每日三题 Day5--leetcode98、202、50--咕咕咕
人类本质——鸽鸽鸽,说好的每天十二点更,但是这几天出去玩,只做了题没写解析,所以打算补一下,每天规定一题+补之前一题+题库随机一题
(又瞎立flag了)
今日:
leetcode98--验证二叉搜索树
leetcode202–快乐数
leetcode50--Pow(x,n)
每日一题 Day5--leetcode98--验证二叉搜索树
题目
链接:https://leetcode-cn.com/problems/validate-binary-search-tree/
链接为leetcode中文社区,题目没有区别,感觉很好用
题面描述: 给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/ \
1 3
输出: true
示例2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
解析+c语言实现
二叉搜索树,特点为所有左子树的节点小于根节点,所有右子树的节点大于根节点,如例子:
5
/ \
1 6
/ \
4 7
输出: false
根节点为5,左节点为1,右节点为6满足条件,再看右子树,根节点为6,左为4,右为7,满足条件,但是!右子树的左节点4小于原树的根节点5,所以不满足条件,输出为false
这个例子可以看出,不仅需要比较最近的左右节点和根节点的大小关系,还需要比较左右子树的其他节点与根节点的关系。
本题很明显是一个递归的题目,即可以用判断根的方法来判断左子树,而在递归的过程中需要传给子树一个范围(最小值,最大值)开区间,一旦有数超过这个范围即输出false,不是二叉搜索树
/**
\* Definition for a binary tree node.
\* struct TreeNode {
\* int val;
\* struct TreeNode *left;
\* struct TreeNode *right;
\* };
*/
bool sousuoshu(struct TreeNode * root,long long lower,long long upper)//递归函数
{
if(root==NULL) return true;//递归结束条件
if(root->val<=lower||root->val>=upper) return false;//
return sousuoshu(root->left,lower,root->val)&&sousuoshu(root->right,root->val,upper);//递归判断左右子树是否满足
}
bool isValidBST(struct TreeNode* root){
return sousuoshu(root,-2147483649,2147483648);//递归从根节点开始
}
执行结果:
可以分析得到,每个节点都只遍历一次,所以时间复杂度为O(n);
每日一题 Day6–leetcode202–快乐数
题目
链接:https://leetcode-cn.com/problems/happy-number/链接为leetcode中文社区,题目没有区别,感觉很好用
题面描述:编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
解析+c语言实现
失败的暴力解法
按照题目描述,最容易想到的就是暴力求解,一直按规则计算直到得到1时返回true,出现循环时返回false,而在检测循环时采用数组标1/0的方法于是,便有了以下的失败版本:
bool isHappy(int n){//错误代码!
int a[10000000];//开了一个数组记录
memset(a,0,sizeof(a));
int i,sum=0;
a[n]=1;
while(n!=0) //循环
{
• sum=0;
• int p=n;
• while(p!=0)//按规则计算下一个数
• {
• sum+=(p%10)*(p%10);
• p=p/10;
• }
• if(sum==1) return true;
• if(a[sum]==1) return false;
• else a[sum]=1;
• n=sum;
}
return false;
}
但是!问题来啦,当提交的时候出现错误:
意思为数组越界,但是当我加大数组大小时又出现错误:
错误为爆栈,数组内存过大或递归层数太深 ,总结下来 ,不能用数组记录是否出现循环,在c++或python或java里可以使用HashSet进行存储记录,详情参考:https://www.cnblogs.com/chanceYu/p/12808107.html
快慢指针
再次分析问题:按照计算规则后这个数串只可能有三种走向,
走到1
进入循环
值会越来越大最后接近无穷
第一种即为所求true,第二种为false,对于第三种情况:
位数 |
最大值 |
下一个数 |
1 |
9 |
81 |
2 |
99 |
162 |
3 |
999 | 243 |
4 |
9999 | 324 |
如表格最后一行显示当位数大于4时,下一位数都会小于它,这说明这一串数字不会出现第三种情况——越来越大而对于位数为3的数999的下一位是243,说明情况1和2的值都会小于243,所以在代码中并不需要处理第三种情况
总结下来,本题即判断链表是否有环的题
如有环,返回false
如没环,一条路走到1,返回 true;
快慢指针解法: 另两个指针从原点开始,沿链表往下跑,快指针每次跑两步,慢指针每次跑一步,快慢指针早晚会相遇,如果链表无环则相遇在终点1,如果有环则相遇在某一非1的点。
int next(int n)//自定义函数计算下一个数
{
int sum=0;
while(n!=0)
{
• int p=n%10;
• n=n/10;
• sum+=p*p;
}
return sum;
}
bool isHappy(int n){
int left=n,right=next(n);//快慢指针
while(left!=right)
{
• left=next(left);
• right=next(next(right));
}
if(left==1) return true;//如果相遇时点为1
else return false;
}
执行结果:
每日一题 Day7--leetcode50--Pow(x,n)
题目
链接:https://leetcode-cn.com/problems/powx-n/
链接为leetcode中文社区,题目没有区别,感觉很好用
题面描述: 实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例1:
输入: 2.00000, 10
输出: 1024.00000
示例2:
输入: 2.10000, 3
输出: 9.26100
示例3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25
说明:
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
解析和c语言实现
思路很简单,既然为算法题一定不会累乘实现。
当求一个奇数次幂时,只需要计算这个数的一半次幂再平方再乘x即可
当求一个偶数次幂时,只需要计算这个数的一半次幂再平方即可
例如77=39*2+1 那么计算x的39次幂后直接两数相乘便可以节省另外一个39次幂的计算复杂度
注意!这里没规定n的范围,所以需要分为正数/0/负数来考虑
double ppow(double x,long long N)//计算x的非负数次幂
{
if(N==0) return 1.0;//如果0次幂即返回1
double temp=ppow(x,N/2);
if(N%2==0) //如果计算偶数次幂则需计算x的N/2次幂再平方
return temp*temp;
else //如果计算奇数次幂则计算x的N/2次幂平方再乘x
return temp*temp*x;
}
double myPow(double x, int n){
long long N=n;
if(N>=0)
return ppow(x,N);//非负数次幂
else
return 1.0/ppow(x,-N);//负数次幂则先计算相反数次幂再取倒数
}
执行结果:
可以分析得到,此算法时间复杂度为O(logn),击败双百
关于每日一题:
疫情在家学业不重,又觉得自己算法很薄弱,所以希望可以每天刷一道算法题。
在翻leetcode找题的时候看到了推出的每日1题打卡计划,觉得不错,在此写下来加深记忆,也希望可以帮到其他人 。
今天只写了c语言实现,最近在学习python和go,在复习java,过几天尝试不同语言实现。
这几天出去玩,只做了题没写解析,所以打算补一下,每天规定一题+补之前一题+题库随机一题
Day5总结
leetcode98为一道 递归遍历二叉树 问题
leetcode202是一道 判断链表是否有环 的题,解法很有趣。
leetcode50是一道很简单的幂指数分解递归问题
如果不出意外,每天这个时间更,欢迎监督,大家共勉。