Problem
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.
Understanding
采用分治策略,對(duì)于給定的串,滿足題設(shè)的子串(substring)要么在前半段,要么在后半段,要么跨越前后兩段,取其中的最大值即可。
關(guān)鍵問(wèn)題是,如何求取跨越其中兩段的最長(zhǎng)子串。
求跨越兩段最長(zhǎng)子串的策略
對(duì)于一個(gè)串s的兩個(gè)部分:left, right
為了求跨越left,right的最長(zhǎng)滿足條件的子串, 首先left,right的相鄰邊界必須有字符并且不相同: left[-1], right[0], null 三者兩兩不相等。
其次,求解策略是,將令i指向left的尾部,j指向right的首部, 如果對(duì)于某一個(gè)狀態(tài)i,j 總是嘗試將現(xiàn)有的最長(zhǎng)串?dāng)U展到i-1,j+1的范圍顯然i-1,j+1所指向的字符如果已經(jīng)存在于當(dāng)前的最長(zhǎng)串中,則可以證明此時(shí)的指針已經(jīng)達(dá)到邊界。
循環(huán)不變式是:每次循環(huán)結(jié)束,i,j必然包括最長(zhǎng)的串,且i非遞增,j非遞減。所以在i,j的變化過(guò)程中所求得串長(zhǎng)度一定是非遞減的。
循環(huán)結(jié)束的條件是i,j停止變化,因而當(dāng)循環(huán)結(jié)束時(shí)能夠得到最長(zhǎng)的串。
Code(Java)
import java.util.*;
public class LongestNoRepeat{
public static void main(String[] args)
{
Scanner in=new Scanner(System.in);
//String s="qwekewre";
System.out.println("input \"-\" to terminate");
String s="-";
while(in.hasNextLine() && !((s=in.nextLine()).equals("-")))
{
int[] res=findMost(s,0,s.length()-1);
System.out.println("i,j,s[i...j]="+res[0]+","+res[1]+" : "+s.substring(res[0],res[1]+1));
}
}
//返回int[]{i,j} 分別記錄開始和結(jié)束下標(biāo),對(duì)于非空串,不會(huì)返回null
public static int[] findMost(String s,int i,int j)
{
if(j-i==0)
return new int[]{i,j};
int mid=(j+i)/2;
int[] s1=findMost(s,i,mid);
int[] s2=findMost(s,mid+1,j);
int x=mid,y=mid+1;
boolean xvalid=true,yvalid=true; //分別記錄左右指針是否還在變化
int[] s0=null;
if(s.charAt(x)!=s.charAt(y))
{
Set<Character> set=new HashSet<Character>();
set.add(s.charAt(x));
set.add(s.charAt(y));
while(xvalid || yvalid)
{
//循環(huán)不變式:每次循環(huán)開始時(shí), x,y必然指向當(dāng)前最長(zhǎng)的串
//每次循環(huán)結(jié)束時(shí), x非遞增變化, y非遞減變化
//且當(dāng)x,y都不變化時(shí),循環(huán)退出
if(xvalid)
{
Character ch=null;
if(x==i)xvalid=false;
else if(set.contains(ch=s.charAt(x-1)))
xvalid=false;
else
{
x--;
set.add(ch);
}
}
if(yvalid)
{
Character ch=null;
if(y==j)yvalid=false;
else if(set.contains(ch=s.charAt(y+1)))
yvalid=false;
else
{
y++;
set.add(ch);
}
}
}
s0=new int[]{x,y};
}
int[] max=s0;
if(max==null || max[1]-max[0]<s1[1]-s1[0])
max=s1;
if(max[1]-max[0] < s2[1]-s2[0])
max=s2;
return max;
}
}