LeetCode破解之射击比赛的得分

104 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

题目描述

Alice 和 Bob 是一场射箭比赛中的对手。比赛规则如下:

  1. Alice 先射 numArrows 支箭,然后 Bob 也射 numArrows 支箭。

  2. 分数按下述规则计算:

    1. 箭靶有若干整数计分区域,范围从 0 到 11 (含 0 和 11)。
    2. 箭靶上每个区域都对应一个得分 k(范围是 0 到 11),Alice 和 Bob 分别在得分 k 区域射中 ak 和 bk 支箭。如果 ak >= bk ,那么 Alice 得 k 分。如果 ak < bk ,则 Bob 得 k 分
    3. 如果 ak == bk == 0 ,那么无人得到 k 分。
  3. 例如,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:

image-20220630081626909

输入: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 更高的分数。

双指针

这个题目我的初步思路是:我是方法是选择回溯法,可以说是万能的标准解法,只需要注意将最后剩余的箭都射入0节点。且每次射箭的最少数量应该等于Alice射箭数量+1。对于Bob而言一个有12个层级,每个层级可以分为得分和不得分。如果想得分,则需要超过Alice一个,若不想得分,则为0即可。所以我们可以枚举每一种情况,并记录下最大值时候的状态。并且从大到小递归每一层级,直到-1停止。若是有多余的箭,则都给层级0。然后用max来记录最大的得分,若是递归到-1的时候,得分大于最大得分,则替换,更新各个层级的状态。递归的时候,分为两种状态,分别为得分/不得分,得分的时候,需要剩余的箭数大于Alice的箭数。具体注意点如下:

  • 如果先获得对于bob如果需要得分,对应每个分值所需的最少射箭数量
  • 使用堆最少射箭数量的进行回溯
  • 我们来维护保存过程中的最大得分
  • 如果总射箭数少于numArrows,我们就可以随意分配剩余射箭数。

实现思路如下:

  • 先计算每个得分区域的收益(分值/箭的数量)
  • 然后按照收益降序排序
  • 最后遍历收益数组,如果剩余的箭数量足够一个得分区域,就把它添加到答案里
class Solution {
    List<int[]> res = new ArrayList<>();
    int[] path = new int[12];
    public int[] maximumBobPoints(int n, int[] a) {
        backTrace(n, a, 1);
        if (res.size() == 0) return new int[12];
        int max = 0;
        int max_index = 0;
        for (int i = 0; i < res.size(); i++) {
            int sum = 0;
            int[] cur = res.get(i);
            for (int j = 0; j < cur.length; j++) {
                if (cur[j] > a[j]) {
                    sum += j;
                }
            }
            if (sum > max) {
                max = sum;
                max_index = i;
            }
        }
        int[] ans = res.get(max_index);
        for (int i : ans) {
            n -= i;
        }
        ans[0] += n;
        return ans;
    }

    public void backTrace(int n, int[] a, int pos) {
        if (pos >= a.length || n <= 0) {
            res.add(path.clone());
            return;
        }

        for (int i = pos; i < a.length; i++) {
            if (n > a[i]) {
                n -= a[i] + 1;
                path[i] = a[i] + 1;
                backTrace(n, a, i + 1);
                path[i] = 0;
                n += a[i] + 1;
            }else {
                backTrace(n, a, i + 1);
            }
        }
    }
       
}

最后

暴力回溯有很多细节要处理好,不然就会一直吃wa。吃的很难受。