leetcode之单链表题目汇总

来源:互联网 发布:联影 算法怎么样 编辑:程序博客网 时间:2024/06/01 20:33
leetcode(2)单链表之Add Two Numbers
 

题目】

You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8

【题意】

给你两个链表,表示两个非负整数。数字在链表中按反序存储,例如342在链表中为2->4->3。链表每一个节点包含一个数字(0-9)。

计算这两个数字和并以链表形式返回。

分析:用链表表示数据,模拟加法, 时间复杂度 O(m+n),空间复杂度 O(1)

 
//
#include<iostream>
using namespace std;
struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(nullptr){}
};
class Solution
{
public:
    ListNode * addTwoNumbers(ListNode *list1,ListNode *list2)
    {
        ListNode *head=new ListNode(0);
        ListNode *pre=head;
        ListNode *node=nullptr;
        int c=0,sum;
        
        while(list1!=nullptr&&list2!=nullptr)
        {
            sum=list1->val+list2->val+c;
            c=sum/10;
            node=new ListNode(0);
            node->val=sum%10;
            node->next=nullptr;
            //
            pre->next=node;
            pre=node;
            list1=list1->next;
            list2=list2->next;
        }
        while(list1!=nullptr)
        {
            sum=list1->val+c;
            c=sum/10;
            node=new ListNode(0);
            node->val=sum%10;
            node->next=nullptr;
            pre->next=node;
            pre=node;
            list1=list1->next;
        }
        while(list2!=nullptr)
        {
            sum=list2->val+c;
            c=sum/10;
            node=new ListNode(0);
            node->val=sum%10;
            node->next=nullptr;
            pre->next=node;
            pre=node;
            list2=list2->next;
        }
            
        //
        if(c>0)
        {
            node=new ListNode(0);
            node->val=c;
            node->next=nullptr;
            pre->next=node;
            pre=node;
                
        }
        return head->next;
    }
};
int main()
{
    Solution solution;
    int A[]={2,4,7,9};
    int B[]={5,6,4};
    ListNode *head=nullptr;
    ListNode *head1=new ListNode(0);
    ListNode *head2=new ListNode(0);
    head1->next=nullptr;
    head2->next=nullptr;
    ListNode *node;
    ListNode *pre=head1;
    for(int i=0;i<4;++i)
    {
        node=new ListNode(0);
        node->val=A[i];
        node->next=nullptr;
        pre->next=node;
        pre=node;
    }
    pre=head2;
    for(int i=0;i<3;++i)
    {
        node=new ListNode(0);
        node->val=B[i];
        node->next=nullptr;
        pre->next=node;
        pre=node;
    }
    head=solution.addTwoNumbers(head1->next,head2->next);
    while(head!=nullptr)
    {
        cout<<head->val<<endl;
        head=head->next;
    }
    system("pause");
    return 0;
}
//
ListNode * addTwoNumbers(ListNode *l1,ListNode *l2)
{
    ListNode *sumList=new ListNode(-1);
    ListNode *cur=sumList;
    int carry=0;
    while(l1!=nullptr||l2!=nullptr||carry!=0)
    {
        int val1=l1==nullptr?0:l1->val;
        int val2=l2==nullptr?0:l2->val;
        int sum=val1+val2+carry;
        carry=sum/10;
        sum%=10;
        cur->next=new ListNode(sum);
        cur=cur->next;
        l1=l1==nullptr?nullptr:l1->next;
        l2=l2==nullptr?nullptr:l2->next;
    }   
    ListNode *result=sumList->next;
    delete sumList;
    return result;

}


Leetcode(92)单链表之Reverse Linked List II
 

【题目】

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

For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,

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

Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.

【题意】

将给定链表第m个节点到第n个节点的位置逆序,返回逆序后的链表。
给定M,N满足以下条件: 
1≤M≤N≤列表的长度。
注意要求:在原地反转,也就是不能申请额外的空间,且只能遍历一遍。

