cycle,reverse,rotate linked list

来源:互联网 发布:欧文生涯数据统计 编辑:程序博客网 时间:2024/05/22 11:37

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 LL0L1→…→Ln-1Ln,
reorder it to: L0LnL1Ln-1L2Ln-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;//找到第一个大小的分割点,curif(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);}};




0 0