青训营X豆包MarsCode 代码详解 day3 | 豆包MarsCode AI 刷题

100 阅读6分钟

构造特定数组的逆序拼接

问题描述

小U得到了一个数字n,他的任务是构造一个特定数组。这个数组的构造规则是:对于每个i从1到n,将数字n到i逆序拼接,直到i等于n为止。最终,输出这个拼接后的数组。

例如,当n等于3时,拼接后的数组是 [3, 2, 1, 3, 2, 3]


测试样例

样例1:

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

样例2:

输入:n = 4
输出:[4, 3, 2, 1, 4, 3, 2, 4, 3, 4]

样例3:

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

1. 题目理解

关键点:

  • 输入一个数字n

  • 需要构造n个序列

  • 第i个序列是从n到i的逆序数字

  • 将所有序列依次拼接

示例分析(n=3):

i=1时:[3,2,1]

i=2时:[3,2]

i=3时:[3]

最终结果:[3,2,1,3,2,3]

2.代码

    public static int[] constructArray(int n) {
        // 1. 计算结果数组长度
        int len = 0;
        for (int i = 1; i <= n; i++) {
            len += (n - i + 1);
        }
        
        // 2. 构造结果数组
        int[] result = new int[len];
        int index = 0;
        
        // 3. 填充数组
        for (int i = 1; i <= n; i++) {
            for (int j = n; j >= i; j--) {
                result[index++] = j;
            }
        }
        
        return result;
    }
}

3. 算法步骤详解

步骤1:计算长度

  • 第1个序列长度:n

  • 第2个序列长度:n-1

  • 第3个序列长度:n-2

...以此类推

  • 总长度 = n + (n-1) + (n-2) + ... + 1

步骤2:构造数组

  • 外层循环i从1到n

  • 内层循环j从n到i(逆序)

  • 依次填充数字

步骤3:示例执行过程(n=3)

i=1: j=3,2,1 -> [3,2,1] i=2: j=3,2 -> [3,2,1,3,2] i=3: j=3 -> [3,2,1,3,2,3]

4. 复杂度分析

时间复杂度:O(n²)

  • 外层循环:n次

  • 内层循环:最多n次

  • 总操作次数:n + (n-1) + ... + 1 = n(n+1)/2

空间复杂度:O(n²)

  • 结果数组长度:n(n+1)/2

数组元素之和最小化

问题描述

小c希望构建一个包含n个元素的数组,且满以下条件: 1.数组中所有的元素两两不同 2.数组所有元素的最大公约数为k 3.数组元素之和尽可能小 任务是输出数组元素之和的最小值

测试样例

样例1:

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

样例2:

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

样例3:

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

问题理解

你需要构造一个包含 n 个元素的数组,满足以下条件:

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

解题思路

  1. 最大公约数为 k

    • 这意味着数组中的每个元素都必须是 k 的倍数。
    • 因此,我们可以考虑从 k 开始,逐步增加 k 的倍数来构造数组。
  2. 数组元素两两不同

    • 为了避免重复,我们可以从 k 开始,每次增加 k 的倍数,直到找到 n 个不同的元素。
  3. 数组元素之和尽可能小

    • 为了使数组元素之和最小,我们应该从最小的 k 的倍数开始,逐步增加。

算法步骤

  1. 初始化一个变量 current 为 k,表示当前考虑的数。

  2. 初始化一个列表 result 来存储数组元素。

  3. 循环 n 次:

    • 将 current 添加到 result 中。
    • 将 current 增加 k,以确保下一个数是 k 的倍数且不重复。
  4. 计算 result 中所有元素的和,并返回该和。

代码

import java.util.List;

public class Main {
    public static int solution(int n, int k) {
       // 初始化当前数为 k
    int current = k;
    // 初始化结果列表
    List<Integer> result = new ArrayList<>();
    
    // 循环 n 次
    for (int i = 0; i < n; i++) {
        // 将当前数添加到结果列表
        result.add(current);
        // 将当前数增加 k
        current += k;
    }
    
    // 计算结果列表中所有元素的和
    int sum = 0;
    for (int num : result) {
        sum += num;
    }
    
    // 返回和
    return sum;
    }

    public static void main(String[] args) {
        System.out.println(solution(3, 1) == 6);
        System.out.println(solution(2, 2) == 6);
        System.out.println(solution(4, 3) == 30);
    }
}

最小前缀操作问题

问题描述

小U和小R有两个字符串,分别是 S 和 T,现在小U需要通过对 S 进行若干次操作,使其变成 T 的一个前缀。操作可以是修改 S 的某一个字符,或者删除 S 末尾的字符。现在你需要帮助小U计算出,最少需要多少次操作才能让 S 变成 T 的前缀。

测试样例

样例1:

输入:S = "aba", T = "abb" 输出:1

样例2:

输入:S = "abcd", T = "efg" 输出:4

样例3:

输入:S = "xyz", T = "xy" 输出:1

样例4:

输入:S = "hello", T = "helloworld" 输出:0

样例5:

输入:S = "same", T = "same" 输出:0

  • 问题分析:

  • 目标是将字符串S转换为T的前缀

  • 允许的操作有两种:

  • 修改某个字符

  • 删除末尾字符

  • 特殊情况处理:

  • 如果S已经是T的前缀,直接返回0

  • 可以使用T.startsWith(S)快速判断

3. 主要情况分类:

  • 情况1:S比T长

  • 必须删除多余的字符(sLen - tLen次操作)

  • 还需要修改不匹配的字符

  • 情况2:S长度小于等于T

  • 只需要修改不匹配的字符

  • 示例分析:

   - S和T等长,只需修改最后一个字符
   - 操作次数 = 1

   例2: S = "abcd", T = "efg"
   - S比T长,需要删除1个字符
   - 还需要修改3个字符
   - 操作次数 = 1 + 3 = 4

   例3: S = "xyz", T = "xy"
   - S比T长,需要删除1个字符
   - 操作次数 = 1

代码

    public static int solution(String S, String T) {
        // 如果S已经是T的前缀,直接返回0
        if (T.startsWith(S)) {
            return 0;
        }
        
        int sLen = S.length();
        int tLen = T.length();
        
        // 如果S比T长,需要删除多余的字符再修改不匹配的字符
        if (sLen > tLen) {
            int deleteCount = sLen - tLen;
            int changeCount = 0;
            for (int i = 0; i < tLen; i++) {
                if (S.charAt(i) != T.charAt(i)) {
                    changeCount++;
                }
            }
            return deleteCount + changeCount;
        }
        
        // 如果S长度小于等于T,只需要计算需要修改的字符数
        int changeCount = 0;
        for (int i = 0; i < sLen; i++) {
            if (S.charAt(i) != T.charAt(i)) {
                changeCount++;
            }
        }
        return changeCount;
    }

    public static void main(String[] args) {
        System.out.println(solution("aba", "abb") == 1);
        System.out.println(solution("abcd", "efg") == 4);
        System.out.println(solution("xyz", "xy") == 1);
        System.out.println(solution("hello", "helloworld") == 0);
        System.out.println(solution("same", "same") == 0);
    }
}
  • 时间复杂度分析:

  • O(min(len(S), len(T)))

  • 只需要遍历较短的字符串长度

  • 空间复杂度分析:

  • O(1)

  • 只使用了常数级别的额外空间

这道题的关键是理解:

  • 当S比T长时,必须先考虑删除操作

  • 对于需要保留的字符,只需要考虑修改操作

  • 不需要实际执行修改操作,只需要计算次数