【2018今日头条笔试题】字符交换

题目

链接:https://www.nowcoder.com/question/next?pid=8537228&qid=141031&tid=22230511

**Level: ** 2018算法工程师笔试题

Discription:
字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?

第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)
一个非负整数,表示操作之后,连续最长的相同字母数量。

Example 1:

Input: abcbaa 2
Output: 2

Note:

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

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;

vector<vector<int>> loc(26); //二维数组初始化
int mem[1001][1001];
int dp(int start, int end, vector<int> loc)
{
    if (start == end || start == (end + 1) || start > end)
    {
        mem[start][end] = 0;
        return 0;
    }
    else if (mem[start][end] != -1)
        return mem[start][end];
    else
    {
        mem[start][end] = dp(start + 1, end - 1, loc) + loc[end] - loc[start] - (end - start);
        return mem[start][end];
    }
}

int main()
{
    string str;
    int m;
    cin >> str >> m;
    for (int i = 0; i < str.length(); i++)
        loc[str[i] - 'a'].push_back(i);

    int nums[26] = { 0 };

    for (int i = 0; i < 26; i++)
    {
        fill(mem[0], mem[0] + 1001 * 1001, -1);
        if (loc[i].size() >= 1)
            nums[i] = 1;//至少有一个连续的
        for (int j = 0; j < loc[i].size(); j++)
        {
            for (int k = j + 1; k < loc[i].size(); k++)
            {
                int len = k - j + 1;
                int lx = dp(j, k, loc[i]);
                if (lx <= m && len > nums[i])
                    nums[i] = len;
            }
        }
    }
    sort(nums, nums + 26);
    cout << nums[25] << endl;
    system("pause");
    return 0;
}

思考

  • 算法时间复杂度为O(\(S^3\)),空间复杂度为O(\(S^2\) ),S是字符串的长度,递归最深是S/2。
  • DP实现,转移方程是dp(start, end, loc) = dp(start + 1, end - 1, loc) + loc[end] - loc[start] - (end - start);最优的操作总是两边向中间聚合。DP的难点在于想通如何把大问题化解成为小问题,其次是想明白小问题的最优操作是怎样的,比如这题中的两边向中间聚合,如果这一步想不通,即使化解成为小问题也求解不出来。
  • 光用递归实现会超时,定义一个数组来存放中间重复计算的值。
posted @ 2019-03-16 19:11  我的小叮当  阅读(1122)  评论(0编辑  收藏  举报