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

题目链接:https://www.nowcoder.com/test/1725829/summary

1.构造回文

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

解题思路分析:题意是说问我们最少删几个字符能够使得这个字符变成一个回文串,这里需要用到回文串的性质,因为回文串是前后对称的,所以我们只需要求字符串和它的反串的最长公共子串长度即可,最少删的字符数就是总长度减去最长公共子串长度。求解最长公共子序列长度的方法动态规划即可,dp[i][j]记录当我们匹配第一个字符串i位置前面的子串和第二个字符串j位置前面的子串的最长公共子序列长度,则有,如果s1[i] == s2[j],则dp[i][j] = dp[i-1][j-1] + 1,否则dp[i][j] = max(dp[i-1][j], dp[i][j-1])。

代码;

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1000+5;
char s1[maxn], s2[maxn];
int dp[maxn][maxn];
int main() {
    while(cin >> s1) {
        int len = strlen(s1);
        for(int i=0; i<len; i++) {
            s2[i] = s1[len - i - 1];
        }
        for(int i=0; i<=len; i++) {
            dp[i][0] = 0;
            dp[0][i] = 0;
        }
        for(int i=1; i<=len; i++) {
            for(int j=1; j<=len; j++) {
                if(s1[i-1] == s2[j-1]) {
                    dp[i][j] = dp[i-1][j-1] + 1;
                }
                else {
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        cout << len - dp[len][len] << endl;
    }
    return 0;
}
添加笔记

2.算法基础

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

解题思路分析:不能开额外的空间,那么我们直接在这个字符串上进行交换即可,这题我们就从后往前,只要遇到一个大写字母,就将其一直向后交换到最后或者另一个大写字母。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1000 + 5;
char str[maxn];
int main() {
    while(cin >> str) {
        int len = strlen(str);
        int pos = len - 1;
        for(int i=len-1; i>=0; i--) {
            if(str[i] <= 'Z' && str[i] >= 'A') {
                for(int j=i+1; j<=pos; j++) {
                    swap(str[j-1], str[j]);
                }
                pos--;
            }
        }
        cout << str << endl;
    }
}

3.有趣的数字

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

解题思路分析:题意是说问我们差最小和最大的二元组有多少对。

首先我们先将所有数进行排序,然后再对所有的数的重复元素去掉,并记录其出现的次数,显然差最大值肯定是最大的数减去最小的数,所以差最大的对数就是最大的数的个数乘最小的数的个数。如果出现了重复元素的话那么最小的差值当然是0,如果没有出现重复元素的话,那么我们只需要从这个已经排好序的序列的相邻元素的差值中去找最小的,因为最小的差值一定是相邻元素的差,然后我们再通过第二次遍历便可以找到。

代码:

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 5;
int a[maxn], b[maxn];
map<int, int> Map;
int main() {
    int n;
    while(cin >> n) {
        Map.clear();
        for(int i=0; i<n; i++) {
            cin >> a[i];
        }
        sort(a, a+n);
        int num = 0;
        int ok = 0;
        for(int i=0; i<n; i++) {
            if(i == 0 || a[i] != a[i-1]) {
                b[num++] = a[i];
                Map[a[i]]++;
            }
            else {
                Map[a[i]]++;
                ok = 1;
            }
        }
        int Max = 0, Min = 0;
        Max = Map[b[0]] * Map[b[num-1]];
        if(ok) {
            for(int i=0; i<num; i++) {
                if(Map[b[i]] > 1) {
                    Min += (Map[b[i]] * (Map[b[i]] - 1)) / 2;
                }
            }
        }
        else {
            int MinL = 0x3f3f3f3f;
            for(int i=1; i<num; i++) {
                int L = b[i] - b[i-1];
                if(L < MinL) {
                    MinL = L;
                }
            }
            for(int i=1; i<num; i++) {
                int L = b[i] - b[i-1];
                if(L == MinL) {
                    Min += Map[b[i]] * Map[b[i-1]];
                }
            }
        }
        cout << Min << " " << Max << endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值