無重複字符最長子串----------------滑動窗口法

1.問題:給出一個字符串,找出其中無重複字符最長子串

  abcbc  最長無重複子串是abc  長度是3

 

2.方法一,暴力法

  我們可以找出每一個子串,然後找到最長的無重複字符的子串就可了,方法簡單粗暴。

  代碼如下:

  

 1 #include<stdio.h>
 2 #include<string.h> 
 3 //判斷有沒有重複字符
 4 int isRepeat(char*str,int start,int end)
 5 {
 6     int i;
 7     for(i=start;i<end;i++)
 8     {
 9         if(str[i]==str[end])
10             return i;//如果找到重複的字符,返回該字符的索引 
11     }
12     return -1;//否則返回-1,表示沒有重複字符 
13 }
14 
15 void findMaxSubString(char * str)
16 {    
17     int i,j;
18     int n,m;//記錄最長子串開始和結束的下標 
19     int max=0;//記錄無重複字符子串最大長度 
20     int num=0;//當前無重複字符子串的長度 
21     int len=strlen(str);//求出字符串長度
22     //開始列舉每一個子串 
23     for(i=0;i<len;i++)
24     {
25         for(j=i+1;j<len;j++)
26         {    
27             //判斷從i開始到j之間有沒有重複字符 
28             if(isRepeat(str,i,j)!=-1)
29             {    
30                 //如果有重複的字符 
31                 num=j-i;//記錄當前的子串長度 
32                 if(num>max)
33                 {
34                     max=num;//記最大長度 
35                     n=i;//開始的下標 
36                     m=j-1;//結束的下標,因爲第j個字符與前面有重複了 
37                 } 
38                 
39                 break;//有重複字符,結束本次循環 
40             }
41         }
42     }
43     //輸出長度和該字符串 
44     for(i=n;i<=m;i++)
45         printf("%c",str[i]);
46     printf("\nthe max len is %d ",max);
47 }
48 
49 int main()
50 {
51     char * str="abcdefghacbcnnmjklabak";
52     findMaxSubString(str);
53     return 0;
54 } 

算法分析,要遍歷每一個子串,時間複雜度O(n^2),判斷每一個子串是否有重複,時間複雜度O(n),

所以整個時間複雜度O(n^3),這個複雜度是很高的,所以暴力法不合適。

3.方法二,滑動窗口

  滑動窗口是一個在字符串處理中常用的方法,簡單而言窗口就是一個自己維護的序列。對於字符串str而言,我們已經知道從

  開始到 j  之間的字符串是沒有重複字符的,那麼從 i就是一個窗口。下一步,我們要判斷下一個字符 j+1 是否在窗口裏重複了,如果沒有重複

  那麼 j 滑動  j++  i 保持不變。如果重複了 i 滑動到重複字符的位置下一個位置,j 繼續向前滑動 j++。這樣當 j 走完就可以得到最長無重複子串。

  這方法其實就是利用之前已知的信息進行判斷,因爲我們已知之前的子串有沒有重複,在哪個位置重複了。

  代碼如下:

  

 1 #include<stdio.h>
 2 #include<string.h> 
 3 //判斷子串有麼有重複字符 
 4 int isRepeat(char*str,int start,int end)
 5 {
 6     int i;
 7     for(i=start;i<end;i++)
 8     {
 9         if(str[i]==str[end])
10             return i;//如果找到重複的字符,返回該字符的索引 
11     }
12     return -1;//否則返回-1,表示沒有重複字符 
13 }
14 
15 void findMaxSubString(char *str)
16 {
17     int len=strlen(str);//得到字符串長度 
18     int max=0;//記錄最大無重複子串長度 
19     int flag=0;// 
20     int i=0,j=1;
21     int num=1;//當前無重複子串長度 
22     int n,m;//記錄最大無重複子串的開始,結束下標
23     // 
24     while(j<len)
25     {
26         flag=isRepeat(str,i,j);
27         if(flag==-1)//flag爲-1沒有重複字符 
28         {
29             j++;//j向前滑動 
30             num++;//當前無重複子串長度加一 
31         }
32         //有重複字符                            
33         else
34         {    
35             //如果當前長度大於最大長度 
36             if(num>max)
37             {    
38                 //記錄下標 
39                 n=i;
40                 m=j-1;
41                 max=num;
42             
43             }
44             //i從有重複字符的下一個位置開始 
45             i=flag+1;
46             j++;//j繼續向前滑動 
47             num=j-i;//當前無重複子串長度 
48             
49         }
50     }
51     //輸出長度和該子串 
52     for(i=n;i<=m;i++)
53         printf("%c",str[i]);
54     printf("\nthe max len is %d ",max);
55 } 
56 int main()
57 {
58     char * str="abcdefghacbcnnmjklabak";
59     findMaxSubString(str);
60     return 0;
61 } 

算法分析,滑動窗口是一遍過的,時間複雜度爲O(n),加上判斷子串是否有重複的時間複雜度O(n),所以

時間複雜度是O(n^2)。但其實很多時候判斷子串是否有重複字符,不是用我上面的方法,而是用哈希表,或者集合,時間複雜度是O(1)

因此該方法的時間複雜度是線性的,實質爲O(n)比暴力法好很多。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章