Skip to content

feat: add solutions to lc problems: No.1899,1918 #4324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,20 @@ tags:

### 方法一:贪心

我们记 $target = [x, y, z]$,初始时 $d = e = f = 0$,表示当前的 $a, b, c$ 的最大值
我们记 $\textit{target} = [x, y, z]$,我们需要判断是否存在三元组 $[a, b, c]$ 使得 $a \le x, b \le y, c \le z$

我们遍历数组 $triplets$,对于每个三元组 $[a, b, c]$,如果 $a \le x, b \le y, c \le z$,则将 $d, e, f$ 分别更新为 $max(d, a), max(e, b), max(f, c)$。
我们可以将所有的三元组分为两类:

最后判断 $[d, e, f]$ 是否等于 $target$ 即可。
1. 满足 $a \le x, b \le y, c \le z$ 的三元组。
2. 不满足 $a \le x, b \le y, c \le z$ 的三元组。

时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为数组 $triplets$ 的长度。
对于第一类三元组,我们可以将它们的 $a, b, c$ 分别取最大值,得到一个新的三元组 $[d, e, f]$。

对于第二类三元组,我们可以忽略它们,因为它们无法帮助我们得到目标三元组。

最后,我们只需要判断 $[d, e, f]$ 是否等于 $\textit{target}$ 即可。如果等于,返回 $\textit{true}$,否则返回 $\textit{false}$。

时间复杂度 $O(n)$,其中 $n$ 为数组 $\textit{triplets}$ 的长度。空间复杂度 $O(1)$。

<!-- tabs:start -->

