欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > 力扣10.19

力扣10.19

2024/10/24 5:20:37 来源:https://blog.csdn.net/qq_40052678/article/details/143077260  浏览:    关键词:力扣10.19

3192. 使二进制数组全部等于 1 的最少操作次数 II

给你一个二进制数组 nums 。

你可以对数组执行以下操作 任意 次(也可以 0 次):

选择数组中 任意 一个下标 i ,并将从下标 i 开始一直到数组末尾 所有 元素 反转 。
反转 一个元素指的是将它的值从 0 变 1 ,或者从 1 变 0 。

请你返回将 nums 中所有元素变为 1 的 最少 操作次数。

数据范围

  • 1 <= nums.length <= 105
  • 0 <= nums[i] <= 1

分析

考虑10110这个元素,要使下标为[2:]的元素均为1,必须得先把[3:]的元素变为0,因此考虑从尾向头遍历,若当前位置为1且不是首部,则反转它和后面的,若当前位置为0,也进行翻转

代码

class Solution {
public:int minOperations(vector<int>& nums) {int n = nums.size();int res = 0;for(int i = n - 1; i >= 0; i -- ) {int j = i;while(j >= 0) {if(nums[j] == nums[i]) j -- ;else break;}i = j + 1;if(nums[i] == 1 && i != 0) res ++ ;else if(nums[i] == 0) res ++ ;  }return res;}
};

741. 摘樱桃

给你一个 n x n 的网格 grid ,代表一块樱桃地,每个格子由以下三种数字的一种来表示:

  • 0 表示这个格子是空的,所以你可以穿过它。

  • 1 表示这个格子里装着一个樱桃,你可以摘到樱桃然后穿过它。

  • -1 表示这个格子里有荆棘,挡着你的路。
    请你统计并返回:在遵守下列规则的情况下,能摘到的最多樱桃数:

  • 从位置 (0, 0) 出发,最后到达 (n - 1, n - 1) ,只能向下或向右走,并且只能穿越有效的格子(即只可以穿过值为 0 或者 1 的格子);

  • 当到达 (n - 1, n - 1) 后,你要继续走,直到返回到 (0, 0) ,只能向上或向左走,并且只能穿越有效的格子;

  • 当你经过一个格子且这个格子包含一个樱桃时,你将摘到樱桃并且这个格子会变成空的(值变为 0 );

  • 如果在 (0, 0) 和 (n - 1, n - 1) 之间不存在一条可经过的路径,则无法摘到任何一个樱桃。

数据范围

  • n == grid.length
  • n == grid[i].length
  • 1 <= n <= 50
  • grid[i][j] 为 -1、0 或 1
  • grid[0][0] != -1
  • grid[n - 1][n - 1] != -1

分析