前m-1个不变,从第m+1个到第n个,依次删除,用尾插法插入到第m-1个节点后面。

第一步把4节点删除放入2节点之后

 第二步把5节点删除放入2节点之后

 
//
struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(nullptr){}
};
class Solution
{
public:
    ListNode *reverseBetween(ListNode *head,int m,int n)
    {
        if(m>=n||n<0)
            return head;
        ListNode *result=nullptr;
        ListNode *tail=nullptr;
        ListNode *rtail=nullptr;
        ListNode *p=nullptr;
        //
        ListNode *beginNode=new ListNode(0);
        beginNode->next=head;
        ListNode *pre=beginNode;
        //m-1
        int index=1;
        while(pre!=nullptr&&index<m)
        {
            pre=pre->next;
            ++index;
        }
        
        tail=pre;
        rtail=tail->next;
        index=1;
        //n-m
        while(index<(n-m+1))
        {
            //p
            p=rtail->next;
            rtail->next=p->next;
            //ptail
            p->next=tail->next;
            tail->next=p;
            ++index;
        }
        result=beginNode->next;
        delete beginNode;
        return result;
    }
};
 

 
ListNode *reverseBetween(ListNode *head,int m,int n)
{
    ListNode dummy(0);
    dummy.next=head;
    ListNode *pre=&dummy;
    ListNode *preM=nullptr;
    for(int i=1;i<=n;++i)
    {
        if(i==m)
            preM=pre;
        if(i>m&&i<=n)
        {
            //head
            pre->next=head->next;
            head->next=preM->next;
            //
            preM->next=head;
            head=pre; // head has been moved, so pre becomes current
        }
        pre=head;
        head=head->next;
    }
    return dummy.next;
}

leecode(86)单链表之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.

For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.

【题意】

给定一个链表和一个值x,对它进行分区,使得小于x的所有节点来到大于或等于x的所有节点之前。 
你应该保持在每两个分区的节点的原始相对顺序。
方法:
遍历一遍链表,把小于x的都挂到left后,把大于等于x的都放到right后,最后再把大于等于的链表挂到小于链表的后面就可以了。

 
//
struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(nullptr){}
};
ListNode *partition(ListNode *head,int x)
{
    if(head==nullptr)
        return nullptr;
    ListNode *left=new ListNode(-1);
    ListNode *right=new ListNode(-1);
    ListNode *lpre=left;
    ListNode *rpre=right;
    ListNode *result=nullptr;
    while(head)
    {
        if(head->val<x)
        {
            lpre->next=head;
            lpre=head;
        }
        else
        {
            rpre->next=head;
            rpre=head;
        }
        head=head->next;
    }
    rpre->next=nullptr;
    lpre->next=right->next;
    result=left->next;
    delete left;
    delete right;
    return result;
}
//
ListNode *partition(ListNode *head,int x)
{
    ListNode leftDummy(-1);
    ListNode rightDummy(-1);
    auto leftCur=&leftDummy;
    auto rightCur=&rightDummy;
    while(head)
    {
        if(head->val<x)
        {
            leftCur->next=head;
            leftCur=head;
        }
        else
        {
            rightCur->next=head;
            rightCur=head;
        }
        head=head->next;
    }
    rightCur->next=nullptr;
    leftCur->next=rightDummy.next;
    return leftDummy.next;
}
 
leecode(86)单链表之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.

For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.

【题意】

