查看: 11143| 回复: 25
跳转到指定楼层
上一主题 下一主题
收起左侧

[高频题] 想讨论一道谷歌高频题

全局:
高频题
公司名称: google

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
最近看到一道谷歌高频题,一直没有思路想和大家讨论一下.
有一个integer的数据流,其中要去除最大的百分之5和最小的百分之五的数据,然后求剩下数据的平均数!

楼主只想到brute force的方法

上一篇:不懂就问---Top一线公司 软件工程师 都要面试算法和System design么
下一篇:刷一遍leetcode sql大概要多久呀?
推荐
djmiss 2020-2-6 08:05:40 | 只看该作者
全局:
本帖最后由 djmiss 于 2020-2-6 08:11 编辑

感觉这题其实比295,480还要简单一点。

我的想法是维护两个pq,把5%的最小数和最大数放进去。在维护一个TreeSet放中间的数
如果数据量太大,就存Pair<value, count>, 再不行就用分布式分段计算

import java.util.*;

public class Test {
    PriorityQueue<Integer> bottom;
    PriorityQueue<Integer> top;
    TreeSet<Integer> middle;
    int totalSize;
    int percentage;
    int sumOfMiddle;
    /** initialize your data structure here. */
    public Test() {
        bottom = new PriorityQueue<>((a, b)-> b.compareTo(a));
        top = new PriorityQueue<>();
        middle = new TreeSet<>();
        totalSize = 0;
        percentage = 5;
        sumOfMiddle = 0;
    }
   
    public void addNum(int num) {
        middle.add(num);
        totalSize++;
        sumOfMiddle += num;
        rebalanceBottom();
        rebalanceTop();
    }
   
    public double findAverage() {
        return (double)sumOfMiddle / middle.size();
    }

    private void rebalanceBottom() {
        int bottomSize = percentage * totalSize / 100;
        //put one more to bottomHeap
        if (bottomSize > bottom.size()) {
            int num = middle.pollFirst();
            bottom.add(num);
            sumOfMiddle -= num;
        } else {
            //same size:
            int num = middle.pollFirst(); //pull out the smallest number
            bottom.offer(num);
            sumOfMiddle -= num;
            num = bottom.poll(); //pull in the biggest value
            middle.add(num);
            sumOfMiddle += num;
        }
    }

    private void rebalanceTop() {
        int topSize = percentage * totalSize / 100;
        //put one more to topHeap
        if (topSize > top.size()) {
            int num = middle.pollLast();
            top.add(num);
            sumOfMiddle -= num;
        } else {
            //same size:
            int num = middle.pollLast(); //pull out the largest number
            top.offer(num);
            sumOfMiddle -= num;
            num = top.poll(); //pull in the smallest value
            middle.add(num);
            sumOfMiddle += num;
        }
    }

    public static void main(String args[]) {
      Test t = new Test();
      for (int i = 0; i < 200; i++) {
        t.addNum(i);
        System.out.println("i=" +i+ ", avg="+ t.findAverage());
        System.out.print("number removed in top: ");
        for (int j: t.top) {
          System.out.print(j + " ");
        }
        System.out.println();
        
        System.out.print("number removed in bottom: ");
        for (int j: t.bottom) {
          System.out.print(j + " ");
        }
        System.out.println();
      }
      for (int i = 100; i >= 0; i--) {
        t.addNum(i);
        System.out.println("i=" +i+ ", avg="+ t.findAverage());
        System.out.print("number removed in top: ");
        for (int j: t.top) {
          System.out.print(j + " ");
        }
        System.out.println();
        
        System.out.print("number removed in bottom: ");
        for (int j: t.bottom) {
          System.out.print(j + " ");
        }
        System.out.println();
      }
   }
}
回复

使用道具 举报

推荐
WIwindson 2020-2-21 14:12:11 | 只看该作者
全局:
O(log(k)) 的解法以及步骤,大家看看哪里不对:

1. 使用最近的 k 个元素建立一个哈希表,其中键为该元素的 index,值为该元素的(值,index)组成的 tuple。
2. 使用最近的 k 个元素的(值,index)组成的 tuple 组成一个二叉平衡树(Treaps,红黑树),其中每个节点都记录左右子树的节点个数以及和。
3. 当有新的元素加入的时候,通过哈希表找到需要删除的旧 index 对应的 tuple,在二叉平衡树找到该 tuple 并删除,更新相应子树的记录。
4. 把新元素插入到哈希表以及二叉平衡树,并更新相应的子树记录。
5. 在二叉平衡树总查找第 5% 大 以及第 95% 大的元素,并用根节点的总和减去它们分别左右子树的值。得到结果
回复

使用道具 举报

