刷题——数组

数组基础知识

数组是存放在连续内存空间上的相同类型数据的集合。
特点:

  • 数组下标都是从0开始的。
  • 数组内存空间的地址是连续的
  • 易读取
  • 难增删

简单

二分查找

二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

方法:二分查找(闭区间)

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
let left = 0, right = nums.length-1 
  while(left <= right){
    let mid = left + Math.floor((right - left)/2)
    if(nums[mid] > target){
      right = mid - 1
    }else if(nums[mid] < target){
      left = mid +1
    }else{
      return mid
    }
  }
  return -1
};

移除元素

移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

方法一:暴力

两层循环

var removeElement = function (nums, val) {
  let len = nums.length;
  // 遍历数组元素,查找val
  for (let i = 0; i < len; i++) {
    // 找到val
    if (nums[i] == val) {
      // 将val后面的数组元素整体前移1位
      for (let j = i + 1; j < len; j++) {
        nums[j - 1] = nums[j];
      }
      // 下标i之后的数值都前移1位,所以i也向前移1位
      i--;
      // 数组长度-1
      len--;
    }
  }
  return len;
};

方法二:双指针

var removeElement = function (nums, val) {
  let fast = 0,
    slow = 0,
    len = nums.length;
  while (fast < len) {
    if (nums[fast] != val) {
      nums[slow] = nums[fast];
      slow++;
    }
    fast++;
  }
  return slow;
};

有序数组的平方

有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

方法:双指针

var sortedSquares = function (nums) {
  let len = nums.length;
  let res = [];
  let left = 0,
    k = len - 1;
  right = len - 1;
  while (left <= right) {
    let leftNum = nums[left] * nums[left];
    let rightNum = nums[right] * nums[right];
    if (leftNum < rightNum) {
      res[k--] = rightNum;
      right--;
    } else {
      res[k--] = leftNum;
      left++;
    }
  }
  return res;
};

中等

长度最小的子数组

长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

方法:滑动窗口

var minSubArrayLen = function (target, nums) {
  let len = nums.length;
  // 窗口开始指针
  let i = 0;
  // 窗口末尾指针
  let j = 0;
  // 窗口里值的和
  let sum = 0;
  let res = Infinity;
  // 遍历,增大窗口
  for (; j < len; j++) {
    // 更新窗口值和
    sum += nums[j];
    // 当窗口值和大于等于目标值
    while (sum >= target) {
      // 计算窗口现在长度
      let nowLen = j - i + 1;
      // 比较更新最小窗口长度
      res = Math.min(res, nowLen);
      // 缩小窗口:窗口开始指针右移,更新窗口值和
      sum -= nums[i++];
    }
  }
  return res == Infinity ? 0 : res;
};

类似题目

最小覆盖子串

最小覆盖子串

输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”


var minWindow = function(s, t) {
    let maxLength = 100000, maxStartIndex = -1;
    let needWhich = {}; // 这里存 t 子串中各字符的数量,即需要满足的个数
    let windowAll = {}; // 这里存滑动窗口遍历过程中,处于滑动窗口内部的 t 中的字符
    // 初始化 needWhich,总共需要哪些字符
    for(let val of t) {
        needWhich[val] = (needWhich[val] || 0) + 1;
    }

    let left = 0, right = 0;
    let len = s.length, nowSatisfy = 0; // 要多少个键值对满足 needWhich 中的才算覆盖
    while(right < len) {
        const key = s[right]; // 右指针当前遍历到的字符
        right++;

        // 如果是 t 字符串中字符
        if(needWhich[key]) {
            windowAll[key] = (windowAll[key] || 0) + 1; // 当前滑动窗口的该键,值 + 1
            // 如果读取到这个字符后,该字符总数 === 覆盖的子串中的该字符总数了,那就总数 + 1
            if(windowAll[key] === needWhich[key]) {
                nowSatisfy++;
            }
        }
        
        // 当验证数量与需要的字符个数一致时,就应该收缩窗口了
        while(nowSatisfy === Object.keys(needWhich).length) {
            // 更新最小覆盖子串
            if (right - left < maxLength) {
                maxStartIndex = left;
                maxLength = right - left;
            }
            //即将移出窗口的字符
            const outKey = s[left];
            // 窗口左边界右移
            left++;
            // 如果是 t 字符串中字符
            if(needWhich[outKey]) {
                // 对于要移出窗口的这个字符的个数,如果 窗口内部 和 t 中的相同,即没有多余,那么 nowSatisfy--,开始找下一滑动窗口了,否则还得继续移除该字符
                if (windowAll[outKey] === needWhich[outKey]) {
                    nowSatisfy--;
                }
                windowAll[outKey]--;
            }
        }
    }

    return maxStartIndex === -1 ? "" : s.slice(maxStartIndex, maxStartIndex + maxLength);
};

螺旋矩阵

螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
在这里插入图片描述

var spiralOrder = function(matrix) {
  let len1=matrix.length,len2=matrix[0].length
  let res=[]
  let left=0,right=len2-1,top=0,bottom=len1-1
  while(left<=right&&top<=bottom){
    // 从左到右
    for(len2=left;len2<=right;len2++){
      res.push(matrix[top][len2])
    }
    // 从上到下
    for(len1=top+1;len1<=bottom;len1++){
      res.push(matrix[len1][right])
    }
    if(left<right&&top<bottom){
      // 从左到右
      for(let len2=right-1;len2>left;len2--){
        res.push(matrix[bottom][len2])
      }
      // 从下到上
      for(let len1=bottom;len1>top;len1--){
        res.push(matrix[len1][left])
      }
    }
    [left,right,top,bottom]=[left+1,right-1,top+1,bottom-1]
  }
  return res
};
console.log(spiralOrder([[1,2,3,4],[5,6,7,8],[9,10,11,12]]))

题目来源力扣

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值