【问题标题】:Code Golf: Zigzag pattern scanningCode Golf:之字形图案扫描
【发布时间】:2010-06-11 19:20:00
【问题描述】:

挑战

按字符数计算的最短代码,它采用单个输入整数 N (N >= 3) 并返回一个索引数组,在迭代时将根据 JPEG“zigzag”遍历 NxN 矩阵"扫描模式。下面是一个遍历 8x8 矩阵的示例src

示例

(中间矩阵不是输入或输出的一部分,只是输入所代表的NxN矩阵的表示。)

                1 2 3
(Input) 3  -->  4 5 6  -->  1 2 4 7 5 3 6 8 9 (Output)
                7 8 9

                1  2  3  4
(Input) 4  -->  5  6  7  8  -->  1 2 5 9 6 3 4 7 10 13 14 11 8 12 15 16 (Output)
                9 10 11 12
               13 14 15 16

注意事项

  • 结果数组的基数应该适合您的语言(例如,Matlab 数组是从 1 开始的,C++ 数组是从 0 开始的)。
  • 这与this question有关。

奖金

扩展您的答案以获取两个输入 NM (N, M >=3) 并对 NxM 矩阵执行相同的扫描。 (在这种情况下,N 是列数,M 是行数。)

奖励示例

                  1  2  3  4
(Input) 4 3  -->  5  6  7  8  -->  1 2 5 9 6 3 4 7 10 11 8 12 (Output)
                  9 10 11 12

                   1  2  3
(Input) 3 4  -->   4  5  6  -->  1 2 4 7 5 3 6 8 10 11 9 12 (Output)
                   7  8  9
                  10 11 12

【问题讨论】:

  • 我将使用...在 7 个字符以下开始 J 池。
  • @Mark:到目前为止,我最好的是 15。我很确定 7 是不可能的,但我很想被证明是错误的。
  • 为什么我花了一天的时间编写代码,然后又花了 3 个小时进行代码高尔夫? =P

标签: language-agnostic code-golf rosetta-stone


【解决方案1】:

J,13 个 15 个字符

;<@|.`</.i.2$

用法:

   ;<@|.`</.i.2$  3
0 1 3 6 4 2 5 7 8

   ;<@|.`</.i.2$  4
0 1 4 8 5 2 3 6 9 12 13 10 7 11 14 15

说明

NB.是J的评论指标)

;         NB. Link together...
<@|.`<    NB. ... 'take the reverse of' and 'take normally'
/.        NB. ... applied to alternating diagonals of...
i.        NB. ... successive integers starting at 0 and counting up to fill an array with dimensions of...
2$        NB. ... the input extended cyclically to a list of length two.

J,奖金,13 个字符

;<@|.`</.i.|.

用法:

   ;<@|.`</.i.|. 3 4
