算法题-相加为目标数之和(两数之和、三数之和、从数组中取n个数相加为m(不可重复取)、从数组中取任意个数相加为m(可重复取))
创始人
2025-05-28 13:24:48

目录

相加为目标数之和

题目

两数之和

三数之和

原题链接

解析

核心思想

答案

从数组中取n个数相加为m(不可重复取)

解析 

核心思想

答案

从数组中取任意个数相加为m(可重复取)

解析

核心思想

答案


相加为目标数之和

当为两数、三数之和时,可以通过取出一个数和目标值的差去解决问题,通常会用到hash、双指针等算法去优化题解。

当为多数之和时,我们可以采取递归的方法,把n个数和拆为n-1个数和与剩余的一个数去递归。或者用动态规范的方法,找到res[i]的解和res[i-arr[j]]的关系(j表示的是数组中的每一位)

最后需要注意在求解的时候是否会有重复的解集存在。

题目

两数之和

算法题--哈希(给定差值的组合、最小权重路径解法加步骤)_YF-SOD的博客-CSDN博客

三数之和

给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。

  1. 三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
  2. 解集中不能包含重复的三元组。

示例:给定的数组 S = {-10 0 10 20 -10 -40},解集为(-10, -10, 20),(-10, 0, 10)

输入:[0]

返回值:[]

输入:[0,0,0]

返回值:[[0,0,0]]

输入:[-2,0,1,1,2]

返回值:[[-2,0,2],[-2,1,1]]

输入:[-10,0,10,20,-10,-40]

返回值:[[-10,-10,20],[-10,0,10]]

原题链接

三数之和_牛客题霸_牛客网

解析

注意第二个示例,输入3个零返回的数组中由零构成,上面的不包含重复的三元组是指的数组中的每一位在一个解集中只可以出现1次,但数字时可以相同的。

核心思想

采用双指针的算法,首先固定一位,左右指针从两端开始,向内收紧结束,当有和为固定的数的相反数的加入解集。

固定的这一位从数组0~len-2,双指针一直在固定位的右端,这样能方便计算。

答案

function threeSum(num) {num.sort((a, b) => a - b)let len = num.lengthlet res = []if (len < 3) {return res}for (let i = 0; i < len - 2; i++) {while (num[i] == num[i - 1]) {i++}let left = i + 1, right = len - 1while (left < right) {let sum = num[i] + num[left] + num[right]if (sum === 0) {res.push([num[i], num[left], num[right]])right--left++while (num[left] == num[left - 1]) {left++}while (num[right] == num[right + 1]) {right--}} else if (sum < 0) {left++} else {right--}}}return res
}

从数组中取n个数相加为m(不可重复取)

请用算法实现,从给定的不重复的数组中,取出n个数,使其相加和为m,如:

let arr = [1, 4, 7, 11, 9, 8, 10, 6]
let n = 3
let m = 27
Result:
[[7,11,9],[11,10,6],[9,8,10]]

解析 

注意该题答案不能直接用于上题三数之和,因为给的数组是不重复的,当nums([-2,0,0,2,2],3,0)会返回[[-2,0,2],[-2,0,2]]。得到重复的答案。

核心思想

把n个数和拆为n-1个数和与剩余的一个数。

backtrace(start)表示从start-length-1的nums数组中选n为数和为m。

stack数组中为已经选取了的数。

剩余的这个数可能是每一位,故for循环将数组的每一位放入stack中调用backtrace函数,由于每次将一位放入了数组,故需要取出(这里注意的是递归中每次也会调用push和pop,所以for循环时,最外层每次的stack数组会为空)。

最后寻找出口:当放入stack中的数为n-1时,表示只用寻找一个数了。

答案

