【LeetCode】3.无重复字符的最长子串(滑动窗口)

Given a string s, find the length of the longest substring without repeating characters.

Example 1:

Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.

Example 2:

Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.

Example 3:

Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.

Example 4:

Input: s = ""
Output: 0

Constraints:

  • 0 <= s.length <= 5 * 104
  • s consists of English letters, digits, symbols and spaces.

这道题很容易想到可以用滑动窗口的办法解决,代码如下:

// O(n^2)
int lengthOfLongestSubstring(string s) {
 
  if (s.size() <= 1) return s.size();

  int maxRange = 0;
  int left = 0, right;
  for (right = 1; right < s.size(); right++) {
    int equalIndex = -1;

    for (int i = right - 1; i >= left; i--) {
      if (s[right] == s[i]) {
        equalIndex = i;
        break;
      }
    }

    if (equalIndex != -1) {
      left = equalIndex + 1;
    }
    maxRange = max(maxRange, right - left + 1);

  }

  return maxRange;
}

对于 01 这种特殊情况,直接返回串的长度即可。

这里有一个优化可以省一点时间,那就是每次找到重复的字符时,事实上可以直接将 left 移动到 equalIndex 的下一位,之前的都可以不用管 (假设一步一步的移动,那么在下一次主循环中,马上又发现有重复的字符,且发生重复的位置不变,其实,最终的 left 一定是放在equalIndex + 1)。

这个解法虽然可以 AC,但每次查重复字符的时候还是有点耗时间的,那么能不能让查重快一点?

办法就是用空间换时间:

我们可以存一下字符最近一次出现的位置,代码如下:

int lengthOfLongestSubstring(string s) {
 
  if (s.size() <= 1) return s.size();

  vector<int> lastPosOfChar(128, -1);
  
  int maxRange = 0;
  int left = 0, right;
  for (right = 0; right < s.size(); right++) {
    int lasPosOfCur = lastPosOfChar[s[right]];
		
		// lasPosOfCur >= left,要保证不走回头路,因为下一个区间里的字符可能在之前的区间出现过
    if (lasPosOfCur != -1 && lasPosOfCur >= left) {
      left = lasPosOfCur + 1;
    }
    maxRange = max(maxRange, right - left + 1);
    lastPosOfChar[s[right]] = right;
  }

  return maxRange;
}

这样一来的话,每个字符都只用访问一遍,时间复杂度优化到了 O(n)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值