第一题
题目:给你两个正整数 a 和 b ,返回 a 和 b 的 公 因子的数目。
如果 x 可以同时整除 a 和 b ,则认为 x 是 a 和 b 的一个 公因子。
解法:实际上相当于枚举a,b最大公因数的因子。特别要注意的是优化的方法:对于一个因子x,如果 x 2 x^{2} x2 >数字本身,那么说明n/x(另一半更小的因子)在之前肯定被枚举过了,所以不要再计数了。
c++最大公因数函数:__gcd(a,b)
第二题
沙漏的最大总和
脑瘫题
第三题
题目:给你两个正整数 num1
和 num2
,找出满足下述条件的整数 x
:
x
的置位数和 num2
相同,且
x XOR num1
的值 最小
注意 XOR
是按位异或运算。
返回整数 x
。题目保证,对于生成的测试用例, x
是 唯一确定 的。
整数的 置位数 是其二进制表示中 1 的数目。
解法:其实就是尽量消除num1
中的1并且根据num2
的置位数数量分情况讨论,主要记录一些位运算的方法。
1:求置位数,c++:
bitset <位数> a (unsigned long);
cout<<a.count
2: lowbit:
lowbit=x&(-x);
之后用原数减去lowbit就可以去掉最后一位的1。
3:把一个数a最后的0变成1
a = 10011
a+1 = 10100
a|=a+1;
第四题
题目:给你一个仅由小写英文字母组成的字符串 s 。在一步操作中,你可以:
删除 整个字符串 s ,或者
对于满足 1 <= i <= s.length / 2 的任意 i ,如果 s 中的 前 i 个字母和接下来的 i 个字母 相等 ,删除 前 i 个字母。
例如,如果 s = “ababc” ,那么在一步操作中,你可以删除 s 的前两个字母得到 “abc” ,因为 s 的前两个字母和接下来的两个字母都等于 “ab” 。
返回删除 s 所需的最大操作数。
解法:对字符串操作之后的子字符串可以继续操作,相当于子问题,故用dp解决。
定义 f[i] 表示删除后缀 s[i:]所需的最大操作数。ans=f[0];
根据题意,我们可以枚举删除字母的长度 j,如果 s[i:i+j] = s[i+j:i+2j]
,那么可以删除,此时有转移 f[i] = f[i+j] + 1
。如果不存在两个子串相等的情况,则 f[i] = 1
。f[i]
取所有情况的最大值。
倒着计算 f[i]
,答案为 f[0]
。
class Solution {
public:
int deleteString(string s) {
int n = s.length();
if (equal(s.begin() + 1, s.end(), s.begin())) // 特判全部相同的情况
return n;
int lcp[n + 1][n + 1]; // lcp[i][j] 表示 s[i:] 和 s[j:] 的最长公共前缀
memset(lcp, 0, sizeof(lcp));
for (int i = n - 1; i >= 0; --i)
for (int j = n - 1; j > i; --j)
if (s[i] == s[j])
lcp[i][j] = lcp[i + 1][j + 1] + 1;
int f[n];
memset(f, 0, sizeof(f));
for (int i = n - 1; i >= 0; --i) {
f[i]=1;
for (int j = 1; i + j * 2 <= n; ++j)
if (lcp[i][i + j] >= j) // 说明 s[i:i+j] == s[i+j:i+j*2],等价于最长相同前缀长度(lcp)>j
f[i] = max(f[i], f[i + j]+1);
}
return f[0];
}
};
以上题解只是对灵神题解的总结,非原创捏1