[프로그래머스 LV3] 등산코스 정하기

Junyoung Park·2022년 9월 3일
0

코딩테스트

목록 보기
606/631
post-thumbnail

1. 문제 설명

등산코스 정하기

2. 문제 분석

다익스트라를 통해 출발지-산봉우리까지 가는 경로 중 비용의 최댓값을 기록한다. 다익스트라를 여러 번 돌리지 않고, 출발지로부터 시작하는 시작 노드를 우선순위 큐에 모두 넣은 채로 한 번만 돌린다.

3. 나의 풀이

import sys
import heapq

def solution(n, paths, gates, summits):
    INF = sys.maxsize
    nodes = [[] for _ in range(n+1)]
    summits_set = set(summits)
    for path in paths:
        node1, node2, cost = path
        nodes[node1].append([node2, cost])
        nodes[node2].append([node1, cost])
        
    pq = []
    distances = [INF for _ in range(n+1)]
    for gate in gates:
        heapq.heappush(pq, [0, gate])
        distances[gate] = 0
    
    while pq:
        cur_cost, cur_node = heapq.heappop(pq)
        if cur_cost > distances[cur_node]: continue
        
        for next_node, next_cost in nodes[cur_node]:
            total_cost = max(next_cost, cur_cost)
            if total_cost < distances[next_node]:
                distances[next_node] = total_cost
                if next_node not in summits_set:
                    heapq.heappush(pq, [total_cost, next_node])
    
    answer = [-1, INF]
    summits.sort()
    
    for summit in summits:
        if answer[1] > distances[summit]:
            answer = [summit, distances[summit]]
    return answer
import Foundation

struct PQ<T> {
    var nodes = [T]()
    let sort:(T, T) -> Bool
    
    init(sort: @escaping (T, T) -> Bool) {
        self.sort = sort
    }
    
    var isEmpty: Bool {
        return nodes.isEmpty
    }
    
    var count: Int {
        return nodes.count
    }
    
    func leftChild(from parentIndex: Int) -> Int {
        return parentIndex * 2 + 1
    }
    
    func rightChild(from parentIndex: Int) -> Int {
        return parentIndex * 2 + 2
    }
    
    func parentIndex(from child: Int) -> Int {
        return (child - 1) / 2
    }
    
    mutating func siftDown(from index: Int) {
        var parent = index
        while true {
            let left = leftChild(from: parent)
            let right = rightChild(from: parent)
            var candidate = parent
            if left < count && sort(nodes[left], nodes[candidate]) {
                candidate = left
            }
            
            if right < count && sort(nodes[right], nodes[candidate]) {
                candidate = right
            }
            
            if candidate == parent {
                return
            }
            
            nodes.swapAt(parent, candidate)
            parent = candidate
        }
    }
    
    mutating func siftUp(from index: Int) {
        var child = index
        var parent = parentIndex(from: child)
        while child > 0 && sort(nodes[child], nodes[parent]) {
            nodes.swapAt(child, parent)
            child = parent
            parent = parentIndex(from: child)
        }
    }
    
    mutating func pop() -> T? {
        guard !isEmpty else { return nil }
        nodes.swapAt(0, count-1)
        defer {
            siftUp(from: 0)
        }
        return nodes.removeLast()
    }
    
    mutating func push(_ element: T) {
        nodes.append(element)
        siftUp(from: count - 1)
    }
}

func solution(_ n:Int, _ paths:[[Int]], _ gates:[Int], _ summits:[Int]) -> [Int] {
    var nodes = Array(repeating: [(Int, Int)](), count: n+1)
    let summitsSet = Set(summits)
    for path in paths {
        let (node1, node2, cost) = (path[0], path[1], path[2])
        nodes[node1].append((node2, cost))
        nodes[node2].append((node1, cost))
    }
    
    func Dijkstra() -> [Int] {
        var pq = PQ<(Int, Int)>(sort: {$0.0 < $1.0})
        let INF = Int.max
        var distances = Array(repeating: INF, count: n+1)
        for gate in gates {
            pq.push((0, gate))
            distances[gate] = 0
        }
        
        while !pq.isEmpty {
            guard let curData = pq.pop() else { break }
            let curCost = curData.0
            let curNode = curData.1
            
            if distances[curNode] < curCost {
                continue
            }
            
            for nextData in nodes[curNode] {
                let nextNode = nextData.0
                let nextCost = nextData.1
                
                let totalCost = max(curCost, nextCost)
                if distances[nextNode] > totalCost {
                    distances[nextNode] = totalCost
                    if summitsSet.contains(nextNode) {
                        continue
                    }
                    pq.push((totalCost, nextNode))
                }
            }
        }
        return distances
    }
    let distances = Dijkstra()
    var answer = [Int.max, Int.max]
    for summit in summits {
        let distance = distances[summit]
        if answer[1] > distance {
            answer = [summit, distance]
        } else if answer[1] == distance {
            if answer[0] > summit {
                answer = [summit, distance]
            }
        }
    }
    return answer
}

파이썬과 동일한 로직으로 푼 스위프트 풀이. 하지만 마지막 테스트케이스인 25번에서 시간 초과를 해결하지 못했다. 커스텀 우선순위 큐를 사용해서 그런지.. 파이썬의 힙큐보다 시간 효율이 떨어진다. 어떻게 해야 풀릴까?

profile
JUST DO IT

0개의 댓글

관련 채용 정보