Longest repeated odd number - javascript

Consider:
let N = 12
let arr = [1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1]
Your task is to find the maximum number of times an odd number is continuously repeated in the array.
What is the approach for this?
This is the hint:
1 is repeated 4 times from index 0 to index 3 → 4 times
2 is repeated 5 times from index 4 to index 8 → 5 times
1 is repeated 3 times from index 9 to index 11 → 3 times
The odd numbers in array are 1s.
1 occurs 4 times and 3 times continuously, so 4 is the maximum number of times an odd number is continuously repeated in this array.
function longestRepeatedOdd(N, array) {
// Write code here
let count = 0;
for (let i = 0; i <= array.length-1; i++){
if (array[i] % 2 !== 0){
count++
}else if (array[i] % 2 === 0){
break;
}
}
console.log(count)
}

You can use Array.reduce() to keep track of the current run of odd numbers and the maximum.
We use an accumulator value with a max and current field, the current field the current run of odd numbers and the max field is the longest run.
If the current run exceeds the max we set the max to this value.
function longestRepeatedOdd(arr) {
return arr.reduce((acc, n, idx) => {
acc.current = (n === arr[idx - 1] ? acc.current: 0) + (n % 2);
acc.max = (acc.current > acc.max) ? acc.current: acc.max;
return acc;
}, { max: 0, current: 0 }).max;
}
const inputs = [
[1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1],
[7, 7, 4, 4, 1, 1, 1, 1, 1, 1, 4, 3],
[1, 2, 2, 2]
]
inputs.forEach((input, idx) => {
console.log(`Test input #${idx + 1} result:`, longestRepeatedOdd(input))
})

Your answer is definitely valid. Just replace break with continue.
function longestRepeatedOdd(N, array) {
//write code here
let count = 0;
for (let i = 0; i <= array.length-1; i++){
if (array[i] % 2 !== 0){
count++
}else if (array[i] % 2 === 0){
continue;
}
}
return count
}

Try reduce and creating a JavaScript object that reports its value:
const count = arr.reduce((accumulator, value) => {
return {...accumulator, [value]: (accumulator[value] || 0) + 1};
}, {});
Object { 1: 7, 2: 5 }
console.log(count);
Number one repeated 7 times and number two 5 times.

Related

Sum of similar value in n X n dimensional array with n^2 complexity

