最长无重复字符子串

题目

有奖征名
题目描述
MTK 内部每款芯片都会有一个名字,比如 Oppo R15 中采用的 AI 芯片 HelioP60。现在公司即将量产一块芯片,为此在内部举办了征名比赛,命名的规则要求简洁,请你找出员工提交的命名中不包含重复字符的最长子串作为最后的候选结果,如果存在多个符合条件的子串,则输出第一个符合条件的子串。 例如输入一个字符串为:helioP60isisGood ,该字符串中满足要求的子串为 helioP60。 因此输出该子串。

输入说明
通过命令行参数方式传入一个字符串,且只包含数字和字母(区分大小写)。

int main(int argc, char argv[])
{
char input = argv[1];
……
return 0;
}
输出说明
向标准输出打印要求的结果字符串

示例
输入

helioP60isisGood
输出

helioP60

思路

  1. 首先肯定是暴力,把每个子串都判断一下,这样的话这篇文章就没必要写了~
  2. 我们有复杂度为O(n)的算法,那就是滑动窗口。
  3. 假设 Sij S i j 表示从 i 到 j 已经访问过的字符,刚开始i=j=0,i 与 j 都是可以往后滑动的。当我们再遍历到 j+1 的时候,我们会在 Sij S i j 中寻找是否有这个字符,如果有,并假设其索引为 j’ ,我们将 i 滑至 j’+1,则此时 Sij S i j 内字符并不重复。中间记录一下状态即可。
  4. 而 i 怎么滑动到 j’+1,使用不同的数据结构会有不同的滑动方式。

代码

#include <iostream>
#include <string>
#include <set>
#include <map>

using namespace std;

// 滑动窗口,O(2n)
int main(int args, char** argc) {
    char* s = argc[1];
    //char* s = "helioP60isisGOOD";
    int len = strlen(s);

    set<char> set;
    int max = 0, left = 0, right = len - 1;
    int i = 0, j = 0;
    while (i < len && j < len) {
        if (set.find(s[j]) == set.end()) {
            set.insert(s[j]);
            if (max < j - i + 1) {
                left = i, right = j + 1;
                max = j - i + 1;
            }
            j++;
        }
        else {
            set.erase(s[i++]);
        }
    }

    cout << string(s).substr(left, max) << endl;
    system("pause");

    return 0;
}

用map存储的话,就可以直接让 i 跳至 j’+1,只需遍历一遍:

#include <iostream>
#include <string>
#include <set>
#include <map>

using namespace std;

// 优化的滑动窗口,O(n)
int main(int args, char** argc) {
    char* s = argc[1];
    //char* s = "s6ws";
    int len = strlen(s);

    map<char, int> map;
    int max = 0, left = 0, right = len - 1;
    int i = 0, j = 0;
    for (; j < len; j++) {
        if (map.find(s[j]) != map.end()) {
            i = map[s[j]] + 1;
        }
        if (max < j - i + 1) {
            left = i, right = j + 1;
            max = j - i + 1;
        }
        map[s[j]] = j;
    }

    cout << string(s).substr(left, max) << endl;
    system("pause");

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值