总结leetcode75中的二分查找算法题解题思路。
上一篇:力扣75——堆/优先队列
力扣75——二分查找
- 1 猜数字大小
- 2 咒语和药水的成功对数
- 3 寻找峰值
- 4 爱吃香蕉的珂珂
- 1-4解题总结
1 猜数字大小
题目:
猜数字游戏的规则如下:每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):-1:我选出的数字比你猜的数字小 pick < num
1:我选出的数字比你猜的数字大 pick > num
0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num
返回我选出的数字。
题解:
二分查找。用left
、right
分别记录左端点和右端点。然后计算出它们的平均值mid
,接着用guess(mid)
判断是大了还是小了。
class Solution {
public:int guessNumber(int n) {long int left = 1, right=n;long int mid;while(left<=right){mid = (left+right)/2;if (guess(mid)<0){right = mid-1;}else if(guess(mid)>0){left = mid +1;}else{return mid;}}return left;}
};
2 咒语和药水的成功对数
题目:
给你两个正整数数组 spells 和 potions ,长度分别为 n 和 m ,其中 spells[i] 表示第 i 个咒语的能量强度,potions[j] 表示第 j 瓶药水的能量强度。同时给你一个整数 success 。一个咒语和药水的能量强度 相乘 如果 大于等于 success ,那么它们视为一对 成功 的组合。请你返回一个长度为 n 的整数数组 pairs,其中 pairs[i] 是能跟第 i 个咒语成功组合的 药水 数目。
题解:
先快速排序
,然后用upper_bound()
找到第一个成功的数,这样就可以计算出每个咒语对应的成功组合数目了。
class Solution {
public:vector<int> successfulPairs(vector<int> &spells, vector<int> &potions, long long success) {sort(potions.begin(), potions.end());for (auto &x : spells)x = potions.end() - upper_bound(potions.begin(), potions.end(), (success - 1) / x);return spells;}
};
3 寻找峰值
题目:
峰值元素是指其值严格大于左右相邻值的元素。给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值
所在位置即可。你可以假设 nums[-1] = nums[n] = -∞ 。你必须实现时间复杂度为 O(log n) 的算法来解决此问题。
题解:
二分查找。
用left
、right
分别记录左端点和右端点。然后计算出它们的中间值mid
。接着判断中间值,如果是峰值则return mid
,如果只大于右值,则在mid
的右边进行二分查找;如果小于右值,则在mid
的左边进行二分查找。
class Solution {
public:int findPeakElement(vector<int>& nums) {int n = nums.size();// 辅助函数,输入下标 i,返回一个二元组 (0/1, nums[i])// 方便处理 nums[-1] 以及 nums[n] 的边界情况auto get = [&](int i) -> pair<int, int> {if (i == -1 || i == n) {return {0, 0};}return {1, nums[i]};};int left = 0, right = n - 1, ans = -1;while (left <= right) {int mid = (left + right) / 2;if (get(mid - 1) < get(mid) && get(mid) > get(mid + 1)) {ans = mid;break;}if (get(mid) < get(mid + 1)) {left = mid + 1;}else {right = mid - 1;}}return ans;}
};
4 爱吃香蕉的珂珂
题目:
珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。
题解:
class Solution {
public:int minEatingSpeed(vector<int>& piles, int h) {int low = 1;int high = 0;for (int pile : piles) {high = max(high, pile);}int k = high;while (low < high) {int speed = (high - low) / 2 + low;long time = getTime(piles, speed);if (time <= h) {k = speed;high = speed;} else {low = speed + 1;}}return k;}long getTime(const vector<int>& piles, int speed) {long time = 0;for (int pile : piles) {int curTime = (pile + speed - 1) / speed;time += curTime;}return time;}
};
1-4解题总结
使用二分查找的场景:从一组有序特性的数据中查找某个值。
有序特性:不需要严格有序,像题目3,因为通过判断mid跟其左右的大小,就可以确定在其左边或右边一定有个峰值。