오늘부터는 본격적으로 연결 리스트의 medium 레벨의 문제를 풀려고 합니다.
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 contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example 1:
Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807.
Example 2:
Input: l1 = [0], l2 = [0]
Output: [0]
Example 3:
Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]
Constraints:
[1, 100]
.0 <= Node.val <= 9
개인적으로 해당 문제를 이해하는데 조금 걸렸습니다. 오히려 예시 설명이 더 헷갈렸습니다.. 쉽게 보자면 다음과 같습니다.
두 개의 non-empty 연결 리스트가 주어집니다. 주어진 두 개의 연결 리스트를 더한 결과를 새로운 연결 리스트로 반환하는 문제입니다.
말 그대로 두 개의 연결 리스트 l1과 l2가 [2, 4, 3], [5, 6, 4]가 있으면 각 자리숫자를 더한 값을 연결 리스트로 나타내면 됩니다. 합이 10이 넘어가면 나머지를 다음 노드에 넘겨주면 됩니다.
이제 문제 입출력을 살펴보도록 하겠습니다.
첫 번째 예시를 살펴보겠습니다.
2와 5를 더하면 7, 4와 6을 더하면 10이며 10은 노드 값이 될 수 없습니다. 그렇기 때문에 나머지를 노드값, 몫을 다음 노드에 추가합니다. 그렇다면 두 번째 노드 값은 0, 세 번째 노드 값은 1 + 3 + 4로 8이나옵니다. 즉, 결과는 [7, 0, 8] 이 나오게 됩니다.
두 연결 리스트를 순회하면서 위처럼 구현하면 충분히 해결될 것으로 보입니다.
그럼 코드 설계를 하러 가볼까요?
Step2에서 사용했던 예시를 아래처럼 표현해보았습니다.
초기화는 다음과 같이 진행합니다
이것을 기반으로 코드 구현을 진행하도록 하겠습니다. 그런데 이 방법은 두 개의 연결 리스트를 반복문을 통해 순회하면서 진행합니다. 이는 재귀로도 가능할 것으로 보입니다.
carry
: 자리 올림 값을 저장.dummy
: 새 연결 리스트를 구성할 더미 노드.curr
: 현재 노드를 가리키는 포인터.l1
, l2
)의 노드를 순회하며 자리수를 더함.carry
)를 계산하여 다음 노드에 반영.carry
)이 없으면 종료.val1
, val2
및 carry
포함).l1
, l2
의 다음 노드 및 carry
를 재귀 호출에 전달.따라서, 코드는 두 가지로 진행하도록 하겠습니다.
반복문
# Definition for singly-linked list.
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
# 1. Linked List
def addTwoNumbers(self, l1, l2):
# https://leetcode.com/problems/add-two-numbers/submissions/1469870730/
"""
:type l1: Optional[ListNode]
:type l2: Optional[ListNode]
:rtype: Optional[ListNode]
"""
dummy = ListNode() # 더미 노드 생성
curr = dummy # 현재 노드 포인터
carry = 0 # 올림 값 초기화
# l1, l2 또는 carry가 존재하는 동안 반복
while carry or l1 or l2:
if l1:
carry += l1.val
l1 = l1.next # l1의 다음 노드로 이동
if l2:
carry += l2.val
l2 = l2.next # l2의 다음 노드로 이동
# 현재 자리수 계산 및 연결
curr.next = ListNode(carry % 10) # 자릿수 값 생성
carry //= 10 # 올림값 업데이트
# 다음 노드로 이동
curr = curr.next
# 결과로 더미 노드의 다음 노드 반환
return dummy.next
dummy
와 curr
로 새로운 연결 리스트를 만듭니다.while
반복문에서 두 리스트와 자리 올림(carry
)을 모두 처리.재귀
# Definition for singly-linked list.
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
def addTwoNumbers(self, l1, l2,carry=0):
# https://leetcode.com/problems/add-two-numbers/submissions/1469872346
"""
:type l1: Optional[ListNode]
:type l2: Optional[ListNode]
:rtype: Optional[ListNode]
"""
# base case
if not l1 and not l2 and carry == 0:
return None
val1 = l1.val if l1 else 0
val2 = l2.val if l2 else 0
total = val1 + val2 + carry
node = ListNode(total % 10)
node.next = self.addTwoNumbers(
l1.next if l1 else None,
l2.next if l2 else None,
total // 10
)
return node
l1
, l2
가 없고 자리 올림이 없을 때.이번 문제는 두 연결 리스트를 더하는 방식으로, 반복문과 재귀를 모두 사용해 풀 수 있었습니다. 자리 올림(carry) 처리와 각 노드 값을 더한 결과를 새 연결 리스트로 만드는 과정이 핵심이었습니다.
추후 비슷한 문제에서 두 방식을 모두 활용할 수 있을 것입니다!
전체 코드는 다음 링크에서 확인할 수 있습니다.
읽어주셔서 감사합니다!
연결 리스트는 정말 어렵다!! 하지만 난 할 수 있다!