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; } };