Looping over numbers - javascript

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

Related

What does it mean by "second += arr[i][arr.length-i-1]"

I been practicing my algorithm solving skill by solving HackerRank problems. However, one of the problems is giving me a difficult time to understand. It is about calculating absolute difference between sum of diagonals in a square matrix "arr".
If the square matrix is like this:
1 2 3
4 5 6
5 2 4
and the solution is like this:
1st diagonal = 1 + 5 + 4 = 10
2nd diagonal = 3 + 5 + 5 = 13
difference = |10 - 13| = 3 <-- This should appear!
So, I came up with this solution:
function diagonalDifference(arr) {
let first = 0;
let second = 0;
let diff = 0;
for(let i = 0; i < arr.length; i++){
first += arr[i][i];
second += arr[i][arr.length-i-1]
}
diff = first - second;
return Math.abs(diff);
}
However, I figure out all other parts except the "second += arr[i][arr.length-i-1]" part.
I don't understand what [arr.length-i-1] is doing. Help me understand this.
When i starts at 0, arr.length - i - 1 starts at the last index in the array and iterates backwards towards the beginning. So, for example, if there are 4 elements, it'll access index [3], then [2], then [1], then [0].
For this problem, the array of arrays is square. arr[i][arr.length - i - 1] will result in arr[0][2], then arr[1][1], then arr[2][0] - which is the diagonal from the top right to the bottom left (which the problem is asking you to calculate).
If there were 5 subarrays, the indicies iterated over would be arr[0][4], arr[1][3], arr[2][2], arr[3][1], arr[4][0]. And so on.

How to solve CountDistinctSlices codility question

I am trying the "CountDistinctSlices" codility question. I tried my best scored 30% so tried to look up on someone who did it for insights. and basically what I don't get in the answer is the use of the initialized seen array(and M for that matter) and how its being used can someone who get it kindly walk me through this code.
THis is the Answer I found without explanation
function solution(M, A) {
// write your code in JavaScript (Node.js 8.9.4)
let sum = 0;
let front = 0;
let back = 0;
const seen = new Array(M+1).fill(false);
while (front < A.length && back < A.length){
while (front < A.length && seen[A[front]] !== true){
sum += (front-back+1);
seen[A[front]] = true;
front += 1;
}
while (A[back] !== A[front]){
seen[A[back]] = false;
back += 1;
}
seen[A[back]] = false;
back += 1;
}
return Math.min(sum, 1000000000);
}
This is the full question
An integer M and a non-empty array A consisting of N non-negative
integers are given. All integers in array A are less than or equal to
M.
A pair of integers (P, Q), such that 0 ≤ P ≤ Q < N, is called a slice
of array A. The slice consists of the elements A[P], A[P + 1], ...,
A[Q]. A distinct slice is a slice consisting of only unique numbers.
That is, no individual number occurs more than once in the slice.
For example, consider integer M = 6 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 5
A[3] = 5
A[4] = 2
There are exactly nine distinct slices: (0, 0), (0, 1), (0, 2), (1,
1), (1, 2), (2, 2), (3, 3), (3, 4) and (4, 4).
The goal is to calculate the number of distinct slices.
Write a function:
function solution(M, A);
that, given an integer M and a non-empty array A consisting of N
integers, returns the number of distinct slices.
If the number of distinct slices is greater than 1,000,000,000, the
function should return 1,000,000,000.
For example, given integer M = 6 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 5
A[3] = 5
A[4] = 2
the function should return 9, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
M is an integer within the range [0..100,000];
each element of array A is an integer within the range [0..M].
Lets go through the algorithm first:
You first start from the beginning and traverse until you find a duplicate. Now you have a range = [ back - front ]
The code called this range [back, front] where "back" is beginning and "front" is your moving pointer.
How many distinct slices are there in this range? There are slices of size 1, 2, .... front - back + 1, so it is sum = 1 + 2 + 3 + ... [front - back + 1]
Now that you encountered a duplicate what you should do ? To understand lets take the example in the question : [3,4,5,5,2]. Now front reached 5. Now we should bring the back pointer to 5 but also at the same time remove the elements 3, 4, 5 from the set because those may be present after the current front. So back comes to 5 which is currently pointed by front.
Lets take another example [1,2,1] , for this front will reach 1 at the index 2 because that is the first duplicate found. Now where should back come to? It should come to 2 because that will be the position where set won't have any duplicates when you delete the elements in the set while you move the back pointer.
Do this until the front reaches the end of the array.
Your question about seen:
How do you find a duplicate in an array? You could use either a Set or you could use a boolean array. I think the only purpose of M in this question is to specify the maximum value that an element in the array can have. So the code used a boolean array of size M.
If you use the boolean array, once you find an element of value say v you can just say boolean_arr[v] = true that means it was "seen".
Or you could use a set and create a new one when needed without having to clear your whole boolean array everytime you find a duplicate - by letting the JavaScript to handle the garbage collection - something like below ( not fully tested ):
function solution(M, A) {
let sum = 0;
let front = 0;
let back = 0;
let set = new Set();
while (front < A.length) {
while (front < A.length && !set.has(A[front])){
sum += (front-back+1);
set.add(A[front]);
front += 1;
}
while (A[back] != A[front]) {
set.delete(A[back]);
back += 1;
}
set.delete(A[back]);
back += 1;
}
return Math.min(sum, 1000000000);
}

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;
}

