找出并计算给定字符串中最长的不重复的子字符串,假设字符串只包含'a~z'字符,如:'arabcacfr'中 最长不重复子字符串是'acfr',长度为4。
暴力法:枚举所有子串,判断其是否是无重复串,找出最大长度返回。
//枚举出所有子串,若子串为无重复子串 则将长度最长的返回
public static boolean isUnique(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;
}
public static int longestSubstring(String s) {
int ans = 0;
for(int i = 0; i < s.length(); i++) {
for(int j = i+1; j <= s.length(); j++) {
if(isUnique(s,i,j)) {
ans = Math.max(ans, j-i);
}
}
}
return ans;
}
public static void main(String[] args) {
String str = "arabcacfr";
System.out.println(LongestSubstringWithoutDupilication(str));
System.out.println(longestSubstring(str));
}
思路:动态规划算法来降低复杂度,以i为结尾的不重复子字符串的最长长度为f(i), 从左往右遍历字符串的每个字符。当要计算f(i)时,已经得到f(i-1)。每次遍历一个字符,若字符未曾出现,则f(i)=f(i-1)+1,若已经出现,则需要借助一个存放每个字符在字符串中的位置的数组,当i位置的字符已经在前字符串中出现,则从该辅助数组中找到它最近一次出现的位置,i与该位置的距离为d,若d<=f(i-1),则f(i)=d。若d>f(i-1),说明这个字符出现在f(i-1)对应的字符串之前,所以f(i)=f(i-1)+1。
code:
public class NoReaptSubString {
public static int LongestSubstringWithoutDupilication(String s){
char[] chas = s.toCharArray();
int[] arr = new int[26];
int curLength = 0;
int maxLength = 0;
for(int i = 0; i < arr.length; i++) {//arr数组每个位置存放每个字符上次出现在字符串中位置的下标,初始全为-1
arr[i] = -1;
}
for(int i = 0; i < chas.length; i++) {
int pre = arr[chas[i]-'a'];
if(pre < 0 || i - pre > curLength) {//若字符从未出现过,或者当前字符与上一次出现的字符的位置差大于当前不重复字串长度,则当前长度加一
curLength++;
}else {
if(maxLength < curLength) {
maxLength = curLength;
}
curLength = i - pre; //若字符已出现过,位置差小于当前子串长度,则当前长度就为位置差
}
arr[chas[i]-'a'] = i;
}
if(maxLength < curLength) {
maxLength = curLength;
}
return maxLength;
}
public static void main(String[] args) {
String str = "arabcacfr";
System.out.println(LongestSubstringWithoutDupilication(str));
}
}