《五月集训》第十七天——广度优先搜索

前言

这是五月集训的第十七日,今日的训练内容是 广度优先搜索

解题报告

1.力扣LCP44

原题链接

LCP 44. 开幕式焰火

题目概述

「力扣挑战赛」开幕式开始了,空中绽放了一颗二叉树形的巨型焰火。
给定一棵二叉树 root 代表焰火,节点值表示巨型焰火这一位置的颜色种类。请帮小扣计算巨型焰火有多少种不同的颜色。

解题思路

定义一个哈希表,然后定义一个函数使用广度优先搜索的方式对树进行遍历,在主函数中先将数填入哈希表,然后再遍历哈希表就可以了,至于遍历的方式将在源码剖析中写出。

源码剖析

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
int hash[1001];

void count(struct TreeNode* root)
{
    if(root)
    {
        hash[root -> val]++;
        count(root -> right);
        count(root -> left);
    }
}

int numColor(struct TreeNode* root)
{
    memset(hash, 0, sizeof(hash));
    count(root);
    int sum = 0;
    for(int i = 1; i <= 1000; i++)
    {
        if(hash[i])
            sum++;
    }
    return sum;
}

if(root)只要结点不为空就继续遍历,这是递归的出口,出口具体是遍历到数的结点没有孩结点为止,否则就对其孩结点进行遍历。

2.力扣102

原题链接

102. 二叉树的层序遍历

题目概述

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

解题思路

见源码剖析的注释

源码剖析

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
struct que{
    struct TreeNode* node;                          //结构体分为结点域
    struct que* next;                               //指针域
};

void que_enter(struct que* a,struct TreeNode *node){        //尾插法插入结点
    struct que* tmp = a;                                    //首先定义一个队列结点
    while(tmp->next!=NULL){                                 //如果当前结点的下一个结点不为空时
        tmp = tmp->next;                                    //使得tmp变为指向的下一个结点
    }                                                       //这一步的作用就是,使得结点指向队列的尾部之后
    struct que *b=(struct que*)malloc(sizeof(struct que));  //申请一个新的队列结点b
    b->node = node;                                         //将树结点填入队列结点的结点域
    b->next = NULL;                                         //使得结点指向NULL
    tmp->next = b;                                          //然后再使得tmp指向的结点变为b
}

struct  TreeNode* deQueue(struct que *queueHead)            //这个函数返回一个树结点,结点就是当前的队列结点中的树结点
{
    struct que* queueIt    = queueHead->next;               //定义一个队列结点指向头结点的下一个
    struct  TreeNode* node;                                 //定义一个树结点
    if(queueIt != NULL)                             //假如指向不是队尾
    {
        queueHead->next =  queueIt->next;           //头结点的下一个结点变为下下个结点
        node = queueIt->node;                       //把当前结点的值给树结点
        free(queueIt);                              //释放结点
        return node;                                //返回树结点
    }
    return NULL;                                   //如果是队尾 node中肯定没有值,直接返回NULL
}

void que_free(struct que *a){                              //释放队列
    struct que *tmp = a->next;                             //定义一个结点代表当前结点的下一个结点
    struct que *pre = a->next;                             //定义一个结点代表前一个结点
    if(tmp!=NULL){                                  //当前结点next结点不为NULL时(如果是NULL就只剩头结点了)
        pre = tmp;                                  //pre就等于tmp
        tmp = tmp->next;                            //tmp变为下一个结点
        free(pre);                                  //随后释放pre,这时后续的结点(包括tmp)就都被断开了
    }
    free(a);                                        //再释放头结点
}

