leetcode#1104 二叉树寻路

目录

题目描述:

“     在一棵无限的二叉树上,每个节点都有两个子节点,树中的节点 逐行 依次按 “之” 字形进行标记。如下图所示:
    在奇数行(即,第一行、第三行、第五行……)中,按从左到右的顺序进行标记;

    而偶数行(即,第二行、第四行、第六行……)中,按从右到左的顺序进行标记。

    给你树上某一个节点的标号 label,请你返回从根节点到该标号为 label 节点的路径,该路径是由途经的节点标号所组成的。 “

示例:

示例 1:
​ 输入:label = 14
​ 输出:[1,3,4,14]
​示例 2:

​ 输入:label = 26
​ 输出:[1,2,6,10,26]

提示:

​ 1 <= label <= 10^6
来源:力扣(LeetCode)
​链接:https://leetcode-cn.com/problems/path-in-zigzag-labelled-binary-tree



题解性能:





思路:

看到题目的一刻,想到建立完全树,只不过这个建树的顺序比较奇特。

1)种树(未用)

    起初中规中矩,希望可以通过建两颗树来解决问题,于是想到两种种树的方法:

第一种: 生成的时候,赋值按照规矩来,也就是按照数字顺序建类似一条链表的线性结构,然后利用数学规律找到某个endNum 数字的父节点-》直至root

第二种: 直接前序建完全树,直到节点数目达到endNum停止(最终因为难以使父亲不同的节点横线连接未采用)

​ 但还是写了前序建立完全树代码:

int locCol(int label)  //按照完全树的定位某个在第几行
{
   
    int cols=1;
    int sum=1;
    int base=2;
    while(sum < label)
    {
   
        cols ++;
        sum += base;
        base *= 2;
    }

    return cols;
}

void preOrderCreate(treeNode &tr,int endNum) //按照顺序前向建树
{
   
    data ++;
    if(data == endNum)
    {
   
        cout<<"end"<<endl;
        tr = new Node;
        tr->val = data;
        tr->left=NULL;
        tr->right=NULL;
        tr->next=NULL;
        return; //终点限制
    }
    else if(depth == locCol(endNum))
    {
   
        cout<<"end col"<<endl;
        tr = new Node;
        tr->val = data;
        tr->left=NULL;
        tr->right=NULL;
        return;  //层数限制
    }
    else
    {
   

        tr = new Node;
        tr->val = data;

        depth++;
        preOrderCreate(tr->left,endNum);
 
        if(data == endNum) return;
 
        preOrderCreate(tr->right,endNum);
        depth--;
        //回到父节点,此时的data是父节点的data
        if(tr->left!=NULL && tr->right!=NULL)
        {
   
            if(locCol(data)%2==0)  //所以儿子们在奇数行
            {
   
                tr->left->next = tr->right;
            }
            else //所以儿子们在偶数行
            {
   
                tr->right->next = tr->left;
            }
        }
    }
}

(2种建树示意图)


2) 找规律用数学方法

​  ​  舍弃建树,尝试找规律,最后研究出一个神奇的公式
f a t h e r = ( s o n / 2 ) + ( a r e a [ t e m p C o l − 1 ] − 2 ∗ r o u n d ( f l o a t ( s o n − p r e A r e a [ t e m p C o l − 1 ] ) / 2 ) + 1 ) father = (son / 2) + (area[tempCol-1] - 2 * round(float(son - preArea[tempCol-1])/2) + 1) father=(son/2)+(area[tempCol1]2round(float(sonpreArea[tempCol1])/2)+1)
​ ​  ​  其中,tempCol 是当前子节点 son 所在的行(行标从1开始)

​ ​  ​  area 数组存储每个行有多少个节点,故 area[tempCol-1] 代表当前子节点前一行有多少个节点

​ ​​    preAre 数组存储前x行一共多少个节点,故 preArea[tempCol-1] 代表当前子节点之前的所有行节点数之和

(不同符号含义示意图)

怎么得出这个公式的呢?只能说是 小学计算 + 灵感

​  ​  是完全树的性质给的灵感,对于一颗数字顺序存储的完全二叉树,父子编号有这样的性质:

​  ​  父节点 = 子节点 / 2(int型除法,直接保留整数部分)

​  ​  因此,从这个入手,加上本题中每行奇怪的顺序,加上一个偏移量就可以从子得到父,然后经一番推导就得到以上公式。

​  ​  想通了这一点,树不用建了,甚至一个顺序存储的数组也不用建了——上代码(主要关注函数pathInZigZagTree):



题解代码:

class Solution {
   
public:
    int locCol(int label)  //按照完全树的定位某个在第几行
    {
   
    int cols=1;
    int sum=1;
    int base=2;
    while(sum < label)
    {
   
        cols ++;
        sum += base;
        base *= 2;
    }

    return cols;
    }

    vector<int> pathInZigZagTree(int endNum) {
   
    int sum=1;
    int base=1;
    int col=1;
    int cols=locCol(endNum);
    int *area = new int[cols+2]; //每个段的树的量
    int *pre_area = new int[cols+1];  //前面的每一段的总数
    int footprint = endNum;
    vector<int> path;
    area[0] = -1;
    pre_area[0] = -1;

    while(col <= cols)
    {
   
        area[col] = base; //每一段的树
        pre_area[col] = sum; //前col段的总数
        col ++;
        base *= 2;
        sum += base;
    }



    for(int i=1;i<=cols;i++)
    {
   
        path.insert(path.begin(),footprint);
        int temp_col = locCol(footprint); //当前行
        int pre = pre_area[temp_col-1]; //之前和
        int temp = area[temp_col];  //当前行数目
        int cal = (footprint / 2) + (area[temp_col-1] - 2 * round(float(footprint - pre)/2) + 1);  //呕心力学
        footprint = cal;

    }

    return path;
    }
};