function numsSum(nums, n, m) {if (!nums.length || nums.length < n) return [];nums.sort((a, b) => a - b)const result = [];const stack = []const backtrace = (start) => {if (stack.length === n - 1) {const temp = stack.reduce((acc, cur) => acc + cur);if(nums.slice(start).includes(m-temp)){result.push([...stack,m-temp])}return}for (let i = start; i < nums.length; i++) {stack.push(nums[i])backtrace(i + 1)stack.pop()}}backtrace(0)return result
}

从数组中取任意个数相加为m(可重复取)

从数组中选取任意个数的数可以重复相加为target,输出所有的组合,不要求组合中的顺序,

例如[1,2,3],target=4,输出[[1,1,1,1],[1,1,2],[1,3],[2,2]]。

解析

注意是可重复选取,故可能存在重复的解,故最后需要去重。

核心思想

递归:

把n个数和拆为n-1个数和与剩余的一个数。

首先确定入参和出参,入参f(arr,target),出参result数组。

确定上下层级的关系,f(arr,target)=选中的1位和剩下的n-1位返回的result的拼接数组即f(arr,target-arr[i]),i从0~length-1。

找出口,当target-arr[i]===0时,存入result中,大于0时不进行操作。

动态规划:

赋初始值:小于数组中最小值的,res解集为空,

找到res[i]下层之间的关系:res[i]=对数组的每一位进行循环(j),如果res[i-arr[j]]的数组有解就将该解和arr[j]合并,还需要判断右直接等于arr[j]的也加入。

答案

方法一(递归) 

function join(a, arr) {return arr.map(v => {v.push(a)return v})
}
function find(arr, target) {arr = arr.sort((a, b) => a - b).filter(v => v <= target)if (!arr.length) {return;}let result = []for (let i = 0; i < arr.length; i++) {if (target - arr[i] > 0) {result.push(...join(arr[i], find(arr, target - arr[i])))}if (target - arr[i] === 0) {result.push([arr[i]])}}return result
}
let result = find([1, 2, 3, 4], 6)
console.log([...new Set(result.map((v) => v.sort((a, b) => a - b).join('')))].map((v) => v.split('').map(v => Number(v))))

方法二(动态规划) 

function find(arr, target) {function join(a, arr) {return JSON.parse(JSON.stringify(arr)).map(v => {v.push(a)return v})}let result = []arr = arr.sort((a, b) => a - b).filter(v => v <= target)for (let i = 0; i <= target; i++) {if (i < arr[0]) {result[i] = []} else {result[i] = []for (let j = 0; j < arr.length; j++) {if (i>arr[j] && result[i - arr[j]].length) {result[i].push(...join(arr[j], result[i - arr[j]]))}if(i===arr[j]){result[i].push([i])}}}}return [...new Set(result.pop().map((v)=>v.sort((a,b)=>a-b).join('')))].map((v)=>v.split('').map(v=>Number(v)))
}
console.log(find([2,3,4],6))

相关内容

热门资讯

