Skip to content

Commit e22d506

Browse files
committed
leetcode热题100
1 parent 8517a63 commit e22d506

File tree

101 files changed

+26707
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+26707
-0
lines changed

algorithm/AddTwoList2.java

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
package com.funian.algorithm.algorithm;
2+
3+
import java.util.Map;
4+
import java.util.Scanner;
5+
import java.util.concurrent.ConcurrentHashMap;
6+
7+
/**
8+
* 两数相加(LeetCode 2)
9+
*
10+
* 时间复杂度:O(max(m, n))
11+
* - m 是第一个链表的长度,n 是第二个链表的长度
12+
* - 需要遍历两个链表,直到两个链表都遍历完且无进位
13+
* - 总时间复杂度为两个链表中较长者的长度
14+
*
15+
* 空间复杂度:O(max(m, n))
16+
* - 结果链表的长度最多为 max(m, n) + 1
17+
* - 需要创建新节点存储结果
18+
*/
19+
public class AddTwoList2 {
20+
21+
/**
22+
* 链表节点定义
23+
*/
24+
static class ListNode {
25+
int val;
26+
ListNode next;
27+
ListNode(int x) { val = x; }
28+
}
29+
30+
/**
31+
* 主函数:处理用户输入并输出两数相加的结果
32+
*
33+
* 算法流程:
34+
* 1. 读取用户输入的两个链表
35+
* 2. 调用addTwoNumbers方法计算两数之和
36+
* 3. 输出结果链表
37+
*/
38+
public static void main(String[] args) {
39+
Scanner scanner = new Scanner(System.in);
40+
41+
// 输入第一个链表
42+
System.out.println("输入第一个链表(用空格分隔每个节点的值):");
43+
ListNode l1 = createList(scanner);
44+
45+
// 输入第二个链表
46+
System.out.println("输入第二个链表(用空格分隔每个节点的值):");
47+
ListNode l2 = createList(scanner);
48+
49+
// 调用addTwoNumbers方法计算两数之和
50+
ListNode result = addTwoNumbers(l1, l2);
51+
System.out.println("结果链表:");
52+
printList(result);
53+
}
54+
55+
/**
56+
* 创建链表的辅助方法
57+
*
58+
* 算法思路:
59+
* 使用哑节点简化链表创建过程
60+
* 依次将输入的数值转换为链表节点
61+
*
62+
* 时间复杂度分析:
63+
* - 遍历输入数组:O(k),其中k为输入数字个数
64+
*
65+
* 空间复杂度分析:
66+
* - 创建链表节点:O(k)
67+
*
68+
* @param scanner Scanner对象用于读取输入
69+
* @return 创建的链表头节点
70+
*/
71+
private static ListNode createList(Scanner scanner) {
72+
// 读取一行输入
73+
String line = scanner.nextLine();
74+
// 按空格分割字符串得到字符串数组
75+
String[] strArray = line.split(" ");
76+
// 创建哑节点
77+
ListNode dummy = new ListNode(0);
78+
// 当前节点指针,初始指向哑节点
79+
ListNode current = dummy;
80+
81+
// 遍历字符串数组
82+
for (String s : strArray) {
83+
// 创建新节点并连接到链表中
84+
current.next = new ListNode(Integer.parseInt(s));
85+
// 移动当前节点指针
86+
current = current.next;
87+
}
88+
// 返回链表的头节点(哑节点的下一个节点)
89+
return dummy.next;
90+
91+
}
92+
93+
/**
94+
* 打印链表的辅助方法
95+
*
96+
* 算法思路:
97+
* 从头节点开始依次遍历并打印每个节点的值
98+
*
99+
* 时间复杂度分析:
100+
* - 遍历链表:O(m),其中m为链表长度
101+
*
102+
* 空间复杂度分析:
103+
* - 只使用常数额外空间:O(1)
104+
*
105+
* @param head 链表的头节点
106+
*/
107+
private static void printList(ListNode head) {
108+
// 遍历链表直到末尾
109+
while (head != null) {
110+
// 打印当前节点的值
111+
System.out.print(head.val + " ");
112+
// 移动到下一个节点
113+
head = head.next;
114+
}
115+
// 换行
116+
System.out.println();
117+
}
118+
119+
/**
120+
* 两数相加的核心方法
121+
*
122+
* 算法思路:
123+
* 模拟手工加法过程,从低位到高位依次相加
124+
* 处理进位情况,直到两个链表都遍历完且无进位
125+
*
126+
* 执行过程分析(以 l1=[2,4,3], l2=[5,6,4] 为例,表示 342 + 465 = 807):
127+
*
128+
* 初始状态:
129+
* l1: 2 -> 4 -> 3 -> null (表示数字 342)
130+
* l2: 5 -> 6 -> 4 -> null (表示数字 465)
131+
* dummy -> null
132+
* current -> dummy
133+
* carry = 0
134+
*
135+
* 第1位相加(2 + 5):
136+
* sum = 0 + 2 + 5 = 7
137+
* carry = 7 / 10 = 0
138+
* 创建节点:new ListNode(7 % 10) = new ListNode(7)
139+
* dummy -> 7 -> null
140+
* current -> 7
141+
* l1: 4 -> 3 -> null
142+
* l2: 6 -> 4 -> null
143+
*
144+
* 第2位相加(4 + 6):
145+
* sum = 0 + 4 + 6 = 10
146+
* carry = 10 / 10 = 1
147+
* 创建节点:new ListNode(10 % 10) = new ListNode(0)
148+
* dummy -> 7 -> 0 -> null
149+
* current -> 0
150+
* l1: 3 -> null
151+
* l2: 4 -> null
152+
*
153+
* 第3位相加(3 + 4):
154+
* sum = 1 + 3 + 4 = 8
155+
* carry = 8 / 10 = 0
156+
* 创建节点:new ListNode(8 % 10) = new ListNode(8)
157+
* dummy -> 7 -> 0 -> 8 -> null
158+
* current -> 8
159+
* l1: null
160+
* l2: null
161+
*
162+
* 循环结束(l1和l2都为null,且carry为0)
163+
*
164+
* 返回 dummy.next,即 7 -> 0 -> 8 -> null(表示数字 807)
165+
*
166+
* 时间复杂度分析:
167+
* - 遍历两个链表:O(max(m, n)),其中m为第一个链表长度,n为第二个链表长度
168+
* - 每次循环执行常数时间操作
169+
*
170+
* 空间复杂度分析:
171+
* - 结果链表节点数:O(max(m, n))
172+
* - 常数额外变量:O(1)
173+
*
174+
* @param l1 第一个数的链表表示(逆序存储)
175+
* @param l2 第二个数的链表表示(逆序存储)
176+
* @return 两数之和的链表表示(逆序存储)
177+
*/
178+
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
179+
// 哑节点,用于简化链表操作
180+
ListNode dummy = new ListNode(0);
181+
// 当前节点指针,初始指向哑节点
182+
ListNode current = dummy;
183+
// 进位值,初始为0
184+
int carry = 0;
185+
186+
// 遍历两个链表,直到两个链表都遍历完且无进位
187+
while (l1 != null || l2 != null || carry != 0) {
188+
// 初始化和为进位
189+
int sum = carry;
190+
191+
// 如果 l1 不为空,则加上 l1 的值
192+
if (l1 != null) {
193+
sum += l1.val;
194+
l1 = l1.next;
195+
}
196+
197+
// 如果 l2 不为空,则加上 l2 的值
198+
if (l2 != null) {
199+
sum += l2.val;
200+
l2 = l2.next;
201+
}
202+
203+
// 计算新的进位
204+
carry = sum / 10;
205+
// 创建新节点,保存当前位的值
206+
current.next = new ListNode(sum % 10);
207+
// 移动到下一个节点
208+
current = current.next;
209+
}
210+
211+
// 返回结果链表(哑节点的下一个节点)
212+
return dummy.next;
213+
}
214+
215+
}

0 commit comments

Comments
 (0)