Decorative image frame

leetcode回顾——[934] Shortest Bridge

题目

在给定的二维二进制数组 A 中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)

现在,我们可以将 0 变为 1,以使两座岛连接起来,变成一座岛。

返回必须翻转的 0 的最小数目。(可以保证答案至少是 1。)

示例 1:

输入:[[0,1],[1,0]]
输出:1
示例 2:

输入:[[0,1,0],[0,0,0],[0,0,1]]
输出:2
示例 3:

输入:[[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
输出:1

提示:

1 <= A.length = A[0].length <= 100
A[i][j] == 0 或 A[i][j] == 1

Read More...

java源码解析之CopyOnWriteArrayList

CopyOnWriteArrayList的并发实现

  • 锁机制的采用:final transient ReentrantLock lock = new ReentrantLock();
  • 元素的存储:private transient volatile Object[] array;,采用了volatile修饰,确保array的在多线程下的可见性
  • 并发下的设置元素,采用了java.util.concurrent包的ReentrantLock锁(创建时采用了默认的不公平锁),在设置新元素时,是获取了原数组的一个拷贝Object[] elements = getArray();,在拷贝的数组上进行元素的更改,在更改完成后,通过setArray方法更新旧的array数组
Read More...

简易实现文件分块上传功能——后端代码的实现

原理解析

面对大文件上传时,如果文件过大,不仅上传耗时长,并且后端的I/O线程将处于长时间的写文件状态,不仅拖累后端的运行,而且对于前端用户的体验也不好,如果中途失败的话,文件上传失败,不仅白白浪费时间,后端也白白浪费了线程的工作效率

这个时候,就可以考虑前后端合作实现文件的分块上传,前端实现文件的切割服务,后端根据文件块进行文件块的存储、最终文件块的merge成为最终的上传文件

其实原理很简单,前端将文件分块,同时对文件的内容进行MD5处理生成一个签名,在发送文件块的时候,附带几个信息

  • 当前文件块的chunkId
  • 总文件chunk数目
  • 原文件名
  • 文件MD5签名
Read More...

leetcode回顾——[402] Remove K Digits

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:

num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
示例 1 :

输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
示例 2 :

输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :

输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0。
Read More...

leetcode回顾——[662] Maximum Width of Binary Tree

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。
每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。

示例 1:

输入:

1
/ \
3 2
/ \ \
5 3 9

输出: 4
解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)。
示例 2:

输入:

1
/
3
/ \
5 3

输出: 2
解释: 最大值出现在树的第 3 层,宽度为 2 (5,3)。
示例 3:

输入:

1
/ \
3 2
/
5

输出: 2
解释: 最大值出现在树的第 2 层,宽度为 2 (3,2)。
示例 4:

输入:

1
/ \
3 2
/ \
5 9
/ \
6 7
输出: 8
解释: 最大值出现在树的第 4 层,宽度为 8 (6,null,null,null,null,null,null,7)。
Read More...

leetcode回顾——[164] Maximum Gap

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。

如果数组元素个数小于 2,则返回 0。

示例 1:

输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
示例 2:

输入: [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。
说明:

你可以假设数组中所有元素都是非负整数,且数值在 32 位有符号整数范围内。
请尝试在线性时间复杂度和空间复杂度的条件下解决此问题。
Read More...

java源码解析之ConcurrentHashMap

ConcurrentHashMap的并发实现

  • transient volatile Node<K,V>[] table;确保了table对所有线程的可见性
  • transient volatile Node<K,V>[] nextTable;用于hashmap重新resize时
  • 确定元素在hashmap中的位置

    1
    2
    3
    static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
    return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
    }

    通过源码可以看出,tabAt调用了Unsafe类的getObjectVolatile方法(获取obj对象中offset偏移地址对应的object型field的值,支持volatile load语义),再加上table是线程可见的,因此保证了tabAt拿到的都是最新的数据

Read More...