剑指offer—栈最后一题(判断栈的弹出顺序是否是该栈的一种)(链表1:基本概念及python描述,单链表倒叙输出,倒叙存储,倒叙输出第k个)

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

  • 本题目刚开始读的时候没有读懂,后来才读懂,那么当时思路就是:直接判断好像不太好处理,每一个stack的pop序列情况有好多种,如何确定某一个序列是不是pop可能的序列呢?总不能暴力把所有的序列都找出来再判断吧。正当一筹莫展之际,忽然想起来,能不能正向判断:所谓的正向判断,就是如果我们自己再处理一个stack的时候,面队一个元素,我们有2种情况,第一种就是压入、第二种就是弹出已有的前面元素,不久是这两种吗?
  • 所以先把元素push进来,之后就是比较这个元素个pop队列里面的元素一致不,如果一致,说明这个元素被压进去之后又弹了出来,此时压入的元素pop出这个元素,同时popV这个list里面也pop出第一个元素;如果不一致,说明,此时该元素被压入了栈中,还没等到该元素弹栈的时候;
  • 之后继续比较压入栈的末端元素和popV的第一个元素是否相等,如果相等就一致采取上述的第一条,二者均弹栈,如果不想等,就直接继续压栈,如果二者最后匹配,那么二者的长度都变成了0,因为都pop完了,没东西了。
  • 这就是正向思考,而不用直接反向去判断到底popV是不是pushV的一个pop序列,这种思维很重要。
     def IsPopOrder(self, pushV, popV):
            # write code here
            pushV_copy = []
            i = 0
            while i < len(pushV):
                pushV_copy.append(pushV[i])
                while True:
                    if pushV_copy[-1] == popV[0]:
                        pushV_copy.pop()
                        popV.pop(0)
                        if len(popV) == 0:   # 防止popV没有元素了,还在pop,就溢出了
                            return True
                    else:
                        break
                i += 1
            return False

    这是python代码

  • class Solution {
    public:
        bool IsPopOrder(vector<int> pushV,vector<int> popV) {
            vector<int> pushV_copy;
            int i = 0;
            while(i < pushV.size()){
                pushV_copy.push_back(pushV[i]);
                while(true){
                    if (pushV_copy.back() == popV.front()){
                        pushV_copy.pop_back();
                        popV.erase(begin(popV));
                        if(popV.size() == 0)   return true;
                    }
                    else break;
                }
                i++;
            }
            return false;
        }
    };

    这是C++代码

链表的基本知识python

  • 再开始链表的概念之前,先对链表的基本内容进行一些阐述。
  • 链表在python中,首先说明不像数组、栈、队列那样可以直接用list表示,这里的链表首先说明是需要自己定义class类来构造节点,需要自己定义的。
  • 我们需要掌握的仅仅是三种链表:一种是单链表,最后的一个节点的next = None; 第二种是单循环列表,就是在第一种单链表的基础上再最后一个节点的next指向了开始节点; 第三种就是双向链表,就是再第一种从左向右的基础上,加上了从右向左的方向,注意从右向左的最开始节点的frort = None,只要记住这三点就行。
  • 具体可以看视屏的那个图

这里补充说明关于list动态扩容的机理

  • 说明C++里面vector的扩充机理:先开辟一定的内存,将需要push_back的数据放进去,如果容量够了之后,再申请当前内存的几倍,然后把前面的数据拷贝进来,然后把这边的小内存释放,这就是动态扩容的机理。
  • 而python里面的list的扩容个和上述基本的差不多,只不过不是释放前面的,是当内存不够时,新开辟内存。然后用前面的内存的位置指向新的内存,这样就连起来了,本质上时一个链表,这就是这二者的不同之处。

对于单链表的几种题目:倒叙打印、倒叙形成list、倒叙打印第K个节点(节点的值)

  • 处理这种题目首先一定要明白:单链表的遍历只能从头到尾进行遍历。
  •      1:对于倒着打印,可以用list,可以用stack,也可以递归处理
  •      2:对于形成数组:只能用list,stack
  •      3:对于打印倒数第K个,这个时重点,它当然可以list,stack,但是从缩小时间复杂度的角度来说,只要一个变量就可以。
  • 下面针对上述的几种关于单链表的题目,给出代码以及一定的分析。

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

  • def printListFromTailToHead(self, listNode):
            # write code here
            daoxu = []
            Temp = listNode
            while Temp:
                daoxu.append(Temp.val)
                Temp = Temp.next
            return list(reversed(daoxu))
    
    
            # 这里要注意第一点,reversed反转之后,生成一个迭代器,要想生成元素,必须显示的转化
    
    
            # 注意:list.reverse()是在本地做的修改,所以先reverse(),之后需要单独返回list,
            # 而不能直接返回list.reverse(),直接返回结果是None
    
    
            # 为了保持头节点的记忆,我们不直接使用传进来的头节点,而是将其复制给另外的一个变量,这点注意
            # 传进来的这个就是类的实例,所以不是None,只要有东西就不是None

     

输入一个链表,输出该链表中倒数第k个结点。

  • def FindKthToTail(self, head, k):
        # write code here
        if k == 0:
            return None
        daoxu = []
        Temp = head
        while Temp:
            daoxu.append(Temp)
            Temp = Temp.next
        return None if len(daoxu) < k else daoxu[-k]
    
    
    # 可以时可以,但是空间复杂度高

    下面时只用一个变量

  • def FindKthToTail(self, head, k):
            # write code here
            Temp  = head
            Temp_copy = head
            shunXu = 1
            while Temp:
                if shunXu > k:
                    Temp_copy = Temp_copy.next
                Temp = Temp.next
                shunXu += 1
            return Temp_copy if shunXu > k else None
                
        # 本题需要注意两个点:第一:人家让输出节点,不是节点的值,这一点要注意,不是节点的值就可能没有val这个属性,本题就是这样
    
    
        # 其次,当K == 0,则return None,这点要注意。因为倒数第0个就是不输出的意思

     

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值