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

简介: LeetCode每日一道一周小结20
🌟欢迎来到 我的博客 —— 探索技术的无限可能!


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


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


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

13.腐烂的橘子

题目链接:994. 腐烂的橘子

在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:

值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。

返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。

示例 1:
image.png

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

输出:4

示例 2:

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

输出:-1

解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个方向上。

示例 3:

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

输出:0

解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。

提示:

m == grid.length

n == grid[i].length

1 <= m, n <= 10

grid[i][j] 仅为 0、1 或 2

题解:
方法:广度优先搜索

class Solution {
   
    private static final int[][] DIRECTIONS = {
   {
   -1, 0}, {
   1, 0}, {
   0, -1}, {
   0, 1}}; // 四方向

    public int orangesRotting(int[][] grid) {
   
        int m = grid.length;
        int n = grid[0].length;
        int fresh = 0;
        List<int[]> q = new ArrayList<>();
        for (int i = 0; i < m; i++) {
   
            for (int j = 0; j < n; j++) {
   
                if (grid[i][j] == 1) {
   
                    fresh++; // 统计新鲜橘子个数
                } else if (grid[i][j] == 2) {
   
                    q.add(new int[]{
   i, j}); // 一开始就腐烂的橘子
                }
            }
        }

        int ans = -1;
        while (!q.isEmpty()) {
   
            ans++; // 经过一分钟
            List<int[]> tmp = q;
            q = new ArrayList<>();
            for (int[] pos : tmp) {
    // 已经腐烂的橘子
                for (int[] d : DIRECTIONS) {
    // 四方向
                    int i = pos[0] + d[0];
                    int j = pos[1] + d[1];
                    if (0 <= i && i < m && 0 <= j && j < n && grid[i][j] == 1) {
    // 新鲜橘子
                        fresh--;
                        grid[i][j] = 2; // 变成腐烂橘子
                        q.add(new int[]{
   i, j});
                    }
                }
            }
        }

        return fresh > 0 ? -1 : Math.max(ans, 0);
    }
}

14.完成所有任务需要的最少轮数

题目链接:2244. 完成所有任务需要的最少轮数

给你一个下标从 0 开始的整数数组 tasks ,其中 tasks[i] 表示任务的难度级别。在每一轮中,你可以完成 2 个或者 3 个 相同难度级别 的任务。

返回完成所有任务需要的 最少 轮数,如果无法完成所有任务,返回 -1 。

示例 1:

输入:tasks = [2,2,3,3,2,4,4,4,4,4]

输出:4

解释:要想完成所有任务,一个可能的计划是:

  • 第一轮,完成难度级别为 2 的 3 个任务。
  • 第二轮,完成难度级别为 3 的 2 个任务。
  • 第三轮,完成难度级别为 4 的 3 个任务。
  • 第四轮,完成难度级别为 4 的 2 个任务。

可以证明,无法在少于 4 轮的情况下完成所有任务,所以答案为 4 。

示例 2:

输入:tasks = [2,3,3]

输出:-1

解释:难度级别为 2 的任务只有 1 个,但每一轮执行中,只能选择完成 2 个或者 3 个相同难度级别的任务。因此,无法完成所有任务,答案为
-1 。

提示:

1 <= tasks.length <= 105

1 <= tasks[i] <= 109

题解:
方法:贪心

public class Solution {
   
    public int minimumRounds(int[] tasks) {
   
        Map<Integer, Integer> cnt = new HashMap<>();
        for (int t : tasks) {
   
            cnt.merge(t, 1, Integer::sum);
        }
        int ans = 0;
        for (int c : cnt.values()) {
   
            if (c == 1) {
   
                return -1;
            }
            ans += (c + 2) / 3;
        }
        return ans;
    }
}

15.完成所有任务的最少时间

题目链接:2589. 完成所有任务的最少时间

你有一台电脑,它可以 同时 运行无数个任务。给你一个二维整数数组 tasks ,其中 tasks[i] = [starti, endi, durationi] 表示第 i 个任务需要在 闭区间 时间段 [starti, endi] 内运行 durationi 个整数时间点(但不需要连续)。

当电脑需要运行任务时,你可以打开电脑,如果空闲时,你可以将电脑关闭。

请你返回完成所有任务的情况下,电脑最少需要运行多少秒。

示例 1:

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

输出:2

解释:

  • 第一个任务在闭区间 [2, 2] 运行。
  • 第二个任务在闭区间 [5, 5] 运行。
  • 第三个任务在闭区间 [2, 2] 和 [5, 5] 运行。

电脑总共运行 2 个整数时间点。

示例 2:

输入:tasks = [[1,3,2],[2,5,3],[5,6,2]]

输出:4

解释:

  • 第一个任务在闭区间 [2, 3] 运行
  • 第二个任务在闭区间 [2, 3] 和 [5, 5] 运行。
  • 第三个任务在闭区间 [5, 6] 运行。

电脑总共运行 4 个整数时间点。

提示:

1 <= tasks.length <= 2000

tasks[i].length == 3

1 <= starti, endi <= 2000

1 <= durationi <= endi - starti + 1

题解:
方法:贪心+暴力

