数组
快速排序
function quickSort(arr, left, right) {
if (left >= right) return
const base = arr[left]
let p = left, q = right
while (p < q) {
while (arr[q] > base && q >= p) {
q--
}
while (arr[p] < base && p <= q) {
p++
}
const temp = arr[q]
arr[q] = arr[p]
arr[p] = temp
}
arr[p] = base
quickSort(arr, left, p)
quickSort(arr, p + 1, right)
}
归并排序
function mergeSort(arr) {
if (arr.length <= 1) return arr
const mid = Math.floor(arr.length / 2)
const left = arr.slice(0, mid)
const right = arr.slice(mid)
const leftArr = mergeSort(left)
const rightArr = mergeSort(right)
const result = []
while (leftArr.length > 0 && rightArr.length > 0) {
if (leftArr[0] < rightArr[0]) {
result.push(leftArr.shift())
} else {
result.push(rightArr.shift())
}
}
return result.concat(leftArr).concat(rightArr)
}
两数之和
var twoSum = function (nums, target) {
let hash = {};
for (let i = 0; i < nums.length; i++) {
if (hash[target - nums[i]] !== undefined) {
return [i, hash[target - nums[i]]];
}
hash[nums[i]] = i;
}
return [];
};
三数之和
var threeSum = function(nums) {
const len = nums.length;
if(len < 3) return [];
nums.sort((a, b) => a - b);
const resSet = new Set();
for(let i = 0; i < len - 2; i++) {
if(nums[i] > 0) break;
let l = i + 1, r = len - 1;
while(l < r) {
const sum = nums[i] + nums[l] + nums[r];
if(sum < 0) { l++; continue };
if(sum > 0) { r--; continue };
resSet.add(`${nums[i]},${nums[l]},${nums[r]}`);
l++;
r--;
}
}
return Array.from(resSet).map(i => i.split(","));
};
二分查找
var search = function(nums, target) {
let left = 0, right = nums.length - 1;
// 使用左闭右闭区间
while (left <= right) {
let mid = left + Math.floor((right - left)/2);
if (nums[mid] > target) {
right = mid - 1; // 去左面闭区间寻找
} else if (nums[mid] < target) {
left = mid + 1; // 去右面闭区间寻找
} else {
return mid;
}
}
return -1;
};
螺旋矩阵遍历
var generateMatrix = function(n) {
let startX = startY = 0; // 起始位置
let loop = Math.floor(n/2); // 旋转圈数
let mid = Math.floor(n/2); // 中间位置
let offset = 1; // 控制每一层填充元素个数
let count = 1; // 更新填充数字
let res = new Array(n).fill(0).map(() => new Array(n).fill(0));
while (loop--) {
let row = startX, col = startY;
// 上行从左到右(左闭右开)
for (; col < startY + n - offset; col++) {
res[row][col] = count++;
}
// 右列从上到下(左闭右开)
for (; row < startX + n - offset; row++) {
res[row][col] = count++;
}
// 下行从右到左(左闭右开)
for (; col > startX; col--) {
res[row][col] = count++;
}
// 左列做下到上(左闭右开)
for (; row > startY; row--) {
res[row][col] = count++;
}
// 更新起始位置
startX++;
startY++;
// 更新offset
offset += 2;
}
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
if (n % 2 === 1) {
res[mid][mid] = count;
}
return res;
};
合并两个有序数组
var merge = function(nums1, m, nums2, n) {
let p1 = m - 1, p2 = n - 1;
let tail = m + n - 1;
var cur;
while (p1 >= 0 || p2 >= 0) {
if (p1 === -1) {
cur = nums2[p2--];
} else if (p2 === -1) {
cur = nums1[p1--];
} else if (nums1[p1] > nums2[p2]) {
cur = nums1[p1--];
} else {
cur = nums2[p2--];
}
nums1[tail--] = cur;
}
};
随机排序
function shuffle(arr) {
var i, j, temp;
for (i = arr.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
// 这个实现有问题
function shuffle(arr){
return arr.sort(function(){
return Math.random() - 0.5;
});
}
字符串
两数之和
var addStrings = function (num1, num2) {
const result = []
let p = num1.length - 1
let q = num2.length - 1
let add = 0
while (p >= 0 || q >= 0 || add) {
const x = p >= 0 ? Number(num1[p]) : 0
const y = q >= 0 ? Number(num2[q]) : 0
const sum = x + y + add
result.unshift(sum % 10)
add = Math.floor(sum / 10)
p--
q--
}
return result.join('')
};
千分符格式化
var thousandSeparator = function(n) {
let res = ''
let count = 0
const str = n.toString()
const len = str.length
for(let i = len - 1; i >= 0; i--) {
count++
if (count % 3 === 0 && i !== 0) {
res = '.' + str[i] + res
} else {
res = str[i] + res
}
}
return res
};
有效括号
var isValid = function(s) {
const n = s.length;
if (n % 2 === 1) {
return false;
}
const pairs = new Map([
[')', '('],
[']', '['],
['}', '{']
]);
const stk = [];
for (let ch of s){
if (pairs.has(ch)) {
if (!stk.length || stk[stk.length - 1] !== pairs.get(ch)) {
return false;
}
stk.pop();
}
else {
stk.push(ch);
}
};
return !stk.length;
};
链表
反转链表
var reverseList = function(head) {
let pre = null
let cur = head
while(cur !== null) {
const temp = cur.next
cur.next = pre
pre = cur
cur = temp
}
return pre
};
删除链表倒数第N个结点
var removeNthFromEnd = function(head, n) {
let ret = new ListNode()
ret.next = head
let p = ret, q = ret
// p 先前进N
while(n--) {
p = p.next
}
// p 遍历到尾结点
while(p.next !== null) {
p = p.next
q = q.next
}
q.next = q.next.next
return ret.next
};
合并两个有序链表
var mergeTwoLists = function(l1, l2) {
const prehead = new ListNode(-1);
let prev = prehead;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
prev.next = l1;
l1 = l1.next;
} else {
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev.next = l1 === null ? l2 : l1;
return prehead.next;
};
二叉树
深度优先遍历(递归和迭代)
// 递归
var preorderTraversal = function(root) {
let res=[];
const dfs=function(root){
if(root===null)return ;
//先序遍历所以从父节点开始
res.push(root.val);
//递归左子树
dfs(root.left);
//递归右子树
dfs(root.right);
}
//只使用一个参数 使用闭包进行存储结果
dfs(root);
return res;
};
// 迭代
var preorderTraversal = function(root, res = []) {
if(!root) return res;
const stack = [root];
let cur = null;
while(stack.length) {
cur = stack.pop();
res.push(cur.val);
cur.right && stack.push(cur.right);
cur.left && stack.push(cur.left);
}
return res;
};
层次遍历
var levelOrder = function(root) {
//二叉树的层序遍历
let res=[],queue=[];
queue.push(root);
if(root===null){
return res;
}
while(queue.length!==0){
// 记录当前层级节点数
let length=queue.length;
//存放每一层的节点
let curLevel=[];
for(let i=0;i
最大深度
var maxdepth = function(root) {
if (!root) return root
return 1 + math.max(maxdepth(root.left), maxdepth(root.right))
};
最近公共祖先
var lowestCommonAncestor = function(root, p, q) {
// 使用递归的方法
// 需要从下到上,所以使用后序遍历
// 1. 确定递归的函数
const travelTree = function(root,p,q) {
// 2. 确定递归终止条件
if(root === null || root === p||root === q) {
return root;
}
// 3. 确定递归单层逻辑
let left = travelTree(root.left,p,q);
let right = travelTree(root.right,p,q);
if(left !== null&&right !== null) {
return root;
}
if(left ===null) {
return right;
}
return left;
}
return travelTree(root,p,q);
};
对称二叉树
var isSymmetric = function(root) {
//使用递归遍历左右子树 递归三部曲
// 1. 确定递归的参数 root.left root.right和返回值true false
const compareNode=function(left,right){
//2. 确定终止条件 空的情况
if(left===null&&right!==null||left!==null&&right===null){
return false;
}else if(left===null&&right===null){
return true;
}else if(left.val!==right.val){
return false;
}
//3. 确定单层递归逻辑
let outSide=compareNode(left.left,right.right);
let inSide=compareNode(left.right,right.left);
return outSide&&inSide;
}
if(root===null){
return true;
}
return compareNode(root.left,root.right);
};
动态规划
最长重复子数组
// 输入: A: [1,2,3,2,1] B: [3,2,1,4,7] 输出:3 解释: 长度最长的公共子数组是 [3, 2, 1] 。
const findLength = (A, B) => {
// A、B数组的长度
const [m, n] = [A.length, B.length];
// dp数组初始化,都初始化为0
const dp = new Array(m + 1).fill(0).map(x => new Array(n + 1).fill(0));
// 初始化最大长度为0
let res = 0;
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
// 遇到A[i - 1] === B[j - 1],则更新dp数组
if (A[i - 1] === B[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
// 更新res
res = dp[i][j] > res ? dp[i][j] : res;
}
}
// 遍历完成,返回res
return res;
};
最长公共子序列
// 输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace",它的长度为 3。
const longestCommonSubsequence = (text1, text2) => {
let dp = Array.from(Array(text1.length+1), () => Array(text2.length+1).fill(0));
for(let i = 1; i <= text1.length; i++) {
for(let j = 1; j <= text2.length; j++) {
if(text1[i-1] === text2[j-1]) {
dp[i][j] = dp[i-1][j-1] +1;;
} else {
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1])
}
}
}
return dp[text1.length][text2.length];
};
最长连续递增序列
const findLengthOfLCIS = (nums) => {
let dp = Array(nums.length).fill(1);
for(let i = 0; i < nums.length - 1; i++) {
if(nums[i+1] > nums[i]) {
dp[i+1] = dp[i]+ 1;
}
}
return Math.max(...dp);
};
最大回文子串
var longestPalindrome = function (s) {
const len = s.length
if (len < 2) return s
let max = 0
let str = s[0]
const dp = Array.from(new Array(len), () => new Array(len))
for(let j=0; j< len; j++) {
for(let i=0; i max) {
max = j - i + 1
str = s.substring(i, j+1)
}
}
}
return str
}
最长回文子序列
const longestPalindromeSubseq = (s) => {
const strLen = s.length;
let dp = Array.from(Array(strLen), () => Array(strLen).fill(0));
for(let i = 0; i < strLen; i++) {
dp[i][i] = 1;
}
for(let i = strLen - 1; i >= 0; i--) {
for(let j = i + 1; j < strLen; j++) {
if(s[i] === s[j]) {
dp[i][j] = dp[i+1][j-1] + 2;
} else {
dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);
}
}
}
return dp[0][strLen - 1];
};
无重复子数组最大长度 (滑动窗口)
function sub(arr) {
let max = 0
let base = 0
const has = new Map()
for(let i = 0; i < arr.length; i++) {
const cur = arr[i]
if (hash.hash(cur)) {
base = Math.max(base, has.get(cur) + 1)
}
hast.set(cur, i)
max = Math.max(max, i - base + 1)
}
return max
}
子数组乘积最大
function largestSum(arr) {
let max = Number.MIN_SAFE_INTEGER, fmin = arr[0], fmax= arr[0]
for(let num of arr) {
if (num < 0) {
const temp = fmax
fmax = fmin
fmin = temp
}
fmin = Math.min(fmin*num, num)
fmax = Math.max(fmax*num, num)
max = Math.max(max, fmax)
}
return max
}
最小费用
function minCount(days, cost) {
const len = days.length
let maxDay = days[len - 1], minDay = days[0]
let dp = new Array(maxDay + 31).fill(0)
for(let d = maxDay, i = len -1; d >= minDay; d-- ) {
if (days[i] === d) {
dp[d] = Math.min(dp[d + 1] + cost[0], dp[d+7] + cost[1], dp[d+30]+cost[2])
i--
} else {
dp[d] = dp[d+1]
}
}
return dp[minDay]
}