【888题秋招篇】剑指大厂offer第十题,带你用思维秒杀米哈游校招真题-子序列,斩获大厂年薪60wOffer

更多精彩内容

这里是带你游历编程世界的Dashcoding编程社,我是Dash/北航硕士/ICPC区域赛全国排名30+/给你呈现我们眼中的世界!

256题算法特训课,帮你斩获大厂60W年薪offer

原题

米哈游校招真题子序列

B站动画详解

问题分析

这道题目可以归类为字符串处理与子序列操作问题,特别考察对子序列的增删操作以及其在字符串中的分布规律。给定两个字符串 st,我们需要通过删除或添加子序列 "mhy" 判断 s 是否可以转换为 t。题目中的操作不限次数,且子序列的顺序必须是 "mhy",这意味着增删操作只能集中在这三个字符上,而不能改变字符串中其他部分的顺序。

在进行分析时,需要注意以下几点:

  1. 子序列特性:题目指定子序列是 "mhy",意味着这三个字符的出现顺序必须固定。因此,我们只能在这三个字符上进行删除或添加操作,而不能随意调整顺序。由此可知,只要剩余字符部分顺序不变,且 "m", "h", "y" 的数量差满足特定条件,就可以通过多次增删操作达成转换。

  2. 问题简化:为了简化问题分析,可以将字符串 st 拆分为两部分:一个是只包含 "m", "h", "y" 的部分,另一个是剔除了这些字符后的部分。只要剔除后的部分完全一致,并且剩余部分 "m", "h", "y" 的数量差能够通过添加或删除达到平衡,则可以通过多次操作将 s 转化为 t

  3. 数量关系:核心判断条件在于 "m", "h", "y" 三者之间的数量关系。如果 s 中这三个字符的数量差可以通过相同的增删操作(如同时添加或同时删除)达到与 t 的一致,那么就可以完成转换。

  4. 时间复杂度:由于字符串的长度限制在 1000 内,总共有最多 1000 次询问,算法必须在合理时间内完成。因此,拆分字符并进行简单的线性遍历和比较,可以确保每次询问在 O(n) 时间内解决。

通过上述分析,我们可以明确:首先要对字符进行分类统计和拆分,然后在满足字符顺序和数量关系的前提下进行比较,最终决定是否输出 "Yes""No"

思路分析

本题考察了字符串的操作与匹配问题,重点在于如何通过添加或删除子序列 "mhy" 来使得字符串 s 转化为目标字符串 t。题目的关键点在于识别并操作字符串中的 "mhy" 子序列,这个子序列可以任意添加或删除,所以只要处理好其他字符的顺序一致性,同时关注 "mhy" 的匹配情况,就能判断是否可以完成转换。

思路是:首先将 st 中的非 "mhy" 字符分别提取出来,并判断它们是否相同。如果这部分相同,再比较 st"mhy" 各字符的数量关系。若数量关系满足一定条件(即三者数量的增减保持一致),则可以通过添加或删除 "mhy" 实现转换。

算法实现

算法的核心是分类统计 "m", "h", "y" 这三个字符的出现次数,并将其他字符提取出来进行比较。步骤如下:

  1. 初始化两个计数数组 bin_sbin_t,用于记录 st"m""h""y" 各自的数量。
  2. 遍历 st,分别统计 "m""h""y" 的数量,其他字符放入新字符串 new_snew_t
  3. 比较 new_snew_t 是否相同。如果相同,继续判断 "m""h""y" 的数量差是否一致(即三者的增减保持一致)。
  4. 如果两部分都满足条件,则输出 "Yes";否则输出 "No"

通过这样的处理,算法能够在每次询问中以线性时间复杂度完成判断,适用于较大规模的输入。

代码详解

标准代码程序

C++代码

#include <bits/stdc++.h>
using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        array<int, 3> bin_s = {0, 0, 0}, bin_t = {0, 0, 0};
        string s, t;
        cin >> s >> t;
        string filtered_s, filtered_t;

        // 统计 s 中 'm', 'h', 'y' 的数量,过滤掉其他字符
        for (char c : s) {
            if (c == 'm') bin_s[0]++;
            else if (c == 'h') bin_s[1]++;
            else if (c == 'y') bin_s[2]++;
            else filtered_s += c;
        }

        // 统计 t 中 'm', 'h', 'y' 的数量,过滤掉其他字符
        for (char c : t) {
            if (c == 'm') bin_t[0]++;
            else if (c == 'h') bin_t[1]++;
            else if (c == 'y') bin_t[2]++;
            else filtered_t += c;
        }

        // 如果非 "mhy" 部分相同,进一步判断 "m", "h", "y" 数量关系
        if (filtered_s == filtered_t) {
            if ((bin_s[0] - bin_t[0] == bin_s[1] - bin_t[1]) &&
                (bin_s[0] - bin_t[0] == bin_s[2] - bin_t[2])) {
                cout << "Yes" << endl;
            } else {
                cout << "No" << endl;
            }
        } else {
            cout << "No" << endl;
        }
    }
    return 0;
}

