使用最少的操作将给定的字符串转换为已排序的字符串

时间:2015-04-06 09:00:04

标签: c++ string algorithm sorting

我们获得了一个任意字符串。现在,我们可以对此字符串执行一些操作。 任何字母都可以转换为任何其他字母。现在,我们可以从字符串中选择任何字母并将其转换为任何其他字母。这将被称为单个操作。

如何使用上述最少的操作数将字符串转换为字母按排序顺序排列的字符串?

欢迎所有解决方案,包括开箱即用的解决方案!

P.S。:这是一个例子 -

Given string: dcba
We can convert this string into a sorted using at least 3 operations. The generated string can be any of the following:
dddd (3 operations)
aaaa (3 operations)
cccc (3 operations)
..
etc.

P.P.S。:有些人问我,我在这里提供自己的解决方案 -

其中一个暴力解决方案就是利用递归。当我们处于字符串的某个字符索引时,我们可以不更改它或将其更改为其他字符,并递归调用索引递增1的函数。如果我们改变角色,增加号码。 1的操作只是按原样传递。在递归的每一步,我们都可以检查字符串是否排序 - 如果是,则用当前计数更新总体最小值,如果它小于当前计数。

2 个答案:

答案 0 :(得分:7)

这个问题等同于你的字符串的longest increasing subsequence:显然,保持最大字母数不变是最佳的,并且这些字母必须形成一个递增的子序列。另一个方向类似。

虽然LIS可以在一般序列的O(n log n)中求解,但你甚至不需要它,因为你手头有一个更简单的特殊情况,字母大小为a = 26.你可以使用动态编程来解决O(n·a)中的问题:

设f(i,j)是以字母j结尾的前缀s [0 ..(i-1)]的最优解。我们有复发

f(0, j) = 0  for j = 0..25
f(i + 1, j) = [j != s[i]] + MIN(k = 0..j, f(i, k))

如果k!= j,则[k!= j]为1,否则为0。通过顺序计算表的每一行(增加j),您可以计算O(1)中的最小值。

最终解是MIN(j = 0..25,f(n,j))。您可以通过递归跟随导致最优解的DP状态来构造相应的字符串:

const int a = 'z' - 'a' + 1;
vector<array<int, a>> f;
string s = "azbzc";

void reconstruct(int i, int j) {
  if (i == 0)
    return;
  int prev_j = min_element(begin(f[i-1]), begin(f[i-1]) + j + 1) - begin(f[i-1]);
  reconstruct(i - 1, prev_j);
  cout << (char)('a' + j);
}

int main() {
  f.resize(s.size() + 1);
  int n = s.size();
  for (int i = 0; i < n; ++i) {
    int sol = f[i][0];
    for (int j = 0; j < a; ++j) {
      sol = min(sol, f[i][j]);
      f[i+1][j] = (j != s[i] - 'a') + sol;
    }
  }
  int j = min_element(begin(f[n]), end(f[n])) - begin(f[n]);
  cout << "solution: " << f[n][j] << endl;
  reconstruct(n, j);
  cout << endl;
}

输出:

solution: 2
aabbc

答案 1 :(得分:0)

// One way is to find the max length of a pattern conforming and then total length - pattern length is the min count of changes.
// 
// Here is the code to find max length of entries as sorted.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdbool.h>


struct data_entry {
    int v;
    int w;
};

typedef struct data_entry data_t;

int
find_max_weight(const data_t *l, int cnt, int v)
{
    int ret = 0;
    int min = -1;

    l += cnt-1;

    while(cnt-- >= 0) {
        if ((l->v > min) && (l->v <= v)) {
            if (ret < l->w) {
                ret = l->w;
                min = l->v;
            }
        }
        --l;
    }
    return ret;
}

int
max_pattern_len(const char *s, int len)
{
    int i, max_len = 0;
    data_t l[len];

    for(i = 0; i < len; ++i) {
        data_t *p = l + i;

        p->v = *s++;

        p->w = find_max_weight(l, i, p->v) + 1; // +1 for self

        if (max_len < p->w) {
            max_len = p->w;
        }
    }
    for(i=0; i < len; ++i) {
        printf("{%d, %d}\n", l[i].v, l[i].w);
    }

    return max_len;
}

int
main(int argc, const char **argv)
{
    char buff[100];
    int i;

    if ((argc > 1) && (argc < sizeof(buff))) {
        int max;

        for(i = 1; i < argc; ++i) {
            buff[i-1] = atoi(argv[i]);
        }
        max = max_pattern_len(buff, argc-1);
        printf("max_pattern_len=%d min_changes=%d\n", max, argc-1-max);
    }
    return 0;
}