手撕题加代码题

56 阅读21分钟

常见手撕题

日常题

export const create = (obj: any)=>{
    function fn(){

    }
    fn.prototype = obj
    return new fn()
}

export const instanceofCase = (left: any,right: any)=>{
    let l=left.__proto__;
    let r = right.prototype
    while(true){
        if(l===null){
            return false
        }
        if(l===r){
            return true
        }
        l=l.__proto__
    }
}

export const callFn = (target: any,...args:any)=>{
    target = window || target
    const targetKey = Symbol()
    target[targetKey] = this
    const res = target[targetKey](...args)
    delete target[targetKey]
    return res
}

export const applyFn = (target: any,args: any[])=>{
    target = window || target
    const targetKey = Symbol()
    target[targetKey] = this
    const res = target[targetKey].args
    delete target[targetKey]
    return res
}

export const bindFn = (target: any,...args: any)=>{
    target  = window || target
    const targetKey = Symbol()
    target[targetKey] = this
    return function(...args1:any){
        return target[targetKey](...args,args1)
    }
}

export const newFn = (constructor: any,...args)=>{
    let obj = {}
    obj.__proto__ = constructor.prototype
    const res  =constructor.apply(obj,args)
    return Object.prototype.toString.call(res) === '[object Object]' ? res : obj
}


var pending = 'pending'
var reject = 'reject'
var resolve = 'resolve'
class Mypromise(executor){
    constructor{
        this.status = pending
        this.value = ''
        this.reason = ''
        this.onFufilledFn = []
        this.onRejectFn = []
    }
   const resolve = (value)=>{
    if(this.status===pending){
        this.status = resolve
        this.value=value
        if(this.onFufilledFn.length>0){
            this.onFufilledFn.forEach(fn=>fn())
        }
    }
    }
    const reject = (reason)=>{
        if(this.status===pending){
            this.status===reject
            this.reason=reason
            if(this.onRejectFn.length>0){
                this.onRejectFn.forEach(fn=>fn())
            }
        }
    }
    try{
        executor(resolve,reject)
    }catch(error){
       if(this.status===pending) {
        this.status===reject
        this.reason=error
       }
    }
    then(onFufilled,onReject){
        const onFufilledFns = typeof onFufilled === 'function' ? onFufilled : value=>value
        const onRejectFns = typeof onReject === 'function' ? onReject : error=>{throw error}
        if(this.status===pending){
            this.onFufilledFn.push(onFufilledFns)
            this.onRejectFn.push(onRejectFns)
        }
        if(this.status===resolve){
            onFufilledFns(this.value)
        }
        if(this.status===reject){
            onRejectFns(this.reason)
        }
    }
}
.
const promiseAll = (promises: any)=>{
    return new Promise((resolve,reject)=>{
        let len = promises.length
        let res = []
        let count = 0
        for(let i=0;i<len;i++){
            Promise.resolve(promises[i].then((value)=>{
                res[i]=value
                count++
                if(count>=len){
                    resolve(res)
                }
            },error=>{
                reject(error)
            }))
        }
    })
}   

export const promiseRace = (promises: any)=>{
    return new Promise((resolve,reject)=>{
        for(let i=0;i<promises.length;i++){
            promises[i].then(resolve,reject)
        }
    })
}

// 防抖 一段时间后再执行,如果在这段时间内再次触发,则重新计时,eg:搜索框,点击发送请求等
export const debounce =(fn,wait)=>{
    let timer = null
    return function(){
        if(timer){
            clearTimeout(timer)
            timer = null
        }
        setTimeout(()=>{
            fn.apply(this,arguments)
        },wait)
    }

}

//节流,一段时间内只执行一次,当时间间隔超过指定时间,则再次执行
export const throttle = (fn,wait)=>{
    let curTime = Date.now()
    return function(){
        let nowTime = Date.now()
        setTimeout(()=>{
            if(nowTime-curTime>=wait){
                fn.apply(this,arguments)
                curTime = Date.now()
            }
        },wait)
    }
}

export const valueType = (target: any)=>{
    if(target===null){
        return target+''
    }
    if(typeof target ==='object'){
        const valueClass = Object.prototype.toString.call(target)
        const type = valueClass.split('')[1].split('')
        type.pop()
        return type.join('').toLowerCase()
    }else{
        return typeof target
    }
}
export const curry = (fn,args)=>{
    let len = args.length
    return function(){
        let subArgs = args.slice(0)
        subArgs = subArgs.concat(arguments)
        if(subArgs.length>len){
            return fn.aplly(this,subArgs)
     }else{
        return curry.call(this,fn,subArgs)
     }
}
}



export const myAjax = (url,op)=>{
    return new Promise((resolve,reject)=>{
        const xml = new XMLHttpRequest()
        xml.open(op.method,url,true)
        xml.onreadystatechange = (readyState)=>{
            if(readyState!==4){
                return 
            }
            if(readyState===200){
                resolve()
            }
        }
        xml.onerror = ()=>{
            reject()
        }
        xml.setRequestHeader('Content-type','application/json')
        xml.send()
    })
}

export const shallowCopy = (target: any)=>{
    if(!target || typeof target!=='object' ) return ;
    let newObj = target instanceof Array?[]:{}
    for(let key in target){
        if(target.hasOwnProperty(key)){
            newObj[key] = target[key]
        }
    }
    return newObj
}

//deepCopy(深拷贝需要补充)

// 检测循环依赖
export const isCyclic = (obj: any)=>{
    const set = new WeakSet()
    function detect(obj: any){
        if(obj&&typeof obj==='object'){
            if(set.has(obj)){
                return true
            }
            set.add(obj)
            for(let key in obj){
                if(obj.hasOwnProperty(key)&&detect(obj[key])){
                    return true
                }
            }
        }
        return detect(obj)
    }
}

// 实现简易vue


//观察者模式

class Subscribe{
    constructor(){
        this.observers = []
    }
    addObserver(observer){
        if(observer&&observer.update){
            this.observers.push(observer)
        }
    }
    notify(){
        this.observers.forEach((i)=>i.update())
    }
}
class Observer{
    constructor(){
    ....
    }
    update(){
        console.log('update')
    }
}
//订阅者模式

class EventEmitt{
    constructor(){
        this.subscribes  =new Map()
    }
    addEvent(type,cb,once){
        let sub = this.subscribes.get(type) || []
        sub.push(cb,once)
        this.subscribes.set(type,sub)
    }
    on(type,cb){
        this.addEvent(type,cb)
    }
    emit(type,...args){
        let sub = this.subscribes.get(type)
        const context = this
        sub.forEach(fn=>fn.call(context,...args))
        let newSub = sub.filter(i=>i.once)
        this.subscribes.set(type,newSub)
    }
    off(type,cb){
        let sub = this.subscribes.get(type)
        if(sub){
            let newSub = sub.filter(i=>i!==cb)
             this.subscribes.set(type,newSub)
        }
    }
    once(type,cb){
        addEvent(type,cb,true)
    }
}


