無重複字符的最長子串

給定一個字符串,請你找出其中不含有重複字符的最長子串的長度.html

示例 1:算法

輸入: "abcabcbb"
輸出: 3 
解釋: 由於無重複字符的最長子串是 "abc",因此其長度爲 3

示例2:數組

輸入: "bbbbb"
輸出: 1
解釋: 由於無重複字符的最長子串是 "b",因此其長度爲 1

示例3:函數

輸入: "pwwkew"
輸出: 3
解釋: 由於無重複字符的最長子串是 "wke",因此其長度爲 3。
     請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。

 

 解法一:暴力解決優化

思想:逐個檢查全部的子字符串,看它是否不含有重複的字符。spa

算法:若是咱們有一個函數allUnique(_ s: String, start: Int, end: Int) -> Bool若是子字符串的字符都是惟一的,它會返回true,不然會返回false。咱們遍歷給定字符串s的全部可能的子字符串並調用函數allUnique,若是事實證實返回值爲true,那麼咱們將會更新無重複子串的最大長度的答案。code

爲了枚舉給定字符串的全部子字符串,咱們須要枚舉它們開始和結束的索引。假設開始和結束的索引分別爲 i 和 jhtm

那麼咱們有0<=i<j<=n,咱們使用i從0到n-1及j從i+1到n這兩個嵌套的循環,枚舉出全部子字符串。blog

要檢查一個字符串是否有重複字符,可使用集合。咱們遍歷字符串中的全部字符,並將它們逐個放入set中,在放置一個字符以前,檢查改集合是否已經包含它,若是包含,咱們會返回false,循環結束後,咱們返回true。索引

let s: String = "abcabcbb"
func lengthOfLongestSubstring(_ s: String) -> Int {
    var results: Int = 0
    for i in 0..<s.count {
        for j in i+1..<s.count + 1 {
            if allUnique(s, start: i, end: j) {
               results =  max(results, j - i)//更新最長子字符長度
            }
        }
    }
    return results
}

func allUnique(_ s: String, start: Int, end: Int) -> Bool {
    var set: Set = Set<Character>()
    var characters = Array(s)//轉爲字符數組
    for i in start..<end {
        let ch: Character = characters[i]
        if set.contains(ch) {return false}
        set.insert(ch)
    }
    return true
}

let result = lengthOfLongestSubstring(s)
print(result)

 

解法二:滑動窗口法

暴力法很是簡單,但它太慢了。那麼咱們該如何優化它呢?

在暴力法中,咱們會反覆檢查一個子字符串是否含有有重複的字符,但這是沒有必要的。

要檢查一個字符是否已經在子字符串中,咱們能夠檢查整個子字符串,這將產生一個複雜度爲 O(n2) 的算法,但咱們能夠作得更好。

經過使用 HashSet 做爲滑動窗口,咱們能夠用 O(1)O(1) 的時間來完成對字符是否在當前的子字符串中的檢查。

let s: String = "abcabcbb"
func lengthOfLongestSubstring(_ s: String) -> Int {
    var set: Set = Set<Character>()
    var characters = Array(s)//轉爲字符數組
    var results: Int = 0
    var i: Int = 0
    var j: Int = 0
    while i < s.count && j < s.count {
        if !set.contains(characters[j]) {
            set.insert(characters[j])
            j += 1
            results = max(results, j - i)
        } else {
            set.remove(characters[i])
            i += 1
        }
    }
    return results
}

let result = lengthOfLongestSubstring(s)
print(result)

時間複雜度:O(2n)=O(n),在最糟糕的狀況下,每一個字符將被 i和 j 訪問兩次。

空間複雜度:O(min(m,n)),與以前的方法相同。滑動窗口法須要 O(k) 的空間,其中 k 表示 Set 的大小。而 Set 的大小取決於字符串 nn 的大小以及字符集 / 字母 mm 的大小。

 

以上就是兩種方式,你們要着重理解一下後一種方式!!!

相關文章
相關標籤/搜索