06-C++ 基本算法 - 二分法

在这里插入图片描述

📖 前言

在这个笔记中,我们将介绍二分法这种基本的算法思想,以及它在 C++ 中的应用。我们将从一个小游戏猜数字开始,通过这个案例来引出二分法的概念。然后我们将详细讲解什么是二分法以及它的套路和应用。最后,我们还会介绍 C++ STL 中的二分查找函数。让我们一起来探索吧!

🎯 什么是二分法

二分法是一种高效的搜索算法,通过将搜索范围不断缩小一半来快速找到目标值。它适用于有序数组或有序区间中查找特定元素的问题。二分法的基本思想是通过比较中间值与目标值的大小关系,来确定目标值可能存在的那一半区间,然后在该区间内继续查找。

🎮 小游戏猜数字

让我们通过一个小游戏来理解二分法的基本思想。假设有一个整数范围为 1 到 100,你需要猜一个隐藏的数字。每次猜测后,系统会告诉你猜的数字是大了还是小了,直到猜中为止。

在这里插入图片描述

这个小游戏的思路就是使用二分法来快速定位目标数字的范围。每次猜测时,将当前范围的中间数字与目标数字进行比较,根据比较结果来调整范围。通过不断缩小范围,最终可以找到目标数字。

🌟 二分法的套路

二分法有一些常见的套路和应用场景,我们将逐个介绍它们。

3.1 整数的二分

整数的二分是二分法的一种常见应用。我们以两个案例来说明整数的二分应用。

3.1.1 案例1: 力扣704. 二分查找

给定一个升序排列的整数数组 nums 和一个目标值 target,请你实现二分查找算法,如果目标值存在于数组中,则返回其索引,否则返回 -1。

示例代码:

#include <iostream>
#include <vector>
using namespace std;

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

int main() {
    vector<int> nums = {1, 3, 5, 7, 9, 11};
    int target = 7;
    int result = binarySearch(nums, target);
    if (result != -1) {
        cout << "目标值 " << target << " 在数组中的索引为 " << result << endl;
    } else {
        cout << "目标值 " << target << " 不存在于数组中" << endl;
    }
    return 0;
}

运行结果:

目标值 7 在数组中的索引为 3

在上述代码中,我们使用二分法实现了查找目标值在有序数组中的索引。通过不断调整搜索范围的左右边界,并根据中间值与目标值的比较结果来确定下一步的搜索方向,最终可以找到目标值的索引。

3.1.2 案例2: 力扣350. 两个数组的交集 II

给定两个整数数组 nums1nums2,请你返回它们的交集。结果中每个元素的出现次数应与元素在两个数组中出现的次数一致(如果次数不一致,则取较小的次数)。结果不考虑顺序。

示例代码:

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
    unordered_map<int, int> counter;
    for (int num : nums1) {
        counter[num]++;
    }
    
    vector<int> result;
    for (int num : nums2) {
        if (counter[num] > 0) {
            result.push_back(num);
            counter[num]--;
        }
    }
    
    return result;
}

int main() {
    vector<int> nums1 = {1, 2, 2, 1};
    vector<int> nums2 = {2, 2};
    vector<int> result = intersect(nums1, nums2);
    
    cout << "两个数组的交集为:";
    for (int num : result) {
        cout << num << " ";
    }
    cout << endl;
    
    return 0;
}

运行结果:

两个数组的交集为:2 2

在上述代码中,我们使用哈希表记录了 nums1 中每个元素的出现次数,并通过遍历 nums2 找到与之对应的交集元素。通过减少交集元素的出现次数,最终可以得到交集的结果。

3.2 实数的二分

除了整数的二分,实数的二分也是二分法的一种应用。在实数的二分中,我们需要考虑精度问题,因为实数在计算机中无法表示为精确的值。下面是一个案例来说明实数的二分应用。

案例: 计算平方根

给定一个非负实数 x,要

求计算它的平方根并返回。我们可以使用二分法来逼近平方根的值,直到达到所需的精度。

示例代码:

#include <iostream>
using namespace std;

double sqrt(double x, double precision) {
    if (x < 0) {
        return -1; // 输入错误,返回 -1
    }
    
    double left = 0;
    double right = x;
    double mid;
    
    while (right - left > precision) {
        mid = left + (right - left) / 2;
        if (mid * mid <= x) {
            left = mid;
        } else {
            right = mid;
        }
    }
    
    return left;
}

int main() {
    double x = 16;
    double precision = 0.0001;
    double result = sqrt(x, precision);
    
    cout << "输入的数:" << x << endl;
    cout << "计算得到的平方根:" << result << endl;
    
    return 0;
}

运行结果:

输入的数:16
计算得到的平方根:4

在上述代码中,我们通过二分法逼近平方根的值,直到所达到的精度小于指定的 precision。通过不断调整搜索范围的左右边界,最终可以得到近似的平方根值。

💡 STL 二分查找

除了手动实现二分法算法,C++ STL(标准模板库)中也提供了二分查找的函数。这些函数包括 lower_bound()upper_bound(),它们可以方便地应用于有序容器中。

