diff --git a/Maths/MobiusFunction.js b/Maths/MobiusFunction.js index bd268b8bbd..4239d6ab31 100644 --- a/Maths/MobiusFunction.js +++ b/Maths/MobiusFunction.js @@ -28,6 +28,6 @@ export const mobiusFunction = (number) => { return primeFactorsArray.length !== new Set(primeFactorsArray).size ? 0 : primeFactorsArray.length % 2 === 0 - ? 1 - : -1 + ? 1 + : -1 } diff --git a/Search/JumpSearchOptimized.js b/Search/JumpSearchOptimized.js new file mode 100644 index 0000000000..eeac870ed4 --- /dev/null +++ b/Search/JumpSearchOptimized.js @@ -0,0 +1,59 @@ +/** + * This version of Jump Search works for both ascending and descending sorted arrays. + * + * Time Complexity: O(√n) + * Space Complexity: O(1) + * + * Example: + * jumpSearchOptimized([1, 3, 5, 7, 9, 11], 7) -> 3 + * jumpSearchOptimized([20, 15, 10, 5, 0], 10) -> 2 + */ + +function jumpSearchOptimized(arr, target) { + if (!Array.isArray(arr) || arr.length === 0) return -1 + + const n = arr.length + const step = Math.floor(Math.sqrt(n)) + let prev = 0 + + // Detect array order + const isAscending = arr[0] < arr[n - 1] + + // Jump in blocks based on order + while (prev < n) { + const next = Math.min(prev + step, n) + const value = arr[next - 1] + + if ((isAscending && value >= target) || (!isAscending && value <= target)) { + // Linear search in the found block + for (let i = prev; i < next; i++) { + if (arr[i] === target) return i + } + return -1 + } + + prev = next + } + + return -1 +} + +module.exports = { jumpSearchOptimized } + +/* ----------------------------------------- + Quick local test: run `node Search/JumpSearchOptimized.js` + ----------------------------------------- */ +if (require.main === module) { + const tests = [ + { arr: [1, 3, 5, 7, 9, 11], target: 7 }, + { arr: [20, 15, 10, 5, 0], target: 10 }, + { arr: [2, 4, 6, 8, 10, 12], target: 11 }, + { arr: [], target: 3 } + ] + + tests.forEach(({ arr, target }) => { + console.log( + `Array: [${arr}] | Target: ${target} | Index: ${jumpSearchOptimized(arr, target)}` + ) + }) +} diff --git a/Search/test/JumpSearchOptimized.test.js b/Search/test/JumpSearchOptimized.test.js new file mode 100644 index 0000000000..662c47ebdf --- /dev/null +++ b/Search/test/JumpSearchOptimized.test.js @@ -0,0 +1,37 @@ +import { jumpSearchOptimized } from '../JumpSearchOptimized' + +test('jumpSearchOptimized([0, 0, 4, 7, 10, 23, 34, 40, 55, 68, 77, 90], 77) => 10', () => { + const arr = [0, 0, 4, 7, 10, 23, 34, 40, 55, 68, 77, 90] + const res = jumpSearchOptimized(arr, 77) + expect(res).toEqual(10) +}) + +test('jumpSearchOptimized([11, 12, 15, 65, 78, 90], 4) => -1', () => { + const arr = [11, 12, 15, 65, 78, 90] + const res = jumpSearchOptimized(arr, 4) + expect(res).toEqual(-1) +}) + +test('jumpSearchOptimized([11, 12, 15, 65, 78, 90], 11) => 0', () => { + const arr = [11, 12, 15, 65, 78, 90] + const res = jumpSearchOptimized(arr, 11) + expect(res).toEqual(0) +}) + +test('jumpSearchOptimized([], 50) => -1', () => { + const arr = [] + const res = jumpSearchOptimized(arr, 50) + expect(res).toEqual(-1) +}) + +test('jumpSearchOptimized([5, 10, 15, 20, 25], 25) => 4', () => { + const arr = [5, 10, 15, 20, 25] + const res = jumpSearchOptimized(arr, 25) + expect(res).toEqual(4) +}) + +test('jumpSearchOptimized([1, 3, 5, 7, 9], 2) => -1', () => { + const arr = [1, 3, 5, 7, 9] + const res = jumpSearchOptimized(arr, 2) + expect(res).toEqual(-1) +})