Roman and Arabic calculator JavaScript - javascript

I have an assignment on js (Roman and Arabic calculator). As I am not familiar with js, but I have to finish this assignment, I want your help to debug the code and fix my mistakes. I am confused on syntaxis of js and that's why my code looks so messed.
P.S. the problem occurs on the part where I consider Roman numerals
Basically, here is how calculator should work:
calculate('1 + 2')->3
calculate('VI / III')->III
calculate('I - II')->" " because there are no negative numbers in roman
calculate('I + 1'->throw Error
calculate('I')->throw Error
calculate('1 + 1 + 1')->throw Error
function romanToInt(s, c) {
const sym = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
}
if (c == 1) {
const result = 0;
for (i = 0; i < s.length; i++) {
const cur = sym[s[i]];
const next = sym[s[i + 1]];
if (cur < next) {
result += next - cur
i++
} else
result += cur
}
} else {
const result = "";
for (let digit in sym) {
result += digit.repeat(Math.floor(s / sym[digit]))
s %= sym[digit]
}
}
return result;
};
function calculator(s) {
if (s.length <= 1 || !s.trim())
throw Error;
let dig_flag = 0,
rom_flag = 0,
op_flag = 0;
let sum = 0;
let op = 1;
const stack = [];
const roman = "IVXLCDM"
for (let i = 0; i < s.length; i++) {
if (/[0-9]/.test(s[i])) {
if (rom_flag == 0) {
dig_flag = 1;
let num = 0;
while ((/[0-9]/.test(s[i])))
num = num * 10 + +s[i++];
if (num < 10 && num > 0)
throw Error;
else
stack.push(num);
i--;
} else
throw Error;
} else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/') {
if (op_flag == 0) {
op_flag = 1;
op = s[i];
} else
throw Error;
} else if (s[i] == ' ')
continue;
else if (roman.includes(s[i])) {
if (dig_flag == 0) {
rom_flag = 1;
let num = "";
while (roman.includes(s[i]))
num += s[i];
num = romanToInt(num, 1);
stack.push(num);
} else
throw Error;
} else
throw Error;
}
if (stack.length == 1)
return "";
else if (stack.length > 2)
throw Error;
else {
let fs = stack.pop();
let sn = stack.pop();
if (op == '+')
sum = fs + sn;
if (op == '-')
sum = sn - fs;
if (op == '*')
sum = fs * sn;
if (op == '/')
sum = Math.trunc(sn / fs);
}
if (rom_flag == 1) {
if (sum < 0)
throw Error;
else
return romanToInt(sum, 2);
}
return sum.toString();
}
module.exports = calculator;

Related

Confused regarding time complexity of different implementations (Hash map setting/getting slower than N-loop)

I am having some trouble understanding a pattern I am seeing with a leet code problem I have been doing. The question regards detecting the longest palindrome in a string. I figured using a hashmap to determine palindromes, where length 1= palindrome, length 2 where characters are the same is a palindrome, and where if the first and last characters, and all the characters in the middle is a palindrome (detected by hash map) Basically this implementation with a hash map should be able to detect if something is a palindrome of 0(1) time complexity. But its much slower than the implementation without a hashmap, where we use a for loop to detect if a substring is a palindrome in 0(n): Here are the two imeplementations, does anyone know why the first is so much slower than the second. Shouldn't it be much quicker?
Slow implementation
/**
* #param {string} s
* #return {string}
*/
var longestPalindrome = function (s) {
let palindromes = new Map();
let palin = s[0];
for (let c = 0; c <= s.length; c++) {
for (let r = 0; r < c; r++) {
let tempStr = s.slice(r, c);
if (tempStr.length == 1) {
palin = tempStr.length > palin.length ? tempStr : palin;
palindromes.set(r + "r" + c + "c", true);
} else if (tempStr.length == 2) {
if (tempStr[0] === tempStr[1]) {
palin = tempStr.length > palin.length ? tempStr : palin;
palindromes.set(r + "r" + c + "c", true);
}
} else if (tempStr[0] === tempStr[tempStr.length - 1]) {
if (palindromes.get(r + 1 + "r" + (c - 1) + "c") === true) {
palin = tempStr.length > palin.length ? tempStr : palin;
palindromes.set(r + "r" + c + "c", true);
}
} else {
palindromes.set(r + "r" + c + "c", false);
}
}
}
return palin;
};
Faster implementation, for some reason
var isPalidrome = function (s) {
for (var i = 0; i < s.length / 2; i++) {
if (s[i] !== s[s.length - i - 1]) {
return false;
}
}
return true;
};
var longestPalindrome = function (s) {
let palindromes = new Map();
var max = s[0];
let palin = "";
for (let c = 0; c <= s.length; c++) {
for (let r = 0; r < c; r++) {
let tempStr = s.slice(r, c);
if (isPalidrome(tempStr)) {
max = tempStr.length > max.length ? tempStr : max;
}
}
}
return max;
};
Thanks!
EDIT:
So by allocating and using array indices instead of the map, I made it finally run quicker than the N loop implementation. I guess my question is, why isn't the Map accesses 0(1). Is Javascript not using the most efficient map implementation or something? Do maps get very slow where their big for some reason? Some help understanding this would be appreciated.
So to Refactor my question: Why is this:
/**
* #param {string} s
* #return {string}
*/
var longestPalindrome = function (s) {
let palindromes2 = [];
for (let i = 0; i < s.length; i++) {
palindromes2.push([]);
}
let palin = s[0];
for (let c = 0; c <= s.length; c++) {
for (let r = 0; r < c; r++) {
let tempStr = s.slice(r, c);
if (tempStr.length == 1) {
palin = tempStr.length > palin.length ? tempStr : palin;
palindromes2[r][c] = true;
} else if (tempStr.length == 2) {
if (tempStr[0] === tempStr[1]) {
palin = tempStr.length > palin.length ? tempStr : palin;
palindromes2[r][c] = true;
} else {
palindromes2[r][c] = false;
}
} else if (tempStr[0] === tempStr[tempStr.length - 1]) {
if (palindromes2[r + 1][c - 1] === true) {
palin = tempStr.length > palin.length ? tempStr : palin;
palindromes2[r][c] = true;
} else {
palindromes2[r][c] = false;
}
} else {
palindromes2[r][c] = false;
}
}
}
return palin;
};
SOOOO much faster (6x+ faster) than the first implementation I posted, with a hash map.
Thanks.

