วิธีเล่นกอล์ฟด้วยการเรียกซ้ำ
การเรียกซ้ำแม้ว่าจะไม่ใช่ตัวเลือกที่เร็วที่สุด แต่มักจะสั้นที่สุด โดยทั่วไปการเรียกซ้ำนั้นสั้นที่สุดหากโซลูชันสามารถทำให้การแก้ปัญหาง่ายขึ้นสำหรับส่วนเล็ก ๆ ของความท้าทายโดยเฉพาะอย่างยิ่งถ้าอินพุตเป็นตัวเลขหรือสตริง ตัวอย่างเช่นหากf("abcd")
สามารถคำนวณได้จาก"a"
และf("bcd")
มักจะใช้การเรียกซ้ำ
ยกตัวอย่างเช่นแฟคทอเรียล:
n=>[...Array(n).keys()].reduce((x,y)=>x*++y,1)
n=>[...Array(n)].reduce((x,_,i)=>x*++i,1)
n=>[...Array(n)].reduce(x=>x*n--,1)
n=>{for(t=1;n;)t*=n--;return t}
n=>eval("for(t=1;n;)t*=n--")
f=n=>n?n*f(n-1):1
ในตัวอย่างนี้การเรียกซ้ำเป็นทางสั้นกว่าตัวเลือกอื่น ๆ อย่างชัดเจน
วิธีการเกี่ยวกับผลรวมของ charcodes:
s=>[...s].map(x=>t+=x.charCodeAt(),t=0)|t
s=>[...s].reduce((t,x)=>t+x.charCodeAt())
s=>[for(x of(t=0,s))t+=x.charCodeAt()]|t // Firefox 30+ only
f=s=>s?s.charCodeAt()+f(s.slice(1)):0
หนึ่งนี้เป็น trickier .map
แต่เราจะเห็นว่าเมื่อดำเนินการอย่างถูกต้องจะช่วยประหยัดการเรียกซ้ำมากกว่า
ทีนี้ลองดูการเรียกซ้ำแบบต่างๆ:
Pre-เรียกซ้ำ
นี่เป็นประเภทการเรียกซ้ำที่สั้นที่สุด การป้อนข้อมูลที่ถูกแบ่งออกเป็นสองส่วนa
และb
และฟังก์ชั่นคำนวณสิ่งที่มีและa
f(b)
กลับไปที่ตัวอย่างปัจจัยของเรา:
f=n=>n?n*f(n-1):1
ในกรณีนี้a
คือn , b
เป็นn-1a*f(b)
และค่าที่ส่งกลับคือ
หมายเหตุสำคัญ:ฟังก์ชันเรียกซ้ำทั้งหมดจะต้องมีวิธีหยุดการเรียกซ้ำเมื่ออินพุตมีขนาดเล็กพอ ในฟังก์ชั่นแฟกทอเรียลนี่คือการควบคุมด้วยn? :1
เช่นถ้าอินพุตเป็น0ส่งคืน1โดยไม่ต้องโทรf
อีกครั้ง
โพสต์เรียกซ้ำ
โพสต์ - เรียกซ้ำคล้าย pre- ซ้ำ แต่แตกต่างกันเล็กน้อย การป้อนข้อมูลที่ถูกแบ่งออกเป็นสองส่วนa
และb
และฟังก์ชั่นคำนวณสิ่งที่มีแล้วโทรออกa
f(b,a)
อาร์กิวเมนต์ที่สองมักจะมีค่าเริ่มต้น (เช่นf(a,b=1)
)
การเรียกซ้ำล่วงหน้าเป็นสิ่งที่ดีเมื่อคุณต้องทำอะไรเป็นพิเศษด้วยผลลัพธ์สุดท้าย ตัวอย่างเช่นหากคุณต้องการแฟคทอเรียลของตัวเลขบวก 1:
f=(n,p=1)=>n?f(n-1,n*p):p+1
อย่างไรก็ตามถึงกระนั้นการโพสต์ก็ยังไม่สั้นกว่าการใช้การเรียกซ้ำล่วงหน้าภายในฟังก์ชั่นอื่น:
n=>(f=n=>n?n*f(n-1):1)(n)+1
ดังนั้นเมื่อมันสั้นลง? คุณอาจสังเกตเห็นว่าการโพสต์ซ้ำในตัวอย่างนี้ต้องใช้วงเล็บรอบ ๆ อาร์กิวเมนต์ของฟังก์ชั่นในขณะที่การสอบถามซ้ำไม่ได้ โดยทั่วไปหากทั้งสองโซลูชันต้องการวงเล็บล้อมรอบข้อโต้แย้งการโพสต์ซ้ำจะสั้นกว่าประมาณ 2 ไบต์:
n=>!(g=([x,...a])=>a[0]?x-a.pop()+g(a):0)(n)
f=([x,...a],n=0)=>a[0]?f(a,x-a.pop()+n):!n
(โปรแกรมที่นำมาจากคำตอบนี้ )
วิธีการหาทางออกที่สั้นที่สุด
โดยปกติแล้ววิธีเดียวที่จะหาวิธีที่สั้นที่สุดคือลองทั้งหมด รวมถึง:
- ลูป
.map
(สำหรับสตริงอย่างใดอย่างหนึ่ง[...s].map
หรือs.replace
; สำหรับตัวเลขคุณสามารถสร้างช่วง )
- ความเข้าใจของอาเรย์
- การเรียกซ้ำล่วงหน้า (บางครั้งอยู่ในตัวเลือกอื่นเหล่านี้)
- โพสต์เรียกซ้ำ
และนี่เป็นเพียงวิธีแก้ปัญหาที่พบบ่อยที่สุด ทางออกที่ดีที่สุดอาจจะมีการรวมกันของเหล่านี้หรือแม้กระทั่งบางสิ่งบางอย่างที่แตกต่างกันอย่างสิ้นเชิง วิธีที่ดีที่สุดที่จะหาวิธีการแก้ปัญหาที่สั้นที่สุดคือการพยายามทำทุกอย่าง