【二分查找】自写二分函数的总结

简介: 【二分查找】自写二分函数的总结

自写二分函数 的封装

我暂时只发现两种:

一,在左闭右开的区间寻找最后一个符合条件的元素,我封装成FindEnd函数。

二,在左开右闭的区间寻找第一个符合条件的元素,我封装成FindFirst函数。

namespace NBinarySearch
{
  template<class INDEX_TYPE,class _Pr>
  INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE rightInclue, _Pr pr)
  {
    while (rightInclue - left > 1)
    {
      const auto mid = left + (rightInclue - left) / 2;
      if (pr(mid))
      {
        rightInclue = mid;
      }
      else
      {
        left = mid;
      }
    }
    return rightInclue;
  }
  template<class INDEX_TYPE, class _Pr>
  INDEX_TYPE FindEnd(INDEX_TYPE leftInclude, INDEX_TYPE right, _Pr pr)
  {
    while (right - leftInclude > 1)
    {
      const auto mid = leftInclude + (right - leftInclude) / 2;
      if (pr(mid))
      {
        leftInclude = mid;
      }
      else
      {
        right = mid;
      }
    }
    return leftInclude;
  }
}

左闭右开 左开右闭的例子

LeetCode33: C++算法:二分查找旋转数组

class Solution {
public:
  int search(vector<int>& nums, int target) {
    int rBegin = NBinarySearch::FindFrist(-1, (int)nums.size() - 1, [&](const int mid) {return nums[mid] <= nums.back(); });
    if (target <= nums.back())
    {
      return Find(nums, rBegin, nums.size(), target);
    }
    return Find(nums, 0, rBegin, target);
  }
  int Find(const vector<int>& nums, int left, int r, int target)
  {
    int iRet = NBinarySearch::FindEnd(left,r, [&](const int mid) {return nums[mid] <= target; });
    return (target == nums[iRet]) ? iRet : -1;
  }
};
int main()
{
  vector<int> vNums = { 1,2,3,4,6 };
  auto res = Solution().search(vNums, 4);
  std::cout << "index:" << res;
  if (-1 != res)
  {
    std::cout << " value:" << vNums[res];
  }
}

左闭右开的例子

Leetcode2790:C++二分查找算法的应用:长度递增组的最大数目

