From b5b16d73de32474928074c1cadeef31861d6f9ad Mon Sep 17 00:00:00 2001 From: yanglbme Date: Thu, 6 Feb 2025 13:58:58 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1930 No.1930.Unique Length-3 Palindromic Subsequences --- .../README.md | 128 +++++++++-------- .../README_EN.md | 134 ++++++++++-------- .../Solution.cpp | 13 +- .../Solution.cs | 9 +- .../Solution.go | 11 +- .../Solution.java | 11 +- .../Solution.js | 33 +++-- .../Solution.ts | 27 ++-- 8 files changed, 210 insertions(+), 156 deletions(-) diff --git a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/README.md b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/README.md index d211ced089ca7..05f86a482da50 100644 --- a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/README.md +++ b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/README.md @@ -87,7 +87,7 @@ tags: 枚举结束后,即可得到答案。 -时间复杂度 $O(n \times C)$,空间复杂度 $O(C)$,其中 $n$ 为字符串长度,而 $C$ 为字符集大小。本题中 $C = 26$。 +时间复杂度 $O(n \times |\Sigma|)$,其中 $n$ 为字符串长度,而 $\Sigma$ 为字符集大小,本题中 $|\Sigma| = 26$。空间复杂度 $O(|\Sigma|)$ 或 $O(1)$。 @@ -112,11 +112,14 @@ class Solution { int ans = 0; for (char c = 'a'; c <= 'z'; ++c) { int l = s.indexOf(c), r = s.lastIndexOf(c); - Set cs = new HashSet<>(); + int mask = 0; for (int i = l + 1; i < r; ++i) { - cs.add(s.charAt(i)); + int j = s.charAt(i) - 'a'; + if ((mask >> j & 1) == 0) { + mask |= 1 << j; + ++ans; + } } - ans += cs.size(); } return ans; } @@ -132,9 +135,14 @@ public: int ans = 0; for (char c = 'a'; c <= 'z'; ++c) { int l = s.find_first_of(c), r = s.find_last_of(c); - unordered_set cs; - for (int i = l + 1; i < r; ++i) cs.insert(s[i]); - ans += cs.size(); + int mask = 0; + for (int i = l + 1; i < r; ++i) { + int j = s[i] - 'a'; + if (mask >> j & 1 ^ 1) { + mask |= 1 << j; + ++ans; + } + } } return ans; } @@ -147,55 +155,38 @@ public: func countPalindromicSubsequence(s string) (ans int) { for c := 'a'; c <= 'z'; c++ { l, r := strings.Index(s, string(c)), strings.LastIndex(s, string(c)) - cs := map[byte]struct{}{} + mask := 0 for i := l + 1; i < r; i++ { - cs[s[i]] = struct{}{} + j := int(s[i] - 'a') + if mask>>j&1 == 0 { + mask |= 1 << j + ans++ + } } - ans += len(cs) } return } ``` -#### C# - -```cs -public class Solution { - public int CountPalindromicSubsequence(string s) { - int ans = 0; - for (char c = 'a'; c <= 'z'; ++c) { - int l = s.IndexOf(c), r = s.LastIndexOf(c); - HashSet cs = new HashSet(); - for (int i = l + 1; i < r; ++i) { - cs.Add(s[i]); - } - ans += cs.Count; - } - return ans; - } -} -``` - #### TypeScript ```ts -export function countPalindromicSubsequence(s: string): number { - const cnt = new Map(); - const n = s.length; +function countPalindromicSubsequence(s: string): number { let ans = 0; - - for (let i = 0; i < n; i++) { - const ch = s[i]; - if (cnt.has(ch)) cnt.get(ch)![1] = i; - else cnt.set(ch, [i, i]); - } - - for (const [_, [i, j]] of cnt) { - if (i !== j) { - ans += new Set(s.slice(i + 1, j)).size; + const a = 'a'.charCodeAt(0); + for (let ch = 0; ch < 26; ++ch) { + const c = String.fromCharCode(ch + a); + const l = s.indexOf(c); + const r = s.lastIndexOf(c); + let mask = 0; + for (let i = l + 1; i < r; ++i) { + const j = s.charCodeAt(i) - a; + if (((mask >> j) & 1) ^ 1) { + mask |= 1 << j; + ++ans; + } } } - return ans; } ``` @@ -203,24 +194,49 @@ export function countPalindromicSubsequence(s: string): number { #### JavaScript ```js -export function countPalindromicSubsequence(s) { - const cnt = new Map(); - const n = s.length; +/** + * @param {string} s + * @return {number} + */ +var countPalindromicSubsequence = function (s) { let ans = 0; - - for (let i = 0; i < n; i++) { - const ch = s[i]; - if (cnt.has(ch)) cnt.get(ch)[1] = i; - else cnt.set(ch, [i, i]); + const a = 'a'.charCodeAt(0); + for (let ch = 0; ch < 26; ++ch) { + const c = String.fromCharCode(ch + a); + const l = s.indexOf(c); + const r = s.lastIndexOf(c); + let mask = 0; + for (let i = l + 1; i < r; ++i) { + const j = s.charCodeAt(i) - a; + if (((mask >> j) & 1) ^ 1) { + mask |= 1 << j; + ++ans; + } + } } + return ans; +}; +``` - for (const [_, [i, j]] of cnt) { - if (i !== j) { - ans += new Set(s.slice(i + 1, j)).size; +#### C# + +```cs +public class Solution { + public int CountPalindromicSubsequence(string s) { + int ans = 0; + for (char c = 'a'; c <= 'z'; ++c) { + int l = s.IndexOf(c), r = s.LastIndexOf(c); + int mask = 0; + for (int i = l + 1; i < r; ++i) { + int j = s[i] - 'a'; + if ((mask >> j & 1) == 0) { + mask |= 1 << j; + ++ans; + } + } } + return ans; } - - return ans; } ``` diff --git a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/README_EN.md b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/README_EN.md index 98f8bacde694b..d859523c8fe19 100644 --- a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/README_EN.md +++ b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/README_EN.md @@ -79,7 +79,13 @@ tags: -### Solution 1 +### Solution 1: Enumerate Both End Characters + Hash Table + +Since the string contains only lowercase letters, we can directly enumerate all pairs of end characters. For each pair of end characters $c$, we find their first and last occurrence positions $l$ and $r$ in the string. If $r - l > 1$, it means we have found a palindromic subsequence that meets the conditions. We then count the number of unique characters between $[l+1,..r-1]$, which gives the number of palindromic subsequences with $c$ as the end characters, and add it to the answer. + +After enumerating all pairs, we get the answer. + +The time complexity is $O(n \times |\Sigma|)$, where $n$ is the length of the string and $\Sigma$ is the size of the character set. In this problem, $|\Sigma| = 26$. The space complexity is $O(|\Sigma|)$ or $O(1)$. @@ -104,11 +110,14 @@ class Solution { int ans = 0; for (char c = 'a'; c <= 'z'; ++c) { int l = s.indexOf(c), r = s.lastIndexOf(c); - Set cs = new HashSet<>(); + int mask = 0; for (int i = l + 1; i < r; ++i) { - cs.add(s.charAt(i)); + int j = s.charAt(i) - 'a'; + if ((mask >> j & 1) == 0) { + mask |= 1 << j; + ++ans; + } } - ans += cs.size(); } return ans; } @@ -124,9 +133,14 @@ public: int ans = 0; for (char c = 'a'; c <= 'z'; ++c) { int l = s.find_first_of(c), r = s.find_last_of(c); - unordered_set cs; - for (int i = l + 1; i < r; ++i) cs.insert(s[i]); - ans += cs.size(); + int mask = 0; + for (int i = l + 1; i < r; ++i) { + int j = s[i] - 'a'; + if (mask >> j & 1 ^ 1) { + mask |= 1 << j; + ++ans; + } + } } return ans; } @@ -139,55 +153,38 @@ public: func countPalindromicSubsequence(s string) (ans int) { for c := 'a'; c <= 'z'; c++ { l, r := strings.Index(s, string(c)), strings.LastIndex(s, string(c)) - cs := map[byte]struct{}{} + mask := 0 for i := l + 1; i < r; i++ { - cs[s[i]] = struct{}{} + j := int(s[i] - 'a') + if mask>>j&1 == 0 { + mask |= 1 << j + ans++ + } } - ans += len(cs) } return } ``` -#### C# - -```cs -public class Solution { - public int CountPalindromicSubsequence(string s) { - int ans = 0; - for (char c = 'a'; c <= 'z'; ++c) { - int l = s.IndexOf(c), r = s.LastIndexOf(c); - HashSet cs = new HashSet(); - for (int i = l + 1; i < r; ++i) { - cs.Add(s[i]); - } - ans += cs.Count; - } - return ans; - } -} -``` - #### TypeScript ```ts -export function countPalindromicSubsequence(s: string): number { - const cnt = new Map(); - const n = s.length; +function countPalindromicSubsequence(s: string): number { let ans = 0; - - for (let i = 0; i < n; i++) { - const ch = s[i]; - if (cnt.has(ch)) cnt.get(ch)![1] = i; - else cnt.set(ch, [i, i]); - } - - for (const [_, [i, j]] of cnt) { - if (i !== j) { - ans += new Set(s.slice(i + 1, j)).size; + const a = 'a'.charCodeAt(0); + for (let ch = 0; ch < 26; ++ch) { + const c = String.fromCharCode(ch + a); + const l = s.indexOf(c); + const r = s.lastIndexOf(c); + let mask = 0; + for (let i = l + 1; i < r; ++i) { + const j = s.charCodeAt(i) - a; + if (((mask >> j) & 1) ^ 1) { + mask |= 1 << j; + ++ans; + } } } - return ans; } ``` @@ -195,24 +192,49 @@ export function countPalindromicSubsequence(s: string): number { #### JavaScript ```js -export function countPalindromicSubsequence(s) { - const cnt = new Map(); - const n = s.length; +/** + * @param {string} s + * @return {number} + */ +var countPalindromicSubsequence = function (s) { let ans = 0; - - for (let i = 0; i < n; i++) { - const ch = s[i]; - if (cnt.has(ch)) cnt.get(ch)[1] = i; - else cnt.set(ch, [i, i]); + const a = 'a'.charCodeAt(0); + for (let ch = 0; ch < 26; ++ch) { + const c = String.fromCharCode(ch + a); + const l = s.indexOf(c); + const r = s.lastIndexOf(c); + let mask = 0; + for (let i = l + 1; i < r; ++i) { + const j = s.charCodeAt(i) - a; + if (((mask >> j) & 1) ^ 1) { + mask |= 1 << j; + ++ans; + } + } } + return ans; +}; +``` + +#### C# - for (const [_, [i, j]] of cnt) { - if (i !== j) { - ans += new Set(s.slice(i + 1, j)).size; +```cs +public class Solution { + public int CountPalindromicSubsequence(string s) { + int ans = 0; + for (char c = 'a'; c <= 'z'; ++c) { + int l = s.IndexOf(c), r = s.LastIndexOf(c); + int mask = 0; + for (int i = l + 1; i < r; ++i) { + int j = s[i] - 'a'; + if ((mask >> j & 1) == 0) { + mask |= 1 << j; + ++ans; + } + } } + return ans; } - - return ans; } ``` diff --git a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.cpp b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.cpp index d60134c664b7a..5c932851783d0 100644 --- a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.cpp +++ b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.cpp @@ -4,10 +4,15 @@ class Solution { int ans = 0; for (char c = 'a'; c <= 'z'; ++c) { int l = s.find_first_of(c), r = s.find_last_of(c); - unordered_set cs; - for (int i = l + 1; i < r; ++i) cs.insert(s[i]); - ans += cs.size(); + int mask = 0; + for (int i = l + 1; i < r; ++i) { + int j = s[i] - 'a'; + if (mask >> j & 1 ^ 1) { + mask |= 1 << j; + ++ans; + } + } } return ans; } -}; \ No newline at end of file +}; diff --git a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.cs b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.cs index f46a2f6530684..97ad2dfeaaafd 100644 --- a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.cs +++ b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.cs @@ -3,11 +3,14 @@ public int CountPalindromicSubsequence(string s) { int ans = 0; for (char c = 'a'; c <= 'z'; ++c) { int l = s.IndexOf(c), r = s.LastIndexOf(c); - HashSet cs = new HashSet(); + int mask = 0; for (int i = l + 1; i < r; ++i) { - cs.Add(s[i]); + int j = s[i] - 'a'; + if ((mask >> j & 1) == 0) { + mask |= 1 << j; + ++ans; + } } - ans += cs.Count; } return ans; } diff --git a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.go b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.go index 6cb14bc8f6696..0cf31d92a9054 100644 --- a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.go +++ b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.go @@ -1,11 +1,14 @@ func countPalindromicSubsequence(s string) (ans int) { for c := 'a'; c <= 'z'; c++ { l, r := strings.Index(s, string(c)), strings.LastIndex(s, string(c)) - cs := map[byte]struct{}{} + mask := 0 for i := l + 1; i < r; i++ { - cs[s[i]] = struct{}{} + j := int(s[i] - 'a') + if mask>>j&1 == 0 { + mask |= 1 << j + ans++ + } } - ans += len(cs) } return -} \ No newline at end of file +} diff --git a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.java b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.java index 16348eee602ca..541de05cf23aa 100644 --- a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.java +++ b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.java @@ -3,12 +3,15 @@ public int countPalindromicSubsequence(String s) { int ans = 0; for (char c = 'a'; c <= 'z'; ++c) { int l = s.indexOf(c), r = s.lastIndexOf(c); - Set cs = new HashSet<>(); + int mask = 0; for (int i = l + 1; i < r; ++i) { - cs.add(s.charAt(i)); + int j = s.charAt(i) - 'a'; + if ((mask >> j & 1) == 0) { + mask |= 1 << j; + ++ans; + } } - ans += cs.size(); } return ans; } -} \ No newline at end of file +} diff --git a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.js b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.js index be91880d3c561..a7d6e135b02a7 100644 --- a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.js +++ b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.js @@ -1,19 +1,22 @@ -export function countPalindromicSubsequence(s) { - const cnt = new Map(); - const n = s.length; +/** + * @param {string} s + * @return {number} + */ +var countPalindromicSubsequence = function (s) { let ans = 0; - - for (let i = 0; i < n; i++) { - const ch = s[i]; - if (cnt.has(ch)) cnt.get(ch)[1] = i; - else cnt.set(ch, [i, i]); - } - - for (const [_, [i, j]] of cnt) { - if (i !== j) { - ans += new Set(s.slice(i + 1, j)).size; + const a = 'a'.charCodeAt(0); + for (let ch = 0; ch < 26; ++ch) { + const c = String.fromCharCode(ch + a); + const l = s.indexOf(c); + const r = s.lastIndexOf(c); + let mask = 0; + for (let i = l + 1; i < r; ++i) { + const j = s.charCodeAt(i) - a; + if (((mask >> j) & 1) ^ 1) { + mask |= 1 << j; + ++ans; + } } } - return ans; -} +}; diff --git a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.ts b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.ts index 2602edafef8e6..fa92d90711e18 100644 --- a/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.ts +++ b/solution/1900-1999/1930.Unique Length-3 Palindromic Subsequences/Solution.ts @@ -1,19 +1,18 @@ -export function countPalindromicSubsequence(s: string): number { - const cnt = new Map(); - const n = s.length; +function countPalindromicSubsequence(s: string): number { let ans = 0; - - for (let i = 0; i < n; i++) { - const ch = s[i]; - if (cnt.has(ch)) cnt.get(ch)![1] = i; - else cnt.set(ch, [i, i]); - } - - for (const [_, [i, j]] of cnt) { - if (i !== j) { - ans += new Set(s.slice(i + 1, j)).size; + const a = 'a'.charCodeAt(0); + for (let ch = 0; ch < 26; ++ch) { + const c = String.fromCharCode(ch + a); + const l = s.indexOf(c); + const r = s.lastIndexOf(c); + let mask = 0; + for (let i = l + 1; i < r; ++i) { + const j = s.charCodeAt(i) - a; + if (((mask >> j) & 1) ^ 1) { + mask |= 1 << j; + ++ans; + } } } - return ans; }