【LeetCode】二分 binary_search(共58题)

【4】Median of Two Sorted Arrays html

 

【29】Divide Two Integers 面试

 

【33】Search in Rotated Sorted Array 算法

 

【34】Find First and Last Position of Element in Sorted Array api

 

【35】Search Insert Position 数组

 

【50】Pow(x, n) app

 

【69】Sqrt(x) less

 

【74】Search a 2D Matrix (2019年1月25日,谷歌tag复习)剑指offer原题dom

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:ide

  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.

Example 1:google

Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
Output: true 

Example 2:

Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
Output: false

题解:用 target 和当前右上角元素作比较,若是相等返回 true,若是不想等,若是右上角元素大于target,那么删除这一列,若是右上角元素小于target,那么删除这一行。

 1 class Solution {
 2 public:
 3     bool searchMatrix(vector<vector<int>>& matrix, int target) {
 4         if (matrix.empty() || matrix[0].empty()) {
 5             return false;
 6         }
 7         const int n = matrix.size(), m = matrix[0].size();
 8         int up = 0, right = m-1;
 9         while (up < n && right >= 0) {
10             if (matrix[up][right] == target) {
11                 return true;
12             }
13             if (matrix[up][right] < target) {
14                 up++;
15             } else if (matrix[up][right] > target) {
16                 --right;
17             }
18         }
19         return false;
20     }
21 };
View Code

  

【81】Search in Rotated Sorted Array II 

 

【153】Find Minimum in Rotated Sorted Array 

 

【154】Find Minimum in Rotated Sorted Array II 

 

【162】Find Peak Element (2018年11月27日)(本题须要复习,一开始不会作的。我以为二分也容易写错的。)

这题要求咱们在一个无序的数组里找到一个peak元素,所谓peak,就是值比两边邻居大就能够了。

题解:对于这道题目,最简单的解法就是遍历数组,只要找到第一个符合要求的元素就能够了,时间复杂度为O(n),可是这题要求O(LogN)的时间复杂度,还能够用二分来作。https://blog.csdn.net/NK_test/article/details/49926229

首先咱们找到中间节点mid,若是大于两边返回当前的index就能够了,若是左边的节点比mid大,那么咱们能够继续在左半区间查找,这里面必定存在一个peak,为何这么说呢?假设此时的区间范围为[0,mid-1],由于num[mid-1]必定大于num[mid],若是num[mid-2]<=num[mid-1],那么num[mid-1]就是一个peak。若是num[mid-2]>num[mid-1],那么咱们就继续在[0,mid-2]区间查找,由于num[-1]为负无穷,因此咱们最终绝对能在左半区间找到一个peak。同理右半区间同样。

 1 class Solution {
 2 public:
 3     int findPeakElement(vector<int>& nums) {
 4         const int n = nums.size();
 5         int left = 0, right = n - 1;
 6         while (left < right) {
 7             int mid = (left + right) / 2;
 8             int target = nums[mid+1];
 9             if (nums[mid] < target) {
10                 left = mid + 1;
11             } else {
12                 right = mid;
13             }
14         }
15         return left;
16     }
17 };
View Code

2019年4月15日更新。咱们能够根据mid和旁边元素的大小来移动指针。咱们的目标实际上是把搜索方向放到元素增大的一侧。

若是咱们把二分写成以下的形式,那么能够发现,当 left = right 的时候退出循环,mid 永远取不到 right,那么 mid + 1 也就永远合法。

 1 class Solution {
 2 public:
 3     int findPeakElement(vector<int>& nums) {
 4         const int n = nums.size();
 5         int left = 0, right = n-1;
 6         while (left < right) {
 7             int mid = (left + right) / 2;
 8             if (nums[mid] < nums[mid+1]) {
 9                 left = mid + 1;
10             } else {
11                 right = mid;
12             }
13         }
14         return left;
15     }
16 };

 

【167】Two Sum II - Input array is sorted 

 

【174】Dungeon Game 

【209】Minimum Size Subarray Sum 

【222】Count Complete Tree Nodes 

【230】Kth Smallest Element in a BST 

 

【240】Search a 2D Matrix II (2019年1月26日,谷歌tag复习)

write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

  • Integers in each row are sorted in ascending from left to right.
  • Integers in each column are sorted in ascending from top to bottom.

题解:不少种方法能够作,我仍是每次看右上角元素。

 1 class Solution {
 2 public:
 3     bool searchMatrix(vector<vector<int>>& matrix, int target) {
 4         if (matrix.empty() || matrix[0].empty()) {
 5             return false;
 6         }
 7         const int n = matrix.size(), m = matrix[0].size();
 8         int up = 0, right = m-1;
 9         while (up < n && right >= 0) {
10             if (matrix[up][right] == target) {
11                 return true;
12             }
13             while (up < n && matrix[up][right] < target) {
14                 ++up;
15             }
16             if (up == n) { break; }
17             while (right >= 0 && matrix[up][right] > target) {
18                 --right;
19             }
20         }
21         return false;
22     }
23 };
View Code

 

