1. 程式人生 > >每日一題之 hiho229周 Same Letters In A Row

每日一題之 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;
}