|
53 | 53 |
|
54 | 54 | <!-- 这里可写通用的实现逻辑 -->
|
55 | 55 |
|
| 56 | +**方法一:贪心 + 动态规划 + 逆推** |
| 57 | + |
| 58 | +我们定义 $f[i][j]$ 表示在前 $i$ 个数中选取若干个数,使得选取的数的和模 $3$ 为 $j$ 的最大长度。为了使得选取的数最大,我们需要尽可能选取更多的数,因此我们需要使得 $f[i][j]$ 尽可能大。我们初始化 $f[0][0] = 0$,其余的 $f[0][j] = -\infty$。 |
| 59 | + |
| 60 | +考虑 $f[i][j]$ 如何进行状态转移。我们可以不选取第 $i$ 个数,此时 $f[i][j] = f[i - 1][j]$;我们也可以选取第 $i$ 个数,此时 $f[i][j] = f[i - 1][(j - x_i \bmod 3 + 3) \bmod 3] + 1$,其中 $x_i$ 表示第 $i$ 个数的值。因此我们有如下的状态转移方程: |
| 61 | + |
| 62 | +$$ |
| 63 | +f[i][j] = \max \{ f[i - 1][j], f[i - 1][(j - x_i \bmod 3 + 3) \bmod 3] + 1 \} |
| 64 | +$$ |
| 65 | + |
| 66 | +如果 $f[n][0] \le 0$,那么我们无法选取任何数,因此答案字符串为空。否则我们可以通过 $f$ 数组进行逆推,找出选取的数。 |
| 67 | + |
| 68 | +定义 $i = n$, $j = 0$,从 $f[i][j]$ 开始逆推,记 $k = (j - x_i \bmod 3 + 3) \bmod 3$,如果 $f[i - 1][k] + 1 = f[i][j]$,那么我们选取了第 $i$ 个数,否则我们没有选取第 $i$ 个数。如果我们选取了第 $i$ 个数,那么我们将 $j$ 更新为 $k$,否则我们保持 $j$ 不变。为了使得同等长度的数最大,我们应该优先选取较大的数,因此,我们在前面首先对数组进行排序。 |
| 69 | + |
| 70 | +时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为数组的长度。 |
| 71 | + |
56 | 72 | <!-- tabs:start -->
|
57 | 73 |
|
58 | 74 | ### **Python3**
|
59 | 75 |
|
60 | 76 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
61 | 77 |
|
62 | 78 | ```python
|
63 |
| - |
| 79 | +class Solution: |
| 80 | + def largestMultipleOfThree(self, digits: List[int]) -> str: |
| 81 | + digits.sort() |
| 82 | + n = len(digits) |
| 83 | + f = [[-inf] * 3 for _ in range(n + 1)] |
| 84 | + f[0][0] = 0 |
| 85 | + for i, x in enumerate(digits, 1): |
| 86 | + for j in range(3): |
| 87 | + f[i][j] = max(f[i - 1][j], f[i - 1][(j - x % 3 + 3) % 3] + 1) |
| 88 | + if f[n][0] <= 0: |
| 89 | + return "" |
| 90 | + arr = [] |
| 91 | + j = 0 |
| 92 | + for i in range(n, 0, -1): |
| 93 | + k = (j - digits[i - 1] % 3 + 3) % 3 |
| 94 | + if f[i - 1][k] + 1 == f[i][j]: |
| 95 | + arr.append(digits[i - 1]) |
| 96 | + j = k |
| 97 | + i = 0 |
| 98 | + while i < len(arr) - 1 and arr[i] == 0: |
| 99 | + i += 1 |
| 100 | + return "".join(map(str, arr[i:])) |
64 | 101 | ```
|
65 | 102 |
|
66 | 103 | ### **Java**
|
67 | 104 |
|
68 | 105 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
69 | 106 |
|
70 | 107 | ```java
|
| 108 | +class Solution { |
| 109 | + public String largestMultipleOfThree(int[] digits) { |
| 110 | + Arrays.sort(digits); |
| 111 | + int n = digits.length; |
| 112 | + int[][] f = new int[n + 1][3]; |
| 113 | + final int inf = 1 << 30; |
| 114 | + for (var g : f) { |
| 115 | + Arrays.fill(g, -inf); |
| 116 | + } |
| 117 | + f[0][0] = 0; |
| 118 | + for (int i = 1; i <= n; ++i) { |
| 119 | + for (int j = 0; j < 3; ++j) { |
| 120 | + f[i][j] = Math.max(f[i - 1][j], f[i - 1][(j - digits[i - 1] % 3 + 3) % 3] + 1); |
| 121 | + } |
| 122 | + } |
| 123 | + if (f[n][0] <= 0) { |
| 124 | + return ""; |
| 125 | + } |
| 126 | + StringBuilder sb = new StringBuilder(); |
| 127 | + for (int i = n, j = 0; i > 0; --i) { |
| 128 | + int k = (j - digits[i - 1] % 3 + 3) % 3; |
| 129 | + if (f[i - 1][k] + 1 == f[i][j]) { |
| 130 | + sb.append(digits[i - 1]); |
| 131 | + j = k; |
| 132 | + } |
| 133 | + } |
| 134 | + int i = 0; |
| 135 | + while (i < sb.length() - 1 && sb.charAt(i) == '0') { |
| 136 | + ++i; |
| 137 | + } |
| 138 | + return sb.substring(i); |
| 139 | + } |
| 140 | +} |
| 141 | +``` |
| 142 | + |
| 143 | +### **C++** |
| 144 | + |
| 145 | +```cpp |
| 146 | +class Solution { |
| 147 | +public: |
| 148 | + string largestMultipleOfThree(vector<int>& digits) { |
| 149 | + sort(digits.begin(), digits.end()); |
| 150 | + int n = digits.size(); |
| 151 | + int f[n + 1][3]; |
| 152 | + memset(f, -0x3f, sizeof(f)); |
| 153 | + f[0][0] = 0; |
| 154 | + for (int i = 1; i <= n; ++i) { |
| 155 | + for (int j = 0; j < 3; ++j) { |
| 156 | + f[i][j] = max(f[i - 1][j], f[i - 1][(j - digits[i - 1] % 3 + 3) % 3] + 1); |
| 157 | + } |
| 158 | + } |
| 159 | + if (f[n][0] <= 0) { |
| 160 | + return ""; |
| 161 | + } |
| 162 | + string ans; |
| 163 | + for (int i = n, j = 0; i; --i) { |
| 164 | + int k = (j - digits[i - 1] % 3 + 3) % 3; |
| 165 | + if (f[i - 1][k] + 1 == f[i][j]) { |
| 166 | + ans += digits[i - 1] + '0'; |
| 167 | + j = k; |
| 168 | + } |
| 169 | + } |
| 170 | + int i = 0; |
| 171 | + while (i < ans.size() - 1 && ans[i] == '0') { |
| 172 | + ++i; |
| 173 | + } |
| 174 | + return ans.substr(i); |
| 175 | + } |
| 176 | +}; |
| 177 | +``` |
| 178 | +
|
| 179 | +### **Go** |
| 180 | +
|
| 181 | +```go |
| 182 | +func largestMultipleOfThree(digits []int) string { |
| 183 | + sort.Ints(digits) |
| 184 | + n := len(digits) |
| 185 | + const inf = 1 << 30 |
| 186 | + f := make([][]int, n+1) |
| 187 | + for i := range f { |
| 188 | + f[i] = make([]int, 3) |
| 189 | + for j := range f[i] { |
| 190 | + f[i][j] = -inf |
| 191 | + } |
| 192 | + } |
| 193 | + f[0][0] = 0 |
| 194 | + for i := 1; i <= n; i++ { |
| 195 | + for j := 0; j < 3; j++ { |
| 196 | + f[i][j] = max(f[i-1][j], f[i-1][(j-digits[i-1]%3+3)%3]+1) |
| 197 | + } |
| 198 | + } |
| 199 | + if f[n][0] <= 0 { |
| 200 | + return "" |
| 201 | + } |
| 202 | + ans := []byte{} |
| 203 | + for i, j := n, 0; i > 0; i-- { |
| 204 | + k := (j - digits[i-1]%3 + 3) % 3 |
| 205 | + if f[i][j] == f[i-1][k]+1 { |
| 206 | + ans = append(ans, byte('0'+digits[i-1])) |
| 207 | + j = k |
| 208 | + } |
| 209 | + } |
| 210 | + i := 0 |
| 211 | + for i < len(ans)-1 && ans[i] == '0' { |
| 212 | + i++ |
| 213 | + } |
| 214 | + return string(ans[i:]) |
| 215 | +} |
| 216 | +
|
| 217 | +func max(a, b int) int { |
| 218 | + if a > b { |
| 219 | + return a |
| 220 | + } |
| 221 | + return b |
| 222 | +} |
| 223 | +``` |
71 | 224 |
|
| 225 | +### **TypeScript** |
| 226 | + |
| 227 | +```ts |
| 228 | +function largestMultipleOfThree(digits: number[]): string { |
| 229 | + digits.sort((a, b) => a - b); |
| 230 | + const n = digits.length; |
| 231 | + const f: number[][] = new Array(n + 1).fill(0).map(() => new Array(3).fill(-Infinity)); |
| 232 | + f[0][0] = 0; |
| 233 | + for (let i = 1; i <= n; ++i) { |
| 234 | + for (let j = 0; j < 3; ++j) { |
| 235 | + f[i][j] = Math.max(f[i - 1][j], f[i - 1][(j - (digits[i - 1] % 3) + 3) % 3] + 1); |
| 236 | + } |
| 237 | + } |
| 238 | + if (f[n][0] <= 0) { |
| 239 | + return ''; |
| 240 | + } |
| 241 | + const arr: number[] = []; |
| 242 | + for (let i = n, j = 0; i; --i) { |
| 243 | + const k = (j - (digits[i - 1] % 3) + 3) % 3; |
| 244 | + if (f[i - 1][k] + 1 === f[i][j]) { |
| 245 | + arr.push(digits[i - 1]); |
| 246 | + j = k; |
| 247 | + } |
| 248 | + } |
| 249 | + let i = 0; |
| 250 | + while (i < arr.length - 1 && arr[i] === 0) { |
| 251 | + ++i; |
| 252 | + } |
| 253 | + return arr.slice(i).join(''); |
| 254 | +} |
72 | 255 | ```
|
73 | 256 |
|
74 | 257 | ### **...**
|
|
0 commit comments