【Leetcode】3. Longest Substring Without Repeating Characters

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;

    }
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容