剑指offer解题思路简述 31-40

  • 面试题31:栈的压入,弹出序列

方法:先判断特殊情况,如果栈1为空或者两个栈的长度不相等的话,直接return False,设置一个辅助栈,设置一个for循环,每次将栈1的数据压入到辅助栈中,然后设置一个while循环,判断辅助栈当前的栈顶元素是否等于栈二的最前面数,如果相等,两个栈都调用pop,一直循环到不等,最后到退出for循环,判断栈1是否为空,如果不是空,return False。

class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        if not pushV or len(pushV) != len(popV):
            return False
        stack = []
        for i in pushV:
            stack.append(i)
            while len(stack) and stack[-1] == popV[0]:
                stack.pop()
                popV.pop(0)
        if len(stack):
            return False
        return True
  • 面试题32:从上到下打印二叉树

方法一:设置一个队列,while循环,挨个取出队列里的数,将它的左右节点挨个放入队列的尾部,停止条件是队列是否为空。

#建立一个队列
def levelorder(root):
    if root==None:
        return
    else:
        queue = [root]
        ree = []
        while queue:
            node = queue.pop(0)
            res.append(node.val)
            if node.left:
                queue.append(node.left) 
            if node.right:
                queue.append(node.right)
        return res

方法:需要在上面思路的基础上,while里面需要一个for循环

class Solution:
    def levelOrder(self, root):
        if not root: return []
        res, queue = [],[]
        queue.append(root)
        while queue:
            tmp,tmpnode = [],[]
            for node in queue:
                tmp.append(node.val)
                if node.left: tmpnode.append(node.left)
                if node.right: tmpnode.append(node.right)
            queue = tmpnode
            res.append(tmp)
        return res

class Solution:
    def levelOrder(self, root):
        if not root: return []
        res = []
        stack1 =[]
        stack2 = []
        tmp = []
        stack1.append(root)
        while stack1 :
            # 打印奇数层
            for _ in range(len(stack1)):
                # 从左向右打印
                node = stack1.pop()
                tmp.append(node.val)
                # 先左后右加入下层节点
                if node.left: stack2.append(node.left)
                if node.right: stack2.append(node.right)
            res.append(tmp)
            stack1 = []
            tmp = []
            if not stack2: break # 若为空则提前跳出
            # 打印偶数层
            for _ in range(len(stack2)):
                # 从右向左打印
                node = stack2.pop()
                tmp.append(node.val)
                # 先右后左加入下层节点
                if node.right: stack1.append(node.right)
                if node.left: stack1.append(node.left)
            res.append(tmp)
            srack2 = []
            tmp = []
        return res
  • 面试题33:二叉搜索树的后序遍历

方法:二叉搜索树的特点是跟节点的左边都比跟节点的值要小,右边都比它大,后序遍历中,根节点永远在最后,前半部分的值小于跟节点,右边部分的值大于跟节点,所以采用递归,每次取出该部分的最后一个数作为跟节点,将剩下的数分成两部分,如果存在不符合条件的直接return false。

class Solution(object):
    def verifyPostorder(self, postorder):
        if not postorder:
            return True
        root = postorder[-1]
        length = len(postorder)
        for i in range(length): # 找到左子树的区间,此时注意下这样的切分不可能出现左子树中的节点比根节点大
            if postorder[i] > root:
                break      
        for j in range(i, length-1):# 如果右子树中存在比根节点的小的值,那么是不符合条件的
            if postorder[j] < root:
                return False
        left = self.verifyPostorder(postorder[:i])#判断左子树是否符合条件
        right = self.verifyPostorder(postorder[i:-1])#判断右子树是否符合条件
        return left and right

  • 面试题34:二叉树中和为某一值的路径

方法:创建一个子函数dfs([], root, expectNumber, res),[]里存放每条路径,res存在符合条件的路径,每次调用self.dfs(list(path), root.left, expectNumber - root.val, res)把期望值减去当前的root值

class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        # write code here
        res = []
        if root:
            self.dfs([], root, expectNumber, res)
        return res
    def dfs(self, path, root, expectNumber, res):
        path.append(root.val)
        if (root.val == expectNumber) and (not root.left) and (not root.right):
            res.append(path)
        if root.left:
            self.dfs(list(path), root.left, expectNumber - root.val, res)
        if root.right:
            self.dfs(list(path), root.right, expectNumber - root.val, res)
  • 面试题35:复杂链表的复制

方法一:先复制一份前向链表,利用格外的存储空间建立每个note的哈希对,然后搜索原链表,找到m_pSibling的指向节点,对应的在新链表上添加,太难了!!!

