LeetCode-316-mid-去除重複數字(單調棧)
技術標籤:algorithmleetcode資料結構演算法leetcode
關鍵字:“單調棧”
文章目錄
題目描述
給你一個字串 s
,請你去除字串中重複的字母,使得每個字母只出現一次。需保證 返回結果的字典序最小(要求不能打亂其他字元的相對位置)
分析
題目要求:
- 去重且每個字母出現一次:則返回結果的長度固定
- 返回結果的排列保持原有相對位置
- 返回結果的字典序最小
設s中每個字母出現次數為
[
c
a
,
c
b
,
.
.
.
,
c
z
]
[c_a, c_b,..., c_z]
解題思路
條件2和儘量字典序的條件3:-> 單調棧(有相對位置+一定順序)
目前還沒有理清之間的關係。單調棧的性質和與這道題的聯絡。
目標是條件3:儘量把字典序小的字元(‘a’,‘b’,‘c’,…,‘z’)排在前邊。所以可以儘量按照字典序升序的單調棧來排列。如果遇到原打算刪除的字元在剩餘字串中不存在,則保留該字元。
設已有字串pre,當前字元c,剩餘字串post。
如果c沒有出現在pre中,則將c放入pre中(並將pre中最鄰近結尾且大於c的在post中仍然存在的字元刪除)// 這裡是c字元所在位置要儘可能放在滿足其字典序的位置,操作後所能形成的字典序更小。要求可刪除的字元要在post字串中出現,這樣才能在剩餘字串中將該刪除的字元附在最終形成的字串的末尾。
如果c已經出現在pre中,則檢視下一字元。(如果將pre中的c去掉,則使得字典序變大)
演算法
INPUT: s
OUTPUT: ans
INIT:
visit[26], count[26]
for c in s :
count[c-'a'] ++
//迴圈不變數:visit, count, stack
stack
for c in s :
// 現有stack中沒有c
if visit[c] == false :
while !stack.empty() && stack.top() > c && count[stack.top()-'a'] > 0 )
visit[ stack.top() ] = false
stack.pop()
stack.push( c )
visit[c-'a'] = true
count[c-'a'] --
ans = string(stack)
return ans
資料結構
記錄訪問資訊:陣列、vector
模擬單調棧:string、stack
複雜度分析
空間複雜度 O ( n ) O(n) O(n)
時間複雜度 O ( n ) O(n) O(n),不考慮stack.pop()
程式碼實現
class Solution {
public:
string removeDuplicateLetters(string s) {
vector<int> visit(26), count(26) ;
for ( char c : s ){
++ count[c-'a'] ;
}
string stk = "" ;
for ( char c : s ){
if ( visit[c-'a'] == 0 ){
while ( !stk.empty() && stk.back() > c && count[stk.back()-'a'] > 0 ){
visit[ stk.back()-'a' ] = 0 ;
stk.pop_back() ;
}
stk.push_back( c ) ;
visit[c-'a'] = 1 ;
}
-- count[c-'a'] ;
}
return stk ;
}
};
- 使用vector或陣列來儲存對字元資訊的訪問,時間複雜度更低
- 單調棧訪問中,每個元素至少入棧一次
相關問題
PS.
-
相比較於其他已有的leetcode刷題筆記,我希望能夠提供相關的解題分析和部分相關問題的連結,使得大家能獲得一個較好的分析與相關問題的比較。
-
偶爾會進行類似題目的總結工作,有需要的讀者可以對這份工作進行關注。
-
如果你發現有相關的錯誤或者表述不當不清晰的地方,請進行評論,我會盡快進行核對勘正。