zoukankan      html  css  js  c++  java
  • 海量数据处理算法与面试题

    九章微课 

    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.概率类大数据问题

  • 相关阅读:
    设计模式 里氏替换原则
    java队列
    java 多线程
    设计模式-里氏替换原则
    设计模式-单一职责原则
    一、概念
    六、序列化和反序列化(对象流)
    七、随机访问文件流
    五、包装流
    四、字符输入输出流
  • 原文地址:https://www.cnblogs.com/shawshawwan/p/8454621.html
Copyright © 2011-2022 走看看