掘金刷题之路 Day 2 | 豆包MarsCode AI刷题

194 阅读8分钟

数组元素之和最小化

考察: 数字逻辑思维

功能亮点 多维度分析, 引导刷题方向

刷题实践:

首先借助MarsCode AI 读懂题目

对题目的样例进行分析

得到分析结果:

题目分析

题目要求构造一个包含 ( n ) 个元素的数组,并且满足以下条件:

  1. 数组中的所有元素两两不同:这意味着数组中的每个元素都必须是唯一的。
  2. 数组所有元素的最大公约数为 ( k ) :这意味着数组中的每个元素都必须是 ( k ) 的倍数。
  3. 数组元素之和尽可能小:我们需要找到一组满足上述条件的数组,使得它们的和最小。

样例解释

  • 样例 1
    • 输入:( n = 3 ), ( k = 1 )
    • 输出:6
    • 解释:当 ( k = 1 ) 时,数组中的每个元素可以是任意正整数。
      为了使数组元素之和最小,我们可以选择最小的 ( n ) 个正整数:1, 2, 3。
      这些数的和为 ( 1 + 2 + 3 = 6 )。
  • 样例 2
    • 输入:( n = 2 ), ( k = 2 )
    • 输出:6
    • 解释:当 ( k = 2 ) 时,数组中的每个元素必须是 2 的倍数。
      为了使数组元素之和最小,我们可以选择最小的 ( n ) 个 2 的倍数:2, 4。
      这些数的和为 ( 2 + 4 = 6 )。
  • 样例 3
    • 输入:( n = 4 ), ( k = 3 )
    • 输出:30
    • 解释:当 ( k = 3 ) 时,数组中的每个元素必须是 3 的倍数。
      为了使数组元素之和最小,我们可以选择最小的 ( n ) 个 3 的倍数:3, 6, 9, 12。
      这些数的和为 ( 3 + 6 + 9 + 12 = 30 )。

解题思路

  1. 确定数组元素的范围:由于数组中的每个元素必须是 ( k ) 的倍数,因此我们可以从 ( k ) 开始,依次选择 ( k ) 的倍数。
  2. 选择最小的 ( n ) ( k ) 的倍数:为了使数组元素之和最小,我们只需要选择最小的 ( n ) 个 ( k ) 的倍数。
  3. 计算这些数的和:将这些数相加,得到的结果就是数组元素之和的最小值。

伪代码

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

根据AI 给出的伪代码已经很明显了,解题方法就是,累加n个(1-n)*k的和。

我的思考:

因为最小的数列是一个等差数列所以我们可以利用公式求和 (a1+an)*n/2

    public static int solution(int n, int k) {
        int a = n*k;
        int result = (k+a)*n/2;
        return result;
    }

AC代码

public class Main {
    public static int solution(int n, int k) {
        int a = n*k;
        int result = (k+a)*n/2;
        return result;
    }

    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的最大连续移动次数问题

考察: 搜索算法

我比较蠢一开始题目样例没有看懂。然后MarsCode AI 启动!!!

样例解释

样例 1

  • 解释
    • 地图是一个 2x2 的矩阵,包含以下高度:
3  4
1  2
    • 小 U 可以选择的移动顺序是:3 -> 4 -> 1 -> 2,这样他可以移动 3 次。
      • 从 3 到 4 是上坡。
      • 从 4 到 1 是下坡。
      • 从 1 到 2 是上坡。
    • 这个顺序满足题目中的所有条件:交替上坡和下坡,每个位置只经过一次。

样例 2

  • 解释
    • 地图是一个 3x3 的矩阵,包含以下高度:
3  9  5
10 1  6
2  7  4
    • 小 U 可以选择的移动顺序是:3 -> 9 -> 5 -> 10 -> 1 -> 6 -> 2 -> 7 -> 4,这样他可以移动 8 次。
      • 从 3 到 9 是上坡。
      • 从 9 到 5 是下坡。
      • 从 5 到 10 是上坡。
      • 从 10 到 1 是下坡。
      • 从 1 到 6 是上坡。
      • 从 6 到 2 是下坡。
      • 从 2 到 7 是上坡。
      • 从 7 到 4 是下坡。
    • 这个顺序满足题目中的所有条件:交替上坡和下坡,每个位置只经过一次。

我这个小辣鸡看了样例还是没有啥思路,于是我又让ai给了点提示 (目前是学习阶段所以我问ai的比较多,后期有一定基础之后就不会这样啦)

看到AI给的提示 用BFS或者DFS!!!!我靠 这个题目不就是这样吗,给你一个网格图形然后问你什么最小!!! 这不是典型的搜索问题吗!!!AI都能秒杀想到,我怎么没有想到。我不会比AI还傻吧,嘿嘿嘿(有点倒反天罡)

问题分析:

小U在地图上行走,要求:

