3. Longest Substring Without Repeating Characters

题目

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

Example 1:

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

我的思路

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s == null || s.length() == 0) return 0;
        if(s.length() == 1) return 1;
        int left = 0, right = 0, max = 0;
        boolean[] used = new boolean[128];
        while(right < s.length()){
            if(used[s.charAt(right)] == true){
                used[s.charAt(left)] = false;
                while(left < right){
                    used[s.charAt(right)] = false;
                    right--;
                }
                right++;
                left++;
            }
            if(used[s.charAt(right)] == false){
                used[s.charAt(right)] = true;
                right++;
            }
            max = Math.max(max,(right - left));
        }
        return max;
    }
}

2019.11.10 update:
首先想到的就是sliding window

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s == null || s.length() == 0) {
            return 0;
        }
        int left = 0;
        int right = 0;
        int max = 0;
        HashSet<Character> set = new HashSet<>();
        while(right < s.length()) {
            if(!set.contains(s.charAt(right))) {
                set.add(s.charAt(right));
                right++;
                if(right - left > max) {
                    max = right - left;
                }
            } else {
                set.remove(s.charAt(left));
                //注意在这里只移左边!
                left++;
            }
        }
        return max;
    }
}

解答

leetcode solution 1
时间复杂度:O(n),最坏情况O(2n)
空间复杂度:O(min(size of charset, n))

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        Set<Character> set = new HashSet<>();
        int ans = 0, i = 0, j = 0;
        while (i < n && j < n) {
            // try to extend the range [i, j]
            if (!set.contains(s.charAt(j))){
                set.add(s.charAt(j++));
                ans = Math.max(ans, j - i);
            }
            else {
                set.remove(s.charAt(i++));
            }
        }
        return ans;
    }
}

数组版sliding window解法

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s == null || s.length() == 0) return 0;
        if(s.length() == 1) return 1;
        int left = 0, right = 0, max = 0;
        boolean[] used = new boolean[128];
        while(right < s.length()){
            if(used[s.charAt(right)] == true){
                used[s.charAt(left)] = false;
                left++;
            }
            else{
                used[s.charAt(right)] = true;
                right++;
                max = Math.max(max,(right - left));
            }         
        }
        return max;
    }
}

leetcode solution 2
Instead of using a set to tell if a character exists or not, we could define a mapping of the characters to its index. Then we can skip the characters (直接把 i 跳到重复的地方)immediately when we found a repeated character.

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        Map<Character, Integer> map = new HashMap<>(); // current index of character
        // try to extend the range [i, j]
        for (int j = 0, i = 0; j < n; j++) {
            if (map.containsKey(s.charAt(j))) {
                i = Math.max(map.get(s.charAt(j)), i);
            }
            ans = Math.max(ans, j - i + 1);
            map.put(s.charAt(j), j + 1);
        }
        return ans;
    }
}
总结
  1. 在不知道string大小的情况下用map比较保险,如果已知string比较小,可以直接使用数组

int[26] for Letters ‘a’ - ‘z’ or ‘A’ - ‘Z’
int[128] for ASCII
int[256] for Extended ASCII

  1. solution 1的sliding window感觉很聪明。如果遇到了重复的右指针可以一直不动而只移动左指针,直到左指针指向重复元素并删除,再重新开始新一轮的搜索。
  2. solution 2用 j-i 的值来表示长度。当 j 遇到重复的元素时,i 直接跳到重复的元素那。省去了存储每一个元素的访问情况,而通过索引的相对位置来记录。厉害!

2019.3.27创建:完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值