算法通关村第十五关——超大规模数据场景青铜挑战笔记

此篇之前,我们所学习的普通数组、链表、Hash、树、字符串等结构递归、排序等思想,以及后面需要学习的滑动窗口、回溯、贪心、动态规划等思想在面对超大规模数据场景时表现差强人意亟需面对超大规模数据场景的解题思想,帮助我们以较小的代价快速解决该类问题。

总结三种经典解题思路:

方法一:使用位存储,例如:给定一个数组,其数据范围在1-32000,数据流远远不断到来,使用int类型的数组标记这些元素,需要32000个int块,所占用的内存大小就是128KB,但是如果使用最小单位Bit来标记这些元素,仅仅需要32000个Bit,所占用的内存大小就是4000B,也就是1000个int块。试想32000个int块和1000个int块熟大熟小呢?

方法二:使用外部排序,如果文件太大,无法在内存中放下,需要考虑将大文件分成若干小块,先处理每个块,然后再逐步得想要的结果。

方法三:使用堆结构,在超大数据流中找第K大、第K小、K个最大、K个最小,则特别适合使用堆来完成。

1.用4KB内存寻找重复元素

针对方法一进行练习,分析如何使用位存储。

题目描述:给定一个数组,其数据范围在1-32000,数据流远远不断到来,只使用4KB内存,寻找数据流中重复元素。

题目分析:使用int类型的数组标记这些元素,需要32000个int块,所占用的内存大小就是128KB,但是如果使用最小单位Bit来标记这些元素,仅仅需要32000个Bit,所占用的内存大小就是4000B<4096B=4KB,也就是1000个int块。另一个关键点在于,如何确定数据流中的元素应该存储在哪一个int块,以及int块中的哪一个Bit?答:使用两个变量wordNumber和bitNumber维护元素应放置在哪一个int块和哪一位Bit。具体而言,1-32存放在第一个int块,33-64存放在第二个int块依次....;1存放在第1个Bit,33存放在第1个Bit,34存放在第二个Bit,Bit的确定就是:元素&0x1F(也就是31)

存放:当元素确定存放位置后,该位置的比特为0,则可以存放,每次存放应使用“或”运算,不能修改其他已经存放元素的位置。

取出:当元素确定存放位置后,该位置的比特为1,则元素重复,输出重复元素即可!

厘清思路,直接上代码!

public class FindDuplicatesIn32000 {
    public static void main(String[] args) {
        int[] array = {0,1,4,6,6,7,8,6,4,2,1,6};
        checkDuplicates(array);
    }
    public static void checkDuplicates(int[] array) {
        BitSet bs = new BitSet(32000);
        for (int i = 0; i < array.length; i++) {
            int num = array[i];
            int num0 = num - 1;
            if (bs.get(num)) {
                System.out.println(num);
            } else {
                bs.set(num);
            }
        }
    }
    static class BitSet {
        int[] bitset;

        public BitSet(int size) {
            this.bitset = new int[size >> 5];
        }

        boolean get(int pos) {
            int wordNumber = (pos >> 5);//除以32
            int bitNumber = (pos & 0x1F);//除以32
            return (bitset[wordNumber] & (1 << bitNumber)) != 0;
        }

        void set(int pos) {
            //wordNumber值得是数据pos应该存放在int[1000]数组的哪一个int索引块内,
            // 比如int[0]可以存放0-31个数字
            // int[1]可以存放32-63个数字
            // 具体来说我先找到应该存放在哪一个int块中,然后在找存放在该int块中的哪一个bit
            int wordNumber = (pos >> 5);//除32,确定存放在哪一个块
            int bitNumber = (pos & 0x1F);//和31进行&操作,确定存放在块中哪一个bit里面   0x1F就是31
            bitset[wordNumber] |= 1 << bitNumber;//存放数据时,应该保留之前的数据
        }
    }
}

OK,《算法通关村第十五关——超大规模数据场景青铜挑战笔记》结束,喜欢的朋友三联加关注!关注鱼市带给你不一样的算法小感悟!(幻听)

再次,感谢鱼骨头教官的学习路线!鱼皮的宣传!小y的陪伴!ok,拜拜,第十五关第二幕见!

你可能感兴趣的:(算法,笔记)