diff --git a/linked-list-cycle/radiantchoi.swift b/linked-list-cycle/radiantchoi.swift new file mode 100644 index 0000000000..cef32a6d93 --- /dev/null +++ b/linked-list-cycle/radiantchoi.swift @@ -0,0 +1,79 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * } + * } + */ + +// 1차 버전: 문제의 constraint에 따라 1만 번의 traverse를 수행하는 답안 (통과는 됩니다) +class Solution { + func hasCycle(_ head: ListNode?) -> Bool { + guard let head else { return false } + + return traverse(head, 0) + } + + func traverse(_ node: ListNode?, _ currentIndex: Int) -> Bool { + guard let node else { return false } + guard currentIndex < 10000 else { return true } + + return traverse(node.next, currentIndex + 1) + } +} + +// LLM 첨삭 버전: Floyd's Cycle Detection Algorithm 사용 +class Solution { + func hasCycle(_ head: ListNode?) -> Bool { + guard let head else { return false } + + var slow: ListNode? = head + var fast: ListNode? = head + + while true { + // fast는 한 번에 두 칸씩 이동 + fast = fast?.next?.next + + // slow는 한 번에 한 칸씩 이동 + slow = slow?.next + + // fast나 slow가 nil이면 cycle이 없다 + if fast == nil || slow == nil { return false } + + // fast와 slow가 같은 노드를 가리키면 cycle이 있다 + // break로 마무리한 이유는, 그래서 그 만나는 노드가 어디인가? 라는 문제에 응용하기 위함 + if fast === slow { break } + } + + // 사이클 시작 지점을 찾는 문제일 경우 여기에 entry 포인터 삽입 후 탐색 + + return true + } +} + +/* +사이클 시작 지점을 찾으시오, 라는 문제일 경우? +entry라는 별도의 포인터를 하나 더 둔 다음 slow와 함께 한 칸씩 이동시킨다. +두 포인터가 만나는 지점이 사이클 시작 지점! +이것이 가능한 이유는, 아래의 이동 거리 공식 때문에 그렇다. + +L: 사이클 입구까지의 길이 +C: 사이클 길이 +d: 사이클 내에서, 사이클 종료(==시작)까지 남은 거리 + +fast의 이동 거리: L + n * C + d +slow의 이동 거리: L + d + +fast의 이동 거리는 slow의 이동 거리의 2배이므로 +2 * (L + d) = L + n * C + d + +따라서, L = n * C - d 이다. +그리고 L은 entry 포인터가 이동해야 하는 거리이다. +n * C - d는 사이클 안에서는 C - d와 같다. fast 노드가 n번 돌았을 뿐, 사이클 안이었기 때문. +따라서 entry 포인터와 slow 포인터를 다시 한 칸씩 이동시키다 보면, 반드시 만나게 된다. +이 만나는 지점이 사이클 시작 지점. +*/ diff --git a/pacific-atlantic-water-flow/radiantchoi.swift b/pacific-atlantic-water-flow/radiantchoi.swift new file mode 100644 index 0000000000..1bd47c8f51 --- /dev/null +++ b/pacific-atlantic-water-flow/radiantchoi.swift @@ -0,0 +1,49 @@ +// 힌트를 받은 아이디어: 특정 칸에서 흘러내려가는 것이 아니라, 바다에서부터 거슬러 올라가는 것을 계산하면 어떨까? + +class Solution { + func pacificAtlantic(_ heights: [[Int]]) -> [[Int]] { + var result = [[Int]]() + var pacificMap = Array(repeating: Array(repeating: false, count: heights[0].count), count: heights.count) + var atlanticMap = Array(repeating: Array(repeating: false, count: heights[0].count), count: heights.count) + + for k in 0..= previous else { return } + guard !reachabilities[row][col] else { return } + + reachabilities[row][col] = true + + traverse(heights, row - 1, col, heights[row][col], &reachabilities) + traverse(heights, row + 1, col, heights[row][col], &reachabilities) + traverse(heights, row, col - 1, heights[row][col], &reachabilities) + traverse(heights, row, col + 1, heights[row][col], &reachabilities) + } +}