每天一道算法題-兩數相加

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

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

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

示例一:
輸入:l1 = [2,4,3], l2 = [5,6,4]
輸出:[7,0,8]
解釋:342 + 465 = 807.

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

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

首先,題目說兩個非空鏈表,每個節點存一位數字,而且是逆序存儲的。比如,數字342會被存為2->4->3這樣的鏈表。那我要把這樣的兩個鏈表相加,得到的結果同樣用逆序的鏈表表示。并且,除了數字0之外,這兩個數都不會以0開頭。那輸出的鏈表也應該符合這個條件,比如結果如果是0的話,就只能有一個節點。

那怎么做呢?我記得通常處理這種鏈表加法的時候,是模擬加法進位的過程。因為鏈表是逆序的,所以最低位在鏈表頭,這樣可以直接從頭開始相加,處理進位。這應該比較直接。

那步驟大概是這樣的:同時遍歷兩個鏈表,逐位相加,同時考慮進位。當其中一個鏈表遍歷完時,繼續處理剩下的節點,加上進位。最后如果還有進位,要新建一個節點。

比如例子中的情況:比如輸入是2->4->3(342)和5->6->4(465),相加得到807,結果應該是7->0->8。那鏈表就是7->0->8。這個過程需要處理每一位相加,進位保存下來加到下一位。

那具體實現的話,我需要創建兩個指針分別遍歷兩個鏈表,同時維護一個進位變量carry。每次取出兩個節點的值相加,加上carry,然后計算當前位的值(sum%10)和新的進位(sum/10)。然后將當前位的值作為新節點添加到結果鏈表中。直到兩個鏈表都遍歷完,并且進位為0為止。

這里需要注意的情況是,當兩個鏈表長度不一致的時候,較長的那個鏈表剩下的部分需要繼續處理。比如一個鏈表已經遍歷完,另一個還有節點,或者進位還存在的情況下要繼續處理。

舉個例子,比如鏈表1是9->9,鏈表2是9。那相加的話,結果應該是8->0->1。即99+9=108,逆序的話是8->0->1。這時候,當鏈表2遍歷完后,鏈表1還有節點,這時候要繼續處理剩下的節點,加上進位。

那如何實現呢?可以用循環,當鏈表1或鏈表2還有節點,或者進位不為零的時候繼續循環。在循環中,每次取出當前節點的值,如果鏈表已經到頭了,就取0。然后計算和,然后移動指針,如果鏈表還有下一個節點的話。

那現在考慮鏈表的遍歷方式。比如,用while循環,條件是l1不為空或者l2不為空或者carry不為零。這樣就能覆蓋所有情況。

比如,初始化進位carry為0。然后,在每次循環中:

? 取l1的當前值,如果l1不為空,否則取0。
? 取l2的當前值,如果l2不為空,否則取0。
? 計算sum = val1 + val2 + carry。
? 計算新的carry = sum / 10。
? 創建新節點,值為sum %10。
? 將新節點連接到結果鏈表的末尾。
? 移動l1和l2的指針(如果存在的話)。

但是,這樣處理的話,結果鏈表的構建需要維護一個當前指針,或者使用啞結點(dummy node)來簡化操作。啞結點的下一個節點是真正的頭節點,這樣可以避免處理初始空鏈表的情況。

比如,初始化一個dummy節點,然后維護一個當前指針curr,初始指向dummy。每次生成新節點時,curr.next指向它,然后curr移動到下一個節點。這樣最后返回dummy.next即可。

這樣就能處理所有情況,包括最后的進位。例如,當所有節點都處理完了,但還有進位1,這時候需要新建一個節點。

那現在編寫具體的代碼步驟:

  1. 創建一個啞結點dummy,curr指向dummy。
  2. 初始化carry為0。
  3. 當l1不為空,或l2不為空,或者carry不為0時循環:
    a. 獲取l1的值,如果l1存在,否則為0。
    b. 獲取l2的值,如果l2存在,否則為0。
    c. 計算sum = val1 + val2 + carry。
    d. 計算新的carry = sum /10。
    e. 創建新節點,值為sum %10。
    f. curr.next指向新節點,curr移動到next。
    g. 如果l1不為空,l1移動到l1.next。
    h. 如果l2不為空,l2移動到l2.next。
  4. 返回dummy.next作為結果鏈表的頭節點。

那這樣的邏輯應該可以覆蓋所有情況。

比如測試案例:

