leetcode刷题记录(27)-简单

这篇博客记录了LeetCode的五道题目:单调数列、递增顺序查找树、按奇偶排序数组、最小差值和卡牌分组的解题思路。对于单调数列,通过比较字符大小关系判断;递增顺序查找树可通过重构或交换节点实现;按奇偶排序数组采用双指针法;最小差值问题考虑最大值与最小值的差是否小于2*K;卡牌分组则寻找所有数的最大公约数来判断是否能分组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.单调数列

题目:

如果数组是单调递增或单调递减的,那么它是单调的。

如果对于所有 i <= j,A[i] <= A[j],那么数组 A 是单调递增的。 如果对于所有 i <= j,A[i]> = A[j],那么数组 A 是单调递减的。

当给定的数组 A 是单调数组时返回 true,否则返回 false。

思路:遇到不同的字符时,比较当前的关系和上一次的大小关系就行

/**
 * @param {number[]} A
 * @return {boolean}
 */
var isMonotonic = function(A) {
  const l = A.length;
  if (l < 3) return true;
  let flag;
  for (let i = 1; i < l; i++) {
    if (A[i] > A[i - 1]) {
      if (flag === false) return false;
      flag = true;
    } else if (A[i] < A[i - 1]) {
      if (flag === true) return false;
      flag = false;
    }
  }
  return true;
};

2.递增顺序查找树

题目:给你一个树,请你 按中序遍历 重新排列树,使树中最左边的结点现在是树的根,并且每个结点没有左子结点,只有一个右子结点。

思路:可以重新构造树,也可以直接交换节点的引用关系。构造树比较简单,中序遍历+重新构造节点就行。这里只说说交换引用关系的方法。

递归调用方法,每一课子树调用方法的结果,应该是最左侧的子节点开头,中序遍历方连接右子树,所以先处理右子树,如果没左节点,就返回当前的根节点;如果有左节点,那么处理之后,返回的左子树是它的开始节点,我们找到最后一个节点,奖它的right指向当前节点就行

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var increasingBST = function(root) {
  if (!root) return root;
  root.right = increasingBST(root.right);
  if (!root.left) return root;
  const left = increasingBST(root.left);
  root.left = null;
  let node = left;
  while (node.right) {
    node = node.right;
  }
  node.right = root;
  return left;
};

3.按奇偶排序数组

题目:

给定一个非负整数数组 A,返回一个数组,在该数组中, A 的所有偶数元素之后跟着所有奇数元素。

你可以返回满足此条件的任何数组作为答案。

思路:先说简单的,奇偶数分成两个数组然后连接

/**
 * @param {number[]} A
 * @return {number[]}
 */
var sortArrayByParity = function(A) {
  let left = [];
  let right = [];
  for (const n of A) {
    if (n % 2) {
      right.push(n);
    } else {
      left.push(n);
    }
  }
  return left.concat(right);
};

不使用额外空间,就用双指针法,左指针和由指针分别从两边向中间遍历,左指针遇到奇数停,右指针遇到偶数停,然后交换

/**
 * @param {number[]} A
 * @return {number[]}
 */
var sortArrayByParity = function(A) {
  let left = 0;
  let right = A.length - 1;
  while (left < right) {
    while (!(A[left] % 2) && left < right) {
      left++;
    }
    while (A[right] % 2 && left < right) {
      right--;
    }
    [A[left], A[right]] = [A[right], A[left]];
  }
  return A;
};

4.最小差值

题目:

给你一个整数数组 A,请你给数组中的每个元素 A[i] 都加上一个任意数字 x (-K <= x <= K),从而得到一个新数组 B 。

返回数组 B 的最大值和最小值之间可能存在的最小差值。

思路:取最大值和最小值,比较他们的差与2*K的关系,差值小于2* K的话,结果是0,否则是两个数之差

/**
 * @param {number[]} A
 * @param {number} K
 * @return {number}
 */
var smallestRangeI = function(A, K) {
  const l = A.length;
  if (l < 2) return 0;
  let max = Math.max(...A),
    min = Math.min(...A);

  return Math.abs(min - max) > 2 * K ? Math.abs(min - max) - 2 * K : 0;
};

5.卡牌分组

题目:

给定一副牌,每张牌上都写着一个整数。

此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:

每组都有 X 张牌。
组内所有的牌上都写着相同的整数。
仅当你可选的 X >= 2 时返回 true。

思路:记录每个数出现的次数,然后直接思路就是,从2开始遍历,如果所有字母出现的次数都是当前数的整数倍,那么就符合条件,否则不符合

/**
 * @param {number[]} deck
 * @return {boolean}
 */
var hasGroupsSizeX = function(deck) {
  const map = new Map();
  const l = deck.length;
  for (const n of deck) {
    map.set(n, (map.get(n) || 0) + 1);
  }
  const count = Math.min(...map.values());
  if (count < 2) return false;
  for (let i = 2; i <= count; i++) {
    if (l % i) continue;
    let flag = true;
    for (const v of map.values()) {
      if (v % i) {
        flag = false;
        break;
      }
    }
    if (flag) return true;
  }
  return false;
};

然后可以发现,遍历数比较是否是整数倍,其实就是找出这些数的最大公约数,用辗转相除法获取,不过比较次数其实更多一点

/**
 * @param {number[]} deck
 * @return {boolean}
 */
const gcd = (a, b) => {
  return b === 0 ? a : gcd(b, a % b);
};
var hasGroupsSizeX = function (deck) {
  const map = new Map();
  const l = deck.length;
  let count;
  for (const n of deck) {
    map.set(n, (map.get(n) || 0) + 1);
    count = map.get(n);
  }

  for (const v of map.values()) {
    count = gcd(v, count);
  }
  return count >= 2;
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值