21 counting game (like nim game)

I'd like to develop a bot that is able to win the 21 - counting game/NIM - game every time.
Rules: Here are the rules for the game:
In a game players take it in turns to say up to 3 numbers (starting at 1 and working their way up).
Who every say's the number 21 is eliminated.
Strategie: Winning the game ever time is possible if you know the right strategy How to win?
Continuing on, if you say 12 you win
if you say 9, you win,
if you say 6, you win,
if you say 3, you win
So, if you go second, you can guarantee that you will say 3, and win every time.
My question: I'd like to create a bot using javascript that is able to beat the user.
let _ = function(call, int) {
setTimeout(call, int)
}
class game {
constructor() {
this.number = 1;
}
user(val) {
console.log(`Userinput: +${val}`)
for (let i=0; i<val; i++)
console.log(`number: ${this.number++}`)
this.checkWin("bot")
console.log("\n\n\n")
this.bot()
}
bot() {
let val = (this.number === 3) ? 3 : parseInt(Math.random()*2)+1
console.log(`Botinput: +${val}`)
for (let i=0; i<val; i++)
console.log(`number: ${this.number++}`)
this.checkWin("user")
console.log("\n\n\n")
}
checkWin(looser) {
if (this.number >= 21) {
console.log(`${looser} lost the game.`);
}
}
}
let instance = new game()
_(function() {
instance.user(3)
},0)
_(function() {
instance.user(2)
},100)
_(function() {
instance.user(3)
},200)
_(function() {
instance.user(3)
},300)
_(function() {
instance.user(1)
},400)
Note: I did not finished the development but obviously there are some issues. I would really appreciate if somebody is able to help me finding/fixing them.
To solve a nim game we calculate the nimbers:
the losing state has nimber 0
the rest of the nimbers is calculated by looking at all the reachable states and taking the mex (minimal exclusive) which is the smallest missing number in the sequence of 0, 1, 2, 3, ...
nimber(21) = 0
nimber(20) = 1, only 0 can be reached, so 1 is the mex
nimber(19) = 2, 0 and 1 can be reached within one move, so mex is 2
nimber(18) = 3
nimber(17) = 0, because we can reach 1 to 3, so 0 is the smallest missing number
and so on...
It is easy to see, that it is repeating. So we can calculate the nimber like this (n is the current state): 3 - (n + 2) % 4. Or generalized if we can count up to x numbers and the losing number is y: we want to add z to y, so that (y + z) % (x + 1) = x and then the formula is x - (n + z) % (x + 1). We could also say that y % (x + 1) + z = x (to find the smallest non-negative z, the other formula has an infinite amount of solutions for z), so z = x - y % (x + 1).
So if the nimber of a state is not 0, the winning move is the one going to the next losing state with nimber 0. As it turns out the winning move (how many numbers to count) is exactly equal to the nimber.
It is important to note, that 21 denotes the state when 20 was said, 21 itself wasn't said yet.
It gets interesting when we play with several instances, like having cards numbered from 1 to 21 in several stacks where you can draw 1 to 3 of the lowest cards in a stack. The one taking the very last card loses. Here we can just xor the nimbers of all stacks, if it is 0 we are in a losing state, otherwise there is a winning move.

Finding the nth item in a repeating list of fixed items

