最長のスティックを選ぶ


13

あなたは他の2人の親友と一緒に住んでいる若いプログラミングオタクです。毎週、あなたの一人が家のすべての雑用をしなければなりません、そして、あなたは棒を選ぶことによってそれが誰の番であるかを決定します。最も短い棒を選んだ人は、すべての雑用を失い、します。

皆さんはプログラマーであり、パズルを作成するのが大好きなので、「最短のスティックを選ぶ」をコンピューターパズルに変更しました。

ここにパズルのルールがあります。

  1. 各列が棒を表す2Dマトリックスが表示されます。
  2. 各列の1はスティックの一部を表し、0は空のスペースを表します
  3. 各列の上から下に移動すると、最初にがあり、を押す0とすぐ1にスティックが開始され、列の残りの部分がいっぱいになります1だけ
  4. 1つの列を選択するプログラムを作成できます。その列のスティックのサイズが勝者/敗者を決定します。スティックのサイズ==その列の1の数。
  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が表示された場合、以下のすべてが1つになります。
  • 空の列(長さ0)のスティック許可されます。

これはコードゴルフなので、最短のコードが勝ちますます!*

コードを説明するか、予期しない2つの入力形式のいずれかとともに、(時間の複雑さを確認するために)未使用バージョンを提供してください。

ここでの更新の線形時間の複雑さは、nが列サイズでmが行サイズであるO(n + m)を意味します。(不明瞭な人向け)

更新2 これは間違いなく線形時間で実行できます。また、回答を投稿する場合は、公正な戦いのためにロジック/アルゴリズムの投稿を数日遅らせてください。

更新3時間の複雑さとプログラムを検証するために、数時間ですべての回答を確認します:)


2
各セルに重要な値(つまり、最長のスティック/列の最初の「1」)を含めることができるため、O(n + m)でこれを行うことはできないと主張します。したがって、O(n * m)をとる各セルを調べる必要があります。
ファルコ14

空の列がありますか?
マーティンエンダー14

@Optimizer:なるほど。あなたが正しい。:)
ファルコ14

11
それはできません O(N + M)で行われます。入力がランダムアクセスを許可する形式に変換されると、残りの処理はO(n + m)になりますが、プログラムを作成する必要があります。最悪の場合1、入力の最後のセルだけが入力全体を読み取る必要があります。言語の標準ライブラリがstdinへのランダムアクセスを偽装している場合でも、シーンではそれがバッファリングされるため、かかる時間はOmega(n * m)です。
ピーターテイラー14

2
配列を受け入れる関数を単純に作成する」ことを人々に許可したい場合、質問は彼らがプログラムを書かなければならないと述べるべきではありません。また、O(N ^ 0.5)の解が必要な場合(Nは入力のサイズ)、線形時間解を求めるべきではありません。線形時間ソリューションは、入力全体を読み取ることができます。
ピーターテイラー14

回答:


4

GolfScript、45文字

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

入力を文字列の配列として受け取り、最も高い列の(0から始まる)インデックスを返します。O( + )の反復で実行され、各反復は本質的に一定の時間(少なくとも一定時間の算術を想定)を要するはずです。ループ内で行われる配列/文字列の操作は、要素の検索(=)と文字列の長さの取得(,)のみです。どちらもGolfScriptでは一定の時間がかかります。

オンラインでお試しください。

説明:

ここでのほとんどのソリューションと同様に、このコードは、マトリックスの左下隅から開始し、マトリックスの現在の要素が1であるか0であるかに応じて上下に移動し、最後に上に移動した列を追跡します。

プログラムの開始時に、変数に入力配列を割り当て、変数の^長さ(つまり行数)をy0 に割り当てxます。値0もスタックに残ります。次のループでは、最も高い列のインデックスに置き換えられます。

