leetcode面试题之数组


注:p为leetcode顺序题号,o为leetcode上剑指offer第二版题号

p27 移除元素

题目:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

链接:https://leetcode.cn/problems/remove-element/

思路:双指针

  1. p1从头到尾遍历
  2. 2.p2记录值不等于val
public int removeElement(int[] nums, int val) {
        int n = nums.length, p2 = 0;
        for (int p1 = 0; p1 < n; p1 ++) {
            if (nums[p1] != val) {
                nums[p2 ++] = nums[p1];
            }
        }
        return p2;
    }

p42 接雨水

在这里插入图片描述

/**
 * 42. 接雨水
 * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
 * https://leetcode-cn.com/problems/trapping-rain-water/
 */
/**
 * @param {number[]} height
 * @return {number}
 */
var trap = function(height) {
    let n = height.length, res = 0
    if (n === 0) return 0
    // leftMax[i]:保存i左边的最大值 rightMax[i]:保存i右边的最大值
    let leftMax = [], rightMax = []

    // 处理两边界
    leftMax[0] = height[0]
    rightMax[n - 1] = height[n - 1]

    // 从左往右遍历,找i左边的最大值
    for (let i = 1; i < n; i ++) {
        leftMax[i] = Math.max(leftMax[i - 1], height[i])
    }
    // 从右往左遍历,找i右边的最大值
    for (let i = n - 2; i >= 0; i --) {
        rightMax[i] = Math.max(rightMax[i + 1], height[i])
    }
    // 遍历求每个矩形上方的雨水量:min(左最大值,右最大值)减去当前高度值
    for (let i = 0; i < n; i ++) {
        res += Math.min(leftMax[i], rightMax[i]) - height[i]
    }
    return res
};

p54 螺旋矩阵

在这里插入图片描述

/**
 * 54. 螺旋矩阵
 * 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
 * https://leetcode-cn.com/problems/spiral-matrix/
 */
/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var spiralOrder = function (matrix) {
    const res = [], n = matrix.length, m = matrix[0].length,
        // dx dy:定义4个方向 st:标记是否遍历过
        dx = [0, 1, 0, -1], dy = [1, 0, -1, 0],
        st = Array.from({length: n}, () => Array.from({length: m}, () => false))
    if (n < 0) return res

    // 从左上角开始遍历,x y:位置 d:方向
    for (let i = 0, x = 0, y = 0, d = 0; i < n * m; i++) {
        res.push(matrix[x][y]) // 遍历
        st[x][y] = true // 标记

        let a = x + dx[d], b = y + dy[d] //新的方向
        // 判断条件:1.走到边界 2.已经遍历过
        if (a < 0 || a >= n || b < 0 || b >= m || st[a][b]) {
            d = (d + 1) % 4 // 方向变化
            a = x + dx[d]
            b = y + dy[d]
        }
        x = a
        y = b
    }
    return res
};

p209 长度最小的子数组

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

链接:https://leetcode.cn/problems/minimum-size-subarray-sum/

思路:滑动窗口

  1. 双指针 l r 分别表示滑动窗口的左右两端
  2. 窗口中的数之和sum<target时,r右移;否则l右移
public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length, sum = 0;
        int res = Integer.MAX_VALUE;

        for (int l = 0, r = 0; r < n; r ++) {
            sum += nums[r];
            while (sum >= target) { // 注意边界条件
                res = Math.min(res, r - l + 1);
                sum -= nums[l ++];
            }
        }
        return res == Integer.MAX_VALUE ? 0 : res;
    }

p704 二分查找

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

链接:https://leetcode.cn/problems/binary-search/

思路: 注意边界条件

  1. r = n - 1
  2. while (l <= r)
public int search(int[] nums, int target) {
        int n = nums.length;
        int l = 0, r = n - 1;
        while(l <= r) { // 注意边界条件
            int m = l + r >> 1;
            if (nums[m] > target) {
                r = m - 1;
            } else if (nums[m] < target) {
                l = m + 1;
            } else {
                return m;
            }
        }
        return -1;
    }

p997 有序数组的平方

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

链接:https://leetcode.cn/problems/squares-of-a-sorted-array/

思路:双指针

​ 负数的平方可能会比正数的平方大
​ 数组两头的平方值大于中间的平方值

1.l指向数组最左端;r指向数组最右端

2.i指向平方值结果数组,从最大值开始

public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        int l = 0, r = n - 1, i = n - 1; // 结果数组索引
        int[] res = new int[n]; // 结果数组
        while (l <= r) {
            if (nums[l] * nums[l] < nums[r] * nums[r]) {
                res[i --] = nums[r] * nums[r --];
            } else {
                res[i --] = nums[l] * nums[l ++];
            }
        }
        return res;
    }

o3 数组中重复的数字

/**
 * 剑指 Offer 03. 数组中重复的数字
 * 找出数组中重复的数字。
 * 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。
 * 数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。
 * 请找出数组中任意一个重复的数字。
 * https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
 */
/**
 * @param {number[]} nums
 * @return {number}
 */
var findRepeatNumber = function(nums) {
  let n = nums.length
  // 遍历一遍,如果不在[0, n-1]范围内,返回-1
  for (let x of  nums) {
    if (x < 0 || x >= n) return -1
  }
  // 遍历找重复数字
  for (let i = 0; i < n; i ++) {
    // 一共开辟n个位置,每个数存放在对应值的位置
    // 如果当前位置的数不在其对应位置,则将当前位置的数与其应在的位置交换
    while (nums[nums[i]] !== nums[i]) {
      // [nums[i], nums[nums[i]]] = [nums[nums[i]], nums[i]]  不能这样用,会超时,应该把nums[nums[i]]放在前面,防止nums[i]先改变了
      [nums[nums[i]], nums[i]] = [nums[i], nums[nums[i]]]

      /* 或者可以先用一个临时变量把nums[i]存储起来
      let temp = nums[i];
      [nums[i], nums[temp]] = [nums[temp], nums[i]];
      */
    }
    // 交换完成后,如果当前位置的数还不在对应位置,说明有重复值,即该位置和其应在的位置
    if (i !== nums[i]) return nums[i]
  }
  return -1 // 没有重复 返回-1
};

o39 数组中出现次数超过一半的数字

/**
 * 剑指 Offer 39. 数组中出现次数超过一半的数字
 * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
 * 你可以假设数组是非空的,并且给定的数组总是存在多数元素。
 * https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/
 */
/**
 * @param {number[]} nums
 * @return {number}
 * 思路:思路很奇特
 * 如果一个数大于一半,这个数最后的数量肯定大于其他所有数的数量之和
 * 如果当前数是所求数,count++;不是所求数,则count--
 * 用非所求数来消耗所求数,消耗不完,最后剩下的数就是所求数
 * 时间复杂度:O(n) 空间复杂度:O(1)
 *
 * y总说:创造一个新解法比回忆起一个解法难一万倍!要多刷题!
 */
var majorityElement = function(nums) {
  let count = 0, value = -1
  for (let x of nums) {
    // 如果count===0,记录value,count++
    if (!count) {
      count ++
      value = x
    } else {
      // count!==0 此时value值存在,判断value是否等于当前x,等于count增加,否则count消耗
      if (value === x) count ++
      else count --
    }
  }
  return value
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值