【问题标题】:Can't find the problem with my solution to leetcode problemCan\'t find the problem with my solution to leetcode problem
【发布时间】:2022-10-25 15:22:33
【问题描述】:

我正在尝试赎金记录挑战:

给定两个字符串ransomNote和magazine,如果ransomNote可以使用来自magazine的字母构造,则返回true,否则返回false。

杂志中的每个字母只能在赎金笔记中使用一次。

示例 1:

输入:ransomNote = "a", magazine = "b" 输出:假 示例 2:

输入:ransomNote = "aa",杂志 = "ab" 输出:假 示例 3:

输入:ransomNote = "aa",杂志 = "aab" 输出:真

这是我的解决方案:

public static boolean canConstruct(String ransomNote, String magazine) {
        ArrayList<Character> ransomChar = new ArrayList<Character>();
        ArrayList<Character> magazineChar = new ArrayList<Character>();

        if (ransomNote.length() == 1 && magazine.length() == 1) {
            if (ransomNote.equals(magazine)) {
                return true;
            }
            return false;
        }

        else if (ransomNote.length() == 1 && magazine.length() > 1) {
            for (int i = 0; i < magazine.length(); i++) {
                if (magazine.charAt(i) == ransomNote.charAt(0)) {
                    return true;
                }
            }
            return false;
        }
        else if (ransomNote.length() > 1 && magazine.length() > 1) {
            for (int i = 0; i < ransomNote.length(); i++) {
                ransomChar.add(ransomNote.charAt(i));
            }
            for (int i = 0; i < magazine.length(); i++) {
                magazineChar.add(magazine.charAt(i));
            }
            while (ransomChar.size() > 1) {
                for (int i = 0; i < ransomChar.size(); i++) {
                    boolean flag = false;
                    for (int j = 0; j < magazineChar.size(); j++) {
                        if (ransomChar.get(i).equals(magazineChar.get(j))) {
                            ransomChar.remove(i);
                            magazineChar.remove(j);
                            flag = true;
                        }
                        else if (ransomChar.isEmpty()) {
                            return true;
                        }
                    }
                    if (!flag) {
                        return false;
                    }
                }
            }
            
            if (ransomChar.size() == 1 && magazineChar.size() == 1) {
                if (ransomChar.equals(magazineChar)) {
                    return true;
                }
                return false;
            }

            else if (ransomChar.size() == 1 && magazineChar.size() > 1) {
                for (int i = 0; i < magazineChar.size(); i++) {
                    if (ransomChar.get(0).equals(magazineChar.get(i))) {
                        return true;
                    }
                }
                return false;
            }
        }
        return false;
    }

我正在通过大多数测试用例,但它在输入时引发错误:

    "bg"
    "efjbdfbdgfjhhaiigfhbaejahgfbbgbjagbddfgdiaigdadhcfcj"

它抛出错误:

java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
at line: if (ransomChar.get(i).equals(magazineChar.get(j)))

【问题讨论】:

  • 欢迎来到堆栈溢出。它抛出什么错误?请把错误放在你的问题中,包括堆栈跟踪。
  • 抱歉,我刚刚更新了它。
  • 您正在尝试从空字符串中提取第一个字符,而 Java 抱怨这是不允许的。 .最好使用 IDE 的调试模式运行代码,看看为什么会发生这种情况
  • 您正在从正在迭代的列表中删除项目。这通常是一个坏主意,并且会搞砸你的逻辑。当您从列表中删除一个项目时,之后的所有项目都会向下移动一个插槽。但是无论如何你都会增加循环索引。充其量,你跳过了你应该考虑的字符,更糟糕的是,你会像你看到的那样崩溃。你需要重新考虑你的循环是如何工作的,以考虑到你删除项目会使其他项目向下移动的事实。
  • 您可能需要考虑使用 StringBuffer 类。它将清理您的代码并避免必须逐个字符地显式复制您的输入字符串。

标签: java algorithm


【解决方案1】:

