链表leetcode刷题笔记

链表

设计链表


class Node {
public:
    int val;
    Node* next;
    Node()
    {
        this->next = nullptr;
    }
};

class MyLinkedList {
public:
    /** Initialize your data structure here. */
    Node* head;
    int size;
    MyLinkedList() {
        head = new Node();
        head->next = nullptr;
        size = 0;
    }

    /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
    //返回值为-1有两种情况,坐标值小于0或者坐标值已经超过链表结点的最大个数
    int get(int index) {
        if(index<0||index>size-1)
            return -1;
        Node* temp = head;
        for (int i = 0; i <= index; i++)
        {
            temp = temp->next;
        }
        return temp->val;
    }

    /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
    void addAtHead(int val) {
        Node* newNode = new Node();
        newNode->val = val;
        newNode->next = head->next;
        head->next = newNode;
        size++;

    }

    /** Append a node of value val to the last element of the linked list. */
    void addAtTail(int val) {
        Node* temp = head;
        while (temp->next)
        {
            temp = temp->next;
        }
        Node* newNode = new Node();
        newNode->val = val;
        temp->next = newNode;
        size++;
    }

    /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
    //坐标不符合增加的条件:坐标值小于0或者坐标值大于结点个数
    //坐标是从零开始的
    void addAtIndex(int index, int val) {
        if (index < 0 || index>size)
        {
            return;
        }
        Node* newNode = new Node();
        newNode->val = val;          
        Node* temp = head;
        for (int i = 0; i < index; i++)
        {
            temp = temp->next;
        }
        newNode->next = temp->next;
        temp->next = newNode;
        size++;
    }

