📌  相关文章
📜  具有相同元素的最长子数组的长度,最多K个增量

📅  最后修改于: 2021-05-06 19:59:38             🧑  作者: Mango

给定一个整数数组arr和一个数字K ,任务是找到最长子数组的长度,以使该子数组中的所有元素最多可以K个增量相同。

例子:

方法:

  • 变量i将用于存储所需的最长子数组的起点,变量j用于终点。因此范围将是[i,j]
  • 最初假定有效范围为[0,N)。
  • 实际范围[i,j]将使用二进制搜索计算。对于执行的每个搜索:
    • 细分树可用于查找[i,j]范围内的最大元素
    • 使[i,j]范围内的所有元素都等于找到的max元素。
    • 然后,使用前缀和数组来获取[i,j]范围内的元素之和。
    • 然后,该范围内所需的增量数可以计算为:
      Total number of increments
       = (j - i + 1) * (max_value) - Σ(i, j)
      
      where i = index of the starting point of the subarray
            j = index of end point of subarray
            max_value = maximum value from index i to j
            Σ(i, j) = sum of all elements from index i to j
      
    • 如果所需的增量数小于或等于K ,则它是有效的子数组,否则无效。
    • 对于无效的子数组,请为下一个二进制搜索相应地更新起点和终点。
  • 返回最长的此类子数组范围的长度。

下面是上述方法的实现。

C++
// C++ program to find the length of
// Longest Subarray with same elements
// in atmost K increments
  
#include 
using namespace std;
  
// Initialize array for segment tree
int segment_tree[4 * 1000000];
  
// Function that builds the segment
// tree to return the max element
// in a range
int build(int* A, int start, int end,
          int node)
{
    if (start == end)
        // update the value in segment
        // tree from given array
        segment_tree[node] = A[start];
  
    else {
        // find the middle index
        int mid = (start + end) / 2;
  
        // If there are more than one
        // elements, then recur for left
        // and right subtrees and
        // store the max of values in this node
        segment_tree[node]
            = max(
                build(A, start, mid, 2 * node + 1),
                build(A, mid + 1, end, 2 * node + 2));
    }
    return segment_tree[node];
}
  
// Function to return the max
// element in the given range
int query(int start, int end, int l, int r,
          int node)
{
    // If the range is out of bounds,
    // return -1
  
    if (start > r || end < l)
        return -1;
    if (start >= l && end <= r)
        return segment_tree[node];
    int mid = (start + end) / 2;
  
    return max(query(start, mid, l,
                     r, 2 * node + 1),
               query(mid + 1, end, l,
                     r, 2 * node + 2));
}
  
