Description

每艘船最多載兩人,且有重量上限 limit。給定每個人的體重 people,回傳載完所有人所需的最少船數。

Example:

Input: people = [3,2,2,1], limit = 3 Output: 3([1,2], [2], [3])

Intuition#

核心思路:排序後,最重的人嘗試與最輕的人配對上同一艘船。若無法配對,最重的人獨自一船。

  • 貪心策略:讓最重的和最輕的配對,能省一艘船就省
  • 排序後用左右指針,若 people[left] + people[right] <= limit 則配對成功,兩人一船
  • 每輪無論是否配對,right 都會減一(最重的人一定會上船)

Approaches#

1: 排序 + 逐一配對(Brute Force 思維)#

  • 概念: 排序後嘗試為每個人找配對,用 visited 標記
  • 時間複雜度: O(n²) - 最差每人掃一遍
  • 空間複雜度: O(n) - visited 陣列
Brute Force 程式碼
class Solution {
    fun numRescueBoats(people: IntArray, limit: Int): Int {
        people.sort()
        val used = BooleanArray(people.size)
        var boats = 0
        for (i in people.indices.reversed()) {
            if (used[i]) continue
            used[i] = true
            boats++
            for (j in 0 until i) {
                if (!used[j] && people[j] + people[i] <= limit) {
                    used[j] = true
                    break
                }
            }
        }
        return boats
    }
}

⭐2: 排序 + Two Pointers 貪心#

  • 概念: 排序後左右指針,嘗試配對最輕和最重的人
  • 時間複雜度: O(n log n) - 排序主導
  • 空間複雜度: O(1) - 原地排序
class Solution {
    fun numRescueBoats(people: IntArray, limit: Int): Int {
        people.sort()
        var left = 0
        var right = people.size - 1
        var boats = 0

        while (left <= right) {
            if (people[left] + people[right] <= limit) {
                left++ // 最輕的人也上船
            }
            right-- // 最重的人一定上船
            boats++
        }
        return boats
    }
}

注意迴圈條件是 left <= right(包含等號),因為最後一個人自己也需要一艘船。

🔑 Takeaways#

  • Pattern: 排序 + 相向雙指針 + 貪心配對
  • 關鍵技巧: 每艘船最多兩人的限制讓貪心配對最輕和最重成為最佳策略;right 每輪必減代表最重的人必定安排