1. 程式人生 > 實用技巧 >Good String

Good String

Good String

題目連結:傳送門

題目大意:

給定我們一個字串,按照題目中描訴的那樣可以進行環形左移和右移,如果左移和右移之後的字串相等那麼說明這個字串是good的。**且這個字串只由0 - 9 組成 **, 問你需要從給定的字串中擦掉多少個字元使得,字串變為good

分析

通過觀察我們發現以下幾點資訊:

  • 字串的長度很長\(2 * 10^5\) 時間複雜度大概在\(O(n) / O(nlogn)\) 的樣子
  • 每個字元的由 0 ~ 9 構成
  • 如果滿足左移和右移都相等的字串那麼一定滿足\(t_1 = t_3 = ... =tn-1 , t_2 = t_4 = ... t_n\)

也就是說字串必須是以兩個不同的字串進行週期出現例如

25252525 即滿足上述條件,那麼我們只需要找到滿足這個條件的最長的子串即可,剩下的就是我們需要擦去的字串,這是時候我們發現每個字元僅由 0 ~ 9 構成,我們可以利用沒兩對數字在字串中出現的次數來統計這個規律的字串在子串中出現的最大的長度

時間複雜度為 \(O(100 * n)\)

關鍵程式碼

值得注意的是我們統計的 a == b的時候我們無論左移還是右移都不會影響結果

但是當a != b 的時候 如果我們得到的長度為奇數例:

252 這種情況實際符合的長度只有 2 ,我們需要對這種情況進行一下特判。

int find(string s , int a , int b)
{
	int ans = 0;
	for(int i = 0;i < s.size();i ++)
	{
		int x = s[i] - '0';
		if(x == a)
		{
			swap(a , b);
			ans++;
		}
	}
	if(a != b && ans % 2 == 1)ans--;
	return ans;
}

C++ 程式碼

int find(string s , int a , int b)
{
	int ans = 0;
	for(int i = 0;i < s.size();i ++)
	{
		int x = s[i] - '0';
		if(x == a)
		{
			swap(a , b);
			ans++;
		}
	}
	if(a != b && ans % 2 == 1)ans--;
	return ans;
}
void slove()
{
	string s;cin >> s;
	int ans = MAX;
	int n = s.size();
	for(int i = 0;i < 10;i ++)
	{
		for(int j = 0;j < 10 ;j ++)
		ans = min(ans , n - find(s , i , j));
	}
	cout << ans << endl;
}

python 程式碼

  • python中快速調換兩個數可以用 a , b = b , a
def find(s , a , b):
	ans = 0
	for c in s:
		if a == c:
			a , b = b , a
			ans += 1
	if a != b and ans % 2 == 1:
		ans -= 1
	return ans

def slove():
	s = input()
	ans = 0
	for i in range(0,10):
		for j in range(0,10):
			ans = max(ans , find(s , str(i) , str(j)))
	print(len(s) - ans)

def main():
	t = int(input())
	while t > 0:	
		slove()
		t-=1

if __name__ == '__main__':
	main()