cen's blog cen's blog
首页
  • 编程文章

    • markdown使用
  • 学习笔记

    • C++学习
    • C++数据结构
    • MySQL
    • Linux
    • 网络编程
算法
  • CLion
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)

cen

十年饮冰,难凉热血
首页
  • 编程文章

    • markdown使用
  • 学习笔记

    • C++学习
    • C++数据结构
    • MySQL
    • Linux
    • 网络编程
算法
  • CLion
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)
  • 双指针算法
  • 二分算法
    • 引入
    • 二分查找
      • 34.在排序数组中查找元素的第一个和最后一个位置
      • 162.寻找峰值
      • 153.寻找旋转排序数组中的最小值
    • 二分答案
      • 875.爱吃香蕉的珂珂
      • 2861.最大合金数
  • 常用数据结构
  • 算法
cen
2025-08-20
目录

二分算法

# 引入

题目:一个按照非递减顺序排列的整数数组 nums,找出第一个大于等于 target 的数字下标

C++提供了lower_bound库函数来解决对应问题

    vector<int> nums = {1, 2, 66, 89, 100, 233};
    cout << lower_bound(nums.begin(), nums.end(), 100) - nums.begin();  // 4
    cout << lower_bound(nums.begin(), nums.end(), 500) - nums.begin();  // nums.size() = 6
1
2
3

我们使用二分查找来实现以及拓展(三种写法):

int lower_bound1(vector<int> &nums, int target) {
    // [left, right]
    int left = 0, right = nums.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return left;
}

int lower_bound2(vector<int> &nums, int target) {
    // [left, right)
    int left = 0, right = nums.size();
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    return left;
}

int lower_bound3(vector<int> &nums, int target) {
    // (left, right)
    int left = -1, right = nums.size();
    while (left + 1 < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid;
        } else {
            right = mid;
        }
    }
    return right;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

四种类型:

  • >=(x)
  • >(x) 转换 >=(x + 1)
  • <(x) 转换 >=(x) - 1
  • <=(x) 转换 >(x) - 1

# 二分查找

# 34.在排序数组中查找元素的第一个和最后一个位置

题目:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。

示例:输入:nums = [5,7,7,8,8,10], target = 8 输出:[3,4]

class Solution {
public:
    int findFirst(vector<int>& nums, int target) {
        int left = 0, right = nums.size();
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
    vector<int> searchRange(vector<int>& nums, int target) {
        // 非递减顺序排列:二分
        // 返回[>= target, > target - 1]
        int start = findFirst(nums, target);
        if (start == nums.size() || nums[start] != target) {
            return {-1, -1};
        }
        return {start, findFirst(nums, target + 1) - 1};
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 162.寻找峰值

题目:峰值元素是指其值严格大于左右相邻值的元素。给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。你可以假设 nums[-1] = nums[n] = -∞

示例:输入:nums = [1,2,3,1] 输出:2 解释:3 是峰值元素,你的函数应该返回其索引 2

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        // 返回任何一个峰值(严格大于左右相邻值)所在下标
        int l = 0, r = nums.size() - 1;
        while(l < r) {
            int mid = l + (r - l) / 2;
            if(nums[mid] < nums[mid + 1]) {
                l = mid + 1;
            }
            else {
                r = mid;
            }
        }
        return l;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 153.寻找旋转排序数组中的最小值

题目:已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次旋转后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]给你一个元素值互不相同的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的最小元素。

示例:输入:nums = [3,4,5,1,2] 输出:1 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组

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

# 二分答案

# 875.爱吃香蕉的珂珂

题目:珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。珂珂可以决定她吃香蕉的速度 k(单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。

示例:输入:piles = [3,6,7,11], h = 8 输出:4

class Solution {
public:
    bool check(vector<int>& piles, int h, int k) {
        int time = 0;
        for (auto& pile : piles) {
            time += (pile - 1) / k + 1;
            if (time > h) {
                return false;
            }
        }
        return true;
    }

    int minEatingSpeed(vector<int>& piles, int h) {
        // 吃香蕉速度的范围:[1, INT_MAX]
        int left = 1, right = INT_MAX;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (check(piles, h, mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  • ⌈ x / y ⌉ = (x - 1) / y + 1
  • ⌊x / y ⌋ = x / y

# 2861.最大合金数

题目:假设你是一家合金制造公司的老板,你的公司使用多种金属来制造合金。现在共有 n 种不同类型的金属可以使用,并且你可以使用 k 台机器来制造合金。每台机器都需要特定数量的每种金属来创建合金。对于第 i 台机器而言,创建合金需要 composition[i][j] 份 j 类型金属。最初,你拥有 stock[x] 份 x 类型金属,而每购入一份 x 类型金属需要花费 cost[x] 的金钱。给你整数 n、k、budget,下标从 1 开始的二维数组 composition,两个下标从 1 开始的数组 stock 和 cost,请你在预算不超过 budget 金钱的前提下,最大化 公司制造合金的数量。所有合金都需要由同一台机器制造。返回公司可以制造的最大合金数。

示例:输入:n = 3, k = 2, budget = 15, composition = [[1,1,1],[1,1,10]], stock = [0,0,0], cost = [1,2,3] 输出:2 解释:最优的方法是使用第 1 台机器来制造合金。要想制造 2 份合金,我们需要购买:

  • 2 份第 1 类金属。
  • 2 份第 2 类金属。
  • 2 份第 3 类金属。

总共需要 2 _ 1 + 2 _ 2 + 2 * 3 = 12 的金钱,小于等于预算 15

class Solution {
public:
    bool check(int budget, vector<vector<int>>& composition, vector<int>& stock,
               vector<int>& cost, int num) {
        long long ret = 0;
        int k = composition.size();
        int n = composition[0].size();
        for (int i = 0; i < k; i++) {
            long long sum = 0;
            for (int j = 0; j < n; j++) {
                sum += max(static_cast<long long>(composition[i][j]) * num - stock[j], 0LL) * cost[j];
            }
            if (sum <= budget)
                return true;
        }
        return false;
    }

    int maxNumberOfAlloys(int n, int k, int budget,
                          vector<vector<int>>& composition, vector<int>& stock,
                          vector<int>& cost) {
        int l = 0, r = 2e8;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (check(budget, composition, stock, cost, mid)) {
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        return l - 1;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
上次更新: 2025/09/03, 18:26:17
双指针算法
常用数据结构

← 双指针算法 常用数据结构→

最近更新
01
网络协议
09-03
02
套接字和TCP
08-26
03
常用数据结构
08-23
更多文章>
Theme by Vdoing | Copyright © 2024-2025 京ICP备2020044002号-3 京公网安备11010502056119号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式