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()
posted @ 2020-08-19 16:23  _starsky  阅读(291)  评论(0编辑  收藏  举报