前端算法题

目录

算法相关资料

1.有效的括号

2.删除字符串中所有的相邻重复项

3.简化路径

4.最近的请求次数

5.环形链表

6.删除链表中的节点

7.删除链表中的重复元素

8.反转链表

9.两数之和

10.存在重复元素

11.两个数组的交集

12.独一无二的出现次数

13.无重复字符的最长子串

14.二叉树的前序遍历

15.二叉树的中序遍历

16.二叉树的后序遍历

17.二叉树的最小深度

18.二叉树的最大深度

19.翻转二叉树

20.相同的树

21.数组中的第k个最大元素

22.猜数字大小

23.多数元素

24.爬楼梯

25.打家劫舍

26.跳跃游戏

27.分发饼干

28.买卖股票的最佳时机2

29.字符串解码

30.Pow(x, n)


算法相关资料

js 数据结构_js中的数据结构-CSDN博客  

[译] JavaScript 中的数据结构:写给前端软件工程师 - 掘金

【精选】Js中常见的数据结构(Data Structure)_js数据结构_傻乎乎的小不点的博客-CSDN博客

JS 常见的排序算法_js排序算法_东风过境F的博客-CSDN博客

动态规划详解_Meiko丶的博客-CSDN博客

【精选】贪心算法(greedy algorithm,又称贪婪算法)详解(附例题)-CSDN博客

代码随想录

1.有效的括号

题目:

解法:

var isValid = function(s) {
    const stack = []
    for(let i = 0; i < s.length; i++) {
        const start = s[i]
        if(s[i] == '(' || s[i] == '{' || s[i] == '[') {
            stack.push(s[i])
        } else {
            const end = stack[stack.length - 1]
            if(start == ')' && end == '(' || start == '}' && end == '{' || start == ']' && end == '[' ) {
                stack.pop()
            } else {
                return false
            }
        }
    }
    return stack.length == 0
}

2.删除字符串中所有的相邻重复项

题目:

解法:

var removeDuplicates = function(s) {
    let stack = []
    for(let v of s) {
        if(stack[stack.length - 1] != v) {
            stack.push(v)
        } else {
            stack.pop()
        }
    }
    return stack.join('')
}

3.简化路径

题目:

解法:

var simplifyPath = function(path) {
    let stack = []
    let str = ''
    let arr = path.split('/')
    arr.forEach( val => {
        if(val && val == '..') {
            stack.pop()
        } else if(val && val != '.') {
            stack.push(val)
        }
    })
    arr.length ? str = '/' + stack.join('/') : str = '/'
    return str
}

4.最近的请求次数

题目:

解法:

var RecentCounter = function() {
    this.stack = []
}

RecentCounter.prototype.ping = function(t) {
    this.stack.push(t)
    while(this.stack[0] < t - 3000) {
        this.stack.shift()
    }
    return this.stack.length
}

5.环形链表

题目:

解法:

var hasCycle = function(head) {
    // 快慢指针初始化指向head
    let f = head, s = head
    // 快指针走到末尾时停止
    while(f && f.next) {
        // 慢指针走一步,快指针走两步
        s = s.next
        f = f.next.next
        // 快慢指针相遇,说明含有环
        if(s == f) {
            return true
        }
    }
    // 不包含环
    return false
}

6.删除链表中的节点

题目:

解法:

var deleteNode = function(node) {
    node.val = node.next.val
    node.next = node.next.next
}

7.删除链表中的重复元素

题目:

解法:

var deleteDuplicates = function(head) {
    if(!head) {
        return head
    }
    // 指定cur指针指向头部head
    let cur = head
    while(cur && cur.next) {
        if(cur.val == cur.next.val) {
            cur.next = cur.next.next
        } else {
            cur = cur.next
        }
    }
    return head
}

8.反转链表

题目:

解法:

var reverseList = function(head) {
    let prev = null
    let curr = head
    while(curr) {
        // 将curr的下一个节点储存在变量里
        const next = curr.next
        // 让curr的下一个节点指针指向prev
        curr.next = prev
        // 将prev和curr往后顺移一位
        prev = curr
        curr = next
    }
    // 此时prev为头节点
    return prev
}

9.两数之和

题目:

解法:

var twoSum = function(nums, target) {
    const map = new Map() 
    for(let i = 0; i < nums.length; i++) {
        let num = target - nums[i]
        if(map.has(num)) {
            return [map.get(num), i]
        } else {
            map.set(nums[i], i)
        }
    }
    return []
}

