自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

Y_M的博客

大道至简!

  • 博客(122)
  • 收藏
  • 关注

原创 volatile CAS 原子类 的重要知识点,短小精练

volatile 是一种轻量级的同步机制。volatile 具有三个特点可以保证可见性 无法保证原子性 可以防止指令重排JMM(Java内存模型)Java内存模型并非是一种实际存在的东西,它是一个概念。Java内存模型需要保证三个特点:可见性 原子性 有序性1,3特点,都可以依靠volatile实现,第二个特点可以通过JUC包下的原子类来实现。可见性 即当主内存中的共享变量发生改变时,让其它线程可以立即得知该变化,并更新各自工作内存变量的值。...

2020-09-13 19:02:18 258

原创 1、面向过程和面向对象的区别

面向过程:面向过程呢,主要是分析解决一个问题的方法和步骤,然后将一个个步骤封装成一个方法,然后调用这些实现的方法即可面向对象:面向对象的思想是将问题中涉及的各种事物用对象去描述,建立类的目的是为了描述事物在问题中的行为。面向对象的特性:面向对象具有低耦合,易维护、高扩展的特点。 由于封装、继承、多态三大特性的存在,使得可以设计出更加低耦合的系统,易于维护。面向过程和面向对象的性能差异面向过程的性能会优于面向对象。 原因是: 类在调用的过程中需要实例化,开销较.

2020-08-08 11:36:34 279

原创 计算机网络面试核心大总结

1 网络基础知识1.1 OSI七层参考模型全称:开放系统互连参考模型(Open System Interconnection Reference Model,OSI/RM)补充:为什么要有一个个层:物理层:010101比特流,设备之间原始数据的传输,数模转换(发送端)和模数转换(接收端)-》传输过程可能出现错码和误码?-------又问题,引入下一层:数据链路层数据链路层:将原始比特流转换成逻辑传输符号,提供纠错编码,格式变为帧-》出现多个网络节点,应该选择哪个...

2020-07-28 22:17:51 741

原创 剑指 offer 19 正则表达式匹配 (动态规划)

1 题目描述2 算法思路题目中的重点式中的字符'.'表示任意一个字符 而'*'表示它前面的字符可以出现任意次(含0次) 例如: a*b 可以视作 aaaaaaaaaaab需要注意的是 .* 这种情况,可以认为这里的 '*' ,可以换做n个 '.'输入:s = "ab"p = ".*"输出: true解释:".*" 表示可匹配零个或多个('*')任意字符('.')。思路:动态规划首先定义状态:dp[i][j] :s前 i 个字符是否能够和前 ...

2020-07-28 07:46:57 268

原创 剑指 offer 68 - 2 二叉树的最近公共祖先(递归)

1 题目描述2 算法思路思路:这题和上一题不同,上一题由于二叉搜索树的特性,因此更为简单,本题更为一般,因此必须遍历整个二叉树才行。递归算法:终止条件; 当超过叶子节点,返回null 当root等于q或者p,直接返回root 递归工作 递归左子树,返回值记为left 递归右子树,返回值记为right 返回值: 当left和right都为空,说明,root的左右子树中都不含p,q,返回null 当left和right都不为,说明p,q在两侧,返回r.

2020-07-28 07:46:49 126

原创 剑指 offer 68 - 1 二叉搜索树的最近公共祖先(递归)

