leetcode 4月 每日一题(持续更新

不会算法的前端不是好前端
用js刷leetcode,坚持每日一题

4月

4.1 String to Integer (atoi)

4.2 Container With Most Water

4.1 String to Integer (atoi)

题目:8. String to Integer (atoi) 字符串转换整数

解法1: 用现成的parseInt()呀,来对比一下需求

题目要求为:parseInt()
无视开头空格符合
含有符号符合
无视整数部分后的字符符合
范围在32位内,超出返回 INT_MAX (2^31− 1) 或 INT_MIN (−2^31)不符合(需要手动判断一下)
不能有效转换时返回 0不能转化时返回NaN
/**
 * @param {string} str
 * @return {number}
 */
var myAtoi = function(str) {
    const number = parseInt(str, 10);//10进制
    if(isNaN(number)) return 0;//不能有效的转换
    return number < Math.pow(-2, 31) ? Math.pow(-2, 31):(number > Math.pow(2, 31) - 1?Math.pow(2, 31) - 1:number);
}

在这里插入图片描述

再来看一下官方的方法:确定有限状态机

4.2 Container With Most Water

题目:11. Container With Most Water 盛最多水的容器
在这里插入图片描述
贪心,左右指针

var maxArea = function(height) {
    var l = 0, r = height.length-1; // 左右指针
    var temp = 0, ans = 0;
    while(l < r){
        temp = (r-l)*(Math.min(height[l],height[r])); //计算此时容积
        ans<temp && (ans = temp); //记录最优解
        height[l] < height[r] ? l++ : r--; //哪边短哪边往里移动
    }
    return ans;
};

在这里插入图片描述

4.3 Generate Parentheses

题目:22. Generate Parentheses 括号生成

一开始的写法比较蠢… 循环加(),set去重
() --> (()) --> (()()), ((())), (())()
() --> ()() --> (())(), ()()(), ()(())

/**
 * @param {number} n
 * @return {string[]}
 */
var fun1 = function(s){
    let ans = new Set();
    for(let temp of s){
        for(var j=0;j<temp.length;j++){
           ans.add(temp.slice(0,j-1)+"()"+temp.slice(j-1));
        }
    }
    return ans;
}
var generateParenthesis = function(n) {
    if(n==0) return [];
    let s = new Set();s.add("()");
    while(--n){s = fun1(s);}
    return [...s];
};

回溯

var generateParenthesis = function(n) {
    let res = [];
    let dfs = (s, left, right)=>{
        if(left ==n &&right==n) return res.push(s);
        if(left < n) dfs(s+'(', left+1, right);
        if(right < left) dfs(s+')', left, right+1);
    }
    dfs('', 0, 0);
    return res;
};

在这里插入图片描述

4.5 Jump Game

题目:55. Jump Game 跳跃游戏
暴力 遍历一遍记可到达的最远位置

var canJump = function(nums) {
    var maxIndex = nums[0];
    for(var i=0;i<nums.length;i++){
        if(i>maxIndex) return false;
        maxIndex = Math.max(maxIndex,i+nums[i]);
    }
    return true;
};

在这里插入图片描述

4.8 Reverse Words in a String

题目 151. Reverse Words in a String 翻转字符串里的单词

var reverseWords = function(s) {
    return s.trim().split(" ").filter(item => item).reverse().join(' ');
};

在这里插入图片描述

4.9 Binary Tree Right Side View

题目:199. Binary Tree Right Side View 二叉树的右视图

在这里插入图片描述
深搜 右枝先遍历(后放入栈),找到每个深度第一次遍历到的元素值

var rightSideView = function(root) {
    if(root==null) return [];
    var _s=[],ans=[],t;
    root.h=0; _s.push(root);
    while(_s.length>0){
        t = _s.pop();
        if(t.left!=null){
            t.left.h = t.h+1; _s.push(t.left);
        }
        if(t.right!=null){
            t.right.h = t.h+1; _s.push(t.right);
        }
        ans[t.h]==undefined &&(ans[t.h] = t.val) ;
    }
    return ans;
};

在这里插入图片描述

4.10 Game of Life

题目 289. Game of Life 生命游戏
方法1是复制一个原矩阵出来

/**
 * @param {number[][]} board
 * @return {void} Do not return anything, modify board in-place instead.
 */
var gameOfLife = function(board) {
    if(!board.length) return null;
    var m=board.length,n=board[0].length, t;
    var _board = JSON.parse(JSON.stringify(board));
    for(var i=0;i<m;i++){
        for(var j=0;j<n;j++){
            t=0;
            if(i>0){
                t += _board[i-1][j] + (j>0?_board[i-1][j-1]+_board[i][j-1]:0)+(j<n-1?_board[i-1][j+1] + _board[i][j+1]:0);
            }else{
                t += (j>0?_board[i][j-1]:0)+(j<n-1?_board[i][j+1]:0);
            }
            if(i<m-1){
                t += _board[i+1][j] + (j>0?_board[i+1][j-1]:0)+(j<n-1?_board[i+1][j+1]:0);
            }
            if( _board[i][j]==1 && (t<2 || t>3))board[i][j]=0;
            else if(_board[i][j]==0 && t==3)board[i][j]=1;
        }
    }
    return board;
};

在这里插入图片描述

方法2 不使用额外内存,而是用状态值
2: 原本死了的活了;-1:原本活的死了

var gameOfLife = function (board) {
    if(!board.length) return null;
    let rows = board.length; let cols = board[0].length;
    let neighbors = [0, -1, 1];
    for (let row = 0; row < rows; row++) {
        for (let col = 0; col < cols; col++) {
            let liveBox = 0;
            // 遍历每个格子的周围的八个格子
            for (let i = 0; i < 3; i++) {
                for (let j = 0; j < 3; j++) {
                    if (!i && !j) continue
                    let r = row + neighbors[i];
                    let c = col + neighbors[j];
                    if ((r >= 0 && r < rows) && (c >= 0 && c < cols) && Math.abs(board[r][c]) === 1) {
                        liveBox++;
                    }
                }
            }
            if ((board[row][col] === 1) && (liveBox < 2 || liveBox > 3)) {
                board[row][col] = -1;//-1:原本活的死了
            }
            if (board[row][col] === 0 && liveBox === 3) {
                board[row][col] = 2;//2: 原本死了的活了
            }
        }
    }
    // 转换状态,2 -> 1,-1 -> 0
    for (let row = 0; row < rows; row++) {
        for (let col = 0; col < cols; col++) {
            board[row][col] = board[row][col] > 0 ? 1 : 0;
        }
    }
};

在这里插入图片描述

4.23 Rotate Matrix LCCI

01.07. Rotate Matrix LCCI 旋转矩阵

  1. 复制赋值:会占用额外空间的方法
    在这里插入图片描述
    代码:
var rotate = function(matrix) {
    var _matrix = JSON.parse(JSON.stringify(matrix)), len = matrix.length;
    for(var i=0;i<len;i++){
         for(var j=0;j<len;j++){
             matrix[j][len-1-i]=_matrix[i][j];
         }
    }
};

在这里插入图片描述
2. 转置倒序法

let rotate = (matrix) =>{
    for(let i = 0; i < matrix.length; i++){
        for (let j = i; j < matrix[i].length; j++){
            [matrix[i][j],matrix[j][i]] = [matrix[j][i],matrix[i][j]]
        }
    }
    matrix.forEach(row=> row.reverse())
};  

在这里插入图片描述

4.24 Coin LCCI

硬币,给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)
动态规划,

