力扣top100(day02-01)--鏈表01

160. 相交鏈表

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {/*** 查找兩個鏈表的相交節點* @param headA 第一個鏈表的頭節點* @param headB 第二個鏈表的頭節點* @return 相交的節點,如果不相交則返回null*/public ListNode getIntersectionNode(ListNode headA, ListNode headB) {// 使用HashSet來存儲已經訪問過的節點Set<ListNode> visited = new HashSet<ListNode>();// 遍歷第一個鏈表headA,將所有節點存入HashSetListNode temp = headA;while (temp != null) {visited.add(temp);  // 將當前節點加入已訪問集合temp = temp.next;   // 移動到下一個節點}// 遍歷第二個鏈表headB,檢查每個節點是否在HashSet中存在temp = headB;while (temp != null) {// 如果當前節點已存在于HashSet中,說明是相交節點if (visited.contains(temp)) {return temp;  // 返回相交節點}temp = temp.next;  // 移動到下一個節點}// 如果遍歷完headB都沒有找到相交節點,返回nullreturn null;}
}

代碼解讀:尋找兩個鏈表的交點

這段代碼實現了在Java中尋找兩個單鏈表相交節點的功能。以下是詳細解讀:

方法簽名

public ListNode getIntersectionNode(ListNode headA, ListNode headB)
  • 參數:兩個鏈表的頭節點?headA?和?headB

  • 返回值:兩個鏈表相交的節點,如果不相交則返回?null

實現思路

代碼使用了哈希集合的方法來解決問題,具體步驟如下:

  1. 遍歷第一個鏈表:將鏈表A的所有節點存入一個HashSet中

  2. 遍歷第二個鏈表:檢查鏈表B的每個節點是否存在于HashSet中

  3. 找到交點:如果存在,則該節點就是交點;如果遍歷完都沒有找到,則返回null

代碼逐行解析

Set<ListNode> visited = new HashSet<ListNode>();
  • 創建一個HashSet用于存儲鏈表節點

ListNode temp = headA;
while (temp != null) {visited.add(temp);temp = temp.next;
}
  • 遍歷鏈表A,將所有節點添加到HashSet中

temp = headB;
while (temp != null) {if (visited.contains(temp)) {return temp;}temp = temp.next;
}
  • 遍歷鏈表B,檢查每個節點是否存在于HashSet中

  • 如果存在,則立即返回該節點(第一個相交節點)

return null;
  • 如果遍歷完鏈表B都沒有找到相交節點,返回null

復雜度分析

  • 時間復雜度:O(m+n),其中m和n分別是兩個鏈表的長度

  • 空間復雜度:O(m),需要存儲鏈表A的所有節點

其他解法

這種方法雖然直觀,但需要額外空間。還有兩種更優的空間O(1)解法:

  1. 雙指針法

    • 計算兩個鏈表的長度

    • 讓長鏈表的指針先移動長度差步

    • 然后兩個指針同步前進,相遇點即為交點

  2. 環形檢測法

    • 將鏈表A的尾節點連接到鏈表B的頭節點

    • 使用快慢指針檢測環的起點,即為交點

    • 最后需要恢復鏈表結構

邊界情況

  • 兩個鏈表都為空

  • 一個鏈表為空

  • 兩個鏈表不相交

  • 兩個鏈表完全重合

  • 交點在鏈表頭部或尾部

206. 反轉鏈表

/*** 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 {/*** 反轉單鏈表* @param head 原鏈表的頭節點* @return 反轉后新鏈表的頭節點*/public ListNode reverseList(ListNode head) {// prev指針用于記錄前一個節點,初始為null(因為反轉后原頭節點將指向null)ListNode prev = null;// curr指針用于遍歷鏈表,初始指向原鏈表頭節點ListNode curr = head;// 遍歷鏈表直到當前節點為null(到達鏈表尾部)while (curr != null) {// 1. 先保存當前節點的下一個節點(否則修改指針后會丟失)ListNode next = curr.next;// 2. 反轉指針方向:當前節點的next指向前一個節點curr.next = prev;// 3. 移動prev指針到當前節點(為下一次迭代做準備)prev = curr;// 4. 移動curr指針到之前保存的下一個節點curr = next;}// 循環結束時,prev指向原鏈表的最后一個節點,即新鏈表的頭節點return prev;}
}

算法圖解

假設原始鏈表為:1 → 2 → 3 → 4 → null

執行過程:

  1. 初始狀態:prev = null, curr = 1

  2. 第一次迭代后:null ← 1 2 → 3 → 4 → null

  3. 第二次迭代后:null ← 1 ← 2 3 → 4 → null

  4. 第三次迭代后:null ← 1 ← 2 ← 3 4 → null

  5. 第四次迭代后:null ← 1 ← 2 ← 3 ← 4

最終返回節點4作為新鏈表的頭節點

關鍵點說明

  1. 三指針技術

    • prev:記錄前一個節點

    • curr:當前處理節點

    • next:臨時保存下一個節點

  2. 指針操作順序

    • 必須先保存next = curr.next,否則反轉后會丟失后續鏈表

    • 然后才能修改curr.next指向

    • 最后移動prevcurr指針

  3. 終止條件

    • curr == null時循環結束

    • 此時prev指向原鏈表的最后一個節點(新鏈表的頭節點)

  4. 邊界情況處理

    • 空鏈表(head == null):直接返回null

    • 單節點鏈表:自動正確處理

復雜度分析

  • 時間復雜度:O(n),只需遍歷鏈表一次

  • 空間復雜度:O(1),只使用了固定數量的指針變量

234. 回文鏈表

/*** 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 temp=head;List<Integer> vals = new ArrayList<Integer>();while(temp!=null){vals.add(temp.val);temp=temp.next;}int left=0;int length=vals.size();int right=length-1;while(left<right){if(vals.get(left)!=vals.get(right)){return false;}left++;right--;}return true;}
}

算法分析

方法思路

  1. 存儲階段:將鏈表所有節點的值按順序存入一個ArrayList

  2. 驗證階段:使用雙指針法,從列表兩端向中間比較元素是否對稱

時間復雜度

  • O(n):需要完整遍歷鏈表兩次(一次存儲,一次比較)

  • 其中n是鏈表的長度

空間復雜度

  • O(n):需要使用額外空間存儲所有節點的值

141. 環形鏈表

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {/*** 檢測鏈表是否有環* @param head 鏈表頭節點* @return 如果鏈表有環返回true,否則返回false*/public boolean hasCycle(ListNode head) {// 處理邊界情況:空鏈表或單節點無環if (head == null || head.next == null) {return false;}// 初始化快慢指針ListNode slow = head;      // 慢指針每次走1步ListNode fast = head.next; // 快指針每次走2步// 當快慢指針不相遇時繼續循環while (slow != fast) {// 如果快指針到達鏈表末尾,說明無環if (fast == null || fast.next == null) {return false;}// 移動指針slow = slow.next;      // 慢指針走1步fast = fast.next.next; // 快指針走2步}// 快慢指針相遇,說明有環return true;}
}

算法原理(Floyd判圈算法)

核心思想

  • 使用兩個指針,一個慢指針(每次移動1步),一個快指針(每次移動2步)

  • 如果鏈表無環,快指針會先到達末尾(null)

  • 如果鏈表有環,快指針最終會追上慢指針(相遇)

為什么這樣能工作

  1. 無環情況:快指針會先到達鏈表末尾(null)

  2. 有環情況

    • 快指針每次比慢指針多走1步

    • 經過若干步后,快指針會繞環一圈追上慢指針

    • 可以證明最多需要O(n)時間就能檢測出環

關鍵點解析

  1. 指針初始化

    • 慢指針slow從head開始

    • 快指針fast從head.next開始(避免第一次循環就滿足slow==fast)

  2. 循環條件

    • slow != fast時繼續循環

    • 如果相等則跳出循環,返回true(有環)

  3. 終止條件檢查

    • 檢查fast == null || fast.next == null

    • 因為fast走得快,只需要檢查fast是否到末尾

  4. 指針移動

    • 慢指針每次移動1步:slow = slow.next

    • 快指針每次移動2步:fast = fast.next.next

復雜度分析

  • 時間復雜度:O(n)

    • 無環情況:快指針到達末尾,最多n/2步

    • 有環情況:慢指針最多走一圈就會被快指針追上

  • 空間復雜度:O(1)

    • 只使用了兩個額外指針,常數空間

邊界情況處理

  1. 空鏈表:直接返回false

  2. 單節點鏈表:直接返回false(除非自環,但題目通常不考慮)

  3. 大環/小環:算法都能正確處理

  4. 環在頭部/尾部:都能正確檢測

142. 環形鏈表 II

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public ListNode detectCycle(ListNode head) {if(head==null){return null;}ListNode slow = head;      // 慢指針ListNode fast = head; // 快指針while(fast!=null){slow=slow.next;if(fast.next!=null){fast=fast.next.next;}else{return null;}if(slow==fast){ListNode temp=head;while(temp!=slow){temp=temp.next;slow=slow.next;}return temp;}}return null;}
}

算法原理(Floyd判圈算法的擴展)

第一階段:檢測環的存在

  1. 快指針每次移動2步,慢指針每次移動1步

  2. 如果快指針遇到null,說明鏈表無環

  3. 如果快慢指針相遇,說明鏈表有環

第二階段:確定環的起點

  1. 當快慢指針相遇后,將一個指針(temp)重新指向鏈表頭部

  2. temp和slow指針每次都移動1步

  3. 當它們再次相遇時,相遇點就是環的起點

數學證明

設:

  • 鏈表頭到環起點的距離為a

  • 環起點到相遇點的距離為b

  • 相遇點回到環起點的距離為c

  • 環的長度為L = b + c

當快慢指針相遇時:

  • 慢指針走的距離:a + b

  • 快指針走的距離:a + b + k*L (k為快指針繞環的圈數)

因為快指針速度是慢指針的2倍:
2(a + b) = a + b + kL
=> a + b = k
L
=> a = k*L - b = (k-1)*L + c

這意味著:從鏈表頭走a步,等于從相遇點走c步加上整數倍的環長。因此,兩個指針分別從頭節點和相遇點出發,以相同速度前進,必將在環起點相遇。

復雜度分析

  • 時間復雜度:O(n)

    • 第一階段最多需要O(n)時間檢測環

    • 第二階段最多需要O(n)時間找到環起點

  • 空間復雜度:O(1)

    • 只使用了固定數量的指針變量

邊界情況處理

  1. 空鏈表:直接返回null

  2. 單節點無環:快指針會走到null

  3. 單節點自環:能正確檢測并返回該節點

  4. 環在頭部:能正確返回頭節點

  5. 環在尾部:能正確返回環起點

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

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

相關文章

LLM 中 語音編碼與文本embeding的本質區別

直接使用語音編碼,是什么形式,和文本的區別 直接使用語音編碼的形式 語音編碼是將模擬語音信號轉換為數字信號的技術,其核心是對語音的聲學特征進行數字化表征,直接承載語音的物理聲學信息。其形式可分為以下幾類: 1. 基于波形的編碼(保留原始波形特征) 脈沖編碼調制…

模型選擇與調優

一、模型選擇與調優在機器學習中&#xff0c;模型的選擇和調優是一個重要的步驟&#xff0c;它直接影響到最終模型的性能1、交叉驗證在任何有監督機器學習項目的模型構建階段&#xff0c;我們訓練模型的目的是從標記的示例中學習所有權重和偏差的最佳值如果我們使用相同的標記示…

vue+Django農產品推薦與價格預測系統、雙推薦+機器學習預測+知識圖譜

vueflask農產品推薦與價格預測系統、雙推薦機器學習價格預測知識圖譜文章結尾部分有CSDN官方提供的學長 聯系方式名片 文章結尾部分有CSDN官方提供的學長 聯系方式名片 關注B站&#xff0c;有好處&#xff01;編號: D010 技術架構: vueflaskmysqlneo4j 核心技術&#xff1a; 基…

數據分析小白訓練營:基于python編程語言的Numpy庫介紹(第三方庫)(下篇)

銜接上篇文章&#xff1a;數據分析小白訓練營&#xff1a;基于python編程語言的Numpy庫介紹&#xff08;第三方庫&#xff09;&#xff08;上篇&#xff09;&#xff08;十一&#xff09;數組的組合核心功能&#xff1a;一、生成基數組np.arange().reshape() 基礎運算功能&…

負載因子(Load Factor) :哈希表(Hash Table)中的一個關鍵性能指標

負載因子&#xff08;Load Factor&#xff09; 是哈希表&#xff08;Hash Table&#xff09;中的一個關鍵性能指標&#xff0c;用于衡量哈希表的空間利用率和發生哈希沖突的可能性。一&#xff1a;定義負載因子&#xff08;通常用希臘字母 λ 表示&#xff09;的計算公式為&…

監控插件SkyWalking(一)原理

一、介紹 1、簡介 SkyWalking 是一個 開源的 APM&#xff08;Application Performance Monitoring&#xff0c;應用性能監控&#xff09;和分布式追蹤系統&#xff0c;主要用于監控、追蹤、分析分布式系統中的調用鏈路、性能指標和日志。 它由 Apache 基金會托管&#xff0c;…

【接口自動化測試】---自動化框架pytest

目錄 1、用例運行規則 2、pytest命令參數 3、pytest配置文件 4、前后置 5、斷言 6、參數化---對函數的參數&#xff08;重要&#xff09; 7、fixture 7.1、基本用法 7.2、fixture嵌套&#xff1a; 7.3、請求多個fixture&#xff1a; 7.4、yield fixture 7.5、帶參數…

Flink Stream API 源碼走讀 - socketTextStream

概述 本文深入分析了 Flink 中 socketTextStream() 方法的源碼實現&#xff0c;從用戶API調用到最終返回 DataStream 的完整流程。 核心知識點 1. socketTextStream 方法重載鏈 // 用戶調用入口 env.socketTextStream("hostname", 9999)↓ 補充分隔符參數 env.socket…

待辦事項小程序開發

1. 項目規劃功能需求&#xff1a;添加待辦事項標記完成/未完成刪除待辦事項分類或標簽管理&#xff08;可選&#xff09;數據持久化&#xff08;本地存儲&#xff09;2. 實現功能添加待辦事項&#xff1a;監聽輸入框和按鈕事件&#xff0c;將輸入內容添加到列表。 標記完成/未完…

【C#】Region、Exclude的用法

在 C# 中&#xff0c;Region 和 Exclude 是與圖形編程相關的概念&#xff0c;通常在使用 System.Drawing 命名空間進行 GDI 繪圖時出現。它們主要用于定義和操作二維空間中的區域&#xff08;幾何區域&#xff09;&#xff0c;常用于窗體裁剪、控件重繪、圖形繪制優化等場景。 …

機器學習 - Kaggle項目實踐(3)Digit Recognizer 手寫數字識別

Digit Recognizer | Kaggle 題面 Digit Recognizer-CNN | Kaggle 下面代碼的kaggle版本 使用CNN進行手寫數字識別 學習到了網絡搭建手法學習率退火數據增廣 提高訓練效果。 使用混淆矩陣 以及對分類出錯概率最大的例子單獨拎出來分析。 最終以99.546%正確率 排在 86/1035 …

新手如何高效運營亞馬遜跨境電商:從傳統SP廣告到DeepBI智能策略

"為什么我的廣告點擊量很高但訂單轉化率卻很低&#xff1f;""如何避免新品期廣告預算被大詞消耗殆盡&#xff1f;""為什么手動調整關鍵詞和出價總是慢市場半拍&#xff1f;""競品ASIN投放到底該怎么做才有效&#xff1f;""有沒有…

【論文閱讀 | CVPR 2024 | UniRGB-IR:通過適配器調優實現可見光-紅外語義任務的統一框架】

論文閱讀 | CVPR 2024 | UniRGB-IR&#xff1a;通過適配器調優實現可見光-紅外語義任務的統一框架?1&&2. 摘要&&引言3.方法3.1 整體架構3.2 多模態特征池3.3 補充特征注入器3.4 適配器調優范式4 實驗4.1 RGB-IR 目標檢測4.2 RGB-IR 語義分割4.3 RGB-IR 顯著目…

Hyperf 百度翻譯接口實現方案

保留 HTML/XML 標簽結構&#xff0c;僅翻譯文本內容&#xff0c;避免破壞富文本格式。采用「HTML 解析 → 文本提取 → 批量翻譯 → 回填」的流程。百度翻譯集成方案&#xff1a;富文本內容翻譯系統 HTML 解析 百度翻譯 API 集成 文件結構 app/ ├── Controller/ │ └──…

字節跳動 VeOmni 框架開源:統一多模態訓練效率飛躍!

資料來源&#xff1a;火山引擎-開發者社區 多模態時代的訓練痛點&#xff0c;終于有了“特效藥” 當大模型從單一語言向文本 圖像 視頻的多模態進化時&#xff0c;算法工程師們的訓練流程卻陷入了 “碎片化困境”&#xff1a; 當業務要同時迭代 DiT、LLM 與 VLM時&#xff0…

配置docker pull走http代理

之前寫了一篇自建Docker鏡像加速器服務的博客&#xff0c;需要用到境外服務器作為代理&#xff0c;但是一般可能沒有境外服務器&#xff0c;只有http代理&#xff0c;所以如果本地使用想走代理可以用以下方式 臨時生效&#xff08;只對當前終端有效&#xff09; 設置環境變量…

OpenAI 開源模型 gpt-oss 本地部署詳細教程

OpenAI 最近發布了其首個開源的開放權重模型gpt-oss&#xff0c;這在AI圈引起了巨大的轟動。對于廣大開發者和AI愛好者來說&#xff0c;這意味著我們終于可以在自己的機器上&#xff0c;完全本地化地運行和探索這款強大的模型了。 本教程將一步一步指導你如何在Windows和Linux…

力扣-5.最長回文子串

題目鏈接 5.最長回文子串 class Solution {public String longestPalindrome(String s) {boolean[][] dp new boolean[s.length()][s.length()];int maxLen 0;String str s.substring(0, 1);for (int i 0; i < s.length(); i) {dp[i][i] true;}for (int len 2; len …

Apache Ignite超時管理核心組件解析

這是一個非常關鍵且設計精巧的 定時任務與超時管理組件 —— GridTimeoutProcessor&#xff0c;它是 Apache Ignite 內核中負責 統一調度和處理所有異步超時事件的核心模塊。&#x1f3af; 一、核心職責統一管理所有需要“在某個時間點觸發”的任務或超時邏輯。它相當于 Ignite…

DAY 42 Grad-CAM與Hook函數

知識點回顧回調函數lambda函數hook函數的模塊鉤子和張量鉤子Grad-CAM的示例# 定義一個存儲梯度的列表 conv_gradients []# 定義反向鉤子函數 def backward_hook(module, grad_input, grad_output):# 模塊&#xff1a;當前應用鉤子的模塊# grad_input&#xff1a;模塊輸入的梯度…