受到这篇文章的启发,于是我写下了这篇博客主要是记录自己准备实习前的刷题过程。

按照笔者推荐的刷题过程,剑指offer->Leetcode动态规划->面试前再过一遍剑指offer

我觉得这个刷题过程的可行性是很高的,于是在时间规定下,我决定在一个星期之内按照牛客上剑指offer的题目刷完对应的题。
        


目录

  • 1. 写在前面
  • 2. 数据结构类题目
    • 2.1 排序
    • 2.2 递归
    • 2.3 贪心
    • 2.4 动态规划
    • 2.5 分治
    • 2.6 穷举
    • 2.7 回溯
    • 2.8 数学
    • 2.9 dfs
    • 2.10 双指针
    • 2.11 二分
    • 2.13 位运算
    • 2.14 bfs
    • 2.15 数组
    • 2.16 字符串
    • 2.17 链表
    • 2.18 栈
    • 2.19 队列
    • 2.20 树
    • 2.21 哈希
    • 2.22 堆

1. 写在前面

面试季来了,不管是作为面试者还是以后作为面试官,了解算法这门程序员之间的沟通方式都是非常必要的。

找过工作的朋友应该都听说过《剑指offer》,本文主要对我这些天刷过的《剑指offer》做个简单的分类小结,方便后面专项复(练)习~

【1】剑指offer推荐刷题地址:
https://www.nowcoder.com/ta/coding-interviews

【2】我的所有AC题解(Python语言),每道题都写了点自己的思路:
笔者:https://github.com/nlpjoe/Coding4Interviews

【3】剑指offer面试题内容:https://www.cnblogs.com/yanmk/p/9130681.html


2. 数据结构类题目

2.1 排序

(1)JZ29 题目

题目描述

给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。如果K>数组的长度,那么返回一个空的数组。


"""
**排序**题目描述:给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。如果K>数组的长度,那么返回一个空的数组解题思路:首先使用插入排序,排序完对应的数组,然后相应切片输出。
"""# -*- coding:utf-8 -*-
class Solution:def GetLeastNumbers_Solution(self, tinput, k):length = len(tinput)  # 计算出数组的长度# 当k大于这类长度时,或者输入的数组为空时,返回空if (k > length) or tinput == []:return []# 典型的插入排序for i in range(1, length):# 输入该插入的数字(遍历从1到最后一个元素)key = tinput[i]j = i - 1# 如果j没有越界,同时,key比前面已经拍好数组小时,需要插入while j >= 0 and key < tinput[j]:tinput[j+1] = tinput[j]j = j -1# 找到了该插入的位点,为最后比较位点j+1tinput[j+1] = keyreturn tinput[:k]

当然,可以直接运用python特有的函数 .sort() 直接得到排序后的数组。
这样就可以避免使用了一些排序算法。

(2)JZ63题目

题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。


"""
**排序**题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,
那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,
那么中位数就是所有数值排序之后中间两个数的平均值。
我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。解题思路:
利用两个堆:1. 用于存储输入数字中较小一半的最大堆(最大堆中的所有数字都小于或等于最大堆的top元素)
2. 用于存储输入数字的较大一半的最小堆(最小堆中的所有数字都大于或等于最小堆的顶部元素)python 库heapq中默认的堆为小顶堆,在使用了-num传入到堆中时,此时pop出堆顶的元素后最大值的相反数。
值得提醒:最大堆的最大值<=最小堆的最小值
"""# -*- coding:utf-8 -*-
import heapq
class Solution:def __init__(self):self.count = 0self.max_heap = []self.min_heap = []def Insert(self, num):# 统计加入数据的个数self.count += 1#将数据放到最大堆中heapq.heappush(self.max_heap, -num)#将最大堆中的堆顶元素放到最小堆中# 将最大堆中最小的元素放入最小堆中max_heap_top = heapq.heappop(self.max_heap)heapq.heappush(self.min_heap, -max_heap_top)#如果最小堆和最大堆之间的差距大于1,将最小堆中的堆顶放进最大堆# 这一步判断的过程:二进制判断,如果self.count为基数例如3二进制为11,此时与1进行与运算。# 其实这一步保证了大顶堆中元素的个数要大于小顶堆元素的个数if self.count & 1:min_heap_top = heapq.heappop(self.min_heap)heapq.heappush(self.max_heap, -min_heap_top)#题目getmedian参数少了个sdef GetMedian(self,s):# write code hereif self.count & 1:return -self.max_heap[0]else:return (self.min_heap[0] - self.max_heap[0]) / 2.0

2.2 递归

(1)JZ8题目

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

这道题目是典型的递归题,可以看出第N阶段的结果=第N-2阶段结果+第N-1阶段结果。

"""
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。
求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
"""# -*- coding:utf-8 -*-
class Solution:def jumpFloor(self, number):# write code herevar0 = 1var1 = 2if number < 3:return numberi = 3while i <= number:num = var0 + var1var0 = var1var1 = numi += 1return num

(2)JZ10题目

题目描述

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

这道题也是典型的递归类的题目,可以看出第N阶段的结果=第N-2阶段结果+第N-1阶段结果。

在牛客剑指offer这道题的评论区,有位大佬画了一副图,很形象解释了第N阶段的结果=第N-2阶段结果+第N-1阶段结果。 f(n-2)阶段放两个,f(n-1)放一个。
           


"""
**递归**题目描述
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。
请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?"""# -*- coding:utf-8 -*-
class Solution:def jumpFloor(self, number):# write code herevar0 = 1var1 = 2if number < 3:return numberi = 3while i <= number:num = var0 + var1var0 = var1var1 = numi += 1return numdef rectCover(self, number):res = [0,1,2]while len(res) <= number:res.append(res[-1] + res[-2])return res[number]

2.3 贪心

(1)JZ9题目

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。


# -*- coding:utf-8 -*-
class Solution:def jumpFloorII(self, number):# write code herevar = [0, 1, 2]while len(var) <= number:var.append(sum(var) + 1)return var[number]class Solution2:def jumpFloorII(self, number):return 2**(number-1)

还可以使用等比数列的方法来求解这,也就是第二种解决方法:
           

2.4 动态规划

