一、构造回文
给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?
输出需要删除的字符个数。
输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出描述:
对于每组数据,输出一个整数,代表最少需要删除的字符个数。
输入例子:
abcda
google
输出例子:
2
2
思路:
根据回文串的特点,如果一个字符串是回文串,那么这个字符串和它的逆序串是相等的。所以上述问题转化为求字符串和逆序字符串的最长公共子序列长度。
c++代码:
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
string s;
while(cin>>s){
string s1=s;
string s2=s;
reverse(s2.begin(),s2.end());
int len1=s1.length();
int len2=s2.length();
//动态申请一个二维数组
//因为题目给出了s.length<=1000,因此L的长度可以固定
//直接定义L[1001][1001]也可以,比动态规划更方便
int **L = new int* [len1+1];
int i,j;
for(i=0; i<=len1;i++){
L[i] = new int[len2+1];
}
for(i=0;i<=len1;i++){
for(j=0;j<=len2;j++)
L[i][j]=0; //对数组进行初始化
}//for
for(i=1;i<=len1;i++){
for(j=1;j<=len2;j++){
if(s1[i-1] == s2[j-1]){
L[i][j] = L[i-1][j-1] + 1;
}else{
L[i][j] = max(L[i-1][j], L[i][j-1]);
}
}
}
cout<<len1-L[len1][len2]<<endl;
}
return 0;
}
二、算法基础-字符移位
小Q最近遇到了一个难题:把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,且不能申请额外的空间。
你能帮帮小Q吗?
输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出描述:
对于每组数据,输出移位后的字符串。
输入例子:
AkleBiCeilD
输出例子:
kleieilABCD
思路:
遍历两遍字符串,第一遍输出所有的小写字母,第二遍输出所有的大写字母
c++代码
#include<iostream>
#include<cstring>
using namespace std;
int main(){
string s;
while(cin>>s){
int len=s.length();
int i,j;
for(i=0;i<len;i++){
if(s[i]<='z' && s[i]>='a')
cout<<s[i];
}
for(i=0;i<len;i++){
if(s[i]<='Z' && s[i]>='A')
cout<<s[i];
}
cout<<endl;
}//while
return 0;
}
三、有趣的数字
小Q今天在上厕所时想到了这个问题:有n个数,两两组成二元组,差最小的有多少对呢?差最大呢?
输入描述:
输入包含多组测试数据。 对于每组测试数据: N - 本组测试数据有n个数 a1,a2...an - 需要计算的数据 保证: 1<=N<=100000,0<=ai<=INT_MAX.
输出描述:
对于每组数据,输出两个数,第一个数表示差最小的对数,第二个数表示差最大的对数。
输入例子:
6
45 12 45 32 5 6
输出例子:
1 2
思路:
本题坑较多,题目提供的测试用例是远远不够的,好几种情况没想到也导致了我提交了很多次也没有AC。首先应该用map存储所有的数,first存储值,second存储这个数出现的次数。因为map自带first排序功能,因此从map.begin()开始往后遍历是first的值本来就是递增的,这让我们省掉了排序这一步。很显然,最大的差值肯定是第一个数减去最后一个数再取绝对值,第一个坑来了,如果所有的数都是一样的呢,比如总共3个数,分别是1 1 1,那么最小的差和最大的差是一样的,对数也是一样的。这种情况一定要考虑到。显然判断一下第一个数和最后一个数是否相同即可,若相同差最大的对数就等于差最小的对数就好。如果不相同再另算,对于两个数num1,num2,num1有a个,num2有b个,那么对数一共是(a*b)个。
现在要算差最小的对数,如果序列中有一个数出现的次数大于1次的,那么最小的差就是0,该数有n个,那么对数就是(n-1)*n/2个。注意第二个坑来了,一定不要忽略序列中有多个出现次数大于1次的数,所以在算对数的时候要把这些都加起来。
如果序列中所有的数都只出现了一次,那么最小的差肯定出现在相邻的两个数间。第三个坑来了,这样的对数不只是在一个相邻的两个数,其他相邻的两个数差也可能是最小的差,也一定要加上这种情况。
c++代码:
#include<iostream>
#include<map>
#include<climits>
#include<cmath>
using namespace std;
int main(){
//用map来存储输入,first存值,second存出现的次数
int n; //有n个数
while(cin>>n){
map<int, int> a;
int tmp,i,j;
int flag=0;
for(i=0;i<n;i++){
cin>>tmp;
if(a[tmp]>1)
flag=1;
a[tmp] ++;
}
map<int,int>::iterator it1;
map<int,int>::iterator it2;
int min=INT_MAX;
int min_count=0;
int max_count=0;
it1 = a.begin();
it2 = a.begin();
it2++;
if(flag){
int count;
for(it1=a.begin();it1!=a.end();it1++){
count = it1->second;
if(count > 1){
tmp = ((count-1)*count)/2;
min_count += tmp;
}
}
}else{
//相隔的
for(;it2!=a.end();it1++,it2++){
tmp = fabs((it1->first) - (it2->first));
if(tmp<min){
min=tmp;
min_count = (it1->second) * (it2->second);
}else if(tmp == min){
min_count++;
}
}//for
}
it1=a.begin();
it2=a.end();
it2--;
if(it1->first == it2->first)
max_count=min_count;
else
max_count = (it1->second)*(it2->second);
cout<<min_count<<" "<<max_count<<endl;
} //while
return 0;
}