括号补全问题|小c的好数 | 豆包MarsCode AI刷题

119 阅读4分钟

问题描述

小R有一个括号字符串 s,他想知道这个字符串是否是有效的。一个括号字符串如果满足以下条件之一,则是有效的:

  1. 它是一个空字符串;
  2. 它可以写成两个有效字符串的连接形式,即 AB
  3. 它可以写成 (A) 的形式,其中 A 是有效字符串。

在每次操作中,小R可以在字符串的任意位置插入一个括号。你需要帮小R计算出,最少需要插入多少个括号才能使括号字符串 s 有效。

例如:当 s = "())" 时,小R需要插入一个左括号使字符串有效,结果为 1


当下解题想法

  • 这是个括号匹配问题,直接用,秒了
  • 可以使用linkList模拟栈,使用方法addFrist,removeFrist操作栈
  • 遇到(压入栈,遇到)判断栈顶是不是(,是的话出栈,不是的话就是括号不匹配,入栈;

解题代码:

    public static int solution(String s) {
        // write code here
        LinkedList<Character> sites = new LinkedList<Character>();
         for (char ch : s.toCharArray()) {
            if (ch=='(') {
                //入栈
                sites.addFirst(ch);
            }else if (ch == ')') {
                if (sites.getFirst()=='(') {
                     //出栈
                sites.removeFirst();
                }else{
                    sites.addFirst(ch);
                } 
            }
        }
        return sites.size(); // 
    }

遇到问题

编译不过:

java.util.NoSuchElementException at 
java.base/java.util,Linkedlist,getFirst(LinkedList.java:248) at Main.solution(Main.java:12) at 
TestRunnerMain.lambda$runCase$0(TestRunnerMain.java:56) at 
java.base/java.lang.Thread.run(Thread.java:842)

调试过程:

把出错直接发给了豆包:

遇到的 java.util.NoSuchElementException 异常是由于在尝试获取 LinkedList 的第一个元素时,LinkedList 为空。这通常发生在 sites.getFirst() 调用时,sites 中没有元素。

解决方法

  1. 检查栈是否为空

    • 在调用 sites.getFirst() 之前,先检查 sites 是否为空。如果为空,则直接将当前字符(右括号 ))压入栈。
  2. 修正代码

    • 修改代码,确保在调用 sites.getFirst() 之前检查 sites 是否为空。

于是修改了十二行的代码,在获取栈顶元素前先判断是不是空。

                //先判断是否为空
             if (!sites.isEmpty() && sites.getFirst()=='(') {
                     //出栈
                sites.removeFirst();
                }else{
                    sites.addFirst(ch);
                } 

感悟

写题时总是觉得这种题简单,不用写直接秒,但实际编写的时候就忘这忘那,就比如这次没有判断栈为空的情况,直接就获取了第一个元素。不过有豆包不仅能直接将异常翻译出来还能生成出解决方法,直接在原代码上修改实在是方便了很多。


问题描述

小C对“好数”非常感兴趣,她定义一个不含前导零的正整数为“好数”,如果它的所有数位最多包含两种不同的数字。例如,数字 2323239111,和 101 都是好数。现在小C想知道,从1到nn之间有多少个好数。

例如:当n=110n=110时,所有的1位数、2位数,以及一些3位数(如 100101)都是好数,一共有102个。

当下解题想法

  • 位数不过两种:使用set集合
  • 遍历n个数字,将数字变成字符串,遍历数字。
  • 所有的一位数都是可以减少一些遍历

解题代码:

public static int solution(int n) {
       int count = 0; // 用于计数好数的数量

       if (n<=10) {
           return n;
       }
       count+=10;
       for (int i = 11; i <= n; i++) {
           String numStr = Integer.toString(i);

           Set<Character> digits = new HashSet<>();
           for (char c : numStr.toCharArray()) {
               digits.add(c);
           }

           if (digits.size() <= 2) {
               count++;
           }
       }

       return count; 
   }

解答通过

使用豆包优化:

优化思路

  1. 减少字符串转换:每次将数字转换为字符串可能会带来一定的性能开销。可以考虑直接处理数字的每一位。
  2. 减少集合操作:每次使用集合来记录不同数字可能会带来额外的开销。可以考虑使用数组或其他数据结构来记录数字的出现情况。
  3. 提前终止循环:如果已经确定某个数字不是“好数”,可以提前终止对该数字的检查。

优化代码:

public class Main {
    public static int solution(int n) {
        int count = 0; // 用于计数好数的数量

        // 遍历从1到n的所有数字
        for (int i = 1; i <= n; i++) {
            // 使用数组来记录数字中出现的不同数字
            int[] digitCount = new int[10]; // 记录0-9每个数字的出现次数
            int distinctCount = 0; // 记录不同数字的个数

            int num = i;
            while (num > 0) {
                int digit = num % 10; // 获取当前数字的最后一位
                if (digitCount[digit] == 0) {
                    distinctCount++; // 如果该数字第一次出现,增加不同数字的计数
                }
                digitCount[digit]++; // 记录该数字的出现次数
                num /= 10; // 去掉最后一位

                // 如果不同数字的个数超过2,提前终止循环
                if (distinctCount > 2) {
                    break;
                }
            }

            // 如果不同数字的个数不超过2,则该数字是好数
            if (distinctCount <= 2) {
                count++;
            }
        }

        return count; // 返回好数的数量
    }

    public static void main(String[] args) {
        System.out.println(solution(110) == 102);
        System.out.println(solution(1000) == 352);
        System.out.println(solution(1) == 1);
    }
}

感悟

看完豆包的优化后发现这里不用集合的方法更好更巧妙,毕竟这里的要求只需要小于两位不同的数字,使用集合每次都要将数字放进集合,这样的开销不小。