Javascript even and odd range - javascript

I an trying to solve an online quiz but i don't seem to be able to pass all the tests. here is the question
Given two numbers X and Y, write a function that:
1 returns even numbers between X and Y, if X is greater than Y else it returns odd numbers between x and y
For instance, take the integers 10 and 2 . the function would return all the even numbers between 2 and 10.
Examples:
12, 0 => [2,4,6,8,10]
2, 12 => [3, 5, 7, 9, 11]
0, 0 => [ ]
Here is my code:
function number_game(x, y){
let numbers = [];
if (x > y){
for (let i = y; i <= x; i++){
if (i > y){
numbers.push(i);
}
}
}else{
for (let i = x; i <= y; i++){
if (i > x){
numbers.push(i);
}
}
}
const result = numbers.filter(function(num){
return x > y ? num % 2 === 0: num % 2 === 1;
});
return result;
}

While not written optimally, your code is essentially OK, except that it includes the higher number in the result. You're skipping the lower number with your if (i > y) test, although it would be simpler to just start your loop at y + 1.
To exclude the higher number, simply change the repetition criteria from <= to <.
It would also be simpler to perform the even or odd test in those loops.
function number_game(x, y) {
let numbers = [];
if (x > y) {
for (let i = y + 1; i < x; i++) {
if (i % 2 == 0) {
numbers.push(i);
}
}
} else {
for (let i = x + 1; i < y; i++) {
if (i % 2 == 1) {
numbers.push(i);
}
}
}
return numbers;
}
console.log(number_game(12, 0));
console.log(number_game(2, 12));
console.log(number_game(0, 0));
console.log(number_game(3, 13));
console.log(number_game(1, 1));

Because I'm such a damn sucker for code golfing:
const number_game = (x, y) => {
const min = Math.min(x, y), max = Math.max(x, y);
return Array.from(Array(max - min), (_, i) => i + min).slice(1)
.filter(v => v % 2 == (x < y));
};

Perhaps something like this could help.
function number_game(x, y) {
let result = [];
let min=0, max=0;
if(x==y) {
return result;
} else if (x > y) {
min = y;
max = x;
} else {
min = x;
max = y;
}
for (let i = min; i <= max; i++){
if (i%2===0 && x > y && i!=min && i!=max) {
result.push(i);
}
if (i%2===1 && x < y && i!=min && i!=max) {
result.push(i);
}
}
return result;
}
console.log(number_game(12,0));
console.log(number_game(2,12));
console.log(number_game(0,0));
console.log(number_game(13,1));
console.log(number_game(3,13));
console.log(number_game(1,1));
console.log(number_game(1,1000));
console.log(number_game(3,1300));

Instead of generating all the numbers, and then filtering them, you can generate just the numbers that you need:
function number_game(x, y) {
const start = Math.min(x, y);
const end = Math.max(x, y);
const base = x > y ? 2 - start % 2 : start % 2 + 1; // how much you need to add, to get from start to the first number in the result
const numbers = [];
for(let i = start + base; i < end; i+= 2) numbers.push(i);
return numbers;
}
console.log(JSON.stringify(number_game(9, 1)));
console.log(JSON.stringify(number_game(1, 9)));
console.log(JSON.stringify(number_game(12, 2)));
console.log(JSON.stringify(number_game(2, 12)));
console.log(JSON.stringify(number_game(12, 1)));
console.log(JSON.stringify(number_game(1, 12)));
console.log(JSON.stringify(number_game(2, 2)));

function returnOddOrEven(x,y){
// return empty array if both x and y are equal to 0
let mixedArr = [];
if (x ===0 && y===0){
return [];
}
// first condition of x greater than y
else if ( x > y){
for (var i = 1; i < x; i++){
if( i % 2 === 0){
mixedArr.push(i)
}
}
}
// second condition of y > x
else if( y > x){
for (var i = 1; i < y; i++){
if(i > 1 && i % 2 === 1){
mixedArr.push(i)
}
}
}
return mixedArr;
}

function number_game(x, y) {
var numArray = new Array();
if (x > y) {
for (i=y+1; i<x; i++) {
if (i%2 == 0) {
numArray[numArray.length] = i;
}
}
} else {
for (i=x+1; i<y; i++) {
if (i%2 != 0) {
numArray[numArray.length] = i;
}
}
}
return numArray;
}

Related

if a positive number is equal to its reverse