(1)JZ27题目

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。


"""
**字符串 动态规划 回溯算法**题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。
例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串:
abc,acb,bac,bca,cab和cba。"""# -*- coding:utf-8 -*-
class Solution:def Permutation(self, ss):# write code heress = list(ss)def backtrack(position ,end):if position == end:var = ''.join(ss[:])if var not in res:res.append(var)returnfor index in range(position, end):ss[index], ss[position] = ss[position], ss[index]backtrack(position + 1, end)ss[index], ss[position] = ss[position], ss[index]res = []backtrack(0, len(ss))return sorted(res)

(2)JZ30题目

题目描述

输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为 O(n).


"""
**动态规划**题目描述
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。
求所有子数组的和的最大值。要求时间复杂度为 O(n).
"""# -*- coding:utf-8 -*-
class Solution:def FindGreatestSumOfSubArray(self, array):# write code hereres = array[0]  # 记录当前所有子数组的和的最大值temp = 0  # 包含array[i]的连续数组最大值for i in array:temp = max(i,temp+i)res = max(res,temp)return res

2.5 分治

JZ26题目

题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

"""
**分治**题目描述输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。
要求不能创建任何新的结点,只能调整树中结点指针的指向。思路:
(1)直接在中序遍历中,进行指针的连接操作。
(2)使用中序遍历,然后再将数组中的结点与前后依次相互连接。
"""# -*- coding:utf-8 -*-
class TreeNode:def __init__(self, x):self.val = xself.left = Noneself.right = Noneclass Solution1:def Convert(self, pRootOfTree):if not pRootOfTree: returnself.head = self.pre = Noneself.MidTraversal(pRootOfTree)return self.headdef MidTraversal(self, root):if not root: returnself.MidTraversal(root.left)if not self.head:self.head = self.pre = rootelse:self.pre.right, root.left, self.pre = root, self.pre, rootself.MidTraversal(root.right)class Solution2:def Convert(self, pRootOfTree):# write code hereif not pRootOfTree:returnself.arr = []self.midTraversal(pRootOfTree)for i,v in enumerate(self.arr[:-1]):v.right = self.arr[i + 1]self.arr[i + 1].left = vreturn self.arr[0]def midTraversal(self, root):if not root: returnself.midTraversal(root.left)self.arr.append(root)self.midTraversal(root.right)

2.6 穷举

JZ26题目

题目描述

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!


"""
**穷举**题目描述小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。
没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
"""# -*- coding:utf-8 -*-
class Solution:def FindContinuousSequence(self, tsum):# write code here# 生成一个等长的递归数组var = [x+1 for x in range(tsum)]# 中位数的坐标num = tsum//2 + 1res = []for i in range(num):j = i+2while j <= tsum:if sum(var[i:j]) == tsum:res.append(var[i:j])j += 1return res

2.7 回溯

JZ27题目

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。


"""
**字符串 动态规划 回溯算法**题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。
例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串:
abc,acb,bac,bca,cab和cba。"""# -*- coding:utf-8 -*-
class Solution:def Permutation(self, ss):# write code heress = list(ss)def backtrack(position ,end):if position == end:var = ''.join(ss[:])if var not in res:res.append(var)returnfor index in range(position, end):ss[index], ss[position] = ss[position], ss[index]backtrack(position + 1, end)ss[index], ss[position] = ss[position], ss[index]res = []backtrack(0, len(ss))return sorted(res)

2.8 数学

(1)JZ11

题目描述
输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。


"""
**数字**
题目描述
输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。
"""# -*- coding:utf-8 -*-
class Solution:def NumberOf1(self, n):# write code here# 当n为负数时,用补码if n < 0:n = n & 0xffffffffvar = "{:032b}".format(n)res = list(var)sum = 0for i in res:if i == '1':sum += 1return sum# 方法二使用位运算def NumberOf1_2(self, n):# write code herecount = 0if n < 0:n = n & 0xffffffffwhile n:if (n & 1):count += 1n = n >> 1return count

(2)JZ12

题目描述

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0

"""
**数字**题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0"""
# -*- coding:utf-8 -*-
class Solution:def fast_power(self, base, exponent):if base == 0:return 0if exponent == 0:return 1e = abs(exponent)tmp = baseres = 1while(e > 0):#如果最后一位为1,那么给res乘上这一位的结果,也就是分成奇数个if (e & 1 == 1):  res =res * tmp e = e >> 1tmp = tmp * tmpreturn '%.5f'%res if exponent > 0 else 1/resdef Power(self, base, exponent):# write code hereif base == 0 and exponent == 0:return 0return pow(base, exponent)

上面的很简单,没有使用快速幂算法,下面使用一下快速幂算法,快速幂算法参考下面的博客
https://blog.csdn.net/hkdgjqr/article/details/5381028

(3)JZ31

题目描述

求出1 ~ 13的整数中1出现的次数,并算出100 ~ 1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)


"""
**数字**题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?
"""# -*- coding:utf-8 -*-
class Solution:def NumberOf1Between1AndN_Solution(self, n):# write code herels = [str(i+1) for i in range(n)]res = ''.join(ls)count = 0for i in res:if i == '1':count += 1return count

(4)JZ33

题目描述

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。


"""
**数字 二分**题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。
例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。
求按从小到大的顺序的第N个丑数。
"""# -*- coding:utf-8 -*-
class Solution:def GetUglyNumber_Solution(self, index):# write code hereif index<7:return indexp1,p2,p3 = 0,0,0array = [1]while len(array)<index:newnum = min(array[p1]*2,array[p2]*3,array[p3]*5)array.append(newnum)if newnum == array[p1]*2:p1 += 1if newnum == array[p2]*3:p2 += 1if newnum == array[p3]*5:p3 +=1return array[-1]

2.9 dfs

(1)JZ4

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

