当前位置: 首页 > news >正文

【华为OD- B卷 - 增强的strstr 100分(python、java、c++、js、c)】

【华为OD- B卷 - 增强的strstr100分(python、java、c++、js、c)】

题目

**C 语言有一个库函数: char *strstr(const char haystack, const char needle) ,实现在字符串 haystack 中查找第一次出现字符串 needle 的位置,如果未找到则返回 null。
现要求实现一个strstr的增强函数,可以使用带可选段的字符串来模糊查询,与strstr一样返回首次查找到的字符串位置。
可选段使用“[]”标识,表示该位置是可选段中任意一个字符即可满足匹配条件。比如“a[bc]”表示可以匹配“ab”或“ac”。
注意目标字符串中可选段可能出现多次

输入描述

  • 与strstr函数一样,输入参数是两个字符串指针,分别是源字符串和目标字符串

输出描述

  • 与strstr函数不同,返回的是源字符串中,匹配子字符串相对于源字符串地址的偏移(从0开始算),如果没有匹配返回-1。

补充说明:源字符串中必定不包含‘[]’;目标字符串中‘[]’必定成对出现,且不会出现嵌套。

输入的字符串长度在[1,100]之间

用例

用例一:
输入:
abcd
b[cd]
输出:
1

python解法

  • 解题思路:
    1. 解题思路
      题目要实现的是一个增强版的 strstr 函数,它允许目标字符串 tar 中含有可选段(用 [] 包裹的一组字符,表示任意一个字符即可匹配成功),在源字符串 src 中查找第一个匹配的位置。

举例:
src = “abcde”

tar = “a[bc]d”:表示目标可以匹配 “abd” 或 “acd”,滑动源字符串查找第一个匹配子串的位置。

整体思路:
解析目标字符串 tar:

把 [bc] 这种可选段转换为集合 {'b', 'c'};普通字符如 a 转换为集合 {'a'};得到目标的匹配模板,如 [{'a'}, {'b','c'}, {'d'}]。滑动窗口匹配源字符串 src:使用一个长度为模板长度的窗口滑动 src;每一位置依次判断 src[i+j] in substrings[j];若全部匹配成功,返回起始下标 i;否则继续滑动,若遍历完仍无匹配,返回 -1。
  1. 使用到的算法
    字符串解析 解析 tar 字符串,构造匹配模板
    滑动窗口 模拟 strstr 子串匹配过程
    集合判断 判断字符是否落入候选集合中
# 将目标字符串 tar 解析为字符集合数组
def parse_target(tar):# substrings:最终构造的匹配模板,如 [{'a'}, {'b','c'}, {'d'}]substrings = []current_set = set()inside_brackets = False  # 是否处于 [ ] 内部for char in tar:if char == '[':inside_brackets = True  # 进入可选段elif char == ']':inside_brackets = False  # 结束可选段substrings.append(current_set)  # 把当前集合加入模板current_set = set()  # 重置集合else:if inside_brackets:current_set.add(char)  # 添加进可选段集合else:substrings.append({char})  # 普通字符作为单元素集合加入return substrings# 滑动窗口匹配 src 中的子串,是否能与 substrings 模板匹配
def find_match_position(src, substrings):# 遍历 src 的所有起点 i(窗口长度等于模板长度)for i in range(len(src) - len(substrings) + 1):# 判断从位置 i 开始的子串是否匹配模板if all(src[i + j] in substrings[j] for j in range(len(substrings))):return i  # 匹配成功,返回起始下标return -1  # 未找到匹配# 总控制函数:解析目标并查找匹配位置
def get_match_position(src, tar):substrings = parse_target(tar)  # 构造匹配模板return find_match_position(src, substrings)  # 滑动匹配# 主程序入口:接收输入并输出结果
if __name__ == "__main__":src = input()  # 输入源字符串tar = input()  # 输入目标字符串print(get_match_position(src, tar))  # 输出匹配位置

java解法

  • 解题思路
  1. 解题思路
    题目需求回顾
    实现一个增强版 strstr 函数(模糊匹配子串):

    **源字符串(src)中查找目标字符串(pat)**的第一次匹配位置;

    目标字符串可以含有可选段(格式如 [abc]),表示当前位置可以匹配多个字符之一;

    匹配成功即返回起始下标;否则返回 -1。

✅ 解题步骤
解析目标串 pat 为匹配模板:

如果是普通字符 a,则只接受 a;如果是 [abc],则接受 'a'、'b' 或 'c';转换为 List<boolean[]>,每个位置是一个 boolean[256] 数组表示可匹配字符集合。滑动窗口遍历源字符串 src:用窗口在 src 上滑动,尝试从每个位置起始是否能完整匹配 pat 模板;若能全部匹配,返回起始下标;若都无法匹配,返回 -1。
  1. 使用到的算法
    字符串解析 将带 [abc] 的模式串解析为多字符集合的匹配模板
    滑动窗口匹配 遍历源串每个可能起始位置,逐字符匹配目标模板
    映射数组查表 使用 boolean[256] 表示可选字符集合,查表高效
