第一部分---线段树:https://leetcode.com/tag/segment-tree/

【218】The Skyline Problem

【307】Range Sum Query - Mutable

【308】Range Sum Query 2D - Mutable

【315】Count of Smaller Numbers After Self

【493】Reverse Pairs

【699】Falling Squares (我的线段树第一题,2019年1月24日)

在 X 轴上落方块,问最后整个区间内的最高的高度是多少。

Input: [[1, 2], [2, 3], [6, 1]]
Output: [2, 5, 5]
Explanation: After the first drop of positions[0] = [1, 2]:
_aa
_aa
-------
The maximum height of any square is 2. After the second drop of positions[1] = [2, 3]:
__aaa
__aaa
__aaa
_aa__
_aa__
--------------
The maximum height of any square is 5.
The larger square stays on top of the smaller square despite where its center
of gravity is, because squares are infinitely sticky on their bottom edge. After the third drop of positions[1] = [6, 1]:
__aaa
__aaa
__aaa
_aa
_aa___a
--------------
The maximum height of any square is still 5. Thus, we return an answer of [2, 5, 5].

题解:用了线段树的单点更新,只能beats 1.9% == 如果用区间更新的话, 应该快很多。但是这是第一题线段树,纪念一下。(我的线段树写的都是 base 0)

 class Solution {
public:
const static int MAX_SIZE = << ;
struct SegmentTree {
void init(int _n) {
n = ;
while (n < _n) {
n *= ;
}
for (int i = ; i < n * -; ++i) { dat[i] = ; }
}
#define lson(k) k*2+1
#define rson(k) k*2+2
#define father(k) (k-1)/2
inline void pushup(int k) { dat[k] = max(dat[lson(k)], dat[rson(k)]); }
void update(int k, int value) {
k += n - ;
dat[k] = value;
while (k > ) {
k = (k-)/;
pushup(k);
}
}
int query(int a, int b, int k, int l, int r) {
if (r <= a || b <= l) { return ; }
if (a <= l && r <= b) {
return dat[k];
} else {
int vl = query(a, b, lson(k), l, (l+r)/);
int vr = query(a, b, rson(k), (l+r)/, r);
return max(vl, vr);
}
}
void print() {
for (int i = ; i < * n - ; ++i) {
printf("%d ", dat[i]);
}
printf("\n");
}
int n, dat[MAX_SIZE];
};
vector<int> fallingSquares(vector<pair<int, int>>& positions) {
int size = positions.size();
set<int> st;
for (auto pos : positions) {
st.insert(pos.first),
st.insert(pos.first + pos.second - );
}
vector<int> nums(st.begin(), st.end());
SegmentTree seg;
seg.init((int)st.size());
vector<int> ans;
for (auto pos : positions) {
int l = pos.first, r = pos.first + pos.second - , h = pos.second;
int idxL = distance(st.begin(), st.find(l)), idxR = distance(st.begin(), st.find(r));
int base = seg.query(idxL, idxR+, , , seg.n);
for (int i = idxL; i <= idxR; ++i) {
seg.update(i, base + h);
}
int maxx = seg.query(, (int)st.size(), , , seg.n);
ans.push_back(maxx);
}
return ans;
}
};

【715】Range Module

【732】My Calendar III

【850】Rectangle Area II (2019年3月15日,google tag)重叠矩形求面积

题解:我们需要一个新的grid,然后去标记grid上的每个格子是不是被矩形覆盖。grid可以不均匀,(离散化思想)。具体来说,将所有的X坐标集中起来(要去除重复),将所有的Y坐标集中起来,然后将其两两配对组成一个二维的网络。

然后对于每一个矩形,去grid上标记grid上的方格是不是被覆盖,被覆盖的话标记为 true,这个小方格需要计算面积。简单来说:在这个网络中找到每个矩形所框起来的范围(遵循左闭右开的原则),标记这个范围内的网格点为true,意味着这些网格点是落在被cover的面积里。遍历完所有的矩形后,所有标记为true的网格点都是要被算入面积的,而那些没有标记的说明不用被计算。

