排序(一)

15. 三数之和

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 数组排序,固定一个数字后,通过双指针寻找另外两个数字
        # 需要跳过重复数字
        # 时间复杂度 O(n^2)
        res = []
        n = len(nums)
        if n < 3:
            return res
        # 排序
        nums.sort()
        for i in range(n):
            # 如果 nums[i]>0,后面三个数相加一定大于 0
            if nums[i] > 0:
                return res
            # 跳过重复元素
            if i > 0 and nums[i] == nums[i-1]:
                continue
            l, r = i+1, n-1
            while l < r:
                if (nums[i] + nums[l] + nums[r]) == 0:
                    res.append([nums[i], nums[l], nums[r]])
                    # 跳过重复元素
                    while l < n-1 and nums[l] == nums[l+1]:
                        l += 1
                    while r > 0 and nums[r] == nums[r-1]:
                        r -= 1
                    l += 1
                    r -= 1
                elif (nums[i] + nums[l] + nums[r]) > 0:
                    r -= 1
                else:
                    l += 1
        return res

16. 最接近的三数之和

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        # 排序 + 双指针
        res = nums[0] + nums[1] + nums[2]
        dismin = abs(res - target)
        n = len(nums)
        nums.sort()
        print(nums)
        for i in range(n):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            l, r = i+1, n-1
            while l < r:
                ans = nums[i] + nums[l] + nums[r]
                print(i,l,r,ans,res)
                if ans == target:
                    return target
                elif ans > target:
                    dis = ans - target
                    if dis < dismin:
                        dismin = dis
                        res = ans
                    while r > 0 and nums[r] == nums[r-1]:
                        r -= 1
                    r -= 1
                else:
                    dis = target - ans
                    if dis < dismin:
                        dismin = dis
                        res = ans
                    while l < n-1 and nums[l] == nums[l+1]:
                        l += 1
                    l += 1
        return res

49. 字母异位词分组

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        # 字母异位词,字符串排序后的值相同,可作为 key,value 为 str list
        res = dict()
        # for s in strs:
        #     key = ''.join(sorted(s))
        #     if key in res.keys():
        #         res[key].append(s)
        #     else:
        #         res[key] = [s]

        # 使用 26 个字母出现的次数组成 key
        for s in strs:
            count = [0] * 26
            for ch in s:
                count[ord(ch) - ord('a')] += 1
            key = tuple(count)
            if key in res.keys():
                res[key].append(s)
            else:
                res[key] = [s]
        return list(res.values())

56. 合并区间

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        # 把区间按照 start 排序,判断下一个区间的 start 是否小于前一个区间的 end,如果是,可以合并,否则不可以
        if not intervals or not intervals[0]:
            return [[]]
        # 按照 start 排序
        new_intervals = sorted(intervals, key=lambda arg:arg[0])
        # intervals.sort(key=lambda x: x[0])
        # print(new_intervals)

        res = []
        start = new_intervals[0][0]
        end = new_intervals[0][1]
        
        for i in range(1, len(new_intervals)):
            # 如果当前区间start 小于等于 end,end 取最大值
            if new_intervals[i][0] <= end:
                end = max(new_intervals[i][1], end)
            else:
                res.append([start, end])
                start = new_intervals[i][0]
                end = new_intervals[i][1]
        # 最后一个区间需要加入到 res 中
        res.append([start, end])
        return res

75. 颜色分类

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # 双指针,0 放到前面,2 放到后面
        n = len(nums)
        p1, p2 = 0, n-1
        for i in range(n):
            # 注意执行顺序,不能颠倒,2 换完可能是 0,需要继续执行下一个 if
            while i <= p2 and nums[i] == 2:
                nums[i], nums[p2] = nums[p2], nums[i]
                p2 -= 1
            if nums[i] == 0:
                nums[i], nums[p1] = nums[p1], nums[i]
                p1 += 1
        return

        # # all in [0, zero] = 0
        # # all in (zero, i) = 1
        # # all in (two, len - 1] = 2

        # def swap(nums, index1, index2):
        #     nums[index1], nums[index2] = nums[index2], nums[index1]

        # size = len(nums)
        # if size < 2:
        #     return

        # zero = -1
        # two = size - 1

        # i = 0

        # while i <= two:
        #     # 这里只有是 0 和 1 的时候,i 才加 1,是 2 的话,需要继续判断
        #     if nums[i] == 0:
        #         zero += 1
        #         swap(nums, i, zero)
        #         i += 1
        #     elif nums[i] == 1:
        #         i += 1
        #     else:
        #         swap(nums, i, two)
        #         two -= 1

88. 合并两个有序数组

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        # 双指针,从后往前插入,可以保证 nums1 的元素不被覆盖
        p1, p2 = m-1, n-1
        tail = m+n-1
        # 原数组为排序数组,p2 结束即可结束循环
        while p2 >= 0:
            # 注意 p1 先结束的 case
            if p1 == -1:
                nums1[tail] = nums2[p2]
                p2 -= 1
            elif nums1[p1] > nums2[p2]:
                nums1[tail] = nums1[p1]
                p1 -= 1
            else:
                nums1[tail] = nums2[p2]
                p2 -= 1
            tail -= 1

