【LeetCode每日一題】21. 合并兩個有序鏈表 2. 兩數相加

每日一題

  • 21. 合并兩個有序鏈表
    • 題目
    • 總體思路
      • 算法步驟
      • 時間復雜度與空間復雜度
    • 代碼
  • 2. 兩數相加
    • 題目
    • 總體思路
    • 算法步驟
    • 時間復雜度與空間復雜度
    • 代碼
    • 知識
    • 感悟

2025.8.30

21. 合并兩個有序鏈表

題目

將兩個升序鏈表合并為一個新的 升序 鏈表并返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。

示例 1:
在這里插入圖片描述
輸入:l1 = [1,2,4], l2 = [1,3,4]
輸出:[1,1,2,3,4,4]
示例 2:

輸入:l1 = [], l2 = []
輸出:[]
示例 3:

輸入:l1 = [], l2 = [0]
輸出:[0]

提示:

兩個鏈表的節點數目范圍是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非遞減順序 排列

總體思路

這個算法采用迭代合并的方式將兩個有序鏈表合并成一個新的有序鏈表。核心思想是使用一個啞節點(dummy node)作為新鏈表的起始點,然后逐個比較兩個鏈表的節點值,選擇較小的節點連接到新鏈表中,最后將剩余的節點直接連接到最后。

算法步驟

  1. 初始化:創建啞節點和尾指針
  2. 比較合并:同時遍歷兩個鏈表,選擇較小值的節點連接
  3. 處理剩余:將未遍歷完的鏈表直接連接到尾部
  4. 返回結果:返回啞節點的下一個節點

時間復雜度與空間復雜度

  • 時間復雜度:O(n + m)
    • 需要遍歷兩個鏈表的所有節點
    • n 和 m 分別是兩個鏈表的長度
    • 最壞情況下需要比較 n + m 次
  • 空間復雜度:O(1)
    • 只使用了常數級別的額外空間(啞節點和幾個指針)
    • 原地操作,不創建新節點,直接重用原有節點

代碼

golang

func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {dump := &ListNode{}tail := dumpfor list1 != nil && list2 != nil {if list1.Val >= list2.Val {tail.Next = list2list2 = list2.Next}else {tail.Next = list1list1 = list1.Next}tail = tail.Next}if list1 != nil {tail.Next = list1}else {tail.Next = list2}return dump.Next
}
/*** 合并兩個有序鏈表* 將兩個升序鏈表合并為一個新的升序鏈表并返回* * @param list1 *ListNode 第一個有序鏈表的頭節點* @param list2 *ListNode 第二個有序鏈表的頭節點* @return *ListNode 合并后的新鏈表的頭節點*/
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {// 創建啞節點(dummy node)作為新鏈表的起始前驅節點// 使用啞節點可以簡化代碼,避免處理頭節點的特殊情況dummy := &ListNode{}// 尾指針,指向新鏈表的最后一個節點// 初始時指向啞節點,隨著節點的添加而移動tail := dummy// 同時遍歷兩個鏈表,直到其中一個鏈表遍歷完畢// 比較兩個鏈表當前節點的值,選擇較小的節點添加到新鏈表for list1 != nil && list2 != nil {if list1.Val <= list2.Val {// 如果list1的當前節點值小于等于list2的當前節點值// 將list1的當前節點連接到新鏈表的尾部tail.Next = list1// list1指針前進到下一個節點list1 = list1.Next} else {// 如果list2的當前節點值小于list1的當前節點值// 將list2的當前節點連接到新鏈表的尾部tail.Next = list2// list2指針前進到下一個節點list2 = list2.Next}// 尾指針前進到新添加的節點,保持指向新鏈表的最后一個節點tail = tail.Next}// 處理剩余的節點:將未遍歷完的鏈表直接連接到新鏈表的尾部// 由于兩個鏈表都是有序的,剩余部分本身已經是有序的if list1 != nil {// 如果list1還有剩余節點,直接全部連接tail.Next = list1} else {// 如果list2還有剩余節點,或者兩個鏈表都為空,連接list2// 如果兩個鏈表都為空,list2為nil,連接nil也是正確的tail.Next = list2}// 返回啞節點的下一個節點,即新鏈表的實際頭節點// 啞節點本身不存儲有效數據,只是輔助節點return dummy.Next
}

2. 兩數相加

題目

給你兩個 非空 的鏈表,表示兩個非負的整數。它們每位數字都是按照 逆序 的方式存儲的,并且每個節點只能存儲 一位 數字。

請你將兩個數相加,并以相同形式返回一個表示和的鏈表。

你可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。

示例 1:
在這里插入圖片描述
輸入:l1 = [2,4,3], l2 = [5,6,4]
輸出:[7,0,8]
解釋:342 + 465 = 807.

