可能导致错误的极端情况

时间:2017-08-25 11:32:36

标签: python python-3.x

最近我在尝试过去一年的AIO问题,而我无法解决这个问题。

问题如下:

安全破解 输入文件:safein.txt 输出文件:safeout.txt 时间限制:1秒 几个世纪以来,已经赢得了许多战争,而不是通过力量之战,而是斗智斗勇。您的消息来源最近通知您,您的母亲购买了最新电脑游戏WheeZork的预发行副本,并将其隐藏在家中的保险箱中。要打开保险箱,必须通过以正确的顺序将圆形转盘旋转到每个数字来输入一长串数字。

如果在保险箱中输入了正确的数字序列,保险箱将打开,您可以提早偷偷出现您的圣诞礼物。如果序列错误,报警系统将被激活,您将终身接地!幸运的是,你知道你的母亲已经将代码写在床头抽屉里的一张纸上,她喜欢称之为“#34;代码表”。

她常常夸耀她是多么聪明,并向你解释说明表上的数字确实是安全的代码,但是序列中的每个数字都增加了一个常数非负整数k,只有她知道。如果没有这个价值,那么这张纸是没用的,因此只有她可以打开保险箱...或者她认为这样!

为了确定正确的代码,当你解锁保险箱并且你已经设法记住她输入的部分代码时,你已经监视了你的母亲。您不确定这对应于哪个代码部分,但它肯定是代码中连续的数字序列。有了这些知识,你就开始确定保险箱的完整代码。

您的任务是,如果您的母亲在她的代码表上写下了完整的数字列表,并且您知道的更短的序列出现在实际代码中,请确定解锁保险箱的整个序列。

例如,如果保险箱的代码是7,9,4,6,8,12,并且您的母亲已将所有数字增加4,则她的代码表将为11,13,8,10,12,这是因为7 + 4 = 11,给出第一个数字11.第二个数字是通过加9 + 4 = 13得到的。第三个数字是通过加4 + 4 = 8得到的,依此类推。您可能已经看到她按顺序输入数字4,6,8。有了这些知识,您就可以确定整个代码。

输入 输入文件的第一行将包含两个整数,一个b,由空格分隔。整数a是写在母亲代码表上的序列的长度(2 <= a <= 100000)。整数b是您知道的序列的长度,该序列包含在保险箱的代码中(2&lt; = b&lt; = 30)。

接下来是一行,每行包含1到1000000之间的单个整数。这些行是按照母亲的代码表写入的顺序,按照它们输入保险箱的顺序。

接下来将是b行,每行包含一个整数,也在1到1000000之间。这些行描述了实际代码对安全的一瞥。

您可以保证,对于任何给定的输入方案,只有一种可能的解决方案。

输出 您的输出文件应包含一行。这些行中的每一行都应包含一个整数,表示打开保险箱所需的完整数字序列。

我的代码(通过大多数测试用例)如下:

'''program implements a function diff which is returns a list that is the difference of the current elements in the list
to solve the problem, the subset list is reduced until it consists of a single integer
the index of this integer in the original list is then found, before determining the non-negative integer
which was used to encode the numbers'''
def diff(lst):
    lst2=[]
    for i in range(len(lst)-1):
        lst2.append(lst[i+1]-lst[i])
    return lst2
infile = open("safein.txt", "r")
outfile = open("safeout.txt", "w")
a, b = map(int, infile.readline().split())
lst, sub = [], []
for i in range(a):
    lst.append(int(infile.readline()))
for j in range(b):
    sub.append(int(infile.readline()))
temp_sub=sub
temp_lst=lst
k = 0
while len(temp_sub) != 1:
    temp_sub=diff(temp_sub)
    k+=1
for x in range(k):
    temp_lst=diff(temp_lst)
n = temp_lst.index(temp_sub[0])
m = lst[n]-sub[0]
lst=[x-m for x in lst]
for i in lst:
    outfile.write(str(i) + "\n")

由于此代码通过大多数测试用例,除了一些出错的情况(我不知道它是什么错误),我想知道是否有人可以建议一些会导致此算法创建的错误案例错误。到目前为止,我所想到的所有案例都已通过。

