vlambda博客
学习文章列表

【算法图解-01_二分查找】


二分查找

【算法图解-01_二分查找】

假设要在电话簿中找一个名字以K打头的人,(现在谁还用电话簿!) 可以从头开始翻页,直到进入以K打头的部分。但你很可能不这样做,而是从中间开始,因为你知道以K打头的名字在电话簿中间。又假设要在字典中找一个以O打头的单词,你也将从中间附近开始。现在假设你登录Facebook。当你这样做时,Facebook必须核实你是否有其网站的账户,因此必须在其数据库中查找你的用户名。如果你的 用户名为karlmageddon,Facebook可从以A打头的部分开始查找,但更合乎逻辑的做法是从中间开始查找。这是一个查找问题,在前述所有情况下,都可使用同一种算法来解决问题,这种算法就是 二分查找

【算法图解-01_二分查找】

下面的示例说明了二分查找的工作原理。我随便想一个1~100的数字。你的目标是以最少的次数猜到这个数字。你每次猜测后,我会说小了、大了或对了。假设你从1开始依次往上猜,猜测过程会是这样。

【算法图解-01_二分查找】

这是简单查找,更准确的说法是傻找。每次猜测都只能排除一个数字。如果我想的数字是99, 你得猜99次才能猜到!

【算法图解-01_二分查找】

下面是一种更佳的猜法。从 50 开始。

【算法图解-01_二分查找】

小了,但排除了一半的数字!至此,你知道1~50都小了。接下来,你猜75。

【算法图解-01_二分查找】

大了,那余下的数字又排除了一半!使用二分查找时,你猜测的是中间的数字,从而每次都 将余下的数字排除一半。接下来,你猜63(50和75中间的数字)

【算法图解-01_二分查找】

这就是二分查找,你学习了第一种算法!每次猜测排除的数字个数如下。

【算法图解-01_二分查找】

不管我心里想的是哪个数字,你在7次之内都能猜到,因为每次 猜测都将排除很多数字!假设你要在字典中查找一个单词,而该字典包含240 000个单词, 你认为每种查找最多需要多少步?如果要查找的单词位于字典末尾,使用简单查找将需要240 000步。使用二分查找时,每次 排除一半单词,直到最后只剩下一个单词

【算法图解-01_二分查找】

因此,使用二分查找只需18步——少多了!一般而言,对于包含n个元素的列表,用二分查 找最多需要log2n步(对数是幂运算的逆运算),而简单查找最多需要n步。

仅当列表是有序的时候,二分查找才管用





二分查找C++实现

定义 target 是在一个在左闭右闭的区间里,也就是[left, right] (这个很重要非常重要)
区间的定义这就决定了二分法的代码应该如何写,因为定义target在[left, right]区间,所以有如下两点:
while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
class Solution {public: int search(vector<int>& nums, int target) { int left = 0; int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right] while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <= int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2 if (nums[middle] > target) { right = middle - 1; // target 在左区间,所以[left, middle - 1] } else if (nums[middle] < target) { left = middle + 1; // target 在右区间,所以[middle + 1, right] } else { // nums[middle] == target return middle; // 数组中找到目标值,直接返回下标 } } // 未找到目标值 return -1; }};

leetcode 35. 搜索插入位置  https://leetcode-cn.com/problems/search-insert-position/

class Solution {public: int searchInsert(vector<int>& nums, int target) { int left = 0; int right = nums.size()-1; while(left <= right) { int middle = (left + right) / 2; // int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2 if (target < nums[middle]) { right = middle - 1; } else if (target > nums[middle]) { left = middle + 1; } else { return middle;  } } // 分别处理如下四种情况 // 目标值在数组所有元素之前 [0, -1] // 目标值等于数组中某一个元素 return middle; // 目标值插入数组中的位置 [left, right],return right + 1 // 目标值在数组所有元素之后的情况 [left, right],  return right + 1; }};


leetcode 704.二分查找 https://leetcode-cn.com/problems/binary-search/submissions/

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(target < nums[middle]) { right = middle - 1; } else if(target > nums[middle]) { left = middle + 1; } else { return middle; } } return -1; }};


【算法图解-01_二分查找】

二分查找Python实现

【算法图解-01_二分查找】





点个不要钱的“在看”就好啦!
努力活成自己喜欢的样子~
你期待的都会来到你身边
走过路过不要错过
想攒点奶