找到一个时间复杂度为 O(n + k*log(k)) 的整数排序算法
Find an algorithm for sorting integers with time complexity O(n + k*log(k))
设计一种算法,对存在重复项的 n 个整数进行排序。不同数字的总数是k。你的算法应该有时间复杂度 O(n + k*log(k))。预计时间足够了。对于 k 的哪些值,算法变为线性?
我无法想出一个整数排序算法来满足它必须是 O(n + k*log(k)) 的条件。我不是一个非常高级的程序员,但在这个应该为列表中的所有数字 xi
0 ≤ xi ≤ m
提出算法之前我遇到了问题,这样算法是 O(n+m ),其中 n 是列表中元素的数量,m 是列表中最大整数的值。我通过使用计数排序轻松解决了这个问题,但我一直在努力解决这个问题。对我来说最困难的条件是 ordo 符号下的术语 k*log(k)
如果那是 n*log(n)
而不是我可以使用合并排序,对吗?但现在这是不可能的,所以任何想法都会很有帮助。
提前致谢!
这是一个可能的解决方案:
使用散列table,计算每个值的唯一值的数量和重复的数量。这应该具有 O(n).
的复杂性
枚举散列table,将唯一值存储到临时数组中。复杂度为 O(k).
使用标准算法(例如归并排序)对该数组进行排序:复杂度为 O(k.log(k)).
通过复制已排序的唯一值数组的元素来创建结果数组,每次复制存储在散列中的次数 table。复杂度是 O(n) + O(k).
组合复杂度为 O(n + k.log(k)).
例如,如果 k 是一个小常数,则对 n 值的数组排序会收敛于线性时间,因为 n越来越大
如果在第一阶段,k 是增量计算的,看起来 k 并不明显小于 n,删除散列 table 并使用标准算法对原始数组进行排序。
O(n + k*log(k)
的运行时表示(就像运行时中的加法一样)您有 2 个子例程,一个在 O(n)
中运行,另一个在 O(k*log(k))
中运行。
您可以先计算 O(n)
中元素的频率(例如在Hashmap,不熟悉的可以看看这个,很有用。
然后你只需对 unique 个元素进行排序,从中有 k
。此排序在 O(k*log(k))
中运行,使用您想要的任何排序算法。
最后,通过在您在步骤 1 中创建的地图中查找,将单个唯一元素替换为它们实际出现的频率。
可能的 Java 解决方案如下:
public List<Integer> sortArrayWithDuplicates(List<Integer> arr) {
// O(n)
Set<Integer> set = new HashSet<>(arr);
Map<Integer, Integer> freqMap = new HashMap<>();
for(Integer i: arr) {
freqMap.put(i, freqMap.getOrDefault(i, 0) + 1);
}
List<Integer> withoutDups = new ArrayList<>(set);
// Sorting => O(k(log(k)))
// as there are k different elements
Arrays.sort(withoutDups);
List<Integer> result = new ArrayList<>();
for(Integer i : withoutDups) {
int c = freqMap.get(i);
for(int j = 0; j < c; j++) {
result.add(i);
}
}
// return the result
return result;
}
上述代码的时间复杂度为O(n + k*log(k))
,解决方案与上面的回答在同一行。
设计一种算法,对存在重复项的 n 个整数进行排序。不同数字的总数是k。你的算法应该有时间复杂度 O(n + k*log(k))。预计时间足够了。对于 k 的哪些值,算法变为线性?
我无法想出一个整数排序算法来满足它必须是 O(n + k*log(k)) 的条件。我不是一个非常高级的程序员,但在这个应该为列表中的所有数字 xi
0 ≤ xi ≤ m
提出算法之前我遇到了问题,这样算法是 O(n+m ),其中 n 是列表中元素的数量,m 是列表中最大整数的值。我通过使用计数排序轻松解决了这个问题,但我一直在努力解决这个问题。对我来说最困难的条件是 ordo 符号下的术语 k*log(k)
如果那是 n*log(n)
而不是我可以使用合并排序,对吗?但现在这是不可能的,所以任何想法都会很有帮助。
提前致谢!
这是一个可能的解决方案:
使用散列table,计算每个值的唯一值的数量和重复的数量。这应该具有 O(n).
的复杂性
枚举散列table,将唯一值存储到临时数组中。复杂度为 O(k).
使用标准算法(例如归并排序)对该数组进行排序:复杂度为 O(k.log(k)).
通过复制已排序的唯一值数组的元素来创建结果数组,每次复制存储在散列中的次数 table。复杂度是 O(n) + O(k).
组合复杂度为 O(n + k.log(k)).
例如,如果 k 是一个小常数,则对 n 值的数组排序会收敛于线性时间,因为 n越来越大
如果在第一阶段,k 是增量计算的,看起来 k 并不明显小于 n,删除散列 table 并使用标准算法对原始数组进行排序。
O(n + k*log(k)
的运行时表示(就像运行时中的加法一样)您有 2 个子例程,一个在 O(n)
中运行,另一个在 O(k*log(k))
中运行。
您可以先计算
O(n)
中元素的频率(例如在Hashmap,不熟悉的可以看看这个,很有用。然后你只需对 unique 个元素进行排序,从中有
k
。此排序在O(k*log(k))
中运行,使用您想要的任何排序算法。
最后,通过在您在步骤 1 中创建的地图中查找,将单个唯一元素替换为它们实际出现的频率。
可能的 Java 解决方案如下:
public List<Integer> sortArrayWithDuplicates(List<Integer> arr) {
// O(n)
Set<Integer> set = new HashSet<>(arr);
Map<Integer, Integer> freqMap = new HashMap<>();
for(Integer i: arr) {
freqMap.put(i, freqMap.getOrDefault(i, 0) + 1);
}
List<Integer> withoutDups = new ArrayList<>(set);
// Sorting => O(k(log(k)))
// as there are k different elements
Arrays.sort(withoutDups);
List<Integer> result = new ArrayList<>();
for(Integer i : withoutDups) {
int c = freqMap.get(i);
for(int j = 0; j < c; j++) {
result.add(i);
}
}
// return the result
return result;
}
上述代码的时间复杂度为O(n + k*log(k))
,解决方案与上面的回答在同一行。