본문 바로가기
🐣 알고리즘

[프로그래머스] Swift - 구명보트 (LV.2)

by @Eddy 2024. 6. 6.
728x90

👆문제풀러 가기👆

문제 설명

 

무인도에 갇힌 사람들을 구명보트를 이용하여 구출하려고 합니다. 구명보트는 작아서 한 번에 최대 2명씩 밖에 탈 수 없고, 무게 제한도 있습니다.

예를 들어, 사람들의 몸무게가 [70kg, 50kg, 80kg, 50kg]이고 구명보트의 무게 제한이 100kg이라면 2번째 사람과 4번째 사람은 같이 탈 수 있지만 1번째 사람과 3번째 사람의 무게의 합은 150kg이므로 구명보트의 무게 제한을 초과하여 같이 탈 수 없습니다.

구명보트를 최대한 적게 사용하여 모든 사람을 구출하려고 합니다.

사람들의 몸무게를 담은 배열 people과 구명보트의 무게 제한 limit가 매개변수로 주어질 때, 모든 사람을 구출하기 위해 필요한 구명보트 개수의 최솟값을 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • 무인도에 갇힌 사람은 1명 이상 50,000명 이하입니다.
  • 각 사람의 몸무게는 40kg 이상 240kg 이하입니다.
  • 구명보트의 무게 제한은 40kg 이상 240kg 이하입니다.
  • 구명보트의 무게 제한은 항상 사람들의 몸무게 중 최댓값보다 크게 주어지므로 사람들을 구출할 수 없는 경우는 없습니다.

Swift로는 풀 수 없도록 설정되어 있는 문제인데, 그냥.. 풀었다. Programmers.. 이정도는 해 줄 수 있잖아..?

문제 분류는 기본적으로 Greedy이다. 근데 투포인터를 처음 공부하는 사람들에게 나쁘지않은 문제라고 생각된다.

간단한 조건만으로 투포인터를 구현할 수 있기에..

 

풀이

func solution(_ people: [Int], _ limit: Int) -> Int {
    var boat = 0
    var people = people.sorted(by: >)
    var result = [Int]()

    while !people.isEmpty {
        let heavyWeight = people.removeFirst() // 현재 가장 무거운 사람
        boat += heavyWeight                    // 보트에 탑승

        if let lightWeight = people.last, lightWeight+boat <= limit { // 가장 가벼운 사람이 함께 탈 수 있다면
            boat += people.removeLast()  // 함께 보트에 탑승
        }

        result.append(boat) // 떠나보낸 보트
        boat = 0            // 사람들이 보트에서 내렸으므로 초기화
    }

    return result.count
}

이 문제를 greedy로 풀면서 의문이었던 점은, 가장 무거운 사람과, 함께 탑승할 수 있는 사람 중 가장 무거운 사람을 함께 보트에 태우는 게 가장 효율적이지 않나? 였다.

하지만 시간효율상으로는 그렇게 풀면 틀릴 것이기 때문에, 위처럼 풀게 되었는데

생각해보면, 굳이 같이 탈 사람 중 무거운 사람을 찾을 필요가 있나.. 라는 생각이 든다.

 

왜냐면, 풀이는 다음과 같다.

  1. 가장 무거운사람 -> 가장 가벼운 사람 순으로 정렬을 하고
    • 무거운 사람부터 정렬하는 이유는, 이 사람과 함께 탑승 가능한 사람이 있는지 확인하기 편리하기 때문이다. 함께 탑승 못하면 혼자 타야한다.
  2. 가장 무거운 사람부터 보트에 태운다.
  3. 가장 무거운 사람이 가장 가벼운 사람과 함께 탑승할 수 있다면, 보트는 2명이서 운행이 가능하다.
    • 하지만, 함께 탑승할 수 없다면 보트는 가장 무거운 사람 혼자 타야한다.
    • 만약, 가장 무거운 사람과 함께 탈 가장 무거운 사람을 찾으려 했다면, 전체 배열을 탐색하는 비효율이 발생한다.
  4. 가장 무거운 사람이 배열에서 사라지면, 가장 무거운 사람보다 조금 가벼운 사람이 다음 순서이다.
    • 반대로, 가장 가벼운 사람이 위에서 보트를 탔다면, 그보다는 조금 무거운 사람이 다음 순서가 된다.
    • 따라서 배열은 무거운 순으로 정렬되어 있기 때문에, 오른쪽으로 갈수록 가벼워지고, 왼쪽으로 갈 수록 무거워진다.
  5. 위의 특징을 가지기 때문에 보트를 계속 타도 (어느정도) 무게가 상쇄가 된다.

최대한 보트에 꽉꽉 채워야 한다. 라고 했다면 풀이가 달라졌을지도 모르겠다.

 

 

다른 풀이

// 투포인터 풀이
func solution2(_ people: [Int], _ limit: Int) -> Int {
    var with = 0 // 함께 탑승한 보트 갯수
    var people = people.sorted(by: >)
    var left = 0
    var right = people.endIndex-1

    while left < right {
        if people[left] + people[right] <= limit { // 무겁고, 가벼운 사람이 함께 타도 된다면
            with += 1   // 함께 탄 보트 갯수 카운트
            right -= 1  // 가벼운 사람 보트 동승
        }
        left += 1  // 무거운 사람은 항상 탑승
    }


    return people.count - with // 인당 1대의 보트를 탔다고 가정하고, 함께 탄 사람 수 빼기
}

 

반응형

댓글