๐Ÿ’ซ ETC/Leetcode

Week 2-2. [Divide & Conquer] 148. Sort List (Python3)

ming412 2023. 9. 4. 23:49

๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •

โœ๏ธ ๋‚˜๋งŒ์˜ ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ ์ •๋ฆฌํ•˜๊ธฐ (=์ฒด๊ณ„ํ™”)

https://leetcode.com/problems/sort-list/?envType=study-plan-v2&envId=top-interview-150 

 

Sort List - LeetCode

Can you solve this real interview question? Sort List - Given the head of a linked list, return the list after sorting it in ascending order.   Example 1: [https://assets.leetcode.com/uploads/2020/09/14/sort_list_1.jpg] Input: head = [4,2,1,3] Output: [1,

leetcode.com

์ฃผ์–ด์ง„ ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ๋ฅผ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๋ผ.
  • ๋ฌธ์ œ์— ์ฃผ์–ด์ง„ ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ํƒ€์ž…์€ Optional[ListNode]์ด๋‹ค.
    • ์ด๋Ÿด ๋•Œ๋Š” dummy node๋ฅผ ์„ ์–ธํ•˜๊ณ  ๊ทธ dummy node์˜ next๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋œ๋‹ค.
  • ๋…ธ๋“œ ๊ฐœ์ˆ˜์˜ ๋ฒ”์œ„๋Š” [0, 5*10^4]์ด๋‹ค.
  • ๋…ธ๋“œ์˜ ๊ฐ’์˜ ๋ฒ”์œ„๋Š” [-10^5, 10^5]์ด๋‹ค.

 

๐Ÿ”Ž ์–ด๋–ค ์‹์œผ๋กœ ์ ‘๊ทผํ–ˆ๋Š”๊ฐ€?

์ฃผ์–ด์ง„ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํšŒํ•˜์—ฌ ์š”์†Œ๋ฅผ ๋ฆฌ์ŠคํŠธ์— ๋‹ด๊ณ , ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌํ•œ ๋’ค ๋‹ค์‹œ ๋…ธ๋“œ๋กœ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

๐Ÿ™ˆ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ ํƒ: ์ž…๋ ฅ์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ

linear search์™€ sort๋ฅผ ์ด์šฉํ•œ๋‹ค. ์ž…๋ ฅ์˜ ์ตœ๋Œ€๊ฐ€ 5*10^4

 

๐Ÿ“ ์˜์‚ฌ ์ฝ”๋“œ

lst = []
head๊ฐ€ None์ด ์•„๋‹Œ ๋™์•ˆ:
	head.val ๊ฐ’์„ lst์— ์ถ”๊ฐ€ํ•œ๋‹ค.
    
lst๋ฅผ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌํ•œ๋‹ค.

ans = cur = ListNode(-1)
x๋กœ lst์˜ ์›์†Œ๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ:
	cur.next = ListNode(x)
    cur = cur.next

 

๐ŸŽฏ ๊ตฌํ˜„ ์ฝ”๋“œ

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        lst = []
        while head:
            lst.append(head.val)
            head = head.next
        lst.sort()

        # ans: ์ •๋ ฌ๋œ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ
        # cur: ํ˜„์žฌ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋ ๋ถ€๋ถ„์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ
        ans = cur = ListNode(-1) # dummy(-1)๋กœ ์ดˆ๊ธฐํ™”
        for x in lst:
            cur.next = ListNode(x)
            cur = cur.next

        return ans.next

 

๋‚ด ์ฝ”๋“œ๋ฅผ ํƒ๊ตฌํ•ด๋ณด๊ธฐ

โฑ ์„ฑ๋Šฅ ์ธก์ • (์‹œ๊ฐ„๋ณต์žก๋„/๊ณต๊ฐ„๋ณต์žก๋„)

linear search(O(n))์™€ sort(O(n log n))๋ฅผ ์ด์šฉํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ „์ฒด ์ฝ”๋“œ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(n log n)์ด๋‹ค.

 

โœ๏ธ ์„ฑ๋Šฅ ํšŒ๊ณ 

1์ดˆ ์ œํ•œ์—์„œ O(n log n)์˜ ์ตœ๋Œ€ ์ž…๋ ฅ์€ 10^6~10^7์ด๋‹ค. ๋ฌธ์ œ์—์„œ๋Š” ์ตœ๋Œ€ ์ž…๋ ฅ์ด 5*10^4์ด๋ฏ€๋กœ ์„ฑ๋Šฅ์€ ๊ดœ์ฐฎ๋‹ค.

 

๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ์ฝ”๋“œ๋ฅผ ํƒ๊ตฌํ•ด๋ณด๊ธฐ

๐ŸŽฏ ๊ตฌํ˜„ ์ฝ”๋“œ

  • ์ œ์•ฝ์กฐ๊ฑด์„ ๊ณ ๋ คํ–ˆ์„ ๋•Œ ์•ˆ์ •์ ์œผ๋กœ O(nlogn)์˜ ์‹œ๊ฐ„์„ ๋ณด์žฅํ•˜๋Š” ๋ณ‘ํ•ฉ์ •๋ ฌ์„ ํ™œ์šฉํ•˜์ž.
  • ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ๋Š” ์ „์ฒด ๊ธธ์ด๋ฅผ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋Ÿฐ๋„ˆ ๊ธฐ๋ฒ•์„ ํ™œ์šฉํ•จ์„ธ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด, ํ•˜๋‚˜์˜ ๋ณ€์ˆ˜๋Š” ํ•œ ์นธ์”ฉ, ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋Š” ๋‘ ์นธ์”ฉ ์ด๋™ํ•˜๋„๋ก ํ•˜๋ฉด, ๋‘ ์นธ์”ฉ ์ด๋™ํ•œ ๋ณ€์ˆ˜๊ฐ€ ๋ฆฌ์ŠคํŠธ ๋์— ๋‹ฟ์„ ๋•Œ, ํ•œ ์นธ์”ฉ ์ด๋™ํ•œ ๋ณ€์ˆ˜๋Š” ์ค‘๊ฐ„์— ๋„๋‹ฌํ•  ๊ฒƒ
  • merge ๊ณผ์ •์€ ๋งŒ์•ฝ ๋‘ ListNode๊ฐ€ ์กด์žฌํ•˜๋ฉด ๊ฐ’์ด ์ž‘์€ ์ชฝ์ด l1์œผ๋กœ ๊ฐ€๊ฒŒ๋” ์น˜ํ™˜ํ•˜๊ณ  l1.next์— ๋Œ€ํ•ด ์žฌ๊ท€ํ˜ธ์ถœํ•˜์—ฌ ํ•œ์ชฝ ListNode๊ฐ€ None์ด ๋  ๋•Œ๊นŒ์ง€ ํ˜ธ์ถœํ•œ๋‹ค. ์ดํ›„ ๋ณ‘ํ•ฉ๋œ ํ˜•ํƒœ์˜ ListNode๊ฐ€ ๋ฐ˜ํ™˜๋˜๋ฉด ์žฌ๊ท€๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค.
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not (head and head.next): return head
    
        # ๋Ÿฐ๋„ˆ ๊ธฐ๋ฒ• ํ™œ์šฉ
        half, slow, fast = None, head, head
        while fast and fast.next:
            half, slow, fast = slow, slow.next, fast.next.next # slow๋Š” 1์นธ, fast๋Š” 2์นธ ์ด๋™
        half.next = None # ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ ์—ฐ๊ฒฐ ๋Š๊ธฐ
        
        # ๋ถ„ํ•  ์žฌ๊ท€ ํ˜ธ์ถœ
        l1 = self.sortList(head)
        l2 = self.sortList(slow) # half๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋Š์€ ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ
        
        return self.mergeTwoLists(l1, l2)

    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if (not l1) or (l2 and l1.val > l2.val):
            l1, l2 = l2, l1
        if l1: l1.next = self.mergeTwoLists(l1.next, l2)
        
        return l1

 

โฑ ์„ฑ๋Šฅ ์ธก์ • (์‹œ๊ฐ„๋ณต์žก๋„/๊ณต๊ฐ„๋ณต์žก๋„)

์ •๋ ฌ ์—ฐ์‚ฌ์˜ ์‹œ๊ฐ„๋ณต์žก๋„์— ์˜ํ•ด ๊ฒฐ์ •๋œ๋‹ค. ์ •๋ ฌ ์—ฐ์‚ฐ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋Š” ์ตœ์†Œ O(n log n)์ด๋‹ค.

 

๋А๋‚€ ์ 

๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์—์„œ ๋ณ‘ํ•ฉ ์ •๋ ฌ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์•„์ง์€ ๋‚ฏ์„ค์—ˆ๋‹ค. ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์—์„œ ๊ฐ’์„ ๊บผ๋‚ด ํŒŒ์ด์ฌ ๋‚ด์žฅํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ •๋ ฌํ•˜๋Š” ์ฝ”๋“œ๋Š” ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ์ง์ ‘ ๋ณ‘ํ•ฉ ์ •๋ ฌ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ• ๋˜ํ•œ ์•Œ์•„๋‘์–ด์•ผ๊ฒ ๋‹ค.

 

์ฐธ๊ณ  ์ž๋ฃŒ

[์•Œ๊ณ ๋ฆฌ์ฆ˜] Leetcode #148 ๋ฆฌ์ŠคํŠธ ์ •๋ ฌ (Python)

LeetCode #148 Sort List