ngrok快速使用

剑指 Offer 52. 两个链表的第一个公共节点--leetcode刷题之路

  返回  

离散hua....

2021/7/21 3:30:42 浏览:

假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。

现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。

接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。

输入格式
第一行包含两个整数 n 和 m。

接下来 n 行,每行包含两个整数 x 和 c。

再接下来 m 行,每行包含两个整数 l 和 r。

输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。

数据范围
−109≤x≤109,
1≤n,m≤105,
−109≤l≤r≤109,
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
观察数据范围

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;
typedef pair<int,int>PII;
map<int,int>mp;
int n,m,x,c,l,r;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>x>>c;
        if(mp.find(x)==mp.end())mp[x]=c;
        else mp[x]+=c;
    }
    int sum=0;
    vector<PII>v;
    for(auto a:mp){
        v.push_back({a.first,sum});
        sum+=a.second;
    }
    v.push_back({1e9+1,sum});
    while(m--){
        cin>>l>>r;
        auto p1=upper_bound(v.begin(),v.end(),PII{l,-1e9});
        auto p2=upper_bound(v.begin(),v.end(),PII{r,1e9+1});
        cout<<p2->second-p1->second<<endl;
    }
    
}

这里提供一种map + upper_bound()的解法
时间复杂度 O((n + m) * log n)
将各个出现过的x映射到map中
计算一下前缀和
upper_bound()查找l与r
C++ 代码
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

#define pii pair<int, int>
const int inf = 1e9 + 5;
vector<pii> a;
map<int, int> mp;

int main()
{
    int n, m;
    cin >> n >> m;
    while(n --)
    {
        int x, c;
        cin >> x >> c;
        if(mp.find(x) == mp.end()) mp[x] = c;  //x未出现过
        else mp[x] += c;  //x出现过
    }
    int sum = 0;
    for(pii x : mp)  //计算前缀和
    {
        a.push_back({x.first, sum});  //这里的sum不包含x.first上的值,方便使用upper_bound()
        sum += x.second;
    }
    a.push_back({inf, sum});  //最后加一个无穷大的点,方便处理
    //因为mp是有序的,所以a是有序的
    while(m --)
    {
        int l, r;
        cin >> l >> r;
        auto p1 = upper_bound(a.begin(), a.end(), (pii){l , -inf}); //找到第一个大于等于l的点
        auto p2 = upper_bound(a.begin(), a.end(), (pii){r , inf});  //找到第一个大于r的点
        cout << p2 -> second - p1 -> second << endl;
    }
    return 0;
}

作者:空空如也
链接:https://www.acwing.com/solution/content/12167/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

可以用TreeMap这个集合,完成去重、排序、二分查找,所以代码要少一些。
解释一下TreeMap:底层是红黑树实现的。可以简单理解为有序的HashMap。
getOrDefault(key, default): 获取key对应的value,如果没有key,则返回默认值default。
ceilingEntry(key): 返回大于等于key的Entry(二分)
lowerEntry(key): 返回小于key的Entry(二分),注意,如果没有key,会报空指针异常。

java 代码
import java.util.Scanner;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt(), m = in.nextInt();
        int[][] q = new int[m][2];
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for (int i = 0; i < n; i++) {
            int add1 = in.nextInt();
            int add2 = in.nextInt();
            map.put(add1, map.getOrDefault(add1, 0) + add2);
        }
        for (int i = 0; i < m; i++) {
            q[i][0] = in.nextInt();
            map.put(q[i][0], map.getOrDefault(q[i][0], 0));
            q[i][1] = in.nextInt();
            map.put(q[i][1], map.getOrDefault(q[i][1], 0));
        }
        Object[] keys = map.keySet().toArray();
        for (int i = 1; i < keys.length; i++) { // 前缀和
            map.put((Integer) keys[i], map.get(keys[i-1]) + map.get(keys[i]));
        }
        for (int i = 0; i < m; i++) {
            if(q[i][0] == (Integer)keys[0]){ // 避免空指针异常
                System.out.println(map.ceilingEntry(q[i][1]).getValue());
            }else{
                System.out.println(map.ceilingEntry(q[i][1]).getValue() -  map.lowerEntry(q[i][0]).getValue());
            }
        }
    }
}


