如何判斷一個單向鏈表是否為回文鏈表(Palindrome Linked List)


題目:給定一個單向鏈表,判斷它是不是回文鏈表(即從前往后讀和從后往前讀是一樣的)。原題見下圖,還要求了O(n)的時間復雜度O(1)的空間復雜度。

我的思考:

1,一看到這個題目,大腦馬上想到的解決方案就是數組。遍歷鏈表,用數組把數據存下來,然后再進行一次遍歷,同時用數組反向地與之比較,這樣就可以判斷是否回文。這個方法時間復雜度是O(n),達到了要求,然而空間復雜度顯然不滿足要求。所以,開數組這一類的方法顯然不是最佳的。

2,既然要滿足O(1)的空間復雜度,我就想到了用一個變量來存儲這些數據,恰好題目給出的數據也是整型。具體思路就是用一個long int:sum來存儲這些數據,第一次遍歷:第一個節點的數據乘1加到sum,第二個節點的數據乘2加到sum,第三個節點的數據乘3加到sum……;然后再反向進行第二次遍歷,sum減去最后一個節點的數據和1的乘積,sum減去倒數第二個節點的數據和2的乘積……。只要看最后的sum是否為0就可以判斷鏈表是否回文。當然,在第一次遍歷的時候需要一邊遍歷一邊逆置該鏈表,才能進行第二次遍歷。貼上代碼:

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
class Solution { public: bool isPalindrome(ListNode* head) { ListNode *point1, *point2, *point3; point3 = point2 = head; point1 = NULL; long int sum = 0; int n = 1; if(head == NULL || head->next == NULL return true; while(point3->next != NULL)//第一次遍歷,取值並逆置 { sum += n*point3->val; n++; point3 = point3->next; point2->next = point1; point1 = point2; point2 = point3; } sum += n*point3->val; point2->next = point1; n = 1; while(point2 != NULL)//第二次遍歷 { sum -= n*point2->val; n++; point2 = point2->next; } if(sum == 0) return true; else
            return false; } };

提交的結果顯示這個方法在題目的條件范圍內是可行的:

仔細一想,如果節點中的數據是字符,是浮點數怎么辦?這時這個方法的局限性就顯現出來了。

3,不能用一個整型來存儲字符這類的信息,那只能直接比較節點里的信息了。怎么比較?我們知道回文鏈表的特點就是對稱,那么要判斷是否回文就可以用兩個指針指向對稱的節點,看里面的信息是否一樣。即對稱的位置是否有對稱的信息。由於是單向鏈表,不能同時用兩個指針從頭尾向內部遍歷取值比較。那么就考慮從鏈表中間開始,用兩個指針向兩頭遍歷取值比較,顯然這也需要進行鏈表逆置。

具體的做法就是先遍歷一次鏈表得到鏈表長度。然后第二次遍歷到鏈表中間,並在遍歷的時候進行逆置。然后兩個指針分離,分別向兩個端點移動,同時進行比較,數據相同則繼續,數據不同則直接返回false。直到遍歷完成,最后返回true。代碼:

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
class Solution { public: bool isPalindrome(ListNode* head) { int lenth, i; ListNode *point1, *point2, *point3; point3 = point2 = head; point1 = NULL; lenth = 0; if(head == NULL || head->next == NULL) return true; while(point3 != NULL)//取得長度 { point3 = point3->next; lenth++; } for(i = 0;i < (lenth / 2);i++)//遍歷到中間,並逆置 { point3 = point2->next; point2->next = point1; point1 = point2; point2 = point3; } if((lenth % 2) == 1) point3 = point3->next; while(point3 != NULL && point1 != NULL)//兩個指針開始向兩頭移動,取值比較 { if(point3->val != point1->val) return false; point3 = point3->next; point1 = point1->next; } return true;//比較中沒有發現不同值,則為回文鏈表 } };

最后的結果也證明這個方法是可行的:

 

比起上一種方法,這個方法沒有存儲信息的操作,所以不必擔心用什么數據類型去存儲,也不用擔心數據的溢出,適用的范圍當然也就更大。

若博文中有什么不正確的地方歡迎大家指正,謝謝~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM