剑指offer: 剩下的题

字符串的排列


  • 问题描述: 输入一个字符串,返回字符串中字符的字典序排列
  • 解题思路:每次固定一个字符,递归增加后续字符,性能最差。采用交换替代直接遍历增加,最后仍需去重。考虑需要字典序的排列,也可以用字典排序算法。
# 递归、交换 => 排序
class Solution:
    def Permutation(self, charseq):
        if not charseq:
            return []
        result = set()
        maxn = len(charseq)
        def recur(i,cur):
            if i >= maxn:
                result.add(''.join(cur))
            else:
                for j in range(i,maxn):
                    if i!=j  and cur[i]==cur[j]:
                        continue
                    cur[i],cur[j] = cur[j],cur[i]
                    recur(i+1,cur)
                    cur[i], cur[j] = cur[j], cur[i]
        recur(0,list(charseq))
        return list(sorted(result))
# 字典排序算法
class Solution:
    def Permutation(self, charseq):
        if not charseq:
            return []
        charseq = sorted(list(charseq))
        result = list()
        result.append(''.join(charseq))
        maxn = len(charseq)
        i = maxn - 1
        while True:
            while i and charseq[i] <= charseq[i-1]:
                i -= 1
            if not i: break
            j = maxn-1
            while j > i and charseq[j] <= charseq[i-1]:
                j -= 1
            charseq[i-1],charseq[j] = charseq[j],charseq[i-1]
            charseq[i:] = reversed(charseq[i:])
            result.append(''.join(charseq))
            i = maxn - 1
        return result

变态跳台阶


  • 问题描述:跳台阶的升级版,青蛙可以跳任意正数<=n的步数
  • 解题思路:递推,为了支持跳n步,增加dp[0]=1即可
class Solution:
    def __init__(self):
        self.__dp = list()
        self.__n = 50
        for i in range(self.__n):
            if i < 1:
                self.__dp.append(1)
            else:
                fib_sum = 0
                for j in range(i-1,-1,-1):
                    fib_sum += self.__dp[j]
                self.__dp.append(fib_sum)
    def jumpFloorII(self, number):
            if number > self.__n:
                for i in range(self.__n,number):
                    fib_sum = 0
                    for j in range(i-1,-1,-1):
                        fib_sum += self.__dp[j]
                    self.__dp.append(fib_sum)
                self.__n  = number
            return self.__dp[number]

二进制中1的个数


  • 问题描述: 补码表示的数的1的个数
  • 解题思路:无fa可说
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        n = n&0xffffffff
        cnt = 0
        while n:
            if n&1:
                cnt += 1
            n >>= 1
        return cnt

调整数组顺序使奇数位于偶数前面


  • 问题描述:如题以外,保证奇数、偶数各自的相对位置不变
  • 解题思路: 无fa可说
# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        i = 0
        maxn = len(array)
        while True:
            while i < maxn and array[i]&1:
                i += 1
            if i == maxn:
                break 
            j = i 
            while j < maxn and not array[j]&1:
                j += 1
            if j == maxn:
                break 
            k = j 
            while k < maxn and array[k]&1:
                k += 1
            array[k-j+i:k],array[i:i+k-j] = array[i:j],array[j:k]
            i += k-j
        return array

数值的整数次方


  • 问题描述: 求double类型浮点数的整型幂
  • 解题思路:注意负指数情形
# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        result = 1
        if exponent < 0:
            base = 1/base
            exponent *= -1
        while exponent:
            if exponent&1:
                result *= base 
                exponent -= 1
            else:
                base = base**2
                exponent >>= 1
        return result

二叉树的镜像


  • 问题描述: 输入一个二叉树根节点,返回其镜像二叉树的根节点
  • 解题思路: 无fa可说
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        if not root:
            return None
        if not root.left and not root.right:
            return root
        root.left,root.right = self.Mirror(root.right),self.Mirror(root.left)
        return root

合并两个排序的链表


  • 问题描述: 输入两个单调递增单链表的头节点,返回合并后单调不减的单链表的头结点
  • 解题思路: 类似的题以后只考虑写起来最快的递归
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        if not pHead1:
            return pHead2
        if not pHead2:
            return pHead1
        if pHead1.val < pHead2.val:
            pHead1.next = self.Merge(pHead1.next,pHead2)
            return pHead1
        else:
            pHead2.next = self.Merge(pHead1,pHead2.next)
            return pHead2

顺时针打印矩阵


  • 问题描述:输入一个二维矩阵,返回一个从外到内、顺时针方向遍历该矩阵的一维数组
  • 解题思路:与Codewars的Snail一致,这里使用矩阵旋转、递归只需要一行代码
# -*- coding:utf-8 -*-
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        return list(matrix[0]) + self.printMatrix(zip(*matrix[1:])[::-1]) if matrix else []

树的子结构


  • 问题描述: 输入A、B两树的根节点,返回是否B树为A树的子结构,前提:空树不为任意树的子结构
  • 解题思路:贪心的递归用于判断从根节点开始的子结构,主调用的递归用于搜索根节点
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        def subtree_from_root(a,b):
            if not b:
                return True
            if not a:
                return False
            if a.val == b.val:
                return subtree_from_root(a.left,b.left) and subtree_from_root(a.right,b.right)
        if not pRoot2 or not pRoot1:
            return False
        if subtree_from_root(pRoot1,pRoot2):
            return True
        else:
            return self.HasSubtree(pRoot1.left,pRoot2) or self.HasSubtree(pRoot1.right,pRoot2)

栈的压入、弹出序列


  • 问题描述:输入为入栈出栈的序列,返回两个序列是否合法
  • 解题思路:栈混洗
# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        stack = list()
        i,j = 0,0
        maxm = len(pushV)
        maxn = len(popV)
        while i < maxm and j < maxn:
            if stack and stack[-1]==popV[j]:
                j += 1
                stack.pop()
            else:
                stack.append(pushV[i])
                i += 1
        while j < maxn:
            if stack and stack[-1]==popV[j]:
                stack.pop()
            j += 1
        return not stack

从上向下打印二叉树


  • 问题描述:输入二叉树根节点,返回其层序遍历的结果
  • 解题思路:二叉树的层序遍历
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        if not root:
            return []
        queue = list()
        queue.append(root)
        result = list()
        while queue:
            node = queue.pop(0)
            result.append(node.val)
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        return result

二叉搜索树的后序遍历序列


  • 问题描述:输入一维数组,返回是否该数组为二叉搜索树的后序遍历序列,前提:一维数组中没有重复的值
  • 解题思路:后序遍历产生的序列为左子树->右子树->根节点,二叉搜索树的性质使得该序列进一步具有约束:比根节点小的区段->比根节点大的区段->根节点,递归检查这一约束即可。
# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        if not sequence:
            return []
        def recur(seq):
            maxn = len(seq)
            if maxn <= 2:
                return True
            i = maxn - 2
            root = seq[-1]
            while i>=0 and seq[i] > root:
                i -= 1
            if i == -1:
                return recur(seq[:-1])
            j = i 
            while j>=0 and seq[j] < root:
                j -= 1
            if j != -1:
                return False
            return recur(seq[i:-1]) and recur(seq[:i])
        return recur(sequence)

二叉树和为某一值的路径


  • 问题描述: 输入二叉树根节点和期望整数值,返回包含直到叶节点节点值加和为期望整数值的所有路径的二维数组。
  • 解题思路: 无fa可说
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        result = list()
        def recur(node,num,arr):
            arr.append(node.val)
            num -= node.val
            if not node.left and not node.right and num == 0:
                result.append(arr)
            if node.left:
                recur(node.left,num,arr[:])
            if node.right:
                recur(node.right,num,arr[:])
        if not root:
            return []
        recur(root,expectNumber,list())
        return result

复杂链表的复制


  • 问题描述: 输入一个复杂链表(label,random,next)的头节点,返回其复制链表的头节点。
  • 解题思路: 三种思路,直接复制-暴力搜索,新旧节点映射-辅助复制random域,利用next域-新节点链接到旧节点。
class Solution:
    def Clone(self, pHead):
        if not pHead:
            return None
        tp = pHead
        while tp:
            ctp = RandomListNode(tp.label)
            ctp.random = tp.random
            ctp.next = tp.next
            tp.next = ctp
            tp = ctp.next
        ctp = pHead
        while ctp:
            ctp = ctp.next
            if ctp.random:
                ctp.random = ctp.random.next
            ctp = ctp.next
        ctp = pHead.next
        tp = pHead
        chead = pHead.next
        while ctp:
            if ctp.next:
                tp.next = ctp.next
                ctp.next = ctp.next.next
            else:
                tp.next = None
            ctp = ctp.next
            tp = tp.next

        return chead

二维数组中的查找

  • 问题描述: 输入一个二维数组和一个整数,返回二维数组中是否含有该整数。前提:二维数组每个维度长度一致,按行列分别递增。
  • 解题思路:从副对角线开始能规避多余的判断。
# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        if not array or len(array)==1 and not array[0]:
            return False
        maxn = len(array)
        i,j=0,maxn-1
        while i < maxn and j >= 0:
            if array[i][j] == target:
                return True
            if array[i][j] > target:
                j -= 1
            else:
                i += 1
        return False

空格替换


  • 问题描述: 输入一个字符串,返回其空格被替换为‘%20’后的字符串
  • 解题思路: 不使用str.replace(),而是先统计空格个数,然后从后向前移位替换空格,模拟需要自己管理内存的字符串带来的粒度更细的操作。
# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # 模拟自己管理内存的字符串
        cnt = 0
        for ch in s:
            if ch == ' ': 
                cnt += 1
        replaced = list(s) + ['#','#']*cnt
        for i in range(len(s)-1,-1,-1):
            if replaced[i] != ' ':
                replaced[i+cnt*2] = replaced[i]
            else:
                cnt -= 1
                replaced[i+cnt*2:i+cnt*2+3] = list('%20')
        return ''.join(replaced)