"""
题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。解题思路:使用递归、树相关的知识点
"""class TreeNode:def __init__(self, x):self.val = xself.left = Noneself.right = Noneclass Solution:# 返回构造的TreeNode根节点def reConstructBinaryTree(self, pre, tin):if len(pre) == 0:return None# 判断是否是最后一个节点if len(pre) == 1:Root = TreeNode(pre[0])Root.left = NoneRoot.right = Nonereturn RootRoot = TreeNode(pre[0])loc = tin.index(pre[0])length = len(tin[:loc])if loc == 0:# 无左节点Root.left = Noneelse:Root.left = self.reConstructBinaryTree(pre[1:length+1], tin[:loc])if length+1 < len(pre):Root.right = self.reConstructBinaryTree(pre[length+1:], tin[loc+1:])else:# 无右节点Root.right = Nonereturn Root

(2)JZ39
题目描述

输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

"""
题目描述输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。解题思路:"""class Solution:def IsBalanced_Solution(self, pRoot):# write code hereif pRoot is None:return Trueelse:res = abs(self.dapth(pRoot.left) - self.dapth(pRoot.right)) <=1 \& self.IsBalanced_Solution(pRoot.left) & \self.IsBalanced_Solution(pRoot.right)return res# 存储每个结点的高度def dapth(self, root):if root is None:return 0else:return 1 + max(self.dapth(root.left), self.dapth(root.right))

(3)JZ65
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。
例如
矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。


"""
题目描述:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。解题思路:dfs
"""class Solution:def hasPath(self, matrix, word):if word == '':return Trueif not matrix:return Falsedef dfs(i, j, k):# 判断路径是否存在if not 0 <= i < len(matrix) or not 0 <= j < len(matrix[0]) or \matrix[i][j] != word[k]:return Falseif len(word) - 1 == k:return Truematrix[i][j] = ""res = dfs(i + 1, j, k + 1) or dfs(i - 1, j, k + 1) or dfs(i, j - 1, k + 1) or dfs(i, j + 1, k + 1)matrix[i][j] = word[k]return res# 遍历入口for i in range(len(matrix)):for j in range(len(matrix[0])):if dfs(i, j, k=0):return True

2.10 双指针

(1)JZ42
题目描述

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。


"""
题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。解题思路:
双指针、数组
"""# -*- coding:utf-8 -*-
class Solution:def FindNumbersWithSum(self, array, tsum):# write code herelow = 0high = len(array)-1if len(array)<=1 or tsum ==0 :return []while low <= high:if array[low] + array[high] == tsum:return [array[low], array[high]]if array[low] + array[high] > tsum:high -= 1else:low += 1return []

(2)JZ64
题目描述

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
窗口大于数组长度的时候,返回空.


"""
题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。思路:
双指针,数组
"""# -*- coding:utf-8 -*-
class Solution:def maxInWindows(self, num, size):# write code hereif len(num) < size or not num or size == 0:return []var = []i = 0while i <= len(num)-size:var.append(max(num[i:i+size]))i += 1return var

2.11 二分

(2)JZ6
题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

"""
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。思路:
二分,旋转
"""# -*- coding:utf-8 -*-
class Solution:def minNumberInRotateArray(self, rotateArray):# write code hereif len(rotateArray) == 0:return 0low = 0high = len(rotateArray) -1while low < high:mid = (low + high) // 2if rotateArray[mid] > rotateArray[high]:low = mid + 1elif rotateArray[mid] < rotateArray[high]:high = midreturn rotateArray[low]

(2)JZ33
题目描述

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

"""
**数字 二分**题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。
例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。
求按从小到大的顺序的第N个丑数。"""# -*- coding:utf-8 -*-
class Solution:def GetUglyNumber_Solution(self, index):if index < 7:return indexp1, p2, p3 = 0, 0, 0array = [1]while len(array) < index:var = min(array[p1]*2, array[p2]*3, array[p3]*5)array.append(var)if array[p1]*2 == var:p1 += 1if array[p2]*3 == var:p2 += 1if array[p3]*5 == var:p3 += 1return array[-1]

(3)JZ39
题目描述

统计一个数字在升序数组中出现的次数。

"""
题目描述
统计一个数字在升序数组中出现的次数。思路:
双指针,二分法
"""
# -*- coding:utf-8 -*-
class Solution:def GetNumberOfK(self, data, k):if len(data) == 0:return 0def getLower(data, k):low = 0high = len(data) -1mid = (low + high)//2# 获取k第一次出现的下标while low <= high:if data[mid] < k:low = mid + 1else:high = mid - 1mid = (low + high)//2return low# 获得k最后一次出现的下标def getHigher(data, k):low = 0high = len(data) - 1mid = (low + high) // 2# 获取k第一次出现的下标while low <= high:if data[mid] <= k:low = mid + 1else:high = mid - 1mid = (low + high) // 2return high# 获得k最后一次出现的下标return getHigher(data, k) - getLower(data, k) + 1

2.13 位运算

(1)JZ40

题目描述

一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。


"""
题目描述
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。思路:
使用位运算
"""class Solution:def FindNumsAppearOnce(self , array ):# write code hereXORsum = 0for i in array:XORsum ^= it = 1while (XORsum&t)==0:t = t<<1ans1 = 0ans2 = 0for i in array:if (t&i)==0:ans1 ^= ielse:ans2 ^= iif ans1<ans2:return [ans1,ans2]else:return [ans2,ans1]

2.14 bfs

(1)JZ60
题目描述

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

"""
题目描述:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。思路:
使用bfs
"""# -*- coding:utf-8 -*-class TreeNode:def __init__(self, x):self.val = xself.left = Noneself.right = None# 使用层次遍历来输出结果
class Solution:# 返回二维列表[[1,2],[4,5]]def Print(self, pRoot):# write code hereif not pRoot:return []res = []queue = [pRoot]while queue:temp = []for _ in range(len(queue)):cur = queue.pop(0)temp.append(cur.val)if cur.left:queue.append(cur.left)if cur.right:queue.append(cur.right)res.append(temp)return res

2.15 数组

(1)JZ1 二维数组中的查找

描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
给定 target = 7,返回 true。
给定 target = 3,返回 false。

# -*- coding:utf-8 -*-
class Solution:# array 二维列表def Find(self, target, array):# write code hereif not array:return Falsem = len(array)n = len(array[0])# 在右上角往左下角进行二分查找row, col = 0, n-1while row<m and col>=0:if target == array[row][col]:return Trueelif target > array[row][col]:row += 1else:col -=1return False

