链表之指定区间反转

描述

将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度O(n),空间复杂度 O(1)。
例如:
给出的链表为 1→2→3→4→5→NULL, m=2,n=4,
返回 1→4→3→2→5→NULL.
 

数据范围: 链表长度 0<size≤1000,0<m≤n≤size,链表中每个节点的值满足 ∣val∣≤1000

要求:时间复杂度 O(n) ,空间复杂度 O(n)

进阶:时间复杂度 O(n),空间复杂度 O(1)

示例1

输入:

{1,2,3,4,5},2,4

返回值:

{1,4,3,2,5}

示例2

输入:

{5},1,1

返回值:

{5}


基本思路:

1.遍历整个链表

2.将从第m个结点开始到第n个结点的结点都倒置

既然要倒置从m到n的结点,所以可以想到之前的链表之反转链表

这里有个疑问:如果正好从第一个开始倒置怎么办?

当时我没注意到这个点,所以写完后发现,有例子出错了。那么如果我们想要保证原来的链表的任何位置都保持相同处理逻辑,那么最好引入一个头结点

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */

public class Solution {
    /**
     *
     * @param head ListNode类
     * @param m int整型
     * @param n int整型
     * @return ListNode类
     */
    public ListNode reverseBetween (ListNode head, int m, int n) {
         //1.判空或只有一个结点
        if (head == null || head.next == null) {
            return head;
        }

        //2.需要设置一个头结点 (非常重要)
        ListNode dummyNode = new ListNode(0);
        dummyNode.next = head;

        ListNode leftNode = null;
        ListNode rightNode = null;
        ListNode preNode = null;
        ListNode curNode = dummyNode;
        int location = 0;
        //3.找到需要反转的结点的头和尾
        while (curNode != null) {
            if (location == m - 1) {
                preNode = curNode;
            }
            if (location == m) {
                leftNode = curNode;
            }
            if (location == n) {
                rightNode = curNode;
            }
            // 在第n个结点的后一个位置,进行调整
            if (location == n + 1) {
                break;
            }
            location++;
            curNode = curNode.next;
        }
        //4.切断反转链表的对前后的连接
        preNode.next = null;
        rightNode.next = null;

        //5.反转m到n个结点
        preNode.next = reverse(leftNode);
        leftNode.next = curNode;

        return dummyNode.next;
    }

    public ListNode reverse(ListNode head) {
        ListNode newHead = null;
        ListNode cur = head;
        ListNode next = null;
        while (cur != null) {
            System.out.println("curNode = " + cur.val);
            //先定位到下一个节点的位置
            next = cur.next;
            //将当前节点的下一个节点指向新链表的表头
            cur.next = newHead;
            //再将新链表的表头重新定位到当前节点
            //此时已经实现的当前结点指向前一个节点的操作
            newHead = cur;
            //将当前结点指向下一个节点,为下一次循环作准备
            cur = next;
        }
        return newHead;
    }
}

是否还能再简约一些呢?

import java.util.*;
 
/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */
 
public class Solution {
    /**
     *
     * @param head ListNode类
     * @param m int整型
     * @param n int整型
     * @return ListNode类
     */
    public ListNode reverseBetween (ListNode head, int m, int n) {
        //1.设置虚拟头节点
        ListNode dummy =new ListNode(0);
        dummy.next=head;
        ListNode pre=dummy;
        //2.将pre指针移动到m前一个位置
        for(int i=0;i<m-1;i++){
            pre=pre.next;
        }
        //3.获取m位置
        ListNode cur=pre.next;
        ListNode next;
        for(int i=0;i<n-m;i++){
            next=cur.next;
            cur.next=next.next;
            //注意这里不能是next.next=cur,因为cur一直指的是最开始时m位置的节点
            next.next=pre.next;
            pre.next=next;
        }
        return dummy.next;
 
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链表的原地反转是一种常见的链表操作,它可以通过改变链表节点之间的指针来实现链表反转。原地反转链表的方法有多种,其中一种常见的方法是使用两个指针对链表进行调整,从而达到反转的效果。即通过改变节点的next指针的指向,将链表的方向翻转。 在原地反转链表的过程中,可以使用三个指针来进行操作。首先,设定一个指针pre指向当前节点的前一个节点,一个指针cur指向当前节点,一个指针next指向当前节点的后一个节点。 具体的原地反转链表的步骤如下: 1. 初始化pre为None,cur为链表的头节点。 2. 使用一个循环遍历链表,直到cur为None。 3. 在循环中,首先将next指针指向cur的下一个节点,以便在后面的操作中能够访问到该节点。 4. 将cur的next指针指向pre,即将当前节点的指针翻转。 5. 将pre指针指向cur,将cur指针指向next。 6. 重复步骤3-5,直到遍历完整个链表。 通过以上步骤,就可以实现链表的原地反转。这种方法的空间复杂度为O(1),即只需要常数级别的额外空间。 引用提供了一个模型来说明整个链表反转过程,引用中的图片也展示了通过四个步骤来实现链表反转。这些方法都可以帮助我们更好地理解和实现链表的原地反转操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值