贪心鱼的鱼干大分配和数据表是否能顺利产出| 豆包MarsCode AI 刷题

48 阅读6分钟

问题描述

在猫星球上,小R负责给一行排队的猫分发鱼干。每只猫有一个等级,等级越高的猫应该得到更多的鱼干。规则如下:

  1. 每只猫至少得到一斤鱼干。
  2. 如果一只猫的等级高于它相邻的猫,它就应该得到比相邻的猫更多的鱼干。

小R想知道,为了公平地满足所有猫的等级差异,他至少需要准备多少斤鱼干。


思路

这个问题的核心在于分配鱼干给每只猫,需要满足以下条件:

  1. 每只猫至少有一斤鱼干。
  2. 如果一只猫的等级比前一只猫高,则它必须得到更多的鱼干。
  3. 如果一只猫的等级比后一只猫高,则它也必须得到更多的鱼干。

为了实现这一点,我们可以分两步进行:

  1. 从左到右遍历:确保每个猫的鱼干数不少于其前面的猫且满足等级要求。
  2. 从右到左遍历:确保每个猫的鱼干数不少于其后面的猫且满足等级要求。

假设我们有以下猫的等级列表 [1, 2, 2]

  1. 初始化fishCounts = [1, 1, 1]

    注: 为什么初始化为1?

    因为每只猫至少需要一斤鱼干。

  2. 从左到右遍历

    (1) 第二只猫的等级高于第一只猫,所以 fishCounts[1] = fishCounts[0] + 1 = 2

    (2) 第三只猫的等级与第二只猫相同,所以 fishCounts[2] 不变

    (3) 结果:fishCounts = [1, 2, 1]

  3. 从右到左遍历

    (1) 第二只猫的等级高于第三只猫,所以 fishCounts[1] = Math.max(fishCounts[1], fishCounts[2] + 1) = 2

    (2) 第一只猫的等级低于第二只猫,所以 fishCounts[0] 不变

    (3) 结果:fishCounts = [1, 2, 1]

  4. 累加总鱼干数total_fish = 1 + 2 + 1 = 4

代码详解

import java.util.*;

public class Main {
    public static int solution(int n, List<Integer> cats_levels) {
        // 初始化
        int[] fishCounts = new int[n];
        for (int i = 0; i < n; i++) {
            fishCounts[i] = 1;
        }

        // 从第二只猫开始,逐个比较当前猫与前一只猫的等级
        for (int i = 1; i < n; i++) {
            if (cats_levels.get(i) > cats_levels.get(i - 1)) {
                fishCounts[i] = fishCounts[i - 1] + 1;
            }
        }

        // 从倒数第二只猫开始,逐个比较当前猫与后一只猫的等级
        for (int i = n - 2; i >= 0; i--) {
            if (cats_levels.get(i) > cats_levels.get(i + 1)) {
                fishCounts[i] = Math.max(fishCounts[i], fishCounts[i + 1] + 1);
            }
        }

        // 累加
        int total_fish = 0;
        for (int count : fishCounts) {
            total_fish += count;
        }

        return total_fish;
    }

    public static void main(String[] args) {
        List<Integer> catsLevels1 = new ArrayList<>();
        catsLevels1.add(1);
        catsLevels1.add(2);
        catsLevels1.add(2);

        List<Integer> catsLevels2 = new ArrayList<>();
        catsLevels2.add(6);
        catsLevels2.add(5);
        catsLevels2.add(4);
        catsLevels2.add(3);
        catsLevels2.add(2);
        catsLevels2.add(16);

        List<Integer> catsLevels3 = new ArrayList<>();
        catsLevels3.add(1);
        catsLevels3.add(2);
        catsLevels3.add(2);
        catsLevels3.add(3);
        catsLevels3.add(3);
        catsLevels3.add(20);
        catsLevels3.add(1);
        catsLevels3.add(2);
        catsLevels3.add(3);
        catsLevels3.add(3);
        catsLevels3.add(2);
        catsLevels3.add(1);
        catsLevels3.add(5);
        catsLevels3.add(6);
        catsLevels3.add(6);
        catsLevels3.add(5);
        catsLevels3.add(5);
        catsLevels3.add(7);
        catsLevels3.add(7);
        catsLevels3.add(4);

        System.out.println(solution(3, catsLevels1) == 4); 
        System.out.println(solution(6, catsLevels2) == 17); 
        System.out.println(solution(20, catsLevels3) == 35); 
    }
}

思考总结

虽然这不是一个典型的动态规划问题,但这种分两次遍历的思想类似于动态规划中的状态转移。通过分别从前向后和从后向前遍历数组,确保每个元素同时满足与其前后相邻元素的关系。在每次遍历时,都需要尽可能地满足局部最优解,最终达到全局最优解。

