抱歉,未找到你想要查询的结果
  • 前端开发

    JavaScript

    JavaScript 入门教程

    本教程带你从初级到高级全面掌握 Javascript 的使用方法

    TypeScript 入门教程

    这是一个很好的简单课程,只需2小时你就可以学习TypeScript基础知识。

    Vue 入门教程

    本教程带您从零开始学习 Vue 框架的使用,让您轻松应对 Vue 项目的开发。

    Ajax 入门教程

    本教程涵盖Ajax的实现原理,及Ajax封装,最后是框架实现方法。

    ES6-10 入门教程

    对比 ES5 进行学习 ES6+,理解 ES6+ 语法背后的思想

    Yarn 入门教程

    Yarn得相关基础知识和高级进阶

    ECharts 入门教程

    从零开始学习 ECharts ,掌握 ECharts 核心内容

    HTML & CSS

    CSS3 入门教程

    本课程从盒模型、文字、颜色、过渡、动画、布局、伪类等方面介绍 CSS3 的使用。

    雪碧图入门教程

    本文详细介绍了雪碧图的由来历史以及各种使用方式

    移动端布局教程

    由于移动互联网的兴起,移动端项目占据了很大一部分比重,本章将详细讲解几种常见布局

    Html5 入门教程

    最新一代的HTML标准,增加了许多实用的特性

    Sass 入门教程

    前端项目中 Sass 的快速入门教程

    HTML 入门教程

    从零讲解 HTML,掌握基础 HTML 知识内容

    canvas 入门教程

    本教程带你从初级到高级全面掌握canvas的使用方法

    uni-app 入门教程

    从零开始学习 uni-app 框架,轻松上手应用开发

  • 服务端相关

    服务器

    Nginx 入门教程

    本教程使您掌握 Nginx 安装、配置、核心模块的详解、实际使用的能力。

    HTTP 入门教程

    从协议原理开始到 Web 服务器以及 Web 安全一网打尽

    Docker 入门教程

    从 Docker 的基础概念开始,从实际问题入手带你学习 Docker

    Shell 入门教程

    本教程由浅入深,系统性的讲解Linux Shell脚本编程。

    Linux 入门教程

    本教程从安装 Linux 开始,囊括 Linux 基础命令操作以及进阶系统管理

    开发工具

    Gradle 入门教程

    本教程使您掌握实际使用gradle进行项目构建、测试、打包、发布的能力。

    Vim 编辑器教程

    课程主要讲解Vim的安装配置,四种模式、基本操作,以及包管理工具和寄存器等内容。

    RESTful 规范教程

    本教程从什么是 REST 开始带你领略 Web 开发中无处不在的规范

    Dreamweaver 教程

    DW 是一款同时具有网页制作和网页管理功能的网站开发工具,可以快速进行网站建设

    Markdown 入门教程

    本课程涵盖 Markdown 的基本及扩展语法。

    Maven 入门教程

    从最基础的安装 Maven 开始到 Maven 在开发中的实际应用

    Eclipse 编辑器教程

    本教程从Eclipse安装开始带你轻松掌握Eclipse常用开发技巧

    GitHub 入门教程

    本教程带你轻松掌握最实用的 GitHub 知识

    Android Studio 编辑器教程

    Android Studio 编程技巧一网打尽

    PyCharm 编辑器教程

    工作经常用到的 PyCharm 编辑器使用技巧一网打尽

    Sublime Text 使用教程

    花里胡哨展示sublime编辑器的各种功能

    Postman 教程

    Postman 由Google 开发用来做接口请求测试,前后端开发人员都可以使用

    Git入门教程

    从入门到精通。

    热门服务端语言

    C 语言入门教程

    本教程从语法基础、进阶知识等各方面详解 C 语言。

    Go 入门教程

    本教程从 Go 语言的基本语法掌握到进阶编程实践

    Kotlin 教程

    从 Kotlin 的基础语法到高级特性一网打尽

    Ruby 入门教程

    本教程从 Ruby 的各种对象开始学习到 Ruby 的实际使用

    ThinkPHP 入门教程

    本教程主要讲解 ThinkPHP 框架如何上手开发应用

  • Java

    基础应用

    Java 入门教程

    深入浅出讲解 Java 语言基础知识,带你入门 Java 语言

    Android 入门教程

    为你解析最实用的 Android 技术,让你平滑上手,顺利进阶,为开发保驾护航

    算法入门教程

    分析讲解常见算法的思想及使用

    数据结构入门教程

    通俗易懂的带你了解 Java 数据结构

    Lambda 表达式教程

    本教程展现了Lambda表达式的基础语法以及在程序中的应用

    Java 并发原理入门教程

    本教程为Java并发原理入门教程,在Java程序开发中占据着举足轻重的地位

    设计模式入门教程

    带你分析最常见的九个设计模式

    Java并发工具

    本课程简洁明了展示最基本的并发工具类相关概念及应用方法。

    JVM 入门教程

    JVM 入门教程,对JVM结构进行分模块讲解,简单易懂。

    RabbitMQ 入门教程

    超系统的RabbitMQ基础知识课程,你还在等什么?

    网络编程入门教程

    Java 网络编程核心要点详解

    后端通用面试教程

    带你系统梳理后端高频面试题,轻松丰富你的校招&社招阶段

    框架应用

    Spring Boot 入门教程

    循序渐进讲解 Spring Boot 企业级应用开发

    Spring 入门教程

    通俗易懂 渐进式讲解 Spring 企业级开发应用

    Hibernate 入门教程

    由浅入深讲解 Hibernate 企业级 JDBC 应用框架

    MyBatis 入门教程

    本教程整理出"百分之二十"的知识,帮你办到"百分之八十"事情

    Spring MVC 入门教程

    通俗易懂讲解 Spring MVC 框架应用

    Swagger 入门教程

    本课程以图文并茂的方式带你学习 Swagger 核心知识和应用剖析

    Zookeeper 入门教程

    由浅入深的 学习 ZooKeeper 的基本使用以及高级使用

    Netty 教程

    由浅入深的讲解 Netty 的核心知识体系,快速上手使用和理解 Netty

    Spring Security

    本课程涵盖了 Spring Security 框架的基本原理和集成方法

    微服务

    Spring Cloud Hystrix

    系统介绍 Hystrix 支持特性与实际应用场景实战

  • Python

    基础应用

    Python 入门语法教程

    本教程带你从 Python 的基础语法开始学习 Python。

    Python 原生爬虫教程

    本教程从爬虫基础知识到进阶技巧到实际应用。

    Python 进阶应用教程

    本教程涵盖 Python 的面向对象、标准库解析、异常处理直至最后的领域应用

    Python 算法入门教程

    用 Python 代码实现常用算法并汲取算法核心思想。

    进阶方向应用

    Django 入门教程

    从 Web 基础到 Django 框架的实际开发应用

    Flask 框架教程

    Flask 框架快速入门实现一个 TodoList 功能

    NumPy 入门教程

    本教程从基础的数据类型开始到 NumPy 的高级应用一网打尽

    Scrapy 入门教程

    从爬虫基础开始到使用 Scrapy 框架抓取各大网站数据

    TensorFlow 入门教程

    通过本教程对 TensorFlow 框架快速入门

    Python 办公自动化教程

    本教程带你使用Python快速操作Excel、Word、PPT,处理各种文件

    Pandas 入门教程

    本教程从基础的数据类型开始到 Pandas 的高级应用一-网打尽

  • 数据库

    MySQL

    MySQL 入门教程

    本教程主要讲解 MySQL 增删改查等基础操作

    SQL 入门教程

    本教程讲解使用 SQL 访问和处理数据系统中的数据的方法。

    MySQL 进阶教程

    那些你还不理解的 MySQL 高阶特性一网打尽