// Function that returns length of longest
// subarray with same elements in atmost
// K increments.
int longestSubArray(int* A, int N, int K)
{
  
    // Initialize the result variable
    // Even though the K is 0,
    // the required longest subarray,
    // in that case, will also be of length 1
    int res = 1;
  
    // Initialize the prefix sum array
    int preSum[N + 1];
  
    // Build the prefix sum array
    preSum[0] = A[0];
    for (int i = 0; i < N; i++)
        preSum[i + 1] = preSum[i] + A[i];
  
    // Build the segment tree
    // for range max query
    build(A, 0, N - 1, 0);
  
    // Loop through the array
    // with a starting point as i
    // for the required subarray till
    // the longest subarray is found
    for (int i = 0; i < N; i++) {
  
        int start = i, end = N - 1,
            mid, 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 max element
            // in the range [i, mid]
            // using Segment Tree
            int max_element
                = query(0, N - 1,
                        i, mid, 0);
  
            // Total sum of subarray after increments
            int expected_sum = (mid - i + 1)
                               * max_element;
  
            // Actual sum of elements
            // before increments
            int actual_sum = preSum[mid + 1]
                             - preSum[i];
  
            // Check if such increment is possible
            // If true, then current i
            // is the actual starting point
            // of the required longest subarray
            if (expected_sum - actual_sum <= K) {
  
                // Now for finding the endpoint
                // for this range
                // Perform the Binary search again
                // with the updated start
                start = mid + 1;
  
                // Store max end point for the range
                // to give longest subarray
                max_index = max(max_index, mid);
            }
  
            // If false, it means that
            // the selected range is invalid
            else {
  
                // Perform the Binary Search again
                // with the updated 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[] = { 2, 0, 4, 6, 7 }, K = 6;
    int N = sizeof(arr) / sizeof(arr[0]);
  
    cout << longestSubArray(arr, N, K);
  
    return 0;
}


Java
// Java program to find the length of 
// Longest Subarray with same elements 
// in atmost K increments 
class GFG 
{
      
    // Initialize array for segment tree 
    static int segment_tree[] = new int[4 * 1000000]; 
      
    // Function that builds the segment 
    // tree to return the max element 
    // in a range 
    static int build(int A[], int start, int end, 
                     int node) 
    { 
        if (start == end) 
          
            // update the value in segment 
            // tree from given array 
            segment_tree[node] = A[start]; 
      
        else 
        { 
              
            // find the middle index 
            int mid = (start + end) / 2; 
      
            // If there are more than one 
            // elements, then recur for left 
            // and right subtrees and 
            // store the max of values in this node 
            segment_tree[node] = Math.max( 
                    build(A, start, mid, 2 * node + 1), 
                    build(A, mid + 1, end, 2 * node + 2)); 
        } 
        return segment_tree[node]; 
    } 
      
    // Function to return the max 
    // element in the given range 
    static int query(int start, int end, int l, int r, 
                     int node) 
    { 
        // If the range is out of bounds, 
        // return -1 
        if (start > r || end < l) 
            return -1; 
        if (start >= l && end <= r) 
            return segment_tree[node]; 
        int mid = (start + end) / 2; 
      
        return Math.max(query(start, mid, l, 
                        r, 2 * node + 1), 
                        query(mid + 1, end, l, 
                        r, 2 * node + 2)); 
    } 
      
    // Function that returns length of longest 
    // subarray with same elements in atmost 
    // K increments. 
    static int longestSubArray(int A[], int N, int K) 
    { 
      
        // Initialize the result variable 
        // Even though the K is 0, 
        // the required longest subarray, 
        // in that case, will also be of length 1 
        int res = 1; 
      
        // Initialize the prefix sum array 
        int preSum[] = new int[N + 1]; 
      
        // Build the prefix sum array 
        preSum[0] = A[0]; 
        for (int i = 0; i < N; i++) 
            preSum[i + 1] = preSum[i] + A[i]; 
      
        // Build the segment tree 
        // for range max query 
        build(A, 0, N - 1, 0); 
      
        // Loop through the array 
        // with a starting point as i 
        // for the required subarray till 
        // the longest subarray is found 
        for (int i = 0; i < N; i++) 
        { 
      
            int start = i, end = N - 1, 
                mid, 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 max element 
                // in the range [i, mid] 
                // using Segment Tree 
                int max_element = query(0, N - 1, 
                                        i, mid, 0); 
      
                // Total sum of subarray after increments 
                int expected_sum = (mid - i + 1) 
                                * max_element; 
      
                // Actual sum of elements 
                // before increments 
                int actual_sum = preSum[mid + 1] 
                                - preSum[i]; 
      
                // Check if such increment is possible 
                // If true, then current i 
                // is the actual starting point 
                // of the required longest subarray 
                if (expected_sum - actual_sum <= K)
                { 
      
                    // Now for finding the endpoint 
                    // for this range 
                    // Perform the Binary search again 
                    // with the updated start 
                    start = mid + 1; 
      
                    // Store max end point for the range 
                    // to give longest subarray 
                    max_index = Math.max(max_index, mid); 
                } 
      
                // If false, it means that 
                // the selected range is invalid 
                else 
                { 
      
                    // Perform the Binary Search again 
                    // with the updated end 
                    end = mid - 1; 
                } 
            } 
      
            // Store the length of longest subarray 
            res = Math.max(res, max_index - i + 1); 
        } 
      
        // Return result 
        return res; 
    } 
      
    // Driver code 
    public static void main (String[] args) 
    { 
        int arr[] = { 2, 0, 4, 6, 7 }, K = 6; 
        int N = arr.length; 
      
        System.out.println(longestSubArray(arr, N, K)); 
    } 
}
  
// This code is contributed by AnkitRai01


Python3
# Python3 program to find the length of 
# Longest Subarray with same elements 
# in atmost K increments 
  
# Initialize array for segment tree 
segment_tree = [0]*(4 * 1000000); 
  
# Function that builds the segment 
# tree to return the max element 
# in a range 
def build(A, start, end, node) : 
  
    if (start == end) :
          
        # update the value in segment 
        # tree from given array 
        segment_tree[node] = A[start]; 
  
    else :
          
        # find the middle index 
        mid = (start + end) // 2; 
  
        # If there are more than one 
        # elements, then recur for left 
        # and right subtrees and 
        # store the max of values in this node 
        segment_tree[node] = max( 
                build(A, start, mid, 2 * node + 1), 
                build(A, mid + 1, end, 2 * node + 2)); 
  
    return segment_tree[node]; 
  
# Function to return the max 
# element in the given range 
def query(start, end, l, r, node) :
  
    # If the range is out of bounds, 
    # return -1 
    if (start > r or end < l) :
        return -1; 
          
    if (start >= l and end <= r) :
        return segment_tree[node];
          
    mid = (start + end) // 2; 
  
    return max(query(start, mid, l, 
                    r, 2 * node + 1), 
            query(mid + 1, end, l, 
                    r, 2 * node + 2)); 
  
# Function that returns length of longest 
# subarray with same elements in atmost 
# K increments. 
def longestSubArray(A, N, K) : 
  
    # Initialize the result variable 
    # Even though the K is 0, 
    # the required longest subarray, 
    # in that case, will also be of length 1 
    res = 1; 
  
    # Initialize the prefix sum array 
    preSum = [0] * (N + 1); 
  
    # Build the prefix sum array 
    preSum[0] = A[0]; 
    for i in range(N) :
        preSum[i + 1] = preSum[i] + A[i]; 
  
    # Build the segment tree 
    # for range max query 
    build(A, 0, N - 1, 0); 
  
    # Loop through the array 
    # with a starting point as i 
    # for the required subarray till 
    # the longest subarray is found 
    for i in range(N) :
  
        start = i;
        end = N - 1;
        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 max element 
            # in the range [i, mid] 
            # using Segment Tree 
            max_element = query(0, N - 1, i, mid, 0); 
  
            # Total sum of subarray after increments 
            expected_sum = (mid - i + 1) * max_element; 
  
            # Actual sum of elements 
            # before increments 
            actual_sum = preSum[mid + 1] - preSum[i]; 
  
            # Check if such increment is possible 
            # If true, then current i 
            # is the actual starting point 
            # of the required longest subarray 
            if (expected_sum - actual_sum <= K) : 
  
                # Now for finding the endpoint 
                # for this range 
                # Perform the Binary search again 
                # with the updated start 
                start = mid + 1; 
  
                # Store max end point for the range 
                # to give longest subarray 
                max_index = max(max_index, mid); 
  
            # If false, it means that 
            # the selected range is invalid 
            else :
  
                # Perform the Binary Search again 
                # with the updated end 
                end = mid - 1; 
  
        # Store the length of longest subarray 
        res = max(res, max_index - i + 1); 
  
    # Return result 
    return res; 
  
# Driver code 
if __name__ == "__main__" : 
  
    arr = [ 2, 0, 4, 6, 7 ]; K = 6; 
    N = len(arr); 
  
    print(longestSubArray(arr, N, K)); 
  
# This code is contributed by AnkitRai01


C#
// C# program to find the length of 
// longest Subarray with same elements 
// in atmost K increments 
using System;
  
class GFG 
{
      
    // Initialize array for segment tree 
    static int []segment_tree = new int[4 * 1000000]; 
      
    // Function that builds the segment 
    // tree to return the max element 
    // in a range 
    static int build(int []A, int start, int end, 
                    int node) 
    { 
        if (start == end) 
          
            // update the value in segment 
            // tree from given array 
            segment_tree[node] = A[start]; 
      
        else
        { 
              
            // find the middle index 
            int mid = (start + end) / 2; 
      
            // If there are more than one 
            // elements, then recur for left 
            // and right subtrees and 
            // store the max of values in this node 
            segment_tree[node] = Math.Max( 
                    build(A, start, mid, 2 * node + 1), 
                    build(A, mid + 1, end, 2 * node + 2)); 
        } 
        return segment_tree[node]; 
    } 
      
    // Function to return the max 
    // element in the given range 
    static int query(int start, int end, int l, int r, 
                    int node) 
    { 
        // If the range is out of bounds, 
        // return -1 
        if (start > r || end < l) 
            return -1; 
        if (start >= l && end <= r) 
            return segment_tree[node]; 
        int mid = (start + end) / 2; 
      
        return Math.Max(query(start, mid, l, 
                        r, 2 * node + 1), 
                        query(mid + 1, end, l, 
                        r, 2 * node + 2)); 
    } 
      
    // Function that returns length of longest 
    // subarray with same elements in atmost 
    // K increments. 
    static int longestSubArray(int []A, int N, int K) 
    { 
      
        // Initialize the result variable 
        // Even though the K is 0, 
        // the required longest subarray, 
        // in that case, will also be of length 1 
        int res = 1; 
      
        // Initialize the prefix sum array 
        int []preSum = new int[N + 1]; 
      
        // Build the prefix sum array 
        preSum[0] = A[0]; 
        for (int i = 0; i < N; i++) 
            preSum[i + 1] = preSum[i] + A[i]; 
      
        // Build the segment tree 
        // for range max query 
        build(A, 0, N - 1, 0); 
      
        // Loop through the array 
        // with a starting point as i 
        // for the required subarray till 
        // the longest subarray is found 
        for (int i = 0; i < N; i++) 
        { 
      
            int start = i, end = N - 1, 
                mid, 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 max element 
                // in the range [i, mid] 
                // using Segment Tree 
                int max_element = query(0, N - 1, 
                                        i, mid, 0); 
      
                // Total sum of subarray after increments 
                int expected_sum = (mid - i + 1) 
                                * max_element; 
      
                // Actual sum of elements 
                // before increments 
                int actual_sum = preSum[mid + 1] 
                                - preSum[i]; 
      
                // Check if such increment is possible 
                // If true, then current i 
                // is the actual starting point 
                // of the required longest subarray 
                if (expected_sum - actual_sum <= K)
                { 
      
                    // Now for finding the endpoint 
                    // for this range 
                    // Perform the Binary search again 
                    // with the updated start 
                    start = mid + 1; 
      
                    // Store max end point for the range 
                    // to give longest subarray 
                    max_index = Math.Max(max_index, mid); 
                } 
      
                // If false, it means that 
                // the selected range is invalid 
                else
                { 
      
                    // Perform the Binary Search again 
                    // with the updated end 
                    end = mid - 1; 
                } 
            } 
      
            // Store the length of longest subarray 
            res = Math.Max(res, max_index - i + 1); 
        } 
      
        // Return result 
        return res; 
    } 
      
    // Driver code 
    public static void Main(String[] args) 
    { 
        int []arr = { 2, 0, 4, 6, 7 };
        int K = 6; 
        int N = arr.Length; 
      
        Console.WriteLine(longestSubArray(arr, N, K)); 
    } 
}
  
// This code is contributed by PrinciRaj1992


输出:
3

时间复杂度: O(N *(log(N)) 2 )