Big O analysis of solving longest palindromic subsequence by recursion with cache - javascript

I am not good at algorithm analysis. The source code is from this place: https://repl.it/KREy/4
Instead of dynamic programming, this piece of code uses a cache to optimize the BigO by sacrificing memory. However, I just don't know how to calculate the BigO mathematically after this cache mechanism is added. May anyone genius give an explanation?
To ease reading I will copy and paste them in the following space:
// using cache to optimize the solution 1 from http://www.techiedelight.com/longest-palindromic-subsequence-using-dynamic-programming/
const cache = {};
var runningtime = 0;
var runningtimeWithCache = 0;
function computeGetLP(x, start, end){
const answer = a => {
runningtime++;
return a;
}
console.log("try to compute: " + x + " " + start + " " + end + " ");
if(start > end)
return answer(0);
if(start == end)
return answer(1);
if(x[start] == x[end])
return answer(2 + computeGetLP(x, start+1, end-1));
return answer(Math.max(computeGetLP(x, start+1, end),
computeGetLP(x, start, end-1)));
}
function computeGetLPWithCache(x, start, end){
const answer = a => {
runningtimeWithCache ++;
console.log("do cache: " + x + " " + start + " " + end + " is " + a);
cache["" + x + start + end] = a;
return a;
}
console.log("try to compute: " + x + " " + start + " " + end + " ");
if(cache["" + x + start + end]){
console.log("hit cache " + x + " " + start + " " + end + " "+ ": ",cache["" + x + start + end]);
return cache["" + x + start + end];
}
if(start > end)
return answer(0);
if(start == end)
return answer(1);
if(x[start] == x[end])
return answer(2 + computeGetLPWithCache(x, start+1, end-1));
return answer(Math.max(computeGetLPWithCache(x, start+1, end),
computeGetLPWithCache(x, start, end-1)));
}
const findLongestPadlindrom1 = s => computeGetLPWithCache(s, 0, s.length-1)
const findLongestPadlindrom2 = s => computeGetLP(s, 0, s.length-1)
const log = (function(){
var lg = [];
var output = function(text){
lg.push(text);
}
output.getRecord = function(){
return lg;
}
return output;
})();
log("Now let's do it with cache")
log("result: "+findLongestPadlindrom1("ABBDCACB"))
log("running time is: " + runningtimeWithCache)
log("Now let's do it without cache")
log("result: "+findLongestPadlindrom2("ABBDCACB"))
log("running time is: " + runningtime)
log.getRecord();

I'm not an expert in algorithms either, but I remember cache techniques like this from Introduction to Algorithms, chapter 15, just beside Dynamic Programming. It has the same big O to DP, which is O(n^2) in your case.
Each call to computeGetLPWithCache() costs O(1) for it does not contain loops. Consider the worst case where x[start] != x[end] in each recursion. How many times are we going to call computeGetLPWithCache()?
Let n = length(x), [start, end] represent a call to computeGetLPWithCache(x, start, end), and F(n) equals the number of calls. In computeGetLPWithCache(x, 0, n), 2 sub calls - [0, n-1] and [1, n] - are issued. The former costs F(n), and when we're doing the latter, we discover that in each iteration, the first call's [start, end] range is a true subset of [0, n-1] whose result is already written to cache during the [0, n-1] call, thus no need for recursing. Only the second call which has the element n in it has to be calculated; there're n such calls [1,n][2,n][3,n]...[n,n] (one in each stack layer), so F(n+1) = F(n) + O(n).
F(n) = F(n-1) + O(n-1) = F(n-2) + O(n-2) + O(n-1) = ... = O(1+2+...+(n-1)) = O(n^2).
Hope I've got the meaning through. Replies are welcome.

Related

Am I correct about .toFixed() and decimals?

