一、题目内容为:
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K = 3, then you must output 3→2→1→6→5→4; if K = 4, you must output 4→3→2→1→5→6.
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N(<= 10^5) which is the total number of nodes, and a positive K(<= N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address is the position of the node, Data is an integer, and Nextis the position of the next node.
Output Specification:
For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.
Sample Input:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
Sample Output:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1
00100 7 4
00000 4 99999
00100 1 12309
68237 6 -1
11111 8 44444
33218 3 00000
99999 5 68237
12309 2 33218
数组下标 | 00000 | ... | 00100 | … | 12309 | … | 33218 | … | 68237 | … | 99999 |
节点值 | 4 | … | 1 | … | 2 | … | 3 | … | 6 | ... | 5 |
节点的下一个指针 | 99999 | … | 12309 | … | 33218 | ... | 00000 | ... | -1 | ... | 68237 |
如:1->2->3->4->5->6->7->8,以K=4进行逆转之后,就会变成4->3->2->1->8->7->6->5;
又比如:1->2->3->4->5->6,以K=4进行逆转之后,就会变成4->3->2->1->5->6.
(2)获取数组中属于链表的有效节点;
(3)当K=1时不需要进行逆转,当K>1时进行逆转;
(4)打印逆转后的链表,输出格式如输出案例所示,因为要显示“00000”,所以需要将整数型数据转化为字符型;最后一行的最后可以有回车符,但是不能有多余的空格;
四、程序源码:
import java.util.Scanner;
class ArrayNode {
int data;
int next;
public ArrayNode() {
}
}
public class Test {
public static void main(String[] args) {
// 读取数据存入数组
ArrayNode[] array = new ArrayNode[100000];
Scanner scan = new Scanner(System.in);
int head = scan.nextInt();
int N = scan.nextInt();
int K = scan.nextInt();
int current = 0;
int a = head;
for (int i = 0; i < N; i++) {
current = scan.nextInt();
array[current] = new ArrayNode();
array[current].data = scan.nextInt();
array[current].next = scan.nextInt();
}
// 返回数组中有效的节点个数,为了防止数组中有多余的节点
N = number(head, array, N);
// 逆转单向链表
if (K > 1) {
a = reverse(head, array, N, K);
}
// 打印逆转后的链表
display(a, array, N);
}
/*
* 改变输出数字格式 在不够五位数的前面补0
*/
public static String change(int val) {
if (val == -1) {
return val + "";
}
String s = "00000";
String first = val + "";
int length = first.length();
s = s.substring(length) + first;
return s;
}
/*
* 打印数组中的静态链表
*/
public static int display(int head, ArrayNode[] arr, int N) {
int num = 0;
while (head != -1) {
String head1 = change(head);
String next1 = change(arr[head].next);
System.out.println(head1 + " " + arr[head].data + " " + next1);
head = arr[head].next;
num++;
}
return num;
}
// 返回数组中有效的节点个数
public static int number(int head, ArrayNode arr[], int N) {
int num = 0;
while (head != -1) {
head = arr[head].next;
num++;
}
return num;
}
//以K为分界线对单向链表进行逆转
public static int reverse(int head, ArrayNode[] arr, int N, int K) {
int num = 1;
int reverse = 1;
int remain = head;
int old_head = arr[head].next;
int new_head = head;
int temp;
int remain2 = head;
while (reverse <= N / K) {
while (num < K) {
temp = arr[old_head].next;
int a = arr[old_head].data;
// 注意这里需要给数组该位置创建一个结点,不能直接用“arr[old_head].next= new_head”会影响old_head的值;
arr[old_head] = new ArrayNode();
arr[old_head].data = a;
arr[old_head].next = new_head;// 将链表方向逆转
new_head = old_head;
old_head = temp;
num++;
}
if (reverse == 1) {// 第一次逆转时,找到头节点,并将逆转之后的节点与还没逆转的节点相连
head = new_head;
arr[remain].next = old_head;
} else {// 第i(i>1)次的逆转,都直接把逆转之后的节点与第i+1次逆转之后的节点连接起来
arr[remain].next = new_head;
remain = remain2;
}
if (old_head == -1) {// 当链表逆转结束时,将尾节点的下一个指向-1
arr[remain2].next = -1;
} else {// 如果一轮逆转之后链表还没结束,则还需要再进行一轮逆转,所以把所有的节点都往后移一位
new_head = old_head;
old_head = arr[old_head].next;
remain2 = new_head;
}
num = 1;
reverse++;
}
return head;
}
}
五、测试点分析
测试点1,如案例所示;
测试点2,题目分析中也有说明;
测试点3,当K=N时正好链表上所有的节点都进行一次反转;
测试点4,当K=1时不用反转;
测试点5,不用解释吧;
测试点6,即当N取到10^5时,要反转X=N/K次,还剩下K-1个节点不反转;
测试点7,题目分析中也有说明,需要获取数组中存在的有效节点个数。
注:此处我的测试点6为运行超时,是因为该系统用JAVA编程耗时太多,有多个题目都是这样,如果有解决办法的朋友,可以留言提醒,谢谢!
额外附送:
1、陈越老师对这题的讲解视频链接:
http://www.icourse163.org/learn/ZJU-93001?tid=1001757011#/learn/content?type=detail&id=1002249375
2、陈越老师对单向链表逆转模块的图解:
3、单向链表逆转的伪代码:
LinkList Reverse (LinkList head, int K) //单链表逆转K个结点 且仅一次
2 {
3 int cnt = 1; //用于计数已逆转的结点数
4 LinkList new_ = head->next;
5 LinkList old = new_->next;
6 LinkList tmp;
7 while(cnt < K) {
8 tmp = old->next; //用于old结点逆转后 记录未逆转链表的头结点
9 old->next = new_; //逆转
10 new_ = old; //向后移位
11 old = tmp; //向后移位
12 cnt++; //逆转节点+1
13 }
14 head->next->next = old;
15 return new_; //新的头结点
16 }