วงเล็บนิพจน์


20

เมื่อเร็ว ๆ นี้ฉันได้เขียนภาษาใหม่เพื่อหลีกเลี่ยงความจำเป็นในการดำเนินการตามลำดับฉันเพียงแค่วงเล็บแต่ละนิพจน์ให้ถูกต้องเพื่อหลีกเลี่ยงปัญหานี้โดยสิ้นเชิง

เนื่องจากวงเล็บอยู่ที่ char-codes 40-41 รหัสของคุณจะต้องสั้นที่สุด


ตัวอย่าง

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)

กฎระเบียบ

การดำเนินการเดียวที่คุณจะต้องจัดการคือ: *(การคูณ), /(การหาร), +(การเพิ่ม) และ-(การลบ)

  • คำสั่งของการดำเนินงานคือ
    • วงเล็บ
    • การคูณ, การหาร
    • Adition การลบ
  • คุณควรไปทางซ้ายขวา
  • ตัวเลขที่ป้อนจะเป็นจำนวนเต็มบวกเสมอ (ดูโบนัส)

โบนัส

-20%ถ้าคุณจัดการกับการปฏิเสธ:

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

-5%ถ้าคุณอนุญาตให้มีช่องว่างที่จะอยู่ภายในอินพุต:

3  + 4
(3+4)

-10%ถ้าคุณสามารถจัดการทศนิยมในอินพุต:

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

500 เงินรางวัล:ถ้าคุณสามารถเขียนคำตอบในUnnamed / Blocks


25
"เนื่องจากวงเล็บอยู่ที่รหัสถ่าน 40-41 รหัสของคุณจะต้องสั้นที่สุด" ตกลงตอนนี้คุณแค่ไร้สาระธรรมดา ; P
ETHproductions

3
และสิ่งนี้ง่ายกว่าเครื่องหมายนำหน้า (โปแลนด์) เพราะ?
wizzwizz4

3
เป็นไปได้ที่ซ้ำกัน
ข้อบกพร่อง

8
@ flawr ฉันเห็นว่า แต่มันแตกต่างกันมากในความจริงที่ว่าคำถามที่คุณส่งออกทุกวิธีวงเล็บแสดงออก ที่นี่คุณต้องคำนึงถึงลำดับการดำเนินการซึ่งฉันคิดว่าเป็นข้อแตกต่างที่สำคัญเนื่องจากรหัสไม่สามารถแก้ไขได้เล็กน้อยสำหรับความท้าทายนี้
Downgoat

3
กรณีทดสอบที่สำคัญ: 1+2+3+4(ซึ่งโซลูชั่นบางตัวอาจเป็นวงเล็บ((1+2)+(3+4)))
Martin Ender

คำตอบ:


2

Python, 153 * 0.9 = 137.7 ไบต์

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

โปรแกรมนี้จัดการอินพุตทศนิยม

บรรทัดที่สองเริ่มต้นด้วยช่องว่างบรรทัดที่สองเริ่มต้นด้วยแท็บบรรทัดที่สองที่มีสองแท็บและบรรทัดที่สามที่มีช่องว่าง บันทึกนี้หนึ่งไบต์ นี่คือ 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.

นี่คือโปรแกรมที่ฉันใช้สำหรับการทดสอบ: (บันทึกโปรแกรมด้านบนเป็น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!"

ตรวจสอบให้แน่ใจว่าเทอร์มินัลของคุณใช้\033[38;5;<COL>mรหัสยกเว้นสำหรับสี


* สี่ด้วยช่องว่าง?
Element118

1
prefer to go left-rightโปรแกรมนี้ไม่ได้ ลองกรณีทดสอบ 3 ใน OP ผลลัพธ์ของคุณไม่ถูกต้อง นี่อาจเป็นปัญหาจริงเช่นด้วยเลขจำนวนเต็ม: ((2*(3/4))+3)! =(((2*3)/4)+3)
edc65

1
@ user12365 ไม่ใช้เลขจำนวนเต็ม (ใน C หรือ C ++) 3/4 == 0 ดังนั้น ((2 * (3/4)) +3) คือ 3 ในขณะที่ ((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]

ในขณะที่อีกสองคำตอบนั้นผิดทั้งคู่ฉันจะโพสต์ของฉัน มันเป็นรูปแบบของตัวแยกวิเคราะห์นิพจน์ที่ฉันใช้ที่นี่และที่นี่และที่อื่น ดูคำอธิบายอัลกอริทึมที่มีรายละเอียดเพิ่มเติม

มันค่อนข้างใหญ่ แต่ควรใช้งานได้

ตัวอย่างการทดสอบ

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>


1

Python 241 * 0.8 * 0.95 * 0.9 = 164.84 ตัวอักษร

ฉันกำลังใช้ห้องสมุด ast (Abstract Syntax Trees)และการแทนที่สตริงโฮมบรูว์ การแทนที่สตริงมีค่าใช้จ่ายสูง แต่โบนัสช่วยให้คะแนนค่อนข้างต่ำ บางที (ส่วนการเปลี่ยนสตริง) สามารถเล่นกอล์ฟเพิ่มเติม

โปรดทราบว่าวิธีนี้จะเพิ่มวงเล็บจำนวนมากรอบ ๆ แต่ละหมายเลข แต่ฉันคิดว่านั่นเป็นสิ่งที่อยู่ในใจของคำถาม

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

ชุดทดสอบ:

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)

ผลลัพธ์ของชุดทดสอบ:

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))

ไม่มีimport astรหัสของคุณ
edc65

และนั่นไม่ใช่วิธีที่ถูกต้องในการรับโบนัสเป็นเปอร์เซ็นต์ หากคุณได้รับส่วนลด 50% และที่เหลืออีก 50% คุณจะไม่ได้รับการจ่าย 0 คะแนนของคุณควรเป็น 157.32 (มีอะไรเพิ่มเติมหลังจากเพิ่มบรรทัดการนำเข้า) นั่นเป็นคะแนนที่ดี - ฉันจะโหวตถ้าคุณแก้ไขได้
edc65

จุดดี. เพิ่มการนำเข้า 241 ตัวอักษรในขณะนี้ ไม่แน่ใจว่าจะคำนวณโบนัสอย่างไร ถ้าฉันเข้าใจความคิดเห็นของคุณถูกต้องลำดับที่โบนัสจะถูกหักออก ...
agtoever

โบนัสจะไม่ถูกหัก (เป็นการคูณ) และการสั่งซื้อนั้นไม่สำคัญ 241 * (1-20%) * (1-5%) * (1-10%) => 241 * 0.8 * 0.95 * 0.9 => 164.84
edc65

@ edc65 Ah ขวา. ไม่ได้คิดมาก ขอบคุณ
agtoever
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.