蓝桥杯2023年A组-试题D-平方差

0. 题目



1. 题解

1.1 基于中心扩展的字符串处理算法

思路

我们可以选定一个中心,然后从中心开始,向外扩展我们的子串,且能存储之前子串的部分性质(这里便于左等于右的情况)
0. 确定中心点
这里我们用外层一个大循环来表示,中心点即为变量i。

  1. 首先分为子串为奇数串和偶数串的情况
    奇数串的话比如像上图示例的我们选的是3作为中心, 但由于要求是连续子串,所以我们默认初始长度为3(长度为1的翻转也没有任何意义,不会改变大小)开始进行翻转。
    这里落实到程序中就是 L=i-1,R=i作为初始值,'L>=0&&R<str.length()'作为结束条件, L--,R++向外扩展。
    偶数串的话其实同理,见程序。

2.其次再考虑到何时可以翻转?
由于我们是由中心点向外扩展, 我们利用贪心的思想,从局部来看,何时能达到翻转后大小变小?

只要区域最左边的值大于最右边的值,结果就会变小。真的只有这样吗?
到了本题的一大难点:我们发现存在 2312 这种,虽然左值等于右值,但是翻转后 2132 > 2312的,就是说左等于右,还要再往里面看一层,就比较麻烦了,可能涉及到递归。

但是这就是我们为何使用从中心扩展的字符串处理,我们发现,只要我们在从中心向外扩展的过程中,加上一个flag标记,标记之前一个是否可以反转,就可以在下一次遇到左等于右的情况时,直接通过标记判断是否可以反转;

你问第一次就是左等于右? 由于为奇数串:121(怎么翻转都不会变), 偶数串:11(怎么翻都不会变) 我们设置flag初值为false(不可翻转)即可!

代码

#include<bits/stdc++.h>
using namespace std;
int ans = 0;
int main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	string str;
	cin >> str;
	for (int i = 0; i < str.length(); i++){
		// 子串个数为偶数
		bool flag = false;
		for (int L = i - 1, R = i; L >= 0 && R < str.length(); L--, R++){
			if(str[L] > str[R]) flag = true; // 左大于右,代表可以交换 
			if(str[L] < str[R]) flag = false; // 右大于左,代表不可以交换 
			if (flag) ans++; // 这里隐含了左等于右的情况,flag情况跟之前保持相同,所以无需写出 
		} 
		
		// 子串个数为奇数 
		flag = false;
		for (int L = i - 1, R = i + 1; L >= 0 && R < str.length(); L--, R++){
			if(str[L] > str[R]) flag = true;
			if(str[L] < str[R]) flag = false;
			if (flag) ans++;
		}
	} 
	cout << ans;
	return 0;
}
posted @   DawnTraveler  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示