【剑指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;
}

题目 二:平衡二叉树

输入一颗二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左、右子树的深度相差不超过 1 ,那么它就是一颗平衡二叉树。例如,如上图中的二叉树就是一颗平衡儿叉树。

解题程序:

#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++)
    {
       int bitMask = 1;
        for(int j = 31;j>=0;j--)
        {
            int bit = numbers[i] & bitMask;
            if( bit != 0 )
                bitSum[j] += 1;

            bitMask = bitMask << 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;
}

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35396127/article/details/79949116
个人分类: 剑指offer
上一篇【剑指offer】第五十三题(在排序数组中查找数字) 和 第五十四题(二叉搜索树的第 K 大结点)
下一篇【剑指offer】第五十七题(和为 s 的两个数字) 和 第五十八题(翻转字符串)
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