牛客BM11题:从竖式加法到栈的妙用
引言:从生活场景到算法问题
想象你在小学时做过的竖式加法:把两个数字右对齐,从个位开始逐位相加,遇到进位就向高位传递。当我们需要处理链表表示的大数相加时,这个熟悉的场景突然变得复杂起来——因为链表只能顺序访问,而加法需要从最低位开始处理。这就是BM11题的核心挑战。
一、问题重述与难点分析
给定两个链表,每个节点存储0-9的数字,链表整体代表一个整数(如9->3->7表示937)。要求返回表示两数之和的新链表。关键难点在于:
链表是单向的,无法直接反向访问
数字长度可能不同(如1234+56)
最高位可能产生额外进位(如999+1=1000)
二、核心解法:栈的应用
为什么选择栈?
栈的"后进先出"(LIFO)特性完美解决了链表反向访问的问题:
第一次遍历:将链表节点值压入栈,栈顶即为数字最低位
计算阶段:每次弹出栈顶元素,相当于从个位开始处理
结果构建:使用头插法自然形成正确顺序的结果链表
三、代码实现
/** * struct ListNode { * int val; * struct ListNode *next; * ListNode(int x) : val(x), next(nullptr) {} * }; */ class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param head1 ListNode类 * @param head2 ListNode类 * @return ListNode类 */ ListNode* addInList(ListNode* head1, ListNode* head2) { stack<int> s1, s2; // 将链表数据压入栈(反向处理) while (head1) { s1.push(head1->val); head1 = head1->next; } while (head2) { s2.push(head2->val); head2 = head2->next; } int carry = 0; ListNode* res = nullptr; // 栈顶元素相加(即链表尾部开始) while (!s1.empty() || !s2.empty() || carry) { int sum = carry; if (!s1.empty()) { sum += s1.top(); s1.pop(); } if (!s2.empty()) { sum += s2.top(); s2.pop(); } carry = sum / 10; ListNode* node = new ListNode(sum % 10); node->next = res; // 头插法构建结果链表 res = node; } return res; } };
四、案例演示
以9->3->7 + 6->3为例:
栈s1: [7,3,9] (对应937)
栈s2: [3,6] (对应63)
计算过程:
1. 7+3=10 → 写0进1
2. 3+6+1=10 → 写0进1
3. 9+0+1=10 → 写0进1
4. 处理最后进位1 → 写1
结果:1->0->0->0 (1000)
五、总结与拓展
通过这个问题,我们学到了:
掌握这种"数据结构特性转化问题本质"的思维,比记住解法本身更重要。
原创内容 转载请注明出处