数字三角形翻转


30

假设您在三角形中列出了正整数,然后将其从左向右翻转。给定一个数字,输出它发送到的数字。这是一个自逆映射。

         1                      1         
       2   3                  3   2       
     4   5   6    <--->     6   5   4     
   7   8   9  10         10   9   8   7   
11  12  13  14  15     15  14  13  12  11

这是A038722的第n个元素,被索引:

1, 3, 2, 6, 5, 4, 10, 9, 8, 7, 15, 14, 13, 12, 11, ...

此序列以递增的长度反转正整数的连续块:

 1, 3, 2, 6, 5, 4, 10, 9, 8, 7, 15, 14, 13, 12, 11, ...
<-><----><-------><-----------><------------------>

测试用例:

1 -> 1
2 -> 3
3 -> 2
4 -> 6
14 -> 12
990 -> 947
991 -> 1035
1000 -> 1026
1035 -> 991
1036 -> 1081
12345 -> 12305

排行榜:

Answers:


15

JavaScript(ES7),26个字节

n=>((2*n)**.5+.5|0)**2-n+1

OEIS中以下公式的实现:

式

演示版


我喜欢OR操作将其分块为整数!不错的工作!
CraigR8806

7

果冻8 7字节

RṁR€UFi

感谢@ErikTheOutgolfer节省了1个字节!

在线尝试!

怎么运行的

RṁR€UFi  Main link. Argument: n

R        Range; yield [1, ..., n].
  R€     Range each; yield [[1], [1, 2], [1, 2, 3], ..., [1, ..., n]].
 ṁ       Mold the left argument like the right one, yielding
         [[1], [2, 3], [4, 5, 6], ...]. The elements of the left argument are 
         repeated cyclically to fill all n(n+1)/2 positions in the right argument.
    U    Upend; reverse each flat array, yielding [[1], [3, 2], [6, 5, 4], ...].
     F   Flatten, yielding [1, 3, 2, 6, 5, 4, ...].
      i  Index; find the first index of n in the result.

6

爱丽丝,27字节

感谢Sp3000的.C想法。

/o
\i@/.2:e2,tE*Y~Z.H2*~.C+

在线尝试!

说明

我认为使用三角数来计算该方法可能更短,但是我认为这是对内置函数的一种有趣滥用,因此这是另一种解决方案。

基本思想是利用Alice的“ pack”和“ unpack”内置函数。“ Pack”(即Z)取两个整数,将它们双射地映射为一个整数。“解压”或Y,将这个双射反转,并将一个整数变成两个。通常,它可用于将列表或整数树存储为单个(大)整数,并稍后恢复单个值。但是,在这种情况下,我们可以按相反的顺序使用函数,以使双射的性质对我们有用。

将一个整数分解为两个整数基本上包括三个步骤:

  1. 用简单的“折叠”将ℤ→ℕ(包括零)映射。也就是说,将负整数映射到奇数自然数,将非负整数映射到偶数自然数。
  2. 地图ℕ→ℕ 2,使用康托尔配对功能。也就是说,自然数是沿着无限网格的对角线写的,我们返回索引:

       ...
    3  9 ...
    2  5 8 ...
    1  2 4 7 ...
    0  0 1 3 6 ...
    
       0 1 2 3
    

    例如8将映射到该对(1, 2)

  3. 地图2 →ℤ 2,使用在单独的各整数步骤1的倒数。也就是说,奇数自然数映射到负整数,甚至自然数映射到非负整数。

要将两个整数打包为一个,我们只需将每个步骤取反即可。

现在,我们可以看到Cantor配对函数的结构方便地编码了我们需要的三角形(尽管值是一一对应的)。要反转这些对角线,我们所需要做的就是将xy坐标交换到网格中。

不幸的是,由于上述所有三个步骤都组合成一个内置的Y(或Z),因此我们需要自己撤消ℤ→ℕℕ→ℤ映射。但是,这样做时,我们可以直接使用+ →ℤℤ→ℕ +映射来保存几个字节,以照顾表中的一次性错误。所以这是整个算法:

  1. 使用(n / 2)*(-1)n-1映射+ →ℤ。选择此映射以使其在解压缩过程中取消隐式ℤ→ℕ映射,除了将值向下移动1之外。
  2. 将结果解压缩为两个整数。
  3. 交换他们。
  4. 再次将交换后的值打包为单个整数。
  5. | 2n |映射ℤ→ℕ + +(n≥0)。再次选择该映射,以便在打包过程中取消隐式ℕ→ℤ映射,只是它将值上移1。

