文章目录
一、数字统计
- 注意事项:一般情况下ACM模式的编辑界面是空白的,因此需要自己写出框架,而不要依赖网站给出的框架,如果已有,就全部删掉然后自己写上去。

题目解析
根据题目,我们需要在区间 [ L, R ] 上找到数字 "2" 出现的次数,输入为两个正整数 L 和 R,输出为区间内数字 "2" 出现的次数。
例如,区间 [ 2, 22 ] 上数字 "2" 出现的次数是 6:2、12、20、21、22,其中 2、12、20 和 21 均出现了一次数字 "2",22 出现了两次,总共是出现了 6 次。
算法原理 + 代码实现
枚举 + 数字拆分
那怎样实现这个逻辑呢?
我们可以遍历区间,枚举每一个数字,拿到数字之后进行数字拆分(即按照个、十、百这些位数拆分),拆分后判断每位数上的数字是否为 "2",如果是,那就让计数器自增,否则继续拆分,直到这个数字不能被拆分为止,然后继续枚举下一个数字,以此类推。
拆分数字的方法:
num % 10得到最后位数的数字num / 10将最后位数删去
- 例如:要对数字 1234 进行拆分,一般从右往左来拆,先通过 "1234 % 10" 拿到最右边位数的数字,也就是 4,然后通过 "1234 / 10" 删去 4;接下来数字 1234 就变成 123 了,然后再通过 "123 % 10" 拿到数字 3,通过 "123 / 10" 删去 3,后面以此类推,最后数字是 0 的话,就没法继续拆分了,于是结束。
由于我们是要遍历区间,枚举区间内所有数字的,因此要用到循环。
在对每一个数字进行拆分的时候,不能直接对拿到的数字进行拆分,在代码中我们拆分过后原本的数字就没了,那还怎么通过循环继续枚举下一个数字呢?可以使用临时变量存放当前要被拆分的数字。

这里要注意一下题目的数据大小,如果数据 > 1010,就需要改成 long 类型了。
代码实现
Java
import java.util.*;
public class Main {
public static void main (String[] args) {
Scanner in = new Scanner(System.in);
int l = in.nextInt();
int r = in.nextInt();
int count = 0; // 计数器,用于统计2的出现次数
// 遍历区间[l,r]
for (int i = l; i <= r; i++) {
int temp = i; // 使用临时变量存放要被拆分的数字
// 对当前数字进行拆分
while (temp != 0) {
// 判断每位数上的数字是否为2
if ((temp % 10) == 2) count++;// 若是2就让计数器自增
// 删除最后的位数
temp /= 10;
}
}
// 打印结果
System.out.println(count);
}
}
二、两个数组的交集
题目解析

题目要求我们找到两个数组的公共元素,由于数据量不算太大,我们可以在已知一个数组元素的情况下,遍历查找另一个数组的元素,然后用一个数组记录公共元素:若有相同元素,就添加到这个数组当中,否则继续遍历下一个元素。
算法原理 + 代码实现
哈希表
这里我们涉及到对另一个数组的查找,从效率的角度来说,哈希表是最优解。

我们根据例二来分析:
- 两个数组的公共元素是:[ 2, 3 ]。我们把 nums1 中的元素用哈希表来记录,然后遍历 nums2,查找其中的元素是否已在 nums1 中存在。
- ❗❗❗这里要注意,nums2 中有两个数字 "2",但是我们不能把他们都记录下来,只记录一个即可。
- 我们使用两个哈希表,hash1 用于存放 nums1 的元素,hash2 用于存放两个数组的公共元素
代码实现
Java
import java.util.*;
public class Solution {
public ArrayList<Integer> intersection (ArrayList<Integer> nums1, ArrayList<Integer> nums2) {
HashSet<Integer> hash1 = new HashSet<>(nums1); // 存放num1的元素
HashSet<Integer> hash2 = new HashSet<>(); // 存放两数组的公共元素
// 遍历nums2
for (int i = 0; i < nums2.size(); i++)
if (hash1.contains(nums2.get(i))) hash2.add(nums2.get(i));
// 将哈希表转为数组
ArrayList<Integer> ret = new ArrayList<>(hash2);
// 返回结果
return ret;
}
}
模拟哈希
虽然这个代码设计可以通过,但是并不推荐在考试场上这样写,因为一般考场上的时间是有限制的,我们申请的两个哈希表固然高效,但是申请的时间也比较长,有超时的风险,因此建议使用数组来模拟哈希表,而不是直接申请一个容器。
- 我们可以使用一个布尔类型的数组来模拟哈希表,其中的下标当作 nums1 中的元素,看到题目的数据量是 [ 1, 1000 ],因此设置其长度 > 1000。比如 nums1 = [ 1, 2, 3 ],那么布尔数组的下标为 1、2、3 的值就改为 true ------ 表示已存储了 nums1 中的元素。
- 在遍历 num2 的过程中,判断到 num2 中的元素与 nums1 中的元素相同,就将其添加到结果中。但是如何解决重复添加的问题呢?添加一个元素之后,就将布尔数组的对应下标的值改为 false ------ 表示该元素已被添加过了。
代码实现Ⅱ
基于以上,我们可以写出代码:
Java
import java.util.*;
public class Solution {
public ArrayList<Integer> intersection (ArrayList<Integer> nums1, ArrayList<Integer> nums2) {
// 使用布尔类型的数组模拟哈希表
boolean[] hash = new boolean[1010];
// 存储nums1中的元素
for (int i : nums1) {
hash[i] = true;
}
ArrayList<Integer> ret = new ArrayList<>();
// 遍历nums2
for (int i = 0; i < nums2.size(); i++) {
if (hash[nums2.get(i)]) {
ret.add(nums2.get(i));
hash[nums2.get(i)] = false;
}
}
return ret;
}
}
三、点击消除
题目解析
题目需要我们消除相邻的两个相同字符,如 abbc,消除之后得到 ac。
这道题目与 "括号匹配" 有点像,都可以使用一种先进后出的数据结构来解决。
算法原理 + 代码实现
栈
我们可以利用栈这个数据结构来解决这个问题:
- 遍历输入的字符串,拿到每一个字符并判断当前字符是否与栈顶字符相同,如果相同,就直接出栈,把栈顶字符删去,然后继续遍历后续字符;如果不相同,那就把它添加到栈中。
- 在每一次的判断之前需要确保栈不为空。
- 我们可以使用一个可变的数组来模拟栈,而不是直接申请一个容器,这里由于操作元素是字符,我们可以使用 StringBuilder 来充当栈这个数据结构。
- 需要注意,在返回结果的时候要判断一下栈是否为空,如果为空的话就返回 0,如果不是就将 StringBuilder 转成字符串返回。
代码实现
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String input = in.next();
// 使用StringBuilder模拟栈
StringBuilder stack = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
if ((stack.length() != 0) && (stack.charAt(stack.length() - 1) == ch)) {
// 判断当前字符与栈顶字符相同,需要消除
stack.deleteCharAt(stack.length() - 1); // 删除栈顶字符
} else stack.append(ch);
}
System.out.println((stack.length() == 0) ? 0 : stack.toString());
}
}
文章到这里就告一段落了,若有错误请尽管指出~
完