2024年Python最全蓝桥杯 ALGO-1004 无聊的逗 01背包+回溯 python,2024年阿里Python高级面试题分享

在这里插入图片描述

感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:

① 2000多本Python电子书(主流和经典的书籍应该都有了)

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

如何理解分割成两个等和的列表子集

为了确定是否能够得出两个等长木棍,我们就看在这些木棍中能否拼出总长度之和的一半这个数来,如果可以,这些木棍就能够分出两条等长的木棍。举个例子, 有4根木棍:4 2 9 2 木棍长度总和是4+2+9+2 = 17 。因为两根木棍长度之和必定是偶数,所以这些木棍要想拼出两根等长木棍是不可能的。但如果木棍长度是 4 2 9 3 长度总和是 18,就要看木棍列表中能否凑出18 / 2 = 9 这个数了。我们一眼望去可以发现,是能够凑出9这个数的,因此 4 2 9 3 这个木棍列表是能够分出两根的等长木棍的。

不知道我说到这里各位同学能否明白这道题的解决思路,如果不明白,我再举个例子。还是以 4 2 9 2 木棍为例,我们知道,这些木棍是不能分出两个等长木棍的。但如果我硬要得出两根等长木棍的最大长度是多少,该怎么办呢? 就要舍弃掉一些木棍了,舍弃谁好呢?我们一眼望去可以发现 舍弃了9后木棍列表变成 4 2 2 是可以凑成两根等长木棍的,木棍的长度是(4+2+2)/ 2 = 4。而4也是在 4 2 9 2 木棍列表中所能找到等长的单根的最大长度,所以4作为结果返回。

说到这里不知道同学们能不能区分开以上整体与部分的关系,如果可以我们继续,否则再倒回上面仔细琢磨一下。

思路

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

现在我们就知道该干啥了,就是要判断木棍列表能否凑出长度之和的一半(sum(Stick_list) / 2)这个数。细心的同学看到前面的两个一眼发现都加粗显示了,因为,可能肉眼看起来容易找到,但如果想告诉电脑该怎么发现并不容易

这里就要使用01背包思路来求解了。01背包是整道题的前置知识点。如果01背包不懂的朋友没关系,@代码随想录 在B站有非常详细的讲解视频,一次看不懂没关系,多看几遍,我也是看了四五遍才懂的,一定要理解每个步骤,理解完后会发现并没有你想的这么难。🔍🔍戳这里进入~

搞清楚01背包后,你会发现,判断木棍列表能否凑出长度之和一半这个数 还是不知道该如何下手。说实话让我想,我也想不出用01背包。

那你会不会说岂不是白学01背包了?当然不是,01背包应用是非常广的,你现在遇不到以后也会遇到,越早学越好。学了01背包,起码是不知道怎么做,如果告诉你思路你就能够做,但你学都没学的话,那跟你说了也不会。

我们看一下力扣这道题,可以说跟我们所要求的东西非常相似。

在这里插入图片描述

📮📮📮虽然我现在知道该怎么做,但我建议你还是跟着视频学好点,如果单纯看文字描述思考的话会比较枯燥而且较难理解。我是看leetcode官方题解视频学会的,也是看了四五遍才懂,所以推荐给大家。 🔑🔑leetcode官方视频题解

在这里插入图片描述

跟着他们学还是挺有意思的。


上面是分割线,当你看到这里的时候我默认当做你已经会了判断木棍列表能否凑出长度之和一半这个数

如果初始的木棍列表能够凑出长度之和一半这个数,那么我们就能直接返回结果。但如果不能的话我们就要在这个列表中删掉一些木棍再来看是否能够分成两根等长木棍,最后在这些可能的情况中返回木棍长度的最大值作为结果。

接着我们思考一下,如何在删掉一些木棍的列表中找出能够分成两根等长木棍的最大长度?

