首页 > 试题广场 >

实现字通配符*

[编程题]实现字通配符*
  • 热度指数:6707 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
\hspace{15pt}在 Linux Shell 中,通配符 `*` 代表任意长度(可为 0的字符串。给定:
\hspace{23pt}\bullet\, 一条模式串 `p`(仅包含可见字符及通配符 `*`,无其他元字符);
\hspace{23pt}\bullet\, 一条目标串 `s`;
\hspace{15pt}请输出 `s` 中所有与 `p` 匹配的子串的起始位置(从 0 开始计)及长度

\hspace{15pt}若不存在匹配,输出 `-1 0`。多组匹配按"起始位置升序,长度升序"排序输出。

\hspace{15pt}> `*` 可匹配空串;匹配不要求整个 `s`,只需匹配其任一连续子串。

输入描述:
\hspace{15pt}第一行:模式串 `p`  (长度不超过20)
\hspace{15pt}第二行:目标串 `s`  (长度不超过 5\times 10^6
保证输出的总行数不超过 5\times 10^6


输出描述:
\hspace{15pt}对每一个匹配子串输出 `匹配起始位置  匹配的长度`(空格分隔)一行;若无匹配输出 `-1 0`。
示例1

输入

shopee*.com
shopeemobile.com

输出

0 16

说明

0 起始位置,16长度
示例2

输入

*.com
shopeemobile.com

输出

0 16
1 15
2 14
3 13
4 12
5 11
6 10
7 9
8 8
9 7
10 6
11 5
12 4
示例3

输入

o*m
shopeemobile.com

输出

2 5
2 14
7 9
14 2
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

var pStr, sStr string
var endPositions map[int]bool

// dfs: 从 sIdx 和 pIdx 开始尝试匹配
func dfs(sIdx, pIdx int) {
	if pIdx == len(pStr) {
		endPositions[sIdx] = true
		return
	}
	if sIdx == len(sStr) {
		return
	}

	if pStr[pIdx] == sStr[sIdx] {
		dfs(sIdx+1, pIdx+1)
	} else if pStr[pIdx] == '*' {
		// 三种情况:
		// 1. '*' 匹配空(跳过 '*')
		dfs(sIdx, pIdx+1)
		// 2. '*' 匹配当前字符,并继续用 '*' 匹配后续
		dfs(sIdx+1, pIdx)
		// 3. '*' 仅匹配当前字符
		dfs(sIdx+1, pIdx+1)
	}
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)

	scanner.Scan()
	pStr = scanner.Text()
	scanner.Scan()
	sStr = scanner.Text()

	foundMatch := false

	// 存储结果:起始位置 → 长度列表
	type Result struct {
		Start, Length int
	}
	var results []Result

	for i := 0; i < len(sStr); i++ {
		// 只有首字符匹配,或模式首字符是 '*' 才尝试匹配
		if pStr[0] == '*' ||
			pStr[0] == sStr[i] {

			endPositions = make(map[int]bool) // 清空上次结果
			dfs(i, 0)

			if len(endPositions) > 0 {
				foundMatch = true
				// 收集所有有效的匹配(长度 > 0)
				for endPos := range endPositions {
					if endPos > i {
						results = append(results, Result{Start: i, Length: endPos - i})
					}
				}
			}
		}
	}

	// 去重并排序:按起始位置,再按长度
	uniqueResults := make(map[string]bool)
	var finalResults []Result
	for _, r := range results {
		key := strconv.Itoa(r.Start) + "," + strconv.Itoa(r.Length)
		if !uniqueResults[key] {
			uniqueResults[key] = true
			finalResults = append(finalResults, r)
		}
	}

	// 排序输出
	sort.Slice(finalResults, func(i, j int) bool {
		if finalResults[i].Start == finalResults[j].Start {
			return finalResults[i].Length < finalResults[j].Length
		}
		return finalResults[i].Start < finalResults[j].Start
	})

	// 输出结果
	if foundMatch && len(finalResults) > 0 {
		for _, r := range finalResults {
			fmt.Printf("%d %d\n", r.Start, r.Length)
		}
	} else {
		fmt.Println("-1 0")
	}
}

发表于 2025-09-07 22:51:05 回复(0)