704、二分查找
题目描述:在一个升序数组中找到目标值target,返回下标;目标值不存在则返回-1.
- 暴力解法:遍历数组,搜索目标值target
int search(vector<int>& nums,int target){ for (int i=0;i<nums.size();i++){ if(nums[i]==target){ return i;} } return -1; }
时间复杂度:O(n);空间复杂度:O(1)
- 二分查找
对区间的定义决定了不同的写法。
这里用双闭区间。[0,nums.size()-1]搜索区间包括0和数组的长度减一的索引
循环条件:左指针可以在不断右移之后达到初始right指向的位置(nums.size()-1),因此循环条件为(left<=right)。
mid计算:为了防止两个值计算结果导致大数越界,mid = (right-left)/2+left
nums[mid]<target:表明目标值(如果存在的话)应该在[mid+1,right]的范围内
nums[mid]>target:表明目标值应该在[mid+1,right]的范围内
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;//左指针、右指针
while (left <= right){
int mid = (right-left)/2+left;//找出中间索引
if (nums[mid] < target){
left = mid + 1;
}else if (nums[mid] > target){
right = mid -1;
}else{
return mid;
}
}
return -1;
}
时间复杂度:O(logn);空间复杂度:O(1)
27、移除元素
题目描述:移除一个数组nums中值为val的元素,返回移除元素之后数组的长度
注意:数组在内存中是连续的,因此这里对元素的移除本质上是对原数组的覆盖
1.暴力解法
int removeElement(vector<int>& nums,int val){
int size = nums.size();//数组的长度
//遍历数组
for(int i=0;i<size;i++){
//如果找到符合要求的值
if (nums[i] != val){
//把当前元素之后的所有元素往前移一位
for(int j=i;j<size-1;j++){
nums[j] = nums[j+1];
}
size--;//数组长度减一
i--;//所有数值往前移一位,i也要向前移一位,继续从前移序列的第一位开始继续判断
}
}
return size;
}
时间复杂度:O(n**2);空间复杂度:O(1)
对于i--解释的一个例子:
当i=0时,进入if语句,把所有之后的元素前移,这时完成了一次“移除”。
若没有i--,那么下一次循环时i=1,前移之后的第一个新元素(i=0的元素)就不会被遍历到。
2.双指针法(快慢指针法)
初始化两个指针。
快指针:用来在原数组中搜索符合条件的元素,慢指针:用来覆盖原数组,从0开始给新数组赋值。
最终,慢指针的值就是移除所有val之后的数组长度
时间复杂度:O(n);空间复杂度:O(1)
int removeElement(vector<int>& nums,int val){
int slowindex = 0;//慢指针,用来从0给原指针赋值,覆盖原指针
for (int fastindex = 0;fastindex<nums.size();fastindex++){
//fastindex从0在数组中搜索符合要求的值
//搜索到符合要求的值之后,就把值按顺序赋值到数组中,覆盖原数组
if (nums[fastindex]!=val){
nums[slowindex] = nums[fastindex];
slowindex++;
}
}
return slowindex;//移除所有val之后数组的长度
}