Найдите строку, представляющую наименьшее целое число в отсортированной по строке матрице - PullRequest
65 голосов
/ 29 ноября 2010

Мне задали этот вопрос в недавнем интервью по телефону на Java:

Вам предоставляется двоичная (0-1) матрица NxN со следующими свойствами:

  • Каждая строка сортируется (последовательность из 0 следует за последовательностью из 1)
  • Каждая строка представляет целое число без знака (путем чтения битов)
  • Каждый ряд уникален

Пример:

0 1 1
1 1 1
0 0 1

Значения битов в каждой строке сортируются, и строки представляют целые числа 3, 7 и 1.

Найдите строку, представляющую наименьшее целое число. В приведенном выше примере ответом является строка 3, представляющая целое число 1.

Я начал с грубой силы квадратичной сложности. Интервьюер ответил, что я не эксплуатирую отсортированное имущество.

После долгих раздумий я использовал бинарный поиск в каждой строке, и он пришел к O (nlogn). Он спросил, могу ли я улучшить еще дальше. Я много думал, но не смог улучшить.

Буду признателен, если кто-нибудь подскажет, как его улучшить.

Другой пример:

0 1 1 1
0 0 0 1
0 0 0 0
1 1 1 1

Ответом будет строка 3, представляющая целое число 0.

Ответы [ 14 ]

101 голосов
/ 29 ноября 2010

Начните со строки 1. Идите направо, пока не нажмете первую 1. Затем спуститесь в строку 2, но оставайтесь в том же столбце и повторяйте процесс, пока вы не нажмете 1. Делайте это неоднократно. Строка, в которой вы в последний раз сделали правильный шаг, является вашим ответом.

Это решение O (N + M) (для матрицы NxM или O (N) для квадратной матрицы NxN, как указано в вопросе).

Используя ваш пример:

0 1 1 1
0 0 0 1
0 0 0 0
1 1 1 1

Здесь . представляют пройденный путь:

. . 1 1
0 . . .
0 0 0 . . Last right step, therefore this is our answer
1 1 1 1 .

Это решение работает с неквадратными матрицами, сохраняя эффективность O (N + M) в наихудшем случае для матрицы NxM.

Почему это работает? Гарантия того, что числа будут отсортированы, означает, что каждая строка будет серией 0, а затем последовательностью 1. Таким образом, величина строки эквивалентна тому, как далеко вы можете пройти вправо, прежде чем нажать 1. Поэтому, если строка когда-либо может продвинуть вас дальше, просто следуя 0, то она должна быть длиннее, чем все, что мы обрабатывали ранее.

Код Python:

li = [[0, 1, 1, 1],
      [0, 0, 0, 1],
      [0, 0, 0, 0],
      [1, 1, 1, 1]]

ans, j = 0, 0
for i, row in enumerate(li):
  while j < len(row) and row[j] == 0:
    j += 1
    ans = i

print "Row", ans+1, "".join(map(str, li[ans]))

Существует также более простое решение, из-за ограничений всегда иметь квадратную матрицу NxN и отдельные строки вместе. Вместе они означают, что строка с наименьшим значением будет либо 0 0 ... 0 1, либо 0 0 ... 0 0. Это связано с тем, что в матрице представлено N из N + 1 возможных чисел, поэтому «пропущенное» число равно либо 0 (в этом случае наименьшее представленное значение равно 1), либо другому (наименьшее значение равно 0).

Обладая этим знанием, мы проверяем столбец, второй справа, на 0. Когда мы находим один, мы смотрим вправо, и если в нем содержится еще 0, у нас есть ответ (может быть только одна строка, оканчивающаяся на 0). В противном случае мы продолжаем искать в столбце еще один 0. Если мы не найдем еще 0, первой найденной будет строка, которую мы ищем (может быть только одна строка, заканчивающаяся на 01, и поскольку ни один, заканчивающийся на 00, это самое маленькое).

