LeeCode例题——二分查找
1.二分查找:(面对一个升序排列的数组)
class Soulution {
public:
int search(vector<int>& nums, int target) {//函数名(数组,变量)
int left = 0, right = nums.size() - 1;//声明变量left定义为数组的左边界,变量right定义为数组的右边界。
while(left <= right){
int mid = left + (right - left)/2;//取数组的中间位置,前面加上left是为了防止溢出
int num = muns[mid];//取数组的中间位置的元素
if (num == target){//当寻找的变量等于数组中间位置的元素时,返回为中间未知的下标
return mid;
}else if (target < num){//当寻找的变量小于mid时,将右边界定义为mid-1,下次while循环计算mid的位置时,mid代表左边界的中间,从数组的左边开始寻找
right = mid -1
}else {//当寻找的变量大于mid时,将左边界定义为mid+1,下次while循环计算mid的位置时,mid代表右边界的中间,从数组的右边开始寻找
left = mid +1
}
}
return -1;//查找无果则返回-1
};
为什么计算变量mid时要在前面加上left防止溢出:
假设数组从1到10,查找数字为7,第一次计算变量mid的值为5,左边界left为6,第二次计算mid的值为8,但如果不加上left,mid的值会变为2,原因是这里算法的查找方法是(右边界-左边界)/2,每一次计算mid后,左右边界都会比原来更靠近,换句话说,右边界-左边界的差值将随着每一次循环的进行而缩小。
显然,当从1到10查找数字7的情况下,如果我们不做什么改变,mid的值将会越来越小,根本查找不到7,那么又为什么要加left呢?
假设从1到10查找的数字为3,那么在查找的过程中,左边界是不移动的,右边界缩小,mid将会变得越来越小,而想要查找到数字3,正好就需要mid的值随循环而变小。同时,在查找数字为7的情况下,左边界缩小,右边界不动,mid的值加上left将变得越来越大。
当然聪明的人可能已经发现我说错了,在这个算法的每一次循环过程中并非只有左边界或者右边界移动的(实际去算就能知道),但从结果上来看,无非就是左边界向右边界移动或者右边界向左边界移动,移动到某一个位置,输出这个位置而已,上面的内容各位看官抽象的理解一下就行。
本算法耗时32ms,LeeCode上有更快的算法,最离谱的是有4ms的算法。
28ms:(可能是我才疏学浅,没看出这个和32ms的有什么区别)
class Solution {
public:
int search(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;
}
};
24ms:
下面是我对这个算法快于32ms算法的理解:
1.这个算法在第一个if和第二个if中先处理了基准情况,按照书上的说法,应该是这样理解的吧。
2.在第三个if中加入break提前终止。
class Solution {
public:
int search(vector<int>& nums, int target) {
int m, start = 0, end = nums.size()-1;//和第一个算法一样,先定义左边界和右边界
int flag = -1;
int tmp = 0;
while(start <= end){//当左边界小于右边界时
m = (start + end ) / 2;//m为数组的中间位置
tmp = nums[m];//tmp为数组中m位置上的数字
if(start == end){//当左边界等于右边界时,即数组中只有一个数字
if(target==nums[m]){//如果查找到变量target则返回m
return m;
}else{
return -1;//没有则返回-1
}
}
if (tmp == target){//当tmp==target时返回flag,且结束循环
flag = m;
break;
}else if (tmp > target){//接下来和32ms算法同理
end = m;
}
else {
start = m+1;
}
}
return flag;
}
};
20ms:
1.相比于32ms的算法,这个算法只声明了两个变量,第四个变量num用nums[mid]代替,其他的原谅我才疏学浅,看不出来。
class Solution {
public:
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)
{
return mid;
}
else if(nums[mid]>target)
{
right=mid-1;
}
else
{
left=mid+1;
}
}
return -1;
}
};
16ms:(好像和那个24ms的算法一样啊)
class Solution {
public:
int search(vector<int>& nums, int target) {
int m, start = 0, end = nums.size()-1;
int flag = -1;
int tmp = 0;
while(start <= end){
m = (start + end ) / 2;
tmp = nums[m];
if(start == end){
if(target==nums[m]){
return m;
}else{
return -1;
}
}
if (tmp == target){
flag = m;
break;
}else if (tmp > target){
end = m - 1;
}
else {
start = m + 1;
}
}
return flag;
}
};
12ms:
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();//初始化变量n为数组的长度
if(n == 0 ) return -1;//这里优先处理了基准情况,当数组长度为0时直接返回-1
int l = 0, r = n-1, mid ;//初始化变量为l,r为数组的左边界和右边界,声明变量mid为整型
while(l <= r){//和32ms算法一样
mid = (r+l)/2;
if(nums[mid] == target) return mid;
else if(nums[mid] < target) l = mid+1;
else if(nums[mid] > target) r = mid-1;
}
return -1;
}
};
8ms:
降维打击了。
int init = [] {
ios::sync_with_stdio(false);
cin.tie(nullptr);
ofstream out("user.out");
for (string s; getline(cin, s); out << '\n') {
string t;
getline(cin, t);
int tar = stoi(t);
for (int i = 0, _i = 1, _n = s.length(); _i < _n; ++i, ++_i) {
bool _neg = false;
if (s[_i] == '-') ++_i, _neg = true;
int v = s[_i++] & 15;
while ((s[_i] & 15) < 10) v = v * 10 + (s[_i++] & 15);
if (_neg) v = -v;
if (v == tar) {
out << i;
goto next;
}
if (v > tar) break;
}
out << -1;
next:;
}
out.flush();
exit(0);
return 0;
}();
class Solution {
public:
int search(vector<int>, int) { return 0; }
};
4ms:
int init = [] {
ios::sync_with_stdio(false);
cin.tie(nullptr);
ofstream out("user.out");
for (string s; getline(cin, s); out << '\n') {
string t;
getline(cin, t);
int tar = stoi(t);
for (int i = 0, _i = 1, _n = s.length(); _i < _n; ++i, ++_i) {
bool _neg = false;
if (s[_i] == '-') ++_i, _neg = true;
int v = s[_i++] & 15;
while ((s[_i] & 15) < 10) v = v * 10 + (s[_i++] & 15);
if (_neg) v = -v;
if (v == tar) {
out << i;
goto next;
}
if (v > tar) break;
}
out << -1;
next:;
}
out.flush();
exit(0);
return 0;
}();
class Solution {
public:
int search(vector<int>, int) { return 0; }
};
真是应了书上那句话,程序长的运行效率不一定低。