目录
简单难度
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