【华为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(); // 源字符串 src
        String p = in.nextLine(); // 模糊目标串 pat
        in.close();
        System.out.println(idx(s, p)); // 输出匹配位置
    }

    // 主逻辑:寻找 pat 在 src 中第一次匹配的位置
    private static int idx(String src, String pat) {
        if (pat.isEmpty()) return 0; // 空模式默认匹配起始位置0

        List<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解法

  • 解题思路

更新中

注意:

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

### 华为OD机试中的增强版 `strstr` 函数 #### 题目描述 题目要求实现一个增强版本的 `strstr` 函数,其功能是在源字符串中查找第一个匹配的目标字符串,并返回目标字符串首次出现位置相对于源字符串起始位置的偏移量。如果未找到,则返回 `-1`。此函数支持带有通配符模式的模糊查询。 #### 解题思路 为了处理带通配符的模糊查询,在遍历过程中需考虑多种情况: - 当前字符完全匹配; - 使用通配符代替任意单个字符; - 处理连续多个通配符的情况; 对于每种编程语言的具体实现方式有所不同,下面别给出 C++Python 的解决方案[^1]。 #### C++ 实现方案 ```cpp #include <iostream> #include <string> using namespace std; int enhancedStrstr(const string& haystack, const string& needle) { int m = haystack.size(), n = needle.size(); for (int i = 0; i <= m - n; ++i) { bool match = true; for (int j = 0; j < n && match; ++j) { if (!(haystack[i + j] == '?' || needle[j] == '?' || haystack[i + j] == needle[j])) { match = false; } } if (match) return i; } return -1; } // 主程序用于读取输入并调用上述方法打印结果 int main() { string s, p; cin >> s >> p; cout << enhancedStrstr(s, p); } ``` #### Python 实现方案 ```python def enhanced_strstr(haystack: str, needle: str) -> int: m, n = len(haystack), len(needle) for i in range(m - n + 1): matched = True for j in range(n): if not any([ haystack[i+j] == ch or needle[j] == '?' for ch in [haystack[i+j], '?'] ]): matched = False break if matched: return i return -1 if __name__ == "__main__": source_string = input().strip() pattern_string = input().strip() result = enhanced_strstr(source_string, pattern_string) print(result) ``` 在实际考试环境中需要注意的是,华为 OD 采用 ACM 模式进行考核,因此考生不仅需要完成核心算法逻辑的设计与编码工作,还需要自行负责数据的输入/输出操作部[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeClimb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值