ครับ!!! ผมเคยได้ยินประโยคแบบนี้มานักต่อนักล่ะ บางคนบอกว่าผมไม่รู้จักใช้เครื่องมือให้เกิดประโยชน์
คุณกำลังเข้าใจผิดกับคำว่า "การเลือกใช้เครื่องมือ" กับ "การฝึกทักษะการแก้ปัญหา"
ที่ผมเขียนเอง เพราะผมต้องการฝึก skill เพื่อให้เกิดความคล่องตัว เมื่อเราเจอโจทย์ปัญหาลักษณะนี้ เราจะแก้มันได้รึเปล่า ลองใช้ความคิดของเราดูสิ
skill มันส่งต่อผ่านประสบการณ์กันไม่ได้ ต่อให้มีคนพยายามเล่าประสบการณ์ทั้งชีวิตของเขาให้คุณฟัง คุณก็ทำแบบเขาไม่ได้ คุณต้องฝึก ฝึก ฝึก ลงมือทำด้วยตัวคุณเองครับ
ปัญหา
โดยทั่วไป การหาความน่าจะเป็นหรือความเป็นไปได้ของสมาชิกทั้งหมดภายในเซต S ซึ่งมีสมาชิกจำนวน n ตัว
คุณจะต้องวนลูปทั้งหมด n รอบ และลึก n ชั้น ถึงจะได้ค่าทั้งหมดออกมา เช่น
S = {'A', 'B', 'C'}
n = 3 ตัว
จำนวนความเป็นไปได้ทั้งหมดคือ 3 x 3 x 3 = 27 ค่า
การเขียนโปรแกรมแบบง่ายๆ จะได้
for (var i = 0; i < S.lenght; i++){ for (var j = 0; j < S.lenght; j++){ for (var k = 0; k < S.lenght; k++){ print(S[i] + ',' + S[j] + ',' + S[k]); } } } A,A,A A,A,B A,A,C A,B,A A,B,B ... ... ... C,B,C C,C,A C,C,B C,C,Cแล้วถ้าเขาต้องการให้คุณเขียน code ที่รองรับ S ที่มี size ขนาดใดก็ได้ คุณจะเขียนยังไง?
แน่นอน loop ใช้ไม่ได้ล่ะ เพราะมัน fixed ตายตัว
แล้วอะไรที่เราเอามาใช้แทน loop ได้ แถมยังเป็นแบบ dynamic อีก
คำตอบคือ Recursive ครับ
code
function probabilityWalking(topElement, elements, index, callback){ if (index < 0) { callback(topElement); return; } for (var i=0; i < elements.length; i++) { probabilityWalking( (topElement ? (topElement + ',') : topElement) + elements[i], elements, index - 1, callback ); } }using
probabilityWalking('', ['A', 'B'], 1, function(el){ console.log(el); }); A,A A,B B,A B,B
probabilityWalking('', ['A', 'B', 'C'], 2, function(el){ console.log(el); }); A,A,A A,A,B A,A,C A,B,A A,B,B ... ... ... C,B,C C,C,A C,C,B C,C,Cตอนนี้ code เราสามารถหาความเป็นไปได้ทั้งหมดของ S ขนาดเท่าใดก็ได้ แล้วครับ :)
การนำแนวคิดไปประยุกต์ใช้
maven dependencies
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.1</version> <type>jar</type> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency>Probability.java
package com.blogspot.na5cent.learning; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang3.StringUtils; /** * @author redcrow */ public class Probability { private static interface Callback { void call(String element); } private final List<String> elements; private boolean distinct = false; private boolean unique = false; private Integer size; private Set<String> signatures; private Probability(List<String> elements) { this.elements = elements; } public static Probability ofElements(String... elements) { return ofElements(Arrays.asList(elements)); } public static Probability ofElements(List<String> elements) { return new Probability(elements); } public Probability size(int size) { this.size = size; return this; } public Probability distinct() { this.distinct = true; return this; } public Probability unique() { this.unique = true; return this; } private Set<String> getSignatures() { if (signatures == null) { signatures = new HashSet<>(); } return signatures; } private boolean contains(String str, String target) { if (!str.isEmpty()) { String[] els = StringUtils.split(str, ":"); for (String el : els) { if (el.equals(target)) { return true; } } } return false; } private String findSignature(String str) { String[] els = StringUtils.split(str, ":"); Arrays.sort(els); return StringUtils.join(els, ":"); } private boolean has(String element) { String signature = findSignature(element); if (getSignatures().contains(signature)) { return true; } getSignatures().add(signature); return false; } private void walking(String topElement, List<String> elements, int index, Callback callback) { if (index < 0) { if (unique && has(topElement)) { return; } callback.call(topElement); return; } for (String element : elements) { if (distinct && contains(topElement, element)) { continue; } walking( (topElement.isEmpty() ? topElement : topElement + ":") + element, elements, index - 1, callback ); } } public List<String> find() { if (size == null) { size = elements.size(); } final List<String> results = new ArrayList<>(); walking("", elements, size - 1, new Callback() { @Override public void call(String element) { results.add(element); } }); return results; } }
ลองดูวิธีการเรียกใช้และผลลัพธ์ที่ Test
ProbabilityTest.java
package com.blogspot.na5cent.learning; import java.util.Arrays; import java.util.List; import org.junit.Test; import static org.junit.Assert.*; /** * @author redcrow */ public class ProbabilityTest { @Test public void allOf2ElementsSize2() { List<String> probs = Probability .ofElements("A", "B") .find(); List<String> results = Arrays.asList( "A:A", "A:B", "B:A", "B:B" ); assertEquals(probs, results); } @Test public void allOf3ElementsSize3() { List<String> probs = Probability .ofElements("A", "B", "C") .find(); List<String> results = Arrays.asList( "A:A:A", "A:A:B", "A:A:C", "A:B:A", "A:B:B", "A:B:C", "A:C:A", "A:C:B", "A:C:C", "B:A:A", "B:A:B", "B:A:C", "B:B:A", "B:B:B", "B:B:C", "B:C:A", "B:C:B", "B:C:C", "C:A:A", "C:A:B", "C:A:C", "C:B:A", "C:B:B", "C:B:C", "C:C:A", "C:C:B", "C:C:C" ); assertEquals(probs, results); } @Test public void distinctOf2ElementsSize2() { List<String> probs = Probability .ofElements("A", "B") .distinct() //ตัด A:A กับ B:B ออก เพราะ A กับ B ซ้ำกัน 2 ตัว .find(); List<String> results = Arrays.asList( "A:B", "B:A" ); assertEquals(probs, results); } @Test public void distinctOf3ElementsSize3() { List<String> probs = Probability .ofElements("A", "B", "C") .distinct() .find(); List<String> results = Arrays.asList( "A:B:C", "A:C:B", "B:A:C", "B:C:A", "C:A:B", "C:B:A" ); assertEquals(probs, results); } @Test public void distinctOf4ElementsSize2() { List<String> probs = Probability .ofElements("A", "B", "C", "D") .distinct() .size(2) .find(); List<String> results = Arrays.asList( "A:B", "A:C", "A:D", "B:A", "B:C", "B:D", "C:A", "C:B", "C:D", "D:A", "D:B", "D:C" ); assertEquals(probs, results); } @Test public void uniqueOf2ElementsSize2() { List<String> probs = Probability .ofElements("A", "B") .unique() .find(); List<String> results = Arrays.asList( "A:A", "A:B", "B:B" ); assertEquals(probs, results); } @Test public void uniqueOf3ElementsSize3() { List<String> probs = Probability .ofElements("A", "B", "C") .unique() .find(); List<String> results = Arrays.asList( "A:A:A", "A:A:B", "A:A:C", "A:B:B", "A:B:C", "A:C:C", "B:B:B", "B:B:C", "B:C:C", "C:C:C" ); assertEquals(probs, results); } @Test public void uniqueAndDistinctOf2ElementsSize2() { List<String> probs = Probability .ofElements("A", "B") .distinct() //ตัด A:A กับ B:B ออก เพราะ A กับ B ซ้ำกัน 2 ตัว .unique() //A:B กับ B:A ถือเป็นตัวเดียวกัน แค่สลับตำแหน่ง .find(); List<String> results = Arrays.asList( "A:B" ); assertEquals(probs, results); } @Test public void uniqueAndDistinctOf3ElementsSize3() { List<String> probs = Probability .ofElements("A", "B", "C") .distinct() .unique() .find(); List<String> results = Arrays.asList( "A:B:C" ); assertEquals(probs, results); } @Test public void uniqueAndDistinctOf3ElementsSize2() { List<String> probs = Probability .ofElements("A", "B", "C") .distinct() .unique() .size(2) .find(); List<String> results = Arrays.asList( "A:B", "A:C", "B:C" ); assertEquals(probs, results); } @Test public void uniqueAndDistinctOf4ElementsSize2() { List<String> probs = Probability .ofElements("A", "B", "C", "D") .distinct() .unique() .size(2) .find(); List<String> results = Arrays.asList( "A:B", "A:C", "A:D", "B:C", "B:D", "C:D" ); assertEquals(probs, results); } @Test public void uniqueAndDistinctOf4ElementsSize3() { List<String> probs = Probability .ofElements("A", "B", "C", "D") .distinct() .unique() .size(3) .find(); List<String> results = Arrays.asList( "A:B:C", "A:B:D", "A:C:D", "B:C:D" ); assertEquals(probs, results); } }code นี้เป็นส่วนนึงของโจทย์ที่ผมกำลังแก้อยู่ครับ โจทย์มีอยู่ว่า
ให้เขียนโปรแกรมเพื่อหาสมการทั้งหมดที่เป็นไปได้ โดยให้เรา
1. ใส่คำตอบที่อยากจะได้ลงไป
2. ใส่ตัวเลขอะไรก็ได้ กี่ตัวก็ได้ลงไป (ในที่นี้คือ S)
3. ใส่ operators + หรือ - หรือ * หรือ / ลงไปกี่ตัวก็ได้ ใน 4 ตัวนี้
แล้วให้โปรแกรมคืนค่าสมการที่เกิดจากการป้อน input ข้อ 1- 3 ทั้งหมดออกมาครับ
น่าสนุกน่ะ
ตอนนี้ผมเหลือเงื่อนไขวงเล็บทั้งหมดที่เป็นไปได้ ตามจำนวนสมาชิกใน S ครับ
ยังคิดไม่ออก ฮ่าๆๆๆ
ขอบคุณมากครับ กำลัง ศึกษาอยู่พอดีเลย
ตอบลบ