Java 什么';检查一个字符串是否包含另一个字符串的最快方法是什么?
我得到字符串a和b,并检查b是否包含a的确切字符。例如:“ABBA”和“baaaa”返回false,“ABBA”和“ABABAB”返回true。我将每个字符串值做成一个and数组,并检查b是否包含该值,如果包含该值,则删除该值,这样就不会找到它两次 然而,这个方法太慢了,对于一些大字符串来说,显然需要12秒。我一直在尝试,但还没有找到更快的解决方案。如果可以的话,请帮帮我Java 什么';检查一个字符串是否包含另一个字符串的最快方法是什么?,java,arrays,string,Java,Arrays,String,我得到字符串a和b,并检查b是否包含a的确切字符。例如:“ABBA”和“baaaa”返回false,“ABBA”和“ABABAB”返回true。我将每个字符串值做成一个and数组,并检查b是否包含该值,如果包含该值,则删除该值,这样就不会找到它两次 然而,这个方法太慢了,对于一些大字符串来说,显然需要12秒。我一直在尝试,但还没有找到更快的解决方案。如果可以的话,请帮帮我 public static boolean inneholdt(String a, String b) { int
public static boolean inneholdt(String a, String b)
{
int k = 0;
String[] Inn = a.split("(?!^)");
for (int i = 0; i < Inn.length; i++)
{
if(b.contains(Inn[i]))
{
b = b.replaceFirst(Inn[i], "");
k++;
}
}
if(k >= Inn.length)
{
return true;
} else return false;
}
公共静态布尔inneholdt(字符串a、字符串b)
{
int k=0;
字符串[]Inn=a.split((?!^)”;
for(int i=0;i=客栈长度)
{
返回true;
}否则返回false;
}
如果我理解这个问题,有两种主要方法:
- 对两个字符串的字符数组进行排序,并检查最短数组是否为最长数组的前缀
- 填充
,该映射统计最短字符串中每个字符的出现次数。然后,遍历最长的字符串并减少遇到的每个字符的计数。如果一个计数器达到0,则将其从映射中删除。如果映射为空,则返回映射
。如果在使用了最长字符串的所有字符后,映射没有变为空,则返回true
false
// in Java 8. For older versions, it is also easy but more verbose
public static boolean inneholdt(String a, String b) {
if (b.length() > a.length()) return false;
Map<Character, Integer> countChars = new HashMap<>();
for (char ch : b.toCharArray()) countChars.put(ch, countChars.getOrDefault(ch, 0) + 1);
for (char ch : a.toCharArray()) {
Integer count = countChars.get(ch);
if (count != null) {
if (count == 1) countChars.remove(ch);
else countChars.put(ch, count - 1);
}
if (countChars.isEmpty()) return true;
}
return false;
}
这表明收集器.groupingBy
的实现非常消耗内存。Max的解决方案原则上并不坏,即使它做的工作比它可能做的更多,因为这是一个高级解决方案,所以它无法控制一些实现细节,例如记录分组的方式。查看Java标准库的代码,它看起来像是执行了排序,因此需要一些内存,特别是因为多个线程同时进行排序。我使用默认设置-Xmx2g
运行了这个程序。我使用-Xmx4g
重新运行它
My version :
Mean time of 3 ms with lenA = 50000, lenB = 50
Mean time of 1 ms with lenA = 50000, lenB = 500
Mean time of 2 ms with lenA = 50000, lenB = 5000
Mean time of 5 ms with lenA = 50000, lenB = 50000
Mean time of 7 ms with lenA = 5000000, lenB = 5000
Mean time of 17 ms with lenA = 5000000, lenB = 50000
Mean time of 93 ms with lenA = 5000000, lenB = 500000
Mean time of 642 ms with lenA = 5000000, lenB = 5000000
Mean time of 64 ms with lenA = 50000000, lenB = 50000
Mean time of 161 ms with lenA = 50000000, lenB = 500000
Mean time of 836 ms with lenA = 50000000, lenB = 5000000
Mean time of 11962 ms with lenA = 50000000, lenB = 50000000
Max's parallel solution :
Mean time of 45 ms with lenA = 50000, lenB = 50
Mean time of 18 ms with lenA = 50000, lenB = 500
Mean time of 19 ms with lenA = 50000, lenB = 5000
Mean time of 35 ms with lenA = 50000, lenB = 50000
Mean time of 1691 ms with lenA = 5000000, lenB = 5000
Mean time of 1162 ms with lenA = 5000000, lenB = 50000
Mean time of 1817 ms with lenA = 5000000, lenB = 500000
Mean time of 1671 ms with lenA = 5000000, lenB = 5000000
Mean time of 12052 ms with lenA = 50000000, lenB = 50000
Mean time of 10034 ms with lenA = 50000000, lenB = 500000
Mean time of 9467 ms with lenA = 50000000, lenB = 5000000
Mean time of 18122 ms with lenA = 50000000, lenB = 50000000
这一次运行良好,但仍然缓慢。请注意,用于测试不同版本的测试用例,这是一个相当糟糕的基准测试,但我认为它足以显示收集器。groupingBy
非常消耗内存,不尝试尽快返回是一个很大的缺点
代码是可用的。如果我理解这个问题,有两种主要方法:
- 对两个字符串的字符数组进行排序,并检查最短数组是否为最长数组的前缀
- 填充
,该映射统计最短字符串中每个字符的出现次数。然后,遍历最长的字符串并减少遇到的每个字符的计数。如果一个计数器达到0,则将其从映射中删除。如果映射为空,则返回映射
。如果在使用了最长字符串的所有字符后,映射没有变为空,则返回true
false
// in Java 8. For older versions, it is also easy but more verbose
public static boolean inneholdt(String a, String b) {
if (b.length() > a.length()) return false;
Map<Character, Integer> countChars = new HashMap<>();
for (char ch : b.toCharArray()) countChars.put(ch, countChars.getOrDefault(ch, 0) + 1);
for (char ch : a.toCharArray()) {
Integer count = countChars.get(ch);
if (count != null) {
if (count == 1) countChars.remove(ch);
else countChars.put(ch, count - 1);
}
if (countChars.isEmpty()) return true;
}
return false;
}
这表明收集器.groupingBy
的实现非常消耗内存。Max的解决方案原则上并不坏,即使它做的工作比它可能做的更多,因为这是一个高级解决方案,所以它无法控制一些实现细节,例如记录分组的方式。查看Java标准库的代码,它看起来像是执行了排序,因此需要一些内存,特别是因为多个线程同时进行排序。我使用默认设置-Xmx2g
运行了这个程序。我使用-Xmx4g
重新运行它
My version :
Mean time of 3 ms with lenA = 50000, lenB = 50
Mean time of 1 ms with lenA = 50000, lenB = 500
Mean time of 2 ms with lenA = 50000, lenB = 5000
Mean time of 5 ms with lenA = 50000, lenB = 50000
Mean time of 7 ms with lenA = 5000000, lenB = 5000
Mean time of 17 ms with lenA = 5000000, lenB = 50000
Mean time of 93 ms with lenA = 5000000, lenB = 500000
Mean time of 642 ms with lenA = 5000000, lenB = 5000000
Mean time of 64 ms with lenA = 50000000, lenB = 50000
Mean time of 161 ms with lenA = 50000000, lenB = 500000
Mean time of 836 ms with lenA = 50000000, lenB = 5000000
Mean time of 11962 ms with lenA = 50000000, lenB = 50000000
Max's parallel solution :
Mean time of 45 ms with lenA = 50000, lenB = 50
Mean time of 18 ms with lenA = 50000, lenB = 500
Mean time of 19 ms with lenA = 50000, lenB = 5000
Mean time of 35 ms with lenA = 50000, lenB = 50000
Mean time of 1691 ms with lenA = 5000000, lenB = 5000
Mean time of 1162 ms with lenA = 5000000, lenB = 50000
Mean time of 1817 ms with lenA = 5000000, lenB = 500000
Mean time of 1671 ms with lenA = 5000000, lenB = 5000000
Mean time of 12052 ms with lenA = 50000000, lenB = 50000
Mean time of 10034 ms with lenA = 50000000, lenB = 500000
Mean time of 9467 ms with lenA = 50000000, lenB = 5000000
Mean time of 18122 ms with lenA = 50000000, lenB = 50000000
这一次运行良好,但仍然缓慢。请注意,用于测试不同版本的测试用例,这是一个相当糟糕的基准测试,但我认为它足以显示收集器。groupingBy
非常消耗内存,不尝试尽快返回是一个很大的缺点
代码可用。Java8+lambda表达式
public static boolean inneholdt(String a, String b) {
// Here we are counting occurrences of characters in the string
Map<Integer, Long> aCounted = a.chars().parallel().boxed().collect(Collectors.groupingBy(o -> o, Collectors.counting()));
Map<Integer, Long> bCounted = b.chars().parallel().boxed().collect(Collectors.groupingBy(o -> o, Collectors.counting()));
// Now we're checking if the second string contains all the characters from the first
return bCounted.keySet().parallelStream().allMatch(
x -> bCounted.getOrDefault(x, 0l) >= aCounted.getOrDefault(x, 0l)
);
}
第一个数字代表@Dici的解决方案,第二个数字代表我的普通流解决方案,第三个数字代表这个答案的版本 Java8+lambda表达式
public static boolean inneholdt(String a, String b) {
// Here we are counting occurrences of characters in the string
Map<Integer, Long> aCounted = a.chars().parallel().boxed().collect(Collectors.groupingBy(o -> o, Collectors.counting()));
Map<Integer, Long> bCounted = b.chars().parallel().boxed().collect(Collectors.groupingBy(o -> o, Collectors.counting()));
// Now we're checking if the second string contains all the characters from the first
return bCounted.keySet().parallelStream().allMatch(
x -> bCounted.getOrDefault(x, 0l) >= aCounted.getOrDefault(x, 0l)
);
}
第一个数字代表@Dici的解决方案,第二个数字代表我的普通流解决方案,第三个数字代表这个答案的版本 基于第一眼,无需进一步阅读,但:
a.split((?!^)”
如果您使用的是java8,那么只需使用a.split(“”)
或可能a.tocharray()
。在任何情况下,避免替换第一个字符串中的每一个字母,否则会造成高昂的成本。-分别计算第一个字符串中的字符怎么样?如果您知道需要查找2个A和2个B,那么(最多)一次遍历另一个字符串就足够了。我将使用int[]计数器=new int[256]
并开始在这两个字符串中最短的字符串中找到的每个字符的int
值中添加1,然后遍历第二个字符串,并为每个字符的int
值减除1。基于第一眼,不使用