📜  对的最大长度链| DP-20

📅  最后修改于: 2021-04-24 22:46:50             🧑  作者: Mango

您会得到n对数字。在每对中,第一个数字始终小于第二个数字。如果b 资料来源:亚马逊访谈|套装2
例如,如果给定的对为{{5,24},{39,60},{15、28},{27、40},{50、90}},则可以形成的最长链为长度为3,且链为{{5,24},{27,40},{50,90}}

此问题是标准“最长增加子序列”问题的变体。以下是一个简单的两步过程。
1)按照第一个(或更小的)元素的升序对给定的对进行排序。为什么不需要排序?考虑示例{{6,8},{3,4}}以了解排序的需要。如果我们不进行排序就进行第二步,则输出为1。但是正确的输出为2。
2)现在运行修改后的LIS流程,在该流程中,我们将已经完成的LIS的第二个元素与正在构建的新LIS的第一个元素进行比较。
下面的代码是本文的方法2的略微修改。

C++
// CPP program for above approach
#include 
using namespace std;
  
// Structure for a Pair 
class Pair 
{
    public:
    int a; 
    int b; 
}; 
  
// This function assumes that arr[] 
// is sorted in increasing order 
// according the first 
// (or smaller) values in Pairs. 
int maxChainLength( Pair arr[], int n) 
{ 
    int i, j, max = 0; 
    int *mcl = new int[sizeof( int ) * n ]; 
      
    /* Initialize MCL (max chain length)
    values for all indexes */
    for ( i = 0; i < n; i++ ) 
        mcl[i] = 1; 
      
    /* Compute optimized chain 
    length values in bottom up manner */
    for ( i = 1; i < n; i++ ) 
        for ( j = 0; j < i; j++ ) 
            if ( arr[i].a > arr[j].b && 
                    mcl[i] < mcl[j] + 1) 
                mcl[i] = mcl[j] + 1; 
      
    // mcl[i] now stores the maximum 
    // chain length ending with Pair i 
      
    /* Pick maximum of all MCL values */
    for ( i = 0; i < n; i++ ) 
        if ( max < mcl[i] ) 
            max = mcl[i]; 
      
    /* Free memory to avoid memory leak */
      
    return max; 
} 
      
  
/* Driver code */
int main() 
{ 
    Pair arr[] = { {5, 24}, {15, 25}, 
                        {27, 40}, {50, 60} }; 
    int n = sizeof(arr)/sizeof(arr[0]); 
    cout << "Length of maximum size chain is " 
                  << maxChainLength( arr, n ); 
    return 0; 
} 
  
// This code is contributed by rathbhupendra


C
#include
#include
  
// Structure for a pair
struct pair
{
  int a;
  int b;
};
  
// This function assumes that 
// arr[] is sorted in increasing order
// according the first 
// (or smaller) values in pairs.
int maxChainLength( struct pair arr[], int n)
{
   int i, j, max = 0;
   int *mcl = (int*) malloc ( sizeof( int ) * n );
  
   /* Initialize MCL (max chain 
     length) values for all indexes */
   for ( i = 0; i < n; i++ )
      mcl[i] = 1;
  
   /* Compute optimized chain length 
   values in bottom up manner */
   for ( i = 1; i < n; i++ )
      for ( j = 0; j < i; j++ )
         if ( arr[i].a > arr[j].b && 
                mcl[i] < mcl[j] + 1)
            mcl[i] = mcl[j] + 1;
  
   // mcl[i] now stores the maximum 
   chain length ending with pair i
    
   /* Pick maximum of all MCL values */
   for ( i = 0; i < n; i++ )
      if ( max < mcl[i] )
         max = mcl[i];
  
   /* Free memory to avoid memory leak */
   free( mcl );
  
   return max;
}
  
  
/* Driver program to test above function */
int main()
{
    struct pair arr[] = { {5, 24}, {15, 25},
                          {27, 40}, {50, 60} };
    int n = sizeof(arr)/sizeof(arr[0]);
    printf("Length of maximum size chain is %d\n",
           maxChainLength( arr, n ));
    return 0;
}


Java
// Java program for above approach
class Pair
{
    int a;
    int b;
      
    public Pair(int a, int b) 
    {
        this.a = a;
        this.b = b;
    }
      
