第 49 场双周赛

302 阅读3分钟

1812. 判断国际象棋棋盘中一个格子的颜色

题目

给你一个坐标 coordinates ,它是一个字符串,表示国际象棋棋盘中一个格子的坐标。下图是国际象棋棋盘示意图。

![img](/Users/caohonghai/Documents/Books/LeetCode/Untitled 1.assets/chessboard.png)

如果所给格子的颜色是白色,请你返回 true,如果是黑色,请返回 false

给定坐标一定代表国际象棋棋盘上一个存在的格子。坐标第一个字符是字母,第二个字符是数字。

示例 1:

输入:coordinates = "a1"
输出:false
解释:如上图棋盘所示,"a1" 坐标的格子是黑色的,所以返回 false

示例 2:

输入:coordinates = "h3"
输出:true
解释:如上图棋盘所示,"h3" 坐标的格子是白色的,所以返回 true

示例 3:

输入:coordinates = "c7"
输出:false

提示:

  • coordinates.length == 2
  • 'a' <= coordinates[0] <= 'h'
  • '1' <= coordinates[1] <= '8'

代码

class Solution {
public:
    bool squareIsWhite(string c) {
        return ((c[0] - 'a') + (c[1] - '0')) % 2 == 0;
    }
};

1813. 句子相似性 III

题目

一个句子是由一些单词与它们之间的单个空格组成,且句子的开头和结尾没有多余空格。比方说,"Hello World""HELLO""hello world hello world" 都是句子。每个单词都 包含大写和小写英文字母。

如果两个句子 sentence1sentence2 ,可以通过往其中一个句子插入一个任意的句子(可以是空句子)而得到另一个句子,那么我们称这两个句子是 相似的 。比方说,sentence1 = "Hello my name is Jane"sentence2 = "Hello Jane" ,我们可以往 sentence2"Hello""Jane" 之间插入 "my name is" 得到 sentence1

给你两个句子 sentence1sentence2 ,如果 sentence1sentence2 是相似的,请你返回 true ,否则返回 false

示例 1:

输入:sentence1 = "My name is Haley", sentence2 = "My Haley"
输出:true
解释:可以往 sentence2 中 "My""Haley" 之间插入 "name is" ,得到 sentence1 。

示例 2:

输入:sentence1 = "of", sentence2 = "A lot of words"
输出:false
解释:没法往这两个句子中的一个句子只插入一个句子就得到另一个句子。

示例 3:

输入:sentence1 = "Eating right now", sentence2 = "Eating"
输出:true
解释:可以往 sentence2 的结尾插入 "right now" 得到 sentence1 。

示例 4:

输入:sentence1 = "Luky", sentence2 = "Lucccky"
输出:false

提示:

  • 1 <= sentence1.length, sentence2.length <= 100
  • sentence1sentence2 都只包含大小写英文字母和空格。
  • sentence1sentence2 中的单词都只由单个空格隔开。

思路

c++没有string相应的函数,所以用stringstream读入string内容,这里相似性就是等价于某一句话中间插入了一些单词,匹配到s2

因此,前后匹配即可

代码

class Solution {
public:
    bool areSentencesSimilar(string s1, string s2) {
        if (s1.size() > s2.size()) return areSentencesSimilar(s2, s1);
        stringstream s1in(s1), s2in(s2);
        vector<string> a, b;
        string s;
        while (s1in >> s) a.push_back(s);
        while (s2in >> s) b.push_back(s);
        int i = 0, j = a.size() - 1;
        for (int k = 0; k < b.size() && i < a.size(); k++) {
            if (a[i] == b[k]) i++;
            else break;
        }
        for (int k = b.size() - 1; k >= 0 && j >= 0; k--) {
            if (a[j] == b[k]) j--;
            else break;
        }
        return i > j;
    }
};

1814. 统计一个数组中好对子的数目

题目

给你一个数组 nums ,数组中只包含非负整数。定义 rev(x) 的值为将整数 x 各个数字位反转得到的结果。比方说 rev(123) = 321rev(120) = 21 。我们称满足下面条件的下标对 (i, j)好的

  • 0 <= i < j < nums.length
  • nums[i] + rev(nums[j]) == nums[j] + rev(nums[i])

请你返回好下标对的数目。由于结果可能会很大,请将结果对 109 + 7 取余 后返回。

示例 1:

输入:nums = [42,11,1,97]
输出:2
解释:两个坐标对为:
 - (0,3):42 + rev(97) = 42 + 79 = 121, 97 + rev(42) = 97 + 24 = 121 。
 - (1,2):11 + rev(1) = 11 + 1 = 12, 1 + rev(11) = 1 + 11 = 12

示例 2:

输入:nums = [13,10,35,24,76]
输出:4

提示:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] <= 109

思路

