首页 > 试题广场 >

字符串匹配

[编程题]字符串匹配
  • 热度指数:6195 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
牛牛有两个字符串A和B,其中A串是一个01串,B串中除了可能有0和1,还可能有'?',B中的'?'可以确定为0或者1。 寻找一个字符串T是否在字符串S中出现的过程,称为字符串匹配。牛牛现在考虑所有可能的字符串B,有多少种可以在字符串A中完成匹配。

例如:A = "00010001", B = "??"
字符串B可能的字符串是"00","01","10","11",只有"11"没有出现在字符串A中,所以输出3

输入描述:
输入包括两行,第一行一个字符串A,字符串A长度length(1 ≤ length ≤ 50),A中每个字符都是'0'或者'1'。
第二行一个字符串B,字符串B长度length(1 ≤ length ≤ 50),B中的字符包括'0','1'和'?'。


输出描述:
输出一个整数,表示能完成匹配的字符串种数。
示例1

输入

00010001
??

输出

3
用Java实现的正则表达式写法,简洁明了:
import java.util.*;
 
public class Main{
 
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String A = sc.nextLine();
        String B = sc.nextLine();
        StringBuilder sb = new StringBuilder();
        //将sb装换成模式匹配
        for(int i=0; i<B.length(); i++)
            if(B.charAt(i) == '?')
                sb.append("[01]{1}");
            else
                sb.append(B.charAt(i));
        Set<String> res = new HashSet<>();
 
        for(int i=0; i<=A.length()-B.length(); i++){
            String sub = A.substring(i, i+B.length());
            if(sub.matches(sb.toString()))
                res.add(sub);
        }
        System.out.println(res.size());
    }
}

发表于 2018-10-15 16:54:07 回复(6)
def solution(A,B):
    if len(B)>len(A):
        return 0
    s=len(B)
    count=0
    res=[]
    for i in range(len(A)-s+1):
        t=0
        for j in range(s):
            if B[j]=='?' or B[j]==A[i:i+s][j]:
                t+=1
                if t==s:
                    res.append(A[i:i+s])
            else:
                break
    return len(set(res))
A=raw_input().strip()
B=raw_input().strip()
print solution(A,B)

发表于 2018-07-18 17:53:54 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main(){
    string A, B;
    cin>>A>>B;
    int n=A.length(), m=B.length(), s=0;
    if(n<m){
        puts("0");
        return 0;
    }
    vector<string> v;
    for(int i=0;i<n-m+1;i++){
        bool flag = true;
        for(int j=0;j<m;j++)
            if(A[i+j]!=B[j] && B[j]!='?')
                flag = false;
        if(flag){
            string t = A.substr(i, m);
            if(find(v.begin(), v.end(), t) == v.end())
                v.push_back(t);
        }
    }
    printf("%ld\n", v.size());
    return 0;
}

发表于 2020-11-30 00:32:44 回复(0)
暴力 + 剪枝
#include<bits/stdc++.h>

using namespace std;

int getAns(string a,string b,int num){
    if(num == 0) return a.find(b) != -1 ? 1:0;    // kmp算法
    int i = 0;
    while(b[i] != '?') ++i;
    if(a.find(b.substr(0,i)) == -1) return 0;
    return getAns(a,b.substr(0,i) + "1" + b.substr(i+1),num - 1) + getAns(a,b.substr(0,i) + "0" + b.substr(i+1),num - 1);
}

int main(){
    string a;
    string b;
    cin >> a >> b;

    int num = 0;
    for(int i = 0;i < b.size();++ i)
        if(b[i] == '?') ++ num;

    cout<<getAns(a,b,num)<<endl;
}


发表于 2019-09-07 16:31:50 回复(0)
#include <iostream>
using namespace std;
#include <set>
#include <string>

