数组✅
本章准确的说不算算法内容,只是针对数组常用操作做一些说明,
说一下 Array 的常用方法?
答案
延伸阅读
数组合并?
给定两个有序数组 s1、s2, 将 s1 和 s2 合并成一个有序数组。注意 s1 的长度可以容纳 s2 的所有元素。
const s1 = [1, 3, 5, 6, undefined, undefined, undefined]
const s2 = [3, 10]
function mergeArrays (arr1, arr2) {
}
答案
三数求和?
给定数组 s1, 返回所有 array[i, j, k] 的和为 0 的解,对应索引组成的集合
const s1 = [-1, -2, 1, 2, 0]
function threeSum (arr) {
}
答案
两数求和问题?
给定一个数组 S 和一个整数 target,在数组 S 中找到两个数,使得它们的和等于 target。例如
const s1 = [1, 3, 5, 6]
const target = 9
function twoSum (arr, target) {
}
答案
最大子数组和
给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
const nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
function maxSubArray (nums) {
}
答案
寻找数组中的第 k 大元素
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
const nums = [3, 2, 1, 5, 6, 4]
const k = 2
function findKthLargest (nums, k) {
}
答案
Fizz Buzz 问题
答案
核心概念 经典条件判断算法题(LeetCode 412):从 1 到 n 遍历:
- 若同时是 3 和 5 的倍数(即 15 的倍数),输出
"FizzBuzz"。 - 若仅是 3 的倍数,输出
"Fizz";若是 5 的倍数,输出"Buzz"。 - 否则输出数字字符串本身。
代码实现:
function fizzBuzz (n) {
const result = []
for (let i = 1; i <= n; i++) {
const divBy3 = i % 3 === 0
const divBy5 = i % 5 === 0
if (divBy3 && divBy5) {
result.push('FizzBuzz')
} else if (divBy3) {
result.push('Fizz')
} else if (divBy5) {
result.push('Buzz')
} else {
result.push(String(i))
}
}
return result
}
// 复杂度分析
// 时间复杂度:O(n)
// 空间复杂度:O(1)(除返回值外)
面试官视角
- 考察代码整洁度与判断顺序(必须先判断 15 的倍数,或通过字符串拼接
let s = ''; if (div3) s += 'Fizz'; if (div5) s += 'Buzz';提高扩展性)。
寻找首次匹配子序列
答案
核心概念
在主数组 arr 中寻找子序列 subseq 首次出现的起始索引:
- 如果要求连续子数组匹配,采用滑动窗口或双指针逐个比较,或者 KMP 算法。
- 如果要求非连续但相对顺序一致的子序列,使用贪心双指针匹配。
连续子数组匹配实现(类似 indexOf / strStr):
function findSubsequence (arr, subseq) {
const m = arr.length
const n = subseq.length
if (n === 0) return 0
if (m < n) return -1
for (let i = 0; i <= m - n; i++) {
let match = true
for (let j = 0; j < n; j++) {
if (arr[i + j] !== subseq[j]) {
match = false
break
}
}
if (match) return i
}
return -1
}
// 验证
console.log(findSubsequence([1, 2, 3, 4, 5], [3, 4])) // 2
console.log(findSubsequence([1, 2, 3], [4])) // -1
面试官视角
- 考查双指针边界判断(
i <= m - n)与滑动窗口思想。
移动零
答案
核心概念
LeetCode 283 原题:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
- 约束要求:必须在不复制数组的情况下**原地(in-place)**对数组进行操作,空间复杂度为 $O(1)$。
- 解题思路(双指针一次遍历):维护指针
slow指向当前第一个为 0 的位置,快指针fast遍历数组。当nums[fast] !== 0时,将其与nums[slow]交换,并将slow右移。
代码实现:
function moveZeroes (nums) {
let slow = 0
// 1. 将所有非零元素按顺序移动到前面
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== 0) {
if (slow !== fast) {
// 交换非零元素与 slow 处的 0
const temp = nums[slow]
nums[slow] = nums[fast]
nums[fast] = temp
}
slow++
}
}
return nums
}
// 验证
const list = [0, 1, 0, 3, 12]
moveZeroes(list)
console.log(list) // [1, 3, 12, 0, 0]
复杂度分析
- 时间复杂度:$O(n)$,只需遍历一次数组。
- 空间复杂度:$O(1)$,无任何额外数组开销。
面试官视角
- 考查对双指针(快慢指针)原地调整数组顺序的熟练程度,交换优化避免了二次循环重写 0 的步骤。