刷题题解 | 豆包MarsCode AI刷题

101 阅读6分钟

数字分组求偶数和

1. 问题描述

小M面对一组从 1 到 9 的数字,这些数字被分成多个小组,并从每个小组中选择一个数字组成一个新的数。目标是使得这个新数的各位数字之和为偶数。任务是计算出有多少种不同的分组和选择方法可以达到这一目标。

  • numbers: 一个由多个整数字符串组成的列表,每个字符串可以视为一个数字组。小M需要从每个数字组中选择一个数字。

例如对于[123, 456, 789],14个符合条件的数为:147 149 158 167 169 248 257 259 268 347 349 358 367 369

2. 测试样例

样例1:

输入:numbers = [123, 456, 789]
输出:14

样例2:

输入:numbers = [123456789]
输出:4

样例3:

输入:numbers = [14329, 7568]
输出:10

3. 解题思路

要从每个数字组中选择一个数字,使得这些数字的和为偶数。问题可以主要拆解为两部分内容:

  1. 奇偶性:一个数是偶数当且仅当它的各位数字之和为偶数;
  2. 组合生成:我们需要生成所有可能的组合,并检查这些组合的和是否为偶数。

换言之,需要使用递归或迭代的方式来生成所有可能的组合,并且利用一个布尔数组来记录每个数字组中选择的数字是否为偶数。

算法步骤:

  1. 递归生成组合

    • 对于每个数字组,选择一个数字;
    • 递归地处理下一个数字组;
    • 当处理完所有数字组时,检查当前组合的和是否为偶数。
  2. 检查和的奇偶性

    • 如果当前组合的和为偶数,则计数加一。

4. 代码

public class Main {
    public static int solution(int[] numbers) {
        // 初始化计数器
        int count = 0;
        
        // 生成组合
        count = fab(numbers, 0, 0, count);
        
        return count;
    }

    // 递归生成组合
    private static int fab(int[] numbers, int index, int currentSum, int count) {
        // 如果已经处理完所有数字组
        if (index == numbers.length) {
            // 检查当前组合的和是否为偶数
            if (currentSum % 2 == 0) {
                count++;
            }
            return count;
        }
        
        // 获取当前数字组
        int currentGroup = numbers[index];
        
        // 遍历当前数字组中的每个数字
        while (currentGroup > 0) {
            int digit = currentGroup % 10;
            // 递归处理下一个数字组
            count = fab(numbers, index + 1, currentSum + digit, count);
            currentGroup /= 10;
        }
        
        return count;
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution(new int[]{123, 456, 789}) == 14);
        System.out.println(solution(new int[]{123456789}) == 4);
        System.out.println(solution(new int[]{14329, 7568}) == 10);
    }
}

image.png

数组元素之和最小化

1.题目描述

小C希望构造一个包含n个元素的数组,且满足以下条件:

  1. 数组中的所有元素两两不同。
  2. 数组所有元素的最大公约数为 k
  3. 数组元素之和尽可能小。

任务是输出该数组元素之和的最小值。

2.测试样例

样例1:

输入:n = 3 ,k = 1
输出:6

样例2:

输入:n = 2 ,k = 2
输出:6

样例3:

输入:n = 4 ,k = 3
输出:30

3.解题思路

最大公约数为k,只需要以k的倍数从小到大构造数组即可得到元素和的最小值。

4.代码

public static int solution(int n, int k) {
    int sum = 0;
    for (int i = 1; i <= n; i++) sum += k * i;
    return sum;
}

image.png

基本字符串转换

1.题目描述

小U正在研究字符串的转换问题。他发现一个由字母 'a' 组成的字符串被称为“基本”字符串。现在给定一个长度为N的字符串S,该字符串中的字符从0N-1进行编号。在每次操作中,你可以选择三个索引ijk,其中i < j < k,并且满足 S[i] 和 S[k] 都是 'a',然后你可以将 S[j] 的字符也设置为 'a'

你的任务是判断是否可以通过多次执行该操作,将字符串S变为一个基本字符串。如果可以,将返回 1;否则返回 0

2.测试样例

样例1:

输入:N = 7, S = "aaacaaa"
输出:True

样例2:

输入:N = 5, S = "ababa"
输出:True

样例3:

输入:N = 6, S = "aaaaab"
输出:False

3.解题思路

题目要求我们判断能不能通过操作把一个字符串转变成基本字符串,仔细研究这个操作可以发现 ik之间的字符都可以设置成a,因此只需要确定第一个字符和最后一个字符是否都是a,就可以判断字符串能否转成一个基本字符串。

4.代码

public class Main {
    public static boolean solution(int N, String S) {
        int len = S.length();
        if(S.charAt(0)=='a' && S.charAt(len-1)=='a') return true;
        return false;
    }

    public static void main(String[] args) {
        System.out.println(solution(7, "aaacaaa") == true);
        System.out.println(solution(5, "ababa") == true);
        System.out.println(solution(6, "aaaaab") == false);
    }
}

image.png

小U的地板砖之旅

1. 问题描述

小U有 n 块地砖,她需要从第一块地砖走到第 n 块地砖。走到第 i 块地砖需要消耗 a_i 的体力值。每次,小U可以选择向前走一步或者向前走两步,目的是消耗最少的体力值走到第 n 块地砖。

请你帮忙计算小U走到第 n 块地砖时消耗的最小体力值。

2. 测试样例

样例1:

输入:n = 5, a = [0, 3, 2, 1, 0]
输出:2

样例2:

输入:n = 4, a = [0, 5, 6, 0]
输出:5

样例3:

输入:n = 6, a = [0, 1, 2, 3, 1, 0]
输出:3

3. 解题思路

一道DP类问题,需要找到最小消耗值,跟走楼梯问题相似,小U只能前进一步或者两步,因此当前的消耗值只有两种情况:

  • 从第i-1块砖前进一步到第i块转;
  • 从第i-2块砖前进一步到第i块转;

由此可得动态转移方程为: dp(i) = min{a(i)+dp(i-1), a(i)+dp(i-2)}

关键步骤:

  1. 处理边界情况

    • 如果 n 为 1,直接返回 a[0]
    • 如果 n 为 2,返回 Math.min(a[0], a[1])
  2. 初始化 dp 数组

    • dp[0] = a[0] 和 dp[1] = a[1]
  3. 动态规划状态转移

    • dp[i] = Math.min(a[i] + dp[i - 1], a[i] + dp[i - 2]);
  4. 返回结果

    • return dp[n - 1];

4. 代码

public class Main {
    public static int solution(int n, int[] a) {
        int[] dp = new int[n];

        // 判断一下边界
        dp[0] = 0;
        if(n > 1) dp[1] = a[1];
        for(int i=2; i<n; i++){
            // 动态转移方程
            dp[i] = Math.min(a[i] + dp[i-1], a[i] + dp[i-2]);
        }

        // 返回结果
        return dp[n-1];
    }

    public static void main(String[] args) {
        System.out.println(solution(15, new int[]{8,6,10,13,2,6,8,11,15,8,10,4,11,16,6}) == 58);
        System.out.println(solution(4, new int[]{0, 5, 6, 0}) == 5);
        System.out.println(solution(6, new int[]{0, 1, 2, 3, 1, 0}) == 3);
    }
}

其中,dp(i)表示从起点到第i块地砖所需要的最小消耗值。

首先判断一下n是否大于1,如果大于1,那么dp[1] = a[1],否则直接返回0,之后从i = 2开始,进行动态转移,计算每个dp(i)的值,最后返回dp[n-1]

image.png