Reputation: 51
https://www.codewars.com/kata/is-my-friend-cheating/train/javascript
My goal is to devise a function that finds number pairs (a, b)
which satisfy the equation a * b == sum(1, 2, 3 ..., n-2, n-1, n) - a - b
.
The following code finds all the pairs, but is too slow and times out. I have seen in the comments for this challenge that the algorithm needs to have O(n) complexity to pass. How is this done?
function removeNb (n) {
if(n===1) return null;
let sum = (n * (n+1))/2;
let retArr = [];
let a = n;
while( a !== 0){
let b = n;
while( b !== 0){
if(b != a && a*b == ((sum - b) - a) ){
retArr.push([a,b]);
}
b--;
}
a--;
}
retArr.sort( (a,b) => a[0] - b[0]);
return retArr;
}
Thanks to all for the assistance! Here is my final solution:
function removeNb (n) {
let retArr = [];
let a = 1;
let b = 0;
let sumN = (n * (n+1))/2;
while( a <= n){
b = parseInt((sumN - a) / (a + 1));
if( b < n && a*b == ((sumN - b) - a) )
retArr.push([a,b]);
a++;
}
return retArr;
}
I think my main issue was an (embarrassing) error with my algebra when I attempted to solve for b
. Here are the proper steps for anyone wondering:
a*b = sum(1 to n) - a - b
ab + b = sumN - a
b(a + 1) = sumN - a
b = (sumN - a) / (a + 1)
Upvotes: 4
Views: 6170
Reputation: 52
let n = 100;
let sumOfNum = n => {
return (n * (n + 1)) / 2;
};
let sum = sumOfNum(n);
let response = [];
for (let i = 1; i <= 26; i++) {
let s = (sum - i) / (i + 1);
if (s % 1 == 0 && s * i == sum - s - i && s <= n) {
response.push([s, i]);
}
}
// this is O(N) time complexity
Upvotes: 1
Reputation: 534
As explained in other answers, it is possible to make a O(n) algorithm solving for b. Moreover, given the symmetry of solution -- if (a,b) is a solution, also (b,a) is -- it is also possible to save some iterations adding a couple of solutions at a time. To know how many iterations are required, let us note that b > a if and only if a < -1+sqrt(1+sum). To prove it:
(sum-a)/(a+1) > a ; sum-a > a^2+a ; sum > a^2+2a ; a^2+2a-sum < 0 ; a_1 < a < a_2
where a_1 and a_2 comes from 2-degree equation solution:
a_1 = -1-sqrt(1+sum) ; a_2 = -1+sqrt(1+sum)
Since a_1 < 0 and a > 0, finally we proved that b > a if and only if a < a_2.
Therefore we can avoid iterations after -1+sqrt(1+sum).
A working example:
function removeNb (n) {
if(n===1) return null;
let sum = (n * (n+1))/2;
let retArr = [];
for(let a=1;a<Math.round(Math.sqrt(1+sum));++a) {
if((sum-a)%(a+1)===0) {
let b=(sum-a)/(a+1);
if(a!==b && b<=n) retArr.push([a,b],[b,a]);
}
}
retArr.sort( (a,b) => a[0] - b[0]);
return retArr;
}
However, with this implementation we still need the final sort. To avoid it, we can note that b=(sum-a)/(a+1) is a decreasing function of a (derive it to prove). Therefore we can build retArr concatenating two arrays, one adding elements to the end (push), one adding elements at the beginning (unshift). A working example follows:
function removeNb (n) {
if(n===1) return null;
let sum = (n * (n+1))/2;
let retArr = [];
let retArr2 = [];
for(let a=1;a<Math.round(Math.sqrt(1+sum));++a) {
if((sum-a)%(a+1)===0) {
let b=(sum-a)/(a+1);
if(a!==b && b<=n) {
retArr.push([a,b]);
retArr2.unshift([b,a]); // b>a and b decreases with a
}
}
}
retArr=retArr.concat(retArr2); // the final array is ordered in the 1st component
return retArr;
}
As a non-native speaker, I would say that the phrase from the reference "all (a, b) which are the possible removed numbers in the sequence 1 to n" implies a!=b, so I added this constraint.
Upvotes: 0
Reputation: 94319
Here's an implementation:
function removeNb(n){
var sum = (1 + n) * n / 2;
var candidates = [];
// O(n)
for(var y = n; y >= 1; y--){
x = (-y + sum) / (y + 1);
/*
* Since there are infinite real solutions,
* we only record the integer solutions that
* are 1 <= x <= n.
*/
if(x % 1 == 0 && 1 <= x && x <= n)
// Assuming .push is O(1)
candidates.push([x, y]);
}
// Output is guaranteed to be sorted because
// y is iterated from large to small.
return candidates;
}
console.log(removeNb(26));
console.log(removeNb(100));
https://jsfiddle.net/DerekL/anx2ox49/
From your question, it also states that
Within that sequence, he chooses two numbers, a and b.
However it does not mention that a
and b
are unique numbers, so a check is not included in the code.
Upvotes: 0
Reputation: 4122
You can solve for b and get: b = (sum - a)/(a + 1)
(given a != -1)
Now iterate over a
once -> O(n)
Upvotes: 2