【270】Closest Binary Search Tree Value ()

【275】H-Index II 

 

【278】First Bad Version (2018年12月22日,地里面经)

给了一个数字 n, 表明数组 [1..n],给了一个 api, bool isBadVersion(int version); 能判断一个数字是否是 bad version。在调用这个给定的api最小次数的前提下,返回这个数组中第一个bad version。

题解:二分,lower_bound 本身实现

 1 // Forward declaration of isBadVersion API.
 2 bool isBadVersion(int version);
 3 
 4 class Solution {
 5 public:
 6     int firstBadVersion(int n) {
 7         long long left = 0, right = (long long)n + 1;
 8         long long mid;
 9         while (left < right) {
10             mid = left +  (right - left) / 2;
11             if (!isBadVersion(mid)) {
12                 left = mid + 1;
13             } else {
14                 right = mid;
15             }
16         }
17         return left;
18     }    
19 };
View Code

 

【287】Find the Duplicate Number (2019年1月26日,二分查找)

给了一个nums数组,里面包含 1 — n-1 的数字,有一个数字可能重复了2次到屡次。找出来这个数。

题解:解法1. sort + 2 pointers

 1 class Solution {
 2 public:
 3     int findDuplicate(vector<int>& nums) {
 4         sort(nums.begin(), nums.end());
 5         for (int i = 0; i < nums.size() - 1; ++i) {
 6             if (nums[i] == nums[i+1]) {
 7                 return nums[i];
 8             }
 9         }
10         return -1;
11     }
12 };
View Code

解法2. 二分==总写错啊

 

【300】Longest Increasing Subsequence 

【302】Smallest Rectangle Enclosing Black Pixels (2019年1月26日,谷歌tag题)

给了一个矩阵,0表明白色像素,1表明黑色像素,黑色全部的像素是四联通的,问把黑色全部像素的包围起来的最小矩形面积。

题解:这题是个二分 tag,可是我只会用dfs解法。dfs解法时间复杂度是O(mn)的。咱们须要找四个值,1像素的最左,最右,最上和最下。而后用矩阵的长和宽相乘一下就能够了。

 1 class Solution {
 2 public:
 3     int minArea(vector<vector<char>>& image, int x, int y) {
 4         if (image.size() == 0 || image[0].size() == 0) {
 5             return 0;
 6         }
 7         n = image.size(), m = image[0].size();
 8         vector<vector<int>> visit(n, vector<int>(m, 0));
 9         left = right = y;
10         top = buttom = x;
11         dfs(image, x, y, visit);
12         int area = (right - left + 1) * (buttom - top + 1);
13         return area;
14     }
15     int n, m;
16     int left = -1, right = -1, top = -1, buttom = -1;
17     void dfs(const vector<vector<char>>& image, int x, int y, vector<vector<int>>& visit) {
18         visit[x][y] = 1;
19         left = min(left, y), right = max(right, y);
20         top = min(top, x), buttom = max(buttom, x);
21         for (int k = 0; k < 4; ++k) {
22             int newx = x + dirx[k], newy = y + diry[k];
23             if (newx >= 0 && newx < n && newy >= 0 && newy < m && image[newx][newy] == '1' && !visit[newx][newy]) {
24                 dfs(image, newx, newy, visit);
25             }
26         }
27         return;
28     }
29     int dirx[4] = {-1, 0, 1, 0};
30     int diry[4] = {0, -1, 0, 1};
31 };
View Code

 

【349】Intersection of Two Arrays (2018年11月6日,算法群相关题)

hash-table 里面有这题,hash-table:http://www.javashuo.com/article/p-mjknibky-mq.html

也能够二分解答,二分没有想过,我估计就是先排序,而后二分吧

 

【350】Intersection of Two Arrays II (2018年11月6日,算法群)

hash-table 里面有这题,hash-table:http://www.javashuo.com/article/p-mjknibky-mq.html

也能够二分解答,二分没有想过,我估计就是先排序,而后二分吧

 

【354】Russian Doll Envelopes 

【363】Max Sum of Rectangle No Larger Than K 

【367】Valid Perfect Square 

 

【374】Guess Number Higher or Lower (2019年1月25日,谷歌tag复习)

在 [1, n] 这个区间里面猜数,给了一个 guess 的api,返回一开始 pick 的数字。

You call a pre-defined API guess(int num) which returns 3 possible results (-11, or 0):

-1 : My number is lower
 1 : My number is higher
 0 : Congrats! You got it!

