一、题目
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
二、题解
方法一: 递归
使用递归反转链表的思路来源于反转字符串时使用的类似方法。反转字符串的一个巨大优势是可以使用下标信息。我们可以创建两个指针,一个开头,一个结尾。不断地交换这两个指针指向的元素,并将两个指针向中间移动。在分析链表的情况前,先让我们看看字符串上的示例。
反转给定链表的一部分的思路基于上述方法。我们需要两个不同指针,一个指向第 m 个结点,另一个指向第 n 个结点。一旦有了这两个指针,我们就可以不断地交换这两个指针指向结点的数据,并将两个指针相向移动,就像字符串的情况那样。
然而,链表中没有向后指针,也没有下标。因此,我们需要使用递归来 模拟 向后指针。递归中的回溯可以帮助我们模拟一个指针从第n个结点向中心移动的移动过程。
下面是一系列整个算法的示意图
方法1 递归代码实现:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
private boolean stop;
private ListNode left;
public ListNode reverseBetween(ListNode head, int m, int n) {
this.left = head;
this.stop = false;
this.recurseAndReverse(head, m, n);
return head;
}
public void recurseAndReverse(ListNode right, int m, int n){
if(n == 1)
return;
right = right.next;
if(m > 1)
this.left = this.left.next;
this.recurseAndReverse(right, m - 1, n - 1);
// right指针等于或是已经穿过了left指针 就设置stop为true,后面不再进行数据交换
if(this.left == right || right.next == this.left)
this.stop = true;
if(!stop){
int t = this.left.val;
this.left.val = right.val;
right.val = t;
this.left = this.left.next;
}
}
}
方法2 迭代链接反转
在上个方法中,我们研究了一种反转给定链表部分的算法,该算法不改变给定链表的内在结构,只是修改了对于结点的值。 然而,有时可能无法修改结点的数据值。这时,我们就需要改变结点的链接来完成反转。
从位置 m 到位置 n 的全部结点,我们需要反转每个结点的 next 指针。下面来看看具体的算法。
7 -->9 -->2 -->10 -->1 -->8 -->6
7 -->9 -->8 -->1 -->10 -->2 -->6
代码实现:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
if(head == null || head.next == null)
return head;
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode curr = dummyHead;
for(int i = 1 ; i <= m ; i ++){
if(i == m){
curr.next = reverseLen(curr.next, n - m +1);
}
curr= curr.next;
}
return dummyHead.next;
}
// head = 2 len = 4 2 -->10 -->1 -->8 -->
private ListNode reverseLen(ListNode head, int len){
if(len == 1)
return head;
ListNode curr = head;
ListNode prev = null;
while(len > 0){
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
len --;
}
head.next = curr;
return prev;
}
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/two-sum/solution/fan-zhuan-lian-biao-ii-by-leetcode/
来源:力扣(LeetCode)