回文鏈表(快慢指針解法之在推進過程中反轉)

歸納編程學習的感悟,
記錄奮斗路上的點滴,
希望能幫到一樣刻苦的你!
如有不足歡迎指正!
共同學習交流!
🌎歡迎各位→點贊 👍+ 收藏? + 留言?📝

抱怨深處黑暗,不如提燈前行!

?

題目描述:

給你一個單鏈表的頭節點?head?,請你判斷該鏈表是否為回文鏈表。如果是,返回?true?;否則,返回?false?。

示例 1:

輸入:head = [1,2,2,1]
輸出:true

示例 2:

輸入:head = [1,2]
輸出:false

提示:

  • 鏈表中節點數目在范圍[1, 105]?內
  • 0 <= Node.val <= 9

思路推導

判斷該鏈表是否為回文鏈表,數據范圍node.val<=9,節點數量∈[1,10^5]node.val <= 9, 節點數量 ∈ [1,10^5]node.val<=9,節點數量∈[1,10^5?]

可選方案1:轉數字,判斷是否為回文數
可選方案2:轉字符串,判斷是否為回文串
但這樣做就沒有利用到鏈表自身的性質,因此不是最合適的解法。
根據「206.反轉鏈表」的思路,可以在完成「鏈表前半部分的反轉」之后,通過雙指針指向前半部分的頭結點和后半部分鏈表的頭結點,每次推進一步并判斷數值是否相等。
但這存在「奇數節點個數的鏈表」和「偶數節點個數的鏈表」的前半部分和后半部分劃分上的不同的問題。
情況分析
回文鏈表必然會存在「奇數個節點」的鏈表和「偶數個節點」的鏈表。

對于長度為奇數的回文鏈表
1->2->3->2->1,長度為5的鏈表,那么從回文中心3向左右兩側出發,會遍歷得到相同的數字序列。
對于偶數長度的回文鏈表:
1->2->2->1,長度為4的鏈表,如果回文,那么從第2和第3個節點出發,向兩側掃描,可以得到相同的數字序列。
因此,假設節點個數為n

奇數鏈表:

回文中心為:(n+1)/2個節點
回文邊界為:(n+1)/2 - 1,(n+1)/2 + 1
偶數鏈表:

沒有回文中心
回文邊界:n/2和n/2 + 1
之后可以通過「統計節點個數」->「對奇偶鏈表需要翻轉的節點個數分別判斷完成前半部分反轉」->「從前半部分鏈表和后半部分鏈表的頭結點向兩側掃描推進判斷數字是否相同」的方法來判斷回文鏈表。

但目前這樣的考慮過于復雜了,因為實際上我們無需計算節點個數,只需要確定鏈表中間節點的位置即可。「確定鏈表中間節點的位置」的方法通常使用快慢指針法。

示例分析
設計雙指針slow = head, fast = head
「奇數鏈表」和「偶數鏈表」最終確定的中間節點不一致,我們可以先確定「鏈表中間節點位置」,再「反轉前半部分的鏈表」;也可以考慮在slow指針推進過程中完成「局部反轉」,這樣到達「中間位置節點」時恰好完成了前半部分的反轉。

  • 偶數鏈表的示例分析:
局部翻轉還需要的變量pre以及變量初始化:
設計pre = null, slow = fast = head;
當前循環條件未知。
每次循環,slow指針每次前進一步,就翻轉局部鏈表,fast指針前進兩步。
偶數節點情況:
初始化:
null 1 -> 2 -> 2 -> 1 -> null^   ^
pre slow,fast
---------------------------------
第1輪循環
null<- 1   2 ->  2 -> 1 -> null^   ^ 	 ^pre  slow fast
---------------------------------
第2輪循環:
null<- 1 <- 2   2-> 1-> null^	^		 ^pre  slow 	fast
第二次循環結束后,就已經完成了前半部分鏈表的反轉,
pre指向前半部分鏈表的第一個元素。
slow到達「中間節點的第二個節點」。
slow指針指向后半部分鏈表的第一個元素。
偶數鏈表的循環退出條件是 fast == null
  • 奇數鏈表的示例分析:

奇數鏈表模擬:
初始化
null 1 -> 2 -> 3 -> 2 -> 1 -> null^   ^
pre  slow,fast
第一輪循環
null<- 1	2 -> 3 -> 2 -> 1 -> null^    ^	 ^pre  slow fast第二輪循環:
null<- 1 <- 2 	3 -> 2 -> 1 -> null^	^		  ^pre slow		fast
第二輪循環結束后,slow到達「鏈表中間節點」位置。
循環退出條件是 fast.next == null 
循環退出時
fast = 鏈表最后一個元素
pre 指向前部分鏈表的第一個元素
slow 指針指向后部分鏈表的第一個元素。
需要特殊處理:即將slow指針向后推進一位,
以保證和「偶數鏈表」相同,slow指針指向后半部分回文鏈表的第一個元素。
  • 抽取循環結束時的共性:

pre指向前半部分鏈表的第一個元素。
slow指針經過處理后,指向后半部分鏈表的首個元素
循環退出條件:
????????對于奇數鏈表為fast.next == null
????????對于偶數鏈表為fast==null

  • 通過「奇數鏈表」和「偶數鏈表」的示例分析得到偽代碼:

循環開始:
1. 變量初始化 
雙指針賦值slow = head, fast = head, 
局部旋轉前一個變量指針pre = null
局部翻轉需要保存的下一個節點 tmp = null 
2. 雙指針推進循環
循環條件(fast != null && fast.next != null){2.1 快指針每次推進兩步。2.2 慢指針通過「局部反轉」的方式進行指針的推進。
}
3.循環結束后的情況分析:3.1 偶數鏈表循環結束后,fast == null,pre指向前半部分第一個回文數slow指向后半部分第一個回文數3.2 奇數鏈表循環結束后,fast !=null, fast.next == nullpre指向前半部分第一個回文數slow指向后半部分第一個節點(鏈表中間節點)。為使得一致,slow指針需要指向第一個回文數需要將slow向前推進一步
因此,如果fast != null,將slow指針推進一步。
4. 此時pre指向前半部分鏈表第一個回文數,slow指向后半部分鏈表第一個回文數。
循環判斷:
循環條件:pre!= null || slow.next != null
向兩邊同時推進pre和slow,比較pre.val和slow.val是否相等,
如果pre.val != slow.val,說明不是回文數,返回false。
當pre和slow都推進到鏈表末尾,說明每個數都相等,返回true。

代碼實現:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
typedef struct ListNode LNode;
bool isPalindrome(struct ListNode* head) {LNode*fast;LNode*slow;fast=head;slow=head;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;}LNode *temp,*pre,*cur;pre=NULL;cur=slow;while(cur){temp=cur->next;cur->next=pre;pre=cur;cur=temp;}LNode*p;p=head;while(pre&&p){if(p->val!=pre->val){break;}p=p->next;pre=pre->next;}if(p==NULL||pre==NULL){return true;}else{return false;}
}

復雜度分析:

時間復雜度:O(n),雙指針掃描鏈表一遍O(n),局部反轉時間復雜度O(1),回文數比較時間復雜度O(n)。
空間復雜度:O(1),指針只占用了常量的空間。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/18100.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/18100.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/18100.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

進程間通信IPC機制

進程間通信&#xff08;IPC&#xff0c;InterProcess Communication&#xff09;是指在不同進程之間傳播或交換信息。IPC機制有多種方式&#xff0c;每種方式都有其特定的工作原理、應用場景以及優缺點。以下是對幾種主要IPC方式的詳細解釋&#xff1a; 管道&#xff08;Pipe&a…

數據結構算法題day04

