剑指JS-04

73 阅读7分钟

1. 栈的压入-弹出序列

// 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

//

// 示例 1:

// 输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
// 输出:true
// 解释:我们可以按以下顺序执行:
// push(1), push(2), push(3), push(4), pop() -> 4,
// push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
// 示例 2:

// 输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
// 输出:false
// 解释:1 不能在 2 之前弹出。

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

var validateStackSequences = function (pushed, popped) {
  let stack = []
  let i = 0
  pushed.forEach(item => {
    stack.push(item)
    while (stack.length > 0 && stack[stack.length - 1] == popped[i]) {
      stack.pop()
      i++
    }
  })
  return stack.length > 0 ? false : true
}
// console.log(validateStackSequences([1, 2, 3, 4, 5], [4, 5, 3, 2, 1]));

2. 从上到下打印二叉树

// 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

//

// 例如:
// 给定二叉树: [3,9,20,null,null,15,7],

//     3
//    / \
//   9  20
//     /  \
//    15   7
// 返回:

// [3,9,20,15,7]
//

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

var levelOrder = function (root) {
  if (root === null) return []
  let query = []
  let res = []
  // 根节点
  query.push(root)
  res.push(root.val)
  while (query.length != 0) {
    let flag = query.shift()
    console.log(flag)
    if (flag.left) {
      query.push(flag.left)
      res.push(flag.left.val)
    }
    if (flag.right) {
      query.push(flag.right)
      res.push(flag.right.val)
    }
  }
  return res
}

3. 二叉树中和为某一值的路径

// 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

// 叶子节点 是指没有子节点的节点。

//

// 示例 1:

// 输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
// 输出:[[5,4,11,2],[5,8,4,5]]
// 示例 2:

// 输入:root = [1,2,3], targetSum = 5
// 输出:[]
// 示例 3:

// 输入:root = [1,2], targetSum = 0
// 输出:[]

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

var pathSum = function (root, target) {
  let res = []
  let path = []
  DFS(root, 0)
  function DFS (root, sum) {
    if (!root) return
    if (!root.left && !root.right && sum + root.val === target) {
      res.push([...path, root.val])
    }
    path.push(root.val)
    DFS(root.left, sum + root.val)
    DFS(root.right, sum + root.val)
    path.pop()
  }
}

4. 二叉搜索树与双向链表

// 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

// 为了让您更好地理解问题,以下面的二叉搜索树为例:

// 我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

// 下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

// 特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

var treeToDoublyList = function (root) {
  if (!root) return root
  let head = null
  let pre = null
  inOrder(root)
  head.left = pre
  pre.right = head
  return head
  function inOrder (root) {
    if (!root) return
    inOrder(root.left)
    root.left = pre
    !pre ? (pre = root) : (pre.right = root)
    pre = root
    inOrder(root.right)
  }
}

5. 序列化二叉树

// 请实现两个函数,分别用来序列化和反序列化二叉树。

// 你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

// 提示:输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

// 示例:

// 输入:root = [1,2,3,null,null,4,5]
// 输出:[1,2,3,null,null,4,5]

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */



// 常规前序遍历左子树
var preorderTraversal = function (root) {
  if (!root) return []
  const res = []
  const stack = []
  while (root && stack.length) {
    while (root) {
      res.push(root.val)
      stack.push(root.right)
      root = root.left
    }
    root = stack.pop()
  }
}

var deserialize = function (data) {
  if (data == '[]') return null
  let arr = JSON.parse(data)
  let root = new TreeNode(arr[0])
  let queue = [root],
    i = 1
  while (queue.length && i < arr.length) {
    let node = queue.shift()
    if (arr[i] != null) {
      node.left = new TreeNode(arr[i])
      queue.push(node.left)
    }
    i++
    if (arr[i] != null) {
      node.right = new TreeNode(arr[i])
      queue.push(node.right)
    }
    i++
  }
  return root
}

6. 字符串的排列

// 输入一个字符串,打印出该字符串中字符的所有排列。

// 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

// 示例:

// 输入:s = "abc"
// 输出:["abc","acb","bac","bca","cab","cba"]

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
let s = 'abc'
var permutation = function (s) {
  // set没有重复的  用于去重
  let res = new Set()
  let used = Array(s.length).fill(false)
  let dfs = (str, used) => {
    if (str.length == s.length) {
      // str 是拼凑的结果
      res.add(str)
      return
    }
    for (let i = 0; i < s.length; i++) {
      if (used[i]) continue
      else {
        used[i] = true
        console.log(s[i])
        dfs(str + s[i], used)
        used[i] = false
      }
    }
  }
  dfs('', used)
  console.log(res)
  return [...res]
}

console.log(permutation(s))

7. 数组中出现次数超过一半的数字

