|
64 | 64 |
|
65 | 65 | <!-- 这里可写通用的实现逻辑 -->
|
66 | 66 |
|
| 67 | +**方法一:计数 + 排列组合 + 预处理** |
| 68 | + |
| 69 | +题目中的操作实际上是求当前排列的上一个字典序排列,因此,我们只需要求出比当前排列小的排列的数量,就是答案。 |
| 70 | + |
| 71 | +这里我们需要考虑一个问题,给定每一种字母的频率,我们可以构造出多少种不同的排列? |
| 72 | + |
| 73 | +假设总共有 $n$ 个字母,其中字母 $a$ 有 $n_1$ 个,字母 $b$ 有 $n_2$ 个,字母 $c$ 有 $n_3$ 个,那么我们可以构造出 $\frac{n!}{n_1! \times n_2! \times n_3!}$ 种不同的排列。其中 $n=n_1+n_2+n_3$。 |
| 74 | + |
| 75 | +我们可以通过预处理的方式,预先计算出所有的阶乘 $f$ 和阶乘的逆元 $g$。其中阶乘的逆元可以通过费马小定理求得。 |
| 76 | + |
| 77 | +接下来,我们从左到右遍历字符串 $s$,对于每一个位置 $i$,我们需要求出当前总共有多少个比 $s[i]$ 小的字母,记为 $m$。那么,我们可以构造出 $m \times \frac{(n - i - 1)!}{n_1! \times n_2! \cdots \times n_k!}$ 种不同的排列,其中 $k$ 为字母的种类数,累加到答案中。接下来,我们将 $s[i]$ 的频率减一,继续遍历下一个位置。 |
| 78 | + |
| 79 | +遍历完整个字符串后,即可得到答案。注意答案的取模操作。 |
| 80 | + |
| 81 | +时间复杂度 $O(n \times k)$,空间复杂度 $O(n)$。其中 $n$ 和 $k$ 分别为字符串的长度和字母的种类数。 |
| 82 | + |
67 | 83 | <!-- tabs:start -->
|
68 | 84 |
|
69 | 85 | ### **Python3**
|
70 | 86 |
|
71 | 87 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
72 | 88 |
|
73 | 89 | ```python
|
74 |
| - |
| 90 | +n = 3010 |
| 91 | +mod = 10**9 + 7 |
| 92 | +f = [1] + [0] * n |
| 93 | +g = [1] + [0] * n |
| 94 | + |
| 95 | +for i in range(1, n): |
| 96 | + f[i] = f[i - 1] * i % mod |
| 97 | + g[i] = pow(f[i], mod - 2, mod) |
| 98 | + |
| 99 | + |
| 100 | +class Solution: |
| 101 | + def makeStringSorted(self, s: str) -> int: |
| 102 | + cnt = Counter(s) |
| 103 | + ans, n = 0, len(s) |
| 104 | + for i, c in enumerate(s): |
| 105 | + m = sum(v for a, v in cnt.items() if a < c) |
| 106 | + t = f[n - i - 1] * m |
| 107 | + for v in cnt.values(): |
| 108 | + t = t * g[v] % mod |
| 109 | + ans = (ans + t) % mod |
| 110 | + cnt[c] -= 1 |
| 111 | + if cnt[c] == 0: |
| 112 | + cnt.pop(c) |
| 113 | + return ans |
75 | 114 | ```
|
76 | 115 |
|
77 | 116 | ### **Java**
|
78 | 117 |
|
79 | 118 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
80 | 119 |
|
81 | 120 | ```java
|
| 121 | +class Solution { |
| 122 | + private static final int N = 3010; |
| 123 | + private static final int MOD = (int) 1e9 + 7; |
| 124 | + private static final long[] f = new long[N]; |
| 125 | + private static final long[] g = new long[N]; |
| 126 | + |
| 127 | + static { |
| 128 | + f[0] = 1; |
| 129 | + g[0] = 1; |
| 130 | + for (int i = 1; i < N; ++i) { |
| 131 | + f[i] = f[i - 1] * i % MOD; |
| 132 | + g[i] = qmi(f[i], MOD - 2); |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + public static long qmi(long a, int k) { |
| 137 | + long res = 1; |
| 138 | + while (k != 0) { |
| 139 | + if ((k & 1) == 1) { |
| 140 | + res = res * a % MOD; |
| 141 | + } |
| 142 | + k >>= 1; |
| 143 | + a = a * a % MOD; |
| 144 | + } |
| 145 | + return res; |
| 146 | + } |
| 147 | + |
| 148 | + public int makeStringSorted(String s) { |
| 149 | + int[] cnt = new int[26]; |
| 150 | + int n = s.length(); |
| 151 | + for (int i = 0; i < n; ++i) { |
| 152 | + ++cnt[s.charAt(i) - 'a']; |
| 153 | + } |
| 154 | + long ans = 0; |
| 155 | + for (int i = 0; i < n; ++i) { |
| 156 | + int m = 0; |
| 157 | + for (int j = s.charAt(i) - 'a' - 1; j >= 0; --j) { |
| 158 | + m += cnt[j]; |
| 159 | + } |
| 160 | + long t = m * f[n - i - 1] % MOD; |
| 161 | + for (int v : cnt) { |
| 162 | + t = t * g[v] % MOD; |
| 163 | + } |
| 164 | + --cnt[s.charAt(i) - 'a']; |
| 165 | + ans = (ans + t + MOD) % MOD; |
| 166 | + } |
| 167 | + return (int) ans; |
| 168 | + } |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +### **C++** |
| 173 | + |
| 174 | +```cpp |
| 175 | +const int N = 3010; |
| 176 | +const int MOD = 1e9 + 7; |
| 177 | +long f[N]; |
| 178 | +long g[N]; |
| 179 | + |
| 180 | +long qmi(long a, int k) { |
| 181 | + long res = 1; |
| 182 | + while (k != 0) { |
| 183 | + if ((k & 1) == 1) { |
| 184 | + res = res * a % MOD; |
| 185 | + } |
| 186 | + k >>= 1; |
| 187 | + a = a * a % MOD; |
| 188 | + } |
| 189 | + return res; |
| 190 | +} |
| 191 | + |
| 192 | +int init = []() { |
| 193 | + f[0] = g[0] = 1; |
| 194 | + for (int i = 1; i < N; ++i) { |
| 195 | + f[i] = f[i - 1] * i % MOD; |
| 196 | + g[i] = qmi(f[i], MOD - 2); |
| 197 | + } |
| 198 | + return 0; |
| 199 | +}(); |
| 200 | + |
| 201 | + |
| 202 | +class Solution { |
| 203 | +public: |
| 204 | + int makeStringSorted(string s) { |
| 205 | + int cnt[26]{}; |
| 206 | + for (char& c : s) { |
| 207 | + ++cnt[c - 'a']; |
| 208 | + } |
| 209 | + int n = s.size(); |
| 210 | + long ans = 0; |
| 211 | + for (int i = 0; i < n; ++i) { |
| 212 | + int m = 0; |
| 213 | + for (int j = s[i] - 'a' - 1; ~j; --j) { |
| 214 | + m += cnt[j]; |
| 215 | + } |
| 216 | + long t = m * f[n - i - 1] % MOD; |
| 217 | + for (int& v : cnt) { |
| 218 | + t = t * g[v] % MOD; |
| 219 | + } |
| 220 | + ans = (ans + t + MOD) % MOD; |
| 221 | + --cnt[s[i] - 'a']; |
| 222 | + } |
| 223 | + return ans; |
| 224 | + } |
| 225 | +}; |
| 226 | +``` |
82 | 227 |
|
| 228 | +### **Go** |
| 229 | +
|
| 230 | +```go |
| 231 | +const n = 3010 |
| 232 | +const mod = 1e9 + 7 |
| 233 | +
|
| 234 | +var f = make([]int, n) |
| 235 | +var g = make([]int, n) |
| 236 | +
|
| 237 | +func qmi(a, k int) int { |
| 238 | + res := 1 |
| 239 | + for k != 0 { |
| 240 | + if k&1 == 1 { |
| 241 | + res = res * a % mod |
| 242 | + } |
| 243 | + k >>= 1 |
| 244 | + a = a * a % mod |
| 245 | + } |
| 246 | + return res |
| 247 | +} |
| 248 | +
|
| 249 | +func init() { |
| 250 | + f[0], g[0] = 1, 1 |
| 251 | + for i := 1; i < n; i++ { |
| 252 | + f[i] = f[i-1] * i % mod |
| 253 | + g[i] = qmi(f[i], mod-2) |
| 254 | + } |
| 255 | +} |
| 256 | +
|
| 257 | +func makeStringSorted(s string) (ans int) { |
| 258 | + cnt := [26]int{} |
| 259 | + for _, c := range s { |
| 260 | + cnt[c-'a']++ |
| 261 | + } |
| 262 | + for i, c := range s { |
| 263 | + m := 0 |
| 264 | + for j := int(c-'a') - 1; j >= 0; j-- { |
| 265 | + m += cnt[j] |
| 266 | + } |
| 267 | + t := m * f[len(s)-i-1] % mod |
| 268 | + for _, v := range cnt { |
| 269 | + t = t * g[v] % mod |
| 270 | + } |
| 271 | + ans = (ans + t + mod) % mod |
| 272 | + cnt[c-'a']-- |
| 273 | + } |
| 274 | + return |
| 275 | +} |
83 | 276 | ```
|
84 | 277 |
|
85 | 278 | ### **...**
|
|
0 commit comments