第一题:
给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?
输出需要删除的字符个数。
输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出描述:
对于每组数据,输出一个整数,代表最少需要删除的字符个数。
输入例子1:
abcda google
输出例子1:
2 2
题解:
开始的想法是模拟,用一个栈存下字符所有的出现次数,过程看代码注释。当然结果是错误。
后面看的牛客题解是求原字符串和翻转字符串最大公共子序列(不是子串,可以不连续),只要保证字符相对顺序不变就行(因为可以删字符)。
然后所求答案就是字符长度减去最大公共子序列长度。
//未AC模拟代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define maxn 235
using namespace std;
int main() {
string str;
while( cin >> str ) {
int maxlen = -1, delnum = 0;
for( int i = 0, len = str.length(); i < len; i ++ ) {
stack<int> vis[maxn];
for( int j = 0; j < len; j ++ ) { //存下字符每次出现的位置
vis[int(str[j])].push(j);
}
int cnt[maxn] = {0}, num = 0, maxtmp = 0, end_j = 1e9, pre;
map<int,int> mp;
for( int j = i; j < len; j ++ ) {
cnt[int(str[j])] ++; //记录当前字符已经出现了多少次
// cout << j << " maxtmp: " << maxtmp << " end_j: " << end_j << " pre: " << mp[end_j] << endl;
if( j >= end_j ) { //遍历到边界时判断匹配字符个数
if( mp[end_j] == j-1 ) { //判断中间能不能再夹个数
if( maxtmp < 2*num ) {
maxtmp = 2*num;
}
} else {
if( maxtmp < 2*num+1 ) {
maxtmp = 2*num+1;
}
}
end_j = pre;
num --;
}
// cout << "---" << j << "---" << endl;
if( vis[int(str[j])].size() > cnt[int(str[j])] && vis[int(str[j])].top() < end_j ) { //找到对应字符最后面出现的位置,然后pop出栈,记录下来此位置作为边界
num ++; //匹配的个数
pre = end_j; //记录上次的边界,方便回滚
end_j = vis[int(str[j])].top();
mp[end_j] = j;
// cout << end_j << " " << j << endl;
vis[int(str[j])].pop();
}
}
// cout << i << ": " << maxtmp << endl;
if( maxtmp == 0 ) {
maxtmp = 1;
}
if( maxlen < maxtmp ) {
maxlen = maxtmp;
delnum = len-maxlen;
}
}
cout << delnum << endl;
}
return 0;
}
//最大公共子序列AC代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#define maxn 1010
using namespace std;
int sameList[maxn][maxn];
int maxLen( string str1, string str2 ) {
int len1 = str1.length(), len2 = str2.length();
for( int i = 0; i < len1; i ++ ) {
sameList[i][0] = 0;
}
for( int i = 0; i < len2; i ++ ) {
sameList[0][i] = 0;
}
for( int i = 1; i <= len1; i ++ ) {
for( int j = 1; j <= len2; j ++ ) {
if( str1[i-1] == str2[j-1] ) {
sameList[i][j] = sameList[i-1][j-1] + 1;
} else {
sameList[i][j] = max(sameList[i-1][j],sameList[i][j-1]);
}
}
}
return sameList[len1][len2];
}
int main() {
string str1;
while( cin >> str1 ) {
int len = str1.length();
if( len == 1 ) {
cout << 1 << endl;
continue;
}
string str2 = str1;
reverse(str2.begin(),str2.end());
cout << len - maxLen(str1,str2) << endl;
}
return 0;
}
第二题:
小Q最近遇到了一个难题:把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,且不能申请额外的空间。
你能帮帮小Q吗?
输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出描述:
对于每组数据,输出移位后的字符串。
输入例子1:
AkleBiCeilD
输出例子1:
kleieilABCD
题解:
每次遇到大写字母,遍历找寻后面的第一个小写字母,然后将其插入到大写字母的前面。插入过程使用遍历交换。
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define maxn 1010
using namespace std;
int main() {
string str;
while( cin >> str ) {
for( int i = 0, len = str.length(); i < len; i ++ ) {
if( str[i] >= 'A' && str[i] <= 'Z' ) {
for( int j = i+1; j < len; j ++ ) {
if( str[j] >= 'a' && str[j] <= 'z' ) {
swap(str[i],str[j]);
for( int k = i+1; k < j; k ++ ) {
swap(str[k],str[j]);
}
break;
}
}
}
}
cout << str << endl;
}
return 0;
}
第三题:
小Q今天在上厕所时想到了这个问题:有n个数,两两组成二元组,相差最小的有多少对呢?相差最大呢?
输入描述:
输入包含多组测试数据。
对于每组测试数据:
N - 本组测试数据有n个数
a1,a2...an - 需要计算的数据
保证:
1<=N<=100000,0<=ai<=INT_MAX.
输出描述:
对于每组数据,输出两个数,第一个数表示差最小的对数,第二个数表示差最大的对数。
输入例子1:
6 45 12 45 32 5 6
输出例子1:
1 2
题解:
差最大是最大数和最小数的差。差最大的对数就是最大数的个数乘以最小数的个数,注意最大数和最小数相同的情况,此时结果为从所有数里取二个数的组合问题。
差最小是排序后相邻两个数差的最小值。差最小的对数是所有相邻差值是差最小值的对数。注意差最小值为0的情况,此时差最小是从所有相同数里取两个数的组合问题。
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define maxn 100010
using namespace std;
int main() {
int n, a[maxn];
while( cin >> n ) {
map<int,int> mp; //map存相同数的个数,方便统计
for( int i = 0; i < n; i ++ ) {
cin >> a[i];
mp[a[i]] ++;
}
if( n == 1 ) {
cout << "0 0" << endl;
continue;
}
sort(a,a+n);
int minm = 1e9;
for( int i = 1; i < n; i ++ ) {
if( (a[i]-a[i-1]) < minm ) {
minm = a[i]-a[i-1];
}
}
int cnt1 = 0, cnt2 = 1, cnt3 = 0, flag = 1;
if( a[0] == a[n-1] ) {
flag = 0;
}
for( int i = 1; i < n; i ++ ) {
if( (a[i]-a[i-1]) == minm && mp[a[i-1]] != -1 ) {
if( minm == 0 ) {
cnt1 += (mp[a[i]]*(mp[a[i]]-1))/2;
} else {
cnt1 += mp[a[i]]*mp[a[i-1]];
}
mp[a[i-1]] = -1;
}
if( a[i] == a[0] ) {
cnt2 ++;
}
if( a[i] == a[n-1] && flag ) {
cnt3 ++;
}
}
if( flag ) {
cout << cnt1 << " " << cnt2*cnt3 << endl;
} else {
cout << cnt1 << " " << (cnt2*(cnt2-1))/2 << endl;
}
}
return 0;
}