【题解】—— LeetCode一周小结31

简介: LeetCode每日一道一周小结31

🌟欢迎来到 我的博客 —— 探索技术的无限可能!

🌟博客的简介(文章目录)


【题解】—— 每日一道题目栏


上接:【题解】—— LeetCode一周小结30

29.棒球比赛

题目链接:682. 棒球比赛

你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。

比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表 ops,其中 ops[i] 是你需要记录的第 i 项操作,ops 遵循下述规则:

整数 x - 表示本回合新获得分数 x

“+” - 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。

“D” - 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效的分数。

“C” - 表示前一次得分无效,将其从记录中移除。题目数据保证记录此操作时前面总是存在一个有效的分数。

请你返回记录中所有得分的总和。

示例 1:

输入:ops = [“5”,“2”,“C”,“D”,“+”]

输出:30

解释:

“5” - 记录加 5 ,记录现在是 [5]

“2” - 记录加 2 ,记录现在是 [5, 2]

“C” - 使前一次得分的记录无效并将其移除,记录现在是 [5].

“D” - 记录加 2 * 5 = 10 ,记录现在是 [5, 10].

“+” - 记录加 5 + 10 = 15 ,记录现在是 [5, 10, 15].

所有得分的总和 5 + 10 + 15 = 30

示例 2:

输入:ops = [“5”,“-2”,“4”,“C”,“D”,“9”,“+”,“+”]

输出:27

解释:

“5” - 记录加 5 ,记录现在是 [5]

“-2” - 记录加 -2 ,记录现在是 [5, -2]

“4” - 记录加 4 ,记录现在是 [5, -2, 4]

“C” - 使前一次得分的记录无效并将其移除,记录现在是 [5, -2]

“D” - 记录加 2 * -2 = -4 ,记录现在是 [5, -2, -4]

“9” - 记录加 9 ,记录现在是 [5, -2, -4, 9]

“+” - 记录加 -4 + 9 = 5 ,记录现在是 [5, -2, -4, 9, 5]

“+” - 记录加 9 + 5 = 14 ,记录现在是 [5, -2, -4, 9, 5, 14]

所有得分的总和 5 + -2 + -4 + 9 + 5 + 14 = 27

示例 3:

输入:ops = [“1”]

输出:1

提示:

1 <= ops.length <= 1000

ops[i] 为 “C”、“D”、“+”,或者一个表示整数的字符串。整数范围是 [-3 * 104, 3 * 104]

对于 “+” 操作,题目数据保证记录此操作时前面总是存在两个有效的分数

对于 “C” 和 “D” 操作,题目数据保证记录此操作时前面总是存在一个有效的分数

题解:

方法:模拟

       

class Solution {
    public int calPoints(String[] operations) {
        List<Integer> st = new ArrayList<>();
        for (String op : operations) {
            switch (op.charAt(0)) {
                case '+':
                    st.add(st.get(st.size() - 2) + st.get(st.size() - 1));
                    break;
                case 'D':
                    st.add(st.get(st.size() - 1) * 2);
                    break;
                case 'C':
                    st.remove(st.size() - 1);
                    break;
                default:
                    st.add(Integer.parseInt(op));
            }
        }
        int sum = 0;
        for (int x : st) {
            sum += x;
        }
        return sum;
    }
}

30.双模幂运算

题目链接:2961. 双模幂运算

给你一个下标从 0 开始的二维数组 variables ,其中 variables[i] = [ai, bi, ci, mi],以及一个整数 target 。

如果满足以下公式,则下标 i 是 好下标:

0 <= i < variables.length

((aibi % 10)ci) % mi == target

返回一个由 好下标 组成的数组,顺序不限 。

示例 1:

输入:variables = [[2,3,3,10],[3,3,3,1],[6,1,1,4]], target = 2

输出:[0,2]

解释:对于 variables 数组中的每个下标 i :

  1. 对于下标 0 ,variables[0] = [2,3,3,10] ,(23 % 10)3 % 10 = 2 。
  2. 对于下标 1 ,variables[1] = [3,3,3,1] ,(33 % 10)3 % 1 = 0 。
  3. 对于下标 2 ,variables[2] = [6,1,1,4] ,(61 % 10)1 % 4 = 2 。

因此,返回 [0,2] 作为答案。

示例 2:

输入:variables = [[39,3,1000,1000]], target = 17

输出:[]

解释:对于 variables 数组中的每个下标 i :

  1. 对于下标 0 ,variables[0] = [39,3,1000,1000] ,(393 % 10)1000 % 1000 = 1

因此,返回 [] 作为答案。

提示:

1 <= variables.length <= 100

variables[i] == [ai, bi, ci, mi]

1 <= ai, bi, ci, mi <= 103

0 <= target <= 103

题解:

方法:快速幂取模

       

