Longest Substring Without Repeating Characters

要求

找出字符串中,最长的没有重复元素的子串,返回它的长度。

示例

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.

求是求非手法

求是,就是判断是不是符合条件的,这种做法可以过滤掉不符合条件的,它是针锋相对的筛选,直接的思维,免去为数众多的边界条件和终止条件的判断,是以快刀斩乱麻的方式取得结果的手段。
求非,是求是的反面,如果你觉得一个东西是什么你拿捏不准,但是它不是什么你却非常清楚,就可以通过判断它不是什么来得到自己想要的结果。

划窗

这是个技巧。想象一下数组像一把尺子,上面套了一个游标,游标长短可调,除了游标内部的部分,尺子上其余的部分都不可见。这是一个解决字符串问题的思维模型,每次处理划窗内的部分,这一招对于处理字符串的子串尤其有效,可以使时间复杂度降为O(n)。

代码实现及用法

package com.company;

public class Main {

    public static void main(String[] args) {
    // write your code here
        String sourceString0 = "abcabcbb";
        String sourceString1 = "bbbbb";
        String sourceString2 = "pwwkew";
        String sourceString3 = "c";
        String sourceString4 = "aab";
        String sourceString5 = "dvdf";
        System.out.println(Solution.findLongestDistinctiveSubstring0(sourceString5));
    }
}

package com.company;

import java.util.*;

public class Solution {
    /**
     * 从前往后遍历,以每遍历到的元素为开始点
     * 再顺序遍历它后面的元素,只要没碰到重复的就继续。
     * 不断重复此过程,直到源数组被遍历完。
     * 它维持了一个哈希表,有没有重复是通过判断哈希表
     * 中的标志位来判断的。
     * 虽然这种算法能得到正确的结果,但是耗费时间太长。
     * 这种算法核心的思想还是双重遍历。
     * 但是经过测试这个算法超时了,我需要改进它。
     * @param sourceString
     * @return
     */
    static public int findLongestDistinctiveSubstring(String sourceString) {
        Map flagMap = new HashMap<>();
        int maxSubstringLength = 0;
        for (int counter = 0;counter < sourceString.length();counter++) {
            for (int counter1 = 0;counter1 < sourceString.length();counter1++)
                flagMap.put(sourceString.charAt(counter1),false);
            for (int counter0 = counter;counter0 < sourceString.length();counter0++) {
                if (!flagMap.get(sourceString.charAt(counter0))) {
                    flagMap.put(sourceString.charAt(counter0),true);
                    if (counter0 - counter + 1 > maxSubstringLength)
                        maxSubstringLength = counter0 - counter + 1;
                } else break;
            }
        }
        return maxSubstringLength;
    }

    /**
     * 这是对方法的改进以期把它的时间复杂度降到O(n)
     * 我的代码实现并没有很好地体现出我的想法,后来
     * 查了查资料原来这种想法名叫"划窗"思想。就好像
     * 尺上的游标,只不过这个游标是可以调节长短的。
     * 安装这个划窗以后,数组上面就是一片黑,除了这
     * 个划窗里面。
     * 所谓花窗思想是指用两个指针为边界对之间内容做
     * 逻辑处理的编程手法,这一招对于字符串的处理特别有效。
     * 更形象一点的话,整个过程有点像个毛毛虫在那蠕动一样。
     * 有的时候从这个形象上面也能联想到一些解决办法。
     * 再有就是哈希表,这个哈希表我还是不想用数组来
     * 实现,我直接用hashset。
     * 另外,要想让时间复杂度降下来就不能单独处理hash
     * 表中的值,必须在每次遍历的时候处理。
     * @param sourceString
     * @return
     */
    static public int findLongestDistinctiveSubstring0(String sourceString) {
        Set flagSet = new HashSet<>();
        int maxSubstringLength = 0;
        int startIndex = 0;
        int endIndex = 0;
        while (startIndex <= endIndex && endIndex < sourceString.length()) {
            if (!flagSet.contains(sourceString.charAt(endIndex))) {
                flagSet.add(sourceString.charAt(endIndex));
                if (endIndex - startIndex + 1 > maxSubstringLength)maxSubstringLength = endIndex - startIndex + 1;
                endIndex++;
            }
            else {
                //此时已经找到了和startindex一样的元素了,
                // endIndex指向了和startindex值相同的地
                // 方,换句话说找到了重复的元素。并且此间所
                // 有的元素都不是重复的。
                flagSet.remove(sourceString.charAt(startIndex));
                startIndex++;
            }
        }
        System.out.println("最长不重复子串为:" + sourceString.substring(startIndex,endIndex));
        return maxSubstringLength;
    }
}

输出

最长不重复子串为:vdf
3

你可能感兴趣的:(Longest Substring Without Repeating Characters)