class Solution {
   
    public int findMinimumTime(int[][] tasks) {
   
        Arrays.sort(tasks, (a, b) -> a[1] - b[1]);
        int ans = 0;
        int mx = tasks[tasks.length - 1][1];
        boolean[] run = new boolean[mx + 1];
        for (int[] t : tasks) {
   
            int start = t[0];
            int end = t[1];
            int d = t[2];
            for (int i = start; i <= end; i++) {
   
                if (run[i]) {
   
                    d--; // 去掉运行中的时间点
                }
            }
            for (int i = end; d > 0; i--) {
    // 剩余的 d 填充区间后缀
                if (!run[i]) {
   
                    run[i] = true; // 运行
                    d--;
                    ans++;
                }
            }
        }
        return ans;
    }
}

16.你可以工作的最大周数

题目链接:1953. 你可以工作的最大周数

给你 n 个项目,编号从 0 到 n - 1 。同时给你一个整数数组 milestones ,其中每个 milestones[i] 表示第 i 个项目中的阶段任务数量。

你可以按下面两个规则参与项目中的工作:

每周,你将会完成 某一个 项目中的 恰好一个 阶段任务。你每周都 必须 工作。
在 连续的 两周中,你 不能 参与并完成同一个项目中的两个阶段任务。
一旦所有项目中的全部阶段任务都完成,或者仅剩余一个阶段任务都会导致你违反上面的规则,那么你将 停止工作 。注意,由于这些条件的限制,你可能无法完成所有阶段任务。

返回在不违反上面规则的情况下你 最多 能工作多少周。

示例 1:

输入:milestones = [1,2,3]

输出:6

解释:一种可能的情形是: ​​​​- 第 1 周,你参与并完成项目 0 中的一个阶段任务。

  • 第 2 周,你参与并完成项目 2 中的一个阶段任务。
  • 第 3 周,你参与并完成项目 1 中的一个阶段任务。
  • 第 4 周,你参与并完成项目 2 中的一个阶段任务。
  • 第 5 周,你参与并完成项目 1 中的一个阶段任务。
  • 第 6 周,你参与并完成项目 2 中的一个阶段任务。

总周数是 6 。

示例 2:

输入:milestones = [5,2,1]

输出:7

解释:一种可能的情形是:

  • 第 1 周,你参与并完成项目 0 中的一个阶段任务。
  • 第 2 周,你参与并完成项目 1 中的一个阶段任务。
  • 第 3 周,你参与并完成项目 0 中的一个阶段任务。
  • 第 4 周,你参与并完成项目 1 中的一个阶段任务。
  • 第 5 周,你参与并完成项目 0 中的一个阶段任务。
  • 第 6 周,你参与并完成项目 2 中的一个阶段任务。
  • 第 7 周,你参与并完成项目 0 中的一个阶段任务。

总周数是 7 。

注意,你不能在第 8 周参与完成项目 0 中的最后一个阶段任务,因为这会违反规则。

因此,项目 0 中会有一个阶段任务维持未完成状态。

提示:

n == milestones.length

1 <= n <= 105

1 <= milestones[i] <= 109

题解:
方法:贪心

class Solution {
   
    public long numberOfWeeks(int[] milestones) {
   
        long s = 0;
        int m = 0;
        for (int x : milestones) {
   
            s += x;
            m = Math.max(m, x);
        }
        return m > s - m + 1 ? (s - m) * 2 + 1 : s;
    }
}

17.安排工作以达到最大收益

题目链接:826. 安排工作以达到最大收益

你有 n 个工作和 m 个工人。给定三个数组: difficulty, profit 和 worker ,其中:

difficulty[i] 表示第 i 个工作的难度,profit[i] 表示第 i 个工作的收益。
worker[i] 是第 i 个工人的能力,即该工人只能完成难度小于等于 worker[i] 的工作。
每个工人 最多 只能安排 一个 工作,但是一个工作可以 完成多次 。

举个例子,如果 3 个工人都尝试完成一份报酬为 $1 的同样工作,那么总收益为 $3 。如果一个工人不能完成任何工作,他的收益为 $0 。
返回 在把工人分配到工作岗位后,我们所能获得的最大利润 。

示例 1:

输入: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker =
[4,5,6,7]

输出: 100

解释: 工人被分配的工作难度是 [4,4,6,6] ,分别获得 [20,20,30,30] 的收益。

示例 2:

输入: difficulty = [85,47,57], profit = [24,66,99], worker = [40,25,25]

输出: 0

提示:

n == difficulty.length

n == profit.length

m == worker.length

1 <= n, m <= 104

1 <= difficulty[i], profit[i], worker[i] <= 105

题解:
方法:排序

class Solution {
   
    public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
   
        int n = difficulty.length;
        int[][] jobs = new int[n][2];
        for (int i = 0; i < n; i++) {
   
            jobs[i][0] = difficulty[i];
            jobs[i][1] = profit[i];
        }
        Arrays.sort(jobs, (a, b) -> a[0] - b[0]);
        Arrays.sort(worker);
        int ans = 0, j = 0, maxProfit = 0;
        for (int w : worker) {
   
            while (j < n && jobs[j][0] <= w) {
   
                maxProfit = Math.max(maxProfit, jobs[j++][1]);
            }
            ans += maxProfit;
        }
        return ans;
    }
}