namespace NBinarySearch
{
  template<class INDEX_TYPE,class _Pr>
  INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE rightInclue, _Pr pr)
  {
    while (rightInclue - left > 1)
    {
      const auto mid = left + (rightInclue - left) / 2;
      if (pr(mid))
      {
        rightInclue = mid;
      }
      else
      {
        left = mid;
      }
    }
    return rightInclue;
  }
  template<class INDEX_TYPE, class _Pr>
  INDEX_TYPE FindEnd(INDEX_TYPE leftInclude, INDEX_TYPE right, _Pr pr)
  {
    while (right - leftInclude > 1)
    {
      const auto mid = leftInclude + (right - leftInclude) / 2;
      if (pr(mid))
      {
        leftInclude = mid;
      }
      else
      {
        right = mid;
      }
    }
    return leftInclude;
  }
}
class Solution {
public:
  int maxIncreasingGroups(vector<int>& usageLimits) {
    m_c = usageLimits.size();
    m_v = usageLimits;
    sort(m_v.begin(), m_v.end());
    auto Can = [&](int len)
    {
      int i = m_c - 1;
      long long llNeed = 0;
      for (; len > 0; len--, i--)
      {
        llNeed -= (m_v[i] - len);
        if (m_v[i] >= len)
        {
          llNeed = max(0LL, llNeed);
        }
      }
      for (; i >= 0; i--)
      {
        llNeed -= m_v[i];
      }
      return llNeed <= 0;
    };
    return NBinarySearch::FindEnd(1, m_c + 1, Can);
  }
  int m_c;
  vector<int> m_v;
};
template<class T>
void Assert(const T& t1, const T& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{
  Solution slu;
  vector<int> usageLimits;
  int res = 0;
  usageLimits = { 2,2,2 };
  res = slu.maxIncreasingGroups(usageLimits);
  Assert(res, 3);
  usageLimits = { 1,2,5 };
  res = slu.maxIncreasingGroups(usageLimits);
  Assert(res, 3);
  usageLimits = { 2,1,2 };
  res = slu.maxIncreasingGroups(usageLimits);
  Assert(res, 2);
  usageLimits = { 1,1 };
  res = slu.maxIncreasingGroups(usageLimits);
  Assert(res, 1);
  //CConsole::Out(res);
}

左闭右开的应用

C++二分查找算法的应用:最小好进制

Is

计算是否存在m位 k进制的1为目标数。m位iRet 进制1大于等于目标数,可能有多个符合的iRet,取最小值。非最小值一定不是。

namespace NBinarySearch
{
  template<class INDEX_TYPE,class _Pr>
  INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE rightInclue, _Pr pr)
  {
    while (rightInclue - left > 1)
    {
      const auto mid = left + (rightInclue - left) / 2;
      if (pr(mid))
      {
        rightInclue = mid;
      }
      else
      {
        left = mid;
      }
    }
    return rightInclue;
  }
  template<class INDEX_TYPE, class _Pr>
  INDEX_TYPE FindEnd(INDEX_TYPE leftInclude, INDEX_TYPE right, _Pr pr)
  {
    while (right - leftInclude > 1)
    {
      const auto mid = leftInclude + (right - leftInclude) / 2;
      if (pr(mid))
      {
        leftInclude = mid;
      }
      else
      {
        right = mid;
      }
    }
    return leftInclude;
  }
}
class Solution {
public:
  string smallestGoodBase(string n) {
    long long llN = 0;
    for (const auto& ch : n)
    {
      llN = (llN * 10 + ch - '0');
    }
    for (int i = 70; i > 2; i--)
    {
      long long llRet = Is(i, llN);
      if (llRet > 0)
      {
        return std::to_string(llRet);
      }
    }
    return std::to_string(llN - 1);
  }
  long long Is(int m, long long n)
  {
    int iRet = NBinarySearch::FindEnd(2LL, n + 1LL, [&](const auto mid) {return Cmp(mid, m, n) >= 0; });
    return (0 == Cmp(iRet,m,n))? iRet : 0;
  }
  //k进制的m个1和n的大小比较,n大返回正数,相等返回0,n小返回负数
  long long Cmp(long long k, int m, long long n)
  {
    long long llHas = 1;
    for (; m > 0; m--)
    {
      if (n < llHas)
      {
        return -1;
      }
      n -= llHas;
      if (m > 1)
      {// 最后一次llHas并不使用,所以越界不影响
        if (LLONG_MAX / k < llHas)
        {
          return -1;
        }
        llHas *= k;
      }
    }
    return n;
  }
};
template<class T>
void Assert(const T& t1, const T& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{
  Solution slu;
  string res;
  res = slu.smallestGoodBase("470988884881403701");
  Assert(res, std::string("686286299"));
  res = slu.smallestGoodBase("2251799813685247");
  Assert(res, std::string("2"));
  res = slu.smallestGoodBase("13");
  Assert(res, std::string("3"));
  res = slu.smallestGoodBase("4681");
  Assert(res, std::string("8"));
  res = slu.smallestGoodBase("1000000000000000000");
  Assert(res, std::string("999999999999999999"));
  res = slu.smallestGoodBase("1333");
  Assert(res, std::string("36"));
  res = slu.smallestGoodBase("463381");
  Assert(res, std::string("463380"));
  //CConsole::Out(res);
}


扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。



相关文章
|
存储 人工智能 前端开发
全球首个搭载 Kimi-K2 的 Serverless 架构 VibeCoding解决方案重磅来袭!
本文介绍了基于阿里云 Function AI 和 Serverless 架构的 AI 编程解决方案 VibeCoding,展示其如何通过 AI 快速开发并上线小游戏及平台。方案支持普通与专家两种模式,用户可选择不同模型与数据库配置,具备良好的扩展性与交互体验,适合开发者与企业快速实现创意落地。
|
程序员 PHP UED
一直让 PHP 程序员懵逼的同步阻塞异步非阻塞,终于搞明白了
【9月更文挑战第8天】恭喜你掌握了同步阻塞和异步非阻塞的概念,这是许多 PHP 程序员容易困惑的地方。同步阻塞指代码按顺序执行,需等待操作完成;异步非阻塞则允许后台执行操作,不阻塞程序。理解这些概念能显著提升程序性能和用户体验,特别是在高并发场景和分布式系统中。随着技术发展,越来越多的 PHP 框架支持异步编程,掌握这些概念将让你在开发中更得心应手。
258 7
|
8月前
|
IDE 开发工具 git
pycharm如何查看git历史版本变更信息
通过上述步骤,你可以在 PyCharm 中轻松查看 Git 的历史版本变更信息,无论是针对整个项目、特定文件还是分支。使用 PyCharm 的 Git 集成功能,可以更高效地管理和审查代码变更,提高开发过程的透明度和可维护性。
558 19
|
网络协议 Linux
Linux下connect函数 阻塞 与 非阻塞 问题
Linux下connect函数 阻塞 与 非阻塞 问题
818 0
|
分布式计算 安全 大数据
MaxCompute操作报错合集之创建oss外部表时出现了报错:"Semantic analysis exception - external table checking failure, error message:,该怎么办
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
446 1
|
XML JSON 缓存
Java实现根据商品ID请求京东工业商品详情数据方法
Java实现根据商品ID请求京东工业商品详情数据方法
|
机器学习/深度学习 人工智能 算法
【AI】从零构建深度学习框架实践
【5月更文挑战第16天】 本文介绍了从零构建一个轻量级的深度学习框架tinynn,旨在帮助读者理解深度学习的基本组件和框架设计。构建过程包括设计框架架构、实现基本功能、模型定义、反向传播算法、训练和推理过程以及性能优化。文章详细阐述了网络层、张量、损失函数、优化器等组件的抽象和实现,并给出了一个基于MNIST数据集的分类示例,与TensorFlow进行了简单对比。tinynn的源代码可在GitHub上找到,目前支持多种层、损失函数和优化器,适用于学习和实验新算法。
438 2
|
Java
对引用拷贝,浅拷贝,深拷贝的理解
对引用拷贝,浅拷贝,深拷贝的理解
249 0
|
人工智能 决策智能
【AI Agent系列】【阿里AgentScope框架】2. Pipeline模块入门:使用Pipeline模块实现最简单的多智能体交互
【AI Agent系列】【阿里AgentScope框架】2. Pipeline模块入门:使用Pipeline模块实现最简单的多智能体交互
761 0
|
人工智能 自然语言处理 Swift
元象开源70 亿参数通用大模型 XVERSE-7B,全开源、免费可商用,魔搭最佳实践来啦!
元象推出 70 亿参数通用大模型 XVERSE-7B 底座与对话版,保持高性能、全开源、免费可商用,让海量中小企业和 AI 开发者能以低成本用上高性能大模型,并在魔搭社区开源,共同推动中国大模型生态建设。