Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
For sequence = [1, 3, 2, 1], the output should be
almostIncreasingSequence(sequence) === false
There is no one element in this array that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be
almostIncreasingSequence(sequence) === true
As you can remove 3 from the array to get the strictly increasing sequence [1, 2]. Alternately, you can remove 2 to get the strictly increasing sequence [1, 3].
Here is what I have so far:
function almostIncreasingSequence(sequence) {
//compare current int to previous, return true if greater than
//remove int at index and compare with new values, return false if comparison fails
var result = false;
for(var i = 0; i < sequence.length; i++){
var newSequence = sequence.slice();
var subSequence = newSequence.splice(i, 1);
for(var j = 0; j < newSequence.length - 1; j++){
if(newSequence === newSequence.sort((a,b) => a < b).reverse()){
result = true;
}
}
}
return result;
}
I'm trying to figure out how to solve this problem. I feel like I'm very close but for some reason when I call reverse in the conditional statement it also sorts out the newSequence variable. It's sorting two variables in the conditional, not one. As a result it resolves to true. I'm not clear why this is happening. Any feedback is appreciated.
There is no need to use a nested loop, nor to create new arrays. This can be done in O(n) time:
function almostIncreasingSequence(sequence) {
var prev = -Infinity,
beforePrev = -Infinity,
allowExceptions = true;
for (var curr of sequence) {
// Is order not maintained?
if (curr <= prev) {
// Give up when this is not the first exception
if (!allowExceptions) return false;
allowExceptions = false;
// Decide whether to skip the current or previous value
if (curr > beforePrev) prev = curr;
} else { // Normal case: keep track of two preceding values
beforePrev = prev;
prev = curr;
}
}
return true;
}
console.log(almostIncreasingSequence([1,5,3,4,8])); // true
console.log(almostIncreasingSequence([1,5,0,6,8])); // true
console.log(almostIncreasingSequence([1,5,0,4,8])); // false
sort() modifies the array in place, it doesn't return a new array. And you can't compare the contents of two arrays using ==, so that's not a good way to tell if an array is sorted. You can simply loop through the array, testing if each element is greater than the previous one.
function almostIncreasingSequence(sequence) {
for (var i = 0; i < sequence.length; i++) {
var newSequence = sequence.slice();
newSequence.splice(i, 1);
var isSorted = true;
for (j = 1; isSorted && j < newSequence.length; j++) {
if (newSequence[j] <= newSequence[j-1]) {
isSorted = false;
}
}
if (isSorted) {
return true;
}
}
return false;
}
console.log(almostIncreasingSequence([1, 3, 2, 1]));
console.log(almostIncreasingSequence([1, 3, 2]));
console.log(almostIncreasingSequence([1, 2, 3, 4, 5, 3]));
console.log(almostIncreasingSequence([8, 1, 2, 3, 4, 5]));
console.log(almostIncreasingSequence([8, 1, 2, 2, 4, 5]));
Related
I have an array of teams, I am trying to split that array into multiple arrays with having minimum players in each array. I mean, form the array into multiple teams from array. I forgot what this feature is called, but let me tell you with an explanation:
minimum players: 3
team array: [4, 6, 5, 8]
This array will form like this:
[
[4, 6, 5],
[4, 6, 8],
[4, 5, 8],
[6, 5, 8],
[4, 6, 5, 8]
]
So, I have tried doing this problem, but I got stuck that what to do and how to do.
function teams(minPlayers, arr) {
for (let i = 0; i < arr.length; i++) {
const subArray = []
let startMax = minPlayers - 2
let end = minPlayers
for (let j = 0; j < arr.length; j++) {
if (j < startMax) {
subArray[i] = arr[i]
}
}
}
}
console.log(teams(3, [4, 6, 5, 10]))
It will be a pleasure if you help me.
Here is a generator that generates the combinations through recursion. Array.from will consume the iterator:
function teams(minPlayers, arr) {
// Execute a generator, and pass it to Array.from to turn its
// yielded values into an array and return it
return Array.from(function* iter(minPlayers, start) {
// When there are as many remaining elements (from start)
// as we need players, then there are no other options
// than selecting all those values, so yield that slice of
// the array and return (base case)
if (arr.length - minPlayers == start) return yield arr.slice(start);
// Produce the cases where the element at start is not selected.
// Use recursion for this, by reducing the slice that is still available
yield* iter(minPlayers, start + 1);
// Produce the cases where the element at start is selected.
// Use recursion to get the combinations after that, and
// prefix the start element to each of those
for (let combi of iter((minPlayers || 1) - 1, start + 1)) {
yield [arr[start], ...combi];
}
}(minPlayers, 0)); // Immediately execute the generator function
}
console.log(teams(3, [4, 6, 5, 10]));
So the idea of the generator is to either take the current value or not (current is arr[start]). In either case, defer the other selections to recursion. The recursive call will get an increased start value so there are fewer elements to choose from.
This is not exactly permutation quite the opposite since we don't care for order, but we do care for picking n different items.
The recursive function picks works by picking an item (length times) then running picks on the rest - concatenating the results. A care is given not to pick numbers that are "left" to the position of our current item position since we already counted them.
// this loops over minPlayers to maxPlayers (length)
function teams(minPlayers, arr) {
var result = [];
for (var i = minPlayers; i <= arr.length; i++) {
result = result.concat(picks(i, arr))
}
return result;
}
// picks all possible n items from arr (hopefully)
function picks(n, arr) {
// will hold all possible series (pick of n items from array)
var result = [];
if (n == 1) {
// base case return n arrays of 1 item
for (var i = 0; i < arr.length; i++) {
result.push([arr[i]])
}
return result;
}
// else we will loop over each of items
for (var i = 0; i < arr.length; i++) {
// make a copy since we are going to remove items from it
var copy = [...arr];
// pick an item, the first one of our series
var item = copy.splice(i, 1);
// ignore those before it
for (j = 0; j < i; j++) {
// remove an item from beginning of array
copy.shift();
}
// recursion! get picks of the rest n-1 items
var others = picks(n - 1, copy);
// combine each pf those picks with our item
others.forEach(function(other) {
// push to result the series which is [item, ...rest]
result.push(item.concat(other))
})
}
// return array of arrays
return result;
}
console.log(teams(3, [4, 6, 5, 10]))
.as-console-wrapper {
max-height: 100% !important;
}
Last function can be refactored a little since base case looks similar to the other steps and no need to mutate the array. Here's the shorter version:
// loop for each possible minPlayers and above
function teams(minPlayers, arr) {
var result = [];
for (var i = minPlayers; i <= arr.length; i++) {
result = result.concat(picks(i, arr))
}
return result;
}
// recursive function to pick all possible n items from arr
function picks(n, arr) {
var result = [];
for (var i = 0; i < arr.length; i++) {
// foreach item
var item = arr[i];
if (n == 1) {
// if we need pick 1, then pick item
result.push([item])
} else {
// pick n-1 possible except our item (and those before it)
var others = picks(n - 1, arr.slice(i + 1));
// combine with our item n times
others.forEach(function(other) {
result.push([item, ...other])
})
}
}
return result;
}
console.log(teams(3, [4, 6, 5, 10]))
.as-console-wrapper {
max-height: 100% !important;
}
I need to compare the elements of two arrays to know if the first index is greater than the other one and vice versa but my if statement is not working.
function winround(arr, arr2) {
var set = Array.from(new Set(arr))
var set2 = Array.from(new Set(arr2))
var uniqueItems = set.sort(function(a, b) {
return b - a
});
var uniqueItems2 = set2.sort(function(a, b) {
return b - a
});
for (var i in uniqueItems)
if (uniqueItems[0] > uniqueItems2[0])
return "true";
else {
for (var i in uniqueItems2)
if (uniqueItems[0] < uniqueItems2[0])
return "false";
}
}
winround([2, 1, 5, 4, 4, 3, 2, 1], [8, 6, 7]);
You should avoid using for(var i in uniqueItems) . The purpose of the for-in statement is to enumerate over object properties.
Instead of this use:
for (var i = 0; i < uniqueItems.length; i++) {
/* your code here */
}
Inside for loop of else part, you are always comparing the 1st element of 1st array with 1st element of 2nd array.
i.e., uniqueItems[0] < uniqueItems2[0]
It should be: uniqueItems[0] < uniqueItems2[i]
The following should give you the answer in a much simpler way:
function winround(arr, arr2) {
return Math.max(...arr)>Math.max(...arr2);
}
console.log(winround([2,1,5,4,4,3,2,1], [8,6,7]));
I need to find first two numbers and show index like:
var arrWithNumbers = [2,5,5,2,3,5,1,2,4];
so the first repeated number is 2 so the variable firstIndex should have value 0. I must use for loop.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var firstIndex
for (i = numbers[0]; i <= numbers.length; i++) {
firstIndex = numbers[0]
if (numbers[i] == firstIndex) {
console.log(firstIndex);
break;
}
}
You can use Array#indexOf method with the fromIndex argument.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
// iterate upto the element just before the last
for (var i = 0; i < numbers.length - 1; i++) {
// check the index of next element
if (numbers.indexOf(numbers[i], i + 1) > -1) {
// if element present log data and break the loop
console.log("index:", i, "value: ", numbers[i]);
break;
}
}
UPDATE : Use an object to refer the index of element would make it far better.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11],
ref = {};
// iterate over the array
for (var i = 0; i < numbers.length; i++) {
// check value already defined or not
if (numbers[i] in ref) {
// if defined then log data and brek loop
console.log("index:", ref[numbers[i]], "value: ", numbers[i]);
break;
}
// define the reference of the index
ref[numbers[i]] = i;
}
Many good answers.. One might also do this job quite functionally and efficiently as follows;
var arr = [2,5,5,2,3,5,1,2,4],
frei = arr.findIndex((e,i,a) => a.slice(i+1).some(n => e === n)); // first repeating element index
console.log(frei)
If might turn out to be efficient since both .findIndex() and .some() functions will terminate as soon as the conditions are met.
You could use two for loops an check every value against each value. If a duplicate value is found, the iteration stops.
This proposal uses a labeled statement for breaking the outer loop.
var numbers = [1, 3, 6, 7, 5, 7, 6, 6, 4, 9, 10, 2, 11],
i, j;
outer: for (i = 0; i < numbers.length - 1; i++) {
for (j = i + 1; j < numbers.length; j++) {
if (numbers[i] === numbers[j]) {
console.log('found', numbers[i], 'at index', i, 'and', j);
break outer;
}
}
}
Move through each item and find if same item is found on different index, if so, it's duplicate and just save it to duplicate variable and break cycle
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var duplicate = null;
for (var i = 0; i < numbers.length; i++) {
if (numbers.indexOf(numbers[i]) !== i) {
duplicate = numbers[i];
break; // stop cycle
}
}
console.log(duplicate);
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var map = {};
for (var i = 0; i < numbers.length; i++) {
if (map[numbers[i]] !== undefined) {
console.log(map[numbers[i]]);
break;
} else {
map[numbers[i]] = i;
}
}
Okay so let's break this down. What we're doing here is creating a map of numbers to the index at which they first occur. So as we loop through the array of numbers, we check to see if it's in our map of numbers. If it is we've found it and return the value at that key in our map. Otherwise we add the number as a key in our map which points to the index at which it first occurred. The reason we use a map is that it is really fast O(1) so our overall runtime is O(n), which is the fastest you can do this on an unsorted array.
As an alternative, you can use indexOf and lastIndexOf and if values are different, there are multiple repetition and you can break the loop;
function getFirstDuplicate(arr) {
for (var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) !== arr.lastIndexOf(arr[i]))
return arr[i];
}
}
var arrWithNumbers = [2, 5, 5, 2, 3, 5, 1, 2, 4];
console.log(getFirstDuplicate(arrWithNumbers))
var numbers = [1, 3, 6, 7, 5, 7, 6, 6, 4, 9, 10, 2, 11]
console.log(getFirstDuplicate(numbers))
I have the same task and came up with this, pretty basic solution:
var arr = [7,4,2,4,5,1,6,8,9,4];
var firstIndex = 0;
for(var i = 0; i < arr.length; i++){
for( var j = i+1; j < arr.length; j++){
if(arr[i] == arr[j]){
firstIndex = arr[i];
break;
}
}
}
console.log(firstIndex);
First for loop takes the first element from array (number 7), then the other for loop checks all other elements against it, and so on.
Important here is to define j in second loop as i+1, if not, any element would find it's equal number at the same index and firstIndex would get the value of the last one after all loops are done.
To reduce the time complexity in the aforementioned answers you can go with this solution:
function getFirstRecurringNumber(arrayOfNumbers) {
const hashMap = new Map();
for (let number of arrayOfNumbers) { // Time complexity: O(n)
const numberDuplicatesCount = hashMap.get(number);
if (numberDuplicatesCount) {
hashMap.set(number, numberDuplicatesCount + 1);
continue;
}
hashMap.set(number, 1); // Space complexity: O(n)
}
for (let entry of hashMap.entries()) { // Time complexity: O(i)
if (entry[1] > 1) {
return entry[0];
}
}
}
// Time complexity: O(n + i) instead of O(n^2)
// Space complexity: O(n)
Using the code below, I am able to get just the first '5' that appears in the array. the .some() method stops looping through once it finds a match.
let james = [5, 1, 5, 8, 2, 7, 5, 8, 3, 5];
let onlyOneFives = [];
james.some(item => {
//checking for a condition.
if(james.indexOf(item) === 0) {
//if the condition is met, then it pushes the item to a new array and then
//returns true which stop the loop
onlyOneFives.push(item);
return james.indexOf(item) === 0;
}
})
console.log(onlyOneFives)
Create a function that takes an array with numbers, inside it do the following:
First, instantiate an empty object.
Secondly, make a for loop that iterates trough every element of the array and for each one, add them to the empty object and check if the length of the object has changed, if not, well that means that you added a element that already existed so you can return it:
//Return first recurring number of given array, if there isn't return undefined.
const firstRecurringNumberOf = array =>{
objectOfArray = {};
for (let dynamicIndex = 0; dynamicIndex < array.length; dynamicIndex ++) {
const elementsBeforeAdding = (Object.keys(objectOfArray)).length;0
objectOfArray[array[dynamicIndex]] = array[dynamicIndex]
const elementsAfterAdding = (Object.keys(objectOfArray)).length;
if(elementsBeforeAdding == elementsAfterAdding){ //it means that the element already existed in the object, so it didnt was added & length doesnt change.
return array[dynamicIndex];
}
}
return undefined;
}
console.log(firstRecurringNumberOf([1,2,3,4])); //returns undefined
console.log(firstRecurringNumberOf([1,4,3,4,2,3])); //returns 4
const arr = [1,9,5,2,3,0,0];
const copiedArray = [...arr];
const index = arr.findIndex((element,i) => {
copiedArray.splice(0,1);
return copiedArray.includes(element)
})
console.log(index);
var addIndex = [7, 5, 2, 3, 4, 5, 7,6, 2];
var firstmatch = [];
for (var i = 0; i < addIndex.length; i++) {
if ($.inArray(addIndex[i], firstmatch) > -1) {
return false;
}
firstmatch.push(addIndex[i]);
}
I am trying to to write a function to find all missing elements in an array. The series goes from 1...n. the input is an unsorted array and the output is the missing numbers.
below is what I have so far:
function findMissingElements(arr) {
arr = arr.sort();
var missing = [];
if (arr[0] !== 1) {
missing.unshift(1);
}
// Find the missing array items
for (var i = 0; i < arr.length; i++) {
if ((arr[i + 1] - arr[i]) > 1) {
missing.push(arr[i + 1] - 1);
}
}
return missing;
}
var numbers = [1, 3, 4, 5, 7, 8]; // Missing 2,6
var numbers2 = [5, 2, 3]; //missing 1, 4
var numbers3 = [1, 3, 4, 5, 7]; // Missing 2,6
console.log(findMissingElements(numbers)); // returns 2,6 correct
console.log(findMissingElements(numbers2)); // returns 1,4
console.log(findMissingElements(numbers3)); // returns 2, 6
I "manually" checked for the first element with an if block, is there any way to handle the case of the first element inside the for loop?
You can produce that by tracking which number should appear next and adding it to a list of missing numbers while it is less than the next number.
function findMissingElements(arr) {
// Make sure the numbers are in order
arr = arr.slice(0).sort(function(a, b) { return a - b; });
let next = 1; // The next number in the sequence
let missing = [];
for (let i = 0; i < arr.length; i++) {
// While the expected element is less than
// the current element
while (next < arr[i]) {
// Add it to the missing list and
// increment to the next expected number
missing.push(next);
next++;
}
next++;
}
return missing;
}
A not so efficient but more intuitive solution:
var n = Math.max.apply(null, arr); // get the maximum
var result = [];
for (var i=1 ; i<n ; i++) {
if (arr.indexOf(i) < 0) result.push(i)
}
Aside from the fact that your tests are not consistent, this feels a bit neater to me:
function findMissingElements (arr, fromFirstElement) {
arr.sort();
var missing = [];
var next = fromFirstElement ? arr[0] : 1;
while(arr.length) {
var n = arr.shift();
while (n != next) {
missing.push(next++);
}
next++;
}
return missing;
}
var numbers = [1, 3, 4, 5, 7, 8]; // Missing 2,6
var numbers2 = [5, 2, 3]; // Missing 1, 4
var numbers3 = [1, 3, 4, 5, 7]; // Missing 2, 6
console.log(findMissingElements(numbers)); // returns 2, 6
console.log(findMissingElements(numbers2)); // returns 1, 4
console.log(findMissingElements(numbers3)); // returns 2, 6
I've added an argument fromFirstElement which, if passed true, will enable you to start from a number defined by the first element in the array you pass.
Hi I'm struggling to solve this problem. How to create a javascript function that takes any number of arrays as arguments, then returns an array of elements that only appear in one of the arrays. All items that appear in multiple arrays are removed. Getting nowhere with a solution, suspect I'm not approaching it in the right way, stumped!
Edit: the other question addresses eliminating duplicate values in one array, I need to compare x number of separate arrays and return the values that aren't duplicated between arrays. So ([5,6,7],[5,8,9]) returns [6,7,8,9].
function sym(args) {
var ans = [];
for(var i =0;i<arguments.length;i++){
var tempArr = arguments[i].filter(function(el){
var filtTrue = false;
for(var j = 0;j<arguments.length;j++){
if(Array.isArray(arguments[j]) && arguments[j] !== arguments[i]){
if(arguments[j].indexOf(el) === -1){
filtTrue = true;
}}
}
return filtTrue;
});
ans = ans.concat(tempArr);
}
return ans;
}
Here's one way to do it. The idea here is that you create a map for keeping counts of all the items in the array. You then cycle through each array, look up each value in the map and, if found, you increment its count. If not found, you set the count to 1. Then, when done with all the arrays, you collect any items that have a count of 1.
You weren't specific about what to do if an item appears more than once in the same array, but not in any other array. This first solution will not include that item (since it detects duplicates). It could be adapted (with a little more complexity) to allow that item if that was an issue (see 2nd code block below for that implementation).
function sym(/* pass one or more arrays here */) {
var ans = [], cnts = {};
//count all items in the array
for (var i = 0; i < arguments.length; i++){
arguments[i].forEach(function(item) {
if (cnts.hasOwnProperty(item)) {
// increase cnt
++cnts[item].cnt;
} else {
// initalize cnt and value
cnts[item] = {cnt: 1, val: item};
}
});
}
for (var item in cnts) {
if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
ans.push(cnts[item].val);
}
}
return ans;
}
If you want to include items that are present more than once in a single array, but not present in any other array, then you can use this slightly more complicated adaptation:
function sym(/* pass one or more arrays here */) {
var ans = [], cnts = {}, currentMap;
//count all items in the array
for (var i = 0; i < arguments.length; i++){
currentMap = {};
arguments[i].forEach(function(item) {
// if we haven't already counted this item in this array
if (!currentMap.hasOwnProperty(item)) {
if (cnts.hasOwnProperty(item)) {
// increase cnt
++cnts[item].cnt;
} else {
// initalize cnt and value
cnts[item] = {cnt: 1, val: item};
}
}
// keep track of whethere we've already counted this item in this array
currentMap[item] = true;
});
}
// output all items that have a cnt of 1
for (var item in cnts) {
if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
ans.push(cnts[item].val);
}
}
return ans;
}
Working demo: http://jsfiddle.net/jfriend00/bete5k3n/
I know this is increadibly late but this is another way to do it. Maybe not the most rigorous one but certainly creative. The method Array.symmetricDifference() expects any number of arguments and returns the symmetric difference of those arguments.
Array.prototype.symmetricDifference = function() {
var args = [];
// copy arguments into a real array and get rid of duplicates with filter
for(var i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
args[i] = args[i].filter(function(item, pos, self) {
return self.indexOf(item) == pos;
});
}
var diff = args[0];
// iterate through every arguments in args.
// concatenate the first two arguments to form a new set.
// now every number in this new set that was contained in both arguments
// from before will be contained at least twice in this new set.
for(var j = 1; j < args.length; j++) {
//sort the new set so that duplicates are next to each other.
diff = diff.concat(args[j]).sort();
var index = 0;
// now iterate through the new set and delete both duplicates if you
// find any. Otherwise proceed to the next index.
while(index < diff.length) {
// if duplicate is found delete both, otherwise look at next index.
diff[index] === diff[index + 1] ? diff.splice(index, 2) : index++;
}
}
return diff;
};
You can invoke that method on any array or create a new one and invoke it on that one like this for example:
// take any number of arrays
var a = [3, 3, 3, 2, 5];
var b = [2, 1, 5, 7];
var c = [3, 4, 6, 6];
var d = [1, 2, 3];
var e = [5, 3, 9, 8];
var f = [1];
// invoke the method on "solution" with any number of arguments
// and store it in solution.
var solution = solution.symmetricDifference(a,b,c,d,e,f);
console.log(solution); // [1, 2, 4, 5, 6, 7, 8, 9]
I hope this helps!
Finding unique items in multiple arrays
function uniqueItemsInArrays(...args){
let allItems = [];
allItems = allItems.concat(...args)
return allItems.filter(function(item, pos, self) {
return self.indexOf(item) === pos && self.indexOf(item,pos+1) === -1;
});
}
uniqueItemsInArrays( [1, 5, 1, 8, 1, 2],
[2, 2, 9, 3, 5],
[1, 4, 7, 6] );
The above code uses ES6 rest parameters to access all the arrays passed as arguments. Then using the concat() function, I am joining all the individual arrays to a single array. Finally, filter function has been used to identify and return the unique items from this array. The logic here is to find out the first index of the current item and if there are no more occurrence from the first index then we return that item.