18.找出可整除性得分最大的整数

题目链接:2644. 找出可整除性得分最大的整数

给你两个下标从 0 开始的整数数组 nums 和 divisors 。

divisors[i] 的 可整除性得分 等于满足 nums[j] 能被 divisors[i] 整除的下标 j 的数量。

返回 可整除性得分 最大的整数 divisors[i] 。如果有多个整数具有最大得分,则返回数值最小的一个。

示例 1:

输入:nums = [4,7,9,3,9], divisors = [5,2,3]

输出:3

解释:divisors 中每个元素的可整除性得分为:

divisors[0] 的可整除性得分为 0 ,因为 nums 中没有任何数字能被 5 整除。

divisors[1] 的可整除性得分为 1 ,因为 nums[0] 能被 2 整除。

divisors[2] 的可整除性得分为 3 ,因为 nums[2]、nums[3] 和 nums[4] 都能被 3 整除。

因此,返回 divisors[2] ,它的可整除性得分最大。

示例 2:

输入:nums = [20,14,21,10], divisors = [5,7,5]

输出:5

解释:divisors 中每个元素的可整除性得分为:

divisors[0] 的可整除性得分为 2 ,因为 nums[0] 和 nums[3] 都能被 5 整除。

divisors[1] 的可整除性得分为 2 ,因为 nums[1] 和 nums[2] 都能被 7 整除。

divisors[2] 的可整除性得分为 2 ,因为 nums[0] 和 nums[3] 都能被5整除。

由于 divisors[0]、divisors[1] 和 divisors[2] 的可整除性得分都是最大的,因此,我们返回数值最小的一个,即
divisors[2] 。

示例 3:

输入:nums = [12], divisors = [10,16]

输出:10

解释:divisors 中每个元素的可整除性得分为:

divisors[0] 的可整除性得分为 0 ,因为 nums 中没有任何数字能被 10 整除。

divisors[1] 的可整除性得分为 0 ,因为 nums 中没有任何数字能被 16 整除。

由于 divisors[0] 和 divisors[1] 的可整除性得分都是最大的,因此,我们返回数值最小的一个,即 divisors[0]

提示:

1 <= nums.length, divisors.length <= 1000

1 <= nums[i], divisors[i] <= 109

题解:
方法:枚举

class Solution {
   
    public int maxDivScore(int[] nums, int[] divisors) {
   
        int ans = divisors[0];
        int mx = 0;
        for (int div : divisors) {
   
            int cnt = 0;
            for (int x : nums) {
   
                if (x % div == 0) {
   
                    ++cnt;
                }
            }
            if (mx < cnt) {
   
                mx = cnt;
                ans = div;
            } else if (mx == cnt) {
   
                ans = Math.min(ans, div);
            }
        }
        return ans;
    }
}

19.找出数组游戏的赢家

题目链接:1535. 找出数组游戏的赢家

给你一个由 不同 整数组成的整数数组 arr 和一个整数 k 。

每回合游戏都在数组的前两个元素(即 arr[0] 和 arr[1] )之间进行。比较 arr[0] 与 arr[1] 的大小,较大的整数将会取得这一回合的胜利并保留在位置 0 ,较小的整数移至数组的末尾。当一个整数赢得 k 个连续回合时,游戏结束,该整数就是比赛的 赢家 。

返回赢得比赛的整数。

题目数据 保证 游戏存在赢家。

示例 1:

输入:arr = [2,1,3,5,4,6,7], k = 2

输出:5

解释:一起看一下本场游戏每回合的情况:
image.png

因此将进行 4 回合比赛,其中 5 是赢家,因为它连胜 2 回合。

示例 2:

输入:arr = [3,2,1], k = 10

输出:3

解释:3 将会在前 10 个回合中连续获胜。 示例 3:

输入:arr = [1,9,8,2,3,7,6,4,5], k = 7

输出:9

示例 4:

输入:arr = [1,11,22,33,44,55,66,77,88,99], k = 1000000000

输出:99

提示:

2 <= arr.length <= 10^5

1 <= arr[i] <= 10^6

arr 所含的整数 各不相同 。

1 <= k <= 10^9

题解:
方法:模拟

class Solution {
   
    public int getWinner(int[] arr, int k) {
   
        int mx = arr[0];
        int win = 0;
        for (int i = 1; i < arr.length && win < k; i++) {
   
            if (arr[i] > mx) {
    // 新的最大值
                mx = arr[i];
                win = 0;
            }
            win++; // 获胜回合 +1
        }
        return mx;
    }
}

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


相关文章
|
24天前
|
人工智能 BI
|
1月前
|
测试技术 索引
【题解】—— LeetCode一周小结40
LeetCode每日一道一周小结40
【题解】—— LeetCode一周小结41
【题解】—— LeetCode一周小结41
|
2月前
|
算法
【题解】—— LeetCode一周小结36
LeetCode每日一道一周小结36
|
3月前
|
Perl
|
4月前
|
算法