I'm working on this CodeSignal exercise that says:
You have an array of integers nums and an array queries, where queries[i] is a pair of indices (0-based). Find the sum of the elements in nums from the indices at queries[i][0] to queries[i][1] (inclusive) for each query, then add all of the sums for all the queries together. Return that number modulo 10^9 + 7.
This is my code:
function solution(nums, queries) {
let accumulator = 0;
let M = 1000000007;
for(let i = 0; i < queries.length; i++){
accumulator += nums.slice(queries[i][0],queries[i][1]+1).reduce((a,b) => a+b);
}
return accumulator < 0 ? ((accumulator % M) + M) % M : accumulator%M;
}
It works perfectly, BUT the penultimate hidden test throws a timeout, and I'm out of ideas on how to make this faster.
Thanks in advance for any help you may provide.
PS: if you're wondering about the difference using modulo at the end, it's because it seems JS has a bug when using negative numbers.
As tflave pointed out, using a prefix sum made the code perform faster, and it didn't timeout. Here's the code if anyone needs it:
let pre = new Array(1000,0);
function preCompute(nums)
{
let n = nums.length;
pre[0] = nums[0];
for (let i = 1; i < n; i++) {
pre[i] = nums[i] + pre[i - 1];
}
}
function solution(nums, queries)
{
preCompute(nums);
let accumulator = 0;
let M = 1000000007;
for(let i = 0; i < queries.length; i++){
if (queries[i][0] === 0) {
accumulator += pre[queries[i][1]];
} else {
accumulator += pre[queries[i][1]] - pre[queries[i][0] - 1];
}
}
return accumulator < 0 ? ((accumulator % M) + M) % M : accumulator%M;
}
Related
My question maybe seems like duplicated but I can't find how to do this in vanilla javascript.
(I found answer in python here.)
So basically I want to get a list of all possible combinations of number that sum up to a desired number.
For example:
function sum_to_n(n,size){}
x = sum_to_n(6,3)
// [6,0,0] [5,1,0] [4,2,0] [4,1,1] [3,3,0] [3,2,1] [2,2,2]
This is what I can do so far:
function sum_to_n(n, size, sum=[], limit) {
if (size === 1) {
sum.push(n)
return sum
}
if (!limit) {
limit = n
}
let start = Math.min(n, limit)
let stop = Math.ceil(n/size) - 1
for (let i = start; i > stop; i--) {
let tmp = [...sum];
tmp.push(i)
let combination = sum_to_n(n-i, size - 1, tmp, i)
if (combination) {
console.log(combination) // this work
}
}
}
// I don't know how to make this work
let x = sum_to_n(6, 3)
// or maybe this
for (let y in sum_to_n(6,3)) {
console.log(y)
}
This is closely related to partitions of an integer, which finds all distinct ways of breaking an integer into the sum of positive integers. For instance, the partitions of 4 are 4, 3 + 1, 2 + 2, 2 + 1 + 1, and 1 + 1 + 1 + 1. Although there is probably a more direct way of calculating your sum, it's easy to do atop a partitions function:
const partitions = (n, max = n) =>
n == 0
? [[]]
: n < 0
? []
: Array .from ({length: Math .min (n, max)}, (_, i) => i + 1) // or use a `ramge` function
.reverse()
.flatMap (x => partitions (n - x, x) .map (p => [x, ...p]))
const sumToN = (n, c) =>
partitions (n + c)
.filter (p => p .length == c)
.map (p => p .map (x => x - 1))
console .log (sumToN (6, 3))
.as-console-wrapper {max-height: 100% !important; top: 0}
(The reverse call is not strictly necessary, but the usual partition description is written in this order, as is your requested output. The Array.from (...) call would be better expressed using a range function, but is not horrible inlined like this.)
We need to do two things: we have to find only those of the correct length, and we need to allow zeros as well as the positive numbers that partition generates. We can do this by partitioning a larger number and subtracting 1 from each value in every partition, and filtering the results down to those with the proper length.
The larger number we need -- since we're going to subtract 1 for every one of our c elements in each partition -- is simply n + c.
This algorithm's performance is exponential in n. But that's necessary as there are an exponential number of such partitions, and presumably an exponential number of results for your requested output. (I don't know a proof of this, and it's possible I'm wrong. If I am, I'd love to see a sub-exponential algorithm.)
'use strict';
function _sumToN(n, size, acc = [], solutions = []) {
if (size === 0) {
const sum = acc.reduce((sum, num) => sum + num);
return sum === n ? solutions.concat([acc]) : solutions;
}
for (let i = 0; i <= n; ++i)
solutions = _sumToN(n, size - 1, acc.concat(i), solutions);
return solutions;
}
function sumToN(n, size) {
return _sumToN(n, size);
}
console.log(sumToN(6, 3));
The above uses a driver, _sumToN, which accepts an additional acc accumulator array, and a solutions array that will eventually hold all the solutions. It iterates as follows:
0 0 0
0 0 1
0 0 2
...
0 0 6
...
6 6 6
and saves off solutions when they sum to n. There are of course optimizations that can be made, but hopefully this trivial implementation helps.
let sum_to_n = (n, iteration_limit) => {
let res = [];
for (let i = 0; i < iteration_limit; i++) {
for (let j = 0; j < iteration_limit; j++) {
for (let h = 0; h < iteration_limit; h++) {
if(i+j+h == n){
res.push([i, j, h])
}
}
}
}
return res;
};
This worked for me, however it does not have a size parameter.
let getOperator = (size, arr, expect) => {
let ev = "";
for (let i = 0; i < size; i++) {
ev += `${arr[i]}+`;
}
return `${ev.slice(0, ev.length-1)} == ${expect}`;
}
let sum_to_n = (n, size, iteration_limit) => {
return new Promise(resolve => {
let identifiers = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split('');
let all_identifiers = [];
let res = [];
let ev = "";
for (let i = 0; i < size; i++) {
let r = identifiers[i];
all_identifiers.push(r);
ev += `for (let ${r} = 0; ${r} < iteration_limit; ${r}++){\n`;
}
let push_value_string = "";
for (let i = 0; i < all_identifiers.length; i++) {
push_value_string += `${all_identifiers[i]}, `;
}
ev += `\nif(${getOperator(size, all_identifiers, n)}){\nres.push([${push_value_string.slice(0, push_value_string.length-1)}]);\n}`;
for (let i = 0; i < size; i++) {
ev += "}";
}
console.log(ev);
eval(ev);
resolve(res);
});
};
sum_to_n(15, 3, 100).then(console.log);
Basically depending on the size it will make a JavaScript code in a text size times, save what word it used for the for loop and check if the addition of all is equal to n. Then evaluate it and resolve it.
I am using a map in JS to store the number of occurrences of an element, but I am not sure whether I should store the element also as a value in order to access it quicker. For reference, I am solving Single Number II on LeetCode (https://leetcode.com/problems/single-number-ii/).
var singleNumber = function(nums) {
let map = new Map();
for (let i = 0; i < nums.length; i++){
if (!map.has(nums[i])){
map.set(nums[i], [nums[i], 1])
} else {
map.set(nums[i], [nums[i], map.get(nums[i][1]) + 1])
}
}
let res = [...map.values()].filter((x)=> x[1] === 1);
return res[0][0]
};
Here is what I thought of doing: storing each key also as a value, so that I could easily filter them and grab the key. The other option is to iterate through the entire map:
class Solution {
public int singleNumber(int[] nums) {
HashMap<Integer, Integer> hashmap = new HashMap<>();
for (int num : nums)
hashmap.put(num, hashmap.getOrDefault(num, 0) + 1);
for (int k : hashmap.keySet())
if (hashmap.get(k) == 1) return k;
return -1;
}
}
The above solution is from the LeetCode solution page.
Which one of these methods is preferred? Is one better than the other regarding time complexity?
Here is what I thought of doing: storing each key also as a value
No, you should not do that. It just creates unnecessary tuple objects taking up memory unnecessarily. Keys are available easily enough when accessing a map.
So that I could easily filter them and grab the key. [Without] iterat[ing] through the entire map
You already are iterating through the entire map, that's what [...map.values()] does. In fact you should not do that, as you don't need to iterate through the entire map and filter for all values that match the condition, you only want to find the first and break the iteration once you got it.
The proper way to iterate through a JavaScript Map when you need both key and value is by using its .entries() method, which is also the default iterator:
function singleNumber(nums) {
const map = new Map();
for (const num of nums) {
const val = map.has(num) ? map.get(num) : 0;
map.set(num, val + 1)
}
for (let [key, val] of map) {
if (val === 1) {
return key;
}
}
return -1; // or null or undefined or something
}
Usually, the lowest time complexity is desired, there are exceptions though. Then, we'd look into memory complexity.
For this question, bitwise algorithm is preferred because it'll reduce the memory complexity to constant (O(1)).
JavaScript
var singleNumber = function(nums) {
let seenOnce = 0
let seenTwice = 0
for (let num of nums) {
seenOnce = ~seenTwice & (seenOnce ^ num);
seenTwice = ~seenOnce & (seenTwice ^ num);
}
return seenOnce;
};
Java
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for (int i = 0; i < 32; i++) {
int sum = 0;
for (int j = 0; j < nums.length; j++)
if (((nums[j] >> i) & 1) == 1) {
sum++;
sum %= 3;
}
if (sum != 0)
res |= sum << i;
}
return res;
}
}
Here is a LeetCode's solution with comments:
class Solution {
public int singleNumber(int[] nums) {
int seenOnce = 0, seenTwice = 0;
for (int num : nums) {
// first appearence:
// add num to seen_once
// don't add to seen_twice because of presence in seen_once
// second appearance:
// remove num from seen_once
// add num to seen_twice
// third appearance:
// don't add to seen_once because of presence in seen_twice
// remove num from seen_twice
seenOnce = ~seenTwice & (seenOnce ^ num);
seenTwice = ~seenOnce & (seenTwice ^ num);
}
return seenOnce;
}
}
The above algorithm runs at O(N) time and O(1) space.
Python using Counter
class Solution:
def singleNumber(self, nums):
return collections.Counter(nums).most_common(len(nums))[-1][0]
C++
#include <cstdint>
#include <vector>
struct Solution {
static std::int_fast32_t singleNumber(const std::vector<int>& nums) {
std::vector<int> num_vect(32);
const std::size_t length = nums.size();
std::int_fast32_t i;
std::int_fast32_t j;
std::int_fast32_t num;
for (i = 0; i < length; ++i) {
num = nums[i];
for (j = 31; j >= 0; --j) {
num_vect[j] += num & 1;
num >>= 1;
if (!num) {
break;
}
}
}
std::int_fast32_t single_num = 0;
for (j = 31; j >= 0; --j) {
num = num_vect[j] % 3;
if (num) {
single_num += 1 << (31 - j);
}
}
return single_num;
}
};
By the way, you should not use sorting at all for this question, because it'll increase the time complexity from O(N) to O(N Log N).
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.
Test Cases:
(6, [1,3,2,6,1,2]) returns (pairs / 2) = 5
It does get the answer the thing is that is doing more than it needs to, It is possible just add some validation to know when he is adding same reversed index but it will only give it more to do. am looking to remove the unneeded work. can it be more reliable?
function returnOcurrences(k,ar){
debugger;
const letters = [new Set(ar)];
let pairs = 0;
for (let i = 0; i < ar.length; i++) {
for (let ii = 0; ii < ar.length; ii++) {
let a = ar[i] + ar[ii];
if (i != ii) {
if (a >= k) {
pairs += (a % k == 0) ? 1 : 0
}
}
}
}
return pairs/2;
}
What I assume you want to do is prevent the algorithm from checking e.g. ar[1] + ar[2], then ar[2] + ar[1] again.
To solve this, consider starting your inner loop from i + 1 and not from 0. This prevents the mentioned scenario from happening, and also prevents the algorithm from summing an element with itself (e.g. ar[0] + ar[0]). So no need to check anymore if i is equal to ii.
Why so? Assume the first iteration of the outer loop. You are checking the sum of ar[0] with ar[1], then with ar[2], ar[3], and so on.
On the second iteration of the outer loop, you are checking sums of ar[1] with other elements of the array. However, you already checked ar[0] + ar[1] in the previous iteration. So you start with ar[1] + ar[2], where ii = i + 1 = 2.
So the code becomes:
function returnOcurrences(k,ar){
const letters = [new Set(ar)]; //I don't see the purpose of this variable but okay
var pairs = 0;
for (var i = 0; i < ar.length; i++) {
for (var ii = i + 1; ii < ar.length; ii++) {
var a = ar[i] + ar[ii];
if (a >= k) {
pairs += (a % k == 0) ? 1 : 0
}
}
}
return pairs/2;
}
Hope this helps!
I'm taking a course on FreeCodeCamp.org and the assignment is to find "Smallest Common Multiple". So I came up with a solution I think works and I does up to a certain point. Then the code just seems like it's breaking down. Here is my code:
function smallestCommons(arr) {
arr = arr.sort((a,b) => {return a - b;});
console.log(arr);
var truesec = false;
for(var a = arr[1]; truesec != true; a++){
for(var e = 1; e <= arr[1]; e++){
//console.log(a % e + " " + e);
if(a % e != 0){
truesec = false;
break;
}else{
truesec = true;
}
}
//console.log(truesec + " " + a);
if(truesec == true){
return a;
}
}
return a;
}
console.log(smallestCommons([23,18]));
This should return 6056820 according to their checklist but every time I check I get a different result I've gotten both 114461 & 122841 from the same code. Can somebody please tell me what is wrong with this?
Here is the assignment if it helps:
Intermediate Algorithm Scripting: Smallest Common Multiple
What your algorithm trying to do is find the common multiple between 1 and the greater number in the array, which might take a very long time. However, the question from the FreeCodeCamp asks you to find the common multiple between the two numbers in the array, so the result calculated from your algorithm does not match the tests.
To make your solution works, you can change
from for (var e = 1; e <= arr[1]; e++)
to for (var e = arr[0]; e <= arr[1]; e++)
in order to loop between two numbers in the array.
I would take a different approach to this problem:
create function to get all prime factors
create array of prime factor of all number between a[0] and a[1]
reduce the array as the biggest power for each prime factor.
multiple all the prime factor left in the array
Your approach will take O(k*a[1]) when k is the answer - and k can be very high... This approach will take O((a[1])^2)
Consider the following code:
function smallestCommons2(arr) {
arr.sort((a,b) => {return a - b;});
let factors = [];
for(let i = arr[0]; i <= arr[1]; i++)
factors.push(findPrimeFactors(i));
let reduced = reduceFactors(factors);
let ans = 1;
for (let i in reduced)
ans *= Math.pow(i, reduced[i]);
return ans;
}
function reduceFactors(factorsArr) {
let factorObject = {};
for (let i in factorsArr) {
for(let key in factorsArr[i]) {
if (!(key in factorObject) || factorObject[key] < factorsArr[i][key])
factorObject[key] = factorsArr[i][key];
}
}
return factorObject;
}
function findPrimeFactors (num) {
var primeFactors = [];
while (num % 2 === 0) {
primeFactors.push(2);
num = num / 2;
}
var sqrtNum = Math.sqrt(num);
for (var i = 3; i <= sqrtNum; i++) {
while (num % i === 0) {
primeFactors.push(i);
num = num / i;
}
}
if (num > 2)
primeFactors.push(num);
let factorObject = {};
for (let item of primeFactors) {
if (item in factorObject)
factorObject[item] += 1;
else factorObject[item] = 1;
}
return factorObject;
}
console.log(smallestCommons2([23,18]));
This code will output 6056820 in sec
Edited - found a post that do the same thing in a better way
A codility problem asks to find the missing number in zero-indexed array A consisting of N different integers.
E.g.
Arr[0] = 2
Arr[1] = 3
Arr[2] = 1
Arr[3] = 4
Arr[4] = 6
I previously submitted a solution that first sorts the array and then performs a forEach function returning the value +1 where the array difference between elements is more than 1, however this doesn't get the 100 points.
Is there a way to improve this?
Here is 100% javascript solution:
function solution(A) {
if (!A.length) return 1;
let n = A.length + 1;
return (n + (n * n - n) / 2) - A.reduce((a, b) => a + b);
}
We return 1 if the given array is empty, which is the missing element in an empty array.
Next we calculate the 'ordinary' series sum, assuming the first element in the series is always 1. Then we find the difference between the given array and the full series, and return it. This is the missing element.
The mathematical function I used here are series sum, and last element:
Sn = (n/2)*(a1 + an)
an = a1 + (n - 1)*d
Get 100 in correctness and performance using this function
function solution(A) {
// write your code in JavaScript (Node.js 4.0.0)
var size = A.length;
var sum = (size + 1) * (size + 2) / 2;
for (i = 0; i < size; i++) {
sum -= A[i];
}
return sum;
}
Easy if you use the Gauss formula to calculate the sum of the first N consecutive numbers:
function solution(A) {
var np1, perfectSum, sum;
if (!A || A.length == 0) {
return 1;
}
np1 = A.length + 1;
// Gauss formula
perfectSum = np1 * (1 + np1) / 2;
// Sum the numbers we have
sum = A.reduce((prev, current) => prev + current);
return perfectSum - sum;
}
From the sum of first natural numbers formula we have
now since the N item for us in the task is (N+1) we substitue n with n+1 and we get
with the formula above we can calculate the sum of numbers from 1 to n+1, since in between these numbers there is the missing number, now what we can do is we can start iterating through the given array A and subtracting the array item from the sum of numbers. The ending sum is the item which was missing in the array. hence:
function solution(A) {
var n = A.length;
// using formula of first natural numbers
var sum = (n + 1) * (n + 2) / 2;
for (var i = 0; i < n; i++) {
sum -= A[i];
}
return sum;
}
No Gauss formula, only simple and plain separate for loops that give an O(N) or O(N * log(N)) and 100% score:
function solution(A) {
if(!A.length){
return 1; //Just because if empty this is the only one missing.
}
let fullSum = 0;
let sum = 0;
for(let i = 0; i <= A.length; i++){
fullSum += i+1;
}
for(let i = 0; i < A.length; i++){
sum += A[i];
}
return fullSum - sum;
}
Try utilizing Math.min , Math.max , while loop
var Arr = [];
Arr[0] = 2
Arr[1] = 3
Arr[2] = 1
Arr[3] = 4
Arr[4] = 6
var min = Math.min.apply(Math, Arr),
max = Math.max.apply(Math, Arr),
n = max - 1;
while (n > min) {
if (Arr.indexOf(n) === -1) {
console.log(n);
break;
}
--n;
}
This should be work good:
function solution(A) {
// Size of the A array
const size = A.length;
// sum of the current values
const arrSum = A.reduce((a, b) => a + b, 0);
// sum of all values including the missing number
const sum = (size + 1) * (size + 2) / 2;
// return substruction of all - current
return (sum - arrSum);
}
This got me 100%
function solution(A) {
if (A.length === 0 || !A) {
return 1;
}
A.sort((a, b) => a - b);
let count = A[0];
if (count !== 1) { return 1 }
for (let i = 0; i <= A.length; i++) {
if (A[i + 1] === count + 1) {
count ++;
continue
}
return count + 1;
}
}
// you can write to stdout for debugging purposes, e.g.
// console.log('this is a debug message');
function solution(A) {
if (!A.length) return 1;
A = A.sort((a, b) => a - b);
for (let i = 0; i < A.length + 1; i++) {
if (A[i] !== i + 1) {
return i + 1;
}
}
}
My 100% JavaScript solution:
function solution(A) {
const N = A.length;
// use the Gauss formula
const sumNatural = (N + 1) * (N + 2) / 2;
// actual sum with the missing number (smaller than sumNatural above)
const actualSum = A.reduce((sum, num) => sum += num, 0);
// the difference between sums is the missing number
return sumNatural - actualSum;
}
I wonder why there isn't any answer using a hashtable.
It's obvious that we need to iterate this array from start to end.
Therefore, best solution we can have is O(n).
I simply map numbers, and access them with O(1) in another iteration.
If all numbers are tagged as true, it means it's either an empty array, or it doesn't contain missing number. Either way length + 1 returns the expected output.
It returns 1 for [], and it returns 3 for [1,2].
// you can write to stdout for debugging purposes, e.g.
function solution(A) {
// write your code in JavaScript (Node.js 8.9.4)
let nums = new Map()
for (let i = 0; i < A.length; i++) {
nums[A[i]] = true;
}
for (let i = 1; i < A.length + 1; i++) {
if (nums[i]) { continue; }
else { return i;}
}
return A.length + 1;
}
function solution(A) {
// write your code in JavaScript (Node.js 8.9.4)
const n = A.length+1
return (n*(n+1)/2) - A.reduce((a, b) => a + b, 0)
}
Explanation:
The formula for sum of natural numbers => n(n+1)/2
where n is the last number or last nth term.
In our case, n will be our array.length. But the question states that exactly one item is missing, meaning the last nth term is array.length +1.
To find the expected sum of all our natural numbers,
We can deduct the total of the available numbers (A.reduce((a, b) => a + b, 0)) from the expected sum n(n+1)/2 to arrive at the missing number.
I had the same problem with my code:
function solution(A) {
var i, next;
A.sort();
next = 1;
for (i=0; i<A.length; i++){
if (A[i] != next) return next;
next++;
}
return next;
}
Altough it scored 100% in correctness, it returned wrong answer in all the performance tests.
The same code in C receives 100% on both:
int cmpfunc (const void * a, const void * b){
return ( *(int*)a - *(int*)b );
}
int solution(int a[], int n) {
int i, next;
qsort(a, n, sizeof(int), cmpfunc);
next = 1;
for (i=0; i<n; i++){
if (a[i] != next) return next;
next++;
}
return next;
}
I got an alternative 100% correctness/performance solution without the Gauss formula, sorting the array first instead:
function solution(A) {
A.sort((a, b) => a-b);
for(let i=0; i<A.length; i++){
if(A[i] != i+1) {
return 0;
}
}
return 1;
}