【问题标题】:Is there a binary search algorithm that takes a unary predicate rather than a search value?是否存在采用一元谓词而不是搜索值的二进制搜索算法?
【发布时间】:2021-11-18 15:33:11
【问题描述】:

我有这个练习:

给定一个整数数组,在线性时间和常数空间中找到第一个丢失的正整数。换句话说,找到数组中不存在的最小正整数。该数组也可以包含重复数和负数。
例如,输入[3, 4, -1, 1] 应为2,输入[1, 2, 0] 应为3
您可以就地修改输入数组。

 
我的实现:

template <typename In_It>
int missingPositiveInt(In_It first, In_It last){
    first = std::find_if( first, last, [](int x){return x > 0;} );
    if(first == last || *first > 1)
        return 1;
    for( auto next = first; (++next != last) && ( !(*next - *first > 1) ); )
        ++first;

    return *first + 1;
}

int main(){

    std::vector<int> v{5, 2, -1, 7, 0};
    std::sort(v.begin(), v.end());
    std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';

    v = {2, -1, 1, 0};
    std::sort(v.begin(), v.end());
    std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';

    v = {5, 2, -1, 7, 0};
    std::sort(v.begin(), v.end());
    std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';

    v = {3, 4, -1, 1};
    std::sort(v.begin(), v.end());
    std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';

    v = {1, 2, 0};
    std::sort(v.begin(), v.end());
    std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';

    std::cout << '\n';
}

输出:

1
3
1
2
3

该程序运行良好,但我使用算法 std::find_if 来查找序列(排序序列)中的第一个正值,并且该算法进行线性搜索。

  • 只要输入序列已经排序,我想使用一些二进制搜索算法来加快处理速度。

  • 我尝试使用std::binary_search,但它需要搜索参数。我需要的是获得一个版本,它采用一元谓词并应用二进制搜索或任何其他更快的算法来找到序列中的最低正值,以便我可以编写:

    auto it = binary_search(first, last, [](int x){ return x > 0; });
    

有可能吗?我的代码是好的还是我需要修改它。因此,非常感谢任何建议和提示。

【问题讨论】:

  • 线性时间?但是单独排序需要的不仅仅是线性时间,不是吗?
  • 库中应该有一个二进制搜索算法,您可以使用一元谓词调用它,但没有。但是,即使有,也不会让你在这里达到线性时间。
  • @numzero 问题中的代码是的,但是整数数组可以在线性时间内排序
  • std::binary_search 只返回一个布尔值,而不是迭代器。 std::lower_bound(first, last, 1) 可能就是您要找的。​​span>
  • 这不是“二分查找”问题。您会注意到没有一个示例数组是排序的。二分查找仅适用于排序数组。这个编码难题的正确解决方案与任何二进制搜索无关。这是一个棘手的问题,只要你花点时间从逻辑上思考一下手头的任务,答案就应该很明显了。

标签: c++ binary-search


【解决方案1】:

是的,std::partition_point 完全符合您的要求。

【讨论】:

    【解决方案2】:

    基于@numzero 的答案的部分解决方案。这不处理数组中的负数或零,但您可以通过线性预处理数组以预先删除它们来处理它。它只是通过否定每个索引将其标记为“已找到”,然后查找第一个非负值,这就是那个。尽管它是部分解决方案,但它显示了核心算法。

    #include <iostream>
    using namespace std;
    
    int main() {
        
        int arr[] = {1, 4, 6, 7, 2, 7, 7, 8, 3};
        
        int arrSize = sizeof(arr)/sizeof(int);
        
        for(int i=0; i<arrSize; ++i)
        {
            int val = abs(arr[i]);
            if(val > 0 && val-1 < arrSize)
            {
                if (arr[val-1]>0)
                {
                    arr[val-1] = -arr[val-1];
                }
            }
        }
        
        for(int i=0; i<arrSize; ++i)
        {
            if(arr[i] > 0)
            {
                std::cout << "Smallest is " << (i+1) << std::endl;
                return 0;
            }
        }
        
        std::cout << "Nothing found!" << std::endl;
        
        // your code goes here
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2022-10-02
      • 2011-02-19
      • 1970-01-01
      • 2014-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-23
      • 1970-01-01
      相关资源
      最近更新 更多