一种思路是直接对 n 个数排序,然后两个指针一个从小到大,另一个从大到小遍历数组,如果和等于 m 输出即可;如果和小于 m,则小的指针递增;如果和大于 m,则大的指针递减,直至两个指针相遇。但是数据个数很大,如此遍历会超时。
考虑到每个数的范围不超过500,因此可以采用散列的思想进行另一种方式的排序。
注意 i == j 的情况,必须散列值大于 1 时才可输出,因为只有一张钱币面值为 i (或 j)的情况是不满足的。
三、参考代码
#include<cstdio>
using namespace std;
int h[505] = { 0 };
int main() {
int n, m, t;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%d", &t);
h[t]++;
}
int i = 1, j = 505;
while (i < j) {
while (!h[i]) i++;
while (!h[j]) j--;
if (i + j == m && i < j) {
printf("%d %d\n", i, j);
return 0;
}
else if (i + j < m) i++;
else if (i + j > m) j--;
}
if (i == j && h[i] >= 2)
printf("%d %d\n", i, j);
else
printf("No Solution\n");
return 0;
}
四、解题感悟
所谓的散列排序(桶排序、基数排序)?O(n) ?
也可以直接判断 m - i 的散列值是否大于 0,这样更简便。散列表需要开得大一些,同时 i == m - i 时需要散列值大于 1。