如果一个单词由唯一字母组成(不区分大小写),我需要检查Java。由于直接的解决方案很无聊,我想出了:
indexOf(char) == lastIndexOf(char)
。HashSet
并检查set size == string length。c[i] == c[i+1]
。目前我最喜欢#2,似乎是最简单的方式。还有其他有趣的解决方案吗?
答案 0 :(得分:12)
我不喜欢1. - 这是一个O(N 2 )算法。你的2.大致是线性的,但总是遍历整个字符串。你的3.是O(N lg 2 N),(可能)是一个相对较高的常数 - 可能几乎总是慢于2。
然而,我的偏好是,当您尝试在集合中插入一个字母时,检查它是否已经存在,如果是,则可以立即停止。给定字母的随机分布,这应该只需要扫描平均一半的字符串。
编辑:两个注释都是正确的,您希望扫描的字符串的哪个部分将取决于分布和长度 - 在某些时候字符串足够长,重复是不可避免的,并且(例如)一个性格不足,机会仍然很高。事实上,给定一个平坦的随机分布(即,集合中的所有字符同样可能),这应该与生日悖论密切相关,这意味着碰撞的可能性与可能的字符数量的平方根有关。字符集。例如,如果我们假设基本的US-ASCII(128个字符)具有相同的概率,那么我们将在大约14个字符处达到50%的碰撞几率。当然,在真正的字符串中,我们可能会比它更早,因为在大多数字符串中,ASCII字符不会与频率接近相等的地方一起使用。
答案 1 :(得分:5)
选项2是三者中最好的 - 哈希比搜索更快。
但是,如果你有足够的内存,那么有一种更快的方法。
利用字符集有限且已经枚举的事实,并在检查每个字符时跟踪出现的内容和未出现的内容。
例如,如果您使用的是单字节字符,则只有256种可能性。在读取字符串时,您只需要256位来跟踪。如果出现字符0x00,则翻转第一位。如果出现字符0x05,则翻转第六位,依此类推。遇到已经翻转的位时,该字符串不是唯一的。
最糟糕的情况是O(min(n,m))其中n是字符串的长度,m是字符集的大小。
当然,正如我在另一个人的评论中看到的,如果n> m(即字符串的长度>字符集的大小),然后通过鸽子孔原理,有一个重复的字符,可在O(1)时间内确定。
答案 2 :(得分:3)
我喜欢HashSet的想法。它在概念上很简单,只有一个通过字符串。要获得简单的性能改进,请检查add返回值。您应该注意的一件事是,这可以通过案例折叠来实现。在一个方向。你可以创建一个围绕Character的包装类,它具有不同的equals语义,实际上不区分大小写。
有趣的是,Apache Commons有一个CaseInsensitiveMap(src),它通过上部套管工作然后降低密钥。您可能知道,Java的HashSet由HashMap支持。
public static boolean allUnique(String s)
{
// This initial capacity can be tuned.
HashSet<Character> hs = new HashSet<Character>(s.length());
for(int i = 0; i < s.length(); i++)
{
if(!hs.add(s.charAt(i).toUpperCase())
return false;
}
return true;
}
答案 3 :(得分:3)
“独特字母”的意思是仅仅标准的英文26集,还是允许有趣的Unicode?如果字符串包含非字母,您期望得到什么结果?
如果您只考虑26个可能的字母,并且您想要忽略任何非字母或认为它是自动失败,那么最好的算法可能就是这个伪代码:
create present[26] as an array of booleans.
set all elements of present[] to false.
loop over characters of your string
if character is a letter
if corresponding element of present[] is true
return false.
else
set corresponding element of present[] to true.
end if
else
handle non-letters
end if
end loop
唯一剩下的问题是你的数组实际上应该是一个数组(需要26个操作为零),还是一个位域(可能需要更多的工作来检查/设置,但可以在一次操作中归零)。我认为位域访问与数组查找非常相似,如果不是更快,那么我希望bitfield是正确的答案。
答案 4 :(得分:1)
选项2的改进是检查HashSet add方法返回的布尔标志。如果物体不在那里,那就是真的。虽然,为了使这个方法有用,你首先必须将字符串设置为全部大写或小写。
答案 5 :(得分:1)
使用int存储对应于alpabhet字母索引的位数怎么样?或者可能很长,能够达到64个不同的符号。
long mask;
// already lower case
string = string.toLowerCase();
for (int i = 0; i < string.length(); ++i)
{
int index = 1 << string.charAt(i) - 'a';
if (mask & index == index)
return false;
mask |= index;
}
return true;
这应该是&lt; O(n)平均情况下,O(n)最差。但是我不确定在Java中有多少高性能的按位操作。
答案 6 :(得分:1)
public boolean hasUniqChars(String s){
Hashset h = new Hashset();
HashSet<Character> h = new HashSet<Character>();
for (char c : s.toCharArray()) {
if (!h.add(Character.toUpperCase(c))) // break if already present
return false;
}
return true;
}
如果你正在执行像utf-8这样的字符集并且为了国际化,你应该使用hashset技术。
对于utf的案例,在Character.toUpperCase上使用Javadoc: 此方法(toUpperCase(char))无法处理增补字符。要支持所有Unicode字符(包括补充字符),请使用toUpperCase(int)方法。
答案 7 :(得分:1)
我建议使用(2)的变体 - 使用“已经看过的字符”标志的数组而不是散列集。当您遍历字符串时,如果已经看到当前字符,请立即退出。
如果你有一个bitvector类可用(我忘记了Java是否提供了一个),你可以使用它,虽然节省内存不一定会带来任何速度提升,并且很容易减慢速度。
这是O(n)最糟糕的情况,并且可能会有更好的平均性能,具体取决于你的字符串 - 你可能会发现大多数都在一开始就有重复。事实上,严格地说,无论如何,这是O(1)最坏的情况,因为字符串长度超过字符集的字符串必须重复字符,所以你有一个常量绑定到你需要的字符数检查每个字符串。
答案 8 :(得分:1)
首先检查字符串的大小是否为&lt; = 26。如果不是,String有重复。返回 否则尝试添加到HashSet中,如果失败,则字符串重复返回。 如果HashSet的大小=字符串字符串的大小具有唯一字符。 如果我们不允许使用任何其他数据结构和字符串的内部方法,并且仍然必须在O(n)中执行,则循环通过String.if i!= myLastIndexof(i),返回重复项存在。
答案 9 :(得分:0)
这是我为Kache的答案编写的代码(通过破解代码并修改):
public boolean check() {
int[] checker = new int[8];
String inp = "!a~AbBC#~";
boolean flag = true;
if (inp.length() > 256)
flag = false;
else {
for(int i=0;i<inp.length();i++) {
int x = inp.charAt(i);
int index = x/32;
x = x%32;
if((checker[index] & (1<<x)) > 0) {
flag = false;
break;
}
else
checker[index] = checker[index] | 1<<x;
}
}
return flag;
}
答案 10 :(得分:0)
只需检查所有26个字母的条件,即a,b,c,d,..,z,即可优化第一个解决方案(indexof == lastindexof)。所以这种方式你不必遍历所有的字符串。
答案 11 :(得分:-2)
import java.io.*;
class unique
{
public static int[] ascii(String s)
{
int length=s.length();
int asci[] = new int[length];
for(int i=0;i<length;i++)
{
asci[i]=(int)s.charAt(i);
}
return asci;
}
public static int[] sort(int a[],int l)
{
int j=1,temp;
while(j<=l-1)
{
temp = a[j];
int k=j-1;
while(k>=0 && temp<a[k])
{
a[k+1]= a[k];
k--;
}
a[k+1]=temp;
j++;
}
return a;
}
public static boolean compare(int a[])
{
int length=a.length;
int diff[] = new int[length-1];
boolean flag=true;
for(int i=0;i<diff.length;i++)
{
diff[i]=a[i]-a[i+1];
if(diff[i]==0)
{
flag=false;
break;
}
else
{
flag=true;
}
}
return flag;
}
public static void main(String[] args) throws IOException
{
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
String str = null;
boolean result = true;
System.out.println("Enter your String.....");
str = br.readLine();
str = str.toLowerCase();
int asc[]=ascii(str);
int len = asc.length;
int comp[]=sort(asc,len);
if(result==compare(comp))
{
System.out.println("The Given String is Unique");
}
else
{
System.out.println("The Given String is not Unique");
}
}
}