第 11 天题目
0344. 反转字符串
- 标签:字符串
- 难度:简单
题目大意
给定一个字符串数组,将其反转。要求不能使用额外的数组空间。
解题思路
简单题,遍历字符串,将 s[i] 与 s[len-1-i] 交换即可。
代码
0015. 三数之和
- 标签:数组、双指针
- 难度:中等
题目大意
给定一个整数数组 nums,判断 nums 中是否存在三个元素 a、b、c,满足 a + b + c = 0。要求找出所有满足要求的不重复的三元组。
解题思路
直接三重遍历查找 a、b、c 的时间复杂度是:。我们可以通过一些操作来降低复杂度。
先将数组进行排序,以保证按顺序查找 a、b、c 时,元素值为升序,从而保证所找到的三个元素是不重复的。同时也方便下一步使用双指针减少一重遍历。时间复杂度为:
第一重循环遍历 a,对于每个 a 元素,从 a 元素的下一个位置开始,使用双指针 left,right。left 指向 a 元素的下一个位置,right 指向末尾位置。先将 left 右移、right 左移去除重复元素,再进行下边的判断。
- 若
nums[a] + nums[left] + nums[right] = 0
,则得到一个解,将其加入答案数组中,并继续将 left 右移,right 左移; - 若
nums[a] + nums[left] + nums[right] > 0
,说明 nums[right] 值太大,将 right 向左移; - 若
nums[a] + nums[left] + nums[right] < 0
,说明 nums[left] 值太小,将 left 右移。
代码
0080. 删除有序数组中的重复项 II
- 标签:数组、双指针
- 难度:中等
题目大意
给定一个有序数组 nums
。
要求:在原数组空间基础上删除重复出现 2 次以上的元素,并返回删除后数组的新长度。
解题思路
因为数组是有序的,所以重复元素必定是连续的。可以使用双指针来解决。具体做法如下:
使用两个指针 slow
,fast
。slow
指针指向即将放置元素的位置,fast
指针指向当前待处理元素。
本题要求相同元素最多出现 2 次,并且 slow - 2
是上上次放置了元素的位置。则应该检查 nums[slow - 2]
和当前待处理元素 nums[fast]
是否相同。
- 如果
nums[slow - 2] == nums[fast]
时,此时必有nums[slow - 2] == nums[slow - 1] == nums[fast]
,则当前nums[fast]
不保留,直接向右移动快指针fast
。 - 如果
nums[slow - 2] != nums[fast]
时,则保留nums[fast]
。将nums[fast]
赋值给nums[slow]
,同时将slow
右移。然后再向右移动快指针fast
。
这样 slow
指针左边均为处理好的数组元素,而从 slow
指针指向的位置开始, fast
指针左边都为舍弃的重复元素。
遍历结束之后,此时 slow
就是新数组的长度。
代码
第 12 天题目
0283. 移动零
- 标签:数组、双指针
- 难度:简单
题目大意
给你一个数组,将所有 0 移动到末尾,并保持原有的非 0 数字的相对顺序。要求只能在原数组上进行操作。
解题思路
使用两个指针 left,right。left 指向处理好的非 0 数字数组的尾部,right 指针指向当前待处理元素。
不断向右移动 right 指针,每次移动到非零数,则将左右指针对应的数交换,交换同时将 left 右移。
此时,left 指针左边均为处理好的非零数,而从 left 指针指向的位置开始, right 指针左边都为 0。
遍历结束之后,则所有 0 都移动到了右侧,且保持了非零数的相对位置。
代码
0075. 颜色分类
- 标签:数组、排序、双指针
- 难度:中等
题目大意
给定一个数组 nums,元素值只有 0、1、2,分别代表红色、白色、蓝色。将数组进行排序,使得 红色在前,白色在中间,蓝色在最后。
要求不使用标准库函数,同时仅用常数空间,一趟扫描解决。
解题思路
使用两个指针 left,right,分别指向数组的头尾。left 表示当前处理好红色元素的尾部,right 表示当前处理好蓝色的头部。
再使用一个下标 index 遍历数组,如果遇到 nums[index] == 0,就交换 nums[index] 和 nums[left],同时将 left 右移。如果遇到 nums[index] == 2,就交换 nums[index] 和 nums[right],同时将 right 左移。
直到 index 移动到 right 位置之后,停止遍历。遍历结束之后,此时 left 左侧都是红色,right 右侧都是蓝色。
注意:移动的时候需要判断 index 和 left 的位置,因为 left 左侧是已经处理好的数组,所以需要判断 index 的位置是否小于 left,小于的话,需要更新 index 位置。
代码
0088. 合并两个有序数组
- 标签:数组、双指针
- 难度:简单
题目大意
给定两个有序数组 nums1
、nums2
。将 nums2
合并到 nums1
中,使 nums1
成为一个有序数组。
其中给定数组 nums1 空间大小为 m + n 个,其中前 m 个为 nums1 的元素。nums2
空间大小为 n。这样可以用 nums1
的空间来存储最终的有序数组。
解题思路
将两个指针 p1、p2 分别指向 nums1、nums2 元素的尾部,再用一个指针 p 指向数组 nums1 的尾部。从后向前判断当前指针下 nums1[p1] 和 nums[p2] 的值大小,将较大值存入 num1[p] 中,然后继续向前遍历。最后再将 nums 中剩余元素赋值到 num1 前面对应位置上。
代码
第 13 天题目
0674. 最长连续递增序列
- 标签:数组
- 难度:简单
题目大意
给定一个未经排序的数组 nums
。要求:找到最长且连续递增的子序列,并返回该序列的长度。
解题思路
因为要求了连续,所以只需要比较相邻的元素大小。我们使用变量 count
计算当前子序列的递增长度,使用 res
记录最长连续递增子序列长度。然后递推求解即可。
代码
1004. 最大连续1的个数 III
- 标签:双指针、滑动窗口
- 难度:中等
题目大意
给定一个由 0、1 组成的数组 nums,再给定一个整数 k。最多可以将 k 个值从 0 变到 1。返回仅包含 1 的最长连续子数组的长度。
解题思路
使用滑动窗口的方法来做。使用两个指针 left、right 指向数组开始位置。使用 max_count 来维护仅包含 1 的最长连续子数组的长度。
不断右移 right 指针,扩大滑动窗口范围,并统计窗口内 0 元素的个数,直到 0 元素的个数超过 k 时将 left 右移,缩小滑动窗口范围,并减小 0 元素的个数。并维护 max_count。
代码
0220. 存在重复元素 III
- 标签:排序、有序集合、哈希表
- 难度:中等
题目大意
给定一个整数数组 nums,以及两个整数 k、t。判断数组中是否存在两个不同下标的 i 和 j,其对应元素满足 abs(nums[i] - nums[j]) <= t
,同时满足 abs(i - j) <= k
。如果满足条件则返回 True,不满足条件返回 False。
解题思路
对于第 i 个元素 nums[i],需要查找的区间为 。可以利用桶排序的思想。
桶的大小设置为 t+1。我们将元素按照大小依次放入不同的桶中。
遍历数组 nums 中的元素,对于元素 nums[i] :
- 如果 nums[i] 放入桶之前桶里已经有元素了,那么这两个元素必然满足
abs(nums[i] - nums[j]) <= t
, - 如果之前桶里没有元素,那么就将 nums[i] 放入对应桶中。
- 然后再判断左右桶的左右两侧桶中是否有元素满足
abs(nums[i] - nums[j]) <= t
。 - 然后将 nums[i-k] 之前的桶清空,因为这些桶中的元素与 nums[i] 已经不满足
abs(i - j) <= k
了。
最后上述满足条件的情况就返回 True,最终遍历完仍不满足条件就返回 False。
代码