/**
 * @param {number} n
 * @return {number}
 */
let waysToChange = (n)=> {
    let dp = new Array(n+1).fill(1)
    let coins = [1,5,10,25]
    for(let i=1; i<4; i++){
        for(let j=1; j<=n; j++){
            if(j-coins[i]>=0){
                dp[j] = (dp[j]+dp[j-coins[i]]) % (1e9+7)
            } 
        }
    }
    return dp[n];
};

在这里插入图片描述

4.25 Permutations

46 Permutations 全排列
回溯法 深度优先搜索
在这里插入图片描述

var permute = function(nums) {
  if(nums==0) return [];
    var len=nums.length,used=[],path=[],ans=[];
    var dfs = function(d){
        if(d==len){ans.push([...path]);//拷贝}
        for(var i=0;i<len;i++){
            if(!used[nums[i]]){//该数字还没被加入path
                path.push(nums[i]);
                used[nums[i]] = true;
                dfs(d+1);
                path.pop();
                used[nums[i]] = false;
            }
        }
    }
    dfs(0);
    return ans;
};

在这里插入图片描述

4.26 Merge k Sorted Lists

题目 23. Merge k Sorted Lists 合并K个排序链表
先来看一下21. Merge Two Sorted Lists 合并两个排序链表

var mergeTwoLists = function(l1, l2) {
    var ans= new ListNode(-1),cur=ans;
    while(l1&&l2){
        if(l1.val <= l2.val){
            cur.next = l1; l1=l1.next;
        }else{
            cur.next = l2; l2=l2.next;
        }
        cur=cur.next;
    }
    cur.next = l1?l1:l2;
    return ans.next;
};

这道题可以两个两个来合并

var mergeKLists = function(lists) {
    let mergeTwoLists = (l1,l2) => {
        let pre = new ListNode(-1)
        let cur = pre;
        while(l1 && l2){
            if(l1.val <= l2.val){
                cur.next = l1 l1 = l1.next
            }else{
                cur.next = l2 l2 = l2.next
            }
            cur = cur.next;
        }
        cur.next = l1 ? l1 : l2;
        return pre.next;
    }
    if(lists.length == 0) return null;
    let res = lists[0]
    for(let i = 1;i < lists.length;i++){
        if(lists[i]){
            res = mergeTwoLists(res,lists[i]);
        }
    }
    return res;
};

在这里插入图片描述

4.27 Search in Rotated Sorted Array

题目33. Search in Rotated Sorted Array 搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )
输入: nums = [4,5,6,7,0,1,2], target = 0 输出: 4

