C# 这不是一个O(n)算法吗?

C# 这不是一个O(n)算法吗?,c#,algorithm,tree,time-complexity,C#,Algorithm,Tree,Time Complexity,我试图弄明白为什么我的算法通过了所有没有超时的测试用例。据我所知,这是一个O(n)算法,因为它是一系列O(n)算法的执行。这让我很好奇为什么它会超时。我想不出一种方法可以显著减少这里所涉及的操作数量(我想通过使用更精简的数据结构来实现一些轻微的操作,但这并不能降低复杂性) 使用系统; 使用System.Collections.Generic; 使用System.IO; 使用System.Linq; /// /// ///解决方案https://www.hackerrank.com/chall

我试图弄明白为什么我的算法通过了所有没有超时的测试用例。据我所知,这是一个O(n)算法,因为它是一系列O(n)算法的执行。这让我很好奇为什么它会超时。我想不出一种方法可以显著减少这里所涉及的操作数量(我想通过使用更精简的数据结构来实现一些轻微的操作,但这并不能降低复杂性)

使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
/// 
/// 
///解决方案https://www.hackerrank.com/challenges/cut-the-tree
/// 
///算法说明:
/// 
///给一棵像树一样的树
/// 
///Val=100
///           \
///Val=200
///           /   \
////Val=100
///Val=100
///     /       \
///Val=500 Val=600
///
///为每个节点设置一个字段,显示值的总和
///在根为该节点的子树中,使其成为
/// 
///Val=100
///总和=1600
///           \
///Val=200
///总和=1500
///          /   \
////Val=100
////Sum=100
///Val=100
///总和=1200
///     /        \
///Val=500 Val=600
///总和=500总和=600
/// 
///这样我们就可以很容易地找到两个变量之和之间的最小差值
///断开分支后产生的两棵树:如果根节点
///是R,我们连接节点N,那么两者之间的区别是什么
///总和是| R.Sum-2*N.Sum |。
///
/// 
类节点
{
公共int Val{get;set;}
公共节点父节点{get;set;}=null;
公共列表邻居{get;set;}=new List();
/// 
///子节点中的值之和
///    
公共int子体sum{get;set;}=0;
/// 
///根为此节点的树中的值之和
/// 
public int TreeSum{get{return Val+genderantssum;}}
}
类解决方案
{
/// 
///在节点之间建立父关系
///复杂性:O(n),其中n是节点数
/// 
静态节点BuildToTree(节点[]节点)
{
节点根=节点[0];//使用任意节点作为根
var Q=新队列();
排队(根);
而(Q.Count>0)
{
var current=Q.Dequeue();
foreach(当前.nextries.Where(nbr=>nbr!=current.Parent&&nbr.Parent==null)中的var邻居)
{
邻居。父项=当前;
排队(邻居);
}
}
返回根;
}
/// 
///设置每个节点的子代树的总和
///复杂性:O(n),其中n是节点数
/// 
静态无效集合(节点[]节点)
{
foreach(节点中的var节点)
for(var parent=node.parent;parent!=null;parent=parent.parent)
parent.degenantssum+=node.Val;
}
/// 
///获取两个值之和之间的最小差值
///因切断一根树枝而导致的两棵树。
/// 
静态int MinDiff(节点[]节点,节点根)
{
返回节点
.Skip(1)
.Min(node=>Math.Abs(root.TreeSum-2*node.TreeSum));
}
静态void Main(字符串[]参数)
{
字符串curdir=Directory.GetCurrentDirectory();
System.IO.StreamReader文件=新的System.IO.StreamReader(
Path.GetFullPath(Path.Combine(curdir,@.\..\,“TestFiles\\SampleInput.txt”))
);
intn=Int32.Parse(file.ReadLine());
int[]vals=Array.ConvertAll(file.ReadLine().Split(“”),Int32.Parse);
Node[]nodes=vals.Select(val=>newnode(){val=val}).ToArray();
对于(int i=0,n=n-1;i
您的SetSums()函数是O(n^2)(考虑一棵树,其中所有节点都链接到一个列表中)。您应该按后序或反向拓扑顺序遍历树,并根据其子树的和计算每个父树的和。

O(n)算法可能会超时,如果它们足够慢。树在插入过程中通常是对数(n)的,对吗?也许你在思考它。强烈地考虑把它移到时间复杂度是主要话题的地方。那里的许多计算机科学家应该能够帮助解决这类问题。如果您确实移动了它,请确保首先从此处删除它,然后将其发布到那里;交叉发布是非常不受欢迎的。算法的复杂性与其执行时间几乎没有关系。无论是对于列表中的每个成员,算法都会打印该成员,还是生成斐波那契序列的第百万位,它仍然是O(n)。看起来您正在计算此处所有节点的后代。这意味着您要为每个同级节点重复计算祖先。这不在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));
    }
}