LeetCode-798 得分最高的最小论调 及差分和前缀和的学习
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-rotation-with-highest-score
题目描述
给你一个数组 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
解题思路
根据题目最容易想到的是暴力法,尝试用暴力法做,将每个k下的nums数组求出来,统计所有得分,时间复杂度为O(n2),不出所料超时了。
根据题意寻找规律,可以得出结论,每次k加1后,下标会-1,这个时候,原来比下标小的数会继续得分,下标比原来大的数会继续不得分,下标与原来相同的数,会从得分变成失分,下标为0的那个数,下标从0变成了n-1,会变得得分,那么递推公式就可以表示为Vali= Vali-1 - Count下标相同 + 1,只需要初始时候找到最初的val,找到k时候与k下标相同的元素数目,就可以通过一次遍历将所有的得分求出来,时间复杂度为O(n)。这里注意每一个元素必然有且只有一个k使得其下标与元素值相同,所以对于每一个元素值,可以直接找到使得其下标与元素值相同的k,时间复杂度为O(n).
本题还可以通过上下界和差分的方法来做,假设原坐标为i,那么修改后的坐标应该满足0 <= i - k <= n -1 可以推出,k的取值范围为[i - n + 1, i],又从得分条件来说得到 i - k >= x,及k <= i - x,因为x取值范围是[0, n),所以k的取值范围[a ,b]为[i - n + 1, i - x],但是由于存在上下界会出现负数,需要取模为正,所以k的上下界可能出现 a > b的情况,这个时候,可得分的k范围应该为[0, i - n + 1],[i - x, n - 1]。那么,对于i 来说,k在区间[a,b]将会得分,所以可以有一个数组sk来记录每个k的得分情况,遍历每个i将对应区间的k分数分别+1,最终得分最高的k就是最终的解,但是如果这样做的话,时间复杂度仍然为O(n2)。可以使用前缀和+差分的思想,由于是区间修改,所以可以记录sk的一个差分数组diff,diff[i] = sk[i] - sk[i - 1],那么区间[a, b]范围内同时+1的情况,可以将diff[a] +=1, diff[b + 1] -= 1,便可以得到与sk在[a,b]范围内均+1的记录效果,在计算完成后,计算diff的[0, i]前缀和就是sk[i]的结果。
代码展示
暴力法:
class Solution {
public:
int bestRotation(vector<int>& nums) {
int iRet = 0, iMax = 0, n = nums.size();
for(int i = 0; i < n; i++)
{
nums[i] -= i;
}
for (int i = 0; i < n; i++)
{
if (nums[i] <= 0)
{
iMax++;
}
}
for(int i = 1; i < n; i++)
{
int iCount = 0;
for(int j = 0; j < n; j++)
{
if(j == i - 1)
{
nums[j] = nums[j] - n + 1;
}
else
{
nums[j] = nums[j] + 1;
}
if(nums[j] <= 0)
{
iCount++;
}
}
if(iCount > iMax)
{
iMax = iCount;
iRet = i;
}
}
return iRet;
}
};
找规律DP
class Solution {
public:
int bestRotation(vector<int>& nums) {
int iRet = 0, iMax = 0, n = nums.size(), iVal = 0;
for(int i = 0; i < n; i++)
{
if(nums[i] <= i)
{
iMax++;
}
}
vector<int> steps(n, 0);
for(int i = 0; i < n; i++)
{
if(i - nums[i] >= 0)
{
steps[i - nums[i]]++;
}
else
{
steps[i - nums[i] + n]++;
}
}
iVal = iMax;
for(int i = 1; i < n; i++)
{
iVal = iVal - steps[i - 1] + 1;
if(iVal > iMax)
{
iMax = iVal;
iRet = i;
}
}
return iRet;
}
};
上下界+差分数组
class Solution {
public:
int bestRotation(vector<int>& nums) {
int n = nums.size();
vector<int> diff(n, 0);
int iRet = 0;
for(int i = 0; i < n; i++)
{
int a = ((n - i + 1) + n) % n;
int b = ((i - nums[i]) + n) % n;
if(a <= b)
{
diff[a] += 1;
if (b + 1 < n)
{
diff[b + 1] -= 1;
}
}
else
{
diff[0] += 1;
diff[b + 1] -= 1;
diff[a] += 1;
}
}
for(int i = 1; i < n; i++)
{
diff[i] += diff[i - 1];
}
for(int i = 1; i < n; i++)
{
if(diff[iRet] < diff[i])
{
iRet = i;
}
}
return iRet;
}
};
运行结果

LeetCode-798 得分最高的最小论调 及差分和前缀和的学习的更多相关文章
- Java实现 LeetCode 798 得分最高的最小轮调 (暴力分析)
798. 得分最高的最小轮调 给定一个数组 A,我们可以将它按一个非负整数 K 进行轮调,这样可以使数组变为 A[K], A[K+1], A{K+2], - A[A.length - 1], A[0] ...
- [差分数组] LeetCode789 得分最高的最小轮调
LeetCode 得分最高的最小轮调 今天当然CV了因为今天比较忙,所以直接走算法,因为什么都不做的话并不符合社会主义核心价值观,今天小学一手查分数组. 题目:并不存在CV了还写什么题解 算法背景: ...
- [LeetCode] 727. Minimum Window Subsequence 最小窗口子序列
Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a subsequenceof ...
- [Swift]LeetCode798. 得分最高的最小轮调 | 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 ...
- LeetCode之Min Stack 实现最小栈
LeetCode相关的网上资源比较多,看到题目一定要自己做一遍,然后去学习参考其他的解法. 链接: https://oj.leetcode.com/problems/min-stack/ 题目描述: ...
- LeetCode 155 Min Stack(最小栈)
翻译 设计支持push.pop.top和在常量时间内检索最小元素的栈. push(x) -- 推送元素X进栈 pop() -- 移除栈顶元素 top() -- 得到栈顶元素 getMin() -- 检 ...
- LeetCode 939. Minimum Area Rectangle (最小面积矩形)
题目标签:HashMap 题目给了我们一组 xy 上的点坐标,让我们找出 能组成矩形里最小面积的那个. 首先遍历所有的点,把x 坐标当作key 存入map, 把重复的y坐标 组成set,当作value ...
- LeetCode 1255 得分最高的单词集合 Maximum Score Words Formed by Letters
地址 https://leetcode-cn.com/problems/maximum-score-words-formed-by-letters/ 题目描述你将会得到一份单词表 words,一个字母 ...
- [LeetCode] 910. Smallest Range II 最小区间之二
Given an array A of integers, for each integer A[i] we need to choose either x = -K or x = K, and ad ...
- [LeetCode] 908. Smallest Range I 最小区间
Given an array A of integers, for each integer A[i] we may choose any x with -K <= x <= K, and ...
随机推荐
- ChatGPT 会开源吗?
最近,我被一款叫做 ChatGPT 的人工智能(AI)聊天机器人,刷屏了.网上有人说它是搜索引擎杀手,还有人说它将取代程序员... 最后,我还是没扛住铺天盖地的赞美,跑去注册了个账号,抱着调侃&quo ...
- day37-文件上传和下载
文件上传下载 1.基本介绍 在Web应用中,文件上传和下载是非常常见的功能 如果是传输大文件一般用专门的工具或者插件 文件上传和下载需要用到两个包:commons-fileupload.jar和com ...
- json提取器和beanshell处理器组合,将提取的所有id以数组返回
1.添加json提取器 2.添加beanshell处理器,并编写脚本 String str1 = vars.get("buildid_ALL"); log.info(str1); ...
- JavaScript:函数:函数传参传的是什么?值传递还是引用传递?
我们调用函数的时候,把实参放入到括号里进行传参,让形参接收实参的数据. 在这个过程中,形参接收的数据到底是什么,换句话说,我们传参传的到底是什么东西? 初学JS的,可能不太难理解这个问题的意义是什么? ...
- vivo 游戏中心低代码平台的提效秘诀
作者:vivo 互联网服务器团队- Chen Wenyang 本文根据陈文洋老师在"2022 vivo开发者大会"现场演讲内容整理而成.公众号回复[2022 VDC]获取互联网技术 ...
- 使用nodejs编写api接口并部署到服务器上
一.用node.js编写api接口 1.安装node环境,没有就去下载nodejs, 下载地址 2.创建一个node项目, 新建一个目录文件,例node_proxy 3.在新建的node项目执行npm ...
- vite+ts+vue3+router4+Pinia+ElmPlus+axios+mock项目基本配置
1.vite+TS+Vue3 npm create vite Project name:... yourProjectName Select a framework:>>Vue Selec ...
- 数据库日志——binlog、redo log、undo log扫盲
日志是数据库中比较重要的组成部分,很多核心的功能必须依靠日志才能完成. 该篇文章简要介绍了binlog.redo log与undo log,能够在一定程度上拓宽对mysql日志的整体认识. binlo ...
- Coolify系列-解决WARNING: IPv4 forwarding is disabled. Networking will not work.以及开启防火墙端口
背景 我在windows电脑安装了一个VM,使用VM开启了Linux服务器,运行docker,然后遇到了这个报错. 解决 首先:在宿主机上执行 echo "net.ipv4.ip_forwa ...
- 【数据结构和算法】Trie树简介及应用详解
作者:京东物流 马瑞 1 什么是Trie树 1.1 Trie树的概念 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经 ...