// 实现react的useState
const useState = (defalutValue)=>{
    const value = useRef(defaultValue);
    const setValue = (newValue)=>{
        if(typeof newValue==='function'){
            value.current = newValue(value.current)
        }else{
            value.current = value
        }
    }
    dispatchAction()
    return [value,setValue]
    
}

// 数组-》树
    function arrToTree(list){
        let obj = {}
        let res = []
        for(let item of list){
            obj[item.id] = item
        }
        for(let item of list){
            if(obj[item.parent_id]){
                (obj[item.parent_id].children || (obj[item.parent_id].children=[])).push(item)
            }else{
                res.push(item)
            }
        }
        return res
    }
    
// 树=》数组
    function treeToArr(list){
        let arr=[]
        let newArr = [].concat(list)
        while(newArray.length>0){
            let first = newArr.shift()
            if(first.children){
                newArr = newArr.concat(first.children)
                delete first.children
            }
            arr.push(first)
        }
        return arr
    }
    

场景题

// 亮灯函数

function red(){
    console.log('red')
}

function yellow(){
    console.log('yellow')
}

function green(){
    console.log('green')
}

const task = (timer,light,cb)=>{
    setTimeout(()=>{
        if(light==='red'){
            red()
        }else if(light==='yellow'){
            yellow()
        }else if(light==='green'){
            green()
        }
    },timer)
}
const step=()=>{
    task(3000,'red',()=>{
        task(2000,'yellow',()=>{
            task(1000,'green',Function.prototype)
        })
    })
}
step()
// 用promise实现
const task1 = (timer,light)=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            if(light==='red'){
                red()
            }else if(light==='yellow'){
                yellow()
            }else if(light==='green'){
                green()
            }
            resolve()
        },timer)
    })
}

const step1 =()=>{
    task1(3000,'red').then(()=>{task1(2000,'yellow')}).then(()=>{task1(1000,'green')}).then(step1)
}
step1()

//async
const taskRunner = async()=>{
    await task1(3000,'red')
    await task1(2000,'yellow')
    await task1(1000,'green')
    taskRunner()
}
taskRunner()

//每隔一秒打印1234
for(let i=0;i<5;i++){
    setTimeout(()=>{
        console.log(i)
    },1000*i)
}

//小孩报数

export const lastChildStanding = (num: number,count: number)=>{
    let children  = Array.from({length:num},(item,index)=>index+1)
    let counter = 0;
    while(children.length>1){
        children = children.filter((_,index)=>{
            counter++;
            if(counter===count){
                counter=0;
                return false
            }
            return true
        })
    }
    return children[0]
}
export const lastChildStanding1 = (num: number,count: number)=>{
    let counter=0;
    let allPlayer=[]
    let res=[]
    for(let i=0;i<num;i++){
        allPlayer[i]=i+1
    }
    let exitCount=0;
    let curIndex=0;
    while(exitCount<num-1){
        if(allPlayer[curIndex]!==0) count++;
        if(counter===count){
            allPlayer[curIndex]=0
            count=0;
            exitCount++
        }
        curIndex++
        if(curIndex===num){
            curIndex=0
        }
    }
    for(let i=0;i<num;i++){
        if(allPlayer[i]!==0){
            res.push(allPlayer[i])
        }
    }
    return res;
}

export const imgLoading = (url: any)=>{
    return new Promise((resolve,reject)=>{
        const img = document.createElement('img')
        img.src = url 
        img.onload = ()=>{
            resolve(img)
        }
        img.onerror = (error)=>{
            reject(error)
        }
    })
}

算法题

常见数据结构

数组

export const randomArr = (arr: any[])=>{
    for(let i=0;i<arr.length;i++){
        const randomIndex = Math.round(Math.random()*(arr.length-i-1))
        [arr[i],arr[randomIndex]] = [arr[randomIndex],arr[i]]
    }
    return arr;
}

export const flat = (arr)=>{
    let res =[]
    for(let i=0;i<arr.length;i++){
        if(Array.isArray(arr[i])){
            res = res.concat(flat(arr[i]))
        }else{
            res.push(arr[i])
        }
    }
    return res
}

export const reduceFlat = (arr)=>{
    return arr.reduce((prev,cur)=>{
        return prev.concat(Array.isArray(cur)?reduceFlat(cur):cur)
    })
}

// 实现push
Array.prototype.mypush = ()=>{
    for(let i=0;i<this.arguments;i++){
        this[this.length] = arguments[i]
    }
    return this.length
}

Array.prototype.myfilter = (fn)=>{
    if(typeof fn!=='function'){
        return 'error'
    }
    let res=[]
    for(let i=0;i<this.arguments;i++){
        fn[this[i]]&&res.push(this[i])
    }
    return res;
}

Array.prototype.mymap = (fn)=>{
    if(typeof fn!=='function'){
        return 'error'
    }
    let res=[]
    for(let i=0;i<this.length;i++){
        res.push(fn(this[i]))
    }
    return res;
}

export const myRepeat = (str,time)=>{
    return new Array(time+1).join(str)
}

export const dRepeat  = (str,time)=>{
    return time>0?str.concat(dRepeat(str,time-1)):''
}

// 千分位-含小数位
export const thousand = (num)=>{
    let str = num.toString()
    let strNum = str.split('.')
    let a = strNum[0].split('')
    let b = strNum[1] || ''
    let r=''
    a.reverse().forEach((item,index)=>{
        if(index%3===0){
            r+=item+','
        }else{
            r+=item
        }
    })
    return r+b
}

// 非负大数相加
export const moreAdd = (a,b)=>{
    a = a.split('')
    b = b.split('')
    let res=''
    let temp = 0
    while(a.length||b.length){
        temp+=~~a.pop()+~~b.pop()
        res+=temp%10+res
        temp = temp>9
    }
    return res.replace(/^0+/,'')
}

export const frequencyWord = (text:string)=>{
    const words = text.toLocaleLowerCase().match(/\b(\w+)\b/g)
    let frequency = {}
    let wordMost = ''
    let max=0
    if(words){
        words.forEach((word)=>{
            frequency[word] = frequency[word] || frequency[word]++;
            if(frequency[word]>max){
                max = frequency[word]
                wordMost = word
            }
        })
    }
    return wordMost
}
//查询有序二维数组的目标值
export const search = (matrix,target)=>{
    if(matrix===null || matrix.length===0){
        return false
    }
    let row=0;
    let col = matrix[0].length-1;
    while(row<matrix.length && col>0){
        if(matrix[row][col]===target){
            return true
        }else if(matrix[row][col]>target){
            col--
        }else{
            row++
        }
}
return false
}