How to find the first prime number in range on JS

I have this code that finds all the prime numbers between 2 values, but how do i change it to find only the first one?
e.g. 33 and 147 = 37
let a, b, i, j, primo;
a = window.prompt("Numero minimo: ");
b = window.prompt("Numero maximo: ");
console.log("Numeros primos entre " + a + " e " + b << " é: ");
for (i = a; i <= b; i++) {
if (i == 1 || i == 0)
continue;
primo = 1;
for (j = 2; j < i; ++j) {
if (i % j == 0) {
primo = 0;
break;
}
}
if (primo == 1)
document.write(i," ");
}
You can extend the final if statement with this:
if (primo == 1) {
document.write(i, " ");
break;
}
break allows you to exit the for loop. You can learn more here: https://www.w3schools.com/js/js_break.asp
let a, b, i, j, primo;
a = window.prompt("Numero minimo: ");
b = window.prompt("Numero maximo: ");
console.log("Numeros primos entre " + a + " e " + b << " é: ");
for (i = a; i <= b; i++) {
if (i == 1 || i == 0)
continue;
primo = 1;
for (j = 2; j < i; ++j) {
if (i % j == 0) {
primo = 0;
break;
}
}
if (primo == 1) {
document.write(i, " ");
break;
}
}
That would be the algorithm for find the first prime in a array.
function makeArr(start, end) {
end++
return Array.from({length: (end-start)}, (v, k) => k+start)
}
isPrime = num => {
for(let i = 2, s = Math.sqrt(num); i <= s; i++)
if(num % i === 0) return false;
return num > 1;
}
nums = makeArr(33,147);
r = nums.filter(n => isPrime(n))
console.log(r[0])
Wrapped in a function example
function getFirstPrimeNumber(s, e) {
const start = parseInt(s);
let end = parseInt(e);
end++;
const _a= Array.from({length: (end-start)}, (v, k) => k+start)
const isPrime = num => {
for(let i = 2, s = Math.sqrt(num); i <= s; i++)
if(num % i === 0) return false;
return num > 1;
}
const primes = _a.filter(n => isPrime(n));
return primes[0];
}
const a = window.prompt("Numero minimo: ");
const b = window.prompt("Numero maximo: ");
const r = getFirstPrimeNumber(a,b)
console.log('result', r);

Run IndexOf more than one time JS

