当前位置:首页 > 洛谷 > 洛谷P2412题解:后缀树高效解决字符串比较问题

洛谷P2412题解:后缀树高效解决字符串比较问题

2天前

洛谷P2412题解:后缀树高效解决字符串比较问题 洛谷题解 后缀树 ST结构构建 ST表 字典序 第1张

一、题目解读

洛谷P2412题要求处理一组字符串,并支持区间内字典序最小字符串的查询。题目关键在于高效处理字符串比较与查找,传统暴力方法时间复杂度无法满足需求,需引入更优的数据结构

二、解题思路

采用**后缀树ST表)**解决。核心思路为:

1. 预处理:将输入字符串转为小写,避免重复字符转换,减少比较开销。

2. 构建ST表:利用倍增思想,通过logN级预处理,保存每个区间的最小值索引。

3. 查询优化:利用二分查找原理,通过ST表快速定位区间内字典序最小的字符串索引。

三、解题步骤

1. 输入处理:读取N个字符串,存储原版与预处理小写版本。

2. ST表构建:

○ 初始化第一层级(log2(N)级):直接记录每个位置的原索引。

○ 递进层级:通过比较相邻区间的字典序最小值,合并生成更高层索引。

3. 查询实现:

○ 计算查询区间长度对应的ST层级j。

○ 比较区间两端对应层级的最小值,返回字典序更小者。

四、代码与注释

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

// 构建后缀(ST表)
vector<vector<int>> buildST(const vector<string>& words) {
    int n = words.size();
    int k = log2(n) + 1; // 层级数量
    vector<vector<int>> st(n, vector<int>(k)); // 存储各层级区间最小值索引
    
    // 预处理小写版本避免重复转换
    vector<string> lower_words(n);
    for(int i = 0; i < n; ++i) {
        lower_words[i].resize(words[i].size());
        transform(words[i].begin(), words[i].end(), lower_words[i].begin(), ::tolower);
    }

    // 初始化第一层级(每个位置即为自身最小值)
    for(int i = 0; i < n; ++i) st[i][0] = i;
    
    // 递进构建高层级
    for(int j = 1; (1<<j) <= n; ++j) { // 遍历层级
        for(int i = 0; i + (1<<j) - 1 < n; ++i) { // 遍历起始位置
            int x = st[i][j-1], y = st[i+(1<<(j-1))][j-1];
            // 比较两个子区间的最小值(考虑字典序相同则取索引小者)
            st[i][j] = (lower_words[x] > lower_words[y] || (lower_words[x] == lower_words[y] && x > y))? x : y;
        }
    }
    return st;
}

// 查询区间字典序最小值索引
int query(const vector<vector<int>>& st, const vector<string>& words, const vector<string>& lower_words, int l, int r) {
    int len = r - l + 1;
    int j = log2(len); // 对应层级
    int x = st[l][j], y = st[r - (1<<j) + 1][j];
    return (lower_words[x] > lower_words[y] || (lower_words[x] == lower_words[y] && x > y))? x : y;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m;
    cin >> n >> m; // 输入字符串数量与查询次数
    vector<string> words(n);
    for(int i = 0; i < n; ++i) cin >> words[i];
    
    auto st = buildST(words);
    vector<string> lower_words(n);
    for(int i = 0; i < n; ++i) {
        lower_words[i].resize(words[i].size());
        transform(words[i].begin(), words[i].end(), lower_words[i].begin(), ::tolower);
    }
    
    while(m--) {
        int x, y;
        cin >> x >> y;
        x--; y--;
        int pos = query(st, words, lower_words, x, y);
        cout << words[pos] << '\n';
    }
    
    return 0;
}

五、总结

本解法通过后缀树(ST表)将区间查询优化至O(logN),结合预处理与二分思想,显著降低时间复杂度。适用于需频繁查询区间最值的场景,代码中细节(如小写预处理、字典序比较逻辑)体现了优化技巧,为同类问题提供高效解决方案。

原创内容 转载请注明出处

分享给朋友:

相关文章

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

一、题目解读洛谷1656题要求在无向图中找出所有割边(即删除后导致图不连通的边)。题目核心在于判断图的连通性,并识别哪些边是“桥”。需理解图论中的连通分量概念,以及如何通过算法高效定位割边。二、解题思...

洛谷P2190题解:铁路售票系统车厢计算(差分数组+前缀和优化)

洛谷P2190题解:铁路售票系统车厢计算(差分数组+前缀和优化)

一、题目解读洛谷P2190题要求解决铁路售票系统中的车厢数量计算问题。题目给定n个车站和m条订票申请,每条申请包含区间[x,y)及乘客数z。需要计算在不超载的情况下(每节车厢最多36人),满足所有乘客...

洛谷P1141题解:迷宫连通块问题的深度优先搜索算法与代码解析

洛谷P1141题解:迷宫连通块问题的深度优先搜索算法与代码解析

一、题目解读洛谷P1141题目要求处理一个由字符构成的迷宫,其中相同字符形成连通块,不同字符构成分隔。题目需统计连通块数量及大小,并支持查询两点是否属于同一连通块。核心在于高效识别并标记迷宫中的连通区...

洛谷P3393题解:基于多源BFS与Dijkstra算法求解图论最小花费路径问题

洛谷P3393题解:基于多源BFS与Dijkstra算法求解图论最小花费路径问题

一、题目解读洛谷P3393题要求在一个包含N个城市和M条双向道路的图中,求解从起点1到终点N的最小花费路径。图中存在僵尸城市(僵尸无法通过)和危险城市(由僵尸城市扩散S步后标记),需要避开所有危险城市...

洛谷P2789题解:递归算法与避免重复计算的技巧

洛谷P2789题解:递归算法与避免重复计算的技巧

一、题目解读洛谷P2789题要求计算n条直线在平面上两两相交产生的交点总数。题目强调交点不重复,需考虑平行线情况。关键点在于如何高效枚举所有可能的交点组合,并排除重复结果。二、解题思路采用递归算法,核...

洛谷P1438题解:基于线段树的等差数列

洛谷P1438题解:基于线段树的等差数列

一、题目解读洛谷P1438题要求处理数列的区间更新与单点查询操作,其中更新方式为给定区间内元素按等差数列递增。传统暴力修改会因多次区间遍历导致超时,需设计高效数据结构——线段树,结合等差数列性质实现O...

发表评论

访客

看不清,换一张

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