活用递推

许多题目需要细心考虑是否可能用到递推关系

例如就一类涉及序列的题目来说。假如 序列的每一位所需要计算的值 都可以通过 该位左右两侧的计算结果得到,那就可以考虑所谓的“左右两侧的结果”是否可以通过递推进行预处理来得到,这样在后面的使用中就可以不必反复求解

例题:PAT B1040/A1093 有几个PAT

题目描述

字符串 APPAPT 中包含了两个单词“PAT”,其中第一个PAT是由第二位(P)、第四位(A)和第六位(T)组成的;第二个PAT是由第三位(P)、第四位(A)和第六位(T)组成的。现给定字符串,问一共可以形成多少个PAT?

输入格式

输入只有一行,包含一个字符串,长度不超过 105,只包含 P、A、T 这三种字母

输出格式

在一行中输出给定字符串中包含多少个 PAT。由于结果比较大,因此只输出对 1000000007 取余数的结果

输入样例

APPAPT

输出样例

2

这题与 PAT B1045/A1101 的思路很像

思路

直接用暴力会超时

换个角度考虑,对一个确定位置的 A 来说,以他为中心形成的 PAT 的个数等于 它左边P的个数 * 它右边T的个数,例如序列 PPAPT 就是 2*1=2。这样问题就转换成了:对序列中的每个 A,计算 其左边P个数 与 其右边T个数的乘积 之和

那么有没有比较快的获取每一位左边 P 个数的方法呢?有,递推

设定一个数组 leftNumP,它用来记录每一位左边 P 的个数(含当前位,下同)。接着从左向右遍历字符串,如果当前位(第 i 位)是 P,那么 lleftNumP[i] = leftNumP[i]+1;如果当前位不是 P,那么 leftNumP[i] = leftNumP[i-1]

这样的方法只要 O(len) 的时间复杂度就能统计出 leftNumP 数组

这使我想到了计算相同分数相同排名的方法:首先将分数数组进行非递增排序,然后从头遍历分数数组,如果当前分数与上一位同学的分数相同,那么排名就相同,如果比上一位同学小,那排名+1

以同样的方法可以计算出右边 T 的个数。为了节省代码,不妨在统计每一位右边 T 的个数时,直接计算答案 ans


胡凡《算法笔记》

你可能感兴趣的:(数据结构与算法)