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,12,4,1,34,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 。将 numsi 改为 numsi + 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,12,23,34,4

示例 2:

输入:deck = 1,1,1,2,2,2,3,3

输出:false

解释:没有满足要求的分组。

** 提示:**

1 <= deck.length <= 10^4

0 <= decki < 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

相关推荐
lqqjuly4 分钟前
一致性模型深度解析
人工智能·深度学习·算法
RisunJan5 分钟前
Linux命令-patch (为开放源代码软件安装补丁程序)
linux·服务器·算法
一条大祥脚22 分钟前
ABC460贪心|多源BFS|数论|计数|线段树|树的直径
算法·宽度优先
小欣加油32 分钟前
leetcode121买卖股票的最佳时机
数据结构·c++·算法·leetcode·职场和发展
暖阳华笺1 小时前
【高频考点】K-Means聚类算法
c++·算法·机器学习·kmeans·聚类
下午写HelloWorld1 小时前
后量子密码算法:协同签名研究综述
算法·密码学·后量子·协同签名
小蒋学算法1 小时前
算法-计算右侧小于当前元素的个数-分治&归并思想
java·数据结构·算法
lqqjuly1 小时前
FlashAttention 深度解析
人工智能·深度学习·算法
满怀冰雪1 小时前
第05篇-滑动窗口算法-一套模板解决子串与子数组问题
java·算法
叫我:松哥1 小时前
基于LSTM与ARIMA的城市空气质量分析与预测系统
人工智能·python·rnn·算法·机器学习·flask·lstm