【算法-LeetCode】1047. 删除字符串中的所有相邻重复项(双指针;栈)

1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)

发布:2021年10月10日24:08:12

问题描述及示例

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

输入:“abbaca”
输出:“ca”

解释:
例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。

提示:
1 <= S.length <= 20000
S 仅由小写英文字母组成。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的题解

我的题解1(双指针)

思路比较简单:

  1. 首先利用 split() 函数将 s 转换为单字符数组 sArr
  2. 然后用两个一前一后且始终相邻的 i 指针和 j 指针来标识字符串 s 中的相邻两个字符。
  3. 利用 while 循环遍历 sArr 数组。
    • 如果两个指针指向的字符是相同的。则利用 splice() 函数将两个指针指向的两个字符从 sArr 中删除。删除的同时还要注意数组下标塌陷的问题。而且删除之后要注意让两个指针都往后退一步以防删除元素之后再次出现相邻的重复字符。
    • 如果两个指针指向的字符不相同。那么就继续往后遍历。
  4. 直到靠后的 j 指针到达 sArr 数组的尾部,此时停止遍历,将 sArr 中剩余的字符重新利用 join() 函数拼接为字符串并作为返回值返回。

有关详解请看下方注释:

/**
 * @param {string} s
 * @return {string}
 */
var removeDuplicates = function(s) {
  // 利用 `split()` 函数将 `s` 转换为单字符数组 `sArr`
  let sArr = s.split('');
  // 初始化 i、j 指针
  let i = 0;
  let j = 1;
  // 开始遍历 sArr 数组,当靠后的 j 指针指向其尾部时,跳出循环
  while(j < sArr.length) {
    // 如果 i、j 指针指向的字符相等
    if(sArr[i] === sArr[j]) {
      // 删除 i、j 指针指向的两个字符元素,注意此时 sArr 数组的长度变短了,但是不影响后续
      sArr.splice(i, 2);
      // 为了防止删除字符的同时又生成了相邻的重复字符,要让 i、j 指针往后退一步
      i--;
      j--;
      // 直接跳到下一次循环
      continue;
    }
    // 如果 i、j 指针指向的字符不相等,则继续往后遍历
    i++;
    j++;
  }
  // 遍历结束后,重新将 sArr 中的字符拼接为字符串并作为返回值返回
  return sArr.join('');
};


提交记录
106 / 106 个通过测试用例
状态:通过
执行用时:3092 ms, 在所有 JavaScript 提交中击败了5.43%的用户
内存消耗:46.3 MB, 在所有 JavaScript 提交中击败了84.51%的用户
时间:2021/10/10 00:10

可以看到,这种方法的时间表现还是比较差的,应该是因为用到了 splice() 函数,因为该函数会移动大量的元素,性能自然比较差。

我的题解2(栈)

成功前的尝试

这次我作了一下妖,想着能不能重复利用一下 sArr 的空间。于是想着把 sArr 首部元素弹出,判断是否和后续字符重复,然后把符合要求的字符压入 sArr 尾部。还用了一个特殊字符 ? 来作为原字符的结束标志。

/**
 * @param {string} s
 * @return {string}
 */
var removeDuplicates = function(s) {
  let sArr = s.split('');
  sArr.push('?');
  let head = sArr.shift();
  while(head !== '?') {
    if(head === sArr[0]) {
      sArr.shift();
      sArr[0] === sArr[sArr.length-1] && sArr.length !== 1 ? sArr.shift() && sArr.pop() : null;
    } else {
      sArr.push(head);
    }
    head = sArr.shift();
  }
  return sArr.join('');
};

