【leetcode】排序题(python)

本文精选了LeetCode上的经典算法题目,涵盖简单到中等难度,包括字符串处理、数组操作、排序算法、矩阵处理等多个方面,通过实例解析,帮助读者理解和掌握算法设计的基本思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单难度

1370:上升下降字符串(type: easy)

题目描述的复杂,其实就是不停地按字典序升序追加,降序追加,每次加一个
示例:

输入:s = "aaaabbbbcccc"
输出:"abccbaabccba"
输入:s = "leetcode"
输出:"cdelotee"

代码:
预排序+双栈实现,逻辑比较清晰

class Solution(object):
    def sortString(self, s):
        """
        :type s: str
        :rtype: str
        """
        res = ''
        stack1 = sorted(s,reverse=True)
        stack2 = []
        while stack1 or stack2:
            while stack1:
                if len(stack1) == 1 or stack1[-1] < stack1[-2]:
                    res+=stack1.pop()
                else:
                    stack2.append(stack1.pop())
            while stack2:
                if len(stack2) == 1 or stack2[-1] > stack2[-2]:
                    res += stack2.pop()
                else:
                    stack1.append(stack2.pop())
        return res

349、两个数组的交集(type: easy)

给定两个数组,编写一个函数来计算它们的交集。
示例:

输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]

代码:
主要用到了in和not in判断元素是否在某个数组里,为了减小运行时间,判断数组大小,以小的开始计算。

