最小化给定字符串中的分区以获取另一个字符串
给定两个字符串A和B ,打印A中获得另一个字符串B所需的最小切片数。如果无法从A获得B ,则打印“-1”。
例子 :
Input: A = “geeksforgeeks”, B = “ksgek”
Output: 5
Explanation: g | ee | ks | forge | ek | s : minimum 5 slices are required to create B
Input: A = “topgames”, B = “mepo”
Output: 5
Explanation: t | o | p | ga | me | s : minimum 5 slices are required to create B
Input: A = “memk”, B = “memo”
Output: -1
Explanation: Not possible to create B with the help of A
方法:这个问题是最长公共子串问题的变体。做这个问题的主要思想是获取A和B之间最长的公共子串,然后根据A 中公共子串的起始索引决定从 A中切割该部分所需的切片数。然后用 1 片或 2 片从A中取出那部分。此外,从B中删除该子字符串,并在A的情况下将该子字符串替换为“0”或字母以外的任何内容。现在,请按照以下步骤解决此问题:
- 首先,用A和B的长度做一个简单的检查。如果B更长,则返回 -1。
- 现在第一步是在两个字符串中找到最长的公共子字符串。
- 现在,如果字符串A中该公共子字符串的开始索引或结束索引分别为 0 或N (A.length()-1) ,则只需 1 个切片即可将其切掉。
For example: A = “game” and B = “ga” then ga | me. Only one slice is required
- 如果子字符串在字符串A的第一个字符和最后一个字符之间,那么在这种情况下,需要 2 个切片来切掉该部分。
For example: A = “gamer” and B = “me” -> ga | me | r . Two slices are required
- 现在,通过从中删除当前最长的子字符串来减小B的大小。这样做是必要的,因为这样会在下一次调用longSubstring()中选择不同的子字符串作为最长的公共子字符串。
- 之后,将A中存在的公共子字符串替换为字符“0”。子字符串不能直接从A中删除,因为顺序很重要,因为我们使用A中存在的公共子字符串的索引来决定切片的数量。
- 重复相同的过程,直到字符串B变为空。
下面是上述方法的实现:
Java
// Java program for the above approach
import java.io.*;
class GFG {
// Function returning the ending points
// of LCS and the length of LCS
public static int[] longestSubString(
String X, String Y)
{
// Find length of both the Strings.
int m = X.length();
int n = Y.length();
// Variable to store length of
// longest common subString.
int result = 0;
// Variable to store ending point of
// longest common subString in X.
int endIndexX = 0;
int endIndexY = 0;
// Matrix to store result of two
// consecutive rows at a time.
int cache[][] = new int[2][m + 1];
// Variable to represent which row of
// matrix is current row.
int currentRow = 0;
// For a particular value of i and j,
// len[currRow][j] stores length of
// longest common subString in
// String X[0..i] and Y[0..j].
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0 || j == 0) {
cache[currentRow][j] = 0;
}
else if (X.charAt(i - 1)
== Y.charAt(j - 1)) {
cache[currentRow][j]
= cache[1 -
currentRow][j
- 1]
+ 1;
if (cache[currentRow][j]
> result) {
result
= cache[currentRow][j];
endIndexX = i - 1;
endIndexY = j - 1;
}
}
else {
cache[currentRow][j] = 0;
}
}
// Make current row as previous row and
// previous row as new current row.
currentRow = 1 - currentRow;
}
// Longest common subString is from index
// (endIndexX - result + 1) in X and
// (endIndexY - result + 1) in Y.
int[] array = new int[] { (endIndexX
- result
+ 1),
(endIndexY
- result
+ 1),
result };
return array;
}
// Function to replace used substring in A with 0's
public static String processString(String A,
int index,
int length)
{
String X = A.substring(0, index);
String Y = "";
// Insering "0" in place
// of that substring.
for (int i = 0; i < length; i++) {
Y += "0";
}
String Z = A.substring(index
+ length);
return (X + Y + Z);
}
// Function to return the minimum
// number of slices required.
public static int minimumSlice(String A,
String B)
{
// Checking the length of A and B.
if (A.length() < B.length())
return -1;
// If both are equal no slice required.
if (A.equals(B))
return 0;
int result = 0, n = (A.length() - 1);
// Loop continues until B is empty.
while (!B.isEmpty()) {
int[] processed
= longestSubString(A, B);
if (processed[2] == 0)
return -1;
// Incrementing result by 1 if
// longest substring start at index 0
// or the end point is equal to n
if ((processed[0]
+ processed[2] - 1 == n)
|| processed[0] == 0) {
// Result should only
// be incremented if
// character just before
// and after the
// substring is not "0";
// if "0" is there,
// then the slice
// has already been counted
if (processed[0] == 0) {
if (A.charAt(processed[0]
+ processed[2])
!= '0')
result++;
}
else {
if (A.charAt(processed[0] - 1)
!= '0')
result++;
}
}
// In any other case increment it by 2
else {
// Result should only
// be incremented if
// character just before
// and after the substring
// is not "0";
// if "0" is there,
// then the slice has
// already been counted.
if (A.charAt(processed[0]
+ processed[2])
!= '0') {
result++;
}
if (A.charAt(processed[0] - 1)
!= '0') {
result++;
}
}
// Reducing the size of B by
// removing current longest
// substring from it.
B = B.substring(0, processed[1])
+ B.substring(processed[1]
+ processed[2]);
// Clearing the used substring from A.
A = processString(A, processed[0],
processed[2]);
}
return result;
}
// Driver Code
public static void main(String[] args)
{
System.out.println(minimumSlice("topgames", "mepo"));
}
}
Python3
# Python 3 program for the above approach
# Function returning the ending points
# of LCS and the length of LCS
def longestSubString(
X, Y):
# Find length of both the Strings.
m = len(X)
n = len(Y)
# Variable to store length of
# longest common subString.
result = 0
# Variable to store ending point of
# longest common subString in X.
endIndexX = 0
endIndexY = 0
# Matrix to store result of two
# consecutive rows at a time.
cache = [[0 for x in range(m+1)] for y in range(2)]
# Variable to represent which row of
# matrix is current row.
currentRow = 0
# For a particular value of i and j,
# len[currRow][j] stores length of
# longest common subString in
# String X[0..i] and Y[0..j].
for i in range(m + 1):
for j in range(n + 1):
if (i == 0 or j == 0):
cache[currentRow][j] = 0
elif (X[i - 1] == Y[j - 1]):
cache[currentRow][j] = cache[1 - currentRow][j - 1] + 1
if (cache[currentRow][j]
> result):
result = cache[currentRow][j]
endIndexX = i - 1
endIndexY = j - 1
else:
cache[currentRow][j] = 0
# Make current row as previous row and
# previous row as new current row.
currentRow = 1 - currentRow
# Longest common subString is from index
# (endIndexX - result + 1) in X and
# (endIndexY - result + 1) in Y.
array = [(endIndexX
- result
+ 1),
(endIndexY
- result
+ 1),
result]
return array
# Function to replace used substring in A with 0's
def processString(A, index, length):
X = A[0: index]
Y = ""
# Insering "0" in place
# of that substring.
for i in range(length):
Y += "0"
Z = A[index + length:]
return (X + Y + Z)
# Function to return the minimum
# number of slices required.
def minimumSlice(A,
B):
# Checking the length of A and B.
if (len(A) < len(B)):
return -1
# If both are equal no slice required.
if (A == B):
return 0
result = 0
n = (len(A) - 1)
# Loop continues until B is empty.
while (len(B) != 0):
processed = longestSubString(A, B)
if (processed[2] == 0):
return -1
# Incrementing result by 1 if
# longest substring start at index 0
# or the end point is equal to n
if ((processed[0]
+ processed[2] - 1 == n)
or processed[0] == 0):
# Result should only
# be incremented if
# character just before
# and after the
# substring is not "0"
# if "0" is there,
# then the slice
# has already been counted
if (processed[0] == 0):
if (A[processed[0] + processed[2]] != '0'):
result += 1
else:
if (A[processed[0] - 1] != '0'):
result += 1
# In any other case increment it by 2
else:
# Result should only
# be incremented if
# character just before
# and after the substring
# is not "0"
# if "0" is there,
# then the slice has
# already been counted.
if (A[processed[0]
+ processed[2]]
!= '0'):
result += 1
if (A[processed[0] - 1] != '0'):
result += 1
# Reducing the size of B by
# removing current longest
# substring from it.
B = B[0:processed[1]] + B[processed[1] + processed[2]:]
# Clearing the used substring from A.
A = processString(A, processed[0],
processed[2])
return result
# Driver Code
if __name__ == "__main__":
print(minimumSlice("topgames", "mepo"))
# This code is contributed by ukasp.
C#
// C# program for the above approach
using System;
class GFG
{
// Function returning the ending points
// of LCS and the length of LCS
public static int[] longestSubstring(string X, string Y)
{
// Find length of both the strings.
int m = X.Length;
int n = Y.Length;
// Variable to store length of
// longest common substring.
int result = 0;
// Variable to store ending point of
// longest common substring in X.
int endIndexX = 0;
int endIndexY = 0;
// Matrix to store result of two
// consecutive rows at a time.
int[,] cache = new int[2, m + 1];
// Variable to represent which row of
// matrix is current row.
int currentRow = 0;
// For a particular value of i and j,
// len[currRow][j] stores length of
// longest common substring in
// string X[0..i] and Y[0..j].
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
{
cache[currentRow, j] = 0;
}
else if (X[i - 1] == Y[j - 1])
{
cache[currentRow, j]
= cache[1 - currentRow, j - 1]
+ 1;
if (cache[currentRow, j]
> result)
{
result
= cache[currentRow, j];
endIndexX = i - 1;
endIndexY = j - 1;
}
}
else
{
cache[currentRow, j] = 0;
}
}
// Make current row as previous row and
// previous row as new current row.
currentRow = 1 - currentRow;
}
// Longest common substring is from index
// (endIndexX - result + 1) in X and
// (endIndexY - result + 1) in Y.
int[] array = new int[] { (endIndexX
- result
+ 1),
(endIndexY
- result
+ 1),
result };
return array;
}
// Function to replace used substring in A with 0's
public static string processstring(string A,
int index,
int length)
{
string X = A.Substring(0, index);
string Y = "";
// Insering "0" in place
// of that substring.
for (int i = 0; i < length; i++)
{
Y += "0";
}
string Z = A.Substring(index
+ length);
return (X + Y + Z);
}
// Function to return the minimum
// number of slices required.
public static int minimumSlice(string A,
string B)
{
// Checking the length of A and B.
if (A.Length < B.Length)
return -1;
// If both are equal no slice required.
if (A.Equals(B))
return 0;
int result = 0, n = (A.Length - 1);
// Loop continues until B is empty.
while (B.Length != 0)
{
int[] processed
= longestSubstring(A, B);
if (processed[2] == 0)
return -1;
// Incrementing result by 1 if
// longest substring start at index 0
// or the end point is equal to n
if ((processed[0]
+ processed[2] - 1 == n)
|| processed[0] == 0)
{
// Result should only
// be incremented if
// character just before
// and after the
// substring is not "0";
// if "0" is there,
// then the slice
// has already been counted
if (processed[0] == 0)
{
if (A[processed[0] + processed[2]]
!= '0')
result++;
}
else
{
if (A[processed[0] - 1]
!= '0')
result++;
}
}
// In any other case increment it by 2
else
{
// Result should only
// be incremented if
// character just before
// and after the substring
// is not "0";
// if "0" is there,
// then the slice has
// already been counted.
if (A[processed[0] + processed[2]]
!= '0')
{
result++;
}
if (A[processed[0] - 1]
!= '0')
{
result++;
}
}
// Reducing the size of B by
// removing current longest
// substring from it.
B = B.Substring(0, processed[1])
+ B.Substring(processed[1]
+ processed[2]);
// Clearing the used substring from A.
A = processstring(A, processed[0],
processed[2]);
}
return result;
}
// Driver Code
public static void Main()
{
Console.Write(minimumSlice("topgames", "mepo"));
}
}
// This code is contributed by gfgking.
5
时间复杂度: O(N*(M 2 )) 其中 N 是字符串A 的长度,M 是字符串B 的长度
辅助空间: O(M)