js解leetcode(39)-中等

1.找树左下角的值

题目:给定一个二叉树,在树的最后一行找到最左边的值。

思路:可以用层序遍历的思想,递归遍历节点的时候记录当前层级即可

迭代的代码比较多,就不放了

时间复杂度O(n),空间复杂度O(h)

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var findBottomLeftValue = function(root) {
  let preLevel = -1;
  let v;
  const search = (root, level = 0) => {
    if (!root) return;
    if (level > preLevel) {
      v = root.val;
      preLevel = level;
    }
    search(root.left, level + 1);
    search(root.right, level + 1);
  };
  search(root);
  return v;
};

2.在每个树行中找最大值

题目:您需要在二叉树的每一行中找到最大的值。

思路:借鉴层序遍历的思路

时间复杂度O(n),空间复杂度O(h)

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var largestValues = function(root) {
      const res = [];
  const search = (root, level = 0) => {
    if (!root) return;
    if (res[level] === undefined) {
      res[level] = root.val;
    } else if (root.val > res[level]) {
      res[level] = root.val;
    }
    search(root.left, level + 1);
    search(root.right, level + 1);
  };
  search(root);
  return res;
};

3.最长回文子序列

题目:给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。

思路:动态规划问题。可以用dp[i][j]来记录区间[i,j]的最长回文子序列。

那么,状态转移方程是:

如果s[i]=s[j],那么

dp[i][j]=dp[i+1][j-1]+2,

如果不等,那么dp[i][j]=Math.max(dp[i][j-1],dp[i+1][j])

可以发现,字符串依赖前一行及当期行之前的结果,所以从后往前遍历

时间复杂度O(n2),空间复杂度O(n2)

/**
 * @param {string} s
 * @return {number}
 */
var longestPalindromeSubseq = function(s) {
  const l = s.length;
  if (!l) return 0;
  if (l == 1) return 1;
  const dp = new Array(l).fill("").map(() => new Array(l).fill(0));
  for (let i = 0; i < l; i++) {
    dp[i][i] = 1;
  }
  let pre = 0;
  for (let i = 1; i < l; i++) {
    if (s[i] == s[i - 1]) {
      dp[pre][i] = i - pre + 1;
    } else {
      pre = i;
    }
  }
  for (let i = l - 2; i >= 0; i--) {
    for (let j = i + 1; j < l; j++) {
      if (dp[i][j] === j - i + 1) continue;
      dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
      if (s[i] === s[j]) {
        dp[i][j] = Math.max(dp[i][j], dp[i + 1][j - 1] + 2);
      }
    }
  }
  return dp[0][l - 1];
};

用一个变量记录当前行之前的最长区间,可以压缩一下空间复杂度

时间复杂度O(n2),空间复杂度O(n)

/**
 * @param {string} s
 * @return {number}
 */
var longestPalindromeSubseq = function(s) {
  const len = s.length;
  if (len < 2) {
    return len;
  }

  const dp = new Array(len).fill(1);
  let max = 0;
  for (let i = 1; i < len; i++) {
    max = 0;
    for (let j = i - 1; j >= 0; j--) {
      const tmp = dp[j];
      if (s[i] === s[j]) {
        dp[j] = max + 2;
      }
      max = Math.max(tmp, max);
    }
  }
  return Math.max(...dp)
};

4.零钱兑换

题目:给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。 

思路:完全背包问题,动态规划即可。dp[i]表示金额为i的硬币组合数,那么对于每一种硬币,有dp[i]=dp[i]+dp[i-item]

时间复杂度O(mn),m是金额,n是硬币种类,空间复杂度(m)

/**
 * @param {number} amount
 * @param {number[]} coins
 * @return {number}
 */
var change = function(amount, coins) {
  const dp = new Array(amount + 1).fill(0);
  dp[0] = 1;

  for (const item of coins) {
    for (let i = item; i <= amount; i++) {
      dp[i] = dp[i - item] + dp[i];
    }
  }
  return dp[amount];
};

5.随机翻转矩阵

题目:

题中给出一个 n_rows 行 n_cols 列的二维矩阵,且所有值被初始化为 0。要求编写一个 flip 函数,均匀随机的将矩阵中的 0 变为 1,并返回该值的位置下标 [row_id,col_id];同样编写一个 reset 函数,将所有的值都重新置为 0。尽量最少调用随机函数 Math.random(),并且优化时间和空间复杂度。

注意:

1 <= n_rows, n_cols <= 10000
0 <= row.id < n_rows 并且 0 <= col.id < n_cols
当矩阵中没有值为 0 时,不可以调用 flip 函数
调用 flip 和 reset 函数的次数加起来不会超过 1000 次

思路:用数组记录,试过会内存溢出,所以只能用更节约性能的set或者map

对于m*n的矩阵,随机取点其实可以看成在0-m*n随机取一个整数,假定矩阵的点是有序的,就能算出对应的坐标。所以每次随机取一个下标,然后用set记录,出现过就重新取,reset就clear一下set

/**
 * @param {number} n_rows
 * @param {number} n_cols
 */
var Solution = function (n_rows, n_cols) {
  this.count = n_rows * n_cols;
  this.n_cols = n_cols;
  this.flipC = new Set();
};

/**
 * @return {number[]}
 */
Solution.prototype.flip = function () {
  if (this.flipC.size === this.count) return;
  let v = ~~(Math.random() * this.count);
  while (this.flipC.has(v)) {
    v = ~~(Math.random() * this.count);
  }
  this.flipC.add(v);
  return [~~(v / this.n_cols), v % this.n_cols];
};

/**
 * @return {void}
 */
Solution.prototype.reset = function () {
  this.flipC.clear();
};
/**
 * @return {void}
 */

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值