class Solution(object):
    def intersection(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        res = []
        if len(nums1) < len(nums2):
            for i in range(len(nums1)):
                if (nums1[i] in nums2) and (nums1[i] not in res):
                    res.append(nums1[i])
        else:
            for i in range(len(nums2)):
                if (nums2[i] in nums1) and (nums2[i] not in res):
                    res.append(nums2[i])
        return res

1356、根据数字二进制下 1 的数目排序

给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。
示例:

输入:arr = [0,1,2,3,4,5,6,7,8]
输出:[0,1,2,4,8,3,5,6,7]
输入:arr = [1024,512,256,128,64,32,16,8,4,2,1]
输出:[1,2,4,8,16,32,64,128,256,512,1024]

思路1: sorted()的功能就是对序列进行排序,key指定的函数将作用于list的每个元素上,并根据key函数返回的结果进行排序。
sorted(arr, key=lambda x:(bin(x).count(‘1’),x)):按照1的个数排列,1个数相同时,按照arr的顺序输出
lambda x:[bin(x).count(‘1’), x] : lambda改成输出为元组或list,sort在比较第一个数相同后,再比较第二个数
代码:

class Solution(object):
    def sortByBits(self, arr):
        """
        :type arr: List[int]
        :rtype: List[int]
        """
        return sorted(arr, key=lambda x:[bin(x).count('1'), x])

思路2: 初始一个空字典,二进制1的个数为键,对应的数字为值,分别进行排序。
代码:

class Solution(object):
    def sortByBits(self, arr):
        """
        :type arr: List[int]
        :rtype: List[int]
        """
        res = []
        dic = {}
        for i in arr:
            n = bin(i).count('1')	# 计算二进制1的个数
            if n not in dic:
                dic[n] =[]
            dic[n].append(i)	# ’二进制1的个数‘:对应的数字

        for i in sorted(dic):	# 按二进制1的个数排列
            res+=sorted(dic[i])	# 按对应数字排列
        return res

922、按奇偶排序数组 II

给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。
对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。
示例:

输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。

思路: 两个栈分别存储偶数和奇数,再按偶数奇数次序交替输出。学习的点:判断奇数偶数时,位操作(num&1)比余数操作(num%2) 更快,占的内存更小。
代码:

class Solution(object):
    def sortArrayByParityII(self, A):
        """
        :type A: List[int]
        :rtype: List[int]
        """
        stack_odd = []
        stack_even = []
        res = []
        for a in A:
            if a & 1:  # odd
                stack_odd.append(a)
            else:   # even
                stack_even.append(a)
        for i in range(len(stack_even)):    
            res.append(stack_even[i])
            res.append(stack_odd[i])
        return res

1122、数组的相对排序

给你两个数组,arr1 和 arr2,
arr2 中的元素各不相同;arr2 中的每个元素都出现在 arr1 中
对 arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。
示例:

输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
输出:[2,2,2,1,4,3,3,9,6,7,19]

代码:

class Solution(object):
    def relativeSortArray(self, arr1, arr2):
        """
        :type arr1: List[int]
        :type arr2: List[int]
        :rtype: List[int]
        """
        res = []
        pop_num = 0
        for i in arr2:	# arr2按顺序循环,判断元素是否存在arr1中
            if i in arr1:
                pop_num = 0
                for j in range(len(arr1)):
                    j = j - pop_num
                    if arr1[j] == i:
                        res.append(arr1.pop(j))	# 将对应索引pop到res,最后剩下未在arr2出现过的值。
                        pop_num += 1
        return res + sorted(arr1)

976、三角形的最大周长

给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的、面积不为零的三角形的最大周长。
如果不能形成任何面积不为零的三角形,返回 0。
示例:

输入:[2,1,2]
输出:5
输入:[3,2,3,4]
输出:10

思路: 大到小排序后,判断相邻3个数是否满足三角形条件,如满足则为最大值。三角形条件:两短边之和大于长边;最大值如果小于两相邻较小值,则后续的值无需比较。
代码:

class Solution(object):
    def largestPerimeter(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        A = sorted(A, reverse=True) # 大到小排序
        for a in range(len(A)-2):
            if A[a] < A[a+1] +A [a+2]:  # 满足两短边之和大于长边即可
                return  A[a] + A[a+1] +A [a+2]  # 周长
        return 0

1030、距离顺序排列矩阵单元格

给出 R 行 C 列的矩阵,其中的单元格的整数坐标为 (r, c),满足 0 <= r < R 且 0 <= c < C。
另外,我们在该矩阵中给出了一个坐标为 (r0, c0) 的单元格。
返回矩阵中的所有单元格的坐标,并按到 (r0, c0) 的距离从最小到最大的顺序排,其中,两单元格(r1, c1) 和 (r2, c2) 之间的距离是曼哈顿距离,|r1 - r2| + |c1 - c2|。(你可以按任何满足此条件的顺序返回答案。)
示例:

输入:R = 2, C = 2, r0 = 0, c0 = 1
输出:[[0,1],[0,0],[1,1],[1,0]]
解释:从 (r0, c0) 到其他单元格的距离为:[0,1,1,2]
[[0,1],[1,1],[0,0],[1,0]] 也会被视作正确答案。

代码: 此题思路和1356二进制排序一样

class Solution(object):
    def allCellsDistOrder(self, R, C, r0, c0):
        """
        :type R: int
        :type C: int
        :type r0: int
        :type c0: int
        :rtype: List[List[int]]
        """
        dic = {}
        res = []
        for r in range(R):
            for c in range(C):
                distance = abs(r-r0)+abs(c-c0)
                if distance not in dic:
                    dic[distance] = []
                dic[distance].append([r,c])
        for i in sorted(dic):
            res+=sorted(dic[i])
        return res

242、有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例:

输入: s = "anagram", t = "nagaram"
输出: true

代码: 解法比较取巧

class Solution(object):
    def isAnagram(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        return sorted(s) == sorted(t)

350、两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。
示例:

输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]

代码:

class Solution(object):
    def intersect(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        res = []
        if len(nums1) < len(nums2):
            for i in range(len(nums1)):
                if nums1[i] not in nums2: continue
                for j in range(len(nums2)):
                    if(nums1[i] == nums2[j]):
                        res.append(nums2.pop(j))
                        break
        else:
            for i in range(len(nums2)):
                if nums2[i] not in nums1: continue
                for j in range(len(nums1)):
                    if(nums2[i] == nums1[j]):
                        res.append(nums1.pop(j))
                        break
        return res

5376、非递增顺序的最小子序列

给你一个数组 nums,请你从中抽取一个子序列,满足该子序列的元素之和 严格大于未包含在该子序列中的各元素之和。同时,返回的答案应当按 非递增顺序 排列。
示例:

输入:nums = [4,3,10,9,8]
输出:[10,9] 
输入:nums = [4,4,7,6,7]
输出:[7,7,6] 	# 非递增排序

思路: 小到大排序,nums每次把最大值给res,计算和的大小
代码:

class Solution(object):
    def minSubsequence(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        nums = sorted(nums)
        res = []
        while 1:
            res.append(nums.pop())
            if len(nums) == 0 or sum(res[:]) > sum(nums[:]):
                return res

中等难度

面试题 16.21. 交换和

给定两个整数数组,请交换一对数值(每个数组中取一个数值),使得两个数组所有元素的和相等。
返回一个数组,第一个元素是第一个数组中要交换的元素,第二个元素是第二个数组中要交换的元素。若有多个答案,返回任意一个均可。若无满足条件的数值,返回空数组。
示例:

输入: array1 = [4, 1, 2, 1, 1, 2], array2 = [3, 6, 3, 3]
输出: [1, 3]

代码:

class Solution(object):
    def findSwapValues(self, array1, array2):
        """
        :type array1: List[int]
        :type array2: List[int]
        :rtype: List[int]
        """
        diff = sum(array1) - sum(array2)
        if diff & 1: return []  # 差值一定为偶数,sum_1-set_1[i]+set_2[j] == sum_2-set_2[j]+set_1[i]
        diff >>= 1  # diff/2
        array1 = list(set(array1))  # 转集合再转列表减少参数
        s2 = set(array2)
        for a in array1:
            if a - diff in s2:
                return [a, a - diff]
        return []

75、颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:不能使用代码库中的排序函数来解决这道题。
示例:

输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]

思路: 遍历数组,将0丢到p0位置,将2丢到p2位置,注意在把2丢到p2位置后,需要再判断相同位置的值(与2交换的值)。
在这里插入图片描述
代码:

class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        p0 = 0
        p2 = len(nums)-1
        cur_pt = 0
        while cur_pt <= p2: # p2后面均正确
            if nums[cur_pt] == 0:
                nums[p0], nums[cur_pt] = nums[cur_pt], nums[p0]
                cur_pt += 1 # 确保前面均正确,移动到下一个元素
                p0 += 1
            elif nums[cur_pt] == 2:
                nums[p2], nums[cur_pt] = nums[cur_pt], nums[p2]
                p2 -= 1
            else:
                cur_pt += 1

56、合并区间

给出一个区间的集合,请合并所有重叠的区间。
示例:

输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

代码:

class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: List[List[int]]
        """
        intervals = sorted(intervals)	# 排序
        i = 0
        while i < len(intervals):
            j = i+1
            while j < len(intervals):
                if intervals[i][1] >= intervals[j][0]:	# 区间1后端大于或等于区间2前端,在区间1位置插入合并区间
                    intervals.insert(i, [min(intervals[i][0], intervals[j][0]), max(intervals[i][1], intervals[j][1])])	# 注意合并区间大小
                    intervals.pop(i+1)	# 丢掉原来的区间
                    intervals.pop(j)	# j不用加1
                    i -= 1	# 从合并区间位置继续循环
                    break
                j += 1
            i += 1
        return intervals

面试题45、把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例:

输入: [3,30,34,5,9]
输出: "3033459"

代码: 字符串两两组合,判断组合后的大小。再用选择排序

class Solution(object):
    def minNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: str
        """
        str_nums = ''
        for i in range(len(nums)):
            for j in range(i+1, len(nums)):
                if str(nums[i])+str(nums[j]) > str(nums[j])+str(nums[i]):
                    nums[i], nums[j] = nums[j], nums[i]
        for i in nums:
            str_nums = str_nums + str(i)
        return str_nums

179、最大数

给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。
示例:

输入: [3,30,34,5,9]
输出: 9534330

代码: 与上一题类似

class Solution(object):
    def largestNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: str
        """
        if max(nums) != 0:
            str_num = []
            for num in nums:
                str_num.append(str(num))
            for i in range(len(str_num)):
                for j in range(i+1, len(str_num)):
                    if str_num[i]+str_num[j] < str_num[j]+str_num[i]:
                        str_num[i], str_num[j] = str_num[j], str_num[i]
            res = ''
            for i in str_num:
                res += i
            return res
        else:
            return '0'

1387、将整数按权重排序

我们将整数 x 的 权重 定义为按照下述规则将 x 变成 1 所需要的步数:
如果 x 是偶数,那么 x = x / 2;如果 x 是奇数,那么 x = 3 * x + 1
比方说,x=3 的权重为 7 。因为 3 需要 7 步变成 1 (3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1)。
给你三个整数 lo, hi 和 k 。你的任务是将区间 [lo, hi] 之间的整数按照它们的权重 升序排序 ,如果大于等于 2 个整数有 相同 的权重,那么按照数字自身的数值 升序排序 。
请你返回区间 [lo, hi] 之间的整数按权重排序后的第 k 个数。
注意,题目保证对于任意整数 x (lo <= x <= hi) ,它变成 1 所需要的步数是一个 32 位有符号整数。
示例:

输入:lo = 12, hi = 15, k = 2
输出:13
解释:12 的权重为 9(12 --> 6 --> 3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1)
13 的权重为 9、14 的权重为 17、15 的权重为 17
区间内的数按权重排序以后的结果为 [12,13,14,15] 。对于 k = 2 ,答案是第二个整数也就是 13 。
注意,12 和 13 有相同的权重,所以我们按照它们本身升序排序。14 和 15 同理。

代码: 递归+关键字lambda排序

class Solution(object):
    def getKth(self, lo, hi, k):
        """
        :type lo: int
        :type hi: int
        :type k: int
        :rtype: int
        """
        def getWeight(x):   # 递归计算权值
            if x == 1:  return 0
            return (getWeight(3*x+1) if x&1 else getWeight(x//2)) + 1
        res = list(range(lo, hi+1))
        res.sort(key=lambda x:(getWeight(x),x)) # (getWeight(x),x)先按权值排序,权值相等时按元素排序
        return res[k-1]

1329、将矩阵按对角线排序

给你一个 m * n 的整数矩阵 mat ,请你将同一条对角线上的元素(从左上到右下)按升序排序后,返回排好序的矩阵。
示例:
在这里插入图片描述
代码:

class Solution(object):
    def diagonalSort(self, mat):
        """
        :type mat: List[List[int]]
        :rtype: List[List[int]]
        """
        R = len(mat)	# 行长度
        C = len(mat[0])	# 列长度

        start_point = []	# 左列和上行排序起始点
        for i in range(R):
            start_point.append([i, 0])
        for j in range(1, C):
            start_point.append([0, j])

        tmp = []
        for point in start_point: 
            i, j = point[0], point[1]	# 起始点坐标
            while i < R and j < C:		# 暂存数据
                tmp.append(mat[i][j])
                i += 1
                j += 1
            tmp.sort(reverse=True)		# 大到小排序
            i, j = point[0], point[1]
            while i < R and j < C:		# 矩阵重新赋值
                mat[i][j] = tmp.pop()
                i += 1
                j += 1
        return mat

面试16.16 部分排序

给定一个整数数组,编写一个函数,找出索引m和n,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的m和n(例如整个数组是有序的),请返回[-1,-1]。
示例:

输入: [1,2,4,7,10,11,7,12,6,7,16,18,19]
输出: [3,9]

代码: 只需要寻找最靠右的那个数(满足左边存在大于它的数),和最靠左的那个数(满足右边存在小于它的数)

class Solution(object):
    def subSort(self, array):
        """
        :type array: List[int]
        :rtype: List[int]
        """
        sort_array = sorted(array)
        if array == sort_array:
            return [-1,-1]
        m = 0
        n = len(array) - 1
        MAX, MIN = array[m], array[n]
        for i in range(len(array)):
            if array[i] < MAX: n = i    # a[i]<max,则左边存在大于它的数
            else:   MAX = array[i]
        for i in range(len(array)-1, -1, -1):
            if MIN < array[i]:  m = i   # a[i]>min,则右边边存在于它的
            else:   MIN = array[i]
        return [m, n]

1333、餐厅过滤器

给你一个餐馆信息数组 restaurants,其中 restaurants[i] = [idi, ratingi, veganFriendlyi, pricei, distancei]。你必须使用以下三个过滤器来过滤这些餐馆信息。
其中素食者友好过滤器 veganFriendly 的值可以为 true 或者 false,如果为 true 就意味着你应该只包括 veganFriendlyi 为 true 的餐馆,为 false 则意味着可以包括任何餐馆。此外,我们还有最大价格 maxPrice 和最大距离 maxDistance 两个过滤器,它们分别考虑餐厅的价格因素和距离因素的最大值。
过滤后返回餐馆的 id,按照 rating 从高到低排序。如果 rating 相同,那么按 id 从高到低排序。简单起见, veganFriendlyi 和 veganFriendly 为 true 时取值为 1,为 false 时,取值为 0 。
示例:

输入:restaurants = [[1,4,1,40,10],[2,8,0,50,5],[3,8,1,30,4],[4,10,0,10,3],[5,1,1,15,1]], veganFriendly = 1, maxPrice = 50, maxDistance = 10
输出:[3,1,5] 

代码:

class Solution(object):
    def filterRestaurants(self, restaurants, veganFriendly, maxPrice, maxDistance):
        """
        :type restaurants: List[List[int]]
        :type veganFriendly: int
        :type maxPrice: int
        :type maxDistance: int
        :rtype: List[int]
        """ 
        i = 0
        while i < len(restaurants):	# 过滤餐厅
            if veganFriendly and restaurants[i][2] == 0 or restaurants[i][3] > maxPrice or restaurants[i][4] > maxDistance:
                restaurants.pop(i)
            else: i += 1
        restaurants.sort(reverse=True, key=lambda x:(x[1],x[0]))	# 排序
        res = []
        for i in restaurants:
            res.append(i[0])
        return res

973、最接近原点的K个点

我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。
(这里,平面上两点之间的距离是欧几里德距离。)
你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。
示例:

输入:points = [[1,3],[-2,2]], K = 1 
输出:[[-2,2]] 
解释:  
(1, 3) 和原点之间的距离为 sqrt(10),
 (-2, 2) 和原点之间的距离为 sqrt(8), 
由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。
我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]。

代码: 缓存栈存储[distance, x, y],倒序排序后取后K个值的坐标

class Solution:
    def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]:
        stack = []
        res = []
        for x,y in points:
            dist =  (x**2+y**2)**0.5	# 计算欧式距离
            stack.append([dist, x, y])	
        stack = sorted(stack, reverse=True)
        for i in range(K):
            _, x, y = stack.pop()
            res.append([x, y])
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值