10.存在重复元素

题目:

解法:

var containsDuplicate = function(nums) {
    const map = new Map()
    for(let i of nums) {
        if(map.has(i)) {
            return true
        } else {
            map.set(i, 1)
        }
    }
    return false
}

11.两个数组的交集

题目:

解法:

var intersection = function(nums1, nums2) {
    const set = new Set(nums2)
    return [...new Set(nums1)].filter((val) => set.has(val))
}

12.独一无二的出现次数

题目:

解法:

var uniqueOccurrences = function(arr) {
    const map = new Map()
    for(let i of arr) {
        if(map.has(i)) {
            map.set(i, map.get(i) + 1)
        } else {
            map.set(i, 1)
        }
    }
    const set = new Set() 
    for(let [key, value] of map) {
        set.add(value)
    }
    return set.size == map.size
}

13.无重复字符的最长子串

题目:

解法1(队列):

var lengthOfLongestSubstring = function(s) {
    let res = []
    let max = 0
    for(let str of s) {
        while(res.includes(str)) {
            res.shift()
        }
        res.push(str)
        max = Math.max(max, res.length)
    }
    return max
}

解法2(滑动窗口):

var lengthOfLongestSubstring = function(s) {
    const map = new Map()
    // 左指针
    let l = 0
    let max = 0
    for(let i = 0; i < s.length; i++) {
        if(map.has(s[i]) && map.get(s[i]) >= l) {
            l = map.get(s[i]) + 1
        }
        map.set(s[i], i)
        max = Math.max(max, i-l+1)
    }
    return max
}

14.二叉树的前序遍历

题目:

解法1(递归):

var preorderTraversal = function(root) {
    let arr = []
    const fun = (node) => {
        if(node) {
            // 遍历根节点
            arr.push(node.val)
            // 遍历左子树
            fun(node.left)
            // 遍历右子树
            fun(node.right)
        }
    }
    fun(root)
    return arr
}

解法2(栈):

var preorderTraversal = function(root) {
    if(!root) return []
    let arr = []
    // 根节点入栈
    let stack = [root]
    while(stack.length) {
        // 出栈
        let o = stack.pop()
        arr.push(o.val)
        o.right && stack.push(o.right)
        o.left && stack.push(o.left)
    }
    return arr
}

15.二叉树的中序遍历

题目:

解法1(递归):

var inorderTraversal = function(root) {
    const arr = []
    const fun = (root) => {
        if(!root) return;
        fun(root.left)
        arr.push(root.val)
        fun(root.right)
    }
    fun(root)
    return arr
}

解法2(栈): 

var inorderTraversal = function(root) {
    const arr = []
    const stack = []
    let o = root
    while(stack.length || o) {
        while(o) {
            stack.push(o)
            o = o.left
        }
        const n = stack.pop()
        arr.push(n.val)
        o = n.right
    }
    return arr
}

16.二叉树的后序遍历

题目:

解法1(递归):

var postorderTraversal = function(root) {
    const arr = []
    const fun = (root) => {
        if(root) {
            fun(root.left)
            fun(root.right)
            arr.push(root.val)
        }
    }
    fun(root)
    return arr
}

解法2(栈):

var postorderTraversal = function(root) {
    if(!root) return []
    const arr = []
    const stack = [root]
    while(stack.length) {
        const o = stack.pop()
        arr.unshift(o.val)
        o.left && stack.push(o.left)
        o.right && stack.push(o.right)
    }
    return arr
}

17.二叉树的最小深度

题目:

解法1(递归):

var minDepth = function(root) {
    if(!root) return 0
    // 到叶子节点,返回1
    if(!root.left && !root.right) return 1
    // 只有右节点时,递归右节点
    if(!root.left) return minDepth(root.right) + 1
    // 只有左节点时,递归左节点
    if(!root.right) return minDepth(root.left) + 1
    return Math.min(minDepth(root.right), minDepth(root.left)) + 1
}

解法2(迭代):

var minDepth = function(root) {
    if(!root) return 0
    const queue = [root]
    let dep = 0
    while(true) {
        let size = queue.length
        dep++
        while(size--) {
            const node = queue.shift()
            // 到第一个叶子节点,返回当前深度
            if(!node.left && !node.right) return dep
            node.left && queue.push(node.left)
            node.right && queue.push(node.right)
        }
    }
}

