• 链表小结


    链表总结

    链表基础

    如何实现一个单链表

    #include "bits/stdc++.h"
    
    using namespace std;
    struct MyListNode
    {
      int data;
      MyListNode *next;
      MyListNode(int left = -1, MyListNode *right = nullptr) : data(left), next(right) {}
    };
    
    class MyLinkedList
    {
    public:
      MyLinkedList() : m_size(0)
      {
        m_head = new MyListNode;
        m_tail = new MyListNode;
        m_head->next = m_tail; //初始化外部不可见节点,后续节点插入头尾之间
      }
      /**析构函数
    	~MyLinkedList()
    	{
    		MyListNode* p=m_head->next;
    		for(int i=0; i<m_size; i++)
    		{
    			MyListNode* p2=p;
    			p=p->next;
    			delete p2;
    		}
    		delete m_head;
    		delete m_tail;
    	}*/
      MyListNode *reverse(MyListNode *head)
      {
        if (head == nullptr || head->next == nullptr)
        {
          return head;
        }
        MyListNode *next = head->next;
        MyListNode *newHead = reverse(next);
        next->next = head;
        head->next = nullptr;
        return newHead;
      }
      // api=> get
      int get(int index)
      {
        if (index < 0 || index > m_size - 1) //入口参数合法性检验
          return -1;
        MyListNode *p = findpre(index);
        return p->next->data;
      }
    
      MyListNode *getHead()
      {
        return findpre(1);
      }
      // api=>addAtHead
      void addAtHead(int val)
      {
        insert(0, val); //三个插入接口统一成一般形式
      }
      // api=>addAtTail
      void addAtTail(int val)
      {
        insert(m_size, val);
      }
      // api=>addAtIndex
      void addAtIndex(int index, int val)
      {
        if (index > m_size) //入口参数调整取值0~链表长度
          return;
        if (index < 0)
          index = 0;
        insert(index, val);
      }
      // api=>deleteAtIndex
      void deleteAtIndex(int index)
      {
        if (index < 0 || index > m_size - 1)
          return; //入口参数合法性检验
        MyListNode *p = findpre(index);
        MyListNode *curNode = p->next;
        p->next = p->next->next;
        m_size--;
        delete curNode;
      }
      // helper method
      void printList()
      {
        for (int i = 0; i < m_size; i++)
        {
          cout << get(i) << " ";
        }
      }
    
    private:
      MyListNode *findpre(int index)
      {
        MyListNode *p = m_head;
        while (index != 0)
        {
          p = p->next;
          index--;
        }
        return p;
      }
      void insert(int index, int val)
      {
        MyListNode *preNode = findpre(index);
        MyListNode *afterNode = preNode->next;
        MyListNode *currNode = new MyListNode;
        preNode->next = currNode;
        currNode->next = afterNode;
        currNode->data = val;
        m_size++;
      }
      MyListNode *m_head;
      MyListNode *m_tail;
      int m_size;
    };
    
    int main()
    {
      MyLinkedList *linkedList = new MyLinkedList();
      linkedList->addAtHead(1);
      linkedList->addAtTail(3);
      linkedList->addAtIndex(1, 2); //链表变为1-> 2-> 3
      linkedList->printList();
      cout << linkedList->get(1) << endl; //返回2
      linkedList->deleteAtIndex(1);       //现在链表是1-> 3
      linkedList->printList();
      cout << linkedList->get(1) << endl; //返回3
    }
    

    如何实现一个简单的双链表

    struct MyListNode{
        int val;
        MyListNode *next;
        MyListNode *prev;
        MyListNode(int x=-1, MyListNode* left = nullptr,MyListNode* right =nullptr): val(x), prev(left), next(right) {}
    };
    class MyLinkedList {
    private:
        MyListNode *m_head;
        //MyListNode *m_tail;
        int m_size;
        MyListNode *findNode(int index){
            MyListNode *p = m_head->next;
            while(index!=0){
                p = p->next;
                index--;
            }
            return p;
        }
    public:
        /** Initialize your data structure here. */
        MyLinkedList():m_size(0) {
            m_head = new MyListNode;
            //m_tail = new MyListNode;
            m_head -> next = m_head->prev=m_head;
            
        }
        
        /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
        int get(int index) {
            if(index<0 || index>=m_size){
                return -1;
            }
            MyListNode *p = findNode(index);
            return p->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) {
            MyListNode *cur = new MyListNode(val,m_head,m_head->next);
            m_head->next->prev = cur;
            m_head->next = cur;
            m_size++;
        }
        
        /** Append a node of value val to the last element of the linked list. */
        void addAtTail(int val) {
            MyListNode *cur = new MyListNode(val,m_head->prev,m_head);
            m_head->prev->next = cur;
            m_head->prev = cur;
            m_size +=1;
        }
        
        /** 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. */
        void addAtIndex(int index, int val) {
            if(index>m_size) return;
            if(index<0) index = 0;
            MyListNode *p = findNode(index);
            MyListNode *pre = p->prev;
            MyListNode *newNode = new MyListNode(val,pre,p);
            pre->next = newNode;
            p->prev = newNode;
            m_size+=1;
        }
        
        /** Delete the index-th node in the linked list, if the index is valid. */
        void deleteAtIndex(int index) {
            if(index<0||index>=m_size){
                return;
            }
            MyListNode *p = findNode(index);
            MyListNode *pre = p->prev;
            MyListNode *after = p->next;
            pre->next = p->next;
            after->prev = p->prev;
            delete p;
            m_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);
     */
    

    双指针法

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

    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos-1,则在该链表中没有环。

    示例 1:

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

    img

    /**
     * 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) {
            bool flag = false;
            ListNode *slow = head;
            ListNode *fast = head;
            while(fast && fast->next){
                slow = slow->next;
                fast = fast->next->next;
                if(slow==fast){
                    return true;
                }
            }
            return false;
        }
    };
    

    2.给定一个链表,返回链表开始入环的第一个节点。

    如果链表无环,则返回 null

    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos-1,则在该链表中没有环。

    说明:不允许修改给定的链表。

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode *getMeet(ListNode *head){
            ListNode *slow = head;
            ListNode *fast = head;
            while(fast && fast->next){
                slow = slow -> next;
                fast = fast -> next ->next;
                if(fast == slow){
                    return slow;
                }
            }
            return NULL;
        }
        ListNode *detectCycle(ListNode *head) {
            ListNode * meet = getMeet(head);
            if(meet==nullptr) return NULL;
            ListNode *cur = head;
            
            while(meet&&cur){
                if(cur==meet){
                    return cur;
                }
                cur=cur->next;
                meet = meet->next;
            }
            return NULL;
        }
    };
    

    3.相交链表

    编写一个程序,找到两个单链表相交的起始节点。

    如下面的两个链表

    img

    在节点 c1 开始相交。

    示例 1:

    img

    输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
    输出:Reference of the node with value = 8
    输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
    
    /**
    * 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 * l1 = headA;
           ListNode * l2 = headB;
           while(l1!=l2){
               l1 = (l1==nullptr)?headB:l1->next;
               l2 = (l2==nullptr)?headA:l2->next;
           }
           return l1;
       }
    };
    

    4. 删除倒数第N个节点

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* removeNthFromEnd(ListNode* head, int n) {
            ListNode* fast = head;
            ListNode* slow = head;
            while(n-->0){
                fast=fast->next;
            }
            if(fast==nullptr) return head->next;
            while(fast->next){
                fast = fast->next;
                slow = slow->next;
            }
            slow->next = slow->next->next;
            return head;
        }
    };
    

    经典问题

    1. 反转链表

    206. Reverse Linked List (Easy)

    头插法

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* reverseList(ListNode* head) {
            ListNode *newHead = new ListNode(-1);
            while(head){
                ListNode *next = head->next;
                head->next = newHead->next;
                newHead->next = head;
                head = next;
            }
            return newHead->next;
        }
    };
    

    递归

    class Solution{
        public:
        ListNode *reverseList(ListNode* head){
            if(!head||!head->next){
                return head;
            }
            ListNode *nextNode = head->next;
            ListNode *newHead = reverseList(head->next);
            nextNode->next = head;
            head->next = nullptr;
            return newHead;
        }   
    }
    

    2. 奇偶链表

    328. Odd Even Linked List (Medium)

    Example:
    		Given 1->2->3->4->5->NULL,
    		return 1->3->5->2->4->NULL.
    
    class Solution {
    public:
        ListNode* oddEvenList(ListNode* head) {
            if(head==nullptr) return nullptr;
            ListNode* odd=head,*even=head->next,*evenHead = even;
            while(even && even->next){
                odd->next = odd->next->next;
                odd = odd->next;
                even->next = even->next->next;
                even = even->next;
            }
            odd->next = evenHead;
            return head;
        }
    };
    

    3. 回文链表

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

    示例 1:

    输入: 1->2
    输出: false
    

    示例 2:

    输入: 1->2->2->1
    输出: true
    

    进阶:
    你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

    class Solution {
    public:
        bool isPalindrome(ListNode* head) {
            if(head==nullptr || head->next == nullptr){
                return true;
            }
            ListNode *slow =head,*fast = head->next;
            while(fast && fast->next){
                slow = slow->next;
                fast = fast->next->next;
            }
            if(fast!=nullptr){
                slow = slow->next;
            }
            cut(head,slow);
            return isEqual(head,reverse(slow));
        }
        bool isEqual(ListNode* l1, ListNode* l2){
            while(l1 && l2){
                if(l1->val!=l2->val) return false;
                l1 = l1->next;
                l2 = l2->next;
            }
            return true;
        }
        ListNode* reverse(ListNode* head){
            ListNode* newHead = new ListNode(-1);
            while(head){
                ListNode* next = head->next;
                head->next = newHead->next;
                newHead->next = head;
                head = next;
            }
            return newHead->next;
        }
        void cut(ListNode* head, ListNode* cutNode){
            while(head->next!=cutNode){
                head = head->next;
            }
            head->next=nullptr;
        }
    };
    

    4. 交换链表中的相邻节点

    ListNode *swapPairs(ListNode *head)
    {
      ListNode *node = new ListNode(-1);
      node->next = head;
      ListNode *pre = node;
      while (pre->next != nullptr && pre->next->next != nullptr)
      {
        ListNode *l1 = pre->next, *l2 = pre->next->next;
        ListNode *next = l2->next;
        l1->next = next;
        l2->next = l1;
        pre->next = l2;
    
        pre = l1;
      }
      return node->next;
    }
    

    5. 合并两个有序链表

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

    示例:

    输入:1->2->4, 1->3->4
    输出:1->1->2->3->4->4
    
    class Solution {
    public:
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
            if(l1==nullptr){
                return l2;
            }
            if(l2==nullptr){
                return l1;
            }
            if(l1->val<l2->val){
                l1->next = mergeTwoLists(l1->next,l2);
                return l1;
            }else{
                l2->next = mergeTwoLists(l1,l2->next);
                return l2;
            }
        }
    };
    

    6.链表求和

    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

    如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

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

    示例:

    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807
    
    class Solution {
    public:
      ListNode *addTwoNumbers(ListNode *l1, ListNode *l2)
      {
        ListNode *newHead = new ListNode(-1);
        ListNode *p = newHead;
        int carry = 0;
        while (l1 || l2 || carry != 0)
        {
          int x = l1 ? l1->val : 0;
          int y = l2 ? l2->val : 0;
          int sum = x + y + carry;
          ListNode *node = new ListNode(sum % 10);
          p->next = node;
          p=p->next;
          if(l1) l1=l1->next;
          if(l2) l2=l2->next;
          carry = sum / 10;
        }
        return newHead->next;
      }
    
    };
    

    7. 删除重复节点

    class Solution {
    public:
        ListNode* deleteDuplicates(ListNode* head) {
            if(!head || !head->next) return head;
            head->next = deleteDuplicates(head->next);
            return head->val == head->next->val ? head->next : head;
        }
    };
    
  • 相关阅读:
    设计模式:代理模式/中介者模式 / 桥接模式/适配器
    手把手教Qt Creator插件开发-QT运行计时器
    使用QT维护工具
    QDir+QTreeWidget (QViewWidget) 展示文件系统树形目录
    NUCLEO-L496ZG+Gokit3S+Rtthead+AT组件组网
    stm32CubeMX 结合Rtthread Env做BSP框架
    某个师兄教会了我,面对着沉重的科研任务,即使做一条咸鱼,也要做一条快乐的有梦想的咸鱼。哈哈哈
    经济金融的应用层______是什么呢___数量计算是底层吗?_____计算机的应用层___软件应用_____二进制运算是最底层__c/cpp都没有到计算了
    究竟是利己推动了社会进步还是利他推动了社会进步____经济学中的利己与利他,斯密在他的经济学着作《国民财富的性质和原因的研究》,究竟是利己推动了社会进步还是利他推动了社会进步
    1. 好好吃药 2. 多接触社会 3. 多跑路 4. 多打炮 【 在ethershock imm.mitbbs.com › 33126389
  • 原文地址:https://www.cnblogs.com/jiaweixie/p/13276376.html
Copyright © 2020-2023  润新知