剑指offer系列-面试题31-栈的压入、弹出序列(python)

文章目录

  • 1. 题目
  • 2. 解题思路
  • 3. 代码实现
  • 4. 总结
  • 5. 参考文献

1. 题目

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列{1,2,3,4,5}是某栈的压栈序列,序列{4,5,3,2,1}是该压栈序列对应的一个弹出序列,但{4,3,5,1,2}就不可能是该压栈序列的弹出序列。

2. 解题思路

多举举例子,找到规律,也就是代码的逻辑。
建立一个辅助栈,把输入的第一个序列中的数字依次压入该辅助栈,并按照第二个序列的顺序依次从该栈中弹出数字

分析弹出序列,
如果辅助栈的栈顶数字等于弹出序列中的当前元素,那么直接弹出,弹出序列指针右移
如果弹出序列中的当前数字不在栈顶,则把压栈序列中还没有入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶位置
如果所有数字都压入栈后仍然没有找到下一个弹出的数字,那么该序列不可能是一个弹出序列。

3. 代码实现

# 定义栈类
class Stack(object):
     # 初始化栈为空列表
    def __init__(self):
        self.values = []
    # 向栈顶压入一个新数据项
    def push(self, value):
        self.values.append(value)
    # 返回栈顶元素,并删除
    def pop(self):
        return self.values.pop()
    # 判断栈是否为空
    def is_empty(self):
        return self.size() == 0
    # 返回栈的大小
    def size(self):
        return len(self.values)
    # 返回栈顶数据项,但不删除。
    def peak(self):
        return self.values[self.size()-1]
    
def is_pop_order(push_list, pop_list):
    # 是否是压栈序列的弹出序列,默认不是
    possible = False 
    # 建立一个辅助栈
    stack_data = Stack()
    i = 0 # 指向压入序列的指针
    j = 0 # 指向弹出序列的指针
    
    if push_list and pop_list and len(push_list) == len(pop_list):
        # 外层循环控制的是,弹出序列的指针移动
        while j < len(pop_list):
                # 内层循环控制的是,栈顶元素是谁,是否需要将元素压入栈中
                # 当栈为空,或者辅助栈的栈顶数字不等于弹出序列中的当前元素时,向辅助栈中压入数字
                while stack_data.is_empty() or stack_data.peak() != pop_list[j]:
                    # 在辅助栈中压入一个数字,然后判断这个数字是否是弹出序列中的第一个数字,
                    # 是,表明此数字作为栈顶弹出过?否,则继续压入数字?
                    if i < len(push_list):
                        print("当前压入序列元素{}".format(push_list[i]))
                        stack_data.push(push_list[i])
                        i += 1
                    else:
                        # return False
                        print("已经遍历完压栈序列")
                        break
                # 什么原因退出的内层while循环
                if stack_data.peak() != pop_list[j]: # 不是因为stack_data.peak() == pop_list[j]而退出的内层循环
                    print("辅助栈的栈顶元素{}, 弹出序列当前元素{}".format(stack_data.peak(), pop_list[j]))
                    break
                # 是因为stack_data.peak() == pop_list[j]而退出的内层循环
                res_pop = stack_data.pop()
                print("栈顶元素{}等于弹出序列当前元素,弹出该元素, 同时弹出指针右移一位".format(res_pop))
                j += 1
        # 最后,只有当辅助栈中没有元素了,且指针已经指向了弹出序列的末尾时,才能确定这个弹出序列是此压入序列的一个弹出序列。
        # 防止辅助栈的长度大于或小于弹出序列的长度    
        if stack_data.is_empty() and j == len(pop_list):
            possible = True
            
    return possible
                    

if __name__ == '__main__':
    push_list = [1, 2, 3, 4, 5]
    pop_list = [4, 5, 3, 1, 2]
    result = is_pop_order(push_list, pop_list)
    print(result)

4. 总结

在应对栈相关的问题时,首先是举例子,然后画图,找出思路,最后才写代码。而且,这类问题常常需要使用辅助栈。

5. 参考文献

[1] 剑指offer丛书

你可能感兴趣的:(算法)