可视化最大公约数


28

背景

最大公约数(简称gcd)是一种便捷的数学函数,因为它具有许多有用的属性。Bézout的身份就是其中之一:if d = gcd(a, b),则存在整数xand y这样d = x*a + y*b。在这个挑战中,您的任务是使用简单的ASCII艺术形象化此属性。

输入值

您的输入是两个正整数ab,以任何合理的格式给出。您也可以使用一元输入(您选择的单个可打印ASCII字符的重复),但是您必须保持一致,并且两个输入都使用相同的格式。输入可以是任何顺序,并且可以相等。

输出量

您的输出是一串s长度lcm(a, b) + 1lcm代表最小公倍数)。的字符s表示从0到的整数lcm(a, b)。如果是或的倍数,则该字符s[i]为小写,o否则i为一个句点。请注意,零是每个数字的倍数。现在,因为贝祖等式中,将有至少一对人物,在其距离正好。最左边的这样的对将被大写s 代替;这是最终的输出。ab.osgcd(a, b)O

考虑输入a = 4b = 6。然后我们有gcd(a, b) = 2lcm(a, b) = 12,这样的长度s13。的倍数ab摘要如下:

0  1  2  3  4  5  6  7  8  9 10 11 12
o  .  .  .  o  .  o  .  o  .  .  .  o

有两对os,距离为2,但我们只会用Os 替换最左边的对,因此最终输出为

o...O.O.o...o

规则和计分

您可以编写完整的程序或函数。最低字节数获胜,并且不允许出现标准漏洞。

测试用例

 1  1 -> OO
 2  2 -> O.O
 1  3 -> OOoo
 4  1 -> OOooo
 2  6 -> O.O.o.o
 2  3 -> o.OOo.o
10  2 -> O.O.o.o.o.o
 4  5 -> o...OO..o.o.o..oo...o
 8  6 -> o.....O.O...o...o.o.....o
12 15 -> o...........O..O........o.....o.....o........o..o...........o
19 15 -> o..............o...o..........o.......o......o...........o..o..............OO.............o....o.........o........o.....o............o.o..............o.o............o.....o........o.........o....o.............oo..............o..o...........o......o.......o..........o...o..............o

1
一元输入时,我们可以选择任何字符吗?(特别是,怎么样.oO)或者它必须是1?还是0
Martin Ender'1

1
@MartinBüttner可以是任何字符,只要您一致且两个输入都使用相同的格式即可。
Zgarb'1

2
我很惊讶您没有使用3和5作为测试用例之一。
尼尔

我可以使用buildin吗?
Akangka '16

@ChristianIrwan是的,允许所有内置插件。
Zgarb

Answers:


7

Jolf,52个字节

on*'.wm9jJΡR m*Yhm8jJDN?<*%Sj%SJ1'o'.}"'o%o"n"O%O"n

我将这段代码分为两部分。

on*'.wm9jJ
on         set n
  *'.       to a dot repeated
      m9jJ  the gcd of two numeric inputs

ΡR m*Yhm8jJDN?<*%Sj%SJ1'o'.}"'o%o"n"O%O"n
    *Y                                    multiply (repeat) Y (Y = [])
      hm8jJ                                by the lcm of two inputs + 1
  _m       DN              }              and map the array of that length
             ?<*%Sj%SJ1'o'.               "choose o if i%a*(i%b)<1; otherwise choose ."
 R                          "'            join by empty string
Ρ                            'o%o"n        replace once (capital Rho, 2 bytes): "o"+n+"o"
                                   "O%O"n   with "O"+n+"O"
                                          implicit printing

在这里尝试!


比到目前为止的所有内容都短。:P
Rɪᴋᴇʀ

1
@RikerW是的!我希望Jolf最终能赢得一次。
科纳·奥布莱恩

10

利亚,111个 110 107 103 96字节

f(a,b)=replace(join([i%a*(i%b)<1?"o":"."for i=0:lcm(a,b)]),"o$(d="."^(gcd(a,b)-1))o","O$(d)O",1)

此函数接受两个整数并返回一个字符串。

取消高尔夫:

