定理类
最大公约数
—— 辗转相除法(欧几里得法)
int a, b,r;
if(a < b) swap(a,b);
do{
r = a % b;
a = b;
b = r
}while(r);//answer is a
最小公倍数
—— 公式法:两个数的乘积 = 最大公约数 * 最小公倍数
大整数
大整数加法
string addStrings(string &num1, string &num2) {
// write your code here
if(num1.empty()) return num2;
if(num2.empty()) return num1;
int len1 = num1.size();
int len2 = num2.size();
string res = "";
int len = len1>len2 ? len1 : len2;
while(len1 > len2)
{
num2 = '0' + num2;
len2++;
}
while(len1 < len2)
{
num1 = '0' + num1;
len1++;
}
int c_i = 0;
for(int i = len - 1; i >= 0; i--)
{
int sum = c_i + (num1[i] - '0') + (num2[i] - '0');
if(sum >= 10)
{
sum = sum % 10;
c_i = 1;
res = to_string(sum) + res;
}
else
{
c_i = 0;
res = to_string(sum) + res;
}
}
if(c_i == 1) res = '1' + res;
return res;
}
};
key point
- 补齐字符串
- 模拟竖式计算
大整数乘法
二进制求和
67. 二进制求和 思路同大整数求和,只是在判断条件处不同。
位运算
int singleNumber(vector<int>& nums) {
/*
<--- 2^i
4 3 2 1 0
-----------
num: 1 0 0 1 0
1 1 0 1 0
1 0 0 1 0
1 0 0 1 0
-----------
1 0 1 1 0
1 0 0 1 0
1 0 1 1 0
1 0 1 1 0
*/
int ans = 0;
for(int i = 0; i < 32; i++)
{
int total = 0;
for(auto num : nums)
{
total += ((num>>i) & 1);
}
if(total % 3)
{
ans |= (1<<i);
}
}
return ans;
}
key point
这个思路太重要了,之前完全没有涉及过。
为了方便叙述,我们称「只出现了一次的元素」为「答案」。
由于数组中的元素都在int(即32位整数)范围内,因此我们可以依次计算答案的每一个二进制位是0还是1。
具体地,考虑答案的第 i个二进制位(i从 0开始编号),它可能为 0 或 1。对于数组中非答案的元素,每一个元素都出现了 3 次,对应着第 ii 个二进制位的 33个 0 或 3 个 11,无论是哪一种情况,它们的和都是 3 的倍数(即和为 0 或 3)。因此:
答案的第 i 个二进制位就是数组中所有元素的第 i 个二进制位之和除以 3 的余数。
这样一来,对于数组中的每一个元素 x,我们使用位运算
(x >> i) & 1得到 x 的第 i 个二进制位,并将它们相加再对 3 取余,得到的结果一定为 0 或 1,即为答案的第 i 个二进制位。
看官方解析吧,目前为止还没搞懂。