例子1:
輸入:l1 = [2,4,3], l2 = [5,6,4]
相加結果:342 + 465 = 807 → 逆序是7->0->8。
按照步驟:
初始化carry為0。
第一次循環:
val1=2,val2=5,sum=7+0=7。carry=0,新節點7。curr指向它。l1和l2都移動到下一個。
第二次循環:
val1=4,val2=6,sum=10+0=10。sum%10=0,carry=1。新節點0。curr指向它。l1和l2移動到下一位。
第三次循環:
val1=3,val2=4,sum=3+4+1=8 → sum%10=8,carry=0。新節點8。此時l1和l2都到頭了,但循環繼續嗎?因為此時carry為0,但是此時循環的條件是l1或l2不為空或carry不為零。此時l1和l2都是空,carry為0,所以退出循環。
結果鏈表是7->0->8。正確。

另一個例子,其中一個鏈表較長:
比如l1是9->9->9,l2是9->9。即數字是999和99,相加是1098。逆序存儲的話,鏈表應該是8->9->0->1。
處理過程:
初始carry=0。
第一次循環:9+9=18+0=18 → sum%10=8,carry=1。新節點8。l1和l2都移動。
第二次循環:9+9+1=19 → sum%10=9,carry=1。l1移動,l2為空。
第三次循環:9+0+1=10 → sum%10=0,carry=1。此時l1還有嗎?l1此時是第三個節點,處理完這次后,l1變為null。l2還是null,但carry是1。所以循環繼續。
第四次循環:0+0+1=1 → sum%10=1,carry=0。創建節點1。此時所有條件都不滿足,退出循環。結果鏈表是8->9->0->1。正確。

那這樣處理是正確的。

那關于啞結點的使用,這樣可以避免處理初始頭節點為空的情況,簡化代碼。

現在考慮代碼的實現,比如用Java的話:

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
int carry = 0;
while (l1 != null || l2 != null || carry != 0) {
int val1 = (l1 != null) ? l1.val : 0;
int val2 = (l2 != null) ? l2.val : 0;
int sum = val1 + val2 + carry;
carry = sum / 10;
curr.next = new ListNode(sum % 10);
curr = curr.next;
if (l1 != null) l1 = l1.next;
if (l2 != null) l2 = l2.next;
}
return dummy.next;
}

這樣應該可以正確處理所有情況。例如,當兩個鏈表都處理完,但還有進位的情況,比如最后進位為1時,會生成一個新節點。

那這個解法的時間復雜度是O(max(m, n)),其中m和n是兩個鏈表的長度,因為需要遍歷兩個鏈表的全部節點。空間復雜度是O(max(m, n)),因為需要創建結果鏈表,其長度最多為max(m,n)+1(比如最后進位的情況)。

那有沒有特殊情況需要處理?比如兩個鏈表都為空,但題目規定是非空的,所以不需要考慮。或者結果鏈表的前導零?題目說明除了數字0外,不會以0開頭,所以比如結果為0的情況只能是0本身,也就是一個節點。這種情況會在循環中處理嗎?

比如,輸入是兩個0的鏈表。則相加得到0,此時循環的條件是l1或l2不為空或carry不為零。初始時,l1和l2都是非空,所以進入循環:

val1=0,val2=0,sum=0+0+0=0,carry=0。創建節點0。然后l1和l2都移動到null。此時循環是否繼續?此時,l1和l2都為空,carry為0,所以不進入循環。返回dummy.next是節點0。正確。

那沒有問題。

另一個測試案例,比如l1是[9,9],l2是[9]。相加得到18 + 9 = 99+9=108?或者原題中的例子是否應該更仔細?

比如,鏈表1是9->9,即99,逆序的話是99。鏈表2是9,即9。相加得到99+9=108。逆序存儲的話應該是8->0->1。按照上述代碼的處理:

第一次循環,sum是9+9+0=18 → sum%10=8,carry=1。節點8。l1移動,l2移動(到null)。
第二次循環,l1有節點9,val1=9,val2=0,sum=9+0+1=10 → sum%10=0,carry=1。節點0。l1移動(null)。
第三次循環,l1和l2都null,carry=1。sum=0+0+1=1 → sum%10=1,carry=0。節點1。此時循環結束。結果鏈表是8->0->1,正確。

綜上,這個代碼應該可以正確處理所有情況。

要將兩個逆序鏈表表示的數字相加并返回同樣格式的鏈表,可以按照以下步驟進行:

方法思路

  1. 初始化:使用啞結點(dummy node)簡化鏈表操作,并維護一個當前指針 curr 來構建結果鏈表。同時,用變量 carry 記錄進位值。
  2. 遍歷鏈表:同時遍歷兩個鏈表,逐位相加:
    ? 如果某個鏈表已遍歷完,則其后續位的值視為0。
    ? 計算當前位的和(包括進位),更新進位。
    ? 將當前位的值作為新節點添加到結果鏈表中。
  3. 處理剩余進位:若遍歷結束后仍有進位,需添加新節點。

