Выберите самую длинную палку


13

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

Поскольку вы все программисты и любите создавать головоломки, вы превратили «Выбери самую короткую палку» в компьютерную головоломку.

Вот правила головоломки.

  1. Вам будет предоставлена ​​2D-матрица, где каждый столбец представляет палку.
  2. В каждом столбце 1 представляет часть флешки, а 0 - пустое место
  3. При переходе сверху вниз в каждом столбце, изначально у вас есть 0и, как только вы нажмете 1, палка запустилась, и остальная часть столбца будет заполнена 1только
  4. Вы можете написать свою программу, чтобы выбрать один столбец. Размер палки в этом столбце определяет победителя / проигравшего. Размер флешки == количество единиц в этом столбце.
  5. Однако эта программа может иметь только линейную сложность времени наихудшего случая.

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

Ваша работа заключается в:

  • Напишите программу или функцию, которая принимает входные данные в формате 2D или в виде массива строк.
  • Ввод может быть взят из STDIN / prompt / console или аргумента функции.
  • Если вы читаете входные данные из STDIN / приглашения, вы можете предположить, что чтение входных данных и преобразование их в массив занимает 0 раз (хотя код для этого должен присутствовать в вашем ответе)
  • Определите колонку с самой длинной палкой в ​​ней.
  • Выход может быть возвращаемым значением функции или STDOUT / console / alert.
  • Программа / функция должна иметь линейную сложность времени наихудшего случая, O(m+n)где mесть количество строк и nколичество столбцов.

Ввод может быть одним из следующих форматов:

2D массив:

[ [0, 0, 0, 0],
  [1, 0, 0, 0],
  [1, 1, 0, 1],
  [1, 1, 1, 1] ]

Массив строк:

[ "0000", "1000", "1101", "1111" ]

Вход будет иметь следующие свойства:

  • Размер массива неизвестен, допустим прямоугольник любого размера
  • В любом столбце, идущем сверху вниз, если вы видите 1, то все ниже будет одним
  • Пустые-столбцы (т.е. 0-длина) палочки имеют допускается.

Это код-гольф, поэтому выигрывает самый короткий код ! *

Пожалуйста, объясните свой код или дайте неоправданную версию (чтобы проверить сложность времени) вместе с тем, какой из двух форматов ввода вы ожидаете.

ОБНОВЛЕНИЕ Под линейной временной сложностью здесь понимается O (n + m), где n - размер столбца, а m - размер строки. (Для тех, кому было непонятно)

ОБНОВЛЕНИЕ 2 Это определенно может быть сделано за линейное время. И если вы публикуете ответ, не стесняйтесь отложить публикацию логики / алгоритма на пару дней для честной борьбы :)

ОБНОВЛЕНИЕ 3 Я рассмотрю все ответы через пару часов, чтобы проверить сложность времени и программу :)


2
Я бы сказал, что это не может быть сделано в O (n + m), так как каждая ячейка может содержать критическое значение (то есть первую «1» самой длинной палки / столбца). Так что вам нужно посмотреть на каждую ячейку, которая занимает O (n * m).
Фалько

Могут ли быть пустые столбцы?
Мартин Эндер

@ Оптимизатор: О, я вижу. Ты прав. :)
Фалько

11
Это не может быть сделано в O (n + m). После того как входные данные были преобразованы в формат, обеспечивающий произвольный доступ, оставшаяся обработка может быть O (n + m), но вам нужно написать программу, и в худшем случае единственной 1входной информацией является самая последняя ячейка, тогда необходимо прочитать весь ввод. Даже если стандартная библиотека языка подделывает произвольный доступ к стандартному вводу данных, под сценой он буферизует его, и поэтому требуется время Омега (n * m).
Питер Тейлор

2
Если вы хотите позволить людям « просто создать функцию, которая принимает массив », вопрос не должен указывать, что они должны написать программу. И если вам требуются решения, которые находятся в O (N ^ 0,5), где N - это размер входных данных, вам не следует запрашивать решения с линейным временем. Решение с линейным временем может считывать весь ввод.
Питер Тейлор

