算法200

90 阅读16分钟
670. 最大交换

给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。

var maximumSwap = function(num) {
    const numArr = num.toString().split('')
    const lastArr = Array(10).fill(-1);

    // 存储每个数字的位置
    for(let i = 0;i<numArr.length;i++){
        lastArr[numArr[i]] = i
    }
    for(let i=0;i<numArr.length;i++){
        // 比当前值大 且位置在当前值后边      遍历9- numarr【ℹ️】 就是找 比他大的数
        for(let j=9;j>numArr[i];j--){
            if(lastArr[j]>i){
                // 交换是交换位置 lastArr[j] 才是j的位置 并不是j
                [numArr[i], numArr[lastArr[j]]] = [numArr[lastArr[j]], numArr[i]]
                return Number(numArr.join(''))
            }
        }
    }
    return num;
};
1305. 两棵二叉搜索树中的所有元素
var getAllElements = function(root1, root2) {
    let arr1=[],arr2=[], result=[]

    function getValue(root, arr){
        if(!root)return;
        root.left&&getValue(root.left, arr)
        arr.push(root.val)
        root.right&&getValue(root.right, arr)
    }

    getValue(root1,arr1)
    getValue(root2,arr2)
    while (arr1.length&&arr2.length){
        if(arr1[0]<arr2[0]){
            result.push(arr1.shift())
        }else {
            result.push(arr2.shift())
        }
    }
    return [...result, ...arr1,...arr2]
};
1013. 将数组分成和相等的三个部分

给你一个整数数组 arr,只有可以将其划分为三个和相等的 非空 部分时才返回 true,否则返回 false

var canThreePartsEqualSum = function(arr) {
    let totalSum = arr.reduce((a,b)=>a+b)
    // 首先看总和能不能被3整除
    if(totalSum%3!==0) return  false;
    // 每一块的值
    let partSum = totalSum/3
    let sum = 0, parts = 0;
    for(let num of arr){
        sum +=num;
        if(sum === partSum){
            parts++;
            sum =0;
        }
        // 如果计算两部分  后一部分基本可以确定的 但是如果是 [-1,1,-1,1]这种会有问题 也可以当作一个优化项
        if(parts === 3)return true;
    }
    return false;
};
25. K 个一组翻转链表

给你链表的头节点 head ,每 k **个节点一组进行翻转,请你返回修改后的链表。

var reverseKGroup = function(head, k) {
    let currentNode = head;
    let count = 0;
    // 计数检查是否有足够的节点进行下一次翻转
    while (currentNode != null && count != k) {
        currentNode = currentNode.next;
        count++;
    }
    // 如果有足够的节点进行翻转
    if (count == k) {
        // 翻转这 k 个节点
        currentNode = reverseKGroup(currentNode, k); // 翻转剩余部分,并将结果连接到当前部分
        while (count-- > 0) { // 翻转当前 k 个节点
            let temp = head.next; // 临时保存下一个节点
            head.next = currentNode; // 将当前节点的 next 指向翻转的剩余部分
            currentNode = head; // 将 currentNode 移动到当前节点
            head = temp; // 移动 head 到下一个节点
        }
        head = currentNode;
    }
    return head;
};
674. 最长连续递增序列

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

var findLengthOfLCIS = function(arr) {


    if (arr.length === 0) return 0;

    let maxLen = 1;
    let currentLen = 1;

    for (let i = 1; i < arr.length; i++) {
        if (arr[i] > arr[i - 1]) {
            currentLen++;
            maxLen = Math.max(maxLen, currentLen);
        } else {
            currentLen = 1;
        }
    }
    return maxLen;
};
300. 最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

// 以下是动态规划解决此问题的步骤:
//
// 初始化一个数组 dp 与输入数组 nums 长度相同,每个元素的值为 1。因为最长上升子序列的最小长度为 1(即包含数组本身的每个单独元素)。
// 对于数组中的每个元素 nums[i],遍历 i 之前的所有元素 nums[j](其中 j < i)。
// 如果找到一个元素 nums[j] 比 nums[i] 小,这意味着可以在以 nums[j] 结尾的子序列后追加 nums[i],因此更新 dp[i] 为 dp[j] + 1,如果这会使 dp[i] 更大的话。
// 遍历完成后,数组 dp 中的最大值即为最长上升子序列的长度。
var lengthOfLIS = function(nums) {
    const dep = Array.from({length:nums.length}).fill(1)
    let result = 0
    for(let i=0;i<nums.length;i++){
        for(let j=0;j<i;j++){
            if(nums[i]>nums[j]){
                // 可以不连续 上升就可以
                dep[i] = Math.max(dep[i],dep[j]+1)
            }
        }
        result = Math.max(result,dep[i])
    }
    return result;
};
198. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

