九度 1543 无限完全二叉树的层次遍历(递归问题)

题目

给定这么一个二叉树, 求解 (1) 对于给定正整数 n, 求解其值, 比如当 n = 5 时, 返回 p = 3, q = 2 (2) 对于给定的 p,q 返回其序号 n

 

思路

1. 最初以为这是道数学题, 但当画出第四层叶子节点时, 发现即便这是道数学问题, 也可以用递归求解. 同时因为此题属于完全二叉树, 所以使用递归效率也不会太差, 毕竟每次递归数据规模都可以减少一半

2. 已知 n 或已知 p,q 都属于某一个叶子节点, 因此我们需要从底向上推导, 属于 bottomUp 算法. 我曾总结过 bottomUp 算法, 那次的结论是使用后序遍历即可, 但这是一道逻辑上的树, 不能进行后续遍历, 所以需要另想方法

3. 对于第一问, 已知 n, 通过手工计算的话, 是根据 n 的奇偶性选择向上走的方向, 一直走到 root, 记录路径再回溯回来. 用递归实现, 有点意思, 这里我还想了蛮长时间, 毕竟第一次接触, 感觉有点绕, 最后写出这样的代码

void bottomUp(unsigned long long n, unsigned long long &p, unsigned long long &q) {
    if(n == 1) {
        p = 1;
        q = 1;
        return;
    }
    // n != 1;
    bottomUp(n/2, p, q);
 
    if(n & 1) { // odd number
        p = p+q;
    }else{
        q = p+q;
    }
}

 

代码的精髓在于使用一个函数来做出了 bottomUp and 回溯回去两个过程

4. 第 2 问就显得更加直接了, 思路相同

void nth(unsigned long long p, unsigned long long q, unsigned long long &n) {
    if(p == 1 && q == 1) {
        n = 1;
        return;
    }
    if(p > q) {
        unsigned long long newp = p-q;
        nth(newp, q, n);
        n = n*2 +1;
    }else{
        unsigned long long newq = q-p;
        nth(p, newq, n);
        n *= 2;
    }
}

 

想到 Leetcode 上一道题, 求解十进制数中 1 的个数, 递归求法同样奇妙

 

代码 未通过 JOBDU 测试

#include <utility>
#include <iostream>
#include <math.h>
using namespace std;
 
void bottomUp(unsigned long long n, unsigned long long &p, unsigned long long &q) {
    if(n == 1) {
        p = 1;
        q = 1;
        return;
    }
    // n != 1;
    bottomUp(n/2, p, q);
 
    if(n & 1) { // odd number
        p = p+q;
    }else{
        q = p+q;
    }
}
 
 
void nth(unsigned long long p, unsigned long long q, unsigned long long &n) {
    if(p == 1 && q == 1) {
        n = 1;
        return;
    }
    if(p > q) {
        unsigned long long newp = p-q;
        nth(newp, q, n);
        n = n*2 +1;
    }else{
        unsigned long long newq = q-p;
        nth(p, newq, n);
        n *= 2;
    }
}
 
int main() {
    //freopen("testcase.txt", "r", stdin);
    unsigned long long n, p, q;
    unsigned long long cases, types;
    while(scanf("%lld", &cases) != EOF) {
        for(int i = 0; i < cases; i ++) {
            scanf("%lld", &types);
            n = p = q = 0;
            if(types == 1) {
                scanf("%lld", &n);
                bottomUp(n, p, q);
                printf("%lld %lld\n",p, q);
            }else{
                scanf("%lld%lld", &p, &q);
                nth(p, q, n);
                printf("%lld\n",n );
            }
        }
         
    }
 
    return 0;
 
}
View Code

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值