오늘부터 LeetCode의 자료구조와 알고리즘 문제 풀이를 본격적으로 시작하려고 합니다. 첫 번째 파트는 Linked List 자료구조입니다.
Linked List는 단독으로는 많이 등장하지 않지만, 트리나 그래프 같은 고급 자료구조를 다룰 때 자주 활용되기 때문에 기본적으로 익혀두는 것이 중요합니다. 오늘 풀 문제는 Linked List의 정말 기초적인 문제로 보이지만, 막상 풀어보니 생각보다 많이 헷갈렸습니다. 역시 기본기를 더 단단히 다질 필요가 있음을 느꼈습니다. 😞
그럼, 오늘의 문제를 함께 살펴보겠습니다.
You are given the heads of two sorted linked lists list1
and list2
.
Merge the two lists into one sorted list. The list should be made by splicing together the nodes of the first two lists.
Return the head of the merged linked list.
Example 1:
Input: list1 = [1,2,4], list2 = [1,3,4]
Output: [1,1,2,3,4,4]
Example 2:
Input: list1 = [], list2 = []
Output: []
Example 3:
Input: list1 = [], list2 = [0]
Output: [0]
Constraints:
[0, 50]
.-100 <= Node.val <= 100
list1
and list2
are sorted in non-decreasing order.두 개의 오름차순의 링크드 리스트 list1과 list2가 있습니다. 이 두 개의 링크드 리스트를 하나의 오름차순으로 정렬된 연결 리스트로 병합하는 문제입니다.
그런데, 저는 시작부터 약간 멈칫하는 부분이 있었습니다. 문제의 마지막 문장입니다.
Return the head of the merged linked list.
저는 이 문장을 보고,, 어? 분명 병합된 연결 리스트를 반환하는거 아냐? 왜 head를 반환하는거지?
사실.. 이것은 제가 연결 리스트를 제대로 이해하지 않았다는 것을 의미합니다.
문제에서 head를 반환하라는 것은 단순히 병합된 연결 리스트의 시작 노드를 반환하라는 의미입니다. 연결 리스트는 노드들이 포인터를 통해 서로 연결된 구조이기 때문에, 연결 리스트 전체를 반환하는 대신, 첫 번째 노드(Head)만 반환하면 나머지 노드들도 접근할 수 있습니다.
연결 리스트에서 head
를 반환하는 이유
head
)를 통해 이후의 노드들에 접근할 수 있습니다.head
를 반환하면 추가 작업 없이 바로 연결 리스트를 사용할 수 있습니다.head
를 반환하는 것이 맞습니다.즉, 문제에서 "head를 반환하라"고 명시한 것은 연결 리스트의 구조적 특성을 활용해 병합된 리스트의 시작점을 반환하는 방식으로 리스트를 나타내기 위함입니다.
문제의 입출력과 제약 조건을 확인하겠습니다.
어느 정도 문제 이해가 완료되었습니다. 이제 문제 분석하러 가보시죠!
오름차순으로 정렬된 두 개의 연결리스트가 있습니다. 이 두 개의 연결리스트를 하나의 오름차순으로 정렬된 연결 리스트를 구하는 문제입니다.
그렇다면, 각 두 개의 연결리스트의 요소들을 서로서로 비교하면서 나아가면 되지 않을까요?
예를 들어, 아래와 같이 두 개의 연결 리스트가 있다고 가정하겠습니다(간단히 리스트로 표현하겠습니다).
list1 = [1,2,3]
list2 = [1,4,6]
list1과 list2는 연결 리스트로 표현한다면 다음과 같이 표현할 수 있습니다.
list1과 list2의 첫번째 요소는 같습니다. 그렇기 때문에 병합된 첫번째 노드는 1이 되겠죠? (head제외입니다)
그 다음은 2와 4입니다. 여기서 병합된 연결리스트는 2를 가리켜야 하겠죠? 이렇게 두 개의 연결 리스트의 요소를 비교하면서 더 작은 값을 이전 값의 next node로 설정하면 됩니다.
이것을 순서로 보이자면 다음과 같습니다.
문제 분석까지 완료되었습니다.
이렇게 진행한다면 시간 복잡도는 두 연결 리스트를 순회하기 때문에 O(len(list1) + len(list2))가 될 것으로 예상됩니다.
이제 코드를 설계하러 가볼까요?
해당 문제는 이렇게 두 연결리스트를 순회하면서 요소를 비교하면서 병합된 연결 리스트
반복문 설계
head
라는 빈 노드를 생성합니다.start
변수를 초기화하여 병합 작업을 진행합니다.list1
과 list2
를 모두 순회하며 값을 비교합니다.start.next
에 연결하고, 해당 리스트의 다음 노드로 이동합니다.start
포인터도 다음 노드로 이동합니다.head.next
를 반환하여 병합된 리스트의 시작점을 반환합니다.재귀 설계
list1
또는 list2
가 None
이면, 남아 있는 다른 리스트를 반환합니다.list1.val
과 list2.val
을 비교하여 더 작은 값을 가진 노드를 선택합니다.next
를 재귀적으로 호출하여 병합된 결과와 연결합니다.# 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 mergeTwoLists(self, list1, list2):
"""
:type list1: Optional[ListNode]
:type list2: Optional[ListNode]
:rtype: Optional[ListNode]
"""
head = ListNode()
start = head
while list1 and list2:
if list1.val < list2.val:
start.next = list1
list1 = list1.next
else:
start.next = list2
list2 = list2.next
start = start.next
if list1:
start.next = list1
if list2:
start.next = list2
return head.next
코드 설명:
head
라는 dummy 노드를 생성하여 병합된 리스트를 임시로 저장합니다.list1
과 list2
의 값을 비교하면서 순차적으로 병합 작업을 진행합니다.시간 복잡도:
list1
과 list2
의 노드 개수입니다.결과:
https://leetcode.com/problems/merge-two-sorted-lists/submissions/1465462206
# 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 mergeTwoLists(self, list1, list2):
"""
:type list1: Optional[ListNode]
:type list2: Optional[ListNode]
:rtype: Optional[ListNode]
"""
# base case
if list1 is None or list2 is None:
return list1 or list2
if list1.val < list2.val:
list1.next = self.mergeTwoLists(list1.next, list2)
return list1
else:
list2.next = self.mergeTwoLists(list1, list2.next)
return list2
코드 설명:
list1
이나 list2
가 비었을 때 남은 리스트를 반환합니다.next
를 재귀적으로 병합합니다.시간 복잡도:
결과:
https://leetcode.com/problems/merge-two-sorted-lists/submissions/1465462983
이번 문제는 Linked List의 기초 문제이지만, 반복문과 재귀를 모두 활용할 수 있는 좋은 예제였습니다.
두 가지 방식 모두 상황에 따라 적절히 사용할 수 있도록 익혀두는 것이 중요합니다. 앞으로 고급 자료구조를 다룰 때 연결 리스트를 활용하는 문제들이 자주 등장하니 기본기를 잘 다져둡시다! 🚀
다음 링크에는 실제 이 코드를 문제에서 주어진 리스트 형태의 입출력을 적용시킨 코드가 있습니다. 확인하시면 도움이 될 것입니다.
읽어주셔서 감사합니다!
Keep Going!!