Find absolute sum of minimum slice - codility [duplicate] - javascript

This question already has answers here:
Finding minimal absolute sum of a subarray
(11 answers)
Closed 4 years ago.
Hi I've taken Codility test twice and scored 0. Please help me in solving the issue using JavaScript.
A non-empty array A consisting of N integers is given. A pair of integers (P, Q), such that 0 ≤ P ≤ Q < N, is called a slice of array A. The sum of a slice (P, Q) is the total of A[P] + A[P+1] + ... + A[Q].
A min abs slice is whose absolute sum is minimal.
For example, array A such that:
A[0] = 2
A[1] = -4
A[2] = 6
A[3] = -3
A[4] = 9
contains the following slice among others:
(0,1), whose absolute sum is = |2 + (-4)| = 2
(0,2), whose absolute sum is = |2 + (-4) + 6| = 4
(0,3), whose absolute sum is = |2 + (-4) + 6 + (-3)| = 1
(1,3), whose absolute sum is = |(-4) + 6 + (-3)| = 1
(1,4), whose absolute sum is = |(-4) + 6 + (-3) + 9| = 8
(4,4), whose absolute sum is = |9| = 9
Both slices (0,3) and (1,3) are min abs slice and their absolute sum equals 1.
Write a function:
function solution(A);
that, given a non-empty array A consisting of N integers, return the absolute sum of min abs slice.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..1,000,000];
each element of array A is an integer within the range [−10,000..10,000];
Here is my solution:
function solution(A, i = 0, sum = 0) {
const N = A.length;
if (N === 0) {
return 0;
}
if (N == 1) {
return Math.abs(A[0]);
}
A.sort();
// All positives
if (A[0] >= 0 && A[N - 1] >= 0) {
return Math.abs(A[0]);
}
// All Negatives
if (A[0] <= 0 && A[N - 1] <= 0) {
return Math.abs(A[N - 1]);
}
let currAbsSum = 0;
let minAbsSum = Number.MAX_SAFE_INTEGER;
for (var i = 0; i < N; i++) {
let j = N - 1;
while (j >= i) {
currAbsSum = Math.abs(A[i] + A[j]);
if (currAbsSum === 0) {
return 0;
}
minAbsSum = Math.min(currAbsSum, minAbsSum);
if (Math.abs(A[i]) > Math.abs(A[j])) {
i++;
} else {
j--;
}
}
if (A[i] > 0) break;
}
return minAbsSum;
}

Here is a javascript version of O(n log n) answer taken from here:
function solution(A) {
if (1 == A.length) return Math.abs(A[0]);
let sums = new Array(A.length + 1);
let minAbsSum = Number.MAX_SAFE_INTEGER;
sums[0] = 0;
for (var i = 0; i < A.length; i++) {
sums[i + 1] = A[i] + sums[i];
}
sums.sort();
for (var i = 1; i < sums.length; i++) {
minAbsSum = Math.min(minAbsSum, Math.abs(sums[i] - sums[i - 1]));
}
return minAbsSum;
}
console.log(solution([2, -4, 6, -3, 9]))
console.log(solution([10, 10, 10, 10, 10, -50]))

Related

Javascript multiplying strings

I was doing following leetcode question on multiplying
Given two non-negative integers num1 and num2 represented as strings, return the
product of num1 and num2, also represented as a string.
Note: You must not use any built-in BigInteger library or convert the inputs to
integer directly.
Example 1:
Input: num1 = "2", num2 = "3"
Output: "6"
Example 2:
Input: num1 = "123", num2 = "456"
Output: "56088"
Constraints:
- 1 <= num1.length, num2.length <= 200
- num1 and num2 consist of digits only.
- Both num1 and num2 do not contain any leading zero, except the number 0 itself.
For this used the following approach
Convert the string to int
Multiply the int
Algo for the same is
const numberMap = {
"0": 0,
"1": 1,
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9
}
var multiply = function(num1, num2) {
let i = num1.length
let j = num2.length
let sum = currentPower = 0
let firstNumber = secondNumber = 0
while(i > 0 || j > 0) {
// if I or J is equal to zero, means we have itterated hence we will set the value to one
const firstNum = i > 0 ? (numberMap[num1[i-1]]) * (10**currentPower) : 0
const secondNum = j > 0 ? (numberMap[num2[j-1]]) * (10**currentPower) : 0
firstNumber += firstNum
secondNumber += secondNum
currentPower++
i--
j--
}
sum = firstNumber * secondNumber
return sum.toString()
};
but when the following input is given
"123456789"
"987654321"
it yields the following output "121932631112635260" instead of "121932631112635269"
Any idea how I can fix this?
You could multiply each digit with each other digit and take the indices as position.
Like you would do by hand, like
1 2 3 4 * 4 3 2 1
-------------------------
1 2 3 4
1 4 6 8
3 6 9 12
4 8 12 16
-------------------------
5 3 2 2 1 1 4
This approach uses the reversed arrays of the strings and reverse the result set as well.
Before retuning the result, the array is filterd by the leading zeros.
function multiply(a, b) {
var aa = [...a].reverse(),
bb = [...b].reverse(),
p = [],
i, j;
for (i = 0; i < aa.length; i++) {
for (j = 0; j < bb.length; j++) {
if (!p[i + j]) p[i + j] = 0;
p[i + j] += aa[i] * bb[j];
if (p[i + j] > 9) {
if (!p[i + j + 1]) p[i + j + 1] = 0;
p[i + j + 1] += Math.floor(p[i + j] / 10);
p[i + j] %= 10;
}
}
}
return p
.reverse()
.filter((valid => (v, i, { length }) => valid = +v || valid || i + 1 === length)(false))
.join('');
}
console.log(multiply('2', '3')); // 6
console.log(multiply('123', '456')); // 56088
console.log(multiply('9133', '0')); // 0
console.log(multiply('9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999', '9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999'));
function multiply() {
var str = document.getElementById('a').value;
var str1 = document.getElementById('b').value;
var l = str.length;
var l1 = str1.length;
var list = [];
var prod = 0;
var cur = 0;
list.length = l + l1;
// store 0 to to all list elements
list.fill(0);
// access string in reverse
for (var i = l - 1; i >= 0; i--) {
for (
var j = l1 - 1;
j >= 0;
j-- // access string in reverse
) {
// ASCII value of character and - ("0") ASCII Value 48
prod = (str.charCodeAt(i) - 48) * (str1.charCodeAt(j) - 48);
cur = list[i + j + 1] + prod;
list[i + j + 1] = cur % 10;
list[i + j] += parseInt(cur / 10);
}
}
var res = '';
res = list.join('');
if (res[0] == 0) {
// if First Char ==0 then remove
res = res.slice(1);
}
console.log(res);
}
var multiply = function(num1, num2) {
let v1=BigInt(num1)
let v2=BigInt(num2)
let v3=v1*v2
return v3.toString()
};
Just convert to Numbers, multiply, and then convert back to a string.
function mult(a, b){
return (Number(a) * Number(b)).toString();
}
In JavaScript, ints are not a specific type. They're the number type. We could use the parseInt() function instead of the Number() function to convert, but we know we're receiving an int as an input anyway, so there's no need for that kind of parsing.

find sum of multiples 3 and 5, JS

