从数组中删除重复的字符

时间:2019-08-25 23:09:51

标签: algorithm

Got在采访中问了这个问题,找不到解决方案。 给定一个字符数组,删除连续重复k次或更多次的所有字符,并为每个删除的字符在数组末尾添加“#”。  示例:

“ xavvvarrrt”->“ xaat ######”

O(1)的内存和O(n)的时间而没有两次写入同一单元。

对我来说,棘手的部分是不允许我多次覆盖一个单元格,这意味着我需要确切知道每个字符在删除重复项之后将移动的位置。 我能想到的最好的方法是在数组上迭代一次,然后将每个字符的出现保存在映射中,然后再次迭代并检查是否未删除当前字符,然后根据偏移量将其移动到新位置。删除它,然后更新偏移量变量。 这种方法的问题在于,在这种情况下将无法使用: “ aabbaa”,因为“ a”出现在两个不同的位置。 因此,当我考虑在地图中保存一系列事件时,现在却不使用O(1)内存。

谢谢

3 个答案:

答案 0 :(得分:2)

这似乎适用于您的示例,尽管对我来说似乎有点复杂:)我想知道我们是否可以简化它。基本思想是从左到右遍历,记录当前重复块中有多少地方仍可替换,而右指针则需要查找更多的块。

JavaScript代码:

function f(str){
  str = str.split('')
  let r = 1
  let l = 0
  let to_fill = 0
  let count = 1
  let fill = function(){
    while (count > 0 && (to_fill > 0 || l < r)){
      str[l] = str[r - count]
      l++
      count--
      to_fill--
    }
  }
  for (; r<str.length; r++){
    if (str[r] == str[r-1]){
      count++
        
    } else if (count < 3){
      if (to_fill)
        fill()
      count = 1
      if (!to_fill)
        l = r

    } else if (!to_fill){
      to_fill = count
      count = 1
      
    } else {
      count = 1
    }
  }
 
  if (count < 3)
    fill()
  
  while (l < str.length)
    str[l++] = '#'

  return str.join('')
}

var str = "aayyyycbbbee"
console.log(str)
console.log(f(str)) // "aacee#######"

str = "xavvvarrrt"
console.log(str)
console.log(f(str)) // "xaat######"

str = "xxaavvvaarrrbbsssgggtt"
console.log(str)
console.log(f(str))

答案 1 :(得分:1)

以下是与the other JS answer类似的版本,但更简单:

function repl(str) {
    str = str.split("");
    var count = 1, write = 0;

    for (var read = 0; read < str.length; read++) {
        if (str[read] == str[read+1])
            count++;
        else {
            if (count < 3) {
                for (var i = 0; i < count; i++)
                    str[write++] = str[read];
            }
            count = 1;
        }
    }

    while (write < str.length)
        str[write++] = '#';

    return str.join("");
}

function demo(str) {
    console.log(str + " ==> " + repl(str));
}

demo("a");
demo("aa");
demo("aaa");
demo("aaaaaaa");
demo("aayyyycbbbee");
demo("xavvvarrrt");
demo("xxxaaaaxxxaaa");
demo("xxaavvvaarrrbbsssgggtt");

/*
Output:
a ==> a
aa ==> aa
aaa ==> ###
aaaaaaa ==> #######
aayyyycbbbee ==> aacee#######
xavvvarrrt ==> xaat######
xxxaaaaxxxaaa ==> #############
xxaavvvaarrrbbsssgggtt ==> xxaaaabbtt############
*/

这个想法是保留当前索引以读取下一个字符和一个索引以供写入,以及连续重复的字符数。如果后面的字符等于当前字符,我们只需增加计数器。否则,我们将复制所有小于3的字符,从而适当增加写索引。

在读取结束时,从当前写入索引到数组结尾的所有内容都是我们已跳过的重复字符数。我们现在只用散列填充。

由于我们仅存储3个值,因此内存消耗为O(1);我们读取每个数组单元两次,因此是O(n)时间(写入时多余的读取可以被另一个变量消除);每个写索引仅被访问一次。

答案 2 :(得分:-2)

从此开始:https://www.geeksforgeeks.org/remove-consecutive-duplicates-string/

还要看看这个:https://www.geeksforgeeks.org/recursively-remove-adjacent-duplicates-given-string/

如果您准确记录每次交换的次数,那么在末尾加上“#”应该是微不足道的。