求最长不重复子串

求最长不重复子串

今天逛了下LeetCode,做了一下OJ,发现题目很不错,并且解答里用Java语言描述算法描述的很巧妙,故整理如下。

题目描述

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

Examples:

Given “abcabcbb”, the answer is “abc”, which the length is 3.

Given “bbbbb”, the answer is “b”, with the length of 1.

Given “pwwkew”, 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.

求解思路

1.滑动窗口算法

A sliding window is an abstract concept commonly used in array/string problems. A window is a range of elements in the array/string which usually defined by the start and end indices, i.e. [i, j)[i,j) (left-closed, right-open). A sliding window is a window “slides” its two boundaries to the certain direction. For example, if we slide [i, j)[i,j) to the right by 11 element, then it becomes [i+1, j+1)[i+1,j+1) (left-closed, right-open).

滑动窗口,就理解为 [i,j] 的一个区间吧,并且窗口会一直向右移动,即 i 和 j 只会增加,不会减少。通常这个算法会用于数组、字符串问题。

Back to our problem. We use HashSet to store the characters in current window [i, j)[i,j) (j = ij=i initially). Then we slide the index jj to the right. If it is not in the HashSet, we slide jj further. Doing so until s[j] is already in the HashSet. At this point, we found the maximum size of substrings without duplicate characters start with index ii. If we do this for all ii, we get our answer.

对于这个问题,滑动窗口中的字符串,就是向右滑动的不重复的子串,在滑动的同时要把字符存在HashSet中,从而可以持续向右滑动窗口。

    /**
     * 滑动窗口算法
     * @param s
     * @return
     */
    public static int slidingWindow(String s) {
        int n = s.length();
        int result = 0, i = 0, j = 0;
        Set<Character> charSet = new HashSet<>();
        while (i < n && j < n) {
            if (charSet.contains(s.charAt(j))) {
                //left-close
                charSet.remove(s.charAt(i++));
            } else {
                //right-open
                charSet.add(s.charAt(j++));
                //迭代result
                result = Math.max(result, j - i);
            }
        }
        return result;
    }

2.最优化的滑动窗口

i的值不需要以i++的形式移动,可以使用HashMap将字符和所在位置做映射,快速滑动窗口。

    /**
     * 快速滑动窗口(缓存字符位置)
     * @param s
     * @return
     */
    public static int slidingWindowOptimized(String s) {
        int length = s.length();
        int result = 0, i = 0, j = 0;
        //char:nextIndex
        Map<Character, Integer> indexMap = new HashMap<>();
        //左边界根据indexMap获得
        for (i = 0, j = 0; j < length; j++) {
            if (indexMap.containsKey(s.charAt(j))) {
                //滑动左窗口,防止后退
                i = Math.max(i, indexMap.get(s.charAt(j)));
            }
            indexMap.put(s.charAt(j), j + 1);
            result = Math.max(result, j - i + 1);
        }
        return result;
    }

上面的算法就是著名的KMP算法,想起大学时看了半天并没有看懂…

猜你喜欢

转载自blog.csdn.net/qq_21508059/article/details/78735113