力扣刷题记录

163 阅读1分钟

排序

blog.csdn.net/qq_41370833…

冒泡排序

搜索插入位置

记住找得到的时候插入位置就是mid 找不到的时候 right就是你的左边界 插入right+1处即可

二分查找

一个容易犯的小错误是数组最后一个元素的下标是length-1

二分法:数组有序、数组元素不重复

二分法的循环条件是left<=right

当一直找不到跳出循环时 right在左left在右 right指左边界 left指右边界

(均不包括target)(target在right和left指的元素的范围之间)

元素在right和left之间

最后四种情况:(其实也就两种:找到和找不到)

  1. target在数组左边 left指向0 right一直往左移到指向-1跳出循环
  2. target在数组右边 right指向length-1 left一直往右移到length跳出循环
  3. target在数组中且找到 mid指向target位置 此时left和right是正常的
  4. target在数组中且找不到 跳出时 right在前 left在后 target在两个指的范围之间

简单说就是:

找到了:left在左 right 在右 mid在中间指向找到的元素

找不到:right在左是右边界 left在右是左边界 target在right和left数值范围之间(且不包含)

排序数组中查找元素的第一个和最后一个位置

leetcode.cn/problems/fi…

在mid就算已经找到的情况下 持续让左指针往右逼近/右指针往左逼近 直到跳出循环

此时right为左边界 left为右边界 target范围在左右边界之间(且不包含)

var searchRange = function(nums, target) {
    let left=searchLeft(nums,target)
    let right=searchRight(nums,target)
    // 说明找到了
    if(nums[left+1]===target || nums[right-1]===target) return [left+1,right-1]
    return [-1,-1]


};

// 跳出循环时 right就是左边界 left是右边界 
// 找左边界
var searchLeft = function(nums,target){
    let left = 0,right=nums.length-1
    // 闭闭区间 等于号有效
    // 尽可能向左逼近 就算找到了也向左逼近
    while(left<=right){
        let mid = left + ((right-left) >> 1)
        if(nums[mid] < target){
            left = mid+1
        }else{
            right = mid-1
        }
    }
    return right 
}
var searchRight = function(nums,target){
    let left = 0,right=nums.length-1
    // 尽可能向右逼近
    while(left<=right){
        let mid = left + ((right-left) >> 1)
        if(nums[mid] <= target){
            left=mid+1
        }else{
            right=mid-1
        }
    }
    return left
}

移除元素

双指针法 思路是快指针遍历原数组 慢指针指向新数组的下标

比较含退格的字符串(难)

leetcode.cn/problems/ba…

String用split('')转成Array在处理

返回的时候k指向新数组的length位 用slice切片之后再join回字符串

slice含左不含右

退格慢指针最多退到0

var backspaceCompare = function(s, t) {
    return (backspaceString(s) == backspaceString(t))
};
var backspaceString = function(s){
    // 注意先把字符串转为数组才能进行操作
    const arr = s.split('')
    let k = 0 //k指新数组元素 i遍历当前数组的下标
    for(let i=0;i<arr.length;i++){
        if(arr[i]!=='#'){
            arr[k]=arr[i]
            k++
        }
        // 碰到# 慢指针退格
        if(arr[i]==='#'){
            k>=1 ? k-- : k = 0 //最多退到0
        }
    }
    return arr.slice(0,k).join('')
}

两数之和

leetcode.cn/problems/tw…

哈希:Map 什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法

两数之和:一个for循环来遍历元素 一个map来存遍历过的元素 每次循环时查map里是否有符合条件的元素

var twoSum = function(nums, target) {
    const map = new Map()
    // map存已经遍历过的元素和对应下标
    for(let i=0;i<nums.length;i++){
        // 先从map里查找是否有符合条件的元素
        if(map.has(target-nums[i])) return [i,map.get(target-nums[i])]
        // 没有的话 存入该元素
        map.set(nums[i],i)
    }
};

三数之和

leetcode.cn/problems/3s…

双指针 先排序 然后遍历 当前i指target 然后双指针二分查

var threeSum = function(nums) {
    // 升序排序
    nums.sort((a,b)=>a-b)
    let result = []
    // 遍历时 i指target 
    // -4 -1 -1 0 1 2
    for(let i=0;i<nums.length;i++){
        // 定义左右两个指针
        let left=i+1,right=nums.length-1
        // 对target元素去重 
        if(nums[i] === nums[i-1]) continue
        while(left<right){
            let sum = nums[i]+nums[left]+nums[right]
            if(sum>0) right--
            else if(sum<0) left++
            else{
                result.push([nums[i],nums[left],nums[right]])
                // 找到一个满足条件的三元组后 对left和right进行去重
                while(left<right && nums[left]===nums[left+1]) left++
                while(left<right && nums[right]===nums[right-1]) right--
                left++
                right--
            }
        }
    }
    return result
};

盛最多水的容器

leetcode.cn/problems/co… 双指针 向内移动指针

var maxArea = function(height) {
    let left=0,right = height.length-1
    let max = 0
    while(left<right){
        // 容量=短板*宽度 宽度肯定会变小
        // 移动长板 短板变短或不变 体积肯定变小
        // 移动短板 短板可能变大 体积可能变大
        // 所以移动短板
        if(height[left]<height[right]){
            let curr = height[left]*(right-left)
            max = Math.max(max,curr)
            left++
        }else{
            let curr = height[right]*(right-left)
            max = Math.max(max,curr)
            right--
        }
    }
    return max
};

动态规划

image.png

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

01背包:物品只有一个 选or不选 完全背包:物品有无数个 选几个or不选

爬楼梯

leetcode.cn/problems/cl…

不同路径

leetcode.cn/problems/un…

js生成二维数组

const m = 4;
const  n = 5;
let arr = Array.from(new Array(m), () => new Array(n));
const m = 4;
const  n = 5;
let arr = new Array(m).fill().map(() => new Array(n));

Array(m) 和 new Array(m)效果是一样的

分割等和子集

leetcode.cn/problems/pa… 01背包问题 weight和value是相同的 dp[target]=target代表刚好装满 可以分割