2. 离散化

离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。

概述

离散化本质上可以看成是一种哈希,是程序设计中一个常用的技巧,它可以有效的降低时间复杂度。其基本思想就是在众多可能的情况中,只考虑需要用的值。离散化可以改进一个低效的算法,甚至实现根本不可能实现的算法。

通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:
原数据:1,999,100000,15;处理后:1,3,4,2;
原数据:{100,200},{20,50000},{1,400};
处理后:{3,4},{2,6},{1,5};

实现

C++ 离散化有现成的 STL 算法:

// 思路:先排序,再删除重复元素,最后就是索引元素离散化后对应的值
// a[i] 为初始数组,下标范围为 [1, n]
// len 为离散化后数组的有效长度
std::sort(a + 1, a + 1 + n);

len = std::unique(a + 1, a + n + 1) - a - 1;
// 离散化整个数组的同时求出离散化后本质不同数的个数。

// 在完成上述离散化之后可以使用 std::lower_bound 函数查找离散化之后的排名(即新编号):
std::lower_bound(a + 1, a + len + 1, x) - a;  // 查询 x 离散化后对应的编号

Java 自实现版本

import java.util.Arrays;
import java.util.SortedSet;
import java.util.TreeSet;

public class Discretization {
    public static int lowerBound(int[] arr,int target){ //找到第一个大于等于x的数的位置
        int l=0;
        int r=arr.length;
        while (l<r){
            int mid=l+(r-l)/2;
            if(arr[mid]>=target){
                r=mid;
            }else{
                l=mid+1;
            }
        }
        return l==arr.length?-1:l;
    }

    public static int[] solve(int[] array){
        SortedSet<Integer> set=new TreeSet<Integer>();
        //利用TreeSet可以同时实现排序和去重 可以代替c++中的unique实现
        for(int i=0;i<array.length;++i){
            set.add(array[i]);
        }

        int[] b=new int[set.size()]; //将去重排序的数组赋值给b数组
        int ct=0;
        for(int cur:set){
            b[ct++]=cur;
        }

        for(int i=0;i<array.length;++i){
            array[i]=lowerBound(b,array[i])+1; //利用lowerBound找到该数值的排位(rank)
            //排名代表大小 越前越小 越后越大
        }
        //10000000,2,2,123123213离散化成2,1,1,3
        return array;
    }
    public static void main(String[] args) {
        int[] a={10000000,2,2,123123213};
        System.out.println(Arrays.toString(solve(a)));
    }
}

实战

Leetcode 剑指 Offer 51. 数组中的逆序对

题解

使用了树状数组+离散化

import java.util.HashMap;
import java.util.SortedSet;
import java.util.TreeSet;

class Solution {
    int[] t = new int[50002];

    public int lowBit(int x) {
        return x & -x;
    }

    public int query(int i) {
        int ans = 0;
        for (--i; i > 0; i -= lowBit(i) ) {
            ans += t[i];
        }
        return ans;
    }

    public void update(int i, int x) {
        for (; i < t.length; i += lowBit(i)) {
            t[i] += x;
        }
    }

    public int reversePairs(int[] nums) {
        SortedSet<Integer> set = new TreeSet<>();
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            set.add(nums[i]);
        }

        int i = set.size() + 1;
        for(int x : set) {
            map.put(x, i);
            i--;
        }

        int ans = 0;
        for (i = 0; i < nums.length; i++) {
            int hi = map.get(nums[i]);
            ans += query(hi);
            update(hi, 1);
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值