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));
Related
I don't know what's wrong, my function miniMaxSum isn't summing 1+3+4+5. At the end, the result array turns into this [ 14, 12, 11, 10 ], when it should looks like this [ 14, 13, 12, 11, 10 ]
function miniMaxSum(arr) {
let results = [];
let actualValue = 0;
let skipIndex = 0;
for (let i = 0; i < arr.length; i++) {
//skip actual index
if (i == skipIndex) continue;
actualValue += arr[i];
//restart the loop
if (i == arr.length - 1) {
skipIndex++;
results.push(actualValue);
actualValue = 0;
i = 0;
}
}
console.log(results);
console.log(Math.min(...results), Math.max(...results));
}
console.log(miniMaxSum([1, 2, 3, 4, 5]));
You're over-complicating your algorithm by trying to check whether you should add the current number to the overall sum or not. Instead, all you need to do is run a loop over your array, to sum up all your elements in your array. This will give you the total sum of all your elements. Then, again, iterate through your array. For each element in your array subtract it from the sum you just calculated and push it into a new array. This will give you the sum if you were to not use the number in the ith position. You can then find the min/max of this using JavaScript's Math.min and Math.max functions.
Here is an example using .reduce() and .map() to calculate the final result:
const miniMaxSum = arr => {
const sum = arr.reduce((s, n) => n+s, 0)
const results = arr.map(n => sum - n);
return [Math.min(...results), Math.max(...results)];
}
const [min, max] = miniMaxSum([1, 2, 3, 4, 5]);
console.log(min, max);
If you prefer standard for loops, here is an implementation of the above in a more imperative style:
const miniMaxSum = arr => {
let sum = 0;
for(let i = 0; i < arr.length; i++) { // sum all elements
sum += arr[i];
}
let results = [];
for(let i = 0; i < arr.length; i++) {
results[i] = sum - arr[i]; // sum minus the current number
}
return [Math.min(...results), Math.max(...results)];
}
const [min, max] = miniMaxSum([1, 2, 3, 4, 5]);
console.log(min, max);
Assuming you're talking about this question.
Whenever you want to restart the loop, you're setting i=0 but observe that you also have increment statement i++ in for loop so, effectively i starts from 1, not 0. You need to set i=-1 so that i=-1+1 = 0 in subsequent iteration. After doing this, you need to handle a corner case. When skipIndex==arr.length-1, check if i == arr.length-1. If yes, do results.push(actualValue); for the last value and then for loop terminates because i < arr.length is false in next iteration.
Code:
function miniMaxSum(arr) {
let results = [];
let actualValue = 0;
let skipIndex = 0;
for (let i = 0; i < arr.length; i++) {
//skip actual index
if (i == skipIndex){
if(i == arr.length - 1)
results.push(actualValue);
continue;
}
actualValue += arr[i];
//restart the loop
if (i == arr.length - 1) {
skipIndex++;
results.push(actualValue);
actualValue = 0;
i = -1;
}
}
console.log(results);
console.log(Math.min(...results), Math.max(...results));
}
miniMaxSum([1, 2, 3, 4, 5]);
Output
[ 14, 13, 12, 11, 10 ]
10 14
I am looking for an implementation in JavaScript for the following problem.
Consider a sorted array:
[1,2,5,9,10,12,20,21,22,23,24,26,27]
I would like to calculate the length of the maximum range that increased by 1, duplicates are not allowed.
The given example has the following ranges:
1,2
9,10
20,21,22,23,24 // the maximum range
26,27
So the return value for the given example should be 5.
I know how to solve this problem with the obvious solution, but I believe it is possible to solve the problem with more efficient and short algorithm.
A short solution
I don't think this is any more efficient than what pretty much everybody else has suggested, but the code is reasonably short and only loops over the array once, except for the first element. Not sure if it's any help:
var arr = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27];
var streak = 0, best = 0, bestStart;
for (var i = 1; i < arr.length; i++) {
if(arr[i]-arr[i-1] === 1) streak++;
else streak = 0;
if (streak > best) [best, bestStart] = [streak, i - streak];
}
var bestArr = arr.slice(bestStart, bestStart + best + 1);
console.log('Best streak: '+bestArr);
Speeding it up
After looking at the code, I realized that there is a way to speed it up slightly, by not checking the last few elements of the array, based on the previous value of best:
var arr = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27];
var streak = 0, best = 0, bestStart;
for (var i = 1; i < arr.length; i++) {
if(best > arr.length - i + streak) break;
if(arr[i]-arr[i-1] === 1) streak++;
else streak = 0;
if (streak > best) [best, bestStart] = [streak, i - streak];
}
var bestArr = arr.slice(bestStart, bestStart + best + 1);
console.log('Best streak: '+bestArr);
One possible solution would be to iterate the array, keeping the the current range as long as the numbers are successors. If the next number is not a successor of the previous number, close the current range and store its length - by comparing it to the length of the last range.
In this approach, the array is iterated only once and the maximum found length of a range is updated in constant time, yielding an O(n) algorithm where n is the number of elements in the input.
An implementation in C#-like pseudocode could be as follows.
int MaximumLength = minus infinity
int CurrentValue = Input[0];
int CurrentLength = 1;
for(int i = 1; i < Input.Length; i++)
{
if ( CurrentValue + 1 == Input[i] )
{
// same range
CurrentLength = CurrentLength + 1;
}
else
{
// new range
MaximumLength = Math.Max(MaximumLength, CurrentLength);
CurrentLength = 1;
}
CurrentValue = Input[i];
}
// check current length again after loop termination
MaximumLength = Math.Max(MaximumLength, CurrentLength);
It is impossible to obtain better than O(n) because the input cannot be read in less than O(n) time. If that would be possible, it would imply that there are instances for which the result does not depend on every element of the input, which is not the case for the given problem. The algorithm Philipp Maurer has sketched below would also yield an O(n) runtime bound if the maximum range length is 1, i.e. no adjacent numbers in the input are successors.
Something like this should find the maximum length first and not last.
Let max = 0
Let n = array length
While n > 2
Let m = 0
While m <= (array length - n)
Let first = m
Let last = m + n - 1
Let diff = (value of element 'last' in array) - (value of element 'first' in array)
if diff = n - 1 then
max = n
stop
end if
Increase m
end while
Decrease n
end while
Edit (javascript implementation)
var a = [1,2,5,9,10,12,20,21,22,23,24,26,27];
var max = 1;
var n = a.length;
while(n > 2) {
var m = 0;
while(m <= a.length - n)
{
var first = m;
var last = m + n - 1;
var diff = a[last] - a[first];
if (diff == n - 1 && diff > max) {
max = n;
break;
}
m++;
}
n--;
}
console.log(max);
JSFiddle
I think looping and comparing with stored previous maximum length is optimal solution. Maybe like this:
function findLongestRange(input) {
let maxLength = 0
let currentLength = 0
for (let i = 0; i < input.length; i++) {
if (i !== input.length) {
if (input[i] === input[i + 1] - 1) {
currentLength++
} else {
if (maxLength <= currentLength && currentLength !== 0) {
maxLength = currentLength + 1
}
currentLength = 0
}
}
}
return maxLength
}
const data = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27]
console.log(findLongestRange(data))
Here is the version with tests to check how it works with different input.
const data = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27]
function findLongestRange(input) {
let maxLength = 0
let currentLength = 0
for (let i = 0; i < input.length; i++) {
if (i !== input.length) {
if (input[i] === input[i + 1] - 1) {
currentLength++
} else {
if (maxLength <= currentLength && currentLength !== 0) {
maxLength = currentLength + 1
}
currentLength = 0
}
}
}
return maxLength
}
console.clear()
;[
[[1,2,5,6,7,1,2], 3],
[[], 0],
[data, 5],
[[1,2,3], 3],
[[1,3,4,6,8,1], 2],
[[1,3,5], 0],
].forEach((test, index) => {
const result = findLongestRange(test[0])
console.assert(result === test[1], `Fail #${index}: Exp: ${test[1]}, got ${result}`)
})
A Python answer:
l = [1,2,5,9,10,12,20,21,22,23,24,26,27]
current_range = None
current_range_val = 0
max_range = 0
max_range_val = 0
for i, j in zip(l, l[1:]):
if j - i == 1:
current_range_val += 1
if current_range is None:
current_range = (i, j)
current_range = (current_range[0], j)
else:
if current_range_val > max_range_val:
max_range = current_range
max_range_val = current_range_val
current_range_val = 0
current_range = (j, None)
print(max_range)
gives
(20, 24)
Change the given amount of money into minimum number of bills.
Inputs:
Amount: positive integer;
Bills: a sorted list of distinct positive integers (e.g. [1, 5, 10]).
Assumptions:
Amount does not exceed 100.
At most 4 bill values.
Must return 0 if the amount cannot be changed.
Examples:
Amount: 17, bills: [1, 5, 10], answer: 4 -> 10+5+1+1
Amount: 17, bills: [2, 4], answer: 0
Here's the code I have so far
function sort(array) {
for (var i = array.length - 1; i >= 0; i--) {
for (var j = 0; j < i; j++) {
if (array[j + 1] > array[j]) {
var z = array[j];
array[j] = array[j + 1];
array[j + 1] = z;
}
}
}
return array;
}
function change(amount, bills) {
sort(bills);
var result = [];
while (amount > 0) {
for (var i = 0; i < bills.length; i++) {
if (amount >= bills[i]) {
amount -= bills[i];
result.push(bills[i]);
i--;
}
}
}
return result.length;
}
console.log(change(17, [1, 5, 10])); // Expect: 4
console.log(change(17, [2, 4])); // Expect: 0
console.log(change(18, [2, 4])); // Expect: 5
//console.log(change(17, [3, 5])); // Expect: 5
There are 2 problems
One is that if the amount cannot be divided it doesn't return 0 but just lags out because it's an infinite loop.
Second is that in the last example, 17,[3,5] my code takes the 5 3 times and then realises that it can't do the remaining 2 and lags out, instead of doing 3 4 times and adding a 5.
Would really appreciate suggestions, or fixed code. Please keep it fairly simple I am just a starter.
If fixed your change function and added comments to explain my changes, let me know if you have any doubts
function change (amount, bills) {
//Asign sorted array of bills to possibleBills
var possibleBills = sort(bills);
var result = [];
//Asign amount to currentAmount
var currentAmount = amount;
//Sort through possibleBills
for (var i = 0; i < possibleBills.length; i++) {
//Perform action inside while loop if the current bill value can be substracted from currentAmount
while (currentAmount - possibleBills[i] >= 0) {
currentAmount -= possibleBills[i];
result.push(possibleBills[i]);
//End loop and return the length of result if currentAmount reaches 0
if (currentAmount === 0) {
return result.length;
}
}
}
//Return 0 if the amount couldn't be changed with the given bills
if (currentAmount > 0) {
return 0;
}
return result.length;
};
function change(amount, bills) {
const billsDesc = bills.sort((a, b) => b - a);
const give = {}
let remaining = amount;
for (const bill of billsDesc) {
const qty = Math.floor(remaining/bill);
give[bill] = qty;
remaining -= qty*bill;
}
give.totalQty = Object.values(give).reduce((curr, prev) => curr + prev, 0);
return remaining === 0? give.totalQty : 0;
}
console.log(`${change(17, [1, 5, 10])} should equal 4`);
console.log(`${change(17, [2, 4])} should equal 0`);
console.log(`${change(18, [2, 4])} should equal 5`);
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));
I'm wondering why i'm hitting an infinite loop in my recursive quick sort algorithm
when I try to run the return statement return (quicksort(less).concat([swapPos], quicksort(more)) it enters an infinite loop.
http://jsbin.com/uMAmIXA/1/edit
var quicksort = function (array) {
//base case
if (array.length <= 1) {
return array;
}
var pivot = Math.floor(((array.length - 1) / 2));
console.log(pivot);
var swapPos = array[pivot];
console.log(swapPos);
var less = [];
var more = [];
array = array.slice(0, swapPos).concat(array.slice(swapPos + 1));
// console.log(array);
for (i = 0; i < array.length; i++)
{
if (array[i] < swapPos) {
less.push(array[i]);
}
else {
more.push(array[i]);
}
}
//console.log(more);
// console.log(less);
// return (quicksort(less).concat([swapPos], quicksort(more)));
};
quicksort([19, 12, 44, 2, 1, 7, 85, 22, 5, 4, 3]);
array = array.slice(0,swapPos).concat(array.slice(swapPos+1));
I think this should be pivot rather than swapPos. Plus, I think you should exchange their names.