第一部分---线段树: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. win8安装maven

    1.下载并解压maven F:\maven\apache-maven-3.5.2 2. 设置环境变量 3. Path路径中添加maven的可执行文件目录(bin目录) 4.验证maven是否安装成功: ...

  2. 阿里HBase的数据管道设施实践与演进

    摘要:第九届中国数据库技术大会,阿里巴巴技术专家孟庆义对阿里HBase的数据管道设施实践与演进进行了讲解.主要从数据导入场景. HBase Bulkload功能.HImporter系统.数据导出场景. ...

  3. grunt教程

    https://blog.csdn.net/sinat_38992528/article/details/79400595

  4. (3)狄泰软件学院C++课程学习剖析一

    深度剖析C++第一部分 1.类是一种模型,这种模型可以创建出一个对应的实体.有了类不一定有对应的实体,但是一个实体必定属于某一个类. 2.类用于抽象的描述 一类事物所持有的属性和行为:对象是具体的事物 ...

  5. vue2.0 之 douban (五)创建cell,media-cell组件

    1.组件cell 这里的cell分为三种样式,左侧带图标,不带图标,以及左侧带竖线的cell. 每一个组件都有一个底部边框: 这里我们采用了移动端1px像素问题的解决方法:父级元素设置相对定位,构建1 ...

  6. 五一清北学堂培训之数据结构(Day 1&Day 2)

    Day 1 前置知识: 二进制 2.基本语法 3.时间复杂度 正片       1.枚举 洛谷P1046陶陶摘苹果  入门题没什么好说的 判断素数:从2枚举到sqrt(n),若出现n的因子,则n是合数 ...

  7. php面向对象重的抽象类,接口类与静态

    static 静态 <?php class ren { public $name; public static $sex; static function shao() { echo " ...

  8. SqlSession 内部运行

    <深入浅出MyBatis技术原理与实战>p150页 SqlSession内部运行图 四大对象在流程中的操作. 1.准备sql.StatementHandler 的prepare方法进行sq ...

  9. Gitlab仓库搭建和免密使用gitlab

    Gitlab简介 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务. 可通过Web界面进行访问公开的或者私人项目.它拥有与Github类似的 ...

  10. 性能工具之JMeter+InfluxDB+Grafana打造压测可视化实时监控

    一.安装配置InfluxDB InfluxDB是GO语言开发的一个开源分布式时序数据库,非常适合存储指标.事件.分析等数据.有人做过mysql和influxDB对比,存储1000万条数据mysql要7 ...