第 121 场 LeetCode 双周赛题解

A 大于等于顺序前缀和的最小缺失整数

在这里插入图片描述

模拟:先求最长顺序前缀的和 s s s ,然后从 s s s 开始找没有出现在 n u m s nums nums 中的最小整数

class Solution {
public:
    int missingInteger(vector<int> &nums) {
        unordered_set<int> vis(nums.begin(), nums.end());
        int s = nums[0];
        int i = 0;
        while (i + 1 < nums.size() && nums[i + 1] == nums[i] + 1)
            s += nums[++i];
        while (vis.count(s))
            s++;
        return s;
    }
};


B 使数组异或和等于 K 的最少操作次数

在这里插入图片描述

枚举:求出 n u m s nums nums 各元素异或和 t o t tot tot ,对 t o t tot tot k k k 的二进制表示按位枚举,若两数某一位不同,则需要增加一次操作数

class Solution {
public:
    int minOperations(vector<int> &nums, int k) {
        int tot = 0;
        for (auto x: nums)
            tot ^= x;
        int res = 0;
        for (int i = 0; i < 32; i++)
            if ((tot >> i & 1) != (k >> i & 1))
                res++;
        return res;
    }
};

C 使 X 和 Y 相等的最少操作次数

在这里插入图片描述
在这里插入图片描述

bfs:相当于求从 x x x 出发到 y y y 的最短路,搜素过程中用集合记录已经到达过的数

class Solution {
public:
    int minimumOperationsToMakeEqual(int x, int y) {
        unordered_set<int> vis;
        queue<pair<int, int>> q;
        vis.insert(x);
        q.emplace(x, 0);
        int res;
        while (!q.empty()) {
            auto [v, cnt] = q.front();
            q.pop();
            if (v == y) {
                res = cnt;
                break;
            }
            if (v > y && v % 11 == 0 && !vis.count(v / 11)) {
                vis.insert(v / 11);
                q.emplace(v / 11, cnt + 1);
            }
            if (v > y && v % 5 == 0 && !vis.count(v / 5)) {
                vis.insert(v / 5);
                q.emplace(v / 5, cnt + 1);
            }
            if (!vis.count(v + 1)) {
                vis.insert(v + 1);
                q.emplace(v + 1, cnt + 1);
            }
            if (v > y && !vis.count(v - 1)) {
                vis.insert(v - 1);
                q.emplace(v - 1, cnt + 1);
            }
        }
        return res;
    }
};


D 统计强大整数的数目

在这里插入图片描述

数位dp + 记忆化搜素:定义 c m p ( x , m x , s u f ) cmp(x,mx,suf) cmp(x,mx,suf) 为不超过 x x x 且数中各数位不超过 m x mx mx 且数的末尾部分是 s u f suf suf 的数的数目,则题目答案为 c m p ( f i n i s h , l i m i t , s ) − c m p ( s t a r t − 1 , l i m i t , s ) cmp(finish, limit, s) - cmp(start - 1, limit, s) cmp(finish,limit,s)cmp(start1,limit,s) 。在 c m p cmp cmp 中定义 p [ l o c ] [ v a l ] [ e q ] p[loc][val][eq] p[loc][val][eq] 为:当前枚举下标为 l o c loc loc 且 之前位置对应的数位是否有数字(0:无,1:有)且 之前位置对应的数位的数字形成的前缀是否和 x x x 对应的前缀相等(0:不等,1:相等),这种情况下末尾部分是 s u f suf suf 的数的数目,通过记忆化搜素枚举状态转移的过程,最终 c m p ( x , m x , s u f ) cmp(x,mx,suf) cmp(x,mx,suf) 即为 p [ 0 ] [ 0 ] [ 1 ] p[0][0][1] p[0][0][1]

class Solution {
public:
    using ll = long long;

    long long numberOfPowerfulInt(long long start, long long finish, int limit, string s) {
        return cmp(finish, limit, s) - cmp(start - 1, limit, s);
    }

