本文总结《剑指offer》中使用动态规划思路高效率解决问题的几个典型题目:
1、面试题47 礼物的最大价值
思路:首先,最简单的思路是使用递归逐步计算,但这样存在大量重复计算,该方法舍弃!
其次,我们想到构造一个辅助二维数组,数组中座标为(i,j)的元素表示到达座标为(i,j)的格子时能拿到的礼物价值总和的最大值。仔细想一下,其实在二维数组中存储的很多元素是我们并不需要的。比如座标(i,j)处的值只取决于(i-1,j)和(i, j-1)两个位置的元素。所以我们可以继续简化为一维辅助数组,代码实现如下:
package offer.coder;
/**
*
* @author FHY
* 礼物的最大价值,动态规划实现
*/
public class GetMaxValueDemo47_2 {
public static void main(String[] args) {
int[][] arr = {{1,10,3,8},{12,2,9,6},{5,7,4,11},{3,7,16,5}};
System.out.println(getMaxValue(arr));
}
private static int getMaxValue(int[][] arr) {
if(arr.length == 0 || arr[0].length == 0){
return 0;
}
int rows = arr.length;
int cols = arr[0].length;
int[] maxArr = new int [cols];
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
int left = 0;
int up = 0;
if(j > 0)
up = maxArr[j - 1];
if(i > 0)
left = maxArr[j];
maxArr[j] = max(up, left) + arr[i][j];
}
}
return maxArr[cols - 1];
}
private static int max(int a, int b) {
return a > b ? a : b;
}
}
2、最长不含重复字符的子字符串
思路:该题我们已知字符串中的字母都是‘a’-'z'之间的字符,一共26个,所以我们借助一个长度为26的一维辅助数组(position)存储对应元素在数组中最近一次出现的位置。
如果当前元素在position数组中对应值为-1 或者 当前元素位置与该元素最近一次出现的位置 距离distance > 当前子串长度,则当前元素可加入子串,子串长度+1,继续往下走。
否则,distance < 当前子串长度,说明当前元素在子串中出现过了,则当前元素不能加入子串。
代码如下:
package offer.coder;
public interface TheMaxNoRepeatString48 {
public static void main(String[] args) {
System.out.println(getMaxNoRepeatString("arabcacfr"));
}
public static int getMaxNoRepeatString(String str){
if("".equals(str) || str.length() == 0){
return 0;
}
int[] position = new int[26];
//初始化位置数组position
for(int i = 0; i < position.length; i++){
position[i] = -1;
}
int maxLength = 0;
int curLength = 0;
for(int i = 0; i < str.length(); i++){
int index = str.charAt(i) - 'a'; // 定位元素在数组中的下标
int prePosition = position[index]; // 上一个元素出现的位置
int distance = i - prePosition; // 计算此次出现距上次出现的距离
if(prePosition < 0 || distance > curLength) //距离>当前长度 ; 忽略,长度+1,继续判断下一个元素
curLength++;
else
curLength = distance;
maxLength = maxLength > curLength ? maxLength : curLength;
position[index] = i;
}
return maxLength ;
}
}