1. 程式人生 > >給定一個字串,找出不含有重複字元的最長子串的長度。

給定一個字串,找出不含有重複字元的最長子串的長度。

題目描述:

  給定一個字串,找出不含有重複字元的最長子串的長度。

思路1:

  依排列組合的所有可能拿到所有子串,依次傳入重複子穿的判斷方法中進行判斷,每次更新出不重複子串的最大長度!

具體程式碼:

 

 1 import java.util.Scanner;
 2 
 3 public class test{
 4     public static void main(String[] args) {
 5         Scanner sc = new Scanner(System.in);
 6         System.out.println("請輸入一列字串:");
7 String line = sc.nextLine(); 8 System.out.println("該字串的最長五重複子穿的長度是:" + test.lengthOfLongestSubstring(line)); 9 } 10 11 public static int lengthOfLongestSubstring(String s) { 12 StringBuffer sb = new StringBuffer(s); // 轉為StringBuffer呼叫更多的字串方法 13 int length = 0; //
無重複子串最大長度的表示 14 for (int i = 0; i < sb.length(); i++) { 15 for (int j = i + 2; j < sb.length() + 1; j++) { 16 if (!IsChongFu(sb.substring(i, j))) { // 按所有排列組合的可能截取出所有子串,傳入判斷函式 17 if (sb.substring(i, j).length() > length) { 18 length = sb.substring(i, j).length(); //
更新待返回的長度 19 } 20 } 21 } 22 } 23 return length; 24 } 25 26 private static boolean IsChongFu(String obj) {// 判斷子串是否重複 27 for (int k = 0; k < obj.length() - 1; k++) { 28 for (int l = k + 1; k < obj.length(); l++) { 29 if (obj.charAt(k) == obj.charAt(l)) { 30 return true; 31 } 32 } 33 } 34 return false; 35 } 36 37 }

 

一點思考:

  上述演算法的時間複雜度似乎不太理想,返回長度的方法以及判斷重複的方法都用到了兩層for迴圈,能否改進一下呢???

我是這樣想的:

  遍歷字串,用一個數據容器來依次接收遍歷到的每一個字元,當即將接收容器裡已經出現的字元時,用lengh儲存容器此時元素的實際個數,即長度,並刪除容器內重複位置及之前的所有元素;然後繼續接收字元,如果又遇到重複,執行上述操作,比較並更新出最大長度;直到字串遍歷結束,再次更新出最大長度。

  因此,我利用Set集合不儲存重複元素的特性,選用Set中存取一致的LingkedHashSet來當作演算法所需的容器。

具體程式碼:

 

 1 import java.util.LinkedHashSet;
 2 import java.util.Scanner;
 3 
 4 public class test再改進 {
 5 
 6     public static void main(String[] args) {
 7         System.out.println("請輸入一列字串:");
 8         Scanner sc = new Scanner(System.in);
 9         String line = sc.nextLine();
10         System.out.println("該字串的最大無重複子串的長度為:" + findLargestOfLine(line));
11     }
12 
13     private static int findLargestOfLine(String line) {
14         // 建立容器
15         LinkedHashSet<Character> set = new LinkedHashSet<>();
16         // 遍歷字串,並存入容器
17         int largest = 0;
18         for (int i = 0; i < line.length(); i++) {
19             if (!set.add(line.charAt(i))) { // 此操作先執行儲存,若成功儲存則不進行其餘操作:若不能儲存,則表示該元素是重複元素
20                 largest = set.size() > largest ? set.size() : largest;// 更新並記錄容器內的長度
21                 // 刪除重複位置及之前的元素
22 //                for (Character c : set) {
23 //                    if(c==line.charAt(i)) {
24 //                        set.remove(c);
25 //                        continue;
26 //                    }else    //標註的程式碼目的也是想實現刪除操作,但暴露出的問題是:Set集合中不能在遍歷的同時進行刪除操作,否則否丟擲異常
27 //                    set.remove(c);
28 //                }
29                 LinkedHashSet delSet = new LinkedHashSet<>();// 解決上述問題的辦法是將要刪除的元素存入集合,遍歷完成再刪除
30                 for (Character c : set) {
31                     delSet.add(c);
32                     if (c == line.charAt(i))
33                         break;
34                 }
35                 set.removeAll(delSet);// 先刪除
36                 set.add(line.charAt(i));// 再將遇到的重複元素新增到set中
37             }
38             // 每一次遍歷都實現了set中重複位置及之前的刪除,重複元素的新增,最大長度的更新
39         }
40         // 當字串遍歷完成,還要執行依次最大長度的更新
41         largest = set.size() > largest ? set.size() : largest;
42 
43         return largest;
44     }
45 
46 }

總結:

第一種思路及演算法很蠻力,for巢狀用得多,第二種思路及方法顯得就要輕鬆多了!!!

蠻力法主要包含:

  1.String轉StringBuffer後可使用的擷取功能(SubString());

  2.字串是否出現重複的判斷演算法

另一種方法主要包含:

  1.LingkedHashSet儲存無重複元素,且存取一致;

  2.Set集合不能邊遍歷邊刪除