4398 查询字符串(暴力 + 哈希表)

该博客介绍了如何解决一个字符串子串查询的问题,给出了一种利用哈希表优化的解决方案。在给定一定数量的字符串并进行多次子串查询时,通过构建哈希表存储所有字符串的子串及其出现次数,能高效地回答每个查询并输出包含特定子串的字符串。代码实现分别用Python和Go语言进行了展示。
摘要由CSDN通过智能技术生成

1. 问题描述:

给定 n 个字符串 f1,f2,…,fn,这些字符串两两不同,下面给定 q 个询问,其中,第 i 次询问给定一个字符串 si,你的任务是:
计算 f1∼fn 这 n 个字符串中,包含 si 作为子串的字符串的数量;
从 f1∼fn 这 n 个字符串中,任选一个包含 si 作为子串的字符串输出;

输入格式

第一行包含整数 n,接下来 n 行,其中第 i 行包含字符串 fi。再一行包含整数 q。接下来 q 行,其中第 i 行包含字符串 si,所有 fi 和 si 都只包含小写字母、数字以及 .

输出格式

共 q 行,其中第 i 行输出第 i 个询问的答案,首先输出 f1∼fn 这 n 个字符串中包含 si 作为子串的字符串的数量,然后从 f1∼fn 这 n 个字符串中任选一个包含 si 作为子串的字符串输出。如果这样的字符串不唯一,则输出任意合理字符串均可,如果这样的字符串不存在,则输出 -。

数据范围

前三个测试点满足 1 ≤ n,q ≤ 20;
所有测试点满足 1 ≤ n ≤ 10000,1 ≤ q ≤ 50000,1 ≤ |fi|,|si| ≤ 8;

输入样例:

4
test
contests
test.
.test
6
ts
.
st.
.test
contes.
st

输出样例:

1 contests
2 .test
1 test.
1 .test
0 -
4 test.
来源:https://www.acwing.com/problem/content/description/4401/

2. 思路分析:

分析题目可以知道每一个 fi 和 si 的长度满足:1 <= |fi|,|si| ≤ 8,所以字符串的长度是非常短的,那么子串的数目相对就比较少,对于一个长度为 8 的字符串对应的子串数目为 (1 + 8) * 8 / 2 = 36,一共有 10000 个 f 字符串,所以总共的子串数目为 36 w,我们可以开一个哈希表来存储这些子串,时间复杂度大概为:360000 * 8 = 2880000 是可以通过的;由于需要输出包含子串 si 的 fi 的字符串数量,并且需要输出包含 si 对应的 fi,所以至少需要开两个哈希表,其中哈希表 count 用来记录子串 si 在 fi 中出现的次数,哈希表 mp 用来记录子串 si 对应的字符串 fi,并且每一个 fi 对应的子串 s 可能是重复的所以需要开一个哈希表 S 用来去重,存储 fi 中所有不重复子串。

3. 代码如下:

python:

class Solution:
    def process(self):
        n = int(input())
        count, mp = dict(), dict()
        i = 0
        while n > 0:
            s = input()
            # S用来去重
            S = set()
            for i in range(len(s)):
                # s1 拼接所有的子串
                s1 = ""
                for j in range(i, len(s)):
                    s1 += s[j]
                    S.add(s1)
            # 枚举 s 中的所有子串
            for x in S:
                if x not in count:
                    count[x] = 1
                else:
                    count[x] += 1
                # mp 用来记录字串对应的其中一个字符串
                mp[x] = s
            n -= 1
        m = int(input())
        for i in range(m):
            s = input()
            if s in mp:
                print(count[s], mp[s])
            else:
                print(0, "-")


if __name__ == "__main__":
    Solution().process()

go:

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func run(r io.Reader, w io.Writer) {
	// 使用bufio.NewReader()优化输入输出数据的效率
	in := bufio.NewReader(r)
	out := bufio.NewWriter(w)
    // 将缓存输出写入到标准输出中
	defer out.Flush()
	var (
		n, m int
		s    string
	)
	fmt.Fscan(in, &n)
	count := make(map[string]int)
	// mp 记录子串对应的字符串
	mp := make(map[string]string)
	for k := 0; k < n; k++ {
		fmt.Fscan(in, &s)
		// S 用来去重
		S := make(map[string]int)
		// 拼接 s 中的所有子串
		for i := 0; i < len(s); i++ {
			s1 := ""
			for j := i; j < len(s); j++ {
				s1 += string(s[j])
				S[s1] = 1
			}
		}
		// 遍历哈希表
		for key := range S {
			count[key] += 1
			mp[key] = s
		}
	}
	// m 个询问
	fmt.Fscan(in, &m)
	for i := 0; i < m; i++ {
		fmt.Fscan(in, &s)
		v, flag := mp[s]
		if flag {
			fmt.Fprintln(out, count[s], v)
		} else {
			fmt.Fprintln(out, 0, "-")
		}
	}
}

func main() {
	run(os.Stdin, os.Stdout)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值