力扣刷题44-46(力扣0062/0152/0198)

2024-03-26 14:12
文章标签 力扣 刷题 44 46 0062 0152 0198

本文主要是介绍力扣刷题44-46(力扣0062/0152/0198),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

62. 不同路径

题目描述:

一个机器人位于一个 m x n 网格的左上角 ,机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。问总共有多少条不同的路径?

思路:

其实就是问(0,0)->(m-1,n-1)一共有几条路。

第一个方法:数学上排列组合

第二个方法:

动态规划。抓住语句:机器人每次只能向下或者向右移动一步,所以动态规划转移方程为dp[i][j]=dp[i-1][j]+dp[i][j-1];考虑边界情况,dp[0][j],从(0,0)->(0,j)一共只有1条路(横着走)dp[i][0]同理只能竖着走。

所以代码如下:

class Solution {
public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m, vector<int>(n, 1)); // 初始化二维数组并将所有值初始化为1for(int i=1;i<m;i++){for(int j=1;j<n;j++){dp[i][j]=dp[i-1][j]+dp[i][j-1];}}return dp[m-1][n-1];}
};

本题over


152. 乘积最大子数组

题目描述:

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

思路:

哲哲这道题典型动态规划的背包问题。用dp[i][j]表示从i到j的最大结果,要求连续,可以重新开始,也可以是上一个的结果乘nums[j],来吧状态转移方程:dp[i][j]=max(nums[j],dp[i][j-1]*nums[j])。最后的结果就是返回dp数组里的最大值就可以。但还记得之前有一篇也是类似的做法,后来采用临时变量+max的方法,将复杂度降低么?所以这次依然尝试。

但是!!!显然我忘记了一件事负负得正这个问题。这样会存在跳过的情况。所以方案pass

 但还记得之前有一篇也是类似的做法,后来采用临时变量+max的方法,将复杂度降低么?所以这次依然尝试。(但这句话依然有效)

重新分析:

1.连续想乘,什么情况下会变小?1.*0 直接=0;2.*负数;但负数,会有一个负负得正的情况。所以我们不妨将负数的结果也存下来。

2.转移方程dp[i][j]=max(nums[j],dp[i][j-1]*nums[j])。设置为临时变量+max

于是有了方法:

在计算最大乘积时,我们同时考虑当前位置的值当前位置乘上前一个位置的最大乘积、当前位置乘上前一个位置的最小乘积这三种情况。

我们可以使用两个变量 max_prodmin_prod 来分别记录当前位置之前的最大乘积和最小乘积。然后我们遍历数组,对于每个位置的元素,更新 max_prodmin_prod,并根据当前位置的值、当前位置乘上前一个位置的最大乘积、当前位置乘上前一个位置的最小乘积这三者之间的关系来更新这两个变量。

具体的代码逻辑如下:
  • 用 max_prod 和 min_prod 分别记录当前位置之前的最大乘积和最小乘积,初始化为第一个元素 nums[0]
  • 从第二个元素开始遍历数组,对于每个位置的元素,如果该元素是负数,则交换 max_prod 和 min_prod,因为乘以负数会导致最大值变成最小值,最小值变成最大值。
  • 更新 max_prod 和 min_prod,分别取当前位置的值、当前位置乘上前一个位置的最大乘积、当前位置乘上前一个位置的最小乘积中的最大值和最小值。
  • 在更新 max_prod 的过程中,不断维护全局的最大乘积 result

通过这种方法,我们在遍历数组的过程中不断更新 max_prodmin_prodresult,最终得到的 result 就是乘积最大的子数组的乘积。

顺便举个例子:

假设给定数组 nums = [2, 3, -2, 4],我们来计算乘积最大的连续子数组。初始时,我们有:
max_prod = 2 (以第一个元素结尾的最大乘积)
min_prod = 2 (以第一个元素结尾的最小乘积)
result = 2 (全局最大乘积)接下来,我们依次遍历数组中的元素:对于第二个元素 3:
更新 max_prod = max(3, 2 * 3) = 6,min_prod = min(3, 2 * 3) = 3
更新 result = max(result, 6) = 6对于第三个元素 -2:
因为是负数,交换 max_prod 和 min_prod
更新 max_prod = max(-2, 6 * -2) = -2,min_prod = min(-2, 6* -2) = -12
更新 result = max(result, -2) = 6对于第四个元素 4:
更新 max_prod = max(4, -2 * 4) = 4,min_prod = min(4, -12 * 4) = -48
更新 result = max(result, 4) = 6
最终得到的结果是 6,即数组中乘积最大的连续子数组的乘积为 6。