示例 2:

輸入:l1 = [0], l2 = [0]
輸出:[0]
示例 3:

輸入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
輸出:[8,9,9,9,0,0,0,1]

提示:

每個鏈表中的節點數在范圍 [1, 100] 內
0 <= Node.val <= 9
題目數據保證列表表示的數字不含前導零

總體思路

這個算法模擬了手工豎式加法的過程,將兩個用鏈表逆序存儲的數字相加。數字的低位存儲在鏈表的前面,高位存儲在后面,這樣可以直接從頭開始逐位相加,正確處理進位問題。

算法步驟

  1. 初始化:創建啞節點、尾指針和進位變量
  2. 逐位相加:同時遍歷兩個鏈表,對應位相加加上進位
  3. 處理進位:計算當前位的值和新的進位
  4. 處理剩余:處理鏈表長度不一致和最終進位的情況
  5. 返回結果:返回結果鏈表的頭節點

時間復雜度與空間復雜度

  • 時間復雜度:O(max(n, m))
    • 需要遍歷較長的鏈表
    • n 和 m 分別是兩個鏈表的長度
    • 每個節點處理時間是常數時間
  • 空間復雜度:O(max(n, m))
    • 需要創建新的鏈表存儲結果
    • 最壞情況下結果鏈表長度為 max(n, m) + 1(有進位時)
    • 只存儲結果,不存儲中間過程

代碼

golang

/*** Definition for singly-linked list.* type ListNode struct {*     Val int*     Next *ListNode* }*/
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {dump := &ListNode{}tail := dumpcarry := 0for l1 != nil || l2 != nil || carry != 0 {val1, val2 := 0, 0if l1 != nil {val1 = l1.Vall1 = l1.Next}if l2 != nil {val2 = l2.Vall2 = l2.Next}sum := val1 + val2 + carryval := sum % 10carry = sum / 10tail.Next = &ListNode{Val: val}tail = tail.Next}return dump.Next
}
/*** 兩個逆序鏈表表示的數字相加* 數字的低位存儲在鏈表前面,高位存儲在后面* 例如:數字 342 表示為 2 -> 4 -> 3* * @param l1 *ListNode 第一個數字的鏈表表示(逆序)* @param l2 *ListNode 第二個數字的鏈表表示(逆序) * @return *ListNode 相加結果的鏈表表示(逆序)*/
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {// 創建啞節點(dummy node)作為結果鏈表的起始前驅節點// 使用啞節點可以簡化代碼,避免處理頭節點的特殊情況dummy := &ListNode{}// 尾指針,指向結果鏈表的最后一個節點// 用于高效地在鏈表尾部添加新節點tail := dummy// 進位值,表示上一位相加產生的進位// 初始為0,因為第一位相加沒有前一位的進位carry := 0// 循環條件:只要任一鏈表還有節點,或者還有進位需要處理,就繼續循環// l1 != nil: 第一個鏈表還有數字位// l2 != nil: 第二個鏈表還有數字位  // carry != 0: 還有進位需要處理(重要!處理最后一位的進位)for l1 != nil || l2 != nil || carry != 0 {// 初始化當前位的值,如果對應鏈表為空則值為0val1, val2 := 0, 0// 處理第一個鏈表的當前位if l1 != nil {val1 = l1.Val    // 獲取當前位的值l1 = l1.Next     // 指針移動到下一位}// 處理第二個鏈表的當前位if l2 != nil {val2 = l2.Val    // 獲取當前位的值l2 = l2.Next     // 指針移動到下一位}// 計算當前位的總和:兩個數字位加上進位sum := val1 + val2 + carry// 計算當前位的值:取總和除以10的余數// 例如:7 % 10 = 7, 12 % 10 = 2newVal := sum % 10// 計算新的進位值:取總和除以10的商// 例如:7 / 10 = 0, 12 / 10 = 1carry = sum / 10// 創建新節點存儲當前位的值,并連接到結果鏈表尾部tail.Next = &ListNode{Val: newVal}// 移動尾指針到新添加的節點,保持指向鏈表尾部tail = tail.Next}// 返回啞節點的下一個節點,即結果鏈表的實際頭節點// 啞節點本身不存儲有效數據,只是輔助節點return dummy.Next
}

知識

各種結構體初始化方式

