最小距离查询

最小距离查询

时间限制 1000 ms 内存限制 65536 KB
题目描述

给定一个由小写字母 a 到 z 组成的字符串 S,其中第 i 个字符为 S[i](下标从 0开始)。你需要完成下面两个操作:
INSERT c 其中 c 是一个待输入的字符。你需要在字符串的末尾添加这个字符。保证输入的字符同样是 a 到 z 之间的一个小写字母。
QUERY x 其中 x 是一个输入的整数下标。对于这个询问,你需要回答在 S 中和 S[x]相等且与 x 最近的距离。输入保证 x 在当前字符串中合法
例如 S = “abcaba”,如果我们操作:
INSERT a
则在 S 的末端加一个字符 a,S 变成"abcabaa"。
接下来操作
QUERY 0
由于 S[0] = a,在 S 中出现的离他最近的 a 在下标为 3 的位置上,距离为 3 - 0 = 3。因此应当输出 3。
接下来,如果
QUERY 4
S[4] = b,S 中离它最近的 b 出现在下标为 1 处,距离为 4 - 1 = 3。同样应当输出 3。
给定初始字符串 S 和若干操作,对于每个 QUERY,你需要求出相应的距离。
HINT 由于输入数据较大,C/C++中推荐使用 scanf 进行读入以获得更快的读入速度。同时请注意算法复杂度。

输入格式

输入的第一行是一个正整数 T(T≤20),表示测试数据的组数。
每组输入数据的第一行是一个初始串 S。第二行是一个正整数
m(1≤m≤100000),表示总共操作的数量。接下来 m 行,每行表示一个操作。操作的格式如上所述。
数据保证在任何情况下,S 的长度不会超过 100000。

输出格式

对于每个 QUERY,输出所求的最小距离。如果 S 中其它位置都不存在和它相同的字符,输出-1。

输入样例

2
axb
3
INSERT a
QUERY 0
QUERY 1
explore
3
INSERT r
QUERY 7
QUERY 1

输出样例

3
-1
2
-1

思路

这道题抽象一下变成,有一个字符数组

a[i] = [a,c,c,e,p,t,e,p]

对于每一个a[i]如何求出a[j]使得a[i] = a[j]且 a[i] a[j]距离最近(左右连个方向)

暴力

每一次查找,从x往左循环遍历到起点找到第一个与a[x]相等的元素,下标为left,往右循环遍历到终点找到第一个与a[x]相等的元素,下标为right,根据left和right的情况输出

时间复杂度为0(n) n为字符串长度

题目已知n = 10e6 输入规模m = 10e6,最终的时间复杂度达到了O(n*m),达到了10e12,肯定超时
所以必须想办法优化查询到O(1)

空间换时间

lr[i][0]记录下标为i的元素的左边与它相同且距离最近的元素的距离
lr[i][1]记录下标为i的元素的左边与它相同且距离最近的元素的距离
pre[k]记录最近上一次出现k的下标

a[i] = [a,c,c,e,p,t,e,p]

假设插入e,此时上一次出现e的下标为3(pre['e'-'a'] = 3),这时候只需要更新e

C++

#include"iostream"
#include"cstring"

using namespace std;

const int N = 100005;
int T;

int lr[N][2],idx;
int cnt[26],pre[26];


void insert(char x){
    int k = x - 'a';
    cnt[k]++;
    if(cnt[k] >= 2){
        lr[pre[k]][1] = lr[idx][0] =  idx - pre[k];
    }
    pre[k] = idx;
    idx++;
}

int query(int x){
    
    int l = lr[x][0];
    int r = lr[x][1];
    if(l == 0 && r == 0){
        return -1;
    }else if(l != 0 && r != 0){
        return min(l,r);
    }else{
        return max(l,r);
    }
}

void init_lr(string s){
    for(int i = 0; i < s.size(); i++){
        insert(s[i]);
    }
}
int main(){
    cin >> T;
    while(T--){
        memset(lr,0,sizeof lr);
        memset(cnt,0,sizeof cnt);
        memset(pre,-1,sizeof pre);
        idx = 0;
        string s;
        cin >> s;
        init_lr(s);
        
        int n;
        cin >> n;
        while(n--){
            string op;
            cin >> op;
            if(op == "INSERT"){
                char x;
                cin >> x;
                insert(x);
            }else{
                int x;
                cin >> x;
                cout << query(x) << endl;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值