Big O of this short code - javascript

I would need to determin the Big O of this short code:
var iterations = 0;
function operation(num){
iterations++;
if (num == 0) return 1;
return operation(Math.floor((num / 10) * 2));
}
var result = operation(1000);
alert('Result = ' + result + ', number of iterations = ' + iterations);
I came up with something around O(log(logN)) but I'm not sure. Would you please help me a bit?
http://jsfiddle.net/qotbu5pq/2/

[Answer from comment]
you are almost dividing operations by 5 until hit the zero result
so should not it be ~log5(N) iterations instead which means O(log(N))
sorry didn't want to add such trivial answer ...

Related

Why is the exact calculation solution slower than binary search solution?

So I tried doing this leetcode question: https://leetcode.com/problems/arranging-coins/
After doing some math, I came up with this solution:
var arrangeCoins = function(n) {
return parseInt((Math.sqrt(8*n+1)-1)/2);
};
This does return the right answer. However, I noticed that it is literally the bottom of the barrel when it comes to execution speed. Comparatively, the alternative solution, where binary search is used to search for the right value in the range of 1 to n is around 2 to 3 times faster than mine. So something like this:
var arrangeCoins = function(n) {
let left = 1;
let right = n;
while(left + 1 < right){
let mid = Math.floor(left + (right - left) / 2);
let sum = (mid + 1) * mid / 2
if(sum === n){
return mid;
}else if(sum < n){
left = mid;
}else{
right = mid;
}
}
return (right + 1) * right / 2 === n? right : left;
}
Compared to my solution, this has the time complexity of O(log n), which would mean it should have been slower, at least in theory.
Why is this the case? What can I do to improve the execution speed of my solution?
This is not an authoritative answer but:
sqrt is relatively slow
it looks like your parseInt is useless and wastes time

Applying Fibonacci, working with large numbers

I am trying to successfully complete this challenge on the Rosalind page. The challenge is:
Given: Positive integers n≤40 and k≤5.
Return: The total number of rabbit pairs that will be present after n months if we begin with 1 pair and in each generation, every pair of reproduction-age rabbits produces a litter of k rabbit pairs (instead of only 1 pair).
The exercise gives a text file of two numbers, the n and k mentioned above.
My code, which attempts to implement Fibonacci, works as expected for lower numbers of months. However, the result begins to become extremely large for higher numbers of months, and in each case I am given, my answer is Infinity.
Is my formula applied incorrectly? Or is Javascript a bad choice of language to use for such an exercise?
My code:
function fibonacciRabbits(months, pairs){
var months = months;
var numberOfPairs = pairs;
var result = 0;
// Declare parent & child arrays with constants
var parentArr = [1, numberOfPairs + 1]
var childArr = [numberOfPairs, numberOfPairs]
var total = []
// Loop from the point after constants set above
for(var i = 2; i < months - 2 ; i++){
parentArr.push(parentArr[i-1] + childArr[i-1])
childArr.push(parentArr[i-1] * childArr[i-2])
total.push(parentArr[i-1] + childArr[i-1])
}
result = childArr[childArr.length - 1] + parentArr[parentArr.length - 1]
console.log(months + ' months and ' + numberOfPairs + ' pairs:\n')
console.log('parentArr:\n', parentArr)
console.log('childArr:\n', childArr)
console.log('total\n', total)
console.log('result:', result)
console.log('\n\n\n')
}
fibonacciRabbits(5, 3)
fibonacciRabbits(11, 3)
fibonacciRabbits(21, 3)
fibonacciRabbits(31, 2)
And here is a REPL
Here is a more brief solution that doesn't produce such large numbers, and handles the maximum case without hitting infinity in Javascript. I think your solution was getting too big too fast.
function fibonacciRabbits(months, reproAmount){
var existingAdults = 0;
var adultPairs = 0;
var childPairs = 1;
for(var i = 2; i <= months; i++){
adultPairs = childPairs; //children mature
childPairs = (existingAdults * reproAmount); //last month's adults reproduce
existingAdults += adultPairs; //new adults added to the reproduction pool
}
console.log(existingAdults + childPairs);
}
To make sure you are on the right track, test your function with:
fibonacciRabbits(1, 1);
fibonacciRabbits(2, 1);
Which from the website says: f(1)=f(2)=1. So these should both produce "1" no matter what. Your code produces "3" for both of these.