推荐
joe297 2020-2-7 07:09:48 | 只看该作者
全局:
开一个BST,维护一个mean,total number of integers,number of integers in BST
每有一个新integer,进树,更新mean和两个number,然后看要不要从BST里去除最大最小数,如果不用就不管,如果用就去掉,更新树和number

之后可以想下怎么把BST中间的那部分放进disk里

评分

参与人数 2大米 +2 收起 理由
Aegeaner + 1 赞一个
kenyang + 1 聪明的办法!

查看全部评分

回复

使用道具 举报

全局:
个人觉得,可以用一个最大堆,一个最小堆,然后一个记录所有的小的数,另一个记录所有大的数。另外记录一个size,每次来一个数据,对比一个两个堆,看看是不是需要加入堆。然后再看是不是要平均这个数。
回复

使用道具 举报

🔗
c393323264 2020-1-17 05:51:09 | 只看该作者
全局:
不知道小帅 发表于 2020-1-17 02:15
个人觉得,可以用一个最大堆,一个最小堆,然后一个记录所有的小的数,另一个记录所有大的数。另外记录一个 ...

好奇一下,你的堆要开多大,比如这种情况,流的头部是大于1的值,后面都是1
这种情况你的大数堆要怎么处理?
回复

使用道具 举报

🔗
stcheng 2020-1-17 06:02:58 | 只看该作者
全局:
c393323264 发表于 2020-1-17 05:51
好奇一下,你的堆要开多大,比如这种情况,流的头部是大于1的值,后面都是1
这种情况你的大数堆要怎么处 ...

堆里存储的可以是data structure——比如<value, count>的pair
回复

使用道具 举报

🔗
c393323264 2020-1-17 06:11:09 | 只看该作者
全局:
stcheng 发表于 2020-1-17 06:02
堆里存储的可以是data structure——比如的pair

我的意思是,刚开始的一些数字比如2不在top 5 percent里面,然后如果stream后面都是1,在足够多的1之后,2就会来到top 5 percent里面
回复

使用道具 举报

🔗
WIwindson 2020-1-17 13:58:03 | 只看该作者
全局:
楼主是哪里看到高频题的?因为我onsite也遇到了。问题有一点不一样。给一个数据流,求最近的k个元素的去掉top5%和最后5%之后的平均值。O(k)的方法是

1. 队列第一次达到 k 个元素的时候,用额外列表 lst 存储队列前 k 个元素从小到大的排序(init 操作需要 O (k * log(k)))
2. 当增加新元素 i 的时候,先遍历 lst 找到 oldest 元素然后删除( O(k) 时间),然后使用插入排序,插入 i 到 lst 中( O(k) 时间)
3. 使用 sum 函数计算中间 90% 的元素和( O(k) 时间)

你的题目就把k当成现有数据流的长度n就好,除了第一次之外,之后每次O(n)。我听面试官说好像有 log(k) (我的问题)的解法,不过没想出来。
回复

使用道具 举报

🔗
c393323264 2020-1-18 03:30:15 | 只看该作者
全局:
WIwindson 发表于 2020-1-17 13:58
楼主是哪里看到高频题的?因为我onsite也遇到了。问题有一点不一样。给一个数据流,求最近的k个元素的去掉t ...

你这个就简单很多了,因为你的窗大小是固定的,它的那个窗是一直变大的
回复

使用道具 举报

全局:
c393323264 发表于 2020/01/18 03:30:15
你这个就简单很多了,因为你的窗大小是固定的,它的那个窗是一直变大的
我的解法只能每次O(n),你有想到什么更好的做法吗?
回复

使用道具 举报

🔗
Evilcat 2020-1-18 15:13:10 | 只看该作者
全局:
WIwindson 发表于 2020-1-17 13:58
楼主是哪里看到高频题的?因为我onsite也遇到了。问题有一点不一样。给一个数据流,求最近的k个元素的去掉t ...

可以优化到 log(k) 的话

1. init k 不变还是 k * log k
2. 删除 oldest 可以用一个queue 每次pop top 在list里删除
  这样 多一个O(k) space 但是记录 oldest 就是 O(1)
  sorted list 删除 是 O(log k)
  sorted list 增加 是 O(log k)
3. total sum 可以类似 sliding window 记录
  删除时候 sum -= 删除项 O(1)
  增加时候 sum += 增加项 O(1)
  减除 top bottom 5% 估计需要 再加 一个 minheap 一个maxheap
  会在第二步多2个 O(log k)

=。 = 有错误请指正~
top bottm sum哪里 估计还能优化
回复

使用道具 举报

全局:
不知道小帅 发表于 2020/01/17 02:15:58
个人觉得,可以用一个最大堆,一个最小堆,然后一个记录所有的小的数,另一个记录所有大的数。另外记录一个size,每次来一个...
我也是这个想法,如果两个堆超出memory你会怎么处理呢?想讨论一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表