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

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

本文涉及的基础知识点

二分查找算法合集

题目

Winston 构造了一个如上所示的函数 func 。他有一个整数数组 arr 和一个整数 target ,他想找到让 |func(arr, l, r) - target| 最小的 l 和 r 。

请你返回 |func(arr, l, r) - target| 的最小值

请注意, func 的输入参数 l 和 r 需要满足 0 <= l, r < arr.length 。

示例 1:

输入:arr = [9,12,3,7,15], target = 5

输出:2

解释:所有可能的 [l,r] 数对包括 [[0,0],[1,1],[2,2],[3,3],[4,4],[0,1],[1,2],[2,3],[3,4],[0,2],[1,3],[2,4],[0,3],[1,4],[0,4]], Winston 得到的相应结果为 [9,12,3,7,15,8,0,3,7,0,0,3,0,0,0] 。最接近 5 的值是 7 和 3,所以最小差值为 2 。

示例 2:

输入:arr = [1000000,1000000,1000000], target = 1

输出:999999

解释:Winston 输入函数的所有可能 [l,r] 数对得到的函数值都为 1000000 ,所以最小差值为 999999 。

示例 3:

输入:arr = [1,2,4,8,16], target = 0

输出:0

参数范围

1 <= arr.length <= 10^5

1 <= arr[i] <= 10^6

0 <= target <= 10^7

方法一超时

按二进制的位讨论

对任意一个二进制位,从左到右,出现第一个0之前是1,之后是0。我们用vIndexs记录各二进制位0的索引。

两层循环,第一层循环枚举起始l,第二层循环枚举各位。只需要考虑有二进位第一个变成0的位。

时间复杂度

O(nlogmax(logn+logm)) 约O(3e7) 处于超时边缘。

核心代码

class Solution {
public:
  int closestToTarget(vector<int>& arr, int target) {
    m_c = arr.size();
    const int iBitNum = 21;
    vector<vector<int>> vIndexs(iBitNum);
    for (int i = 0; i < m_c; i++)
    {
      for (int j = 0; j < iBitNum; j++)
      {
        if (arr[i] & (1 << j))
        {
          continue;
        }
        vIndexs[j].emplace_back(i);
      }
    }
    int iRet = INT_MAX;
    for (int l = 0; l < m_c; l++)
    {
      set<int> setIndexs ;
      for (int j = 0; j < iBitNum; j++)
      {
        auto it = std::lower_bound(vIndexs[j].begin(), vIndexs[j].end(), l);
        if (vIndexs[j].end() != it)
        {
          setIndexs.emplace(*it);
        }
      }
      vector<int> vValue = { arr[l] };
      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;
};

测试用例

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()
{
  vector<int> arr;
  int target;
  int res;
  {
    Solution slu;   
    arr = { 9, 12, 3, 7, 15 };
    int target = 5;
    res = slu.closestToTarget(arr, target);
     Assert(2, res);
  }
  {
    Solution slu;
    arr = { 1000000,1000000,1000000 };
    int target =1;
    res = slu.closestToTarget(arr, target);
    Assert(999999, res);
  }
  {
    Solution slu;
    arr = { 1,2,4,8,16 };
    int target = 0;
    res = slu.closestToTarget(arr, target);
    Assert(0, res);
  }
  //CConsole::Out(res);
}


相关文章
|
18天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
29天前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
43 6
|
27天前
|
机器学习/深度学习 人工智能 算法
【MM2024】面向 StableDiffusion 的多目标图像编辑算法 VICTORIA
阿里云人工智能平台 PAI 团队与华南理工大学合作在国际多媒体顶级会议 ACM MM2024 上发表 VICTORIA 算法,这是一种面向 StableDiffusion 的多目标图像编辑算法。VICTORIA 通过文本依存关系来修正图像编辑过程中的交叉注意力图,从而确保关系对象的一致性,支持用户通过修改描述性提示一次性编辑多个目标。
|
27天前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
316 0
高精度算法(加、减、乘、除,使用c++实现)
|
29天前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
21 0
C++ 多线程之线程管理函数
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
23 3
|
1月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
124 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
25 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
37 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
25天前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
20 0