『力扣周赛』第110次双周赛、第357次周赛

115 阅读2分钟

第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)
};

第357次周赛