精华内容
下载资源
问答
  • C++比较四个数字的最大

    千次阅读 2019-07-10 16:01:20
    #include<iostream> #include<cstring> using namespace std; int q_max(int x,int y,int z,int h){ x=x>y?x:y; x=x>z?x:z; x=x>h?x:h; return x; } int main(){ //找出4...

    #include<iostream>
    #include<cstring>
    using namespace std;

    int q_max(int x,int y,int z,int h){
        x=x>y?x:y;
        x=x>z?x:z;
        x=x>h?x:h;
        return x;
    }

    int main(){
        //找出4个数中的最大值 
        int x,y,z,h;
        cin >>x>>y>>z>>h;
        int M_max=q_max(x,y,z,h);
        cout <<M_max;
        
        return 0;
    }

    展开全文
  •  Python——无序数组找出和为N的两个(三个四个数) 【问题描述】无序数组找出和为N的两个,例如,nums = [1, 4, 3, 2, 6, 5]找出和为target = 6的序列,答案:[(1, 5), (4, 2)]。 参考博客: 1、...

     

            Python——无序数组中找出和为N的两个数(三个数、四个数)

    【问题描述】无序数组中找出和为N的两个数,例如,nums = [1, 4, 3, 2, 6, 5]中找出和为target = 6的序列,答案:[(1, 5), (4, 2)]。

    参考博客:

    1、一个无序数组中两个数之和等于给定的值sum

    2、Python算法题----在列表中找到和为s的两个数字

    输入:

    nums = [1, 4, 3, 2, 6, 5]

    target = 6

    输出 :

    [(1, 5), (4, 2)]

     

    方法一:暴力——穷举法(O(N^2))

           思想:嵌套循环,外层循环遍历全部列表,内层循环遍历当前元素位置之后的所有元素。内层循环中将两个数字相加,等于target,保存当前结果。需要注意的是同一个元素不能重复使用!

    # 暴力解法——穷举
    def getRes_Enumeration(arr, value):
        len1 = len(arr)
        res = []
        for i in range(len1):
            for j in range(i + 1, len1):
                if arr[i] + arr[j] == value:
                    res.append((arr[i], arr[j]))
        return res
    
    if __name__ == "__main__":
        nums = [int(i) for i in input().split()]
        target = int(input())
        print(getRes_Enumeration(nums, target))

    运行结果:

    小结:这个思想确实简单,很容易想到,可能不具有挑战性!毕竟时间复杂度为O(N^2),那有没有更好的方法呢?答案是肯定的,比如O(NlogN)与O(N)。

     

    方法二:双指针——快速排序思想,O(NlogN)

            思想:来自于快速排序,在一个有序的数组(从小到大)中最左边一定是最小值,最右边是最大值。我们可将最小值与最大值相加与目标值进行比较,如果两数之和大于目标值,我们就让最大值小一点(读取第二个最大值),如果两数之和小于目标值,我们就让最小值大一点(读取第二个最小值),如果两数之和刚好等于目标值,保存最大值,最小值,并且让最大值小一点,最小值大一点。需要注意的是前提条件是数组必须有序!!!

            简化:nums先排序,然后定义两个指针,一个low = 0指向数组头,一个high = len(nums) - 1指向数组的尾,看其和nums[low]+nums[high]是否== target;若==,则查找成功返回;若>sum,则尾指针high--;若<sum,则头指针low++。

             时间复杂度:快排O(NlogN),查找O(N);所以总的时间复杂度为:O(NlogN)。

    # 快速排序思想
    def getRes_QuickSort(nums, target):
        nums = sorted(nums)
        len1 = len(nums)
        res = []
        if len1>= 2:
            low, high = 0, len1-1
            while low < high:
                if nums[low] + nums[high] == target:
                    res.append((nums[low], nums[high]))
                    low += 1
                    high -= 1
                elif nums[low] + nums[high] > target:
                    high -= 1
                else:
                    low += 1
            return res
    
    if __name__ == "__main__":
        nums = [int(i) for i in input().split()]
        target = int(input())
        print(getRes_QuickSort(nums, target))

    运行结果:

           细心的朋友这里会发现,诶,最后的输出结果顺序不对啊,因为我们是对排序后的数组进行查找的,如果想要返回原来的,还需进一步改进。

           需要注意的是,这里的排序算法选择的是时间复杂度为O(NlogN)的,加上查找所花时间O(N),最终为O(NlogN)。肯定有人会想,那我为啥不选择时间复杂度为O(N)的排序算法(如:非比较排序的基数排序、计数排序或桶排序)先排序,再查找呢?这样结果就是O(N)了,效率岂不是更高,哎呀,你真的很聪明!!!但是接下面的方法,并不是这样做的,而是利用哈希表来完成!

     

    方法三:哈希表思想求解,O(N)

            思想:给定一个数,根据hash表查找另一个数只需要O(1)的时间。但需要空间换时间,空间复杂度为O(n);可以用hashMap实现,hashMap<a[i], 次数>。遍历一遍数组,若次数没有存在hashMap中,则将其加入,次数为1;再遍历一遍数组,对每个值nums[i],判断target - nums[i]是否在hashmap中【即对应的value是否==1】;若存在,则查找成功;否则继续遍历下一个。直到遍历完整个数组。

    # 哈希表思想
    def getRes_HashMap(nums, target):
        result = []
        for i, value in enumerate(nums):
            if (target - value) in nums[i+1:]:
                result.append((value, target - value))
        return result
    
    if __name__ == "__main__":
        nums = [int(i) for i in input().split()]
        target = int(input())
        print(getRes_HashMap(nums, target))

    运行结果:

     

    变式:给定一个无序数组,求

    (1)三个数或四个数,甚至N个数之和等于target;

    (2)两个数之差等于target;

    这些都可以采取上面三种方法中的思想进行求解,但是,如果作为面试,后面两种才是面试官想要看到的解法!!!

     

    练习一:剑指offer——和为S的两个数

    输入描述:

            输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

    输出描述:

            对应每个测试案例,输出两个数,小的先输出。

    例如:

    输入(假设无序):

             1 4 3 2 6 5

             6

    输出:[1,5]

    输入:

              1 3 4 6 7 8

               45

    输出:

               []

    # -*- coding:utf-8 -*-
    class Solution:
        def FindNumbersWithSum(self, array, tsum):
            # write code here
            # array = sorted(array)
            len1 = len(array)
            res = []
            myres = []
            if len1>= 2:
                low, high = 0, len1-1
                while low < high:
                    if array[low] + array[high] == tsum:
                        res.append([array[low], array[high]])
                        low += 1
                        high -= 1
                    elif array[low] + array[high] > tsum:
                        high -= 1
                    else:
                        low += 1
                # 求最小的一组数
                lentmp = len(res)
                if lentmp >= 1:
                    tmp = []
                    for i in range(lentmp):
                        tmp.append(res[i][0]*res[i][1])
                    index = tmp.index(min(tmp))
                    myres = res[index]
            return myres

    或者精简版本:

    # -*- coding:utf-8 -*-
    class Solution:
        def FindNumbersWithSum(self, array, tsum):
            # write code here
            res = []
            len1, minM = len(array), 10000000
            if len1 < 2: return res
            for i, value in enumerate(array):
                if (tsum - value) in array[i+1:]:
                    if value*(tsum - value)<minM:
                        minM = value*(tsum - value)
                        res = [value, tsum - value]
            return res

     

    练习二:leetcode中的3sum

    方法一:快速排序的思想,与2sum差不多,就是多了一个外层循环,注意left与right的初始值就行了。Python代码如下:

    def Sum3(arr, target):
        arr.sort()
        len1 = len(arr)
        res = []
        if len1<=2: print(res)
        for i in range(len1 - 1):
            left, right = i + 1, len1 - 1 # 以下思路与2sum中的快速排序思想一样
            while left < right:
                sum = arr[i] + arr[left] + arr[right]
                if sum == target and [arr[i], arr[left], arr[right]] not in res:
                    res.append([arr[i], arr[left], arr[right]])
                    left += 1
                    right -= 1
                elif sum < target:
                    left += 1
                else:
                    right -= 1
        print(res)
    
    if __name__ == '__main__':
        arr = [int(i) for i in input().split()]
        target = int(input())
        Sum3(arr, target)

    运行结果为:

    方法二:哈希表的思想求解

    def Sum3(arr, targe):# 3sum问题
        # arr.sort()
        # arr = list(set(arr))
        res = []
        for i, value1 in enumerate(arr):
            for j, value2 in enumerate(arr[i+1:]):
                if (target - value1 - value2) in arr[i+2:]:
                    minV = min(value1, value2, target - value1 - value2)
                    maxV = max(value1, value2, target - value1 - value2)
                    midV = target - minV - maxV
                    res.append((minV, midV, maxV))
        print(list(set(res)))
    
    if __name__ == '__main__':
        arr = [int(i) for i in input().split()]
        target = int(input())
        Sum3(arr, target)

    运行结果:

     

    练习三:leetcode中的4sum

    解决思路与前面的很相似,还是用两种方法:

    方法一:快速排序思想(先排序 + 双指针)

    def Sum4(arr, target):
        arr.sort()
        len1 = len(arr)
        res = []
        if len1<=3:
            print(res)
    
        for i in range(len1 - 2):
            for j in range(i + 1, len1):
                ss = target - arr[i] - arr[j]
                left, right = j + 1, len1 - 1
                while left<right:
                    sum = arr[left] + arr[right]
                    if sum == ss and [arr[i], arr[j], arr[left], arr[right]] not in res:
                        res.append([arr[i], arr[j], arr[left], arr[right]])
                        left += 1
                        right -= 1
                    elif sum < ss:
                        left += 1
                    else:
                        right -= 1
        print(res)
    
    if __name__ == '__main__':
        arr = [int(i) for i in input().split()]
        target = int(input())
        Sum4(arr, target)

    运行结果:

    方法二:哈希表的思想求解

    # 4sum问题
    def Sum4(arr, target):
        res = []
        for i, value1 in enumerate(arr):
            for j, value2 in enumerate(arr[i + 1:]):
                for k, value3 in enumerate(arr[i + 2:]):
                    if (target - value1 - value2 - value3) in arr[i+3:]:
                        tmp = [value1, value2, value3 ,target - value1 - value2 - value3]
                        tmp.sort()
                        res.append(tuple(tmp))
        res = list(set(res))
        print(res)
    
    if __name__ == '__main__':
        arr = [int(i) for i in input().split()]
        target = int(input())
        Sum4(arr, target)

    运行结果:

     

    展开全文
  •  先拿10000个数建堆,然后一次添加剩余元素,如果大于堆顶的(10000最小的),将这个数替换堆顶,并调整结构使之仍然是一最小堆,这样,遍历完后,堆的10000个数就是所需的最大的10000。建堆

            前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望能完成最后一面,各方面原因造成我无比想去鹅场的心已经按捺不住了),这个问题还是建立最小堆比较好一些。

            先拿10000个数建堆,然后一次添加剩余元素,如果大于堆顶的数(10000中最小的),将这个数替换堆顶,并调整结构使之仍然是一个最小堆,这样,遍历完后,堆中的10000个数就是所需的最大的10000个。建堆时间复杂度是O(mlogm),算法的时间复杂度为O(nmlogm)(n为10亿,m为10000)。

            优化的方法:可以把所有10亿个数据分组存放,比如分别放在1000个文件中。这样处理就可以分别在每个文件的10^6个数据中找出最大的10000个数,合并到一起在再找出最终的结果。

            以上就是面试时简单提到的内容,下面整理一下这方面的问题:

    top K问题

            在大规模数据处理中,经常会遇到的一类问题:在海量数据中找出出现频率最好的前k个数,或者从海量数据中找出最大的前k个数,这类问题通常被称为top K问题。例如,在搜索引擎中,统计搜索最热门的10个查询词;在歌曲库中统计下载最高的前10首歌等。

            针对top K类问题,通常比较好的方案是分治+Trie树/hash+小顶堆(就是上面提到的最小堆),即先将数据集按照Hash方法分解成多个小数据集,然后使用Trie树活着Hash统计每个小数据集中的query词频,之后用小顶堆求出每个数据集中出现频率最高的前K个数,最后在所有top K中求出最终的top K。

    eg:有1亿个浮点数,如果找出期中最大的10000个?

            最容易想到的方法是将数据全部排序,然后在排序后的集合中进行查找,最快的排序算法的时间复杂度一般为O(nlogn),如快速排序。但是在32位的机器上,每个float类型占4个字节,1亿个浮点数就要占用400MB的存储空间,对于一些可用内存小于400M的计算机而言,很显然是不能一次将全部数据读入内存进行排序的。其实即使内存能够满足要求(我机器内存都是8GB),该方法也并不高效,因为题目的目的是寻找出最大的10000个数即可,而排序却是将所有的元素都排序了,做了很多的无用功。

            第二种方法为局部淘汰法,该方法与排序方法类似,用一个容器保存前10000个数,然后将剩余的所有数字——与容器内的最小数字相比,如果所有后续的元素都比容器内的10000个数还小,那么容器内这个10000个数就是最大10000个数。如果某一后续元素比容器内最小数字大,则删掉容器内最小元素,并将该元素插入容器,最后遍历完这1亿个数,得到的结果容器中保存的数即为最终结果了。此时的时间复杂度为O(n+m^2),其中m为容器的大小,即10000。

            第三种方法是分治法,将1亿个数据分成100份,每份100万个数据,找到每份数据中最大的10000个,最后在剩下的100*10000个数据里面找出最大的10000个。如果100万数据选择足够理想,那么可以过滤掉1亿数据里面99%的数据。100万个数据里面查找最大的10000个数据的方法如下:用快速排序的方法,将数据分为2堆,如果大的那堆个数N大于10000个,继续对大堆快速排序一次分成2堆,如果大的那堆个数N大于10000个,继续对大堆快速排序一次分成2堆,如果大堆个数N小于10000个,就在小的那堆里面快速排序一次,找第10000-n大的数字;递归以上过程,就可以找到第1w大的数。参考上面的找出第1w大数字,就可以类似的方法找到前10000大数字了。此种方法需要每次的内存空间为10^6*4=4MB,一共需要101次这样的比较。

            第四种方法是Hash法。如果这1亿个书里面有很多重复的数,先通过Hash法,把这1亿个数字去重复,这样如果重复率很高的话,会减少很大的内存用量,从而缩小运算空间,然后通过分治法或最小堆法查找最大的10000个数。

            第五种方法采用最小堆。首先读入前10000个数来创建大小为10000的最小堆,建堆的时间复杂度为O(mlogm)(m为数组的大小即为10000),然后遍历后续的数字,并于堆顶(最小)数字进行比较。如果比最小的数小,则继续读取后续数字;如果比堆顶数字大,则替换堆顶元素并重新调整堆为最小堆。整个过程直至1亿个数全部遍历完为止。然后按照中序遍历的方式输出当前堆中的所有10000个数字。该算法的时间复杂度为O(nmlogm),空间复杂度是10000(常数)。

    实际运行:

            实际上,最优的解决方案应该是最符合实际设计需求的方案,在时间应用中,可能有足够大的内存,那么直接将数据扔到内存中一次性处理即可,也可能机器有多个核,这样可以采用多线程处理整个数据集。

           下面针对不容的应用场景,分析了适合相应应用场景的解决方案。

    (1)单机+单核+足够大内存

            如果需要查找10亿个查询次(每个占8B)中出现频率最高的10个,考虑到每个查询词占8B,则10亿个查询次所需的内存大约是10^9 * 8B=8GB内存。如果有这么大内存,直接在内存中对查询次进行排序,顺序遍历找出10个出现频率最大的即可。这种方法简单快速,使用。然后,也可以先用HashMap求出每个词出现的频率,然后求出频率最大的10个词。

    (2)单机+多核+足够大内存

            这时可以直接在内存总使用Hash方法将数据划分成n个partition,每个partition交给一个线程处理,线程的处理逻辑同(1)类似,最后一个线程将结果归并。

            该方法存在一个瓶颈会明显影响效率,即数据倾斜。每个线程的处理速度可能不同,快的线程需要等待慢的线程,最终的处理速度取决于慢的线程。而针对此问题,解决的方法是,将数据划分成c×n个partition(c>1),每个线程处理完当前partition后主动取下一个partition继续处理,知道所有数据处理完毕,最后由一个线程进行归并。

    (3)单机+单核+受限内存

            这种情况下,需要将原数据文件切割成一个一个小文件,如次啊用hash(x)%M,将原文件中的数据切割成M小文件,如果小文件仍大于内存大小,继续采用Hash的方法对数据文件进行分割,知道每个小文件小于内存大小,这样每个文件可放到内存中处理。采用(1)的方法依次处理每个小文件。

    (4)多机+受限内存

            这种情况,为了合理利用多台机器的资源,可将数据分发到多台机器上,每台机器采用(3)中的策略解决本地的数据。可采用hash+socket方法进行数据分发。


            从实际应用的角度考虑,(1)(2)(3)(4)方案并不可行,因为在大规模数据处理环境下,作业效率并不是首要考虑的问题,算法的扩展性和容错性才是首要考虑的。算法应该具有良好的扩展性,以便数据量进一步加大(随着业务的发展,数据量加大是必然的)时,在不修改算法框架的前提下,可达到近似的线性比;算法应该具有容错性,即当前某个文件处理失败后,能自动将其交给另外一个线程继续处理,而不是从头开始处理。

            top K问题很适合采用MapReduce框架解决,用户只需编写一个Map函数和两个Reduce 函数,然后提交到Hadoop(采用Mapchain和Reducechain)上即可解决该问题。具体而言,就是首先根据数据值或者把数据hash(MD5)后的值按照范围划分到不同的机器上,最好可以让数据划分后一次读入内存,这样不同的机器负责处理不同的数值范围,实际上就是Map。得到结果后,各个机器只需拿出各自出现次数最多的前N个数据,然后汇总,选出所有的数据中出现次数最多的前N个数据,这实际上就是Reduce过程。对于Map函数,采用Hash算法,将Hash值相同的数据交给同一个Reduce task;对于第一个Reduce函数,采用HashMap统计出每个词出现的频率,对于第二个Reduce 函数,统计所有Reduce task,输出数据中的top K即可。

            直接将数据均分到不同的机器上进行处理是无法得到正确的结果的。因为一个数据可能被均分到不同的机器上,而另一个则可能完全聚集到一个机器上,同时还可能存在具有相同数目的数据。


    以下是一些经常被提及的该类问题。

    (1)有10000000个记录,这些查询串的重复度比较高,如果除去重复后,不超过3000000个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。请统计最热门的10个查询串,要求使用的内存不能超过1GB。

    (2)有10个文件,每个文件1GB,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。按照query的频度排序。

    (3)有一个1GB大小的文件,里面的每一行是一个词,词的大小不超过16个字节,内存限制大小是1MB。返回频数最高的100个词。

    (4)提取某日访问网站次数最多的那个IP。

    (5)10亿个整数找出重复次数最多的100个整数。

    (6)搜索的输入信息是一个字符串,统计300万条输入信息中最热门的前10条,每次输入的一个字符串为不超过255B,内存使用只有1GB。

    (7)有1000万个身份证号以及他们对应的数据,身份证号可能重复,找出出现次数最多的身份证号。


    重复问题

            在海量数据中查找出重复出现的元素或者去除重复出现的元素也是常考的问题。针对此类问题,一般可以通过位图法实现。例如,已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。

            本题最好的解决方法是通过使用位图法来实现。8位整数可以表示的最大十进制数值为99999999。如果每个数字对应于位图中一个bit位,那么存储8位整数大约需要99MB。因为1B=8bit,所以99Mbit折合成内存为99/8=12.375MB的内存,即可以只用12.375MB的内存表示所有的8位数电话号码的内容。

    展开全文
  • 如何在1亿个数中找出最大的100个数(top K问题) ​ 最容易想到的方法是将数据全部排序,然后在排序后的集合进行查找,最快的排序算法的时间复杂度一般为O(nlogn),如快速排序。但是在32位的机器上,每float...

    如何在1亿个数中找出最大的100个数(top K问题)

    ​ 最容易想到的方法是将数据全部排序,然后在排序后的集合中进行查找,最快的排序算法的时间复杂度一般为O(nlogn),如快速排序。但是在32位的机器上,每个float类型占4个字节,1亿个浮点数就要占用400MB的存储空间,对于一些可用内存小于400M的计算机而言,很显然是不能一次将全部数据读入内存进行排序的。其实即使内存能够满足要求(我机器内存都是8GB),该方法也并不高效,因为题目的目的是寻找出最大的10000个数即可,而排序却是将所有的元素都排序了,做了很多的无用功。

    ​ 第二种方法为局部淘汰法,该方法与排序方法类似,用一个容器保存前10000个数,然后将剩余的所有数字——与容器内的最小数字相比,如果所有后续的元素都比容器内的10000个数还小,那么容器内这个10000个数就是最大10000个数。如果某一后续元素比容器内最小数字大,则删掉容器内最小元素,并将该元素插入容器,最后遍历完这1亿个数,得到的结果容器中保存的数即为最终结果了。此时的时间复杂度为O(n+m^2),其中m为容器的大小,即10000。

    ​ 第三种方法是分治法,将1亿个数据分成100份,每份100万个数据,找到每份数据中最大的10000个,最后在剩下的10010000个数据里面找出最大的10000个。如果100万数据选择足够理想,那么可以过滤掉1亿数据里面99%的数据。100万个数据里面查找最大的10000个数据的方法如下:用快速排序的方法,将数据分为2堆,如果大的那堆个数N大于10000个,继续对大堆快速排序一次分成2堆,如果大的那堆个数N大于10000个,继续对大堆快速排序一次分成2堆,如果大堆个数N小于10000个,就在小的那堆里面快速排序一次,找第10000-n大的数字;递归以上过程,就可以找到第1w大的数。参考上面的找出第1w大数字,就可以类似的方法找到前10000大数字了。此种方法需要每次的内存空间为10^64=4MB,一共需要101次这样的比较。*

    ​ 第四种方法是Hash法。如果这1亿个书里面有很多重复的数,先通过Hash法,把这1亿个数字去重复,这样如果重复率很高的话,会减少很大的内存用量,从而缩小运算空间,然后通过分治法或最小堆法查找最大的10000个数。

    ​ 第五种方法采用最小堆。首先读入前10000个数来创建大小为10000的最小堆,建堆的时间复杂度为O(mlogm)(m为数组的大小即为10000),然后遍历后续的数字,并于堆顶(最小)数字进行比较。如果比最小的数小,则继续读取后续数字;如果比堆顶数字大,则替换堆顶元素并重新调整堆为最小堆。整个过程直至1亿个数全部遍历完为止。然后按照中序遍历的方式输出当前堆中的所有10000个数字。该算法的时间复杂度为O(nmlogm),空间复杂度是10000(常数)。

    实际运行:

    ​ 实际上,最优的解决方案应该是最符合实际设计需求的方案,在时间应用中,可能有足够大的内存,那么直接将数据扔到内存中一次性处理即可,也可能机器有多个核,这样可以采用多线程处理整个数据集。

    ​ 下面针对不容的应用场景,分析了适合相应应用场景的解决方案。

    (1)单机+单核+足够大内存
    ​ 如果需要查找10亿个查询次(每个占8B)中出现频率最高的10个,考虑到每个查询词占8B,则10亿个查询次所需的内存大约是10^9 * 8B=8GB内存。如果有这么大内存,直接在内存中对查询次进行排序,顺序遍历找出10个出现频率最大的即可。这种方法简单快速,使用。然后,也可以先用HashMap求出每个词出现的频率,然后求出频率最大的10个词。

    (2)单机+多核+足够大内存
    ​ 这时可以直接在内存总使用Hash方法将数据划分成n个partition,每个partition交给一个线程处理,线程的处理逻辑同(1)类似,最后一个线程将结果归并。

    ​ 该方法存在一个瓶颈会明显影响效率,即数据倾斜。每个线程的处理速度可能不同,快的线程需要等待慢的线程,最终的处理速度取决于慢的线程。而针对此问题,解决的方法是,将数据划分成c×n个partition(c>1),每个线程处理完当前partition后主动取下一个partition继续处理,知道所有数据处理完毕,最后由一个线程进行归并。

    (3)单机+单核+受限内存
    ​ 这种情况下,需要将原数据文件切割成一个一个小文件,如次啊用hash(x)%M,将原文件中的数据切割成M小文件,如果小文件仍大于内存大小,继续采用Hash的方法对数据文件进行分割,知道每个小文件小于内存大小,这样每个文件可放到内存中处理。采用(1)的方法依次处理每个小文件。

    (4)多机+受限内存
    ​ 这种情况,为了合理利用多台机器的资源,可将数据分发到多台机器上,每台机器采用(3)中的策略解决本地的数据。可采用hash+socket方法进行数据分发。

    ​ 从实际应用的角度考虑,(1)(2)(3)(4)方案并不可行,因为在大规模数据处理环境下,作业效率并不是首要考虑的问题,算法的扩展性和容错性才是首要考虑的。算法应该具有良好的扩展性,以便数据量进一步加大(随着业务的发展,数据量加大是必然的)时,在不修改算法框架的前提下,可达到近似的线性比;算法应该具有容错性,即当前某个文件处理失败后,能自动将其交给另外一个线程继续处理,而不是从头开始处理。

    ​ top K问题很适合采用MapReduce框架解决,用户只需编写一个Map函数和两个Reduce 函数,然后提交到Hadoop(采用Mapchain和Reducechain)上即可解决该问题。具体而言,就是首先根据数据值或者把数据hash(MD5)后的值按照范围划分到不同的机器上,最好可以让数据划分后一次读入内存,这样不同的机器负责处理不同的数值范围,实际上就是Map。得到结果后,各个机器只需拿出各自出现次数最多的前N个数据,然后汇总,选出所有的数据中出现次数最多的前N个数据,这实际上就是Reduce过程。对于Map函数,采用Hash算法,将Hash值相同的数据交给同一个Reduce task;对于第一个Reduce函数,采用HashMap统计出每个词出现的频率,对于第二个Reduce 函数,统计所有Reduce task,输出数据中的top K即可。

    ​ 直接将数据均分到不同的机器上进行处理是无法得到正确的结果的。因为一个数据可能被均分到不同的机器上,而另一个则可能完全聚集到一个机器上,同时还可能存在具有相同数目的数据。

    以下是一些经常被提及的该类问题。

    (1)有10000000个记录,这些查询串的重复度比较高,如果除去重复后,不超过3000000个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。请统计最热门的10个查询串,要求使用的内存不能超过1GB。

    (2)有10个文件,每个文件1GB,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。按照query的频度排序。

    (3)有一个1GB大小的文件,里面的每一行是一个词,词的大小不超过16个字节,内存限制大小是1MB。返回频数最高的100个词。

    (4)提取某日访问网站次数最多的那个IP。

    (5)10亿个整数找出重复次数最多的100个整数。

    (6)搜索的输入信息是一个字符串,统计300万条输入信息中最热门的前10条,每次输入的一个字符串为不超过255B,内存使用只有1GB。

    (7)有1000万个身份证号以及他们对应的数据,身份证号可能重复,找出出现次数最多的身份证号。

    重复问题
    ​ 在海量数据中查找出重复出现的元素或者去除重复出现的元素也是常考的问题。针对此类问题,一般可以通过位图法实现。例如,已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。

    ​ 本题最好的解决方法是通过使用位图法来实现。8位整数可以表示的最大十进制数值为99999999。如果每个数字对应于位图中一个bit位,那么存储8位整数大约需要99MB。因为1B=8bit,所以99Mbit折合成内存为99/8=12.375MB的内存,即可以只用12.375MB的内存表示所有的8位数电话号码的内容。

    算法一:冒泡排序法

    千里之行,始于足下。我们先不说最好,甚至不说好。我们只问,如何“从10000个整数中找出最大的10个”?我最先想到的是用冒泡排序的办法:我们从头到尾走10趟,自然会把最大的10个数找到。方法简单,就不再这里写代码了。这个算法的复杂度是10N(N=10000)。

    算法二:

    有没有更好一点的算法呢?当然。维持一个长度为10的降序数组,每一个从数组拿到的数字都与这个降序数组的最小值比较。如果小于最小值,就舍弃;如果大于最小值,就把它插入到降序数组中的合适位置,舍弃原来的最小值。这样,遍历一遍就可以找到最大的10个数。因为需要在降序数组中插入一个数,对于遍历的每个数可能都需要这样,所以其复杂为5N。

    伪代码如下:

      A[N],a[m](分别为原始数组和降序数组,其中N=10000,m=10)
    
      a = A[0 ... 9](将数组A的前10个数赋给数组a)
    
      sort a(将组数a降序排序)
    
      for i in A[ 10 ... N](从10到N遍历数组A)
    
        if A[i] > a[9] then (如果当前值比降序数组中的最小值大)
    
          删除a[9]
    
          将A[i]插入a的合适位置,使a保持降序
    
        end if
    
      end for
    
      输出数组a
    
    

    其实算法二还有一个优点,就是当数组很大时,可以将数据分段读入内存处理,而这样做并不影响结果。

    1、首先一点,对于海量数据处理,思路基本上是确定的,必须分块处理,然后再合并起来。

    2、对于每一块必须找出10个最大的数,因为第一块中10个最大数中的最小的,可能比第二块中10最大数中的最大的还要大。

    3、分块处理,再合并。也就是Google MapReduce 的基本思想。Google有很多的服务器,每个服务器又有很多的CPU,因此,100亿个数分成100块,每个服务器处理一块,1亿个数分成100块,每个CPU处理一块。然后再从下往上合并。注意:分块的时候,要保证块与块之间独立,没有依赖关系,否则不能完全并行处理,线程之间要互斥。另外一点,分块处理过程中,不要有副作用,也就是不要修改原数据,否则下次计算结果就不一样了。

    4、上面讲了,对于海量数据,使用多个服务器,多个CPU可以并行,显著提高效率。对于单个服务器,单个CPU有没有意义呢?

    也有很大的意义。如果不分块,相当于对100亿个数字遍历,作比较。这中间存在大量的没有必要的比较。可以举个例子说明,全校高一有100个班,我想找出全校前10名的同学,很傻的办法就是,把高一100个班的同学成绩都取出来,作比较,这个比较数据量太大了。应该很容易想到,班里的第11名,不可能是全校的前10名。也就是说,不是班里的前10名,就不可能是全校的前10名。因此,只需要把每个班里的前10取出来,作比较就行了,这样比较的数据量就大大地减少了。

    之前看到一个面试题,1000个乱序正整数中找出10个最小值,要求高效快速,不能使用API。

    ​ 这学期学了些排序的方法,什么快速排序啊,冒泡啊,归并排序啊之类的。看到这个题的时候,第一反应是快速排序,因为它的名字叫快速嘛,应该够快吧。然后又想到这个题目不是要你完整的排序,只需要求出最小的10个就够了,那么冒泡法呢?冒泡法只冒前面10个数?

    ​ 发现这样子还是要遍历比较1000*10次。

    ​ 然后,利用类似于数据结构里的栈的特性?把这1000个数的前10个放到一个数组中,排好序,然后,剩下的990个数字,每个都与这10个数的最大数比较,大于则不考虑,小于就把最大值拿出来,把这个数放进去,这样的话,冒泡排序的比较次数就变成了990次,好像高效很多哦?

    展开全文
  • 方法一、先拿10000个数建堆,然后一次添加剩余元素,如果大于堆顶的(10000最小的),将这个数替换堆顶,并调整结构使之仍然是一最小堆,这样,遍历完后,堆的10000个数就是所需的最大的10000。...
  • 求N个数最大公约数和最小公倍数以及Hankson"逆问题"(python) 一、题目要求 1.基本要求: 求N个数最大公约数和最小公倍数。用C或C++或java或python语言实现程序解决问题 2.提高要求: 已知正整数a0,a1,b0,b1,...
  • 任意给一个位数(各位不完全相同), 各位上的可组成一个最大数和一个最小数, 它们的差又能组成一个最大数和一个最小数, 直到某一步得到的差将会出现循环重复。写一个程序统计所有满足以上条件的位数。 ...
  • 修改/etc/security /limits.conf 配置文件。 使用命令:sudo gedit /etc/security /limits.conf 在文件增加 * soft nofile 3000 ...* hard nofile 20000 ...hard 表示 最大不能超过后面的配置 nofile表示 我
  • 程序如下: #include<iostream> using namespace std; int main() { int max(int x,int y); //对max函数作声明 int a,b,c; cin>>a>>b; c=max(a,b); //调用max函数 ..."max=...
  • 先利用数组的sort方法对数组的进行排序(我在这里采用升序的方式(return b-a;就是实现数组的降序)),然后排序后的数组首尾肯定是最小值和最大值。var ary = [12,13,5,18,30,24]; ary.sort(function(a,b){ ...
  • 第三列,见列表,打开文件数是nofile 第列,数量,这也不能设置太大 # #Each line describes a limit for a user in the form: # #<domain> <type> <item> # #Where: #<domain> can be...
  • 寻找最大的K个数(TOP K算法)

    万次阅读 2012-08-07 16:03:42
    前言: ... 问题描述: 有很多无序的,怎么...这问题的很多可以是几个数也可以使成百上亿的,针对此问题我们有以下解法: 解法一: 咱们先简单的理解,要求一序列最小的k个数,按照惯有的思维方式,很简
  • 在文章的最后笔者提到了还有一些特殊情况比如说Docker,会导致MySQL的最大连接被限制在一值上。今天笔者就要来讲一下为什么在Docker环境会出现这问题。这次的问题也是在公司实习的时候碰到的。当时导师要...
  • 题目:求两正整数的最大公约数和最小公倍数。 基本要求:1.程序风格良好(使用自定义注释模板),两种以上算法解决最大公约数问题,提供友好的输入输出。 提高要求:1.三种以上算法解决两正整数最大公约数问题。...
  • 单机最大tcp连接

    万次阅读 2016-09-01 15:13:24
    那么对单机,其最大并发tcp连接数是多少? 如何标识一TCP连接 在确定最大连接数之前,先来看看系统如何标识一tcp连接。系统用一4四元组来唯一标识一TCP连接:{local ip, local port,remote ip,remote
  • 在数学,辗转相除法,又称欧几里得算法,是求最大公约数的算法...辗转相除法基于如下原理:两整数的最大公约数等于其中较小的和两的相除余数的最大公约数。例如,252和105的最大公约数是21(252 = 21 × 12;10
  • 先拿10000个数建堆,然后一次添加剩余元素,如果大于堆顶的(10000最小的),将这个数替换堆顶,并调整结构使之仍然是一最小堆,这样,遍历完后,堆的10000个数就是所需的最大的10000。建堆...
  •  RDD在Spark【Scala语言】,是一种数据结构【基于内存,可持久化】,就好比Java的ArrayList一样,可以进行各种的Action操作,比如Java的List集合,可以进行get【获取元素】、add【增加元素】、remove【移除元素...
  • 以下数据结构,()是非线性数据结构A:树(二叉树) B:字符串 C:队列 D:栈 E:线性表 F:二维数组 G:多维数组数据的逻辑结构分为线性结构和非线性结构。 常用的线性结构有:线性表,栈,队列,双队列,...
  • 详解Linux服务器Tcp最大连接

    千次阅读 2017-12-15 11:19:13
    那么对单机,其最大并发tcp连接数是多少? 如何标识一TCP连接 在确定最大连接数之前,先来看看系统如何标识一tcp连接。系统用一4四元组来唯一标识一TCP连接:{local ip, local port,remote ip,remote ...
  • 看《鸟哥的Linux私房菜》的时候,说是partition table只能有四个分区,想知道为什么,以下参考自Wiki 第一个扇区 磁盘的第一个扇区(也可以叫做MBR,根据语境确定是第一个扇区还是主引导分区)记录了整块磁盘的...
  • 条件: 限制最大 100,最小0,最长两位小数 输入大于100,自动变为100. 超出,2位小数,自动舍五入 以下是使用全局指令的案例 (也可以使用局部指令,可以参考文档 ...
  • 例题:下列给定程序,函数fun的功能是:给定n实数,输出平均值,并统计在平均值以上(含平均值)的实数个数。 下列给定程序,函数fun的功能是:给定n实数,输出平均值,并统计在平均值以上(含平均值)的...
  • Oracle 9i默认的连接为150,有的时候我们需要调整这个最大链接,而这个链接的调整是在oacle下的dbs目录下init.ora文件调整的。  ORACLE的连接(sessions)与其参数文件的进程(process)有关,它们的...
  • 数据挖掘所需的概率论与数理统计知识

    万次阅读 多人点赞 2012-12-17 19:24:47
    导言:本文从微积分相关概念,梳理到概率论与数理统计的相关知识,但本文之压轴戏在本文第4节(彻底颠覆以前读书时大学课本灌输给你的观念,一探正态分布之神秘芳踪,知晓其前后发明历史由来),相信,每一学过...
  • 最近在接中间件Memcached的时候,总是会出现以下错误: [18-11-9 12:10:59:156 CST] 0000014b SystemOut O 2018-11-09 12:10:59 156 [ERROR][Heal-Session-Thread]...
  • Scrum敏捷开发流程主要包扩三个角色、四个会议和个三物件。 三个角色 Scrum团队包括三个角色,他们分别是产品负责人、开发团队和 项目的直接管理者(Scrum Master)。 Scrum 团队是自组织、跨职能的完整...
  • Linux 内核优化-调大TCP最大连接

    万次阅读 2017-10-19 19:03:20
    一、tcp 概述 1、服务器如何标识tcp连接...在确定最大连接之前,先来看看系统如何标识一tcp连接。系统用一4四元组来唯一标识一TCP连接:{local ip, local port,remote ip,remote port}。 (1)、client最大tcp
  • 多线程-线程池(队列-最大线程-核心线程)

    千次阅读 热门讨论 2020-01-10 16:08:11
    java 多线程: ...通过线程池主要是创建以下4种类型的线程池。 工具类 : Executors ExecutorService newFixedThreadPool() : 创建固定大小的线程池 ExecutorService newCachedThreadPool() : 缓存线...
  • 前几天去国内某二线互联网企业参加实习生面试,与面试官讨论Server上允许的最大TCP连接数是多少。我回答,由于资源限制或其他客观因素,一般保持3000-4000的连接就死掉了。面试官问我,如果不考虑这些因素,理论上的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 603,912
精华内容 241,564
关键字:

以下四个数中最大的是