单例模式
引入在之前的文章中我们介绍了常见的设计模式,今天我们来使用 Java 语言对单例模式进行具体实现举例。
实例在下面的例子中,我们使用单例模式来保证每次生成的对象都是唯一的。
统一接口1234567/** * 单例对象 * * @author marx * @date 2022/03/10 */interface SingletonObject{}
饿汉式1234567891011121314151617181920212223242526/** * 饿汉 * * @author marx * @date 2022/03/10 */class Hungry implements SingletonObject{ /** * 实例 */ private static Hungry instance = new Hungry(); /** * 私有构造,避免外部利用 new 创建实例 */ private Hungry() {} /** * 得到实例通过饿汉式 * ...
数据库表中的salt是什么
引入在数据库的user表中我们通常可以看到一个叫做salt的字段,salt大家很容易就知道意思是盐,大家一开始接触可能感觉很奇怪,为何用户要有一个“盐”属性?我们可以上维基查一下定义:
盐(Salt)
在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。
以上这段话是维基百科上中对于 Salt 的定义,但是仅凭这句话还是很难理解什么叫 Salt,以及它究竟在用户表里面会起到什么样的作用。接下来我们就以用户表的设计开始来揭示“salt”的必要性。
数据表设计直接设计我们在设计用户表时,首当其冲需要设计用户名(或账号)以及密码,这两个字段可以说是用户表的核心,一个表示用户的唯一身份,一个表示和唯一身份相匹配的登录凭证。所以我们的用户表至少要设计成这样:
字段名
类型
是否为空
说明
……
……
……
……
username
varchar(50)
no
用户名
password
varchar(100)
no
密码
……
……
……
……
PS:这里设计的数据表默认为MySQL中的表 ...
黄金矿工
力扣 1219. 黄金矿工题目说明你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0。
为了使收益最大化,矿工需要按以下规则来开采黄金:
每当矿工进入一个单元,就会收集该单元格中的所有黄金。
矿工每次可以从当前位置向上下左右四个方向走。
每个单元格只能被开采(进入)一次。
不得开采(进入)黄金数目为 0 的单元格。
矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。
提示:
1 <= grid.length, grid[i].length <= 15
0 <= grid[i][j] <= 100
最多 25 个单元格中有黄金。
示例示例 1:
123输入:grid = [[0,6,0],[5,8,7],[0,9,0]] 输出:24 解释: [[0,6,0], [5,8,7], [0,9,0]] 一种收集最多黄金的路线是:9 -> 8 -> 7。
示例 2:
1234输入:grid = [[ ...
游戏中弱角色的数量
力扣 1996. 游戏中弱角色的数量题目说明你正在参加一个多角色游戏,每个角色都有两个主要属性:攻击 和 防御 。给你一个二维整数数组 properties ,其中 properties[i] = [attacki, defensei] 表示游戏中第 i 个角色的属性。
如果存在一个其他角色的攻击和防御等级 都严格高于 该角色的攻击和防御等级,则认为该角色为 弱角色 。更正式地,如果认为角色 i 弱于 存在的另一个角色 j ,那么 attackj > attacki 且 defensej > defensei 。
返回 弱角色 的数量。
提示:
2 <= properties.length <= 10^5
properties[i].length == 2
1 <= attacki, defensei <= 10^5
示例示例 1:
123输入:properties = [[5,5],[6,3],[3,6]]输出:0解释:不存在攻击和防御都严格高于其他角色的角色。
示例 2:
123输入:properties = [[2,2],[3,3]]输出 ...
删除回文子序列
力扣 1332. 删除回文子序列题目说明给你一个字符串 s,它仅由字母 'a' 和 'b' 组成。每一次删除操作都可以从 s 中删除一个回文 子序列。
返回删除给定字符串中所有字符(字符串为空)的最小删除次数。
「子序列」定义:如果一个字符串可以通过删除原字符串某些字符而不改变原字符顺序得到,那么这个字符串就是原字符串的一个子序列。
「回文」定义:如果一个字符串向后和向前读是一致的,那么这个字符串就是一个回文。
提示:
1 <= s.length <= 1000
s 仅包含字母 'a' 和 'b'
示例示例 1:
123输入:s = "ababa"输出:1解释:字符串本身就是回文序列,只需要删除一次。
示例 2:
1234输入:s = "abb"输出:2解释:"abb" -> "bb" -> "". 先删除回文子序列 "a",然后再删除 "bb"。
示例 ...
最小时间差
力扣 539. 最小时间差题目说明给定一个 24 小时制(小时:分钟 **”HH:MM”**)的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。
提示:
2 <= timePoints.length <= 2 * 10^4
timePoints[i] 格式为 “HH:MM”
示例示例 1:
12输入:timePoints = ["23:59","00:00"]输出:1
示例 2:
12输入:timePoints = ["00:00","23:59","00:00"]输出:0
笔者理解此题是一道字符串算法问题,在力扣题库中被定义为中等题。
解法当笔者阅读完此题后,发现此题直接计算即可,让我们来看看具体如何实现的吧。
实现12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152public int findMinDiffe ...
建造者模式
引入在之前的文章中我们介绍了常见的设计模式,今天我们来使用 Java 语言对建造者模式进行具体实现举例。
实例在下面的例子中,我们使用建造者模式来对 Person 类的实例化进行了改装,使其能够以链式调用的形式创建对象。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980/** * 建造者模式 * * 当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。 * 源自 https://zhuanlan.zhihu.com/p/58093669 * * @author marx * @date 2022/01/13 */public class Builder { public static void main(String[] args) { Person person ...
累加数
力扣 306. 累加数题目说明累加数 是一个字符串,组成它的数字可以形成累加序列。
一个有效的 累加序列 必须 至少 包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。
给你一个只包含数字 ‘0’-‘9’ 的字符串,编写一个算法来判断给定输入是否是 累加数 。如果是,返回 true ;否则,返回 false 。
说明:累加序列里的数 不会 以 0 开头,所以不会出现 1, 2, 03 或者 1, 02, 3 的情况。
提示:
1 <= num.length <= 35
num 仅由数字(0 - 9)组成
示例示例 1:
123输入:"112358"输出:true 解释:累加序列为: 1, 1, 2, 3, 5, 8 。1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8
示例 2:
123输入:"199100199"输出:true 解释:累加序列为: 1, 99, 100, 199。1 + 99 = 100, 99 + 100 = 199
笔者理解此题是一道 ...
格雷编码
力扣 89. 格雷编码题目说明n 位格雷码序列 是一个由 2n 个整数组成的序列,其中:
每个整数都在范围 [0, 2n - 1] 内(含 0 和 2n - 1)
第一个整数是 0
一个整数在序列中出现 不超过一次
每对 相邻 整数的二进制表示 恰好一位不同 ,且
第一个 和 最后一个 整数的二进制表示 恰好一位不同
给你一个整数 n ,返回任一有效的 n 位格雷码序列 。
提示:
1 <= n <= 16
示例示例 1:
12345678910111213输入:n = 2输出:[0,1,3,2]解释:[0,1,3,2] 的二进制表示是 [00,01,11,10] 。- 00 和 01 有一位不同- 01 和 11 有一位不同- 11 和 10 有一位不同- 10 和 00 有一位不同[0,2,3,1] 也是一个有效的格雷码序列,其二进制表示是 [00,10,11,01] 。- 00 和 10 有一位不同- 10 和 11 有一位不同- 11 和 01 有一位不同- 01 和 00 有一位不同
示例 2:
12输入:n = 1输出:[0,1]
笔者理解此题是 ...
简化路径
力扣 71. 简化路径题目说明给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 ‘/‘ 开头),请你将其转化为更加简洁的规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,’//‘)都被视为单个斜杠 ‘/‘ 。 对于此问题,任何其他格式的点(例如,’…’)均被视为文件/目录名称。
请注意,返回的 规范路径 必须遵循下述格式:
始终以斜杠 ‘/‘ 开头。
两个目录名之间必须只有一个斜杠 ‘/‘ 。
最后一个目录名(如果存在)不能 以 ‘/‘ 结尾。
此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 ‘.’ 或 ‘..’)。
返回简化后得到的 规范路径 。
提示:
1 <= path.length <= 3000
path 由英文字母,数字,’.’,’/‘ 或 ‘_’ 组成。
path 是一个有效的 Unix 风格绝对路径。
示例示例 1:
123输入:path = " ...