數據結構算法題day04 題目分析算法思想代碼完整運行代碼如下&#xff1a; 題目 對長度為n的順序表L&#xff0c;編寫一個時間復雜度為O(n)、空間復雜度為O(1)的算法 該算法刪除線性表中所有值為X的數據元素。分析 O(n) -> 掃描一次順序表 O(1) -> 申請常數個輔助空間 1…

代碼隨想錄算法訓練營day14|二叉樹的遞歸遍歷、二叉樹的迭代遍歷、二叉樹的統一迭代法

二叉樹的遞歸遍歷 首先需要明確的一點是&#xff0c;前序中序和后序在二叉樹的遞歸遍歷中的區別僅在于遞歸函數中操作的順序&#xff0c;前序是在遍歷一個節點的左右子樹前進行操作&#xff0c;中序是在遍歷一個節點的左子樹后進行操作再遍歷右子樹&#xff0c;而后序是在遍歷…

C++算術運算和自增自減運算

一 引言 表示運算的符號稱為運算符。 算術運算&#xff1b; 比較運算&#xff1b; 邏輯運算&#xff1b; 位運算&#xff1b; 1 算術運算 算術運算包括加、減、乘、除、乘方、指數、對數、三角函數、求余函數&#xff0c;這些都是算術運算。 C中用、-、*、/、%分別表示加、減…

【AI】AI框架項目OpenWebUI如何追加模型

【背景】 openWebUI是一個非常好用的AI框架項目&#xff0c;既可以用API形式連接各類外部AI模型&#xff0c;也可以直接連接服務器硬盤上部署的離線大模型。 簡單來說&#xff0c;OpenWebUI可以用來方便地把你的本地模型變為可供所有內網人員使用的SAAS服務站點&#xff0c;并…

《當微服務遇上Ribbon:一場負載均衡的華麗舞會》

在微服務的廚房里&#xff0c;如何確保每一道服務都恰到好處&#xff1f;揭秘Spring Cloud Ribbon如何像大廚一樣精心調配資源&#xff0c;讓負載均衡變得像烹飪藝術一樣簡單&#xff01; 文章目錄 Spring Cloud Ribbon 詳解1. 引言微服務架構中的負載均衡需求Spring Cloud Rib…

【算法實戰】每日一題:設計一個算法,用最少數量的矩形覆蓋一系列寬度為d、高度為w的矩形,且使用矩形不能超出邊界

題目 設計一個算法&#xff0c;用最少數量的矩形覆蓋一系列寬度為d、高度為w的矩形建筑物側墻&#xff0c;且矩形不能超出邊界。 核心思路 考慮這種結構 前面遞增后面一個與前面的某個高度一致&#xff0c;這時候考慮最下面的覆蓋&#xff08;即都是從最下面向上覆蓋&#…

redis數據類型set,zset

華子目錄 Set結構圖相關命令sdiff key1 [key2]sdiffstore destination key1 [key2...]sinter key1 [key2...]sinterstore destination key1 [key2...]sunion key1 [key2...]sunionstore destination key1 [key2...]smove source destination memberspop key [count]sscan key c…

Java GC問題排查的一些個人總結和問題復盤

個人博客 Java GC問題排查的一些個人總結和問題復盤 | iwts’s blog 是否存在GC問題判斷指標 有的比較明顯&#xff0c;比如發布上線后內存直接就起飛了&#xff0c;這種也是比較好排查的&#xff0c;也是最多的。如果單純從優化角度&#xff0c;看當前應用是否需要優化&…

探索旅行的優惠之選,千益暢行旅游卡讓旅程更省心省力!

在旅行的道路上&#xff0c;一張旅游卡往往能為您帶來意想不到的便利與優惠。那么&#xff0c;對于千益暢行旅游卡&#xff0c;您是否好奇如何輕松擁有它呢&#xff1f; 首先&#xff0c;千益暢行旅游卡作為旅行者的貼心伴侶&#xff0c;為您提供了多樣化的獲取渠道。您可以通…

Unity實現首行縮進兩個字符

