字节青训营每日一题部分汇总

1.假如在抖音中发布视频时,可以选择带上位置信息,请设计一种数据结构或方案,用于存储检索位置信息(简化为平面坐标 x, y),以实现搜索附近视频的功能(如附近 3km)。

坐标范围检索,有四叉树、geohash 等几种标准解法。这道题本质并不是考察对高阶算法的掌握,而是想发掘在学习教材 btree 等基础二分思想后,能否进一步思考解出更复杂的问题;
另外考察思维灵活程度,看是否能变通的解决问题,如距离并没有限定必须是欧式距离;位置可以不精确,可以容忍有误差等。

  • 方法 1,四叉树(QTree):在二叉树左、右节点的思想下,加入上、下、前、后等更多的方向,演进为四叉树和八叉树。高阶树比较超纲,相关实现省略
  • 方法 2,geohash:把二维问题降为一维
    如坐标(示例非标准 geohash,只是演示了思想):
    (12, 345) -> (012, 345) -> "031425"
    (13, 348) -> (013, 348) -> "031438"
    (2, 789) -> (002, 789) -> "070829"
    最终做字符串前缀匹配,可得 "031425" 和 "031438" 匹配到的位数最多,二者距离最近。求 3km 内的坐标,只需提前算出需匹配前几位即可,如匹配前 4 位,按 sql 表达是 LIKE '0314%'
  • 方法 3,变通距离为 方圆 3km(曼哈顿距离),即 deltaX = 1500, deltaY = 1500,通过数据库解决 Create table tb_name ( x int, y int ) 并添加索引。
    假如原点是 (x0, y0),sql 如下:
    WHERE (x > x0 - 1500) AND (x < x0 + 1500) AND (y > y0 - 1500) AND (y < y0 + 1500)

2.【多选】下列关于Join 运算不正确的是:

a. Nested Loop Join 不能使用索引做优化。
b. 如果左表太大,不能放入内存中,则不能使用 Hash Join。
c. 如果 Join 的一个输入表在 Join Key 上有序,则一定会使用 Sort Merge Join。
d. Broadcast Join 适用于一张表很小,另一张表很大的场景。

a、b、c;
Nested Loop Join 可以使用索引优化(Index Nested Loop Join);
如果左表太大,不能放入内存,可以先对量表做分区,再对每个分区做 Hash Join (Parititioned Hash Join);
如果Join的一个输入表在Join Key上有序,也可以 Hash Join,具体使用哪种 Join 方式取决于优化器的代价估计结果。

3.给定一个正整数数组 arrs 和整数 K ,请找出该数组内乘积小于等于 k 的连续的子数组的个数,算法时间复杂度o(n)。

双指针思想,对于每个right, 不断单调的移动left,直到满足需求。

4.【多选】绝大多数硬盘可以提供哪些写入保证?

a. 单个sector原子写入
b. 单个page原子写入
c. 硬盘顺序执行文件系统发送的操作
d. 以上都不可以

d;
本题主要考察对于一个数据密集型应用开发者(比如数据库开发者、文件系统开发者),在数据不能出错的前提下,可以依赖磁盘的哪些能力,事实证明几乎没有什么能力可以依赖。
在随时可能断电的情况下,大多数硬件能提供单个sector的原子性写入;但是也有少数硬件连单个sector的写入都无法保证;如果一个page对应多个sector,则单个page的完整写入总是无法得到保障。更加详细的情况可以查看这个讨论:crash - Are disk sector writes atomic?
对于同时发给硬盘的多个操作(比如写多个不连续的sector),硬盘并不保证操作的顺序。结合其弱原子性,所以硬盘可能处在任何一个中间状态。这主要是由于机械硬盘的寻址优化策略和固态/机械硬盘的缓存策略导致的。

5.判断一棵二叉树是否是平衡二叉树。(平衡二叉树要求:树中节点左右子树树高差不超过1。)

解法一(常规解法):
分别求左右子树的深度,再进行判断、递归。(此方法会遍历一个节点多次,效率不高。)

bool IsBalanced_Solution1 (BinaryTreeNode * pRoot )
{
    if ( pRoot == NULL ) return true ;
    int left = TreeDepth ( pRoot->m_pLeft );
    int right = TreeDepth ( pRoot->m_pRight );
    int diff = left - right ;
    if ( diff >1|| diff <-1 ) return false ;
    return IsBalanced_Solution1 ( pRoot - >m_pLeft ) && IsBalanced_Solution1 ( pRoot - >m_pRight );
}

 解法二(更高效的解法):
