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     }
View Code

 

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     }
View Code

 

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     }
View Code

 

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     }
View Code

 

GITHUB:

https://github.com/yuzhangcmu/LeetCode_algorithm/blob/master/algorithm/dp/MinAdjustmentCost_Class.java

posted on 2014-12-09 18:47  Yu's Garden  阅读(6622)  评论(7编辑  收藏  举报

导航