📌 문제
- 파이썬 알고리즘 인터뷰 60번 문제
- 연결리스트를 "삽입 정렬"을 사용해 정렬하라.
📌 날짜
2020.02.26
📌 시도 횟수
책 보고 이해함ㅠ / Failed
💡 Code
class Solution:
def insertionSortList(self, head: ListNode) -> ListNode:
cur = parent = ListNode(0)
while head:
while cur.next and cur.next.val < head.val:
cur = cur.next
cur.next, head.next, head = head, cur.next, head.next
cur = parent
return parent.next
💡 문제 해결 방법
- 문제 해결 과정은 아래와 같다.
- cur은 정렬이 완료된 연결 리스트를 가리킨다.
- parent는 "항상" 정렬이 완료된 연결리스트의 루트를 가리킨다.
- head는 정렬을 해야 될 현재 노드를 가리킨다.
1. 정렬되어야 할 현재 노드는 head이다.
2. 이미 정렬된 연결 리스트(cur)에 head가 어디 들어가야 할 지 찾아야 한다.
3. cur은 정렬된 연결리스트를 맨 앞부터 차례대로 순회하면서
cur.next가 head보다 값이 커지는 경우에서 스톱한다.
4. 만약 cur.next.val > head.val인 경우를 찾으면,
> cur.next, head.next, head = head, cur.next, head.next
를 통해 head를 정렬된 연결리스트에 삽입하고 head를 새로운 head로 갱신한다.
⭐반드시 *다중할당*으로 처리해야 된다. 그렇지 않으면 recursion error가 뜸⭐
5. cur을 다시 정렬된 연결리스트 맨 앞으로 옮기고 1~5를 반복한다.
💡 새롭게 알게 된 점
> cur.next, head.next, head = head, cur.next, head.next
다중할당으로 처리해야 recursion error이 뜨지 않음을 알게 되었다.
가독성이 떨어지지만 다중할당으로 처리하는 이유가 있었다. (p.211 참고)
❌ (한번에 맞추지 못한 경우) 오답의 원인
✔ 더 생각할 점
- 원래 삽입 정렬은 현재 값에 대하여 현재 값의 왼쪽 값인 (가장 큰값)부터 시작하여
차례대로 (큰 값 -> 작은 값) 왼쪽 방향으로 내려가며 삽입 위치를 찾는다.
- 그러나, 연결리스트의 경우 무조건 순차적으로 순회해야 하기 때문에
큰값에서 작은값으로 거꾸로 거슬러 내려가는 것이 사실상 불가능하다.
- 그렇다면 어떻게 기존 삽입 정렬만큼의 효율을 낼 수 있을까?
😉 다른 풀이
📌 하나. 위의 풀이의 비효율성을 고친 풀이
class Solution:
def insertionSortList(self, head: ListNode) -> ListNode:
cur = parent = ListNode(0)
while head:
while cur.next and cur.next.val < head.val:
cur = cur.next
cur.next, head.next, head = head, cur.next, head.next
if head and cur.val > head.val:
cur = parent
return parent.next
💡 문제 해결 방법
- cur의 갱신을 꼭 필요한 경우에만 실행시킴으로써 불필요한 연산을 최소화했다.
- cur.val이 새롭게 삽입해야할 head의 head.val보다 값이 작은 경우
굳이 cur을 맨 앞(가장 작은 값)으로 갱신할 필요가 없다.
- 우리가 찾고자 하는 것은 cur이 언제 "처음" head.val보다 값이 "커지느냐"이기 때문이다.
💡 새롭게 알게 된 점
- 코드의 비효율성을 줄이는 방법을 고려해볼 수 있었다.