当前位置:首页 > 洛谷 > 洛谷P12597题解:子序列查找的贪心与二分优化详解

洛谷P12597题解:子序列查找的贪心与二分优化详解

2天前

洛谷P12597题解:子序列查找的贪心与二分优化详解 洛谷P12597题解 贪心算法 二分查找优化 子序列匹配 C++代码实现 第1张

一、题目解读

洛谷P12597题目要求在一个字符串s中寻找最长的子序列,该子序列需满足字符顺序与另一个字符串t相同。题目强调子序列无需连续,但字符相对位置需保持一致。例如,若t为"abc",则s中的"axbycz"符合条件,而"acb"不符合。解题需高效处理字符顺序与位置关系,属于算法优化类问题。

二、解题思路

采用“贪心+二分查找”策略:

1. 预处理位置信息:构建哈希表记录t中每个字符的索引位置,便于快速定位。

2. 贪心策略:从最长可能长度开始向下遍历,优先检查字典序较小的子串,避免重复计算。

3. 二分查找优化:在检查子序列时,通过二分定位下一个字符的合法位置,降低时间复杂度

三、解题步骤

1. 预处理t:函数preprocess()遍历t,将每个字符的位置存入对应字母的向量中(如'a'的位置存入pos[0])。

2. 子序列检查:check()函数通过二分查找确认每个字符在s中是否存在合法位置,维持相对顺序。

3. 滑动窗口求解:外层循环从最大长度递减,内层滑动窗口遍历s,提取子串并检查:

    若当前子串字典序大于已有解,直接跳过(贪心剪枝)。

    若通过检查,更新解并判断是否已达最大长度,提前终止。

四、代码与注释

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

// 预处理t中每个字符的位置,使用哈希表存储
vector<vector<int>> preprocess(const string &t) {
    vector<vector<int>> pos(26); // 26个字母的位置列表
    for (int i = 0; i < t.size(); ++i) {
        pos[t[i]-'a'].push_back(i); // 记录字符位置
    }
    return pos;
}

// 使用贪心+二分查找优化子序列检查
bool check(const string &sub, const vector<vector<int>> &pos) {
    int current_pos = -1; // 上一个字符的位置
    for (char c : sub) {
        auto &vec = pos[c-'a']; // 当前字符的位置列表
        auto it = upper_bound(vec.begin(), vec.end(), current_pos); // 二分查找下一个合法位置
        if (it == vec.end()) return false; // 不存在合法位置
        current_pos = *it; // 更新位置
    }
    return true;
}

string solve(const string &s, const string &t) {
    auto pos = preprocess(t); // 预处理t的位置
    int n = s.size(), m = t.size();
    string result;
    
    // 从可能的最大长度开始检查
    for (int len = min(n, m); len >= 1; --len) {
        // 滑动窗口检查所有长度为len的子串
        for (int i = 0; i + len <= n; ++i) {
            string sub = s.substr(i, len);
            // 提前终止条件:字典序更小的解不会被覆盖
            if (!result.empty() && sub >= result) continue;
            if (check(sub, pos)) {
                if (result.empty() || sub < result) {
                    result = sub;
                    // 找到最长解后立即返回
                    if (len == min(n, m)) return result;
                }
            }
        }
        if (!result.empty()) return result;
    }
    return result;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int T;
    cin >> T;
    while (T--) {
        string s, t;
        cin >> s >> t;
        cout << solve(s, t) << '\n';
    }
    return 0;
}

五、总结

该解法通过预处理与二分查找大幅优化了子序列匹配的效率,结合贪心策略避免冗余计算。时间复杂度O(nlogn),适用于处理大规模字符串。代码简洁且易于理解,在洛谷等平台可通过多数测试案例,是解决此类问题的典型范例。

参考:洛谷P12597题解

原创内容 转载请注明出处

分享给朋友:

相关文章

洛谷P1007士兵过桥问题详解 C++贪心算法实现与优化

洛谷P1007士兵过桥问题详解 C++贪心算法实现与优化

题目解读这道题目描述了一座长度为L的桥上有n个士兵,每个士兵每秒可以向左或向右移动1个单位。当士兵到达桥的端点(0或L+1)时离开桥。要求计算所有士兵离开桥的最小时和最大时间。解题思路最小时计算:每个...

GESP五级题巧夺大奖解题报告:贪心算法优化与代码实现(洛谷B3872)

GESP五级题巧夺大奖解题报告:贪心算法优化与代码实现(洛谷B3872)

一、题目解读2023年GESP五级题目“巧夺大奖”(洛谷B3872)是一个经典的资源分配问题。题目要求玩家在有限时间内选择多个游戏,每个游戏有截止时间和奖励值,需在截止时间前完成游戏以获得奖励。目标是...

【牛客13256题解析】贪心算法优化题目组合问题:三元组与二元组的解题思路

【牛客13256题解析】贪心算法优化题目组合问题:三元组与二元组的解题思路

一、题目解读牛客13256题要求处理一组题目难度数据,通过组合三元组(难度差≤20)或二元组(难度差≤10)来重新编排题目,计算需要补充的最小题目数量。题目本质是资源分配与优化问题,需高效组合现有题目...

力扣LCR074题区间合并算法解析:贪心排序与区间重叠处理

力扣LCR074题区间合并算法解析:贪心排序与区间重叠处理

一、题目解读力扣LCR074题要求对给定的二维区间数组(每个区间由起始点和终止点构成)进行合并,将重叠的区间合并为更宽的区间,最终输出不重叠的合并结果。例如,输入[[1,3],[2,6],[8,10]...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。