Q1 分类求和并作差
-
解题思路1:
- 就按照题目的意思
- 遍历[1, n]中的所有数,num1记录无法被m整除的数之和,num2记录可以被m整除的数之和
- 返回num1 - num2
-
解题代码1:
class Solution {
public:
int differenceOfSums(int n, int m) {
int num1 = 0, num2 = 0;
for(int i = 1; i <= n; i++)
{
if(i % m == 0)
num2 += i;
else
num1 += i;
}
return num1 - num2;
}
};
- 改进一下只用一个变量就可以
class Solution {
public:
int differenceOfSums(int n, int m) {
int ans = 0;
for(int i = 1; i <= n; i++)
{
if(i % m == 0)
ans -= i;
else
ans += i;
}
return ans;
}
};
- 解题思路2:
- 等差数列分别求出[1, n]的和sum,及[1, n]中是m的倍数的数的和sum1
- 然后答案就是 sum - 2 * sum1
- 这样就是O(1) 的
- 解题代码:
class Solution {
public:
int differenceOfSums(int n, int m) {
int sum = (1 + n) * n / 2;
int sum1 = (m + n / m * m) * (n / m) / 2;
return sum - 2 * sum1;
}
};
Q2 最小处理时间
-
解题思路:
- 贪心
- 给早空闲的处理器安排需要时间长的工作,给晚空闲的处理器安排需要时间短的工作
- 将处理器空闲时间从小到大排序,工作所需时间从大到小排序
- 对第i个处理器,执行完任务的时间是 processorTime[i] + tasks[i * 0]
- 所有任务执行完的时间是每个处理器执行完任务的时间的最大值
-
解题代码:
class Solution {
public:
int minProcessingTime(vector<int>& processorTime, vector<int>& tasks) {
sort(tasks.rbegin(), tasks.rend());
sort(processorTime.begin(), processorTime.end());
int n = processorTime.size();
int ans = 0;
for(int i = 0; i < n; i++)
ans = max(ans, processorTime[i] + tasks[i * 4]);
return ans;
}
};
Q3 执行操作使两个字符串相等
-
解题思路:
-
首先考虑什么情况下会返回-1,每次操作都是翻转两个不同下标的数,因此总会改变两个位置是否相等的状态;如果初始情况下s1 和 s2中不相同的位置数为奇数,那么永远无法变得相同,返回-1 (也可以参考灵神的讲解,由于一次翻转两个位置,所以字符串中1出现次数的奇偶性是不变的,如果初始状态下两个字符串中1出现次数的奇偶性不同,直接返回-1)
-
一种错误思路:直接贪心
- 将所有字符不同的下标位置取出来,放到diffIdx数组中
- 从前向后考虑所有相邻位置的两个下标(i,i+1),把两者均变相同需要min(x, diffIdx[i+1] - diffIdx[i])
- 这样的思路存在问题,比如: s1 = “1000110001” s2 = “0000000000” x = 3
-
换思路,考虑记忆化搜索
-
对于i位置的不同,可以有两种操作:
- 使用操作1进行翻转,此时i位置和哪个位置一起翻转都是一样的,代价为x
- 使用操作2进行翻转,那么显然与相距最近的j位置一起翻转代价是最小的,为diffIdx[j] - diffIdx[i]
-
定义dfs(i, j):i表示考虑第i个位置不同,j表示在先前的过程中是否有位置使用了操作1进行翻转(0:没有, 1:有),其返回值就是所需的最小代价
-
考虑边界情况,当i == diffIdx.size()时,所有不同位置都已经完成了翻转,如果此时j == 0, 返回0, 否则返回1
-
状态转移:
- 使用操作1,转移到dfs(i+1, 1-j) + (1-j) * x (这里的1-j,如果之前有位置使用操作1进行了翻转,那么i位置可以和之前的位置同时翻转,也就不需要花费代价了)
- 使用操作2,转移到dfs(i+2, j) + diffIdx[i+1] - diffIdx[i]
- dfs(i, j)的值应为上述两种情况的最小值
-
-
-
解题代码:
class Solution {
public:
int minOperations(string s1, string s2, int x) {
vector<int> diffIdx;
int n = s1.size();
for(int i = 0; i < n; i++)
{
if(s1[i] != s2[i])
diffIdx.push_back(i);
}
int len = diffIdx.size();
if(len & 1)
return -1;
vector<vector<int>> f(len, vector<int>(2, -1));
function<int(int, int)> dfs = [&](int i, int j) -> int
{
if(i == len)
return j == 0 ? 0 : INT_MAX;
if(f[i][j] != -1)
return f[i][j];
int &ans = f[i][j];
ans = INT_MAX;
if(i != len - 1)
ans = min(ans, dfs(i+2, j) + diffIdx[i+1] - diffIdx[i]);
ans = min(ans, dfs(i+1, 1-j) + (1-j) * x);
return ans;
};
return dfs(0, 0);
}
};
Q4 对数组执行操作使平方和最大
-
解题思路:
- 当 x < y 时,且x有个比特位是1,y有个比特位是0,那么可以把x中的1移到y中的0上
( x − d ) 2 + ( y + d ) 2 = x 2 + y 2 − 2 d x + 2 d y + 2 d 2 > = x 2 + y 2 (x - d) ^ 2 + (y + d) ^ 2 = x ^ 2 + y ^ 2 - 2dx + 2dy + 2d^2 >= x^2 + y^2 (x−d)2+(y+d)2=x2+y2−2dx+2dy+2d2>=x2+y2 - 由上式,如果可以操作,就尽量操作
- 所以统计数组中各位上1的个数,构造k个数,每个数使用尽量多的1
- 当 x < y 时,且x有个比特位是1,y有个比特位是0,那么可以把x中的1移到y中的0上
-
解题代码:
class Solution {
public:
int maxSum(vector<int>& nums, int k) {
int bits[32];
memset(bits, 0, 32 * sizeof(int));
for(auto num : nums)
{
for(int i = 0; i < 32; i++)
bits[i] += (num >> i) & 1;
}
long long ans = 0;
int MOD = 1e9 + 7;
for(int i = 0; i < k; i++)
{
long long temp = 0;
for(int j = 0; j < 32; j++)
{
if(bits[j] != 0)
{
temp |= (1 << j);
bits[j] -= 1;
}
}
ans = (ans + (temp * temp) % MOD) % MOD;
}
return ans;
}
};