彩色宝石项链
题目描述:
有一条彩色宝石项链,是由很多种不同的宝石组成的,包括红宝石,蓝宝石,钻石,翡翠,珍珠等。有一天国王把项链赏赐给了一个学者,并跟他说,你可以带走这条项链,但是王后很喜欢红宝石,蓝宝石,紫水晶,翡翠和钻石这五种,我要你从项链中截取连续的一小段还给我,这一段中必须包含所有的这五种宝石,剩下的部分你可以带走。如果无法找到则一个也无法带走。请帮助学者找出如何切分项链才能够拿到最多的宝石。
输入描述:
我们用每种字符代表一种宝石,A表示红宝石,B表示蓝宝石,C代表紫水晶,D代表翡翠,E代表钻石,F代表玉石,G代表玻璃等等,我们用一个全部为大写字母的字符序列表示项链的宝石序列,注意项链是首尾相接的。每行代表一种情况。
输出描述:
输出学者能够拿到的最多的宝石数量。每行一个
示例
输入: ABCYDYE 输出: 1
输入: ATTMBQECPD 输出: 3
思路分析:穷举暴力法,利用两个指针,将项链进行切割,两个指针中需要包含ABCDE这五种宝石,项链总长度减去这段序列即未能获得的最大宝石数。
实例1的算法思路图解
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main() {
string inputStr;
while (cin >> inputStr) {
int strLength = inputStr.size();
int maxGet = 0;//能取得的最大宝石数
//输入的宝石顺序的第一个开始寻找一段序列,并且逐渐移动指针
for (int beginPtr = 0; beginPtr < strLength; ++beginPtr) {
int flags[5] = { 0 };//由于标记五种宝石是否找到
int endPtr = beginPtr;//尾指针,
int cnt = 0;//选中的宝石序列中宝石个数
int sumFlag = 0;//序列中已经找到的特殊宝石总数
while (sumFlag < 5 && cnt < strLength) {
//序列中已找到的特殊宝石总数小于5,且序列中的宝石数小于宝石总数
if (endPtr < strLength) {
//**因为初始宝石链是环状**,所以尾指针可能移到头指针的前面
if (inputStr[endPtr] >= 'A' && inputStr[endPtr] <= 'E' && flags[inputStr[endPtr] - 'A'] == 0) {
//如果尾指针指向的宝石(即将添加的宝石)是特殊宝石,且该宝石之前没有遇到
flags[inputStr[endPtr] - 'A'] = 1;//标记已找到
++sumFlag;//找到的特殊宝石总数自增
}
++cnt;//不管有没有找到,宝石序列都增加了一个长度
++endPtr;//尾指针后移
}
else {
//如果尾指针移动了头指针的前面,将序号对strLength求余即可
if (inputStr[endPtr % strLength] >= 'A' && inputStr[endPtr % strLength] <= 'E' && flags[inputStr[endPtr % strLength] - 'A'] == 0) {
//如果尾指针指向的宝石(即将添加的宝石)是特殊宝石,且该宝石之前没有遇到
flags[inputStr[endPtr % strLength] - 'A'] = 1;//标记已找到
++sumFlag;//找到的特殊宝石总数自增
}
++cnt;//不管有没有找到,宝石序列都增加了一个长度
++endPtr;//尾指针后移
}
}
if (maxGet < strLength - cnt) {
//如果上一次寻找能获得的最大宝石数小于此次获得的,则更新
maxGet = strLength - cnt;
}
}
//输出结果
cout << maxGet << endl;
}
return 0;
}
上面的代码通过了牛客的测试。
恭喜你通过本题
运行时间:4ms
占用内存:480k
对算法进行优化:注意到,上面的代码每次头指针向后移动后都是直接放入中间截出的序列中,并没有对头指针指向的宝石种类进行判断。不难发现,如果头指针指向的宝石不是特殊宝石,那么将头指针指向的宝石从中间截出的序列段中移去,操作后的截出序列任然满足条件,从而达到了缩减序列长度的效果,继而减少了寻找次数。优化思路,增加对头指针指向的宝石类型进行判断的功能。
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main() {
string inputStr;
while (cin >> inputStr) {
int strLength = inputStr.size();
int maxGet = 0;//能取得的最大宝石数
//输入的宝石顺序的第一个开始寻找一段序列,并且逐渐移动指针
for (int beginPtr = 0; beginPtr < strLength; ++beginPtr) {
if (inputStr[beginPtr] >= 'A' && inputStr[beginPtr] <= 'E') {
//如果头指针指向的宝石类型是特殊类型才进行寻找操作
int flags[5] = { 0 };//由于标记五种宝石是否找到
int endPtr = beginPtr;//尾指针,
int cnt = 0;//选中的宝石序列中宝石个数
int sumFlag = 0;//序列中已经找到的特殊宝石总数
while (sumFlag < 5 && cnt < strLength) {
//序列中已找到的特殊宝石总数小于5,且序列中的宝石数小于宝石总数
if (endPtr < strLength) {
//因为初始宝石链是链状,所以尾指针可能移到头指针的前面
if (inputStr[endPtr] >= 'A' && inputStr[endPtr] <= 'E' && flags[inputStr[endPtr] - 'A'] == 0) {
//如果尾指针指向的宝石(即将添加的宝石)是特殊宝石,且该宝石之前没有遇到
flags[inputStr[endPtr] - 'A'] = 1;//标记已找到
++sumFlag;//找到的特殊宝石总数自增
}
++cnt;//不管有没有找到,宝石序列都增加了一个长度
++endPtr;//尾指针后移
}
else {
//如果尾指针移动了头指针的前面,将序号对strLength求余即可
if (inputStr[endPtr % strLength] >= 'A' && inputStr[endPtr % strLength] <= 'E' && flags[inputStr[endPtr % strLength] - 'A'] == 0) {
//如果尾指针指向的宝石(即将添加的宝石)是特殊宝石,且该宝石之前没有遇到
flags[inputStr[endPtr % strLength] - 'A'] = 1;//标记已找到
++sumFlag;//找到的特殊宝石总数自增
}
++cnt;//不管有没有找到,宝石序列都增加了一个长度
++endPtr;//尾指针后移
}
}
if (maxGet < strLength - cnt) {
//如果上一次寻找能获得的最大宝石数小于此次获得的,则更新
maxGet = strLength - cnt;
}
}
}
cout << maxGet << endl;
}
return 0;
}
恭喜你通过本题
运行时间:3ms
占用内存:457k
代码简化思路:不难发现,中间的while循环中,对endPtr讨论分成了两种情况,但显得有点多余,可以进行合并。因为小于strLength的数模上strLength后对本身没有影响。
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main() {
string inputStr;
while (cin >> inputStr) {
int strLength = inputStr.size();
int maxGet = 0;//能取得的最大宝石数
//输入的宝石顺序的第一个开始寻找一段序列,并且逐渐移动指针
for (int beginPtr = 0; beginPtr < strLength; ++beginPtr) {
if (inputStr[beginPtr] >= 'A' && inputStr[beginPtr] <= 'E') {
//如果头指针指向的宝石类型是特殊类型才进行寻找操作
int flags[5] = { 0 };//由于标记五种宝石是否找到
int endPtr = beginPtr;//尾指针,
int cnt = 0;//选中的宝石序列中宝石个数
int sumFlag = 0;//序列中已经找到的特殊宝石总数
while (sumFlag < 5 && cnt < strLength) {
//序列中已找到的特殊宝石总数小于5,且序列中的宝石数小于宝石总数
if (inputStr[endPtr % strLength] >= 'A' && inputStr[endPtr % strLength] <= 'E' && flags[inputStr[endPtr % strLength] - 'A'] == 0) {
//如果尾指针指向的宝石(即将添加的宝石)是特殊宝石,且该宝石之前没有遇到
flags[inputStr[endPtr % strLength] - 'A'] = 1;//标记已找到
++sumFlag;//找到的特殊宝石总数自增
}
++cnt;//不管有没有找到,宝石序列都增加了一个长度
++endPtr;//尾指针后移
}
if (maxGet < strLength - cnt) {
//如果上一次寻找能获得的最大宝石数小于此次获得的,则更新
maxGet = strLength - cnt;
}
}
}
//输出结果
cout << maxGet << endl;
}
return 0;
}
如果代码有错误,或者有更好的思路,欢迎指正或指导。
小男子不才,前排大佬让一让。