I gave an example of using .tofixed() with math, functions, and arrays, to a beginner coder friend who has been reviewing these topics in his class.
const bananaX = 9;
const bananaY = 2.9768;
bananaArray = [bananaX , bananaY];
console.log("X before array = " + bananaX);
console.log("Y before array = " + bananaY + '\n')
console.log("X,Y after array = " + bananaArray + '\n')
console.log("Value of X in array: " + bananaArray[0]+ '\n')
console.log("Value of Y in array: " + bananaArray[1]+ '\n')
function bananaDivision (bananaArray){
console.log("Value of X after function = " + bananaX);
console.log("Value of Y after function = " + bananaY + '\n')
let bananaDivided = Math.abs(bananaX/bananaY );
console.log (`X divided by Y = + ${bananaDivided}` + '\n')
let bananaFixed = bananaDivided.toFixed(2);
console.log("After using .toFixed(2) : " + bananaFixed + '\n');
};
bananaDivision();
They were understanding and following along no problem.
Then they asked me - "What if we put a decimal in the .toFixed ?"
So I ran:
const bananaX = 9;
const bananaY = 2.9768;
bananaArray = [bananaX , bananaY];
console.log("X before array = " + bananaX);
console.log("Y before array = " + bananaY + '\n')
console.log("X,Y after array = " + bananaArray + '\n')
console.log("Value of X in array: " + bananaArray[0]+ '\n')
console.log("Value of Y in array: " + bananaArray[1]+ '\n')
function bananaDivision (bananaArray){
console.log("Value of X after function = " + bananaX);
console.log("Value of Y after function = " + bananaY + '\n')
let bananaDivided = Math.abs(bananaX/bananaY );
console.log (`X divided by Y = + ${bananaDivided}` + '\n')
let bananaFixed = bananaDivided.toFixed(2);
let bananaFixed1 = bananaDivided.toFixed(.69420);
let bananaFixed2 = bananaDivided.toFixed(1.69420);
console.log("After using .toFixed(2) : " + bananaFixed + '\n');
console.log("After using .toFixed(.69420) : " + bananaFixed1 + '\n');
console.log("After using .toFixed(1.69420) : " + bananaFixed2 + '\n');
};
bananaDivision();
I explained it as that .toFixed is looking at the first number within the () and that the decimals are ignored.
Am I correct? For my own curiousity, is there a crazy way to break .toFixed() so that it actually uses decimals? I'm experimenting atm but wanted to know if someone already figured that out.
I explained it as that .toFixed is looking at the first number within the () and that the decimals are ignored.
This would be correct. That is essentially what happens.
For full correctness, the input of toFixed() will be converted to an integer. The specification states that the argument must first be converted to a number - NaN will be converted to a zero. Numbers with a fractional part will be rounded down.
Which means that if you pass any number, you essentially get the integer part of it.
It also means that non-numbers can be used:
const n = 3;
console.log(n.toFixed("1e1")); // 1e1 scientific notation for 10
You're close, since toFixed() expects an integer it will handle converting decimal numbers before doing anything else. It uses toIntegerOrInfinity() to do that, which itself uses floor() so the number is always rounded down.
Most of Javascript handles type conversion implicitly, so it's something you should really understand well if you don't want to run into problems. There's a free book series that explains that concept and a lot of other important Javascript knowledge very well, it's called You Don't Know JS Yet.
just a demo how .tofixed works !!!!!!
function roundFloat(x, digits) {
const arr = x.toString().split(".")
if (arr.length < 2) {
return x
}else if(arr[1] === ""){
return arr[0]
}else if(digits < 1){
return arr[0]
}
const st = parseInt(x.toString().split(".")[1]);
let add = false;
const rudgt = digits
const fX = parseInt(st.toString().split("")[rudgt]);
fX > 5 ? add = true : add = false
nFloat = parseInt(st.toString().split("").slice(0, rudgt).join(""))
if (add) {
nFloat += 1
}
const repeat0 = (() => {
if (rudgt - st.toString().length < 0) {
return 0
}
return rudgt - st.toString().length
})()
const output = x.toString().split(".")[0] + "." + nFloat.toString() + "0".repeat(repeat0);
return output
}
console.log(roundFloat(1.200, 2))

Javascript switch(true) executes false statements?