Код Python:

li = [[0, 1, 1, 1],
      [0, 0, 0, 1],
      [0, 0, 0, 0],
      [1, 1, 1, 1]]

for i, row in enumerate(li):
  if row[-2] == 0:
    ans = i
    if row[-1] == 0:
      break

print "Row", ans+1, "".join(map(str, li[ans]))

Это решение отвечает на вопрос с наименьшими трудностями в O (N), но обобщение его для обработки неквадратных матриц NxM или нечетных чисел приведет к эффективности в худшем случае O (N ^ 2). Я лично предпочитаю первое решение.

50 голосов
/ 29 ноября 2010

наименьшее число должно быть 0 или 1. (потому что нет дубликатов и строки отсортированы). все, что вам нужно сделать, это перейти к последнему столбцу, если ti содержит 0, наименьшее число равно 0, а наименьшее число равно 1.

РЕДАКТИРОВАТЬ - объяснение
В N строках с указанным ограничением может быть максимум N+1 уникальных значений.
так что наверняка по крайней мере 0 или 1 должны быть в матрице ....

Редактировать 2 - алгоритм

//assuming the matrix is 0 indexed base
for i = 0...N-1
  if M[i][N-1] == 0
    return "Value is 0 in row i";
for i = 0...N-1
  if M[i][N-2] == 0
    return "Value is 1 in row i";
//because of the explanation above the flow will never reach here.
41 голосов
/ 29 ноября 2010

Поскольку числа уникальны, а цифры отсортированы, совершенно ясно, что для любого значения N наименьшее число может иметь форму [0 (N-1 раз), затем 1] или 0 (N раз).

Например, для N = 4 наименьшее число может быть 0001 или 0000.

Другими словами, вторая последняя цифрачисла, которое мы хотим найти равным 0. И последняя цифра может быть 0 или 1

Эта проблема сводится к простому нахождению этих шаблонов в массиве, что можно сделать с помощьюпростой цикл

int rowNum = -1;

for(int i=0;i<N;i++)
{
    if(arr[i][N-2]==0) //Second last digit is 0. Hence the number could be min.
    {
        rowNum = i;

        if(arr[i][N-1]==1) // If number of the form 0001 was found, keep looking for 0000
        {
            continue;
        }
        else
         //If number of the form 0000 was found, exit. 
         //No other number can be lesser than 0000
        {
            break;
        }
    }
}
return rowNum;

Этот алгоритм будет иметь сложность O (n)

24 голосов
/ 29 ноября 2010

Вы хотите найти строки с максимальным количеством нулей.

  • Начало в arr[0][0]
  • Если это 0, проверьте элемент в направлении Право этого, arr[0][1].
  • Если это не 0, пропустите эту строку и начать проверку на элементе в следующая строка ниже текущего элемента.

Продолжайте, пока не пройдете последний ряд / последний столбец или не найдете строку со всеми нулями.

Алгоритм:

i = 0 
j = 0 
answer = 0 

# continue till i is a valid index.
while(i<N) 

        # continue till j is valid index and ele is 0.
        while(j < N AND arr[i][j] == 0)

                # move towards right.
                j++ 

                #update answer.
                answer = i 

                # found a row with all zeros.
                if(j == N)  
                        break all loops.
                end-if

        end-while

        # skip current row..continue on next row.    
        i++ 

end-while

print answer

Сложность этого O(N+N), то есть O(N), то есть линейная.

Реализация Java

Смежный вопрос Который использует точно такой же трюк

Как эффективно искать в упорядоченной матрице?

3 голосов
/ 29 ноября 2010
Start at the top-left.

The first row is the best row so far.

Repeat until you reach the bottom:
  If you're not already over a 1:
    Go right until you find a 1.
    This row is the best row so far.
  Go down one row.

Report the best row that was found.

