前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >反转链表 II !

反转链表 II !

作者头像
五分钟学算法
发布2021-12-21 16:57:35
6060
发布2021-12-21 16:57:35
举报
文章被收录于专栏:五分钟学算法
题目描述

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

吴师兄的参考思路

1、构建一个虚拟节点,让它指向原链表的头节点。

2、设置两个指针,pre 指针指向以虚拟头节点为链表的头部位置,cur 指针指向原链表的头部位置。

3、让着两个指针向前移动,直到 pre 指向了第一个要反转的节点的前面那个节点,而 cur 指向了第一个要反转的节点。

4、开始指向翻转操作

  • 1)、设置临时变量 temp,temp 是 cur 的 next 位置,保存当前需要翻转节点的后面的节点,我们需要交换 temp 和 cur
  • 2)、让 cur 的 next 位置变成 temp 的下一个节点
  • 3)、让 temp 的 next 位置变成 cur
  • 4)、让 pre 的 next 位置变成 temp

吴师兄的参考代码

1、Java 代码

代码语言:javascript
复制
// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// 反转链表 II ( LeetCode 92 ):https://leetcode-cn.com/problems/reverse-linked-list-ii
class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        
        // 一开始设置一个虚拟节点,它的值为 -1,它的值可以设置为任何的数,因为我们根本不需要使用它的值
        // 设置虚拟节点的目的是为了让原链表中所有节点就都可以按照统一的方式进行翻转
        // 比如如果翻转的区间包含了原链表中的第一个位置,那么如果不设置 dummy
        // 在翻转的过程中需要设置其它的临时变量来保持第一位置节点的指针
        // 具体可以通过动画来理解
        ListNode dummy = new ListNode(-1);

        // 让虚拟节点指向原链表的头部
        dummy.next = head;
        
        // 设置一个指针,指向以虚拟头节点为链表的头部位置
        ListNode pre = dummy;

        // 设置一个指针,指向原链表的头部位置

        ListNode cur = head;


        // 从虚拟头节点出发,pre 走 left - 1 步找到需要翻转的左区间
        // for 循环结束后,pre 的右节点是需要翻转的节点
        // for 循环结束后,cur 指向的就是需要翻转的节点
        for (int i = 0; i < left - 1; i++) {
           

            // pre 不断的向右移动,直到走到翻转的左区间为止
            pre = pre.next;
            // cur 不断的向右移动,找到了需要翻转的第一个节点
            cur = cur.next;
        }

        // 开始翻转这些节点
        for (int i = 0; i < right - left; i++) {
            
            // 设置临时变量,保存当前需要翻转节点的后面的节点
            ListNode temp = cur.next;

            // 这个时候,让 temp 和 cur 两个节点翻转一下
            // 比如,一开始 i = 0 的时候 cur 为 2, temp 为 3
            // 执行完下面的代码,如果原链表是
            // 1 --> 2 --> 3 --> 4 --> 5
            // 变成了
            // 1 --> 3 --> 2 --> 4 --> 5
            
            // cur 的下一节点是等号右侧的值
            // i = 0 的时候, cur 为 2,cur.next.next 的值是 4
            // 所以,这行代码让 cur 的下一节点不是 3 ,而是 4 
            // 2 --> 4
            // 等价于 cur.next = temp.next
            cur.next = cur.next.next;

            // temp 的下一节点是等号右侧的值
            // i = 0 的时候, temp 为 3,pre 为 1,pre 下一节点的值是 2
            // 所以,这行代码让 temp 的下一节点不是 4 ,而是 2 
            // 3 --> 2
            temp.next = pre.next;

            // pre 的下一节点是等号右侧的值
            // i = 0 的时候, pre 为 1,temp 的值是 3
            // 所以,这行代码让 pre 的下一节点为 3
            // 1 --> 3
          
            pre.next =temp;

            // i = 0 结束之后,链表变成了
            // 1 --> 3 --> 2 --> 4 --> 5
           
        }

        // 最后返回虚拟头节点的下一个节点,因为虚拟节点不在链表中
        return dummy.next;
    }
}

2、C++ 代码

