之前按照顺序来做题,总是一天一道还卡死了,后来求教了师兄
才知道由简到难,按照这样的顺序做
推荐了我代码随想录,跟着那个顺序刷题。
这两天将这里的数组做完了,对其进行一个总结梳理:
题目1:二分查找(704)
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
思路:
每一次都对数组的中位数进行选取比较,可能会遇到一下的情况:
- 大于目标值,即目标值会出现在中位数的左侧,就将此时的区间右边界变为中位数的上一位
- 小于目标值,即目标值会出现在中位数的右侧,就将此时区间的左边界变为中位数的下一位
- 等于目标值,直接返回此时的下标
当区间满足,在此区间内有值,即合法的时候,我们按照这个顺序一直执行即可。
题目2:搜索插入位置(35)
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n)
的算法。
思路:
出现对时间复杂度要求是log,首先想到二分法
本题查找部分可以参照题目1
当无法找到的时候,此时的区间边界左边界是大于右边界的,此时可以发现我们所要插入的数值位于此时右边界的下一位,返回该位即可。
题目3:在排序数组中查找元素的第一个和最后一个位置(34)
给你一个按照非递减顺序排列的整数数组 nums
,和一个目标值 target
。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target
,返回 [-1, -1]
。
你必须设计并实现时间复杂度为 O(log n)
的算法解决此问题。
思路:
一般查找思路可以按照上面的来
我这里想着,查找到一个符合的值之后,定义两个临时变量,i--和j++,直到找到和目标值不一样的下标,最后的边界就是此时的i+1和j-1(因为最后一次的判断不满足条件的时候执行了一次i--和j++),但我不知道这样会不会时间复杂度变为O(n)
可以按照左右边界分开查找
左边界,找到>=目标值的最右边的元素
右边界,找到<=目标值的的最左边元素
题目4:移除元素(27)
给你一个数组 nums
和一个值 val
,你需要 原地 移除所有数值等于 val
的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1)
额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
思路:
因为额外空间只可以使用一个,将其定位数组变化后的长度
起始时,该值位数组原长。
利用for遍历每一位数值元素,当出现某一位的值和目标值相等,此元素后面的元素一次前移一位
这里需要注意,找到i时,移动使用for语句,要使得j=i+1,因为用j=i的话,每一次移动的最后一位是无法填补元素的,会报错
每删减一次元素,此时的长度就会减去1
并且删减掉第i个位置,移动之后第i个位置补上了元素,在此时也需要i--
题目5:有序数组的平方(977)
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
思路:
一开始想着找0,但无法保证每一个数组都有零
面对这样的数组,我们无法从中间取值来定界,只能从两边入手
可以求边界平方最高的,将其存入数组
若取的是左边界,存了该数之后,左边界加一
若取的是右边界,存了该数之后,右边界减一
此时存入数组的是递减的排序,可以使用reverse(v.begin(),v.end())进行翻转
题目5:长度最小的子数组(209)
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其和 ≥ target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
思路一:
可以做哈希表,两个都是int类型,哈希表的关键字是每个元素的下标,对应的键值是该下标所满足的最小长度,若是没有满足条件的,该下标为0
将哈希表做好之后,若是键值都是0,则返回0
若有不为0的元素,进行大小比较,返回最小值键值对应的关键字和关键字+键值
思路二:
用一个动态窗口,来储存满足条件的最小数组,定义长度是一个INT32_MAX
第一次,从下标为0开始取长度最小的数组,记录长度,取此时长度和定义长度的最小值
第二次,下标变为1取长度最小的数组,记录长度,取此时长度和定义长度的最小值
.............
因为我们只需要返回长度,每一次取最小的长度即可,没有要求返回该位置,所以可以使用一个for语句,在for中求和,当求得的和大于等于目标值之后,记录长度
减去此时存储的第一项,for中再加上满足条件的值,每一次都只记录长度
有点类似二分法的左右边界,只是右边界是通过for定义,左边界是满足条件之后+1
题目6:螺旋矩阵 II(59)
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
思路:
将其进行问题拆分
为了规律,每一次的插入元素,不论是行还是列,其所属的最后一个元素都不进行插入,留给下一个部分
比如:
1 | 1 | 2 |
4 | 5 | 2 |
4 | 3 | 3 |
3*3的矩阵中,按照1-2-3-4-5的插入数据,我们可以得到规律操作
若是按照
1 | 1 | 1 |
4 | 4 | 2 |
3 | 3 | 2 |
这种计算方法的话,需要根据具体情况具体确定行规律和列规律,对于较小的数字还好操作,数字一旦大了,就很难操作了
每一次操作,都相当于是外包围了一圈,操作了两行和两列,那么操作的循环次数就是n/2
第二次操作的时候,行和列的起始都各加一,他们在此次循环中所需要操作行/列就是1----n-1
...........
n是奇数的时候,最中间的一项自定义即可
题目7:螺旋矩阵(54)
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
思路:
参照构造螺旋矩阵的方法,逆推
m行n列
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 |
5 | 5 | 6 | 2 | ||||||
4 | 9 | 9 | 10 | 2 | |||||
8 | 12 | 11 | 11 | 6 | 2 | ||||
8 | 7 | 7 | 2 | ||||||
4 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
m和n中最小值,若最小值是偶数,则循环圈数为最小值除以2,若是奇数,除以2之后的值加一
最后再单独处理m=n且m为奇数的元素存入最后一个
最后:
在数组这些题中,我逐渐发现
首先掌握方法:二分查找和快慢指针的方法
面对不一样的题,具体先分析思路,有了想法,可以套这两个思路进行求解
面对难题,可以自己先试着取简单的例子,看有没有什么方法,最后总结技巧
其实算法就是前人精炼处理的经验