当前位置: 首页 > news >正文

蓝桥杯 Java B 组之区间调度、找零问题(理解贪心局限性)

Day 1:区间调度、找零问题(理解贪心局限性)


📖 一、贪心算法简介

贪心算法(Greedy Algorithm) 是一种通过局部最优解来得到全局最优解的算法策略。它每一步选择当前最优的选择,而不考虑后续的选择。贪心算法适用于某些特定问题,能有效地简化问题的求解过程。

贪心算法的基本特点:

  1. 局部最优选择:每次选择问题中最优的解。
  2. 无后效性:每次的选择不会影响之前的选择。
  3. 全局最优解:当满足某些条件时,贪心策略会导致全局最优解。

贪心算法的核心步骤:

  1. 贪心选择:从当前状态中选择最优解。
  2. 可行性检查:检查当前选择是否满足问题的约束。
  3. 更新状态:做出选择后,更新问题的状态,继续执行下一步。

📖 二、区间调度问题(Activity Selection Problem)

问题描述:

假设有一个会议室,可以接待多个活动(每个活动有开始和结束时间)。我们需要选择尽可能多的活动,使得它们之间不冲突,即活动的开始时间不早于前一个活动的结束时间。

贪心策略:

  1. 每次选择结束时间最早的活动,因为这样可以腾出更多时间给后续活动,从而最大化能安排的活动数量。

步骤

  1. 按照活动的结束时间对所有活动进行排序。
  2. 从第一个活动开始,选择第一个活动并安排。
  3. 对于每个后续活动,判断其开始时间是否大于等于已选活动的结束时间,若满足条件,选择该活动。

代码实现(活动选择问题)

import java.util.*;

public class ActivitySelection {
    static class Activity {
        int start, end;
        public Activity(int start, int end) {
            this.start = start;
            this.end = end;
        }
    }

    public static void activitySelection(List<Activity> activities) {
        // 按照结束时间排序
        activities.sort(Comparator.comparingInt(a -> a.end));

        int count = 1; // 至少选择第一个活动
        int lastEndTime = activities.get(0).end; // 第一个活动结束时间

        System.out.println("选中的活动是:");
        System.out.println("开始时间: " + activities.get(0).start + " 结束时间: " + activities.get(0).end);

        // 遍历剩余的活动
        for (int i = 1; i < activities.size(); i++) {
            // 如果活动的开始时间 >= 上一个活动的结束时间,则选择该活动
            if (activities.get(i).start >= lastEndTime) {
                System.out.println("开始时间: " + activities.get(i).start + " 结束时间: " + activities.get(i).end);
                lastEndTime = activities.get(i).end;
                count++;
            }
        }

        System.out.println("最大活动数量为:" + count);
    }

    public static void main(String[] args) {
        List<Activity> activities = new ArrayList<>();
        activities.add(new Activity(1, 4));
        activities.add(new Activity(2, 6));
        activities.add(new Activity(5, 8));
        activities.add(new Activity(7, 9));
        activities.add(new Activity(8, 10));

        activitySelection(activities);
    }
}

代码讲解:

  1. 活动类 Activity:每个活动有一个开始时间和结束时间。
  2. 排序:首先按照结束时间对活动进行排序,目的是为了优先选择结束时间早的活动。
  3. 贪心选择:从第一个活动开始,依次选择那些开始时间不早于前一个选择活动的结束时间的活动。

📖 三、找零问题(Coin Change Problem)

问题描述:

给定一些硬币面额,和一个目标金额 amount,我们需要用最少的硬币组合成这个目标金额。例如,面额是 [1, 2, 5],目标金额是 11,用最少的硬币组成 11

贪心策略:

  • 贪心算法并不适用于所有找零问题。有时贪心选择(选择最大的面额硬币)并不能得到最优解。

贪心策略的局限性:

贪心算法假设选择当前最优解最终能带来全局最优解,但在某些情况下,这种假设是不成立的。例如,面额为 [1, 3, 4],目标金额为 6,贪心策略选择面额 4,然后剩余 2,而最优解应该选择 3 + 3,而非 4 + 1 + 1

