兩個例子,使用動態規划算法解決
第一個例子是LeetCode題目:
面試題 17.16:
按摩師一個有名的按摩師會收到源源不斷的預約請求,每個預約都可以選擇接或不接。在每次預約服務之間要有休息時間,因此她不能接受相鄰的預約。給定一個預約請求序列,替按摩師找到最優的預約集合(總預約時間最長),返回總的分鍾數。
遞歸方法 :
public static int rec_opt(int []arr,int i){
//遞歸終止的條件,意味着如果只能選第一個,那么最好的方法就是arr[0]
if(i==0)
return arr[0];
//處理特殊情況,因為題目要求間隔選擇
else if(i==1)
return Math.max(arr[0],arr[1]);
else{
int a = rec_opt(arr,i-2) + arr[i]; //對於每一個顧客無非兩種情況,選或者不選,如果選的話,就是,i-2個的最優解加上當前的value
int b = rec_opt(arr,i-1); //如果不選,那么就只能使用上一個的最優解
return Math.max(a,b); //最后比較兩種情況,得出當前情況的最優解
}
}
非遞歸方法 :
public static int dp_opt(int []arr){
int len =arr.length;
if(len == 0) return 0;
if(len == 1) return arr[0];
int []opt = new int[len];
opt[0]=arr[0];
opt[1]=Math.max(arr[1],arr[0]);
for(int i=2;i<len;i++){
int a = opt[i-2] + arr[i]; //對於每一個顧客無非兩種情況,選或者不選,如果選的話,就是,i-2個的最優解加上當前的value
int b = opt[i-1]; //如果不選,那么就只能使用上一個的最優解
opt[i] = Math.max(a,b); //最后比較兩種情況,得出當前情況的最優解
}
return opt[len-1];
}
第二個例子:
給定一個數組和一個數字,如果數組中存在一個或多個數字相加可以得到該數字,則返回true,得不到則返回false(ps:暫時不考慮數組中有負數,和給的數字是負數的情況)
遞歸方法:
public static boolean rec_subset(int []nums,int i,int s){ //傳進來的是len-1表示,從后往前找可能的情況
if(s==0) return true; //如果s等於0表示已經找到了需要的數字
else if(i==0) return nums[0]==s; //如果找到了最后一個數字,也就是數組中的第一個數字,那么如果這個數與s不等,也就說明,該種情況不可能
else if(nums[i]>s) return rec_subset(nums,i-1,s); //如果當前數字大於s也就沒必要找這個分支,直接進入不用該數字的分支
else{
boolean a = rec_subset(nums,i-1,s-nums[i]); //對於每一個數字無非有兩種情況,選他和不選他,選他,就遞歸調用,求之前的數組中有無數字相加得到s-nums[i]
boolean b = rec_subset(nums,i-1,s); //不選:求之前的數組,有無數字相加得到s
return a||b;
}
}
非遞歸方法 :
public static boolean dp_subset(int []nums,int S){
if(S<=0) return false; //暫且不考慮小於等於零的情況
int len = nums.length;
boolean [][]subset = new boolean[len][S+1]; //新建二維數組保存子問題結果
for(int i=0;i<S+1;i++) subset[0][i]=false; //初始化第一行
for(int i=0;i<len;i++) subset[i][0]=true; //初始化第一列
subset[0][nums[0]] = true;
for(int i=1;i<len;i++)
for(int s=1;s<S+1;s++)
if(nums[i]>s) //如果當前數字大於s也就沒必要找這個分支,直接進入不用該數字的分支
subset[i][s] = subset[i-1][s];
else
subset[i][s] = subset[i-1][s-nums[i]] || subset[i-1][s]; //兩種情況的判斷
return subset[len-1][S];
}
另外推薦學習b站正月點燈籠的動態規划教學視頻.