一、題目描述
Given a string, find the length of the longest substring without repeating characters.
給定一個字符串,找出不含有重複字符的最長子串的長度。
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:
Input: "pwwkew"
Output: 3
Explanation: 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.
二、解題思路
一眼看出,皆是暴力。用暴力法,可以很簡單的解決,但是時間複雜度就比較高一點。我是選擇用Java中的HashMap,進行二重循環,對第一層循環,每進行一次i++,就新建一個HashMap內存空間,爲了防止第i個字符所用的map中的值對第i+1個字符的map造成影響。再第二層循環中,進行的操作是判斷HashMap中是否有這個字符,如果有就跳出第二層循環,沒有的話就將該字符添加到Map中,然後將map的大小和最長字符的個數進行比較,大則賦值。
第二種方法,時間複雜度爲O(2n),定義二個int變量,一個用來控制字符串的字符位置,一個用來代表存放在HashSet中的字符位置,如果HashSet中沒有這個字符,就加入進去,如果有,就刪除HashSet下標i所指向的字符,並i++.獲取最大的長度:設置一個初值maxnum = 0,只要HashSet的值比maxnum大就將其賦予maxnum,最後返回maxnum的值。
第三種方法,改進的滑動窗口算法。用HashMap方法,將字符和下標聯繫起來,設置二個變量,i和j.j用來標識當前字符的下標。i用來標識重複字符的下標的下一個字符的下標。用j-i+1用來獲取未重複字符串的長度。如果hashmap中有某個字符,然後就獲取再hashmap中這個字符的下標和i作比較,選取較大的一個。(因爲可能會出現abba的出現,到最後一個字符的時候,於a重複的字符下標是0,而且i已經有值爲2.如果不選擇較大的一個值,就會出現錯誤的結果4,反之出現的結果是2.將該字符加入到hashmap中。直到將字符遍歷完。
第四種方法,用數組存放。因爲字符代表着0-256對於所有的ASCII碼。用下標代表字符,該下標存放的值是該字符在字符串中的位置,假設有重複的字符,那麼存放的值就變成最新重複的字符的下標。只要獲取到最新重複字符的下標和此時遍歷字符串的所處位置,就可計算出未重複字符的長度,獲取到最大值即可。
三、代碼實現
package com.acm.Secondmonth;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class LetCode003 {
/**
* 返回:最長沒有重複字符的個數
* 先用暴力法
* 直接二重循環 對第一層循環的每一個值度找一下不重複字符串個數
* @param s
* @return
*/
public static int lengthOfLongestSubstring(String s) {
if(s == null) {
throw new RuntimeException("invaild input:S is null");
}
int max = 0;
for(int i=0 ; i<s.length() && s.length()-i>=max ; i++) {
Map<Character , Integer> result = new HashMap<>();
for(int j=i ; j<s.length() ; j++) {
if(result.containsKey(s.charAt(j))) {
break;
}else {
result.put(s.charAt(j), j);
}
if(result.size() > max) {
max = result.size();
}
}
}
return max;
}
/**
*
* @param s
* @return
* 時間複雜度 O(2n)
* 每發現一個重複的字符就將一開始的字符刪除 ,一直到將與其重複的字符和其前面的全部刪除
*/
public static int lengthOfLongestSubstring01(String s) {
if(s == null) {
throw new RuntimeException("invaild input:S is null");
}
Set<Character> result = new HashSet<>();
int i=0 , j=0 , maxNum = 0;
while(i < s.length() && j < s.length()) {
if(!result.contains(s.charAt(j))) {
result.add(s.charAt(j++));
if(result.size() > maxNum) {
maxNum = result.size();
}
}else {
result.remove(s.charAt(i++));
}
}
return maxNum;
}
public static int lengthOfLongestSubstring03(String s ) {
if(s == null) {
throw new RuntimeException("invaild input:S is null");
}
int maxNum = 0;
Map<Character, Integer> result = new HashMap<>();
int start = 0 ; int end = 0;
while(end < s.length()) {
if(result.containsKey(s.charAt(end))) {
start = Math.max(result.get(s.charAt(end))+1 , start);
}
result.put(s.charAt(end), end);
maxNum = Math.max(maxNum, end-start+1);
end++;
}
return maxNum;
}
public static int lengthOfLongestSubstring04(String s) {
if(s == null) {
throw new RuntimeException("invaild input:S is null");
}
int maxNum = 0;
int[] result =new int[256];
for(int i=0 , j=0 ; j<s.length() ; j++) {
i = Math.max(result[s.charAt(j)], i);
maxNum = Math.max(maxNum , j-i+1);
result[s.charAt(j)] = j+1;
}
return maxNum;
}
public static void main(String[] args) {
test01();
test02();
test03();
test04();
}
private static void test01() {
String test = "abcabcbb";
System.out.println(lengthOfLongestSubstring(test));
System.out.println(lengthOfLongestSubstring01(test));
System.out.println(lengthOfLongestSubstring03(test));
System.out.println(lengthOfLongestSubstring04(test));
}
private static void test02() {
String test = "abba";
System.out.println(lengthOfLongestSubstring(test));
System.out.println(lengthOfLongestSubstring01(test));
System.out.println(lengthOfLongestSubstring03(test));
System.out.println(lengthOfLongestSubstring04(test));
}
private static void test03() {
String test = "pwwkew";
System.out.println(lengthOfLongestSubstring(test));
System.out.println(lengthOfLongestSubstring01(test));
System.out.println(lengthOfLongestSubstring03(test));
System.out.println(lengthOfLongestSubstring04(test));
}
private static void test04() {
String test = " ";
System.out.println(lengthOfLongestSubstring(test));
System.out.println(lengthOfLongestSubstring01(test));
System.out.println(lengthOfLongestSubstring03(test));
System.out.println(lengthOfLongestSubstring04(test));
}
}