LeetCode-题目详解(二):归并排序【时间:O(nlogn)、稳】、快速排序【二路快排、三路快排】、选择排序【时间:O(n^2)、不稳】、堆排序【时间:O(nlogn)、不稳】

LeetCode题目

1.1、56-合并区间 【中等】

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

示例 1:

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

示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

提示:

  • 1 < = i n t e r v a l s . l e n g t h < = 1 0 4 1 <= intervals.length <= 10^4 1<=intervals.length<=104
  • intervals[i].length == 2
  • 0 < = s t a r t i < = e n d i < = 1 0 4 0 <= start_i <= end_i <= 10^4 0<=starti<=endi<=104

在这里插入图片描述

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key=lambda x: x[0])

        merged = []
        for interval in intervals:
            # 如果列表为空,或者当前区间与上一区间不重合,直接添加
            if not merged or merged[-1][1] < interval[0]:
                merged.append(interval)
            else:
                # 否则的话,我们就可以与上一区间进行合并
                merged[-1][1] = max(merged[-1][1], interval[1])

        return merged

1.2、179-最大数 【中等】

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。

注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。

示例 1:

输入:nums = [10,2]
输出:"210"

示例 2:

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

示例 3:

输入:nums = [1]
输出:"1"

示例 4:

输入:nums = [10]
输出:"10"

提示:

  • 1 <= nums.length <= 100
  • 0 < = n u m s [ i ] < = 1 0 9 0 <= nums[i] <= 10^9 0<=nums[i]<=109

方法一:选择排序

class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        n=len(nums)
        nums=list(map(str,nums))
        for i in range(n):
            for j in range(i+1,n):
                if nums[i]+nums[j]<nums[j]+nums[i]:
                    nums[i],nums[j]=nums[j],nums[i]
        
        return str(int("".join(nums)))

方法二:快速排序

class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        def quick_sort(left , right):
            if left >= right: 
                return
            i, j = left, right
            while i < j:
                while i < j and strs[j] + strs[left] <= strs[left] + strs[j]: 
                    j -= 1
                while i < j and strs[i] + strs[left] >= strs[left] + strs[i]: 
                    i += 1
                strs[i], strs[j] = strs[j], strs[i]
            strs[i], strs[left] = strs[left], strs[i]
            quick_sort(left, i - 1)
            quick_sort(i + 1, right)
        
        strs = [str(num) for num in nums]
        quick_sort(0, len(strs) - 1)
        res = ''.join(strs)
        if res[0] == '0':
            res = '0'
        return res

方法三:内置函数 cmp_to_key

from typing import List
from functools import cmp_to_key


class Solution:
    # 先把nums中的所有数字转化为字符串,形成字符串数组 nums_str
    # 比较两个字符串x,y的拼接结果x+y和y+x哪个更大,从而确定x和y谁排在前面;将nums_str降序排序
    # 把整个数组排序的结果拼接成一个字符串,并且返回
    def largestNumber(self, nums: List[int]) -> str:
        print("原始数据:nums = ", nums)
        nums_str = list(map(str, nums))
        print("转为字符串后:nums_str = ", nums_str)
        compare = lambda x, y: 1 if x + y < y + x else -1
        nums_str.sort(key=cmp_to_key(compare))
        print("按照自定义规则排序后:nums_str = ", nums_str)
        res = ''.join(nums_str)
        if res[0] == '0':
            res = '0'
        return res


nums = [3, 30, 34, 5, 9]
solution = Solution()
result = solution.largestNumber(nums=nums)
print("result = ", result)
原始数据:nums =  [3, 30, 34, 5, 9]
转为字符串后:nums_str =  ['3', '30', '34', '5', '9']
按照自定义规则排序后:nums_str =  ['9', '5', '34', '3', '30']
result =  9534330

Process finished with exit code 0

1.3、148-排序链表 【中等】

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 1:
在这里插入图片描述

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:
在这里插入图片描述

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目在范围 [ 0 , 5 ∗ 1 0 4 ] [0, 5 * 10^4] [0,5104]
  • − 1 0 5 < = N o d e . v a l < = 1 0 5 -10^5 <= Node.val <= 10^5 105<=Node.val<=105

进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?


方法一:快速排序(没有随机化,超时)

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        if head is None:
            return head

        # 分成三个链表,分别是比轴心数小,相等,大的数组成的链表
        big = None
        small = None
        equal = None
        cur = head
        while cur is not None:
            t = cur
            cur = cur.next
            if t.val < head.val:
                t.next = small
                small = t
            elif t.val > head.val:
                t.next = big
                big = t
            else:
                t.next = equal
                equal = t
        
        # 拆完各自排序即可,equal 无需排序
        big = self.sortList(big)
        small = self.sortList(small)

        ret = ListNode(None)
        cur = ret

        # 将三个链表组合成一起,这一步复杂度是 o(n)
        # 可以同时返回链表的头指针和尾指针加速链表的合并。
        for p in [small, equal, big]:
            while p is not None:
                cur.next = p
                p = p.next
                cur = cur.next
                cur.next = None
        return ret.next

方法二:归并排序

