两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例
输入: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
题目数据保证列表表示的数字不含前导零
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers
解题:
多加了些代码,比如打印链表值等,方便查看输出结果, 思路就是从l1, l2两个链从头到尾,两两相加,然后再放到新表中。
中间做些是否为空的判断,及判断好是否有进位就行。
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
if (l1 == NULL && l2 == NULL)
return NULL;
ListNode *p1 = l1;
ListNode *p2 = l2;
ListNode *ret = NULL;
ListNode *cur = NULL;
int add = 0;
int value = 0;
while (p1 || p2) {
value = add; // 把进位值加上
// 添加l1上值
if (p1) {
value += p1->val;
//printf("%d %d\n", p1->val, value);
p1 = p1->next;
}
// 添加l2上值
if (p2) {
value += p2->val;
//printf("%d %d\n", p2->val, value);
p2 = p2->next;
}
// 相加结果要做下进位判断
if (value >= 10) {
add = value / 10;
value = value % 10;
} else {
add = 0;
}
if (cur) {
// 把当前node链到上一结点的next上
cur->next = new ListNode(value);
cur = cur->next;
}
else {
// 当前结点是头结点
cur = new ListNode(value);
}
if (ret == NULL)
ret = cur;
//printf("val:%d add:%d\n", value, add);
}
// 最后一步,要检测下有没有剩下没有算的进位
if (add > 0) {
cur->next = new ListNode();
cur = cur->next;
cur->val = add;
//printf("add:%d\n", add);
}
return ret;
}
ListNode *newList(int *is, int n)
{
if (is == NULL || n <= 0)
return NULL;
ListNode *ret = NULL;
ListNode *p = NULL;
ListNode *pre = NULL;
int i = 0;
while (--n >= 0) {
p = new ListNode();
if (ret == NULL)
ret = p;
if (pre) {
pre->next = p;
pre = p;
} else {
pre = p;
}
p->val = is[i];
printf("%p is[%d]:%d ", p, i, p->val);
printf("\n");
++i;
}
return ret;
}
void printList(ListNode *l)
{
ListNode *p = l;
while (p) {
printf("%p %d ", p, p->val);
p = p->next;
}
printf("\n");
}
int main(int argc, char **argv)
{
int is[] = {2, 4, 3};
ListNode *l1 = newList(is, 3);
int is1[] = {5, 6, 4};
ListNode *l2 = newList(is1, 3);
printList(l1);
printList(l2);
ListNode* ret = addTwoNumbers(l1, l2);
printList(ret);
return 0;
}
执行用时:40 ms, 在所有 C++ 提交中击败了67.02%的用户
内存消耗:69.5 MB, 在所有 C++ 提交中击败了63.11%的用户
算法
1. 算法定义
算法是解决特定问题的一系列明确指令步骤,具有以下特性:
有穷性:必须在有限步骤内结束。
确定性:每一步骤无歧义。
可行性:可通过基本操作实现。
输入/输出:有零或多个输入,至少一个输出。
2. 算法分类
(1) 按设计范式
类型 特点 典型算法
分治法 将问题分解为子问题递归求解 归并排序、快速排序
动态规划 通过存储子问题解避免重复计算 背包问题、最短路径(Floyd)
贪心算法 每一步选择局部最优解 Dijkstra算法、霍夫曼编码
回溯法 尝试所有可能的解并通过剪枝优化 N皇后问题、数独求解
分支限界法 结合广度优先搜索与剪枝策略 旅行商问题(TSP)
(2) 按应用领域
排序算法:快速排序、堆排序、桶排序
搜索算法:二分查找、深度优先搜索(DFS)、广度优先搜索(BFS)
图算法:最小生成树(Prim/Kruskal)、拓扑排序
加密算法:RSA、AES、SHA-256
3. 复杂度分析
衡量算法效率的核心指标:
时间复杂度:执行所需时间随输入规模的增长趋势
(常见:O(1)、O(log n)、O(n)、O(n²)、O(2ⁿ))
空间复杂度:执行所需额外内存空间
示例对比:
算法 平均时间复杂度 空间复杂度 稳定性
冒泡排序 O(n²) O(1) 稳定
快速排序 O(n log n) O(log n) 不稳定
归并排序 O(n log n) O(n) 稳定
4. 算法设计技巧
(1) 递归 vs. 迭代
递归实现斐波那契数列
def fib(n):
if n <= 1: return n
return fib(n-1) + fib(n-2) # 时间复杂度O(2ⁿ)
迭代优化(动态规划)
def fib_dp(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b # 时间复杂度O(n)
return a
(2) 空间换时间
哈希表:用O(n)空间将查找时间从O(n)降至O(1)
前缀和数组:预处理数组以实现区间和的快速查询
5. 实际应用场景
推荐系统:协同过滤算法(基于用户/物品的相似度)
路径规划:A*算法(结合启发式搜索)
数据压缩:LZ77、DEFLATE(ZIP文件基础)
机器学习:梯度下降(模型优化核心)
6. 学习资源推荐
书籍
《算法导论》——经典理论教材
《算法图解》——入门友好型
在线平台
LeetCode(面试向)
Codeforces(竞赛向)
可视化工具
VisuAlgo(https://visualgo.net/)
7. 常见误区
过度追求最优解:实际工程中常需权衡效率与可维护性。
忽视边界条件:如空输入、极端值处理。
混淆时间/空间复杂度:例如递归算法的栈空间消耗。
作者:帅得不敢出门
该博客介绍了一个使用链表结构表示非负整数并进行相加的算法问题。代码以C++实现,通过遍历两个链表,逐位相加并处理进位,最终构建表示和的链表。示例展示了不同输入情况下的输出,并提供了辅助函数用于创建和打印链表。
3614

被折叠的 条评论
为什么被折叠?



