Number of digits within an interval - javascript

I need to calculate how many times each digit appears within the numeric sequence from 1 to given number.
Example:
Input: 12
Output: 5 2 1 1 1 1 1 1 1 1
Explanation:
1 2 3 4 5 6 7 8 9 1 0 1 1 1 2
The first number is the quantity of ones, the second one – of twos...the last one of zeros
So far, I have written a function that splits any integer into parts (2512 will be 2000 500 10 2). Maybe it can be useful for future executions:
function splitToParts(x) {
var multiplier = 1;
while (x > 0) {
var result = x % 10;
if (result > 0) {
parts.unshift(result * multiplier);
}
x = Math.floor(x / 10);
multiplier *= 10;
}
}

2000, 500 and 10 are just not digits, so for direct counting they are not feasible to work with. A simple approach would be saying that you are always interested in the least significant digit (the "ones"), and "consume" the number as long as it is not 0.
For a single number it would be this simple:
function digits(number){
var retval=[0,0,0,0,0,0,0,0,0,0];
while(number>0){
retval[number%10]++;
number=Math.floor(number/10);
}
return retval;
}
console.log(digits(123).join()); // join just makes it a single line, looks better
Then one may make the statistics updateable via accepting an argument for it. It does not even have to be mandatory, the function can simply create it if it is missing:
function digits(number,stats){
var retval=stats || [0,0,0,0,0,0,0,0,0,0];
while(number>0){
retval[number%10]++;
number=Math.floor(number/10);
}
return retval;
}
var stats=digits(123);
console.log(stats.join());
console.log(digits(234,stats).join());
And make it a loop:
function digits(number,stats){
var retval=stats || [0,0,0,0,0,0,0,0,0,0];
while(number>0){
retval[number%10]++;
number=Math.floor(number/10);
}
return retval;
}
function intervalDigits(min,max){
var stats;
for(var i=min;i<=max;i++)
stats=digits(i,stats);
return stats;
}
console.log(intervalDigits(1,12).join());
That would be a "brute force", but working solution in JavaScript.
Then one can go for maths instead of brute forcing, and start working with the 2000-500-10-2 "decomposition", finding patterns in "contribution" to the statistics for digits at 'ones', 'tens', 'hundreds', and so on. These contributions will not be trivial, so the existing snippets may come useful to check what happens around different "transitions".
function digits(number,stats){
var retval=stats || [0,0,0,0,0,0,0,0,0,0];
while(number>0){
retval[number%10]++;
number=Math.floor(number/10);
}
return retval;
}
function intervalDigits(min,max){
var stats;
for(var i=min;i<=max;i++)
stats=digits(i,stats);
return stats;
}
for(var i=1;i<21;i++)console.log("1-"+i,intervalDigits(1,i).join());
console.log("---");
for(var i=95;i<115;i++)console.log("1-"+i,intervalDigits(1,i).join());
console.log("---");
var x100=intervalDigits(1,100);
var x200=intervalDigits(1,200);
var x300=intervalDigits(1,300);
console.log("1-100",x100.join());
console.log("1-200",x200.join());
console.log("1-300",x300.join());
console.log("---");
console.log("1-100 -> 1-200",x200.map((x,i)=>x-x100[i]).join());
console.log("1-200 -> 1-300",x300.map((x,i)=>x-x200[i]).join());
console.log("1-100 -> 1-300",x300.map((x,i)=>x-x100[i]).join());
Given the range of 1018, you are most likely expected to pursue this track (too), but here and now this 'starter pack' is what I have had time for.

Related

Integer adding problems with JavaScript

We are currently learning JavaScript in our labs and we just created a simple Fibonacci function that calculates first 100 numbers of the Fibonacci sequence.
function fibo(stop) {
let counter = 0;
let first = 1;
let second = 1;
let third = 0;
console.log(third);
console.log(second);
console.log(first);
while (true) {
third = second;
second = first;
first = second + third;
counter++;
if (counter >= stop) {
break;
}
console.log(first);
}
}
fibo(100);
Now when I run it there's a section that just magically adds numbers together wrong.
When I separately add those exact two numbers together in JavaScript, I get the same answer as the third line in the screenshot. However when I redo the adding on a calculator, it shows 14 472 334 024 676 221 instead of 14 472 334 024 676 220. My first guess was that it has something to do with Integer Overflow, but then again log2(14472334024676220) = 53.684... which means that in a 64 bit integer it is not overflowing. Why is it so? Where does it come from? I tried asking my teacher but he had no idea.
When dealing with integers, the maximum safe integer (i.e where n + 1 !== n) is 9007199254740991 which is 2^53 - 1
Javsacript Numbers are 64 bit floating point, that doesn't mean integers
Use BigInts - to initialise a BigInt youse can use the n suffix to a number as below
function fibo(stop) {
let counter = 0;
let first = 1n;
let second = 1n;
let third = 0n;
console.log(third.toString());
console.log(second.toString());
console.log(first.toString());
while (true) {
third = second;
second = first;
first = second + third;
counter++;
if (counter >= stop) {
break;
}
console.log(first.toString());
}
}
fibo(100);
Note: the Stack Snippet console.log fails to log BigInt which is why I put the .toString()

