跳转至

1753. 移除石子的最大得分

题目描述

你正在玩一个单人游戏,面前放置着大小分别为 a​​​​​​、bc​​​​​​ 的 三堆 石子。

每回合你都要从两个 不同的非空堆 中取出一颗石子,并在得分上加 1 分。当存在 两个或更多 的空堆时,游戏停止。

给你三个整数 abc ,返回可以得到的 最大分数

示例 1:

输入:a = 2, b = 4, c = 6
输出:6
解释:石子起始状态是 (2, 4, 6) ,最优的一组操作是:
- 从第一和第三堆取,石子状态现在是 (1, 4, 5)
- 从第一和第三堆取,石子状态现在是 (0, 4, 4)
- 从第二和第三堆取,石子状态现在是 (0, 3, 3)
- 从第二和第三堆取,石子状态现在是 (0, 2, 2)
- 从第二和第三堆取,石子状态现在是 (0, 1, 1)
- 从第二和第三堆取,石子状态现在是 (0, 0, 0)
总分:6 分 。

示例 2:

输入:a = 4, b = 4, c = 6
输出:7
解释:石子起始状态是 (4, 4, 6) ,最优的一组操作是:
- 从第一和第二堆取,石子状态现在是 (3, 3, 6)
- 从第一和第三堆取,石子状态现在是 (2, 3, 5)
- 从第一和第三堆取,石子状态现在是 (1, 3, 4)
- 从第一和第三堆取,石子状态现在是 (0, 3, 3)
- 从第二和第三堆取,石子状态现在是 (0, 2, 2)
- 从第二和第三堆取,石子状态现在是 (0, 1, 1)
- 从第二和第三堆取,石子状态现在是 (0, 0, 0)
总分:7 分 。

示例 3:

输入:a = 1, b = 8, c = 8
输出:8
解释:最优的一组操作是连续从第二和第三堆取 8 回合,直到将它们取空。
注意,由于第二和第三堆已经空了,游戏结束,不能继续从第一堆中取石子。

 

提示:

  • 1 <= a, b, c <= 105

解法

方法一:贪心 + 模拟

每次贪心地从最大的两堆石子中取石头,直到至少有两堆石子为空。

时间复杂度 $O(n)$,其中 $n$ 为石子总数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution:
    def maximumScore(self, a: int, b: int, c: int) -> int:
        s = sorted([a, b, c])
        ans = 0
        while s[1]:
            ans += 1
            s[1] -= 1
            s[2] -= 1
            s.sort()
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
    public int maximumScore(int a, int b, int c) {
        int[] s = new int[] {a, b, c};
        Arrays.sort(s);
        int ans = 0;
        while (s[1] > 0) {
            ++ans;
            s[1]--;
            s[2]--;
            Arrays.sort(s);
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    int maximumScore(int a, int b, int c) {
        vector<int> s = {a, b, c};
        sort(s.begin(), s.end());
        int ans = 0;
        while (s[1]) {
            ++ans;
            s[1]--;
            s[2]--;
            sort(s.begin(), s.end());
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func maximumScore(a int, b int, c int) (ans int) {
    s := []int{a, b, c}
    sort.Ints(s)
    for s[1] > 0 {
        ans++
        s[1]--
        s[2]--
        sort.Ints(s)
    }
    return
}

方法二:贪心 + 数学

我们不妨设 $a \le b \le c$,那么:

  • 当 $a + b \le c$ 时,我们可以先从 $a$, $c$ 两堆中取石头,得到分数 $a$;再从 $b$, $c$ 两堆中取石头,得到分数 $b$,总分数为 $a + b$;
  • 当 $a + b \gt c$ 时,这时我们每次会从 $c$ 以及 $a$ 和 $b$ 中较大的那一堆中取石头,最终将 $c$ 取空。此时 $a$ 和 $b$ 的大小差最多为 $1$。我们再从 $a$, $b$ 两堆中取石头,直到不能取为止,总分数为 $\left \lfloor \frac{a + b + c}{2} \right \rfloor$。

时间复杂度 $O(1)$。

1
2
3
4
5
6
class Solution:
    def maximumScore(self, a: int, b: int, c: int) -> int:
        a, b, c = sorted([a, b, c])
        if a + b < c:
            return a + b
        return (a + b + c) >> 1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution {
    public int maximumScore(int a, int b, int c) {
        int[] s = new int[] {a, b, c};
        Arrays.sort(s);
        if (s[0] + s[1] < s[2]) {
            return s[0] + s[1];
        }
        return (a + b + c) >> 1;
    }
}
1
2
3
4
5
6
7
8
9
class Solution {
public:
    int maximumScore(int a, int b, int c) {
        vector<int> s = {a, b, c};
        sort(s.begin(), s.end());
        if (s[0] + s[1] < s[2]) return s[0] + s[1];
        return (a + b + c) >> 1;
    }
};
1
2
3
4
5
6
7
8
func maximumScore(a int, b int, c int) int {
    s := []int{a, b, c}
    sort.Ints(s)
    if s[0]+s[1] < s[2] {
        return s[0] + s[1]
    }
    return (a + b + c) >> 1
}

评论