leetcode 798.得分最高的最小轮调(js)

题目

给你一个数组 nums,我们可以将它按一个非负整数 k 进行轮调,这样可以使数组变为 [nums[k], nums[k + 1], … nums[nums.length - 1], nums[0], nums[1], …, nums[k-1]] 的形式。此后,任何值小于或等于其索引的项都可以记作一分。

例如,数组为 nums = [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 。

示例 1:

输入:nums = [2,3,1,4,0]
输出:3
解释:
下面列出了每个 k 的得分:
k = 0,  nums = [2,3,1,4,0],    score 2
k = 1,  nums = [3,1,4,0,2],    score 3
k = 2,  nums = [1,4,0,2,3],    score 3
k = 3,  nums = [4,0,2,3,1],    score 4
k = 4,  nums = [0,2,3,1,4],    score 3
所以我们应当选择 k = 3,得分最高。

示例 2:

输入:nums = [1,3,0,2,4]
输出:0
解释:
nums 无论怎么变化总是有 3 分。
所以我们将选择最小的 k,即 0。

提示:

1 <= nums.length <= 105
0 <= nums[i] < nums.length

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-rotation-with-highest-score

解题

1.预处理

作为刚接触算法的小白,我最开始还是用了两层循环,果不其然,超时了。所以就正好用上了昨天刚做过的题的预处理方法。成功没超时。

认真看提示会发现,数组是n长度的数组,数组里面的元素恰好是1…n,就相当于打乱顺序,费劲想了想发现这个规律。

每次都是往前移一个位置,每次的动作相同的。移完之后,相当于和每位元素比较的下标都减小了1位,除了第一位移到最后的元素,但又因为元素不可能大于下标,移到最后的元素绝对小于等于下标。所以移一次改变的数量是,减去原来和数组下标相等的元素,加上第一位移到最后的元素。

var bestRotation = function (nums) {
            var ans = 0;
            var sum = 0;
            var n = nums.length;
            var a = new Array(n).fill(0);
            //预处理 记录没移位时小于索引的总数
            for (let i = 0; i < n; i++) {
                if (nums[i] <= i) {
                    sum++;
                }
            }
            var maxSum = sum;
            //记录索引和值相等的情况
            for (let i = 0; i < n; i++) {
                if (nums[i] <= i) {
                    a[i - nums[i]]++;
                } else {
                    a[n + i - nums[i]]++;
                }
            }
            //移位
            for (let k = 1; k < n; k++) {
                sum = sum - a[k - 1] + 1;
                if (sum > maxSum) {
                    console.log(sum);
                    console.log(maxSum);
                    maxSum = sum;
                    ans = k;
                }
            }
            return ans;
        };
a[i - nums[i]]++;

这个数组是下标和元素值相等的数量。比如nums[2] = 1, nums[3] = 2,这两个元素都是往前移一步,所以这两个处理过之后是两次a[1]++。

2.差分(官方)

官方差分的写法也是找规律,虽然说用了差分,但是个人觉得和预处理也没差多少,感兴趣的可以了解一下。

var bestRotation = function(nums) {
    const n = nums.length;
    const diffs = new Array(n).fill(0);
    for (let i = 0; i < n; i++) {
        const low = (i + 1) % n;
        const high = (i - nums[i] + n + 1) % n;
        diffs[low]++;
        diffs[high]--;
        if (low >= high) {
            diffs[0]++;
        }
    }
    let bestIndex = 0;
    let maxScore = 0;
    let score = 0;
    for (let i = 0; i < n; i++) {
        score += diffs[i];
        if (score > maxScore) {
            bestIndex = i;
            maxScore = score;
        }
    }
    return bestIndex;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值