Finding range in an array - javascript

Lets assume we have an array of those elements (always sorted).
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
Our goal is to find the min-index and max-index of a given value e.g. Lets assume we're searching for the min-index and max-index of the element 3.
We quickly see, that the min-index for 3 is 8 and the max-index is 11.
For the value 1, the min is 0 and the max is 3.
How would you develop a solution for that returns the min and max in JavaScript? I have tried to do this, but I can't figure how to, I always get the wrong answer.

You can try Array.indexOf() and Array.lastIndexOf()
var sortedArr =[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3];
console.log(sortedArr.indexOf(1));
console.log(sortedArr.lastIndexOf(1));

Basically Array.indexOf() and Array.lastIndexOf() will do it but they'll do a linear search (go through whole array with a loop until the element is found) which is obviously done in linear time O(n).
If it is true that your array is always sorted then we can use this property to optimize it and use binary search. It is way faster and will do it in logarithmic time O(log n).
After that we simply check the elements before (and after) the found index and until we find an element which isn't equal to our element.
For finding last occurence:
var i= foundIndex;
while(sortedArr[i] == sortedArr[foundIndex]){
i++;
}
foundIndex = i;
And for first occurence:
var i= foundIndex;
while(sortedArr[i] == sortedArr[foundIndex]){
i--;
}
foundIndex = i;
That's it! This will help a lot with the run time especially if you have big arrays.
You can find binary search implementations everywhere, just use any of them.

Is that what you want?
var myarr = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3];
var minNum = myarr[0];
var maxNum = myarr[1];
var minNumStartINDX, maxNumStartINDX, minNumEndINDX, maxNumEndINDX;
/********************************************/
for (var x = 0; x < myarr.length; ++x) {
if (minNum >= myarr[x]) {
minNum = myarr[x];
minNumEndINDX = x;
}
}
for (var x = 0; x < myarr.length; ++x) {
if (minNum >= myarr[x]) {
minNumStartINDX = x;
break;
}
}
for (var x = 0; x < myarr.length; ++x) {
if (maxNum <= myarr[x]) {
maxNum = myarr[x];
maxNumEndINDX = x;
}
}
for (var x = 0; x < myarr.length; ++x) {
if (maxNum <= myarr[x]) {
maxNumStartINDX = x;
break;
}
}
/********************************************/
console.log(minNum);
console.log(minNumStartINDX + "-" + minNumEndINDX);
console.log(maxNum);
console.log(maxNumStartINDX + "-" + maxNumEndINDX);

