贪心算法---java---黑马

news2024/11/26 14:27:08

贪心算法

1)Greedy algorithm

称之为贪心算法或者贪婪算法,核心思想是

  1. 将寻找最优解的问题分为若干个步骤
  2. 每一步骤都采用贪心原则,选取当前最优解
  3. 因为未考虑所有可能,局部最优的堆叠不一定得到最终解最优

贪心算法例子

Dijkstra

while (!list.isEmpty()) {
    // 选取当前【距离最小】的顶点
    Vretex curr = chooseMinDistVertex(list);
    
    // 更新当前顶点到相邻顶点距离
    updateNeighboursDish(curr);
    
    // list集合中移除当前顶点
    list.remove(curr);
    // 标记当前顶点已被访问
    curr.visited = true;
}
  • 未能找到最短路径:存在负边 情况,得不到正确解;
  • 贪心原则会认为本次已找到该顶点的最短路径,使得该顶点赋为已访问
  • 与之对比,Bellman-Ford算法并未考虑局部距离最小顶点,而是每次处理所有边 ,不会出错,当然效率不如Dijkstra算法;

prim

while (!list.isEmpty()) {
    // 选取当前【距离最小】的顶点
    Vretex curr = chooseMinDistVertex(list);
    // 更新当前顶点到相邻顶点距离
    updateNeighboursDish(curr);
    // list集合中移除当前顶点
    list.remove(curr);
    // 标记当前顶点已被访问
    curr.visited = true;
}

prim与Dijkstra的区别在于,根据距离选取最小顶点不同,Dijkstra算法是一个累加距离,而prim算法中距离是跟相邻顶点间的距离

KrusKal

List<String> list = new ArrayList<>();
DisjoinSet set = new DisjoinSet(size);
while (list.size() < size - 1) {
    // 选取当前【距离最短】的边
    Edge poll = queue.poll();
    int i = set.find(poll.start);
    int j = set.find(poll.end);
    // 判断两个集合是否相交
    if (i != j) {// 未相交
        list.add(poll);
        set.union(i, j);	// 相交操作
    }
    
}

其他贪心算法例子

  • 选择排序、堆排序
  • 拓扑排序
  • 并查集和中的union by size 和union by height
  • 哈夫曼编码
  • 钱币找零
  • 任务编排
  • 近似算法

零钱兑换ⅡLeetcode518

递归实现

public class Leetcode518 {
    public int change(int[] coins, int amount) {
        return coinChange(coins, 0, amount, new LinkedList<>(), true);
    }
    
    public int coinChange(int[] coins, int index, int amount, LinkedList<Integer> stack, boolean first) {
        if (!first) {
            stack.push(coins[i]);
        }
        int sum = 0;
        if (amount == 0) {
            System.out.printlin(stack);
            sum = 1;
        } else if (amount < 0) {
            System.out.println(stack)
            sum = 0;
        } else {
            for(int i = index; i < coins.length; i++) {
               sum += coinChange(coins, i, amount - coins[i], stack, false);
            }
        }
        if (!stack.isEmpty()) {
            stack.pop();
        }
        return sum;
    }
}
    

零钱兑换Leetcode322

递归实现

public class Leetcode322 {
    
    static int min = -1;
    
    public int change(int[] coins, int amount) {
        coinChange(coins, 0, amount, new AtomicInteger(-1), new LinkedList<Integer>(), true);
        return min;
    }
    
    public void coinChange(int[] coins, int index, int amount, AtomicInteger count, LinkedList<Integer> stack, boolean first) {
        if (!first) {
            stack.push(coins[i]);
        }
        count.incrementAndGet();	// count++;
        int sum = 0;
        if (amount == 0) {
            System.out.println(stack);
            if (min == -1) {
                min = min.get();
            } else {
                min = Math.min(min, count.get());
            }
        } else {
            for(int i = index; i < coins.length; i++) {
               sum += coinChange(coins, i, amount - coins[i], count, stack, false);
            }
        }
        count.decrementAndGet();	// count--;	
        if (!stack.isEmpty()) {
            stack.pop();
        }
        return sum;
    }
    
    public static void main(String[] args) {
        int[] coins = {5, 2, 1};
        Leetcode322 leetcode = new Leetcode322();
        System.out.printlin(leetcode.coinChange(coins, 5));
    }
}

