I'm trying to do this problem where you are given an array of arrays. You start at the first item and them move either 1 item to the right or 1 item down depending on which item is bigger. the goal is to make it to the bottom right corner with the highest sum possible. Maybe I'm missing the point, but I figured this was a recursive function.
let map = [
[8,3,5],
[4,3,4],
[2,2,3]
]
const find = (y,x,map) => {
if (y === map.length - 1 && x === map[map.length - 1].length - 1){
return map[y][x]
} else if(map[y + 1][x] > map[y][x + 1]){
return map[y][x] + find(((y + 1), x,map))
} else {
return map[y][x] + find((y,(x + 1),map))
}
}
console.log(find(0,0,map))
In this case the goal is to get 22 via 8->4->3->4->3, but whenever I pass the map into the next level of recursion, the array on the next level reads as undefined. Is there any way to pass down the array of arrays so that it can be read by other levels of the recursive function?
If you like to get the greatest sum by moving only right or down, you could take an recursive approach by creating an exit condition first, with the last possible value and then take another exit condition if indices are out of bound (meybe here is a value of -Infinity better to omit this value).
Then take the real possible value and decide which value you like to return for getting a maximum.
const find = (map, i = 0, j = 0) => {
if (i + 1 === map.length && j + 1 === map[map.length - 1].length) return map[i][j];
if (i === map.length || j === map[map.length - 1].length) return 0;
let a = find(map, i + 1, j),
b = find(map, i, j + 1);
return map[i][j] + (a > b ? a : b);
}
let map = [[8, 3, 5], [4, 3, 4], [2, 2, 3]];
console.log(find(map));
Related
I read this, but it doesn't apply (and/or, I can't figure out how to adapt the solutions). I also found this, but I don't want to change the array - I just want to check the information. I was unable to adapt the solutions to fit my needs.
I want to find out of the values in a Javascript Array are Sequential.
For example - I have an array of UNIX timestamps
var ts = [1451772000, 1451858400, 1452031200]
I want to return true if they are sequential (lower to higher values) and false if they are not sequential. I would also like to return false if there are duplicate values.
You can use Array.prototype.every, like this
var data = [1451772000, 1451858400, 1452031200];
console.log(data.every((num, i) => i === data.length - 1 || num < data[i + 1]));
The same can be written with a normal function, like this
console.log(data.every(function(num, index) {
return index === data.length - 1 || num < data[index + 1];
}));
There are basically only two conditions to take care here
If we reached the last index, then all the elements are good.
If it is not the last element, then the current number should be strictly lesser than the next element.
This expression takes care of the above two conditions.
i === data.length - 1 || num < data[i + 1]
The every function calls the function passed to it, for each and every value of the array, with three parameters.
current element,
current index
the actual array
It will keep calling the function, till the array elements run out or any of the calls to the function returns a falsy value.
You can use simple for-loop like this
function isSequential(data) {
for (var i = 1, len = data.length; i < len; i++) {
// check if current value smaller than previous value
if (data[i] < data[i - 1]) {
return false;
}
}
return true;
}
console.log(isSequential([1]));
console.log(isSequential([1, 2, 3, 4]));
console.log(isSequential([1, 5, 3, 4]));
console.log(isSequential([1451772000, 1451858400, 1452031200]));
This works on any length and prevents the first element to check.
function isSequential(array) {
return array.every(function (a, i, aa) {
return !i || aa[i - 1] < a;
});
}
document.write(isSequential([42]) + '<br>');
document.write(isSequential([1, 2, 3, 4]) + '<br>');
document.write(isSequential([1, 5, 3, 4]) + '<br>');
document.write(isSequential([1451772000, 1451858400, 1452031200]) + '<br>');
I'm working on a challenge from codefights.com.
Given an array of integer (possibly negative) I need to return the biggest sum I can achieve without adding two consecutive integer (I can't change the order of the array).
Not easy to explain so here's a few examples:
input: [1, 2, 3, 4]: you're gonna pass the '1', take 2, can't take 3, take 4 and you get 6.
input: [1, 3, 1]: pass the '1', take 3 and you can't take 1 so you have 3.
I though I had it with this code :
function solve(vals) {
var even=0; var odd=0;
for(var i=0; i<vals.length; i++){
if(i%2==0){
even+=vals[i];
} else {
odd+=vals[i];
}
}
return Math.max(even, odd);
}
But then I got this testcase: [1,0,0,3] where it should return 4, skipping the two '0' which made me realize I've been looking at it all wrong.
And now I'm stuck, don't really know how to do it.
Any ideas ?
edit:
Using MrGreen's answer I got this:
function target_game(a) {
var dp=[], l=a.length-1;
dp[0]=a[0];
dp[1]=Math.max(a[0],a[1]);
for(var i=2; i<=a.length-1; i++){
dp[i]=Math.max(dp[i - 1], dp[i - 2] + a[i]);
}
return dp[l];
}
Which works fine unless the array contains negative value.
This input: [-1,0,1,-1] returns 0.
I'm still working on a fix but I'm editing the question to have a bullet proof solution :p
This is a classical dynamic programming problem.
Define dp[i] to be the maximum sum we can get if we consider the elements from 0 to i.
Then dp[i] = max(dp[i - 1], dp[i - 2] + a[i])
The intuition behind this, if you takea[i] in the sum then you cannot take a[i - 1]
Base cases: dp[0] = max(0, a[0]) and dp[1] = max(0, a[0], a[1])
You can check this lesson:
part-1 part-2 part-3 part-4
Here is the "best" answer from the challenge (shortest actually):
function solve(a) {
b = t = 0
for (i in a) {
c = b + a[i]
b = t
t = c > t ? c : t
}
return t
}
Here is a version where I renamed the variables to make it more understandable:
function solve(vals) {
prevTotal = total = 0
for (i in vals) {
alt = prevTotal + vals[i]
prevTotal = total
total = alt > total ? alt : total
}
return total
}
I'm working on some coderbyte code, and noticed that when I try to get the max item in an array of equal values undefined is returned. When logging the min value is logs 80 and not undefined. Why is this?
Updated Code:
function noRepeat(arr) {
tmp = []
if (arr.length === 2 && arr[0] === arr[1]) {
return arr;
}
for (var i = 0;i<arr.length;i++) {
if (tmp.indexOf(arr[i]) === -1) {
tmp.push(arr[i])
}
}
return tmp
}
function SecondGreatLow(arr) {
arr = noRepeat(arr).sort(function (a,b) {return a-b;});
var low = arr[arr.indexOf(Math.min.apply(Math,arr))+1];
console.log("low",low);
var high = arr[arr.indexOf(Math.max.apply(Math,arr))-1];
console.log("high",high);
return low +" "+high;
}
console.log(SecondGreatLow([80,80]));
Output:
"low" 80
"high" undefined
"80 undefined"
That's, actually, ok. How do you want to find the second largest \ smallest number in an array of two similar numbers?
It should output "no solution" or something else. Just like there is no solution for an empty array.
function SecondGreatLow(arr)
{
arr = noRepeat(arr).sort(function (a,b) {return a-b;});
if (arr.length < 2)
return "No solution";
console.log("low ", arr[1]);
console.log("high ", arr[arr.length - 2]);
return low + " " + high;
}
You don't need Math min and max functions as your array is sorted and values are unique. You need to take the second from beginning and the second from the end.
Also, you don't need this part as it is calculated right by algorithm.
if (arr.length === 2)
{
return arr[1] + " " + arr[0];
}
For example, you have an array [1, 1, 2].
You remove repetitions and get [1, 2].
Now your algorithms returns low = arr[1] = 2 and high = arr[2 - 2] = arr[0] = 1.
The answer is correct - 2 is the second minimum number and 1 is the second largest.
After seeing this lecture I created the following knapsack code. In the lecture, the professor says it will be easy to determine the set from the optimal value (minute 19:00), however I can not find how to do it. I provide an example in the code which sums the values to 21, how can I determine the set (in this case 12, 7, 2) from this value?
/*
v = value
w = weight
c = capacity
*/
function knapsack(v, w, c) {
var n = v.length,
table = [];
// create two-dimensional array to hold values in memory
while (table.length <= c) {
table.push([]);
}
return ks(c, 0);
function ks(c, i) {
if (i >= n) {
table[c][i] = 0;
return table[c][i];
}
if (c < w[i]) {
if (table[c][i+1] === undefined) {
table[c][i + 1] = ks(c, i + 1);
}
return table[c][i + 1];
}
else {
if (table[c][i + 1] === undefined) {
table[c][i + 1] = ks(c, i + 1);
}
if (table[c - w[i]][i + 1] === undefined) {
table[c - w[i]][i + 1] = ks(c - w[i], i + 1);
}
return Math.max(table[c][i + 1], v[i] + table[c - w[i]][i + 1]);
}
}
}
//This is a test case
var v = [7, 2, 1, 6, 12];
var w = [3, 1, 2, 4, 6];
var c = 10;
var result = knapsack(v, w, c);
document.getElementById("solution").innerHTML = result;
<pre>Optimal solution value is: <span id="solution"></span></pre>
That's not easy at all. Determining whether a subset of some set of numbers has a certain sum is known as the subset sum problem, and it is NP-complete, just like knapsack itself. It would be a lot easier to just keep pointers to the solution of the subproblem from which you constructed the optimal solution to a larger subproblem. That way you can just walk back along the pointers from the globally optimal solution to find the actual set that gave you the optimal value.
(EDIT: as noted in the comments by j_random_hacker, once we have the DP table, we can actually determine the set that gave the optimal value in O(n2) time, by starting from the optimal solution and working backwards through the table, consider each possible item that could have been the last item added and checking if that solution matches the expected value.)
On a different note, I'd recommend watching some different lectures. The guy makes some strange claims, like that O(nc) -- n number of items, c capacity -- is much less than O(2n), which is simply not true when c is large. (In fact, this is called a pseudo-polynomial time solution, and it is still exponential in the length of the input, measured in bits.)
I was recently presented with a coding assignment by a startup I was interviewing with. They gave me the following problem and asked for a solution:
Congratulations! You are the new elite hacker in a group of villainous
ne'er-do-wells.
Luckily this group is more saavy than your last band of ruffians, and
they are looking to software (and you) to improve their take. The con
man for the team, has gone door-to-door down each street posing as a
termite inspector so he could covertly total the valuable goods in
each house. Normally the gang would just rob all the valuable homes,
but there's a catch! Whenever a house is robbed in this wealthy
neighborhood, the police watch it and the neighboring houses for
months.
So the gang can't simply rob all the homes, and if they choose to rob
one, they can no longer rob the house on either side of it.
The ringleader wants to know what houses he should rob to maximize the
team's profit, and he wants to know now. Write a function that takes
in an array of positive integers (home values) and returns the maximum
expected value of robbing that street.
For example:
[ 20, 10, 50, 5, 1 ] should return $71, as robbing the first, third,
and fifth houses is optimal [ 20, x, 50, x, 1 ]
[ 20, 50, 10, 1, 5 ] should return $55, as robbing the second and
fifth houses is optimal [ x, 50, x, x, 5 ]
Basically, you can only sum the values of alternative houses because if a house is robbed, the houses immediately before and after it cannot be robbed, due to heavy security in the street.
I wrote a solution using recursion and presented it to them.
I presented a solution which accounted for all cases except for the following:
[2, 3, 2], for which the returned answer was 3, instead of 4.
They told me to fix the bug. Since, it was the only case for which the algorithm didn't work, I used the following code to fix the problem (written in JavaScript):
// The recursive alrogithm doesn't account for arrays of length 3.
if(array.length === 3) {
if(array[0] + array[2] > array[1]) {
return 'Optimal expectation of robbing street: ' + String(array[0] + array[2]);
} else{
return 'Optimal expectation of robbing street: ' + String(array[1]);
}
}
So the complete final solution is as follows (with the above snippet of code included):
// Global variable for expectation:
var expectation = 0;
function optimalExpectation(array) {
// 'array' contains the home values
// The recursive alrogithm doesn't account for arrays of length 3.
if(array.length === 3) {
if(array[0] + array[2] > array[1]) {
return 'Optimal expectation of robbing street: ' + String(array[0] + array[2]);
} else{
return 'Optimal expectation of robbing street: ' + String(array[1]);
}
}
// Base case for recursion:
if(array.sum() === 0) {
return 'Optimal expectation of robbing street: ' + String(expectation);
} else{
expectation += array.max();
var maxIndex = array.indexOf(array.max());
// Recursive call:
return optimalExpectation(injectZeros(array, maxIndex));
}
}
//===============================================================================
// Protypal methods for maximum & sum:
// All array objects inherit these methods from the Array prototype:
Array.prototype.max = function(){
if(this.length === 1){
return this[0];
} else if(this.length === 0){
return null;
}
var maximum = 0;
for(var i = 0; i < this.length; i++){
if(maximum < Math.max(this[i], this[i + 1])){
maximum = Math.max(this[i], this[i + 1]);
}
}
return maximum;
};
Array.prototype.sum = function(){
var sum = 0;
this.forEach(function(el){
sum += el;
});
return sum;
};
// Function to replace maximum values, already accounted for, with zeroes:
function injectZeros(array, index){
if(array.length > 0){
if(index < array.length - 1)
array[index + 1] = 0;
if(index > 0)
array[index - 1] = 0;
}
array[index] = 0;
return array;
}
//==================================================================================
console.log(optimalExpectation([2, 3, 2])); // correctly returns 4, instead of 3
I was rejected after I submitted the above solution. They didn't reject me after my initial solution (they definitely could have). They wanted me to explain my thought process and how I fixed the bug.
I would appreciate any input on where I might have gone wrong. Is there a way to improve my algorithm? Is my code well organized? Is this the right approach? If you are a professional developer who has knowledge of how hiring decisions are made in startups, could you elaborate on what might have lead the team to reject me?
You should go a watch Professor Roughgarden's lecture about Weighted Independent Set in Path Graphs, https://class.coursera.org/algo2-2012-001/lecture/83. It uses Dynamic Programming to solve the interview question. The solution is fairly trivial. You can do it using either recursion or iterations.
I am not a hiring manager. But a quick inspection says that you only picked biggest houses as much as you could. The problem is conceptual, and you swept it under the rug instead of fixing your algorithm (the issue would also present itself with [2, 3, 2, 0.5], as you pick 3 then 0.5, instead of the optimal 2 and 2 - there is nothing special about length 3). The correct solution would at least use backtracking to explore if picking different elements would have made more profit, rather than greedily picking the local maximum without regard to context. It is sufficient to inspect the maximum and the neighbours at each step.
var values = [2, 3, 2, 0.5];
function rob(values) {
if (values.every(function(e) { return e === null })) return [];
var len = values.length;
var max = Math.max.apply(null, values);
var subMax = -Infinity;
var subArray = [];
for (var i = 0; i < len; i++) {
if (values[i] !== null && (values[i - 1] === max || values[i] === max || values[i + 1] === max)) {
nextValues = values.slice();
nextValues[i] = null;
if (i > 0) nextValues[i - 1] = null;
if (i < len - 1) nextValues[i + 1] = null;
var subResult = rob(nextValues);
var subSum = subResult.reduce(function(a, b) { return a + b; }, 0) + values[i];
if (subSum > subMax) {
subArray = subResult;
subArray.push(values[i]);
subMax = subSum;
}
}
}
return subArray;
};
alert(rob(values));
function computeRob (arr, index, canRob) {
if(arr.length == index){
return 0;
}
if (canRob == true) {
var withRob = arr[index] + computeRob(arr, index + 1, false);
var withoutRob = computeRob(arr, index + 1, true);
return Math.max(withRob, withoutRob)
} else {
return withoutRob = computeRob(arr, index + 1, true);
}
}
console.log(computeRob([4,3,8,9,2],0,true));