class Solution:
    # 归并排序
    def sortList(self, head: ListNode) -> ListNode:
        if not head or not head.next: return head
        left_end = self.find_mid(head)
        mid = left_end.next 
        left_end.next = None
        left, right = self.sortList(head), self.sortList(mid)
        return self.merged(left, right)
    # 快慢指针查找链表中点
    def find_mid(self, head):
        if head is None or head.next is None: return head
        slow,fast = head, head.next
        while fast is not None and fast.next is not None:
            slow=slow.next
            fast=fast.next.next
        return slow
    # 合并有序链表
    def merged(self, left, right):
        res = ListNode()
        h = res
        while left and right:
            if left.val < right.val: 
                h.next, left = left, left.next
            else: 
                h.next, right = right, right.next
            h = h.next
        h.next = left if left else right
        return res.next

方法三:堆排序

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        from queue import PriorityQueue
        ptr = head
        p_queue = PriorityQueue()
        while ptr != None:
            p_queue.put(ptr.val)
            ptr = ptr.next
            
        ptr = head
        while not p_queue.empty():
            ptr.val = p_queue.get()
            ptr = ptr.next
        return head

1.4、面试题 17.14-最小K个数 【中等】

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例:

输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]

提示:

  • 0 <= len(arr) <= 100000
  • 0 <= k <= min(100000, len(arr))

方法一:快速排序(随机化处理)

class Solution:
    def partition(self, nums, l, r):
        pivot = nums[r]
        i = l - 1
        for j in range(l, r):
            if nums[j] <= pivot:
                i += 1
                nums[i], nums[j] = nums[j], nums[i]
        nums[i + 1], nums[r] = nums[r], nums[i + 1]
        return i + 1

    def randomized_partition(self, nums, l, r):
        i = random.randint(l, r)
        nums[r], nums[i] = nums[i], nums[r]
        return self.partition(nums, l, r)

    def randomized_selected(self, arr, l, r, k):
        pos = self.randomized_partition(arr, l, r)
        num = pos - l + 1
        if k < num:
            self.randomized_selected(arr, l, pos - 1, k)
        elif k > num:
            self.randomized_selected(arr, pos + 1, r, k - num)

    def smallestK(self, arr: List[int], k: int) -> List[int]:
        if k == 0:
            return list()
        self.randomized_selected(arr, 0, len(arr) - 1, k)
        return arr[:k]

方法二:堆

class Solution:
    def smallestK(self, arr: List[int], k: int) -> List[int]:
        if k == 0:
            return list()

        hp = [-x for x in arr[:k]]
        heapq.heapify(hp)
        for i in range(k, len(arr)):
            if -hp[0] > arr[i]:
                heapq.heappop(hp)
                heapq.heappush(hp, -arr[i])
        ans = [-x for x in hp]
        return ans

方法三:直接调用排序函数

class Solution:
    def smallestK(self, arr: List[int], k: int) -> List[int]:
        arr.sort()
        return arr[:k]

1.5、剑指 Offer 45-把数组排成最小的数 【中等】

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

示例 1:

输入: [10,2]
输出: "102"

示例 2:

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

提示:0 < nums.length <= 100

说明:

  • 输出结果可能非常大,所以你需要返回一个字符串而不是整数
  • 拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0

方法一:快速排序

class Solution:
    def minNumber(self, nums: List[int]) -> str:
        def quick_sort(l , r):
            if l >= r: return
            i, j = l, r
            while i < j:
                while strs[j] + strs[l] >= strs[l] + strs[j] and i < j: j -= 1
                while strs[i] + strs[l] <= strs[l] + strs[i] and i < j: i += 1
                strs[i], strs[j] = strs[j], strs[i]
            strs[i], strs[l] = strs[l], strs[i]
            quick_sort(l, i - 1)
            quick_sort(i + 1, r)
        
        strs = [str(num) for num in nums]
        quick_sort(0, len(strs) - 1)
        return ''.join(strs)

方法二:内置函数 cmp_to_key

class Solution:
    def minNumber(self, nums: List[int]) -> str:
        def sort_rule(x, y):
            a, b = x + y, y + x
            if a > b: return 1
            elif a < b: return -1
            else: return 0
        
        strs = [str(num) for num in nums]
        strs.sort(key = functools.cmp_to_key(sort_rule))
        return ''.join(strs)

1.6、147-对链表进行插入排序 【中等】

对链表进行插入排序。

插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。

插入排序算法:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

方法一:插入排序

class Solution:
    def insertionSortList(self, head: ListNode) -> ListNode:
        if not head:
            return head
        
        dummyHead = ListNode(0)
        dummyHead.next = head
        lastSorted = head
        curr = head.next

        while curr:
            if lastSorted.val <= curr.val:
                lastSorted = lastSorted.next
            else:
                prev = dummyHead
                while prev.next.val <= curr.val:
                    prev = prev.next
                lastSorted.next = curr.next
                curr.next = prev.next
                prev.next = curr
            curr = lastSorted.next
        
        return dummyHead.next

56. 合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

示例 1:

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

示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