Ответы:


4

GolfScript, 45 символов

:^,:y;0:x{^y(=x=2%y*{y(:y;x\}{x):x}if^0=,<}do

Принимает входные данные в виде массива строк, возвращает (на основе 0) индекс самого высокого столбца. Он выполняется за O ( строки + столбцы ), и каждая итерация должна занимать по существу постоянное время (по крайней мере, предполагая арифметику с постоянным временем). Единственные операции с массивом / строкой, выполняемые в цикле, - это поиск элементов ( =) и получение длины строки ( ,), которые в GolfScript требуют постоянного времени.

Попробуйте онлайн.

Объяснение:

Как и большинство решений здесь, этот код работает, начиная с левого нижнего угла матрицы, перемещаясь вверх или вправо в зависимости от того, равен ли текущий элемент матрицы 1 или 0, и отслеживая столбец, в котором он последний раз перемещался вверх ,

В начале программы я назначаю входной массив переменной ^, его длина (то есть количество строк) yи 0 x. Значение 0 также остается в стеке; во время следующего цикла он будет заменен индексом самого высокого столбца.

Внутри основного цикла ^y(=x=извлекает x-й символ из y-1-ой строки в ^. Это на самом деле возвращает ASCII-код символа, поэтому 2%необходимо удалить все, кроме последнего бита. В особом случае, если yравно 0 (что может произойти, если самый высокий столбец, найденный до сих пор, достигает самого верхнего ряда), искомый бит будет фактически поступать из последней строки в матрице (индекс -1), но следующее y*заставляет его обнулять, тем самым эффективно создавая виртуальную строку из всех нулей в верхней части матрицы.

Далее ifбудет выполняться один из двух кодовых блоков, предшествующих ему, в зависимости от того, является ли искомый бит ненулевым (true) или нулевым (false). Если не ноль, yуменьшается на единицу, и текущее значение xзаменяет самый высокий индекс столбца в стеке (со старым значением, временно оставленным поверх него). Если ноль, xпросто увеличивается на единицу (и временно остается в стеке, поверх индекса самого высокого столбца).

Наконец, ^0=извлекает первую строку матрицы, ,возвращает ее длину и <сравнивает ее с индексом столбца, временно оставленным в стеке (который будет равен, xесли он был просто увеличен). Если индекс меньше длины строки, цикл повторы.

Ps. Основываясь на моем тестировании, должна быть возможность сократить эту программу на один символ, заменив тест длины строки ,<в конце цикла на >, который обрезает строку по заданному индексу и возвращает конечную часть (которая будет пустой, и таким образом, ложно, в конце цикла). Однако, хотя обрезка строки, подобной этой, кажется реализованной как операция постоянного времени в GolfScript (или, точнее, в Ruby, над которым работает GolfScript), я не нашел никакой официальной документации, подтверждающей это. Просто чтобы быть в безопасности, я выбрал немного более длинную, но определенно O (1), версию выше.


6

Рубин, 83 75 68 66 63 байта

f=->m{m[b=c=i=0].map{(c=i;b-=1)while(r=m[b-2])&&r[i]>0;i+=1};c}

Определяет функцию, fкоторая принимает форму 2D-массива в качестве входных данных.

Я начинаю с левого нижнего края, отслеживая максимальную длину флешки (на самом деле, минус это) и соответствующий столбец. Если в каждом столбце все еще есть 1s, превышающие предыдущую максимальную длину флешки, я подхожу к флешке до конца и запоминаю новую максимальную длину и столбец. Это означает, что я перебираю один раз по столбцам и самое большее один раз по строкам (в частности, я перебираю максимальную длину флешки), что точно O(m+n).


@Optimizer Я не видел ваше второе редактирование до тех пор, пока не опубликовал его, так что оно все равно было в истории редактирования. Вот почему я просто поместил это в спойлер для людей, которые хотят понять это сами.
Мартин Эндер

4

Python 2 - 71, 69, 73, 75 81

j=i=-1
M=input()
for m in M[0]:
 j+=1
 while-i<len(M)and M[i][j]:i-=1;J=j
print J

Это предназначено для запуска в Python 2 или 3? Как должен выглядеть ввод?
feersum

1
@feersum Python 2, массив массивов.
Джастин

@feersum: Quincunx прав. Ввод - это двумерный массив целых, как вы и предлагали.
Фалько,

Не iвыйдет ли за пределы, если палка займет целую колонку?
xnor

1
Извините, но это похоже на изменение jотсчета от 0прерывания условия цикла i*j.
xnor

2

C, 64 байта

Редактировать: я узнал, что вопрос требует расположения самого длинного столбца, а не его длины.

Первая строка - это код для игры в гольф, а остальная часть - это образец вызова.

g(int m,int n,int**a,int*r){for(*r=n;n*m;a[m][n]?m--,*r=n:--n);}

/* usage:
    m = number of rows
    n = number of columns
    a = 1-based 2D array such that a[i][j] gives the value at the ith row and jth column
    r = address of return value 
    Returns (to r) the 1-indexed location of a column with the longest length, or 0 if n=0
    */

int main()
{
    int flat[4*4] = {1, 0, 0, 0,
                     1, 0, 0, 1,
                     1, 1, 0, 1,
                     1, 1, 1, 1};
    int*twoD[4] = {flat-1,flat+3,flat+7,flat+11};
    int ret;
    g(4,4,twoD-1,&ret);
    printf("%d", ret);
    return 0;
}

// old function which determines longest length (65 bytes)
f(int m,int n,int**a,int*r){for(*r=m;n*m;a[m][n]?m--:--n);*r-=m;}

Впечатляет! Можете ли вы intслучайно заглушить s в сигнатуре функции или это не работает из-за указателей там?
Мартин Эндер

1
Входные данные должны содержать только массив. Вы не можете сказать программе о размере массива.
Оптимизатор

Подождите, это на самом деле работает? Похоже, это возвращает длину самой длинной палки, а не ее позицию: ideone.com/YEzqzl
Мартин Эндер

2
@ Оптимизатор, который в принципе невозможен в C.
Мартин Эндер

Может быть, но это вопрос :)
Оптимизатор

2

C #: 236 символов

int p(int[,] a){int y=0,s=0,i=0,x;for(;++y<=a.GetUpperBound(0);)for(x=i;x<=a.GetUpperBound(1);){if(a[y,x++]==0)break;s=y;i++;}return s;}

ungolfed:

int p(int[,] a)
{
    int selectedRow=0;
    int maxLength=0;
    for(var y = 0; y<=a.GetUpperBound(0); y++)
        for(var x=maxLength; x<=a.GetUpperBound(1); x++)
        {
            if(a[y,x++]==0)
                break;
            selectedRow=y;
            maxLength++;
        }
    return selectedRow;
}

2

PHP 5,4 - 108 байт

(113, если вы включите <?php)

Формат ввода: массив будет читаться как строка JSON.

php longest_stick.php "[[0, 0, 0, 0],[1, 0, 0, 0],[1, 1, 0, 1],[1, 1, 1, 1]]"

Добавлены пробелы для удобства чтения - все символы новой строки и начальные пробелы могут быть удалены.

<?php
$t=count($s=json_decode($argv[1]))-1;
foreach($s[0] as $k=>$_)
    while($s[$t][$k]) {
        $t--;
        $l = $k;
    }
echo $l?:0;

Минимизированная версия:

<?php $t=count($s=json_decode($argv[1]))-1;foreach($s[0] as $k=>$_)while($s[$t][$k]){$t--;$l=$k;}echo $l?:0;

В некотором смысле здесь можно украсть алгоритм у Мартина, но приятно поиграться с языками, которые не так часто встречаются здесь. XD


@ MartinBüttner Я «украл» ваш алгоритм, поэтому теперь он должен быть O (n + m). Я думаю, что это правильно XD
Niet the Dark Absol

Вы можете заменить $s=json_decode($argv[1]);$t=count($s)-1;на $t=count($s=json_decode($argv[1]))-1;(-3 байта).
Blackhole

@ Blackhole Действительно, вы можете. Спасибо!
Niet the Dark Absol

@ Blackhole Я думаю, что это нарушит функциональность. Он выполнит назначения, даже если условие не выполнено.
Niet the Dark Absol

@ Blackhole все еще ломает это, я боюсь, что XD $t--должен произойти, только если условие выполнено.
Niet the Dark Absol

2

Кобра - 98

def f(a)
    s,x,y=0,0,a.count-1
    while y+1and x<a[0].count
        while a[y][x],y,s=y-1,x
        x+=1
    print s

2

C ++ :: 78

В отличие от другого решения C, это целая программа. (не требуется вызова, нет необходимости сообщать функции размер массива). К сожалению, это означает, что оно длиннее, чем mainдолжно быть использовано вместо имени односимвольной функции, я должен интерпретировать ввод и затем вывести ответ, где другое решение обрабатывает это «в другом месте». Также мой первый код гольф.
скомпилировано g++ file.cpp -include iostream, работает с ./a 000 010 110 111(например) == массивом строк (я полагаю, что это разрешено в спецификации вопроса)

int c;main(int r,char**v){for(r--;r*v[r][c];v[r][c]-48?std::cout<<c,r--:++c);}

Приведенная выше версия выводит текущее значение, наилучшее найденное на каждой итерации Окончательная выходная цифра - это ответ. Переход от обработки снизу слева вместо нижнего правого и 0индексация сократили это решение на 10 (!) Символов.
переключение на c ++ прекращает отправку еще на один символ, так как std::cout<<оно короче, putchar(-48)и оно также должно явно поддерживать более 9 стиков с правильным выводом (хотя это может затруднить дифференцирование каждого вывода).
Удаление поля ответа и его вывод напрямую сокращают еще 6 символов. Теперь он выводит ток наилучшим образом только тогда, когда он движется вверх, что, по крайней мере, отключает какой-либо выход.
Весь файл теперь имеет размер всего 78 байт, что приближает решение к функции только по сравнению с другимCпредставление использует. (с большим количеством дополнительного кода для поддержки указанной функции).

Как показано ниже, описание устарело:

cявляется глобальным, поэтому инициализируется с 0
rпомощью: количество входов (строк) +1 (имя программы)
v- массив строк с v[0]недопустимыми (имя программы).
Поскольку индекс 0, rон выходит за пределы, поэтому уменьшается.
Хотя r!=0(указывая на действительную строку) и символ cв строке не является нулевым терминатором, '\0'
если символ не равен 0,
поднимитесь на строку ( r) и выведите столбец ( c),
иначе перейдите к следующему столбцу (c )

сделано

Могу ли я даже играть в гольф дальше?

Неуправляемый код (с дополнительным выводом):

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
  int rows = argc-1;
  int cols = strlen(argv[1]);
  int ans;

  printf("rows: %d, cols: %d\n",rows, cols);

  while((rows)&&cols)
  {
    if (argv[rows][cols-1]-'0')
    {
      printf("stick @%d,%d\n",cols,rows);
      ans = cols;
      rows--;
    }
    else
    {
      printf("no stick @%d,%d\n",cols,rows);
      cols--;
    }
  }
  printf("%d",ans);
}
Он использует длину строк, чтобы узнать количество столбцов, и argc, чтобы найти количество строк. Начиная с нижнего правого угла, следуйте этим простым правилам: если ячейка - это палка, то двигайтесь вверх, установите ответ для текущего столбца. Если ячейка не является палкой, то двигайтесь влево. O (n + m): поскольку он только перемещается вверх и влево, он может иметь только максимальное n + m прочтений. Он выходит рано, если падает сверху или слева от массива.