给定一个链表和一个值x,对它进行分区,使得小于x的所有节点来到大于或等于x的所有节点之前。 
你应该保持在每两个分区的节点的原始相对顺序。
方法:
遍历一遍链表,把小于x的都挂到left后,把大于等于x的都放到right后,最后再把大于等于的链表挂到小于链表的后面就可以了。

 
//
struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(nullptr){}
};
ListNode *partition(ListNode *head,int x)
{
    if(head==nullptr)
        return nullptr;
    ListNode *left=new ListNode(-1);
    ListNode *right=new ListNode(-1);
    ListNode *lpre=left;
    ListNode *rpre=right;
    ListNode *result=nullptr;
    while(head)
    {
        if(head->val<x)
        {
            lpre->next=head;
            lpre=head;
        }
        else
        {
            rpre->next=head;
            rpre=head;
        }
        head=head->next;
    }
    rpre->next=nullptr;
    lpre->next=right->next;
    result=left->next;
    delete left;
    delete right;
    return result;
}
//
ListNode *partition(ListNode *head,int x)
{
    ListNode leftDummy(-1);
    ListNode rightDummy(-1);
    auto leftCur=&leftDummy;
    auto rightCur=&rightDummy;
    while(head)
    {
        if(head->val<x)
        {
            leftCur->next=head;
            leftCur=head;
        }
        else
        {
            rightCur->next=head;
            rightCur=head;
        }
        head=head->next;
    }
    rightCur->next=nullptr;
    leftCur->next=rightDummy.next;
    return leftDummy.next;
}
 
leetcode(83)单链表之Remove Duplicates from Sorted List
 Given a sorted linked list, delete all duplicates such that each element appear only once.

For example,
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.

【题意】

给定一个有序链表,删除所有重复元素,使得每个元素只出现一次。