作者:quinlandai@163.com
链接:https://www.acwing.com/solution/content/50620/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

#include<bits/stdc++.h>
using namespace std;
vector<int>xs;
typedef pair<int, int> PII;
vector<PII>op;
vector<PII>q;
int n,m,x,c,l,r;
int sum[100010];
int a[100010];
int get(int x){
    return lower_bound(xs.begin(),xs.end(),x)-xs.begin();
}
int find(int x){//找x对应的下标也就是第一个大于等于x的数字
    int l=0,r=xs.size()-1;
    while(l<r){
        int mid=l+r>>1;
        if(xs[mid]>=x)r=mid;
        else l=mid+1;
    }
    return r+1;
//这里为什么要加1呢
//原因是把1,20,300,4000,5万,60万映射到下标012345不好做前缀和操作
//干脆直接映射到下标123456,这样就用到了前缀和数组sum【0】=0
    
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>x>>c;
        op.push_back({x,c});
        xs.push_back(x);
    }
    for(int i=0;i<m;i++){
        cin>>l>>r;
        q.push_back({l,r});
        xs.push_back(l);
        xs.push_back(r);
    }
    sort(xs.begin(),xs.end());
    xs.erase(unique(xs.begin(),xs.end()),xs.end());
    
    for(int i=0;i<n;i++){
        int x=find(op[i].first);
        int c=op[i].second;
        a[x]+=c;
    }
    for(int i=1;i<=xs.size();i++){
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=0;i<m;i++){
        int l=q[i].first;
        int r=q[i].second;
        l=find(l);
        r=find(r);
        //cout<<"l="<<l<<" r="<<r<<endl;
        cout<<sum[r]-sum[l-1]<<endl;
    }
    
}

部分内容转载自https://blog.csdn.net/jsjwangxinleijsj/article/details/82020825

upper_bound():返回的是被查序列中第一个大于查找值得指针;

lower_bound():返回的是被查序列中第一个大于等于查找值的指针;

如下图所示:
一、lower_bound;

用法:int t=lower_bound(a+l,a+r,m)-a//由于返回的值为指针所以要用返回值减去a才能得到目标值的下标
解释:在升序排列的a数组内二分查找[l,r)区间内的值为m的元素。返回m在数组中的下标。
特殊情况:
1.如果m在区间中没有出现过,那么返回第一个比m大的数的下标。
2.如果m比所有区间内的数都大,那么返回r。这个时候会越界,小心。
3.如果区间内有多个相同的m,返回第一个m的下标。
二、upper_bound
用法:int t=upper_bound(a+l,a+r,m)-a
解释:在升序排列的a数组内二分查找[l,r)区间内的值为m的元素。返回m在数组中的下标+1。
特殊情况:
1.如果m在区间中没有出现过,那么返回第一个比m大的数的下标。
2.如果m比所有区间内的数都大,那么返回r。这个时候会越界,小心。
3.如果区间内有多个相同的m,返回最后一个m的下标+1。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int k,n=10;
int a[10]={1,1,1,3,3,5,5,5,5,6};
int main()
{
    for(int i=0;i<n;i++)cout<<a[i]<<" ";
    cout<<endl;
   while(scanf("%d",&k))
   {
       cout<<k<<"的第一个大于等于它的位置在"<<((lower_bound(a,a+n,k))-a)+1<<endl;
   }
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int k,n=10;
int a[10]={1,1,1,3,3,5,5,5,5,6};
int main()
{
    for(int i=0;i<n;i++)cout<<a[i]<<" ";
    cout<<endl;
   while(scanf("%d",&k))
   {
       cout<<k<<"的第一个大于它的位置在"<<((upper_bound(a,a+n,k))-a)+1<<endl;
   }
}

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号