1

OCaml - 144 символа

let s a=Array.(let rec f i j m=if i=0then m else if a.(i).(j)=0then if j=length a.(i)-1then m else f i(j+1)m else f(i-1)j j in f(length a-1)0 0)

Принимает в int array arrayкачестве входных данных и начинает снизу слева, двигаясь вверх или вправо, если видит a 1или a 0. Количество столбцов начинается с 0.

использование

 s [| [| 0; 0; 0; 0 |]; [| 0; 0; 1; 0|]; [| 1; 0; 1; 0 |]; [| 1; 1; 1; 0 |]; [| 1; 1; 1; 1 |] |];;
 - : int = 2

Ungolfed

let s a = Array.(
  let rec f i j m = (* m is the longest stick seen so far *)
    if i=0 then m (* A column is full: this is the longest possible stick and j=m anyway *)
    else if a.(i).(j)=0 then (* current column is shorter than a previously seen stick *)
      if j=length a.(i)-1 then m (* we have examined all columns, just return m *)
      else f i(j+1) m (* start examining next column *)
    else f (i-1) j j (* current column is longer than all the ones previously seen. Check how long the stick is *)
  in
  f (length a-1) 0 0)

0

T-SQL - 71 64

Принимает таблицу A в качестве входных данных

SELECT IDENTITY(INT, 1, 1) R, A INTO A
FROM (VALUES
 ('0000')
,('1000')
,('1101')
,('1111')
) AS A(A)

