ARTS - 第一週:算法——翻轉鏈表

 

題目

反轉一個單鏈表。

示例:

輸入: 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在賦值後不會再在代碼塊中使用)

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章