vlambda博客
学习文章列表

每日三题 Day5--leetcode98、202、50--咕咕咕

This browser does not support music or audio playback. Please play it in WeChat or another browser.


每日三题 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);//递归从根节点开始
}

执行结果:

每日三题 Day5--leetcode98、202、50--咕咕咕

可以分析得到,每个节点都只遍历一次,所以时间复杂度为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;
}

但是!问题来啦,当提交的时候出现错误:

每日三题 Day5--leetcode98、202、50--咕咕咕

意思为数组越界,但是当我加大数组大小时又出现错误:

每日三题 Day5--leetcode98、202、50--咕咕咕

错误为爆栈,数组内存过大或递归层数太深 ,总结下来 ,不能用数组记录是否出现循环,在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;
}

执行结果:每日三题 Day5--leetcode98、202、50--咕咕咕


每日一题 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语言实现

思路很简单,既然为算法题一定不会累乘实现。

每日三题 Day5--leetcode98、202、50--咕咕咕

当求一个奇数次幂时,只需要计算这个数的一半次幂再平方再乘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);//负数次幂则先计算相反数次幂再取倒数
}

执行结果:

每日三题 Day5--leetcode98、202、50--咕咕咕

可以分析得到,此算法时间复杂度为O(logn),击败双百


关于每日一题:

疫情在家学业不重,又觉得自己算法很薄弱,所以希望可以每天刷一道算法题。

在翻leetcode找题的时候看到了推出的每日1题打卡计划,觉得不错,在此写下来加深记忆,也希望可以帮到其他人 。

今天只写了c语言实现,最近在学习python和go,在复习java,过几天尝试不同语言实现。

这几天出去玩,只做了题没写解析,所以打算补一下,每天规定一题+补之前一题+题库随机一题

Day5总结

leetcode98为一道 递归遍历二叉树 问题

leetcode202是一道 判断链表是否有环 的题,解法很有趣。

leetcode50是一道很简单的幂指数分解递归问题


如果不出意外,每天这个时间更,欢迎监督,大家共勉。



每日三题 Day5--leetcode98、202、50--咕咕咕