export const printArr = (arr:any[])=>{
    const rows = arr.length
    const cols = arr[0].length
    let res = []
    for(let sum=0;sum<rows+cols-2;sum++){
        for(let i=0;i<=sum;i++){
            let j=sum-i
            if(i<rows&&j<cols){
                res.push(arr[i][j])
            }
        }
    }
    return res
}

// 螺旋打印数组-右、下、左、上 
export const spiralPrint = (arr: any[])=>{
    let left = 0;
    let top =0;
    let right = arr[0].length-1;
    let bottom = arr.length-1
    let res= []
    while(left<=right&&top<=bottom){
        for(let i=left;i<=right;i++){
            res.push(arr[top][i])
        }
        top++;
        for(let i=top;i<=bottom;i++){
            res.push(arr[i][right])
        }
        right--;
        if(top<=bottom){
            for(let i=right;i>=left;i--){
                res.push(arr[bottom][i])
            }
            bottom--
        }
        if(left<=right){
            for(let i=bottom;i>=top;i--){
                res.push(arr[i][left])
            }
            left++
        }
        
    }
    return res
}

// 字符串相加
export const addString = (num1: string,num2: string)=>{
    let i = num1.length-1
    let j=num2.length-1
    let res = ''
    let carry=0
    while(i>=0||j>=0){
        let n1 = i>=0?num1[i]:0
        let n2 = j>=0?num2[j]:0
        let temp = Number(n1)+Number(n2)+carry
        res = temp%10+res
        carry = Math.floor(temp/10)
        j--;
        i--
    }
    if(carry===1) res=carry+res
    return res
}

//字符串相乘
export const multiply = (num1: string,num2: string)=>{
    let len1=num1.length
    let len2=num2.length
    let nums = new Array(num1+num2).fill(0)
    for(let i=len1-1;i>=0;i--){
        for(let j=len2-1;j>=0;j--){
            let sum = +num1.charAt(i)*+num2.charAt(j)+nums[i+j+1]
            nums[i+j+1] = sum%10
            nums[i+j] += Math.floor(sum/10)
        }
    }
    let res=''
    let flag=false
    for(let i=0;i<nums.length;i++){
        if(nums[i]!==0){
            flag=true
        }
        if(flag){
            res+=nums[i]
        }
    }
    return res;
}

//版本号比较
export const compareVersion = (version1: string,version2: string)=>{
    let v1 = version1.split('.')
    let v2 = version2.split('.')
    for(let i=0;i<v1.length||i<v2.length;i++){
        let x=0,y=0;
        if(i<v1.length){
            x = parseInt(v1[i])
        }
        if(i<v2.length){
            y = parseInt(v2[i])
        }
        if(x<y){
            return 1
        }
        if(x>y){
            return -1
        }
    }
    return 0;
}

// 匹配字符串
export const  validIPAddress = function(queryIP: string) {
    const ValidIpv4 = (ip: string)=>{
        ip = ip.split('.')
        if(ip.length!==4) return false
        for(let i=0;i<4;i++){
            if(ip[i].length>3 ||ip[i].length<1) return false
            if(ip[i].startsWith('0')&&ip[i].length>1) return false;
            if((+ip[i])>255) return false
            let res = /^[0-9]+$/
            let flag = res.test(ip[i])
            if(!flag) return false 
        }
        return true
    }
    const ValidIpv6 = (ip: string)=>{
        ip = ip.split(':')
        let flag=false
        if(ip.length!==8) return false
        for(let i=0;i<8;i++){
            if(ip[i].length<1||ip[i].length>4) return false
            let  regex = /^[A-Fa-f0-9]+$/;
            flag =  regex.test(ip[i])
            if(!flag) return false
        }
        return true
    }
    if(ValidIpv4(queryIP)){
        return 'IPv4'
    }else if(ValidIpv6(queryIP)){
        return 'IPv6'
    }else{
        return "Neither"
    }
};

排序

  1. 冒泡排序
常见版
export const bubbleSort = (arr: any[])=>{
    for(let i=0;i<arr.length;i++){
        for(let j=0;j<arr.length-i-1;j++){
            if(arr[j+1]>arr[j]){
                let temp = arr[j+1]
                arr[j+1] = arr[j]
                arr[j] = temp
            }
        }
    }
    return arr
}
优化版
由于每一轮交换完成后的部分数组元素是有序的,因此引入标记,当没有数据交换后,表示该数组已经达到有序状态
const bubbleSort = (arr: any[])=>{
    for(let i=0;i<arr.length;i++){
        let isSorted = true
        for(let j=0;j<arr.length-i-1;j++){
            if(arr[j+1]>arr[j]){
                let temp = arr[j+1]
                arr[j+1] = arr[j]
                arr[j] = temp
                isSorted = false
            }
        }
        if(isSorted){
            break;
       }
    }
    return arr
}

引入标记的同时,记录最后一次交换数据的下标,缩减每次对比的数组范围

const bubbleSort = (arr: any[])=>{
    let lastSortedIndex = 0;
    let sortBubble = arr.length-1
    for(let i=0;i<arr.length;i++){
        let isSorted = true
        for(let j=0;j<sortBubble;j++){
            if(arr[j+1]>arr[j]){
                let temp = arr[j+1]
                arr[j+1] = arr[j]
                arr[j] = temp
                isSorted = false
                lastSortedIndex = j
            }
        }
        sortBubble = lastSortedIndex
        if(isSorted){
            break;
        }
    }
    return arr
}

  1. 插入排序
// 与已排序的值进行比较
export const insertSort = (arr: any[])=>{
    for(let i=0;i<arr.length;i++){
        for(let j=0;j<i;j++){
            if(arr[j]<arr[i]){
                let temp = arr[j]
                arr[j]=arr[i]
                arr[i]=temp
            }
        }
    }
    return arr
}
  1. 选择排序
export const selectSort = (arr: any[])=>{
    for(let i=0;i<arr.length;i++){
        let index = i
        for(let j=0;j<arr.length;j++){
            if(arr[j]<arr[index]){
                index = j
            }
        }
        let temp = arr[i]
        arr[i] = arr[index]
        arr[index] = temp
    }
    return arr
}
  1. 合并排序
export const mergeSort = (arr: any[])=>{
   
    function sort(arr: any[],l: any,r: any){
        if(l>=r) return ;
        let mid  = Math.floor((l+r)/2)
        sort(arr,l,mid)
        sort(arr,mid+1,r)
        let i=l,j=mid+1
        let ans=[]
        while(i<=mid&&j<=r){
            if(arr[i]<arr[j]){
                ans.push(arr[i++])
            }else{
                ans.push(arr[j++])
            }
        }
        while(i<=mid) ans.push(arr[i++])
        while(j<=r) ans.push(arr[j++])
    for(let i=0,j=l;j<=r;i++,j++){
            arr[j] = ans[i]
        }
    }
    sort(arr,0,arr.length-1)
    return arr;
}
  1. 快速排序
