#c #binary-search
Вопрос:
У меня есть это упражнение:
Учитывая массив целых чисел, найдите первое пропущенное положительное целое число в линейном времени и постоянном пространстве. Другими словами, найдите наименьшее положительное целое число, которого нет в массиве. Массив также может содержать дубликаты и отрицательные числа.
Например, ввод[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) amp;amp; ( !(*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; });
Возможно ли это? Мой код в порядке, или мне нужно его изменить. Поэтому любое предложение, подсказка высоко ценятся.
Комментарии:
1. Линейное время? Но сама по себе сортировка занимает больше, чем линейное время, не так ли?
2. В библиотеке должен быть алгоритм двоичного поиска, который вы можете вызвать с помощью унарного предиката, но его нет. Но даже если бы это было так, это не приведет вас к линейному времени здесь.
3. @numzero с кодом в вопросе да, но массив целых чисел можно отсортировать за линейное время
4.
std::binary_search
просто возвращает bool, а не итератор.std::lower_bound(first, last, 1)
возможно, это то, что вы ищете в своем случае.5. Это не проблема «двоичного поиска». Вы заметите, что ни один из примеров массивов не отсортирован. Двоичный поиск работает только с отсортированными массивами . Правильное решение этой головоломки кодирования не будет иметь никакого отношения к любому двоичному поиску. Это вопрос с подвохом, и ответ должен быть очень очевидным, как только вы уделите время, чтобы логически продумать поставленную задачу.
Ответ №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 amp;amp; 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;
}