然后把 grid 上标记为 true 的小方格的面积加起来就可以了。

 class Solution {
public:
int rectangleArea(vector<vector<int>>& rectangles) {
set<int> x_axis, y_axis;
for (auto& r : rectangles) {
x_axis.insert(r[]),
x_axis.insert(r[]),
y_axis.insert(r[]),
y_axis.insert(r[]);
}
vector<int> x(x_axis.begin(), x_axis.end()), y(y_axis.begin(), y_axis.end());
vector<vector<int>> grid(y.size(), vector<int>(x.size(), ));
for (auto& r : rectangles) {
int xleft = distance(x_axis.begin(), x_axis.lower_bound(r[]));
int xright = distance(x_axis.begin(), x_axis.lower_bound(r[]));
int ybuttom = distance(y_axis.begin(), y_axis.lower_bound(r[]));
int ytop = distance(y_axis.begin(), y_axis.lower_bound(r[]));
for (int x0 = xleft; x0 < xright; ++x0) {
for (int y0 = ybuttom; y0 < ytop; ++y0) {
grid[y0][x0] = ;
}
}
}
long res = ;
const int mod = 1e9+;
for (int y0 = ; y0 < grid.size(); ++y0) {
for (int x0 = ; x0 < grid[y0].size(); ++x0) {
if (grid[y0][x0]) {
res += long(x[x0+] - x[x0]) * long(y[y0+] - y[y0]);
res %= mod;
}
}
}
return res;
}
};

第二部分---树状数组:https://leetcode.com/tag/binary-indexed-tree/

【218】The Skyline Problem (2019年1月22日)

本题想不出来用树状数组怎么做,最后自己yy出来了一种写法来做。

给了一堆大楼,给了每个楼的坐标和高度,用 (l, r, h) 表示,返回所有的 key points, A key point is the left endpoint of a horizontal line segment.

For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] .

For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ].

题解:这个题用BIT我是想不出来有什么解法,但是 heap (斜堆) 和 线段树可以做。我是利用了 C++ STL 里面的 multiset 做的。

我们先用扫描线看这个图,从左往右扫,如果扫描到了一个building的左边,说明这个大楼开始了,我们想查看下这个楼的左上角能不能作为 key point,如果能,就把它加到答案里面,如果不能就不加。怎么判断这个楼的左上角能不能加到答案里面呢?我们先看下它的高度,如果它比前面所有的楼都高,那它的左上角肯定是个 key point, 如果前面有比它高的楼并且这个楼还没有结束,那么他就不是一个 key point。如果扫描到了一个大楼的右边,说明这个楼结束了,那么这个楼的右边界的坐标能不能做 key point 呢?如果它前面有楼比它高,就不能,如果前面有楼跟它一样高,还是不能,只有把它删除之后,剩下所有的楼都比它矮,它才能做 key point。所以我们用扫描线依次扫描所有的坐标,就能生成答案。

 //本题还有个边界情况是两个楼高度一样,如果不交叠,刚好碰上了怎么办,[[0,2,3],[2,5,3]]
class Solution {
public:
struct kcmp {
bool operator() (const pair<int, int>& p1, const pair<int, int>& p2) const {
if (p1.first == p2.first) {
return p1.second > p2.second;
}
return p1.first < p2.first;
}
};
vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
for (auto b : buildings) {
record.insert(make_pair(b[], b[]));
record.insert(make_pair(b[], -b[]));//离开用负数来记录
}
vector<pair<int, int>> ret;
for (auto line : record) {
bool enter = line.second > ? true : false;
int h = abs(line.second);
if (enter) { //如果这条线上有个楼进来了
if (h > getMaxHeight()) {
ret.push_back(make_pair(line.first, h));
}
stHeight.insert(h);
} else { //如果这条线有个楼出去了,可能会往ret里面加个低的点,或者前面还有楼比它高的话,就把这条线给扔了
auto iter = stHeight.find(h);
stHeight.erase(iter);
if (h > getMaxHeight()) {
ret.push_back(make_pair(line.first, getMaxHeight()));
}
}
}
return ret;
}
multiset<pair<int, int>, kcmp> record;
multiset<int> stHeight;
int getMaxHeight() {
if (stHeight.empty()) {
return ;
}
return *stHeight.rbegin();
}
};

