【优快云竞赛】36期题解(Javascript)

文章介绍了四道编程竞赛题目,包括查找点在自然区间的坐标、统计鬼画符数量、去除整数以及括号上色问题。对于每道题目,都提供了思路分析和代码实现,其中括号上色问题采用暴力回溯法,但指出应使用动态规划求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这次最后一题时间超限,没有拿全分数。但就算90也到第五了哈哈。

1. 查找点在自然区间的坐标

1.1 题目描述

  • 定义
    实数轴上的一个区间由左右两个端点,假设区间是左闭右开的,例如区间[0,1)
    给定一个有序的不重合非负整数区间列表 range_list :[ [0,1), [3,4) ]
    该非负整数区间列表将实数轴分割成了这些区间列表
    range_list_nature_ext : [(-∞,0),[0,1),[1,3),[3,4),[4,+∞)]
    我们称 range_list_nature_ext 为由 range_list 扩展的 自然区间

  • 问题
    写一个查找算法,对于给定非负整数区间列表 range_list ,查找一个非负整数 p 落在了 range_list_nature_ext 的那个区间,返回那个区间的在 range_list_nature_ext 里的下标,我们称这个下标为非负整数 p 在 rage_list 里的 自然坐标。

1.2 思路分析

我们需要转化题目意思,求自然坐标,转成求一个数在有序数组的位置。

首先将所有区间的左端点和右端点存入一个数组中,并对这个数组进行升序排序,得到有序数组 arr;
当 p 小于 arr 中第一个元素时,其所在的自然区间下标为 0;
当 p 大于或等于 arr 中最后一个元素时,其所在的自然区间下标为 arr 的长度;
在 arr 中查找第一个比 p 大的元素,该元素左边的自然区间下标为该元素的下标。

1.3 代码实现

class Solution {
    solution(P, N, vector) {
        var result;
        let arr = [];
        // 将所有区间的左端点和右端点存入一个数组中,并对这个数组进行升序排序,得到有序数组 arr
        for(let i=0;i<N;i++){
            arr.push(vector[i][0]);
            arr.push(vector[i][1]);
        }
        arr.sort((a,b)=>{
            return a-b;
        })
        // 当 p 小于 arr 中第一个元素时,其所在的自然区间下标为 0
        if(P < arr[0]) return 0;
        // 当 p 大于或等于 arr 中最后一个元素时,其所在的自然区间下标为 arr 的长度
        if(P >= arr[arr.length-1]) return arr.length;
        // 在 arr 中查找第一个比 p 大的元素,该元素左边的自然区间下标为该元素的下标
        let i = 1;
        for(i=1;i<arr.length;i++){
            if(P>=arr[i-1] && P<arr[i] ){
                return i;
            }
        }
        return i;
    }
}

2. 鬼画符门之大师兄恋爱

2.1 题目描述

鬼画符门,每年都会统计自己宗门鬼画符消耗的数量。 往年一直是大师兄管理。 但是大师兄谈恋爱了!!怎么能让这种事
耽误自己恋爱时间呢!! 鬼艺接手了!! 你能帮鬼艺写一个程序帮助她统计每年消耗数量最多的鬼画符吗?

2.2 思路分析

该题目的输入就是不同的颜色字符串,我们只需要用Map来存储每个鬼画符出现的次数,然后遍历Map,找出出现次数最多的鬼画符即可。

2.3 代码实现

class Solution {
    solution(n, vector) {
        let m = new Map();
        for(let i=0;i<n;i++){
            let str = vector[i];
            if(m.has(str) == false){
                m.set(str,1);
            }else{
                m.set(str,1+m.get(str))
            }
        }
        let maxCount = 0;
        let maxStr = "";
        m.forEach((value,key)=>{
            if(value > maxCount){
                maxCount = value;
                maxStr = key;
            }
        })
        return maxStr;
    }
}

3. 去除整数

3.1 题目描述

已知存在集合A包含n个整数,从1到n。 存在m个整数a。 在集合A中去除这m个整数的的倍数。 输出集合中包含的元素的个数。

3.2 思路分析