export const quickSort = (arr: any[])=>{
    function sort(arr: any[],left: any,right: any){
        let mid = arr[Math.floor((left+right)/2)]
        let i = left-1
        let j = right+1
        if(i>j) return ;
        while(i<j){
            do i++; while(arr[i]<mid)
            do j--; while(arr[j]>mid)
            if(i<j){
                [arr[i],arr[j]] = [arr[j],arr[i]]
            }
        }
        sort(arr,left,j)
        sort(arr,j+1,right)
    }
    sort(arr,0,arr.length-1)
}

6.二分查找

// 二分查找
export const findBinary = (arr:any[],target: any)=>{
    if(!arr.length) return -1;
    let i=0,j=arr.length-1
    while(i<j){
        let mid = Math.floor((i+j)/2)
        if(target<arr[mid]){
            j = mid-1
        }else if(target>mid){
            i=mid+1
        }else{
            return mid
        }
    }
    return -1
}

// 二分的使用
// 查找开始位置和结束为止
export const searchRange = (nums: any[],target: any)=>{
    let left = 0;
    let right = nums.length-1
    while(left<=right){
        let mid = Math.floor((left+right)/2)
        if(nums[mid]===target){
            let start=mid
            let end=mid
            while(nums[start--]==target) start--;
            while(nums[end++]===target) end++;
            return [start,end]
        }else if(nums[mid]<target){
            left = mid+1
        }else{
            right = mid-1
        }
    }
    return [-1,-1]
}

7.合并有序数组


export const mergeArr = (arr1:any[],arr2: any[]) =>{
    let ans = []
    let i=0,j=0
    while(i<arr1.length && j<arr2.length){
        if(arr1[i]<arr2[j]){
            ans.push(arr1[i++])
        }else{
            ans.push(arr2[j++])
        }
    }
    while(i<arr1.length) ans.push(arr1[i++])
    while(j<arr2.length) ans.push(arr2[j++])
    return ans
}

// 合并两个有序数组,只改变nums1,不返回任何值
export const mergeArrs = (nums1: any,m: any,nums2:any,n: any)=>{
    let p1=0,p2=0;
    var cur
    const arr = new Array(m+n).fill(0)
    while(p1<m||p2<n){
        if(p1===m){
            cur=nums2[p2++]
        }else if(p2===n){
            cur=nums1[p1++]
        }else if(nums1[p1]<nums2[p2]){
            cur = nums1[p1++]
        }else{
            cur = nums2[p2++]
        }
        arr[p1+p2-1]=cur
    }
    for(let i=0;i!=m+n;++i){
        nums1[i] = arr[i]
    }
}

链表

// 合并有序链表
function ListNode(val: any, next: any) {
        this.val = (val===undefined ? 0 : val)
        this.next = (next===undefined ? null : next)
}

export const mergeList = (l1: any,l2: any)=>{
    if(l1===null){
        return l2
    }else if(l2===null){
        return l1
    }else if(l1.val<=l2.val){
        l1.next = mergeList(l1.next,l2)
        return l1
    }else{
        l2.next = mergeList(l1,l2.next)
        return l2
    }
}
// 链表倒叙(插入、查找、删除、排序)

export const reverseList = (head: any)=>{
    let prev = null
    let cur = head
    while(cur){
        let next = cur.next
        cur.next = prev
        prev = cur
        cur = cur.next
    }
}

// 反转链表的一部分[left,right]
export const reverseBetween = (head,left,right)=>{
    const dummy = new ListNode()
    dummy.next = head
    let node = dummy
    for(let i=1;i<left;i++){
        node = node.next
    }
    head = node.next
    for(let i=left;i<right;i++){
        let next = head.next
        head.next = next.next
        next.next = node.next
        node.next = next
    }
    return dummy.next
}

// delete node
export const deleteList = (head,target)=>{
    let dummy = new ListNode()
    dummy.next = head
    let cur = dummy
    while(cur&&cur.next){
        if(cur.next.val===target){
            cur.next = cur.next.next
        }else{
            cur = cur.next
        }
    }
    return dummy.next
}

export const findNode = (head: any,target: any)=>{
    let cur = head
    while(cur){
        if(cur.val===target){
            return true
        }else{
            cur = cur.next
        }
    }
    return false
}

export const insertNode = (head: any,target: any,index: any)=>{
    let cur = head
    for(let i=1;i<index;i++){
        cur=cur.next
    }
    let node = new ListNode(target)
    node.next = cur.next
    cur.next  = node
    
}

// 判断链表是否为循环链表/找到循环链表的入口/找到链表的中间节点//
export const isCycleList = (head: any)=>{
    if(!head) return ;
    let fast = head,slow = head
    while(fast&&fast.next){
        slow=slow.next
        fast = fast.next.next
        if(fast===slow){
            return true
        }
    }
    return false
}

export const findCycleList = (head: any)=>{
    if(!head) return ;
    const map = new Map()
    while(head){
        if(!map.has(head)){
            map.set(head)
        }else{
            return head
        }
        head = head.next
    }
    return null
}
// 相交链表
export const getIntersectionNode = (headA: any,headB: any)=>{
    if(!headA||!headB) return null;
    let lenA=0,lenB=0
    let p=headA,q=headB
    while(headA){
        lenA++
        headA = headA.next
    }
    while(headB){
        lenB++
        headB = headB.next
    }
    if(lenA>lenB){
        for(let i=lenB;i<lenA;i++){
            p = p.next
        }
    }else{
        for(let i=lenA;i<lenB;i++){
            q=q.next
        }
    }
    while(q&&p){
        if(q===p) return q;
        q=q.next
        p=p.next
    }
}

// 交换第i个和第n-i-1链表中的节点

export const swapNode = (head: any)=>{
    if(!head) return null
    let p = head
    let queue = []
    while(p){
        queue.push(p)
        p=p.next
    }
    while(queue.length>2){
        let h = queue.shift()
        let t = queue.pop()
        t.next = h.next
        h.next = t
    }
    queue[queue.length-1].next = null
    return queue
}

//两两交换链表中的节点
export const swapPairs = (head: any)=>{
    const dummy = new ListNode(0)
    const prev = dummy
    dummy.next = head
    while(head&&head.next){
        const next = head.next
        head.next = next.next
        prev.next = next
        next.next = head
        prev=head
        head=head.next
    }
    return dummy.next
}

// 删除链表中倒数第n个数

export const removeNthFromEnd = (head: any,n: any)=>{
    if(!head) return null
    let fast = head
    let slow= head
    while(n--){
        fast = fast.next
    }
    if(!fast){
        return head.next
    }
    while(fast&&fast.next){
        fast = fast.next
        slow = slow.next
    }
    slow.next = slow.next.next
    return head
}

