在最多 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.