function f(a::Int, b::Int)
    # Construct an array of dots and o's
    x = [i % a * (i % b) < 1 ? "o" : "." for i = 0:lcm(a, b)]

    # Join it into a string
    j = join(x)

    # Replace the first pair with distance gcd(a, b) - 1
    replace(j, "o$(d = "."^(gcd(a, b) - 1))o", "O$(d)O", 1) 
end

感谢妮米节省了一个字节!


10

视网膜112 109 99 94 91字节

^
. 
+r`(?<!^\1+). (.+) 
$'$0
.(?=.* (.+) (.+))(?=\1* |\2* )
o
o(\.*)o((\1\.*o)*) .*
O$1O$2

我认为竞争不是很激烈,但是视网膜中的数论总是很有趣。:)

将输入作为一进制数字,.用作一进制数字。

在线尝试。

说明

^
. 

这会.在输入前面插入和。这最终将成为输出。

+r`(?<!^\1+). (.+) 
$'$0

这种预先考虑的LCM ab字符串。由于我们已经有一个了,.所以我们最后得到lcm(a,b)+1b只要a不分隔此新前缀,就可以通过反复添加前缀来实现。我们捕获a到一个组,然后通过匹配捕获至少一次来检查是否可以到达字符串的开头。b然后通过很少使用的字符串将$'其插入字符串,该字符串将匹配的所有内容插入替换项。

.(?=.* (.+) (.+))(?=\1* |\2* )
o

该字符在用a或分隔的位置匹配字符b。它利用了结果是对称的事实:因为lcm(a,b)被除以,a然后b通过减去的实例向左移动a或通过将它们相加而b产生与向右移动相同的模式0。先行先行捕获a和捕获b。第二次前行检查在第一个空格之前是否存在每个a或多个b字符的倍数。

o(\.*)o((\1\.*o)*) .*
O$1O$2

如Wikipedia所述,除了Bézout的身份外,

最大公约数d是可以写为的最小正整数ax + by

这意味着GCD将对应o于输出中两个s 之间的最短间隙。因此,我们根本不必费心查找GCD。相反,我们只是寻找最短的差距的第一实例。o(\.*)o匹配候选间隙并将其宽度捕获到组1中。然后,我们尝试通过对组1的向后引用和os(带有可选的附加.s)之间交替来到达第一个空间。如果右边还有一个更短的间隙,则将无法匹配,因为我们无法使用反向引用来克服该间隙。一旦所有其他间隙至少与当前间隙一样大,则匹配。我们将LCM字符串的末尾捕获到组2中,并将字符串的其余部分与匹配.*。我们写回大写OS(与之间的间隙),以及所述的LCM串的其余部分,但丢弃一切从空间开始,以除去ab从最终结果。


我对视网膜数论了解不多,但是是否不会将输入字符设置为不需要转义保存字节的内容?即(\.*)=>(a*)
科纳·奥布莱恩

@CᴏɴᴏʀO'Bʀɪᴇɴ是的,但是后来我必须用.以后的替换它,这需要四个字节(而摆脱转义符只能节省3个字节)。
Martin Ender

哦 凉!非常有趣的答案。
科纳·奥布莱恩

5

𝔼𝕊𝕄𝕚𝕟,50个字符/ 90个字节

⩥Мū⁽îí+1)ⓜ$%î⅋$%í?⍘.:⍘o)⨝ċɼ(`o⦃⍘.ĘМũ⁽îí-1)}o”,↪$ú⬮

Try it here (Firefox only).

必须有进一步打高尔夫球的方法!

说明

这是基本的两阶段算法。实际上很简单。

阶段1

⩥Мū⁽îí+1)ⓜ$%î⅋$%í?⍘.:⍘o)⨝

首先,我们创建一个从0到LCM + 1的范围。然后我们在其上进行映射,检查输入中的任何一个是否是该范围内当前项目的一个因素。如果是这样,我们将该项目替换为o;否则,我们将其替换为.。加入它可以给我们一系列o和点,我们可以将其传递给第二阶段。

阶段2

ċɼ(`o⦃⍘.ĘМũ⁽îí-1)}o”,↪$ú⬮

