数组
二分查找(查)
二分查找的条件:
1、数组是有序数组
2、数组中无重复元素(一旦有了重复的数组使用二分法返回的条件就不唯一了)
二分查找的关键点:
这道题目主要的关键点就在于保持“区间的不变量”,对区间右边的定义决定了要使用左闭右开还是左开右闭。右开就是这个下标对数组有效,右闭就是这个下标对数组无效
总结:
对于数组来说,当知道一个元素的下标之后,查询一个数字是很快的,时间复杂度是O(1),一步到位。
但是如果不知道元素的下标,只知道要查询的元素,这种情况下就只能进行对数组进行遍历,从第一个元素开始查找,进行比较,这个时间复杂度是O(n)
此时,如果这个数组符合二分查找的条件,那就可是使用二分查找进行操作,一步一步缩小元素可能出现的范围,这个时间复杂度是O(logn),其中n 是数组的长度
移除元素(删)
数组真是出了通过下标查找元素的时候方便,然后就是干啥都不方便
这道题目是要删除数组中出现过的目标值元素,如果数组中元素不重复的,我们可以创建一个比原数组长度小于1 的数组,然后将不是目标值的数组移动到新数组中,这样时间复杂度是O(n),空间复杂度是O(n),因为需要开辟一块空间重新进行存储。
但是这道题目并没有说明元素是不可重复的,而且强调了要删除所有的目标值,这一条就比比较复杂,因为就算创建新数组,你不知道创建多长的,其实也可以整,但就是比较麻烦
而且这道题目明确要求必须仅使用O(1) 额外空间并原地修改数组,所以要牺牲时间来获取空间,那就使用两重遍历,第一for循环找数,第二for循环移动元素,这样时间复杂度是O(n^2),也就是暴力解法
因为力扣的输出不用管,但是它会按照你返回的数组长度进行遍历,本质上你的数组长度并没有发生变化,只是你给一个数组长度,它只会遍历输出到这里,所以每删除一个元素要在长度上进行减操作
此时,有一个思路就很妙了,那就是双指针法,双指针可以说是双层for循环的一种替代,但是通过双指针在不增加空间的情况下来降低时间复杂度。
一个快指针在前面进行判断,一个慢指针在后面进行收割,这两个指针代表的都是数组的下标
其实遍历数组的时候,就是在用 i 指针进行遍历,指哪取哪
这里增加了一个指针,遍历时,i 在前面指,然后 if 进行判断,如果不是我们要查找的目标值,那我就把你保留着,如果不是,我就不鸟你,i 继续。同时慢指针负责记录要返回的数组长度的工作
总结:
用好双指针,通过两个指针在一个for循环下完成两个for循环的工作
双指针在数组、链表、N数之和、字符串 中用起来都很绝:
数组:
移除元素
有序数组的平方
长度最小的子数组
链表:
翻转链表
删除链表中的倒数第n个元素
链表相交
环形链表
N数之和:
三数之和
四数之和
字符串:
反转字符串
替换空格
反转字符串里的单词
有序数组的平方
首先是数字的平方,这个好办,进行遍历,然后每个元素平方就可以了,麻烦就麻烦在有序上,因为存在负数,我们先平方后,然后再对平方后的数组进行排序就可以了,这是一种暴力的解法,而且用到了java语言特有的工具类
哪怎么可以在不使用工具类的情况下进行排序呢,就需要我们对得到的新元素进行排序
其次是有序数组,因为存在负数,其实两头的元素平方下来是最大的
题目的条件是这是一个递增的数组,而且平方之后的数组也是需要递增的,也就是返回的数组也要是递增的数组,这个条件能有什么用,能做什么文章呢
哪接下来要考虑的就是怎么比较,怎么排序了
首先考虑一下,能不能在原数组中进行排序呢?可以,但是会时间复杂度比较高,埋个线(好好了解一下数组的排序问题)
我们需要的是利用题目的特点进行排序,其实数组中的元素平方后,我们不能马上找到最小的数字,我们最有可能的就是有机会找到最大的数字,那就是要么是第一个元素,要么就是最后一个元素,那就对这两个元素进行比较,将最大的放在数组的末尾,然后小的那个元素进行待命,继续比较
接下来就是往哪放的问题了
如果是往原数组中放,会造成数字的丢失,因为从两头进行比较的话,可能有些数字还没比较就被覆盖了
所以那就开辟一下新的空间存放新的数组,返回的数组要是有序的,我们不能马上找到最小的元素,不能从小到大地放,只能从大到小,所以存放结果的时候,从新数组的最后一位往前放
总结:
开辟新的空间存放新数组
原数组定义两个指针从两边开始进行比较
将比较出的大的元素依次从新数组的后面往前进行存放
长度最小的子数组
螺旋矩阵||
数组的模拟,保持区间不变量
总结
二分查找是查,用元素的值查,是有序不重复的数组
移除元素是删,不开辟新空间的删,双指针顶两个for
有序数组的平方是改+排序,改好办,就是不好排序,开辟空间,利用题目特点进行排序
长度最小的子数组是更高一层的查,我不仅要查,还要在查的同时搞点事情,子数组是连续的,用双指针滑动窗口
螺旋矩阵是用数组模拟,考察的是对数组的掌握程度,更具体点是对数组遍历的掌握程度
所以一般的考虑思路就能有个大概的方向:
能不能暴力解决
查是不需要开辟新地址的,可以暴力试试,但是怎么可以查得方便是需要考虑的
删和改有时需要开辟新空间(因为要返回数组),可不可以不开辟空间进行呢
使用双指针会不会更方便呢