算法基础之离散化&区间合并-c++&python

1.离散化:

离散化的本质,是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量。

题目:区间和

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

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

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

输入格式

第一行包含两个整数 n 和 m。

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

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

输出格式

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

数据范围

−1e9≤x≤1e9,
1≤n,m≤1e5,
−1e9≤l≤r≤1e9,
−10000≤c≤10000

输入样例:

3 3
1 2
3 6
7 5
1 3
4 6
7 8

输出样例:

8
0
5

解题思路:

1.读输入。将每次读入的x c push_back()到add中,将每次读入的位置x push_back()到alls中,将每次读入的l r push_back()到query中。

     cin>>n>>m;
    for(int i=0;i     {
        int x,c;
        cin>>x>>c;
        add.push_back({x,c});
        alls.push_back(x);
    }
    for(int i=0;i     {
        int l,r;
        cin>>l>>r;
        query.push_back({l,r});
        alls.push_back(l);
        alls.push_back(r);
    }


2.排序、去重。 

    //去重
    //对all数组中的元素进行排序并删除重复元素
    sort(alls.begin(),alls.end());
    //unique函数将alls数组中不重复的元素放在前面,重复的元素放到后面,并返回第一个重复元素的地址
    alls.erase(unique(alls.begin(),alls.end()),alls.end());


3.通过遍历add,完成在离散化的数组映射到的a数组中进行加上c的操作(用到find函数)。

     for(auto item : add)
    {
        int x=find(item.first);
        a[x]+=item.second;
    }

int find(int x)//利用二分方法查找x在alls中的下标+1
{
    int l=0,r=alls.size()-1;
    while(l     {
        int mid=l+r>>1;
        if(alls[mid]>=x) r=mid;
        else l=mid+1;
    }
    return r+1;//为方便利用前缀和返回r+1
}


4.初始化s数组(前缀和)

    for(int i=1;i<=alls.size();i++)

            s[i]=s[i-1]+a[i];


5.通过遍历query,完成求区间[l,r]的和。

    for(auto item : query)
    {
        int l=find(item.first),r=find(item.second);
        cout<     }

完整代码

C++:

#include
#include
#include

using namespace std;

typedef pairPII;
vectoralls;
vectoradd,query;

const int N=3e5+10;

int a[N],s[N];

int m,n;
int find(int x)//利用二分方法查找x在alls中的下标+1
{
    int l=0,r=alls.size()-1;
    while(l>1;
        if(alls[mid]>=x) r=mid;
        else l=mid+1;
    }
    return r+1;//为方便利用前缀和返回r+1
}
int main()
{
    cin>>n>>m;
    for(int i=0;i>x>>c;
        add.push_back({x,c});
        alls.push_back(x);
    }
    for(int i=0;i>l>>r;
        query.push_back({l,r});
        alls.push_back(l);
        alls.push_back(r);
    }
    //去重
    //对all数组中的元素进行排序并删除重复元素
    sort(alls.begin(),alls.end());
    //unique函数将alls数组中不重复的元素放在前面,重复的元素放到后面,并返回第一个重复元素的地址
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    //插入
    for(auto item : add)
    {
        int x=find(item.first);
        a[x]+=item.second;
    }
    //前缀和
    for(int i=1;i<=alls.size();i++)  s[i]=s[i-1]+a[i];
    for(auto item : query)
    {
        int l=find(item.first),r=find(item.second);
        cout<

python:
 

N = 300010 #n + 2m
alls = list()
a = [0] * N
s = [0] * N
add = [[0] * 2 for i in range(N)]
query = [[0] * 2 for i in range(N)]
size = 0 #统计alls中的坐标个数

def quickSort(a, l, r):
    if(l >= r):
        return
    x, i, j = a[l + r >> 1], l - 1, r + 1
    while(i < j):
        while(True):
            i += 1
            if(a[i] >= x): break
        while(True):
            j -= 1
            if(a[j] <= x): break
        if(i < j):
            tmp = a[i]
            a[i] = a[j]
            a[j] = tmp
    quickSort(a, l, j)
    quickSort(a, j + 1, r)

def unique(a):
    global size
    i, j = 0, 0
    while(i < size):
        if(i == 0 or a[i] != a[i - 1]):
            a[j] = a[i]
            j += 1
        i += 1
    size = j

def find(x):
    global alls
    l, r = 0, size - 1
    while(l < r):
        mid = l + r >> 1
        if(alls[mid] >= x): r = mid
        else: l = mid + 1
    return r + 1

def main():
    global alls, a, s, add, query, size
    n, m = list(map(int, input().split()))
    oldn, oldm = n, m
    i = 0
    while(oldn):
        x, c = list(map(int, input().split()))
        alls.append(x)
        add[i][0] = x
        add[i][1] = c
        i += 1
        oldn -= 1

    i = 0
    while(oldm):
        l, r = list(map(int, input().split()))
        alls.append(l)
        alls.append(r)
        query[i][0] = l
        query[i][1] = r
        i += 1
        oldm -= 1
    size = len(alls)
    #排序 和 去重
    quickSort(alls, 0, size - 1)
    unique(alls)
    alls = alls[:size]

    for i in range(n):
        x = add[i][0]
        c = add[i][1]
        index = find(x)
        a[index] += c

    for i in range(size):
        s[i + 1] = s[i] + a[i + 1]

    for i in range(m):
        l = find(query[i][0]);
        r = find(query[i][1]);
        print(s[r] - s[l - 1])
main()

2.区间合并:

题目:区间合并

给定 n 个区间 [li,ri],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。

例如[1,3] 和 [2,6]可以合并为一个区间 [1,6]。

输入格式

第一行包含整数 n。

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

输出格式

共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围

1≤n≤100000,
−1e9≤li≤ri≤1e9

输入样例:

5
1 2
2 4
5 6
7 8
7 9

输出样例:

3

解题思路:

1:先排序。依照左端点从小到大排序,若左端点同 则按照右端点从小到大排序
2:不断 更新 st 和 ed :现有区间的左右端点
   若最新枚举到的 小区间 属于现有大区间, 则st不会改变 只需要更新 ed
   若最新枚举到的 小区间 不属于现有大区间,则res++ , 同时更新 st 和 ed为最新区间的左右端点

所以本题:

首先按照左端点排序;
逐个遍历所有区间,判断当前区间能不能接到前一个区间里面:
2.1 如果没有交集,那么就将上一个区间记录到答案中,然后将当前区间作为新的区间范围。
2.2 如果有交集,能够接到上一个区间中,那么就更新区间的范围 —— 判断右端点是否需要更新。

C++:

#include 
#include 
#include 
#include 

using namespace std;

typedef pair PII;

int n;

void merge(vector &segs)
{
    vector res;

    // 1. 首先按照左端点排序;
    sort(segs.begin(), segs.end());

    // 2. 然后遍历所有区间:
    int st = -2e9, ed = -2e9;
    for (auto seg : segs)
    {
        // 2.1 如果没有交集,那么就将上一个区间记录到答案中,然后将当前区间作为新的区间范围;
        if (ed < seg.first)
        {
            if (st != -2e9) res.push_back({st, ed});
            st = seg.first, ed = seg.second;
        }
        // 2.2 如果有交集,能够接到上一个区间中,那么就更新区间的范围。
        else
            ed = max(ed, seg.second);
    }

    // 3. 需要将最后一个区间也加到答案中去。
    if (st != -2e9)
        res.push_back({st, ed});

    segs = res;
}

int main()
{
    cin >> n;
    vector segs;

    for (int i = 0; i < n; i ++ )
    {
        int l, r;
        cin >> l >> r;
        segs.push_back({l, r});
    }

    merge(segs);

    cout << segs.size() << endl;

    return 0;
}

 python:

N = int(input())
qujian_list = []
for i in range(N):
    qujian_list.append(list(map(int, input().split())))


def diagnose(list_1, list_2):  # list根据区间左端点排序
    if list_1[-1] < list_2[0]:
        return 'not inter'
    if list_1[-1] >= list_2[-1]:
        return 'contained'
    if list_1[-1] >= list_2[0]:
        return 'inter'

qujian_list.sort()
new_list = qujian_list[0]
res = 1
for i in qujian_list[1:]:
    if diagnose(new_list, i) == 'not inter':
        res += 1
        new_list = i
    if diagnose(new_list, i) == 'contain':
        pass
    if diagnose(new_list, i) == 'inter':
        new_list = [new_list[0], i[-1]]

print(res)

你可能感兴趣的:(算法,c++,python,蓝桥杯)