I'm given a number and I need to find the sum of the multiples of 3 and 5 below the number.
For example:
20 => 78 = 3 + 5 + 6 + 9 + 10 + 12 + 15 + 18
My code works, but not for numbers greater than 1,000,000 (I tested it for 100,000 - it gives the result with 2sec delay). So, it should be optimized. Could someone help me? Why is my code slow? Thanks.
My logic is as follows:
add multiples to an array
filter duplicate values
sum all values
my code:
function sumOfMultiples(number) {
let numberBelow = number - 1;
let numberOfThrees = Math.floor(numberBelow / 3);
let numberOfFives = Math.floor(numberBelow / 5);
let multiples = [];
let multipleOfThree = 0;
let multipleOfFive = 0;
for (var i = 0; i < numberOfThrees; i++) {
multiples.push(multipleOfThree += 3);
}
for (var j = 0; j < numberOfFives; j++) {
multiples.push(multipleOfFive += 5);
}
return multiples
.filter((item, index) => multiples.indexOf(item) === index)
.reduce((a, b) => a + b);
}
You can also do this without using any loops.
For example if N is 1000, the sum of all multiples of 3 under 1000 is 3 + 6 + 9 ..... 999 => 3( 1 + 2 + 3 .... 333)
Similarly for 5, sum is 5(1 + 2 + 3 .... 200). But we have to subtract common multiples like 15, 30, 45 (multiples of 15)
And sum of first N natural numbers is N*(N+1)/2;
Putting all of this together
// Returns sum of first N natural numbers
const sumN = N => N*(N+1)/2;
// Returns number of multiples of a below N
const noOfMulitples = (N, a) => Math.floor((N-1)/a);
function sumOfMulitples(N) {
const n3 = noOfMulitples(N, 3); // Number of multiples of 3 under N
const n5 = noOfMulitples(N, 5); // Number of multiples of 5 under N
const n15 = noOfMulitples(N, 15); // Number of multiples of 3 & 5 under N
return 3*sumN(n3) + 5*sumN(n5) - 15*sumN(n15);
}
You can just run a loop from 1 to number, and use the modulo operator % to check if i divides 3 or 5:
function sumOfMultiples(number) {
var result = 0;
for (var i = 0; i < number; i++) {
if (i % 5 == 0 || i % 3 == 0) {
result += i;
}
}
return result;
}
console.log(sumOfMultiples(1000));
console.log(sumOfMultiples(100000));
console.log(sumOfMultiples(10000000));
You can do that just using a single loop.
function sumOfMultiples(number) {
let sum = 0;
for(let i = 1; i < number; i++){
if(i % 3 === 0 || i % 5 === 0){
sum += i;
}
}
return sum;
}
console.time('t');
console.log(sumOfMultiples(100000))
console.timeEnd('t')
You can do something like this
Set the difference equal to 5 - 3
Start loop with current as 0, keep looping until current is less than number,
Add 3 to current in every iteration,
Add difference to current and check if it is divisible by 5 only and less than number, than add it final result,
Add current to final result
function sumOfMultiples(number) {
let num = 0;
let difference = 5 - 3
let current = 0
while(current < number){
current += 3
let temp = current + difference
if((temp % 5 === 0) && (temp %3 !== 0) && temp < number ){
num += temp
}
difference += 2
if(current < number){
num += current
}
}
return num
}
console.log(sumOfMultiples(20))
console.log(sumOfMultiples(1000));
console.log(sumOfMultiples(100000));
console.log(sumOfMultiples(10000000));
you can do something like this
function multiplesOfFiveAndThree(){
let sum = 0;
for(let i = 1; i < 1000; i++) {
if (i % 3 === 0 || i % 5 === 0) sum += i;
}
return sum;
}
console.log(multiplesOfFiveAndThree());

Javascript - adding Integers using arrays

