字节跳动两道动态规划题

字节跳动

字节跳动2018校招后端方向(第二批)笔试题第三题

题目名: 字母交换
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32M,其他语言64M
题目描述: 字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?
输入描述:

第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)

输出描述:

一个非负整数,表示操作之后,连续最长的相同字母数量。

输入例子:

abcbaa 2

输出例子:

2

例子说明:

使3个字母a连续出现,至少需要3次操作。即把第1个位置上的a移动到第4个位置。
所以在至多操作2次的情况下,最多只能使2个b或2个a连续出现。

题目解析
题目的意思即在有限的交换次数下,找到最长的连续的相同字母。首先可以想到的是,每个字母和其它字母没有关系,唯一重要的就是每个字母的位置信息,因此首先分别把每个字母的位置提取出来,都是小写字母,因此共需要26个vector来存储。剩下的就是对每个字母分别进行分析,找到在有限交换次数m下,最长的连续字母。
每个长的连续相同的字母串,比如aaaa,是可以由abaaba中两端的a向中间移动得到的,其移动次数和两端到中间的距离,以及在这之前得到中间的aa所花费的移动次数有关。因此考虑如下状态转移矩阵:设dp[j][k]表示某字符第j个位置到第k个位置的字符连续,至少需要多少次交换。有以下几种情况:

  1. j==k时,表示一个字符,那么dp[j][k]=0;
  2. j+1==k时,表示两个字符,需要交换次数为dis=position[i][k]-position[i][j]-(k-j);//position[i]存储字符i的位置
  3. 其它情况:dp[j][k]=dp[j+1][k-1]+position[i][k]-position[i][j]-(k-j)。//position[i][k]-position[i][j]-(k-j)即在j+1至k-1连续的情况下,将j、k上的字符移动到其两端所花费的交换次数
    代码:
#include 
#include 
#include 
using namespace std;
int longest(vector<vector<int>>& position,int m){
    int res=0;
    for(int i=0;i<position.size();i++){//依次遍历每个字母
        int sz=position[i].size();
        vector<vector<int>> dp(sz,vector<int>(sz,0));
        for(int j=sz-1;j>=0;j--){//使用合适的循环方法来先求解子问题
            for(int k=j+1;k<sz;k++){
                int dis=position[i][k]-position[i][j]-(k-j);
                if(j+1!=k)
                    dis+=dp[j+1][k-1];
                dp[j][k]=dis;
                if(dp[j][k]<=m)//判断所有交换次数小于等于m步的情况中的最大的连续个数,即k-j+1的最大值
                    res=max(res,k-j+1);
            }
        }
    }
    return res;
}
int main(){
    int m;
    string str;
    cin>>str>>m;
    vector<vector<int>> position(26,vector<int>());
    for(int i=0;i<str.size();i++){
        position[str[i]-'a'].push_back(i);
    }
    cout<<longest(position,m);
    return 0;
}

字节跳动19年校招真题——毕业旅行问题

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32M,其他语言64M
题目描述:
小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北京,每个城市之间均乘坐高铁,且每个城市只去一次。由于经费有限,希望能够通过合理的路线安排尽可能的省一些路上的花销。给定一组城市和每对城市之间的火车票的价钱,找到每个城市只访问一次并返回起点的最小车费花销。
输入描述:

城市个数n(1<n≤20,包括北京)

城市间的车票价钱 n行n列的矩阵 m[n][n]

输出描述:

最小车费花销 s

示例:

输入:

4
0 2 6 5
2 0 4 4
6 4 0 2
5 4 2 0

输出:

13

说明:

4 个城市,城市 1 和城市 1 的车费为0,城市 1 和城市 2 之间的车费为 2,城市 1 和城市 3 之间的车费为 6,城市 1 和城市 4 之间的车费为 5,依次类推。
假设任意两个城市之间均有单程票可购买,且票价在1000元以内,无需考虑极端情况。

题目解析:
这是一个典型的旅行商问题,是一个NP问题,因此目前无法找到一个多项式时间复杂度的算法来求解。
比较容易想到的是暴力法,即穷举所有的可能,时间复杂度为O(n!),可以利用回溯的方法来实现,但复杂度太高,即使通过判断当前路径是否已经大于之前的最小值来剪枝,也无法跑通所有数据,看到大神的解法,才发现可以使用动态规划,将复杂度大大降低。
动态规划:首先由于要回到起点,因此最终会形成一个圈,所以选择任意的城市作为起点得到的最优解一定是相同的,因此不妨选择城市0作为起点和终点。
将大问题拆分成小问题,例如大问题是从顶点0开始,经过顶点1,2,3然后回到顶点1的最短路程,那么我们可以分割为三个小问题找最优解:
从顶点0出发,途径2,3城市(不保证访问顺序),再到1,然后回到0的最短路径
从顶点0出发,途径1,3城市,再到2,然后回到0的最短路径
从顶点0出发,途径1,2城市,再到3,然后回到0的最短路径
那么这三个小问题的最小值就是问题得最优解。
设dp[i][j]中i的二进制表示经过城市的集合(假设i为3,二进制为101,即表示经过了城市0和城市2),dp[i][j]表示经过i中的城市集合并以j结尾的路径长度。
因此考虑状态转移方程:dp[i|(1< 即将城市k加入经过城市的结合,并以k结尾的路径长度为:在加入k之前的城市集合中到j的路径长+从j到k的路径长。求解其最小值。
其时间复杂度O(n ^ 2 * 2 ^ n)和空间复杂度为O(n * 2 ^ n):
代码:

int findMin(vector<vector<int>>& matrix){
    int n=matrix.size();
    int flag=1<<n;
    vector<vector<int>> dp(flag,vector<int>(n,INT_MAX));
    dp[1][0]=0;//从城市0出发,经过城市0,以城市0结尾,路径为0
    for(int i=1;i<flag;i++){
        for(int j=0;j<n;j++){
            if(dp[i][j]!=INT_MAX){//如果dp[i][j]已经访问过,才可以利用其求解(在这一步也就排除了不以城市0出发的情况)
                for(int k=0;k<n;k++){
                    if((i&(1<<k))==0){//判断k是否已经访问,如果没有访问,求解访问k城市后的最小值
                        dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+matrix[j][k]);
                    }
                }
            }
        }
    }
    int res=INT_MAX;
    for(int i=1;i<n;i++){
        res=min(res,dp[flag-1][i]+matrix[i][0]);//flag-1等于01111111...111,即访问了所有城市的集合。以某个城市作为结尾,从其回到城市0
    }
    return res;
}
int main(){
    int n;
    cin>>n;
    vector<vector<int>> matrix;
    int tmp=n;
    while(tmp--){
        int col=n;
        vector<int> line;
        while(col--){
            int val;
            cin>>val;
            line.push_back(val);
        }
        matrix.push_back(line);
    }
    int minPrice=findMin(matrix);
    cout<<minPrice;
    return 0;
}

你可能感兴趣的:(数据结构与算法)