Given 2 integers S and K and an array arr[] of N integers, find the longest subarray in arr[] such that the subarray can be divided into at most K contiguous segments and the sum of elements of each segment can be at most S.
Example:
Input: n = 5, k = 2, s = 5, arr = { 1, 3, 2, 1, 5 }
Output: 4
Explanation: One of the segments with length 4 is [1,3,2,1]. It can be divided into two segments [1,3] and [2,1] whose sums are at most S=5.Input: n = 5, k = 3, s = 5, arr = {5, 1 ,5 ,1 ,1}
Output: 4
Explanation: One of the segments with length 4 is [1,5,1,1]. It can be divided into three segments [1], [5] and [1,1] whose sums are at most S=5.
Approach:
The idea is to uses a two-pointer approach to find the right boundary of each segment, precomputes right boundaries using binary lifting, and make use of binary lifting to determine the maximum number of elements in a good segment for each starting index. The result is the maximum value encountered during these calculations.
-
Initialize Variables:
- Set up variables for the current sum (currSum) and the maximum number of elements in a good segment (maxGoodSegment).
-
Segment Boundary Calculation:
- Use a two-pointer approach to find the right boundary of each segment:
- Iterate over possible left boundaries.
- Extend the right boundary until the sum exceeds s.
- Store the right boundary in the 2D array up.
-
Precompute Right Boundaries:
- Use binary lifting to precompute the right boundaries for each power of 2.
-
Binary Lifting for Maximum Segments:
- Use binary lifting to find the maximum number of elements in a good segment for each starting index (i):
- Iterate over the binary representation of k.
- Update the current index based on the binary lifting technique.
- Track the maximum segment size encountered during these iterations.
-
Output Result:
- The maximum number of elements in a good segment (maxGoodSegment) represents the solution for the given input
Below is the implementation of the above approach:
#include <bits/stdc++.h> using namespace std;
const int MAX_N = 1e5;
int up[MAX_N + 5][20];
int solve( int n, int k, int s, vector< int >& arr)
{ vector< int > nums(n, 0);
int currSum = 0;
int maxGoodSegment = 0;
// Calculate the maximum number of elements in a good
// segment
for ( int i = 0, j = 0; i < n; i++) {
// Extend the current segment until the sum exceeds
// 's'
while (j < n && currSum + arr[j] <= s) {
currSum += arr[j];
j++;
}
// Store the right boundary of the current segment
up[i][0] = j;
currSum -= arr[i]; // Move the left boundary of the
// segment
}
up[n][0] = n;
// Precompute the right boundaries for each power of 2
for ( int j = 1; j < 20; j++) {
for ( int i = 0; i <= n; i += 1) {
up[i][j] = up[up[i][j - 1]][j - 1];
}
}
// Calculate the maximum number of elements in a good
// segment using binary lifting
for ( int i = 0; i < n; i++) {
int currIndex = i;
for ( int j = 19; j >= 0; j--) {
if (k & (1 << j)) {
currIndex = up[currIndex][j];
}
}
maxGoodSegment = max(maxGoodSegment, currIndex - i);
}
// Output the result for the current test case
return maxGoodSegment;
} int main()
{ int n = 5, k = 2, s = 5;
vector< int > arr = { 1, 3, 2, 1, 5 };
cout << solve(n, k, s, arr);
return 0;
} |
import java.util.Arrays;
import java.util.Vector;
public class Main {
static final int MAX_N = 100005 ;
static int [][] up = new int [MAX_N + 5 ][ 20 ];
static int solve( int n, int k, int s, Vector<Integer> arr) {
// Vector to store nums array, initialized with 0
Vector<Integer> nums = new Vector<>(n);
for ( int i = 0 ; i < n; i++) {
nums.add( 0 );
}
int currSum = 0 ;
int maxGoodSegment = 0 ;
// Calculate the right boundaries of segments
for ( int i = 0 , j = 0 ; i < n; i++) {
while (j < n && currSum + arr.get(j) <= s) {
currSum += arr.get(j);
j++;
}
up[i][ 0 ] = j; // Store the right boundary of the current segment
currSum -= arr.get(i); // Move the left boundary of the segment
}
up[n][ 0 ] = n; // Set the right boundary of the last element
// Precompute the right boundaries for each power of 2 using binary lifting
for ( int j = 1 ; j < 20 ; j++) {
for ( int i = 0 ; i <= n; i += 1 ) {
up[i][j] = up[up[i][j - 1 ]][j - 1 ];
}
}
// Calculate the maximum number of elements in a good segment using binary lifting
for ( int i = 0 ; i < n; i++) {
int currIndex = i;
for ( int j = 19 ; j >= 0 ; j--) {
if ((k & ( 1 << j)) != 0 ) {
currIndex = up[currIndex][j];
}
}
maxGoodSegment = Math.max(maxGoodSegment, currIndex - i);
}
return maxGoodSegment;
}
public static void main(String[] args) {
// Example input
int n = 5 , k = 2 , s = 5 ;
Vector<Integer> arr = new Vector<>(Arrays.asList( 1 , 3 , 2 , 1 , 5 ));
// Output the result for the current test case
System.out.println(solve(n, k, s, arr));
}
} // This code is contributed by akshitaguprzj3 |
MAX_N = 10 * * 5
up = [[ 0 ] * 20 for _ in range (MAX_N + 5 )]
def solve(n, k, s, arr):
nums = [ 0 ] * n
curr_sum = 0
max_good_segment = 0
# Calculate the maximum number of elements in a good segment
for i in range (n):
j = i
# Extend the current segment until the sum exceeds 's'
while j < n and curr_sum + arr[j] < = s:
curr_sum + = arr[j]
j + = 1
# Store the right boundary of the current segment
up[i][ 0 ] = j
curr_sum - = arr[i] # Move the left boundary of the segment
up[n][ 0 ] = n
# Precompute the right boundaries for each power of 2
for j in range ( 1 , 20 ):
for i in range (n + 1 ):
up[i][j] = up[up[i][j - 1 ]][j - 1 ]
# Calculate the maximum number of elements in a good segment using binary lifting
for i in range (n):
curr_index = i
for j in range ( 19 , - 1 , - 1 ):
if k & ( 1 << j):
curr_index = up[curr_index][j]
max_good_segment = max (max_good_segment, curr_index - i)
# Output the result for the current test case
return max_good_segment
if __name__ = = "__main__" :
n, k, s = 5 , 2 , 5
arr = [ 1 , 3 , 2 , 1 , 5 ]
print (solve(n, k, s, arr))
|
using System;
using System.Collections.Generic;
public class Solution
{ const int MAX_N = 100005;
static int [,] up = new int [MAX_N + 5, 20];
static int Solve( int n, int k, int s, List< int > arr)
{
int currSum = 0;
int maxGoodSegment = 0;
// Calculate the maximum number of elements in a good
// segment
for ( int i = 0, j = 0; i < n; i++)
{
// Extend the current segment until the sum exceeds
// 's'
while (j < n && currSum + arr[j] <= s)
{
currSum += arr[j];
j++;
}
// Store the right boundary of the current segment
up[i, 0] = j;
currSum -= arr[i]; // Move the left boundary of the
// segment
}
up[n, 0] = n;
// Precompute the right boundaries for each power of 2
for ( int j = 1; j < 20; j++)
{
for ( int i = 0; i <= n; i += 1)
{
up[i, j] = up[up[i, j - 1], j - 1];
}
}
// Calculate the maximum number of elements in a good
// segment using binary lifting
for ( int i = 0; i < n; i++)
{
int currIndex = i;
for ( int j = 19; j >= 0; j--)
{
if ((k & (1 << j)) != 0)
{
currIndex = up[currIndex, j];
}
}
maxGoodSegment = Math.Max(maxGoodSegment, currIndex - i);
}
// Output the result for the current test case
return maxGoodSegment;
}
public static void Main( string [] args)
{
int n = 5, k = 2, s = 5;
List< int > arr = new List< int > { 1, 3, 2, 1, 5 };
Console.WriteLine(Solve(n, k, s, arr));
}
} |
// Javascript code for the above approach const MAX_N = 100005; const up = Array.from({ length: MAX_N + 5
}, () => Array.from({ length: 20
}, () => 0)) function solve(n, k, s, arr) {
// Array to store nums array, initialized with 0
const nums = Array(n).fill(0);
let currSum = 0;
let maxGoodSegment = 0;
// Calculate the right boundaries of segments
for (let i = 0, j = 0; i < n; i++) {
while (j < n && currSum + arr[j] <= s) {
currSum += arr[j];
j++;
}
up[i][0] = j; // Store the right boundary of the current segment
currSum -= arr[i]; // Move the left boundary of the segment
}
up[n][0] = n; // Set the right boundary of the last element
// Precompute the right boundaries for each power of 2 using binary lifting
for (let j = 1; j < 20; j++) {
for (let i = 0; i <= n; i += 1) {
up[i][j] = up[up[i][j - 1]][j - 1];
}
}
// Calculate the maximum number of elements in a good segment using binary lifting
for (let i = 0; i < n; i++) {
let currIndex = i;
for (let j = 19; j >= 0; j--) {
if ((k & (1 << j)) != 0) {
currIndex = up[currIndex][j];
}
}
maxGoodSegment = Math.max(maxGoodSegment, currIndex - i);
}
return maxGoodSegment;
} // Example input const n = 5, k = 2,
s = 5;
const arr = [1, 3, 2, 1, 5]; // Output the result for the current test case console.log(solve(n, k, s, arr)); // This code is contributed by ragul21 |
4
Time complexity: O(n + n * log(k)), where n is the size of the input array and k is the given parameter.
Auxiliary space: O(n * log(n)).