Add Two Numbers
Ссылки:
Решение (первое, переполнение)
<?php
class ListNode
{
public $val = 0;
public $next = null;
function __construct($val = 0, $next = null)
{
$this->val = $val;
$this->next = $next;
}
}
class Solution
{
/**
* @param ListNode $l1
* @param ListNode $l2
* @return ListNode
*/
function addTwoNumbers($l1, $l2)
{
$n1 = '';
$n2 = '';
$current1 = $l1;
$current2 = $l2;
while ($current1 || $current2) {
if ($current1) {
$n1 .= $current1->val;
$current1 = $current1->next;
}
if ($current2) {
$n2 .= $current2->val;
$current2 = $current2->next;
}
}
$result = (int)strrev($n1) + (int)strrev($n2);
$result = (int)$result;
$pointer = $curPointer = new ListNode($result % 10);
$result = intdiv($result, 10);
while ($result > 0) {
$curPointer->next = new ListNode($result % 10);
$curPointer = $curPointer->next;
$result = intdiv($result, 10);
}
return $pointer;
}
}
Проблема
У нас есть два числа, представленных в виде связанных списков, где каждая цифра числа хранится в узле списка в обратном порядке (например, число 465 представлено как список [5, 6, 4]). Нужно сложить эти два числа и вернуть результат также в виде связанного списка, где цифры результата снова будут расположены в обратном порядке.
Ошибка в исходном решении:
В твоем коде ты сначала преобразуешь связанные списки в строки, затем переворачиваешь их, преобразуешь обратно в числа, складываешь их и затем обратно создаешь связанный список. Однако такая стратегия может привести к ошибкам:
- Если числа большие, то может возникнуть переполнение при работе с большими числами, что и вызывает неправильные результаты, как, например,
-8
- Преобразование в строки и обратно не подходит для сложения очень длинных чисел (как в случае с
l1
, где много нулей и единицы в начале и конце).
Решение
Чтобы избежать проблем с переполнением, мы будем складывать числа побитно, то есть цифра к цифре, с учетом переноса (если сумма двух цифр превышает 9).
Как работает решение:
- Создаем вспомогательный узел (dummy node): Мы создаем фиктивный узел dummy, который будет указывать на начало нового списка, где будет храниться результат.
- Проходим по обоим спискам одновременно: Мы начинаем проходить по обоим связанным спискам, начиная с самой младшей цифры каждого числа (поскольку числа хранятся в обратном порядке).
-
Если один из списков короче другого, мы просто считаем недостающие цифры как
javascript 0
. * Складываем соответствующие цифры и добавляем к ним значение переноса (
javascript carry
), если оно есть. 3. Обрабатываем перенос (carry): Если сумма двух цифр больше 9, то перенос (единица) передается на следующую итерацию. Например, если складываем 6 и 7, получаем 13, записываем в текущий узел 3, а 1 (перенос) передаем на следующий шаг. 4. Продолжаем до конца списков: Мы продолжаем суммировать, пока не обработаем все цифры из обоих списков. Если по завершении работы над обоими списками у нас остался перенос, добавляем новый узел с этим значением. 5. Возвращаем результат: Так как результат хранится в узлах, начиная с фиктивного узла dummy, конечный результат — это список, который начинается с dummy->next.
Пример:
Возьмем два числа:
- l1 =
[1, 0, 0, 0, ..., 0, 1]
(очень большое число), - l2 =
[5, 6, 4]
(число 465).
Складываем их:
- Сначала складываем младшие цифры: 1 + 5 = 6 (записываем 6 в результат).
- Далее: 0 + 6 = 6 (записываем 6).
- Далее: 0 + 4 = 4 (записываем 4).
- Остальные цифры — это нули, и в конце списков добавляется 1 из первого числа.
Итого: результат будет [6, 6, 4, 0, 0, ..., 0, 1].
Код:
<?php
class ListNode {
public $val = 0;
public $next = null;
function __construct($val = 0, $next = null) {
$this->val = $val;
$this->next = $next;
}
}
class Solution {
/**
* @param ListNode $l1
* @param ListNode $l2
* @return ListNode
*/
function addTwoNumbers($l1, $l2) {
$dummy = new ListNode(0);
$current = $dummy;
$carry = 0;
while ($l1 !== null || $l2 !== null || $carry !== 0) {
$x = ($l1 !== null) ? $l1->val : 0;
$y = ($l2 !== null) ? $l2->val : 0;
$sum = $x + $y + $carry;
$carry = intdiv($sum, 10);
$current->next = new ListNode($sum % 10);
$current = $current->next;
if ($l1 !== null) $l1 = $l1->next;
if ($l2 !== null) $l2 = $l2->next;
}
return $dummy->next;
}
}
\