Given an array [[1, 7, 3, 8],[3, 2, 9, 4],[4, 3, 2, 1]],
how can I find the sum of its repeating elements? (In this case, the sum would be 10.)
Repeated values are - 1 two times, 3 three times, 2 two times, and 4 two times
So, 1 + 3 + 2 + 4 = 10
Need to solve this problem in the minimum time
There are multiple ways to solve this but time complexity is a major issue.
I try this with the recursion function
How can I optimize more
`
var uniqueArray = []
var sumArray = []
var sum = 0
function sumOfUniqueValue (num){
for(let i in num){
if(Array.isArray(num[i])){
sumOfUniqueValue(num[i])
}
else{
// if the first time any value will be there then push in a unique array
if(!uniqueArray.includes(num[i])){
uniqueArray.push(num[i])
}
// if the value repeats then check else condition
else{
// we will check that it is already added in sum or not
// so for record we will push the added value in sumArray so that it will added in sum only single time in case of the value repeat more then 2 times
if(!sumArray.includes(num[i])){
sumArray.push(num[i])
sum+=Number(num[i])
}
}
}
}
}
sumOfUniqueValue([[1, 7, 3, 8],[1, 2, 9, 4],[4, 3, 2, 7]])
console.log("Sum =",sum)
`
That's a real problem, I am just curious to solve this problem so that I can implement it in my project.
If you guys please mention the time it will take to complete in ms or ns then that would be really helpful, also how the solution will perform on big data set.
Thanks
I would probably use a hash table instead of an array search with .includes(x) instead...
And it's also possible to use a classical for loop instead of recursive to reduce call stack.
function sumOfUniqueValue2 (matrix) {
const matrixes = [matrix]
let sum = 0
let hashTable = {}
for (let i = 0; i < matrixes.length; i++) {
let matrix = matrixes[i]
for (let j = 0; j < matrix.length; j++) {
let x = matrix[j]
if (Array.isArray(x)) {
matrixes.push(x)
} else {
if (hashTable[x]) continue;
if (hashTable[x] === undefined) {
hashTable[x] = false;
continue;
}
hashTable[x] = true;
sum += x;
}
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
This is probably the fastest way...
But if i could choose a more cleaner solution that is easier to understand then i would have used flat + sort first, chances are that the built in javascript engine can optimize this routes instead of running in the javascript main thread.
function sumOfUniqueValue (matrix) {
const numbers = matrix.flat(Infinity).sort()
const len = numbers.length
let sum = 0
for (let i = 1; i < len; i++) {
if (numbers[i] === numbers[i - 1]) {
sum += numbers[i]
for (i++; i < len && numbers[i] === numbers[i - 1]; i++);
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
You could use an objkect for keeping trak of seen values, like
seen[value] = undefined // value is not seen before
seen[value] = false // value is not counted/seen once
seen[value] = true // value is counted/seen more than once
For getting a value, you could take two nested loops and visit every value.
Finally return sum.
const
sumOfUniqueValue = (values, seen = {}) => {
let sum = 0;
for (const value of values) {
if (Array.isArray(value)) {
sum += sumOfUniqueValue(value, seen);
continue;
}
if (seen[value]) continue;
if (seen[value] === undefined) {
seen[value] = false;
continue;
}
seen[value] = true;
sum += value;
}
return sum;
},
sum = sumOfUniqueValue([[1, 7, 3, 8], [3, 2, 9, 4], [4, 3, 2, 1]]);
console.log(sum);
Alternatively take a filter and sum the values. (it could be more performat with omitting same calls.)
const
data = [[1, 7, 3, 8], [3, 2, 9, 4, 2], [4, 3, 2, 1]],
sum = data
.flat(Infinity)
.filter((v, i, a) => a.indexOf(v) !== a.lastIndexOf(v) && i === a.indexOf(v))
.reduce((a, b) => a + b, 0);
console.log(sum);
You can flatten the array, filter-out single-instance values, and sum the result:
const data = [
[ 1, 7, 3, 8 ],
[ 3, 2, 9, 4 ],
[ 4, 3, 2, 1 ]
];
const numbers = new Set( data.flat(Infinity).filter(
(value, index, arr) => arr.lastIndexOf(value) != index)
);
const sum = [ ...numbers ].reduce((a, b) => a + b, 0);
Another approach could be the check the first and last index of the number in a flattened array, deciding whether or not it ought to be added to the overall sum:
let sum = 0;
const numbers = data.flat(Infinity);
for ( let i = 0; i < numbers.length; i++ ) {
const first = numbers.indexOf( numbers[ i ] );
const last = numbers.lastIndexOf( numbers[ i ] );
if ( i == first && i != last ) {
sum = sum + numbers[ i ];
}
}
// Sum of numbers in set
console.log( sum );

Factorial push to array

I'm making a factorial. How do I push specific number to an array? For example if we factor a 14 then the result will be 1, 2, 7, 14 then I only want to push 2 and 7 to the array. Another example is if we factor 18, then the values that I want to push is only 2, 3, 6, 9. I want to exclude the 1 * 14 or 1 * 18. How can I do that?
const isNFactored = function(value, number) {
let i;
let array = [];
for(i = 1; i <= value; i++) {
if(value % i === 0) {
array.push(i);
}
}
console.log(array);
}

Group numbers in array where the sum is closest to X

I have a group of numbers:
const numbers = [ 4, 6, 2, 1, 5, 3, 6, 11 ]
And I would like to return these numbers in groups where the sum is closest to x. For example if x was 13, the expected output would be:
// console.log(result)
[ 2, 11 ] // sum is 13
[ 3, 4, 5 ] // sum is 12
[ 1, 6, 6 ] // sum is 13
All numbers must be used. "Closest" being below the number (not above 13), so the above example would be acceptable but if the sum was 14 it would not be. This should find the best results (closest to 13) and remove each number from the pool of options in the array when it has been grouped.
How would I approach this?
How about something like this?
const x = 13;
const result = [];
let numbers = [4, 6, 2, 1, 5, 3, 6, 11];
let i = numbers.length;
while (--i > -1) {
const length = result.length;
let target = x - numbers[i];
let a = numbers.length - 1;
while (target > 0) {
if (numbers[--a] !== target) {
if (a === -1) {
a = numbers.length - 1;
target--;
}
continue;
}
result[length] ??= [];
result[length].push(numbers[a]);
target = x - numbers[i];
for (const entry of result[length]) {
target -= entry;
}
numbers = [...numbers.slice(0, a), ...numbers.slice(a + 1)];
a = numbers.length - 1;
}
if (!result[length]) {
continue;
}
result[length].push(numbers[numbers.length - 1]);
numbers = numbers.slice(0, -1);
i = numbers.length;
}
console.log(result);
It's kinda crude though.

Optimize a function to iterate less into arrays

As a part of a CodeSignal challange i'm asked to :
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
function(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 function(sequence) =
true. 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].
Guaranteed constraints:
2 ≤ sequence.length ≤ 105 &
-105 ≤ sequence[i] ≤ 105.
My code works but i'm looking for a more performant solution because the challenge has fixed the execution time limit of 4 seconds.
Here's my code:
const almostIncreasingSequence = seq => {
let i = 0;
while (i < seq.length) {
const filtred = [...seq];
// splice 1 element at index i from array
filtred.splice(i, 1);
// create a `sorted` array with only unique numbers and sort it
const sorted = [...new Set([...filtred].sort((a, b) => a - b))];
if (filtred.join("") === sorted.join("")) {
console.log(`filtred [${filtred}] ✅ sorted [${sorted}]`);
return true;
} else {
console.log(`filtred [${filtred}] 🛑 sorted [${sorted}]`);
}
i++;
}
return false;
};
// array of random numbers for testing
const testArr = Array.from({ length: 100000 }, () =>
Math.floor(Math.random() * 100)
);
// [1,,N] for testing
// const testArr = Array.apply(null, { length: 100001 }).map(Number.call, Number);
console.log(almostIncreasingSequence(testArr));
You could take a found index.
This approach tests either three consecutive elements, like
v
1 2 [3 8 4] 5 6 7 -> found at index 3
or takes for the next loop a check which omits the found value by checking the found index.
v
1 2 3 [8 4 5] 6 7
^ omit value on found index
Then if not in sequence, the adjacent items are checked to prevent this pattern
v
1 2 3 1 2 5 6 7
3 > 2
v
1 2 3 8 2 5 6 7
3 > 2
and if found, more than one element is in wrong position.
function inSequence(array) {
var i,
found;
for (i = 1; i < array.length - 1; i++) {
if ((found === i - 1 || array[i - 1] < array[i]) && array[i] < array[i + 1]) continue;
if (array[i - 1] >= array[i + 1] || found !== undefined) return false;
found = i;
}
return true;
}
console.log(inSequence([2, 1]));
console.log(inSequence([1, 2, 3]));
console.log(inSequence([2, 1, 3]));
console.log(inSequence([1, 2, 4, 3]));
console.log(inSequence([1, 2, 3, 8, 4, 5, 6, 7]));
console.log(inSequence([1, 2, 3, 8, 4, 5, 6, 9, 7]));
console.log(inSequence([2, 1, 3, 4, 5, 2]));
console.log(inSequence([1, 2, 3, 1, 2, 5, 6, 7]));
console.log(inSequence([1, 2, 3, 8, 2, 5, 6, 7]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Loop through your array once for a worst case performance of O(n). Count the number of times the next number is less than the last (ie out of sequence) and also bomb out as soon as this has occurred more than once to improve performance where possible.
let sequenceTrue = [1, 2, 3, 4, 2, 5, 6, 7, 8, 9];
let sequenceFalse = [1, 3, 4, 2, 5, 6, 7, 8, 2, 9];
function isAlmostIncreasingSequence(sequence) {
let count = 0;
for (let index = 0; index < sequence.length && count <= 1; index++) {
if (
!!sequence[index - 1]
&& sequence[index] <= sequence[index - 1]
) {
count++;
}
}
return count <= 1;
}
console.log("should be true", isAlmostIncreasingSequence(sequenceTrue));
console.log("should be false", isAlmostIncreasingSequence(sequenceFalse));
EDIT:
improve performance of the example above by removing the first check from the for loop and manually evaluate the first item in the array.
function isAlmostIncreasingSequence(sequence) {
let count = 0;
if (sequence[1] < sequence[0]) count++;
for (let index = 1; index < sequence.length && count <= 1; index++) {
if (sequence[index] <= sequence[index - 1]) {
count++;
}
}
return count <= 1;
}

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

Categories

Resources