4.1 lower_bound()

lower_bound() 函数用于在有序容器中查找第一个大于或等于给定值的元素的迭代器。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> nums = {1, 3, 5, 7, 9};
    int target = 4;
    auto it = lower_bound(nums.begin(), nums.end(), target);
    
    if (it != nums.end()) {
        cout << "第一个大于或等于目标值的元素为:" << *it << endl;
    } else {
        cout << "没有找到满足条件的元素" << endl;
    }
    
    return 0;
}

运行结果:

第一个大于或等于目标值的元素为:5

在上述代码中,我们使用 lower_bound() 函数在有序容器 nums 中查找第一个大于或等于目标值 target 的元素。函数返回一个迭代器,指向满足条件的元素。

4.2 upper_bound()

upper_bound() 函数用于在有序容器中查找第一个大于给定值的元素的迭代器。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> nums = {1, 3, 5, 7, 9};
    int target = 4;
    auto it = upper_bound(nums.begin(), nums.end(), target);
    
    if (it != nums.end()) {
        cout << "第一个大于目标值的元素为:" << *it << endl;
    } else {
        cout << "没有找到满足条件的元素" << endl;
    }
    
    return 0;
}

运行结果:

第一个大于目标值的元素为:5

在上述代码中,我们使用 upper_bound() 函数在有序容器 nums 中查找第一个大于目标值 target 的元素。函数返回一个迭代器,指向满足条件的元素。

📚 总结

在本篇笔记中,我们学习了二分法这种基本的算法思想,并在 C++ 中通过案例和代码进行了详细讲解。我们了解了二分法的套路和应用场景,包括整数的二分和实数的二分。此外,我们还介绍了 C++ STL 中的二分查找函数 lower_bound()upper_bound(),它们可以方便地应用于有序容器中。希望通过本篇笔记的学习,你对二分法有了更深入的理解,并能够熟练应用于解决问题。祝你在算法学习的道路上越走越远!

本篇笔记内容主要参考了《算法竞赛进阶指南》和 LeetCode 等相关资源。

⭐️希望本篇文章对你有所帮助。

⭐️如果你有任何问题或疑惑,请随时向提问。

⭐️感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/39917.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为什么弹性内容交付网络是决定网站性能的关键

如今的用户对于所访问网站都对网站有自己的标准&#xff0c;他们期望访问的网站性能良好&#xff0c;具有快速的页面加载时间和易于访问、新鲜且动态的内容&#xff0c;同时他们还希望享受无缝且安全的体验&#xff0c;无需停机或内容访问受到限制。比如微博等平台每次在网络热…

centos7安装 mongodb

一、rpm安装 1.1、配置MongoDB Enterprise的yum 源文件 [mongodb-enterprise] nameMongoDB Enterprise Repository baseurlhttps://repo.mongodb.com/yum/redhat/$releasever/mongodb-enterprise/3.4/$basearch/ gpgcheck1 enabled1 gpgkeyhttps://www.mongodb.org/static/pgp…

【Python爬虫+可视化案例】采集电商网站商品数据信息,并可视化分析

爬虫可视化案例 &#xff1a;苏宁易购 案例所需要掌握的知识点&#xff1a; selenium的使用html标签数据解析方法 需要准备的环境&#xff1a; python 3.8pycharm 2022专业版selenium python里面的第三方库 可以用来操作浏览器 爬虫代码展示 所需模块 【代码领取 请看文末…

开发工具篇第二十六讲:使用IDEA进行本地调试和远程调试

开发工具篇第二十六讲&#xff1a;使用IDEA进行本地调试和远程调试 Debug用来追踪代码的运行流程&#xff0c;通常在程序运行过程中出现异常&#xff0c;启用Debug模式可以分析定位异常发生的位置&#xff0c;以及在运行过程中参数的变化&#xff1b;并且在实际的排错过程中&am…

C++-string类的模拟实现

本博客基于C官方文档当中给出的string类当中的主要功能实现&#xff0c;来作为参照&#xff0c;简单模拟实现 My-string 。 对于C当中的string类的介绍&#xff0c;在之前的几篇博客当中有说明&#xff0c;如有问题&#xff0c;请参照一下两个博客文章进行参考&#xff1a; (2…

使用 Pytest 运行 yaml 文件来驱动 Appium 自动化测试

目录 前言&#xff1a; 获取 yaml 文件 YamlTest 测试类 Appium 初始化 Pytest 测试类 自定义 runtest demo&#xff1a; 自定义错误输出 Yaml 使用方式规则 前言&#xff1a; 使用Pytest来运行yaml文件来驱动Appium自动化测试是一种方便且灵活的方法。通过将测试数据…

CSS 渐变边框及动画

转载请注明出处&#xff0c;点击此处 查看更多精彩内容 用 CSS 实现渐变边框及动画&#xff0c;下面对关键点进行解释说明&#xff0c;查看完整代码及预览效果请 点击这里。 简单说明原理&#xff1a;使用伪元素 ::before 绘制一个渐变色&#xff0c;然后使用伪元素 ::after 绘…