Expand Down Expand Up @@ -193,6 +200,50 @@ function mergeTriplets(triplets: number[][], target: number[]): boolean {
}
```

#### Rust

```rust
impl Solution {
pub fn merge_triplets(triplets: Vec<Vec<i32>>, target: Vec<i32>) -> bool {
let [x, y, z]: [i32; 3] = target.try_into().unwrap();
let (mut d, mut e, mut f) = (0, 0, 0);

for triplet in triplets {
if let [a, b, c] = triplet[..] {
if a <= x && b <= y && c <= z {
d = d.max(a);
e = e.max(b);
f = f.max(c);
}
}
}

[d, e, f] == [x, y, z]
}
}
```

#### Scala

```scala
object Solution {
def mergeTriplets(triplets: Array[Array[Int]], target: Array[Int]): Boolean = {
val Array(x, y, z) = target
var (d, e, f) = (0, 0, 0)

for (Array(a, b, c) <- triplets) {
if (a <= x && b <= y && c <= z) {
d = d.max(a)
e = e.max(b)
f = f.max(c)
}
}

d == x && e == y && f == z
}
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,22 @@ The target triplet [5,5,5] is now an element of triplets.

<!-- solution:start -->

### Solution 1
### Solution 1: Greedy

Let $\textit{target} = [x, y, z]$. We need to determine whether there exists a triplet $[a, b, c]$ such that $a \leq x$, $b \leq y$, and $c \leq z$.

We can divide all triplets into two categories:

1. Triplets that satisfy $a \leq x$, $b \leq y$, and $c \leq z$.
2. Triplets that do not satisfy $a \leq x$, $b \leq y$, and $c \leq z$.

For the first category, we can take the maximum values of $a$, $b$, and $c$ from these triplets to form a new triplet $[d, e, f]$.

For the second category, we can ignore these triplets because they cannot help us achieve the target triplet.

Finally, we just need to check whether $[d, e, f]$ is equal to $\textit{target}$. If it is, return $\textit{true}$; otherwise, return $\textit{false}$.

Time complexity is $O(n)$, where $n$ is the length of the array $\textit{triplets}$. Space complexity is $O(1)$.

<!-- tabs:start -->

Expand Down Expand Up @@ -175,6 +190,50 @@ function mergeTriplets(triplets: number[][], target: number[]): boolean {
}
```

#### Rust

```rust
impl Solution {
pub fn merge_triplets(triplets: Vec<Vec<i32>>, target: Vec<i32>) -> bool {
let [x, y, z]: [i32; 3] = target.try_into().unwrap();
let (mut d, mut e, mut f) = (0, 0, 0);

for triplet in triplets {
if let [a, b, c] = triplet[..] {
if a <= x && b <= y && c <= z {
d = d.max(a);
e = e.max(b);
f = f.max(c);
}
}
}

[d, e, f] == [x, y, z]
}
}
```

#### Scala

```scala
object Solution {
def mergeTriplets(triplets: Array[Array[Int]], target: Array[Int]): Boolean = {
val Array(x, y, z) = target
var (d, e, f) = (0, 0, 0)

for (Array(a, b, c) <- triplets) {
if (a <= x && b <= y && c <= z) {
d = d.max(a)
e = e.max(b)
f = f.max(c)
}
}

d == x && e == y && f == z
}
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
impl Solution {
pub fn merge_triplets(triplets: Vec<Vec<i32>>, target: Vec<i32>) -> bool {
let [x, y, z]: [i32; 3] = target.try_into().unwrap();
let (mut d, mut e, mut f) = (0, 0, 0);

for triplet in triplets {
if let [a, b, c] = triplet[..] {
if a <= x && b <= y && c <= z {
d = d.max(a);
e = e.max(b);
f = f.max(c);
}
}
}

[d, e, f] == [x, y, z]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
object Solution {
def mergeTriplets(triplets: Array[Array[Int]], target: Array[Int]): Boolean = {
val Array(x, y, z) = target
var (d, e, f) = (0, 0, 0)

for (Array(a, b, c) <- triplets) {
if (a <= x && b <= y && c <= z) {
d = d.max(a)
e = e.max(b)
f = f.max(c)
}
}

d == x && e == y && f == z
}
}
117 changes: 113 additions & 4 deletions solution/1900-1999/1918.Kth Smallest Subarray Sum/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,19 @@ tags:

我们注意到,题目中数组元素均为正整数,子数组的和 $s$ 越大,那么数组中子数组和小于等于 $s$ 的个数就越多。这存在一个单调性,因此我们可以考虑使用使用二分查找的方法来求解。

我们二分枚举子数组的和,初始化左右边界分别为数组 $nums$ 中的最小值以及所有元素之和。每次我们计算数组中子数组和小于等于当前枚举值的个数,如果个数大于等于 $k$,则说明当前枚举值 $s$ 可能是第 $k$ 小的子数组和,我们缩小右边界,否则我们增大左边界。枚举结束后,左边界即为第 $k$ 小的子数组和。
我们二分枚举子数组的和,初始化左右边界分别为数组 $\textit{nums}$ 中的最小值以及所有元素之和。每次我们计算数组中子数组和小于等于当前枚举值的个数,如果个数大于等于 $k$,则说明当前枚举值 $s$ 可能是第 $k$ 小的子数组和,我们缩小右边界,否则我们增大左边界。枚举结束后,左边界即为第 $k$ 小的子数组和。

问题转换为计算一个数组中,有多少个子数组的和小于等于 $s$,我们可以通过函数 $f(s)$ 来计算。

函数 $f(s)$ 的计算方法如下:

- 初始化双指针 $j$ 和 $i$,分别指向当前窗口的左右边界,初始时 $j = i = 0$。初始化窗口内元素的和 $t = 0$。
- 用变量 $cnt$ 记录子数组和小于等于 $s$ 的个数,初始时 $cnt = 0$。
- 遍历数组 $nums$,每次遍历到一个元素 $nums[i]$,我们将其加入窗口,即 $t = t + nums[i]$。如果此时 $t \gt s$,我们需要不断地将窗口的左边界右移,直到 $t \le s$ 为止,即不断地执行 $t -= nums[j]$,并且 $j = j + 1$。接下来我们更新 $cnt$,即 $cnt = cnt + i - j + 1$。继续遍历下一个元素,直到遍历完整个数组。
- 用变量 $\textit{cnt}$ 记录子数组和小于等于 $s$ 的个数,初始时 $\textit{cnt} = 0$。
- 遍历数组 $\textit{nums}$,每次遍历到一个元素 $\textit{nums}[i]$,我们将其加入窗口,即 $t = t + \textit{nums}[i]$。如果此时 $t \gt s$,我们需要不断地将窗口的左边界右移,直到 $t \le s$ 为止,即不断地执行 $t -= \textit{nums}[j]$,并且 $j = j + 1$。接下来我们更新 $\textit{cnt}$,即 $\textit{cnt} = \textit{cnt} + i - j + 1$。继续遍历下一个元素,直到遍历完整个数组。

最后将 $cnt$ 作为函数 $f(s)$ 的返回值。

时间复杂度 $O(n \times \log S)$,空间复杂度 $O(1)$。其中 $n$ 为数组 $nums$ 的长度,而 $S$ 为数组 $nums$ 中所有元素之和。
时间复杂度 $O(n \times \log S)$,其中 $n$ 为数组 $\textit{nums}$ 的长度,而 $S$ 为数组 $\textit{nums}$ 中所有元素之和。空间复杂度 $O(1)$

<!-- tabs:start -->

Expand Down Expand Up @@ -219,6 +219,115 @@ func kthSmallestSubarraySum(nums []int, k int) int {
}
```

#### TypeScript

```ts
function kthSmallestSubarraySum(nums: number[], k: number): number {
let l = Math.min(...nums);
let r = nums.reduce((sum, x) => sum + x, 0);

const f = (s: number): number => {
let cnt = 0;
let t = 0;
let j = 0;

for (let i = 0; i < nums.length; i++) {
t += nums[i];
while (t > s) {
t -= nums[j];
j++;
}
cnt += i - j + 1;
}
return cnt;
};

while (l < r) {
const mid = (l + r) >> 1;
if (f(mid) >= k) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
```

#### Rust

```rust
impl Solution {
pub fn kth_smallest_subarray_sum(nums: Vec<i32>, k: i32) -> i32 {
let mut l = *nums.iter().min().unwrap();
let mut r: i32 = nums.iter().sum();

let f = |s: i32| -> i32 {
let (mut cnt, mut t, mut j) = (0, 0, 0);

for i in 0..nums.len() {
t += nums[i];
while t > s {
t -= nums[j];
j += 1;
}
cnt += (i - j + 1) as i32;
}
cnt
};

while l < r {
let mid = (l + r) / 2;
if f(mid) >= k {
r = mid;
} else {
l = mid + 1;
}
}
l
}
}
```

#### Scala

```scala
object Solution {
def kthSmallestSubarraySum(nums: Array[Int], k: Int): Int = {
var l = Int.MaxValue
var r = 0

for (x <- nums) {
l = l.min(x)
r += x
}

def f(s: Int): Int = {
var cnt = 0
var t = 0
var j = 0

for (i <- nums.indices) {
t += nums(i)
while (t > s) {
t -= nums(j)
j += 1
}
cnt += i - j + 1
}
cnt
}

while (l < r) {
val mid = (l + r) / 2
if (f(mid) >= k) r = mid
else l = mid + 1
}
l
}
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
Loading