164. 最大间距

基数排序 or 桶排序

169. 多数元素

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        # 1、哈希表,时间复杂度 O(n), 空间复杂度 O(n)
        # 2、排序,时间复杂度 O(nlogn), 空间复杂度 O(1)
        # 3、分治,时间复杂度 O(nlogn), 空间复杂度 O(logn)
        # 4、投票算法,时间复杂度 O(n), 空间复杂度 O(1)
        candidate = 0
        count = 0
        for num in nums:
            if count == 0:
                candidate = num
            if candidate == num:
                count += 1
            else:
                count -= 1
        return candidate

179. 最大数

class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        # 转换成字符串之后,按照两个字符串组合的大小排序
        # map() 会根据提供的函数对指定序列做映射
        strs = map(str, nums)

        def cmp(a, b):
            if a + b == b + a:
                return 0
            elif a + b > b + a:
                return 1
            else:
                return -1
        
        strs = sorted(strs, key=functools.cmp_to_key(cmp), reverse=True)
        # 返回时注意首位是 0 时,直接返回 0
        return ''.join(strs) if strs[0] != '0' else '0'

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

力扣

partition模板

def partition(nums, left, right):
    pivot = nums[left]#初始化一个待比较数据
    i,j = left, right
    while(i < j):
        while(i<j and nums[j]>=pivot): #从后往前查找,直到找到一个比pivot更小的数
            j-=1
        nums[i] = nums[j] #将更小的数放入左边
        while(i<j and nums[i]<=pivot): #从前往后找,直到找到一个比pivot更大的数
            i+=1
        nums[j] = nums[i] #将更大的数放入右边
    #循环结束,i与j相等
    nums[i] = pivot #待比较数据放入最终位置 
    return i #返回待比较数据最终位置
