菜鸟刷题Day8

本文介绍了如何解决LeetCode上的三个编程问题:奇偶树的判断算法,利用层序遍历和奇偶判断;数组的相对排序,通过哈希表统计元素出现次数并重构数组;最长和谐子序列问题,采用排序和双指针方法。文章强调了长期坚持练习编程的重要性。
摘要由CSDN通过智能技术生成

⭐作者:别动我的饭
⭐专栏:菜鸟刷题
⭐标语:悟已往之不谏,知来者之可追
在这里插入图片描述

一.奇偶树:1609. 奇偶树 - 力扣(LeetCode)

描述

如果一棵二叉树满足下述几个条件,则可以称为 奇偶树 :

二叉树根节点所在层下标为 0 ,根的子节点所在层下标为 1 ,根的孙节点所在层下标为 2 ,依此类推。
偶数下标 层上的所有节点的值都是 奇 整数,从左到右按顺序 严格递增
奇数下标 层上的所有节点的值都是 偶 整数,从左到右按顺序 严格递减
给你二叉树的根节点,如果二叉树为 奇偶树 ,则返回 true ,否则返回 false

示例 1:

在这里插入图片描述

输入:root = [1,10,4,3,null,7,9,12,8,6,null,null,2]
输出:true
解释:每一层的节点值分别是:
0 层:[1]
1 层:[10,4]
2 层:[3,7,9]
3 层:[12,8,6,2]
由于 0 层和 2 层上的节点值都是奇数且严格递增,而 1 层和 3 层上的节点值都是偶数且严格递减,因此这是一棵奇偶树。


解题思路

因为是对某一层的数进行判断,所以一次要拿到一层的数据,于是就可以很自然的想到要用层序遍历(根节点入队列,在根节点出队列的时候带入这个节点的左右孩子),但是也不能手搓一个队列,所以这里还是采取数组模拟队列。如果队列中存在元素就要循环,这个循环既是对队列中的元素进行判断,也是带入队列元素的左右孩子。

将一个数按位与上1,就可以判断这个数的奇偶性,但这样在不同层就要有不同的判断条件,所以我们可以直接多设置一个变量k用来判断,这个变量k在刚开始时是0(第0层是奇数,如果按位与1等等于0,那就说明不满足条件),此后可以用k=1-k来更新这个变量。

还有就是在判断是否严格递增或者递减的时候,为了避免在不同的层有不同的条件判断,可以设置一个flag=1(因为第0层是偶数层要递增),并通过flag= - flag来更新,在不同层只要将相邻的两个数乘上flag来判断.

bool isEvenOddTree(struct TreeNode* root)
{
    struct TreeNode* queue[100000];
    int front = -1;  int rear = -1; //控制队列的首尾
    queue[++rear] = root;           //放入根结点
    int k = 0;                      //判断奇偶性
    int flag = 1;                   // 判断单调性

    while(rear != front)            //队列中还有元素则循环继续
    {
        for(int i = front + 1; i <= rear; i++)
        {
            if((queue[i]->val & 1) == k)
                return false;
            
            //后续会更新front,所以不能用大于2来判断,只要大于front+1就肯定有两个元素
            if(i > front + 1 && flag * queue[i-1]->val >= flag * queue[i]->val)
                return false;
        }
        
      //  更新k和flag
        k = 1 - k;                 // 1 ~ 0互换
        flag = -flag;              // 1 ~ -1互换

        int tmp = rear;//后续要将这个赋值给front来更新front
        //带入左右孩子
        for(int i = front + 1; i <= tmp; i++)
        {
            if(queue[i]->left)     //存在则入列
                queue[++rear] = queue[i]->left;
            if(queue[i]->right)
                queue[++rear] = queue[i]->right;
        }
        front = tmp;  //即使更新front,可以看到我并没有出队,我只是控制下标来达到出队的效果
    }
    return true;
    
}

二.数组的相对排序:1122. 数组的相对排序 - 力扣(LeetCode)

