前言:
2022 年 3 月初到 2022 年 10 月中旬,我照着 github 用户halfrost编写的 LeetCode 刷题书的知识点顺序,初学了 LeetCode 涉及的基础数据结构和算法。从本周开始,我将按照 LeetCode 网站上的 tag,根据更为细化的知识点顺序,开始新一轮的刷题,预计每周不少于五道题。本系列文章并非完全按照每周完成的题目做的记录,而是阶段性的按照知识点分类组的总结,大致上每周一更,总结 1-2 个知识点,并简单记录该周的刷题进展。
本周做题记录
LC-4、LC-169、LC-240、LC-139、LC-140,涉及知识点二分查找、分治法、记忆化搜索等。
本周总结 1-二分查找
基础
首先回顾对数组vector\<int> nums
进行二分查找搜索元素int target
的写法
1 | bool BinarySearch(vector<int> nums, int target) |
35 搜索插入位置
原问题实际是要寻找数组中第一个大于target
的元素的位置。实现的方式是维护 int 变量ans
,初始值设为n
,每次满足条件nums[mid]>=target
都将对应的mid
值记录在ans
中。初始值设为n
的目的是,若ans
一次也未被更新,表明数组中的数值都小于target
,则元素应插入在数组最后位置。
关键代码如下所示:
1 | int searchInsert(vector<int>& nums, int target) |
34 数组中搜索元素的第一和最后一个位置
原问题场景为一个具有若干重复元素的数组,给定目标元素值target
,返回该元素在数组中出现的第一个位置和最后一个位置。
原问题可转化为如下两个子问题:
- 寻找小于
target
的最大值所在位置\(x\) - 寻找大于
target
的最小值所在位置\(y\)
原问题的答案即为\(x+1,y-1\)。上述两个子问题的解决思路与 33 题类似,题目核心代码段如下所示:
1 | vector<int> searchRange(vector<int>& nums, int target) |
33 搜索旋转排序数组
原问题考察将有序数组绕数组中某元素旋转后,二分查找某目标元素的实现。思路是观察旋转后数组中的元素大小,合理设置左右指针的变化即可。实现代码如下:
1 | int search(vector<int>& nums, int target) |
240 搜索二位矩阵
对二维矩阵的每一行进行二分查找即可。
4 寻找两个正序数组中位数
该题为困难题,借用了二分查找的思路,具体如下:假设两数组分别为 A,B,两数组元素总和为\(k\)个,原问题转化为寻找两数组中第\(k/2\)大的数,观察\(A[k/2]\)和\(B[k/2]\)的大小,若\(A[k/2]<B[k/2]\),则\(A[k/2]\)之前的数也一定不是中位数,原问题就转化为求\(A[k/2..n]\)和\(B\)中第\(k/2\)大的数,直到\(k=1\),返回数组头即可。实现代码如下:
1 | double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) |
备注
- 对于长度为\(k\)的数组,可不讨论奇偶情况,中位数可统一标识为下标为\((k-1)/2\)和下标为\(k/2\)的元素的平均数。该做法可免去奇偶讨论。