Returning Null - why is this going wrong? - javascript

I am returning null with this code, however I cannot see why/where this is going wrong. (It may be due to the sort function since I got this from a well upvoted snippet on how to sort an array). I care more about the understanding than the correct answer.
Task I am trying to achieve :
Ratiorg got statues of different sizes as a present from CodeMaster for his birthday, each statue having an non-negative integer size. Since he likes to make things perfect, he wants to arrange them from smallest to largest so that each statue will be bigger than the previous one exactly by 1. He may need some additional statues to be able to accomplish that. Help him figure out the minimum number of additional statues needed.
Example
For statues = [6, 2, 3, 8], the output should be
solution(statues) = 3.
Ratiorg needs statues of sizes 4, 5 and 7.
My code & thinking:
function solution(statues) {
let total = 0;
statues.sort(function(a, b) { //From what I understand this should sort the array numerically
return a - b;
});
for (let i = 1; i < statues.length; i++) { //iterate through the array comparing the index to the one before it
if (statues[i + 1] != (statues[i] + 1)) { //if there is a diff between index of more than 1 it will add the diff
total += statues[i + 1] - statues[i]; //to the total variable
}
}
return total;
}
const result = solution([6, 2, 3, 8]);
console.log(result);

Thanks to people who commented who helped me see that there were some errors in my logic - I have now changed the if statement to compare an index starting at 1 to the behind it i.e index 1 compared to index 0. On top of that, there was an issue with the following line total += statues[i] - statues[i-1];
I replaced that with a for loop so that it counts up to the number rather than a simple subtraction of it.
function solution(statues) {
//[6, 2, 3, 8] --- 2,3,6,8 --- 3,6 7-2,
let total = 0;
statues.sort(function(a, b) {
return a - b;
});
for(let i =1; i<statues.length; i++){
if(statues[i] != (statues[i-1]+1) ){
//total += statues[i] - statues[i-1];
for(let j = statues[i-1]; j<statues[i]-1; j++){
total += 1;
}
}
}
return total;
}

Related

LeetCode 120: Triangle - Minimum path sum

