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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM