​welcome to my blog​

程序员代码面试指南第二版 16.反转部分单向链表

题目描述

给定一个单链表,在链表中把第 L 个节点到第 R 个节点这一部分进行反转。

输入描述:
n 表示单链表的长度。

val 表示单链表各个节点的值。

L 表示翻转区间的左端点。

R 表示翻转区间的右端点。

输出描述:
在给定的函数中返回指定链表的头指针。

示例1

输入
5
1 2 3 4 5
1 3

输出
3 2 1 4 5

第一次做, 这道题挺难的, 主要是很细; 核心: 1)找到fromLeft节点和toRight节点; 2)从待反转链表的第二个节点开始反转 3)待反转链表的头结点一定指向toRight 4)待反转链表的尾结点稍微复杂些, 如果该尾结点是整体链表的头结点, 就没有东西的next指向它了; 如果该尾结点不是整体链表的头结点, 就会有fromLeft.next指向该尾结点; 题外话: 注意反转可以通过交换实现,例子:1,2,3反转成3,2,1可以用交换实现; 1,2,3,4反转成4,3,2,1可以用交换实现

import java.util.Scanner;

public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = Integer.parseInt(sc.nextLine());
String[] str = sc.nextLine().split(" ");
String s = sc.nextLine();
int l = Integer.parseInt(s.split(" ")[0]);
int r = Integer.parseInt(s.split(" ")[1]);
//input check
if(l>r || l<1 || r>n)
return;
//创建链表
ListNode head = new ListNode(Integer.parseInt(str[0]));
ListNode curr = head;
for(int i=1; i<n; i++){
curr.next = new ListNode(Integer.parseInt(str[i]));
curr = curr.next;
}
//找到第l-1个节点和第r+1个节点
//initialize
int len=1;
curr = head;
ListNode fromLeft=null, toRight=null;
while(curr!=null){
//execute
if(len==l-1)
fromLeft = curr;
if(len==r+1)
toRight = curr;
//update
len++;
curr = curr.next;
}
//反转链表, 注意反转部分链表时, 是从from.next开始反转, 并不是常规反转链表时从from开始
//left指向from
ListNode left = fromLeft==null? head : fromLeft.next; //fromLeft不为null的话, 那么fromLeft.next一定不是null
curr = left.next;
//将待反转部分的头结点和toRight连接; 放在这里写比较省事
left.next = toRight;
ListNode right;
while(curr!=toRight){
//save
right = curr.next;
//change
curr.next = left;
//update
left = curr;
curr = right;
}
//处理待反转部分的尾结点, 需要考虑反转后该尾结点是否会变成头结点
//会变成头结点; 就没有东西需要指向该尾结点了, 因为它已经是头结点
if(fromLeft==null)
head = left;
//不会变成头结点
else
fromLeft.next = left;
//打印结果
curr = head;
while(curr!=null){
System.out.print(curr.val+" ");
curr = curr.next;
}
}
public static class ListNode{
int val;
ListNode next;
ListNode(int val){
this.val = val;
}
}
}