7、整数反转:
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
思路:假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。
根据这个假设,如果反转后的整数溢出,则返回 0。
先判断正负,然后看在反转过程中会不会越界,越界则返回0;
注意:判断时用除法而不用乘法是为了避免溢出发生;
class Solution { public: // #define INT_MAX 2147483647 // #define INT_MIN (-INT_MAX-1) int reverse(int x) { int flag=x<0?-1:1; int num=0; while(x){ //判断是否溢出 if((flag==-1&&(INT_MIN/10>num))||(flag==1&&INT_MAX/10<num))return 0; num=num*10+x%10; x/=10; } return num; } };
202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,
也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
思路:
对于快乐数,难度在于计算每个位置上的数字的平方和,这里我们可以对n取余数得到n的个位,求其平方并累加,对n /10的结果用int保存,得到去除个位的n的其他位数字,
重复上述步骤,直至其他位数字求取结果为零,得到n的各个位置的数字的平方和,重复操作直至平方和等于1。
对于非快乐数,肯定不能进入死循环,那么肯定循环进行到一定程度,数字会和之前出现过n重复,因此我们保存每一步骤的n,
并在得到新的n的时候判断该数字是否出现过,出现过就为非快乐数,跳出循环。
class Solution { public: bool isHappy(int n) { set<int> recordN; int sum = 0; while(n != 1){ recordN.insert(n); sum = 0; while(n != 0){ //各个数字求平方和 sum += ((n % 10) * (n % 10)); n = n / 10; } //若构成死循环,则返回false if(recordN.find(sum) != recordN.end()) return false; n = sum; } return true; } };
请你来实现一个 atoi
函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
- 如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
- 假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
- 该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
提示:
- 本题中的空白字符只包括空格字符
' '
。 - 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
输入: "42" 输出: 42
示例 2:
输入: " -42" 输出: -42 解释: 第一个非空白字符为 '-', 它是一个负号。 我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:
输入: "words and 987" 输出: 0 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 因此无法执行有效的转换。
示例 5:
输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−231) 。
思路:是否为空判断,然后处理空格和正负号情况,然后遍历数字,字符相减转换成int
溢出的情况下,返回INT_MIN或者INT_MAX,最后判断一下正负返回
class Solution { public: int myAtoi(string s) { int len = s.length(); if(len==0){ return 0; } int i=0; //跳过前面空格,判断正负 while(s[i]==' '){ i++; } bool neg = false; //对非空和非+-号的有效数字进行处理 if(s[i]=='-'){ neg=true; i++; }else if(s[i]=='+'){ i++; } long ans =0; for(;i<len;i++){ if(s[i]>='0'&&s[i]<='9'){ //***字符相减转换成int ans = ans*10+(s[i]-'0'); if(ans > INT_MAX && neg) return INT_MIN; if(ans > INT_MAX && !neg) return INT_MAX; } //碰到非有效数字就退出 else{ break; } } return neg?-ans:ans; } };
9. 回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121
输出: true
示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。
思路:反转数字后判断两个数是不是相等,需要注意数据反转后溢出的情况,所以将反转后的类型定义为long
或者,输入数字转化为字符串。回文数关于中心对称,只需比较对称的数是否相等即可
class Solution { public: bool isPalindrome(int x) { if(x<0){ return false; } int num=x; long res = 0; while(x){ res = res*10+x%10; x = x/10; } cout<<res; if (res!=num){ return false; } return true; } };
43. 字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
说明:
num1 和 num2 的长度小于110。
num1 和 num2 只包含数字 0-9。
num1 和 num2 均不以零开头,除非是数字 0 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
思路:
①m位数乘以n位数的结果,最长为m+n位。
②在计算机中,以string标示的数字,下标i乘以下标j的结果,理应放在下标(i+j)处。
但是,考虑到进位,需要留一位固定的answer[0]给最高位进位的数字。
于是(i,j)乘积的临时结果temp的实际下标应该为answer[i+j+1]。
注意,要从个位开始乘法累加,在string中是从str[str.size()-1]开始到str[0]结束。
③在①中可以证明,m位乘n位结果最多m+n位,因此我们申请m+n位的数组,下标最大值为m+n-1。
在②中显然,下标i<=m-1,下标j<=n-1,则下标i+j+1<=m+n-1,恰好为数组下标的最大值。
从两个方向获得的上界吻合,所申请空间的利用率为100%。
模拟正常算乘法的步骤就可以,需要注意最后结果的第一个字符不能为‘0’。
class Solution { public: string multiply(string num1, string num2) { if(num1 == "0" || num2 == "0") return "0"; int size1 = num1.size(), size2 = num2.size(); string str(size1 + size2, '0'); for(int i = size1 - 1; i >= 0; i--){ int mulflag = 0; int addflag = 0; for(int j = size2 - 1; j >= 0; j--){ int tmp = (num1[i] - '0') * (num2[j] - '0') + mulflag; mulflag = tmp / 10; tmp = tmp % 10; int tmp2 = str[i + j + 1] - '0' + tmp + addflag; str[i + j + 1] = tmp2 % 10 + '0'; addflag = tmp2 / 10; } str[i] += mulflag + addflag; } if (str[0] == '0') str = str.substr(1, str.size()); return str; } };
172. 阶乘后的零
给定一个整数 n,返回 n! 结果尾数中零的数量。
示例 1:
输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。
思路:阶乘后的零是因为5乘以一个偶数的结果,所以5的个数,决定了阶乘后零的个数。
但是怎样查看阶乘中5的个数呢,要根据因式分子
例如n=30,30!=1*2*3*4*5*6*7*8*9*10*...*30;
里面有多少个为5的因式分子的,先看里面有多少个元素可以整除5,
有5,10,15,20,25,30共6个这个6是怎么求出来的呢?6=30/5;
然后在这六个元素里分别提取分式因子5,可以提取出六个,提取后变成1,2,3,4,5,6,然后看这六个里面有多少个元素可以整除5,6/5=1,
所以有一个元素5还可以继续提取出一个因式分子5,这样就可以看出30!中总共包括7个因式分子5.,所以有7个零
class Solution { public: int trailingZeroes(int n) { int num=0; while(n){ num=num+n/5; n=n/5; } return num; } };
258. 各位相加
给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。
示例:
输入: 38
输出: 2
解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2。
进阶:
你可以不使用循环或者递归,且在 O(1) 时间复杂度内解决这个问题吗?
思路:常规方法,每位数字相加,如果和小于10,则直接返回,否则将和继续按位求和,直到满足条件
class Solution { public: int addDigits(int num) { int res = 0; int sum= 0; while(num){ sum=sum+num%10; num=num/10; if(num==0&&sum>=10){ num = sum; sum = 0; } if(num==0&&sum<10){ return sum; } } res= sum; return res; } };