类似二分,
在这里插入图片描述
代码

var search = function(nums, target) {
    let l = 0, r = nums.length-1;
    if(r==0) return nums[0]==target?0:-1;
    m = parseInt((l+r)/2);
    while(l<=r){
        m = parseInt((l+r)/2);
        if(nums[m]==target) return m;
        if(nums[l]<=nums[m]){
            if(target <= nums[m] && target >= nums[l]){
                r = m-1;
            }else{
                l = m+1;
            }
        }else if(nums[m]<nums[r]){
            if(target >= nums[m] && target <= nums[r]){
                l = m+1;
            }else{
                r = m-1;
            }
        }
    }
    return -1;
};

在这里插入图片描述

4.28

面试题56 - I. 数组中数字出现的次数 LCOF
用额外O(n)空间

var singleNumbers = function(nums) {
  let obj = {}
  for(let i = 0; i < nums.length; i++){
    obj[nums[i]] = obj[nums[i]] ? obj[nums[i]] + 1 : 1
  }
  let list = []
  for(let prop in obj){
    if(obj[prop] === 1){
      list.push(prop)
    }
  }
  return list
};

在这里插入图片描述
异或法
先看一下如果是要找到只出现一次的一个数字,只要全员异或就可以了
异或:对于两个操作数的每一位,相同结果为 0,不同结果为 1。成对出现的数字的所有位会两两抵消为 0,最终得到的结果就是那个出现了一次的数字。

var singleNumbers = function(nums) {
	let res = 0;
	for(let n in nums){
		res ^= n;
	}
	return res;
}

如果我们可以把所有数字分成两组,使得:

  • 两个只出现一次的数字在不同的组中;
  • 相同的数字会被分到相同的组中。

那么对两个组分别进行异或操作,即可得到答案的两个数字
记这两个只出现了一次的数字为 a 和 b,那么所有数字异或的结果就等于 a 和 b异或的结果x
xi==1表示ai!=bi

var singleNumbers = function(nums) {
  var ret = 0;
  for(let n of nums){ret ^= n;}
  let i = 1;
  while((i & ret)==0){i <<= 1;} //找到第一个为1的位
  let a = 0, b = 0;
  for(let n of nums){
      if(i & n) a ^= n;
      else b ^= n;
  }
    return [a,b];
};

在这里插入图片描述

01 Matrix

题目 542. 01 Matrix 01 矩阵
bfs 从所有0往四个方向遍历,

var updateMatrix = function(matrix) {
    if(matrix.length==0) return ;
    var st = [],cur;
    var f = [[0,-1],[-1,0],[0,1],[1,0]];
    for(var i=0;i<matrix.length;i++){
        for(var j=0;j<matrix[0].length;j++){
            if(matrix[i][j]==1) matrix[i][j]=-1;
            else st.push([i,j]);
        }
    } 
    while(st.length){
        cur = st.pop();
        for(var i = 0; i < 4; i++){
            var r =  cur[0] + f[i][0]; var c = cur[1] + f[i][1];
            if ((r >= 0 && r < matrix.length) && (c >= 0 && c < matrix[0].length) 
            && (matrix[r][c]== -1 || matrix[r][c] > matrix[cur[0]][cur[1]]+1)) {
                matrix[r][c] = matrix[cur[0]][cur[1]]+1;
                st.push([r,c]);
            }
        }
    }
    return matrix;
}

在这里插入图片描述

动态规划