class Solution {
    public List<Integer> getGoodIndices(int[][] variables, int target) {
        List<Integer> ans = new ArrayList<>();
        for (int i = 0; i < variables.length; i++) {
            int[] v = variables[i];
            if (pow(pow(v[0], v[1], 10), v[2], v[3]) == target) {
                ans.add(i);
            }
        }
        return ans;
    }
    // 本题 mod 很小,即使平方也不会超过 int 范围,所以不需要用 long
    private int pow(int x, int n, int mod) {
        int res = 1;
        while (n > 0) {
            if (n % 2 > 0) {
                res = res * x % mod;
            }
            x = x * x % mod;
            n /= 2;
        }
        return res;
    }
}

31.覆盖所有点的最少矩形数目

题目链接:3111. 覆盖所有点的最少矩形数目

给你一个二维整数数组 point ,其中 points[i] = [xi, yi] 表示二维平面内的一个点。同时给你一个整数 w 。你需要用矩形 覆盖所有 点。

每个矩形的左下角在某个点 (x1, 0) 处,且右上角在某个点 (x2, y2) 处,其中 x1 <= x2 且 y2 >= 0 ,同时对于每个矩形都 必须 满足 x2 - x1 <= w 。

如果一个点在矩形内或者在边上,我们说这个点被矩形覆盖了。

请你在确保每个点都 至少 被一个矩形覆盖的前提下,最少 需要多少个矩形。

注意:一个点可以被多个矩形覆盖。

示例 1:

输入:points = [[2,1],[1,0],[1,4],[1,8],[3,5],[4,6]], w = 1

输出:2

解释:

上图展示了一种可行的矩形放置方案:

一个矩形的左下角在 (1, 0) ,右上角在 (2, 8) 。

一个矩形的左下角在 (3, 0) ,右上角在 (4, 8) 。

示例 2:

输入:points = [[0,0],[1,1],[2,2],[3,3],[4,4],[5,5],[6,6]], w = 2

输出:3

解释:

上图展示了一种可行的矩形放置方案:

一个矩形的左下角在 (0, 0) ,右上角在 (2, 2) 。

一个矩形的左下角在 (3, 0) ,右上角在 (5, 5) 。

一个矩形的左下角在 (6, 0) ,右上角在 (6, 6) 。

示例 3:

输入:points = [[2,3],[1,2]], w = 0

输出:2

解释:

上图展示了一种可行的矩形放置方案:

一个矩形的左下角在 (1, 0) ,右上角在 (1, 2) 。

一个矩形的左下角在 (2, 0) ,右上角在 (2, 3) 。

提示:

1 <= points.length <= 105

points[i].length == 2

0 <= xi == points[i][0] <= 109

0 <= yi == points[i][1] <= 109

0 <= w <= 109

所有点坐标 (xi, yi) 互不相同。

题解:

方法:贪心 + 排序

       

class Solution {
    public int minRectanglesToCoverPoints(int[][] points, int w) {
        Arrays.sort(points, (a, b) -> a[0] - b[0]);
        int ans = 0, x1 = -1;
        for (int[] p : points) {
            int x = p[0];
            if (x > x1) {
                ++ans;
                x1 = x + w;
            }
        }
        return ans;
    }
}

2024.8

1.心算挑战

题目链接:LCP 40. 心算挑战

「力扣挑战赛」心算项目的挑战比赛中,要求选手从 N 张卡牌中选出 cnt 张卡牌,若这 cnt 张卡牌数字总和为偶数,则选手成绩「有效」且得分为 cnt 张卡牌数字总和。 给定数组 cards 和 cnt,其中 cards[i] 表示第 i 张卡牌上的数字。 请帮参赛选手计算最大的有效得分。若不存在获取有效得分的卡牌方案,则返回 0。

示例 1:

输入:cards = [1,2,8,9], cnt = 3

输出:18

解释:选择数字为 1、8、9 的这三张卡牌,此时可获得最大的有效得分 1+8+9=18。

示例 2:

输入:cards = [3,3,1], cnt = 1

输出:0

解释:不存在获取有效得分的卡牌方案。

提示:

1 <= cnt <= cards.length <= 10^5

1 <= cards[i] <= 1000

题解:

方法:排序+贪心

       

class Solution {
    public int maxmiumScore(int[] cards, int cnt) {
        Arrays.sort(cards);
        int n = cards.length;
        int s = 0;
        for (int i = n - cnt; i < n; i++) {
            s += cards[i]; // 最大的 cnt 个数之和
        }
        if (s % 2 == 0) { // s 是偶数
            return s;
        }
        int x = cards[n - cnt];
        int ans = replacedSum(cards, cnt, s, x); // 替换 x
        for (int i = n - cnt + 1; i < n; i++) {
            if (cards[i] % 2 != x % 2) { // 找到一个最小的奇偶性和 x 不同的数
                ans = Math.max(ans, replacedSum(cards, cnt, s, cards[i])); // 替换
                break;
            }
        }
        return ans;
    }
    private int replacedSum(int[] cards, int cnt, int s, int x) {
        for (int i = cards.length - cnt - 1; i >= 0; i--) {
            if (cards[i] % 2 != x % 2) { // 找到一个最大的奇偶性和 x 不同的数
                return s - x + cards[i]; // 用 cards[i] 替换 s
            }
        }
        return 0;
    }
}

