您的位置:首页 > 其它

cycle,reverse,rotate linked list

2014-07-17 21:37 253 查看


Linked List Cycle

 

Given a linked list, determine if it has a cycle in it.

/**
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL || head->next == NULL) return false;
ListNode* h = head;
ListNode* p = head;

while(p->next != NULL && p->next->next != NULL)//注意直接是对走两步的进行判断就好,如果结束,两步的先结束,
{

h = h->next;
p = p->next->next;
if(p == h) return true;
}
return false;
}
};


Linked List Cycle II



Given a linked list, return the node where the cycle begins. If there is no cycle, return 
null
.


两个节点,一个快节点(q)每次走两步,一个慢节点(p)每次走一步,如果有环相遇时候,q走得路程是p的两倍


q = x + y + z + y =2p =2(x + y),x起点到环路开始距离,y 环路开始到相遇点距离,z相遇点到环路开始距离

x = z,那么一个点从起点走到环路开始点和一个点从相遇点走到环路开始,都走一步,相遇时候就是环路开始阶段

class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head == NULL || head->next == NULL)
return NULL;
ListNode* p = head;
ListNode* q = head;
bool flag = false;
while(q != NULL && q->next != NULL)
{
q=q->next->next;
p=p->next;
if(p == q)
{
p=head;
while(p!=q)
{
p = p->next;
q = q->next;
}
return p;
}
}
return NULL;
}
};



Reverse Linked List II

 

Reverse
a linked list from position m to n.
Do it in-place and in one-pass.

主要思想就是边遍历边改变指针,使得在m,n之间的节点指向他们的前一个节点,最后再更改m-1和n+1的指针指向

我翻转链表的方法是往后走,有点复杂,涉及k的判断可能越界

class Solution {
public:
ListNode *reverseBetween(ListNode *head, int m, int n) {
if(head == NULL || m == n)
return head;
ListNode* guard = new ListNode(0);
guard->next = head;
ListNode* h = guard;
ListNode* p = guard;
ListNode* q = guard;
ListNode* k = guard;
int c = 0;
while(c!=m)
{
++c;
h = p;
p = p->next;
}
q = p->next;
k = p->next->next;
while(c!=n)
{
++c;
q->next = p;
p = q;
q = k;
if(k!=NULL)
k = k->next;
}
h->next->next = q;
h->next = p;
return guard->next;
}
};





修改的新代码如下


主要在反转的时候,注意添加pre节点,p当前节点,q是下一个节点,这样子迭代就只是当前节点和下一个节点和一个已经处理了的节点,简洁多了。


class Solution {
public:
ListNode *reverseBetween(ListNode *head, int m, int n) {
if(head == NULL || m == n)
return head;
ListNode* guard = new ListNode(0);
guard->next = head;
ListNode* h = guard;
ListNode* p = guard;
ListNode* q = guard;
ListNode* pre = NULL;
int c = 0;
while(c!=m)
{
++c;
h = p;
p = p->next;
}
while(c<=n)
{
++c;
q = p->next;
p->next = pre;
pre = p;
p = q;
}
h->next->next = p;
h->next = pre;
return guard->next;
}
};



Reorder List

 Given
a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…

举个例子,1>2>3>4>5>6>7
 ——>   1>7>2>6>3>5>4,找到中间点4

   
               1>2>3>4>                        1>2>3>4> 

   
              >5>6>7      ——>            >7>6>5         4之后的节点翻转,然后依次链接到前面的链表中

   
             

class Solution {
public:
void reorderList(ListNode *head) {
if(head == NULL || head->next == NULL || head->next->next == NULL)
return;

ListNode *mid,*p,*q,*k;
mid=p=q=k=head;
while(p!=NULL && p->next!=NULL)
{
p = p->next->next;
mid = mid->next;
}
p = mid->next;
if(p->next!=NULL)
{
q = p->next;
k = q->next;
p->next = NULL;
if(k==NULL)
{
q->next = p;
}
while(k!=NULL)
{
q->next = p;
p = q;
q = k;
if(k!=NULL)
k = k->next;
}
if(k==NULL)
{
q->next = p;
}
mid->next = q;
}
p = head;
q = mid->next;
while(q!=NULL)
{
mid->next = q->next;
q->next = p->next;
p->next = q;
p = p->next->next;
q = mid->next;
}
}
};


下面就个就简单一点,因为他设置了pre,p,q。其中,p是当前节点,q是下一个节点,pre是前一个节点,pre一开始是NULL,这样子,我只需要判断一个节点是否为空就好了,比自己的处理的情况简单。

class Solution {
public:
void reorderList(ListNode *head) {
if(head == NULL || head->next == NULL || head->next->next == NULL)
return ;

ListNode *mid,*p,*q,*pre=NULL;
mid=p=q=head;
while(p!=NULL && p->next!=NULL)
{
p = p->next->next;
mid = mid->next;
}
p = mid->next;
if(p->next!=NULL)
{

while(p!=NULL)
{
q = p->next;
p->next = pre;
pre = p;
p = q;
}
mid->next = pre;
}
p = head;
q = mid->next;
while(q!=NULL)
{
mid->next = q->next;
q->next = p->next;
p->next = q;
p = p->next->next;
q = mid->next;
}
}
};


Rotate List

 

Given a list, rotate the list to the right by k places, where k is non-negative.

For example:

Given 
1->2->3->4->5->NULL
 and k = 
2
,

return 
4->5->1->2->3->NULL
.

class Solution {
public:
ListNode *rotateRight(ListNode *head, int k) {
//完全理解错题目的意思,不是找到倒数第k个旋转就好的,此处考虑k是否大于等于链表长度
//而是不断将链表右边的节点向左边旋转k次,k可以无限大,但是可以转化成前面的问题
//规律在于,其实k<length就是前面一个问题,k>length取k % length的值必定小于length即使前面的问题,k==length就是一样的链表

//小心可能k的值比链表长度要大,可能一样长度
if(head == NULL || head->next == NULL || k==0)
return head;
ListNode *p, *q,*next;
next=p=q=head;
int c = 1;
while(p->next!=NULL)//计算链表长度
{
p = p->next;
++c;
}
k = k % c;
if(k==0)
return head;

p = head;
c = 0;
while(p!=NULL)//p多走k步
{
p = p->next;
++ c;
if(c == k)
break;
}

while(p->next!=NULL)//p,q同时走,最后q到达的就是倒数第k个节点的前一个节点,因为我对p->next进行判断,p走到最后一个NULL节点的前一个有                                 //效节点
{
q = q->next;
p = p->next;
}
next = q->next;//第k个节点
q->next = NULL;//倒数第K个节点的前一个节点处断开,
p->next = head;
return next;
}
};


Partition List

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

//虽然正确率很高,但是我做了蛮久一是效率低下,一是,太多情况要考虑,有点乱
//首先可能都大于x,或者都小于等于x,还有就是有大于等于也有小于的

//next = cur->next;
class Solution {
public:
ListNode *partition(ListNode *head, int x) {
if(head == NULL || head->next == NULL)
return head;
ListNode* guard = new ListNode(0);
guard->next = head;
ListNode *cur, *next,*pre;
cur = next = guard;
//找到第一个大小的分割点,cur
if(cur->next->val < x)//首先找到大于等于x的节点的前一个节点,如果第一个就小于x往下找直到到第一个大于等于的节点,如果第一个就大于,不  处理
{
while(cur->next!= NULL && cur->next->val < x)
cur = cur->next;
}
pre = cur;
next = cur->next;
while(next != NULL)//如果是都小于则退出
{
if(next->val >= x)//如果都小于等于也退出了,或者是都是大于等于的也退出了,否则,next指向第一个小于的节点,cur是前面小于的最后一个  节点,或者是第一个是大于的前一个guard节点,pre是next的父亲节点
{
while(next!= NULL && next->val >= x)
{
pre = next;
next = next->next;
}
}
if(next!=NULL)//加NULL判断,是哪种原因推出while的,
{//链接
pre->next = next->next;
next->next = cur->next;
cur->next = next;

cur = cur->next;//注意cur是前面小于的最后一个  节点,需要往后移动一个
next = pre->next;//next此时是pre的下一个节点
}
}
return guard->next;
}
};


看到别人的代码真的有重伤,自己脑子估计进水了这么简单的方法都没有想到,只要大于等于一个链表,小于一个链表,最后合并就好了。

class Solution {
public:
ListNode *partition(ListNode *head, int x) {
if(head == NULL || head->next == NULL)
return head;
ListNode* left = new ListNode(-1);
ListNode* right = new ListNode(-1);
ListNode* l_h = left;
ListNode* r_h = right;
ListNode* cur = head;
while(cur!=NULL)
{
if(cur->val < x)
{
l_h->next = cur;
l_h = l_h->next;
}
else
{
r_h->next = cur;
r_h = r_h->next;
}
cur = cur->next;
}
l_h->next = right->next;
r_h->next = NULL;
return left->next;
}
};



Copy List with Random Pointer

 

剑指offer上的有的,但是忘记了。
class Solution {
public:
void CloneNodes(RandomListNode* head)
{
RandomListNode* h = head;
while(h != NULL)
{
RandomListNode* p1 = new RandomListNode(h->label);
p1->next = h->next;
h->next = p1;
h = p1->next;
}
}

void ConnectRandomLinks(RandomListNode *head)
{
RandomListNode* h = head;
while(h!=NULL)
{
RandomListNode* p = h->next;
if(h->random != NULL)
p->random = h->random->next;
h = p->next;
}

}

RandomListNode *ReconnectNodes(RandomListNode *head)
{
RandomListNode* h = head;
RandomListNode* clonedHead = NULL;
RandomListNode* clonedNode = NULL;
if(h != NULL)
{
clonedHead = clonedNode = h->next;
h->next = clonedNode->next;
h = h->next;
}
while(h!=NULL)
{
clonedNode->next = h->next;
clonedNode = clonedNode->next;
h->next = clonedNode->next;
h = h->next;
}
return clonedHead;
}

RandomListNode *copyRandomList(RandomListNode *head)
{
if(head == NULL )
return head;

CloneNodes(head);
ConnectRandomLinks(head);
return ReconnectNodes(head);
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: