พาแงะ Algorithm เบื้องหลังวิธีคิด จากสองเจ้าของเหรียญคอมโอลิมปิก - Coders At Work | WorkWithCode
August 11, 2025
|
11 mins read

พาแงะ Algorithm เบื้องหลังวิธีคิด จากสองเจ้าของเหรียญคอมโอลิมปิก

คุยกับพี่พลและพี่ต้นสัก เจ้าของเพจ “เรื่องเล่าชาวอัลกอ: Practical Algorithms” กับสองสไตล์การเรียนรู้และกระบวนการแก้ปัญหา

พาแงะ Algorithm เบื้องหลังวิธีคิด จากสองเจ้าของเหรียญคอมโอลิมปิก

พี่พล เหรียญเงิน TOI ครั้งที่ 13 และพี่ต้นสัก เหรียญทอง TOI ครั้งที่ 15 ผู้สร้างเพจ “เรื่องเล่าชาวอัลกอ: Practical Algorithms” ที่เขียนแชร์ความรู้เกี่ยวกับอัลกอริทึม และประสบการณ์ในค่าย สอวน

ถึงแม้ทั้งคู่จะชอบเขียนโปรแกรมและชอบแก้ปัญหาเหมือนกัน แต่วิธีการเดินมาถึงจุดนี้ไม่เหมือนกัน

คนนึงมีวิธีการแก้ปัญหาแบบนึง อีกคนก็แบบนึง คนนึงเรียนรู้แบบนึง อีกคนก็แบบนึง คนนึงเรียนมหาลัยในไทย ส่วนอีกคนเรียนมหาลัยที่อเมริกา

บทความนี้อยากชวนผู้อ่านมาแงะ algorithm เบื้องหลังความแตกต่างของวิธีคิดของทั้งคู่กันครับ

ตอนฝึกแก้โจทย์ เคยเจอเพดานหรือจุดที่รู้สึกว่าตัวเองไม่เก่งขึ้นไหม และผ่านจุดนั้นมาได้ยังไง?

จริง ๆ เพดานนี่คือเจอได้เรื่อย ๆ เรียกว่าทุกขั้นตอนของค่ายคอมโอลิมปิกเลย (พี่พลพูด) มันจะมีวันที่รู้สึกว่าฉันทำยังไงก็ทำไม่ได้

วิธีที่ทำได้ก็คือการดูเฉลย แต่ไม่ได้ดูเฉลยที่เป็นการอธิบาย แต่จะเป็นการ “เอาโค้ดที่คนอื่นเขียนมาแกะ” และศึกษาจากสิ่งที่เขาทำ

ข้อดีคือ อย่างแรกมันทำให้เราได้เห็นท่าใหม่ ๆ ว่าคนอื่นเขียนโค้ดกันยังไง กับอย่างที่สองคือปกติเวลาเราอ่านเฉลยที่คนอื่นเขียนไว้ เขามักจะบอกเราว่าเราจะต้องทำยังไง 1, 2, 3 ซึ่งส่วนตัวมองว่ามันตรงไปตรงมาเกินไป

การแก้โจทย์หรือการแก้ปัญหาในมุมผม มันคือมี 2 จุดคือจุด A จุด B และอีกหลาย ๆ จุดระหว่างกลาง การที่เราจะผ่านจากจุดนึงไปอีกจุดนึงได้มันมาจากการที่เรา “observe เห็นอะไรบางอย่างที่เอาไปใช้ประโยชน์ได้” อาจจะมาจากการอ่านโจทย์ มาจากการตั้งคำถาม หรือเดินไปเดินมาแล้วคิดได้เอง

Problem Definition
ตัวอย่างเช่นถ้าเราอยากหาค่ามากที่สุดจาก arr เราอาจจะสังเกตได้ว่า “ถ้าเรา sort arr จากมากไปน้อย” ค่าที่มากที่สุดก็คือ element ตัวแรกของ arr นั่นเอง

การอ่านเฉลยที่คนอื่นเขียนมันเหมือนกับเขาบอกเราหมดแล้วว่าจะเดินจาก A ไป B ต้องคิดหรือสังเกตอะไร แต่การอ่านโค้ดมันเหมือนเราเดินจากหลังมาหน้า (เริ่มที่จุด B ย้อนกลับไป A) มันชวนเราตั้งคำถามว่า “ทำไมเขาถึงเขียนโค้ดออกมาแบบนี้หล่ะ?” เขาสังเกตเห็นอะไรหรือคิดยังไงถึงได้เทคนิคแบบนี้ออกมา

“สำหรับผมการได้เห็นว่าเขามองโจทย์ยังไง สำคัญมากกว่าว่าจะต้องเขียนโค้ดหรือใช้เทคนิคอะไรเพื่อให้แก้โจทย์นี้ได้”

เข้าใจว่าการแกะโค้ดก็ไม่ง่าย เรามีวิธีเล่นหรือ debug มันยังไง เพื่อให้เราเข้าใจโค้ด?

Example Code
ตัวอย่างโค้ดที่ส่งในการแข่งเขียนโปรแกรมหรือ competitive programming – จะเห็นว่าโค้ดไม่ได้แกะง่ายขนาดนั้น เนื่องจากว่าโค้ดถูกเขียนมาเพื่อเน้นแก้โจทย์ไว ๆ มากกว่าเขียนเพื่อกลับมาอ่านหรือแก้ในภายหลัง

จริง ๆ บางส่วนมันมองง่าย เช่นบางทีประกาศ array หรือมี loop แค่ไม่กี่ชั้นก็เข้าใจได้เลย

แต่ในส่วนที่มองยาก ๆ บางทีโค้ดมันจะมีส่วนที่เป็น “intermediary” หรือ “ตัวกลาง” เป็นส่วนที่จะเก็บผลลัพธ์จากโค้ดด้านบน เพื่อที่จะเอาผลลัพธ์หรือข้อมูลตรงนี้ไป process ต่อไปในโค้ดอีกส่วน

“พยายามมองหา intermediary ระหว่าง A และ B”

ตรงส่วนนี้ผมก็จะคอยทำความเข้าใจทั้งในส่วนของข้อมูล (data) และวิธีการเก็บข้อมูล (data structures) ว่ามันมีหน้าตายังไง แล้ว “มันสัมพันธ์อะไรกับ input หรือ output ของตัวโจทย์”

จากนั้นคำถามถัดมาที่ต้องคิดก็คือ “ทำไมมันถึงอยู่ในรูปนี้” และ “อยู่ในรูปนี้มันมีประโยชน์อะไร”

พยายามมองหา intermediary ระหว่าง A และ B

พี่ต้นสักหล่ะมีอะไรอยากเสริมไหม? จัดการกับเพดานของตัวเองยังไง

ผมก็เจอเพดานเรื่อย ๆ เหมือนกันครับ สิ่งที่ผมทำเวลาเจอโจทย์ที่ทำไม่ได้คือผมจะเก็บโจทย์ไว้ “คิดไปเรื่อย ๆ โดยที่ไม่อ่านเฉลยครับ” ผมจะอ่านเฉลยก็ต่อเมื่อได้ใช้เวลากับโจทย์นั้นเกือบเดือน หรือดีสุดหน่อยก็อาจจะแค่ 7 วันถึงจะเริ่มอ่านเฉลย

ผมจะชอบคิดอะไรเล่น ๆ อย่างเช่นสมมุติเอาโจทย์ที่เคยทำได้ “มาแต่ง มาลองเพิ่มเงื่อนไข หรือลองเพิ่ม constraints ให้มากกว่านั้น” แล้วดูว่าเราจะแก้มันยังไง

Quick Sum Example
ตัวอย่างโจทย์ quick sum (บางทีโจทย์จะถามหาผลรวมหลาย ๆ ช่วงบน array เดียว ทำให้ต้องคิด algorithm ที่ทำให้หาผลบวกได้ไวกว่าการที่ต้องไล่ index ทุกรอบในการถามแต่ละครั้ง)

ยกตัวอย่างเช่นโจทย์ quick sum ที่ให้ array มาแล้วให้หาผลบวกของช่วงสองช่วงใน array นั้น ผมก็อาจจะแต่งโจทย์หรือเพิ่ม condition เข้าไปอีกว่า แล้วถ้า array นั้นถูก update  ค่าได้จะเป็นอย่างไร?

“ผมรู้สึกว่าพอผมได้ทำแบบนี้ ได้ลองแต่งโจทย์ ได้ตั้ง challenge ให้ตัวเอง ผมรู้สึกว่า limit ผมมันเริ่มสูงขึ้นไปเรื่อย ๆ”

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

ส่วนตัวถ้าข้อไหนยอมแพ้ “ผมจะดูเฉลยที่คนอื่นเขียนไว้ และจะไม่ดูโค้ดเด็ดขาด” (ซึ่งตรงข้ามกับพี่พล) ด้วยความที่ว่าผมอยากรู้มากว่ามันทำยังไงกันแน่ และเอาสิ่งที่เฉลยเขียนไว้ “มาลองเขียนโค้ดในแบบของตัวเอง” เพราะผมมองว่าการดูโค้ดของคนอื่นอาจจะ influence การเขียนโค้ดของผมเองมากเกินไป

“ถ้าให้ผมสรุปก็เหมือนกับว่า style การเรียนผมมันเหมือน top-down คือมีโค้ดเป็นเป้าอยู่แล้วค่อย ๆ แกะวิธีคิด แต่ของต้นสักเป็นแบบ bottom-up คือมีวิธีคิดอยู่แล้ว แล้วหาทางเขียนโค้ด” - พี่พลเสริม

พอใช้วิธีนี้บางทีผมก็ได้ค้นพบ trick การเขียนโค้ดใหม่ ๆ ของตัวเอง ที่ช่วยให้ผมเขียนโค้ดสะดวกขึ้นในภายหลัง

แล้วในเรื่องของการเขียนโค้ดหล่ะ แต่ละคนมีสไตล์หรือลายเส้นของตัวเองต่างกันไหม?

จริง ๆ ค่อนข้างชัด อย่างเวลาอ่านโค้ดของต้นสัก เอะอะก็ไปทาง decision tree อยู่นั้นแหละ (ฮา) ส่วนถ้าเป็นผมภาพแรกที่ผมจะมองก็จะเป็น graph

ภาพแรกที่ผมจะมองคือมันเป็น dynamic programming หรือ binary search รึป่าว (ต้นสักเสริม)

มันเหมือนกับ mental model แต่ละคนจะต่างกัน อาจจะโดนหล่อหลอมมาจากว่าชอบโจทย์แนวไหน ถ้าโยนโจทย์ให้ผมข้อนึงกับให้ต้นสักทำอาจจะได้คนละ solution กันเลยก็ได้ เช่นมีโจทย์ข้อนึงชื่อว่า T-junction ที่เคยแชร์ลงเพจ ซึ่งผมสองคนก็มองคนละภาพกันเลย

ถ้างั้นอยากชวนคุยเรื่อง problem solving process บ้าง แต่ละคนมีวิธีการแก้ปัญหายังไง?

สำหรับผมเวลาเจอโจทย์ผมจะทำความเข้าใจก่อนว่า input และ output เป็นยังไง มี constraints อะไรบ้าง พยายามมองหา observation ว่ามีอะไรบ้าง พอได้ solution คร่าว ๆ แล้วก็ลอง implement ดูแล้วก็ทดสอบไปเรื่อย ๆ (พี่ต้นสักพูด)

ส่วนก่อนจะ implement ผมจะพยายามคิด core idea ให้มันแน่นก่อน เห็นภาพให้ชัดว่า data จะมีหน้าตาเป็นยังไง

ส่วนตอนเทสอันนี้จะเป็นท่าของผมเฉพาะตัวคือผมจะ “เขียนโค้ด generate random ตัว input และ output ออกมาให้ตรงตาม constraints” โดยใช้ naive solution หรือใช้ bruteforce solution ที่สามารถเขียนออกมาได้ไว ๆ 

แล้วผมค่อยเอา “โค้ดที่ผมเขียนไปลองรันและเทียบ output กันดูว่ามีข้อผิดพลาดอะไรไหม” จากนั้นก็ค่อย ๆ debug และแก้จนกระทั่งโค้ดทำงานถูกต้อง

“แล้วพี่พลหล่ะมีอะไรอยากเสริมไหม?”

ส่วนใหญ่แล้วก็ใช้วิธีคล้าย ๆ กัน แต่ว่าในส่วนของการ come up with solution อาจจะต่างนิดนึง อย่างที่ได้เล่าไปว่าผมเรียนแบบ top-down ผมจะพยายาม list ให้เห็นก่อนว่าผมรู้อะไรบ้าง (observation) แล้วพยายามหา clue ว่าปัญหาประมาณนี้ควรจะต้องใช้ algorithm หรือ data structures ประมาณไหน

ผมจะพยายามถามว่า “ถ้าฉันใช้ algorithm นี้แล้วมันจะเข้าใกล้คำตอบขึ้นไหม?”

ส่วนถ้าตอนไหนรู้สึกว่าคิดไม่ออกก็จะมานั่งหา observation ต่อ แล้วดูว่า observation ที่ได้มาเอาไปทำอะไรต่อได้

ของผมก่อน implement จะต่างกับต้นสักนิดนึง ถ้าให้พูดคือต้นสักเหมือนจะทำ unit test นั่นหละ แต่ของผมจะนั่งทด proof ประมาณนึง – แต่ไม่ถึงขั้นว่าเป็น formal proof – ว่าผมสามารถเปลี่ยน input A ให้เป็น B หรือ “intermediary” ระหว่างนั้นได้ไหม

การ verify algorithm correctness หลัก ๆ จะทำได้สองวิธีคือ “empirical proof” เช่นทำ simulation แล้วดูว่ามีโค้ดทำงานได้ถูกต้องไหม หรือเขียน script เพื่อ generate testcases เหมือนที่พี่ต้นสักทำ ส่วนอีกวิธีคือ “logical proof” เช่นใช้การให้เหตุผลหรือใช้ math proof method ต่าง ๆ เพื่อยืนยันว่า algorithm ของเราจะทำงานถูกต้องตามหลักเหตุและผล (เหมือนที่พี่พลทำ)