var data={1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3};
var value=3;
var min=data.length;
var max=0;
for(var key in data){
if(data[key]==value){
if(key<min){
min=key;
}
if(key > max){
max=key;
}
}
console.log(min);
console.log(max);

Related

How to randomize an array, leaving the items that are the same far from each other?

Basically I have an array where there are similar items close by, but I would like to find a way where I leave these items that are the same apart from each other ex:
var array = [1,2,3,3,4];
var myWishArray = [1,2,3,4,3];
||
var myWishArray = [3,2,3,4,1];
||
var myWishArray = [3,2,3,1,4];
...
If it's enough that two equal numbers are never neighbors, then you can
sort the list
fill a new array with these numbers in two passes, leaving a space of one
a = [1, 1, 1, 1, 2, 3, 2, 3, 4, 4, 4];
a.sort();
b = Array(a.length);
for (i = 0; i < a.length; i ++) {
if (i * 2 < a.length) {
b[i * 2] = a[i];
} else {
start = i - Math.ceil(a.length / 2)
b[start * 2 + 1] = a[i];
}
}
console.log(b);

Resetting index in a for loop

This function needs to find the first occurrence of consecutive numbers whose sum equals 10, and return them as an array. My idea was to keep summing the numbers until the accumulator, in this case x becomes greater than 10, at which point the value of x is reset to zero, and i is reset back to index 1, by being assigned to the ct variable that is supposed to grow by one on each reset, so the loop would go back and start at the next element, until it gets the correct value. But for some reason ct is stuck at 1 and doesn't grow and the loop doesn't move past the second array element at index 1. Is there an error in the logic or the implementation?
Warning: This code may cause the page to crash or become unresponsive
const arr = [2, 3, 1, 2, 7, 2, 5, 4, 5, 1, 2, 1];
function test(arr) {
let x = 0;
for (let i = 0; i < arr.length; i++) {
let ct = 0;
x = x + arr[i]
if (x > 10) {
x = 0;
i = ct;
ct++
}
console.log(x)
}
}
console.log(test(arr))
The problem is that you've defined ct in the wrong place. It's inside the loop, meaning that every time you get to a point where i = ct, i is reset to 0 and ct++ has no effect (because every iteration, ct is reset to 0). You need to define ct in the same scope as x:
const arr = [2, 3, 1, 2, 7, 2, 5, 4, 5, 1, 2, 1];
function test(arr) {
let x = 0;
let ct = 0;
for (let i = 0; i < arr.length; i++) {
x = x + arr[i];
if (x > 10) {
x = 0;
i = ct;
ct++;
}
console.log(x);
}
}
test(arr);
I've also filled in the rest of the logic of the function for you in case you'd like it:
const arr = [2, 3, 1, 2, 7, 2, 5, 4, 5, 1, 2, 1];
function test(arr) {
let x = 0;
let ct = 0;
let result = [];
for (let i = 0; i < arr.length; i++) {
x = x + arr[i];
if (x > 10) {
x = 0;
i = ct;
ct++;
}
if (x == 10) {
result = arr.slice(ct, i + 1);
return result;
}
console.log(x);
}
return result;
}
console.log(test(arr));

Find int that appears an odd number of times in an array

I am working on this task where I need to find a number that happens to appear an odd number of times in an array.
I believe I've almost done it, but if some number appears more than once in a row (like 1 in [1,1,3,1,1]), it will always return that number, no matter if it appears an odd number of times or not.
function findOdd(A) {
var a;
var count = 0;
for (var i = 0; i < A.length; i++) {
a = A[i];
for (var l = i + 1; l < A.length; l++) {
if (a == A[l]) {
count++;
}
}
if (!(count % 2)) {
break;
} else {
count = 0;
}
}
return a;
}
console.log(findOdd([ 1, 1, 2, -2, 5, 2, 4, 4, -1, -2, 5 ]));
I've tried to play with adding 1 to count if [i] = [i+1], but it didn't work.
I'd expect output of findOdd([1, 1, 2, -2, 5, 2, 4, 4, -1, -2, 5]) to be -1, but it is 1. The function always returns first number that happens to be equal to next element of an array.
There's no need to reset count or use a break.
function findOdd(A) {
for (var i = 0; i < A.length; i++){
var count = 0;
for (var l = 0; l < A.length; l++) {
if (A[i] === A[l]) count++;
}
if (count % 2 !== 0) return A[i];
}
}
An important thing to note is that the inner loop is not starting at i+1, its starting at the 0. When A[i] matches A[l], we increment count. A number that appears an odd number of times will result in count becoming odd as well and we can return that number.
The following works but I wonder how the performance compares to simply doing for loops. The complexity seems to be the same.
function findOdd(a) {
let m = {};
a.forEach(e => (m[e] in m) ? m[e] += 1 : m[e] = 1);
for (k in m) {
if (m[k] % 2 != 0) return k;
}
}
console.log(findOdd([1, 1, 3, 1, 1]));
console.log(findOdd([1, 1, 2, -2, 5, 2, 4, 4, -1, -2, 5]));
You could count all values first and then get the value with an odd count.
function getOddCount(array) {
var value,
count = {},
k;
for (value of array) count[value] = (count[value] || 0) + 1;
for (k in count) if (count[k] % 2) return +k;
}
console.log(getOddCount([1, 1, 3, 1, 1]));
console.log(getOddCount([1, 1, 2, -2, 5, 2, 4, 4, -1, -2, 5]));
A naive implementation would simply use an object to store the frequency of each element and then iterate over it at the end to find the element that appeared an odd amount of times.
function findOdd(arr) {
const freq = {};
for(const num of arr){
freq[num] = (freq[num] || 0) + 1;
}
return +Object.keys(freq).find(num => freq[num] % 2 == 1);
}
A more efficient implementation could leverage the properties of the bitwise XOR (^), namely the fact that a ^ a == 0 and that the operation is commutative and associative, leading to the solution of applying XOR on each element of the array to obtain the answer.
function findOdd(arr) {
return arr.reduce((a,c)=>a ^ c, 0);
}

Need help in finalizing this Best Fit Algorithm

Excuse me, quick question:
I am using the below routine to find all Combinations of integers that their sum is equal or less than some integer K.
Imagine I have a glass with volume K, and some beer bottles. I am trying to know which bottles I can pick, and get as much beer as possible!
let K = 4; // my glass
let Input = [1, 2, 0.5, 1.5, 2, 0.75, 3, 4]; // beer bottles
let allCombinations = [];
for(var i = 0; i < Input.length; i++)
{
let currentCombination = [];
if(Input[i] <= K)
currentCombination.push(Input[i]);
let difference = K - Input[i];
for(var j = i + 1; j < Input.length; j++)
{
if(Input[j] <= difference)
{
currentCombination.push(Input[j]);
difference -= Input[j];
}
}
allCombinations.push(currentCombination);
}
Input:
K = 4
[1, 2, 0.5, 1.5, 2, 0.75, 3, 4]
Current Output:
[1, 2, 0.5]
[2, 0.5, 1.5]
[0.5, 1.5, 2]
[1.5, 2]
[2, 0.75]
[0.75, 3]
[3]
[4]
But I want more beer choices! Some combinations are not included:
Expected Output:
All the above, plus:
[1, 2, 1.5]
[1, 2, 0.75]
[2, 0.5, 0.75]
[2, 2]
[1, 3]
etc ..
My guess is that this is suboptimal, but you could use a recursive algorithm that produces all possible permutations, checks each one to determine if it's a unique combination, and adds unique solutions to a solution list:
combinations = [];
function getCombinationsLessThan(currentCombination, choices, remainingSum) {
// Check if currentCombination should be added to the solutions list
if (remainingSum < 0) {
return // Sum is too large; terminate recursion
} else if (currentCombination.length > 0) {
currentCombination.sort(); // Sort all combinations so comparison can be made sequentially
var uniquePermutation = true;
for (var i=0; i<combinations.length; i++) {
if (currentCombination.length == combinations[i].length) {
for (var j=0; currentCombination[j]==combinations[i][j] && j<combinations[i].length; j++); // Pass
if (j == currentCombination.length) {
// For loop got all the way through combinations[i], so currentCombination = combinations[i]
uniquePermutation = false;
break;
}
}
}
if (uniquePermutation) {
combinations.push(currentCombination);
}
}
for (var i=0; i<choices.length; i++) {
// Copy choices
var newChoices = choices.slice();
// Cut out the i'th element and add to the current combination
var newCombination = currentCombination.concat(newChoices.splice(i,1));
var newRemainingSum = remainingSum - choices[i];
getCombinationsLessThan(newCombination, newChoices, newRemainingSum);
}
}
var k = 4;
var choices = [1, 2, 0.5, 1.5, 2, 0.75, 3, 4];
getCombinationsLessThan([], choices, k);
var result = '';
for (var i=0; i<combinations.length; i++) {
result += combinations[i] + '\n';
}
console.log(result);
This produces the following result:
1
1,2
0.5,1,2
0.75,1,2
0.5,1
0.5,1,1.5
0.5,0.75,1,1.5
0.5,0.75,1
1,1.5
0.75,1,1.5
0.75,1
1,3
2
0.5,2
0.5,1.5,2
0.5,0.75,2
1.5,2
2,2
0.75,2
0.5
0.5,1.5
0.5,0.75,1.5
0.5,0.75
0.5,3
1.5
0.75,1.5
0.75
0.75,3
3
4
I agree. This does sound like the knapsack problem: determine if excluding or including an item in the knapsack results in a higher value that does not exceed the capacity of the container.

Javascript: How to find first duplicate value and return its index?

I have to find first duplicate value in array and then return its index in variable firstIndex. This has to be done with for loop which should stop after having found first duplicate. I know this is probably pretty simple but I got stuck. So far I have this but it doesn't seem to be working:
var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
for (var a = 0; a < numbers4.length; a++) {
for (var b = a+1; b < numbers4.length; b++) {
if (numbers4[a] === numbers4[b])
firstIndex = numbers4.indexOf(numbers4[a]);
break;
}
}
console.log(firstIndex);
Console prints out 1 which is fine because 2 is first duplicate, but when I change numbers in array, the loop doesn't work. Can you advise what can be changed here?
Thanks in advance!
If I correctly understand your question, that's should help you...
Basically, you need for a double iteration.
const firstDupeIndex = list => list.findIndex(
(item, index) => list.lastIndexOf(item) !== index
);
console.log(
"First Dupe at index:",
firstDupeIndex([5, 2, 3, 4, 4, 6, 7, 1, 2, 3])
);
Thee above implementation comes with the drawback of being O(n2), due to nesting the lastIndexOf within the findIndex function.
A better solution would be to index your occurrences by building a dictionary, therefore keeping time complexity to just O(n) in the worst case. Probably a little bit less neat, but surely more efficient with big inputs.
const firstDupeIndex = (list) => {
const dict = {};
for (const [index, value] of list.entries()) {
if (dict.hasOwnProperty(value)) {
return dict[value];
}
dict[value] = index;
}
return -1;
};
console.log(
"First Dupe at index:",
firstDupeIndex(['a', 'b', 'c', 'd', 'e', 'b', 'z', 't', 'c'])
);
Change your code with the following
var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
var isMatch=false;
for (var a = 0; a < numbers4.length; a++) {
for (var b = a+1; b < numbers4.length; b++) {
if (numbers4[a] === numbers4[b]){
firstIndex = numbers4.indexOf(numbers4[a]);
isMatch=true;
break;
}
}
if (isMatch) {break;}
}
console.log(firstIndex);
I would use an object remembering the values already found... Something like that should work ;)
var numbers4 = [5, 2, 3, 4, 4, 6, 7, 1, 2, 3];
function findFirstDuplicateIndex(arr){
var found = {};
for (var a = 0, aa = arr.length; a < aa ; a++) {
if (found[arr[a]])
return found[arr[a]];
found[numbers4[a]] = a
}
}
console.log(findFirstDuplicateIndex(numbers4));
It's quite fast because you just loop one time through the array. The rest of the time you just access an object property or you set the object property... Let me know if you have questions ;)
However maybe there something faster... It's just an idea ^^
PS: It also works with words, not just numbers
Your break; terminates b loop, because if() is not using parenthesis {}.
Additionally, firstIndex should be simply set to either a or b depending on whether you need to return the duplicate's first occurance or first repetition.
It should be:
if (numbers4[a] === numbers4[b])
{
firstIndex = a;
break;
}
Your problem is - you have two loops and only one break, you need to break out of both.
Why not simply return the index as soon as values match?
var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
function getDuplicate(numbers4)
{
for (var a = 0; a < numbers4.length; a++) {
for (var b = a+1; b < numbers4.length; b++) {
if (numbers4[a] === numbers4[b]){
return a;
}
}
}
}
console.log(getDuplicate(numbers4 ));
However, you can optimize your code further by keeping a map
function getDuplicate( numbers )
{
var map = {};
for (var a = 0; a < numbers.length; a++)
{
if( map[ numbers[ a ] ] )
{
return a;
}
map[ numbers[ a ] ] = true;
}
return -1;
}
You can check if indexOf() is not equal to lastIndexOf() and return value and break loop
var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
for (var i = 0; i < numbers4.length; i++) {
if (numbers4.indexOf(numbers4[i]) != numbers4.lastIndexOf(numbers4[i])) {
firstIndex = i;
break;
}
}
console.log(firstIndex)
You don't even need nested for loops.
var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
for (var a = 1; a < numbers4.length; a++) { //start from second elem since first is never a duplicate
if (numbers4.lastIndexOf(numbers4[a])> a) {
firstIndex = a;
break;
}
}
console.log(firstIndex); //1
All you have to do during iterating is to check if current value exists somewhere further in array. That is done by checking last index of this value's occurrence using lastIndexOf().
var numbers = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex;
var len = numbers.length;
for (var i = 0; i < len; i++) {
var tmpArray = numbers.slice(i + 1, len);
var index = tmpArray.indexOf(numbers[i]);
if (index !== -1) {
firstIndex = index + i + 1;
break;
}
}
console.log(firstIndex);
Update:
Actually your logic is right, but you missed braces for if condition and also if the condition satisfies then it means firstIndex is the same as a
This is your code with braces,
var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3];
var firstIndex = "";
for (var a = 0; a < numbers4.length; a++) {
for (var b = a + 1; b < numbers4.length; b++) {
if (numbers4[a] === numbers4[b]) {
firstIndex = a
break;
}
}
}
console.log(firstIndex);
The question states the first dupe in the array has to be found along with it's index. So I return an object where the i property is the index and the e property is the first duplicate element itself. One way of performing this task would be
var numbers4 = [5, 2, 3, 4, 2, 6, 7, 1, 2, 3],
headDupe = (a,r={}) => (r.e = a.find((n,i) => (r.i = a.indexOf(n), r.i < i)),r);
console.log(headDupe(numbers4));

Categories

Resources