Im looping over a collection of coordinate values and doing math on the coordinates to see if the calculated values are in a hashmap. if they are in the hash map then I want to run an additional function. since I had multiple cases I wanted to check for each coord in the collection, I figured a switch statement would be cool to use to replace my if statements so all my checks could be visually and logically grouped. When I replaced my if statements with a switch, my code returned bad results. When I debugged, I realized the switch statements would sometimes execute even when the case was false(I added console.logs to output the result of the same switch condition and it would print false, but should only run when true). Here is a small example:
var idm = {0:1, 3:1, 9:1, 10:1, 11:1, 12:1, 20:1, 21:1, 23:1}
var findNeighbors = function(b) {
var u,d,l,r,lRow,rRow;
var currentBuilding = parseInt(b);
var currRow = Math.floor(currentBuilding/column);
//remove value from map so we dont recount it.
delete idm[currentBuilding];
u = currentBuilding - column;
d = currentBuilding + column;
l = currentBuilding - 1;
lRow = Math.floor(l/column);
r = currentBuilding + 1;
rRow = Math.floor(r/column);
console.log("current idx:" + currentBuilding);
console.log("u:" + u + ", d:" + d + ", l:" + l + " r:" + r);
// debugger;
switch(true) {
case (idm.hasOwnProperty(u) === true):
console.log((idm.hasOwnProperty(u)));
console.log("map has " + currentBuilding + " -> u: " + u);
findNeighbors(u);
case (idm.hasOwnProperty(d) === true):
console.log((idm.hasOwnProperty(d)));
console.log("map has " + currentBuilding + " -> d: " + d);
findNeighbors(d);
case (lRow === currRow && idm.hasOwnProperty(l) === true):
console.log((lRow === currRow && idm.hasOwnProperty(l)));
console.log("map has " + currentBuilding + " -> l: " + l);
findNeighbors(l);
case (rRow === currRow && idm.hasOwnProperty(r) === true):
console.log((rRow === currRow && idm.hasOwnProperty(r)))
console.log("map has " + currentBuilding + " -> r: " + u);
findNeighbors(r);
}
console.log("---------------------------");
}
I figured a switch statement would be cool to use to replace my if statements so all my checks could be visually and logically grouped.
Well, write code that works not code that looks cool. You were forgetting break statements, so the execution flow fell through - without evaluating the other case expressions after the first one matched. Btw switching on a constant is a horrible (uncool) practice.
Use standard if/else instead.

How to return data from a function

