📌  相关文章
📜  使用给定的删除元素规则找到最小的数组大小

📅  最后修改于: 2021-04-24 20:40:05             🧑  作者: Mango

给定一个数字数组和一个常数k,请使用以下删除元素的规则将数组的大小最小化。

  • 可以一次删除3个元素。
  • 删除的三个元素必须在数组中相邻,即arr [i],arr [i + 1],arr [i + 2]。并且第二个元素必须比第一个元素大k,第三个元素必须比第二个元素大k,即arr [i + 1] – arr [i] = k和arr [i + 2] -arr [i + 1] = k。

例子:

Input: arr[] = {2, 3, 4, 5, 6, 4}, k = 1
Output: 0
We can actually remove all elements. 
First remove 4, 5, 6 => We get {2, 3, 4}
Now remove 2, 3, 4   => We get empty array {}

Input:  arr[] = {2, 3, 4, 7, 6, 4}, k = 1
Output: 3
We can only remove 2 3 4

来源:https://code.google.com/codejam/contest/4214486/dashboard#s=p2

强烈建议您最小化浏览器,然后自己尝试。
对于每个元素arr [i],都有两种可能性
1)要么不删除该元素。
2)删除OR元素(如果遵循删除规则)。删除元素后,又有两种可能性。
…..a)可以直接将其删除,即,初始arr [i + 1]为arr [i] + k,而arr [i + 2]为arr [i] + 2 * k。
…..b)存在x和y,使得arr [x] – arr [i] = k,arr [y] – arr [x] = k,以及子数组“ arr [i + 1…x-1]” &“ arr [x + 1…y-1]”可以完全删除。

下面是基于以上思想的递归算法。

// Returns size of minimum possible size of arr[low..high]
// after removing elements according to given rules
findMinSize(arr[], low, high, k)

// If there are less than 3 elements in arr[low..high]
1) If high-low+1 < 3, return high-low+1

// Consider the case when 'arr[low]' is not considered as
// part of any triplet to be removed.  Initialize result 
// using this case
2) result = 1 + findMinSize(arr, low+1, high)

// Case when 'arr[low]' is part of some triplet and removed
// Try all possible triplets that have arr[low]
3) For all i from low+1 to high
    For all j from i+1 to high
      Update result if all of the following conditions are met
      a) arr[i] - arr[low] = k  
      b) arr[j] - arr[i]  = k
      c) findMinSize(arr, low+1, i-1, k) returns 0
      d) findMinSize(arr, i+1, j-1, k) also returns 0
      e) Result calculated for this triplet (low, i, j)
         is smaller than existing result.

4) Return result

上述解决方案的时间复杂度是指数的。如果绘制完整的递归树,则可以观察到许多子问题一次又一次地得到解决。由于再次调用了相同的问题,因此此问题具有“重叠子问题”属性。像其他典型的动态编程(DP)问题一样,可以通过构造临时数组dp [] []来存储子问题的结果,从而避免相同子问题的重新计算。以下是基于动态编程的解决方案

以下是上述想法的实现。该实现是基于记忆的,即,它是递归的,并使用查找表dp [] []来检查子问题是否已解决。

C++
// C++ program to find size of minimum possible array after
// removing elements according to given rules
#include 
using namespace std;
#define MAX 1000
  
// dp[i][j] denotes the minimum number of elements left in
// the subarray arr[i..j].
int dp[MAX][MAX];
  
