1. 題目
【題目鏈接】👉234. 迴文鏈表
請判斷一個鏈表是否爲迴文鏈表。
示例 1:
輸入: 1->2
輸出: false
示例 2:
輸入: 1->2->2->1
輸出: true
進階:你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?
2. 鏈表構建
節點的創建連接
- 先在堆上開闢空間,將待添加的節點放入,
new ListNode(node)
- 然後指針後移一位即可
temp = temp.next
指針移動
- 將指針cur的值(地址)複製給pre即可
鏈表複製構建
創建一個 [以head
爲頭結點的鏈表] 相同的鏈表(head爲頭結點鏈表的克隆)
3. 解法一:鏈表複製反轉比較
- 先將給定鏈表複製一份新的res
- 反轉res
- 遍歷res和原鏈表,比較val是否相等
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null) return true;
ListNode res = new ListNode(head.val);
ListNode node = res;
ListNode temp = head.next;
while(temp != null) {
node.next = new ListNode(temp.val);
node = node.next;
temp = temp.next;
}
/*鏈表res克隆完成*/
ListNode l1 = head; //不破壞原鏈表結構,定義指針開始遍歷
ListNode l2 = reverse(res);
while(l1 != null) {
if(l1.val != l2.val) {
return false;
}
l1 = l1.next;
l2 = l2.next;
}
return true;
}
public ListNode reverse(ListNode head) {
if(head == null) return null;
ListNode prev = null;
while(head != null) {
ListNode next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
}
4. 解法二:輔助數組法
-
單鏈表檢查迴文串的難點就在於,只能沿一個方便遍歷,雙指針無法進行
-
於是我們就想到可以借用一個輔助數組,將鏈表節點拷貝到數組中,然後再數組中雙指針檢查,非常容易!
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null) return true;
ArrayList<Integer> list = new ArrayList<>();
ListNode temp = head;
while(temp != null) {
list.add(temp.val);
temp = temp.next;
}
int left = 0;
int right = list.size() - 1;
while(left <= right) {
if(!list.get(left).equals(list.get(right)))
return false;
left++;
right--;
}
return true;
}
}
5. 解法三:快慢指針 + 折半反轉
- 你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null) return true;
ListNode slow = head;
ListNode fast = head.next;
//快慢指針不斷迭代,找到中間節點
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 偶數節點,讓 slow 指向下一個節點
if(fast != null) {
slow = slow.next;
}
// 切成兩個鏈表
cut(head, slow);
return isEqual(head, reverse(slow));
}
private void cut(ListNode head, ListNode cutNode) {
while (head.next != cutNode) {
head = head.next;
}
head.next = null;
}
private ListNode reverse(ListNode head) {
if(head == null) return head;
ListNode prev = null;
while(head != null) {
ListNode next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
private boolean isEqual(ListNode l1, ListNode l2) {
while (l1 != null && l2 != null) {
if (l1.val != l2.val) return false;
l1 = l1.next;
l2 = l2.next;
}
return true;
}
}
如果兩表元素爲偶數個時,切割完後:
- L1:1 —> 2 —> null
- L2:1—> 2 —> 3 —> null
isEqual
方法的條件是l1 != null && l2 != null
,L1走到節點2後爲空,結束循環!