Cinema Seating With Gaps - javascript

Given and Array
**[0,0,0,1,0,0,1,0,0,0]**
of occupied and unoccupied seats, where 1 indicated occupied and 0 indicated unoccupied, we have return the maximum maximum number of people who can be seated as long as there is a gap of **2 seats **between people.
I trid a sliding window approac but it didnt worked
`
// maxim seats question
// [0,0,0,1,0,0,1,0,0,0]
function cinSeating(array) {
let seats = 0;
for (let p1 = 0, p2 = 3; p1, p2 <= array.length; p1++, p2++) {
if (array[p1] !== array[p2]) {
seats++;
}
}
return seats;
}
console.log(cinSeating([0, 0, 0, 1, 0, 0, 1, 0, 0, 0]));
`

Try using dynamic programming to solve this problem.
Basic approach:
Parse through the array one by one recursively
At every point, check if that seat can be filled in or not. At this point, you can take either one of the two options - YES or NO
If YES - increment the total count and call the same function with the next index and incremented count
If YES - call the same function with the next index and existing count
Find out the max between the two calculations and return the answer
Code will look something like this:
function hasAPerson(array, index){
// Utility function to encapsulate all the checks while checking the next index for possible vacant seat
if(index >= array.length){
return false;
}
else return array[index] === 1;
}
function cinSeating(array, existingNumber, leftIndex, index) {
let newlyAdded = 0;
if(index >= array.length){
return existingNumber;
}
if(array[index] === 1){
return cinSeating(array, existingNumber, index, index + 1);
}
let excludeCurrentSeat = currentValue = cinSeating(array, existingNumber, leftIndex, index + 1);
let includeCurrentSeat = existingNumber;
//Check if last leftIndex with 1 is beyond index-2
if(leftIndex < index-2){
let next = index+1;
let nextToNext = next+1;
//Check if next or next to next index has any 1
if(!hasAPerson(array, next) && !hasAPerson(array, nextToNext)){
includeCurrentSeat = cinSeating(array, existingNumber + 1, index, index+1);
}
}
return Math.max(currentValue, includeCurrentSeat);
}
You can call the cinSeating function with the following arguments:
input array
existing number of people (seats already booked) - basically number of 1s in the array
last left index that had 1. When we start we can pass -3 so that left check gets passed
index to process
console.log(cinSeating([0, 0, 0, 1, 0, 0, 1, 0, 0, 0], 2, -3, 0));
This is something that I wrote quickly to illustrate my approach. This code can definitely be optimised. Feel free to play around with it

Related

Create a function, validateCred() that has a parameter of an array. Scope of variables

I'm learning Javascript on Codecademy and have gotten stumped by a problem. I believe my issue is with the scope of my iterator tracker but not too sure.
Here are the directions given to me:
"Create a function, validateCred() that has a parameter of an array. The purpose of validateCred() is to return true when an array contains digits of a valid credit card number and false when it is invalid. This function should NOT mutate the values of the original array.
To find out if a credit card number is valid or not, use the Luhn algorithm. Generally speaking, an algorithm is a series of steps that solve a problem — the Luhn algorithm is a series of mathematical calculations used to validate certain identification numbers, e.g. credit card numbers. The calculations in the Luhn algorithm can be broken down as the following steps:
Starting from the farthest digit to the right, AKA the check digit, iterate to the left.
As you iterate to the left, every other digit is doubled (the check digit is not doubled). If the number is greater than 9 after doubling, subtract 9 from its value.
Sum up all the digits in the credit card number.
If the sum modulo 10 is 0 (if the sum divided by 10 has a remainder of 0) then the number is valid, otherwise, it’s invalid.
Here’s a visual that outlines the steps. Check your function using both the provided valid and invalid numbers."
Here's an array that should be passed into this function and return true:
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
Here's an array that should return false:
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
Lastly, here's my code for trying to solve this:
function validateCred(arr) {
//Keeps track for the sum modulo later on
let totalSum = 0;
//Iterates to the left
for (let i = arr.length; i > 0; i--) {
//Keeps track of place to later double every other digit
let iterater = 1;
//Checks for every other digit and doubles it
if (iterater % 2 === 0) {
//Doubles it
let doubledAmnt = arr[i] * 2;
//Checks if doubled amount is greater than 9
if (doubledAmnt > 9) {
totalSum += (doubledAmnt - 9);
//Adds the doubled amount if not over 9
} else {
totalSum += doubledAmnt;
}
//Adds the digit if it does not need to be doubled
} else {
totalSum += arr[i];
};
//Adds to place tracker (I think my problem is here?)
iterater++
};
//Checks if the total sum is divisible by 10 to return true or false
if (totalSum % 10 === 0) {
return true;
} else {
return false;
}
}
function validateCred(arr) {
//Keeps track for the sum modulo later on
let totalSum = 0;
let iterater = 1; //iterater should be outside loop so that it wont reset in for loop
//Iterates to the left
for (let i = arr.length-1; i >= 0; i--) { //index starts in 0, so you should minus 1 to read the 16 digits
//Checks for every other digit and doubles it
if (iterater % 2 === 0) {
//Doubles it
let doubledAmnt = arr[i] * 2;
//Checks if doubled amount is greater than 9
if (doubledAmnt > 9) {
totalSum += (doubledAmnt - 9);
//Adds the doubled amount if not over 9
} else {
totalSum += doubledAmnt;
}
//Adds the digit if it does not need to be doubled
} else {
totalSum += arr[i];
};
//Adds to place tracker (I think my problem is here?)
iterater++
};
//Checks if the total sum is divisible by 10 to return true or false
if (totalSum % 10 === 0) {
return true;
} else {
return false;
}
}
Please note that indexes always start in 0 so if you start with 1, you have to minus 1 so that it will read the whole array. Next is, you put the iterater inside the loop, so it resets whenever the loop iterates, so you have to put it outside the loop. Hope this helps.
Please see the code I modified above with comments.