代码语言:javascript
复制
// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// 反转链表 II ( LeetCode 92 ):https://leetcode-cn.com/problems/reverse-linked-list-ii
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        // 一开始设置一个虚拟节点,它的值为 -1,它的值可以设置为任何的数,因为我们根本不需要使用它的值
        // 设置虚拟节点的目的是为了让原链表中所有节点就都可以按照统一的方式进行翻转
        // 比如如果翻转的区间包含了原链表中的第一个位置,那么如果不设置 dummy
        // 在翻转的过程中需要设置其它的临时变量来保持第一位置节点的指针
        // 具体可以通过动画来理解
        ListNode *dummy = new ListNode(-1);

        // 让虚拟节点指向原链表的头部
        dummy->next = head;
        
        // 设置一个指针,指向以虚拟头节点为链表的头部位置
        ListNode *pre = dummy;

        // 设置一个指针,指向原链表的头部位置
        ListNode *cur = head;


        // 从虚拟头节点出发,pre 走 left - 1 步找到需要翻转的左区间
        // for 循环结束后,pre 的右节点是需要翻转的节点
        // for 循环结束后,cur 指向的就是需要翻转的节点
        for (int i = 0; i < left - 1; i++) {
           
            // pre 不断的向右移动,直到走到翻转的左区间为止
            pre = pre->next;
            // cur 不断的向右移动,找到了需要翻转的第一个节点
            cur = cur->next;
        }

        // 开始翻转这些节点
        for (int i = 0; i < right - left; i++) {
            
            // 设置临时变量,保存当前需要翻转节点的后面的节点
            ListNode *temp = cur->next;

            // 这个时候,让 temp 和 cur 两个节点翻转一下
            // 比如,一开始 i = 0 的时候 cur 为 2, temp 为 3
            // 执行完下面的代码,如果原链表是
            // 1 --> 2 --> 3 --> 4 --> 5
            // 变成了
            // 1 --> 3 --> 2 --> 4 --> 5
            
            // cur 的下一节点是等号右侧的值
            // i = 0 的时候, cur 为 2,cur->next->next 的值是 4
            // 所以,这行代码让 cur 的下一节点不是 3 ,而是 4 
            // 2 --> 4
            // 等价于 cur->next = temp->next
            cur->next = cur->next->next;

            // temp 的下一节点是等号右侧的值
            // i = 0 的时候, temp 为 3,pre 为 1,pre 下一节点的值是 2
            // 所以,这行代码让 temp 的下一节点不是 4 ,而是 2 
            // 3 --> 2
            temp->next = pre->next;

            // pre 的下一节点是等号右侧的值
            // i = 0 的时候, pre 为 1,temp 的值是 3
            // 所以,这行代码让 pre 的下一节点为 3
            // 1 --> 3
          
            pre->next = temp;

            // i = 0 结束之后,链表变成了
            // 1 --> 3 --> 2 --> 4 --> 5
           
        }

        // 最后返回虚拟头节点的下一个节点,因为虚拟节点不在链表中
        return dummy->next;
    }
};

3、Python 代码

代码语言:javascript
复制
# 登录 AlgoMooc 官网获取更多算法图解
# https://www.algomooc.com
# 作者:程序员吴师兄
# 代码有看不懂的地方一定要私聊咨询吴师兄呀
# 反转链表 II ( LeetCode 92 ):https://leetcode-cn.com/problems/reverse-linked-list-ii
class Solution:
    def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
         # 一开始设置一个虚拟节点,它的值为 -1,它的值可以设置为任何的数,因为我们根本不需要使用它的值
        # 设置虚拟节点的目的是为了让原链表中所有节点就都可以按照统一的方式进行翻转
        # 比如如果翻转的区间包含了原链表中的第一个位置,那么如果不设置 dummy
        # 在翻转的过程中需要设置其它的临时变量来保持第一位置节点的指针
        # 具体可以通过动画来理解
        dummy =  ListNode(-1)

        # 让虚拟节点指向原链表的头部
        dummy.next = head
        
        # 设置一个指针,指向以虚拟头节点为链表的头部位置
        pre = dummy

        # 设置一个指针,指向原链表的头部位置
        cur = head


        # 从虚拟头节点出发,pre 走 left - 1 步找到需要翻转的左区间
        # for 循环结束后,pre 的右节点是需要翻转的节点
        # for 循环结束后,cur 指向的就是需要翻转的节点
        for _ in range(left - 1):
            # pre 不断的向右移动,直到走到翻转的左区间为止
            pre = pre.next
            # cur 不断的向右移动,找到了需要翻转的第一个节点
            cur = cur.next

        # 开始翻转这些节点
        for _ in range(right - left):
            
            # 设置临时变量,保存当前需要翻转节点的后面的节点
            temp = cur.next

            # 这个时候,让 temp 和 cur 两个节点翻转一下
            # 比如,一开始 i = 0 的时候 cur 为 2, temp 为 3
            # 执行完下面的代码,如果原链表是
            # 1 --> 2 --> 3 --> 4 --> 5
            # 变成了
            # 1 --> 3 --> 2 --> 4 --> 5
            
            # cur 的下一节点是等号右侧的值
            # i = 0 的时候, cur 为 2,cur.next.next 的值是 4
            # 所以,这行代码让 cur 的下一节点不是 3 ,而是 4 
            # 2 --> 4
            # 等价于 cur.next = temp.next
            cur.next = cur.next.next

            # temp 的下一节点是等号右侧的值
            # i = 0 的时候, temp 为 3,pre 为 1,pre 下一节点的值是 2
            # 所以,这行代码让 temp 的下一节点不是 4 ,而是 2 
            # 3 --> 2
            temp.next = pre.next

            # pre 的下一节点是等号右侧的值
            # i = 0 的时候, pre 为 1,temp 的值是 3
            # 所以,这行代码让 pre 的下一节点为 3
            # 1 --> 3
          
            pre.next = temp

            # i = 0 结束之后,链表变成了
            # 1 --> 3 --> 2 --> 4 --> 5
           

        # 最后返回虚拟头节点的下一个节点,因为虚拟节点不在链表中
        return dummy.next
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 五分钟学算法 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 吴师兄的参考思路
  • 吴师兄的参考代码
    • 1、Java 代码
      • 2、C++ 代码
        • 3、Python 代码
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档