链表反转的拓展----算法通关村第二关白银挑战

1.指定区间反转

LeetCode 92 反转链表 Ⅱ
题目描述:

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

  • 1.1头插法
    以left所在的位置为头节点,依次对left到right的节点进行头插,如下图所示
    在这里插入图片描述

下面这个是我第一次写的思路,以pre指向要反转的节点的前一个结点,再对left~right之间的每一个节点进行依次头插(即插入到pre的后面)。但是我这个做法必须在头插完之后将最初的left节点的next去指向right的后一个节点(即将2节点的next指向6节点)。因为我是将要反转的节点单独拎出来去头插,相当于前面的链表与后面的断开了。因此最后还需要将两端链表进行连接。

public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode newHead = new ListNode(-1,head);
        ListNode pre = newHead,cur;
        
        //使得pre指向left的前一个节点
        for(int i = 1;i < left;i++){
            pre = pre.next;
        }
        cur = pre.next;
        ListNode temp = cur,next;
        //如果此时的left为遍历的第一个节点,那么不需要头插,直接跳过
        cur = cur.next;
        
        //将left~right的节点进行头插
        while(left < right){
            next = cur.next;
            cur.next = pre.next;
            pre.next = cur;
            cur = next;
            left++;
        }
        //将两段链表连接起来
        temp.next = cur;
        return newHead.next;
    }

后面看了骨头哥的做法,才发现可以直接让cur一直指向left所在节点,让left~right的节点去进行头插。再将cur的next去指向还未反转的最前一个节点(相当于将此时的cur与其后面的节点调换了顺序),具体实现如下图。
在这里插入图片描述

public ListNode reverseBetween(ListNode head, int left, int right) {
        //新建个虚拟头节点
        ListNode newHead = new ListNode(-1,head);
        ListNode pre = newHead;
        //使得pre指向left的前一个节点
        for(int i = 1;i < left;i++){
            pre = pre.next;
        }
        ListNode cur = pre.next,next;
        while(left < right){
            next = cur.next;
            cur.next = next.next;
            next.next = pre.next;
            pre.next = next;
            left++;
        }
        return newHead.next;
    }
  • 1.2穿针引线法
    这个方法基本就是截取left~right的链表出来当作子链表,并用之前的建立虚拟头节点的链表反转方法去反转子链表。最后将反转后的链表与原链表进行拼接即可。
public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode dummyNode = new ListNode(-1,head);
        //记录前一段的尾节点
        ListNode pre = dummyNode;
        //记录后一段的头节点
        ListNode nextHead = dummyNode;
        //定义子链表的头尾
        ListNode leftNode,rightNode;

        for(int i = 1;i < left;i++){
            pre = pre.next;
        }
        //遍历找到子链表
        leftNode = pre.next;
        rightNode = pre.next;
        for(int i = 0;i < right -left;i++){
            rightNode = rightNode.next;
        }
        
        nextHead = rightNode.next;
        //注意一定要将rightNode.next置空,不然会将left后面的链表全部反转的
        rightNode.next = null;
        
        //反转子链表
        reverseList(leftNode);
        
        //拼接链表
        pre.next = rightNode;
        leftNode.next = nextHead;
        
        return dummyNode.next;
    }

    public void reverseList(ListNode head) {
        //定义个虚拟的头节点去辅助反转链表
        ListNode res = new ListNode(-1);
        ListNode cur = head,next = head;
        while(cur != null){
            next = cur.next;
            cur.next = res.next;
            res.next = cur;
            cur = next;
        }
    }
  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值