Sort a single dimensional array by the indexes listed in second single demential array - JavaScript

Here is the situation: I need the ability to reorder any single dimensional array so that the new array starts with the center number(if object count is odd) or the center 2 numbers (if object count is even) and iterates low, then high until all numbers in original array are accounted for.
Example 1 - odd number of objects:
Original Array: [1,2,3,5,8,13,20]
New Array: [5,3,8,2,13,1,20]
Example 2 - even number of objects:
Original Array: [1,2,3,4]
New Array: [2,3,1,4]
I have tried this with a for loop and can get it to work hypothetically, but I am not able to use a for loop as a computed property in Vue.js.
Here is my attempt which does not work:
gameInfo: {
cards: [1, 2, 3, 6, 8, 13, 21, 40, 1000],
}
reorderOddCards() {
ATTEMPT 1
const cardCount = this.gameInfo.cards.length;
const middleNumber = (cardCount / 2).toFixed(0);
const newCardOrder = this.gameInfo.cards.map(addToArray);
function addToArray(value, index) {
if (index < middleNumber) {
const newIndex = (((middleNumber - index) * 2) - 1);
newCardOrder.splice(newIndex, 1, value);
} else if (index === middleNumber) {
newCardOrder.splice(index, 1, value);
} else {
const newIndex = ((middleNumber - index) * 2);
newCardOrder.splice(newIndex, 1, value);
}
}
return newCardOrder;
},
Here is a seemingly better approach with a .sort function, but I can't seem to get it working either.
Potential Solution
This can be achieved with a simple while loop. The key here is finding the middle index(es). In an odd length array, there is only one center, which we can think of as having the left and right centers on the same point to generalize the solution. This index will be the result of flooring the length divided by two. The right index will always be this value as well. However, for even length arrays, we need to decrement the left index by one. After computing these indexes, we loop while decrementing the left index and incrementing the right index to add values to our result array.
function order(arr){
let right = Math.floor(arr.length / 2);
let left = right - (arr.length % 2 == 1 ? 0: 1);
let res = left === right ? [arr[left]] : arr.slice(left, right + 1);
while(left > 0){
res.push(arr[--left]);
res.push(arr[++right]);
}
return res;
}
console.log(...order([1,2,3,5,8,13,20]));
console.log(...order([1,2,3,4]));

Count total number of elements in array, that is greater than the previous element in the same array

I am tracking numbers of miles run, for a sequence of long-distance runs. I want to count the number of times progress is made (i.e. the number of times a logged distance exceeded the previously logged distance).
I am convinced that the .every() method will be useful to me here. I need a counter, which increases by one every time it finds an item that was greater than the previous item. It is this last bit of functional logic that I cannot generate myself.
const progressDays = (runs) => {
return runs.reduce(aFunc, 0)
}
const aFunc = (total, num) => {
//the logic I need goes here
}
}
console.log(progressDays([3, 4, 1, 2]))
I would expect the output of the above code to be 2, because on 2 occasions (3->4) and (1->2) progress was made.
Iterate starting at the second element, checking whether it's greater than arr[i - 1]:
const progressDays = (runs) => {
let total = 0;
for (let i = 1; i < runs.length; i++) {
if (runs[i] > runs[i - 1]) {
total++;
}
}
return total;
}
console.log(progressDays([3, 4, 1, 2]))
.reduce doesn't work all that well here, because you don't want to iterate over all the days, only over every gap between array items, essentially.
You oculd reduce the array and take the actual value as well as the previous value from the array by a destructuring with the reduced index. Then count the with the condition.
const
progressDays = runs => runs.reduce(check, 0),
check = (total, num, i, { [i - 1]: prev }) => total + (prev < num);
console.log(progressDays([3, 4, 1, 2]));

