代码随想录算法训练营Day1|数组理论基础,704. 二分查找,27. 移除元素 ,977. 有序数组的平方

96 阅读5分钟

数组理论基础

参考文档:programmercarl.com/%E6%95%B0%E…

数组在内存中的存储方式

数组是存放在连续内存空间相同类型数据的集合 数组下标从0开始,可以通过下标索引快速获取对应数据

🌰以整型数组为例 Pasted image 20250108103740.png

由于数组存放在连续空间内,在数组中删除/添加元素都需要移动被修改元素之后的元素的位置

Java语言二维数组的存放方式

在Java中,二维数组是一个包含多个数组的数组。二维数组中,每一行在内存地址上连续,而行与行之间并不一定连续 如int[3][4]在内存里看起来像这样:

[row 0] -> [0, 0, 0, 0]
[row 1] -> [0, 0, 0, 0]
[row 2] -> [0, 0, 0, 0]

LeetCode 704 二分查找

题目链接:leetcode.cn/problems/bi…

文章讲解:programmercarl.com/0704.%E4%BA…

视频讲解:www.bilibili.com/video/BV1fA…

思路

使用二分法的两个前提

  • 数组有序
  • 数组中无重复元素(二分法返回不唯一)

边界条件选择

  1. 区间左闭右开:则right不在区间内,初始值为nums长度
    1. 循环条件:while(left<right)
    2. 左闭:去右区间寻找,区间包含left不包含上轮中点mid,则left=mid+1
    3. 右开:去左区间寻找,区间不包含right不包含上轮中点mid,则right=mid
  2. 区间左闭右闭
    1. 循环条件:while(left<=right)
    2. 和上条左闭分析同理,两侧应该对应+1或-1

难点

在整个流程中,对于left和right的使用与赋值要统一一种类型的区间。一共有四处:

  1. 对left和right的初始值赋值
  2. while循环条件
  3. 换到左侧区间
  4. 换到右侧区间

细节

取中点时,mid=(left+right)/2先计算两数之和有溢出风险。 建议修改为mid=(right-left)/2+left,这样计算过程中不会出现比现有数字更大的数字。

LeetCode 27 移除元素

题目链接:leetcode.cn/problems/re…

文章讲解:programmercarl.com/0027.%E7%A7…

视频讲解:www.bilibili.com/video/BV12A…

思路

重点:

  1. 原地移除,即不可以使用多余的空间。
  2. 顺序可以打乱 值为val的元素不需要被保留,即可以覆盖。👉可以用需要保留的元素覆盖值为val的元素 那么就需要一个游走在原数组上的指针和游走在现数组上的指针。👉双指针法

双指针法:

  1. 如果原数组指针指向元素为val,只向前移动原数组指针
  2. 如果原数组指针指向元素不为val,把此元素赋值给现数组指针指向的位置,并把两个指针都向前移动

易错点

由于每次为现数组添加元素后,现数组指针都会向前移动,所以其一直等于现数组长度。 故最后退出循环后,只需要返回其值,无需+1

暴力解法

看到卡哥建议先写一次暴力法,下简述暴力解法

基本思路:循环遍历数组元素,每检查一个数组元素,如果需要删除,则循环把后面的元素向前移动 即需要两个循环嵌套,复杂度为O(n2)O(n^2)

注意:由于只有一个指针,需要一个变量记录新数组的长度。初始值为原数组长度,每找到一个val值元素,都把长度记录-1.

难点

  1. 何时退出循环返回长度 应该在每次循环的开始处检查,如果指针等于长度记录,就应返回
  2. 每次批量移动完元素,需要把指针向左移动一位,因为当前元素被覆盖为新的元素,需要重新检查

LeetCode 977 有序数组的平方

题目链接:leetcode.cn/problems/sq… 文章讲解:programmercarl.com/0977.%E6%9C… 视频讲解: www.bilibili.com/video/BV1QB…

思路

首先这道题可以依次平方每个数,再把它们排序,时间复杂度最少为O(nlogn)O(nlogn). 但原数组是有序的,上述方法不能利用这一点,于是如下考虑:

想象nums是分布在x轴上的点,他们对于函数y=x2y=x^2有不同的y。那么最小的y应该是最靠近原点的点,最大的y是距离原点最远的点。 所以既可以先找到最靠近原点的点,逐渐向外扩张填写平方数组;也可以先找到最远离原点的点,逐渐向内反向填写平方数组

🌰以数组[-6,-3,2,4]为例,有颜色数字表示计算顺序,并非下标 699E8583-0BFA-4FAD-82AF-68555AD6DBD2_1_201_a.jpeg

由于平方在正负区间内扩张方向相反,需要两个指针分别在正负区间内向相反方向移动👉双指针法

时间复杂度为O(n)O(n)

难点

尽管left和right都有可能进入不属于自己的区间,但这并不需要额外处理。因为当left和right处于同一区间,原本属于此区间的指针会一直移动直到与另一个指针重合,因为此时y=x2y=x^2是单调的

今日收获总结

今天学了约莫3小时,此外1小时在和博客网站的编辑器磨合

总体感受:今天是数组的入门练习,二分查找和双指针法都是很常用的技巧,写博客加画图能更好的帮助消化这些知识,这样实战的时候也能想起来用。之前也断断续续练过,但不成气候。希望这次能跟着打卡坚持下来~