Random Number List Missing Number 1

I have an issue with a function I have written: although it mostly works, there is one issue where sometimes the number 1 isn't added to the list. The code is supposed to make a list of numbers from 1 - 10, however the number 1 is sometimes missing, where I presumably the issue is it is being overwritten when number 10 is already there before number 1
The code is written using the Code.org AppLab, written in a pseudo-code that is similar to JavaScript.
function randomizer(stringName, numbersShuffled) {
//This creates a string of Numbers that will eventually be converted to a list
for (var i = 0; i < numbersShuffled; i++) {
var tempNum = randomNumber(1, numbersShuffled);
console.log(numbersShuffled);
if (stringName.includes(tempNum)) {
console.log(stringName);
if (tempNum == 1 && stringName.includes(10)) {
tempNum = randomNumber(1, numbersShuffled);
}
while ((stringName.includes(tempNum))) {
tempNum = randomNumber(1, numbersShuffled);
}
}
stringName = (stringName + " ") + tempNum;
}
console.log(stringName);
The issue is that usually the number 1 is missing if number 10 is already in place in the list.enter code here

How would I fix my approach to this Manhattan Skyline/Stone Wall and where did I go wrong? Javascript

I just came across this problem and thought I would give it a try, but now I'm stuck and need help if possible.
The problem I keep facing is my return is usually off by 1 or 2 but I can't figure out why not. I have traced my code back but still can't figure it out
The problem :
You are to write a program to assist an architect in drawing the skyline of a city. Building are rectangular in shape, the height of each building is represented by an element in a given array.
The above skyline above is represented like
[1,3,2,1,2,1,5,3,3,4,2]
SO FAR HERE IS WHAT I AM WORKING WITH:
const skyline =(H)=> {
let stack = [];
let count = 0;
let height = 0;
const addBlock = (value) => {
if (value > height) {
stack.push(value - height);
height = value;
count += 1;
}
}
const pop = (value) => {
while (value < height) {
height -= stack.pop();
}
if (value > height) {
addBlock(value)
}
}
for (let i = 0; i < H.length; i += 1) {
let value = H[i];
if (value < height) {
pop(value)
} else if (value > height) {
addBlock(value)
}
}
return count
}
skyline([1,3,2,1,2,1,5,3,3,4,2]) //Expect 9
// Test CASES:
let strokes = [1,3,2,1,2,1,5,3,3,4,2] // Expect 9
// let strokes = [5,8] // Expect 8
// let strokes = [1,1,1,1] // Expect 1
skyline(strokes)
Is this the basic algorithm?
* Big eats small (and equal-sized)
* Small reduces big to small
adding the difference
* Count last one standing
Examples:
[5,8]
-> 8 eats 5, count 8
[1,1,1,1]
-> 1 eats 1 eats 1 eats 1
-> count 1
[1,3,2,1,2,1,5,3,3,4,2]
-> 3 eats 1
-> 2 reduces 3 to 2 and adds 3-2
-> 1 reduces 2 to 1 and adds 2-1
-> 2 eats 1
-> 1 reduces 2 to 1 and adds 2-1
-> 5 eats 1
-> 3 reduces 5 to 3 and adds 5-3
-> 3 eats 3
-> 4 eats 3
-> 2 reduces 4 to 2 and adds 4-2
-> count 2
Total: 1 + 1 + 1 + 2 + 2 + 2 = 9
JavaScript code:
function f(A){
let result = 0;
for (let i=1; i<A.length; i++)
result += Math.max(0, A[i-1] - A[i]);
return result + A[A.length-1];
}
console.log(f([1,3,2,1,2,1,5,3,3,4,2]));
console.log(f([5,8]));
console.log(f([1,1,1,1]));
One liner :)
function f(A){
return [0].concat(A).reduce((a,b,i,A) => a + Math.max(0, A[i-1] - b)) + A[A.length-1];
}
the current answer seems to solve the problem presented, additionally I would like to point that a way to tackle this kind of problems is to solve it by hand and take notes on which steps you took to solve it.
In this case, they ask you to draw horizontal lines without picking up the pencil and one way to do that by hand is to do all the posible strokes on the same row before passing on to the next, until there are no rows left to check.
On every row, you will surely check if the current spot (array element) is greater than 0, which means that it is part of the stroke.
Now in more concise words:
While there are rowsLeft I will traverse the array. on every
traversal I will:
check if the current position is greater than 0 which means there is a
newStroke, it also means there are rowsLeft and since you want to keep
moving forward you would like to decrease the current element by one.
then, if there is a newStroke and the current element is 0 (end of the
stroke) or if it is the end of the array, I would add 1 to my numOfStrokes
count and also state that since I have just finished the stroke then there is
no newStroke at the moment.
Well that's what I did to solve the case you posted, I believe you can code it from there and I hope it helps you, then again, bruce's answer seems to be right, I just wanted to add how you could came up with the solution, there are surely many ways f doing it.
function minimalNumberOfSkylinesIn(array) {
if(array.length == 0)
return 0;
let result = array[0];
for(let i=1; i<array.length; ++i) {
let differnce = array[i] - array[i-1];
result += difference > 0 ? difference : 0;
}
return result;
}

