LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)相关的知识,希望对你有一定的参考价值。
870. 优势洗牌
2022.10.8 国庆回来,先巩固代码
题目描述
给定两个大小相等的数组 nums1 和 nums2,nums1 相对于 nums 的优势可以用满足 nums1[i] > nums2[i] 的索引 i 的数目来描述。
返回 nums1 的任意排列,使其相对于 nums2 的优势最大化。
示例 1:
输入:nums1 = [2,7,11,15], nums2 = [1,10,4,11]
输出:[2,11,7,15]
示例 2:
输入:nums1 = [12,24,8,32], nums2 = [13,25,32,11]
输出:[24,32,8,12]
提示:
1 <= nums1.length <= 10^5
nums2.length == nums1.length
0 <= nums1[i], nums2[i] <= 10^9
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/advantage-shuffle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
超时了
想到要超时了,但是一下想不出怎么才能良好的改进,因为可能出现重复的数字,所以所用的字典还不能直接用num2中的数字来直接作为键,或者说需要将值变成一个列表,但是变成列表也需要
或者说需要有一个字典来记录num2排序后对应的数字顺序
class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 其实就是在nums1 中找比nums2中数字刚好大一点的数字,这个可以用二分
# 但是找到以后还需要删除才能找下一个,这样就比较麻烦
# 所以还是将两个数据排序,然后对应比较直接
# 将可以对应的数字放到一个字典中,剩下的数字放在一个列表中
# 然后遍历nums2,按照字典对应关系填充nums1,找不到的就从列表中拿数字
n1 = nums1.copy()
n2 = nums2.copy()
n1.sort()
n2.sort()
d, lst = dict(), []
i, j = 0, 0
while i < len(n1) and j < len(n2):
# 如果大于,那么放在字典里
if n1[i] > n2[j]:
d[j] = n1[i]
i += 1
j += 1
# 如果小于等于,那么放在列表里
else:
lst.append(n1[i])
i += 1
idx = 0
for i, n in enumerate(nums2):
for j in d:
if n == n2[j]:
nums1[i] = d[j]
d.pop(j)
break
else:
nums1[i] = lst[idx]
idx += 1
return nums1
还是直接二分吧,但是已经找过的数字怎么处理呢?
放在set集合中,然后下一次再找到这个数字就跳过,然后向后取一个没有使用过的
试一试
二分过了
class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 其实就是在nums1 中找比nums2中数字刚好大一点的数字,这个可以用二分
# 但是找到以后还需要删除才能找下一个,这样就比较麻烦
# 所以还是将两个数据排序,然后对应比较直接
# 将可以对应的数字放到一个字典中,剩下的数字放在一个列表中
# 然后遍历nums2,按照字典对应关系填充nums1,找不到的就从列表中拿数字
n1 = nums1.copy()
#n2 = nums2.copy()
n1.sort()
#n2.sort()
s = set()
l = len(nums1)
res = [-1] * l
for i, n in enumerate(nums2):
left = 0
right = l - 1
while left < right:
mid = (right - left) // 2 + left
# 如果这个数大于n
if n1[mid] > n:
right = mid
else:
left = mid + 1
if n1[left] <= n:
continue
while left in s:
left += 1
if left >= l:
continue
s.add(left)
res[i] = n1[left]
#print(res)
idx = 0
for i, n in enumerate(n1):
while idx < l and res[idx] != -1:
idx += 1
if idx == l:
break
if i not in s:
res[idx] = n
return res
官解中直接对索引排序的代码,很巧妙,这个需要学会
class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
n = len(nums1)
idx1, idx2 = list(range(n)), list(range(n))
# 直接对索引进行排序
idx1.sort(key=lambda x: nums1[x])
idx2.sort(key=lambda x: nums2[x])
ans = [0] * n
left, right = 0, n - 1
for i in range(n):
# 如果能找到比2中数字大的,那么就填充从左到右填充ans
if nums1[idx1[i]] > nums2[idx2[left]]:
ans[idx2[left]] = nums1[idx1[i]]
left += 1
else:
# 当前数字没有2中数字大,那么当前数字多余,所以放在最后
ans[idx2[right]] = nums1[idx1[i]]
right -= 1
return ans
856. 括号的分数
2022.10.9 每日一题
题目描述
给定一个平衡括号字符串 S,按下述规则计算该字符串的分数:
() 得 1 分。
AB 得 A + B 分,其中 A 和 B 是平衡括号字符串。
(A) 得 2 * A 分,其中 A 是平衡括号字符串。
示例 1:
输入: “()”
输出: 1
示例 2:
输入: “(())”
输出: 2
示例 3:
输入: “()()”
输出: 2
示例 4:
输入: “(()(()))”
输出: 6
提示:
S 是平衡括号字符串,且只含有 ( 和 ) 。
2 <= S.length <= 50
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/score-of-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
class Solution:
def scoreOfParentheses(self, s: str) -> int:
# 还是那种栈处理括号的题吧
# 遇到左括号入栈,遇到右括号出栈,匹配
# 然后进行计算,计算结果放到栈中,如果前面有数字就做加法
# 如果右括号前面是数字,那么就做乘法
stack = []
for ss in s:
if ss == '(':
stack.append(ss)
else:
# 如果前面一个是数字,那么记录该数字
# 不可能出现连续两个数字
num = 0
if stack[-1] != '(':
num = stack.pop(-1)
# 弹出括号
stack.pop(-1)
num = num * 2
if len(stack) > 0 and stack[-1] != '(':
num += stack.pop(-1)
stack.append(num)
else:
# 如果是括号,那么就等于1
# 先将括号弹出
stack.pop(-1)
num = 1
if len(stack) > 0 and stack[-1] != '(':
num += stack.pop(-1)
stack.append(num)
return stack.pop(-1)
用数字代替符号
class Solution:
def scoreOfParentheses(self, s: str) -> int:
# 直接用数字代替
# 遇到左括号,是0,遇到右边括号,如果前一个是0,那么就是1
# 如果前一个不是0,那么就乘以2加上前面的,
# 其实和之前思路一样,就是写法更简单了
# 这里为了能使两种情况合并为一种,在开始加了0
stack = [0]
for c in s:
if c == '(':
stack.append(0)
else:
top = stack.pop()
stack.append(stack.pop() + max(top * 2, 1))
return stack.pop()
直接看()相邻能形成配对括号的层数
class Solution:
def scoreOfParentheses(self, s: str) -> int:
# 第三种,其实就是看()这种括号的层数,有一层就多乘以2
res = 0
level = 0
for i,c in enumerate(s):
level += 1 if c == '(' else -1
if c == ')' and s[i - 1] == '(':
res += 1 << level
return res
801. 使序列递增的最小交换次数
2022.10.10 每日一题
题目描述
我们有两个长度相等且不为空的整型数组 nums1 和 nums2 。在一次操作中,我们可以交换 nums1[i] 和 nums2[i]的元素。
- 例如,如果 nums1 = [1,2,3,8] , nums2 =[5,6,7,4] ,你可以交换 i = 3 处的元素,得到 nums1 =[1,2,3,4] 和 nums2 =[5,6,7,8] 。
返回 使 nums1 和 nums2 严格递增 所需操作的最小次数 。
数组 arr 严格递增 且 arr[0] < arr[1] < arr[2] < … < arr[arr.length - 1] 。
注意:
- 用例保证可以实现操作。
示例 1:
输入: nums1 = [1,3,5,4], nums2 = [1,2,3,7]
输出: 1
解释:
交换 A[3] 和 B[3] 后,两个数组如下:
A = [1, 3, 5, 7] , B = [1, 2, 3, 4]
两个数组均为严格递增的。
示例 2:
输入: nums1 = [0,3,5,8,9], nums2 = [2,1,4,6,9]
输出: 1
提示:
2 <= nums1.length <= 10^5
nums2.length == nums1.length
0 <= nums1[i], nums2[i] <= 2 * 10^5
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-swaps-to-make-sequences-increasing
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
好久不做dp了,有点难搞
class Solution:
def minSwap(self, nums1: List[int], nums2: List[int]) -> int:
# 看数据范围,最多是个nlogn的复杂度
# 而且看到了顺序,所以二分可能会用到
# 然后呢,看了下例子,好像是看到不满足顺序的,就需要进行调整
# 但是怎么调整,换哪个呢
# 为了能够更好的接上后面的数字,肯定是使递增序列越小越好
# 动态规划
# dp[i][0] 表示i位置不交换使得递增的最少次数,dp[i][1]表示交换使得递增的最少次数
# 如果当前位置符合交换的条件1,即a2>a1 && b2>b1,则可以都交换或者都不交换
# 如果当前位置符合交换的条件2,即a2>b1 && b2>a1,则可以交换1次
# 如果都满足,取较小值
l = len(nums1)
dp = [[l+1, l+1] for _ in range(l)]
dp[0] = [0, 1]
for i in range(1, l):
if nums1[i] > nums1[i - 1] and nums2[i] > nums2[i - 1]:
# 上一次不交换这次也不换
dp[i][0] = dp[i - 1][0]
# 上一次交换这次也得交换
dp[i][1] = dp[i - 1][1] + 1
if nums1[i] > nums2[i - 1] and nums2[i] > nums1[i - 1]:
# 对于这次不交换的情况,如果上次没交换,说明肯定a2>a1,b2>b1所以这次也不换
# 如果上次交换了,那么这次就不用换了
dp[i][0] = min(dp[i][0], dp[i - 1][1])
# 对于本次交换了的情况,如果上次交换了,那么本次就不用交换了,否则需要交换
dp[i][1] = min(dp[i][1], dp[i - 1][0] + 1)
return min(dp[l - 1][0], dp[l - 1][1])
以上是关于LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 870 优势洗牌[自定义排序] HERODING的LeetCode之路
LeetCode 870 优势洗牌[自定义排序] HERODING的LeetCode之路