面试经典算法系列之链表3 -- 反转链表Ⅱ

面试经典算法9-反转链表Ⅱ

LeetCode.92
公众号:阿Q技术站

问题描述

给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表

示例 1:

img

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例 2:

输入:head = [5], left = 1, right = 1
输出:[5]

提示:

  • 链表中节点数目为 n
  • 1 <= n <= 500
  • -500 <= Node.val <= 500
  • 1 <= left <= right <= n

思路

  1. 创建虚拟头节点:首先,创建一个虚拟头节点 dummy,并将它的 next 指针指向原始链表的头节点 head。这样做的目的是为了处理反转部分的特殊情况,例如需要反转的部分从链表的头部开始。
  2. 定位需要反转的部分:使用两个指针 precur 分别指向需要反转部分的前一个节点和第一个节点。通过遍历链表,将 pre 移动到需要反转部分的前一个节点,将 cur 移动到需要反转的第一个节点。
  3. 反转链表部分:接下来,使用头插法将需要反转的部分进行反转操作。具体步骤如下:
    • 遍历需要反转的部分,每次取出当前节点 cur 的下一个节点 next
    • curnext 指针指向 next 的下一个节点,即断开 next 节点。
    • nextnext 指针指向 pre 的下一个节点,即将 next 节点插入到 pre 节点之后。
    • 更新 prenext 指针,将其指向 next,完成节点的插入操作。
  4. 返回反转后的链表:最后,返回虚拟头节点 dummynext 指针,即为反转后的链表头节点。

图解

  1. 初始状态,head = [1,2,3,4,5], left = 2, right = 4

image-20240205210822119

  1. 创建一个虚拟头节点,并初始化pre节点,cur节点。根据left确定pre和cur的位置。将 pre 移动到第一个要反转的节点的前面,将 cur 移动到第一个要反转的节点的位置上。我们就以 left=2right=4为例。

image-20240205214831022

  1. cur 后面的元素删除,然后添加到 pre 的后面,这里就跟反转链表的步骤一样了。

image-20240205220008932

  1. 重复步骤3

image-20240205220317346

  1. 返回反转后的链表头节点

参考代码

C++
#include <iostream>

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        if (left == right) {
            return head; // 如果 left 和 right 相等,不需要反转,直接返回头节点
        }

        ListNode *dummy = new ListNode(0); // 创建一个虚拟头节点,方便处理头部的特殊情况
        dummy->next = head;
        ListNode *pre = dummy; // pre 指向需要反转部分的前一个节点
        for (int i = 0; i < left - 1; ++i) {
            pre = pre->next;
        }

        ListNode *cur = pre->next; // cur 指向需要反转的第一个节点
        for (int i = 0; i < right - left; ++i) {
            ListNode *next = cur->next; // 记录下一个节点
            cur->next = next->next;      // 将当前节点的 next 指针指向下一个节点的下一个节点,断开 next 节点
            next->next = pre->next;      // 将 next 节点插入到 pre 节点之后
            pre->next = next;            // 更新 pre 的 next 指针,连接反转部分
        }

        return dummy->next; // 返回反转后的链表头节点
    }
};

void printList(ListNode *head) {
    ListNode *cur = head;
    while (cur != nullptr) {
        std::cout << cur->val << " ";
        cur = cur->next;
    }
    std::cout << std::endl;
}

int main() {
    ListNode *head = new ListNode(1);
    head->next = new ListNode(2);
    head->next->next = new ListNode(3);
    head->next->next->next = new ListNode(4);
    head->next->next->next->next = new ListNode(5);

    Solution solution;
    ListNode *newHead = solution.reverseBetween(head, 2, 4);

    printList(newHead); // 输出:1 4 3 2 5

    return 0;
}
Java
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        if (left == right) {
            return head; // 如果 left 和 right 相等,不需要反转,直接返回头节点
        }

        ListNode dummy = new ListNode(0); // 创建一个虚拟头节点,方便处理头部的特殊情况
        dummy.next = head;
        ListNode prev = dummy; // prev 指向需要反转部分的前一个节点
        for (int i = 0; i < left - 1; ++i) {
            prev = prev.next;
        }

        ListNode curr = prev.next; // curr 指向需要反转的第一个节点
        for (int i = 0; i < right - left; ++i) {
            ListNode next = curr.next; // 记录下一个节点
            curr.next = next.next;      // 将当前节点的 next 指针指向下一个节点的下一个节点,断开 next 节点
            next.next = prev.next;      // 将 next 节点插入到 prev 节点之后
            prev.next = next;            // 更新 prev 的 next 指针,连接反转部分
        }

        return dummy.next; // 返回反转后的链表头节点
    }
}

public class Main {
    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);

        Solution solution = new Solution();
        ListNode newHead = solution.reverseBetween(head, 2, 4);

        printList(newHead); // 输出:1 4 3 2 5
    }

    private static void printList(ListNode head) {
        ListNode curr = head;
        while (curr != null) {
            System.out.print(curr.val + " ");
            curr = curr.next;
        }
        System.out.println();
    }
}
Python
# 定义链表节点
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
        if left == right:
            return head  # 如果 left 和 right 相等,不需要反转,直接返回头节点

        dummy = ListNode(0)  # 创建一个虚拟头节点,方便处理头部的特殊情况
        dummy.next = head
        prev = dummy  # prev 指向需要反转部分的前一个节点
        for _ in range(left - 1):
            prev = prev.next

        curr = prev.next  # curr 指向需要反转的第一个节点
        for _ in range(right - left):
            next_node = curr.next  # 记录下一个节点
            curr.next = next_node.next  # 将当前节点的 next 指针指向下一个节点的下一个节点,断开 next 节点
            next_node.next = prev.next  # 将 next 节点插入到 prev 节点之后
            prev.next = next_node  # 更新 prev 的 next 指针,连接反转部分

        return dummy.next  # 返回反转后的链表头节点

def printList(head: ListNode) -> None:
    curr = head
    while curr:
        print(curr.val, end=" ")
        curr = curr.next
    print()

if __name__ == "__main__":
    head = ListNode(1)
    head.next = ListNode(2)
    head.next.next = ListNode(3)
    head.next.next.next = ListNode(4)
    head.next.next.next.next = ListNode(5)

    solution = Solution()
    new_head = solution.reverseBetween(head, 2, 4)

    printList(new_head)  # 输出:1 4 3 2 5
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值