📜  门| GATE IT 2006 |第40章(1)

📅  最后修改于: 2023-12-03 15:42:13.974000             🧑  作者: Mango

门| GATE IT 2006 |第40章

洛谷题目链接

门| GATE IT 2006 |第40章

题目描述

给定一个字符串 $s$ 和一个数字 $k$,求出 $s$ 中的所有长度为 $k$ 的子串,并且按字典序从小到大输出。

输入格式

第一行包含一个整数 $T$,表示数据组数。

每组数据包含两行,第一行包含一个字符串 $s$,第二行包含一个整数 $k$。

输出格式

对于每组数据,按照字典序从小到大输出所有长度为 $k$ 的子串,每个子串占一行。

输入样例
2
luogu
3
hello
2
输出样例
g
l
o
ogu
ugu
h
e
l
ll
lo
o
算法

本题可以使用滑动窗口算法来解决。首先移动窗口,直至窗口大小为 $k$,然后输出此时窗口中的子串。然后每次移动窗口时,保留窗口左端点,移动右端点,如此往复。具体实现中,为了保证字典序的正确性,我们可以通过一个优先队列来保存当前窗口中的子串,并定义小于符号,保证待输出的子串始终是当前窗口中的最小值。

代码示例
#include <iostream>
#include <queue>
#include <cstring>

using namespace std;

const int N = 1010;

int n;
int k;
char s[N];

struct SubStr {
    int idx;
    char s[N];
    bool operator< (const SubStr &t) const {
        for (int i = 0; i < k; i ++ )
            if (s[idx + i] != t.s[t.idx + i])
                return s[idx + i] > t.s[t.idx + i];
        return false;
    }
};

int main() {
    int T;
    cin >> T;
    while (T -- ) {
        priority_queue<SubStr> q;
        cin >> s + 1 >> k;
        n = strlen(s + 1);

        for (int i = 1; i <= k; i ++ ) q.push({0, s});
        while (!q.empty()) {
            auto t = q.top();
            q.pop();
            cout << string(t.s + t.idx + 1, t.s + t.idx + k + 1) << endl;
            if (t.idx + k == n) continue;

            t.idx ++ ;
            q.push(t);
        }
    }

    return 0;
}

时间复杂度 $O(n\log n)$,其中 $n$ 是字符串长度。