[LeetCode刷题笔记]Math数学类型题目(三)特殊的数字结构

来源:互联网 发布:异度空间知乎 编辑:程序博客网 时间:2024/06/16 00:28

原创文章

转载请注册来源http://blog.csdn.net/tostq

特殊的数字结构这类题一般都是折腾数字本身,特别要注意到观察数字的结构和特征。
常见的出题类型主要分为了回文数字、数字翻转、数字分割等几类。

一、回文数(对称数)
9. Palindrome Number
判断一个数是否是回文数(即数是对称的,如7654567)
这题的难点在于要求不能额外分配空间,也就是说我们不能先通过保存倒置数位,再来进行头尾数位的相互比较。换句话说,题目要求我们要同时比较头尾。
(1)一种可行的方法是同时保存首尾数字
class Solution {public:    bool isPalindrome(int x) {        if(x<0)return false;        // wei        int w;        int xtemp=x;        for(w=0;xtemp!=0;w++)xtemp=xtemp/10;        //printf("%d",w);                int h=x,t=x;        int wh=w-1,wt=1;        while(h==t&&wh>=0){            t=x%10;            h=x/pow(10,wh);            x=(x-h*pow(10,wh))/10;            wh=wh-2;            //printf("|t=%d,h=%d,x=%d,wh=%d|",t,h,x,wh);        }        return (h==t)?true:false;    }};
(2)另一种更为巧妙的方法,是先计算数字的倒转数,再比较两个数是否相等
bool isPalindrome(int x) {    if(x<0)return false;    int w;    int xtemp=x;    for(w=0;xtemp!=0;w++)xtemp=xtemp/10;        xtemp=x;    int cmp=0;    while(w--){        cmp=cmp*10+xtemp%10;        xtemp=xtemp/10;    }    return cmp==x;}

二、数字翻转
7. Reverse Integer
输入:x = 123, 输出:321
输入:x = -123, 输出:-321
这道并不难,前面的回文介绍了数字倒转的方法,然而这道题的正确提交率并不高。
主要原因在于数据溢出,比如-2147483645,其数字倒转后肯定是溢出了,这个时候我们需要返回0,而实际上是不进行处理的话,返回肯定是非0的。
这里我们介绍一种非常简单判断是否溢出的方法,比如判断x*y=z是否溢出,只需要判断z/y==x就可以了。下面是具体的解法:
class Solution {public:    int reverse(int x) {        int sign=(x>0)?1:-1;        x=(x>0)?x:-x;        int res=0;        while(x>0){            int newres=res*10+x%10;            if((newres-x%10)%10!=0||(newres-x%10)/10!=res)return 0; // good            x=x/10;            res=newres;        }        return sign*res;    }};

三、高兴数
202. Happy Number
高兴数定义了这样一个过程:将数字的各位数平方相加得到一个新数,然后将这个新数的各位数平方继续相加,如果这个过程最终结果为1,则为高兴数,如果一直循环的话,则不是高兴数。
比如:19 就是一个高兴数
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
(1)通过Hash表记录
一种比较直观的方法,就是记录这个过程,来判断是否出现过循环,
这里我们可以引入前面介绍的Hash表unordered_map
class Solution {public:    bool isHappy(int n) {        unordered_map<int,bool> m;        while(1){            if(m.find(n)==true)return false;            if(n==1)return true;            m.insert(make_pair(n,true));            int temp=0;            while(n!=0){                temp=temp+(n%10)*(n%10);                n=n/10;            }            n=temp;        }    }};

(2)Floyd 循环定理
另一种更好的方法,是利用循环定理
Floyd 循环定理表明这样的一个现象:速度不同的两人,在一个环形跑道上同时起跑,那么未来他们两个肯定会在某一时刻相遇。
因此我们有如下的方法。
//Floyd Cycle detection algorithmint powsum(int n){    int sum=0;    while(n!=0){        sum=sum+(n%10)*(n%10);        n=n/10;    }    return sum;}bool isHappy(int n) {    int slow=n,fast=n;    do{        slow=powsum(slow);        fast=powsum(fast);        fast=powsum(fast);    }while(slow!=fast);    if(slow==1)return true;    return false;}

四、组合序列
60. Permutation Sequence
这道题是给定两个整数n(n=1~9),k,计算n!个组合数中的第k个的值,需要返回的是字符串形式。比如给n=3,k=6,有如下:
"123"
"132"
"213"
"231"
"312"
"321"
……
所以我们返回的是"321"
解题的思路:
1、因为我们已经知道n的大小,所以我们可以提前将一些存储起来。
2、注意序列是从1开始的,而不是从0开始的
3、这里是可以用递归的
具体解法:
class Solution {private:    int fact[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};public:    string getPermutation(int n, int k) {        if(n==1)return "1";        string s="";        int div=(k-1)/fact[n-1]+1;        int mod=(k-1)%fact[n-1]+1;        string s1=getPermutation(n-1,mod);        for(int i=0;i<s1.length();i++)            if(s1[i]-'0'>=div)s1[i]++;        s+=(char)(div+'0')+s1;        return s;    }};

五、数字分割
343. Integer Break
这道题是给定一个正整数,将这个正整数分成多个正整数的和,使其分割的这些数相乘最大
比如n = 10, 返回 36 (10 = 3 + 3 + 4).
(1)动态归划来解决
这道题比较直观的方式是通过动态归划来解决,因为我们可以看到,n的结果同n-i的结果有明显的关系,假设n的结果为dp[n]。
则dp[n]=MAX(max(dp[n-i],(n-i))*max(i,dp[i]))
具体的解法:
#define max(x,y) (x>y?x:y)int integerBreak(int n) {    if(n<4)return n-1;    int* dp=(int*)malloc((n+1)*sizeof(int));    dp[0]=0,dp[1]=0;    dp[2]=1; //n=2    dp[3]=2; //n=3        for(int i=4;i<=n;i++){ // from 4        int maxpro=0;        for(int j=i-1;j>1;j--){            maxpro=max(maxpro,max(j,dp[j])*max(i-j,dp[i-j]));        }        dp[i]=maxpro;    }    return dp[n];}
(2)另外,我们可以观察数的本身特征
我们可以直观地认为如果把一个数分解成越来越多的份,其相乘应该是越来越大的
考虑到n=a+b,a+b<ab,仅当a或b等于1,或a=b=2时,不成立。
所以当我们把数分成多个3相加的形式,最后乘应该是最大的。
但是还需要考虑最后的余数。
如果余数为1,最后应该写成3*4,而不是3*3*1。
而余数为2,还是可以写成3*3*2,其是大于3*5的。
具体解法:
int integerBreak(int n) {    if(n<4)return n-1;    int ret=n%3;    int dbn=n/3;    if(ret<2)return (3+ret)*(long long)pow(3,dbn-1);    else return ret*(long long)pow(3,dbn);}



0 1
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 婴儿吃奶粉不大便怎么办 孩子喝奶粉拉大便干怎么办 吃奶粉拉不出来怎么办 一岁半宝宝睡觉抱着睡放不下怎么办 3月大婴儿拉奶瓣怎么办 70多天宝宝便秘怎么办 宝宝喝奶粉上火便秘怎么办 a2奶粉吃了便秘怎么办 两个月宝宝两天没有大便怎么办 婴儿一直拉肚子吃药也不好怎么办 吃奶粉的婴儿便秘怎么办 一个多月小狗便便不成形怎么办 3个月宝宝不拉屎怎么办 好几天不拉大便怎么办 20个月宝宝大便干燥怎么办 两月宝宝三天没大便怎么办 六个月宝宝大便干燥怎么办 五个月宝宝拉肚子怎么办拉水样 2个月婴儿拉稀水怎么办 两个月的宝宝拉肚子怎么办 两天了不拉大便怎么办 25天的宝宝便秘怎么办 2个月宝宝便秘怎么办 猫拉绿色稀水怎么办 50天的宝宝便秘怎么办 人工喂养大便次数少怎么办 4个月宝宝肠炎怎么办? 三个月的宝宝拉肚子有奶瓣怎么办 吃米粉后不拉屎怎么办 宝宝拉绿色稀水怎么办 3个月宝宝肠胃炎怎么办 两个月婴儿拉水怎么办 3个月宝宝拉绿水怎么办 宝宝拉绿色的水怎么办 宝宝大便绿又水怎么办 8个月婴儿便秘怎么办 2个月婴儿便秘怎么办 四个月宝宝拉稀带有泡沫怎么办 六个月宝宝拉肚子怎么办拉水 婴儿拉的是沫怎么办 婴儿拉泡沫屎是怎么办