I'm making a program to receive a positive number and output "yes" if it's equal to its reverse;
otherwise, output "no".
What I've done so far:
HTML
<div class="column1">
<div class="input">
<button onclick="problem()"> Run the program </button>
</div>
<strong><p id="output"> </p></strong>
</div>
JS
function problem() {
var outputObj = document.getElementById("output");
var a = parseInt(prompt("Please enter a number: ", ""));
outputObj.innerHTML = "number: " + a + "<br><br>";
var reverse = 0;
while (a > 0){
num = a % 10; // the last digit
reverse = (reverse *10) + num; // calculating the reverse
a = Math.floor(a / 10); // go to next digit
}
if ( reverse == a){
outputObj.innerHTML = "yes";
}
else {
outputObj.innerHTML = "no";
}
outputObj.innerHTML = outputObj.innerHTML + "<br><br>" + "program ended";
document.getElementsByTagName("button")[0].setAttribute("disabled","true");
}
function isPalindrome(number){
return +number.toString().split("").reverse().join("") === number
}
Art for art
function palindrom(x)
{
let len = Math.floor(Math.log(x)/Math.log(10) +1);
while(len > 0) {
let last = Math.abs(x - Math.floor(x/10)*10);
let first = Math.floor(x / Math.pow(10, len -1));
if(first != last){
return false;
}
x -= Math.pow(10, len-1) * first ;
x = Math.floor(x/10);
len -= 2;
}
return true;
}
You should search for plaindromic numbers. For example the following code:
const isPalindrome = x => {
if (x < 0) return false
let reversed = 0, y = x
while (y > 0) {
const lastDigit = y % 10
reversed = (reversed * 10) + lastDigit
y = (y / 10) | 0
}
return x === reversed
}
const isPalindrome = num => {
const len = Math.floor(Math.log10(num));
let sum = 0;
for(let k = 0; k <= len; k++) {
sum += (Math.floor(num / 10 ** k) % 10) * 10 ** (len - k);
}
return sum === num;
}
console.log(isPalindrome(12321));

The algorithm problem: Unique Paths III. Using backtracing pattern in javascript and not work