    /** Delete the index-th node in the linked list, if the index is valid. */
    //不能删的条件:坐标值小于0或者坐标值大于结点个数-1
    void deleteAtIndex(int index) {

        int flag = 0;
        Node* temp = head;
        if (index < 0||index>size-1)
        {
            return;
        }
        for (int i = 0; i < index; i++)
        {
            temp = temp->next;
        }
        temp->next = temp->next->next;
        size--;
    }
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */
int main()
{
    MyLinkedList* list = new MyLinkedList();
    list->addAtHead(1);
    list->addAtTail(3);
    list->addAtIndex(1, 2);
    cout<<list->get(1);
    list->deleteAtIndex(1);
    cout << list->get(1);



}
/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

一开始用的指针遍历,发现一直过不去,后来引入了变量size,用size来计算坐标和遍历次数,成功通过了,对指针还是不够熟悉。

双指针技巧

环形链表

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

链表中节点的数目范围是 [0, 10000]
-100000 <= Node.val <= 100000
pos 为 -1 或者链表中的一个 有效索引 。

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

链接:https://leetcode-cn.com/leetbook/read/linked-list/jbex5/

解法一:遍历法
  • 题目给出了节点的数目范围是10000以内
  • 从头到尾依次遍历,当循环的次数超过10000次的时候,说明是有环的,否则是无环的
/**
 * 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) {
        int i=0;
        while(head)
        {
            head=head->next;
            i++;
            if(i==10001)  
               return true;
        }
        
        return false;
    }
};
解法二:快慢指针法
  • 一开始的思路是不断遍历,如果找到和头指针重复就说明有环,仔细看题之后发现原来环不一定是整个链表,可能是链表的一部分存在环,所以这种方法是不行的
  • 快慢指针就是一个指针的速度快,一个指针的速度慢,如果存在环,那么快指针一定会追上慢指针,也就是两个的值总会有相等的时候,只要快指针和慢指针指向同一个元素,那就是有环
/**
 * 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) {
       
        ListNode *fast=head;
        ListNode *slow=head;
        while(fast&&fast->next)
        {
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow)
                return true;
        }
       
        return false;
        
    }
};

环形链表Ⅱ

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。
链接:https://leetcode-cn.com/leetbook/read/linked-list/jjhf6/

  • 遍历,如果读到了空指针或者快指针追上慢指针就退出循环
  • 如果读到了空指针说明此时没有环,返回null
  • 如果快指针追上了慢指针,此时快指针比慢指针多走的步数恰好是环的结点数,快指针走了2n步,慢指针走了n步,两者相减为n,n=环节点数=慢指针走的步数
  • 假设进入还之后慢指针走了x步,那么n-x就是两指针进入环之前的距离,同时也是走到环第一个节点还需要走的步数
  • 那么此时让其中一个指针从头开始走,另一个指针继续走,两个指针就会在环的第一个结点相遇
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *fast=head;
        ListNode *slow=head;
        //遍历,如果读到了空指针或者快指针追上慢指针就退出循环
        while(fast&&fast->next)
        {
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow)
                break;
        }
        //如果不是环返回null
        if(fast==nullptr||fast->next==nullptr)
            return nullptr;
        //如果是环,此时快指针比慢指针多走的步数恰好是环的结点数,快指针走了2n步,慢指针走了n步,两者相减为n
        //也就是慢指针走的距离是n,也是环的节点数
        //假设进入还之后慢指针走了x步,那么n-x就是两指针进入环之前的距离,同时也是走到环第一个节点还需要走的步数
        //那么此时让其中一个指针从头开始走,另一个指针继续走,两个指针就会在环的第一个结点相遇
        slow=head;
        while(fast!=slow)
        {
            fast=fast->next;
            slow=slow->next;
        }
        return fast;
        


    }
};

相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

链接:https://leetcode-cn.com/leetbook/read/linked-list/jjbj2/

  • 两个指针分别指向两个链表的头节点,从头到尾遍历两个链表,当走到链表尾部时,指向另一个链表
  • 如果存在交点,那么当两个指针都遍历完两个链表时,一定会相遇
  • 否则遍历完两个链表时会指向null
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p1=headA;
        ListNode *p2=headB;
        //从头到尾遍历两个链表,直到找到两个指针指向同一个元素,也就是交点
        //如果存在交点,那么当两个指针都遍历完两个链表时,一定会相遇
        while(p1!=p2)
        {
            
            p1=p1->next;
            p2=p2->next;
            //如果p1和p2遍历完了两个链表还没有交点,那就是没有交点,因为都走过了两个链表的长度,最终会指向null
            //p1,p2每同时走一步都要判断是不是同时指向了null,如果是的话就说明走完了直接退出
            if(p1==nullptr&&p2==nullptr) 
                return nullptr;
            
            //如果还没遍历完两个链表,就判断是不是有其中一个链表走完了,如果是的话就让他指向另一个链表的头节点
            if(p1==nullptr)
                p1=headB;
            if(p2==nullptr)
                p2=headA;
               
        }
        return p1;
    }
};

删除链表的倒数第N个节点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

  • 双指针,慢指针指向头节点,快指向头节点之后的n个结点,当快指针到达链尾时,慢指针距离链尾还有n步,也就是要删除的值
  • 注意需要考虑删除的节点是第一个结点的情况,这个时候可以加一个头结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *pre=new ListNode();
        pre->next=head;
        ListNode * fast=pre;
        ListNode* slow=pre;
        while(n)
        {
            fast=fast->next;
            n--;
        }
        while(fast->next)
        {
            fast=fast->next;
            slow=slow->next;
        }
        slow->next=slow->next->next;
        return pre->next;
    }
};

总结

  • 需要考虑链表有没有头节点,如果没有,删除和插入的操作要对第一个结点进行特殊处理

  • 注意判断条件的顺序是否会导致构成死循环

  • 在调用 next 字段之前,始终检查节点是否为空。获取空节点的下一个节点将导致空指针错误。例如,在我们运行 fast = fast.next.next 之前,需要检查 fast 和 fast.next 不为空。

  • 双指针模板

    // Initialize slow & fast pointers
    ListNode* slow = head;
    ListNode* fast = head;
    /**
     * Change this condition to fit specific problem.
     * Attention: remember to avoid null-pointer error
     **/
    while (slow && fast && fast->next) {
        slow = slow->next;          // move slow pointer one step each time
        fast = fast->next->next;    // move fast pointer two steps each time
        if (slow == fast) {         // change this condition to fit specific problem
            return true;
        }
    }
    return false;   // change return value to fit specific problem
    

经典问题

反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //递归终止条件:当只有一个结点或者没有结点时,返回head
        if(head==nullptr||head->next==nullptr)
            return head;
         //假设原链表为head->2->3->4->5->null,需要的结果是5->4->3->2->head->null
        //假设后四个链表已经翻转,新的头节点为newhead那么此时 newhead->5->4->3->2->null
        ListNode* newhead=reverseList(head->next);

