diff --git a/other/parse_nested_brackets.ts b/other/parse_nested_brackets.ts index 6d373d27..759e83eb 100644 --- a/other/parse_nested_brackets.ts +++ b/other/parse_nested_brackets.ts @@ -8,7 +8,7 @@ * @example parseNestedBrackets(`
`) => [ '
', '' ] * @example parseNestedBrackets( * `THIS IS SAMPLE TEXT(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))`, - * { openBrackets: '(', closingBrackets: ')' }) => + * { openBrackets: '(', closingBrackets: ')' }) => * [ '(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))', '(ITEM fuga hoge)', @@ -18,13 +18,14 @@ */ export const parseNestedBrackets = ( text: string, - openBrackets = '<', - closingBrackets = '>' -) => { + openBrackets: string = '<', + closingBrackets: string = '>' +): string[] => { let array: string[] = [] // The array of the tags in this present floor. let prFloor = 0 // The present floor. - let begin = 0, // The begin index of the tag. - end = 0 // The end index of the tag. + let begin = 0 // The begin index of the tag. + let end = 0 // The end index of the tag. + for (let i = 0; i < text.length; i++) { if (text[i] === openBrackets) { prFloor++ diff --git a/other/shuffle_array.ts b/other/shuffle_array.ts index 992145c2..8a29a4c0 100644 --- a/other/shuffle_array.ts +++ b/other/shuffle_array.ts @@ -1,8 +1,6 @@ -export function shuffleArray(arr: number[]) { +export function shuffleArray(arr: number[]): void { for (let i = arr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)) - const temp = arr[i] - arr[i] = arr[j] - arr[j] = temp + ;[arr[i], arr[j]] = [arr[j], arr[i]] } } diff --git a/other/test/parse_nested_brackets.test.ts b/other/test/parse_nested_brackets.test.ts index 15a4d45f..816364b6 100644 --- a/other/test/parse_nested_brackets.test.ts +++ b/other/test/parse_nested_brackets.test.ts @@ -10,7 +10,7 @@ describe('parseNestedBrackets', () => { it('should return an array of the tags (nested)', () => { expect( parseNestedBrackets( - `THIS IS SAMPLE TEXT(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))`, + 'THIS IS SAMPLE TEXT(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))', '(', ')' ) diff --git a/search/binary_search.ts b/search/binary_search.ts index cf86f39a..62a89a6c 100644 --- a/search/binary_search.ts +++ b/search/binary_search.ts @@ -8,7 +8,7 @@ * * @param {number[]} array - sorted list of numbers * @param {number} target - target number to search for - * @return {number} - index of the target number in the list, or null if not found + * @return {number | null} - index of the target number in the list, or null if not found * @see [BinarySearch](https://www.geeksforgeeks.org/binary-search/) * @example binarySearch([1,2,3], 2) => 1 * @example binarySearch([4,5,6], 2) => null diff --git a/search/exponential_search.ts b/search/exponential_search.ts index 4a8eba47..abcb4e91 100644 --- a/search/exponential_search.ts +++ b/search/exponential_search.ts @@ -11,7 +11,7 @@ import { binarySearchIterative } from './binary_search' * thus avoiding several comparisons that would make the search more verbose. * * @param {number[]} array - sorted list of numbers - * @param {number} x - target number to search for + * @param {number} target - target number to search for * @return {number | null} - index of the target number in the list, or null if not found * @see [ExponentialSearch](https://www.geeksforgeeks.org/exponential-search/) * @example exponentialSearch([1, 2, 3, 4, 5], 3) => 2 @@ -20,21 +20,21 @@ import { binarySearchIterative } from './binary_search' export const exponentialSearch = ( array: number[], - x: number + target: number ): number | null => { const arrayLength = array.length if (arrayLength === 0) return null - if (array[0] === x) return 0 + if (array[0] === target) return 0 let i = 1 - while (i < arrayLength && array[i] <= x) { - i = i * 2 + while (i < arrayLength && array[i] <= target) { + i *= 2 } const start = Math.floor(i / 2) const end = Math.min(i, arrayLength - 1) - const result = binarySearchIterative(array, x, start, end) + const result = binarySearchIterative(array, target, start, end) return result } diff --git a/search/fibonacci_search.ts b/search/fibonacci_search.ts index b0125277..0cee8869 100644 --- a/search/fibonacci_search.ts +++ b/search/fibonacci_search.ts @@ -18,9 +18,9 @@ export const fibonacciSearch = ( target: number ): number | null => { const arrayLength = array.length - let a = 0 // (n-2)'th Fibonacci No. - let b = 1 // (n-1)'th Fibonacci No. - let c = a + b // n'th Fibonacci + let a: number = 0 // (n-2)'th Fibonacci No. + let b: number = 1 // (n-1)'th Fibonacci No. + let c: number = a + b // n'th Fibonacci while (c < arrayLength) { a = b @@ -31,11 +31,10 @@ export const fibonacciSearch = ( let offset = -1 while (c > 1) { - let i = Math.min(offset + a, arrayLength - 1) + const i = Math.min(offset + a, arrayLength - 1) if (array[i] < target) { - c = b - b = a + ;[c, b] = [b, a] a = c - b offset = i } else if (array[i] > target) { @@ -48,7 +47,7 @@ export const fibonacciSearch = ( } } - if (b && array[offset + 1] === target) { + if (Boolean(b) && array[offset + 1] === target) { return offset + 1 } diff --git a/search/jump_search.ts b/search/jump_search.ts index e54aa196..92c783e4 100644 --- a/search/jump_search.ts +++ b/search/jump_search.ts @@ -23,8 +23,8 @@ export const jumpSearch = (array: number[], target: number): number => { // declare pointers for the current and next indexes and step size const stepSize: number = Math.floor(Math.sqrt(array.length)) - let currentIdx: number = 0, - nextIdx: number = stepSize + let currentIdx: number = 0 + let nextIdx: number = stepSize while (array[nextIdx - 1] < target) { currentIdx = nextIdx @@ -37,7 +37,7 @@ export const jumpSearch = (array: number[], target: number): number => { } for (let index = currentIdx; index < nextIdx; index++) { - if (array[index] == target) { + if (array[index] === target) { return index } } diff --git a/search/linear_search.ts b/search/linear_search.ts index 83a84205..a35b91d7 100644 --- a/search/linear_search.ts +++ b/search/linear_search.ts @@ -5,7 +5,7 @@ * if it's not present, the return it will be -1 * @param {number[]} array - list of numbers * @param {number} target - target number to search for - * @return {number} - index of the target number in the list, or -1 if not found + * @return {number | -1} - index of the target number in the list, or -1 if not found * @see https://en.wikipedia.org/wiki/Linear_search\ * @example linearSearch([1,2,3,5], 3) => 2 * @example linearSearch([1,5,6], 2) => -1 diff --git a/search/minesweeper.ts b/search/minesweeper.ts new file mode 100644 index 00000000..a0ebdaaa --- /dev/null +++ b/search/minesweeper.ts @@ -0,0 +1,50 @@ +/* + * Author: IcarusTheFly (https://github.com/IcarusTheFly) + * Minesweeper explanation can be found in: https://en.wikipedia.org/wiki/Minesweeper_(video_game) + * This function will take a rectangular matrix filled with boolean values - the value for a cell + * with a mine will be true, otherwise it will be false. + * As a result it will return a rectangular matrix where each cell will have an integer that + * counts all the mines in the adjacent cells + * Two cells should share at least one corner to be considered adjacent + */ + +/** + * @function minesweeper + * @description It counts the amount of mines surrounding every cell and returns a formatted matrix + * @param {boolean[][]} matrix + * @returns {number[][]} Matrix of numbers with the amount of mines surrounding each cell + * @example minesweeper([ + [true, false, false], + [false, true, false], + [false, false, false] + ]) ===> [ + [1, 2, 1], + [2, 1, 1], + [1, 1, 1] + ] + */ + +export const minesweeper = (matrix: boolean[][]): number[][] => { + const arrResult: number[][] = [] + + for (let x = 0; x < matrix.length; x++) { + const arrLine: number[] = [] + + for (let y = 0; y < matrix[x].length; y++) { + let minesInCell: number = 0 + + for (let xi = x - 1; xi <= x + 1; xi++) { + if (matrix[xi] !== undefined) { + for (let yi = y - 1; yi <= y + 1; yi++) { + if ((xi !== x || yi !== y) && matrix[xi][yi]) { + minesInCell++ + } + } + } + } + arrLine.push(minesInCell) + } + arrResult.push(arrLine) + } + return arrResult +} diff --git a/search/rabin_karp.ts b/search/rabin_karp.ts new file mode 100644 index 00000000..583000ac --- /dev/null +++ b/search/rabin_karp.ts @@ -0,0 +1,64 @@ +/* + * Implements the Rabin-Karp algorithm for pattern searching. + * + * The Rabin-Karp algorithm is a string searching algorithm that uses hashing to find patterns in strings. + * It is faster than naive string matching algorithms because it avoids comparing every character in the text. + * + * This implementation uses a rolling hash function to efficiently compute the hash values of substrings. + * It also uses a modulo operator to reduce the size of the hash values, which helps to prevent hash collisions. + * + * The algorithm returns an array of indices where the pattern is found in the text. If the pattern is not + * found, the algorithm returns an empty array. + * + * [Reference](https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm) + */ + +const BASE = 256 // The number of characters in the alphabet +const MOD = 997 // A prime number used for the hash function + +function rabinKarpSearch(text: string, pattern: string): number[] { + const patternLength: number = pattern.length + const textLength: number = text.length + const hashPattern: number = hash(pattern, patternLength) + const hashText: number[] = [] + const indices: number[] = [] + + // Calculate the hash of the first substring in the text + hashText[0] = hash(text, patternLength) + + // Precompute BASE^(patternLength-1) % MOD + const basePow: number = Math.pow(BASE, patternLength - 1) % MOD + + for (let i = 1; i <= textLength - patternLength + 1; i++) { + // Update the rolling hash by removing the first character + // and adding the next character in the text + hashText[i] = + (BASE * (hashText[i - 1] - text.charCodeAt(i - 1) * basePow) + + text.charCodeAt(i + patternLength - 1)) % + MOD + + // In case of hash collision, check character by character + if (hashText[i] < 0) { + hashText[i] += MOD + } + + // Check if the hashes match and perform a character-wise comparison + if (hashText[i] === hashPattern) { + if (text.substring(i, i + patternLength) === pattern) { + indices.push(i) // Store the index where the pattern is found + } + } + } + + return indices +} + +function hash(str: string, length: number): number { + let hashValue: number = 0 + for (let i = 0; i < length; i++) { + hashValue = (hashValue * BASE + str.charCodeAt(i)) % MOD + } + return hashValue +} + +export { rabinKarpSearch } diff --git a/search/sentinel_search.ts b/search/sentinel_search.ts index bbafdad5..93f1028d 100644 --- a/search/sentinel_search.ts +++ b/search/sentinel_search.ts @@ -10,7 +10,7 @@ * * @param {number[]} array - sorted list of numbers * @param {number} target - target number to search for - * @return {number|null} - index of the target number in the list, or null if not found + * @return {number | null} - index of the target number in the list, or null if not found * @see [SentinelSearch](https://www.geeksforgeeks.org/sentinel-linear-search/) * @example sentinelSearch([1,2,3], 2) => 1 * @example sentinelSearch([4,5,6], 2) => null @@ -30,7 +30,7 @@ export const sentinelSearch = ( if (arrayLength === 0) return null // Element to be searched is placed at the last index - const last = array[arrayLength - 1] + const last: number = array[arrayLength - 1] array[arrayLength - 1] = target let index: number = 0 diff --git a/search/ternary_search.ts b/search/ternary_search.ts new file mode 100644 index 00000000..2fa738bd --- /dev/null +++ b/search/ternary_search.ts @@ -0,0 +1,87 @@ +/* Ternary search is similar to binary search but it divides the sorted array + * into three parts and determines which part the key lies in. The array will + * be divided into three intervals by using two middle points, mid1 and mid2. + * The value of the key will first be compared with the two mid points, the value + * will be returned if there is a match. Then, if the value of the key is less + * than mid1, narrow the interval to the first part. Else, if the value of the + * key is greater than mid2, narrow the interval to the third part. Otherwise, + * narrow the interval to the middle part. Repeat the steps until the value is + * found or the interval is empty (value not found after checking all elements). + * + * Reference: https://www.geeksforgeeks.org/ternary-search/ + */ + +function ternarySearchRecursive( + arr: any[], + key: any, + low: number = 0, + high: number = arr.length - 1 +): number { + // if low > high => we have searched the whole array without finding the item + if (low > high) return -1 + + // find the mid1 and mid2 + const mid1: number = Math.floor(low + (high - low) / 3) + const mid2: number = Math.floor(high - (high - low) / 3) + + // check if key is found at any mid + // return index of key if found + if (arr[mid1] === key) return mid1 + + // return index of key if found + if (arr[mid2] === key) return mid2 + + // since the key is not found at mid, + // check in which region it is present + // and repeat the Search operation + // in that region + if (key < arr[mid1]) { + // the key lies in between low and mid1 + return ternarySearchRecursive(arr, key, low, mid1 - 1) + } else if (key > arr[mid2]) { + // the key lies in between mid2 and high + return ternarySearchRecursive(arr, key, mid2 + 1, high) + } else { + // the key lies in between mid1 and mid2 + return ternarySearchRecursive(arr, key, mid1 + 1, mid2 - 1) + } +} + +function ternarySearchIterative( + arr: any[], + key: any, + low: number = 0, + high: number = arr.length - 1 +): number { + while (high >= low) { + // find the mid1 and mid2 + const mid1: number = Math.floor(low + (high - low) / 3) + const mid2: number = Math.floor(high - (high - low) / 3) + + // check if key is found at any mid + // return index of key if found + if (arr[mid1] === key) return mid1 + + // return index of key if found + if (arr[mid2] === key) return mid2 + + // since the key is not found at mid, + // check in which region it is present + // and repeat the Search operation + // in that region + if (key < arr[mid1]) { + // the key lies in between low and mid1 + high = mid1 - 1 + } else if (key > arr[mid2]) { + // the key lies in between mid2 and high + low = mid2 + 1 + } else { + // the key lies in between mid1 and mid2 + ;[low, high] = [mid1 + 1, mid2 - 1] + } + } + // the key was not found + return -1 +} + +export { ternarySearchRecursive, ternarySearchIterative } diff --git a/search/test/binary_search.test.ts b/search/test/binary_search.test.ts index 13b13251..5ce01a5e 100644 --- a/search/test/binary_search.test.ts +++ b/search/test/binary_search.test.ts @@ -2,7 +2,7 @@ import { binarySearchIterative, binarySearchRecursive } from '../binary_search' describe('BinarySearch', () => { const testArray: number[] = [1, 2, 3, 4] - type FunctionsArray = { (array: number[], index: number): number | null }[] + type FunctionsArray = Array<(array: number[], index: number) => number | null> const functions: FunctionsArray = [ binarySearchIterative, binarySearchRecursive diff --git a/search/test/minesweeper.test.ts b/search/test/minesweeper.test.ts new file mode 100644 index 00000000..e76dfbd2 --- /dev/null +++ b/search/test/minesweeper.test.ts @@ -0,0 +1,75 @@ +import { minesweeper } from '../minesweeper' + +describe('Testing minesweeper function', () => { + it('should return the expected 3x3 array', () => { + const input = [ + [true, false, false], + [false, true, false], + [false, false, false] + ] + const expectedOutput = [ + [1, 2, 1], + [2, 1, 1], + [1, 1, 1] + ] + expect(minesweeper(input)).toStrictEqual(expectedOutput) + }) + + it('should return the expected 3x4 array', () => { + const input = [ + [true, false, false, true], + [false, false, true, false], + [true, true, false, true] + ] + const expectedOutput = [ + [0, 2, 2, 1], + [3, 4, 3, 3], + [1, 2, 3, 1] + ] + expect(minesweeper(input)).toStrictEqual(expectedOutput) + }) + + it('should return the expected 5x2 array', () => { + const input = [ + [true, false], + [true, false], + [false, true], + [false, false], + [false, false] + ] + const expectedOutput = [ + [1, 2], + [2, 3], + [2, 1], + [1, 1], + [0, 0] + ] + expect(minesweeper(input)).toStrictEqual(expectedOutput) + }) + + it('should return the correct result when there are no mines', () => { + const input = [ + [false, false, false], + [false, false, false] + ] + const expectedOutput = [ + [0, 0, 0], + [0, 0, 0] + ] + expect(minesweeper(input)).toStrictEqual(expectedOutput) + }) + + it('should return the correct result when there are mines in every cell', () => { + const input = [ + [true, true, true], + [true, true, true], + [true, true, true] + ] + const expectedOutput = [ + [3, 5, 3], + [5, 8, 5], + [3, 5, 3] + ] + expect(minesweeper(input)).toStrictEqual(expectedOutput) + }) +}) diff --git a/search/test/rabin_karp.test.ts b/search/test/rabin_karp.test.ts new file mode 100644 index 00000000..5af150ed --- /dev/null +++ b/search/test/rabin_karp.test.ts @@ -0,0 +1,30 @@ +import { rabinKarpSearch } from '../rabin_karp' + +describe('Rabin-Karp Search', function () { + it('should find the pattern in the text', function () { + const text: string = 'ABABDABACDABABCABAB' + const pattern: string = 'DAB' + const expected: number[] = [4, 9] + + const result: number[] = rabinKarpSearch(text, pattern) + expect(result).toEqual(expected) + }) + + it('should handle multiple occurrences of the pattern', function () { + const text: string = 'ABABABABABAB' + const pattern: string = 'ABAB' + const expected: number[] = [2, 4, 6, 8] + + const result: number[] = rabinKarpSearch(text, pattern) + expect(result).toEqual(expected) + }) + + it('should handle pattern not found', function () { + const text: string = 'ABCD' + const pattern: string = 'XYZ' + const expected: number[] = [] + + const result: number[] = rabinKarpSearch(text, pattern) + expect(result).toEqual(expected) + }) +}) diff --git a/search/test/ternary_search.test.ts b/search/test/ternary_search.test.ts new file mode 100644 index 00000000..b9591d24 --- /dev/null +++ b/search/test/ternary_search.test.ts @@ -0,0 +1,59 @@ +import { + ternarySearchRecursive, + ternarySearchIterative +} from '../ternary_search' + +test('should return the index of a number in an array of numbers:', () => { + const indexNumber = ternarySearchRecursive([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3) + expect(indexNumber).toBe(2) +}) + +test('should return the index of a number in an array of numbers:', () => { + const indexNumber = ternarySearchIterative([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 8) + expect(indexNumber).toBe(7) +}) + +test('should return the index of a number in an array of numbers:', () => { + const indexNumber = ternarySearchRecursive([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 0) + expect(indexNumber).toBe(-1) +}) + +test('should return the index of a number in an array of numbers:', () => { + const indexNumber = ternarySearchIterative( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + 12 + ) + expect(indexNumber).toBe(-1) +}) + +test('should return the index of a string in an array of strings:', () => { + const indexNumber = ternarySearchRecursive( + ['Ali', 'Cathrynli', 'Josuke', 'Thomas'], + 'Josuke' + ) + expect(indexNumber).toBe(2) +}) + +test('should return the index of a string in an array of strings:', () => { + const indexNumber = ternarySearchIterative( + ['Ali', 'Cathrynli', 'Josuke', 'Thomas'], + 'Josuke' + ) + expect(indexNumber).toBe(2) +}) + +test('should return the index of a string in an array of strings:', () => { + const indexNumber = ternarySearchRecursive( + ['Ali', 'Cathrynli', 'Josuke', 'Thomas'], + 'Angela' + ) + expect(indexNumber).toBe(-1) +}) + +test('should return the index of a string in an array of strings:', () => { + const indexNumber = ternarySearchIterative( + ['Ali', 'Cathrynli', 'Josuke', 'Thomas'], + 'Angela' + ) + expect(indexNumber).toBe(-1) +}) diff --git a/sorts/bubble_sort.ts b/sorts/bubble_sort.ts index 5ab1f853..f50887aa 100644 --- a/sorts/bubble_sort.ts +++ b/sorts/bubble_sort.ts @@ -1,31 +1,29 @@ /** - * @function bubbleSort - * @description Bubble sort algorithm is simple and easy. In bubble sort every pair of adjacent value is compared and swap if the first value is greater than the second one. By this with every iteration the greatest value goes to the right side making it ascending order.This algorithm is not suitable for large data sets as its average and worst-case time complexity is quite high. - * @Complexity_Analysis - * Space complexity - O(1) - * Time complexity - *      Best case   -   O(n^2) - * The best case occurs when an array is already sorted. - *      Worst case  -   O(n^2) - * The worst case occurs when an array is reverse sorted. - *      Average case -  O(n^2) - * The average case occurs when an array is reverse sorted. + * @function bubbleSort + * @description Bubble sort algorithm is simple and easy. In bubble sort every pair of adjacent value is compared and swap if the first value is greater than the second one. By this with every iteration the greatest value goes to the right side making it ascending order.This algorithm is not suitable for large data sets as its average and worst-case time complexity is quite high. + * @Complexity_Analysis + * Space complexity - O(1) + * Time complexity + * Best case - O(n^2) + * The best case occurs when an array is already sorted. + * Worst case - O(n^2) + * The worst case occurs when an array is reverse sorted. + * Average case - O(n^2) + * The average case occurs when an array is reverse sorted. * - * @param {number[]} arr - The input array - * @return {number[]} - The sorted array. - * @see [Bubble Sort](https://www.freecodecamp.org/news/bubble-sort) - * @example bubbleSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] + * @param {number[]} arr - The input array + * @return {number[]} - The sorted array. + * @see [Bubble Sort](https://www.freecodecamp.org/news/bubble-sort) + * @example bubbleSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] */ export const bubbleSort = (arr: number[]): number[] => { for (let i = 0; i < arr.length; i++) { for (let j = 0; j < arr.length - 1; j++) { - //iterating till the 2nd last element of array + // iterating till the 2nd last element of array if (arr[j] > arr[j + 1]) { - //current indexed number > next indexed number - const temp: number = arr[j] //swapping two numbers - arr[j] = arr[j + 1] - arr[j + 1] = temp + // current indexed number > next indexed number + ;[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]] } } }