**
1.二分查找
**
前提:有序数组
思路:不断缩小区间直到找到所需的元素
KEY:坚持循环不变量的原则,我是通过左闭右开的方式实现的二分查找,因此在查找的过程中就需要一直坚持这样的定义方式,既然是左闭右开,那么也就意味着左边和右边的边界是不可以相等的,否则这就是一个不合法的区间,例如[1,1),因而在设置循环条件的时候,left必须小于right才可以;同理,当后面进行元素的比较时并更新边界的时候,也要遵循该原则才可以
总结:
一定要根据区间的定义方式来决定边界的处理;
凡是有序数组都可以考虑二分查找,它的时间复杂度只有O(logn)。
代码:
class Solution {
public:
int search(vector<int>& nums, int target) {
int numsize=nums.size();
int left=0;
int right=numsize;//左闭右开写法
while(left<right)
{
int middle=(left+right)/2;
if(nums[middle]>target)
{
right=middle;
}
else if(nums[middle]<target)
{
left=middle+1;
}
else
{
return middle;
}
}
return -1;
}
};
2.移除数组元素
思路:数组的删除本质是覆盖,因此覆盖的操作是不能省的,这也决定了该操作的时间复杂度不可能低于0(n)
本题可以通过暴力方式解,就是写两层for循环,第一层查找删除的元素,第二层实现覆盖,但是这样的时间复杂度平均会达到O(n^2)的水平
通过双指针的方式可以实现O(n)的时间复杂度,fast用来指向新数组的元素(也就是不等于待删元素的元素),slow用来指向新数组的下标
KEY:fast不等于待删除元素的时候,就把该元素赋值给新数组的下标所指向的位置,并让slow++,这样当fast遍历完数组时,新数组也就构建完成了,slow的值就是新数组的大小,因为数组的下标是从0开始的。
总结:双指针是用fast通过遍历的方式来完成查找,将不用删的元素配合slow直接完成覆盖,因此时间复杂度只有O(n)。
代码:
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;
}
};