        //同时   head->2->null(也就是head=>next=2)
        //此时只需要把原来的head插在2后面即可
        //也就是head->next->next=head,head->next=null

        head->next->next=head;
        head->next=nullptr;
        return newhead;

    }
};

移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

  • 没想到有什么特别快的办法,就暴力解,插入删除注意处理第一个结点
  • 可以给链表插入头节点来解决删不掉第一个节点的问题
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //给链表加一个头节点指向第一个结点,使得可以删除第一个结点
        ListNode *pre=new ListNode();
        pre->next=head;
        ListNode *temp=pre;
        
        while(temp->next!=nullptr)
        {
           if(temp->next->val==val)
           {
               temp->next=temp->next->next;
           }
           else{
               temp=temp->next;
           }
        }
       
        return pre->next;

    }
};

奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
链接:https://leetcode-cn.com/leetbook/read/linked-list/fe0kj/

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        //如果只有一个结点或者没有结点返回head
        if(head==nullptr||head->next==nullptr)
            return head;
        //定义奇数链和偶数链的头节点
        ListNode *oddHead=head;
        ListNode *evenHead=head->next;

        //定义两个指针分别指向第一个奇数结点和第一个偶数结点
        ListNode*odd=head;
        ListNode*even=head->next;
        
        //遍历整个链表
        while(odd&&odd->next&&even&&even->next)
        {
            //寻找下一个奇数结点
            odd->next=even->next;
            odd=odd->next;
            //寻找下一个偶数结点
            even->next=odd->next;
            even=even->next;
        }
        //把偶数链表的头接到奇数链表的尾部
        odd->next=evenHead;
        return oddHead;

    }
};

回文链表

请判断一个链表是否为回文链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:

    //反转链表函数
    static ListNode* reverse(ListNode *head)
    {
        if(head==nullptr||head->next==nullptr)
            return head;
        ListNode* newHead=reverse(head->next);
        head->next->next=head;
        head->next=nullptr;
        return newHead;
    }

    bool isPalindrome(ListNode* head) {
        //显然这是一道快慢指针的题目,定义快指针一次走两步,慢指针一次走一步   
        ListNode* fast=head;
        ListNode* slow=head;
        while(fast&&fast->next)
        {
            fast=fast->next->next;
            slow=slow->next;
        }
        //当快指针走到尾部的时候慢指针刚好走到链表的中间
        //这个时候对后半部分链表进行反转,用last指针保存后半部分的链表
        ListNode * last=reverse(slow);

        //再依次比较后半部分和前半部分的值是否相等,如果对应位置不相等就不是回文链表,否则为回文链表
        ListNode *pre=head;
  
        while(last)
        {
            if(pre->val!=last->val)
                return false;
            pre=pre->next;
            last=last->next;
        }
        return true;


        
    }
};

双链表

  • 注意插入和删除都需要先处理对应结点
  • 在改对应结点的前驱结点和后继结点
class Node {
public:
    int val;
    Node* next;
    Node* pre;
    Node()
    {
        this->next = nullptr;
        this->pre = nullptr;
    }
};