编辑: 正如niemmi在下面指出的那样,我的上述算法无法处理一些侧面情况。因此,我重写了另一种算法来解决它。该算法通过大多数测试用例,除了执行时间超过1秒外没有任何错误。任何人都可以帮助减少此解决方案的时间复杂度吗?

def subset(lst1, lst2):
    if lst2[0] in lst1:
        idx = lst1.index(lst2[0])
        for i in range(len(lst2)):
            if lst2[i]==lst1[idx+i]:
                continue
            else:
                return False
    else:
        return False
    return True

infile = open("safein.txt", "r")
outfile = open("safeout.txt", "w")

a, b = map(int, infile.readline().split())
lst, sub = [], []
for x in range(a):
    lst.append(int(infile.readline()))
for y in range(b):
    sub.append(int(infile.readline()))

if subset(lst, sub):
    for i in range(a):
        outfile.write(str(int(lst[i])) + "\n")
    infile.close()
    outfile.close()
    exit()

i=1
while True:
    temp_sub = [x+i for x in sub]
    if subset(lst, temp_sub):
        lst = [x-i for x in lst]
        for j in range(a):
            outfile.write(str(int(lst[j])) + "\n")
        infile.close()
        outfile.close()
        exit()
    i+=1

编辑: 感谢niemmi,他提供了一个下面的解决方案,我稍微编辑了一个测试用例,返回错误。

def diff(seq):
    return (seq[i - 1] - seq[i] for i in range(1, len(seq)))


with open('safein.txt') as in_file:
    a, b = (int(x) for x in in_file.readline().split())
    code = [int(in_file.readline()) for _ in range(a)]
    plain = [int(in_file.readline()) for _ in range(b)]

code_diff = tuple(diff(code))
plain_diff = tuple(diff(plain))

k = 0
def index(plain_diff, code_diff, plain, code, a, b, k):
    for i in range(k, a - b):
        for j, x in enumerate(plain_diff, i):
            if code_diff[j] != x:
                break
        else:
            k = code[i] - plain[0]
            break # found match, break outer loop
    return k

k = index(plain_diff, code_diff, plain, code, a, b, k)

with open('safeout.txt', 'w') as out_file:
    out_file.write('\n'.join(str(x - k) for x in code))

谢谢!

1 个答案:

答案 0 :(得分:2)

上述实现重复计算以下行中连续元素的差异:

private void listBoxItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    foreach (var items in listBoxItems.SelectedItems)
    {
        ListBoxItem lbi = listBoxItems.ItemContainerGenerator.ContainerFromItem(items) as ListBoxItem;
        if (lbi != null)
        {
            RadioButton rb = FindVisualChildren<RadioButton>(lbi).FirstOrDefault(x => x.IsChecked == true);
            if (rb != null)
            {
                MessageBox.Show("selected: " + rb.Content.ToString());
            }
        }
    }
}

private static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj != null)
    {
        int NbChild = VisualTreeHelper.GetChildrenCount(depObj);

        for (int i = 0; i < NbChild; i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);

            if (child != null && child is T)
            {
                yield return (T)child;
            }

            foreach (T childNiv2 in FindVisualChildren<T>(child))
            {
                yield return childNiv2;
            }
        }
    }
}

在第一轮while len(temp_sub) != 1: temp_sub=diff(temp_sub) k+=1 temp_sub之后针对示例输入运行时,在第二轮和最后一轮之后运行[2, 2]。然后,实现继续对包含增加的代码[0]的{​​{1}}进行相同类型的缩减。

然后temp_lst用于查找来自[-7, 7, 0, 2]的{​​{1}}值的索引,然后用于推导k。如果在您尝试查找的索引之前index上有另一个0值,则此方法显然不会起作用。我们可以很容易地在这种情况下创建输入,例如在代码表的开头添加temp_lst两次,这样整个工作表就是0

编辑为什么不使用后续数字差异的初始方法来查找temp_lst?下面的代码在代码表上循环,并且对于每个位置检查普通序列是否可以从那里开始,即如果数字等于或大于普通序列中的第一个数字,因为11被定义为非负整数。然后它在代码表和普通序列上循环遍历下一个[11, 11, 11, 13, 8, 10, 12, 16]数字,以查看差异是否匹配。

最差时间复杂度 O(ab),如果不够好,您可以利用KMP来加快匹配。

k