在leetcode上有兩個題
234. 回文鍊錶
面試題 02.06. 回文鍊錶
請判斷乙個鍊錶是否為回文鍊錶。
示例 1:
輸入: 1->2
輸出: false
示例 2:
輸入: 1->2->2->1
輸出: true
高階:你能否用 o(n) 時間複雜度和 o(1) 空間複雜度解決此題?
遍歷一遍鍊錶得到值的陣列
判斷陣列是否是回文的
時間複雜度:o(n),其中 n指的是鍊錶的元素個數。class
solution
int n = list.
size()
;// 使用stream得到int陣列
int[
] array = list.
stream()
.maptoint
(i -
> i)
.toarray()
;for
(int i =
0; i < n /
2; i++)}
return
true;}
}
空間複雜度:o(n),其中 n指的是鍊錶的元素個數,我們使用了乙個陣列列表存放鍊錶的元素值。
為了想出使用空間複雜度為 o(1)的演算法,你可能想過使用遞迴來解決,但是這仍然需要 o(n)的空間複雜度。
遞迴為我們提供了一種優雅的方式來方向遍歷節點。
如果使用遞迴反向迭代節點,同時使用遞迴函式外的變數向前迭代,就可以判斷鍊錶是否為回文。function print_values_in_reverse
(listnode head)
if head is not null
print_values_in_reverse
(head.next)
print head.val
演算法currentnode 指標是先到尾節點,由於遞迴的特性再從後往前進行比較。frontpointer 是遞迴函式外的指標。若 currentnode.val != frontpointer.val 則返回 false。反之,frontpointer 向前移動並返回 true。
演算法的正確性在於遞迴處理節點的順序是相反的(回顧上面列印的演算法),而我們在函式外又記錄了乙個變數,因此從本質上,我們同時在正向和逆向迭代匹配。
時間複雜度:o(n,其中 n指的是鍊錶的大小。class
solution
private
boolean
check
(listnode head)
}
空間複雜度:o(n),其中 n指的是鍊錶的大小。我們要理解計算機如何執行遞迴函式,在乙個函式中呼叫乙個函式時,計算機需要在進入被呼叫函式之前跟蹤它在當前函式中的位置(以及任何區域性變數的值),通過執行時存放在堆疊中來實現(堆疊幀)。在堆疊中存放好了資料後就可以進入被呼叫的函式。在完成被呼叫函式之後,他會彈出堆疊頂部元素,以恢復在進行函式呼叫之前所在的函式。在進行回文檢查之前,遞迴函式將在堆疊中建立 nn 個堆疊幀,計算機會逐個彈出進行處理。所以在使用遞迴時空間複雜度要考慮堆疊的使用情況。
這種方法不僅使用了 o(n) 的空間,且比第一種方法更差,因為在許多語言中,堆疊幀的開銷很大(如 python),並且最大的執行時堆疊深度為 1000(可以增加,但是有可能導致底層解釋程式記憶體出錯)。為每個節點建立堆疊幀極大的限制了演算法能夠處理的最大鍊錶大小。
避免使用 o(n)額外空間的方法就是改變輸入。
我們可以將鍊錶的後半部分反轉(修改鍊錶結構),然後將前半部分和後半部分進行比較。比較完成後我們應該將鍊錶恢復原樣。雖然不需要恢復也能通過測試用例,但是使用該函式的人通常不希望鍊錶結構被更改。
該方法雖然可以將空間複雜度降到 o(1),但是在併發環境下,該方法也有缺點。在併發環境下,函式執行時需要鎖定其他執行緒或程序對鍊錶的訪問,因為在函式執行過程中煉表會被修改。
演算法整個流程可以分為以下五個步驟:
找到前半部分鍊錶的尾節點。 【快慢指標】
反轉後半部分鍊錶。 【反轉鍊錶】
判斷是否回文。
恢復鍊錶。
返回結果。
時間複雜度:o(n),其中 n指的是鍊錶的大小。class
solution
// 找到前半部分鍊錶的尾節點並反轉後半部分鍊錶
listnode firsthalfend =
getfirsthalf
(head)
; listnode secondhalfstart =
reverselist
(firsthalfend.next)
;// 判斷是否回文
listnode firsthalfcur = head;
listnode secondhalfcur = secondhalfstart;
boolean result =
true
;// 注意這裡是secondhalfcur不為空,不能是firsthalfcur。
while
(result && secondhalfcur != null)
firsthalfcur = firsthalfcur.next;
secondhalfcur = secondhalfcur.next;
} firsthalfend.next =
reverselist
(secondhalfstart)
;return result;
}public listnode reverselist
(listnode head)
return pre;
}public listnode getfirsthalf
(listnode head)
return slow;
}}
空間複雜度:o(1)。我們只會修改原本鍊錶中節點的指向,而在堆疊上的堆疊幀不超過 o(1)。
我們知道棧是先進後出的一種資料結構,這裡還可以使用棧先把鍊錶的節點全部存放到棧中。
其實我們只需要拿鍊錶的後半部分和前半部分比較即可,沒必要全部比較,所以這裡可以優化一下
public
boolean
ispalindrome
(listnode head)
stack
stack =
newstack
<
>()
; listnode cur = head;
while
(cur != null)
int size = stack.
size()
; size >>=1;
while
(size--
>=0)
head = head.next;
}return
true
;}
初級 鍊錶 回文鍊錶
題目 請判斷乙個鍊錶是否為回文鍊錶。示例 1 輸入 1 2 輸出 false 示例 2 輸入 1 2 2 1 輸出 true 高階 你能否用 o n 時間複雜度和 o 1 空間複雜度解決此題?思路 原思路 將鍊錶遍歷一遍,存入陣列,但空間複雜度為o n 不符合要求 正確思路 用快慢陣列找出鍊錶的中間...
leetcode 鍊錶 回文鍊錶
請判斷乙個鍊錶是否為回文鍊錶。示例 1 輸入 1 2 輸出 false 示例 2 輸入 1 2 2 1 輸出 true 高階 你能否用 o n 時間複雜度和 o 1 空間複雜度解決此題?head null 空鍊錶,回文,返回true head.next null 只有乙個節點的列表,回文,返回tru...
leetcode 鍊錶 回文鍊錶
請判斷乙個鍊錶是否為回文鍊錶。示例 1 輸入 1 2輸出 false示例 2 輸入 1 2 2 1輸出 true高階 你能否用 o n 時間複雜度和 o 1 空間複雜度解決此題?思路 利用快慢指標找到中間節點,當快指標走到末尾時,慢指標指向中間節點 交中間節點之後的節點進行鍊錶反轉 設定指標p1從h...