Search closest next value in javascript array - javascript

I have a javascript array like var test = [2,5,8,12,56]; and now I want to search the closest next value of 9. So the output is 12 in this case (and not 8!).

Well here's a simple way to do it:
function getNextVal(arr, val) {
// omit the next line if the array is always sorted:
arr = arr.slice(0).sort(function(a,b){return a-b;});
for (var i=0; i < arr.length; i++)
if (arr[i] >= val)
return arr[i];
// return default value when val > all values in array
}
You don't say what to return if the search value is in the array, so I've assumed you want to return it. If by "closest next value" you meant that it should always return the next number higher than the search value change arr[i] >= val to use > instead of >=.
If you have a large array you probably want some kind of binary sort instead of just going through from the beginning.

Here is what you can try if the array is sorted, you need to tune for for boundry cases, this is just for idea of algorithm...
NUM is input
TEST is your array
INDEX is index variable
For INDEX from 0 .. TEST.SIZE -1
IF NUM > TEXT[INDEX]
RETURN TEXT[INDEX]

A very simple code is given below. Hope this will help you
var test = [2,5,8,12,56];
var key = 9;
var closestNext=1000;
for(var i=0;i<test.length;i++)
{
if(test[i] > key)
{
if(test[i]<closestNext)
{
closestNext = test[i];
}
}
}
alert(closestNext);
​
see the working one here

1 Start by sorting the array, using arr.sort();, just sorts the values in the ascending order (3,6,4,7,1 --> 1,3,4,6,7), then just iterate:
function getNext(inputVal,arr)
{
arr.sort();;
for (var i=0;i<arr.lenght;i++)
{
if (arr[i] >= inputVal)
{
return arr[i];
}
}
throw new Error('Out of range');
}