class MyLinkedList {
public:
    /** Initialize your data structure here. */
    //头指针
    Node* head;
    //尾指针
    Node* tail;
    int size;
    MyLinkedList() {
        head = new Node();
       
        head->pre = nullptr;
        tail = new Node();
        head->next = tail;
        tail->pre = head;
        tail->next = nullptr;

        size = 0;
    }

    /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
    //返回值为-1有两种情况,坐标值小于0或者坐标值已经超过链表结点的最大个数
    int get(int index) {
        if (index<0 || index>size - 1)
            return -1;
        Node* temp = head;
        for (int i = 0; i <= index; i++)
        {
            temp = temp->next;
        }
        return temp->val;
    }

    /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
    void addAtHead(int val) {
        Node* newNode = new Node();
        newNode->val = val;
        newNode->next = head->next;
        newNode->pre = head;
        head->next->pre = newNode;
        head->next = newNode;
        size++;

    }

    /** Append a node of value val to the last element of the linked list. */
    void addAtTail(int val) {
        Node* temp = tail;
       
        Node* newNode = new Node();
        newNode->val = val;
        newNode->next = tail;
        newNode->pre = tail->pre;
        tail->pre->next = newNode;
        tail->pre = newNode;
        size++;
    }

    /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
    //坐标不符合增加的条件:坐标值小于0或者坐标值大于结点个数
    //坐标是从零开始的
    void addAtIndex(int index, int val) {
        if (index < 0 || index>size)
        {
            return;
        }
        Node* newNode = new Node();
        newNode->val = val;
        Node* temp = head;
        for (int i = 0; i < index; i++)
        {
            temp = temp->next;
        }
        newNode->next = temp->next;
        newNode->pre = temp;
        temp->next = newNode;
        newNode->next->pre = newNode;
        size++;


    }

    /** Delete the index-th node in the linked list, if the index is valid. */
    //不能删的条件:坐标值小于0或者坐标值大于结点个数-1
    void deleteAtIndex(int index) {
        Node* temp = head;
        if (index < 0 || index>size - 1)
        {
            return;
        }
        //找到这个结点
        for (int i = 0; i <= index; i++)
        {
            temp = temp->next;
        }
        //修改这个结点的前一个结点的next值
        temp->pre->next = temp->next;
        //修改这个结点的后一个结点的pre值
        temp->next->pre = temp->pre;
        size--;
    }
};

总结

合并两个有序的链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        //如果l1为空,返回l2
        if(l1==nullptr)
            return l2;
        //如果l2为空,返回l1
        if(l2==nullptr)
            return l1;
        //如果l1的第一个结点小于l2的第一个结点,那就把l1->next和l2合并,并且使l1->next为新合并的链表的头节点
        if(l1->val<l2->val)
        {
            ListNode* newHead=mergeTwoLists(l1->next,l2);
            l1->next=newHead;
            return l1;
        }
        else{
            ListNode * newHead=mergeTwoLists(l2->next,l1);
            l2->next=newHead;
            return l2;
        }
    }
    
};

两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/linked-list/fv6w7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *res=new ListNode();
        ListNode *temp1=l1;
        ListNode *temp2=l2;
        ListNode *temp=res;
        int flag=0;
        while(temp1||temp2)
        {                
            //记录结果数字当前位的值
            int cur=0;
            
            if(temp1==nullptr)
            {
                cur=temp2->val+flag;
                temp2=temp2->next;
            }
            else if(temp2==nullptr)
            {
                cur=temp1->val+flag;
                temp1=temp1->next;
            }          
            else 
            { 
                cur=temp1->val+temp2->val+flag;
                temp1=temp1->next;
                temp2=temp2->next;
                                        
            }
            //记录进位
            if(cur>=10)
            {
                cur=cur%10;
                flag=1;
            }
            else{
                flag=0;
            }
            //把当前位插入结果链表里
            ListNode *newNode=new ListNode();
            newNode->val=cur;
            temp->next=newNode;           
            temp=temp->next;           
        }
        //如果最后还有进位,则继续加一位
        if(flag==1)
        {
             ListNode *newNode=new ListNode();
         newNode->val=1;
         temp->next=newNode;
        }
        
        return res->next;

    }
};
  • 我只想到了暴力解法,把每一位相加

