Skip to content

Latest commit

 

History

History
82 lines (58 loc) · 2.23 KB

39.组合总和.md

File metadata and controls

82 lines (58 loc) · 2.23 KB

组合总和

解题思路

1、条件解读

  • 数字是可以被重复选择来进行组合的
  • 数字可以单独是本身的组合
  • candidate 中的每个元素都是独一无二的
  • 1 <= target <= 500
  • 1 <= candidates.length <= 30
  • 1 <= candidates[i] <= 200

2、初步解读的处理

判断元素与目标值的大小,由于元素大于零,适当的处理三种情况

  • 小于目标值:不符合条件,但后续还会用到
  • 大于目标值:不符合条件,且后续再也不会用到
  • 等于目标值:符合条件,且后续不会再用到

3、小于目标值数字处理

这里就到了一个组合的场景了,大致会有一下几种情况

  • 单个元素重复拼合
  • 多个不同的元素拼合
  • 有部分重复元素与其他部分或非重复元素拼合

4、查找方案

单次遍历会引申出多个遍历,需要确保运行没有遗漏也没有重复

方案:

  • 为了使得单次查找有效性提高,可以将有效元素的数组先进行排序

  • 由于元素会不断的前后遍历,前面部分在遍历后,后面部分无需再和前面部分拼装,避免重复

  • 如何开始查找? 从单个数字开始,而后下级以最小的开始多级遍历,如:第一组查找为多个最小数组的组合

  • 单个数字查找到何种程度结束遍历? 正常结束:下级所有元素都遍历完,则单个数字结束 理论结束:若当前数字与下级元素之后大于目标值,则后续所有的下级元素无需继续遍历

优化

1、前置判断

数组元素前置判断,该判断在不合格的元素居多时收益才会较大,因此可以去除

// 数组元素前置判断
for (let i = 0; i < candidates.length; i++) {
  const item = candidates[i];
  if (item < target) {
  } else if (item === target) {
    results.push(candidates.splice(i--, 1));
  } else {
    candidates.splice(i--, 1);
  }
}

2、代码优雅程度优化 减少代码量

const comb = (start, sum, arr) => {
  /* code */
  comb(index, nextSum, arr.concat(combItem));
  /* code */
};
comb(0, 0, []);

疑问

1、函数传入 candidates 与在上层作用域查找 candidates 的优缺点 传入 candidates 读取会更快? 传入 candidates 内存消耗会变多?