// 删除链表中重复的节点
export const removeRepeat = (head: any)=>{
    if(!head) return null
    let dummy = new ListNode()
    dummy.next = head
    let cur = dummy
    while(cur.next&&cur.next.next){
        if(cur.next.val===cur.next.next.val){
            let next = cur.next.val
            while(cur.next&&cur.next.val===next){
                cur.next = cur.next.next
            }
        }else{
            cur = cur.next
        }
        
    }
    return dummy.next
}

//链表排序
export const sortList = (head:any)=>{
    const merge = (l1,l2)=>{
        const dummy = new ListNode()
        let cur = dummy
        let h1 = l1,h2 = l2
        while(h1!==null&&h2!==null){
            if(h1.val<h2.val){
                cur.next = h1
                h1=h1.next
            }else{
                cur.next = h2
                h2 = h2.next
            }
            cur = cur.next
        }
        if(h1!==null){
            cur.next  = h1
            h1 = h1.next
        }else if(h2!==null){
            cur.next = h2
            h2 = h2.next
        }
        return dummy.next
    }
    const toSortList = (head,tail)=>{
        if(head.next===tail){
            head.next = null
            return head
        }
        let fast = head,slow=head
        while(fast!==tail){
            slow = slow.next
            fast = fast.next
            if(fast!==tail){
                fast=fast.next
            }
        }
        let mid = slow
    }
    return mergeArr(toSortList(head,mid),toSortList(mid,tail))
}

// k个一组翻转链表
export const transLists = (head,k)=>{
    const HEAD = new ListNode()
    let node = HEAD
    if(head===null) return null;
    while(head){
        let curNode = head
        let stackArr=[]
        for(let i=0;i<k;i++){
            if(!curNode){
                node.next = head
                return HEAD.next
            }
            stackArr.push(curNode)
            curNode = curNode.next
        }
        for(let i=k-1;i>=0;i--){
            node.next = stackArr[i]
            node=node.next
        }
        head = curNode
    }
    node.next = null
    return HEAD.next
}

// 树的遍历(前序、中序、后序、dfs/bfs)

export const  preOrder = (root: any)=>{
    let res = []
    if(!root) return res;
    const dfs  = (root: any)=>{
        if(!root) return ;
        res.push(root.val)
        dfs(root.left)
        dfs(root.right)
    }
    dfs(root)
    return res
}

export const  inOrder = (root: any)=>{
    let res = []
    if(!root) return res;
    const dfs  = (root: any)=>{
        if(!root) return ;
        dfs(root.left)
        res.push(root.val)
        dfs(root.right)
    }
    dfs(root)
    return res
}

export const  postOrder = (root: any)=>{
    let res = []
    if(!root) return res;
    const dfs  = (root: any)=>{
        if(!root) return ;
        dfs(root.left)
        dfs(root.right)
        res.push(root.val)
    }
    dfs(root)
    return res
}

// 层次优先遍历
export const bfs = (root: any)=>{
    let res = []
    if(!root) return res
    let queue=[]
    queue.push(root)
    while(queue.length){
        let size  = queue.length
        res.push([])
        for(let i=0;i<size;i++){
            let node = queue.shift()
            res[res.length-1].push(node.val)
            if(node.left) queue.push(node.left)
            if(node.right) queue.push(node.right)
        }
    }
    return res
}

// 二叉树的最大深度

export const maxDepth = (root: any)=>{
    if(!root) return 0;
    let left = maxDepth(root.left)
    let right = maxDepth(root.right)
    return Math.max(left,right)+1
}

// 二叉树的最大宽度
export const maxWidth  = (root: any)=>{
    if(!root) return 0;
    let queue =[]
    let max = BigInt(1)
    queue.push([root,BigInt(1)])
    while(queue.length){
        let size  = queue.length
        for(let i=0;i<size;i++){
            let [node,index] = queue.shift()
            if(node.left){ 
                queue.push([node.left,index*BigInt(2)])
            }
            if(node.right){
                queue.push([node.right,index*BigInt(2)+BigInt(2)+BigInt(1)])
            } 
        }
        if(queue.length){
            let start = queue[0][1]
            let end = queue[queue.length-1][1]
            let len = end-start+BigInt(1)
            if(len>max){
                max = len
            }
        }
    }
    return max
}   

// 平衡二叉树(左右子节点高度差小于1)

export const isBalanced = (root: any)=>{
    if(!root) return true;
    const height = (root: any)=>{
        if(!root) return 0;
        return Math.max(height(root.left),height(root.right))+1
    }
    let left = height(root.left)
    let right = height(root.right)
    if(Math.abs(left-right)>1){
        return false
    }
    return isBalanced(root.left) && isBalanced(root.right)
}

//对称二叉树
export const isSymmetry = (root: any)=>{
    if(!root) return true;
    const isMirror = (node1: any,node2: any)=>{
        if(node1===null&&node2===null) return true
        if(node1===null||node2===null) return false
        return (node1.val===node2.val)&&isMirror(node1.left,node2.right)&&isMirror(node1.right,node2.left)
    }
    return isMirror(root.left,root.right)
}

//从左向右看能看到的所有二叉树的节点(从右向左)
export const leftView = (root: any)=>{
    let res =[]
    if(!root) return res;
    let queue = []
    queue.push(root)
    while(queue.length){
        let size = queue.length
        for(let i=0;i<size;i++){
            let node = queue.shift()
            if(i===0) res.push(node.val)   // if(i===size-1) (从右向左看)
            if(node.left) queue.push(node.left)
            if( node.right) queue.push(node.right)
        }
    }
    return res;
}

//二叉树的叶子节点

export const leafNode = (root: any)=>{
    let res = []
    if(!root) return res;
    const dfs = (root:any)=>{
        if(!root) return;
        if(!root.left&&!root.right&&root) res.push(root.val)
        dfs(root.left)
        dfs(root.right)
    }
    return res;
}


// 二叉树的最近公共祖先
export const lowestCommonAncestor = (root: any,p: any,q: any)=>{
    if(!root) return null
    if(root===p||root===q) return root;
    let left =lowestCommonAncestor(root.left,p,q)
    let right = lowestCommonAncestor(root.right,p,q)
    if(left&&right){
        return root
    }else if(left){
        return left
    }else if(right){
        return right
    }
}

// 二叉树的最大路径和(不重复路径)/最小路径和/路径总和/
export const maxPathSum = (root: any)=>{
    let max=0
    if(!root) return max;
    const dfs = (root:any)=>{ 
        let left = dfs(root.left)
        let right  = dfs(root.right)
         max = Math.max(max,left+right+root.val)
         return root.val+Math.max(left,right)
        
    }
    dfs(root)
    return max
}

