【问题标题】:Solution of working with two stacks使用两个堆栈的解决方案
【发布时间】:2017-11-27 20:28:55
【问题描述】:

我正在尝试来自 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)

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

我完全不解。

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

提前致谢。

【问题讨论】:

    标签: python math stack


    【解决方案1】:

    由于@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)  
    

    【讨论】:

      【解决方案2】:

      您的解决方案与正确解决方案之间的区别在于您的堆栈是相反的。在这种情况下,您应该调用 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
      

      【讨论】:

        【解决方案3】:

        订单事项

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

        是的,这有所作为。假设您有以下堆栈:

        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 作为中间堆栈的总和。

        堆栈意味着顺序:我们必须先移除圆柱体上方的元素,然后才能弹出该元素,因此顺序很重要。

        为什么第一个不起作用。

        在第一个代码片段中,您从该堆栈的总和中减去第一个元素。但是您确实不会从列表中删除该元素。结果,您不断地从堆栈中弹出 first 元素。

        您可以通过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 是列表的大小。

        【讨论】:

        • 您的逻辑是正确的,除了在 OP 的解决方案中,他正在索引 H[0],所以他仍然减去 1。我认为顺序不是问题。 OP 没有打电话给H.pop(0)
        • @Coldspeed: 但pop() 从列表的右侧弹出(因此是堆栈的顶部)。这就是为什么第一个失败而第二个成功的原因。
        • pop(0) 从一开始就弹出。在 OP 的堆栈反转的情况下,pop(0) 是正确的操作,OP 没有这样做(据我所见)。 &gt;&gt;&gt; x = [1, 2, 3]; &gt;&gt;&gt; x.pop(0); 1
        • @Coldspeed:我没有注意到第一个代码片段中的列表没有反转。固定。
        猜你喜欢
        • 2015-10-08
        • 2019-02-25
        • 2014-07-21
        • 2019-05-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多