linked list 뒤집는 방법
방법1)
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev = None
cur = head
while cur is not None:
nextNode = cur.next
cur.next = prev
prev = cur
cur = nextNode
return prev
방법2) recursive 재귀
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head
reversedSublist = self.reverseList(head.next)
head.next.next = head
head.next = None
return reversedSublist
방법3) 기존 head노드를 점점 뒤로 옮기면서 currentHead 갱신하는 방법
아래는 C++ template
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == NULL) {
return head;
}
ListNode* currentHead = head;
while (head->next) {
ListNode* p = head->next;
head->next = p->next;
p->next = currentHead;
currentHead = p;
}
return currentHead;
}
};
처음쓴 코드)
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
prev = None
cur = head
while cur:
if cur.val == val:
if prev is None:
head = cur.next
prev = None
else:
prev.next = cur.next
else:
prev = cur
cur = cur.next
return head
일반적인 linked list 노드의 deletion은 prevode.next = curnode.next 라는 논리로 쉽게 해결이 된다.
다음에 설명할 내용에서는 sentinel node를 pseudo-head로 사용해서 모든 case를 standard하게 처리하고자 한다.
sentinel 사용 코드)
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
sentinel = ListNode(0)
sentinel.next = head
prev = sentinel
cur = head
while cur:
if cur.val == val:
prev.next = cur.next
else:
prev = cur
cur = cur.next
return sentinel.next
처음풀었을때는 linked list내의 cycle로 인해 실패했다. cycle은 짝수번째 노드의 끝이 null로 끝나지 않아서 생긴 문제였다.
풀이를 보니 odd node를 기준으로 뒤에 even과 even.next(즉, odd의 next가 될 노드)만 존재하지는에 따라 while문을 돌려주면 내가 생각한 조건보다도 훨씬 간단해졌다.
내가 복잡하게 생각한 이유는 null의 next를 접근하려는 오류를 막으려고 그런것인데 odd를 기준으로 even과 even.next가 있다면 even.next.next 접근이 에러가 나지 않을 것이므로 간단해진다.
또한 1->2->3->4->5->null, 1->2->3->4->null 이므로 odd를 기준으로 while문을 작성한다면
전자의 경우는 odd가 3일때, 4는 even.next.next가 null이라서 4->null이 되고,
후자의 경우는 애초에 4->null이므로 odd가 3일때 even->next가 null이라서 while문이 돌아가지 않더라도 내가 범했던 문제(짝수번째 노드 끝이 null로 끝나지 않아서 cycle이 생김)를 해결하게 된다.
그래서 정답은 아래와 같다.
class Solution:
def oddEvenList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:
return head
odd = head
even = head.next
even_head = head.next
while even and even.next:
odd.next = odd.next.next
odd = odd.next
even.next = even.next.next
even = even.next
odd.next = even_head
return head
아이디어는 linked list의 절반지점을 slow와 fast runner방식으로 찾은 뒤, 절반의 뒤쪽에 해당하는 list를 뒤집어서 앞의 list 절반과 비교하는 것이다.
처음 푼 코드)
class Solution:
def flip(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None:
return head
currHead = head
while head.next:
p = head.next
head.next = p.next
p.next = currHead
currHead = p
return currHead
def isPalindrome(self, head: Optional[ListNode]) -> bool:
sentinel = ListNode(0)
sentinel.next = head
slow = sentinel
fast = sentinel
if head.next is None:
return True
#리스트 절반지점 찾기
while fast and fast.next:
slow = slow.next
fast = fast.next.next
#절반 뒤쪽 list 뒤집기
reversedList = self.flip(slow.next)
#그냥 깔끔함을 위해 linked list 2개 분리시킴.
#아래 줄은 없어도 되긴함. slow.next접근할 일이 없어서.
slow.next = None
while reversedList:
if reversedList.val == head.val:
reversedList = reversedList.next
head = head.next
else:
return False
return True
꺄 누나 멋있어요