(2)JZ4 重建二叉树

描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

class Solution:# 返回构造的TreeNode根节点def reConstructBinaryTree(self, pre, tin):# write code hereif len(pre) == 0:return Noneelif len(pre) == 1:return TreeNode(pre[0])if len(pre) == 1:head = TreeNode(pre[0])head.left = Nonehead.right = Nonereturn headhead = TreeNode(pre[0])      temp1 = tin.index(pre[0])length = len(tin[:temp1])if temp1 == 0:head.left = Noneelse:head.left = self.reConstructBinaryTree(pre[1:length+1], tin[:temp1])if length + 1 < len(pre):head.right = self.reConstructBinaryTree(pre[length+1:], tin[temp1+1:])else:head.right = Nonereturn head

(3)JZ7 斐波那契数列

描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。

# -*- coding:utf-8 -*-
class Solution:def Fibonacci(self, n):# write code herea = [0, 1, 1, 2]if n <= 3:return a[n]i = 0a2 = 1a3 = 2while i+4 <= n:temp = a2 + a3a2 = a3a3 = tempi += 1return temp

(4)JZ13 调整数组顺序使奇数位于偶数前面

描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

class Solution:def reOrderArray(self , array ):a = []b = []for i in array:if i%2 == 0:b.append(i)else:a.append(i)return a + b

(5)JZ19 顺时针打印矩阵

# -*- coding:utf-8 -*-
class Solution:# matrix类型为二维列表,需要返回列表def printMatrix(self, matrix):if not matrix:return []# 定义了dir行走的轨迹# 按照右->下->左-上的顺序遍历dx = [0, 1, 0, -1]dy = [1, 0, -1, 0]x = y = dir = 0# 矩阵的长宽n= len(matrix)m = len(matrix[0])vis = [[0 for i in range(m)] for i in range(n)]list = []while 0<=x<n and 0<=y<m and not vis[x][y]:list.append(matrix[x][y])vis[x][y] = 1# 试着向dir方向行走while (0<= x+dx[dir] <n) and (0 <= y+dy[dir] <m) and not vis[x+dx[dir]][y+dy[dir]]:x += dx[dir]y += dy[dir]list.append(matrix[x][y])vis[x][y] = 1# 走不动时dir = (dir + 1) % 4x += dx[dir]y += dy[dir]return list

(6)JZ28 数组中出现次数超过一半的数字

描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。你可以假设数组是非空的,并且给定的数组总是存在多数元素。1<=数组长度<=50000

class Solution:def MoreThanHalfNum_Solution(self, numbers):# write code here# sort the listif not numbers:return []if len(numbers) == 1:return numbers[0]numbers.sort()i ,count = 1,1while i < len(numbers):j = iwhile numbers[j] == numbers[j-1]:count += 1j += 1if count>len(numbers)/2:return numbers[j-1]i = ji += 1return None

(7)JZ32 把数组排成最小的数

描述

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

# -*- coding:utf-8 -*-
class Solution:def PrintMinNumber(self, numbers):# write code here# 给序列标号if not numbers:return ""if len(numbers) == 1:return numbers[0]num = [i for i in range(len(numbers)-1)]# 比较两个列表大小def judge_min(var_a, var_b):"""输入:两个数输出:1表示前者大于后者,0表示后者大于前者"""var_a = [int(i) for i in list(str(var_a))]var_b = [int(i) for i in list(str(var_b))]max_length = max(len(var_a), len(var_b))while len(var_a) < max_length:var_a.append(var_a[-1])while len(var_b) < max_length:var_b.append(var_b[-1])# flag = 1 表示var_a更大些i = 0while i <= max_length-1:if var_a[i] == var_b[i]:i += 1elif var_a[i] < var_b[i]:return 0else:return 1return i# 冒泡排序for i in range(len(numbers)):for j in range(0, len(numbers)-i-1):if judge_min(numbers[j], numbers[j+1]) == 1:numbers[j], numbers[j+1] = numbers[j+1], numbers[j]return "".join(map(str, numbers))

(8)JZ35 数组中的逆序对

描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

class Solution:def __init__(self):self.c = 0def InversePairs(self, data):self.merge_sort(data)return self.cdef merge_sort(self, A):if len(A) <=1:return Amid = len(A) // 2left = self.merge_sort(A[:mid])right = self.merge_sort(A[mid:])return self.merge(left, right)def merge(self, left, right):n1 ,n2 = len(left), len(right)i = j = 0res = []while i < n1 and j < n2:if left[i] < right[j]:res.append(left[i])i += 1else:res.append(right[j])j += 1# 因为返回的值为有序的序列所有left[i:]后面的元素都是大于right[j]的元素self.c += len(left) - iself.c %= 10 ** 9 + 7if i < n1:res += left[i:]elif j < n2:res += right[j:]return res

(9)JZ37 数字在升序数组中出现的次数

描述

统计一个数字在升序数组中出现的次数。

class Solution:def GetNumberOfK(self, data, k):if len(data) == 0:return 0def getLower(data, k):low = 0high = len(data) -1mid = (low + high)//2# 获取k第一次出现的下标while low <= high:if data[mid] < k:low = mid + 1else:high = mid - 1mid = (low + high)//2return low# 获得k最后一次出现的下标def getHigher(data, k):low = 0high = len(data) - 1mid = (low + high) // 2# 获取k第一次出现的下标while low <= high:if data[mid] <= k:low = mid + 1else:high = mid - 1mid = (low + high) // 2return high# 获得k最后一次出现的下标return getHigher(data, k) - getLower(data, k) + 1

(10)JZ42 和为S的两个数字

描述

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,返回两个数的乘积最小的,如果无法找出这样的数字,返回一个空数组即可。

# -*- coding:utf-8 -*-
class Solution:def FindNumbersWithSum(self, array, tsum):# write code herelow = 0high = len(array)-1if len(array)<=1 or tsum ==0 :return []while low <= high:if array[low] + array[high] == tsum:return [array[low], array[high]]if array[low] + array[high] > tsum:high -= 1else:low += 1return []

(11)JZ50 数组中重复的数字

描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任一一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1