有了这些,我们可以看一下程序:

/o
\i@/...

这只是具有整数输入和输出的线性算术程序的框架。

.    Duplicate the input.
2:   Halve it.
e    Push -1.
2,   Pull up the other copy of the input.
t    Decrement.
E    Raise -1 to this power.
*    Multiply. We've now computed (n/2) * (-1)^(n-1).
Y    Unpack.
~    Swap.
Z    Pack.
.H   Duplicate the result and take its absolute value.
2*   Double.
~    Swap with other copy.
.C   Compute k-choose-k. That's 1 for k ≥ 0 and 0 for k < 0.
+    Add. We've now computed |2n| + (n≥0).



4

八度71 68字节

感谢Conor O'Brien节省了3个字节。

x=triu(ones(n=input('')));x(~~x)=1:nnz(x);disp(nonzeros(flip(x))(n))

由于内存限制,这不适用于大型输入。

在线尝试!

说明

考虑输入n = 4。代码首先建立矩阵

 1     1     1     1
 0     1     1     1
 0     0     1     1
 0     0     0     1

然后,它取代了非零条目列主顺序(下来,然后在)的123...:

 1     2     4     7
 0     3     5     8
 0     0     6     9
 0     0     0    10

然后垂直翻转矩阵:

 0     0     0    10
 0     0     6     9
 0     3     5     8
 1     2     4     7

最后,它采用n列优先顺序的第-个非零值,在这种情况下为6


1
@ rahnema1那e是天才!您绝对应该将其与其他非常好的建议一起作为答案发布。至于ans =,我永远不确定它是否有效
Luis Mendo

4

Haskell,31个字节

r=round
f n=r(sqrt$2*n)^2-r n+1

在线尝试!

该答案仅使用公式。这是最不有趣的答案,但它恰好是最高尔夫球的。

Haskell38 36 34字节

x!y|x<=y=1-x|v<-y+1=v+(x-y)!v
(!0)

在线尝试!

(!0) 是我们关注的无点功能。

说明

首先,我对这个答案感到非常满意。

这里的基本思想是,如果我们删除小于输入的最大三角数,则可以将其取反,然后再增加三角数。因此,我们定义了一个运算符!,使用!了常规输入x,但是也需要一个额外的数字yy跟踪不断增长的三角数的大小。如果x>y我们要递归,我们减少xy,增加y一个。因此,我们计算(x-y)!(y+1)并添加y+1到它。如果x<=y我们已经达到基本情况,则要反转x在三角形行中的位置,我们将返回1-x

Haskell,54个字节

f x|u<-div(x^2-x)2=[u+x,u+x-1..u+1]
(!!)$0:(>>=)[1..]f

在线尝试!

(!!)$0:(>>=)[1..]f 是没有积分的功能

说明

我们关心的第一件事是f,它f是一个函数,该函数以相反的方式获取x并返回x第三角形的第th行。为此,首先计算第x-1n个三角数并将其分配给uu<-div(x^2-x)2。然后,我们返回列表[u+x,u+x-1..u+1]u+x是第三x个三角数,并且行中的第一个数字,u+x-1比该数小一个,并且该行中的第二个数字,u+1与最后一个三角数(也就是该行中的最后一个数字)相比,多一个。

一旦我们有了f一个列表(>>=)[1..]f,它就是三角形的展平。我们在前面加上零,以0:使我们的答案不会被一抵消,并将其提供给索引功能(!!)

Haskell,56个字节

f 0=[0]
f x|u<-f(x-1)!!0=[u+x,u+x-1..u+1]
(!!)$[0..]>>=f

在线尝试!

我认为这长了2个字节,但更加优雅。


3

C(gcc),48个字节

k,j,l;f(n){for(k=j=0;k<n;)l=k,k+=++j;n=1+k-n+l;}

在线尝试!

可能不是最佳选择,但是我对此感到非常满意。使用以下事实

NTF N = T N + A057944N-N + 1

(如果我正确地写下了公式,那就是。)


您不是在调用return,而是使用了return值。那是未定义的行为。
2501年

@ 2501只要程序有效,就可以。并且,写入函数的第一个参数等效于返回值。
科纳·奥布莱恩

并且,写入函数的第一个参数等效于返回值。C语言中不存在这样的东西。该标准甚至明确表示使用未返回的函数的返回值是未定义的行为。
2501年

