分治法(持续更新中)
自上而下的分治法可以使用结合记忆化搜索,亦等于自下而上的动态规划。
241.为运算表达式设计优先级
public List<Integer> diffWaysToCompute(String expression) {
// 分治法
// 统计可能的结果
List<Integer> list = new ArrayList<>();
// 遇到 + - * 符号就左右计算
int n = expression.length();
for(int i=0;i<n;i++){
Character c = expression.charAt(i);
if(c == '+' || c == '-' || c == '*'){
List<Integer> left = diffWaysToCompute(expression.substring(0,i));
List<Integer> right = diffWaysToCompute(expression.substring(i+1,n));
for(int l:left){
for(int r:right){
if(c == '+'){
list.add(l+r);
}else if(c == '-'){
list.add(l-r);
}else{
list.add(l*r);
}
}
}
}
}
// 当此时expresssion不含运算符号时,添加当前记录的数字返回
if(list.size() == 0){
list.add(Integer.parseInt(expression));
}
return list;
}
312.戳气球
public int maxCoins(int[] nums) {
// 自上而下的分治法 == 自下而上的动态规划
// 定义辅助数组,两边补1,方便处理边界问题
int[] temp = new int[nums.length+2];
temp[0] = 1;
temp[nums.length+1] = 1;
for(int i=0;i<nums.length;i++){
temp[i+1] = nums[i];
}
// 定义数组 dp[i][j] 表示 i和j区间的 气球所能取得的最大硬币数量 return dp[0][temp.length-1];
int[][] dp = new int[temp.length+1][temp.length+1];
// 递推公式
// i表示当前区间的长度
for(int i=3;i<=temp.length;i++){
// j表示当前区间的左端点
for(int j=0;j<=temp.length-i;j++){
// 记录当前循环后的最大值
int res = 0;
// j+i-1 表示左端点+区间长度-1 === 最大右端点位置
// k表示
for(int k=j+1;k<j+i-1;k++){
int left = dp[j][k];
int right = dp[k][j+i-1];
res = Math.max(res, left + temp[j]*temp[k]*temp[j+i-1] + right);
}
// 左端点j,右端点j+i-1
dp[j][j+i-1] = res;
}
}
return dp[0][temp.length-1];
}