// 从前序遍历和中序遍历得到树
export const buildTree = (preorder: any[],inorder: any[])=>{
    if(!preorder.length) return null;
    let root = new TreeNode(preorder[0])
    let mid = inorder.findIndex((item)=>item===preorder[0])
    root.left = buildTree(preorder.slice(1,mid+1),inorder.slice(0,mid))
    root.right = buildTree(preorder.slice(mid+1,preorder.length),inorder.slice(mid+1,inorder.length))
    return root;
}

//从中序遍历和后序遍历得到树
export const buildTree1 = (inorder: any[],postorder: any[])=>{
    if(!inorder.length) return null;
    let node = postorder.pop()
    let root = new TreeNode(node)
    let mid = inorder.findIndex((item)=>item===node)
    let left = buildTree(inorder.slice(0,mid),postorder.slice(0,mid))
    let right = buildTree(inorder.slice(mid+1),postorder.slice(mid))
    return root;
}

// 二叉树的所有路径
export const allPath = (root: any)=>{
    let res = []
    let path = []
    if(!root) return res;
    const dfs = (root,path)=>{
        if(root){
            path.push(root.val)
            if(!root.left&&!root.right){
                return res.push([...path])
            }else{
                dfs(root.left,path)
                dfs(root.right,path)
            }
        }
    }
    dfs(root,path)
    return res;
}

//二叉树的完全性检验
export const isCompleteTree = (root: any)=>{
    let end = false
    if(!root) return true
    const queue = [root]
    while(queue.length){
        let size = queue.length
        for(let i=0;i<size;i++){
            let node = queue.shift()
            if(node===null){
                end = true
            }else{
                if(end) return false;
                queue.push(node.left);
                queue.push(node.right);
            }
        }
    }
    return true
}
// 验证搜索二叉树
export const isValidBST = (root: any)=>{
    let prev=root
    const dfs = (root: any)=>{
        if(!root) return true
        let left = dfs(root.left)
        if(prev!==null&&prev.val>root.val){
            return false
        }
        prev=root
        let right = dfs(root.right)
        return left&&right
    }
    return dfs(root)
}
// 二叉树展开为链表
export const treeToList = (root)=>{
    if(!root) return null;
    let res = []
    preOrder(root,res)
    const size = res.length
    for(let i=1;i<size;i++){
        let prev=res[i-1],cur=res[i]
        prev.left=null
        prev.right=cur
    }
}

// 二叉树中和为某个值的所有路径
export const targetPath = (root,target)=>{
    let res=[],path=[]
    if(!root) return res
    const dfs = (root,path,num)=>{
        path.push(root.val)
        if(!root.left&&!root.right){
            if(num===root.val){
                res.push([...path])
            }
        }
        if(root.left){
            dfs(root.left,path,num-root.val)
        }
        if(root.right){
            dfs(root.right,path,num-root.val)
        }
    }
    dfs(root,path,target)
    return res
}

// 检测循环依赖
// 课程是否可以修完//拓扑排序
export const canFinish = (numCourses: any,prerequisites: any[])=>{
    const inDegree = new Array(numCourses).fill(0)
    const map={}
    for(let i=0;i<prerequisites.length;i++){
        inDegree[prerequisites[i][0]]++;
        if(map[prerequisites[i][1]]){
            map[prerequisites[i][1]].push(prerequisites[i][0])
        }else{
            map[prerequisites[i][1]]=[prerequisites[i][0]]
        }
    }
    const queue=[]
    for(let i=0;i<inDegree.length;i++){
        if(inDegree[i]===0) queue.push(i)
    }
    const res=[]
    while(queue.length){
        let cur = queue.shift()
        res.push(cur)
        let toEnqueue = map[cur]
        if(toEnqueue&&toEnqueue.length){
            for(let i=0;i<toEnqueue.length;i++){
                inDegree[toEnqueue[i]]--
                if(inDegree[toEnqueue[i]])===0 queue.push(toEnqueue[i])
            }
        }
    }
    if(res.length!==numCourses) return false
    return res;
}
普里姆+krusal+迪杰斯特拉
// prim算法(最小生成树)
// 首先定义一个数组,用来存放已经加入最小生成树的顶点,初始时数组为空。
// 再定义一个数组,用于存储每个顶点到最小生成树的最小权值,初始时数组的值为第一个顶点到其余各个顶点的权值。
// 最后定一个数组,用于记录当前节点是否被访问过,初始时数组的值为false。
export const prim = (graph: any,v:any)=>{
    const parent = new Array(graph.length).fill(-1)
    const visited = new Array(graph.length).fill(false)
    let minHeight = 10000
    visited[v] = true;
    let l = 0,r=0;
    for(let k=1;k<graph.length;k++){
        for(let i=0;i<graph.length;i++){
            for(let j=0;j<graph.length;j++){
                if(graph[i][j]&&visited[i]&&!visited[j]&&graph[i][j]<minHeight){
                    minHeight = graph[i][j]
                    l=i
                    r=j
                }
            }
        }
    }

    parent.push([l,r])
    visited[r]=true
    minHeight=1000
}

// kruskal算法(最小生成树)
// 首先将图中所有的边按照权值从小到大排序。
// 然后从权值最小的边开始,如果这条边的两个顶点不在同一棵树上,则将这条边加入最小生成树中。
class UnionFind{
    constructor(n){
        this.parent = new Array(n).fill(0).map((value,index)=>index)
    }
    find(x){
        if(this.parent[x]!==x){
            this.parent[x] = this.find(this.parent[x])
        }
        return this.parent[x]   
    }
    union(x,y){
        this.parent[this.find(x)] = this.parent[y]   //合并时,将y的父节点作为x的根节点
    }
}
function krusal (graph){
    const edges = []
    const unionFind = new UnionFind(graph.length)
    const mst = []
    for(let i=0;i<graph.length;i++){
        for(let j=i+1;j<graph.length;j++){
            if(graph[i][j]){
                edges.push(i,j,graph[i][j])
            }
        }
    }
    edges.sort((a,b)=>a[2]-b[2])
    for(let i=0;i<graph.length;i++){
        const [u,v] = edges[i]
        if(unionFind.find[u]!==unionFind.find[v]){  // 判断两个节点是否在同一棵树上
            unionFind.union(u,v)
            mst.push(edges[i])
        }
    }
    return mst
}

// 迪杰斯特拉(需要补充)

贪心算法

// 合并区间
export const distance = (intervals: any[])=>{
    let ans = []
    intervals.sort((a,b)=>a[0]-b[0])
    let prev = intervals[0]
    for(let i=0;i<intervals.length;i++){
        let cur = intervals[i]
        if(prev[1]>=cur[0]){
            prev[1] = Math.max(prev[1],cur[1])
        }else{
            ans.push(prev)
            prev=cur
        }
    }
    ans.push(prev)
    return ans
}

