135.Candy---貪心

題目連接數組

題目大意:分糖果,每一個小朋友都有一個ratings值,且每一個小朋友至少都要有一個糖果,並且每一個小朋友的ratings值若是比左右鄰舍的小朋友的ratings值高,則其糖果數量也比鄰舍的小朋友多。ide

法一:超時。按照要求,從前日後比較每一個小朋友的ratings值,若是後一個小朋友的ratings值比前一個大,則更新小朋友糖果值dp[i]=dp[i-1]+1;不然,將當前小朋友的糖果值置1,而後考察其前一個小朋友糖果值是否知足dp[i-1]<=dp[i],且ratings[i-1]>ratings[i],若是知足這兩個條件,則說明前小朋友的糖果值須要更新,且須要循環遍歷更新前面小朋友的糖果值。o(n^2)。代碼以下:spa

 1     public int candy(int[] ratings) {
 2         int len = ratings.length;
 3         if(len == 0) {
 4             return 0;
 5         }
 6         else if(len == 1) {
 7             return 1;
 8         }
 9         int[] dp = new int[len];
10         //初始化第一個小夥伴的糖果值
11         dp[0] = ratings[0] <= ratings[1] ? 1 : 2;
12         int cnt = 0;
13         for(int i = 1; i < len; i++) {
14             //只與前面小夥伴的ratings進行比較
15             if(ratings[i] > ratings[i - 1]) {
16                 dp[i] = dp[i - 1] + 1;
17             }
18             else {
19                 dp[i] = 1;
20                 //若是前面小夥伴的糖果是1,且ratings比較高,則遍歷其前面的全部小夥伴
21                 if(dp[i - 1] == 1 && ratings[i - 1] > ratings[i]) {
22                     //更新前面的小夥伴的糖果值,由於這個更新,對於這種用例5,3,1,這個小夥伴前面的全部糖果值都要更新,因此進入下面的for循環進行判斷
23                     dp[i - 1] = 2;
24                     for(int j = i - 2; j >= 0; j--) {
25                         //若是前面的小夥伴的糖果值小,且ratings又比較高,則更新其值
26                         if(ratings[j] > ratings[j + 1] && dp[j] <= dp[j + 1]) {
27                             dp[j] = dp[j + 1] + 1;
28                         }
29                         else {
30                             break;
31                         }
32                     }
33                 }
34             }
35         }
36         //計算全部的糖果值
37         for(int i = 0; i < len; i++) {
38             cnt += dp[i];
39         }
40         return cnt;
41     }
View Code

法二(借鑑):兩個數組,一個數組從前日後遍歷,一旦ratings值比前一個大,則dp[i]=dp[i-1]+1;一個數組從後往前遍歷,一旦ratings值比後一個大,則dp[i]=dp[i+1]+1。最後從這兩個數組中取一個較大者,計算最終糖果值。o(n)。固然也能夠用一個數組,可是思想邏輯都是同樣的,只是若是用一個數組的話,就是從後往前遍歷獲得的新值與當前數組值進行比較,取較大者就是了。代碼以下(耗時5ms):3d

 1     public int candy(int[] ratings) {
 2         int len = ratings.length;
 3         if(len == 0) {
 4             return 0;
 5         }
 6         else if(len == 1) {
 7             return 1;
 8         }
 9         int[] left_candy = new int[len];
10         int[] right_candy = new int[len];
11         //初始化
12         left_candy[0] = ratings[0] <= ratings[1] ? 1 : 2;
13         right_candy[len - 1] = ratings[len - 1] <= ratings[len - 2] ? 1 : 2;
14         //從前日後遍歷
15         for(int i = 1; i < len; i++) {
16             if(ratings[i] > ratings[i - 1]) {
17                 left_candy[i] = left_candy[i - 1] + 1;
18             }
19             else {
20                 left_candy[i] = 1;
21             }
22         }
23         //從後往前遍歷
24         for(int j = len - 2; j >= 0; j--) {
25             if(ratings[j] > ratings[j + 1]) {
26                 right_candy[j] = right_candy[j + 1] + 1;
27             }
28             else {
29                 right_candy[j] = 1;
30             }
31         }
32         //二者中取較大者,計算糖果值
33         int cnt = 0;
34         for(int i = 0; i < len; i++) {
35             cnt += Math.max(left_candy[i], right_candy[i]);
36         }
37         return cnt;
38     }
View Code

法三(借鑑):最優解。只遍歷一遍,o(n)。一旦遍歷到遞減rating,則計數遞減的個數,而暫停計算其糖果值;當遍歷到遞增rating時,則開始計算前面遞減的小朋友的糖果值,以及當前小朋友的糖果值。具體註釋看代碼。代碼以下(耗時5ms):code

 1     public int candy(int[] ratings) {
 2         int first = 1, cnt = 0, res = 1, len = ratings.length;
 3         for(int i = 1; i < len; i++) {
 4             //若是比前一個小朋友rating高,則計算總糖果值
 5             if(ratings[i] >= ratings[i - 1]) {
 6                 //若是當前小朋友前面有遞減rating,先處理這幾個小朋友的糖果值
 7                 if(cnt > 0) {
 8                     //從遞減的第二個數開始,到最後一個遞減rating結束爲止,這幾個小朋友的糖果總值就是cnt * (cnt + 1) / 2
 9                     res += cnt * (cnt + 1) / 2;
10                     //處理開始遞減的第一個數,即將其須要增長的糖果數cnt-res+1,加入res中
11                     if(cnt >= first) {
12                         res += cnt - first + 1;
13                     }
14                     //重置
15                     cnt = 0;
16                     first = 1;
17                 }
18                 //對於當前第i個小朋友,正常計算其糖果值,將其加入res結果中
19                 first = (ratings[i] == ratings[i - 1]) ? 1 : first + 1;
20                 res += first;
21             }
22             //計數遞減rating的個數
23             else {
24                 cnt++;
25             }
26         }
27         //處理最後一組遞減rating,而其後沒有再反彈的小夥伴,即一直遞減,不知足ratings[i] >= ratings[i - 1]就到數組終結
28         if(cnt > 0) {
29             res += cnt * (cnt + 1) / 2;
30             if(cnt >= first) {
31                 res += cnt - first + 1;
32             }
33         }
34         return res;
35     }
View Code
相關文章
相關標籤/搜索