ไดนามิกโปรแกรมมิงไม่ใช่เวทมนตร์
- ไดนามิกโปรแกรมมิงเป็นเทคนิคที่ใช้แก้ปัญหาซับซ้อน โดยแบ่งปัญหาออกเป็นปัญหาย่อย ๆ แล้วค่อยจัดการ
- เทคนิคนี้เป็นสิ่งที่เป็นธรรมชาติ และอัลกอริทึมทั่วไปจำนวนมากก็เป็นการนำไดนามิกโปรแกรมมิงไปใช้กับปัญหาเฉพาะอย่างหนึ่ง
- เพื่อช่วยให้เข้าใจไดนามิกโปรแกรมมิงมากขึ้น จึงมีการอธิบายแบบเกริ่นนำที่ง่ายกว่าและคำอธิบายอย่างละเอียด
คำบ่น
- วิศวกรรมซอฟต์แวร์มักตั้งชื่อสิ่งต่าง ๆ ได้แย่มาก
- คำอย่าง 'bootstrap', 'daemon', 'cascading style sheets', 'cookie', 'artificial intelligence' เป็นต้น ล้วนกำกวมหรือชวนให้เข้าใจผิด
- คำว่า 'ไดนามิกโปรแกรมมิง' เองก็ไม่ได้เกี่ยวข้องกับความ "ไดนามิก" ตามชื่อ แต่แท้จริงแล้วเป็นแนวคิดที่ใช้ในการออกแบบอัลกอริทึม
การแคชพื้นฐาน
- เมื่อพยายามแก้ปัญหาโดยแยกออกเป็นปัญหาย่อยเล็ก ๆ ที่คล้ายกัน อาจต้องแก้ปัญหาย่อยเดิมซ้ำหลายครั้ง
- หากยกตัวอย่างลำดับฟีโบนัชชี การเขียนด้วยฟังก์ชันรีเคอร์ซีฟอย่างง่ายจะทำให้เกิดการคำนวณเดิมซ้ำไปซ้ำมา
- สามารถหลีกเลี่ยงการคำนวณซ้ำได้ด้วยการแคชผลลัพธ์ (หรือ memoization)
การแคชแบบเพิ่มประสิทธิภาพ
- เมื่อใช้ memoization เราสามารถคงรูปแบบรีเคอร์ชันไว้ได้ แต่จะคำนวณเฉพาะสิ่งที่จำเป็นในเวลาที่ต้องใช้
- แต่อีกแนวทางหนึ่งคือคำนวณทุกอย่างที่ต้องใช้ไว้ล่วงหน้า
- วิธีนี้แก้ปัญหาได้โดยไม่ต้องเรียกรีเคอร์ชัน และนี่เองคือไดนามิกโปรแกรมมิง
ระยะห่างการแก้ไข
- ระยะห่างการแก้ไขระหว่างสตริงสองชุด คือจำนวนครั้งขั้นต่ำของการแก้ไขที่ต้องใช้เพื่อแปลงสตริงหนึ่งให้เป็นอีกสตริงหนึ่ง
- ระยะห่างการแก้ไขสามารถคำนวณได้จากการแทนที่ แทรก และลบตัวอักษร ซึ่งสามารถแก้ได้อย่างมีประสิทธิภาพด้วยไดนามิกโปรแกรมมิง
- สิ่งสำคัญคือการหาวิธีดึงคำตอบของปัญหาทั้งหมดออกมาจากคำตอบของปัญหาย่อย
Advent of Code, Day 12
- ในโจทย์ Advent of Code วันที่ 12 ธันวาคม 2023 ต้องแก้ปัญหาโนโนแกรมแบบ 1 มิติ
- จะใช้วิธี brute force ก็ได้ แต่มีความซับซ้อนแบบเอ็กซ์โพเนนเชียล
- ทางเลือกที่ดีกว่าคือใช้ไดนามิกโปรแกรมมิงเพื่อแก้ปัญหาอย่างมีประสิทธิภาพ
บทสรุป
- ไดนามิกโปรแกรมมิงไม่ใช่เรื่องง่าย แต่ก็ไม่ได้ไกลเกินเอื้อมสำหรับโปรแกรมเมอร์ส่วนใหญ่
- หากเข้าใจวิธีแบ่งปัญหาออกเป็นปัญหาย่อย ก็จะสามารถใช้ memoization ได้ในหลายสถานการณ์ ซึ่งเป็นการปรับปรุงที่สำคัญเหนือกว่าการเขียนแบบไร้เดียงสา
- เมื่อเชี่ยวชาญไดนามิกโปรแกรมมิงแล้ว ก็จะเข้าใจอัลกอริทึมทั้งกลุ่มได้ดีขึ้น เข้าใจ trade-off ได้ชัดเจนขึ้น และเปิดทางให้กับการเพิ่มประสิทธิภาพแบบอื่น ๆ
ความเห็นของ GN⁺
- ไดนามิกโปรแกรมมิงเป็นเทคนิคสำคัญในการแก้ปัญหาซับซ้อนอย่างมีประสิทธิภาพ โดยลดการคำนวณซ้ำผ่านการแคชคำตอบของปัญหาย่อยแทนการพึ่งพาแนวทางรีเคอร์ซีฟเพียงอย่างเดียว
- บทความนี้มีประโยชน์มากสำหรับวิศวกรซอฟต์แวร์ระดับเริ่มต้นที่อยากเข้าใจแนวคิดพื้นฐานของไดนามิกโปรแกรมมิง
- ตัวอย่างลำดับฟีโบนัชชีและระยะห่างการแก้ไขช่วยให้เข้าใจแนวคิดของไดนามิกโปรแกรมมิงได้ง่ายขึ้น และเป็นจุดเริ่มต้นที่ดีสำหรับการนำไปใช้แก้ปัญหาจริง
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
บทความอธิบายอัลกอริทึม dynamic programming (DP) ว่าเป็นการทำแคชให้กับการเรียกซ้ำ ซึ่งเป็นจุดที่ดี
ชอบแนวทางของบทความที่เริ่มจากจัดการปัญหาแบบเรียกซ้ำก่อน แล้วค่อย ๆ เพิ่มแคชเข้าไป จากนั้นลดขนาดให้เหลือเท่าที่จำเป็น
หนึ่งในการประยุกต์ใช้ dynamic programming ที่ยอดเยี่ยมคือการจัดแนวลำดับแบบเป็นคู่ของลำดับกรดนิวคลีอิก/โปรตีน
มีการเล่าประสบการณ์เกี่ยวกับอาจารย์ด้านอัลกอริทึมที่เก่งมาก
แชร์ลิงก์ไปยังบทความ Dynamic Programming is not Black Magic
มีความเห็นว่าถ้าเป็นคนที่เรียนเขียนโปรแกรมด้วยตัวเองเป็นหลัก ตอนหางานถ้าในสัมภาษณ์บอกให้ใช้ dynamic programming ก็คงจะไม่รู้จักมัน
ชื่อว่า "dynamic programming" อาจฟังดูเหมือนไม่ได้มาจากวงการ programming โดยตรง
มีการตั้งคำถามว่าการนึกถึงแค่ "memoization" เมื่อได้ยินคำว่า "dynamic programming" นั้นผิดหรือไม่
dynamic programming ไม่ใช่ black magic แต่สิ่งที่ยากคือการพิสูจน์ว่าปัญหานั้นสามารถทำเป็น dynamic programming ได้ และพิสูจน์ความถูกต้องของมัน
มีการแนะนำหนังสืออัลกอริทึม DPV และคอร์สของ Udacity จาก Georgia Tech เพื่อให้เชี่ยวชาญ dynamic programming