var rob = function(nums) {
    // 一家都没有 返回0
    if(nums.length==0)return 0;
    if(nums.length ==1)return nums[0]
    // 动态规划   只有一家 只有两家的情况
    let dep = [nums[0], Math.max(nums[0],nums[1])];
    for(let i=2;i<nums.length;i++){
        // 每一家如果偷 得到钱的情况 就是这一家加上这家的上上家 如果不偷就是前一家 偷了得到的钱 ****
        dep[i] = Math.max(dep[i-1],dep[i-2]+nums[i])
    }
    return dep.pop()
};
384. 打乱数组
/**
 * @param {number[]} nums
 */
var Solution = function(nums) {
    this.original = nums.slice();  // 保存原始数组的副本
    this.array = nums;
};

/**
 * Resets the array to its original configuration and return it.
 * @return {number[]}
 */
Solution.prototype.reset = function() {
    this.array = this.original.slice(); // 恢复原始数组的副本
    return this.array;
};

/**
 * Returns a random shuffling of the array.
 * @return {number[]}
 */
Solution.prototype.shuffle = function() {
    for (let i = 0; i < this.array.length; i++) {
        let rand = Math.floor(Math.random() * (i + 1)); // 随机选择一个小于或等于 i 的索引
        // 交换当前元素和随机选择的元素
        [this.array[i], this.array[rand]] = [this.array[rand], this.array[i]];
    }
    return this.array;
};
154. 寻找旋转排序数组中的最小值 II
var findMin = function(nums) {
    // 升序螺旋 如果旋转了  旋转点一定小于前一个值;如果旋转后和原来一样  第一个就是最小值
    for(let i =1;i<nums.length;i++){
       if(nums[i]<nums[i-1]){
           return nums[i]
       }
    }
    return nums[0]
};
402. 移掉 K 位数字

给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k **位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。

var removeKdigits = function(num, k) {
    let stack = []
    for(let step of num){
        // 如果后边的值比前面的值小就 用后边的值把前面的值删除掉;  删除掉k个之后不再删除
        while(stack.length>0&&k>0&&stack.slice(-1)>step){
            stack.pop()
            k--;
        }
        stack.push(step)
    }
    // 如果上边没删完 删除后边的
    while (k>0){
        stack.pop()
        k--
    }
    // 如果第一个值是0的情况处理下
    while (stack[0] == '0'){
        stack.shift()
    }
    return stack.join('')||'0'
};
287. 寻找重复数
var findDuplicate = function(nums) {
    let low = 1;
    let high = nums.length - 1;

    while (low < high) {
        const mid = Math.floor((low + high) / 2);
        let count = 0;

        // 计算数组中有多少个数小于等于 mid
        nums.forEach((num) => {
            if (num <= mid) {
                count++;
            }
        });

        // 根据抽屉原理缩小搜索范围
        if (count > mid) {
            high = mid;
        } else {
            low = mid + 1;
        }
    }

    // low 和 high 相遇的地方就是重复的数字
    return low;
};
3. 无重复字符的最长子串
var lengthOfLongestSubstring = function(s) {
     let l = 0; // 定义左指针
            let r=0
            let res = 0; // 结果
            let map = new Map(); // 存放字符和对应下标
            let len = s.length
            while (r<len) {
                if (map.has(s[r]) && map.get(s[r]) >= l) {
                    l = map.get(s[r]) + 1;
                }
                res = Math.max(res, r - l + 1); // 计算结果
                map.set(s[r], r); // 存下每个字符的下标
                r++
            }
            return res;

};
93. 复原 IP 地址

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

