【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

相關文章
相關標籤/搜索