在最多 T 成本下,将 A 的最长子串更改为 B 的子串


在这个问题中,我们将找到 A 的最长子串,将其转换为从相同索引开始的 B 的子串,成本小于 T。

我们将使用二分查找算法来找到满足给定条件的子串的最大长度。然而,解决这个问题的朴素方法是找到满足问题陈述中条件的所有子串,并取长度最大的子串。

问题陈述 - 我们给定长度为 N 的字符串 A 和 B。此外,我们还给定一个总成本“T”。K 是将一个字符转换为另一个字符的成本。

我们需要找到 A 字符串的最长子串,以便我们可以使其与 B 字符串中从相同索引开始的子串相同,并且将一个子串转换为另一个子串的总成本不应超过 T。此外,打印此类子串的起始和结束索引。

示例

输入

A = "wxyz", B = "wpqt"; K = 2, T = 5;

输出

Starting index – 0, ending index - 2

解释

我们可以将“wxy”转换为“wpq”,成本为 4,小于 5。

输入

A = "wxyz", B = "ewrt"; K = 6, T = 5;

输出

‘Not possible.’

解释

这里,K 大于 T,并且没有从相同索引开始的子串相同。因此,无法找到子串。

输入

A = "pqdetr", B = "tqcets"; K = 1, T = 5;

输出

Starting index – 0, ending index - 5

解释

我们可以将字符串 A 作为子串,因为它的 5 个字符不同,我们可以将其与字符串 B 的成本为 5。

方法 1

在这种方法中,我们将使用二分查找算法来解决问题。我们将检查是否存在长度等于“中间长度”的有效子串。如果是,我们将在 [中间长度,字符串长度] 范围内查找有效子串长度。否则,我们将在 [0,中间长度] 范围内查找有效字符串长度。

我们将使用滑动窗口技术来查找特定长度的有效子串。

算法

  • 步骤 1 - 将 st_ind 和 end_ind 变量初始化为 -1,以存储最长子串的起始和结束索引。

  • 步骤 2 - 将“左”指针初始化为 0,将“右”指针初始化为字符串长度 + 1。还将“maxLen”初始化为 0,以存储子串的最大长度。

  • 步骤 3 - 现在,我们需要使用二分查找技术。因此,开始使用 while 循环进行迭代,直到左指针的值小于右指针的值。

  • 步骤 4 - 通过将左和右的总和除以 2 来找到中间长度。

  • 步骤 5 - 执行 isMidValid() 函数以检查是否存在长度等于“中间长度”的子串。

  • 步骤 5.1 - 在 isMidValid() 函数中,将“p”和“q”变量初始化为 0,作为滑动窗口指针。还将“ct”初始化为 0,以存储当前窗口使其与 B 字符串子串相同的成本。

  • 步骤 5.2 - 将“isValid”变量初始化为 false,以跟踪是否存在有效子串。

  • 步骤 5.3 - 使用循环进行迭代,直到“q”小于 A 字符串的长度。在循环中,如果 A[q] 和 B[q] 不相同,则将 K(将一个字符转换为另一个字符的成本)添加到“ct”。

  • 步骤 5.4 - 如果当前窗口的长度等于“midLen”,请按照以下步骤操作。

  • 步骤 5.4.1 - 如果“ct”小于 T,则将“isValid”设置为 true,将“st_ind”更新为 p,将“end_ind”更新为 q。

  • 步骤 5.4.2 - 要移动到下一个长度为“midLen”的窗口,请从“ct”中移除“A[p]”的成本,并将“p”的值增加 1。

  • 步骤 5.5 - 将“q”的值增加 1。

  • 步骤 5.6 - 返回“isValid”变量的值。

  • 步骤 6 - 如果函数返回 true,则更新“maxLen”并在右半部分搜索最大长度。否则,在左半部分搜索最大长度。

  • 步骤 7 - 最后,如果“st_ind”的值为 -1,则子串不可能。否则,打印最长有效子串的起始和结束索引。

