Skip to content

Commit b6d70ec

Browse files
committed
加入一些题目: 其中587翻译的官方题解但是还是错的, 两个月之后再做
1 parent c17268a commit b6d70ec

File tree

8 files changed

+371
-104
lines changed

8 files changed

+371
-104
lines changed

cpp/leetcode/307. range-sum-query-mutable.cpp

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,104 @@
11
#include "public.h"
22

3+
//44ms, 69.11%
4+
//真:线段树
5+
6+
class NumArray {
7+
private:
8+
//此函数为求区间和写法
9+
vector<int> raw;
10+
int t[100002 << 2]; //a为原来区间,t为线段树,t的大小是a的四倍, 用来防止下标溢出RE
11+
int lazy[100002 << 2]; //懒惰标记, 的大小是a的四倍, 用来防止下标溢出RE
12+
int rIndex; //最大下标
13+
14+
void Pushup(int k) { //更新函数,这里是实现最大值 ,同理可以变成,最小值,区间和等
15+
t[k] = t[k << 1] + t[k << 1 | 1];
16+
}
17+
18+
//递归方式建树 build(1,1,n);
19+
//此函数仅在main调用一次, 线段树的结构在pushup过程中不变
20+
void build(int k, int l, int r) { //k为当前需要建立的结点,l为当前需要建立区间的左端点,r则为右端点
21+
if (l == r) //左端点等于右端点,即为叶子节点,直接赋值即可
22+
t[k] = raw[l];
23+
else {
24+
int m = l + ((r - l) >> 1); //m则为中间点,左儿子的结点区间为[l,m],右儿子的结点区间为[m+1,r]
25+
build(k << 1, l, m); //递归构造左儿子结点
26+
build(k << 1 | 1, m + 1, r); //递归构造右儿子结点
27+
Pushup(k); //更新父节点
28+
}
29+
}
30+
31+
void Pushdown(int k) { //更新子树的lazy值,这里是RMQ的函数,要实现区间和等则需要修改函数内容
32+
if (lazy[k]) { //如果有lazy标记
33+
lazy[k << 1] += lazy[k]; //更新左子树的lazy值
34+
lazy[k << 1 | 1] += lazy[k]; //更新右子树的lazy值
35+
t[k << 1] += lazy[k]; //左子树的最值加上lazy值
36+
t[k << 1 | 1] += lazy[k]; //右子树的最值加上lazy值
37+
lazy[k] = 0; //lazy值归0
38+
}
39+
}
40+
41+
//递归更新区间 updata(L,R,v,1,n,1);
42+
//v是待增加的值, 可能是个负的!
43+
void update(int L, int R, int v, int l, int r, int k) { //[L,R]即为要更新的区间,l,r为结点区间,k为结点下标
44+
if (L <= l && r <= R) { //如果当前结点的区间真包含于要更新的区间内
45+
lazy[k] += v; //懒惰标记
46+
t[k] += v; //最大值加上v之后,此区间的最大值也肯定是加v
47+
}
48+
else {
49+
Pushdown(k); //重难点,查询lazy标记,更新子树
50+
int m = l + ((r - l) >> 1);
51+
if (L <= m) //如果左子树和需要更新的区间交集非空
52+
update(L, R, v, l, m, k << 1);
53+
if (m < R) //如果右子树和需要更新的区间交集非空
54+
update(L, R, v, m + 1, r, k << 1 | 1);
55+
Pushup(k); //更新父节点
56+
}
57+
}
58+
59+
//递归方式区间查询 query(L,R,1,n,1);
60+
int query(int L, int R, int l, int r, int k) { //[L,R]即为要查询的区间,l,r为结点区间,k为结点下标
61+
if (L <= l && r <= R) //如果当前结点的区间真包含于要查询的区间内,则返回结点信息且不需要往下递归
62+
return t[k];
63+
else {
64+
Pushdown(k); /**每次都需要更新子树的Lazy标记*/
65+
int res = 0; //返回值变量,根据具体线段树查询的什么而自定义
66+
int m = l + ((r - l) >> 1); //m则为中间点,左儿子的结点区间为[l,m],右儿子的结点区间为[m+1,r]
67+
if (L <= m) //如果左子树和需要查询的区间交集非空
68+
res += query(L, R, l, m, k << 1);
69+
if (R > m) //如果右子树和需要查询的区间交集非空,注意这里不是else if,因为查询区间可能同时和左右区间都有交集
70+
res += query(L, R, m + 1, r, k << 1 | 1);
71+
72+
return res; //返回当前结点得到的信息
73+
}
74+
}
75+
76+
public:
77+
NumArray(vector<int>& nums) {
78+
int nSize = nums.size();
79+
if (nSize == 0) return;
80+
raw = nums;
81+
raw.insert(raw.begin(), -99999); //相当于移动下标
82+
memset(t, 0, (100002 << 2) * sizeof(int));
83+
memset(lazy, 0, (100002 << 2) * sizeof(int));
84+
85+
rIndex = nums.size();
86+
this->build(1, 1, rIndex);
87+
}
88+
89+
void update(int i, int val) {
90+
int old = this->query(i + 1, i + 1, 1, rIndex, 1);
91+
this->update(i + 1, i + 1, val - old, 1, rIndex, 1);
92+
}
93+
94+
int sumRange(int i, int j) {
95+
return this->query(i + 1, j + 1, 1, rIndex, 1);
96+
}
97+
};
98+
399
//40ms, 91.86%
4100
//分段求和, 伪线段树
5-
101+
/*
6102
class NumArray {
7103
private:
8104
vector<int> sums;
@@ -66,6 +162,7 @@ class NumArray {
66162
else return -99999; //dump
67163
}
68164
};
165+
*/
69166

