数字能排序字符串不能排序_算法题——[leetcode1585]判断字符串s能否通过排序操作变为t...

Hard级别的新题:给定数字串s和t,它们只由'0'到'9'这10个数字组成。问你可以不断选择s的任意子串,对其进行排序,问最后能不能把它变为t?

数据范围: s和t只由数字组成,并且长度相同,长度不超过100000。

例如s = "84532" t = "34852", 返回true。

我们可以选择先对s的前4个字符排序,变为"34582"

再对s的下标为2和3的两个字符排序,变为"34852"得到t。

分析:有点意思的题。问题的关键是,对任意子串排序和对任意长度为2的子串排序——对相邻两个字符排序,没有任何区别。看起来对相邻两个字符排序的操作要弱于对任意子串排序,但其实它们是等效的。因为如果我们要对某个子串排序,我们可以选择这个子串里的最小的,通过对相邻两个字符排序的操作,将其换到子串的开头,再找到次小的,把它换到第2个位置——就像冒泡排序一样。因此,我们可以简单地考虑是否能通过对相邻两个字符排序,把s变为t。

方法1 由小到大处理字符c。我们看字符c在s和t出现的位置。这里必须满足s和t中该字符出现的次数一样多,并且t中该字符出现的每个位置一定要不大于s中该字符出现的每个位置——这样该字符可以不断左移动到指定位置,然后我们再把所有的c从s和t中删掉,继续统计下一个字符。

这里多说两句,真正的操作过程是反过来的,先处理9,这时0-8都删光了,所以只要个数相等,就一定没问题。然后处理8,这时实际上字符串只有8和9,然后按照我们的判断方法,只要t中每个8的位置比s中8的位置更靠前,则就可以。因为8在只有8和9的世界里,8可以自由地往前换……如此类推。

可是在实现时,我们c是从0-9循环的,每次判断位置时,忽略掉小于它的字符即可,而没有必要真正地删除。

代码:

class Solution {public:    bool isTransformable(string s, string t) {        for (char c = '0'; c <= '9'; ++c) {            vector<int> v;            for (int i = 0, p = 0; i < s.length(); ++i) {                if (s[i] == c) {                    v.push_back(p);                }                if (s[i] >= c) {                    ++p;                }            }            int num = 0;            for (int i = 0, p = 0; i < t.length(); ++i) {                if (t[i] == c) {                    if (num >= v.size() || v[num] < p) {                        return false;                    }                    ++num;                }                if (t[i] >= c) {                    ++p;                }            }            if (num != v.size()) {                return false;            }                    }        return true;            }};

方法2 按照t中的顺序处理。思路类似。我们统计s中每个字符出现的位置。然后对t中的每个字符,我们知道该字符是该数字的第几次出现。设这个字符是x, 若其可以移动到指定位置(无论前移还是后移),只要保证s中比x小的还没处理的字符不在x之前(左)出现就好。因为如果这样一个字符y存在,y在s中比 x更靠前(左),而在t中比x更靠后(右),而y < x,这是不可能的。因为从s中无论如何交换y只能在x的左边。

代码:

class Solution {public:    bool isTransformable(string s, string t) {        vector<vector<int>> p(10);        vector<int> ind(10);        for (int i = 0; i < s.length(); ++i) {            p[s[i] - '0'].push_back(i);        }        for (char x : t) {            const int c = x - '0';            if (ind[c] >= p[c].size()) {                return false;            }            for (int j = 0; j < c; ++j) {                if (ind[j] < p[j].size() && p[j][ind[j]] < p[c][ind[c]]) {                    return false;                }            }            ++ind[c];        }        return true;            }};

1a64d641dd62807795425d8f2377bfdf.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值