这道题目的思路是遍历所有要去除的整数的倍数,将其添加到一个集合中。最后,集合的大小就是集合中剩余的元素数量。具体来说,算法的步骤如下:

  1. 如果要去除的整数数量 m 等于 1,那么将 n 除以这个整数的值,向下取整,即可得到集合中剩余的元素数量。

  2. 创建一个空集合 set,遍历要去除的整数数组 arr,对于每个整数 x,从 x 开始,以 x 为步长遍历集合 A 中的元素,将每个倍数添加到集合 set 中。

  3. 集合中剩余的元素数量即为 n 减去集合 set 的大小。

3.3 代码实现

class Solution {
    solution(n, m, arr) {
        var result = 0;
        // 如果要去除的整数数量 m 等于 1,那么直接计算集合中剩余的元素数量
        if(m == 1){
            n -= Math.floor(n/arr[0]);  // 计算整数 arr[0] 的倍数个数
            return n;
        }
        // 创建一个空集合 set,遍历要去除的整数数组 arr,将所有倍数添加到集合 set 中
        var set = new Set();
        for(let i=0;i<arr.length;i++){
            let x = arr[i];
            for(let j=x;j<=n;j+=x){
                set.add(j);
            }
        }
        // 集合中剩余的元素数量即为 n 减去集合 set 的大小
        return n - set.size;
    }
}

4. 括号上色

4.1 题目描述

小艺酱又得到了一堆括号。 括号是严格匹配的。 现在给括号进行上色。 上色有三个要求:
1、只有三种上色方案,不上色,上红色,上蓝色。
2、每对括号只有一个上色。
3、相邻的两个括号不能上相同的颜色,但是可以都不上色。
问括号上色有多少种方案?答案对1000000007取模。

4.2 思路分析

这里是我没全过的题目分析:暴力回溯法(时间超限:通过率60%)

正确的解法应该是动态规划,这里期待一下其他大佬的题解。

这道题目可以使用递归的方式求解,每次递归遍历到一个括号的时候,判断当前括号是否可以填色,如果可以填色就填色,否则直接跳过。

在递归的过程中,可以使用一个数组 path 来记录每个括号填的颜色,如果递归结束之后 path 数组记录的就是一种可行的方案,累加器 count 就加1即可。

4.3 代码实现(纯暴力)


class Solution {
  solution(s) {
    var count = 0;
    let n = s.length;
    let tag = new Map();
    let st = [];
    // 先找到每一个括号匹配的另外一个括号的位置
    for (let i = 0; i < n; i++) {
      if (s[i] == '(') {
        st.push(i);
      } else {
        let leftIndex = st.pop();
        tag.set(leftIndex, i);
        tag.set(i, leftIndex);
      }
    }
    let path = new Array(n).fill(0);
    digui(path, 0)
    function digui(path, index) {
      if (index == n) {
        count = (count + 1) % 1000000007;
        return;
      }
      // 第一个括号可任意上色
      if (index == 0) {
        path[0] = 1; // 1 代表 红色
        digui(path, index + 1);
        path[0] = 2; // 2 代表 蓝色
        digui(path, index + 1);
        path[0] = 0; // 0 代表不上色
        digui(path, index + 1);
        return;
      }
      let other = tag.get(index);
      // 如果是右括号,考虑另外一个括号的限制
      if (index > other) {
        // 如果左括号没填色
        if (path[other] == 0) {
          if (path[index - 1] != 1) {
            path[index] = 1;
            digui(path, index + 1);
            path[index] = 0;
          }
          if (path[index - 1] != 2) {
            path[index] = 2;
            digui(path, index + 1);
            path[index] = 0;
          }
          return;
        } else {
          digui(path, index + 1);
        }
      } else {
        // 如果是左括号就不考虑右括号的限制
        if (path[index - 1] != 1) {
          path[index] = 1;
          digui(path, index + 1);
          path[index] = 0;
        }
        if (path[index - 1] != 2) {
          path[index] = 2;
          digui(path, index + 1);
          path[index] = 0;
        }
        digui(path, index + 1);
      }
    }
    return count;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

如果皮卡会coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值