И запрос

SELECT TOP(1)CHARINDEX('1',A)FROM A WHERE A LIKE'%1%' ORDER BY R

SQLFiddle

Это возвращает первую строку из таблицы a, упорядоченную по r, где есть 1 в строке a.

TOP(1) ограничивает результат первой возвращенной строкой.

CHARINDEX('1',A) возвращает позицию первой 1 в строке или ноль, если она не найдена.

WHERE A LIKE'%1%' фильтрует строки, где A содержит 1

ORDER BY R обеспечивает чтение таблицы сверху вниз


Можете ли вы объяснить, что происходит в этом коде? : D Нет опыта работы с T-SQL
Оптимизатор

Я так понимаю, не является ли фильтрация в каждой части строки операцией O (n * m)? т.е. не линейная сложность времени.
Оптимизатор

Сложно сказать. Движок SQL проверит все строки на 1 в столбце. Он вернет только первый ряд сверху вниз, который соответствует требованиям. Так что в этой ситуации он сканирует всю таблицу. Фильтрует строки со столбцом, содержащим 1. Сортирует результаты по столбцу идентификаторов и возвращает первый результат.
MickyT

Посмотрите на это так: что если ваши строки похожи на «0000», «0000», «0000», «0001». В этом случае ему придется идти до последней строки и до последнего символа строки, чтобы выяснить наличие 1
Optimizer

