JavaScript: Improve performance inside nested loops - javascript

how can I optimize the incredibly slow code shown below to speed? I think, JS converts the ints to floats and vise-versa all the time. How can I spot such performance killers? I think, there is much space left to optimize :-). I think, there is a better way to handle the nibble values.
At first, I tried to ditch the &15 operation for the higher nibble. That just slowed more down instead of speed up.
(The code is incomplete. It is just a part taken from a bigger one. It is filling a buffer for createBufferSource(). It should be processed an played as soon as possible after a click event. Currently, on a mobile, it takes up to 2s for an average audio file.)
for (var len = adpcm.length, i = 0; i < len; i++) {
n = [
adpcm.charCodeAt(i) & 15,
(adpcm.charCodeAt(i) >> 4) & 15
];
for (var j = 0; j < 2; j++) {
s = n[j];
stp = imaStepTable[index];
diff = stp >> 3;
if (s & 4) diff += stp;
if (s & 2) diff += (stp >> 1);
if (s & 1) diff += (stp >> 2);
if (s & 8) diff = 0 - diff;
pred += diff;
if (pred > 32760) pred = 32760;
else if (pred < -32760) pred = -32760; //limiter
index += imaIndexTable[s];
if (index < 0) index = 0;
else if (index > 88) index = 88;
for (var k = 0; k < sampleScale; k++) { //resampler
if (!k) {
lPcm[c] = pred / 32768;
rPcm[c] = (c - shift) < 0 ? 0 : lPcm[(c - shift)];
} else {
lPcm[c] = lPcm[c - k];
rPcm[c] = rPcm[c - k];
}
c++;
}
}
}

Related

The algorithm problem: Unique Paths III. Using backtracing pattern in javascript and not work

