leetcode 3. Longest Substring Without Repeating Characters (C/C++)

题目: leetcode 3. Longest Substring Without Repeating Characters.

对定字符串,如何找连续无重复字符的字串?


2021/4/9更新:
三个月后再来看这个…真是一言难尽。
本来很简单的问题为什么当初搞的这么复杂,又复杂又容易出错,要个啥动态规划噢,规划了个寂寞,当时我是怎么蜜汁自信觉得自己理解的很好…

直接用个双指针(sliding window)找最长substring就好了嘛,从0到strlen-1,往左往右找都行,找的过程用hash。
至于C中怎么利用数组搞一个hash,见文末的参考链接中C++解法二或者我新写的博客

参考链接中就是往左找,为什么往左呢,因为你每遍历一次同时可以记录每个字符最新出现的位置,记录这个就可以找max length。往右的话,每个循环里还得新建一个hash再遍历。
这个用sliding window好理解,left指向的是window左边的index,window位置是left+1~i。所以left一直往右移动,指向的是s[i]字符上一次出现的位置或者不动。left=max(left,myHash[s[i]]); 妙啊!


原标题: 动态规划+unordered_map (C++)

动态回归:
Let s[i] denotes the i th char in the string.
Let s[k: i] denotes the longest substring without repeating characters of s[0:i].
Let OPT(i) denotes the length of the longest substring without repeating characters.
Final result: res=max(res,OPT(i))

说人话:对于第i个字符,当前最大字串为s[k:i] (包括第i个字符),其长度为OPT(i),找出最大的OPT,即为结果。

if s[i] is not in s[k:i-1]:(k是i-1对应的)
OPT(i)=OPT(i-1)+1
else:
OPT(i)=当前字符到左边最近相同字符直接的距离
同时更新k

(题外话:实际上后文写代码中把k定义成了substring左边的index,i.e.substring为k+1到i的字符,是注意事项⚠️里的第三点)

所以,代码实现的关键在于怎么求“当前字符到左边最近相同字符直接的距离”。可以建立一个 HashMap,建立每个字符和其最后出现位置之间的映射。HashMap用unordered_map实现:unordered_map<char, int> myMap;

如此,判断条件也可通过HashMap得知:myMap[s[i]]<k则表示不再substr里。所以更新map应在得到OPT之后。

综上,每一次遍历i时都应该:

  1. 根据map做如上if,找到k,计算当前OPT(i),同时记录最大的OPT作为res。
  2. 更新map,记录当前字符出现的位置
#include <iostream>
#include <vector>
#include <stack>
#include<unordered_map>

using namespace std;

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int N=s.size();
        if (N==0)
            return 0;
        int res=0;
        int k=-1;//substring is from k+1 to i, including k+1 and i
        int opt=0;
        unordered_map<char, int> myMap;

        for (int i=0;i<N;++i){
            if (myMap.count(s[i]) && myMap[s[i]]>k){
                //in the substring
                k=myMap[s[i]];
                opt=i-k;
            }
            else
                opt+=1;
            res=max(res,opt);

            myMap[s[i]]=i;
        }
        return res;
    }
};

int main()
{
    Solution s;
    string test1="pwwkew";
    cout<<s.lengthOfLongestSubstring(test1)<<endl;
    string test2="abcabcbb";
    cout<<s.lengthOfLongestSubstring(test2)<<endl;
    string test3="a";
    cout<<s.lengthOfLongestSubstring(test3)<<endl;
    string test4="aa";
    cout<<s.lengthOfLongestSubstring(test4)<<endl;
    string test5="au";
    cout<<s.lengthOfLongestSubstring(test5)<<endl;

    return 0;
}


⚠️写码的时候遇到的问题:

  1. 使用myMap[s[i]]的时候,如果map中没有s[i]会自动添加{s[i],0},而我们的键值也有可能是0,所以会出现问题,解决方法就是加一个判断:myMap.count(s[i]),如果存在会返回1,不存在返回0,并且不会更改myMap。
  2. 出现“Reference to non-static member function must be called”报错的时候,检查是不是括号写错了!!为这个问题debug好久真的不值得!
  3. 遇到0/1、</<=的时候要注意,要跟判断里的内容结合。总之就写之前想好吧…

参考: https://www.cnblogs.com/grandyang/p/4480780.html.

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值