[LeetCode] Smallest Rotation with Highest Score 得到最高分的最小旋轉


 

Given an array A, we may rotate it by a non-negative integer K so that the array becomes A[K], A[K+1], A{K+2], ... A[A.length - 1], A[0], A[1], ..., A[K-1].  Afterward, any entries that are less than or equal to their index are worth 1 point. 

For example, if we have [2, 4, 1, 3, 0], and we rotate by K = 2, it becomes [1, 3, 0, 2, 4].  This is worth 3 points because 1 > 0 [no points], 3 > 1 [no points], 0 <= 2 [one point], 2 <= 3 [one point], 4 <= 4 [one point].

Over all possible rotations, return the rotation index K that corresponds to the highest score we could receive.  If there are multiple answers, return the smallest such index K.

Example 1:
Input: [2, 3, 1, 4, 0]
Output: 3
Explanation:  
Scores for each K are listed below: 
K = 0,  A = [2,3,1,4,0],    score 2
K = 1,  A = [3,1,4,0,2],    score 3
K = 2,  A = [1,4,0,2,3],    score 3
K = 3,  A = [4,0,2,3,1],    score 4
K = 4,  A = [0,2,3,1,4],    score 3

So we should choose K = 3, which has the highest score.

 

Example 2:
Input: [1, 3, 0, 2, 4]
Output: 0
Explanation:  A will always have 3 points no matter how it shifts.
So we will choose the smallest K, which is 0.

Note:

  • A will have length at most 20000.
  • A[i] will be in the range [0, A.length].

 

這道題給了我們一個長度為N的數組,說是數組中的數字的范圍都在[0, N]之間,然后定義了一個旋轉操作,比如在位置K進行旋轉,數組在K位置斷開,新數組以A[k]為開頭數字,斷開的前半段數組直接拼到末尾即可。然后又定義了一種積分規則,說是如果某個坐標位置大於等於其數字的話,得1分,讓我們求出某個旋轉位置K,使得其積分最大,如果積分相同的話,取位置小的K。通過分析題目中的例子,發現題目並不難理解。博主首先嘗試了暴力搜索的方法,就是遍歷每個K值,生成旋轉后的數組,然后再統計得分,不幸掛掉了。那么我們必須要想出更好的解法才行。首先我們想,如果數組中的每個數字都跟其坐標值相同的話,比如[0, 1, 2, 3, 4],那么肯定得分最高,即K=0。但實際上並不會是有序的,而且並不是每個數字都會出現,題目中只給了數字的范圍,有可能會有重復數字哦。說實話這道題博主研究大神lee215的帖子,都研究了好久,最后終於有些明白了,就大概講講吧,如果有不對的地方歡迎大家指正。

這道題博主感覺還是很有難度的,而且答案的思路也十分巧妙,並沒有采用brute force那種直接求每一個K值的得分,而是反其道而行之,對於每個數字,探究其跟K值之間的聯系。首先我們要討論一下邊界情況,那么就是當A[i] = 0 或 N 的情況,首先如果A[i] = 0的話,那么0這個數字在任何位置都會小於等於坐標值,所以在任何位置都會得分的,那么其實可以忽略之,因為其不會對最大值產生任何影響,同理,如果A[i] = N的時候,由於長度為N的數組的坐標值范圍是[0, N-1],所以數字N在任何位置都不得分,同樣也不會對最大值產生任何影響,可以忽略之。那么我們關心的數字的范圍其實是[1, N-1]。在這個范圍內的數字在旋轉數組的過程中,從位置0變到N-1位置的時候,一定會得分,因為此范圍的數字最大就是N-1。這個一定得的分我們在最后統一加上,基於上面的發現,我們再來分析下題目中的例子 [2, 3, 1, 4, 0],其中紅色數字表示不得分的位置:

A:    2   3   1   4   0   (K = 0)

A:    3   1   4   0   2   (K = 1)

A:    1   4   0   2   3   (K = 2)

A:    4   0   2   3   1   (K = 3)

A:    0   2   3   1   4   (K = 4)

idx:  0   1   2   3   4

對於某個數字A[i],我們想知道其什么時候能旋轉到坐標位置為A[i]的地方,這樣就可以得分了。比如上面博主標記了紅色的數字3,最開始時的位置為1,此時是不得分的,我們想知道其什么時候能到位置3,答案是當K=3的時候,其剛好旋轉到位置3,K再增加的時候,其又開始不得分了。所以這個最后能得分的臨界位置是通過 (i - A[i] + N) % N 得到,那么此時如果K再增加1的話,A[i]就開始不得分了(如果我們suppose每個位置都可以得分,那么不得分的地方就可以當作是失分了),所以我們可以在這個剛好開始不得分的地方標記一下,通過-1進行標記,這個位置就是 (i - A[i] + 1 + N) % N。我們用一個長度為N的change數組,對於每個數字,我們都找到其剛好不得分的地方,進行-1操作,那么此時change[i]就表示數組中的數字在i位置會不得分的個數,如果我們仔細觀察上面紅色的數字,可以發現,由於是左移,坐標在不斷減小,所以原先失分的地方,在K+1的時候還是失分,除非你從開頭位置跑到末尾去了,那會得分,所以我們要累加change數組,並且K每增加1的時候,要加上額外的1,最后change數組中最大數字的位置就是要求的K值了,參見代碼如下:

 

解法一:

class Solution {
public:
    int bestRotation(vector<int>& A) {
        int n = A.size();
        vector<int> change(n, 0);
        for (int i = 0; i < n; ++i) change[(i - A[i] + 1 + n) % n] -= 1;
        for (int i = 1; i < n; ++i) change[i] += change[i - 1] + 1;
        return max_element(change.begin(), change.end()) - change.begin();
    }
};

 

我們也可以不用STL自帶的max_element函數,而是在遍歷的過程中同時找最大值即可,參見代碼如下: 

 

解法二:

class Solution {
public:
    int bestRotation(vector<int>& A) {
        int n = A.size(), res = 0;
        vector<int> change(n, 0);
        for (int i = 0; i < n; ++i) change[(i - A[i] + 1 + n) % n] -= 1;
        for (int i = 1; i < n; ++i) {
            change[i] += change[i - 1] + 1;
            res = (change[i] > change[res]) ? i : res;
        }
        return res;
    }
};

 

參考資料:

https://leetcode.com/problems/smallest-rotation-with-highest-score/discuss/121296/7-lines-C++-solution

https://leetcode.com/problems/smallest-rotation-with-highest-score/discuss/118725/Easy-and-Concise-5-lines-Solution-C++JavaPython?page=2

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

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



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