我最开始的思路是使用BFS让木棍列表按字典序由小到大逐步弹出一个元素,每弹一个匹配一次,当第一次匹配到的木棍列表的时候长度必然 (我的想法而已)最大,因为我是按字典序从小到大弹出元素的,每次将小的弹出,再弹大的,那如果找到第一次能够划分等长木棍的列表,应该就是木棍的最大长度了。比如:假设木棍 1 2 3 4 凑不出两根等长的木棍,我的思路就是弹出1 变成 234 然后匹配看234能否凑出等长木棍,不行的话弹出2变成134匹配,不行再弹出3 变成124匹配等等等,然后弹出12 13 14 23 24 34 这样逐个弹出并匹配。

感觉挺完美的,但一提交结果就拿了个50分。想了半天,头发也都快抓没了,就是想不出来,因此我也改了名,我本来叫李帅哥的,哎,说多都是泪。但最后调试打印长度总和的时候终于看到了问题所在。

我们先看个优化前的数据截图

在这里插入图片描述

左边列表是用来判断是否能够拼成两根等长木棍的,右边的那个数是长度总和。注意又是假设啊,假设图中两个红框的列表才能分成两根等长的木棍,那么一定是先出现的列表长度就越大吗?答案是否定的,存有五个数的列表未必会大过存有三个数的列表,可能数多的列表元素值更小。

既然知道了不能够直接返回第一个能够分成两根等长木棍的列表,那么我们就要遍历搜索找出能够分割成等长木棍的最大值了。

我的做法是:先将木棍列表降序排序,之后使用DFS得到木棍列表的每个子集,然后分别判断这个子集能够否分成两根等长的木棍,如果可以,比较得出最大值,最后返回结果,期间需要剪枝

剪枝还是挺有讲究的,没搞好分分钟超时。我们在遍历过程中需要让子集调用一个自定义的函数,这个函数是用来判断列表是否能够分出两根等长木棍的,但如果每有一个子集就要匹配一次的话,会消耗大量资源。因此在调用这个函数前,要进行一个判断:如果此列表总和大于已知的木棍之和最大值,以及这个列表总和是偶数(奇数的话必定不能分成两根等长木棍),才能调用那个函数。让列表降序排序再遍历是因为整体列表长度总和还是由高到低的,这样能较为容易的得到更大值,那么就能直接将子集中更小的值排除,而无需进行函数调用。

接着就是DFS的经典剪枝操作了,如果有数组used用来标记元素是否使用的话,就是,如果这个数使用过,可以直接跳过;如果这个数与前一个数相等且前一个数没有使用过的话,跳过。同时,要有个start标记起始位置,每走一层递归start+1。当然,这里不是排列而是组合(也就是说(2,1),(1,2)存在一个即可)可以不使用used数组,直接+1即可。

如果你看不懂我说的剪枝操作,没关系,做多一点回溯题即可,做多两条你就会发现,这类题型写法总是千变一律啊…

如果你想多了解回溯算法的剪枝思路,我还是推荐你看下@代码随想录的讲解视频,讲的确实不错。

忙乎了一天,终于把这篇文章给写完了,下面我们看下代码实现。

代码实现

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

def canPartition(stick_list):

求木棍列表长度总和

s = sum(stick_list)

如果是奇数不可能分成两根等长木棍

if s % 2 != 0:

return False

我们是要看能否求出列表长度总和的一半这个值,如果可以就能够等分成两根木棍

target = int(s / 2)

length = len(stick_list)

target+1 是要从0开始到target的整个区间

dp = [[False for i in range(target + 1)] for j in range(length)]

if stick_list[0] <= target:

在第0行的对应位置标上能得到stick_list[0]长度的木棍

dp[0][stick_list[0]] = True

套用01背包模板

for i in range(1, length):

for j in range(target + 1):

i-1 区间能拼成那些数 第i个数就能拼成哪些数

dp[i][j] = dp[i - 1][j]

if stick_list[i] < j:

dp[i - 1][j - stick_list[i]] 就是看 有无一个值能够与stick_list[i]凑出j这个数

dp[i][j] = dp[i - 1][j] or dp[i - 1][j - stick_list[i]]

如果等于,表示能够拼出长度为j的木棍

elif stick_list[i] == j:

dp[i][j] = True

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

一、Python所有方向的学习路线

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、学习软件

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

三、全套PDF电子书

书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。

四、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

五、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值