zoukankan      html  css  js  c++  java
  • 九度 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
    ",p, q);
                }else{
                    scanf("%lld%lld", &p, &q);
                    nth(p, q, n);
                    printf("%lld
    ",n );
                }
            }
             
        }
     
        return 0;
     
    }
    View Code
  • 相关阅读:
    解决端口被占用
    Oracle查询所有表的字段明细
    Spring cron表达式
    Java爬取12306余票
    Activiti工作流框架——快速上手
    ERROR 1045 (28000): Access denied for user 'xxx'@'localhost' (using password: YES)【奇葩的bug】
    一分钟学会JavaMail(假)__手动滑稽
    通过Servlet实现汉字验证码
    使用ServletContext对象读取资源文件
    编写一个简单的java服务器程序
  • 原文地址:https://www.cnblogs.com/xinsheng/p/3575676.html
Copyright © 2011-2022 走看看