• [leetcode] 798 得分最高的最小轮调 思维dp


    题目链接
    在这里插入图片描述
    轮调实际上是这个样子的:
    每次讲最前面的元素放到数组最后,然后将所有元素集体向前移动一位
    在当前值 a [ i ] ≤ i a[i] \leq i a[i]i的时候会获得 1 1 1分,问最大的的分是多少?
    先说明一个事实:
    一次轮调之后,对于除了最前面的每个数,他的下标会减小 1 1 1,而对于最前面的那个数,他的下标直接变为最大
    大致分为以下三种情况:

    1. 本来 a [ i ] a[i] a[i]就小于下标 i i i,轮调之后下标减小值不变,所以依旧会获得 1 1 1
    2. 本来 a [ i ] = = i a[i] == i a[i]==i,轮调之后,下标减小而值不变,所以值就比下标大 1 1 1,所以说会失去 1 1 1
    3. 本来 a [ i ] > i a[i] > i a[i]>i,轮调之后,下标更小,值依旧会大于下标,所以依旧不得分
    4. 在最前面的数,一次轮调之后,被放到最大的下标的位置,会得到 1 1 1

    我们用 d p [ i ] dp[i] dp[i]表示在第 i i i次轮调之后会得到的分数,那么就有:
    d p [ i ] = d p [ i − 1 ] − x + 1 dp[i] = dp[i-1] - x + 1 dp[i]=dp[i1]x+1
    其中, x x x表示 i − 1 i-1 i1次轮调时下标和值相等的个数{
    在这里 x x x可以预处理得到
    }
    式中的 + 1 + 1 +1是为了解决数组最前面的数到数组最后的最大下标处的贡献值
    d p [ 0 ] = 未 轮 调 的 时 候 的 得 分 dp[0] = 未轮调的时候的得分 dp[0]=
    因为之和前一个关系有关,所以我们可以只用一个变量解决,记录最大值处的下标返回即可

    Code:

    class Solution {
    public:
        int bestRotation(vector<int>& nums) {
            int val = 0;
            const int n = nums.size();
            int a[n+1],pos = 0;
            memset(a,0,sizeof a);
            for(int i = 0; i < n;i ++) {
                if(nums[i] <= i) val ++;
            }
            int mxval = val;
            for(int i = 0; i < n;i ++) {
                if(i >= nums[i]) a[i-nums[i]] ++;
                else a[i + n - nums[i]] ++;
            }
            
            for(int i=1;i<n;i++) {
                val = val - a[i-1] + 1;
                if(val > mxval) {
                    val = mxval;
                    pos = i;
                }
            }
            return pos;
        }
    };
    

    在这里插入图片描述

  • 相关阅读:
    sql server日志已满报错
    图片基础信息
    android小细节
    内存泄露分析
    一个非常快的android模拟器
    activity退出
    ListView中内容的动画效果
    视频相关android软件
    Android Screen Monitor抓取真机屏幕
    ListView中使用type需要注意的东西
  • 原文地址:https://www.cnblogs.com/PushyTao/p/16196722.html
Copyright © 2020-2023  润新知