一.打表
在程序中一次性计算出所有需要用到的结果,之后可直接取这些结果;
二.活用递推
正在计算的结果可以通过以前计算的结果得到;
三.随机选择算法
如何从一个无序的数组中求出第 K 大的数(数组中元素各不相同)
代码:
int randSelect(int A[], int left, int right, int K) {
if(left == right) return A[left];
else {
int p = randPartition(A, left, right);
int M = p - left + 1;
if(M == K) return A[p];
else if(M > K) return randSelect(A, left, p - 1, K);
else return randSelect(A, p + 1, right, K - M);
}
}
为什么递归边界是 left == right ?
四.题目
1.PAT B1040
思路:
1).统计出每个 A 左边的 numP 和右边的 numT,此 A 能形成的 PAT 数为 numP * numT;
2).如何统计:用数组保存每个char左边的 P 个数,利用递推式防止重复计算;计算右边的 T 个数的同时计算答案;
注意:
1).i --;
2).计算答案的每一步都取模,而不是最后一步取模;
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 10;
const int MOD = 1e9 + 7;
char ori[maxn];
int leftP[maxn] = {0};
int main() {
scanf("%s", ori);
int len = strlen(ori);
for(int i = 0; i < len; i++) {
if(i > 0) leftP[i] = leftP[i - 1];
if(ori[i] == 'P') leftP[i]++;
}
long int rightT = 0;
long int sum = 0;
for(int i = len - 1; i >= 0; i--) {
if(ori[i] == 'T') rightT++;
if(ori[i] == 'A') sum = (sum + leftP[i] * rightT) % MOD;
}
printf("%d", sum);
return 0;
}
2.PAT B1045
思路:
1).类似上面那道题,记录 A[i] 左边最大的数和右边最小的数;
2).对于首位两个数,设 leftMax[0] = 0,rightMin[n - 1] = INF;
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 10;
const int INF = 0x3fffffff;
int A[maxn], N;
int leftMax[maxn], rightMin[maxn], ans[maxn];
int main() {
scanf("%d",&N);
for(int i = 0; i < N; i++) {
scanf("%d",&A[i]);
if(i == 0) leftMax[i] = 0;
else leftMax[i] = max(leftMax[i - 1], A[i - 1]);
}
for(int i = N - 1; i >= 0; i--) {
if(i == N - 1) rightMin[i] = INF;
else rightMin[i] = min(rightMin[i + 1], A[i + 1]);
}
int cnt = 0;
int j = 0;
for(int i = 0; i < N; i++) {
if(leftMax[i] < A[i] && rightMin[i] > A[i]) {
cnt++;
ans[j++] = A[i];
}
}
printf("%d\n",cnt);
for(int i = 0; i < cnt; i ++) {
printf("%d",ans[i]);
if(i != cnt - 1) printf(" ");
}
printf("\n");
return 0;
}