好吧,这很奇怪……不用等待,甚至!


70

前言

整数始终为偶数或奇数。偶数可被二整除,奇数不可。

当您将两个整数相加时,可以根据被加数是偶数还是奇数来推断结果是偶数还是奇数:

  • 偶数+偶数=偶数
  • 偶数+奇数=奇数
  • 奇数+偶数=奇数
  • 奇数+奇数=偶数

同样,当您将两个整数相乘时,可以根据因子是偶数还是奇数来推断结果是偶数还是奇数:

  • 偶数*偶数=偶数
  • 偶数*奇数=偶数
  • 奇数*偶数=偶数
  • 奇数*奇数=奇数

因此,如果您知道数学表达式中仅涉及加法和乘法的所有变量的偶数或奇数,则可以推断结果是偶数还是奇数。

例如,我们可以确信地说(68 + 99) * 37结果是奇数,因为偶数加上奇数(68 + 99)就是一个奇数,而奇数乘以另一个奇数(odd * 37)就是一个奇数。

挑战

编写一个仅包含四个字符的字符串的程序或函数eo+*。该字符串表示一个以前缀表示法给出的数学表达式,仅涉及加法(+)和乘法(*)。每个e代表任意的偶数,每个o代表任意的奇数。

您的任务是简化表达式,打印或返回单个eo基于表达式结果是偶数还是奇数。

您可以假设输入将始终使用有效的前缀表示法。具体来说,每个+*将始终具有两个对应的操作数。这些操作数可以是单个eo,或另一个+*表达式,又具有操作数。

例如,输入*+eoo可以读取为mul(add(e, o), o)(e + o) * o以普通的中止符号表示。在e与第一o是对应于操作数+,以及+eo最后o是对应于操作数*

为了清楚起见,这是一些无效的输入,这些输入的前缀表示法不正确:

eo
ooe
o+e
ee*
+*oe
+e*o

输出中的单个尾随换行符就可以了,但否则,应该输出的是e偶数还是o奇数。

以字节为单位的最短代码获胜。

测试用例

(空行仅用于帮助从视觉上区分相似的案例。)

e -> e
o -> o

+ee -> e
+eo -> o
+oe -> o
+oo -> e
*ee -> e
*eo -> e
*oe -> e
*oo -> o

+e+ee -> e
+e+eo -> o
+e+oe -> o
+e+oo -> e
+e*ee -> e
+e*eo -> e
+e*oe -> e
+e*oo -> o

+o+ee -> o
+o+eo -> e
+o+oe -> e
+o+oo -> o
+o*ee -> o
+o*eo -> o
+o*oe -> o
+o*oo -> e

*e+ee -> e
*e+eo -> e
*e+oe -> e
*e+oo -> e
*e*ee -> e
*e*eo -> e
*e*oe -> e
*e*oo -> e

*o+ee -> e
*o+eo -> o
*o+oe -> o
*o+oo -> e
*o*ee -> e
*o*eo -> e
*o*oe -> e
*o*oo -> o

++eee -> e
++eeo -> o
++eoe -> o
++eoo -> e
++oee -> o
++oeo -> e
++ooe -> e
++ooo -> o

+*eee -> e
+*eeo -> o
+*eoe -> e
+*eoo -> o
+*oee -> e
+*oeo -> o
+*ooe -> o
+*ooo -> e

*+eee -> e
*+eeo -> e
*+eoe -> e
*+eoo -> o
*+oee -> e
*+oeo -> o
*+ooe -> e
*+ooo -> e

**eee -> e
**eeo -> e
**eoe -> e
**eoo -> e
**oee -> e
**oeo -> e
**ooe -> e
**ooo -> o

+e+e+e+ee -> e
+o+o+o+oo -> o
*e*e*e*ee -> e
*o*o*o*oo -> o
+e+o+e+oe -> e
+o+e+o+eo -> o
*e*o*e*oe -> e
*o*e*o*eo -> e
+e*e+e*ee -> e
+o*o+o*oo -> o
*e+e*e+ee -> e
*o+o*o+oo -> o

+**++*+*eeoeeooee -> e
+**++*+***eooeoeooeoe -> e
+**+***+**++**+eooeoeeoeeoeooeo -> o