解決代碼

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 addTwoNumbers(ListNode l1, ListNode l2) {ListNode dummy = new ListNode(0);ListNode curr = dummy;int carry = 0;while (l1 != null || l2 != null || carry != 0) {int val1 = (l1 != null) ? l1.val : 0;int val2 = (l2 != null) ? l2.val : 0;int sum = val1 + val2 + carry;carry = sum / 10;curr.next = new ListNode(sum % 10);curr = curr.next;if (l1 != null) l1 = l1.next;if (l2 != null) l2 = l2.next;}return dummy.next;}
}

代碼解釋

  1. 啞結點初始化dummy 節點簡化鏈表頭部的處理,curr 用于逐步構建結果鏈表。
  2. 循環條件l1l2 未遍歷完,或仍有進位時繼續循環。
  3. 計算當前位和進位:取兩鏈表當前節點的值(若存在),加上進位計算總和,更新進位。
  4. 添加新節點:將當前位的值(sum % 10)作為新節點,移動 curr
  5. 移動鏈表指針:若鏈表未遍歷完,繼續移動指針。
  6. 返回結果:最終返回啞結點的下一個節點,即結果鏈表的頭節點。

該方法時間復雜度為 O(max(m, n)),空間復雜度為 O(max(m, n)),能高效處理兩數相加問題。

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

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

相關文章

win10搭建opengl環境搭建并測試--輸出立方體球體和碗型并在球體上貼圖

參照本文檔可以完成環境搭建和測試,如果想要快速完成環境的搭建可以獲取本人的工程,包括所用到的工具鏈和測試工程源碼獲取(非免費介意務下載):鏈接: https://pan.baidu.com/s/1H2ejbT7kLM9ore5MqyomgA 提取碼: 8s1b …

CIR-Net:用于 RGB-D 顯著性目標檢測的跨模態交互與優化(問題)

摘要 問題一:自模態注意力優化單元和跨模態加權優化單元什么意思? 1 優化中間件結構的作用 位置:位于編碼器和解碼器之間 輸入:編碼器提取的RGB特征,深度特征以及RGB-D特征。 輸出:經過優化的RGB&…

LS-NET-004-簡單二層環路解決(華為銳捷思科)

LS-NET-004-簡單二層環路解決(華為銳捷思科) 以下是為您準備的二層環路示意圖及解決方案,包含四大廠商配置對比: 一、Mermaid 二層環路示意圖 graph TD SW1 -->|Gi0/1| SW2 SW2 -->|Gi0/2| SW3 SW3 -->|Gi0/3| SW1 SW1…

【正點原子K210連載】第七十六章 音頻FFT實驗 摘自【正點原子】DNK210使用指南-CanMV版指南

第七十六章 音頻FFT實驗 本章將介紹CanMV下FFT的應用,通過將時域采集到的音頻數據通過FFT為頻域。通過本章的學習,讀者將學習到CanMV下控制FFT加速器進行FFT的使用。 本章分為如下幾個小節: 32.1 maix.FFT模塊介紹 32.2 硬件設計 32.3 程序設…

火絨終端安全管理系統V2.0——行為管理(軟件禁用+違規外聯)

火絨終端安全管理系統V2.0:行為管理策略分為軟件禁用和違規外聯兩部分,能夠管理終端用戶軟件的使用,以及終端用戶違規連接外部網絡的問題。 l 軟件禁用 軟件禁用策略可以選擇軟件名單的屬性、添加軟件名單以及設置發現終端使用禁用軟件時的…

FastJson:JSON JSONObject JSONArray詳解以及SimplePropertyPreFilter 的介紹

FastJson:JSON JSONObject JSONArray詳解以及SimplePropertyPreFilter 的介紹 FastJson是阿里巴巴開發的一款專門用于Java開發的包,實現Json對象,JavaBean對,Json字符串之間的轉換。 文章目錄 FastJson:JSON JSONObje…

DEFI幣生態重構加速,XBIT去中心化交易所引領DEX安全新范式

2025年3月18日,全球加密市場在監管與技術共振下迎來結構性變革。去中心化金融(DeFi)代幣DEFI幣因跨鏈流動性協議升級引發社區熱議,而幣應XBIT去中心化交易所(以下簡稱XBIT)憑借其鏈上透明驗證機制、無需下載…

解析漏洞總結

首先說下為什么要寫著篇文章,之前學習倒是學過,學完就忘啊,tmd iis 5.x/6.0 這個版本有兩種解析姿勢  一.兩種解析漏洞 1.目錄解析 2./xxx.asp/xx.jpg 簡單說一下是什么意思,這里是先在他服務器跟目錄創建一個名為 xxx.…

前端小食堂 | Day18 - 身份認證の八卦陣

