找出數組中出現次數最多的前k個元素[leetcode題]

Given a non-empty array of integers, return the k most frequent elements
For example, Given [1,1,1,2,2,3] and k = 2, return [1,2]. https://leetcode.com/problems/top-k-frequent-elements/golang

Haskell 解法,leetcode不提供Haskell語言。數組

import Data.List
import Data.Ord
topKFrequent list k = map head . take k . sortBy (comparing (Down . length)) . group . sort $ list

main = do
    print $ topKFrequent  [1,1,1,2,2,3] 2

先sort,而後 group 分組,而後根據數量倒敘排列 sortBy (comparing (Down . length)) 而後取前 k 個,若是原數組是 [1,1,2,2,3,3] 取 k=2 則,輸出[1,2] [1,3] [2,3] 等都算正確。因此這樣的解法算是最精簡、最簡單的解法。ruby

惟一的問題是:由於排序可能會打亂原先的順序,因此另一種解法是,本身寫一個sort函數來實現對數組的同類合併排序,即 [2,1,2,3,2,3,1,3,1] 排序後 變成:[2,2,2,1,1,1,3,3,3] 將後面相同的提到最前面一個相同值的後面,這樣原先的順序並不會被破壞,即保留原有順序。app

利用 filter 來實現:函數

equalsort :: (Ord a) => [a] -> [a]
equalsort []       = []
equalsort (x:xs)   = filter (==x) (equalsort xs) ++ [x] ++ filter (/=x) (equalsort xs)

equalsort 將相等的排到一塊兒,並不改變原先順序: 測試:測試

main = do
    print $ equalsort [2,1,2,3,2,3,1,3,1]

輸出:[2,2,2,1,1,1,3,3,3]ui

好用equalsort來替換sort,獲得另一種寫法:code

topKFrequent2 list k = map head . take k . sortBy (comparing (Down . length)) . group . equalsort $ list 
        where 
            equalsort []       = []
            equalsort (x:xs)   = filter (==x) (equalsort xs) ++ [x] ++ filter (/=x) (equalsort xs)

golang語言的解法:排序

package main

import (
	"fmt"
	"sort"
)

type Counts [][2]int

func (c Counts) Len() int {
	return len(c)
}
func (c Counts) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c Counts) Less(i, j int) bool {
	return c[i][1] < c[j][1]
}

func topKFrequent(nums []int, k uint) []int {
	ret := []int{}           // 返回數組
	tmp := make(map[int]int) // 計算數組元素出現次數
	cou := Counts{}          // Counts爲二維數組。
	for _, v := range nums {
		if _, ok := tmp[v]; ok { // 存在,次數增長
			tmp[v]++
		} else {
			tmp[v] = 1 // 第一次
		}
	}
	for _, v := range nums { // 建立 Counts數組
		if c, ok := tmp[v]; ok {
			cou = append(cou, [2]int{v, c})
			delete(tmp, v)
		}
	}
	sort.Sort(sort.Reverse(cou))
	for _, v := range cou[0:k] {
		ret = append(ret, v[0])
	}
	return ret
}

func main() {
	fmt.Println(topKFrequent([]int{1, 1, 1, 2, 2, 3}, 2))
}

go語言自定義一個類型,只要該類型實現 Len、Swap、Less三個方法,就能夠直接用sort.Sort調用,提交到leetcode運算完成20個測試耗時48ms,還算比較快。element

Ruby的,比較慢

def top_k_frequent(nums, k)
    nums.reduce({}){|acc, x|  acc[x] ? acc[x]+=1 : acc[x] =1; acc}.sort{|x,y| y[1] <=> x[1]}.take(k).map(&:first)
end

耗時120ms 或者用 each_with_object 替代reduce

def top_k_frequent(nums, k)
  nums.each_with_object({}){|e, acc| acc[e] = (acc[e] || 0) + 1 }.sort{|i, j| j[1] <=> i[1] }.take(k).map(&:first)
end

Ruby的第二種解法,更Ruby,但速度較慢762ms

def top_k_frequent(nums, k)
    nums.sort_by{|e| nums.index(e) }.slice_when{|i, j| i != j }.sort_by{|e| -e.size }.take(k).map(&:first)
end

解法的原理,nums.sort_by{|e| nums.index(e) } 相似於Haskell的 equalsort 函數,將相等的值排序到一塊兒,不相等的保持原來順序不變,slice_when爲ruby2.2新增方法,將一個數組分隔成不少小數組,相似Haskell的group函數,將相等的歸到一個數組,而後按照長度倒序排列,最後取前k個元素,最後map獲取第一個。

相關文章
相關標籤/搜索