数学问题总结
主要是leetcode以及部分习题上的简单数学问题,因主要是回答考题,所以不太考虑时间复杂度以及空间复杂度。
1.回文数
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是
思路:
1.先处理特殊情况:最后一位为零(不包括本身是0)和负数一定不是
2.把每一位存入数组,然后当成回文串的问题去处理。
// An highlighted block
bool isPalindrome(int x){
int a[20];
int i=0,j;//i统计输入数的位数
if(x<0||(x%10==0&&x!=0)){
return false;
}
while(x>0){//取每一位存入数组
a[i]=x%10;
x=x/10;
i++;
}
for(j=0;j<i/2;j++){//对称的数作比较
if(a[j]!=a[i-1-j]){
return false;
}
}
return true;
}
2.罗马数组转整数
题目太长,直接复制。
思路:把字母做相应隐射,数组的小标是字母,值是字母对应的值。取字符串每个字符时,与上一个字符对应的值比较,如果大于上一个字符,则加;小于上一个,则减
// An highlighted block
int romanToInt(char* s) {
int symbolValues[26];
symbolValues['I' - 'A'] = 1;
symbolValues['V' - 'A'] = 5;
symbolValues['X' - 'A'] = 10;
symbolValues['L' - 'A'] = 50;
symbolValues['C' - 'A'] = 100;
symbolValues['D' - 'A'] = 500;
symbolValues['M' - 'A'] = 1000;
int ans = 0;
int n = strlen(s);
for (int i = 0; i < n; ++i) {
int value = symbolValues[s[i] - 'A'];
if (i < n - 1 && value < symbolValues[s[i + 1] - 'A']) {
ans -= value;
} else {
ans += value;
}
}
return ans;
}
3.快乐数
思路:“快指针” 每次走两步,“慢指针” 每次走一步,当二者相等时,即为一个循环周期。此时,判断是不是因为 1 引起的循环,是的话就是快乐数,否则不是快乐数。
// An highlighted block
int count(int n){
int res = 0;
int a=0;
while(n){
a = n%10;
n = n/10;
res += a*a;
}
return res;
}
bool isHappy(int n){
int fast = n,slow = n;
do{
slow = count(slow);
fast = count(fast);
fast = count(fast);
}while(slow != fast);
return (slow == 1);
}
4.各位相加
思路:循环判断是否>10(个位数判断),内层循环用来处理数字相加
// An highlighted block
int addDigits(int num){
while (num >= 10) {
int sum = 0;
while (num > 0) {
sum += num % 10;
num /= 10;
}
num = sum;
}
return num;
}
5.丑数
思路:对 n 反复除以 2,3,5直到 n 不再包含质因数 2,3,5。若剩下的数等于1 ,则说明 n 不包含其他质因数,是丑数;否则,说明 n包含其他质因数,不是丑数。
// An highlighted block
bool isUgly(int n) {
if (n <= 0) {
return false;
}
int factors[] = {2, 3, 5};
for (int i = 0; i < 3; i++) {
while (n % factors[i] == 0) {
n /= factors[i];
}
}
return n == 1;
}
6.是否是a的幂
判断一个数是否是a的幂,如27=3^3
// An highlighted block
int isPowerOfThree(int n,int a) {
while (n && n % a == 0) {
n /= a;
}
return n == 1;
}
7.完美数
对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」
例子:28 = 1 + 2 + 4 + 7 + 14
思路:枚举法,只需要枚举到a的开根,另一个=a/d
bool checkPerfectNumber(int num){
if (num == 1) {
return false;
}
int sum = 1;
for (int d = 2; d * d <= num; ++d) {
if (num % d == 0) {
sum += d;
if (d * d < num) {
sum += num / d;
}
}
}
return sum == num;
}
8.自除数
自除数 是指可以被它包含的每一位数整除的数。
自除数 不允许包含 0 。
给定两个整数 left 和 right ,返回一个列表,列表的元素是范围 [left, right] 内所有的 自除数 。
例子:128 是一个 自除数 ,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。
bool isSelfDividing(int num) {
int temp = num;
while (temp > 0) {
int digit = temp % 10;
if (digit == 0 || num % digit != 0) {
return false;
}
temp /= 10;
}
return true;
}
int* selfDividingNumbers(int left, int right, int* returnSize){
int * ans = (int *)malloc(sizeof(int) * (right - left + 1));
int pos = 0;
for (int i = left; i <= right; i++) {
if (isSelfDividing(i)) {
ans[pos++] = i;
}
}
*returnSize = pos;
return ans;
}
9.三角形最长周长
给定数组,判断里面数字所能组成的周长最长的三角形
贪心 + 排序:选择枚举三角形的最长边 c,而从贪心的角度考虑,我们一定是选「小于 ccc 的最大的两个数」作为边长 a和 b,此时最有可能满足 a+b>c,使得三条边能够组成一个三角形,且此时的三角形的周长是最大的。
int largestPerimeter(int *A, int ASize) {
sort(A);//自己写排序
for (int i = ASize - 1; i >= 2; --i) {
if (A[i - 2] + A[i - 1] > A[i]) {
return A[i - 2] + A[i - 1] + A[i];
}
}
return 0;
}
10.一年中的第几天
int dayOfYear(char * date){
int year = atoi(date);
int month = atoi(date + 5);
int day = atoi(date + 8);
int amount[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
++amount[1];
}
int ans = 0;
for (int i = 0; i < month - 1; ++i) {
ans += amount[i];
}
return ans + day;
}
11.一周的第几天
输入的日期一定是在 1971 到 2100 年之间的有效日期,1970 年 12月 31 日是星期四
思路:计算出到1970 年 12月 31 日间隔天数days,(days+3)%7 因为数组从0开始
对于单位年要判断间隔中有几个闰年,对于单位月要判断是否是闰年2月
char * dayOfTheWeek(int day, int month, int year){
char * week[7] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
int monthDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30};
/* 输入年份之前的年份的天数贡献 每4年有一个366天。1969/4=1,是最近的新一轮开始*/
int days = 365 * (year - 1971) + (year - 1969) / 4;
/* 输入年份中,输入月份之前的月份的天数贡献 */
for (int i = 0; i < month - 1; ++i) {
days += monthDays[i];
}
if ((year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) && month >= 3) {
days += 1;
}
/* 输入月份中的天数贡献 */
days += day;
return week[(days + 3) % 7];
}
12.下周的日期
思路:1.闰年判断。2.+7后是否超过当月,当月加1后是否超过当年
int monthDays[13] = {0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30};//第一位舍弃,让月份与下标对应
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
monthDays[2]=29;
if(day+7>monthDays[month]){
day=day+7-monthDays[month];
if(month+1>12){year++;month=1;}
else month++;
}
13.打印杨辉三角
思路:先对特殊位置:每行第一个元素a[i][0]和最后一个元素a[i][i],赋值1;其他位置遍历矩阵,核心语句,a[i][j]=a[i-1][j]+a[i][j-1];
int a[n][n];
int i=0,j=0;
for(i=0;i<n;i++)}{
for(j=0;j<=i;j++){
if(j=0||j==i) a[i][j]=1;
else if(i>1) a[i][j]=a[i-1][j-1]+a[i-1][j];
print("%d",a[i][j]);
}
}
14.两个数的最小公倍数和最大公约数
思路:最大公约数:辗转相除法。最小公倍数a*b/最大公约数
int temp=0
if(a<b){//对保证a一定大于b
temp=a;
a=b;
b=temp;
}
while(b!=0){
r=a%b;
a=b;
b=r;
}
return a;
//若是最小公倍数,开始时 int c=a*b;最后 return c/a;
15.三除数
给你一个整数 n 。如果 n 恰好有三个正除数 ,返回 true ;否则,返回 false 。
例子:4 有三个除数:1、2 和 4 。
bool isThree(int n) {
int sum=0;
for(int i=1;i*i<=n;i++)
{
if(n%i==0)
{
if (i != n / i){
// 此时 i 与 n / i 为不同整数
sum += 2;
}
else{
// 此时 i 与 n / i 相等
sum += 1;
}
}
}
return (sum==3);
}