2.直角三角形

题目链接:3128. 直角三角形

给你一个二维 boolean 矩阵 grid 。

请你返回使用 grid 中的 3 个元素可以构建的 直角三角形 数目,且满足 3 个元素值 都 为 1 。

注意:

如果 grid 中 3 个元素满足:一个元素与另一个元素在 同一行,同时与第三个元素在 同一列 ,那么这 3 个元素称为一个 直角三角形 。这 3 个元素互相之间不需要相邻。

示例 1:

输入:grid = [[0,1,0],[0,1,1],[0,1,0]]

输出:2

解释:

有 2 个直角三角形。

示例 2:

输入:grid = [[1,0,0,0],[0,1,0,1],[1,0,0,0]]

输出:0

解释:

没有直角三角形。

示例 3:

输入:grid = [[1,0,1],[1,0,0],[1,0,0]]

输出:2

解释:

有两个直角三角形。

提示:

1 <= grid.length <= 1000

1 <= grid[i].length <= 1000

0 <= grid[i][j] <= 1

题解:

方法:枚举

       

class Solution {
    public long numberOfRightTriangles(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        int[] rows = new int[m];
        int[] cols = new int[n];
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                rows[i] += grid[i][j];
                cols[j] += grid[i][j];
            }
        }
        long ans = 0;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    ans += (rows[i] - 1) * (cols[j] - 1);
                }
            }
        }
        return ans;
    }
}

3.正方形中的最多点数

题目链接:3143. 正方形中的最多点数

给你一个二维数组 points 和一个字符串 s ,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的 标签 。

如果一个正方形的中心在 (0, 0) ,所有边都平行于坐标轴,且正方形内 不 存在标签相同的两个点,那么我们称这个正方形是 合法 的。

请你返回 合法 正方形中可以包含的 最多 点数。

注意:

如果一个点位于正方形的边上或者在边以内,则认为该点位于正方形内。

正方形的边长可以为零。

示例 1:

输入:points = [[2,2],[-1,-2],[-4,4],[-3,1],[3,-3]], s = “abdca”

输出:2

解释:

边长为 4 的正方形包含两个点 points[0] 和 points[1] 。

示例 2:

输入:points = [[1,1],[-2,-2],[-2,2]], s = “abb”

输出:1

解释:

边长为 2 的正方形包含 1 个点 points[0] 。

示例 3:

输入:points = [[1,1],[-1,-1],[2,-2]], s = “ccd”

输出:0

解释:

任何正方形都无法只包含 points[0] 和 points[1] 中的一个点,所以合法正方形中都不包含任何点。

提示:

1 <= s.length, points.length <= 105

points[i].length == 2

-109 <= points[i][0], points[i][1] <= 109

s.length == points.length

points 中的点坐标互不相同。

s 只包含小写英文字母。

题解:

方法:哈希表 + 排序

       

class Solution {
    public int maxPointsInsideSquare(int[][] points, String s) {
        TreeMap<Integer, List<Integer>> g = new TreeMap<>();
        for (int i = 0; i < points.length; ++i) {
            int x = points[i][0], y = points[i][1];
            int key = Math.max(Math.abs(x), Math.abs(y));
            g.computeIfAbsent(key, k -> new ArrayList<>()).add(i);
        }
        boolean[] vis = new boolean[26];
        int ans = 0;
        for (var idx : g.values()) {
            for (int i : idx) {
                int j = s.charAt(i) - 'a';
                if (vis[j]) {
                    return ans;
                }
                vis[j] = true;
            }
            ans += idx.size();
        }
        return ans;
    }
}

4.另一棵树的子树

题目链接:572. 另一棵树的子树

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

示例 1:

输入:root = [3,4,5,1,2], subRoot = [4,1,2]

输出:true

示例 2:

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]

输出:false

提示:

root 树上的节点数量范围是 [1, 2000]

subRoot 树上的节点数量范围是 [1, 1000]

-104 <= root.val <= 104

-104 <= subRoot.val <= 104

题解:

方法:暴力

       

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if (root == null) {
            return false;
        }
        return isSameTree(root, subRoot) ||
               isSubtree(root.left, subRoot) ||
               isSubtree(root.right, subRoot);
    }
    // 100. 相同的树
    private boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null || q == null) {
            return p == q; // 必须都是 null
        }
        return p.val == q.val &&
               isSameTree(p.left, q.left) &&
               isSameTree(p.right, q.right);
    }
}

下接:【题解】—— LeetCode一周小结32


相关文章
|
1月前
|
索引
|
1月前
|
测试技术 索引
【题解】—— LeetCode一周小结40
LeetCode每日一道一周小结40
|
3月前
|
Perl
|
5月前
|
算法