# 【剑指offer】第五十五题(二叉树的深度) 和 第五十六题(数组中数字出现的次数)

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
using namespace std;

// 二叉树的存储结构
struct BinaryTreeNode
{
int m_nValue;
struct BinaryTreeNode *m_pLeft;
struct BinaryTreeNode *m_pRight;
};

// 二叉树结点的创建

BinaryTreeNode* CreateBinaryNode(int val)
{
BinaryTreeNode *pBinaryTreeNode = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
if( pBinaryTreeNode == NULL)
{
printf("pBinaryTreeNode malloc failed!\n");
return NULL;
}

pBinaryTreeNode->m_nValue = val;
pBinaryTreeNode->m_pLeft = NULL;
pBinaryTreeNode->m_pRight = NULL;

return pBinaryTreeNode;
}

// 连接二叉树的结点

void ConnectTreeNodes(BinaryTreeNode *pParent,BinaryTreeNode *pLeft,BinaryTreeNode *pRight)
{
if( pParent != NULL    )
{
pParent->m_pLeft = pLeft;
pParent->m_pRight = pRight;
}
}

// 销毁二叉树

void DestroyTree(BinaryTreeNode *pRoot)
{
if(pRoot != NULL)
{
BinaryTreeNode *pLeft = pRoot->m_pLeft;
BinaryTreeNode *pRight = pRoot->m_pRight;

free(pRoot);
pRoot = NULL;

DestroyTree(pLeft);
DestroyTree(pRight);

}
}

// 获取二叉树的深度

int TreeDepth(BinaryTreeNode *pRoot)
{
if( pRoot == NULL )
return 0;

int left = TreeDepth(pRoot->m_pLeft);
int right = TreeDepth(pRoot->m_pRight);

int res = left > right ? left+1:right+1;

return res;
}

// 测试用例

void test()
{
// 创建结点
BinaryTreeNode *pNode1 = CreateBinaryNode(1);
BinaryTreeNode *pNode2 = CreateBinaryNode(2);
BinaryTreeNode *pNode3 = CreateBinaryNode(3);
BinaryTreeNode *pNode4 = CreateBinaryNode(4);
BinaryTreeNode *pNode5 = CreateBinaryNode(5);
BinaryTreeNode *pNode6 = CreateBinaryNode(6);
BinaryTreeNode *pNode7 = CreateBinaryNode(7);

// 连接结点
ConnectTreeNodes(pNode1,pNode2,pNode3);
ConnectTreeNodes(pNode2,pNode4,pNode5);
ConnectTreeNodes(pNode5,pNode7,NULL);
ConnectTreeNodes(pNode3,NULL,pNode6);

int ret = TreeDepth(pNode1);
printf("二叉树的深度为：%d\n",ret);
// 销毁二叉树
DestroyTree(pNode1);
}

int main(void)
{
test();

return 0;
}


#include<iostream>
#include<stdlib.h>
#include<stdio.h>
using namespace std;

// 二叉树的存储结构
struct BinaryTreeNode
{
int m_nValue;
struct BinaryTreeNode *m_pLeft;
struct BinaryTreeNode *m_pRight;
};

// 二叉树结点的创建

BinaryTreeNode* CreateBinaryNode(int val)
{
BinaryTreeNode *pBinaryTreeNode = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
if( pBinaryTreeNode == NULL)
{
printf("pBinaryTreeNode malloc failed!\n");
return NULL;
}

pBinaryTreeNode->m_nValue = val;
pBinaryTreeNode->m_pLeft = NULL;
pBinaryTreeNode->m_pRight = NULL;

return pBinaryTreeNode;
}

// 连接二叉树的结点

void ConnectTreeNodes(BinaryTreeNode *pParent,BinaryTreeNode *pLeft,BinaryTreeNode *pRight)
{
if( pParent != NULL    )
{
pParent->m_pLeft = pLeft;
pParent->m_pRight = pRight;
}
}

// 销毁二叉树

void DestroyTree(BinaryTreeNode *pRoot)
{
if(pRoot != NULL)
{
BinaryTreeNode *pLeft = pRoot->m_pLeft;
BinaryTreeNode *pRight = pRoot->m_pRight;

free(pRoot);
pRoot = NULL;

DestroyTree(pLeft);
DestroyTree(pRight);

}
}

// 获取二叉树的深度

int TreeDepth(BinaryTreeNode *pRoot)
{
if( pRoot == NULL)
return 0;

int left = TreeDepth(pRoot->m_pLeft);
int right = TreeDepth(pRoot->m_pRight);

int res = left > right ? left+1:right+1;

return res;
}

// 需要重复遍历结点多次的解法，简单但不足以打动面试官

// 判断一颗二叉树是否是平衡二叉树

bool isBalanced(BinaryTreeNode *pRoot)
{
if( pRoot == NULL )
return true;
int left = TreeDepth(pRoot->m_pLeft);
int right = TreeDepth(pRoot->m_pRight);

int ret = left - right;
if( ret >1 || ret < -1)
return false;
return isBalanced(pRoot->m_pLeft) && isBalanced(pRoot->m_pRight);
}

// 解法二：每个结点只遍历一次，正是面试官喜欢的