var restoreIpAddresses = function(s) {
    const ret = [];

    // 判断是否0开头 或者大于255;0开头转成数字给去掉
    const isValid = (str) => {
        const num = parseInt(str, 10);
        if(num > 255) return false;
        return str == ''+num; // 验证 '0' 前导的情况
    };

    const backtracking = (s, startIndex, path) => {
        if (path.length === 4 && startIndex === s.length) {
            ret.push(path.join('.'));
            return;
        }

        if (path.length === 4 && startIndex < s.length) {
            return;
        }

        // 循环三次 三位数
        for (let i = 1; i <= 3; i++) {
            if (startIndex + i > s.length) return;
            const substring = s.substring(startIndex, startIndex + i);
            if (isValid(substring)) {
                path.push(substring);
                backtracking(s, startIndex + i, path);
                path.pop();
            }
        }
    };

    backtracking(s, 0, []);
    return ret;
};
22. 括号生成
var generateParenthesis = function(n) {

        let result = [];
        bracket(n,n,'');
        return result;
        // lNum表示剩余可用的左括号数量,rNum表示剩余可用的右括号数量, item表示当前已经使用的括号组成的字符串
        function bracket(lNum, rNum, item){
            if(lNum==0&&rNum==0){
                result.push(JSON.parse(JSON.stringify(item)));
                return;
            }

            if(lNum>0){
                item += '(';
                bracket(lNum-1, rNum,item);
                item = item.substring(0,item.length-1);
            }
            // 只有剩余的右括号数量大于剩余的左括号数量时,才能添加右括号
            if(rNum>0 && rNum>lNum){
                item += ')';
                bracket(lNum, rNum-1,item);
            }
        }

};
142. 环形链表 II
var detectCycle = function(head) {
  let fast = head, slow = head;

  do{
    //检查是否有环 + 寻找相遇点 encounter point
    if(!fast || !fast.next) return null;
    fast = fast.next.next
    slow = slow.next
  }while(fast != slow)


  fast = head;

  //寻找入口 entrance
  //为什么这能寻找入口,请看下图
  while(fast != slow){
    fast = fast.next
    slow = slow.next
  }

  return fast;
    
};
42. 接雨水
var trap = function(height) {
    let left = 0;
    let right = height.length-1;
    let leftMax = 0
    let rightMax = 0
    let result = 0;
    while (left<right){
        // 哪边低从哪边开始
        if(height[left]<height[right]){
            if(height[left]>leftMax){
                leftMax = height[left]
            }else{
                result +=(leftMax - height[left])
            }
            left ++
        }else{
            if(height[right]> rightMax){
                rightMax = height[right]
            }else {
                result +=(rightMax - height[right])
            }
            right--;
        }
    }
    return result;
};
121. 买卖股票的最佳时机
var maxProfit = function(prices) {
    // 买入最大值  初始化时候
    let inPrice = Number.MAX_VALUE;
    let result = 0;
    for(let i= 0; i<prices.length;i++){
        if(inPrice>prices[i]){
            inPrice = prices[i]
        }
        result = Math.max(result, prices[i]-inPrice)
    }
    return result
};
130. 被围绕的区域
var solve = function(board) {
    const rows = board.length;
    const cols = board[0].length;

    function dfs(x,y){
        if(x<0||y<0||x>=rows||y>=cols||board[x][y]!='O')return;
        board[x][y] = '/'
        dfs(x+1,y)
        dfs(x-1,y)
        dfs(x,y+1)
        dfs(x,y-1)
    }
    for(let i=0;i<rows;i++){
        dfs(i,0)
        dfs(i,cols-1)
    }
    for(let i=0;i<cols;i++){
        dfs(0,i)
        dfs(rows-1,i)
    }
    console.log(board)
    for(let i=0;i<rows;i++){
        for(let j=0;j<cols;j++){
            if (board[i][j] === 'O') board[i][j] = 'X';
            if (board[i][j] === '/') board[i][j] = 'O';
        }
    }
    return board;
};
39. 组合总和
var combinationSum = function(candidates, target) {
    const result = []
    candidates.sort((a, b) => a - b); // 首先对数组进行排序
    function backTrack(remaining, path, start){
        if(remaining==0){
            // 推入副本
            result.push([...path]);
            return
        }
        for(let i=start; i<candidates.length;i++){
            if (candidates[i] > remaining) {
                // 如果当前值大于剩余值,不需要继续探索
                break;
            }
            // 选择当前值
            path.push(candidates[i])
            // 继续探索
            backTrack(remaining-candidates[i],path,i)
            // 撤销选择
            path.pop()
        }
    }
    backTrack(target,[], 0)
    return result;
};
150. 逆波兰表达式求值
var evalRPN = function(tokens) {
    const stack = [];
    for (let token of tokens) {
        if (!isNaN(parseFloat(token)) && isFinite(token)) {
            stack.push(parseInt(token, 10)); // 明确指定十进制
        } else {
            let right = stack.pop();
            let left = stack.pop();
            switch (token) {
                case '+':
                    stack.push(left + right);
                    break;
                case '-':
                    stack.push(left - right);
                    break;
                case '*':
                    stack.push(left * right);
                    break;
                case '/':
                    // 结果应该向零取整
                    stack.push(parseInt(left / right, 10));
                    break;
            }
        }
    }
    return stack.pop();
};
53. 最大子数组和
var maxSubArray = function(nums) {
    let currentMax = nums[0]
    let globalMax = nums[0]
    for(let i=1;i<nums.length;i++){
        currentMax = Math.max(currentMax+nums[i], nums[i])
        globalMax = Math.max(currentMax, globalMax)
    }
    return globalMax;
};
104. 二叉树的最大深度
var maxDepth = function(root) {
    if(root === null){
        return 0
    }
    
    return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1
};
860. 柠檬水找零
var lemonadeChange = function(bills) {
    let five = 0, ten =0;
    for(let bill of bills){
        if(bill === 5){
            five++
        }
        if(bill === 10){
            if(five<=0)return false;
            ten++;
            five--;
        }
        if(bill === 20){
            if(ten>0 && five>0){
                ten--;
                five--;
                continue;
            }
            if(five>2){
                five-=3
                continue;
            }
            return  false
        }
    }
    return true;

};
15. 三数之和
var threeSum = function(nums) {
    nums.sort((a,b)=>a-b)
    const result = []
    // i<nums.length-2
    for(let i = 0; i<nums.length-2; i++){
        // 跳过重复的数字
        if(i>0&&nums[i]=== nums[i-1]) continue;
        let left = i + 1
        let right = nums.length -1
        while (left<right){
            const target = nums[i] + nums[left] + nums[right]
            if(target == 0){
                result.push([nums[i] , nums[left] , nums[right]])
                while (nums[left]=== nums[left+1])left++;
                while (nums[right] === nums[right-1])right--;
                // 上边去重复  下边跳过
                left++;
                right--;
            }
            if(target>0){right--}
            if(target<0){left++}
        }
    }
    return result;
};
283. 移动零
var moveZeroes = function(nums) {
    let insert = 0
    for(let i=0;i<nums.length;i++){
        if(nums[i]!=0){
            nums[insert] = nums[i]
            insert++
        }
    }
    while (insert<nums.length){
        nums[insert] = 0;
        insert++;
    }
    return nums;
};
1046. 最后一块石头的重量
var lastStoneWeight = function(stones) {
    while (stones.length>1){
        stones.sort((a,b)=>{return a-b})
        const y = stones.pop()
        const x = stones.pop()
        if(y>x){
            stones.push(y-x)
        }
    }
    return stones[0]||0;
};
38. 外观数列
var countAndSay = function(n) {
  if(n==1) return '1';
  let prev = '1'
   for(let i=2;i<=n;i++){
      let curr = ''
      let j=0;
      // 遍历pre
      while (j<prev.length){
         let count = 1
         // 累加相同
         while (j<prev.length&&prev[j]===prev[j+1]){
            count++;
            j++
         }
         // j++
         curr += count + prev[j]
         j++
      }
      prev = curr

   }
   return prev;
};
230. 二叉搜索树中第K小的元素
// 二叉搜索树的一个关键特性是,对于任何给定的节点,其左子树的所有节点值都小于该节点,而其右子树的所有节点值都大于该节点。
var kthSmallest = function(root, k) {
    let result =[]

    function getVal(node){
        if(node ==null || result.length>=k)return;
        getVal(node.left)
        result.push(node.val)
        getVal(node.right)
    }
    getVal(root)
    return result[k-1]

};
836. 矩形重叠
var isRectangleOverlap = function(rec1, rec2) {
    // 在左 右 上 下的时候不重合 判断四个点
    return !(rec1[2]<=rec2[0]||rec1[0]>=rec2[2]||rec1[1]>=rec2[3]||rec1[3]<=rec2[1])
};
168. Excel表列名称
var convertToTitle = function(columnNumber) {
    let result = ''
    while (columnNumber>0){
        // 列在0 开始 都要-1
        const current =(columnNumber-1)%26;
        result = String.fromCharCode(current + 65) + result
        columnNumber = Math.floor((columnNumber-1)/26)
    }
    return result
};
171. Excel 表列序号
var titleToNumber = function(columnTitle) {
    // let result = 0
    // let step = 1
    // while (columnTitle){
    //     const end = columnTitle.substring(columnTitle.length-1,columnTitle.length)
    //     result += step*(end.charCodeAt(0)-64)
    //     step *=26;
    //     columnTitle = columnTitle.substring(0,columnTitle.length-1)
    //     console.log(columnTitle)
    // }
    // return result;

    let result = 0;
    for (let i = 0; i < columnTitle.length; i++) {
        result = result * 26 + (columnTitle.charCodeAt(i) - 64);
    }
    return result;
};
101. 对称二叉树
var isSymmetric = function(root) {

// 判断两个树是否是镜像对称的
    function isMirror(left, right) {
        if (left === null && right === null) return true;
        if (left === null || right === null) return false;
        return (left.val === right.val) && isMirror(left.right, right.left) && isMirror(left.left, right.right);
    }
// 判断一棵树是否是对称的
    return isMirror(root, root);
};
LCR 147. 最小栈
var MinStack = function() {
    this.stack = [];
    this.minStack = [];
};