Algorithm that involves rounding and multiples

So I have a problem where I have an array of some length (usually long). I have an initial start index into that array and a skip value. So, if I have this:
var initial = 5;
var skip = 10;
Then I'd iterate over my array with indexes 5, 15, 25, 35, etc.
But then I may get a new start value and I need to find the closest value to the initial plus or minus a multiple of the skip and then start my skip. So if my new value is 23 then I'd iterate 25, 35, 45, etc.
The algorithm I have for this is:
index = (round((start - initial) / skip) * skip) + initial
And then I need a check to see if index has dropped below zero:
while(index < 0) index += skip;
So my first question is if there's a name for this? A multiple with random start?
My second question is if there's a better way? I don't think what I have is terribly complicated but if I'm missing something I'd like to know about it.
If it matters I'm using javascript.
Thanks!
Edit
Instead of
while(index < 0) index += skip;
if we assume that both initial and skip are positive you can use:
if (index < 0) index = initial % skip;
To get the closest multiple of a number to a test number: See if the modulo of your test number is greater than number/2 and if so, return number - modulo:
function closestMultiple(multipleTest,number)
{
var modulo = multipleTest%number;
if(0 == modulo )
{
return multipleTest;
}
else
{
var halfNumber = number/2;
if(modulo >= halfNumber)
{
return multipleTest + (number-modulo);
}
else
{
return multipleTest - modulo;
}
}
}
To check if a number is a multiple of another then compare their modulo to 0:
function isMultiple(multipleTest,number)
{
return 0 == multipleTest%number;
}
You might want to add some validations for 0 in case you expect any inside closestMultiple.
The value of index computed as you put it
index = round((start - initial)/skip) * skip + initial
is indeed the one that minimizes the distance between the sequence with general term
aj = j * skip + initial
and start.
Therefore, index can only be negative if start lies to the left of
(a-1 + a0)/2 = initial - skip/2
in other words, if
start < initial - skip/2.
So, only in that case you have to redefine index to 0. In pseudo code:
IF (start < (initial - skip/2))
index = 0
ELSE
index = round((start - initial)/skip) * skip + initial
Alternatively, you could do
index = round((start - initial)/skip) * skip + initial
IF index < 0 THEN index = 0
which is the same.
No while loop required:
function newNum(newstart, initial, skip) {
var xLow = newstart + Math.abs(newstart - initial) % skip;
var xHi = newstart + skip;
var result = (xLow + xHi) / 2 > newstart ? xLow : xHi;
if (result < 0) result += skip;
return result;
}
Take the distance between your new starting point and your initial value, and find out what the remainder would be if you marched towards that initial value (Modulus gives us that). Then you just need to find out if the closest spot is before or after the starting point (I did this be comparing the midpoint of the low and high values to the starting point).
Test:
newNum(1, 20, 7) = 6
newNum(-1, 20, 7) = 6
newNum(180, 10, 3) = 182
(Even though you stated in your comments that the range of the new starting point is within the array bounds, notice that it doesn't really matter).

Pick 4 values in an array with a random starter index

My array looke like :
var arr = [0,1,2,3,4,5];
So I random starter point (index) like :
var start = getRandomInt(0,5);
function getRandomInt (min,max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
For example :
if start is 0, so return 0,1,2,3
if start is 1, so return 1,2,3,4
if start is 2, so return 2,3,4,5
if start is 3, so return 3,4,5,0
if start is 4, so return 4,5,0,1
if start is 5, so return 5,0,1,2
Just random a start index so loop that array
I wonder any easy way to do this ?
Playground : http://jsfiddle.net/2tSdb/
The main issue here is to move from the last index back to 0, which you can do with the modulo operation. You should do something similar to the following:
var data = [0,1,2,3,4,5];
var NUM_VALUES = 4; // Amount of values to take
var start = 3; // Replace with getRandomInt function
var values = [];
for(var i = start, j = 0; j < NUM_VALUES; j++, i = (i+1) % data.length) {
values.push(data[i]);
}
console.log(values); // [ 3, 4, 5, 0 ]
Variable i contains the current index of the Array we are going to access. It is initialized to start like you want. The variable j is only there to make sure we grab the number of values you want, 4 in this case. As you can see, j is incremented by 1 after each loop and we keep going until it is equal to NUM_VALUES. Nothing fancy there.
Variable i is also incremented by 1 (i = i+1), but we apply the modulo operation after that in order to keep the resulting number between 0 and data.length-1. Modulo simply results in the remainder after integer division, so 6 % 4 would be 2, 6 % 6 would be 0, etc. This is done so the index can never be higher than the last index. When i hits 6 here, the modulo would push it back to 0 like we want.

Categories