• careercup-扩展性和存储限制10.3


    题目

    给你一个文件,里面包含40亿个整数,写一个算法找出该文件中不包含的一个整数, 假设你有1GB内存可用。

    如果你只有10MB的内存呢?

    解答

    我们先来做个算术题,40亿个整数大概有多大?

    40 * 10^8 * 4B = 16GB (大约值,因为不是按照2的幂来做单位换算)

    这个明显无法一次性装入内存中。但是,如果我们用计算机中的一位来表示某个数出现与否, 就可以减少内存使用量。比如在一块连续的内存区域,15出现,则将第15位置1。 这个就是Bit Map算法。关于这个算法,网上有篇文章写得挺通俗易懂的,推荐:

    http://blog.csdn.net/hguisu/article/details/7880288

    如果用Bit Map算法,一个整数用一位表示出现与否,需要的内存大小是:

    40 * 10^8 b = 5 * 10^8 B = 0.5GB

    而我们有1GB的内存,因此该算法可行。由于Bit Map只能处理非负数, (没有说在第-1位上置1的),因此对于有符号整数,可以将所有的数加上0x7FFFFFFF, 将数据移动到正半轴,找到一个满足条件的数再减去0x7FFFFFFF即可。 因此本文只考虑无符号整数,对于有负数的情况,按照上面的方法处理即可。

    我们遍历一遍文件,将出现的数对应的那一位置1,然后遍历这些位, 找到第一个有0的位即可,这一位对应的数没有出现。代码如下:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    int main(){
        // freopen("12.3.in", "w", stdout);
        // int miss = 12345;
        // for(int i=0; i<20000; ++i){
        //     if(i == miss) continue;
        //     cout<<i<<endl;
        // }
        // fclose(stdout);
    
        freopen("12.3.in", "r", stdin);
    
        int int_len = sizeof(int) * 8;
        int bit_len = 0xFFFFFFFF / int_len;
        int* bit = new int[bit_len];
        int v;
        while(scanf("%d", &v) != EOF){
            bit[v/int_len] |= 1<<(v%int_len);
        }
        bool found = false;
        for(int i=0; i<bit_len; ++i){
            for(int j=0; j<int_len; ++j){
                if((bit[i] & (1<<j)) == 0){
                    cout<<i*int_len + j<<endl;
                    found = true;
                    break;
                }
    
            }
            if(found) break;
        }
    
        delete[] bit;
        fclose(stdin);
        return 0;
    }

    而我们有1GB的内存,因此该算法可行。由于Bit Map只能处理非负数, (没有说在第-1位上置1的),因此对于有符号整数,可以将所有的数加上0x7FFFFFFF, 将数据移动到正半轴,找到一个满足条件的数再减去0x7FFFFFFF即可。 因此本文只考虑无符号整数,对于有负数的情况,按照上面的方法处理即可。

    接下来我们就可以用Bit Map算法了。我们再遍历一遍数据, 把落在这个块的数对应的位置1(我们要先把这个数归约到0到blocksize之间)。 最后我们找到这个块中第一个为0的位,其对应的数就是一个没有出现在该文件中的数。 代码如下:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    int main(){
        freopen("12.3.in", "r", stdin);// 20000 number
        int int_len = sizeof(int) * 8;
        int totalnum = 20000;
        int blocksize = 2000;
        int blocknum = totalnum / blocksize;
        int* block = new int[blocknum];
        int* bit = new int[blocksize/int_len+1];
        int v;
        while(scanf("%d", &v) != EOF){
            ++block[v/blocksize];
        }
        fclose(stdin);
        int start;
        for(int i=0; i<blocknum; ++i){
            if(block[i] < blocksize){
                start = i * blocksize;
                break;
            }
        }
        freopen("12.3.in", "r", stdin);
        while(scanf("%d", &v) != EOF){
            if(v>=start && v<start+blocksize){
                v -= start; // make v in [0, blocksize)
                bit[v/int_len] |= 1<<(v%int_len);
            }
        }
    
        bool found = false;
        for(int i=0; i<blocksize/int_len+1; ++i){
            for(int j=0; j<int_len; ++j){
                if((bit[i] & (1<<j)) == 0){
                    cout<<i*int_len+j+start<<endl;
                    found = true;
                    break;
                }
            }
            if(found) break;
        }
    
        delete[] block;
        delete[] bit;
        fclose(stdin);
        return 0;
    }
  • 相关阅读:
    前端工具Gulp的学习
    研究javascript中的this
    如何让引入ES6的html文件运行起来
    windows用命令方式查看文件内容
    windows中用'ls'命令查看项目目录
    一步步理解ajax
    【拥抱ES6】搭建一个ES6环境
    npm还是cnpm
    【聊一聊】css中的经典布局——圣杯布局
    【聊一聊】css中的经典布局——双飞翼布局
  • 原文地址:https://www.cnblogs.com/wuchanming/p/4449391.html
Copyright © 2020-2023  润新知