void bfs(int *returnSize,int **returnColumnSizes,int **returnNum,struct que *queueHead){   //广度优先搜索
    struct que* queueIt = queueHead->next;
    if (queueIt->node == NULL)                                      //如果当前队列已经没有树了,结束递归
    {
        return;
    }
    int count = 0;                                                  //计数器
    returnNum[*returnSize] = (int*)malloc(sizeof(int) * 2000);      //为返回的数组申请内存
    while(1)
    {
       struct TreeNode * node = deQueue(queueHead);               //把队列中的当前的结点的树值给树
       if(node == NULL)                                           //如果树空
       {
           break;                                                 //直接结束循环
       }
       returnNum[*returnSize][count] = node->val;                 //返回值就为树的值
       count++;                                                   //计数器加一

       if(node->left != NULL)                                     //如果左孩不为空  
       {
           que_enter(queueHead,node->left);                         //将左树加入队列继续递归
       }

       if(node->right != NULL)                                    //右孩类似   
       {
           que_enter(queueHead,node->right);
       }
    }
    que_enter(queueHead,NULL);                                      //如果上面出现break了说明已经只有null了
    (*returnColumnSizes)[*returnSize ] = count;                   //列数就等于计数器(每行的结点数)
    *returnSize = *returnSize + 1;                                
    bfs(returnSize,returnColumnSizes,returnNum,queueHead);        //递归出口在最开头
}
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
     *returnSize = 0;
    if(root == NULL)
        return NULL;
    int** returnNum = (int**)malloc(sizeof(int*) * 2000);
    *returnColumnSizes = (int*)malloc(sizeof(int) * 2000);
    struct que *queueHead = malloc(sizeof(struct que));
    queueHead->next = NULL;
    queueHead->node = NULL;
    que_enter(queueHead,root);
    que_enter(queueHead,NULL);
    bfs(returnSize,returnColumnSizes,returnNum,queueHead);
    que_free(queueHead);
    return returnNum;
}

3.力扣1609

原题链接

1609. 奇偶树

题目概述

如果一棵二叉树满足下述几个条件,则可以称为 奇偶树 :

二叉树根节点所在层下标为 0 ,根的子节点所在层下标为 1 ,根的孙节点所在层下标为 2 ,依此类推。
偶数下标 层上的所有节点的值都是 奇 整数,从左到右按顺序 严格递增
奇数下标 层上的所有节点的值都是 偶 整数,从左到右按顺序 严格递减
给你二叉树的根节点,如果二叉树为 奇偶树 ,则返回 true ,否则返回 false 。

解题思路

将上一题的代码复用,然后判断一下数组的情况

源码剖析

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
**/
struct que{
    struct TreeNode* node;                          //结构体分为结点域
    struct que* next;                               //指针域
};

void que_enter(struct que* a,struct TreeNode *node){        //尾插法插入结点
    struct que* tmp = a;                                    //首先定义一个队列结点
    while(tmp->next!=NULL){                                 //如果当前结点的下一个结点不为空时
        tmp = tmp->next;                                    //使得tmp变为指向的下一个结点
    }                                                       //这一步的作用就是,使得结点指向队列的尾部之后
    struct que *b=(struct que*)malloc(sizeof(struct que));  //申请一个新的队列结点b
    b->node = node;                                         //将树结点填入队列结点的结点域
    b->next = NULL;                                         //使得结点指向NULL
    tmp->next = b;                                          //然后再使得tmp指向的结点变为b
}

struct  TreeNode* deQueue(struct que *queueHead)            //这个函数返回一个树结点,结点就是当前的队列结点中的树结点
{
    struct que* queueIt    = queueHead->next;               //定义一个队列结点指向头结点的下一个
    struct  TreeNode* node;                                 //定义一个树结点
    if(queueIt != NULL)                             //假如指向不是队尾
    {
        queueHead->next =  queueIt->next;           //头结点的下一个结点变为下下个结点
        node = queueIt->node;                       //把当前结点的值给树结点
        free(queueIt);                              //释放结点
        return node;                                //返回树结点
    }
    return NULL;                                   //如果是队尾 node中肯定没有值,直接返回NULL
}

void que_free(struct que *a){                              //释放队列
    struct que *tmp = a->next;                             //定义一个结点代表当前结点的下一个结点
    struct que *pre = a->next;                             //定义一个结点代表前一个结点
    if(tmp!=NULL){                                  //当前结点next结点不为NULL时(如果是NULL就只剩头结点了)
        pre = tmp;                                  //pre就等于tmp
        tmp = tmp->next;                            //tmp变为下一个结点
        free(pre);                                  //随后释放pre,这时后续的结点(包括tmp)就都被断开了
    }
    free(a);                                        //再释放头结点
}