0 1 3 6 4 2 5 7 9 10 8 11

   ;<@|.`</.i.|. 9 6
0 1 9 18 10 2 3 11 19 27 36 28 20 12 4 5 13 21 29 37 45 46 38 30 22 14 6 7 15 23 31 39 47 48 40 32 24 16 8 17 25 33 41 49 50 42 34 26 35 43 51 52 44 53

【讨论】:

  • 我喜欢两个字符“应用于交替对角线”的方式。
  • 是的,内置的“交替对角线”使这成为可能。我正在研究一个不使用它的 goflscript 解决方案.. 会看到它有多短
【解决方案2】:

Python, 92, 95, 110, 111, 114, 120122162164 个字符

N=input()
for a in sorted((p%N+p/N,(p%N,p/N)[(p%N-p/N)%2],p)for p in range(N*N)):print a[2],

测试:

$ echo 3 | python ./code-golf.py 
0 1 3 6 4 2 5 7 8

$ echo 4 | python ./code-golf.py 
0 1 4 8 5 2 3 6 9 12 13 10 7 11 14 15

此解决方案很容易推广到NxM 板:调整输入处理并将N*N 替换为N*M

N,M=map(int,raw_input().split())
for a in sorted((p%N+p/N,(p%N,p/N)[(p%N-p/N)%2],p)for p in range(N*M)):print a[2],

我怀疑有一些更容易/更短的方法来读取两个数字。

测试:

$ echo 4 3 | python ./code-golf.py 
0 1 4 8 5 2 3 6 9 10 7 11

【讨论】:

  • 我不熟悉 Python 语法,但是这如何打印以空格分隔的数字?
  • @Adam 逗号可以做到这一点,并且“最后会写一个 '\n' 字符,除非打印语句以逗号结尾”
  • 你可以使用'split()'而不是'replace()'
  • @David:不,他不能。他将留下一个由两个字符串组成的数组。他需要一个包含两个整数的数组,所以这就是他使用 eval + replace 的原因。您可以只使用 split 然后将每个数组元素转换为 int,但我认为最终会使用更多字符。
  • @wallacoloo:N,M=input() (python 2.x) 怎么样?
【解决方案3】:

Ruby,69 个 89 字符

n=gets.to_i
puts (0...n*n).sort_by{|p|[t=p%n+p/n,[p%n,p/n][t%2]]}*' '

89 个字符

n=gets.to_i
puts (0...n*n).map{|p|[t=p%n+p/n,[p%n,p/n][t%2],p]}.sort.map{|i|i[2]}.join' '

运行

> zigzag.rb
3
0 1 3 6 4 2 5 7 8

> zigzag.rb
4
0 1 4 8 5 2 3 6 9 12 13 10 7 11 14 15

排序方法的功劳加倍。

【讨论】:

  • n=eval *$&lt;;p (0...n*n).sort_by{|p|[t=p%n+p/n,[p%n,p/n][t%2]]}61
  • @matyr: p 打印 [0, 1, 3,...] 而不是 0 1 3...
  • @matyr,谢谢。达到了 69。 eval *$
  • @Sebastian “索引数组”并不表示以空格分隔。 @Adam puts -> $&gt;&lt;&lt;.
【解决方案4】:

F#,126 个字符

let n=stdin.ReadLine()|>int
for i=0 to 2*n do for j in[id;List.rev].[i%2][0..i]do if i-j<n&&j<n then(i-j)*n+j|>printf"%d "

例子:

$ echo 3 | fsi --exec Program.fsx
0 1 3 6 4 2 5 7 8

$ echo 4 | fsi --exec Program.fsx
0 1 4 8 5 2 3 6 9 12 13 10 7 11 14 15

【讨论】:

  • [x;y].[i%2] 而不是 if i%2=0 then x else y - 很好,一定要记住那个 - @doublep 的道具
  • 哦,这是一个不错的技巧。我认为它也可以在 PowerShell 中工作。
【解决方案5】:

Golfscript,26/30 32/36 45 59 个字符

迄今为止最短的非J解:

更新排序(不要告诉其他人!) - 30 个字符:

 ~:1.*,{..1/\1%+.2%.+(@*]}$' '* #solution 1
#~:\.*,{.\/1$\%+.1&@.~if]}$' '* #solution 2
#~\:1*,{..1/\1%+.2%.+(@*]}$' '* #(bonus)
#~\:\*,{.\/1$\%+.1&@.~if]}$' '* #(bonus)

直接实现 - 36 个字符:

 ~:@.*,{[.@%:|\@/:^+|^- 2%^|if]}$' '*
#~\:@*,{[.@%:|\@/:^+|^- 2%^|if]}$' '* #(bonus)

如果您可以将输出提供为“013642578”而不是“0 1 3 6 4 2 5 7 8”,那么您可以删除最后 4 个字符。

感谢 doublep 的排序技术。


解释:

~\:@*        #read input, store first number into @, multiply the two
,            #put range(@^2) on the stack
{...}$       #sort array using the key in ...
" "*         #join array w/ spaces

对于关键:

[            #put into an array whatever is left on the stack until ]
.@%:|        #store @%n on the stack, also save it as |
\@/:^        #store @/n on the stack, also save it as ^
+            #add them together. this remains on the stack.
|^- 2%^|if   #if (| - ^) % 2 == 1, then put ^ on stack, else put | on stack.
]            #collect them into an array

【讨论】:

  • @Nabb:你确定更新后的排序有效吗?我试过了,但它给出了不同的输出
  • 对于我测试的值的平方和红利问题,输出完全相同
  • 不熟悉 Golfscript,但 (a+b)%2 等于 (a-b)%2。如果这有助于节省一些字符,您也许可以 %2 计算 |^ 的总和。
【解决方案6】:

MATLAB,101/116 个字符

它基本上是给定here 的相同答案的浓缩版本,可直接在命令提示符下运行:

N=input('');i=fliplr(spdiags(fliplr(reshape(1:N*N,N,N)')));i(:,1:2:end)=flipud(i(:,1:2:end));i(i~=0)'

还有一个从用户那里读取两个值的扩展:

S=str2num(input('','s'));i=fliplr(spdiags(fliplr(reshape(1:prod(S),S)')));i(:,1:2:end)=flipud(i(:,1:2:end));i(i~=0)'

测试:

3
ans =
     1     2     4     7     5     3     6     8     9

4 3
ans =
     1     2     5     9     6     3     4     7    10    11     8    12

【讨论】:

    【解决方案7】:

    Ruby 137 130 138 个字符

    n=gets.to_i
    def g(a,b,r,t,s);x=[s*r]*t;t==r ?[a,x,a]:[a,x,g(b,a,r,t+1,-s),x,a];end
    q=0;puts ([1]+g(1,n,n-1,1,1)).flatten.map{|s|q+=s}*' '
    
    $ zz.rb
    3
    1 2 4 7 5 3 6 8 9
    
    $ zz.rb
    4
    1 2 5 9 6 3 4 7 10 13 14 11 8 12 15 16
    

    【讨论】:

    • 你应该使用puts [array]*' '来匹配问题中的输出。
    【解决方案8】:

    C89(280 字节)

    我想这仍然可以优化 - 我使用四个数组来存储可能的运动 撞墙时的向量。我想可以做到,在定义中保存一些字符,但我认为进一步实现逻辑会花费更多。无论如何,给你:

    t,l,b,r,i,v,n;main(int c,char**a){n=atoi(*++a);b=n%2;int T[]={n-1,1},L[]={1-n,n}
    ,B[]={1-n,1},R[]={n-1,n};for(c=n*n;c--;){printf("%d%c",i,c?32:10);if(i>=n*(n-1))
    v=B[b=!b];else if(i%n>n-2){if(!(n%2)&&i<n)goto g;v=R[r=!r];}else if(i<n)g:v=T[t=
    !t];else if(!(i%n))v=L[l=!l];i+=v;}}
    

    编译时带有一些警告,但据我所知它是可移植的 C89。我其实不确定 我的算法是否聪明,也许你可以用更好的算法来缩短 (尚未花时间了解其他解决方案)。

    【讨论】:

      【解决方案9】:

      Haskell 117 个字符

      i s=concatMap(\q->d q++(reverse.d$q+1))[0,2..s+s]
       where d r=[x+s*(r-x)|x<-[0..r],x<s&&(r-x)<s]
      main=readLn>>=print.i
      

      运行:

      $ echo 3 | ./Diagonals 
      [0,1,3,6,4,2,5,7,8]
      
      $ echo 4 | ./Diagonals 
      [0,1,4,8,5,2,3,6,9,12,13,10,7,11,14,15]
      

      矩形变体稍长一些,有 120 个字符:

      j(w,h)=concatMap(\q->d q++(reverse.d$q+1))[0,2..w+h]
       where d r=[x+w*(r-x)|x<-[0..r],x<w&&(r-x)<h]
      main=readLn>>=print.j
      

      这里的输入需要一个元组:

      $ echo '(4,3)' | ./Diagonals 
      [0,1,4,8,5,2,3,6,9,10,7,11]
      
      $ echo '(3,4)' | ./Diagonals 
      [0,1,3,6,4,2,5,7,9,10,8,11]
      

      答案都是从 0 开始的,并以列表形式返回(Haskell 的自然形式)。

      【讨论】:

        【解决方案10】:

        Perl 102 个字符

        <>=~/ /;print map{$_%1e6," "}sort map{($x=($%=$_%$`)+($/=int$_/$`))*1e9+($x%2?$/:$%)*1e6+$_}0..$'*$`-1
        

        用法:

        echo 3 4 | perl zigzag.pl
        0 1 3 6 4 2 5 7 9 10 8 11
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-06-02
          • 1970-01-01
          • 1970-01-01
          • 2012-08-06
          • 2014-07-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多