海量数据处理算法与面试题

那年仲夏 提交于 2021-02-06 04:56:26

九章微课 

 

1.最高频 K 项问题

前导问题:前k大数 

在一个整数数组中,找最大的k个数

 这个问题有在线和离线两种解法:

  1. 离线算法:允许多遍遍历数组。排序后找的方法时间复杂度O(nlogn),但是需要找O(n)的解法。答案就是使用快速选择算法,先一遍遍历找到第k大的数,然后再一遍遍历找到前k大的数,总复杂度为o(n)
  2. 在线算法:数据以数据流进入,只允许一遍遍历。
    public class topK {
        /**
         * @param nums: an integer array
         * @param k: An integer
         * @return: the top k largest numbers in array
         */
        public int[] topkOffline(int[] nums, int k) {
            // 1.离线算法:
            // 首先一遍遍历找到第K大的数:快速选择算法O(n)
            int kLargestNum = QuickSelect(nums, k, 0, nums.length - 1);
            int [] res = new int[k];
            int i = 0;
            for (Integer num : nums) {
                if (num >= kLargestNum && i < k) res[i++] = num;
            }
            return res;
        }
        public int[] topkOnline(int[] nums, int k) {
            // 2.在线算法:数据流形式进入,只允许一遍遍历: 使用最大堆
            Comparator<Integer> comparator = new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    if (o1 > o2) return -1;
                    else if (o1 < o2) return 1;
                    else return 0;
                }
            };
            PriorityQueue<Integer> pq = new PriorityQueue<>(k, comparator);
            for (Integer num : nums) {
                pq.add(num);
            }
            int[] res = new int[k];
            for (int i = 0; i < k; i++) res[i] = pq.poll();
            return res;
        }
        private int QuickSelect(int[] nums, int k, int start, int end) {
            if (k > nums.length || start > end) return -1;
            int pivot = end;
            int left = start;
            int right = end;
            while (left < right) {
                while (nums[left] <= pivot && left < right) left++;
                while (nums[right] >= pivot && left < right) right--;
                swap(nums, left, right);
            }
            swap(nums, left, pivot);
            
            if (k - 1 > left) QuickSelect(nums, k, left + 1, end);
            if (k - 1 < left) QuickSelect(nums, k, start, left - 1);
            return nums[left];
        }
        private void swap(int[] nums, int x, int y) {
            int tmp = nums[x];
            nums[x] = nums[y];
            nums[y] = tmp;
        }
        public static void main(String[] args) {
            topK tk = new topK();
            int [] nums = {6, 4, 10, 14, 3, 7, 2, 9};
            int[] res = tk.topkOnline(nums, 4);
            for (Integer num : res) System.out.println(num);
        }
    }
    View Code

    Top k Largest Numbers II

          实现一个数据结构,提供下面两个接口:add(number) 添加一个元素;topk() 返回前K大的数

          简单的很容易想到维护一个大顶堆。来一个数就add一个,然后返回topk。但这是很低效的算法。因为每次add操作的时间复杂度是O(logn),每次topk是O(klogn)。

          

public class topK2 {
    private int kSize;
    private PriorityQueue<Integer> pq;

    public topK2(int k) {
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                if (o1 < o2) return -1;
                else if (o1 > o2) return 1;
                else return 0;
            }
        };
        pq = new PriorityQueue<>(k, comparator);
        kSize = k;
    }

    public void add(int num) {
        if (pq.size() < kSize) {
            pq.add(num);
        }
        else if (pq.size() == kSize) {
            int minNum = pq.peek();
            if (num < minNum) return;
            else {
                pq.poll();
                pq.add(num);
            }
        }
    }

    public List<Integer> topk() {
        List<Integer> res = new ArrayList<>();
        Integer[] arr = new Integer[pq.size()];
        Integer[] arr1 = pq.toArray(arr);
        Arrays.sort(arr1, Collections.reverseOrder());
        res = Arrays.asList(arr1);
        return res;
    }

}
View Code

 

最高频k项问题:

 也分为离线算法和在线算法。

  1. 离线算法:hash+heap的方式来解决 
    public class Solution {
        /*
         * @param words: an array of string
         * @param k: An integer
         * @return: an array of string
         */
        public String[] topKFrequentWords(String[] words, int k) {
            // write your code here
            Map<String, Integer> map = new HashMap<>();
            for (String word : words) {
                if (!map.containsKey(word))
                    map.put(word, 1);
                else
                    map.put(word, map.get(word) + 1);
            }
            PriorityQueue<String> pq = new PriorityQueue<>( (a, b) -> map.get(a) == map.get(b) ? b.compareTo(a) : map.get(a) - map.get(b));
            for (String word : map.keySet()) {
                pq.add(word);
                if (pq.size() > k) pq.poll();
            }
            LinkedList<String> res = new LinkedList<>();
            while (!pq.isEmpty()) {
                res.addFirst(pq.poll());
            }
            String[] ret = new String[res.size()];
            ret = res.toArray(ret);
            return ret;
        }
    }
    View Code

     

  2. 在线算法:在实时数据流中找到最常使用的k个单词.
    实现TopK类中的三个方法:
    TopK(k), 构造方法
    add(word), 增加一个新单词
    topk(), 得到当前最常使用的k个单词.

 

2.布隆过滤器

3.外排序算法

4.概率类大数据问题

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!