70167
/*
71168
//224ms, 24.73%

cpp/leetcode/327. count-of-range-sum.cpp

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,117 @@
11
#include "public.h"
22

3-
//TLE
4-
//暴力O(n^2)
3+
//68ms, 13.42%
4+
//离散线段树
55

66
class Solution {
7+
private:
8+
//离散化, 求某个区间内的数字的个数, update和query同时进行
9+
map<long long, int> gblum; //离散化用:转换
10+
long long t[50005 << 2]; //t为线段树,t的大小是a的四倍, 用来防止下标溢出RE, 线段树区间记录此区间的值数量
11+
long long startV; //用于build, 线段树的起始值, 端点的
12+
int rightLoc; //数据总量
13+
14+
void Pushup(int k) { //更新函数,这里是实现最大值 ,同理可以变成,最小值,区间和等
15+
t[k] = t[k << 1] + t[k << 1 | 1];
16+
}
17+
18+
//递归方式建树 build(1,1,n);
19+
//此函数仅在main调用一次, 线段树的结构在pushup过程中不变
20+
void build(int k, int l, int r) { //k为当前需要建立的结点,l为当前需要建立区间的左端点,r则为右端点
21+
if (l == r) //左端点等于右端点,即为叶子节点,直接赋值即可
22+
t[k] = startV;
23+
else {
24+
int m = l + ((r - l) >> 1); //m则为中间点,左儿子的结点区间为[l,m],右儿子的结点区间为[m+1,r]
25+
build(k << 1, l, m); //递归构造左儿子结点
26+
build(k << 1 | 1, m + 1, r); //递归构造右儿子结点
27+
Pushup(k); //更新父节点
28+
}
29+
}
30+
31+
//递归更新区间 updata(P,1,n,1);, 实际上此函数变成了单点更新:), 单点值+1
32+
void update(int P, int l, int r, int k) { //[L,R]即为要更新的区间,l,r为结点区间,k为结点下标
33+
if (P <= l && r <= P) { //如果当前结点的区间真包含于要更新的区间内
34+
t[k] += 1; //这个数加一个:)
35+
}
36+
else {
37+
int m = l + ((r - l) >> 1);
38+
if (P <= m) //如果左子树和需要更新的区间交集非空
39+
update(P, l, m, k << 1);
40+
if (m < P) //如果右子树和需要更新的区间交集非空
41+
update(P, m + 1, r, k << 1 | 1);
42+
Pushup(k); //更新父节点
43+
}
44+
}
45+
46+
//递归方式区间查询 query(L,R,1,n,1);
47+
//查找[L,R]的区间和
48+
int query(int L, int R, int l, int r, int k) { //[L,R]即为要查询的区间,l,r为结点区间,k为结点下标
49+
if (L <= l && r <= R) //如果当前结点的区间真包含于要查询的区间内,则返回结点信息且不需要往下递归
50+
return t[k];
51+
else {
52+
//Pushdown(k); //每次都需要更新子树的Lazy标记, 用不到这个
53+
int res = 0; //返回值变量,根据具体线段树查询的什么而自定义
54+
int m = l + ((r - l) >> 1); //m则为中间点,左儿子的结点区间为[l,m],右儿子的结点区间为[m+1,r]
55+
if (L <= m) //如果左子树和需要查询的区间交集非空
56+
res += query(L, R, l, m, k << 1);
57+
if (R > m) //如果右子树和需要查询的区间交集非空,注意这里不是else if,因为查询区间可能同时和左右区间都有交集
58+
res += query(L, R, m + 1, r, k << 1 | 1);
59+
60+
return res; //返回当前结点得到的信息
61+
}
62+
}
763
public:
864
int countRangeSum(vector<int>& nums, int lower, int upper) {
9-
vector<int> sums(nums.size() + 1, 0);
65+
if (nums.empty()) return 0;
1066

11-
int preSum = 0;
12-
for (int index = 0; index < nums.size(); ++index)
13-
{
14-
preSum += nums[index];
15-
sums[index + 1] = preSum;
67+
//全局变量初始化
68+
gblum.clear();
69+
memset(t, 0, (50005 << 2) * sizeof(long long));
70+
startV = 0;
71+
72+
long long preSum = 0;
73+
//计算离散map, 以及数据量总数
74+
set<long long> us;
75+
us.insert(0);
76+
for (auto& n : nums) {
77+
preSum += n;
78+
us.insert(preSum);
79+
}
80+
int index = 0;
81+
for (auto& iterus : us) {
82+
gblum[iterus] = ++index;
1683
}
84+
rightLoc = index;
85+
86+
//建树
87+
this->build(1, 1, rightLoc);
1788

18-
int res = 0;
89+
//搞起来:)
90+
this->update(gblum.at(0), 1, rightLoc, 1);
91+
int ret = 0;
92+
preSum = 0;
93+
for (auto& n : nums) {
94+
preSum += (long long)n;
1995

20-
for (int st = 0; st < nums.size(); ++st)
21-
{
22-
for (int en = st + 1; en <= nums.size(); ++en)
23-
{
24-
if (((sums[en] - sums[st]) <= upper) && ((sums[en] - sums[st]) >= lower))
25-
res++;
96+
//包括n 以及至少一个前面的
97+
//long long realLow = (long long)preSum - (long long)upper;
98+
//long long realHi = (long long)preSum - (long long)lower;
99+
100+
auto loit = gblum.lower_bound(preSum - upper);
101+
auto hiit = gblum.upper_bound(preSum - lower);
102+
if (loit != gblum.end() && hiit != gblum.begin()) {
103+
int lowBoundV = loit->first;
104+
hiit--;
105+
int highBoundV = hiit->first;
106+
int preRet = this->query(loit->second, hiit->second, 1, rightLoc, 1);
107+
ret += preRet;
26108
}
109+
else { //不可能找到值了!
110+
;
111+
}
112+
this->update(gblum.at(preSum), 1, rightLoc, 1);
27113
}
28-
return res;
114+
return ret;
29115
}
30116
};
31117

@@ -117,7 +203,13 @@ int main()
117203
{
118204
Solution* s = new Solution();
119205
vector<int> nums = {-2,5,-1};
120-
cout << s->countRangeSum(nums, -2, 2);
206+
cout << s->countRangeSum(nums, -2, 2) << endl; //3
207+
vector<int> nums2 = { 0, -3, -3, 1, 1, 2 };
208+
cout << s->countRangeSum(nums2, 3, 5) << endl; //2
209+
vector<int> nums3 = { -2147483647, 0, -2147483647, 2147483647 };
210+
cout << s->countRangeSum(nums3, -564, 3864) << endl; //3
211+
vector<int> nums4 = { 2147483647,2147483647,0,-2147483647 };
212+
cout << s->countRangeSum(nums4, 4232, 7660) << endl; //2
121213
return 0;
122214
}
123215
*/

