Вычисление суммы значений в связанном списке

недавно я получил вопрос о программировании на интервью.

есть 2 связанных списка. Каждый узел хранит значение от 1 до 9 (указывающее один индекс числа). Следовательно, 123 будет связанным списком 1->2 - >3

задача была создать функцию:

static LinkedListNode getSum(LinkedListNode a, LinkedListNode b)

это вернет сумму значений в 2 аргументах связанного списка.

если массив a: 1->2->3->4

и массив b: 5->6->7->8

ответ должен быть: 6->9->1->2

вот мой алгоритм:

пройдите через каждый узел в a и b, получите значения как целое число и добавьте их. Создайте новый связанный список с этими значениями.

вот код: он работает со сложностью O (n) примерно я предполагаю. Один раз через каждый из входов массива и один раз для создания выходного массива.

какие-либо улучшения? Лучшие алгоритмы... или код улучшения

public class LinkedListNode {
        LinkedListNode next;
        int value;

    public LinkedListNode(int value) {
        this.value = value;
        this.next = null;
    }

    static int getValue(LinkedListNode node) {
        int value = node.value;
        while (node.next != null) {
            node = node.next;
            value = value * 10 + node.value;
        }
        return value;
    }

    static LinkedListNode getSum(LinkedListNode a, LinkedListNode b) {
        LinkedListNode answer = new LinkedListNode(0);
        LinkedListNode ans = answer;
        int aval = getValue(a);
        int bval = getValue(b);
        int result = aval + bval;
        while (result > 0) {
            int len = (int) Math.pow((double) 10,
                    (double) String.valueOf(result).length() - 1);
            int val = result / len;
            ans.next = new LinkedListNode(val);
            ans = ans.next;
            result = result - val*len;
            }    
        return answer.next;
    }
}

5 ответов


другие решения, которые я видел для этой проблемы, включают построение возвращаемого списка постепенно, повторяя назад оба входных списка одновременно добавляя каждый элемент по мере перехода к новому списку. Этот способ сложнее, потому что вы должны добавить каждый элемент и иметь дело с переносами.

Если массив a: 1->2->3->4

и массив b: 5->6->7->8

итерации назад

затем 4 + 8 = 12 (возвращаемый список current = 2)

нести 1

(1) + 3 + 7 = 11 (возвращенный список = 1-> 2)

нести 1

(1) + 2 + 6 = 9 (возвращенный список = 9 -> 1 ->2 )

1 + 5 = 6 ( список вернуться= 6->9>1->2)

вы можете реализовать это, используя стеки, чтобы получить природу LIFO для итерации назад, если список связан только по отдельности.


другие ответы, которые я видел, часто полагаются на дополнительный стек. На самом деле это можно решить только с помощью O(1) дополнительное пространство. Я изменил пример в другом ответе, чтобы сделать два списка разными по длине:

list a is: 1->2->3->4
list b is: 5->6->7->8->3->6

мы можем просто перебрать оба списка, хранить значения текущих значений в a и b, в значении нового списка c. Но мы не можем просто взять сумму двух значений как значение в c, потому что в случае, если два списка отличаются в длина, мы не смогли восстановить исходные значения в list a и b. Небольшой трюк заключается в создании двухзначного значения, первая цифра которого является значением в a и второе значение b, например:

list c: 15 <- 26 <- 37 <- 48 <- 3 <- 6
                                     ^ pointer "p1"
                           ^ pointer "p2" here to mark the end of list a

когда-то полностью создан, перематываем с указателя "p1". Сначала мы разделяем два числа в узле по указателю "p2", затем добавляем правильное число к значению в p1. Затем мы переворачиваем p1 и устанавливаем p1->next, и p2 и p2->next, а затем продолжить к предыдущим узлам.

list c: 15 <- 26 <- 37 <- 8 <- 3 -> 4
                               ^ p1
                     ^ p2
                               carry = 1

сложность времени 2*max( length(a), length(b) ).


Привет @rtindru: как вы сказали, что хотите добавить два связанных списка. Первый связанный список a:1->2->3->4 Второй связанный список b:5->6->7->8

в вопросе не упоминается, что цифры, хранящиеся в связанном списке, хранятся в том же порядке или в обратном порядке, что и число. Первый подход сложнее.

Первый Подход:

list a: 1234
list b: 5678

ответ должен быть: 6->9->1->2

   1 2 3 4
+  5 6 7 8
-----------------
   6 9 1 2

Второй Подход

если номер хранится в обратном порядке, то

первый связанный список a:1->2->3->4. Фактическое число:N1=4321. И второй связанный список b:5->6->7->8. Фактическое число:N2=8765. Сумма будет 6->8->0->3->1. Это легкий подход.

в вопросе, который вы задаете для первого подхода, и данный пример также для первого подхода, но ваш исходный код для второго подхода. Пожалуйста соответствуй ему.


