数
- 1 最大公约数
- 2 最小公约数
- 3 进制转换
- 4 阶乘
- 统计阶乘尾部0的个数
- 5 字符串加法减法
- 二进制加法
- 6 多数投票问题
- 数组中出现次数多于n/2的元素
- 7 相遇问题
- 改变数组元素使所有元素都相同
1 最大公约数
欧几里得算法:两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。
gcd(a,b)=gcd(b,a%b); /* a>b*/
具体代码实现如下:
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);
}
2 最小公约数
设a,b的最小公约数为lcm(a,b)。有定理:
lcm(a,b)*gcd(a,b)=a*b);
具体代码实现:
int lcm(int a, int b) {return a * b / gcd(a, b);
}
3 进制转换
比如将十进制num10转为七进制num7。
如果是负数,我们可以先将其转为正数,在前面添加个’-'号。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>char * convertToBase7(int num){if(num == 0){return "0";}char *str = (char*)malloc(sizeof(char)*32);memset(str,0,sizeof(str));int index=30;int negative = 0;if(num<0){negative = 1;num = abs(num);}while(num!=0){str[index--] = num % 7+'0';//num = num - str[index];num = num / 7;//index++;}if(negative==1){str[index--]='-';//return str;}str[31]='\0';return str+index+1;
}int main(void)
{//int nums[]={10,9,2,5,3,7,101,18};//int count = countPrimes(2);printf("count = %s\n",convertToBase7(14));return 0;
}
4 阶乘
统计阶乘尾部0的个数
实现:
int trailingZeroes(int n){return n==0?0:n/5+trailingZeroes(n/5);
}
如果统计的是 N! 的二进制表示中最低位 1 的位置,只要统计有多少个 2 即可
5 字符串加法减法
二进制加法
给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。
输入: a = “11”, b = “1”
输出: “100”
/* 将一个字符串反转 */
void reserve(char* s) {int len = strlen(s);for (int i = 0; i < len / 2; i++) {char t = s[i];s[i] = s[len - i - 1], s[len - i - 1] = t;}
}char* addBinary(char* a, char* b) {/* 将两个字符串反转 */reserve(a);reserve(b);/* 获取两个字符串长度 */int len_a = strlen(a), len_b = strlen(b);int n = fmax(len_a, len_b);int carry = 0, len = 0;/* 结果的长度是a、b最大长度加2 */char* ans = (char*)malloc(sizeof(char) * (n + 2));for (int i = 0; i < n; ++i) {/* 如果i小于len_a,表示字符串a还有元素,如果有元素,是1则返回1,是0则返回0 */carry += i < len_a ? (a[i] == '1') : 0;carry += i < len_b ? (b[i] == '1') : 0;ans[len++] = carry % 2 + '0';/* carry进位处理 */carry /= 2;}/* 最后还有进位 */if (carry) {ans[len++] = '1';}ans[len] = '\0';/* 反转 */reserve(ans);return ans;
}
6 多数投票问题
数组中出现次数多于n/2的元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
因为找的元素次数大于⌊ n/2 ⌋ ,所以我们只需将数组排序,返回中间值即可:
int cmp(void *a,void *b)
{return *(int *)a-*(int *)b;
}
int majorityElement(int* nums, int numsSize){qsort(nums,numsSize,sizeof(int),cmp);return nums[numsSize/2];
}
7 相遇问题
改变数组元素使所有元素都相同
给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。
输入:
[1,2,3]
输出:
2
说明:
只有两个动作是必要的(记得每一步仅可使其中一个元素加1或减1):
[1,2,3] => [2,2,3] => [2,2,2]
这是个典型的相遇问题,移动距离最小的方式是所有元素都移动到中位数。理由如下:
设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。
设数组长度为 N,则可以找到 N/2 对 a 和 b 的组合,使它们都移动到 m 的位置。
思路:先排序,然后计算移到中位数的位置所需的移动次数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>int cmp(void *a,void *b)
{return *(int *)a-*(int *)b;
}int minMoves2(int* nums, int numsSize){qsort(nums,numsSize,sizeof(int),cmp);int left=0,right=numsSize-1;int count=0;while(left<=right){count +=nums[right]-nums[left];left++;right--;}return count;
}
int main(void)
{int nums[]={1,2,3};//int count = trailingZeroes(10);printf("count = %d\n",minMoves2(nums,3));return 0;
}