/** 
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
    this.stack.push(x);
    if (this.minStack.length === 0 || x <= this.minStack[this.minStack.length - 1]) {
        this.minStack.push(x);
    }
};
/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
    const popped = this.stack.pop();
    if (popped === this.minStack[this.minStack.length - 1]) {
        this.minStack.pop();
    }
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
    return this.stack[this.stack.length - 1];
};

/**
 * @return {number}
 */
MinStack.prototype.getMin = function() {
    return this.minStack[this.minStack.length - 1];
};

// 类的写法
// class MinStack {
//     constructor() {
//         this.stack = [];
//         this.minStack = [];
//     }
//
//     push(x) {
//         this.stack.push(x);
//         if (this.minStack.length === 0 || x <= this.minStack[this.minStack.length - 1]) {
//             this.minStack.push(x);
//         }
//     }
//
//     pop() {
//         const popped = this.stack.pop();
//         if (popped === this.minStack[this.minStack.length - 1]) {
//             this.minStack.pop();
//         }
//     }
//
//     top() {
//         return this.stack[this.stack.length - 1];
//     }
//
//     getMin() {
//         return this.minStack[this.minStack.length - 1];
//     }
// }
LCR 085. 括号生成
var generateParenthesis = function(n) {
    const result = []
    function backTrack(s,left, right){
        if(s.length == 2*n){
            result.push(s)
            return
        }
        if(left<n){
            backTrack(s+'(', left+1, right)
        }
        // 右边小于左边
        if(right<left){
            backTrack(s+')', left, right+1)
        }
    }
    backTrack('',0,0)
    return result;
};
62. 不同路径
var uniquePaths = function(m, n) {
    const dp = Array.from({ length: m }, () => Array(n).fill(0));
    // 初始化第一行和第一列
    for(let i=0;i<m;i++){
        dp[i][0] = 1
    }
    for(let i=0;i<n;i++){
        dp[0][i] = 1
    }

    // 循环在1开始
    for(let i=1;i<m;i++){
        for(let j=1;j<n;j++){
            dp[i][j] = dp[i][j-1]+dp[i-1][j]
        }
    }
    return dp[m-1][n-1]

};
103. 二叉树的锯齿形层序遍历
var zigzagLevelOrder = function(root) {
    if(root == null)return [];
    const queue = [root];
    const result = []
    let level = 0// 控制顺序
    while (queue.length){
        // 循环一遍一层
        const queueSize = queue.length;
        const tempResult = []
        for(let i=0;i<queueSize;i++){
            // 从前往后删除 添加
            const tempNode = queue.shift()
            if(level%2==0){
                tempResult.push(tempNode.val)
            } else{
                tempResult.unshift(tempNode.val)
            }
            if(tempNode.left) queue.push(tempNode.left)
            if(tempNode.right) queue.push(tempNode.right)
        }
        level++;
        result.push(tempResult)
    }
    return result
};
21. 合并两个有序链表
var mergeTwoLists = function(list1, list2) {
    let temp = new ListNode(0);
    // 存着这个链表节点 一直做赋值用
    let result = temp
    while (list1!==null&&list2!=null){
        if(list1.val<=list2.val){
            result.next = list1
            list1 = list1.next
        }else{
            result.next = list2
            list2 = list2.next
        }
        result = result.next
    }
    result.next = list1||list2
    return temp.next;
};
LCR 021. 删除链表的倒数第 N 个结点
var removeNthFromEnd = function(head, n) {
    let fast = head;
    let slow = head;
    for(let i=0;i<n;i++){
        fast = fast.next
    }
    // 如果fast为null 说明删除第一个 直接取第二个即可
    if(fast == null)return head.next;
    while (fast.next!=null){
        fast = fast.next
        slow = slow.next
    }
    // .next时候才能跳过  要不然相当改的是变量值
    slow.next = slow.next.next
    return head;
};
70. 爬楼梯
var climbStairs = function(n) {
    const dep =[1,2,3]
    //后一次是前两次的和
    for(let i=3;i<n;i++){
        dep[i] = dep[i-1] + dep[i-2]
    }
    return dep[n-1]
};
LCR 008. 长度最小的子数组
// 先加到target值 再缩短长度,再继续加 记录最短长度
var minSubArrayLen = function(target, nums) {
    let left = 0;
    let result =0;
    let minLen = Infinity
    for(let i=0;i<nums.length;i++){
        result +=nums[i];
        while (result>=target){
            minLen = Math.min(minLen, i-left+1)
            result -= nums[left]
            left++
        }
    }
    return minLen === Infinity ? 0 : minLen;
};
LCR 024. 反转链表
var reverseList = function(head) {
    let pre = null // 反转链表
    let current = head
    while (current){
        // 临时存当前节点的下一个
        const tempCurrent = current.next
        // 当前的 下一个指向上一个
        current.next = pre
        // 反转拼接
        pre = current
        // 当前继续循环
        current = tempCurrent
    }
    return  pre

};
200. 岛屿数量
var numIslands = function(grid) {
    let count = 0;
    for(let i=0;i<grid.length;i++){
        for(let j=0;j<grid[i].length;j++){
            if(grid[i][j]==='1'){
                count++;
                defs(i,j, grid)
            }
        }
    }
    return count;
    
};
// 挨着的岛算是一个岛屿
function defs(i,j,grid){
    if(i<0||i>=grid.length||j<0||j>=grid[0].length||grid[i][j]==='0'){
        return
    }
    grid[i][j] = '0'
    defs(i-1,j,grid)
    defs(i+1,j,grid)
    defs(i,j-1,grid)
    defs(i,j+1,grid)
}
141. 环形链表
var hasCycle = function(head) {
    let fast = head;
    let slow = head;
    while (fast &&fast.next&& slow){
        fast = fast.next.next
        slow = slow.next
        if(fast === slow){
            return true;
        }
    }
    return false
};
54. 螺旋矩阵
var spiralOrder = function(matrix) {
    const result = [];
    let top=0,bottom=matrix.length-1;
    let left=0,right=matrix[0].length-1;
    while (left<=right&&top<=bottom){
        for(let i=left;i<=right;i++){
            result.push(matrix[top][i])
        }
        top++
        for(let i=top;i<=bottom;i++){
            result.push(matrix[i][right])
        }
        right--

        if(bottom>=top){
            for(let i=right;i>=left;i--){
                result.push(matrix[bottom][i])
            }
            bottom--
        }
        if(right>=left){
            for(let i=bottom;i>=top;i--){
                result.push(matrix[i][left])
            }
            left++
        }
    }
    return result;
};
LCR 076. 数组中的第 K 个最大元素
var findKthLargest = function(nums, k) {
    // 第k大个元素 就是从小排序的倒数第几个元素  nums.length - k
    return quickSelect(nums, 0, nums.length - 1, nums.length - k);
};

