<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>树 on 一共十七划</title>
		<link>https://noirzh.com/tags/%E6%A0%91/</link>
		<description>Recent content in 树 on 一共十七划</description>
		<generator>Hugo</generator>
		<language>zh-CN</language>
		
		
		
		
			<lastBuildDate>Mon, 13 Nov 2023 09:17:59 +0800</lastBuildDate>
		
			<atom:link href="https://noirzh.com/tags/%E6%A0%91/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>题解-每棵子树内缺失的最小基因值</title>
				<link>https://noirzh.com/minimum-time-to-eat-all-grains-solution/</link>
				<pubDate>Tue, 07 Nov 2023 15:33:00 +0800</pubDate>
				<guid>https://noirzh.com/minimum-time-to-eat-all-grains-solution/</guid>
				<description>&lt;blockquote&gt;&#xD;&#xA;&lt;p&gt;&lt;a href=&#34;https://leetcode.cn/problems/smallest-missing-genetic-value-in-each-subtree/&#34;&gt;每棵子树内缺失的最小基因值&lt;/a&gt;&lt;/p&gt;&#xD;&#xA;&lt;/blockquote&gt;&#xD;&#xA;&lt;h2&gt;题目简介&lt;/h2&gt;&#xD;&#xA;&lt;p&gt;有一棵根节点为 0 的家族树 ，总共包含 n 个节点，节点编号为 0 到 n – 1 。给你一个下标从 0 开始的整数数组 parents ，其中 parents[i] 是节点 i 的父节点。由于节点 0 是 根 ，所以 parents[0] == -1 。&lt;/p&gt;&#xD;&#xA;&lt;p&gt;总共有 $10^5$ 个基因值，每个基因值都用 闭区间 $[1, 10^5]$ 中的一个整数表示。给你一个下标从 0 开始的整数数组 nums ，其中 nums[i] 是节点 i 的基因值，且基因值互不相同 。&lt;/p&gt;&#xD;&#xA;&lt;p&gt;请你返回一个数组 ans ，长度为 n ，其中 ans[i] 是以节点 i 为根的子树内 缺失 的 最小 基因值。&lt;/p&gt;&#xD;&#xA;&lt;p&gt;节点 x 为根的 子树 包含节点 x 和它所有的后代节点。&lt;/p&gt;&#xD;&#xA;&lt;h2&gt;思路&lt;/h2&gt;&#xD;&#xA;&lt;ul&gt;&#xD;&#xA;&lt;li&gt;在概念上与41. 缺失的第一个正数题类似,都是找数,由于本题没有要求O(1)O(1)O(1)的空间复杂度,所以用哈希表是可能的&lt;/li&gt;&#xD;&#xA;&lt;li&gt;与数组中缺失的第一个正数类似的是,如果一棵树的节点不包括1,则以该树的任意节点为根的的子树都缺少1,这是最简单的情况&lt;/li&gt;&#xD;&#xA;&lt;li&gt;对于子节点有1的才是重要讨论的情况&lt;/li&gt;&#xD;&#xA;&lt;/ul&gt;&#xD;&#xA;&lt;h2&gt;解题方法&lt;/h2&gt;&#xD;&#xA;&lt;ul&gt;&#xD;&#xA;&lt;li&gt;注意到需要处理的只是根节点到基因值为1的这一段的每个节点  &#xD;&#xA;&lt;ul&gt;&#xD;&#xA;&lt;li&gt;注意到此时讨论的只是一条链&lt;/li&gt;&#xD;&#xA;&lt;li&gt;其他的节点的缺失值一定为1&lt;/li&gt;&#xD;&#xA;&lt;/ul&gt;&#xD;&#xA;&lt;/li&gt;&#xD;&#xA;&lt;li&gt;可以用哈希表记录以该节点为根的子树包含的所有基因值,然后再每个节点都遍历一下&lt;/li&gt;&#xD;&#xA;&lt;li&gt;上述复杂度很高,再仔细观察节点的哈希表的形式,可以知道父节点的哈希表是所有子节点的合集加上自己的基因数&#xD;&#xA;&lt;ul&gt;&#xD;&#xA;&lt;li&gt;所以我们只需要自底向上遍历,维护一个哈希表就可以了&lt;/li&gt;&#xD;&#xA;&lt;li&gt;注意到父节点缺失的值不可能比子树缺失的还小,所以也需要维护一个基因数&lt;/li&gt;&#xD;&#xA;&lt;/ul&gt;&#xD;&#xA;&lt;/li&gt;&#xD;&#xA;&lt;li&gt;时间复杂度:$O(n)$&lt;/li&gt;&#xD;&#xA;&lt;li&gt;空间复杂度:$O(n)$&lt;/li&gt;&#xD;&#xA;&lt;/ul&gt;&#xD;&#xA;&lt;h2&gt;代码&lt;/h2&gt;&#xD;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;class Solution:&#xD;&#xA;    def smallestMissingValueSubtree(self, parents: List[int], nums: List[int]) -&amp;gt; List[int]:&#xD;&#xA;        n=len(parents)&#xD;&#xA;        res=[1]*n #默认最有可能缺1&#xD;&#xA;        if 1 not in nums:&#xD;&#xA;            return res&#xD;&#xA;        graph=[[]for _ in range(n)]&#xD;&#xA;        for i in range(1,n):&#xD;&#xA;            graph[parents[i]].append(i)&#xD;&#xA;&lt;pre&gt;&lt;code&gt;    visited=set()  &#xD;&#xA;    def dfs(index):&#xD;&#xA;        visited.add(nums[index])&#xD;&#xA;        for child in graph[index]:&#xD;&#xA;            if nums[child] not in visited:&#xD;&#xA;                dfs(child)&#xD;&#xA;&#xD;&#xA;    root=nums.index(1) #找分界点&#xD;&#xA;    now=2&#xD;&#xA;    while root&amp;amp;gt;=0: #自底向上递归查找&#xD;&#xA;        dfs(root)&#xD;&#xA;        while now in visited:&#xD;&#xA;            now+=1&#xD;&#xA;        res[root]=now&#xD;&#xA;        root=parents[root]&#xD;&#xA;    return res&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&#xD;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2&gt;其他&lt;/h2&gt;&#xD;&#xA;&lt;p&gt;这个理论上不能用与41题类似的将数组本身化为哈希表的操作,不然代码的复杂性很高,而且也不好理解&lt;/p&gt;</description>
			</item>
			<item>
				<title>题解-有向图访问计数,一个有向基环树的简单应用</title>
				<link>https://noirzh.com/count-visited-nodes-in-a-directed-graph-solutions/</link>
				<pubDate>Sat, 14 Oct 2023 08:27:00 +0800</pubDate>
				<guid>https://noirzh.com/count-visited-nodes-in-a-directed-graph-solutions/</guid>
				<description>&lt;p&gt;&amp;gt; Problem: &lt;a href=&#34;https://leetcode.cn/problems/count-visited-nodes-in-a-directed-graph/description/&#34;&gt;2876. 有向图访问计数&lt;/a&gt;&lt;/p&gt;&#xD;&#xA;&lt;h2&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/h2&gt;&#xD;&#xA;&lt;p&gt;– 注意到这个图一定有环,而且每个点的出度都为1&lt;/p&gt;&#xD;&#xA;&lt;p&gt;– 由题意可知从任意节点出发其都能访问到相关的环&lt;/p&gt;&#xD;&#xA;&lt;p&gt;– 答案只分为两个情况:&lt;/p&gt;&#xD;&#xA;&lt;p&gt;    – 点在环上,此时能访问的点只有环上的点,不可能出环,答案为环的长度&lt;/p&gt;&#xD;&#xA;&lt;p&gt;    – 点在环外,除了环本身之外,其能访问本节点到环的几个节点,答案为环的长度加上其到环的距离&lt;/p&gt;&#xD;&#xA;&lt;p&gt;– 注意到可能有多个环相互独立存在,但是不可能出现两个环连通,所以几个图之间互相并不干扰&lt;/p&gt;&#xD;&#xA;&lt;h2&gt;&lt;strong&gt;解题方法&lt;/strong&gt;&lt;/h2&gt;&#xD;&#xA;&lt;p&gt;1. 由以上思路得到基本想法,遍历解决每一个单独的环即可&lt;/p&gt;&#xD;&#xA;&lt;p&gt;2. 选择一个没有访问的节点,开始访问,其一定能进入环&lt;/p&gt;&#xD;&#xA;&lt;p&gt;    1. 记录初次访问访问点的深度&lt;/p&gt;&#xD;&#xA;&lt;p&gt;    2. 判断是否已经入环的方法就是判断该节点是否已经访问过&lt;/p&gt;&#xD;&#xA;&lt;p&gt;3. 对于当前点已经访问过有两种情况:&lt;/p&gt;&#xD;&#xA;&lt;p&gt;    1. 当前节点在之前的旧图上就访问过:此时根据访问深度加上之前已经得出点的答案来更新答案数组&lt;/p&gt;&#xD;&#xA;&lt;p&gt;    2. 当前节点是在这个新图上访问两次:此时第二次访问深度减去节点访问深度就是环的长度,更新环上节点的答案,环外带上的节点根据访问深度加环的长度更新&lt;/p&gt;&#xD;&#xA;&lt;p&gt;4. 持续上述操作直到所有节点都访问过,因为我们每次都将单个有环图的所有节点处理,所以每个节点都已经处理&lt;/p&gt;&#xD;&#xA;&lt;p&gt;&amp;gt; 时间复杂度,$O(n)$&lt;/p&gt;&#xD;&#xA;&lt;p&gt;&amp;gt; 空间复杂度,$O(n)$&lt;/p&gt;&#xD;&#xA;&lt;h2&gt;代码&lt;/h2&gt;&#xD;&#xA;&lt;p&gt;,对于这种问题应该可以补一个快慢指针法,但是此处没有做&lt;/p&gt;&#xD;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;class Solution:&#xD;&#xA;    def countVisitedNodes(self, edges: List[int]) -&amp;gt; List[int]:&#xD;&#xA;        n=len(edges)&#xD;&#xA;        res=[-1]*n&#xD;&#xA;        visited=set()&#xD;&#xA;        for i in range(n):&#xD;&#xA;            if i in visited:&#xD;&#xA;                continue&#xD;&#xA;            now=begin=i #记录begin就不用做反图,直接顺序遍历就能找到答案&#xD;&#xA;            tmp=dict()#记录此次遍历的时候访问的点&#xD;&#xA;            index=0&#xD;&#xA;            while now not in visited:&#xD;&#xA;                tmp[now]=index&#xD;&#xA;                visited.add(now)&#xD;&#xA;                index+=1&#xD;&#xA;                now=edges[now]&#xD;&#xA;            # 此时我们访问了的图有三种可能,一条带,一个环,一个有带的环&#xD;&#xA;            # 后两种可能都是如下解法&#xD;&#xA;            if now in tmp:&#xD;&#xA;                #此时tmp[now]长度为点到环的长度&#xD;&#xA;                belt=dict()&#xD;&#xA;                circle=set()&#xD;&#xA;                length=tmp[now]&#xD;&#xA;                now=begin&#xD;&#xA;                while length&amp;gt;0:&#xD;&#xA;                    belt[now]=length&#xD;&#xA;                    length-=1&#xD;&#xA;                    now=edges[now]&#xD;&#xA;                while now not in circle:&#xD;&#xA;                    circle.add(now)&#xD;&#xA;                    now=edges[now]&#xD;&#xA;                r=len(circle)#环的长度&#xD;&#xA;                for u in tmp:&#xD;&#xA;                    res[u]=r if u in circle else r+belt[u]&#xD;&#xA;            # 第一种可能是比较好处理的&#xD;&#xA;            else:&#xD;&#xA;                #说明连接到了之前的有向基环树上,直接与已经访问的点相加即可&#xD;&#xA;                length=index&#xD;&#xA;                baseLength=res[now]&#xD;&#xA;                now=begin&#xD;&#xA;                while length&amp;gt;0:&#xD;&#xA;                    res[now]=baseLength+length&#xD;&#xA;                    now=edges[now]&#xD;&#xA;                    length-=1&#xD;&#xA;&lt;pre&gt;&lt;code&gt;    return res&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&#xD;&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
			</item>
			<item>
				<title>题解-在二叉树中分配硬币-深度优先搜索,自底向上考虑</title>
				<link>https://noirzh.com/posts/%E9%A2%98%E8%A7%A3-%E5%9C%A8%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E5%88%86%E9%85%8D%E7%A1%AC%E5%B8%81/</link>
				<pubDate>Fri, 14 Jul 2023 23:46:22 +0800</pubDate>
				<guid>https://noirzh.com/posts/%E9%A2%98%E8%A7%A3-%E5%9C%A8%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E5%88%86%E9%85%8D%E7%A1%AC%E5%B8%81/</guid>
				<description>&lt;blockquote&gt;&#xA;&lt;p&gt;Problem: &lt;a href=&#34;https://leetcode.cn/problems/distribute-coins-in-binary-tree/description/&#34;&gt;979. 在二叉树中分配硬币&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;!-- toc --&gt;&#xD;&#xA;&lt;h1 id=&#34;思路&#34;&gt;思路&lt;/h1&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;考虑最后计算成本的时候实际上是计算的是每个节点对硬币的操作数&lt;/li&gt;&#xA;&lt;li&gt;每个节点只需要一个硬币,如何确定多出来的或少的硬币的流向&lt;/li&gt;&#xA;&lt;li&gt;考虑自底向上,叶子节点只需要一个硬币,这样就能向父节点要硬币或者向父节点送硬币,之后父节点变成了叶子节点(其子节点已完成使命)&lt;/li&gt;&#xA;&lt;li&gt;设一个值为$Need$表示需要向上移或者向上要的硬币数,根据以上推论我们能够得到如下公式,正数表示需要向上移动,负数表示需要上方向下移动&#xA;$$Need_{节点}=Need_{子节点}+val-1$$&lt;/li&gt;&#xA;&lt;li&gt;每次将一个节点处理完就将Need的绝对值加入到操作数之中&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h1 id=&#34;code&#34;&gt;Code&lt;/h1&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-Python&#34; data-lang=&#34;Python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Solution&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;distributeCoins&lt;/span&gt;(self, root: Optional[TreeNode]) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; int:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;res&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dfs&lt;/span&gt;(node:TreeNode):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; node&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            left&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dfs(node&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;left)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            right&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dfs(node&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;right)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;res&lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt;abs(left)&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;abs(right)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; right&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;left&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;node&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;val&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        dfs(root)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;res&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Solution&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;public:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    int res&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    int dfs(TreeNode&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; root){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;!&lt;/span&gt;root) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        int left&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dfs(root&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;left);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        int right&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dfs(root&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;right);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        res&lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt;abs(left)&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;abs(right);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; left&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;right&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;root&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;val&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    int distributeCoins(TreeNode&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; root) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        dfs(root);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; res;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
			</item>
	</channel>
</rss>
