每日两道力扣,day3
每日两道力扣,day3

每日两道力扣,今日是:
第一题:点名

1.思路:
这个题其实有两个方法。一是暴力遍历,二是二分查找。
方法一:
1.遍历找第一个不匹配的位置 < == >if (records[i] != i)
return i;
2.全部匹配,缺席的就是最后一个学号 n < == > return n;
方法二:
利用二分查找的逼近特性,查找不匹配的位置
2.代码实现:
方法一(暴力):
class Solution {
public:
int takeAttendance(vector<int>& records) {
int n = records.size();
// 遍历找第一个不匹配的位置
for (int i = 0; i < n; ++i) {
if (records[i] != i) {
return i;
}
}
// 全部匹配,缺席的就是最后一个学号 n
return n;
}
};
方法二(二分查找):
class Solution {
public:
int takeAttendance(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while(left < right){
int mid = (left + right)/2;
if(nums[mid] != mid) right = mid;
else left = mid + 1;
}
if(nums[right] == right) right++;//特殊情况
return right;
}
};
3.细节
(1)对于方法一,我们必须考虑前面全部匹配时,最后一个缺席的人就是n这种情况,不然测试用例跑不满。
(2)对于方法二,同理我们必须考虑方法一中的情况,不然同样跑不满。
(3)一定要考虑周全。我最开始直接用二分查找,就因为漏了这个情况卡了好几分钟。然后把我逼急了,我又想出了暴力求解,后面在脑子里面写伪代码的时候,可算整出来了。然后就有了两种解法。
第二题:搜索旋转排序数组


1.思路:
还记得咱们昨天写的寻找旋转排序数组中的最小值吗?那道题用的二分查找,这道题是昨天那道题的一个子题,所以咱们果断采用二分查找。
草图如下:

核心思路:
首先咱们回味一下昨天那道题的思路。题目要求是求寻旋转排序数组中的最小值。
想象一下你在爬坡。将 mid 与右边界 right 进行比较
(1)如果nums[mid] > nums[right],mid 在左侧的高斜坡,最小值肯定在右边,left = mid + 1。让mid往右走一点
(2)反之nums[mid] < nums[right],mid 在右侧的低斜坡,最小值在 mid 或者是 mid 的左边,right = mid。让mid往左走一点。
(3)循环结束时,left 和 right 相遇,指向的就是最小值
同理咱们这个题的大致方向如上,但有一些细节得处理好。
(1)我们并不知道nums[mid]具体在左侧上坡,还是在右侧上坡。而且咱们也不知道target具体在左侧上坡,还是在右侧上坡。我们必须运用假设法。
(2)首先假设nums[mid]位于左侧上坡 <=> if(nums[left] <= nums[mid]),其次咱们继续假设target在左侧的半个上坡,即if(target >= nums[left] && target < nums[mid])
(3)反之,咱们继续假设在右上坡的情况。
2.代码实现:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right)
{
int mid = left + (right - left)/2;
// 运气好,第一次就找到了 (注意:返回下标 mid,千万别加 1)
if(nums[mid] == target)
return mid;
// 左边是完美升序的斜坡
if(nums[left] <= nums[mid])
{
// 假设 target 在这半个完美的左坡上
if(target >= nums[left] && target < nums[mid])
{
// 砍掉右边,在左边找
right = mid - 1;
}
else
{
// 不在左坡,那一定在右边。砍掉左边!
// (注意:这里千万别写 left = mid,会死循环)
left = mid + 1;
}
}
// 右边是完美升序的斜坡
else
{
// 假设 target 在这半个完美的右坡上
// (注意:在升序坡上,target 必须大于 nums[mid])
if(target > nums[mid] && target <= nums[right])
{
// 砍掉左边,在右边找
left = mid + 1;
}
else
{
// 不在右坡,那一定在左边。砍掉右边!
right = mid - 1;
}
}
}
// 循环都跑完了还没 return,说明真没有
return -1;
}
};
3.细节:

我们得采用 int mid = left + (right - left)/2; 来防止数据溢出
好了,今天的每日两道力扣到这里就算是结束了,看完是不是感觉有所收获呢?如果学有所获的话,麻烦给个三连支持一下呗。感谢观看,您的支持,将是我前进路上的重要动力。