提示:

  • 1 < = i n t e r v a l s . l e n g t h < = 1 0 4 1 <= intervals.length <= 10^4 1<=intervals.length<=104
  • intervals[i].length == 2
  • 0 < = s t a r t i < = e n d i < = 1 0 4 0 <= start_i <= end_i <= 10^4 0<=starti<=endi<=104

在这里插入图片描述

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key=lambda x: x[0])

        merged = []
        for interval in intervals:
            # 如果列表为空,或者当前区间与上一区间不重合,直接添加
            if not merged or merged[-1][1] < interval[0]:
                merged.append(interval)
            else:
                # 否则的话,我们就可以与上一区间进行合并
                merged[-1][1] = max(merged[-1][1], interval[1])

        return merged

179. 最大数

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。

注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。

示例 1:

输入:nums = [10,2]
输出:"210"

示例 2:

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

示例 3:

输入:nums = [1]
输出:"1"

示例 4:

输入:nums = [10]
输出:"10"

提示:

  • 1 <= nums.length <= 100
  • 0 < = n u m s [ i ] < = 1 0 9 0 <= nums[i] <= 10^9 0<=nums[i]<=109

方法一:选择排序

class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        n=len(nums)
        nums=list(map(str,nums))
        for i in range(n):
            for j in range(i+1,n):
                if nums[i]+nums[j]<nums[j]+nums[i]:
                    nums[i],nums[j]=nums[j],nums[i]
        
        return str(int("".join(nums)))
class Solution {
public:
    string largestNumber(vector<int>& nums) {
        int n = nums.size();
        vector<string> strs;
        for(int num : nums){
            strs.push_back(std::to_string(num));
        }

        for(int i = 0; i < n; i++){
            for(int j = i + 1; j < n; j++){
                if(strs[i] + strs[j] < strs[j] + strs[i]){
                    swap(strs[i], strs[j]); // vector中的2元素互换位置
                }
            }
        }
        string result;
        for(string str : strs){
            result += str;
        }
        if(result[0] == '0'){
            return "0";
        }else{
            return result;
        }
    }
};

方法二:快速排序

class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        def quick_sort(left , right):
            if left >= right: 
                return
            pivot = left    # 每轮的排序基准
            i = left
            j = right
            while i < j:
                while i < j and strs[j] + strs[pivot] <= strs[pivot] + strs[j]: 
                    j -= 1
                while i < j and strs[i] + strs[pivot] >= strs[pivot] + strs[i]: 
                    i += 1
                strs[i], strs[j] = strs[j], strs[i]
            strs[i], strs[pivot] = strs[pivot], strs[i]
            quick_sort(left, i - 1)
            quick_sort(i + 1, right)
        
        strs = [str(num) for num in nums]
        quick_sort(0, len(strs) - 1)
        res = ''.join(strs)
        if res[0] == '0':
            res = '0'
        return res
class Solution {
public:
    string largestNumber(vector<int>& nums) {
        int n = nums.size();

        // 将vector中的所有元素转为string类型
        vector<string> strs;
        for(int num : nums){
            strs.push_back(std::to_string(num));
        }
        // 快速排序
        quickSort(strs, 0, strs.size() - 1);
        // 整理结果
        string result;
        for(string str : strs){
            result += str;
        }
        if(result[0] == '0'){
            return "0";
        }else{
            return result;
        }
    }

    // 快速排序
    void quickSort(vector<string>& strs, int left, int right){
        if(left >= right){
            return;
        }
        int pivot = left; // 每轮的排序基准
        int i = left;
        int j = right;

        while(i < j){
            while(i < j && strs[j] + strs[pivot] <= strs[pivot] + strs[j]){
                j--;
            }
            while(i < j && strs[i] + strs[pivot] >= strs[pivot] + strs[i]){
                i++;
            }
            swap(strs[i], strs[j]);
        }
        swap(strs[pivot], strs[i]);
        quickSort(strs, left, i - 1);
        quickSort(strs, i + 1, right);
    }
};

方法三:内置函数 cmp_to_key

from typing import List
from functools import cmp_to_key


class Solution:
    # 先把nums中的所有数字转化为字符串,形成字符串数组 nums_str
    # 比较两个字符串x,y的拼接结果x+y和y+x哪个更大,从而确定x和y谁排在前面;将nums_str降序排序
    # 把整个数组排序的结果拼接成一个字符串,并且返回
    def largestNumber(self, nums: List[int]) -> str:
        print("原始数据:nums = ", nums)
        nums_str = list(map(str, nums))
        print("转为字符串后:nums_str = ", nums_str)
        compare = lambda x, y: 1 if x + y < y + x else -1
        nums_str.sort(key=cmp_to_key(compare))
        print("按照自定义规则排序后:nums_str = ", nums_str)
        res = ''.join(nums_str)
        if res[0] == '0':
            res = '0'
        return res


nums = [3, 30, 34, 5, 9]
solution = Solution()
result = solution.largestNumber(nums=nums)
print("result = ", result)
原始数据:nums =  [3, 30, 34, 5, 9]
转为字符串后:nums_str =  ['3', '30', '34', '5', '9']
按照自定义规则排序后:nums_str =  ['9', '5', '34', '3', '30']
result =  9534330

