【发布时间】:2019-09-17 03:37:08
【问题描述】:
免责声明 这是我的课程练习,而不是正在进行的比赛。
问题描述
问题描述很直接:
给定两个数组,A 和 B,分别包含 n 和 m 个元素。您需要排序的数字是 Ai*Bj ,对于 1
令 C 是这种排序的结果,是一个非递减的元素序列。打印这个序列的每第十个元素的总和,即 C1 + C11 + C21 + ... 。
1
1
内存限制:512MB
时间限制:2秒
到目前为止我的解决方案
首先我使用Java,使用Arrays.sort,给定最大的n,m。我们需要对一个大小为 36000000 的数组进行排序。然后遍历数组中的每 10 个元素以获得总和。这通过了 23 个测试用例,其余的通过了 TLE。
然后我切换到C++,同样使用内置的排序方法,结果稍微好一点,通过了29个测试用例。
我的观察
给定这个输入
4 4
7 1 4 9
2 7 8 11
如果我们先对两个数组 A 和 B 进行排序,然后将它们相乘,我们得到
2 8 14 18 7 28 49 63 8 32 56 72 11 44 77 99
这是一个包含 m 个已排序子数组的数组。 但是我想不出任何好的解决方案来将所有这些排序的子数组合并到 O(mn) 或附近的某个地方。或者我们需要换个角度看问题,将两个数组的每个元素相乘是否有什么特殊的性质?
更新 1: - 使用 MinHeap - 不够快。 [TLE]
更新 2: - 使用 k 方式合并 - 仍然不够快。 [TLE]
更新 3: - 我忘了提到 A 和 B 中的元素范围,所以我刚刚更新了它。
更新 4: - 基数排序基数 256 [已接受]
结论
通过这个问题,我了解了更多关于一般排序的知识,以及一些关于使用 Java 和 C++ 库进行排序的有用信息。
C++ 中内置的排序方法,比如 std::sort 并不稳定,因为它基本上是一种快速排序,但是当数据格式不利于快速排序时,它会切换到归并排序,但总的来说它是最快的内置的 C++ 排序(除了 qsort、stable_sort)。
对于 Java,有 3 种排序类型,一种是 Arrays.sort(primitive[]),它在底层使用归并排序,Arrays.sort(Object[]),它使用 Timsort 和 Collections.sort它基本上调用 Arrays.sort 来完成繁重的处理工作。
非常感谢@rcgldr 的基数排序基数 256 C++ 代码,它在 6000*6000 元素的更坏情况下工作起来就像一个冠军,最大运行时间为 1.187 秒。
- 有趣的是,C++ 的 std::sort 仅在最后 3 个最大的测试用例中失败,它适用于大小为 6000*3000 的输入。
【问题讨论】:
-
couldn't think of any good solution to merge all of these sorted subarrays in O(n)你脑子里最想念的事情是什么? (我想我是在问 O(mn log(min(m, n)) 会做吗?) -
(未指定为非负数的元素并不完全有帮助。)
-
@greybeard 他们都是非负数,你有解决方案吗?如果是的话,你能给我一点提示吗?因为只是正常的排序是行不通的,不管排序步骤有多好。
-
(我想提到 O(mn log(min(m, n))) 是一个提示;也应该适用于混合符号.)
-
你的意思是循环遍历数组C,然后在A或B中进行某种二分查找,这样我们就可以知道C排序时那个元素的顺序?跨度>
标签: java c++ algorithm sorting