0. 赛后总结
如上一个博客所述,这周的比赛其实因为一些琐事没能参加,只是赛后做了一下比赛的题目,这里就大致记录一下吧。
1. 题目一
给出题目一的试题链接如下:
1. 解题思路
这一题我的解法其实很暴力,就是彻底的暴力求解,把所有的 2 n 2^n 2n种可能性全部计算一下,然后就能够得到最终的答案了。
2. 代码实现
给出python代码实现如下:
class Solution:
def subsetXORSum(self, nums: List[int]) -> int:
n = len(nums)
res = 0
for item in product(range(2), repeat=n):
s = 0
for flag, k in zip(item, nums):
if flag == 1:
s = s ^ k
res += s
return res
提交代码评测得到:耗时148ms,占用内存14MB。
2. 题目二
给出题目二的试题链接如下:
1. 解题思路
这一题我这边的思路其实也挺暴力的,要能够完成这种变换,那么0和1的数目就必须满足差值最多只能为1,然后最终的字符排列就是确定的,由此,我们统计一下原始字符串与最终目标字符串之间的差异字符数目就可以最终给出需要交换的次数。
2. 代码实现
给出python代码实现如下:
class Solution:
def minSwaps(self, s: str) -> int:
cnt = Counter(s)
def count_diff(s1, s2):
cnt = 0
for c1, c2 in zip(s1, s2):
if c1 != c2:
cnt += 1
return cnt // 2
if abs(cnt["0"] - cnt["1"]) > 1:
return -1
elif cnt['0'] == cnt['1'] + 1:
return count_diff("0" + "10" * (len(s) // 2), s)
elif cnt["0"] == cnt['1'] - 1:
return count_diff("1" + "01" * (len(s) // 2), s)
else:
return min(count_diff("10" * (len(s) // 2), s), count_diff("01" * (len(s) // 2), s))
提交代码评测得到:耗时24ms,占用内存14.3MB。
3. 题目三
给出题目三的试题链接如下:
1. 解题思路
这一题我给出的结构其实不算多么巧妙,就是用两个字典结构保存nums1和nums2,然后为了保留index信息,在单独保存一下nums2,然后后面的add操作的算法复杂度就是 O ( 1 ) O(1) O(1),然后count的算法复杂度就是 O ( N 1 ) O(N_1) O(N1)。
2. 代码实现
给出python代码实现如下:
class FindSumPairs:
def __init__(self, nums1: List[int], nums2: List[int]):
self.nums1_cnt = Counter(nums1)
self.nums1_elems = sorted(self.nums1_cnt.keys())
self.nums2 = nums2
self.nums2_cnt = Counter(nums2)
def add(self, index: int, val: int) -> None:
x = self.nums2[index]
self.nums2_cnt[x] -= 1
self.nums2[index] += val
self.nums2_cnt[x+val] += 1
def count(self, tot: int) -> int:
res = 0
for k in self.nums1_elems:
if k >= tot:
break
res += self.nums1_cnt[k] * self.nums2_cnt[tot-k]
return res
提交代码评测得到:耗时816ms,占用内存44.4MB。
4. 题目四
给出题目四的试题链接如下:
1. 解题思路
这次的第四题坦率地说有点一言难尽,怎么说呢,思路一开始就很明确,就是动态规划,然后就是考虑递推公式,然后就是想了一下午都没有想出来,但是看了一下答案之后发现简直简单的离谱,原因就是换个角度思考问题就行。
我们先给出递推公式如下:
f
(
n
,
k
)
=
f
(
n
−
1.
k
−
1
)
+
(
n
−
1
)
×
f
(
n
−
1
,
k
)
f(n, k) = f(n-1. k-1) + (n-1) \times f(n-1, k)
f(n,k)=f(n−1.k−1)+(n−1)×f(n−1,k)
其中, f ( n , k ) f(n, k) f(n,k)的定义就是题目中的定义,就是n个数,然后可见的数为k个。
但是,我们考察迭代公式的时候,不要去考虑加入一个最大的数,而是应该考虑将原始的排列中所有的数字加1,然后加入一个最小的数,此时,需要考虑的前一种 k k k的可能性只能为 k k k或者 k − 1 k-1 k−1,我们分别这两种情况:
- 如果原来暴露的数刚好就是k个时,我们能够加入的位置就一定是除了第一个位置之外所有的位置,所以此时的排列数目就是 ( n − 1 ) × f ( n − 1 , k ) (n-1) \times f(n-1, k) (n−1)×f(n−1,k);
- 如果原来暴露的数目为k-1时,此时我们就必须将这个最小数加入到第一个数的位置,此时的所有可能性为: f ( n − 1 , k − 1 ) f(n-1, k-1) f(n−1,k−1)。
结合上述两种情况,我们即可得到最终的递推公式。
2. 代码实现
给出python代码实现如下:
class Solution:
def rearrangeSticks(self, n: int, k: int) -> int:
MOD = 10**9+7
dp = [[0 for _ in range(k+1)] for _ in range(n+1)]
dp[1][1] = 1
for i in range(n):
for j in range(min(k, i+1)):
if i == 0 and j == 0:
continue
dp[i+1][j+1] = (dp[i][j] + i * dp[i][j+1]) % MOD
return dp[n][k]
提交代码评测得到:耗时2548ms,占用内存38.6MB。