快速排序
/*
** 快速排序的思想
** 以一个元素为目标,找到这个元素所在的正确位置
** 将这个元素左右一分为二(partition),继续在左右找一个元素,对应它的正确位置,直到不能再分位置
** partition的过程就是左边大于val 右边小于val 两个值交换
*/
function fastSort(arr) {
sort(arr, 0, arr.length - 1);
}
function sort(arr, l, r) {
if (l >= r) return;
// 找到某个元素的正确位置
let p = partition(arr, l, r);
sort(arr, l, p - 1);
sort(arr, p + 1, r);
}
/* 找到一个元素l,左边找到大于l,右边找到小于l 交换,直到i>j,
** 此时j就是小于l范围的最右边元素,将l与选定元素交换,此时j就是该元素的正确位置
*/
function partition(arr, l, r) {
let rnd = Math.floor(Math.random() * (r - l)) + l;
wrap(arr, rnd, l);
let i = l + 1;
let j = r;
while (true) {
/*
** i是找到大于val的元素
*/
while (arr[i] < arr[l] && i <= j) {
i++;
}
/*
** j是找到小于val的元素
*/
while (arr[j] > arr[l] && i <= j) {
j--;
}
if (i >= j) break;
swap(arr, i, j);
i++;
j--;
}
wrap(arr, j, l);
return j;
}
function swap(arr, i, j) {
let val = arr[i];
arr[i] = arr[j];
arr[j] = val;
}
双路快速排序的主要思想 O(nlogn)
partition分割过程:随机抽取一个元素,找到该元素的正确排序位置p。
利用递归,在p元素的左边和右边,重复执行partition分割过程
直到不能分割为止。
问题1:为什么要使用随机抽取index的方法,不能直接取第一个元素为基准吗?
直接取第一个元素,对于已经排好序的数组来说,复杂度会变高 O(n*n)。
问题2:如果数组中相等的元素出现的频率很高,使用双路排序法
可以将相等的元素平均分散在左右两边的数组中。
三路快速排序算法
应用场景:当数组中元素重复度较高时,将相等的元素分散在左右两路中,会造成算法的重复执行。
对于完全相等的数组,三路快速排序复杂度是O(n)
所以,三路快速排序的partition是将[l,r]分成小于V、等于V和大于V三部分。
function fastSortThree(arr) {
sort(arr, 0, arr.length - 1);
}
function sort(arr, l, r) {
if (l >= r) return;
// [p,q]之间的元素是已经排好序的
let [p, q] = partition(arr, l, r);
sort(arr, l, p - 1);
sort(arr, q + 1, r);
}
function partition(arr, l, r) {
let rnd = Math.floor(Math.random() * (r - l)) + l;
swap(arr, rnd, l);
// [l+1,lt] 小于val
let lt = l;
// [gt,r] 大于val
let gt = r + 1;
let i = l + 1;
while (i < gt) {
if (arr[i] < arr[l]) {
swap(arr, lt + 1, i);
lt++;
i++;
} else if (arr[i] === arr[l]) {
i++;
} else if (arr[i] > arr[l]) {
swap(arr, gt - 1, i);
gt--;
}
}
swap(arr, l, lt);
return [lt, gt - 1];
}
function swap(arr, i, j) {
let val = arr[i];
arr[i] = arr[j];
arr[j] = val;
}
经典题目:找到第K个最大值 、sort colors
滑动窗口
滑动窗口类问题都有个关键点,就是连续的最长/最短子..
例题:209 寻找和大于等于target的最短连续子数组的长度。
/**
* @param {number} target
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(target, nums) {
// [l,r] 表示滑动窗口的左右位置
let l = 0;
let r = -1;
let sum = 0;
let result = nums.length + 1;
while(l<nums.length){
// 这里要加条件 r+1 < nums.length 否则在没有解的情况下会出现死循环,因为l一直小于nums.length
if(sum < target && r+1 < nums.length){
r++;
sum += nums[r];
} else {
sum -= nums[l];
l++;
}
if(sum >= target){
result = Math.min(result,r-l+1);
}
}
if(result === nums.length + 1) return 0;
return result;
};
例题2:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let arr = s.split('');
let l = 0;
let r = -1;
let result = 0;
while(l<arr.length){
if(!isRepeat(arr.slice(l,r+2)) && r+1 < arr.length){
r++;
} else {
l++;
}
if(!isRepeat(arr.slice(l,r+1))) {
result = Math.max(result,r-l+1);
}
}
return result;
};
function isRepeat(arr){
let arr1 = Array.from(new Set(arr));
if(arr1.length === arr.length) return false;
return true;
}
Set Map
Set是集合 Map是映射。
Set方法:add has clear size delete
Set遍历:forEach keys values
Set是类数组数据结构,Array.from(new Set([1,2,2,5]))数组去重
Set不接受相同的数据,原理是严格等于(===),所以对于对象/数组来说,总是不相等。
Map方法:set get has size delete clear
Map的键值如果是基础类型,则只要判断键值是否相等
如果是引用类型,则判断引用类型的地址是否相等。
let m = new Map([['1',2],['2',3]]);
[...m.keys()]
[...m.values()]
[...m.entries()]
例题1 :给定两个数组 `nums1` 和 `nums2` ,返回 它们的交集 。
输出结果中的每个元素一定是 **唯一** 的。我们可以不考虑输出结果的顺序 。
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
let s1 = new Set();
let s2 = new Set();
nums1.forEach(item=>{
s1.add(item);
})
nums2.forEach(item=>{
if(s1.has(item)){
s2.add(item);
}
})
return Array.from(s2);
};
以上题目不需要考虑重复元素出现的次数,所以不需要记录key的value值,所以可以只用Set就完成。
例题2(350):需要记录重复元素的出现频率 要用Map
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersect = function(nums1, nums2) {
let m1 = new Map();
let res = [];
nums1.forEach(item=>{
if(m1.has(item)){
let count = m1.get(item);
m1.set(item,count+1);
} else {
m1.set(item,1);
}
})
nums2.forEach(item=>{
if(m1.get(item)>0){
res.push(item);
let count = m1.get(item);
m1.set(item,count-1);
}
})
return res;
};
下面这道题的重点在于,是一个无序的数组。如果是有序的数组,我们可以用双指针解决问题。
例题3(1):无序数组,找到和等于target的两个下标。
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
输入: nums = [3,3], target = 6
输出: [0,1]
var twoSum = function (nums, target) {
let m1 = new Map();
// 注意 不要在foreach中返回数据
// 如果是重复key 后面的会覆盖前面的 用一个循环简单的解决问题
nums.forEach((item, index) => {
if (m1.has(item)) {
res = [m1.get(item), index];
} else {
let a = target - item;
m1.set(a, index);
}
});
return res;
};
15.3sum为0--- 双指针和一层循环
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
// 先对数组进行排序
nums.sort((a,b)=>a-b);
// 防止结果数组有重复 [0,0,0,0] [[0,0,0],[0,0,0]]是错误的
let res = new Set();
// 一个for循环 双指针
for(let i=0;i<nums.length;i++){
let left = i + 1;
let right = nums.length - 1;
// 剪枝
if(right - i < 2) break;
while(left<right){
if(nums[i]+nums[left]+nums[right]>0){
right--;
} else if(nums[i]+nums[left]+nums[right]<0){
left++;
} else {
res.add([nums[i],nums[left],nums[right]].join('/'));
// 可能还会存在其他可能性 必须要移动指针 不移动的话就会产生相同的解
left++;
right--;
}
}
}
let result = [];
res.forEach(item=>{
result.push(item.split('/'));
})
return result;
};
#### [16. 最接近的三数之和](https://leetcode.cn/problems/3sum-closest/)
输入: nums = [-1,2,1,-4], target = 1
输出: 2
解释: 与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var threeSumClosest = function(nums, target) {
nums.sort((a,b)=>a-b);
let res = nums[0]+nums[1]+nums[nums.length-1];
for(let i=0;i<nums.length;i++){
let left = i+ 1;
let right = nums.length - 1;
if(right - i < 2) break;
while(left<right){
let sum = nums[i]+nums[left]+nums[right];
if(Math.abs(sum -target) < Math.abs(res -target) ){
res = sum;
}
if(sum > target ){
right--;
} else if(sum < target) {
left++;
} else {
res = sum;
break;
}
}
}
return res;
};
链表
问题1 :206--反转链表
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
// 使用三个指针帮助我们记住数据
let prev = null;
let cur = head;
let next;
while(cur !== null){
// next指针后移问题放在这里 是为了避免取不到next而报错
next = cur.next;
// 这一步是真正的反转操作
cur.next = prev;
// 接下来是指针后移操作
prev = cur;
cur = next;
}
return prev;
};
问题2 :206--删除链表中节点,需要删除的节点只有一个
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var deleteNode = function(head, val) {
let dummyHead = new ListNode(-1);
dummyHead.next = head;
let pre = dummyHead;
let cur = head;
while(cur.val !== val){
pre = cur;
cur = cur.next;
}
pre.next = cur.next;
return dummyHead.next;
};
问题3 :203--删除链表中所有等于val的节点
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var removeElements = function(head, val) {
let dummyHead = new ListNode(-1);
dummyHead.next = head;
let pre = dummyHead;
let cur = head;
while(cur !== null){
if(cur.val === val){
pre.next = cur.next;
cur = cur.next;
} else {
pre = cur;
cur = cur.next;
}
}
return dummyHead.next;
};
问题4 :24. 两两交换链表中的节点
输入: head = [1,2,3,4]
输出: [2,1,4,3]
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var swapPairs = function(head) {
let dummyHead = new ListNode(null);
dummyHead.next = head;
let prev = dummyHead;
while(prev.next && prev.next.next){
let node1 = prev.next;
let node2 = prev.next.next;
let next = node2.next;
prev.next = node2;
node2.next = node1;
node1.next = next;
prev = node1;
}
return dummyHead.next;
};
问题5 :237. 删除链表中的节点(不知道head节点)
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} node
* @return {void} Do not return anything, modify node in-place instead.
*/
var deleteNode = function(node) {
let next = node.next;
node.val = next.val;
node.next = next.next;
};
问题6 :19. 删除链表的倒数第 N 个结点
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let dummyHead = new ListNode(0);
dummyHead.next = head;
let cur = head;
let count = 1;
while(cur.next !== null){
count++;
cur = cur.next;
}
delNode();
return dummyHead.next;
function delNode(){
let prev = dummyHead;
let cur = head;
for(let i=0;i<count-n;i++){
console.log(prev.val,cur.val)
prev = cur;
cur = cur.next;
}
prev.next = cur.next;
}
};
第二种解法:只遍历一遍链表,双指针
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let dummyHead = new ListNode(0);
dummyHead.next = head;
let p = dummyHead;
let q = dummyHead;
for(let i=0;i<=n;i++){
q = q.next;
}
while(q !== null){
p = p.next;
q = q.next;
}
p.next = p.next.next;
return dummyHead.next;
};
队列(解决广度优先遍历)
给你二叉树的根节点 `root` ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
输入: root = [3,9,20,null,null,15,7]
输出: [[3],[9,20],[15,7]]
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
let res = [];
// 存放每层节点 一次存放一层的节点
let q = [];
if(root === null){
return res;
}
q.push(root);
while(q.length!==0){
res.push([]);
let currLevelSize = q.length;
for(let i=0;i<currLevelSize;i++){
// 由于队列先进先出的结构 才能从左到右打印每层树节点
let node = q.shift();
res[res.length-1].push(node.val);
node.left && q.push(node.left);
node.right && q.push(node.right);
}
}
return res;
};
二叉树和递归
[104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/);
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxDepth = function(root) {
if(root === null) return 0;
let leftDepth = maxDepth(root.left);
let rightDepth = maxDepth(root.right);
return Math.max(leftDepth,rightDepth) + 1;
};
[111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/)
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var minDepth = function(root) {
if(root === null) return 0;
let leftDepth = minDepth(root.left);
let rightDepth = minDepth(root.right);
if(root.left === null && root.right === null){
return 1;
}
if(root.left === null){
return rightDepth + 1;
}
if(root.right === null){
return leftDepth + 1;
}
return Math.min(leftDepth,rightDepth) + 1;
};
#### [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/)
给你一棵二叉树的根节点 `root` ,翻转这棵二叉树,并返回其根节点。
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if(root === null) return root;
let left = invertTree(root.left);
let right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
};
# 100 给你两棵二叉树的根节点 `p` 和 `q` ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} p
* @param {TreeNode} q
* @return {boolean}
*/
var isSameTree = function(p, q) {
if(p === null && q === null) return true;
if(p === null || q === null || p.val !== q.val) return false;
if(p.val === q.val) {
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
};
# 101 #### [101. 对称二叉树](https://leetcode.cn/problems/symmetric-tree/)
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isSymmetric = function(root) {
if(root === null) return true;
return loop(root.left,root.right);
};
function loop(left,right){
if(left === null && right === null) return true;
if(left === null || right === null) return false;
if(left.val === right.val) {
return loop(left.left,right.right) && loop(left.right,right.left) ;
} else {
return false;
}
}
# 222 #### [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/)
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var countNodes = function(root) {
if(root === null) return 0;
return loop(root);
};
function loop(root){
let count = 0;
if(!root) return 0;
if(root) count += 1;
if(root.left){
count += loop(root.left);
}
if(root.right){
count += loop(root.right);
}
return count;
}
# 110
递归和回溯
树形结构解决排列问题
17 #### [电话号码的字母组合](https://leetcode.cn/problems/letter-combinations-of-a-phone-number/)
输入: digits = "23"
输出: ["ad","ae","af","bd","be","bf","cd","ce","cf"]
/**
* @param {string} digits
* @return {string[]}
*/
var letterCombinations = function(digits) {
if(!digits) return [];
let res = [];
let s = '';
let m = new Map([['2','abc'],['3','def'],['4','ghi'],['5','jkl'],['6','mno'],['7','pqrs'],['8','tuv'],['9','wxyz']]);
loop(digits,0,s)
// 计算第index位的digits,所计算得到的字符串
function loop(digits,index,s){
if(index === digits.length) {
res.push(s);
return;
}
m.get(digits[index]).split('').forEach(item=>{
loop(digits,index+1,s+item);
})
}
return res;
};
46,47
树形结构解决组合问题
#### [77. 组合](https://leetcode.cn/problems/combinations/)
给定两个整数 `n` 和 `k`,返回范围 `[1, n]` 中所有可能的 `k` 个数的组合。
你可以按 **任何顺序** 返回答案。
/**
* @param {number} n
* @param {number} k
* @return {number[][]}
*/
var combine = function(n, k) {
if(n <=0 || k <= 0 || k>n) return [];
let res = [];
loop(n,k,1,[]);
function loop(n,k,start,p){
// 剪支
if(k - p.length > n - start + 1 ) return;
if(p.length === k){
res.push(p.slice());
return;
}
for(let i=start;i<=n;i++){
p.push(i);
loop(n,k,i+1,p);
// 回溯算法
p.pop();
}
}
return res;
};
动态规划
1.斐波那契数列
方法一:动态规划(自上至下)
/**
* @param {number} n
* @return {number}
*/
var fib = function(n) {
let memo = new Array(n+1);
memo.fill(-1);
memo[0] = 0;
memo[1] = 1;
for(let i=2;i<=n;i++){
memo[i] = (memo[i-1]+memo[i-2])%1000000007;
}
return memo[n];
};
方法二:记忆化搜索法(递归+记忆化搜索)
/**
* @param {number} n
* @return {number}
*/
var fib = function(n) {
let memo = new Array(n+1);
memo.fill(-1);
return loop(n);
function loop(n){
if(n===0) return 0;
if(n===1) return 1;
if(memo[n]!==-1){
return memo[n];
} else {
memo[n] = (loop(n-1)+loop(n-2))%1000000007;
return memo[n];
}
}
};
#### [120. 三角形最小路径和](https://leetcode.cn/problems/triangle/)
输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
输出:11
解释:如下面简图所示:
2
3 4
6 5 7
4 1 8 3
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
方法1:递归和搜索记忆法
/**
* @param {number[][]} triangle
* @return {number}
*/
var minimumTotal = function(triangle) {
let memo = [];
for(let i=0;i<triangle.length;i++){
memo[i] = new Array(triangle[i].length);
memo[i].fill(undefined);
}
return f(0,0);
// f(i,j)表示triangle[0][0]到triangle[i][j]的最小距离
function f(i,j){
if(i === triangle.length) return 0;
if(memo[i][j] !== undefined){
return memo[i][j];
} else {
memo[i][j] = Math.min(f(i+1,j),f(i+1,j+1)) + triangle[i][j];
return memo[i][j];
}
}
};
方法2:动态规划
/**
* @param {number[][]} triangle
* @return {number}
*/
var minimumTotal = function(triangle) {
let n = triangle.length - 1;
let memo = [];
for(let i=0;i<triangle.length;i++){
memo[i] = new Array(triangle[i].length);
memo[i].fill(undefined);
}
memo[n] = triangle[n];
for(let i=n-1;i>=0;i--){
for(let j=0;j<triangle[i].length;j++){
memo[i][j] = Math.min(memo[i+1][j],memo[i+1][j+1]) + triangle[i][j];
}
}
return memo[0,0];
};
#### [64. 最小路径和](https://leetcode.cn/problems/minimum-path-sum/)
输入: grid = [[1,3,1],[1,5,1],[4,2,1]]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
/**
* @param {number[][]} grid
* @return {number}
*/
var minPathSum = function(grid) {
let m = grid.length;
let n = grid[0].length;
let memo = new Array(m);
for(let i=0;i<m;i++){
memo[i] = (new Array(n)).fill(undefined);
}
memo[0][0] = grid[0][0];
return f(m-1,n-1);
function f(i,j){
if(i<0 || j<0) return 0;
if(i===0 && j===0) return grid[0][0];
if(i===0) return f(0,j-1) + grid[0][j];
if(j===0) return f(i-1,0) + grid[i][0];
if(memo[i][j] !==undefined){
return memo[i][j];
} else {
memo[i][j] = Math.min(f(i-1,j),f(i,j-1)) + grid[i][j];
return memo[i][j];
}
}
};
#### [343. 整数拆分](https://leetcode.cn/problems/integer-break/)
方法1:递归和搜索记忆法
/**
* @param {number} n
* @return {number}
*/
var integerBreak = function(n) {
// 需要计算f(n) 所以要创建n+1个数
let memo = new Array(n+1);
memo.fill(-1);
console.log(memo)
return f(n);
// f(n)将n至少分成2部分 返回每个部分的乘积的最大值
function f(n){
if(n === 1) return 1;
if(memo[n]!==-1){
return memo[n];
} else {
let max = -1;
for(let i=1;i<=n-1;i++){
// (n-i)*i表示不再分割 也是一种答案
max = max3(max,(n-i)*i,f(n-i)*i);
}
memo[n] = max;
return memo[n];
}
}
function max3(a,b,c){
return Math.max(Math.max(a,b),c);
}
};
方法2:动态规划
/**
* @param {number} n
* @return {number}
*/
var integerBreak = function(n) {
// 需要计算f(n) 所以要创建n+1个数
let memo = new Array(n+1);
memo.fill(-1);
memo[1] = 1;
for(let i=2;i<=n;i++){
let res = -1;
for(let j=1;j<=i-1;j++){
res = max3(j*(i-j),memo[i-j]*j,res)
}
memo[i] = res;
}
return memo[n];
function max3(a,b,c){
return Math.max(Math.max(a,b),c);
}
};