LeetCode two sum not working as expected with a hash graph - javascript

I am trying to come up with an efficient solution to the two sum function on leetCode. From what I understand this code SHOULD work, but it keeps on returning undefined
var twoSum = function(nums, target) {
let hashGraph = {}
let slow = 0
let fast = nums.length - 1
while(slow < Math.abs(nums.length / 2)) {
if(nums[slow] + nums[fast] == target) {
return [slow, fast]
} else if(!hashGraph[target - nums[slow]] === undefined) {
let answer = [slow, hashGraph[target - nums[slow]]].sort()
return answer
} else if(!hashGraph[target - nums[fast]] === undefined) {
return [hashGraph[target - nums[fast]], fast].sort()
} else {
hashGraph[nums[slow]] = slow
hashGraph[nums[fast]] = fast
slow++
fast--
}
}
};
essentially I am storing the values at each index inside of a hash graph and assigning the values at that location to the index that the number was found. When I iterate through I am checking if the complement for the number at the current index exists in the hash table. If it does I return the current index and the value of the found index (which is the value in the array that the number was discovered on)
For the first test case I am given the array [2,7,11,15] and a target of 9
what SHOULD happen here is that the while loop's else case is hit and the graph is populated as follows:
{
2: 0,
15: 3
}
Then on the second iteration the second condition is hit where it checks if
hashGraph[target - nums[slow]] is valid. Given the target of 9 and the input of 7 I am essentially asking it if hashGraph[9-2] or hashGraph[2] exists. Indeed it does, however when visualizing the execution with python tutor's Javascript execution visualizer it fails this check and reaches the else clause.
This is what is stumping me. hashGraph[2] does exist. I can replicate the same thing and get the correct result if I use the following:
let hash = {
2: 0,
15: 3
}
let arr = [7]
console.log(hash[9 - arr[0]])
If that code gets me the correct result then why does my if condition fail?

Related

I'm getting fatal error with small change in for loop in the below code. anyone know why error is coming?

const computeDash=(num)=>{
const arr=num.split('');
const nums=arr.map(Number);
for(let i=0;i<(nums.length-1);i++){
if(nums[i]%2===0 && nums[i+1]%2===0){
nums.splice(i,0,'-');
}
}
return nums.join('');
}
console.log(computeDash('025468'));
The above code is giving FATAL ERROR.
But the below code is working fine when I changed for loop. I can't understand why 1st code giving error. Does anyone know why?
const computeDash=(num)=>{
const arr=num.split('');
const nums=arr.map(Number);
for(let i=0;i<nums.length;i++){
if(nums[i-1]%2===0 && nums[i]%2===0){
nums.splice(i,0,'-');
}
}
return nums.join('');
}
console.log(computeDash('025468')); //0-254-6-8
The first approach is not working because you are adding the '-' at index i. And for the given test case '025468' your loop keeps on adding '-' at the start always. i.e. after the first iteration, the array would be ['-',0,2,5,4,6,8] and after the second iteration it becomes ['-','-',0,2,5,4,6,8] and goes in an infinite loop.
The fix that will make the first approach work is
const computeDash=(num)=>{
const arr=num.split('');
const nums=arr.map(Number);
for(let i=0;i<(nums.length-1);i++){
if(nums[i]%2===0 && nums[i+1]%2===0){
nums.splice(i+1,0,'-');
}
}
return nums.join('');
}
console.log(computeDash('025468'));
In general I don't recommend altering an array while you are looping through it. Your for loop will not be reliable in terms of the count of nums because the length of the array is changing while you are looping. In this case the fatal error occurs because you are getting into an infinite loop due to the fact that nums.length keeps increasing every time you insert a new - into the array.
As to the specific question, why does one work and not the other - mainly its about luck here. Other inputs would behave differently. But the program as written should be considered suspicious in both cases!
Here is an example of looping without altering the array you are looping ... instead we push the numbers to a new array which will contain the desired result.
const computeDash = (num) => {
const arr = num.split('');
const nums = arr.map(Number);
const result = [];
for (let i = 0; i < (nums.length-1); i++) {
result.push(nums[i]);
if (nums[i] % 2 === 0 && nums[i + 1] % 2 === 0) {
result.push('-');
}
}
result.push(nums[nums.length-1]);
return result.join('');
}
console.log(computeDash('025468'));

