LeetCode 每日一题 Day 158-166

2079. 给植物浇水

你打算用一个水罐给花园里的 n 株植物浇水。植物排成一行,从左到右进行标记,编号从 0 到 n - 1 。其中,第 i 株植物的位置是 x = i 。x = -1 处有一条河,你可以在那里重新灌满你的水罐。

每一株植物都需要浇特定量的水。你将会按下面描述的方式完成浇水:

按从左到右的顺序给植物浇水。
在给当前植物浇完水之后,如果你没有足够的水 完全 浇灌下一株植物,那么你就需要返回河边重新装满水罐。
你 不能 提前重新灌满水罐。
最初,你在河边(也就是,x = -1),在 x 轴上每移动 一个单位 都需要 一步 。

给你一个下标从 0 开始的整数数组 plants ,数组由 n 个整数组成。其中,plants[i] 为第 i 株植物需要的水量。另有一个整数 capacity 表示水罐的容量,返回浇灌所有植物需要的 步数 。

示例 1:

输入:plants = [2,2,3,3], capacity = 5
输出:14
解释:从河边开始,此时水罐是装满的:

  • 走到植物 0 (1 步) ,浇水。水罐中还有 3 单位的水。
  • 走到植物 1 (1 步) ,浇水。水罐中还有 1 单位的水。
  • 由于不能完全浇灌植物 2 ,回到河边取水 (2 步)。
  • 走到植物 2 (3 步) ,浇水。水罐中还有 2 单位的水。
  • 由于不能完全浇灌植物 3 ,回到河边取水 (3 步)。
  • 走到植物 3 (4 步) ,浇水。
    需要的步数是 = 1 + 1 + 2 + 3 + 3 + 4 = 14 。
    示例 2:

输入:plants = [1,1,1,4,2,3], capacity = 4
输出:30
解释:从河边开始,此时水罐是装满的:

  • 走到植物 0,1,2 (3 步) ,浇水。回到河边取水 (3 步)。
  • 走到植物 3 (4 步) ,浇水。回到河边取水 (4 步)。
  • 走到植物 4 (5 步) ,浇水。回到河边取水 (5 步)。
  • 走到植物 5 (6 步) ,浇水。
    需要的步数是 = 3 + 3 + 4 + 4 + 5 + 5 + 6 = 30 。
    示例 3:

输入:plants = [7,7,7,7,7,7,7], capacity = 8
输出:49
解释:每次浇水都需要重新灌满水罐。
需要的步数是 = 1 + 1 + 2 + 2 + 3 + 3 + 4 + 4 + 5 + 5 + 6 + 6 + 7 = 49 。

提示:

n == plants.length
1 <= n <= 1000
1 <= plants[i] <= 106
max(plants[i]) <= capacity <= 1e9

模拟即可:

class Solution {
public:
    int wateringPlants(vector<int>& plants, int capacity) {
        int n = plants.size();
        int ans = n;
        int water = capacity;
        for (int i = 0; i < n; i++) {
            if (water < plants[i]) {
                ans += i * 2;
                water = capacity;
            }
            water -= plants[i];
        }
        return ans;
    }
};

2960. 统计已测试设备

给你一个长度为 n 、下标从 0 开始的整数数组 batteryPercentages ,表示 n 个设备的电池百分比。

你的任务是按照顺序测试每个设备 i,执行以下测试操作:

如果 batteryPercentages[i] 大于 0:
增加 已测试设备的计数。
将下标在 [i + 1, n - 1] 的所有设备的电池百分比减少 1,确保它们的电池百分比 不会低于 0 ,即 batteryPercentages[j] = max(0, batteryPercentages[j] - 1)。
移动到下一个设备。
否则,移动到下一个设备而不执行任何测试。
返回一个整数,表示按顺序执行测试操作后 已测试设备 的数量。

示例 1:

输入:batteryPercentages = [1,1,2,1,3]
输出:3
解释:按顺序从设备 0 开始执行测试操作:
在设备 0 上,batteryPercentages[0] > 0 ,现在有 1 个已测试设备,batteryPercentages 变为 [1,0,1,0,2] 。
在设备 1 上,batteryPercentages[1] == 0 ,移动到下一个设备而不进行测试。
在设备 2 上,batteryPercentages[2] > 0 ,现在有 2 个已测试设备,batteryPercentages 变为 [1,0,1,0,1] 。
在设备 3 上,batteryPercentages[3] == 0 ,移动到下一个设备而不进行测试。
在设备 4 上,batteryPercentages[4] > 0 ,现在有 3 个已测试设备,batteryPercentages 保持不变。
因此,答案是 3 。
示例 2:

