6341. Determine the Winner of a Bowling Game

给你两个下标从 0 开始的整数数组 player1 和 player2 ,分别表示玩家 1 和玩家 2 击中的瓶数。

保龄球比赛由 n 轮组成,每轮的瓶数恰好为 10 。

假设玩家在第 i 轮中击中 xi 个瓶子。玩家第 i 轮的价值为:

  • 如果玩家在前两轮中击中了 10 个瓶子,则为 2xi 。
  • 否则,为 xi 。

玩家的得分是其 n 轮价值的总和。

返回

  • 如果玩家 1 的得分高于玩家 2 的得分,则为 1 ;
  • 如果玩家 2 的得分高于玩家 1 的得分,则为 2 ;
  • 如果平局,则为 0 。

测试样例:

输入:player1 = [4,10,7,9], player2 = [6,5,2,3]

输出:1

解释:player1 的得分是 4 + 10 + 27 + 29 = 46 。player2 的得分是 6 + 5 + 2 + 3 = 16 。player1 的得分高于 player2 的得分,所以 play1 在比赛中获胜,答案为 1 。

解答:按题意计算每个玩家的成绩,然后比较大小

class Solution {
    public int isWinner(int[] player1, int[] player2) {
        int s1 = score(player1), s2 = score(player2);
        if (s1 > s2) {
            return 1;
        } else if (s2 > s1) {
            return 2;
        }
        return 0;
    }

    private int score(int[] player) {
        int res = 0;
        for (int i = 0; i < player.length; ++i) {
            if (i - 1 >= 0 && player[i - 1] == 10) {
                res += 2 * player[i];
            } else if (i - 2 >= 0 && player[i - 2] == 10) {
                res += 2 * player[i];
            } else {
                res += player[i];
            }
        }
        return res;
    }
}

6342. First Completely Painted Row or Column

给你一个下标从 0 开始的整数数组 arr 和一个 m x n 的整数 矩阵 mat 。arr 和 mat 都包含范围 [1,m * n] 内的 所有 整数。

从下标 0 开始遍历 arr 中的每个下标 i ,并将包含整数 arr[i] 的 mat 单元格涂色。

请你找出 arr 中在 mat 的某一行或某一列上都被涂色且下标最小的元素,并返回其下标 i 。

测试样例:

输入:arr = [1,3,4,2], mat = [[1,4],[2,3]]

输出:2

解释:arr[2] 在矩阵中的第一行或第二列上都被涂色。

解答:首先只做一个Map,知道每个数所对应的位置。然后遍历arr,同时更新行列的涂色情况。如果发现某一列或者某一行完成着色,则返回当前位置。

class Solution {
    public int firstCompleteIndex(int[] arr, int[][] mat) {
        int m = mat.length, n = mat[0].length;
        int[] cr = new int[m], cc = new int[n];
        int[][] map = new int[m * n][2];
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                map[mat[i][j] - 1][0] = i;
                map[mat[i][j] - 1][1] = j;
            }
        }
        for (int i = 0; i < arr.length; ++i) {
            cr[map[arr[i] - 1][0]] += 1;
            cc[map[arr[i] - 1][1]] += 1;
            if (cr[map[arr[i] - 1][0]] == n || cc[map[arr[i] - 1][1]] == m) {
                return i;
            }
        }
        return -1;
    }
}

6343. Minimum Cost of a Path With Special Roads

给你一个数组 start ,其中 start = [startX, startY] 表示你的初始位置位于二维空间上的 (startX, startY) 。另给你一个数组 target ,其中 target = [targetX, targetY] 表示你的目标位置 (targetX, targetY) 。

从位置 (x1, y1) 到空间中任一其他位置 (x2, y2) 的代价是 |x2 - x1| + |y2 - y1| 。

给你一个二维数组 specialRoads ,表示空间中存在的一些特殊路径。其中 specialRoads[i] = [x1i, y1i, x2i, y2i, costi] 表示第 i 条特殊路径可以从 (x1i, y1i) 到 (x2i, y2i) ,但成本等于 costi 。你可以使用每条特殊路径任意次数。

返回从 (startX, startY) 到 (targetX, targetY) 所需的最小代价。

测试样例

输入:start = [1,1], target = [4,5], specialRoads = [[1,2,3,3,2],[3,4,4,5,1]]

输出:5

解释:

从 (1,1) 到 (4,5) 的最优路径如下:

  • (1,1) -> (1,2) ,移动的代价是 |1 - 1| + |2 - 1| = 1 。
  • (1,2) -> (3,3) ,移动使用第一条特殊路径,代价是 2 。
  • (3,3) -> (3,4) ,移动的代价是 |3 - 3| + |4 - 3| = 1.
  • (3,4) -> (4,5) ,移动使用第二条特殊路径,代价是 1 。

总代价是 1 + 2 + 1 + 1 = 5 。可以证明无法以小于 5 的代价完成从 (1,1) 到 (4,5) 。

解答:最近是真的很喜欢考Dijkstra。

这道题目是一道需要一点点脑筋急转弯的题目。如果一个点不是特殊路径的起点或者终点,那这个点本质上对计算不会产生影响(cost一定是|x2 - x1| + |y2 - y1|)。我们需要做的是,利用起点,然后用Dijkstra查看利用特殊路径会对特殊路径的起点和终点产生什么影响。不断更新最小代价,直到所有点都是最优情况为止。

这个时候,我们查看所有特殊点到终点的代价,并记录最少代价即可。

class Solution {
    private static final long mul = 1_000_01;

