因为种种原因,实际比赛时间大概只有半个多小时,不过前两题都秒了,最后一题有一定的思路但是又被异或给整跑偏了,菱形那题确实没做出来。
- 长度为三且各字符不同的子字符串
class Solution {
public:
int countGoodSubstrings(string s) {
int n = s.size();
if(n <= 2)
return 0;
int beg = 0, end = 2;
int count = 0;
while(end < n){
if(s[beg] == s[end] || s[beg] == s[beg + 1] || s[end] == s[end - 1]){
}else{
count++;
}
beg++;
end++;
}
return count;
}
};
经验:
1、简单的双指针滑动窗口,水题
- 数组中最大数对和的最小值
一个数对 (a,b) 的 数对和 等于 a + b 。最大数对和 是一个数对数组中最大的 数对和 。
比方说,如果我们有数对 (1,5) ,(2,3) 和 (4,4),最大数对和 为 max(1+5, 2+3, 4+4) = max(6, 5, 8) = 8 。
给你一个长度为 偶数 n 的数组 nums ,请你将 nums 中的元素分成 n / 2 个数对,使得:
nums 中每个元素 恰好 在 一个 数对中,且
最大数对和 的值 最小 。
请你在最优数对划分的方案下,返回最小的 最大数对和 。
class Solution {
public:
int minPairSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
int maxsum = 0;
int n = nums.size();
for(int i = 0; i < n / 2; i++){
if(maxsum < nums[i] + nums[n - 1 - i])
maxsum = nums[i] + nums[n - 1 - i];
}
return maxsum;
}
};
经验:
1、水题,简单的均值就可以了。
- 两个数组最小的异或值之和
给你两个整数数组 nums1 和 nums2 ,它们长度都为 n 。
两个数组的 异或值之和 为 (nums1[0] XOR nums2[0]) + (nums1[1] XOR nums2[1]) + … + (nums1[n - 1] XOR nums2[n - 1]) (下标从 0 开始)。
比方说,[1,2,3] 和 [3,2,1] 的 异或值之和 等于 (1 XOR 3) + (2 XOR 2) + (3 XOR 1) = 2 + 0 + 2 = 4 。
请你将 nums2 中的元素重新排列,使得 异或值之和 最小 。
请你返回重新排列之后的 异或值之和 。
方法一:模拟退火
class Solution {
private:
int n;
vector<int> n1;
vector<int> n2;
int ans;
int cal(){
int res = 0;
for(int i = 0; i < n; i++)
res += n1[i] ^ n2[i];
ans = min(res, ans);
return res;
}
void simulate_anneal(){
random_shuffle(n2.begin(), n2.end());
for(double x = 1e6; x > 1e-5; x *= 0.98){
int i = rand() % n;
int j = rand() % n;
int before = cal();
swap(n2[i], n2[j]);
int after = cal();
int delta = before - after;
if(delta < 0 && (double) rand() / RAND_MAX <= exp(-1 * delta / x)){
swap(n2[i], n2[j]);
}
}
return;
}
public:
int minimumXORSum(vector<int>& nums1, vector<int>& nums2) {
n = nums1.size();
n1 = nums1;
n2 = nums2;
ans = 0;
for(int i = 0;i < n;i ++) ans += n1[i] ^ n2[i];
for(int i = 0; i < 10; i++){
simulate_anneal();
}
return ans;
}
};
经验:
1、这种随机化搜索本质就是带有一定逻辑性的随机排序,对小规模数据的时候会有比较好的效果。尤其是大部分内容都是板子,实质与题目相关部分只有cal()里面的ans计算方法。
2、random_shuffle()是相当于重启一次模拟退火,确保不会过拟合。
方法二:状态压缩DP
```cpp
class Solution {
public:
int minimumXORSum(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size();
vector<int>f(1 << n, INT_MAX);
f[0] = 0;
for(int i = 1; i < 1 << n; i++){
for(int j = 0; j < n ; j++){
if(i & (1 << j))
f[i] = min(f[i], f[i ^ (1 << j)] + (nums1[__builtin_popcount(i) - 1] ^ nums2[j]));
}
}
return f[(1 << n) - 1];
}
};
经验:
1、这个思路我个人非常喜欢,是很多题目当中都能够共通的好方法。
2、位运算yyds
3、__builtin_popcount()可以用来统计一个整数的二进制有多少位1.
4、f[x] = min(f[x], blabla)这个写法不错,以前都是整一个temp,拿到最小之后再赋值,要写的行数偏多。