void help()
{
string A, B;
cin >> A >> B;
int A_size = A.length();
int B_size = B.length();

set<string> s;
int ret = 0;
/*从A中切出和B串等长的子串,对每个切出的子串分别和B进行比较,如果相等就加1,同时z注意的是从A串中可能切出相同的子串,为防止重复计算,可在比较之前判断当前子串是否经在set集合中,若存在则进行下一轮循环*/
for (int i=0; i<=A_size-B_size; i++)
{
string cur = A.substr(i, B_size);
//如果当前切出的子串已经在set中出现过,则说明已经统计过
if (s.count(cur)) continue;
s.insert(cur);
bool flag = true;
for (int k=0; k<B_size; k++)
{
if (cur[k] != B[k])
{
if (B[k] == '?')
continue;
else
{
flag = false;
break;
}
}
}

if (flag)
ret++;
}

cout << ret << endl;
}

int main()
{
help();
}
编辑于 2018-08-22 10:29:26 回复(0)

用一个map来存字符串,暴力匹配时间复杂度n的平方。

当找到第一个字符串后进入循环,这里注意匹配条件,相等或者b[i]为0

#include<bits/stdc++.h>
using namespace std;
int main()
{
    unordered_set<string> strMap;
    string a, b;
    while(cin >> a >> b){
        int sizeA = a.size();
        int sizeB = b.size();
        for(int i = 0;i < sizeA - sizeB + 1;i++)
        {
            if(a[i] == b[0] || b[0] == '?'){
                int cnt = 0;
                for(int j = 0;j < sizeB;j++){
                    if(a[i + j] == b[j] || b[j] == '?')
                        cnt++;
                    else
                        break;
                }
                if(cnt == sizeB){
                    strMap.insert(a.substr(i, sizeB));
                }
            }
        }
        cout << strMap.size() << endl;
    }
    return 0;
}
发表于 2019-04-02 15:22:30 回复(0)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;

/**
 * @author wylu
 */
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        char[] a = br.readLine().toCharArray();
        char[] b = br.readLine().toCharArray();

        HashSet<String> set = new HashSet<>();
        for (int i = 0; i <= a.length - b.length; i++) {
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < b.length; j++) {
                if (b[j] == '?' || b[j] == a[i + j]) {
                    sb.append(a[i + j]);
                }
            }
            if (sb.toString().length() == b.length) set.add(sb.toString());
        }
        System.out.println(set.size());
    }
}

发表于 2019-01-18 15:09:59 回复(0)
采用深度优先搜索填写字符串B中的所有?,如果能在A中找到这个字符串,则计数自增
#include <iostream>
#include <string>
using namespace std;

void dfs(string a, string b, int i, int& count) {
    if(i == b.size()){
        // 已经搜索了b字符串的长度,如果当前的字符串在a中,结果就进行自增
        if(a.find(b) != string::npos)
            count ++;
        return;
    }
    if(a.find(b.substr(0, i)) != string::npos){    // 剪枝,保证i之前的字符能够匹配成功
        // 位置i的字符未定就进行尝试,否则直接到下一个位置
        if(b[i] == '?'){
            b[i] = '0';
            dfs(a, b, i + 1, count);
            b[i] = '1';
            dfs(a, b, i + 1, count);
            b[i] = '?';
        }else
            dfs(a, b, i + 1, count);
    }
}

int main() {
    string a, b;
    cin >> a >> b;
    int count = 0;
    dfs(a, b ,0, count);
    cout << count << endl;
    return 0;
}


发表于 2021-02-26 16:15:12 回复(0)
js 字符窜匹配(朴素)
const readline = require("readline");

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

let inArr = [];
let temp = [];
r1.on("line", (line) => {
    inArr.push(line.trim());
    let a = inArr[0];
    let b = inArr[1];
    a += "";
    b += "";
    if (inArr.length > 1) {
        let index = stringMatch(a, b, 0);
        while (index < a.length - b.length) {
            stringMatch(a, b, ++index);
        }
        temp = temp.filter((item, index) => temp.indexOf(item) == index);
        console.log(temp.length);
    }
});

var stringMatch = function (T, P, t) {
    let p = 0;
    if (T.length < P.length) return 0;
    while (t < T.length && p < P.length) {
        if (T[t] == P[p] || P[p] == "?") {
            t++;
            p++;
        } else {
            t = t - p + 1;
            p = 0;
        }
    }

    if (p >= P.length) {
        temp.push(T.slice(t - p, t - p + P.length));
        return t - p;
    }

    return 0;
};

