File tree Expand file tree Collapse file tree 5 files changed +153
-0
lines changed
src/algorithms/others/recursive-staircase Expand file tree Collapse file tree 5 files changed +153
-0
lines changed Original file line number Diff line number Diff line change 1+ # Bài Toán Đệ Quy Cầu Thang
2+
3+ ## Vấn đề
4+
5+ Có ` n ` bậc thang, người đứng dưới cầu thang muốn đi lên trên cùng. Họ có thể lựa chọn bước ` 1 ` hoặc ` 2 ` bậc tại một thời điểm. _ Đếm số cách mà một người có thể đi lên trên cầu thang_ .
6+
7+ ![ ] ( https://cdncontribute.geeksforgeeks.org/wp-content/uploads/nth-stair.png )
8+
9+ ## Giải pháp
10+
11+ Đây là một bài toán thú vị vì có nhiều cách để giải nó, dưới đây là minh hoạ của các giải pháp lập trình khác nhau.
12+
13+ - [ Phá Mã] ( ./recursiveStaircaseBF.js ) - Thời gian: ` O(2^n) ` ; Không gian: ` O(1) `
14+ - [ Dùng Bộ Nhớ Phụ] ( ./recursiveStaircaseMEM.js ) - Thời gian: ` O(n) ` ; Không gian: ` O(n) `
15+ - [ Quy Hoạch Động] ( ./recursiveStaircaseDP.js ) - Thời gian: ` O(n) ` ; Không gian: ` O(n) `
16+ - [ Vòng Lặp] ( ./recursiveStaircaseIT.js ) - Time: ` O(n) ` ; Space: ` O(1) `
17+
18+ ## Vòng Lặp
19+
20+ - [ On YouTube by Gayle Laakmann McDowell] ( https://www.youtube.com/watch?v=eREiwuvzaUM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=81&t=0s )
21+ - [ GeeksForGeeks] ( https://www.geeksforgeeks.org/count-ways-reach-nth-stair/ )
Original file line number Diff line number Diff line change 1+ /**
2+ * Bài Toán Đệ Quy Cầu Thang (Phá Mã)
3+ *
4+ * @param {number } stairsNum - số bậc có thể bước.
5+ * @return {number } - Số cách để bước lên cầu thang.
6+ */
7+ export default function recursiveStaircaseBF ( stairsNum ) {
8+ if ( stairsNum <= 0 ) {
9+ // Số bậc nhỏ hơn 1 thì không có gì để bước
10+ return 0 ;
11+ }
12+
13+ if ( stairsNum === 1 ) {
14+ // Nếu chỉ có 1 bậc chỉ có một cách bước.
15+ return 1 ;
16+ }
17+
18+ if ( stairsNum === 2 ) {
19+ // Nếu có hai bậc có hai cách bước là (1+1) và (2).
20+ return 2 ;
21+ }
22+
23+ // Tính tổng số bước ta cần thực hiện sau khi thực hiện một bước
24+ // với số bước ta cần thực hiện sau khi thực hiện hai bước lên.
25+ return recursiveStaircaseBF ( stairsNum - 1 ) + recursiveStaircaseBF ( stairsNum - 2 ) ;
26+ }
Original file line number Diff line number Diff line change 1+ /**
2+ * Bài Toán Đệ Quy Cầu Thang (Quy Hoạch Động)
3+ *
4+ * @param {number } stairsNum - số bậc có thể bước.
5+ * @return {number } - Số cách để bước lên cầu thang.
6+ */
7+ export default function recursiveStaircaseDP ( stairsNum ) {
8+ if ( stairsNum < 0 ) {
9+ // Không có bậc thang nào để bước.
10+ return 0 ;
11+ }
12+
13+ // Khởi tạo vector "steps" sẽ chứa tất cả các cách có thể đến bước tương ứng.
14+ const steps = new Array ( stairsNum + 1 ) . fill ( 0 ) ;
15+
16+ // Khởi tạo số cách để đến bậc thứ 0, 1 và 2.
17+ steps [ 0 ] = 0 ;
18+ steps [ 1 ] = 1 ;
19+ steps [ 2 ] = 2 ;
20+
21+ if ( stairsNum <= 2 ) {
22+ // Trả về số cách để đến bậc thứ 0, 1 và 2.
23+ return steps [ stairsNum ] ;
24+ }
25+
26+ // Tính toán bước kế tiếp dựa trên hai bước trước nó.
27+ for ( let currentStep = 3 ; currentStep <= stairsNum ; currentStep += 1 ) {
28+ steps [ currentStep ] = steps [ currentStep - 1 ] + steps [ currentStep - 2 ] ;
29+ }
30+
31+ // Trả về các cách để có thể đi hết cầu thang.
32+ return steps [ stairsNum ] ;
33+ }
Original file line number Diff line number Diff line change 1+ /**
2+ * Bài Toán Đệ Quy Cầu Thang (Vòng Lặp)
3+ *
4+ * @param {number } totalStairs - số bậc có thể bước.
5+ * @return {number } - Số cách để bước lên cầu thang.
6+ */
7+ export default function recursiveStaircaseIT ( stairsNum ) {
8+ if ( stairsNum <= 0 ) {
9+ // Số bậc nhỏ hơn 1 thì không có gì để bước
10+ return 0 ;
11+ }
12+
13+ // Tạo mảng lưu số cách đến bậc thứ 0, 1 và 2.
14+ const steps = [ 1 , 2 ] ;
15+
16+ if ( stairsNum <= 2 ) {
17+ // Trả về số cách có thể để đến bậc thứ 1 hoặc thứ 2.
18+ return steps [ stairsNum - 1 ] ;
19+ }
20+
21+ // Tính số cách đi đến bước thứ n dựa trên những cách trước đó.
22+ // So với giải pháp Quy hoạch động, ta chỉ lưu trữ thông tin cho hai bước
23+ // trước nó thay vì lưu tất cả các bước.
24+ for ( let currentStep = 3 ; currentStep <= stairsNum ; currentStep += 1 ) {
25+ [ steps [ 0 ] , steps [ 1 ] ] = [ steps [ 1 ] , steps [ 0 ] + steps [ 1 ] ] ;
26+ }
27+
28+ // Trả lại các cách có thể để đến bậc được yêu cầu.
29+ return steps [ 1 ] ;
30+ }
Original file line number Diff line number Diff line change 1+ /**
2+ * Bài Toán Đệ Quy Cầu Thang (Giải Pháp dùng Bộ Nhớ Phụ)
3+ *
4+ * @param {number } totalStairs - số bậc có thể bước.
5+ * @return {number } - Số cách để bước lên cầu thang.
6+ */
7+ export default function recursiveStaircaseMEM ( totalStairs ) {
8+ // Bảng ghi nhớ sẽ chứa tất cả các kết quả được tính toán đệ quy để
9+ // tránh tính toán chúng nhiều lần.
10+ const memo = [ ] ;
11+
12+ // Đệ quy với closure.
13+ const getSteps = ( stairsNum ) => {
14+ if ( stairsNum <= 0 ) {
15+ // Số bậc nhỏ hơn 1 thì không có gì để bước
16+ return 0 ;
17+ }
18+
19+ if ( stairsNum === 1 ) {
20+ // Nếu chỉ có 1 bậc chỉ có một cách bước.
21+ return 1 ;
22+ }
23+
24+ if ( stairsNum === 2 ) {
25+ // Nếu có hai bậc có hai cách bước là (1+1) và (2).
26+ return 2 ;
27+ }
28+
29+ // Tránh đệ quy cho các bước đã tính toán gần đây.
30+ if ( memo [ stairsNum ] ) {
31+ return memo [ stairsNum ] ;
32+ }
33+
34+ // Tính tổng số bước ta cần thực hiện sau khi thực hiện một bước
35+ // với số bước ta cần thực hiện sau khi thực hiện hai bước lên.
36+ memo [ stairsNum ] = getSteps ( stairsNum - 1 ) + getSteps ( stairsNum - 2 ) ;
37+
38+ return memo [ stairsNum ] ;
39+ } ;
40+
41+ // Trả về các cách để có thể đi hết cầu thang.
42+ return getSteps ( totalStairs ) ;
43+ }
You can’t perform that action at this time.
0 commit comments