解决了遍历一个问题多次的问题。用后序遍历的方式遍历二叉树的每一个节点,在遍历到一个节点之前我们就已经遍历了它的左右子树。只要在遍历每个节点的时候记录深度,就可以一边遍历一边判断每个节点是不是平衡的。

bool IsBalanced_Solution2(BinaryTreeNode * pRoot)
{
    int depth =0 ;
    return IsBalanced(pRoot,& depth);
}
bool IsBalanced(BinaryTreeNode * pRoot, int* pDepth)
{
    if (pRoot == NULL)
    {
        *pDepth=0 ;
        return true ;
    }
    int left, right;
    if (IsBalanced(pRoot-> m_pLeft,& left) && IsBalanced(pRoot-> m_pRight,& right))
    {
        int diff = left - right;
        if (diff <=1&& diff>=-1 )
        {
            *pDepth = 1 + (left> right ? left : right);
            return true ;
        }
    }
    return false ;
}

5.【分布式文件处理,获取最多的 URL】如果有一个 20g 的日志文件,日志文件记录着用户访问过的 url,每一行为一个 url,给你一台 512M 的主机,找出出现次数最多的 10 个 url。

Top K算法:使用堆排序算法+大顶堆+10 个元素的数组。

  • IP 地址最多有 2^32=4G 种取值情况,所以不能完全加载到内存中处理;
  • 可以考虑采用“分而治之”的思想,按照 IP 地址的 Hash(IP)%1024 值,把海量 IP 日志分别存储到 1024 个小文件中。这样,每个小文件最多包含 4MB 个 IP 地址;
  • 对于每一个小文件,可以构建一个 IP 为 key,出现次数为 value 的 Hash map,同时记录当前出现次数最多的那个 IP 地址;
  • 可以得到 1024 个小文件中的出现次数最多的 IP,再依据常规的排序算法得到总体上出现次数最多的 IP;

6.Top K算法:使用堆排序算法+大顶堆+10 个元素的数组。

  • IP 地址最多有 2^32=4G 种取值情况,所以不能完全加载到内存中处理;
  • 可以考虑采用“分而治之”的思想,按照 IP 地址的 Hash(IP)%1024 值,把海量 IP 日志分别存储到 1024 个小文件中。这样,每个小文件最多包含 4MB 个 IP 地址;
  • 对于每一个小文件,可以构建一个 IP 为 key,出现次数为 value 的 Hash map,同时记录当前出现次数最多的那个 IP 地址;
  • 可以得到 1024 个小文件中的出现次数最多的 IP,再依据常规的排序算法得到总体上出现次数最多的 IP;

c;
Python 运行时并不会检查变量类型, 类型提示主要给第三方工具使用, 比如IDE可以据此给出方法/属性的自动补全建议。

7.给定包含 N 个任务 task 的数组 tasks 和整数 K,和一个可并发调用的执行函数 execute,要求实现以下逻辑:

  1. execute并发调用次数不超过10
  2. 以最快速度执行完所有task
  3. 使用golang

利用并发 + channel 缓冲区实现。

type Task int

func handle(tasks []Task, execute func(task Task)) {
   wg := sync.WaitGroup{}
   ch := make(chan struct{}, 10)
   for i, _ := range tasks {
      ch <- struct{}{}
      wg.Add(1)
      task := tasks[i]
      go func() {
         defer wg.Done()
         // execute task
         execute(task)
         <-ch
      }()
   }
   wg.Wait()
}

8.【多选】下面关于 HTTP1.x 的性能优化方式,正确的有:

a. 对域名进行分片,使得客户端可以创建更多的 TCP 连接提高请求并发度
b. 设置 Connection: Keep-Alive Header 保持长连接,减少 TCP 连接握手的开销
c. 利用 ServerPush 将页面上的关键静态资源直接推送到客户端,无需等待客户端请求
d. 将小的静态资源直接嵌入到页面中,减少 HTTP 请求次数

a,b,d;
ServerPush 为 HTTP2 协议才具备的能力,无法应用在 HTTP1.x 的优化中。

9.时间复杂度 O(nlogn) 空间复杂度 O(1) (非递归) 的限制下从单链表中找出第 K 大的节点 。

快排思路的逆向,快排递归思路是对序列持续拆成两个子序列处理,逆向过程就是每 2 个相邻的元素做合并排序,然后每相邻 4 个相邻的元素合并排序(因为之前一轮已经使这 4 个元素由两个长度为 2 的子序列构成),然后 8 个,16 个,直到覆盖整个原始序列。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值