我是如何将贪心算法一步一步优化到88%+59%(1)

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例1

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

示例2

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

二、思路分析

=========================================================================

  • 熟悉笔者的应该了解之前分享了多篇的动态规划算法了,此题如果通过动态规划来解决的话有个痛点–二维

  • 什么叫二维呢?之前我们在动态规划中机器人寻址也是二维的。为什么那里可以通过动态规划来实现呢?

  • 首先我们来回顾下机器人走路图示 , 我们当前状态(i,j)和上面两种状态是有关联的且这种关联我们是可以通过方程进行描述的

  • 但是将同样的布局放置到分饼干中就有点麻烦了。首先我们当前状态(i,j)并不一定来资源(i-1,j)或者(i,j-1)。

  • 我们这样理解下:当孩子g固定时,s块饼干可能可以分配给m个孩子(m<g) 。 随着饼干的增加并不确定m会不会增加。因为饼干的大小是未知的。

  • 所以动态规划在分饼干中就有点捉襟见肘了。针对本题贪心算法就很合适 。 贪心算法的本质就是局部最优来实现问题的解决

  • 贪心算法和动态规划不同的是前者是通过正向推进来实现问题解决的。在动态规划中是需要通过前一状态来决定当前状态的。而贪心算法是不考虑之前状态的。只考虑当前自己状态。总结一句话就是贪心算法只保证自己当前问题的解决不靠别人

image-20210524142935535

贪心分析


  • 既然采用贪心算法,那么我们就得确定贪心的策略这点和动归确定转移方程是一样的。首先我们需要将孩子和饼干进行排序排序规则按胃口值从小到大。

  • 因为我们需要知道有多少孩子能够被满足所以我们已孩子为主体进行扩展。

  • 我们在g[i]是需要在s中找到大于当前孩子胃口值的饼干的最小值。为什么需要最小值呢?

  • 上图中我们将满足情况的最小的饼干分配给当前孩子,那么下一个饼干也满足条件可以继续分配给下一个孩子

  • 但是如果我们不是将满足条件的最小饼干分配出去,最坏的情况就会出现前一个饼干无法满足下一个孩子

三、AC 代码

==========================================================================

初版


  • 基于上面的分析我们可以给出如下的代码。下面就是将排序后的饼干最小满足情况分配给当前孩子这样能尽可能多的满足更多的孩子

  • 里面有些边界情况我们需要判断下,因为是已孩子为主体循环的不会产生数组越界的情况。但是饼干数组会出现数组越界,下面的if判断就是防止数组越界

public int findContentChildren(int[] g, int[] s) {

if (s.length == 0) {

return 0;

}

Arrays.sort(g);

Arrays.sort(s);

int sIndex = 0;

int total = 0;

for (int i = 0; i < g.length; i++) {

if (sIndex >= s.length) {

return total;

}

while (g[i] > s[sIndex]) {

sIndex++;

if (sIndex >= s.length) {

return total;

}

}

sIndex++;

total++;

}

return total;

}

  • 结果并不是很满意

升级1


  • 上面执行速度和内存消耗都不大理想 。 其实我们可以避免掉上面的数组越界的情况从而减少我们判断在执行内存上应该会有不少提升的。

  • 我们仔细观察下,对于g(i)来说他对应饼干s(j)存在如下关系i>=j 。所以我们优化之后看看代码

public int findContentChildren(int[] g, int[] s) {

Arrays.sort(g);

Arrays.sort(s);

int total = 0;

for (int i = 0; i < g.length; i++) {

for (int j = i; j < s.length; j++) {

if (s[j] >= g[i]) {

//为了下次在被别的孩子比较,这里置为-1,就不会分配给任何孩子

s[j] = -1;

total++;

break;

}

}

}

return total;

}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

言尽于此,完结

无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。

  • 第一,设计模式能让专业人之间交流方便,如下:

程序员A:这里我用了XXX设计模式

程序员B:那我大致了解你程序的设计思路了

  • 第二,易维护

项目经理:今天客户有这样一个需求…

程序员:明白了,这里我使用了XXX设计模式,所以改起来很快

  • 第三,设计模式是编程经验的总结

程序员A:B,你怎么想到要这样去构建你的代码

程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题

  • 第四,学习设计模式并不是必须的

程序员A:B,你这段代码使用的是XXX设计模式对吗?

程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的

image

从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!

image

搜集费时费力,能看到此处的都是真爱!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!

[外链图片转存中…(img-v6eJHDKF-1713691276126)]

搜集费时费力,能看到此处的都是真爱!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 17
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值