【307】Range Sum Query - Mutable (2019年1月14日,学习BIT)

实现一个一维的树状数组模板。

 class NumArray {
public:
NumArray(vector<int> nums) {
n = nums.size();
this->nums.resize(n+);
bit.resize(n+);
for (int i = ; i <= n; ++i) {
this->nums[i] = nums[i-];
add(i, this->nums[i]);
}
}
void update(int i, int val) {
add(i+, val - nums[i+]);
nums[i + ] = val;
}
int sumRange(int i, int j) {
++i, ++j;
return sum(j) - sum(i-);
}
int lowbit(int x) {
return x & -x;
}
void add(int x, int v) {
for (int i = x; i <= n; i += lowbit(i)) {
bit[i] += v;
}
}
int sum(int x) {
int ret = ;
for (int i = x; i > ; i -= lowbit(i)) {
ret += bit[i];
}
return ret;
}
vector<int> nums, bit;
int n;
}; /**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* obj.update(i,val);
* int param_2 = obj.sumRange(i,j);
*/

【308】Range Sum Query 2D - Mutable (2019年1月14日,学习BIT)

【315】Count of Smaller Numbers After Self (2019年1月22日,Fenwick Tree 练习)

给了一个数组 nums, 返回一个数组,数组中的元素 ret[i] 代表 nums[i] 的右边有多少个比它小的数。(题目如果换一下, 求每个元素左/右边有多少个比它小/大/大于等于/小于等于的数)

You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:
Input: [,,,]
Output: [,,,]
Explanation:
To the right of there are smaller elements ( and ).
To the right of there is only smaller element ().
To the right of there is smaller element ().
To the right of there is smaller element.

题解:这个题第一个想法是dp做,但是尝试了两下,完全推导不了。dp做不出来。看了下tag是树状数组,还有BST等等等很多种解法。我这次先练习下怎么用树状数组解题。

树状数组有两个用途(1)用 O(logN)的时间求前缀和。(2)用log(N)的时间在位置为 i 的元素上增加一个数。

这个题求数组中一个元素右边有多少个数比它小。我们如果翻转下数组,就可以变成求数组中一个元素左边有多少元素比它小。

那么它和 Fenwick Tree 有什么关系呢?

你想啊,我们可以把原数组先排序并且去重,得到一个递增的并且unique元素的新数组,但是呢这个新数组不能代表原来的数组,因为原来数组中可能有重复元素。所以我们搞出来一个 freq 数组(其实就是我们树状数组的原来数组),配合sorted数组使用。

sorted数组里面的元素不是连续的,我们需要把它离散化,求出他们的相对位置。关系如下图:

nums:      [7, 1, 3, 2, 9, 2, 1]

sorted:    [1, 2, 3, 7, 9] (1-based)(其实就是我们元素 对应 树状数组的下标) sorted[nums[i]] = j

reversed: [1, 2, 9, 2, 3, 1, 7]

rank:       [1, 2, 5, 2, 3, 1, 4]

依次遍历 reversed 数组,先求这个元素前面有多少个元素小于它(树状数组的前缀和),增加每个元素的 freq。往下求就ok了。

 class Solution {
public:
class FenwickTree {
public:
FenwickTree(int n): sums_(n+, ) {}
void add (int i, int delta) {
while (i < sums_.size()) {
sums_[i] += delta;
i += lowbit(i);
}
}
int query (int i) {
int sum = ;
while (i > ) {
sum += sums_[i];
i -= lowbit(i);
}
return sum;
}
private:
static inline int lowbit(int x) {return x & -x;}
vector<int> sums_;
};
vector<int> countSmaller(vector<int>& nums) {
set<int> sorted(nums.begin(), nums.end());
unordered_map<int, int> rank;
int r = ;
for (auto num : sorted) {
rank[num] = ++r;
}
vector<int> ret;
FenwickTree bit(rank.size());
for (int i = nums.size() - ; i >= ; --i) {
r = rank[nums[i]];
ret.push_back(bit.query(r-));
bit.add(r, );
}
reverse(ret.begin(), ret.end());
return ret;
}
};