效果 在Unity中如果想實現首行縮進兩個字符&#xff0c;你會發現按空格是沒法實現的。 實現原理&#xff1a;用空白的透明的字替代原來的位置。 代碼&#xff1a; <color#FFFFFF00>XXX</color> 趕緊去試試吧&#xff01;

備戰秋招—模擬版圖面試題來了

隨著暑期的腳步逐漸臨近&#xff0c;電子工程和集成電路設計領域的畢業生們&#xff0c;也將迎來了另一個求職的黃金期——秋招。我們總說機會是留給有準備的人。對于有志于投身于模擬版圖設計的學子們來說&#xff0c;為了在眾多求職者中脫穎而出&#xff0c;充分備戰模擬版圖…

C# 工商銀行缺少infosecapiLib.infosec

搜索Tlbimp.exe 這里使用4.8.1下的處理&#xff0c;以管理員身份打開powershell cd "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools".\TlbImp.exe "G:\CSharp\icbc-api-sdk-cop-c#\sdk-cop\sdk-cop\dll\infosecapi.dll" …

PCIe協議之-DLLP詳解

?前言&#xff1a; &#x1f31f;數據鏈路層的功能 數據鏈路層將從物理層中獲得報文&#xff0c; 并將其傳遞給事務層&#xff1b; 同時接收事務層的報文&#xff0c; 并將其轉發到物理層; 核心的功能有以下三點 1.保證TLP在 PCIe 鏈路中的正確傳遞; 2.數據鏈路層使用了容錯…

頁面導出PDF,非可視區域如何解決

const exportToPDF () > {const element document.getElementById(chart-container);if (!element) return;const originalScrollHeight element.scrollHeight;// 臨時解除滾動條限制&#xff0c;確保所有內容都可見element.style.height ${originalScrollHeight}px;// …

殺死那個進程

一、場景 eclipse在啟動tomcat時&#xff0c;出現端口被占用的情況。我尋思著“任務管理器”沒出現相應程序在跑啊。 1.1問題&#xff1a;端口和進程的關系 端口和進程之間存在著一種關系&#xff0c;端口是一個邏輯概念&#xff0c;它用于標識網絡通信中的一個終點&#xff0…

SEC突發:以太坊ETF大概率獲批

美國證監會大概率批準以太坊現貨ETF。 5月20日&#xff0c;據外媒CoinDesk報道&#xff0c;知情人士透露&#xff0c;美國SEC周一要求證券交易所更新以太坊現貨ETF的19b-4備案文件。19b-4備案文件是一種表格&#xff0c;用于向SEC通報允許基金在交易所交易的規則變更。 三位消息…

利用cherry pick巧妙地將某次提交單獨合并到其他分支

0. 引言 最近在進行系統的多版本并行開發&#xff0c;涉及一些共有基礎功能提交時就遇到了麻煩&#xff0c;一份代碼需要向多個版本分支進行同步&#xff0c;以保證多版本都能有更新該基礎功能。 多次對比提交的方式顯然會帶來巨大的工作量。但實際上我們可以通過git的cherry…

「Python Socket超能力:網絡世界的隱形斗篷!」

Hi&#xff0c;我是阿佑&#xff0c;今天將帶領大家揭開Python Socket編程的神秘面紗&#xff0c;賦予我們的網絡應用隱形斗篷般的超能力&#xff01; 深入探討Socket編程的革命性力量&#xff0c;教你如何用Python的Socket模塊來構建強大的網絡應用。從簡單的HTTP服務器到復雜…

MagicLens:新一代圖像搜索技術和產品形態

MagicLens&#xff1a;Self-Supervised Image Retrieval with Open-Ended Instructions MagicLens: 自監督圖像檢索與開放式指令 作者&#xff1a;Kai Zhang&#xff0c; Yi Luan&#xff0c; Hexiang Hu&#xff0c; Kenton Lee&#xff0c; Siyuan Qiao&#xff0c; Wenhu …