1 题目描述2 算法思路思路:两个节点p,q,最近的公共祖先root,只会存在下面三种可能:p , q 在root的子树中,并且一定存在于两侧 p == root ,q在左右子树中 q == root,p在左右子树中算法:循环搜索,当root等于空跳出 当p,q都在右子树,就root,right 当p,q都在左子树,就root.left 否则说明找到了,跳出 3 代码class Solution { public TreeNode .

2020-07-28 07:46:40 139

原创 剑指 offer 67 把字符串转换成整数(越界问题)

1 题目描述2 算法思路思路:先去掉首部的空格 再看遇到的第一个字符 如果是正负号,那么就设置一个falg = 1代表正号,-1代表负号,0代表无符号 如果是数字,那么就开始进行计算,res = 0; res = res * 10 + num; 处理数字越界的情况,每次进行计算时,先判断res的大小是否越界 越界的情况分为两个,边界 = 2147483647 一个是res * 10的时候就越界了,boundary =2147483647 / 10 =...

2020-07-28 07:46:26 267

原创 剑指 offer 66 构建乘积数组(乘积数组)

1 题目描述2 算法思路思路:如果是直接乘,复杂度是O(n²),因此需要用一个更好的方法 这里就使用乘积数组。 正向遍历 在正向遍历时,让B[i] 等于 A[0] 一直乘到 A[i - 1] 也就是 B[i] = B[i - 1] * A[i - 1] 反向遍历 最后一个元素不用乘自己本身 因此B[i - 1] *= A[a.length] 一直到乘到A[i] 3 代码class Solution { public int[] c...

2020-07-28 07:46:20 129

原创 剑指 offer 65 不用加减乘除法做加法(位运算)

1 题目描述2 算法思路思路:十进制加法,可以分为三步走 1.先做不进位加法 2. 做进位 3.把前两个的结果相加 二进制同样适用。5---101 17---10001 1. 先做不进位加法 --- 10100 2, 记下进位 --- 10 3 把前两个相加 10110 --- 22 答案正确。 算法;不进位加法,可以得知结果是和异或的结果一致 进位和与运算的结果左移1位 ,相同对于负数的处理:在计算机系统中,数值一律用补码来...

2020-07-28 07:46:14 146

原创 剑指 offer 64 求1到n的和(短路效应)

1 题目描述2 算法思路思路:本题使用递归 终止条件的判断使用短路效应 n > 1 && sumNums(n - 1) // 当 n = 1 时 n > 1 不成立 ,此时 “短路” ,终止后续递归3 代码class Solution { int res = 0; public int sumNums(int n) { boolean x = ( n > 1 && sumNums(n - 1

2020-07-28 07:46:05 103

原创 剑指 offer 63 股票的最大利润(动态规划)

1 题目描述2 算法思路动态规划:状态定义:dp[i],代表以i结尾的子数组最大利润 转移方程: 前i日最大利润 = 前i - 1天的最大利润 和 第i天价格 - 前i天最低价格 的最大值 dp[i] = max(dp[i - 1], prices[i] - min(price[i] , minPrice) 初始化,dp[0] = 0, 返回值 dp[n - 1]3 代码class Solution { public int maxProfi..

2020-07-27 14:42:28 276

原创 剑指 offer 62 圆圈中最后剩下的数字(数学方法)

1 题目描述2 算法思路数学方法:每次筛选后,数组的长度就会-1,因此在进行下次索引判断的时候,就需要模上n - 1 那么反推,求出最后一个数字,在一开始那个数组中的索引即可 反推的流程 第一次,加上m个位置,然后对2取余 第二次,加上m个位置,然后对3取余 。。。 总结一下反推的过程,就是(当前index + m) % 上一轮剩余数字的个数。3 代码class Solution { public int lastRemaining(i...

2020-07-27 14:29:56 117

原创 剑指 offer 61 扑克牌中的顺子(Set + max - min < 5)

1 题目描述2 算法思路思路:一个顺序,例如,3,4,5,6,7,那么肯定有max - min < 5 因此再添加元素时,只要保证添加的元素不是重复的,且max - min < 5即可 接下来讨论大王出现的次数,算法;遍历5个数 遇到大小王直接跳过 遇到数字,添加进set,更新max,min 最后判断max - min <5 满足,返回true 不满足,返回false 3 代码class Solution { ..

2020-07-27 14:02:58 211

原创 剑指 offer 60 n个骰子的点数(动态规划)

1 题目描述2 算法思路动态规划:状态定义:dp[]为n个骰子的点数概率数组,pre[] 为n-1个骰子的点数概率数组 初始化:pre[] = {1/6,1/6,1/6,1/6,1/6,1/6} 状态转移方程: dp[x+y] = pre[x] * num[y]; //从最小值,一直更新到最大值 3 代码class Solution { public double[] twoSum(int n) { double[] pre ...

2020-07-27 13:50:20 131

原创 剑指 offer 59 - 2 队列的最大值(单调栈)

1 题目描述2 算法思路思路:首先思考,这个题目,为啥就和上一题是一个大题呢?

2020-07-27 13:26:26 163

原创 剑指 offer 59 - 1 滑动窗口的最大值(单调栈)

1 题目描述2 算法思路思路:使用一个单调栈来装最大值,每次窗口移动,都进行更新,栈首存放最大值 在往窗口添加元素后 先判断,当前窗口移出的元素是不是栈首的元素,如果是,就移出栈首,如果不是,就不管 然后将当前元素num[j] 从栈底添加,弹出所有比nums[j] 小的元素 此时栈顶就是最大值,更新res 3 代码class Solution { public int[] maxSlidingWindow(int[] nums, int k) ..

2020-07-27 07:57:17 210

原创 剑指 offer 58 - 2 左旋转字符串(substring函数、stringbuilder 和 string)

1 题目描述2 算法思路本题介绍三种思路,分别使用了substring函数、stringbuilder 和 string,由于string的不可变性,因此效率依次降低2.1 substring将str按照n的长度切分成两个部分,s1,s2 在s2 +s1即可2.2stringbuilder当substring不允许的时候,就使用这种方法 新建一个stringbuilder,先添加第n+1至末位的字符 再添加0到n的字符 将res转化为字符串返回...

2020-07-27 07:57:07 130

原创 剑指 offer 58 - 1 翻转单词顺序(双指针)

1 题目描述2 算法思路算法分析:s.trim() ---- 删除头尾空格 倒序遍历字符串,记录单词左右指针i , j 每确定一个单词的边界,就添加到res3 代码class Solution { public String reverseWords(String s) { s.trim(); int i = s.length() - 1; int j = i; StringBuilder ..

2020-07-27 07:56:58 142

原创 剑指 offer 57 - 2 和为s的连续正数序列(滑动窗口)

1 题目描述2 算法思路思路:设滑动窗口的左边界i,右边界为j 初始化 i = 1 ,j = 1 当窗口内的和 > target 时,窗口需要减小,i++ 当窗口内的和 <target 时,窗口需要增加,j++ 当窗口内的和 = target 时,需要添加当前的结果到res 终止条件:i < target / 23 代码class Solution { public int[][] findContinuousSequence(int..

2020-07-27 07:56:50 109

原创 剑指 offer 57 和为s的两个数字(双指针+正确性说明)

1 题目描述2 算法思路思路:利用两个指针,一头一尾,当和小于target,left++,当和大于target,right--算法:初始化双指针i , j 指向nums的双端 循环遍历:当i 和j 相遇就退出 s = nums[i] + nums[j] 如果s > target j-- 如果s < target, i++ 如果相等,返回 正确性说明:由下图可知,当s(i,j) 发生改变,变成s(i+1,j)的时候 排除掉的只是橘色..

2020-07-27 07:56:36 160

原创 剑指 offer 56 - 2 数组中数字出现的次数2(位运算)

1 题目描述2 算法思路思路:将所有数字,按位相加,然后对3取余,那么结果就是只出现了一次的数字。因为其它数字为1的位都可以被3整除。接下来的重点就是如何在遍历时,计算位数:有限状态机实在难以理解,因此选择了更简单的处理方式。有兴趣可以自己看使用与运算,获取num的最后一位, n1 = num & i 无符号右移, num = num >>>1 利用int[] count = new int[32]进行统计 然后对count对3求余,再利用左..

2020-07-26 17:05:45 139

原创 剑指 offer 56 - 1 数组中数字出现的次数(异或操作的妙用)

1 题目描述2 算法思路思路:题目要求数组出,唯二,只出现一次的数字,其它数字都存在两个 可以先分析,如果数组中只存在一个 出现一次的数字,那么全员异或,可以得到该数字。 可是本题存在两个,因此需要做一些改变。 第一个改变,就是希望找一个方法,可以将两个数字分到两个组中,这样就可以分别求出了 进行分组的方法 ​​​​​​​1、先进行全员异或,那么最后的结果相当于,存在的两个数a,b的异或结果,那么只要找到异或结果中为1的位,就可以找到a,b两个数在某一位上的差异,然后根.

2020-07-26 15:46:08 128

原创 剑指 offer 55 - 2 平衡二叉树(递归)

1 题目描述2 算法思路思路:此题基于上一题,《求二叉树的深度》,在此基础上只需要进行稍微修改即可 同样是后序遍历二叉树,求出每个节点的左右子树的深度, 如果深度差 < 2,就返回深度 如果深度差 > 2,就返回 -1 递归算法:终止条件 当root == null 时,代表越过了叶子节点,返回0 如果左右子树的深度 == -1,代表已经不是平衡二叉树了,直接返回-1 返回值: 当 深度差 < 2时,返回深度 max(depthL.

2020-07-26 14:55:53 152

原创 剑指 offer 55 - 1 二叉树的深度(递归,层序遍历)

1 题目描述2 算法思路思路:求深度,肯定需要遍历一遍所有的节点,这里采取后序遍历(也可以层序遍历,时间复杂度都是 n)使用递归:当前节点的深度 = 左子树的深度 和 右子树的深度 的较大值 再加上 1递归思路:终止条件:当root为空时,说明已经到了叶子节点,返回0 递归工作:(后序遍历) 计算左子树的深度 depth1 计算右子树深度 depth2 返回值,max(depth1,depth2) + 13 代码class Solutio...

2020-07-26 14:43:20 113

原创 剑指 offer 54 二叉搜索树的第k大节点(中序逆遍历)

1 题目描述2 算法思路思路:二叉搜索树,中序遍历的结果是递增的 中序遍历---左、根、右,因此如果我们逆着中序遍历的流程进行遍历 每次遍历k--,当k == 0时,就是res递归流程:终止条件,当节点root == null 时返回 递归右子树,dfs(root.right) 递归“根”,完成操作 如果k == 0直接返回 k-- 如果此时k == 0,res = root.val 递归左子树,dfs(root.left)3 代码..

2020-07-26 14:34:16 174

原创 剑指 offer 53 - 2 0~n-1中缺失的数字(二分)

1 题目描述2 算法思路思路:解决排好序的数字查找问题,可以使用二分 此处二分的条件并非是比较大小,而是看num[i] 是否等于i算法:初始化i = 0 , j = len - 1 循环二分,当 i > j 时跳出 m = i + (j - i) / 2; 如果nums[m] = m,说明在右半边 如果num[m] != m ,说明在左边 返回值:返回左边界 i3 代码class Solution { public int mi..

2020-07-26 14:24:15 129

原创 剑指 offer 53 - 1 在排序数组中查找数字 1(二分查找 + 取巧)

1 题目描述2 算法思路算法:初始化 左边界i = 0 ,右边界 j = len - 1 二分查找,当[i ,j] 碰到退出 m = i + (j - i) / 2 如果nums[m] < target ,代表target在右边,i = m + 1 如果nums[m] > target ,代表target在左边,j = m -1 如果nums[m] = target 查找右边界,i = m + 1 查找左边界,j = m - 1 返回值:.

2020-07-26 12:36:09 142

原创 剑指 offer 52 两个链表的第一个公共节点(双指针)

1 题目描述2 算法思路思路:用两个指针A,B分别指向两个链表的头,然后以相同的速度遍历,如果指针到了末尾,就从对方的头再来 由题目可知,链表不存在循环,因此只要存在交点,就一定可以通过这种追赶的方式找到。 两个链表长度分别为L1+C、L2+C, C为公共部分的长度,按照楼主的做法: 第一个人走了L1+C步后,回到第二个人起点走L2步;第2个人走了L2+C步后,回到第一个人起点走L1步。 当两个人走的步数都为L1+L2+C时就两个家伙就相爱了 如果不存在,那么最后,no.

2020-07-26 12:22:35 172

原创 剑指 offer51 数组中的逆序对(分治算法,归并排序)

1 题目描述2 算法思路思路:根据一个特例可知,当数组是升序的,那么逆序对就是0 当数组是降序的,那么每一个数字,都是与后面的数构成逆序对 因此,我们可以采取分治思路,将一个数组,分成若干个有序的数组,然后对其进行逆序对的计算 由上图可知,这种思想其实就是归并排序的思想,O(n) = nlogn对两个分别有序数组,求逆序对的过程进行分析:创建一个和数组等大的辅助数组,用来存放合并前的数字,因此空间复杂度 O(n) = n 合并思路 两个指针i 和 j 分别指...

2020-07-26 11:49:14 194

原创 剑指 offer 50 第一个只出现一次的字符(有序哈希表)

1 题目描述2 算法思路算法:初始化一个LinkedHashMap,注意此处的value 设置为Boolean,稍微优于integer 遍历字符串中所有的字符c 如果哈希表中不含c,就put(c,true) 如果已经包含了,就put(c,false) 由于是有序哈希表,记录了装入的顺序...

2020-07-26 11:02:24 90

原创 剑指 offer 49 丑数(动态规划)

1 题目描述2 算法思路思路:首先要通过性质可知,每一个丑数,必定可以由前面的丑数 乘以 2 / 3 / 5所得 因此,当前丑数,应该是前面的 xa *2 / xb * 3 / xc * 5中的最小值 那么如何求得xa,xb,xc呢 可知,丑数是按照顺序存储的,因此当前丑数必定满足三个条件,即 xa * 2 > x > xa-1 * 2 //3 和 5的省略 动态规划算法:状态定义:dp[i] 代表第i + 1个丑数 转移方程: 首...

2020-07-25 21:55:36 126

原创 剑指 offer 48 最长不含重复字符的字符串(双指针+哈希表, 动态规划)

1 题目描述2 算法思路

2020-07-25 21:27:46 141

原创 剑指 offer 47 礼物的最大价值(动态规划)

1 题目描述2 算法思路动态规划解析:状态定义,dp[i][j] 代表从左上角开始,到(i,j)时,礼物的最大价值 转移方程: 当i = 0, j = 0,为起始元素 当i = 0,j != 0, 代表是第一行的元素,只能从左到右到达 当i != 0,j = 0,代表是第一列的元素,只能从上到下到达 当i != 0,j != 0 ,可以从左边,或者上边到达 初始状态: dp[0][0] = grid[0][0] dp[0][j] = grid[0]...

2020-07-25 06:21:42 173

原创 剑指 offer 46 把数字翻译成字符串(动态规划)

1 题目描述2 算法思路思路:假设第i - 1个数字,翻译的方法是dp[i - 1] 那么dp[i] 就拥有两个情况,如下图 一个是当前的数字可以和前一个数字进行翻译,也就是属于[0,25] ,那么dp[i] = dp[i -1] + dp[i -2] 如果当前的数字不可以和前一个数字进行翻译,那么dp[i] = dp[i - 1] 动态规划:状态定义:dp[i] 代表第i个数字的翻译数量 转移方程: 一个是当前的数字可以和前一个数字进行翻译,也就是属于[0,2.

2020-07-25 06:21:35 116

原创 剑指 offer 45 把数组排成最小的数(特殊的排序)

1 题目描述2 算法思路思路:这题实际上,本质上,竟然是一个排序题,只是在排序时,需要重新制定排序规则

2020-07-25 06:21:26 160

原创 剑指 offer 44 数字序列中某一位的数字(数学规律)

1 题目描述2 算法思路思路:根据下图可得规律,因此将找数分为三个步骤找n属于哪一个数位区间,也就是看它属于哪个[start,end] 确定它是哪一个数字,例如 456 最后确定 是456中的哪一个数字,例如:5算法流程:确定位数 循环的减去每个位数含有的数位数量count,当n <= count 时跳出, 此时状态,位数digit,起始数字start,往后第n个位数 确定所求数位所在的数字 这个区间一个数,占digit 个数位 求出是区间...

2020-07-25 06:21:16 121

原创 剑指 offer 43 1~n整数中1出现的次数(按位计算)

1 题目描述2 算法思路感觉是一个找数学规律的题,可以分别求出每位上1出现的次数,再相加数学规律如下:如图cur == 0high * digitcur == 1high * digit + low + 1cur > 1(high + 1) * digit3 代码class Solution { public int countDigitOne(int n) { int digit = 1; /...

2020-07-24 19:56:34 109

原创 剑指 offer 42 连续子数组的最大和(动态规划)

1 题目描述2 算法思路动态规划:状态定义:dp[i] 代表以第 i 个元素结果的数组的最大和 转移方程:dp[i] = Max( dp[i - 1] + nums[i] , nums[i]) 初始状态:dp[0] = nums[0] 返回值:返回dp列表中的最大值3 代码class Solution { public int maxSubArray(int[] nums) { int res = nums[0]; for(i.

2020-07-24 18:51:29 100

原创 剑指 offer 41 数据流中的中位数(两个堆)

1 题目描述2 算法思路思路:中位数的查找,本质就是找一个有序数组的中间的数,那么可以先对无序数组进行排序。 还有一个思路就行,在进行添加时,就按照顺序进行添加,如此一来就可以减小查找时的时间复杂度 本题就使用两个堆来实现,一个大顶堆,一个小顶堆 小顶堆用来存放较大的那一半数,如果是奇数,那么多出来的一个放在小顶堆 大顶堆用来存放较小的那一半 查找时: 如果是奇数,直接返回小顶堆 堆顶元素 如果是偶数,直接返回(大顶堆顶 + 小顶堆顶) / 2 算法: 设..

2020-07-24 15:35:00 165

原创 剑指 offer 40 最小的k个数(堆 + 快排)

1 题目描述2 算法思路2.1 堆思路:利用堆数据结构来辅助得到最小的k个数 堆的性质是可以找到最大或者最小的元素 我们可以使用一个大小为k的大顶堆,将元素依次遍历加入堆,如果堆的大小超过了k,就将最大的元素弹出 如此就保证了堆中的元素都是当前最小的k个元素 时间复杂度 nlogk 这里的大顶堆选择的是 Java中的PriorityQueue PriorityQueue默认是小顶堆,需要重写比较器,使其变为最大堆2.2 快速排序(选择)2.3 比较...

2020-07-24 15:11:55 131

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除