对字谜的改进

时间:2010-11-06 03:53:05

标签: java anagram

刚刚完成了最近的作业,但我知道它可能更有效率。它从命令行读取两个单词,忽略空格和标点符号,并确定它们是否是字谜。我的内容如下;据我所知,它完全正常运作。

/**
 * Find out if a string is an anagram of another string
 * 
 */

import java.util.Arrays;

public class Anagram
{
    public static void main(String[] args)
    {
        if (args.length != 2)
            System.out.println("You did not enter two words!");        
        else            
            printWords(args[0], args[1]);                              
    }

    // method to determine whether two strings have the same chars
    public static boolean areAnagrams(String wordOne, String wordTwo) 
    {
        // new strings for letters only
        String ltrsOnlyOne = lettersOnly(wordOne);
        String ltrsOnlyTwo = lettersOnly(wordTwo);      

        // convert strings to lowercase char arrays
        char[] first = ltrsOnlyOne.toLowerCase().toCharArray();
        char[] second = ltrsOnlyTwo.toLowerCase().toCharArray();

        // sort char arrays using sort method
        Arrays.sort(first);
        Arrays.sort(second);

        if (Arrays.equals(first, second))
            return true;
        else
            return false;
    }

    public static String lettersOnly(String word) 
    {
        int length = word.length();
        StringBuilder end = new StringBuilder(length);
        char x;

        for (int i = (length - 1); i >= 0; i--) {
            x = word.charAt(i);
            if (Character.isLetter(x)) {
                end.append(x);
            }
        }
        return end.toString();
    }

    public static void printWords(String wordOne, String wordTwo)
    {
       boolean b = areAnagrams(wordOne, wordTwo);
       if (b == true) {
            System.out.println(wordOne + " is an anagram of "+ wordTwo);
       }

       if (b == false) {
            System.out.println(wordOne + " is not an anagram of "+ wordTwo);
       }
    }
}

6 个答案:

答案 0 :(得分:12)

错误修复:lettersOnly的返回值丢失

您的lettersOnly方法不会修改其参数,它会返回新的字符串。当你调用它时,你需要用这个返回值做一些事情。否则你只是在调用它并丢弃结果。

// method to determine whether two strings have the same chars
public static boolean sameChars(String wordOne, String wordTwo) 
{
    lettersOnly(wordOne);
    lettersOnly(wordTwo);
    wordOne = lettersOnly(wordOne);
    wordTwo = lettersOnly(wordTwo);

    ...
}

死代码删除

main()中,您无需检查其返回值即可调用sameChars。由于sameChars不会修改其参数或有任何其他副作用,因此该调用是死代码,应该删除。

public static void main(String[] args)
{
    if (args.length != 2) {
        System.out.println("You did not enter two words!");
    }

    sameChars(args[0], args[1]);        
    printWords(args[0], args[1]);             
}

重构if语句

虽然您的if语句是正确的,但使用==truefalse进行比较并非惯用语。使用布尔值时,无需进行显式比较。它更短,读取更好,简单地省略比较。

