3337: Total-Characters-in-String-After-Transformations-II
Hard
table of contents
Main Algorithm:
Looking at this question, since there is no difference between
applying t
transformations on separate letters of the same
type, it makes intuitive sense to precompute the number of letters you
are left after transforming each letter in the alphabet t
times.
But how would you do this?
You can do this by rephrasing the question problem. For example,
given the nums
array:
we can compute a 26 x 26
matrix to
compute the letters formed after 1 transformation.
In this 26 x 26
matrix, each row
corresponds to the letters formed after 1 transformation. For example,
given the nums
array above, if we take the letter
c
located at index position 2jI
, since
nums[2] = 3
, it means the 3
letters after
c
will be formed. In the matrix, that specific row (row 3)
will look like:
If we do this for all the 26 rows, then we will end
up with a transformation matrix, A
. This
transformation matrix basically means that, if we want
to find the frequency of any letter, we can just check the index, we can
initialize a vector, v
, of height 26
, with the
value at each index being 1
,
and then do the operation A * v
so that each index is
thus the length of each letter after 1
transformation.
For consequent transformations, we can just continue multiplying
v
by A
. This leads us to our first (and only)
optimisation (there is too many…)
Square and Multiply Algorithm:
To slightly speed-up the multiplication process,
realise that we can convert it to O(log(t))
.
Given t = 23
, we can convert t
into
binary to get 0b10111
.
Since multiplying v
by A
23 times
is just A^23 * v
Now, using the binary representation of
23
, we get A^23
=
A^1 + A^2 + A^4 + A^16
.
Overall, that means instead of doing ... * (A * (A * v))
23 times (which is equivalent to A^23 * v
) we can
just continuously square A
, and break down
the original equation into
A^23 * v = (A^1 * v) + (A^2 * v) + (A^4 * v) + (A^16 * v).
code
class Solution {
public:
int lengthAfterTransformations(string s, int t, vector<int>& nums) {
<vector<long>> matrix (26, vector<long>(26, 0));
vector<vector<long>> v (26, vector<long>(1, 1));
vector
for (int i = 0; i < nums.size(); ++i) {
for (int j = 1; j <= nums[i]; ++j) {
++matrix[i][(i+j)%26];
}
}
int n = t;
while (n > 0) {
if (n%2 == 1) {
= matrixMultiplication(matrix, v);
v }
= matrixMultiplication(matrix, matrix);
matrix >>= 1;
n }
long ans = 0;
for (char& c : s) {
= (ans + v[c-'a'][0]) % MOD;
ans }
return ans;
}
private:
static const int MOD = 1e9+7;
<vector<long>> matrixMultiplication(vector<vector<long>> &leftMatrix, vector<vector<long>> &rightMatrix) {
vector<vector<long>> result (leftMatrix.size(), vector<long>(rightMatrix[0].size(), 0));
vector
for (int i = 0; i < leftMatrix.size(); ++i) {
for (int j = 0; j < rightMatrix[0].size(); ++j) {
for (int k = 0; k < rightMatrix.size(); ++k) {
[i][j] = (result[i][j] + leftMatrix[i][k] * rightMatrix[k][j]) % MOD;
result}
}
}
return result;
}
};