博客
关于我
刷题:《算法笔记》-二分法
阅读量:486 次
发布时间:2019-03-06

本文共 3021 字,大约阅读时间需要 10 分钟。


二分搜索的常见问题及解决方案

二分搜索是一种高效的查找算法,广泛应用于排序数组和有序列表中寻找元素的问题。其核心在于通过不断地将查找范围缩小,提高效率。以下我将详细探讨几个常见的二分搜索应用,并提供解决方案。

一、寻找有序序列中的第一个满足条件的位置

在这个问题中,我们需要在一个有序的数组中,从左到右找到第一个满足特定条件的元素的位置。条件可以是从左到右的,也可以是从右到左的。以下是通用的解决方案:

解决思路:

  • 初始化两个指针leftright,分别指向数组的开头和结尾。
  • 计算中间指针mid的位置。
  • 如果中间位置的元素满足条件,将right指针移动到mid,继续搜索更小的范围。
  • 如果中间位置的元素不满足条件,将left指针移动到mid + 1
  • leftright指针交叉时,返回left指针的位置,作为第一个满足条件的元素。
  • 示例一: 给定一个从小到大排序的数组,寻找第一个大于等于给定值x的元素。

    int findFirstNotLessThanX(int A[], int left, int right, int x) {
    int mid;
    while (left < right) {
    mid = (left + right) / 2;
    if (A[mid] >= x) {
    right = mid;
    } else {
    left = mid + 1;
    }
    }
    return left;
    }

    示例二: 寻找从大到小排序的数组中的最小元素,满足条件A[mid] < x

    int findFirstLessThanX(int A[], int left, int right, int x) {
    int mid;
    while (left < right) {
    mid = (left + right) / 2;
    if (A[mid] < x) {
    left = mid + 1;
    } else {
    right = mid;
    }
    }
    return left - 1;
    }

    解决策略: 对于每个问题,确定正确的比较条件,并在二分搜索过程中调整指针位置。通过这种方式,能够有效找到目标元素的位置。

    二、查找是否存在满足特定条件的元素

    另一个常见的二分问题是判断是否存在一个特定的元素。这种情况下,我们可以用一个类似的方法,但每次比较都是为了缩小搜索范围,最终确定是否存在目标元素。

    解决思路:

  • 初始化两个指针leftright,分别指向数组的开头和结尾。
  • 计算中间指针mid的位置。
  • 比较mid位置的元素与目标值x
    • 如果相等,返回mid,表示存在。
    • 如果小于,说明目标值在mid的右侧。
    • 如果大于,说明目标值在mid的左侧。
  • 通过不断调整指针位置,直到leftright指针重合或交叉。
  • 如果未找到目标值,返回-1。
  • 示例:

    int findExists(int A[], int left, int right, int x) {
    int mid;
    while (left <= right) {
    mid = (left + right) / 2;
    if (A[mid] == x) {
    return mid;
    } else if (A[mid] > x) {
    right = mid - 1;
    } else {
    left = mid + 1;
    }
    }
    return -1;
    }

    服务器优化建议:

    • 保持语言简洁明了,避免复杂句式。
    • 使用小标题分隔不同类型内容。
    • 适当使用列表项突出要点,便于阅读。

    木棒切割问题:求最长能分割成K段相等长度的部分

    该问题要求通过切割木棒,得到至少K段长度相等的木棒。目标是找到这些段的最大可能长度。

    分析:

    • 长度越长,总段数越少,因此最长段数越大,相应的最小乘积越小。
    • 需要对木棒长度进行排序,倒序处理,找到满足条件的最大长度。

    解决策略:

  • 排序木棒,按长度递减顺序排列。
  • 使用二分搜索,寻找最大长度l,使得木棒数量至少达到K段。
  • 切割方法:选择长度为l的木棒,尽可能多地切成l长度的段。
  • 示例解法: 给定木棒长度[15,10,24],K=7,提取最长长度6。

    二分搜索步骤:

  • 排序后:24,15,10。
  • 初始化left=1(最小可能长度),right=24
  • 调用二分函数,找到最大的长度,使得切割后能满足至少7段。
  • 最终返回6作为最大长度。

  • 凸多边形的最大外接圆半径计算

    给定N条线段,期望通过将它们首尾相接,组成凸多边形,求其外接圆半径的最大值。

    分析:

    • 最大半径至少为最大线段的一半。
    • 圆心角总和为

    解决策略:

  • 使用二分搜索求解半径。
  • 对中间半径mid,计算所有线段对应的圆心角。
  • 根据圆心角总和判断半径的可行性。
  • 调整搜索范围,寻找最大可行半径。
  • 示例计算:

    double totalCornerAngles(double edges[], int n, double r) {
    double sum = 0.0;
    for (int i = 0; i < n; i++) {
    sum += 2 * asin(edges[i] / r);
    }
    return sum;
    }
    double computeMaxRadius(double A[], int n) {
    sort(A, A + n);
    double maxedge = A[0];
    double maxr = maxedge / 2;
    // 二分搜索之间的比较条件
    const double eps = 1e-5;
    double left = maxr;
    double right = 100; // 上界设置
    while (right - left > eps) {
    double mid = (left + right) / 2;
    double sum = totalCornerAngles(A, n, mid);
    if (sum > 2 * PI) {
    // 半径可以更小
    right = mid;
    } else {
    // 半径需要更大
    left = mid;
    }
    }
    return mid;
    }

    总结

    通过以上分析,我成功理解并应用了二分搜索在不同问题中的解决方法。无论是寻找元素位置还是求解外接圆半径,二分搜索都提供了高效的解决方案。未来,我将继续练习这些算法,以提升对数据结构和算法的理解能力。

    转载地址:http://xeldz.baihongyu.com/

    你可能感兴趣的文章
    NI笔试——大数加法
    查看>>
    NLog 自定义字段 写入 oracle
    查看>>
    NLog类库使用探索——详解配置
    查看>>
    NLP 基于kashgari和BERT实现中文命名实体识别(NER)
    查看>>
    NLP 模型中的偏差和公平性检测
    查看>>
    Vue3.0 性能提升主要是通过哪几方面体现的?
    查看>>
    NLP 项目:维基百科文章爬虫和分类【01】 - 语料库阅读器
    查看>>
    NLP_什么是统计语言模型_条件概率的链式法则_n元统计语言模型_马尔科夫链_数据稀疏(出现了词库中没有的词)_统计语言模型的平滑策略---人工智能工作笔记0035
    查看>>
    NLP三大特征抽取器:CNN、RNN与Transformer全面解析
    查看>>
    NLP学习笔记:使用 Python 进行NLTK
    查看>>
    NLP度量指标BELU真的完美么?
    查看>>
    NLP的不同研究领域和最新发展的概述
    查看>>
    NLP的神经网络训练的新模式
    查看>>
    NLP采用Bert进行简单文本情感分类
    查看>>
    NLP问答系统:使用 Deepset SQUAD 和 SQuAD v2 度量评估
    查看>>
    NLP项目:维基百科文章爬虫和分类【02】 - 语料库转换管道
    查看>>
    NLP:使用 SciKit Learn 的文本矢量化方法
    查看>>
    nmap 使用方法详细介绍
    查看>>
    Nmap扫描教程之Nmap基础知识
    查看>>
    nmap指纹识别要点以及又快又准之方法
    查看>>