int minSizeRec(int arr[], int low, int high, int k)
{
    // If already evaluated
    if (dp[low][high] != -1)
        return dp[low][high];
  
    // If size of array is less than 3
    if ( (high-low + 1) < 3)
        return high-low +1;
  
    // Initialize result as the case when first element is
    // separated (not removed using given rules)
    int res = 1 + minSizeRec(arr, low+1, high, k);
  
    // Now consider all cases when first element forms a triplet
    // and removed. Check for all possible triplets (low, i, j)
    for (int i = low+1; i<=high-1; i++)
    {
        for (int j = i+1; j <= high; j++ )
        {
            // Check if this triplet follows the given rules of
            // removal. And elements between 'low' and 'i' , and
            //  between 'i' and 'j' can be recursively removed.
            if (arr[i] == (arr[low] + k) &&
                arr[j] == (arr[low] + 2*k) &&
                minSizeRec(arr, low+1, i-1, k) == 0 &&
                minSizeRec(arr, i+1, j-1, k) == 0)
            {
                 res = min(res, minSizeRec(arr, j+1, high, k));
            }
        }
    }
  
    // Insert value in table and return result
    return (dp[low][high] = res);
}
  
// This function mainlu initializes dp table and calls
// recursive function minSizeRec
int minSize(int arr[], int n, int k)
{
    memset(dp, -1, sizeof(dp));
    return minSizeRec(arr, 0, n-1, k);
}
  
// Driver prrogram to test above function
int main()
{
    int arr[] = {2, 3, 4, 5, 6, 4};
    int n = sizeof(arr)/sizeof(arr[0]);
    int k = 1;
    cout << minSize(arr, n, k) << endl;
    return 0;
}


Java
// Java program to find size of 
// minimum possible array after 
// removing elements according 
// to given rules 
class GFG 
{
  
    static int MAX = 1000;
  
    // dp[i][j] denotes the minimum 
    // number of elements left in 
    // the subarray arr[i..j]. 
    static int dp[][] = new int[MAX][MAX];
  
    static int minSizeRec(int arr[], int low,
                            int high, int k) 
    {
        // If already evaluated 
        if (dp[low][high] != -1) 
        {
            return dp[low][high];
        }
  
        // If size of array is less than 3 
        if ((high - low + 1) < 3) 
        {
            return high - low + 1;
        }
  
        // Initialize result as the
        // case when first element is 
        // separated (not removed 
        // using given rules) 
        int res = 1 + minSizeRec(arr, 
                        low + 1, high, k);
  
        // Now consider all cases when
        // first element forms a triplet 
        // and removed. Check for all 
        // possible triplets (low, i, j) 
        for (int i = low + 1; i <= high - 1; i++)
        {
            for (int j = i + 1; j <= high; j++) 
            {
                // Check if this triplet 
                // follows the given rules of 
                // removal. And elements 
                // between 'low' and 'i' , and 
                // between 'i' and 'j' can 
                // be recursively removed. 
                if (arr[i] == (arr[low] + k) && 
                    arr[j] == (arr[low] + 2 * k) &&
                    minSizeRec(arr, low + 1, i - 1, k) == 0 && 
                    minSizeRec(arr, i + 1, j - 1, k) == 0) 
                {
                    res = Math.min(res, minSizeRec(arr, j + 1, high, k));
                }
            }
        }
  
        // Insert value in table and return result 
        return (dp[low][high] = res);
    }
  
    // This function mainlu initializes
    // dp table and calls recursive
    // function minSizeRec 
    static int minSize(int arr[], int n, int k)
    {
        for (int i = 0; i < MAX; i++)
        {
            for (int j = 0; j < MAX; j++) 
            {
                dp[i][j] = -1;
            }
        }
        return minSizeRec(arr, 0, n - 1, k);
    }
  
    // Driver code 
    public static void main(String[] args) 
    {
        int arr[] = {2, 3, 4, 5, 6, 4};
        int n = arr.length;
        int k = 1;
        System.out.println(minSize(arr, n, k));
    }
} 
  
// This code is contributed by 29AjayKumar


Python3
# Python3 program to find size of 
# minimum possible array after 
# removing elements according to given rules 
MAX=1000
  
dp=[[-1 for i in range(MAX)] for i in range(MAX)]
# dp[i][j] denotes the minimum number of elements left in 
# the subarray arr[i..j]. 
  