题解:二分,这题我写成了左闭右闭的形式。

 1 // Forward declaration of guess API.
 2 // @param num, your guess
 3 // @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
 4 int guess(int num);
 5 
 6 class Solution {
 7 public:
 8     int guessNumber(int n) {
 9         int left = 1, right = n;
10         long long mid;
11         while (left <= right) {
12             mid = (long long)left + (right - left) / 2;
13             int res = guess(mid);
14             if (res == 0) {
15                 return mid;
16             } else if (res < 0) { //leftside
17                 right = mid - 1;
18             } else {
19                 left = mid + 1;
20             }
21         }
22         return -1;
23     }
24 };
View Code

 

【378】Kth Smallest Element in a Sorted Matrix (2019年2月9日)

给了一个 n * n 的矩阵,返回矩阵中第 k 小的元素。

题解:二分答案。咱们要找到一个最小的元素x,知足矩阵中的元素小于等于x的值的有k个。(lower_bound)

 1 class Solution {
 2 public:
 3     int kthSmallest(vector<vector<int>>& matrix, int k) {
 4         const int n = matrix.size();
 5         int left = matrix[0][0], right = matrix[n-1][n-1] + 1;
 6         while (left < right) {
 7             int mid = left + ((right - left) / 2);
 8             int tot = 0;
 9             for (auto& row : matrix) {
10                 auto iter = upper_bound(row.begin(), row.end(), mid);
11                 tot += distance(row.begin(), iter);
12             }
13             // printf("left = %d, right = %d, mid = %d, tot = %d\n", left, right, mid, tot);
14             if (tot < k) {
15                 left = mid + 1;
16             } else {
17                 right = mid;
18             }
19         }
20         return left;
21     }
22 };
View Code

 

【392】Is Subsequence 

 

【410】Split Array Largest Sum (2019年3月2日,谷歌tag)

给了一个连续的数组,每一个元素表明任务完成的时间,而后给了一个天数m,要求这些任务必须在m天以内完成(能够提早)可是这些任务必须按顺序作,求最小化这这些天花在任务上时间的最大值。

举个例子:

nums = [7,2,5,10,8]
m = 2
Output:
18

Explanation:
There are four ways to split nums into two subarrays.
The best way is to split it into [7,2,5] and [10,8],
where the largest sum among the two subarrays is only 18.

 

题解:咱们其实能够枚举这个时间,咱们假设一天最多作 k 个小时,看 m 天以内能不能完成。若是不能的话,咱们尝试扩大k,若是能够的话,咱们尝试缩小k。因此二分查找的思路就出来了。left 边界是数组的最大值,right边界是整个数组的和。

总体时间复杂度是 O(nlogn)

 

 1 class Solution {
 2 public:
 3     int splitArray(vector<int>& nums, int m) {
 4         const int n = nums.size();
 5         long long left = -1, right = 0;
 6         for (auto& num : nums) {
 7             right += num;
 8             if (num > left) {
 9                 left = num;
10             }
11         }
12         int res(-1);
13         while (left <= right) {
14             long long mid = left + (right - left) / 2;
15             if (check(nums, mid, m)) {
16                 res = mid;
17                 right = mid - 1;
18             } else {
19                 left = mid + 1;
20             }
21         }
22         return res;
23     }
24     bool check(vector<int>& nums, long long mid, int m) {
25         int cnt = 0; long long sum = 0LL;
26         for (auto num : nums) {
27             if (sum + num <= mid) {
28                 sum += num;
29             } else {
30                 cnt++;
31                 sum = num;
32                 if (cnt == m || sum > mid) {return false;}
33             }
34         }
35         return true;
36     }
37 };
View Code

 

 

【436】Find Right Interval 

 

【441】Arranging Coins (2018年11月26日)

给了 n 枚硬币, 咱们排列这些硬币,第一行放1个,第二行放2个,.. ,第 k 行放 k 个。问这 n 个硬币最多能彻底放满多少行。

题解:我一个解法是用 等差数列的公式求解的, k * (k + 1) <= 2 * n。 枚举 k, 找到最大知足条件的 k,而后 返回 k . 这个解法只能 beats 20%+。

后来我看是二分的tag,我就写了一个 二分,而后就beats 90+了。

 1 class Solution {
 2 public:
 3     int arrangeCoins(int n) {
 4         int k = my_upper_bound(1, (long long)n + 1, (long long)n * 2);
 5         return k - 1;
 6     }
 7     int my_upper_bound(int begin, long long end, long long target) {
 8         long long mid = 0;
 9         while (begin < end) {
10             mid = ((long long)begin + end) / 2;
11             long long temp = mid * (mid + 1);
12             if (temp > target) {
13                 end = mid;
14             } else {
15                 begin = mid + 1;
16             }
17         }
18         return begin;
19     }
20 };
View Code

 

【454】4Sum II

 

