【leetcode_310】【中等】minimum-height-trees / 最小高度树

URL

链接:https://leetcode-cn.com/problems/minimum-height-trees/


题目

截图
在这里插入图片描述


分析

在这里插入图片描述
证明:http://courses.csail.mit.edu/6.046/fall01/handouts/ps9sol.pdf
截图


源码

工程结构

.
└── main_310.c

源码文件

/* main_310.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct list_node {
    int val;
    struct list_node * next;
}LIST_NODE;

int * find_mid_height_trees(int n , int ** edges ,
        int edges_size ,
        int * return_size)
{
    int *res = NULL;
    if (n == 1){
        res = (int *)malloc(sizeof(int));
        *res = 0;
        *return_size = 1;
        return res;
    }

 	/* 
    	申请n个节点的list
       	申请n个节点的degree
       	初始化每个节点的next为NULL
    */
    struct list_node ** adj = (struct list_node **)malloc(sizeof(struct list_node *) * n);  // leetcode 官解给的强转类型是(struct list_node *) , emm....如果是我错了烦请告知一下原因
    int *degree = (int *)malloc(sizeof(int) * n);
    memset(degree, 0, sizeof(int) * n);
    for (int i = 0; i < edges_size; ++i){
        adj[i] = NULL;
    }

    /*
    	定义u,v为节点列表中的下标
    	申请node,赋值val,next指向节点列表中下表为u的节点,同时将节点列表中下标为u的指针指向当前node地址
    	申请node,赋值val,next指向节点列表中下表为v的节点,同时将节点列表中下标为v的指针指向当前node地址
    */
    for (int i = 0; i < edges_size; ++i){
        int u = edges[i][0];
        int v = edges[i][1];
        struct list_node *node = (struct list_node *)malloc(sizeof(struct list_node));
        node->val = u;
        node->next = adj[v];
        adj[v] = node;
        node = (struct list_node *)malloc(sizeof(struct list_node));
        node->val = v;
        node->next = adj[u];
        adj[u] = node;
        degree[u]++;
        degree[v]++; // 20220407 FIX
    }

    /*
    	申请一个大小为n的队列,用于存储degree为1的节点下标,
    	遍历degree数组,找到度为1的节点下标,并将下标存储到queue队列中,同时queue尾++,便于计算queue元素个数
    */
    int * queue = (int *)malloc(sizeof(int) * n);
    int head = 0;
    int tail = 0;
    for (int i = 0; i < n; ++i){
        if(degree[i] == 1){
            queue[tail++] = i;
        }
    }
    /*
    	将queue外的节点数记为remain_nodes,即remain_nodes == n - queue中节点个数(变化值),即:remain_nodes = n;sz = tail - head;remain_nodes -= sz;
    	遍历queue中节点,将该节点所有子节点的degree--,将最后度为1的节点再加到queue中,将queue尾++,即将合法节点val记录到queue[tail]处 ;head++,到最后queue中[head,tail]的节点都为合法值
    */
    int remain_nodes = n;
    while(remain_nodes > 2){
        int sz = tail - head;
        remain_nodes -= sz;
        for (int i = 0; i < sz; ++i){
            int curr = queue[head++];
            struct list_node * node = adj[curr];
            while(node){
                int v = node->val;
                degree[v]--;
                if (degree[v] == 1){
                    queue[tail++] = v;
                }
                node = node->next;
            }
        }
    }

    /*
    	remain_nodes即为所有合法节点的数量,赋值return_size返回合法节点的个数,
    	将queue中[head,tail]的节点赋值给res,返回res数组
    */
    res = (int *)malloc(sizeof(int) * remain_nodes);
    *return_size = remain_nodes;
    int pos = 0;
    while (head != tail){
        res[pos++] = queue[head++];
    }

    free(queue);
    free(degree);
    for (int i = 0; i < n; ++i){
        struct list_node * node = adj[i];
        while(node){
            struct list_node * curr = node;
            node = curr->next;
            free(curr);
        }
    }

    free(adj);
    return res;
}

int main()
{

#if 0
    int n = 4;
    int edges_arr[][2] = {{1,0},{1,2},{1,3}};
#else
    int n = 6;
    int edges_arr[][2] = {{3,0},{3,1},{3,2},{3,4},{5,4}};
#endif

    /*  */
    int edges_size = sizeof(edges_arr)/sizeof(edges_arr[0]);
    int ** edges = (int **)malloc(sizeof(int *) * (edges_size * 2));
    for (int i = 0; i < edges_size; ++i){
        edges[i] = (int *)malloc(sizeof(int) * 2);
        edges[i][0] = edges_arr[i][0];
        edges[i][1] = edges_arr[i][1];
    }

    /*  */
    int ret_size = 0;
    int * ret_node = find_mid_height_trees(n, edges, edges_size, &ret_size);

    for(int i = 0; i < ret_size; ++i){
        printf("root node = %d\n",ret_node[i]);
    }

    /*  */
    for (int i = 0; i < edges_size; ++i){
        free(edges[i]);
    }
    free(edges);
    free(ret_node);
    return 0;
}

LOG参考

root node = 1
root node = 3
root node = 4

源码概述

  1. 看源码,不赘述

小结

  1. 一个数学证明是算法前提
  2. 将degree做自减操作,得到需要的度
  3. 用 u,v 表示前节点值、后节点地址
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过得精彩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值