能被两个给定字符串整除的最小字符串


本文旨在确定最小的字符串,它是两个给定字符串的倍数。一个有趣的观察是,对于两个给定的字符串 s 和 t,字符串 s 是 t 的倍数当且仅当 s 可以通过重复 t 一次或多次来形成。我们必须找到最小的这样的字符串。

问题陈述

给定两个非空字符串 s1 和 s2,长度分别为 n 和 m,目标是确定最小的字符串,它是 s1 和 s2 的倍数。

如果存在一个字符串 z 使得 x = yz,则字符串 x 可被字符串 y 整除。换句话说,y 是 x 的因子。能够被 s 和 t 整除的字符串必须是它们最大公约数 (GCD) 的倍数。

示例

Input: s1 = “abab”, s2 = “ab”
Output: abab

解释

s1 = s2 + s2。因此,最小的可整除字符串是 s1 本身。

Input: s1 = “abcdef”, s2 = “z”
Output: -1

解释

s1 和 s2 的最大公约数不存在,因此不存在这样的输出。

Input: s1 = “aaaaa”, s2 = “aca”
Output: -1

解释

s1 和 s2 的最大公约数不存在,因此不存在这样的输出。

解决方案方法

查找长度最短且是字符串 S 和 T 的倍数的字符串的暴力方法是生成这两个字符串的所有可能组合,并检查每个组合是否都可以被 S 和 T 整除。我们可以从生成 S 和 T 的所有可能的子串开始,然后将它们连接起来形成所有可能的组合。

生成所有可能的组合后,我们可以检查每个组合是否可以被 S 和 T 整除。要确定一个字符串是否可以被另一个字符串整除,我们可以使用模运算符来检查当我们将字符串除以另一个字符串时余数是否为零。

这种暴力方法的时间复杂度为 O(N^3),其中 N 表示输入字符串的长度。对于大型输入,这种方法效率低下,因此我们使用基于最大公约数 (GCD) 概念的更高效的方法。

步骤

  • 声明并初始化一个名为“findSmallestString”的函数,该函数以参数形式接收字符串“s”和“t”作为输入。

  • 分别用字符串“s”和“t”的长度初始化两个整数“n”和“m”。

  • 使用“lcm”函数计算“n”和“m”的最小公倍数 (LCM)。

  • 连接字符串“s”和“t”以形成一个新的字符串“st”。

  • 初始化一个名为“result”的空字符串。

  • 遍历字符串“s”和“t”,直到找到不匹配项。将匹配的字符添加到“result”字符串。

  • 如果两个字符串的长度相等,则输出字符串“s”并退出函数。

  • 如果“s”的长度大于“t”,则交换“n”和“m”的值以及“s”和“t”的值。

  • 在公共前缀之后提取“t”的剩余部分,并将其存储在名为“repeatString”的字符串中。

  • 重复“repeatString” “l / m”次并将结果添加到“result”字符串。

示例

以下是上述方法的程序:

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

// Function to determine the greatest common divisor of two numbers
int gcd(int num1, int num2) {
   if (num2 == 0)
      return num1;
   return gcd(num2, num1 % num2);
}

// Function to compute the least common multiple of two numbers
int lcm(int num1, int num2) {
   return (num1 / gcd(num1, num2)) * num2;
}

void findSmallestString(char *s, char *t) {
   int n = strlen(s), m = strlen(t);
   int l = lcm(n, m);
   // Concatenate s and t to make st
   char st[n + m + 1];
   strcpy(st, s);
   strcat(st, t);
   // Initialize result string
   char result[n + m + 1];
   strcpy(result, "");
   // Add the common prefix of s and t to the result string
   for (int i = 0; i < (n < m ? n : m); i++) {
      if (s[i] != t[i]) {
         printf("-1\n");
         return;
      }
      strncat(result, &s[i], 1);
   }
   // If s and t are equal, output s
   if (n == m) {
      printf("%s\n", s);
      return;
   }
   // Swap s and t if n > m
   if (n > m) {
      int temp = n;
      n = m;
      m = temp;
      char *tempStr = s;
      s = t;
      t = tempStr;
   }
   // Repeat the remainder of t (after the common prefix) (l / m) times
   char repeatString[m - n + 1];
   strcpy(repeatString, &t[n]);
   for (int i = 0; i < l / m; i++) {
      strcat(result, repeatString);
   }
   printf("%s\n", result);
}
int main() {
   char S[] = "bcdbcd";
   char T[] = "bcd";
   printf("Minimum length string that is a multiple of the two given strings: ");
   findSmallestString(S, T);
   return 0;
}

输出

Minimum length string that is a multiple of the two given strings: bcdbcd
// C++ program to find the minimum length string that is a multiple of the two given strings
#include <iostream>
#include <string>
using namespace std;