+e*o*e**eoe -> e
+*e+e+o+e**eeoe -> e
**o++*ee*++eoe*eo+eoo -> o

8
我们可以用1和0代替e和o作为输入吗?
ghosts_in_the_code

8
@ghosts_in_the_code不,对不起。
卡尔文的爱好

2
使用eval确定吗?
xnor 2015年

1
@xnor当然。无论如何。
卡尔文的爱好2015年

2
我怀疑我可以用它来击败已经发布的13个字节,但是我注意到加法匹配一个异或或一个简单或。
WGroleau

Answers:


43

CJam,18 17 13字节

感谢aditsu节省了4个字节。

qW:O%eu~"eo"=

在这里尝试测试套件。(测试套件对于固定链接来说太长了。只需从挑战说明中复制它们即可。)

说明

q     e# Read the input.
W:O   e# Push a -1 and store it in variable O.
%     e# Use the -1 to reverse the string, because CJam's stack-based nature and the
      e# commutativity of the operators means we can evaluate the code in postfix notation.
eu    e# Convert the string to upper case, turning 'e' into 'E' (a variable with even value
      e# 14) and 'o' into 'O' (which we've stored the odd value -1 in).
~     e# Evaluate the string as CJam code, leaving the result on the stack.
"eo"= e# Use the result as an index into the string "eo". CJam's indexing is cyclic so it
      e# automatically takes inputs modulo 2. Negative indices also work as expected.

27

Pyth,16个 14字节

@"eo".vjdXzGU9

Pyth本身可以计算一个使用Pyth语法的字符串。因此,我代替eo45。然后评估将给我一个偶数或奇数,并且我可以轻松打印结果。

在线尝试:演示测试套件

说明:

@"eo".vjdXzGU9   implicit: z = input string
         XzGU9   replace "e" in z with 4 and "o" with 5
       jd        put a space between each char
     .v          evaluate it (Pyth style)
@"eo"            and print "e" or "o"

替换的附加说明。G是用字母初始化的变量abc...xyzU9是清单[0, 1, ..., 8]XzGU9用列表的值替换字母。所以a被替换为0b1...,e4...,i8j0,...,并o5。因此,我e被替换为偶数和o奇数。所有其他替代品完全无效。


为什么要反转表达式?另外,您是否不需要对模取2的结果,还是索引环绕了?
xnor 2015年

@xnor以模包装方式完成对字符串中元素的访问。因此,没有必要对模2
Jakube

@xnor但是,感谢相反的事情。当然这不是必须的。(我今天有点累了。)
Jakube 2015年

16

Perl,50 45 40个字符

(39个字符的代码+ 1个字符的命令行选项。)

1while s/\+oe|\+eo|\*oo/o/||s/\W\w\w/e/

样品运行:

bash-4.3$ echo -n '**o++*ee*++eoe*eo+eoo' | perl -pe '1while s/\+oe|\+eo|\*oo/o/||s/\W\w\w/e/'
o

怎么while/../
primo

h 我真笨 在尝试其sed版本时实际上使用了该条件…谢谢@primo。
manatwork

甚至更好1while s/\+oe...。我也很确定[+*]可以将替换为\W
primo

再次谢谢你,@ primo。我想我应该一次只专注于一个解决方案。(gema让我发疯…)
manatwork

与Sed相同的方法现在缩短了2个字节!
Digital Trauma 2015年

13

视网膜,29字节