If you know the array is always going to be sorted or if it is reasonable to sort the array beforehand (e.g. when the array doesn't change very often but you need a lot of retrievals), you can use a binary search on the sorted array.
If the value is not found in the array, the upper bound is returned which indicates the smallest element greater than the given value. This gives O(log n) complexity on average whereas the naive approach (looping over the whole array) gives O(n) complexity on average.
// Binary search
// Adapted from http://jsfromhell.com/array/search
function binarySearch(arr, val, insert) {
var high = arr.length, low = -1, mid;
while (high - low > 1) {
mid = (high + low) >> 1;
if (arr[mid] < val) low = mid;
else high = mid;
}
if (arr[high] == val || insert) {
return high;
} else {
return -1;
}
}
function getClosestNext(arr, val) {
// Get index
var i = binarySearch(arr, val, true);
// Check boundaries
return (i >= 0 && i < arr.length) ? arr[i] : null;
}

Related

Optimizing node.js solution for HackerRank QHEAP1

Hi I'm trying to familiarize myself a bit better with Heaps so wanted to try and implement a solution to HackerRanks>Practice>Data Structures>Heaps>QHEAP1 using primitives, however I'm getting a timeout error for two of the tests.
A quick summary: I need to be able to parse a standardized input and handle the following 3 types of queries:
Add an element to the heap.
Delete a specific element from the heap.
Print the minimum of all the elements in the heap.
I'm wondering where this could be optimized? From what I can tell my del() will be performed in O(n) since I need to search for the element provided.
// search for and delete specific element {x} from heap
function del(arr, x){
let i = 0;
let found = false;
let n = arr.length;
while(!found && i < n){
if(arr[i] == x) found = true;
i++;
}
if(found){
arr[i-1] = arr[n-1]; // take the last element and overwrite to delete
arr.length = n - 1; // shorten array
downHeap(arr, i); // perform downHeap opertaion from index deleted
}
}
// NOTE: customized for minHeap due to requirement to print minimum value
function downHeap(arr, t){
// use array as binary tree - next index looking down is double current index
// NOTE: i and t are 1 indexed for heap lookahead
let i = 2 * t;
if(i >= arr.length) return; // no more room
// checkes if right child is smallest - if so updates index to right child
if(i < arr.length - 1 && arr[i - 1] > arr[i]) i = i + 1;
// if lower element is smaller than current element, swap em
if(arr[i-1] < arr[t-1]){
swap(arr, i-1, t-1);
downHeap(arr,i); // downHeap again at the next level
}
}
// insert x into heap
function insert(arr, x){
const n = arr.length;
arr.length = n + 1; // increasing array size
arr[n] = x; // adding el to end of array
upHeap(arr, arr.length)
}
//NOTE: customized as minHeap due to requirement to print minimum value.
function upHeap(arr, t){
// using array as binary tree - looking up - parant is half of current index
const i = Math.floor(t/2);
// if we've hit zero gone too far - NOTE: i, and t are 1 indexed for heap reference
// also nothing to do if parent is smaller than current index
if(i == 0 || arr[i-1] <= arr[t-1]) return;
// child is smaller than parent swap and upHeap from parent
swap(arr, t-1, i-1)
upHeap(arr, i)
}
// swahp
function swap(arr, l, r){
const t = arr[l];
arr[l] = arr[r];
arr[r] = t;
}
PS. as a side question, I'm kind of switching between a 1 indexed for heap operations, and a 0 index for array operations (e.g. you'll notices a lot of i-1 statements inside the up and downHeap methods) - wondering if there's a smarter way of having done that?
Support Code:
function processData(input) {
//Enter your code here
const inputs = input.split('\n');
const n = inputs[0];
let arr = [];
for(let i = 1; i <= n; i++){
const query = inputs[i].split(' ');
const op = query[0];
if(op == "1"){
insert(arr, parseInt(query[1]))
} else if(op == "2"){
del(arr, parseInt(query[1]))
} else if(op == "3"){
console.log(arr[0])
} else {
console.log("Error reading op");
}
}
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function (input) {
_input += input;
});
process.stdin.on("end", function () {
processData(_input);
});
Example Input
22
1 286789035
1 255653921
1 274310529
1 494521015
3
2 255653921
2 286789035
3
1 236295092
1 254828111
2 254828111
1 465995753
1 85886315
1 7959587
1 20842598
2 7959587
3
1 -51159108
3
2 -51159108
3
1 789534713
The code is indeed confusing because (as you write) it sometimes uses 1-based indexes, while other times it uses them as 0-based.
For instance, in insert, the following line shows that you intend t and i to be a 1-based index, since you convert them on-the-fly to a 0-based index:
if(arr[i-1] < arr[t-1])
...but then in this line, you treat i as a 0-based index (arr.length would be an admissible value of i if it is 1-based):
if(i >= arr.length) return; // no more room
And the same mix-up happens here:
if(i < arr.length - 1 && arr[i - 1] > arr[i]) i = i + 1;
By consequence you will get wrong results.
It is confusing to work with 1-based indexes when JavaScript is expecting 0-based indexes everywhere indexes are used. I didn't feel the courage to further debug your code in that state. I would suggest to use 0-based indexes throughout your code, which means that the left child of a value at index t is at index t*2+1.
Some other remarks:
To find the index where a value occurs in the heap, you don't have to write an explicit loop. Just use the built-in indexOf method.
Recursion is nice, but the downHeap and upHeap functions will work more efficiently with an iterative method, because then -- instead of swapping values -- you can take a copy of the value to bubble up or down, and then only move (not swap) the conflicting values to finally insert the copied value in its right place. This will perform fewer assignments than swapping repeatedly.
To insert a value you can just use the push method instead of updating the length "manually".
Instead of Math.floor for the integer division by 2, you can use a shift operator.
So here is a correction of your code:
function del(arr, x) {
const i = arr.indexOf(x); // This will be faster
if (i >= 0) {
const value = arr.pop();
if (i < arr.length) { // Only assign back when it was not last
arr[i] = value;
downHeap(arr, i);
}
}
}
function downHeap(arr, t) {
const val = arr[t];
while (true) {
let i = t * 2 + 1;
if (i < arr.length - 1 && arr[i] > arr[i + 1]) i = i + 1;
if (i >= arr.length || arr[i] >= val) break;
arr[t] = arr[i]; // Don't swap to gain time
// No recursion to save stack space
t = i;
}
arr[t] = val;
}
function insert(arr, x) {
arr.push(x); // adding element to end of array
upHeap(arr, arr.length - 1);
}
function upHeap(arr, t) {
const val = arr[t];
while (true) {
let i = (t - 1) >> 1; // Shift operator may give some speed increase
if (i < 0 || arr[i] <= val) break;
arr[t] = arr[i]; // Don't swap to gain time
// No recursion to save stack space
t = i;
}
arr[t] = val;
}