Java代码

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        while (T-- > 0) {
            int[] binS = new int[3];
            int[] binT = new int[3];
            String s = scanner.next();
            String t = scanner.next();
            StringBuilder filteredS = new StringBuilder();
            StringBuilder filteredT = new StringBuilder();

            // 统计 s 中 'm', 'h', 'y' 的数量,过滤掉其他字符
            for (char c : s.toCharArray()) {
                if (c == 'm') binS[0]++;
                else if (c == 'h') binS[1]++;
                else if (c == 'y') binS[2]++;
                else filteredS.append(c);
            }

            // 统计 t 中 'm', 'h', 'y' 的数量,过滤掉其他字符
            for (char c : t.toCharArray()) {
                if (c == 'm') binT[0]++;
                else if (c == 'h') binT[1]++;
                else if (c == 'y') binT[2]++;
                else filteredT.append(c);
            }

            // 如果非 "mhy" 部分相同,进一步判断 "m", "h", "y" 数量关系
            if (filteredS.toString().equals(filteredT.toString())) {
                if ((binS[0] - binT[0] == binS[1] - binT[1]) &&
                    (binS[0] - binT[0] == binS[2] - binT[2])) {
                    System.out.println("Yes");
                } else {
                    System.out.println("No");
                }
            } else {
                System.out.println("No");
            }
        }
        scanner.close();
    }
}

Python代码

def can_transform():
    t = int(input())
    for _ in range(t):
        bin_s = [0, 0, 0]
        bin_t = [0, 0, 0]
        s = input()
        t = input()
        filtered_s = []
        filtered_t = []

        # 统计 s 中 'm', 'h', 'y' 的数量,过滤掉其他字符
        for char in s:
            if char == 'm':
                bin_s[0] += 1
            elif char == 'h':
                bin_s[1] += 1
            elif char == 'y':
                bin_s[2] += 1
            else:
                filtered_s.append(char)

        # 统计 t 中 'm', 'h', 'y' 的数量,过滤掉其他字符
        for char in t:
            if char == 'm':
                bin_t[0] += 1
            elif char == 'h':
                bin_t[1] += 1
            elif char == 'y':
                bin_t[2] += 1
            else:
                filtered_t.append(char)

        # 如果非 "mhy" 部分相同,进一步判断 "m", "h", "y" 数量关系
        if filtered_s == filtered_t:
            if bin_s[0] - bin_t[0] == bin_s[1] - bin_t[1] == bin_s[2] - bin_t[2]:
                print("Yes")
            else:
                print("No")
        else:
            print("No")

can_transform()

Javascript代码

function canTransform() {
    const readline = require('readline');

    const input = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    const data = [];
    input.on('line', line => {
        data.push(line);
    });

    input.on('close', () => {
        let t = parseInt(data[0]);
        for (let i = 1; i <= t * 2; i += 2) {
            const s = data[i];
            const t = data[i + 1];

            const binS = [0, 0, 0];
            const binT = [0, 0, 0];
            let filteredS = '';
            let filteredT = '';

            // 统计 s 中 'm', 'h', 'y' 的数量,过滤掉其他字符
            for (let char of s) {
                if (char === 'm') binS[0]++;
                else if (char === 'h') binS[1]++;
                else if (char === 'y') binS[2]++;
                else filteredS += char;
            }

            // 统计 t 中 'm', 'h', 'y' 的数量,过滤掉其他字符
            for (let char of t) {
                if (char === 'm') binT[0]++;
                else if (char === 'h') binT[1]++;
                else if (char === 'y') binT[2]++;
                else filteredT += char;
            }

            // 如果非 "mhy" 部分相同,进一步判断 "m", "h", "y" 数量关系
            if (filteredS === filteredT) {
                if (binS[0] - binT[0] === binS[1] - binT[1] &&
                    binS[0] - binT[0] === binS[2] - binT[2]) {
                    console.log("Yes");
                } else {
                    console.log("No");
                }
            } else {
                console.log("No");
            }
        }
    });
}