This while loop for my sorting algorithm doesn't seem to exit, why?

I am coding in javascript and am trying to make a sorting algorithm, and my while loop doesnt seem to exit, anybody know why?
let sort = true
let length = 0
let i = 1
function multiSort(n) {
length = n.length-1
while (sort=true) {
sort = false
if (n[i]>n[i+1]) {
[n[i],n[i+1] = n[i+1],n[i]]
i += 1
sort=true
if (i = length) {
i = 1
}
console.log(i)
}
}
return n
}
console.log("Final Product: ", multiSort([3,2,5,1,4]), " Iterations: ", i)
You have a couple problems here.
As mentioned your using javascript incorrectly. You should spend some time learning about how operators and comparisons work. You can read about them here. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#assignment_operators
Your while statement will never be false.
n[i+1] in your compare statement can be undefined so will be false when it shouldn't be checked.
I have re-written your algorithm using a for loop instead of a while loop since we get a free iterator when we set up the loop.
// We keep track of the iterations outside of the function
let iterations = 0
function multiSort(n) {
iterations++
// We set sort to false, if our conditions are not met we won't need to keep sorting
let sort = false
// Loop through every item in the array
for(let i = 0; i < n.length; i++) {
let next = n[i+1]
// If the current item is larger than the next swap their positions. We also have to check for undefined here since the end of the array can't compare to anything.
if(n[i] > next && next !== undefined) {
// Set sort to true since at least one item need to be sorted. This will not be set if all items in the array are in sequence.
sort = true
n[i+1] = n[i]
n[i] = next
}
}
// If we set sort to true re-run everything with the current array.
if(sort) {
multiSort(n)
}
// return the final array
return n
}
console.log("Final Product: ", multiSort([3,2,5,1,4]), " Iterations: ", iterations)

indexOf / includes don't do an exact match and return false positives

