【Java】 剑指offer(48) 最长不含重复字符的子字符串

本文参考自《剑指offer》一书,代码采用Java语言。html

更多:《剑指Offer》Java实现合集  java

题目 

  请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含从'a'到'z'的字符。数组

思路

  动态规划法:定义函数f(i)为:以第i个字符为结尾的不含重复字符的子字符串的最大长度。函数

  (1)当第i个字符以前未出现过,则有:f(i)=f(i-1)+1post

  (2)当第i个字符以前出现过,记该字符与上次出现的位置距离为d测试

    1)若是d<=f(i-1),则有f(i)=d;url

    2)若是d>f(i-1),则有f(i)=f(i-1)+1;htm

  咱们从第一个字符开始遍历,定义两个int变量preLength和curLength来分别表明f(i-1)和f(i),再建立一个长度为26的pos数组来存放26个字母上次出现的位置,便可根据上述说明进行求解。blog

  注意:每次最大长度和字母出现位置要记得更新。字符串

  另外一种思路:遍历每一个字符,把当前字符当作子字符串的末尾结点,同时更新开头结点,详细代码见Longest Substring Without Repeating Characters

测试算例 

  1.功能测试(一个或者多个字符,所有字符不一样/相同)

  2.特殊测试(null,空字符串)

Java代码

//题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子
//字符串的长度。假设字符串中只包含从'a'到'z'的字符。

public class LongestSubstringWithoutDup {
	public static int  maxLength(String str) {
		if(str==null || str.length()<=0)
			return 0;
		int preLength=0;  //即f(i-1)
		int curLength=0;  //即f(i)
		int maxLength=0;
		int[] pos= new int[26];  //用于存放字母上次出现的位置
		for(int i=0;i<pos.length;i++)
			pos[i]=-1;
		for(int i=0;i<str.length();i++) {
			int letterNumber = str.charAt(i)-'a';
			if(pos[letterNumber]<0 || i-pos[letterNumber]>preLength) {
				curLength=preLength+1;
			}else {
				curLength=i-pos[letterNumber];
			}
			pos[letterNumber]=i;
			if(curLength>maxLength)
				maxLength=curLength;			
			preLength=curLength;
		}
		return maxLength;
	}
	
	public static void main(String[] args) {
		System.out.println(maxLength("arabcacfr")==4);
		System.out.println(maxLength("a")==1);
		System.out.println(maxLength("aaa")==1);
		System.out.println(maxLength("abcdef")==6);
		System.out.println(maxLength("")==0);
		System.out.println(maxLength(null)==0);
	}
}

  

收获

  1.函数f(i)为:以第i个字符为结尾的不含重复字符的子字符串的最大长度。而不是以第i个字符做为开头。第i个字符做为结尾能够方便与下一个字符进行联系。

  2.学会用长度为26的数组来存放26个字母所在的位置下标。

 

更多:《剑指Offer》Java实现合集 

相关文章
相关标签/搜索