使用数据结构(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 );
}
}
没有数据结构,我想出了一个直截了当的方法。 这有O(n ^ 2)
class unique
{
public static void main(String[] args)
{
String inputString = args[0];
System.out.println( isUnique( inputString ) );
}
private static boolean isUnique(String inputString) {
String methodString = inputString;
for ( int i = 0; i < inputString.length(); i++ )
{
for ( int j = i+1; j < inputString.length(); j++ )
{
if ( methodString.charAt( i ) == methodString.charAt( j ) )
{
return false;
}
}
}
return true;
}
}
我想知道是否有可能以O(n)时间复杂度来解决
答案 0 :(得分:1)
角色的定义是什么? a-z A-Z或所有unicode? p>
如果字符串的长度非常大,例如一百万,则可以构建一个int数组,数组的长度是字符集的长度,数组将初始化为零。
之后,根据每个字符串遍历字符串:array [(int)char] ++,这样,你就可以很容易地找到从数组中出现字符的时间。
然而,短字符串不需要这样的方法。
这个方法是O(n)
答案 1 :(得分:1)
如果您需要支持代理字符对未表示的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;
}
它使用位翻转来节省内存。它与使用一组布尔值基本相同:
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;
}
如果您只需要支持ASCII字符,则可以在任何一种情况下限制used
的大小以减少所需的内存(因此long[4]
和boolean[256]
)。低于inputString
的某个长度,执行n ^ 2检查可能比为此分配内存更快。理想情况下,你根据长度做两者的组合。
如果您需要支持所有可能的Unicode字符,则必须修改它以支持代理字符对。您可以使用Character.isHighSurrogate(c)
检测它们。有关帮助,请参阅this page,并在Google上搜索更多详细信息。
答案 2 :(得分:1)
我想知道是否有可能解决O(n)时间复杂度:
有两个简单的解决方案O(N)
及时:
HashSet
方法的时间为O(N)
,空间为O(N)
,其中N
为字符串长度。 (包含HashSet
个不同字符的常规Java N
将占用O(N)
空格,并且具有相对较大的比例常数。)
位数组方法的时间为O(N)
,空间为O(1)
,但O(1)
为8K字节(如果使用boolean[]
则为64K字节并且有一个相关的成本,即将大量内存添加到当时。
在所有情况下,这些都不是最佳答案。
对于足够小的N
,一个简单的O(N^2)
嵌套循环将是最快的。 (并且它不使用额外的内存。)
对于中等大小的N
,在碰撞时使用重新散列的自定义散列表将优于HashSet
或位数组方法。 HashSet
方法将比位阵列方法更好。
对于足够大的N
,位阵列方法将是最快的并使用最少的内存。
(对于上面的内容,我假设输入字符串不包含任何重复字符。如果有,那么N
的实际值将小于字符串长度。)
如果重复的字符检测需要处理UTF-16代理对,那么简单的方法是即时转码为Unicode代码点,并将数据结构更改为使用HashSet<Integer>
,更大的位数组等
相反,如果可以限制输入字符集的大小,可以减小位数组的大小等。
这些调整会对小/中/大阈值可能下降的位置产生重大影响。