Longest common subsequence (Why does this recursive solution not work?) - javascript

Trying to write a similar recursive solution to the one described on: http://www.geeksforgeeks.org/longest-common-subsequence/ but it does not work. It outputs one. Anyone have an idea of why?
LCS_seq_req = (str1, str2) => {
m=str1.length;
n=str2.length;
str1_cut = str1.slice(0, m-1)
str2_cut = str2.slice(0, n-1)
if (m===0 || n===0) {
return 0
}
else if (str1.slice(m-1, m) === str2.slice(n-1, n) ) {
return LCS_seq_req(str1_cut, str2_cut) + 1
} else {
res_1 = LCS_seq_req(str1_cut, str2)
res_2 = LCS_seq_req(str1,str2_cut)
return Math.max(res_1, res_2)
}
}
LCS_seq_req("AGGTAB", "GXTXAYB")

In JavaScript, unlike (say) Python, assigning to a variable inside a function does not implicitly declare it as a local variable. Instead, you need to explicitly declare it using the var keyword; otherwise you get a global variable.
More specifically, your problem is that this line:
res_1 = LCS_seq_req(str1_cut, str2)
has the side-effect of mutating the global variable str2_cut, causing this line:
res_2 = LCS_seq_req(str1,str2_cut)
to compute the wrong value. If you add var in the right places, you'll get the right answer.
Incidentally, Eric Lippert has written a blog post, https://ericlippert.com/2014/03/05/how-to-debug-small-programs/, which gives very good advice for how to debug this sort of problem on your own.

I looked at the Naive recursive Python implementation of LCS problem you give and converted Python code into JS code. Hope it will help.
LCS_seq_req = (str1, str2, m, n) => {
if(m == 0 || n == 0)
return 0;
else if(str1.charAt(m-1) === str2.charAt(n-1))
return 1 + LCS_seq_req(str1, str2, m-1, n-1);
else
return Math.max(LCS_seq_req(str1, str2, m, n-1), LCS_seq_req(str1, str2, m-1, n));
}
var X = "AGGTAB";
var Y = "GXTXAYB";
console.log(LCS_seq_req(X , Y, X.length, Y.length)); //6

Related

freeCodeCamp Golf code but with Ternary operators instead of else if [duplicate]

