LeetCode二分 binary_search(共58题)

Posted zhangwanying

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode二分 binary_search(共58题)相关的知识,希望对你有一定的参考价值。

【4】Median of Two Sorted Arrays 

 

【29】Divide Two Integers 

 

【33】Search in Rotated Sorted Array 

 

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

 

【35】Search Insert Position 

 

【50】Pow(x, n) 

 

【69】Sqrt(x) 

 

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

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 from left to right.
  • The first integer of each row is greater than the last integer of the previous row.

Example 1:

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:https://www.cnblogs.com/zhangwanying/p/9886262.html

也可以二分解答,二分没有想过,我估计就是先排序,然后二分吧

 

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

hash-table 里面有这题,hash-table:https://www.cnblogs.com/zhangwanying/p/9886262.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) / 2LeetCode二分 binary_search(共58题)

关于二分查找binary_search的结构体struct运用

C++之binary_search二分查找算法

stl中的二分查找

二分函数总结

C++二分查找常用函数