2021-11-18每日刷题打卡
力扣——每日一题
563. 二叉树的坡度
给定一个二叉树,计算 整个树 的坡度 。
一个树的 节点的坡度 定义即为,该节点左子树的节点之和和右子树节点之和的 差的绝对值 。如果没有左子树的话,左子树的节点之和为 0 ;没有右子树的话也是一样。空结点的坡度是 0 。
整个树 的坡度就是其所有节点的坡度之和。
示例 1:
输入:root = [1,2,3]
输出:1
解释:
节点 2 的坡度:|0-0| = 0(没有子节点)
节点 3 的坡度:|0-0| = 0(没有子节点)
节点 1 的坡度:|2-3| = 1(左子树就是左子节点,所以和是 2 ;右子树就是右子节点,所以和是 3 )
坡度总和:0 + 0 + 1 = 1
准备一个全局变量ans来计算坡度总和,递归遍历二叉树,先把根节点送去遍历,每次递归一开始先判断节点是否为空,如果为空,直接返回0,(递归函数的返回值是树整体的val值和,比如上面这图的2节点,它整个树的val和就是2+3+5),然后把当前节点的左子树和右子树送去递归,返回值分别用num_l和num_r接收,然后把他俩的差值的绝对值加到ans上,这就是这个节点的坡度了,然后把当前节点的val和num_l与nums_r的总和返回。当所有递归结束后,返回ans即可。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int ans=0;
int findTilt(TreeNode* root) {
dfs(root);
return ans;
}
int dfs(TreeNode*root)
{
if(!root)return 0;
int val_num=root->val;
int val_l=dfs(root->left);
int val_r=dfs(root->right);
ans+=abs(val_l-val_r);
return val_r+val_l+val_num;
}
};
802. 区间和 - AcWing题库
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含两个整数 x 和 c。
再接下来 m 行,每行包含两个整数 l 和 r。
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
−109≤x≤109
1≤n,m≤10^5
−109≤l≤r≤109
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
离散化就这么说,题目虽然说了无限长的数轴,但实际用到的只有几个点而已,比如有一条数轴,上面有10w个点,但我只在1 20 5000 10000上加上1,其它点还是0,那么我们只要算这四个点就行,反正其它点是0,我们就把这四个点重新排,第1个点是1,第二个点是20,第三个点是5000,第四个点是10000,那么当题目问我们区间和时,我们只要看区间之间有没有我们这几个点就行,比如计算5~10000的和,那就是20和5000和10000上的值加起来就行。
#include<iostream>
using namespace std;
typedef pair<int,int> PII;
#include<vector>
#include<algorithm>
const int N=300010;
int a[N],s[N];
vector<int>alls;
vector<PII>adds,range;
int find(int x)
{
int l=0,r=alls.size()-1;
while(l<r)
{
int mid=l+r>>1;
if(alls[mid]>=x)r=mid;
else l=mid+1;
}
return r+1;
}
int main()
{
int l,r,n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
int x,c;
cin>>x>>c;
adds.push_back({x,c});
alls.push_back(x);
}
for(int i=0;i<m;i++)
{
cin>>l>>r;
range.push_back({l,r});
alls.push_back(l);
alls.push_back(r);
}
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
for(auto i:adds)
{
int x=find(i.first);
a[x]+=i.second;
}
for(int i=1;i<=alls.size();i++)s[i]=s[i-1]+a[i];
for(auto i:range)
{
l=find(i.first),r=find(i.second);
cout<<s[r]-s[l-1]<<endl;
}
return 0;
}
803. 区间合并 - AcWing题库
给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:[1,3]和 [2,6] 可以合并为一个区间 [1,6]。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含两个整数 l 和 r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
1≤n≤100000
−109≤li≤ri≤109
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3
区间合并就是把多个区间合并成一个区间,但必须是有交集的才能合并,比如【1,3】和【2,6】这种才能合并,或者【1,3】和【3,4】这类,即第一个区间的尾部在第二个区间的范围里,如果没交集则没法合并。
我们把每个区间设置成键值对的情况然后存入vector中,然后我们根据区间的左端点进行排序,从小到大,然后遍历vector,判断当前区间的右端点在不在下一个区间的范围里,如果在说明有交集,把这两个区间合并,如果不在范围里则不合并,最后输出vector容器的size(即有多少区间)。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
typedef pair<int,int> PII;
const int N=100010;
int n,l,r;
vector<PII>segs;
void merge(vector<PII>&segs)
{
vector<PII>res;
sort(segs.begin(),segs.end());
int st=-2e9,ed=-2e9;
for(auto i:segs)
{
if(ed<i.first)
{
if(st!=-2e9)res.push_back({st,ed});
st=i.first,ed=i.second;
}
else ed=max(ed,i.second);
}
if(st!=-2e9)res.push_back({st,ed});
segs=res;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>l>>r;
segs.push_back({l,r});
}
merge(segs);
cout<<segs.size()<<endl;
return 0;
}