1
Так что да, тогда это O (m * n) :)
Оптимизатор

0

Delphi 122 символа

Вздох ... это такой объемный язык.

Обновление: пришлось добавить 6 символов в функцию изменения типа возврата от I до целого числа. Функция все еще скомпилирована, поскольку у тестовой программы было «type I = integer;» заявление осталось от более ранней версии программы.

function S(A:array of string):integer;var n,c:integer;begin n:=0; repeat c:=Pos('1',A[n]);inc(n) until c>0; result:=c;end;

Вы выполняете вызов Pos () для каждой строки (в вашем случае, строки) массива?
Оптимизатор

@Optimiser Да, программа ищет каждую строку в массиве (используя «inc (n)»), пока не найдет «1». Первая найденная цифра «1» будет самой высокой (или равной самой высокой) «1», поэтому ее позиция в строке (строки с 1-индексированием в delphi) будет позицией самого длинного столбца. Рутина завершается ошибкой, если в массиве нет единиц, но я считаю, что это будет неверный ввод, поскольку тогда не будет «самой длинной палки».
Пингвино

1
Итак, во-первых, это верный вход: "0000", "0010", "1111"во-вторых, ваш ответ не соответствует требованию линейной сложности времени
Оптимизатор,

@Optimizer Да, это будет корректный ввод и правильно идентифицирует 3-й стик. Но после публикации сообщения я понял, что преобразовал свою действительную программу N-го порядка, в которой использовались массивы, в программу N ^ 2 недопустимого порядка, в которой использовались строки (в погоне за сокращением от ~ 160 символов).
Penguino