【493】Reverse Pairs (2019年1月23日,复习Fenwick Tree 和 学习Segment Tree)

给了一个数组,求数组中逆序对的个数。注意这题的逆序对和我们平常定义的有个非常微小的差异。

Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].

数据规模:

  1. The length of the given array will not exceed 50,000.
  2. All the numbers in the input array are in the range of 32-bit integer.

Example1:

Input: [1,3,2,3,1]
Output: 2

Example2:

Input: [2,4,3,5,1]
Output: 3

题解:我是用树状数组求的。我们先把数组离散化获得他们的相对大小。然后用排序好了的去重之后的数组下标来作为bit的原始数组,原始数组中所有元素都为0。我们从头开始遍历 nums 数组,对于nums[i]这个元素,首先获取它离散化之后的下标。然后查询从 nums[i] * 2 + 1 到排序数组的最大值的这段区间里面的区间和。累加到ret上面就可以了。注意数据规模 nums[i] 最大可以到 INT_MAX, 最小可以到 INT_MIN,所以 nums[i] * 2 + 1 完全可能超过 int 的范围。

 class Solution {
public:
int reversePairs(vector<int>& nums) {
const int n = nums.size();
set<int> st(nums.begin(), nums.end());
m = st.size();
summ = vector<int>(m+, );
map<int, int> mp;
int idx = ;
for (auto e : st) {
mp[e] = idx++;
}
vector<long long> sorted(m+, ); //0-based
int t = ;
for (auto e : st) {
sorted[t++] = e;
}
int ret = ;
for (int i = ; i < nums.size(); ++i) {
int e = nums[i];
int x = mp[e];
long long target = * (long long)nums[i];
int x1 = distance(sorted.begin(), upper_bound(sorted.begin(), sorted.end(), target));
ret += query(m) - query(x1 - );
add(x, );
}
return ret;
}
int m;
vector<int> summ; //bit sum
void add(int x, int val) {
for (int i = x; i <= m; i += lowbit(i)) {
summ[i] += val;
}
}
int query(int x) {
int res = ;
for (int i = x; i > ; i -= lowbit(i)) {
res += summ[i];
}
return res;
}
int lowbit(int x) {
return x & (-x);
}
void print(map<int, int>& mp) {
for (auto p : mp) {
cout << p.first << " " << p.second << endl;
}
}
void print(vector<int>& nums) {
for (auto e : nums) {
cout << e << " " ;
}
cout << endl;
}
};