编辑于 2023-03-10 20:32:57 回复(0)
var str = readline();
var strChild = readline();
var patt = "^";
for (var i = 0; i < strChild.length; i++) {
    if (strChild[i] == "?") {
        patt += ".";
    } else {
        patt += strChild[i];
    }
}
var re = new RegExp(patt);
var set = new Set();
while (str.length > 0) {
    var child = str.match(re);
    if (child) {
        set.add(child[0])
    }
    str = str.substr(1);
}
print(set.size);
发表于 2018-07-12 11:12:37 回复(0)
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string a,b;
    cin>>a>>b;
    set<vector<char>> se;
    for(int i=0;i<=a.length()-b.length();i++)
    {
        vector<char> v;
        int flag=1;
        for(int j=0;j<b.length();j++)
        {
            if(b[j]==a[i+j])    continue;
            else if(b[j]=='?') v.push_back(a[i+j]);
            else    {flag=0;break;}
        }
        if(flag)    se.insert(v);
    }
    cout<<se.size()<<endl;
}
移动窗口暴力破解。
发表于 2022-04-04 00:09:07 回复(0)
主要思想:遍历a,将匹配b的a的子序列加入到set中,最后返回set的大小即可
let aa=readline();
let bb=readline();let as=new Set();
let l=0;//这里是需要l来记录a的子序列开始位置,这个子序列无论是匹配成功还是匹配失败,下一个子序列的开头都是a的第l+1
for(let i=0,j=0;i<aa.length;){
    if(aa[i]==bb[j]||bb[j]=='?'){
        
        j++;
        if(j==bb.length){
            j=0;
            as.add(aa.slice(l,i+1));
            i=l+1; 
            l=i;
            continue;
        }
        
    }else{
        j=0;
        i=l+1;
        l=i;
        continue;
    }
    i++
}
console.log(as.size);


发表于 2022-03-27 16:12:35 回复(0)
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String a = in.next();
        String b = in.next();
        HashSet<String> s = new HashSet<>();
        for (int i = 0; i < a.length() - b.length() + 1; i++) {
            int c = 0;
            for (int j = 0, k = i; j < b.length(); j++, k++) {
                if (b.charAt(j) == '?' || b.charAt(j) == a.charAt(k)) {
                    //匹配到b串中的字符个数+1
                    c++;
                }
            }
            //匹配的字符数等于b串长度,说明从第i项开始在a串中完成匹配,将匹配出的存入set
            if (c == b.length()) {
                s.add(a.substring(i, i + b.length()));
            }
        }
        System.out.print(s.size());
    }
}

发表于 2022-03-26 11:53:18 回复(0)
var count = 0
func main() {
	var A,B string
	fmt.Scanf("%s",&A)
	fmt.Scanf("%s",&B)
	dfs([]byte(A),[]byte(B),0)
	fmt.Println(count)
}
//深度优先超时
func dfs (a,b []byte,i int){
	if i == len(b){
		if strings.Contains(string(a),string(b)){
			count++
		}
		return
	}
	if strings.Contains(string(a), string(b[:i+1])){
		dfs(a,b,i+1)
	}else{
		if b[i] == '?'{
			b[i] = '0'
			dfs(a,b,i+1)
			b[i] = '1'
			dfs(a,b,i+1)
			b[i] = '?'
		}
	}
}

深度优先实行递归,
案例
1101010101111010101011111111110001010101
???????????????????????????????????
显示超时
发表于 2022-03-25 11:13:51 回复(0)
暴力匹配,从A中取出匹配上的,放入set,最后求set大小
#include<bits/stdc++.h>
using namespace std;
int main(){
    string a, b;
    cin>>a;
    cin>>b;
    int n=a.length();
    int m=b.length();
//     int i=0;
    if(m>n)
        return 0;
    unordered_set<string> s;
    for(int i=0; i+m<=n; ++i){
        for(int j=0; j<m; ++j){
            if(a[i+j]!=b[j] && b[j]!='?')
                break;
            if(j==m-1){
                s.insert(a.substr(i, m));
            }
        }
    }
    cout<<s.size()<<endl;
    
    return 0;
}
发表于 2022-03-15 17:39:14 回复(0)
package main

