目录
1.增顺序搜索树
给你一棵二叉搜索树的 root ,请你 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没有左子节点,只有一个右子节点。
示例1:

输入:root = [5,3,6,2,4,null,8,1,null,null,null,7,9]
输出:[1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9]
思路
按中序遍历的顺序得到增序搜索树,这里采用Morris算法来实现
Morris算法先找到当前节点的前驱,重新构造二叉树结构,再从上往下按照中序遍历
java
class Solution {
public TreeNode increasingBST(TreeNode root) {
//Morris遍历 中序遍历
TreeNode curNode = root;
// List<TreeNode> ans = new LinkedList<>();
TreeNode newRoot = null;
TreeNode newPre = null;
while(curNode!= null){
if(curNode.left==null){
//更新当前节点
if(newPre==null){
newRoot = curNode;
newPre = curNode;
}else{
newPre.right = curNode;
newPre = curNode;
}
curNode = curNode.right;
continue;
}
TreeNode preNode = curNode.left;
while(preNode.right!=null&&preNode.right!=curNode){
preNode = preNode.right;
}
if(preNode.right==null){//第一次
preNode.right = curNode;
curNode = curNode.left;
}else if(preNode.right==curNode){//第二次
// ans.add(curNode);
//更新当前节点
newPre.right = curNode;
newPre = curNode;
curNode.left=null;
curNode = curNode.right;
}
}
return newRoot;
}
}
时间复杂度: O(n),n是二叉树的节点数量
空间复杂度: O(1),原地算法
2.按奇偶排序数组
给你一个整数数组 nums,将 nums 中的的所有偶数元素移动到数组的前面,后跟所有奇数元素。
返回满足此条件的 任一数组 作为答案。
示例 1:
输入:nums = [3,1,2,4]
输出:[2,4,3,1]
解释:[4,2,3,1]、[2,4,1,3] 和 [4,2,1,3] 也会被视作正确答案。
思路
双指针算法,左右各一个指针,分别指向首尾节点,左指针左侧全为偶数,右指针右侧全为奇数,两指针中间为待遍历节点,当左指针处为偶数时,左指针右移,为奇数时,与右指针处交换元素,右指针左移
java
class Solution {
public int[] sortArrayByParity(int[] nums) {
int l=0,r=nums.length-1;
while(l<r){
if((nums[l]&1)==1){//奇数
int temp = nums[r];
nums[r--] = nums[l];
nums[l] = temp;
continue;
}
l++;
}
return nums;
}
}
时间复杂度: O(n) n是数组长度
空间复杂度: O(1)
3. 最小差值 I
给你一个整数数组 nums,和一个整数 k 。
在一个操作中,您可以选择 0 <= i < nums.length 的任何索引 i 。将 nums[i] 改为 nums[i] + x ,其中 x 是一个范围为 [-k, k] 的任意整数。对于每个索引 i ,最多 只能 应用 一次 此操作。
nums 的 分数 是 nums 中最大和最小元素的差值。
在对 nums 中的每个索引最多应用一次上述操作后,返回 nums 的最低 分数 。
示例 1:
输入:nums = [1], k = 0
输出:0
解释:分数是 max(nums) - min(nums) = 1 - 1 = 0。
示例 2:
输入:nums = [0,10], k = 2
输出:6
解释:将 nums 改为 [2,8]。分数是 max(nums) - min(nums) = 8 - 2 = 6。
示例 3:
输入:nums = [1,3,6], k = 3
输出:0
解释:将 nums 改为 [4,4,4]。分数是 max(nums) - min(nums) = 4 - 4 = 0。
思路
这题要理解题目意思,从中找到解题思路,对每个元素,都可以执行一次加减操作,加减元素区间在[-k,k],得到新的数组,求数组中最大最小值的差值最小。其实不用考虑其他元素,只要考虑原数组的最大最小值即可,若差值大于2k,则相减即可,若小于等于2k,则新数组中最大最小值差值为0
java
class Solution {
public int smallestRangeI(int[] nums, int k) {
int minNum = nums[0];
int maxNum = nums[0];
for(int i=1;i<nums.length;i++){
if(nums[i]<minNum){
minNum = nums[i];
}
if(nums[i]>maxNum){
maxNum = nums[i];
}
}
return maxNum-minNum>2*k?maxNum-minNum-2*k:0;
}
}
时间复杂度: O(n)
空间复杂度: O(1)
4.卡牌分组
给定一副牌,每张牌上都写着一个整数。
此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:
每组都有 X 张牌。
组内所有的牌上都写着相同的整数。
仅当你可选的 X >= 2 时返回 true。
示例 1:
输入:deck = [1,2,3,4,4,3,2,1]
输出:true
解释:可行的分组是 [1,1],[2,2],[3,3],[4,4]
示例 2:
输入:deck = [1,1,1,2,2,2,3,3]
输出:false
解释:没有满足要求的分组。
** 提示:**
1 <= deck.length <= 10^4
0 <= deck[i] < 10^4
思路
这题有意思,看题目有点迷,开始以为统计每个元素个数,看是否相同即可,后来提测不通过,发现题目本质上是先统计每个元素数量,得到一组数字,再找到这组数字的最大公约数,看是否大于等于2
java
class Solution {
public boolean hasGroupsSizeX(int[] deck) {
int[] counts = new int[1_0001];
for(int num:deck){
counts[num]++;
}
int g = -1;
for(int i=0;i<counts.length;i++){
if(g==-1){
g = counts[i];
}else{
g = gcd(g,counts[i]);
}
}
return g>=2;
}
//最大公约数求法,辗转相除法(欧几里得法)
//原理:假设a=b*k+r,d是a,b的最大公约数,则a,b能被d整除
//则r也能被d整除,所以(a,b)最大公约数与(b,r)最大公约数一样
//因此一直辗转相除,一直到(0,l),则此时l为最大公约数,因为前一步是(k%l=0,l)
//此时k和l的最大公约数l,才会有一个数为0
private int gcd(int x,int y){
return x==0?y:gcd(y%x,x);
}
}
时间复杂度: O(NlogC) 这里N是元素数量,C是数据范围
空间复杂度: O(N+C),统计元素N,递归求公约数C