Entre parênteses uma expressão

20

Recentemente, eu escrevi um novo idioma . Para evitar a necessidade de lidar com a ordem das operações , simplesmente parênteses pare cada expressão corretamente para evitar isso completamente.

Como os parênteses estão nos códigos de caracteres 40 a 41, seu código precisará ser o mais curto possível.


Exemplos

1+2*3
(1+(2*3))

2*(3+4)
(2*(3+4))

2*3/4+3
(((2*3)/4)+3)

342*32/8
((342*32)/8)

Regras

As únicas operações que você precisará manipular são: *(multiplicação), /(divisão), +(adição) e -(subtração).

  • A ordem das operações é:
    • Parêntese
    • Multiplicação, Divisão
    • Adição, Subtração
  • Você deve preferir ir esquerda-direita
  • Os números de entrada sempre serão números inteiros positivos (ver bônus)

Bónus

-20% se você lida com negação:

3+-5
(3+(-5))

-5% se você permitir que espaços sejam colocados dentro da entrada:

3  + 4
(3+4)

-10% se você puder manipular casas decimais na entrada:

1+.12
(1+.12)
1+0.21/3
(1+(0.21/3))

Recompensa 500: se você conseguir escrever uma resposta em Sem nome / Blocos

Downgoat
fonte
25
"Como os parênteses estão nos códigos de caracteres 40 a 41, seu código precisará ser o mais curto possível." OK, agora você está sendo ridículo. ; P
ETHproductions
3
E isso é mais fácil do que a notação de prefixo (polonês) porque?
wizzwizz4
3
Possível duplicado .
flawr
8
Flawr @ eu vi isso, mas é muito diferente no fato de que essa pergunta tem saída de todas as maneiras entre parênteses uma expressão. Aqui você deve levar em conta a ordem das operações, que eu acho que é uma diferença significativa, pois o código não pode ser modificado trivialmente para esse desafio.
Downgoat
3
Caso de teste importante: 1+2+3+4(que certas soluções podem estar entre parênteses como ((1+2)+(3+4))) #
268 Martin Ender

Respostas:

2

Python, 153 * 0,9 = 137,7 bytes

def p(e):
 for o in"+-*/":
    for i,c in enumerate(e):
        if(c==o)*(0==sum([(d=="(")-(d==")")for d in e[:i]])):return"("+p(e[:i])+o+p(e[i+1:])+")"
 return e

Este programa lida com entrada decimal.

A segunda linha começa com um espaço, a segunda começa com uma guia, a terceira com duas guias e a terceira com um espaço. Isso salvou um byte. Aqui está um hexdump ( xxdpp):

0000000: 6465 6620 7028 6529 3a0a 2066 6f72 206f  def p(e):. for o
0000010: 2069 6e22 2b2d 2a2f 223a 0a09 666f 7220   in"+-*/":..for 
0000020: 692c 6320 696e 2065 6e75 6d65 7261 7465  i,c in enumerate
0000030: 2865 293a 0a09 0969 6628 633d 3d6f 292a  (e):...if(c==o)*
0000040: 2830 3d3d 7375 6d28 5b28 643d 3d22 2822  (0==sum([(d=="("
0000050: 292d 2864 3d3d 2229 2229 666f 7220 6420  )-(d==")")for d 
0000060: 696e 2065 5b3a 695d 5d29 293a 7265 7475  in e[:i]])):retu
0000070: 726e 2228 222b 7028 655b 3a69 5d29 2b6f  rn"("+p(e[:i])+o
0000080: 2b70 2865 5b69 2b31 3a5d 292b 2229 220a  +p(e[i+1:])+")".
0000090: 2072 6574 7572 6e20 650a                  return e.

Aqui está um programa que eu usei para testar: (Salve o programa acima como paren.py)

import paren

cases = {
        "2+3*4": "(2+(3*4))", 
        "(2+3)*4": "((2+3)*4)", 
        "1+2+3+4": "(1+(2+(3+4)))", 
        "3/2+5": "((3/2)+5)", 
        "1+2-3": "(1+(2-3))", 
        "2-1+2": "((2-1)+2)",
        "3+-5": "(3+(-5))",
        "1+.12": "(1+.12)",
        "1+0.21/3": "(1+(0.21/3))",
}


for num, case in enumerate(cases):
    print "\n\n\033[1m\033[38;5;14mCase #%d: %s" % (num + 1, case)
    result = paren.p(case)
    print "\033[38;5;4mParenthesize returned: %s" % (result)
    solution = cases[case]
    if result == solution:
        print "\033[38;5;76mCorrect!"
    else:
        print "\033[38;5;9mNot correct!"

Verifique se o seu terminal usa o \033[38;5;<COL>mcódigo de escape para cores.

Loovjo
fonte
* quarto com um espaço?
precisa
1
Este programa não prefer to go left-right. Experimente o caso de teste 3 no OP, seu resultado não está correto. Isso pode ser um problema real , por exemplo, com aritmética inteira ((2*(3/4))+3)(((2*3)/4)+3)
:!
1
@ user12365 Não está usando aritmética inteira (em C ou C ++ por exemplo) 3/4 == 0, então ((2 * (3/4)) + 3) é 3, enquanto ((((2 * 3) / 4) + 3) é 4
edc65
3

JavaScript (ES6) 179 (263 -20% -5% -10%)

(x,W=[],Q=['('],z=1,w=v='',h=p=>'*/+-))('.indexOf(p)|1,C=n=>{for(;h(q=Q.pop())<=h(n);)W[0]=`(${W[1]+q+W.shift()})`;z&&Q.push(q,n)})=>(x+')').replace(/[\d.]+|\S/g,t=>t>'('?t>')'?~h(t)?z?(w+='('+t,v+=')'):C(t,z=1):W=[w+t+v,...W,z=w=v='']:C(t,z=0):z=Q.push(t))&&W[0]

Como as outras duas respostas estão erradas, postarei as minhas. É uma variação do analisador de expressão que usei aqui e aqui e em outro lugar. Procure aqui explicações mais detalhadas sobre algoritmos.

É bastante volumoso, mas deve funcionar.

Snippet de teste

f=(x,W=[],Q=['('],z=1,w=v='',h=p=>'*/+-))('.indexOf(p)|1,C=n=>{for(;h(q=Q.pop())<=h(n);)W[0]=`(${W[1]+q+W.shift()})`;z&&Q.push(q,n)})=>(x+')').replace(/[\d.]+|\S/g,t=>t>'('?t>')'?~h(t)?z?(w+='('+t,v+=')'):C(t,z=1):W=[w+t+v,...W,z=w=v='']:C(t,z=0):z=Q.push(t))&&W[0]

// More readable
x=(x,W=[],Q=['('],z=1,w=v='',
  h=p=>'*/+-))('.indexOf(p)|1,
  C=n=>{
    for(;h(q=Q.pop())<=h(n);)W[0]=`(${W[1]+q+W.shift()})`;
    z&&Q.push(q,n)
  }
)=>(
  (x+')')
  .replace(/[\d.]+|\S/g,t=> 
       t>'('    
       ?t>')'
       ?~h(t)
       ?z
       ?(w+='('+t,v+=')')
       :C(t,z=1)
       :W=[w+t+v,...W,z=w=v=''] // overfill W to save 2 chars ()
       :C(t,z=0)
       :z=Q.push(t)
  ),
  W[0]
)

console.log=(...x)=>O.textContent+=x.join` `+'\n'

// TEST
;[
  ['1+2*3','(1+(2*3))'],['2*(3+4)','(2*(3+4))'],['2*3/4+3','(((2*3)/4)+3)'],['342*32/8','((342*32)/8)'],
  ['3+-5','(3+(-5))'],['-3+-4*7','((-3)+((-4)*7))'], // bonus 20%
  ['3  + 4','(3+4)'], // bonus 5%
  ['1+.12','(1+.12)'],['1+0.21/3','(1+(0.21/3))'] // bonus 10%
].forEach(t=>{var k=t[1],i=t[0],r=f(i); console.log(i+' : '+r+(r==k? ' OK':' Fail expecting '+k))})
<pre id=O></pre>

edc65
fonte
1

Python, 241 * 0,8 * 0,95 * 0,9 = 164,84 caracteres

Estou usando a biblioteca ast (Abstract Syntax Trees) e um dict de substituição de string de homebrew. A substituição da corda custa muito, mas o bônus ajuda a manter a pontuação um pouco baixa. Talvez (a peça de substituição da corda) possa ser jogada ainda mais.

Observe que esta solução adiciona um conjunto extra de parênteses em torno de cada número, mas acho que isso está dentro do espírito da pergunta

import ast;def p(e):
 r,s={"Module([":"",")])":"","Expr(":"","BinOp":"","Num":"",", Add(), ":"+",", Sub(), ":"-",", Div(), ":"/",", Mult(), ":"*"},ast.dump(ast.parse(e),annotate_fields=False)
 for f,t in r.iteritems():s=s.replace(f,t)
 return s

Suíte de teste:

cases = {
    "2+3*4", 
    "(2+3)*4", 
    "1+2+3+4", 
    "3/2+5", 
    "1+2-3", 
    "2-1+2",
    "3+-5",
    "1+.12",
    "1+0.21/3"
}

for num,case in enumerate(cases):
    result = p(case)
    print "Case {}: {:<16} evaluates to: {}".format(num+1,case,result)

Saída do conjunto de testes:

Case 1: 3+-5             evaluates to: ((3)+(-5))
Case 2: 3/2+5            evaluates to: (((3)/(2))+(5))
Case 3: 2+3*4            evaluates to: ((2)+((3)*(4)))
Case 4: 1+2+3+4          evaluates to: ((((1)+(2))+(3))+(4))
Case 5: 1+0.21/3         evaluates to: ((1)+((0.21)/(3)))
Case 6: (2+3)*4          evaluates to: (((2)+(3))*(4))
Case 7: 2-1+2            evaluates to: (((2)-(1))+(2))
Case 8: 1+.12            evaluates to: ((1)+(0.12))
Case 9: 1+2-3            evaluates to: (((1)+(2))-(3))
de qualquer maneira
fonte
Faltando import astno seu código
edc65
E esse não é o caminho certo para obter bônus percentuais. Se você obtiver um desconto de 50% e, além disso, outro de 50%, não estará pagando 0. Sua pontuação deve ser 157,32 (algo mais depois de adicionar a linha de importação). Essa é uma boa pontuação - vou votar se você fizer o conserto #
edc65
Bom ponto. Adicionada a importação. 241 caracteres agora. Não tenho certeza de como calcular o bônus. Se eu entendi o seu comentário corretamente, a ordem na qual o bônus é subtraído é importante ...
agtoever 30/12/15
O bônus não é subtraído (é uma multiplicação) e a ordem não importa. 241 * (1-20%) * (1-5%) * (1-10%) => * 241 0,8 * 0,95 * 0,9 => 164,84
edc65
@ edc65 Ah. Direita. Não estava pensando direito. Obrigado.
agtoever