贪心实现

public class Leetcode322{
    
    public int coinChange(int[] coins, int amount) {
        
        // 前提是coins是降序排序
    	int reminder = amount;
        int count;
        for(int coin : coins) {
            while (reminder > coin) {
                reminder -= coin;
                count++;
            }
            if (reminder == coin) {
                reminder -= coin;
                count++;
                break;
            }
        }
        if (reminder > 0) {
            return -1;
        } else {
            return count;
        }
    }
    
}

但是这个代码放到Leetcode上跑,有些测试用例是不能通过。

动态规划实现

使用动态规划求解,如下面代码

public class Leetcode322{
    
    public int coinChange(int[] coins, int amount) {
        
        int[] dp = new int[amount + 1];
        Arrays.fill(dp, amount + 1);
        dp[0] = 0;
        for(int coin : coins) {
            for(int j = coin; j < amount + 1; j++) {
                dp[j] = Math.min(dp[j], dp[j - coin] + 1);
            }
        }
        int r = dp[amount];
        return r > amount ? -1 : r;
    }
    
}

哈夫曼编码

Huffman树构建过程

  1. 统计出现频次字符,放入优先级队列
  2. 每次出对两个频次最低元素(小顶堆),
  3. 当队列中只有一个元素时,构建Huffman树完成
public class Huffman{
    
    static class Node{
        Character ch;
        int freq;
        Node left;
        Node right;
        String code;
        
        public Node(Character ch) {
            this.ch = ch;
        }
        
        public Node(int freq, Node left, Node right) {
            this.freq = freq;
            this.left = left;
            this.right = right;
        }
        
        int getFreq() {
            return freq;
        }
        
        boolean isLeaf() {
            return node.left == null;
        }
        
        @Override
        public void toString() {
            return "Node{" +
                "ch=" + ch + 
                ", freq=" + freq +
                "}";
        }
    }
    
    String str;
    Node root;
    HashMap<Character, Node> map = new HashMap<>();
    public Huffman(String str) {
        this.str = str;
        char[] chars = str.toCharArray();
		
        // 1.统计频次
        for(char ch : chars) {
            if (!map.containsKey(ch)) {
                map.put(ch, new Node(ch));
            } else {
                Node node = map.get(ch);
                node.freq++;
            }
            
            //方法引用
            // Node node = map.computeIfAbsent(ch, Node :: new);
            // node.frea++;
        }
        for(Node node : map.values()) {
            System.out.println(node.toString());
        }
        
        2.构造树
        PriorityQueue<Node> queue = new PriorityQueue<>(
        Comparator.ComparingInt(Node::getFreq)
        );
        queue.offerAll(map.values());
        while (queue.size() >= 2) {
            Node x = queue.poll();
            Node y = queue.poll();
            int f = x.freq + y.freq;
            queue.offer(new Node(f, x, y));
        }
        root = queue.poll();
        System.out.println(root);
        
        // 功能3 计算每个字符编码		//功能4 字符串编码后占几个bit
        int sum = dfs(root, new StringBuilder());		// 得到字符串编码后占的bit
        for(Node node : map.values()) {
            System.out.printlin(node);
        }
        System.out.println(sum);
        
    }
    
    public int dfs(Node node, StringBuilder sb) {
        int sum = 0;
        if (node.isLeaf()) {
            //编码
            node.node = sb.toString();
            sum = sb.length() * node.freq;
         	// System.out.println(sb.toString());   
        } else {
            sum += dfs(node.left, sb.append("0"));
            sum += dfs(node.right, sb.append("1"));
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sum;
    }
    
    public String encode() {
        char[] chars = str.toCharArray();
        StringBuilder sb = new StringBuilder();
        for(char ch : chars) {
            sb.append(map.get(ch).code);
        }
        return sb.toString();
    }
    
    public String decode(String str) {
        int i = 0;
        char[] chars = str.toCharArray();
        StringBuilder sb = new StringBuilder();
        Node node = root;
        while (i < chars.length) {
            if (!node.isLeaf()) {
                if (chars[i] == '0') {
                    node = node.left;
                } else if (chars[i] == '1'){
                    node = node.right;
                }
                i++;
            } 
            if (node.isLeaf()) {
                sb.append(node.ch);
                node = root;
            }
            
        }
        return sb.toString();
    }
}

活动选择问题

要在一个会议室举办n个活动

