面试题:求给定字符串中最长无重复子字符串的长度。

题干:

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.


 

解法一:

列出所有字符串,并判断是否有重复字符。(最直观的方法,但是运算量极大,不要用)

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int ans = 0;
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j <= n; j++)
                if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
        return ans;
    }

    public boolean allUnique(String s, int start, int end) {
        Set<Character> set = new HashSet<>();
        for (int i = start; i < end; i++) {
            Character ch = s.charAt(i);
            if (set.contains(ch)) return false;
            set.add(ch);
        }
        return true;
    }
}

解法二:

利用HashSet做划窗来判断字符唯一性。(用这个)

public class LengthOfLongestSubstring3 {
	/*
	 * 思路:
	 * 	用Set做一个范围为 [i,j)的划窗(利用Set检查char的唯一性)。
	 * 	在确定s[i,j-1]没有重复字符的情况下,只需检查s[j]是否存在于s[i,j-1]中就可以了。
	 * 	如果s[j]存在于s[i,j-1]中,那么划窗变为 [i+1,j),继续检查。
	 * 
	 **/
	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))) {
				// 此处是根据角标j来遍历,一个一个的往里存
				set.add(s.charAt(j++));
				ans = Math.max(ans, j - i);//注意这里为什么是j-1而不是j-i+1呢?因为j已经++了
			} else {
				set.remove(s.charAt(i++));
			}
		}
		return ans;
	}
}

思考:整个流程中,角标是如何变化的?以及while(i<n & j<n)配合i++和j++这种代码结构。


解法三:

利用HashMap建立{字符-索引}的映射,降低找重复时的时间复杂度(优解但是不太好想)

public class Solution {
	/*
	 * 思路: 使用HashMap存放{字符-索引}的映射,当我们发现重复的字符时,直接跳过这些字符。
	 * 通过遍历j来循环。如果遍历到j时,s[i,j)中有重复元素s[j],我们不再一点一点移动i的位置了,
	 * 若重复元素角标为j',直接跳过[i,j′]这个区间即可,直接将i赋值为j'+1。
	 * 
	 */
	public int lengthOfLongestSubstring(String s) {
		int n = s.length(), ans = 0;
		// Hashmap中存放的是 字符-索引
		Map<Character, Integer> map = new HashMap<>();
		// try to extend the range [i, j]
		for (int j = 0, i = 0; j < n; j++) {
			if (map.containsKey(s.charAt(j))) {
				// 如果map里已经有这个index[j]处的char,将i赋成j+1。
				i = Math.max(map.get(s.charAt(j)) + 1, i);
			}
			// 注意这里的max,适用于“abba”这种情况,“a”虽然存在于map中了,但i也不移动
			ans = Math.max(ans, j - i + 1);
			// 将char加入哈希表中,value为索引值j。
			map.put(s.charAt(j), j);
		}
		return ans;
	}
}

  思考:怎么用一次循环完成整个算法的?想清楚整个流程中两个索引i,j是怎么变化的。

      *注意max*

posted @ 2017-10-18 15:51  Kkky  阅读(4059)  评论(0编辑  收藏  举报