📌  相关文章
📜  通过从末尾删除字符并在任意位置重新插入,将字符串A 转换为 B

📅  最后修改于: 2022-05-13 01:56:04.564000             🧑  作者: Mango

通过从末尾删除字符并在任意位置重新插入,将字符串A 转换为 B

给定两个互为字谜的字符串A 和 B,任务是尽可能以最少的操作将 A 转换为 B。操作被定义为删除 A 中的第一个或最后一个字符并将其插入回字符串中的任何位置。

例子:

方法:该方法基于动态规划和最长公共子序列(LCS)

直觉:

  • 不是通过将字符从 A 的末端移动到内部来从 A 形成 B,我们将尝试通过将字符从 B 的内部移动到它的末端来从 B 形成 A。很明显,这个问题是等价的。
  • 现在,在多次执行此反向操作之后,我们将得到一个结果字符串B' ,我们可以将其拆分为三个部分:
    B' = 前缀 + 核心 + 后缀
    在哪里
    • 核心由不动的字符组成,并且
    • prefix / suffix 是分别移到开头或结尾的字符。
  • 请注意,一旦我们移动了一个字符,再次移动它总是次优的。
    由于我们可以自由选择移动字符的顺序,所以我们应该选择从内向外移动前缀/后缀的字符。
    那么,以这种方式从 B 形成 B' 的成本是 len(prefix) + len(suffix)。
  • 核心是 B 的子序列:它仅由 B 中未移动的字符按原始顺序组成。确实,这是双向的——我们可以将 B 的任何子序列变成一个核心,并在它周围任意排列剩余的字母。
  • 现在我们的问题是找到一种方法将 A 分解为这三个部分:
    • 最小化 len(prefix) + len(suffix)。
    • 最大化 len(core) (未触及字符的数量)。
  • 这可以重新表述为找到 A 的最大长度子串,它是 B 的子序列

算法:这个问题可以用动态规划来解决,就像经典的 LCS(最长公共子序列)问题一样。有关精确的 DP 状态,请参阅代码中的注释。与 LCS 的主要区别在于我们不能在 dp[i][j] 中包含 dp[i-1][j],因为这会破坏 A 子串的连续性。

以下是上述方法的实现:

C++
// C++ implementation of the above approach
 
#include 
using namespace std;
 
// Function to find min operations
int minOperations(string A, string B)
{
    // dp[i][j] = length of longest
    //(contiguous) suffix of A[0..i]
    // that is a subsequence of B[0..j]
    int dp[1001][1001];
 
    // r = maximum value over all
    // dp[i][j] computed so far
    int r = 0;
 
    for (int i = 0; i <= A.size(); ++i) {
        for (int j = 0; j <= B.size(); ++j) {
 
            dp[i][j] = 0;
 
            if (i && j) {
 
                // any suffix of A[0..i]
                // which is a subsequence of B[0..j]
                // is also a subsequence of B[0..j-1]...
                dp[i][j] = dp[i][j - 1];
 
                // or, if last character matches (i.e.
                // A[i-1] == B[j-1]), and then the rest
                // of the suffix is a suffix of
                // A[0..i-1] and a subsequence of B[j-1]
                if (A[i - 1] == B[j - 1]) {
 
                    dp[i][j] = max(
                        dp[i][j],
                        1 + dp[i - 1][j - 1]);
                    r = max(r, dp[i][j]);
                }
            }
        }
    }
 
    // r = the length of the
    // longest (contiguous) substring
    // of A that is a subsequence of B
    return A.size() - r;
}
 
// Driver code
int main()
{
    string A = "edacb";
    string B = "abcde";
    cout << minOperations(A, B);
    return 0;
}


Java
// Java implementation of the above approach
import java.util.*;
public class GFG {
 
    // Function to find min operations
    static int minOperations(String A, String B)
    {
       
        // dp[i][j] = length of longest
        //(contiguous) suffix of A[0..i]
        // that is a subsequence of B[0..j]
        int[][] dp = new int[1001][1001];
 
        // r = maximum value over all
        // dp[i][j] computed so far
        int r = 0;
 
        for (int i = 0; i <= A.length(); ++i) {
            for (int j = 0; j <= B.length(); ++j) {
 
                dp[i][j] = 0;
 
                if (i > 0 && j > 0) {
 
                    // any suffix of A[0..i]
                    // which is a subsequence of B[0..j]
                    // is also a subsequence of B[0..j-1]...
                    dp[i][j] = dp[i][j - 1];
 
                    // or, if last character matches (i.e.
                    // A[i-1] == B[j-1]), and then the rest
                    // of the suffix is a suffix of
                    // A[0..i-1] and a subsequence of B[j-1]
                    if (A.charAt(i - 1)
                        == B.charAt(j - 1)) {
 
                        dp[i][j] = Math.max(
                            dp[i][j], 1 + dp[i - 1][j - 1]);
                        r = Math.max(r, dp[i][j]);
                    }
                }
            }
        }
 
        // r = the length of the
        // longest (contiguous) substring
        // of A that is a subsequence of B
        return A.length() - r;
    }
 
    // Driver code
    public static void main(String args[])
    {
        String A = "edacb";
        String B = "abcde";
        System.out.println(minOperations(A, B));
    }
}
 
// This code is contributed by Smim Hossain Mondal.


Python3



输出
3

时间复杂度: O(N^2)
辅助空间: O(N^2)