字符串
【数学】大整数加法字符串相加
var addStrings = function(num1, num2) {
let i = num1.length - 1, j = num2.length - 1, add = 0;
const ans = [];
while (i >= 0 || j >= 0 || add != 0) {
const x = i >= 0 ? num1.charAt(i) - '0' : 0;
const y = j >= 0 ? num2.charAt(j) - '0' : 0;
const result = x + y + add;
ans.push(result % 10);
add = Math.floor(result / 10);
i -= 1;
j -= 1;
}
return ans.reverse().join('');
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/add-strings/solution/zi-fu-chuan-xiang-jia-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
678. 有效的括号字符串
var checkValidString = function(s) {
const leftStack = [];
const asteriskStack = [];
const n = s.length;
for (let i = 0; i < n; i++) {
const c = s[i];
if (c === '(') {
leftStack.push(i);
} else if (c === '*') {
asteriskStack.push(i);
} else {
if (leftStack.length) {
leftStack.pop();
} else if (asteriskStack.length) {
asteriskStack.pop();
} else {
return false;
}
}
}
while (leftStack.length && asteriskStack.length) {
const leftIndex = leftStack.pop();
const asteriskIndex = asteriskStack.pop();
if (leftIndex > asteriskIndex) {
return false;
}
}
return leftStack.length === 0;
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/valid-parenthesis-string/solution/you-xiao-de-gua-hao-zi-fu-chuan-by-leetc-osi3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
数组
数组中的第K个最大元素
思路:快速排序
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function(nums, k) {
const length = nums.length;
const targetIndex = k - 1;
let left = 0;
let right = length - 1;
while (left < right) {
let index = partition(left, right, nums);
if (index === targetIndex) {
return nums[index];
}
else if (index > targetIndex) {
right = index - 1;
} else {
left = index + 1;
}
}
return nums[left];
};
var partition = function (start, end, nums) {
let povit = nums[start];
while (start < end) {
while (start < end && nums[end] <= povit) {
end--
}
nums[start] = nums[end];
while (start < end && nums[start] > povit) {
start++;
}
nums[end] = nums[start];
}
nums[start] = povit;
return start;
}
最大子数组和
/**
* @param {number[]} nums
* @return {number}
*/
let maxSubArray = function(nums) {
let max =nums[0];
let pre = 0;
for (const num of nums) {
if (pre > 0) {
pre += num;
} else {
pre = num;
}
max = Math.max(max, pre);
}
return max;
}
FED5 全排列
// 补全代码
const _permute = string => {
if(string.length === 1) {
return [string]
}
const results = []
for(let s of string){
const arr = string.split('').filter(str =>str !== s)
_permute(arr.join('')).forEach(item => {
results.push(s + item)
})
}
return results
}
2-sum(数组中查找两数之和为K的序列对)两数之和
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let map = new Map();
for (let i = 0; i < nums.length; i++) {
if (map.has(target - nums[i])) {
return [map.get(target - nums[i]), i];
} else {
map.set(nums[i], i)
}
}
return [];
}
三数之和
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
let ans = [];
const len = nums.length;
if(nums == null || len < 3) return ans;
nums.sort((a, b) => a - b); // 排序
for (let i = 0; i < len ; i++) {
if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
let L = i+1;
let R = len-1;
while(L < R){
const sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.push([nums[i],nums[L],nums[R]]);
while (L<R && nums[L] == nums[L+1]) L++; // 去重
while (L<R && nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
};
作者:guanpengchn
链接:https://leetcode-cn.com/problems/3sum/solution/hua-jie-suan-fa-15-san-shu-zhi-he-by-guanpengchn/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
麦乐鸡块问题
问题:在一个平行宇宙中,麦当劳的麦乐鸡块分为 7 块装、13 块装和 29 块装。有一天,你的老板让你出去购买正好为 n 块(0 < n <= 10000)的麦乐鸡块回来,请提供一个算法判断是否可行。
const checkNuggets = (nuggets) => {
let temp = []
temp[7] = true
temp[13]-= true
temp[29] = true
for (let i = 7; i < nuggets; i+= 1) {
if (temp[i]) {
temp[i + 7] = true
temp[i + 13] = true
temp[i + 29] = true
} else continue
}
return !!temp[nuggets]
}
console.log(checkNuggets(25)) // false
console.log(checkNuggets(26)) // true
console.log(checkNuggets(27)) // true
console.log(checkNuggets(28)) // true
console.log(checkNuggets(29)) // true
console.log(checkNuggets(30)) // false
链表
剑指 Offer 24. 反转链表
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
let prev = null;
let curr = head;
while(curr) {
let next = curr.next;
curr.next = prev;
pre = curr;
curr = next;
}
return prev;
};
链表求和
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
let carry = 0;
let node = new ListNode(null);
let p = node;
while(true) {
var val = (l1 ? l1.val : 0) + carry + (l2 ? l2.val : 0);
carry = Math.floor(val / 10);
val = val % 10;
p.next = new ListNode(val);
p = p.next;
if (l1) l1 = l1.next;
if (l2) l2 = l2.next;
if (!l1 && !l2 && !carry) break
}
return node.next
};
传送门:链表求和
剑指 Offer 22. 链表中倒数第k个节点
var getKthFromEnd = function(head, k) {
let node = head, n = 0;
while (node) {
node = node.next;
n++;
}
node = head;
for (let i = 0; i < n - k; i++) {
node = node.next;
}
return node;
};
21. 合并两个有序链表
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;
};
二叉树
236. 二叉树的最近公共祖先
var lowestCommonAncestor = function(root, p, q) {
let ans;
const dfs = (root, p, q) => {
if (root === null) return false;
const lson = dfs(root.left, p, q);
const rson = dfs(root.right, p, q);
if ((lson && rson) || ((root.val === p.val || root.val === q.val) && (lson || rson))) {
ans = root;
}
return lson || rson || (root.val === p.val || root.val === q.val);
}
dfs(root, p, q);
return ans;
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/solution/er-cha-shu-de-zui-jin-gong-gong-zu-xian-by-leetc-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 34. 二叉树中和为某一值的路径
/**
* 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
* @param {number} target
* @return {number[][]}
*/
var pathSum = function(root, target) {
let res = [];
var backtrack = function (root, path, sum) {
if (root === null) return null;
path.push(root.val);
sum += root.val;
if (root.left === null && root.right === null && sum === target) res.push(path.slice());
backtrack(root.left, path, sum);
backtrack(root.right, path, sum);
path.pop();
}
backtrack(root, [], 0);
return res;
};
112. 路径总和
const hasPathSum = (root, sum) => {
if (root == null) { // 遍历到null节点
return false;
}
if (root.left == null && root.right == null) { // 遍历到叶子节点
return sum - root.val == 0; // 如果满足这个就返回true。否则返回false
}
// 不是上面的情况,则拆成两个子树的问题,其中一个true了就行
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
剑指 Offer 39. 数组中出现次数超过一半的数字
- 哈希表
- 排序取众数 时间复杂度:O(n\log n)O(nlogn)空间复杂度:O(\log n)O(logn)
- 摩尔投票法(最优)
/**
* @param {number[]} nums
* @return {number}
*/
var majorityElement = function(nums) {
let count = 0;
let num = 0;
for (let i = 0; i < nums.length; i++) {
if (!count) {
num = nums[i];
count++;
} else {
count += num === nums[i] ? 1 : -1;
}
}
return num
};
剑指 Offer 55 - I. 二叉树的深度
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxDepth = function(root) {
if (root === null) return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
};
时间复杂度 O(N)O(N) : NN 为树的节点数量,计算树的深度需要遍历所有节点。 空间复杂度 O(N)O(N) : 最差情况下(当树退化为链表时),递归深度可达到 NN 。
124. 二叉树中的最大路径和
/**
* 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 maxPathSum = function(root) {
let maxSum = Number.MIN_SAFE_INTEGER;
const dfs = function (root) {
if (root == null) return 0
let left = dfs(root.left);
let right = dfs(root.right);
let innerMaxSum = left + root.val + right;
maxSum = Math.max(innerMaxSum, maxSum);
let outputMaxSum = root.val + Math.max(0, left, right);
return outputMaxSum > 0 ? outputMaxSum : 0;
}
dfs(root);
return maxSum;
};
传送门:「手画图解」别纠结递归的细节 | 124.二叉树中的最大路径和
蛇形打印二叉树 103. 二叉树的锯齿形层序遍历
var zigzagLevelOrder = function(root) {
if (!root) {
return [];
}
const ans = [];
const nodeQueue = [root];
let isOrderLeft = true;
while (nodeQueue.length) {
let levelList = [];
const size = nodeQueue.length;
for (let i = 0; i < size; ++i) {
const node = nodeQueue.shift();
if (isOrderLeft) {
levelList.push(node.val);
} else {
levelList.unshift(node.val);
}
if (node.left !== null) {
nodeQueue.push(node.left);
}
if (node.right !== null) {
nodeQueue.push(node.right);
}
}
ans.push(levelList);
isOrderLeft = !isOrderLeft;
}
return ans;
};
时间复杂度:O(N)O(N),其中 NN 为二叉树的节点数。每个节点会且仅会被遍历一次。
空间复杂度:O(N)O(N)。我们需要维护存储节点的队列和存储节点值的双端队列,空间复杂度为 O(N)O(N)。
作者:LeetCode-Solution 链接:leetcode-cn.com/problems/bi… 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
二叉树的右视图
DFS
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var rightSideView = function(root) {
if(!root) return []
let arr = []
dfs(root, 0, arr)
return arr
};
function dfs (root, step, res) {
if(root){
if(res.length === step){
res.push(root.val) // 当数组长度等于当前 深度 时, 把当前的值加入数组
}
// console.log(step, '-------', res)
dfs(root.right, step + 1, res) // 先从右边开始, 当右边没了, 再轮到左边
dfs(root.left, step + 1, res)
}
}
作者:shetia
链接:https://leetcode-cn.com/problems/binary-tree-right-side-view/solution/shen-du-you-xian-sou-suo-by-shetia-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
BFS
var rightSideView = function(root) {
if(!root) return []
let queue = [root] // 队列 把树顶加入队列
let arr = [] // 用来存储每层最后个元素值
while(queue.length > 0){
let len = queue.length
while (len) {
let node = queue.shift() // 取出队列第一个元素
if(len === 1) arr.push(node.val) // 当是 当前一层的最后一个元素时,把值加入arr
if(node.left) queue.push(node.left) // 继续往队列添加元素
if(node.right) queue.push(node.right)
len--
}
}
return arr
};
作者:shetia
链接:https://leetcode-cn.com/problems/binary-tree-right-side-view/solution/shen-du-you-xian-sou-suo-by-shetia-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
动态规划
爬楼梯
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
let p = 0;
let q = 0;
let r = 1;
for (let i = 1; i <= n; i++) {
p = q;
q = r;
r = p + q;
}
return r
};
进制
剑指 Offer 15. 二进制中1的个数
var hammingWeight = function(n) {
let ret = 0;
for (let i = 0; i < 32; i++) {
if ((n & (1 << i)) !== 0) {
ret++;
}
}
return ret;
};
时间复杂度:O(k)O(k),其中 kk 是 \texttt{int}int 型的二进制位数,k=32k=32。我们需要检查 nn 的二进制位的每一位,一共需要检查 3232 位。
空间复杂度:O(1)O(1),我们只需要常数的空间保存若干变量。
作者:LeetCode-Solution 链接:leetcode-cn.com/problems/er… 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
var hammingWeight = function(n) {
let ret = 0;
while (n) {
n &= n - 1;
ret++;
}
return ret;
};
时间复杂度:O(\log n)O(logn)。循环次数等于 nn 的二进制位中 11 的个数,最坏情况下 nn 的二进制位全部为 11。我们需要循环 \log nlogn 次。
空间复杂度:O(1)O(1),我们只需要常数的空间保存若干变量。
最大交换
矩阵
54. 螺旋矩阵
var spiralOrder = function(matrix) {
if (!matrix.length || !matrix[0].length) {
return [];
}
const rows = matrix.length, columns = matrix[0].length;
const order = [];
let left = 0, right = columns - 1, top = 0, bottom = rows - 1;
while (left <= right && top <= bottom) {
for (let column = left; column <= right; column++) {
order.push(matrix[top][column]);
}
for (let row = top + 1; row <= bottom; row++) {
order.push(matrix[row][right]);
}
if (left < right && top < bottom) {
for (let column = right - 1; column > left; column--) {
order.push(matrix[bottom][column]);
}
for (let row = bottom; row > top; row--) {
order.push(matrix[row][left]);
}
}
[left, right, top, bottom] = [left + 1, right - 1, top + 1, bottom - 1];
}
return order;
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析
时间复杂度:O(mn)O(mn),其中 mm 和 nn 分别是输入矩阵的行数和列数。矩阵中的每个元素都要被访问一次。
空间复杂度:O(1)O(1)。除了输出数组以外,空间复杂度是常数。
509. 斐波那契数
var fib = function(n) {
if (n < 2) {
return n;
}
let p = 0, q = 0, r = 1;
for (let i = 2; i <= n; i++) {
p = q;
q = r;
r = p + q;
}
return r;
};