输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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个就是不输出的意思