反转链表II 两种解法

链表的操作问题,一般而言面试(机试)的时候不允许我们修改节点的值,而只能修改节点的指向操作。所以这其中一些链表的常用技巧我们应该掌握,反转链表很好地体现了链表的一些技巧,这里记录一下反转链表II的递归和迭代两种解法。

题目描述

image-20230721124942389

递归解法

反转一整条链表的递归解法如下:

// 定义:输入一个单链表头结点,将该链表反转,返回新的头结点
ListNode reverse(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    ListNode newHead = reverse(head.next);	// 记录新的头节点

    head.next.next = head;

    head.next = null;

    return newHead;
}

在上面代码基础上可以写出反转链表前N个节点的解法:

ListNode successor = null; // 后驱节点

// 反转以 head 为起点的 n 个节点,返回新的头结点
ListNode reverseN(ListNode head, int n) {
    if (n == 1) {
        // 记录第 n + 1 个节点
        successor = head.next;
        return head;
    }
    // 以 head.next 为起点,需要反转前 n - 1 个节点
    ListNode last = reverseN(head.next, n - 1);

    head.next.next = head;
    // 让反转之后的 head 节点和后面的节点连起来
    head.next = successor;
    return last;

}

再在上面的基础上可以写出反转[left,right]区间中的节点的代码:

ListNode succ = null;	//  记录后驱节点
public ListNode reverseBetween(ListNode head, int left, int right) {
    if(left == 1){
        return reverseN(head, right);	// basecase,找到了开始反转的节点
    }
    head.next = reverseBetween(head.next, left-1, right-1);	// 递归找反转开始处
    return head;
}
ListNode reverseN(ListNode head, int n){	// 反转N个节点的方法
    if(n == 1){
        succ = head.next;
        return head;
    }
    ListNode newHead = reverseN(head.next, n-1);
    head.next.next = head;
    head.next = succ;
    return newHead;
}

上面的思路就是先递归找反转开始的地方,找到了之后反转right-left个节点就行

迭代解法

迭代法采用头插法来实现反转,具体思路:

1、我们定义两个指针,分别称之为 g(guard 守卫) 和 p(point)。 我们首先根据方法的参数 m 确定 g 和 p 的位置。将 g 移动到第一个要反转的节点的前面,将 p 移动到第一个要反转的节点的位置上。我们以 m=2,n=4为例。 2、将 p 后面的元素删除,然后添加到 g 的后面。也即头插法。 3、根据 m 和 n 重复步骤(2) 4、返回 dummy.next

image-20230721130643499

代码:

public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode dummy = new ListNode(0, head); // 虚拟头节点,方便处理left==1的情况
        int m = left, n = right-left;
        ListNode g = dummy, p = head;   // p指向第一个要反转的节点,g指向p之前的节点
        while(m>1){     // 找到p和g所指向的节点
            g = g.next;
            p = p.next;
            m--;
        }
        while(n>0){     // 头插法反转链表
            ListNode pNext = p.next;    
            p.next = p.next.next;   // 把p后面的那个节点先删了
            pNext.next = g.next;    // 再插到g的后面
            g.next = pNext;
            n--;
        }
        return dummy.next;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值