How to search multiple same values and look if it meets the conditions without regex? Suppose that I have this string ***6**5****8*9***2
What I need to do is to check if the string has at least three times *** altogether and then if the number before and after the *** sums 11. In the example given, these conditions are met because: First, the string has three *** altogether, and then 9 + 2 is 11.
I have solved this problem using regex, match, and replace, but how I can do it without applying to those solutions.
I have tried to do this without regex but it did not work because indexOf is only giving me one result:
string = "***6**5****8*9***2";
for (var i = 0; i < string.length; i++) {
let where = (string.indexOf("***"));
let a = parseInt(string.charAt(where - 1));
let b = parseInt(string.charAt(where + 3));
if (a + b == 11){
isTrue = true;
}
}
You could split the string by stars amd keep the starts in the array then check if the value starts with a star, check the length and the left and right element for sum.
var string = "***6**5****8*9***2",
parts = string.split(/(\*+)/),
result = parts.some((s, i, { [i - 1]: l, [i + 1]: r }) =>
s[0] === '*' && s.length >= 3 && +l + +r === 11
);
console.log(result);
console.log(parts);
I tried to create a solution based off of your existing code:
string = "***6**5****8*9***2***4";
let where = 0;
// Skip leading *
while (where < string.length && '*' == string.charAt(where)) {
where += 1;
}
while (true) {
// Find three stars based on previous result
where = string.indexOf("***", where);
// No more triples
if (where == -1) break;
// Convert to digit - will be NaN if not a digit
let a = parseInt(string.charAt(where - 1));
// Find trailing digit
let j = where + 1;
// Skip to next non * char
while (j < string.length && '*' == string.charAt(j)) {
j += 1;
}
// No matches - quit
if (j == string.length) break;
// Parse digit
let b = parseInt(string.charAt(j));
// Do the math
if (!isNaN(a) && !isNaN(b)){
console.log(`${a} + ${b} = ${a+b}`);
}
where = j;
}
I wrote a simple Parser.I hope it can help you
string = "***6**5****8*9***2";
class Parser {
static parse(string) {
var lexer = new Lexer(string);
var token = lexer.getToken();
var prevNumberToken = null ;
while (token.type !== TOKEN_TYPE_END) {
if(token.type === TOKEN_TYPE_NUMBER){
if(prevNumberToken && prevNumberToken.value + token.value === 11 ) {
return true;
}
prevNumberToken = token ;
} else if(token.type !== TOKEN_TYPE_THREESTARS){
prevNumberToken = null ;
}
token = lexer.getToken();
}
return false;
}
}
class Lexer {
constructor(string) {
this._string = string;
this._index = -1;
this._len = string.length;
}
getToken() {
if (this._index < 0) {
this._index = 0;
return new Token(TOKEN_TYPE_START, '', -1);
}
if (this._index >= this._len) {
return new Token(TOKEN_TYPE_END, '', this._len);
}
if (this._string[this._index] === "*") {
return this._getStarToken()
} else {
return this._getNumberToken();
}
}
_getStarToken() {
var stars = "";
var i = this._index;
while (this._index < this._len && this._string[this._index] === "*") {
stars += "*";
this._index++;
}
if (stars.length === 3) {
return new Token(TOKEN_TYPE_THREESTARS, stars, i)
}
return new Token(TOKEN_TYPE_STARS, stars, i)
}
_getNumberToken() {
var numbers = "";
var i = this._index;
while (this._index < this._len && this._string[this._index] !== "*") {
if (this._string[this._index] >= "0" && this._string[this._index] <= "90") {
numbers += this._string[this._index];
this._index++;
} else {
throw new Error("invalid character")
}
}
return new Token(TOKEN_TYPE_NUMBER, parseInt(numbers), i);
}
}
class Token {
constructor(type, value, index) {
this._type = type
this._index = index
this._value = value
}
get type() { return this._type }
get index() { return this._index }
get value() { return this._value }
}
const TOKEN_TYPE_START = 1;
const TOKEN_TYPE_NUMBER = 2;
const TOKEN_TYPE_THREESTARS = 4;
const TOKEN_TYPE_STARS = 8;
const TOKEN_TYPE_END = 16;
console.log(Parser.parse(string));

Javascript Function Issues for Prime Numbers

So what I'm trying to do is use a function that prompts to enter a number and then prints all prime numbers up till that number. I have the code as far as I know but I keep getting an error that the bracket following prime(num) is wrong. Not sure what I'm doing wrong here, would appreciate any help.
function p5Bela() {
var num = prompt("Please enter a number: ", "");
for (i = 2; i <= num; i++) {
if (prime(i)==true) {
alert(i);
}
}
prime(num) {
var flag = true;
var d = 2;
while (flag==true && d <= num/2) {
if (num%d == 0) {
flag = false;
}
d++;
}
return flag;
}
}
Simplest Way
function isPrime(num) {
for(var i = 2; i < num; i++)
if(num % i === 0) return false;
return num > 1;
}
With the ES6 syntax:
const isPrime = num => {
for(let i = 2; i < num; i++)
if(num % i === 0) return false;
return num > 1;
}
You can also decrease the complexity of the algorithm from O(n) to O(sqrt(n)) if you run the loop until square root of a number:
const isPrime = num => {
for(let i = 2, s = Math.sqrt(num); i <= s; i++)
if(num % i === 0) return false;
return num > 1;
}

