Двоичный поиск, чтобы решить "Kth самый маленький элемент в отсортированной матрице". Как можно обеспечить правильность алгоритма,

Я имею в виду вопрос о Leetcode: Kth самый маленький элемент в отсортированной матрице

Есть два известных решения этой проблемы. Один использует Heap/PriorityQueue, а другой использует бинарный поиск. Решение для бинарного поиска выглядит следующим образом ( верхняя запись):

public class Solution {
public int kthSmallest(int[][] matrix, int k) {
    int lo = matrix[0][0], hi = matrix[matrix.length - 1][matrix[0].length - 1] + 1;//[lo, hi)
    while(lo < hi) {
        int mid = lo + (hi - lo) / 2;
        int count = 0,  j = matrix[0].length - 1;
        for(int i = 0; i < matrix.length; i++) {
            while(j >= 0 && matrix[i][j] > mid) j--;
            count += (j + 1);
        }
        if(count < k) lo = mid + 1;
        else hi = mid;
    }
    return lo;
}
}

Хотя я понимаю, как это работает, у меня есть проблемы с выяснением одной проблемы. Как мы можем быть уверены, что вернулись lo всегда в матрице?

Так как пространство поиска min а также max значение массива, mid НЕ ДОЛЖНО быть значением, которое находится в массиве. Тем не менее, вернулся lo всегда есть.

Почему это происходит?

1 ответ

Потому что мы находим нижнюю границу с помощью двоичного поиска, и в массиве не может быть никакого числа меньше числа (lo), которое могло бы быть k-м наименьшим элементом.

Ради аргумента, мы можем переместить расчет count в отдельную функцию, такую ​​как следующее:

bool valid(int mid, int[][] matrix, int k) {
    int count = 0, m = matrix.length;
    for (int i = 0; i < m; i++) {
        int j = 0;
        while (j < m && matrix[i][j] <= mid) j++;
        count += j;
    }
    return (count < k);
}

Этот предикат будет делать то же самое, что и указанная вами операция. Здесь инвариант цикла заключается в том, что диапазон [lo, hi] всегда содержит kth наименьшее число двумерного массива.

Другими словами, lo <= solution <= hi

Теперь, когда цикл заканчивается, очевидно, что lo >= hi

Объединяя эти два свойства, мы получаем, lo = solution = hi, поскольку solution является членом массива, можно сказать, что lo всегда находится в массиве после завершения цикла и будет правильно указывать на kth самый маленький элемент.

Другие вопросы по тегам