算法通关村第二关——指定区间反转


问题

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

例如: 输入:head = [1,2,3,4,5], left = 2, right = 4
   		输出:[1,4,3,2,5]
例如: 输入:head = [9,7,2,5,4,3,6], left = 3, right = 6
  		输出:[9,7,3,4,5,2,6]

在这里插入图片描述


题目解读与解题思路:

题目解读:将左右指针里的元素进行反转。
解题思路:
1.头结点法。
2.穿针引线法

1.头结点法

反转的整体思想:在需要反转的区间里,每遍历到一个结点,让这个新结点来到反转部分的起始位置。

缺点:若left和right差值过大,并且恰好是链表的头结点和尾结点时,找到left和right需要遍历一次,反转它们之间的链表还需要在遍历一次。时间复杂度为O(N),但遍历了链表2次,那么如何只能遍历一次?

如图所示:
在这里插入图片描述
这个过程就是前面的带虚拟结点的插入操作,每走一步都要考虑各种指针怎么指,既要将结点摘下来接到对应的位置上,还要保证后续结点能够找到。

 public static ListNode reverseBetween(ListNode head,int left,int right){
        //虚拟头结点
        ListNode dumy = new ListNode(-1);
        dumy.next = head;

         ListNode prev = dumy;
        for (int i = 0; i < left - 1; i++) {
            prev = prev.next;
        }

        //left 位置
        ListNode cur = prev.next;
        ListNode next;
        for (int i = 0; i < right - left; i++) {
            next = cur.next;
            cur.next = next.next;
            next.next = prev.next;
            prev.next = next;
        }

        return dumy.next;
    }

2.穿针引线法

如下图:反转蓝色区域的链表为例在这里插入图片描述

思路:
1.先确定好需要反转的部分,即下图的left到right之间。
2.再将三段链表拼接起来,如下图。

在这里插入图片描述
步骤:
1.先将待反转的区域反转;
2.把pre的next指针指向反转以后的链表头节点,把反转以后的链表的尾节点的next指针指向succ。

在这里插入图片描述

public static ListNode reverseBetween(ListNode head, int left, int right) {
        //虚拟头结点
        ListNode dumy = new ListNode(-1);
        dumy.next = head;
        ListNode pre = dumy;
        //1.从虚拟头结点 走 left -1 步,来到left 节点的前一个节点
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }
        //2.从pre 再走 right - left  +1 ,来到 right 节点
        ListNode rightNode = pre;
        for (int i = 0; i < right - left; i++) {
            rightNode = rightNode.next;
        }
        //3.切出一个子链表
        ListNode leftNode = pre.next;
        ListNode succ = rightNode.next;
        pre.next = null;
        rightNode.next = null;

        //4.反转链表的子区间
        reverseLinkedList(leftNode);

        //5.接回到原来的链表中
        pre.next = rightNode;
        leftNode.next = succ;
        return dumy.next;

    }

    private void reverseLinkedList(ListNode head) {
        //也可以使用递归反转一个链表
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
    }

该处使用的url网络请求的数据。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值