nums[i] + rev(nums[j]) == nums[j] + rev(nums[i]) 等价于 nums[i] - rev(nums[i]) == nums[j] - rev(nums[j]) 然后存值到map中,算C n 2的排列组合即可

代码

int mod = 1e9 + 7;
typedef long long ll;
class Solution {
public:
    int rev(int num) {
        int ret = 0;
        while (num) {
            ret = ret * 10 + num % 10;
            num /=  10;
        }
        return ret;
    }

    int countNicePairs(vector<int>& nums) {
        ll ret = 0;
        unordered_map<ll, ll> mp;
        for (auto& n : nums) {
            mp[n - rev(n)]++;
        }
        for (auto& [k, v] : mp) {
            ret = (ret + v * (v - 1) / 2) % mod;
        }   
        return (int)ret;
    }
};

1815. 得到新鲜甜甜圈的最多组数

题目

有一个甜甜圈商店,每批次都烤 batchSize 个甜甜圈。这个店铺有个规则,就是在烤一批新的甜甜圈时,之前 所有 甜甜圈都必须已经全部销售完毕。给你一个整数 batchSize 和一个整数数组 groups ,数组中的每个整数都代表一批前来购买甜甜圈的顾客,其中 groups[i] 表示这一批顾客的人数。每一位顾客都恰好只要一个甜甜圈。

当有一批顾客来到商店时,他们所有人都必须在下一批顾客来之前购买完甜甜圈。如果一批顾客中第一位顾客得到的甜甜圈不是上一组剩下的,那么这一组人都会很开心。

你可以随意安排每批顾客到来的顺序。请你返回在此前提下,最多 有多少组人会感到开心。

示例 1:

输入:batchSize = 3, groups = [1,2,3,4,5,6]
输出:4
解释:你可以将这些批次的顾客顺序安排为 [6,2,4,5,1,3] 。那么第 1,2,4,6 组都会感到开心。

示例 2:

输入:batchSize = 4, groups = [1,3,2,5,2,2,1,6]
输出:4

提示:

  • 1 <= batchSize <= 9
  • 1 <= groups.length <= 30
  • 1 <= groups[i] <= 109

思路

模拟退火 算法 :

一个可以尽量达到全局最优的算法

每次随机交换序列中的两个位置 来判断当前的序列是否可以比原始序列更优

  1. 若比原始序列更优,则保留交换
  2. 否则按一定概率保留交换 (这样才有机会达到全局最优)

还有一种思路就是状态压缩+记忆化搜索

具体可以参考leetcode-cn.com/problems/ma…

代码

模拟退火代码

class Solution {
public:
    int n, m;
    vector<int> w;
    int ans;

    int calc() {
        int res = 1;
        for (int i = 0, s = 0; i < n; i ++ ) {
            s = (s + w[i]) % m;
            if (!s && i < n - 1) res ++ ;
        }
        ans = max(ans, res);
        return res;
    }

    void simulate_anneal() {
        random_shuffle(w.begin(), w.end());

        for (double t = 1e6; t > 1e-5; t *= 0.97) {
            int a = rand() % n, b = rand() % n;
            int x = calc();
            swap(w[a], w[b]);
            int y = calc();
            int delta = x - y;
            if (!(exp(-delta / t) > (double)rand() / RAND_MAX))
                swap(w[a], w[b]);
        }
    }

    int maxHappyGroups(int batchSize, vector<int>& groups) {
        w = groups;
        n = w.size();
        m = batchSize;
        ans = 0;
        for (int i = 0; i < 80; i ++ ) simulate_anneal();
        return ans;
    }
};

状态压缩

class Solution {
public:
    int dp[1111111];
    int maxHappyGroups(int batchSize, vector<int>& groups) {
        int cnt[batchSize];
        memset(cnt, 0, sizeof(cnt));
        for (int group: groups) {
            cnt[group % batchSize]++;
        }
        int sz = 1;
        int w[11];
        w[0] = 1;
        for (int i = 0; i < batchSize; i++) {
            w[i + 1] = w[i] * (cnt[i] + 1);
            sz *= (cnt[i] + 1);
        }
        dp[0] = 0;
        for (int mask = 1; mask < sz; mask++) {
            dp[mask] = 0;
            int tmp = mask, sum = 0;
            int v[10];
            memset(v, 0, sizeof(v));
            for (int b = 0; b < batchSize; b++) {
                if (!cnt[b]) continue;
                int x = tmp % (cnt[b] + 1);
                v[b] = x;
                sum = (sum + x * b) % batchSize;
                tmp /= (cnt[b] + 1);
            }
            for (int b = 0; b < batchSize; b++) {
                if (v[b]) {
                    int last = (sum - b + batchSize) % batchSize;
                    dp[mask] = max(dp[mask], dp[mask - w[b]] + (last == 0));
                }
            }
        }
        return dp[sz - 1];
    }
};