题目
给定两个字符串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),查看当前专栏更新的所有题目。