bool isBalanced(BinaryTreeNode *pRoot,int *pDepth)
{
if( pRoot == NULL )
{
*pDepth = 0;
return true;
}

int left,right;
if(isBalanced(pRoot->m_pLeft,&left) && isBalanced(pRoot->m_pRight,&right))
{
int dif = left - right;
if( dif<= 1 || dif >= -1 )
{
*pDepth =1+(left > right? left:right);
return true;
}
}

return false;
}

bool isBalanced2(BinaryTreeNode *pRoot)
{
int depth = 0;
return isBalanced(pRoot,&depth);
}

// 测试用例

void test()
{
// 创建结点
BinaryTreeNode *pNode1 = CreateBinaryNode(1);
BinaryTreeNode *pNode2 = CreateBinaryNode(2);
BinaryTreeNode *pNode3 = CreateBinaryNode(3);
BinaryTreeNode *pNode4 = CreateBinaryNode(4);
BinaryTreeNode *pNode5 = CreateBinaryNode(5);
BinaryTreeNode *pNode6 = CreateBinaryNode(6);
BinaryTreeNode *pNode7 = CreateBinaryNode(7);

// 连接结点
ConnectTreeNodes(pNode1,pNode2,pNode3);
ConnectTreeNodes(pNode2,pNode4,pNode5);
ConnectTreeNodes(pNode5,pNode7,NULL);
ConnectTreeNodes(pNode3,NULL,pNode6);

bool ret = isBalanced(pNode1);
if(ret)
printf("二叉树是一颗平衡二叉树\n");
else
printf("二叉树不是一颗平衡二叉树\n");

ret = isBalanced2(pNode1);
if(ret)
printf("二叉树是一颗平衡二叉树\n");
else
printf("二叉树不是一颗平衡二叉树\n");

// 销毁二叉树
DestroyTree(pNode1);
}

int main(void)
{
test();

return 0;
}


一个整型数组里除两个数字之外，其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度 O(n)，空间复杂度 O(1)。

#include<iostream>
#include<stdio.h>
using namespace std;

// 算法思想：任何一个数字异或它自己等于 0。也就是说，如果我们从头到尾异或数组中的每个数字，那么最终的结果刚好
// 是那个只出现一次的数字，因为那些成对出现的两次的数字全部在异或中抵消了

// 在整数 num 的二进制中国找到最右边是 1 的位
unsigned int FindFirstBits1(int num)
{
int indexBit = 0;
while((num & 1) == 0 && (indexBit< 8 *sizeof(int)))
{
num = num >> 1;
++indexBit;
}

return indexBit;
}

// 判断 num 的二进制表示中从右边数起的 indexBit 位是不是 1

bool IsBits1(int num,unsigned int indexBit)
{
num = num>>indexBit;
return (num & 1);
}

// 获取数组中只出现过一次的数字

void FindNumsAppearOnce(int *data,int len,int *num1,int *num2)
{
if(data == NULL || len <= 0)
return ;

// 异或结果
int resultExclusiveOr = 0;

for(int i=0;i<len;i++)
resultExclusiveOr ^= data[i];

// 划分子数组
unsigned int indexOf1 = FindFirstBits1(resultExclusiveOr);

*num1 = *num2 = 0;
for(int j=0;j<len;j++)
{
if(IsBits1(data[j],indexOf1))
*num1 ^= data[j];
else
*num2 ^= data[j];
}

}

// 测试用例：

void test()
{
int data[] = {2,4,3,6,3,2,5,5};
int len = sizeof(data) / sizeof(data[0]);
int num1,num2;

FindNumsAppearOnce(data,len,&num1,&num2);

printf("数组中两个只出现一次的数字是：%d\t%d\n",num1,num2);
}

int main(void)
{
test();
return 0;
}


#include<iostream>
#include<stdio.h>
using namespace std;

// 查找数组中唯一出现一次的数字

int FindNumberAppearingOnce(int numbers[],int len)
{
if(numbers == NULL || len<=0)
return -1;

int bitSum[32] = {0};

for(int i = 0;i<len;i++)
{
for(int j = 31;j>=0;j--)
{
int bit = numbers[i] & bitMask;
if( bit != 0 )
bitSum[j] += 1;

}

}

int result = 0;
for(int i=0;i<32;i++)
{
result = result << 1;
result += bitSum[i] % 3;
}

return result;
}

// 测试用例

void test()
{
int data[] = {1,1,1,2,3,3,3,4,4,4};
int len = sizeof(data) / sizeof(data[0]);
int ret = FindNumberAppearingOnce(data,len);
printf("数组中只出现一次的数字是: %d\n",ret);
}

int main(void)
{
test();
return 0;
}


#### 第五十五题：对称的二叉树

2018-04-13 17:31:07

#### 第五十六题（最长公共子串）

2014-07-03 10:25:02

#### 第五十六题：数据流中的中位数

2018-04-15 21:54:27

#### 《剑指offer》——数字在排序数组中出现的次数

2015-11-22 14:54:23

#### 【剑指offer】出现次数超过一半的数字

2014-05-25 15:00:56

#### 《剑指Offer》面试题：统计一个数字在排序数组中出现的次数

2015-09-12 22:23:12

#### 【剑指Offer】数组中出现次数超过一半的数字

2015-09-21 00:23:32

#### （剑指offer）数字在排序数组中出现的次数 二叉树的深度

2018-03-31 19:58:17

#### 剑指Offer:面试题29——数组中出现次数超过一半的数字(java实现)

2016-07-08 11:34:50

#### 剑指offer：数组中出现次数超过一半的数字（Python）

2018-04-12 22:29:19