cpp/leetcode/493. reverse-pairs.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,10 @@ class Solution {
124124
}
125125
};
126126

127+
/*
127128
int main() {
128129
Solution* s = new Solution();
129130
vector<int> v = {2147483647,2147483647,2147483647,2147483647,2147483647,2147483647};
130131
cout << s->reversePairs(v) << endl;
131132
}
133+
*/
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#include "BinaryTree.h"
2+
#include "listnode.h"
3+
4+
//Graham 扫描
5+
//翻译至leetcode官方题解的JAVA版本的Graham方法
6+
//
7+
8+
class Solution {
9+
private:
10+
//这个函数有 3 个参数,分别是当前凸包上的点 p,下一个会加到凸包里的点 q,其他点空间内的任何一个点 r。如果 q 点相对于 r 点来说在点 p 的逆时针方向上的话,这个函数返回一个负值。
11+
int orientation(const vector<int>& p, const vector<int>& q, const vector<int>& r) {
12+
return (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
13+
}
14+
15+
//求p和q的距离平方
16+
int distance(const vector<int>& p, const vector<int>& q) {
17+
return (p[0] - q[0]) * (p[0] - q[0]) + (p[1] - q[1]) * (p[1] - q[1]);
18+
}
19+
20+
vector<int> bottomLeft(const vector<vector<int>> points) {
21+
int stY = points[0][1];
22+
int stX = points[0][0];
23+
int stIndex = 0;
24+
for (int index = 1; index < points.size(); ++index) {
25+
if (points[index][1] < stY) {
26+
stY = points[index][1];
27+
stX = points[index][0];
28+
stIndex = index;
29+
}
30+
else if (points[index][1] == stY) {
31+
if (points[index][0] < stX) {
32+
stY = points[index][1];
33+
stX = points[index][0];
34+
stIndex = index;
35+
}
36+
}
37+
}
38+
return points[stIndex];
39+
}
40+
41+
public:
42+
vector<vector<int>> outerTrees(vector<vector<int>>& points) {
43+
if (points.size() <= 1) return points;
44+
vector<int> bL = this->bottomLeft(points);
45+
sort(points.begin(), points.end(), [this, &bL](vector<int> p, vector<int> q)
46+
{
47+
int diff = this->orientation(bL, p, q) - this->orientation(bL, q, p);
48+
if (diff == 0) {
49+
return (this->distance(bL, p) - this->distance(bL, q)) > 0;
50+
}
51+
else {
52+
return diff > 0 ? true : false;
53+
}
54+
}
55+
);
56+
57+
int i = points.size() - 1;
58+
while (i >= 0 && orientation(bL, points[points.size() - 1], points[i]) == 0)
59+
i--;
60+
for (int l = i + 1, h = points.size() - 1; l < h; l++, h--) {
61+
vector<int> temp = points[l];
62+
points[l] = points[h];
63+
points[h] = temp;
64+
}
65+
66+
vector<vector<int>> st;
67+
st.push_back(points[0]);
68+
st.push_back(points[1]);
69+
for (int j = 2; j < points.size(); j++) {
70+
vector<int> top = st.back();
71+
st.pop_back();
72+
while (orientation(st.back(), top, points[j]) > 0) {
73+
top = st.back();
74+
st.pop_back();
75+
}
76+
st.push_back(top);
77+
st.push_back(points[j]);
78+
}
79+
80+
return st;
81+
}
82+
};
83+
84+
int main() {
85+
Solution* s = new Solution();
86+
vector<vector<int>> points1 = { {1, 1},{2, 2 }, {2, 0}, {2, 4}, { 3, 3}, {4, 2} };
87+
auto ret = s->outerTrees(points1);
88+
89+
return 0;
90+
}

cpp/leetcode/leetcode.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@
419419
<ClCompile Include="5264. find-elements-in-a-contaminated-binary-tree.cpp" />
420420
<ClCompile Include="5265. greatest-sum-divisible-by-three.cpp" />
421421
<ClCompile Include="5266. minimum-moves-to-move-a-box-to-their-target-location.cpp" />
422+
<ClCompile Include="587. erect-the-fence.cpp" />
422423
<ClCompile Include="摩尔投票法升级229. majority-element-ii.cpp" />
423424
<ClCompile Include="230. kth-smallest-element-in-a-bst.cpp" />
424425
<ClCompile Include="231. power-of-two.cpp" />

cpp/leetcode/leetcode.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,5 +1184,8 @@
11841184
<ClCompile Include="493. reverse-pairs.cpp">
11851185
<Filter>源文件\HardAlg\线段树/sqrt%28n%29算法</Filter>
11861186
</ClCompile>
1187+
<ClCompile Include="587. erect-the-fence.cpp">
1188+
<Filter>源文件</Filter>
1189+
</ClCompile>
11871190
</ItemGroup>
11881191
</Project>

0 commit comments

Comments
 (0)