Skip to content

Commit 3843541

Browse files
committed
Add some basic math algo
1 parent e0d6948 commit 3843541

File tree

16 files changed

+406
-1
lines changed

16 files changed

+406
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Thuật toán là một đặc tả rõ ràng về cách giải quyết một l
5050
* `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - tìm ước số chung lớn nhất (GCD)
5151
* `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) - tìm bội số chung nhỏ nhất (LCM)
5252
* `B` [Sieve of Eratosthenes](src/algorithms/math/sieve-of-eratosthenes) - tìm tất cả số nguyên tố theo giới hạn được đưa.
53-
* `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - kiểm tra một số có phải bình phương của 2 (dương lẫn âm).
53+
* `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - kiểm tra một số có phải luỹ thừa của 2.
5454
* `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle) - tam giác Pascal.
5555
* `B` [Complex Number](src/algorithms/math/complex-number) - số phức và các phép toán cơ bản.
5656
* `B` [Radian & Degree](src/algorithms/math/radian) - chuyển từ radian sang độ và ngược lại.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Thuật toán Euclidean
2+
3+
Trong toán học, thuật toán Euclidean hay Euclid's, là một phương pháp hiệu quả để tính ước chung lớn nhất (GCD) của hai số, GCD của hai số là số lớn nhất mà cả hai cùng chia hết hay chia không có phần dư.
4+
5+
Thuật toán Euclidean được xây dựng dựa trên nguyên tắc ước chung lớn nhất của hai số không thay đổi, nếu số lớn hơn được thay thế bởi hiệu số của nó với số nhỏ hơn. Ví dụ, `21` là GCD của `252``147` (vì `252 = 21 × 12``147 = 21 × 7`) đồng thời `21` cũng là GCD của `147``105 = 252 − 147`.
6+
Vì sự thay đổi này sẽ làm cho số lớn hơn thành số nhỏ hơn, nên quá trình này sẽ lặp lại cho đến khi nào hai số bằng nhau. Khi đó, chúng sẽ là GCD của hai số ban đầu.
7+
8+
Bằng cách đảo ngược các bước, GCD có thể được biểu thị dưới dạng tổng của hai số ban đầu, mỗi số nhân với một số nguyên dương hoặc âm, ví dụ: `21 = 7 × 147 + (−4) × 252`. GCD thể hiện theo cách này được gọi là bổ đề Bézout.
9+
10+
![GCD](https://upload.wikimedia.org/wikipedia/commons/3/37/Euclid%27s_algorithm_Book_VII_Proposition_2_3.png)
11+
12+
Phương pháp của Euclid để tìm ước chung lớn nhất (GCD) của hai đoạn có độ dài bắt đầu là `BA``DC`, cả hai đều được xác định theo một "đơn vị" chung. Độ dài `DC` ngắn hơn, nó được dùng để "đo" `BA`, nhưng chỉ một lần vì phần dư `EA` nhỏ hơn `DC`. EA sẽ đo (hai lần) chiều dài của `DC`, với phần còn lại `FC` ngắn hơn `EA`. Sau đó `FC` đo (ba lần) độ dài` EA`. Bởi vì không có phần dư, quá trình kết thúc với `FC`` GCD`. Ở ví dụ bên phải của Nicgastus với các số `49``21` dẫn đến GCD của họ là `7`.
13+
14+
![GCD](https://upload.wikimedia.org/wikipedia/commons/7/74/24x60.svg)
15+
16+
Hình chữ nhật `24 x 60` được bao phủ bởi mười ô vuông `12 x 12`, trong đó `12` là GCD của `24 'và `60`. Nói một cách tổng quát hơn, một hình chữ nhật `a-by-b` có thể được bao phủ bởi các ô vuông có độ dài cạnh `c` chỉ khi `c` là ước chung của `a``b`.
17+
18+
![GCD](https://upload.wikimedia.org/wikipedia/commons/1/1c/Euclidean_algorithm_1071_462.gif)
19+
20+
Hoạt ảnh dựa trên phép trừ của thuật toán Euclide. Hình chữ nhật ban đầu có kích thước `a = 1071``b = 462`. Các hình vuông có kích thước `462 × 462` được đặt bên trong nó để lại một hình chữ nhật `462 × 147`. Hình chữ nhật này được lắp bằng các ô vuông `147 × 147` cho đến khi còn lại một hình chữ nhật `21 × 147`, lần lượt được lắp bằng các ô vuông `21 × 21`, không để lại gì cả, diện tích đã bị che khuất hoàn toàn. Kích thước hình vuông nhỏ nhất, `21`, là GCD của `1071``462`.
21+
22+
## Liên kết
23+
24+
[Wikipedia](https://en.wikipedia.org/wiki/Euclidean_algorithm)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Phiên bản đệ quy của Thuật toán Euclid tìm ước số chung lớn nhất (GCD).
3+
* @param {number} originalA
4+
* @param {number} originalB
5+
* @return {number}
6+
*/
7+
export default function euclideanAlgorithm(originalA, originalB) {
8+
// Làm cho số nhập vào luôn dương.
9+
const a = Math.abs(originalA);
10+
const b = Math.abs(originalB);
11+
12+
// Để làm cho thuật toán hoạt động nhanh hơn thay vì trừ một số cho số kia
13+
// chúng ta có thể sử dụng thao tác chia lấy phần dư.
14+
return (b === 0) ? a : euclideanAlgorithm(b, a % b);
15+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Phiên bản dùng vòng lặp của Thuật toán Euclid tìm ước số chung lớn nhất (GCD).
3+
* @param {number} originalA
4+
* @param {number} originalB
5+
* @return {number}
6+
*/
7+
export default function euclideanAlgorithmIterative(originalA, originalB) {
8+
// Làm cho số nhập vào luôn dương.
9+
let a = Math.abs(originalA);
10+
let b = Math.abs(originalB);
11+
12+
// Trừ một số bởi số lớn hơn cho đến khi chúng bằng nhau.
13+
// Kết quả sẽ là GCD thì chúng sẽ thoát khỏi vòng lặp. Hoặc là chúng bằng 0
14+
while (a && b && a !== b) {
15+
[a, b] = a > b ? [a - b, b] : [a, b - a];
16+
}
17+
18+
// Trả về số khác 0 từ phép trừ cuối cùng (đấy là GCD).
19+
return a || b;
20+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Luỹ thừa của hai
2+
3+
Cho một số nguyên, viết hàm kiểm tra nó phải luỹ thừa của hai hay không.
4+
5+
**Giải pháp đơn giản**
6+
7+
Đơn giản nhất, ta chỉ cần liên tục chia lấy dư cho hai mỗi lần làm như vậy ta cần kiểm tra xem phần dữ có luôn bằng `0` không. Nếu có lần nào nó bằng `1` thì số đấy không phải luỹ thừa của hai.
8+
9+
**Giải pháp bitwise**
10+
11+
Luỹ thừa của hai ở dạng nhị phân luôn chỉ có một bit có giá trị là `1`. Trừ khi đấy là số nguyên có dấu (ví dụ: số nguyên có dấu 8-bit có giá trị -128 sẽ là : `10000000`)
12+
13+
```
14+
1: 0001
15+
2: 0010
16+
4: 0100
17+
8: 1000
18+
```
19+
20+
Vì vậy, sau khi kiểm tra rằng số đấy lớn hơn không, chúng ta có thể sử dụng một thủ thuật bitwise để kiểm tra số đó chỉ có một bit là `1`.
21+
22+
```
23+
number & (number - 1)
24+
```
25+
26+
Ví dụ thao tác với số `8` như sau :
27+
28+
```
29+
1000
30+
- 0001
31+
----
32+
0111
33+
34+
1000
35+
& 0111
36+
----
37+
0000
38+
```
39+
40+
## Liên kết
41+
42+
- [GeeksForGeeks](https://www.geeksforgeeks.org/program-to-find-whether-a-no-is-power-of-two/)
43+
- [Bitwise Solution on Stanford](http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2)
44+
- [Binary number subtraction on YouTube](https://www.youtube.com/watch?v=S9LJknZTyos&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=66)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @param {number} number
3+
* @return {boolean}
4+
*/
5+
export default function isPowerOfTwo(number) {
6+
// 1 (2^0) là luỹ thừa của hai nhỏ nhất.
7+
if (number < 1) {
8+
return false;
9+
}
10+
11+
// Ta sẽ kiểm tra xem có thể chia number cho hai
12+
// nhiều lần mà không có dư.
13+
let dividedNumber = number;
14+
while (dividedNumber !== 1) {
15+
if (dividedNumber % 2 !== 0) {
16+
// Đối với bất kỳ trường hợp nào khi phần dư khác không, chúng ta có thể
17+
// nói rằng số này không phải là lũy thừa của hai.
18+
return false;
19+
}
20+
21+
dividedNumber /= 2;
22+
}
23+
24+
return true;
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @param {number} number
3+
* @return {boolean}
4+
*/
5+
export default function isPowerOfTwoBitwise(number) {
6+
// 1 (2^0) là luỹ thừa của hai nhỏ nhất.
7+
if (number < 1) {
8+
return false;
9+
}
10+
11+
/*
12+
* Luỹ thừa của hai ở dạng nhị phân như sau:
13+
* 1: 0001
14+
* 2: 0010
15+
* 4: 0100
16+
* 8: 1000
17+
*
18+
* Ta thấy luôn chỉ có một bit có giá trị là `1`. Trừ khi đấy là số nguyên có dấu
19+
* (ví dụ: số nguyên có dấu 8-bit có giá trị -128 sẽ là : `10000000`)
20+
*
21+
* Vì vậy, sau khi kiểm tra rằng số đấy lớn hơn không, chúng ta có thể sử dụng
22+
* một thủ thuật bitwise để kiểm tra số đó chỉ có một bit là `1`.
23+
*/
24+
return (number & (number - 1)) === 0;
25+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Bội chung nhỏ nhất
2+
3+
Trong lý thuyết số học, bội số chung nhỏ nhất hoặc bội chung nhỏ nhất của hai số nguyên `a``b`, thường được ký hiệu là `LCM (a, b)`, là số nguyên dương nhỏ nhất có thể chia hết cho cả `a`` b`. Vì phép chia số cho số 0 là undefined, nên định nghĩa này chỉ có nghĩa nếu `a``b` đều khác 0.
4+
5+
## Ví dụ
6+
7+
Bội chung nhỏ nhất của 4 và 6?
8+
9+
Bội số của 4 là :
10+
```
11+
4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, ...
12+
```
13+
14+
Và bội số của 6 là :
15+
```
16+
6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, ...
17+
```
18+
19+
Các bội số chung của `4``6` trong danh sách là :
20+
21+
```
22+
12, 24, 36, 48, 60, 72, ....
23+
```
24+
25+
Vì vậy theo danh sách, bội số chung đầu tiên của `4``6` cũng là bội số chung nhỏ nhất là `12`.
26+
27+
## Tính bội số chung nhỏ nhất
28+
29+
Công thức sau đây tính bội số chung nhỏ nhất bằng cách lấy tích hai số (luôn dương) chia cho ước số chung lớn nhất (GCD) :
30+
31+
```
32+
lcm(a, b) = |a * b| / gcd(a, b)
33+
```
34+
35+
![LCM](https://upload.wikimedia.org/wikipedia/commons/c/c9/Symmetrical_5-set_Venn_diagram_LCM_2_3_4_5_7.svg)
36+
37+
Biểu đồ Venn cho thấy bội số chung nhỏ nhất của kết hợp của `2`, `3`, `4`,`5``7` (`6` được bỏ qua dó nó có dạng là `2 × 3`, cả hai số đều đã được biểu diễn).
38+
39+
## Liên kết
40+
41+
[Wikipedia](https://en.wikipedia.org/wiki/Least_common_multiple)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import euclideanAlgorithm from '../euclidean-algorithm/euclideanAlgorithm';
2+
3+
/**
4+
* @param {number} a
5+
* @param {number} b
6+
* @return {number}
7+
*/
8+
9+
export default function leastCommonMultiple(a, b) {
10+
return ((a === 0) || (b === 0)) ? 0 : Math.abs(a * b) / euclideanAlgorithm(a, b);
11+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Tam giác Pascal
2+
3+
Trong toán học, **Tam giác Pascal** là một mảng tam giác của các [hệ số nhị thức](https://en.wikipedia.org/wiki/Binomial_coefficient).
4+
5+
Các hàng của tam giác Pascal được liệt kê theo quy ước bắt đầu bằng hàng `n = 0` ở trên cùng (hàng `0`). Các mục trong mỗi hàng được đánh số từ đầu bên trái với `k = 0` và thường được đặt so le so với các số trong các hàng liền kề. Tam giác có thể được xây dựng theo cách sau: Trong hàng `0` (hàng trên cùng), có một số 1 duy nhất. Mỗi số của mỗi hàng tiếp theo được xây dựng bằng cách thêm số ở trên và bên trái với số ở trên và sang bên phải, coi các mục trống là `0`. Ví dụ: số ban đầu trong hàng đầu tiên (hoặc bất kỳ số nào khác) là `1` (tổng của `0``1`), trong khi các số `1``3` trong hàng thứ ba được thêm vào để tạo ra số 4 ở hàng thứ tư.
6+
7+
![Pascal's Triangle](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif)
8+
9+
## Công thức
10+
11+
Mục nhập trong hàng thứ n và cột thứ k của tam giác Pascal được ký hiệu ![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/206415d3742167e319b2e52c2ca7563b799abad7). Ví dụ: mục nhập khác duy nhất ở hàng trên cùng là ![Formula example](https://wikimedia.org/api/rest_v1/media/math/render/svg/b7e35f86368d5978b46c07fd6dddca86bd6e635c).
12+
13+
Với ký hiệu này, việc xây dựng đoạn trước có thể được viết như sau :
14+
15+
![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/203b128a098e18cbb8cf36d004bd7282b28461bf)
16+
17+
với mọi số nguyên n không âm và mọi số nguyên k nằm trong khoảng từ 0 đến n.
18+
19+
![Binomial Coefficient](https://wikimedia.org/api/rest_v1/media/math/render/svg/a2457a7ef3c77831e34e06a1fe17a80b84a03181)
20+
21+
## Tính toán các mục nhập tam giác trong thời gian O (n)
22+
23+
Ta biết rằng mục nhập thứ `i` ở dòng `lineNumber` là một hệ số nhị thức `C(lineNumber, i)` và tất cả các dòng bắt đầu bằng `1`. Ý tưởng để tính `C(lineNumber, i)` sử dụng `C(lineNumber, i-1)`. Và có thể được tính bằng thời gian `O(1)` như sau :
24+
25+
```
26+
C(lineNumber, i) = lineNumber! / ((lineNumber - i)! * i!)
27+
C(lineNumber, i - 1) = lineNumber! / ((lineNumber - i + 1)! * (i - 1)!)
28+
```
29+
30+
Chúng ta có thể suy ra biểu thức sau từ hai biểu thức trên:
31+
32+
```
33+
C(lineNumber, i) = C(lineNumber, i - 1) * (lineNumber - i + 1) / i
34+
```
35+
36+
Vì vậy, `C(lineNumber, i)` có thể được tính toán
37+
từ `C(lineNumber, i - 1)` trong thời gian `O(1)`.
38+
39+
## Liên kết
40+
41+
- [Wikipedia](https://en.wikipedia.org/wiki/Pascal%27s_triangle)
42+
- [GeeksForGeeks](https://www.geeksforgeeks.org/pascal-triangle

0 commit comments

Comments
 (0)