Process finished with exit code 0

148. 排序链表

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 1:
在这里插入图片描述

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:
在这里插入图片描述

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目在范围 [ 0 , 5 ∗ 1 0 4 ] [0, 5 * 10^4] [0,5104]
  • − 1 0 5 < = N o d e . v a l < = 1 0 5 -10^5 <= Node.val <= 10^5 105<=Node.val<=105

进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?


方法一:快速排序(没有随机化,超时)

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        if head is None:
            return head

        # 分成三个链表,分别是比轴心数小,相等,大的数组成的链表
        big = None
        small = None
        equal = None
        cur = head
        while cur is not None:
            t = cur
            cur = cur.next
            if t.val < head.val:
                t.next = small
                small = t
            elif t.val > head.val:
                t.next = big
                big = t
            else:
                t.next = equal
                equal = t
        
        # 拆完各自排序即可,equal 无需排序
        big = self.sortList(big)
        small = self.sortList(small)

        ret = ListNode(None)
        cur = ret

        # 将三个链表组合成一起,这一步复杂度是 o(n)
        # 可以同时返回链表的头指针和尾指针加速链表的合并。
        for p in [small, equal, big]:
            while p is not None:
                cur.next = p
                p = p.next
                cur = cur.next
                cur.next = None
        return ret.next

方法二:归并排序

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    # 归并排序
    def sortList(self, head: ListNode) -> ListNode:
        if not head or not head.next: 
            return head
        
        left_end = self.find_left_end(head)
        new_head = left_end.next 
        left_end.next = None

        left = self.sortList(head)
        right = self.sortList(new_head)
        
        return self.merged(left, right)
    
    # 快慢指针查找链表中点(左半链表的结尾节点)
    def find_left_end(self, head):
        if head is None or head.next is None: 
            return head
        
        slow,fast = head, head
        
        while fast and fast.next and fast.next.next:
            slow=slow.next
            fast=fast.next.next
        
        return slow
    
    # 合并有序链表
    def merged(self, left, right):
        dummy = ListNode()
        prev = dummy
        while left and right:
            if left.val < right.val: 
                prev.next = left
                left = left.next
            else: 
                prev.next = right
                right = right.next
            prev = prev.next
        
        prev.next = left if left else right
        
        return dummy.next

方法三:堆排序

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        from queue import PriorityQueue
        ptr = head
        p_queue = PriorityQueue()
        while ptr != None:
            p_queue.put(ptr.val)
            ptr = ptr.next
            
        ptr = head
        while not p_queue.empty():
            ptr.val = p_queue.get()
            ptr = ptr.next
        return head

面试题 17.14. 最小K个数

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例:

输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]

提示:

  • 0 <= len(arr) <= 100000
  • 0 <= k <= min(100000, len(arr))

方法一:快速排序(随机化处理)

class Solution:
    def partition(self, nums, l, r):
        pivot = nums[r]
        i = l - 1
        for j in range(l, r):
            if nums[j] <= pivot:
                i += 1
                nums[i], nums[j] = nums[j], nums[i]
        nums[i + 1], nums[r] = nums[r], nums[i + 1]
        return i + 1

    def randomized_partition(self, nums, l, r):
        i = random.randint(l, r)
        nums[r], nums[i] = nums[i], nums[r]
        return self.partition(nums, l, r)

    def randomized_selected(self, arr, l, r, k):
        pos = self.randomized_partition(arr, l, r)
        num = pos - l + 1
        if k < num:
            self.randomized_selected(arr, l, pos - 1, k)
        elif k > num:
            self.randomized_selected(arr, pos + 1, r, k - num)

    def smallestK(self, arr: List[int], k: int) -> List[int]:
        if k == 0:
            return list()
        self.randomized_selected(arr, 0, len(arr) - 1, k)
        return arr[:k]

方法二:堆

class Solution:
    def smallestK(self, arr: List[int], k: int) -> List[int]:
        if k == 0:
            return list()

        hp = [-x for x in arr[:k]]
        heapq.heapify(hp)
        for i in range(k, len(arr)):
            if -hp[0] > arr[i]:
                heapq.heappop(hp)
                heapq.heappush(hp, -arr[i])
        ans = [-x for x in hp]
        return ans

方法三:直接调用排序函数

class Solution:
    def smallestK(self, arr: List[int], k: int) -> List[int]:
        arr.sort()
        return arr[:k]

剑指 Offer 45. 把数组排成最小的数【面试题45. 把数组排成最小的数】

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

示例 1:

输入: [10,2]
输出: "102"

示例 2:

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

提示:0 < nums.length <= 100

说明:

  • 输出结果可能非常大,所以你需要返回一个字符串而不是整数
  • 拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0

https://leetcode.cn/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/solution/by-dormiveglia_zachary-5dqj/

冒泡排序

