题目:二分查找
- 给定一个
n
个元素有序的(升序)整型数组nums
和一个目标值target
,写一个函数搜索nums
中的target
,如果目标值存在返回下标,否则返回-1
。
题解
-
在升序数组 nums \textit{nums} nums 中寻找目标值 target \textit{target} target,对于特定下标 i,比较 nums [ i ] \textit{nums}[i] nums[i] 和 target \textit{target} target 的大小:
-
如果 nums[i]=target,则下标 i 即为要寻找的下标;
-
如果 nums[i]>target,则 target 只可能在下标 i 的左侧;
-
如果 nums[i]<target,则 target 只可能在下标 i 的右侧。
-
-
二分查找的做法是,定义查找的范围 [ left , right ] [\textit{left}, \textit{right}] [left,right],初始查找范围是整个数组。每次取查找范围的中点 mid,比较 nums [ mid ] \textit{nums}[\textit{mid}] nums[mid] 和 target 的大小,如果相等则 mid 即为要寻找的下标,如果不相等则根据 nums[mid] 和 target 的大小关系将查找范围缩小一半。由于每次查找都会将查找范围缩小一半,因此二分查找的时间复杂度是 O ( log n ) O(\log n) O(logn),其中 n 是数组的长度。
-
二分查找的条件是查找范围不为空,即 left ≤ right \textit{left} \le \textit{right} left≤right。如果 target 在数组中,二分查找可以保证找到 target,返回 target 在数组中的下标。如果 target 不在数组中,则当 left > right \textit{left} > \textit{right} left>right 时结束查找,返回 −1。
-
#include<iostream> #include<vector> using namespace std; int search_binary(vector<int>nums, int target) { int left=0,right=nums.size()-1; while(left<=right){ int mid = (right-left)/2+left; int num = nums[mid]; if(num==target) return mid; else if (num>target) right = mid-1; else left = mid+1; } return -1; } int main() { vector<int>v{ 8,11,19,23,27,33,45,55,67,98 }; cout << search_binary(v, 19); return 0; }
-
mid索引计算优化,可用位运算
-
int mid = left&right+(left^right)>>1;//效率略高
作者:力扣官方题解
链接:https://leetcode.cn/problems/binary-search/solutions/980494/er-fen-cha-zhao-by-leetcode-solution-f0xw/
-
题目:移除元素
- 给你一个数组
nums
和一个值val
,你需要 原地 移除所有数值等于val
的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用O(1)
额外空间并 原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
题解
-
由于题目要求删除数组中等于 val 的元素,因此输出数组的长度一定小于等于输入数组的长度,我们可以把输出的数组直接写在输入数组上。可以使用双指针:右(快)指针 right 指向当前将要处理的元素,左(慢)指针 left 指向下一个将要赋值的位置。
-
如果右指针指向的元素不等于 val,它一定是输出数组的一个元素,我们就将右指针指向的元素复制到左指针位置,然后将左右指针同时右移;
-
如果右指针指向的元素等于 val,它不能在输出数组里,此时左指针不动,右指针右移一位。
-
-
整个过程保持不变的性质是:区间 [0,left) 中的元素都不等于 val。当左右指针遍历完输入数组以后,left 的值就是输出数组的长度。这样的算法在最坏情况下(输入数组中没有元素等于 val,左右指针各遍历了数组一次。
-
时间复杂度:O(n),其中 n 为序列的长度。我们只需要遍历该序列至多两次。空间复杂度:O(1)。我们只需要常数的空间保存若干变量。
-
#include<iostream> #include<vector> using namespace std; int removeElement(vector<int>& nums, int val) { int fast =0,slow=0; for(fast;fast<nums.size();fast++){ if(nums[fast]!=val){ nums[slow] = nums[fast]; slow++; } } return slow; } int main() { vector<int>v{ 8,11,19,23,19,33,45,19,67,19 }; cout << removeElement(v, 19); return 0; }
-
暴力删除法
-
class Solution { public: int removeElement(vector<int>& nums, int val) { int n=nums.size(); for(int i=0;i<n;i++) { if(nums[i]==val) { for(int j=i+1;j<n;j++) { nums[j-1]=nums[j]; } i--; n--; } } return n; } };
-
-
迭代器删除法
-
class Solution { public: int removeElement(vector<int>& nums, int val) { for(vector<int>::iterator iter=nums.begin();iter!=nums.end();iter++) { //从vector中删除指定的某一个元素 if(*iter==val) { iter= nums.erase(iter); iter--; } } return nums.size(); } };
-
数组是存放在连续内存空间上的相同类型数据的集合。数组可以方便的通过下标索引的方式获取到下标下对应的数据。代码随想录 (programmercarl.com)
-
-
数组下标都是从0开始的;
-
数组内存空间的地址是连续的.
-
-
使用C++的话,要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。数组的元素是不能删的,只能覆盖。
-
二维数组在内存的空间地址是连续的么?
-
不同编程语言的内存管理是不一样的,以C++为例,在C++中二维数组是连续分布的。
-
#include <iostream> #include <vector> using namespace std; void test_arr() { int array[2][3] = { {0, 1, 2}, {3, 4, 5} }; cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl; cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << endl; } int main() { test_arr(); }
-
0x7ffd58fb62f0 与 0x7ffd58fb62f4 差了一个4,就是4个字节,因为这是一个int型的数组,所以两个相邻数组元素地址差4个字节。
-