condition exponentially less likely per loop pass - javascript

I want to achieve a condition inside a for loop, which will get exponentially less likely to be true after every loop pass.
Here is a simplified version of my current, linear solution: every loop pass it is x+1 less likely that the random number === 0 and thus the probability per run is reduced.
for (let x = 0; x < 10; x++) {
if (getRandomInt(0,x) === 0) {
// do something
}
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
But I don't know how to change the condition so that the probability per loop pass becomes exponential and not linearly smaller as in my solution.
Anyone an idea? Thanks for your time!

Instead of increasing x by adding, increment it by multiplying.
for (let x = 1; x < 128; x *= 2) {
if (getRandomInt(0, x) == 0) {
// do something
}
}

If i understand what you are looking for couldn't you just do following?
for (let x = 0; x < 10; x++) {
if (getRandomInt(0,Math.pow(2, x)) === 0) {
// do something
}
}

Related

averagePair problem using multiple pointers as a solution

I'm trying to solve the following problem :
What I've come up with so far:
function averagePair(arr,tar){
if (arr.length < 2){
return false
}
let x = 0
for (var y = 1; y < arr.length; y++){
if ((arr[x] + arr[y]) / 2 == tar){
return true
}
else {
x++;
}
}
return false
}
I know this solution isn't correct, can someone explain why? It works for some cases but not all
There's a solution with O(1) additional space complexity and O(n) time complexity.
Since an array is sorted, it makes sense to have two indices: one going from begin to end (say y), another from end to begin of an array (say x).
Here's the code:
function averagePair(arr,tar){
// That's now included in for-loop condition
// if (arr.length < 2) {
// return false;
// }
let x = arr.length - 1;
for (var y = 0; y < x; y++) {
// Division may lose precision, so it's better to compare
// arr[x] + arr[y] > 2*tar
// than
// (arr[x] + arr[y]) / 2 > tar
while (y < x && arr[x] + arr[y] > 2*tar) {
x--;
}
if (x != y && arr[x] + arr[y] == 2*tar) {
return true;
}
}
return false;
}
It's kinda two-pointers technique: we'll decrease x until a[x] + a[y] > 2*tar for current loop iteration because we need to find the closest match. At the next for-loop iteration a[y] is greater or equal than the previous one, so it makes no sense to check if a[z] + a[y] == 2*tar for any z > x. We'll do this until indices aren't equal, which means there's no match.
You're only comparing adjacent elements, eg [0] vs [1], and [1] vs [2]. You also need to compare [0] vs [2] and so on. The simplest tweak would be to use a nested loop:
for (let x = 0; x < arr.length; x++) {
for (let y = 0; y < arr.length; y++) {
if (x !== y) {
// test arr[x] against arr[y]
But it'd be more elegant and less computationally complex (O(n) instead of O(n ^ 2)) to use a Set to keep track of what's been found so far:
const nums = new Set();
for (const num of arr) {
if (nums.has(tar - num)) {
return true;
} else {
nums.add(num);
}
}
function averagePair(arr,tar){
const nums = new Set();
for (const num of arr) {
if (nums.has(tar - num)) {
return true;
} else {
nums.add(num);
}
}
return false;
}
console.log(averagePair([-2, 3, 2], 0));
console.log(averagePair([-2, 3, 3], 0));

Fill an array with distanced random integers

I need an array to be filled with random integers
Those integers should be very distinct from each other i.e. must at least be 20 units of separation between each items
This is what i have tried so far :
var all = [];
var i = 0;
randomDiff();
function randomDiff() {
var num1 = randomNumber(10, 290); //chose a first random num in the range...
all[0] = num1; //...put it in first index of array
do // until you have 12 items...
{
var temp = randomNumber(10, 290); //...you pick a temporary num
var j;
for (j = 0; j < all.length; j++) // for each item already in the array
{
if ((temp < all[i] - 10) || (temp > all[i] + 10)) // if the temporary num is different enough from others members...
{
all.push(temp); //then you can store it
i++; //increment until....
console.log(all[i]);
}
}
}
while (i < 11) // ...it is filled with 12 items in array
}
////////////Radom in int range function///////////////////////////////////////
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
but always unsuccessful, including infinite loops...
Have a look on something like this:
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
const LIST_SIZE = 20;
const DISTANCE = 10;
const STOP_AFTER_ATTEMPT = 2000;
const randomList = [];
let attempt = 0;
while(randomList.length < LIST_SIZE && attempt < STOP_AFTER_ATTEMPT) {
const num = randomNumber(10, 290);
const numberExistsWithSmallerDistance = randomList.some(r => Math.abs(r - num) < DISTANCE)
if (!numberExistsWithSmallerDistance) {
randomList.push(num);
}
attempt++;
}
if (randomList.length === LIST_SIZE) {
console.log(randomList);
} else {
console.log("Failed to create array with distnct values after ", attempt, " tries");
}
Here's a solution that will always work, as long as you allow enough room in the range/separation/count you choose. And it's way more efficient than a while loop. It doesn't just keep trying until it gets it right, it actually does the math to make sure it's right the first time.
This comes at the cost of tending to lean towards certain numbers more than others (like from + (i * separation)), so take note of that.
function getSeparatedRadomInts(from, through, separation, count) {
if(through < from) return getSeparatedRadomInts(through, from, separation, count);
if(count == 0) return [];
if(separation == 0) return !!console.log("Please allow enough room in the range/separation/count you choose.");
//pick values from pool of numbers evenly stepped apart by units of separation... adding 1 to from and through if from is 0 so we can divide properly
var smallFrom = Math.ceil((from || 1) / separation);
var smallThrough = Math.floor((through + (from == 0)) / separation);
var picks = randoSequence(smallFrom, smallThrough).slice(-count).sort((a, b) => a - b);
if(picks.length < count) return !!console.log("Please allow enough room in the range/separation/count you choose.");
for (var i = 0; i < picks.length; i++) picks[i] *= separation;
//go through each pick and randomize with any wiggle room between the numbers above/below it... adding 1 to from and through if from is 0
for (var i = 0; i < picks.length; i++) {
var lowerBound = picks[i - 1] + separation || from || 1;
var upperBound = picks[i + 1] - separation || (through + (from == 0));
picks[i] = rando(lowerBound, upperBound);
}
//subtract 1 from all picks in cases where from is 0 to compensate for adding 1 earlier
for (var i = 0; i < picks.length; i++) if(from == 0) picks[i] = picks[i] - 1;
return picks;
}
console.log(getSeparatedRadomInts(10, 290, 20, 12));
<script src="https://randojs.com/1.0.0.js"></script>
To be clear, from is the minimum range value, through is the maximum range value, separation is the minimum each number must be apart from each other (a separation of 20 could result in [10, 30, 50, 70], for example), and count is how many values you want to pick.
I used randojs in this code to simplify the randomness and make it easier to read, so if you want to use this code, just remember to paste this in the head of your HTML document:
<script src="https://randojs.com/1.0.0.js"></script>

Generate Random elements without duplicate

I am trying to make a Random Number Generator.
I made a code and it does work well.
document.querySelector('#btn').addEventListener('click',()=>{
generate(1,45,6)
});
function generate(min, max, count){
const arr = [];
if(min >= max) return;
if(max - min + 1 < count) return;
while (arr.length < count) {
let num = Math.floor(Math.random() * max) + min;
let flag = arr.every((i) => {
return i === num ? false : true;
});
if (flag) {
arr.push(num);
}
}
console.log(arr);
}
<button id="btn">Gen</button>
But my algorithm's time complexity is O(n). (I am not sure, I didn't calculate it strictly)
I hope to reduce the time complexity if I can.
And, I guess my above code can be compacted, but I can't.
Summary What I Want
To reduce the time complexity if it can be
To make it compacted
You can use a Set (which will take care of duplicates) instead of an array and keep checking its size until you have all the numbers you want:
document.querySelector('#btn').addEventListener('click',()=>{
generate(1,45,6)
});
function generate(min, max, count){
const s = new Set();
if(min >= max) return;
if(max - min + 1 < count) return;
while (s.size < count) { // O(1)
let num = Math.floor(Math.random() * max) + min;
s.add(num); // O(1)
}
console.log(Array.from(s));
}
<button id="btn">Gen</button>

JavaScript - Improving algorithm for finding square roots of perfect squares without Math.sqrt

I'm trying to learn algorithms and coding stuff by scratch. I wrote a function that will find square roots of square numbers only, but I need to know how to improve its performance and possibly return square roots of non square numbers
function squareroot(number) {
var number;
for (var i = number; i >= 1; i--) {
if (i * i === number) {
number = i;
break;
}
}
return number;
}
alert(squareroot(64))
Will return 8
Most importantly I need to know how to improve this performance. I don't really care about its limited functionality yet
Here is a small improvement I can suggest. First - start iterating from 0. Second - exit loop when the square of root candidate exceeds the number.
function squareroot(number) {
for (var i = 0; i * i <= number; i++) {
if (i * i === number)
return i;
}
return number; // don't know if you should have this line in case nothing found
}
This algo will work in O(√number) time comparing to initial O(n) which is indeed performance improvement that you asked.
Edit #1
Just even more efficient solution would be to binary search the answer as #Spektre suggested. It is known that x2 is increasing function.
function squareroot(number) {
var lo = 0, hi = number;
while(lo <= hi) {
var mid = Math.floor((lo + hi) / 2);
if(mid * mid > number) hi = mid - 1;
else lo = mid + 1;
}
return hi;
}
This algo has O(log(number)) running time complexity.
The stuff that you try to do is called numerical methods. The most rudimentary/easy numerical method for equation solving (yes, you solve an equation x^2 = a here) is a Newtons method.
All you do is iterate this equation:
In your case f(x) = x^2 - a and therefore f'(x) = 2x.
This will allow you to find a square root of any number with any precision. It is not hard to add a step which approximate the solution to an integer and verifies whether sol^2 == a
function squareRoot(n){
var avg=(a,b)=>(a+b)/2,c=5,b;
for(let i=0;i<20;i++){
b=n/c;
c=avg(b,c);
}
return c;
}
This will return the square root by repeatedly finding the average.
var result1 = squareRoot(25) //5
var result2 = squareRoot(100) //10
var result3 = squareRoot(15) //3.872983346207417
JSFiddle: https://jsfiddle.net/L5bytmoz/12/
Here is the solution using newton's iterative method -
/**
* #param {number} x
* #return {number}
*/
// newstons method
var mySqrt = function(x) {
if(x==0 || x == 1) return x;
let ans, absX = Math.abs(x);
let tolerance = 0.00001;
while(true){
ans = (x+absX/x)/2;
if(Math.abs(x-ans) < tolerance) break;
x = ans;
}
return ans;
};
Separates Newton's method from the function to approximate. Can be used to find other roots.
function newton(f, fPrime, tolerance) {
var x, first;
return function iterate(n) {
if (!first) { x = n; first = 1; }
var fn = f(x);
var deltaX = fn(n) / fPrime(n);
if (deltaX > tolerance) {
return iterate(n - deltaX)
}
first = 0;
return n;
}
}
function f(n) {
return function(x) {
if(n < 0) throw n + ' is outside the domain of sqrt()';
return x*x - n;
};
}
function fPrime(x) {
return 2*x;
}
var sqrt = newton(f, fPrime, .00000001)
console.log(sqrt(2))
console.log(sqrt(9))
console.log(sqrt(64))
Binary search will work best.
let number = 29;
let res = 0;
console.log((square_root_binary(number)));
function square_root_binary(number){
if (number == 0 || number == 1)
return number;
let start = 0;
let end = number;
while(start <= end){
let mid = ( start + end ) / 2;
mid = Math.floor(mid);
if(mid * mid == number){
return mid;
}
if(mid * mid < number){
start = mid + 1;
res = mid;
}
else{
end = mid - 1;
}
}
return res;
}
If you analyze all natural numbers with their squares you might spot a pattern...
Numbers Squares Additives
1 1 3
2 4 5
3 9 7
4 16 9
5 25 11
6 36 13
7 49 15
Look at the first row in the squares column (i.e 1) and add it with the first row in the additives column (ie. 3). You will get four which is in the second row of the squares column.
If you keep repeating this you'll see that this applies to all squares of natural numbers. Now if you look at the additives column, all the numbers below are actually odd.
To find the square root of a perfect square you should keep on subtracting it with consecutive odd numbers (starting from one) until it is zero. The number of times it could be subtracted is the square root of that number.
This is my solution in typescript...
function findSquareRoot(number: number): number {
for (let i = 1, count = 0; true; number -= i, i += 2, count++) {
if (number <= 0) {
return number === 0 ? count : -1; // -1 if number is not a perfect square
}
}
}
Hopefully this has better time complexity :)
I see this solution on Github which is the much better and easiest approach to take a square root of a number without using any external library
function TakingPerfectSquare(Num) {
for (var i = 0; i <= Num; i++) {
var element = i;
if ((element == element) && (element*element == Num)) {
return true;
}
}
return false;
}
console.log(TakingPerfectSquare(25));

Function to determine largest prime factor

I am trying to write a function in JS that returns a number's maximum "prime" factor. For example, if I ran maxPrimeFactor(57), I should return a 19. However, my function only works part of the time. I have written a helper function called isPrime that returns a boolean that indicates whether a given number is prime.
Can anyone spot-check my logic and give me pointers as to where I may be going wrong/how I can improve my algorithm and implementation? Any help is appreciated.
function isPrime(n){
var flag = true;
for (var i = 2; i < n / 2; i++) {
if (n % i == 0) {
flag = false;
return flag;
}
}
return flag;
}
function maxPrimeFactor (n) {
var max = 1;
for (var i = 1; i <= n/2; i++) {
if (n % i == 0 && isPrime(i)) {
max = i;
}
}
return max;
}
1 is not prime, so if you pass 1 to the function it will return 1 as the max prime factor which is incorrect. Perhaps a check returning a value like NaN or undefined may be helpful to prevent invalid values, this depends on if you need to limit the scope of the inputs.
if (n < 2) {
return NaN;
}
You also need to consider the case for when n is prime. A possible way around this more efficiently would be to initialize max to n, and then if max is never set again, the max prime is n.
function maxPrimeFactor (n) {
var max = n;
for (var i = 2; i <= n/2; i++) {
if (n % i == 0 && isPrime(i)) {
max = i;
}
}
return max;
}
Since the algorithm only cares about the greatest prime factor, if you start counting down from n/2, you can further optimize the function to return the first prime factor that is found, otherwise return the number.
As the local var flag in isPrime() isn't making the code more readable or functional I would remove it . (Also, no need to loop to n/2 as no number has a prime greater than it's square root);
function isPrime(n){
for (var i = 2; i < Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
I give U a code written in C++ below:
#include <cstdio>
#include <cmath>
int max(int x, int y)
{
return x > y ? x : y;
}
int maxPrime(int x)
{
int mx = -1;
int curX = x;
/*i * i <= x is correct, because there is only one prime factor larger than
Sqrt(x), it's power must be 1, and actually it is curX after this loop, because
all prime factor less or equal than Sqrt(x) is eliminated.*/
for(int i = 2; i * i <= x; ++i)
{
while(curX % i == 0)
{
/*Here i must be a prime. consider Prime factorization
x = p1^q1 * p2^q2 * p3^q3...(p1<p2<p3...)
the first number that satisfied x % i == 0 must be p1, it's prime!
and p2 > p1 so I can continue to enumerate i, don't need to reset i to 2.
curX = x/(p1^q1 * p2^q2 * ... * pj^qj) and i = p[j+1]
*/
curX /= i, mx = max(i, mx);
}
}
return max(mx, curX);
}
int main()
{
int n;
scanf("%d", &n);
//I suppose n is positive
if(n == 1) //1 is not prime
printf("No solution\n");
else
printf("%d\n", maxPrime(n));
return 0;
}
This code reaches a worst case running time O(Sqrt(n))
And your code is wrong, because when n is a prime, your code cannot get the right answer.
And your code's efficiency is not good.
If you want a faster code, you can learn Pollard Rho or SQUFOF.

Categories

Resources