題意
給你一個長爲N N N 的數組A A A ,返回A A A 中滿足條件的子串個數
條件是:子串中恰好有K K K 個不同的元素
數據範圍:N ≤ 20000 N \le 20000 N ≤ 2 0 0 0 0
思路
這種子串的問題一般是用two pointer或者DP來解決,這個題比較有意思的是兩種思路都要用到
先根據DP的想法,我們考慮子問題,設前i i i 個元素這樣的子串有F ( i ) F(i) F ( i ) 個,必須以i i i 結尾的子串有f ( i ) f(i) f ( i ) 個
這樣有一個很簡單的結論:F ( i ) = F ( i − 1 ) + f ( i ) F(i) = F(i-1) + f(i) F ( i ) = F ( i − 1 ) + f ( i )
那麼我們的問題的關鍵就是用f ( i − 1 ) f(i-1) f ( i − 1 ) 的知識幫助我們求出f ( i ) f(i) f ( i ) 了,很顯然這兩個部分關聯性非常強,舉個例子比如A ( i ) = A ( i − 1 ) A(i) = A(i-1) A ( i ) = A ( i − 1 ) 的情況,那麼有f ( i ) = f ( i − 1 ) f(i) = f(i-1) f ( i ) = f ( i − 1 )
這裏我們需要一些其它的輔助信息了,首先是兩個指針p 1 ( i ) p_1(i) p 1 ( i ) 和p 2 ( i ) p_2(i) p 2 ( i ) ,我們讓他們表示以i i i 結尾的可行子串的第一個和最後一個開頭位置的索引,不難發現,如果存在以i i i 結尾的可行子串,那麼所有的i i i 結尾可行子串的開頭位置應該都在p 1 ( i ) p_1(i) p 1 ( i ) 和p 2 ( i ) p_2(i) p 2 ( i ) 之間,而且它們之間的位置作爲頭也都是可行的,即f ( i ) = p 2 ( i ) − p 1 ( i ) + 1 f(i) = p_2(i) - p_1(i) + 1 f ( i ) = p 2 ( i ) − p 1 ( i ) + 1
另外,我們還需要記錄一下映射map<int, int>
記爲m i m_i m i ,他記錄以i i i 結尾的子串裏,包含的數值,以及數值對應出現的位置,要求這個位置是在i i i 之前該數值最後一次出現的位置
那麼我們接下來就是用p 1 ( i ) p_1(i) p 1 ( i ) ,p 2 ( i ) p_2(i) p 2 ( i ) 和m i m_i m i 來更新p 1 ( i + 1 ) p_1(i+1) p 1 ( i + 1 ) ,p 2 ( i + 1 ) p_2(i+1) p 2 ( i + 1 ) 和m i + 1 m_{i+1} m i + 1
加入A ( i + 1 ) A(i+1) A ( i + 1 ) 出現在了m i m_i m i 中,那麼其實p 1 ( i ) p_1(i) p 1 ( i ) ,p 2 ( i ) p_2(i) p 2 ( i ) 之間的位置做開頭一定都可行,只是如果p 2 ( i ) = A ( i + 1 ) p_2(i) = A(i+1) p 2 ( i ) = A ( i + 1 ) 時,我們會有更多可行解;我們首先更新m ( A ( i + 1 ) ) = i + 1 m(A(i+1)) = i+1 m ( A ( i + 1 ) ) = i + 1 並賦值給m i + 1 m_{i+1} m i + 1 ,需要通過遍歷更新p 2 p_2 p 2 ,我們找到第一個位置j j j ,保證A ( j ) = = m i + 1 ( A ( j ) ) A(j) == m_{i+1}(A(j)) A ( j ) = = m i + 1 ( A ( j ) ) ,領p 2 ( i + 1 ) = j p_2(i+1)=j p 2 ( i + 1 ) = j
如果A ( i + 1 ) A(i+1) A ( i + 1 ) 未出現在m i m_i m i 中,那麼p 1 ( i ) p_1(i) p 1 ( i ) ,p 2 ( i ) p_2(i) p 2 ( i ) 之間的位置做開頭就會多一個元素,不難發現這個元素就是A ( p 2 ( i ) ) A(p_2(i)) A ( p 2 ( i ) ) ,因此我們令p 1 ( i + 1 ) = p 2 ( i ) + 1 p_1(i+1) = p_2(i) + 1 p 1 ( i + 1 ) = p 2 ( i ) + 1 ,p 1 ( i + 1 ) p_1(i+1) p 1 ( i + 1 ) 的更新則和上一個條件分支基本一樣,然後更新m i m_i m i 即可
我們可以發現p 1 p_1 p 1 和p 2 p_2 p 2 的更新都是單調遞增的,因此每個位置至多被遍歷一次,所以總體複雜度是O ( N ) O(N) O ( N ) 的
class Solution {
public:
int subarraysWithKDistinct ( vector< int > & A, int K) {
unordered_map< int , int > mapp;
int pre = 0 , suf = 0 , now = 0 ;
int ans = 0 ;
for ( ; now < A. size ( ) ; now++ ) {
mapp[ A[ now] ] = now;
if ( mapp. size ( ) == K) {
break ;
}
}
for ( int i = now; i < A. size ( ) ; i++ ) {
if ( mapp. find ( A[ i] ) != mapp. end ( ) ) {
mapp[ A[ i] ] = i;
while ( mapp[ A[ suf] ] != suf) {
suf++ ;
}
}
else {
mapp. erase ( A[ suf++ ] ) ;
mapp[ A[ i] ] = i;
pre = suf;
while ( mapp[ A[ suf] ] != suf) {
suf++ ;
}
}
ans + = suf - pre + 1 ;
}
return ans;
}
} ;