( 0 , 0 ) (0,0) (0,0)出发到 ( n − 1 , n − 1 ) (n-1,n-1) (n1,n1)再返回 ( 0 , 0 ) (0,0) (0,0),可以相当于从两个机器人同时从(0,0)出发到达 ( n − 1 , n − 1 ) (n-1,n-1) (n1,n1),观察一下数据范围,只有50,因此可以直接将两个机器人的状态作为dp,令 d p [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] dp[x1][y1][x2][y2] dp[x1][y1][x2][y2]表示机器人1和2分别位于 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x1,y1),(x2,y2) (x1,y1),(x2,y2)时收集的樱桃总和,使用记忆化搜索的方式会更加简单

  • d f s ( x 1 , y 1 , x 2 , y 2 ) = m a x ( d f s ( x 1 , y 1 − 1 , x 2 , y 2 − 1 ) , d f s ( x 1 , y 1 − 1 , x 2 − 1 , y 2 ) , d f s ( x 1 − 1 , y 1 , x 2 − 1 , y 2 ) , d f s ( x 1 − 1 , y 1 , x 2 , y 2 − 1 ) + c dfs(x1,y1,x2,y2)=max(dfs(x1,y1-1,x2,y2-1), dfs(x1,y1-1,x2-1,y2), dfs(x1-1,y1,x2-1,y2), dfs(x1-1,y1,x2,y2-1)+c dfs(x1,y1,x2,y2)=max(dfs(x1,y11,x2,y21),dfs(x1,y11,x21,y2),dfs(x11,y1,x21,y2),dfs(x11,y1,x2,y21)+c,c为这次当前位置两个机器人收获的樱桃

代码

class Solution {
public:const static int N = 55;int dp[N][N][N][N];int dx[2] = {0, 1};int dy[2] = {1, 0};int n, m;int dfs(int x1, int y1, int x2, int y2, vector<vector<int>>& grid) {if(x1 == n - 1 && y1 == m - 1 && x2 == n - 1 && y2 == m - 1) return grid[x1][y1];if(x1 < 0 || x2 < 0 || x1 >= n || x2 >= n || y1 < 0 || y2 < 0 || y1 >= m || y2 >= m) return -0x3f3f3f3f;if(grid[x1][y1] == -1 || grid[x2][y2] == -1) return -0x3f3f3f3f;int& t = dp[x1][y1][x2][y2];if(t != -1) return t;t = 0;int c;if(x1 == x2 && y1 == y2) c = grid[x1][y1];else c = grid[x1][y1] + grid[x2][y2];int tmpt = -0x3f3f3f3f;for(int i = 0; i < 2; i ++ ) {for(int j = 0; j < 2; j ++ ) {tmpt = max(tmpt, dfs(x1 + dx[i], y1 + dy[i], x2 + dx[j], y2 + dy[j], grid));}}t = tmpt + c;return t;}int cherryPickup(vector<vector<int>>& grid) {n = grid.size();m = grid[0].size();memset(dp, -1, sizeof(dp));int res = dfs(0, 0, 0, 0, grid);if(res < 0) return 0;return res;}
};

2915. 和为目标值的最长子序列的长度

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

返回和为 target 的 nums 子序列中,子序列 长度的最大值 。如果不存在和为 target 的子序列,返回 -1 。

子序列 指的是从原数组中删除一些或者不删除任何元素后,剩余元素保持原来的顺序构成的数组。

数据范围

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 1000
  • 1 <= target <= 1000

分析

01背包,将每个数的价值看作是1,背包容量为target,令dp[i][j]为前i个数容量正好为j是的长度,这道题和普通01背包不同就在于需要正好是j,因此需要将其他的不合法状态设置为一个极小值,其他就按照正常01背包套路来写,然后可以利用轮动数组优化一下

代码

class Solution {
public:const static int N = 1005;int dp[N];int lengthOfLongestSubsequence(vector<int>& nums, int target) {int n = nums.size();memset(dp, -0x3f, sizeof(dp));dp[0] = 0;for(int i = 0; i < n; i ++ ) {for(int j = target; j >= nums[i]; j -- ) {dp[j] = max(dp[j], dp[j - nums[i]] + 1);}}return dp[target] < 0 ? -1 : dp[target];}
};

2787. 将一个数字表示成幂的和的方案数

给你两个 正 整数 nx

请你返回将 n 表示成一些 互不相同 正整数的 x 次幂之和的方案数。换句话说,你需要返回互不相同整数 [n1, n2, ..., nk] 的集合数目,满足 n = n1x + n2x + ... + nkx

由于答案可能非常大,请你将它对 109 + 7 取余后返回。

比方说,n = 160x = 3,一个表示 n 的方法是 n = 23 + 33 + 53

数据范围

  • 1 <= n <= 300
  • 1 <= x <= 5

分析

令dp[i][j]为前i个数的x次方里,满足总和为j的方案数,由于n最大为300,因此快速幂处理i的x次方时可以将超过300的部分返回301,接下来是状态转移

  • d p [ i ] [ j ] + = d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j − q p o w ( i , x ) ] dp[i][j]+=dp[i-1][j]+dp[i-1][j-qpow(i,x)] dp[i][j]+=dp[i1][j]+dp[i1][jqpow(i,x)]
    同样这题可以通过滚动数组进行优化

代码

typedef long long LL;
class Solution {
public:const static int N = 305, mod = 1e9 + 7;int dp[N];LL qpow(LL a, LL n) {LL res = 1;while(n) {if(res > 300 || a  > 300) return 301;if(n & 1) res = res * a;a = a * a;n >>= 1;}return res;}int numberOfWays(int n, int x) {dp[0] = 1;for(int i = 1; i <= n; i ++ ) {for(int j = n; j >= qpow(i, x); j -- ) {dp[j] += dp[j - qpow(i,x)];dp[j] %= mod;}}return dp[n];}
};

3180. 执行操作可获得的最大总奖励 I

给你一个整数数组 rewardValues,长度为 n,代表奖励的值。

最初,你的总奖励 x0,所有下标都是 未标记 的。你可以执行以下操作 任意次 :

  • 从区间 [0, n - 1] 中选择一个 未标记 的下标 i。
  • 如果 rewardValues[i] 大于 你当前的总奖励 x,则将 rewardValues[i] 加到 x 上(即x = x + rewardValues[i]),并 标记 下标 i。
    以整数形式返回执行最优操作能够获得的 最大 总奖励。

数据范围

  • 1 <= rewardValues.length <= 2000
  • 1 <= rewardValues[i] <= 2000

分析

  • 首先,若先选最大的数,那就选不了小的数,因此贪心的思路肯定是从小往大选,先排序

  • 考虑最大的值会不会选,假如不选,则将选的最大值替换为全局最大值一定会更优,因此最大值一定被选,假设最大值为k,则前 n − 1 n-1 n1个物品就构成了01背包问题。

  • 接下来考虑背包容量,体积和价值分别是什么,首先,要想装下最后一个数k,因此前面的价值之和不能超过 k − 1 k-1 k1,因此背包容量为 k − 1 k-1 k1体积和价值都为数的大小

  • 接下来考虑状态定义,令dp[i][j]为前i个数,总体积不超过j时价值的最大值

  • 然后是状态转移,对前n-1个数进行01背包,但这里需要注意,原始的01背包是 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w ] + v ) dp[i][j]=max(dp[i-1][j],dp[i-1][j-w]+v) dp[i][j]=max(dp[i1][j],dp[i1][jw]+v),即分为选或不选两种情况,若选则从上一个状态j-w转移过来,但这题有限制, d p [ i − 1 ] [ j − w ] dp[i-1][j-w] dp[i1][jw]的价值不一定比w小,因此状态转移暂定如下

    • d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ c ] + w ) dp[i][j]=max(dp[i-1][j],dp[i-1][c]+w) dp[i][j]=max(dp[i1][j],dp[i1][c]+w)
  • 接下来考虑 c c c的取值,首先,本体价值和体积相同,因此对于状态 d p [ i ] [ w ] dp[i][w] dp[i][w],其价值v必然不会大于 w w w,考虑到这一点,上一个状态 j − w j-w jw的价值也不会大于 j − w j-w jw,因此对 j − w j-w jw进行讨论

    • j − w > = w j-w>=w jw>=w,此时 c c c w − 1 w-1 w1,因为最大不能取j-w
    • j − w < w j-w<w jw<w,此时 c c c j − w j-w jw
  • 最终答案为 d p [ n − 1 ] [ k − 1 ] + k dp[n-1][k-1]+k dp[n1][k1]+k
    同样这题可以用滚动数组进行优化
    下面的代码1为没有空间优化的代码,代码2进行轮动数组优化