Fibonacci Sequence - Find the number of digits - JavaScript

So, I have successfully written the Fibonacci sequence to create an array with the sequence of numbers, but I need to know the length (how many digits) the 500th number has.
I've tried the below code, but its finding the length of the scientific notation (22 digits), not the proper 105 it should be returning.
Any ideas how to convert a scientific notation number into an actual integer?
var fiblength = function fiblength(nth) {
var temparr = [0,1];
for(var i = 2; i<=nth; i++){
var prev = temparr[temparr.length-2],
cur = temparr[temparr.length-1],
next = prev + cur;
temparr.push(next);
}
var final = temparr[temparr.length-1].toString().length;
console.log(temparr[temparr.length-1]);
return final;
};
a = fiblength(500);
console.log(a);
Why not use the simple procedure of dividing the number by 10 until the number is less than 1.
Something as simple as this should work (a recursive def obv works as well)
function getDigits(n) {
var digits = 0;
while(n >= 1) {
n/=10;
digits += 1;
}
return digits;
}
getDigits(200);//3
getDigits(3.2 * 10e20);//=>22
Here's a solution in constant time:
function fiblength(n) {
return Math.floor((n>1)?n*.2089+.65051:1);
}
Let's explain how I arrived to it.
All previous solutions will probably not work for N>300 unless you have a BigNumber library in place. Also they're pretty inneficient.
There is a formula to get any Fibonacci number, which uses PHI (golden ratio number), it's very simple:
F(n) = ABS((PHI^n)/sqrt(5))
Where PHI=1.61803399 (golden ratio, found all over the fibonacci sequence)
If you want to know how many digits a number has, you calculate the log base 10 and add 1 to that. Let's call that function D(n) = log10(n) + 1
So what you want fiblength to be is in just the following function
fiblength(n) = D(F(n)) // number of digits of a fibonacci number...
Let's work it out, so you see what the one liner code will be like once you use math.
Substitute F(n)
fiblength(n) = D(ABS((PHI^n)/sqrt(5)))
Now apply D(n) on that:
fiblength(n) = log10(ABS((PHI^n)/sqrt(5))) + 1
So, since log(a/b) = log(a) - log(b)
fiblength(n) = log10(ABS((PHI^n))) - log10(sqrt(5))) + 1
and since log(a^n) = n * log(a)
fiblength(n) = n*log10(PHI) - log10(sqrt(5))) + 1
Then we evaluate those logarithms since they're all on constants
and add the special cases of n=0 and n=1 to return 1
function fiblength(n) {
return Math.floor((n>1)?n*.2089+.65051:1);
}
Enjoy :)
fiblength(500) => 105 //no iterations necessary.
Most of the javascript implementations, internally use 64 bit numbers. So, if the number we are trying to represent is very big, it uses scientific notation to represent those numbers. So, there is no pure "javascript numbers" based solution for this. You may have to look for other BigNum libraries.
As far as your code is concerned, you want only the 500th number, so you don't have to store the entire array of numbers in memory, just previous and current numbers are enough.
function fiblength(nth) {
var previous = 0, current = 1, temp;
for(var i = 2; i<=nth; i++){
temp = current;
current = previous + current;
previous = temp;
}
return current;
};
My Final Solution
function fiblength(nth) {
var a = 0, b = 1, c;
for(var i=2;i<=nth;i++){
c=b;
b=a+b;
a=c;
}
return Math.floor(Math.log(b)/Math.log(10))+1;
}
console.log(fiblength(500));
Thanks for the help!!!
The problem is because the resulting number was converted into a string before any meaningful calculations could be made. Here's how it could have been solved in the original code:
var fiblength = function fiblength(nth) {
var temparr = [0,1];
for(var i = 2; i<=nth; i++){
var prev = temparr[temparr.length-2],
cur = temparr[temparr.length-1],
next = prev + cur;
temparr.push(next);
}
var x = temparr[temparr.length-1];
console.log(x);
var length = 1;
while (x > 1) {
length = length + 1;
x = x/10;
}
return length;
};
console.log ( fiblength(500) );