// Function to determine the greatest common divisor of two numbers
int gcd(int num1, int num2) {
   if (num2 == 0)
   return num1;
   return gcd(num2, num1 % num2);
}
// Function to computer the least common multiple of two numbers
int lcm(int num1, int num2) {
   return (num1 / gcd(num1, num2)) * num2;
}
// Function to find the string of minimum length which is a multiple of strings s and t
void findSmallestString(string s, string t) {
   int n = s.length(), m = t.length();
   // Calculate LCM of n and m
   int l = lcm(n, m);
   // Concatenate s and t to make st
   string st = s + t;
   // Initialize result string
   string result = "";
   // Add the common prefix of s and t to the result string
   for (int i = 0; i < min(n, m); i++) {
      if (s[i] != t[i]) {
         cout << -1 << endl;
         return;
      }
      result += s[i];
   }
   // If s and t are equal, output s
   if (n == m) {
      cout << s << endl;
      return;
   }
   // Swap s and t if n > m
   if (n > m) {
      swap(n, m);
      swap(s, t);
   }
   // Repeat the remainder of t (after the common prefix) (l / m) times
   string repeatString = t.substr(n);
   for (int i = 0; i < l / m; i++) {
      result += repeatString;
   }
   // Print the resultant string
   cout << result << endl;
}
int main() {
   string S = "bcdbcd", T = "bcd";
   cout << "Minimum length string that is a multiple of the two given strings: "; 
   findSmallestString(S, T);
   return 0;
}

输出

Minimum length string that is a multiple of the two given strings: bcdbcd
public class SmallestMultipleString {
   // Function to determine the greatest common divisor of two numbers
   static int gcd(int num1, int num2) {
      if (num2 == 0)
         return num1;
      return gcd(num2, num1 % num2);
   }

   // Function to compute the least common multiple of two numbers
   static int lcm(int num1, int num2) {
      return (num1 / gcd(num1, num2)) * num2;
   }

   static void findSmallestString(String s, String t) {
      int n = s.length();
      int m = t.length();
      // Calculate LCM of n and m
      int l = lcm(n, m);
      // Concatenate s and t to make st
      String st = s + t;
      // Initialize result string
      StringBuilder result = new StringBuilder();
      // Add the common prefix of s and t to the result string
      for (int i = 0; i < Math.min(n, m); i++) {
         if (s.charAt(i) != t.charAt(i)) {
            System.out.println("-1");
            return;
         }
         result.append(s.charAt(i));
      }
      // If s and t are equal, output s
      if (n == m) {
         System.out.println(s);
         return;
      }
      // Swap s and t if n > m
      if (n > m) {
         int temp = n;
         n = m;
         m = temp;
         String tempStr = s;
         s = t;
         t = tempStr;
      }
      // Repeat the remainder of t (after the common prefix) (l / m) times
      String repeatString = t.substring(n);
      for (int i = 0; i < l / m; i++) {
         result.append(repeatString);
      }
      System.out.println(result);
   }

   public static void main(String[] args) {
      String S = "bcdbcd";
      String T = "bcd";
      System.out.print("Minimum length string that is a multiple of the two given strings: ");
      findSmallestString(S, T);
   }
}

输出

Minimum length string that is a multiple of the two given strings: bcdbcd
# Function to determine the greatest common divisor of two numbers
def gcd(num1, num2):
   if num2 == 0:
      return num1
   return gcd(num2, num1 % num2)

# Function to compute the least common multiple of two numbers
def lcm(num1, num2):
   return (num1 // gcd(num1, num2)) * num2

def find_smallest_string(s, t):
   n = len(s)
   m = len(t)
   # Calculate LCM of n and m
   l = lcm(n, m)
   # Concatenate s and t to make st
   st = s + t
   # Initialize result string
   result = ""
   # Add the common prefix of s and t to the result string
   for i in range(min(n, m)):
      if s[i] != t[i]:
         print("-1")
         return
      result += s[i]
   # If s and t are equal, output s
   if n == m:
      print(s)
      return
   # Swap s and t if n > m
   if n > m:
      n, m = m, n
      s, t = t, s
   # Repeat the remainder of t (after the common prefix) (l // m) times
   repeat_string = t[n:]
   for i in range(l // m):
      result += repeat_string
        
   print(result)

S = "bcdbcd"
T = "bcd"
print("Minimum length string that is a multiple of the two given strings:", end=" ")
find_smallest_string(S, T)

输出

Minimum length string that is a multiple of the two given strings: bcdbcd

时间复杂度 - O(n*log n)

程序的时间复杂度由 lcm 函数决定,该函数的时间复杂度为 O(log n),其中 n 是由 s 和 t 组成的连接字符串的长度。然后程序遍历结果字符串的长度,该长度最多可以达到 n + m 个字符。此外,由 lcm 函数调用的 gcd 函数的时间复杂度也为 O(log n)。总的来说,程序的时间复杂度由 lcm 函数决定。

空间复杂度 - O(n)

程序的空间复杂度为 O(n),其中 n 表示由 s 和 t 组合而成的连接字符串的大小。这是因为程序存储连接字符串 st、结果字符串和 repeatString 字符串,所有这些字符串的长度最多为 n 个字符。此外,gcd 和 lcm 函数需要恒定的空间,因此它们对整体空间复杂度的贡献可以忽略不计。总的来说,程序的空间复杂度由字符串存储所需的空间决定。

结论

本文讨论了一种朴素方法和一种高效方法,用于查找长度最小的字符串,该字符串是两个给定字符串的倍数。通过详细的示例解释了问题的概念。解决方案方法附带伪代码、各种程序以及时间和空间复杂度分析。

更新于:2023年10月27日

926 次浏览

开启你的职业生涯

完成课程获得认证

开始学习
广告