function quickSelect(nums, low, high, k) {
    const pivot = nums[Math.floor((low + high) / 2)];

    let left = low;
    let right = high;

    while (left <= right) {
        while (nums[left] < pivot) left++;
        while (nums[right] > pivot) right--;
        if (left <= right) {
            [nums[left], nums[right]] = [nums[right], nums[left]];
            left++;
            right--;
        }
    }

    if (k <= right) return quickSelect(nums, low, right, k);
    if (k >= left) return quickSelect(nums, left, high, k);

    return nums[k];
}
5. 最长回文子串
var longestPalindrome = function(s) {
    let start =0;
    let end =0;
    let maxLen = 0
    function getOther(left, right){
        while (left>=0&&right<s.length&&s[left]===s[right]){
            left--;
            right++;
        }
        return right - left - 1
    }
    for(let i=0;i<s.length;i++){
        // 考虑奇数偶数
        const len1 = getOther(i, i);
        const len2 = getOther(i, i+1)
        const len = Math.max(len1,len2)
        if(maxLen<len){
            maxLen = len
            start = i - Math.floor((len-1)/2)
            end = i + Math.floor(len/2)
        }
    }
    return s.substring(start,end+1)
};
102. 二叉树的层序遍历
var levelOrder = function(root) {
    if(root === null) return []
    let result = [];
    let queue = [root]
    while (queue.length){
        const leveSize = queue.length
        const tempArr = []
        for(let i=0;i<leveSize;i++){
            const current = queue.shift()
            tempArr.push(current.val)
            current.left && queue.push(current.left)
            current.right && queue.push(current.right)
        }
        result.push(tempArr)
    }
    return result
};
LCR 007. 三数之和
var threeSum = function(nums) {
    nums.sort((a, b) => a - b);
    const result = [];
    for (let i = 0; i < nums.length - 2; i++) {
        if (i > 0 && nums[i] == nums[i - 1]) continue;
        let left = i + 1;
        let right = nums.length - 1;
        while (left < right) {
            const sum = nums[i] + nums[left] + nums[right];
            if (sum === 0) {
                result.push([nums[i], nums[left], nums[right]]);
                while (nums[left] === nums[left + 1]) left++;
                while (nums[right - 1] === nums[right]) right--;
                left++;
                right--;
            } else if (sum < 0) {
                left++;
            } else {
                right--;
            }
        }
    }
    return result;
};
LCR 083. 全排列
var permute = function(nums) {
    const result = []
    backTrack(nums,[],result)
    return result;
};

