​welcome to my blog​

程序员面试金典 17.16 按摩师 (Java版; Easy)

题目描述

一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,
因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。

注意:本题相对原题稍作改动



示例 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。

第一次做; 动态规划, 时间复杂度O(N) 核心:1)注意dp[i]的含义和返回值之间的关系 2)递推公式dp[i]和dp[i-?], 以及需要几个dp[i-?]都是需要明确的

class Solution {
public int massage(int[] nums) {
int n = nums.length;
if(n==0){
return 0;
}
/*
dp[i][0]表示[0,i]范围上不选nums[i]的最长预约时间
dp[i][1]表示[0,i]范围上选nums[i]的最长预约时间

dp[i][0] = max(dp[i-1][0], dp[i-1][1])
*/
int[][] dp = new int[n][2];
dp[0][0] = 0;
dp[0][1] = nums[0];
for(int i=1; i<n; i++){
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1]);
dp[i][1] = dp[i-1][0] + nums[i];
}

return Math.max(dp[n-1][0], dp[n-1][1]);
}
}

第一次做; 动态规划, 时间复杂度O(N^2) 核心: 1)dp[i]表示以nums[i]结尾时的最长预约时间; 计算dp[i]时必须以nums[i]结尾, 否则就没法计算状态转移了 2)注意dp[i]的含义和返回值之间的关系!注意dp[i]的含义和返回值之间的关系!注意dp[i]的含义和返回值之间的关系! 不要无脑返回dp[n-1]

class Solution {
public int massage(int[] nums) {
if(nums==null || nums.length==0){
return 0;
}
int n = nums.length;
/*
选或者不选, 一共是2^N种可能

dp[i]表示以nums[i]结尾时的最长预约时间; nums[i]一定要选!
dp[i] = max{dp[0,...,i-2]+nums[i]}

最大值并不一定在dp[n-1]处, 因为dp[i]的含义是以num[i]结尾时的最大值! 所以max可能是任何一个dp[i]
*/
int[] dp = new int[n];
// for(int i=0; i<n; i++){
// dp[i] = nums[i];
// }
int max = dp[0];
for(int i=0; i<n; i++){
dp[i] = nums[i];
for(int j=0; j<i-1; j++){
dp[i] = Math.max(dp[i], dp[j]+nums[i]);
}
max = Math.max(max, dp[i]);
}
return max;
}
}