想进某电商公司?建议学会电商 sku 的全排列算法!
前言
前段时间在掘金看到一个热帖 《今天又懒得加班了,能写出这两个算法吗?带你去电商公司写商品中心》,里面提到了一个比较有意思故事,大意就是一个看似比较简单的电商 sku 的全排列组合算法,但是却有好多人没能顺利写出来。有一个毕业生小伙子在面试的时候给出了思路,但是进去以后还是没写出来,羞愧跑路~
其实排列组合是一个很经典的算法,也是对递归回溯法的一个实践运用,本篇文章就以带你学习一个标准「排列组合求解模板」,耐心看完,你会有更多收获。
需求
需求描述起来很简单,有这样三个数组:
let names = ["iPhone X", "iPhone XS"]let colors = ["黑色", "白色"]let storages = ["64g", "256g"]
需要把他们的所有组合穷举出来,最终得到这样一个数组:
;[["iPhone X", "黑色", "64g"],["iPhone X", "黑色", "256g"],["iPhone X", "白色", "64g"],["iPhone X", "白色", "256g"],["iPhone XS", "黑色", "64g"],["iPhone XS", "黑色", "256g"],["iPhone XS", "白色", "64g"],["iPhone XS", "白色", "256g"],
]
由于这些属性数组是不定项的,所以不能简单的用三重的暴力循环来求解了。
思路
如果我们选用递归回溯法来解决这个问题,那么最重要的问题就是设计我们的递归函数。
思路分解
以上文所举的例子来说,比如我们目前的属性数组就是:names
、colors
、storages
,首先我们会处理 names
数组,很显然对于每个属性数组,都需要去遍历它,然后一个一个选择后再去和 下一个数组的每一项进行组合。
我们设计的递归函数接受两个参数:
index
对应当前正在处理的下标,是names
还是colors
或是storage
。prev
上一次递归已经拼接成的结果,比如['iPhone X', '黑色']
。
进入递归函数:
处理属性数组的下标
0
:假设我们在第一次循环中选择了iPhone XS
,那此时我们有一个未完成的结果状态,假设我们叫它prev
,此时prev = ['iPhone XS']
。处理属性数组的下标
1
:那么就处理到colors
数组的了,并且我们拥有prev
,在遍历colors
的时候继续递归的去把prev
拼接成prev.concat(color)
,也就是['iPhone XS', '黑色']
这样继续把这个prev
交给下一次递归。处理属性数组的下标
2
:那么就处理到storages
数组的了,并且我们拥有了name + color
的prev
,在遍历storages
的时候继续递归的去把prev
拼接成prev.concat(storage)
,也就是['iPhone XS', '黑色', '64g']
,并且此时我们发现处理的属性数组下标已经到达了末尾,那么就放入全局的结果变量res
中,作为一个结果。
编码实现
let names = ["iPhone X", "iPhone XS"]let colors = ["黑色", "白色"]let storages = ["64g", "256g"]let combine = function (...chunks) {let res = []let helper = function (chunkIndex, prev) {let chunk = chunks[chunkIndex]let isLast = chunkIndex === chunks.length - 1for (let val of chunk) {let cur = prev.concat(val)if (isLast) {// 如果已经处理到数组的最后一项了 则把拼接的结果放入返回值中res.push(cur)} else {helper(chunkIndex + 1, cur)}}}// 从属性数组下标为 0 开始处理// 并且此时的 prev 是个空数组helper(0, [])return res
}console.log(combine(names, colors, storages))
递归树图
画出以 iPhone X
这一项为起点的递归树图,当然这个问题是一个多个根节点的树,请自行脑补 iPhone XS
为起点的树,子结构是一模一样的。
万能模板
为什么说这种接法是排列组合的「万能模板呢」?来看一下 LeetCode 上的 77. 组合 问题,这是一道难度为 medium
的问题,其实算是比较有难度的问题了:
问题
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],
]
解答
let combine = function (n, k) {let ret = []let helper = (start, prev) => {let len = prev.lengthif (len === k) {ret.push(prev)return}for (let i = start; i <= n; i++) {helper(i + 1, prev.concat(i))}}helper(1, [])return ret
}
可以看出这题和我们求解电商排列组合的代码竟然如此相似。只需要设计一个接受 start
排列起始位置、prev
上一次拼接结果为参数的递归 helper
函数,
然后对于每一个起点下标 start
,先拼接上 start
位置对应的值,再不断的再以其他剩余的下标作为起点去做下一次拼接。当 prev
这个中间状态的拼接数组到达题目的要求长度 k
后,就放入结果数组中。
剪枝
在这个解法中,有一些递归分支是明显不可能获取到结果的,我们每次递归都会循环到 不停的尝试 <= n
的所有项,尝试作为start
,假设我们要求的数组长度 k = 3
,最大值 n = 4
。
而我们以 prev = [1]
,再去以 n = 4
为 start
作为递归的起点,那么显然是不可能得到结果的,因为 n = 4
的话就只剩下 4
这一项可以拼接了,最多也就拼接成 [1, 4]
,不可能满足 k = 3
的条件。
所以在进入递归之前,就果断的把这些“废枝”给减掉。
let combine = function (n, k) {let ret = []let helper = (start, prev) => {let len = prev.lengthif (len === k) {ret.push(prev)return}// 还有 rest 个位置待填补let rest = k - prev.lengthfor (let i = start; i <= n; i++) {if (n - i + 1 < rest) {continue}helper(i + 1, prev.concat(i))}}helper(1, [])return ret
}
相似题型
当然,力扣中可以套用这个模板的相似题型还有很多,而且大多数难度都是 medium
的,比如快手的面试题子集 II-90,可以看出排列组合的递归解法还是有一定的难度的。
我在维护的 LeetCode 题解仓库 中已经按标签筛选好 「递归与回溯」类型的几道题目和解答了,感兴趣的小伙伴也可以一起攻破它们。
总结
排列组合问题并不是空中楼阁,在实际工作中也会经常遇到这种场景,掌握了递归回溯的标准模板当然不是为了让你死记硬背套公式,而是真正的理解它。遇到需要递归解决的问题。
画出递归树状图,找出递归公式。
对于不可能达成条件的分支递归,进行合理的「剪枝」。
希望阅读完本篇文章的你,能对递归和排列组合问题有进一步的理解和收获。
最后
我是黑叔,关注我,跑得更快噢!
亲,点这涨工资
想进某电商公司?建议学会电商 sku 的全排列算法!相关推荐
- 前端电商 sku 的全排列算法
前端电商 sku 的全排列算法 什么是sku 聊聊常见的需求 解决思路 思路分解 上代码 什么是sku 针对电商而言: 1.SKU是指一款商品,每款都有出现一个SKU,便于电商品牌识别商品. 2.一款 ...
- 前端电商 SKU 的全排列算法很难吗?学会这个套路,彻底掌握排列组合。
前言 前段时间在掘金看到一个热帖 <今天又懒得加班了,能写出这两个算法吗?带你去电商公司写商品中心>,里面提到了一个比较有意思故事,大意就是一个看似比较简单的电商 sku 的全排列组合算法 ...
- 【转载】前端电商 sku 的全排列算法
需求 需求描述起来很简单,有这样三个数组: let names = ["iPhone X", "iPhone XS"] let colors = [" ...
- 本想制衡经销商价格,不料成为黄牛货源地!茅台电商公司被迫解散!
说起白酒中的贵族,一定要谈到茅台,茅台是世界三大名酒之一,许久以来,茅台成为了人们口中的白酒奢侈品,有许多人买茅台并不是为了喝,而是为了送礼或者收藏,甚至是屯着等涨价再卖出去,变成了一个理财产品. 因 ...
- 程序员想进大公司?学会这门编程知识,决定你能进什么样的企业!
对于程序员来讲,很多技术真正掌握之后,都能影响甚至说改变一个人的命运,比如:python.AI.DL.算法等等,但是如果只让你选择其中的一项基础知识,你会选择哪个呢? 如果是我, 我会选--数据结构与 ...
- 亚马逊——不一样的电商公司
其一: 电商公司就是电子商务公司.电子商务通俗的说就是利用电子工具进行各种商务活动,如网上购物.在线电子支付等.可以说电子商务是传统商业活动的电子化和网络化.离我们最近的就是网购了,通常我们会在淘宝. ...
- 奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些并发编程核心技能是你必须要掌握的!!(建议收藏)
大家好,我是冰河~~ 最近有很多学弟学妹问我:冰河,并发编程要学哪些内容呀?我看你CSDN博客的的[精通高并发系列]更新了很多高并发编程的技术文章,你是怎么学习的呢?后面你还会更新吗?啥时候更新完呀? ...
- OKR分解/360对齐的方法详解-电商公司
这篇文章从「公司级OKR」[部门级OKR][个人级OKR]出发,涉及到销售部门.研发部门.CSM部门以及相关的职能部门参与其中,以理论方法 + 案例的形式,介绍OKR的分解和360对齐,阅读时间约5m ...
- 初创跨境电商公司,让Callnovo的海外客服成为您出海的桨
蓝牙耳机跨境出海大促当天销售额有8万美金! 下单率竟然超89%! 好评率100%,还有买家洋洋洒洒写长文好评信,他们是怎么做到的? 让我们来看一看这篇好评信,到底写了些什么. 从顾客的反馈中,可以看到 ...
最新文章
- 爬虫之 lxml模块的安装与使用示例
- 信号建模与参数估计作业重新计算
- 2020年下信息系统项目管理师合格分数线通知
- CRMEB后台前端文档说明
- C语言学习之输入任意年份,判断是否为闰年
- 使用ImpromptuInterface反射方便的创建自定义DfaGraphWriter
- 1043 幸运号码 数位DP
- 智力问答 46倒计时
- 论文赏析[ACL18]基于RNN和动态规划的线性时间成分句法分析
- Windows 系统软件有哪些「必备」软件?
- Tuple和 ValueTuple
- Android 视频直播 ( 从快播到直播,从高清到无码 )十年视频开发项目
- 千兆路由器和百兆路由器
- 一根竹子,4天的生长过程
- 从零开始学GIMP:一.从基本图形开始
- 诛仙账号合并服务器,《诛仙3》10/17 服务器数据互通公告
- 关于六边形地图的生成算法
- Python(17)python使用tkinter实现一个简单的CSGO幸运转盘抽奖游戏
- IntelliJ idea (最新版)激活方法
- select2 新增全选功能