On a 2-dimensional grid, there are 4 types of squares:
1 represents the starting square.  There is exactly one starting square.
2 represents the ending square.  There is exactly one ending square.
0 represents empty squares we can walk over.
-1 represents obstacles that we cannot walk over.
Return the number of 4-directional walks from the starting square to the ending square, that walk over every non-obstacle square exactly once.
source:力扣(LeetCode)
link:https://leetcode-cn.com/problems/unique-paths-iii
i'm trying to use backtrack pattern to solve this problem
here is my code
/**
* #param {number[][]} grid
* #return {number}
*/
var uniquePathsIII = function(grid) {
let m = grid.length,
n = grid[0].length;
let start, targetIndex1,targetIndex2;
let res = 0;
let zero_counts = 0;
for(let i = 0; i < m; i++){
for(let j = 0; j < n; j++){
if(grid[i][j] == 1){
start = [i,j]
}
else if(grid[i][j] == 0){
zero_counts += 1;
}
else if(grid[i][j] == 2){
targetIndex1 = i;
targetIndex2 = j;
}
}
}
const backtrace = (i, j, zero_count) => {
if( i < 0 || i >= m ||
j < 0 || j >= n ||
grid[i][j] == -1 || zero_count < 0)
{
return;
}
if(i == targetIndex1 && j == targetIndex2 ){
if(zero_count == 0)
{
console.log("yes")
res += 1;
}
return
}
grid[i][j] = -1;
backtrace(i+1, j, zero_count - 1)
backtrace(i-1, j, zero_count - 1)
backtrace(i, j+1, zero_count - 1)
backtrace(i, j-1, zero_count - 1)
grid[i][j] = 0;
}
backtrace(start[0], start[1], zero_counts);
return res;
};
test sample:
[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
expect result:
2
acutal result:
0
Perhaps a simpler solution is to use Depth First Search to solve Unique Paths III, as shown here.
The concept is that you take a point and then traverse in all directions until you hit an obstacle.
The guts are as follows:
int totalPaths = dfs(grid, x+1, y, zero) +
dfs(grid, x, y+1, zero) +
dfs(grid, x-1, y, zero) +
dfs(grid, x, y-1, zero);

Trying to multiply the first two numbers that results to a particular number, is there way i can do this without using nested loops?

Here is the full solution, please is there much better ways to go about this
the question is getting total number of squares in a box but in the inverse way, for example the normal question is 2,9 and the total number of available squares will be 26. but i was given the question in another way such that 26 will be given and im to find all the possible ways m and n can be arranged so the total number of squares will be the given question, which is 26
The code actually works but i need a faster way to do this.
const n = 26;
function count(m, n) {
if (n < m) {
const temp = n;
n = m;
m = temp;
}
return m * (m + 1) * (2 * m + 1) /
6 + (n - m) * m * (m + 1) / 2;
}
const arr = [];
const len = n + 1;
for (let i = 1; i < len; i++) {
if(i<len/2) {
}
for (let b = 1; b < len; b++) {
if (i === 1) {
arr.push(`${i} ${n}`);
break;
} else if (i === n) {
arr.push(`${n} 1`);
break;
} else {
const sum = count(i, b);
if (sum == n) {
arr.push(`${i} ${b}`);
break;
}
}
}
}
const arrLength = arr.length;
console.log(arrLength); //shows the length of the array
for (let g = 0; g < arrLength; g++) {
console.log(arr[g]); // shows each ways it can be arranged to give 26
}

Bug when attempting to time my JavaScript functions

I was given the challenge which is essentially: given an array of numbers as input, find the greatest difference between any two numbers, given that j < i, and input[i] > input[j].
I wrote two solutions, one a brute-force double nested loop and the other my attempt at optimizing it. They are as follows:
// Brute Force Method
function findGreatestDiffV1(nums) {
let start = new Date().getTime();
let greatestDiff = 0;
for (let i = 1; i < nums.length; i++) {
for (let j = 0; j < i; j++) {
let diff = nums[i] - nums[j];
if (diff > greatestDiff) greatestDiff = diff;
}
}
console.log(((new Date().getTime() - start) / 1000.0) + " Seconds");
return greatestDiff;
}
// Optimized method
function findGreatestDiffV2(nums) {
let start = new Date().getTime();
let smallestNum = nums[0];
let greatestDiff = 0;
for (let i = 1; i < nums.length; i++) {
if (nums[i] < smallestNum) smallestNum = nums[i];
if ((nums[i] - smallestNum) < greatestDiff) continue;
for (let j = 0; j < i; j++) {
let diff = nums[i] - nums[j];
if (diff > greatestDiff) greatestDiff = diff;
}
}
console.log(((new Date().getTime() - start) / 1000.0) + " Seconds");
return greatestDiff;
}
These work fine, and output both the correct results as well as the expected run-times, i.e. significantly lower for V2 for larger datasets.
I then modified them to return only the run-times:
function findGreatestDiffV1Time(nums) {
let start = new Date().getTime();
let greatestDiff = 0;
for (let i = 1; i < nums.length; i++) {
for (let j = 0; j < i; j++) {
let diff = nums[i] - nums[j];
if (diff > greatestDiff) greatestDiff = diff;
}
}
return ((new Date().getTime() - start) / 1000.0);
}
function findGreatestDiffV2Time(nums) {
let start = new Date().getTime();
let smallestNum = nums[0];
let greatestDiff = 0;
for (let i = 1; i < nums.length; i++) {
if (nums[i] < smallestNum) smallestNum = nums[i];
if ((nums[i] - smallestNum) < greatestDiff) continue;
for (let j = 0; j < i; j++) {
let diff = nums[i] - nums[j];
if (diff > greatestDiff) greatestDiff = diff;
}
}
return ((new Date().getTime() - start) / 1000.0);
}
I created this helper function, which generates inputs of length numOfDiffs and of greatest individual number maxDiff:
function generateDiffs(numOfDiffs, maxDiff) {
let diffs = [];
for (let i = 0; i < numOfDiffs; i++) {
diffs.push(Math.floor(Math.random() * maxDiff));
}
return diffs;
}
However, this is the point where things are bugging out and I cannot figure out why.
When using the versions which only return the run-time, regardless of the size of the input, I'm getting a time of 0 for V1. V2 is returning the correct time for any size set, but V1 continues to escape almost immediately and return 0.
The most likely issue is that I have an obvious bug somewhere, but I'm wondering if it might be some misunderstanding of how JavaScript performs some function, or even scope bleed somewhere. But regardless, I can't locate it and it's driving me crazy.
So, #Barmar was the man here. Chrome absolutely was attempting to optimize my code by skipping everything it saw was never being returned by the function. Once I changed my return value to
return [((new Date().getTime() - start) / 1000.0), greatestDiff];
I began getting the expected results.
And it is definitely interesting that I wasn't getting this for V2; as Barmar said, it's likely that the more complex instructions were causing Chrome to err on the side of caution.
Also, for the record, here was the function I wrote to calculate the run-times.
function runTimes(numOfDiffs, maxDiff) {
let runTimeDiffs = generateDiffs(numOfDiffs, maxDiff)
let timesV1 = 0;
let timesV2 = 0;
for (let x = 0; x < 10; x++) {
timesV1 += findGreatestDiffV1Time(runTimeDiffs)[0];
timesV2 += findGreatestDiffV2Time(runTimeDiffs)[0];
}
console.log(`V1 times for numOfDiffs = ${numOfDiffs} and maxDiff = ${maxDiff} was: ${timesV1 / 10} seconds.`)
console.log(`V2 times for numOfDiffs = ${numOfDiffs} and maxDiff = ${maxDiff} was: ${timesV2 / 10} seconds.`)
}
As for #gcampbell's suggestion of using performance.now, I'll look into that; I wasn't familiar with that functionality. Good to know these things :)

Compare strings with 'similar' letters [duplicate]

So I have a random javascript array of names...
[#larry,#nicholas,#notch] etc.
They all start with the # symbol. I'd like to sort them by the Levenshtein Distance so that the the ones at the top of the list are closest to the search term. At the moment, I have some javascript that uses jQuery's .grep() on it using javascript .match() method around the entered search term on key press:
(code edited since first publish)
limitArr = $.grep(imTheCallback, function(n){
return n.match(searchy.toLowerCase())
});
modArr = limitArr.sort(levenshtein(searchy.toLowerCase(), 50))
if (modArr[0].substr(0, 1) == '#') {
if (atRes.childred('div').length < 6) {
modArr.forEach(function(i){
atRes.append('<div class="oneResult">' + i + '</div>');
});
}
} else if (modArr[0].substr(0, 1) == '#') {
if (tagRes.children('div').length < 6) {
modArr.forEach(function(i){
tagRes.append('<div class="oneResult">' + i + '</div>');
});
}
}
$('.oneResult:first-child').addClass('active');
$('.oneResult').click(function(){
window.location.href = 'http://hashtag.ly/' + $(this).html();
});
It also has some if statements detecting if the array contains hashtags (#) or mentions (#). Ignore that. The imTheCallback is the array of names, either hashtags or mentions, then modArr is the array sorted. Then the .atResults and .tagResults elements are the elements that it appends each time in the array to, this forms a list of names based on the entered search terms.
I also have the Levenshtein Distance algorithm:
var levenshtein = function(min, split) {
// Levenshtein Algorithm Revisited - WebReflection
try {
split = !("0")[0]
} catch(i) {
split = true
};
return function(a, b) {
if (a == b)
return 0;
if (!a.length || !b.length)
return b.length || a.length;
if (split) {
a = a.split("");
b = b.split("")
};
var len1 = a.length + 1,
len2 = b.length + 1,
I = 0,
i = 0,
d = [[0]],
c, j, J;
while (++i < len2)
d[0][i] = i;
i = 0;
while (++i < len1) {
J = j = 0;
c = a[I];
d[i] = [i];
while(++j < len2) {
d[i][j] = min(d[I][j] + 1, d[i][J] + 1, d[I][J] + (c != b[J]));
++J;
};
++I;
};
return d[len1 - 1][len2 - 1];
}
}(Math.min, false);
How can I work with algorithm (or a similar one) into my current code to sort it without bad performance?
UPDATE:
So I'm now using James Westgate's Lev Dist function. Works WAYYYY fast. So performance is solved, the issue now is using it with source...
modArr = limitArr.sort(function(a, b){
levDist(a, searchy)
levDist(b, searchy)
});
My problem now is general understanding on using the .sort() method. Help is appreciated, thanks.
Thanks!
I wrote an inline spell checker a few years ago and implemented a Levenshtein algorithm - since it was inline and for IE8 I did quite a lot of performance optimisation.
var levDist = function(s, t) {
var d = []; //2d matrix
// Step 1
var n = s.length;
var m = t.length;
if (n == 0) return m;
if (m == 0) return n;
//Create an array of arrays in javascript (a descending loop is quicker)
for (var i = n; i >= 0; i--) d[i] = [];
// Step 2
for (var i = n; i >= 0; i--) d[i][0] = i;
for (var j = m; j >= 0; j--) d[0][j] = j;
// Step 3
for (var i = 1; i <= n; i++) {
var s_i = s.charAt(i - 1);
// Step 4
for (var j = 1; j <= m; j++) {
//Check the jagged ld total so far
if (i == j && d[i][j] > 4) return n;
var t_j = t.charAt(j - 1);
var cost = (s_i == t_j) ? 0 : 1; // Step 5
//Calculate the minimum
var mi = d[i - 1][j] + 1;
var b = d[i][j - 1] + 1;
var c = d[i - 1][j - 1] + cost;
if (b < mi) mi = b;
if (c < mi) mi = c;
d[i][j] = mi; // Step 6
//Damerau transposition
if (i > 1 && j > 1 && s_i == t.charAt(j - 2) && s.charAt(i - 2) == t_j) {
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
}
}
}
// Step 7
return d[n][m];
}
I came to this solution:
var levenshtein = (function() {
var row2 = [];
return function(s1, s2) {
if (s1 === s2) {
return 0;
} else {
var s1_len = s1.length, s2_len = s2.length;
if (s1_len && s2_len) {
var i1 = 0, i2 = 0, a, b, c, c2, row = row2;
while (i1 < s1_len)
row[i1] = ++i1;
while (i2 < s2_len) {
c2 = s2.charCodeAt(i2);
a = i2;
++i2;
b = i2;
for (i1 = 0; i1 < s1_len; ++i1) {
c = a + (s1.charCodeAt(i1) === c2 ? 0 : 1);
a = row[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
row[i1] = b;
}
}
return b;
} else {
return s1_len + s2_len;
}
}
};
})();
See also http://jsperf.com/levenshtein-distance/12
Most speed was gained by eliminating some array usages.
Updated: http://jsperf.com/levenshtein-distance/5
The new Revision annihilates all other benchmarks. I was specifically chasing Chromium/Firefox performance as I don't have an IE8/9/10 test environment, but the optimisations made should apply in general to most browsers.
Levenshtein Distance
The matrix to perform Levenshtein Distance can be reused again and again. This was an obvious target for optimisation (but be careful, this now imposes a limit on string length (unless you were to resize the matrix dynamically)).
The only option for optimisation not pursued in jsPerf Revision 5 is memoisation. Depending on your use of Levenshtein Distance, this could help drastically but was omitted due to its implementation specific nature.
// Cache the matrix. Note this implementation is limited to
// strings of 64 char or less. This could be altered to update
// dynamically, or a larger value could be used.
var matrix = [];
for (var i = 0; i < 64; i++) {
matrix[i] = [i];
matrix[i].length = 64;
}
for (var i = 0; i < 64; i++) {
matrix[0][i] = i;
}
// Functional implementation of Levenshtein Distance.
String.levenshteinDistance = function(__this, that, limit) {
var thisLength = __this.length, thatLength = that.length;
if (Math.abs(thisLength - thatLength) > (limit || 32)) return limit || 32;
if (thisLength === 0) return thatLength;
if (thatLength === 0) return thisLength;
// Calculate matrix.
var this_i, that_j, cost, min, t;
for (i = 1; i <= thisLength; ++i) {
this_i = __this[i-1];
for (j = 1; j <= thatLength; ++j) {
// Check the jagged ld total so far
if (i === j && matrix[i][j] > 4) return thisLength;
that_j = that[j-1];
cost = (this_i === that_j) ? 0 : 1; // Chars already match, no ++op to count.
// Calculate the minimum (much faster than Math.min(...)).
min = matrix[i - 1][j ] + 1; // Deletion.
if ((t = matrix[i ][j - 1] + 1 ) < min) min = t; // Insertion.
if ((t = matrix[i - 1][j - 1] + cost) < min) min = t; // Substitution.
matrix[i][j] = min; // Update matrix.
}
}
return matrix[thisLength][thatLength];
};
Damerau-Levenshtein Distance
jsperf.com/damerau-levenshtein-distance
Damerau-Levenshtein Distance is a small modification to Levenshtein Distance to include transpositions. There is very little to optimise.
// Damerau transposition.
if (i > 1 && j > 1 && this_i === that[j-2] && this[i-2] === that_j
&& (t = matrix[i-2][j-2]+cost) < matrix[i][j]) matrix[i][j] = t;
Sorting Algorithm
The second part of this answer is to choose an appropriate sort function. I will upload optimised sort functions to http://jsperf.com/sort soon.
I implemented a very performant implementation of levenshtein distance calculation if you still need this.
function levenshtein(s, t) {
if (s === t) {
return 0;
}
var n = s.length, m = t.length;
if (n === 0 || m === 0) {
return n + m;
}
var x = 0, y, a, b, c, d, g, h, k;
var p = new Array(n);
for (y = 0; y < n;) {
p[y] = ++y;
}
for (; (x + 3) < m; x += 4) {
var e1 = t.charCodeAt(x);
var e2 = t.charCodeAt(x + 1);
var e3 = t.charCodeAt(x + 2);
var e4 = t.charCodeAt(x + 3);
c = x;
b = x + 1;
d = x + 2;
g = x + 3;
h = x + 4;
for (y = 0; y < n; y++) {
k = s.charCodeAt(y);
a = p[y];
if (a < c || b < c) {
c = (a > b ? b + 1 : a + 1);
}
else {
if (e1 !== k) {
c++;
}
}
if (c < b || d < b) {
b = (c > d ? d + 1 : c + 1);
}
else {
if (e2 !== k) {
b++;
}
}
if (b < d || g < d) {
d = (b > g ? g + 1 : b + 1);
}
else {
if (e3 !== k) {
d++;
}
}
if (d < g || h < g) {
g = (d > h ? h + 1 : d + 1);
}
else {
if (e4 !== k) {
g++;
}
}
p[y] = h = g;
g = d;
d = b;
b = c;
c = a;
}
}
for (; x < m;) {
var e = t.charCodeAt(x);
c = x;
d = ++x;
for (y = 0; y < n; y++) {
a = p[y];
if (a < c || d < c) {
d = (a > d ? d + 1 : a + 1);
}
else {
if (e !== s.charCodeAt(y)) {
d = c + 1;
}
else {
d = c;
}
}
p[y] = d;
c = a;
}
h = d;
}
return h;
}
It was my answer to a similar SO question
Fastest general purpose Levenshtein Javascript implementation
Update
A improved version of the above is now on github/npm see
https://github.com/gustf/js-levenshtein
The obvious way of doing this is to map each string to a (distance, string) pair, then sort this list, then drop the distances again. This way you ensure the levenstein distance only has to be computed once. Maybe merge duplicates first, too.
I would definitely suggest using a better Levenshtein method like the one in #James Westgate's answer.
That said, DOM manipulations are often a great expense. You can certainly improve your jQuery usage.
Your loops are rather small in the example above, but concatenating the generated html for each oneResult into a single string and doing one append at the end of the loop will be much more efficient.
Your selectors are slow. $('.oneResult') will search all elements in the DOM and test their className in older IE browsers. You may want to consider something like atRes.find('.oneResult') to scope the search.
In the case of adding the click handlers, we may want to do one better avoid setting handlers on every keyup. You could leverage event delegation by setting a single handler on atRest for all results in the same block you are setting the keyup handler:
atRest.on('click', '.oneResult', function(){
window.location.href = 'http://hashtag.ly/' + $(this).html();
});
See http://api.jquery.com/on/ for more info.
I just wrote an new revision: http://jsperf.com/levenshtein-algorithms/16
function levenshtein(a, b) {
if (a === b) return 0;
var aLen = a.length;
var bLen = b.length;
if (0 === aLen) return bLen;
if (0 === bLen) return aLen;
var len = aLen + 1;
var v0 = new Array(len);
var v1 = new Array(len);
var i = 0;
var j = 0;
var c2, min, tmp;
while (i < len) v0[i] = i++;
while (j < bLen) {
c2 = b.charAt(j++);
v1[0] = j;
i = 0;
while (i < aLen) {
min = v0[i] - (a.charAt(i) === c2 ? 1 : 0);
if (v1[i] < min) min = v1[i];
if (v0[++i] < min) min = v0[i];
v1[i] = min + 1;
}
tmp = v0;
v0 = v1;
v1 = tmp;
}
return v0[aLen];
}
This revision is faster than the other ones. Works even on IE =)

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