Comparing values between two arrays

I'm trying to set up a function that checks if a word or a text is a palindrome. To do that, it splits the text so that every letter is an element of a new array, it takes rid of the white spaces and it makes the reverse array.
Then it checks if every element of the two arrays, at the same positions, are equal. If not it returns false, if yes it returns true.
Here the function:
function palindrome(str) {
var low = str.toLowerCase();
var newArray = low.split("");
var noSpace = newArray.filter(function(val) {
return val !== " ";
});
var reverse = noSpace.reverse();
function check (a, b) {
console.log(`checking '${a}' against '${b}'`);
var partial;
var result = 1;
for (var i = 0; i < a.length; i++) {
console.log(`comparing '${a[i]}' and '${b[i]}'`);
if (a[i] !== b[i]) {
result = 0;
} else {
partial = 1;
result *= partial;
}
}
return result;
}
var result = check(noSpace, reverse);
if (result == 1) {
return true;
} else {
return false;
}
}
palindrome("r y e");
I don't know what's wrong but it seems that the function keeps on returning a true value no matter what word or text I pass to the function. What is wrong with that?
Your issue seems to be because reverse() changes the actual array as well. So doing
var reverse = noSpace.reverse();
Will reverse noSpace and assign a reference to it on the variable reverse. That is, both arrays will be the same (reversed) array.
To bypass that, I've used .slice() to create a copy of the original array, and then called .reverse() on that new array, ridding you of any conflicts.
Here's a working snippet of what it looks like:
function palindrome(str) {
var str_array = str.toLowerCase().split("");
var no_space = str_array.filter(function(val) {
return val !== " ";
});
// By applying '.slice()', we create a new array
// reference which can then be reversed and assigned
// to the 'reverse' variable
var reverse = no_space.slice().reverse();
function check(a, b) {
var partial;
var result = 1;
for(var i=0; i < a.length; i++) {
if(a[i] !== b[i]) {
// We don't need to keep
// comparing the two, it
// already failed
return 0;
} else {
// I've kept this part even though
// I don't really know what it is
// intended for
partial = 1;
result *= partial;
}
}
return result;
}
return check(no_space, reverse) === 1;
}
console.log(palindrome("a b a"));
console.log(palindrome("r y e"));
The way you have coded for palindrome is way too complicated.
But there is one problem with your code: when you do a reverse() it changes the original array as well.
So you will need to make sure that you copy it via slice().
Also you can directly send a boolean result rather than doing a 1 and 0.
At result *= partial;, 1 * 1 will always equal 1
I didn't correct your code, but here is a optimized solution for you.
function palindrom(string) {
var arr = string.split("");
var lengthToCheck = Math.floor(arr.length / 2);
for (var i = 0; i < lengthToCheck; i++) {
if (arr[i] != arr[arr.length - (1 + i)]) {
return false;
}
}
return true;
}
First I split the array after every charater of the passed String. After that I get the half of the length of the array as it's enough to check just one half.
With the for-loop I compare the first half with the second half. As soon as I found two characters that do not match I return false. In case the whole first half matches the second half of the array, the for-loop will be completed and after that true will be returned.
What's actually happening is .reverse() reverses an array in place, it then stores a reference to that array which is not what you're calling in your check() method.
Simple fix would be to change your if statement:
if (a[i] !== b.reverse()[i])

How to optimize my function that takes a positive integer and returns the next smaller positive integer?