// 和为k的子数组个数
export const subarraySum = (nums: any[],k: any)=>{
    let map = new Map()
    map.set(0,1)
    let pre = 0
    let count = 0
    for(let i=0;i<nums.length;i++){
        pre+=nums[i]
        if(map.has(pre-k)){
            count+=map.get(pre-k)
        }
        map.set(pre,(map.get(pre)||0)+1)
    }
    return count
} 

// 最长连续子序列
export const longestConsecutive = (nums: any[])=>{
    let set = new Set(nums)
    let max= 0;
    for(let num of nums){
        if(!set.has(num-1)){
            let cur= num
            let count=1
            while(set.has(cur+1)){
                cur++;
                count++
            }
            max = Math.max(max,count)
        }
    }
    return max;
}

回溯+剪枝


// n皇后问题/
export const solveNQueens = (n: any)=>{
    const board:string[][] = new Array(n).fill(0).map(()=>new Array(n).fill('.'))
    const res: string[][] = []
    const isValid = (row: any,col: any)=>{
        for(let i=0;i<col;i++){
            if(board[row][i]==='Q'){
                return false
            }
            for(let i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
                if(board[i][j]==='Q'){
                    return false
                }
            }
            for(let i=row-1,j=col+1;i>=0&&j<n;i--,j++){
                if(board[i][j]==='Q'){
                    return false
                }
            }
        }
        return true
    }
    const dfs = (row: any)=>{
        if(row===n){
            res.push(board.map(row=>row.join('')))
            return;
        }
        for(let i=0;i<n;i++){
            if(!isValid(row,i)){
                continue;
            }
            board[row][i]='Q'
            dfs(row++)
            board[row][i]='.'
        }
    }
    dfs(0)
    return res;
}

// 给出一数字/全排列/不重复的全排列/子集/子集2
export const allRes = (nums: any[])=>{
    let res = []
    let path = []
    let used = new Array(nums.length).fill(false)
    const dfs = (nums,k,used)=>{
        if(k===path.length){
            res.push([...path])
            return ;
        }
        for(let i=0;i<k;i++){
            if(used[i]) continue;
            used[i]=true
            path.push(nums[i])
            dfs(nums,k,used)
            path.pop()
            used[i]=false
        }
    }
    dfs(nums,nums.length,used)
    return res
}

// 不重复的全排列
export const noRepeat = (nums: any[])=>{
    let res = [],path=[]
    let uesd= new Array(nums.length).fill(false)
    const dfs = (nums,index,used)=>{
        if(index===nums.length){
            res.push([...path])
            return ;
        }
        for(let i=0;i<nums.length;i++){
            if(used[i]||i>0&&nums[i]===nums[i-1]&&!used[i-1]) continue
            path.push(nums[i])
            used[i]=true
            dfs(nums,index+1,used)
            path.pop()
            used[i]=false
        }
    }
    dfs(nums,0,used)
    return res;
}

// 下一个排列
export const nextPermutation = (nums: any[])=>{
    let i = nums.length-2
    while(i>=0&&nums[i]>nums[i+1]){
        i--
    }
    if(i>0){
        let j=nums.length-1
        while(j>0&&nums[j]<nums[i]){
            j--
        }
        if(i<j){
            [nums[i],nums[j]] =  [nums[j],nums[i]]
        }
    }
    let l=i+1
    let r = nums.length-1
    while(l<r){
        [nums[l],nums[r]] = [nums[r],nums[l]]
        l++;r--;
    }

}
// 子集
export const subsets = (nums: any[])=>{
    let res=[],path=[]
    const dfs = (nums: any,path: any,startIndex: any)=>{
        res.push([...path])
        for(let i=startIndex;i<nums.length;i++){
            path.push(nums[i])
            dfs(nums,path,i+1)
            path.pop()
        }
    }
    dfs(nums,path,0)
    return res
}

// 有效的括号

    export const valid = (s: string)=>{
        s.split('')
        if(s.length%2) return false
        let stack = []
        let map = new Map([[')','('],[']','['],['}','{']])
        for(let i of s){
            if(map.get(i)){
                if(stack[stack.length-1]!==map.get(i)) return false;
                else stack.pop()
            }else{
                stack.push(i)
            }
        }
        return stack.length===0
    }

// 网格中岛屿的数量
export const numIslands = (grid: any[])=>{
    if(!grid.length) return 0;
    let row = grid.length
    let col = grid[0].length
    let count = 0
    for(let i=0;i<row;i++){
        for(let j=0;j<col;j++){
            if(grid[i][j]==='1'){
                count++;
                toZero(grid,i,j)
            }
        }
    }
    function toZero(grid: any[],i: any,j: any){
        if( i>=grid.length|| j>=grid[0].length||i<0||j<0 || grid[i][j]==='0' ) return ;
        grid[i][j] = 0;
        toZero(grid,i-1,j)
        toZero(grid,i+1,j)
        toZero(grid,i,j+1)
        toZero(grid,i,j-1)
    }
    return count
}


// 复原ip地址(排列组合)
export const restoreIpAddresses = (s: string)=>{
    let res = []
    const dfs = (subRes: any,start: any)=>{
        if(subRes.length===4&&start===s.length){
            res.push(subRes.join('.'))
            return ;
        }
        if(subRes.length===4&&start<s.length){
            return ;
        }
        for(let i=1;i<=3;i++){
            if(i+start-1>=s.length) return;
            if(i!==1&&s[start]==='0') return;
            let str = s.substring(start,start+i)
            if(i>=3&&+str>255) return;
            subRes.push(str)
            dfs(subRes,start+i)
            subRes.pop()
        }
    }
    dfs([],0)
    return res;
}

// 括号的生成(dfs)
export const generateParenthesis = (n: number)=>{
    let outArr=[]
    const dfs=(str: string,left: any,right: any)=>{
        if(left>n||right>n||left>right){
            return;
        }
        if(left===n&&right===n){
            outArr.push(str)
            return;
        }
        dfs(str+')',left+1,right)
        dfs(str+'(',left,right+1)
    }
    dfs('',0,0)
    return outArr;
}

动态规划

// 买卖股票的最佳时机I(选择某一天买入,某一天卖出,得到最大利润)
export const maxProfit1 = (prices: any[])=>{
    let low = Infinity
    let max = 0
    for(let i=0;i<prices.length;i++){
        max = Math.max(max,prices[i])
        low = Math.min(low,prices[i])
    }
    return max
}

