2011-10-26 18 views
1

昨日のインタビューで、数字を含む2つの単独リンクリストの値を合計する方法を尋ねられました。彼らはまた、リストが不等長である可能性があると述べた。インタビュー:2つのリンクリストの合計数

リストが後方に保存されていたかどうかを尋ねました。これはユニにそれについて学んだ方法ですが、いいえ、それは前方に保存されていました。彼らはまた、リストを単純に逆にすることはできないと言っていました。この種のソリューションは、私がオンラインで見つけることができたすべてです。

再帰関数でこれを行う必要があることを暗示したとしても、回答を得ることができませんでした。

解決策があれば誰でも助けてくれますか?これはC++の仕事のためのもので、私が帰ってきたら、私が解決策を研究したことを説明することができれば、それは良い兆候と見ることができると思っています。ありがとうございました。

合計がどのように働くのか混乱している人には、この方法で提示されました。

リスト1:1-> 2-> 9 リスト2:1->番号が前方に格納されているので、だから、私は両方のリストの9及び3(末端を添加することによって開始する必要がある

3 )。次に、1キャリーを取って1 + 2 + 1を実行します。その他

+0

Cの質問のように聞こえます。なぜ再帰??? –

+2

あなたは正確に何を計算するつもりでしたか? l1 [0] + l2 [0] - > l3 [0]、またはl1 [0] + l1 [私は本当にそれを取得しない;) –

+1

それはあなたのインタビュアーがばかだと示しています。それを再帰的に行うことは、少なくともリストの長さを1回カウントすることと同じくらい遅いです。リストを直接逆にする代わりに、スタックを逆のリストとして使用したいと考えています。あなたが望むなら、私はコードを書くことができますが、この時点ではかなり明確にすべきです。 – xanatos

答えて

4

両方のリストの長さを数えます。先頭に短いリストを0桁の数字で埋めて、長さが等しくなるようにします。今度は、両方の数字を余分な0で埋めます(最初の数字のキャリーで使用されるので、9 + 1 = 10となる可能性があります)。 前の2つの長さの3番目のリンクされたリストを作成します。

class Digit 
{ 
    public: 
    Digit *Next; 
    int Dt; 
} 

と、このような機能::

  • これは、 "バージョン0" である

    今、あなたは、このようなクラスを行います。

  • "バージョン1"では、最後のキャリーの余分なパディングを削除し、必要な場合にのみ追加します。
  • "バージョン2"では、リンクされたリストの先頭から不要な "0"桁を削除します。
  • "バージョン3"では、runningTotalリンクリストをSumに直接作成します。あなたは第1レベルにランニングトータルの「ヘッド」だけを合計します。
  • より短いLLを埋め込むのではなく、 "バージョン4"では、最も長いLLからスキップするための桁数のパラメータを渡します(これは最も困難な通過です)。

さらに複雑な可能性がありますが、リストの長さを事前にカウントする必要はありません。

第1の再帰関数は、両方が存在するときに単に左右に移動するだけです。両方が同時に終了した場合は、前の例のように単純にロールバックすることができます。

それらの一方が他方の前に終了した場合、あなたはこのような別の再帰関数を使用(* extraDigitsの初期値は1):

この機能は最終的に返す
void SaveRemainingDigits(const Digit *remaining, int *extraDigits, int **buffer) 
{ 
    int currentDigit = *extraDigits - 1; 

    *extraDigits = *extraDigits + 1; 

    if (remaining->Next) 
    { 
     SaveRemainingDigits(remaining->Next, extraDigits, buffer);  
    } 
    else 
    { 
     *buffer = (int*)malloc(sizeof(int) * extraDigits); 
    } 

    (*buffer)[currentDigit] = remaining->Dt; 
} 

、我々はスクラッチパッドからを持っていますどこの数字とスクラッチパッドの長さを抽出するか

私たちの最初の再帰関数の最下位レベルは、最短のリンクリストの現在の桁とスクラッチパッドの最後の桁を合計し、最も長いちょうど使用された数字の代わりにスクラッチパッド内のリンクされたリスト。これで、再帰関数をアンロールし、スクラッチパッドを円形配列として使用します。アンロールを終了すると、要素をスクラッチパッドから直接取り出して実行中のリンクリストに追加します。

私が言ったように、少し複雑ですが、1〜2時間でプログラムとして書き留めることができました。 (キャリーなし)

1 2 3 4 
6 5 

あなたが最初の2つの要素を再帰的に。だから、

1-6 (in the first level) 
2-5 (in the second level) 

は今、あなたは第二のリストが終了したことを見ていると、あなたは第2の機能を使用します。