I have a function to check sums in an array :
function checkSum(array, sum) {
// array = [1,4,6,11] sum = 10
var answers = [];
var map = new Map();
for (var x = 0; x < array.length; x++) {
if (map.has(array[x])) {
answers.push([sum - array[x], array[x]])
} else {
map.set(sum - array[x])
}
}
answers.length != 0 ? console.log(answers) : console.log("nada")
}
I originally had the last line just return answers; but let's say I don't want to return an empty array -- instead, I'd rather just log a statement.
why doesn't a return in a ternary conditional work such as this:
answers.length != 0 ? return answers : console.log("nada")
You need to use return answers.length != 0 ? answers : console.log("nada"). The reason it fails is because ternary conditions do not support return in their conditions. Infact, the ternary operator evaluates to an expression and expressions do not contain a return statement.
function checkSum(array, sum) {
// array = [1,4,6,11] sum = 10
var answers = [];
var map = new Map();
for (var x = 0; x < array.length; x++) {
if (map.has(array[x])) {
answers.push([sum - array[x], array[x]])
} else {
map.set(sum - array[x])
}
}
return answers.length != 0 ? answers : console.log("nada")
}
console.log(checkSum([1, 4, 6, 11], 10));
The ternary (conditional) operator expects the "expr1" part (where return answers is) to be an expression - that is, something that can be evaluated to a value, which can be used in other expressions. But a return statement is a statement, one which cannot possibly be interpreted as value, or as an expression; hence, a syntax error is thrown.
Instead of
answers.length != 0 ? console.log(answers) : console.log("nada")
either use a standard if statement:
if (answers.length !== 0) return answers;
console.log('nada');
or, if you just want to log, put the conditional operator inside the console.log instead:
console.log(
answers.length === 0
? 'nada'
: answers
)
I used ternary operators like this a lot in the past. It's fun, and keeps it to one line.
It can certainly be done, as Ankit shows, by putting the return statement out front
return answers.length != 0 ? answers : console.log('nada')
But I would recommend you use a classic if statement for this. Particularly since you're testing whether to return a value or just log one.
if (answers.length != 0) {
return answers;
};
console.log('nada')
I would go even further and recommend that you return the same value type no matter what. This will go a long way for using your function, well - functionally. In this case, that would involve still returning the array (even if it's empty) and logging the nada as well if empty.
if (answers.length == 0) {
console.log('nada');
};
return answers;

Code Refactoring. Trying to improve my code

My code passed, no problem. But I would like your guys opinion as to what I could have improved in my code. Unnecessary things, tips, better ways to do the same thing, faster ways, I'm literally open to any kind of feedback. Lately I'm only trying to focus on improve how fast I can solve a problem, and this one, took me almost 5 hours.
This code comes from the 2D Array HourGlass.
My thought process was to makeup a model of what I wanted, than for loop through the lines and rows, and that's how I came with this result.
Also, I wanted to improve from thinking of WHAT the code should do, other than HOW. It's hard, but any tips I would really appreciate.
Since I'm coding only Front End stuff, my solving problems is literally shit.
Thanks !
function hourglassSum(arr) {
let newInput = arr
let arrAnswer = []
for(let line in newInput){
for (let row in newInput){
let newRow = parseInt(row)
let newLine = parseInt(line)
if(newLine < 4){
let a =newInput[newLine +0][newRow]
let b =newInput[newLine +0][newRow+1]
let c =newInput[newLine +0][newRow+2]
let d =newInput[newLine +1][newRow+1]
let e =newInput[newLine +2][newRow]
let f =newInput[newLine +2][newRow+1]
let g =newInput[newLine +2][newRow+2]
if(a,b,c,d,e,f,g == undefined){
break
}
arrAnswer.push([a,b,c,d,e,f,g].reduce((item1,item2)=> item1 + item2, 0))
}
}
}
let answer = arrAnswer.reduce((item1, item2) => (item1 > item2 ) ? item1: item2 )
return answer
}
if(a,b,c,d,e,f,g == undefined) Are you expecting this to check if any of your 7 values are undefined?
Based on the comma operator specs I believe it is only checking g == undefined.
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
If you really mean to check for any null values, here's one way you could do it
if([a,b,c,d,e,f,g].indexOf(undefined)>=0) ...
Your code has a lot of redundancies:
let newInput = arr
Unnecessary.
let answer = arrAnswer.reduce((...
Stuffing it in a var is unnecessary, since you just return it on the next line.
As far as I can tell, your entire code can be changed to the following:
const hourglassSum = input => {
return input
.map((a, i, arr) => { // NEVER use for..in with arrays. Use .map or for..of
return arr.map(b => {
const idx1 = parseInt(a, 10); // always use radix
const idx2 = parseInt(b, 10);
// Use boolean short-circuiting, we'll filter later.
// Your original code had potentially error throw here
// if the first access resulted in undefined.
const intermediate = input[idx1] !== undefined &&
input[idx1 + 1] !== undefined &&
input[idx1 + 2] !== undefined &&
[
input[idx1][idx2],
input[idx1][idx2 + 1],
input[idx1][idx2 + 2],
input[idx1 + 1][idx2 + 1],
input[idx1 + 2][idx2],
input[idx1 + 2][idx2 + 1],
input[idx1 + 2][idx2 + 2],
];
// boolean again, check to make sure we don't pollute the
// arithmetic
return intermediate &&
intermediate.every(x => x !== undefined) &&
intermediate;
})
.filter(x => x) // weed out falses
.reduce((a, b) => a + b, 0); // sum to int
})
.reduce((a, b) => Math.max(a, b)); // Math.max replaces ternary
};
This is arguably more readable, definitely less error prone, slightly shorter, makes better use of the built-ins like Math.max and the array methods. Is also consistent rather than mixing functional style with loops. One thing it isn't is faster, but you make it correct first, then fast.

Javascript recursion example trouble

const writeText = function(word, n) {
if(n >= 5) {
return '';
}
n = n + 1;
return word + writeText(word + n);
};
debugger;
writeText('hello', 1);
I want to write a code which will return 'hello1', 'hello2', ... 'hello5' using recursion.
My code didn't work so I used debugger to see what's wrong. It shows that after the first recursive call, n turns into undefined. Can anyone help me out and show what's wrong with this code?
Some hints:
When using recursive calls, you better use a named function instead of a function expression, because the name does not change with assingment of the function. This is necessary for recursive calling, which might call a unknown function.
Exit function if the value is greater than 5.
You need to display the actual value of n (and maybe a new line).
Call the function with the word and a second parameter of the incremented value.
function writeText(word, n) {
if (n > 5) {
return '';
}
return word + n + '\n' + writeText(word, n + 1);
};
console.log(writeText('hello', 1));
you were almost there - the answer provided by #Nina Scholz is good.
Here an approach you could use using ES6 template literals to keep us up to date.
Since you're new some comments about the syntax which you could google:
=> : arrow functions
`text` : template literals
const writeText = (word, n) =>
`${word+n} ${n < 5 ? writeText(word, n+1) : ''}`;
console.log(writeText('hello',1))
```

Logic concerning negative num inputs being converted to positive num inputs

Maybe I'm asking google all the wrong questions but I scoured the internet and could not find posts similar to my unique problem.
This is a simple coding challenge from FreeCodeCamp:
I need to work on the function abTest(a,b) where when a OR b is less than 0, the function will exit with the value of undefined. This is because we run the value a and b through a square root function. And you cannot take the square root of a negative number. Below is the code.
// Setup
function abTest(a, b) {
if (a < 0) {
a = -a;
return undefined;
} else if (b < 0) {
b = -b;
return undefined;
}
return Math.round(Math.pow(Math.sqrt(a) + Math.sqrt(b), 2));
}
// Change values below to test your code
abTest(2,2);
This code I used above works fine. However I have to specify that when a or b is < 0, a is assigned -a and b is assigned -b. Why is this necessary? In addition I want to convert this into a Switch statement, but I run into this problem of negative num values. Below are two switch statements I wrote but when using negative num input the abTest(-2,2) or abTest(2,-2) does not return the value undefined.
My First Switch Statement
switch (a,b) {
case a<0 || b<0:
return undefined;
}
My Second Switch Statement
switch (a,b) {
case a < 0:
a = -a;
console.log(undefined);
break;
case b < 0:
b = -b;
console.log(undefined);
break;
}
Where is this hole in my logic concerning switch statements and negative num values?
Thank you guys,
There should be no need to convert a = -a unless there is something wrong with freecodecamp. Just returning the value of undefined would/should produce the exact same result as changing a variable and then still returning undefined. To simplify your code you could also combine the if and else if statements like so
function abTest(a, b) {
if (a < 0 || b < 0){
return undefined;
} else {
return Math.round(Math.pow(Math.sqrt(a) + Math.sqrt(b), 2));
}
}
hope this helps

Understanding d3.js source: stuck at function.call() and "=+"

In the source code of d3.layout.force, line 158, there is this code
force.charge = function(x) {
if (!arguments.length) return charge;
charge = typeof x === "function" ? x : +x;
return force;
};
Now, if you go to line 225, you will see
charges = [];
if (typeof charge === "function") {
for (i = 0; i < n; ++i) {
charges[i] = +charge.call(this, nodes[i], i);
}
} else {
for (i = 0; i < n; ++i) {
charges[i] = charge;
}
}
What I did not understand here is the line
charges[i] = +charge.call(this, nodes[i], i);
I am new to JavaScript and can not understand what's going on here.
As far as I understood charge takes only 1 argument (x). Here "this" is passed to give the context of current object but what about the other two? Which one of "nodes[i]" and "i" is taken as "x" ?
Again what is "= +" doing here?
Check out the MDN listings for call, apply and bind.
It's a tough concept to wrap your head around but what's happening in call and apply is that you're choosing to execute a function in a different "context."
I say "context" with quotes as "execution context" has an exact meaning in JS and this isn't it. I don't have a great word for it but what's happening here is that you're making swapping out the this object when executing the function.
This might help:
var obj = { foo: "bar" };
method.call( obj, "arg" );
function method( arg ) {
console.log( this.foo ); #bar
console.log( arg ); #"arg"
}
I think you'll find your answer here.
Basically, it's converting this:
function(){ return +new Date; }
into this:
function(){ return Number(new Date); }
Essentially, it is converting the argument into a number, and adding it to the previous value.
More reading about this here
You have to follow charge more carefully. It is variable defined in line 11:
charge = -30,
The function force.charge which you quoted is for setting the charge, it is not the function referred to in +charge.call(this, nodes[i], i);. Have a look at the second line of force.charge:
charge = typeof x === "function" ? x : +x;
x can be a function (callback) you pass, to dynamically calculate the charge. The current node (nodes[i]) and the index of the node (i) will be passed to this callback, so that you can calculate the charge dynamically based on these values:
force.charge(function(node, index) {
return index * 2;
});
x (and therefore charge) can also be a number or numerical string. That's why it is tested beforehand whether charge is a function or not:
if (typeof charge === "function") {
// function so we call it and pass the current node and index
} else {
// static value, the same for each node
}
Apert from that, you can always pass any number of arguments to a function, no matter how many parameters it has defined. For example:
function foo() {
alert([].join.call(null, arguments));
}
foo('a', 'b');
will alert a,b.
To answer your questions: The arguments passed to .call() [MDN] or .apply() [MDN] are passed in the same order to the function. So if I have a function function foo(a, b, c) then foo.call(null, x, y) would pass x as a and y as b (c would be undefined).
The + operator is the unary plus operator [MDN], which simply converts the operand into a number.

Categories

Resources