Виберіть найдовшу паличку


13

Ви молодий видовище програмування, який живе з вашими двома іншими найкращими друзями. Щотижня один з вас повинен виконувати всі справи в будинку, і ви вирішуєте, чия черга, вибравши палицю. Той, хто вибирає найкоротшу паличку, втрачає і виконує всі справи.

Оскільки ви всі програмісти і любите створювати пазли, ви змінили "Виберіть найкоротший паличку" в комп'ютерну головоломку.

Ось правила головоломки.

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

Оскільки ви всі програмісти, ви дізнаєтесь, чи чужа програма знімає межу складності часу.

Ваше завдання:

  • Напишіть програму або функцію, яка приймає вхід у двовимірному форматі або масиві рядків.
  • Введення можна взяти з STDIN / prompt / console або аргументу функції.
  • Якщо ви читаєте вхід з STDIN / prompt, тоді ви можете припустити, що зчитування введення та перетворення його в масив займає 0 разів (хоча код для цього повинен бути у вашій відповіді)
  • Визначте стовпчик з найдовшою паличкою в ньому.
  • Вихідним може бути повернене значення функції або STDOUT / консоль / попередження.
  • Програма / функція повинна мати лінійну найгіршу часову складність, 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).
Фалько

Чи можуть бути порожні стовпці?
Мартін Ендер

@Optimizer: О, бачу. Ти маєш рацію. :)
Фалько

11
Це неможливо зробити в O (n + m). Після того як вхід перетворений у формат, який дозволяє випадковий доступ, тоді обробка, що залишилася, може бути O (n + m), але вам потрібно написати програму, і в гіршому випадку, що єдиним 1у вході є остання комірка необхідно прочитати весь вхід. Навіть якщо стандартна бібліотека мови факсує випадковий доступ до stdin, під сценами він буферизує її, і тому час, що витрачається, становить Omega (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буде виконано один із двох блоків коду, що передували йому, залежно від того, чи є розглянутий біт не нульовим (істинним) або нульовим (хибним). Якщо він не дорівнює нулю, yзменшується на одиницю, і поточне значення xзамінює найвищий індекс стовпця на стеку (при цьому старе значення тимчасово залишається вгорі). Якщо нуль, xпросто збільшується на одиницю (і тимчасово залишається на стеці, вгорі найвищого індексу стовпця).

Нарешті, ^0=витягує перший рядок матриці, ,повертає її довжину та <порівнює її з індексом стовпців, тимчасово залишеним на стеку (що буде рівним, xякщо він був лише збільшений) Якщо індекс менший за довжину рядка, цикл повторюється.

Пс. На основі мого тестування, слід скоротити цю програму на один символ, замінивши тест довжини рядка ,<в кінці циклу на >, який обрізає рядок на заданий індекс і повертає кінцеву частину (яка буде порожньою, і таким чином помилковим, в кінці петлі). Однак, вирізаючи такий рядок, як видається, реалізується як операція постійного часу в 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

Пітон 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 має рацію. Введення - це двовимірний масив ints, як ви запропонували.
Фалько

Не 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
@Optimizer, що в принципі неможливо в 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;}

неозорений:

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 паличок з належним висновком (хоча може бути важче розмежувати кожен вихід)
. Тепер він видає найкращий струм лише тоді, коли він рухається вгору, що прирізає принаймні деякий вихід.
Весь файл розміром має лише 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

Безумовно

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

Приймає таблицю А як вхідний

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

Це повертає перший рядок із таблиці впорядкованому по r, де є рядок 1.

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
оптимізатора

1
Так що так, це O (m * n), то :)
Оптимізатор

0

Delphi 122 символів

Зітхніть ... це така об’ємна мова.

Оновлення: довелося додати 6 символів при зміні функції типу повернення з I на ціле число. Функція все ще компілюється, оскільки тестова програма мала "тип I = ціле число;" заява, що залишилася від попередньої версії програми.

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-ndexed у delphi) буде позицією найдовшого стовпця. Рутинна помилка, якщо в масиві немає «1», але я вважаю, що це було б несправним введенням, оскільки тоді не було б «найдовшої палички», яку не можна було б знайти.
Penguino

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)). Я думаю, що це справедливе представлення 2D-масиву для схеми.

(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

Гольф:

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

Припускає, що вхід - це двовимірний масив, який у Ракетці буде списком списків:

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

Безголівки:

(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

Повертає індекс стовпця з найдовшою палицею.


Отже, ви в основному переглядаєте кожен стовпець і підраховуєте кількість 1s?
Оптимізатор

Я бачу вашу думку. Алгоритм оновлений.
Метью Баттерк

Це все ще має найгірший випадок складності 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) не думав прямо.
Джордж Рейт

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