每日一題之 hiho229周 Same Letters In A Row
描述
Litter Ho has a string of lowercase letters. He wants to re-order the letters so that the same letters are placed together in a row.
Unfortunately he can do at most K times of swaps. Each time he can only swap two letters. What is the maximum number of the consective same letters?
Assume the string is “bababbaa” and K = 1. By 1 swapping Little Ho can get “aabbbbaa”. “bbbb” has length 4 which is also the maximum number of the consective same letters Little Ho can get.
輸入
The fist line contains an integer K. (1 <= K <= 100000)
The second line contain a string of lowercase letters. The length is no more than 100000.
輸出
Output the answer.
樣例輸入
1
bababbaa
樣例輸出
4
題意:
給一個字串,然後給定一個k,表示最多可以交換兩個字元k次,問經過上述操作之後最大連續的字元長度是多少?
思路:
假設輸入的字串是s。
如果對於一個區間[i, j],可以通過不超過K次交換使得s[i]…s[j]都變成相同字元,我們就稱區間[i, j]是可行的;否則稱之為不可行的。
我們先考慮這樣一個問題:對於給定區間[i, j],如何判斷這個區間是否是可行的?
要解決上面的問題,我們可以逐次判斷:
區間[i, j]是否可以變成全a? 區間[i, j]是否可以變成全b?… 區間[i, j]是否可以變成全z?
而對於一個確定的小寫字元ch,區間[i, j]可以變成全ch的充分必要條件是:
(1)整個字串s包含至少j-i+1個ch字元
(2)[i, j]區間中的非ch字元不超過K個
於是我們只要知道(1)這個字串中’a’-‘z’的數目,我們用tot[]儲存;以及(2)s[i] … s[j]中’a’-'z’的數目,我們用cnt[]儲存。即可在O(26)=O(1)的複雜度判斷[i, j]是否可行。
其中tot[]陣列可以通過O(|s|)的預處理求出。
此外,我們知道區間的可行性具有某種單調性,即:
(1)如果[i, j]是不可行的,那麼[i, j+1], [i, j+2], … 都是不可行的
(2)如果[i, j]是可行的,那麼[i, j-1], [i, j-2], … 都是可行的
所以我們可以用雙指標(滑動視窗)的思路去列舉極大可行區間。這樣總共列舉O(|s|)數量的區間,並且當區間改變(從[i, j1]變為[i+1, j2])時,cnt[]陣列的變化是均攤O(1)完成的。
總的時間複雜度是O(|s|)的。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int tot[30];
int cnt[30];
string s;
bool judge(int i, int j, int k) {
for (int ch = 0; ch < 26; ++ch) {
int tmp = j-i+1;
int num = 0;
if (tot[ch] >= tmp) {
for (int ii = i; ii <= j; ++ii) {
if (s[ii]-'a' != ch ) ++num;
}
if (num <= k) return true;
}
}
return false;
}
void solve(int n) {
int len = s.length();
memset(tot, 0, sizeof(tot));
memset(cnt, 0, sizeof(cnt));
for (int i = 0; i < len; ++i) {
tot[s[i]-'a']++;
cnt[s[i]-'a']++;
}
int res = 0;
int i = 0;
int j = 1;
while(i < len && j < len) {
if (judge(i, j, n)) {
res = max(j-i+1, res);
++j;
}
else {
++i;
}
}
cout << res << endl;
}
int main() {
int k;
cin >> k >> s;
solve(k);
return 0;
}