LCP 24. 数字游戏
class Solution:
def numsGame(self, nums: List[int]) -> List[int]:
# 题目的要求 等价于 将 nums[i] - i 操作成相同的数 符合要求时, i 加 1, nums[i] 加 1
res = [0] * len(nums)
MOD = 10**9 + 7
left = [] # 维护 较小的一半 大根堆
right = [] # 维护 较大的 一半 小根堆 中位数 必定为 right[0]
left_sum = right_sum = 0
for i, num in enumerate(nums):
x = num - i
if i % 2 == 0: # 左右 元素一样多。 要把 -left[0] 和 x 中大的 添加 到 right
left_sum -= max(-left[0] - x, 0) if left else 0 # 要是 x 大于 -left[0] left 不变
temp = -heappushpop(left, -x)
right_sum += temp
heappush(right, temp)
res[i] = (right_sum - right[0] - left_sum) % MOD # 右边多。 根据计算公式 有一个中位数 无法抵消。
else: # right 多 要把 right[0] 和 x 中 小的 加到 left
right_sum += max(x - right[0], 0) # 要是 x 大于 right[0], x 加到 left。 right_sum 不变
temp = heappushpop(right, x)
left_sum += temp
heappush(left, -temp)
res[i] = (right_sum - left_sum) % MOD
return res
class Solution {
public:
vector<int> numsGame(vector<int>& nums) {
const int mod = 1e9 + 7;
vector<int> res(nums.size());
priority_queue<int> left; // 大顶堆
priority_queue<int, vector<int>, greater<int>> right; // 较长,right.top()必为中位数。 小根堆
long long left_sum = 0, right_sum = 0;
for (int i = 0; i < nums.size(); ++i){
int x = nums[i] - i;
if (i % 2 == 0){// 总长为 奇数, 中位数为 right.top() left.top()和 x 中更大的 加到 right
if (!left.empty() && x < left.top()){
left_sum -= left.top() - x; // 换了 个 更小的数
left.push(x);
x = left.top();
left.pop();
}
right_sum += x;
right.push(x);
res[i] = (right_sum - right.top() - left_sum) % mod;
}else{// 总长 为 偶数, 中位数 为 (left.top() + right.top()) / 2 right.top() 和 x 中 更小的加到 left
if (x > right.top()){ // x 替换 right.top()。 原来right.top() 加入 left
right_sum += x - right.top();
right.push(x);
x = right.top();
right.pop();
}
left_sum += x;
left.push(x);
res[i] = (right_sum - left_sum) % mod;
}
}
return res;
}
};
462. 最小操作次数使数组元素相等 II
将 所有数 变成 中位数 所需的 移动数 最少。
方法一:排序
class Solution:
def minMoves2(self, nums: List[int]) -> int:
nums.sort()
return sum(abs(num - nums[len(nums)//2]) for num in nums)
⭐ 方法二: 快速选择
class Solution {
public:
int minMoves2(vector<int>& nums) {
nth_element(nums.begin(), nums.begin() + nums.size() / 2, nums.end()); // 将数组中第k小的整数放在区间第k个位置。 中间规定找中位数
int median = nums[nums.size()/2];
int res = 0;
for (int x : nums){
res += abs(x - median); // 将所有 数 都变成中位数
}
return res;
}
};
1103. 分糖果 II
方法一:遍历, 有糖就分
class Solution:
def distributeCandies(self, candies: int, num_people: int) -> List[int]:
res = [0] * num_people
i = 0
while candies != 0:
res[i % num_people] += min(i + 1, candies)
candies -= min(i + 1, candies)
i += 1
return res
LCR 170. 交易逆序对的总数 【归并】
class Solution:
def reversePairs(self, record: List[int]) -> int:
def merge_sort(left, right):
# 终止条件
if left >= right:
return 0
# 递归 划分
mid = (left + right) // 2
res = merge_sort(left, mid) + merge_sort(mid + 1, right)
# 合并
i, j = left, mid + 1 # 两两 比较
temp[left : right + 1] = record[left : right + 1] # temp暂存之前的。 record 不断变得有序
for k in range(left, right + 1):
if i == mid + 1: # 左 子数组 遍历完成
record[k] = temp[j]
j += 1
elif j == right + 1 or temp[i] <= temp[j]: # 右 子数组 遍历完成 或 temp[i] <= temp[j]
record[k] = temp[i]
i += 1
else: # temp[i] > temp[j] # 逆序对
record[k] = temp[j]
j += 1
res += mid - i + 1 # temp[i-mid] 有序,则temp[i] - temp[mid] 均大于 temp[j] 逆序对 个数 增加 mid - i + 1
return res
temp = [0] * len(record)
return merge_sort(0, len(record) - 1)
class Solution {
public:
int reversePairs(vector<int>& record) {
vector<int> temp(record.size());
return merge_sort(0, record.size() - 1, record, temp);
}
private:
int merge_sort(int left, int right, vector<int>& record, vector<int>& temp){
// 终止条件
if (left >= right) return 0;
// 递归划分
int mid = (left + right) / 2;
int res = merge_sort(left, mid, record, temp) + merge_sort(mid + 1, right, record, temp);
// 合并
int i = left, j = mid + 1;
for (int k = left; k <= right; ++k){
temp[k] = record[k];
}
for (int k = left; k <= right; ++k){
if (i == mid + 1){
record[k] = temp[j];
++j;
}else if (j == right + 1 || temp[i] <= temp[j]){
record[k] = temp[i];
++i;
}else{
record[k] = temp[j];
++j;
res += mid - i + 1; // temp[i].. temp[mid] 有序, 由于 temp[i] > temp[j]。temp[i].. temp[mid]这些数 都比 temp[j] 大
}
}
return res;
}
};
class Solution {
public:
int reversePairs(vector<int>& record) {
vector<int> temp(record.size());
function<int(int, int)> merge_sort = [&](int left, int right){
// 终止条件
if (left >= right) return 0;
// 递归划分
int mid = (left + right) / 2;
int res = merge_sort(left, mid) + merge_sort(mid + 1, right);
// 合并
int i = left, j = mid + 1;
for (int k = left; k <= right; ++k){
temp[k] = record[k];
}
for (int k = left; k <= right; ++k){
if (i == mid + 1){
record[k] = temp[j];
++j;
}else if (j == right + 1 || temp[i] <= temp[j]){
record[k] = temp[i];
++i;
}else{
record[k] = temp[j];
++j;
res += mid - i + 1; // temp[i].. temp[mid] 有序, 由于 temp[i] > temp[j]。temp[i].. temp[mid]这些数 都比 temp[j] 大
}
}
return res;
};
return merge_sort(0, record.size() - 1);
}
};