从尾到头打印链表


  • 问题描述:输入单链表的头节点,返回其从尾到头的节点值数组
  • 解题思路:无fa可说
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        result = list()
        while listNode:
            result.append(listNode.val)
            listNode = listNode.next
        return result[::-1]

重建二叉树


  • 问题描述:输入二叉树的前序遍历和中序遍历序列,返回根据两个序列建立的二叉树的头节点
  • 解题思路:无fa可说
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        def make_tree(pre_start,pre_end,tin_start,tin_end):
            if pre_end <= pre_start or tin_end <= tin_start:
                return None
            root_val = pre[pre_start]
            root = TreeNode(root_val)
            pre_start += 1
            for i in range(tin_start,tin_end):
                if tin[i] == root_val:
                    root.left = make_tree(pre_start,pre_start+i-tin_start,tin_start,i)
                    root.right = make_tree(pre_start+i-tin_start,pre_end,i+1,tin_end)
                    break 
            return root
        return make_tree(0,len(pre),0,len(tin))

用两个栈实现队列


  • 问题描述: 完成Queue class的pop和push方法,采用stack实现
  • 解题思路: 无fa可说
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.__stack = list()
        self.__buf = list()
    def push(self, node):
        self.__stack.append(node)
    def pop(self):
        if not self.__buf:
            while self.__stack:
                self.__buf.append(self.__stack.pop())
        return self.__buf.pop()

旋转数组的最小值


  • 问题描述: 数组的旋转指 数组最前面的一段移到数组尾部,输入一个单调不减数组的旋转,求其最小值
  • 解题思路:注意元素全等的情形。
# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        if not rotateArray:
            return 0
        i = 0
        maxn = len(rotateArray)
        while i < maxn:
            if i and rotateArray[i]<rotateArray[i-1]:
                return rotateArray[i]
            i += 1
        return rotateArray[0]

链表中倒数第k个节点


  • 问题描述:输入单链表头节点和k,返回单链表中倒数第k个节点的引用

* 解题思路:注意k只能从1开始

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        arr = list()
        while head:
            arr.append(head)
            head=head.next
        if k > len(arr) or k <=0:
            return None
        return arr[-k]

二叉搜索树转换到双向链表


  • 问题描述: 输入二叉搜索树根节点,返回双向链表头节点,要求不能新建节点,在原节点上使用left和right指针域操作
  • 解题思路:在二叉树中序遍历时重设left,right

class Solution:
    def Convert(self, pRootOfTree):
        stack = list()
        last_node = None
        link_head = None
        while stack or pRootOfTree:
            while pRootOfTree:
                stack.append(pRootOfTree)
                pRootOfTree = pRootOfTree.left
            pRootOfTree = stack.pop()
            if not link_head:
                link_head = pRootOfTree
            if last_node:
                pRootOfTree.left = last_node
                last_node.right = pRootOfTree
            last_node = pRootOfTree
            pRootOfTree = pRootOfTree.right
        return link_head

数组中出现次数超过一半的数字


  • 问题描述: 输入一个一维数组,返回其中中出现次数超过其数组一半的数字,否则返回0
  • 解题思路:用空间换时间可以几行代码搞定。超过数组一半长度,意味着所求数字如果存在,则一定为该数组的中位数,其出现次数也必然大于剩下所有数字出现次数之和。有两种不需要额外空间的办法:均采用两次O(n)的统计,第一次找该到满足其中一个条件的数,第二次判别验证。
# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        cnt = dict()
        maxn = len(numbers)/2.0
        for i in numbers:
            if not i in cnt:
                cnt[i] = 1
            else:
                cnt[i] += 1
            if cnt[i] > maxn:
                return i 
        return 0

最小的k个数

  • 问题描述: 输入一个数组和整数k,返回数组中最小的k个数(单调不减)
  • 解题思路:数据结构实验时为了统计topk,考虑用最小堆添加约束,这道题也是类似的,可以用最大堆,限制每次更新最大堆时做两个检查:目前的堆容量是否为k,否则加入;堆顶是否大于待添加的值,是则替掉堆顶并向下更新。但是为了快速实现,这里采用求数组中第k大数的O(n)策略,据此得到最小的k个数的无序数组。
# -*- coding:utf-8 -*-
def partition(arr,s,e):
    if e - s <= 1:
        return s
    i = s + 1
    j = e - 1
    pivot = arr[s]
    while i < j:
        while i < j and arr[i] < pivot: i += 1
        while i < j and arr[j] >= pivot: j -= 1
        if i < j: arr[i],arr[j] = arr[j],arr[i]
    arr[i-1],arr[s] = pivot,arr[i-1]
    return i-1

class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        if not tinput:
            return []
        maxn = len(tinput)
        if maxn < k:
            return []
        start,end = 0,maxn
        i = partition(tinput,start,end)
        while i != k:
            if i < k:
                start = i + 1
            else:
                end = i
            i = partition(tinput,start,end)
        return sorted(tinput[:k])

猜你喜欢

转载自blog.csdn.net/qq_35279914/article/details/82320067
今日推荐