赞
踩
将最值问题转换为判定
二分查找:在一个已知的有序数据集上进行二分地查找
二分答案:答案有一个区间,在这个区间中二分,直到找到最优答案
1、答案在一个区间内(一般情况下,区间会很大,暴力超时)
2、直接搜索不好搜,但是容易判断一个答案可行不可行
3、该区间对题目具有单调性,即:在区间中的值越大或越小,题目中的某个量对应增加或减少。
此外,可能还会有一个典型的特征:求...最大值的最小 、 求...最小值的最大。
1、求...最大值的最小,我们二分答案(即二分最大值)的时候,判断条件满足后,尽量让答案往前来(即:让r=mid)
2、同样,求...最小值的最大时,我们二分答案(即二分最小值)的时候,判断条件满足后,尽量让答案往后走(即:让l=mid)
珂珂喜欢吃香蕉。这里有 n
堆香蕉,第 i
堆中有 piles[i]
根香蕉。警卫已经离开了,将在 h
小时后回来。
珂珂可以决定她吃香蕉的速度 k
(单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k
根。如果这堆香蕉少于 k
根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
返回她可以在 h
小时内吃掉所有香蕉的最小速度 k
(k
为整数)。
示例 1:
输入:piles = [3,6,7,11], h = 8 输出:4
示例 2:
输入:piles = [30,11,23,4,20], h = 5 输出:30
示例 3:
输入:piles = [30,11,23,4,20], h = 6 输出:23
提示:
1 <= piles.length <= 104
piles.length <= h <= 109
1 <= piles[i] <= 109
比如:
- [6,4 ,5,2,4,3],离开20h
- 假如说速度是5根/1h
- 1)6->1
- 2)1->0
- 然后休息
- 3)4->0
- 休息
- 有富余的时间就休息了,没富余时间继续吃下一堆
- 推下来5达标满足
- 然后推下来4也达标
- 要求速度尽量小还要达标
- 1不达标....2达标(所以答案是2)
- bool check(int* piles, int pilesSize, int h, int mid) {
- long int sum = 0;
- for (int i = 0; i < pilesSize; i++) {
-
- if (piles[i] % mid != 0) {
- sum += (piles[i] / mid) + 1;
- }
- else{
- sum+=piles[i]/mid;
- }
- }
- return sum <= h;
- }
- int minEatingSpeed(int* piles, int pilesSize, int h) {
- // 最小且达标的速度,范围[l,r]
- int l = 1;
- int r = 0;
- for (int i = 0; i < pilesSize; i++) {
- if (piles[i] >= r)
- r = piles[i];
- }
- //[l,r]不停的二分
- int ans = 0;
- while (l <= r) { // 直到二分范围消失
- int mid = (r + l) / 2;
- if (check(piles, pilesSize, h, mid)) {
- // 达标,记录答案
- // 左侧二分
- ans = mid;
- r = mid - 1;
- } else {
- // 不达标,不记答案
- // 右侧二分
- l = mid + 1;
- }
- }
- return ans;
- }

给定一个非负整数数组 nums
和一个整数 k
,你需要将这个数组分成 k
个非空的连续子数组。
设计一个算法使得这 k
个子数组各自和的最大值最小。
示例 1:
输入:nums = [7,2,5,10,8], k = 2 输出:18 解释: 一共有四种方法将 nums 分割为 2 个子数组。 其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。 因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。
示例 2:
输入:nums = [1,2,3,4,5], k = 2 输出:9
示例 3:
输入:nums = [1,4,4], k = 3 输出:4
提示:
1 <= nums.length <= 1000
0 <= nums[i] <= 106
1 <= k <= min(50, nums.length)
思路:
估计最终答案可能的范围
分析问题的答案和给定条件之间的单调性
建议一个check函数,当答案固定的情况下,判断给定的条件是否达标
在最终答案可能的范围上不断二分搜索,每次使用check函数判断,直到二分结束,找到最合适的答案
- bool check(int* nums, int numsSize, int k, int mid) {
- // 必须让数组每一份的累加和满足<=mid,请问划分成几个部分才够
- // 一直加加到要超了,就停,代表一个子达成,
- // 但如果单点的值就超过,直接用整数最大值表示没有方案
- int parts = 1;
- int sum = 0;
- for (int i = 0; i < numsSize; i++) {
- if (nums[i] > mid) {
- return false;
- }
- if (sum + nums[i] > mid) {
- parts++;
- sum = nums[i];
- } else {
- sum += nums[i];
- }
- }
- return parts <= k;
- }
- int splitArray(int* nums, int numsSize, int k) {
- long int sum = 0;
- for (int i = 0; i < numsSize; i++) {
- sum += nums[i];
- }
- long int ans = 0;
- long int l = 0;
- long int r = sum;
- //[0,ans]二分
- while (l <= r) {
- // 必须让数组每一份的累加和满足<=mid,请问划分成几个部分才够
- int mid = (l + r) / 2;
- if (check(nums, numsSize, k, mid)) {
- // 如果你需要的部分数量<=给你的部分的数量说明达标
- ans = mid;
- r = mid - 1;
- } else {
- l = mid + 1;
- }
- }
- return ans;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。