方法二;在原始链表上复制一份一模一样的前向链表,得到a1-a2-c1-c2-d1-d2-w1-w2,然后若a1.m_pSibling=w1,a1.next.m_pSibling=w1.next,这样就可以把所有节点之间的关系全部复制,最后将列表拆成两部分

class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        if not pHead:return None
        cur = pHead
        #insert new node between origin listnode
        while cur:
            tmp = RandomListNode(cur.label)
            tmp.next = cur.next
            cur.next = tmp
            cur = tmp.next
        cur  = pHead
        # find the random
        while cur:
            tmp = cur.next
            if cur.random:
                tmp.random = cur.random.next
            cur = tmp.next
        # to two listNode
        cur = pHead
        res = pHead.next
        while cur.next:
            tmp = cur.next
            cur.next = tmp.next
            cur = tmp
        return res

方法三:python的深拷贝:copy.deepcopy(head)

  • 面试题36:二叉搜索树和双向链表

方法:先中序遍历,把结果存到链表中,然后挨个节点遍历,for i,v in enumerate(self.arr[:-1]): v.right = self.arr[i + 1]  self.arr[i + 1].left = v

class Solution:
    def Convert(self, pRootOfTree):
        # write code here
        if not pRootOfTree:return
        self.arr = []
        self.midTraversal(pRootOfTree)
        for i,v in enumerate(self.arr[:-1]):
            v.right = self.arr[i + 1]
            self.arr[i + 1].left = v
        return self.arr[0]
    def midTraversal(self, root):
        if not root: return
        self.midTraversal(root.left)
        self.arr.append(root)
        self.midTraversal(root.right)
  • 面试题38:序列化二叉树

方法:序列化就是层序遍历,稍微有些不同在于,不需要判断左右节点是否有值直接append,当对每个节点处理时需要判断是否是空,是的话直接输出null;反序列化,需要挨个点遍历,设置一个i记录当前节点的位置

class Codec:   
    def serialize(self, root):
        res = []
        listnode = [root]
        while listnode:
            tmp = []
            for i in listnode:
                if i:
                    res.append(i.val)
                    tmp.append(i.left)
                    tmp.append(i.right)
                else:
                    res.append('null')
            listnode = tmp     
        return '[' + ( ','.join(str(i) for i in res) )+ ']'

    def deserialize(self, data):
        if data == '[]': return
        vals, i = data[1:-1].split(','), 1
        root = TreeNode(int(vals[0]))
        queue = collections.deque()
        queue.append(root)
        while queue:
            node = queue.popleft()
            if vals[i] != "null":
                node.left = TreeNode(int(vals[i]))
                queue.append(node.left)
            i += 1
            if vals[i] != "null":
                node.right = TreeNode(int(vals[i]))
                queue.append(node.right)
            i += 1
        return root
  • 面试题39:数组中出现次数超过一半的数字

方法:要找的数字出现的次数比其他所有数字出现次数之和还要多,所以可以把当前数字存下,如果重复出现则次数加一,如果出现的不一样则次数减一,如果次数为0,则保存下新来的数字,次数加一,最后剩下保存的数字即为需要的数字

# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        count = 0
        for i in numbers:
            if count==0:
                temp = i
                
            if i == temp:
                count = count+1
            else:
                count= count-1
        return temp
  • 面试题40:最小的K个数

方法一:O(n),但是需要修改原始数组,快排的思路,while循环的终止条件是index=k-1

class Solution(object):
    def getLeastNumbers(self, arr, k):
        """
        :type arr: List[int]
        :type k: int
        :rtype: List[int]
        """
        # 方法一:partition方法(基于快速排序)
        if k > len(arr) or k <= 0:
            return [] 
        start = 0
        end = len(arr) - 1
        index = self.quickSort(arr, start, end)
        while index != k-1:
            if index > k-1:
                end = index - 1
                index = self.quickSort(arr, start, end)
            if index < k-1:
                start = index + 1
                index = self.quickSort(arr, start, end)
        return arr[:k]

    def quickSort(self, arr, left, right):
        flag = left
        tmp=arr[left]
        while left<right:
            while left<right and arr[right]>=tmp:  #第一步:找右边比左边tmp小的数,移动右边i ndex
                right=right-1   
            while left<right and arr[left]<=tmp:   #第三步:找左边比起大的数,移动左边index
                left=left+1
            arr[right],arr[left] =arr[left],arr[right]   #第四步 左边移到右边
        arr[left],arr[flag]=arr[flag],arr[left]   #标志位和当前的left换
        return left

方法二:O(nlogn),特别适用的大规模数据,容器里放k个数,并记录当前最大的数,当新数来的时候进行比较,若小则替换。基于大根堆可以在O(1)时间得到k个数的最大值,nlogn的时间完成最大值的删除和插入。

 

 

           

           

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值