(我的代码是用Java编写的,但问题是不可知的;我只是在寻找算法的想法)
这就是问题所在:我做了一个方法,只是找到数据集的中位数(以数组的形式给出)。这是实施:
public static double getMedian(int[] numset) {
ArrayList<Integer> anumset = new ArrayList<Integer>();
for(int num : numset) {
anumset.add(num);
}
anumset.sort(null);
if(anumset.size() % 2 == 0) {
return anumset.get(anumset.size() / 2);
} else {
return (anumset.get(anumset.size() / 2)
+ anumset.get((anumset.size() / 2) + 1)) / 2;
}
}
我去的学校的老师然后挑战我写一个方法再次找到中位数,但没有使用任何数据结构。这包括任何可以容纳多个值的东西,所以包括字符串,任何形式的数组等等。我花了很长时间试图想出一个想法,我很难过。有什么想法吗?
答案 0 :(得分:5)
该任务的通常算法是Hoare的Select算法。这非常类似于快速排序,除了在快速排序中您在分区后递归排序两个一半,但对于select,您只在包含感兴趣项目的分区中执行递归调用。
例如,让我们考虑这样的输入,我们将在其中找到第四个元素:
[7,1,17,21,3,12,0,5]
我们随意使用第一个元素(7
)作为我们的支点。我们最初将它拆分为(带有标记为*:
[1,3,0,5,] * 7,[17,21,12]
我们正在寻找第四个元素,而7是第五个元素,所以我们然后分区(仅)左侧。我们将再次使用第一个元素作为我们的支点,使用{
和}
来标记我们现在只是忽略的输入部分。
[0] 1 [3,5] {7,17,21,12}
1
最终成为第二个元素,所以我们需要将项目分区到右边(3和5):
{0,1} 3 [5] {7,17,21,12}
使用3
作为枢轴元素,我们最左边没有任何内容,右边是5
。 3
是第三个元素,因此我们需要向右看。这只是一个元素,因此(5
)是我们的中位数。
通过忽略未使用的一面,这降低了从排序的O(n log n)到仅O(N)的复杂性[虽然我有点滥用符号 - 在这种情况下我们是&#39;处理预期的行为,而不是最坏的情况,正如大O通常所做的那样。
如果你想确保良好的行为(以牺牲平均速度稍慢为代价),还有中位数算法的中位数。
这保证了O(N)的复杂性。
答案 1 :(得分:1)
Sort数组到位。当你正在做的时,把元素放在数组的中间。无需额外存储空间。
在Java中花费n log n
时间左右。最佳时间是线性的(您必须至少检查一次每个元素,以确保您得到正确的答案)。出于教学目的,额外的复杂性降低是不值得的。
如果您无法修改阵列,则必须交换额外的时间复杂度,以避免使用与输入大小一半成比例的额外存储。 (如果您愿意接受近似值,情况并非如此。)
答案 2 :(得分:1)
一些效率不高的想法:
对于数组中的每个值,遍历数组,计算低于当前值的值的数量。如果该计数是数组长度的“一半”,则为中位数。 O(n ^ 2)(需要考虑一下如何处理中值的重复。)
您可以通过跟踪到目前为止的最小值和最大值来稍微改善性能。例如,如果您已经确定50太高而不是中位数,那么您可以跳过数组中的每个值大于或等于50的计数传递。同样,如果您已经确定25如果太低,您可以跳过每个小于或等于25的值的计数传递。
在C ++中:
int Median(const std::vector<int> &values) {
assert(!values.empty());
const std::size_t half = values.size() / 2;
int min = *std::min_element(values.begin(), values.end());
int max = *std::max_element(values.begin(), values.end());
for (auto candidate : values) {
if (min <= candidate && candidate <= max) {
const std::size_t count =
std::count_if(values.begin(), values.end(), [&](int x)
{ return x < candidate; });
if (count == half) return candidate;
else if (count > half) max = candidate;
else min = candidate;
}
}
return min + (max - min) / 2;
}
性能糟糕,但它不使用数据结构,也不修改输入数组。