(+`\*oo|\+(eo|oe)
o
\W\w\w
e

为了方便使用一个文件版本,-s使用了标志。

我们换奇表达式(*oo+oe+eo),以o直到我们可以,然后交换剩余的符号字母字母的表达式e。我们重复此过程,直到可以,最后一个字母是我们的输出。

(此解决方案类似于manatwork的Perl回答。)

在线尝试!(丹尼斯)


12

python 2,90

def f(s):i=iter(s);a=next(i);return(a>'a')*a or'oe'[f(i)==f(i)if'*'<a else'e'in f(i)+f(i)]

iter函数是使输入字符串进入FIFO队列的好方法,该队列记住在调用时已解析了多少字符串f。它是幂等的,因此当输入已经是迭代器而不是字符串时再次调用它是无害的。答案的后半部分以or'oe'... 开头似乎应该可以打高尔夫球,但我什么也找不到。

-1感谢Sp3000。


很好的解决方案!使用递归函数iter的确让我大吃一惊。
xnor 2015年

3
这是直接使用以下方法计算算术的方法evaldef f(s,e=0,o=1):i=iter(s);a=next(i);return'eo'[eval(a*(a>'a')or f(i)+a+f(i))%2]
xnor

1
@xnor您最好将其发布为答案。与该解决方案有很大不同。
feersum

9

Mathematica,91 84字节

#//.s_:>s~StringReplace~{"+ee"|"+oo"|"*ee"|"*eo"|"*oe"->"e","+eo"|"+oe"|"*oo"->"o"}&

寻找一种压缩方式...


3
//.比短FixedPoint
alephalpha

8

Python 2,80个字节

def f(s,e=0,o=1):i=iter(s);a=next(i);return(a>'a')*a or'eo'[eval(f(i)+a+f(i))%2]

这是基于feersum的非常聪明的答案构建的,该答案使用iter来实现波兰语符号操作。新的想法是使用eval来计算表达式+,并*eval(f(i)+a+f(i))中,操作人员a放置递归结果之间的中缀。eval使用e=0,o=1可选函数参数中的绑定。然后将输出设为mod 2。


这也适用于python3。顺便说一句,eval如何需要“ e = 0,o = 1”绑定?
karhell 2015年

@karhell它计算像的表达式e+o,因此它需要变量来引用数字。
xnor

8

C,79字节

直接递归。依赖于四个允许的输入字符的某些(巧合?)按位属性。

f(){int c=getchar();return c&4?c:c&1?f()^f()^'e':f()&f();}main(){putchar(f());}

8

Shell + GNU实用程序,33

dc -eFo`rev|tr oe OK`2%p|tr 10 oe

输入来自STDIN。

在这种情况下,这样做具有相同的技巧,即反转输入并使用基于堆栈的计算器求值dc。我们可以将eand 替换o0and 1,但随后需要插入空格以防止将数字贪婪地解析为错误的数字。

取而代之的e是将当前精度推入堆栈Kdc命令,默认情况下为0。而o替换O为的dc是将当前输出基数推入堆栈的命令。这应该是奇怪的,因此Fo在进行dc其他操作之前,我们将其设置为15 。

然后,只需采取mod 2并进行打印即可2%p。现在唯一的值是0and 1,因此输出基数为15无关紧要。然后tr转换为oor e


我喜欢你if着眼睛看,这个来源几乎就像dc Forever OK


5

严重的是,24个字节

,R'2'e(Æ'1'o(Æ£ƒ'e'o2(%I

更有效的堆栈操作可能会使时间更短,但是,我对此感到满意。

将输入作为字符串,例如 "+*oee"

在线尝试(输入必须手动输入)

说明:

,R        get input and reverse it
'2'e(Æ    replace all "e"s with "2"s
'1'o(Æ    replace all "o"s with "1"s
£ƒ        cast as function and call
'e'o2(%I  push "e" if result is even, else "o"

5

Ruby,61个字节

使用递归下降解析和布尔代数。

def f
gets(1)==?+?f^f : ~/\*/?f&f : $_==?o
end
puts f ? ?o:?e

该函数一次从stdin读取一个字符。如果读取a +或a *,它将调用两次以确定奇数或偶数。该函数返回true的奇数和falseeven。的^ XOR& AND运算符分别用于确定加法和乘法表达式的“奇”。

这是一个非高尔夫版本:

def f
  x = gets(1)
  case x
  when '+'
    f ^ f
  when '*'
    f & f
  else
    x == 'o'
  end
end

puts f ? 'o' : 'e'

感谢@Shel指出初始版本中的错误。


1
这是不行的,+eeo。我喜欢这个主意
-Shelvacu 2015年

更换f^f!f^ff&ff|f和它的作品。运行测试用例的程序:pastebin.com/ufXfd1vc
Shelvacu 2015年

1
谢谢,很好!似乎我在那里有些困惑。不错的测试套件!测试驱动是必经之路,也是打高尔夫球的时候:)
daniero 2015年

@谢尔阿哈..!我改回去f^ff&f然后翻转$_==?e?e:?o相反:)
daniero

1
哇,每天都学点新东西... ruby-doc.org/core/Regexp.html#method-i-7E
Shelvacu 2015年

4

Minkolang 0.14,40字节

我试图做一个聪明的eval方法,但事实证明,程序计数器永远无法到达添加到原始空间之外的代码箱中的任何值。所以我做了一个不太聪明的评估方法。:P

$o"eo+*"r0I4-[4g1Z2*1F]l*"e"+O.
0f1f+f*f

在这里尝试。

说明

$o                                Read in whole input as characters
  "eo+*"                          Push these characters onto the stack (in reverse order)
        r                         Reverse the stack
         I4-                      Push the length of the stack - 4
            [                     For loop; pop n and repeat that many times
             4g                   Get the item at the fourth index and put it on top
               1Z                 Pops n and pushes first index of n in stack
                 2*               Multiply by 2
                   1F             Gosub; goes to codebox(2n,1) to be returned to
                     ]            Close for loop
                      l*          Multiply by 10
                        "e"+      Add 101 ("o" is 111)
                            O.    Output as character and stop.
0f1f+f*f                          Does the appropriate operation then returns to F

1
hoo!好的 ol'shell击败了(半)打高尔夫球的语言;-P
Digital Trauma

4

JavaScript,110106 94字节

while(i.length>2)i=i.replace(/([+*][eo]{2})/,(o,e)=>{return"+oe+eo*oo".indexOf(o)<0?"e":"o"});

当然不是最小的解决方案,但可能是像JavaScript这样的冗长语言中可能的最小解决方案!


使用非捕获组有利于性能,但不利于代码大小。最好删除那些?:
manatwork 2015年

同意...这样修改。
Arkain 2015年

现在换了个样子。您的代码可以进一步简化为while(i.length>2)i=i.replace(/[+*][eo]{2}/,function(o){return"+oe+eo*oo".indexOf(o)>=0?"o":"e"})。或者,如果您更改为ECMAScript 6的粗箭头功能,则单击while(i.length>2)i=i.replace(/[+*][eo]{2}/,o=>"+oe+eo*oo".indexOf(o)>=0?"o":"e")。但是不幸的是,该要求是程序或函数,而您当前的代码只是一段代码。它应该处理输入和输出或参数和返回值。
manatwork

1
不幸的是,为了在此站点上有效,我们无法假定变量已经存在。您必须使其具有i您所说的功能。
Alex A.

1
@Arkain,您无需在正则表达式中捕获一个组,因为无论如何您将整个匹配的子字符串作为一个部分使用。出于相同的原因,无需将参数e传递给回调。
manatwork 2015年

4

O24 20 19 18字节

i`2:e;1:o;~2%'o'e?

取输入,它反转,分配e2o1帖子它的tumblr评估它作为O编码。

说明:

我`获取输入并反转输入,因为O使用后缀表示法
2:e; 将e分配给2
1:o; 将o分配给1
〜2%评估并检查结果是否均匀
'o'e?如果为偶数则输出“ e”,如果为奇数则输出“ o”

4

GNU Sed,36岁

:
s/*oo\|+eo\|+oe/o/
t
s/\W\w\w/e/
t

发布后,我看到了与@manatwork的Perl答案@randomra的Retina答案完全相同的方法。因此,我想我也最好一路走下去,并借用他们\W\w\w

感谢@Ruud削减了4个字节。


随着括号的消失,现在可以放弃扩展的正则表达式了。您会因不转义而赢得2个字节,而因转义+而会丢失2个字节|,但最终结果是您因放弃选项而获1个字节-r
Ruud Helderman 2015年

@Ruud是的。我以前尝试过,但是没有意识到不使用|时需要逃脱的需求-r。不过,比分还差2个字节-谢谢!
Digital Trauma 2015年

2

Haskell,160字节

致电f

f=until((==1).l)r
r s|l s<3=s|3#s?o=r('o':3%s)|3#s?sequence["+*","oe","oe"]=r('e':3%s)|0<1=1#s++r(1%s)
l=length
(#)=take
(%)=drop
(?)=elem
o=["+eo","+oe","*oo"]

2

JavaScript,92 71字节

f=i=>i>"0"?i:f(i.replace(/.[eo]{2}/,e=>"eo"[eval((e[1]>"e")+"^&"[+(e[0]<"+")]+(e[2]>"e"))]))

这有点令人困惑,但是我想使用eval按位运算符来做一些事情。注释:

f = (i) => // function(i) { return
    i>"0"  // i[0] == "o" || i[0] == "e" :-) - the characters `*` and `+` are both <"0"
      ? i  // finish
      : f(i.replace( // recursively repeat with
          /.[eo]{2}/, // first occurrence of "something" followed by two values
          (e) =>    // replaced by
              "eo"[ // string indexing
                eval(
                    (e[1]>"e")        // e[1] == "o" ? "true" : "false"
                  + "^&"[+(e[0]<"+")] // e[0] == "+" ? "^" : "&"
                  + (e[2]>"e")        // e[2] == "o" ? "true" : "false"
                )
              ]     // like eval(…) ? "o" : "e"
        ))

重复的操作(e[…]>"e")让我有些烦恼,但是下面的方法(103字节)也不好:

f=i=>i>"0"?i:f(i.replace(/e|o/g,x=>+(x>"e")).replace(/.\d\d/,e=>"eo"[eval(e[1]+"^&"[+(e[0]<"+")]+e[2])]))

因此,最后,@ Arkain的简单子字符串匹配方法非常出色。经过优化后制成一个函数:

f=i=>i>"0"?i:f(i.replace(/.[eo]{2}/,v=>"eo"[+"+oe+eo*oo".includes(v)]))

1

Dart,173个字节

f(i){var l=i.split(''),e='e',o='o';g(p){if(l[p]!=e&&l[p]!=o){var x=p+1,y=p+2;g(x);g(y);l[p]=l[p]=='+'?l[x]!=l[y]?o:e:l[x]==o?l[y]:e;l.removeRange(x,p+3);}}g(0);print(l[0]);}

这没有竞争力,但是无论如何。解决方案的要点是,从0开始,将每个运算符递归替换为该运算符后面的一对字符,然后从列表中删除这些字符。


1

Haskell,231个字节

这是一种使用严肃语言的方法;)

高尔夫球版:

p(s:_)[]=s
p s(x:y)=p(r$x:s)y
r[]=[]
r('e':'e':'+':x)=r$'e':x
r('e':'o':'+':x)=r$'o':x
r('o':'e':'+':x)=r$'o':x
r('o':'o':'+':x)=r$'e':x
r('e':'e':'*':x)=r$'e':x
r('e':'o':'*':x)=r$'e':x
r('o':'e':'*':x)=r$'e':x
r('o':'o':'*':x)=r$'o':x
r x=x

例:

*Main> p [] "+**+***+**++**+eooeoeeoeeoeooeo"
'o'

非高尔夫版本,非常全面:

type Stack = String

parse :: String -> Char
parse = parse' []

parse' :: Stack -> String -> Char
parse' (s:_) []     = s
parse' s     (x:xs) = parse' (reduce $ x:s) xs

reduce :: Stack -> Stack
reduce [] = []
reduce ('e':'e':'+':xs) = reduce $ 'e':xs
reduce ('e':'o':'+':xs) = reduce $ 'o':xs
reduce ('o':'e':'+':xs) = reduce $ 'o':xs
reduce ('o':'o':'+':xs) = reduce $ 'e':xs
reduce ('e':'e':'*':xs) = reduce $ 'e':xs
reduce ('e':'o':'*':xs) = reduce $ 'e':xs
reduce ('o':'e':'*':xs) = reduce $ 'e':xs
reduce ('o':'o':'*':xs) = reduce $ 'o':xs
reduce xs               = xs

例:

*Main> parse "+**+***+**++**+eooeoeeoeeoeooeo"
'o'

特点:模式匹配和递归。


1

Jolf,11个字节

(非竞争性的,因为该语言是该问题的最早提出者。)请在此处尝试!

FVyAi"oe"@\x12

(用\x12实际字符替换\x12。这应该在解释器中自动完成。)

说明:

FVyAi"oe"@\x12
    i          input
          \x12 character 12
         @     char code at
   A "oe"      replace all os with 1s and all es with 2s
  y            eval as jolf, returning the answer
 V             return parity "even" or "odd"
F              get first character
               implicit output

1

Python 3中,171个 145 135字节

没有竞争力,但是我做得很开心,所以我无法保持自己。与feersum的(非常聪明的)递归迭代器Python条目不同,该条目会反转输入,然后对旧的基于波兰语的反向波兰语表示法进行很好的解析。

def p(i):
 s=[]
 for c in i[::-1]:
  s+=[c>'e'if c>'a'else getattr(s.pop(),'__'+('axnodr'[c>'*'::2])+'__')(s.pop())]
 return'eo'[s[0]]

callable()很优雅,但是很长。(反转条件并除去条件not会更短。)相反,检查m是否为整数m in[0,1]会更短,但检查c是否为value c in'eo'会更短。稍后与c>'a'此情况相同。
manatwork 2015年

实际上,不需要变量m及其数值。仅将其放入以下内容fors+=[c>'e'if c>'a'else{'*':o.and_,'+':o.xor}[c](s.pop(),s.pop())]
manatwork 2015年

@manatwork:谢谢!我认为我无法逆转这种情况,因为我认为这意味着s.pop()每个循环都要调用(两次)。直到现在我才开始打扰。但是,现在要解决这个问题了。
蒂姆·佩德里克

从一开始就困扰着我一个问题:为什么要使用operator 模块?bool.__and__()并且bool.__xor__()是更加便利:s+=[c>'e'if c>'a'else getattr(s.pop(),{'*':'__and__','+':'__xor__'}[c])(s.pop())]。但是根据ni鱼切片技巧,可以更改为s+=[c>'e'if c>'a'else getattr(s.pop(),'__'+('axnodr'[c>'*'::2])+'__')(s.pop())]
manatwork 2015年

@manatwork:因为我没有想到。我只考虑了infix运算符(^&)及其operator对等运算符,而忽略了实际实现它们的方法。哦,reversed()由于另一个Python高尔夫技巧,现在已被删除。
蒂姆·佩德瑞克

1

Haskell,98 94字节

很抱歉再次尝试Haskell。只是想证明它在不到100个字节的情况下很有可能。

p(c:s)|any(<'a')s=p(c:p s)
p('+':x:y:s)|x/=y='o':s
p('*':'o':s)=s
p(c:_:_:s)|c<'a'='e':s
p s=s

定义一个函数p,该函数接受任何有效的表达式作为参数,并以长度为1的字符串返回结果。

例:

*Main> p "**o++*ee*++eoe*eo+eoo"
"o"

该函数的工作方式是反复减少字符串中最右边的运算符,直到没有剩余的运算符为止。


0

加++,46字节

D,g,@,d"oe"$eA"e"=+o
D,f,@,bR€gbU32CjbV2%"eo":

在线尝试!

页脚仅枚举所有示例输入及其对应的输出。

这个怎么运作

就像这里没有答案一样,它使用替换和评估。我们的主要功能是f,并且g是辅助功能。我们将以"*e*o*e*oe"(为e)作为示例。

f首先采用输入字符串并将其反转,从而产生"eo*e*o*e*"。然后,我们映射g每个元素:

g首先复制参数,直到最后一条命令之前都保留一个副本。然后,我们检查参数是否在字符串中"oe",字母是否为1,或则为0。然后,我们再次推送该参数,并检查其是否等于。然后将此结果添加到先前的检查中。这产生0为任一或,1对和2对。然后,我们在该值和参数之间进行逻辑或。如果值为0,则将其替换为参数(即或),否则将保持原样(即12)。*+"e"*+oe*+

它将所有与输入相反的字母转换为数值。然后,我们用空格将每个元素连接起来,以确保数字没有连接在一起。对于我们的示例,这将产生字符串"2 1 * 2 * 1 * 2 *"。然后,我们可以使用Add ++的后缀表示法对此进行评估,得出8。然后,我们对该值进行奇偶校验,在索引到字符串并返回相应的字母之前,对偶数产生0,对奇数产生1"eo"

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.