前端面试知识点整理——前端题库1(字节)
文章目录
- 一、209.长度最小的子数组
- 二、88.合并两个有序数组
- 三、1.两数之和
- 四、3.无重复字符的最长子串
- 五、53.最大子序和
- 六、112.路径总和
- 七、113.路经总和II
- 八、415.字符串相加
- 九、剑指offer 62.圆圈中最后剩下的数字
- 十、93.复原IP地址
- 十一、160.相交链表
- 十二、695.岛屿的最大面积
- 十三、15.三数之和
- 十四、141.环形链表
- 十五、142.环形链表II
- 十六、206.反转链表
- 十七、215.数组中的第k个最大元素
- 十八、230.二叉搜索树中第K小的元素
- 十九、121.买卖股票的最佳时机
- 二十、146.LRU缓存机制
- 二十一、21.合并两个有序链表
- 二十二、剑指offer 10-I 斐波那契数列
- 二十三、609.在系统中查找重复文件(不会)
- 二十四、232.用栈实现队列
- 二十五、165.比较版本号
- 二十六、104.二叉树的最大深度
- 二十七、102.二叉树的层序遍历
- 二十八、20.有效的括号
- 二十九、129.求根节点到叶结点数字之和
- 三十、226.翻转二叉树
- 三十一、39.组合总和
- 三十二、199.二叉树的右视图
一、209.长度最小的子数组
解法一:暴力解法
时间复杂度:O(n^2)
空间复杂度:O(1)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
if(nums.length == 0) return 0;
int ans = Integer.MAX_VALUE;
for(int i = 0; i < nums.length; i++){
int sum = 0;
for(int j = i;j<nums.length;j++){
sum+=nums[j];
if(sum >= target){
ans = Math.min(ans, j-i +1);
break;
}
}
}
return (ans == Integer.MAX_VALUE) ? 0:ans;
}
}
解法二:前缀和+二分查找
class Solution {
public int minSubArrayLen(int s, int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int ans = Integer.MAX_VALUE;
int[] sums = new int[n + 1];
// 为了方便计算,令 size = n + 1
// sums[0] = 0 意味着前 0 个元素的前缀和为 0
// sums[1] = A[0] 前 1 个元素的前缀和为 A[0]
// 以此类推
for (int i = 1; i <= n; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
//不懂
for (int i = 1; i <= n; i++) {
int target = s + sums[i - 1];
int bound = Arrays.binarySearch(sums, target);
if (bound < 0) {
bound = -bound - 1;
}
if (bound <= n) {
ans = Math.min(ans, bound - (i - 1));
}
}
return ans == Integer.MAX_VALUE ? 0 : ans;
}
}
解法三:滑动窗口
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int ans = Integer.MAX_VALUE;
int start = 0, end = 0;
int sum = 0;
while (end < n) {
sum += nums[end];
while (sum >= target) {
ans = Math.min(ans, end - start + 1);
sum -= nums[start];
start++;
}
end++;
}
return ans == Integer.MAX_VALUE ? 0 : ans;
}
}
二、88.合并两个有序数组
/**
*
* @param A int整型一维数组
* @param B int整型一维数组
* @return void
*/
function merge( A, m, B, n ) {
// write code here
//双指针 从后往前
let index1 = m - 1;
let index2 = n - 1;
let tail = m + n -1;
while(index1 >=0 && index2 >= 0) {
if(A[index1] >= B[index2]) {
A[tail--] = A[index1--];
} else {
A[tail--] = B[index2--];
}
}
while(index1 >= 0){
A[tail--] = A[index1--];
}
while(index2 >= 0){
A[tail--] = B[index2--];
}
return A;
}
module.exports = {
merge : merge
};
/**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
//提取nums1中真实部分
var nums3 = nums1.slice(0, m);
//合并nums3和nums2
var mergeArr = nums3.concat(nums2);
//对mergeArr进行排序
var sortArr = mergeArr.sort(function (a, b) {
return a - b;
})
//直接用nums1 = sortArr不行
for(var i = 0; i< nums1.length; i++){
nums1[i] = sortArr[i];
}
};
三、1.两数之和
var twoSum = function (nums, target) {
//使用哈希表存储已经遍历过的数据 数据->索引
const map = new Map();
map.set(nums[0], 0);
for (let i = 1; i < nums.length; i++) {
let need = target - nums[i];
//map.get(key) 若不存在 返回undefined 存在返回对应的值
if (map.get(need) !== undefined) { //哈希表中存在这样的值
return [map.get(need), i];
}
map.set(nums[i], i);
}
}
四、3.无重复字符的最长子串
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
//用哈希表存储不重复的的字符和对应的索引
let map = new Map();
let max = 0;
//滑动窗口 i为左指针 j为右指针
for (let i = 0, j = 0; j < s.length; j++) {
if (map.has(s[j])) {//重复出现
i = Math.max(map.get(s[j]) + 1, i);
}
max = Math.max(max, j - i + 1);
map.set(s[j], j);
}
console.log(max);
};
lengthOfLongestSubstring("abcabcdebggbsdyujf");
五、53.最大子序和
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function (nums) {
//动态规划算法 前一个元素<0 不加 >0 加
let max = nums[0];
for (let i = 1; i < nums.length; i++) {
if (nums[i - 1] > 0) {
nums[i] += nums[i - 1];
}
max = max > nums[i] ? max : nums[i];
}
console.log(max);
};
maxSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4]); //6
六、112.路径总和
/**
* 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} targetSum
* @return {boolean}
*/
var hasPathSum = function(root, targetSum) {
//当前节点为null节点时
if(root == null) return false;
//当前节点为叶子节点时
if(root.left == null && root.right == null){
return targetSum == root.val;
}
//否则递归左右孩子
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
};
七、113.路经总和II
/**
* 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} targetSum
* @return {number[][]}
*/
var pathSum = function(root, targetSum) {
if(root == null) return [];
let res = [];
let dfs = (root, total, nums) => {
total += root.val;
nums.push(root.val);
if(root.left || root.right){
if(root.left != null){
dfs(root.left, total, nums.slice());
}
if(root.right != null){
dfs(root.right, total, nums.slice());
}
} else if(total == targetSum){
res.push(nums);
}
}
dfs(root, 0, []);
return res;
};
八、415.字符串相加
好像不能用这种方法(大数相加的思路)
/**
* @param {string} num1
* @param {string} num2
* @return {string}
*/
var addStrings = function(num1, num2) {
//把num1、num2转化为数组并反转
let arr1 = num1.split("").reverse();
let arr2 = num2.split("").reverse();
let len1 = arr1.length;
let len2 = arr2.length;
let max = Math.max(len1,len2);
//补0
if(len1 > len2){
for(let i = 0; i < len1 - len2; i++){
arr2.push(0);
}
}else {
for(let i = 0; i < len2 - len1; i++){
arr1.push(0);
}
}
let res = []; //存储相加的值
//初始化
for(let i = 0; i < max; i++){
res[i] = 0;
}
//相加
for(let i = 0; i< max;i++){
res[i] = res[i] + parseInt(arr1[i]) + parseInt(arr2[i]);
if(res[i] > 9){
res[i] = res[i] - 10;
res[i+1] = 1;
}
}
return res.reverse().join("");
};
官方写法:
var addStrings = function(num1, num2) {
//i、j定义目前字符相加位置
let i = num1.length - 1;
let j = num2.length - 1;
//进位
let add = 0;
//存储结果
const res = [];
while (i >= 0 || j >= 0 || add != 0 ) {
//定义两个相加的数 注意字符串相减隐式转换为数字 若字符已经遍历完 则补0
const x = (i >= 0) ? num1.charAt(i) - '0' : 0;
const y = (j >= 0) ? num2.charAt(j) - '0' : 0;
const result = x + y + add;
res.push(result % 10);
add = Math.floor(result / 10);
i--;
j--;
}
return res.reverse().join('');
};
九、剑指offer 62.圆圈中最后剩下的数字
约瑟夫环问题:公式法(迭代)
/**
* @param {number} n
* @param {number} m
* @return {number}
*/
var lastRemaining = function(n, m) {
//公式法 f(n,m) = (f(n-1,m) + m) % n
//开始时f(1) = 0 一个人的位置为0
let f = 0;
for(let i = 2; i <= n; i++){ //迭代
f = (f + m) % i;
}
return f;
};
暴力链表法:无hhhh
十、93.复原IP地址
/**
* @param {string} s
* @return {string[]}
*/
var restoreIpAddresses = function(s) {
//使用回溯算法
const res = []; //存储结果
const segment = new Array(4); //存储一个符合要求的IP地址(四段)
//寻找一个符合的IP地址
//segId表示在找哪一段(0~3)segStart为起始位置
function dfs(s, segId, segStart){
if(segId == 4){ //前面已经找了4段了
if(segStart == s.length){
res.push(segment.join('.')); //加进结果数组
}
return;
}
//如果没找到四段就已经遍历完 提前回溯
if(segStart == s.length){
return;
}
//如果为0 则0必须为单独一段
if(s.charAt(segStart) == '0'){
segment[segId] = 0;
dfs(s, segId + 1, segStart + 1);
}
//普通情况
let addr = 0;
for(let segEnd = segStart; segEnd < s.length; segEnd++){
addr = addr*10 + (s.charAt(segEnd)-'0'); //当前值应满足0~255
if(addr > 0 && addr <= 255){
segment[segId] = addr;
dfs(s, segId + 1, segEnd + 1);
} else {
break;
}
}
}
dfs(s, 0, 0);
return res;
};
十一、160.相交链表
法一:暴力解法
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
//暴力解法
if(!headA || !headB) return null;
let pA = headA;
while(pA){
let pB = headB;
while(pB){
if(pA == pB) return pA;
pB = pB.next;
}
pA = pA.next;
}
};
法二:哈希表法
var getIntersectionNode = function(headA, headB) {
//哈希表法
if(!headA || !headB) return null;
//先遍历A链表并存入哈希表
let pA = headA;
const map = new Map();
while(pA){
map.set(pA,1);
pA = pA.next;
}
//遍历B链表
let pB = headB;
while(pB){
if(map.has(pB)) return pB;
pB = pB.next;
}
return null;
};
法三:双指针
var getIntersectionNode = function(headA, headB) {
//双指针法
if(!headA || !headB) return null;
let pA = headA;
let pB = headB;
while(pA!=pB){
pA = pA === null? headB : pA.next;
pB = pB === null? headA : pB.next;
}
return pA;
};
十二、695.岛屿的最大面积
递归 对每个为1的位置算上下左右 访问过的节点置0
/**
* @param {number[][]} grid
* @return {number}
*/
var maxAreaOfIsland = function(grid) {
let max = 0;
let x = grid.length;
let y = grid[0].length;
for(let i = 0; i < x; i++){
for(let j = 0; j < y; j++){
if(grid[i][j] == 1){
max = Math.max(max, count(grid, i, j, x, y));
}
}
}
return max;
};
function count(grid, i, j, x, y){ //计算上下左右
if(i<0 || i>=x || j<0 || j>=y || grid[i][j]==0) return 0;
let cnt = 1;
grid[i][j] = 0; //防止重复访问节点
cnt += count(grid, i+1, j, x, y);
cnt += count(grid, i-1, j, x, y);
cnt += count(grid, i, j+1, x, y);
cnt += count(grid, i, j-1, x, y);
return cnt;
};
十三、15.三数之和
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
//类似双指针
let ans = [];
let len = nums.length;
//第一步先排序
nums.sort(function(a, b){
return a - b;
});
//遍历数组
for(let i = 0; i < len; i++){
if(nums[i] > 0) break; // nums已排序 后面的也大于零
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{
r--;
}
}
}
return ans;
};
十四、141.环形链表
我用集合(或者哈希表)来做,时间空间O(N)做法
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
let now = head;
const hashSet = new Set(); //let map = new Map();
//遍历
while(now){
if(hashSet.has(now)) return true; //map.has(now)
hashSet.add(now); //map.set(now)
now = now.next;
}
return false;
};
快慢指针法:时间O(N)空间O(1)做法
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
//快慢指针
let fast = head;
let slow = head;
while(fast){
if(fast.next == null) return false; //因为fast是跳两次 所以这里要判断一下
slow = slow.next;
fast = fast.next.next;
if(slow == fast) return true;
}
return false;
};
十五、142.环形链表II
注意这里找的是具体的节点,不仅仅是判断,时间空间和上题一样
哈希表做法:
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
//哈希表做法
let map = new Map();
let curr = head;
while(curr){
if(map.has(curr)) return curr;
map.set(curr,true);
curr = curr.next;
}
return null;
};
快慢指针做法:
var detectCycle = function(head) {
//快慢指针做法
let fast = head;
let slow = head;
while(fast){
if(fast.next == null) return null;
fast = fast.next.next;
slow = slow.next;
if(fast == slow){ //快慢指针相遇 表明存在环
//定义相遇的位置 和 头节点的位置 两者一步一步移动总会相遇
let index1 = fast;
let index2 = head;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
};
十六、206.反转链表
/**
* 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 reverseList = function(head) {
//创建一个空节点
let nullhead = null;
//定义prev、now、 next指针
let prev = nullhead;
let now = head;
while(now != null){
let next = now.next;
now.next = prev;
prev = now;
now = next;
}
return prev;
};
十七、215.数组中的第k个最大元素
法一:暴力法:O(nlogn)
var findKthLargest = function(nums, k) {
//暴力法
nums.sort(function(a,b){
return a - b;
})
return nums[nums.length - k];
};
法二:建立做大堆并删除k-1个,最后取堆顶元素
建堆:O(n)删除O(k-1 logn) 总体O(nlogn)
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function(nums, k) {
//最大堆法
//1.获取堆的大小
let heapSize = nums.length;
//建立最大堆
buildHeap(nums, heapSize);
//删除堆顶k-1个元素
for(let i = nums.length - 1; i > nums.length - k ; i--){
swap(nums, 0, i); //根元素和最后一个元素交换
heapSize--; //堆的大小减一
siftDown(nums, 0, heapSize);
}
//堆顶元素为所求
return nums[0];
};
function buildHeap(nums, heapSize){
//对根元素进行siftDown操作
//吐了 忘了js在这里直接除会有浮点数 向下取整
for(let i = Math.floor(heapSize/2) - 1; i >= 0; i--){
siftDown(nums, i, heapSize);
}
}
function siftDown(nums, i, heapSize){
let largest = i;
let left = 2*i + 1;
let right = 2*i + 2;
if(left < heapSize && nums[largest] < nums[left]) largest = left;
if(right < heapSize && nums[largest] < nums[right]) largest = right;
if(largest != i){
swap(nums, largest, i);
siftDown(nums, largest, heapSize);
}
}
function swap(nums, i, j){
let temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
法三:快速选择 O(n)
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var findKthLargest = function(nums, k) {
//快速选择法
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
};
//返回index对应的值
function quickSelect(nums, l, r, index){
//取得一次划分的轴值下标
let q = partition(nums, l, r);
//比较轴值下标和目标下标 如果相等 返回对应的值
if(q === index) {
return nums[q];
}else {
return q > index ? quickSelect(nums, l, q - 1, index) : quickSelect(nums, q + 1, r, index);
}
}
//返回一次划分的轴值下标
function partition(nums, l, r){
//选择最左值为轴值
let pivot = nums[l];
//把轴值和放到最右
swap(nums, l, r);
//i记录小于轴值的部分下标 j计数遍历
let i = l;
for(let j = l; j < r; j++){
if(nums[j] < pivot){
swap(nums, i, j);
i++;
}
}
//交换轴值和第一个大于轴值的数
swap(nums, i, r);
return i;
}
function swap(nums,i,j){
let temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
十八、230.二叉搜索树中第K小的元素
BST中序遍历可以得到升序结果
法一:递归做法 O(k)
/**
* 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} k
* @return {number}
*/
var kthSmallest = function(root, k) {
//中序遍历 递归
let ans = null;
let inorder = function(node){
if(node != null && k != 0){ //只有当node不为空,才有k--
//左子树
inorder(node.left);
//根(本身)
k--;
if(k == 0){
res = node.val;
return;
}
//右子树
inorder(node.right);
}
};
inorder(root);
return res;
};
法二:迭代(难理解)O(H + K)H为树高
var kthSmallest = function(root, k) {
//中序遍历 迭代
let stack = [];
let node = root;
while(node || stack.length){
//遍历左子树 先存入栈
while(node){
stack.push(node);
node = node.left;
}
// 然后弹出
node = stack.pop();
//此时可以开始计数
k--;
if(k === 0){
return node.val;
}
node = node.right;
}
return null;
};
十九、121.买卖股票的最佳时机
时间:O(n) 空间:O(1)
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
//min存储已遍历的最小值 max存储当前最大利润
let min = prices[0], max = 0;
for(let i = 1; i < prices.length; i++){
min=Math.min(min, prices[i-1]);
max = Math.max(max, prices[i] - min);
}
return max;
};
二十、146.LRU缓存机制
这种方法直接利用了map的可以删除最久的的元素的性质
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
let map = this.map;
if(!map.has(key)) {
return -1;
} else {
//保存键对应的value
const temp = map.get(key);
//删除这个映射
map.delete(key);
//再重新加入
map.set(key, temp);
return temp;
}
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
let map = this.map;
if(map.has(key)){ //存在 先删除原来的再加
map.delete(key);
map.set(key,value);
}else if(map.size == this.capacity) { // 满了
map.delete(map.keys().next().value);
map.set(key,value);
}else { //直接加
map.set(key,value);
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* var obj = new LRUCache(capacity)
* var param_1 = obj.get(key)
* obj.put(key,value)
*/
更通用的做法:(我感觉还是要做一下,但是我现在不想做)
删除O(1)-> 双向链表 自定义数据结构来做
查找:O(1)-> 哈希表
二十一、21.合并两个有序链表
法一:递归做法
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var mergeTwoLists = function(l1, l2) {
//递归做法
if(l1 == null) {
return l2;
} else if(l2 == null) {
return l1;
} else if(l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
};
法二:迭代做法
var mergeTwoLists = function(l1, l2) {
//迭代做法
//先让头节点指向一个-1的结点
const prehead = new ListNode(-1);
//定义prev为未定义next的节点
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;
}
//还有谁没有被检测完
prev.next = l1 === null? l2:l1;
return prehead.next;
};
二十二、剑指offer 10-I 斐波那契数列
/**
* @param {number} n
* @return {number}
*/
var fib = function(n) {
let arr = new Array(n);
arr[0] = 0, arr[1] = 1;
for(let i = 2; i <= n; i++){
arr[i] = (arr[i-1] + arr[i-2]) % 1000000007;
}
return arr[n];
};
二十三、609.在系统中查找重复文件(不会)
/**
* @param {string[]} paths
* @return {string[][]}
*/
var findDuplicate = function(paths) {
let map = new Map();
let ans = [];
for(let p of paths) { //注意for in是遍历index for of是遍历值
let pArr = p.split(' '); //用空格划分 pArr=["root/a","1.txt(abcd)","2.txt(edgh)"]
let pHead = pArr[0]; //"root/a"
for(let i = 1; i < pArr.length; i++){ //从1开始
let curS = pArr[i]; //"1.txt(abcd)"
let s = curS.indexOf('(');
let e = curS.indexOf(')');
let content = curS.slice(s+1, e); //abcd
let path = pHead + '/' + curS.slice(0, s);//"root/a/1.txt"
if(map.has(content)){ //如果已经有了
map.get(content).push(path);
} else {
map.set(content, [path]); //存在数组里
}
}
}
for(let e of map.values()){
if(e.length > 1) { //输出重复的
ans.push(e);
}
}
return ans;
};
二十四、232.用栈实现队列
/**
* Initialize your data structure here.
*/
var MyQueue = function() {
this.stack1 = []; //存放所有数据
this.stack2 = []; //过渡栈
};
/**
* Push element x to the back of queue.
* @param {number} x
* @return {void}
*/
MyQueue.prototype.push = function(x) {
let cur = null;
while(cur = this.stack1.pop()){
this.stack2.push(cur);
}
this.stack2.push(x);
while(cur = this.stack2.pop()){
this.stack1.push(cur);
}
};
/**
* Removes the element from in front of queue and returns that element.
* @return {number}
*/
MyQueue.prototype.pop = function() {
return this.stack1.pop();
};
/**
* Get the front element.
* @return {number}
*/
MyQueue.prototype.peek = function() {
return this.stack1[this.stack1.length-1];
};
/**
* Returns whether the queue is empty.
* @return {boolean}
*/
MyQueue.prototype.empty = function() {
return this.stack1.length === 0;
};
/**
* Your MyQueue object will be instantiated and called as such:
* var obj = new MyQueue()
* obj.push(x)
* var param_2 = obj.pop()
* var param_3 = obj.peek()
* var param_4 = obj.empty()
*/
二十五、165.比较版本号
/**
* @param {string} version1
* @param {string} version2
* @return {number}
*/
var compareVersion = function(version1, version2) {
//把字符串按.分成数组
let arr1 = version1.split('.');
let arr2 = version2.split('.');
//把数组中的字符转换成数字型
arr1 = arr1.map((item) => Number(item));
arr2 = arr2.map((item) => Number(item));
//依次比较这两个数组里面的值
const len = Math.max(arr1.length, arr2.length);
//补0
while(arr1.length < len){
arr1.push(0);
}
while(arr2.length < len){
arr2.push(0);
}
for(let i = 0; i < len; i++){
if(arr1[i] > arr2[i]){
return 1;
}else if(arr1[i] < arr2[i]){
return -1;
}
}
return 0;
};
二十六、104.二叉树的最大深度
/**
* 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;
else{
const left = maxDepth(root.left);
const right = maxDepth(root.right);
return Math.max(left, right) + 1;
}
};
二十七、102.二叉树的层序遍历
O(n)O(n)
/**
* 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 ans = [];
if(root == null) return ans;
//定义一个队列
let queue = [root]; //开始时队列只有根节点
while(queue.length > 0){
let len = queue.length;
let arr = []; //存储一层数据
while(len > 0){ //shift当前层数据并加入下一层
let node = queue.shift();
arr.push(node.val);
if(node.left) queue.push(node.left);
if(node.right) queue.push(node.right);
len--;
}
ans.push(arr);
}
return ans;
};
二十八、20.有效的括号
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function(s) {
//定义一个栈存储相反的符号
let stack = [];
for(let i = 0; i < s.length; i++) {
let c = s.charAt(i);
if(c == '(') {
stack.push(')');
}
else if(c == '{') {
stack.push('}');
}
else if(c == '[') {
stack.push(']');
}
else if (stack.length == 0){
return false;
}
else if(c != stack.pop()){
return false;
}
}
if(stack.length == 0) return true;
else return false;
};
二十九、129.求根节点到叶结点数字之和
/**
* 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}
*/
const dfs = (root, preSum) => {
if(root == null) return 0;
let sum = preSum * 10 + root.val;
if(root.left == null && root.right == null){
return sum;
} else {
return dfs(root.left, sum) + dfs(root.right, sum);
}
}
var sumNumbers = function(root) {
三十、226.翻转二叉树
/**
* 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}
*/
const swap = root => {
//定义结束条件
if(root == null) return;
if(root.left == null && root.right == null) return;
//交换
let node = root.left;
root.left = root.right;
root.right = node;
//递归
swap(root.left);
swap(root.right);
}
var invertTree = function(root) {
swap(root);
return root;
};
三十一、39.组合总和
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum = function(candidates, target) {
let ans = [];
//回溯算法
//target是目标值、combine是当前组合、index是当前索引
const dfs = (target, combine, index) => {
if(index === candidates.length) { //已经遍历完candidates
return;
}
if(target === 0) { //已经找到匹配的组合
ans.push(combine);
return;
}
//情况一:跳过当前值
dfs(target, combine, index + 1);
//情况二:计算当前值
if(target - candidates[index] >= 0){
dfs(target - candidates[index], [...combine, candidates[index]], index);
}
}
dfs(target, [], 0); //从索引为0开始
return ans;
};
三十二、199.二叉树的右视图
竟然自己快速想出来了!!!
/**
* 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 rightSideView = function(root) {
let ans = [];
let map = new Map();
const dfs = (root, height) => {
if(root == null) return;
//首次出现的高度并定是最右的字节点
if(!map.has(height)){
map.set(height, 1);
ans.push(root.val);
}
dfs(root.right, height + 1);
dfs(root.left, height + 1);
}
dfs(root, 1);
return ans;
};