跟着卡哥学算法Day 1:数组整体学习 & 常见题目

1518 字
8 分钟
跟着卡哥学算法Day 1:数组整体学习 & 常见题目

数组在内存空间中连续存储的,这样会使得通过下标获取数组元素很方便,但删除或新增元素时,就需要移动其他元素的位置。

接下来都通过 🌟 来代表题目难度:

  • 简单:🌟
  • 中等:🌟🌟
  • 困难:🌟🌟🌟

经典题目#

704. 二分查找 🌟#

力扣链接

前提#

有序排列

无重复值

题目描述#

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

示例 1:

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

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

  • 你可以假设 nums 中的所有元素是不重复的。
  • n 将在 [1, 10000]之间。
  • nums 的每个元素都将在 [-9999, 9999]之间。

解题思路#

重点:定好区间

开闭:包含这个元素

左闭右闭:[left, right]

左闭右开:[left, right)

需要定义三个值:

  • left:0 左侧初始下标
  • right:nums.length - 1 右侧初始下标
  • middle

判断条件:

确保 left <= right

  • left + ((right - left) >> 1):计算 middle
  • nums[middle] < target]:中间值小于目标值,目标值在右侧,更新 left 为middle + 1
  • nums[middle] > target]: 中间值大于目标值,目标值在左侧,更新 right 为middle - 1
  • nums[middle] === target:等于目标值,返回 middle

代码#

function search(nums: number[], target: number): number {
let left = 1
let right = nums.length - 1
while (left <= right) {
const middle = left + ((right - left) >> 1)
if (nums[middle] === target) return middle
if (nums[middle] > target) {
right = middle - 1
} else {
left = middle + 1
}
}
return -1
}

相似题目#

35. 搜索插入位置 🌟

思路:

  • 按照二分法找到的返回下标
  • 未找到则返回 right + 1(left 一直增加,当一直未找到 targe 时,left 会不满足条件,即 left > right,此时 right + 1 就是插入的位置)
function searchInsert(nums: number[], target: number): number {
let left = 0
let right = nums.length - 1
while (left <= right) {
let middle = left + ((right - left) >> 1)
if (nums[middle] > target) {
right = middle - 1
} else if (nums[middle] < target) {
left = middle + 1
} else {
return middle
}
}
return right + 1
}

34. 在排序数组中查找元素的第一个和最后一个位置 🌟🌟

解题思路:

  • 两次二分查找

    • 查找目标值第一次出现位置 nums[middle] >= target,一直移动 right
    • 查找目标值最后一次出现位置 nums[middle] <= target,一直移动 left
  • target 在数组左或右,返回 [-1, -1]

  • target 在数组范围内,但不存在 right - left < 0,返回 [-1, -1]

  • target 在数组范围内,存在,返回 [left, right]

function searchRange(nums, target) {
if (nums[0] > target || nums[nums.length - 1] < target) return [-1, -1]
const left = searchLeft(nums, target)
const right = searchRight(nums, target)
if (right - left < 0) return [-1, -1]
return [left, right]
}
function searchLeft(nums, target) {
let left = 0
let right = nums.length - 1
while (left <= right) {
let middle = left + ((right - left) >> 1)
if (nums[middle] < target) {
left = middle + 1
} else {
right = middle - 1
}
}
return left
}
function searchRight(nums, target) {
let left = 0
let right = nums.length - 1
while (left <= right) {
let middle = left + ((right - left) >> 1)
if (nums[middle] <= target) {
left = middle + 1
} else {
right = middle - 1
}
}
return right
}

69. x 的平方根 🌟

function mySqrt(x: number): number {
if (x < 2) return x
let left = 0
let right = x
while (left <= right) {
let mid = left + ((right - left) >> 1)
if (mid * mid < x) {
left = mid + 1
} else if (mid * mid > x) {
right = mid - 1
} else {
return mid
}
}
return right
}

367. 有效的完全平方数 🌟

function isPerfectSquare(num: number): boolean {
let left = 0
let right = num
while (left <= right) {
let mid = left + ((right - left) >> 1)
if (mid * mid === num) {
return true
} else if (mid * mid < num) {
left = mid + 1
} else {
right = mid - 1
}
}
return false
}

27. 移除元素 🌟#

力扣链接 🌟

题目描述#

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。 返回 k。

解题思路#

  • 双指针
    • slow:填充进新数组的 value(只有 nums[fast] !== val 才填充进新数组)
    • fast:代表新数组的 index

“一个萝卜一个坑”

代码#

function removeElement(nums: number[], val: number): number {
let k = 0
for (let i = 0; i < nums.length; i++) {
if (nums[i] !== val) {
nums[k] = nums[i]
k++
}
}
return k
}

相似题目#

26. 删除有序数组中的重复项 🌟

思路:

  • 双指针
  • 慢指针填充条件:当 nums[fast + 1] !== nums[fast] 时,填充进新数组
function removeDuplicates(nums: number[]): number {
let slow = 0
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast + 1] !== nums[fast]) {
nums[slow] = nums[fast]
slow++
}
}
return slow
}

283. 移动零 🌟

思路:

  • 双指针
  • 填充条件:当 nums[fast] !== 0 时,填充进新数组
  • 最后使用 fill 填充数组
function moveZeroes(nums: number[]): void {
let slow = 0
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== 0) {
nums[slow] = nums[fast]
slow++
}
}
nums.fill(0, slow)
}

844. 比较含退格的字符串 🌟

思路:

function backspaceCompare(s, t) {
const s1 = getResult(s)
const t1 = getResult(t)
return s1 === t1
}
function getResult(s) {
let slow = 0
let count = 0
s = s.split('')
for (let fast = 0; fast < s.length; fast++) {
if (s[fast] !== '#') {
s[slow] = s[fast]
slow++
} else {
if (slow !== 0) {
slow--
s[slow] = ''
count++
}
}
}
s.fill('', s.length - 1 - count)
return s.join('')
}

977. 有序数组的平方 🌟#

力扣链接 🌟

思路:

  • 双指针
function sortedSquares(nums: number[]): number[] {
let i = 0
const length = nums.length
let j = length - 1
let res = new Array(length).fill(0)
let k = length - 1
while (i <= j) {
let left = nums[i] * nums[i]
let right = nums[j] * nums[j]
if (left < right) {
res[k] = right
j--
} else {
res[k] = left
i++
}
k--
}
return res
}
跟着卡哥学算法Day 1:数组整体学习 & 常见题目
https://wangxiang.website/posts/算法/array-code/
作者
翔子
发布于
2025-02-12
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
翔子
前端开发工程师
公告
博客已从 VitePress 迁移到 Astro + Firefly 主题,223 篇文章全部保留。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
221
分类
9
标签
28
总字数
411,914
运行时长
0
最后活动
0 天前

文章目录