Gereksiz parantezleri kaldırın


32

Karakterlerden oluşan bir dize verilir 0123456789+*(). Dize her zaman geçerli bir matematiksel ifade olduğunu varsayalım.

Göreviniz, çarpma işleminin eklemekten daha yüksek önceliğe sahip olduğunu varsayarak, gereksiz parantezleri kaldırmaktır.

Parantezler yalnızca yapısal olarak gerekmediklerinde çıkarılmalıdır :

  • çarpma nedeniyle daha yüksek öncelik: 3+(4*5)=>3+4*5
  • çarpma veya toplama ilişkililiği nedeniyle: 3*(4*5)=>3*4*5
  • bunlar bir ifadede etrafında gereksiz olduğunda: 3*((4+5))=>3*(4+5)

Parantezler , belirli sayı değerlerinden dolayı basitleştirildiklerinde tutulmalıdır :

  • 1*(2+3) sadeleştirilmemeli 1*2+3
  • 0*(1+0) sadeleştirilmemeli 0*1+0

Örnekler:

(4*12)+11         ==>    4*12+11
(1+2)*3           ==>    (1+2)*3
3*(4*5)           ==>    3*4*5
((((523))))       ==>    523
(1+1)             ==>    1+1
1*(2*(3+4)*5)*6   ==>    1*2*(3+4)*5*6
1*(2+3)           ==>    1*(2+3)
0*(1+0)           ==>    0*(1+0)


(((2+92+82)*46*70*(24*62)+(94+25))+6)    ==>    (2+92+82)*46*70*24*62+94+25+6

1
Daha fazla test vitrin lütfen?
Sızdıran Rahibe,

2
1*(2*(3+4)*5)*6ilginç bir testcase (çözümümün şu anda başarısız olduğu) olmalıdır.
Sızdıran Rahibe,

8
“Gereksiz” yapısal olarak mı yoksa duruma göre mi tanımlanır ? Başka bir deyişle, burada parantez gerekli değil mi? (2+2)*1
Luis Mendo

2
@LuisMendo Her iki şekilde de yorumlamanın doğru olduğunu düşünüyorum
anatolyg

2
@anatolyg Bunun adil olacağını düşünmüyorum, çünkü ikisi için yaklaşımlar çok farklı olurdu. Bir açıklama yapsak iyi olur.
Sp3000

Yanıtlar:


15

Mathematica, 105 97 91 bayt

-6 Roman sayesinde bayt !

a=StringReplace;ToString@ToExpression@a[#,{"*"->"**","+"->"~~"}]~a~{" ** "->"*","~~"->"+"}&

Yerini +ve *ile ~~( StringExpression) ve **( NonCommutativeMultiply), sırasıyla, stringifies, bunu değerlendirir ve geri operatörlerini değiştirir.


Ne? Mathematica'da yerleşik değil mi?
Outgolfer Erik,

@EriktheGolfer Temelde yapar; Bunu yapmaya çalışıyorum değil operatörleri değerlendirir.
LegionMammal978

Bu yüzden Mathematica, reklamını yaptığını ve çok pahalı olduğunu düşünüyorum. Ancak, eğer bulmaca yeterince sert ise, Mathematica'nın diğer diller üzerinde bir değişikliği olmaz, ancak “diğer diller” burada hiç rekabet etmez.
Outgolfer Erik,

91 baytStringExpression yerine kullanarak Dotve " "->""maddeyi kaldırarak :a=StringReplace;ToString@ToExpression@a[#,{"*"->"**","+"->"~~"}]~a~{" ** "->"*","~~"->"+"}&
Roman

@Roman Teşekkürler! Görünüşe göre, sayılarla birleştirmeyen, başka bir değişmeli, değişmeyen, değer biçilmemiş işleç bulmuş gibisin.
LegionMammal978

7

JavaScript (ES6) 163 178

15 bayt düzenle thx @IsmaelMiguel kaydetti

a=>eval(`s=[]${_=';for(b=0;a!=b;a=b.replace(/'}\\(([^()]*)\\)(?=(.?))/,(x,y,z,p)=>~y.indexOf('+')?-s.push(b[p-1]=='*'|z=='*'?x:y):y))b=a;${_}-\\d+/,x=>s[~x]))b=a`)

Daha az golf oynadı

a=>{
  for(s=[],b='';
      a!=b;
      a=b.replace(/\(([^()]*)\)(?=(.?))/,(x,y,z,p)=>y.indexOf('+')<0?y:-s.push(b[p-1]=='*'|z=='*'?x:y)))
    b=a;
  for(b=0;
      a!=b;
      a=b.replace(/-\d+/,x=>s[~x]))
    b=a;
  return a
}

Ölçek

f=a=>eval(`s=[]${_=';for(b=0;a!=b;a=b.replace(/'}\\(([^()]*)\\)(?=(.?))/,(x,y,z,p)=>~y.indexOf('+')
?-s.push(b[p-1]=='*'|z=='*'?x:y)
:y))b=a;${_}-\\d+/,x=>s[~x]))b=a`)

console.log=x=>O.textContent+=x+'\n'

test=`(4*12)+11         ==>    4*12+11
(1+2)*3           ==>    (1+2)*3
3*(4*5)           ==>    3*4*5
((((523))))       ==>    523
(1+1)             ==>    1+1
1*(2*(3+4)*5)*6   ==>    1*2*(3+4)*5*6
1*(2+3)           ==>    1*(2+3)
0*(1+0)           ==>    0*(1+0)
(((2+92+82)*46*70*(24*62)+(94+25))+6)    ==>    (2+92+82)*46*70*24*62+94+25+6`

test.split`\n`.forEach(r=>{
  var t,k,x
  [t,,k]=r.match(/\S+/g)
  x=f(t)
  console.log((x==k?'OK ':'KO ')+t+' -> '+x+(x==k?'':' expected '+k))
})
<pre id=O></pre>


y.indexOf('+')Bunun yerine neden yazdın y.indexOf`+`[...]? ([...] biçimlendirmeyi engellememek için eklendi) Bu yoldan mı çıkıyordu?
Ismael Miguel,

1
Buyrun, 170 bayt:a=>eval(`for(b=s=[]${_=';a!=b;a=b.replace(/'}\\(([^()]*)\\)(?=(.?))/,(x,y,z,p)=>~y.indexOf('+')<0?-s.push(b[p-1]=='*'|z=='*'?x:y):y))b=a;for(b=0${_}-\\d+/,x=>s[~x]))b=a`)
Ismael Miguel

@IsmaelMiguel gerçekten zekice, teşekkürler!
Alınan

Kodunuzu azaltmak için basit bir çözüm benim sevdim sevindim. Ben bir şeyler yapmak isterdim for(b=, =='*'ve diğer tekrarlanan bit. Ayrıca, değil ~y.indexOf('+')<0aynı ~y.indexOf('+')? indexOf()Sahte bir değere geri dönen tek değer olduğundan -1, <0fazlalık görünüyor. Ya da yanlış yaparsam yapabilirsiny.indexOf('+')>1
Ismael Miguel

@IsmaelMiguel 1: evet, <0ungolfed versiyonundan kalan saçmalıktır ve çıkarılmalıdır. 2: tekrar düşünerek for, tekrarlanan bölüme dahil edilmek üzere revize edilebilir. Tekrar teşekkürler
edc65

5

Python'da Python3 + PEG Uygulaması , 271 bayt

import peg
e=lambda o,m=0:o.choice and str(o)or(m and o[1][1]and"("+e(o[1])+")"or e(o[1]))if hasattr(o,"choice")else o[1]and e(o[0],1)+"".join(str(x[0])+e(x[1],1)for x in o[1])or e(o[0])
print(e(peg.compile_grammar('e=f("+"f)*f=p("*"p)*p="("e")"/[0-9]+').parse(input())))

Bir süre önce Python'da bir PEG uygulaması yaptım . Sanırım bunu burada kullanabilirim.

İfadeyi bir ağaca ayrıştırır ve yalnızca çocuk eklenirse ve üst çarpma ise parantezi tutar.


4

Perl, 132 bayt

-pBayrak için 129 bayt kaynak + 3 :

#!perl -p
0while s!\(([^\(\)]+)\)!$f{++$i}=$1,"_$i"!e;s!_$i!($v=$f{$i})=~/[+]/&&($l.$r)=~/[*]/?"($v)":$v!e
while($l,$i,$r)=/(.?)_(\d+)(.?)/

Kullanımı:

echo "1*(2*(3+4)*5)*6" | perl script.pl

4

Ruby, 140 130 bayt

127 bayt kaynak için + 3 -pbayrak:

t={}
r=?%
0while$_.gsub!(/\(([^()]+)\)/){t[r+=r]=$1;r}
0while$_.gsub!(/%+/){|m|(s=t[m])[?+]&&($'[0]==?*||$`[/\*$/])??(+s+?):s}

Ve asılsız:

tokens = Hash.new
key = '%'

# convert tokens to token keys in the original string, innermost first
0 while $_.gsub!(/\(([^()]+)\)/) { # find the innermost parenthetical
  key += key # make a unique key for this token
  tokens[key] = $1
  key # replace the parenthetical with the token key in the original string
}

# uncomment to see what's going on here
# require 'pp'
# pp $_
# pp tokens

# convert token keys back to tokens, outermost first
0 while $_.gsub!(/%+/) {|key|
  str = tokens[key]
  if str['+'] and ($'[0]=='*' or $`[/\*$/]) # test if token needs parens
    '(' + str + ')'
  else
    str
  end
}
# -p flag implicity prints $_

çok güzel cevap 0 whilesözdiziminde neler oluyor ?
Jonah

1
@Jonah Ruby'de expr while condeşittir while cond; expr; end. Burada, sadece condtekrar tekrar yapmak istiyorum ve aslında bir döngü gövdesi yok. Genellikle biri bunu while cond; endveya belki olarak yazardı loop{ break unless cond }ama 0 while conddaha az bayt. Bu 0hiçbir şey yapmaz; sadece orada çünkü while döngüsünün kısa şekli bir vücuda ihtiyaç duyar.
ezrast

2

Retina, 155 bayt

{`\(((\d+|\((((\()|(?<-5>\))|[^()])*(?(5)^))\))(\*(\d+|\((((\()|(?<-10>\))|[^()])*(?(10)^))\)))*)\)
$1
(?<!\*)\((((\()|(?<-3>\))|[^()])*(?(3)^))\)(?!\*)
$1

Çevrimiçi deneyin!

Tüm test durumlarını bir kerede doğrulayın.

açıklama

Önemli olan bu kod:

(((\()|(?<-3>\))|[^()])*(?(3)^)

Bu regex, parantezlerin dengeli olduğu herhangi bir dizeyle eşleşebilir, örneğin 1+(2+(3))+4veya 2+3.

Açıklama kolaylığı için, bu regex olsun B .

Ayrıca bize kullanmak <ve >bunun yerine parantez yanı sıra için pve miçin \+ve \*.

Kod olur:

{`<((\d+|<B>)(m(\d+|<B>))*)>
$1
(?<!m)<B>(?!m)
$1

İlk iki satır yalnızca çarpma işleminden oluşan, örneğin (1*2*3)veya hatta(1*(2+3)*4) . İçlerindeki içerikleri ile değiştirilirler.

Son iki satır, daha önce çarpılmayan ve takip etmeyen braketler için eşleşir. İçlerindeki içerikleri ile değiştirilirler.

İlk {` , "başarısız olana kadar değiştir" anlamına gelir, yani değiştirmeler, artık eşleşmeyene veya kendileriyle değiştirilinceye kadar yapılır.

Bu durumda, değiştirmeler artık uyuşmayana kadar yapılır.


İçin başarısız 1*(2*(3+4)*5)*6.
orlp

@orlp Teşekkürler, düzeltildi.
Sızdıran Rahibe,

Başarısız oluyor(1*(2+3)+4)*5
Sp3000 11

@ Sp3000 Teşekkürler, düzeltildi.
Sızdıran Rahibe,

2

Python 3, 274 269 359 337 336 bayt

Bu yöntem temelde her bir parantez çiftini kaldırır ve hala aynı olup olmadığını görmek için kontrol eder.

from re import *
def f(x):
    *n,=sub('\D','',x);x=sub('\d','9',x);v,i,r,l=eval(x),0,lambda d,a,s:d.replace(s,"?",a).replace(s,"",1).replace("?",s),lambda:len(findall('\(',x))
    while i<l():
        j=0
        while j<l():
            h=r(r(x,i,"("),j,")")
            try:
                if eval(h)==v:i=j=-1;x=h;break
            except:0
            j+=1
        i+=1
    return sub('9','%s',x)%tuple(n)

Test Demeti

print(f("(4*12)+11")=="4*12+11")
print(f("(1+2)*3") =="(1+2)*3")
print(f("3*(4*5)")=="3*4*5")
print(f("((((523))))")=="523")
print(f("(1+1)")=="1+1")
print(f("1*(2*(3+4)*5)*6")=="1*2*(3+4)*5*6")
print(f("(((2+92+82)*46*70*(24*62)+(94+25))+6)")=="(2+92+82)*46*70*24*62+94+25+6")
print(f("1*(2+3)")=="1*(2+3)")
print(f("0*(1+0)")=="0*(1+0)")

Güncellemeler

  • -1 [16-10-04] Ekstra alan kaldırıldı
  • -22 [16-05-07] reLib kullanıldı
  • +90 [16-05-07] Yeni sınav davalarını ele almak için güncellendi
  • -5 [16-05-07] Uzunluk ( l) lambda'dan parametre kaldırıldı

1
Bu, test durumundaki başarısızlığı 1*(2+3), çünkü OP, özel sayı durumları için basitleştirmediğini söyledi. Yine de iyi cevap; Bu benim artı oyum var.
HyperNeutrino

1
@AlexL. Onu yakaladığın için teşekkürler! Test durumlarımı güncellemedim D: Ama şimdi düzeltildi.
NonlinearFruit

1

PHP, 358 bayt

function a($a){static$c=[];$d=count($c);while($g=strpos($a,')',$g)){$f=$a;$e=0;for($j=$g;$j;--$j){switch($a[$j]){case')':++$e;break;case'(':--$e;if(!$e)break 2;}}$f[$g++]=$f[$j]=' ';if(eval("return $f;")==eval("return $a;"))$c[str_replace(' ', '', $f)]=1;}if(count($c)>$d){foreach($c as$k=>$v){a($k);}}return$c;}$t=a($argv[1]);krsort($t);echo key($t);

Etkileyici bir uzunluk değil, en uygun yaklaşımdan daha azını almak için elde ettiğim (ve en uygun dili daha az kullandığım için).

Bir çift braketi dışarı çıkarır, sonra ortaya çıkan ifadeyi değiştirir. Sonuç, orijinal ile aynıysa, yeni ifadeler bulana kadar geçerli ifadeler ve özyinelemeler haritasına ekler. Sonra en kısa geçerli ifadeyi yazdırır.

İfadenin sonucu büyüyünce ve çift / üs notasyonunda atma göründüğünde kırılır.


1

Prolog (SWI) , 122 118 bayt

T+S:-term_string(T,S).
I/O:-X+I,X-Y,Y+O.
E-O:-E=A+(B+C),A+B+C-O;E=A*(B*C),A*B*C-O;E=..[P,A,B],A-X,B-Y,O=..[P,X,Y];E=O.

Çevrimiçi deneyin!

//2Parantezleri ilk argümanının dize değerinden kaldıran ve bir ikinci argümandan bir dize çıktı veren bir yüklem tanımlar . Girdi Prolog terimlerinde olabiliyorsa, bu yalnızca ayrıntıyla uğraşmak zorunda kalmadan tanımlayan 81 77 bayt olabilirdi , ancak çok fazla gereksiz parantez bu şekilde başlamak zorunda kalmayacaktı, bu yüzden hile yapmaya oldukça yakın olacaktı, çünkü tek yapması gereken ilişkilendirmedir.+/2term_string/2+/2

Kullanmaya çalıştım =../2Bunların hepsini , ancak çok uzun sürdü, çünkü listelerde çalışan üç baytlık bir operatör tam tersine değil:

Prolog (SWI) , 124 bayt

T+S:-term_string(T,S).
I/O:-X+I,X-Y,Y+O.
X-Y:-X=..[O,A,B],(B=..[O,C,D],E=..[O,A,C],F=..[O,E,D],F-Y;A-C,B-D,Y=..[O,C,D]);X=Y.

Çevrimiçi deneyin!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.