剑指Offer题解(3-40)
面试题03. 数组中重复的数字
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
1 | 输入: |
思路和代码:
1 | class Solution { |
面试题04. 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 matrix 如下:
1 | [ |
给定 target = 5,返回 true。
给定 target = 20,返回 false。
思路和代码:
我们分析该二维数组的特点,左到右递增,上到下递增,因此可以从右上角开始寻找。
如果比目标值大,就往左边找,如果比目标值小,就往下边找。
1 | class Solution { |
面试题05. 替换空格
请实现一个函数,把字符串 s 中的每个空格替换成”%20”。
示例 1:
1 | 输入:s = "We are happy." |
思路和代码:
这道题很简单没什么好说的,利用StringBuilder拼接字符串即可,如果遇到空格就替换。
1 | class Solution { |
面试题06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
1 | `输入:head = [``1``,``3``,``2``]``输出:[``2``,``3``,``1``]` |
思路和代码:
方法一:利用LinkedList顺序保存链表,然后逆序保存到结果数组中返回即可。
1 | class Solution { |
方法二:递归至尾节点后逐步输出
1 | class Solution { |
面试题07. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
1 | `前序遍历 preorder = [``3``,``9``,``20``,``15``,``7``]``中序遍历 inorder = [``9``,``3``,``15``,``20``,``7``]` |
返回如下的二叉树:
1 | 3 |
思路和代码:
1 | class Solution { |
面试题09. 用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
示例 1:
1 | 输入: |
示例 2:
1 | 输入: |
思路和代码:
1 | class CQueue { |
面试题10- I. 斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
1 | F(0) = 0, F(1) = 1 |
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
1 | `输入:n = ``2``输出:``1` |
示例 2:
1 | 输入:n = 5 |
思路和代码:
简单的动态规划
1 | class Solution { |
面试题10- II. 青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
1 | `输入:n = ``2``输出:``2` |
示例 2:
1 | 输入:n = 7 |
提示:
0 <= n <= 100
思路和代码:
简单的动态规划,跳到0或1级有1种方法,之后跳到i的方法数量=跳到i-1的方法数量+跳到i-2的方法数量(因为每次可以跳1或2级)。
由于每次结果要取模所以要mod1000000007。
方法一、空间复杂度O(n)
1 | class Solution { |
方法二、优化为O(1)空间复杂度
1 | class Solution { |
面试题11. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一 个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
1 | 输入:[3,4,5,1,2] |
示例 2:
1 | 输入:[2,2,2,0,1] |
思路和代码:
方法一、从头遍历,如果一个数字大于它的下一个,就返回它的下一个。
例如示例1,5>1,返回1,示例2,2>0,返回0。
如果没找到就返回第一个,例如12345返回1。
1 | class Solution { |
方法二、优化为二分查找
1 | class Solution { |
面试题12. 矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,”b“,”c”,”e”],
[“s”,”f“,”c“,”s”],
[“a”,”d”,”e“,”e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
示例 1:
1 | 输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" |
示例 2:
1 | 输入:board = [["a","b"],["c","d"]], word = "abcd" |
思路和代码:
使用深度优先搜索回溯,从全部字符以头开始遍历,如果寻找到了就直接返回true,否则继续以下一个字符为头重新开始。
k代表已经成功匹配的字符数量,初始为0,每匹配一个加1,当达到目标长度时返回true。
每次进行下一层搜索时将当前字符设为一个非字母值,这样可以防止重复遍历。
1 | class Solution { |
面试题13. 机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0]的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
示例 1:
1 | 输入:m = 2, n = 3, k = 1 |
示例 2:
1 | 输入:m = 3, n = 1, k = 0 |
提示:
1 <= n,m <= 1000 <= k <= 20
思路和代码:
由于最多100行,100列,因此索引从0~99。用/和%计算各位的数字之和,例如35和37,35/10+35%10+37/10+37%10=18。
一、DFS
1 | class Solution { |
二、BFS
1 | class Solution { |
面试题14- I. 剪绳子
给你一根长度为 n 的绳子 ,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m] 。请问 k[0]*k[1]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
1 | 输入: 2 |
示例 2:
1 | 输入: 10 |
提示:
2 <= n <= 58
思路和代码:
推论一: 将绳子 以相等的长度等分为多段 ,得到的乘积最大。
推论二: 尽可能将绳子以长度 3 等分为多段时,乘积最大。
1 | class Solution { |
或者分三种情况直接求积
切分规则:
最优: 3 。把绳子尽可能切为多个长度为 3 的片段,留下的最后一段绳子的长度可能为 0,1,2三种情况。
次优: 2 。若最后一段绳子长度为 2 ;则保留,不再拆为 1+1 。
最差: 1 。若最后一段绳子长度为 1 ;则应把一份 3+1 替换为 2+2,因为 2×2 > 3×1。
1 | class Solution { |
面试题14- II. 剪绳子 II
给你一根长度为 n 的绳子 ,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m] 。请问 k[0]*k[1]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
思路和代码:
同上一题,取个模就行
1 | class Solution { |
面试题15. 二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
示例 1:
1 | 输入:00000000000000000000000000001011 |
示例 2:
1 | 输入:00000000000000000000000010000000 |
思路和代码:
方法一、根据与运算特点,使n与1逐位比较,判断n最右一位是否为1,根据结果计数
1 | public class Solution { |
方法二、利用n&(n-1)
- (n−1) : 二进制数字 n 最右边的 1 变成 0 ,此 1 右边的 0 都变成 1 。
- n&(n−1) : 二进制数字 n 最右边的 1 变成 0 ,其余不变。
1 | public class Solution { |
面试题16. 数值的整数次方
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
示例 1:
1 | 输入: 2.00000, 10 |
示例 2:
1 | 输入: 2.10000, 3 |
示例 3:
1 | 输入: 2.00000, -2 |
思路和代码:
快速幂法,注意区分奇偶即可
1 | class Solution { |
面试题17. 打印从1到最大的n位数
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
1 | 输入: n = 1 |
说明:
用返回一个整数列表来代替打印
n 为正整数
思路和代码:
本意是考察大数问题,不考虑大数解法:
1 | class Solution { |
大数问题解法:
1 | public class solution { |
面试题18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
示例 1:
1 | 输入: head = [4,5,1,9], val = 5 |
示例 2:
1 | 输入: head = [4,5,1,9], val = 1 |
思路和代码:
1 | class Solution { |
面试题19. 正则表达式匹配
请实现一个函数用来匹配包含'. '和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但与"aa.a"和"ab*a"均不匹配。
示例 1:
1 | 输入: |
示例 2:
1 | 输入: |
示例 3:
1 | 输入: |
示例 4:
1 | 输入: |
思路和代码:
1 | class Solution { |
面试题20. 表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”、”5e2”、”-123”、”3.1416”、”0123”都表示数值,但”12e”、”1a3.14”、”1.2.3”、”+-5”、”-1E-16”及”12e+5.4”都不是。
思路和代码:
[abc]表示匹配a、b、c任意一个即可。[0-9]表示匹配数字0-9
\\.表示小数点,?表示0或1次,+表示1或多次,*表示任意次,|表示或。
首先判断开头,[+-]?表示可以以加号或减号开头,也可以不以加减号开头。
数字部分是[0-9]+\\.?表示0-9必须出现一次,小数点可以不出现,例如111,11.
或者是[0-9]*\\.[0-9]+,表示小数点前任意次,小数点必须有,小数点后必须有,例如.5,1.5
最后指数[e][+-]?[0-9]+匹配时表示必须有e,正负号可有可无,有e时后面必须有数字,?表示也可以没指数。
1 | class Solution { |
面试题21. 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示例:
1 | 输入:nums = [1,2,3,4] |
思路与代码:
类似于快速排序的思想,使用双指针,从头找偶数,从尾找奇数,然后交换它们的位置。
1 | class Solution { |
面试题22. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
示例:
1 | 给定一个链表: 1->2->3->4->5, 和 k = 2. |
思路和代码:
使用双指针,让前指针先走k个,这样当前指针为null时后指针就是答案。
1 | class Solution { |
面试题24. 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
1 | 输入: 1->2->3->4->5->NULL |
思路和代码:
方法一、利用两个指针,pre指针保存前一个节点,cur指针用于遍历链表, 每次迭代到 cur,都将 cur 的 next 指向 pre,然后 pre 和 cur 前进一位。

1 | class Solution { |
方法二、递归

1 | class Solution { |
面试题25. 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
1 | 输入:1->2->4, 1->3->4 |
思路和代码:
比较简单,由于是有序链表,所以分别从头开始遍历,如果l1更小,将节点的下一个指向l1,否则就指向l2。如果有一个为空,就将另一个剩下的链表直接拼接。
1 | class Solution { |
面试题26. 树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
示例 1:
1 | 输入:A = [1,2,3], B = [3,1] |
示例 2:
1 | 输入:A = [3,4,5,1,2], B = [4,1] |
思路和代码
递归即可
1 | class Solution { |
面试题27. 二叉树的镜像
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
示例 :
1 | 输入: 4 |
思路和代码
方法一、简单递归
1 | class Solution { |
方法二、借助辅助栈或队列
1 | class Solution { |
面试题28. 对称的二叉树
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1 | 1 |
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1 | 1 |
思路和代码:
如果根节点为空,那么空节点是对称的,否则比较它的左右子树是否对称。
如果都为空那对称,如果只有一个为空肯定不对称。
如果都不为空那么比较值,值不同肯定不对称,如果值相同,再比较左节点的右子树和右节点的左子树是否对称(最里面那一层),比较左节点的左子树和右节点的右子树是否对称(最外面那一层)。
1 | class Solution { |
面试题29. 顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
1 | 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] |
示例 2:
1 | 输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] |
限制:
0 <= matrix.length <= 1000 <= matrix[i].length <= 100
思路和代码:
在循环中按照右下左上的顺序循环,每次改变方向前先判断是否越界。
1 | class Solution { |
面试题30. 包含min函数的栈
定义栈的数据结构,请在该类型中 实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
1 | MinStack minStack = new MinStack(); |
思路和代码:
使用一个辅助栈helper作为最小栈,进栈出栈helper都没有限制,对于最小栈helper只有helper为空或入栈节点值小于等于helper栈顶时才可入栈,出栈时,只有data和helper栈顶相同helper才出栈。
1 | class MinStack { |
面试题31. 栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
示例 1:
1 | 输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1] |
示例 2:
1 | 输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2] |
思路和代码:
借助一个栈来模拟弹出操作,依次将pushed数组中的元素入栈,并与poped数组中元素值比较,若相等即立刻弹出,循环结束栈空则说明符合。
1 | class Solution { |
面试题32 - I. 从上到下打印二叉树
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
例如:
给定二叉树: [3,9,20,null,null,15,7],
1 | 3 |
返回:
1 | [3,9,20,15,7] |
思路和代码:
利用队列存储二叉树每一层的节点,当队列非空时将节点从头移除并加入结果集。然后按照先左后右将下一层节点加入队列。
1 | class Solution { |
面试题32 - II. 从上到下打印二叉树 II
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
例如:
给定二叉树: [3,9,20,null,null,15,7],
1 | 3 |
返回:
1 | [ |
思路和代码:
和上一题类似,只是要将每一行的数值保存到同一个list中。每次出队之前先计算当前队列的大小,这个大小就是这一层的节点数量,然后按这个数量依次从队头移除。
1 | class Solution { |
DFS的递归解法参考
1 | public List<List<Integer>> levelOrder(TreeNode root) { |
面试题32 - III. 从上到下打印二叉树 III
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
例如:
给定二叉树: [3,9,20,null,null,15,7],
1 | 3 |
返回:
1 | [ |
思路和代码:
在上一题的基础上判断每一层的奇偶,利用双端队列对每层选择不同的输入方式(偶数从头进,奇数从尾进)。
1 | class Solution { |
或者设置层数标识符来进行判断和逆序操作
1 | class Solution { |
DFS解法参考
1 | public List<List<Integer>> levelOrder(TreeNode root) { |
面试题33. 二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
1 | 5 |
示例 1:
1 | 输入: [1,6,3,2,5] |
示例 2:
1 | 输入: [1,3,2,6,5] |
思路和代码:
方法一、递归,根据后序遍历左-右-根的特点,从左边找到第一个大于根节点的值划分左右子树,左子树的值必须都比该值小(由于找到的是第一个大于根节点的值,这点肯定满足),接下来由于右子树都比根节点值大,再找到第一个不大于根节点的值,此时索引肯定等于根节点,如果不等于就是false。
1 | class Solution { |
方法二、辅助栈,利用后续遍历的倒序,遍历数组。借助单调栈tmp存储递增节点,每当遇到递减节点时,通过出栈来更新当前节点的父节点,每轮判断当前节点和父节点的大小,大于父节点,返回false,小于则继续遍历。
1 | class Solution { |
面试题34. 二叉树中和为某一值的路径
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
示例:
给定如下二叉树,以及目标和 sum = 22,
1 | 5 |
返回:
1 | [ |
思路和代码:
回溯法,先序遍历: 按照 “根、左、右” 的顺序,遍历树的所有节点。
路径记录: 在先序遍历中,记录从根节点到当前节点的路径。当路径为 ① 根节点到叶节点形成的路径 且 ② 各节点值的和等于目标值 sum 时,将此路径加入结果列表。
1 | class Solution { |
面试题35. 复杂链表的复制
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例 1:

1 | 输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] |
示例 2:

1 | 输入:head = [[1,1],[2,1]] |
示例 3:

1 | 输入:head = [[3,null],[3,0],[3,null]] |
示例 4:
1 | 输入:head = [] |
提示:
-10000 <= Node.val <= 10000Node.random为空(null)或指向链表中的节点。节点数目不超过 1000 。
思路和代码:
方法一、链表原地复制节点和指针,然后断开形成新链表。
1 | class Solution { |
方法二、哈希表复制
1 | class Solution { |
面试题36. 二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
思路和代码:
是二叉搜索树,使用中序遍历从小到大遍历即可,每次遍历的时候把当前节点的left指向前一个节点,把前一个节点的right指向当前节点。
遍历到的第一个节点就是最小节点,此时head就是它,从第二个节点开始操作,每次更新pre。
遍历完之后pre就是最后一个节点,再把它和head连起来。
1 | class Solution { |
面试题 37. 序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树。
示例:
1 | 你可以将以下二叉树: |
思路和代码:
层序遍历BFS,只附代码参考
1 | public class Codec { |
面试题38. 字符串的排列
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
1 | 输入:s = "abc" |
思路和代码:
简单的回溯思想,重复方案与剪枝: 当字符串存在重复字符时,排列方案中也存在重复方案。为排除重复方案,需在固定某位字符时,保证 “每种字符只在此位固定一次” ,即遇到重复字符时不交换,直接跳过。从 DFS 角度看,此操作称为 “剪枝” 。
1 | class Solution { |
面试题39. 数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
1 | 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] |
限制:
1 | 1 <= 数组长度 <= 50000 |
思路和代码:
摩尔投票法:
- 票数和: 由于众数出现的次数超过数组长度的一半;若记 众数 的票数为
+1,非众数 的票数为-1,则一定有所有数字的 票数和> 0。 - 票数正负抵消: 设数组
nums中的众数为x,数组长度为n。若 nums 的前a个数字的 票数和= 0,则 数组后(n-a)个数字的 票数和一定仍> 0(即后(n−a)个数字的 众数仍为x)。
1 | class Solution { |
面试题40. 最小的k个数
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
1 | 输入:arr = [3,2,1], k = 2 |
示例 2:
1 | 输入:arr = [0,1,2,1], k = 1 |
思路和代码:
总结的很好
1 | //计数排序的方法 |