canTransform();

复杂度分析

时间复杂度

对于每一组询问,算法的时间复杂度可以分为以下几部分:

  1. 遍历字符串 s s s t t t,统计每个字符串中 'm''h''y' 的数量,并过滤掉其他字符。这一步的时间复杂度是 O ( n ) O(n) O(n),其中 n n n 是字符串的长度。

  2. 比较过滤后的字符串 n e w _ s new\_s new_s n e w _ t new\_t new_t。字符串的比较操作在最坏情况下也是 O ( n ) O(n) O(n)

  3. 如果过滤后的字符串相同,还需要检查 'm''h''y' 的数量关系。这一步的操作时间是常数级别 O ( 1 ) O(1) O(1)

由于每个查询的字符串长度最多为 1000 1000 1000,并且最多有 1000 1000 1000 组查询,因此整体时间复杂度为 O ( q × n ) O(q \times n) O(q×n),其中 q q q 是查询次数, n n n 是字符串的最大长度。考虑到题目中 q q q n n n 的限制,算法在最坏情况下需要处理 1 , 000 , 000 1,000,000 1,000,000 个字符,这在现代计算机上是可以接受的。

最终的时间复杂度: O ( q × n ) O(q \times n) O(q×n)

空间复杂度

算法的空间复杂度主要体现在以下几方面:

  1. 存储统计 'm''h''y' 数量的数组 b i n _ s bin\_s bin_s b i n _ t bin\_t bin_t,这两个数组的大小都是常数 O ( 1 ) O(1) O(1)

  2. 过滤后的字符串 n e w _ s new\_s new_s n e w _ t new\_t new_t 需要额外的空间,最坏情况下,它们的长度分别为 n n n,因此这部分的空间复杂度是 O ( n ) O(n) O(n)

  3. 输入字符串和其他临时变量的存储空间也为 O ( n ) O(n) O(n),但这是问题所固有的需求。

由于我们为每个查询单独处理,空间不会累积。整体来看,空间复杂度为 O ( n ) O(n) O(n),其中 n n n 是字符串的最大长度。

最终的空间复杂度: O ( n ) O(n) O(n)

总结

本题的解决方案通过统计字符频率和过滤字符串进行比对,设计上采用了高效的线性扫描算法,使得每次查询都可以在线性时间内完成。总体时间复杂度为 O ( q × n ) O(q \times n) O(q×n),空间复杂度为 O ( n ) O(n) O(n)。该算法的实现不仅能够正确处理题目中的各种边界情况,还具有较高的可读性和扩展性,适合在大规模输入数据下运行。

本题的难点在于理解如何通过字符频率和顺序判断两个字符串能否通过有限操作相互转化。代码的逻辑清晰,思路明确,能够应对复杂度较高的情况,是一个优秀的字符串操作问题的解决方案。

米哈游Java后端笔试真题是面向Java后端开发岗位的一套笔试目,旨在考察应聘者对Java后端开发的理解和应用能力。 这套笔试目往往包含以下几个方面的内容: 1. Java语言基础:主要考察Java的基本语法、面向对象编程、常用类库等方面的知识。例如,常见的有关Java语言基础的目有:反射机制的理解和应用、线程的创建和使用、异常处理等。 2. 数据库相关知识:主要考察应聘者对数据库的基本理解和SQL的使用能力。例如,常见的数据库相关目有:数据库事务的概念和应用、数据库索引的优化策略、SQL语句的编写和调优等。 3. Web开发框架:主要考察应聘者对常用的Web开发框架的理解和应用能力。例如,常见的Web开发框架目有:Spring框架的注解使用、MyBatis的配置和映射关系等。 4. 系统设计和优化:主要考察应聘者对大型系统设计和性能优化的能力。例如,常见的系统设计和优化目有:数据库连接池的设计和实现、分布式系统的负载均衡策略、系统性能调优等。 总的来说,米哈游Java后端笔试真题是一套综合考察Java后端开发能力的目,内容涵盖了Java语言基础、数据库相关知识、Web开发框架以及系统设计和优化等方面。应聘者需要具备扎实的Java编程基础,熟悉常用的开发框架和工具,以及对大型系统的设计和性能优化有一定的了解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值