2

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

/**
 * 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);
       }
    }
}
4

6 回答 6

11

Bug 修复: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陈述是正确的,但==用于比较true并且false不是惯用的。当您使用布尔值时,不需要显式比较。简单地省略比较,它更短,读起来更好。

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()为真时,您返回真。否则当它为假时,你返回假。如果您考虑一下,您实际上只是在返回返回的任何内容equals。您实际上可以完全消除ifandelse并简单地直接返回结果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);
    }
}
于 2010-11-06T04:10:33.790 回答
3
  • 执行时间:如果要提高执行时间,可以统计每个字母在每个单词中出现的次数,然后比较计数。这样,您可以避免排序(具有O(n * log n)复杂性)并在线性 ( O(n)) 时间内解决问题。

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

于 2010-11-06T04:30:06.803 回答
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); 
   } 
} 
于 2010-11-06T04:12:52.713 回答
0

您只需调用sameChars一次。否则,在错误的情况下,您将小写并迭代您的数组两次。尝试:

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);
    }
}
于 2010-11-06T04:16:09.903 回答
0

在去除非字母时,为什么还要费心将结果塞回字符串中,而您要做的只是再次将它们放入数组中?

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

如果两个字符串有不同数量的字母,则它们不是字谜。否则对它们进行排序和比较 - 但请注意仅包含数组的第一个 numLetters。

于 2010-11-06T15:20:37.473 回答
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);
       }
    }
}
于 2014-10-15T21:51:12.757 回答