3 (extraDigit enters as 0, is modified to 1. currentDigit = 0) 
4 (extraDigit enters as 1, is modified to 2. currentDigit = 1. 
    malloc of 2 elements, 
    buffer[currentDigit] = 4 => buffer[1] = 4) 

unroll and we return to the previous row 

3 (currentDigit = 0 
    buffer[currentDigit] = 3 => buffer[0] = 3) 

は、今、私たちはその後、リストを反復私は、私はから始まったノードのアドレスを格納する*ヘッドまたは*尻尾のようなノードを作成していた以前の機能に

2-5 (in the second level, 
    with a lengthBuffer == 2, 
    we set index = length(buffer) - 1 
    currentDigitTotal = 5 + buffer[index] => currentDigitTotal = 5 + 4 
    buffer[index] = 2 => buffer[1] = 2; 
    index = (index - 1 + lengthBuffer) % lengthBuffer => index = 0 

1-6 (in the first level, 
    with a lengthBuffer == 2, 
    index = 0, 
    currentDigitTotal = 6 + buffer[index] => currentDigitTotal = 6 + 3 
    buffer[index] = 1 => buffer[0] = 1; 
    index = (index - 1 + lengthBuffer) % lengthBuffer => index = 1 

now we exited the recursive function. 
In an external function we see that we have a buffer. 
We add its elements to the head of the total. 

Our Linked list now is 9-9 and our buffer is 1,2 with index 1 

for (int i = 0; i < lengthBuffer; i++) 
{ 
    runningTotal.AddHead(buffer(index)); 
    index = (index - 1 + lengthBuffer) % lengthBuffer 
} 
+0

私が知りたいのは、この説明が明らかなのかどうかです...誰かが私が書いたことを理解することができますか、それともぎこちないのですか? – xanatos

+0

スクラッチパッドのビットは追随するのが難しいですが、再帰的な説明は何ですか? –

+0

L1の長さが1000であり、L2の長さが200であるとします。L2の先頭に800のゼロをパッドしますか?それは非常に非効率的だとは思わない? –

0

を返します私の出発点に戻っていないことを確認してください。これはそれぞれの長さを数える必要はなく、非効率的であると言えます。

再帰性については、関数の先頭でこのチェックを行い、戻り値(node-> value + myfunct(node-> prev))を返します。あなたが数学を一度やっているのであれば、より効率的です。

2

私はのは、2つのリストがあるとしよう。この

のようなもので、この問題にアプローチします:
1 - > 2 - > 7> 6>> 3 4-および
5> 7 > 2

合計は1->2->7 + Sum(6->4->3, 5->7->2)

今、私たちは、同じサイズの2つのリストを取る機能を作成し、その合計を返します

れていますベースケースと

list1->val + list2->val + Sum(list1->next, list2->next) 

ようになりますif(list1->next == NULL) return list1->val+list2->val;

注::我々は簡単に次のパスでキャリーを扱うことができるか、私たちのSUM関数自体、このすべての後にそう

でそれを処理することができ、当社ansは1->2->7->11->11->5 になり、再帰的に%10を実行してキャリーをとり、それを以前の値に加算します。

最終的なANSは1->2->8->2->1->5

0

リスト "1、2、9" 及び "1,3" それぞれであろう和が "142" である場合には数字 "129" 及び "13" を表します。再帰

  • 各リストの長さを計算を使用

  • 長さが異なる場合は、最短でゼロを埋めます。
  • リストを再帰的に反復し、a)キャリー番号(存在する場合)またはそれ以外の場合はゼロ、b)リストの末尾。擬似コードで

:別の方法として

def sum_lists_rec(a, b, start_a, start_b, length_a, length_b): 
    """Returns a pair of two elements: carry and the tail of the list.""" 

    if the end of the lists: 
     return (0, empty_list) 

    result = sum_lists_rec(a+1, b+1, start_a+1, start_b+1, length_a, length_b) 

    carry = (a[0] + b[0] + result[0])/10 
    digit = (a[0] + b[0] + result[0]) % 10 

    return (carry, [digit] ++ result[1]) 

def sum_lists1(a, b): 
    length_a = length(a) 
    length_b = length(b) 

    if length_a < length_b: 
     a = [0, 0, ..., (length_b - length_a)] ++ a 
    else if length_b < length_a: 
     b = [0, 0, ..., (length_a - length_b)] ++ b 

    result = sum_lists_rec(a, b, length_a, length_b, 0, 0) 

    if result[0] != 0: 
     return [result[0]] ++ result[1] 
    else: 
     return result[1] 

、あなたはスタックを使用することができます。

  • は、各リストの長さを計算します。
  • 長さが異なる場合は、最短でゼロを埋めます。
  • スタック上の両方のリストの各桁を押します。
  • スタックが空になるまでポップし、新しいリストを作成します。
関連する問題