I am using an array in order to calculate large powers of 2. The arrays add to each other and afterwords they calculate the carries and loop n-1 amount of times until i end up with the number as an array. I do this in order to avoid the 15 digit limit that JavaScript has.
Everything works fine once i reach n = 42, where the carries start to be overlooked and numbers aren't reduced, producing wrong answers.
I tried changing the method of which the carry is processed inside the while loop from basic addition to integer division and modulus
Sounds stupid but i added an extra loop to check if any elements are greater than 10 but it didn't find them.
for (var n = 1; n <= 100; n++) {
for (var i = 0, x = [2]; i < n - 1; i++) { // Loop for amount of times to multiply
x.unshift(0)
for (var j = x.length - 1; j > 0; j--) { // Double each element of the array
x[j] += x[j]
}
for (j = x.length - 1; x[j] > 0; j--) { // Check if element >= 10 and carry
while (x[j] >= 10) {
x[j - 1] += Math.floor(x[j] / 10)
x[j] = x[j] % 10
}
}
if (x[0] === 0) {
x.shift()
}
}
console.log('N: ' + n + ' Array: ' + x)
}
The expected results are that each element in the array will be reduced into a single number and will "carry" onto the element to its left like :
N: 1 Array: 2
N: 2 Array: 4
N: 3 Array: 8
N: 4 Array: 1,6
N: 5 Array: 3,2
N: 6 Array: 6,4
but starting at n=42 carries get bugged looking like this:
N: 42 Array: 4,2,18,18,0,4,6,5,1,1,1,0,4
N: 43 Array: 8,4,36,36,0,8,12,10,2,2,2,0,8
N: 44 Array: 1,7,5,9,2,1,8,6,0,4,4,4,1,6
N: 45 Array: 2,14,10,18,4,2,16,12,0,8,8,8,3,2
N: 46 Array: 7,0,3,6,8,7,4,4,1,7,7,6,6,4
N: 47 Array: 14,0,7,3,7,4,8,8,3,5,5,3,2,8
What's the error that could be throwing it off like this?
I think the reason your code doesn't work is this line for (j = x.length - 1; x[j] > 0; j--) { // Check if element >= 10 and carry you don't want to check for x[j] > 0 but j > 0.
Also your second loop: for (var i = 0, x = [2]; i < n - 1; i++) { - you don't need it, there is no reason to recalculate everything on every iteration, you can use previous result.
You can also double values this way : x = x.map(n => n * 2) (seems a bit more coventional to me).
And there is no need to x[j - 1] += Math.floor(x[j] / 10) it could be just x[j - 1] += 1 as previous numbers are up to 9, doubled they are no more than 18 so 1 is the only case if x[j] >= 10.
Could be the code:
let x = [2] // starting point
for (var n = 1; n <= 100; n++) {
x = [0, ...x].map(n => n * 2)
for (j = x.length - 1; j > 0; j--) {
if (x[j] >= 10) {
x[j - 1] += 1
x[j] %= 10
}
}
if (x[0] === 0) {
x = x.slice(1)
}
console.log('N: ' + n + ' Array: ' + x)
}
If all you want are large powers of 2, why are you going through the insane hassle of using lists to calculate that? Isn't this the exact same:
function BigPow2(x, acc=2.0) {
//document.writeln(acc);
acc = acc >= 5 ? acc / 5 : acc * 2;
return x <= 1 ? acc : BigPow2(x-1, acc);
}
Or alternatively, use BigInt?

Split number into 4 random numbers

I want to split 10 into an array of 4 random numbers, but neither can be 0 or higher than 4. For example [1,2,3,4], [1,4,4,1] or [4,2,3,1].
I think it's an easy question, but for some reason I can't think of how to do this. If someone has some instruction that would be very helpful!
Edit:
This is the code I have now, but I generates also a total number under 10:
let formation = [];
let total = 0;
for (let i = 0; i < 4; i ++) {
if (total < 9) {
formation[i] = Math.floor(Math.random() * 4) + 1;
} else {
formation[i] = 1;
}
}
You could create all possible combinations and pick a random array.
function get4() {
function iter(temp) {
return function (v) {
var t = temp.concat(v);
if (t.length === 4) {
if (t.reduce(add) === 10) {
result.push(t);
}
return;
}
values.forEach(iter(t));
};
}
const
add = (a, b) => a + b,
values = [1, 2, 3, 4],
result = [];
values.forEach(iter([]));
return result;
}
console.log(get4().map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
An algorithm for getting random values without a list of all possible combinations
It works by using a factor for the random value and an offset, based on the actual sum, index, minimum sum which is needed for the next index, and the maximum sum.
The offset is usually the minimum sum, or the greater value of the difference of sum and maximum sum. For getting the factor, three values are taken for the minimum for multiplying the random value.
The table illustrates all possible values of the sum and the needed iterations, based on a given value and the iteration for getting all values.
At the beginning the sum is the value for distribution in small parts. The result is the second block with a rest sum of 14 ... 10, because it is possible to take a value of 1 ... 5. The third round follows the same rules. At the end, the leftover sum is taken as offset for the value.
An example with 1, ..., 5 values and 5 elements with a sum of 15 and all possibilities:
min: 1
max: 5
length: 5
sum: 15
smin = (length - index - 1) * min
smax = (length - index - 1) * max
offset = Math.max(sum - smax, min)
random = 1 + Math.min(sum - offset, max - offset, sum - smin - min)
index sum sum min sum max random offset
------- ------- ------- ------- ------- -------
_ 0 15 4 20 5 1
1 14 3 15 5 1
1 13 3 15 5 1
1 12 3 15 5 1
1 11 3 15 5 1
_ 1 10 3 15 5 1
2 13 2 10 3 3
2 12 2 10 4 2
2 11 2 10 5 1
2 10 2 10 5 1
2 9 2 10 5 1
2 8 2 10 5 1
2 7 2 10 5 1
2 6 2 10 4 1
_ 2 5 2 10 3 1
3 10 1 5 1 5
3 9 1 5 2 4
3 8 1 5 3 3
3 7 1 5 4 2
3 6 1 5 5 1
3 5 1 5 4 1
3 4 1 5 3 1
3 3 1 5 2 1
_ 3 2 1 5 1 1
4 5 0 0 1 5
4 4 0 0 1 4
4 3 0 0 1 3
4 2 0 0 1 2
4 1 0 0 1 1
The example code takes the target 1, ..., 4 with a length of 4 parts and a sum of 10.
function getRandom(min, max, length, sum) {
return Array.from(
{ length },
(_, i) => {
var smin = (length - i - 1) * min,
smax = (length - i - 1) * max,
offset = Math.max(sum - smax, min),
random = 1 + Math.min(sum - offset, max - offset, sum - smin - min),
value = Math.floor(Math.random() * random + offset);
sum -= value;
return value;
}
);
}
console.log(Array.from({ length: 10 }, _ => getRandom(1, 4, 4, 10).join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
The simplest solution is brute force.
Make a while loop to nest your calculations in
In the loop, create an empty array and fill it with random values until length is reached
Check if the sum of the array is your desired value, and if it is then break the loop
The above should run until you have a result.
Two things worth considering though.
Your can easily test if a solution is at all possible by calculating, that length-of-array times minimum-value isn't more than the sum and length-of-array times maximum-value isn't less than the sum.
A loop based on random conditions could potentially run forever, so a maximum amount of iterations might be desirable.
Both of these points are considered in the snippet below:
function randomNumber(max, min) {
while (true) {
var r = Math.round(Math.random() * max);
if (r >= min) {
return r;
}
}
}
function splitXintoYComponentsBetweenMaxAndMin(numberToSplit, numberOfSplits, maxValue, minValue, onUpdate) {
if (minValue === void 0) {
minValue = 1;
}
//Test that a result can exist
if (maxValue * numberOfSplits < numberToSplit || minValue * numberOfSplits > numberToSplit) {
return new Promise(function(resolve, reject) {
resolve(false);
});
}
//Create returner array
var arr = [];
var accumulator = 0;
while (arr.length < numberOfSplits) {
var val = randomNumber(Math.floor(numberToSplit / numberOfSplits), minValue);
accumulator += val;
arr.push(val);
}
return new Promise(function(resolve, reject) {
function runTest() {
var d = Date.now();
var localMaxValue = Math.min(maxValue, Math.ceil((numberToSplit - accumulator) / 4));
//Combination loop
while (accumulator < numberToSplit && Date.now() - d < 17) {
var index = Math.round(Math.random() * (arr.length - 1));
if (arr[index] >= maxValue) {
continue;
}
var r = randomNumber(localMaxValue, minValue);
while (arr[index] + r > maxValue || accumulator + r > numberToSplit) {
if (Date.now() - d >= 17) {
break;
}
r = randomNumber(localMaxValue, minValue);
}
if (arr[index] + r > maxValue || accumulator + r > numberToSplit) {
continue;
}
arr[index] += r;
accumulator += r;
}
if (accumulator < numberToSplit) {
if (onUpdate !== void 0) {
onUpdate(arr);
}
requestAnimationFrame(runTest);
} else {
resolve(arr);
}
}
runTest();
});
}
//TEST
var table = document.body.appendChild(document.createElement('table'));
table.innerHTML = "<thead><tr><th>Number to split</th><th>Number of splits</th><th>Max value</th><th>Min value</th><th>Run</th></tr></thead>" +
"<tbody><tr><th><input id=\"number-to-split\" value=\"10\" type=\"number\" min=\"1\"/></th><th><input id=\"number-of-splits\" value=\"4\" type=\"number\" min=\"1\"/></th><th><input id=\"max-value\" type=\"number\" min=\"1\" value=\"4\"/></th><th><input id=\"min-value\" type=\"number\" min=\"1\" value=\"1\"/></th><th><input id=\"run\" type=\"button\" value=\"Run\"/></th></tr></tbody>";
var output = document.body.appendChild(document.createElement('pre'));
output.style.overflowX = "scroll";
document.getElementById("run").onclick = function() {
splitXintoYComponentsBetweenMaxAndMin(parseInt(document.getElementById("number-to-split").value, 10), parseInt(document.getElementById("number-of-splits").value, 10), parseInt(document.getElementById("max-value").value, 10), parseInt(document.getElementById("min-value").value, 10))
.then(function(data) {
if (data !== false) {
output.textContent += data.join("\t") + '\n';
} else {
output.textContent += 'Invalid data\n';
}
});
};
EDIT 1 - Big calculations
Using requestAnimationFrame and Promises the code can now execute asynchronously, which allows for longer calculation time without bothering the user.
I also made the random function scale with the remaining range, greatly reducing the amount of calculations needed for big numbers.
A litte late to the show, but I found this a fun task to think about so here you go. My approach does not need to create all partitions, it also does not rely on pure luck of finding a random match, it is compact and it should be unbiased.
It works efficiently even when large values are used, as long as max is not too limiting.
const len = 4;
const total = 10;
const max = 4;
let arr = new Array(len);
let sum = 0;
do {
// get some random numbers
for (let i = 0; i < len; i++) {
arr[i] = Math.random();
}
// get the total of the random numbers
sum = arr.reduce((acc, val) => acc + val, 0);
// compute the scale to use on the numbers
const scale = (total - len) / sum;
// scale the array
arr = arr.map(val => Math.min(max, Math.round(val * scale) + 1));
// re-compute the sum
sum = arr.reduce((acc, val) => acc + val, 0);
// loop if the sum is not exactly the expected total due to scale rounding effects
} while (sum - total);
console.log(arr);
Basically you need the partitions (See https://en.wikipedia.org/wiki/Partition_(number_theory)) of 10 and apply your conditions on the resulting set.
// Partition generator taken from
// https://gist.github.com/k-hamada/8aa85ac9b334fb89ac4f
function* partitions(n) {
if (n <= 0) throw new Error('positive integer only');
yield [n];
var x = new Array(n);
x[0] = n;
for (var i = 1; i < n; i++) x[i] = 1;
var m = 0, h = 0, r, t;
while (x[0] != 1) {
if (x[h] == 2) {
m += 1;
x[h] = 1;
h -= 1;
} else {
r = x[h] - 1;
x[h] = r;
t = m - h + 1;
while (t >= r) {
h += 1;
x[h] = r;
t -= r;
}
m = h + (t !== 0 ? 1 : 0);
if (t > 1) {
h += 1;
x[h] = t;
}
}
yield x.slice(0, m + 1);
}
}
results = [];
// Get all possible partitions for your number
for (var partition of partitions(10)) {
// Apply your conditions (must be 4 numbers, none of them greater than 4)
if(partition.length != 4 || partition.some((x) => x > 4)) continue;
results.push(partition);
}
console.log(results);
Given that:
In a collection of n positive numbers that sum up to S, at least one of them will be less than S divided by n (S/n)
and that you want a result set of exactly 4 numbers,
you could use the following algorithm:
Get a random number from range [1, floor(S/n)], in this case floor(10/4) = 2, so get a random number in the range of [1,2]. Lets mark it as x1.
Get a random number from range [1, floor((S - x1)/(n - 1))]. Lets mark it as x2.
Get a random number from range [1, floor((S - x1 - x2)/(n - 2))].
Continue until you get x(n-1).
Get the last number by doing S - x1 - x2 .... - x(n-1).
Finally, extend the above algorithm with a condition to limit the upper limit of the random numbers.
In n steps, you can get a collection.
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getRandomCollection(min, max, length, sum) {
var collection = [];
var leftSum = sum - (min - 1);
for(var i = 0; i < length - 1; i++) {
var number = getRandomInt(min, Math.min(Math.ceil(leftSum/(length - i)), max));
leftSum -= number;
collection.push(number);
}
leftSum += min - 1;
while(leftSum > max) {
var randomIndex = Math.floor(Math.random() * collection.length);
if(collection[randomIndex] < max) {
collection[randomIndex]++;
leftSum--;
}
}
collection.push(leftSum);
return collection;
}
console.log(getRandomCollection(1, 4, 4, 10).join(' + ') + ' = 10');
console.log(getRandomCollection(3, 20, 10, 100).join(' + ') + ' = 100');
Reference
My answer using the same algorithm for another question
Quick and simple but biased and nondeterministically terminating
function partition(sum, len, min, max) {
const a = Array(len).fill(min)
while (a.reduce((acc,val)=>acc+val) < sum) {
const i = Math.random()*len|0
if (a[i] < max) a[i]++
}
return a
}
console.log(Array(10).fill().map(_=>partition(10, 4, 1, 4).join(' ')))
.as-console-wrapper { max-height: 100% !important; top: 0; }
The while loop can loop forever with an infinitesimal probability. To prevent this, you can keep another array of "valid indexes" and delete keys of it when the value reaches max.
this calculates a random number from 1 to 4
wrap it on a function to your needs to generate the arrays
Math.floor(Math.random() * 4) + 1
var randomNumber = Math.floor(Math.random() * 4) + 1 ;
console.log(randomNumber);
It was too easy.
var values = null;
while(true) {
var currentSum = 0;
var expectedSum = 10;
values = [];
while(expectedSum !== currentSum) {
//var value = Math.floor(Math.random() * 9) + 1;
var value = Math.floor(Math.random() * 4) + 1;
if(value + currentSum > expectedSum) {
continue;
}
currentSum += value;
values.push(value);
}
if(values.length === 4) {
break;
} else {
console.log('false iteration')
}
}
console.log(values);

Peak and Flag Codility latest chellange

I'm trying to solve the latest codility.com question (just for enhance my skills). I tried allot but not getting more than 30 marks there so now curious what exactly I am missing in my solution.
The question says
A non-empty zero-indexed array A consisting of N integers is given. A peak is an array element which is larger than its neighbours. More precisely, it is an index P such that
0 < P < N − 1 and A[P − 1] < A[P] > A[P + 1]
For example, the following array A:
A[0] = 1
A[1] = 5
A[2] = 3
A[3] = 4
A[4] = 3
A[5] = 4
A[6] = 1
A[7] = 2
A[8] = 3
A[9] = 4
A[10] = 6
A[11] = 2
has exactly four peaks: elements 1, 3, 5 and 10.
You are going on a trip to a range of mountains whose relative heights are represented by array A. You have to choose how many flags you should take with you. The goal is to set the maximum number of flags on the peaks, according to certain rules.
Flags can only be set on peaks. What's more, if you take K flags, then the distance between any two flags should be greater than or equal to K. The distance between indices P and Q is the absolute value |P − Q|.
For example, given the mountain range represented by array A, above, with N = 12, if you take:
> two flags, you can set them on peaks 1 and 5;
> three flags, you can set them on peaks 1, 5 and 10;
> four flags, you can set only three flags, on peaks 1, 5 and 10.
You can therefore set a maximum of three flags in this case.
Write a function that, given a non-empty zero-indexed array A of N integers, returns the maximum number of flags that can be set on the peaks of the array.
For example, given the array above
the function should return 3, as explained above.
Assume that:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [0..1,000,000,000].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(N), beyond input storage (not counting the
storage required for input arguments).
So I tried this code according to my understanding of question
var A = [1,5,3,4,3,4,1,2,3,4,6,2];
function solution(A) {
array = new Array();
for (i = 1; i < A.length - 1; i++) {
if (A[i - 1] < A[i] && A[i + 1] < A[i]) {
array.push(i);
}
}
//console.log(A);
//console.log(array);
var position = array[0];
var counter = 1;
var len = array.length;
for (var i = 0; i < len; i++) {
if (Math.abs(array[i+1] - position) >= len) {
position = array[i+1];
counter ++;
}
}
console.log("total:",counter);
return counter;
}
The above code works for sample array elements: [1,5,3,4,3,4,1,2,3,4,6,2]
Get peaks at indices: [1, 3, 5, 10] and set flags at 1, 5, and 10 (total 3)
But codility.com says it fails on array [7, 10, 4, 5, 7, 4, 6, 1, 4, 3, 3, 7]
My code get peaks at indices: [1, 4, 6, 8] and set flags at 1 and 6 (total 2)
but coditity.com says it should be 3 flags. (no idea why)
Am I miss-understanding the question ?
Please I am only looking for the hint/algo. I know this question is already asked by someone and solved on private chatroom but on that page I tried to get the help with that person but members rather flagging my posts as inappropriate answer so I am asking the question here again.
P.S: You can try coding the challenge yourself here!
This is a solution with better upper complexity bounds:
time complexity: O(sqrt(N) * log(N))
space complexity: O(1) (over the original input storage)
Python implementation
from math import sqrt
def transform(A):
peak_pos = len(A)
last_height = A[-1]
for p in range(len(A) - 1, 0, -1):
if (A[p - 1] < A[p] > last_height):
peak_pos = p
last_height = A[p]
A[p] = peak_pos
A[0] = peak_pos
def can_fit_flags(A, k):
flag = 1 - k
for i in range(k):
# plant the next flag at A[flag + k]
if flag + k > len(A) - 1:
return False
flag = A[flag + k]
return flag < len(A) # last flag planted successfully
def solution(A):
transform(A)
lower = 0
upper = int(sqrt(len(A))) + 2
assert not can_fit_flags(A, k=upper)
while lower < upper - 1:
next = (lower + upper) // 2
if can_fit_flags(A, k=next):
lower = next
else:
upper = next
return lower
Description
O(N) preprocessing (done inplace):
A[i] := next peak or end position after or at position i
(i for a peak itself, len(A) after last peak)
If we can plant k flags then we can certainly plant k' < k flags as well.
If we can not plant k flags then we certainly can not plant k' > k flags either.
We can always set 0 flags.
Let us assume we can not set X flags.
Now we can use binary search to find out exactly how many flags can be planted.
Steps:
1. X/2
2. X/2 +- X/4
3. X/2 +- X/4 +- X/8
...
log2(X) steps in total
With the preprocessing done before, each step testing whether k flags can be planted can be performed in O(k) operations:
flag(0) = next(0)
flag(1) = next(flag(1) + k)
...
flag(k-1) = next(flag(k-2) + k)
total cost - worst case - when X - 1 flags can be planted:
== X * (1/2 + 3/4 + ... + (2^k - 1)/(2^k))
== X * (log2(X) - 1 + (<1))
<= X * log(X)
Using X == N would work, and would most likely also be sublinear, but is not good enough to use in a proof that the total upper bound for this algorithm is under O(N).
Now everything depends on finding a good X, and it since k flags take about k^2 positions to fit, it seems like a good upper limit on the number of flags should be found somewhere around sqrt(N).
If X == sqrt(N) or something close to it works, then we get an upper bound of O(sqrt(N) * log(sqrt(N))) which is definitely sublinear and since log(sqrt(N)) == 1/2 * log(N) that upper bound is equivalent to O(sqrt(N) * log(N)).
Let's look for a more exact upper bound on the number of required flags around sqrt(N):
we know k flags requires Nk := k^2 - k + 3 flags
by solving the equation k^2 - k + 3 - N = 0 over k we find that if k >= 3, then any number of flags <= the resulting k can fit in some sequence of length N and a larger one can not; solution to that equation is 1/2 * (1 + sqrt(4N - 11))
for N >= 9 we know we can fit 3 flags
==> for N >= 9, k = floor(1/2 * (1 + sqrt(4N - 11))) + 1 is a strict upper bound on the number of flags we can fit in N
for N < 9 we know 3 is a strict upper bound but those cases do not concern us for finding the big-O algorithm complexity
floor(1/2 * (1 + sqrt(4N - 11))) + 1
== floor(1/2 + sqrt(N - 11/4)) + 1
<= floor(sqrt(N - 11/4)) + 2
<= floor(sqrt(N)) + 2
==> floor(sqrt(N)) + 2 is also a good strict upper bound for a number of flags that can fit in N elements + this one holds even for N < 9 so it can be used as a generic strict upper bound in our implementation as well
If we choose X = floor(sqrt(N)) + 2 we get the following total algorithm upper bound:
O((floor(sqrt(N)) + 2) * log(floor(sqrt(N)) + 2))
{floor(...) <= ...}
O((sqrt(N) + 2) * log(sqrt(N) + 2))
{for large enough N >= 4: sqrt(N) + 2 <= 2 * sqrt(N)}
O(2 * sqrt(N) * log(2 * sqrt(N)))
{lose the leading constant}
O(sqrt(N) * (log(2) + loq(sqrt(N)))
O(sqrt(N) * log(2) + sqrt(N) * log(sqrt(N)))
{lose the lower order bound}
O(sqrt(N) * log(sqrt(N)))
{as noted before, log(sqrt(N)) == 1/2 * log(N)}
O(sqrt(N) * log(N))
QED
Missing 100% PHP solution :)
function solution($A)
{
$p = array(); // peaks
for ($i=1; $i<count($A)-1; $i++)
if ($A[$i] > $A[$i-1] && $A[$i] > $A[$i+1])
$p[] = $i;
$n = count($p);
if ($n <= 2)
return $n;
$maxFlags = min(intval(ceil(sqrt(count($A)))), $n); // max number of flags
$distance = $maxFlags; // required distance between flags
// try to set max number of flags, then 1 less, etc... (2 flags are already set)
for ($k = $maxFlags-2; $k > 0; $k--)
{
$left = $p[0];
$right = $p[$n-1];
$need = $k; // how many more flags we need to set
for ($i = 1; $i<=$n-2; $i++)
{
// found one more flag for $distance
if ($p[$i]-$left >= $distance && $right-$p[$i] >= $distance)
{
if ($need == 1)
return $k+2;
$need--;
$left = $p[$i];
}
if ($right - $p[$i] <= $need * ($distance+1))
break; // impossible to set $need more flags for $distance
}
if ($need == 0)
return $k+2;
$distance--;
}
return 2;
}
import java.util.Arrays;
import java.lang.Integer;
import java.util.ArrayList;
import java.util.List;
public int solution(int[] A)
{
ArrayList<Integer> array = new ArrayList<Integer>();
for (int i = 1; i < A.length - 1; i++)
{
if (A[i - 1] < A[i] && A[i + 1] < A[i])
{
array.add(i);
}
}
if (array.size() == 1 || array.size() == 0)
{
return array.size();
}
int sf = 1;
int ef = array.size();
int result = 1;
while (sf <= ef)
{
int flag = (sf + ef) / 2;
boolean suc = false;
int used = 0;
int mark = array.get(0);
for (int i = 0; i < array.size(); i++)
{
if (array.get(i) >= mark)
{
used++;
mark = array.get(i) + flag;
if (used == flag)
{
suc = true;
break;
}
}
}
if (suc)
{
result = flag;
sf = flag + 1;
}
else
{
ef = flag - 1;
}
}
return result;
}
C++ solution, O(N) detected
#include <algorithm>
int solution(vector<int> &a) {
if(a.size() < 3) return 0;
std::vector<int> peaks(a.size());
int last_peak = -1;
peaks.back() = last_peak;
for(auto i = ++a.rbegin();i != --a.rend();i++)
{
int index = a.size() - (i - a.rbegin()) - 1;
if(*i > *(i - 1) && *i > *(i + 1))
last_peak = index;
peaks[index] = last_peak;
}
peaks.front() = last_peak;
int max_flags = 0;
for(int i = 1;i*i <= a.size() + i;i++)
{
int next_peak = peaks[0];
int flags = 0;
for(int j = 0;j < i && next_peak != -1;j++, flags++)
{
if(next_peak + i >= a.size())
next_peak = -1;
else
next_peak = peaks[next_peak + i];
}
max_flags = std::max(max_flags, flags);
}
return max_flags;
}
100% Java solution with O(N) complexity.
https://app.codility.com/demo/results/trainingPNYEZY-G6Q/
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
int[] peaks = new int[A.length];
int peakStart = 0;
int peakEnd = 0;
//Find the peaks.
//We don't want to traverse the array where peaks hasn't started, yet,
//or where peaks doesn't occur any more.
//Therefore, find start and end points of the peak as well.
for(int i = 1; i < A.length-1; i++) {
if(A[i-1] < A[i] && A[i+1] < A[i]) {
peaks[i] = 1;
peakEnd = i + 1;
}
if(peakStart == 0) {
peakStart = i;
}
}
int x = 1;
//The maximum number of flags can be √N
int limit = (int)Math.ceil(Math.sqrt(A.length));
int prevPeak = 0;
int counter = 0;
int max = Integer.MIN_VALUE;
while(x <= limit) {
counter = 0;
prevPeak = 0;
for(int y = peakStart; y < peakEnd; y++) {
//Find the peak points when we have x number of flags.
if(peaks[y] == 1 && (prevPeak == 0 || x <= (y - prevPeak))) {
counter++;
prevPeak = y;
}
//If we don't have any more flags stop.
if(counter == x ) {
break;
}
}
//if the number of flags set on the peaks starts to reduce stop searching.
if(counter <= max) {
return max;
}
//Keep the maximum number of flags we set on.
max = counter;
x++;
}
return max;
}
}
There is a ratio between the number of flags we can take with us and
the number of flags we can set. We can not set more than √N number of
flags since N/√N = √N. If we set more than √N, we will end up with
decreasing number of flags set on the peaks.
When we increase the numbers of flags we take with us, the number of
flags we can set increases up to a point. After that point the number
of flags we can set will decrease. Therefore, when the number of
flags we can set starts to decrease once, we don't have to check the
rest of the possible solutions.
We mark the peak points at the beginning of the code, and we also
mark the first and the last peak points. This reduces the unnecessary
checks where the peaks starts at the very last elements of a large
array or the last peak occurs at the very first elements of a large
array.
Here is a C++ Solution with 100% score
int test(vector<int> &peaks,int i,int n)
{
int j,k,sum,fin,pos;
fin = n/i;
for (k=0; k< i; k++)
{
sum=0;
for (j=0; j< fin; j++)
{ pos = j + k * fin;
sum=sum + peaks[ pos ];
}
if (0==sum) return 0;
}
return 1;
}
int solution(vector<int> &A) {
// write your code in C++98
int i,n,max,r,j,salir;
n = A.size();
vector<int> peaks(n,0);
if (0==n) return 0;
if (1==n) return 0;
for (i=1; i< (n-1) ; i++)
{
if ( (A[i-1] < A[i]) && (A[i+1] < A[i]) ) peaks[i]=1;
}
i=1;
max=0;
salir =0;
while ( ( i*i < n) && (0==salir) )
{
if ( 0== n % i)
{
r=test(peaks,i,n);
if (( 1==r ) && (i>max)) max=i;
j = n/i;
r=test(peaks,j,n);
if (( 1==r ) && (j>max)) max=j;
if ( max > n/2) salir =1;
}
i++;
}
if (0==salir)
{
if (i*i == n)
{
if ( 1==test(peaks,i,n) ) max=i;
}
}
return max;
}
The first idea is that we cannot set more than sqrt(N) flags. Lets imagine that we've taken N flags, in this case we should have at least N * N items to set all the flags, because N it's the minimal distance between the flags. So, if we have N items its impossible to set more than sqrt(N) flags.
function solution(A) {
const peaks = searchPeaks(A);
const maxFlagCount = Math.floor(Math.sqrt(A.length)) + 1;
let result = 0;
for (let i = 1; i <= maxFlagCount; ++i) {
const flagsSet = setFlags(peaks, i);
result = Math.max(result, flagsSet);
}
return result;
}
function searchPeaks(A) {
const peaks = [];
for (let i = 1; i < A.length - 1; ++i) {
if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
peaks.push(i);
}
}
return peaks;
}
function setFlags(peaks, flagsTotal) {
let flagsSet = 0;
let lastFlagIndex = -flagsTotal;
for (const peakIndex of peaks) {
if (peakIndex >= lastFlagIndex + flagsTotal) {
flagsSet += 1;
lastFlagIndex = peakIndex;
if (flagsSet === flagsTotal) {
return flagsSet;
}
}
}
return flagsSet;
}
Such solution has O(N) complexity. We should iterate over A to find peaks and iterate from 1 to sqrt(N) flag counts trying to set all the flags. So we have O(N + 1 + 2 + 3 ... sqrt(N)) = O(N + sqrt(N*N)) = O(N) complexity.
Above solution is pretty fast and it gets 100% result, but it can be even more optimized. The idea is to binary search the flag count. Lets take F flags and try to set them all. If excess flags are left, the answer is less tan F. But, if all the flags have been set and there is space for more flags, the answer is greater than F.
function solution(A) {
const peaks = searchPeaks(A);
const maxFlagCount = Math.floor(Math.sqrt(A.length)) + 1;
return bSearchFlagCount(A, peaks, 1, maxFlagCount);
}
function searchPeaks(A) {
const peaks = [];
for (let i = 1; i < A.length - 1; ++i) {
if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
peaks.push(i);
}
}
return peaks;
}
function bSearchFlagCount(A, peaks, start, end) {
const mid = Math.floor((start + end) / 2);
const flagsSet = setFlags(peaks, mid);
if (flagsSet == mid) {
return mid;
} else if (flagsSet < mid) {
return end > start ? bSearchFlagCount(A, peaks, start, mid) : mid - 1;
} else {
return bSearchFlagCount(A, peaks, mid + 1, end);
}
}
function setFlags(peaks, flagsTotal) {
let flagsSet = 0;
let lastFlagIndex = -flagsTotal;
for (const peakIndex of peaks) {
if (peakIndex >= lastFlagIndex + flagsTotal) {
flagsSet += 1;
lastFlagIndex = peakIndex;
// It only matters that we can set more flags then were taken.
// It doesn't matter how many extra flags can be set.
if (flagsSet > flagsTotal) {
return flagsSet;
}
}
}
return flagsSet;
}
Here is the official Codility solutions of the task.
My C++ solution with 100% result
bool check(const vector<int>& v, int flags, int mid) {
if (not v.empty()) {
flags--;
}
int start = 0;
for (size_t i = 1; i < v.size(); ++i) {
if (v[i] - v[start] >= mid) {
--flags;
start = i;
}
}
return flags <= 0;
}
int solution(vector<int> &A) {
vector<int> peaks;
for (size_t i = 1; i < A.size() - 1; ++i) {
if (A[i] > A[i - 1] and A[i] > A[i + 1]) {
peaks.push_back(i);
}
}
int low = 0;
int high = peaks.size();
int res = 0;
while (low <= high) {
int mid = high - (high - low) / 2;
if (check(peaks, mid, mid)) {
low = mid + 1;
res = mid;
} else {
high = mid - 1;
}
}
return res;
}
public int solution(int[] A) {
int p = 0;
int q = 0;
int k = 0;
for (int i = 0; i < A.length; i++) {
if (i > 0 && i < A.length && (i + 1) < A.length - 1) {
if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
p = i;
if (i < A.length / 2)
k++;
}
if (i > 0 && i < A.length && (A.length - i + 1) < A.length) {
if (A[A.length - i] > A[A.length - i - 1]
&& A[A.length - i] > A[A.length - i + 1] ) {
q = A.length - i;
if (i < A.length / 2)
k++;
else {
if (Math.abs(p - q) < k && p != q)
k--;
}
}
}
}
}
return k;
}
import sys
def get_max_num_peaks(arr):
peaks = [i for i in range(1, len(arr)-1, 1) if arr[i]>arr[i-1] and arr[i]>arr[i+1]]
max_len = [1 for i in peaks]
smallest_diff = [0 for i in peaks]
smallest_diff[0] = sys.maxint
for i in range(1, len(peaks), 1):
result = 1
for j in range(0, i, 1):
m = min(smallest_diff[j], peaks[i]-peaks[j])
if smallest_diff[j]>0 and m>=max_len[j]+1:
max_len[i] = max_len[j]+1
smallest_diff[i] = m
result = max(result, max_len[i])
return result
if __name__ == "__main__":
result = get_max_num_peaks([7, 10, 4, 5, 7, 4, 6, 1, 4, 3, 3, 7])
print result
I used DP to solve this problem. Here is the python code:
The max num of flags can be set for array ending at i is the max num of flags can be set on j if min(min_diff(0 .. j), j to i) is no less than max_len(0 .. j)+1
Please correct me if I'm wrong or there is a O(N) solution
I know that the answer had been provided by francesco Malagrino, but i have written my own code. for the arrays {1,5,3,4,3,4,1,2,3,4,6,2} and { 7, 10, 4, 5, 7, 4, 6, 1, 4, 3, 3, 7 } my code is working just fine. and when I took my code on the codility exams i had failed on {9, 9, 4, 3, 5, 4, 5, 2, 8, 9, 3, 1}
my answer resulted to 3 maximum flags. the way I understand it it supposed to be 3 but instead
the correct answer is 2, and also with also in respect to francesco Malagrino's solution.
what seems to be wrong in my code and how come the answer should only be 2 the fact that
distances between peaks 4, 6, 9 followed the rule.
private static int getpeak(int[] a) {
List<Integer> peak = new ArrayList<Integer>();
int temp1 = 0;
int temp2 = 0;
int temp3 = 0;
for (int i = 1; i <= (a.length - 2); i++) {
temp1 = a[i - 1];
temp2 = a[i];
temp3 = a[i + 1];
if (temp2 > temp1 && temp2 > temp3) {
peak.add(i);
}
}
Integer[] peakArray = peak.toArray(new Integer[0]);
int max = 1;
int lastFlag = 0;
for (int i = 1; i <= peakArray.length - 1; i++) {
int gap = peakArray[i] - peakArray[lastFlag];
gap = Math.abs(gap);
if (gap >= i+1) {
lastFlag = i;
max = max + 1;
}
}
return max;
}
I cam up with an algorithm for this problem that is both of O(N) and passed all of the codility tests. The main idea is that the number of flags can not be more than the square root of N. So to keep the total order linear, each iteration should be less than the square root of N too, which is the number of flags itself.
So first, I built an array nextPeak that for each index of A provides the closest flag after the index.
Then, in the second part, I iterate f over all possible number of flags from root of N back to 0 to find the maximum number of flags that can be applied on the array. In each iteration, I try to apply the flags and use the nextPeak array to find the next peak in constant time.
The code looks like this:
public int solution(int[] A){
if( A==null || A.length<3){
return 0;
}
int[] next = new int[A.length];
int nextPeak=-1;
for(int i =1; i<A.length; i++){
if(nextPeak<i){
for(nextPeak=i; nextPeak<A.length-1; nextPeak++){
if(A[nextPeak-1]<A[nextPeak] && A[nextPeak]>A[nextPeak+1]){
break;
}
}
}
next[i] = nextPeak;
}
next[0] = next[1];
int max = new Double(Math.sqrt(A.length)).intValue();
boolean failed = true ;
int f=max;
while(f>0 && failed){
int v=0;
for(int p=0; p<A.length-1 && next[p]<A.length-1 && v<f; v++, p+=max){
p = next[p];
}
if(v<f){
f--;
} else {
failed = false;
}
}
return f;
}
Here is a 100% Java solution
class Solution {
public int solution(int[] A) {
int[] nextPeaks = nextPeaks(A);
int flagNumebr = 1;
int result = 0;
while ((flagNumebr-1)*flagNumebr <= A.length) {
int flagPos = 0;
int flagsTaken = 0;
while (flagPos < A.length && flagsTaken < flagNumebr) {
flagPos = nextPeaks[flagPos];
if (flagPos == -1) {
// we arrived at the end of the peaks;
break;
}
flagsTaken++;
flagPos += flagNumebr;
}
result = Math.max(result, flagsTaken);
flagNumebr++;
}
return result;
}
private boolean[] createPeaks(int[] A) {
boolean[] peaks = new boolean[A.length];
for (int i = 1; i < A.length-1; i++) {
if (A[i - 1] < A[i] && A[i] > A[i + 1]) {
peaks[i] = true;
}
}
return peaks;
}
private int[] nextPeaks (int[] A) {
boolean[] peaks = createPeaks(A);
int[] nextPeaks = new int[A.length];
// the last position is always -1
nextPeaks[A.length-1] = -1;
for (int i = A.length-2; i >= 0 ; i--) {
nextPeaks[i] = peaks[i] ? i : nextPeaks[i+1];
}
return nextPeaks;
}
}
to solve this problem:
you have to find peaks
calculate distance (indices differences) between every 2 peaks
Initially the number of flags is the same number of peaks
compare distance between every 2 peaks with the initially specified number of flags ([P - Q] >= K)
after the comparison you will find that you have to avoid some peaks
the final number of maximum flags is the same number of remain peaks
** I'm still searching for how to write the best optimized code for this problem
C# Solution with 100% points.
using System;
using System.Collections.Generic;
class Solution {
public int solution(int[] A) {
// write your code in C# 6.0 with .NET 4.5 (Mono)
List<int> peaks = new List<int>();
for (int i = 1; i < A.Length - 1; i++)
{
if (A[i - 1] < A[i] && A[i + 1] < A[i])
{
peaks.Add(i);
}
}
if (peaks.Count == 1 || peaks.Count == 0)
{
return peaks.Count;
}
int leastFlags = 1;
int mostFlags = peaks.Count;
int result = 1;
while (leastFlags <= mostFlags)
{
int flags = (leastFlags + mostFlags) / 2;
bool suc = false;
int used = 0;
int mark = peaks[0];
for (int i = 0; i < peaks.Count; i++)
{
if (peaks[i] >= mark)
{
used++;
mark = peaks[i] + flags;
if (used == flags)
{
suc = true;
break;
}
}
}
if (suc)
{
result = flags;
leastFlags = flags + 1;
}
else
{
mostFlags = flags - 1;
}
}
return result;
}
}
100% working JS solution:
function solution(A) {
let peaks = [];
for (let i = 1; i < A.length - 1; i++) {
if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
peaks.push(i);
}
}
let n = peaks.length;
if (n <= 2) {
return n;
}
let maxFlags = Math.min(n, Math.ceil(Math.sqrt(A.length)));
let distance = maxFlags;
let rightPeak = peaks[n - 1];
for (let k = maxFlags - 2; k > 0; k--) {
let flags = k;
let leftPeak = peaks[0];
for (let i = 1; i <= n - 2; i++) {
if (peaks[i] - leftPeak >= distance && rightPeak - peaks[i] >= distance) {
if (flags === 1) {
return k + 2;
}
flags--;
leftPeak = peaks[i];
}
if (rightPeak - peaks[i] <= flags * (distance + 1)) {
break;
}
}
if (flags === 0) {
return k + 2;
}
distance--;
}
return 2;
}
100 % python O(N) detected.
import math
def solution(A):
N=len(A)
#Trivial cases
if N<3:
return 0
Flags_Idx=[]
for p in range(1,N-1):
if A[p-1]<A[p] and A[p]>A[p+1] :
Flags_Idx.append(p)
if len(Flags_Idx)==0:
return 0
if len(Flags_Idx)<=2:
return len(Flags_Idx)
Start_End_Flags=Flags_Idx[len(Flags_Idx)-1]-Flags_Idx[0]
#Maximum number of flags N is such that Start_End_Flags/(N-1)>=N
#After solving a second degree equation we obtain the maximal value of N
num_max_flags=math.floor(1.0+math.sqrt(4*Start_End_Flags+1.0))/2.0
#Set the current number of flags to its total number
len_flags=len(Flags_Idx)
min_peaks=len(Flags_Idx)
p=0
#Compute the minimal number of flags by checking each indexes
#and comparing to the maximal theorique value num_max_flags
while p<len_flags-1:
add = 1
#Move to the next flag until the condition Flags_Idx[p+add]-Flags_Idx[p]>=min(num_max_flags,num_flags)
while Flags_Idx[p+add]-Flags_Idx[p]<min(num_max_flags,min_peaks):
min_peaks-=1
if p+add<len_flags-1:
add+=1
else:
p=len_flags
break
p+=add
if num_max_flags==min_peaks:
return min_peaks
#Bisect the remaining flags : check the condition
#for flags in [min_peaks,num_max_flags]
num_peaks=min_peaks
for nf in range (min_peaks,int(num_max_flags)+1):
cnt=1
p=0
while p<len_flags-1:
add = 1
while Flags_Idx[p+add]-Flags_Idx[p]<nf:
if p+add<len_flags-1:
add+=1
else:
cnt-=1
p=len_flags
break
p+=add
cnt+=1
num_peaks=max(min(cnt,nf),num_peaks)
return num_peaks
I first computed the maximal possible number of flags verifying the condition
Interval/(N-1) >= N , where Interval is the index difference between first and last flag. Then browsing all the flags comparing with the minimum of this value and the current number of flags. Subtract if the condition is not verified.
Obtained the minimal number of flags and use it as a starting point to check the condition
on the remaining ones (in interval [min_flag,max_flag]).
100% python solution which is far simpler than the one posted above by #Jurko Gospodnetić
https://github.com/niall-oc/things/blob/master/codility/flags.py
https://app.codility.com/demo/results/training2Y78NP-VHU/
You don't need to do a binary search on this problem. MAX flags is the (square root of the (spread between first and last flag)) +1. First peak at index 9 and last peak at index 58 means the spread is sqrt(49) which is (7)+1. So try 8 flags then 7 then 6 and so on. You should break after your solution peaks! no need to flog a dead horse!
def solution(A):
peak=[x for x in range(1,len(A))if A[x-1]<A[x]>A[x+1]]
max_flag=len(peak)
for x in range(1,max_flag+1):
for y in range(x-1):
if abs(peak[y]-peak[y+1])>=max_flag:
max_flag=max_flag-1
print(max_flag)**strong text**
I got 100% with this solution in Java. I did one thing for the first loop to find peaks, i.e. after finding the peak I am skipping the next element as it is less than the peak.
I know this solution can be further optimized by group members but this is the best I can do as of now, so please let me know how can I optimize this more.
Detected time complexity: O(N)
https://app.codility.com/demo/results/trainingG35UCA-7B4/
public static int solution(int[] A) {
int N = A.length;
if (N < 3)
return 0;
ArrayList<Integer> peaks = new ArrayList<Integer>();
for (int i = 1; i < N - 1; i++) {
if (A[i] > A[i - 1]) {
if (A[i] > A[i + 1]) {
peaks.add(i);
i++;// skip for next as A[i + 1] < A[i] so no need to check again
}
}
}
int size = peaks.size();
if (size < 2)
return size;
int k = (int) Math.sqrt(peaks.get(size - 1) - peaks.get(0))+1; // added 1 to round off
int flagsLeft = k - 1; // one flag is used for first element
int maxFlag = 0;
int prevEle = peaks.get(0);
while (k > 0) { // will iterate in descending order
flagsLeft = k - 1; // reset first peak flag
prevEle = peaks.get(0); // reset the flag to first element
for (int i = 1; i < size && flagsLeft > 0; i++) {
if (peaks.get(i) - prevEle >= k) {
flagsLeft--;
prevEle = peaks.get(i);
}
if ((size - 1 - i) < flagsLeft) { // as no. of peaks < flagsLeft
break;
}
}
if (flagsLeft == 0 && maxFlag < k) {
maxFlag = k;
break; // will break at first highest flag as iterating in desc order
}
k--;
}
return maxFlag;
}
int solution(int A[], int N) {
int i,j,k;
int count=0;
int countval=0;
int count1=0;
int flag;
for(i=1;i<N-1;i++)
{`enter code here`
if((A[i-1]<A[i]) && (A[i]>A[i+1]))
{
printf("%d %d\n",A[i],i);
A[count++]=i;
i++;
}
}
j=A[0];
k=0;
if (count==1 || count==0)
return count;
if (count==2)
{
if((A[1]-A[0])>=count)
return 2;
else
return 1;
}
flag=0;
// contval=count;
count1=1;
countval=count;
while(1)
{
for(i=1;i<count;i++)
{
printf("%d %d\n",A[i],j);
if((A[i]-j)>=countval)
{
printf("Added %d %d\n",A[i],j);
count1++;
j=A[i];
}
/* if(i==count-1 && count1<count)
{
j=A[0];
i=0;
count1=1;
}*/
}
printf("count %d count1 %d \n",countval,count1);
if (count1<countval)
{
count1=1;
countval--;
j=A[0];
}
else
{
break; }
}
return countval;
}

Categories

Resources