798. Smallest Rotation with Highest Score

本文介绍了一种寻找数组旋转后的最高得分方法,通过Interval Stabbing算法优化求解过程,实现高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 1
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].

思路:Brute force Python会TLE,既然不能一个个数过去,那就构造interval,转化成选择一个数,使得与所有interval中有交集的总个数最多,但是实在是卡在这一步了,最后只写出一个很brute force的方法

class Solution:
    def bestRotation(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        d, n = [0]*len(A), len(A)
        for i in range(len(A)):
            if A[i]==0: continue
            if A[i]<=i<=n:
                for j in range(i-A[i]+1): d[j]+=1
                for j in range(i+1,n): d[j]+=1
            else:
                for j in range(i+1, i+1+n-A[i]): d[j]+=1
            
        return d.index(max(d))
    
s=Solution()
print(s.bestRotation([2, 3, 1, 4, 0]))
print(s.bestRotation([1, 3, 0, 2, 4]))


看答案发现有个Interval Stabbing算法

https://www.cs.cmu.edu/afs/cs/academic/class/15210-f11/www/resources/recis/rec12.pdf

这个其实就解决了上述问题,每个interval只记录起始位置和结束位置,然后要求最佳的点,就从左往右遍历过去就好了,遍历的时候维持一个running sum,在数学上思考一下确实没毛病,但是就是如果事先没见过类似的,估计很难想出来的

class Solution:
    def bestRotation(self, A):
        goods, n = [], len(A)
        for i in range(n):
            if A[i]==0: continue
            if A[i]>i:
                goods.append([i+1, i+n-A[i]])
            else:
                goods.append([0, i-A[i]])
                if i+1<n:
                    goods.append([i+1, n-1])
        
        # build aux array
        aux = [0]*n
        for left, right in goods:
            aux[left] += 1
            if right+1<n: aux[right+1] -= 1
        
        # cumulate aux result
        acc, ma, res = 0, -999999, -1
        for i in range(n):
            acc += aux[i]
            if acc>ma: 
                ma = acc
                res = i
        return res
    
s=Solution()
print(s.bestRotation([2, 3, 1, 4, 0]))
print(s.bestRotation([1, 3, 0, 2, 4]))

或者利用python的-1 index可以写得更简单

class Solution(object):
    def bestRotation(self, A):
        N = len(A)
        bad = [0] * N
        for i, x in enumerate(A):
            left, right = (i - x + 1) % N, (i + 1) % N
            bad[left] -= 1
            bad[right] += 1
            if left > right:
                bad[0] -= 1

        best = -N
        ans = cur = 0
        for i, score in enumerate(bad):
            cur += score
            if cur > best:
                best = cur
                ans = i
        return ans

s=Solution()
print(s.bestRotation([2, 3, 1, 4, 0]))

Approach #1: Interval Stabbing [Accepted]

Intuition

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, 2 wraps 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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值