2021-05-29周赛小记

因为种种原因,实际比赛时间大概只有半个多小时,不过前两题都秒了,最后一题有一定的思路但是又被异或给整跑偏了,菱形那题确实没做出来。

- 长度为三且各字符不同的子字符串

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,拿到最小之后再赋值,要写的行数偏多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值