Related
having a problem when running two tests using this code, test 1 returns the whole array, test2 returns the appropriate index. (the point in the array in which it stops decreasing or increasing and starts the reverse) if there is only one sequence it should return -1
the test cases are
Input: [-4, -2, 9, 10]
Output: -1
Input: [5, 4, 3, 2, 10, 11]
Output: 3
for (i = 0; i < arr.length; i++) {
while (arr[i] < arr[i + 1]) {
i++;
if (arr[i] < arr[i - 1]) {
return -1
}
else if (arr[i] > arr[i + 1]) {
return i
}
} while (arr[i] > arr[i + 1]) {
i++;
if (arr[i] > arr[i - 1]) {
return -1
} else if (arr[i] < arr[i + 1]) {
return i
}
}
}
return arr;
}
In the solution below, the isHomogeneous() method returns true if the content of the array is ever-increasing or ever-decreasing. The isIncreasing() method returns true if the array content is constantly decreasing. The isDecreasing() method returns true if the array content is ever-increasing. The getAscendingIndex() method returns the index at which the contents of the array begin to decrease. The getDescendingIndex() method returns the index at which the contents of the array begin to decrease. The application() method contains application code that executes other methods. If the content of the array is not homogeneous (continuously increasing or decreasing), the first index value at which the values start to increase in an array that starts with decreasing values is obtained using the getDescendingIndex() method.
/* Returns true if the array is descending to the elements (homogeneous). */
function isIncreasing(array) {
for(let i = 0 ; i < array.length ; ++i)
if(array[i] < array[i + 1])
return false;
return true;
}
/* Returns true if the array is incremental (homogeneous) to the elements. */
function isDecreasing(array) {
for(let i = 0 ; i < array.length ; ++i)
if(array[i] > array[i + 1])
return false;
return true;
}
/* Returns true if the array content is ever-increasing or ever-decreasing. */
function isHomogeneous(array) {
return isIncreasing(array) || isDecreasing(array);
}
/* return the descending index in the array starting with increasing. */
function getAscendingIndex(array) {
for(let i = 0 ; i < array.length ; ++i)
if(array[i] > array[i + 1])
return i;
return -1;
}
/* return increasing index in array starting with decreasing. */
function getDescendingIndex(array) {
for(let i = 0 ; i < array.length ; ++i)
if(array[i] < array[i + 1])
return i;
return -1;
}
/* demo */
function application() {
let firstArray = [-4, -2, 9, 10];
let secondArray = [5, 4, 3, 2, 10, 11];
console.log(`Increasing: ${(isIncreasing(firstArray) == true) ? "true" : "false"}`);
console.log(`Decreasing: ${(isDecreasing(firstArray) == true) ? "true" : "false"}`);
console.log(`First Array Index: ${getAscendingIndex(firstArray)}`);
if(!isHomogeneous(secondArray) && getAscendingIndex(secondArray) != -1) {
console.log(`Second Array Index: ${getDescendingIndex(secondArray)}`);
}
}
application();
Maybe this approach would be useful:
Find the index of the maximum and minimum element.
Check if this index is the beginning or the end of the array and retern -1 if it is.
And last return the maximal index out of the found ones.
const first = [-4, -2, 9, 10];
const second = [5, 4, 3, 2, 10, 11];
const getMyIndex = (arr) => {
const maxIndex = arr.indexOf(Math.max(...arr));
const minIndex = arr.indexOf(Math.min(...arr));
const getResult = (index) =>
(index === 0) || (index === arr.length - 1) ? -1 : index;
return Math.max(getResult(maxIndex), getResult(minIndex));
};
console.log('arr:', first, 'result:', getMyIndex(first));
console.log('arr:', second, 'result:', getMyIndex(second));
.as-console-wrapper{min-height: 100%!important; top: 0}
java solution that works!!!hope you will find it useful
public class MyClass {
public static void main(String args[]) {
int[] arr={1,2,3,4,5,6,7,1,2,3};
boolean asc=false;
boolean dsc=false;
int n=arr.length;
int x=0;
int y=0;
for(int i=1;i<n;i++){
if(arr[i]<arr[i-1]){
x=i;
break;
}
if(i==n-1){
if(arr[i]>arr[i-1])
asc=true;
}
}
for(int i=1;i<n;i++){
if(arr[i]>arr[i-1]){
y=i;
break;
}
if(i==n-1){
if(arr[i]<arr[i-1])
dsc=true;
}
}
if(asc||dsc)
System.out.println("-1");
else{
if(x>y)
System.out.println("asc"+(x-1));
else
System.out.println("dsc"+(y-1));
}
}
}
arr = [ 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 ]
const JumpSearch = (arr, num) => {
const length = arr.length;
const eachBlock = Math.floor(length/4);
let index = 0;
while(index < length){
let temp = arr[index];
if(num < temp){
//search left
index = index - 1;
} else if(num === temp) {
//matched return this
return true
} else {
// jump eachBlock
index = index + eachBlock;
}
}
return false;
} // O(√4)
console.log(JumpSearch(arr, 14))
Here i am trying to implement JumpSearch in javascript.
It is sometimes coming stay running the else block infinitely if the
result is not matching.
PLease have a look.
I think this is correct, basically adapted from the PHP code. You could actually pass in the interval. They say the square root of the array length is optimal. The first loop get the interval and returns -1 if num is not in an interval. The second loop starts at the beginning of the interval increments the index by 1 starting at the beginning of the interval until the end of the interval is reached of the end of the array is reached. Seems to work.
arr = [0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233];
const JumpSearch = (arr, num) => {
const length = arr.length;
const interval = 3;
let current = interval;
let prev = 0;
while (arr[Math.min(current, length) - 1] < num) {
prev = current;
current += interval;
if (prev >= length) {
return -1;
}
}
while (arr[prev] < num) {
prev++;
// If we reached next block or end of
// array, element is not present.
if (prev == Math.min(current, length)) return -1;
}
// If element is found
if (arr[prev] == num) return prev;
else return -1;
}
console.log(JumpSearch(arr, 21));
I have a sorted array:
[0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000]
I am trying to use a binary search to parse this sorted array and return all values of the array that are greater or equal to a given value. So if I feed my search 6, the resulting array I desire would be:
[6, 6, 6, 50, 70, 80, 81, 100, 10000]
I cannot just look for the first occurence of a value, because the value may not be present in the array. For example, I may have to look for 5, which is not present, but my output would need to be the same as above.
I have some code here that is stuck in an infinite loop at this jsFiddle: http://jsfiddle.net/2mBdL/691/
var arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000];
function binarySearch(arr, i) {
var mid = Math.floor(arr.length / 2);
var leftOfMid = mid - 1;
console.log(arr[mid], i);
if (arr[mid] == i && arr[leftOfMid] == i) {
console.log('needle is exactly at 6, but left is same, checking lower half', arr[mid], i);
binarySearch(arr.splice(leftOfMid, Number.MAX_VALUE), i);
} else if (arr[mid] < i && arr.length > 1) {
console.log('needle is at a value that is less than 6', arr[mid], i);
binarySearch(arr.splice(mid, Number.MAX_VALUE), i);
} else if (arr[mid] > i && arr.length > 1) {
console.log('needle is at a value that is higher than 6 days', arr[mid], i);
binarySearch(arr.splice(0, mid), i);
} else if (arr[mid] == i && arr[leftOfMid] < i) {
console.log('MATCH, needle is the beginning of the range', arr[mid], i);
return arr[mid];
}
else {
console.log('not here', i);d
return -1;
}
}
var result = binarySearch(arr, 6);
console.log(result);
How could I utilize a binary search for this use case? The array can get very large, so I am really trying to get this to work!
You can use binary search for this. You just need to search for the boundary where the values go from being less than the target to greater or equal to the target.
function bsearch(arr, lim, start = 0, end = arr.length - 1) {
let index = Math.floor((end - start) / 2) + start
if (start >= end) return -1
if (arr[index] > lim)
return (arr[index - 1] < lim || arr[index - 1] === undefined) ? index : bsearch(arr, lim, start, index)
if (arr[index] < lim)
return arr[index - 1] > lim ? index : bsearch(arr, lim, index + 1, end)
if (arr[index] === lim) {
return (arr[index - 1] === lim) ? bsearch(arr, lim, start, index) : index
}
}
let arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000]
// all values >= 6
let index = bsearch(arr, 6)
console.log(arr.slice(index))
// all values >= 5
index = bsearch(arr, 5)
console.log(arr.slice(index))
On large arrays this will have all the benefits of binary search. For example searching an array of 10000 elements only takes about 13 iterations.
You can simply use Array.prototype.filter to filter elements in an array.
array.filter(i => i >= 6)
console.log(
[0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000]
.filter(i => i >= 6)
);
Or in a functional form:
function search(arr, n) {
return arr.filter(i => i >= n);
}
let arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000]
function search(arr, n) {
return arr.filter(i => i >= n);
}
console.log( search(arr, 6) );
Binary search will not help here because it searches for a single value not for a range so you can not know if the value you are testing in current iteration is the first one that is greater than 6 or not. The solution is really simple:
arr.filter(e => e > i);
A binary search can really help with large arrays, for smaller ones it likely doesn't matter. I think your strategy is OK but the implementation seems a bit convoluted so I can't see where your error is.
Consider the following, I've tried to keep it simple with comments:
var arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000];
function binaryFind(arr, value) {
// Helper: go down until stop getting matches
function goLeft(arr, value, pos) {
while (arr[pos - 1] == value) --pos;
return arr.slice(pos);
}
// Find match or first value larger
function search(arr, value, pos, iteration, direction) {
// Update position for this iteration
++iteration;
pos += direction * arr.length / (iteration*2) | 0;
// Check if at start or end of array
if (pos >= arr.length) {
return [];
} else if (pos <=0) {
return arr.slice(0);
}
// Hit value
if (arr[pos] == value) {
return goLeft(arr, value, pos);
}
// Under
if (arr[pos] < value) {
// Check higher adjacent
if (arr[pos + 1] >= value) {
return arr.slice(pos+1);
}
//Otherwise search up
return search(arr, value, pos, iteration, 1);
}
// Over
if (arr[pos] > value) {
// Check lower adjacent
if (arr[pos - 1] < value) {
return arr.slice(pos);
}
// Otherwise search down
return search(arr, value, pos, iteration, -1);
}
}
return search(arr, value, 0, 0, 1);
}
[0,1,2,3,4,5,6,7,55,1e6,555,70,69,-1,71].forEach(v =>
console.log(v + ': ' + binaryFind(arr, v))
);
Mark Meyer's idea of searching for the boundary got me thinking, so here's a version that should be more efficient as it continues to use a binary search rather than "walking" down matching values (it looks for the first value that is le). Of course testing with real data will determine whether that's a benefit or not but it's a simpler solution.
The search function is wrapped in an outer function to protect the additional parameters from abuse. Without the wrapper it's 3 lines of code, but one is a bit long. ;-)
// Use a binary search to find all elements in a sorted array
// that are equal to or greater than value.
function binaryFind(arr, value) {
function search(arr, value, pos=0, iteration=1, direction=1) {
pos += direction * arr.length / (iteration*2) | 0;
return pos >= arr.length? [] :
pos <=0? arr.slice(0) :
arr[pos] < value? (arr[pos + 1] >= value? arr.slice(pos+1) : search(arr, value, pos, ++iteration, 1)):
(arr[pos - 1] < value? arr.slice(pos) : search(arr, value, pos, ++iteration, -1));
}
return search(arr, value);
}
// Testing
var arr = [0, 1, 1, 2, 3, 4, 6, 6, 6, 50, 70, 80, 81, 100, 10000];
[0,1,2,3,4,5,6,7,55,1e6,555,70,69,-1,71].forEach(v =>
console.log(v + ': ' + binaryFind(arr, v))
);
I am attempting to write a "binary search" which I've never done before. The code below does not work when the value searched for is 6 or 2 and I want to know what I am doing wrong and how to remedy it.
EDIT
To explain what it is suppose to do (based on my understanding) a binary search requires that an array is already sorted, it then looks for the mid-point index of an array. For example, if an array had nine indexes (0-8)the the mid point would be index 4.
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
The algorithm then determines if that mid point has a higher or lower value than the number you are searching for. All elements on the side of the array that does not contain the searched for number and that exist before the midpoint value simply get removed. If the search for value is 8 then the result would be:
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
array midpoint value: 5
[ 5, 6, 7, 8, 9 ]
array midpoint value: 7
[ 7, 8, 9 ]
array midpoint value: 8
Code
//_________________________________________________BEGIN notes
// Step 1. Get length of array
// Step 2. Find mid point
// Step 3. Compare if mid point is lower or higher than searched number
// Step 4. lop off unneeded side
// Step 5. go to step 1
//_________________________________________________END notes
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 44, 55];
function getMidPoint(arr, searchNumb) {
var length = arr.length;
var midPoint = Math.floor(length / 2);
var newArr = arr;
console.log(arr);
console.log("array midpoint value: " + arr[midPoint]);
if (arr[midPoint] > searchNumb) {
var newArr = arr.slice(0, arr[midPoint]);
return getMidPoint(newArr, searchNumb);
} else if (arr[midPoint] < searchNumb) {
var newArr = arr.slice(midPoint, arr.length);
return getMidPoint(newArr, searchNumb);
} else {
return arr
}
}
Language agnostic, here is the simplified flow of a recursive binary search implementation, assuming we have an (initially non-empty) array [ARR] and a target [T], where we refer to the middle element of ARR as M:
// 1. If M == T, return true
// 2. If length of ARR is 0, return false (note: step 1 short circuits, ensuring we only hit step 2 if step 1 evaluates to false)
// 3. If T < M, return the result of the recursion on the lower half of ARR
// 4. If T > M, return the result of the recursion on the the latter half of ARR
Following is solution that executes the control flow outlined above. This is similar to solutions already presented in this post, with a few noteworthy differences:
function binarySearch(arr, target, start=0, stop=(arr.length-1)) {
let midPoint = Math.floor(((stop-start)/2) + start)
switch (true) {
case arr[midPoint] === target:
return true
case stop - start === 0:
return false
case arr[midPoint] < target:
return binarySearch(arr, target, midPoint+1, stop)
case arr[midPoint] > target:
return binarySearch(arr, target, start, midPoint)
}
}
Let's unpack the main differences of this implementation:
Slice is no longer used:
We are eschewing the use of Array.prototype.slice because it is a relatively expensive operation (copying half of the current array with each recursive call!) and it is not required for the algorithm to function properly.
In place of slice, we are passing the start and stop indexes of the range of the array that we have narrowed the search down to. This keeps our heap happy by not cluttering it with (potentially many) partial, impermanent copies of the same (potentially massive) array.
We are passing two additional arguments, and they have defaults:
These arguments (start and stop) serve to keep track of the range of the array we are currently recurring on. They are our alternative to slice!
The default arguments enable us to call this recursive function exactly the same as we would when using slice (should the user not provide an explicit range when it is first called).
We are using a switch statement:
The speed of a switch statement vs. an if-else chain depends on several factors, most notably the programming language and the amount of conditionals in each. A switch statement was used here primarily for readability. It is a control flow that matches what we are concerned with handling in this recursive function: 4 discrete cases, each requiring different action. Additionally, a few individuals have a rare allergy to if-else statements that exceed 3 logical tests.
For more information on JavaScript's switch statement and its performance vs. if-else, please take a look at this post: Javascript switch vs. if...else if...else, which links to this more informative page http://archive.oreilly.com/pub/a/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html
You are slicing it wrong.
Use this code:
//_________________________________________________BEGIN notes
// Step 1. Get length of array
// Step 2. Find mid point
// Step 3. Compare if mid point is lower or higher than searched number
// Step 4. lop off unneeded side
// Step 5. go to step 1
//_________________________________________________END notes
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 44, 55];
function getMidPoint(arr, searchNumb) {
var length = arr.length;
var midPoint = Math.floor(length / 2);
var newArr = arr;
console.log(arr);
console.log("array midpoint value: " + arr[midPoint]);
if (arr[midPoint] > searchNumb) {
var newArr = arr.slice(0, midPoint);
return getMidPoint(newArr, searchNumb);
} else if (arr[midPoint] < searchNumb) {
var newArr = arr.slice(midPoint + 1, arr.length);
return getMidPoint(newArr, searchNumb);
} else {
return midPoint;
}
}
Also, if the search element is not in array, this will go on infinitely. Add a base case for that too.
I think that this line:
var newArr = arr.slice(0, arr[midPoint]);
should probably be:
var newArr = arr.slice(0, midPoint);
But I don't know if that's the only issue with your code. (It's not clear to me what the code is supposed to actually do. Right now "getMidPoint" appears to returns a smaller array containing the searched-for value.)
Probably You are already a master with Binary search. However I would like to indicate that is not necessary to create a sliding window for resolving a binary search.
function binarySearch(arr, value){
if(!arr.length) return -1;
let average = Math.floor(arr.length-1/2);
if (value === arr[average]) return average;
if (value > arr[average]) return binarySearch(arr.slice(average+1),value);
if (value < arr[average]) return binarySearch(arr.slice(0,average),value);
}
binarySearch([1,2,3,4,5],6) //-1
binarySearch([1,2,3,4,5],3) //2
Follow this steps to create the Binary search with recursion:
function binarySearch(arr, value){
1 ) implement a base case
if(!arr.length) return -1;
2 ) create a middle point
let average = Math.floor(arr.length-1/2);
3 ) if the middle point is equal to the searched valued, you found it! return the value
if (value === arr[average]) return average;
4) if the value is greater than the middle point run a new process with only the sub array starting from the middle + 1 till the end
if (value > arr[average]) return binarySearch(arr.slice(average+1),value);
5) if the value is lower than the middle point run a new process with only the sub array starting from 0 to the middle
if (value < arr[average]) return binarySearch(arr.slice(0,average),value);
}
I hope it helps!
Note: you can use a switch statement in order to not repeat if,if,if but I like it more this way, more readable.
For solving the question in recursion please find the answer and explanation below.
const BinarySearchRec = (arr, el) => {
// finding the middle index
const mid = Math.floor(arr.length / 2);
if (arr[mid] === el) {
// if the element is found then return the element.
return mid;
}
if (arr[mid] < el && mid < arr.length) {
/** here we are having the value returned from recursion as
the value can be -1 as well as a value which is in second half of the original array.**/
const retVal = BinarySearchRec(arr.slice(mid + 1, arr.length), el);
/** if value is greater than or equal to 0 then only add that value with mid
and also one as mid represents the index.
Since index starts from 0 we have to compensate it as we require the length here.**/
return retVal >= 0 ? mid + 1 + retVal : -1;
}
if (arr[mid] > el) {
// here we need not do any manipulation
return BinarySearchRec(arr.slice(0, mid), el);
}
return -1;
};
The above solutions which have been added and the one accepted fails in scenarios when the element to be found is in the second half.
There is solution with while loop which works correctly but since the question was to solve it recursively I have given a comprehensive recursive version.
There are 2 issues in your code :-
1) You are slicing it incorrectly
2) You have not put any base condition
This code should work hopefully :-
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 44, 55];
function getMidPoint(arr, searchNumb) {
var length = arr.length;
var midPoint = Math.floor(length / 2);
var newArr = arr;
console.log(arr);
console.log("array midpoint value: " + arr[midPoint]);
if (arr[midPoint] > searchNumb) {
var newArr = arr.slice(0, midPoint);
return getMidPoint(newArr, searchNumb);
} else if (arr[midPoint] < searchNumb) {
var newArr = arr.slice(midPoint+1, arr.length);
return getMidPoint(newArr, searchNumb);
} else {
return arr[midPoint];
}
}
This function would return undefined if element is not found in array.
This is fully rewritten code to achieve your goal (commented, linted).
This example doesn't have any checks for params.
Main error:
wrong slicing
Disadvantages of this approach:
recursion is slower and takes up more of the stack
slice() also there is no needed (because of the stack again)
/**
* Searches recursively number from the list
* #param {Array} list
* #param {number} item Search item
* #param {number} low Lower limit of search in the list
* #param {number} high Highest limit of search in the list
* #param {number} arrLength Length of the list
* #return {(number | null)} Number if the value is found or NULL otherwise
*/
const binarySearch = ( list, item, low, high, arrLength ) => {
while ( low <= high ) {
let mid = Math.floor((low + high) / 2);
let guess = list[mid];
if ( guess === item ) {
return mid;
} else if ( guess > item ) {
high = mid - 1;
list = list.slice( 0, mid );
return binarySearch( list, item, low, high );
} else {
low = mid + 1;
list = list.slice( low, arrLength );
return binarySearch( list, item, low, high );
}
}
return null;
};
/**
* Creates the array that contains numbers 1...N
* #param {number} n - number N
* #return {Array}
*/
const createArr = ( n ) => Array.from({length: n}, (v, k) => k + 1);
const myList = createArr( 100 );
const arrLength = myList.length;
let low = 0;
let high = arrLength - 1;
console.log( '3 ' + binarySearch( myList, 3, low, high, arrLength ) ); // 2
console.log( '-1 ' + binarySearch( myList, -1, low, high, arrLength ) ); // null
I think it's more elegant solution for binary search:
const binarySearch = ( list, item ) => {
let low = 0;
let high = list.length - 1;
while ( low <= high ) {
let mid = Math.floor((low + high) / 2);
let guess = list[mid];
if ( guess === item ) {
return mid;
} else if ( guess > item ) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return null;
};
const myList = [1, 3, 5, 7, 9];
console.log( binarySearch( myList, 3 ) );
console.log( binarySearch( myList, -1 ) );
Here's my recursive binary search solution:
// arr = sorted array, val = search value
// left and right are the index pointers enclosing the search value
// e.g. binarySearch([1,5,7,9,14,17,24,29,33,38,49,52,61,62,70,80,90,95,104,107,109],70)
binarySearch = (arr,val,left=0,right=arr.length) => {
position = (left,right) => {
let pos = (left + right)/2
return Math.floor(pos)
}
let i = position(left,right)
if (arr[i] === val) {
return i
}
// Base Case: if left and midpoint index coincide then there are no more possible solutions
else if (i === left) {
return -1
}
// For this case we shift the left index pointer
else if (arr[i] < val) {
return binarySearch(arr,val,i,right)
}
// For this case we shift the right index pointer
else if (arr[i] > val) {
return binarySearch(arr,val,left,i)
}
}
Here is my approach for binary search recursively.
We don't slice the array because it is not needed if we can just pass down the indexes.
I think that will save some time.
Function will return index if the element is found and -1 if not.
l is standing for left, r is standing for right.
function binarySearch(arr, searchNumber) {
return _binarySearch(0, arr.length -1, arr, searchNumber);
function _binarySearch(l, r, arr, searchNumber) {
const mid = Math.floor((l + r) / 2);
const guess = arr[mid];
if (guess === searchNumber) { // base case
return mid;
} else if (l === r) { // end-case the element is not in the array
return -1;
} else if (guess < searchNumber) {
return _binarySearch(mid + 1, arr.length - 1, arr, searchNumber);
} else if (guess > searchNumber) {
return _binarySearch(l, mid - 1, arr, searchNumber);
}
}
}
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(binarySearch(list, 4));
Simple and Easy
let arr = [1,2,3,4,5];
function BinarySearch(arr, start, end, key) {
if(start > end) return -1;
let mid = Math.floor((start + end) / 2);
if(arr[mid] === key) return mid;
if(key > arr[mid]) {
return BinarySearch(arr, mid + 1, end, key);
} else if(key < arr[mid]) {
return BinarySearch(arr, start, mid -1, key);
}
}
BinarySearch([1,3,4,5], 0, arr.length - 1, 1); // it will return 0;
BinarySearch recursion Returning search element index.
Below code worked for me
function binerySearchRecursive(arr, num, start=0 end=arr.length-1){
let mid = Math.floor((start+end/2));
if(start> end){
return -1; // edge case if array has 1 element or 0
}
if(num === arr[mid])
return mid;
else if(num < arr[mid])
return binerySearchRecursive(arr, num, start, mid-1 );
else
return binerySearchRecursive(arr, num, mid+1 , end);
}
binerySearchRecursive([1,2,3,4,5], 5)
function binarySearch(arr, n) {
let mid = Math.floor(arr.length / 2);
// Base case
if (n === arr[mid]) {
return mid;
}
//Recursion
if (n > arr[mid]) {
return mid + binarySearch(arr.slice(mid, arr.length), n)
} else {
return binarySearch(arr.slice(0, mid), n)
} }
Simple solution to recursive binary search
For a recursive binary search you can try this :
function recursiveBinarySearch(lst, target, start=0, end=(lst.length-1)){
let midPoint = (Math.floor((start+end)/2));
if (start > end){
return false;
}
if (lst[midPoint] === target){
return true;
}
else{
if(lst[midPoint] < target){
return recursiveBinarySearch(lst, target, midPoint+1, end);
}
else{
return recursiveBinarySearch(lst, target, start, midPoint-1);
}
}
}
this too late but i hope this well be useful for some one :)
const items = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
let target = 30;
function binarySearch(L,R){
if(L == R){
return false;
}
let mid = Math.floor((L + R)/2);
if(mid == target){
return target;
}
if(mid > target){
binarySearch(L,mid);
}
if(mid < target){
binarySearch(mid+1,R);
}
}
binarySearch(1,items.length);
This is the most comprehensive version of binary recursive search for JavaScript. In my opinion, this is O(log n).
function binaryRecursion(arr, val) {
if (arr.length === 0) return -1
let middle = Math.floor(arr.length - 1 / 2)
if (arr[middle] === val) return middle;
if (val > arr[middle]) {
return binaryRecursion(arr.slice(middle + 1), val)
}
if (val < arr[middle]) {
return binaryRecursion(arr.slice(0, middle), val)
}
}
This returns the index of the element, not whether it exists or not.
I'm new to lodash and just getting the feel for functional programming with javascript. I'm using lodash 3.0.0-pre.
I have an array of numbers that are in order and a target number.
I need an array with the first and second closest numbers unless it was the last number then I just need it. How do I get that using lodash?
I found:
function getClosest(array, target) {
var tuples = _.map(array, function(val) {
return [val, Math.abs(val - target)];
});
return _.reduce(tuples, function(memo, val) {
return (memo[1] < val[1]) ? memo : val;
}, [-1, 999])[0];
}
I could change it to give me the closest two instead of one but I believe it will sequence through the entire array instead of just stopping once it has the two numbers it needs since it can stop when the difference in numbers starts to increase.
I would recommend not to use lodash looping functions here if you care about performance.
As soon as you array is ordered - it's good to use a modified version of Binary search to find index of the closest value:
function closestIndex(arr, target) {
var i = 0, j = arr.length - 1, k;
while (i <= j) {
k = Math.floor((i+j) / 2);
if (target === arr[k] || Math.abs(i - j) <= 1 ) {
return k;
} else if (target < arr[k]) {
j = k-1;
} else {
i = k+1;
}
}
return -1;
}
and then simply compare adjacent elements in the array:
if (_.isNumber(arr[closestIndex - 1]) && _.isNumber(arr[closestIndex + 1])) {
if (Math.abs(target - arr[closestIndex - 1]) < Math.abs(target - arr[closestIndex + 1])) {
result.push(arr[closestIndex - 1]);
} else {
result.push(arr[closestIndex + 1]);
}
}
See full example here.
Not really a lodash task because it's not an easy n -> n or n -> 1 transformation. Additionally lodash doesn't allow you to cancel a statement early.
Anyway here's a solution:
var array= [2, 3, 5, 25, 135, 250, 300];
function getClosest(array, target) {
var tuples = _.map(array, function(val) {
return [val, Math.abs(val - target)];
});
var prev= [0, Number.MAX_VALUE];
for(var i=0; i<tuples.length; i++){
if(tuples[i][1] < prev[1]){
prev= tuples[i];
}else{
if(i<2 || tuples[i][1] < tuples[i-2][1]){
return [prev[0], tuples[i][0]];
}else{
return [prev[0], tuples[i-2][0]];
}
}
}
return [prev[0]];
}
console.log(getClosest(array, 3));
Could be optimized by finding the nearest element with Newton's method and then looking at elements before and after that. (If you have like 50000 numbers in your array ^^)
Assuming that your array is sorted and arr[0] ≤ target:
var getClosests = function (arr, target) {
var last = _.last(arr)
if (target > last) {
return [last];
}
var index = _.findIndex(arr, function(a) { return target - a <= 0 });
neighbours = [arr[index-1], arr[index], arr[index+1]]
return _.chain(neighbours).sortBy(function(a) {
return Math.abs( a - target) })
.take(2).value()
}
getClosests([2, 3, 5, 25, 135, 250, 300], 100);
getClosests([2, 3, 5, 25, 135, 250, 300], 25);
getClosests([2, 3, 5, 25, 135, 250, 300], 400);
Find two Closet to given Goal in Array: (without Lodash)
function findCloset(givenList, goal) {
var first;
var second;
var finalCollection = [givenList[0], givenList[1]];
givenList.forEach((item, firtIndex) => {
first = item;
for (let i = firtIndex + 1; i < givenList.length; i++) {
second = givenList[i];
if (first + second < goal) {
if (first + second > finalCollection[0] + finalCollection[1]) {
finalCollection = [first, second];
}
}
}
});
return finalCollection;
}
var counts = [2, 42, 82, 329, 122, 40, 162, 202, 3, 5, 242, 282, 322, 35, 362];
var goal = 80;
console.log(findCloset(counts, goal));