输入:batteryPercentages = [0,1,2]
输出:2
解释:按顺序从设备 0 开始执行测试操作:
在设备 0 上,batteryPercentages[0] == 0 ,移动到下一个设备而不进行测试。
在设备 1 上,batteryPercentages[1] > 0 ,现在有 1 个已测试设备,batteryPercentages 变为 [0,1,1] 。
在设备 2 上,batteryPercentages[2] > 0 ,现在有 2 个已测试设备,batteryPercentages 保持不变。
因此,答案是 2 。

提示:

1 <= n == batteryPercentages.length <= 100
0 <= batteryPercentages[i] <= 100

还是模拟:

class Solution {
public:
    int countTestedDevices(vector<int>& batteryPercentages) {
        int dec = 0;
        for (int x : batteryPercentages) {
            dec += x > dec;
        }
        return dec;
    }
};

2391. 收集垃圾的最少总时间

给你一个下标从 0 开始的字符串数组 garbage ,其中 garbage[i] 表示第 i 个房子的垃圾集合。garbage[i] 只包含字符 ‘M’ ,‘P’ 和 ‘G’ ,但可能包含多个相同字符,每个字符分别表示一单位的金属、纸和玻璃。垃圾车收拾 一 单位的任何一种垃圾都需要花费 1 分钟。

同时给你一个下标从 0 开始的整数数组 travel ,其中 travel[i] 是垃圾车从房子 i 行驶到房子 i + 1 需要的分钟数。

城市里总共有三辆垃圾车,分别收拾三种垃圾。每辆垃圾车都从房子 0 出发,按顺序 到达每一栋房子。但它们 不是必须 到达所有的房子。

任何时刻只有 一辆 垃圾车处在使用状态。当一辆垃圾车在行驶或者收拾垃圾的时候,另外两辆车 不能 做任何事情。

请你返回收拾完所有垃圾需要花费的 最少 总分钟数。

示例 1:

输入:garbage = [“G”,“P”,“GP”,“GG”], travel = [2,4,3]
输出:21
解释:
收拾纸的垃圾车:

  1. 从房子 0 行驶到房子 1
  2. 收拾房子 1 的纸垃圾
  3. 从房子 1 行驶到房子 2
  4. 收拾房子 2 的纸垃圾
    收拾纸的垃圾车总共花费 8 分钟收拾完所有的纸垃圾。
    收拾玻璃的垃圾车:
  5. 收拾房子 0 的玻璃垃圾
  6. 从房子 0 行驶到房子 1
  7. 从房子 1 行驶到房子 2
  8. 收拾房子 2 的玻璃垃圾
  9. 从房子 2 行驶到房子 3
  10. 收拾房子 3 的玻璃垃圾
    收拾玻璃的垃圾车总共花费 13 分钟收拾完所有的玻璃垃圾。
    由于没有金属垃圾,收拾金属的垃圾车不需要花费任何时间。
    所以总共花费 8 + 13 = 21 分钟收拾完所有垃圾。
    示例 2:

输入:garbage = [“MMM”,“PGM”,“GP”], travel = [3,10]
输出:37
解释:
收拾金属的垃圾车花费 7 分钟收拾完所有的金属垃圾。
收拾纸的垃圾车花费 15 分钟收拾完所有的纸垃圾。
收拾玻璃的垃圾车花费 15 分钟收拾完所有的玻璃垃圾。
总共花费 7 + 15 + 15 = 37 分钟收拾完所有的垃圾。

提示:

2 <= garbage.length <= 105
garbage[i] 只包含字母 ‘M’ ,‘P’ 和 ‘G’ 。
1 <= garbage[i].length <= 10
travel.length == garbage.length - 1
1 <= travel[i] <= 100

哈希遍历:

class Solution {
public:
    int garbageCollection(vector<string>& garbage, vector<int>& travel) {
        unordered_map<char, int> last;
        int ans = 0;
        for (int i = 0; i < garbage.size(); ++i) {
            auto& s = garbage[i];
            ans += s.size();
            for (char& c : s) {
                last[c] = i;
            }
        }
        int ts = 0;
        for (int i = 1; i <= travel.size(); ++i) {
            ts += travel[i - 1];
            for (auto& [_, j] : last) {
                if (i == j) {
                    ans += ts;
                }
            }
        }
        return ans;
    }
};

1553. 吃掉 N 个橘子的最少天数

厨房里总共有 n 个橘子,你决定每一天选择如下方式之一吃这些橘子:

吃掉一个橘子。
如果剩余橘子数 n 能被 2 整除,那么你可以吃掉 n/2 个橘子。
如果剩余橘子数 n 能被 3 整除,那么你可以吃掉 2*(n/3) 个橘子。
每天你只能从以上 3 种方案中选择一种方案。