示例

以下是上述算法的程序 -

#include <stdio.h>
#include <string.h>

// Starting and ending position of valid substring
int st_ind = -1, end_ind = -1;

int isMidValid(int midLen, char A[], char B[], int K, int T) {
   int p = 0, q = 0, len = strlen(A), ct = 0;
   // To track whether any substring of length MidLen is valid
   int isValid = 0;
   while (q < len) {
      // Cost for converting one character to another
      ct += (A[q] != B[q]) ? K : 0;
      // Shifting the window to the right
      if (q - p + 1 == midLen) {
         // For cost less than T
         if (ct <= T) {
            isValid = 1;
            st_ind = p;
            end_ind = q;
         }
         // Removing the left character from the window
         ct -= (A[p] != B[p]) ? K : 0;
         p++;
      }
      q++;
   }
   // Output
   return isValid;
}

void printLongestSubstr(char A[], char B[], int K, int T) {
   st_ind = -1, end_ind = -1;

   // Left and right pointers for binary search
   int left = 0;
   int right = strlen(A) + 1;

   // To store the maximum length
   int maxLen = 0;
   while (left < right) {
      // Mid calculation
      int midLen = (left + right) / 2;
      // If midLen length is valid
      if (isMidValid(midLen, A, B, K, T)) {
         // Update max length
         maxLen = midLen;
         // Find the maximum length in the right half
         left = midLen + 1;
      } else {
         // If mid is invalid, then find in the left half
         right = midLen;
      }
   }
   if (st_ind == -1)
      printf("Not possible\n");
   else
      printf("Starting index - %d ending index - %d\n", st_ind, end_ind);
}

int main() {
   char A[] = "wxyz";
   char B[] = "wpqt";
   int K = 2, T = 5;
   printLongestSubstr(A, B, K, T);
   return 0;
}

输出

Starting index - 0 ending index - 2
#include <bits/stdc++.h>
using namespace std;

// Starting and ending position of valid substring
int st_ind = -1, end_ind = -1;
bool isMidValid(int midLen, string &A, string &B, int K, int T) {
   int p = 0, q = 0, len = A.size(), ct = 0;
   // To track whether any substring of length MidLen is valid
   bool isValid = false;
   while (q < len) {
   
      // Cost for converting one character to other
      ct += ((A[q] != B[q]) ? K : 0);
      
      // Shifting the window to right
      if (q - p + 1 == midLen) {
      
         // For cost less than T
         if (ct <= T) {
            isValid = true;
            st_ind = p;
            end_ind = q;
         }
         
         // Removing left character from window
         ct -= ((A[p] != B[p]) ? K : 0);
         p++;
      }
      q++;
   }
   
   // output
   return isValid;
}
void printLongestSubstr(string A, string B, int K, int T) {
   st_ind = -1, end_ind = -1;

   // Left and right pointers for binary search
   int left = 0;
   int right = A.size() + 1;
   int len = A.size();

   // To store the maximum length
   int maxLen = 0;
   while (left < right) {

      // Mid calculation
      int midLen = (left + right) / 2;
      
      // If midLen length is valid
      if (isMidValid(midLen, A, B, K, T)) {
      
         // Update max length
         maxLen = midLen;
         
         // Find the maximum length in the right half
         left = midLen + 1;
      } else {
      
         // If mid is invalid, then find in the left half
         right = midLen;
      }
   }
   if (st_ind == -1)
      cout << "Not possible\n";
   else
      cout << "Starting index - " << st_ind << " ending index - " << end_ind << "\n";
}
int main() {
   string A = "wxyz", B = "wpqt";
   int K = 2, T = 5;
   printLongestSubstr(A, B, K, T);
   return 0;
}

输出

Starting index - 0 ending index - 2
public class LongestValidSubstring {

   // Starting and ending position of valid substring
   static int st_ind = -1;
   static int end_ind = -1;