вот мой ответ на этот вопрос (используется C# вместо Java, но логика может быть легко воспроизведен на любом языке). Я использовал разворот связанного списка для прямого суммирования, а для обратного хранения я использовал подход переноса вперед.

/*  Program: Given two numbers represented in a linked list in reverse order, sum them and store the result in a third linked list
 *  
 *  Date: 12/25/2015
 */

using System;

namespace CrackingTheCodingInterview
{
    /// <summary>
    /// Singly Linked List with a method to add two numbers stored in two linked lists in reverse order
    /// </summary>
    public partial class SinglyLinkedList
    {
        /// <summary>
        /// Adding two numbers stored in a linked list in reverse order
        /// </summary>
        /// <param name="num1">Linked List 1 storing number 1</param>
        /// <param name="num2">Linked List 2 storing number 2</param>
        /// <param name="result">Linked List 3 storing sum of number 1 and number 2</param>
        public static void SumNumbersReverse(SinglyLinkedList num1, SinglyLinkedList num2, SinglyLinkedList result)
        {
            int carryForward = 0;
            int sum = 0;

            Node num1Digit = num1.head;
            Node num2Digit = num2.head;

            int sum1 = 0;
            int sum2 = 0;

            while (num1Digit != null || num2Digit != null)
            {
                if (num1Digit == null)
                {
                    sum1 = 0;
                }
                else
                {
                    sum1 = (int)num1Digit.Data;
                }

                if (num2Digit == null)
                {
                    sum2 = 0;
                }
                else
                {
                    sum2 = (int)num2Digit.Data;
                }

                sum = sum1 + sum2 + carryForward;

                if (sum > 9)
                {
                    carryForward = 1;
                }
                else
                {
                    carryForward = 0;
                }

                result.Insert(sum % 10);

                if (num1Digit != null)
                {
                    num1Digit = num1Digit.Next;
                }

                if (num2Digit != null)
                {
                    num2Digit = num2Digit.Next;
                }
            }

            result.ReverseList();
        }

        /// <summary>
        /// Adding two numbers stored in a linked list in reverse order
        /// </summary>
        /// <param name="num1">Linked List 1 storing number 1</param>
        /// <param name="num2">Linked List 2 storing number 2</param>
        /// <param name="result">Linked List 3 storing sum of number 1 and number 2</param>
        public static void SumNumbersForward(SinglyLinkedList num1, SinglyLinkedList num2, SinglyLinkedList result)
        {
            num1.ReverseList();
            num2.ReverseList();

            SumNumbersReverse(num1, num2, result);

            result.ReverseList();
        }

        /// <summary>
        /// Reverse a singly linked list
        /// </summary>
        public void ReverseList()
        {
            Node prev = null;
            Node curr = head;
            Node currNext;

            while(curr != null)
            {
                currNext = curr.Next;
                curr.Next = prev;
                prev = curr;
                curr = currNext;
            }

            head = prev;
        }
    }


    internal class SumNumbersLinkedListTest
    {
        static void Main()
        {
            SinglyLinkedList num1 = new SinglyLinkedList();
            SinglyLinkedList num2 = new SinglyLinkedList();

            num1.Insert(6);
            num1.Insert(1);
            num1.Insert(7);

            num2.Insert(2);
            num2.Insert(9);
            num2.Insert(5);

            num1.Print();
            num2.Print();

            SinglyLinkedList resultReverseSum = new SinglyLinkedList();
            SinglyLinkedList resultForwardSum = new SinglyLinkedList();

            SinglyLinkedList.SumNumbersReverse(num1, num2, resultReverseSum);
            Console.WriteLine("After summing reverse: ");
            resultReverseSum.Print();

            SinglyLinkedList num3 = new SinglyLinkedList();
            SinglyLinkedList num4 = new SinglyLinkedList();

            num3.Insert(7);
            num3.Insert(1);
            num3.Insert(6);

            num4.Insert(5);
            num4.Insert(9);
            num4.Insert(2);

            SinglyLinkedList.SumNumbersForward(num3, num4, resultForwardSum);
            Console.WriteLine("After summing forward: ");
            resultForwardSum.Print();

            Console.ReadLine();
        }
    }
}

вы можете сделать это, изменив linkedlists. Это реализация c# и Это O (n).

    public LinkedList ElementSum(LinkedList other)
    {
        LinkedList linkedListSum = new LinkedList();
        this.Reverse();
        other.Reverse();
        Node n1 = this.head, n2 = other.head;
        int toAdd = 0, carryOver = 0;
        while ((n1 != null) || (n2 != null))
        {
            int num1 = (int) (n1 == null ? 0 : n1.NodeContent);
            int num2 = (int) (n2 == null ? 0 : n2.NodeContent);
            toAdd = (num1 + num2 + carryOver) % 10;
            carryOver = (int)(num1 + num2 + carryOver) / 10;
            linkedListSum.Add(toAdd);
            n1 = (n1 == null ? null : n1.Next);
            n2 = (n2 == null ? null : n2.Next);
        }
        this.Reverse();
        other.Reverse();
        linkedListSum.Reverse();
        return linkedListSum;
    }