Leetcode算法初学——动态规划算法“按摩师”
题目
一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 选择 1 号预约和 3 号预约,总时长 = 1 + 3 = 4。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 选择 1 号预约、 3 号预约和 5 号预约,总时长 = 2 + 9 + 1 = 12。
示例 3:
输入: [2,1,4,5,3,1,1,3]
输出: 12
解释: 选择 1 号预约、 3 号预约、 5 号预约和 8 号预约,总时长 = 2 + 4 + 3 + 3 = 12。
题解
拿到题的第一想法其实是遍历,思路是两种情况,从n开始或者从n-1开始往前走,标志符是i,按摩师每工作一次就重置一次标志位,然后直接比较标志位i-2和i-3的大小,遍历整个数组,然后两种情况比较最大值
1 class Solution { 2 public: 3 int massage(vector<int>& nums) { 4 int n1=0,n2=0;//n1为从nums[0]开始遍历的结果,n2为从nums[1]开始遍历的结果 5 int length=nums.size(); 6 for(int i=length-1;i>=0;) 7 { 8 if(i<=-1) 9 { 10 break; 11 } 12 n1=n1+nums[i]; 13 if(nums[i-2]>=nums[i-3]) 14 { 15 i=i-2; 16 } 17 else if(nums[i-2]<nums[i-3]) 18 { 19 i=i-3; 20 } 21 } 22 for(int i=length-1;i>=0;) 23 { 24 if(i<=-1) 25 { 26 break; 27 } 28 n2=n2+nums[i]; 29 if(nums[i-2]>=nums[i-3]) 30 { 31 i=i-2; 32 } 33 else if(nums[i-2]<nums[i-3]) 34 { 35 i=i-3; 36 } 37 } 38 return max(n1,n2); 39 } 40 };
但是这种写法会导致数组访问越位,无法通过leetcode的AddressSanitizer检测,所以这种思路仅供参考,目前我还没有想到相对完善不会产生数组访问越位的情况,也只是用vs测试了示例中的三个例子,都通过了测试,但是没有更多的例子让我发现问题,所以仅供参考,不建议采用。用了很长时间考虑动态规划,但是没有接触过这种需要考虑间隔的问题,实在没有办法就参考了大神的题解https://leetcode-cn.com/problems/the-masseuse-lcci/solution/dong-tai-gui-hua-by-liweiwei1419-8/大神已经在题解里把这道题分析的很清楚了,我觉得需要注意的点就是考虑数组长度为0和1的情况,还有最后是要比较nums[n]的工作状态和非工作状态的取值大小,返回最大值,我本人是因为忘记限定数组长度的特殊范围被报错两次,这里就只贴代码了
1 class Solution { 2 public: 3 int massage(vector<int>& nums) { 4 int length=nums.size(); 5 if(length==0) 6 { 7 return 0; 8 } 9 if(length==1) 10 { 11 return nums[0]; 12 } 13 int dp[length][2]; 14 dp[0][0]=0; 15 dp[0][1]=nums[0]; 16 for(int i=1;i<length;i++) 17 { 18 dp[i][0]=max(dp[i-1][0],dp[i-1][1]); 19 dp[i][1]=dp[i-1][0]+nums[i]; 20 } 21 return max(dp[length-1][0],dp[length-1][1]); 22 } 23 };
成功通过测试样例:
时间复杂度O(n),空间复杂度O(n)。
在这里记录一点自己的感想,本题难度仍为简单,我本来以为在已经有练习过几道题后,对于动态规划的题即使不是得心应手,费点时间也应该能自己独立ac,然而被现实教做人,每个算法不是表面上那么简单的,即使每道题解决的本质思路都相同,仍然会出现这样那样的情况让你无处下手,还是要多加练习,勉励自己。