class Solution {
public:
    string minNumber(vector<int>& nums) {
        int len = nums.size();
        for (int i = 0; i < len  - 1; i++){
            bool isSort = true;
            for (int j = 0; j < len - 1 - i ; j++){
                string s1 = to_string (nums[j]) + to_string (nums[j + 1]);
                string s2 = to_string (nums[j + 1]) + to_string (nums[j]);
                if (s1 > s2){
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                    isSort = false;
                }
            }

            if (isSort) break;
        }

        string ret = "";
        for (int i = 0; i < len; i++){
            ret += to_string (nums[i]);
        }
        
        return ret;
    }
};

选择排序

class Solution {
public:
    string minNumber(vector<int>& nums) {
        // 选择排序
        int len = nums.size();
        vector<string> ans;
        for (auto num : nums){
            ans.push_back(to_string(num));
        }

        for (int i = 0; i < len; i++){
            int minIndex = i;
            for (int j = i + 1; j < len; j++){
                if (ans[minIndex] + ans[j] > ans[j] + ans[minIndex]){
                    minIndex = j;
                }
            }

            string temp = ans[minIndex];
            ans[minIndex] = ans[i];
            ans[i] = temp;
        }

        string ret = "";
        for (auto str : ans){
            ret += str;
        }
        
        return ret;
    }
};

插入排序

class Solution {
public:
    string minNumber(vector<int>& nums) {
        // 插入排序
        int len = nums.size();
        vector<string> ans;
        for (auto num : nums) ans.push_back(to_string(num));

        for (int i = 1; i < len; i++){
            for (int j = i; j > 0 && ans[j - 1] + ans[j] > ans[j] + ans[j - 1]; j--){
                string tmp = ans[j - 1];
                ans[j - 1] = ans[j];
                ans[j] = tmp;
            }
        }

        string ret = "";
        for (auto str : ans) ret += str;
        return ret;
    }
};

希尔排序

class Solution {
public:
    string minNumber(vector<int>& nums) {
        // 希尔排序
        int len = nums.size();
        vector<string> ans;
        for (auto num : nums) ans.push_back(to_string(num));

        int h = 1;
        while (h < len / 3) h = 3 * h + 1;

        while (h >= 1){
            for (int i = h; i < len; i++){
                for (int j = i; j >= h && ans[j - h] + ans[j] > ans[j] + ans[j - h]; j -= h){
                    string tmp = ans[j - h];
                    ans[j - h] = ans[j];
                    ans[j] = tmp;
                }
            }
            h /= 3;
        }
        
        string ret = "";
        for (auto str : ans) ret += str;
        return ret;
    }
};

归并排序(自顶向下)

class Solution {
public:
    string minNumber(vector<int>& nums) {
        vector<string> nums_str;
        for(int num : nums){
            nums_str.push_back(to_string(num));
        }

        sort(nums_str, 0, nums_str.size() - 1);

        string result;
        for(int i = 0; i < nums_str.size(); i++){
            result += nums_str[i];
        }

        return result;

    }

    void sort(vector<string>& nums, int left, int right){
        if(left >= right){
            return;
        }
        int mid = left + (right - left) / 2;
        sort(nums, left, mid);
        sort(nums, mid + 1, right);
        merge(nums, left, mid, right);
    }

    void merge(vector<string>& nums, int left, int mid, int right){
        int i = left;
        int j = mid + 1;
        vector<string> temp;

        while(i <= mid && j <= right){
            if(nums[i] + nums[j] < nums[j] + nums[i]){
                temp.push_back(nums[i]);
                i++;
            }else{
                temp.push_back(nums[j]);
                j++;
            }
        }
        while(i <= mid){
            temp.push_back(nums[i]);
            i++;
        }
        while(j <= right){
            temp.push_back(nums[j]);
            j++;
        }
        for(int i = 0; i < temp.size(); i++){
            nums[left] = temp[i];
            left++;
        }
    }
};
class Solution:
    def minNumber(self, nums: List[int]) -> str:
        nums_str = list(map(str,nums))
        self.sort(nums_str,0,len(nums_str)-1)

        result = "".join(nums_str)
        return result

    def sort(self, nums:List[str],left:int,right:int):
        if left>=right:
            return
        mid = left + (right - left)//2
        self.sort(nums,left,mid)
        self.sort(nums,mid+1,right)
        self.merge(nums,left,mid,right)

    def merge(self, arr,left,mid,right):
        i = left
        j = mid+1
        temp = []

        while i<=mid and j <=right:
            if arr[i]+arr[j] < arr[j]+arr[i]:
                temp.append(arr[i])
                i +=1
            else:
                temp.append(arr[j])
                j +=1
        while i<=mid:
            temp.append(arr[i])
            i+=1
        while j<=right:
            temp.append(arr[j])
            j+=1

        for i in range(len(temp)):
            arr[left]=temp[i]
            left +=1

归并排序-自底向上

class Solution {
public:
    string minNumber(vector<int>& nums) {
        // 归并排序,自底向上
        int len = nums.size();
        vector<string> ans;
        for (auto num : nums) ans.push_back(to_string(num));
        vector<string> tmp(len);

        for (int i = 1; i < len; i = i + i){
            for (int j = 0; j < len - i; j += i + i){
                Merge(ans, tmp, j, j + i - 1, min(j + i + i - 1, len - 1));
            }
        }
        
        string ret = "";
        for (auto str : ans) ret += str;
        return ret;
    }