import java.util.*;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);String s = in.nextLine(); // 源字符串 srcString p = in.nextLine(); // 模糊目标串 patin.close();System.out.println(idx(s, p)); // 输出匹配位置}// 主逻辑:寻找 pat 在 src 中第一次匹配的位置private static int idx(String src, String pat) {if (pat.isEmpty()) return 0; // 空模式默认匹配起始位置0List<boolean[]> box = split(pat); // 将 pat 模式解析为字符集合数组int m = box.size(); // 模式的有效长度(每个位置一个集合)int n = src.length(); // 源字符串长度// 遍历源串的每个可能起始位置for (int i = 0; i <= n - m; i++) {int j = 0;// 匹配模式每一位字符是否落在对应字符集合中while (j < m && box.get(j)[src.charAt(i + j)]) j++;if (j == m) return i; // 完全匹配成功,返回起始下标}return -1; // 未找到匹配}// 将目标字符串拆分为匹配模板,每位是一个 boolean[256] 可接受字符集合private static List<boolean[]> split(String p) {List<boolean[]> res = new ArrayList<>(); // 最终模板for (int i = 0; i < p.length(); ) {char c = p.charAt(i);if (c == '[') {// 开始处理可选段boolean[] set = new boolean[256]; // 用 ASCII 码表记录可匹配字符i++; // 跳过 [while (i < p.length() && p.charAt(i) != ']') {set[p.charAt(i++)] = true; // 标记可选字符}i++; // 跳过 ]res.add(set); // 添加到匹配模板} else {// 普通单字符匹配boolean[] set = new boolean[256];set[c] = true; // 仅匹配该字符i++;res.add(set);}}return res;}
}

C++解法

  • 解题思路
  1. 解题思路
    题目需求
    实现一个增强版的 strstr 函数。

    源字符串 src:不含 [],为纯文本。

    目标字符串 tar:可以包含多个 “可选段”(用 [] 包含的一组字符,表示该位置可以匹配其中任意一个字符)。

    查找 src 中第一个符合 tar 模式的子串,返回其起始下标(从0开始),否则返回 -1。

✅ 解题核心
解析 tar 为模板结构(vector<set>):

普通字符变成集合 {c}可选段 [abc] 变成集合 {a,b,c}滑动窗口在 src 中匹配模板:枚举起点 i,长度为模板长度 m对于每个位置 j,判断 src[i+j] 是否属于 substrings[j]全部匹配即返回 i
  1. 使用到的算法
    字符串解析 将 tar 分解为多个字符集合
    滑动窗口匹配 在 src 中以固定窗口长度查找目标模式
    哈希查找(set) 判断某字符是否属于某一字符集合,复杂度 O(1)
#include <iostream>
#include <vector>
#include <set>
#include <string>
using namespace std;// 函数:解析目标字符串 tar,将其转为字符集合列表
vector<set<char>> parse_target(const string& tar) {vector<set<char>> substrings;     // 保存每一位置对应的可匹配字符集合set<char> current_set;            // 当前正在构造的字符集合bool inside_brackets = false;     // 标记是否处于 [] 内部for (char ch : tar) {if (ch == '[') {inside_brackets = true;   // 进入可选段}else if (ch == ']') {inside_brackets = false;  // 可选段结束substrings.push_back(current_set);  // 加入集合current_set.clear();      // 清空用于下次构造}else {if (inside_brackets) {current_set.insert(ch);         // 加入可选集合}else {set<char> s;s.insert(ch);                   // 普通字符单独成集合substrings.push_back(s);}}}return substrings;
}// 函数:使用滑动窗口匹配解析后的 substrings 模板
int find_match_position(const string& src, const vector<set<char>>& substrings) {int n = src.size(), m = substrings.size();  // n为源串长度,m为模板长度for (int i = 0; i <= n - m; i++) {          // 枚举每个可能起始点bool match = true;for (int j = 0; j < m; j++) {// 如果某字符不在对应集合中,匹配失败if (substrings[j].find(src[i + j]) == substrings[j].end()) {match = false;break;}}if (match) return i; // 找到匹配位置,返回下标}return -1; // 未找到
}// 总控函数:从 tar 解析模板并进行匹配
int get_match_position(const string& src, const string& tar) {auto substrings = parse_target(tar);           // 模板解析return find_match_position(src, substrings);   // 执行匹配
}// 主函数:读取输入并输出匹配结果
int main() {string src, tar;getline(cin, src);      // 输入源字符串getline(cin, tar);      // 输入目标字符串(可能带[])cout << get_match_position(src, tar) << endl;  // 输出匹配下标return 0;
}

C解法

  • 解题思路

更新中

JS解法

  • 解题思路

更新中

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏

相关文章:

  • 如何解决全局或静态变量被修改的bug
  • 高频Java面试题深度拆解:String/StringBuilder/StringBuffer三剑客对决(万字长文预警)
  • SpringBoot 自动配置
  • FEKO许可证与其他电磁仿真软件的比较
  • 2024年热门AI趋势及回顾
  • leetcode 3355. 零数组变换 I 中等
  • PYTHON训练营DAY31
  • ⼆叉搜索树详解
  • 迅为RK3562开发板旋转Uboot logo和内核logo
  • string在c语言中代表什么(非常详细)
  • VitePress 中以中文字符结尾的字体加粗 Markdown 格式无法解析
  • 嵌入式学习笔记 D24 :系统编程之i/o操作
  • PyTorch 之 torch.distributions.Categorical 详解
  • MATLAB中进行语音信号分析
  • USB学习【13】STM32+USB接收数据过程详解
  • 关于element-ui的table type=“expand“ 嵌套表格展开异常问题解决方案
  • CYT4BB Dual Bank 1 - 存储机制
  • 02 基本介绍及Pod基础排错
  • P/Invoke 内存资源处理方案
  • Linux bash shell的循环命令for、while和until
  • 又有明星分析师晋升管理层:“白金分析师”武超则已任中信建投证券党委委员
  • 中纪报:强化监督推动过紧日子要求落到实处
  • 新冠阳性率升高,专家:新冠变异株致病力没太多变化
  • 山东发布高温橙警:预计19日至21日局地可达40℃
  • 世界高血压日|专家:高血压患者控制血压同时应注重心率管理
  • 解锁儿时愿望!潘展乐战胜孙杨,全国冠军赛男子400自夺冠