#P2984. 最多提取子串数目(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 482
            Accepted: 140
            Difficulty: 4
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>贪心算法          
 
最多提取子串数目(100分)
题目简述
给定两个字符串 A 和 B,其中 A 是由 [a-z] 中小写字母组成且可能有重复字符,而 B 是由 [a-z] 中小写字母组成且不含重复字符。要求从字符串 A 中按一定规则挑选字符以组成字符串 B,并计算最多能从 A 中同时挑选出多少组字符串 B。
挑选规则:
- 同一个位置的字符只能挑选一次。
 - 挑选出的字符相对顺序不能改变。
 
解题思路
1. 问题拆解
- 核心问题是从字符串 
A中找到B的子序列。 - 为了满足子序列的定义,字符顺序不能打乱, 
B的字符不重复,因此可以使用贪心的方式:- 遍历字符串 
A,找到B的每个字符依次出现的位置。 
 - 遍历字符串 
 
2. 实现步骤
- 使用一个哈希表 
char_index保存B中每个字符及其索引位置,方便快速判断某个字符是否属于B。 - 使用一个数组 
match_count表示当前能够匹配到B的每一位的次数。 - 遍历字符串 
A:- 如果当前字符属于 
B,尝试将其放入对应位置,更新match_count。 - 如果某一位 
B已匹配完成,则将匹配推进到下一位。 
 - 如果当前字符属于 
 - 最终统计 
match_count中最后一位的次数,这就是最多匹配B的组数。 
3. 复杂度分析
- 时间复杂度:
O(A.length + B.length),其中哈希表建立需要O(B.length),遍历字符串A需要O(A.length)。 - 空间复杂度:
O(B.length),用于存储哈希表和匹配状态数组。 
代码实现
Python代码
# Python解法
A = input()  # 输入字符串A
B = input()  # 输入字符串B
n = len(B)
# char_index存储B中每个字符的位置索引
char_index = {B[i]: i for i in range(n)}
# match_count用于存储匹配到B每一位的次数
match_count = [ 0 for i in range(n+1)]
for i in A:
    if i not in char_index:  # 如果当前字符不在B中,跳过
        continue
    k = char_index[i]  # 获取字符i在B中的位置
    if k == 0:
        match_count[k + 1] += 1  # 如果是B的第一个字符,直接匹配
    elif match_count[k] > 0:
        match_count[k] -= 1  # 消耗前一位匹配的次数
        match_count[k + 1] += 1  # 当前位匹配次数加1
print(match_count[n])  # 输出能组成B的最大组数
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();
        int bLen = B.length();
        Map<Character, Integer> charIndex = new HashMap<>();
        for (int i = 0; i < bLen; i++) {
            charIndex.put(B.charAt(i), i); // 存储B中每个字符及其索引
        }
        int[] matchCount = new int[bLen + 1]; // 匹配计数
        for (char c : A.toCharArray()) {
            if (!charIndex.containsKey(c)) continue; // 如果当前字符不在B中,跳过
            int idx = charIndex.get(c);
            if (idx == 0) {
                matchCount[idx + 1] += 1; // 匹配B的第一个字符
            } else if (matchCount[idx] > 0) {
                matchCount[idx] -= 1; // 消耗前一位的匹配次数
                matchCount[idx + 1] += 1; // 当前位匹配次数加1
            }
        }
        System.out.println(matchCount[bLen]); // 输出能组成B的最大组数
    }
}
C++代码
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int main() {
    string A, B;
    cin >> A >> B;
    int n = B.size();
    unordered_map<char, int> char_index;
    for (int i = 0; i < n; ++i) {
        char_index[B[i]] = i; // 将B中字符及其索引存入哈希表
    }
    int match_count[n + 1] = {0}; // 用于存储匹配到B每一位的次数
    for (char c : A) {
        if (char_index.find(c) == char_index.end()) continue; // 如果当前字符不在B中,跳过
        int k = char_index[c];
        if (k == 0) {
            match_count[k + 1] += 1; // 匹配B的第一个字符
        } else if (match_count[k] > 0) {
            match_count[k] -= 1; // 消耗前一位的匹配次数
            match_count[k + 1] += 1; // 当前位匹配次数加1
        }
    }
    cout << match_count[n] << endl; // 输出能组成B的最大组数
    return 0;
}
        题目内容
给定 [a−z],26 个英文字母小写字符串组成的字符串 A 和 B,其中 A 可能存在重复字母,B 不会存在重复字母,现从字符串 A 中按规则挑选一些字母,可以组成字符串 B 。
挑选规则如下:
同一个位置的字母只能挑选一次 被挑选字母的相对先后顺序不能被改变 求最多可以同时从 A 中挑选多少组能组成 B 的字符串。
输入描述
输入为 2 行,第 1 行输入字符串 A ,第 2 行输入字符串 B,行首行尾没有多余空格,其中:
A、B 均由 [a−z] 26 个英文小写字母组成
0<A.length<100,A 中可能包含重复字母
0<B.length<10,B 中不会出现重复字母
输出描述
输出 1 行,包含 1 个数字,表示最多可以同时从 A 中挑选多少组能组成 B 的字符串
行末没有多余空格
备注
无需验证输入格式和输入数据合法性
样例1
输入
badc
bac
输出
1
说明
从字符串 A("badc")中可以按字母相对先后顺序取出字符串 B("bac")
样例2
输入
badc
abc
输出
0
说明
从字符串 A("badc")中无法按字母相对先后顺序取出字符串 B("bac")
样例3
输入
aabbcxd
abcd
输出
1
说明
从字符串 A("aabbcxd")中挑选一组 B("abcd")后,A 中剩余字符串为 "abx",无法再挑选出 "abcd"
样例4
输入
ababcecfdc
abc
输出
2
说明
从按如下步骤(步骤不唯一),可以同时从字符串 A("ababcecfdc")中最多取出两个 B("abc"),其中颜色标注的是每步提取的字母:

剩余的 "efdc" 无法继续提取 "abc",结果为 2
样例5
输入
aaa
a
输出
3
说明
从字符串 A("aaa")中可以挑选出 3 个字符串 B("a")