算法题
快速排序的基本思路
找中位数
比较两个数组的中间,剪枝
图如何判环,讲下思路(包括判断是否有环,以及环的路径)
答的时候可以多答一个环的路径
合并区间
算法题:以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
Test case:
[[1,4],[0,2],[3,5]]
[[2,3],[4,5],[6,7],[8,9],[1,10]]
[[1,4],[2,3]]
[[1,4],[4,5]]
*/
数组转树
求一个字符串中,回文字符串个数
回文子串,最长回文子串都是这个套路,注意dp的遍历方向
var countSubstrings = function (s) {
const dp = Array.from({ length: s.length }).map(d => Array.from({ length: s.length }));
let res = 0;
for (let i = s.length - 1; i >= 0; i--) {
for (let j = i; j < s.length; j++) {
if (s[i] === s[j]) {
if (j - i <= 1) {
dp[i][j] = true;
res++;
} else if (dp[i + 1][j - 1]) {
dp[i][j] = true;
res++;
}
}
}
}
return res
};
远程调用api实现加法运算
本机无法实现加法运算,需要请求远程服务。远程有一个 addRemote
的API ,只接受两个参数
实现add方法 const add = async (...args)=>{}
const addRemote = async (a, b) =>
new Promise((resolve) => {
setTimeout(() => resolve(a + b), 1000);
});
const add = async (...args) => {
if (args.length <= 2) {
return addRemote(args[0] || 0, args[1] || 0);
}
const middle = Math.floor(args.length / 2);
const leftArgs = args.slice(0, middle);
const rightArgs = args.slice(middle, args.length);
//递归调用 ,直到返回两个Promise
const leftSumPromise = add(...leftArgs);
const rightSumPromise = add(...rightArgs);
const [leftSum, rightSum] = await Promise.all(
leftSumPromise,
rightSumPromise
);
return addRemote(leftSum, rightSum);
};
删除字符串中出现次数最少的字符
let obj = {};
let res = "";
for (let i = 0; i < str.length; i++) {
if (obj[str[i]]) obj[str[i]]++;
else obj[str[i]] = 1;
}
let min = Math.min(...Object.values(obj));
for (let i = 0; i < str.length; i++) {
if (obj[str[i]] !== min) res += str[i];
}
找出字符串 中不含重复字符的最长子串长度
eg: s = “aaaaaa” , res=1。s=”abcabcbb”, res = 3
注意滑动窗口模版
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
let res = 0;
const set = new Set();
let left = 0;
let right = 0;
let index = 0;
while (right < s.length) {
//扩大右边界
set.add(s.charAt(right));
right++;
//更新结果
res = Math.max(res, right - left);
//这个while判断是否需要收缩左边界
while (set.has(s.charAt(right))) {
//收缩左边界
set.delete(s.charAt(left));
left++;
}
}
return res;
};
背包问题
0-1 背包问题
每个物品只能放一次,在遍历背包容量时从后往前遍历
// 物品:nums
// 背包容量:target
nums.forEach((n) => {
for (let j = target; j <= n; j--) {
dp[j] = Math.max(dp[j], dp[j - n] + n); //1. 求最大价值
dp[j] += dp[j - n]; // 2. 求能装满的组合个数
}
});
完全背包问题
每个物品可以无限放,在遍历背包容量时要从前往后遍历
nums.forEach((n) => {
for (let j = n; j <= target; j++) {
dp[j] = Math.max(dp[j], dp[j - n] + n); //1. 求最大价值
dp[j] += dp[j - n]; // 2. 求能装满的组合个数
}
});
排列和组合问题
将{1,5} 和 {5,1} 视为一种情况的,称为组合;
将{1,5} 和 {5,1} 视为两种情况的,称为排列;
组合问题
先遍历物品,再遍历背包。
这样的话对于对于每一个物品,先把1加入计算,然后再把5加入计算,得到的方法数量只有{1, 5}这种情况。而不会出现{5, 1}的情况。
nums.forEach((n) => {
for (let j = target; j <= n; j--) {
dp[j] += dp[j - n]; //
}
});
排列问题
先遍历背包,再遍历物品
这样的话对于每一个背包容量,{1,5} 和 {5,1} 都会被搜到
因为会这么累加
dp[6] = dp[5] + 1
dp[6] = dp[1] + 5
for (let j = 0; j <= target; j++) {
nums.forEach(n => {
if (n <= j) {
dp[j] += dp[j - n]; // 注意这里也是j
}
});
}