From b0784447d9a6ac451e63d410111d8a9e633703cd Mon Sep 17 00:00:00 2001 From: hasanalkaf3 Date: Thu, 12 Sep 2024 18:42:19 +0300 Subject: [PATCH 1/4] feat: add sentinel search algorithm --- Search/QuickSelectSearch.js | 9 +++---- Search/SentinelSearch.js | 41 ++++++++++++++++++++++++++++++ Search/test/SentinelSearch.test.js | 13 ++++++++++ 3 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 Search/SentinelSearch.js create mode 100644 Search/test/SentinelSearch.test.js diff --git a/Search/QuickSelectSearch.js b/Search/QuickSelectSearch.js index c332af6721..7d2a5a4c3d 100644 --- a/Search/QuickSelectSearch.js +++ b/Search/QuickSelectSearch.js @@ -18,16 +18,15 @@ export function quickSelectSearch(array, k) { let from = 0 let to = array.length - 1 + while (from < to) { - let left = from - let right = to + let [left, right] = [from, to] + const pivot = array[Math.ceil((left + right) * 0.5)] while (left < right) { if (array[left] >= pivot) { - const tmp = array[left] - array[left] = array[right] - array[right] = tmp + ;[array[left], array[right]] = [array[right], array[left]] --right } else { ++left diff --git a/Search/SentinelSearch.js b/Search/SentinelSearch.js new file mode 100644 index 0000000000..8f595abf78 --- /dev/null +++ b/Search/SentinelSearch.js @@ -0,0 +1,41 @@ +/** + * @function sentinelSearch + * @description Sentinel search algorithm for array. + * + * Sentinel linear search is a variation of the standard linear search algorithm used to + * find a target value in an array or list. The basic idea behind this algorithm is to add a + * sentinel value at the end of the array which is equal to the target value we are looking for. + * This helps to avoid checking the array boundary condition during each iteration of the loop, + * as the sentinel value acts as a stopper for the loop. + * + * @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 + * @see [SentinelSearch](https://www.geeksforgeeks.org/sentinel-linear-search/) + * @example sentinelSearch([1,2,3], 2) => 1 + * @example sentinelSearch([4,5,6], 2) => null + * @complexity_analysis + * Time Complexity : + * Worst Case -> The time complexity of the Sentinel Linear Search algorithm is O(n) in the worst case. + * Best Case -> In the best case, when the key is found in the first iteration, the time complexity will be O(1). + * Average Case -> However, the average time complexity is still O(n). + * Auxiliary Space: O(1) + */ + +export const sentinelSearch = (array, target) => { + const arrayLength = array.length + if (arrayLength === 0) return null + + // Element to be searched is placed at the last index + const last = array[arrayLength - 1] + array[arrayLength - 1] = target + + let index = 0 + while (array[index] !== target) index++ + + // Put the last element back + array[arrayLength - 1] = last + + if (index < arrayLength - 1 || array[arrayLength - 1] === target) return index + return null +} diff --git a/Search/test/SentinelSearch.test.js b/Search/test/SentinelSearch.test.js new file mode 100644 index 0000000000..dde901fa30 --- /dev/null +++ b/Search/test/SentinelSearch.test.js @@ -0,0 +1,13 @@ +import { sentinelSearch } from '../SentinelSearch' + +describe('Sentinel search', () => { + test.each([ + [['o', 'b', 'c'], 'c', 2], + [[1, 2, 3, 4, 5], 4, 3], + [['s', 't', 'r', 'i', 'n', 'g'], 'a', null], + [['1', '2', '3'], '1', 0], + [['4', 'e', '6', '10'], 4, null] + ])('of %o , searching for %o, expected %i', (array, target, index) => { + expect(sentinelSearch(array, target)).toStrictEqual(index) + }) +}) From 163f1c0f7b51d18c8308a5cc9239f556251a9364 Mon Sep 17 00:00:00 2001 From: hasanalkaf3 Date: Thu, 26 Sep 2024 14:56:42 +0300 Subject: [PATCH 2/4] chore: improve Ternary Search algorithm --- Search/TernarySearch.js | 69 ++++++++++++++----------------- Search/test/TernarySearch.test.js | 14 +++++-- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/Search/TernarySearch.js b/Search/TernarySearch.js index ea0d049341..1e0c568a61 100644 --- a/Search/TernarySearch.js +++ b/Search/TernarySearch.js @@ -12,38 +12,33 @@ */ function ternarySearchRecursive(arr, key, low = 0, high = arr.length - 1) { - if (high >= low) { - // find the mid1 and mid2 - const mid1 = Math.floor(low + (high - low) / 3) - const mid2 = Math.floor(high - (high - low) / 3) + // if low > high => we have searched the whole array without finding the item + if (low > high) return -1 - // check if key is found at any mid - if (arr[mid1] === key) { - // return index of key if found - return mid1 - } - if (arr[mid2] === key) { - // return index of key if found - return mid2 - } + // find the mid1 and mid2 + const mid1 = Math.floor(low + (high - low) / 3) + const mid2 = Math.floor(high - (high - low) / 3) - // 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) - } + // 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 { - // if low > high => we have searched the whole array without finding the item - return -1 + // the key lies in between mid1 and mid2 + return ternarySearchRecursive(arr, key, mid1 + 1, mid2 - 1) } } @@ -54,14 +49,11 @@ function ternarySearchIterative(arr, key, low = 0, high = arr.length - 1) { const mid2 = Math.floor(high - (high - low) / 3) // check if key is found at any mid - if (arr[mid1] === key) { - // return index of key if found - return mid1 - } - if (arr[mid2] === key) { - // return index of key if found - return mid2 - } + // 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 @@ -75,8 +67,7 @@ function ternarySearchIterative(arr, key, low = 0, high = arr.length - 1) { low = mid2 + 1 } else { // the key lies in between mid1 and mid2 - low = mid1 + 1 - high = mid2 - 1 + ;[low, high] = [mid1 + 1, mid2 - 1] } } // the key was not found diff --git a/Search/test/TernarySearch.test.js b/Search/test/TernarySearch.test.js index 375c5c5fbd..a1a7a2ccd1 100644 --- a/Search/test/TernarySearch.test.js +++ b/Search/test/TernarySearch.test.js @@ -29,13 +29,13 @@ test('should return the index of a number in an array of numbers:', () => { test('should return the index of a string in an array of strings:', () => { const indexNumber = ternarySearchRecursive( ['Ali', 'Cathrynli', 'Josuke', 'Thomas'], - 'Cathrynli' + 'Josuke' ) - expect(indexNumber).toBe(1) + expect(indexNumber).toBe(2) }) test('should return the index of a string in an array of strings:', () => { - const indexNumber = ternarySearchRecursive( + const indexNumber = ternarySearchIterative( ['Ali', 'Cathrynli', 'Josuke', 'Thomas'], 'Josuke' ) @@ -49,3 +49,11 @@ test('should return the index of a string in an array of strings:', () => { ) 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) +}) From 8d7d6ea38228532db7c6bab047a42d623a3d6910 Mon Sep 17 00:00:00 2001 From: hasanalkaf3 Date: Thu, 3 Oct 2024 18:57:06 +0300 Subject: [PATCH 3/4] chore: update SentinelSearch.js --- Search/QuickSelectSearch.js | 8 +++++--- Search/SentinelSearch.js | 10 ++-------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Search/QuickSelectSearch.js b/Search/QuickSelectSearch.js index 7d2a5a4c3d..2cf7a17b82 100644 --- a/Search/QuickSelectSearch.js +++ b/Search/QuickSelectSearch.js @@ -18,15 +18,17 @@ export function quickSelectSearch(array, k) { let from = 0 let to = array.length - 1 - while (from < to) { - let [left, right] = [from, to] + let left = from + let right = to const pivot = array[Math.ceil((left + right) * 0.5)] while (left < right) { if (array[left] >= pivot) { - ;[array[left], array[right]] = [array[right], array[left]] + const tmp = array[left] + array[left] = array[right] + array[right] = tmp --right } else { ++left diff --git a/Search/SentinelSearch.js b/Search/SentinelSearch.js index 8f595abf78..c6d14714a4 100644 --- a/Search/SentinelSearch.js +++ b/Search/SentinelSearch.js @@ -1,8 +1,5 @@ /** - * @function sentinelSearch - * @description Sentinel search algorithm for array. - * - * Sentinel linear search is a variation of the standard linear search algorithm used to + * @description Sentinel linear search is a variation of the standard linear search algorithm used to * find a target value in an array or list. The basic idea behind this algorithm is to add a * sentinel value at the end of the array which is equal to the target value we are looking for. * This helps to avoid checking the array boundary condition during each iteration of the loop, @@ -15,10 +12,7 @@ * @example sentinelSearch([1,2,3], 2) => 1 * @example sentinelSearch([4,5,6], 2) => null * @complexity_analysis - * Time Complexity : - * Worst Case -> The time complexity of the Sentinel Linear Search algorithm is O(n) in the worst case. - * Best Case -> In the best case, when the key is found in the first iteration, the time complexity will be O(1). - * Average Case -> However, the average time complexity is still O(n). + * Time Complexity : O(n) * Auxiliary Space: O(1) */ From 2303b28b5bd8628541ec08a28487ba0821fb8b95 Mon Sep 17 00:00:00 2001 From: hasanalkaf3 Date: Thu, 3 Oct 2024 20:52:43 +0300 Subject: [PATCH 4/4] style: remove unrelated changes --- Search/QuickSelectSearch.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Search/QuickSelectSearch.js b/Search/QuickSelectSearch.js index 2cf7a17b82..c332af6721 100644 --- a/Search/QuickSelectSearch.js +++ b/Search/QuickSelectSearch.js @@ -21,7 +21,6 @@ export function quickSelectSearch(array, k) { while (from < to) { let left = from let right = to - const pivot = array[Math.ceil((left + right) * 0.5)] while (left < right) {