1585. 检查字符串是否可以通过排序子字符串得到另一个字符串(单调栈)

题目链接

 解析链接

给你两个字符串 s 和 t ,请你通过若干次以下操作将字符串 s 转化成字符串 t :

选择 s 中一个 非空 子字符串并将它包含的字符就地 升序 排序。
比方说,对下划线所示的子字符串进行操作可以由 "14234" 得到 "12344" 。

如果可以将字符串 s 变成 t ,返回 true 。否则,返回 false 。

一个 子字符串 定义为一个字符串中连续的若干字符。

 

示例 1:

输入:s = "84532", t = "34852"
输出:true
解释:你可以按以下操作将 s 转变为 t :
"84532" (从下标 2 到下标 3)-> "84352"
"84352" (从下标 0 到下标 2) -> "34852"
示例 2:

输入:s = "34521", t = "23415"
输出:true
解释:你可以按以下操作将 s 转变为 t :
"34521" -> "23451"
"23451" -> "23415"
示例 3:

输入:s = "12345", t = "12435"
输出:false
示例 4:

输入:s = "1", t = "2"
输出:false
 

提示:

s.length == t.length
1 <= s.length <= 105
s 和 t 都只包含数字字符,即 '0' 到 '9' 。

 

这个题就是首先我们遍历t中的元素如果s[i]!=t[i]的话

我们可以向s数组中i的后面找到这个离i最近数t[i],下标为j。

然后我们看看从i到j中有没有比t[i]小的数,如果有的话就不行

这听起来是个n^2的

但是我们可以把每一个数字出现的下标存到一个vector中

 

 

比如


s = "84532", t = "34852"
我们想把 s 变成 t,那么第一步我们需要把 s 的第一个字母变成 3,其实就可以从第一个字母遍历到是 3 的地方,如果这个过程中遇到比 3 小的字母,那么一定是不可能变过来的,因为怎么 sort,这个字母一定在 3 前面,所以就不行,如果没有的话,那么我们就标记一下 s 中 3 的下标,表明已经用过了,下次遍历的时候就跳过就好了。然后依次类推,每次都遍历一遍,时间复杂度为 O(n^2),果然数据量 10^5
的这种时间复杂度过不了。。。

那么怎么去优化一下呢?其实我们上面的思路已经能显现出一些问题了,我们没必要每次都去遍历寻找我们想要的字母,直接去存一下这些字母的下标不就好找了吗,直接从 O(n) 的寻找时间变成 O(1),

class Solution {
public:
    bool isTransformable(string s, string t) {
        int n=s.size();
        vector<queue<int>> v(10);
        for(int i=0;i<n;i++){
            v[s[i]-'0'].push(i);
        }
        for(int i=0;i<n;i++){
            int pos=t[i]-'0';
            if(v[pos].size()==0){
                return false;
            }
            for(int j=0;j<pos;j++){//找到这个比pos小的数的下标看看有没有小于pos的下标
                if(!v[j].empty() && v[j].front() < v[pos].front()){
                    return false;
                }
            }
            v[pos].pop();
        }
        return true;
    }
};

 

posted @ 2021-05-29 16:28  lipu123  阅读(80)  评论(0编辑  收藏  举报