🔐 今日秘術:JWT/OAuth2 攻防奧義 1. JWT 安全の六合陣法 // 🚫 危險操作:未驗證簽名 const decodeUnsafe (token) > JSON.parse(atob(token.split(.)[1])); // ? 安全姿勢一:嚴格簽名驗證 import jwt fro…

將bin文件燒錄到STM32

將bin文件燒錄到STM32 CoFlash下載生成hex文件hex2bin使用下載bin到單片機 CoFlash下載 選擇需要安裝的目錄 在Config中可以選擇目標芯片的類型 我演示的是 stm32f103c8t6 最小系統板 Adapter:燒錄器類型 Max Clock:下載速度 Por:接口類型&am…

【Embedded World 2025:邊緣 AI、存儲革新與 1X nm 工藝重塑嵌入式未來】

Embedded World 2025于3月11-13日在德國紐倫堡舉辦,作為全球嵌入式系統領域頂級盛會,匯聚超千家展商與3萬專業觀眾,聚焦嵌入式智能、安全管理及行業解決方案。展會呈現邊緣AI、低功耗MCU、5G RedCap、新型存儲及車規級技術等前沿方向&#xf…

3.19刷題

P6443 [COCI 2010/2011 #1] TIMSKO - 洛谷 #include<bits/stdc.h> using namespace std; int main(){int n,m,k,maxp0;cin>>m>>n>>k;for(int i0;i<n;i){//男生參加人數if(k3*i<mn&&2*i<m) maxpi;}cout<<maxp;return 0; }P645…

Android NDK --- JNI從入門到基礎的全面掌握 (上)

引言 先問 jni是什么&#xff1f; jni和ndk 的關系&#xff1f; 答&#xff1a; java調用 C、C 的代碼。 兩者一個是調用&#xff0c;一個是用c 、c 寫 。 這兩個問題問出來似乎知道又好像不知道。 正文 jni 概述 定義&#xff1a;java Native Interface 即 java本地接口 …

爬蟲 crawler 入門爬取不設防網頁 并實現無限增生

基礎版本 爬取網頁后直接將前端html代碼不加處理的輸出 # pip3 install requests import requests# request the target URL def crawler():response requests.get("https://www.scrapingcourse.com/ecommerce/")response.raise_for_status()print(response.text)…

C++高頻(四)之c++11新特性

C++面試高頻(四)之c++11新特性 1.簡述C++11有什么新特性?? 自動類型推導(Type Inference):引入了 auto 關鍵字,允許編譯器根據初始化表達式的類型自動推導變量的類型。統一的初始化語法(Uniform Initialization Syntax):引入了用花括號 {} 進行初始化的統一語法,可…

HarmonyOs- UIAbility應用上下文

上下文為何物 上下文在計算機科學領域是一個廣泛存在的概念。是現代操作系統核心抽象概念之一。其本質是環境信息的結構化封裝。 有過開發經驗的都知道&#xff0c;當我們在一個系統上進行開發的時候&#xff0c;無論是Android&#xff0c;HarmonyOs&#xff0c;Linux 等等&a…

Redis解決緩存擊穿問題——兩種方法

目錄 引言 解決辦法 互斥鎖&#xff08;強一致&#xff0c;性能差&#xff09; 邏輯過期&#xff08;高可用&#xff0c;性能優&#xff09; 設計邏輯過期時間 引言 緩存擊穿&#xff1a;給某一個key設置了過期時間&#xff0c;當key過期的時候&#xff0c;恰好這個時間點對…

架構思維:軟件建模與架構設計的關鍵要點

文章目錄 1. 軟件建模的核心概念2. 七種常用UML圖及其應用場景類圖時序圖組件圖部署圖用例圖狀態圖活動圖 3. 軟件設計文檔的三階段結構4. 架構設計的關鍵實踐1. 用例圖&#xff1a;核心功能模塊2. 部署圖&#xff1a;架構演進階段3. 技術挑戰與解決方案4. 關鍵架構圖示例5. 架…

numpy學習筆記14:模擬隨機游走過程(一次實驗)

numpy學習筆記14&#xff1a;模擬隨機游走過程(一次實驗) 隨機游走是一個對象在離散時間步中的隨機移動&#xff0c;每次移動的方向和步長由概率決定。在用戶提供的代碼中&#xff0c;步長數組steps的每個元素是-1或1&#xff0c;代表向左或向右移動一步。np.random.choice的作…

FPGA-DE2115開發板實現流水燈

文章目錄 一、安裝VScode&#xff0c;在其中下載安裝Verilog-HDL/SystemVerilog插件&#xff1b;&#xff08;1&#xff09;安裝VScode&#xff08;2&#xff09;安裝插件&#xff08;3&#xff09;與Quartus關聯 二、不分模塊實現流水燈&#xff08;1&#xff09;新建工程&…