diff --git a/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/README.md b/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/README.md index 2f1a5fb18..913192e0e 100755 --- a/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/README.md +++ b/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/README.md @@ -1,28 +1,44 @@ # [2227.Encrypt and Decrypt Strings][title] -> [!WARNING|style:flat] -> This question is temporarily unanswered if you have good ideas. Welcome to [Create Pull Request PR](https://github.com/kylesliu/awesome-golang-algorithm) - ## Description +You are given a character array `keys` containing unique characters and a string array `values` containing strings of length 2. You are also given another string array `dictionary` that contains all permitted original strings after decryption. You should implement a data structure that can encrypt or decrypt a **0-indexed** string. -**Example 1:** +A string is **encrypted** with the following process: -``` -Input: a = "11", b = "1" -Output: "100" -``` +1. For each character `c` in the string, we find the index `i` satisfying `keys[i] == c` in `keys`. +2. Replace `c` with `values[i]` in the string. -## 题意 -> ... +Note that in case a character of the string is **not present** in `keys`, the encryption process cannot be carried out, and an empty string `""` is returned. -## 题解 +A string is **decrypted** with the following process: -### 思路1 -> ... -Encrypt and Decrypt Strings -```go -``` +1. For each substring `s` of length 2 occurring at an even index in the string, we find an `i` such that `values[i] == s`. If there are multiple valid `i`, we choose **any** one of them. This means a string could have multiple possible strings it can decrypt to. +2. Replace `s` with `keys[i]` in the string. + +Implement the `Encrypter` class: +- `Encrypter(char[] keys, String[] values, String[] dictionary)` Initializes the `Encrypter` class with `keys`, `values`, and `dictionary`. +- `String encrypt(String word1)` Encrypts `word1` with the encryption process described above and returns the encrypted string. +- `int decrypt(String word2)` Returns the number of possible strings `word2` could decrypt to that also appear in `dictionary`. + +**Example 1:** + +``` +Input +["Encrypter", "encrypt", "decrypt"] +[[['a', 'b', 'c', 'd'], ["ei", "zf", "ei", "am"], ["abcd", "acbd", "adbc", "badc", "dacb", "cadb", "cbda", "abad"]], ["abcd"], ["eizfeiam"]] +Output +[null, "eizfeiam", 2] + +Explanation +Encrypter encrypter = new Encrypter([['a', 'b', 'c', 'd'], ["ei", "zf", "ei", "am"], ["abcd", "acbd", "adbc", "badc", "dacb", "cadb", "cbda", "abad"]); +encrypter.encrypt("abcd"); // return "eizfeiam". + // 'a' maps to "ei", 'b' maps to "zf", 'c' maps to "ei", and 'd' maps to "am". +encrypter.decrypt("eizfeiam"); // return 2. + // "ei" can map to 'a' or 'c', "zf" maps to 'b', and "am" maps to 'd'. + // Thus, the possible strings after decryption are "abad", "cbad", "abcd", and "cbcd". + // 2 of those strings, "abad" and "abcd", appear in dictionary, so the answer is 2. +``` ## 结语 diff --git a/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/Solution.go b/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/Solution.go index d115ccf5e..fdfda5e97 100644 --- a/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/Solution.go +++ b/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/Solution.go @@ -1,5 +1,102 @@ package Solution -func Solution(x bool) bool { - return x +import ( + "strings" +) + +type trieNode2227 struct { + child [26]*trieNode2227 + end bool +} + +func buildTrieNode2227(dic []string) *trieNode2227 { + root := &trieNode2227{ + child: [26]*trieNode2227{}, + } + for _, word := range dic { + walker := root + for _, b := range []byte(word) { + index := b - 'a' + if walker.child[index] == nil { + walker.child[index] = &trieNode2227{} + } + walker = walker.child[index] + } + walker.end = true + } + return root +} + +type Encrypter struct { + tree *trieNode2227 + keys []byte + keysMap map[byte]int + values []string + valuesMapper map[string][]int +} + +func Constructor(keys []byte, values []string, dictionary []string) Encrypter { + tree := buildTrieNode2227(dictionary) + e := Encrypter{ + tree: tree, + keys: keys, + keysMap: make(map[byte]int), + values: values, + valuesMapper: map[string][]int{}, + } + for i, b := range keys { + e.keysMap[b] = i + } + for i, str := range values { + if _, ok := e.valuesMapper[str]; !ok { + e.valuesMapper[str] = []int{} + } + e.valuesMapper[str] = append(e.valuesMapper[str], i) + } + + return e +} + +func (this *Encrypter) Encrypt(word1 string) string { + buf := strings.Builder{} + for _, b := range []byte(word1) { + index, ok := this.keysMap[b] + if !ok { + return "" + } + + buf.WriteString(this.values[index]) + } + return buf.String() +} + +func (this *Encrypter) search(word2 string, index int, tree *trieNode2227) int { + if index >= len(word2) { + if tree.end { + return 1 + } + return 0 + } + // ab -> c, c + cur := word2[index : index+2] + var ret int + for _, i := range this.valuesMapper[cur] { + childIndex := this.keys[i] - 'a' + if tree.child[childIndex] == nil { + continue + } + ret += this.search(word2, index+2, tree.child[childIndex]) + } + return ret +} +func (this *Encrypter) Decrypt(word2 string) int { + return this.search(word2, 0, this.tree) +} + +func Solution(keys []byte, values []string, dictionary []string, encryptStr, decryptStr string) []any { + c := Constructor(keys, values, dictionary) + var ret []any + ret = append(ret, c.Encrypt(encryptStr)) + ret = append(ret, c.Decrypt(decryptStr)) + return ret } diff --git a/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/Solution_test.go b/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/Solution_test.go index 14ff50eb4..25a0f1573 100644 --- a/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/Solution_test.go +++ b/leetcode/2201-2300/2227.Encrypt-and-Decrypt-Strings/Solution_test.go @@ -9,31 +9,31 @@ import ( func TestSolution(t *testing.T) { // 测试用例 cases := []struct { - name string - inputs bool - expect bool + name string + keys []byte + values, dictionary []string + word1, word2 string + expect []any }{ - {"TestCase", true, true}, - {"TestCase", true, true}, - {"TestCase", false, false}, + {"TestCase1", []byte{'a', 'b', 'c', 'd'}, []string{"ei", "zf", "ei", "am"}, []string{"abcd", "acbd", "adbc", "badc", "dacb", "cadb", "cbda", "abad"}, "abcd", "eizfeiam", []any{"eizfeiam", 2}}, } // 开始测试 for i, c := range cases { t.Run(c.name+" "+strconv.Itoa(i), func(t *testing.T) { - got := Solution(c.inputs) + got := Solution(c.keys, c.values, c.dictionary, c.word1, c.word2) if !reflect.DeepEqual(got, c.expect) { - t.Fatalf("expected: %v, but got: %v, with inputs: %v", - c.expect, got, c.inputs) + t.Fatalf("expected: %v, but got: %v, with inputs: %v %v %v %v %v", + c.expect, got, c.keys, c.values, c.dictionary, c.word1, c.word2) } }) } } -// 压力测试 +// 压力测试 func BenchmarkSolution(b *testing.B) { } -// 使用案列 +// 使用案列 func ExampleSolution() { }