  • 每个活动有它们各自的起始和结束时间
  • 找出时间上不冲突的活动组合,能够最充分利用会议室(举办的活动次数最多)
public class ActivitySelectionProblem{
    
    static class Activity{
        int index;
        int start;
        int end;
        
        public Activity(int index, int start, int end) {
            this.index = index;
            this.start = start;
            this.end = end;
        }
        
        public int getEnd() {
            return end;
        }
        
        @Override
        public void tostring() {
            return "Activity(" + index + ")";
        }
    }
    
    public static void main(String[] args) {
        Activity[] activity = new Activity[]{
            new Activity(0, 1, 3),
            new Activity(1, 2, 4),
            new Activity(2, 3, 5)
        }	
        
        Arrays.sort(activity, Comparator.comparingInt(Activity::getEnd))
        System.out.println(activity);
        
        // 
        select(activity, activity.length);
    }
    
    public void select(Activity[] activity, int n) {
        
        List<int[]> res = new ArrayList<>();
        res.add(activity[0]);
        Activity pre = res;
        for(int i = 1; i < n; i++) {
            Activity curr = activity[i];
            if (curr.start >= pre.end) {
                res.add(curr);
                pre =  curr;
            }
        }
        for(Activity a : res) {
            System.out.println(a);
        }
    }
}

Leetcode435

无重叠区间

public class Leetcode435{
    
    public int eraseOverlapIntervals(int[][] intervals) {
        // 根据数组中的第二个元素先升序排序
        Arrays.sort(intervals, (a, b) -> a[1] - b[1]);
        
        List<int[]> res = new ArrayList<>();
        res.add(intervals[0]);
        int[] pre = res.get(0);
        int count = 0;	// 减少个数
        for(int i = 1; i < intervals.length; i++) {
            int[] curr = intervals[i];
            if (curr[0] < pre[1]) {		// 当前的初始值小于前一个的结束值,有冲突
                count++;
            } else {	// 只要当前的初始值大于等于前一个的结束值,则不冲突
                res.add(curr);
                pre = curr;
            }
        }
        return count;
    }
}

分数背包问题

  1. n个液体物品,有重量和价格属性
  2. 现取走10L物品
  3. 每次可以不拿,全拿,拿一部分,问最高价值是多少
    在这里插入图片描述
public class FractionalKnapsackProblem{
    
    static class Item{
        int index;
        int weight;
        int value;
        
        public Item(int index, int weight, int value) {
            this.index = index;
            this.weight = weight;
            this.value = value;
        }
        
        public int perValue() {
            return value / weight;
        }
        
        @Override
        public void toString() {
            return "Item(" + index + ")";
        }
    }
    
    public static void main(String[] args) {
        Item[] items = new Item[]{
            new Item(0, 4, 24),
            new Item(1, 8, 160),
            new Item(2, 2, 4000),
            new Item(3, 6, 108),
            new Item(4, 1, 4000),
        }
        
        select(items, 10);
    }
    
    public int select(Item[] items, int n) {
        Arrays.sort(items, Comparator.comparingInt(Item::preValue).reverse());
        int sum = 0;
        for(int i = 0; i < items.length; i++) {
            Item curr = items[i];
            if (n >= curr.weight) {
                n -= curr.weight;
                sum += curr.value;
            } else {
                sum += curr.perValue() * n;
                break;
            }
        }
        return sum;
    }
}

0-1背包问题

在这里插入图片描述

  1. n个物体都是固体,有重量和价值
  2. 现取走不超过10克物品
  3. 每次可以不拿或者全拿,问最高价值是多少
public class FractionalKnapsackProblem{
    
    static class Item{
        int index;
        int weight;
        int value;
        
        public Item(int index, int weight, int value) {
            this.index = index;
            this.weight = weight;
            this.value = value;
        }
        
        public int perValue() {
            return value / weight;
        }
        
        @Override
        public void toString() {
            return "Item(" + index + ")";
        }
    }
    
    public static void main(String[] args) {
        Item[] items = new Item[]{
            new Item(0, 1, 1000000),
            new Item(1, 4, 1600),
            new Item(2, 8, 2400),
            new Item(3, 5, 30),
        }
        
        select(items, 10);
    }
    