int stringToInteger(string input) {
   
    return stoi(input);
}

string integerVectorToString(vector<int> list, int length = -1) {
   
    if (length == -1) {
   
        length = list.size();
    }

    if (length == 0) {
   
        return "[]";
    }

    string result;
    for(int index = 0; index < length; index++) {
   
        int number = list[index];
        result += to_string(number) + ", ";
    }
    return "[" + result.substr(0, result.length() - 2) + "]";
}

int main() {
   
    string line;
    while (getline(cin, line)) {
   
        int label = stringToInteger(line);
        vector<int> ret = Solution().pathInZigZagTree(label);
        string out = integerVectorToString(ret);
        cout << out << endl;
    }
    return 0;
}
全部评论

相关推荐

好久没来牛客了,今天面试了一个实习生,感觉对方形象乱糟糟的,头发像鸡窝,像刚睡醒就来面试了,第一印象直接大打折扣,感觉我没有受到应有的尊重,再加上对方业务能力也一般,我直接挂掉;大家面试的时候还是好好收拾一下自己吧,争取给面试官留下个好印象,面试这东西还是存在眼缘的
MinJerous:更在乎本质,应该看候选人是否和岗位需要的能力匹配。洗脸/不洗头都无所谓吧,说不定人家刚刚通宵准备,就是为了这场面试呢?你挂掉他核心原因还是他能力不行,而不是形象。就算形象好点,能力不行你敢给过吗,不怕后面+1质疑你
点赞 评论 收藏
分享
04-11 00:51
已编辑
门头沟学院 Java
先说一下楼主的情况:双非本大三,两段实习,javaer,想要找一个暑期大厂offer,努力了两个月,三月份每天的状态就是算法,八股,项目,四月份更是一个面试没有,最终还是没有结果,心碎了一地。期间面了一些中小厂,大厂只有腾讯约面,其他大厂都投了一遍,但是还是石沉大海。再看一下楼主的面试结果吧,就不说ttl了腾讯s3:三面挂csig:一面挂teg:三面挂wxg:一面挂没错,面了八次腾讯,两次三面挂,当时真的心都碎了。其他中小厂都有面,有的没过,有的oc,但是都没有去。其他大厂投了简历,但是不是简历挂,就是测评挂,都说今年行情好很多,各大厂都扩招,可是问题出在那里呢?学历背景吗?实习经历吗?还是简历不够好看?依稀记得,从年初七就离开了家里,回到学校,早早准备面试,当时自己认为凭借着自己的两段实习经历,以及大二就开始准备的八股算法,拿大厂offer不是问题,但是还是不敢放松,回校的状态每天就是算法,八股,还有查看各种招聘信息,想着尽早投机会多,但是事实证明,投的早,不如投的刚刚好。当时想着,先投一些中小厂开始面试,找找面试感觉,从2.10就开始有面试了,基本都是线下面试,面试的感觉都很不错,觉得自己的状态慢慢回来了,期间也有oc一些中小厂,但是自己的目标并不在此,只是想练一下手,遂拒。后面投了腾讯的暑期实习基地,不久就约面了,第一次面这么大的厂,多少有点紧张,好在运气还不错,遇到的面试官也比较好,一直干到了三面,期间看牛客有不少说一面就挂了的,感觉自己还是比较幸运的,但是没想到倒在了三面,一周后就挂了,伤心是有的,但是想到这才刚刚开始,还有很多机会,便继续准备下一次面试了,很快,被另外一个部门捞了,一进会议,面试官没开摄像头,看网上说没开摄像头很多都是kpi,但是自己给自己打气,认为面试官只是不方便开摄像头罢了,面完,感觉良好,没问什么很难得问题,基本都答出来了,算法两道也a了一道,感觉实习不会这么严格吧?还是过了一会挂了,因为这个?还是技术不太匹配?面试过程中说搞C++的,心想,搞c++的你面我干啥?唉,这时候有点气馁,然后就接下来半个月没有面试。这时已经是三月底了,看到牛客好多人都已经陆陆续续拿到了offer,看人家的面试准备也没那么早,有0实习的,有没刷算法的,有两个面的,,,唉,反正是一言难尽啊,感觉努力没有什么意义,面试多半是看面试官的感觉,主观性很大啊,只要你技术没有太大的问题。第三次面试腾讯,面试来的比较突然,期间已经有几天没看八股什么的了,临时看了一下之前自己做的面试笔记,但是面试却异常顺利,三天闯到了三面,自己也不敢相信,三面玩感觉也良好,脑子里不得不想着一些“offer结算画面”,但是过了一会查看流程显示“流程终止”,我?哎,当时真的有苦说不出啊,也是一晚没睡。后面就逐渐开始褪去大厂梦了,看着曾经跟自己交流的牛油,朋友,认识的人,觉得他们技术不太如你,算法刷的没你多,进了大厂,但是这又如何呢?能力强不强不是你了说了,面试官说了算。也逐渐知道,不是你能力好就可以了,还得有运气,运气,运气。这个过程太累了,和自己和解吧,不用非得大厂,找个合适一点的就好,放轻松一点。今天有点心事睡不着,闲着想写一些自己的面试过程,勿喷。附上一张面试的情况,公司就不方便透露了。
怒卷的斯科特:八分运气两分实力
点赞 评论 收藏
分享
06-04 16:50
腾讯_TEG_技术
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务