数组基础
重点:
- 存放在连续的内存空间
- 在C,C++中,一维和二维数组的地址是连续的
- JAVA和Python中有类似的数据结构,Python中有列表结构,但是地址并不是连续的
- 连续地址储存的好处有:访问速度更快,提高内存的使用效率,在大量数据传输中可以提高效率
- 不连续地址储存的好处:允许动态拓展或缩小数据结构大小,有效的利用内存,不需要一次性分配一大块内存,支持并发或并行操作
- 相同类型数据
- 通过下标索引获取数据
- 下标从 0开始
- 元素不能删,只能覆盖(因为地址连续性)
LeetCode704 二分查找
题目:
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
思路:
二分法是一种迭代的方法,使用循环不断缩小搜索范围。二分法的时间复杂度为O(logn),普通线性搜索的时间为O(n),复杂度显著减小。
数组为有序数组,且无重复元素。逻辑简单,但是边界条件需要注意。
重点在于区间的定义:
- 左闭右闭:[left, right],while(left<=right),当left=right时是有意义的。中间值大于目标值时,right要赋值为中间值-1。
- 左闭右开:[left, right),while(left<right),当left=right时是无意义的。中间值大于目标值时,right要赋值为中间值,因为寻找的区间规定为左闭右开。
应用:
二分法的分割和搜索能力可以应用于
- 已排序数组中查找元素。
- 求解方程。
- 优化问题中 寻找最大值或最小值
- 缩小搜索区间
- 光线追踪算法中确定相交点
LeetCode27 移除元素
题目:
给定一个数组 nums
和一个值 val
,你需要原地移除所有数值等于 val
的元素。元素的顺序可能发生改变。然后返回 nums
中与 val
不同的元素的数量。
暴力解法:
由于连续性,所以移除元素后需要将后面的所有元素向前移动一位,也就是覆盖前面的元素。所以可以使用两层循环,一层用来遍历数组的元素,一层用来更新数组元素。很明显的缺点是时间复杂度过大,为O(n^2)。
暴力解法是一种较为直观的解法,原理是遍历每一个元素,然后对元素做出相应的保留或更改,所以适用的场合并不多。首先,这个解法适用于小规模、复杂度低、容易实现且对性能要求不高的情况。比较重要的应用在于是解决复杂问题的初步实现和调试工具。
双指针法:
使用快指针和慢指针两个指针在一层循环中实现对元素的移除和修改。快指针用来遍历所有的元素并判断这个元素是否需要留下,而慢指针只负责记录需要留下的元素,从而生成一个修改过后的“新数组”。
由于for循环会在很大程度上增加代码的时间复杂度,所以在写代码过程中应尽量避免。所以可以考虑增加指针的数量来提高算法效率(相当于增加工作的人数并增加了通信设备,减少了一个员工的工作量)。适用的场景有:有序数组的处理(合并,寻找和为定值的数对),滑动窗口,链表(反转)。
既然有双指针的出现,那应该也有三指针、四指针解法的出现。这样可以处理更复杂的情况。应用找到了三路快排,三数之和,合并n个有序数组。增加指针的本意是为了减少循环的使用,来减少时间复杂度。
指针:存储的是变量的内存地址,而不是变量的值,允许直接访问和操作内存。