姑且算是二刷吧?之前跟着卡哥的视频刷了大概50题,后来因为准备期末考就放下了,趁暑假报了班鞭策一下自己,为了跟进度还从第一题刷起。
题目链接:https://leetcode.cn/problems/binary-search/
视频链接:【手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找】https://www.bilibili.com/video/BV1fA4y1o715?vd_source=82cd289daf33ddd26b7489e3bbe8cd72
二分查找是我本科学数据结构的时候就学过的,所以看视频的时候思路很好理解,主要注意的有两点:
最后两遍才AC,第一遍是因为编译错误,写成了python的语法。。。第二遍编译通过。我的代码如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right){
int mid = (left - right) / 2 + right; //防止溢出
if(nums[mid] < target){
left = mid + 1;
}else if (nums[mid] > target){//不是elif!!!
right = mid - 1;
}else{
return mid;
}
}
return -1;
}
};
这里注意使用int mid = (left - right) / 2 + right
防止两个大数相加溢出,这里的数比较小当然不会出现。
然后是题解:
// 版本一
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if (nums[middle] > target) {
right = middle - 1; // target 在左区间,所以[left, middle - 1]
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,所以[middle + 1, right]
} else { // nums[middle] == target
return middle; // 数组中找到目标值,直接返回下标
}
}
// 未找到目标值
return -1;
}
};
我写的是解法一,也符合我学数学时的思维。
题目链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
这是一个拓展题目,首先拿到就有思路,设置左右指针分别从两边向中间逼近, 其中每个指针的值等于目标值后停止移动,如果左指针跑到右指针后面还没找到, 说明没有返回-1。
但这道题提交了好几遍才AC,以上是我的AC代码:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res(2);
if(nums.size() == 0){
res[0] = -1;
res[1] = -1;
return res;
}else if(nums.size() == 1){
if(nums[0]!= target){
res[0] = -1;
res[1] = -1;
return res;
}else{
res[0] = 0;
res[1] = 0;
return res;
}
}
int left = 0, right = nums.size() - 1;
while((nums[left] != target || nums[right] != target) && left <= right){
if(nums[left] != target){
left++;
}
if(nums[right] != target) {
right--;
}
}
if(left > right){//没找到
left = -1;
right = -1;
}
res[0] = left;
res[1] = right;
return res;
}
};
出的问题:
int arr[] = {5,7,7,8,8,10};
vector<int> nums(arr,arr+6);
查看了题解过后,发现大家还是用二分解法比较多,首先先找到一个target,然后从target左右循环找边界, 最惊艳我的还是这个两次二分的算法,分别找左边界和右边界:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left=0, right=nums.size()-1, middle, ans_left=-1, ans_right=-1;
// 查找左边界
while(left<=right){
middle = left + (right - left) / 2;
if(nums[middle]==target){
ans_left = middle;
right = middle - 1;//因为是左边界,所以要看看左边是不是还有目标值存在
}
else if(nums[middle]<target)
left = middle + 1;
else
right = middle - 1;
}
// 查找右边界
left=0;
right=nums.size()-1;
while(left<=right){
middle = left + (right - left) / 2;
if(nums[middle]==target){
ans_right = middle;
left = middle + 1;//因为是右边界,所以要看看右边是不是还有目标值存在
}
else if(nums[middle]<target)
left = middle + 1;
else
right = middle - 1;
}
return {ans_left, ans_right};
}
};
这里学到了数值对的赋值方法,不要再傻傻的赋值了,使用{a,b}进行返回。
题目链接:https://leetcode.cn/problems/remove-element/
视频链接:【数组中移除元素并不容易! | LeetCode:27. 移除元素】https://www.bilibili.com/video/BV12A4y1Z7LP?vd_source=82cd289daf33ddd26b7489e3bbe8cd72
这题也是二刷过了一下就有思路了,设置快慢指针,快指针遍历数组,慢指针存放数据,最后修改数组的长度:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
if(nums.size() == 0){
return 0;
}
int fast = 0,slow = 0;
while(fast <= nums.size() - 1){
if(nums[fast] != val){
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
}
};
运行失败:
Line 1034: Char 9: runtime error: reference binding to null pointer of type 'int' (stl_vector.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1043:9
今天的内容还算简单,基本二刷看到就有思路了,最重要的是把CLion的环境搭好了,之后可以愉快的用IDE进行debug了。可以看出二刷还是有效果的,明天也要加油⛽️。