时间复杂度 O(n),空间复杂度 O(1)

 
/**代码一:
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution
{
public:
    ListNode * deleteDuplicates(ListNode *head)
    {
        if(head==nullptr)
            return nullptr;
        ListNode *beginNode=new ListNode(-1);
        beginNode->next=head;
        ListNode *cur=beginNode->next;
        ListNode *pre=cur;
        
        while(cur!=nullptr)
        {
            if(cur->val==pre->val)
            {
                pre->next=cur->next;
                cur=cur->next;
            }
            else
            {
                pre=cur;
                cur=cur->next;
            }   
        }
        ListNode *result=beginNode->next;
        delete beginNode;
        return result;
    }
};
 

 


 
//
ListNode * deleteDuplicates(ListNode *head)
    {
        if(head==nullptr)
            return nullptr;
        ListNode *beginNode=new ListNode(-1);
        beginNode->next=head;
        ListNode *pre=beginNode->next;
        ListNode *cur=pre->next;
        
        while(cur!=nullptr)
        {
            if(cur->val==pre->val)
            {
                pre->next=cur->next;
                cur=cur->next;
            }
            else
            {
                pre=cur;
                cur=cur->next;
            }
    
        }
        ListNode *result=beginNode->next;
        delete beginNode;
        return result;
    }
 

 


leetcode(82)单链表之 Remove Duplicates from Sorted List II

【题目】

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.

【题意】

给定一个有序链表,删除具有重复的数字,从原来的列表中只留下了不同数字的所有节点。

方法:

遍历链表,记录重复元素的起始位置和截止位置。要删除的重复元素的上一个位置begin,截止位置end。例如:1,2,2,2,4 begin = 0 end = 3

如果当前元素和上一个元素相等,则更新end;如果不相等则判断beigin和end是否相等,相等没有重复元素需要删除,不相等删除[being+1,end]中元素。

如果最后几个元素重复,则需要最后单独通过判断begin,end是否等来解决。 

 
//
class Solution
{
public:
    ListNode * deleteDuplicates(ListNode *head)
    {
        if(head==nullptr||head->next==nullptr)
            return head;
        //
        ListNode *beginNode=new ListNode(-1);
        beginNode->next=head;
        ListNode *begin=beginNode; //
        ListNode *end=beginNode;//
        ListNode *pre=head; //
        ListNode *cur=head->next; //
    
        
        while(cur!=nullptr)
        {
             if(cur->val==pre->val)
             {
                 end=cur;              // 
             }
             else
             {
                 pre=cur;
                 //[begin,end]
                 if(begin!=end)         // 
                 {
                     begin->next=end->next;
                     end=begin;
                 }
                 //[begin,end],
                 else
                 {
                     begin=end=pre;
                 }
             }
             pre=cur;
             cur=cur->next; 
             
        }
        //2,1,1,1,1
             if(begin!=end)
                 begin->next=end->next; //
        
        ListNode *result=beginNode->next;
        delete beginNode;
        return result;
    }
};
 
 

 
//
class Solution
{
public:
    ListNode * deleteDuplicates(ListNode *head)
    {
        if(head==nullptr)
            return nullptr;
        ListNode *beginNode=new ListNode(-1);
        beginNode->next=head;
        ListNode *pre=beginNode;
        ListNode *cur=pre->next;
        ListNode *tmp=nullptr;
        
        while(cur!=nullptr)
        {
            bool duplicated=false;//
            while(cur->next!=nullptr&&cur->val==cur->next->val) //
            {
                duplicated=true;
                tmp=cur->next;
                pre->next=cur->next;
                cur=tmp;
            }
            
            if(duplicated)     //     
            {
                tmp=cur->next;
                pre->next=cur->next;
                cur=tmp;    
                continue;
            }
            pre=cur;
            cur=cur->next;
    
        }
        ListNode *result=beginNode->next;
        delete beginNode;
        return result;
    }
};
leetcode(61)单链表之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.

【题意】

给定一个链表,向右旋转k个位置,其中k是非负的。

方法一:

先遍历一遍,得出链表长度 len,注意 k 可能大于 len,因此令 k% = len。将尾节点 next 指针
指向首节点,形成一个环,接着往后跑 len -  k 步,从这里断开,就是要求的结果了。

 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution
{
public:
    ListNode *rotateRight(ListNode *head,int k)
    {
        if(head==nullptr||k<=0)
            return head;
        // 
        int size=1;
        ListNode *p=head;
        while(p->next)
        {
            ++size;
            p=p->next;
        }
        k=size-k%size;
        p->next=head;//
        for(int i=0;i<k;++i)   //k
        {
            p=p->next;
        }
        head=p->next;// 
        p->next=nullptr;//
        return head;
    }
};
 



方法二:

 
class Solution
{
public:
    ListNode * rotateRight(ListNode *head,int k)
    {
        if(head==nullptr||k<=0)
            return head;
        // 
        int size=0;
        ListNode *p=head;
        while(p)
        {
            ++size;
            p=p->next;
        }
        //
        k=size-k%size;
        if(k==size)
            return head;
        ListNode *right=head;
        ListNode *pre=nullptr;
        for(int i=0;i<k;++i)
        {
            pre=right;
            right=right->next;
        }
        pre->next=nullptr;
        p=right;
        while(p->next)
        {
            p=p->next;
        }
        p->next=head;
        return right;
    }
    
};
leetcode(19)单链表之Remove Nth Node From End of List
 

【题目】

Given a linked list, remove the nth node from the end of list and return its head.

For example,

Given linked list: 1->2->3->4->5, and n = 2. After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:
Given n will always be valid.
Try to do this in one pass.

【题意】

给你一个链表,去除掉倒数第n个节点。

 

class Solution
{
public:
    ListNode *removeNthFromEnd(ListNode *head,int n)
    {
        if(head==nullptr||n<=0)
            return head;
        ListNode *beginNode=new ListNode(-1);
        beginNode->next=head;
        ListNode *pre=beginNode;
        ListNode *cur=beginNode->next;
        //
        int size=0;
        while(cur)
        {
            ++size;
            cur=cur->next;
        }
        int k=size-n;
        cur=beginNode;
        for(int i=0;i<=k;++i)
        {
            pre=cur;
            cur=cur->next;
        }
        pre->next=cur->next;
        ListNode *result=beginNode->next;
        delete beginNode;
        return result;
    }
};
 
方法二:遍历一遍数组 

 设两个指针 p; q,让 q 先走 n 步,然后 p 和 q 一起走,直到 q 走到尾节点,删除 p->next 即可。

 
class Solution
{
public:
    ListNode *removeNthFromEnd(ListNode *head,int n)
    {
        if(head==nullptr||n<=0)
            return head;
        ListNode *beginNode=new ListNode(-1);
        beginNode->next=head;
        ListNode * p1=beginNode;
        ListNode * p2=beginNode;
        ListNode *tmp=nullptr;
        //p2n
        for(int i=0;i<n;++i)
        {
            p2=p2->next;
        }
          while(p2->next!=nullptr)
          {
              p1=p1->next;
              p2=p2->next;
          }
        tmp=p1->next;
        p1->next=tmp->next;
        
        ListNode *result=beginNode->next;
        delete beginNode;
        return result;
    }
};
leetcode(24)单链表之Swap Nodes in Pairs
 

【题目】

Given a linked list, swap every two adjacent nodes and return its head.

For example,
Given 1->2->3->4, you should return the list as 2->1->4->3.

Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.

【题意】

给定一个链表,交换每两个相邻的节点,并返回它的头。

你的算法应该使用常数空间。不得修改在列表中的值,只有节点本身是可以改变的。

 方法一:符合题意。 时间复杂度 O(n),空间复杂度 O(1)
//
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *swapPairs(ListNode *head)
{
    if(head==nullptr||head->next==nullptr)
        return head;
    ListNode *beginNode=new ListNode(-1);
    beginNode->next=head;
    ListNode *pre=beginNode;
    ListNode *cur=pre->next;
    ListNode *tmp=nullptr;
    //
    while(cur!=nullptr&&cur->next!=nullptr)
    {
        tmp=cur->next;
        cur->next=tmp->next;
        tmp->next=cur;
        pre->next=tmp;
        pre=cur;
        cur=cur->next;
    }
    
    ListNode *result=beginNode->next;
    delete beginNode;
    return result;
}
};
 

 方法二:点(不符合题意)

ListNode *swapPairs(ListNode *head)
{
    if(head==nullptr||head->next==nullptr)
        return head;
    ListNode *p=head;
    while(p&&p->next)
    {
        swap(p->val,p->next->val);
        p=p->next->next;
    }
    return head;
}
 
leetcode(25)单链表之 Reverse Nodes in k-Group

【题目】

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

You may not alter the values in the nodes, only nodes itself may be changed.

Only constant memory is allowed.

For example,
Given this linked list: 1->2->3->4->5

For k = 2, you should return: 2->1->4->3->5

For k = 3, you should return: 3->2->1->4->5

【题意】

对链表中的元素按K个一组,反序后,形成新的链表。对于最后不满K个元素,保持原来的顺序输出。

 
方法一: 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *reverseKGroup(ListNode *head,int k)
{
    if(head==nullptr||k<=1)
        return head;
    ListNode *beginNode=new ListNode(-1);
    beginNode->next=head;
    ListNode *pre=beginNode;
    ListNode *cur=nullptr;
    ListNode *tail=nullptr;
    
    //
    int size=0;
    while(pre->next!=nullptr)
    {
        ++size;
        pre=pre->next;
    }
    //
    int count=size/k;
    pre=beginNode;
    tail=pre->next;//
    while(count--)
    {
        int i=k-1;
        while(i>0)
        {
            //cur
            cur=tail->next;
            tail->next=cur->next;
            //cur
            cur->next=pre->next;
            pre->next=cur;
            i--;
        }
        pre=tail;
        tail=pre->next;
    }
    
    ListNode *result=beginNode->next;
    delete beginNode;
    return result;
}
};
 

 方法二:

1、建立空的新链表list1.

2、如果原链表剩余元素个数不小于K个,则取K个元素,采用头插法构建反序的临时链表,插入list1的尾部。

3、如果链表剩余元素个数小于K个,则将剩余的链表插入到list1的尾部。

 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
   int getListSize(ListNode* head)  
{  
    int count = 0;  
    while (head)  
    {  
        head = head->next;  
        count++;  
    }  
    return count;  
}  
//  
ListNode* addHead(ListNode*head, ListNode*Node)  
{  
    Node->next = head;  
    return Node;  
}  
ListNode* reverseKGroup(ListNode* head, int k) {  
    int length = getListSize(head);  
    ListNode tmpHead(-1);  
    ListNode *pNode = &tmpHead;  
    while(length >= k){  
        ListNode* pHead = NULL;  
        for (int i=0; i<k; i++)  
        {  
            ListNode*ptmpNode = head;  
            head = head->next;  
            ptmpNode->next = NULL;  
            //  
            pHead = addHead(pHead, ptmpNode);  
        }  
        pNode->next = pHead;  
        while(pNode->next)  
            pNode = pNode->next;  
        length -= k;  
    }  
    //  
    pNode->next = head;  
    return tmpHead.next;  
}  
};
leetcode(138)复杂链表之Copy List with Random Pointer
 【描述】
A linked list is given such that each node contains an additional random pointer which could point to
any node in the list or null.
Return a deep copy of the list.

【题意】

深拷贝一个链表,链表除了含有next指针外,还包含一个random指针,该指针指向链表中的某个节点或者为空。
【方法一】暴力复制,时间复杂度O(n^2)
 
/**
 * Definition for singly-linked list with a random pointer.
 * struct RandomListNode {
 *     int label;
 *     RandomListNode *next, *random;
 *     RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
 * };
 */