// 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

//

// 你可以假设数组是非空的,并且给定的数组总是存在多数元素。

//

// 示例 1:

// 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
// 输出: 2

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
let nums = [1, 2, 3, 2, 2, 2, 5, 4, 2]
// var majorityElement = function (nums) {
//   nums.sort((a, b) => a - b)
//   let a = Math.floor(nums.length / 2)
//   return nums[a]
// }

var majorityElement = function (nums) {
  let hashTable = {}
  for (let i = 0; i < nums.length; i++) {
    if (!(nums[i] in hashTable)) {
      hashTable[nums[i]] = 1
    } else {
      hashTable[nums[i]] += 1
    }
  }
  let min = Math.min(...nums)
  let max = Math.max(...nums)
  for (let j = min; j <= max; j++) {
    if (hashTable[j] >= Math.floor(nums.length / 2)) {
      return j
    }
  }
}

console.log(majorityElement(nums))

8. 最小的k个数

// 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

// 示例 1:

// 输入:arr = [3,2,1], k = 2
// 输出:[1,2] 或者 [2,1]
// 示例 2:

// 输入:arr = [0,1,2,1], k = 1
// 输出:[0]

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
let arr = [0, 1, 2, 1]
var getLeastNumbers = function (arr, k) {
  for (let i = arr.length - 1; i > 0; i--) {
    for (let j = 0; j < i; j++) {
      if (arr[j] > arr[j + 1]) {
        let temp = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = temp
      }
    }
  }
  let res = []
  for (let l = 0; l < k; l++) {
    res.push(arr[l])
  }
  return res
}
console.log(getLeastNumbers(arr,2))

9. 数据流中的中位数

// 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

// 例如,

// [2,3,4] 的中位数是 3

// [2,3] 的中位数是 (2 + 3) / 2 = 2.5

// 设计一个支持以下两种操作的数据结构:

// void addNum(int num) - 从数据流中添加一个整数到数据结构中。
// double findMedian() - 返回目前所有元素的中位数。
// 示例 1:

// 输入:
// ["MedianFinder","addNum","addNum","findMedian","addNum","findMedian"]
// [[],[1],[2],[],[3],[]]
// 输出:[null,null,null,1.50000,null,2.00000]
// 示例 2:

// 输入:
// ["MedianFinder","addNum","findMedian","addNum","findMedian"]
// [[],[2],[],[3],[]]
// 输出:[null,null,2.00000,null,2.50000]

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

var MedianFinder = function () {
  this.queue = []
  this.left = -1
  this.right = -1
}

MedianFinder.prototype.addNum = function (num) {
  if (this.left == -1) {
    this.left++
    this.right++
  } else {
    // 加入num后队列长度变为偶数
    if (this.left == this.right) {
      this.right++
    } else {
      // 加入num后队列长度变为奇数
      this.left++
    }
  }
  this.queue.push(num)
}

MedianFinder.prototype.findMedian = function () {
  if (!this.queue.length) return null
  this.queue.sort((a, b) => a - b)
  return (this.queue[this.left] + this.queue[this.right]) / 2
}

10. 连续子数组的最大和

// 输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

// 要求时间复杂度为O(n)。

// 示例1:

// 输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
// 输出: 6
// 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

var maxSubArray = function (nums) {
  if (!nums.length) return null
  let max = nums[0]
  let record = nums[0]
  for (let i = 1; i < nums.length; i++) {
    record = Math.max(record + nums[i], nums[i])
    if (record > max) max = record
  }
  return max
}

console.log(maxSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4]))

11. 礼物的最大价值

// 在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)
// 。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。
// 给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

// 示例 1:

// 输入:
// [
//   [1,3,1],
//   [1,5,1],
//   [4,2,1]
// ]
// 输出: 12
// 解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

var maxValue = function (grid) {
  const m = grid.length,
    n = grid[0].length
  const visited = Array.from(Array(m), () => Array(n).fill(0))
  function dfs (i, j) {
    if (i < 0 || j < 0 || i <= m || j >= n) return 0
    if (!visited[i][j])
      visited[i][j] = grid[i][j] + Math.max(dfs(i - 1, j), dfs(i, j - 1))
    return visited[i][j]
  }
  return dfs(m - 1, n - 1)
}

12. 第一次只出现一次的字符

// 在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

// 示例 1:

// 输入:s = "abaccdeff"
// 输出:'b'
// 示例 2:

// 输入:s = ""
// 输出:' '

// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
let s = 'abaccdeff'
var firstUniqChar = function (s) {
  for (let i = 0; i < s.length; i++) {
    if (s.indexOf(s[i]) === s.lastIndexOf(s[i])) {
      return s[i]
    }
  }
  return ' '
}
console.log(firstUniqChar(s))