题目描述:
书店店员有一张链表形式的书单,每个节点代表一本书,节点中的值表示书的编号。为更方便整理书架,店员需要将书单倒过来排列,就可以从最后一本书开始整理,逐一将书放回到书架上。请倒序返回这个书单链表。
/*** 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<Integer> 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)。