使用两个堆栈的解决方案

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用两个堆栈的解决方案相关的知识,希望对你有一定的参考价值。

我正在尝试Hackerrank的相同堆栈问题:https://www.hackerrank.com/challenges/equal-stacks/problem

有人可以帮我理解下面两个代码的逻辑差异。当第一个失败时,另一个成功:

首先(我的解决方案):

n1, n2, n3 = map(int, input().split())
H1 = list(map(int, input().split()))
H2 = list(map(int, input().split()))
H3 = list(map(int, input().split()))

sum_h1 = sum(H1)
sum_h2 = sum(H2)
sum_h3 = sum(H3)
#print (sum_h1,sum_h2,sum_h3)

while not (sum_h1 == sum_h2 and sum_h2 == sum_h3):
    if sum_h1 > sum_h2 or sum_h1 > sum_h3:
        #t = H1.pop()
        sum_h1 -= H1[0]
        #print ("Checking:",sum_h1)
    if sum_h2 > sum_h1 or sum_h2 > sum_h3:
        #t = H2.pop()
        sum_h2 -= H2[0]
    if sum_h3 > sum_h1 or sum_h3 > sum_h2:
        #t = H3.pop()
        sum_h3 -= H3[0]
print (sum_h1)

第二种解决方案(正确):

n1, n2, n3 = map(int, input().split())
H1 = list(map(int, input().split()))[::-1]
H2 = list(map(int, input().split()))[::-1]
H3 = list(map(int, input().split()))[::-1]

sum_h1 = sum(H1)
sum_h2 = sum(H2)
sum_h3 = sum(H3)
#print (sum_h1,sum_h2,sum_h3)

while not (sum_h1 == sum_h2 and sum_h2 == sum_h3):
    if sum_h1 > sum_h2 or sum_h1 > sum_h3:
        t = H1.pop()
        sum_h1 -= t
    if sum_h2 > sum_h1 or sum_h2 > sum_h3:
        t = H2.pop()
        sum_h2 -= t
    if sum_h3 > sum_h1 or sum_h3 > sum_h2:
        t = H3.pop()
        sum_h3 -= t
print (sum_h1)

我知道在第二个中我们正在反转输入数组。但是,这应该有什么不同。

我完全不解。

请帮我指出第一个代码的问题。

提前致谢。

答案

Order matters

我知道在第二个中我们正在反转输入数组。但是,这应该有什么不同。

是的,这有所不同。假设您有以下堆栈:

1
1  2  1
1  1  3

现在我们可以简单地从右侧堆栈中弹出1(粗体),并且所有堆栈都具有相同的高度。

但事实恰恰相反。如果堆栈相反:

1
1  1  3
1  2  1

我们必须弹出正确的堆栈,因为它是最大的堆栈。但我们只能从中弹出3(粗体字)。因此,最大高度只能是1。当我们弹出3时,我们稍后会发现,我们可以获得的最大相等高度是0。如果我们弹出正确的堆栈,我们获得:

1
1  1
1  2  1

但是中间的堆栈底部有2个。所以我们永远不能在中间产生1作为堆栈的总和。

堆栈意味着一个订单:在我们可以弹出该元素之前,我们必须删除圆柱体上方的元素,因此顺序很重要。

Why the first does not work.

在第一个代码片段中,从该堆栈的总和中减去第一个元素。但是你不从列表中删除该元素。因此,您不断从堆栈中弹出第一个元素。

您可以通过pop(0)修复它(从列表的开头弹出),或者稍后删除该元素:

# fix of the first code fragment

while not (sum_h1 == sum_h2 and sum_h2 == sum_h3):
    if sum_h1 > sum_h2 or sum_h1 > sum_h3:
        sum_h1 -= H1.pop(0)
        #print ("Checking:",sum_h1)
    if sum_h2 > sum_h1 or sum_h2 > sum_h3:
        sum_h2 -= H2.pop(0)
    if sum_h3 > sum_h1 or sum_h3 > sum_h2:
        sum_h3 -= H3.pop(0)

要么:

# fix of the first code fragment

