1. 二分查找
题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
文章讲解:代码随想录
视频讲解:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili
很久之前开始看,看了一会(将近把数组看完)就颓废了,现在重新开始吧,先打复活赛!
思路: 二分查找法, 确定一个中间值 middle,通过比较值nums[middle]和target的大小来判断在左边二分查找还是在右边二分查找, 这里的边界需要注意, right到底是nums.size()还是nums.size() - 1, 不同的值会影响到while中的条件是 left < right 还是 left <= right.
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while(left <= right){
int middle = left + ((right - left) >> 1);
if (nums[middle] < target){
left = middle + 1;
}
else if (nums[middle] > target){
right = middle - 1;
}
else if (nums[middle] == target){
return middle;
}
}
return -1;
}
};
我的错误:
定义 right 的时候是 right = num.size(), 但是 while 语句中的内容并没有修改成 left < right. 可能出现如下的错误
除此之外, 还学到了一些东西:
1. 因为 left 和 right 都是整型元素, 我们计算middle = (left + right) / 2时, left + right 可能产生越界的情况, 如果使用 left + ((right - left) >> 1), 能够达到相同的效果而且不会产生越界的影响.
2. 位运算 >> 相当于左移1位, 除以2的1次方.
2. 移除元素:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
你不需要考虑数组中超出新长度后面的元素。
《代码随想录》算法视频公开课 (opens new window):数组中移除元素并不容易!LeetCode:27. 移除元素 (opens new window),相信结合视频再看本篇题解,更有助于大家对本题的理解。
思路: 定义一个慢指针和一个快指针, 慢指针负责模拟删除, 快指针负责把后面的元素往前移一位
// 第一次的错误代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for(int fast = 1; fast < nums.size(); fast++){
if( nums[fast] != val && nums[slow] == val) {
nums[slow] == nums[fast];
slow++;
}
if (nums[slow] != val) slow++;
}
return slow;
}
};
大致这样一个思路吧:slow指针和fast指针一前一后的遍历数组。
但是我发现会有一个这样的错误:
- 执行完第一个 if 判断语句后 slow++ 直接进入了下一个 if 判断语句了, 导致了 slow 反而变成了快指针, 原本的预想直接作废了。
于是我想着, 既然这个 slow++ 语句会影响 slow 指针,我就删掉 if(nums[slow] != val) slow++; 这个语句嘛。于是我自信的又去执行一遍,结果又出现了问题:
- 我在第一个判断语句里加入了这么一个条件: nums[slow] == val, 我想着如果慢指针指着目标值肯定就得等一下嘛, 但是显然, 这只是我的主观判断, 这会导致后面 slow 语句一直停留在 val 元素的下一个元素处一直停留.
所以, 删去 nums[slow] == val, 再通过上述的图进行Debug, 再去运行, 然后还是出现问题了...
- 如果fast指针从1开始, 会导致容器内的第1个元素, 也就是nums[0]被直接抹去了
所以最终正确的代码:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for(int fast = 0; fast < nums.size(); fast++){
if( nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
};
今天代码部分花费时间挺长的将近2个小时, 博客也将近写了2个小时, 不过开始就坚持下去吧.