首页 慕课教程 Python 算法入门教程 简单难度贪心算法实战

简单难度贪心算法实战

在 leetcode 上贪心算法相关的编程题比较多,本节以及接下来的一节都会选择使用 leetcode 习题来帮助我们巩固和实战贪心算法。本节会选择一些标签为简单的题目,而在下一节中会选择标签为中级和困难的编程题。

1. 分发饼干

这是 leetcode 上算法部分第 455 题,为简单编程题。题目描述如下:

你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 ii ,都有一个胃口值 $g_i ,ドル这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 jj ,都有一个尺寸 sjs_j 。如果 $s_j >= g_i ,ドル我们可以将这个饼干 jj 分配给孩子 ii ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

注意:你可以假设胃口值为正。一个小朋友最多只能拥有一块饼干。

示例1:

输入: [1,2,3], [1,1]
输出: 1
解释: 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。所以你应该输出1。

示例2:

输入: [1,2], [1,2,3]
输出: 2
解释: 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。你拥有的饼干数量和尺寸都足以让所有孩子满足。所以你应该输出2。

这里的解题思路也是非常清晰的:**同样也是贪心的思路,我们将孩子和饼干的胃口分别从小到大进行排序,从最小的饼干和第一个孩子开始。饼干指针一直向后执行,找到一个饼干满足孩子胃口,则孩子指针向后移动一位,同时满足的孩子数加1,如此执行直到孩子或者饼干的指针走完即可。**这样的一个尽可能最小饼干满足最小胃口的策略其实就是贪心思路。

