Leetcode周赛366总结

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 (xd)2+(y+d)2=x2+y22dx+2dy+2d2>=x2+y2
    • 由上式,如果可以操作,就尽量操作
    • 所以统计数组中各位上1的个数,构造k个数,每个数使用尽量多的1
  • 解题代码:

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;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值