finding the nth prime javascript

the functions below are supposed to spit out the nth prime number. However, it keeps on spitting out 3. Can somebody please help? Cheers, Anthony
function Prime(num) {
output = true
for (i=2 ; i<num ; i++) {
if (num%i === 0) {
output = false ; break
}
}
return output
}
function PrimeMover(num) {
var count = 0
for (i=2 ; i<10000 ; i++) {
if (Prime(i) === true) {
count = count + 1
}
if (count === num) {
return i
break
}
}
}
You have created loop counter i in global scope.so both PrimeMover and Prime mutates same global i.In every iteration ,PrimeMover assigns i=2.After that Prime assigns i=2.your i variable's value will be changed between 2 and 3.use local loop counter variable var i=0;
function Prime(num) {
output = true
for (var i=2 ; i<num ; i++) { //var i=2
if (num%i === 0) {
output = false ; break
}
}
return output
}
function PrimeMover(num) {
var count = 0
for (var i=2 ; i<10000 ; i++) { //var i=2
if (Prime(i) === true) {
count = count + 1
}
if (count === num) {
return i
break
}
}
}
For minimal code lovers,
function nthprime(n)
{
var prime=[], i=1
while (i++ && prime.length<n) prime.reduce((a,c)=>(i%c)*a,2) && prime.push(i)
return prime.length?prime.pop():-1
}
[-1,0,1,2,3,5,10,100].forEach(n=>console.log(`nthprime(${n})=${nthprime(n)}`))
function main(inp) {
var count = 0;
for (var i = 2; i <= 100000; i++) {
if (isPrime(i)) count = count + 1;
if (count == inp) return i;
}
}
function isPrime(i) {
for (var j = 2; j < i; j++) {
//instead of `j < i` it can be reduced using other conditions
if (i % j == 0) {
return false
}
}
return true
}
main(5) // any number
This might be a bit more optimal
function nthPrime(n) {
var P = 0;
function isPrime(x) {
var isPrime= true;
for (var d = 2; d <= Math.sqrt(x); d++) {
if((x/d) % 1 == 0) {
isPrime = false;
break;
}
}
return isPrime;
}
for (var i = 1; 0 < n; i++) {
if(isPrime(i)) {
P = i; n--;
}
// we can skip the even numbers
if(3 <= i){
i++;
}
}
return P;
}
Try this
var pos=10001;
console.log(primeNumforPos(pos));
function primeNumforPos(pos){
var num=2,curPos=0;
while(curPos<=pos){
if(isPrime(num)){
curPos++;
}
if(curPos==pos){
return num;
}else{
num++;
}
}
}
function isPrime(num){
for(var i=2;i<=Math.sqrt(num);i++){
if(num%i==0){
return false;
}
}
return true;
}
So, I decided to optimise the hell out of the code (cuz why not). It is almost 6 times as fast as that of ppseprus (297ms vs 1773ms in nth_prime(100000)).
let primes = [2, 3];
const nth_prime = (n) => {
if (n <= primes.length) return primes[n - 1]; // handle values which have been cached
let i = 1;
while (1){
const a = 6 * i - 1, b = 6 * i + 1, a_limit = Math.sqrt(a), b_limit = Math.sqrt(b); // the 6n - 1 and 6n + 1 rule for primes
let a_prime = true, b_prime = true;
i++;
// prime check
for (const prime of primes){
if (prime > a_limit) break;
if (a % prime == 0){
a_prime = false;
break;
}
}
if (a_prime){
if (primes.length + 1 == n) return a;
primes.push(a); // cache
}
for (const prime of primes){
if (prime > b_limit) break;
if (b % prime == 0){
b_prime = false;
break;
}
}
if (b_prime){
if (primes.length + 1 == n) return b;
primes.push(b); // cache
}
}
}
const findPrime = num => {
let i, primes = [2, 3], n = 5
const isPrime = n => {
let i = 1, p = primes[i],
limit = Math.ceil(Math.sqrt(n))
while (p <= limit) {
if (n % p === 0) {
return false
}
i += 1
p = primes[i]
}
return true
}
for (i = 2; i <= num; i += 1) {
while (!isPrime(n)) {
n += 2
}
primes.push(n)
n += 2
};
return primes[num - 1]
}
console.time('Time')
let x = findPrime(9999)
console.timeEnd('Time')
console.log(x)

Categories