Leetcode刷题记录-排序(堆、桶、随机快排)

Leetcode刷题记录-排序

  • 堆排序
    • 215. 数组中的第K个最大元素(中等)
  • 桶排序
    • 347.出现频率前k次多的元素(中等)
    • 451.按照字符出现次数对字符串排序
  • 荷兰国旗问题
    • 75.颜色分类(中等)
  • Tips:
  • 重写整合

堆排序

215. 数组中的第K个最大元素(中等)

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
Leetcode刷题记录-排序(堆、桶、随机快排)_第1张图片
代码:
待改进,有重复元素会出错

# 方法一 直接排序
nums = [3, 1, 6, 4, 6, 1, 2]
k = 2

nums.sort()
print(nums)
print(len(nums) - k)
# 方法二 快速排序
import random
class Solution:
    def findKthLargest(self, nums, k):
        def Qsort(left, right):
            if left >= right:
                return -1
            randindex = random.randint(left, right - 1)
            nums[left], nums[randindex] = nums[randindex], nums[left]
            l , r, pivot = left, right, nums[left]
            while l < r:
                while nums[r] >= pivot and l < r:
                    r -= 1
                nums[l] = nums[r]

                while nums[l] <= pivot and l < r:
                    l += 1
                nums[r] = nums[l]

            nums[r] = pivot
            Qsort(left, l - 1)
            Qsort(l + 1, right)

        Qsort(0, len(nums) - 1)
        return nums[len(nums) - k]
    # 方法三 堆排序 (重复会报错)
    def findKthLargest_heapsort(self):
        def heapsort(nums, i, right):
            left = 2 * i + 1
            # 堆调整
            while left <= right:
                # 左节点是最后一个节点
                if left == right:
                    if nums[left] > nums[i]:
                        nums[left], nums[i] = nums[i], nums[left]
                    else:
                        break

                if nums[left] < nums[left + 1]:
                    left += 1

                if nums[i] < nums[left]:

                    nums[left], nums[i] = nums[i], nums[left]
                    i = left
                    left = 2 * i + 1
                else:
                    break

        # 创建大顶堆,从最后一个有子节点的非叶子节点开始,往前遍历
        for i in range((len(nums) - 1) // 2, -1, -1):
            heapsort(nums, i, len(nums) - 1)
        print(nums)


        for right in range(len(nums) - 1, -1, -1):
            nums[0], nums[right] = nums[right], nums[0]
            self.k -= 1
            if self.k == 0:
                print(nums[right])
                return nums[right]
            heapsort(nums, 0, right - 1)
        print(nums)



示例代码:

class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """

        max_n = max(nums)
        min_n = min(nums[:k])
        l = [0] * (max_n - min_n + 1)

        for n in nums:
            if n < min_n:
                continue
            l[n - min_n] += 1

        c = 0  
        for i in range(max_n - min_n, -1, -1):
            c += l[i]
            if c >= k:
                return i + min_n

        return min_n
        

桶排序

347.出现频率前k次多的元素(中等)

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按任意顺序返回答案。
Leetcode刷题记录-排序(堆、桶、随机快排)_第2张图片
代码:
(很爱偷懒的一些女的

# 方法一 counter()
import collections
class Solution(object):
    def topKFrequent(self, nums, k):

        return list(zip(*collections.Counter(nums).most_common(k)))[0]

# 方法二 桶排序
class Solution(object):
    def topKFrequent(self, nums, k):
        counter = collections.Counter(nums)
        n = len(nums)
        dic = [ [] for i in range(n + 1)]
        for v, c in counter.items():
            dic[c].append(v)
        res = []
        for i in range(n, -1, -1):
            res.extend(dic[i])
            if len(res) == k:
                return res

    # 方法三 堆排序
    def topK_heapsort(self):
        freq = collections.Counter(nums)
        dic, ans = [], []
        for i in freq:
            heapq.heappush(dic, (-freq[i], i))
        for _ in range(k):
            ans.append(heapq.heappop(dic)[1])
        print('the top k frequent elems are', ans)
        return ans


    # 方法四 随机快排
    def topKfreq_Qsort(self):
        def topKfrequence(nums, k):
            freq = collections.Counter(nums)
            value = list(freq.keys())
            l , r = 0 , len(value) - 1
            while l <= r:
                pivot = Qsort(value, l , r, freq)
                if pivot == k - 1:
                    return value[:k]
                elif pivot > k - 1:
                    r = pivot - 1
                else:
                    l = pivot + 1


        def Qsort(value,l, r, freq):
                randindex = random.randint(l, r)
                nums[l], nums[randindex] = nums[randindex], nums[l]
                right, pivot = l, r

                for i in range(l , r):
                    if freq.get(value[i]) >= freq.get(value[pivot]):
                        value[i], value[right] = value[right], value[i]
                        right += 1
                value[right], value[pivot] = value[pivot], value[i]
                return right

        print(topKfrequence(nums, k))


451.按照字符出现次数对字符串排序

给定一个字符串 s ,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。返回已排序的字符串 。如果有多个答案,返回其中任何一个。

Leetcode刷题记录-排序(堆、桶、随机快排)_第3张图片
代码:

import collections
class Solution(object):
    def frequencySort(self, s):
        freq = collections.Counter(s)
        dic = []
        for key, value in freq.items():
            dic.append((key, value))
        dic.sort(key = lambda x:x[1], reverse = True)
        ans = []
        for i in dic:
            if i[1] > 1:
                ans.append(i[0]*i[1])
            else:
                ans.append(i[0])
        return ''.join(ans)

@TODO 桶排序


@TODO 堆排序


荷兰国旗问题

75.颜色分类(中等)

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。必须在不使用库内置的 sort 函数的情况下解决这个问题。

Leetcode刷题记录-排序(堆、桶、随机快排)_第4张图片

代码:

# 双指针
import random
class Solution(object):
    def sortColors(self, nums):
        l , r = 0 , len(nums) - 1
        i = 0
        while i <= r:
            while nums[i] == 2 and i <= r:
                nums[i], nums[r] = nums[r], nums[i]
                r -= 1  
            if nums[i] == 0:
                nums[i], nums[l] = nums[l], nums[i]
                l += 1
            i += 1

Tips:

1.欧几里得算法(辗转相除法):
a,b为正整数,求a和b的最大公因数可以转化为求b和a%b的最大公因数
证明过程详见:https://blog.csdn.net/alicek1008/article/details/119559494

2.前k个高频元素多种解法:
https://blog.csdn.net/AI414010/article/details/108704282

3.堆排序:
https://zhuanlan.zhihu.com/p/124885051

4.根据字符出现频率排序多种解法
https://blog.csdn.net/weixin_45069761/article/details/106136422

重写整合

import collections
import heapq
from pyparsing import nums
import random

class sort_algrms(object):
    def __init__(self, nums, k, s, color):
        self.nums = nums
        self.k = k
        self.s = s
        self.color = color


    # 选择排序 o(n^2)
    def selected_sort(self):
        def findSmallestWord(nums):
            smallest = nums[0]
            smallest_index = 0
            for i in range(1, len(nums)):
                if nums[i] < smallest:
                    smallest = nums[i]
                    smallest_index = i
            return smallest_index

        newnums = []
        for j in range(len(nums)):
            smallest_word = findSmallestWord(nums)
            # pop() 内含一个要删除元素的索引
            newnums.append(nums.pop(smallest_word))
        nums[:] = newnums
        print('the newnums is', nums)
        return nums

    # 1.找第k个最大的元素
    # 方法一随机快排
    def findKthLargest(self):
        def Qsort(left, right):
            if left >= right:
                return -1
            randindex = random.randint(left, right - 1)
            nums[left], nums[randindex] = nums[randindex], nums[left]
            l, r, pivot = left, right, nums[left]
            while l < r:
                while nums[r] >= pivot and l < r:
                    r -= 1
                nums[l] = nums[r]
                while nums[l] <= pivot and l < r:
                    l += 1
                nums[r] = nums[l]
            nums[r] = pivot
            Qsort(left, l - 1)
            Qsort(l + 1, right)
        Qsort(0, len(nums) - 1)
        print('the sorted num is', nums)
        print(nums[len(nums)-k])
        return nums[len(nums)-k]


    # 方法二 堆排序 (重复会报错)
    def findKthLargest_heapsort(self):
        def heapsort(nums, i, right):
            left = 2 * i + 1
            # 堆调整
            while left <= right:
                # 左节点是最后一个节点
                if left == right:
                    if nums[left] > nums[i]:
                        nums[left], nums[i] = nums[i], nums[left]
                    else:
                        break

                if nums[left] < nums[left + 1]:
                    left += 1

                if nums[i] < nums[left]:

                    nums[left], nums[i] = nums[i], nums[left]
                    i = left
                    left = 2 * i + 1
                else:
                    break

        # 创建大顶堆,从最后一个有子节点的非叶子节点开始,往前遍历
        for i in range((len(nums) - 1) // 2, -1, -1):
            heapsort(nums, i, len(nums) - 1)
        print(nums)


        for right in range(len(nums) - 1, -1, -1):
            nums[0], nums[right] = nums[right], nums[0]
            self.k -= 1
            if self.k == 0:
                print(nums[right])
                return nums[right]
            heapsort(nums, 0, right - 1)
        print(nums)




    # 2.出现频率最高的前k个元素
    # 方法一 :桶排序
    def topKFrequent(self):
        counter = collections.Counter(nums)
        n = len(nums)
        # 与数组长度一样多个空列表(桶),只取了排好顺序的元素,没有取频次
        dic = [ [] for i in range(n + 1)]
        for v, c in counter.items():
            dic[c].append(v)
        # print(dic)
        res = []
        for i in range(n, -1, -1):
            res.extend(dic[i])
            # 倒取前k个桶
            if len(res) == k:
                print('the top k frequent elems are', res)
                return res

    # 方法二 counter()
    def topKFrequent_counter(self):
        return list(zip(*collections.Counter(nums).most_common(k)))[0]


    # 方法三 堆排序
    def topK_heapsort(self):
        freq = collections.Counter(nums)
        dic, ans = [], []
        for i in freq:
            heapq.heappush(dic, (-freq[i], i))
        for _ in range(k):
            ans.append(heapq.heappop(dic)[1])
        print('the top k frequent elems are', ans)
        return ans

    # 方法四 随机快排
    def topKfreq_Qsort(self):
        def topKfrequence(nums, k):
            freq = collections.Counter(nums)
            value = list(freq.keys())
            l , r = 0 , len(value) - 1
            while l <= r:
                pivot = Qsort(value, l , r, freq)
                if pivot == k - 1:
                    return value[:k]
                elif pivot > k - 1:
                    r = pivot - 1
                else:
                    l = pivot + 1


        def Qsort(value,l, r, freq):
                randindex = random.randint(l, r)
                nums[l], nums[randindex] = nums[randindex], nums[l]
                right, pivot = l, r

                for i in range(l , r):
                    if freq.get(value[i]) >= freq.get(value[pivot]):
                        value[i], value[right] = value[right], value[i]
                        right += 1
                value[right], value[pivot] = value[pivot], value[i]
                return right

        print(topKfrequence(nums, k))




    # 3.按照字符出现次数对字符串排序
    def freq_sort(self):
        freq = collections.Counter(s)
        dic = []
        for key,value in freq.items():
            dic.append((key, value))
        dic.sort(key = lambda x:x[1], reverse = True)
        # print(dic)[('b', 2), ('A', 1), ('a', 1)]
        ans = []
        for i in dic:
            if i[1] > 1:
                # ('b', 2 )若出现频次大于1,则输出i[1]个i[0]
                ans.append(i[0]*i[1])
            else:
                ans.append(i[0])
        print('the sorted str is', '-'.join(ans))
        return ''.join(ans)


    # 4.颜色分类
    def color_sort(self):
        l, r = 0, len(color) - 1
        i = 0
        while i <= r:
            while color[i] == 2 and i <= r:
                color[i], color[r] = color[r], color[i]
                r -= 1
            if color[i] == 0:
                color[i], color[l] = color[l], color[i]
                l += 1
            i += 1
        print('the sorted color is', color)
        return color


if __name__ == "__main__":

    # 选择排序、快速排序法参数
    nums = [3, 1, 6, 6, 6, 5, 4, 5, 2]
    k = 2

    # 3.按照字符出现次数对字符串排序参数
    s = 'Aabb'

    # 4.颜色分类参数
    color = [2, 0, 2, 1, 1, 0]


    sort_algrm = sort_algrms(nums, k, s, color)


    # 选择排序法调用
    # sort_algrm.selected_sort()


    # 2.出现频率最高的前k个元素
    # 方法一:快速排序法
    # sort_algrm.findKthLargest()
    sort_algrm.topKfreq_Qsort()

    # 方法二:堆排序
    #sort_algrm.findKthLargest_heapsort()


    # 桶排序找出现频次前k次多的元素
    # sort_algrm.topKFrequent()

    # 3.按照字符出现次数对字符串排序
    # sort_algrm.freq_sort()

    # 4.颜色分类参数
    # sort_algrm.color_sort()













# # 简单递归
# def countdown(i):
#     print(i)
      # 基线条件
#     if i <= 0:
#         return False
      # 递归条件
#     else:
#         countdown(i - 1)
#
# i = 5
# countdown(i)




""" 快速排序 o(n * log(n))
# QSort
nus = [4, 5, 1, 2, 3, 5, 4, 1]

# left,right分别为子数组中第一个元素和最后一个元素在原数组中的位置
def QSort(left, right):
    # 边界条件
    if left >= right:
        return -1
    # 初始化左右指针的初始值
    l, r, key = left, right, nus[left]
    # 调整元素的位置
    while l < r:
        while l < r and nus[r] >= key:
            r -= 1
        nus[l] = nus[r]
        while l < r and nus[l] <= key:
            l += 1
        nus[r] = nus[l]
    # 把基准值赋给左右指针共同指向的位置
    nus[r] = key
    # 对左侧数组排序
    QSort(left, l - 1)
    # 对右侧数组排序
    QSort(l + 1, right)


QSort(0, len(nus) - 1)
print(nus)
"""





你可能感兴趣的:(Diary,leetcode,算法,数据结构)