1. 程式人生 > >騰訊2017暑期實習生程式設計題 題解

騰訊2017暑期實習生程式設計題 題解

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;
}