算法:常見的鏈表算法

文章目錄

  • 鏈表算法
  • 兩數相加
    • 兩兩交換鏈表中的節點
    • 重排鏈表
    • 合并K個升序鏈表
    • K個一組翻轉鏈表
  • 總結

本篇總結常見的鏈表算法題和看他人題解所得到的一些收獲

鏈表算法

關于鏈表的算法:

  1. 畫圖:畫圖可以解決絕大部分的數據結構的問題,任何的算法題借助圖都可以有一個比較清晰的思路
  2. 引入哨兵位頭節點:頭節點可以避免處理很多邊界情況,在解決一些問題前很方便
  3. 多定義幾個變量:可以很方便的解決問題
  4. 快慢指針:在處理帶環的問題,環的入口,倒數節點的時候很好用

兩數相加

在這里插入圖片描述

在這里積累這個題的目的是學習代碼的寫法,學習他人的代碼

這是自己的代碼:

class Solution 
{
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode* newhead = new ListNode();ListNode* cur1 = l1;ListNode* cur2 = l2;ListNode* cur = newhead;int carry = 0, sum = 0, ret = 0;while(cur1 && cur2){// 計算出這個節點要存的值是多少sum = cur1->val + cur2->val + carry;carry = sum / 10;ret = sum % 10;// 插入節點ListNode* newnode = new ListNode(ret);cur->next = newnode;cur = newnode;// 迭代cur1 = cur1->next;cur2 = cur2->next;}while(cur1){// 計算出這個節點要存的值是多少sum = cur1->val + carry;carry = sum / 10;ret = sum % 10;// 插入節點ListNode* newnode = new ListNode(ret);cur->next = newnode;cur = newnode;// 迭代cur1 = cur1->next;}while(cur2){// 計算出這個節點要存的值是多少sum = cur2->val + carry;carry = sum / 10;ret = sum % 10;// 插入節點ListNode* newnode = new ListNode(ret);cur->next = newnode;cur = newnode;// 迭代cur2 = cur2->next;}if(carry){// 插入節點ListNode* newnode = new ListNode(carry);cur->next = newnode;cur = newnode;}return newhead->next;}
};

運行可以通過,但是代碼量比較冗余,其實可以發現while循環和后面的if語句有相當多的相似語句,因此看下面的代碼:

class Solution 
{
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode* newhead = new ListNode();ListNode* cur1 = l1;ListNode* cur2 = l2;ListNode* cur = newhead;int sum = 0;while(cur1 || cur2 || sum){// 先加第一個鏈表if(cur1){sum += cur1->val;cur1 = cur1->next;}// 再加第二個鏈表if(cur2){sum += cur2->val;cur2 = cur2->next;}// 處理節點數據cur->next = new ListNode(sum % 10);cur = cur->next;sum /= 10;}// 處理掉不必要的內存空間cur = newhead->next;delete newhead;return cur;}
};

兩兩交換鏈表中的節點

在這里插入圖片描述
其實這個題已經見過很多次了,有很多種解決方法,直接模擬,遞歸…

但是這里積累它的意義在于,引入虛擬頭節點對于解題是很有幫助的

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution 
{
public:ListNode* swapPairs(ListNode* head) {if(head == nullptr || head->next == nullptr)return head;ListNode* newhead = new ListNode();newhead->next = head;ListNode* prev = newhead;ListNode* cur = newhead->next;ListNode* next = cur->next;ListNode* nnext = next->next;while(cur && next){// 交換節點prev->next = next;next->next = cur;cur->next = nnext;// 迭代prev = cur;cur = prev->next;if(cur) next = cur->next;if(next) nnext = next->next;}ListNode* res = newhead->next;delete newhead;return res;}
};

不帶虛擬頭節點:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution 
{
public:ListNode* swapPairs(ListNode* head) {if(head == nullptr || head->next == nullptr)return head;// 先找到新的頭節點ListNode* newhead = head->next;// 找到當前待交換的兩個節點ListNode* left = head;ListNode* right = head->next;while(left && right){// 交換兩個節點left->next = right->next;right->next = left;// 進行迭代ListNode* prev = left;left = left->next;if(left){right = left->next;if(right)prev->next = right;}}return newhead;}
};

遞歸解題

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution 
{
public:ListNode* swapPairs(ListNode* head) {if(head == nullptr || head->next == nullptr)return head;ListNode* left = head;ListNode* right = left->next;ListNode* tmp = right->next;right->next = left;left->next = swapPairs(tmp);return right;}
};

重排鏈表

在這里插入圖片描述
積累本題的意義在于,本題綜合了逆序鏈表,快慢指針,鏈表插入的問題,是一個綜合性的題

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution 
{
public:void reorderList(ListNode* head) {// 利用快慢雙指針找到中間節點ListNode* slow = head;ListNode* fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}// 得到兩個新鏈表ListNode* newheadleft = head;ListNode* newheadright = Reverse(slow->next);slow->next = nullptr;// 把這兩個鏈表再組裝起來ListNode* newhead = new ListNode();ListNode* tail = newhead;ListNode* cur1 = newheadleft;ListNode* cur2 = newheadright;while(cur1 || cur2){if(cur1){tail->next = cur1;tail = tail->next;cur1 = cur1->next;}if(cur2){tail->next = cur2;tail = tail->next;cur2 = cur2->next;}}ListNode* res = newhead->next;delete newhead;head = res;}ListNode* Reverse(ListNode* head){ListNode* newhead = new ListNode();ListNode* cur = head;while(cur){ListNode* next = cur->next;cur->next = newhead->next;newhead->next = cur;cur = next;}ListNode* res = newhead->next;delete newhead;return res;}
};

合并K個升序鏈表

在這里插入圖片描述

關于這個題,乍一看其實是很難想到用什么方法做的,而實際上如果要是使用優先級隊列或者是遞歸的思想來解題是可以解決的,算法的思路難,但是實際的變現并不難

這里提供三種解題方法:暴力求解、利用優先級隊列來解題、利用歸并的思想來解題

暴力求解

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution 
{
public:// 利用合成的思想解題ListNode* mergeKLists(vector<ListNode*>& lists) {ListNode* newhead = new ListNode();ListNode* tail = newhead;for(int i = 0; i < lists.size(); i++){merge(newhead->next, lists[i]);}return newhead->next;}void merge(ListNode*& head, ListNode* cur){ListNode* newhead = new ListNode();ListNode* tail = newhead;while(head && cur){if(head->val < cur->val){tail->next = head;tail = tail->next;head = head->next;}else{tail->next = cur;tail = tail->next;cur = cur->next;}}if(head) tail->next = head;if(cur) tail->next = cur;head = newhead->next;}
};

利用優先級隊列的思想解題

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution 
{
public:struct cmp{bool operator()(ListNode* l1, ListNode* l2){return l1->val > l2->val;}};// 利用優先級隊列進行優化ListNode* mergeKLists(vector<ListNode*>& lists) {priority_queue<ListNode*, vector<ListNode*>, cmp> pq;// 把每一個鏈表都塞進去for(int i = 0; i <lists.size(); i++){if(lists[i])pq.push(lists[i]);}// 創建虛擬頭節點,開始鏈入到鏈表中ListNode* newhead = new ListNode();ListNode* tail = newhead;// 找到最小的節點,拿出來,再把它的下一個節點再塞進去,直到隊列為空while(!pq.empty()){ListNode* top = pq.top();pq.pop();if(top != nullptr){ListNode* next = top->next;top->next = nullptr;// 塞到目標鏈表中tail->next = top;tail = tail->next;// 再把剩下的部分再塞進去if(next)pq.push(next);}}// 返回信息ListNode* res = newhead->next;delete newhead;return res;}
};

利用歸并的思想解題

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution 
{
public:// 采用歸并的方式進行解題ListNode* mergeKLists(vector<ListNode*>& lists) {return merge(lists, 0, lists.size() - 1);}// 歸并排序ListNode* merge(vector<ListNode*>& lists, int left, int right){// 處理特殊情況if(left > right) return nullptr;if(left == right) return lists[left];// 拆分數組int midi = left + (right - left) / 2;// [left, midi][midi + 1, right]ListNode* l1 = merge(lists, left, midi);ListNode* l2 = merge(lists, midi + 1, right);// 排序return mergetwonode(l1, l2);}// 合并鏈表ListNode* mergetwonode(ListNode* l1, ListNode* l2){ListNode* newhead = new ListNode();ListNode* cur1 = l1, *cur2 = l2, *tail = newhead;while(cur1 && cur2){if(cur1->val <= cur2->val){tail->next = cur1;cur1 = cur1->next;tail = tail->next;}else{tail->next = cur2;cur2 = cur2->next;tail = tail->next;}}if(cur1) tail->next = cur1;if(cur2) tail->next = cur2;ListNode* res = newhead->next;delete newhead;return res;}
};

K個一組翻轉鏈表

在這里插入圖片描述

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution 
{// 思路:把鏈表k個一組拿出來,再翻轉,再鏈入一個新的鏈表中
public:ListNode* reverseKGroup(ListNode* head, int k) {ListNode* newhead = new ListNode();ListNode* tail = newhead;ListNode* left = head, *right = left;while(left && right){// 把鏈表k個一組分出來for(int i = 1; i < k; i++){// 如果此時已經到最后了,那么這最后一組就不需要進行翻轉if(right == nullptr){tail->next = left;return newhead->next;}right = right->next;}// 斷鏈if(right){ListNode* newleft = right->next;right->next = nullptr;// 現在從[left, right]就是一段完整的不帶頭節點的鏈表了// 把這段鏈表進行翻轉,并鏈入到新的鏈表中tail->next = reverse(left);tail = left;// 迭代,找下一組k個節點left = newleft, right = left;}}tail->next = left;return newhead->next;}// 進行鏈表的反轉ListNode* reverse(ListNode* cur){ListNode* newhead = new ListNode();// 把鏈表中的節點頭插到新鏈表中while(cur){ListNode* next = cur->next;cur->next = newhead->next;newhead->next = cur;cur = next;}ListNode* res = newhead->next;delete newhead;return res;}
};

這個題的難點在于細節問題的處理,其實思路并不難

總結

其實對于鏈表這一塊的算法主要是體現在需要處理一些邊界情況和循環調用帶來的問題,通過借助虛擬頭節點和多創建幾個指針可以緩解這種情況,主要是細節要處理好,對于思維的需求沒有那么高

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

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

相關文章

視覺學習筆記12——百度飛漿框架的PaddleOCR 安裝、標注、訓練以及測試

系列文章目錄 虛擬環境部署 參考博客1 參考博客2 參考博客3 參考博客4 文章目錄 系列文章目錄一、簡單介紹1.OCR介紹2.PaddleOCR介紹 二、安裝1.anaconda基礎環境1&#xff09;anaconda的基本操作2&#xff09;搭建飛漿的基礎環境 2.安裝paddlepaddle-gpu版本1&#xff09;安裝…

語言模型GPT與HuggingFace應用

受到計算機視覺領域采用ImageNet對模型進行一次預訓練&#xff0c;使得模型可以通過海量圖像充分學習如何提取特征&#xff0c;然后再根據任務目標進行模型微調的范式影響&#xff0c;自然語言處理領域基于預訓練語言模型的方法也逐漸成為主流。以ELMo為代表的動態詞向量模型開…

C#8.0本質論第十七章--構建自定義集合

C#8.0本質論第十七章–構建自定義集合 17.1更多集合接口 17.1.1IList< T >和IDictionary< TKey , TValue > 這兩個接口決定了集合類型是側重于通過位置索引來獲取值&#xff0c;還是側重于通過鍵來獲取值。 實現這兩個接口的類都必須提供索引器。 17.1.2IColl…

在線教育小程序正在成為教育行業的新生力量

教育數字化轉型是目前教育領域的一個熱門話題&#xff0c;那么到底什么是教育數字化轉型&#xff1f;如何做好教育數字化轉型&#xff1f; 教育數字化轉型是利用信息技術和數字工具改變和優化教育的過程。主要特征包括技術整合、在線學習、個性化學習、大數據分析、云計算、虛擬…

【C++學習手札】基于紅黑樹封裝模擬實現map和set

? &#x1f3ac;慕斯主頁&#xff1a;修仙—別有洞天 &#x1f49c;本文前置知識&#xff1a; 紅黑樹 ??今日夜電波&#xff1a;漂流—菅原紗由理 2:55━━━━━━?&#x1f49f;──────── 4:29 …

Appium獲取toast方法封裝

一、前置說明 toast消失的很快&#xff0c;并且通過uiautomatorviewer也不能獲取到它的定位信息&#xff0c;如下圖&#xff1a; 二、操作步驟 toast的class name值為android.widget.Toast&#xff0c;雖然toast消失的很快&#xff0c;但是它終究是在Dom結構中出現過&…

【計算機網絡】HTTP請求

目錄 前言 HTTP請求報文格式 一. 請求行 HTTP請求方法 GET和POST的區別 URL 二. 請求頭 常見的Header 常見的額請求體數據類型 三. 請求體 結束語 前言 HTTP是應用層的一個協議。實際我們訪問一個網頁&#xff0c;都會像該網頁的服務器發送HTTP請求&#xff0c;服務…

使用Java將圖片添加到Excel的幾種方式

1、超鏈接 使用POI&#xff0c;依賴如下 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency>Java代碼如下,運行該程序它會在桌面創建ImageLinks.xlsx文件。 …

GPT-4V 在機器人領域的應用

在科技的浩渺宇宙中&#xff0c;OpenAI如一顆璀璨的星辰&#xff0c;于2023年9月25日&#xff0c;以一種全新的方式&#xff0c;向世界揭示了其最新的人工智能力作——GPT-4V模型。這次升級&#xff0c;為其旗下的聊天機器人ChatGPT裝配了語音和圖像的新功能&#xff0c;使得用…

『Linux升級路』進度條小程序

&#x1f525;博客主頁&#xff1a;小王又困了 &#x1f4da;系列專欄&#xff1a;Linux &#x1f31f;人之為學&#xff0c;不日近則日退 ??感謝大家點贊&#x1f44d;收藏?評論?? 目錄 一、預備知識 &#x1f4d2;1.1緩沖區 &#x1f4d2;1.2回車和換行 二、倒計…

修改正點原子綜合實驗的NES模擬器按鍵控制加橫屏

??????? 開發板&#xff1a;stm32f407探索者開發板V2 屏幕是4.3寸-800-480-MCU屏 手頭沒有V3開發板&#xff0c;只有V2&#xff0c;所以沒法測試 所以只講修改哪里&#xff0c;請自行修改 先改手柄部分&#xff0c;把手柄改成按鍵 找到左邊的nes文件夾中的nes_mai…

采用軌到軌輸出設計 LTC6363HMS8-2、LTC6363HMS8-1、LTC6363HRD、LTC6363IDCB差分放大器I

產品詳情 LTC6363 系列包括四個全差分、低功耗、低噪聲放大器&#xff0c;具有經優化的軌到軌輸出以驅動 SAR ADC。LTC6363 是一款獨立的差分放大器&#xff0c;通常使用四個外部電阻設置其增益。LTC6363-0.5、LTC6363-1 和 LTC6363-2 都有內部匹配電阻&#xff0c;可分別創建…

【Python百寶箱】代碼沖突?文件合并不再是問題!Python解決方案大揭秘

Python腳本與圖形工具&#xff1a;文件比較與合并的完整指南 前言 在軟件開發、版本控制和數據處理領域&#xff0c;文件比較和合并是至關重要的任務。Python生態系統中涌現了許多強大的工具和庫&#xff0c;為開發者提供了豐富的選擇。本指南將深入探討 Python 中常用的文件…

看完了一個動畫電影-心靈奇旅

refer: 開二倍速看完了&#xff0c;一部分是聽的&#xff0c;劇情還可以&#xff0c;就是普通的治愈片。 里邊有個臺詞&#xff1a; 一條小魚游到一條老魚旁邊說,“我要找到他們稱之為海洋的東西。” “海洋?”老魚問,“你現在就在海洋里啊。” “這兒?”小魚說,“這兒是水…

人工智能:走向未來的智慧之路

1. 定義與范疇 人工智能&#xff08;AI&#xff09;是一門研究如何使計算機系統能夠模擬人類智慧的科學與技術。這包括了機器學習、深度學習、自然語言處理、計算機視覺等多個子領域。機器學習讓計算機能夠通過數據學習&#xff0c;而深度學習則通過模擬人腦神經網絡的方式實現…

C++數據結構:B樹

目錄 一. 常見的搜索結構 二. B樹的概念 三. B樹節點的插入和遍歷 3.1 插入B樹節點 3.2 B樹遍歷 四. B樹和B*樹 4.1 B樹 4.2 B*樹 五. B樹索引原理 5.1 索引概述 5.2 MyISAM 5.3 InnoDB 六. 總結 一. 常見的搜索結構 表示1為在實際軟件開發項目中&#xff0c;常用…

博途PLC SCL間接尋址編程應用

這篇博客里我們將要學習Pointer和Any指針&#xff0c;PEEK和POKE指令&#xff0c;當然我們還可以數組類型數據實現數組指針尋址&#xff0c;具體應用介紹請參考下面文章鏈接&#xff1a; https://rxxw-control.blog.csdn.net/article/details/134761364https://rxxw-control.b…

一文講解如何從 Clickhouse 遷移數據至 DolphinDB

ClickHouse 是 Yandex 公司于2016年開源的 OLAP 列式數據庫管理系統&#xff0c;主要用于 WEB 流量分析。憑借面向列式存儲、支持數據壓縮、完備的 DBMS 功能、多核心并行處理的特點&#xff0c;ClickHouse 被廣泛應用于廣告流量、移動分析、網站分析等領域。 DolphinDB 是一款…

【Hadoop_02】Hadoop運行模式

1、Hadoop的scp與rsync命令&#xff08;1&#xff09;本地運行模式&#xff08;2&#xff09;完全分布式搭建【1】利用102將102的文件推到103【2】利用103將102的文件拉到103【3】利用103將102的文件拉到104 &#xff08;3&#xff09;rsync命令&#xff08;4&#xff09;xsync…

使用 HTML 地標角色提高可訪問性

請務必確保所有用戶都可以訪問您的網站&#xff0c;包括使用屏幕閱讀器等輔助技術的用戶。 一種方法是使用 ARIA 地標角色來幫助屏幕閱讀器用戶輕松瀏覽您的網站。使用地標角色還有其他好處&#xff0c;例如改進 HTML 的語義并更輕松地設置網站樣式。在這篇博文中&#xff0c;我…