【Leetcode】离散化与具体实现(c++)


前言

本文介绍对离散化的理解与具体c++编程实现,给出Leetcode中例题【1331.数组序号转换】、【1854.人口最多的年份】解题思路与编程实现。一起学习!一起进步!


一、离散化

如果有一组数据数量很少但跨度很大(类比稀疏矩阵),可以考虑将其映射为从1开始的连续数据,这样取用某个数时可根据映射后的结果直接得到,比如将-10000000,0,3,9999999999,88888888888888 映射为1,2,3,4。可以理解为下标就是其映射的值。如下图所示,如果我们对下标-100000000的位置进行操作,如加上某个数或减掉某个数,或者是求某个区间和,可以找到其离散后的值,即下标,使得操作过程简化。
在这里插入图片描述

离散化的关键问题

  • 稀疏数组中会存在重复元素
    解决去重问题借助C++中vector容器,先排序再去重
//arr数据类型为vector<int>
sort(arr.begin(),arr.end());
arr.erase(unique(arr.begin(),arr.end()),arr.end());

这样下标就是每个数离散化的结果,因为升序排列,所以保持数据原来的有序性。

  • 如何计算某个数据离散后的值
    解决第一个问题需要进行去重操作,解决第二个问题采用二分法。我们对已经不包含重复元素的数组进行查找,本质就是找到x在数组中对应的下标二分查找某个元素下标的模板如下
int binary(vecotr<int>&arr, int x, int length)
{
	int l = 0 ;int r = length-1 ;
	while(l<r)
	{
		int mid = (l+r)/2 ;
		if(arr[mid]>=x) r = mid ;
		else l = mid+1 ;
	}
	return l+1 ; //这样保证下标从1开始
}

二、离散化应用

【leetcode】1331. 数组序号转换

在这里插入图片描述

解题思路

  • 题目让我们给整数数组中的数据编号并且编号要呈现出升序排列,很明显要用离散化来解题,但我们最后要按照数组原有的数据排列顺序返回其下标,而数组排列与去重会改变数组的数据,因此要定义临时变量保存数组中数据,再进行去重操作。
  • 通过二分法查找下标,注意题目要求从1开始编号,也就是查找到的下标要进行加1操作

程序实现

class Solution {
public:

    int find(vector<int>& arr, int x)
    {
        int l = 0, r = arr.size()-1 ;
        while(l<r)
        {
            int mid = (l+r)/2;
            if(arr[mid]>=x) r = mid ;
            else l = mid+1 ;
        }
        return l+1 ;
    }
    vector<int> arrayRankTransform(vector<int>& arr) {
        //建立一个temp数组保存原有arr
        vector<int>temp ;
        for(int i=0 ;i<arr.size();i++)
        {
            temp.push_back(arr[i]);
        }
        //典型离散化过程,先排序再去重
        //最后通过二分查找
        sort(arr.begin(),arr.end());
        arr.erase(unique(arr.begin(),arr.end()),arr.end());
        vector<int>res ;
        for(int i=0 ;i<temp.size();i++)
        {
            res.push_back(this->find(arr,temp[i]));
        }
        return res ;

    }
};

运行结果

在这里插入图片描述

【Leetcode】1854. 人口最多的年份

在这里插入图片描述
首先声明本题更高效的做法是利用差分!这里采用离散化的思想,以深入学习离散化为主。

解题思路

  • 找到最小年份与最大年份,最小年份离散化后为0,最大年份离散化后是两者差值
  • 循环遍历统计每个人存存活的时间范围,维护一个person数组,数组表示该年份对应活着的人数
  • 对person遍历,找到数组中最大值的最小下标
  • 将最小下标映射回具体年份即可

程序实现

class Solution {
public:
    int maximumPopulation(vector<vector<int>>& logs) {
        //首先对年份离散化
        int max_year = 1950;
        int min_year = 2050 ;
        for(int i=0 ;i<logs.size();i++)
        {
            max_year = max(max_year,logs[i][1]);
            min_year = min(min_year,logs[i][0]) ;
        }
        vector<int>person(max_year - min_year , 0) ;
        for(int i=0 ;i<logs.size();i++)
        {
            int j = logs[i][0] - min_year ;
            int n = logs[i][1] - logs[i][0] ;
            for(int k=0 ;k<n;k++)
            {
                person[j]++ ;
                j++ ;
            }
        }
        //寻找person数组中最大数对应的最小下标
        int max_person = 0;
        int res = 0 ;
        for(int i=0 ;i<(max_year - min_year);i++)
        {
            if(person[i]>max_person)
            {
                max_person = person[i];
                res = i ;
            }
        }
        return res+min_year;
    }
};

运行结果

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值