Kattis挑战赛:电话列表,超过4秒的时间限制,C#

时间:2015-10-20 21:13:18

标签: c# performance time

使用在线自动化测试系统Kattis,我(在C#中)挑战创建电话号码列表的任务,然后找出它们中的任何一个是前缀还是其他。

(参见:https://ncpc.idi.ntnu.no/ncpc2007/ncpc2007problems.pdf,任务A)

提供答案相对容易,但无论我如何尝试,我都无法逃避获得结果:超出时间限制,有一些进一步的信息表明运行程序需要4秒钟(通过自动程序)。

我曾多次尝试从头开始重写它,并且我已经尝试了我可以在互联网上找到的所有现有建议。我发现自己完全不知所措,主要是因为最终我无法确定究竟出了什么问题。

This code被建议用于类似(但尚未解决)的thread,并没有做出魔法 - 但它是迄今为止我见过的最好的:

.*

有什么建议吗?

2 个答案:

答案 0 :(得分:0)

您是否尝试在添加所有数字后按字母顺序对电话号码列表进行排序,然后检查项目n + 1是否以项目n开头?

phoneNumbersList.Sort((x,y) => string.Compare(x, y));

var consistent = true;
for (var j = 0; j < phoneNumbersList.Count - 1; ++j)
{
   if (phoneNumbersList[j + 1].StartsWith(phoneNumbersList[j]))
   {
        consistent = false;
        break;
   }
}

Console.WriteLine(consistent ? "YES" : "NO");

答案 1 :(得分:0)

并不总是最短和最好是最好的:-)尝试以下方法:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Samples
{
    class PhoneListProcessor
    {
        const int MaxCount = 10000;
        const int MaxDigits = 10;
        Dictionary<int, bool> phoneNumberInfo = new Dictionary<int, bool>(MaxCount * MaxDigits);
        public bool Process(IEnumerable<string> phoneNumbers, bool readToEnd)
        {
            phoneNumberInfo.Clear();
            using (var e = phoneNumbers.GetEnumerator())
            {
                while (e.MoveNext())
                {
                    if (Process(e.Current)) continue;
                    if (readToEnd)
                    {
                        while (e.MoveNext()) { }
                    }
                    return false;
                }
            }
            return true;
        }
        bool Process(string phoneNumber)
        {
            var phoneNumberInfo = this.phoneNumberInfo;
            int phoneCode = 0;
            int digitPos = 0;
            bool hasSuffix = true;
            while (true)
            {
                phoneCode = 11 * phoneCode + (phoneNumber[digitPos] - '0' + 1);
                bool isLastDigit = ++digitPos >= phoneNumber.Length;
                bool isPhoneNumber;
                if (hasSuffix && phoneNumberInfo.TryGetValue(phoneCode, out isPhoneNumber))
                {
                    if (isPhoneNumber || isLastDigit) return false;
                }
                else
                {
                    phoneNumberInfo.Add(phoneCode, isLastDigit);
                    if (isLastDigit) return true;
                    hasSuffix = false;
                }
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var processor = new PhoneListProcessor();
            int testCount = int.Parse(Console.ReadLine());
            for (int testIndex = 0; testIndex < testCount; testIndex++)
            {
                int count = int.Parse(Console.ReadLine());
                var numbers = Enumerable.Range(0, count).Select(_ => Console.ReadLine());
                bool readToEnd = testIndex + 1 < testCount;
                bool valid = processor.Process(numbers, readToEnd);
                Console.WriteLine(valid ? "YES" : "NO");
            }
        }
    }
}

基本上做的是在任务约束和细节下动态构建并使用dictionary prefix trie的变体。每个电话号码或前缀被编码为基数11的整数,没有零(每个数字递增,因此而不是0-9,我们有1-10),以便区分具有前导零的数字与相同的数字而没有前导零请求。