在给定的 K 个排列中找到最长公共子序列 (LCS)
给定二维数组arr[][]中从1 到 N的K个数字排列。任务是找到这些 K 个排列的最长公共子序列。
例子:
Input: N = 4, K = 3
arr[][] = {{1, 4, 2, 3},
{4, 1, 2, 3},
{1, 2, 4, 3}}
Output: 3
Explanation: Longest common subsequence is {1, 2, 3} which has length 3.
Input: N = 6, K = 3,
arr[][] = {{2, 5, 1, 4, 6, 3},
{5, 1, 4, 3, 2, 6},
{5, 4, 2, 6, 3, 1}}
Output: 3
Explanation: Longest common subsequence is {5, 4, 6} which has length 3.
方法:这个问题是最长公共子序列的扩展。该解决方案基于动态规划的概念。请按照以下步骤操作:
- 创建一个二维数组(pos[][]) 来存储每个序列中从 1 到 N 的所有数字的位置,其中 pos[i][j] 表示值 j 在第 i 个序列中的位置。
- 初始化一个数组(dp[]),其中dp[i]存储在位置 i 结束的最长公共子序列。
- 将第一个序列视为参考,并为第一个序列的每个元素检查它们在其他序列中的相对位置。
- 遍历所有可能的索引 j 使得j < i并查看第一个序列的索引 i处的值是否可以附加到以 j 结尾的最长递增子序列。
- 这是通过检查数字arr[0][j]的位置是否小于等于值 arr[0][i]在所有排列中的位置来完成的。然后 arr[0][i] 处的值可以附加到以位置 j 结尾的序列。
- 将第一个序列视为参考,并为第一个序列的每个元素检查它们在其他序列中的相对位置。
- 所以递归是dp[i] = max(dp[i], 1 + dp[j]) 。
- 数组 dp[] 的最大值就是答案。
请参见下图:
Illustration:
Take the following example:
N = 4, K = 3, arr[][] = {{1, 4, 2, 3},
{4, 1, 2, 3},
{1, 2, 4, 3}}
- Form the position array: pos[][] = {{1, 3, 4, 2},
{2, 3, 4, 1},
{1, 2, 4, 3}}
In first sequence 1 is in 1st position, 2 in 3rd position, 3 in 4th and 4 in 2nd position. And so on for the other sequences. - Initialize dp[] array: The dp[] array is initialized and it initially dp[] = {0, 0, 0, 0}
- Reference sequence: The first sequence i{1, 4, 2, 3} is used as the reference sequence i.e. relative positions of elements in other sequences are checked according to this one.
- For i = 1: dp[1] = 1 because any sequence of length 1 is a increasing sequence. Now dp[] = {1, 0, 0, 0}
- For i = 2: Now relative position of 4 and 1 will be checked in all the 3 sequences. In 2nd sequence and 3rd sequence the relative position is not maintained. So dp[2] = dp[1]. Now dp[] = {1, 1, 0, 0}.
- For i = 3: Relative positions of (1, 4, 2) are checked.
When j = 1 i.e. value relative position of 1 and 2 are checked it satisfies the condition pos[ind][arr[1][1]] < pos[ind][arr[1][3]] for all ind in range [1, K]. So dp[3] = max(dp[3], dp[1]+1) = max(0, 2) = 2.
Now dp[] = {1, 1, 2, 0} - For i = 4: Here also when j = 3, then pos[ind][arr[1][3]] < pos[ind][arr[1][4]] for all ind in range [1, K]. So the 4th element of 1st sequence can be appended in the longest increasing subsequence ending at 3rd index. dp[4] = dp[3] + 1 = 2 + 1 = 3.
Now dp[] = {1, 1, 2, 3} - The maximum value in dp[] is 3. Therefore, the maximum length of the longest increasing subsequence is 3.
Note: 0 based indexing is used in the actual implementation. Here 1 based indexing is used for easy understanding
下面是上述方法的实现。
C++
// C++ code to find the longest common
// sub sequence of k permutations.
#include
using namespace std;
// Function to find the longest common
// sub sequence of k permutations.
int findLcs(vector> &arr,
int n, int k)
{
// Variable to keep track of the length
// of the longest common sub sequence
int maxLen = 0;
// position array to keep track
// of position of elements
// in each permutation
int pos[k][n];
// Array to store the length of LCS
int dp[n];
for (int i = 0; i < k; i++)
{
for (int j = 0; j < n; j++)
{
pos[i][arr[i][j] - 1] = j;
}
}
// Loop to calculate the LCS
// of all the permutations
for (int i = 0; i < n; i++)
{
dp[i] = 1;
for (int j = 0; j < i; j++)
{
bool good = true;
for (int p = 0; p < k; p++)
{
if (pos[p][arr[0][j] - 1]
> pos[p][arr[0][i] - 1])
{
good = false;
break;
}
}
if (good)
{
dp[i] = max(dp[i], 1 + dp[j]);
maxLen = max(maxLen, dp[i]);
}
}
}
return maxLen;
}
// Driver code
int main()
{
vector> arr =
{{2, 5, 1, 4, 6, 3},
{5, 1, 4, 3, 2, 6},
{5, 4, 2, 6, 3, 1}};
int N = arr[0].size();
int K = 3;
// Function Call
cout << findLcs(arr, N, K);
return 0;
}
Java
// Java code to find the longest common
// sub sequence of k permutations.
import java.util.*;
class GFG{
// Function to find the longest common
// sub sequence of k permutations.
static int findLcs(int[][]arr,
int n, int k)
{
// Variable to keep track of the length
// of the longest common sub sequence
int maxLen = 0;
// position array to keep track
// of position of elements
// in each permutation
int [][]pos = new int[k][n];
// Array to store the length of LCS
int []dp = new int[n];
for (int i = 0; i < k; i++)
{
for (int j = 0; j < n; j++)
{
pos[i][arr[i][j] - 1] = j;
}
}
// Loop to calculate the LCS
// of all the permutations
for (int i = 0; i < n; i++)
{
dp[i] = 1;
for (int j = 0; j < i; j++)
{
boolean good = true;
for (int p = 0; p < k; p++)
{
if (pos[p][arr[0][j] - 1]
> pos[p][arr[0][i] - 1])
{
good = false;
break;
}
}
if (good)
{
dp[i] = Math.max(dp[i], 1 + dp[j]);
maxLen = Math.max(maxLen, dp[i]);
}
}
}
return maxLen;
}
// Driver code
public static void main(String[] args)
{
int[][] arr =
{{2, 5, 1, 4, 6, 3},
{5, 1, 4, 3, 2, 6},
{5, 4, 2, 6, 3, 1}};
int N = arr[0].length;
int K = 3;
// Function Call
System.out.print(findLcs(arr, N, K));
}
}
// This code is contributed by shikhasingrajput
Python3
# Python code for the above approach
# Function to find the longest common
# sub sequence of k permutations.
def findLcs(arr, n, k):
# Variable to keep track of the length
# of the longest common sub sequence
maxLen = 0
# position array to keep track
# of position of elements
# in each permutation
pos = [0] * k
for i in range(len(pos)):
pos[i] = [0] * n
# Array to store the length of LCS
dp = [0] * n
for i in range(k):
for j in range(n):
pos[i][arr[i][j] - 1] = j
# Loop to calculate the LCS
# of all the permutations
for i in range(n):
dp[i] = 1
for j in range(i):
good = True
for p in range(k):
if (pos[p][arr[0][j] - 1] > pos[p][arr[0][i] - 1]):
good = False
break
if (good):
dp[i] = max(dp[i], 1 + dp[j])
maxLen = max(maxLen, dp[i])
return maxLen
# Driver code
arr = [[2, 5, 1, 4, 6, 3], [5, 1, 4, 3, 2, 6], [5, 4, 2, 6, 3, 1]]
N = len(arr[0])
K = 3
# Function Call
print(findLcs(arr, N, K))
# This code is contributed by Saurabh Jaiswal
C#
// C# code to find the longest common
// sub sequence of k permutations.
using System;
class GFG {
// Function to find the longest common
// sub sequence of k permutations.
static int findLcs(int[, ] arr, int n, int k)
{
// Variable to keep track of the length
// of the longest common sub sequence
int maxLen = 0;
// position array to keep track
// of position of elements
// in each permutation
int[, ] pos = new int[k, n];
// Array to store the length of LCS
int[] dp = new int[n];
for (int i = 0; i < k; i++) {
for (int j = 0; j < n; j++) {
pos[i, arr[i, j] - 1] = j;
}
}
// Loop to calculate the LCS
// of all the permutations
for (int i = 0; i < n; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
bool good = true;
for (int p = 0; p < k; p++) {
if (pos[p, arr[0, j] - 1]
> pos[p, arr[0, i] - 1]) {
good = false;
break;
}
}
if (good) {
dp[i] = Math.Max(dp[i], 1 + dp[j]);
maxLen = Math.Max(maxLen, dp[i]);
}
}
}
return maxLen;
}
// Driver code
public static void Main(string[] args)
{
int[, ] arr = { { 2, 5, 1, 4, 6, 3 },
{ 5, 1, 4, 3, 2, 6 },
{ 5, 4, 2, 6, 3, 1 } };
int N = arr.GetLength(1);
int K = 3;
// Function Call
Console.WriteLine(findLcs(arr, N, K));
}
}
// This code is contributed by ukasp.
Javascript
3
时间复杂度: O(N 2 * K)
辅助空间: O(N * K)