import "fmt"

func stringMatch(a, b string) int {
	ret := 0
	at := []rune(a)
	bt := []rune(b)
	res := make(map[string]struct{})
	for i := 0; i < len(at)-len(bt)+1; i++ {
		tmp := 0
		for j := 0; j < len(bt); j++ {
			if at[i+j] == bt[j] || bt[j] == '?' {
				tmp++
				if tmp == len(b) {
					res[a[i:i+len(b)]] = struct{}{}
				}
			}
		}
	}
	ret = len(res)
	return ret
}

func main() {
	a := ""
	fmt.Scan(&a)
	b := ""
	fmt.Scan(&b)
	ret := stringMatch(a, b)
	fmt.Println(ret)
}


发表于 2021-11-22 17:51:24 回复(0)
不会用正则表达式的也可以直接比较
import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            String A = in.nextLine();
            String B = in.nextLine();
            LinkedHashSet<String> set = new LinkedHashSet();   // 存储可以正确匹配的字符串,最终的set.size()就是匹配种数
            for(int i=0;i<=A.length()-B.length();i++){
                boolean b = true;
                for(int j=0,index=i;j<B.length();j++,index++){
                    if(B.charAt(j)!='?' && B.charAt(j)!=A.charAt(index)){ // B的字符不是?,且对应的字符不相等,则说明不可以匹配
                        b = false;                          // 标记不可以匹配
                        break;
                    }
                }
                if(b){                                      // 可以匹配,添加匹配子串
                    set.add(A.substring(i,i+B.length()));
                }
            }
            System.out.println(set.size());
        }
    }
}


发表于 2021-09-01 00:31:31 回复(0)
//C++baolifa


#include <iostream>
#include <stdlib.h>
#include <string>
#include <vector>
#include <set>
#include <unordered_set>
#include <algorithm>

using namespace std;


bool check(string a, string b){
    for (int i = 0; i <a.size();++i){
        if (a[i] == '?'){
            continue;
        }
        else if (a[i] == '0'){
            if (b[i] == '1') return false;
        }
        else if (a[i] == '1'){
            if (b[i] == '0') return false;
        }
    }
    
    
    return true;
}


int main(){
    string str;
    string sub;
    while (cin>>str>>sub){
        unordered_set<string> myset;
        int n = sub.size();
        int num = 0;
        for (int i = 0; i <str.size() ; ++i){
            string cur_sub = str.substr(i,n);
            if (cur_sub.size() == n && check(sub, cur_sub) == true){
                myset.insert(cur_sub);
            }
            
        }
        cout<<myset.size()<<endl;
    }
    
    
    return 0;
}
发表于 2021-04-04 16:15:36 回复(0)
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

int main()
    
{
    string s1,s2;
    while(cin>>s1>>s2)
    {
        int res=0;
        if(s2.size()>s1.size())
        {
            cout<<0<<endl;
            break;
        }
        vector<string> temp;
        for(int i=0;i+s2.size()-1<s1.size();i++)//最多有i+s2.size()-1<s1.size()种
        {
            bool flag=1;
            for(int j=0;j<s2.size();j++)
            {
                if(s1[i+j]==s2[j]||s2[j]=='?');//每走一步比较一下
                else flag=0;
            }
            if(flag) 
            {
                string t=s1.substr(i,s2.size());
                if(temp.empty()||find(temp.begin(),temp.end(),t)==temp.end())
                {
                    temp.push_back(t);
                    //cout<<t<<endl;
                }
            }
        }
        cout<<temp.size()<<endl;
    }
    return 0;
}

发表于 2020-11-22 15:07:07 回复(0)
python2 正则表达式
A = raw_input().strip()
B = raw_input().strip()
patternb = B.replace('?', '[01]')
import re
res = []
for i in range(len(A)-len(B)+1):
    sub = A[i:i+len(B)]
    m = re.findall(patternb, sub)
    res += m
print len(set(res))
发表于 2020-02-26 01:36:46 回复(0)