![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
leetcode剑指offer
记录
624回锅肉
这个作者很懒,什么都没留下…
展开
-
剑指 Offer 45 把数组排成最小的数
题目:给一个int数组,每个int可以进行拼接,返回一个最小的数。用String返回。 public String minNumber(int[] nums) 思路:用快速排序,用字典序进行排序。 如”12”和”34”,可拼为”1234”或”3412”,前面小于后面,所以”12”应该排在”34”前面。 可记为”12”<”34”。 用(strs[l]+strs[j]).compareTo(strs[j]+strs[l]) <= 0这种形式来制定排序规则。 1.快速排序要背完整。一定是在循环里交原创 2021-03-15 14:33:37 · 69 阅读 · 0 评论 -
剑指 Offer 44 数字序列中某一位的数字
题目:序列化的数字,0123456789101112131415…。0对应第0位,9对应第9位,但是第10位为1。给你一个n,让你求第n位的数字是几?(0~9) public int findNthDigit(int n) 思路:找规律题。 1.先根据n来找到该数字的位数 (1位数,1到9,有9位。2位数,10到99,有180位=9乘10乘2。3位数,100到999,有2700位=9乘100乘3。用interval-1表示该n与start=1/10/100…的距离,digit表示所求位数。 可以使用whil原创 2021-03-12 20:57:28 · 77 阅读 · 0 评论 -
剑指 Offer 43 1~n整数中1出现的次数
题目:输入一个int数,求1到到该数中1的次数。 public int countDigitOne(int n) 思路:1.用基本的方法,遍历+每位统计,时间复杂度O(nlog10n),复杂度太大。 2.用每位固定为1,然后看有多少种情况。用找规律的方法来做。 当前位分为3种情况,分别是0,1和2~9。对应的1的数量和规律不同。 把数字分为当前位cur,高位high和低位low,用digit来表示当前的是什么位,digit等于1是当前是个位。 然后cur,high,low不断变化,结果不断累积到res上,原创 2021-03-10 13:48:05 · 109 阅读 · 0 评论 -
剑指 Offer 42 连续子数组的最大和
题目:一个整数数组,有正数和负数。求连续的子数组的和。 public int maxSubArray(int[] nums) 思路: 用动态规划,dp[i]。这里dp[i]表示以nums[i]结尾的连续数组的最大值。因为这连续数组不一定是从nums[0]开始的,但一定是以nums[i]结尾的。 dp[i]为正数的话dp[i+1]就把dp[i]加上,如果是负数的话就不加,就直接是nums[i]。 先把用dp[]的写出来,时间和空间复杂度都为O(n)。然后再把dp[i]和dp[i+1]用变量保存,进行空间优化原创 2021-03-09 11:45:08 · 76 阅读 · 0 评论 -
剑指 Offer 41 数据流中的中位数
题目:数据不断的进入,要求实现addNum()和findMedian()两个函数。来进行数字的添加和中位数的查找。 public void addNum(int num) public double findMedian() 思路:1.先说一下基本的思路: 可以对目前的数据进行排序,如使用快速排序O(nlogn),然后直接返回中间的那个数O(1)。 2. 一:维护较大元素区间的minHeap和一个维护较小元素区间的maxHeap 二:怎么维持?用什么条件判断?(addNum的实现内容) 三:返回中位数时用什原创 2021-03-08 16:33:32 · 71 阅读 · 0 评论 -
剑指 Offer 40 最小的k个数
题目:给一个无序数组,求前k个最小的数,排好序放到数组里输出。 public int[] getLeastNumbers(int[] arr, int k) 思路:1.先用快速排序,然后直接用Arrays.copyOf(arr,k)截取前k个元素并复制为新的数组返回,原数组不变。 快速排序(第一个元素为标准,且标准只在最后交换一次到中间) 快速排序是以第一个元素为标准,但是这个标准不移动,而是让其它元素进行交换移动,最后才把标准交换到中间。标准只交换一次。 快速排序自己实现实现 /* 快排,模板原创 2021-03-04 17:24:44 · 116 阅读 · 1 评论 -
剑指 Offer 39 数组中出现次数超过一半的数字
题目:输出数组中数量超过一半的数字。要求1.数组中一定有数量超过一半的数字2.数组中可能没有数量超过一半的数字,此时返回-1 public int majorityElement(int[] nums) 思路: 思路很浅显,就是先假定第一个数字为目标数字num,然后次数votes给1(用times也行)。遍历数组,如果后面那个元素和num相等则votes加1,不等则减1。当votes为0时,改变num为最新的假定目标数字。 是这个思路,拿变量试一试就好。 会用到nums[i+1],所以要做下标越界判断(如原创 2021-03-03 11:26:56 · 61 阅读 · 0 评论 -
剑指 Offer 38 字符串的排列
题目:求字符串的全排列,并返回。需要考虑字符串里有重复的字符,最后结果不重复才行。 public String[] permutation(String s) 思路:背模板,模板题。 大致思路是第一个位置有n种放法,第二个位置有n-1种放法,然后实现用char[]中元素交换的回溯法traceback实现。 背一下全排列基本回溯法: traceback为递归方法。从0开始递归,for循环里为交换x和i,递归,再把x和i交换回来。当递归参数x到倒数第一个时(最后一个已经确定),就把add进resList中。原创 2021-03-02 16:17:23 · 60 阅读 · 0 评论 -
剑指 Offer 36 二叉搜索树与双向链表
题目:把二叉搜索树转化为元素有序的双向循环链表。(因为二叉树有左右指针,双遍链表也有左右指针) public Node treeToDoublyList(Node root) 思路: 二叉搜索树的中序遍历为有序。所以用中序遍历。 用pre指针保存上一层递归中root的指向(刚开始pre为null,可以确定head。然后pre比root慢一拍然后一直往后)。用pre和下一层递归的root进行连接。 最后pre停在链表尾部,直接把pre当做尾,和head进行连接,然后返回。 public class Bin原创 2021-02-28 13:34:05 · 68 阅读 · 0 评论 -
剑指 Offer 35 复杂链表的复制
题目:带有random指针的链表节点(可指向任意一个元素或null),完成该链表的复制。 public Node copyRandomList(Node head) 思路: 使用Map<Node,Node>保存上下链表各元素之间的映射。 平行对应,上面一个7对应下面的一个7。来完成random关系的复制。 可以先走一遍把节点创建出来,并把Map做好。然后再来一遍,用上下一一对应的关系,把next和random的关系复制出来。 时间:O(n) 空间:O(n) Map额外空间为O(n),新创建的原创 2021-02-27 17:37:16 · 62 阅读 · 0 评论 -
剑指 Offer 34 二叉树中和为某一值的路径
题目:二叉树从root到叶子节点的path称为路径。把所有路径和为sum的路径保存到list当中返回。返回结果为List<List>类型。 public List<List> pathSum(TreeNode root, int sum) 思路:递归模拟遍历,把符合的路径保存。 注意: List变量一般只能放到类属性中,无法放到递归方法的参数中(因为list传递的是引用,无法用递归来回退) 用List<List>来保存list时,需要创建list实体然后再保存,如原创 2021-02-25 11:34:14 · 71 阅读 · 0 评论 -
剑指 Offer 33 二叉搜索树的后序遍历序列
题目:给一个序列,判断该序列是否是一个二叉搜索树的后序遍历序列。是则返回true,否则返回false。 public boolean verifyPostorder(int[] postorder) 思路: 写一个bool recur(int[] postorder,int start,int end)递归函数,用二叉搜索树的性质来分割左右子树。只有左子树都小于root,右子树都大于root才行。然后分别递归左右子树。 注意:当没有左子树或没有右子树时,返回true的条件应该为start>=end,因原创 2021-02-24 11:37:33 · 93 阅读 · 0 评论 -
剑指 Offer 32 从上到下打印二叉树
(一) 题目:给一个二叉树,把层序遍历序列放到数组里返回。 public int[] levelOrder(TreeNode root) 思路: 层序遍历,非递归,用队列实现 1.先把root(非null)放到队列中 2.queue把头部元素弹出,并把头部元素的left和right加入queue(只加入非null元素) 3.不断循环,直到queue为empty,因为不加null结点,结点只会越来越少。 注意: 刚开始不知道root中非null结点的个数,所以先用arrayList保存。最后用list.siz原创 2021-02-03 15:12:04 · 85 阅读 · 0 评论 -
剑指 Offer 31 栈的压入、弹出序列
题目:给一个栈的push和pop的序列,让你判断这个pop的序列是否是符合规则的(元素都不相等),符合规则返回true,不符合返回false。 public boolean validateStackSequences(int[] pushed, int[] popped) 思路: 思路不完全清楚别去写代码(否则就是在浪费时间)。一定要先把思路固定再说其他,固定不下来就花更多的精力去固定,直到固定下来。 核心就是先push,再去判断。为什么? 因为给你push序列,你就只能先去push,然后在过程中去拿s原创 2021-02-02 16:00:17 · 80 阅读 · 0 评论 -
剑指 Offer 30 包含min函数的栈
题目:可以用栈的数据结构。实现一个可以返回最小值的栈的api,有push pop top min方法。 public void push(int x) public void pop() public int top() public int min() 思路:用两个栈stackA和stackB。 既然还需要实现一个栈的push和pop和top功能,所以这些元素肯定都要放到stackA中来用它来实现这些方法(因为stackA本来就是个栈)。那stackB就自然用来实现min方法。 当push时stackA原创 2021-02-01 15:20:58 · 66 阅读 · 0 评论 -
剑指 Offer 29 顺时针打印矩阵
题目:给一个二维数组(矩阵),让按顺时针(从左到右,从上到下,从右到左,从下到上)的顺序放到数组里返回,如果让打印的话直接输出。 public int[] spiralOrder(int[][] matrix) 思路:就按顺序遍历。 1.不只有一圈,所以用while(true)来做,超过边界就break。而且多使用i++和++i才简化代码。 2.一圈分为四部分,那每部分的for中,变量该如何确定? 通过到达边界时要改变的变量来确定(比如第一行从左到右,到边界时要向下走一格,++top,所以这个for变量用原创 2021-01-31 15:13:41 · 101 阅读 · 0 评论 -
剑指 Offer 28 对称的二叉树
题目:给一个二叉树,判断它是否是对称的(当树为null时也返回true)。 public boolean isSymmetric(TreeNode root) symmetric-对称的 adj. 思路: 用root.left和root.right分支进行判断。需要满足l.left和r.right,l.right和r.left对应才行。这里使用了一个二叉树的递归方法isSymmetricDetails(TreeNode l,TreeNode r)的方法。 核心是:理清二叉树递归方法里什么时候返回tr原创 2021-01-25 11:48:13 · 58 阅读 · 0 评论 -
剑指 Offer 27 二叉树的镜像
题目:给一个二叉树,让你返回该二叉树的镜像二叉树(每个节点的左右子树都交换一遍) public TreeNode mirrorTree(TreeNode root) 思路:二叉树的实现方法一般都是递归方法。mirrorTree是一个递归方法。 从给的根节点root开始不断地交换左右子树,用temp指针来保存p.left的指向。p是指向root的一个指针,但其实不需要用p。因为递归也不会改变原来二叉树的根节点root。(所以可以直接用root来做)。 当root为null时就返回,中间也不需要接受递归过程返原创 2021-01-24 13:18:41 · 74 阅读 · 0 评论 -
剑指 Offer 26 树的子结构
题目:给两个树A和B,判断A是不是包含B(B是不是A的子结构),规定null不是子结构。 public boolean isSubStructure(TreeNode A, TreeNode B) 思路:树的解法一般是递归方法。 首先isSubStructure这个是个递归方法,不断拿A的left和right和B作匹配。(要考虑null不是子结构)然后判断以A和B为根节点的两个树是不是包含关系还需要一个方法judge,它也是一个递归方法。 有帮助的是拿例子去跑一跑,然后改例子的节点,加一个节点或者该原创 2021-01-21 12:18:27 · 59 阅读 · 0 评论 -
剑指 Offer 25 合并两个有序链表
题目:给两个有序的链表l1和l2,要把它们合并为一条有序的链表,并返回该条链表。 public ListNode mergeTwoLists(ListNode l1, ListNode l2) 思路:1.朴素思路(面试时不使用),正常地去判断head的位置(到底l1还是l2的第一个元素小),正常地去判断l1和l2那个是null,然后返回什么。然后用l1和l2指针来一个一个判断(关键逻辑)。 2.辅助临时头结点的方法(声明一个temp,默认值为0)。 然后接上关键逻辑,用到cur指针(就是l1和l2有一个为n原创 2021-01-20 16:30:20 · 76 阅读 · 0 评论 -
剑指 Offer 24 反转链表
题目:给一个链表,把它反转,然后返回新的头结点head(新的链表)。 public ListNode reverseList(ListNode head) 思路:使用三指针方法 cur pre temp cur初始指向head,pre初始指向最后的null temp用来保存下一个节点 指针变化是cur的next指向pre,这样才能把从前到后,变为从后到前。 结束条件是cur为null,此时的新head为pre。 /* 用三指针方法cur,pre,temp(cur初始指向head,pre初始指向最后原创 2021-01-19 11:37:22 · 77 阅读 · 0 评论 -
剑指 Offer 22 链表中倒数第k个节点
题目:给一个链表,和一个k,表示拿到倒数第k个节点,然后返回。 public ListNode getKthFromEnd(ListNode head, int k) 思路: 1.先遍历一遍获得length再去做。 //方法一:先求出链表长度length再去做 public ListNode getKthFromEnd(ListNode head, int k) { //处理特殊情况(head为null,k<=0或k>length) if(head ==原创 2021-01-18 11:34:42 · 101 阅读 · 1 评论 -
剑指 Offer 21 调整数组顺序使奇数位于偶数前面
题目:给一个整数数组,有奇数和偶数,实现一个函数,把奇数放到前面,偶数都放到后面。 public int[] exchange(int[] nums) 思路: 1.前后指针方法。 定义一个指向第一个元素的指针left,一个指向最后一个元素的指针right。left往右走直到遇到偶数,right往左直到遇到奇数(数组用下标访问,就要进行下标越界判断)。然后奇偶数交换(在left<right的条件下),结束条件是left>right。 //前后指针方法 public int[] excha原创 2021-01-17 15:06:34 · 110 阅读 · 1 评论 -
剑指 Offer 20 表示数值的字符串
题目:输入一个字符串(可能有空格,’.’,’e/E’),判断它是不是一个合法的数。 public boolean isNumber(String s) 思路: 用index来访问String。并写scanInteger和scanUnsignedInteger来辅助判断,返回boolean。(scanInteger用来判断符号,然后判断数字再调用scanUnsignedInteger来做。扫描无符号函数时先记下原来的下标,如果最后的下标往后移动了,那就返回true)。 然后根据数字格式(X.XeX)来原创 2021-01-16 14:22:07 · 105 阅读 · 0 评论 -
剑指 Offer 19 正则表达式匹配:
题目:给字符串s和模式串p,p中可能会有’.’和’’。’.’表示为任意一个字符,’’表示为0个或多个’*’前面的那个字符。问s和p是否匹配,返回boolean结果。 public boolean isMatch(String s, String p) 思路:1.使用递归方法,public boolean matchCore(s,sIndex,p,pIndex) 当s和p同时都走到最后时,整体匹配成功。当p走到最后,而s还没走到最后时整体就匹配失败。当s走到最后,而p没走到最后则不一定失败(比如s:”a” p原创 2021-01-13 17:26:27 · 80 阅读 · 0 评论 -
剑指 Offer 18 删除链表的节点
题目:给一个链表,给一个节点的值,把对应的节点删除,然后把该链表返回回去。 public ListNode deleteNode(ListNode head, int val) 思路:就是正常地删除。 public ListNode deleteNode(ListNode head, int val) { if(head == null){ return null; } if(head.val == val){原创 2021-01-10 13:25:27 · 103 阅读 · 0 评论 -
剑指 Offer 17 打印从1到最大的n位数
题目:输入一个位数n,把1到最大的n位数(如当n=2时,为99)放到int[]里返回。 public int[] printNumbers(int n) 思路:1.直接用for来放入,不考虑大数问题。 //不考虑大数问题 public int[] printNumbers(int n){ //pow参数是double,返回值也是double int total = (int)Math.pow(10,n) - 1; int[] array = new原创 2021-01-10 10:41:16 · 72 阅读 · 0 评论 -
剑指 Offer 16 数值的整数次方
题目:自己实现底数为double,指数为int的幂次运算(-100.0 < x < 100.0;n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]) public double myPow(double x, int n) 思路:1.正常用n的正负0来分类讨论,用for来累乘。 2.用a^b的快速幂。把b化为二进制,一个指针(想象)放到b二进制的最右边。double temp=a,指针左移一下,temp*=temp(可以理解为二进制最右边表示为1次方,左移一位表示为2次原创 2021-01-08 11:23:15 · 69 阅读 · 0 评论 -
剑指 Offer 15 二进制中1的个数
题目:输入一个二进制串,求其中1的个数。(就理解为输入一个十进制数,可以为负数,求其二进制中有几个1) public int hammingWeight(int n) 思路:1.使用位运算,n&1,然后无符号右移(>>>)。统计res public int hammingWeight(int n){ //先用位运算 //虽然输入为一个二进制串,就理解为输入就是一个对应的十进制的整数 int res = 0; while原创 2021-01-05 19:02:44 · 74 阅读 · 0 评论 -
剑指 Offer 14 剪绳子
题目:一段绳子长度为n(n>1),至少剪一次,问每段长度的乘积的最大值是多少? public int cuttingRope(int n) 思路:当n=2,3,4,时单独分析,结果分别是1,2,4。 当n>=5时,2(n-2)>n,3(n-3)>n。意思是当n大于等于5时,剪一段为2,另一段为n-2,则它们的乘积更大。而3(n-3)>=2(n-2)所以应该尽量地以每段为3来剪。 实现为:n=3a+b; a=n/3; b=n%3 也就是有a段3。b只有0,1,2三种情况。当b=原创 2020-11-26 17:42:05 · 118 阅读 · 2 评论 -
剑指 Offer 13 机器人的运动范围
题目:输入矩阵的行数m和列数n,要求m和n每位数字之和不能大于k,问机器人最多能到达几个元素。 public int movingCount(int m, int n, int k) 思路:dfs+剪枝。类比 矩阵中的路径 来做。 从(0,0)开始搜索,只能i+1(往下),j+1(往右)。那(0,0)就是在左上角。因为只从(0,0)一个点开始搜索,所以被访问过的点就不用回溯到未访问的状态(像矩阵中的路径中要从多个点开始搜索,那就需要回溯,否则就会影响别的点)。 由于不需要回退,则i+1(往下),j+1(往右原创 2020-11-24 11:23:51 · 67 阅读 · 0 评论 -
剑指 Offer 12 矩阵中的路径
题目:判断一个二维数组里是否能找到一条路径。能找到则返回true。 public boolean exist(char[][] board, String word) 思路:使用dfs+剪枝。 (dfs是深度优先遍历,是沿着一个方向一直搜索,直到不满足条件,然后回退到上一级继续搜索。剪枝是在搜索过程中的限制和判断条件,可以保证搜索走正确的路和避免一些没有必要的路) 使用dfs方法,public boolean dfs(char[][] board,char[] wordCharArray,int i,int原创 2020-11-23 14:11:42 · 101 阅读 · 0 评论 -
剑指 Offer 11 旋转数组的最小数字
题目:一个递增的数组把一部分放到数组的后面,求旋转后数组的最小值。如原数组为[1,2,3,4,5],选择后数组可以为[3,4,5,1,2]。 public int minArray(int[] numbers) 思路:1.遍历一遍求最小值。时间复杂度O(n) 2.二分搜索思想,缩小范围。使用p,q,mid来做。 当array[mid]>array[q]时,最小值在mid的右边(因为数组是递增的,mid左边的整体都大于右边),p =mid+1;当array[mid]<array[q]时,最小值在m原创 2020-11-22 15:20:57 · 73 阅读 · 0 评论 -
剑指 Offer 10 斐波那契数列 and 青蛙跳台阶问题
1.斐波那契数列: 题目:求斐波那契数列中第n个数。0 1 1 2 3 5 public int fib(int n) 思路:1.递归,当n=0或1时返回。缺点是重复计算太多,leetcode超时 2.动态规划。状态转移方程为fib[i+1]=fib[i]+fib[i-1],可在数组上实现。但没有必要储存中间过程,使用a,b,sum变量计算。初始a=0,b=1。sum=(a+b)%1000000007,a=b,b=sum。当数字很大时,a+b会溢出,所以边加边整除,最后答案一致(最后a要整除,所以b要整除。原创 2020-11-22 15:16:53 · 104 阅读 · 0 评论 -
剑指 Offer 09 用两个栈实现队列
题目:用两个栈来实现队列入队appendTail和出队deleteHead操作(若队列为空则返回-1)。 public void appendTail(int value) public int deleteHead() 思路:1.现在stackA中放上几个元素,如果队列要出队,要返回的第一个是stackA的栈底元素,所以要把stackA中所以元素放到stackB中。 2.所以放只放到stackA中。出队,当stackA和stackB都为空时抛异常。当stackB为空时把stackA里的元素全部放到stac原创 2020-11-22 15:12:00 · 67 阅读 · 0 评论 -
剑指 Offer 07 重建二叉树
题目:给前序和中序二叉树序列,建立二叉树(数据都不重复) 主方法声明:public TreeNode buildTree(int[] preorder, int[] inorder) 思路:使用递归方法build() private TreeNode build(int[] preorder, int preorderStart, int preorderEnd, int[] inorder, int inorderStart, int inorderEnd, Map<Integer, Integer原创 2020-11-22 15:04:44 · 66 阅读 · 0 评论 -
剑指 Offer 06 从尾到头打印链表
①题目:给一个链表,以从尾到头的顺序把元素放到数组中返回。 public int[] reversePrint(ListNode head) 思路:1.先遍历一遍链表,得到size。然后用size声明数组res,再遍历一遍链表,把每个元素反着放到res中。没有额外的空间使用,时间复杂度O(n)。 2.也可以用栈存储遍历的元素,再弹出放到数组中。 public int[] reverseList(ListNode head){ if(head == null){ ret原创 2020-11-22 15:00:26 · 91 阅读 · 0 评论 -
剑指 Offer 05 替换空格
题目:把一个字符串中的空格全部替换为”%20”。如”We Are Happy”,替换为”We%20Are%20Happy”。 public String replaceSpace(String s) 思路:创建一个新的StringBuffer,从前到后遍历s。遇到空格sb就append(“%20”),遇到不是空格就直接append(s.charAt(i))。 public String replaceSpace(String s){ StringBuffer sb = new StringB原创 2020-11-22 14:56:44 · 74 阅读 · 0 评论 -
面试题4 二维数组的查找
题目:在一个二维数组(m行乘n列)里找到1个数,二维数组每一行从左到右,每一列从上到下都是递增的。如果找到返回true。 public boolean findNumberIn2DArray(int[][] matrix, int target) 思路:1.直接遍历,复杂度O(mn) 2.从四个角分析大小关系。只能从左下角和右上角开始搜索(剩下两个角需要判断更多,不方便使用)。 从左下角开始,往右越大,往上越小。k比它大,就往右移动,k比它小就往上移动。如果离开二维数组的范围,返回false。 public原创 2020-11-22 14:52:18 · 94 阅读 · 0 评论 -
剑指 Offer 03 数组中的重复数字
题目:一个长度为n的数组中元素都是0~n-1的,且数组中有重复元素,要求返回任意一个重复的数。 public int findRepeatNumber(int[] nums) 思路:1.用set(HashSet)来做。重复的元素都可以考虑用set做。 把元素放到set里,直到遍历到重复的元素。时间复杂度O(n)(遍历一遍,hashSet的add和contains都是O(1),因为hashSet是基于哈希表实现的),空间复杂度为O(n)。 2.边遍历边根据下标与值的关系进行交换。(先举有重复和无重复的例子,得原创 2020-11-22 13:52:31 · 102 阅读 · 0 评论