
1.思路:找到要反转区间的前一个位置preLeftNode和它的下一个节点LeftNode,然后对待反转区间的元素进行反转,然后重新连接链表。preLeftNode去连反转链表的新头节点,反转区间的最后一个节点LeftNode去连反转区间后的第一个节点。
2.复杂度分析:
(1)时间复杂度:O(right)。
(2)空间复杂度:O(1)。
附代码:
java
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
if(head == null){
return null;
}
// 创建一个哨兵节点,它的next指向head(当left等于1的时候,即left指向head的时候,head也要做反转)
ListNode sentinel = new ListNode();
sentinel.next = head;
// 找到反转区间前面的节点preLeftNode
// preLeftNode就是left前面的一个位置
ListNode preLeftNode = sentinel;
for(int i = 1;i < left;i++){
preLeftNode = preLeftNode.next;
}
// leftNode表示反转区间的第一个节点,待会反转后会变为尾部
ListNode leftNode = preLeftNode.next;
// pre节点表示当前节点的前一个节点,初始为null,区间节点全部反转后会成为反转后的头部
ListNode pre = null;
// cur初始指向反转区间的第一个节点leftNode
ListNode cur = leftNode;
// 依次遍历要反转的节点,进行反转
for(int i = 0;i < right - left + 1;i++){
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
// 重新连接链表
// 反转区间前面的节点preLeftNode连接到反转后的头部pre
preLeftNode.next = pre;
// 反转后的尾部连接到反转区间后的第一个节点cur(此前cur已走到temp,即反转区间末尾节点的后一个节点cur.next的位置)
leftNode.next = cur;
// 返回完整链表的头节点
return sentinel.next;
}
}
ACM模式:
java
import java.util.Scanner;
// 将 ListNode 定义为独立的类
class ListNode {
int val;
ListNode next;
ListNode() {};
ListNode(int val) {
this.val = val;
this.next = null;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取链表长度
int n = scanner.nextInt();
// 读取链表元素
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = scanner.nextInt();
}
// 读取 left 和 right
int left = scanner.nextInt();
int right = scanner.nextInt();
// 创建链表
ListNode head = null;
if (n > 0) {
head = new ListNode(nums[0]);
ListNode current = head;
for (int i = 1; i < n; i++) {
current.next = new ListNode(nums[i]);
current = current.next;
}
}
// 调用反转区间链表方法
Solution solution = new Solution();
ListNode result = solution.reverseBetween(head, left, right);
// 输出反转后的链表
if (result == null) {
System.out.println("");
} else {
ListNode current = result;
while (current != null) {
System.out.print(current.val);
if (current.next != null) {
System.out.print(" ");
}
current = current.next;
}
System.out.println();
}
scanner.close();
}
}
// 反转区间链表方法放在 Solution 类中
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
if(head == null){
return null;
}
// 创建一个哨兵节点,它的next指向head(当left等于1的时候,即left指向head的时候,head也要做反转)
ListNode sentinel = new ListNode();
sentinel.next = head;
// 找到反转区间前面的节点preLeftNode
// preLeftNode就是left前面的一个位置
ListNode preLeftNode = sentinel;
for (int i = 1; i < left; i++) {
preLeftNode = preLeftNode.next;
}
// leftNode表示反转区间的第一个节点,待会反转后会变为尾部
ListNode leftNode = preLeftNode.next;
// pre节点表示当前节点的前一个节点,初始为null,区间节点全部反转后会成为反转后的头部
ListNode pre = null;
// cur初始指向反转区间的第一个节点leftNode
ListNode cur = leftNode;
// 依次遍历要反转的节点,进行反转
for (int i = 0; i < right - left + 1; i++) {
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
// 重新连接链表
// 反转区间前面的节点preLeftNode连接到反转后的头部pre
preLeftNode.next = pre;
// 反转后的尾部连接到反转区间后的第一个节点cur(此前cur已走到temp,即反转区间末尾节点的后一个节点cur.next的位置)
leftNode.next = cur;
// 返回完整链表的头节点
return sentinel.next;
}
}