LeetCode 热题 100 | 链表(中下)

目录

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

2  24. 两两交换链表中的节点

3  25. K 个一组翻转链表

4  138. 随机链表的复制


菜鸟做题第三周,语言是 C++

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

到底是节点还是结点。。。

解题思路:

  1. 设置双指针 left 和 right
  2. 先让 right 右移 n 格
  3. 再让 left 和 right 一起右移直至 right 指向 nullptr
  4. left 将恰好处于被删除节点的前一个节点

思路说明图:

LeetCode 热题 100 | 链表(中下)_第1张图片

这个虚拟节点(dummy node)的设置非常巧妙,完美处理了被删除节点是头节点的情况。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode * dummy = new ListNode(0, head);
        ListNode * left = dummy, * right = head;

        for (int i = 0; i < n; ++i) {
            right = right->next;
        }
        while (right) {
            left = left->next;
            right = right->next;
        }
        left->next = left->next->next;
        return dummy->next;
    }
};

虽然不设置虚拟节点(dummy node)也能做,但是写 if 语句的模样真的很狼狈。

2  24. 两两交换链表中的节点

思路很简单,一组一组地交换即可,关键在于保存需要再次使用到的节点指针。

LeetCode 热题 100 | 链表(中下)_第2张图片

public:
    ListNode* swapPairs(ListNode* head) {
        ListNode * dummy = new ListNode(0, head);
        ListNode * prev = dummy, * post = nullptr;
        ListNode * left = head, * right = head ? head->next : nullptr;

        while (left && right) {
            post = right->next;
            right->next = left;
            left->next = post;
            prev->next = right;
            prev = left;
            left = post ? post : nullptr;
            right = post ? post->next : nullptr;
        }
        return dummy->next;
    }
};

说明:以下是为了防止指针越界而进行的判断

left = post ? post : nullptr;
right = post ? post->next : nullptr;

3  25. K 个一组翻转链表

是上一题的升级版。

解题思路:

  • 设置 prev、left、right、temp、next 指针
  • prev 用于保存上一组的尾巴
  • left 用于保存当前组的头部
  • right 和 temp 一起右移,对每一个指针进行反向

是不是看起来很烦,但确实可能要使用到很多指针。

我加了一个函数来判断剩余部分还能不能构成 K 个一组:

bool isEnough(ListNode * p, int k) {
    int count = 0;
    while (p && count < k) {
        p = p->next;
        ++count;
    }
    return count == k;
}

 其实思路也不难,就是容易转晕:

class Solution {
public:
    bool isEnough(ListNode * p, int k) {
        int count = 0;
        while (p && count < k) {
            p = p->next;
            ++count;
        }
        return count == k;
    }

    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode * dummy = new ListNode(0, head);
        ListNode * left = head, * right = head->next;

        ListNode * prev = dummy;
        while (isEnough(left, k)) {
            int count = 1;
            ListNode * temp = left;
            while (count < k) {
                ++count;
                ListNode * next = right->next;
                right->next = temp;
                temp = right;
                right = next;
            }
            prev->next = temp;
            prev = left;
            left->next = right;
            left = right;
            right = left ? left->next : nullptr;
        }
        return dummy->next;
    }
};

4  138. 随机链表的复制

这道题用递归真是太神奇了,可惜我不会。。。

class Solution {
public:
    unordered_map cachedNode;
    Node* copyRandomList(Node* head) {
        if (head == nullptr) return nullptr;

        if (!cachedNode.count(head)) {
            Node * headNew = new Node(head->val);
            cachedNode[head] = headNew;
            headNew->next = copyRandomList(head->next);
            headNew->random = copyRandomList(head->random);
        }
        return cachedNode[head];
    }
};

你可能感兴趣的:(力扣,leetcode,算法)