I have to determine the mathematical formula to calculate a particular repeating position in a series of numbers. The list of numbers repeats ad infinitum and I need to find the number every n numbers in this list. So I want to find the *n*th item in a list of repeating y numbers.
For example, if my list has 7 digits (y=7) and I need every 5th item (n=5), how do I find that item?
The list would be like this (which I've grouped in fives for ease of viewing):
12345 67123 45671 23456 71234 56712 34567
I need to find in the first grouping number 5, then in the second grouping number 3, then 1 from the third group, then 6, then 4, then 2, then 7.
This needs to work for any number for y and n. I usually use a modulus for finding *n*th items, but only when the list keeps increasing in number and not resetting.
I'm trying to do this in Javascript or JQuery as it's a browser based problem, but I'm not very mathematical so I'm struggling to solve it.
Thanks!
Edit: I'm looking for a mathematical solution to this ideally but I'll explain a little more about the problem, but it may just add confusion. I have a list of items in a carousel arrangement. In my example there are 7 unique items (it could be any number), but the list in real terms is actually five times that size (nothing to do with the groups of 5 above) with four sets of duplicates that I create.
To give the illusion of scrolling to infinity, the list position is reset on the 'last' page (there are two pages in this example as items 1-7 span across the 5 item wide viewport). Those groups above represent pages as there are 5 items per page in my example. The duplicates provide the padding necessary to fill in any blank spaces that may occur when moving to the next page of items (page 2 for instance starts with 6 and 7 but then would be empty if it weren't for the duplicated 1,2 and 3). When the page goes past the last page (so if we try to go to page 3) then I reposition them further back in the list to page one, but offset so it looks like they are still going forwards forever.
This is why I can't use an array index and why it would be useful to have a mathematical solution. I realise there are carousels out there that do similar tasks to what I'm trying to achieve, but I have to use the one I've got!
Just loop every 5 characters, like so:
var data = "12345671234567123456712345671234567";
var results = [];
for(var i = 4; i < data.length; i += 5){
results.push(data[i]);
}
//results = [5, 3, 1, 6, 4, 2, 7]
If you want to use a variable x = 5; then your for loop would look like this:
for(var i = x - 1; i < data.length; i += x){...
There is no need to know y
If your input sequence doesn't terminate, then outputting every nth item will eventually produce its own repeating sequence. The period (length) of this repetition will be the lowest common multiple of the period of the input sequence (y) and the step size used for outputting its items (x).
If you want to output only the first repetition, then something like this should do the trick (untested):
var sequence = "1234567";
var x = 5;
var y = sequence.length;
var count = lcm(x, y);
var offset = 4;
var output = [];
for (var i = 0; i < count; i += x)
{
j = (offset + i) % y;
output.push(sequence[j]);
}
You should be able to find an algorithm for computing the LCM of two integers fairly easily.
A purely mathematical definition? Err..
T(n) = T(n-1) + K For all n > 0.
T(1) = K // If user wants the first element in the series, you return the Kth element.
T(0) = 0 // If the user want's a non-existent element, they get 0.
Where K denotes the interval.
n denotes the desired term.
T() denotes the function that generates the list.
Lets assume we want every Kth element.
T(1) = T(0) + K = K
T(2) = T(1) + K = 2K
T(3) = T(2) + K = 3K
T(n) = nk. // This looks like a promising equation. Let's prove it:
So n is any n > 1. The next step in the equation is n+1, so we need to prove that
T(n + 1) = k(n + 1).
So let's have a go.
T(n+1) = T(N+1-1) + K.
T(n+1) = T(n) + K
Assume that T(n) = nk.
T(n+1) = nk + k
T(n+1) = k(n + 1).
And there is your proof, by induction, that T(n) = nk.
That is about as mathematical as you're gonna get on SO.
Nice simple recurrence relation that describes it quite well there.
After your edit I make another solution;)
var n = 5, y = 7;
for (var i = 1; i<=y; i++) {
var offset = ( i*y - (i-1)*n ) % y;
var result = 0;
if (offset === n) {
result = y;
} else {
result = (n - offset) > 0 ? n - offset : offset;
}
console.log(result);
}
[5, 3, 1, 6, 4, 2, 7] in output.
JSFIDDLE: http://jsfiddle.net/mcrLQ/4/
function get(x, A, B) {
var r = (x * A) % B;
return r ? r : B;
}
var A = 5;
var B = 7;
var C = [];
for (var x = 1; x <= B; ++x) {
C.push(get(x, A, B));
}
console.log(C);
Result: [5, 3, 1, 6, 4, 2, 7]
http://jsfiddle.net/xRFTD/
var data = "12345 67123 45671 23456 71234 56712 34567";
var x = 5;
var y = 7;
var results = [];
var i = x - 1; // enumeration in string starts from zero
while ( i <= data.length){
results.push(data[i]);
i = i + x + 1;// +1 for spaces ignoring
}

Categories