Largest prime factor function works too slow

I have written the function which finds largest prime factor of some number. This function works but the problem is that it is too slow. e.g when I enter 600851475143 as a parameter, the process of finding largest prime factor lasts too long. How can I modify it so that it works faster?
Here is my code:
class test {
static addArray(someArray, member) {
for (var i = 0; i <= someArray.length; i++) {
if (i == someArray.length) {
someArray[i] = member;
return someArray;
}
}
}
static someLength(someArray) {
var i = 0;
while (someArray[i] !== undefined) {
var lastItem = i;
i++;
}
return i;
}
static testPrime(i) {
for (var k=2; k < i; k++) {
if (i % k == 0) {
return false;
}
}
return true;
}
}
var primeArray = [];
function largestPrime(n) {
for (var i=2; i < n; i++) {
//var k = n / i;
if (n % i == 0 && test.testPrime(i) == true) {
test.addArray(primeArray, i);
n == n / i;
}
}
return primeArray[test.someLength(primeArray) - 1];
}
document.write(largestPrime(600851475143));
Alright, before we go into that, let's get a little bit of theory sorted. The way you measure the time a particular piece of code takes to run is, mathematically, denoted by the O(n) notation (big-o notation) where n is the size of the input.
Your test prime function is of something called linear complexity meaning that it'll become linearly slow as the size of n (in this case, your number input) gets large.
For the number 15, the execution context is as follows:
15 % 2 == 0 (FALSE)
15 % 3 == 0 (TRUE)
...
15 % 14 == 0 (FALSE)
This means that for the number 100, there will be 98 (2 - 99) steps. And this will grow with time. Let's take your number into consideration: 600851475143. The program will execute 600851475143; the for-loop will get triggered 600,851,475,141 times.
Now, let's consider a clock cycle. Say each instruction takes 1 clock cycle, and a dumbed down version of your loop takes 2, the number 600851475143 will execute 1,201,702,950,286 times. Consider each clock cycle takes 0.0000000625 seconds (for a 16-MHz platform such as the Arduino), the time taken by that code alone is:
0.0000000625 * 1201702950286 = ~75,106 seconds
Or around 20 hours.
You see where I am going with this.
Your best best to get this program to work faster is to use a probabilistic test and confirm your findings using this number (or a BigInteger variant thereof).
Your approach is more linear, in the sense that the number of iterations for the for-loop to check for primality increases with an increasing number. You can plot the CPU cycle time along with the number and you'll realize that this is a rather inefficient way to do this.
I have discrete mathematics at my Uni, so just a word of warning - primality tests and their variants get really messy as you get into the utopia of faster and faster tests. It's a path filled with thorns of mathematics and you should have a seat belt while riding through the jungle! ;)
If you need more information on this, I would be glad to assist! I hope this helped! :)

Looping over numbers

