LeetCode刷题 day8

目录

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

相关推荐
-SGlow-2 小时前
Linux相关概念和易错知识点(51)(mmap文件映射、共享内存原理、malloc的原理)
linux·c语言·算法·内核
学习永无止境@2 小时前
Sobel边缘检测的MATLAB实现
图像处理·opencv·算法·计算机视觉·fpga开发
c++逐梦人2 小时前
记忆化搜索(DFS)
算法·深度优先
阿Y加油吧2 小时前
二分查找进阶:搜索二维矩阵 & 查找元素首尾位置 深度解析
线性代数·算法·矩阵
SEO-狼术2 小时前
Visualize Org Charts and Decision Trees in WinForms
算法·决策树·机器学习
UltraLAB-F2 小时前
GPU显存不足时的分配策略:渲染与仿真的显存争夺战解决方案
图像处理·算法·3d·ai·硬件架构
沐苏瑶2 小时前
Java算法之排序
java·算法·排序算法
Ricky111zzz2 小时前
leetcode学python记录2
python·算法·leetcode·职场和发展
查古穆2 小时前
二分查找-搜索二维矩阵
算法