var updateMatrix = function(matrix) {
    if(!matrix.length || !matrix[0].length) return null;

    let n = matrix.length;
    let m = matrix[0].length;
    let ans = new Array(n);
    for(let i = 0; i < n; i++) ans[i] = new Array(m).fill(n+m);

    for(let i = 0; i < n; i++)
        for(let j = 0; j < m; j++)
            if(matrix[i][j] === 0) ans[i][j] = 0;
    
    for(let i = 0; i < n; i++)
        for(let j = 0; j < m; j++) {
            if(i-1 >= 0) ans[i][j] = Math.min(ans[i][j], ans[i-1][j]+1);
            if(j-1 >= 0) ans[i][j] = Math.min(ans[i][j], ans[i][j-1]+1);
        }
    
    for(let i = n-1; i >= 0; i--)
        for(let j = 0; j < m; j++){
            if(i+1 < n) ans[i][j] = Math.min(ans[i][j], ans[i+1][j]+1);
            if(j-1 >= 0) ans[i][j] = Math.min(ans[i][j], ans[i][j-1]+1);
        }
    
    for(let i = n-1; i >= 0; i--)
        for(let j = m -1 ; j >= 0; j--){
            if(i+1 < n) ans[i][j] = Math.min(ans[i][j], ans[i+1][j]+1);
            if(j+1 < m) ans[i][j] = Math.min(ans[i][j], ans[i][j+1]+1);
        }

    for(let i = 0; i < n; i++)
        for(let j = m -1 ; j >= 0; j--){
            if(i-1 >= 0) ans[i][j] = Math.min(ans[i][j], ans[i-1][j]+1);
            if(j+1 < m) ans[i][j] = Math.min(ans[i][j], ans[i][j+1]+1);
        }
    return ans;

};

在这里插入图片描述

4.29 Find in Mountain Array

题目 1095. Find in Mountain Array 山脉数组中查找目标值
三次二分:先二分查找找到峰值,再左右两次二分

/**
 * @param {number} target
 * @param {MountainArray} mountainArr
 * @return {number}
 */
var findInMountainArray = function(target, mountainArr) {
  let l = 0, r = mountainArr.length() - 1;
  // 寻找山峰
  while (l < r) {
    const mid = (l + r) / 2 | 0;
    if (mountainArr.get(mid) >= mountainArr.get(mid + 1)) {
      r = mid
    } else {
      l = mid + 1
    }
  }
  // 标记山峰所在的位置
  const peak = l;
  // 在山峰左边查找,即在升序序列中查找
  const index = binarySearch(mountainArr, target, 0, peak, v => v)
  // 若存在,则直接返回下标
  if (index !== -1) {
    return index
  }
  // 否则在山峰右边查找,即在降序序列中查找
  return binarySearch(mountainArr, target, peak + 1, mountainArr.length() - 1, v => -v)

  // 二分法查找
  // 其中 fn 是用来对升序还是降序的特殊处理
  function binarySearch (list, target, l, r, fn) {
    target = fn(target)
    while (l <= r) {
      const mid = (l + r) / 2 | 0
      const cur = fn(list.get(mid))
      if (cur === target) {
        return mid
      } else if (cur < target) {
        l = mid + 1
      } else {
        r = mid - 1
      }
    }
    return -1
  }
};

在这里插入图片描述

4.30 202. Happy Number

题目 202. Happy Number 快乐数字
第一个方法:记住所有访问过的数字,来判断是否循环
时间复杂度 O(logn) ,空间复杂度 O(logn)

var isHappy = function(n) {
    var _map={}, t;
    while(true){
        t=n; n=0;
        while(t>0){
            n += (t%10)*(t%10);
            t = (t-t%10)/10;
        }
        if(n==1) return true;
        if(_map[n] == 1) return false;
        _map[n] = 1;
    }
};

在这里插入图片描述

方法2:快慢指针,用快慢指针来找是否有循环

var isHappy = function(n) {
    var getNextNumber = (num)=>{
        let t=num; num=0;
        while(t>0){
            num += (t%10)*(t%10);
            t = (t-t%10)/10;
        }
        return num;
    }
    var k = getNextNumber(n), m = n;
    while(true){
        if(k == 1 || m == 1) return true;
        if(k == m) return false;
        k = getNextNumber(getNextNumber(k));
        m = getNextNumber(m);
    }
};

在这里插入图片描述

方法3:数学法,只有出现数字1或者4会循环

var isHappy = function(n) {
   var t=0;
    while (n != 1 && n != 4) {
        t=n; n = 0;
        while(t>0){
            n += (t%10)*(t%10);
            t = (t-t%10)/10;
        }
    }
    return n == 1;
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值