Round number up to the nearest multiple of 3

How would I go about rounded a number up the nearest multiple of 3?
i.e.
25 would return 27
1 would return 3
0 would return 3
6 would return 6
if(n > 0)
return Math.ceil(n/3.0) * 3;
else if( n < 0)
return Math.floor(n/3.0) * 3;
else
return 3;
Simply:
3.0*Math.ceil(n/3.0)
?
Here you are!
Number.prototype.roundTo = function(num) {
var resto = this%num;
if (resto <= (num/2)) {
return this-resto;
} else {
return this+num-resto;
}
}
Examples:
y = 236.32;
x = y.roundTo(10);
// results in x = 240
y = 236.32;
x = y.roundTo(5);
// results in x = 235
I'm answering this in psuedocode since I program mainly in SystemVerilog and Vera (ASIC HDL). % represents a modulus function.
round_number_up_to_nearest_divisor = number + ((divisor - (number % divisor)) % divisor)
This works in any case.
The modulus of the number calculates the remainder, subtracting that from the divisor results in the number required to get to the next divisor multiple, then the "magic" occurs. You would think that it's good enough to have the single modulus function, but in the case where the number is an exact multiple of the divisor, it calculates an extra multiple. ie, 24 would return 27. The additional modulus protects against this by making the addition 0.
As mentioned in a comment to the accepted answer, you can just use this:
Math.ceil(x/3)*3
(Even though it does not return 3 when x is 0, because that was likely a mistake by the OP.)
Out of the nine answers posted before this one (that have not been deleted or that do not have such a low score that they are not visible to all users), only the ones by Dean Nicholson (excepting the issue with loss of significance) and beauburrier are correct. The accepted answer gives the wrong result for negative numbers and it adds an exception for 0 to account for what was likely a mistake by the OP. Two other answers round a number to the nearest multiple instead of always rounding up, one more gives the wrong result for negative numbers, and three more even give the wrong result for positive numbers.
This function will round up to the nearest multiple of whatever factor you provide.
It will not round up 0 or numbers which are already multiples.
round_up = function(x,factor){ return x - (x%factor) + (x%factor>0 && factor);}
round_up(25,3)
27
round up(1,3)
3
round_up(0,3)
0
round_up(6,3)
6
The behavior for 0 is not what you asked for, but seems more consistent and useful this way. If you did want to round up 0 though, the following function would do that:
round_up = function(x,factor){ return x - (x%factor) + ( (x%factor>0 || x==0) && factor);}
round_up(25,3)
27
round up(1,3)
3
round_up(0,3)
3
round_up(6,3)
6
Building on #Makram's approach, and incorporating #Adam's subsequent comments, I've modified the original Math.prototype example such that it accurately rounds negative numbers in both zero-centric and unbiased systems:
Number.prototype.mround = function(_mult, _zero) {
var bias = _zero || false;
var base = Math.abs(this);
var mult = Math.abs(_mult);
if (bias == true) {
base = Math.round(base / mult) * _mult;
base = (this<0)?-base:base ;
} else {
base = Math.round(this / _mult) * _mult;
}
return parseFloat(base.toFixed(_mult.precision()));
}
Number.prototype.precision = function() {
if (!isFinite(this)) return 0;
var a = this, e = 1, p = 0;
while (Math.round(a * e) / e !== a) { a *= 10; p++; }
return p;
}
Examples:
(-2).mround(3) returns -3;
(0).mround(3) returns 0;
(2).mround(3) returns 3;
(25.4).mround(3) returns 24;
(15.12).mround(.1) returns 15.1
(n - n mod 3)+3
$(document).ready(function() {
var modulus = 3;
for (i=0; i < 21; i++) {
$("#results").append("<li>" + roundUp(i, modulus) + "</li>")
}
});
function roundUp(number, modulus) {
var remainder = number % modulus;
if (remainder == 0) {
return number;
} else {
return number + modulus - remainder;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Round up to nearest multiple of 3:
<ul id="results">
</ul>
A more general answer that might help somebody with a more general problem: if you want to round numbers to multiples of a fraction, consider using a library. This is a valid use case in GUI where decimals are typed into input and for instance you want to coerce them to multiples of 0.25, 0.2, 0.5 etc. Then the naive approach won't get you far:
function roundToStep(value, step) {
return Math.round(value / step) * step;
}
console.log(roundToStep(1.005, 0.01)); // 1, and should be 1.01
After hours of trying to write up my own function and looking up npm packages, I decided that Decimal.js gets the job done right away. It even has a toNearest method that does exactly that, and you can choose whether to round up, down, or to closer value (default).
const Decimal = require("decimal.js")
function roundToStep (value, step) {
return new Decimal(value).toNearest(step).toNumber();
}
console.log(roundToStep(1.005, 0.01)); // 1.01
RunKit example
Using remainder operator (modulus):
(n - 1 - (n - 1) % 3) + 3
By the code given below use can change any numbers and you can find any multiple of any number
let numbers = [8,11,15];
let multiple = 3
let result = numbers.map(myFunction);
function myFunction(n){
let answer = Math.round(n/multiple) * multiple ;
if (answer <= 0)
return multiple
else
return answer
}
console.log("Closest Multiple of " + multiple + " is " + result);
if(x%3==0)
return x
else
return ((x/3|0)+1)*3

Fastest method to replace all instances of a character in a string [duplicate]

This question already has answers here:
How do I replace all occurrences of a string in JavaScript?
(78 answers)
Closed 3 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Needs details or clarity Add details and clarify the problem by editing this post.
What is the fastest way to replace all instances of a string/character in a string in JavaScript? A while, a for-loop, a regular expression?
The easiest would be to use a regular expression with g flag to replace all instances:
str.replace(/foo/g, "bar")
This will replace all occurrences of foo with bar in the string str. If you just have a string, you can convert it to a RegExp object like this:
var pattern = "foobar",
re = new RegExp(pattern, "g");
Try this replaceAll:
http://dumpsite.com/forum/index.php?topic=4.msg8#msg8
String.prototype.replaceAll = function(str1, str2, ignore)
{
return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
}
It is very fast, and it will work for ALL these conditions
that many others fail on:
"x".replaceAll("x", "xyz");
// xyz
"x".replaceAll("", "xyz");
// xyzxxyz
"aA".replaceAll("a", "b", true);
// bb
"Hello???".replaceAll("?", "!");
// Hello!!!
Let me know if you can break it, or you have something better, but make sure it can pass these 4 tests.
var mystring = 'This is a string';
var newString = mystring.replace(/i/g, "a");
newString now is 'Thas as a strang'
Also you can try:
string.split('foo').join('bar');
You can use the following:
newStr = str.replace(/[^a-z0-9]/gi, '_');
or
newStr = str.replace(/[^a-zA-Z0-9]/g, '_');
This is going to replace all the character that are not letter or numbers to ('_'). Simple change the underscore value for whatever you want to replace it.
Use Regex object like this
var regex = new RegExp('"', 'g');
str = str.replace(regex, '\'');
It will replace all occurrence of " into '.
Just thinking about it from a speed issue I believe the case sensitive example provided in the link above would be by far the fastest solution.
var token = "\r\n";
var newToken = " ";
var oldStr = "This is a test\r\nof the emergency broadcasting\r\nsystem.";
newStr = oldStr.split(token).join(newToken);
newStr would be
"This is a test of the emergency broadcast system."
I think the real answer is that it completely depends on what your inputs look like. I created a JsFiddle to try a bunch of these and a couple of my own against various inputs. No matter how I look at the results, I see no clear winner.
RegExp wasn't the fastest in any of the test cases, but it wasn't bad either.
Split/Join approach seems fastest for sparse replacements.
This one I wrote seems fastest for small inputs and dense
replacements:
function replaceAllOneCharAtATime(inSource, inToReplace, inReplaceWith) {
var output="";
var firstReplaceCompareCharacter = inToReplace.charAt(0);
var sourceLength = inSource.length;
var replaceLengthMinusOne = inToReplace.length - 1;
for(var i = 0; i < sourceLength; i++){
var currentCharacter = inSource.charAt(i);
var compareIndex = i;
var replaceIndex = 0;
var sourceCompareCharacter = currentCharacter;
var replaceCompareCharacter = firstReplaceCompareCharacter;
while(true){
if(sourceCompareCharacter != replaceCompareCharacter){
output += currentCharacter;
break;
}
if(replaceIndex >= replaceLengthMinusOne) {
i+=replaceLengthMinusOne;
output += inReplaceWith;
//was a match
break;
}
compareIndex++; replaceIndex++;
if(i >= sourceLength){
// not a match
break;
}
sourceCompareCharacter = inSource.charAt(compareIndex)
replaceCompareCharacter = inToReplace.charAt(replaceIndex);
}
replaceCompareCharacter += currentCharacter;
}
return output;
}
What's the fastest I don't know, but I know what's the most readable - that what's shortest and simplest. Even if it's a little bit slower than other solution it's worth to use.
So use:
"string".replace("a", "b");
"string".replace(/abc?/g, "def");
And enjoy good code instead of faster (well... 1/100000 sec. is not a difference) and ugly one. ;)
I just coded a benchmark and tested the first 3 answers.
It seems that for short strings (<500 characters)
the third most voted answer is faster than the second most voted one.
For long strings (add ".repeat(300)" to the test string) the faster is answer 1 followed by the second and the third.
Note:
The above is true for browsers using v8 engine (chrome/chromium etc).
With firefox (SpiderMonkey engine) the results are totally different
Check for yourselves!!
Firefox with the third solution seems to be
more than 4.5 times faster than Chrome with the first solution... crazy :D
function log(data) {
document.getElementById("log").textContent += data + "\n";
}
benchmark = (() => {
time_function = function(ms, f, num) {
var z;
var t = new Date().getTime();
for (z = 0;
((new Date().getTime() - t) < ms); z++) f(num);
return (z / ms)
} // returns how many times the function was run in "ms" milliseconds.
function benchmark() {
function compare(a, b) {
if (a[1] > b[1]) {
return -1;
}
if (a[1] < b[1]) {
return 1;
}
return 0;
}
// functions
function replace1(s) {
s.replace(/foo/g, "bar")
}
String.prototype.replaceAll2 = function(_f, _r){
var o = this.toString();
var r = '';
var s = o;
var b = 0;
var e = -1;
// if(_c){ _f = _f.toLowerCase(); s = o.toLowerCase(); }
while((e=s.indexOf(_f)) > -1)
{
r += o.substring(b, b+e) + _r;
s = s.substring(e+_f.length, s.length);
b += e+_f.length;
}
// Add Leftover
if(s.length>0){ r+=o.substring(o.length-s.length, o.length); }
// Return New String
return r;
};
String.prototype.replaceAll = function(str1, str2, ignore) {
return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, "\\$&"), (ignore ? "gi" : "g")), (typeof(str2) == "string") ? str2.replace(/\$/g, "$$$$") : str2);
}
function replace2(s) {
s.replaceAll("foo", "bar")
}
function replace3(s) {
s.split('foo').join('bar');
}
function replace4(s) {
s.replaceAll2("foo", "bar")
}
funcs = [
[replace1, 0],
[replace2, 0],
[replace3, 0],
[replace4, 0]
];
funcs.forEach((ff) => {
console.log("Benchmarking: " + ff[0].name);
ff[1] = time_function(2500, ff[0], "foOfoobarBaR barbarfoobarf00".repeat(10));
console.log("Score: " + ff[1]);
})
return funcs.sort(compare);
}
return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();
console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
<textarea rows="50" cols="80" style="font-size: 16; resize:none; border: none;" id="log"></textarea>
The test will run for 10s (+2s) as you click the button.
My results (on the same pc):
Chrome/Linux Ubuntu 64:
1. replace1 score: 100% *winner* (766.18)
2. replace4 score: 99.07% speed of winner. (759.11)
3. replace3 score: 68.36% speed of winner. (523.83)
4. replace2 score: 59.35% speed of winner. (454.78)
Firefox/Linux Ubuntu 64
1. replace3 score: 100% *winner* (3480.1)
2. replace1 score: 13.06% speed of winner. (454.83)
3. replace4 score: 9.4% speed of winner. (327.42)
4. replace2 score: 4.81% speed of winner. (167.46)
Nice mess uh?
Took the liberty of adding more test results
Chrome/Windows 10
1. replace1 score: 100% *winner* (742.49)
2. replace4 score: 85.58% speed of winner. (635.44)
3. replace2 score: 54.42% speed of winner. (404.08)
4. replace3 score: 50.06% speed of winner. (371.73)
Firefox/Windows 10
1. replace3 score: 100% *winner* (2645.18)
2. replace1 score: 30.77% speed of winner. (814.18)
3. replace4 score: 22.3% speed of winner. (589.97)
4. replace2 score: 12.51% speed of winner. (331.13)
Edge/Windows 10
1. replace1 score: 100% *winner* (1251.24)
2. replace2 score: 46.63% speed of winner. (583.47)
3. replace3 score: 44.42% speed of winner. (555.92)
4. replace4 score: 20% speed of winner. (250.28)
Chrome on Galaxy Note 4
1. replace4 score: 100% *winner* (99.82)
2. replace1 score: 91.04% speed of winner. (90.88)
3. replace3 score: 70.27% speed of winner. (70.15)
4. replace2 score: 38.25% speed of winner. (38.18)
I tried a number of these suggestions after realizing that an implementation I had written of this probably close to 10 years ago actually didn't work completely (nasty production bug in an long-forgotten system, isn't that always the way?!)... what I noticed is that the ones I tried (I didn't try them all) had the same problem as mine, that is, they wouldn't replace EVERY occurrence, only the first, at least for my test case of getting "test....txt" down to "test.txt" by replacing ".." with "."... maybe I missed so regex situation? But I digress...
So, I rewrote my implementation as follows. It's pretty darned simple, although I suspect not the fastest but I also don't think the difference will matter with modern JS engines, unless you're doing this inside a tight loop of course, but that's always the case for anything...
function replaceSubstring(inSource, inToReplace, inReplaceWith) {
var outString = inSource;
while (true) {
var idx = outString.indexOf(inToReplace);
if (idx == -1) {
break;
}
outString = outString.substring(0, idx) + inReplaceWith +
outString.substring(idx + inToReplace.length);
}
return outString;
}
Hope that helps someone!
// Find, Replace, Case
// i.e "Test to see if this works? (Yes|No)".replaceAll('(Yes|No)', 'Yes!');
// i.e.2 "Test to see if this works? (Yes|No)".replaceAll('(yes|no)', 'Yes!', true);
String.prototype.replaceAll = function(_f, _r, _c){
var o = this.toString();
var r = '';
var s = o;
var b = 0;
var e = -1;
if(_c){ _f = _f.toLowerCase(); s = o.toLowerCase(); }
while((e=s.indexOf(_f)) > -1)
{
r += o.substring(b, b+e) + _r;
s = s.substring(e+_f.length, s.length);
b += e+_f.length;
}
// Add Leftover
if(s.length>0){ r+=o.substring(o.length-s.length, o.length); }
// Return New String
return r;
};
Use the replace() method of the String object.
As mentioned in the selected answer, the /g flag should be used in the regex, in order to replace all instances of the substring in the string.
#Gumbo adding extra answer - user.email.replace(/foo/gi,"bar");
/foo/g - Refers to the all string to replace matching the case sensitive
/foo/gi - Refers to the without case sensitive and replace all For Eg: (Foo, foo, FoO, fOO)
DEMO

Categories

Resources