    void Merge(vector<string>& ans, vector<string> tmp, int left, int mid, int right){
        int i = left, j = mid + 1;
        for (int k = left; k <= right; k++){
            tmp[k] = ans[k];
        }
        for (int k = left; k <= right; k++){
            if (i > mid) ans[k] = tmp[j++];
            else if (j > right) ans[k] = tmp[i++];
            else if (tmp[i] + tmp[j] > tmp[j] + tmp[i]) ans[k] = tmp[j++];
            else ans[k] = tmp[i++];
        }
    }
};

快速排序

class Solution {
public:
    string minNumber(vector<int>& nums) {
        // 快速排序
        int len = nums.size();
        vector<string> ans;
        for (auto num : nums) ans.push_back(to_string(num));
        sort(ans, 0, len - 1);
        string ret = "";
        for (auto str : ans) ret += str;
        return ret;
    }

    void sort(vector<string>& ans, int left, int right){
        if (right <= left) return;
        int j = partition(ans, left, right);
        sort(ans, left, j - 1);
        sort(ans, j + 1, right);
    }
    
    // 切分
    int partition(vector<string>& ans, int left, int right){
        int i = left, j = right;
        string pivot = ans[left];
        while (true){
            while (ans[i] + pivot <= pivot + ans[i]){
                if (++i > j) break;
            }
            while (pivot + ans[j] < ans[j] + pivot){
                if (--j < i) break;
            }
            if (i >= j) break;
            string tmp = ans[i];
            ans[i] = ans[j];
            ans[j] = tmp;
        }
        string tmp = ans[left];
        ans[left] = ans[j];
        ans[j] = tmp;
        return j;
    }
};
class Solution:
    def minNumber(self, nums: List[int]) -> str:
        def quick_sort(l , r):
            if l >= r: return
            i, j = l, r
            while i < j:
                while strs[j] + strs[l] >= strs[l] + strs[j] and i < j: j -= 1
                while strs[i] + strs[l] <= strs[l] + strs[i] and i < j: i += 1
                strs[i], strs[j] = strs[j], strs[i]
            strs[i], strs[l] = strs[l], strs[i]
            quick_sort(l, i - 1)
            quick_sort(i + 1, r)
        
        strs = [str(num) for num in nums]
        quick_sort(0, len(strs) - 1)
        return ''.join(strs)

快速排序-三向切分

class Solution {
public:
    string minNumber(vector<int>& nums) {
        // 快速排序-三向切分
        int len = nums.size();
        vector<string> ans;
        for (auto num : nums) ans.push_back(to_string(num));
        sort(ans, 0, len - 1);
        string ret = "";
        for (auto str : ans) ret += str;
        return ret;
    }

    void sort(vector<string>& ans, int left, int right){
        if (right <= left) return;
        int lt = left, i = left + 1, gt = right;
        string tmp = ans[left];
        while(i <= gt){

            if (ans[i] + tmp == tmp + ans[i]){
                i++;
            }
            else if (ans[i] + tmp < tmp + ans[i]){
                exchange(ans, lt++, i++);
            }
            else{
                exchange(ans, i, gt--);
            }
        }

        sort(ans, left, lt - 1);
        sort(ans, gt + 1, right);
    }
    
    // 交换
    void exchange(vector<string>& ans, int exchIndex1, int exchIndex2){
        int len = ans.size();
        if (exchIndex1 >= 0 && exchIndex1 < len && exchIndex2 >= 0 && exchIndex2 < len){
            string tmp = ans[exchIndex1];
            ans[exchIndex1] = ans[exchIndex2];
            ans[exchIndex2] = tmp;
        }
    }
};

方法二:内置函数 cmp_to_key

class Solution:
    def minNumber(self, nums: List[int]) -> str:
        def sort_rule(x, y):
            a, b = x + y, y + x
            if a > b: return 1
            elif a < b: return -1
            else: return 0
        
        strs = [str(num) for num in nums]
        strs.sort(key = functools.cmp_to_key(sort_rule))
        return ''.join(strs)

147. 对链表进行插入排序

对链表进行插入排序。

插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。

插入排序算法:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

方法一:插入排序

class Solution:
    def insertionSortList(self, head: ListNode) -> ListNode:
        if not head:
            return head
        
        dummyHead = ListNode(0)
        dummyHead.next = head
        lastSorted = head
        curr = head.next

        while curr:
            if lastSorted.val <= curr.val:
                lastSorted = lastSorted.next
            else:
                prev = dummyHead
                while prev.next.val <= curr.val:
                    prev = prev.next
                lastSorted.next = curr.next
                curr.next = prev.next
                prev.next = curr
            curr = lastSorted.next
        
        return dummyHead.next

剑指 Offer 51. 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:

输入: [7,5,6,4]
输出: 5

限制:

  • 0 <= 数组长度 <= 50000

class Solution {
public:
    int result = 0;
    int reversePairs(vector<int>& nums) {
        int left = 0;
        int right = nums.size() - 1;
        sort(nums, left, right);
        
        return result;
    }

