【笔试强训】Day1

文章目录

一、数字统计

题目链接

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

题目解析

根据题目,我们需要在区间 [ L, R ] 上找到数字 "2" 出现的次数,输入为两个正整数 L 和 R,输出为区间内数字 "2" 出现的次数。

例如,区间 [ 2, 22 ] 上数字 "2" 出现的次数是 6:2、12、20、21、22,其中 2、12、20 和 21 均出现了一次数字 "2",22 出现了两次,总共是出现了 6 次。

算法原理 + 代码实现

枚举 + 数字拆分

那怎样实现这个逻辑呢?

我们可以遍历区间,枚举每一个数字,拿到数字之后进行数字拆分(即按照个、十、百这些位数拆分),拆分后判断每位数上的数字是否为 "2",如果是,那就让计数器自增,否则继续拆分,直到这个数字不能被拆分为止,然后继续枚举下一个数字,以此类推。

拆分数字的方法:

  1. num % 10 得到最后位数的数字
  2. 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;
    }
}

模拟哈希

虽然这个代码设计可以通过,但是并不推荐在考试场上这样写,因为一般考场上的时间是有限制的,我们申请的两个哈希表固然高效,但是申请的时间也比较长,有超时的风险,因此建议使用数组来模拟哈希表,而不是直接申请一个容器。

  1. 我们可以使用一个布尔类型的数组来模拟哈希表,其中的下标当作 nums1 中的元素,看到题目的数据量是 [ 1, 1000 ],因此设置其长度 > 1000。比如 nums1 = [ 1, 2, 3 ],那么布尔数组的下标为 1、2、3 的值就改为 true ------ 表示已存储了 nums1 中的元素。
  2. 在遍历 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。

这道题目与 "括号匹配" 有点像,都可以使用一种先进后出的数据结构来解决。

算法原理 + 代码实现

我们可以利用栈这个数据结构来解决这个问题:

  1. 遍历输入的字符串,拿到每一个字符并判断当前字符是否与栈顶字符相同,如果相同,就直接出栈,把栈顶字符删去,然后继续遍历后续字符;如果不相同,那就把它添加到栈中。
  2. 在每一次的判断之前需要确保栈不为空。
  3. 我们可以使用一个可变的数组来模拟栈,而不是直接申请一个容器,这里由于操作元素是字符,我们可以使用 StringBuilder 来充当栈这个数据结构。
  4. 需要注意,在返回结果的时候要判断一下栈是否为空,如果为空的话就返回 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());
    }
}

文章到这里就告一段落了,若有错误请尽管指出~

相关推荐
风萧萧19992 小时前
Milvus Java 快速入门
java·开发语言·milvus
leiming62 小时前
巧用 FreeRTOS 任务通知作“邮箱”:NeoPixel 灯环控制实战
java·前端·算法
老四啊laosi2 小时前
[双指针] 4. 力扣--盛最多水的容器
算法·leetcode·装水最多的容器
wanderist.2 小时前
高维矩阵的压维存储和高维差分
c++·算法·蓝桥杯
东离与糖宝2 小时前
Java 26 FFM API进阶:零JNI调用TensorRT/OpenVINO,AI端到端延迟砍半
java·人工智能
红云梦2 小时前
互联网三高-高性能之线程池与连接池调优
java·线程池·连接池·池化技术
瑶山2 小时前
SpringBoot + MongoDB 5分钟快速集成:从0到1实操指南
java·数据库·spring boot·后端·mongodb
迈巴赫车主2 小时前
蓝桥杯192.等差数列java
java·数据结构·算法·职场和发展·蓝桥杯
JOEH602 小时前
为什么你的接口总是响应慢?Java 生产环境 6 大排查误区
java