while not (sum_h1 == sum_h2 and sum_h2 == sum_h3):
    if sum_h1 > sum_h2 or sum_h1 > sum_h3:
        sum_h1 -= H1[0]
        del H1[0]
        #print ("Checking:",sum_h1)
    if sum_h2 > sum_h1 or sum_h2 > sum_h3:
        sum_h2 -= H2[0]
        del H2[0]
    if sum_h3 > sum_h1 or sum_h3 > sum_h2:
        sum_h3 -= H3[0]
        del H3[0]

但请注意,这些都是低效的:从一开始就弹出一个O(n)操作,其中n是列表的大小。

另一答案

由于@Willem Van Onsem和@coldspeed解释了第一个解决方案与另一个解决方案的不同之处,我认为我可以解释一个更容易理解的类似解决方案(在我看来)。

假设堆栈与原始问题一样:

3 2 1 1 1  (stack1)
4 3 2      (stack2)
1 1 4 1    (stack3)

这里,最左边的数字是每个堆栈的顶部,最右边的数字是底部。我选择第一个堆栈作为参考堆栈(但它可以是三个中的任何一个)。去除圆柱体时可能的高度是8, 5, 3, 2, 1, 0。任务是尝试所有的高度,看看它们是否是常见的。然后,最大共同高度就是答案。

让我们从下到上解决问题。所以,堆栈是空的,我们想从头开始构建它们。在构建它们时,我们将找到其高度相等的所有堆栈配置。因此,具有最大高度的配置将是问题的答案。

  1. 最初,每个堆叠的最大公共高度以及当前高度是0 0 0 0 0 (max)
  2. 1添加到stack1的高度。然后,因为stack2的当前高度小于stack1的高度,所以通过对底部元素求和来增加它。为stack3做同样的事情 1 2 1 0 (max) 由于高度不同,最大值仍然是0。因此,1不能成为筹码的常见高度。
  3. 1添加到stack1的高度。 stack2的身高相等,所以不做任何事。对于stack3,只要高度较低,就要总结。 2 2 5 0 (max)
  4. 3 5 5 0 (max)
  5. 3 5 5 0 (max)
  6. 5 5 5 5 (max)
  7. 8 9 10 5 (max)
  8. 输出最大高度,因为第一个堆栈是空的,与其他堆栈一起工作是没有意义的(如果它们仍然是非空的)。 5 (max)

现在,算法本身(为了简单起见,在Python3中):

n, m, k = map(int, input().split())
stack1 = list(map(int, input().split()))
stack2 = list(map(int, input().split()))
stack3 = list(map(int, input().split()))

max_height = 0
height1 = 0
height2 = 0
height3 = 0

while len(stack1) > 0:
    if len(stack1) > 0:    
        height1 += stack1.pop() 
    while len(stack2) > 0 and height2 < height1:
        height2 += stack2.pop()        
    while len(stack3) > 0 and height3 < height1:
        height3 += stack3.pop()  

    if height1 == height2 == height3:
        max_height = height1     

print (max_height)  
另一答案

您的解决方案与正确的解决方案之间的区别在于您的堆栈是相反的。在这种情况下,您应该调用list.pop(0)来删除第一个元素。

while not (sum_h1 == sum_h2 and sum_h2 == sum_h3):
    if sum_h1 > sum_h2 or sum_h1 > sum_h3:
        t = H1.pop(0) # -------------- pop 0th element 
        sum_h1 -= t  
    if sum_h2 > sum_h1 or sum_h2 > sum_h3:
        t = H2.pop(0)  # -------------- pop 0th element 
        sum_h2 -= t
    if sum_h3 > sum_h1 or sum_h3 > sum_h2:
        t = H3.pop(0)  # -------------- pop 0th element 
        sum_h3 -= t
print (sum_h1)

对于此输入:

5 3 4
3 2 1 1 1
4 3 2
1 1 4 1

这是输出:

5

以上是关于使用两个堆栈的解决方案的主要内容,如果未能解决你的问题,请参考以下文章

添加到后台堆栈时如何保持片段状态?

添加到后台堆栈时如何维护片段状态?

代码适用于与单个 html 文件不同的堆栈片段

使用两个堆栈的解决方案

在后台堆栈中多次防止相同的片段

来自后台堆栈的片段 onResume