package mainimport "fmt"type ListNode struct {Val  intNext *ListNode
}func main() {// 方式1:字段名初始化(最常用)node1 := &ListNode{Val:  1,Next: nil,}fmt.Printf("節點1: Val=%d, Next=%v\n", node1.Val, node1.Next)// 方式2:順序初始化node2 := &ListNode{2, nil}fmt.Printf("節點2: Val=%d, Next=%v\n", node2.Val, node2.Next)// 方式3:創建結構體后取地址node3 := ListNode{Val: 3}node3Ptr := &node3fmt.Printf("節點3: Val=%d, Next=%v\n", node3Ptr.Val, node3Ptr.Next)// 方式4:使用new函數node4 := new(ListNode)node4.Val = 4fmt.Printf("節點4: Val=%d, Next=%v\n", node4.Val, node4.Next)// 在鏈表操作中的實際使用dummy := &ListNode{}tail := dummy// 這就是你在代碼中看到的語法tail.Next = &ListNode{Val: 5}  // 創建新節點并連接tail = tail.Nexttail.Next = &ListNode{Val: 6}  // 繼續添加節點tail = tail.Nextfmt.Print("鏈表: ")current := dummy.Nextfor current != nil {fmt.Printf("%d", current.Val)if current.Next != nil {fmt.Print(" -> ")}current = current.Next}
}

感悟

最近老是把0和nil寫混。
寫的時候千萬要注意啊!!!

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

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

相關文章

DVWA靶場通關筆記-文件包含(Impossible級別)

目錄 一、源碼分析 二、文件包含防范分析 1、明確指定允許包含的文件 2、拒絕所有未在白名單中的輸入 3、總結 &#xff08;1&#xff09;白名單 (Allow List) &#xff08;2&#xff09;硬編碼/映射 (Hardcoding/Mapping) &#xff08;3&#xff09;輸入過濾 (Input F…

構建堅不可摧的數據堡壘:深入解析 Oracle 高可用與容災技術體系

在當今數字化時代&#xff0c;數據是企業的核心資產&#xff0c;而承載這些數據的數據庫系統的連續性與穩定性直接關系到企業的生死存亡。一次計劃外的停機或災難性的數據丟失&#xff0c;帶來的不僅是經濟上的巨大損失&#xff0c;更是對品牌信譽和客戶信任的致命打擊。因此&a…

【3D算法技術入門】如何基于建筑圖片重建三維數字資產?

要基于建筑圖片重建三維數字資產是一個復雜的計算機視覺任務&#xff0c;涉及圖像采集、特征提取、相機姿態估計、稠密重建和三維模型優化等多個步驟。下面我將提供一個基于Python的解決方案框架&#xff0c;使用開源庫實現從圖片到三維模型的基本流程。 首先需要安裝必要的庫&…

?CVPR2025 自動駕駛半監督 LiDAR 分割新范式:HiLoTs 框架深度解析

&#x1f4c4;論文題目&#xff1a;HiLoTs: High-Low Temporal Sensitive Representation Learning for Semi-Supervised LiDAR Segmentation in Autonomous Driving ??作者及機構&#xff1a; R.D. Lin、Pengcheng Weng、Yinqiao Wang、Fei Wang&#xff08;西安交通大學軟件…

【 MYSQL | 基礎篇 函數與約束 】

摘要&#xff1a;本文介紹數據庫中的函數與約束&#xff0c;函數含字符串、數值、日期、流程四類&#xff0c;可實現字符串處理、數值計算等需求。約束分六類&#xff0c;重點講外鍵約束的語法、刪除更新行為&#xff0c;保證數據正確完整。思維導圖1. 函數函數是指一段可以直接…

Oracle 數據庫性能調優:從瓶頸診斷到精準優化之道

引言&#xff1a;性能優化的本質在當今數據驅動的時代&#xff0c;數據庫性能直接關系到企業的運營效率和用戶體驗。Oracle 作為全球領先的關系型數據庫管理系統&#xff0c;承載著眾多企業的核心業務。然而&#xff0c;隨著數據量的增長和業務復雜度的提升&#xff0c;數據庫性…

楊校老師競賽課堂之C++語言GESP一級筆記

考試大綱 GESP一級考試大綱 計算機基礎與編程環境 計算機歷史 變量的定義與使用 基本數據類型&#xff08;整型、浮點型、字符型、布爾型&#xff09; 輸入與輸出&#xff08;cin與cout、scanf與printf&#xff09; 基本運算&#xff08;算術運算、關系運算、邏輯運算&am…

操作系統-管程

1. 為什么需要管程&#xff1f;—— 信號量 (Semaphore) 的困境在理解管程之前&#xff0c;你必須先知道它要解決什么問題。之前&#xff0c;我們使用信號量 (Semaphore) 來實現進程/線程間的同步與互斥。雖然信號量功能強大&#xff0c;但它存在兩個主要問題&#xff1a;編程復…

日志的實現

目錄 日志與策略模式 Log.hpp class LogStrategy基類 class ConsoleLogStrategy派生類 classFileLogStrategy派生類 日志等級 獲得時間戳 localtime_r函數詳解 函數原型 struct tm結構的指針 Logger類(重點) class LogMessage 日志信息類 std::stringstream 用法 重…