On a 2-dimensional grid, there are 4 types of squares:
1 represents the starting square.  There is exactly one starting square.
2 represents the ending square.  There is exactly one ending square.
0 represents empty squares we can walk over.
-1 represents obstacles that we cannot walk over.
Return the number of 4-directional walks from the starting square to the ending square, that walk over every non-obstacle square exactly once.
source:力扣(LeetCode)
link:https://leetcode-cn.com/problems/unique-paths-iii
i'm trying to use backtrack pattern to solve this problem
here is my code
/**
* #param {number[][]} grid
* #return {number}
*/
var uniquePathsIII = function(grid) {
let m = grid.length,
n = grid[0].length;
let start, targetIndex1,targetIndex2;
let res = 0;
let zero_counts = 0;
for(let i = 0; i < m; i++){
for(let j = 0; j < n; j++){
if(grid[i][j] == 1){
start = [i,j]
}
else if(grid[i][j] == 0){
zero_counts += 1;
}
else if(grid[i][j] == 2){
targetIndex1 = i;
targetIndex2 = j;
}
}
}
const backtrace = (i, j, zero_count) => {
if( i < 0 || i >= m ||
j < 0 || j >= n ||
grid[i][j] == -1 || zero_count < 0)
{
return;
}
if(i == targetIndex1 && j == targetIndex2 ){
if(zero_count == 0)
{
console.log("yes")
res += 1;
}
return
}
grid[i][j] = -1;
backtrace(i+1, j, zero_count - 1)
backtrace(i-1, j, zero_count - 1)
backtrace(i, j+1, zero_count - 1)
backtrace(i, j-1, zero_count - 1)
grid[i][j] = 0;
}
backtrace(start[0], start[1], zero_counts);
return res;
};
test sample:
[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
expect result:
2
acutal result:
0
Perhaps a simpler solution is to use Depth First Search to solve Unique Paths III, as shown here.
The concept is that you take a point and then traverse in all directions until you hit an obstacle.
The guts are as follows:
int totalPaths = dfs(grid, x+1, y, zero) +
dfs(grid, x, y+1, zero) +
dfs(grid, x-1, y, zero) +
dfs(grid, x, y-1, zero);

Create staircase from symbols using javascript

I want to output the staircase from the symbols "#". It should look like this:
but all I achieve is this:
What should I do to get right output?
var n = 6;
var rows=[];
var cols=[];
for(i=n-1;i>=0;i--) {
rows=[];
for(j=0;j<n;j++) {
if(j >= i) {
rows[j] = "#";
} else {
rows[j] = "";
}
}
cols.push(rows);
cols.splice(0, cols.length - 1);
console.log(cols.join(","));
}
Think of it as a coordinate system, loop through y and x and add the needed symbols.
Remember to increase max x with current y if you want it dual sided.
function ladder(size, dualSided, empty, occupied) {
if (dualSided === void 0) { dualSided = true; }
if (empty === void 0) { empty = " "; }
if (occupied === void 0) { occupied = "▲"; }
var str = "";
for (var y = 0; y < size; y++) {
for (var x = 0; x < size + y; x++) {
if (dualSided != true && x == size) {
break;
}
if (x >= size - y - 1) {
str += occupied;
}
else {
str += empty;
}
}
str += "\n";
}
return str;
}
console.log(ladder(20, false));
Ok, try this(last 3 lines);
cols.push(rows.join(""));
cols.splice(0, cols.length - 1);
console.log(cols.join(""));
The issue is you are pushing array(row) in cols, where row array itself contains comma. If you do cols.push(rows.join("")) , all comma will be removed.
Simple solution using Array.from
Live demo check below.
function staircase(n) {
let arr = Array.from({ length: n }).fill(0);
arr.map((v,i) => {
let dummyArr = Array.from({ length: i+1 }).fill('#');
let spaceArr = Array.from({ length: arr.length - (i+1) }).fill(' ');
console.log(`${spaceArr.join('')}${dummyArr.join('')}`);
});
}
staircase(6);
try this simple solution
for (let i = 1; i <= n; i++) {
console.log("#".repeat(i).padStart(n));
}

Convert a number into sum of two other numbers so the difference is minimum

In Mars, there are only two denominations of currency ,x and y. A
Marsian goes to a bar and the bill is "z". Using x and y he has to pay
the bill. But the bar doesn't tender change, any extra money will be
taken as tips.
So write a function in JavaScript that helps the marsian to reduce the
tips.
The function takes in x, y, z and returns the amount of tip he has to
pay.
Example 1
Input: 2, 5, 109
Output: 0
Explanation: 21 coins of 5, and 2 coins of 2
Example 2
Input: 5, 7, 43
Output: 0
Explanation: 4 coins of 7, and 3 coins of 5
Example 3
Input: 15, 19, 33
Output: 1
Explanation: 1 coin of 15 and 1 coin of 19
Solution: I think this is level one DP problem, something like subset sum. Like for finding the optimal tip for the larger number, knowing the optimal tip for all the below numbers would help.
const coinA = 2
const coinB = 5
const sum = 13
var arr = [];
arr[0] =0;
console.log(getMyTip(coinA, coinB, sum));
function getMyTip(){
for(var i=1; i<= sum; i++){
var minA, minB;
if( i < coinA){
minA = coinA - i;
}else{
minA = arr[i - coinA];
}
if( i < coinB){
minB = coinB - i;
}else{
minB = arr [i - coinB]
}
arr[i] = Math.min(minA, minB);
}
return arr[sum];
}
Jsfiddle: https://jsfiddle.net/7c4sbe46/
But I'm not sure why it is not getting accepted. Please let me know if I'm missing something with the logic here.
It is more related to diophantine equations, i.e. is there a solution to a.x+b.y=z ? The answer is yes if z is a multiple of the greatest common divisor of x and y (called it gcd). If not, your tip will be the difference between 1. the smaller number divisible by gcd and greater than z
and 2. z.
Once you know the value of the tip, you can even easily know the number of x and y that you need by slightly modifying the value of z to (z+tip).
#include <stdio.h>
int main()
{
int curr1, curr2, bill;
scanf("%d %d %d",&curr1,&curr2,&bill);
int gcd, tip=0;
int x=curr1;
int y=curr2;
while(x!=y)
{
if(x > y)
x -= y;
else
y -= x;
}
gcd=x;
if((bill%curr1==0) || (bill%curr2==0) || (bill%(curr1 + curr2)==0)){
tip = 0;
} else if(bill>(curr1 + curr2) && (bill % gcd==0)) {
tip = 0;
} else if((curr1 + curr2) > bill){
if(curr2 > curr1){
tip = (bill % (curr2-curr1));
}else{
tip = (bill % (curr1-curr2));
}
}
printf("%d",tip);
return 0;
}
There is no need to use dp for this. Here is the simple solution -
// x -> first currency denomination
// y -> second currency denomination
// z -> total bill
var calculateTip = function(x,y,z) {
var xMax = Math.floor(z/x);
var tip = y;
if(xMax == 0) {
tip = (x-z) < (Math.ceil(z/y)*y - z) ? (x-z) : (Math.ceil(z/y)*y - z);
}
while (xMax>=0) {
var tempTip = xMax*x + Math.ceil((z-xMax*x)/y)*y - z;
if(tempTip < tip) {
tip = tempTip;
}
xMax--;
}
return tip;
}
var minimumTip = function(x,y,z) {
if(x>y) {
return calculateTip(x,y,z);
} else {
return calculateTip(y,x,z);
}
}
console.log(minimumTip(2, 5, 109));
var findTip = function(x=2, y=5, z=13){
var x = x;
var y = y;
var z = z;
var tip ;
var temp1 = x;
var temp2 = y
function findNumber(num,total){
if(num > total){
return num-total;
}
else{
var q = Math.floor(total/num);
return ((q+1)*num)-total;
}
}
function findMin(a,b,c){
var min ;
if(a<b && a<c){
min = a
}else{
if(b<c){
min = b;
}else{
min = c;
}
}
return min;
}
while(temp1!=temp2)
{
if(temp1 > temp2)
temp1 -= temp2;
else
temp2 -= temp1;
}
var factor =temp1;
if(z%x == 0 || z%y == 0 || z%(x+y) == 0) {
tip = 0;
}else if(z%factor == 0 && z>=x*y - x -y){
tip = 0;
}
else {
var minX= findNumber(x,z);
var minY = findNumber(y,z);
var minXY = findNumber(x+y,z);
console.log(minX,minY,minXY)
tip = findMin(minX,minY,minXY);
}
alert('the tip is '+ tip.toString());
return tip;
}
findTip(21, 11, 109);

How to optimize levenshtein distance for checking for a distance of 1?

I'm working on a game where I only need to check if there's a distance of 0 or 1 between two words and return true if that's the case. I found a general purpose levenshtein distance algorithm:
function levenshtein(s, t) {
if (s === t) { return 0; }
var n = s.length, m = t.length;
if (n === 0 || m === 0) { return n + m; }
var x = 0, y, a, b, c, d, g, h, k;
var p = new Array(n);
for (y = 0; y < n;) { p[y] = ++y; }
for (;
(x + 3) < m; x += 4) {
var e1 = t.charCodeAt(x);
var e2 = t.charCodeAt(x + 1);
var e3 = t.charCodeAt(x + 2);
var e4 = t.charCodeAt(x + 3);
c = x; b = x + 1; d = x + 2; g = x + 3; h = x + 4;
for (y = 0; y < n; y++) {
k = s.charCodeAt(y);
a = p[y];
if (a < c || b < c) { c = (a > b ? b + 1 : a + 1); }
else { if (e1 !== k) { c++; } }
if (c < b || d < b) { b = (c > d ? d + 1 : c + 1); }
else { if (e2 !== k) { b++; } }
if (b < d || g < d) { d = (b > g ? g + 1 : b + 1); }
else { if (e3 !== k) { d++; } }
if (d < g || h < g) { g = (d > h ? h + 1 : d + 1); }
else { if (e4 !== k) { g++; } }
p[y] = h = g; g = d; d = b; b = c; c = a;
}
}
for (; x < m;) {
var e = t.charCodeAt(x);
c = x;
d = ++x;
for (y = 0; y < n; y++) {
a = p[y];
if (a < c || d < c) { d = (a > d ? d + 1 : a + 1); }
else {
if (e !== s.charCodeAt(y)) { d = c + 1; }
else { d = c; }
}
p[y] = d;
c = a;
}
h = d;
}
return h;
}
Which works, but this spot is going to be a hotspot and be run potentially hundreds of thousands of times a second and I want to optimize it because I don't need a general purpose algorithm, just one that checks if there's a distance of 0 or 1.
I tried writing it and came up with this:
function closeGuess(guess, word) {
if (Math.abs(word.length - guess.length) > 1) { return false; }
var errors = 0, guessIndex = 0, wordIndex = 0;
while (guessIndex < guess.length || wordIndex < word.length) {
if (errors > 1) { return false; }
if (guess[guessIndex] !== word[wordIndex]) {
if (guess.length < word.length) { wordIndex++; }
else { guessIndex++; }
errors++;
} else {
wordIndex++;
guessIndex++;
}
}
return true;
}
But after profiling it I found that my code was twice as slow, which surprised me because I think the general purpose algorithm is O(n*m) and I think mine is O(n).
I've been testing the performance difference on this fiddle: https://jsfiddle.net/aubtze2L/3/
Are there any better algorithms I can use or any way I can optimize my code to be faster?
I don't see a more elegant way which is at the same time faster than the good old for-loop:
function lev01(a, b) {
let la = a.length;
let lb = b.length;
let d = 0;
switch (la - lb) {
case 0: // mutation
for (let i = 0; i < la; ++i) {
if (a.charAt(i) != b.charAt(i) && ++d > 1) {
return false;
}
}
return true;
case -1: // insertion
for (let i = 0; i < la + d; ++i) {
if (a.charAt(i - d) != b.charAt(i) && ++d > 1) {
return false;
}
}
return true;
case +1: // deletion
for (let i = 0; i < lb + d; ++i) {
if (a.charAt(i) != b.charAt(i - d) && ++d > 1) {
return false;
}
}
return true;
}
return false;
}
console.log(lev01("abc", "abc"));
console.log(lev01("abc", "abd"));
console.log(lev01("abc", "ab"));
console.log(lev01("abc", "abcd"));
console.log(lev01("abc", "cba"));
Performance comparison (Chrome):
80.33ms - lev01 (this answer)
234.84ms - lev
708.12ms - close
Consider the following cases:
If the difference in lengths of the terms is greater than 1, then
the Levenshtein distance between them will be greater than 1.
If the difference in lengths is exactly 1, then the shortest string must be equal to the longest string, with a single deletion (or insertion).
If the strings are the same length then you should
consider a modified version of Hamming distance which returns false
if two, different characters are found:
Here is a sample implementation:
var areSimilar;
areSimilar = function(guess, word) {
var charIndex, foundDiff, guessLength, lengthDiff, substring, wordLength, shortest, longest, shortestLength, offset;
guessLength = guess.length;
wordLength = word.length;
lengthDiff = guessLength - wordLength;
if (lengthDiff < -1 || lengthDiff > 1) {
return false;
}
if (lengthDiff !== 0) {
if (guessLength < wordLength) {
shortest = guess;
longest = word;
shortestLength = guessLength;
} else {
shortest = word;
longest = guess;
shortestLength = wordLength;
}
offset = 0;
for (charIndex = 0; charIndex < shortestLength; charIndex += 1) {
if (shortest[charIndex] !== longest[offset + charIndex]) {
if (offset > 0) {
return false; // second error
}
offset = 1;
if (shortest[charIndex] !== longest[offset + charIndex]) {
return false; // second error
}
}
}
return true; // only one error
}
foundDiff = false;
for (charIndex = 0; charIndex < guessLength; charIndex += 1) {
if (guess[charIndex] !== word[charIndex]) {
if (foundDiff) {
return false;
}
foundDiff = true;
}
}
return true;
};
I've updated your fiddle to include this method. Here are the results on my machine:
close: 154.61
lev: 176.72500000000002
sim: 32.48000000000013
Fiddle: https://jsfiddle.net/dylon/aubtze2L/11/
If you know that you are looking for distance 0 and 1, then the general purpose DP algorithm does not make sense (and by the way the algorithm you showed looks convoluted, take a look at a better explanation here).
To check that the distance is 0, all you need is to check whether 2 strings are the same. Now if the distance is one, it means that either insertion, deletion or substitution should have happened. So generate all possible deletion from the original string and check whether it is equal to second string. So you will get something like this:
for (var i = 0; i < s_1.length; i++) {
if s_2 == s_1.slice(0, i) + s_1.slice(i + 1) {
return true
}
}
For insertions and substitution you will need to know the alphabet of all characters. You can define it as a big string var alphabet = "abcde....". Now you do a similar thing, but when you introduce substitution or insertion, you also iterate over all elements in your alphabet. I am not planning to write the whole code here.
A couple of additional things. You can make a lot of micro-optimizations here. For example if the length of two strings are different by more than 1, they clearly can't have a distance 1. Another one relates to the frequencies of underlying characters in the string.

Categories

Resources