So this is the question that is given.
You are in a room with a circle of 100 chairs. The chairs are numbered sequentially from 1 to 100.
At some point in time, the person in chair #1 will be asked to leave. The person in chair #2 will be skipped, and the person in chair #3 will be asked to leave. This pattern of skipping one person and asking the next to leave will keep going around the circle until there is one person left, the survivor.
And this is the answer I came up with. I believe this is the right answer, I've done it on paper about 10 times as well and came up with 74 every time.
Is this a trick question or something? Because I'm not sure what to do from here.
Here is the jsfiddle http://jsfiddle.net/cQUaH/
var console = {
log : function(s) {
document.body.innerHTML += s + "<br>";
}
};
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 2;
while(chairArr.length > 1) {
console.log('removing ' + chairArr[j]);
chairArr.splice(j, 1);
j++;
if(j >= chairArr.length) {
console.log('--- Finished pass');
console.log('--- Array state:');
console.log(chairArr);
j = (j == chairArr.length) ? 0 : 1;
}
}
console.log('--- Final result: ' + chairArr);
//result 74
With a minor change in indices, you have the Josephus problem. In the traditional formulation, person 1 kills person 2, 3 kills 4, etc. To convert to that form, kill off person 1, as your problem states, and then renumber people 2-100 by subtracting 1, giving people 1-99.
A good treatment of the Josephus problem, including an account of its origin in the Jewish Revolt of 70-73 CE, is in Concrete Mathematics, 2nd edition, by Graham, Knuth, and Patashnik, Section 1.3. Both Wikipedia and Wolfram MathWorld have articles on the problem, Wikipedia even includes the original description by Josephus in The Jewish War.
The book gives a mildly complicated recursion for the solution, and a simpler algorithm. If the number of people is n, and n = 2^l + m where l is as large as possible, then the answer is 2m+1. So, since 99 = 2^6 + 35, the solution is 2*35 + 1 = 71. But you need to reverse the renumbering, so the real answer is 72.
As far as your programming problem, however, why don't you take as your basic operation Remove the first person in the circle and move the second person to the end. So, with 5 people, [1,2,3,4,5], you remove the first getting [2,3,4,5]and moving the new first element to the end getting [3,4,5,2].
var killAndRotate = function(array) { // say [1,2,3,4,5]
var dead = array.shift(), // dead = 1, array = [2,3,4,5]
skipped = array.shift(); // skipped = 2, array = [3,4,5]
array.push(skipped); // array = [3,4,5,2]
}
And then the main loop becomes:
while (chairArray.length > 1) {
killAndRotate(chairArray);
}
alert(chairArray[0]); // or console.log, or return.
// In turn, array is:
// [1,2,3,4,5]
// [3,4,5,2]
// [5,2,4]
// [4,2]
// [2] and we alert, log, or return 2.
Added
The easy way to find that result for the original Josephus problem is to see that:
If there are 2^l people, then in the first pass all the even-numbered people are killed, so the first person remains alive.
1 2 3 4 5 6 7 8
X X X X
Now there are 2^(l - 1) people. Again, the first person survives:
1 2 3 4 5 6 7 8
X X X X
X X
Repeat the process; the first person survives each pass, and so is the last survivor.
Now, suppose there are m extra people with m < 2^l. Here, l = 3 and m = 5. Kill the first m people to die.
1 2 3 4 5 6 7 8 9 10 11 12 13
X X X X X Y
Now, there are 2^l people left, and person 2 m + 1 = 11 is the first in line. So he survives.
One should also point out that adding a new index variable and splicing can lead to programmer error. Since you only need to remove from the front and add to the back, use the basic methods of arrays.
It seems to me the answer is 72. When you realize that rather than removing numbers you can skip them, the code becomes very short and straight-forward.
var chairArr = [];
for (var i = 1; i <= 100; i++)
chairArr.push(i);
for (i = 1; i < chairArr.length-2; i = i + 2)
chairArr.push(chairArr[i]);
console.log('--- Final result: ' + chairArr[i]);
What have you described here is the Josephus problem, and can be solved using dynamic programming:
function josephus(n, k)
{
if (n == 1) {
return 1;
} else {
return ((josephus(n-1, k) + k - 1) % n) + 1;
}
}
alert(josephus(100, 2));
Source: Wikipedia
The n denotes the number of chairs and k indicates every kth person leaving.
The result here is 73.
Update
Unfortunately, I didn't read the problem properly. The above code solves a slightly different problem; instead of killing off the first person in round one, the second person is killed instead. Being a survivor hinges on details :)
Solving your code problem is rather simple, start with the first person instead of the third in the first round.
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 0;
while (chairArr.length > 1) {
chairArr.splice(j, 1);
j = (j + 1) % n;
}
You don't need an iteration to find the result, there is a formula that can be use to obtain the final chair:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 || (input === 1 ? 0 : input)
}
And for the original Josephus problem, which you kill the even numbers instead, the formula can be simplified:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 + 1
}
The cool thing about the original problem, is that you can work with binary. For example:
100 = 1100100
Take the first '1' and place it to the last:
1001001 = 73

Categories