18.二叉树的最大深度

题目:

解法1(递归):

var maxDepth = function(root) {
    if(!root) return 0
    else {
        const left = maxDepth(root.left)
        const right = maxDepth(root.right)
        return Math.max(left, right) + 1
    }
}

解法2(迭代):

var maxDepth = function(root) {
    if(!root) return 0
    const queue = [root]
    let dep = 0
    while(queue.length) {
        let len = queue.length
        dep++
        while(len--) {
            const o = queue.shift()
            o.left && queue.push(o.left)
            o.right && queue.push(o.right)
        }
    }
    return dep
}

19.翻转二叉树

题目:

解法:

var invertTree = function(root) {
    if(!root) return null
    let temp = root.left
    root.left = root.right
    root.right = temp
    invertTree(root.left)
    invertTree(root.right)
    return root
}

20.相同的树

题目:

解法:

var isSameTree = function(p, q) {
    if(p == null && q == null) return true
    if(p == null || q == null) return false
    if(p.val != q.val) return false
    return isSameTree(p.left, q.left) && isSameTree(p.right, q.right)
}

21.数组中的第k个最大元素

题目:

解法:

var findKthLargest = function(nums, k) {
    let heapSize = nums.length
    // 构建好的大顶堆
    buildMaxHeap(nums, heapSize)
    // 进行下沉,最大元素下沉到末尾
    for(let i = nums.length - 1; i >= nums.length - k + 1; i--) {
        swap(nums, 0, i)
        // 下沉后的元素不参与到大顶堆的调整
        --heapSize
        // 重新调整大顶堆
        maxHeapify(nums, 0, heapSize)
    }
    return nums[0]

    // 自下而上构建大顶堆
    function buildMaxHeap(nums, heapSize) {
        for(let i = Math.floor(heapSize / 2) - 1; i >= 0; i--) {
            maxHeapify(nums, i, heapSize)
        }
    }

    // 从左向右,自上而下的调整节点
    function maxHeapify(nums, i, heapSize) {
        let l = i * 2 + 1
        let r = i * 2 + 2
        let largest = i
        if(l < heapSize && nums[l] > nums[largest]) {
            largest = l
        }
        if(r < heapSize && nums[r] > nums[largest]) {
            largest = r
        }
        if(largest !== i) {
            // 进行节点调整
            swap(nums, i ,largest)
            // 继续调整下面的叶子节点
            maxHeapify(nums, largest, heapSize)
        }
    }
    
    function swap(a, i, j) {
        let temp = a[i]
        a[i] = a[j]
        a[j] = temp
    }
}

22.猜数字大小

题目:

解法:

var guessNumber = function(n) {
    let start = 1
    let end = n
    while(start <= end) {
        const mid = Math.floor((start +  end) / 2)
        const res = guess(mid)
        if(res == 0) {
            return mid
        } else if(res == -1) {
            end = mid
        } else if(res == 1) {
            start = mid + 1
        }
    }
}

23.多数元素

题目:

解法:

var majorityElement = function(nums) {
    if(nums.length == 1) {
        return nums[0]
    }
    const map = new Map()
    for(let i of nums) {
        if(!map.get(i)) {
            map.set(i, 1)
        } else {
            map.set(i, map.get(i) + 1)
            if(map.get(i) > nums.length / 2) return i
        }
    }
}

24.爬楼梯

题目:

解法:

var climbStairs = function(n) {
    const arr = []
    arr[0] = 1
    arr[1] = 1
    for(let i = 2; i <= n; i++) {
        arr[i] = arr[i - 1] + arr[i - 2]
    }
    return arr[n]
}

思路:

25.打家劫舍

题目:

解法:

var rob = function(nums) {
    const l = nums.length
    if(l == 0) return 0
    const dp = new Array(l + 1)
    dp[0] = 0
    dp[1] = nums[0]
    for(let i = 2; i <= l; i++) {
        dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i - 1])
    }
    return dp[l]
}

思路: 

26.跳跃游戏

题目:

解法1(动态规划): 