class Solution:def duplicate(self, numbers):if not numbers:return -1var = sorted(numbers)for i in range(len(numbers)-1):if var[i] == var[i+1]:return var[i]return -1

(12)JZ51 构建乘积数组
描述

给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)
对于A长度为1的情况,B无意义,故而无法构建,因此该情况不会存在。

# -*- coding:utf-8 -*-
class Solution:def multiply(self, A):# write code hereif not A:return []res = []for i in range(len(A)):var = A[:]var.pop(i)temp = 1for j in var:temp *= jres.append(temp)return res

2.16 字符串

(1)JZ2 替换空格

描述

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

class Solution:def replaceSpace(self , s):return '%20'.join(s.split(' '))

(2)JZ27 字符串的排列

描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

# -*- coding:utf-8 -*-
# 使用回溯的方法class Solution:def Permutation(self, ss):# write code heress = list(ss)def backtrack(position ,end):if position == end:var = ''.join(ss[:])if var not in res:res.append(var)returnfor index in range(position, end):ss[index], ss[position] = ss[position], ss[index]backtrack(position + 1, end)ss[index], ss[position] = ss[position], ss[index]res = []backtrack(0, len(ss))return sorted(res)

(3)JZ34 第一个只出现一次的字符

描述

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

# -*- coding:utf-8 -*-
class Solution:def FirstNotRepeatingChar(self, s):# write code herereturn s.index(list(filter(lambda c: s.count(c) == 1, s))[0]) if len(s)>0 else -1

(4)JZ43 左旋转字符串

描述

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列 S,请你把其循环左移 K 位后的序列输出(保证 K 小于等于 S 的长度)。例如,字符序列S=”abcXYZdef”,要求输出循环左移 3 位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

# -*- coding:utf-8 -*-
class Solution:def LeftRotateString(self, s, n):# write code hereif len(s) == 0:return ""length = len(s)n = n % lengths += sreturn s[n:length+n]

(5)JZ44 翻转单词序列

描述

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“nowcoder. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a nowcoder.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

# -*- coding:utf-8 -*-
class Solution:def ReverseSentence(self, s):# write code hereif len(s) == 0:return ''str = s.split(' ')# 将str中的元素对调i = 0j = len(str) - 1while i < j:str[i], str[j] = str[j], str[i]i += 1j -= 1return ' '.join(str)

(6)JZ49 把字符串转换成整数

描述

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

# -*- coding:utf-8 -*-
class Solution:def StrToInt(self, str):# write code herestr = str.strip()if not str:return 0number, flag = 0, 1# 符号位的判断是否有正负号if str[0] == '-':str = str[1:]flag = -1elif str[0] == '+':str = str[1:]# 遍历除了+,-以外所有字符,如果遇到非数字,则返回0for c in str:if '0' <= c <= '9':number = 10*number + int(c)else:return 0number *= flagreturn number

(7)JZ52 正则表达式匹配

描述

请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

# 使用的是动态规划方法class Solution:def match(self , str , pattern ):m, n = len(str) + 1, len(pattern) + 1dp = [[False] * n for _ in range(m)]dp[0][0] = True# 初始化首行for j in range(2, n, 2):dp[0][j] = dp[0][j - 2] and pattern[j - 1] == '*'# 状态转移for i in range(1, m):for j in range(1, n):if pattern[j - 1] == '*':if dp[i][j - 2]: dp[i][j] = True                              # 1.elif dp[i - 1][j] and str[i - 1] == pattern[j - 2]: dp[i][j] = True   # 2.elif dp[i - 1][j] and pattern[j - 2] == '.': dp[i][j] = True        # 3.else:if dp[i - 1][j - 1] and str[i - 1] == pattern[j - 1]: dp[i][j] = True # 1.elif dp[i - 1][j - 1] and pattern[j - 1] == '.': dp[i][j] = True    # 2.return dp[-1][-1]

(8)JZ53 表示数值的字符串

描述

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。

class Solution:def isNumeric(self , str ):# write code heretry:res = float(str)return Trueexcept:return False

(9)JZ54 字符流中第一个不重复的字符

描述

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
后台会用以下方式调用Insert 和 FirstAppearingOnce 函数

# -*- coding:utf-8 -*-
class Solution:# 返回对应chars = ''def FirstAppearingOnce(self):for i in self.s:if self.s.count(i) == 1:return ireturn '#'# write code heredef Insert(self, char):# write code hereself.s += char

2.17 链表

(1)JZ3 从尾到头打印链表

描述

输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。

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

(2)JZ14 链表中倒数最后k个结点

描述

输入一个链表,输出一个链表,该输出链表包含原链表中从倒数第k个结点至尾节点的全部节点。
如果该链表长度小于k,请返回一个长度为 0 的链表。

class Solution:def FindKthToTail(self , pHead , k ):# write code hereresult = []if pHead is None:return Nonewhile pHead:result.append(pHead)pHead = pHead.nextif k<1 or k>len(result):return Noneelse:return result[-k]

(3)JZ15 反转链表

描述

输入一个链表,反转链表后,输出新链表的表头。

class Solution:# 返回ListNodedef ReverseList(self, pHead):# write code hereif not pHead:return Noneres = Nonewhile pHead:temp = pHead.nextpHead.next = resres = pHeadpHead = tempreturn res

(4)JZ16 合并两个排序的链表

class Solution:# 返回合并后列表def Merge(self, pHead1, pHead2):# write code hereif not pHead1 and not pHead2:return Nonetmp = ListNode(0)head = tmpwhile pHead1 and pHead2:if pHead1.val <= pHead2.val:head.next = pHead1pHead1 = pHead1.nextelse:head.next = pHead2pHead2 = pHead2.nexthead = head.nextif pHead1:head.next = pHead1elif pHead2:head.next = pHead2return tmp.next

(5)JZ25 复杂链表的复制

描述

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。 下图是一个含有5个结点的复杂链表。图中实线箭头表示next指针,虚线箭头表示random指针。为简单起见,指向null的指针没有画出。

class Solution:# 返回 RandomListNodedef Clone(self, pHead):# write code hereif not pHead:return Nonenewnode = RandomListNode(pHead.label)newnode.random = pHead.randomnewnode.next = self.Clone(pHead.next)return newnode