I'm doing this problem on leetcode:
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
My logic is to find the minimum number in each array and add that to the sum.
This is my code in javascript:
var minimumTotal = function(triangle) {
let sum = 0;
for (let i = 0; i < triangle.length; i++) {
sum += Math.min.apply(null, triangle[i])
}
return sum;
};
But it doesn't work for this test case: [[-1],[2,3],[1,-1,-3]].
The expected output is -1. I'm confused how it should equal -1, because -1 + 2 = 1 and none of the numbers in third array equal -1 when summed with 1.
I looked at the discussion answers and they all used some sort of dynamic programming solution.
What am I doing wrong?
There is a path where the output should be -1.
[
[ -1 ],
[ 2, 3 ],
[ 1, -1, -3 ],
]
-1 + 3 - 3 = -1
The problem is that you only have 2 possible branches at each fork, whereas it appears you're taking the lowest number from the entire row.
Under the rules of the challenge, you shouldn't be able to go from 2 in the second row to -3 in the third row, which would be the most efficient path under your approach.
What you are doing does not seem to follow the desired data structure of the problem. You are generating an int, while the desired output should be an array.
The correct answers are already posted in the discussion board:
This solution is an accepted one (just tested it):
JavaScript
var minimumTotal = function(triangle) {
for (let row = triangle.length - 2; row > -1; row--)
for (let col = 0; col < triangle[row].length; col++)
triangle[row][col] += Math.min(triangle[-~row][col], triangle[-~row][-~col])
return triangle[0][0]
}
-~row is the same as row + 1 (bitwise version).
Reference
Explains it here
If you might be interested in Python and Java, these are "accepted" solutions:
Python
class Solution:
def minimumTotal(self, triangle):
if not triangle:
return
dp = triangle[-1]
for row in range(len(triangle) - 2, -1, -1):
for col in range(len(triangle[row])):
dp[col] = min(dp[col], dp[-~col]) + triangle[row][col]
return dp[0]
Java
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[] dp = new int[-~triangle.size()];
for (int row = triangle.size() - 1; row > -1; row--)
for (int col = 0; col < triangle.get(row).size(); col++)
dp[col] = Math.min(dp[col], dp[-~col]) + triangle.get(row).get(col);
return dp[0];
}
}
For each step, you may move to an adjacent number of the row below. More formally, if you are on index i on the current row, you may move to either index i or index i + 1 on the next row.
The above statement is part of the question and it helps to create a graph like this.
Dynamic programming is used where we have problems, which can be divided into similar sub-problems, so that their results can be re-used. We start from the bottom and determine which minimum value we take and then we are going to be using that minimum value above. That is why we use dynamic programming here. Now each row gets 1 size bigger, so you can imagine under the last row, we have 4 0's.
that is why in dynamic programming we always create an array whose size is always 1 greater than the original array. We fill the array with default values. I will be explaining in python but later on I will challenge myself to write in javascript. first, initialize the dp array
dp=[0]*(len(triangle)+1) #[[0],[0],[0],[0]]
Now, we are starting from the level=[1,-1,3]. For this level, since the bottom is full of 0's, our dp array will be
dp=[1,-1,-3,0]
now we are moving above level, level=[2,3], but we are using the data from the bottom. (That is why we are using dynamic programming). From 2, its index is 0, so I ask myself what is the minimum between 0'th and 1'st value of the dp array. Whichever is minimum we add it to 2? Obviously, -1 is minimum, 2+(-1)=1 and dp gets updated.
dp=[1, -1, -3, 0]
We do the same for 3. its index is 1, and we ask what is the min(-1,3), because 3 is pointing to -1 and 3 and then we add -1 to 3 which is 2. new dp
dp=[1,0,-3,0]
Now we are at the root level. -1 and its index is 0. We ask what is min value of index 0'th and index 1'st of the dp array. min(1,0)=0 and we add it to -1. dp gets updated
dp=[-1,0,3,0]
and finally, we return dp[0]=0
Here is the code in python:
from typing import List
class Solution:
def min_total(self,triangle:List[List[int]])->int:
# dp[] is the bottom row
dp=[0]*(len(triangle)+1)
// triangle[::-1] says start from the last element of triangle
for row in triangle[::-1]:
for i,n in enumerate(row):
dp[i]=n+min(dp[i],dp[i+1])
return dp[0]
Here is javascript code:
function minPath(triangle) {
let dp = new Array(triangle.length + 1).fill(0);
for (let row = triangle.length - 1; row >= 0; row--) {
for (let i = 0; i <= triangle[row].length - 1; i++) {
dp[i] = triangle[row][i] + Math.min(dp[i], dp[i + 1]);
}
}
console.log(dp);
return dp[0];
}
const triangle = [[-1], [2, 3], [1, -1, -3]];
console.log(minPath(triangle));
As this was brought back up, it's worth pointing out that the dynamic programming technique discussed in answers and comments can be done very simply with a reduceRight:
const minSum = (triangle) =>
triangle .reduceRight ((ms, ns) => ns .map (
(n, i) => n + (i > ms.length ? ms[i] : Math .min (ms [i], ms [i + 1]))
)) [0]
console .log (minSum ([[-1], [2, 3], [1, -1, -3]])) //=> -1
console .log (minSum ([[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]])) //=> 11
console .log (minSum ([[-10]])) //=> -10
At each step we calculate the minimum paths through all the elements in a row. ms is the minimum paths through the row below (and on the initial pass will just be the bottom row) and for each n in our row ns, if we're at the rightmost element, we just copy the value from the corresponding row below, otherwise we take the minimum of the element right below and the one to its right.
Since this is called a triangle, I think we can assume that the first row has only one element. But if that's not the case, we could simply take the minimum of the results rather than taking the first element in the final value. That is, we could replace triangle .reduceRight ( ... ) [0] with Math .min (... triangle .reduceRight ( ... )).
/*
[120] Triangle
https://leetcode.com/problems/triangle/description/
*/
import java.util.List;
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
if (triangle.size() == 0)
return 0;
int rows = triangle.size();
int cols = triangle.get(rows - 1).size();
int[] tmp = new int[cols];
int index = 0;
for (int var : triangle.get(rows - 1)) {
tmp[index++] = var;
}
for (int i = rows - 2; i >= 0; i--) {
for (int j = 0; j <= triangle.get(i).size() - 1; j++) {
tmp[j] = triangle.get(i).get(j) + Math.min(tmp[j], tmp[j + 1]);
}
}
return tmp[0];
}
}

Javascript: Check array of numbers for number of missing numbers needed to make the array consecutive

Working on some Javascript challenges on Code Signal and I'm having an issue solving this:
Ratiorg got statues of different sizes as a present from CodeMaster for his birthday, each statue having an non-negative integer size. Since he likes to make things perfect, he wants to arrange them from smallest to largest so that each statue will be bigger than the previous one exactly by 1. He may need some additional statues to be able to accomplish that. Help him figure out the minimum number of additional statues needed.
Example
For statues = [6, 2, 3, 8], the output should be
makeArrayConsecutive2(statues) = 3.
Ratiorg needs statues of sizes 4, 5 and 7.
My approach:
Sort the array smallest to largest
Create counter variable to store number of missing numbers
Iterate through array
Subtract [i + 1] element from [i] element
If it equals 1, numbers are consecutive, if not the numbers are not consecutive (increment counter variable)
Return counter variable
Here is my code:
function makeArrayConsecutive2(statues) {
// Sorts array numerically smallest to largest
statues.sort((a, b) => a - b);
let counter = 0;
// If array only contains one number return 0
if(statues.length === 1) {
return 0;
}
/* Iterate through array, subtract the current element from the next element, if it
equals 1 the numbers are consecutive, if it doesn't equal one increment the counter
variable */
for(let i = 0; i <= statues.length -1; i++) {
if(statues[i] !== statues.length -1 && statues[i + 1] - statues[i] != 1) {
counter++;
}
console.log(statues[i]);
console.log('counter : ' + counter);
}
return counter;
}
When statues contains [5, 4, 6] the output is this:
4
counter : 0
5
counter : 0
6
counter : 1
I think the problem is when array is on the last element, in this case 6, it's attempting to look at statues[i + 1] when that element doesn't exist. I added statues[i] !== statues.length -1 to my if statement to address that but it doesn't appear to be working. What's wrong with my code and why is the final element incrementing the counter variable?
I'd approach it by building the target array which goes from the min+1 to the max-1 of the input by ones, excluding members of the input.....
function missingConseq(input) {
let min = Math.min.apply(null, input)
let max = Math.max.apply(null, input)
let result = []
for (i = min+1; i < max; i++) {
if (!input.includes(i)) result.push(i)
}
return result
}
let array = [6, 2, 3, 8]
console.log(missingConseq(array))

