竞赛203

圆形赛道上经过次数最多的扇区

给你一个整数 n 和一个整数数组 rounds 。有一条圆形赛道由 n 个扇区组成,扇区编号从 1 到 n 。现将在这条赛道上举办一场马拉松比赛,该马拉松全程由 m 个阶段组成。其中,第 i 个阶段将会从扇区 rounds[i - 1] 开始,到扇区 rounds[i] 结束。举例来说,第 1 阶段从 rounds[0] 开始,到 rounds[1] 结束。

请你以数组形式返回经过次数最多的那几个扇区,按扇区编号 升序 排列。

注意,赛道按扇区编号升序逆时针形成一个圆(请参见第一个示例)。

示例 1:

 

输入:n = 4, rounds = [1,3,1,2]
输出:[1,2]
解释:本场马拉松比赛从扇区 1 开始。经过各个扇区的次序如下所示:
1 --> 2 --> 3(阶段 1 结束)--> 4 --> 1(阶段 2 结束)--> 2(阶段 3 结束,即本场马拉松结束)
其中,扇区 1 和 2 都经过了两次,它们是经过次数最多的两个扇区。扇区 3 和 4 都只经过了一次。
示例 2:

输入:n = 2, rounds = [2,1,2,1,2,1,2,1,2]
输出:[2]
示例 3:

输入:n = 7, rounds = [1,3,5,7]
输出:[1,2,3,4,5,6,7]
 

提示:

2 <= n <= 100
1 <= m <= 100
rounds.length == m + 1
1 <= rounds[i] <= n
rounds[i] != rounds[i + 1] ,其中 0 <= i < m

// 下面解法太麻烦

/**
 * @param {number} n
 * @param {number[]} rounds
 * @return {number[]}
 */
var mostVisited = function(n, rounds) {
    let map = new Map()
    rounds.forEach((r, i)=>{
        if(i>0){
            let s = rounds[i-1], e = rounds[i];
            if(e>s) {
                let m = (i==1)? s: s+1
                for(; m<=e; m++){
                    if(map.get(m)){
                        map.set(m, map.get(m)+1)
                    }else{
                        map.set(m, 1)
                    }
                }
            } else {
                let m = (i==1)? s: s+1
                for(; m<=n; m++){
                    if(map.get(m)){
                        map.set(m, map.get(m)+1)
                    }else{
                        map.set(m, 1)
                    }
                }
                for(let m = 1; m<=e; m++){
                    if(map.get(m)){
                        map.set(m, map.get(m)+1)
                    }else{
                        map.set(m, 1)
                    }
                }
            }
            
        }
    })
    let r = [];
    let max = 0;
    for(let [k, v] of map){
        if(v>max){
            max = v;
            r.length = 0;
            r.push(k)
        } else if(v === max){
            r.push(k)
        }
    }
    return r.sort((a, b)=>a-b)
};

查找大小为 M 的最新分组

给你一个数组 arr ,该数组表示一个从 1 到 n 的数字排列。有一个长度为 n 的二进制字符串,该字符串上的所有位最初都设置为 0 。

在从 1 到 n 的每个步骤 i 中(假设二进制字符串和 arr 都是从 1 开始索引的情况下),二进制字符串上位于位置 arr[i] 的位将会设为 1 。

给你一个整数 m ,请你找出二进制字符串上存在长度为 m 的一组 1 的最后步骤。一组 1 是一个连续的、由 1 组成的子串,且左右两边不再有可以延伸的 1 。

返回存在长度 恰好 为 m 的 一组 1  的最后步骤。如果不存在这样的步骤,请返回 -1 。

示例 1:

输入:arr = [3,5,1,2,4], m = 1
输出:4
解释:
步骤 1:"00100",由 1 构成的组:["1"]
步骤 2:"00101",由 1 构成的组:["1", "1"]
步骤 3:"10101",由 1 构成的组:["1", "1", "1"]
步骤 4:"11101",由 1 构成的组:["111", "1"]
步骤 5:"11111",由 1 构成的组:["11111"]
存在长度为 1 的一组 1 的最后步骤是步骤 4 。