(6)JZ36 两个链表的第一个公共结点

class Solution:def FindFirstCommonNode(self, pHead1, pHead2):# write code herestack1 = []stack2 = []while pHead1:stack1.append(pHead1)pHead1 = pHead1.nextwhile pHead2:stack2.append(pHead2)pHead2 = pHead2.nextres = Nonewhile stack1 and stack2:p1 = stack1.pop()p2 = stack2.pop()if p1 == p2:res = p1else:breakreturn res

(7)JZ55 链表中环的入口结点

描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。

class Solution:def EntryNodeOfLoop(self, pHead):# write code hereif not pHead:return Noneif pHead.next == None:return NonepNode1 = pHeadpNode2 = pHeadwhile pNode2 and pNode2.next:pNode1 = pNode1.nextpNode2 = pNode2.next.nextif pNode1 == pNode2:breakpNode1 = pHeadwhile pNode1 and pNode2 and pNode1 != pNode2:pNode1 = pNode1.nextpNode2 = pNode2.nextreturn pNode1

(8)JZ56 删除链表中重复的结点

描述

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

class Solution:def deleteDuplication(self, pHead):if not pHead:return Noneif pHead and not pHead.next:return pHeadcurrent = ListNode(0)if pHead.next.val == pHead.val:current = pHead.next.nextwhile current != None and current.val == pHead.val:current = current.nextreturn self.deleteDuplication(current)else:current = pHead.nextpHead.next = self.deleteDuplication(current)return pHead

2.18 栈

(1)JZ5 用两个栈实现队列

描述

用两个栈来实现一个队列,分别完成在队列尾部插入整数(push)和在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。

# -*- coding:utf-8 -*-
class Solution:def __init__(self):self.items1 = []self.items2 = []def push(self, node):self.items1.append(node)def pop(self):if not self.items1 and not self.items2:return -1else:if self.items2:return self.items2.pop()else:while self.items1:self.items2.append(self.items1.pop())return self.items2.pop()

(2)JZ20 包含min函数的栈

描述

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,并且调用 min函数、push函数 及 pop函数 的时间复杂度都是 O(1)
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素

# -*- coding:utf-8 -*-
class Solution:def __init__(self):self.item = []def push(self, node):# write code herereturn self.item.append(node)def pop(self):# write code herereturn self.item.pop()def top(self):# write code herereturn self.item[-1]def min(self):return min(self.item)

(3)JZ21 栈的压入、弹出序列

描述

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

# -*- coding:utf-8 -*-
class Solution:def IsPopOrder(self, pushV, popV):# write code hereif not pushV or not popV:return Falseif pushV[0] != popV[0] and len(pushV) == len(popV) == 1:return Falsedef get_list(ls, val):index = ls.index(val)res = []if index != 0:res.append(ls[index-1:])else:res.append(ls[index:])return res[0]while pushV:for i,num in enumerate(popV):if i+1 < len(popV) and not popV[i+1] in get_list(pushV, num):return FalsepushV.pop(pushV.index(num))return True

(4)JZ23 二叉搜索树的后序遍历序列

描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。(ps:我们约定空树不是二叉搜素树)

# -*- coding:utf-8 -*-
class Solution:def VerifySquenceOfBST(self, sequence):# write code hereif not sequence:return Falsereturn self.check(sequence)def check(self, arr):if len(arr) <= 2:return True# 寻找第一个大于root的值root = arr[-1]p = 0while arr[p] < root:p += 1index = p# 判断右边都是大于root的值while index < len(arr) -1:if arr[index] > root:index += 1else:return Falsereturn self.check(arr[:index]) and self.check(arr[index:-1])

(5)JZ59 按之字形顺序打印二叉树

描述

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

class Solution:# 返回二维列表[[1,2],[4,5]]def Print(self, pRoot):# write code hereif not pRoot:return []res = []queue = [pRoot]high = 0while queue:temp = []for _ in range(len(queue)):cur = queue.pop(0)temp.append(cur.val)if cur.left:queue.append(cur.left)if cur.right:queue.append(cur.right)high += 1if high % 2 == 0:temp = temp[::-1]res.append(temp)return res

2.19 队列

(1)JZ22 从上往下打印二叉树

描述

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

class Solution:# 返回从上到下每个节点值列表,例:[1,2,3]def PrintFromTopToBottom(self, root):# write code hereif not root:return []res = []queue = [root]while queue:temp = queuequeue = []for i in temp:res.append(i.val)if i.left:queue.append(i.left)if i.right:queue.append(i.right)return res

(2)JZ61 序列化二叉树

class Solution:def Serialize(self, root):if not root:return '#'return str(root.val) + ',' + self.Serialize(root.left)+ ',' + self.Serialize(root.right)def Deserialize(self, s):root, index = self.deserialize(s.split(","), 0)return rootdef deserialize(self,s,index):if s[index]=='#':return None, index+1root = TreeNode(int(s[index]))index += 1root.left, index = self.deserialize(s, index)root.right, index = self.deserialize(s, index)return root, index

2.20 树

(1)JZ4 重建二叉树

描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

class Solution:# 返回构造的TreeNode根节点def reConstructBinaryTree(self, pre, tin):# write code hereif len(pre) == 0:return Noneelif len(pre) == 1:return TreeNode(pre[0])if len(pre) == 1:head = TreeNode(pre[0])head.left = Nonehead.right = Nonereturn headhead = TreeNode(pre[0])      temp1 = tin.index(pre[0])length = len(tin[:temp1])if temp1 == 0:head.left = Noneelse:head.left = self.reConstructBinaryTree(pre[1:length+1], tin[:temp1])if length + 1 < len(pre):head.right = self.reConstructBinaryTree(pre[length+1:], tin[temp1+1:])else:head.right = Nonereturn head

(2)JZ17 树的子结构

描述

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

