2017-08-16 3 views
0

Je devais écrire une fonction qui prend en entrée deux chaînes. L'un est le message que je veux écrire et le second est donné des lettres. Les lettres sont classées de manière aléatoire. Il n'est pas garanti que chaque lettre se répète autant de fois. Certaines lettres peuvent être complètement manquantes. La fonction doit déterminer si je peux écrire un message avec les lettres données et il doit renvoyer vrai ou faux en conséquence.Plus rapide façon de vérifier si nous pouvons écrire un message à partir de lettres données

Je l'ai codé et je pense que c'est très rapide, mais comment puis-je l'améliorer en gardant à l'esprit que la chaîne avec des lettres serait très grande alors que le message serait très court?

Y a-t-il un moyen le plus rapide?

import java.util.HashMap; 
import java.util.Map; 
import java.util.Random; 

public class LetterBowl { 

    public static void main(String []args){ 
     String message = generateRandomStringUpToThousandChars(); 
     String bowlWithLetters = generateRandomStringUpToThousandChars(); 

     if(canConstructMessage(message, bowlWithLetters)) { 
      System.out.println("Message '" + message + "' can be constructed with letters from bowl : " + bowlWithLetters); 
     } 
    } 


    public static boolean canConstructMessage(String message, String letters) { 
     Map<Character,Integer> letterMap = stringToCharacterMap(letters); 
     char[] messageList = stringToCharacterList(message); 

     for(char c : messageList) { 
      if (!containsLetterAndSubtract(c,letterMap)) 
       return false; 
     } 
     return true; 
    } 


    // checks if map(bowl) contains char andsubtract one char from map(or removes it if it is last one) 
    public static boolean containsLetterAndSubtract(char c, Map<Character,Integer> letterMap) { 
     if(letterMap.containsKey(c)) { 
      if(letterMap.get(c) > 1) { 
       letterMap.put(c, letterMap.get(c) - 1); 
      } else { 
       letterMap.remove(c); 
      } 
      return true; 
     } 
     return false; 
    } 

    public static char[] stringToCharacterList(String message) { 
     return message.replaceAll(" ", "").toCharArray(); 
    } 

    public static Map<Character,Integer> stringToCharacterMap(String s) { 
     Map<Character,Integer> map = new HashMap<Character,Integer>(); 

     for (char c : s.toCharArray()) { 
      if(map.containsKey(c)) 
       map.put(c, map.get(c) + 1); 
      else 
       map.put(c, 1); 
     } 
     return map; 
    } 

    public static String generateRandomStringUpToThousandChars(){ 
     char[] chars = "abcdefghijklmnopqrstuvwxyz".toCharArray(); 

     StringBuilder sb = new StringBuilder(); 
     Random random = new Random(); 
     for (int i = 0; i < random.nextInt(1000); i++) { 
      char c = chars[random.nextInt(chars.length)]; 
      sb.append(c); 
     } 
     String output = sb.toString(); 

     return output; 
    }; 

} 

Pour la grande taille du bol et de plus petite taille msg je trouve que ce serait mor efficace:

public (message String, String bowlWithLetters) statique canConstructMessageSorted booléen { int counter = 0; boolean hasLetter;

//sorting 
    char[] chars = bowlWithLetters.toCharArray(); 
    Arrays.sort(chars); 
    String sortedBowl = new String(chars); 

    //sorting 
    chars = message.toCharArray(); 
    Arrays.sort(chars); 
    String sortedMsg = new String(chars); 

    for (int i = 0; i < sortedMsg.length(); i++) { 
     hasLetter = false; 
     for( ; counter < sortedBowl.length() ; counter++) { 
      if(sortedMsg.charAt(i) == sortedBowl.charAt(counter)) { 
       hasLetter = true; 
       break; 
      } 
     } 
     if(!hasLetter) return false; 
    } 
    return true; 
} 
+0

Les lettres sont-elles nécessairement en anglais? – meowgoesthedog

+0

ce n'est pas nécessairement. mais l'anglais est ok pour l'exemple. – Juka

Répondre

1

Vous opérez sur O (message.size + letters.size). C'est la plus basse complexité temporelle que je puisse comprendre. En vous référant au le plus rapide, vous pouvez toujours faire plus. Par exemple, définir la méthode

public static char[] stringToCharacterList(String message) 

et de ne l'utiliser qu'une seule fois est techniquement inefficace. Vous auriez pu simplement placer ce corps de code dans la méthode canConstructMessage(), en sauvant qu'un autre élément ne soit placé et retiré de la pile. Bien que ce soit un petit fragment de temps, quand vous dites le plus rapide, il pourrait être intéressant de parler.

+0

y at-il un moyen le plus rapide de le faire, en gardant à l'esprit que nous aurions toujours une petite chaîne de message et une longue chaîne de caractères (le message pourrait être 'abc' et les lettres pourraient être "sabcjksdafofjifdhsf ...... jusqu'à 10000 caractères etc.)? donc nous cherchons le meilleur scénario le plus rapide. Une autre façon de faire serait-elle meilleure? – Juka

+1

@Juka Je ne suis pas votre intérêt pour le * meilleur des cas *. Généralement, vous voulez améliorer votre cas le plus défavorable, ou même le cas moyen. Quand vous parlez du meilleur scénario, vous trouvez un algorithme qui a le * potentiel * pour le temps de vérification le plus rapide. Dans ce cas, ajouter simplement * if (message == lettres) {return true;} * au début de votre fonction serait le * meilleur des cas *, où vous avez 2 chaînes vides qui sont rapidement vérifiées dans O (1) temps. Cependant, ceci est sur * moyen * pas le cas, et ne fera que ralentir le reste de votre fonction. Si cela n'a pas aidé, faites le moi savoir. –

0

Pour chaque lettre de letters, supprimez-en une copie du message. Si le message se termine vide, la réponse est « oui »:

public static boolean canConstructMessage(String message, String letters) { 
    for (int i = 0; i < letters.length(); i++) 
     message = message.replaceFirst("" + letters.charAt(i), ""); 
    return message.isEmpty(); 
}  

Si la réutilisation des lettres est permis, vous pouvez le faire en 1 ligne:

public static boolean canConstructMessage(String message, String letters) { 
    return letters.chars().boxed().collect(Collectors.toSet()) 
     .containsAll(message.chars().boxed().collect(Collectors.toSet()); 
} 
+0

cela ne fonctionnera pas pour message = "aaa", lettres = "abcdefgh" parce que vous n'avez pas assez de lettres "a" pour former un message. – Juka

+0

@Juka J'ai interprété la question comme permettant la réutilisation des lettres, mais je pense que vous avez raison (voir la réponse éditée). – Bohemian

0

J'ai trouvé ce serait plus efficace pour taille de grand bol et petit taille de msg:

public static boolean canConstructMessageSorted(String message, String bowlWithLetters) { 
    int counter = 0; 
    boolean hasLetter; 

    //sorting 
    char[] chars = bowlWithLetters.toCharArray(); 
    Arrays.sort(chars); 
    String sortedBowl = new String(chars); 

    //sorting 
    chars = message.toCharArray(); 
    Arrays.sort(chars); 
    String sortedMsg = new String(chars); 

    for (int i = 0; i < sortedMsg.length(); i++) { 
     hasLetter = false; 
     for( ; counter < sortedBowl.length() ; counter++) { 
      if(sortedMsg.charAt(i) == sortedBowl.charAt(counter)) { 
       hasLetter = true; 
       break; 
      } 
     } 
     if(!hasLetter) return false; 
    } 
    return true; 
}