題目:給你一個單連結串列的頭節點 head ,請你判斷該連結串列是否為迴文連結串列。如果是,返回 true ;否則,返回 false 。
連結: 力扣LeetBook—初級演算法—連結串列—迴文連結串列.
示例 1:
輸入:head = [1,2,2,1]
輸出:true
示例 2:
輸入:head = [1,2]
輸出:false
標籤:棧、遞迴、連結串列、雙指標
思路:
- 迴圈遍歷連結串列,快指標每次走兩個節點,慢指標每次走一個節點,當快指標遍歷完連結串列,慢指標停下的位置就是中心點。(因為快指標從第二個節點開始走,所以不需要考慮奇偶的情況)
- 當找到中心點後,把慢指標走過的節點從頭到中心點截斷,為待比較的第一部分連結串列。
- 將從中心點到連結串列結尾的部分所有節點進行倒序操作。作為待比較的第二部分連結串列。
- 比較兩個連結串列每個節點是否相等,如果相等則為迴文。
主要Go程式碼如下:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func isPalindrome(head *ListNode) bool {
if head == nil || head.Next == nil {
return true
}
fast := head.Next // 快指標,從第二個開始,可以解決奇偶問題
slow := head // 慢指標
// 因為快指標從第二個節點開始走,所以不需要考慮奇偶的情況。
for fast != nil && fast.Next != nil {
fast = fast.Next.Next // 快指標每次走兩個節點
slow = slow.Next // 慢指標每次走一個節點
}
// 當快指標遍歷完連結串列,慢指標停下的位置就是中心點
cur := slow.Next // 保留後面還沒有遍歷的連結串列
slow.Next = nil // 將整個列表進行截斷,儲存為第一個連結串列
p := reverseLink(cur) // 將後面的連結串列倒序
// 比較兩個連結串列
for p != nil && head != nil {
if p.Val != head.Val {
return false
}
p = p.Next
head = head.Next
}
return true
}
// reverseLink 將連結串列倒序
func reverseLink(listHead *ListNode) *ListNode {
if listHead == nil && listHead.Next == nil {
return listHead
}
p := listHead // 遍歷連結串列的指標
var rst *ListNode // 儲存最後結果連結串列的指標
var q *ListNode // 儲存下一個節點的臨時指標
for p != nil {
q = p.Next
p.Next = rst
rst = p
p = q
}
return rst
}
提交截圖:
官方解答:
看了官方解答後恍然大悟,官方這種方法太簡單了,它用了將值複製到陣列中後用雙指標法
步驟:1、 複製連結串列值到陣列列表中。2、使用雙指標法判斷是否為迴文。
func isPalindrome(head *ListNode) bool {
vals := []int{}
for ; head != nil; head = head.Next {
vals = append(vals, head.Val)
}
n := len(vals)
for i, v := range vals[:n/2] {
if v != vals[n-1-i] {
return false
}
}
return true
}