我需要根据元素的频率对元素数组进行排序,例如:
Input array: [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
Expected output: [1, 3, 4, 2, 2, 5, 5, 5, 6, 6, 6, 6]
我尝试了以下代码:
var set: NSCountedSet = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
var dictionary = [Int: Int]()
set.forEach { (item) in
dictionary[item as! Int] = set.count(for: item)
}
dictionary.keys.sorted()
print(dictionary)
说明:由于1、3、4仅出现一次,因此它们显示在开头,其中2次出现两次,5次出现3次,6次出现4次。并且[1、3、4]在其中排序。
预期结果:时间复杂度应为 O(n)
答案 0 :(得分:6)
首先创建一个包含每个元素(O(nlogn)
)出现次数的Dictionary
,然后在{上调用O(n)
{1}}(Swift uses Introsort,即sorted
),并使用先前创建的Array
中的值进行排序。数组的元素需要O(nlogn)
才能正常工作,Dictionary
才能存储在Comparable
中,Hashable
可以提供Dictionary
元素查找。
O(1)
以上解决方案保留了出现次数相同的元素的顺序。如果您实际上想根据这些元素的比较值对它们进行排序(这就是示例输出的结果),则可以像下面这样在extension Array where Element: Comparable & Hashable {
func sortByNumberOfOccurences() -> [Element] {
let occurencesDict = self.reduce(into: [Element:Int](), { currentResult, element in
currentResult[element, default: 0] += 1
})
return self.sorted(by: { current, next in occurencesDict[current]! < occurencesDict[next]!})
}
}
[1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2].sortByNumberOfOccurences() // [1, 4, 3, 2, 2, 5, 5, 5, 6, 6, 6, 6]
中修改闭包:
sorted
或更短的comparing tuples
for sorting:
return self.sorted(by: {occurencesDict[$0]! <= occurencesDict[$1]! && $0 < $1})
生成您提供的示例输出return self.sorted(by: {(occurencesDict[$0]!,$0) < (occurencesDict[$1]!,$1)})
答案 1 :(得分:3)
您可以尝试
let dd = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
let res = dd.sorted { f, s in
dd.filter { $0 == f }.count < dd.filter { $0 == s }.count
}
print(res) // [1, 4, 3, 2, 2, 5, 5, 5, 6, 6, 6, 6]
答案 2 :(得分:2)
没有办法以O(n)时间复杂度进行排序。在Wikipedia.
处查看流行算法的最坏情况复杂度最坏情况下的时间复杂度是O(nlogn)。这是我们可以用O(nlogn)时间复杂度解决的方法:
let array = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
extension Array where Element: Comparable & Hashable {
func countableSorted() -> [Element] {
var counts = [Element: Int]()
// O(n)
for element in self {
counts[element] = (counts[element] ?? 0) + 1
}
// I think that standart method uses O(nlogn) time complexity.
// O(nlogn) + O(n) approximately equal to O(nlogn).
let sorted = counts.sorted { item1, item2 -> Bool in
if item2.value > item1.value {
return true
}
if item2.value == item1.value {
return item2.key > item1.key
}
return false
}
var result = [Element]()
// O(n)
for item in sorted {
let items = Array(repeating: item.key, count: item.value)
result.append(contentsOf: items)
}
// Total time complexity for worst case scenario is O(nlogn)
return result
}
}
print(array.countableSorted())
// Output: [1, 3, 4, 2, 2, 5, 5, 5, 6, 6, 6, 6]
答案 3 :(得分:1)
var inputArray = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
var map:[Int: Int] = [:]
for element in inputArray {
let count = map[element]
if count == nil {
map[element] = 1
} else {
map[element] = count! + 1
}
}
var keysArray = map.keys
let sortedKeys = keysArray.sorted { (number1, number2) -> Bool in
if map[number1]! == map[number2]! {
return number1 < number2
} else {
return map[number1]! < map[number2]!
}
}
var finalArray: [Int] = []
for element in sortedKeys {
for _ in 1...map[element]! {
finalArray.append(element)
}
}
print(finalArray)
时间复杂度:O(nlogn)
答案 4 :(得分:1)
您可以尝试以下代码,此方法正常工作。
var inputArray = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
inputArray.sort()
let freq = inputArray.sorted { f, s in
inputArray.filter { $0 == f}.count < inputArray.filter { $0 == s}.count
}
print(freq)
不确定时间的复杂性。
答案 5 :(得分:1)
我想在O(n)
中添加一个解决方案排序需要O(nLogn),但是无需使用Java中的HashMap进行排序就可以解决此问题,因为它包含根据键排序的对。
import java.util.*;
class Simple
{
public static void main(String[] arg)
{ int inputArray[] = {1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2};
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
Map<Integer,List<Integer>> map2 = new HashMap<Integer,List<Integer>>();
for(int i: inputArray)
{
if(map.get(i) == null){
map.put(i, 1) ;
}
else{
int a = map.get(i);
map.put(i,a+1);
}
}
// using for-each loop for iteration over Map.entrySet()
for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
if(map2.get(entry.getValue()) == null){
map2.put(entry.getValue(), new ArrayList<Integer>()) ;
}
map2.get(entry.getValue()).add(entry.getKey());
}
for(Map.Entry<Integer,List<Integer>> entry : map2.entrySet()){
for(int j=0; j<entry.getValue().size(); j++){
for(int i=0; i<entry.getKey(); i++){
System.out.print(entry.getValue().get(j) + " ");
}
}
}
}
}
more about HashMap 时间复杂度:O(n)
上述代码的快速版本
extension Array where Element: Comparable & Hashable {
func sortByNumberOfOccurences() -> [Element] {
let occurencesDict = self.reduce(into: [Element:Int](), { currentResult, element in
currentResult[element, default: 0] += 1
})
let dict = occurencesDict.sorted(by: {$0.0 < $1.0})
var dictioanary = [Int:Array]()
for (element,occurence) in dict {
if dictioanary[occurence] == nil
{
dictioanary[occurence] = Array()
}
dictioanary[occurence]?.append(element)
}
var resultArray = Array()
let finalDict = dictioanary.sorted(by: {$0.0 < $1.0})
for (frequency,allValuesOccuringWithThisFrequncy) in finalDict {
for i in allValuesOccuringWithThisFrequncy
{
var j = 0
while(j < frequency)
{
resultArray.append(i)
j = j + 1
}
}
}
print(resultArray)
return resultArray
}
}
Swift O(nLogn)中的时间复杂度
答案 6 :(得分:0)
尝试此解决方案。它对我来说就像一种魅力:)
func numberOfOccurences(in array: [Int], of element: Int) -> Int {
let object = NSCountedSet(array: array)
return object.count(for: element)
}
var inputArray = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
var uniqueElements = Array(Set(inputArray))
var otherArray: [Int] = []
var duplicateElements = uniqueElements.filter { (element) -> Bool in
return (inputArray.contains(element) && numberOfOccurences(in: inputArray, of: element) > 1)
}
uniqueElements = uniqueElements.filter({ !duplicateElements.contains($0) }).sorted()
for item in duplicateElements {
let occurences = numberOfOccurences(in: inputArray, of: item)
for _ in 0...occurences - 1 {
otherArray.append(item)
}
}
otherArray = otherArray.sorted()
duplicateElements.removeAll()
let mergedArray = uniqueElements + otherArray
print(mergedArray)
答案 7 :(得分:0)
我认为这种排序可以在O(n)中实现,如下所示:
let input = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
// build the frequency dictionary (easy task)
let frequencies = input.reduce(into: [:]) { $0[$1] = ($0[$1] ?? 0) + 1 }
// allocate a 2-D array of ints, each item in this array will hold the numbers that
// appear I times in the input array
let frequencyTable: [[Int]] = frequencies.reduce(into: Array(repeating: [Int](), count: input.count)) {
// substracting one as arrays are zero indexed
// we can't get of of bounds here since the maximum frequency is the
// number of elements in the input array
// Also replicating the numbers by their frequency, to have
// the same contents as in the input array
$0[$1.value - 1] += Array(repeating: $1.key, count: $1.value)
}
// lastly, simply flatten the 2-D array to get the output we need
let output = frequencyTable.flatMap { $0 }
print(output)
抽样结果:
[4, 1, 3, 2, 2, 5, 5, 5, 6, 6, 6, 6]
请注意,根据字典哈希函数的工作方式,具有相同频率的数字顺序可能会有所不同。
我们也为了时间而牺牲了空间(分配的二维数组)。
frequencyTable
的内容与此类似(同样,1、4、3的顺序可能不同):
[[4, 3, 1], [2, 2], [5, 5, 5], [6, 6, 6, 6], [], [], [], [], [], [], [], []]