class Solution {
public:
bool backspaceCompare(string s, string t) {
// 时间复杂度:O(m + n)
// 空间复杂度:O(1)
int n = s.size(),m = t.size();
int skipS = 0,skipT = 0;// 记录字符串中'#'数量
int i = n - 1,j = m - 1;
while(i >= 0 || j >= 0){
// 从后往前消掉 s 中的 '#'
while(i >= 0){
if(s[i] == '#'){
skipS ++, i --;
}else if(skipS > 0){
skipS --, i --;
}else{
break;
}
}
// 从后往前消掉 t 中的 '#'
while(j >= 0){
if(t[j] == '#'){
skipT ++, j --;
}else if(skipT > 0){
skipT --, j --;
}else{
break;
}
}
// i,j 都没有遍历完,继续比较字符
if(i >= 0 && j >= 0){
if(s[i] != t[j]){
return false;
}
}else if(i >= 0 || j >= 0){ // 只有一个遍历完了
return false;
}
i --,j --;
}
return true;
}
};
2.情感丰富的文字
题目
解析
核心思想:该题最难的部分就是理解 “扩张” 操作:假设有两个字符相同的连续段 a 和 b,如何判断是否能扩展 b -> a;
当 a 和 b 长度相同,定义为可扩张;
当 a 和 b 长度不同,根据「a 和 b 长度对比」以及「a 的长度大小」分情况讨论:
当 b > a,不可扩张;
当 a > b,我们不一定要拿整一段的 b 进行扩张,可以拿 b 中的一个字符进行扩张。 因此只需要满足 a 扩张后的长度大于等于 3 即可定义为可扩张。
代码
class Solution {
public:
int expressiveWords(string s, vector<string>& words) {
// 时间复杂度:O(n * m + ∑(word[i].size()))
// 空间复杂度:O(1)
int n = s.size();
int ans = 0;
for(string word : words){
int m = word.size(),i = 0,j = 0;
// word 为模版字符串,s 为扩展字符串
while(i < n && j < m){
if(s[i] != word[j]) break;// 字母不相等
// 分别找到 s,word 连续相同字符长度 a,b
int a = i,b = j;
while(a < n && s[a] == s[i]) a ++;
while(b < m && word[b] == word[j]) b ++;
a -= i,b -= j;
// 如果长度不相等,且扩展的长度 a < b 模版长度,不可扩展
// 如果扩展长度 a < 3,也不可扩展
if(a != b && (a < b || a < 3)) break;
// 更新指针,继续遍历下一个元素
i += a,j += b;
}
if(i == n && j == m) ans ++;
}
return ans;
}
};
3.最小差
题目
解析
核心思想:两个序列数字进行比较,数字更小的指针移动;
代码
class Solution {
typedef long long ll;
public:
int smallestDifference(vector<int>& a, vector<int>& b) {
// 时间复杂度:O(nlogn + mlogm)
// 空间复杂度:O(1)
int n = a.size(),m = b.size();
ll ans = INT_MAX;
sort(a.begin(),a.end());
sort(b.begin(),b.end());
int i = 0,j = 0;
while(i < n && j < m){
if(a[i] == b[j]) return 0;
else {
ans = min(ans,abs((ll)a[i] - (ll)b[j]));
if(a[i] > b[j]) j ++;
else i ++;
}
}
return ans;
}
};