メインループ内で、の-番目の行の-番目の文字を^y(=x=抽出します。これは実際に文字のASCIIコードを返すため、最後のビットを除くすべてをドロップする必要があります。特別な場合として、0に等しい場合(これまでに見つかった最も高い列が一番上の行に達すると発生する可能性があります)、ルックアップされたビットは実際にはマトリックスの最後の行(インデックス-1)から取得されますが、次の例では、強制的にゼロにし、マトリックスの最上部に事実上すべてゼロの行を作成します。xy-1^2%yy*

次にif、ルックアップビットがゼロ以外(true)かゼロ(false)かによって、次のコードブロックの前の2つのコードブロックのいずれかが実行されます。ゼロ以外の場合、y1ずつ減分され、現在の値がxスタック上の最も高い列インデックスを置き換えます(古い値が一時的にその上に残ります)。ゼロの場合、x単純に1ずつ増加します(そして、最も高い列インデックスの上に一時的にスタックに残されます)。

最後に、^0=行列の最初の行を抽出し、,その長さを返し、<一時的にスタックに残っている列インデックスと比較します(xインクリメントされた場合は等しくなります)インデックスが行の長さより短い場合、ループ繰り返します。

追伸 私のテストに基づいて、,<ループの最後にある文字列の長さのテストをで置き換えて、このプログラムを1文字短くすることが可能です。これ>は、指定されたインデックスで文字列を切り取り、終了部分(空になります。したがって、ループの最後でfalse)。ただし、そのような文字列をカットすること、GolfScript(またはむしろ、GolfScriptが実行されるRuby)での一定時間の操作として実装されているように見えますが、そういう公式文書は見つかりませんでした。念のため、上記のわずかに長いが、間違いなくO(1)バージョンを採用することにしました。


6

Ruby、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配列形式をとる関数を定義します。

左下から始めて、最大スティック長(実際にはマイナス)と対応する列を追跡します。各列で1、以前の最大スティック長を超えるs がまだある場合、スティックを最後まで歩いて、新しい最大長と列を覚えています。つまり、列に沿って1回、行に沿って1回(具体的には、スティックの最大長まで繰り返します)正確にを繰り返しO(m+n)ます。


@Optimizer 2回目の編集は、投稿するまで表示されなかったため、編集履歴に含まれていました。だからこそ、自分でそれを理解したい人のためにネタバレにしたのです。
マーティンエンダー14

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 14

1
@feersum Python 2、配列の配列。
ジャスティン14

@feersum:Quincunxは正しい。入力は、あなたが提案したように、intの2D配列です。
ファルコ14

iスティックが列全体を占める場合、範囲外になりませんか?
xnor 14

1
申し訳ありませんが、jカウントを変更し0てループ条件を解除するようi*jです。
xnor 14

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 を捨てることができますか、またはそこにポインタがあるために機能しませんか?
マーティンエンダー14

1
入力には配列のみを含める必要があります。プログラムに配列のサイズを伝えることはできません。
オプティマイザー14

待って、それは実際に機能しますか?これは、その位置ではなく最長のスティックの長さを返しているようです:ideone.com/YEzqzl-
マーティンエンダー

2
Cでは基本的に不可能な@Optimizer
マーティン・エンダー14

かもしれませんが、それが問題です:)
オプティマイザー14

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;

ここでMartinからアルゴリズムを盗むようなものですが、ここではあまり見られない言語をいじってみるのはいいことです


@MartinBüttner私はあなたのアルゴリズムを「盗んだ」ので、今はO(n + m)になっているはずです。私はそれが正しいと思うXD
ニートザダークアブソル

あなたは置き換えることができ$s=json_decode($argv[1]);$t=count($s)-1;$t=count($s=json_decode($argv[1]))-1;(-3バイト)。
ブラックホール14

@Blackhole確かにできます。ありがとうございました!
ニートザダークアブソル14

@Blackhole機能が壊れると思います。条件が満たされない場合でも、割り当てを実行します。
ニートザダークアブソル14

@Blackholeはまだ壊れています。XD $t--は条件が満たされた場合にのみ発生するのではないかと心配しています。
ニートザダークアブソル14

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、1文字の関数名の代わりに使用する必要があるため、入力を解釈してから答えを出力する必要があるため、他のソリューションがその「他の場所」を処理するため、より長いことを意味します。また、私の最初のコードゴルフ。
でコンパイルし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<<と、より短い1文字 だけ送信がドロップされputchar(-48)、適切な出力で9本以上のスティックを明示的にサポートする必要があります(ただし、各出力を区別するのは難しくなる場合があります)
現在は、少なくとも一部の出力をカットする上に移動した場合にのみ、現在のベストを出力します。
ファイル全体のサイズはわずか78バイトになりました。C提出は使用します。(上記の機能をサポートするための追加のコードがたくさんあります)。

