Lintcode: Minimum Adjustment Cost 解题报告
Minimum Adjustment Cost
Given an integer array, adjust each integers so that the difference of every adjcent integers are not greater than a given number target.
If the array before adjustment is A, the array after adjustment is B, you should minimize the sum of |A[i]-B[i]|
You can assume each number in the array is a positive integer and not greater than 100
Given [1,4,2,3] and target=1, one of the solutions is [2,3,2,3], the adjustment cost is 2 and it's minimal. Return 2.
原题链接:http://lintcode.com/zh-cn/problem/minimum-adjustment-cost/#
SOL 1:
主页君现在最喜欢这种题目了。好兴奋啊!
好啦,我们先上第一个版本,递归版本:
当前可取的值是1-100,并且与上一个值是在target的差值以内。
这个版本肯定是超时啦。因为我们有大量的重复的计算,每一次从头至尾计算时,从某个index开始的某个取值的计算会反复进行。
1 /** 2 * @param A: An integer array. 3 * @param target: An integer. 4 */ 5 public static int MinAdjustmentCost1(ArrayList<Integer> A, int target) { 6 // write your code here 7 if (A == null) { 8 return 0; 9 } 10 11 return rec(A, new ArrayList<Integer>(A), target, 0); 12 } 13 14 /* 15 * SOL 1: 16 * 最普通的递归方法。 17 * */ 18 public static int rec(ArrayList<Integer> A, ArrayList<Integer> B, int target, int index) { 19 int len = A.size(); 20 if (index >= len) { 21 // The index is out of range. 22 return 0; 23 } 24 25 int dif = 0; 26 27 int min = Integer.MAX_VALUE; 28 29 // If this is the first element, it can be from 1 to 100; 30 for (int i = 0; i <= 100; i++) { 31 if (index != 0 && Math.abs(i - B.get(index - 1)) > target) { 32 continue; 33 } 34 35 B.set(index, i); 36 dif = Math.abs(i - A.get(index)); 37 dif += rec(A, B, target, index + 1); 38 min = Math.min(min, dif); 39 40 // 回溯 41 B.set(index, A.get(index)); 42 } 43 44 return min; 45 }
SOL 2:
我们还是跟以前一样,加一个memory,减少重复计算。
轻松AC. M[i][j]的定义是:从index = i处开始往后所有的differ,并且A[i]的取值取为j + 1;
1 /* 2 * 递归2: 3 * Rec + memory. 4 * */ 5 /** 6 * @param A: An integer array. 7 * @param target: An integer. 8 */ 9 public static int MinAdjustmentCost2(ArrayList<Integer> A, int target) { 10 // write your code here 11 if (A == null || A.size() == 0) { 12 return 0; 13 } 14 15 int[][] M = new int[A.size()][100]; 16 for (int i = 0; i < A.size(); i++) { 17 for (int j = 0; j < 100; j++) { 18 M[i][j] = Integer.MAX_VALUE; 19 } 20 } 21 22 return rec2(A, new ArrayList<Integer>(A), target, 0, M); 23 } 24 25 public static int rec2(ArrayList<Integer> A, ArrayList<Integer> B, int target, int index, 26 int[][] M) { 27 int len = A.size(); 28 if (index >= len) { 29 // The index is out of range. 30 return 0; 31 } 32 33 int dif = 0; 34 int min = Integer.MAX_VALUE; 35 36 // If this is the first element, it can be from 1 to 100; 37 for (int i = 1; i <= 100; i++) { 38 if (index != 0 && Math.abs(i - B.get(index - 1)) > target) { 39 continue; 40 } 41 42 if (M[index][i - 1] != Integer.MAX_VALUE) { 43 dif = M[index][i - 1]; 44 min = Math.min(min, dif); 45 continue; 46 } 47 48 B.set(index, i); 49 dif = Math.abs(i - A.get(index)); 50 dif += rec2(A, B, target, index + 1, M); 51 52 min = Math.min(min, dif); 53 54 // Record the result. 55 M[index][i - 1] = dif; 56 57 // 回溯 58 B.set(index, A.get(index)); 59 } 60 61 return min; 62 }
SOL 3:修改了一下,递归增加一个参数 : int x,表示在index 处A[i]取值为x,返回值的意义是,当此值取x时,从index往后,所有的diff之和。
这样的话,递归会看起来更加简洁一点儿。我们不需要记录上一个A[i]的取值。
1 /* 2 * SOLUTION 3 递归2: 3 * Rec + memory. 4 * 改进的递归版本 5 * */ 6 /** 7 * @param A: An integer array. 8 * @param target: An integer. 9 */ 10 public static int MinAdjustmentCost3(ArrayList<Integer> A, int target) { 11 // write your code here 12 if (A == null || A.size() == 0) { 13 return 0; 14 } 15 16 int[][] M = new int[A.size()][100]; 17 for (int i = 0; i < A.size(); i++) { 18 for (int j = 0; j < 100; j++) { 19 M[i][j] = Integer.MAX_VALUE; 20 } 21 } 22 23 // 首个数字可以取1-100 24 int min = Integer.MAX_VALUE; 25 for (int i = 1; i <= 100; i++) { 26 min = Math.min(min, rec3(A, target, 0, i, M)); 27 } 28 29 return min; 30 } 31 32 /* 33 * 将当前值设置为x能求得的最小解 34 * */ 35 public static int rec3(ArrayList<Integer> A, int target, int index, int x, 36 int[][] M) { 37 int len = A.size(); 38 if (index >= len) { 39 // The index is out of range. 40 return 0; 41 } 42 43 if (M[index][x - 1] != Integer.MAX_VALUE) { 44 return M[index][x - 1]; 45 } 46 47 int bas = Math.abs(x - A.get(index)); 48 int min = Integer.MAX_VALUE; 49 50 // 对下一个值尝试取1-100 51 for (int i = 1; i <= 100; i++) { 52 // 下一个值的取值不可以超过abs 53 if (index != len - 1 && Math.abs(i - x) > target) { 54 continue; 55 } 56 57 // 计算dif 58 int dif = bas + rec3(A, target, index + 1, i, M); 59 min = Math.min(min, dif); 60 } 61 62 // Record the result. 63 M[index][x - 1] = min; 64 return min; 65 }
SOL 4:
LALA,主页君终于来打BOSS了。有了前面的递归的铺垫,把它转化为一个二维DP也就是水到渠成了。
D[i][v]: 把index = i的值修改为v,所需要的最小花费
我们引用一下九章算法黄老师课上的课件:
其实很简单,就是当前index为v时,我们把上一个index从1-100全部过一次,取其中的最小值(判断一下前一个跟当前的是不是abs <= target)
1 /* 2 * SOLUTION 4: 3 * DP 4 * */ 5 /** 6 * @param A: An integer array. 7 * @param target: An integer. 8 */ 9 public static int MinAdjustmentCost(ArrayList<Integer> A, int target) { 10 // write your code here 11 if (A == null || A.size() == 0) { 12 return 0; 13 } 14 15 // D[i][v]: 把index = i的值修改为v,所需要的最小花费 16 int[][] D = new int[A.size()][101]; 17 18 int size = A.size(); 19 20 for (int i = 0; i < size; i++) { 21 for (int j = 1; j <= 100; j++) { 22 D[i][j] = Integer.MAX_VALUE; 23 if (i == 0) { 24 // The first element. 25 D[i][j] = Math.abs(j - A.get(i)); 26 } else { 27 for (int k = 1; k <= 100; k++) { 28 // 不符合条件 29 if (Math.abs(j - k) > target) { 30 continue; 31 } 32 33 int dif = Math.abs(j - A.get(i)) + D[i - 1][k]; 34 D[i][j] = Math.min(D[i][j], dif); 35 } 36 } 37 } 38 } 39 40 int ret = Integer.MAX_VALUE; 41 for (int i = 1; i <= 100; i++) { 42 ret = Math.min(ret, D[size - 1][i]); 43 } 44 45 return ret; 46 }
GITHUB:
posted on 2014-12-09 18:47 Yu's Garden 阅读(6622) 评论(7) 编辑 收藏 举报