Skip to content

Commit 5ac898f

Browse files
authored
Merge branch 'TheAlgorithms:master' into master
2 parents e99c722 + d94929e commit 5ac898f

File tree

13 files changed

+188
-60
lines changed

13 files changed

+188
-60
lines changed

.github/workflows/Ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ jobs:
1111
name: Code style and tests
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@v2
15-
- uses: actions/setup-node@v2
14+
- uses: actions/checkout@v3
15+
- uses: actions/setup-node@v3
1616
with:
1717
node-version: "16.x"
1818
cache: npm
@@ -30,7 +30,7 @@ jobs:
3030
name: Check for spelling errors
3131
runs-on: ubuntu-latest
3232
steps:
33-
- uses: actions/checkout@v2
33+
- uses: actions/checkout@v3
3434
- uses: codespell-project/actions-codespell@master
3535
with:
3636
# file types to ignore

Bit-Manipulation/LogTwo.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* https://handwiki.org/wiki/Binary_logarithm
3+
* Approximate log2 using only bitwise operators
4+
* @param {number} n
5+
* @returns {number} Log2 approximation equal to floor(log2(n))
6+
*/
7+
export const logTwo = (n) => {
8+
let result = 0
9+
while (n >> 1) {
10+
n >>= 1
11+
result++
12+
}
13+
return result
14+
}

Bit-Manipulation/test/LogTwo.test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { logTwo } from '../LogTwo'
2+
3+
for (let i = 1; i < 100; i++) {
4+
test('log2(' + i + ')', () => {
5+
expect(logTwo(i)).toBe(Math.floor(Math.log2(i)))
6+
})
7+
}

Ciphers/CaesarsCipher.js renamed to Ciphers/CaesarCipher.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* @param {number} rotation - the number of rotation, expect real number ( > 0)
77
* @return {string} - decrypted string
88
*/
9-
const caesarsCipher = (str, rotation) => {
9+
const caesarCipher = (str, rotation) => {
1010
if (typeof str !== 'string' || !Number.isInteger(rotation) || rotation < 0) {
1111
throw new TypeError('Arguments are invalid')
1212
}
@@ -29,4 +29,4 @@ const caesarsCipher = (str, rotation) => {
2929
})
3030
}
3131

32-
export default caesarsCipher
32+
export default caesarCipher

Ciphers/test/CaesarCipher.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import caesarCipher from '../CaesarCipher'
2+
3+
describe('Testing the caesarsCipher function', () => {
4+
it('Test - 1, Testing for invalid types', () => {
5+
expect(() => caesarCipher(false, 3)).toThrow()
6+
expect(() => caesarCipher('false', -1)).toThrow()
7+
expect(() => caesarCipher('true', null)).toThrow()
8+
})
9+
10+
it('Test - 2, Testing for valid string and rotation', () => {
11+
expect(caesarCipher('middle-Outz', 2)).toBe('okffng-Qwvb')
12+
expect(caesarCipher('abcdefghijklmnopqrstuvwxyz', 3)).toBe('defghijklmnopqrstuvwxyzabc')
13+
expect(caesarCipher('Always-Look-on-the-Bright-Side-of-Life', 5)).toBe('Fqbfdx-Qttp-ts-ymj-Gwnlmy-Xnij-tk-Qnkj')
14+
expect(caesarCipher('THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG', 23)).toBe('QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD')
15+
})
16+
})

Ciphers/test/CaesarsCipher.test.js

Lines changed: 0 additions & 16 deletions
This file was deleted.

Conversions/DateToDay.js

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,54 +9,52 @@
99
algorithm shown below gives us the number of the day and
1010
finally converts it to the name of the day.
1111
12-
Algorithm & Explanation : https://cs.uwaterloo.ca/~alopez-o/math-faq/node73.html
12+
Algorithm & Explanation : https://en.wikipedia.org/wiki/Zeller%27s_congruence
1313
*/
1414

