算法系列--鏈表問題

一.一些經驗總結

  1. 鏈表天然具有遞歸性質,單鏈表可以看做一個單叉樹,很多可以應用到二叉樹的題目也可以應用到鏈表的題目之中,下面是一個體現單鏈表遞歸性質很好的例子逆序打印鏈表的值
private void reversePrint(ListNode head) {if(head == null) return;reversePrint(head.next);System.out.println(head.val)
}

不難發現這種打印方式很像二叉樹中的后序遍歷
2. 對于鏈表的題目,思路往往很容易想到,只是過程可能有點復雜,一定要多畫圖,一定要舍得用變量

二.例題講解

01.刪除排序鏈表中重復的元素
鏈接:https://leetcode.cn/problems/remove-duplicates-from-sorted-list/description/
分析

  • 這是鏈表去重的經典問題,有多種解法
  • 最容易想到的解法就是使用一個去重的數據結構(Set),遍歷整個鏈表
  • 最優秀的解法是一個指針,一次遍歷,注意題目條件,數組是有序的,那么重復元素一定是相鄰的,每遍歷到一個節點,就判斷cur.val == cur.next.val,如果相等,就刪除cur.next(完成一次刪除操作);如果不等,直接讓cur向后走一步即可

代碼:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode deleteDuplicates(ListNode head) {if(head == null) return null;// 原地去重ListNode cur = head;while(cur.next != null) {if(cur.val ==cur.next.val) cur.next = cur.next.next;else cur = cur.next;// 有可能直接走到null}return head;}
}

說明:

  1. 循環的條件往往是根據下面的判斷條件決定的,判斷條件是cur.val == cur.next.val,如果cur.next ==null,則會觸發空指針異常,所以循環的條件是cur.next != null,對于鏈表的最后一個元素,要么是重復元素,要么不是重復元素,如果是重復元素,則前一個節點的值和當前節點的值相等,在上一步就會執行刪除操作;如果不是重復元素,不用刪除
  2. 為什么存在重復元素的情況,刪除重復元素之后不讓cur走一步?因為有可能刪除的是最后一個元素,這樣cur.next = null,如果讓cur向后走一步,在下一步的循環判斷中就會觸發空指針異常

刪除重復元素的進階版
鏈接:https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/description/
分析

  • 本題相較于上一題,需要將所有的重復元素都刪除,而上一題是只保留重復元素的一個
  • 同樣也可以采用一個指針,一次遍歷的操作,不過本題要刪除所有的重復元素,就不能讓指針走到重復元素的位置,應該走到第一個重復元素的前去節點,即判斷cur.next.val == cur.next.next.val,如果相等,則一直循環刪除所有等于cur.next.val(設為x)的所有節點,直到值不為x
  • 循環條件和判斷條件的確立同上一題

代碼:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode deleteDuplicates(ListNode head) {// 個人經驗  使用一個指針更容易理解  反而維護多個指針容易把自己繞暈if(head == null) return null;// 一次遍歷的思路ListNode phead = new ListNode(0);phead.next = head;ListNode cur = phead;while(cur.next != null && cur.next.next != null) {if(cur.next.val == cur.next.next.val) {int x = cur.next.val;while(cur.next != null && cur.next.val == x)// 一直走到值不等于x的節點cur.next = cur.next.next;}else {cur = cur.next;}}return phead.next;}
}

02.反轉鏈表
鏈接:https://leetcode.cn/problems/reverse-linked-list/
分析

1.方法一:使用兩個指針迭代完成局部的鏈表的反轉

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode reverseList(ListNode head) {if(head == null) return null;ListNode pre = null, cur = head;while(cur != null) {ListNode tmp = cur.next;cur.next = pre;pre = cur;cur = tmp;}return pre;// pre此時是原鏈表的最后一個節點  反轉鏈表的頭結點}
}

2.方法2:遞歸寫法

  • 你給我反轉當前節點(head)后面的所有節點,并且把反轉后的頭節點返回
  • 反轉當前節點和后面的節點,將后面的節點當做一個節點即可
/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode reverseList(ListNode head) {if(head == null || head.next == null) return head;ListNode newHead = reverseList(head.next);// 完成一次局部的反轉head.next.next = head;head.next = null;return newHead;}
}
  • 為什么返回newHead而不是head?因為newHead是完成反轉之后的新的頭結點

03.回文鏈表
鏈接:https://leetcode.cn/problems/palindrome-linked-list/description/
分析