class Solution {
public:
    RandomListNode *copyRandomList(RandomListNode *head)
  {
      if(head==nullptr)
          return nullptr;
      RandomListNode *newHead=new RandomListNode(head->label);
      RandomListNode *node=head->next;
      RandomListNode *newNode=newHead;
      while(node!=nullptr)
      {
          newNode->next=new RandomListNode(node->label);
          node=node->next;
          newNode=newNode->next;
      }
      node=head;
      newNode=newHead;
      RandomListNode *index1=nullptr;
      RandomListNode *index2=nullptr;
      while(node!=nullptr)
      {
          if(node->random==nullptr)
              newNode->random=nullptr;
          else
          {
              index1=head;index2=newHead;
              while(node->random!=index1)
              {
                  index1=index1->next;
                  index2=index2->next;
              }
              newNode->random=index2;
          }
          node=node->next;
          newNode=newNode->next;
      }
      return newHead;
  }
};
 
 

【算法二】时间复杂度O(N),空间复杂度O(1)

不用保存原始链表的映射关系,构建新节点时,指针做如下变化,即把新节点插入到相应的旧节点后面:

同理分两步

1、构建新节点random指针:new1->random = old1->random->next, new2-random = NULL, new3-random = NULL, new4->random = old4->random->next

2、恢复原始链表以及构建新链表:例如old1->next = old1->next->next,  new1->next = new1->next->next

 

 
/**
 * Definition for singly-linked list with a random pointer.
 * struct RandomListNode {
 *     int label;
 *     RandomListNode *next, *random;
 *     RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
 * };
 */