class Solution:def HasSubtree(self, pRoot1, pRoot2):result = Falseif pRoot1 and pRoot2:if pRoot1.val == pRoot2.val:result = self.DoesTree1HaveTree2(pRoot1,pRoot2)if not result:result = self.HasSubtree(pRoot1.left, pRoot2)if not result:result = self.HasSubtree(pRoot1.right, pRoot2)return result# 这个也是递归,一个有着边界条件的递归def DoesTree1HaveTree2(self, pRoot_A, pRoot_B):if not pRoot_B:return Trueif not pRoot_A:return Falseif pRoot_A.val != pRoot_B.val:return Falsereturn self.DoesTree1HaveTree2(pRoot_A.left, pRoot_B.left) and self.DoesTree1HaveTree2(pRoot_A.right, pRoot_B.right)

(3)JZ18 二叉树的镜像

描述

操作给定的二叉树,将其变换为源二叉树的镜像。

class Solution:def Mirror(self , pRoot ):# write code hereif pRoot == None:return Nonequeue = [pRoot]res = [] # 存储多行while queue:val = queue.pop()val.left, val.right = val.right, val.leftif val.left:queue.append(val.left)if val.right:queue.append(val.right)return pRoot

(4)JZ22 从上往下打印二叉树

描述

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

class Solution:# 返回从上到下每个节点值列表,例:[1,2,3]def PrintFromTopToBottom(self, root):# write code hereif not root:return []res = []queue = [root]while queue:temp = queuequeue = []for i in temp:res.append(i.val)if i.left:queue.append(i.left)if i.right:queue.append(i.right)return res

(5)JZ23 二叉搜索树的后序遍历序列

描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。(ps:我们约定空树不是二叉搜素树)

# -*- coding:utf-8 -*-
class Solution:def VerifySquenceOfBST(self, sequence):# write code hereif not sequence:return Falsereturn self.check(sequence)def check(self, arr):if len(arr) <= 2:return True# 寻找第一个大于root的值root = arr[-1]p = 0while arr[p] < root:p += 1index = p# 判断右边都是大于root的值while index < len(arr) -1:if arr[index] > root:index += 1else:return Falsereturn self.check(arr[:index]) and self.check(arr[index:-1])

(6)JZ24 二叉树中和为某一值的路径

描述

输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

class Solution:# 返回二维列表,内部每个列表表示找到的路径def FindPath(self, root, expectNumber):def dfs(root, expectNumber):path.append(root.val)expectNumber -= root.valif not root.left and not root.right and expectNumber == 0:ret.append(list(path))if root.left:dfs(root.left, expectNumber)if root.right:dfs(root.right, expectNumber)path.pop()# write code hereif not root:return Noneret, path = [], []dfs(root, expectNumber)return ret

(7)JZ38 二叉树的深度

描述

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

class Solution:def TreeDepth(self, pRoot):# write code hereif not pRoot:return 0if pRoot and not pRoot.left and not pRoot.right:return 1res = 1 + max(self.TreeDepth(pRoot.left), self.TreeDepth(pRoot.right))return res

(8)JZ39 平衡二叉树

描述

输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

class Solution:def IsBalanced_Solution(self, pRoot):# write code hereif not pRoot:return Trueelse:res = abs(self.dapth(pRoot.left) - self.dapth(pRoot.right)) <=1 \and self.IsBalanced_Solution(pRoot.left) \and self.IsBalanced_Solution(pRoot.right) return res# 计算每个结点的高度def dapth(self, root):if not root:return 0 else:return 1 + max(self.dapth(root.left), self.dapth(root.right))

(9)JZ57 二叉树的下一个结点
描述

给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。下图为一棵有9个节点的二叉树。树中从父节点指向子节点的指针用实线表示,从子节点指向父节点的用虚线表示.

class Solution:def GetNext(self, pNode):if not pNode:return pNode# 右子树中的最左子树if pNode.right:pNode = pNode.rightwhile pNode.left:pNode = pNode.leftreturn pNode# 判断父节点是否存在while pNode.next:root = pNode.nextif root.left == pNode:return rootpNode = pNode.nextreturn None

(10)JZ58 对称的二叉树

描述

请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

class Solution:def isSymmetrical(self, pRoot):if not pRoot:return Truedef comp_value(pleft, pright):if not pleft and not pright:return Trueif not pleft or not pright:return Falseif pleft.val != pright.val:return Falsereturn comp_value(pleft.left, pright.right) and comp_value(pleft.right, pright.left)return comp_value(pRoot, pRoot)

(11)JZ59 按之字形顺序打印二叉树

描述

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

class Solution:# 返回二维列表[[1,2],[4,5]]def Print(self, pRoot):# write code hereif not pRoot:return []res = []queue = [pRoot]high = 0while queue:temp = []for _ in range(len(queue)):cur = queue.pop(0)temp.append(cur.val)if cur.left:queue.append(cur.left)if cur.right:queue.append(cur.right)high += 1if high % 2 == 0:temp = temp[::-1]res.append(temp)return res

(12)JZ60 把二叉树打印成多行

描述

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

# 使用层次遍历来输出结果
class Solution:# 返回二维列表[[1,2],[4,5]]def Print(self, pRoot):# write code hereif pRoot == None:return Nonequeue = [pRoot]res = [] # 存储多行while queue:val = queue.pop()res.append(val.val)if val.left:queue.append(val.left)if val.right:queue.append(val.right)return res

(13)JZ62 二叉搜索树的第k个结点

class Solution:# 返回对应节点TreeNodedef KthNode(self, pRoot, k):# write code heredef pre_order(pRoot):if pRoot:pre_order(pRoot.left)list.append(pRoot)pre_order(pRoot.right)list = []pre_order(pRoot)# 冒泡排序for i in range(len(list)):for j in range(0, len(list)-i-1):if list[j].val > list[j+1].val:list[j], list[j+1] = list[j+1], list[j]if k == 0 or k > len(list):return Nonereturn list[k-1]

2.21 哈希

(1)JZ28 数组中出现次数超过一半的数字

描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。你可以假设数组是非空的,并且给定的数组总是存在多数元素。1<=数组长度<=50000

class Solution:def MoreThanHalfNum_Solution(self, numbers):# write code here# sort the listif not numbers:return []if len(numbers) == 1:return numbers[0]numbers.sort()i ,count = 1,1while i < len(numbers):j = iwhile numbers[j] == numbers[j-1]:count += 1j += 1if count>len(numbers)/2:return numbers[j-1]i = ji += 1return None