    void sort(vector<int>& nums, int left, int right){
        if(left >= right){
            return;
        }
        int mid = left + (right - left) / 2;
        sort(nums, left, mid);
        sort(nums, mid + 1, right);
        merge(nums, left, mid, right);
    }

    void merge(vector<int>& nums, int left, int mid, int right){
        int i = left;
        int j = mid + 1;
        vector<int> temp;
        while(i <= mid && j <= right){
            if(nums[i] <= nums[j]){
                temp.push_back(nums[i]);
                i++;
            }else{
                temp.push_back(nums[j]);
                j++;
                result += mid - i + 1;
            }
        }
        while(i <= mid){
            temp.push_back(nums[i]);
            i++;
        }
        while(j <= right){
            temp.push_back(nums[j]);
            j++;
        }
        for(int num : temp){
            nums[left] = num;
            left++;
        }
    }
};
class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        self.result = 0
        left = 0
        right = len(nums) - 1

        self.sort(nums, left, right)
        return self.result

    def sort(self, nums, left, right):
        if left >= right:
            return
        mid = left + (right - left) // 2
        self.sort(nums, left, mid)
        self.sort(nums, mid + 1, right)
        self.merge(nums, left, mid, right)

    def merge(self, nums, left, mid, right):
        i = left
        j = mid + 1
        temp = []
        while i <= mid and j <= right:
            if nums[i] <= nums[j]:
                temp.append(nums[i])
                i += 1
            else:
                temp.append(nums[j])
                j += 1
                self.result += mid - i + 1 
        while i <= mid:
            temp.append(nums[i])
            i += 1
        while j <= right:
            temp.append(nums[j])
            j += 1
        for num in temp:
            nums[left] = num
            left += 1

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        left = 0
        right = len(nums) - 1
        result = 0

        def sort(left, right):
            if left >= right:
                return
            mid = left + (right - left) // 2
            sort(left, mid)
            sort(mid + 1, right)
            merge(left, mid, right)

        def merge(left, mid, right):
            nonlocal result
            i = left
            j = mid + 1
            temp = []
            while i <= mid and j <= right:
                if nums[i] <= nums[j]:
                    temp.append(nums[i])
                    i += 1
                else:
                    temp.append(nums[j])
                    j += 1
                    result += mid - i + 1 
            while i <= mid:
                temp.append(nums[i])
                i += 1
            while j <= right:
                temp.append(nums[j])
                j += 1
            for num in temp:
                nums[left] = num
                left += 1

        sort(left, right)
        return result

剑指 Offer II 076. 数组中的第 k 大的数字(快速排序+剪枝)【215. 数组中的第K个最大元素】

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4

提示:

  • 1 < = k < = n u m s . l e n g t h < = 1 0 4 1 <= k <= nums.length <= 10^4 1<=k<=nums.length<=104
  • − 1 0 4 < = n u m s [ i ] < = 1 0 4 -10^4 <= nums[i] <= 10^4 104<=nums[i]<=104

注意:本题与主站 215 题相同: https://leetcode-cn.com/problems/kth-largest-element-in-an-array/


class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:

        def sort(nums, left, right):   
            if left >= right:
                return
            
            p = partition(nums, left, right)
            idx = len(nums) - p 
            
            #寻找到第k个数停止递归,使得nums数组中index左边是前k个小的数,index右边是后面n-k个大的数
            if idx==k:
                return
            elif idx > k:
                sort(nums, p+1, right)
            else:
                sort(nums, left, p-1)        


        def partition(nums, left, right):
            pivot = left #初始化一个待比较数据
            i = left + 1
            j = right
            
            while i <= j:
                while i <= j and nums[j] >= nums[pivot]: #从后往前查找,直到找到一个比pivot更小的数
                    j-=1
                while i <= j and nums[i] <= nums[pivot]: #从前往后找,直到找到一个比pivot更大的数
                    i+=1
                if i >= j:
                    break
                nums[i], nums[j] = nums[j], nums[i]  #将更大的数放入右边
            
            #循环结束,i与j相等
            nums[j], nums[pivot] = nums[pivot], nums[j] #待比较数据放入最终位置 
            return j #返回待比较数据最终位置


        sort(nums, 0, len(nums)-1)

        print('nums = ', nums)

        return nums[len(nums) - k]

输入:

[3,8,2,9,1,5,6,4,0]
2

打印结果:

[1, 0, 2, 3, 4, 5, 6, 8, 9]
class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:

        def sort(nums, left, right, idx):   #寻找到第k个数停止递归,使得nums数组中index左边是前k个小的数,index右边是后面n-k个大的数
            if left >= right:
                return
            
            p = partition(nums, left, right)
            
            if p==idx:
                return 
            elif p < idx:
                sort(nums, p+1, right, idx)
            else:
                sort(nums, left, p-1, idx)        


        def partition(nums, left, right):
            pivot = left #初始化一个待比较数据
            i = left + 1
            j = right
            
            while i <= j:
                while i <= j and nums[j] >= nums[pivot]: #从后往前查找,直到找到一个比pivot更小的数
                    j-=1
                while i <= j and nums[i] <= nums[pivot]: #从前往后找,直到找到一个比pivot更大的数
                    i+=1
                if i >= j:
                    break
                nums[i], nums[j] = nums[j], nums[i]  #将更大的数放入右边
            
            #循环结束,i与j相等
            nums[j], nums[pivot] = nums[pivot], nums[j] #待比较数据放入最终位置 
            return j #返回待比较数据最终位置


        sort(nums, 0, len(nums)-1, len(nums)-k) #把k换成len(nums)-k
            
        print(nums)
        
        return nums[len(nums) - k]