以下の説明は古くなっています:

cはグローバルなので0
r、入力(行)の数+1(プログラムの名前)
vv[0]無効な文字列の配列(プログラムの名前)で初期化されます
。インデックスが0でrあるため、範囲外であるため、デクリメントします。
while r!=0(有効な文字列を指して)文字列c内の文字は、文字が'\0'
'0'でない場合、nullターミネータではありません。
行を上に移動して(r)、列を出力し(c
、次の列に移動します(c

done

これをさらにゴルフできますか?

ゴルフされていないコード(追加出力あり):

#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 を受け取り、左下から開始し、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

入力としてテーブル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に1が存在するrで順序付けられたテーブルaの最初の行を返します。

TOP(1) 返される最初の行に結果を制限します。

CHARINDEX('1',A) 文字列の最初の1の位置を返します。見つからない場合は0を返します。

WHERE A LIKE'%1%' Aに1が含まれる行へのフィルター

ORDER BY R テーブルが上から下に確実に読み取られるようにします


そのコードで何が起こっているのか説明できますか?:D T-SQLの経験なし
オプティマイザー14

そうですね、各行のフィルタリングはO(n * m)操作ではありませんか?すなわち、線形時間の複雑さではありません。
オプティマイザー

言うのが難しい。SQLエンジンは、列の1についてすべての行をチェックします。条件を満たす最初の行のみを返します。したがって、この状況では、テーブル全体をスキャンします。1を含む列で行をフィルタリングします。ID列で結果をソートし、最初の結果を返します。
MickyT

次のように見てください:行が "0000"、 "0000"、 "0000"、 "0001"の場合 この場合、1の存在を把握するには、最後の行まで、および行の最後の文字まで行かなければなりません。
オプティマイザー

1
そうです、それはO(m * n)です:)
オプティマイザー14

0

Delphi 122文字

ため息...それはそのような膨大な言語です。

更新:戻り値の型をIから整数に変更する際に6文字を追加する必要がありました。テストプログラムが「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()呼び出しを行っていますか?
オプティマイザー14

@Optimiserはい、プログラムは「1」が見つかるまで配列内の各文字列を検索します(「inc(n)」を使用)。最初に見つかった「1」は最高(または最高に等しい)の「1」になるため、文字列内の位置(デルファイでは文字列は1から順に並んでいます)が最長の列の位置になります。配列に「1」がない場合、ルーチンは失敗しますが、「最長のスティック」が見つからないため、これは壊れた入力になると思います。
ペンギノ14

1
まず第一に、これは有効な入力です:"0000", "0010", "1111"第二に、あなたの答えは線形時間の複雑さの要件を満たしていません
オプティマイザー

@Optimizerはい、それは有効な入力であり、3番目のスティックを正しく識別します。しかし、投稿を行った後、配列を使用した有効な順序Nプログラムを、文字列を使用した無効な順序N ^ 2プログラムに変換したことに気付きました(〜160文字からの削減を追跡)。
ペンギノ

0

スキーム-236文字

デルファイバージョンよりもさらに長い...おそらくスキームでこれをはるかに効率的に行う方法があります。さらに悪いことに、私はそれが順序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))の形式のリストです。これは、schemeの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)操作です。
マーティンエンダー14

0

ラケット70

ゴルフ済み:

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

入力が2次元配列であると仮定します。これは、ラケットではリストのリストになります。

(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

最も長いスティックの列インデックスを返します。


それで基本的に、あなたは各列を通過し、の数を数えてい1ますか?
オプティマイザー14

あなたの言ってる事がわかります。アルゴリズムが更新されました。
マシューバタリック14

これには、依然としてO(m * n)の最悪の複雑さがあります(1行列にない場合、または下の行にのみある場合)。
マーティンエンダー14

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呼び出しを実行しません。


indexOfO(log n)またはのいずれかO(n)で動作するため、全体的なアルゴリズムは決して入りませんO(m + n)
オプティマイザー

@Optimizer Yeahは、そのO(m * n)がまっすぐに考えていなかったことに気付きました。
ジョージリース

@Optimizerが更新されましたO(m+n)
ジョージリース
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.