diff --git a/solution/1500-1599/1590.Make Sum Divisible by P/README.md b/solution/1500-1599/1590.Make Sum Divisible by P/README.md index e86b4fe761d74..e123d53b5ffe1 100644 --- a/solution/1500-1599/1590.Make Sum Divisible by P/README.md +++ b/solution/1500-1599/1590.Make Sum Divisible by P/README.md @@ -80,17 +80,17 @@ tags: ### 方法一:前缀和 + 哈希表 -我们可以先求出数组 $nums$ 所有元素之和模 $p$ 的值,记为 $k$。如果 $k$ 为 $0$,说明数组 $nums$ 所有元素之和就是 $p$ 的倍数,直接返回 $0$ 即可。 +我们可以先求出数组 $\textit{nums}$ 所有元素之和模 $p$ 的值,记为 $k$。如果 $k$ 为 $0$,说明数组 $\textit{nums}$ 所有元素之和就是 $p$ 的倍数,直接返回 $0$ 即可。 如果 $k$ 不为 $0$,我们需要找到一个最短的子数组,使得删除该子数组后,剩余元素之和模 $p$ 的值为 $0$。 -我们可以遍历数组 $nums$,维护当前的前缀和模 $p$ 的值,记为 $cur$。用哈希表 $last$ 记录每个前缀和模 $p$ 的值最后一次出现的位置。 +我们可以遍历数组 $\textit{nums}$,维护当前的前缀和模 $p$ 的值,记为 $cur$。用哈希表 $last$ 记录每个前缀和模 $p$ 的值最后一次出现的位置。 -如果当前存在一个以 $nums[i]$ 结尾的子数组,使得删除该子数组后,剩余元素之和模 $p$ 的值为 $0$。也就是说,我们需要找到此前的一个前缀和模 $p$ 的值为 $target$ 的位置 $j$,使得 $(target + k - cur) \bmod p = 0$。如果找到,我们就可以将 $j + 1$ 到 $i$ 这一段闭区间子数组 $nums[j+1,..i]$ 删除,使得剩余元素之和模 $p$ 的值为 $0$。 +如果当前存在一个以 $\textit{nums}[i]$ 结尾的子数组,使得删除该子数组后,剩余元素之和模 $p$ 的值为 $0$。也就是说,我们需要找到此前的一个前缀和模 $p$ 的值为 $target$ 的位置 $j$,使得 $(target + k - cur) \bmod p = 0$。如果找到,我们就可以将 $j + 1$ 到 $i$ 这一段闭区间子数组 $\textit{nums}[j+1,..i]$ 删除,使得剩余元素之和模 $p$ 的值为 $0$。 -因此,如果存在一个 $target = (cur - k + p) \bmod p$,那么我们可以更新答案为 $\min(ans, i - j)$。接下来,我们更新 $last[cur]$ 的值为 $i$。继续遍历数组 $nums$,直到遍历结束,即可得到答案。 +因此,如果存在一个 $target = (cur - k + p) \bmod p$,那么我们可以更新答案为 $\min(ans, i - j)$。接下来,我们更新 $last[cur]$ 的值为 $i$。继续遍历数组 $\textit{nums}$,直到遍历结束,即可得到答案。 -时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $nums$ 的长度。 +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $\textit{nums}$ 的长度。 @@ -234,6 +234,79 @@ function minSubarray(nums: number[], p: number): number { } ``` +#### Rust + +```rust +use std::collections::HashMap; + +impl Solution { + pub fn min_subarray(nums: Vec, p: i32) -> i32 { + let mut k = 0; + for &x in &nums { + k = (k + x) % p; + } + if k == 0 { + return 0; + } + + let mut last = HashMap::new(); + last.insert(0, -1); + let n = nums.len(); + let mut ans = n as i32; + let mut cur = 0; + + for i in 0..n { + cur = (cur + nums[i]) % p; + let target = (cur - k + p) % p; + if let Some(&prev_idx) = last.get(&target) { + ans = ans.min(i as i32 - prev_idx); + } + last.insert(cur, i as i32); + } + + if ans == n as i32 { + -1 + } else { + ans + } + } +} +``` + +#### JavaScript + +```js +/** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ +var minSubarray = function (nums, p) { + let k = 0; + for (const x of nums) { + k = (k + x) % p; + } + if (k === 0) { + return 0; + } + const last = new Map(); + last.set(0, -1); + const n = nums.length; + let ans = n; + let cur = 0; + for (let i = 0; i < n; ++i) { + cur = (cur + nums[i]) % p; + const target = (cur - k + p) % p; + if (last.has(target)) { + const j = last.get(target); + ans = Math.min(ans, i - j); + } + last.set(cur, i); + } + return ans === n ? -1 : ans; +}; +``` + diff --git a/solution/1500-1599/1590.Make Sum Divisible by P/README_EN.md b/solution/1500-1599/1590.Make Sum Divisible by P/README_EN.md index 643b38f1d2d9e..787b4c13c7728 100644 --- a/solution/1500-1599/1590.Make Sum Divisible by P/README_EN.md +++ b/solution/1500-1599/1590.Make Sum Divisible by P/README_EN.md @@ -66,7 +66,19 @@ tags: -### Solution 1 +### Solution 1: Prefix Sum + Hash Table + +First, we calculate the sum of all elements in the array $\textit{nums}$ modulo $p$, denoted as $k$. If $k$ is $0$, it means the sum of all elements in the array $\textit{nums}$ is a multiple of $p$, so we directly return $0$. + +If $k$ is not $0$, we need to find the shortest subarray such that removing this subarray makes the sum of the remaining elements modulo $p$ equal to $0$. + +We can traverse the array $\textit{nums}$, maintaining the current prefix sum modulo $p$, denoted as $cur$. We use a hash table $last$ to record the last occurrence of each prefix sum modulo $p$. + +If there exists a subarray ending at $\textit{nums}[i]$ such that removing this subarray makes the sum of the remaining elements modulo $p$ equal to $0$, we need to find a previous prefix sum modulo $p$ equal to $target$ at position $j$ such that $(target + k - cur) \bmod p = 0$. If found, we can remove the subarray $\textit{nums}[j+1,..i]$ to make the sum of the remaining elements modulo $p$ equal to $0$. + +Therefore, if there exists a $target = (cur - k + p) \bmod p$, we can update the answer to $\min(ans, i - j)$. Then, we update $last[cur]$ to $i$. We continue traversing the array $\textit{nums}$ until the end to get the answer. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $\textit{nums}$. @@ -210,6 +222,79 @@ function minSubarray(nums: number[], p: number): number { } ``` +#### Rust + +```rust +use std::collections::HashMap; + +impl Solution { + pub fn min_subarray(nums: Vec, p: i32) -> i32 { + let mut k = 0; + for &x in &nums { + k = (k + x) % p; + } + if k == 0 { + return 0; + } + + let mut last = HashMap::new(); + last.insert(0, -1); + let n = nums.len(); + let mut ans = n as i32; + let mut cur = 0; + + for i in 0..n { + cur = (cur + nums[i]) % p; + let target = (cur - k + p) % p; + if let Some(&prev_idx) = last.get(&target) { + ans = ans.min(i as i32 - prev_idx); + } + last.insert(cur, i as i32); + } + + if ans == n as i32 { + -1 + } else { + ans + } + } +} +``` + +#### JavaScript + +```js +/** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ +var minSubarray = function (nums, p) { + let k = 0; + for (const x of nums) { + k = (k + x) % p; + } + if (k === 0) { + return 0; + } + const last = new Map(); + last.set(0, -1); + const n = nums.length; + let ans = n; + let cur = 0; + for (let i = 0; i < n; ++i) { + cur = (cur + nums[i]) % p; + const target = (cur - k + p) % p; + if (last.has(target)) { + const j = last.get(target); + ans = Math.min(ans, i - j); + } + last.set(cur, i); + } + return ans === n ? -1 : ans; +}; +``` + diff --git a/solution/1500-1599/1590.Make Sum Divisible by P/Solution.js b/solution/1500-1599/1590.Make Sum Divisible by P/Solution.js new file mode 100644 index 0000000000000..c42f226533c9f --- /dev/null +++ b/solution/1500-1599/1590.Make Sum Divisible by P/Solution.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ +var minSubarray = function (nums, p) { + let k = 0; + for (const x of nums) { + k = (k + x) % p; + } + if (k === 0) { + return 0; + } + const last = new Map(); + last.set(0, -1); + const n = nums.length; + let ans = n; + let cur = 0; + for (let i = 0; i < n; ++i) { + cur = (cur + nums[i]) % p; + const target = (cur - k + p) % p; + if (last.has(target)) { + const j = last.get(target); + ans = Math.min(ans, i - j); + } + last.set(cur, i); + } + return ans === n ? -1 : ans; +}; diff --git a/solution/1500-1599/1590.Make Sum Divisible by P/Solution.rs b/solution/1500-1599/1590.Make Sum Divisible by P/Solution.rs new file mode 100644 index 0000000000000..7773949f3a64d --- /dev/null +++ b/solution/1500-1599/1590.Make Sum Divisible by P/Solution.rs @@ -0,0 +1,34 @@ +use std::collections::HashMap; + +impl Solution { + pub fn min_subarray(nums: Vec, p: i32) -> i32 { + let mut k = 0; + for &x in &nums { + k = (k + x) % p; + } + if k == 0 { + return 0; + } + + let mut last = HashMap::new(); + last.insert(0, -1); + let n = nums.len(); + let mut ans = n as i32; + let mut cur = 0; + + for i in 0..n { + cur = (cur + nums[i]) % p; + let target = (cur - k + p) % p; + if let Some(&prev_idx) = last.get(&target) { + ans = ans.min(i as i32 - prev_idx); + } + last.insert(cur, i as i32); + } + + if ans == n as i32 { + -1 + } else { + ans + } + } +}