【LeetCode】线段树 segment-tree(共9题)+ 树状数组 binary-indexed-tree(共5题)的更多相关文章

  1. 树状数组(Binary Indexed Tree) 总结

    1.“树状数组”数据结构的一种应用 对含有n个元素的数组(a[1],...,a[k],...,a[n]): (1)求出第i个到第j个元素的和,sum=a[i]+...+a[j]. 进行j-i+1次加法 ...

  2. 树状数组 Binary Indexed Tree/Fenwick Tree

    2018-03-25 17:29:29 树状数组是一个比较小众的数据结构,主要应用领域是快速的对mutable array进行区间求和. 对于一般的一维情况下的区间和问题,一般有以下两种解法: 1)D ...

  3. 树状数组(Binary Indexed Tree(BIT))

    先不说别的,这个博客为我学习树状数组提供了很大帮助,奉上传送门 http://blog.csdn.net/int64ago/article/details/7429868 然后就说几个常用的操作 in ...

  4. 树状数组(Binary Index Tree)

    一维BIT(单点更新,区间求和): Problem - 1166 #include <iostream> #include <algorithm> #include <c ...

  5. LeetCode第[98]题(Java):Validate Binary Search Tree(验证二叉搜索树)

    题目:验证二叉搜索树 难度:Medium 题目内容: Given a binary tree, determine if it is a valid binary search tree (BST). ...

  6. 【leetcode刷题笔记】Validate Binary Search Tree

    Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...

  7. Leetcode: Range Sum Query 2D - Mutable && Summary: Binary Indexed Tree

    Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...

  8. 树状数组(Binary Indexed Tree,BIT)

    树状数组(Binary Indexed Tree) 前面几篇文章我们分享的都是关于区间求和问题的几种解决方案,同时也介绍了线段树这样的数据结构,我们从中可以体会到合理解决方案带来的便利,对于大部分区间 ...

  9. 树状数组(Binary Indexed Tree)

    树状数组(Binary Indexed Tree,BIT) 是能够完成下述操作的数据结构. 给一个初始值全为 0 的数列 a1, a2, ..., an (1)给定 i,计算 a1+a2+...+ai ...

  10. 树状数组,Fenwick Tree

    Fenwick Tree, (also known as Binary Indexed Tree,二叉索引树), is a high-performance data structure to cal ...

随机推荐

  1. Dubbo学习-4-dubbo简单案例-1

    模拟一个需求,通过dubbo实现RPC调用: 这里用户服务模块的查询用户地址的功能,就是一个服务提供者,而订单服务模块的创建订单模块就是一个服务消费者: 1. 创建服务提供者的maven工程:user ...

  2. 如何分析及处理 Flink 反压?

    反压(backpressure)是实时计算应用开发中,特别是流式计算中,十分常见的问题.反压意味着数据管道中某个节点成为瓶颈,处理速率跟不上上游发送数据的速率,而需要对上游进行限速.由于实时计算应用通 ...

  3. 如何查看本机上安装的.NET Framework版本

    在开始菜单选择"运行", 或者快捷键 “windows键+R” 在命令窗口输入regedit.exe,打开注册表 在注册表中定位到如下节点 HKEY_LOCAL_MACHINE\S ...

  4. [CF846B]Math Show题解

    暴力一下就好啦! 枚举一下一共做多少次任务,剩下的时间将子任务排序,从头开始能取多少取多少就行了. 贴个代码 #include <cstdio> #include <algorith ...

  5. 开发zeroc ice应用入门(java开发ice应用,python开发ice应用,java与python结合开发ice服务)

    ice作为一种rpc框架,为主流平台设计,包括Windows和Linux,支持广泛的语言,包括C++,Java,C#(和其他.Net的语言,例如Visual Basic),Python,Ruby,PH ...

  6. Period POJ - 1961

    Period POJ - 1961 时限: 3000MS   内存: 30000KB   64位IO格式: %I64d & %I64u 提交 状态 已开启划词翻译 问题描述 For each ...

  7. 洛谷P1546 最短网络 Agri-Net(最小生成树,Kruskal)

    洛谷P1546 最短网络 Agri-Net 最小生成树模板题. 直接使用 Kruskal 求解. 复杂度为 \(O(E\log E)\) . #include<stdio.h> #incl ...

  8. nginxUbuntu安装Nginx和正确卸载Nginx Nginx相关 与Nginx报错:nginx: [error] invalid PID number "" in "/run/nginx.pid" 解决方法

    https://www.cnblogs.com/zhaoyingjie/p/6840616.html https://blog.csdn.net/adley_app/article/details/7 ...

  9. 解决Win7部分便笺的元数据已被损坏的方法

    Win7部分便笺的元数据已被损坏的方法 我们使用键盘上"Win+F"组合键搜索功能,直接找到"inkobj.dll"这个文件,一般会搜索出来好多,先随便选一个. ...

  10. Delphi 文件转换Base64

    uses EncdDecd; function FileToBase64(FileName: string): string; var  MemoryStream: TMemoryStream;beg ...