• 顺丰2023秋招笔试 第二题(C++ 二叉树思想)


    猜测序列

    小明有一个由1到n的整数组成的排列,他让你来猜出这个排列是什么。你每次可以猜测某一位置的数字,小明会告诉你所猜测的数是“大了”、“小了”或是“正确”。你想知道你在最坏情况下,需要猜测几次,才能在排列的所有位置都得到小明“正确”的回复?

    输入

    5
    
    • 1

    输出

    11
    
    • 1

    说明

    二分法,对于一个长度为 k 的序列,最多搜索 ⌊ log ⁡ 2 k ⌋ + 1 \lfloor \log_2k\rfloor + 1 log2k+1 次,。对于本例,第一个位置有 5 个,那就是 3 次搜索,第二个有 4 个,3 次……
    一共 3 + 3 + 2 + 2 + 1 = 11 次。

    那我们一个一个计算,然后加上,多简单,复杂度 O ( n ) O(n) O(n)

    然后呢,超时了,寄。

    分析

    对于每一个 k :

    • k = 1 ∈ [ 2 0 ,   2 1 ) k = 1\in[2^0,\ 2^1) k=1[20, 21) == > 搜索 0 + 1 = 1 0 + 1 = 1 0+1=1
      2 0 ∗ ( 0 + 1 ) = 1 2^0 * (0 + 1) = 1 20(0+1)=1
       
       

    • k = 2 ∈ [ 2 1 ,   2 2 ) k = 2\in[2^1,\ 2^2) k=2[21, 22) == > 搜索 1 + 1 = 2 1 + 1 = 2 1+1=2
      k = 3 ∈ [ 2 1 ,   2 2 ) k = 3\in[2^1,\ 2^2) k=3[21, 22) == > 搜索 1 + 1 = 2 1 + 1 = 2 1+1=2
      2 1 ∗ ( 1 + 1 ) = 4 2^1 * (1 + 1) = 4 21(1+1)=4
       
       

    • k = 4 ∈ [ 2 2 ,   2 3 ) k = 4\in[2^2,\ 2^3) k=4[22, 23) == > 搜索 2 + 1 = 3 2 + 1 = 3 2+1=3
      k = 5 ∈ [ 2 2 ,   2 3 ) k = 5\in[2^2,\ 2^3) k=5[22, 23) == > 搜索 2 + 1 = 3 2 + 1 = 3 2+1=3
      k = 6 ∈ [ 2 2 ,   2 3 ) k = 6\in[2^2,\ 2^3) k=6[22, 23) == > 搜索 2 + 1 = 3 2 + 1 = 3 2+1=3
      k = 7 ∈ [ 2 2 ,   2 3 ) k = 7\in[2^2,\ 2^3) k=7[22, 23) == > 搜索 2 + 1 = 3 2 + 1 = 3 2+1=3
      2 2 ∗ ( 2 + 1 ) = 12 2^2 * (2 + 1) = 12 22(2+1)=12

    • k = 8 ……

    其实就是个二叉树,求各个节点层数的总和,对于 k ∈ [ 2 i − 1 ,    2 i ) k\in [2^{i-1}, \ \ 2^i) k[2i1,  2i) ,有 2 i − 1 2^{i-1} 2i1个和它一样的(包括它自身)都需要搜索 i i i 次,可以避免多次计算。

    图示:
    在这里插入图片描述

    步骤:

    1. p = ⌊ log ⁡ 2 n ⌋ p = \lfloor \log_2n\rfloor p=log2n,然后从 i = 0 遍历到 p - 1,每次加上
    2. 最后加上 ( n − 2 p + 1 ) ∗ ( p + 1 ) (n - 2^p + 1) * (p + 1) (n2p+1)(p+1)

    复杂度:
    O ( log ⁡ 2 n ) O(\log_2n) O(log2n)

    代码

    #include
    #include
    #include 
    
    using namespace std;
    
    int main() {
        int n;
        cin >> n;
        unsigned long long ans = 0;
        unsigned long long p = floor(log2(n));
        for(int i = 0; i < p; i++) {
            ans += (i + 1) * pow(2, i);
        }
            ans += (p + 1) * (n + 1 - pow(2, p));
        cout << ans;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    MySQL进阶查询
    微电网重构|基于群稀疏性的机会约束微电网重构(Matlab代码和Python代码实现)
    node.js学习笔记 09核心模块
    Android流媒体开发之路二:NDK C++开发Android端RTMP直播推流程序
    2023年云计算发展趋势浅析
    接上问题-80端口占用已解决但nginx仍然无法启动
    低代码平台是什么意思?低代码平台如何设计与实现?
    6 Java之 Debug & 进制 原码 反码 补码& 二维数组
    第五章 树 6 AcWing 1576. 再次树遍历
    生成本地的Docker镜像并上传到镜像仓库
  • 原文地址:https://blog.csdn.net/as091313/article/details/126658584