I'm trying to solve the following Kata:
a 2 digit number, if you add the digits together, multiply by 3, add 45 and reverse.
I'm unable to figure out how to return the data from my function so that I can later assign the value to an HTML element.
This is my code.
function daily() {
for(var j = 10; j < 100; j++) {
function teaser(num) {
var x = num;
var y = x.toString().split("");
if(y.length == 2) {
var sum = parseInt(y[0]) + parseInt(y[1]);
if(sum * 3 == x) {
console.log(x + " is equal to 3 times " + sum);
var addFortyFive = x + 45;
console.log("Adding 45 to " + x + " gives " + addFortyFive);
var reversal = parseInt(addFortyFive.toString().split('').reverse().join(''));
console.log("'The 2 digit number " + x + ", is 3 times the sum (" + sum + ") of its digits. If 45 is added to " + x + ", the result is " + addFortyFive + ". If the digits are reversed, the number is... " + reversal + ".");
}
} else {
console.log("Not a 2 digit Number!!");
}
}
teaser(j);
}
}
From your question I'm guessing you need reversal value on function daily for loop.
Would recommend you to take out function teaser from inside for-loop, this will make code much cleaner and easy to understand and you can do like:
function daily() {
for(var j = 10; j < 100; j++) {
var teaser = teaser(j);
// Can now use anything returned from teaser function here
}
}
function teaser(num) {
var x = num;
var y = x.toString().split("");
if(y.length == 2) {
var sum = parseInt(y[0]) + parseInt(y[1]);
if(sum * 3 == x) {
console.log(x + " is equal to 3 times " + sum);
var addFortyFive = x + 45;
console.log("Adding 45 to " + x + " gives " + addFortyFive);
var reversal = parseInt(addFortyFive.toString().split('').reverse().join(''));
console.log("'The 2 digit number " + x + ", is 3 times the sum (" + sum + ") of its digits. If 45 is added to " + x + ", the result is " + addFortyFive + ". If the digits are reversed, the number is... " + reversal + ".");
return reversal;
}
} else {
console.log("Not a 2 digit Number!!");
return false;
}
}
If don't want to take function out then you can do this:
function daily() {
for(var j = 10; j < 100; j++) {
function teaser(num) {
var x = num;
var y = x.toString().split("");
if(y.length == 2) {
var sum = parseInt(y[0]) + parseInt(y[1]);
if(sum * 3 == x) {
console.log(x + " is equal to 3 times " + sum);
var addFortyFive = x + 45;
console.log("Adding 45 to " + x + " gives " + addFortyFive);
var reversal = parseInt(addFortyFive.toString().split('').reverse().join(''));
console.log("'The 2 digit number " + x + ", is 3 times the sum (" + sum + ") of its digits. If 45 is added to " + x + ", the result is " + addFortyFive + ". If the digits are reversed, the number is... " + reversal + ".");
return reversal;
}
} else {
console.log("Not a 2 digit Number!!");
return false;
}
}
var teaser = teaser(j);
// Can now use anything returned from teaser function here
}
}
Returning something from a function is very simple!
Just add the return statement to your function.
function sayHello(name) {
return 'Hello ' + name + '!';
}
console.log(sayHello('David'));
okay, so my issue has been solved! Thanks all of you, especially krillgar, so I had to alter the code you gave me krillgar, a little bit in order to populate the results array with only the numbers (one number in this case) that satisfy the parameters of the daily tease I was asking about. yours was populating with 89 undefined and on number, 27 because it is the only number that works.
One of my problems was that I was expecting the return statement to not only save a value, but also show it on the screen, but what I was not realizing was that I needed a place to store the value. In your code you created a result array to populate with the correct numbers. And also, I needed a variable to store the data for each iteration of the for loop cycling through 10 - 100. Anyways, you gave me what I needed to figure this out and make it do what I wanted it to do, and all is well in the world again.
Anyway, thank you all for your help and input, and I will always remember to make sure I have somewhere to store the answers, and also somewheres to store the value of each loop iteration in order to decide which numbers to push into the results array and save it so it can be displayed and/or manipulated for whatever purpose it may be. I guess I was just so busy thinking about the fact that when I returned num it didn't show the value, instead of thinking about the fact that I needed to store the value. Here is the final code for this problem and thanks again peoples!
function daily() {
var results = [];
for(var j = 10; j < 100; j++) {
function teaser(num) {
var x = num;
var y = x.toString().split("");
if(y.length == 2) {
var sum = parseInt(y[0]) + parseInt(y[1]);
if(sum * 3 == x) {
console.log(x + " is equal to 3 times " + sum);
var addFortyFive = x + 45;
console.log("Adding 45 to " + x + " gives " + addFortyFive);
var reversal = parseInt(addFortyFive.toString().split('').reverse().join(''));
console.log("'The 2 digit number " + x + ", is 3 times the sum (" + sum + ") of its digits. If 45 is added to " + x + ", the result is " + addFortyFive + ". If the digits are reversed, the number is... " + reversal + ".");
return num;
// Here you have one that is correct, so return it:
} else {
console.log(num + " does not fulfill function parameters");
// This is just so you can visualize the numbers
return null;
}
}
}
var answer = teaser(j);
if(answer != null) {
results.push(answer);
}
}
return results;
}
As was said in the comments of the question, because you're going to (most likely) have multiple answers that match your condition, you will need to store those in an array. Your teaser function returns individual results, where daily will check all the numbers in your range.
function daily() {
var results = [];
for(var j = 10; j < 100; j++) {
function teaser(num) {
var x = num;
var y = x.toString().split("");
if(y.length == 2) {
var sum = parseInt(y[0]) + parseInt(y[1]);
if(sum * 3 == x) {
console.log(x + " is equal to 3 times " + sum);
var addFortyFive = x + 45;
console.log("Adding 45 to " + x + " gives " + addFortyFive);
var reversal = parseInt(addFortyFive.toString().split('').reverse().join(''));
console.log("'The 2 digit number " + x + ", is 3 times the sum (" + sum + ") of its digits. If 45 is added to " + x + ", the result is " + addFortyFive + ". If the digits are reversed, the number is... " + reversal + ".");
// Here you have one that is correct, so return it:
return num;
} else {
// Make sure we don't return undefined for when the sum
// times three doesn't equal the number.
return null;
}
} else {
console.log("Not a 2 digit Number!!");
return null;
}
}
var answer = teaser(j);
if (answer !== null) {
results.push(answer);
}
}
return results;
}

How to return a String representation of a calculation in Javascript

