算法面试通关40讲 - 链表

三分学 七分练

leetcode 21 合并两个有序链表

尾插法 头结点

#include <iostream>
using namespace std;
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 *list1, ListNode *list2) {
        if (list1 == nullptr || list2 == nullptr) {
            return list1 == nullptr ? list2 : list1;
        }
        // tail insert
        ListNode header;
        ListNode *tail = &header;
        ListNode *tmp;
        while (list1 != nullptr && list2 != nullptr) {
            if (list1->val > list2->val) {
                tmp = list1;
                list1 = list2;
                list2 = tmp;
            }
            tail->next = list1;
            while (list1 != nullptr && list1->val <= list2->val) {
                tmp = list1;
                list1 = list1->next;
            }
            tail = tmp;
        }
        if (list1 == nullptr) {
            tmp->next = list2;
        }
        return header.next;
    }
};
int main() {
    ListNode list1_4(4);
    ListNode list1_2(2, &list1_4);
    ListNode list1_1(1, &list1_2);
    ListNode list2_4(4);
    ListNode list2_3(3, &list2_4);
    ListNode list2_1(1, &list2_3);
    Solution sol;
    ListNode *result = sol.mergeTwoLists(&list1_1, &list2_1);
}
leetcode 234 回文链表

双指针 快慢指针 头插法

class Solution {
   public:
    bool isPalindrome(ListNode *head) {
        ListNode *slow = head;
        ListNode *fast = head;
        //  1
        //  ^
        //  1 2 3 4 5 6 7
        //        ^     ^
        //  1 2 3 4 5 6 7 8
        //        ^     ^
        ListNode *tmp;
        while ((tmp = fast->next) != nullptr && (fast = tmp->next) != nullptr) {
            slow = slow->next;
        }
        //  1 2 3 4   5 6 7
        //        ^     ^
        fast = slow->next;
        slow->next = nullptr;
        while (fast != nullptr) {
            tmp = fast->next;

            fast->next = slow->next;
            slow->next = fast;

            fast = tmp;
        }
        fast = slow->next;
        while (fast != nullptr) {
            if (fast->val != head->val) return false;
            fast = fast->next;
            head = head->next;
        }
        return true;
    }
};
int main() {
    Solution sol;
    ListNode right1(1);
    ListNode right2(2, &right1);
    ListNode left2(2, &right2);
    ListNode left1(1, &left2);
    cout << sol.isPalindrome(&left1);
}
leetcode 142 环形链表 II

双指针 快慢指针
解析:假设快慢指针相逢的时候,慢指针走了\(slow = a + x\)\(a\)是圈外长度,\(x\)是慢指针圈内走过的节点数目),
快指针走了\(fast = 2 slow = a + y\)\(y\)是快指针圈内走过的节点数目),快指针比慢指针在圈内多走了\(fast - slow = slow = a + x = kb\)\(k\)为正整数,\(b\)为圈长),
由于\(slow\)是线性递增的,必然存在一个最小的\(k\)使得\(slow = kb\);这里\(k\)未必等于\(1\),原因是\(slow\)走过单个\(b\)的长度未必能跨过\(a\)的长度走入圈中:\(a + x = kb\)
\(slow + a = kb + a\)为慢指针转了正整数个圈走过的长度,所以只要在第一次快慢指针相遇的时候,让快指针重新回到起点与慢指针以相同速度前进,相遇点既是入口点。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *fast, *slow;
        fast = slow = head;
        while (fast != nullptr && (fast = fast->next) != nullptr) {
            fast = fast->next;
            slow = slow->next;
            if (fast == slow) {
                break;
            }
        }
        if (fast == nullptr) return nullptr;
        fast = head;
        while (fast != slow) {
            fast = fast->next;
            slow = slow->next;
        }
        return fast;
    }
};
leetcode 25 K 个一组翻转链表

头插法 头结点 链表截断/重连

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        //     v before_begin        v end
        //     --                    3  4  5
        //       1              2
        //       ^ begin        ^ tail
        if (k == 1) return head;
        ListNode header;
        header.next = head;
        ListNode *before_begin = &header;
        ListNode *ori_begin, *begin, *tail, *end, *tmp;
        while (true) {
            begin = before_begin->next;
            int kk = 0;
            for (tail = begin; tail != nullptr && ++kk != k;) {
                tail = tail->next;
            }
            //     v before_begin        v end
            //     --                    3  4  5
            //       1          2
            //       ^ begin    ^ tail   ^ tmp
            if (kk == k) {
                end = tail->next;
                tail = begin->next;
                begin->next = end;
                ori_begin = begin;
                while (tail != end) {
                    tmp = tail->next;
                    tail->next = begin;
                    before_begin->next = tail;
                    begin = tail;
                    tail = tmp;
                }
                before_begin = ori_begin;
            } else {
                break;
            }
        }
        return header.next;
    }
};
posted @ 2024-03-07 21:26  joel-q  阅读(2)  评论(0编辑  收藏  举报