前端面试知识点整理——前端题库1(字节)

前端面试知识点整理——前端题库1(字节)

一、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;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值