LeetCode 798 - Smallest Rotation with Highest Score


https://leetcode.com/problems/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].
https://leetcode.com/problems/smallest-rotation-with-highest-score/discuss/118725/C%2B%2BJavaPython-Solution-with-Explanation
Don't calculate the score for K=0, we don't need it at all.
(I see almost all other solutions did)
The key point is to find out how score changes when K++
Time complexity:
“A will have length at most 20000.”
I think it means you should find a O(N) solution.
How dosen score change when K++ ?
  • Get point
    Each time when we rotate, we make index 0 to index N-1, then we get one more point.
    We know that for sure, so I don't need to record it.
  • Lose point
    (i - A[i] + N) % N is the value of K making A[i]'s index just equal to A[i].
    For example, If A[6] = 1, then K = (6 - A[6]) % 6 = 5 making A[6] to index 1 of new array.
    So when K=5, we get this point for A[6]
    Then if K is bigger when K = (i - A[i] + 1) % N, we start to lose this point, making our score -= 1
    All I have done is record the value of K for all A[i] where we will lose points.
  • A[i]=0
    Rotation makes no change for it, becasue we alwars have 0 <= index.
    However, it is covered in "get point" and "lose point".
Explanation of codes


  1. Search the index where score decrease and record this changement to a list change.
  2. A simple for loop to calculate the score for every K value.
    score[K] = score[K-1] + change[K]
    In my codes I accumulated changes so I get the changed score for every K value compared to K=0
  3. Find the index of best score.


    public int bestRotation(int[] A) {
        int N = A.length;
        int change[] = new int[N];
        for (int i = 0; i < N; ++i) change[(i - A[i] + 1 + N) % N] -= 1;
        int max_i = 0;
        for (int i = 1; i < N; ++i) {
            change[i] += change[i - 1] + 1;
            max_i = change[i] > change[max_i] ? i : max_i;
        }
        return max_i;
    }
