LeetCode每日一题
2023-11-05 LeetCode187: 重复的DNA序列
字符串+去重+滑动窗口 因为s.substring的时间复杂度为O(n),频繁调用会影响效率,所以采用hashmap
1 |
|
2023-11-06 LeetCode318: 最大单词长度乘积
第一次接触位运算。 对于本题目来说,O(n^2)的基础时间复杂度是少不了的,所以最好是可以把单词是否含有公共字母的判断降到O(1)的时间复杂度:
1 |
|
2023-11-07 LeetCode2586: 统计范围内的元音字符串数
一道很直白的简单题:
1 |
|
2023-11-08 LeetCode2609: 最长平衡子字符串
1 |
|
2023-11-09 LeetCode2258: 逃离火灾
双BFS,考虑到位置问题 所有火灾同时参与BFS:
1 |
|
2023-11-10 LeetCode2300: 咒语和药水的 成功对数
O(nlogn)的时间复杂度:
1 |
|
2023-11-13 LeetCode307: 区域和检索,数组可修改
首先,对于本题目来说,直接做也能过,但是时间复杂度较高:
1 |
|
所以,对于今天的每日一题,自然有了新的解法。
(1)线段树。 线段树 segmentTree是一个二叉树,每个结点保存数组 nums在区间 [s,e]的最小值、最大值或者总和等信息。线段树可以用树也可以用数组(堆式存储)来实现。对于数组实现,假设根结点的下标为 0,如果一个结点在数组的下标为 node,那么它的左子结点下标为 node×2+1,右子结点下标为 node×2+2。
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
52private int[] segmentTree;
int n;
public NumArray(int[] nums) {
n = nums.length;
segmentTree = new int[n * 4];
build(0, 0, n - 1, nums);
}
public void update(int index, int val) {
change(index, val, 0, 0, n - 1);
}
public int sumRange(int left, int right) {
return range(left, right, 0, 0, n - 1);
}
//自底向上开始建树 node节点保存nums[s]到nums[e]的总和
private void build (int node, int s, int e, int[] nums) {
if (s == e) {
segmentTree[node] = nums[s];
return;
}
int m = (s + e) / 2;
build(node * 2 + 1, s, m, nums);
build(node * 2 + 2, m + 1, e, nums);
segmentTree[node] = segmentTree[node * 2 + 1] + segmentTree[node * 2 + 2];
}
private void change(int index, int val, int node, int s, int e) {
if (s == e) {
segmentTree[node] = val;
return;
}
int m = (s + e) / 2;
if (index <= m) {
change(index, val, node * 2 + 1, s, m);
} else {
change(index, val, node * 2 + 2, m + 1, e);
}
segmentTree[node] = segmentTree[node * 2 + 1] + segmentTree[node * 2 + 2];
}
private int range(int left, int right, int node, int s, int e) {
if (left == s && right == e) {
return segmentTree[node];
}
int m = (s + e) / 2;
if (right <= m) {
return range(left, right, node * 2 + 1, s, m);
} else if (left > m) {
return range(left, right, node * 2 + 2, m + 1, e);
} else{
return range(left, m, node * 2 + 1, s, m) + range(m + 1, right, node * 2 + 2, m + 1, e);
}
}(2) 树状数组。树状数组是一种可以动态维护序列前缀和的数据结构(序列下标从1开始),它的功能是:
(1)单点修改 add(index, val) 把序列第index个数增加val (2) 区间查询 prefixSum(index):查询前 index 个元素的前缀和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
36private int[] tree;
private int[] nums;
public NumArray(int[] nums) {
tree = new int[nums.length + 1];
this.nums = nums;
for (int i = 0; i < nums.length; i++) {
add(i + 1, nums[i]);
}
}
public void update(int index, int val) {
add(index + 1, val - nums[index]);
nums[index] = val;
}
public int sumRange(int left, int right) {
return prefixSum(right + 1) - prefixSum(left);
}
private int lowBit(int x) {
return x & -x;
}
private void add(int index, int val) {
while (index < tree.length) {
tree[index] += val;
index += lowBit(index);
}
}
private int prefixSum(int index) {
int sum = 0;
while (index > 0) {
sum += tree[index];
index -= lowBit(index);
}
return sum;
}
2023-11-14 LeetCode1334: 阈值距离内邻居最少的城市
图上的动态规划,做了两个多小时:
1 |
|
2023-11-15 LeetCode2656: K个最大元素的和
1 |
|
2023-11-15 LeetCode2760: 最长奇偶子数组
1 |
|
LeetCode每日一题
http://example.com/2023/11/05/LeetCode每日一题/