【问题标题】:Reducing time complexity of the code降低代码的时间复杂度
【发布时间】:2015-09-02 08:26:34
【问题描述】:

我有以下代码,但处理 BigInteger 类型的 52957 个输入需要 20 秒。这是我要解决的问题https://www.hackerearth.com/problem/algorithm/girlfriends-demands/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
namespace girldfriends_demands
{
    class Program
    {
        private static string inputString = String.Empty;
        private static int testCases=0;
        private static BigInteger[,] indexArray;
        static void Main(string[] args)
        {
            initialize();
            printDemand();
            Console.ReadLine();
        }
        private static void initialize()
        {
            inputString = Console.ReadLine();
            testCases = int.Parse(Console.ReadLine());
            indexArray = new BigInteger[testCases, 2];
            for (int i = 0; i < testCases; i++)
            {
                string[] tokens = Console.ReadLine().Split();
                indexArray[i, 0] = BigInteger.Parse(tokens[0]);
                indexArray[i, 1] = BigInteger.Parse(tokens[1]);
            }
        }

        private static void printDemand()
        {
            char[] convertedString = inputString.ToCharArray();
            for (int i = 0; i < testCases; i++)
            {

                BigInteger length=inputString.Length;
                BigInteger startf, endf; ; 
                BigInteger.DivRem(indexArray[i, 0] - 1,length,out startf);
                BigInteger.DivRem(indexArray[i, 1]-1,length,out endf);
                char c=convertedString[((int)startf)];
                char e=convertedString[((int)endf)];
                if(c==e)
                {
                    Console.WriteLine("Yes");
                }
                else
                {
                    Console.WriteLine("No");
                }
            }
        }
    }
}

请说明如何降低代码的时间复杂度。此程序获取字符串中指定位置的字母,如果相同则打印 true,否则为 false。在循环之前计算范围也无济于事

【问题讨论】:

  • 你也有示例输入集吗? Console.WriteLine 速度很慢 - 在循环结束时写入内存/转储输出更快。
  • @OndrejSvejdar 这是示例输入
  • 20 秒?这太荒谬了。你到底想做什么?为什么不直接比较两个字符串,而不是将它们转换为BigInteger,然后做复杂的数学运算呢?您正在做大约一百万件不必要的事情(为什么将 inputString 转换为 char[]?为什么一次将所有数据加载到内存中而不是逐行处理?为什么要让事情如此痛苦的程序化?你来自 Pascal背景?
  • 什么是 DivRem。它是分治算法吗?
  • @Luaan 必须比较字符串的特定字符,并且该字符由输入中的索引指定

标签: c# console-application time-complexity


【解决方案1】:

为什么你使用 BigInteger ? 在任何情况下,string.length 都是 int 的类型。 这意味着如果您的字符串超过2147483647 (2^31 -1),您的程序将被破坏。

我认为将BigInteger 更改为int 会有所帮助。

【讨论】:

  • @Luaan 是的,你是对的,我编辑了答案。 (我指的是单个对象,但在我们的例子中并不重要。)
  • 在给定的约束中 1 ≤ |S| ≤ 10^5。另请参阅问题描述以获取实际问题的链接。您将获得洞察力
  • @AarthnaMaheshwari 听起来不对:10^5 只有 100,000?
  • @MichaelMcMullin 所以在给定的问题中,字符串的长度可以最大为 100000
【解决方案2】:
Console.ReadLine().Split()

是你最大的问题。对于文件中的每一行,您创建一个字符串数组,每个字符串一个字母。这是一个巨大的性能消耗,几乎可以肯定不是你想要的 - 特别是,完全没有必要使用 BigInteger 来存储一位数字......

我假设您实际上想根据某些分隔符将行一分为二。例如,如果您的数字用逗号分隔,您可以使用

Console.ReadLine().Split(',')

即便如此,也没有什么理由使用BigInteger。您尝试执行的操作显然是基于字符串的,并且非常容易使用字符串。但是,我真的无法更具体地帮助您,因为对于如此简单的任务,您的问题描述非常模棱两可,而且代码显然是错误的,猜测您到底是什么完全没用努力去做。

编辑:

好的,您的链接证实了我的假设 - 您大量将其复杂化了。例如,这样的代码就可以了:

var word = Console.ReadLine();
var items = int.Parse(Console.ReadLine());

for (var _ = 0; _ < items; _++)
{
    var indices = 
          Console.ReadLine()
           .Split(' ')
           .Select(i => (int)((long.Parse(i) - 1) % word.Length))
               .ToArray();

    Console.WriteLine(word[indices[0]] == word[indices[1]] ? "Yes" : "No");
}

首先,请注意,数字将始终适合long,这样您就可以避免使用BigIntever。其次,您需要正确使用Split - 在这种情况下,分隔符是一个空格。第三,没有理由不在单个流中进行整个处理——等待整个输入,将其收集到内存中,然后一次输出所有内容,这是对内存的浪费。第四,请注意,在简单的算术运算中加入整个必要机制时,避免大多数复杂检查是多么容易。

每个输入数据的运行时间不到 2 秒,仅使用约 80kiB 的内存。

我认为从意识形态上讲,这非常适合该网站 - 它非常简单明了,适用于所有预期的输入 - 完美的 hack。当然,如果这是针对最终用户应用程序,您可能需要额外检查,但 HackerEarth 网站名称暗示黑客是预期的,真的。

【讨论】:

  • 数字由空格分隔,我必须使用 biginteger 因为输入是这样的 720031795465148928 347859163354280992
  • 我不确定这是否是瓶颈——我认为printDemand() 是需要 20 秒才能执行的方法。 initialize() 方法中的任何低效率都可能会被忽视,因为它正在等待用户输入。
  • @MichaelMcMullin 我也有同感
  • @MichaelMcMullin 你真的认为有人在使用控制台手动输入720031795465148928 347859163354280992 吗?在我看来,它显然是在期待数据被输入。
  • @AarthnaMaheswari 检查我的提交,看看我认为作者的意图。无论如何,我仍然认为您最大的问题是Split - 您尝试过修复它吗?
【解决方案3】:

根据我的经验,频繁的Console.WriteLine 调用会导致执行时间过长。

我认为您应该使用StringBuilder 对象,并将所有输出附加到它,而不是在您想添加一些输出时调用该函数。然后,在for-loop 之后,调用Console.WriteLine 一次以打印StringBuilder 的内容。

这可能不是您的程序最大的问题,但会有所帮助。

【讨论】:

  • 已使用字符串生成器,但仍超出时间限制。
【解决方案4】:

Myabe 通过删除这些行中的强制转换并使用 string.compare 可以减少执行时间

            if(string.Compare(startf.ToString(), endf.ToString()))
            {
                Console.WriteLine("Yes");
                continue;
             }
                Console.WriteLine("No");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    • 2012-07-28
    • 2016-10-07
    相关资源
    最近更新 更多