问题描述

在数据仓库中,表与表之间存在数据依赖关系。例如一张用于电商销售额统计分析表 A ,会依赖商品销售表 B 和商品表 C,商品表 C 会依赖商品类目表 D。如果这些依赖关系中存在循环,那么数据将无法正确地按顺序产出。

目前已知一组数据表的依赖关系,请实现一个函数,用于判断给定的表依赖关系是否能够正常产出数据。

参数说明

  • relations: 二维字符串数组,表示表之间的依赖关系
  • 每个子数组的格式为 ["A", "B", "C", ...],其中:
  • 第一个元素 A 表示目标表
  • 后续元素(BC 等)表示 A 所依赖的上游表
  • 子数组的长度至少为 2(即每个表至少依赖一个上游表),但不长于 10

返回值

  • 如果所有表都能够正常产出数据(不存在循环依赖),返回 true;否则返回 false

思路

  1. 构建图

    使用邻接表表示图,其中每个节点指向其依赖的节点。

  2. 深度优先搜索(DFS)检测环

    (1) 使用两个集合:visited 记录当前路径上的节点,completed 记录已经完成访问的节点。

    (2) 对每个节点进行DFS遍历,检查是否存在环。

图解

假设我们有以下依赖关系:

A -> B, C
B -> D
C -> E
D -> A

我们可以将其表示为一个图:

A -> B -> D -> A
|              |
|              v
+-------------> C -> E

通过DFS遍历,我们可以发现存在环 A -> B -> D -> A

代码详解

  1. 构建图

    Map<String, List<String>> graph = new HashMap<>();
    for (String[] relation : relations) {
        String target = relation[0];
        List<String> dependencies = Arrays.asList(Arrays.copyOfRange(relation, 1, relation.length));
        graph.put(target, dependencies);
    }
    
  2. 初始化集合

    Set<String> visited = new HashSet<>();
    Set<String> completed = new HashSet<>();
    

    其中, visited 用于记录当前路径上的节点。 completed 用于记录已经完成访问的节点。

  3. 对每个节点进行DFS

    for (String node : graph.keySet()) {
        if (hasCycle(node, graph, visited, completed)) {
            return false;
        }
    }
    
  4. DFS检测环

    private static boolean hasCycle(String node, Map<String, List<String>> graph, Set<String> visited, Set<String> completed) {
        // 如果当前节点已经在当前路径中,说明存在环
        if (visited.contains(node)) {
            return true;
        }
    
        // 如果当前节点已经完成访问,返回false
        if (completed.contains(node)) {
            return false;
        }
    
        // 将当前节点加入当前路径
        visited.add(node);
    
        // 递归检查当前节点的依赖节点
        if (graph.containsKey(node)) {
            for (String dependency : graph.get(node)) {
                if (hasCycle(dependency, graph, visited, completed)) {
                    return true;
                }
            }
        }
    
        // 当前节点访问完成
        visited.remove(node);
        completed.add(node);
    
        return false;
    }
    
  5. 主函数测试

    public static void main(String[] args) {
        System.out.println(solution(new String[][] {{"A", "B", "C"}, {"B", "D"}, {"C",7 "E"}, {"D", "A"}}) == false);
        System.out.println(solution(new String[][] {
            {"A", "B", "C", "D", "E"},
            {"F", "G", "H", "I"},
            {"J", "K", "L", "M", "A"},
            {"N", "O", "P", "Q"},
            {"E", "H", "I", "J"},
            {"R", "S", "T", "U"},
            {"V", "W", "X"},
            {"Y", "Z"}}) == false);
    }
    

思考总结

使用邻接表表示图,便于存储和遍历。DFS是一种常用的图遍历算法,适用于检测环、拓扑排序等问题(可以通过递归或栈实现DFS)。使用两个集合 visited 和 completed 来跟踪节点的访问状态。如果在DFS过程中遇到已经在 visited 中的节点,说明存在环。使用HashSet 可以提供高效的插入、删除和查找操作,适合用于记录访问状态。

学习建议

  1. 理解基础概念:确保对基本的数据结构(如数组、列表)和控制结构(如循环、条件语句)有扎实的理解。
  2. 多做练习:通过刷题平台不断练习类似的问题,增强解决问题的能力。
  3. 学会使用AI工具:利用AI工具来辅助学习,获取代码示例、调试帮助和优化建议。
  4. 多问问题:加入编程社区或参加在线课程,与其他学习者交流经验。
  5. 多多动手:将学到的知识应用到实际项目中,加深理解和记忆。