diff --git a/solution/1700-1799/1706.Where Will the Ball Fall/README.md b/solution/1700-1799/1706.Where Will the Ball Fall/README.md index e95268c811286..ed8bb7bf9d0e6 100644 --- a/solution/1700-1799/1706.Where Will the Ball Fall/README.md +++ b/solution/1700-1799/1706.Where Will the Ball Fall/README.md @@ -66,14 +66,18 @@ b4 球开始放在第 4 列上,会卡在第 2、3 列和第 1 行之间的 "V" -球被卡住共有 4 种情况: +**方法一:分情况讨论 + DFS** + +我们可以使用 DFS 来模拟球的运动过程,设计一个函数 $dfs(i, j)$,表示球从第 $i$ 行第 $j$ 列出发,最终会落在第几列。对于以下情况,球会卡住: 1. 球位于最左一列,并且球所在的单元格单元格挡板将球导向左侧 1. 球位于最右一列,并且此单元格挡板将球导向右侧 1. 球所在的单元格挡板将球导向右侧,并且球右侧相邻单元格挡板将球导向左侧 1. 球所在的单元格挡板将球导向左侧,并且球左侧相邻单元格挡板将球导向右侧 -DFS 搜索即可。 +如果满足以上任意一种情况,我们就可以判断球会卡住,返回 $-1$。否则,我们就可以继续递归地寻找球的下一个位置。最后,如果球到了最后一行,我们就可以返回当前列的编号。 + +时间复杂度 $O(m \times n)$,空间复杂度 $O(m)$。其中 $m$ 和 $n$ 分别是数组 $grid$ 的行数和列数。 @@ -84,10 +88,7 @@ DFS 搜索即可。 ```python class Solution: def findBall(self, grid: List[List[int]]) -> List[int]: - m, n = len(grid), len(grid[0]) - - def dfs(i, j): - nonlocal m, n + def dfs(i: int, j: int) -> int: if i == m: return j if j == 0 and grid[i][j] == -1: @@ -100,6 +101,7 @@ class Solution: return -1 return dfs(i + 1, j + 1) if grid[i][j] == 1 else dfs(i + 1, j - 1) + m, n = len(grid), len(grid[0]) return [dfs(0, j) for j in range(n)] ``` @@ -150,35 +152,40 @@ class Solution { ```cpp class Solution { public: - int m, n; - vector> grid; - vector findBall(vector>& grid) { - this->grid = grid; - m = grid.size(); - n = grid[0].size(); + int m = grid.size(), n = grid[0].size(); vector ans(n); - for (int j = 0; j < n; ++j) ans[j] = dfs(0, j); + function dfs = [&](int i, int j) { + if (i == m) { + return j; + } + if (j == 0 && grid[i][j] == -1) { + return -1; + } + if (j == n - 1 && grid[i][j] == 1) { + return -1; + } + if (grid[i][j] == 1 && grid[i][j + 1] == -1) { + return -1; + } + if (grid[i][j] == -1 && grid[i][j - 1] == 1) { + return -1; + } + return grid[i][j] == 1 ? dfs(i + 1, j + 1) : dfs(i + 1, j - 1); + }; + for (int j = 0; j < n; ++j) { + ans[j] = dfs(0, j); + } return ans; } - - int dfs(int i, int j) { - if (i == m) return j; - if (j == 0 && grid[i][j] == -1) return -1; - if (j == n - 1 && grid[i][j] == 1) return -1; - if (grid[i][j] == 1 && grid[i][j + 1] == -1) return -1; - if (grid[i][j] == -1 && grid[i][j - 1] == 1) return -1; - return grid[i][j] == 1 ? dfs(i + 1, j + 1) : dfs(i + 1, j - 1); - } }; ``` ### **Go** ```go -func findBall(grid [][]int) []int { +func findBall(grid [][]int) (ans []int) { m, n := len(grid), len(grid[0]) - var dfs func(i, j int) int dfs = func(i, j int) int { if i == m { @@ -201,12 +208,10 @@ func findBall(grid [][]int) []int { } return dfs(i+1, j-1) } - - var ans []int for j := 0; j < n; j++ { ans = append(ans, dfs(0, j)) } - return ans + return } ``` @@ -216,7 +221,6 @@ func findBall(grid [][]int) []int { function findBall(grid: number[][]): number[] { const m = grid.length; const n = grid[0].length; - const res = new Array(n).fill(0); const dfs = (i: number, j: number) => { if (i === m) { return j; @@ -233,10 +237,11 @@ function findBall(grid: number[][]): number[] { return dfs(i + 1, j - 1); } }; - for (let i = 0; i < n; i++) { - res[i] = dfs(0, i); + const ans: number[] = []; + for (let j = 0; j < n; ++j) { + ans.push(dfs(0, j)); } - return res; + return ans; } ``` diff --git a/solution/1700-1799/1706.Where Will the Ball Fall/README_EN.md b/solution/1700-1799/1706.Where Will the Ball Fall/README_EN.md index 8c43903db9d09..86589eaac2fa7 100644 --- a/solution/1700-1799/1706.Where Will the Ball Fall/README_EN.md +++ b/solution/1700-1799/1706.Where Will the Ball Fall/README_EN.md @@ -60,6 +60,19 @@ Ball b4 is dropped at column 4 and will get stuck on the box between column 2 an ## Solutions +**Solution 1: Case Discussion + DFS** + +We can use DFS to simulate the movement of the ball. We design a function $dfs(i, j)$, which represents that the ball starts from the $i$th row and the $j$th column, and finally falls in which column. The ball will get stuck in the following situations: + +1. The ball is in the leftmost column, and the cell's vane directs the ball to the left. +2. The ball is in the rightmost column, and the cell's vane directs the ball to the right. +3. The cell's vane where the ball is located directs the ball to the right, and the vane of the cell adjacent to the right of the ball directs the ball to the left. +4. The cell's vane where the ball is located directs the ball to the left, and the vane of the cell adjacent to the left of the ball directs the ball to the right. + +If any of the above situations are met, we can judge that the ball will get stuck and return $-1$. Otherwise, we can continue to recursively find the next position of the ball. Finally, if the ball reaches the last row, we can return the current column number. + +The time complexity is $O(m \times n)$, and the space complexity is $O(m)$. Where $m$ and $n$ are the number of rows and columns of the array $grid$, respectively. + ### **Python3** @@ -67,10 +80,7 @@ Ball b4 is dropped at column 4 and will get stuck on the box between column 2 an ```python class Solution: def findBall(self, grid: List[List[int]]) -> List[int]: - m, n = len(grid), len(grid[0]) - - def dfs(i, j): - nonlocal m, n + def dfs(i: int, j: int) -> int: if i == m: return j if j == 0 and grid[i][j] == -1: @@ -83,6 +93,7 @@ class Solution: return -1 return dfs(i + 1, j + 1) if grid[i][j] == 1 else dfs(i + 1, j - 1) + m, n = len(grid), len(grid[0]) return [dfs(0, j) for j in range(n)] ``` @@ -131,35 +142,40 @@ class Solution { ```cpp class Solution { public: - int m, n; - vector> grid; - vector findBall(vector>& grid) { - this->grid = grid; - m = grid.size(); - n = grid[0].size(); + int m = grid.size(), n = grid[0].size(); vector ans(n); - for (int j = 0; j < n; ++j) ans[j] = dfs(0, j); + function dfs = [&](int i, int j) { + if (i == m) { + return j; + } + if (j == 0 && grid[i][j] == -1) { + return -1; + } + if (j == n - 1 && grid[i][j] == 1) { + return -1; + } + if (grid[i][j] == 1 && grid[i][j + 1] == -1) { + return -1; + } + if (grid[i][j] == -1 && grid[i][j - 1] == 1) { + return -1; + } + return grid[i][j] == 1 ? dfs(i + 1, j + 1) : dfs(i + 1, j - 1); + }; + for (int j = 0; j < n; ++j) { + ans[j] = dfs(0, j); + } return ans; } - - int dfs(int i, int j) { - if (i == m) return j; - if (j == 0 && grid[i][j] == -1) return -1; - if (j == n - 1 && grid[i][j] == 1) return -1; - if (grid[i][j] == 1 && grid[i][j + 1] == -1) return -1; - if (grid[i][j] == -1 && grid[i][j - 1] == 1) return -1; - return grid[i][j] == 1 ? dfs(i + 1, j + 1) : dfs(i + 1, j - 1); - } }; ``` ### **Go** ```go -func findBall(grid [][]int) []int { +func findBall(grid [][]int) (ans []int) { m, n := len(grid), len(grid[0]) - var dfs func(i, j int) int dfs = func(i, j int) int { if i == m { @@ -182,12 +198,10 @@ func findBall(grid [][]int) []int { } return dfs(i+1, j-1) } - - var ans []int for j := 0; j < n; j++ { ans = append(ans, dfs(0, j)) } - return ans + return } ``` @@ -197,7 +211,6 @@ func findBall(grid [][]int) []int { function findBall(grid: number[][]): number[] { const m = grid.length; const n = grid[0].length; - const res = new Array(n).fill(0); const dfs = (i: number, j: number) => { if (i === m) { return j; @@ -214,10 +227,11 @@ function findBall(grid: number[][]): number[] { return dfs(i + 1, j - 1); } }; - for (let i = 0; i < n; i++) { - res[i] = dfs(0, i); + const ans: number[] = []; + for (let j = 0; j < n; ++j) { + ans.push(dfs(0, j)); } - return res; + return ans; } ``` diff --git a/solution/1700-1799/1706.Where Will the Ball Fall/Solution.cpp b/solution/1700-1799/1706.Where Will the Ball Fall/Solution.cpp index 8eb576c1e2940..b633b3b3b1208 100644 --- a/solution/1700-1799/1706.Where Will the Ball Fall/Solution.cpp +++ b/solution/1700-1799/1706.Where Will the Ball Fall/Solution.cpp @@ -1,23 +1,29 @@ -class Solution { -public: - int m, n; - vector> grid; - - vector findBall(vector>& grid) { - this->grid = grid; - m = grid.size(); - n = grid[0].size(); - vector ans(n); - for (int j = 0; j < n; ++j) ans[j] = dfs(0, j); - return ans; - } - - int dfs(int i, int j) { - if (i == m) return j; - if (j == 0 && grid[i][j] == -1) return -1; - if (j == n - 1 && grid[i][j] == 1) return -1; - if (grid[i][j] == 1 && grid[i][j + 1] == -1) return -1; - if (grid[i][j] == -1 && grid[i][j - 1] == 1) return -1; - return grid[i][j] == 1 ? dfs(i + 1, j + 1) : dfs(i + 1, j - 1); - } +class Solution { +public: + vector findBall(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + vector ans(n); + function dfs = [&](int i, int j) { + if (i == m) { + return j; + } + if (j == 0 && grid[i][j] == -1) { + return -1; + } + if (j == n - 1 && grid[i][j] == 1) { + return -1; + } + if (grid[i][j] == 1 && grid[i][j + 1] == -1) { + return -1; + } + if (grid[i][j] == -1 && grid[i][j - 1] == 1) { + return -1; + } + return grid[i][j] == 1 ? dfs(i + 1, j + 1) : dfs(i + 1, j - 1); + }; + for (int j = 0; j < n; ++j) { + ans[j] = dfs(0, j); + } + return ans; + } }; \ No newline at end of file diff --git a/solution/1700-1799/1706.Where Will the Ball Fall/Solution.go b/solution/1700-1799/1706.Where Will the Ball Fall/Solution.go index bf0059c2d9412..9c5934592abb1 100644 --- a/solution/1700-1799/1706.Where Will the Ball Fall/Solution.go +++ b/solution/1700-1799/1706.Where Will the Ball Fall/Solution.go @@ -1,6 +1,5 @@ -func findBall(grid [][]int) []int { +func findBall(grid [][]int) (ans []int) { m, n := len(grid), len(grid[0]) - var dfs func(i, j int) int dfs = func(i, j int) int { if i == m { @@ -23,10 +22,8 @@ func findBall(grid [][]int) []int { } return dfs(i+1, j-1) } - - var ans []int for j := 0; j < n; j++ { ans = append(ans, dfs(0, j)) } - return ans + return } \ No newline at end of file diff --git a/solution/1700-1799/1706.Where Will the Ball Fall/Solution.py b/solution/1700-1799/1706.Where Will the Ball Fall/Solution.py index 11aa186f97d27..e4ec502d1364e 100644 --- a/solution/1700-1799/1706.Where Will the Ball Fall/Solution.py +++ b/solution/1700-1799/1706.Where Will the Ball Fall/Solution.py @@ -1,19 +1,17 @@ -class Solution: - def findBall(self, grid: List[List[int]]) -> List[int]: - m, n = len(grid), len(grid[0]) - - def dfs(i, j): - nonlocal m, n - if i == m: - return j - if j == 0 and grid[i][j] == -1: - return -1 - if j == n - 1 and grid[i][j] == 1: - return -1 - if grid[i][j] == 1 and grid[i][j + 1] == -1: - return -1 - if grid[i][j] == -1 and grid[i][j - 1] == 1: - return -1 - return dfs(i + 1, j + 1) if grid[i][j] == 1 else dfs(i + 1, j - 1) - - return [dfs(0, j) for j in range(n)] +class Solution: + def findBall(self, grid: List[List[int]]) -> List[int]: + def dfs(i: int, j: int) -> int: + if i == m: + return j + if j == 0 and grid[i][j] == -1: + return -1 + if j == n - 1 and grid[i][j] == 1: + return -1 + if grid[i][j] == 1 and grid[i][j + 1] == -1: + return -1 + if grid[i][j] == -1 and grid[i][j - 1] == 1: + return -1 + return dfs(i + 1, j + 1) if grid[i][j] == 1 else dfs(i + 1, j - 1) + + m, n = len(grid), len(grid[0]) + return [dfs(0, j) for j in range(n)] diff --git a/solution/1700-1799/1706.Where Will the Ball Fall/Solution.ts b/solution/1700-1799/1706.Where Will the Ball Fall/Solution.ts index c6d0f694b0114..d8a275b8dbfbb 100644 --- a/solution/1700-1799/1706.Where Will the Ball Fall/Solution.ts +++ b/solution/1700-1799/1706.Where Will the Ball Fall/Solution.ts @@ -1,7 +1,6 @@ function findBall(grid: number[][]): number[] { const m = grid.length; const n = grid[0].length; - const res = new Array(n).fill(0); const dfs = (i: number, j: number) => { if (i === m) { return j; @@ -18,8 +17,9 @@ function findBall(grid: number[][]): number[] { return dfs(i + 1, j - 1); } }; - for (let i = 0; i < n; i++) { - res[i] = dfs(0, i); + const ans: number[] = []; + for (let j = 0; j < n; ++j) { + ans.push(dfs(0, j)); } - return res; + return ans; } diff --git a/solution/1700-1799/1707.Maximum XOR With an Element From Array/README.md b/solution/1700-1799/1707.Maximum XOR With an Element From Array/README.md index 1c40c8a34cc99..48ffaddd71e47 100644 --- a/solution/1700-1799/1707.Maximum XOR With an Element From Array/README.md +++ b/solution/1700-1799/1707.Maximum XOR With an Element From Array/README.md @@ -44,7 +44,13 @@ -**方法一:前缀树** +**方法一:离线查询 + 0-1 字典树** + +根据题目描述我们知道,每个查询相互独立,并且查询的结果与 $nums$ 中的元素顺序无关,因此,我们考虑将所有的查询按照 $m_i$ 从小到大排序,并且将 $nums$ 从小到大排序。 + +接下来,我们使用一个 $0-1$ 字典树来维护 $nums$ 中的元素。我们用一个指针 $j$ 来记录当前字典树中的元素,初始时 $j=0$。对于每个查询 $[x_i, m_i]$,我们不断地将 $nums$ 中的元素插入到字典树中,直到 $nums[j] > m_i$,此时我们就可以在字典树中查询到所有不超过 $m_i$ 的元素,我们将其中与 $x_i$ 异或值最大的元素的异或值作为答案。 + +时间复杂度 $O(m \times \log m + n \times (\log n + \log M))$,空间复杂度 $O(n \times \log M)$,其中 $m$ 和 $n$ 分别是数组 $nums$ 和 $queries$ 的长度,而 $M$ 是数组 $nums$ 中的最大值,本题中 $M \le 10^9$。 @@ -54,22 +60,24 @@ ```python class Trie: + __slots__ = ["children"] + def __init__(self): self.children = [None] * 2 - def insert(self, x): + def insert(self, x: int): node = self for i in range(30, -1, -1): - v = (x >> i) & 1 + v = x >> i & 1 if node.children[v] is None: node.children[v] = Trie() node = node.children[v] - def search(self, x): + def search(self, x: int) -> int: node = self ans = 0 for i in range(30, -1, -1): - v = (x >> i) & 1 + v = x >> i & 1 if node.children[v ^ 1]: ans |= 1 << i node = node.children[v ^ 1] @@ -99,36 +107,13 @@ class Solution: ```java -class Solution { - public int[] maximizeXor(int[] nums, int[][] queries) { - Trie trie = new Trie(); - Arrays.sort(nums); - int n = queries.length; - int[] ans = new int[n]; - int[][] qs = new int[n][3]; - for (int i = 0; i < n; ++i) { - qs[i] = new int[] {i, queries[i][0], queries[i][1]}; - } - Arrays.sort(qs, (a, b) -> a[2] - b[2]); - int j = 0; - for (var q : qs) { - int i = q[0], x = q[1], m = q[2]; - while (j < nums.length && nums[j] <= m) { - trie.insert(nums[j++]); - } - ans[i] = trie.search(x); - } - return ans; - } -} - class Trie { - Trie[] children = new Trie[2]; + private Trie[] children = new Trie[2]; public void insert(int x) { Trie node = this; for (int i = 30; i >= 0; --i) { - int v = (x >> i) & 1; + int v = x >> i & 1; if (node.children[v] == null) { node.children[v] = new Trie(); } @@ -140,7 +125,7 @@ class Trie { Trie node = this; int ans = 0; for (int i = 30; i >= 0; --i) { - int v = (x >> i) & 1; + int v = x >> i & 1; if (node.children[v ^ 1] != null) { ans |= 1 << i; node = node.children[v ^ 1]; @@ -153,15 +138,42 @@ class Trie { return ans; } } + +class Solution { + public int[] maximizeXor(int[] nums, int[][] queries) { + Arrays.sort(nums); + int n = queries.length; + Integer[] idx = new Integer[n]; + for (int i = 0; i < n; ++i) { + idx[i] = i; + } + Arrays.sort(idx, (i, j) -> queries[i][1] - queries[j][1]); + int[] ans = new int[n]; + Trie trie = new Trie(); + int j = 0; + for (int i : idx) { + int x = queries[i][0], m = queries[i][1]; + while (j < nums.length && nums[j] <= m) { + trie.insert(nums[j++]); + } + ans[i] = trie.search(x); + } + return ans; + } +} ``` ### **C++** ```cpp class Trie { +private: + Trie* children[2]; + public: Trie() - : children(2) {} + : children{nullptr, nullptr} {} + void insert(int x) { Trie* node = this; for (int i = 30; ~i; --i) { @@ -174,13 +186,13 @@ public: } int search(int x) { - int ans = 0; Trie* node = this; + int ans = 0; for (int i = 30; ~i; --i) { int v = (x >> i) & 1; if (node->children[v ^ 1]) { - node = node->children[v ^ 1]; ans |= 1 << i; + node = node->children[v ^ 1]; } else if (node->children[v]) { node = node->children[v]; } else { @@ -189,9 +201,6 @@ public: } return ans; } - -private: - vector children; }; class Solution { @@ -199,19 +208,18 @@ public: vector maximizeXor(vector& nums, vector>& queries) { sort(nums.begin(), nums.end()); int n = queries.size(); - vector> qs; - for (int i = 0; i < n; ++i) { - qs.push_back({queries[i][1], queries[i][0], i}); - } - sort(qs.begin(), qs.end()); - Trie* trie = new Trie(); - int j = 0; + vector idx(n); + iota(idx.begin(), idx.end(), 0); + sort(idx.begin(), idx.end(), [&](int i, int j) { return queries[i][1] < queries[j][1]; }); vector ans(n); - for (auto& [m, x, i] : qs) { + Trie trie; + int j = 0; + for (int i : idx) { + int x = queries[i][0], m = queries[i][1]; while (j < nums.size() && nums[j] <= m) { - trie->insert(nums[j++]); + trie.insert(nums[j++]); } - ans[i] = trie->search(x); + ans[i] = trie.search(x); } return ans; } @@ -225,28 +233,29 @@ type Trie struct { children [2]*Trie } -func newTrie() *Trie { +func NewTrie() *Trie { return &Trie{} } -func (this *Trie) insert(x int) { - node := this + +func (t *Trie) insert(x int) { + node := t for i := 30; i >= 0; i-- { - v := (x >> i) & 1 + v := x >> i & 1 if node.children[v] == nil { - node.children[v] = newTrie() + node.children[v] = NewTrie() } node = node.children[v] } } -func (this *Trie) search(x int) int { - node := this +func (t *Trie) search(x int) int { + node := t ans := 0 for i := 30; i >= 0; i-- { - v := (x >> i) & 1 + v := x >> i & 1 if node.children[v^1] != nil { - node = node.children[v^1] ans |= 1 << i + node = node.children[v^1] } else if node.children[v] != nil { node = node.children[v] } else { @@ -258,18 +267,19 @@ func (this *Trie) search(x int) int { func maximizeXor(nums []int, queries [][]int) []int { sort.Ints(nums) - type tuple struct{ i, x, m int } n := len(queries) - qs := make([]tuple, n) - for i, q := range queries { - qs[i] = tuple{i, q[0], q[1]} + idx := make([]int, n) + for i := 0; i < n; i++ { + idx[i] = i } - sort.Slice(qs, func(i, j int) bool { return qs[i].m < qs[j].m }) - j := 0 + sort.Slice(idx, func(i, j int) bool { + return queries[idx[i]][1] < queries[idx[j]][1] + }) ans := make([]int, n) - trie := newTrie() - for _, q := range qs { - i, x, m := q.i, q.x, q.m + trie := NewTrie() + j := 0 + for _, i := range idx { + x, m := queries[i][0], queries[i][1] for j < len(nums) && nums[j] <= m { trie.insert(nums[j]) j++ @@ -280,6 +290,65 @@ func maximizeXor(nums []int, queries [][]int) []int { } ``` +### **TypeScript** + +```ts +class Trie { + children: (Trie | null)[]; + + constructor() { + this.children = [null, null]; + } + + insert(x: number): void { + let node: Trie | null = this; + for (let i = 30; ~i; i--) { + const v = (x >> i) & 1; + if (node.children[v] === null) { + node.children[v] = new Trie(); + } + node = node.children[v] as Trie; + } + } + + search(x: number): number { + let node: Trie | null = this; + let ans = 0; + for (let i = 30; ~i; i--) { + const v = (x >> i) & 1; + if (node.children[v ^ 1] !== null) { + ans |= 1 << i; + node = node.children[v ^ 1] as Trie; + } else if (node.children[v] !== null) { + node = node.children[v] as Trie; + } else { + return -1; + } + } + return ans; + } +} + +function maximizeXor(nums: number[], queries: number[][]): number[] { + nums.sort((a, b) => a - b); + const n = queries.length; + const idx = Array.from({ length: n }, (_, i) => i); + idx.sort((i, j) => queries[i][1] - queries[j][1]); + const ans: number[] = []; + const trie = new Trie(); + let j = 0; + for (const i of idx) { + const x = queries[i][0]; + const m = queries[i][1]; + while (j < nums.length && nums[j] <= m) { + trie.insert(nums[j++]); + } + ans[i] = trie.search(x); + } + return ans; +} +``` + ### **...** ``` diff --git a/solution/1700-1799/1707.Maximum XOR With an Element From Array/README_EN.md b/solution/1700-1799/1707.Maximum XOR With an Element From Array/README_EN.md index f6ba7b42b9703..f16a6fabd45a1 100644 --- a/solution/1700-1799/1707.Maximum XOR With an Element From Array/README_EN.md +++ b/solution/1700-1799/1707.Maximum XOR With an Element From Array/README_EN.md @@ -40,28 +40,38 @@ ## Solutions +**Solution 1: Offline Query + Binary Trie** + +From the problem description, we know that each query is independent and the result of the query is irrelevant to the order of elements in $nums$. Therefore, we consider sorting all queries in ascending order of $m_i$, and also sorting $nums$ in ascending order. + +Next, we use a binary trie to maintain the elements in $nums$. We use a pointer $j$ to record the current elements in the trie, initially $j=0$. For each query $[x_i, m_i]$, we continuously insert elements from $nums$ into the trie until $nums[j] > m_i$. At this point, we can query all elements not exceeding $m_i$ in the trie, and we take the XOR value of the element with the maximum XOR value with $x_i$ as the answer. + +The time complexity is $O(m \times \log m + n \times (\log n + \log M))$, and the space complexity is $O(n \times \log M)$. Where $m$ and $n$ are the lengths of the arrays $nums$ and $queries$ respectively, and $M$ is the maximum value in the array $nums$. In this problem, $M \le 10^9$. + ### **Python3** ```python class Trie: + __slots__ = ["children"] + def __init__(self): self.children = [None] * 2 - def insert(self, x): + def insert(self, x: int): node = self for i in range(30, -1, -1): - v = (x >> i) & 1 + v = x >> i & 1 if node.children[v] is None: node.children[v] = Trie() node = node.children[v] - def search(self, x): + def search(self, x: int) -> int: node = self ans = 0 for i in range(30, -1, -1): - v = (x >> i) & 1 + v = x >> i & 1 if node.children[v ^ 1]: ans |= 1 << i node = node.children[v ^ 1] @@ -89,36 +99,13 @@ class Solution: ### **Java** ```java -class Solution { - public int[] maximizeXor(int[] nums, int[][] queries) { - Trie trie = new Trie(); - Arrays.sort(nums); - int n = queries.length; - int[] ans = new int[n]; - int[][] qs = new int[n][3]; - for (int i = 0; i < n; ++i) { - qs[i] = new int[] {i, queries[i][0], queries[i][1]}; - } - Arrays.sort(qs, (a, b) -> a[2] - b[2]); - int j = 0; - for (var q : qs) { - int i = q[0], x = q[1], m = q[2]; - while (j < nums.length && nums[j] <= m) { - trie.insert(nums[j++]); - } - ans[i] = trie.search(x); - } - return ans; - } -} - class Trie { - Trie[] children = new Trie[2]; + private Trie[] children = new Trie[2]; public void insert(int x) { Trie node = this; for (int i = 30; i >= 0; --i) { - int v = (x >> i) & 1; + int v = x >> i & 1; if (node.children[v] == null) { node.children[v] = new Trie(); } @@ -130,7 +117,7 @@ class Trie { Trie node = this; int ans = 0; for (int i = 30; i >= 0; --i) { - int v = (x >> i) & 1; + int v = x >> i & 1; if (node.children[v ^ 1] != null) { ans |= 1 << i; node = node.children[v ^ 1]; @@ -143,15 +130,42 @@ class Trie { return ans; } } + +class Solution { + public int[] maximizeXor(int[] nums, int[][] queries) { + Arrays.sort(nums); + int n = queries.length; + Integer[] idx = new Integer[n]; + for (int i = 0; i < n; ++i) { + idx[i] = i; + } + Arrays.sort(idx, (i, j) -> queries[i][1] - queries[j][1]); + int[] ans = new int[n]; + Trie trie = new Trie(); + int j = 0; + for (int i : idx) { + int x = queries[i][0], m = queries[i][1]; + while (j < nums.length && nums[j] <= m) { + trie.insert(nums[j++]); + } + ans[i] = trie.search(x); + } + return ans; + } +} ``` ### **C++** ```cpp class Trie { +private: + Trie* children[2]; + public: Trie() - : children(2) {} + : children{nullptr, nullptr} {} + void insert(int x) { Trie* node = this; for (int i = 30; ~i; --i) { @@ -164,13 +178,13 @@ public: } int search(int x) { - int ans = 0; Trie* node = this; + int ans = 0; for (int i = 30; ~i; --i) { int v = (x >> i) & 1; if (node->children[v ^ 1]) { - node = node->children[v ^ 1]; ans |= 1 << i; + node = node->children[v ^ 1]; } else if (node->children[v]) { node = node->children[v]; } else { @@ -179,9 +193,6 @@ public: } return ans; } - -private: - vector children; }; class Solution { @@ -189,19 +200,18 @@ public: vector maximizeXor(vector& nums, vector>& queries) { sort(nums.begin(), nums.end()); int n = queries.size(); - vector> qs; - for (int i = 0; i < n; ++i) { - qs.push_back({queries[i][1], queries[i][0], i}); - } - sort(qs.begin(), qs.end()); - Trie* trie = new Trie(); - int j = 0; + vector idx(n); + iota(idx.begin(), idx.end(), 0); + sort(idx.begin(), idx.end(), [&](int i, int j) { return queries[i][1] < queries[j][1]; }); vector ans(n); - for (auto& [m, x, i] : qs) { + Trie trie; + int j = 0; + for (int i : idx) { + int x = queries[i][0], m = queries[i][1]; while (j < nums.size() && nums[j] <= m) { - trie->insert(nums[j++]); + trie.insert(nums[j++]); } - ans[i] = trie->search(x); + ans[i] = trie.search(x); } return ans; } @@ -215,28 +225,29 @@ type Trie struct { children [2]*Trie } -func newTrie() *Trie { +func NewTrie() *Trie { return &Trie{} } -func (this *Trie) insert(x int) { - node := this + +func (t *Trie) insert(x int) { + node := t for i := 30; i >= 0; i-- { - v := (x >> i) & 1 + v := x >> i & 1 if node.children[v] == nil { - node.children[v] = newTrie() + node.children[v] = NewTrie() } node = node.children[v] } } -func (this *Trie) search(x int) int { - node := this +func (t *Trie) search(x int) int { + node := t ans := 0 for i := 30; i >= 0; i-- { - v := (x >> i) & 1 + v := x >> i & 1 if node.children[v^1] != nil { - node = node.children[v^1] ans |= 1 << i + node = node.children[v^1] } else if node.children[v] != nil { node = node.children[v] } else { @@ -248,18 +259,19 @@ func (this *Trie) search(x int) int { func maximizeXor(nums []int, queries [][]int) []int { sort.Ints(nums) - type tuple struct{ i, x, m int } n := len(queries) - qs := make([]tuple, n) - for i, q := range queries { - qs[i] = tuple{i, q[0], q[1]} + idx := make([]int, n) + for i := 0; i < n; i++ { + idx[i] = i } - sort.Slice(qs, func(i, j int) bool { return qs[i].m < qs[j].m }) - j := 0 + sort.Slice(idx, func(i, j int) bool { + return queries[idx[i]][1] < queries[idx[j]][1] + }) ans := make([]int, n) - trie := newTrie() - for _, q := range qs { - i, x, m := q.i, q.x, q.m + trie := NewTrie() + j := 0 + for _, i := range idx { + x, m := queries[i][0], queries[i][1] for j < len(nums) && nums[j] <= m { trie.insert(nums[j]) j++ @@ -270,6 +282,65 @@ func maximizeXor(nums []int, queries [][]int) []int { } ``` +### **TypeScript** + +```ts +class Trie { + children: (Trie | null)[]; + + constructor() { + this.children = [null, null]; + } + + insert(x: number): void { + let node: Trie | null = this; + for (let i = 30; ~i; i--) { + const v = (x >> i) & 1; + if (node.children[v] === null) { + node.children[v] = new Trie(); + } + node = node.children[v] as Trie; + } + } + + search(x: number): number { + let node: Trie | null = this; + let ans = 0; + for (let i = 30; ~i; i--) { + const v = (x >> i) & 1; + if (node.children[v ^ 1] !== null) { + ans |= 1 << i; + node = node.children[v ^ 1] as Trie; + } else if (node.children[v] !== null) { + node = node.children[v] as Trie; + } else { + return -1; + } + } + return ans; + } +} + +function maximizeXor(nums: number[], queries: number[][]): number[] { + nums.sort((a, b) => a - b); + const n = queries.length; + const idx = Array.from({ length: n }, (_, i) => i); + idx.sort((i, j) => queries[i][1] - queries[j][1]); + const ans: number[] = []; + const trie = new Trie(); + let j = 0; + for (const i of idx) { + const x = queries[i][0]; + const m = queries[i][1]; + while (j < nums.length && nums[j] <= m) { + trie.insert(nums[j++]); + } + ans[i] = trie.search(x); + } + return ans; +} +``` + ### **...** ``` diff --git a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.cpp b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.cpp index ca26d547ef311..b6402041d1aec 100644 --- a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.cpp +++ b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.cpp @@ -1,58 +1,58 @@ -class Trie { -public: - Trie() - : children(2) {} - void insert(int x) { - Trie* node = this; - for (int i = 30; ~i; --i) { - int v = (x >> i) & 1; - if (!node->children[v]) { - node->children[v] = new Trie(); - } - node = node->children[v]; - } - } - - int search(int x) { - int ans = 0; - Trie* node = this; - for (int i = 30; ~i; --i) { - int v = (x >> i) & 1; - if (node->children[v ^ 1]) { - node = node->children[v ^ 1]; - ans |= 1 << i; - } else if (node->children[v]) { - node = node->children[v]; - } else { - return -1; - } - } - return ans; - } - -private: - vector children; -}; - -class Solution { -public: - vector maximizeXor(vector& nums, vector>& queries) { - sort(nums.begin(), nums.end()); - int n = queries.size(); - vector> qs; - for (int i = 0; i < n; ++i) { - qs.push_back({queries[i][1], queries[i][0], i}); - } - sort(qs.begin(), qs.end()); - Trie* trie = new Trie(); - int j = 0; - vector ans(n); - for (auto& [m, x, i] : qs) { - while (j < nums.size() && nums[j] <= m) { - trie->insert(nums[j++]); - } - ans[i] = trie->search(x); - } - return ans; - } +class Trie { +private: + Trie* children[2]; + +public: + Trie() + : children{nullptr, nullptr} {} + + void insert(int x) { + Trie* node = this; + for (int i = 30; ~i; --i) { + int v = (x >> i) & 1; + if (!node->children[v]) { + node->children[v] = new Trie(); + } + node = node->children[v]; + } + } + + int search(int x) { + Trie* node = this; + int ans = 0; + for (int i = 30; ~i; --i) { + int v = (x >> i) & 1; + if (node->children[v ^ 1]) { + ans |= 1 << i; + node = node->children[v ^ 1]; + } else if (node->children[v]) { + node = node->children[v]; + } else { + return -1; + } + } + return ans; + } +}; + +class Solution { +public: + vector maximizeXor(vector& nums, vector>& queries) { + sort(nums.begin(), nums.end()); + int n = queries.size(); + vector idx(n); + iota(idx.begin(), idx.end(), 0); + sort(idx.begin(), idx.end(), [&](int i, int j) { return queries[i][1] < queries[j][1]; }); + vector ans(n); + Trie trie; + int j = 0; + for (int i : idx) { + int x = queries[i][0], m = queries[i][1]; + while (j < nums.size() && nums[j] <= m) { + trie.insert(nums[j++]); + } + ans[i] = trie.search(x); + } + return ans; + } }; \ No newline at end of file diff --git a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.go b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.go index db3806c491d31..65d9550ada8d8 100644 --- a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.go +++ b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.go @@ -2,28 +2,29 @@ type Trie struct { children [2]*Trie } -func newTrie() *Trie { +func NewTrie() *Trie { return &Trie{} } -func (this *Trie) insert(x int) { - node := this + +func (t *Trie) insert(x int) { + node := t for i := 30; i >= 0; i-- { - v := (x >> i) & 1 + v := x >> i & 1 if node.children[v] == nil { - node.children[v] = newTrie() + node.children[v] = NewTrie() } node = node.children[v] } } -func (this *Trie) search(x int) int { - node := this +func (t *Trie) search(x int) int { + node := t ans := 0 for i := 30; i >= 0; i-- { - v := (x >> i) & 1 + v := x >> i & 1 if node.children[v^1] != nil { - node = node.children[v^1] ans |= 1 << i + node = node.children[v^1] } else if node.children[v] != nil { node = node.children[v] } else { @@ -35,18 +36,19 @@ func (this *Trie) search(x int) int { func maximizeXor(nums []int, queries [][]int) []int { sort.Ints(nums) - type tuple struct{ i, x, m int } n := len(queries) - qs := make([]tuple, n) - for i, q := range queries { - qs[i] = tuple{i, q[0], q[1]} + idx := make([]int, n) + for i := 0; i < n; i++ { + idx[i] = i } - sort.Slice(qs, func(i, j int) bool { return qs[i].m < qs[j].m }) - j := 0 + sort.Slice(idx, func(i, j int) bool { + return queries[idx[i]][1] < queries[idx[j]][1] + }) ans := make([]int, n) - trie := newTrie() - for _, q := range qs { - i, x, m := q.i, q.x, q.m + trie := NewTrie() + j := 0 + for _, i := range idx { + x, m := queries[i][0], queries[i][1] for j < len(nums) && nums[j] <= m { trie.insert(nums[j]) j++ diff --git a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.java b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.java index 4f992652b2ec5..8be4febaebd6a 100644 --- a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.java +++ b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.java @@ -1,54 +1,54 @@ -class Solution { - public int[] maximizeXor(int[] nums, int[][] queries) { - Trie trie = new Trie(); - Arrays.sort(nums); - int n = queries.length; - int[] ans = new int[n]; - int[][] qs = new int[n][3]; - for (int i = 0; i < n; ++i) { - qs[i] = new int[] {i, queries[i][0], queries[i][1]}; - } - Arrays.sort(qs, (a, b) -> a[2] - b[2]); - int j = 0; - for (var q : qs) { - int i = q[0], x = q[1], m = q[2]; - while (j < nums.length && nums[j] <= m) { - trie.insert(nums[j++]); - } - ans[i] = trie.search(x); - } - return ans; - } -} - -class Trie { - Trie[] children = new Trie[2]; - - public void insert(int x) { - Trie node = this; - for (int i = 30; i >= 0; --i) { - int v = (x >> i) & 1; - if (node.children[v] == null) { - node.children[v] = new Trie(); - } - node = node.children[v]; - } - } - - public int search(int x) { - Trie node = this; - int ans = 0; - for (int i = 30; i >= 0; --i) { - int v = (x >> i) & 1; - if (node.children[v ^ 1] != null) { - ans |= 1 << i; - node = node.children[v ^ 1]; - } else if (node.children[v] != null) { - node = node.children[v]; - } else { - return -1; - } - } - return ans; - } +class Trie { + private Trie[] children = new Trie[2]; + + public void insert(int x) { + Trie node = this; + for (int i = 30; i >= 0; --i) { + int v = x >> i & 1; + if (node.children[v] == null) { + node.children[v] = new Trie(); + } + node = node.children[v]; + } + } + + public int search(int x) { + Trie node = this; + int ans = 0; + for (int i = 30; i >= 0; --i) { + int v = x >> i & 1; + if (node.children[v ^ 1] != null) { + ans |= 1 << i; + node = node.children[v ^ 1]; + } else if (node.children[v] != null) { + node = node.children[v]; + } else { + return -1; + } + } + return ans; + } +} + +class Solution { + public int[] maximizeXor(int[] nums, int[][] queries) { + Arrays.sort(nums); + int n = queries.length; + Integer[] idx = new Integer[n]; + for (int i = 0; i < n; ++i) { + idx[i] = i; + } + Arrays.sort(idx, (i, j) -> queries[i][1] - queries[j][1]); + int[] ans = new int[n]; + Trie trie = new Trie(); + int j = 0; + for (int i : idx) { + int x = queries[i][0], m = queries[i][1]; + while (j < nums.length && nums[j] <= m) { + trie.insert(nums[j++]); + } + ans[i] = trie.search(x); + } + return ans; + } } \ No newline at end of file diff --git a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.py b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.py index 6a0bb402d621a..73848b8cd9709 100644 --- a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.py +++ b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.py @@ -1,39 +1,41 @@ -class Trie: - def __init__(self): - self.children = [None] * 2 - - def insert(self, x): - node = self - for i in range(30, -1, -1): - v = (x >> i) & 1 - if node.children[v] is None: - node.children[v] = Trie() - node = node.children[v] - - def search(self, x): - node = self - ans = 0 - for i in range(30, -1, -1): - v = (x >> i) & 1 - if node.children[v ^ 1]: - ans |= 1 << i - node = node.children[v ^ 1] - elif node.children[v]: - node = node.children[v] - else: - return -1 - return ans - - -class Solution: - def maximizeXor(self, nums: List[int], queries: List[List[int]]) -> List[int]: - trie = Trie() - nums.sort() - j, n = 0, len(queries) - ans = [-1] * n - for i, (x, m) in sorted(zip(range(n), queries), key=lambda x: x[1][1]): - while j < len(nums) and nums[j] <= m: - trie.insert(nums[j]) - j += 1 - ans[i] = trie.search(x) - return ans +class Trie: + __slots__ = ["children"] + + def __init__(self): + self.children = [None] * 2 + + def insert(self, x: int): + node = self + for i in range(30, -1, -1): + v = x >> i & 1 + if node.children[v] is None: + node.children[v] = Trie() + node = node.children[v] + + def search(self, x: int) -> int: + node = self + ans = 0 + for i in range(30, -1, -1): + v = x >> i & 1 + if node.children[v ^ 1]: + ans |= 1 << i + node = node.children[v ^ 1] + elif node.children[v]: + node = node.children[v] + else: + return -1 + return ans + + +class Solution: + def maximizeXor(self, nums: List[int], queries: List[List[int]]) -> List[int]: + trie = Trie() + nums.sort() + j, n = 0, len(queries) + ans = [-1] * n + for i, (x, m) in sorted(zip(range(n), queries), key=lambda x: x[1][1]): + while j < len(nums) and nums[j] <= m: + trie.insert(nums[j]) + j += 1 + ans[i] = trie.search(x) + return ans diff --git a/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.ts b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.ts new file mode 100644 index 0000000000000..561092fe18669 --- /dev/null +++ b/solution/1700-1799/1707.Maximum XOR With an Element From Array/Solution.ts @@ -0,0 +1,54 @@ +class Trie { + children: (Trie | null)[]; + + constructor() { + this.children = [null, null]; + } + + insert(x: number): void { + let node: Trie | null = this; + for (let i = 30; ~i; i--) { + const v = (x >> i) & 1; + if (node.children[v] === null) { + node.children[v] = new Trie(); + } + node = node.children[v] as Trie; + } + } + + search(x: number): number { + let node: Trie | null = this; + let ans = 0; + for (let i = 30; ~i; i--) { + const v = (x >> i) & 1; + if (node.children[v ^ 1] !== null) { + ans |= 1 << i; + node = node.children[v ^ 1] as Trie; + } else if (node.children[v] !== null) { + node = node.children[v] as Trie; + } else { + return -1; + } + } + return ans; + } +} + +function maximizeXor(nums: number[], queries: number[][]): number[] { + nums.sort((a, b) => a - b); + const n = queries.length; + const idx = Array.from({ length: n }, (_, i) => i); + idx.sort((i, j) => queries[i][1] - queries[j][1]); + const ans: number[] = []; + const trie = new Trie(); + let j = 0; + for (const i of idx) { + const x = queries[i][0]; + const m = queries[i][1]; + while (j < nums.length && nums[j] <= m) { + trie.insert(nums[j++]); + } + ans[i] = trie.search(x); + } + return ans; +} diff --git a/solution/1700-1799/1774.Closest Dessert Cost/README.md b/solution/1700-1799/1774.Closest Dessert Cost/README.md index 7ad922131afca..b5e6f04751fc1 100644 --- a/solution/1700-1799/1774.Closest Dessert Cost/README.md +++ b/solution/1700-1799/1774.Closest Dessert Cost/README.md @@ -88,7 +88,7 @@ 每种类型的配料最多可以选两份,因此,我们可以复制一份配料,然后利用 `DFS` 枚举子集之和。在实现上,我们可以只枚举一半的配料的所有子集和,然后在另一半配料子集和中,利用二分查找找到最接近的配料。 -时间复杂度 $O(n\times 2^m \times \log {2^m})$。 +时间复杂度 $O(n \times 2^m \times \log {2^m})$。 相似题目:[1755. 最接近目标值的子序列和](/solution/1700-1799/1755.Closest%20Subsequence%20Sum/README.md)