LeetCode704二分查找
初印象
1.题目条件:升序数组,所有元素不重复,存在返回下标否则返回-1。
2.二分查找法,边界条件很多,考虑使用while循环主要有两种写法,首要区别在于left等于right时是否结束循环。
首先根据循环不变量原则确定区间开闭情况,区间就是不变量!上述条件、赋值在选择左闭右闭或者左闭右开时有所不同。
3.什么是循环不变量原则?链接: 循环不变量原则
4.左闭右闭写法中,下列代码为何能防止溢出?为何能溢出
// 二分法,区间为左闭右闭时middle赋值
int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
两个很大的int数相加可能会导致溢出
(
x
+
y
)
/
2
=
x
+
(
y
−
x
)
/
2
(x+y)/2=x+(y-x)/2
(x+y)/2=x+(y−x)/2
看视频讲解后的想法
1.int类型相加可能越界
2.二分查找法,right的初始赋值会根据区间情况不同发生变化,
左闭右开时,right=nums.size();
左闭右闭,right=nums.size()-1;
3.左闭右开时,right更新为middle,left更新为middle+1。
4.左闭右闭时,right更新为middle-1,left更新为middle+1。
实现过程中遇到的问题
// 左闭右开二分法
class Solution {
public:
int search(vector<int>& nums, int target) {
int left,right,middle;
left=0;//左闭右开式
right=nums.size();//加括号
while(left<right){//进入循环,左闭右开,左右不相等
middle=left+(right-left)/2;
if(target>nums[middle]){//左边界右移,用中括号包裹
left=middle+1;
}else if(target<nums[middle]){//右边界左移
right=middle;
}else{
return middle;
}
}
//未找到目标值
return -1;
}
};
line7 right=nums.size()加括号
line10 nums[middle]中括号
line9 middle赋值放到循环开头
line12 else if和line14else格式
line19在search函数体内放未找到返回-1
总结
1.循环不变法,本题区间不变,确定区间开闭方式后赋值和条件才能确定。否则将是一片混乱。
2.c++数组的一些语法需要注意
LeetCode27移除元素
初印象
给你一个数组 nums 和一个值 val,你需要原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
1.c++指针语法
2.原地移动数组
看讲解后的想法
1.数组元素只能覆盖
2.无需考虑删除后缩小的数组空间里存放了什么
3.暴力解法可以过,时间复杂度O(n²)
4.双指针法(快慢指针法)只需一个for循环,时间复杂度O(n)
实现过程中的问题
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow=0;
for(int quick=slow;quick<nums.size();quick++)
{
if(nums[quick]!=val){
nums[slow]=nums[quick];
slow++;//两个都动,若是目标数则slow不动,quick继续向前
}
}
return slow;
}
};
1.line7-9:用的是quick!=val,也就是说quick借助for循环移动,而slow借助循环体内的if条件移动,从而形成速度差异。
当碰见目标数时什么也不做,quick继续向后寻找非目标数。
4.line12,返回数组长度,即为right最后的位置
总结
暴力解法也要会,两个for循环。
双指针法巧妙地用了一个for循环,利用循环体内的if形成了速度差,最后的slow就是长度非常巧妙