I want to build an if statement in which the if criteria is based on an equality test of whether a variable equals any of several values. However, I do not want to hardcode the test values, but to pass an array of values that had been randomly subset earlier.
First, I get the set of randomized values by subsetting/sampling 5 values out of an array of 15 values. Basically, I'm using this excellent solution.
function getRandomSubarray(arr, size) {
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--) {
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled.slice(0, size);
}
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var fiveRandomMembers = getRandomSubarray(x, 5);
Then, I want to pass fiveRandomMembers to test whether a variable is equal to any of the values in fiveRandomMembers's array. Then do something. To this end, I want to use this solution.
var L = function()
{
var obj = {};
for(var i=0; i<arguments.length; i++)
obj[arguments[i]] = null;
return obj;
};
if(foo in L(fiveRandomMembers)) {
/// do something
};
Unfortunately, this doesn't work for me. I must admit that the implementation of this code is within a Qualtrics survey, so the problem might be nuanced to the Qualtrics platform, and that's the reason it isn't working for me. I'm newbie to JavaScript so I apologize if this is a trivial question. But I believe that my code is problematic even in plain JavaScript (that is, regardless of Qualtrics), and I want to figure out why.
UPDATE 2020-05-24
I've been digging into this more deeply, and I have some insights. This looks more like a qualtrics problem rather than plain JS issue. However, the underlying problem might still have to do with some JS mechanism, and that's why I bother to update it here -- maybe someone will know what's causing this behavior.
To recap -- I want to condition an action based on whether a given variable's content matches either of the values in an array. I've tried using both includes and indexOf, but either method fails. The problem boils down to the functions not doing an exact match. For example, if I have an array of 5 numbers such as 8, 9, 12, 13, 14, and I want to test whether 4 exists in the array, then an exact match should return FALSE. However, both indexOf and contains return TRUE because 14 has 4 in it. This is not an exact matching then. Furthermore, I've tried to investigate what is the position indexOf would return for such a false-positive match. Typically, it would return a position that is even larger than the total length of the array, making no sense whatsoever. Here's an example from my Qualtrics survey, demonstrating the problem:
The code giving this is comprised of two qualtrics questions:
(-) First piece
Qualtrics.SurveyEngine.addOnReady(function()
{
/*Place your JavaScript here to run when the page is fully displayed*/
function getRandomSubarray(arr, size) {
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--) {
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled.slice(0, size);
}
var x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var fiveRandomMembers = getRandomSubarray(x, 5);
if (Array.isArray(fiveRandomMembers)) Qualtrics.SurveyEngine.setEmbeddedData('is_array', "TRUE");
Qualtrics.SurveyEngine.setEmbeddedData('length', fiveRandomMembers.length);
Qualtrics.SurveyEngine.setEmbeddedData('five_sampled_numbers', fiveRandomMembers);
});
(-) Second piece
Qualtrics.SurveyEngine.addOnReady(function()
{
jQuery("#"+this.questionId).find('.QuestionText:first').css("padding-bottom", "0px");
var currentLoopNum = "${lm://CurrentLoopNumber}";
// var currentLoopNum = parseInt(currentLoopNum, 10); // tried converting to numeric but it doesn't solve the problem
var fiveSampledNumbers = "${e://Field/five_sampled_numbers}";
if (fiveSampledNumbers.includes(currentLoopNum)) {
Qualtrics.SurveyEngine.setEmbeddedData('does_loop_number_appear', "Yes");
} else {
Qualtrics.SurveyEngine.setEmbeddedData('does_loop_number_appear', "No");
}
Qualtrics.SurveyEngine.setEmbeddedData('index_of', fiveSampledNumbers.indexOf(currentLoopNum));
});
Here is a link to the Qualtrics survey, demonstrating the problem, in case it's helpful for troubleshooting: link
However, when testing the same code outside of Qualtrics, the problem doesn't replicate.
Does someone have a clue or even a hypothesis what could be the problem with the matching? Even if you're not necessarily familiar with Qualtrics...
I've never worked with Qualtrics before, but to me it is clear that the line
var fiveSampledNumbers = "${e://Field/five_sampled_numbers}";
will assign a string value to fiveSampledNumbers, not an array value.
Indeed, if you attempt to run the checks you are making on a string rather than an array, you get the unexpected results you saw above, because you are doing string operations rather than array operations:
var fiveSampledNumbers = "6,4,10,11,15";
console.log(fiveSampledNumbers.includes(5)); // logs true (string ends with the character "5")
console.log(fiveSampledNumbers.indexOf(5)); // logs 11 (index of the character "5")
To get around this, you will have to split the string by commas and parse each number within it:
var fiveSampledNumbers = "6,4,10,11,15";
fiveSampledNumbers = fiveSampledNumbers.split(",").map(function (n) { return parseInt(n, 10); });
console.log(fiveSampledNumbers.includes(5)); // logs false
console.log(fiveSampledNumbers.indexOf(5)); // logs -1

Leetcode Two sum problem question about why my code doesn't work

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
var twoSum = function(nums, target) {
let comp = {};
for(let i =0; i<nums.length; i++){
let match = target - nums[i]
my question is why doesn't my code work if remove comp[match]>=0 and use comp[match] instead?
if(comp[match]>=0){
return [comp[match], i]
console.log(comp)
}
else{
comp[nums[i]]= i
}
console.log(comp)
}
};
Snippet:
var twoSum = function(nums, target) {
let comp = {};
for (let i = 0; i < nums.length; i++) {
let match = target - nums[i]
if (comp[match]) {
return [comp[match], i]
console.log(comp)
} else {
comp[nums[i]] = i
}
console.log(comp)
}
};
twoSum([2, 7, 11, 15], 9)
The idea behind comp is to store the indexes of the values previously seen while you're looping through your array of numbers. This means that it is possible for a key in your object to point to the index 0.
In JavaScript, 0 is considered falsy, so when put into a if statement, it will skip the if block as it is considered false, and instead, execute the else block.
if(0) {
console.log("truthy"); // doesn't execute
} else {
console.log("falsy");
}
So, if you were to use if(comp[match]) and comp[match] was to give you the index value of 0, your else block would trigger, when instead, you actually need your if block to trigger (as you have previously seen a number which you can now add with the current number). That's why the following works as expected:
if(comp[match] >= 0)
In this scenario, if comp[match] returns back the index value of 0, the code in your if-block will be triggered as needed. It is possible for comp[match] to return undefined though. In this case, your else block will trigger so your code will work fine (as undefined >= 0 is false). However, if you want to make your condition more readable you can instead use:
if(conp[match] !== undefined)