清华大学土木工程系包含哪些专业... 今天给各位分享清华大学土木工程系包含哪些专业的知识,其中也会对清华大学土木工程系包含哪些专业课程进行...
秦国卫鞅怎么死的(卫鞅最后有没... 今天给各位分享秦国卫鞅怎么死的的知识,其中也会对卫鞅最后有没有娶秦国公主进行解释,如果能碰巧解决你现...
美利达车架号(美利达车架号能查... 今天给各位分享美利达车架号的知识,其中也会对美利达车架号能查出什么信息进行解释,如果能碰巧解决你现在...
马杀鸡什么意思(日语马杀鸡什么... 本篇文章极速百科给大家谈谈马杀鸡什么意思,以及日语马杀鸡什么意思对应的知识点,希望对各位有所帮助,不...
一次 JVM 类加载异常 文章目录1. JVM 类加载异常1. 出现问题2. 解决过程1. JDK 7 版本过老2. JDK ...
Button(按钮)与Imag... 今天给大家介绍的Android基本控件中的两个按钮控件,Button普通按钮和ImageButton...
vue子组件无法根据prop属... 问题描述 在vue中,有一个父组件和一个子组件,在父组件里有一个变量&#...
雪佛兰SPARK是什么车?SP... 今天给各位分享雪佛兰SPARK是什么车?SPARK现在还有卖吗的知识,其中也会对2020雪佛兰spa...
全世界最贵的跑车(全世界最贵的... 今天给各位分享全世界最贵的跑车的知识,其中也会对全世界最贵的跑车是啥进行解释,如果能碰巧解决你现在面...
e哥什么意思(e哥是谁啊) e... 今天给各位分享e哥什么意思的知识,其中也会对e哥是谁啊进行解释,如果能碰巧解决你现在面临的问题,别忘...
推荐国内十大品牌润滑油(国内知... 今天给各位分享推荐国内十大品牌润滑油的知识,其中也会对国内知名品牌润滑油进行解释,如果能碰巧解决你现...
前端性能优化之HTTP缓存 前端缓存 前端缓存可分为两大类:HTTP 缓存和浏览器缓存。 我们今天重点是 HTTP...
Linux 端口号占用如何处理 在Linux中,可以使用以下命令来查看端口号的占用情况: sudo ne...
再探pytorch的Datas... 本文从分类、检测、分割三大任务的角度来剖析pytorch得dataset和dataloader源码&...
电影最爱剧情详细介绍,最爱电影... 电影最爱剧情详细介绍目录电影最爱剧情详细介绍最爱电影剧情最爱这部电影讲述的是啥情节电影最爱剧情详细介...
公斤力什么单位(公斤力等于多少... 今天给各位分享公斤力什么单位的知识,其中也会对公斤力等于多少公斤进行解释,如果能碰巧解决你现在面临的...
汽车压缩比是什么意思(汽车压缩... 今天给各位分享汽车压缩比是什么意思的知识,其中也会对汽车压缩比的定义进行解释,如果能碰巧解决你现在面...
小巧实惠又时尚7款市场在售微型... 本篇文章极速百科给大家谈谈小巧实惠又时尚7款市场在售微型电动车,以及微型电动车推荐对应的知识点,希望...
cdn服务器搭建步骤 CDN服务器是现代网络中不可或缺的一部分,其可以大大提高网站的访问速度和用户体验。许多...
Go项目(分布式事务) 文章目录简介分布式事务CAPBASE常见方案 简介 目前,项目的主要代码已经开发完毕&...
leetcode每日一题:45... 系列:贪心算法 语言:java 题目来源:Leetcode...
差速器工作原理是什么(差速器工... 本篇文章极速百科给大家谈谈差速器工作原理是什么,以及差速器工作原理是什么意思对应的知识点,希望对各位...
幸福花园纤细的爱故事内容是什么... 幸福花园纤细的爱故事内容是什么 目录幸福花园纤细的爱故事内容是什么 幸福花园有几部求幸福花园的第二个...
hisuite是什么 ,HiS... hisuite是什么 目录hisuite是什么 HiSuite什么意思?honest是什么意思“hi...
烈火战车刘德华骑的摩托是什么车... 本篇文章极速百科给大家谈谈烈火战车刘德华骑的摩托是什么车是P3还是P4,以及烈火战车中刘德华骑的是什...
Linux命令·diff diff 命令是 linux上非常重要的工具,用于比较文件的内容,特别是...
2021蓝桥杯真题公约数(填空... 题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果...
智能马桶杀菌以及光传感方案 智能马桶杀菌模组,安装在马桶改版底部,实现座垫区域消毒、池内消毒、臀洗喷...
腿玩年是什么意思 ,腿玩年是什... 腿玩年是什么意思 目录腿玩年是什么意思 腿玩年是什么意思玩年腿什么意思啊?腿可玩年是什么意思腿玩年是...
校园yy小说,求校园YY小说 ... 校园yy小说目录校园yy小说求校园YY小说有什么好看的校园YY小说校园yy小说 求校园YY小说校园狂...