function backTrack(nums, currents, result){
    if(currents.length === nums.length){
        result.push([...currents]);
        return
    }
    for(let i=0;i<nums.length;i++){
        if(currents.includes(nums[i])){
            continue;
        }
        currents.push(nums[i])
        backTrack(nums,currents,result)
        currents.pop()
    }
}
LCR 049. 求根节点到叶节点数字之和
var sumNumbers = function(root) {
    function defs (node, sumNum){
        if(node === null){
            return 0
        }
        sumNum = 10*sumNum + node.val
        if(node.left === null && node.right===null){
            return sumNum
        }
        return defs(node.left, sumNum) + defs(node.right, sumNum)
    }
    return defs(root,0)
};
415. 字符串相加
var addStrings = function(num1, num2) {
    let superfluous = 0;
    let result = ''

    let i=num1.length -1,j=num2.length-1
    while(i>=0||j>=0||superfluous>0){
        const sum = ~~(num1[i]||0) + ~~(num2[j]||0) + superfluous
        superfluous = Math.floor(sum/10)
        result = (sum%10) + result
        i--;
        j--;
    }
    return result;

};
165. 比较版本号
var compareVersion = function(version1, version2) {
    var v1 = version1.split('.').map(Number)
    var v2 = version2.split('.').map(Number)
    var vm = Math.max(v1.length, v2.length)
    for(let i=0;i<vm;i++){
        if((v1[i]||0)>(v2[i]||0)){
            return 1;
        }
        if((v1[i]||0)<(v2[i]||0)){
            return -1;
        }
    }
    return 0;
};
88. 合并两个有序数组
var merge = function(nums1, m, nums2, n) {
    let k = m + n -1
    m = m-1
    n = n-1
    while (m>=0 && n>=0){
        if(nums2[n]>nums1[m]){
            nums1[k] = nums2[n]
            n--;
        }else{
            nums1[k] = nums1[m];
            m--
        }
        k--;
    }
    while (n>=0){
        nums1[k] = nums2[n]
        k--;
        n--;
    }

    return nums1;
};
20. 有效的括号
var isValid = function(s) {
    const mapping = {
        ')': '(',
        '}': '{',
        ']': '['
    };
    let stack = []
    for(char of s){
        if(mapping[char]){
            if(mapping[char] !== stack.pop()){
                return false
            }
        }else {
            stack.push(char)
        }
    }
    return  stack.length === 0

};
1. 两数之和
var twoSum = function(nums, target) {
    let tempMap = new Map()
    for(let i=0;i<nums.length;i++){
        if(tempMap.has(target - nums[i])){
            return [tempMap.get(target - nums[i]), i]
        }else{
            tempMap.set(nums[i],i)
        }
    }
    return false;
};
160. 相交链表
var getIntersectionNode = function(headA, headB) {
    let ap = headA,
        bp = headB;
    while (ap !== bp) {
      if (ap === null) {
        ap = headB;
      } else {
        ap = ap.next;
      }
      if (bp === null) {
        bp = headA;
      } else {
        bp = bp.next;
      }
    }
    return ap;
};
23. 合并 K 个升序链表
var mergeKLists = function (lists) {
    const list = [];
    for (let i = 0; i < lists.length; i++) {
        let node = lists[i];
        while (node) {
            list.push(node.val);
            node = node.next;
        }
    }
    list.sort((a, b) => a - b);
    const res = new ListNode();
    let now = res;
    // console.log(list)
    for (let i = 0; i < list.length; i++) {
        now.next = new ListNode(list[i]);
        now = now.next;
    }
    return res.next;
};
347. 前 K 个高频元素
var topKFrequent = function(nums, k) {
    let map = new Map();
    let res = [];
    for(let i = 0; i < nums.length; i++) {
        if(map.has(nums[i])) {
            map.set(nums[i], map.get(nums[i]) + 1);
        } else {
            map.set(nums[i], 1);
        }
    }
    //返回一个按出现次数降序的二维数组
    let sortArray = Array.from(map).sort((a, b) => b[1] - a[1]);
    for(let i = 0; i < k; i++) {
        res.push(sortArray[i][0]);
    }
    return res;
};
215. 数组中的第K个最大元素
var findKthLargest = function(nums, k) {
    // 第k大个元素 就是从小排序的倒数第几个元素  nums.length - k
    return quickSelect(nums, 0, nums.length - 1, nums.length - k);
};

function quickSelect(nums, low, high, k) {
    const pivot = nums[Math.floor((low + high) / 2)];

    let left = low;
    let right = high;

    while (left <= right) {
        while (nums[left] < pivot) left++;
        while (nums[right] > pivot) right--;
        if (left <= right) {
            [nums[left], nums[right]] = [nums[right], nums[left]];
            left++;
            right--;
        }
    }

    if (k <= right) return quickSelect(nums, low, right, k);
    if (k >= left) return quickSelect(nums, left, high, k);

    return nums[k];
}
133. 克隆图
var cloneGraph = function(node) {
    // 记录复制的节点
    let map = new Map()
    function dfs(node){
        if(!node)return node;
        if(map.has(node)) return map.get(node);
        // clone当前节点
        let cloneNode = new Node(node.val);
        map.set(node, cloneNode);
        // 当前节点的相邻节点
        for(let neighbor of node.neighbors){
            cloneNode.neighbors.push(dfs(neighbor))
        }
        return cloneNode
    }
    return dfs(node)
};