LeetCode #2 "Add Two Numbers"
上から2番目のを解いてみた。
問題文
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
数値が、各桁が連結リストのノードで表現されていて、これらを2つ足して、同じく連結リストで表現された数値を導き出せ、というもの。
計算量を減らすためのアルゴリズムを考えるというよりは、データ構造をうまく扱えるかどうかが求められていると感じた。
単純に各桁を足して10以上なら桁上りで次の桁を足す。作業としてはこれだけなのだが、結構奥が深い。
コードを書きながら考えたこと
結果のリストをどう作成するかが重要で、無駄を減らすなら、最初に与えられた2つのリストのうち1つを上書いて計算結果を保持させることになる。ただ、2つのリスト長が不揃いであることがやっかいで、しかもリスト長はリストを全て辿ることでしか得られない。なので、計算速度を求めるなら、どちらのリストに計算結果を書いていくかを事前に得ることはできないだろう。
そこで、どちらかのリストを適当に選んで計算結果の保存先にしておく。各桁を計算していく過程で、保存先としているリストの終端のほうが先に見えたら、それをもう一方のリストへ繋いでしまえば良い。もし保存先としていないリストの終端が先に見えた場合は、繋ぎ変えは必要ない。
一方のリストが終端になった場合、以降の桁を予め作成しておいた値が0のエントリで計算させる。最後の桁を計算し終わった時点で桁上げがあった場合は、新しいリストエントリを作成して追加する。
コード
最終的にsubmitしたのが下記コード。結構時間かかった。。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
auto current1 = l1;
auto current2 = l2;
bool carry = false;
auto dummy = ListNode(0);
while(true){
current1->val += current2->val + carry;
carry = current1->val > 9;
if(carry){
current1->val -= 10;
}
if(!current1->next && !current2->next){
if(carry){
current1->next = new ListNode(1);
}
return l1;
}
else if(!current2->next){
current1 = current1->next;
current2 = &dummy;
}
else if(!current1->next){
current1->next = current2->next;
current1 = current2->next;
current2 = &dummy;
}
else{
current1 = current1->next;
current2 = current2->next;
}
}
throw std::logic_error("cannot resolve");
}
};