Вычисление суммы значений в связанном списке
недавно я получил вопрос о программировании на интервью.
есть 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;
}