今天想做一个50天寒假计划,用来激励和督促自己每天都要学点什么。
内容大概就是算法和数据结构,后面希望有时间也学习一下TCP/IP协议,里面的socket编程我一直很有兴趣。
题目来源
先抛开题目来说,二分法你一想到第一反应绝对就是简单,为什么呀?字如其名,二分法二分法,就是把一段数据一分为二,进行高效率的搜索查找。是的,没有任何问题,但是如果让你细说呢,涉及到边界条件很容易写错,。例如到底是?while(left < right)
?还是?while(left <= right)
,到底是right = middle
呢,还是要right = middle - 1
呢?? 原因就在于根本不理解区间的定义!
二分法区间的定义就是不变量? 有两种定义法 左闭右闭? 左闭右开
第一种写法,我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right]?
区间的定义这就决定了二分法的代码应该如何写,因为定义target在[left, right]区间,所以有如下两点:
?
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;//边界
while (left <= right) {
int middle=(left+right)/2;//来个中点
if(nums[middle]>target){
right=middle-1;//右界大于 所以不能等于 得减去一
}else if(nums[middle]<target){
left=middle+1;
}else{
return middle;
}
}
return -1;//题目要求
}
};
如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同。
有如下两点:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
int middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle; // target 在左区间,在[left, middle)中
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,在[middle + 1, right)中
} else { // nums[middle] == target
return middle; // 数组中找到目标值,直接返回下标
}
}
// 未找到目标值
return -1;
}
};
记住无效的空间 举个例子? 第一种写法[1,1]合法,表示集合有一个元素。而第二种[1,1)不合法,什么都表示不了。所以才有了一二写法的区别
while(left<right)
{
}
和
right=middle;