2021.12.28>>第102场周赛

164 阅读2分钟

第102周赛

题目

905. 按奇偶排序数组

904. 水果成篮

907. 子数组的最小值之和

906. 超级回文数

解题905. 按奇偶排序数组

给定一个非负整数数组 A,返回一个数组,在该数组中, A 的所有偶数元素之后跟着所有奇数元素。

你可以返回满足此条件的任何数组作为答案。

示例:

输入:[3,1,2,4]
输出:[2,4,3,1]
输出 [4,2,3,1][2,4,1,3][4,2,1,3] 也会被接受。

快慢指针

快指针先走,如果碰到基数,不作处理,碰到偶数后,先判断此时和慢指针位置是否一致,否则与慢指针交换,这样,当快指针走到最后,数组区间,从零到慢指针此时的位置都是偶数。

var sortArrayByParity = function(nums) {
  let s = 0
  for(let f = 0; f < nums.length; f++){
    if(nums[f]%2 ===0){
     //解构赋值
     if(s!==f){ [nums[s],nums[f]] = [nums[f],nums[s]]}
     // 第三变量交换
     // const temp = nums[s]
     // nums[s++] = nums[f]
     // nums[f] = temp
      s++;
    }
  }
  return nums
};

左右指针(效率偏低)

通过循环,左指针找到第一个基数的位置,右指针找到第一个偶数的位置,两者交换,继续循环

let l = 0
  let r = nums.length  - 1
  while(l < r){
    while(nums[l] % 2 === 0 && l < r){l++}
    while(nums[r] % 2 !== 0 && l < r){r--}
    [nums[l],nums[r]] = [nums[r],nums[l]]
    console.log(l,r)
    console.log(nums)
    l++;
    r--;
  }
  return nums

相似题目

283. 移动零

解题904. 水果成篮

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。 给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

示例 1:

输入:fruits = [1,2,1]
输出:3
解释:可以采摘全部 3 棵树。

示例 2:

输入:fruits = [0,1,2,2]
输出:3
解释:可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。

示例 3:

输入:fruits = [1,2,3,2,2]
输出:4
解释:可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。

示例 4:

输入:fruits = [3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:可以采摘 [1,2,1,1,2] 这五棵树。

这个问题的关键有几点,①你怎么知道当前水果是不是第三种水果、②当碰到第三种水果后,怎么找到第二种水果出现的最左边位置,以用来记录全新的能装的数量、③当前能装的最大数量

解决:①用一个数组模拟成篮子,碰到没有的就判断数组的长度,当数组长度超过2时,就是碰到第三种水果了、②我们设置一个变量来记录上一种水果的最左边位置,先设置为0,从0开始,当碰到相同的水果,判断是否是该边界值的水果,如果不是,则更新边界值位置,因为已有的最新的水果,永远都是第二种,这样就能保证该变量永远都是第二个值的最左边值、③设置一个用来记录第一种水果的最左边值的变量,让碰到第三种水果时,当前能装的最大数目就是该边界值到目前位置的距离,而该边界值就变成了②里面的值

var totalFruit = function(fruits) {
  // 记录能装水果最大数
  let max = 0
  // 记录第二种水果的最左边值
  let n  = 0;
  // 记录第一种水果的最左边值
  let l = 0;
  // 水果篮子
  const list = []
  for(let r = 0; r < fruits.length; r++){
    // 新水果
    if(!list.includes(fruits[r])){
      // 前两种水果
      if(list.length <= 1){
        list[list.length] = fruits[r]
      }else{
        // 第三种水果
        // 更新篮子
        // 左边界值更改
        l = n
        list[0] = fruits[r - 1]
        list[1] = fruits[r]
      }
    }
    // 在你遇到第三种水果前,目前最新的这种永远都是第二种
    // 所以如果已有这种水果,但不是之前记录的第二种,则更换
    if(fruits[n] !== fruits[r]){n = r}
    max = Math.max(max,r - l + 1)
  }
  return max
};

题解907. 子数组的最小值之和

给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。

由于答案可能很大,因此 返回答案模 10^9 + 7 。

示例 1:

输入:arr = [3,1,2,4]
输出:17
解释:
子数组为 [3][1][2][4][3,1][1,2][2,4][3,1,2][1,2,4][3,1,2,4]。 
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。

示例 2:

输入:arr = [11,81,94,43,3]
输出:444

连续的子数组是有 n*(n-1)/2 + n => n*(n+1) /2 我们可以将问题分解成以某个数为最小值的区间有哪些,以该数为中心向左向右扩展。

区间数= (左边数+1) * (右边数+1)

结果 =该数 * 区间数

题目是找出区间的最小值,我们是以最小值找出区间,不过这样的时间复杂度仍然是n*n,因为以每个数为中心时,都有可能扩展到两边尽头

每一次其实等于在向左、向右找大于等于自己的数,直到有小于自己的数

给一个数组,寻找里面每个值的prev smaller element、 next smaller element

这里就运用到单调栈,单调栈的作用就是为了在数组中寻找比目标值更大或者更小的前一个、后一个值,单调栈存储的索引值

维护一个单调栈

496. 下一个更大元素 I

503. 下一个更大元素 II

739. 每日温度

42. 接雨水

做好这些题目好更好理解