C++二分算法:找到最接近目标值的函数值(二)

简介: C++二分算法:找到最接近目标值的函数值

方法二:超时

分析

从右向左枚举左边缘,setIndexs 记录各位为0的最小索引,vPre记录本位的上一个索引方便删除。

时间复杂度

O(nlogmax(loglogmax)+nlogmax)

核心代码

class Solution {
public:
  int closestToTarget(vector<int>& arr, int target) {
    m_c = arr.size();
    const int iBitNum = 21;
    vector<int> vPre(iBitNum, -1);
    multiset<int> setIndexs;
    int iRet = INT_MAX;
    for (int left = m_c - 1; left >= 0; left--)
    {
      for (int iBit = 0; iBit < iBitNum; iBit++)
      {
        if (arr[left] & (1 << iBit))
        {
          continue;
        }
        if (-1 != vPre[iBit])
        {
          setIndexs.erase(setIndexs.find(vPre[iBit]));
        }
        setIndexs.emplace(left);
        vPre[iBit] = left;
      }
      vector<int> vValue = { arr[left] };
      for (const auto& index : setIndexs)
      {
        vValue.emplace_back(vValue.back() & arr[index]);
      }
      for (const auto& value : vValue)
      {
        iRet = min(iRet, abs(value - target));
      }
    }
    return iRet;
  }
  int m_c;
};

方法三:

分析

func(arr,l,r)等于arr[l]&func(arr,l+1,r)。

令iMax=max(nums[i]) ,func(arr,l,x) x取值范围[l,n) 最多只有log(iMax)种可能。nums[i]最多有log(iMax)个二进制位为1,and只会将1变成0,不会将0变成1。所以1只会不断减少,最坏的情况下,每次减少一个1,共减少log(iMax)次。

时间复杂度

O(nlogmaxloglogmax)。稳定能过。

class Solution {
public:
  int closestToTarget(vector<int>& arr, int target) {
    m_c = arr.size(); 
    set<int> setPre = { arr.back() };
    int iRet = abs(arr.back() - target);
    for (int left = m_c - 1-1; left >= 0; left--)
    {
      set<int> dp = { arr[left] };
      for (const auto& pr : setPre)
      {
        dp.emplace(pr & arr[left]);
      }
      setPre.swap(dp);
      for (const auto& pr : setPre)
      {
        iRet = min(iRet, abs(pr - target));
      }
    }
    return iRet;
  }
  int m_c;
};

方法四

分析

dp本来就是降序,所有用向量也可以判断是否重复,换成向量速度再次提升。理论上速度可以提升几倍,实际提升50%左右。

时间复杂度

O(nlogmax)。

class Solution {
public:
  int closestToTarget(vector<int>& arr, int target) {
    m_c = arr.size(); 
    vector<int> vPre = { arr.back() };
    int iRet = abs(arr.back() - target);
    for (int left = m_c - 1-1; left >= 0; left--)
    {
      vector<int> dp = { arr[left] };
      for (const auto& pr : vPre)
      {
        const int iNew = pr & arr[left];
        if (dp.back() != iNew)
        {
          dp.emplace_back(iNew);
        }
      }
      vPre.swap(dp);
      for (const auto& pr : vPre)
      {
        iRet = min(iRet, abs(pr - target));
      }
    }
    return iRet;
  }
  int m_c;
};

2023年3月第一版

class Solution {
public:
int closestToTarget(vector& arr, int target) {
std::set pre;
std::priority_queue queNear;
for (const auto& a : arr)
{
std::set dp;
for (const auto& pr : pre)
{
dp.insert(pr&a);
queNear.push(abs((pr&a)-target));
if (queNear.size() > 1)
{
queNear.pop();
}
}
dp.insert(a);
queNear.push(abs(a-target));
if (queNear.size() > 1)
{
queNear.pop();
}
pre.swap(dp);
}
return queNear.top();
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
墨子曰:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
相关文章
|
6天前
|
算法 数据中心 C++
基于C++雪花算法工具类Snowflake -来自chatGPT
基于C++雪花算法工具类Snowflake -来自chatGPT
9 1
|
11天前
|
算法 数据处理 C++
C++一分钟之-迭代器与算法
【6月更文挑战第21天】C++ STL的迭代器统一了容器元素访问,分为多种类型,如输入、输出、前向、双向和随机访问。迭代器使用时需留意失效和类型匹配。STL算法如查找、排序、复制要求特定类型的迭代器,注意容器兼容性和返回值处理。适配器和算法组合增强灵活性,但过度使用可能降低代码可读性。掌握迭代器和算法能提升编程效率和代码质量。
24 3
|
12天前
|
C++ 容器
【C++】拷贝构造函数、拷贝赋值函数与析构函数
【C++】拷贝构造函数、拷贝赋值函数与析构函数
65 6
|
8天前
|
编译器 程序员 语音技术
C++的超20种函数类型分享
C++超20种函数类型:编程语言规定规则,编译器实现预定规则
|
8天前
|
C++
C++函数的返回数据写法的思路
C++函数使用尾置返回类型、decltype、类型别名返回一个数组引用
|
9天前
|
关系型数据库 MySQL 测试技术
技术分享:深入C++时间操作函数的应用与实践
技术分享:深入C++时间操作函数的应用与实践
13 1
|
13天前
|
算法 Java C语言
Java中的算法与C语言中的函数
Java中的算法与C语言中的函数
11 2
|
3天前
|
编译器 C++
【C++】类和对象③(类的默认成员函数:赋值运算符重载)
在C++中,运算符重载允许为用户定义的类型扩展运算符功能,但不能创建新运算符如`operator@`。重载的运算符必须至少有一个类类型参数,且不能改变内置类型运算符的含义。`.*::sizeof?`不可重载。赋值运算符`=`通常作为成员函数重载,确保封装性,如`Date`类的`operator==`。赋值运算符应返回引用并检查自我赋值。当未显式重载时,编译器提供默认实现,但这可能不足以处理资源管理。拷贝构造和赋值运算符在对象复制中有不同用途,需根据类需求定制实现。正确实现它们对避免数据错误和内存问题至关重要。接下来将探讨更多操作符重载和默认成员函数。
|
4天前
|
程序员 编译器 C++
探索C++语言宝库:解锁基础知识与实用技能(类型变量+条件循环+函数模块+OOP+异常处理)
探索C++语言宝库:解锁基础知识与实用技能(类型变量+条件循环+函数模块+OOP+异常处理)
8 0
|
4天前
|
算法 vr&ar
技术好文共享:遗传算法解决函数优化
技术好文共享:遗传算法解决函数优化