經典鏈表題:輸入單鏈表頭節點,從尾到頭打印節點值。本文詳細講解四種解法——棧、遞歸、ArrayList 逆序、就地反轉鏈表,對比時空複雜度、優缺點與適用場景,附完整 Java 代碼與測試用例。
輸入:1 → 2 → 3 → 4 → null
輸出:4, 3, 2, 1,
本質是「後進先出」問題,天然適合棧或遞歸。
static class ListNode {
int val;
ListNode next;
ListNode(int v) { val = v; }
}
public static void printWithStack(ListNode head) {
Stack<Integer> stack = new Stack<>();
while (head != null) {
stack.push(head.val);
head = head.next;
}
while (!stack.isEmpty()) {
System.out.print(stack.pop() + ",");
}
}
public static void printRecursive(ListNode head) {
if (head == null) {
System.out.println("空鏈表");
return;
}
if (head.next != null) printRecursive(head.next);
System.out.print(head.val + ",");
}
StackOverflowError;不可中斷/恢復。public static void printWithArrayList(ListNode head) {
if (head == null) { System.out.print("空鏈表"); return; }
List<Integer> list = new ArrayList<>();
while (head != null) {
list.add(head.val);
head = head.next;
}
for (int i = list.size() - 1; i >= 0; i--) {
System.out.print(list.get(i) + ",");
}
}
public static void printByReverse(ListNode head) {
ListNode reversed = reverseRecursive(head);
while (reversed != null) {
System.out.print(reversed.val + ",");
reversed = reversed.next;
}
}
// 遞歸反轉
private static ListNode reverseRecursive(ListNode head) {
if (head == null || head.next == null) return head;
ListNode newHead = reverseRecursive(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
private static ListNode reverseIterative(ListNode head) {
ListNode prev = null, curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
| 解法 | 時間 | 額外空間 | 修改原表 | 棧溢出風險 | 推薦場景 |
|---|---|---|---|---|---|
| 棧 | O(n) | O(n) | 否 | 無 | 通用、面試首選 |
| 遞歸 | O(n) | O(n) 棧 | 否 | 高 | 短鏈表、代碼簡潔優先 |
| ArrayList | O(n) | O(n) | 否 | 無 | 需多次逆序訪問 |
| 就地反轉 | O(n) | O(1) 或 O(n) | 是 | 遞歸版有 | 空間極受限、允許修改 |
public static void main(String[] args) {
// 建構 1→2→3→4
ListNode n1 = new ListNode(1);
ListNode n2 = new ListNode(2);
ListNode n3 = new ListNode(3);
ListNode n4 = new ListNode(4);
n1.next = n2; n2.next = n3; n3.next = n4;
System.out.print("棧:"); printWithStack(n1); System.out.println();
System.out.print("遞歸:"); printRecursive(n1); System.out.println();
System.out.print("ArrayList:"); printWithArrayList(n1); System.out.println();
System.out.print("反轉:"); printByReverse(n1); System.out.println();
// 邊界測試
printRecursive(null); // 空鏈表
printRecursive(new ListNode(5)); // 單節點
}
從尾到頭打印鏈表考察對「後進先出」數據結構的靈活運用。面試建議:首推棧解法(不改結構、無溢出、邏輯清晰),次推 ArrayList;遞歸作為代碼簡潔展示;就地反轉作為「空間優化」進階方案並說明副作用。掌握四種解法權衡,即可應對所有變體追問。