    // This function assumes that 
    // arr[] is sorted in increasing order
    // according the first (or smaller) 
    // values in pairs.
    static int maxChainLength(Pair arr[], int n)
    {
       int i, j, max = 0;
       int mcl[] = new int[n];
       
       /* Initialize MCL (max chain length) 
        values for all indexes */
       for ( i = 0; i < n; i++ )
          mcl[i] = 1;
       
       /* Compute optimized chain length 
        values in bottom up manner */
       for ( i = 1; i < n; i++ )
          for ( j = 0; j < i; j++ )
             if ( arr[i].a > arr[j].b && 
                    mcl[i] < mcl[j] + 1)
                mcl[i] = mcl[j] + 1;
       
       // mcl[i] now stores the maximum 
       // chain length ending with pair i
       
       /* Pick maximum of all MCL values */
       for ( i = 0; i < n; i++ )
          if ( max < mcl[i] )
             max = mcl[i];
       
       return max;
    }
  
    /* Driver program to test above function */
    public static void main(String[] args) 
    {
        Pair arr[] = new Pair[] 
        {
          new Pair(5,24), 
          new Pair(15, 25),                      
          new Pair (27, 40), 
          new Pair(50, 60)};
         System.out.println("Length of maximum 
                               size chain is " + 
                 maxChainLength(arr, arr.length));
    }
}


