问题描述
小R有一个括号字符串 s,他想知道这个字符串是否是有效的。一个括号字符串如果满足以下条件之一,则是有效的:
- 它是一个空字符串;
- 它可以写成两个有效字符串的连接形式,即
AB; - 它可以写成
(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 中没有元素。
解决方法
-
检查栈是否为空:
- 在调用
sites.getFirst()之前,先检查sites是否为空。如果为空,则直接将当前字符(右括号))压入栈。
- 在调用
-
修正代码:
- 修改代码,确保在调用
sites.getFirst()之前检查sites是否为空。
- 修改代码,确保在调用
于是修改了十二行的代码,在获取栈顶元素前先判断是不是空。
//先判断是否为空
if (!sites.isEmpty() && sites.getFirst()=='(') {
//出栈
sites.removeFirst();
}else{
sites.addFirst(ch);
}
感悟
写题时总是觉得这种题简单,不用写直接秒,但实际编写的时候就忘这忘那,就比如这次没有判断栈为空的情况,直接就获取了第一个元素。不过有豆包不仅能直接将异常翻译出来还能生成出解决方法,直接在原代码上修改实在是方便了很多。
问题描述
小C对“好数”非常感兴趣,她定义一个不含前导零的正整数为“好数”,如果它的所有数位最多包含两种不同的数字。例如,数字 23,2323,9,111,和 101 都是好数。现在小C想知道,从1到nn之间有多少个好数。
例如:当n=110n=110时,所有的1位数、2位数,以及一些3位数(如 100, 101)都是好数,一共有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;
}
解答通过
使用豆包优化:
优化思路
- 减少字符串转换:每次将数字转换为字符串可能会带来一定的性能开销。可以考虑直接处理数字的每一位。
- 减少集合操作:每次使用集合来记录不同数字可能会带来额外的开销。可以考虑使用数组或其他数据结构来记录数字的出现情况。
- 提前终止循环:如果已经确定某个数字不是“好数”,可以提前终止对该数字的检查。
优化代码:
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);
}
}
感悟
看完豆包的优化后发现这里不用集合的方法更好更巧妙,毕竟这里的要求只需要小于两位不同的数字,使用集合每次都要将数字放进集合,这样的开销不小。