【数据结构】二叉树详解(2)

⭐️ 前言 ✨ 往期文章链接&#xff1a;二叉树的概念性质 上一篇我们讲了二叉树的结构定义&#xff0c;以及前序/中序/后序的递归遍历&#xff0c;还有一些二叉树的接口实现&#xff0c;本篇我们补充一个二叉树的接口 BinaryTreeDepth。✨上一篇文章链接&#xff1a;二叉树详…

【原创】实现ChatGPT中Transformer模型之Encoder-Decoder

作者&#xff1a;黑夜路人 时间&#xff1a;2023年7月 Transformer Block &#xff08;通用块&#xff09;实现 看以上整个链路图&#xff0c;其实我们可以很清晰看到这心其实在Encoder环节里面主要是有几个大环节&#xff0c;每一层主要的核心作用如下&#xff1a; Multi-he…

出租屋智能电表系统

随着科技的不断发展&#xff0c;智能化逐渐成为人们生活中不可或缺的一部分。在房屋租赁市场中&#xff0c;智能电表系统成为越来越多出租屋的标配&#xff0c;为房东和租户带来了便捷和安全。本文将从以下几个方面介绍出租屋智能电表系统的特点和优势。 一、出租屋智能电表系统…

第二十一章:CCNet:Criss-Cross Attention for Semantic Segmentation ——用于语义分割的交叉注意力

0.摘要 全图像依赖关系为视觉理解问题提供了有用的上下文信息。在这项工作中&#xff0c;我们提出了一种称为Criss-Cross Network&#xff08;CCNet&#xff09;的方法&#xff0c;以更有效和高效的方式获取这种上下文信息。具体而言&#xff0c;对于每个像素&#xff0c;CCNet…

Linux 系统编程-开发环境(二)

目录 7 压缩包管理 7.1 tar 7.2 rar 7.3 zip 8 进程管理 8.1 who 8.2 ps 8.3 jobs 8.4 fg 8.5 bg 8.6 kill 8.7 env 8.8 top 9 用户管理 9.1 创建用户 9.2 设置用户组 9.3 设置密码 9.4 切换用户 9.5 root用户 9.6 删除用户 10 网络管理 10.1 i…

Word之解决中文和英文混写导致字间距增大的问题(六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

机器学习1

核心梯度下降算法&#xff1a; import numpy as np from utils.features import prepare_for_trainingclass LinearRegression:def __init__(self,data,labels,polynomial_degree 0,sinusoid_degree 0,normalize_dataTrue):"""1.对数据进行预处理操作2.先得到…

【iOS】编译与链接

前言 计算机语言分为机器语言、汇编语言和高级语言。 可以将高级语言分为两种&#xff1a;编译语言和解释型语言&#xff08;直译式语言&#xff09;。 解释型语言&#xff08;逐步进行解释执行&#xff09; 解释语言编写的程序在每次运行时都需要通过解释器对程序进行动态…

(四)「消息队列」之 RabbitMQ 路由(使用 .NET 客户端)

0、引言 先决条件 本教程假设 RabbitMQ 已安装并且正在 本地主机 的标准端口&#xff08;5672&#xff09;上运行。如果您使用了不同的主机、端口或凭证&#xff0c;则要求调整连接设置。 获取帮助 如果您在阅读本教程时遇到问题&#xff0c;可以通过邮件列表或者 RabbitMQ 社区…

图数据库:neo4j学习笔记

参考资料&#xff1a;neo4j 教程_w3cschool Springboot集成Neo4j_喝醉的咕咕鸟的博客-CSDN博客 SpringBoot 整合 Neo4j_springboot neo4j_$懒小猿$的博客-CSDN博客 图数据库Neo4j实战&#xff08;全网最详细教程&#xff09;_neo4j使用教程_星川皆无恙的博客-CSDN博客 代码片段…

【个人笔记】linux的cd命令与目录结构理解

cd命令 cd&#xff08;英文全拼&#xff1a;change directory&#xff09;命令用于改变当前工作目录的命令&#xff0c;切换到指定的路径。 若目录名称省略&#xff0c;则变换至使用者的 home 目录 (也就是刚 login 时所在的目录)。 另外&#xff0c;~ 也表示为 home 目录 的…

flask基本用法小白教程+按钮跳转到指定页面+python和pip安装(后附)

一、flask学习教程&#xff1a; 1.1 基本程序&#xff1a; 大家可以在pycharm中复制如下代码&#xff0c;先感受一下flask的基本用法&#xff1a; 点击链接可进入浏览器查看程序运行的结果&#xff0c;在127.0.0.1:5000后面添上/test1/等设定的文字&#xff0c;可查看不同函…

Flutter:网络图像缓存插件——cached_network_image

前言 为什么要使用这个插件&#xff0c;有什么用呢&#xff1f;毕竟官方提供了Image.network来进行网络图片加载 Image.network和CachedNetworkImage都可以用于在Flutter中加载网络图片&#xff0c;但它们之间有一些区别。 Image.network是Flutter核心库提供的一个构造函数&…