Python3
# Python program for above approach
class Pair(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
  
# This function assumes 
# that arr[] is sorted in increasing
# order according the 
# first (or smaller) values in pairs.
def maxChainLength(arr, n):
      
    max = 0
  
    # Initialize MCL(max chain 
    # length) values for all indices
    mcl = [1 for i in range(n)]
  
    # Compute optimized chain 
    # length values in bottom up manner
    for i in range(1, n):
        for j in range(0, i):
            if (arr[i].a > arr[j].b and 
                  mcl[i] < mcl[j] + 1):
                mcl[i] = mcl[j] + 1
  
    # mcl[i] now stores the maximum
    # chain length ending with pair i
  
    # Pick maximum of all MCL values
    for i in range(n):
        if (max < mcl[i]):
            max = mcl[i]
  
    return max
  
# Driver program to test above function
arr = [Pair(5, 24), Pair(15, 25), 
       Pair(27, 40), Pair(50, 60)]
  
print('Length of maximum size chain is',
      maxChainLength(arr, len(arr)))
  
# This code is contributed by Soumen Ghosh


C#
// Dynamic C# program to find 
// Maximum Length Chain of Pairs
using System;
  
class Pair 
{
    int a;
    int b;
      
    public Pair(int a, int b) 
    {
        this.a = a;
        this.b = b;
    }
      
    // This function assumes that arr[] 
    // is sorted in increasing order
    // according the first (or smaller) 
    // values in pairs.
    static int maxChainLength(Pair []arr, int n)
    {
        int i, j, max = 0;
        int []mcl = new int[n];
          
        // Initialize MCL (max chain length)
        // values for all indexes 
        for(i = 0; i < n; i++ )
            mcl[i] = 1;
          
        // Compute optimized chain length 
        // values in bottom up manner 
        for(i = 1; i < n; i++)
            for (j = 0; j < i; j++)
                if(arr[i].a > arr[j].b &&
                   mcl[i] < mcl[j] + 1)
                     
          // mcl[i] now stores the maximum 
          // chain length ending with pair i
          mcl[i] = mcl[j] + 1;
  
        // Pick maximum of all MCL values
        for ( i = 0; i < n; i++ )
            if (max < mcl[i] )
                max = mcl[i];
          
        return max;
    }
  
    // Driver Code
    public static void Main() 
    {
        Pair []arr = new Pair[] 
        {new Pair(5,24), new Pair(15, 25),
        new Pair (27, 40), new Pair(50, 60)};
        Console.Write("Length of maximum size 
                                chain is " + 
                 maxChainLength(arr, arr.Length));
    }
}
  
// This code is contributed by nitin mittal.


CPP14
// CPP program for above approach
#include 
using namespace std;
  
// Structure val
struct val 
{
    int first;
    int second;
};
  
map, int> m;
  
// Memoisation function
int findMaxChainLen(struct val p[], int n, 
                        int prev, int pos)
{
      
    // Check if pair { pos, prev } exists
    // in m
    if (m.find({ pos, prev }) != m.end()) 
    {
        return m[{ pos, prev }];
    }
  
    // Check if pos is >=n 
    if (pos >= n)
        return 0;
  
    // Check if p[pos].first is 
    // less than prev
    if (p[pos].first <= prev) 
    {
        return findMaxChainLen(p, n, prev, 
                                 pos + 1);
    }
  
    else 
    {
        int ans = max(findMaxChainLen(p, n, 
                             p[pos].second, 0) + 1,
                      findMaxChainLen(p, n, 
                                   prev, pos + 1));
        m[{ pos, prev }] = ans;
        return ans;
    }
}
  
// Function to calculate maximum
// chain length
int maxChainLen(struct val p[], int n)
{
    m.clear();
    
    // Call memoisation function
    int ans = findMaxChainLen(p, n, 0, 0);
    return ans;
}
  
// Driver Code
int main()
{
  
    int n = 5;
    val p[n];
    p[0].first = 5;
    p[0].second = 24;
  
    p[1].first = 39;
    p[1].second = 60;
  
    p[2].first = 15;
    p[2].second = 28;
  
    p[3].first = 27;
    p[3].second = 40;
  
    p[4].first = 50;
    p[4].second = 90;
      
    // Function Call
    cout << maxChainLen(p, n) << endl;
    return 0;
}


输出
Length of maximum size chain is 3

时间复杂度: O(n ^ 2),其中n是对的数量。

给定的问题也是“活动选择”问题的一种变体,可以在(nLogn)时间内解决。要将其解决为活动选择问题,请将对中的第一个元素视为活动选择问题中的开始时间,将对中的第二个元素视为结束时间。

另一种方法(自顶向下的动态编程):
现在,我们将探索使用自顶向下的动态编程方法(递归+记忆)解决此问题的方法。
由于我们将使用自上而下的方法解决上述问题,因此我们的第一步是弄清递归关系。获得递归关系的最好和最简单的方法是考虑我们在每个州或每个职位所拥有的选择。
如果我们仔细研究上述问题,我们会发现每个位置/索引都有两个选择。两种选择是:
选择1:选择特定位置的元素并浏览其余位置, (或)
选择2:将元素留在该位置,然后探索其余元素。
请注意,只有在该位置的第一个元素大于我们先前选择的第二个元素时,我们才可以选择该位置的元素(这是问题中给出的约束)。因此,在递归中,我们维护一个变量,该变量将告诉我们我们选择的上一个元素。
此外,我们必须最大化我们的答案。因此,我们必须通过在每个位置探索以上两个选择来找出最大的结果选项。
产生的递归关系将是:

T(n)= max(maxlenchain(p,n,p [pos] .second,0)+ 1,maxlenchain(p,n,prev_choosen_ele,pos + 1))
请注意,函数签名如下:
int cal(struct val p [],int n,int prev_choosen_ele,int pos);

但是,我们不应忘记递归的基本条件。如果不是这样,我们的代码将通过永远执行而不停止而享受假期。
因此,我们解决此问题的基本条件非常简单。如果我们到达探索的终点,我们将只返回0,因为不可能再有链条了。

if(pos> = n)返回0;

为了避免重复的任务,我们采用了动态编程魔术(降低您的时间复杂度是一种魔术)。我们将位置和上一个元素存储在地图中。如果我们碰巧以相同的前一个元素到达相同的位置,则不会再次重新计算。我们只是从地图中返回答案。
下面是上述方法的实现:

CPP14

// CPP program for above approach
#include 
using namespace std;
  
// Structure val
struct val 
{
    int first;
    int second;
};
  
map, int> m;
  
// Memoisation function
int findMaxChainLen(struct val p[], int n, 
                        int prev, int pos)
{
      
    // Check if pair { pos, prev } exists
    // in m
    if (m.find({ pos, prev }) != m.end()) 
    {
        return m[{ pos, prev }];
    }
  
    // Check if pos is >=n 
    if (pos >= n)
        return 0;
  
    // Check if p[pos].first is 
    // less than prev
    if (p[pos].first <= prev) 
    {
        return findMaxChainLen(p, n, prev, 
                                 pos + 1);
    }
  
    else 
    {
        int ans = max(findMaxChainLen(p, n, 
                             p[pos].second, 0) + 1,
                      findMaxChainLen(p, n, 
                                   prev, pos + 1));
        m[{ pos, prev }] = ans;
        return ans;
    }
}
  
// Function to calculate maximum
// chain length
int maxChainLen(struct val p[], int n)
{
    m.clear();
    
    // Call memoisation function
    int ans = findMaxChainLen(p, n, 0, 0);
    return ans;
}
  
// Driver Code
int main()
{
  
    int n = 5;
    val p[n];
    p[0].first = 5;
    p[0].second = 24;
  
    p[1].first = 39;
    p[1].second = 60;
  
    p[2].first = 15;
    p[2].second = 28;
  
    p[3].first = 27;
    p[3].second = 40;
  
    p[4].first = 50;
    p[4].second = 90;
      
    // Function Call
    cout << maxChainLen(p, n) << endl;
    return 0;
}
输出
3