單鏈表-快慢指針-解決迴文問題

先簡單瞭解下:

單鏈表:

快慢指針:

slow:正常的指針,每次走一步

fast:每次走兩步

迴文問題:

noon、奧利奧、1221等等這種就是迴文

 

如何用快慢指針解決單鏈表的迴文問題呢?

看到noon 、 奧利奧這樣的字眼,我們可以想

以noon爲例,我們可以從no  on 中間開始,一邊往左,一邊右,同時去判斷,直到結束(遇到null了)

那麼怎麼找到這個中間位置呢?——快慢指針

爲什麼快慢指針能找到中間位置呢?——如果走n步的話,s(slow)走了n步,f(fast)走了2n步

這時候如果鏈表長度剛好爲2n,那麼s就在中間位置了呀

(這裏先埋下個伏筆,鏈表的長度都一定是2的倍數(偶數)嗎,通常遇到2n我們都要去考慮下奇偶數的問題)

那如果要使指針能夠往左邊走的話,我們是不是需要在原先的鏈表上逆序?(先不考慮破壞原鏈表的問題哈,我們這裏只要結果)

逆序中我們需要幾個指針呢?

1個?——肯定不行

2個?——不夠,原因如下:

假設現在我們有這樣的鏈表,s、prev兩個指針(先忽略fast)

如果此時,s要完成逆序,需要把s的next指向prev,那會發生什麼呢?

這時候可以發現,鏈表斷掉了

那有人說了,我不用prev,我用next,就是這個

如果這是一條很長的鏈表(1,2,3,4只是中間的某幾個點的標註)

那麼s如何找到它的前面一個結點呢?——再遍歷一遍嘛——當然可以,你有錢任性(不管時間複雜度)

因此我們就選用三個指針好了 ,prev s 和next 這三個,這樣就絕對萬無一失了(怎麼指向我都有原來的指針指着,不會丟)

好了我們確定了用三個指針後,就是實現逆序的過程

第一步:改變s.next的指向

第二步,prev去到s的位置(s準備去next的位置)

(注意這裏用的並不是prev.next 中間過程的prev是指向前面的,也就是這樣的)

第三步,s去到next的位置(同樣不是用s.next過去的哦!s.next現在已經指着1了而不是2)

第四步,next移動到下一個位置(這時候可以用next.next了)

這個逆序的過程其實是在s不斷前進直到在中間位置的過程中進行

 

那怎麼到中間位置呢?——靠的是fast來停止而不是slow哦

這是因爲f走得快,容易到鏈表的結尾

剛纔埋下的奇偶問題這裏f也遇到了

也就是鏈表長度爲奇數偶數時,f所在位置時不同的,同時也決定了要不要給s處理一下(是否再往後走一步,爲什麼?看下去)

先來看下爲奇數爲偶數時的s f情況(就先僅僅看s f移動,先不看逆序)

奇數:

偶數:

(f每次走就是 f. next.next)

可以看到到應該停止下來的地方時 奇偶不同 f的位置也不同

就是 奇數:f.next==null  偶數: f==null

這時我們再結合逆序來看下s(之後就是判斷迴文了,此時需要判斷下s的情況)

奇數情況(此時就不再看f了 因爲已經找到中間位置了)

可以看到如果需要進行比較的話肯定是prev和s間進行比較,而此時還需要讓s走下一步,這樣纔到開始判斷的地方(也就是c並不需要判斷),即

不斷 判斷 和 用next移到各自下一個,直到遇到null

偶數情況:

此時可以看到,不需要對s進行額外的操作就可以開始判斷迴文

到這裏,就全部解析完用快慢指針 解決單鏈表迴文問題

 

當然解決單鏈表迴文問題還可以用其他方法解決 例如藉助堆棧

https://blog.csdn.net/tangli555/article/details/51384296

用快慢指針只是因爲我第一次學的時候就是用這個來解決,而且這個相比藉助用堆棧也比較難理解一丟丟丟丟丟丟

借鑑代碼:

https://www.jianshu.com/p/462fa3e4cd43

class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
}
ListNode prev = null;
ListNode slow = head;
ListNode fast = head;

#去找中間位置,同時把前面部分逆序
while (fast != null && fast.next != null) {
  fast = fast.next.next;
  ListNode next = slow.next;
  slow.next = prev;
  prev = slow;
  slow = next;
}

#這是爲奇數時對s額外的操作
if (fast != null) {
  slow = slow.next;
}

#開始判斷迴文
while (slow != null) {
  if (slow.val != prev.val) {
    return false;
  }
  slow = slow.next;
  prev = prev.next;
}

return true;

}
}

 

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