按照上面的思路,题解第一步就是对孩子的胃口和饼干分别进行排序,从小达到:

g.sort()
s.sort()

接下来就是实现饼干满足小孩,我们分别给小孩的胃口数组、饼干数组设置初始化指针,然后初始化一个满足小孩数的变量:

id1, id2, count = 0, 0, 0

接下来就是遍历饼干数组和移动小孩胃口数组指针。如果饼干尺寸大于等于当前小孩胃口,则满足小孩,count 数加1,同时饼干和小孩胃口数组指针分别后移一位;如果饼干尺寸小于小孩胃口,则只有饼干指针后移一位。如此,直到最后饼干或者小孩的指针指到最后循环结束:

# 循环,当其中一个列表扫描完毕后结束
while id1 < len(g) and id2 < len(s):
 if g[id1] <= s[id2]:
 # 满足孩子,孩子指针+1,同时结果+1
 id1 += 1
 count += 1
 # 饼干指针+1,无论是满足和不满足孩子,都要往后走一位
 id2 += 1

最后我们完整给出实现上述题解的方法,如下:

def findContentChildren(g, s):
 # 使用贪心策略,先排序,最小胃口孩子对应最小能满足的饼干
 g.sort()
 s.sort()
 id1, id2, count = 0, 0, 0
 while id1 < len(g) and id2 < len(s):
 # 一次循环,当其中一个列表扫描完毕后结束
 if g[id1] <= s[id2]:
 # 满足孩子,孩子指针+1,同时结果+1
 id1 += 1
 count += 1
 # 饼干指针+1,无论是满足和不满足孩子,都要往后走一位
 id2 += 1
 return count

2. 柠檬水找零

这是 leetcode 上算法部分第 860 题,为简单编程题。题目描述如下:

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。

注意:一开始你手头没有任何零钱。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

示例1:

输入:[5,5,5,10,20]
输出:true
解释:
前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 true。

示例2:

输入:[5,5,10]
输出:true

示例3:

输入:[10,10]
输出:false

示例4:

输入:[5,5,10,10,20]
输出:false
解释:前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。由于不是每位顾客都得到了正确的找零,所以答案是 false。

看到这题,没啥好说的。首先依次扫描收入的钞,此时会有如下三种情况:

  • 如果收到的是 5 元,直接放入 5 元列表中;
  • 如果收到的是 10 元,看看 5 元列表是否还有剩余;
  • 如果没有 5 元则无法找零,返回 False;
  • 否则找零 5 元,减少一个 5 元列表元素,增加1个10元列表的元素;
  • 对于收到的是 20 元,必须先找 10 元,然后剩下的再找 5 元;

首先定义存放5元和10元的数组,20元不会用于找零,所以不用记录:

remain_5 = []
remain_10 = []

根据上面思路,我们可以简单写以下收到5元和10元的逻辑:

for i in range(len(bills)):
 # 假设遍历第i个钞票
 if bills[i] == 5:
 # 5元钱,直接收入
 remain_5.append(1)
 elif bills[i] == 10:
 # 对于10元找零,只需要找零5元即可
 if not remain_5:
 # 没有5元,直接返回False
 return False
 # 减去一个5元
 remain_5.pop()
 # 加上一个10元
 remain_10.append(1)
 else:
 # 对于20元的处理
 pass

对于20元的处理,我们只需要定义一个找零数:res = 15。首先找零10元,如果有10元,则减去一个10元,同时剩余找零也要减去10:

remain = 15
# 如果有10元,先用一个10元
if len(remain_10) >= 1:
 remain -= 10
 remain_10.pop()

