使用在线自动化测试系统Kattis,我(在C#中)挑战创建电话号码列表的任务,然后找出它们中的任何一个是前缀还是其他。
(参见:https://ncpc.idi.ntnu.no/ncpc2007/ncpc2007problems.pdf,任务A)
提供答案相对容易,但无论我如何尝试,我都无法逃避获得结果:超出时间限制,有一些进一步的信息表明运行程序需要4秒钟(通过自动程序)。
我曾多次尝试从头开始重写它,并且我已经尝试了我可以在互联网上找到的所有现有建议。我发现自己完全不知所措,主要是因为最终我无法确定究竟出了什么问题。
This code被建议用于类似(但尚未解决)的thread,并没有做出魔法 - 但它是迄今为止我见过的最好的:
.*
有什么建议吗?
答案 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),以便区分具有前导零的数字与相同的数字而没有前导零请求。