# 1 - 2169. Count Operations to Obtain Zero
class Solution: | |
def countOperations(self, num1: int, num2: int) -> int: | |
cnt = 0 | |
while num1 and num2: | |
num1, num2 = max(num1, num2), min(num1, num2) | |
num1 = num1 - num2 | |
cnt += 1 | |
return cnt |
# 2 - 2170. Minimum Operations to Make the Array Alternating
class Solution: | |
def minimumOperations(self, nums: List[int]) -> int: | |
n = len(nums) | |
if n <= 1: return 0 | |
if n == 2: return 1 if nums[0] == nums[1] else 0 | |
ctr0 = Counter(nums[i] for i in range(n) if i % 2 == 0) | |
ctr1 = Counter(nums[i] for i in range(n) if i % 2 == 1) | |
ans = 0 | |
mc0 = ctr0.most_common(2) | |
mc1 = ctr1.most_common(2) | |
# print(mc0, mc1) | |
if mc0[0][0] != mc1[0][0]: ans = (n // 2 + n % 2 - mc0[0][1]) + (n // 2 - mc1[0][1]) | |
else: | |
a = (n // 2 + n % 2 - (mc0[1][1] if len(mc0) >= 2 else 0)) + (n // 2 - mc1[0][1]) | |
b = (n // 2 + n % 2 - mc0[0][1]) + (n // 2 - (mc1[1][1] if len(mc1) >= 2 else 0)) | |
ans = min(a, b) | |
return ans |
这道题 WA 了两发,一次是 mc 可能只包含一个,另一个是对于 2 2
这种两个相同的。
# 3 - 2171. Removing Minimum Number of Magic Beans
class Solution: | |
def minimumRemoval(self, beans: List[int]) -> int: | |
beans.sort() | |
n = len(beans) | |
cur = sum(beans) - n * beans[0] | |
ans = cur | |
for i in range(1, n): | |
cur = cur + beans[i-1] - (n - i) * (beans[i] - beans[i-1]) | |
ans = min(ans, cur) | |
# print(cur, ans) | |
return ans |
找到上一个和下一个的关系就很简单。
# 4 - 2172. Maximum AND Sum of Array
首先两个 TLE 的解法:
class Solution: | |
def maximumANDSum(self, nums: List[int], numSlots: int) -> int: | |
n, m = len(nums), numSlots | |
ans = 0 | |
slots = [0] * m | |
place = [-1] * n | |
def recur(idx): | |
nonlocal ans | |
if idx == n: | |
cur = sum((place[i] + 1) & nums[i] for i in range(n)) | |
ans = max(ans, cur) | |
# print(place, slots, cur) | |
return | |
myslots = [i for i in range(m) if slots[i] <= 1] | |
for i in myslots: | |
slots[i] += 1 | |
place[idx] = i | |
recur(idx + 1) | |
slots[i] -= 1 | |
recur(0) | |
return ans | |
class Solution: | |
def maximumANDSum(self, nums: List[int], numSlots: int) -> int: | |
n, m = len(nums), numSlots | |
ans = 0 | |
for x in range(numSlots ** n): | |
ctr = Counter() | |
for i in range(n): | |
ctr[x // (m ** i) % m] += 1 | |
if len(ctr) >= 1 and ctr.most_common(1)[0][1] > 2: continue | |
cur = 0 | |
for i, num in enumerate(nums): | |
slot = (x // (m ** i) % m) + 1 | |
cur += num & slot | |
# print(x, cur) | |
ans = max(ans, cur) | |
return ans |
灵神的状压 dp:
class Solution: | |
def maximumANDSum(self, nums: List[int], numSlots: int) -> int: | |
f = [0] * (1 << (numSlots * 2)) | |
for i, fi in enumerate(f): | |
c = i.bit_count() | |
if c >= len(nums): | |
continue | |
for j in range(numSlots * 2): | |
if (i & (1 << j)) == 0: | |
s = i | (1 << j) | |
f[s] = max(f[s], fi + ((j // 2 + 1) & nums[c])) | |
return max(f) |
9400ms 左右,有时候会 TLE……
抄大佬的匈牙利算法:
import numpy as np | |
from scipy.optimize import linear_sum_assignment | |
class Solution: | |
def maximumANDSum(self, nums: List[int], ns: int) -> int: | |
nums, slots, mx = nums + [0] * (2 * ns - len(nums)), [*range(1, ns + 1)] * 2, np.zeros((ns * 2, ns * 2)) | |
for (i, x), (j, sn) in product(enumerate(nums), enumerate(slots)): mx[i, j] = x & sn | |
row, col = linear_sum_assignment(-mx) | |
return int(mx[row, col].sum()) |
只有 200~500ms 的样子,恐怖如斯。
最后再贴一个蒙特卡洛大师 Master of Monte Carlo 的做法:
class Solution: | |
def maximumANDSum(self, nums: List[int], numSlots: int) -> int: | |
ans = 0 | |
for i in range(1000): # guess enough times | |
random.shuffle(nums) # try different orders randomly | |
cur = 0 | |
counter = defaultdict(int) | |
for n in nums: | |
j = 0 | |
for i in range(1, numSlots+1): | |
if counter[i] < 2 and n & i > n & j: # Greedy | |
j = i | |
counter[j] += 1 | |
cur += n & j | |
ans = max(ans, cur) | |
return ans |
……