这期继续带来的是豆包的ai刷题,继上次刷题分享,这次我们来挑战一下困难题
废话不多说,
先来一道中等题当开胃菜
第一题——数字的奥秘:AI与‘11’
问题描述 小U最近开发了一个独特的AI模型,它有一个有趣的特点:当你给出一系列数字时,例如从1到N,AI会将这些数字视为一个没有空格或逗号的连续字符串。例如,当你给定N=11时,AI会展示的内容是“1234567891011”。小U对数字“11”非常感兴趣,她想知道在这个连续字符串中,子字符串“11”出现的次数是多少。
你需要帮助小U编写一个程序,给定一个整数N,计算子字符串“11”在AI模型感知的序列中出现的次数。
测试样例 样例1:
输入:N = 11 输出:1
样例2:
输入:N = 100 输出:2
样例3:
输入:N = 111 输出:6
解答
老实说,最近在公司实现的几个需求都是使用正则表达式来写的,所以我一看到这题我就想到了用正则表达式秒了,直接用正则表达式找出11的数组,返回长度就行了。
所以一开始我的代码是这样的
function solution(N) {
let str = '';
for (let i = 1; i <= N; i++) {
str += i;
}
// 使用正则表达式匹配非重叠的子字符串“11”
const matches = str.match(/11/g);
// 处理匹配结果,返回匹配的次数
return matches ? matches.length : 0;
}
function main() {
console.log(solution(11) === 1); // 输出: true
console.log(solution(100) === 2); // 输出: true
console.log(solution(111) === 6); // 输出: true
}
main();
当我兴高采烈的提交代码后,居然跳出了,true ,false, false。于是我检查了代码,原来,111这样的算两个,我这样写的话只能算一个,好了找到问题了。那就修改一下匹配规则,给它加上正向肯定预查/(?=(11))/g,让‘111’这样的字符算两个。
修改后代码:
function solution(N) {
let str = '';
for (let i = 1; i <= N; i++) {
str += i;
}
// 使用正则表达式匹配非重叠的子字符串“11”
const matches = str.match(/(?=(11))/g);
// 处理匹配结果,返回匹配的次数
return matches ? matches.length : 0;
}
function main() {
console.log(solution(11) === 1); // 输出: true
console.log(solution(100) === 2); // 输出: true
console.log(solution(111) === 6); // 输出: true
}
main();
ok,试一下。
非常的完美
然后就可以让ai转换语言进行提交了
好了,中等题写完了,接下来登场的是卡牌翻面求和问题。
第二题——卡牌翻面求和问题
这是一道困难题,我们先来看看题目
问题描述
小M有 𝑛n 张卡牌,每张卡牌的正反面分别写着不同的数字,正面是 𝑎𝑖ai,背面是 𝑏𝑖bi。小M希望通过选择每张卡牌的一面,使得所有向上的数字之和可以被3整除。你需要告诉小M,一共有多少种不同的方案可以满足这个条件。由于可能的方案数量过大,结果需要对 109+7109+7 取模。
例如:如果有3张卡牌,正反面数字分别为 (1,2),(2,3) 和 (3,2),你需要找到所有满足这3张卡牌正面或背面朝上的数字之和可以被3整除的组合数。
测试样例
样例1:
输入:
n = 3 ,a = [1, 2, 3] ,b = [2, 3, 2]
输出:3
样例2:
输入:
n = 4 ,a = [3, 1, 2, 4] ,b = [1, 2, 3, 1]
输出:6
样例3:
输入:
n = 5 ,a = [1, 2, 3, 4, 5] ,b = [1, 2, 3, 4, 5]
输出:32
解题:
分析完题目发现卡牌的数字正反面是给定的,我们可以看作每张卡牌为两种可能的贡献值 𝑎 𝑖 a i (正面)或 𝑏 𝑖 b i (背面),并且希望最终选择的数字和对 3 取余后为 0。
可以使用动态规划来解决这个问题。对于每一张卡牌 i,我们有两种选择:可以选择它的正面 a[i-1] 或者背面 b[i-1]。如果选择了正面,那么新的和模3的结果就是 (当前和 + a[i-1]) % 3;如果选择了背面,则新的和模3的结果就是 (当前和 + b[i-1]) % 3。因此,我们可以根据上一步的状态 dp[i-1][j] 来更新 dp[i][j]。
具体来说,如果我们想要得到 dp[i][(j + a[i-1]) % 3] 的值,可以通过加上 dp[i-1][j] 来实现,因为这是通过将第 i 张卡牌的正面加入到之前总和为 j 的情况中得到的。同理,也可以通过将背面加入来更新相应的状态。
看看代码怎么实现的:
function solution(n, a, b) {
const MOD = 10**9 + 7;
// dp[i][j] 表示前 i 张卡牌选择后和对 3 取余为 j 的方案数
let dp = new Array(n + 1).fill(0).map(() => new Array(3).fill(0));
dp[0][0] = 1; // 初始状态,没有卡牌时和为0的方案数为1
// 遍历每张卡牌
for (let i = 1; i <= n; i++) {
for (let j = 0; j < 3; j++) {
// 对每一张卡牌,选择正面或者背面
dp[i][j] = (dp[i-1][(j - a[i-1] % 3 + 3) % 3] +
dp[i-1][(j - b[i-1] % 3 + 3) % 3]) % MOD;
}
}
// 返回最后一张卡牌选择后的和为0的方案数
return dp[n][0];
}
// 测试用例
console.log(solution(3, [1, 2, 3], [2, 3, 2]) === 3); // true
console.log(solution(4, [3, 1, 2, 4], [1, 2, 3, 1]) === 6); // true
console.log(solution(5, [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]) === 32); // true
运行一下,
ok,完美解决。
好了,今天的分享就到这里了。