   public static boolean isMidValid(int midLen, String A, String B, int K, int T) {
      int p = 0;
      int q = 0;
      int len = A.length();
      int ct = 0;
      // To track whether any substring of length MidLen is valid
      boolean isValid = false;
      while (q < len) {
         // Cost for converting one character to other
         ct += (A.charAt(q) != B.charAt(q)) ? K : 0;
         // Shifting the window to the right
         if (q - p + 1 == midLen) {
            // For cost less than T
            if (ct <= T) {
               isValid = true;
               st_ind = p;
               end_ind = q;
            }
            // Removing the left character from the window
            ct -= (A.charAt(p) != B.charAt(p)) ? K : 0;
            p++;
         }
         q++;
      }
      // Output
      return isValid;
   }

   public static void printLongestSubstr(String A, String B, int K, int T) {
      st_ind = -1;
      end_ind = -1;

      // Left and right pointers for binary search
      int left = 0;
      int right = A.length() + 1;

      // To store the maximum length
      int maxLen = 0;
      while (left < right) {
         // Mid calculation
         int midLen = (left + right) / 2;
         // If midLen length is valid
         if (isMidValid(midLen, A, B, K, T)) {
            // Update max length
             maxLen = midLen;
            // Find the maximum length in the right half
            left = midLen + 1;
         } else {
            // If mid is invalid, then find in the left half
            right = midLen;
         }
      }
      if (st_ind == -1) {
         System.out.println("Not possible");
      } else {
         System.out.println("Starting index - " + st_ind + " ending index - " + end_ind);
      }
   }

   public static void main(String[] args) {
      String A = "wxyz";
      String B = "wpqt";
      int K = 2;
      int T = 5;
      printLongestSubstr(A, B, K, T);
   }
}

输出

Starting index - 0 ending index - 2
# Starting and ending position of valid substring
st_ind = -1
end_ind = -1

def is_mid_valid(mid_len, A, B, K, T):
   global st_ind, end_ind
   p = 0
   q = 0
   len_A = len(A)
   ct = 0
   # To track whether any substring of length MidLen is valid
   is_valid = False
   while q < len_A:
      # Cost for converting one character to another
      ct += K if A[q] != B[q] else 0
      # Shifting the window to the right
      if q - p + 1 == mid_len:
         # For cost less than T
         if ct <= T:
            is_valid = True
            st_ind = p
            end_ind = q
         # Removing the left character from the window
         ct -= K if A[p] != B[p] else 0
         p += 1
      q += 1
   # Output
   return is_valid

def print_longest_substr(A, B, K, T):
   global st_ind, end_ind
   st_ind = -1
   end_ind = -1

   # Left and right pointers for binary search
   left = 0
   right = len(A) + 1

   # To store the maximum length
   max_len = 0
   while left < right:
      # Mid calculation
      mid_len = (left + right) // 2
      # If mid_len length is valid
      if is_mid_valid(mid_len, A, B, K, T):
         # Update max length
         max_len = mid_len
         # Find the maximum length in the right half
         left = mid_len + 1
      else:
         # If mid is invalid, then find in the left half
         right = mid_len
   if st_ind == -1:
      print("Not possible")
   else:
      print(f"Starting index - {st_ind} ending index - {end_ind}")

A = "wxyz"
B = "wpqt"
K = 2
T = 5
print_longest_substr(A, B, K, T)

输出

Starting index - 0 ending index - 2

时间复杂度 – O((logN)*N),其中 O(N) 用于滑动窗口,O(logN) 用于二分查找。

空间复杂度 – O(1),因为我们不使用任何动态空间。

结论

我们使用了二分查找和滑动窗口这两种不同的算法来解决单个问题。在许多情况下,我们需要使用多种算法来解决问题。

更新于:2023年10月23日

145 次浏览

开启您的职业生涯

通过完成课程获得认证

开始
广告
© . All rights reserved.