算法练习
来源:互联网 发布:网络写手已成高危职业 编辑:程序博客网 时间:2024/05/22 03:51
算法练习 - 栈
关于栈的使用,难度从简单到难
练习1LeetCode - 496. Next Greater Element I
class Solution(object): # 输入:两个无重复的数列nums1和nums2,其中nums1是nums2的一个子集。找出所有的nums中元素之后行下一个比其大的元素在nums2中的位置 # 输出:下一个较大位置的数列 # nums1 和 nums2 中的所有数都是独一无二的 # nums1 和 nums2 的大小不超过1000 # 如果暴力的做,就是遍历nums1然后在nums2中去找对应的比它大一位数的位置,时间复杂度O(n2) # nums1 和 nums2 中的所有数都是独一无二的,那么就说明 (数-位置) 形成了映射关系,这种映射关系可以在线性时间内完成 # 找到每个数的下一个大的数的序列,也就等于找到了位置序列 def nextGreaterElement(self, findNums, nums): """ :type findNums: List[int] :type nums: List[int] :rtype: List[int] """ # 设 d_next 为nums中数对应下一大数的映射关系 d = {} # 设 s 为一个空的栈 s = [] # 遍历 nums,当前元素为x: for x in nums: # 如果 s 不为空 且 栈顶 < x,在d中添加对应的映射关系,并将当前栈顶数出栈: while len(s) and s[-1] < x: d[s.pop()] = x # 否则,继续入栈 s.append(x) # 设 ans 为返回序列 ans=[] # 遍历 findnums ,x: for x in findNums: # 在d中查找对应的x是否存在映射关系: # 如果存在: # ans中添加当前x的对应的下一大 # 不存在: # ans中添加-1 ans.append(d.get(x,-1)) # 返回ans return ans
练习2 LeetCode - 173. Binary Search Tree Iterator
class BSTIterator(object): def __init__(self, root): """ :type root: TreeNode """ # 用栈来初始化 self.s = [] curNode = root while curNode: self.s.append(curNode) curNode = curNode.left # 判断是否存在下一个最小值 def hasNext(self): """ :rtype: bool """ # 如果s不为空,则返回栈顶 if len(self.s): return True else: return False # next 返回的是下一个最小值,也就是当前结点的左子节点 def next(self): """ :rtype: int """ curTop = self.s.pop() # 将下一个大小的入栈 if curTop.right: if curTop.right.left: temp = curTop.right while temp: self.s.append(temp) temp = temp.left else: self.s.append(curTop.right) return curTop.val
练习3 LeetCode - 341. Flatten Nested List Iterator
class NestedIterator(object): # 不能直接遍历的原因,可能嵌套很多层,如果每次都指定一个新的指针来控制list的迭代,而且你不知道到底深度为多少,算法复杂度会很高 def __init__(self, nestedList): """ Initialize your data structure here. :type nestedList: List[NestedInteger] """ # 首先逆序入栈 self.list = [] self.ans = [] for i in nestedList: self.list.append(i) # 利用栈的特性将数列展开 # 如果说队列为空,那么直接返回 if not len(self.list): return # 否则,将当前栈顶展开入栈 while len(self.list): # 如果栈顶元素存在且不是数字,而是数列 curNested = self.list.pop() if curNested and (not curNested.isInteger()): # 那么将数列展开,逆序入栈 for i in curNested.getList(): self.list.append(i) # 如果栈顶元素是数字,将栈顶元素的值输入一个list else: self.ans.append(curNested.getInteger()) def next(self): """ :rtype: int """ return self.ans.pop() def hasNext(self): """ :rtype: bool """ if len(self.ans): return True else: return False
我的方法是先全部展开,参考其他的答案,也每次获取下一个的时候展开,这样可以节约一定的空间,不过时间上的消耗也更多了
class NestedIterator(object): # 不能直接遍历的原因,可能嵌套很多层,如果每次都指定一个新的指针来控制list的迭代,而且你不知道到底深度为多少,算法复杂度会很高 def __init__(self, nestedList): """ Initialize your data structure here. :type nestedList: List[NestedInteger] """ # 首先逆序入栈 self.list = [] for i in reversed(nestedList): self.list.append(i) def next(self): """ :rtype: int """ return self.list.pop() def hasNext(self): """ :rtype: bool """ # 当 栈栈元素为一个数字 的时候,才能返回true while len(self.list): # cur 为 栈顶元素 cur = self.list[-1] # 如果栈顶元素为一个数字,返回返回真 if cur.isInteger(): return True # 否则 则说明当前栈顶为一个数列,展开数列 else: # pop出当前的cur cur = self.list.pop() # 并且逆序的填入栈中 for i in reversed(cur.getList()): self.list.append(i) # 然后继续循环 continue # 遍历到栈空,都没有数字,那就返回空 return False
练习4LeetCode - 331. Verify Preorder Serialization of a Binary Tree
class Solution(object): # 使用先序遍历来序列化一个二叉树,遇数计数,无数记 # # 判断给定的一个字符串,判断是否是一个二叉树先序序列化后的 def isValidSerialization(self, preorder): """ :type preorder: str :rtype: bool """ # 先序遍历的特点是 (自身 - 左 - 右) # 设 s 为一个栈 s = [] # 设 i 为 0 i = 0 # 将preorder转化为一个字符的list preorder = preorder.split(',') # 将 preorder第i个元素 入栈 s.append(preorder[i]) # 如果i小于preorder的size,则循环: for i in range(1,len(preorder)): # 判断不符合的情况,也就是按照出入栈规则无法继续的情况: # 当栈为空的时候,i 还未到 preorder 的边界 # 这种情况下,返回false if len(s) == 0: return False # 如果 当前栈顶 为空 且 如果 preorder[i] 也是空,那么: if len(s) == 1 and s[-1] == '#': return False if preorder[i] == '#': # 将当前的栈顶元素pop出,然后将新的栈顶元素也pop出 while len(s) and s[-1] == '#': s.pop() s.pop() # 并且将 空 入栈 s.append('#') # 否则: else: # 将preorder[i]入栈 s.append(preorder[i]) # 如果此时栈不为空,则返回false,否则返回true if len(s) > 1 or s[-1] != '#': return False else: return True
练习5 LeetCode - 503. Next Greater Element II
class Solution(object): """ 同样是找下一个大的数字,不过这次是一个循环列表 那么只有数列中最大的数(或者同样大小的几个数)为-1,其他的所有数都肯定是有一个比它大的数 并且最大数max之前的所有数肯定在一次循环之内可以找到下一个最大数,或者说在遍历到达max就可以找到下一个最大数 而max之后的数,第二遍循环到max的时候,也可以全部找到下一个最大数 也就是当最大的数只有一个的时候,遍历最多两遍可以找到所有下一大 当有多个最大值的时候呢? 想想数列被切分成了好几份,每两个最大值之间的数,一定可以找到最大值,而又是循环的,所以最后一个最大值之后的数字,都可以在第二次遍历到 第一个max之前找到 最重要的是如何判断要跳出循环,特别在多个最大值的时候 直观的来收,是在第二次遍历到最大值的时候,所以应该先用O(n)的时间找到最大值 然后记录遍历的次数,当遍历到第二遍,且已经为最大值的时候,跳出循环 应为存在相同的数不同的位置,所以这次要使用 (位置-下一大)的,也就是说需要一个值来保存当前栈顶的位置,然后每次找到直接在数组中表示出来 """ def nextGreaterElements(self, nums): """ :type nums: List[int] :rtype: List[int] """ # 如果数列的大小为0,返回空 if len(nums) == 0: return [] # 如果数列的大小为1,那么直接返回[-1] if len(nums) == 1: return [-1] # 遍历一次数组,找到最大值 max_nums max_nums = max(nums) # 设 c = 1 为循环的次数 c = 1 # 设 s_nums 为一个用于保存数字栈 s_nums = [] # 设 s_index 为一个用于保存对应数字位置的栈 s_index = [] # 设 ans 为最后的输出,一个所有元素都是-1的,长度和nums相同的数列 ans = [-1]*len(nums) # 设 i = 0 i = 0 # 遍历 nums,指针为i: while True: # 如果当前栈为空: if len(s_nums) == 0: # s_nums,s_index直接入栈nums[i] s_nums.append(nums[i]) s_index.append(i) i+=1 # 否则: elif s_nums[-1] == nums[i] and s_nums[-1] == max_nums: i+=1 else: # top 为栈顶 top = s_nums[-1] # 如果 top >= nums[i]: if top >= nums[i]: # s_nums 入栈 nums[i] s_nums.append(nums[i]) # s_index 入栈 i s_index.append(i) # i += 1 i += 1 # 如果 top < nums[i]: else: # s_nums,s_index出栈当前元素 top ,top_index s_nums.pop() # ans中将 top_index 设为 nums[i] ans[s_index.pop()] = nums[i] # 如果 i = len(nums): if i == len(nums): # i = 0,回到起始点 # c = 2 i,c = 0,2 # 如果 c = 2 且 nums[i] == max_nums 且 最终的栈内应该只包含最大值一个数 if c == 2 and nums[i] == max_nums and len(s_nums) == 1: # 跳出 break # 返回 ans return ans
大神的算法瞻仰,逻辑清晰,条例分明,说明还得练啊:
def nextGreaterElements(self, nums): # 同样是一个栈和一个等长的res列表 stack, res = [], [-1] * len(nums) # 循环了两遍,同时,简单的循环两遍,节省了很多逻辑 for i in range(len(nums)) * 2: # 如果 stack 为空,且 栈顶元素 的 大小 小于 nums【i】,则出栈 while stack and (nums[stack[-1]] < nums[i]): res[stack.pop()] = nums[i] # 它只用栈保存了位置index,然后通过nums[index]来获取对应的数,很聪明 stack.append(i) # 最后栈中应该全是最大的那个数 return res
阅读全文
0 0
- 【练习】经典算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 【算法练习】
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 算法练习
- 细说Wannacry勒索软件所使用的木马技术
- stm32_FSMC注意事项
- 安卓发布代码到 JCenter
- Android Kotlin 开发--初体验Demo
- 最长递增子序列(longest increasing subsequence) 问题详解
- 算法练习
- kettle安装
- MySQL高级 之 order by、group by 优化
- 海量处理用户日志(一)
- Comparing Hadoop, Spark, and Storm
- 软件设计目标—健壮性
- Oracle12C--索引表(三十二)
- Selenium错误提示
- Vue.js 中 v-if 和 v-show 有什么区别?