接下来找5元,每找零一个5元,则5元数需要减一,同时剩余找零数也要减去5,,直到 remain_5 数组为空或者 remain<=0 结束:

while len(remain_5) > 0 and remain > 0:
 remain -= 5
 remain_5.pop()

如果能找零,则 remain 最后应该为0,那么我们可以判断,如果剩余的 remain > 0,则表明最后无法找零;否则找零成功

if remain > 0:
 return False

在 20 元找零那里之所以能用贪心思想是因为找零的 15 元减去 10 元正好等于 5 元,如果我先找 5 元则会出现这样的情况:**剩余 2 个 5 元和 1 个 10 元,如果先找 5 元,则有 2 个 5 元,最后的 10 元无法完成找零。**最后整个处理柃檬水找零问题的 Python 方法如下:

def lemonadeChange(bills):
 remain_5 = []
 remain_10 = []
 for i in range(len(bills)):
 if bills[i] == 5:
 # 5元钱,直接收入
 remain_5.append(1)
 elif bills[i] == 10:
 # 10元找零5元
 if not remain_5:
 return False
 remain_5.pop()
 remain_10.append(1)
 else:
 # 对于20元钱找零15元,贪心策略,尽可能找零10元,10元不够在找5元
 remain = 15
 # 如果有10元,先用一个10元
 if len(remain_10) >= 1:
 remain -= 10
 remain_10.pop()
 # 这里存在2种情况,上面找了10元,就剩下5元要找;没有10元,就会一直找5元
 while len(remain_5) > 0 and remain > 0:
 remain -= 5
 remain_5.pop()
 # 如果最后还没找完,且5元数组为空,则无法完成找零,直接返回False
 if remain > 0:
 return False
 # 走到这一步,可以返回True
 return True 

3. 两地调度

这是 leetcode 上算法部分第 1029 题,为简单编程题。题目描述如下:

公司计划面试 2N 人。第 i 人飞往 A 市的费用为 costs[i][0],飞往 B 市的费用为 costs[i][1]。返回将每个人都飞到某座城市的最低费用,要求每个城市都有 N 人抵达。

示例:

输入:[[10,20],[30,200],[400,50],[30,20]]
输出:110
解释:
第一个人去 A 市,费用为 10。
第二个人去 A 市,费用为 30。
第三个人去 B 市,费用为 50。
第四个人去 B 市,费用为 20。
最低总费用为 10 +たす 30 +たす 50 +たす 20 = 110,每个城市都有一半的人在面试。

Tips:

  1. 1 <= costs.length <= 100;
  2. costs.length 为偶数;
  3. 1 <= costs[i][0], costs[i][1] <= 1000

这道题需要认真思考下,对于贪心的算法而言我们要首先确定贪心的值。

我们的值并不是拿去城市的费用值来做贪心,这里要非常注意,因为每个人必须两个城市中选择去一个,如果去了 A 市就不能去 B 市;反之,去了 B 市就不能去 A 市。

可以很容易想到我们贪心的值应该是候选人去 A 市和 B 市花费的差值,接着将列表元素按照相应的差值从小到大进行排列,前 N 个人去 A 市,后 N 个人去 B 市,这便是这道题最精妙的解题思路,是不是很有意思?有了上面的贪心过程,那么 Python 实现便呼之欲出:

def twoCitySchedCost(self, costs):
 min_costs = 0
 N = len(costs) // 2
 # 调用python的排序函数,排序值为相应差值
 costs.sort(key=lambda x:x[0]-x[1])
 # 排序后的前半部分人去A市
 min_costs += sum([costs[i][0] for i in range(N)])
 # 后半部分人去B市
 min_costs += sum(costs[i][1] for i in range(N, 2 * N))
 return min_costs

可以看到,这里算法的时间复杂度为 O(nlogn)O(nlogn),在问题规模 N 非常大时,主要的时间消耗在于快排方法 (sort) 那里。

4. 小结

本小节主要是进行贪心算法实战,在 leetcode 上选择 3 道简单题进行实战训练。这里的题目比较基础,贪心算法运用并不复杂。接下来我们将挑战中级和困难题,进一步应用贪心算法解决题目。

  • 划线
  • 写笔记
  • 复制

0/1000

· 最近更新于 请填写更新时间
使用手机查看
最近更新
向你推荐
更多
索引目录

AltStyle によって変換されたページ (->オリジナル) /