3. 无重复字符的最长子串

题目

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例1

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例2

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例3

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

示 例 4 \color{red}{示例4} 4

"abba"

思路(滑动窗口)

  • 使用一个哈希表记录元素的索引。
  • start表示窗口的左边,end表示窗口的右边。保持窗口里的元素不重复。
  • 如果end在右移的时候,出现一个元素在哈希表中,说明它在之前出现过,如果这个重复的字符在窗口内,则将start移动到窗口内该重复的元素后一个位置。
  • 每次更新完窗口,计算窗口的长度。

代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> map;
        int start = 0, end = 0;
        int res = 0;

        while ( end < s.size() ) {
            if ( map.count( s[end] ) > 0 && map[s[end]] >= start ) {	// 如果end处的元素在窗口里重复,则将start的位置调整到第一个重复元素的后一个位置。
                start = map[s[end]] + 1;
            }

            map[s[end]] = end;		// 更新元素的索引
            int cur = end - start + 1;	// 计算当前窗口的长度,即无重复子序列的长度
            res = max( res, cur );	// 保存较大的长度

            ++end;
        }

        return res;
    }
};

用数组快一点

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        vector<int> ht( 128, -1 );

        int start = 0, end = 0;
        int res = 0;

        while ( end < s.size() ) {
            if ( ht[s[end]] != -1 && ht[s[end]] >= start )
                start = ht[s[end]] + 1;

            ht[s[end]] = end;
            int cur = end - start + 1;
            res = max( res, cur );

            ++end;
        }

        return res;
    }
};

另一种写法,数组不保存字符的坐标,而是保存字符是否出现过

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ht[128] = { 0 };
        int res = 0;

        int left = 0, right = 0;

        while ( right < s.size() ) {
            if ( ht[s[right]] == 0 ) {  // 如果字符没出现过
                ht[s[right]] = 1;       // 标记出现
                res = max( res, right - left + 1 ); // 计算最大值
            }
            else {                      // 出现过
                while ( s[left] != s[right] ) {     // 找到出现的位置
                    ht[s[left]] = 0;                // 移出滑动窗口的复位
                    ++left;
                }

                ++left;
            }

            ++right;
        }

        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值