Array Questions Extra

137. (LC 347) Top K Frequent Elements

347. Top K Frequent Elements Medium

O(n) time and space
Bucket sort algorithm [10]
Approach 1
You make a ‘bucket’ array, where:
index - initial nums array values
bucket value - frequency
Problem: in our nums array we could have values [1,1,2, 100]
Then our ‘bucket array’ would need to have 100 indexes.
Approach 2
‘Bucket’ array:
index - frequency <===
value - list of nums values
Then len(bucket)+1 =len(nums)
E.g.
nums = [1,1,1,2,2,3]
bucket = [[], [3], [2], [1], [], [], []] (i.e. e.g. value 1, which we record at index 1,
appears 3 times)
### Solution
class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        count = {}
        freq = [[] for i in range(len(nums) + 1)]

        for n in nums:
            count[n] = 1 + count.get(n, 0)
        for n, c in count.items():
            freq[c].append(n)

        res = []
        for i in range(len(freq) - 1, 0, -1):  #(start, end, step in reverse)
            for n in freq[i]:           #for n in [1], so we get 1, not [1]
                res.append(n)
                if len(res) == k:
                    return res

### My V3 (bucket sort)
import collections, itertools
def f(a, k):
    b = [[] for i in range(len(a) + 1)]  # bucket where i=freq, val=val
    cnt = collections.Counter(a)
    ans = []
    for key, v in cnt.items():
        b[v].append(key)
    for i in reversed(range(len(b))):
        if b[i] != [] and k > 0:
            ans.append(b[i])
            k -= len(b[i])
    return list(itertools.chain.from_iterable(ans))

### My V2 (bucket sort)
import collections
def f(a, k):
    cnt = collections.Counter(a)
    b = [[] for i in range(len(a) + 1)]  # bucket
    for k, f in cnt.items():  # k=key=value in nums, f for frequency
        b[f].append(k)
    ans = []
    for i in range(len(b) - 1, 0, -1):
        for n in b[i]:
            if len(ans) < k - 1:
                ans.append(n)

        # for j in range(len(b[i])):
        # if len(ans) < k - 1:
        #     ans.append(b[i][j])
    return ans

nums = [1, 1, 1, 2, 2, 3]
k = 2
print(f(nums, k)) #[1,2]

### My V1
def f(a, k):
    cnt = collections.Counter(a)
    freq = [(v, k) for k, v in cnt.items()]
    ans = []
    for _ in range(k):
        m = max(freq)
        ans.append(m[1])
        freq.remove(m)
    return ans

nums = [1, 1, 1, 2, 2, 3]
k = 2
print(f(nums, k)) #[1, 2]