แล้วปกติมองหาตัวกลางจาก A ไป B หรือมองจาก B กลับมา A?

จริง ๆ ก็คือทั้งคู่ ถ้ามองจาก B มา A ก็จะถามประมาณว่า “ถ้าอยากได้ output แบบนี้ ข้อมูลก่อนหน้าควรจะมีหน้าตาเป็นยังไง?” หรือทำอะไรแล้วมันจะช่วยให้เราได้ output แบบนี้ได้บ้าง?

ส่วนมองจากด้านหน้าก็จะถามได้ว่า “input หน้าตาแบบนี้สามารถแปลงเป็นอะไรได้บ้าง?”

Think forward, Think backward, and Bridge the gap

ซึ่งผมก็จะพยายามทดในกระดาษประมาณนึงว่า “ถ้าแปลงไปเป็นแบบนั้นแล้วมันจะมีประโยชน์อะไร?” จากนั้นก็พยายามหาตัวกลางไปเรื่อย ๆ จนกระทั่งทั้ง input และ output มันเชื่อมกัน

สุดท้ายนี้ปกติได้มี metric อะไรที่วัดการเขียนโค้ดของตัวเองไหม เช่น productivity หรือว่าเขียนได้แบบนี้คือถือว่าสำเร็จแล้ว?

ของผมไม่ได้มี metric ชัดเจนขนาดนั้นครับ (พี่ต้นสักกล่าว) คือของผมจะนับเป็นชิ้นงานที่ทำได้มากกว่า ว่าถ้าโค้ดนี้ทำให้งานเราสำเร็จได้ก็นับว่าผ่าน

ส่วนของผมน่าจะต่างกับคนอื่นนิดหน่อย (พี่พลเสริม) สำหรับผมเรื่องว่าเขียนโค้ดไปได้กี่บรรทัด หรือทำไปกี่ชั่วโมง หรือทำเสร็จเร็วทำเสร็จช้า หรือ optimize ได้เยอะหรือน้อย ไม่ได้สำคัญเท่าไหร่

ผมมองว่าสิ่งที่สำคัญของการเขียนโค้ดคือ “เราเขียนเพื่อ verify idea” อย่างเช่นว่าเรามีไอเดียที่เราอยากจะลอง และเรารู้ว่าเราเขียนมันออกมาได้ อันนั้นผมนับว่าเป็นความสำเร็จนึงแล้ว

“เขียนโค้ดกี่บรรทัดไม่สน เขียนโค้ดมากี่ชั่วโมงไม่รู้ ขอแค่รู้ว่าวิธีที่ลองทำมานี้มันถูกนะ แค่นั้นก็รู้สึกดีแล้ว”

ส่วนเรื่องว่าจะเขียนโค้ดต้องเป็น app ไหม จะทำเงินได้กี่บาท หรือเขียนแล้วรู้สึกดีไหม อันนั้นส่วนตัวมองว่าเป็น financial กับ personal goal ละ ไม่ใช่ programming goal

Side Project Example
โปรเจค E-ink display ที่เกิดจากความ “อยากลองไอเดีย”

พี่จะเป็นคนนึงที่อยู่ ๆ ก็จะมีไอเดียผุดขึ้นมาว่าแบบ “ทำอันนี้ดีไหมนะ หรือทำอันนั้นดีไหม” ก็จะลองเขียนโค้ดหรือทำลองไอเดียดู อย่างเหมือนล่าสุดก็เพิ่งลง Arch Linux ไป หรือบางทีอยู่ ๆ ก็นึกย้อนกลับไปได้ว่า “เออถ้าทำแบบนี้มันน่าจะดีกว่า” ก็ลองกลับไปแก้ 

“ถามว่าเหนื่อยไหม ก็เหนื่อย แต่พอได้ลองทำ ได้ทดลองไอเดียเสร็จแล้ว มันก็รู้สึกภูมิใจละ”

จริง ๆ พี่ยังมี private repo อีกบานเลย (ฮา)

- พี่พล และพี่ต้นสัก ผู้สร้างเพจ “เรื่องเล่าชาวอัลกอ: Practical Algorithms”

Coders At Work บทสัมภาษณ์ที่จะชวนผู้อ่านไปพูดคุยเจาะลึก “กระบวนการแก้ปัญหา” และ “วิธีคิดเบื้องหลัง”  ของนักพัฒนาเก่ง ๆ ในประเทศไทย 

ติดตามบทความต่อไปได้ที่เพจและเว็บ LearnAlgorithm หรือเว็บไซต์ WorkWithCode แล้วพบกันครับ~