From 3587b0cce0cb99371a6fd595c43dac3398466159 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Mon, 20 May 2024 09:03:55 +0800 Subject: [PATCH] feat: add ts solution to lc problem: No.1542 No.1542.Find Longest Awesome Substring --- .../README.md | 31 ++++++++++++- .../README_EN.md | 43 ++++++++++++++++++- .../Solution.ts | 24 +++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 solution/1500-1599/1542.Find Longest Awesome Substring/Solution.ts diff --git a/solution/1500-1599/1542.Find Longest Awesome Substring/README.md b/solution/1500-1599/1542.Find Longest Awesome Substring/README.md index ca26c962d4ffb..fd64bedaaa98a 100644 --- a/solution/1500-1599/1542.Find Longest Awesome Substring/README.md +++ b/solution/1500-1599/1542.Find Longest Awesome Substring/README.md @@ -80,7 +80,7 @@ tags: 而如果子字符串 $s[j,..i]$ 是“超赞字符串”,那么前缀字符串 $s[0,..i]$ 的状态 $st$ 与前缀字符串 $s[0,..j-1]$ 的状态 $st'$ 的二进制位中,最多只有一位不同。这是因为,二进制位不同,表示奇偶性不同,而奇偶性不同,就意味着子字符串 $s[j,..i]$ 中该数字出现的次数为奇数次。 -所以,我们可以用哈希表或数组记录所有状态 $st$ 第一次出现的位置。若当前前缀字符串的状态 $st$ 在哈希表中已经存在,那么说明当前前缀字符串的状态 $st$ 与前缀字符串 $s[0,..j-1]$ 的状态 $st'$ 的二进制位中,所有位都相同,即子字符串 $s[j,..i]$ 是“超赞字符串”,更新答案的最大值。或者,我们可以枚举每一位,将当前前缀字符串的状态 $st$ 的第 $i$ 位取反,即 $st \oplus (1 << i)$,然后判断 $st \oplus (1 << i)$ 是否在哈希表中,若在,那么说明当前前缀字符串的状态 $st$ 与前缀字符串 $s[0,..j-1]$ 的状态 $st' \oplus (1 << i)$ 的二进制位中,只有第 $i$ 位不同,即子字符串 $s[j,..i]$ 是“超赞字符串”,更新答案的最大值。 +所以,我们可以用哈希表或数组记录所有状态 $st$ 第一次出现的位置。若当前前缀字符串的状态 $st$ 在哈希表中已经存在,那么说明当前前缀字符串的状态 $st$ 与前缀字符串 $s[0,..j-1]$ 的状态 $st'$ 的二进制位中,所有位都相同,即子字符串 $s[j,..i]$ 是“超赞字符串”,更新答案的最大值。或者,我们可以枚举每一位,将当前前缀字符串的状态 $st$ 的第 $i$ 位取反,即 $st \oplus 2^i$,然后判断 $st \oplus 2^i$ 是否在哈希表中,若在,那么说明当前前缀字符串的状态 $st$ 与前缀字符串 $s[0,..j-1]$ 的状态 $st' \oplus 2^i$ 的二进制位中,只有第 $i$ 位不同,即子字符串 $s[j,..i]$ 是“超赞字符串”,更新答案的最大值。 最后,返回答案即可。 @@ -190,6 +190,35 @@ func longestAwesome(s string) int { } ``` +#### TypeScript + +```ts +function longestAwesome(s: string): number { + const d: number[] = Array(1024).fill(-1); + let [st, ans] = [0, 1]; + d[0] = 0; + + for (let i = 1; i <= s.length; ++i) { + const v = s.charCodeAt(i - 1) - '0'.charCodeAt(0); + st ^= 1 << v; + + if (d[st] >= 0) { + ans = Math.max(ans, i - d[st]); + } else { + d[st] = i; + } + + for (let v = 0; v < 10; ++v) { + if (d[st ^ (1 << v)] >= 0) { + ans = Math.max(ans, i - d[st ^ (1 << v)]); + } + } + } + + return ans; +} +``` + diff --git a/solution/1500-1599/1542.Find Longest Awesome Substring/README_EN.md b/solution/1500-1599/1542.Find Longest Awesome Substring/README_EN.md index 07d7b0c0e5f7b..aadd0ced4552f 100644 --- a/solution/1500-1599/1542.Find Longest Awesome Substring/README_EN.md +++ b/solution/1500-1599/1542.Find Longest Awesome Substring/README_EN.md @@ -62,7 +62,19 @@ tags: -### Solution 1 +### Solution 1: State Compression + Prefix Sum + +According to the problem description, the characters in the "super awesome substring" can be swapped to obtain a palindrome string. Therefore, there is at most one digit character in the "super awesome substring" that appears an odd number of times, and the rest of the digit characters appear an even number of times. + +We can use an integer $st$ to represent the parity of the digit characters in the current prefix string, where the $i$-th bit of $st$ represents the parity of the digit character $i$, i.e., the $i$-th bit of $st$ is $1$ means that the digit character $i$ appears an odd number of times, and $0$ means that the digit character $i$ appears an even number of times. + +If the substring $s[j,..i]$ is a "super awesome string", then the state $st$ of the prefix string $s[0,..i]$ and the state $st'$ of the prefix string $s[0,..j-1]$ differ by at most one bit in binary. This is because, if the binary bits are different, it means that the parity is different, and if the parity is different, it means that the number of times the digit appears in the substring $s[j,..i]$ is odd. + +So, we can use a hash table or array to record the first occurrence of all states $st$. If the state $st$ of the current prefix string already exists in the hash table, it means that all bits in the binary of the state $st$ of the current prefix string and the state $st'$ of the prefix string $s[0,..j-1]$ are the same, i.e., the substring $s[j,..i]$ is a "super awesome string", and we update the maximum value of the answer. Or, we can enumerate each bit, flip the $i$-th bit of the state $st$ of the current prefix string, i.e., $st \oplus 2^i$, and then check whether $st \oplus 2^i$ is in the hash table. If it is, it means that only the $i$-th bit in the binary of the state $st$ of the current prefix string and the state $st' \oplus 2^i$ of the prefix string $s[0,..j-1]$ is different, i.e., the substring $s[j,..i]$ is a "super awesome string", and we update the maximum value of the answer. + +Finally, return the answer. + +The time complexity is $O(n \times C)$, and the space complexity is $O(2^C)$. Where $n$ and $C$ are the length of the string $s$ and the number of types of digit characters, respectively. @@ -168,6 +180,35 @@ func longestAwesome(s string) int { } ``` +#### TypeScript + +```ts +function longestAwesome(s: string): number { + const d: number[] = Array(1024).fill(-1); + let [st, ans] = [0, 1]; + d[0] = 0; + + for (let i = 1; i <= s.length; ++i) { + const v = s.charCodeAt(i - 1) - '0'.charCodeAt(0); + st ^= 1 << v; + + if (d[st] >= 0) { + ans = Math.max(ans, i - d[st]); + } else { + d[st] = i; + } + + for (let v = 0; v < 10; ++v) { + if (d[st ^ (1 << v)] >= 0) { + ans = Math.max(ans, i - d[st ^ (1 << v)]); + } + } + } + + return ans; +} +``` + diff --git a/solution/1500-1599/1542.Find Longest Awesome Substring/Solution.ts b/solution/1500-1599/1542.Find Longest Awesome Substring/Solution.ts new file mode 100644 index 0000000000000..8cf1091362d14 --- /dev/null +++ b/solution/1500-1599/1542.Find Longest Awesome Substring/Solution.ts @@ -0,0 +1,24 @@ +function longestAwesome(s: string): number { + const d: number[] = Array(1024).fill(-1); + let [st, ans] = [0, 1]; + d[0] = 0; + + for (let i = 1; i <= s.length; ++i) { + const v = s.charCodeAt(i - 1) - '0'.charCodeAt(0); + st ^= 1 << v; + + if (d[st] >= 0) { + ans = Math.max(ans, i - d[st]); + } else { + d[st] = i; + } + + for (let v = 0; v < 10; ++v) { + if (d[st ^ (1 << v)] >= 0) { + ans = Math.max(ans, i - d[st ^ (1 << v)]); + } + } + } + + return ans; +}