剑指offer--树的子结构

题目描述

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

class Solution {

public:

bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)

{

bool result = false;

if (pRoot1 != NULL&&pRoot2 != NULL)

{

//这时候就要去找大树里边有没有你的子树的根

if (pRoot1->val == pRoot2->val)

{

result = FindHasSubtree(pRoot1, pRoot2);

//这时候就要开始对比这两个树是不是一样了,根一样了往下对比

}

//这时候现在这个结点不一样那就得去他的左孩子或者右孩子里边找找,这里我们用递归比较好

//这样不需要保存当前结点位置,如果左孩子没有的话会退到当前函数去找右孩子

if (!result)

{

result = HasSubtree(pRoot1->left, pRoot2);//这个结点不是就去他的左孩子里边找

}

if (!result)

{

result = HasSubtree(pRoot1->right, pRoot2);//左孩子没找到就去右孩子里边找

}

}

return result;

}

bool FindHasSubtree(TreeNode *p1, TreeNode *p2)

{

//这个函数用来对比两个子树是不是一样,还是用递归

if (p2 == NULL)//如果2到头了这时候说明匹配完了还没有返回错误的值那就是正确的

return true;

if (p1 == NULL)//如果2还没有到底1到底了,那说明不匹配

return false;

if (p1->val != p2->val)//遇到两个值不一样说明不匹配

return false;

//走到这里说明我们1不是空2也不是空并且两个数值一样,那就去比较他们两个的孩子一样不一样一层一层递归

return (FindHasSubtree(p1->left, p2->left) && FindHasSubtree(p1->right, p2->right));

}

};

这算是把别人的代码抄下来了,虽然看懂了,但是自己还是不知道从哪下手写这段代码。

首先拿到题目我们是要找第一棵树是不是包含第二课树,当我们拿到两个树的根节点的时候,首先就要去两个根节点匹配的地方,这是我最初没有想清楚的情况。如果在某一点两个根节点相同了, 这时候再去匹配我们的子树。遍历二叉树自然还是递归比较方便,为了一个程序再去实现一个栈就很不值得,所以我们是通过递归来找我们相同的结点,我们不妨写一个程序是用来找某个节点是不是在某个二叉树里边的。

bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)

{

if (pRoot1 == NULL || pRoot2 == NULL)

return false;

if (pRoot1->val == pRoot2->val)

return true;

//这里说明两个节点不相同就需要去孩子里边找

return HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2);

}

我认为这个程序我写的还是没问题的,我们去找两个节点相同的结点,并且这里需要做的是找到两个相同的结点了,就要进入另一个函数来比较两个子树,找到了起点之后就一点点开始比。找到起点之后就把这两个传入到对比函数里边去。

bool FindHasSubtree(TreeNode *p1, TreeNode *p2)

{

//这个函数用来对比两个子树是不是一样,还是用递归

if (p2 == NULL)//如果2到头了这时候说明匹配完了还没有返回错误的值那就是正确的

return true;

if (p1 == NULL)//如果2还没有到底1到底了,那说明不匹配

return false;

if (p1->val != p2->val)//遇到两个值不一样说明不匹配

return false;

//走到这里说明我们1不是空2也不是空并且两个数值一样,那就去比较他们两个的孩子一样不一样一层一层递归

return (FindHasSubtree(p1->left, p2->left) && FindHasSubtree(p1->right, p2->right));

}

};

这是我们的对比函数,同样是通过递归来实现。这里还有一个需要注意的是,不是说我现在在左孩子找到了相匹配的根节点,然后我和小树去匹配,如果失败了的话直接返回false,因为我们很有可能左孩子右孩子都有一个和小树匹配的结点,要考虑全面不能左边找到匹配了但是没成功就直接返回失败。

这道题并不难,不过饶了一些弯子,自己在写代码的时候没有去好好的思考一下该怎么一步一步的去解决问题,上来直接想让两个树怎么去匹配,匹配成功怎么办匹配失败怎么办,写出来的代码没有头绪。

  今天继续给大家分享选择题

设顺序表的长度为 n 。下列算法中,最坏情况下比较次数小于 n 的是( )

A.寻找最大项

B.堆排序

C.快速排序

D.顺序查找法

 首先大家需要明白什么是堆排序,什么是快速排序。

  1. 寻找我们的最大项,这里我最早认为你的长度是n那你最坏的情况不应该是n么,后来慢慢感觉有点道理,你是n个数,但是你只需要比较n-1次就可以找到最大的那个数,所以他的次数就是小于n是n-1;
  2. 堆排序里边我们都知道最坏的时间复杂度就是O(nlogn)这是要比我们的n要大的。
  3. 快速排序最好的时间复杂度就是我们的O(nlogn)最坏的情况,就是我们当前选的中间轴是最大的数或者说最小的数,其他的数字都在快速排序的左边或者右边,这时候的时间复杂度是O(n2)如果说快速排序每次分的都比较均匀时间复杂度就是O(log2n)
  4. 顺序查找法是在这一堆数里边找到一个数,但是他并不在这个数组里边,他最坏的情况就是O(n)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值