Longest Substring Without Repeating Characters

来源:互联网 发布:python爬虫视频百度云 编辑:程序博客网 时间:2024/05/22 12:38

Longest Substring Without Repeating Characters

问题

给定一个字符串,找出最长不重复字符的子串。例如,”abcabcbb”的最长子串是”abc”,长度是3。对于”bbbbb”的最长子串是”b”,长度是1。

解决方案

O(n) runtime, O(1) space – 两次遍历:
我们如何能立即查找一个字符是否在字符串中存在?答案是用一个最简单的表来存储出现过的字符。请和你的面试官确认字符串是否包含除了”a-z”以外的字符(例如:数字?大写字母?它是否只是包含ASCII字符?或者可能有unicode字符?)
接下来一个你需要问自己如果找出了重复字符应该怎么办?例如,如果字符串是”abcdcef”,当你遇见了第二个重复的c的时候应该怎么办?
当你发现一个重复的字符(假设当在j的位置发现的),这就表明当前的字符串(当然除了重复字符)可能是一个潜在的最长不重复子串,所以接下去更新最长的值。那也表示这个重复的字符在之前i的位置也出现过,当然i肯定小于j。
既然你已经知道所有在i或者i之前开始的子串都会小于当前的最大值,你可以安全地开始找从i+1位置开始的子串。
因此,你会需要两个标志位来记录当前子串的头和尾。既然i和j都最多遍历n步,最坏的可能性就是2n步,所以最终的时间复杂度就是O(n)。
注意空间复杂度是O(1),因为即便我们分配了一个数组,但是由于无论多长,这个数组的长度永远是256。

public int lengthOfLongestSubstring(String s) {    boolean[] exist = new boolean[256];    int i = 0, maxLen = 0;    // j从开始到结尾遍历    for (int j = 0; j < s.length(); j++) {        // 如果当前的字符已经存在,则设为不存在,然后增加i,直到发现不存在为止        while (exist[s.charAt(j)]) {            exist[s.charAt(i)] = false;            i++;        }        // 标记为当前字符存在        exist[s.charAt(j)] = true;        // 设当前最长值为当前或者最长值        maxLen = Math.max(j - i + 1, maxLen);    }    return maxLen;}

如果字符集不仅仅是ascii,而且也包含unicode字符呢?我们可以修改以上方案,用一个Set来代替一个简单的256个元素的boolean数组。
O(n) runtime, O(1) space – 一次遍历:
以上的方案要求最多2n步。其实,我们可以优化成只需要n步。与其用一个table来判断一个字符是否存在,我们可以定义一个字符以及它的位置的mapping。然后我们可以在找到重复字符后,马上跳过字符。

public int lengthOfLongestSubstring(String s) {    // 定义一个256个字符的数组    int[] charMap = new int[256];    // 将charMap中所有的值默认设为-1    Arrays.fill(charMap, -1);    int i = 0, maxLen = 0;    // 从头开始遍历s    for (int j = 0; j < s.length(); j++) {        // 如果当前字符的值>=i,也就是说当前字符在i之前的位置出现过        if (charMap[s.charAt(j)] >= i) {            // 则从当前字符的位置的后面1位再开始算起            i = charMap[s.charAt(j)] + 1;        }        // 标注当前字符的出现位置        charMap[s.charAt(j)] = j;        // 得出当前j-i+1(当前长度),以及最大长度之前的最大值        maxLen = Math.max(j - i + 1, maxLen);    }    return maxLen;}
0 0
原创粉丝点击