I am currently trying to complete an assignment for an intro2Javascript course. The question basically asks me to return a string of multiples of 2 parameters (num, numMultiple). Each time it increments the value i until i = numMultiple. For example:
5 x 1 = 5\n
5 x 2 = 10\n
5 x 3 = 15\n
5 x 4 = 20\n
This was my attempt:
function showMultiples(num, numMultiples) {
var result;
for (i = 1; i <= numMultiples; i++) {
result = num * i
multiples = "" + num + " x " + i + " = " + result + "\n"
return (multiples)
}
}
...and because the assignment comes with pre-written console logs:
console.log('showMultiples(2,8) returns: ' + showMultiples(2, 8));
console.log('showMultiples(3,2) returns: ' + showMultiples(3, 2));
console.log('showMultiples(5,4) returns: ' + showMultiples(5, 4));
console.log('\n');
This is my output:
showMultiples(2,8) returns: 2 x 1 = 2
Scratchpad/1:59:1
showMultiples(3,2) returns: 3 x 1 = 3
Scratchpad/1:60:1
showMultiples(5,4) returns: 5 x 1 = 5
UPDATE
You were doing two things incorrectly:
1) You were returning after the first iteration through your loop
2) You were assigning to multiples instead of appending to it.
Since you want to gather all the values and then show the final result first, I add all of the values to an array, and then use unshift() to add the final element (the result) to the beginning of the array. Then I use join() to return a string representation of the desired array.
function showMultiples(num, numMultiples) {
var result;
var multiples = [];
for (let i = 1; i <= numMultiples; i++) {
result = num * i
multiples.push("" + num + " x " + i + " = " + result + "\n")
}
multiples.unshift(multiples[multiples.length-1]);
return (multiples.join(''))
}
console.log('showMultiples(2,8) returns: ' + showMultiples(2, 8));
console.log('showMultiples(3,2) returns: ' + showMultiples(3, 2));
console.log('showMultiples(5,4) returns: ' + showMultiples(5, 4));
console.log('\n');
You need to declare all variables, because without you get global variables (beside that it does not work in 'strict mode').
The second point is to use multiples with an empty string for collecting all intermediate results and return that value at the end of the function.
For keeping the last result, you could use another variable and append that value at the end for return.
function showMultiples(num, numMultiples) {
var i,
result,
multiples = "",
temp = '';
for (i = 1; i <= numMultiples; i++) {
result = num * i;
temp = num + " x " + i + " = " + result + "\n";
multiples += temp;
}
return temp + multiples;
}
console.log('showMultiples(2,8) returns: ' + showMultiples(2, 8));
console.log('showMultiples(3,2) returns: ' + showMultiples(3, 2));
console.log('showMultiples(5,4) returns: ' + showMultiples(5, 4));
As other answers say, your problem is in multiple.
You are clearing multiple every iteration and storing the new value, but you do not want that, you want to add the new result, and to do so you use this code:
multiples = multiple + "" + num + " x " + i + " = " + result + "\n"
which can be compressed in what the rest of the people answered:
multiples += "" + num + " x " + i + " = " + result + "\n"
Probably you already know, but to ensure:
a += b ---> a = a + b
a -= b ---> a = a - b
a *= b ---> a = a * b
and there are even more.

how to get the position of a number in matrix?

How can I get the number's position by c or Javascript.
It is a ordered number array,like
1 2
3 4
5 6
how can I make a function to get the number 3 is 2-1,and 6 is 3-2
Thank you very much!
You could do something like this in javascript
var data = [
[1, 2],
[3, 4],
[5, 6]
];
var getPos = function(elem, data) {
var result = '';
data.forEach(function(value, index) {
value.forEach(function(v, i) {
if (v == elem) result += (index + 1) + '-' + (i + 1);
});
});
return result;
}
console.log(getPos(5, data));
In C you could write a function that would implement the following pseudo-code:
//...
for(i=0 ; i<ARRAY_SIZE ; i++)
{
if(array[i] == desired_num)
return i;
else
i++;
}
return -1; // return error if desired_num not found
//...
If it's a continuous ordered two-dimensional array you can do something like this to get the indices. (Notice +1 as per your example)
int x = floor(number/2) +1:
int y = (number+1)%2 +1;
If you are using arrays you should be able to jump the the right index without needing to loop like I see other answers suggesting.
array[x][y]
You may do something like this
var table = (new Array (10)).fill(new Array(10).fill("")).map( e=> e.map( f => ~~(Math.random()*1000))),
results = [];
function findInTable(t, q){
var finds = {x:[],y:[]};
t.forEach( (a, i) => {j = a.indexOf(q); ~j && (finds.x.push(j+1), finds.y.push(i+1))});
return finds;
}
results = findInTable(table, 777);
document.write("<pre>" + table[0] + "\n" + table[1] + "\n" + table[2] + "\n" + table[3] + "\n" + table[4] + "\n" + table[5] + "\n" + table[6] + "\n" + table[7] + "\n" + table[8] + "\n" + table[9] + "\n" +"</pre>");
document.write("<pre> Searched for " + 777+ " and found at:\n" + JSON.stringify(results, null, 4) + "</pre>");

Categories