zoukankan      html  css  js  c++  java
  • 【leetcode】链表相关题目思路总结(更新中)

    简单题

    206. 反转链表

    剑指 Offer 24. 反转链表

    https://leetcode-cn.com/problems/reverse-linked-list/
    https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/submissions/

    题目描述:
    反转链表。

    解题思路:
    借助几个临时指针。一个prev,一个curr,一个temp,然后不断做赋值互换即可。

    代码:

    /**
     * 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* prev = nullptr;
            ListNode* curr = head;
            ListNode* temp;
            while(curr) {
                temp = curr->next;
                curr->next = prev;
                prev = curr;
                curr = temp;
            }
            return prev;
        }
    };
    

    21. 合并两个有序链表

    https://leetcode-cn.com/problems/merge-two-sorted-lists/

    题目描述:
    合并两个有序链表。

    解题思路:
    比较两个链表的头指针的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* mergeTwoLists(ListNode* l1, ListNode* l2) {
            ListNode rst(0);
            ListNode* temp = &rst;
            while(l1 && l2) {
                if (l1->val < l2->val) {
                    temp->next = l1;
                    l1 = l1->next;
                } else {
                    temp->next = l2;
                    l2 = l2->next;
                }
                temp = temp->next;
            }
            if (l1) {
                temp->next = l1;
            }
            if (l2) {
                temp->next = l2;
            }
            return rst.next;
        }
    };
    

    面试题 02.07. 链表相交

    剑指 Offer 52. 两个链表的第一个公共节点

    160. 相交链表

    https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/
    https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/
    https://leetcode-cn.com/problems/intersection-of-two-linked-lists/

    题目描述:
    两个长度不同的链表,从某个节点开始相交,后面的都是一样的。

    解题思路:
    先将两个链表长度对齐,然后遍历比较,找到的第一个一样的就是所求。

    代码:

    /**
     * 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) {
            int len_list1 = 0;
            int len_list2 = 0;
            ListNode* tempA;
            ListNode* tempB;
            tempA = headA;
            while(tempA) {
                tempA = tempA->next;
                len_list1 += 1;
            }
            tempB = headB;
            while(tempB) {
                tempB = tempB->next;
                len_list2 += 1;
            }
    
            tempA = headA;
            tempB = headB;
            while (len_list2 < len_list1) {
                tempA = tempA->next;
                len_list1 -= 1;
            }
            while(len_list1 < len_list2) {
                tempB = tempB->next;
                len_list2 -= 1;
            }
    
            for (int i = 0; i < len_list1; i++) {
                if (tempA == tempB) {
                    return tempA;
                }
                tempA = tempA->next;
                tempB = tempB->next;
            }
            return nullptr;
        }
    };
    

    面试题 02.01. 移除重复节点

    https://leetcode-cn.com/problems/remove-duplicate-node-lcci/

    题目描述:
    将链表中的重复元素删除,并不改变链接顺序。

    解题思路:
    方法一,使用哈希表,时间空间复杂度均为O(n)。
    方法二,循环遍历,时间复杂度O(n^2),空间O(1)。

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* removeDuplicateNodes(ListNode* head) {
            set<int> data;
            ListNode* temp = head;
            ListNode* temp2 = new ListNode(0);
            ListNode* rst = temp2; 
            while(temp) {
                if (data.find(temp->val) == data.end()) {
                    data.insert(temp->val);
                    temp2->next = temp;
                    temp2 = temp2->next;
                }
                temp = temp->next;
            }
            temp2->next = nullptr;
            return rst->next;
        }
    };
    

    剑指 Offer 22. 链表中倒数第k个节点

    面试题 02.02. 返回倒数第k个节点

    https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/
    https://leetcode-cn.com/problems/kth-node-from-end-of-list-lcci/

    题目描述:
    找出链表的倒数第k个节点。

    解题思路:
    用双指针,一个比另外一个快k步。

    代码:

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

    234. 回文链表

    面试题 02.06. 回文链表

    https://leetcode-cn.com/problems/palindrome-linked-list/
    https://leetcode-cn.com/problems/palindrome-linked-list-lcci/

    题目描述:
    判断链表是否对称。

    解题思路:
    方法一,将数据复制到数组中,然后双指针。
    方法二,将后半部分链表反转,然后再遍历判断,之后再将后半部分恢复。

    代码:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        bool isPalindrome(ListNode* head) {
            if (!head) {
                return true;
            }
            ListNode* fast;
            ListNode* slow;
            ListNode* prev;
            fast = head;
            slow = head;
            while(fast) {
                fast = fast->next;
                if (fast) {
                    fast = fast->next;
                }
                prev = slow;
                slow = slow->next;
            }
    
            ListNode* save_ptr = reverseList(slow);
            ListNode* rev_ptr = save_ptr;
            ListNode* ptr = head;
            while(rev_ptr && ptr) {
                if (rev_ptr->val != ptr->val) {
                    return false;
                }
                rev_ptr = rev_ptr->next;
                ptr = ptr->next;
            }
    
            ListNode* now_ptr = reverseList(save_ptr);
            prev->next = now_ptr;
            return true;
        }
    
        ListNode* reverseList(ListNode* head) {
            ListNode* prev = nullptr;
            ListNode* curr = head;
            while(curr) {
                ListNode* temp = curr->next;
                curr->next = prev;
                prev = curr;
                curr = temp;
            }
            return prev;
        }
    };
    

    面试题 02.03. 删除中间节点

    237. 删除链表中的节点

    https://leetcode-cn.com/problems/delete-middle-node-lcci/
    https://leetcode-cn.com/problems/delete-node-in-a-linked-list/

    题目描述:
    删除链表中的某个节点。

    解题思路:
    假设链表为A->B->C->D,删除B,将B变为C即可,改变B的next,val。

    代码:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void deleteNode(ListNode* node) {
            node->val = node->next->val;
            node->next = node->next->next;
        }
    };
    

    83. 删除排序链表中的重复元素

    https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/

    题目描述:
    删除链表中的重复元素。

    解题思路:
    判断当前节点和下一个节点的值是否相等,相等则将当前节点的next域直接指向下下个节点(就是丢掉下个节点)。

    代码:

    /**
     * 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) {
            ListNode* rst = head;
            while(head && head->next) {
                if (head->val == head->next->val) {
                    head->next = head->next->next;
                } else {
                    head = head->next;
                }
            }
            return rst;
        }
    };
    

    剑指 Offer 06. 从尾到头打印链表

    https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/

    题目描述:
    逆序打印链表值。

    解题思路:
    借助栈搞定。

    代码:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> reversePrint(ListNode* head) {
            stack<int> data;
            vector<int> rst;
            while(head) {
                data.push(head->val);
                head = head->next;
            }
            while(!data.empty()) {
                rst.push_back(data.top());
                data.pop();
            }
            return rst;
        }
    };
    

    203. 移除链表元素

    剑指 Offer 18. 删除链表的节点

    https://leetcode-cn.com/problems/remove-linked-list-elements/
    https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/

    题目描述:
    删除链表中和给定值相同的元素。

    解题思路:
    因为头结点也可能会被删除,所以应当设置一个哨兵指针。

    代码:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* removeElements(ListNode* head, int val) {
            ListNode* pre = new ListNode(0);
            ListNode* save = pre;
            pre->next = head;
            while(pre->next) {
                if (pre->next->val == val) {
                    pre->next = pre->next->next; 
                } else {
                    pre = pre->next;
                }
            }
            return save->next;
        }
    };
    

    1474. 删除链表 M 个节点之后的 N 个节点

    https://leetcode-cn.com/problems/delete-n-nodes-after-m-nodes-of-a-linked-list/

    题目描述:
    先保留M个,再删掉N个,再保留M个,再删掉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* deleteNodes(ListNode* head, int m, int n) {
            ListNode* pre = new ListNode(0);
            pre->next = head;
            ListNode* save = pre;
            while(pre->next) {
                int temp_m = m;
                int temp_n = n;
                while(pre->next && temp_m > 0) {
                    pre = pre->next;
                    temp_m -= 1;
                }
                while(pre->next && temp_n > 0) {
                    pre->next = pre->next->next;
                    temp_n -= 1;
                }
            }
            return save->next;
        }
    };
    

    876. 链表的中间结点

    https://leetcode-cn.com/problems/middle-of-the-linked-list/

    题目描述:
    求链表最中间的节点,如果有两个,则选择后面一个。

    解题思路:
    采用快慢指针法最好。

    代码:

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

    1290. 二进制链表转整数

    https://leetcode-cn.com/problems/convert-binary-number-in-a-linked-list-to-integer/

    题目描述:
    用链表表示二进制的每位数字,要求转成10进制。

    解题思路:
    模拟题,遍历一遍,一边遍历一边转即可。

    代码:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        int getDecimalValue(ListNode* head) {
            int sum = 0;
            while(head) {
                sum = sum*2 + head->val;
                head = head->next;
            }
            return sum;
        }
    };
    

    141. 环形链表

    https://leetcode-cn.com/problems/linked-list-cycle/

    题目描述:
    判断一个链表是否有环。

    解题思路:
    快慢指针法,如果快慢指针跑着跑着跑到同一个节点了,那么必然是有环。

    代码:

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

    中等题

    1669. 合并两个链表

    https://leetcode-cn.com/problems/merge-in-between-linked-lists/

    题目描述:
    将其中一个链表删去一段,然后接上另外一个链表。

    解题思路:
    把握关键节点,两个连接处的左右两个节点,要加以保存,然后连接即可。

    代码:

    /**
     * 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* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) {
            ListNode* pre = new ListNode(0);
            pre->next = list1;
            ListNode* save = pre;
            ListNode* left;
            ListNode* right;
            int i = 0;
            while(pre->next) {
                if (i == a) {
                    left = pre;
                }
                if (i == b) {
                    right = pre->next->next;
                }
                i += 1;
                pre = pre->next;
            }
            left->next = list2;
            pre = new ListNode(0);
            pre->next = list2;
            while(pre->next) {
                pre = pre->next;
            }
            pre->next = right;
            return save->next;
        }
    };
    

    92. 反转链表 II

    https://leetcode-cn.com/problems/reverse-linked-list-ii/

    题目描述:
    反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

    解题思路:
    除了m和n位置的节点外,m-1和n+1位置的节点也要保存,这样的话,就退化为了简单版本的反转链表,最后接起来就可以了。
    注意m-1为空的情况,即从第一个节点开始逆置。

    代码:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* reverseBetween(ListNode* head, int m, int n) {
            int change_len = n - m + 1; // 需要逆序的长度
            ListNode* result = head; // 最终返回
            // ... pre_head head ... 
            ListNode* pre_head = NULL; 
            while(head && --m) {
                pre_head = head;
                head = head->next;
            }
            // ... modify_list_tail head ...
            ListNode* modify_list_tail = head;
            ListNode* new_head = NULL;
            // head - next - -
            // new_head - - -
            while(head && change_len) {
                ListNode* next = head->next;
                head->next = new_head;
                new_head = head;
                head = next;
                change_len--;
            }
            modify_list_tail->next = head;
            if (pre_head) {
                // 并非从第一个节点开始逆序
                pre_head->next = new_head;
            } else {
                result = new_head;
            }
            return result;
        }
    };
    

    142. 环形链表 II

    面试题 02.08. 环路检测

    https://leetcode-cn.com/problems/linked-list-cycle-ii/
    https://leetcode-cn.com/problems/linked-list-cycle-lcci/

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

    解题思路:
    这道题和环形链表的简单题思路大体相同,只不过最后要返回入环点。
    有两种方法,一是直接用set,二是用快慢指针。

    代码:

    /**
     * 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;
            ListNode* meet = NULL;
            while(fast) {
                fast = fast->next;
                slow = slow->next;
                if (!fast) {
                    return NULL;
                }
                fast = fast->next;
                if (fast == slow) {
                    meet = fast;
                    break;
                }
            }
            if (!meet) {
                return NULL;
            }
            while (head && meet) {
                if (head == meet) {
                    return meet;
                }
                head = head->next;
                meet = meet->next;
            }
            return NULL;
        }
    };
    

    86. 分隔链表

    面试题 02.04. 分割链表

    https://leetcode-cn.com/problems/partition-list/
    https://leetcode-cn.com/problems/partition-list-lcci/

    题目描述:
    给你一个链表和一个特定值 x ,请你对链表进行分隔,使得所有小于 x 的节点都出现在大于或等于 x 的节点之前。
    你应当保留两个分区中每个节点的初始相对位置。

    解题思路:
    模拟法,使用两个临时链表,分别保存比x大的,和比x小的,最后接起来就行。

    代码:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* partition(ListNode* head, int x) {
            ListNode less_head(0);
            ListNode more_head(0);
            ListNode* less_ptr = &less_head;
            ListNode* more_ptr = &more_head;
            while(head) {
                if (head->val < x) {
                    less_ptr->next = head;
                    less_ptr = less_ptr->next;
                } else {
                    more_ptr->next = head;
                    more_ptr = more_ptr->next;
                }
                head = head->next;
            }
            less_ptr->next = more_head.next;
            more_ptr->next = NULL;
            return less_head.next;
        }
    };
    

    138. 复制带随机指针的链表

    剑指 Offer 35. 复杂链表的复制

    https://leetcode-cn.com/problems/copy-list-with-random-pointer/
    https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/

    题目描述:
    请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

    解题思路:
    保存节点地址-序号的映射(map),序号-节点地址的映射(vector),遍历两遍,就完成了链表复制。注意其中random指针为空的情形加判断条件。

    代码:

    /*
    // 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*, int> node_map;
            vector<Node*> node_vec;
            Node* ptr = head;
            int i = 0;
            while(ptr) {
                node_vec.push_back(new Node(ptr->val));
                node_map[ptr] = i;
                i++;
                ptr = ptr->next;
            }
            node_vec.push_back(0);
            ptr = head;
            i = 0;
            while(ptr) {
                node_vec[i]->next = node_vec[i+1];
                if (ptr->random) {
                    node_vec[i]->random = node_vec[node_map[ptr->random]];
                }
                ptr = ptr->next;
                i++;
            }
            return node_vec[0];
        }
    };
    

    困难题

    23. 合并K个升序链表

    https://leetcode-cn.com/problems/merge-k-sorted-lists/

    题目描述:
    给你一个链表数组,每个链表都已经按升序排列。
    请你将所有链表合并到一个升序链表中,返回合并后的链表。

    解题思路:
    方法一:暴力解法,依次合并链表,(n+n)+(n+2n)+...+[n+(k-1)n],时间复杂度为O(nk^2),空间复杂度O(1)。
    方法二:先放到vector里,排序,然后再构造链表,knlog(kn)+kn,时间复杂度O(knlogkn),空间复杂度O(kn)。
    方法三:两两合并,分治法。2nk/2+4nk/4+8nk/8+...,时间复杂度O(knlogk),空间复杂度O(logk),递归用到的栈空间。
    方法四:使用优先级队列,始终维护k个数,每次取出最小值后,将其后的节点插入。时间复杂度O(kn*logk),空间复杂度O(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* mergeKLists(vector<ListNode*>& lists) {
            if (lists.size() == 0) {
                return NULL;
            }
            if (lists.size() == 1) {
                return lists[0];
            }
            if (lists.size() == 2) {
                return mergeTwoLists(lists[0], lists[1]);
            }
            int mid = lists.size() / 2;
            vector<ListNode*> lists_vec1;
            vector<ListNode*> lists_vec2;
            for (int i = 0; i < mid; i++) {
                lists_vec1.push_back(lists[i]);
            }
            for (int i = mid; i < lists.size(); i++) {
                lists_vec2.push_back(lists[i]);
            }
            ListNode* lists1 = mergeKLists(lists_vec1);
            ListNode* lists2 = mergeKLists(lists_vec2);
            return mergeTwoLists(lists1, lists2);
        }
    
        ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
            ListNode temp_head(0);
            ListNode* pre = &temp_head;
            while(list1 && list2) {
                if (list1->val < list2->val) {
                    pre->next = list1;
                    list1 = list1->next;
                } else {
                    pre->next = list2;
                    list2 = list2->next;
                }
                pre = pre->next;
            }
            if (list1) {
                pre->next = list1;
            }
            if (list2) {
                pre->next = list2;
            }
            return temp_head.next;
        }
    };
    
  • 相关阅读:
    自定义 sql Split函数 / 自定义mp_helptext查看存储
    easyUI 节点树选择
    EasyUI手风琴 Tab卡使用
    水晶报表分组,统计,求和,sum()函数使用
    华硕GL502VSK处理器使用XTU降压。
    .
    bootstrap4元素居左居右
    关于npm run dev报错npm ERR! missing script: dev
    使用Vue写一个登陆页面并在管理页面查看和修改
    localStorage注册页面A注册数据在本地储存并在B页面打开
  • 原文地址:https://www.cnblogs.com/yanqiang/p/14129527.html
Copyright © 2011-2022 走看看