打印结果:

[1, 0, 2, 3, 4, 5, 6, 8, 9]
class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:

        def sort(nums, left, right, idx):   #寻找到第k个数停止递归,使得nums数组中index左边是前k个小的数,index右边是后面n-k个大的数
            
            if left >= right:
                return
 
            p = partition(nums, left, right)
            if p==idx:
                return 
            elif p < idx:
                sort(nums, p+1, right, idx)
            else:
                sort(nums, left, p-1, idx)        


        def partition(nums, left, right):
            pivot = left #初始化一个待比较数据
            i = left + 1
            j = right
            
            while i <= j:
                while i <= j and nums[j] >= nums[pivot]: #从后往前查找,直到找到一个比pivot更小的数
                    j-=1
                while i <= j and nums[i] <= nums[pivot]: #从前往后找,直到找到一个比pivot更大的数
                    i+=1
                if i >= j:
                    break
                nums[i], nums[j] = nums[j], nums[i]  #将更大的数放入右边
            
            #循环结束,i与j相等
            nums[j], nums[pivot] = nums[pivot], nums[j] #待比较数据放入最终位置 
            return j #返回待比较数据最终位置


        def topk_large(nums, k):
            #parttion是按从小到大划分的,如果让index左边为前n-k个小的数,则index右边为前k个大的数
            sort(nums, 0, len(nums)-1, len(nums)-k) #把k换成len(nums)-k
            print(nums)
            return nums[len(nums)-k] 
            

        return topk_large(nums, k)
class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        n = len(nums)
        def quick_find(start, end):
            ```
            这是类快排,大体和快排相同但做了适当优化
            ```
            nonlocal n
            pivot = start
            left, right = start, end

            while left < right:
                while left < right and nums[right] >= nums[pivot]: right -= 1   # 如果当前值大于nums[pivot]的值,就继续往左找,直到发现小于的值
                while left < right and nums[left] <= nums[pivot]: left += 1
                nums[left], nums[right] = nums[right], nums[left]
            nums[pivot], nums[right] = nums[right], nums[pivot]     # 此时,pivot左边的数都比nums[pivot]小。同理,右边的都比nums[pivot]大

            if right == n - k:
                return nums[right]      # 此时说明发现了第k大的数,返回
            elif right < n - k:
                return quick_find(right + 1, end)   # 说明第k大的数在右半边,只排右边的
            else:
                return quick_find(start, right - 1)     # 同理,只排左边的
        return quick_find(0, n - 1)

参考:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/solution/pythonpython3-top-kwo-yong-si-chong-fang-y2t2/

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:

        def sort(nums, left, right, idx):   #寻找到第k个数停止递归,使得nums数组中index左边是前k个小的数,index右边是后面n-k个大的数
            
            if left >= right:
                return
 
            p = partition(nums, left, right)
            if p==idx:
                return 
            elif p < idx:
                sort(nums, p+1, right, idx)
            else:
                sort(nums, left, p-1, idx)        


        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 #返回待比较数据最终位置



        def topk_large(nums, k):
            #parttion是按从小到大划分的,如果让index左边为前n-k个小的数,则index右边为前k个大的数
            sort(nums, 0, len(nums)-1, len(nums)-k) #把k换成len(nums)-k
            return nums[len(nums)-k] 


        return topk_large(nums, k)

912. 排序数组

给你一个整数数组 nums,请你将该数组升序排列。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]

提示:

  • 1 < = n u m s . l e n g t h < = 5 ∗ 1 0 4 1 <= nums.length <= 5 * 10^4 1<=nums.length<=5104
  • − 5 ∗ 1 0 4 < = n u m s [ i ] < = 5 ∗ 1 0 4 -5 * 10^4 <= nums[i] <= 5 * 10^4 5104<=nums[i]<=5104

1、二路快排(随机)

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def sort(nums, left, right):
            if left >= right:
                return
            p = partition(nums, left, right)
            sort(nums, left, p - 1)
            sort(nums, p + 1, right)
        
        def partition(nums, left, right):
            rand = random.randint(left, right)
            nums[left], nums[rand] = nums[rand], nums[left]
            i = left + 1
            j = right
            povit = left

            while True:
                while i <= j and nums[i] <= nums[povit]:
                    i += 1
                while i <= j and nums[j] >= nums[povit]:
                    j -= 1
                if i >= j:
                    break
                nums[i], nums[j] = nums[j], nums[i]
            nums[j], nums[povit] = nums[povit], nums[j]
            return j
        
        sort(nums, 0, len(nums) - 1)
        return nums
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值