给定大小为N且整数K的数组arr [] ,任务是找到由相同元素组成的最长子数组的长度,该长度可以通过将数组元素最多K减1来获得。
例子:
Input: arr[] = { 1, 2, 3 }, K = 1
Output: 2
Explanation:
Decrementing arr[0] by 1 modifies arr[] to { 1, 1, 3 }
The longest subarray with equal elements is { 1, 1 }.
Therefore, the required output is 2.
Input: arr[] = { 1, 7, 3, 4, 5, 6 }, K = 6
Output: 4
方法:可以使用段树和二进制搜索技术解决该问题。这个想法是使用以下观察:
Total number of decrements operations required to make all array elements of the subarray { arr[start], …, arr[end] } equal
= (Σ(start, end)) – (end – start + 1) * (min_value)
where, start = index of the starting point of the subarray
end = index of end point of subarray
min_value = smallest value from index i to j
Σ(start, end) = sum of all elements from index i to j
请按照以下步骤解决以上问题:
- 初始化段树以计算数组的子数组中的最小元素,并初始化前缀和数组以计算子数组的和元素。
- 遍历数组arr [] 。对于第i个元素,请执行以下操作:
- 初始化两个变量,即start = i , end = N – 1并在[start,end]范围内应用二进制搜索以检查子数组{arr [start],…,arr [end]}的所有元素是否都可以通过从上述观察中最多减少K个运算,可以使相等或不相等。
- 如果子数组{arr [start],…,arr [end]}的所有元素都可以通过最多减少K个操作而相等,则更新start =(start + end)/ 2 +1 。
- 否则,更新结束=(开始+结束)/ 2 – 1
- 最后,打印从上述操作获得的最长子数组的长度。
下面是上述方法的实现:
C++
// C++ program to implement
// the above appraoch
#include
using namespace std;
// Function to construct Segment Tree
// to return the minimum element in a range
int build(int tree[], int* A, int start,
int end, int node)
{
// If leaf nodes of
// the tree are found
if (start == end) {
// Update the value in segment
// tree from given array
tree[node] = A[start];
return tree[node];
}
// Divide left and right subtree
int mid = (start + end) / 2;
// Stores smallest element in
// subarray { arr[start], arr[mid] }
int X = build(tree, A, start, mid,
2 * node + 1);
// Stores smallest element in
// subarray { arr[mid + 1], arr[end] }
int Y = build(tree, A, mid + 1,
end, 2 * node + 2);
// Stores smallest element in
// subarray { arr[start], arr[end] }
return tree[node] = min(X, Y);
}
// Function to find the smallest
// element present in a subarray
int query(int tree[], int start, int end,
int l, int r, int node)
{
// If elements of the subarray
// are not in the range [l, r]
if (start > r || end < l)
return INT_MAX;
// If all the elements of the
// subarray are in the range [l, r]
if (start >= l && end <= r)
return tree[node];
// Divide tree into left
// and right subtree
int mid = (start + end) / 2;
// Stores smallest element
// in left subtree
int X = query(tree, start, mid, l,
r, 2 * node + 1);
// Stores smallest element in
// right subtree
int Y = query(tree, mid + 1, end, l,
r, 2 * node + 2);
return min(X, Y);
}
// Function that find length of longest
// subarray with all equal elements in
// atmost K decrements
int longestSubArray(int* A, int N, int K)
{
// Stores length of longest subarray
// with all equal elements in atmost
// K decrements.
int res = 1;
// Store the prefix sum array
int preSum[N + 1];
// Calculate the prefix sum array
preSum[0] = A[0];
for (int i = 0; i < N; i++)
preSum[i + 1] = preSum[i] + A[i];
int tree[4 * N + 5];
// Build the segment tree
// for range min query
build(tree, A, 0, N - 1, 0);
// Traverse the array
for (int i = 0; i < N; i++) {
// Stores start index
// of the subarray
int start = i;
// Stores end index
// of the subarray
int end = N - 1;
int mid;
// Stores end index of
// the longest subarray
int max_index = i;
// Performing the binary search
// to find the endpoint
// for the selected range
while (start <= end) {
// Find the mid for binary search
mid = (start + end) / 2;
// Find the smallest element in
// range [i, mid] using Segment Tree
int min_element
= query(tree, 0, N - 1, i, mid, 0);
// Stores total sum of subarray
// after K decrements
int expected_sum
= (mid - i + 1) * min_element;
// Stores sum of elements of
// subarray before K decrements
int actual_sum
= preSum[mid + 1] - preSum[i];
// If subarray found with
// all equal elements
if (actual_sum - expected_sum <= K) {
// Update start
start = mid + 1;
// Update max_index
max_index = max(max_index, mid);
}
// If false, it means that
// the selected range is invalid
else {
// Update end
end = mid - 1;
}
}
// Store the length of longest subarray
res = max(res, max_index - i + 1);
}
// Return result
return res;
}
// Driver Code
int main()
{
int arr[] = { 1, 7, 3, 4, 5, 6 };
int k = 6;
int n = 6;
cout << longestSubArray(arr, n, k);
return 0;
}
Java
// Java program to implement
// the above appraoch
import java.util.*;
class GFG{
// Function to construct Segment Tree
// to return the minimum element in a range
static int build(int tree[], int[] A, int start,
int end, int node)
{
// If leaf nodes of
// the tree are found
if (start == end)
{
// Update the value in segment
// tree from given array
tree[node] = A[start];
return tree[node];
}
// Divide left and right subtree
int mid = (start + end) / 2;
// Stores smallest element in
// subarray { arr[start], arr[mid] }
int X = build(tree, A, start, mid,
2 * node + 1);
// Stores smallest element in
// subarray { arr[mid + 1], arr[end] }
int Y = build(tree, A, mid + 1,
end, 2 * node + 2);
// Stores smallest element in
// subarray { arr[start], arr[end] }
return (tree[node] = Math.min(X, Y));
}
// Function to find the smallest
// element present in a subarray
static int query(int tree[], int start, int end,
int l, int r, int node)
{
// If elements of the subarray
// are not in the range [l, r]
if (start > r || end < l)
return Integer.MAX_VALUE;
// If all the elements of the
// subarray are in the range [l, r]
if (start >= l && end <= r)
return tree[node];
// Divide tree into left
// and right subtree
int mid = (start + end) / 2;
// Stores smallest element
// in left subtree
int X = query(tree, start, mid, l,
r, 2 * node + 1);
// Stores smallest element in
// right subtree
int Y = query(tree, mid + 1, end, l,
r, 2 * node + 2);
return Math.min(X, Y);
}
// Function that find length of longest
// subarray with all equal elements in
// atmost K decrements
static int longestSubArray(int[] A, int N, int K)
{
// Stores length of longest subarray
// with all equal elements in atmost
// K decrements.
int res = 1;
// Store the prefix sum array
int preSum[] = new int[N + 1];
// Calculate the prefix sum array
preSum[0] = A[0];
for(int i = 0; i < N; i++)
preSum[i + 1] = preSum[i] + A[i];
int tree[] = new int[4 * N + 5];
// Build the segment tree
// for range min query
build(tree, A, 0, N - 1, 0);
// Traverse the array
for(int i = 0; i < N; i++)
{
// Stores start index
// of the subarray
int start = i;
// Stores end index
// of the subarray
int end = N - 1;
int mid;
// Stores end index of
// the longest subarray
int max_index = i;
// Performing the binary search
// to find the endpoint
// for the selected range
while (start <= end)
{
// Find the mid for binary search
mid = (start + end) / 2;
// Find the smallest element in
// range [i, mid] using Segment Tree
int min_element = query(tree, 0, N - 1,
i, mid, 0);
// Stores total sum of subarray
// after K decrements
int expected_sum = (mid - i + 1) *
min_element;
// Stores sum of elements of
// subarray before K decrements
int actual_sum = preSum[mid + 1] -
preSum[i];
// If subarray found with
// all equal elements
if (actual_sum - expected_sum <= K)
{
// Update start
start = mid + 1;
// Update max_index
max_index = Math.max(max_index, mid);
}
// If false, it means that
// the selected range is invalid
else
{
// Update end
end = mid - 1;
}
}
// Store the length of longest subarray
res = Math.max(res, max_index - i + 1);
}
// Return result
return res;
}
// Driver Code
static public void main(String args[])
{
int arr[] = { 1, 7, 3, 4, 5, 6 };
int k = 6;
int n = 6;
System.out.print(longestSubArray(arr, n, k));
}
}
// This code is contributed by sanjoy_62
Python3
# Python3 program to implement
# the above appraoch
import sys
# Function to construct Segment Tree
# to return the minimum element in a range
def build(tree, A, start, end, node):
# If leaf nodes of
# the tree are found
if (start == end):
# Update the value in segment
# tree from given array
tree[node] = A[start]
return tree[node]
# Divide left and right subtree
mid = (int)((start + end) / 2)
# Stores smallest element in
# subarray : arr[start], arr[mid]
X = build(tree, A, start, mid,
2 * node + 1)
# Stores smallest element in
# subarray : arr[mid + 1], arr[end]
Y = build(tree, A, mid + 1,
end, 2 * node + 2)
# Stores smallest element in
# subarray : arr[start], arr[end]
return (tree[node] == min(X, Y))
# Function to find the smallest
# element present in a subarray
def query(tree, start, end, l, r, node):
# If elements of the subarray
# are not in the range [l, r]
if (start > r or end < l) :
return sys.maxsize
# If all the elements of the
# subarray are in the range [l, r]
if (start >= l and end <= r):
return tree[node]
# Divide tree into left
# and right subtree
mid = (int)((start + end) / 2)
# Stores smallest element
# in left subtree
X = query(tree, start, mid, l,
r, 2 * node + 1)
# Stores smallest element in
# right subtree
Y = query(tree, mid + 1, end, l,
r, 2 * node + 2)
return min(X, Y)
# Function that find length of longest
# subarray with all equal elements in
# atmost K decrements
def longestSubArray(A, N, K):
# Stores length of longest subarray
# with all equal elements in atmost
# K decrements.
res = 1
# Store the prefix sum array
preSum = [0] * (N + 1)
# Calculate the prefix sum array
preSum[0] = A[0]
for i in range(N):
preSum[i + 1] = preSum[i] + A[i]
tree = [0] * (4 * N + 5)
# Build the segment tree
# for range min query
build(tree, A, 0, N - 1, 0)
# Traverse the array
for i in range(N):
# Stores start index
# of the subarray
start = i
# Stores end index
# of the subarray
end = N - 1
# Stores end index of
# the longest subarray
max_index = i
# Performing the binary search
# to find the endpoint
# for the selected range
while (start <= end):
# Find the mid for binary search
mid = (int)((start + end) / 2)
# Find the smallest element in
# range [i, mid] using Segment Tree
min_element = query(tree, 0, N - 1, i, mid, 0)
# Stores total sum of subarray
# after K decrements
expected_sum = (mid - i + 1) * min_element
# Stores sum of elements of
# subarray before K decrements
actual_sum = preSum[mid + 1] - preSum[i]
# If subarray found with
# all equal elements
if (actual_sum - expected_sum <= K):
# Update start
start = mid + 1
# Update max_index
max_index = max(max_index, mid)
# If false, it means that
# the selected range is invalid
else:
# Update end
end = mid - 1
# Store the length of longest subarray
res = max(res, max_index - i + 2)
# Return result
return res
# Driver Code
arr = [ 1, 7, 3, 4, 5, 6 ]
k = 6
n = 6
print(longestSubArray(arr, n, k))
# This code is contributed by splevel62
C#
// C# program to implement
// the above appraoch
using System;
class GFG{
// Function to construct Segment Tree
// to return the minimum element in a range
static int build(int[] tree, int[] A, int start,
int end, int node)
{
// If leaf nodes of
// the tree are found
if (start == end)
{
// Update the value in segment
// tree from given array
tree[node] = A[start];
return tree[node];
}
// Divide left and right subtree
int mid = (start + end) / 2;
// Stores smallest element in
// subarray { arr[start], arr[mid] }
int X = build(tree, A, start, mid,
2 * node + 1);
// Stores smallest element in
// subarray { arr[mid + 1], arr[end] }
int Y = build(tree, A, mid + 1,
end, 2 * node + 2);
// Stores smallest element in
// subarray { arr[start], arr[end] }
return (tree[node] = Math.Min(X, Y));
}
// Function to find the smallest
// element present in a subarray
static int query(int[] tree, int start, int end,
int l, int r, int node)
{
// If elements of the subarray
// are not in the range [l, r]
if (start > r || end < l)
return Int32.MaxValue;
// If all the elements of the
// subarray are in the range [l, r]
if (start >= l && end <= r)
return tree[node];
// Divide tree into left
// and right subtree
int mid = (start + end) / 2;
// Stores smallest element
// in left subtree
int X = query(tree, start, mid, l,
r, 2 * node + 1);
// Stores smallest element in
// right subtree
int Y = query(tree, mid + 1, end, l,
r, 2 * node + 2);
return Math.Min(X, Y);
}
// Function that find length of longest
// subarray with all equal elements in
// atmost K decrements
static int longestSubArray(int[] A, int N, int K)
{
// Stores length of longest subarray
// with all equal elements in atmost
// K decrements.
int res = 1;
// Store the prefix sum array
int[] preSum = new int[N + 1];
// Calculate the prefix sum array
preSum[0] = A[0];
for(int i = 0; i < N; i++)
preSum[i + 1] = preSum[i] + A[i];
int[] tree = new int[4 * N + 5];
// Build the segment tree
// for range min query
build(tree, A, 0, N - 1, 0);
// Traverse the array
for(int i = 0; i < N; i++)
{
// Stores start index
// of the subarray
int start = i;
// Stores end index
// of the subarray
int end = N - 1;
int mid;
// Stores end index of
// the longest subarray
int max_index = i;
// Performing the binary search
// to find the endpoint
// for the selected range
while (start <= end)
{
// Find the mid for binary search
mid = (start + end) / 2;
// Find the smallest element in
// range [i, mid] using Segment Tree
int min_element = query(tree, 0, N - 1,
i, mid, 0);
// Stores total sum of subarray
// after K decrements
int expected_sum = (mid - i + 1) *
min_element;
// Stores sum of elements of
// subarray before K decrements
int actual_sum = preSum[mid + 1] -
preSum[i];
// If subarray found with
// all equal elements
if (actual_sum - expected_sum <= K)
{
// Update start
start = mid + 1;
// Update max_index
max_index = Math.Max(max_index, mid);
}
// If false, it means that
// the selected range is invalid
else
{
// Update end
end = mid - 1;
}
}
// Store the length of longest subarray
res = Math.Max(res, max_index - i + 1);
}
// Return result
return res;
}
// Driver Code
static void Main()
{
int[] arr = { 1, 7, 3, 4, 5, 6 };
int k = 6;
int n = 6;
Console.WriteLine(longestSubArray(arr, n, k));
}
}
// This code is contributed by susmitakundugoaldanga
4
时间复杂度: O(N *(log(N)) 2 )
辅助空间:O(N)