def minSizeRec(arr,low,high,k):
      
    # If already evaluated 
    if dp[low][high] != -1:
        return dp[low][high]
  
    # If size of array is less than 3 
    if (high-low + 1) < 3:
        return (high-low + 1)
  
    # Initialize result as the case when first element is 
    # separated (not removed using given rules)
    res = 1 + minSizeRec(arr, low+1, high, k)
  
    # Now consider all cases when 
    # first element forms a triplet 
    # and removed. Check for all possible
    # triplets (low, i, j) 
  
    for i in range(low+1,high):
          
        for j in range(i+1,high+1):
              
            # Check if this triplet follows the given rules of
            # removal. And elements between 'low' and 'i' , and 
            # between 'i' and 'j' can be recursively removed.
            if (arr[i]==(arr[low]+k) and arr[j] == (arr[low] + 2*k) and
                minSizeRec(arr, low+1, i-1, k) == 0 and 
                minSizeRec(arr, i+1, j-1, k) == 0):
                res=min(res,minSizeRec(arr,j+1,high,k) )
                  
    # Insert value in table and return result 
    dp[low][high] = res
    return res
      
# This function mainly initializes dp table and calls
# recursive function minSizeRec 
def minSize(arr,n,k):
    dp=[[-1 for i in range(MAX)] for i in range(MAX)]
    return minSizeRec(arr, 0, n-1, k)
  
# Driver program to test above function
if __name__=='__main__':
    arr=[2, 3, 4, 5, 6, 4]
    n=len(arr)
    k=1
    print(minSize(arr,n,k))
      
# this code is contributed by sahilshelangia


C#
// C# program to find size of 
// minimum possible array after 
// removing elements according 
// to given rules 
using System;
  
class GFG 
{
  
    static int MAX = 1000;
  
    // dp[i,j] denotes the minimum 
    // number of elements left in 
    // the subarray arr[i..j]. 
    static int [,]dp = new int[MAX, MAX];
  
    static int minSizeRec(int []arr, int low,
                            int high, int k) 
    {
        // If already evaluated 
        if (dp[low, high] != -1) 
        {
            return dp[low, high];
        }
  
        // If size of array is less than 3 
        if ((high - low + 1) < 3) 
        {
            return high - low + 1;
        }
  
        // Initialize result as the
        // case when first element is 
        // separated (not removed 
        // using given rules) 
        int res = 1 + minSizeRec(arr, 
                        low + 1, high, k);
  
        // Now consider all cases when
        // first element forms a triplet 
        // and removed. Check for all 
        // possible triplets (low, i, j) 
        for (int i = low + 1; i <= high - 1; i++)
        {
            for (int j = i + 1; j <= high; j++) 
            {
                // Check if this triplet 
                // follows the given rules of 
                // removal. And elements 
                // between 'low' and 'i' , and 
                // between 'i' and 'j' can 
                // be recursively removed. 
                if (arr[i] == (arr[low] + k) && 
                    arr[j] == (arr[low] + 2 * k) &&
                    minSizeRec(arr, low + 1, i - 1, k) == 0 && 
                    minSizeRec(arr, i + 1, j - 1, k) == 0) 
                {
                    res = Math.Min(res, minSizeRec(arr, j + 1, high, k));
                }
            }
        }
  
        // Insert value in table and return result 
        return (dp[low, high] = res);
    }
  
    // This function mainlu initializes
    // dp table and calls recursive
    // function minSizeRec 
    static int minSize(int []arr, int n, int k)
    {
        for (int i = 0; i < MAX; i++)
        {
            for (int j = 0; j < MAX; j++) 
            {
                dp[i, j] = -1;
            }
        }
        return minSizeRec(arr, 0, n - 1, k);
    }
  
    // Driver code 
    public static void Main(String[] args) 
    {
        int []arr = {2, 3, 4, 5, 6, 4};
        int n = arr.Length;
        int k = 1;
        Console.WriteLine(minSize(arr, n, k));
    }
}
  
// This code contributed by Rajput-Ji


输出:

0