//买卖股票的最佳时机II(在每一天,你可以决定是否购买和/或出售股票)
export const maxProfit2 = (prices: any[])=>{
    let max = 0;
    for(let i=1;i<prices.length;i++){
        if(prices[i]>prices[i-1]){}
        max+=prices[i]-prices[i-1]
    }
    return max
}
// 买卖股票的最佳时机III(只能交易两次)
export const maxProfit3 = (prices: any[])=>{
    if(prices.length===0) return 0;
    let buy1 = -prices[0]
    let sell1 = 0
    let buy2 = -prices[0]
    let ssell2=0;
    for(let i=1;i<=prices.length;i++){
        buy1 = Math.max(buy1,-prices[i])
        sell1 = Math.max(sell1,buy1+prices[i])
        buy2 = Math.max(buy2,sell1-prices[i])
        sell2 = Math.max(sell1,buy2+prices[i])
    }
    return sell2
}
// 买卖股票的最佳时机III(只能交易k次)
export const maxProfit4 = (prices: any[],k: any)=>{
    if(!prices.length) return 0;
    let n = prices.length
    k = Math.min(k,Math.floor(n/2))
    const buy = new Array(n).fill(0).map(()=>new Array(k+1).fill(0))
    const sell = new Array(n).fill(0).map(()=>new Array(k+1).fill(0))
    buy[0][0]=-prices[0]
    sell[0][0]=0;
    for(let i=1;i<=k;i++){
        buy[0][i]=sell[i][0]=-Number.MAX_VALUE
    }
    for(let i=1;i<n;i++){
        buy[i][0] = Math.max(buy[i-1][0],sell[i-1][0]-prices[i])
        for(let j=1;j<=k;j++){
            buy[i][j]=Math.max(buy[i-1][j],sell[i-1][j]-prices[i])
            sell[i][j] = Math.max(sell[i-1][j],buy[i-1][j-1]+prices[i])
        }
    }
    return Math.max(...sell[n])
}

// 最长递增子序列
export const lengthOfLIS = (nums: any[])=>{
    let len = nums.length
    if(len===0) return 0;
    let ans = 1;
    const dp =new Array(len).fill(1)
    for(let i=1;i<len;i++){
        for(let j=0;j<i;j++){
            if(nums[j]<nums[i]){
                dp[i] = Math.max(dp[i],dp[j]+1)
            }
        }
        ans  = Math.max(ans,dp[i])
    }
    return ans;
}

// 编辑距离 -三种方式:插入、删除、替换
export const editDstance = (w1: string,w2: string)=>{
    let l1 = w1.length
    let l2 = w2.length
    const dp = new Array(l1+1).fill(0).map(()=>new Array(l2+1).fill(0))
    for(let i=1;i<=l1;i++) dp[i][0]=dp[i-1][0]+1 
    for(let i=1;i<=l2;i++) dp[0][i]=dp[0][i-1]+1
    for(let i=1;i<=l1;i++){
        for(let j=1;j<=l2;j++){
            if(w1[i-1]===w2[j-1]){
                dp[i][j] = dp[i-1][j-1]
            }else{
                dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1
            }
        }
    }
    return dp[l1][l2]
}

// 最长公共子序列
export const longestCommonSubsequence = (text1: string,text2: string)=>{
    let m=text1.length
    let n=text2.length
    const dp = new Array(m+1).fill(0).map(()=>new Array(n+1).fill(0))
    for(let i=1;i<=m;i++){
        for(let j=1;j<=n;j++){
            if(text1[i-1]===text2[j-1]){
                dp[i][j] = dp[i-1][j-1]+1
            }else{
                dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1])
            }
        }
    }
    return dp[m][n]
}

// 零钱兑换
export const coinChange = (coins: any[],amount: any)=>{
    const dp = new Array(amount+1).fill(Infinity)
    dp[0]=0;
    for(let i=1;i<=amount;i++){
        for(let coin of coins){
            if(i-coin>=0){
                dp[i] = Math.min(dp[i],dp[i-coin]+1)
            } 
        }
    }
    return dp[amount]===Infinity?-1:dp[amount]
}

// 零钱兑换的组合
export const change = (amount: any,coins: any[])=>{
    const dp = new Array(amount+1).fill(0)
    dp[0]=1;
    for(let coin of coins){
        for(let i=coin;i<=amount;i++){
            dp[i] += dp[i-coin]
        }
    }
    return dp[amount]
}

// 单词拆分
export const wordBreak = (s: string,wordDict: string[])=>{
    let dp = new Array(s.length+1).fill(false)
    dp[0]=true
    for(let i=1;i<=s.length;i++){
        for(let j=0;j<i;j++){
            if(dp[j]&&wordDict.includes(s.substring(j,i))){
                dp[i]=true
                break;
            }
        }
    }
    return dp[s.length]
}

// 乘积最大的子数组
export const maxProduct = (nums: any[])=>{
    let res=nums[0]
    let temp1=0,temp2=0
    let prevMax=nums[0],prevMin= nums[0]
    for(let i=1;i<nums.length;i++){
        temp1=nums[i]*prevMin
        temp2 = nums[i]*prevMax
        prevMin = Math.min(temp1,temp2,nums[i])
        prevMax = Math.max(temp1,temp2,nums[i])
        res = Math.max(res,prevMax)
    }
    return res;
}

滑动窗口

// 不重复字符串的最大长度

export const maxlength = (s:string)=>{
    let res=0;
    let i=-1;
    let m = new Map()
    for(let j=0;j<s.length;j++){
        if(m.has(s[j])){
            i = Math.max(i,m.get(s[j]))
        }
        m.set(s[j],j)
        res = Math.max(res,j-i)
    }
    return res
}

// 判断s1是否为s2的子串
export const isSubString = (s1: string,s2: string)=>{
    if(s1.length>s2.length) return false;
    const count = new Array(26).fill(0);
    for(let i=0;i<s1.length;i++){
        count[s1.charCodeAt(i)-'a'.charCodeAt(0)]++;
        count[s2.charCodeAt(i)-'a'.charCodeAt(0)]--;
    }
    if(count.every(item=>item===0)) return true;
    for(let i=s1.length;i<s2.length;i++){
        count[s2.charCodeAt(i)-'a'.charCodeAt(0)]--
        count[s2.charCodeAt(i-s1.length)-'a'.charCodeAt(0)]++;
        if(count.every(item=>item===0)) return true;
    }
    return false
}



// 滑动窗口内的最大值
export const maxSlidingWindow = (nums: any[],k: any)=>{
    let q=[]
    for(let i=0;i<k;i++){
        while(q.length&&nums[i]>=nums[q[q.length-1]]){
            q.pop()
        }
        q.push(i)
    }
    let ans = [nums[q[0]]]
    for(let i=k;i<nums.length;i++){
        while(q.length&&nums[i]>=nums[q[q.length-1]]){
            q.pop()
        }
        q.push(i)
        if(i-k>=q[0]){
            q.shift()
        }
        ans.push(nums[q[0]])
    }
    return ans
}