diff --git a/Search/SentinelSearch.js b/Search/SentinelSearch.js new file mode 100644 index 0000000000..c6d14714a4 --- /dev/null +++ b/Search/SentinelSearch.js @@ -0,0 +1,35 @@ +/** + * @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, + * 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 : 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/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/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) + }) +}) 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) +})