找到相隔至少5分钟进行的两次测量的最小平方和

时间:2015-03-03 01:06:48

标签: algorithm python-3.x

我正在尝试在Python3中解决这个问题。我知道如何找到min1和min2,但我不知道如何在一次传递中搜索5个元素。

问题陈述

输入程序以 1 分钟的间隔提供设备执行的测量。所有数据的自然数均不超过 1000 问题是要找到间隔不小于5分钟的两次测量的最小平方和。第一行将包含一个自然数 - 测量次数 N < / em>的。保证 5&lt; N <= 10000 。以下 N 行中的每一行都包含一个自然数 - 下一次测量的结果。

你的程序应该输出一个数字,这是两次测量的平方的最小和,间隔不小于5分钟。

示例输入: 9 12 45 的 5 4 21 20 10 的 12 26

预期产出:169

2 个答案:

答案 0 :(得分:0)

我喜欢这个问题。有趣的脑筋急转弯。 :)

我注意到你的样本输入是range(1, 100)中的所有整数并且有一些重复,所以我生成了如下样本列表:

>>> import random                                                           
>>> sample_list = [random.choice(range(1, 100)) for i in range(10)]         
>>> sample_list                                                             
[74, 68, 57, 18, 36, 8, 89, 73, 77, 80]

根据问题陈述,这些数字代表以一分钟为间隔测量的数据,我们的一个限制是我们的结果必须代表至少相隔五分钟收集的数据。最终,这意味着原始列表中的数据索引必须相差至少五个。换句话说,对于任何两个输入v1v2

abs(sample_list.index(v1) - sample_list.index(v2)) >= 5

必须是真的。我们也知道我们正在寻找最小的总和,所以先查看最小的数字会有所帮助。

因此,我首先将sample_list中的值映射到它们出现的索引,然后对它们进行排序:

>>> occurrences = {}                                                        
>>> for index, value in enumerate(sample_list):                             
...   try:                                                                          
...     occurrences[value].append(index)                                        
...   except KeyError:                                                      
...     occurrences[value] = [index]                                        
...                                                                         
>>> occurrences                                                             
{80: [9], 18: [3], 68: [1], 73: [7], 89: [6], 8: [5], 57: [2], 74: [0], 77: [8], 36: [4]}
>>> sorted_occurrences = sorted(occurrences)
>>> sorted_occurrences
[8, 18, 36, 57, 68, 73, 74, 77, 80, 89]

经过大量的反复试验,这就是我最终在函数形式中提出的内容(包括之前讨论过的一些内容):

def smallest_sum_of_squares_five_apart(sample):
    occurrences = {}
    for index, value in enumerate(sample):
        try:
            occurrences[value].append(index)
        except KeyError:
            occurrences[value] = [index]
    sorted_occurrences = sorted(occurrences)
    least_sum = 0
    for index, v1 in enumerate(sorted_occurrences):
        if least_sum and v1**2 > least_sum:
            return least_sum
        for v2 in sorted_occurrences[:index+1]:
            if (abs(max(occurrences[v1]) - min(occurrences[v2])) >= 5 or
                    abs(max(occurrences[v2]) - min(occurrences[v1])) >= 5):
                print('Found candidates:', str((v1, v2)))
                sum_of_squares = v1**2 + v2**2
                if not least_sum or sum_of_squares < least_sum:
                    least_sum = sum_of_squares
    return least_sum

这里的想法是:

  • 首先查看最小值。
  • 将它们逐一与所有较小的值进行比较,直至自己。
  • 根据我们的标准检查每个。请注意,我们通过检查每个的极值来做到这一点,这两个数字在原始样本中距离彼此最远。
  • 在检查时变得毫无意义。

不幸的是,找到第一个是不够的。根据列表的构造方式,它不会总是以这种方式找到最小的对。实际上,它不适用于您自己的样本输入。但是,一旦v1**2(较大值的平方)大于总和,我们知道,因为所有数字都是自然数,所以继续查看是没有意义的。

我在下面列出了完整的可运行实现。它需要一个命令行参数(默认值为10),表示随机生成的样本中所需的项目数。它将打印随机生成的样本以及它检查的所有候选对,最后是总和本身。我已经多次在10个大小的输入上检查了这个,它似乎一般都在工作。但是,如果不正确,欢迎提供反馈。另请注意,您可以从问题中取消注释示例列表,看看它是如何工作的(并且它得到了正确答案)。

import random
import sys

def smallest_sum_of_squares_five_apart(sample):
    occurrences = {}
    for index, value in enumerate(sample):
        try:
            occurrences[value].append(index)
        except KeyError:
            occurrences[value] = [index]
    sorted_occurrences = sorted(occurrences)
    least_sum = 0
    for index, v1 in enumerate(sorted_occurrences):
        if least_sum and v1**2 > least_sum:
            return least_sum
        for v2 in sorted_occurrences[:index+1]:
            if (abs(max(occurrences[v1]) - min(occurrences[v2])) >= 5 or
                    abs(max(occurrences[v2]) - min(occurrences[v1])) >= 5):
                print('Found candidates:', str((v1, v2)))
                sum_of_squares = v1**2 + v2**2
                if not least_sum or sum_of_squares < least_sum:
                    least_sum = sum_of_squares
    return least_sum


if __name__ == '__main__':
    try:
        r = int(sys.argv[1])
    except IndexError:
        r = 10
    sample_list = [random.choice(range(1, 100)) for i in range(r)]
    #sample_list = [9, 12, 45, 5, 4, 21, 20, 10, 12, 26]
    print(sample_list)
    print(smallest_sum_of_squares_five_apart(sample_list))

答案 1 :(得分:0)

试试这个:

#!/usr/bin/env python3
import queue

inp = [9,12,45,5,4,21,20,10,12,26]

q        = queue.Queue()                         #Make a new queue
smallest = False                                 #No smallest number, yet
best     = False                                 #No best sum of squares, yet
for x in inp:
  q.put(x)                                       #Place current element on queue
  #If there's an item from more than five minutes ago, consider it
  if q.qsize()>5:
    temp = q.get()    #Pop oldest item from queue into temporary variable
    if not smallest:  #If this is the first item more than 5 minutes old
      smallest = temp #it is the smallest item by default
    else:             #otherwise...
      smallest = min(temp,smallest) #only store it if it is the smallest yet

    #If we have no best sum of squares or the current item produces one, then
    #save it as the best
    if (not best) or (x*x+smallest*smallest<best):
      best = x*x+smallest*smallest

print(best)

我的想法是走遍队列,跟踪我们已经看到的最小元素,这个元素超过五分钟,并将它与最新元素进行比较,跟踪我们前进的最小平方和。

我认为如果你仔细想想,你会发现答案非常直观。

该算法在O(N)时间内运行。