if (sameChars(wordOne, wordTwo) == true) {
if (sameChars(wordOne, wordTwo)) {
    System.out.println(wordOne + " is an anagram of "+ wordTwo);
}
if (sameChars(wordOne, wordTwo) == false) { if (!sameChars(wordOne, wordTwo)) { System.out.println(wordOne + " is not an anagram of "+ wordTwo); }

请注意== false如何被等效的!(NOT)替换。

实际上,没有理由重复拨打sameChars。拥有看起来如此相似的代码应该在你的脑海中引起一个小小的警报。 “应该有办法消除重复的代码,”你想。是的,我们将第二个if切换为else

if (sameChars(wordOne, wordTwo)) {
    System.out.println(wordOne + " is an anagram of "+ wordTwo);
}
else {
    System.out.println(wordOne + " is not an anagram of "+ wordTwo);
}

高级

沿着类似的方向,您可以简化以下语句集:

if (Arrays.equals(first, second))
    return true;
else
    return false;

equals()的结果为真时,返回true。否则当它为假时你返回false。如果你考虑一下,你实际上只是返回equals返回的内容。您实际上可以完全消除ifelse,只是直接返回equals的结果。咦!

return Arrays.equals(first, second);

这种变化比前一次更加先进。如果您以前从未见过这种变化,您可能会发现这种变化有点奇怪。但它确实相当于四行版本。

循环反转

通常,当程序员编写for个循环时,它们从0开始并迭代到某个上限。您是否有理由将循环编写为降序循环?

for (int i = (length - 1); i >= 0; i--) {
    x = word.charAt(i);
    if (Character.isLetter(x)) {
        end.append(x);
    }
}

有些程序员会像这样向后循环,这是一种“更有效”的可疑尝试。如同,它们只执行一次计算(length - 1),所以它稍快一些。我个人认为这浪费时间和脑力。

事实上,向后写你的lettersOnly函数有一个奇怪的副作用,在删除不需要的字符后,以相反的顺序返回字符串。事实证明这并不重要,因为您稍后将字符按字母顺序排序。但这是一种可以在以后咬你的东西。事情就是这样,你因为排序而逃脱了逆转。我会将循环切换为正常的0到n顺序迭代:

for (int i = 0; i < length; ++i) {
    x = word.charAt(i);
    if (Character.isLetter(x)) {
        end.append(x);
    }
}

答案 1 :(得分:3)

  • 执行时间: 如果要改善执行时间,可以计算每个单词中每个字母出现的次数,然后比较计数。这样,您可以避免排序(具有O(n * log n)复杂度)并在线性(O(n))时间内解决问题。

  • Javadoc:一个小问题,类(/** ... */)的javadoc注释应该在类声明(public class ...)之前出现。现在你在javadoc注释和类声明之间有一个import语句。

答案 2 :(得分:1)

我会将santize步骤lettersOnly()移动到sameChars()之外的单独方法,从main调用。它效率不高,但代码更清晰:

public static void main(String[] args) 
{ 
    if (args.length != 2) { 
        System.out.println("You did not enter two words!"); 
    } 

    String wordOne = lettersOnly(args[0]); 
    String wordTwo = lettersOnly(args[1]);    

    printWords(wordOne, wordTwo);              
} 

// method to determine whether two strings have the same chars 
public static boolean sameChars(String wordOne, String wordTwo)  
{ 
    // convert strings to lowercase char arrays 
    char[] first = wordOne.toLowerCase().toCharArray(); 
    char[] second = wordTwo.toLowerCase().toCharArray(); 

    Arrays.sort(first); 
    Arrays.sort(second); 

    return  Arrays.equals(first, second);
} 

public static void printWords(String wordOne, String wordTwo) 
{ 
    boolean isAnagram = sameChars(wordOne, wordTwo);         

   if (isAnagram) 
   { 
        System.out.println(wordOne + " is an anagram of "+ wordTwo); 
   } 
   else
   { 
        System.out.println(wordOne + " is not an anagram of "+ wordTwo); 
   } 
} 

答案 3 :(得分:0)

您只需拨打一次sameChars即可。否则,在false的情况下,您将小写并迭代两次数组。尝试:

public static void printWords(String wordOne, String wordTwo)
 {
   boolean same = sameChars(wordOne, wordTwo);
   if (same) {
        System.out.println(wordOne + " is an anagram of "+ wordTwo);
    } else {
        System.out.println(wordOne + " is not an anagram of "+ wordTwo);
    }
}

答案 4 :(得分:0)

在剥离非字母时,为什么要把结果填回字符串呢,当你要做的就是将它们再次放入数组中时?

char[] first = word1.toCharArray();
int numLettersFirst = 0;
for(char l: first)
  if(Character.isLetter(l))
      first[numLettersFirst++] = Character.toLower(l);

如果两个字符串的字母数不同,则它们不是字谜。否则排序并比较它们 - 但要小心只包括数组的第一个numLetters。

答案 5 :(得分:0)

我今天制作了这个代码,不使用数组来检查一个单词是否是另一个单词的字谜...对我有效...希望它可以帮助你。

import java.util.Scanner;

public class Anagrams
{
//method for if lengths are different
public static boolean length (String word, String check)
{
    if (word.length() !=check.length())
    {
        return false;
    }
    return true;
}

// display information
public static void main (String[]args)
{
    Scanner input = new Scanner (System.in);
    //prompt user to enter two words and assign one to String "word" and the other to String "check"
    System.out.println("Please enter a word:");
    String word = input.nextLine();
    System. out. println("Please enter another word to check if it is an anagram of the first:");
    String check = input.nextLine();

    int add = 0;//keeps track of number of letters that are correct to eachother
    //first check if length is correct
    if (length(word,check) == false)
    {
        System.out.println("There is no anagram present.");
    }
    else if (length(word,check)== true) //if length is correct, continue checking for anagram
    {
       // check if each letter is in both words
        for (int i=0;i<word.length();i++) //for loop through each letter in word 
       {
           for (int x=0;x<check.length();x++) //for loop through each letter in check
           {
               if (word.charAt(i)==check.charAt(x)) //if letter in first word is the same as one in the next
               {
                   add++;
                   break;// break out of loop section if the letter is found more than once
               }
           }
       }
       if (add == word.length())//if the number of matching letters equals the number of letters in 
       //the word entered by the user, display that the words are anagrams of eachother
       {
           System. out.println (check + " is an anagram of " + word);
       }
    }
}