代码1

class Solution {
public:const static int N = 2005;int dp[N][N];int maxTotalReward(vector<int>& rewardValues) {int n = rewardValues.size();sort(rewardValues.begin(), rewardValues.end());int t = rewardValues.back();for(int i = 0; i < n - 1; i ++ ) {for(int j = 0; j < t; j ++ ) {dp[i + 1][j] = dp[i][j];if(j >= rewardValues[i]) {int c;if(j - rewardValues[i] >= rewardValues[i]) c = rewardValues[i] - 1;else c = j - rewardValues[i];dp[i + 1][j] = max(dp[i][j], dp[i][c] + rewardValues[i]);}}}return dp[n - 1][t - 1] + t;}
};

代码2

class Solution {
public:const static int N = 2005;int dp[N];int maxTotalReward(vector<int>& rewardValues) {int n = rewardValues.size();sort(rewardValues.begin(), rewardValues.end());int t = rewardValues.back();for(int i = 0; i < n - 1; i ++ ) {for(int j = t - 1; j >= rewardValues[i]; j -- ) {int c;if(j - rewardValues[i] >= rewardValues[i]) c = rewardValues[i] - 1;else c = j - rewardValues[i];dp[j] = max(dp[j], dp[c] + rewardValues[i]);}}return dp[t - 1] + t;}
};

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com