![](https://img-blog.csdnimg.cn/20201014180756927.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
剑指offer
文章平均质量分 55
zonaqiu
这个作者很懒,什么都没留下…
展开
-
剑指 offer 50 第一个只出现一次的字符
剑指 offer 50 第一个只出现一次的字符哈希表存储频数01class Solution { public char firstUniqChar(String s) { if(s.isEmpty()){ return ' '; } int len = s.length(); Map<Character,Integer> map = new HashMap<>();原创 2021-06-18 14:01:31 · 48 阅读 · 1 评论 -
剑指 offer 48 丑数
剑指 offer 48 丑数超时版本逐个判断这个数是不是丑数,直到找到第nnn个丑数。class Solution { public int nthUglyNumber(int n) { int counts = 0; int i = 1; while(counts<=n){ if(isUglyNumber(i)){ counts++; }原创 2021-06-18 10:12:33 · 47 阅读 · 0 评论 -
剑指 offer 48 最长不含重复字符的子字符串
剑指 offer 48 最长不含重复字符的子字符串动态规划class Solution { public int lengthOfLongestSubstring(String s) { if(s.isEmpty()){ return 0; } int len = s.length(); int[] dp = new int[len]; dp[0] = 1; Map<原创 2021-06-17 15:45:06 · 68 阅读 · 0 评论 -
剑指 offer 47 礼物的最大价值
剑指 offer 47 礼物的最大价值动态规划class Solution { public int maxValue(int[][] grid) { int rows = grid.length; int colums = grid[0].length; int[][] dp = new int[rows][colums]; dp[0][0] = grid[0][0]; for (int j=1;j<co原创 2021-06-17 14:48:29 · 76 阅读 · 0 评论 -
213 打家劫舍 2
213 打家劫舍 2动态规划和198的区别是,房屋是首尾相连的,第一件房屋和最后一件房屋相邻,因此第一间房屋和最后一间房屋不能在同一晚偷窃。关键是如何保证第一间房屋和最后一间房屋不能同时偷窃。如果偷了第一间房屋,则不能偷最后一间房屋,因此偷窃的范围是第一间房屋到倒数第二间房屋;如果偷了最后一间房屋,则不能偷第一间房屋,因此偷窃房屋的范围是第二间房屋到最后一间房屋。对于两段下标范围分别计算可以偷窃到的最高总金额,其中最大值就是在nnn间房屋中可以偷到的最高总金额。class Solution {原创 2021-06-15 14:24:58 · 60 阅读 · 0 评论 -
198 打家劫舍
198 打家劫舍代码01class Solution { public int rob(int[] nums) { int[] dp = new int[nums.length+1]; dp[0]=0; dp[1] = nums[0]; for(int i=1;i<nums.length;i++){ dp[i+1] = Math.max(dp[i],dp[i-1]+nums[i]);原创 2021-06-15 14:00:38 · 46 阅读 · 0 评论 -
剑指 offer 46 把数字翻译成字符串
剑指 offer 46 把数字翻译成字符串动态规划class Solution { public int translateNum(int num) { String str = String.valueOf(num); int[] dp = new int[str.length()]; dp[0] = 1; if(str.length()<=1){ return 1; }原创 2021-06-15 13:34:04 · 43 阅读 · 0 评论 -
剑指 offer 45 把数组排成最小的数
剑指 offer 45 把数组排成最小的数代码01class Solution { public String minNumber(int[] nums) { String[] strs = new String[nums.length]; for(int i=0;i<nums.length;i++){ strs[i] = String.valueOf(nums[i]); } quickSort原创 2021-06-15 10:21:26 · 30 阅读 · 0 评论 -
剑指 offer 44 数字序列中的某一位的数字
剑指 offer 44 数字序列中的某一位的数字在i=9i =9i=9的时候计算共有多少位会出现溢出,这时候出循环直接计算就好。class Solution { public int findNthDigit(int n) { int i=1; int counts = countOfIntegers(i); if(n<counts){ return n; } while (n原创 2021-06-11 12:42:31 · 56 阅读 · 1 评论 -
剑指 offer 43 1~n 整数中1出现的次数
剑指 offer 43 1~n 整数中1出现的次数class Solution { public int countDigitOne(int n) { int res = 0;// int tmp = n; int high = n/10; int digit = 1; int cur = n%10; int low = 0; while(high !=0 || cur !=0){原创 2021-06-11 10:48:03 · 42 阅读 · 1 评论 -
剑指offer 42 连续子数组的最大和
剑指offer 42 连续子数组的最大和举例分析数组的规律class Solution { public int maxSubArray(int[] nums) { int sum = 0; int res = nums[0]; int len = nums.length; for(int i=0;i<len;i++){ sum+=nums[i]; if(sum<nums原创 2021-06-10 13:42:36 · 31 阅读 · 1 评论 -
剑指 offer 41 数据流中的中位数
剑指 offer 41 数据流中的中位数最大堆 & 最小堆如图所示,如果数据在容器中已经排序,那么中位数可以由P1P_1P1和P2P_2P2指向的数得到。如果容器中数据的数目是奇数,那么P1P_1P1和P2P_2P2指向同一个数据。此时,整个数据容器被分成两部分。位于容器左边部分的数据比右边的数据小。另外,P1P_1P1指向的数据是左边部分最大的数,P2P_2P2指向的数据是右边部分最小的数。如果能保证数据容器左边的数据小于右边的数据,那么即使左、右两边内部的数据没有排序,也可原创 2021-06-09 14:10:02 · 34 阅读 · 1 评论 -
剑指offer 40:最小的K个数
剑指offer 40:最小的K个数基于partion函数的算法这种方法会修改输入的数组。class Solution { public int[] getLeastNumbers(int[] arr, int k) { if(k==0){ return new int[0]; } if(k==arr.length){ return arr; } i原创 2021-06-08 10:32:11 · 58 阅读 · 0 评论 -
剑指 offer 39 数组中出现次数超过一半的数字
剑指 offer 39 数组中出现次数超过一半的数字排序的方法class Solution { public int majorityElement(int[] nums) { Arrays.sort(nums); return nums[nums.length/2]; }}原创 2021-06-07 17:08:07 · 40 阅读 · 0 评论 -
剑指 offer 38 字符串的排列
剑指 offer 38 字符串的排列回溯class Solution { List<String> res = new LinkedList<>(); char[] c; public String[] permutation(String s) { c = s.toCharArray(); dfs(0); return res.toArray(new String[0]); } publ原创 2021-06-06 10:59:18 · 30 阅读 · 0 评论 -
剑指 offer 37:序列化二叉树
剑指 offer 37:序列化二叉树通过层序遍历来序列化和反序列化/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */public class Codec { // Encodes a tree t原创 2021-06-04 15:20:13 · 72 阅读 · 0 评论 -
剑指 offer 36:二叉搜索树与双向链表
剑指 offer 36:二叉搜索树与双向链表代码 01使用中序遍历访问树的各节点cur,并在访问每个节点的时候构建cur和前驱节点pre的引用指向,中序遍历完成后,最后构建头节点和尾节点引用指向即可。/*// Definition for a Node.class Node { public int val; public Node left; public Node right; public Node() {} public Node(int原创 2021-06-03 14:42:08 · 43 阅读 · 0 评论 -
剑指 offer 35:复杂链表的复制
剑指 offer 35 : 复杂链表的复制哈希表用空间换时间。利用哈希表的查询特点,考虑构建原链表节点和新链表对应节点的键值对映射关系,在遍历构建新链表各节点的 next 和 random 引用指向即可。/*// Definition for a Node.class Node { int val; Node next; Node random; public Node(int val) { this.val = val;原创 2021-06-03 12:13:43 · 40 阅读 · 1 评论 -
剑指 offer 34:二叉树中和为某一值的路径
剑指 offer 34:二叉树中和为某一值的路径回溯法典型的二叉树方案搜索问题,使用回溯法解决,包含前序遍历+路径记录两部分。用前序遍历的方法访问到某一节点时,就把该节点添加到路径上,targte 值更新为原值减去当前节点的值。如果该节点是叶节点,并且 target 刚好等于 0,则当前/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left原创 2021-05-30 23:12:39 · 110 阅读 · 1 评论 -
剑指 offer33:二叉搜索树的后序遍历序列
剑指 offer 33:二叉搜索树的后序遍历序列二叉搜索树二叉搜索树是一种节点值之间具有一定数量级次序的二叉树,对于树中的每个节点:如果其左子树存在,则左子树中每个节点的值都不大于该节点的值;如果其右子树存在,则右子树中每个节点的值都不小于该节点的值。示例递归数组最后一个元素一定是根节点,根节点可以把前面的元素分成两组,从某一个元素之前的所有元素都不大于根节点的值,某一个元素到根节点位置都不小于根节点的值,否则就不是二叉搜索树的后序遍历序列,递归判断两个子部分,即不大于根节点的前半部分原创 2021-05-29 18:29:28 · 33 阅读 · 0 评论 -
剑指 offer 32 :从上到下打印二叉树
剑指 offer 32 :从上到下打印二叉树一代码 001广度优先搜索使用队列/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */class Solution { public int[] le原创 2021-05-27 23:38:26 · 39 阅读 · 0 评论 -
剑指 offer 31:栈的压入、弹出序列
剑指 offer 31:栈的压入、弹出序列代码一可以发现判断一个序列不是栈的弹出序列的规律:如果下一个弹出的数字刚好是栈顶数字,那么直接弹出;如果下一个弹出的数字不在栈顶,则把压栈序列中还没入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶为止;如果所有数字都压入栈后仍没有找到下一个弹出的数字,那么该序列不可能是一个弹出序列。出栈为主考虑。class Solution { public boolean validateStackSequences(int[] pushed, int[]原创 2021-05-27 14:06:52 · 38 阅读 · 0 评论 -
剑指 offer 30 包含 min 函数的栈
剑指 offer 30 包含 min 函数的栈方法一在入栈和出栈的时候最小值都可能发生变化,因此,在入栈和出栈之后都要对最小值进行更改。push 时最简单,只需要将入栈的元素和minValue进行比较,如果比 minValue小就更改 minValue的值即可,入栈时间复杂度是O(1)O(1)O(1)。出栈稍复杂些,如果出栈的元素不是最小值,则不用进行任何处理;否则,就需要重新寻找最小值,这里出栈的时间复杂度不是O(1)O(1)O(1)。min 函数,直接返回最小值即可。class MinStack原创 2021-05-25 13:51:53 · 32 阅读 · 0 评论 -
剑指 offer29 顺时针打印矩阵
剑指 offer 29 顺时针打印矩阵方法一class Solution { public int[] spiralOrder(int[][] matrix) { int row = matrix.length; if(row<=0){ return new int[0]; } int colum = matrix[0].length; if(colum<=0){原创 2021-05-25 10:40:36 · 57 阅读 · 0 评论 -
剑指 offer28 对称的二叉树
剑指 offer28 对称的二叉树根据书上写的代码/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */class Solution { public boolean isSymmetric(Tree原创 2021-05-21 20:23:09 · 32 阅读 · 0 评论 -
27二叉树的镜像
27 二叉树的镜像使用递归的思想。首先交换根节点的左右子树,然后继续对根节点的左右子树进行镜像反转。具体看代码。/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */class Solution { p原创 2021-04-19 19:48:14 · 79 阅读 · 0 评论 -
代码的鲁棒性
代码的鲁棒性容错性是鲁棒性的一个重要体现。不鲁棒的软件在发生异常事件的时候,比如用户输入错误的用户名、试图打开的文件不存在或者网络不能连接,就会出现不可预见的诡异行为,或者干脆整个软件崩溃。提高代码鲁棒性的有效途径是进行防御性编程。防御性编程是一种编程习惯,是指预见在什么地方可能会出现问题,并为这些可能出现的问题制定处理方式。比如,当试图打开文件时,发现文件不存在,可以提示用户检查文件名和路径;当服务器连接不上时,可以试图连接备用服务器等。这样,当异常情况发生时,软件的行为也尽在我们的掌握之中,而不至于原创 2021-04-17 17:29:03 · 612 阅读 · 0 评论 -
26 树的子结构
26 树的子结构和链表相比,树中的指针操作更多也更复杂,因此与树有关的问题通常会比链表的更难。如果想加大面试的难度,则树的题目是很多面试官的选择。面对大量的指针操作,我们要更加小心,否则一不留神就会在代码中留下隐患。思路:要查找树A中是否存在和树B结构一样的子树,我们可以分成两步:第一步,在树A中找到和树B的根节点的值一样的节点R;第二步,判断树A中以R为根节点的子树是不是包含和树B一样的结构。第一步在树A中查找与B的根节点的值一样的节点,这实际上就是树的遍历。对二叉树这种数据结构熟悉的读者知道原创 2021-04-17 17:21:16 · 68 阅读 · 0 评论 -
25合并两个排序的链表
25 合并两个排序的链表注意????:这道题要注意鲁棒性的问题。每当代码试图访问空指针指向的内存时程序就会崩溃,从而导致鲁棒性问题。在这道题中一旦输入空的链表就会引入空的指针,因此我们要对空链表单独处理。当第一个链表是空链表,也就是它的头结点是一个空指针时,那么把它和第二个链表合并,显然合并的结果就是第二个链表。同样,当输入的第二个链表的头结点是空指针的时候,我们把它和第一个链表合并得到的结果就是第一个链表。如果两个链表都是空链表,则合并的结果是得到一个空链表。代码/** * Definition原创 2021-04-17 16:35:53 · 75 阅读 · 0 评论 -
22 链表中倒数第k个节点
22 链表中倒数第k个节点为了实现只遍历一次就能找到倒数第kkk个节点,我们可以定义两个指针。第一个指针从链表的头指针开始遍历向前走k−1k-1k−1步,第二个指针保持不动;从第kkk步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k−1k-1k−1,当第一个(走在前面的)指针到达链表的尾结点时,第二个(走在后面的)指针正好指向倒数第k个节点。/** * Definition for singly-linked list. * public class ListNode {原创 2021-04-16 21:45:58 · 78 阅读 · 0 评论 -
20 表示数值的字符串
20 表示数值的字符串常规解法在遍历的过程中如果不满足字符串表示数值的条件就返回false,遍历结束之后若没有返回false,且字符串中包含数字,就返回true。其实就是列举出所有false的情况,只有中间过程没有出现false才有可能返回true。首先定义了四个flag对应四种字符:是否有数字:hasNum是否有e:hasE是否有小数点:hasDot是否有正负号:hasSign这道题目还要考虑字符串首尾出现的空格,在开始遍历之前先处理空格开始遍历。判断数字使用一个while循环。如原创 2021-04-12 16:29:07 · 143 阅读 · 0 评论 -
代码的完整性
代码的完整性3种错误处理的方法通常我们有3种方式把错误信息传递给函数的调用者。第一种方式是函数用返回值来告知调用者是否出错。这种方式最大的问题是使用不便,因为函数不能直接把计算结果通过返回值赋值给其他变量,同时也不能把这个函数计算结果直接作为参数传递给其他函数。第二种方式是当错误发生时设置一个全局变量。此时我们可以在返回值中传递计算结果了。这种方法比第一种方法使用起来更加方便,因为调用者可以直接把返回值赋值给其他变量或者作为参数传递给其他函数。但这种方法有一个问题:调用者很容易忘记检查全局变量,因此原创 2021-04-06 19:35:03 · 587 阅读 · 0 评论 -
位运算
位运算位运算是把数字用二进制表示之后,对每一位上0或者1的运算。原创 2021-04-01 16:38:53 · 308 阅读 · 0 评论 -
动态规划与贪婪算法
动态规划与贪婪算法如果题目是求一个问题的最优解(通常是求最大值或最小值),而且该问题能够分解成若干个子问题,并且子问题之间还有重叠的更小的子问题,就可以考虑用动态规划来解决这个问题。我们在应用动态规划之前要分析能否把大问题分解成小问题,分解后的每个小问题也存在最优解。如果把小问题的最优解组合起来能够得到整个问题的最优解,那么我们可以应用动态规划来解决这个问题。应用动态规划求解问题的特点:求一个问题的最优解(通常是求最大值或最小值)。整体问题的最优解依赖各个子问题的最优解。把大问题分解成若干个小原创 2021-03-31 19:03:15 · 454 阅读 · 0 评论 -
回溯法
回溯法回溯法可以看成暴力法的升级,它从解决问题每一步的所有可能选项里系统地选择出一个可行的解决方案。回溯法非常适合由多个步骤组成的问题,并且每个步骤都有多个选项。当我们在某一步选择了其中一个选项时,就进入下一步,然后又面临新的选项。我们就这样重复选择,直到到达最终的状态。用回溯法解决的问题的所有选项可以形象地用树状结构表示。在某一步有nnn个可能的选项,那么该步骤可以看成是树状结构中的一个节点,每个选项看成树中节点连接线,经过这些连接线到达该节点的nnn个子节点。树的叶节点对应着终结状态。如果在叶节点的原创 2021-03-30 20:07:51 · 381 阅读 · 0 评论 -
查找和排序
查找和排序查找和排序都是程序设计中经常用到的算法。查找相对而言较为简单,不外乎顺序查找、二分查找、哈希表查找和二叉排序树查找。二分查找一定要可以手写代码。如果面试题是要求在排序的数组(或者部分排序的数组)中查找一个数字或者统计某个数字出现的次数,那么我们都可以尝试用二分查找法。哈希表和二叉排序树查找的重点在于考察对应的数据结构而不是算法。哈希表最主要的优点是我们利用它能够在O(1)O(1)O(1)的时间内查找某一元素,是效率最高的查找方式。但其缺点是需要额外的空间来实现哈希表。排序比查找要复杂一些。原创 2021-03-25 23:54:30 · 618 阅读 · 0 评论 -
递归和循环
递归和循环如果我们需要重复地多次计算相同的问题,则通常可以选择用递归或者循环两种不同的方法。递归是在一个函数的内部调用这个函数自身。而循环则是通过设置计算的初始值及终止条件,在一个范围内重复运算。通常递归的代码会比较简洁。但是它同时也有显著的缺点。递归由于是函数调用自身,而函数调用是有时间和空间的消耗的:每一次函数调用,都需要在内存栈中分配空间以保存参数、返回地址、临时变量,而且往栈里压如数据和弹出数据都需要时间。另外,递归中有可能很多计算都是重复的,从而对性能带来很大的负面影响。递归的本质是把一个原创 2021-03-22 22:32:17 · 249 阅读 · 0 评论 -
栈和队列
栈和队列栈是一个非常常见的数据结构,它在计算机领域被广泛应用,比如操作系统会给每个线程创建一个栈来存储函数调用时各个函数的参数、返回地址及临时变量等。栈的特点是先进后出。通常栈是一个不考虑排序的数据结构,我们需要O(n)O(n)O(n)的时间才能找到栈中最大或最小的元素。队列是另外一种很重要的数据结构。队列的特点是先进先出。在树的宽度优先遍历算法中,我们在遍历某一层树的节点时,把节点的子节点放到一个队列里,以备下一层节点的遍历。...原创 2021-03-22 20:29:39 · 518 阅读 · 0 评论 -
树
树树的逻辑:除根节点之外每个结点只有一个父节点,根节点没有父节点;除叶结点之外所有结点都有一个或多个子节点,叶结点没有子节点。父节点和叶结点之间用指针链接。在面试的时候提到的树,大部分是二叉树。所谓二叉树是树的一种特殊结构,在二叉树中每个结点最多只能有两个子节点。在二叉树中最重要的操作是遍历,遍历方式有:前序遍历、中序遍历、后序遍历、宽度优先遍历(先访问树的第一层节点,再访问树的第二层节点……)。二叉树有很多特例,二叉搜索树就是其中之一。在二叉搜索树中,左子节点总是小于或等于根节点,右子节点总是大于或原创 2021-03-21 16:45:06 · 120 阅读 · 0 评论 -
数组(剑指offer)
数组数组的空间效率不是很好,因为即使我们只在数组中存储一个数字,也需要为所有的数据预先分配内存,这样就导致经常会有空闲的区域没有得到充分的利用。数组的时间效率很高。读取时间是O(1)O(1)O(1)。因此我们可以使用数组来实现简单的哈希表:把数组下标设为哈希表的键值(KeyKeyKey),而把数组中的每一个数字设为哈希表的值(ValueValueValue)。为了解决数字空间效率不高的问题,又设计实现了多种动态数组,比如C++的STL中的vector。为了避免浪费,先为数组开辟较小的空间,然后往数组中原创 2021-01-26 01:06:57 · 102 阅读 · 0 评论