| 每日一题做题记录,参考官方和三叶的题解 |
题目要求
思路一:枚举模拟
Java
class Solution {
public List<Integer> fallingSquares(int[][] positions) {
int n = positions.length;
List<Integer> height = new ArrayList<Integer>();
for(int i = 0; i < n; i++) {
int lc = positions[i][0], rc = positions[i][0] + positions[i][1] - 1; // 当前
int res = positions[i][1];
for(int j = 0; j < i; j++) {
int lp = positions[j][0], rp = positions[j][0] + positions[j][1] - 1; // 之前的
if(rc >= lp && rp >= lc)
res = Math.max(res, height.get(j) + positions[i][1]);
}
height.add(res);
}
for(int i = 1; i < n; i++)
height.set(i, Math.max(height.get(i), height.get(i - 1)));
return height;
}
}
- 时间复杂度:
- 空间复杂度:
C++
class Solution {
public:
vector<int> fallingSquares(vector<vector<int>>& positions) {
int n = positions.size();
vector<int> height;
for(int i = 0; i < n; i++) {
int lc = positions[i][0], rc = positions[i][0] + positions[i][1] - 1; // 当前
int res = positions[i][1];
for(int j = 0; j < i; j++) {
int lp = positions[j][0], rp = positions[j][0] + positions[j][1] - 1; // 之前的
if(rc >= lp && rp >= lc)
res = max(res, height[j] + positions[i][1]);
}
height.push_back(res);
}
for(int i = 1; i < n; i++)
height[i] = max(height[i], height[i - 1]);
return height;
}
};
- 时间复杂度:
- 空间复杂度:
思路二:线段树【动态开点】
- 可以把问题归结为『区间修改+区间查询』:
- 当前方块左端点为,则其右端点;
- 题目即为查询与更新当前范围的最大高度;
- 所以使用带”懒标记“的线段树
二.1、估点
- 按照题设,可估算为,其中指查询次数,在本题中为数组的长度。
Java
class Solution {
class Node {
int ls, rs; // 当前左右节点在tree中下标
int height, lazy;
}
int N = (int)1e9, cnt = 0;
Node[] tr = new Node[1000010]; // 初始化一个超级无敌大数组
void update(int u, int lc, int rc, int l, int r, int v) {
if(l <= lc && rc <= r) {
tr[u].height = v;
tr[u].lazy = v;
return ;
}
pushdown(u);
int m = lc + rc >> 1;
if(l <= m)
update(tr[u].ls, lc, m, l, r, v);
if(r > m)
update(tr[u].rs, m + 1, rc, l, r, v);
pushup(u);
}
int query(int u, int lc, int rc, int l, int r) {
if(l <= lc && rc <= r)
return tr[u].height;
pushdown(u);
int m = lc + rc >> 1, res = 0;
if(l <= m)
res = query(tr[u].ls, lc, m, l, r);
if(r > m)
res = Math.max(res, query(tr[u].rs, m + 1, rc, l, r));
return res;
}
void pushdown(int u) {
if(tr[u] == null)
tr[u] = new Node();
if(tr[u].ls == 0) {
tr[u].ls = ++cnt;
tr[tr[u].ls] = new Node();
}
if(tr[u].rs == 0) {
tr[u].rs = ++ cnt;
tr[tr[u].rs] = new Node();
}
if(tr[u].lazy == 0)
return ;
int lazy = tr[u].lazy;
tr[tr[u].ls].lazy = lazy;
tr[tr[u].rs].lazy = lazy;
tr[tr[u].ls].height = lazy;
tr[tr[u].rs].height = lazy;
tr[u].lazy = 0;
}
void pushup(int u) {
tr[u].height = Math.max(tr[tr[u].ls].height, tr[tr[u].rs].height);
}
public List<Integer> fallingSquares(int[][] positions) {
List<Integer> res = new ArrayList<>();
tr[1] = new Node();
for(int[] p : positions) {
int x = p[0], h = p[1];
int cur = query(1, 1, N, x, x + h - 1);
update(1, 1, N, x, x + h - 1, cur + h);
res.add(tr[1].height);
}
return res;
}
}
- 时间复杂度:,其中为数组长度,为值域大小
- 空间复杂度:
C++
static int N = 1e9;
class Solution {
int cnt = 0;
public:
class Node {
public:
int ls, rs; // 当前左右节点在tree中下标
int height, lazy;
};
vector<Node*> tr = vector<Node*>(1000010); // 初始化一个超级无敌大数组
void update(int u, int lc, int rc, int l, int r, int v) {
if(l <= lc && rc <= r) {
tr[u]->height = v;
tr[u]->lazy = v;
return ;
}
pushdown(u);
int m = (lc + rc) >> 1;
if(l <= m)
update(tr[u]->ls, lc, m, l, r, v);
if(r > m)
update(tr[u]->rs, m + 1, rc, l, r, v);
pushup(u);
}
int query(int u, int lc, int rc, int l, int r) {
if(l <= lc && rc <= r)
return tr[u]->height;
pushdown(u);
int m = (lc + rc) >> 1, res = 0;
if(l <= m)
res = query(tr[u]->ls, lc, m, l, r);
if(r > m)
res = max(res, query(tr[u]->rs, m + 1, rc, l, r));
return res;
}
void pushdown(int u) {
if(tr[u] == nullptr)
tr[u] = new Node();
if(tr[u]->ls == 0) {
tr[u]->ls = ++cnt;
tr[tr[u]->ls] = new Node();
}
if(tr[u]->rs == 0) {
tr[u]->rs = ++ cnt;
tr[tr[u]->rs] = new Node();
}
if(tr[u]->lazy == 0)
return ;
int lazy = tr[u]->lazy;
tr[tr[u]->ls]->lazy = lazy;
tr[tr[u]->rs]->lazy = lazy;
tr[tr[u]->ls]->height = lazy;
tr[tr[u]->rs]->height = lazy;
tr[u]->lazy = 0;
}
void pushup(int u) {
tr[u]->height = max(tr[tr[u]->ls]->height, tr[tr[u]->rs]->height);
}
vector<int> fallingSquares(vector<vector<int>>& positions) {
vector<int> res;
tr[1] = new Node();
for(auto p : positions) {
int x = p[0], h = p[1];
int cur = query(1, 1, N, x, x + h - 1);
update(1, 1, N, x, x + h - 1, cur + h);
res.push_back(tr[1]->height);
}
return res;
}
};
- 时间复杂度:,其中为查询次数,为值域大小
- 空间复杂度:
二.2、动态指针
- 可以有效避免new大数组的初始化开销,在不考虑static优化or全局数组优化的情况下,动态指针的方法更好一点。
Java
class Solution {
class Node {
Node ls, rs; // 当前左右节点在tree中下标
int height, lazy;
}
int N = (int)1e9;
Node root = new Node(); // 初始化一个根
void update(Node node, int lc, int rc, int l, int r, int v) {
if(l <= lc && rc <= r) {
node.height = v;
node.lazy = v;
return ;
}
pushdown(node);
int m = lc + rc >> 1;
if(l <= m)
update(node.ls, lc, m, l, r, v);
if(r > m)
update(node.rs, m + 1, rc, l, r, v);
pushup(node);
}
int query(Node node, int lc, int rc, int l, int r) {
if(l <= lc && rc <= r)
return node.height;
pushdown(node);
int m = lc + rc >> 1, res = 0;
if(l <= m)
res = query(node.ls, lc, m, l, r);
if(r > m)
res = Math.max(res, query(node.rs, m + 1, rc, l, r));
return res;
}
void pushdown(Node node) {
if(node.ls == null)
node.ls = new Node();
if(node.rs == null)
node.rs = new Node();
if(node.lazy == 0)
return ;
int lazy = node.lazy;
node.ls.lazy = lazy;
node.rs.lazy = lazy;
node.ls.height = lazy;
node.rs.height = lazy;
node.lazy = 0;
}
void pushup(Node node) {
node.height = Math.max(node.ls.height, node.rs.height);
}
public List<Integer> fallingSquares(int[][] positions) {
List<Integer> res = new ArrayList<>();
for(int[] p : positions) {
int x = p[0], h = p[1];
int cur = query(root, 0, N, x, x + h - 1);
update(root, 0, N, x, x + h - 1, cur + h);
res.add(root.height);
}
return res;
}
}
- 时间复杂度:,其中为查询次数,为值域大小
- 空间复杂度:
C++
【遇事不决加个*号,解决一半报错】
static int N = 1e9;
class Solution {
public:
class Node {
public:
Node *ls, *rs; // 当前左右节点在tree中下标
int height, lazy;
};
Node *root = new Node(); // 初始化一个超级无敌大数组
void update(Node *node, int lc, int rc, int l, int r, int v) {
if(l <= lc && rc <= r) {
node->height = v;
node->lazy = v;
return ;
}
pushdown(node);
int m = (lc + rc) >> 1;
if(l <= m)
update(node->ls, lc, m, l, r, v);
if(r > m)
update(node->rs, m + 1, rc, l, r, v);
pushup(node);
}
int query(Node *node, int lc, int rc, int l, int r) {
if(l <= lc && rc <= r)
return node->height;
pushdown(node);
int m = (lc + rc) >> 1, res = 0;
if(l <= m)
res = query(node->ls, lc, m, l, r);
if(r > m)
res = max(res, query(node->rs, m + 1, rc, l, r));
return res;
}
void pushdown(Node *node) {
if(node->ls == nullptr)
node->ls = new Node();
if(node->rs == nullptr)
node->rs = new Node();
if(node->lazy == 0)
return ;
int lazy = node->lazy;
node->ls->lazy = lazy;
node->rs->lazy = lazy;
node->ls->height = lazy;
node->rs->height = lazy;
node->lazy = 0;
}
void pushup(Node *node) {
node->height = max(node->ls->height, node->rs->height);
}
vector<int> fallingSquares(vector<vector<int>>& positions) {
vector<int> res;
for(auto p : positions) {
int x = p[0], h = p[1];
int cur = query(root, 0, N, x, x + h - 1);
update(root, 0, N, x, x + h - 1, cur + h);
res.push_back(root->height);
}
return res;
}
};
- 时间复杂度:,其中为查询次数,为值域大小
- 空间复杂度:
总结
学了一波线段树动态开点的巧妙应用,感觉可以单开一篇专门学习。因为不太会估点(数据结构学得不太行),所以我比较喜欢动态指针,简单快乐一点(虽然C++的指针又搞了半天)。
【哦这几天这么忙结果总是大难题……能不能平均一点】
| 欢迎指正与讨论! |