提交记录
91 / 106 个通过测试用例
执行结果:解答错误
输入:"cmclrhhapqdfkfjllkedgirfpeegjitijeghhqtpaprhnpljcidotmhdrfesieqcjbtrrtbkblboiduqltrbqqfjbmigseoushtardbbhislcnujegkicmlmodqeodoosgguqhnckcjdqdkfnqfqdupuqgpqukeddcalpqtjlhldhndrhpkliposegmeekfokkjsqldehlibposfggitdslltlkhjqtruugkqmqbiuttagmktpkcocfntbrjrpqostkepooqanhbjbemneogtusjnajniudhtritdcrujkagbmofhehldokqprfadsbgdgcflbrnngamdphoptgcqeujfboseescobuoiqrjhbhomnldulduugegoejffsgikbdqorqrjfmiohbmhijpfgkntuersdebapquucmskcblujeqnodaqcaphsuksdfgjlhmnfsgnpupfuarmmtjfimqtksbdchfounolekpdotpspgoukcmrtsnqkdccfjlcmclrhhapqdfkfjllkedgirfpeegjitijeghhqtpaprhnpljcidotmhdrfesieqcjbtrrtbkblboiduqltrbqqfjbmigseoushtardbbhislcnujegkicmlmodqeodoosgguqhnckcjdqdkfnqfqdupuqgpqukeddcalpqtjlhldhndrhpkliposegmeekfokkjsqldehlibposfggitdslltlkhjqtruugkqmqbiuttagmktpkcocfntbrjrpqostkepooqanhbjbemneogtusjnajniudhtritdcrujkagbmofhehldokqprfadsbgdgcflbrnngamdphoptgcqeujfboseescobuoiqrjhbhomnldulduugegoejffsgikbdqorqrjfmiohbmhijpfgkntuersdebapquucmskcblujeqnodaqcaphsuksdfgjlhmnfsgnpupfuarmmtjfimqtksbdchfounolek"
查看全部
输出:"cmclrapqdfkfjkedgirfpgjitijegqtpaprhnpljcidotmhdrfesieqcjbbkblboiduqltrbfjbmigseoushtardhislcnujegkicmlmodqeodsuqhnckcjdqdkfnqfqdupuqgpqukecalpqtjlhldhndrhpkliposegmkfojsqldehlibposfitdstlkhjqtrgkqmqbiuagmktpkcocfntbrjrpqostkepqanhbjbemneogtusjnajniudhtritdcrujkagbmofhehldokqprfadsbgdgcflbrgamdphoptgcqeujfbocobuoiqrjhbhomnlduldgegoejsgikbdqorqrjfmiohbmhijpfgkntuersdebapqcmskcblujeqnodaqcaphsuksdfgjlhmnfsgnpupfuartjfimqtksbdchfounolekpdotpspgoukcmrtsnqkdfjlcmclrapqdfkfjkedgirfpgjitijegqtpaprhnpljcidotmhdrfesieqcjbbkblboiduqltrbfjbmigseoushtardhislcnujegkicmlmodqeodsuqhnckcjdqdkfnqfqdupuqgpqukecalpqtjlhldhndrhpkliposegmkfojsqldehlibposfitdstlkhjqtrgkqmqbiuagmktpkcocfntbrjrpqostkepqanhbjbemneogtusjnajniudhtritdcrujkagbmofhehldokqprfadsbgdgcflbrgamdphoptgcqeujfbocobuoiqrjhbhomnlduldgegoejsgikbdqorqrjfmiohbmhijpfgkntuersdebapqcmskcblujeqnodaqcaphsuksdfgjlhmnfsgnpupfuartjfimqtksbdchfounolekpdotpspgoukcmrtsnqkdfjl"
预期结果:"cmclrapqdfkfjkedgirfpgjitijegqtpaprhnpljcidotmhdrfesieqcjkblboiduqltrbfjbmigseoushtardhislcnujegkicmlmodqeodsuqhnckcjdqdkfnqfqdupuqgpqukecalpqtjlhldhndrhpkliposegmkfojsqldehlibposfitdstlkhjqtrgkqmqbiuagmktpkcocfntbrjrpqostkepqanhbjbemneogtusjnajniudhtritdcrujkagbmofhehldokqprfadsbgdgcflbrgamdphoptgcqeujfbocobuoiqrjhbhomnlduldgegoejsgikbdqorqrjfmiohbmhijpfgkntuersdebapqcmskcblujeqnodaqcaphsuksdfgjlhmnfsgnpupfuartjfimqtksbdchfounolekpdotpspgoukcmrtsnqkdfjlcmclrapqdfkfjkedgirfpgjitijegqtpaprhnpljcidotmhdrfesieqcjkblboiduqltrbfjbmigseoushtardhislcnujegkicmlmodqeodsuqhnckcjdqdkfnqfqdupuqgpqukecalpqtjlhldhndrhpkliposegmkfojsqldehlibposfitdstlkhjqtrgkqmqbiuagmktpkcocfntbrjrpqostkepqanhbjbemneogtusjnajniudhtritdcrujkagbmofhehldokqprfadsbgdgcflbrgamdphoptgcqeujfbocobuoiqrjhbhomnlduldgegoejsgikbdqorqrjfmiohbmhijpfgkntuersdebapqcmskcblujeqnodaqcaphsuksdfgjlhmnfsgnpupfuartjfimqtksbdchfounolekpdotpspgoukcmrtsnqkdfjl"
时间:2021/10/10 01:15	

我自以为逻辑没有错误,结果提交之后发现有个奇怪的错误:
在这里插入图片描述

在这里插入图片描述

搞了好久也没明白为啥这两个地方的重复字符不会被删除……

不作妖了

算了,不琢磨上面那种写法了,简单一点吧……

遍历 s 中的字符,并用 result 栈来接收 s 中的字符。如果当前遍历字符和 result 栈顶元素相同,则弹出 result 栈顶元素,否则将当前遍历字符压入result 栈。

/**
 * @param {string} s
 * @return {string}
 */
var removeDuplicates = function(s) {
  let res = [];
  for(let i = 0; i < s.length; i++) {
    res[res.length-1] !== s[i] ? res.push(s[i]) : res.pop();
  }
  return res.join('');
};


提交记录
106 / 106 个通过测试用例
状态:通过
执行用时:88 ms, 在所有 JavaScript 提交中击败了59.08%的用户
内存消耗:47 MB, 在所有 JavaScript 提交中击败了58.85%的用户
时间:2021/10/10 01:55

可以看到时间表现还是好了很多的。可见 splice() 确实是性能很低。

官方题解

更新:2021年7月29日18:43:21

因为我考虑到著作权归属问题,所以【官方题解】部分我不再粘贴具体的代码了,可到下方的链接中查看。

更新:2021年10月10日24:37:55

参考:删除字符串中的所有相邻重复项 - 删除字符串中的所有相邻重复项 - 力扣(LeetCode)

【更新结束】

有关参考

更新:2021年10月10日24:38:20
参考:Array.prototype.splice() - JavaScript | MDN

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值