在此循环的每次迭代中:

                for (int i = 0; i < ransomChar.size(); i++) {
                    boolean flag = false;
                    for (int j = 0; j < magazineChar.size(); j++) {
                        if (ransomChar.get(i).equals(magazineChar.get(j))) {
                            ransomChar.remove(i);
                            magazineChar.remove(j);
                            flag = true;
                        }
                        else if (ransomChar.isEmpty()) {
                            return true;
                        }
                    }
                    if (!flag) {
                        return false;
                    }
                }

, 你知道i最初小于ransomChar.size(),因此执行ransomChar.get(i) 是安全的。

但是,内部循环可能会删除ransomChar 的一个(或多个!)元素,之后i 小于ransomChar.size() 可能不再正确。内部循环继续迭代,因此,它可以尝试检索不存在的ransomChar 元素。

老实说,整个代码是一团糟。除了这个特定的问题,

  • 我认为没有必要为纸币和杂志尺寸的所有变化需要特殊情况。我认为,如果您投入一些精力来设计一种在所有情况下都能正常工作的方法,那么您可能会为此编写更好的代码。

  • 你没有很好地利用你正在使用的类的可用特性

  • 您没有很好地利用适用的一般 Java 语言特性。

例如,我可以将那个特定的循环写成:

                for (Character c : ransomChar) {
                    if (!magazineChar.remove(c)) {
                        return false;
                    }
                }
                return true;

那是在我们得出您选择了次优算法的事实之前。它的执行时间将按纸币尺寸 * 杂志尺寸进行缩放,而其他替代方案将按纸币尺寸 + 杂志尺寸进行缩放。这实际上可能很重要,因为选择有效的算法是诸如此类编码挑战的测试用例经常尝试检测的一件事。

【讨论】:

    【解决方案2】:

    这是通过从magazine 构建一组候选字符来解决您的问题的简单方法。完成后,您只需遍历ransomNote,检查每个字符的集合。如果找到它,则将其从集合中移除。如果你不这样做,那么你返回false。如果你一直通过,你会返回true。您需要使用 MultiSet,因为您需要能够在杂志中表示同一字符的多个副本。

    以下是如何做到这一点:

    public static boolean canConstruct(String ransomNote, String magazine) {
        MultiSet<Character> magazineChars = new HashMultiSet<>();
        for (int i = 0; i < magazine.length(); i++)
            magazineChars.add(magazine.charAt(i));
        for (int i = 0 ; i < ransomNote.length(); i++) {
            Character c = ransomNote.charAt(i);
            if (magazineChars.contains(c))
                magazineChars.remove(c);
            else
                return false;
        }
        return true;
    }
    

    【讨论】:

      【解决方案3】:

      请找到时间复杂度 O(n) 和空间复杂度 O(256) 或 O(1) 的小而简单的解决方案

       int[] count = new int[256];
              for (char c : magazine.toCharArray()) {
                  count[c]++;
              }
              for (char c : ransomNote.toCharArray()) {
                  if (count[c]-- == 0) return false;
              }
              return true;  
      

      结果

      【讨论】:

        【解决方案4】:

        @Harsh,所以您正在尝试访问甚至不存在的 ransomChar 元素。看线

        if (ransomChar.get(i).equals(magazineChar.get(j))) {
            ransomChar.remove(i);
            magazineChar.remove(j);
            flag = true;
        }
        

        您正在从列表中删除元素,并且每次从列表中删除元素时,它们的索引都会更改,并且当它重新检查条件时,列表在多次迭代后已经为空。因此给出运行时错误。为避免这种情况,您应该首先检查列表是否为空(您正在检查之后)。

        【讨论】:

          猜你喜欢
          • 2022-12-27
          • 2022-12-19
          • 1970-01-01
          • 2022-12-26
          • 2022-11-20
          • 2022-12-28
          • 2022-12-02
          • 2022-12-26
          • 2022-12-27
          相关资源
          最近更新 更多