这只是一个很大的替换功能。正则表达式创建为o[dots]o,其中点的数量由GCD-1确定。由于此正则表达式不是全局正则表达式,因此只会匹配第一个匹配项。之后,O[dots]O使用toUpperCase函数替换匹配项。


3

MATL,72字节

使用版本6.0.0,它早于此挑战。该代码在Matlab和Octave中运行。

2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 1
> 1
OO

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 2
> 3
o.OOo.o

>> matl
 > 2$tZm1+:1-bbvtbw\A~otbZ}ZdXK1+ltb(3X53$X+1K2$lh*t2=f1)tK+hwg1+Ib('.oO'w)
 > 
> 12
> 15
o...........O..O........o.....o.....o........o..o...........o

说明

不知道它是如何工作的。我只是随机输入字符。我认为涉及一些卷积。

编辑:在线尝试!对该链接中的代码进行了略微修改,以适应语言的更改(截至2016年6月2日)。


您不能随机键入一个72字节的程序。稍后将计算概率(经过一段时间的睡眠和运动后)
CalculatorFeline

2

Japt,83个字节

'.pD=U*V/(C=(G=@Y?G$($YX%Y :X} $($UV)+1 £Y%U©Y%V?".:o"} $.replace($E=`o{'.pC-1}o`Eu

还没有完全打高尔夫球...而且不想打高尔夫球:/


不能r代替使用$.replace($吗?
ETHproductions 2016年

@Eth我还没有弄清楚如何在没有g标志的情况下进行替换,所以不,我不能。
nicael

2

的Javascript,170个 164 161 153 145 141 136字节

(a,b)=>[...Array(a*b/(c=(g=(a,b)=>b?g(b,a%b):a)(a,b))+1)].map((x,i)=>i%a&&i%b?'.':'o').join``.replace(`o${e='.'.repeat(c-1)}o`,`O${e}O`)

那真是lonnnggggg ....

Demo,显式定义的变量,因为解释器使用严格模式。


尝试替换i%a<1||i%b<1?'o':'.'i%a&&i%b?'.':'o'
Mama Fun Roll'1

哦,是的,我想您可以别名加入。
Mama Fun Roll'1

@ןnɟuɐɯɹɐןoɯ谢谢,还用简单的重复替换数组。
nicael

哦,那么在那种情况下,除非您有3次出现,否则您不应该别名连接。
Mama Fun Roll'1

[...Array((d=a*b/(c=(g=(a,b)=>b?g(b,a%b):a)(a,b)))+1).keys()].map(i=>i%a&&i%b?'.':'o')为您节省两个字节。(我也尝试使用字符串索引来创建'。'和'o',但实际上要花费两个字节。)
Neil

1

Python 2中,217个 200 191字节

这有点钝,但是可以。任何打高尔夫球的技巧都会受到赞赏,特别是如果您知道如何解决s[i] = s[v] = "o"我遇到的问题,那会覆盖“ O”的问题!

g=lambda a,b:b and g(b,a%b)or a
def f(a,b):
 h=g(a,b);x=1+a*b/h;s=["."]*x;v=k=0
 for i in range(x):
    if(i%a)*(i%b)<1:
     if k:s[i]="o"
     else:k=i==h+v;s[i]=s[v]="oO"[k]
     v=i
 return''.join(s)

取消高尔夫:

def gcd(a,b):                           # recursive gcd function
    if b:
        return g(b,a%b)
    else:
        return a
def f(a,b):
    h = gcd(a,b)
    x = 1 + a*b/h                       # 1 + lcm(a,b)
    s = ["."] * x
    v = 0
    k = 0
    for i in range(x):
        if i%a == 0 and i % b == 0:
            if k == 0:
                k = (i == h+v)          # correct distance apart?
                if k:                   # if "O" just found
                    s[i] = s[v] = "O"
                else:
                    s[i] = s[v] = "o"
            else:
                s[i] = "o"              # if "O" already found, always "o"
            v = i                       # If we found an "o" or an "O", i is the new v
    return ''.join(s)
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.