Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
- Alice 和 Bob 是一场射箭比赛中的对手。比赛规则如下:
- Alice 先射 numArrows 支箭,然后 Bob 也射 numArrows 支箭。
- 分数按下述规则计算:
- 箭靶有若干整数计分区域,范围从 0 到 11 (含 0 和 11)。箭靶上每个区域都对应一个得分 k(范围是 0 到 11),Alice 和 Bob 分别在得分 k 区域射中 ak 和 bk 支箭。如果 ak >= bk ,那么 Alice 得 k 分。如果 ak < bk ,则 Bob 得 k 分。如果 ak == bk == 0 ,那么无人得到 k 分。
- 例如,Alice 和 Bob 都向计分为 11 的区域射 2 支箭,那么 Alice 得 11 分。如果 Alice 向计分为 11 的区域射 0 支箭,但 Bob 向同一个区域射 2 支箭,那么 Bob 得 11 分。
- 给你整数 numArrows 和一个长度为 12 的整数数组 aliceArrows ,该数组表示 Alice 射中 0 到 11 每个计分区域的箭数量。现在,Bob 想要尽可能 最大化 他所能获得的总分。
- 返回数组 bobArrows ,该数组表示 Bob 射中 0 到 11 每个 计分区域的箭数量。且 bobArrows 的总和应当等于 numArrows 。
- 如果存在多种方法都可以使 Bob 获得最大总分,返回其中 任意一种 即可。
示例 1
输入: numArrows = 9, aliceArrows = [1,1,0,1,0,0,2,1,0,1,2,0]
输出: [0,0,0,0,1,1,0,0,1,2,3,1]
解释: 上表显示了比赛得分情况。
Bob 获得总分 4 + 5 + 8 + 9 + 10 + 11 = 47 。
可以证明 Bob 无法获得比 47 更高的分数。
示例 2
输入: numArrows = 3, aliceArrows = [0,0,1,0,0,0,0,0,0,0,0,2]
输出: [0,0,0,0,0,0,0,0,1,1,1,0]
解释: 上表显示了比赛得分情况。
Bob 获得总分 8 + 9 + 10 = 27 。
可以证明 Bob 无法获得比 27 更高的分数。
思路分析
- 题比较长,但是直接看示例会更容易理解。就是 想要获得一个分数,那么 Bob 就必须在这个分数区域击中靶的次数要比 多。吐槽一下官方的题目描述也太烂了[doge]。
- 接下来就是 选择中靶的方案了,我们要找到可以让 获得分数最多的方案。分数从
0到11, 所以可以所有可能进行回溯搜索。可以从11分往0回溯,并在过程中不断进行剪枝。 - 最后把位置方案转化为答案返回数组即可。
AC 代码
class Solution {
List<Integer> data = new ArrayList<>();
List<Integer> res = new ArrayList<>();
boolean[] visited = new boolean[12];
int max = 0;
public int[] maximumBobPoints(int n, int[] nums) {
// 修改为要想获得 i 分,至少要中靶的次数.
for (int i = 0; i < 12; i++) nums[i] += 1;
dfs(nums, 11, n, 0);
int[] t = new int[12];
for (int i = 1; i < res.size(); i++) {
int p = res.get(i);
t[p] = nums[p];
n -= nums[p];
}
t[res.get(0)] = n;
return t;
}
// 回溯 + 剪枝处理.
private void dfs(int[] nums, int index, int n, int score) {
// 当有获得更多分数的获取方式,则更新记录的信息.
if (score >= max && n >= 0) {
max = score;
res = new ArrayList<>(data);
}
if (n <= 0) return;
for (int i = index; i >= 0; i--) {
if (visited[i] == true) continue;
visited[i] = true;
data.add(i);
dfs(nums, i - 1, n - nums[i],score + i);
visited[i] = false;
data.remove(data.size() - 1);
}
}
}
总结
- 这是今天 leetcode 周赛的第三题,在使用回溯的时候要注意进行剪枝,不然会超时!今早写完提交就出现了超时情况,后面加了剪枝之后就可以通过了。