Skip to content

Commit

Permalink
Add solution 1674、1690
Browse files Browse the repository at this point in the history
  • Loading branch information
halfrost committed Dec 17, 2020
1 parent e85f323 commit e3fd0d2
Show file tree
Hide file tree
Showing 9 changed files with 655 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package leetcode

func minMoves(nums []int, limit int) int {
diff := make([]int, limit*2+2) // nums[i] <= limit, b+limit+1 is maximum limit+limit+1
for j := 0; j < len(nums)/2; j++ {
a, b := min(nums[j], nums[len(nums)-j-1]), max(nums[j], nums[len(nums)-j-1])
// using prefix sum: most interesting point, and is the key to reduce complexity
diff[2] += 2
diff[a+1]--
diff[a+b]--
diff[a+b+1]++
diff[b+limit+1]++
}
cur, res := 0, len(nums)
for i := 2; i <= 2*limit; i++ {
cur += diff[i]
res = min(res, cur)
}
return res
}

func min(a, b int) int {
if a < b {
return a
}
return b
}

func max(a, b int) int {
if a > b {
return a
}
return b
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package leetcode

import (
"fmt"
"testing"
)

type question1674 struct {
para1674
ans1674
}

// para 是参数
// one 代表第一个参数
type para1674 struct {
nums []int
limit int
}

// ans 是答案
// one 代表第一个答案
type ans1674 struct {
one int
}

func Test_Problem1674(t *testing.T) {

qs := []question1674{

{
para1674{[]int{1, 2, 4, 3}, 4},
ans1674{1},
},

{
para1674{[]int{1, 2, 2, 1}, 2},
ans1674{2},
},

{
para1674{[]int{1, 2, 1, 2}, 2},
ans1674{0},
},
}

fmt.Printf("------------------------Leetcode Problem 1674------------------------\n")

for _, q := range qs {
_, p := q.ans1674, q.para1674
fmt.Printf("【input】:%v 【output】:%v\n", p, minMoves(p.nums, p.limit))
}
fmt.Printf("\n\n\n")
}
97 changes: 97 additions & 0 deletions leetcode/1674.Minimum-Moves-to-Make-Array-Complementary/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# [1674. Minimum Moves to Make Array Complementary](https://leetcode.com/problems/minimum-moves-to-make-array-complementary/)

## 题目

You are given an integer array `nums` of **even** length `n` and an integer `limit`. In one move, you can replace any integer from `nums` with another integer between `1` and `limit`, inclusive.

The array `nums` is **complementary** if for all indices `i` (**0-indexed**), `nums[i] + nums[n - 1 - i]` equals the same number. For example, the array `[1,2,3,4]` is complementary because for all indices `i``nums[i] + nums[n - 1 - i] = 5`.

Return the ***minimum** number of moves required to make* `nums` ***complementary***.

**Example 1:**

```
Input: nums = [1,2,4,3], limit = 4
Output: 1
Explanation: In 1 move, you can change nums to [1,2,2,3] (underlined elements are changed).
nums[0] + nums[3] = 1 + 3 = 4.
nums[1] + nums[2] = 2 + 2 = 4.
nums[2] + nums[1] = 2 + 2 = 4.
nums[3] + nums[0] = 3 + 1 = 4.
Therefore, nums[i] + nums[n-1-i] = 4 for every i, so nums is complementary.
```

**Example 2:**

```
Input: nums = [1,2,2,1], limit = 2
Output: 2
Explanation: In 2 moves, you can change nums to [2,2,2,2]. You cannot change any number to 3 since 3 > limit.
```

**Example 3:**

```
Input: nums = [1,2,1,2], limit = 2
Output: 0
Explanation: nums is already complementary.
```

**Constraints:**

- `n == nums.length`
- `2 <= n <= 105`
- `1 <= nums[i] <= limit <= 105`
- `n` is even.

## 题目大意

给你一个长度为 偶数 n 的整数数组 nums 和一个整数 limit 。每一次操作,你可以将 nums 中的任何整数替换为 1 到 limit 之间的另一个整数。

如果对于所有下标 i(下标从 0 开始),nums[i] + nums[n - 1 - i] 都等于同一个数,则数组 nums 是 互补的 。例如,数组 [1,2,3,4] 是互补的,因为对于所有下标 i ,nums[i] + nums[n - 1 - i] = 5 。

返回使数组 互补 的 最少 操作次数。

## 解题思路

- 这一题考察的是差分数组。通过分析题意,可以得出,针对每一个 `sum` 的取值范围是 `[2, 2* limt]`,定义 `a = min(nums[i], nums[n - i - 1])``b = max(nums[i], nums[n - i - 1])`,在这个区间内,又可以细分成 5 个区间,`[2, a + 1)``[a + 1, a + b)``[a + b + 1, a + b + 1)``[a + b + 1, b + limit + 1)``[b + limit + 1, 2 * limit)`,在这 5 个区间内使得数组互补的最小操作次数分别是 `2(减少 a, 减少 b)``1(减少 b)``0(不用操作)``1(增大 a)``+2(增大 a, 增大 b)`,换个表达方式,按照扫描线从左往右扫描,在这 5 个区间内使得数组互补的最小操作次数叠加变化分别是 `+2(减少 a, 减少 b)``-1(减少 a)``-1(不用操作)``+1(增大 a)``+1(增大 a, 增大 b)`,利用这前后两个区间的关系,就可以构造一个差分数组。差分数组反应的是前后两者的关系。如果想求得 0 ~ n 的总关系,只需要求一次前缀和即可。
- 这道题要求输出最少的操作次数,所以利用差分数组 + 前缀和,累加前缀和的同时维护最小值。从左往右扫描完一遍以后,输出最小值即可。

## 代码

```go
package leetcode

func minMoves(nums []int, limit int) int {
diff := make([]int, limit*2+2) // nums[i] <= limit, b+limit+1 is maximum limit+limit+1
for j := 0; j < len(nums)/2; j++ {
a, b := min(nums[j], nums[len(nums)-j-1]), max(nums[j], nums[len(nums)-j-1])
// using prefix sum: most interesting point, and is the key to reduce complexity
diff[2] += 2
diff[a+1]--
diff[a+b]--
diff[a+b+1]++
diff[b+limit+1]++
}
cur, res := 0, len(nums)
for i := 2; i <= 2*limit; i++ {
cur += diff[i]
res = min(res, cur)
}
return res
}

func min(a, b int) int {
if a < b {
return a
}
return b
}

func max(a, b int) int {
if a > b {
return a
}
return b
}
```
65 changes: 65 additions & 0 deletions leetcode/1690.Stone-Game-VII/1690. Stone Game VII.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package leetcode

// 解法一 优化空间版 DP
func stoneGameVII(stones []int) int {
n := len(stones)
sum := make([]int, n)
dp := make([]int, n)
for i, d := range stones {
sum[i] = d
}
for i := 1; i < n; i++ {
for j := 0; j+i < n; j++ {
if (n-i)%2 == 1 {
d0 := dp[j] + sum[j]
d1 := dp[j+1] + sum[j+1]
if d0 > d1 {
dp[j] = d0
} else {
dp[j] = d1
}
} else {
d0 := dp[j] - sum[j]
d1 := dp[j+1] - sum[j+1]
if d0 < d1 {
dp[j] = d0
} else {
dp[j] = d1
}
}
sum[j] = sum[j] + stones[i+j]
}
}
return dp[0]
}

// 解法二 常规 DP
func stoneGameVII1(stones []int) int {
prefixSum := make([]int, len(stones))
for i := 0; i < len(stones); i++ {
if i == 0 {
prefixSum[i] = stones[i]
} else {
prefixSum[i] = prefixSum[i-1] + stones[i]
}
}
dp := make([][]int, len(stones))
for i := range dp {
dp[i] = make([]int, len(stones))
dp[i][i] = 0
}
n := len(stones)
for l := 2; l <= n; l++ {
for i := 0; i+l <= n; i++ {
dp[i][i+l-1] = max(prefixSum[i+l-1]-prefixSum[i+1]+stones[i+1]-dp[i+1][i+l-1], prefixSum[i+l-2]-prefixSum[i]+stones[i]-dp[i][i+l-2])
}
}
return dp[0][n-1]
}

func max(a, b int) int {
if a > b {
return a
}
return b
}
47 changes: 47 additions & 0 deletions leetcode/1690.Stone-Game-VII/1690. Stone Game VII_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package leetcode

import (
"fmt"
"testing"
)

type question1690 struct {
para1690
ans1690
}

// para 是参数
// one 代表第一个参数
type para1690 struct {
stones []int
}

// ans 是答案
// one 代表第一个答案
type ans1690 struct {
one int
}

func Test_Problem1690(t *testing.T) {

qs := []question1690{

{
para1690{[]int{5, 3, 1, 4, 2}},
ans1690{6},
},

{
para1690{[]int{7, 90, 5, 1, 100, 10, 10, 2}},
ans1690{122},
},
}

fmt.Printf("------------------------Leetcode Problem 1690------------------------\n")

for _, q := range qs {
_, p := q.ans1690, q.para1690
fmt.Printf("【input】:%v 【output】:%v\n", p, stoneGameVII(p.stones))
}
fmt.Printf("\n\n\n")
}
Loading

0 comments on commit e3fd0d2

Please sign in to comment.