  1. 只能上坡或下坡,不能走到高度相同的点。
  2. 移动时必须交替进行:上坡后必须下坡,下坡后必须上坡,不能连续上坡或下坡。
  3. 每个位置只能经过一次,不能重复行走。

目标是找到小U在满足上述条件下,能够移动的最大次数,即最大的移动步数。

这里我选择DFS不要问为什么,因为这个比较熟练 。当然BFS应该也可以写,回头我试试哈哈哈

解决思路:

我们可以对地图中的每个点进行深度优先搜索(DFS),在搜索过程中:

  • 记录当前位置 x, y
  • 记录上一次的移动类型 lastMove,1表示上坡,2表示下坡,0表示起点(无移动)。
  • 使用一个 visited 数组来记录已经访问过的点,避免重复。

在每次递归中,尝试移动到四个方向的相邻点,判断是否满足以下条件:

  1. 相邻点未被访问过。
  2. 相邻点的高度与当前点不同(不能走到高度相同的点)。
  3. 根据 lastMove 判断移动方向是否符合交替上坡下坡的要求。

AC代码:

public class Main {
    public static int solution(int m, int n, int[][] a) {
        int maxMoves = 0;
        boolean[][] visited = new boolean[m][n];
        // 从每个点开始进行DFS
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                maxMoves = Math.max(maxMoves, dfs(a, visited, i, j, 0, m, n) - 1);
            }
        }
        return maxMoves;
    }

    // lastMove: 0 = 起点,1 = 上一次是上坡,2 = 上一次是下坡
    private static int dfs(int[][] a, boolean[][] visited, int x, int y, int lastMove, int m, int n) {
        visited[x][y] = true;
        int maxLength = 1; // 当前路径长度
        int[] dx = {-1, 1, 0, 0}; // 上下
        int[] dy = {0, 0, -1, 1}; // 左右
        for (int dir = 0; dir < 4; dir++) {
            int nx = x + dx[dir];
            int ny = y + dy[dir];
            // 判断新坐标是否在地图范围内且未被访问过
            if (nx >= 0 && nx < m && ny >= 0 && ny < n && !visited[nx][ny]) {
                int heightDiff = a[nx][ny] - a[x][y];
                if (heightDiff != 0) { // 不能走到高度相同的点
                    int newLastMove = 0;
                    boolean canMove = false;
                    if (lastMove == 0) {
                        // 起点,可以上坡或下坡
                        canMove = true;
                        newLastMove = heightDiff > 0 ? 1 : 2;
                    } else if (lastMove == 1 && heightDiff < 0) {
                        // 上一次是上坡,下一次必须下坡
                        canMove = true;
                        newLastMove = 2;
                    } else if (lastMove == 2 && heightDiff > 0) {
                        // 上一次是下坡,下一次必须上坡
                        canMove = true;
                        newLastMove = 1;
                    }
                    if (canMove) {
                        int length = 1 + dfs(a, visited, nx, ny, newLastMove, m, n);
                        maxLength = Math.max(maxLength, length);
                    }
                }
            }
        }
        visited[x][y] = false; // 回溯
        return maxLength;
    }

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

备注:

  • visited 数组: 用于记录当前路径中已经访问过的点,防止重复访问。
  • 方向数组 dx 和 dy: 用于遍历当前点的四个相邻方向(上、下、左、右)。
  • 移动规则: 根据 lastMove 判断下一步是上坡还是下坡,确保上坡和下坡交替进行。
  • 递归搜索: 通过 DFS 遍历所有可能的路径,更新 maxLength,并在回溯时重置 visited 数组对应的位置。

有个容易错误的地方:

  • maxLength 表示当前路径的节点数,因此移动次数应为 maxLength - 1

我的总结:这个题目和普通的DFS有一点点,就是不能顺便乱走,只能一上一下,而且限制条件多,很适合练手gogogogo。写完这个题目我感觉对DFS影响更加深刻了,算法还是得多写才能进步快快

AI 刷题优势分析:

在这个解题过程中,AI 刷题平台的功能对我有以下帮助:

  1. 智能解题分析: 在我初步完成代码后,平台提供了详尽的解题报告,指出了代码中可能存在的边界问题,并提醒我注意的细节。这使我在提交之前就修正了潜在的错误。
  2. 即时反馈与交互式调试: 在云端编辑器中,我可以方便地运行测试用例,查看输出结果。当结果不符合预期时,平台还提供了错误定位和可能的改进建议。

学习收获与体会:

通过这次刷题实践,我深刻体会到了DFS强大之处。关键在于找到合适的状态表示和转移方程,简化问题的复杂度。

AI 刷题平台的个性题库让我能够有针对性地练习,提高了学习效率。而智能解题分析则帮助我加深了对算法的理解,避免了许多常见的陷阱。

最重要的肯定是这样啦!!!这种交互式的学习方式激发了我的学习兴趣,使得算法学习不再枯燥,而是充满了探索和发现的乐趣。

最后:

算法的学习不仅需要大量的练习,更需要高质量、有针对性的训练。AI 刷题平台通过个性化的题目推荐和智能的解题分析,帮助我在学习过程中少走弯路