class Solution {
public:
    RandomListNode *copyRandomList(RandomListNode *head)
  {
      if(head==nullptr)
          return nullptr;
      RandomListNode *node=head;
      RandomListNode *newNode=nullptr;
      RandomListNode *tmp=nullptr;
      //
      while(node!=nullptr)
      {
          newNode=new RandomListNode(node->label);
          newNode->next=node->next;
          node->next=newNode;
          node=newNode->next;
      }
      //randomrandom
      node=head;
      while(node!=nullptr)
      {
          newNode=node->next;
          if(node->random!=nullptr)
          {
              tmp=node->random;
              newNode->random=tmp->next;
          }
          else
              newNode->random=nullptr;
          node=newNode->next;
      }
      //
      RandomListNode *newHead=head->next;
      node=head;
      while(node!=nullptr)
      {
          newNode=node->next;
          node->next=newNode->next;
          if(newNode->next!=nullptr)
          {
              tmp=newNode->next;
              newNode->next=tmp->next;
          }
          node=node->next;
      }
      return newHead;
  }
};
 
leetcode(141)单链表之 Linked List Cycle
 

【题目】

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

Follow up:
Can you solve it without using extra space?

【题意】

给定一个链表,判断它是否包含一个环。
【注意】
 
1. 空链表不成环

   2. 一个节点自环

   3. 一条链表完整成环
