写的有啥问题请不吝赐教,万分感谢!
1、斐波那契数列
题目:从第3项开始,当前项等于前两项之和: 1 1 2 3 5 8 13 21 ……
,计算第n项的值
输入:20
输出:6765
思路:
1、核心: dp(n) = dp(n-1) + dp(n-2)
2、需求:取需求项的前两位数的和
3、传统做法:遍历数组后,将每次求出的值进行记录,最后根据下标取值
4、低复杂度做法:只记录需要相加的两个值,两个值的和即所求值
// 斐波那契数列,前两数之和为所求位数的值
// 1 1 2 3 5 8 13 21 ....
function fibonacci(n) {
if (n <= 2) return 1
// 一般是声明数组,将每个求得的值记录进去,最后拿索引下标的值,但是这样复杂度太高
// let dp = [1, 1];
// for (let i = 2; i < n; i++) {
// // 求和之后,进行赋值
// dp[i] = dp[i - 1] + dp[i - 2]
// }
// return dp[n - 1]
// 我们所求的值,就是前两位数相加
// dp[n] = dp[n - 1] + dp[n - 2]
// 只需声明两个存储值的变量,用来记录前两位数的值; r -- 代表两数的和
let p1 = 1, p2 = 1, r;
for (let i = 2; i < n; i++) {
// 求和之后,进行赋值
r = p1 + p2;
p1 = p2;
p2 = r;
}
// 返回我们所需要的值
return r;
}
2、两数之和
题目:在数组 [8, 2, 6, 5, 4, 1, 3] 中找出两个数的和为目标数
输入:7
输出:[ [2, 5] , [6, 1] , [4, 3] ]
思路:
1、因为只取两个数的和,不用考虑太多,展示的是无重复项的,所以可以做一步去重操作
2、最简易的就是遍历两次,取当前位置的数 + 后面位置的数 与所需要对比的值 进行比较
3、将符合条件的归纳到一个数组中
4、使用 while 的好处:(注:记得控制条件变量)
(1)、可以在某个条件表达式为真的前提下,循环执行指定的一段代码,直到那个表达式不为真时结束循环。
(2)、复杂度更低
/* 在数组中找出两个数的和为目标数 */
const Arr = [8, 2, 6, 5, 4, 1, 3];
let target = 7;
/** 在数组中找出两个数的和为目标数
* @param arr 数组
* @param data 合计数
*/
function Summation(arr, data) {
let SumData = []
/* 最简易的 复杂度 O(n^2)
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
let sum = arr[i] + arr[j]
if (sum == data) {
SumData.push([arr[i], arr[j]])
}
}
} */
// O(n*m) n--外层循环 m--内层循环 的迭代次数
for (let i = 0; i < arr.length; i++) {
let Nums = arr.length - 1;
while (Nums > i) {
if (arr[i] + arr[Nums] == data) {
SumData.push([arr[i], arr[Nums]])
}
Nums--
}
}
return SumData
}
3、三数之和
题目:找出数组 [5, 2, 1, 1, 3, 4, 6] 中三个数组合后的值 与 传入值相同,且每组数据不能有重复
输入:8
输出:[ [1, 1, 6] , [1, 2, 5] , [1, 3, 4] ]
思路:
1、分析:每一组数据不能有重复的另一组数据
2、将数组进行排序,便于处理数据
(1)、当前选中项与前一项值相同,直接跳过
(2)、拿取的两个值一定是在当前项后面的,且两值的索引不能一致或交叉
(3)、将拿到的三个值合计与需求值对比,大了-右侧索引向左移,小了,左侧索引向右移
(4)、获取符合条件的数据后,分别向右、向左移动,若与前一位数据相同,则继续移动
const Arr = [5, 2, 1, 1, 3, 4, 6];
let target = 8;
/** SummationThreeNum 找出数组中三个数组合后的值 与 传入值相同,且每组数据不能有重复
* @param arr 数组
* @param target 合计数
*/
function SummationThreeNum(arr, target) {
let Result = [];
// 排序 会改变原数组
arr.sort();
for (let i = 0; i < arr.length; i++) {
// 从下标为 1 的开始,如果当前 索引的值 == 前一位的值,则跳出本次循环
// 数组是排过序的,如果当前项的值跟前一项的值一致,则毫无意义
if (i && arr[i] === arr[i - 1]) continue;
// 获取本次循环索引的左侧下一位数的索引
let Left = i + 1;
// 获取本次循环数组最后一位的索引
let Right = arr.length - 1;
// 因为是按照顺序排的,获取的另外两数必须在当前索引的右侧,
//左侧的下位索引必须小于右侧索引,避免两数重合或交叉
while (Left < Right) {
// 计算获取到的三个数
let sum = arr[i] + arr[Left] + arr[Right];
// 当获取的合计数 大于 需求值时,右侧索引下降一位
if (sum > target) {
Right--;
}
// 当获取的合计数 小于 需求值时,左侧索引上升一位
else if (sum < target) {
Left++;
}
// 当获取的合计数 等于 需求值时,将获取的三个数组合成数组,push进大数组中
else {
// n++ 或 n-- 都是先执行原数据,在进行更改值的操作
// ( 如: 先 arr[Left] 再 Left++ )
Result.push([arr[i], arr[Left++], arr[Right--]]);
// 数据索引变更后,后更后索引下标对应的值 == 前一位,则继续往后进一位
while (arr[Left] == arr[Left - 1]) {
Left++;
};
// 数据索引变更后,后更后索引下标对应的值 == 后一位,则继续往前进一位
while (arr[Right] == arr[Right + 1]) {
Right--;
};
};
};
};
return Result;
};