(2)JZ40 数组中只出现一次的两个数字

描述

一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

class Solution:def FindNumsAppearOnce(self , array ):# write code hereXORsum = 0for i in array:XORsum ^= it = 1while (XORsum&t)==0:t = t<<1ans1 = 0ans2 = 0for i in array:if (t&i)==0:ans1 ^= ielse:ans2 ^= iif ans1<ans2:return [ans1,ans2]else:return [ans2,ans1]

2.22 堆

(1)JZ29 最小的K个数

描述

给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。如果K>数组的长度,那么返回一个空的数组

# -*- coding:utf-8 -*-
class Solution:def GetLeastNumbers_Solution(self, tinput, k):# write code herelength = len(tinput)if (k > length) or tinput == []:return []var = tinput[0]for i in range(1, length):key = tinput[i]j = i - 1while j>=0 and key < tinput[j]:tinput[j+1] = tinput[j]j = j -1tinput[j+1] = keyreturn tinput[:k]

(2)JZ63 数据流中的中位数

描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

import heapq
class Solution:def __init__(self):self.count = 0self.max_heap = []self.min_heap = []def Insert(self, num):# write code hereself.count += 1#将数据放到最大堆中heapq.heappush(self.max_heap, -num)#将最大堆中的堆顶元素放到最小堆中max_heap_top = heapq.heappop(self.max_heap)heapq.heappush(self.min_heap, -max_heap_top)#如果最小堆和最大堆之间的差距大于1,将最小堆中的堆顶放进最大堆if self.count & 1:min_heap_top = heapq.heappop(self.min_heap)heapq.heappush(self.max_heap, -min_heap_top)#题目getmedian参数少了个s       def GetMedian(self):# write code hereif self.count & 1:return -self.max_heap[0]else:return (self.min_heap[0] - self.max_heap[0]) / 2.0

(3)JZ64 滑动窗口的最大值

描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。

例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

窗口大于数组长度的时候,返回空

# -*- coding:utf-8 -*-
class Solution:def maxInWindows(self, num, size):# write code hereif len(num) < size or not num or size == 0:return []var = []i = 0while i <= len(num)-size:var.append(max(num[i:i+size]))i += 1return var

剑指offer:https://www.nowcoder.com/ta/coding-interviews

剑指offer刷题总结相关推荐

  1. 【LeetCode 剑指offer刷题】树题6:28 对称二叉树(101. Symmetric Tree)

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 101. Symmetric Tree /**  * Definition for a binary tree no ...

  2. 【LeetCode 剑指offer刷题】数组题2:57 有序数组中和为s的两个数(167 Two Sum II - Input array is sorted)...

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 57 有序数组中和为s的两个数 题目描述 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是 ...

  3. 【LeetCode 剑指offer刷题】字符串题6:67 把字符串转成整数

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 67 把字符串转成整数 题目描述 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 数值为0或者字符 ...

  4. 【LeetCode 剑指offer刷题】树题16:Kth Smallest Element in a BST

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Kth Smallest Element in a BST Given a binary search tree, ...

  5. 【LeetCode 剑指offer刷题】回溯法与暴力枚举法题6:Number of Islands

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Number of Islands Given a 2d grid map of '1's (land) and ' ...

  6. 【LeetCode 剑指offer刷题】查找与排序题14:Wiggle Sort(系列)

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Wiggle Sort II Given an unsorted array nums, reorder it su ...

  7. 【LeetCode 剑指offer刷题】查找与排序题12:Top K Frequent Elements

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Top K Frequent Elements Given a non-empty array of integer ...

  8. 【LeetCode 剑指offer刷题】矩阵题1:4 有序矩阵中的查找( 74. Search a 2D Matrix )(系列)...

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 74. Search a 2D Matrix Write an efficient algorithm that s ...

  9. 【LeetCode 剑指offer刷题】树题19:8 二叉树中序遍历的下一个结点

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 8 二叉树中序遍历的下一个结点 题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注 ...

  10. 【LeetCode 剑指offer刷题】字符串题12:Valid Palindrome(回文词系列)

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Valid Palindrome Given a string, determine if it is a pali ...

最新文章

  1. BZOJ2743 [HEOI2012]采花
  2. python新手教程 从零开始-Python零基础从零开始学习Python十分钟快速入门
  3. codeforce 457DIV2 C题
  4. 剑指Offer - 面试题36. 二叉搜索树与双向链表(中序循环/递归)
  5. python的os库_os库(python)—总结
  6. (70)FPGA面试题-使用不同的代码实现2:1 MUX ?使用case语句
  7. 服务器 自检 修改,检查多台服务器初始密码是否修改的shell脚本
  8. [转]VUE优秀UI组件库合集
  9. 安装32位linux系统安装教程,Ubuntu16.04安装32位支持库
  10. 一文精讲Wireshark的抓包和分析
  11. 数字电路技术基础-1-补码
  12. c语言实验报告字符数组,C语言实验报告《数组》
  13. /* 商人过河的问题 假如有三个商人各带一个随从要过河。 只有一条船得需要他们划每次只能坐两个人,条件是任何一岸的随从多于商人时随从就会抢劫商人。 请问这三个商人怎样才能安全过河? */...
  14. android壁纸制作,安卓动态壁纸制做壁纸的方法教程
  15. java文件存储系统_分布式小文件存储系统
  16. 发现panda(熊猫)对W32.Looked.I处理得不错
  17. Linux磁盘挂载、扩容、删除
  18. 极客时间_软件设计之美 笔记
  19. 微信公众号自动回复功能
  20. 温梦欣:跨界创业—太空经济时代的创业故事|创新社创新课堂

热门文章

  1. Day 11 - 视频转换成图片
  2. 【PhotoShop】ps 基础知识
  3. 2021年信息系统监理师考试大纲
  4. Typecho 插件开发基础
  5. 动作捕捉——从模型到动画个人流程记录
  6. 【微信小程序】解决Echarts在微信小程序tab切换时的显示问题
  7. vue点击按钮跳转页面
  8. python爬虫-计算机要点
  9. vtk学习教程(一)
  10. PS照片处理尺寸参考表