Дана матрица NxN с 0 и 1. Установите каждую строку, содержащую a 0
для всех 0
s, и установите каждый столбец, содержащий a, 0
для всех 0
s.
Например
1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1
1 1 1 1 1
результаты в
0 0 0 0 0
0 0 0 0 0
0 0 1 1 0
0 0 0 0 0
0 0 1 1 0
Инженер Microsoft сказал мне, что есть решение, которое не требует дополнительной памяти, только две логические переменные и один проход, поэтому я ищу этот ответ.
Кстати, представьте, что это битовая матрица, поэтому в матрице допускается только 1 и 0.
algorithm
optimization
puzzle
jaircazarin-старый счет
источник
источник
Ответы:
Итак, я устал, так как сейчас 3 часа утра, но у меня есть первая попытка на месте с ровно 2 проходами на каждое число в матрице, поэтому в O (NxN) он линейный по размеру матрицы.
Я использую 1-й столбец и первую строку в качестве маркеров, чтобы знать, где строки / столбцы только с 1. Затем есть 2 переменные l и c, которые нужно запомнить, если 1-я строка / столбец тоже все 1. Таким образом, первый проход устанавливает маркеры и сбрасывает остальные на 0.
Второй проход устанавливает 1 в местах, где строки и столбцы отмечены как 1, и сбрасывает 1-ю строку / столбец в зависимости от l и c.
Я сильно сомневаюсь, что я могу сделать за 1 проход, так как квадраты в начале зависят от квадратов в конце. Может быть, мой второй проход можно сделать более эффективным ...
источник
Это невозможно сделать за один проход, поскольку один бит влияет на биты до и после него в любом порядке. IOW. В каком бы порядке вы ни проходили массив, позже вы можете пересечь 0, что означает, что вы должны вернуться назад и изменить предыдущее 1 на 0.
Обновить
Люди, кажется, думают, что, ограничив N некоторым фиксированным значением (скажем, 8), вы можете решить, что это один проход. Ну, это а) упущение и б) не оригинальный вопрос. Я бы не стал публиковать вопрос о сортировке и ожидать ответа, который начинался бы "предполагая, что вы хотите отсортировать только 8 вещей ...".
Тем не менее, это разумный подход, если вы знаете, что N на самом деле ограничен до 8. Мой ответ выше отвечает на оригинальный вопрос, который не имеет такого отступления.
источник
Поэтому моя идея состоит в том, чтобы использовать значения в последней строке / столбце в качестве флага, чтобы указать, все ли значения в соответствующем столбце / строке равны 1.
Использование зигзагообразного сканирования по всей матрице за исключением последней строки / столбца. Для каждого элемента вы устанавливаете значение в последней строке / столбце как логическое И для самого себя со значением в текущем элементе. Другими словами, если вы нажмете 0, последняя строка / столбец будет установлена на 0. Если вы это 1, значение в последней строке / столбце будет 1, только если он уже был 1. В любом случае установите текущий элемент на 0.
Когда вы закончите, ваша последняя строка / столбец будет иметь 1 с, если соответствующий столбец / строка была заполнена 1 с.
Выполните линейное сканирование последней строки и столбца и найдите 1 с. Установите 1 в соответствующих элементах в теле матрицы, где последняя строка и столбец равны 1.
Кодировать его будет непросто, чтобы избежать случайных ошибок и т. Д., Но это должно сработать за один проход.
источник
У меня есть решение, оно выполняется за один проход и выполняет всю обработку «на месте» без дополнительной памяти (за исключением увеличения стека).
Он использует рекурсию, чтобы задержать запись нулей, что, конечно, разрушит матрицу для других строк и столбцов:
источник
Я не думаю, что это выполнимо. Когда вы находитесь на первом квадрате и его значение равно 1, у вас нет возможности узнать, каковы значения других квадратов в той же строке и столбце. Таким образом, вы должны проверить их, и если есть ноль, вернитесь к первому квадрату и измените его значение на ноль. Я рекомендую сделать это в два прохода - первый проход собирает информацию о том, какие строки и столбцы должны быть обнулены (информация хранится в массиве, поэтому мы используем некоторую дополнительную память). Второй проход меняет значения. Я знаю, что это не то решение, которое вы ищете, но я думаю, что это практическое решение. Заданные вами ограничения делают проблему неразрешимой.
источник
Я могу сделать это с двумя целочисленными переменными и двумя проходами (до 32 строк и столбцов ...)
источник
~
инвертирует все биты в переменной. 0x00000000 становится 0x00000000. Я в основном начинаю со всех и очищаю бит для строки / столбца, когда нахожу 0. CompleteCols имеет установленные биты 2 и 3, а CompleteRows имеет установленные биты 2 и 4 (на основе 0).проблема может быть решена за один проход
сохранение матрицы в массиве i X j.
теперь выведите все значения как 0 для значений i и j, сохраненных в a и b, остальные значения равны 1, т. е. (3,3) (3,4) (5,3) и (5,4)
источник
Другое решение, которое занимает два прохода, заключается в накоплении AND по горизонтали и вертикали:
Я думал, что смогу разработать такой алгоритм, используя биты четности , коды Хемминга или динамическое программирование , возможно, используя эти два логических значения в качестве 2-битного числа, но я пока не добился успеха.
Не могли бы вы еще раз проверить формулировку проблемы у своего инженера и сообщить нам? Если это действительно решение, я хочу , чтобы откалывать прочь на проблему.
источник
Сохраняйте единственную переменную, чтобы отслеживать, каковы все строки ANDed вместе.
Если строка равна -1 (все 1 с), то сделайте следующую строку ссылкой на эту переменную
Если строка ничего, но это 0. Это можно сделать за один проход. Псевдопользователей-код:
Это должно быть сделано за один проход - но здесь есть предположение, что N достаточно мало, чтобы процессор выполнял арифметику в одной строке, в противном случае вам нужно будет перебрать каждую строку, чтобы определить, все ли это 1с или нет, я верю. Но, учитывая, что вы спрашиваете об алгоритмах и не ограничиваете мое оборудование, я бы просто начал свой ответ с «Создание процессора, который поддерживает N-битную арифметику ...»
Вот один пример того, как это можно сделать на C. Примечание. Я утверждаю, что значения и arr, взятые вместе, представляют массив, а p и numproduct - это мои итераторы и переменные продукта AND, используемые для реализации проблемы. (Я мог зациклить arr с арифметикой указателя, чтобы проверить мою работу, но одного раза было достаточно!)
Это дает 0, 0, 6, 0, 6, что является результатом для заданных входов.
Или в PHP, если люди думают, что мои стековые игры в C обманывают (я полагаю, что это не так, потому что я должен иметь возможность хранить матрицу в любом удобном для меня виде):
Я что-то упускаю?
источник
Хороший вызов. Это решение использует только два логических значения, созданных в стеке, но логические значения создаются несколько раз в стеке, поскольку функция является рекурсивной.
Это сканирует по схеме, как:
и так далее
И затем изменение значений в этом шаблоне при возврате в каждую из функций сканирования. (Вверх дном):
и так далее
источник
Хорошо, это решение, которое
источник
Фактически. Если вы просто хотите запустить алгоритм и распечатать результаты (т.е. не восстанавливать их, то это легко сделать за один проход. Проблема возникает, когда вы пытаетесь изменить массив во время работы алгоритма.
Вот мое решение. Оно просто включает в себя значения строк и столбцов AND для элемента givein (i, j) и распечатывает их.
источник
Я пытался решить эту проблему в C #.
Я использовал две переменные цикла (i и j) отдельно от фактической матрицы и n, представляющих ее размерность
Логика, которую я попробовал, заключается в следующем:
Код:
источник
Один проход - я обошел ввод только один раз, но использовал новый массив и только две дополнительные логические переменные.
источник
Хотя это и невозможно, учитывая ограничения, наиболее эффективный способ сделать это - обойти матрицу в виде чередующейся чередующейся строки / столбца, что сделает шаблон похожим на укладку кирпичей зигзагообразным способом:
Используя это, вы будете входить в каждую строку / столбец, как указано, и, если в любой момент вы встретите 0, установите логическую переменную и повторно пройдете эту строку / столбец, установив для записей значение 0 по мере продвижения.
Это не потребует дополнительной памяти и будет использовать только одну логическую переменную. К сожалению, если для «дальнего» края задано все 0, это наихудший случай, и вы дважды пройдете весь массив.
источник
создайте матрицу результатов и установите все значения на 1. Пройдите матрицу данных, как только встретите 0, установите столбец строки матрицы результатов на 0
В конце первого прохода матрица результатов будет иметь правильный ответ.
Выглядит довольно просто. Есть ли уловка, которую я пропускаю? Вам не разрешено использовать набор результатов?
РЕДАКТИРОВАТЬ:
Выглядит как функция F #, но это немного обманывает, так как даже если вы делаете один проход, функция может быть рекурсивной.
Похоже, что интервьюер пытается выяснить, знаете ли вы функциональное программирование.
источник
Ну, я придумал однопроходное, нерекурсивное решение на месте, используя 4 bools и 2 счетчика цикла. Мне не удалось сократить его до 2 bools и 2 ints, но я не удивлюсь, если бы это было возможно. Это делает приблизительно 3 чтения и 3 записи каждой ячейки, и это должно быть O (N ^ 2) т.е. линейный по размеру массива.
Мне потребовалось пару часов, чтобы разобраться в этом - я не хотел бы придумывать это под давлением интервью! Если я сделал буфу, я слишком устал, чтобы заметить это ...
Хм ... Я выбираю определение "однопроходного", чтобы сделать один проход по матрице, а не касаться каждого значения один раз! :-)
источник
Я надеюсь, вам понравится мое 1-проходное решение C #
вы можете получить элемент с помощью O (1) и вам понадобится только место в одну строку и один столбец матрицы
источник
1 проход, 2 логических значения. Я просто должен предположить, что целочисленные индексы в итерациях не учитываются.
Это не полное решение, но я не могу пройти этот пункт.
Если бы я мог только определить, является ли 0 исходным 0 или 1, который был преобразован в 0, я бы не использовал -1, и это работало бы.
Мой вывод такой:
Оригинальность моего подхода заключается в использовании первой половины проверки строки или столбца, чтобы определить, содержит ли она 0, а в последней половине - для установки значений - это делается путем просмотра x и width-x, а затем y и высоты -у в каждой итерации. Основываясь на результатах первой половины итерации, если в строке или столбце был найден 0, я использую последнюю половину итерации, чтобы изменить 1 на -1.
Я только что понял, что это можно сделать только с одним логическим значением, оставляя 1 для ...?
Я публикую это в надежде, что кто-то скажет: «А, просто сделай это ...» (И я потратил слишком много времени на это, чтобы не писать.)
Вот код в VB:
источник
Никто не использует бинарные формы? так как это только 1 и 0. Мы можем использовать двоичные векторы.
Вот тест:
И вывод:
источник
Вы можете сделать что-то вроде этого, чтобы использовать один проход, но матрицу ввода и вывода:
где
col(xy)
биты в столбце, содержащем точкуxy
;row(xy)
это биты в строке, содержащей точкуxy
.n
это размер матрицы.Затем просто зациклите ввод. Возможно расширяемый, чтобы быть более экономичным?
источник
Одно матричное сканирование, два логических значения, без рекурсии.
Как избежать второго прохода? Второй проход необходим для очистки строк или столбцов, когда на их конце появляется ноль.
Однако эту проблему можно решить, потому что, когда мы сканируем строку #i, мы уже знаем статус строки для строки # i-1. Таким образом, пока мы сканируем строку #i, мы можем одновременно очистить строку # i-1, если это необходимо.
То же решение работает для столбцов, но нам нужно сканировать строки и столбцы одновременно, пока данные не изменятся при следующей итерации.
Два логических значения требуются для хранения состояния первой строки и первого столбца, поскольку их значения будут изменены во время выполнения основной части алгоритма.
Чтобы не добавлять больше логических значений, мы храним флаг «очистить» для строк и столбцов в первой строке и столбце матрицы.
источник
Кажется, что следующие работы без дополнительных требований к пространству:
Прежде всего обратите внимание, что умножение элементов строки на элементы строки, в которой находится элемент, дает желаемое значение.
Чтобы не использовать дополнительное пространство (не создавая новую матрицу и не заполняя ее, а вместо этого применяя изменения непосредственно к матрице), начните с левого верхнего угла матрицы и выполните вычисления для любой матрицы ixi (которая «начинается» в (0 , 0)) перед рассмотрением любого элемента с любым индексом> i.
надеюсь, что это работает (не тестет)
источник
Это ИСПЫТАНО для разных N в C ++, и это:
ОДИН ПРОХОД , ДВЕ БУЛЫ , НЕТ РЕКУРСИИ , НЕТ ДОПОЛНИТЕЛЬНОЙ ПАМЯТИ , ХОЛДОВ ДЛЯ АРБИТРАЛЬНО БОЛЬШИХ N
(Пока ни одно из решений здесь не делает ВСЕ из них.)
Точнее говоря, я забавно, что два счетчика цикла в порядке. У меня есть два константных знака без знака, которые только существуют, а не вычисляются каждый раз для удобства чтения. Интервал внешнего цикла равен [0, N], а интервал внутреннего цикла равен [1, n - 1]. Оператор switch в цикле в основном существует, чтобы очень четко показать, что на самом деле это всего лишь один проход.
Алгоритм Стратегия:
Первый трюк заключается в том, что нам нужно собрать строку и столбец из самой матрицы, чтобы накапливать содержимое матрицы, эта память становится доступной, выгружая все, что нам действительно нужно знать из первой строки и столбца, в два логических значения. Второй трюк состоит в том, чтобы получить два прохода из одного, используя симметрию подматрицы и ее индексов.
Алгоритм Сводка:
Шаблонная реализация C ++:
источник
Хорошо, я понимаю, что это не совсем совпадает, но я получил его за один проход, используя bool и байт вместо двух bools ... close. Я также не ручаюсь за его эффективность, но такие вопросы часто требуют неоптимальных решений.
источник
Вы можете сделать это за один проход - если вы не учитываете доступ к матрице в порядке произвольного доступа, что исключает преимущества выполнения этого за один проход в первую очередь (кэш-согласованность / пропускная способность памяти).
[править: простое, но неправильное решение удалено]
Вы должны получить лучшую производительность, чем любой однопроходный метод, выполнив это за два прохода: один для накопления информации о строке / столбце и один для его применения. Доступ к массиву (в порядке следования строк) связан; для массивов, превышающих размер кэша (но строки которых могут помещаться в кэш), данные должны быть прочитаны из памяти дважды и сохранены один раз:
источник
Самое простое решение, которое я могу придумать, приведено ниже. Логика заключается в том, чтобы записать, какую строку и столбец установить на ноль во время итерации.
источник
Вот моя реализация Ruby с включенным тестом. Это заняло бы пространство O (MN). Если нам нужно обновление в реальном времени (например, показ результатов, когда мы находим нули, а не ожидание первого цикла нахождения нулей), мы можем просто создать другую переменную класса, такую как
@output
и всякий раз, когда мы находим ноль, мы обновляем@output
и нет@input
.источник
Код ниже создает матрицу размером m, n. Сначала определитесь с размерами матрицы. Я хотел заполнить матрицу [m] [n] случайным образом числами от 0,10. Затем создайте другую матрицу с такими же размерами и заполните ее -1 с (конечная матрица). Затем выполните итерацию по исходной матрице, чтобы увидеть, достигнете ли вы 0. Когда вы нажмете на местоположение (x, y), перейдите к финальной матрице и заполните строку x 0 и столбец y 0. В конце прочитайте окончательную матрицу, если значение равно -1 (исходное значение), скопируйте значение в том же месте исходной матрицы в конечную.
источник
вот мое решение. Как вы можете видеть из кода, учитывая матрицу M * N, он устанавливает всю строку в ноль, как только проверяет ноль в этой строке. Временная сложность моего решения - O (M * N). Я делюсь всем классом, который имеет статический заполненный массив для тестирования и метод отображения, чтобы увидеть результат в консоли.
}
источник