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;
};