Loading

05 反转链表

1 反转链表

image
image
image

1.1 代码实现

  1. 迭代做法
点击查看代码
/**
 * 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) {
        ListNode* pre = nullptr;
        ListNode* cur = head;
        while (cur != nullptr) {
            ListNode* nxt = cur->next;
            cur->next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;    
    }
};
- 时间复杂度:$$O(n)$$ - 空间复杂度:$$O(1)$$
  1. 递归做法
点击查看代码
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == nullptr || head->next == nullptr) {
            return head;
        }
        auto new_head = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return new_head;
        // 1->2->3->4->5
        // new_head 返回 5
        // 此时head = 4 5->4->nullptr
        // new_head 依旧是 5
        // 此时 head = 3 5->4->3->nullptr
    }
};
  • 时间复杂度:$$O(n)$$
  • 空间复杂度:$$O(n)$$

递归的做法还是不太好想。

2 反转链表 II

image
image

2.1 代码实现

点击查看代码
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode* dummyHead = new ListNode(0, head);
        // 需要找到需要反转的头结点的previous
        ListNode* p0 = dummyHead;
        for (int i = 0; i < left - 1; ++i) {
            p0 = p0->next;
        }
        ListNode* pre = nullptr;
        ListNode* cur = p0->next;
        for (int i = 0; i < right - left + 1; ++i) {
            ListNode* nxt = cur->next;
            cur->next = pre;
            pre = cur;
            cur = nxt;
        }
        // cur指向5,pre指向4
        p0->next->next = cur;
        p0->next = pre;
        return dummyHead->next;
    }
};
- 时间复杂度:$$O(n)$$ - 空间复杂度:$$O(1)$$

为什么需要new一个虚拟的头结点,这是因为如果left == 1不太好处理。

3 K个一组翻转链表

image
image
image

3.1 解题思路

由于剩下不足k个元素时是不能翻转的,所以我们可以先求出链表的长度。
翻转之前,先判断一下剩余节点的个数。

3.2 代码实现

点击查看代码
/**
 * 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* reverseKGroup(ListNode* head, int k) {
        ListNode* cur = head;
        int cnt = 0;
        // 1. 求出链表的总长度
        while (cur != nullptr) {
            cnt += 1;
            cur = cur->next;
        }
        // 2. 判断剩余要翻转的元素个数是否大于 k 个
        ListNode* dummy_head = new ListNode(0, head);
        ListNode* p0 = dummy_head;
        ListNode* pre = nullptr;
        while (cnt >= k) {
            cnt -= k;
            // 翻转k个元素
            pre = nullptr;
            cur = p0->next;
            for (int i = 0; i < k; ++i) {
                ListNode* nxt = cur->next;
                cur->next = pre;
                pre = cur;
                cur = nxt;
            }
            ListNode* temp = p0->next; // new p0
            p0->next->next = cur;
            p0->next = pre;
            p0 = temp;
        }
        return dummy_head->next;    
    }
};
  • 时间复杂度:$$O(n)$$
  • 空间复杂度:$$O(1)$$
posted @ 2025-12-26 08:55  王仲康  阅读(3)  评论(0)    收藏  举报