描述

给你两个数组,arr1 和 arr2,arr2 中的元素各不相同,arr2 中的每个元素都出现在 arr1 中。

对 arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。

示例 1:

输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
输出:[2,2,2,1,4,3,3,9,6,7,19]


解题思路

设定一个新数组,将arr1数组中的元素作为新数组的下标统计arr1数组中各元素出现的次数,再用arr2数组中的元素作为新数组的下标,并将这个下标作为元素重新写到arr1数组中。这个思想我们在前面就已经用过好几次了,这种数组就被称为hash数组

这里还要处理一下在arr1数组中出现了,arr2数组中没有的.

int* relativeSortArray(int* arr1, int arr1Size, int* arr2, int arr2Size, int* returnSize)
{
    int tmp[1001]={0};
    
    for(int i=0;i<arr1Size;i++)
    {
        //统计arr1数组中各元素出现的次数
        tmp[arr1[i]]+=1;
    }
    
    int j=0;
    for(int i=0;i<arr2Size;i++)
    {
		while(tmp[arr2[i]]>0)//如果这个下标不为零,说明这个下标就是arr1和arr2都有的元素
        {
            arr1[j]=arr2[i];
            j++;
            tmp[arr2[i]]--;
        }
    }
    //还要将arr2中没出现的元素按升序排好,直接暴力遍历
    for(int i=0;i<1001;i++)
    {
        while(tmp[i]>0)
        {
            arr1[j]=i;
            j++;
            tmp[i]--;
        }
    }
    
	*returnSize=arr1Size;
    return arr1;
}

三.最长和谐子序列:594. 最长和谐子序列 - 力扣(LeetCode)

描述

和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。

现在,给你一个整数数组 nums ,请你在所有可能的子序列中找到最长的和谐子序列的长度。

数组的子序列是一个由数组派生出来的序列,它可以通过删除一些元素或不删除元素、且不改变其余元素的顺序而得到。

示例 1:

输入:nums = [1,3,2,2,5,2,3,7]
输出:5
解释:最长的和谐子序列是 [3,2,2,2,3]

解题思路

最开始我也是想着用hash数组统计次数后,返回相邻位置相减最大值。但是这题的测试用例中会有负数,所以这中办法跑不过,毕竟下标没有负数。

要找的是两者之间差值为1,并且要是最长的。所以首先将这个数组排序,这样会比较好找。排序以后使用双指针,一个指针begin指向数组的首元素,一个指针end指向首元素的下一个,如果begin与end代表的元素之间的差值是1,那么就移动end,否则就移动begin,因为在移动begin的情况下,就代表end与begin之间的元素差值一定不是1,而这个数组是一个有序数组,也就是说在移动begin的时候不用移动end,所以可以直接用end作为循环结束的条件。

int Cmp(const void*a,const void *b)
{
    return *(int*)a-*(int*)b;
}

int findLHS(int* nums, int numsSize)
{
	qsort(nums,numsSize,sizeof(int),Cmp);//使用qsort排序
    
    //排序完毕以后采用双指针计算长度
	int begin=0;
    
    int count=0;//用来计算长度
    
   for(int end=1;end<numsSize;end++)
   {
       if(nums[end]-nums[begin]>1)
           begin++;
       if(nums[end]-nums[begin]==1)
       {
           
           count=count>end-begin+1?count:end-begin+1;
       }
   }
    return count;
}

那么到这里菜鸟刷题专栏就结束了,如果你有心去统计题目个数就会发现总计只有31道题,而专栏介绍却说有32道。我想说,承诺在兑现之前都是一文不值的,别太相信别人的话。最近突然想起《第一序列》中的一句话:“不要让时代的悲哀成为你的悲哀。”不要看着大家都随便,你也随便。

人们总是高估短期努力带来的提升,却低估长期坚持带来的改变。今天是最后一天了,希望你还在坚持。这个专栏就和大家说再见啦,但是我们的故事还没结束……

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别动我的饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值