I am trying to write a function that takes a positive integer and returns the next smaller positive integer containing the same digits, and -1 when there is no smaller number that contains the same digits.
For example:
nextSmaller(21) == 12
nextSmaller(531) == 513
nextSmaller(2071) == 2017
I wrote a code that solves this, but I don't really know how to optimize it further. Could you please help me? It runs fairly fast on repl.it, but when I submit it, it says it takes more than 1200ms and doesn't allow me to submit it even though all the tests pass.
function nextSmaller(n) {
var nArray= n.toString().split("")
var minimumNum = 1 + Array(nArray.length).join('0')
for(var i=n-1; i >= minimumNum; i--) {
var newNumArray = i.toString().split('');
var counter = 0;
for (var j=0; j<newNumArray.length; j++) {
if (nArray.indexOf(newNumArray[j]) > -1) {
counter++
nArray.splice(nArray.indexOf(newNumArray[j]), 1)
if (counter === n.toString().split("").length) {
return i;
}
}
}
nArray = n.toString().split("");
if (i === Number(minimumNum)) return -1;
}
}
Your code could be optimized a bit, for instance you could use a break statement in your inner loop to move on to the next number as soon as you know the current one isn't going to work (that should make it run in about half the time, but it is still quite slow for an n like 91234567) and instead of n.toString().split("").length in the loop, use a variable so you only need to convert n to an array once.
function nextSmaller(n) {
var nArray = n.toString().split("")
var length = nArray.length;
var minimumNum = 1 + Array(length).join('0')
for(var i=n-1; i >= minimumNum; i--) {
var newNumArray = i.toString().split('');
var counter = 0;
for (var j=0; j<newNumArray.length; j++) {
if (nArray.indexOf(newNumArray[j]) < 0)
break;
counter++
nArray.splice(nArray.indexOf(newNumArray[j]), 1)
if (counter === length) {
return i;
}
}
nArray = n.toString().split("");
}
return -1;
}
There is a very efficient algorithm for computing the next permutation, which can easily be adapted to get the previous one instead (and return -1 if the resulting permutation starts with 0). I adapted this algorithm to do that:
[21,531,2071,912345678,9123545678,915345678].forEach( x => console.log( nextSmaller( x ) ) );
function nextSmaller(n) {
const arr = ( n + '' ).split( '' ).map( Number );
// Find longest non-decreasing suffix
let i, prev = 9;
for ( i = arr.length; i--; ) {
if ( arr[ i ] > prev )
break;
prev = arr[ i ];
}
// If whole sequence is non-decreasing,
// it is already the smallest permutation
if ( i < 0 )
return -1;
const pivot_i = i;
const pivot = arr[ pivot_i ];
for ( i = arr.length; i--; ) {
if ( arr[ i ] < pivot )
break;
}
arr[ pivot_i ] = arr[ i ];
arr[ i ] = pivot;
if ( arr[ 0 ] === 0 )
return -1;
return +arr.slice( 0, pivot_i + 1 ).concat( arr.slice( pivot_i + 1 ).reverse( ) ).join('');
}
The algorithm could be like the following:
For the input number n find all numbers that are formed with some permutations of the same digits and sort these numbers. For example, if n=213, we get the sorted list as [123, 132, 213, 231, 312, 321]. (e.g., Permutations in JavaScript? can help you).
Find the index i of the number n in the sorted list. If i>0 return the number at index i-1 else return -1 (if it's the smallest number appearing at the first position of the sorted list).
Another alternative algorithm could be the following:
Decrement the number n until and unless you find one that has exactly same digits (in a different order, you can sort the digits and check for equality).
The most efficient will be similar to the one referred to by #Paulpro(https://www.nayuki.io/page/next-lexicographical-permutation-algorithm)
Find the longest non-decreasing suffix from the decimal string representation of n.
If the entire string n is non-decreasing then return -1 (there can't be any smaller).
Otherwise choose the digit immediately left to the start of the suffix as pivot and swap it with (the leftmost and) the largest digit in the suffix that is smaller than the pivot. Return this number.

JavaScript challenge - Sherlock and array

I got the following challenge in interview, with some constraints.
Watson gives Sherlock an array A of length N. Then he asks him to determine if there exists an element in the array such that the sum of the elements on its left is equal to the sum of the elements on its right. If there are no elements to the left/right, then the sum is considered to be zero. Formally, find an i, such that,
A1+A2...A(i−1)=A(i+1)+A(i+2)...AN.
Input Format
The first line contains T, the number of test cases. For each test case, the first line contains N, the number of elements in the array A. The second line for each test case contains N space-separated integers, denoting the array A.
Output Format
For each test case print YES if there exists an element in the array, such that the sum of the elements on its left is equal to the sum of the elements on its right; otherwise print NO.
Constraints
1≤T≤10
1≤N≤10^5
1≤Ai≤2×10^4
1≤i≤N
I have solved it but it's failing in some test cases, I want to know the pitfall of my coding. I have spent almost 4-5 hours but unable to solve it.
My solution is -
function processData(input) {
input = input.split('\n');
var counter=0;
var sum = function(n){
var r=[];
for(var k=0;k<n.length;k++){
if(!isNaN(n[k])) {
if(n[k] >= 1 && n[k] <= (2 * Math.pow(10,4))){
r.push(n[k].trim());
}
}
}
return r.reduce(function(a, b) { return Number(a) + Number(b); }, 0);
}
for(var i=2;i<=input.length;i+=2){
var ret='NO';
if(counter<=10){
input[i] = input[i].split(' ');
if(input[i].length <= Math.pow(10,5) && input[i-1] <= input[i].length && input[i-1] >= 1){
for(var j=0;j<input[i].length;j++){
if(sum(input[i].slice(0,j)) === sum(input[i].slice(j+1,input[i].length))){
ret = 'YES';
break;
}
}
}
}
counter++;
console.log(ret);
};
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function (input) {
_input += input;
});
process.stdin.on("end", function () {
processData(_input);
});
Challenge link - https://www.hackerrank.com/challenges/sherlock-and-array
I can't easily write code on my phone, but here is the idea of my solution. I'll make a proper edit once back on a keyboard.
Let's admit the parsing of input file is trivial. Then you just have to write a function returning yes or no for a single array.
Step 1: Reduce the array to get the total sum of it's elements: TotalSim
Step 2: Loop on the array and maintain the partial sum of the elements: LeftSum
Step 3: If LeftSum === TotalSum - LeftSum return yes
STEP 4: End of the array: Return false
Please not that integers in javascript are exact until 2^53 -1, meaning that your constraints guarantee no overflow can occur
iterate through cases, then look for first element in each case wether it complies or not - run reduce on each side of the element and compare results until finds a match or runs out of elements.
this should work:
let test = input => input
.map(line => line
.some((el, index) => line.slice(0, index).reduce((p, c) => p + c, 0)
=== line.slice(index - line.length + 1).reduce((p, c) => p + c, 0)))
.map(result => result ? 'YES' : 'NO');
test(cases); // outputs array of YESs and NOs
Here is the optimal solution guys:
function balancedSums(arr) {
// Write your code here
let sum = arr.reduce((acc, val) => acc+val);
let leftSum = 0;
for(let i = 0; i < arr.length; i++){
sum -= arr[i];
if(sum === leftSum){
return 'YES';
};
leftSum += arr[i];
};
return 'NO';
}

How to override JavaScript array sort method?

THIS QUESTION STILL HAS NOT BEEN CORRECTED ANSWERED AS OF Monday Oct 31 (People are wrongly answer it as if I'm asking for array.sort to be modified but I'm not asking that)
How do I override the built in JavaScript sort method for a single array (not Array.sort) with the radix-msd algorthim?
I have the algorithm for the radix msd sort, it's
// radix most-significant-bit sort for integers
//arr: array to be sorted
//begin: 0
//end: length of array
//bit: maximum number of bits required to represent numbers in arr
function radixsort (arr, begin, end, bit) {
var i, j, mask;
i = begin;
j = end;
mask = 1 << bit;
while(i < j) {
while(i < j && !(arr[i] & mask)) {
++i;
}
while(i < j && (arr[j - 1] & mask)) {
--j;
}
if(i < j) {
j--;
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
}
}
if(bit && i > begin) {
radixsort(arr, begin, i, bit - 1); // <=== RECURSIVE FUNCTION
}
if(bit && i < end) {
radixsort(arr, i, end, bit - 1); // <=== RECURSIVE FUNCTION
}
}
And my JavaScript object array is:
homes[0].price;
homes[0].address;
homes[0].city;
homes[0].state;
homes[0].zip;
So that, when I call "homes.sort()" - I want it to sort the entire homes[x] array based on the price using my radix sort array from above. How do I do that?
You don't need to override the sort function, you simply need to pass your comparer function to the sort method as a parameter.
The function signature for the parameter is function (a, b) where a is the item being compared to b.
If you need a different implementation of sort, set it as a different function rather than overriding the default behavior. You can do this for all arrays using:
Array.prototype.radixsort = function ( ...params... )
Which will allow you to call
[1,2,3].radixsort(...params...);
Alternatively, you can add a utility function to Array:
Array.radixsort = function ( ...params... )
Which will be called as:
Array.radixsort([1,2,3], ...params...);
I think modifying Array.prototype.sort is very dangerous (because all other codes probably using sort() will be affected). Here's the code though:
//Just use this function like radixsort(homes,0,homes.length,32)
function radixsort (arr, begin, end, bit) {
var i, j, mask;
i = begin;
j = end;
mask = 1 << bit;
while(i < j) {
while(i < j && !(arr[i].price & mask)) {
++i;
}
while(i < j && (arr[j - 1].price & mask)) {
--j;
}
if(i < j) {
j--;
var tmp = arr[i].price;
arr[i].price = arr[j].price;
arr[j].price = tmp;
i++;
}
}
if(bit && i > begin) {
radixsort(arr, begin, i, bit - 1);
}
if(bit && i < end) {
radixsort(arr, i, end, bit - 1);
}
}
//If you really want to modify default sort function:
Array.prototype.sort = function(){
radixsort(this,0,this.length,32); //Use 'this' to access (get reference) to the array.
}
Expanding on Ray Toal's and zzzzBov's discussion:
function defaultCompare(a, b) {
var a_str = str(a);
var b_str = str(b);
if (a_str < b_str) {
return -1;
} else if (a_str > b_str) {
return 1;
} else {
return 0;
}
}
homes.sort = function (compare_func) {
compare_func = compare_func || defaultCompare;
RadixSort(this, 0, this.length, 64);
}
There are probably typos in the above, but it should be a step toward a more complete implementation.
Your question is asking two things:
How does one call sort on an array but call a function other than Array.sort?
How do you make the sort algorithm use a particular field without hardcoding it?
The answer to the first question is to attach a sort method on the homes object itself:
homes.sort = function () {radixSort(homes, 0, homes.length, bit);}
As one of the commenters, and other answerers have pointed out, doing this can be very confusing. For one thing, Arrays.sort takes a second parameter which is a comparison function. Radix sort is a distribution-based sort, not a comparison-based sort, so "overriding" sort in this way doesn't make much sense. You would be ignoring a comparison function were someone to pass it in.
But there's another problem. Your radixSort as written does not work because it does not compare prices. One of the answers hardcodes the price, but you said you did not like this situation. You can fix this as follows: add a fifth parameter which is a field name. If undefined, use the array element itself, otherwise select the field. Something like this (not tested):
function radixsort (arr, begin, end, bit, field) {
var i = begin, j = end , mask = 1 << bit;
// Use the value of the field at i if present, otherwise the whole element
var at = function (i) {return field in arr ? arr[i][field] : arr[i]};
while (i < j) {
while (i < j && !(arr.at(i) & mask)) {
++i;
}
while (i < j && (arr.at(j-1) & mask)) {
--j;
}
if (i < j) {
j--;
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
}
}
if (bit && i > begin) {
radixsort(arr, begin, i, bit - 1);
}
if (bit && i < end) {
radixsort(arr, i, end, bit - 1);
}
}
Now you can say:
homes.sort = function () {radixSort(homes, 0, homes.length, 64, 'price');}
However, keep in mind the following caveat:
CAVEAT: If price is a floating-point value, a radix sort probably won't work. Your best bet is to just use Array.prototype.sort and pass in a comparator to sort on different fields.

Categories

Resources