題目
反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
難點
1. 識別終止條件
2. 正確處理Java的引用
變量在=左邊時爲引用,在=右邊時爲引用指向的內存地址。
public static void main(String[] args) {
Node first = new Node(1);
first.next = new Node(2);
Node tmp = first.next;
first.next = new Node(9);
System.out.println(tmp.val);//2
System.out.println(first.next.val);//9
}
static class Node{
int val; Node next;
public Node(int val){
this.val = val;
}
@Override
public String toString() {
return "["+ val + "]";
}
}
3. 窗口(指針)移動處理
4. 臨時變量保存何值的選擇
錯誤的實例
1. 死循環
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
* 輸入: 1->2->3->4->5->NULL
* 輸出: NULL<-1<-2<-3<-4<-5
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, prev = null;
while(true){
ListNode tmp = prev;
prev = cur;
cur = cur.next;//1
if(cur == null) break;//2
prev.next = tmp;
cur.next = prev;//3
}
return prev;
}
}
2代碼試圖當窗口移動到NULL時成立並退出循環,但是1與3的執行實際上使得2永遠無法達成,形成死循環
2. 錯誤的使用引用
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
* 輸入: 1->2->3->4->5->NULL
* 輸出: NULL<-1<-2<-3<-4<-5
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, prev = null;
while(cur != null){
ListNode tmp = prev;
prev = cur;//1
prev.next = tmp;//2
cur = cur.next;//3
}
return prev;
}
}
1的執行使得prev和cur引用指向了同一內存地址,2的執行實際上改變了cur.next的值,使得cur.next也被賦予了tmp,3顯然就錯了
3. 正確的做法
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
* 輸入: 1->2->3->4->5->NULL
* 輸出: NULL<-1<-2<-3<-4<-5
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, prev = null;
while(cur != null){
ListNode tmp = cur.next;
cur.next = prev;
prev = cur;
cur = tmp;
}
return prev;
}
}
總結
上面兩道錯誤的解題思路還有個問題在於無法正確處理邊界。我們通過tmp來保存中間變量,兩道錯題保存的是prev值。當窗口向右移動到NULL時,cur值會爲null,此時我們返回的是prev而不是cur。這意味着我們無需處理cur.next的情況了,因爲cur==null時會被捨棄。
swap需要臨時變量tmp協助,前面兩個錯誤的例題使用tmp來保存prev的內存地址指向的值,而實際上tmp只能保存cur.next的值。
錯誤示範
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, prev = null;
while(cur != null){
ListNode tmp = prev;
prev = cur;
prev.next = tmp;
cur = cur.next;//1
cur.next = prev;//2
}
return prev;
}
}
兩個錯誤:
1)1中cur已經被賦予了其他值,2這時候的cur.next不再等於1中的cur.next。顯然需要中間變量來處理
2)1中cur賦值後可能爲null,到2會發生空指針異常。因此cur賦值後不能再被使用,應直接進入循環判斷條件。
結論:實際上這道題解題通過迭代解決方式單一。tmp只能保存cur.next,而不是保存prev。這樣可以使得cur=tmp(cur在賦值後不會再在代碼塊中使用)