在Java中,检测字符串中重复字符的最有效方法是什么?

在Java中,检测字符串中重复字符的最有效方法是什么?,java,hashmap,time-complexity,Java,Hashmap,Time Complexity,使用数据结构(HashMap),我能够做到这一点 代码如下: import java.util.*; class unique{ public static void main(String[] args){ HashMap<Character, Integer> charMap = new HashMap<Character, Integer>(); boolean isNotUnique = false;

使用数据结构(HashMap),我能够做到这一点

代码如下:

import java.util.*;

class unique{
    public static void main(String[] args){
        HashMap<Character, Integer> charMap = new HashMap<Character, Integer>();
        boolean isNotUnique = false;
            for ( char loop : args[0].toCharArray() ){
            Integer freq = charMap.get( loop );
            charMap.put( loop, ( freq == null )? 1 : freq+1 );
            if ( charMap.get( loop ) > 1 )
            {
                isNotUnique = true;
            }
        }
            System.out.println ( isNotUnique );
    }
}
import java.util.*;
类唯一{
公共静态void main(字符串[]args){
HashMap charMap=新的HashMap();
布尔值isNotUnique=false;
对于(字符循环:args[0]。toCharArray()){
整数freq=charMap.get(循环);
put(循环,(freq==null)?1:freq+1;
if(charMap.get(循环)>1)
{
isNotUnique=true;
}
}
System.out.println(不唯一);
}
}
在没有数据结构的情况下,我提出了一种直截了当的方法。 这有O(n^2)

类唯一
{
公共静态void main(字符串[]args)
{
字符串inputString=args[0];
System.out.println(isUnique(inputString));
}
私有静态布尔值是唯一的(字符串输入字符串){
String methodString=inputString;
对于(int i=0;i

我想知道是否有可能在O(n)时间复杂度中求解

字符的定义是什么?a-z a-z还是全unicode

如果字符串的长度相当大,例如一百万,则可以构建一个int数组,数组的长度是字符集的长度,数组将初始化为零

然后,根据每个字符遍历字符串:array[(int)char]++,这样,您就可以很容易地从数组中找到字符出现的时间

但是,短字符串不需要这种方法


这个方法是O(n)

字符的定义是什么?a-z a-z还是全unicode

如果字符串的长度相当大,例如一百万,则可以构建一个int数组,数组的长度是字符集的长度,数组将初始化为零

然后,根据每个字符遍历字符串:array[(int)char]++,这样,您就可以很容易地从数组中找到字符出现的时间

但是,短字符串不需要这种方法


此方法为O(n)

如果需要支持不由代理字符对表示的Unicode字符,则可以这样做:

private static boolean isUnique(String inputString) {
    long[] used = new long[1024];
    for (char c : inputString.toCharArray()) {
        if ((used[c >>> 6] & (1 << c)) > 0) {
            return false;
        }
        used[c >>> 6] |= 1 << c;
    }
    return true;
}
如果您只需要支持ASCII字符,则可以在任何情况下限制使用的
的大小,以减少所需的内存(因此
长[4]
布尔[256]
)。在
inputString
的一定长度以下,执行n^2检查可能比为此分配内存更快。理想情况下,你可以根据长度将两者结合起来


如果您需要支持所有可能的Unicode字符,您必须修改它以支持代理字符对。您可以使用
Character.ishighsrogate(c)
检测它们。请参阅以获取一些帮助,并搜索谷歌以获取更多详细信息。

如果您需要支持不由代理字符对表示的Unicode字符,则可以这样做:

private static boolean isUnique(String inputString) {
    long[] used = new long[1024];
    for (char c : inputString.toCharArray()) {
        if ((used[c >>> 6] & (1 << c)) > 0) {
            return false;
        }
        used[c >>> 6] |= 1 << c;
    }
    return true;
}
如果您只需要支持ASCII字符,则可以在任何情况下限制使用的
的大小,以减少所需的内存(因此
长[4]
布尔[256]
)。在
inputString
的一定长度以下,执行n^2检查可能比为此分配内存更快。理想情况下,你可以根据长度将两者结合起来

如果您需要支持所有可能的Unicode字符,您必须修改它以支持代理字符对。您可以使用
Character.ishighsrogate(c)
检测它们。请参阅以获取一些帮助,并搜索谷歌以获取更多详细信息

我想知道是否有可能解决O(n)时间复杂性:

有两个简单的解决方案,分别是
O(N)

  • HashSet
    方法在时间上是
    O(N)
    ,在空间上是
    O(N)
    ,其中
    N
    是字符串长度。(包含
    N
    不同字符的常规Java
    HashSet
    将占用
    O(N)
    空间,具有相对较大的比例常数。)

  • 位数组方法在时间上是
    O(N)
    ,在空间上是
    O(1)
    ,但是
    O(1)
    是8K字节(如果使用
    布尔[]
    ,则是64K字节),并且将增加到时间上的大量内存归零会带来相关成本

在所有情况下,这两个都不是最好的答案

  • 对于足够小的
    N
    ,一个简单的
    O(N^2)
    嵌套循环将是最快的。(而且它不使用额外的内存。)

  • 对于中等大小的
    N
    ,使用冲突重灰化的自定义哈希表将优于
    HashSet
    或位数组方法。
    HashSet
    方法将优于位数组方法

  • 对于足够大的
    N
    ,位数组方法将是最快的,并且使用最少的内存

(对于以上内容,我假设输入字符串不包含任何重复字符。如果包含,则
N
的实际值将小于字符串长度。)


如果重复字符检测需要处理UTF-16代理项对,那么简单的方法是动态地将代码转换为Unicode码点,并更改数据结构以使用
哈希集
、更大的位数组等

相反,如果可以限制输入字符集的大小,则可以减小位数组的大小,等等

这些调整将对小/中/大阈值可能下降的位置产生重大影响

伊娃
private static boolean isUnique2(String inputString) {
    boolean[] used = new boolean[65536];
    for (char c : inputString.toCharArray()) {
        if (used[c]) {
            return false;
        }
        used[c] = true;
    }
    return true;
}