题目一
测试链接:45. 跳跃游戏 II - 力扣(LeetCode)
分析:这道题用cur代表走完当前步数可以来到的最大长度,next代表如果多走一步可以来到的最大长度,然后遍历索引,如果当前步数可以来到的最大长度小于遍历到的索引,步数加1,最大长度更新为多走一步可以来到的最大长度,每一次遍历索引都会更新多走一步可以来到的最大长度。代码如下。
class Solution {
public:
int jump(vector<int>& nums) {
int length = nums.size();
int cur = 0;
int next = 0;
int ans = 0;
for(int i = 0;i < length;++i){
if(cur < i){
++ans;
cur = next;
}
next = max(i + nums[i], next);
}
return ans;
}
};
题目二
测试链接:1326. 灌溉花园的最少水龙头数目 - 力扣(LeetCode)
分析:这道题思路和上道题差不多,用一个数组存储左边界从i开始的水龙头范围最右可以到达的下标。cur为当前水龙头数可以覆盖的最右下标,next是如果多用一个水龙头可以覆盖的最右下标。遍历下标,每次遍历更新多用一个水龙头可以覆盖的最右下标。如果当前水龙头数可以覆盖的最右下标等于遍历到的下标则需要判断,如果多用一个水龙头可以覆盖的最右下标依旧等于当前下标,则代表即使多用一个水龙头,也不能覆盖住后一个范围,所以返回-1;否则多用一个水龙头,当前最右下标更新为多用一个水龙头的最右下标。代码如下。
class Solution {
public:
int right[10001] = {0};
int minTaps(int n, vector<int>& ranges) {
int start;
for(int i = 0;i <= n;++i){
start = max(0, i - ranges[i]);
right[start] = max(i + ranges[i], right[start]);
}
int cur = 0;
int next = 0;
int ans = 0;
for(int i = 0;i < n;++i){
next = max(next, right[i]);
if(cur == i){
if(next == i){
return -1;
}else{
++ans;
cur = next;
}
}
}
return ans;
}
};
题目三
测试链接:P1809 过河问题 - 洛谷
分析:这道题求最少渡河时间有两种方法,一种是让最少渡河时间依次和每一个人过到西岸,然后最少渡河时间划到东岸继续和另一个人渡河;另一种是让最小的两个渡河时间到西岸,然后最大的两个渡河时间一起到西岸,由西岸的最少渡河时间将船划到东岸。而具体是哪一种需要判断,所以需要使用动态规划。代码如下。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N;
vector<int> person;
vector<int> dp;
int main(void){
scanf("%d", &N);
person.resize(N);
for(int i = 0;i < N;++i){
scanf("%d", &person[i]);
}
if(N == 1){
printf("%d", person[0]);
}else if(N == 2){
printf("%d", max(person[0], person[1]));
}else{
dp.resize(N);
sort(person.begin(), person.end());
dp[0] = person[0];
dp[1] = person[1];
for(int i = 2;i < N;++i){
dp[i] = min(dp[i-1] + person[0] + person[i],
dp[i-2] + person[0] + person[i] + person[1] + person[1]);
}
printf("%d", dp[N-1]);
}
return 0;
}
其中,dp数组表示0~i都到西岸且船留在西岸的最少渡河时间,可能性的展开就是两种,一是让西岸的最小渡河时间将船划到东岸和剩下的i一起到西岸;另一种是让最小渡河时间将船划到东岸,在东岸的i-1和i一起到西岸,船由现在西岸的最小渡河时间划到东岸,然后东岸的两个人一起到西岸。
题目四
测试链接:517. 超级洗衣机 - 力扣(LeetCode)
分析:这道题可以遍历每一个洗衣机,以遍历到的洗衣机为中转站,看中转站左边需要多少衣服,中转站右边需要多少衣服,求出最多需要多少操作步数使左右两边需要的衣服和已有的衣服相等。然后取最大操作步数即是答案。代码如下。
class Solution {
public:
int findMinMoves(vector<int>& machines) {
int length = machines.size();
int sum = machines[0];
for(int i = 1;i < length;++i){
sum += machines[i];
}
if(sum % length != 0){
return -1;
}
machines.push_back(0);
int average = sum / length;
int ans = 0;
int left = 0, right = sum - machines[0];
int left_deserve = 0, right_deserve = (length - 1) * average;
int left_need = left_deserve - left, right_need = right_deserve - right;
for(int i = 0;i < length;++i){
if(left_need > 0 && right_need > 0){
ans = max(ans, left_need + right_need);
}else{
ans = max(ans, max(abs(left_need), abs(right_need)));
}
left += machines[i];
right -= machines[i+1];
left_deserve += average;
right_deserve -= average;
left_need = left_deserve - left;
right_need = right_deserve - right;
}
return ans;
}
};