方法1:棧
遇到對稱有關的問題應該先考慮能否使用stack這種數據結構解決,對稱問題最大的特點就是從前往后遍歷的結果和從后往前遍歷的結果相同,從前往后遍歷容易,關鍵在于對于某些問題從后往前遍歷很困難(比如單鏈表),這是就可以使用棧這種數據結構,充分利用棧后進先出的結構特點完成從后往前遍歷

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public boolean isPalindrome(ListNode head) {// 借助棧Stack<Integer> st = new Stack<>();ListNode i1 = head;// 1.將所有元素入棧while(i1 != null) {st.push(i1.val);i1 = i1.next;}// 2.依次出棧進行比較ListNode i2 = head;while(i2 != null) {if(st.peek() != i2.val) return false;else {i2 = i2.next;st.pop();}}return true;}
}

方法2:反轉后半部分鏈表,依次進行比較

  1. 利用快慢指針找到中間節點
  2. 根據fast是否為null判斷節點的個數是奇數還是偶數,如果是奇數,向前走一步:如果是偶數,無需移動
  3. 反轉后面的所有節點,依次向后比較
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public boolean isPalindrome(ListNode head) {ListNode fast = head, slow = head;// 通過快慢指針找到中點while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}// 如果fast不為空,說明鏈表的長度是奇數個if (fast != null) {slow = slow.next;}// 反轉后半部分鏈表slow = reverse(slow);fast = head;while (slow != null) {// 然后比較,判斷節點值是否相等if (fast.val != slow.val)return false;fast = fast.next;slow = slow.next;}return true;}// 反轉鏈表public ListNode reverse(ListNode head) {if(head == null || head.next == null) return head;ListNode newHead = reverse(head.next);head.next.next = head;head.next = null;return newHead;}}

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

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

相關文章

速盾:cdn節點作用?

CDN&#xff08;Content Delivery Network&#xff09;指的是內容分發網絡&#xff0c;是一種通過部署在全球不同地理位置的服務器節點來提供快速、高效的內容傳輸和分發的技術架構。CDN節點在網絡中的作用非常重要&#xff0c;下面就對其作用進行詳細解析。 提供高速內容傳輸&…

《算法筆記》總結No.6——貪心

一.簡單貪心 貪心法是求解一類最優化問題的方法&#xff0c;它總是考慮在當前狀態下局部最優(或較優)之后&#xff0c;來使全局的結果達到最優(或較優)的策略。顯然&#xff0c;如果采取較優而非最優的策略(最優策略可能不存在或是不易想到)&#xff0c;得到的全局結果也無法是…

socketserver和WSGI服務端實現教程

Python socketserver 和 WSGI 服務端實現教程 在本文中&#xff0c;我們將詳細解析一個使用 socketserver 模塊實現的簡單 WSGI 服務器。該服務器能夠處理 HTTP 請求&#xff0c;支持 WSGI 應用&#xff0c;并正確處理響應頭和錯誤。 代碼概述 這段代碼定義了一個 run_wsgi …

【深入理解JVM】關于Object o = new Object()

1. 解釋一下對象的創建過程 “半初始化”狀態通常指的是對象在內存分配后、但在完全初始化之前的一種狀態。在Java中&#xff0c;雖然JVM的規范和設計努力避免對象處于這種不穩定的狀態&#xff0c;但在多線程環境下&#xff0c;由于指令重排序等并發問題&#xff0c;仍有可能…

Apache Spark詳解

目錄 性能優化 銀行業務案例&#xff1a; 步驟1&#xff1a;環境準備和數據加載 步驟2&#xff1a;數據探索和預處理 步驟3&#xff1a;特征工程 步驟4&#xff1a;數據轉換 步驟5&#xff1a;構建機器學習模型 步驟6&#xff1a;模型評估 步驟7&#xff1a;部署和監控…

Spring JdbcTemplate使用

maven引入Spring JDBC <dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.19</version></dependency> Spring配置中配置 <!-- DataSource配置 --><bean id"…

java代理簡單理解

一、什么是代理 舉例說明&#xff1a;當我想買一臺電腦&#xff0c;國內太貴了。委托好友A在國外幫忙買。 這個情節中我要實現的動作和好友實現的動作一樣&#xff0c;都是買電腦。好友幫我完成了這個動作&#xff0c;這就是代理。 類A和類B都實現一個interface接口C&#x…

【LeetCode刷題筆記】LeetCode.24.兩兩交換鏈表中的節點

創作不易&#xff0c;本篇文章如果幫助到了你&#xff0c;還請點贊 關注支持一下?>&#x16966;<)!! 主頁專欄有更多知識&#xff0c;如有疑問歡迎大家指正討論&#xff0c;共同進步&#xff01; 更多算法知識專欄&#xff1a;算法分析&#x1f525; 給大家跳段街舞感謝…

新手小白的pytorch學習第一彈-------張量

1 導入pytorch包 import torch2 創建張量&#xff08;tensor&#xff09; scalar標量 scalar torch.tensor(7) scalartensor(7)scalar.ndim查看scalar的維度&#xff0c;因為scalar是標量&#xff0c;所以維度為0 0scalar.shapetorch.Size([])torch.item()7vector&#xf…

Apache功能配置:訪問控制、日志分割; 部署AWStats日志分析工具

目錄 保持連接 訪問控制 只允許指定ip訪問 拒絕指定主機其他正常訪問 用戶授權 日志格式 日志分割 操作步驟 使用第三方工具cronolog分割日志 AWStats日志分析 操作步驟 訪問AwStats分析系統 保持連接 Apache通過設置配置文件httpd-default.conf中相關的連接保持參…

基于Java的科大訊飛大模型API調用實現

寫在前面&#xff1a;因為現在自己實習的公司新拓展的一個業務是結合AI的低代碼平臺&#xff0c;我負責后端的開發&#xff0c;之前一直都是直接使用gpt或者文心一言等ui界面來直接使用大模型&#xff0c;從來沒有自己調接口過&#xff0c;所以本文記錄一下自己第一次使用大模型…

源代碼防泄漏的正確方法

為了保護公司的源代碼不被泄露&#xff0c;IT企業可以采取一系列嚴格的安全措施。這些措施涵蓋技術手段、管理策略和操作流程&#xff0c;形成多層次的防護體系做到源代碼防泄漏工作。 技術手段 1、源代碼加密&#xff1a; 采用高級加密標準&#xff08;AES&#xff09;或其他…

【QT】QComboBox允許輸入查詢,且不區分大小寫

目錄 0.簡介 1.環境 2.詳細代碼 3.參考 0.簡介 項目需求&#xff0c;原本有一個下拉框&#xff0c;但是條目太多&#xff0c;不好搜索&#xff0c;所以用戶要求可以輸入查找 修改前 &#xff1a; 修改后&#xff1a; 1.環境 windows11 vs-code qt5.12 2.詳細代碼 QComboB…

中小企業和數智化的距離,只差一塊華為IdeaHub

每次談及中小企業數智化的話題&#xff0c;被提到最多的總是“三不”難題&#xff0c;即不想轉、不敢轉、不會轉。 為了破解這一困局&#xff0c;政府多次在工作報告中提到“深入開展中小企業數字化賦能專項行動”&#xff0c;并在各地為中小企業創新提供政策支持。此外&#…

Android --- Kotlin學習之路:基礎語法學習筆記

------>可讀可寫變量 var name: String "Hello World";------>只讀變量 val name: String "Hello World"------>類型推斷 val name: String "Hello World" 可以寫成 val name "Hello World"------>基本數據類型 1…

MD5加密和注冊頁面的編寫

MD5加密 1.導入包 npm install --save ts-md5 2.使用方式 import { Md5 } from ts-md5; //md5加密后的密碼 const md5PwdMd5.hashStr("123456").toUpperCase(); 遇見的問題及用到的技術 注冊頁面 register.vue代碼 <template><div class"wappe…

從零開始學習嵌入式----Linux 命令行,常用命令速記指南

目錄 一、文件操作 二、文本操作 三、系統管理 四、網絡操作 五、其他常用命令 六、學習建議 在 Linux 世界里&#xff0c;命令行就像一把瑞士軍刀&#xff0c;掌握了它&#xff0c;你就能游刃有余地操控整個系統。但面對茫茫多的命令&#xff0c;新手往往會感到無所適從…

關于Python中的字典你所不知道的七個技巧

01 引言 Python是我最喜歡的編程語言之一&#xff0c;它向來以其簡單性、多功能性和可讀性而聞名。 字典作為Python中最常使用的數據類型&#xff0c;大家幾乎每個人都或多或少在項目中使用過字典&#xff0c;但是字典里有一些潛在的技巧可能并不是每個同學都會用到。 在本文…

相同含義但不同類型字段作為join條件時注意事項

假設表A和表B中都有表示學號的stu_id字段&#xff0c;但該字段在表A和表B中類型分別為bigint和string。當直接通過該字段進行join時&#xff0c;一般情況下可以得到我們預期的結果。 select a.stu_id from a as r join b as l on r.stu_id l.stu_id 但是如果學號長度較長的…

【UE5.1 角色練習】16-槍械射擊——瞄準

目錄 效果 步驟 一、瞄準時拉近攝像機位置 二、瞄準偏移 三、向指定方向射擊 四、連發 效果 步驟 一、瞄準時拉近攝像機位置 打開角色藍圖&#xff0c;在事件圖表中添加如下節點&#xff0c;當進入射擊狀態時設置目標臂長度為300&#xff0c;從而拉近視角。 但是這樣切…