【475】Heaters (2019年2月26日)

给了一个房子数组和一个暖气数组,求暖气的最小半径,要求全部的房子必须被暖气覆盖。

题解:对于每个房子求离它最近的暖气,用 lower_bound 求,而后用这个半径和 global_max 作比较。时间复杂度是 O(nlogn)

 1 class Solution {
 2 public:
 3     int findRadius(vector<int>& houses, vector<int>& heaters) {
 4         sort(heaters.begin(), heaters.end());
 5         int res = 0;
 6         for (auto& pos : houses) {
 7             auto iter = lower_bound(heaters.begin(), heaters.end(), pos);
 8             int radius = 0;
 9             if (iter == heaters.begin()) {
10                 radius = *iter - pos;
11             } else if (iter == heaters.end()) {
12                 --iter;
13                 radius = pos - *iter;
14             } else {
15                 radius = min(*iter - pos, pos - *(iter-1));
16             }
17             res = max(res, radius);
18         }
19         return res;        
20     }
21 };
View Code

 

【483】Smallest Good Base 

 

【497】Random Point in Non-overlapping Rectangles 

 

【528】Random Pick with Weight 

 

【644】Maximum Average Subarray II 

 

【658】Find K Closest Elements 

 

【668】Kth Smallest Number in Multiplication Table 

 

【702】Search in a Sorted Array of Unknown Size (2019年1月26日,二分查找复习,谷歌tag,lower_bound思想, M)

给了一个不知道长度的array,问target是否存在在array中。ArrayReader.get(k) 能获取 index = k的值。数据范围: 

You may assume all integers in the array are less than 10000, and if you access the array out of bounds, ArrayReader.get will return 2147483647.

  1. You may assume that all elements in the array are unique.
  2. The value of each element in the array will be in the range [-9999, 9999].

题解:我推算出数组最长为 20000,因此left = 0, right = 20000,直接用lower_bound, 若是说 reader.get(mid) 这个数字是 INT_MAX 的话,right = mid,丢弃全部右边的。若是说 reader.get(mid) < target 的话,那么说明,mid 这个依旧不知足条件,咱们须要把整个左边和mid一块儿丢掉 left = mid + 1。剩下的话,就是 right = mid

 1 // Forward declaration of ArrayReader class.
 2 class ArrayReader;
 3 
 4 class Solution {
 5 public:
 6     int search(const ArrayReader& reader, int target) {
 7         long long left = 0, right = 20000, mid = 0;
 8         while (left < right) {
 9             mid = (left + right) / 2;
10             int temp = reader.get(mid);
11             if (temp == INT_MAX) {
12                 right = mid;
13             } else if (temp < target) {
14                 left = mid + 1;
15             } else {
16                 right = mid;
17             }
18         }
19         if (reader.get(left) == target) {
20             return left;
21         }
22         return -1;
23     }
24 };
View Code

 

【704】Binary Search 

 

【710】Random Pick with Blacklist 

 

【718】Maximum Length of Repeated Subarray 

 

【719】Find K-th Smallest Pair Distance 

 

【744】Find Smallest Letter Greater Than Target 

 

【774】Minimize Max Distance to Gas Station 

 

【778】Swim in Rising Water 

 

【786】K-th Smallest Prime Fraction 

 

【793】Preimage Size of Factorial Zeroes Function 

 

【852】Peak Index in a Mountain Array (2019年2月27日,google tag)

给了一个三角顺序的数组,(前半段递增,后半段递减),返回值最大的元素下标。

Example 1:
Input: [0,1,0]
Output: 1
Example 2:
Input: [0,2,1,0]
Output: 1 

题解:二分,若是遍历一遍就行的话,这就不该该是一个面试题。时间复杂度是 O(logN)

若是 nums[mid] < nums[mid+1], 说明mid还在递增的区间,咱们这个时候应该++left。

否则若是  nums[mid-1] < nums[mid] > nums[mid+1],说明mid已是咱们寻找的目标值。

再或者 nums[mid-1] > nums[mid], 说明如今已经在递减的区间。咱们应该 right = mid

 1 class Solution {
 2 public:
 3     int peakIndexInMountainArray(vector<int>& A) {
 4         const int n = A.size();
 5         int left = 0, right = n;
 6         while (left < right) {
 7             int mid = (left + right) / 2;            
 8             if (mid + 1 < right && A[mid] < A[mid+1]) {
 9                 left = mid + 1;
10             } else if (mid - 1 >= left && A[mid-1] < A[mid]) {
11                 return mid;
12             } else {
13                 right = mid;
14             }
15         }
16         return left;
17     }
18 };
View Code

 

【862】Shortest Subarray with Sum at Least K 

【875】Koko Eating Bananas 

【878】Nth Magical Number 

【887】Super Egg Drop

相关文章
相关标签/搜索