题目描述:
一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。
注意:本题相对原题稍作改动
示例 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。
解题思路1:这道题我最开始考虑的是用贪婪算法或者是动态规划,然后每次选取最长时间,应该就可以获得整体最优解,但是最后我发现想要解决这种题最好理解的思路当然是蛮力的枚举算法,将每一种可能的结果列举出来,然后一一比较找到最大值即可。
所遇问题1:这种想法固然是好,但是检测超时,庞大的数据经不起我这样一一列举再对比。
public int massage(int[] nums) {
int res = findMax(0,nums);
return res;
}
//递归枚举
public int findMax(int i,int[] arr){
int res = 0;
//当选择超出预约总数时返回0
if (i >= arr.length){
return res;
}
//否则一一比较
for (int j = i; j < i+3; j++) {
if (j == arr.length){
break;
}
int t = j+2;
int temp = arr[j]+findMax(j+2,arr);
//System.out.print(temp+"-");
if(temp > res){
res = temp;
}
}
//System.out.println("->"+res);
return res;
}
这样递归的前提是,按摩师在休息之外所考虑的预约,最多不可能连续推掉三次,这个要好好理解一下,这才是算法思想的核心
解题思路2:我的整体思路是没问题的,我接下来的改进肯定应该是对于蛮力算法做出改进,少做无用功,把已经求过的最优路径把它记录下来,这样就不用反复的对一个路径做多次求解。所以我创建了一个记录数组brr[ ],先将数组全部置为-1,因为预约按摩的时间肯定不可能为负数,所以后面只需判断,brr[ i ]处的值是不是为-1就可知道该路径是不是已经求过最优解。
int brr[] = new int[200];
public int massage(int[] nums) {
for (int i = 0; i < brr.length; i++)
brr[i] = -1;
int res = findMax(0,nums);
return res;
}
public int findMax(int i,int[] arr){
int res = 0;
if (i >= arr.length){
return res;
}
for (int j = i; j < i+3; j++) {
if (j == arr.length){
break;
}
if (brr[j] == -1){
brr[j] = arr[j]+findMax(j+2,arr);
}
System.out.print(brr[j]+"-");
if(brr[j] > res){
res = brr[j];
}
}
System.out.println("->"+res);
return res;
}
原本我是没有对记录数组全部置为-1的,因为我认为不可能有人预约0分钟按摩,没想到题目的测试案例真的很丧心病狂,不仅有预约0分钟的,还有所有用户预约0分钟的,那如果是这种情况,我的记录数组就基本废掉了,又回到了第一种未优化的算法,每条路径都要反复求得多次。所以我才在调用算法前将记录数组全部置为负数。