Skip to content

Commit

Permalink
feat: add solutions to lc problem: No.1590 (#3996)
Browse files Browse the repository at this point in the history
No.1590.Make Sum Divisible by P
  • Loading branch information
yanglbme authored Jan 26, 2025
1 parent 2fa1a47 commit 8974512
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 6 deletions.
83 changes: 78 additions & 5 deletions solution/1500-1599/1590.Make Sum Divisible by P/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}$ 的长度。

<!-- tabs:start -->

Expand Down Expand Up @@ -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<i32>, 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;
};
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
87 changes: 86 additions & 1 deletion solution/1500-1599/1590.Make Sum Divisible by P/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,19 @@ tags:

<!-- solution:start -->

### 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}$.

<!-- tabs:start -->

Expand Down Expand Up @@ -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<i32>, 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;
};
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
29 changes: 29 additions & 0 deletions solution/1500-1599/1590.Make Sum Divisible by P/Solution.js
Original file line number Diff line number Diff line change
@@ -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;
};
34 changes: 34 additions & 0 deletions solution/1500-1599/1590.Make Sum Divisible by P/Solution.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::collections::HashMap;

impl Solution {
pub fn min_subarray(nums: Vec<i32>, 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
}
}
}

0 comments on commit 8974512

Please sign in to comment.