这里写目录标题
- LeetCode题目
- 1.1、56-合并区间 【中等】
- 1.2、179-最大数 【中等】
- 1.3、148-排序链表 【中等】
- 1.4、面试题 17.14-最小K个数 【中等】
- 1.5、剑指 Offer 45-把数组排成最小的数 【中等】
- 1.6、147-对链表进行插入排序 【中等】
- 56. 合并区间
- 179. 最大数
- 148. 排序链表
- 面试题 17.14. 最小K个数
- 剑指 Offer 45. 把数组排成最小的数【面试题45. 把数组排成最小的数】
- 147. 对链表进行插入排序
- 剑指 Offer 51. 数组中的逆序对
- 剑指 Offer II 076. 数组中的第 k 大的数字(快速排序+剪枝)【215. 数组中的第K个最大元素】
- 912. 排序数组
- 1、二路快排(随机)
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,5∗104] 内
- − 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:
输入: 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,5∗104] 内
- − 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
冒泡排序
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:
输入: 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)
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<=5∗104
- − 5 ∗ 1 0 4 < = n u m s [ i ] < = 5 ∗ 1 0 4 -5 * 10^4 <= nums[i] <= 5 * 10^4 −5∗104<=nums[i]<=5∗104
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