https://leetcode.com/articles/smallest-rotation-with-highest-score/
Say N = 10 and A[2] = 5. Then there are 5 rotations that are bad for this number: rotation indexes 0, 1, 2, 8, 9 - these rotations will cause this number to not get 1 point later.
In general, for each number in the array, we can map out what rotation indexes will be bad for this number. It will always be a region of one interval, possibly two if the interval wraps around (eg. 8, 9, 0, 1, 2wraps around, to become [8, 9] and [0, 1, 2].)
At the end of plotting these intervals, we need to know which rotation index has the least intervals overlapping it - this one is the answer.
Algorithm
First, an element like A[2] = 5 will not get score in (up to) 5 posiitons: when the 5 is at final index 0, 1, 2, 3, or 4. When we shift by 2, we'll get final index 0. If we shift 5-1 = 4 before this, this element will end up at final index 4. In general (modulo N), a shift of i - A[i] + 1 to i will be the rotation indexes that will make A[i] not score a point.
If we are trying to plot an interval like [2, 3, 4], then instead of doing bad[2]--; bad[3]--; bad[4]--;, what we will do instead is keep track of the cumulative total: bad[2]--; bad[5]++. For "wrap-around" intervals like [8, 9, 0, 1, 2], we will keep track of this as two separate intervals: bad[8]--, bad[10]++, bad[0]--, bad[3]++. (Actually, because of our implementation, we don't need to remember the bad[10]++ part.)
At the end, we want to find a rotation index with the least intervals overlapping. We'll maintain a cumulative total cur representing how many intervals are currently overlapping our current rotation index, then update it as we step through each rotation index.

public int bestRotation(int[] A) {
    int N = A.length;
    int[] bad = new int[N];
    for (int i = 0; i < N; ++i) {
        int left = (i - A[i] + 1 + N) % N;
        int right = (i + 1) % N;
        bad[left]--;
        bad[right]++;
        if (left > right)
            bad[0]--;
    }

    int best = -N;
    int ans = 0, cur = 0;
    for (int i = 0; i < N; ++i) {
        cur += bad[i];
        if (cur > best) {
            best = cur;
            ans = i;
        }
    }
    return ans;
}
https://leetcode.com/problems/smallest-rotation-with-highest-score/discuss/118839/Simple-Java-O(n)-Solution
The trick of this problem is to convert it into finding most overlap interval problem (like meeting room II, finding most airplanes at a time)
    public int bestRotation(int[] A) {
        int n = A.length;
        int[] a = new int[n];  // to record interval start/end
        for (int i = 0; i < A.length; i++) {
            a[(i + 1) % n]++;             // interval start
            a[(i + 1 - A[i] + n) % n]--;  // interval end
        }
        int count = 0;
        int maxCount = -1;
        int res = 0;
        for (int i = 0; i < n; i++) {  // find most overlap interval
            count += a[i];
            if (count > maxCount) {
                res = i;
                maxCount = count;
            }
        }
        return res;
    }
https://leetcode.com/problems/smallest-rotation-with-highest-score/discuss/118671/Java-O(n)Time-O(n)-Space-Solution
Let's go through an example first. If the input is{2,4,1,3,0}, We write down all status when rotate k steps.
Number:::::: 2 4 1 3 0
k = 0 index: 0 1 2 3 4
k = 1 index: 4 0 1 2 3
k = 2 index: 3 4 0 1 2
k = 3 index: 2 3 4 0 1
k = 4 index: 1 2 3 4 0
If we look in each column, then index for one particular number is somehow decrease with a valley(0). We want to know in which K steps the index is greate or equal than the corresponding number. For number 2, k should be{1,2,3}, for number 1, k should be{0,1,3,4}.
So our task is to collect all k rows in which the index >= number for each paritular number.
  1. If number > index in original array:
    As index is decreasing, so we need to find in which row the index is equals to (length - 1), the largest index of array. Then go down until index == number.
  2. If number <= index in original array:
    k = 0 is always valid, and 0 through the row in which index == number is the last valid row. Also, don't forget the index == len - 1 this corner case;
There are some math tricks from maybe high school: largest index row = (index + 1) % len; Row in which index == number = (index + len - num) % len;
We just need to update count[min] and count[max] to avoid O(n) time to record our result.
    public int bestRotation(int[] A) {
        int[] count = new int[A.length + 1];
        int len = A.length;
        for(int index = 0; index < A.length; index ++){
            int num = A[index];
            if(index < num){
                int maxLenK = (index + 1) % len;
                int ori = (index + len - num) % len;
                count[maxLenK] ++;
                count[ori + 1] --;
            }else{      // index >= num
                int ori = (index + len - num) % len;
                count[0] ++;
                count[ori + 1] --;
                if(index != len - 1){
                    count[(index + 1) % len] ++;
                    count[len] --;
                }
            }
        }
        int max = count[0];
        int res = 0;
        for(int i = 1; i < len; i ++){
            count[i] = count[i] + count[i - 1];
            if(count[i] > max){
                max = count[i];
                res = i;
            }            
        }
        return res;
    }

(区间标记) O(n)
  1. 对于每个数字,求出其能得分的轮调区间。比如样例 1 中下标为 1 位置的数字 3,其能得分的轮调区间为 [2, 3]。再比如下标为 2 的数字 1,其能得分的区间有两段,分别为 [0, 1] 和 [3, 4]
  2. 具体地,每个数字最多有两段能得分的区间。假设数组长度为 n,对于在下标为 i 位置的数字 A[i],如果 A[i] >= n,则得分区间不存在;在 A[i] < n 的情况下,如果 A[i] > i,则得分区间为 [i + 1, i + n - A[i]];如果 A[i] < i,则得分区间为 [0, i - A[i]] 和 [i + 1, n - 1]
  3. 得到了每个数的合法区间,我们通过区间标记的方法求出得分最大的点。如果 [l, r] 是一个得分区间,则我们标记 valid[l]++ 且 valid[r + 1]--,然后求出 valid 数组的前缀和。数组中最大值的点就是得分最大的点。

https://www.acwing.com/solution/LeetCode/content/2552/
给定一个数组 A,我们可以将它按一个非负整数 K 进行轮调,这样可以使数组变为 A[K], A[K+1], A[K+2], ... A[A.length - 1], A[0], A[1], ..., A[K-1] 的形式。此后,任何值小于或等于其索引的项都可以记作 1 分。
例如,如果数组为 [2, 4, 1, 3, 0],我们按 K = 2 进行轮调后,它将变成 [1, 3, 0, 2, 4]。这将记作 3 分,因为 1 > 0 [没有得分], 3 > 1 [没有得分], 0 <= 2 [1 分], 2 <= 3 [1 分], 4 <= 4 [1 分]。
在所有可能的轮调中,返回我们所能得到的最高分数对应的轮调索引 K。如果有多个答案,返回满足条件的最小的索引 K。

样例

输入:[2, 3, 1, 4, 0]
输出:3
解释:
下面列出了每个 K 的得分:
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
所以我们应当选择 K = 3,得分最高。
输入:[1, 3, 0, 2, 4]
输出:0
解释:
 无论怎么变化总是有 3 分。
所以我们将选择最小的 ,即 0。



Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts