动态规划-最长不含重复字符的子字符串

题目描述

输入一个字符串(只包含 a~z 的字符),求其最长不含重复字符的子字符串的长度。例如对于 arabcacfr,最长不含重复字符的子字符串为 acfr,长度为 4。

Solution

使用数组记录a~z字符上一次出现的位置preI,当字符上一次出现在当前子串时,curI-preI为截去重复字符的子串长度。

public int longestSubStringWithoutDuplication(String str) {
	int curLen = 0;
	int maxLen = 0;
	int[] preIndex = new int[26];
	Arrays.fill(preIndex, -1);
	for (int curI = 0; i < str.length(); curI++) {
    	int c = str.charAt(curI) - 'a';
    	int preI = preIndex[c];
    	if (preI == -1 || curI - preI > curLen) { //字符未出现或字符上一次出现位置不在当前不重复子串内
        	curLen++; //子串长加1
        } else {
        	maxLen = Math.max(maxLen, curLen);
        	curLen = curI - preI;
        }
        preIndex[c] = curI;
    }
    maxLen = Math.max(maxLen, curLen);
    return maxLen;
}

时间换空间,使用一个变量保存上一个字符结尾的最长不重复子串长度。
dp[i]遍历以dp[i-1]结尾的最长子串每个位置,看当前字符是否包含在子串中,
如果包含 dp[i]=i - 上一个包含的字符的位置。如果不包含,dp[i]=dp[i-1]+1 。

public int longestSubStringWithoutDuplication(String str) {
	int maxLen = 1;
	int pre = 1; //上一位字符结尾的最长子串长
	for (int curI = 1; curI < str.length(); curI++) {
		int startI = curI - pre; //子串起始位置
		int i;
		for (int i = curI - 1; i >= startI; i--) {
			if (str.charAt(curI) == str.charAt(i)) {  
				break;
			}
		}
		pre = curI - i; //当前字符结尾的最长不重复子串长
		maxLen = Math.max(maxLen, pre);
	}
	return maxLen;
}

你可能感兴趣的:(剑指)