第110次双周赛
上次第二题做得太慢,位次不行,掉了10分。这回虽然第三题还是没做出来,但是侥幸位次进入了前1000。
第三题 - 使循环数组所有元素相等的最少秒数
拿到题目以后脑子中想法:贪心(怎么贪,寻找数组中最多的数吗),回溯(应该不行,时间复杂度太高),动态规划(这tm怎么dp),最后选择了我认为的“贪心”解法,先找数组中最多的数,然后将相邻数都设置为它,设置while循环,每次判断数组中的数是否一样,通过while循环的轮数得到解。然而,贪心的思路不正确,最后通过了529/579。
正确解法,以2, 1, 3, 3, 2为例。先把整个数组拼接到后面,得到 2, 1, 3, 3, 2, 2, 1, 3, 3, 2。这样就不用考虑数组的循环性了,拼到前面和后面的效果一样。
然后需要计算,对于每种数,两个相邻数之间的最大距离(中间隔了多少数)是多少。
- 1: 2 1 3 3 2 2 1 3 3 2,距离=4
- 2: 2 1 3 3 2 2 1 3 3 2,距离=3
- 3: 2 1 3 3 2 2 1 3 3 2,距离=3
所以这三个数中,最小的最大距离minMaxDis = Math.min(4, 3, 3) = 3。
从3的情况来看,如果距离为3,那么需要扩散两次,所以次数的计算公式是Math.ceil(minMaxDis / 2)。
大体思路就是这样,具体细节是设置哈希表,存放每个数的下标数组,根据下标数组求出相邻最大距离,再更新minMaxDis,最后求出答案。
/**
* @param {number[]} nums
* @return {number}
*/
var minimumSeconds = function(nums) {
// map,key为nums中的数,值为在_nums中的下标
const m = new Map()
// 拼接数组
const _nums = nums.concat(nums.slice(0, nums.length))
let minMaxDis = Infinity
// 初始化map
for (let i = 0; i < _nums.length; i++) {
if (!m.has(_nums[i])) {
m.set(_nums[i], [])
}
const arr = m.get(_nums[i])
arr.push(i)
}
// 对于map中每个数,遍历其下标数组,计算相邻两个相同的数之间的最大距离
for (const num of m.keys()) {
const dis = m.get(num)
let maxDisOfNum = 0
for (let i = 1; i < dis.length; i++) {
maxDisOfNum = Math.max(maxDisOfNum, dis[i] - dis[i - 1] - 1)
}
// 遍历每个数后,得到这些最大距离中的最小值
minMaxDis = Math.min(minMaxDis, maxDisOfNum)
}
// 每次扩散距离为2,如果两个数之间距离为3,需要扩散两次,所以向上取整
return Math.ceil(minMaxDis / 2)
};