1. 程式人生 > 其它 >面試之演算法基礎系列1.最多有k個不同字元的最長子字串

面試之演算法基礎系列1.最多有k個不同字元的最長子字串

技術標籤:面試集錦-屢敗屢戰面試演算法基礎最長子字串

文章目錄

1.最長子字串

題目原為:

【題目】
給定一個字串,給定一個數字k ( 0< k ≤ 字串長度),輸出最長的包含k個不同字元子串的長度。
【Example】
“cbca”, k=2,輸出最長的包含2個不同字元子串的長度。
答案:3
題目來源:百度 SRE工程師實習生 一面,可點選https://www.nowcoder.com/discuss/585284檢視一面涼經/(ㄒoㄒ)/~~

最容易想到的是暴力解法,就是遍歷求出字串的所有子串,並找出不同字元為k的最長字元,Python程式碼如下:

def find_max_substring
(string, k): str_length = len(string) sub_string_list = (string[i:i + j + 1] for j in range(str_length) for i in range(str_length - j)) length_list = [] for sub_string in sub_string_list: if len(set(list(sub_string))) == k: length_list.append(len(sub_string)) return
max(length_list) if __name__ == '__main__': string = input() k = int(input()) max_length = find_max_substring(string, k) print(max_length)

顯然,這種實現方式效率是很低的,雖然使用了生成器,但是在效能方面還是有很大的問題,同時未考慮特殊情況。
後來查詢了一些資料,使用了同向雙指標和字典來對實現方式進行了優化:

def find_max_substring(string, k):
    str_length = len
(string) if str_length == 0 or k == 0: return 0 count = 0 left = 0 right = 0 res = 0 count_dic = {} while right < str_length: if string[right] not in count_dic or count_dic[string[right]] == 0: count += 1 count_dic[string[right]] = 1 else: count_dic[string[right]] += 1 right += 1 while count > k: count_dic[string[left]] -= 1 if count_dic[string[left]] == 0: count -= 1 left += 1 res = max(res, right - left) return res if __name__ == '__main__': string = input() k = int(input()) max_length = find_max_substring(string, k) print(max_length)

在字串長度為0或者k為0時直接返回0;
通過使用同向雙指標的方式,可以做到只遍歷一次字串就能得到答案,從而使時間複雜度為O(n),在字串上移動滑動視窗的兩個指標,來保證視窗內的字元不超過k個,具體如下:

  • 設定指標left、right初始位置均為0,初始化計數陣列;
  • 當right小於字串長度時,每次判斷字元s[right]是否位於計數陣列中,不在則計數count加1,同時對字典進行更新,並使right指標向右移動;
    • 在字元數超過k時,需要移去視窗中最左側的字元string[left],同時向右移動left指標使得滑動視窗只包含k個不同字元;
    • 更新最大長度res = max(res, right - left)

此時執行結果如下:
test result 2
可以看到,執行效率還是相對較快的。
可以在https://www.lintcode.com/problem/longest-substring-with-at-most-k-distinct-characters/description使用IDE進行執行測試和效能評估。