linked-list-cycle
【方法一】 
空间复杂度 O(n),时间复杂度 O(N )

用一个哈希表 unordered_map<ListNode *, bool> visited,记录每个元素是否被访问过,一旦出现某个元素被重复访问,说明存在环。

 

 
/**
 * 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==nullptr)
         return false;
     unordered_map<ListNode*,bool> visited(false);
     bool isCycle=false;
    
     while(head!=nullptr)
     {
    
         if(visited[head]==true)
         {
             isCycle=true;
             break;
         }
         else
             visited[head]=true;
         head=head->next;
     }
     return isCycle;
 }
};
 【方法二】时间复杂度 O(n),空间复杂度 O(1) 的。

使用两个指针slow,fast。两个指针都从表头开始走,slow每次走一步,fast每次走两步,如果fast遇到null,则说明没有环,返回false;如果slow==fast,说明有环,并且此时fast超了slow一圈,返回true。

为什么有环的情况下二者一定会相遇呢?因为fast先进入环,在slow进入之后,如果把slow看作在前面,fast在后面每次循环都向slow靠近1,所以一定会相遇,而不会出现fast直接跳过slow的情况。


这里需要注意的一点是算法中循环的条件,这是一个很容易被忽略的细节。

1)因为fast指针比slow指针走得快,所以只要判断fast指针是否为空就好。由于fast指针一次走两步,fast.next可能已经为空(当fast为尾结点时),fast.next.next将会导致NullPointerException异常,所以在while循环中我们要判断fast.next是否为空;

2)考虑一个特殊情况,当输入的链表为空时,算法应该返回false,空链表肯定是不含有环的。如果没有fast != null,也会导致fast.next抛出NullPointerException异常。  

 

 
/**
 * 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==nullptr)
         return false;
     ListNode *slow=head;
     ListNode *fast=head;
     while(fast!=nullptr&&fast->next!=nullptr)
     {
         slow=slow->next;
         fast=fast->next->next;
         if(slow==fast)
             return true;
     }
     return false;
 }
};
leetcode(142)单链表之 Linked List Cycle II
 

题目:

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

Follow up: Can you solve it without using extra space?
题意: 

如何找到环的第一个节点?

分析:
 
 1)先判断是否存在环

使用两个指针slow,fast。两个指针都从表头开始走,slow每次走一步,fast每次走两步,如果fast遇到null,则说明没有环,返回false;如果slow==fast,说明有环,并且此时fast超了slow一圈,返回true。

为什么有环的情况下二者一定会相遇呢?因为fast先进入环,在slow进入之后,如果把slow看作在前面,fast在后面每次循环都向slow靠近1,所以一定会相遇,而不会出现fast直接跳过slow的情况。 

2)找环的第一个节点


设:链表头是X,环的第一个节点是Y,slow和fast第一次的交点是Z。各段的长度分别是a,b,c,如图所示。环的长度是L。slow和fast的速度分别是qs,qf。

第一次相遇时slow走过的距离:a+b,fast走过的距离:a+b+c+b。

因为fast的速度是slow的两倍,所以fast走的距离是slow的两倍,有 2(a+b) = a+b+c+b,可以得到a=c(这个结论很重要!)

发现L=b+c=a+b,也就是说,从一开始到二者第一次相遇,循环的次数就等于环的长度。

已经得到了结论a=c,那么让两个指针分别从X和Z开始走,每次走一步,那么正好会在Y相遇!也就是环的第一个节点。

 
struct ListNode
{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(nullptr){}
};
class Solution
{
public:
    ListNode *detectCycle(ListNode *head)
    {
        if(head==nullptr)
            return nullptr;
        ListNode *slow=head;
        ListNode *fast=head;
        ListNode *slow2=head;
        while(fast!=nullptr&&fast->next!=nullptr)
        {
            slow=slow->next;
            fast=fast->next->next;
            if(fast==slow)
            {
                while(slow!=slow2)
                {
                    slow=slow->next;
                    slow2=slow2->next;
                }
                return slow2;
            }
        }
        return nullptr;
    }
};
 


【题目拓展】 
 

      
1. 环的长度是多少?
       
方法一

第一次相遇后,让fast停着不走了,slow继续走,记录到下次相遇时循环了几次。

方法二

第一次相遇时slow走过的距离:a+b,fast走过的距离:a+b+c+b。

因为fast的速度是slow的两倍,所以fast走的距离是slow的两倍,有 2(a+b) = a+b+c+b,可以得到a=c(这个结论很重要!)

我们发现L=b+c=a+b,也就是说,从一开始到二者第一次相遇,循环的次数就等于环的长度。

 
 

2. 如何找到环中第一个节点(即Linked List Cycle II)?
        我们已经得到了结论a=c,那么让两个指针分别从X和Z开始走,每次走一步,那么正好会在Y相遇!也就是环的第一个节点。 




      3. 如何将有环的链表变成单链表(解除环)?
         在上一个问题的最后,将c段中Y点之前的那个节点与Y的链接切断即可。 



      4. 如何判断两个单链表是否有交点?如何找到第一个相交的节点?
         先判断两个链表是否有环,如果一个有环一个没环,肯定不相交;如果两个都没有环,判断两个列表的尾部是否相等;如果两个都          有环,判断一个链表上的Z点是否在另一个链表上。
      5、(接问题4)
如何找到第一个相交的节点?
        求出两个链表的长度L1,L2(如果有环,则将Y点当做尾节点来算),假设L1<L2,用两个指针分别从两个链表的头部开始走,长度         为L2的链表先走(L2-L1)步,然后两个一起走,直到二者相遇。 

leetcode(143)单链表之Reorder List
 

【题目】

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

You must do this in-place(在原链表基础上) without altering the nodes' values(不能使用额外空间).

For example,
Given {1,2,3,4}, reorder it to {1,4,2,3}.

【题意】

给定一个单链表L:L0→L1→...→LN-1→LN, 
它重新排列到:L0→LN→L1→LN-1→L2→LN-2→...

【分析】

题目规定要 in-place,也就是说只能使用 O(1) 的空间。

可以找到中间节点,断开,把后半截单链表 reverse 一下,再合并两个单链表。 

 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution
{
public:
    ListNode* reorderList(ListNode *head)
    {
        if(head==nullptr||head->next==nullptr)
            return head;
        ListNode *slow=head;
        ListNode *fast=head;
        ListNode *pre=nullptr;
        ListNode *pre2=nullptr;
        ListNode *tmp=nullptr;
        //
        while(fast!=nullptr&&fast->next!=nullptr)
        {
            pre=slow;
            slow=slow->next;
            fast=fast->next->next;
        }
        //
        pre->next=nullptr;
        ListNode *head2=reverse(slow);
        //
        pre=head;
        pre2=head2;
        while(pre->next!=nullptr)
        {
            tmp=pre2->next;
            pre2->next=pre->next;
            pre->next=pre2;
            
            pre=pre->next->next;
            pre2=tmp;
        }
        pre->next=pre2;
        return head;
        
}
private:
    ListNode *reverse(ListNode *head)
    {
        if(head==nullptr||head->next==nullptr)
            return head;
        ListNode *beginNode=new ListNode(-1);
        beginNode->next=head;
        
        ListNode *pre=head;
        ListNode *cur=head->next;
        
        while(cur!=nullptr)
        {
            //
            pre->next=cur->next;
            //
            
            cur->next=beginNode->next;
            beginNode->next=cur;
            
            cur=pre->next;
        }
        ListNode *result=beginNode->next;
        delete beginNode;
        return result;
    }
    
};


0 0
原创粉丝点击