【问题标题】:Solving String reduction Algorithm解决字符串缩减算法
【发布时间】:2012-05-26 13:00:06
【问题描述】:

我正在为周一的面试做准备,我发现这个问题需要解决,称为“String Reduction”。问题是这样表述的:

给定一个由 a、b 和 c 组成的字符串,我们可以执行以下操作 操作:取任意两个相邻的不同字符并替换它 与第三个字符。例如,如果 'a' 和 'c' 相邻, 他们可以用'b'代替。最小的字符串是多少 反复应用这个操作的结果?

例如 cab -> cc 或 cab -> bb,产生一个长度为的字符串 2. 对于这个,一个最优解是:bcab -> aab -> ac -> b。无法应用更多操作,结果字符串的长度为 1。 如果字符串为 = CCCCC,则无法执行任何操作,因此 答案是 5。

我在 stackoverflow 上看到了很多 questions and answers,但我想验证我自己的算法。这是我的伪代码算法。在我的代码中

  1. S 是我要减少的字符串
  2. S[i] 是索引 i 处的字符
  3. P 是一个堆栈:
  4. redux 是减少字符的函数。

    function reduction(S[1..n]){        
    P = create_empty_stack();
    for i = 1 to n
    do
       car = S[i];
       while (notEmpty(P))
       do
          head = peek(p);
          if( head == car) break;
          else {
             popped = pop(P);
             car = redux (car, popped);
           }  
       done
       push(car)
    done
    return size(P)}
    

我的算法的最坏情况是 O(n),因为堆栈 P 上的所有操作都在 O(1) 上。我在上面的例子中尝试了这个算法,我得到了预期的答案。 让我用这个例子“abacbcaa”执行我的算法:

i = 1 :
   car = S[i] = a, P = {∅}
   P is empty, P = P U {car} -> P = {a}

 i = 2 :
   car = S[i] = b, P = {a}
   P is not empty :
       head = a
       head != car ->
            popped = Pop(P) = a 
            car = reduction (car, popped) = reduction (a,b) = c
            P = {∅}

    push(car, P) -> P = {c}



i = 3 :
   car = S[i] = a, P = {c}
   P is not empty :
       head = c
       head != car ->
            popped = Pop(P) = c 
            car = reduction (car, popped) = reduction (a,c) = b
            P = {∅}

    push(car, P) -> P = {b}


 ...


 i = 5 : (interesting case)
  car = S[i] = c, P = {c}
   P is not empty :
       head = c
       head == car -> break

    push(car, P) -> P = {c, c}


 i = 6 :
  car = S[i] = b, P = {c, c}
   P is not empty :
       head = c
       head != car ->
            popped = Pop(P) = c 
            car = reduction (car, popped) = reduction (b,c) = a
            P = {c}

   P is not empty : // (note in this case car = a)
       head = c
       head != car ->
            popped = Pop(P) = c 
            car = reduction (car, popped) = reduction (a,c) = b
            P = {∅}
    push(car, P) -> P = {b}

... and it continues until n

我已经在这样的各种示例上运行了这个算法,它似乎有效。 我用 Java 编写了一个代码来测试这个算法,当我将代码提交给系统时,我得到了错误的答案。我已经在gisthub 上发布了java 代码,所以你可以看到它。

谁能告诉我我的算法出了什么问题。

【问题讨论】:

  • 它要求最小的字符串,那么这意味着如果有不止一种方法可以减少字符串,你必须找到它。你好像只搜索第一种还原方式,当然会失败。有时,不使用规则并等待更多字符出现可能会产生更好的结果。
  • @acattle 是的,但仅在第一种情况下,第一个字符。在每个 for 循环中,堆栈至少有一个字符。
  • @nhahtdh 你能说得更具体点吗??
  • 我认为不可能获得O(n)算法...
  • 这个简单的算法可能有用jsfiddle.net/YFw4G JavaScript 很容易理解

标签: java algorithm pseudocode


【解决方案1】:

我将尝试解释nhahtdh 的含义。您的算法失败的原因有多种。但最基本的一点是,在每个时间点,只有观察到的第一个字符才有机会被压入堆栈p。不应该这样,因为您基本上可以从任何位置开始减少。

让我给你字符串abcc。如果我在

处断点
car = S[i];

算法运行为:

p = {∅}, s = _abcc //underscore is the position
p = {a}, s = a_bcc  
p = {c}, s = ab_cc  

此时你被困在减少ccc

但还有另一个减少:abcc -> aac ->ab ->c

此外,返回堆栈大小P 是错误的。 cc 不能减少,但是 该算法将返回1。您还应该计算您跳过的次数。

【讨论】:

  • 没有。您需要涵盖所有情况。对于大小为n 的给定字符串,有n-1 redux 导致n-1 大小为n-1 的字符串。这导致了一个n!复杂性,这是灾难性的。必须有一种方法(动态编程等)来降低这种复杂性。
【解决方案2】:

你也可以使用蛮力...和递归来解决这个问题

for all n-1 pairs(2 char) replace it with 3rd char if possible and apply reduce on this new string of length n-1
    for all n-2 pairs replace it with 3rd char and apply reduce on new string
         for all n-3 pairs....and so on

长度为 n-1 的新字符串将有 n-2 对,类似地,长度为 n-2 的新字符串将有 n-3 对。

在应用这种方法时,保持存储最小值

if (new_min < min)
    min = new_min

实现:http://justprogrammng.blogspot.com/2012/06/interviewstreet-challenge-string.html

【讨论】:

    猜你喜欢
    • 2012-01-23
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-22
    • 2012-12-09
    • 1970-01-01
    • 2011-08-27
    相关资源
    最近更新 更多