[Leetcode Weekly Contest]297

链接:LeetCode

[Leetcode]2303. 计算应缴税款总额

给你一个下标从 0 开始的二维整数数组 brackets ,其中 brackets[i] = [upperi, percenti] ,表示第 i 个税级的上限是 upperi ,征收的税率为 percenti 。税级按上限 从低到高排序(在满足 0 < i < brackets.length 的前提下,upperi-1 < upperi)。
税款计算方式如下:

  • 不超过 upper0 的收入按税率 percent0 缴纳
  • 接着 upper1 - upper0 的部分按税率 percent1
  • 然后 upper2 - upper1 的部分按税率 percent2 缴纳
  • 以此类推

给你一个整数 income 表示你的总收入。返回你需要缴纳的税款总额。与标准答案误差不超 10-5 的结果将被视作正确答案。

模拟遍历即可。

class Solution {
    public double calculateTax(int[][] brackets, int income) {
        int pre = 0;
        double res = 0;
        for(var bracket:brackets) {
            int end = bracket[0], rate = bracket[1];
            if(income > end) {
                res += (end-pre) * rate / 100.0;
            }
            else {
                res += (income-pre) * rate / 100.0;
                break;
            }
            pre = end;
        }
        return res;
    }
}

[Leetcode]2304. 网格中的最小路径代价

给你一个下标从 0 开始的整数矩阵 grid ,矩阵大小为 m x n ,由从 0 到 m * n - 1 的不同整数组成。你可以在此矩阵中,从一个单元格移动到 下一行 的任何其他单元格。如果你位于单元格 (x, y) ,且满足 x < m - 1 ,你可以移动到 (x + 1, 0), (x + 1, 1), ..., (x + 1, n - 1) 中的任何一个单元格。注意: 在最后一行中的单元格不能触发移动。

每次可能的移动都需要付出对应的代价,代价用一个下标从 0 开始的二维数组 moveCost 表示,该数组大小为 (m * n) x n ,其中 moveCost[i][j] 是从值为 i 的单元格移动到下一行第 j 列单元格的代价。从 grid 最后一行的单元格移动的代价可以忽略。

grid 一条路径的代价是:所有路径经过的单元格的 值之和 加上 所有移动的 代价之和 。从 第一行 任意单元格出发,返回到达 最后一行 任意单元格的最小路径代价。

记忆化搜索。自底向上,先找到最后一行的最短路径代价,然后往上抛结果,直到第一行。

class Solution {
    public int minPathCost(int[][] grid, int[][] moveCost) {
        int n = grid.length, m = grid[0].length;
        for(int i=n-2;i>=0;--i) {
            for(int j=0;j<m;++j) {
                int res = Integer.MAX_VALUE;
                for(int k=0;k<m;++k) {
                    int nxt = grid[i+1][k];
                    res = Math.min(res, nxt+moveCost[grid[i][j]][k]);
                }
                grid[i][j] += res;
            }
        }
        int res = Integer.MAX_VALUE;
        for(int j=0;j<m;++j) {
            res = Math.min(res, grid[0][j]);
        }
        return res;
    }
}

[Leetcode]2305. 公平分发饼干

给你一个整数数组 cookies ,其中 cookies[i] 表示在第 i 个零食包中的饼干数量。另给你一个整数 k 表示等待分发零食包的孩子数量,所有 零食包都需要分发。在同一个零食包中的所有饼干都必须分发给同一个孩子,不能分开。

分发的 不公平程度 定义为单个孩子在分发过程中能够获得饼干的最大总数。

返回所有分发的最小不公平程度。

回溯+剪枝。
每一个饼干包(一共有n个)可以分给任意k个小朋友,一共有k^n种分法。暴力枚举一遍,找最大饼干数的最小值就行了。n和k最大取值为8,枚举方案一共有 \(8^8\) 个,有点大,暴力可能超时。那么可以用回溯+剪枝。回溯本身也类似于暴力法,只不过通过适当的剪枝可以将时间复杂度显著降低。

class Solution {
    int res = Integer.MAX_VALUE;
    public int distributeCookies(int[] cookies, int k) {
        Arrays.sort(cookies);
        int[] children = new int[k];
        dfs(cookies, children, k, cookies.length-1);
        return res;
    }

    public void dfs(int[] cookies, int[] children, int k, int index) {
        if(index == -1) {
            res = Math.min(res, getMaxValue(children));
            return;
        }
        if(getMaxValue(children) >= res) return;
        for(int i=0;i<k;++i) {
            children[i] += cookies[index];
            dfs(cookies, children, k, index-1);
            children[i] -= cookies[index];
        }
    }

    public int getMaxValue(int[] nums) {
        int res = Integer.MIN_VALUE;
        for(var num:nums) res = Math.max(res, num);
        return res;
    }
}

[Leetcode]2306. 公司命名

给你一个字符串数组 ideas 表示在公司命名过程中使用的名字列表。公司命名流程如下:

  1. 从 ideas 中选择 2 个 不同 名字,称为 ideaA 和 ideaB 。
  2. 交换 ideaA 和 ideaB 的首字母。
  3. 如果得到的两个新名字 都 不在 ideas 中,那么 ideaA ideaB(串联 ideaA 和 ideaB ,中间用一个空格分隔)是一个有效的公司名字。
  4. 否则,不是一个有效的名字。

返回 不同 且有效的公司名字的数目。

哈希,根据首字母分组。

对于 A 组中的字符串 s,如果 B 组中存在字符串 t,使得 \(s[1:]=t[1:]\),那么 s 无法与 B 组中的任意字符串互换首字母,否则可以互换。对于 B 组同理。
设 A 组和 B 组交集的大小为 m,则这两个组可以组成的合法答案数为

\[2\cdot(|A|-m)\cdot(|B|-m) \]

其中 ∣A∣ 表示集合 A 的大小,|B∣ 表示集合 B 的大小。
遍历所有组对,累加答案。

class Solution {
    public long distinctNames(String[] ideas) {
        HashSet[] set = new HashSet[26];
        for(int i=0;i<26;++i) {
            set[i] = new HashSet<String>();
        }
        for(var idea:ideas) {
            set[idea.charAt(0) - 'a'].add(idea.substring(1));
        }
        long res = 0L;
        for(int i=0;i<26;++i) {
            for(int j=i+1;j<26;++j) {
                int overlap = 0;
                for(var sub:set[i]) {
                    if(set[j].contains(sub)) overlap += 1;
                }
                res += (long)(set[i].size()-overlap) * (set[j].size()-overlap);
            }
        }
        return 2*res;
    }
}

参考:LeetCode

posted @ 2022-07-08 09:25  Jamest  阅读(28)  评论(0编辑  收藏  举报