    public int select(Item[] items, int n) {
        Arrays.sort(items, Comparator.comparingInt(Item::preValue).reverse());
        int sum = 0;
        for(int i = 0; i < items.length; i++) {
            Item curr = items[i];
            if (n >= curr.weight) {
                n -= curr.weight;
                sum += curr.value;
            }
        }
        return sum;
    }
}

得到的结果,最大价值结果是:1001630 ,实际上选择钻石红宝石 得到的价值结果 1002400

贪心算法局限性

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2232048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

产品宣传册如何分享到微信朋友圈

在这个互联网高速发展的时代&#xff0c;微信已经成为我们日常生活中不可或缺的社交工具。作为商家或个人&#xff0c;如何将产品宣传册分享到微信朋友圈&#xff0c;提高产品知名度和影响力&#xff0c;成为了一项至关重要的技能。 那要怎么操作呢&#xff1f; 1. 实用工具&a…

轻松入门WordPress:在Ubuntu上搭建本地网站并配置公网访问地址

文章目录 前言1. 安装WordPress2. 创建WordPress数据库3. 安装相对URL插件4. 安装内网穿透发布网站4.1 命令行方式&#xff1a;4.2. 配置wordpress公网地址 5. 配置WordPress固定公网地址 前言 本文主要介绍如何在Linux Ubuntu系统上使用WordPress搭建一个本地网站&#xff0c…

ubuntu编译内核安装启动

下载源码 apt update apt install linux-source # /usr/src/linux-source-5.4.0/linux-source-5.4.0.tar.bz2 下载源码 tar -jxvf linux-source-5.4.0.tar.bz2 # /usr/src/linux-source-5.4.0 解压源码 安装依赖 sudo apt -y install build-essential sudo apt -y i…

多个锚点定位时的锚点优选方法(附公式和MATLAB代码讲解)

在多锚点定位系统中,锚点的选择对定位精度有重要影响。以下是几种常见的锚点选优方法,配合相应的公式和MATLAB代码示例进行详细分析。 文章目录 基于几何分布的选择基于距离最小化的选择加权优化选择总结基于几何分布的选择 方法描述: 锚点的几何分布影响定位的可辨识性。选…

DICOM标准:US超声模块属性详解——超声医学的DICOM标准解析

引言 数字成像和通信在医学领域中的应用极为广泛&#xff0c;其中DICOM&#xff08;数字成像和通信医学&#xff09;标准对于确保不同设备和系统之间的兼容性和互操作性至关重要。本文将详细介绍DICOM标准中关于超声医学&#xff08;Ultrasound, US&#xff09;的部分&#xff…

华为鲲鹏一体机 安装笔记

安装驱动 在这个链接 社区版-固件与驱动-昇腾社区 1 下载NPU固件 需要注册登录&#xff0c;否则报错&#xff1a; ERR_NO:0x0091;ERR_DES:HwHiAiUser not exists! Please add HwHi AiUser 准备软件包-软件安装-CANN…

STM32H750 USBCDC配置与使用

STM32H750 USBCDC配置与使用 &#x1f4cd;相关参考文章&#xff1a;《STM32 USB CDC VPC》 STM32H750VB有2个USB OTG接口&#xff08;1FS&#xff0c;1HS/FS&#xff09;无晶振型解决方案&#xff0c;带有LPM和BCD。 &#x1f516;本次使用USB-PTG-FS作为测试 &#x1f33f;…

引领数字时代:万码优才如何变革IT人才招聘新体验(这里有更精准的推荐)

目录 引领数字时代&#xff1a;万码优才如何变革IT人才招聘新体验引领未来科技&#xff0c;精准链接IT精英精准匹配&#xff0c;高效对接海量资源&#xff0c;覆盖广泛优化体验&#xff0c;简化流程 全面升级&#xff1a;AI赋能数字人才职业成长AI模拟面试职场千问智能简历评估…

网络安全法详细介绍——爬虫教程

目录 [TOC](目录)一、网络安全法详细介绍1. 网络安全法的主要条款与作用2. 网络安全法与爬虫的关系3. 合法使用爬虫的指南 二、爬虫的详细教程1. 准备环境与安装工具2. 使用requests库发送请求3. 解析HTML内容4. 使用robots.txt规范爬虫行为5. 设置请求间隔6. 数据清洗与存储 三…

vscode插件-08 Golang

文章目录 Go安装其他必须软件 Go Go语言环境&#xff0c;只需安装这一个插件。然后通过vscode命令下载安装其他go环境需要的内容。 程序调试&#xff0c;需要创建.vscode文件夹并编写launch.json文件。 安装其他必须软件 ctrlshiftp&#xff0c;调出命令面板&#xff0c;输入…

ConnectX-7 25/50/100/200/400G NIC

ConnectX-7 25/50/100/200/400G NIC ConnectX-7提供了广泛的软件定义、硬件加速的网络、存储和安全功能&#xff0c;使组织能够现代化和保护他们的IT基础设施。此外&#xff0c;ConnectX-7还支持从边缘到核心数据中心到云的敏捷和高性能解决方案&#xff0c;同时增强网络安全性…

windows在两台机器上测试 MySQL 集群实现实时备份

在两台机器上测试 MySQL 集群实现实时备份的基本步骤&#xff1a; 一、环境准备 机器配置 确保两台机器&#xff08;假设为服务器 A 和服务器 B&#xff09;能够互相通信&#xff0c;例如它们在同一个局域网内&#xff0c;并且开放了 MySQL 通信所需的端口&#xff08;默认是 …

uniapp实现中间平滑凸起tabbar

uniapp实现中间平滑凸起tabbar 背景实现思路代码实现尾巴 背景 在移动端开发中&#xff0c;tabar是一个使用频率很高的组件&#xff0c;几乎是每个APP都会用到。今天给大家分享一个中间平滑凸起的tabbar组件&#xff0c;有需要的可以做下参考。先上图镇楼&#xff1a; 实现思…

java版询价采购系统 招投标询价竞标投标系统 招投标公告系统源码

在数字化时代&#xff0c;企业需要借助先进的数字化技术来提高工程管理效率和质量。招投标管理系统作为企业内部业务项目管理的重要应用平台&#xff0c;涵盖了门户管理、立项管理、采购项目管理、采购公告管理、考核管理、报表管理、评审管理、企业管理、采购管理和系统管理等…

YOLOV8目标检测C++推理问题总结

背景 数据集有限&#xff0c;使用paddleOCR直接识别准确率无法达到99%&#xff0c;这里尝试用目标检测对识别得分比较低的图片进行二次处理&#xff1b; 类别数目&#xff1a;数字&#xff08;10&#xff09;字母&#xff08;26&#xff09;字符&#xff08;2&#xff09; 38 …

Python毕业设计选题:基于Hadoop的租房数据分析系统的设计与实现

开发语言&#xff1a;Python框架&#xff1a;flaskPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页 房屋信息详情 个人中心 管理员登录界面 管理员功能界面 用户管理界面 房屋信…

CSRF与SSRF

csrf(跨站请求伪造)的原理: csrf全称是跨站请求伪造(cross-site request forgery)&#xff0c;也被称为one-click attack 或者 session riding scrf攻击利用网站对于用户网页浏览器的信任&#xff0c;劫持用户当前已登录的web应用程序&#xff0c;去执行分用户本意的操作。 利…

Rust 力扣 - 1984. 学生分数的最小差值

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 原数组 nums 排序&#xff0c;遍历nums中下标为[0, nums.len() - k]的学生分数 假设当前遍历的下标为i则&#xff0c;以 i 下标为最小值的学生分数的最小差值为nums[i k - 1] - nums[i] 取最小差值的最小值即…

前端笔试新问题总结

记录总结下最近遇到的前端笔试新问题 目录 一、操作数组方法 1.Array.isArray(arr) 2.Object.prototype.toString.call(arr) "[object Array]" 3.arr instanceof Array 1&#xff09;跨帧问题 2&#xff09;修改Array.prototype 3&#xff09;模拟数组的对象…

HTML 基础标签——结构化标签<html>、<head>、<body>

文章目录 1. <html> 标签2. <head> 标签3. <body> 标签4. <div> 标签5. <span> 标签小结 在 HTML 文档中&#xff0c;使用特定的结构标签可以有效地组织和管理网页内容。这些标签不仅有助于浏览器正确解析和渲染页面&#xff0c;还能提高网页的可…