代码如下:

class Solution {
public:int maxProduct(vector<int>& nums) {int n = nums.size();if (n == 0) return 0;int max_prod = nums[0];int min_prod = nums[0];int result = nums[0];for (int i = 1; i < n; i++) {if (nums[i] < 0) {swap(max_prod, min_prod);}max_prod = max(nums[i], max_prod * nums[i]);min_prod = min(nums[i], min_prod * nums[i]);result = max(result, max_prod);}return result;}
};

198. 打家劫舍

题目:

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

思路:

动态规划,当前一个偷完之后,下一个一定不能偷,但下下一个不一定。………………这样思考比较麻烦,不妨倒过来思考。

假设,我第k个房间,当前的值记为dp[k];则有两种情况:1,上一个房间我投过了,这个房间我不能投;2,上一个房间我没投,我投这个房间。所以dp就有以下表达式

dp[k]=max(dp[k-1],dp[k-2]+nums[k-1])

边界情况:

dp[0]=0; 
dp[1]=nums[0];dp[2]=max(nums[0],nums[1]);
//dp[2]=max(nums[0],dp[2-2]+nums[1]);

 推荐题解:. - 力扣(LeetCode) 

好,于是代码如下:(这个用常量优化有点难,所以先写不优化的)

class Solution {
public:int rob(vector<int>& nums) {int n=nums.size();if(n==0) return 0;if(n==1) return nums[0];vector<int>dp(n+1);dp[0]=0;//dp.push_back(0);//dp[1]=nums[0];dp[2]=max(nums[0],dp[0]+nums[1]);for(int i=3;i<=n;i++){dp[i]=max(dp[i-1],dp[i-2]+nums[i-1]);}return dp[n];}
};

性能太差,优化一下:

优化方法:两个常量+max;(前面两道题也是这样做的,要学会)

class Solution {
public:int rob(vector<int>& nums) {int n = nums.size();if (n == 0)return 0;if (n == 1)return nums[0];int prev1 = 0; // 用于存储偷窃到当前房屋的最大价值int prev2 = 0; // 用于存储偷窃到前一间房屋的最大价值for (int i = 0; i < n; ++i) {int temp = prev1; // 临时变量存储偷窃到当前房屋的最大价值prev1 =max(prev2 + nums[i], prev1); // 更新当前房屋的最大偷窃价值prev2 = temp; // 更新前一间房屋的最大偷窃价值}return prev1; // 返回最后一间房屋的偷窃价值即为最终答案}};

今日结束ocver


总结一下动态规划的模板吧

动态规划问题的一般解题思路可以总结为以下几个步骤:

  1. 定义状态:明确定义dp数组的含义,即每个元素dp[i]代表的是什么状态,可以是最大值、最小值等。

  2. 初始化:根据问题的要求对dp数组进行初始化,将初始条件赋给dp数组中相应的元素。

  3. 状态转移方程:找出状态之间的转移关系,即如何通过已知的状态推导出未知的状态。这是动态规划问题的核心,也是最难的部分。

  4. 递推计算:通过循环遍历或者递归的方式填充dp数组,根据状态转移方程更新每个位置的值。

  5. 返回结果:根据问题的要求从dp数组中得到最终的结果,可能是dp数组的最后一个元素,也可能是整个dp数组中的最大/最小值等。

代码:

// 初始化dp数组
vector<int> dp(n, initial_value);// 处理边界条件
dp[0] = initial_condition;// 状态转移方程计算dp数组的值
for (int i = 1; i < n; ++i) {// 根据状态转移方程更新dp[i]dp[i] = update_function(dp, i, other_parameters);
}// 返回最终结果
return final_result;

说在最后,

其实动态规划最核心的就是找出地推关系式。可以抽象的想第k个状态,往前倒退,找出关系式,用1,2,临街情况测试状态方程是否正确。最后再讲dp数组改进为常量,节省空间。

这篇关于力扣刷题44-46(力扣0062/0152/0198)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/848775

相关文章

两数之和--力扣1

两数之和 题目思路C++代码 题目 思路 根据题目要求,元素不能重复且不需要排序,我们这里使用哈希表unordered_map。注意题目说了只对应一种答案。 所以我们在循环中,使用目标值减去当前循环的nums[i],得到差值,如果我们在map中能够找到这个差值,就说明存在两个整数的和为目标值。 如果没有找到,就将当前循环的nums[i]以及下标i放入map中,以便后续查

【每日刷题】Day113

【每日刷题】Day113 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 91. 解码方法 - 力扣(LeetCode) 2. LCR 098. 不同路径 - 力扣(LeetCode) 3. 63. 不同路径 II - 力扣(LeetCode) 1. 91. 解码方法 - 力扣(LeetCode) //思路:动态规划。 cl

力扣第347题 前K个高频元素

前言 记录一下刷题历程 力扣第347题 前K个高频元素 前K个高频元素 原题目: 分析 我们首先使用哈希表来统计数字出现的频率,然后我们使用一个桶排序。我们首先定义一个长度为n+1的数组,对于下图这个示例就是长度为7的数组。为什么需要一个长度为n+1的数组呢?假如说总共有三个数字都为1,那么我们需要把这个1放在数组下标为3的位置,假如说数组长度为n,对于这个例子就是长度为3,那么它的

hot100刷题第1-9题,三个专题哈希,双指针,滑动窗口

求满足条件的子数组,一般是前缀和、滑动窗口,经常结合哈希表; 区间操作元素,一般是前缀和、差分数组 数组有序,更大概率会用到二分搜索 目前已经掌握一些基本套路,重零刷起leetcode hot 100, 套路题按套路来,非套路题适当参考gpt解法。 一、梦开始的地方, 两数之和 class Solution:#注意要返回的是数组下标def twoSum(self, nums: Lis

【数据结构与算法 | 灵神题单 | 删除链表篇】力扣3217, 82, 237

总结,删除链表节点问题使用到列表,哈希表,递归比较容易超时,我觉得使用计数排序比较稳,处理起来也不是很难。 1. 力扣3217:从链表中移除在数组中的节点 1.1 题目: 给你一个整数数组 nums 和一个链表的头节点 head。从链表中移除所有存在于 nums 中的节点后,返回修改后的链表的头节点。 示例 1: 输入: nums = [1,2,3], head = [1,2,3,

力扣 739. 每日温度【经典单调栈题目】

1. 题目 理解题意: 1.1. 给一个温度集合, 要返回一个对应长度的结果集合, 这个结果集合里面的元素 i 是 当前 i 位置的元素的下一个更高温度的元素的位置和当前 i 位置的距离之差, 若是当前元素不存在下一个更高温度的元素, 则这个位置用0代替; 2. 思路 本题用单调栈来求解;单调栈就适用于来求当前元素左边或者右边第一个比当前元素大或者小的元素;【单调栈:让栈中的元素保持单调

代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II

代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II 1.题目 1.1递增子序列 题目链接:491. 非递减子序列 - 力扣(LeetCode) 视频讲解:回溯算法精讲,树层去重与树枝去重 | LeetCode:491.递增子序列_哔哩哔哩_bilibili 文档讲解:https://programmercarl.com/0491.%E9%80%92%E

力扣接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]输出:6解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 示例 2: 输入:height

每日一题,力扣leetcode Hot100之238.除自身以外数组的乘积

乍一看这个题很简单,但是不能用除法,并且在O(N)时间复杂度完成或许有点难度。 考虑到不能用除法,如果我们要计算输出结果位置i的值,我们就要获取这个位置左边的乘积和右边的乘积,那么我新设立两个数组L和R。 对于L来说,由于表达的是位置i左边的数的乘积,那么L[0]=1,因为第一个数字左边没数那么为了不影响乘积初始值就设置为1,那么L[1]=L[0]*nums[0],那么L[i]=L[i-1

代码随想录刷题day24丨93.复原IP地址 ,78.子集 , 90.子集II

代码随想录刷题day24丨93.复原IP地址 ,78.子集 , 90.子集II 1.题目 1.1复原IP地址 题目链接:93. 复原 IP 地址 - 力扣(LeetCode) 视频讲解:回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址_哔哩哔哩_bilibili 文档讲解:https://programmercarl.com/0093.%E5%A4%8