    ll cmp(ll x, int mx, string &suf) {
        if (x < stol(suf))
            return 0;
        string s0 = to_string(x);
        int n = s0.size();
        int m = suf.size();
        ll suf0 = stol(s0.substr(n - m, m));//x与suf相同长度的末尾部分
        ll vsuf = stol(suf);
        ll p[n][2][2];
        memset(p, -1, sizeof(p));
        function<ll(int, int, int)> get = [&](int loc, int val, int eq) {//记忆化搜素
            if (p[loc][val][eq] != -1)
                return p[loc][val][eq];
            if (n - loc == m) {//loc已经为suf的第一位
                if (suf0 >= vsuf || eq == 0)
                    p[loc][val][eq] = 1;
                else //末尾若是suf则会大于x,所以不存在这样的数
                    p[loc][val][eq] = 0;
                return p[loc][val][eq];
            }
            p[loc][val][eq] = 0;
            if (val) {//之前位置对应的数位有数字
                if (eq) {//之前位置对应的数位的数字形成的前缀和x对应的前缀相等
                    for (int i = 0; i <= s0[loc] - '0' && i <= mx; i++)
                        p[loc][val][eq] += get(loc + 1, 1, i == s0[loc] - '0' ? 1 : 0);
                } else {//之前位置对应的数位的数字形成的前缀和x对应的前缀不等
                    for (int i = 0; i <= mx; i++)
                        p[loc][val][eq] += get(loc + 1, 1, 0);
                }
            } else {//之前位置对应的数位无数字
                if (eq) {//之前位置对应的数位的数字形成的前缀和x对应的前缀相等
                    p[loc][val][eq] += get(loc + 1, 0, 0);//当前数位没有数字
                    for (int i = 1; i <= s0[loc] - '0' && i <= mx; i++)
                        p[loc][val][eq] += get(loc + 1, 1, i == s0[loc] - '0' ? 1 : 0);
                } else {//之前位置对应的数位的数字形成的前缀和x对应的前缀不等
                    p[loc][val][eq] += get(loc + 1, 0, 0);//当前数位没有数字
                    for (int i = 1; i <= mx; i++)
                        p[loc][val][eq] += get(loc + 1, 1, 0);
                }
            }
            return p[loc][val][eq];
        };
        return get(0, 0, 1);
    }
};
  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这道题是一道字符串处理题。给定一个字符串 s,它的所有的字符都是小写的英文字母。要求把这个字符串变成一个按照字典序排序的字符串,并且要求在变换过程中只能在原来的字符串中交换两个相邻的字符。 解题思路: - 从前往后扫描字符串 s,找到第一个不满足字典序的字符,记为字符 x。 - 从 x 往后扫描,找到最后一个比 x 大的字符 y,将 x 与 y 交换。 - 将 x 后面的字符串倒序排列,这样就得到了字典序更大的字符串。 下面是 Java 代码的实现: ``` class Solution { public String nextPermutation(String s) { char[] chars = s.toCharArray(); // 从后往前找到第一个不满足字典序的字符 x int i = chars.length - 2; while (i >= 0 && chars[i] >= chars[i + 1]) { i--; } // 如果 i < 0,说明原来的字符串已经是字典序最大的字符串,直接返回倒序排列的字符串 if (i < 0) { reverse(chars, 0, chars.length - 1); return new String(chars); } // 从 x 往后扫描,找到最后一个比 x 大的字符 y int j = chars.length - 1; while (j > i && chars[j] <= chars[i]) { j--; } // 将 x 与 y 交换 swap(chars, i ### 回答2: 题目:LeetCode第38题:报数 题目描述: 给定一个正整数n,输出报数序列前n个数。 报数规则:从1开始报数,数到3的倍数时报Fizz,数到5的倍数时报Buzz,数到同时是3和5的倍数时报FizzBuzz,其他情况下则直接报数。 解题思路: 使用循环遍历1到n的所有数字,按照报数规则进行判断并输出。 具体步骤如下: 1. 创建一个StringBuilder对象res,用于存储报数序列。 2. 使用for循环从1遍历到n。 3. 判断当前数字是否同时是3和5的倍数,如果是,则将"FizzBuzz"添加到res中。 4. 判断当前数字是否是3的倍数,如果是,则将"Fizz"添加到res中。 5. 判断当前数字是否是5的倍数,如果是,则将"Buzz"添加到res中。 6. 如果以上条件都不满足,则将当前数字转换为字符串并添加到res中。 7. 循环结束后,将res转换为字符串并返回。 Java代码如下: ```java public String countAndSay(int n) { StringBuilder res = new StringBuilder(); for (int i = 1; i <= n; i++) { if (i % 3 == 0 && i % 5 == 0) { res.append("FizzBuzz"); } else if (i % 3 == 0) { res.append("Fizz"); } else if (i % 5 == 0) { res.append("Buzz"); } else { res.append(Integer.toString(i)); } } return res.toString(); } ``` 以上代码可以将1到n的报数序列输出,并按照题目要求进行相应转换。 ### 回答3: 题目要求是根据给定的正整数 n,返回一个字符串,该字符串包含从 1 到 n 的所有数字对应的字符串,并且满足以下条件: 1. 如果数字能被 3 整除,则使用字母 "Fizz" 替代该数字。 2. 如果数字能被 5 整除,则使用字母 "Buzz" 替代该数字。 3. 如果数字能同时被 3 和 5 整除,则使用字母 "FizzBuzz" 替代该数字。 解题思路: 利用循环遍历从 1 到 n 的所有数字,使用条件语句判断每个数字是否满足以上三个条件,然后根据条件替换数字并存入结果字符串中,最后返回结果。 Java代码如下: ```java class Solution { public String fizzBuzz(int n) { StringBuilder result = new StringBuilder(); for (int i = 1; i <= n; i++) { if (i % 3 == 0 && i % 5 == 0) { result.append("FizzBuzz"); } else if (i % 3 == 0) { result.append("Fizz"); } else if (i % 5 == 0) { result.append("Buzz"); } else { result.append(i); } if (i != n) { result.append(" "); } } return result.toString(); } } ``` 这段代码使用StringBuilder来构建结果字符串,判断每个数字是否满足条件,并根据条件拼接对应的字符串,每个数字之间用空格隔开。最后将StringBuilder转换成String并返回。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值