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

猜测序列

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

输入

5

输出

11

说明

用二分法,对于一个长度为 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<iostream>
#include<vector>
#include <cmath>

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值