腾讯2017暑期实习生编程题详解

第一题:

给定一个字符串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;
}

  

  

 

  

彼时当年少,莫负好时光。
原文地址:https://www.cnblogs.com/l609929321/p/14989278.html