    public int minimumCost(int[] start, int[] target, int[][] specialRoads) {
        Map<Long, Long> pos = new HashMap<>();
        pos.put(serialize(start), 0L);

        TreeSet<Long> queue = new TreeSet<>(new Comparator<Long>() {
            @Override
            public int compare(Long o1, Long o2) {
                Long v1 = pos.getOrDefault(o1, Long.MAX_VALUE), v2 = pos.getOrDefault(o2, Long.MAX_VALUE);
                if (v1.compareTo(v2) != 0) {
                    return v1.compareTo(v2);
                } else {
                    return o1.compareTo(o2);
                }
            }
        });
        queue.add(serialize(start));
        while (!queue.isEmpty()) {
            long key = queue.first(), cost = pos.get(key);
            queue.remove(key);

            int[] p = deserialize(key);
            for (int[] r : specialRoads) {
                long k1 = serialize(r[0], r[1]), k2 = serialize(r[2], r[3]);
                if (p[0] != r[0] || p[1] != r[1]) {
                    int c = Math.abs(p[0] - r[0]) + Math.abs(p[1] - r[1]);
                    long curCost = c + cost;
                    if (!pos.containsKey(k1) || pos.get(k1) > curCost) {
                        queue.remove(k1);
                        pos.put(k1, curCost);
                        queue.add(k1);
                    }
                } else {
                    int c = r[4];
                    long curCost = c + cost;
                    if (!pos.containsKey(k2) || pos.get(k2) > curCost) {
                        queue.remove(k2);
                        pos.put(k2, curCost);
                        queue.add(k2);
                    }
                }

                if (p[0] != r[2] || p[1] != r[3]) {
                    int c = Math.abs(p[0] - r[2]) + Math.abs(p[1] - r[3]);
                    long curCost = c + cost;
                    if (!pos.containsKey(k2) || pos.get(k2) > curCost) {
                        queue.remove(k2);
                        pos.put(k2, curCost);
                        queue.add(k2);
                    }
                }
            }
        }

        long res = Math.abs(target[0] - start[0]) + Math.abs(target[1] - start[1]);
        for (int[] r : specialRoads) {
            long k1 = serialize(r[0], r[1]), k2 = serialize(r[2], r[3]);
            if (pos.containsKey(k1)) {
                res = Math.min(res, pos.get(k1) + Math.abs(target[0] - r[0]) + Math.abs(target[1] - r[1]));
            }
            if (pos.containsKey(k2)) {
                res = Math.min(res, pos.get(k2) + Math.abs(target[0] - r[2]) + Math.abs(target[1] - r[3]));
            }
        }
        return (int)res;
    }

    private long serialize(int[] p) {
        return p[0] * mul + p[1];
    }

    private long serialize(int p1, int p2) {
        return p1 * mul + p2;
    }

    private int[] deserialize(long key) {
        int l1 = (int)(key / mul), l2 = (int)(key % mul);
        return new int[]{l1, l2};
    }
}

6344. Lexicographically Smallest Beautiful String

如果一个字符串满足以下条件,则称其为 美丽字符串 :

  • 它由英语小写字母表的前 k 个字母组成。
  • 它不包含任何长度为 2 或更长的回文子字符串。

给你一个长度为 n 的美丽字符串 s 和一个正整数 k 。

请你找出并返回一个长度为 n 的美丽字符串,该字符串还满足:在字典序大于 s 的所有美丽字符串中字典序最小。如果不存在这样的字符串,则返回一个空字符串。

对于长度相同的两个字符串 a 和 b ,如果字符串 a 在与字符串 b 不同的第一个位置上的字符字典序更大,则字符串 a 的字典序大于字符串 b 。

例如,"abcd" 的字典序比 "abcc" 更大,因为在不同的第一个位置(第四个字符)上 d 的字典序大于 c 。

测试样例

输入:s = "abcz", k = 26

输出:"abda"

解释:

字符串 "abda" 既是美丽字符串,又满足字典序大于 "abcz" 。可以证明不存在字符串同时满足字典序大于 "abcz"、美丽字符串、字典序小于 "abda" 这三个条件。

解答:这道题目其实也是有点脑经急转弯。需要满足不包含任何长度为 2 或更长的回文子字符串,翻译一下就是对于字符串str来说:

  1. str.charAt(i) != str.charAt(i + 1)
  2. str.charAt(i) != str.charAt(i + 2)

增加这个条件之后,我们就可以用类似寻找下一个字典序的算法来计算结果

class Solution {
    public String smallestBeautifulString(String s, int k) {
        int len = s.length() - 1;
        for (int i = len; i >= 0; --i) {
            int cur = s.charAt(i) - 'a';
            if (cur == k - 1) continue;
            int[] t = before(s, i);
            int isValid = -1;
            for (int j = cur + 1; j < k; ++j) {
                if (j != t[0] && j != t[1]) {
                    isValid = j;
                    break;
                }
            }
            if (isValid != -1) {
                StringBuilder res = new StringBuilder(s.substring(0, i));
                res.append((char)(isValid + 'a'));
                for (int j = i + 1; j <= len; ++j) {
                    int b1 = res.charAt(res.length() - 1) - 'a';
                    int b2 = res.length() - 2 >= 0 ? (res.charAt(res.length() - 2) - 'a') : -1;
                    res.append(findBest(k, b1, b2));
                }
                return res.toString();
            }
        }
        return "";
    }

    private int[] before(String s, int p) {
        int l1 = p - 1 >= 0 ? (s.charAt(p - 1) - 'a') : -1;
        int l2 = p - 2 >= 0 ? (s.charAt(p - 2) - 'a') : -1;
        return new int[]{l1, l2};
    }

    private char findBest(int k, int a, int b) {
        for (int i = 0; i < k; ++i) {
            if (i != a && i != b) {
                return (char)(i + 'a');
            }
        }
        return 0;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *