Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
不是因为看到了希望才坚持,而是因为坚持了才能看到希望。共勉
每日刷题第59天 2021.03.09
798. 得分最高的最小轮调
- leetcode原题链接:leetcode-cn.com/problems/sm…
- 难度:困难
- 方法:前缀和
题目描述
- 给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ,它只包含字符 '' 和 '|' ,其中 '' 表示一个 盘子 ,'|' 表示一支 蜡烛 。
- 同时给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [lefti, righti] 表示 子字符串 s[lefti...righti] (包含左右端点的字符)。对于每个查询,你需要找到 子字符串中 在 两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边 都 至少有一支蜡烛,那么这个盘子满足在 两支蜡烛之间。
- 比方说,s = "|||||" ,查询 [3, 8] ,表示的是子字符串 "||**|" 。子字符串中在两支蜡烛之间的盘子数目为 2 ,子字符串中右边两个盘子在它们左边和右边 都 至少有一支蜡烛。
- 请你返回一个整数数组 answer ,其中 answer[i] 是第 i 个查询的答案。
解题思路
-
以
A=[2,3,1,4,0]为例: -
A[0]=2移动到2号索引位置[4,0,2,3,1]其对应的K为3=(0-A[0]+5)%5 -
根据公式
K=(i-A[i]+N)%N可以计算出,A[i]移动到其索引i=A[i]时对应的K的数组为:[3,3,1,4,4] -
为了更好的理解上面数组的由来,不妨写出K为上述数字中对应值时数组A的情况
3:K为3时对应的数组为:[4,0,2,3,1],此时2、3位置的值与索引相同1:K为1时对应的数组为:[3,1,4,0,2],此时1位置的值与索引相同4:K为4时对应的数组为:[0,2,3,1,4],此时0、4位置的值与索引相同
-
此时若将
K再加1,本来索引与值正好相等,然而索引却变小了1,因此可以知道K+1时对应的这些位置的分值便会减少,不妨记录下、当某个位置的分值由原本的有效到无效时的K的值: -
最后由
diffs还原point,显然diffs[0]就是point[0] -
而
diffs[i] = point[i] - point[i - 1],所以point[i] = diffs[i] + point[i - 1]; -
定义一个
mark先等于point[0],即为不调整时的得分,之后用mark累加diffs数组 -
因为,
mark = diffs[0] + diffs[1] = point[0] + point[1] - point[0] = point[1],这可以推广到i的情况 -
所以
diffs累加到i的结果就是point[i],从中选出最大的即可
AC代码
var bestRotation = function (A) {
// 保存结果
let result = 0;
// 记录保存数组长度
let arrLength = A.length;
// 记录移动K次 节点值等于下标的数量,默认数量都为0
const normalArr = new Array(arrLength).fill(0);
// 记录每个节点的分数
let tem = 0;
for (let i = 0; i < arrLength; i++) {
if (A[i] > i) {
// 移动 arrLength + i - A[i]后,该节点值等于下标,所以
normalArr[arrLength + i - A[i]]++;
} else {
// 移动 i - A[i]后,该节点值等于下标,所以
normalArr[i - A[i]]++;
// 记录初次的分数
tem++;
}
}
// 保存最高分数
let max = tem;
for (let K = 1; K < arrLength; K++) {
// 每次移动只需要判断这次移动 有多少数组变为不符合要求的,将原来的减去该参数即可
tem = tem - normalArr[K - 1] + 1;
// 只有当有更优解的时候 继续新的result
if (tem > max) {
max = tem;
result = K;
}
}
return result;
};
总结
- 困难题,第一次接触拆分的思想,之前接触的快速排序的分治思想,和这个比较相似。