Skip to content

刷题 ​

  1. 【最大化控制资源成本】公司创新实验室正在研究如何最小化资源成本,最大化资源利用率,请你设计算法帮他们解决一个任务混部问题:有taskNum项任务,每个任务有开始时间(startTime),结束时间(endTime),并行度(parallelism)三个属性,并行度是指这个任务运行时将会占用的服务器数量,一个服务器在每个时刻可以被任意任务使用但最多被一个任务占用,任务运行完成立即释放(结束时刻不占用)。任务混部问题是指给定一批任务,让这批任务由同一批服务器承载运行,请你计算完成这批任务混部最少需要多少服务器,从而最大最大化控制资源成本。
  • 输入描述:第一行输入为taskNum,表示有taskNum项任务,接下来taskNum行,每行三个整数,表示每个任务的开始时间,(startTime ),结束时间(endTime ),并行度(parallelism)
  • 输出描述:一个整数,表示最少需要的服务器数量
  • 输入
    • 3
    • 2 3 1
    • 6 9 2
    • 0 5 1
  • 输出 2
    js
          let arr = [[0, 1, 2],[0, 5, 1],[2, 3, 1],[6, 9, 2],[1, 7, 1]]  
          let setArr = Array.from(new Set(arr.flat())).sort((a, b) => a - b)
          let setLen = setArr.length
          let arrLen = arr.length
          let resArr = new Array()
          for (let i = 0; i < setLen - 1; i++) {
            let sum = 0
            for (let j = 0; j < arrLen; j++) {
              if (arr[j][1] <= setArr[i]) continue //如果结束时间过了 跳过  
              if (arr[j][0] <= setArr[i]) {
                sum += arr[j][2] //在区间内
              }
            }
            resArr.push(sum)
          }
          console.log(resArr)  //服务器时间
  1. 【完美走位】输入一个长度为4的倍数的字符串,字符串中仅包含WASD四个字母。将这个字符串中的连续子串用同等长度的仅包含WASD的字符串替换,如果替换后整个字符串中WASD四个字母出现的频数相同,那么我们称替换后的字符串是“完美走位”。求子串的最小长度。如果输入字符串已经平衡则输出0。
  • 输入:一行字符表示给定的字符串s WASDAASD
  • 输出:一个整数表示答案 1
    js
          let str = 'WASDAASDDDSS'
          getPerfectWays(str)
          function getMap(v) { //获取映射
            let map = new Map()
            for (const item of v) {
              map.set(item, (map.get(item) || 0) + 1)
            }
            return map
          }
          function getPerfectWays(str) {
            let strMap = getMap(str) //获取词频表
            //特殊情况,已经完美走位  
            if (strMap.get('W') == strMap.get('S') && strMap.get('W') == strMap.get('A') && strMap.get('W') == strMap.get(
                'D')) {
              console.log(0);
            }
            let left = 0
            let right = 0
            let len = 0
            let maxNums = 0 // 出现次数最多的字母
            let res = str.length //记录最小的长度
            // 可替换字母个数, freeNums大于0且能被4整除,当前范围满足条件,左指针右移一格,否则右指针右移
            let freeNums = 0
            while (right < str.length) {
              //获取剩余部分的映射关系
              console.log(left, right)
              let restMap = getMap((str.slice(0, left) || '') + (str.slice(right + 1) || ''))
              //找到剩余部分映射中的最大长度
              maxNums = Math.max(Math.max(Math.max((restMap.get('W') || 0), (restMap.get('A') || 0)), (restMap.get('S') ||
                  0)),
                (restMap.get('D') || 0))
              len = right - left + 1 //获取窗口长度
              freeNums = len - ((maxNums - (restMap.get('W') || 0)) + (maxNums - (restMap.get('A') || 0)) + (maxNums - (
                  restMap.get(
                    'S') || 0)) +
                (maxNums - (restMap.get('D') || 0))) //如果用来替换的部分足够,并且超出的部分是4的倍数
              console.log(restMap, maxNums, freeNums);
              if (freeNums >= 0 && freeNums % 4 == 0) {
                if (len < res || res == str.length) {
                  res = len // 更新最短值
                }
                left++ //尝试是否可以更短
              } else {
                right++ //扩大窗口
              }
              if (right >= str.length) { // 越界即结束
                console.log(res);
                return res
              };
            }
          }
  1. 【羊、狼、农夫过河】羊、狼、农夫都在岸边,当羊的数量小于狼的数量时,狼会攻击羊,农夫则会损失羊。农夫有一艘容量固定的船,能够承载固定数量的动物。要求求出不损失羊情况下将全部羊和狼运到对岸需要的最小次数。只计算农夫去对岸的次数,回程时农夫不会运送羊和狼。备注:农夫在或农夫离开后羊的数量大于狼的数量时狼不会攻击羊。农夫自身不占用船的容量。
  • 输入描述:第一行输入为M,N,X, 分别代表羊的数量,狼的数量,小船的容量。
  • 输出描述:输出不损失羊情况下将全部羊和狼运到对岸需要的最小次数。(若无法满足条件则输出0)
    js
  1. 【字符串重新排列】给定一个字符串s,s包括以空格分隔的若干个单词,请对s进行如下处理后输出:
  2. 单词内部调整:对每个单词字母重新按字典序排序
  3. 单词间顺序调整:
    1. 统计每个单词出现的次数,并按次数降序排列
    2. 次数相同,按单词长度升序排列
    3. 次数和单词长度均相同,按字典升序排列
  • 请输出处理后的字符串,每个单词以一个空格分隔。
  • 输入描述:一行字符串,每个字符取值范围:【a-zA-z0-9】以及空格,字符串长度范围:【1,1000】
  • 输入: This is an apple My sister is in the house not in the yard
  • 输出: an is This aelpp in in eht eht My is not adry ehosu eirsst
    js
          function sortStr(s) {
            let sArr = s.split(' ')
            //单词内部排序
            let resArr = sArr.map((item) => item.split('').sort((a, b) => a.charCodeAt() - b.charCodeAt()).join(''))
            //统计词频 //A--65 Z--90 a--97 z--122
            let strMap = new Map()
            for (let i = 0; i < resArr.length; i++) {
              strMap.set(resArr[i], (strMap.get(resArr[i]) || 0) + 1)
            }
            //单词之间排序    
            for (let i = 0; i < resArr.length; i++) {
              for (let j = 0; j < resArr.length - 1; j++) {
                //词频高的放前面
                if (strMap.get(resArr[j]) < strMap.get(resArr[j + 1])) {
                  let temp
                  temp = resArr[j]
                  resArr[j] = resArr[j + 1]
                  resArr[j + 1] = temp
                } else if (strMap.get(resArr[j]) = strMap.get(resArr[j + 1])) {
                  if (resArr[j + 1].length < resArr[j].length) {
                    let temp
                    temp = resArr[j]
                    resArr[j] = resArr[j + 1]
                    resArr[j + 1] = temp
                  } else if (resArr[j + 1].length = resArr[j].length) {
                    // console.log(resArr[j + 1] - resArr[j])
                  }
    
                }
              }
              // resArr.sort((a, b) => strMap.get(b) - strMap.get(a))
            }
          }
  1. 【租车骑绿岛】部门组织绿岛骑行团建活动。租用公共双人自行车,每辆自行车最多坐两人,做最大载重M。给出部门每个人的体重,请问最少需要租用多少双人自行车。
  • 输入描述:
    • 第一行两个数字m、n,分别代表自行车限重,部门总人数。
    • 第二行,n个数字,代表每个人的体重,体重都小于等于自行车限重m。
  • 输出描述:
    • 最小需要的双人自行车数量。
  • 输入
    • 3 4
    • 3 2 2 1
  • 输出
    • 3
    js
    //双指针+贪心
        function min(arr) {
          let sortArr = arr.sort((a, b) => a - b)
          let limit = 3
          console.log(sortArr, limit)
          let left = 0
          let right = sortArr.length - 1
          let count = 0
          while (left <= right) {
            if (sortArr[left] + sortArr[right] <= limit) {
              count++
              left++
              right--
            } else {
              count++
              right--
            }
          }
          console.log(count); //6
        }
  1. 【无向图染色】给一个无向图染色,可以填红黑两种颜色,必须保证相邻两个节点不能同时为红色,输出有多少种不同的染色方案?
  • 输入描述:第一行输入M(图中节点数) N(边数),后续N行格式为:V1 V2表示一个V1到V2的边,不能保证所有节点都是连通的
  • 输出描述:输出一个数字表示染色方案的个数。
  • 输入
    • 4 4
    • 1 2
    • 2 4
    • 3 4
    • 1 3
  • 输出:7
    js
  1. 【单向链表中间节点】求单向链表中间的节点值,如果奇数个节点取中间,偶数个取偏右边的那个值。
  • 输入描述:第一行 链表头节点地址path 后续输入的节点数n 后续输入每行表示一个节点,格式:   "节点地址  节点值  下一个节点地址(-1表示空指针)“ 输入保证链表不会出现环,并且可能存在一些节点不属于链表。
  • 输出描述:链表中间节点值。
  • 输入:
    • 00010 4
    • 00000 3 -1
    • 00010 5 12309
    • 11451 6 00000
    • 12309 7 11451
  • 输出:6
    js
      //快慢指针:注意业务要求,偶数的时候取右侧的值,可以让慢指针先走    
      //map存储:遍历一遍并获取长度,取size/2的位置值
  1. 【等和子数组最小和】给定一个数组nums,将元素分为若干个组,使得每组和相等,求出满足条件的所有分组中,组内元素和的最小值
    js
      //求分成k个等和子数组,再找最小的
  2. 【最多颜色的车辆】在一个狭小的路口,每秒只能通过一辆车,假好车辆的颜色只有 3 种,找出 N 秒内经过的最多颜色的车辆数量。三种颜色编号为0 ,1 ,2
    js
      //滑动窗口    
          var uniquePaths = function (nums, window) {
            let left = 0
            let right = 0
            let map = new Map()
            let max = 0
            while (right < nums.length) {
              let rNum = nums[right]
              right++ //窗口右移
              map.set(rNum, (map.get(rNum) || 0) + 1)
              console.log(map, '1111')
              max = Math.max(max, map.get(rNum))
              while (right - left == window && right < nums.length) {
                let r = nums[right]
                let l = nums[left]
                right++
                left++
                map.set(r, (map.get(r) || 0) + 1)
                map.set(l, map.get(l) - 1)
                console.log(map, '2222')
                max = Math.max(max, Math.max(map.get(r), map.get(l)))
              }
            }
            console.log(max)
          }
  3. 【不含 101 的数】小明在学习二进制时,发现了一类不含 101的数,也就是:将数字用二进制表示,不能出现 101 。现在给定一个整数区间 [l,r] ,请问这个区间包含了多少个不含101 的数?
    js
          var uniquePaths = function (left, right) {
            let count = 0
            for (let i = left; i <= right; i++) {
              let str = i.toString(2)
              if (str.indexOf('101') != -1) {
                count++
              }
            }
            return count
          }
  4. 【过滤组合字符串】数字0、1、2、3、4、5、6、7、8、9分别关联 a~z 26个英文字母
    js
          var uniquePaths = function (num, str) {
            let strArr = ['abc', 'def', 'ghi', 'jkl', 'mno', 'prq', 'st', 'uv', 'wx', 'yz']
            let path = []
            let resArr = []
            let backTracking = function (index) {
              if (path.length == num.length) {
                resArr.push(path.slice())
                return
              }
              let current = num[index] //获取对应到编号
              let s = strArr[current] //拿到对应编号的字符串
              for (let i = 0; i < s.length; i++) {
                path.push(s[i]) //
                backTracking(index + 1)
                path.pop()
              }
            }
            backTracking(0)
            console.log(resArr)
          }
  5. 【真正的密码】在一行中输入一个字符串数组,如果其中一个字符串的所有以索引0开头的子串在数组中都有,那么这个字符串就是潜在密码,在所有潜在密码中最长的是真正的密码,如果有多个长度相同的真正的密码,那么取字典序最大的为唯一的真正的密码,求唯一的真正的密码。
  6. 【最小调整顺序次数】给定一个队列,但是这个队列比较特殊,可以从头部添加数据,也可以从尾部添加数据,但是只能从头部删除数据。输入一个数字n,会依次添加数字1~n(也就是添加n次)。
  7. 【探索地块建立】给一块nm的地块,相当于nm的二维数组,每个元素的值表示这个小地块的发电量;求在这块地上建立正方形的边长为c的发电站,发电量满足目标电量k的地块数量。
    js
        //构建二维前缀和数组  按照边长遍历一遍,统计符合条件的子矩阵
  8. 【模拟商场优惠打折】 暴力遍历模拟
  9. 【区间交叠问题】给定坐标轴上的一组线段,线段的起点和终点均为整数并且长度不小于1,请你从中找到最少数量的线段,这些线段可以覆盖住所有线段。 扫描线
    js
        //区间重叠合并问题
  10. 【二元组个数】给定两个数组a,b,若a[i] == b[j] 则称 [i, j] 为一个二元组,求在给定的两个数组中,二元组的个数。
  11. 【最大平分数组】给定一个数组nums,可以将元素分为若干个组,使得每组和相等,求出满足条件的所有分组中,最大的平分组个数。
    js
        //回溯、动态规划问题
  12. 【连接器问题】有一组区间[a0,b0],[a1,b1],…(a,b表示起点,终点),区间有可能重叠、相邻,重叠或相邻则可以合并为更大的区间;给定一组连接器[x1,x2,x3,…](x表示连接器的最大可连接长度,即x>=gap),可用于将分离的区间连接起来,但两个分离区间之间只能使用1个连接器;请编程实现使用连接器后,最少的区间数结果。
    js
        //区间重叠合并问题
  13. 【打印机队列】
  14. 【处理器问题】 阅读理解
  15. 【日志首次上报最多积分】
  16. 【简单的自动曝光】
  17. 【获取最大软件版本号】
  18. 【二进制差异数】 30%
  19. 【Excel单元格数值统计】
  20. 【相同数字的积木游戏】
  21. 【开放日活动】
  22. 【投篮大赛】
  23. 【开心消消乐】
    js
      //类似岛屿问题,BFS+感染
  24. 【通信误码】
  25. 【最大报酬】
    js
      //动态规划 、回溯、背包问题,求最大价值
  26. 【机器人】
    js
        //BFS
  27. 【新学校选址】
    js
      //排序后中位数求解
  28. 【寻找路径】
    js
        //1: 理解了题意之后还是比较简单的。
        //2:第一步找到数组中的最小值,当作为最小叶子节点。
        //3:后面就是根据这个最小值的index,去上层找它的直接父节点。(对应关系就是 / 2)
  29. 【任务调度】
  30. 【匿名信】
  31. 【密室逃生游戏】
  32. 【快递业务站】
    js
        //图的遍历
  33. 【对称美学】
  34. 【箱子之字形摆放】
    js
      //1:可以设置一个大小为n的数组,这样需要做的就变成了怎么把对应的字母放到指定的数组中去。
      //2:设置一个flag变量,这样的话就可以控制在转弯的时候放到哪个数组中去了。
  35. 【数组合并】
  36. 【挑选字符串】
  37. 【优选核酸检测点】
  38. 【最短木板长度】
    js
      //贪心的思想,遍历给的木料长度,每次都补一下最短的木板(只拿出1m的长度),每次补完之后重新排序,找到最短继续补1m,
  39. 【最多获得的短信条数】
    js
        //贪心算法  可以算出平均每一块钱对应多少条来排序
  40. 【星际篮球争霸赛】
    js
        //等和子数组问题
  41. 【最左侧冗余覆盖子串】
  42. 【端口合并】
    js
        //区间合并类的题目 双层循环合并即可,唯一需要注意的是判断两个区间相同元素的个数可以用set来加个速
  43. 【最大利润】
    js
      //股票买卖的最佳时机
  44. 【最长的密码】
  45. 【计算数组中心位置】
    js
      //预处理数组
  46. 【积木最远距离】
  47. 【区间交叠问题】
  48. 【整理扑克牌】
  49. 【分奖金】
    js
        //单调栈
  50. 【计算快递业务主站点】
    js
      //类似岛屿个数的那种DFS 题目
  51. 【去除多余空格】
  52. 【最差产品奖】
    js
        //固定长度滑动窗口
  53. 【最多等和不相交连续子序列】
    js
      //可以利用前缀和获取对应子数组的和
  54. 【货币单位换算】
  55. 【查找单入口空闲区域】
    js
      //类似岛屿问题,多入口不算
  56. 【预订酒店】
  57. 【基站维护最短距离】
  58. 【士兵过河】
    js
      1:出这种hard题,感觉想招ACM选手。。。
      2:类似一个经典的过桥问题,但是有变种,手电筒换成了小船,过桥也变化了过河。。。
      3:最关键的目标就是在过河过程中,让最慢的两个人消耗的时间最短。
      具体的方法就是让最慢的两个一起过河,然后让对岸快的人回来送船。(其实从题目给出的示例的说明中,也能发现符合这个逻辑)
      1、让用时最短的两个士兵a[0], a[1]划船过河到对岸,用时a[1]
      2、然后让a[1]留在对岸,让最快的士兵a[0]划船回来本岸,用时a[0]
      3、然后让本岸用时最长的两个士兵划船过河到对岸
      4、然后再让对岸用时最短的士兵a[1]划船回来本岸
      按照上述步骤进行循环,直到用时达到上限T,或者士兵全部运完。
      5:有重复的子问题,那么动态规划也就顺势而出:
      定义:dp[i] 为 第 0~i 士兵全部过河所需的最短时间。(首先肯定要对耗时数组 a 进行升序排序)
      初始状态:
      士兵总数为1,只能走到第1步:dp[0] = a[0]
      士兵总数为2,只能走到第1步:dp[0] = a[1]
      转移方程:
      dp[i] = min(dp[i - 1] + a[0] + get_shorter_time(a[0], a[i]), 
      dp[i - 2] + a[0] + get_shorter_time(a[i - 1], a[i]) + a[1] + get_shorter_time(a[0], a[1]))
      转义方程解释:
      方案1:本岸剩余士兵个数为奇数,0~i-1 士兵都已经过河(dp[i - 1] ),此时让对岸最快的士兵回来,也就是a[0],然后0号士兵和第 i 号士兵一起过河,用时a[i]。但是题目中有一个特殊条件:当2个士兵坐船1个士兵划船时,用时为 a[i]*10;a[i]为划船士兵用时。如果a[0] = 1, a[i] = 20, 那么a[0] 自己划船更快a[0]*10 < a[i],所以需要判断一下。
      因此:dp[i - 1] + a[0] + get_shorter_time(a[0], a[i])
      方案2:本岸剩余士兵个数为偶数,方案1就不成立了,需要回退一步,0~i-2 士兵都已经过河(dp[i - 2] ),此时让对岸最快的士兵回来,也就是a[0],然后 i-1 号士兵 和i 号士兵划船过河(最慢的两个士兵),用时a[i],然后对岸最快的a[1]划船回来,用时a[1],然后0号士兵和1号士兵划到对岸,用时a[1]。同时考虑题目中的特殊条件,每次两个人过河的时候,都需要考两次一下是否一个人划船更快。
      因此:dp[i - 2] + a[0] + get_shorter_time(a[i - 1], a[i]) + a[1] + get_shorter_time(a[0], a[1])
      6:OK,说明到此结束,考试出这题,能做出来的凤毛麟角吧。我想了很久,网上也各种搜博客和相关的答案才理解的。
  59. 【查找二叉树节点】
  60. 【硬件产品销售方案】
    js
        //leetcode40 组合总和2
  61. 【核酸最快检测效率】
  62. 【计算网络信号】
  63. 【异常的打卡记录】
  64. 【删除重复数字后的最大数字】
    js
      //贪心+单调栈
  65. 【字符串解密】
  66. 【找等值元素】
  67. 【任务总执行时长】
  68. 【水库蓄水问题】
    js
      //1:leetcode 原题,
        设两指针 i , j,指向的水槽板高度分别为 h[i] , h[j] ,此状态下水槽面积为 S(i, j)。由于可容纳水的高度由两板中的 短板 决定,因此可得如下 面积公式 :
                                                        S(i, j) = min(h[i], h[j]) × (j - i)
    
        在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 -1−1​ 变短:
        若向内 移动短板 ,水槽的短板 min(h[i], h[j])可能变大,因此下个水槽的面积 可能增大 。
        若向内 移动长板 ,水槽的短板 min(h[i], h[j])不变或变小,因此下个水槽的面积 一定变小 。
    
        因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出;即可获得最大面积。
  69. 【单词倒序】
  70. 【找出重复代码】
    js
        //最长公共子串   
            var maxLengthLCS = function (s1, s2) {
            //dp[i][j]表示s1[..i]与s2[...j]的最长公共子串长度
            let m = s1.length,
              n = s2.length
            let dp = Array.from(new Array(m + 1), () => new Array(n + 1).fill(0))
            for (let i = 1; i <= m; i++) {
              for (let j = 1; j <= n; j++) {
                if (s1[i] == s2[j]) {
                  dp[i][j] = dp[i - 1][j - 1] + 1
                } else {
                  dp[i][j] = 0
                }
              }
            }
            console.log(dp)
          };
  71. 【优雅子数组】
    js
      //1:直接上暴力法吧,感觉这题如果有什么特殊的解法,应该是要难倒一大片人。
        2:唯一找到一个类似的题目:1157. 子数组中占绝大多数的元素 - 力扣(LeetCode)
        但是感觉考这种hard中的hard真的有用吗。。。暴力能做一点是一点吧。
        3:上一个稍微取巧一点的方法,用数组的下标代表数字的大小,数组的值代表下标数字出现的个数。这样不用使用map来统计每个数字出现的次数。
  72. 【数字加减游戏】
    js
        1:题目说可以加也能减,如果+a和-a同时存在,则正负相抵,啥都没做但已经使用了2次,所以可得-a和+a只能有一个存在。
        2:存在下面三种情况:
        a、s-a*i+b*j=t -> t-(s-a*i)=b*j -> (t-(s-a*i))%b=0
        b、s+a*i+b*j=t >t-(s+a*i)=b*j-> (t-(s+a*i))%b=0
        c、s+a*i- b*j=t - t-(s +a*i) =-b*j -> (t-(s+a*i))%b=0这样一来就很清楚了。
        t减去 s对a的递增或者递减 整除 b,增或者递减的次数则是a的使用次数。递增递减同时进行,先整除b的则是最小使用次数。
        3:所以b是加还是减,应该都没有影响,主要起作用的是a是+ 还是-。
  73. 【猜字谜】