1、构造回文

时间限制:1秒
空间限制:32768K

给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?
输出需要删除的字符个数。

输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.

输出描述:
对于每组数据,输出一个整数,代表最少需要删除的字符个数。

输入例子1:

abcda
google

输出例子1:

2
2

解法一:

分析:先求字符串s的反串reverse,然后求它们的最长的公共子序列,就能知道要删除的字符个数了。

C++程序如下:

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;

const int MAXN=1010;                    //定义一个整型常量MAXN 
int temp[MAXN][MAXN];                   //声明一个数组temp

int getRemoveNumber(string &s1)
{
    string s2(s1);
    reverse(s2.begin(),s2.end());      //翻转s2
    int len=s1.length();               //s1的长度
    memset(temp,0,sizeof temp);        //将temp所指向的某一块内存中的前(sizeof temp)个字节的内容全部设置为0
    for(int i=0;i<len;++i)
    {
        for(int j=0;j<len;++j)
        {
            if(s1[i]==s2[j])
                temp[i+1][j+1]=temp[i][j]+1;
            else temp[i+1][j+1]=max(temp[i][j+1],temp[i+1][j]);
        }
    }
    return len-temp[len][len];
}

int main()
{
   string s;
   while(cin>>s)
   {
       cout<<getRemoveNumber(s)<<endl;
   }
   return 0;
}

【相关函数介绍】

memset函数:

函数原型memset(void *s,int ch,size_t n)

函数说明
memset函数是计算机中C/C++语言函数。将s所指向的某一块内存中的前n个字节的内容全部设置为ch指定的ASCII值,第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作,其返回值为指向s的指针。所在头文件<memory.h>或<string.h>。

该函数的第二个参数ch为进行初始化的值,该值的范围为0到255(00000000到11111111)。如果超过该范围那么会对该值取后8位。如果ch为字符型,那么取其ASCII码。

1.对bool数组进行初始化:初始化结果为true或false
(1)使用 0或1初始化 memset(prime,0,sizeof(prime));0为false,1为true
(2)使用 true或false初始化 memset(prime,true,sizeof(prime));true为true,false为false
(3)使用其它值初始化 memset(prime,‘A’,sizeof(prime)); 非0值为true,0为false(字符0取ASCII码48,为true)

2.对char数组进行初始化:
(1)使用char型变量。memset(CH,‘A’,sizeof(CH));初始化结果为对应的字符。
(2)使用int型变量。将该int值作为ASCII码,使用对应的字符进行初始化。(0到127为ASCII码表,其中0为NULL,128到254未知,应该为扩展ASCII码。255显示字符串中字符无效。)
(3)使用bool型变量true或false。(true为ASCII码1,false为ASCII码0,初始结果同int)

3.对int数组进行初始化:
仅可在初始化的值的最后8位为11111111(255)或00000000(0)时能够正确进行初始化。也就是说int型数组仅能初始化为-1和0。其余方法均不能得到正确的结果。

解法二:

分析:本题可以转换为求该字符串与其反序字符串的最长公共子序列问题,即利用LCS算法求解。

例如:abcda的反序字符串为adcba,最长公共子序列为aba,其公共子序列必为回文序列,然后可求出最少删除多少个字节使其成为回文字符串。
本题采用动态规划来求解问题,下面看看模拟的推导过程。
状态转移方程为:(令A为输入字符串,B为其反序字符串,num[][]记录当前最长公共子序列的长度)

if (A[i] == B[j]) num[i][j] = num[i-1][j-1] + 1
else num[i][j] = max(num[i-1][j] , num[i][j-1])

C++程序如下:

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <vector>
#include <string>
using namespace std;

int main(){
    string s;
    while(cin>>s){
        int len = s.length();
        int maxlen = 0;
        vector<vector<int> > Vec;
        for(int i = 0 ; i < len+1 ; i++){
            vector<int> temp(len+1,0);
            Vec.push_back(temp);
        }
        for(int i = 1; i< len+1 ; i++){
            for(int j = 1 ; j < len+1;j++){
                if(s[i-1]==s[len-j]){
                    Vec[i][j] = Vec[i-1][j-1]+1;
                }
                else {
                    Vec[i][j] = max(Vec[i-1][j],Vec[i][j-1]);
                }
            }
        }
        cout<<len-Vec[len][len]<<endl;
    }
}

2、字符移位

时间限制:1秒
空间限制:32768K

小Q最近遇到了一个难题:把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,且不能申请额外的空间。
你能帮帮小Q吗?

输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.

输出描述:
对于每组数据,输出移位后的字符串。

示例1
输入
AkleBiCeilD

输出
kleieilABCD

分析:如果碰到大写,就插入到字符串的最后面.

C++程序如下:

#include <iostream>
#include <string.h>
using namespace std;

int main()
{
    char a[1000];
    while(cin>>a)
    {
      int len = strlen(a);
      int end = len-1;
       for(int i = 0; i<= end;)
       {
            if(a[i]>='A'&&a[i]<='Z')
            {
                char temp = a[i];
                for(int j=i; j<len; j++)
                {
                    a[j]=a[j+1];
                }
                a[len-1] = temp;
                end--;
            }
           else  i++;
       }
       cout<<a<<endl;
    }
    return 0; 
}

有趣的数字

小Q今天在上厕所时想到了这个问题:有n个数,两两组成二元组,相差最小的有多少对呢?相差最大呢?

时间限制:1秒
空间限制:32768K

输入描述:

 输入包含多组测试数据。

 对于每组测试数据:

 N - 本组测试数据有n个数

 a1,a2...an - 需要计算的数据

 保证:

 1<=N<=100000,0<=ai<=INT_MAX.

输出描述:

对于每组数据,输出两个数,第一个数表示差最小的对数,第二个数表示差最大的对数。

示例1
输入
6
45 12 45 32 5 6

输出
1 2

分析:先排序,然后对有序数组分别求差值最大的对数和差值最小的对数。排序之后,差值最大的好求,看有序数组有几个最小值和几个最大值,相乘即可。差值最小的,由于是有序数组,必定是相邻的差值较小,故由排序后的有序数组求出差值最小值。如果差值最小值为0,则算出数组中相等的元素的对数;如果差值最小值不为0,则只需计算有多少个最小值即可。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(){
    int n;
    while (cin>>n) {
        vector<int> nums(n);
        for (int i=0; i<n; i++) {
            cin>>nums[i];
        }

        int minNum=0, maxNum=0;
        //排序
        sort(nums.begin(), nums.end());

        //最大
        int m1 = 0, m2 = n-1, a=1, b=1;
        while (nums[m1+1] == nums[m1]) {
            a++;
            m1++;
        }

        while (nums[m2] == nums[m2-1]) {
            b++;
            m2--;
        }
        maxNum = a*b;

        //最小
        int minTemp=nums[n-1];
        for (int i=1; i<n; i++) {
            if (nums[i]-nums[i-1]<minTemp) {
                minTemp = nums[i]-nums[i-1];
            }
        }

        if (minTemp >0) {

            for (int i=1; i<n; i++) {
                if (nums[i]-nums[i-1] == minTemp) {
                    minNum++;
                }
            }

        }else{

            for (int i=1; i<n; i++) {
                int j=i-1;
                while (nums[j]==nums[i] && j>=0) {
                    minNum++;
                    j--;
                }
            }
        }
        cout<<minNum<<" "<<maxNum<<endl;
    }

    return 0;
}