请你返回吃掉所有 n 个橘子的最少天数。

示例 1:

输入:n = 10
输出:4
解释:你总共有 10 个橘子。
第 1 天:吃 1 个橘子,剩余橘子数 10 - 1 = 9。
第 2 天:吃 6 个橘子,剩余橘子数 9 - 2*(9/3) = 9 - 6 = 3。(9 可以被 3 整除)
第 3 天:吃 2 个橘子,剩余橘子数 3 - 2*(3/3) = 3 - 2 = 1。
第 4 天:吃掉最后 1 个橘子,剩余橘子数 1 - 1 = 0。
你需要至少 4 天吃掉 10 个橘子。
示例 2:

输入:n = 6
输出:3
解释:你总共有 6 个橘子。
第 1 天:吃 3 个橘子,剩余橘子数 6 - 6/2 = 6 - 3 = 3。(6 可以被 2 整除)
第 2 天:吃 2 个橘子,剩余橘子数 3 - 2*(3/3) = 3 - 2 = 1。(3 可以被 3 整除)
第 3 天:吃掉剩余 1 个橘子,剩余橘子数 1 - 1 = 0。
你至少需要 3 天吃掉 6 个橘子。
示例 3:

输入:n = 1
输出:1
示例 4:

输入:n = 56
输出:6

提示:

1 <= n <= 2*10^9

哈希+DP:

class Solution {
public:
    unordered_map<int, int> dp;
    int minDays(int n) {
        if (n <= 1) {
            return n;
        }
        if (dp.count(n) == 0) {
            dp[n] = 1 + min(n % 2 + minDays(n / 2), n % 3 + minDays(n / 3));
        }
        return dp[n];
    }
};

994. 腐烂的橘子

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

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

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

示例 1:

输入: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

虽然是mid题,还是不会做,bfs做的太少了orz:

class Solution {
    int DIRECTIONS[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 四方向

public:
    int orangesRotting(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        int fresh = 0;
        vector<pair<int, int>> q;
        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.emplace_back(i, j); // 一开始就腐烂的橘子
                }
            }
        }

        int ans = -1;
        while (!q.empty()) {
            ans++; // 经过一分钟
            vector<pair<int, int>> nxt;
            for (auto& [x, y] : q) {        // 已经腐烂的橘子
                for (auto d : DIRECTIONS) { // 四方向
                    int i = x + d[0], j = y + d[1];
                    if (0 <= i && i < m && 0 <= j && j < n &&
                        grid[i][j] == 1) { // 新鲜橘子
                        fresh--;
                        grid[i][j] = 2; // 变成腐烂橘子
                        nxt.emplace_back(i, j);
                    }
                }
            }
            q = move(nxt);
        }

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

灵神题解:多源 BFS

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 <= 1e5
1 <= tasks[i] <= 1e9

贪心+哈希:

class Solution {
public:
    int minimumRounds(vector<int>& tasks) {
        unordered_map<int, int> cnt;
        for (int t : tasks) {
            cnt[t]++;
        }
        int res = 0;
        for (auto [_, v] : cnt) {
            if (v == 1) {
                return -1;
            } else if (v % 3 == 0) {
                res += v / 3;
            } else {
                res += v / 3 + 1;
            }
        }
        return res;
    }
};

2589. 完成所有任务的最少时间(Hard)

你有一台电脑,它可以 同时 运行无数个任务。给你一个二维整数数组 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(vector<vector<int>>& tasks) {
        ranges::sort(tasks, [](auto& a, auto& b) { return a[1] < b[1]; });
        int ans = 0;
        vector<int> run(tasks.back()[1] + 1);
        for (auto& t : tasks) {
            int start = t[0], end = t[1], d = t[2];
            d -= reduce(run.begin() + start,
                        run.begin() + end + 1); // 去掉运行中的时间点
            for (int i = end; d > 0; i--) { // 剩余的 d 填充区间后缀
                if (!run[i]) {
                    run[i] = true; // 运行
                    d--;
                    ans++;
                }
            }
        }
        return ans;
    }
};

灵神题解:三种方法:暴力/线段树/栈+二分

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 <= 1e5
1 <= milestones[i] <= 1e9

贪心:

class Solution {
public:
    long long numberOfWeeks(vector<int>& milestones) {
        long long s = reduce(milestones.begin(), milestones.end(), 0LL);
        long long m = ranges::max(milestones);
        return m > s - m + 1 ? (s - m) * 2 + 1 : s;
    }
};

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XforeverZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值