Вы никогда не идете вверх или влево - вы только понижаетесь (n-1) раз и вправо не более (n-1) раз, делая это O (n).Это использует сортировку, понимая, что вам никогда не нужно идти влево, чтобы проверить 1 - если где-то слева есть 1, то в текущем месте также есть 1 (и, таким образом, число в этой строке, по крайней мереразмером с предыдущую строку).

3 голосов
/ 29 ноября 2010

Поскольку биты в каждой строке отсортированы, после того как вы нашли 1 бит, все биты справа также должны быть равны 1. Другими словами, в массиве хранятся только значения вида 2 ^ n-1.

Таким образом, ответ - строка с наибольшим количеством нулевых записей - наименьшая.

Однако, поскольку могут присутствовать только 2 ** m-1 записи, и их n, и нет двух одинаковых, мы можем вывести больше - для любого N существует N + 1 таких значений. Поэтому должны присутствовать либо 0, либо 1, поскольку мы знаем, что дубликатов нет.

Так что ищите пустую строку (которая только одна с крайним правым столбцом ноль). Если вы не нашли его, ответ - 1, иначе - 0.

O (N)

2 голосов
/ 29 ноября 2010

Как насчет зацикливания каждой строки в обратном порядке и проверки, где заканчиваются 1 с и начинаются нули?

Фактически гарантируется, что в NxN в худшем случае 0 не будет,Таким образом, вы можете просто проверить последние 2 записи в каждой строке.Что делает его линейным.

Так как мое объяснение не было понято, здесь оно находится в несколько псевдокоде:

int lowestRow = -1;
for (k = 0; k < array.length; k ++) {
   byte[] row = array[k];
   if (row[row.length - 1] == 0) {
       lowestRow = k;
       break;
   }
   if (row[row.length - 2] == 0) {
       lowestRow = k;
       //possibly look for all-zeroes, so not breaking
   }
}
1 голос
/ 10 декабря 2010

Наименьшее число может быть 0, которое выглядит как (0000 ... 0000) или 1, которое выглядит как (0000 ... 0001).

Каждое большее число выглядит как (xxxx ... xx11),Таким образом, вы должны проверить следующую за последней цифрой в каждой строке.Если это 0, тогда проверьте, является ли последняя цифра 0. Если это - это самое маленькое число.Если нет, то запомните номер строки и продолжайте искать строку с 0 рядом с последней цифрой.Если вы найдете его, это будет наименьшее число.Если нет, первое найденное число является наименьшим.

Это решение с N + 1 шагом (наихудший сценарий), что составляет O (N) сложность.

1 голос
/ 29 ноября 2010

Я бы добавил это как комментарий к ответу Джереми, если бы мог, потому что его решение в основном правильное.Также мне нравится подход.Во многих случаях это будет НАМНОГО быстрее, чем другие ответы.Возможная проблемаЕсли «Каждая строка отсортирована».не означает, что все сдвинуты вправо, но имеет некоторые другие последствия (я могу вспомнить пару последствий. Мне нужно больше от человека, задающего вопрос)Одна проблема ... как насчет 0011 и 0010. Сортировка строк может означать, что реализуемый вами алгоритм уже используется.Алгоритм, указанный в его ответе, не может различить два.Я бы сохранил индекс обоих ответов в массиве.Если длина массива равна 1, то у вас есть решение, в противном случае вам нужно вернуться к следующему ... просто мысль.Если кто-то читает это и может публиковать комментарии к другим сообщениям, пожалуйста, укажите это в комментарии к своему сообщению.Это серьезная проблема, и было бы неприятно иметь технически неверный ответ, чтобы получить чек.Если мой комментарий будет добавлен, я полностью удалю свой ответ.

1 голос
/ 29 ноября 2010

Найти, какая строка имеет первое ненулевое значение в самом дальнем столбце. Если это двоичное, с MSB слева и LSB справа, ответом является строка, которая начинается с большинства нулей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...