题目
给定两个字符串str1和str2,
str1进行排列组合,只要有一个为str2的子串则认为str1是str2的关联子串,请返回子串在str2的起始位置,若不是关联子串则返回-1。
示例1
输入输出示例仅供调试,后台判题数据一般不包含示例输入
abc efghicbaili
输出
5
示例2
输入输出示例仅供调试,后台判题数据一般不包含
示例输入
abc efghiccaii
输出
-1
思路
题目隐含的条件应该是找到第一个匹配的子串。否则,可能有多种解
比如对于输入:cbcd adbccdebed。cbcd的排列组合可能有:dbcc,bccd等,如果先遍历的bccd那么得到的答案是2,如果先遍历dbcc得到的是1。
本题可以从排列组合和滑动窗口两个角度考虑解决
排列组合
组合模板见:【JAVA-排列组合】一个套路速解排列组合题。不赘述
找到str1所有的排列情况,依次遍历其是否是str2的子串。
滑动窗口
维护一个长度和str1等长的滑动窗口,判断窗口内的值是否和str1匹配,如果匹配,直接输出窗口左边界,否则右移滑动窗口
判断窗口内是否和str1匹配:每个字符数出现次数相等或者将两者按照同一逻辑排序,排序后相等则两者匹配
题解
排列组合解法
package hwod;
import java.util.*;
public class RelationSubStr {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String[] input = sc.nextLine().split(" ");
String str1 = input[0];
String str2 = input[1];
System.out.println(relationSubStr(str1, str2));
}
private static List<String> res = new ArrayList<>();//存放字符串1所有可能的排列
// 暴力解法
private static int relationSubStr(String str1, String str2) {
char[] chars = str1.toCharArray();
int[] used = new int[str1.length()];
dfs(chars, "", used);
int ans = str2.length();
for (int i = 0; i < res.size(); i++) {
int tmp = str2.indexOf(res.get(i));
if (tmp != -1 && tmp < ans) {
ans = tmp;
}
}
return ans == str2.length() ? -1 : ans;
}
private static void dfs(char[] chars, String str, int[] used) {
if (str.length() == chars.length) {
res.add(str);
}
for (int i = 0; i < chars.length; i++) {
if (used[i] == 1) continue;
str += chars[i];
used[i] = 1;
dfs(chars, str, used);
str = str.substring(0, str.length() - 1);
used[i] = 0;
}
}
}
滑动窗口解法
package hwod;
import java.util.*;
public class RelationSubStr {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String[] input = sc.nextLine().split(" ");
String str1 = input[0];
String str2 = input[1];
System.out.println(relationSubStr(str1, str2));
}
//滑动窗口
private static int relationSubStr(String str1, String str2) {
Map<Character, Integer> map1 = new HashMap<>();
Map<Character, Integer> map2 = new HashMap<>();
for (int i = 0; i < str1.length(); i++) {
map1.put(str1.charAt(i), map1.getOrDefault(str1.charAt(i), 0) + 1);
}
int size = str1.length();
int k = 0;
while (k < str2.length()) {
map2.put(str2.charAt(k), map2.getOrDefault(str2.charAt(k), 0) + 1);
int i = k - size + 1;
if (i < 0) {
k++;
continue;
}
if (checked(map1, map2)) {
return i;
}
map2.put(str2.charAt(i), map2.getOrDefault(str2.charAt(i), 0) - 1);
k++;
}
return -1;
}
private static boolean checked(Map<Character, Integer> map1, Map<Character, Integer> map2) {
for (Character key : map1.keySet()) {
if (!map2.containsKey(key)) return false;
if (!map1.get(key).equals(map2.get(key))) return false;
}
return true;
}
}
推荐
如果你对本系列的其他题目感兴趣,可以参考华为OD机试真题及题解(JAVA),查看当前专栏更新的所有题目。
说明
本专栏所有文章均为原创,欢迎转载,请注明文章出处:https://blog.csdn.net/qq_31076523/article/details/134176793。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。