贪心策略不能保证最优解

  • 在找零问题中,贪心策略(选择最大面额硬币)在某些情况下不能得到最少硬币数。
  • 需要考虑其他动态规划策略来确保得到最优解。

代码实现(找零问题)

import java.util.*;

public class CoinChange {
    public static int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount + 1];
        Arrays.fill(dp, amount + 1); // 初始化为一个较大的值
        dp[0] = 0; // 0元需要0个硬币

        for (int i = 1; i <= amount; i++) {
            for (int coin : coins) {
                if (i - coin >= 0) {
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                }
            }
        }

        return dp[amount] == amount + 1 ? -1 : dp[amount]; // 如果没有找到解,返回-1
    }

    public static void main(String[] args) {
        int[] coins = {1, 2, 5};
        int amount = 11;

        System.out.println("最少硬币数为: " + coinChange(coins, amount));
    }
}

代码讲解:

  1. dp[i]:表示组成 i 元需要的最少硬币数。
  2. 初始化dp[0] = 0(0元需要0个硬币),其他元素初始化为一个很大的数 amount + 1,表示不能通过当前硬币组合组成的金额。
  3. 动态转移:对于每个金额 i,遍历所有硬币面额 coin,更新 dp[i]
  4. 返回值:如果 dp[amount] 还是初始值,说明无法组成该金额,返回 -1

贪心与动态规划比较:

  • 贪心法:从最大面额硬币开始,每次选择最大可能的硬币。
  • 动态规划:计算每个金额的最优解,保证了在每一步做出最优选择,从而找到全局最优解。

📖 四、总结:

常见贪心算法题型

  1. 区间调度问题:选择不重叠的活动(按结束时间排序)。
  2. 背包问题:贪心适用于分数背包(物品可以分割),但不适用于0/1背包
  3. Huffman 编码:通过贪心算法生成最优编码。

贪心算法的易错点:

  1. 贪心算法并不总能得到全局最优解,只有在满足“贪心选择性质”和“最优子结构”时,贪心算法才是有效的。
  2. 找零问题:贪心算法在某些面额下可能无法得到最少硬币数。

贪心算法适用条件:

  1. 贪心选择性质:局部最优解能推出全局最优解。
  2. 最优子结构:问题的最优解由子问题的最优解构成。

🎯 练习建议

  1. 练习活动选择问题硬币找零问题等贪心问题。
  2. 多做贪心和动态规划之间的对比,理解它们的区别和联系。

相关文章:

  • 昇腾AI生态组件全解析:与英伟达生态的深度对比
  • 【Python量化金融实战】-第1章:Python量化金融概述:1.4 开发环境搭建:Jupyter Notebook、VS Code、PyCharm
  • 游戏引擎学习第117天
  • JQD武学思想
  • DeepSeek掘金——DeepSeek-R1+ML混合欺诈检测
  • ElasticSearch查询指南:从青铜到王者的骚操作
  • gccgo1.18编译笔记
  • AxiosError: Network Error
  • 关于order by的sql注入实验
  • 如何用Python 3自动打开exe程序
  • c++入门-------命名空间、缺省参数、函数重载
  • 我的电脑是 3070ti 能用那个级别的deepseek
  • 解决Open WebU无法显示基于OpenAI API接口的推理内容的问题
  • 详细介绍嵌入式硬件设计
  • Ubuntu - Redis 安装、远程访问
  • 图书馆系统源码详解
  • 萌新学 Python 之自定义函数
  • Unity技术突破
  • Leetcode 3463. Check If Digits Are Equal in String After Operations II
  • 2025版-Github账号注册详细过程
  • 银行做网站视频/南昌seo全网营销
  • 哪个做app的网站好/怎样推广自己的商城
  • 海南做网站公司/搜索引擎优化seo专员招聘
  • 丰润区建设局网站/app开发成本预算表
  • 网站建设遇到哪些攻击/直通车推广技巧
  • wordpress 宠物/seo关键词