0

схема - 236 символов

Даже дольше, чем версия Delphi ... возможно, есть способ сделать это гораздо более эффективно с помощью схемы. И что еще хуже - я просто заметил, что это порядок m * n.

(define (s l) (cond ((eq? (cdr l) '()) (car l)) (else (map + (car l) (s (cdr l)))))) (define (u l) (define (t n p q l) (cond ((eq? l '()) p) ((< n (car l)) (t (car l) q (+ 1 q) (cdr l))) (else (t n p (+ 1 q) (cdr l))))) (t 0 0 1 (s l)))

l является списком вида '((0 0 0 0) (1 0 0 0) (1 1 0 1) (1 1 1 1)). Я думаю, что это правильное представление входных данных двумерного массива для схемы.

(sl) суммирует n-тые элементы каждого из подсписков списка списков числителей, поэтому (s '((0 0 0 0) (1 0 0 0) (1 1 0 1) (1 1) 1 1))) вернется (3 2 1 2).

(ul) возвращает «индекс» самой большой записи в списке чисел (используя вспомогательную функцию t), поэтому (u '(3 2 1 2)) вернет 1 (как самый большой элемент «3 в списке») (3 2 1 2) находится в положении 1).


Суммирование всех подсписков является операцией O (m * n).
Мартин Эндер

0

Ракетка 70

Golfed:

(define(h m)(for/last([r m]#:final(memv 1 r))(length(takef r even?))))

Предполагается, что input - это двумерный массив, который в Racket будет списком списков:

(define m 
  '((0 0 0 0)
    (1 0 0 0)
    (1 1 0 1)
    (1 1 1 1)))

Ungolfed:

(define (h m)
  ;; step through rows, stopping at the first that contains a 1
  (for/last ([r m] #:final (memv 1 r)) 
    (length (takef r even?)))) ; pop off the leading zeroes to get the column index

Возвращает индекс столбца с самой длинной палкой.


Таким образом, в основном вы просматриваете каждый столбец и подсчитываете число 1?
Оптимизатор

Я понимаю вашу точку зрения. Алгоритм обновлен.
Мэтью Батерик,

Это все еще имеет сложность O (m * n) в худшем случае (для случая, когда нет 1в матрице или только в нижней строке).
Мартин Эндер

0

JavaScript, ES6, 76 символов

W=a=>(j=>{for(k=i=a.length-1;~i&~j;)a[i][j]?(k=j,i--):j--})(a[0].length-1)|k

Принимает массив ввода массива.


0

JavaScript ES6, 65 байт

Принимает оба формата ввода

f=(a,t)=>a.reduceRight((p,c)=>t+1?t:(x=c.indexOf(1,p))+1?x:t=p,0)

Разъяснение:

Итерирует снизу вверх. Использует String.prototype.indexOf()или Array.prototype.indexOf()зависит от ввода каждого значения. Находит первый индекс каждой строки с 1 из предыдущего смещения, если он не находит ни одного, то устанавливает tпеременную на последнее смещение и больше не выполняет indexOfвызовов.


indexOfработает в любом O(log n)или O(n), так что общий алгоритм никогда не будетO(m + n)
Оптимизатор

@ Оптимизатор Да, понял, что это его (м * н) не думал прямо.
Джордж Райт

@Optimizer Обновлено, чтобы бытьO(m+n)
Джордж Райт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.