扁平化多级双向链表

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* prev;
    Node* next;
    Node* child;
};
*/

class Solution {
public:

    Node* flatten(Node* head) {
        if(head==nullptr)
            return head;
        //存储最后的链表的头节点
        Node* resHead=new Node();
        //遍历结果链表
        Node* resTemp=resHead;

        //创建一个栈,对整个链表进行深度遍历
        stack<Node*> sta;
        sta.push(head);
        while(!sta.empty())
        {
            Node*temp=sta.top();
            sta.pop();
            //如果前一个结点是空的,那就把这个结点加入到结果链表里
            if(temp->prev==nullptr)
            {
                resTemp->next=temp;
                
                resTemp=resTemp->next;
            }
            //如果next指针不是空的,就把next指向的结点压栈
            if(temp->next!=nullptr)
            {
                //每次压栈之前把下一个结点的前驱指针置空,表示当前节点已经统计过了
                temp->next->prev=nullptr;
                sta.push(temp->next);
            }
            //然后再把孩子结点压栈
            if(temp->child)
            {               
                sta.push(temp->child);
                temp->child=nullptr;               
            }
        }
        Node* temp=resHead;
        //因为是一个双链表,所以每一个结点的头指针都要指向前一个结点
        while(temp->next)
        {
            temp->child=nullptr;
            temp->next->prev=temp;
            temp=temp->next;
        }
        head=resHead->next;
        head->prev=nullptr;
        
        return head;
       
    }
};

复制带随即指针的链表

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/linked-list/fdi26/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
        map<Node*,Node*> mp;
        Node* temp=head;
        //构造一个map,依次存入原来的链表的结点和对应的值生成的新节点,也就是说这个map,键是原链表的结点,值是新链表的结点,两者是一一对应的
        while(temp)
        {
            Node* newNode=new Node(temp->val);
            mp.insert(pair<Node*,Node*>(temp,newNode));
            temp=temp->next;
        }
       
        //再对应把新的结点的关系连接好,键是什么关系,对应的值就是什么关系
         map<Node*,Node*>::iterator iter;
        iter = mp.begin();
        while(iter != mp.end()) {
            iter->second->next=mp[iter->first->next];
            iter->second->random=mp[iter->first->random];
            iter++;
        }
        return mp[head];
        
    }
};

旋转链表

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
         //空链表或者只有一个节点的链表转来转去还是原来的链表
        if(head==nullptr||head->next==nullptr||k==0)
        {
            return head;
        }
        //如果k比结点的个数大的话,相当于移动了k%size个数字
         ListNode *temp=head;
        int size=0;
        while(temp)
        {
            temp=temp->next;
            size++;
        }
        k=k%size;
        //k=0相当于没有转
        if(k==0)
        {
            return head;
        }
       
        //双指针,快指针指向头节点之后的k个元素,慢指针指向头节点
        ListNode *fast=head;
        ListNode *slow=head;
       
        
        while(k)
        {
            fast=fast->next;
            k--;
        }
        //然后快指针和慢指针依次往后移动,当快指针指到最后一个结点时,慢指针正好指向待求链表的最后一个节点
        while(fast->next)
        {
            fast=fast->next;
            slow=slow->next;
        }
        //此时慢指针的下一个结点就是待求链表的头节点
        ListNode* newHead=slow->next;
        //此时慢指针的下一个结点应该赋值为空,快指针的下一个结点应该指向原来的头节点
        fast->next=head;
        slow->next=nullptr;
        return newHead;
       

    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值