How i put together two functions, both with a recursion inside

I am a beginner and this my first post here(plus I'm not a native English speaker), so please forgive me if my code and/or my English are bad.Given two numbers I want to write a JavaScript function to find if the second one is a power of the first one, and then determine that power (ex: 2,8 the output must be 3). I wrote two functions, both working, but I can't put them together.
This is the first one to check if the second number is a power of the first one.
function checkNumbers(x,y){
if (y%x !==0){
return "this numbers are not valid"
}
else if(x===y) {
return "correct!"
}
else {
y=y/x
return checkNumbers(x,y)
}
}
checkNumbers(2,8) // will give the first answer
checkNumbers(2,18) // will give the second answer
The second function will give you the integral logarithm:
count =1;
function findGrade(x,y) {
if(y/x===1)
return "the grade is " + count;
count++;
y = y/x;
return findGrade(x,y)
}
findGrade(2,8) // output 3
findGrade(2,16) // output 4
How can I put them together into one function? I think i need a closure, but I didn't find the way to make that work.
checkNumbers should return a Boolean value, not a message. Then findGrade can check that result to see whether it should compute the logarithm. Something like this:
function checkNumbers(x,y){
if (y%x !==0){
return false
}
else if(x===y) {
return true
}
// the rest of your function remains the same.
function findGrade(x,y) {
// First, check to see whether y is a power of x
if checkNumbers(x,y) {
// your original findGrade function goes here
}
else
return -1; // Use this as a failure code.
Does this work for you?
Another possibility is to combine the functions entirely: try to find the logarithm (what you call "grade"); if it works, you get your answer; if it fails (at y%x !== 0), then you report the failure.
The solution is, in fact, pretty simple.
You could do the following:
function findGrade(x, y, count = 1) {
// If the numbers are not valid, throw an error. The execution is interrupted.
if(y % x != 0) throw "Invalid inputs";
// If the inputs are different, continue the execution and add 1 to count.
if(x != y) return findGrade(x, y/x, ++count);
// If none of the above are true, you have your result!
return count;
}
Tests:
console.log(findGrade(2, 8)); // Outputs 3
console.log(findGrade(2, 16)); // Outputs 4
console.log(findGrade(2, 3)); // Error: Invalid inputs
console.log(findGrade(3, 3486784401)); // Outputs 20
Please let me know if you need any further help.
I'm not sure if my method is different, but I have implemented it below. In real world application I would do some more typechecking on inputs and check if there is a third argument: if not default to 0 (First Iteration default the count to 0), but this is the general idea. You can run the snippet below.
// Arguments
// 1: Base of Exponent
// 2: test Number
// 3: count by reference
function checkPower (base, test, count) {
let division = test/base
// base case
if (division === 1) {
count++
return count
} else if (division < 1) {
console.log("not a power")
return;
}
// iteration step
count++
return checkPower(base, division, count++)
}
// Test Cases
let test = checkPower(2, 32, 0)
if (test) {
console.log(test) // 5
}
test = checkPower(2, 1024, 0)
if (test) {
console.log(test) // 10
}
test = checkPower(2, 9, 0)
if (test) {
console.log(test) // "not a power"
}

Categories