J'ai besoin de vérifier Java si un mot consiste en des lettres uniques (insensible à la casse). En tant que solution droite, je suis ennuyé, je suis venu avec: p>
indexof (CHAR) == LastIndexof (CHAR) CODE>. LI>
- ajoutez tous les caractères à
hashset code> et vérifiez si la taille de réglage == Longueur de chaîne. Li>
- Convertissez une chaîne en une matrice de caractères, triez-la par ordre alphabétique, en boucle via des éléments de tableau et vérifiez si
c [i] == c [i + 1] code>. Li>.
ol>
J'aime actuellement # 2 le plus, semble être le moyen le plus simple. Toute autre solution intéressante? P>
12 Réponses :
J'aime l'idée de hashset. C'est simple conceptuellement, et ne passe que la chaîne. Pour une amélioration de performance simple, vérifiez le Ajouter Valeur de retour. Une chose que vous devriez être au courant, c'est que cela fonctionne par le pliage de cas. dans un sens. Vous pouvez créer une classe wrapper autour du caractère avec une sémantique différente équivalente à être vraiment insensible à une casse.
Fait intéressant, Apache Commons a un CaseInSensitivemap ( src ) qui fonctionne par le boîtier supérieur puis plus bas la clé. Comme vous le savez probablement, Hashset de Java est soutenu par un hashmap. P>
Une amélioration de l'option 2 consiste à vérifier le drapeau booléen que la méthode d'ajout de hashset retourne. C'est vrai si l'objet n'était pas déjà là. Cependant, pour que cette méthode soit utile, vous devez d'abord définir la chaîne sur toutes les capuchons ou minuscules. P>
Je n'aime pas 1. - c'est un algorithme O (n 2 sup>). Votre 2. est grossièrement linéaire, mais traverse toujours la chaîne entière. Votre 3. est O (N LG 2 SUB> N), avec (probablement) une constante relativement élevée - probablement presque toujours plus lente que 2. P>
Ma préférence, cependant, si vous essayez d'insérer une lettre dans l'ensemble, vérifiez si c'était déjà présent et si c'était le cas, vous pouvez vous arrêter immédiatement. Compte tenu de la distribution aléatoire de lettres, cela devrait nécessiter une numérisation de la moitié de la chaîne en moyenne. p>
Edit: les deux commentaires sont corrects que la partie de la chaîne que vous attendez de numériser dépendra de la distribution et de la longueur - à un moment donné, la chaîne est suffisamment longue pour qu'une répétition soit inévitable et (par exemple) une Caractère court de cela, la chance est toujours assez chère. En fait, étant donné une distribution aléatoire plate (c'est-à-dire que tous les caractères de l'ensemble sont également probables), cela devrait être approfondi avec le paradoxe d'anniversaire, ce qui signifie que les chances d'une collision sont liées à la racine carrée du nombre de caractères possibles dans le jeu de caractères. Par exemple, si nous avons assumé une probabilité de base US-ASCII (128 caractères) avec une probabilité égale, nous atteindrions 50% de chances d'une collision d'environ 14 caractères. Bien sûr, dans de vraies chaînes, nous pourrions probablement s'attendre à ce que cela plus tôt que cela, puisque les personnages ASCII ne soient utilisées nulle part près de la fréquence égale dans la plupart des cordes. P>
+1 - Mais votre dernière phrase est fausse. Le nombre moyen de caractères numérisés (en supposant que les caractères commandés au hasard / choisi) est fonction de la répartition des probabilités des lettres et de la longueur moyenne de la chaîne.
Off-sujets, mais comment obtenez-vous des superscripts et des abonnements?
@ Kache4: Vous pouvez utiliser HTML de base dans les messages (dans ce cas & )
L'avantage de la troisième réponse est que vous pouvez éviter d'utiliser une structure de données supplémentaire. Supposons que le cas au lieu de caractères, nous avons des mots dans un texte et que la taille du hachage peut augmenter beaucoup!
Qu'en est-il de l'utilisation d'un Int pour stocker les bits correspondant à l'index de la lettre de l'alpabhet? Ou peut-être une longue pour pouvoir atteindre 64 symboles distincts.
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;
Par "lettres uniques" Voulez-vous simplement dire l'ensemble anglais standard de 26, ou permettez-vous d'intéressant unicode? Quel résultat vous attendez-vous si la chaîne contient une non-lettre?
Si vous envisagez seulement 26 lettres possibles et que vous souhaitez ignorer une nouvelle lettre ou le considérer comme un échec automatique, le meilleur algorithme est probablement celui-ci. pseudocode: p> La seule question restante est de savoir si votre matrice doit être une matrice (nécessitant 26 opérations à zéro), ou un bitfield (nécessitant éventuellement plus de travail à vérifier / définir , mais peut être mis à zéro en une seule opération). Je pense que l'accès Bitfield sera à peu près comparable à la recherche de la matrice, sinon plus rapide, alors je m'attends à ce que Bitfield soit la bonne réponse. P> P>
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;
}
You should use hashset technique if you are performing char sets like utf-8 and for internationalization's sake.Javadoc on Character.toUpperCase for cases of utf:
This method (toUpperCase(char) ) cannot handle supplementary characters. To support all Unicode characters, including supplementary characters, use the toUpperCase(int) method.
Je suggérerais une variante de (2) - Utilisez des drapeaux de "caractère déjà vu" au lieu d'un hashset. En boucle à travers la chaîne, quittez immédiatement si le caractère actuel était déjà vu. P>
Si vous avez une classe Bitvector disponible (j'oublie si Java en fournit un), vous pouvez l'utiliser, bien que la sauvegarde de la mémoire n'entraîne pas nécessairement une amélioration de la vitesse et pourrait facilement ralentir les choses. P>
C'est o (n) le pire des cas, cependant, et pourrait avoir une performance moyenne de bien meilleure en fonction de vos chaînes - vous pouvez bien constater que la plupart ont une répétition près du début. En fait, à proprement parler, c'est O (1) dans le pire des cas, car une corde plus longue que la taille du jeu de caractères doit avoir des caractères répétés afin que vous ayez une constante liée au nombre de caractères dont vous avez besoin pour Vérifiez chaque chaîne. P>
L'option 2 est le meilleur des trois hachages est plus rapide que la recherche. P>
Cependant, il y a une méthode encore plus rapide, si vous avez assez de mémoire pour cela. P>
Profitez du fait qu'un ensemble de caractères est limité et déjà énuméré, et gardez une trace de ce qui est apparu et ce qui n'a pas comme vous vérifiez chaque personnage. P>
Par exemple, si vous utilisez des caractères à une octet, il n'y a que 256 possibilités. Vous n'auriez besoin que de 256 bits pour garder la piste lorsque vous lisez via la chaîne. Si le caractère 0x00 se produit, retournez le premier bit. Si le personnage 0x05 survient, retournez le sixième bit, et ainsi de suite. Lorsqu'un bit déjà retourné est rencontré, la chaîne n'est pas unique. P>
C'est le pire cas o (min (n, m)) où n est la longueur de la chaîne et m est la taille du jeu de caractères. P>
et bien sûr, comme je l'ai vu dans un autre commentaire d'une autre personne, si N> m (c'est-à-dire la longueur de la taille> taille du jeu de caractères), puis par principe de pigeon-trou, il y a un caractère répété, déterminable dans O (1) temps. p>
+1 Je pense que vous auriez besoin de 2 ^ 8 bits pour des caractères d'une octet, mais n'auriez-vous pas besoin de 2 ^ 16 pour deux octets? bitset code> fonctionnerait de toute façon. Java.sun.com/javase/6/docs/ API / Java / Util / Bitset.html
Oh whoops, je me suis confus là-bas.
Vérifiez d'abord si la taille de la chaîne est <= 26. Sinon, la chaîne a des duplicats. revenir Sinon, essayez d'ajouter dans Hashset, si elle échoue, la chaîne a des doublons de retour. Si la taille du hashset est = la taille de la chaîne de chaîne a des caractères uniques. Si nous ne sommes pas autorisés à utiliser une autre structure de données et que les méthodes internes de la chaîne et doivent toujours le faire dans O (n), puis boucle à travers la chaîne.Si i! = MyLasTindexof (i), les doublons de retour existent. p>
Voici le code que j'ai écrit pour la réponse de Kache (référé de la fissuration du code et modifié):
Vous pouvez optimiser la première solution (indexof == LastIndexof) simplement en vérifiant la condition de tous les 26 alphabets, c'est-à-dire pour A, B, C, D, .., Z. Donc, cette façon de ne pas avoir à parcourir toute la chaîne. P>
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");
}
}
}
Ne postez pas uniquement de code comme une réponse, incluez également une explication