题目## 题目
解题思路
- 兄弟单词的定义:两个单词包含相同的字符,但字符顺序不同
- 处理步骤:
- 对于给定的单词x,找出所有它的兄弟单词
- 将兄弟单词按字典序排序
- 输出第k个兄弟单词(如果存在)
- 判断兄弟单词的方法:
- 将两个单词分别排序后比较是否相等
- 排除与原单词完全相同的情况
代码
def is_brother(word1, word2):
"""判断两个单词是否为兄弟单词"""
# 相同单词不是兄弟单词
if word1 == word2:
return False
# 长度不同不是兄弟单词
if len(word1) != len(word2):
return False
# 排序后相同则是兄弟单词
return sorted(word1) == sorted(word2)
while True:
try:
# 读取输入
inputs = input().split()
n = int(inputs[0]) # 单词个数
words = inputs[1:n+1] # 单词列表
x = inputs[n+1] # 待查找单词
k = int(inputs[n+2]) # 第k个兄弟单词
# 找出所有兄弟单词
brothers = []
for word in words:
if is_brother(word, x):
brothers.append(word)
# 按字典序排序
brothers.sort()
# 输出结果
print(len(brothers))
if len(brothers) >= k:
print(brothers[k-1])
except EOFError:
break
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
bool isBrother(string word1, string word2) {
// 相同单词不是兄弟单词
if (word1 == word2) return false;
// 长度不同不是兄弟单词
if (word1.length() != word2.length()) return false;
// 排序后相同则是兄弟单词
sort(word1.begin(), word1.end());
sort(word2.begin(), word2.end());
return word1 == word2;
}
int main() {
int n;
while (cin >> n) {
vector<string> words(n);
for (int i = 0; i < n; i++) {
cin >> words[i];
}
string x;
int k;
cin >> x >> k;
// 找出所有兄弟单词
vector<string> brothers;
for (const string& word : words) {
if (isBrother(word, x)) {
brothers.push_back(word);
}
}
// 按字典序排序
sort(brothers.begin(), brothers.end());
// 输出结果
cout << brothers.size() << endl;
if (k <= brothers.size()) {
cout << brothers[k-1] << endl;
}
}
return 0;
}
import java.util.*;
public class Main {
private static boolean isBrother(String word1, String word2) {
// 相同单词不是兄弟单词
if (word1.equals(word2)) return false;
// 长度不同不是兄弟单词
if (word1.length() != word2.length()) return false;
// 排序后比较
char[] chars1 = word1.toCharArray();
char[] chars2 = word2.toCharArray();
Arrays.sort(chars1);
Arrays.sort(chars2);
return Arrays.equals(chars1, chars2);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
String[] words = new String[n];
for (int i = 0; i < n; i++) {
words[i] = sc.next();
}
String x = sc.next();
int k = sc.nextInt();
// 找出所有兄弟单词
List<String> brothers = new ArrayList<>();
for (String word : words) {
if (isBrother(word, x)) {
brothers.add(word);
}
}
// 按字典序排序
Collections.sort(brothers);
// 输出结果
System.out.println(brothers.size());
if (k <= brothers.size()) {
System.out.println(brothers.get(k-1));
}
}
}
}
算法及复杂度
- 算法:字符串排序 + 比较
- 时间复杂度: O ( n ⋅ m log m ) \mathcal{O}(n \cdot m \log m) O(n⋅mlogm),其中n是单词个数,m是单词的平均长度
- 空间复杂度: O ( n ) \mathcal{O}(n) O(n),用于存储兄弟单词列表
解题思路
这是一个经典的最长公共子串问题,可以使用动态规划来解决:
- 创建二维dp数组, d p [ i ] [ j ] dp[i][j] dp[i][j] 表示以 s t r 1 [ i ] str1[i] str1[i] 和 s t r 2 [ j ] str2[j] str2[j] 结尾的最长公共子串长度
- 当 s t r 1 [ i ] = = s t r 2 [ j ] str1[i] == str2[j] str1[i]==str2[j] 时, d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j] = dp[i-1][j-1] + 1 dp[i][j]=dp[i−1][j−1]+1
- 否则 d p [ i ] [ j ] = 0 dp[i][j] = 0 dp[i][j]=0
- 在填充dp数组的同时,记录最大长度和对应的结束位置
- 最后根据最大长度和结束位置截取子串
代码
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string findLongestCommonSubstring(string str1, string str2) {
// 确保str1是较短的字符串
if (str1.length() > str2.length()) {
swap(str1, str2);
}
int len1 = str1.length(), len2 = str2.length();
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
int maxLen = 0;
int endIndex = 0;
// 填充dp数组
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (str1[i-1] == str2[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1;
if (dp[i][j] > maxLen) {
maxLen = dp[i][j];
endIndex = i - 1; // 记录在较短串中的位置
}
}
}
}
return str1.substr(endIndex - maxLen + 1, maxLen);
}
int main() {
string str1, str2;
while (cin >> str1 >> str2) {
cout << findLongestCommonSubstring(str1, str2) << endl;
}
return 0;
}
import java.util.*;
public class Main {
public static String findLongestCommonSubstring(String str1, String str2) {
// 确保str1是较短的字符串
if (str1.length() > str2.length()) {
String temp = str1;
str1 = str2;
str2 = temp;
}
int len1 = str1.length(), len2 = str2.length();
int[][] dp = new int[len1 + 1][len2 + 1];
int maxLen = 0;
int endIndex = 0;
// 填充dp数组
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (str1.charAt(i-1) == str2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + 1;
if (dp[i][j] > maxLen) {
maxLen = dp[i][j];
endIndex = i - 1;
}
}
}
}
return str1.substring(endIndex - maxLen + 1, endIndex + 1);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
String str1 = sc.next();
String str2 = sc.next();
System.out.println(findLongestCommonSubstring(str1, str2));
}
}
}
def find_longest_common_substring(str1, str2):
# 确保str1是较短的字符串
if len(str1) > len(str2):
str1, str2 = str2, str1
len1, len2 = len(str1), len(str2)
dp = [[0] * (len2 + 1) for _ in range(len1 + 1)]
max_len = 0
end_index = 0
# 填充dp数组
for i in range(1, len1 + 1):
for j in range(1, len2 + 1):
if str1[i-1] == str2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
if dp[i][j] > max_len:
max_len = dp[i][j]
end_index = i - 1
return str1[end_index - max_len + 1:end_index + 1]
while True:
try:
str1 = input().strip()
str2 = input().strip()
print(find_longest_common_substring(str1, str2))
except:
break
算法及复杂度
- 算法:动态规划
- 时间复杂度: O ( m n ) \mathcal{O}(mn) O(mn),其中 m m m 和 n n n 是两个字符串的长度
- 空间复杂度: O ( m n ) \mathcal{O}(mn) O(mn),需要一个二维dp数组
这个解法使用动态规划来找出最长公共子串。通过dp数组记录以每对位置结尾的最长公共子串长度,同时记录最大长度和结束位置,最后可以直接截取得到结果。如果有多个最长公共子串,这个算法会返回第一个找到的。
4万+

被折叠的 条评论
为什么被折叠?



