这不是一个O(n)算法吗?
本文关键字:算法 一个 这不是 | 更新日期: 2023-09-27 18:09:51
我想弄清楚为什么我的算法通过了所有不超时的测试用例。据我所知,这是一个O(n)算法,因为它是一个O(n)算法序列的执行。这让我很好奇,为什么它会超时。我想不出一种方法可以显著减少这里涉及的操作数量(我认为通过使用更精简的数据结构来进行轻微的操作,但这并不能降低复杂性)。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
/// <summary>
///
/// Solution to https://www.hackerrank.com/challenges/cut-the-tree
///
/// Explanation of algorithm:
///
/// Given a tree like
///
/// Val=100
/// '
/// Val=200
/// / '
/// / Val=100
/// Val=100
/// / '
/// Val=500 Val=600
///
/// set a field for each node showing the sum of the values
/// in the subtree whose root is that node, making it into
///
/// Val=100
/// Sum=1600
/// '
/// Val=200
/// Sum=1500
/// / '
/// / Val=100
/// / Sum=100
/// Val=100
/// Sum=1200
/// / '
/// Val=500 Val=600
/// Sum=500 Sum=600
///
/// Then we can easily find minimum difference between the sum of
/// two trees that result from severing a branch: if the root node
/// is R and we sever node N, then the difference between the two
/// sums is |R.Sum - 2 * N.Sum|.
///
/// </summary>
class Node
{
public int Val { get; set; }
public Node Parent { get; set; } = null;
public List<Node> Neighbors { get; set; } = new List<Node>();
/// <summary>
/// Sum of values in descendant nodes
/// </summary>
public int DescendantsSum { get; set; } = 0;
/// <summary>
/// Sum of values in tree whose root is this node
/// </summary>
public int TreeSum { get { return Val + DescendantsSum; } }
}
class Solution
{
/// <summary>
/// Builds the parent relation between nodes
/// Complexity: O(n) where n is the number of nodes
/// </summary>
static Node BuildToTree(Node[] nodes)
{
Node root = nodes[0]; // use arbitrary node as the root
var Q = new Queue<Node>();
Q.Enqueue(root);
while(Q.Count > 0)
{
var current = Q.Dequeue();
foreach(var neighbor in current.Neighbors.Where(nbr => nbr != current.Parent && nbr.Parent == null))
{
neighbor.Parent = current;
Q.Enqueue(neighbor);
}
}
return root;
}
/// <summary>
/// Sets the sums of the descendant trees of each node
/// Complexity: O(n) where n is the number of nodes
/// </summary>
static void SetSums(Node[] nodes)
{
foreach(var node in nodes)
for (var parent = node.Parent; parent != null; parent = parent.Parent)
parent.DescendantsSum += node.Val;
}
/// <summary>
/// Gets the minimum difference between the sum of
/// two trees that result from severing a branch.
/// </summary>
static int MinDiff(Node[] nodes, Node root)
{
return nodes
.Skip(1)
.Min(node => Math.Abs(root.TreeSum - 2 * node.TreeSum));
}
static void Main(String[] args)
{
string curdir = Directory.GetCurrentDirectory();
System.IO.StreamReader file = new System.IO.StreamReader(
Path.GetFullPath(Path.Combine(curdir, @"..'..'", "TestFiles''SampleInput.txt"))
);
int N = Int32.Parse(file.ReadLine());
int[] vals = Array.ConvertAll(file.ReadLine().Split(' '), Int32.Parse);
Node[] nodes = vals.Select(val => new Node() { Val = val }).ToArray();
for (int i = 0, n = N - 1; i < n; ++i)
{
int[] pair = Array.ConvertAll(file.ReadLine().Split(' '), Int32.Parse);
int p = pair[0] - 1, d = pair[1] - 1;
nodes[p].Neighbors.Add(nodes[d]);
nodes[d].Neighbors.Add(nodes[p]);
}
Node root = BuildToTree(nodes);
SetSums(nodes);
Console.WriteLine(MinDiff(nodes, root));
}
}
你的setsum()函数是O(n^2)(考虑一个所有节点都链接到一个列表中的树)。您应该以后序或反向拓扑顺序遍历树,并根据子节点的和计算每个父节点的和。