LeetCode--No.3--Longest Substring Without Repeating Characters

Given a string, find the length of the longest substringwithout repeating characters.

Example 1:

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

Example 2:

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

Example 3:

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

 

 我的思路:
所有与数组相关题目的最好情况肯定是线性扫描, 而且我还需要维护一个中间结果,也就是一个子串,那我需要双指针, left和right.
那如果我想知道,下一个新的character是不是在之前的substring出现过,那我就要将之前的substring的内容存起来。
那怎么存?
Array, Set, Dict. 
Array肯定不行,那就会变成o(n*n).
Set的话,肯定不如Dict更优秀. 如果遇到 abcdefgc的情况, 当最后一个c出现之后,我想要从第一个c之后的d开始,所以我需要记录substring的index. 那就用Dict. key是character, value是index.

于是我写好了代码

    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0)   return 0;
        Map<Character, Integer> map = new HashMap<>();
        int left = 0, right = 0;
        int res = 0;
        while(right < s.length()){
            if (!map.containsKey(s.charAt(right))){
                map.put(s.charAt(right), right);
                right ++;
                res = Math.max(res, right - left);
            }
            else {
                left = map.get(s.charAt(right)) + 1;
                map.put(s.charAt(right), right);
                right++;
            }
        }
        return res;
    }

我的test case少覆盖了一种情况: 那就是 tmmzuxt. 
也就是说当我的双指针 left 和 right, right遇到了之前map里面存在的character, left直接移动到了和right一样的字母的下一个位置. 但是我忘记在map里面同样要删掉之前出现过的字母了。也就是说,当我遇到了第二个m的时候,我直接把left 设置成了第二个m的位置。但是此时,t依然在我的字典里,可是t不应该是我考虑的范畴。

solution: 1. 在字典里删掉index比m小的字母。但这就又需要扫整个字典,复杂度又会变回(n*n). 
2. 我并没有想起来,应该多思考一下。看了答案。毕竟我这个是字典,字典就是记录了index, 如果它比我想要的index小,那我不考虑不就是了嘛。

更新版的代码 (只在if条件语句里面加了一个判断):

public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0)   return 0;
        Map<Character, Integer> map = new HashMap<>();
        int left = 0, right = 0;
        int res = 0;
        while(right < s.length()){
            if (!map.containsKey(s.charAt(right)) || map.get(s.charAt(right)) < left){
                map.put(s.charAt(right), right);
                right ++;
                res = Math.max(res, right - left);
            }
            else {
                left = map.get(s.charAt(right)) + 1;
                map.put(s.charAt(right), right);
                right++;
            }
        }
        return res;
    }

solution的最优代码:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        Map<Character, Integer> map = new HashMap<>();
        int res = 0;
        for(int i = 0, j = 0; j < n; j++) {
            if (map.containsKey(s.charAt(j)))
                i = Math.max(map.get(s.charAt(j)), i);
            res = Math.max(res, j - i + 1);
            map.put(s.charAt(j), j + 1);
        }
        return res;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值