【論文閱讀】Sparse4D v2:Recurrent Temporal Fusion with Sparse Model

標題&#xff1a; Sparse4D v2&#xff1a;Recurrent Temporal Fusion with Sparse Model 作者&#xff1a; Xuewu Lin, Tianwei Lin, Zixiang Pei, Lichao Huang, Zhizhong Su motivation 在v1的基礎上&#xff0c;作者發現長時序有更好的效果&#xff0c;但v1的計算量太大&am…

構建免費的音視頻轉文字工具:支持多語言的語音識別項目

在當今數字時代&#xff0c;音視頻內容越來越多&#xff0c;但如何快速將其轉換為文字一直是一個挑戰。本項目提供了一個免費的解決方案&#xff0c;支持將視頻和音頻文件轉換為文字&#xff0c;并且支持多語言識別。 一個支持中英文的音視頻轉文字工具&#xff0c;集成了 Vos…

【開題答辯全過程】以 基于SpringBootVue的智能敬老院管理系統為例,包含答辯的問題和答案

個人簡介一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧。感謝大家的…

Linux 830 shell:expect,ss -ant ,while IFS=read -r line,

[rootsamba caozx26]# scp /home/caozx26/pub root192.168.235.3:~/ root192.168.235.3s password: /home/caozx26/pub: not a regular file [rootsamba caozx26]# ls app km nntp.sh ntp.sh until1.sh 公共 圖片 音樂 find.sh l2 ntp1.sh pub u…

???????GPT-5發布引爆爭議,奧特曼連夜回應!付費充值的Plus用戶成最大贏家?

摘要&#xff1a; GPT-5發布后&#xff0c;社區口碑兩極分化&#xff0c;從“強無敵”到“還我4o”的呼聲并存。面對技術故障和用戶質疑&#xff0c;OpenAI CEO薩姆奧爾特曼及團隊火速回應&#xff0c;公布了一系列補救措施和未來計劃。本文將帶你速覽這場風波始末&#xff0c;…

Python 操作 Redis 的客戶端 - Redis Stream

Python 操作 Redis 的客戶端 - Redis Stream1. Redis Stream2. Redis Commands2.1. CoreCommands.xadd() (生產端)2.2. CoreCommands.xlen() (生產端)2.3. CoreCommands.xdel() (生產端)2.4. CoreCommands.xrange() (生產端)2.5. RedisClusterCommands.delete()3. Redis Stream…

【Qt開發】按鈕類控件(一)-> QPushButton

目錄 1 -> 什么是 PushButton&#xff1f; 2 -> 相關屬性 3 -> 代碼示例 3.1 -> 帶有圖標的按鈕 3.2 -> 帶有快捷鍵的按鈕 4 -> 總結 1 -> 什么是 PushButton&#xff1f; 在 Qt 框架中&#xff0c;QPushButton 是最基礎且最常用的按鈕控件之一&am…

Citrix 零日漏洞自五月起遭積極利用

安全研究員 Kevin Beaumont 披露了有關 CVE-2025-6543 的驚人細節&#xff0c;這是一個嚴重的 Citrix NetScaler 漏洞&#xff0c;在該公司發布補丁之前的幾個月里&#xff0c;該漏洞被積極利用作為零日攻擊。 Citrix 最初將其輕描淡寫為簡單的“拒絕服務”漏洞&#xff0c;但…

【系列08】端側AI:構建與部署高效的本地化AI模型 第7章:架構設計與高效算子

第7章&#xff1a;架構設計與高效算子 要將AI模型成功部署到端側&#xff0c;除了對現有模型進行壓縮和優化&#xff0c;更根本的方法是在設計之初就考慮其在資源受限環境下的運行效率。本章將深入探討如何設計高效的網絡架構&#xff0c;以及如何理解并優化常用的核心算子。高…

42-Ansible-Inventory

文章目錄Ansible基本概述手動運維時代&#xff08;原始社會&#xff09;自動化運維時代自動化運維工具的優勢Ansible的功能及優點Ansible的架構Ansible的執行流程安裝AnsibleAnsible配置文件生效順序Ansible inventory主機清單Ansible基于免秘鑰方式管理客戶端小結Ansible-Adho…

Go語言runtime/trace工具全面解析

基本概念與功能 Go語言的runtime/trace是Go標準庫中內置的性能分析工具,主要用于追蹤和可視化Go程序的運行時行為。它能夠記錄程序執行期間的各種事件,包括goroutine調度、系統調用、垃圾回收(GC)、網絡I/O、鎖等待等關鍵信息。 trace工具的核心功能包括: goroutine生命周期…