void bfs(int *returnSize,int **returnColumnSizes,int **returnNum,struct que *queueHead){   //广度优先搜索
    struct que* queueIt = queueHead->next;
    if (queueIt->node == NULL)                                      //如果当前队列已经没有树了,结束递归
    {
        return;
    }
    int count = 0;                                                  //计数器
    returnNum[*returnSize] = (int*)malloc(sizeof(int) * 2000);      //为返回的数组申请内存
    while(1)
    {
       struct TreeNode * node = deQueue(queueHead);               //把队列中的当前的结点的树值给树
       if(node == NULL)                                           //如果树空
       {
           break;                                                 //直接结束循环
       }
       returnNum[*returnSize][count] = node->val;                 //返回值就为树的值
       count++;                                                   //计数器加一

       if(node->left != NULL)                                     //如果左孩不为空  
       {
           que_enter(queueHead,node->left);                         //将左树加入队列继续递归
       }

       if(node->right != NULL)                                    //右孩类似   
       {
           que_enter(queueHead,node->right);
       }
    }
    que_enter(queueHead,NULL);                                      //如果上面出现break了说明已经只有null了
    (*returnColumnSizes)[*returnSize ] = count;                   //列数就等于计数器(每行的结点数)
    *returnSize = *returnSize + 1;                                
    bfs(returnSize,returnColumnSizes,returnNum,queueHead);        //递归出口在最开头
}
int** levelOrder(struct TreeNode* root,int* returnSize, int** returnColumnSizes){
    *returnSize = 0;
    if(root == NULL)
        return NULL;
    int** returnNum = (int**)malloc(sizeof(int*) * 2000);
    *returnColumnSizes = (int*)malloc(sizeof(int) * 2000);
    struct que *queueHead = malloc(sizeof(struct que));
    queueHead->next = NULL;
    queueHead->node = NULL;
    que_enter(queueHead,root);
    que_enter(queueHead,NULL);
    bfs(returnSize,returnColumnSizes,returnNum,queueHead);
    que_free(queueHead);
    return returnNum;
}
bool isEvenOddTree(struct TreeNode* root){
    int* a;
    int** returnColumnSizes;
    int** mat = levelOrder(root,a,returnColumnSizes);
    int i,j;
    for(i = 0;i<a;++i){
        if(i&1){                                    //偶数行递增
            int min = 0;
            for(j = 0;j<returnColumnSizes[i];++j){
                if(mat[i][j]==NULL) continue;
                else{
                    if(min<mat[i][j]) min = mat[i][j];
                    else return false;
                }
            } 
        }else{                                      //奇数行递减
            int max = 10001;
            for(j = 0;j<returnColumnSizes[i];++j){
                if(mat[i][j]==NULL) continue;
                else{
                    if(max>mat[i][j]) max = mat[i][j];
                    else return false;
                }
            }
        }
    }
    return true;
}

代码有一个小问题,就是对于数组的引用,具体的修改要等更加熟悉这里的内容之后。

4.力扣1263

原题链接

1263. 推箱子

题目概述

「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。

游戏地图用大小为 m x n 的网格 grid 表示,其中每个元素可以是墙、地板或者是箱子。

现在你将作为玩家参与游戏,按规则将箱子 ‘B’ 移动到目标位置 ‘T’ >:

玩家用字符 ‘S’ 表示,只要他在地板上,就可以在网格中向上、下、左、右四个方向移动。
地板用字符 ‘.’ 表示,意味着可以自由行走。
墙用字符 ‘#’ 表示,意味着障碍物,不能通行。 
箱子仅有一个,用字符 ‘B’ 表示。相应地,网格上有一个目标位置 ‘T’。
玩家需要站在箱子旁边,然后沿着箱子的方向进行移动,此时箱子会被移动到相邻的地板单元格。记作一次「推动」。
玩家无法越过箱子。
返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1。

暂做记录,之后会去完整的实现一下这个游戏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值