var canJump = function(nums) {
    // 初始化dp
    let dp = new Array(nums.length).fill(false)
    // 第一格能到达
    dp[0] = true
    for(let i = 1; i < nums.length; i++) {
        for(let j = 0; j < i; j++) {
            // 当前位置j能到达,并且当前位置j加上可跳跃距离如果超过了i,则将dp[i]更新为ture,即i位置也可以到达
            if(dp[j] && j + nums[j] >= i) {
                dp[i] = true
                break
            }
        }
    }
    return dp[nums.length - 1]
}

解法2(贪心算法):

var canJump = function(nums) {
    // 长度为1直接就是终点
    if(nums.length == 1) return true
    // 能覆盖的最远距离
    let cover = nums[0]
    for(let i = 0; i <= cover; i++) {
        // 在 当前覆盖距离cover 和 当前位置加可跳跃距离 中取一个较大者
        cover = Math.max(cover, i + nums[i])
        if(cover >= nums.length - 1) {
            // 覆盖距离大于等于nums.length - 1说明能到达终点
            return true
        }
    }
    return false
}

27.分发饼干

题目:

解法:

var findContentChildren = function(g, s) {
    // 先将两个数组进行排序
    g = g.sort((a, b) => a - b)
    s = s.sort((a, b) => a - b)
    let res = 0
    // 使用index来控制饼干数组的遍历
    let index = s.length - 1
    // 优先满足胃口大的孩子
    for(let i = g.length - 1; i >= 0; i--) {
        if(index >= 0 && s[index] >= g[i]) {
            res++
            index--
        }
    }
    return res
}

28.买卖股票的最佳时机2

题目:

解法1(动态规划):

var maxProfit = function(prices) {
    const n = prices.length
    let dp0 = 0, dp1 = -prices[0]
    for(let i = 1; i < n; i++) {
        let newDp0 = Math.max(dp0, dp1 + prices[i])
        let newDp1 = Math.max(dp1, dp0 - prices[i])
        dp0 = newDp0
        dp1 = newDp1
    }
    return dp0
}

思路:

解法2(贪心算法): 

var maxProfit = function(prices) {
    let ans = 0
    let n = prices.length
    for(let i = 1; i < n; i++) {
        ans += Math.max(0, prices[i] - prices[i - 1])
    }
    return ans
}

思路:

29.字符串解码

题目:

解法1: 

var decodeString = function(s) {
    let numStack = []    // 存倍数的栈
    let strStack = []    // 存待拼接字符串的栈
    let num = 0          // 倍数的搬运工
    let res = ''         // 字符串的搬运工
    for(let k of s) {    // 逐字符扫描
        if(!isNaN(k)) {  // 遇到数字
            num = num * 10 + Number(k)  // 算出倍数
        } else if(k == '[') {           // 遇到'['
            strStack.push(res)          // res串入栈
            res = ''                    // 入栈后清零
            numStack.push(num)          // 倍数num入栈
            num = 0                     // 入栈后清零
        } else if(k == ']') {           // 遇到']',两个栈的栈顶出栈
            let repeatTimes = numStack.pop()         // 获取拷贝次数
            res = strStack.pop() + res.repeat(repeatTimes)   // 构建子串
        } else {
            res += k    // 遇到字母,追加给res串
        }
    }
    return res
}

解法2:

var decodeString = function(s) {
    let stack = []
    for(let k of s) {
        // ']'前的字符串都入栈
        if(k !== ']') {
            stack.push(k)
            continue
        }
        let cur = stack.pop()
        let str = ''
        // 接下来遇到字母,直到遇到'['
        while(cur !== '[') {
            str = cur + str
            cur = stack.pop()
        }
        // 此时cur为'[',接下来遇到数字
        let num = ''
        cur = stack.pop()
        while(!isNaN(cur)) {
            num = cur + num
            cur = stack.pop()
        }
        // 现在要么是字母,要么是'['
        stack.push(cur)
        stack.push(str.repeat(num))
    }
    return stack.join('')
}

30.Pow(x, n)

题目:

解法: 

var myPow = function(x, n) {
    // n=0直接返回1
    if(n == 0) return 1

    // n<0时,x的n次方等于1除以x的-n次方
    if(n < 0) {
        return 1 / myPow(x, -n)
    }

    // n为奇数时,x的n次方等于x乘以x的n-1次方
    if(n % 2) {
        return x * myPow(x, n - 1)
    }

    // n为偶数时,使用分治一分为二,等于x*x的n/2次方
    return myPow(x * x, n / 2)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值