class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        # # 暴力解法
        # nums.sort()
        # n = len(nums)
        # # print(nums)
        # # res = sorted(nums)
        # # print(nums)
        # # print(res)
        # return nums[n-k]

        # # 快排
        # def partition(nums, low, high):
        #     i, j = low, high
        #     pivot = nums[i]
        #     while i < j:
        #         # 倒序排列,小的放到后面,注意等号
        #         while i < j and nums[j] <= pivot:
        #             j -= 1
        #         nums[i] = nums[j]
        #         # 注意等号
        #         while i < j and nums[i] >= pivot:
        #             i += 1
        #         nums[j] = nums[i]
        #     nums[i] = pivot
        #     return i

        # # 快速排序
        # def quicksort(nums, left, right):
        #     if left < right:
        #         index = partition(nums, left, right)
        #         quicksort(nums, left, index-1)
        #         quicksort(nums, index+1, right)

        # # topk 切分,获取第 k 大的数
        # def find(nums, low, high):
        #     # 传进来的 low 和 high 是闭区间,注意等号
        #     if low <= high:
        #         index = partition(nums, low, high)
        #         # print(low, high, index)
        #         if index == k-1:
        #             return nums[index]
        #         elif index < k-1:
        #             return find(nums, index+1, high)
        #         else:
        #             return find(nums, low, index-1)
        # n = len(nums)
        # return find(nums, 0, n-1)

        # # 最小堆,利用 API
        # heap = []
        # for num in nums:
        #     heapq.heappush(heap, num)
        #     if len(heap) > k:
        #         heapq.heappop(heap)
        # return heap[0]

        # 最大堆 & k-1次删除之后,剩下的堆顶元素即为目标值
        # 构建大顶堆
        def maxHeap(nums, i, size):
            l, r = 2*i + 1, 2*i + 2
            # print(i, l, r, nums)
            large = i
            if l < size and nums[l] > nums[large]:
                large = l
            if r < size and nums[r] > nums[large]:
                large = r
            # large != i,说明需要交换,递归继续构建大顶堆
            if large != i:
                nums[i], nums[large] = nums[large], nums[i]
                maxHeap(nums, large, size)

        def buildHeap(nums, size):
            # 从最后一个非叶子节点向前遍历
            # 最后一个非叶子节点是 size // 2 - 1
            for i in range(size // 2 - 1, -1, -1):
                maxHeap(nums, i, size)
        
        n = len(nums)
        buildHeap(nums, n)
        # 删除 k-1次,剩下的堆顶为目标值
        for i in range(k-1):
            nums[0], nums[n-1] = nums[n-1], nums[0]
            n = n-1
            maxHeap(nums, 0, n)
        return nums[0]

217. 存在重复元素

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        hashset = set()
        for num in nums:
            if num in hashset:
                return True
            else:
                hashset.add(num)
        return False

229. 多数元素 II

class Solution:
    def majorityElement(self, nums: List[int]) -> List[int]:
        # 摩尔投票
        # 对比之前的大于 n/2问题,差异是先选取两个候选元素
        # 需要针对最后剩下的元素,统计出现次数是否大于 n/3
        ans = []
        element1, element2 = 0, 0
        vote1, vote2 = 0, 0

        for num in nums:
            # 如果该元素为第一个元素,则计数加1
            if vote1 > 0 and num == element1:
                vote1 += 1
            # 如果该元素为第二个元素,则计数加1
            elif vote2 > 0 and num == element2:
                vote2 += 1
            # 选择第一个元素
            elif vote1 == 0:
                element1 = num
                vote1 += 1
            # 选择第二个元素
            elif vote2 == 0:
                element2 = num
                vote2 += 1
            # 如果三个元素均不相同,则相互抵消1次
            else:
                vote1 -= 1
                vote2 -= 1

        cnt1, cnt2 = 0, 0
        for num in nums:
            if vote1 > 0 and num == element1:
                cnt1 += 1
            if vote2 > 0 and num == element2:
                cnt2 += 1        
        # 检测元素出现的次数是否满足要求
        if vote1 > 0 and cnt1 > len(nums) / 3:
            ans.append(element1)
        if vote2 > 0 and cnt2 > len(nums) / 3:
            ans.append(element2)

        return ans

242. 有效的字母异位词

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        # # 排序
        # if len(s) != len(t):
        #     return False
        # s1 = []
        # s2 = []
        # for ch in s:
        #     s1.append(ch)
        # for ch in t:
        #     s2.append(ch)
        # s1.sort()
        # s2.sort()
        # for i in range(len(s)):
        #     if s1[i] != s2[i]:
        #         return False
        # return True

        # hash map
        if len(s) != len(t):
            return False
        hashmap = dict()
        for ch in s:
            if ch not in hashmap.keys():
                hashmap[ch] = 1
            else:
                hashmap[ch] += 1
        for ch in t:
            if ch in hashmap.keys():
                hashmap[ch] -= 1
                if hashmap[ch] < 0:
                    return False
            else:
                return False
        return True

274. H 指数

class Solution:
    def hIndex(self, citations: List[int]) -> int:
        # # 排序,从后向前遍历,初始 h=0, 如果citation[i] > h,说明找到了一个至少引用了 h+1
        # sorted_citation = sorted(citations, reverse = True)
        # h = 0; i = 0; n = len(citations)
        # while i < n and sorted_citation[i] > h:
        #     h += 1
        #     i += 1
        # return h

        # 计数排序,维护一个引用次数对应文章数的数组,下标表示引用次数,值表示文章数
        # 大于文章数的引用次数可限制到 n
        # 计数之后,找到tot 文章数 大于等于 当前引用次数的 h
        n = len(citations); tot = 0
        counter = [0] * (n+1)
        for c in citations:
            if c >= n:
                counter[n] += 1
            else:
                counter[c] += 1
        for i in range(n, -1, -1):
            tot += counter[i]
            if tot >= i:
                return i
        return 0

324. 摆动排序 II

class Solution:
    def wiggleSort(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # n = len(nums)
        # # 排序,时间复杂度 O(nlogn)
        # arr = sorted(nums)
        # x = (n + 1) // 2
        # # 相当于把分开的两个数组倒序之后再插入
        # j, k = x - 1, n - 1
        # for i in range(0, n, 2):
        #     nums[i] = arr[j]
        #     # 每次处理两个数
        #     if i + 1 < n:
        #         nums[i + 1] = arr[k]
        #     j -= 1
        #     k -= 1

        # 无需对整个数组排序,通过快速选择找到数组的中位数,通过 3_way_partion 将数组分成三个部分,倒序穿插
        # 快速选择
        def partition(nums, begin, end, midIndex):
            pivot = nums[begin]
            i, j = begin, end-1
            while i < j:
                # 注意先判断 j,如果 pivot 是 begin
                while i < j and nums[j] >= pivot:
                    j -= 1
                nums[i] = nums[j]
                while i < j and nums[i] <= pivot:
                    i += 1
                nums[j] = nums[i]
            nums[i] = pivot
            if i == midIndex:
                return
            elif i > midIndex:
                # 注意不包含 i
                partition(nums, begin, i, midIndex)
            else:
                partition(nums, i+1, end, midIndex)
        
        n = len(nums)
        # 快速选择找到中位数
        partition(nums, 0, n, n // 2)
        mid = nums[n//2]
        print(n//2, mid, nums)

        # 3-way-partition
        i, j, k = 0, 0, n-1
        while j < k:
            if nums[j] > mid:
                nums[j], nums[k] = nums[k], nums[j]
                k -= 1
            elif nums[j] < mid:
                nums[j], nums[i] = nums[i], nums[j]
                i += 1
                j += 1
            else:
                j += 1
        # print(nums)
        
        x = (n + 1) // 2
        j, k = x - 1, n - 1
        for i in range(0, n, 2):
            nums[i] = arr[j]
            # 每次处理两个数
            if i + 1 < n:
                nums[i + 1] = arr[k]
            j -= 1
            k -= 1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值