15-
// March is taken as the first month of the year.
16-
const calcMonthList = {
17-
1: 11,
18-
2: 12,
19-
3: 1,
20-
4: 2,
21-
5: 3,
22-
6: 4,
23-
7: 5,
24-
8: 6,
25-
9: 7,
26-
10: 8,
27-
11: 9,
28-
12: 10
29-
}
30-
31-
// show the week day in a number : Sunday - Saturday => 0 - 6
32-
const daysNameList = { // weeks-day
33-
0: 'Sunday',
34-
1: 'Monday',
35-
2: 'Tuesday',
36-
3: 'Wednesday',
37-
4: 'Thursday',
38-
5: 'Friday',
39-
6: 'Saturday'
40-
}
15+
// Array holding name of the day: Saturday - Sunday - Friday => 0 - 1 - 6
16+
const daysNameArr = ['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
4117

4218
const DateToDay = (date) => {
4319
// firstly, check that input is a string or not.
4420
if (typeof date !== 'string') {
4521
return new TypeError('Argument is not a string.')
4622
}
4723
// extract the date
48-
const [day, month, year] = date.split('/').map((x) => Number(x))
24+
let [day, month, year] = date.split('/').map((x) => Number(x))
4925
// check the data are valid or not.
50-
if (day < 0 || day > 31 || month > 12 || month < 0) {
26+
if (day < 1 || day > 31 || month > 12 || month < 1) {
5127
return new TypeError('Date is not valid.')
5228
}
53-
// divide year to century and yearDigit value.
54-
const yearDigit = (year % 100)
29+
30+
// In case of Jan and Feb:
31+
// Year: we consider it as previous year
32+
// e.g., 1/1/1987 here year is 1986 (-1)
33+
// Month: we consider value as 13 & 14 respectively
34+
if (month < 3) {
35+
year--
36+
month += 12
37+
}
38+
39+
// divide year into century and the last two digits of the century
40+
const yearDigits = year % 100
5541
const century = Math.floor(year / 100)
56-
// Apply the algorithm shown above
57-
const weekDay = Math.abs((day + Math.floor((2.6 * calcMonthList[month]) - 0.2) - (2 * century) + yearDigit + Math.floor(yearDigit / 4) + Math.floor(century / 4)) % 7)
58-
// return the weekDay name.
59-
return daysNameList[weekDay]
42+
43+
/*
44+
In mathematics, remainders of divisions are usually defined to always be positive;
45+
As an example, -2 mod 7 = 5.
46+
Many programming languages including JavaScript implement the remainder of `n % m` as `sign(n) * (abs(n) % m)`.
47+
This means the result has the same sign as the numerator. Here, `-2 % 7 = -1 * (2 % 7) = -2`.
48+
49+
To ensure a positive numerator, the formula is adapted: `- 2 * century` is replaced with `+ 5 * century`
50+
which does not alter the resulting numbers mod 7 since `7 - 2 = 5`
51+
52+
The following example shows the issue with modulo division:
53+
Without the adaption, the formula yields `weekDay = -6` for the date 2/3/2014;
54+
With the adaption, it yields the positive result `weekDay = 7 - 6 = 1` (Sunday), which is what we need to index the array
55+
*/
56+
const weekDay = (day + Math.floor((month + 1) * 2.6) + yearDigits + Math.floor(yearDigits / 4) + Math.floor(century / 4) + 5 * century) % 7
57+
return daysNameArr[weekDay] // name of the weekday
6058
}
6159

6260
// Example : DateToDay("18/12/2020") => Friday

Conversions/test/DateToDay.test.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { DateToDay } from '../DateToDay'
22

3-
test('The date 18/02/2001 is Monday', () => {
3+
test('The date 18/02/2001 is Sunday', () => {
44
const res = DateToDay('18/02/2001')
5-
expect(res).toBe('Monday')
5+
expect(res).toBe('Sunday')
66
})
77

88
test('The date 18/12/2020 is Friday', () => {
@@ -14,7 +14,22 @@ test('The date 12/12/2012 is Wednesday', () => {
1414
const res = DateToDay('12/12/2012')
1515
expect(res).toBe('Wednesday')
1616
})
17-
test('The date 01/01/2001 is Friday', () => {
17+
test('The date 01/01/2001 is Monday', () => {
1818
const res = DateToDay('01/01/2001')
19-
expect(res).toBe('Friday')
19+
expect(res).toBe('Monday')
20+
})
21+
22+
test('The date 1/1/2020 is Wednesday', () => {
23+
const res = DateToDay('1/1/2020')
24+
expect(res).toBe('Wednesday')
25+
})
26+
27+
test('The date 2/3/2014 is Sunday', () => {
28+
const res = DateToDay('2/3/2014')
29+
expect(res).toBe('Sunday')
30+
})
31+
32+
test('The date 28/2/2017 is Tuesday', () => {
33+
const res = DateToDay('28/2/2017')
34+
expect(res).toBe('Tuesday')
2035
})

Dynamic-Programming/CatalanNumbers.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Author: IcarusTheFly (https://github.com/IcarusTheFly)
3+
* Catalan Numbers explanation can be found in the following links:
4+
* Wikipedia: https://en.wikipedia.org/wiki/Catalan_number
5+
* Brilliant: https://brilliant.org/wiki/catalan-numbers
6+
*/
7+
8+
/**
9+
* @function catalanNumbers
10+
* @description Returns all catalan numbers from index 0 to n
11+
* @param {number} n
12+
* @returns {number[]} Array with the catalan numbers from 0 to n
13+
*/
14+
15+
export const catalanNumbers = (n) => {
16+
if (n === 0) {
17+
return [1]
18+
}
19+
const catList = [1, 1]
20+
21+
for (let i = 2; i <= n; i++) {
22+
let newNumber = 0
23+
for (let j = 0; j < i; j++) {
24+
newNumber += catList[j] * catList[i - j - 1]
25+
}
26+
catList.push(newNumber)
27+
}
28+
29+
return catList
30+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { catalanNumbers } from '../CatalanNumbers'
2+
3+
describe('Testing catalanNumbers function', () => {
4+
test('should return the expected array for inputs from 0 to 20', () => {
5+
const expectedOutput = [
6+
1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900,
7+
2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420
8+
]
9+
10+
for (let i = 0; i <= 20; i++) {
11+
expect(catalanNumbers(i)).toStrictEqual(expectedOutput.slice(0, i + 1))
12+
}
13+
})
14+
})

0 commit comments

Comments
 (0)