题目描述:
书店店员有一张链表形式的书单,每个节点代表一本书,节点中的值表示书的编号。为更方便整理书架,店员需要将书单倒过来排列,就可以从最后一本书开始整理,逐一将书放回到书架上。请倒序返回这个书单链表。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public int[] reverseBookList(ListNode head) {
}
}
示例 1:
输入:head = [3,6,4,1] 输出:[1,4,6,3]提示:
0 <= 链表长度 <= 10000
代码实现:
方法一:
要将书单链表反转,我们可以使用迭代或递归的方法。将给定的单链表反转,并将反转后的结果存储在一个数组中返回。以下是一种可能的实现:
class Solution {
public int[] reverseBookList(ListNode head) {
// 计算链表长度
int len = 0;
ListNode curr = head;
while (curr != null) {
len++;
curr = curr.next;
}
// 将链表反转
ListNode prev = null;
curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
// 将反转后的链表节点值存储到数组中
int[] result = new int[len];
int i = 0;
curr = prev;
while (curr != null) {
result[i++] = curr.val;
curr = curr.next;
}
return result;
}
}
在上述代码中,我们首先计算出原始链表的长度 len
,然后利用迭代的方式将链表反转,并将反转后的节点值存储到数组中,最后返回该数组即可。
需要注意的是,当链表为空或只有一个节点时,反转链表不需要进行任何操作,直接返回原始链表即可。
同时,也需要注意代码的鲁棒性,即对于空链表或空数组,需要进行特殊处理,保证程序正确运行。
在上述方法中,我们首先遍历链表来计算长度,然后再进行反转操作。这个过程需要两次遍历链表,因此可以考虑优化性能,只进行一次遍历。
以下是一种只进行一次遍历的优化方法:
class Solution {
public int[] reverseBookList(ListNode head) {
// 处理空链表情况
if (head == null) {
return new int[0];
}
ListNode prev = null;
ListNode curr = head;
int len = 0;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
len++;
}
// 将反转后的链表节点值存储到数组中
int[] result = new int[len];
int i = 0;
while (prev != null) {
result[i++] = prev.val;
prev = prev.next;
}
return result;
}
}
在这个优化的方法中,我们先处理空链表的情况,如果链表为空,则直接返回一个空数组。然后我们使用一个变量
len
记录链表的长度,同时在进行链表反转的同时,将节点值存储到数组中,最后返回该数组。
这个优化方法只需要一次遍历就可以完成链表反转和数组构建,相比于之前的方法减少了一次遍历,因此可以提升性能。
方法二:
使用栈和数组的方式:
import java.util.Stack;
class Solution {
public int[] reverseBookList(ListNode head) {
// 处理空链表情况
if (head == null) {
return new int[0];
}
Stack stack = new Stack<>();
ListNode curr = head;
while (curr != null) {
stack.push(curr.val);
curr = curr.next;
}
int[] result = new int[stack.size()];
int i = 0;
while (!stack.isEmpty()) {
result[i++] = stack.pop();
}
return result;
}
}
在这个方法中,我们使用一个栈来存储链表节点值。首先,遍历链表,将节点值依次入栈。然后,创建一个新的数组,长度为栈的大小,依次将栈中的元素出栈并存储到数组中。
这种方法的时间复杂度为 O(n),其中 n 是链表的长度。因为需要遍历链表一次来入栈,然后再遍历栈一次来构建数组。
注意,在这种方法中,由于使用了额外的栈来存储链表节点值,因此会占用额外的空间。如果空间复杂度是一个关注点,那么迭代或递归的方法可能更适合。
以上使用递归和栈辅助的两种方法的时间和空间复杂度都是 O(N)。
对于使用递归的方法,在每一次递归调用中,都会向链表的尾部逐步递进,因此时间复杂度为 O(N),其中 N 是链表的长度。另外,由于递归调用的层数不超过链表的长度,因此递归方法的空间复杂度也是 O(N)。
对于使用栈辅助的方法,在遍历链表时,需要将每个节点的值存储到栈中,因此空间复杂度为 O(N)。另外,在遍历栈并构建反转后的链表时,需要遍历整个栈,时间复杂度也是 O(N)。