Kattis Challenge: Phone List, 4-Second Time Limit Exceeded, C#

邮差的信 提交于 2020-01-25 03:04:07

问题


Using the online automated testing system Kattis, I'm challenged (in C#) with the task of creating a list of phone numbers then finding out if any of them is a prefix or another.

(see: https://ncpc.idi.ntnu.no/ncpc2007/ncpc2007problems.pdf, task A)

Providing the answer was relatively easy, but no matter how I try I cannot escape getting the Result: Time Limit Exceeded, with some further information saying it took over 4 seconds to run the program (by an automated program).

I have tried rewriting it from scratch several times, and I've tried every existing suggestion I could find available on the internet. I find myself at a total loss at what to do, mostly because in the end I cannot be sure what is actually wrong.

This code was suggested on a similar (but unresolved) thread, and did not do the magic - yet it's the finest I've seen thus far:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PhoneList
{
class Program
{
    static void Main(string[] args)
    {
        // Save number of test cases.
        var numTestCases = int.Parse(Console.ReadLine());

        // Do this for each test case.
        for (int i = 0; i < numTestCases; i++)
        {
            // Save number of phone numbers.
            var numPhoneNumbers = int.Parse(Console.ReadLine());

            // Save all phonenumbers in the list.
            var phoneNumbersList = new List<string>();
            for (int j = 0; j < numPhoneNumbers; j++)
            {
                string number = Console.ReadLine().Trim();

                // Add to list.
                phoneNumbersList.Add(number);
            }

            // Write output.
            if (phoneNumbersList.All(n => !phoneNumbersList.Except(new[] { n }).Any(o => o.StartsWith(n))))
            {
                Console.WriteLine("YES");
            }
            else
            {
                Console.WriteLine("NO");
            }
        }
    }
}
}

Any suggestions?


回答1:


Have you tried sorting the phone numbers list (alphabetically) once all the numbers are added, and then checking if item n+1 starts with item 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");



回答2:


Not always the shortest and finest is the best :-) Try the following:

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");
            }
        }
    }
}

Basically what is does is building on the fly and using a variant of a dictionary prefix trie under the task constraints and specifics. Each phone number or prefix is encoded as integer number of base 11 with no zeroes (each digit is incremented, so instead of 0-9 we have 1-10) in order to distinguish numbers with leading zeroes from the same numbers without leading zeroes as requested.



来源:https://stackoverflow.com/questions/33246887/kattis-challenge-phone-list-4-second-time-limit-exceeded-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!