题目如下:
给定 N 张卡片,正面分别写上 1、2、……、N,然后全部翻面,洗牌,在背面分别写上 1、2、……、N。将每张牌的正反两面数字相减(大减小),得到 N 个非负差值,其中是否存在相等的差?
输入格式:
输入第一行给出一个正整数 N(2 ≤ N ≤ 10 000),随后一行给出 1 到 N 的一个洗牌后的排列,第 i 个数表示正面写了 i 的那张卡片背面的数字。
输出格式:
按照“差值 重复次数”的格式从大到小输出重复的差值及其重复的次数,每行输出一个结果。
输入样例:
8
3 5 8 6 2 1 4 7
输出样例:
5 2
3 3
2 2
解决方案:
1.思路:读题:题意为正面的数字分别是1、2、…、N,接着输入洗牌后的数字,拿输入的数字按顺序和正面的数字1、2、3、…、N做减法,看是否有相等的差
用输入样例来举例:
正面数字:1 2 3 4 5 6 7 8
输入数字:3 5 8 6 2 1 4 7
做差以后:2 3 5 2 3 5 3 1
可以看出,差值为2的有两个,差值为三的有3个,差值为5的有两个,然后按照题目要求输出即可。
明白题意后,使用一个差值数组来保存这些差值,然后将这些差值排序,遍历差值数组,如果当前元素的后一个和当前元素不同,而且当前元素出现了不止一次,就可以将当前元素输出。当然,还需要一个变量来记录当前元素的次数。
按照以上思路第一次写代码的时候,却出现了问题,并没有成功通过,下方为有问题的代码:
//将差值放入数组
for(int i = 0; i < N; i++) {
cin >> num;
if(num > i) sub[i] = num - 1 - i; //数比下标大
else sub[i] = i - num + 1; //数字比下标小 i-(num-1)
}
//对差值数组排序
sort(sub, sub + N, cmp);
//遍历数组找不同
for(int i = 0; i < N; i++) {
times++; //从第一个元素开始累积次数,如果达到要求,就将次数归零,然后重新累加
//当时想的是如果重复次数超过1次,而且和后一个元素不同,就输出,然后将times归零
if(sub[i + 1] != sub[i] && times > 1) {
cout << sub[i] << " " << times << endl;
times = 0;
}
}
可是提交的时候却没有通过,有两个测试点是错误的,看了半天并没有发现什么问题,于是只好亲自动手写了几个数据来测试,终于发现了问题:
10
1 7 5 6 8 4 1 6 9 3
洗牌的数字是:1 7 5 6 8 4 1 6 9 3
正面的数字是:1 2 3 4 5 6 7 8 9 10
差值: 0 5 2 2 3 2 6 2 0 7
排序后的数组第一个元素和第二个元素分别是7和6,这时候问题产生了,7和6不同,执行到第二个元素6的时候,按照正常想法应该是times归0,然后继续执行下一个元素;可是代码却在这里输出了6。这是因为判断条件写成了“且”条件,需要同时满足前后元素不同和times > 1两个条件,可是在执行第一个元素7的时候,虽然前后元素不同,可是times只加了1,此时times只是1,并不是2,因此没有输出,同时也没有归0。解决方法是将归0条件从times > 1中提取出来,这样的话前后元素只要出现不同,就将times归0。修正后的代码为:
for(int i = 0; i < N; i++) {
times++;
if(sub[i + 1] != sub[i]) {
if(times > 1) cout << sub[i] << " " << times << endl;
times = 0;
}
}
完整代码:
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int a, int b)
{
return a > b;
}
int main()
{
int N;
int num;
int times = 0;
cin >> N;
int sub[N + 1];
for(int i = 0; i < N; i++) {
cin >> num;
if(num > i) sub[i] = num - 1 - i;
else sub[i] = i - num + 1;
}
sort(sub, sub + N, cmp);
for(int i = 0; i < N; i++) {
times++;
if(sub[i + 1] != sub[i]) {
if(times > 1) cout << sub[i] << " " << times << endl;
times = 0;
}
}
}
大神的解答:
柳神的方法是:将差值作为数组的下标,一旦产生一个差值,就将对应的元素的值+1,最后遍历数组,将元素值大于2的输出。比如产生差值为3,就把数组第四个元素a[3]加一,最后输出下标3和对应的元素值。
柳神的解析:PAT 1083. 是否存在相等的差 (20) - 乙级
附柳神的代码:
#include <iostream>
using namespace std;
int main() {
int n, t, a[10000] = {0};
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> t;
a[abs(t-i)]++;
}
for (int i = 9999; i >= 0; i--)
if (a[i] >= 2) cout << i << " " << a[i] << endl;
return 0;
}