Offer Sword Finger Offer】 —— Сводная таблица примеров, связанных с бинарным поиском

Во-первых, минимальное значение вращающегося массива

Требования к теме:

Переместите первые несколько элементов массива в конец массива, мы называем это вращением массива.
Введите поворот неубывающего отсортированного массива и выведите наименьший элемент повернутого массива.
Например, массив {3,4,5,1,2} является поворотом {1,2,3,4,5}, а минимальное значение массива равно 1.
ПРИМЕЧАНИЕ. Все приведенные элементы больше 0, если размер массива равен 0, верните 0.

Анализ темы:

Прежде всего, мы можем прояснить, что массив
после вращения массива вращения действительно может быть разделен на два отсортированных подмассива, а элементы переднего подмассива больше или равны элементам заднего подмассива,
поэтому мы можем следовать этому Пришло время изучить ответы на вопросы. Мы все еще анализируем в простой и понятной форме на конкретных примерах.

Случай 1:
массив {3, 4, 5, 1, 2} используется в качестве столбца. Сначала определите два указателя, чтобы указать на первый элемент и последний элемент массива. Заштрихованная часть является вторым подмассивом.
Вставьте описание изображения здесь
Рассчитайте индекс среднего элемента в это время = (0 + 4) / 2 = 2. Значение элемента массива с индексом 2 равно 5. Поскольку 5> число 3, на которое указывает p1, среднее значение находится в первом подмассиве . Укажите p1 на среднее число.
Вставьте описание изображения здесь
В это время число 1 в середине p1 и p2 меньше, чем число, указанное p2. Число в середине находится во втором подмассиве. Укажите p2 на среднее число.
Вставьте описание изображения здесь
В это время p1 и p2 указывают на два соседних числа , затем
p2
указывает на наименьшее число в массиве .
Почему p2 наименьшее число?
Потому что, когда два указателя находятся на расстоянии только одной позиции, это указывает, что p1 уже указывал на последний элемент первого возрастающего массива, а p2 указывал на первый элемент второго возрастающего массива. Так что p2 указывает на самый маленький элемент в массиве.

Случай 2:
при возникновении ситуации, когда p1, p2 и число, на которое указывает средний указатель, совпадают, например, массив {0,1,1,1,1}. {1,0,1,1,1} и {1,1,1,0,1} - это вращение инкрементного массива,
Вставьте описание изображения здесь
как показано на рисунке выше. В этом случае неясно, к какому инкрементному массиву относится средний элемент Таким образом, вы должны пойти по пути последовательного поиска.

Случай 3:
если первые 0 элементов отсортированного массива перемещаются до конца, то есть самого массива, это все равно вращение массива.
В этом случае просто верните элемент, на который указывает p1. Вот почему indexMid назначен на p1.

Реализация кода

int MinInOrder(int* numbers, int p1, int p2)
{
    int result = numbers[p1];
    for (int i = p1 + 1; i <= p2; i++)
    {
        if (result > numbers[i])
            result = numbers[i];
    }
    return result;
}
int Min(int* numbers, int length)
{
	if (numbers == nullptr || length <= 0)
		throw new::std::exception("Invalid parameters");

	int p1 = 0;
	int p2 = length - 1;
	int indexmid = p1;
	while (numbers[p1] >= numbers[p2])
	{
		//情况一
		if (p2 - p1 == 1)
		{
			indexmid = p2;
			break;
		}
		indexmid = (p1 + p2) / 2;

		//情况二
		if (numbers[p1] == numbers[p2] == numbers[indexmid])
		{
			return MinInOrder(numbers, p1, p2);
		}
		//缩小范围
		if (numbers[indexmid] >= numbers[p1])
			p1 = indexmid;
		else if(numbers[indexmid] <= numbers[p2])
			p2 = indexmid;
	}
	return numbers[indexmid];
}

Во-вторых, найти номер в отсортированном массиве

Тема 1: Сколько раз число появляется в отсортированном массиве

Подсчитайте, сколько раз число появляется в отсортированном массиве. Например, введите отсортированный массив {1,2,3,3,3,3,4,5} и число 3, поскольку в этом массиве 3 раза встречается 3, поэтому выведите 4.

Анализ:
поскольку массив упорядочен, мы, естественно, думаем об использовании бинарного поиска. Предпочтительно использовать двоичный поиск, чтобы найти 3, а затем последовательно сканировать слева и справа от 3, чтобы найти первые 3 и последние 3 соответственно.

Найдите первые 3 в массиве:
число 3 было найдено на основе бинарного поиска выше, но не ясно, является ли это 3 первыми 3 в массиве. Поэтому мы должны судить о числе до 3.
Вставьте описание изображения здесь
Если X на рисунке, если X не 3, то первые 3 массива - это тот, который только что был найден 3.
Если X на рисунке 3, то первый 3 Должно быть в первой половине массива, нам все еще нужно искать в первой половине массива в следующем раунде.
Код реализован следующим образом:

int GetFirstK(int* data, int length, int k, int start, int end)
{
    if (start > end)
        return -1;
    int mid = (start + end) / 2;
    int middleData = data[mid];

    if (middleData == k)
    {
        if ((mid > 0 && data[mid - 1] != k) || mid == 0)
            return mid;
        else
            end = mid - 1;
    }
    else if (middleData > k)
    {
        end = mid - 1;
    }
    else
    start = mid + 1;
    return GetFirstK(data, length, k, start, end);
}

Not found 3 возвращает -1, найденные первые 3 в массиве возвращают свой индекс

Найти последние 3 в массиве:
метод поиска последних 3 аналогичен приведенному выше, код, написанный на основе рекурсии, выглядит следующим образом:

int GetLastK(int* data, int length, int k, int start, int end)
{
    if (start > end)
        return -1;
    int mid = (start + end) / 2;
    int middleData = data[mid];
    if (middleData == k)
    {
        if ((mid < length-1 && data[mid + 1] != k) || mid == length-1)
            return mid;
        else
            start = mid + 1;
    }
    else if (middleData < k)
    {
        start = mid + 1;
    }
    else
      end = mid - 1;
    return GetLastK(data, length, k, start, end);
}

После нахождения индексов первых 3 и последних 3 в массиве можно вычислить количество вхождений в массиве. Код выглядит следующим образом:

int GetNumberOfK(int* data, int length, int k)
{
    int count = 0;
    if (data != nullptr && length > 0)
    {
        int first = GetFirstK(data, length, k, 0, length - 1);
        int last = GetLastK(data, length, k, 0, length - 1);

        if (first > -1 && last > -1)
            count = last - first + 1;
    }
    return count;
}

Тема 2: Пропавшие цифры в 0 ~ n-1

Все числа в возрастающем массиве длины n-1 уникальны, и каждое число находится в диапазоне 0 ~ n-1, и в числе n есть только одно число в диапазоне, которых нет в массиве Пожалуйста, узнайте этот номер

Анализ проблемы:
Метод 1:
Сначала мы можем вычислить сумму всех чисел от 0 до n-1 как s1, а затем вычислить сумму всех чисел в массиве как s2, а разница между s1-s2 составляет 0 ~ n-1. Недостающее число в.
Но этот метод не годится, поскольку приведенное в вопросе правило увеличения массива не используется, а его временная сложность составляет O (n).

Способ 2:
Мы можем использовать идею бинарного поиска для решения,
потому что эти числа 0 ~ n-1 отсортированы в массиве, поэтому начало этих чисел совпадает с индексом массива, предполагая, что число m является отсутствующим числом в массиве, Тогда число после m и нижний индекс не являются соответствующими отношениями,
Вставьте описание изображения здесь
поэтому эта проблема преобразуется в поиск первого элемента в отсортированном массиве, который не равен нижнему индексу

1. Если значение среднего элемента и нижний индекс равны, то нужно искать только правую часть в следующем раунде
2. Если значение среднего элемента и нижний индекс не равны

  1. И элемент перед ним не равен его нижнему индексу, то этот элемент является отсутствующим элементом
  2. И элемент перед ним не равен его нижнему индексу, что означает, что нам нужно искать только справа для следующего раунда поиска

Таким образом, реализация кода выглядит следующим образом:

int GetMissingNumbers(const int* numbers, int length)
{
    if (numbers == nullptr || length <= 0)
        return -1;

    int left = 0;
    int right = length - 1;
    
    while (left <= right)
    {
        int mid = (left + length) / 2;
        if (numbers[mid] != mid)
        {
            if (numbers[mid - 1] == mid - 1 || mid == 0)
                return mid;
            else
                right = mid - 1;
        }
        else
            left = mid + 1;
    }
    //缺失的是最后一个数字
    if (left == length)
        return length;

    return -1;
}

Тема 3: Элементы с равными значениями и индексами в массиве

Предположим, что каждый элемент в монотонно увеличивающемся массиве является целым числом и уникален. Пожалуйста, запрограммируйте функцию, чтобы найти любой элемент в массиве, значение которого равно его нижнему индексу. Например, в массиве {-3, -1, 1, 3, 5} число 3 равно его нижнему индексу.

Анализ проблемы: по-
прежнему в полной мере использовать закон увеличения массивов, предполагая, что значение i-го числа больше, чем индекс i, тогда числа справа от него больше, чем соответствующий индекс. Следующий раунд поиска требует только поиск номера слева от нее.
Если предположить, что значение i-го числа меньше, чем индекс i, то числа слева от него будут меньше соответствующего редактора. Следующий раунд поиска нужно искать только среди чисел справа от нее.
Основываясь на приведенном выше утверждении, код реализован следующим образом:

int GetNumberSameAsIndex( int* numbers, int length)
{
    if (numbers == nullptr || length <= 0)
        return -1;

    int left = 0;
    int right = length - 1;

    while (left <= right)
    {
        int mid = (right - left ) / 2 + left;
        if (numbers[mid] = mid)
            return mid;
        if (numbers[mid] < mid)
            left = mid + 1;
        else
            right = mid + 1;
    }
    return -1;
}
Опубликовано 98 оригинальные статьи · вона похвала 9 · просмотров 3654

рекомендация

отblog.csdn.net/qq_43412060/article/details/105338437