Biggest sum from array without adding 2 consecutive value

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
}

Adding numbers together

I want to loop over an array whilst addding the numbers together.
Whilst looping over the array, I would like to add the current number to the next.
My array looks like
[0,1,0,4,1]
I would like to do the following;
[0,1,0,4,1] - 0+1= 1, 1+0= 1, 0+4=4, 4+1=5
which would then give me [1,1,4,5] to do the following; 1+1 = 2, 1+4=5, 4+5=9
and so on until I get 85.
Could anyone advise on the best way to go about this
This transform follows the specified method of summation, but I also get an end result of 21, so please specify how you get to 85.
var ary = [0,1,0,4,1],
transform = function (ary) {
var length = ary.length;
return ary.reduce(function (acc, val, index, ary) {
if (index + 1 !== length) acc.push(ary[index] + ary[index + 1]);
return acc;
}, []);
};
while (ary.length !== 1) ary = transform(ary);
If you do in fact want the answer to be 21 (as it seems like it should be), what you are really trying to do is closely related to the Binomial Theorem.
I am not familiar with javascript, so I will write an example in c-style pseudocode:
var array = [0,1,0,4,1]
int result = 0;
for (int i = 0; i < array.length; i++)
{
int result += array[i] * nChooseK(array.length - 1, i);
}
This will put the following numbers into result for each respective iteration:
0 += 0 * 1 --> 0
0 += 1 * 4 --> 4
4 += 0 * 6 --> 4
4 += 4 * 4 --> 20
20 += 1 * 1 --> 21
This avoids all the confusing array operations that arise when trying to iterate through creating shorter-and-shorter arrays; it will also be faster if you have a good nChooseK() implementation.
Now, finding an efficient algorithm for a nChooseK() function is a different matter, but it is a relatively common task so it shouldn't be too difficult (Googling "n choose k algorithm" should work just fine). Some languages even have combinatoric functions in standard math libraries.
The result I get is 21 not 85. This code can be optimised to only use single array. Anyway it gets the job done.
var input = [0, 1, 0, 4, 1];
function calc(input) {
if (input.length === 1) {
return input;
}
var result = [];
for (var i = 0; i < input.length - 1; i++) {
result[i] = input[i] + input[i + 1];
}
return calc(result);
}
alert(calc(input));
This is an O(n^2) algorithm.

Why is my while loop not repeating?

var num = [1,1];
var total = 0;
var i = num.length;
do {
i++;
num[i] = num[num.length-1] + num[num.length-2];
total+=num[i];
console.log(total);
}
while(num[num.length] < 4000000);
I've been working on the Project Euler questions for a day or two now to hopefully expand my knowledge and usefulness. On the second question I've been figuring out a (bad) way to get the fibonacci sequence. However my code will print "2" to console as it SHOULD but then stopping. Another issue I have is that just using the "while(X IS TRUE/FALSE) { DO STUFF }" just won't work. Not a clue why.
I'm probably just making dumb mistakes but somebody please enlighten me :)
num.length will always be 1 bigger than the last index of num, i.e. if num.length is 5, num has the indices 0 through 4, num[5] doesn't exist.
The highest available index will be num.length - 1 so try num[num.length - 1] in your while's condition.
Your num array has 2 elements, therefore num.length (and also i) are 2. The 1st statement in your do block is i++. Now i is 3.
You're setting num[3], which means num is now [1, 1, undefined, 1].
Also, in your while, you are checking num[num.length]. Since arrays are zero-indexed, this will never work, as num.length is now 4.
What I suggest is: increment i after setting the element. So, you push a new element, then increment the length counter.
var num = [1, 1],
total = 0,
i = 2; // we already know the length, no need to get it
do {
// we don't need the i++ here
num[i] = num[i - 1] + num[i - 2]; // add the last 2 elements to the end
total += num[i];
console.log(total);
}
while (num[i++] < 4000000); // "i++" increments i and returns its old value

Categories

Resources