一、知识点介绍(数论)
1. 素数
素数的概念:
1. 素数又称质数,素数首先满足条件是要大于等于2,并且除了1和它本身外,不能被其他任何自然数整除;
2. 1既不是素数也不是合数;
3. 2是唯一的偶素数。
素数筛选法:
#define maxp 65536
#define ll long long
int primes[maxp];
bool notprime[maxp]; // 1
void Eratosthenes() {
notprime[1] = true;
primes[0] = 0;
for (int i = 2; i < maxp; i++) {
if (!notprime[i]) {
primes[++primes[0]] = i; // 2
for (ll j = (ll)i*i; j < maxp; j += i) {
notprime[j] = true; // 3
}
}
}
}
二、练习题目
(1) 所有奇数长度子数组的和 简单
(2) 到目标元素的最小距离 简单
(3) 拆炸弹 简单
(4) 能否连接形成数组 简单
(5) 599. 两个列表的最小索引总和
(6) 674. 最长连续递增序列
(7) 989. 数组形式的整数加法
(8) 2319. 判断矩阵是否是一个 X 矩阵
三、算法思路
1. 所有奇数长度子数组的和
(1) 因为数据量特别小,所以暴力枚举就好了
(2) 位运算判断一个数字是不是奇数:形如(num & 1)如果为真的话,num就是奇数。
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
int ans = 0;
int i, j;
int sum;
for(i = 0; i < arr.size(); ++i) {
sum = 0;
for(j = i; j < arr.size(); ++j) {
sum += arr[j];
if((j-i+1) & 1) {
ans += sum;
}
}
}
return ans;
}
};
2. 到目标元素的最小距离
(1) 这道题按照题目要求一步步写下来就好了
(2) 可以用 abs() 方法,用来取绝对值的; 我一开始对这个方法不熟,具体用法就是:abs(需要取绝对值的式子或者变量)。
class Solution {
public:
int getMinDistance(vector<int>& nums, int target, int start) {
int min = 10020;
int i;
int temp = 0;
for(i = 0; i < nums.size(); ++i) {
if(nums[i] == target) {
temp = i -start;
if(temp< 0) temp = -temp;
if(temp < min) min = temp;
}
}
return min;
}
};
3. 拆炸弹
(1) 数据量比较小,所以按照题目要求一步步写下来就好了。
(2) 唯一需要纠结一下的地方就是,当k>0和k<0时,对数组的取值,为了防止越界,要对数组大小就是code.size()取模运算。
class Solution {
public:
vector<int> decrypt(vector<int>& code, int k) {
vector<int> ans;
int i, j;
int n = code.size();
for(i = 0; i < n; ++i) {
int cnt = 0;
int temp = 0;
if(k > 0) {
for(j = (i+1)%n; cnt < k; cnt++) {
temp += code[j];
j = (j+1) %n;
}
ans.push_back(temp);
}
if(k == 0) ans.push_back(0);
if(k < 0) {
for(j = (n+i-1) % n ; cnt > k; cnt--) {
temp += code[j];
j = (j-1+n) % n;
}
ans.push_back(temp);
}
}
return ans;
}
};
4. 能否连接形成数组
(1) 这道题也是暴力循环。要注意的是:要以arr数组为主,和pieces二维数组进行比较,没找到对应的值应该要continue继续找下去,不应该break。
(2) 需要设置一个flag,当数组中元素不对应的时候,flag设为false;对应的时候设为true
(3) 当arr遍历到了最后一个元素,且最后一个元素符合要求返回true
(4) 这道题建议多做几遍,我感觉自己不熟,有一些细节会出错,而且应该有更好的解决方法。
class Solution {
public:
bool canFormArray(vector<int>& arr, vector<vector<int>>& pieces) {
bool ans = false;
int i = 0, j, k;
while(i < arr.size()) {
ans = false;
for(j = 0; j < pieces.size(); ++j) {
if(arr[i] != pieces[j][0]) {
continue;
}
for(k = 0; k < pieces[j].size(); ++k) {
if(pieces[j][k] == arr[i]) {
i++;
ans = true;
} else {
return false;
}
}
if(i == arr.size()) {
return true;
}
}
if(!ans) return false;
}
return true;
}
};
5. 两个列表的最小索引总和
(1) 先遍历找出两个数组当中元素相同的索引值,再把最小的索引数的和存下来
(2) 再重新遍历一遍,当元素相同,并且索引值也等于最小索引数的值存入答案数组中
class Solution {
public:
vector<string> findRestaurant(vector<string>& list1, vector<string>& list2) {
int i, j;
int ans = 3000;
vector<string> res;
for(i = 0; i < list1.size(); ++i) {
for(j = 0; j < list2.size(); ++j) {
if(list1[i] == list2[j]) {
ans = min(ans, i+j);
}
}
}
for(i = 0; i < list1.size(); ++i) {
for(j = 0; j < list2.size(); ++j) {
if(list1[i] == list2[j] && (i+j) == ans) {
res.push_back(list1[i]);
}
}
}
return res;
}
};
6. 最长连续递增序列
(1) 遍历整个数组,如果递增就cnt++;再更新ans的值,ans保存cnt的最大值;
(2) 如果不递增,cnt初始化为1;
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
int cnt = 1;
int ans = 1;
int i;
for(i = 1; i < nums.size(); ++i) {
if(nums[i] > nums[i-1]) {
cnt++;
ans = max(ans, cnt);
} else {
cnt = 1;
}
}
return ans;
}
};
7. 数组形式的整数加法
(1) 这道题略复杂,用java写会更简单;
(2) C++的话,要先把num数组翻转
(3) 把k的值,按位存入一个新的数组中
(4) 然后在按位做加法,用一个pre存放进位的数,因为数组中最大的数为9,所以最多进1位;
(5) 加完之后要判断一个特殊情况,就是最后一位要进位的话,要再push_back一个1;
(6) 最后不要忘记翻转回去。
class Solution {
void address(vector<int>& num, int n, int pre) {
if(n == num.size()-1) {
if(pre > 0) {
num.push_back(1);
pre = 0;
}
if(num[n] > 9) {
num.push_back(1);
num[n] %= 10;
}
} else {
if(pre > 0) {
num[n+1]++;
pre = 0;
address(num, n+1, pre);
}
if(num[n] > 9) {
num[n+1] += 1;
pre = 0;
num[n] %= 10;
address(num, n+1, pre);
}
}
}
public:
vector<int> addToArrayForm(vector<int>& num, int k) {
int i, j;
int pre = 0;
vector<int> saveK;
vector<int> temp;
while(k) {
saveK.push_back(k%10);
k /= 10;
}
reverse(num.begin(), num.end());
if(saveK.size() > num.size()) {
temp = saveK;
saveK = num;
num = temp;
}
for(i = 0; i < saveK.size(); ++i) {
num[i] = num[i] + saveK[i] + pre;
if(num[i] > 9) {
pre = 1;
num[i] %= 10;
} else {
pre = 0;
}
if(i == saveK.size()-1) {
address(num, saveK.size()-1, pre);
}
}
reverse(num.begin(), num.end());
return num;
}
};
8. 判断矩阵是否是一个 X 矩阵
(1) 遍历整个矩阵,对角线的数字有一个特点就是i==j;
(2) 副对角线有一个特点就是(i+j) == grid.size()-1;
(3) 再按照题意写就好了。
class Solution {
public:
bool checkXMatrix(vector<vector<int>>& grid) {
int i, j;
int n = grid.size();
bool ans, flag = false;
for(i = 0; i < n; ++i) {
for(j = 0; j < n; ++j) {
if(i == j && grid[i][j] != 0) {
ans = true;
}else if((i+j) == n-1 && grid[i][j] != 0){
ans = true;
}else if((i != j) && ((i+j)!=n-1) && grid[i][j] == 0) {
ans = true;
}else {
ans = false;
flag = true;
break;
}
}
if(flag) break;
}
return ans;
}
};