1
@ 2501您似乎对C规范的C环境(gcc)感到困惑。是的,C语言/规范称其为undefined,但它是照此实现的。因此,当我说“等效”时,我绝对是指gcc和大多数其他编译器对C的实现。在PPCG上,我们不会编写“完美的”代码-为了打高尔夫球,许多代码都违反了规范。正如我所说,只要有效,这是一个有效的答案。
科纳·奥布莱恩

@ 2501我鼓励您阅读meta网站上的一些文章,尤其是这篇文章。
科纳·奥布莱恩

2

05AB1E,30个字节

U1V[YLO>X›iYLOX-UY<LO>X+,q}Y>V

在线尝试!


我正要说:“什么?没有Unicode的05AB1E答案?” 但是然后一个非ASCII字符破坏了它...:P不错,但是,第一个好答案是,欢迎使用Programming Puzzles和Code Golf!
clismique

@ Qwerp-Derp非常感谢!我刚开始学习这种语言,所以我的回答如此糟糕并不令我感到惊讶。
爱德华多·霍费尔

2

外壳,6个字节

!ṁ↔´CN

在线尝试!

说明

!ṁ↔´CN  -- implicit input N, for example: 4
   ´ N  -- duplicate the natural numbers:
           [1,2,3,…] [1,2,3,…]
    C   -- cut the second argument into sizes of the first:
           [[1],[2,3],[4,5,6],[7,8,9,10],…]
 ṁ↔     -- map reverse and flatten:
           [1,3,2,6,5,4,10,9,8,7,15,…
!       -- index into that list:
           6

2

tinylisp,78个字节

(d _(q((R N T)(i(l T N)(_(a R 1)N(a T R))(a 2(a T(s T(a N R
(d f(q((N)(_ 2 N 1

定义f执行映射的函数。在线尝试!

不打高尔夫球

我们找到了大于或等于输入数字的最小三角数,以及该数字位于该三角的哪一行中。从这些数字中,我们可以计算出该数字的翻转形式。

  • 如果当前的三角形数小于N,则递归到三角形的下一行。(为了简化数学,我们将第一行视为第二行。)
  • 否则,N的翻转版本为(TN)+(TR)+2。

main函数仅从第一行开始flip调用helper函数_flip

(load library)

(def _flip
 (lambda (Num Row Triangular)
  (if (less? Triangular Num)
   (_flip Num (inc Row) (+ Triangular Row))
   (+ 2
    (- Triangular Num)
    (- Triangular Row))))))

(def flip
 (lambda (Num) (_flip Num 2 1)))

1

05AB1E,9个字节

·LD£í˜¹<è

在线尝试!

说明

·L          # push range [1 ... 2n]
  D         # duplicate
   £        # split the first list into pieces with size dependent on the second list
    í       # reverse each sublist
     ˜      # flatten
      ¹<è   # get the element at index <input>-1

不幸的是,数组变平不能很好地处理较大的列表。
以1字节为代价,我们可以使用OEIS上的数学公式进行t2z + inn->floor(sqrt(2*n)+1/2)^2 - n + 1


1

批处理,70字节

@set/ai=%2+1,j=%3+i
@if %j% lss %1 %0 %1 %i% %j%
@cmd/cset/ai*i+1-%1

使用循环查找至少等于的三角数的索引n




0

APL(Dyalog),27个字节

我在相同的字节数下有两个解决方案。

一列火车:

⊢⊃⊃∘(,/{⌽(+/⍳⍵-1)+⍳⍵}¨∘⍳)

在线尝试!

和dfn:

{⍵⊃⊃((⍳⍵),.{1+⍵-⍳⍺}+\⍳⍵)}

在线尝试!

这两个解决方案都首先创建倒三角形,然后在参数指定的索引处提取元素(1基于-)。


0

J,25个字节

3 :'>:y-~*:>.-:<:%:>:8*y'

作为解释,请考虑f(n) = n(n+1)/2f(r)给定该行r,则返回镜像三角形的r第th行的最左边的数字。现在,考虑g(n) = ceiling[f⁻¹(n)]g(i)给定索引i,返回找到索引i的行。然后,f(g(n))返回找到索引n的行的最左边编号。因此,h(n) = f(g(n)) - (n - f(g(n)-1)) + 1就是以上问题的答案。

简化,我们得到h(n) = [g(n)]² - n + 1 = ceiling[(-1 + sqrt(1 + 8n))/2]² - n + 1

从@Arnauld公式的外观可以看出:

ceiling[(-1 + sqrt(1 + 8n))/2] = floor[1/2 + sqrt(2n)]


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.