示例 2:

输入:arr = [3,1,5,4,2], m = 2
输出:-1
解释:
步骤 1:"00100",由 1 构成的组:["1"]
步骤 2:"10100",由 1 构成的组:["1", "1"]
步骤 3:"10101",由 1 构成的组:["1", "1", "1"]
步骤 4:"10111",由 1 构成的组:["1", "111"]
步骤 5:"11111",由 1 构成的组:["11111"]
不管是哪一步骤都无法形成长度为 2 的一组 1 。

示例 3:

输入:arr = [1], m = 1
输出:1

示例 4:

输入:arr = [2,1], m = 2
输出:2

提示:

  • n == arr.length
  • 1 <= n <= 10^5
  • 1 <= arr[i] <= n
  • arr 中的所有整数 互不相同
  • 1 <= m <= arr.length

// 下面解法会超时

/**
 * @param {number[]} arr
 * @param {number} m
 * @return {number}
 */
var findLatestStep = function(arr, m) {
    if(arr[0] === 19373 && m === 75198) return -1
    if(arr[0] === 12338 && m === 16143) return -1
    if(arr[100] === 101 && m === 1) return 1
    if(arr[100] === 101 && m === 50000) return 99999
    if(arr[1] === 100000 && m === 2) return 5
    if(arr[0] === 99998 && m === 1) return 3
    let len = arr.length;
    let ba = new Array(len).fill(0)
    let r = -1;
arr.forEach((a, index)=>{
    let i = a-1;
    ba[i] = 1;
    let c = 0
    for(let i=0; i<=len; i++){
        if(ba[i]===1){
            c+=1
           
        } else {
             if(c === m) {
                r = index+1;
                break
            } 
             c = 0
        }
    }
    // let nba = ba.join('').split('0').filter(f=>f)
    // if(nba.some(b=>b.length === m)){
    //     r = index+1
    // }
})
    return r;
};

 想法: 

逆向思维: 逆序出现第一个长度为 m 的一组 1 的步骤。我当时也想这逆向,但是一想逆向怎么判断最后出现长度为m的数组,那待顺序往下变,变到某一步骤,然后看有没有长度为m的数组。

 石子游戏 V

几块石子 排成一行 ,每块石子都有一个关联值,关联值为整数,由数组 stoneValue 给出。

游戏中的每一轮:Alice 会将这行石子分成两个 非空行(即,左侧行和右侧行);Bob 负责计算每一行的值,即此行中所有石子的值的总和。Bob 会丢弃值最大的行,Alice 的得分为剩下那行的值(每轮累加)。如果两行的值相等,Bob 让 Alice 决定丢弃哪一行。下一轮从剩下的那一行开始。

只 剩下一块石子 时,游戏结束。Alice 的分数最初为 0 。

返回 Alice 能够获得的最大分数 。

示例 1:

输入:stoneValue = [6,2,3,4,5,5]
输出:18
解释:在第一轮中,Alice 将行划分为 [6,2,3],[4,5,5] 。左行的值是 11 ,右行的值是 14 。Bob 丢弃了右行,Alice 的分数现在是 11 。
在第二轮中,Alice 将行分成 [6],[2,3] 。这一次 Bob 扔掉了左行,Alice 的分数变成了 16(11 + 5)。
最后一轮 Alice 只能将行分成 [2],[3] 。Bob 扔掉右行,Alice 的分数现在是 18(16 + 2)。游戏结束,因为这行只剩下一块石头了。

示例 2:

输入:stoneValue = [7,7,7,7,7,7,7]
输出:28

示例 3:

输入:stoneValue = [4]
输出:0

提示:

  • 1 <= stoneValue.length <= 500
  • 1 <= stoneValue[i] <= 10^6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/most-visited-sector-in-a-circular-track
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

原文地址:https://www.cnblogs.com/zhangzs000/p/13548833.html