题目描述
Description
美团外卖的品牌代言人袋鼠先生最近正在进行音乐研究。他有两段音频,每段音频是一个表示音高的序列。现在袋鼠先生想要在第二段音频中找出与第一段音频最相近的部分。
具体地说,就是在第二段音频中找到一个长度和第一段音频相等且是连续的子序列,使得它们的 difference 最小。两段等长音频的 difference 定义为:
d i f f e r e n c e = S U M ( a [ i ] − b [ i ] ) 2 ( 1 ≤ i ≤ n ) {difference = SUM(a[i] - b[i])^2 (1 ≤ i ≤ n)} difference=SUM(a[i]−b[i])2(1≤i≤n)
其中SUM()表示求和,其中 n 表示序列长度, a [ i ] , b [ i ] {a[i], b[i]} a[i],b[i]分别表示两段音频的音高。现在袋鼠先生想要知道,difference的最小值是多少?数据保证第一段音频的长度小于等于第二段音频的长度。
Input
第一行一个整数n(1 ≤ n ≤ 1000),表示第一段音频的长度。
第二行n个整数表示第一段音频的音高(0 ≤ 音高 ≤ 1000)。
第三行一个整数m(1 ≤ n ≤ m ≤ 1000),表示第二段音频的长度。
第四行m个整数表示第二段音频的音高(0 ≤ 音高 ≤ 1000)。
Output
输出difference的最小值
|
|
---|---|
2 1 2 4 3 1 2 4 | 0 |
算法思路
数学求解
这题题干有点迷惑性,笔者一开始就理解错题意想复杂了。它所谓的找相近序列就是单纯的找连着数字个数一样的,跟数字大小没关系。
这就简单了,例如给的样例数列“1 2”与“3 1 2 4”,前者俩数,那就从后者里提取也是俩数的子数列就完了,“3 1”、“ 1 2”、“2 4”,没了。
相似片段找出来了,开始算吧,题目中给出了 difference 的计算公式,那里面 a [ i ] , b [ i ] {a[i], b[i]} a[i],b[i]里的 i,就是数字的位序。以“3 1”举例:
d i f f e r e n c e = S U M ( a [ i ] − b [ i ] ) 2 = ( 1 − 3 ) 2 + ( 2 − 1 ) 2 = 5 {difference = SUM(a[i] - b[i])^2 =(1-3)^2+(2-1)^2=5} difference=SUM(a[i]−b[i])2=(1−3)2+(2−1)2=5
由此,示例中给出的数据,求得difference的值应该有仨:5、0、5,故最小值输出为0。
代码设计
没啥难的,注意存储每次循环求得的 difference 值就得了,c 语言求数组最小值应该得自己写。Python 没数组有列表,列表求最大最小值有现成函数 max 和 min 。
不过 c 语言如果是先储存,再判断最小值再输出,会多出一组循环,可以把判断算法揉进去,只存储当前最小值,每次计算出一个 difference 就立刻比对,不断的更新min值。
代码实现
C
#include <stdio.h>
int main(void){
int a,b;
int line[1000],line1[1000];
int i,j,z;
int min,sum;
scanf("%d",&a);
for(i=0;i<a;i++){
scanf("%d",&line[i]);
}
scanf("%d",&b);
for(i=0;i<b;i++){
scanf("%d",&line1[i]);
}//至此完成所有的输入
for(i=0;i<=(b-a);i++){
sum=0;
for(j=0;j<a;j++){
z = line[j]-line1[j+i];
sum=sum+z*z;
}
if(i==0){
min=sum;
}
if(sum<min){
min=sum;
}//随时更新最小值,只存储当前最小值
}
printf("%d",min);
return 0;
}
Python
n = int(input())
line = list(map(int, input().split()))
m = int(input())
line1 = list(map(int, input().split()))
a = []
for i in range(m - n + 1):
count = 0
for j in range(n):
count += (line[j] - line1[j + i]) ** 2
a.append(count)
print(min(a))
JAVA
待续