Maximum Product Subarray
Given an array that contains both positive and negative integers, find the subarray of the maximum product .
Examples:
Input: arr[] = {6, -3, -10, 0, 2}
Output: The subarray is {6, -3, -10}
Input: arr[] = {-1, -3, -10, 0, 60}
Output: The subarray is {60}
Input: arr[] = {-2, -3, 0, -2, -40}
Output: The subarray is {-2, -40}
Note: Finding the Max Product is done as using the kadane algo where i tried to reuse it for finding sub array but not able to break the part of finding the start index, finding end index is easy. end index is where res < max.
public int maxProductSubArray(int arr[], int len) {
int res = arr[0];
int max = arr[0];
int min = arr[0];
for (int i = 1; i < len; i++) {
int temp = max;
max = Math.max(Math.max(max * arr[i], min * arr[i]), arr[i]);
min = Math.min(Math.min(temp * arr[i], min * arr[i]), arr[i]);
res = Math.max(res, max);
}
return res;
}
but not able to break the problem to find the SubArray.
There are several possible ways to solve this problem:
Brute-Force
Divide-and-Conquer
Backtracking
I will only show you the Brute-Force-Solution. It is not the fastest solution, but in my opinion the most clear and easily understandable solution:
public class SubArray {
public static int findMax(int[] num) {
int max = num[0];
int start = 0;
int end = 0;
for(int i = 0; i < num.length; i++) { //Iterating over every possible starting position
for(int j = i; j < num.length; j++) { //Iterating over every possible end position
int multiply = 1;
for(int k = i; k <= j; k++) { //Multiply from start to end
multiply *= num[k];
}
if(max < multiply) { //Did we find a new maximum?
max = multiply;
start = i;
end = j;
}
}
}
System.out.print("The subarray is {"); //Print subarray with highest product
for(int i = start; i <= end; i++) {
System.out.print(num[i]);
if(i < end) {
System.out.print(", ");
}
}
System.out.println("}");
return max;
}
public static void main(String[] args) {
int[] array = {6, -3, -10, 0, 2} ;
int max = findMax(array);
System.out.println("Maximal product is: " + max);
}
}
This problem can be efficiently solved by divide and conquer.
Assume you want to solve the problem for a subarray [l, r]; Then, assuming c = (l + r) / 2 the solution is either subarray in [l, c], or in [c + 1, r], or in some subarray containing c and c + 1.
Then let's define a function f(l, r) returning the answer for subsegment; Then, to compute this function, first recursively call f(l, c) and f(c + 1, r) and pick the maximum as the temporary answer. Then compute multiplications of segments [c, c], then [c - 1, c] and so on (using multiplication of [c - k, c] = multiplication of [c - k + 1, c] * array[c - k]) and compute maximum and minimum multiplications across all such segments. Do the same for segments to the right of c ([c + 1, c + 1], [c + 1, c + 2] and so on) Then, the answer will be either a temporary answer, of multiplication of maximums or multiplication of minimums or multiplication of minimum and maximum and vice versa (minimum times maximum is required if such multiplication would be negative). Return the maximum across these four values or the temporary answer as the function result.
If it is necessary, instead of returning just the value of multiplication function can also return the segment where these value is reached.
This solution uses Θ(n log n) time and Θ(n) space.
Related
I was trying one problem to count the number of triplets in an array whose sum is less than target value.
Input: [-1, 4, 2, 1, 3], target=5
Output: 4
Explanation: There are four triplets whose sum is less than the target:
[-1, 1, 4], [-1, 1, 3], [-1, 1, 2], [-1, 2, 3]
My Code
import java.util.*;
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for(int i = 0; i < arr.length - 2; i++)
{
int left = i + 1;
int right = arr.length - 1;
while(left < right)
{
int targetDiff = target - arr[i] - arr[left] - arr[right];
if (targetDiff > 0)
{
count++;
right--;
}
else
{
left++;
}
}
}
// TODO: Write your code here
return count;
}
}
It produces the output of 3 where as correct value should be 4 as per the above given input. My logic was , say , x + y + z < targetSum , it implies (targetSum - (x + y + z) ) > 0. If this is true I will increase the count and then decrement the right pointer , since array is sorted. If its not true then I will increment the left pointer . But my logic does not cover the triplet {-1, 2, 3}.
Below is the correct code given by author.
import java.util.*;
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for (int i = 0; i < arr.length - 2; i++) {
count += searchPair(arr, target - arr[i], i);
}
return count;
}
private static int searchPair(int[] arr, int targetSum, int first) {
int count = 0;
int left = first + 1, right = arr.length - 1;
while (left < right) {
if (arr[left] + arr[right] < targetSum) {
count += right - left;
left++;
} else {
right--; // we need a pair with a smaller sum
}
}
return count;
}
public static void main(String[] args) {
System.out.println(TripletWithSmallerSum.searchTriplets(new int[] { -1, 0, 2, 3 }, 3));
System.out.println(TripletWithSmallerSum.searchTriplets(new int[] { -1, 4, 2, 1, 3 }, 5));
}
}
The author has used the concept , say x + y + z < targetSum , it implies x + y < targetSum - z . But I don't get the logic of line count += right - left; . How author use this one line to capture the count. If some one can give me the intution on how to reach this inference. Also what is wrong with my code and what can I do to correct it.
A first issue with your code is that :
you only decrease the right index if the sum is inferior to the target.
However, since you have ordered your list, well you will only be entering that case until left=right.
Quick example : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], target=14
if 1+2+10 <13:
then you will only decrease 10 until you reach 2 in your array
and then you proceed to iterate to the next i-index, here going from 0 to 1.
Meaning that: you will never get the solutions in between such as [1,3,9] and all the one that follows.
I hope it helps you see where there was an error in the logic, which was not from the statement : (targetSum - (x + y + z) ) > 0 but from the action you take according to the result (True/False).
Now, I am not sure there would be an easy way to adapt your code corrctly, because the main issue here is that you have iterate over 2 indexes at once (right and left).
Now regarding your author's answer :
The trick behind :
count += right - left;
goes back to the issue you had, if i tame my example, for
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
it is basically saying that, since the array is ordered, if the sum of two integers with the right one is inferior to target, then it will also be true for all integers inferior to right :
1+2+10<14 => 1+2+9<13
And this statement is true for all integers between left and right, so instead of doing a loop for which we already have the answer, he adds to count the differences between right and left, in other words, the number of integers in your array that will be greater than left and lower than right.
Now that i have explained that, you could use the same "trick" to your code:
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for(int i = 0; i < arr.length - 2; i++)
{
int left = i + 1;
int right = arr.length - 1;
while(left < right)
{
int targetDiff = target -( arr[i] + arr[left] + arr[right]);
if (targetDiff > 0)
{
count += right - left;
left++;
}
else
{
right--;
}
}
}
// TODO: Write your code here
return count;
}
}
I tried to be as detailed as possible, hope it helps you understand better!
I'm working on the following task.
Given an array of n integers and two integer numbers m and k.
You can add any positive integer to any element of the array such that
the total value does not exceed k.
The task is to maximize the
multiples of m in the resultant array.
Consider the following example.
Input:
n = 5, m = 2, k = 2, arr[] = [1, 2, 3, 4, 5]
Let's add 1 to the element arr[0] and 1 to arr[2] then the final array would be:
[2, 2, 4, 4, 5]
Now there are four (4) elements which are multiples of m (2).
I am not getting correct output.
My code:
public class Main {
public static void main(String[] args) {
int n = 5;
int m = 4;
int k = 3;
int count = 0;
int[] arr = {17, 8, 9, 1, 4};
for (int i = 0; i < n; i++) {
for (int j = 0; j <= k; j++) {
// check initial
if (arr[i] % m == 0) {
break;
}
// add
arr[i] = arr[i] + j;
// check again
if (arr[i] % m == 0) {
count++;
break;
}
}
}
System.out.println("Final Array : " + Arrays.toString(arr));
System.out.println("Count : " + count);
}
}
This task boils down to a well-known Dynamic programming algorithm called Knapsack problem after a couple of simple manipulations with the given array.
This approach doesn't require sorting and would be advantages when k is much smaller n.
We can address the problem in the following steps:
Iterate over the given array and count all the numbers that are already divisible by m (this number is stored in the variable count in the code below).
While iterating, for every element of the array calculate the difference between m and remainder from the division of this element by m. Which would be equal to m - currentElement % m. If the difference is smaller or equal to k (it can cave this difference) it should be added to the list (differences in the code below) and also accumulated in a variable which is meant to store the total difference (totalDiff). All the elements which produce difference that exceeds k would be omitted.
If the total difference is less than or equal to k - we are done, the return value would be equal to the number of elements divisible by m plus the size of the list of differences.
Otherwise, we need to apply the logic of the Knapsack problem to the list of differences.
The idea behind the method getBestCount() (which is an implementation Knapsack problem) boils down to generating the "2D" array (a nested array of length equal to the size of the list of differences +1, in which every inner array having the length of k+1) and populating it with maximum values that could be achieved for various states of the Knapsack.
Each element of this array would represent the maximum total number of elements which can be adjusted to make them divisible by m for the various sizes of the Knapsack, i.e. number of items available from the list of differences, and different number of k (in the range from 0 to k inclusive).
The best way to understand how the algorithm works is to draw a table on a piece of paper and fill it with numbers manually (follow the comments in the code, some intermediate variables were introduced only for the purpose of making it easier to grasp, and also see the Wiki article linked above).
For instance, if the given array is [1, 8, 3, 9, 5], k=3 and m=3. We can see 2 elements divisible by m - 3 and 9. Numbers 1, 8, 5 would give the following list of differences [2, 1, 1]. Applying the logic of the Knapsack algorithm, we should get the following table:
[0, 0, 0, 0]
[0, 0, 1, 1]
[0, 1, 1, 2]
[0, 1, 2, 2]
We are interested in the value right most column of the last row, which is 2 plus 2 (number of elements divisible by 3) would give us 4.
Note: that code provided below can dial only with positive numbers. I don't want to shift the focus from the algorithm to such minor details. If OP or reader of the post are interested in making the code capable to work with negative number as well, I'm living the task of adjusting the code for them as an exercise. Hint: only a small change in the countMultiplesOfM() required for that purpose.
That how it might be implemented:
public static int countMultiplesOfM(int[] arr, int k, int m) {
List<Integer> differences = new ArrayList<>();
int count = 0;
long totalDiff = 0; // counter for the early kill - case when `k >= totalDiff`
for (int next : arr) {
if (next % m == 0)
count++; // number is already divisible by `m` we can increment the count and from that moment we are no longer interested in it
else if (m - next % m <= k) {
differences.add(m - next % m);
totalDiff += m - next % m;
}
}
if (totalDiff <= k) { // early kill - `k` is large enough to adjust all numbers in the `differences` list
return count + differences.size();
}
return count + getBestCount(differences, k); // fire the rest logic
}
// Knapsack Algorithm implementation
public static int getBestCount(List<Integer> differences, int knapsackSize) {
int[][] tab = new int[differences.size() + 1][knapsackSize + 1];
for (int numItemAvailable = 1; numItemAvailable < tab.length; numItemAvailable++) {
int next = differences.get(numItemAvailable - 1); // next available item which we're trying to place to knapsack to Maximize the current total
for (int size = 1; size < tab[numItemAvailable].length; size++) {
int prevColMax = tab[numItemAvailable][size - 1]; // maximum result for the current size - 1 in the current row of the table
int prevRowMax = tab[numItemAvailable - 1][size]; // previous maximum result for the current knapsack's size
if (next <= size) { // if it's possible to fit the next item in the knapsack
int prevRowMaxWithRoomForNewItem = tab[numItemAvailable - 1][size - next] + 1; // maximum result from the previous row for the size = `current size - next` (i.e. the closest knapsack size which guarantees that there would be a space for the new item)
tab[numItemAvailable][size] = Math.max(prevColMax, prevRowMaxWithRoomForNewItem);
} else {
tab[numItemAvailable][size] = Math.max(prevRowMax, prevColMax); // either a value in the previous row or a value in the previous column of the current row
}
}
}
return tab[differences.size()][knapsackSize];
}
main()
public static void main(String[] args) {
System.out.println(countMultiplesOfM(new int[]{17, 8, 9, 1, 4}, 3, 4));
System.out.println(countMultiplesOfM(new int[]{1, 2, 3, 4, 5}, 2, 2));
System.out.println(countMultiplesOfM(new int[]{1, 8, 3, 9, 5}, 3, 3));
}
Output:
3 // input array [17, 8, 9, 1, 4], m = 4, k = 3
4 // input array [1, 2, 3, 4, 5], m = 2, k = 2
4 // input array [1, 8, 3, 9, 5], m = 3, k = 3
A link to Online Demo
You must change 2 line in your code :
if(arr[i]%m==0)
{
count++; // add this line
break;
}
// add
arr[i]=arr[i]+1; // change j to 1
// check again
if(arr[i]%m==0)
{
count++;
break;
}
The first is because the number itself is divisible.
and The second is because you add a number to it each time.That is wrong.
for example chenge your arr to :
int[] arr ={17,8,10,2,4};
your output is :
Final Array : [20, 8, 16, 8, 4]
and That is wrong because 16-10=6 and is bigger than k=3.
I believe the problem is that you aren't processing the values in ascending order of the amount by which to adjust.
To solve this I started by using a stream to preprocess the array. This could be done using other methods.
map the values to the amount to make each one, when added, divisible by m.
filter out those that equal to m' (already divisible by m`)
sort in ascending order.
Once that is done. Intialize max to the difference between the original array length and the processed length. This is the number already divisible by m.
As the list is iterated
check to see if k > amount needed. If so, subtract from k and increment max
otherwise break out of the loop (because of the sort, no value remaining can be less than k)
public static int maxDivisors(int m, int k, int[] arr) {
int[] need = Arrays.stream(arr).map(v -> m - v % m)
.filter(v -> v != m).sorted().toArray();
int max = arr.length - need.length;
for (int val : need) {
if (k >= val) {
k -= val;
max++;
} else {
break;
}
}
return max;
}
int m = 4;
int k = 3;
int[] arr ={17,8,9,1,4};
int count = maxDivisors(m, k, arr);
System.out.println(count);
prints
3
For example, {1, 4, 45, 6, 0, 19} and the number 51 should return 3, because the number of elements in the smallest subarray which together are greater than 51 are 3: {4,45,6}`.
{7, 2, 5, 10, 1} and the number 9 should return 1, because the number of the elements in the smallest subarray possible that is greater than 9 is {10}.
If array is null or empty, or the array has no subarray that is greater than the given number, the method has to return -1.
I'm not allowed to use array package from java.util.
My goal is to execute the method in O(n) time.
This is my code so far, if the array has no subarray greater than the given number, it returns an OutofBounds error.
Anyone has a clue?
public static int smallestSubSum(int arr[], int x) {
int left = 0, right = 1, smallest = 0;
int sum = arr[right];
for (int i = 1; i < arr.length; i++) {
if (sum > x)
smallest = left - right;
else
right++;
sum += arr[right];
if (sum > x && left - right < smallest) {
smallest = left - right;
left++;
} else
sum -= arr[left];
left++;
if (sum > x && left - right < smallest)
smallest = left - right;
}
return smallest;
}
Edit: Perhaps I should explain what I tried to do with my code, basically I wanted the sum to hold the first two elements in the code, and then compare with each 'if' iteration if the sum of the current elements are greater or less than X, if not I raise the right element to go further, if yes I erase the first element, the 'left' one.
The array of {1, 4, 45, 6, 0, 19} and the number 51 returns 2, even though the result should be 3. I don't know why, because my right reaches the index 3 which is 6 and the left one reaches index 1 which is 4, so the result should indeed be {4,45,6} but it doesn't get to it.
This is the best I could do.
Here are my test results.
[1, 4, 45, 6, 0, 19] -> 51
3
[7, 2, 5, 10, 1] -> 9
1
[1, 4, 45, 6, 0, 19] -> 200
-1
I just cycled through the array with a for loop. Whenever the total exceeded the X amount, I subtracted values until the total dropped below the X amount.
Here's the complete runnable code I tested with.
import java.util.Arrays;
public class SmallestSubarray {
public static void main(String[] args) {
int[] arr1 = new int[] { 1, 4, 45, 6, 0, 19 };
int x1 = 51;
System.out.println(Arrays.toString(arr1) + " -> " + x1);
System.out.println(smallestSubSum(arr1, x1));
int[] arr2 = new int[] { 7, 2, 5, 10, 1 };
int x2 = 9;
System.out.println(Arrays.toString(arr2) + " -> " + x2);
System.out.println(smallestSubSum(arr2, x2));
int[] arr3 = new int[] { 1, 4, 45, 6, 0, 19 };
int x3 = 200;
System.out.println(Arrays.toString(arr3) + " -> " + x3);
System.out.println(smallestSubSum(arr3, x3));
}
public static int smallestSubSum(int arr[], int x) {
if (arr == null || arr.length < 1) {
return -1;
}
int sum = 0;
int minCount = Integer.MAX_VALUE;
int index = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
while (sum > x) {
minCount = Math.min(i - index + 1, minCount);
sum -= arr[index];
index++;
}
}
return (minCount == Integer.MAX_VALUE) ? -1 : minCount;
}
}
I am attempting to find the maximum sum of non-consecutive subarrays of length at least k.
For example an array of [1, 2, 3, 1, 7, 9] with k = 2 should return 21 with subarrays [2,3] and [7,9] which are the 2 maximum subarrays and are non-consecutive (apart from one another) within the array.
Another example is [1, 2, 3, 4] k = 3
returns: 9, [2, 3, 4]
I am applying the method here which given an array of randomly sorted integers, calculates m number of subarrays of size k but does so by calculating a presum array making it difficult to identify the individual array values which make up the solution. As is done in this example.
Can this method be altered to show the subarrays which make up the total sum?
Below are the functions described in the above method:
// reorganize array
public static int calcProfit(List<Integer> inputArray){
int lotCount = inputArray.get(0);
inputArray.remove(0);
int maxBusiness = inputArray.get(0);
inputArray.remove(0);
// convert arrayList to int array
int[] workingArray = new int[inputArray.size()];
for(int i = 0; i < inputArray.size(); i++) {
if (inputArray.get(i) != null) {
workingArray[i] = inputArray.get(i);
}
}
System.out.println(Arrays.toString(workingArray));
int prefixArray[] = new int[lotCount + 1 - maxBusiness];
int maxArrays = (int) Math.ceil(lotCount / maxBusiness);
arraySum(prefixArray, workingArray, lotCount, maxBusiness);
System.out.println("Prefix array is" + Arrays.toString(prefixArray));
int completeArray = maxSubarray(prefixArray, maxArrays, lotCount + 1 - maxBusiness, maxBusiness, 0);
return completeArray;
}
static void arraySum(int presum[], int arr[], int n, int k)
{
for (int i = 0; i < k; i++)
presum[0] += arr[i];
// store sum of array index i to i+k
// in presum array at index i of it.
for (int i = 1; i <= n - k; i++)
presum[i] += presum[i - 1] + arr[i + k - 1] -
arr[i - 1];
}
private static int maxSubarray(int preSum[], int m, int size, int k, int start) {
// stop if array length is 0
if (m == 0) {
return 0;
}
// stop if start greater than preSum
if (start > size - 1) {
return 0;
}
System.out.println("m is : " + m + " start is : " + start);
// if including subarray of size k
int includeMax = preSum[start] + maxSubarray(preSum,m - 1, size, k, start + k);
// search next possible subarray
int excludeMax = maxSubarray(preSum, m, size, k, start + 1);
System.out.println("exclude max is : " + excludeMax + " include max is " + includeMax);
// return max
return Math.max(includeMax, excludeMax);
}
You can solve the given problem in O(n) using dynamic programming by maintaining a prefix sum array to quickly calculate the sum of a subarray of size k along with maintaining a trace array which records the action taken at each step of the array. Here's an implementation for the same: https://ideone.com/VxKzUn
The ideology behind the approach is that for every element in the array, we have an option to create our sub-array starting from this element or leave it out and move to the next element, thus giving us an optimal sub-structure the recurrence relation of which can be formulated as:
f(n) = max{ sum(arr[n], .. , arr[n + k]) + f(n + k + 1), f(n + 1) }
from collections import defaultdict
dp = defaultdict(lambda: -1)
prefixsum = []
trace = []
def getSubArraySum(i, j):
if i == 0:
return prefixsum[j]
return (prefixsum[j] - prefixsum[i - 1])
def rec(cur, arr, k):
if cur >= len(arr):
return 0
if dp[cur] != -1:
return dp[cur]
# Assuming that all the elements in the array is positive,
# else set s1 and s2 to -Infinity
s1 = -1; s2 = -1
# If we choose the subarray starting at `cur`
if cur + k - 1 < len(arr):
s1 = getSubArraySum(cur, cur + k - 1) + rec(cur + k + 1, arr, k)
# If we ignore the subarray starting at `cur`
s2 = rec(cur + 1, arr, k)
dp[cur] = max(s1, s2)
if s1 >= s2:
trace[cur] = (True, cur + k + 1)
return s1
trace[cur] = (False, cur + 1)
return s2
def getTrace(arr, trace, k):
itr = 0
subArrays = []
while itr < len(trace):
if trace[itr][0]:
subArrays.append(arr[itr : itr + k])
itr = trace[itr][1]
return subArrays
def solve(arr, k):
global dp, trace, prefixsum
dp = defaultdict(lambda: -1)
trace = [(False, 0)] * len(arr)
prefixsum = [0] * len(arr)
prefixsum[0] = arr[0]
for i in range(1, len(arr)):
prefixsum[i] += prefixsum[i - 1] + arr[i]
print("Array :", arr)
print("Max sum: ", rec(0, arr, k))
print("Subarrays: ", getTrace(arr, trace, k))
print("-- * --")
solve([1, 2, 3, 4], 3)
solve([1, 2, 3, 1, 7, 9] , 2)
The output from the above code is,
Array : [1, 2, 3, 4]
Max sum: 9
Subarrays: [[2, 3, 4]]
-- * --
Array : [1, 2, 3, 1, 7, 9]
Max sum: 21
Subarrays: [[2, 3], [7, 9]]
-- * --
I worked with a Codility problem provided below,
A non-empty 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, as shown in a figure below. 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:
class Solution { public int solution(int[] A); }
that, given a non-empty array A of N integers, returns the maximum number of flags that can be set on the peaks of the array.
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
the function should return 3, as explained above.
Assume that:
N is an integer within the range [1..400,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) (not counting the storage required for input arguments).
I walk through the solution provided below,
public static int solution(int[] A) {
int N = A.length;
/*
* P = [1, 1, 3, 3, 5, 5, 10, 10, 10, 10, 10, -1]
* */
int[] P = nextPeak(A);
int i = 1;
int result = 0;
while ((i - 1) * i <= N) {
int index = 0;
int flags = 0;
while (index < N && flags < i) {
/*
* P = [1, 1, 3, 3, 5, 5, 10, 10, 10, 10, 10, -1]
* */
index = P[index];
if (index == -1) {
break;
}
flags += 1;
index += i;
}
/*
* maximize the number of flags for the whole segment
* */
result = Math.max(result, flags);
i++;
}
return result;
}
/*
* A = [1, 1, 3, 3, 5, 5, 10, 10, 10, 10, 10, -1]
* */
public static int[] nextPeak(int[] P) {
int N = P.length;
ArrayList<Integer> peaks = new ArrayList<Integer>();
for (int i = 1; i < P.length - 1; i++) {
if (P[i] > P[i - 1] && P[i] > P[i + 1]) {
peaks.add(i);
}
}
int[] A = new int[N];
A[N - 1] = -1;
for (int i = N - 2; i >= 0; i--) {
if (peaks.contains(i)) {
A[i] = i;
} else {
A[i] = A[i + 1];
}
}
return A;
}
Generally, I understand the computation but fail to see where do we meet the condition if you take K flags, then the distance between any two flags should be greater than or equal to K.
I imagine this is inside the while condition of (i-1)*i <= N but unable to comprehend it properly. Would anyone kindly explain it to me?
Your answer is index += i; combined with the condition flags < i in the while loop.
They work the solution in reverse: walking K steps at a time, insert at most K flags.