力扣-3-无重复字符的最长字串


做之前看题目的印象是“动态规划”,因为好像和以前做的“最大子数和”看起来有点像

查看标签有“滑动窗口”,这个见过听过,但是不知道具体是什么,但是有印象,计网里的拥塞控制也用到了“滑动窗口”的概念

感觉题目降低难度了,只是要求返回长度不是要求返回子串

有了计网“滑动窗口”的概念,我想是需要两个指针来表示窗口的,头指针表示窗口起始,尾指针表示窗口末尾。另外拿一个变量来记录窗口长度

感觉难点在于:

  1. 如何高效地判重
    我想起了刚刚做的题,用set,如果把字串中的字符放到set中,然后用count函数来判断

那么,试试吧

    int lengthOfLongestSubstring(string s) {
        set st;
        int begin = 0,ret =0;
        for(int end = begin;end

第一版,三个示例通过了就迫不及待地提交,结果空字符就报错了
检查一遍健壮性

随手编了一个测试用例,发现一个问题:刷新窗口后set没清空

但还是不对,这是为什么?
问题应该出在最后遍历完成后没有再记录窗口长度,也就是说如果最长无重复子串在数组最后的情况
分析一下,遍历结束后,end指针应该在数组末尾,begin指针还在窗口开头
我把end改成类变量

有一个很复杂的问题,每次出现了重复字符不是把头指针与尾指针置通,而是头指针指向被重复字符的位置去,那我改map,刷新begin到被重复元素的后一个位置,然后这样又有了新问题,容器不能简单得清空了

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ret = 0;
        if(s==""){
            return ret;
        }
        map mp;
        int begin = 0,end;
        for(end = begin;end

这一版,能把目前的四个用例全部跑过

通过!??不过效率奇低

理一下思路

个人思路

初始窗口指针begin、end均为0,end始终向前走,begin不定时刷新,两个指针中间为“窗口”,即“目前无重复的最大字串”

1.end指针遍历字符串,

  • 若map中没有该字符(即当前窗口中字符无重复),将遇到的字符插入map作为键,字符的索引作为值
  • 若map中已有该字符,这时候就需要更新窗口(1. 将begin更新为被重复的元素的后一索引 2. 将原bgin到新begin之间的元素从map中删除)
  1. 为了保证数组遍历完时不会丢失最新的数组长度,于是每一步遍历都更新了结果的值

接下来考虑怎么优化算法的时间和空间效率

优化

首先,end指针的一次遍历过程是没法优化的,这是必须的

我想到了优化更新begin的过程
这样,当我遇到相同的了,就从begin(到end)开始遍历,如果指向的字符不等于现在的重复的字符,就踢掉,那么就可以又回到set

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ret = 0;
        if(s==""){
            return ret;
        }
        set st;
        int begin = 0,end;
        for(end = begin;end

好像…时间提高了一点,空间没变化

继续优化,两个思路

  1. 不用STL容器能否实现?
    我之所以会用容器,主要还是为了保存和判相同,但判相同不是能用位运算?但是保存地数据结构就不好解决了,或者要不,干脆不解决,不用额外的空间呢
    ……好像不太行,遍历只会导致效率更低
  2. map能否更巧妙地实现?
    map的优点是能保存值和索引位置
    我扫描字符串,键没有,就把键(字符)值(索引)放进去,键有了,就把返回值更新为字符长度。
    不不不,思路有问题

看题解了看题解了

官方题解

C++中字符数组名和字符串变量名

这一插一段,因为写的时候遇到了s==nullptr报错的情况,那么说明C++中字符串不是指针?不像是字符数组的数组名?
另外s==NULL也报错,那么它也不是对象?
我用了s=="",但究竟是怎么回事呢?

后记

哈哈哈,我还是很开心,毕竟是自己写出来的中等题(好吧,我看了标签提示)