mirror of
https://github.com/halfrost/LeetCode-Go.git
synced 2025-07-05 08:27:30 +08:00
Add Weekly Contest 218
This commit is contained in:
@ -14,7 +14,7 @@ func interpret(command string) string {
|
||||
i += 3
|
||||
} else {
|
||||
res += "o"
|
||||
i += 1
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type question1678 struct {
|
||||
para1678
|
||||
ans1678
|
||||
}
|
||||
|
||||
// para 是参数
|
||||
// one 代表第一个参数
|
||||
type para1678 struct {
|
||||
command string
|
||||
}
|
||||
|
||||
// ans 是答案
|
||||
// one 代表第一个答案
|
||||
type ans1678 struct {
|
||||
one string
|
||||
}
|
||||
|
||||
func Test_Problem1678(t *testing.T) {
|
||||
|
||||
qs := []question1678{
|
||||
|
||||
{
|
||||
para1678{"G()(al)"},
|
||||
ans1678{"Goal"},
|
||||
},
|
||||
|
||||
{
|
||||
para1678{"G()()()()(al)"},
|
||||
ans1678{"Gooooal"},
|
||||
},
|
||||
|
||||
{
|
||||
para1678{"(al)G(al)()()G"},
|
||||
ans1678{"alGalooG"},
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Printf("------------------------Leetcode Problem 1678------------------------\n")
|
||||
|
||||
for _, q := range qs {
|
||||
_, p := q.ans1678, q.para1678
|
||||
fmt.Printf("【input】:%v 【output】:%v\n", p, interpret(p.command))
|
||||
}
|
||||
fmt.Printf("\n\n\n")
|
||||
}
|
73
leetcode/1678.Goal-Parser-Interpretation/README.md
Normal file
73
leetcode/1678.Goal-Parser-Interpretation/README.md
Normal file
@ -0,0 +1,73 @@
|
||||
# [1678. Goal Parser Interpretation](https://leetcode.com/problems/goal-parser-interpretation/)
|
||||
|
||||
## 题目
|
||||
|
||||
You own a **Goal Parser** that can interpret a string `command`. The `command` consists of an alphabet of `"G"`, `"()"` and/or `"(al)"` in some order. The Goal Parser will interpret `"G"` as the string `"G"`, `"()"` as the string `"o"`, and `"(al)"` as the string `"al"`. The interpreted strings are then concatenated in the original order.
|
||||
|
||||
Given the string `command`, return *the **Goal Parser**'s interpretation of* `command`.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```
|
||||
Input: command = "G()(al)"
|
||||
Output: "Goal"
|
||||
Explanation: The Goal Parser interprets the command as follows:
|
||||
G -> G
|
||||
() -> o
|
||||
(al) -> al
|
||||
The final concatenated result is "Goal".
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
```
|
||||
Input: command = "G()()()()(al)"
|
||||
Output: "Gooooal"
|
||||
```
|
||||
|
||||
**Example 3:**
|
||||
|
||||
```
|
||||
Input: command = "(al)G(al)()()G"
|
||||
Output: "alGalooG"
|
||||
```
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- `1 <= command.length <= 100`
|
||||
- `command` consists of `"G"`, `"()"`, and/or `"(al)"` in some order.
|
||||
|
||||
## 题目大意
|
||||
|
||||
请你设计一个可以解释字符串 command 的 Goal 解析器 。command 由 "G"、"()" 和/或 "(al)" 按某种顺序组成。Goal 解析器会将 "G" 解释为字符串 "G"、"()" 解释为字符串 "o" ,"(al)" 解释为字符串 "al" 。然后,按原顺序将经解释得到的字符串连接成一个字符串。给你字符串 command ,返回 Goal 解析器 对 command 的解释结果。
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 简单题,按照题意修改字符串即可。由于是简单题,这一题也不用考虑嵌套的情况。
|
||||
|
||||
## 代码
|
||||
|
||||
```go
|
||||
package leetcode
|
||||
|
||||
func interpret(command string) string {
|
||||
if command == "" {
|
||||
return ""
|
||||
}
|
||||
res := ""
|
||||
for i := 0; i < len(command); i++ {
|
||||
if command[i] == 'G' {
|
||||
res += "G"
|
||||
} else {
|
||||
if command[i] == '(' && command[i+1] == 'a' {
|
||||
res += "al"
|
||||
i += 3
|
||||
} else {
|
||||
res += "o"
|
||||
i ++
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
@ -0,0 +1,48 @@
|
||||
package leetcode
|
||||
|
||||
// 解法一 优化版
|
||||
func maxOperations(nums []int, k int) int {
|
||||
counter, res := make(map[int]int), 0
|
||||
for _, n := range nums {
|
||||
counter[n]++
|
||||
}
|
||||
if (k & 1) == 0 {
|
||||
res += counter[k>>1] >> 1
|
||||
// 能够由 2 个相同的数构成 k 的组合已经都排除出去了,剩下的一个单独的也不能组成 k 了
|
||||
// 所以这里要把它的频次置为 0 。如果这里不置为 0,下面代码判断逻辑还需要考虑重复使用数字的情况
|
||||
counter[k>>1] = 0
|
||||
}
|
||||
for num, freq := range counter {
|
||||
if num <= k/2 {
|
||||
remain := k - num
|
||||
if counter[remain] < freq {
|
||||
res += counter[remain]
|
||||
} else {
|
||||
res += freq
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 解法二
|
||||
func maxOperations_(nums []int, k int) int {
|
||||
counter, res := make(map[int]int), 0
|
||||
for _, num := range nums {
|
||||
counter[num]++
|
||||
remain := k - num
|
||||
if num == remain {
|
||||
if counter[num] >= 2 {
|
||||
res++
|
||||
counter[num] -= 2
|
||||
}
|
||||
} else {
|
||||
if counter[remain] > 0 {
|
||||
res++
|
||||
counter[remain]--
|
||||
counter[num]--
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type question1679 struct {
|
||||
para1679
|
||||
ans1679
|
||||
}
|
||||
|
||||
// para 是参数
|
||||
// one 代表第一个参数
|
||||
type para1679 struct {
|
||||
nums []int
|
||||
k int
|
||||
}
|
||||
|
||||
// ans 是答案
|
||||
// one 代表第一个答案
|
||||
type ans1679 struct {
|
||||
one int
|
||||
}
|
||||
|
||||
func Test_Problem1679(t *testing.T) {
|
||||
|
||||
qs := []question1679{
|
||||
|
||||
{
|
||||
para1679{[]int{1, 2, 3, 4}, 5},
|
||||
ans1679{2},
|
||||
},
|
||||
|
||||
{
|
||||
para1679{[]int{3, 1, 3, 4, 3}, 6},
|
||||
ans1679{1},
|
||||
},
|
||||
|
||||
{
|
||||
para1679{[]int{2, 5, 4, 4, 1, 3, 4, 4, 1, 4, 4, 1, 2, 1, 2, 2, 3, 2, 4, 2}, 3},
|
||||
ans1679{4},
|
||||
},
|
||||
|
||||
{
|
||||
para1679{[]int{2, 5, 5, 5, 1, 3, 4, 4, 1, 4, 4, 1, 3, 1, 3, 1, 3, 2, 4, 2}, 6},
|
||||
ans1679{8},
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Printf("------------------------Leetcode Problem 1679------------------------\n")
|
||||
|
||||
for _, q := range qs {
|
||||
_, p := q.ans1679, q.para1679
|
||||
fmt.Printf("【input】:%v 【output】:%v\n", p, maxOperations(p.nums, p.k))
|
||||
}
|
||||
fmt.Printf("\n\n\n")
|
||||
}
|
98
leetcode/1679.Max-Number-of-K-Sum-Pairs/README.md
Normal file
98
leetcode/1679.Max-Number-of-K-Sum-Pairs/README.md
Normal file
@ -0,0 +1,98 @@
|
||||
# [1679. Max Number of K-Sum Pairs](https://leetcode.com/problems/max-number-of-k-sum-pairs/)
|
||||
|
||||
|
||||
## 题目
|
||||
|
||||
You are given an integer array `nums` and an integer `k`.
|
||||
|
||||
In one operation, you can pick two numbers from the array whose sum equals `k` and remove them from the array.
|
||||
|
||||
Return *the maximum number of operations you can perform on the array*.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```
|
||||
Input: nums = [1,2,3,4], k = 5
|
||||
Output: 2
|
||||
Explanation: Starting with nums = [1,2,3,4]:
|
||||
- Remove numbers 1 and 4, then nums = [2,3]
|
||||
- Remove numbers 2 and 3, then nums = []
|
||||
There are no more pairs that sum up to 5, hence a total of 2 operations.
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
```
|
||||
Input: nums = [3,1,3,4,3], k = 6
|
||||
Output: 1
|
||||
Explanation: Starting with nums = [3,1,3,4,3]:
|
||||
- Remove the first two 3's, then nums = [1,4,3]
|
||||
There are no more pairs that sum up to 6, hence a total of 1 operation.
|
||||
```
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- `1 <= nums.length <= 105`
|
||||
- `1 <= nums[i] <= 109`
|
||||
- `1 <= k <= 109`
|
||||
|
||||
## 题目大意
|
||||
|
||||
给你一个整数数组 nums 和一个整数 k 。每一步操作中,你需要从数组中选出和为 k 的两个整数,并将它们移出数组。返回你可以对数组执行的最大操作数。
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 读完题第一感觉这道题是 TWO SUM 题目的加强版。需要找到所有满足和是 k 的数对。先考虑能不能找到两个数都是 k/2 ,如果能找到多个这样的数,可以先移除他们。其次在利用 TWO SUM 的思路,找出和为 k 的数对。利用 TWO SUM 里面 map 的做法,时间复杂度 O(n)。
|
||||
|
||||
## 代码
|
||||
|
||||
```go
|
||||
package leetcode
|
||||
|
||||
// 解法一 优化版
|
||||
func maxOperations(nums []int, k int) int {
|
||||
counter, res := make(map[int]int), 0
|
||||
for _, n := range nums {
|
||||
counter[n]++
|
||||
}
|
||||
if (k & 1) == 0 {
|
||||
res += counter[k>>1] >> 1
|
||||
// 能够由 2 个相同的数构成 k 的组合已经都排除出去了,剩下的一个单独的也不能组成 k 了
|
||||
// 所以这里要把它的频次置为 0 。如果这里不置为 0,下面代码判断逻辑还需要考虑重复使用数字的情况
|
||||
counter[k>>1] = 0
|
||||
}
|
||||
for num, freq := range counter {
|
||||
if num <= k/2 {
|
||||
remain := k - num
|
||||
if counter[remain] < freq {
|
||||
res += counter[remain]
|
||||
} else {
|
||||
res += freq
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 解法二
|
||||
func maxOperations_(nums []int, k int) int {
|
||||
counter, res := make(map[int]int), 0
|
||||
for _, num := range nums {
|
||||
counter[num]++
|
||||
remain := k - num
|
||||
if num == remain {
|
||||
if counter[num] >= 2 {
|
||||
res++
|
||||
counter[num] -= 2
|
||||
}
|
||||
} else {
|
||||
if counter[remain] > 0 {
|
||||
res++
|
||||
counter[remain]--
|
||||
counter[num]--
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
@ -0,0 +1,26 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// 解法一 模拟
|
||||
func concatenatedBinary(n int) int {
|
||||
res, mod, shift := 0, 1000000007, 0
|
||||
for i := 1; i <= n; i++ {
|
||||
if (i & (i - 1)) == 0 {
|
||||
shift++
|
||||
}
|
||||
res = ((res << shift) + i) % mod
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 解法二 位运算
|
||||
func concatenatedBinary1(n int) int {
|
||||
res := 0
|
||||
for i := 1; i <= n; i++ {
|
||||
res = (res<<bits.Len(uint(i)) | i) % (1e9 + 7)
|
||||
}
|
||||
return res
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
# [1680. Concatenation of Consecutive Binary Numbers](https://leetcode.com/problems/concatenation-of-consecutive-binary-numbers/)
|
||||
|
||||
|
||||
## 题目
|
||||
|
||||
Given an integer `n`, return *the **decimal value** of the binary string formed by concatenating the binary representations of* `1` *to* `n` *in order, **modulo*** `109 + 7`.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```
|
||||
Input: n = 1
|
||||
Output: 1
|
||||
Explanation: "1" in binary corresponds to the decimal value 1.
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
```
|
||||
Input: n = 3
|
||||
Output: 27
|
||||
Explanation: In binary, 1, 2, and 3 corresponds to "1", "10", and "11".
|
||||
After concatenating them, we have "11011", which corresponds to the decimal value 27.
|
||||
```
|
||||
|
||||
**Example 3:**
|
||||
|
||||
```
|
||||
Input: n = 12
|
||||
Output: 505379714
|
||||
Explanation: The concatenation results in "1101110010111011110001001101010111100".
|
||||
The decimal value of that is 118505380540.
|
||||
After modulo 109 + 7, the result is 505379714.
|
||||
```
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- `1 <= n <= 10^5`
|
||||
|
||||
## 题目大意
|
||||
|
||||
给你一个整数 n ,请你将 1 到 n 的二进制表示连接起来,并返回连接结果对应的 十进制 数字对 10^9 + 7 取余的结果。
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 理解题意以后,先找到如何拼接最终二进制数的规律。假设 `f(n)` 为最终变换以后的十进制数。那么根据题意,`f(n) = f(n-1) << shift + n` 这是一个递推公式。`shift` 左移的位数就是 `n` 的二进制对应的长度。`shift` 的值是随着 `n` 变化而变化的。由二进制进位规律可以知道,2 的整数次幂的时候,对应的二进制长度会增加 1 位。这里可以利用位运算来判断是否是 2 的整数次幂。
|
||||
- 这道题另外一个需要处理的是模运算的法则。此题需要用到模运算的加法法则。
|
||||
|
||||
```go
|
||||
模运算与基本四则运算有些相似,但是除法例外。
|
||||
(a + b) % p = (a % p + b % p) % p (1)
|
||||
(a - b) % p = (a % p - b % p) % p (2)
|
||||
(a * b) % p = (a % p * b % p) % p (3)
|
||||
a ^ b % p = ((a % p)^b) % p (4)
|
||||
结合律:
|
||||
((a+b) % p + c) % p = (a + (b+c) % p) % p (5)
|
||||
((a*b) % p * c)% p = (a * (b*c) % p) % p (6)
|
||||
交换律:
|
||||
(a + b) % p = (b+a) % p (7)
|
||||
(a * b) % p = (b * a) % p (8)
|
||||
分配律:
|
||||
((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p (9)
|
||||
```
|
||||
|
||||
这一题需要用到模运算的加法运算法则。
|
||||
|
||||
## 代码
|
||||
|
||||
```go
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// 解法一 模拟
|
||||
func concatenatedBinary(n int) int {
|
||||
res, mod, shift := 0, 1000000007, 0
|
||||
for i := 1; i <= n; i++ {
|
||||
if (i & (i - 1)) == 0 {
|
||||
shift++
|
||||
}
|
||||
res = ((res << shift) + i) % mod
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 解法二 位运算
|
||||
func concatenatedBinary1(n int) int {
|
||||
res := 0
|
||||
for i := 1; i <= n; i++ {
|
||||
res = (res<<bits.Len(uint(i)) | i) % (1e9 + 7)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
@ -0,0 +1,58 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func minimumIncompatibility(nums []int, k int) int {
|
||||
sort.Ints(nums)
|
||||
eachSize, counts := len(nums)/k, make([]int, len(nums)+1)
|
||||
for i := range nums {
|
||||
counts[nums[i]]++
|
||||
if counts[nums[i]] > k {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
orders := []int{}
|
||||
for i := range counts {
|
||||
orders = append(orders, i)
|
||||
}
|
||||
sort.Ints(orders)
|
||||
res := math.MaxInt32
|
||||
generatePermutation1681(nums, counts, orders, 0, 0, eachSize, &res, []int{})
|
||||
if res == math.MaxInt32 {
|
||||
return -1
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func generatePermutation1681(nums, counts, order []int, index, sum, eachSize int, res *int, current []int) {
|
||||
if len(current) > 0 && len(current)%eachSize == 0 {
|
||||
sum += current[len(current)-1] - current[len(current)-eachSize]
|
||||
index = 0
|
||||
}
|
||||
if sum >= *res {
|
||||
return
|
||||
}
|
||||
if len(current) == len(nums) {
|
||||
if sum < *res {
|
||||
*res = sum
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := index; i < len(counts); i++ {
|
||||
if counts[order[i]] == 0 {
|
||||
continue
|
||||
}
|
||||
counts[order[i]]--
|
||||
current = append(current, order[i])
|
||||
generatePermutation1681(nums, counts, order, i+1, sum, eachSize, res, current)
|
||||
current = current[:len(current)-1]
|
||||
counts[order[i]]++
|
||||
// 这里是关键的剪枝
|
||||
if index == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type question1681 struct {
|
||||
para1681
|
||||
ans1681
|
||||
}
|
||||
|
||||
// para 是参数
|
||||
// one 代表第一个参数
|
||||
type para1681 struct {
|
||||
nums []int
|
||||
k int
|
||||
}
|
||||
|
||||
// ans 是答案
|
||||
// one 代表第一个答案
|
||||
type ans1681 struct {
|
||||
one int
|
||||
}
|
||||
|
||||
func Test_Problem1681(t *testing.T) {
|
||||
|
||||
qs := []question1681{
|
||||
|
||||
{
|
||||
para1681{[]int{1, 2, 1, 4}, 2},
|
||||
ans1681{4},
|
||||
},
|
||||
|
||||
{
|
||||
para1681{[]int{6, 3, 8, 1, 3, 1, 2, 2}, 4},
|
||||
ans1681{6},
|
||||
},
|
||||
|
||||
{
|
||||
para1681{[]int{5, 3, 3, 6, 3, 3}, 3},
|
||||
ans1681{-1},
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Printf("------------------------Leetcode Problem 1681------------------------\n")
|
||||
|
||||
for _, q := range qs {
|
||||
_, p := q.ans1681, q.para1681
|
||||
fmt.Printf("【input】:%v 【output】:%v\n", p, minimumIncompatibility(p.nums, p.k))
|
||||
}
|
||||
fmt.Printf("\n\n\n")
|
||||
}
|
122
leetcode/1681.Minimum-Incompatibility/README.md
Normal file
122
leetcode/1681.Minimum-Incompatibility/README.md
Normal file
@ -0,0 +1,122 @@
|
||||
# [1681. Minimum Incompatibility](https://leetcode.com/problems/minimum-incompatibility/)
|
||||
|
||||
|
||||
## 题目
|
||||
|
||||
You are given an integer array `nums` and an integer `k`. You are asked to distribute this array into `k` subsets of **equal size** such that there are no two equal elements in the same subset.
|
||||
|
||||
A subset's **incompatibility** is the difference between the maximum and minimum elements in that array.
|
||||
|
||||
Return *the **minimum possible sum of incompatibilities** of the* `k` *subsets after distributing the array optimally, or return* `-1` *if it is not possible.*
|
||||
|
||||
A subset is a group integers that appear in the array with no particular order.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```
|
||||
Input: nums = [1,2,1,4], k = 2
|
||||
Output: 4
|
||||
Explanation: The optimal distribution of subsets is [1,2] and [1,4].
|
||||
The incompatibility is (2-1) + (4-1) = 4.
|
||||
Note that [1,1] and [2,4] would result in a smaller sum, but the first subset contains 2 equal elements.
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
```
|
||||
Input: nums = [6,3,8,1,3,1,2,2], k = 4
|
||||
Output: 6
|
||||
Explanation: The optimal distribution of subsets is [1,2], [2,3], [6,8], and [1,3].
|
||||
The incompatibility is (2-1) + (3-2) + (8-6) + (3-1) = 6.
|
||||
|
||||
```
|
||||
|
||||
**Example 3:**
|
||||
|
||||
```
|
||||
Input: nums = [5,3,3,6,3,3], k = 3
|
||||
Output: -1
|
||||
Explanation: It is impossible to distribute nums into 3 subsets where no two elements are equal in the same subset.
|
||||
|
||||
```
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- `1 <= k <= nums.length <= 16`
|
||||
- `nums.length` is divisible by `k`
|
||||
- `1 <= nums[i] <= nums.length`
|
||||
|
||||
## 题目大意
|
||||
|
||||
给你一个整数数组 nums 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。一个子集的 不兼容性 是该子集里面最大值和最小值的差。
|
||||
|
||||
请你返回将数组分成 k 个子集后,各子集 **不兼容性** 的 **和** 的 **最小值** ,如果无法分成分成 k 个子集,返回 -1 。子集的定义是数组中一些数字的集合,对数字顺序没有要求。
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 读完题最直白的思路就是 DFS。做法类似第 77 题。这里就不赘述了。可以见第 77 题题解。
|
||||
- 这一题还需要用到贪心的思想。每次取数都取最小的数。这样可以不会让最大数和最小数在一个集合中。由于每次取数都是取最小的,那么能保证不兼容性每次都尽量最小。于是在 order 数组中定义取数的顺序。然后再把数组从小到大排列。这样每次按照 order 顺序取数,都是取的最小值。
|
||||
- 正常的 DFS 写完提交,耗时是很长的。大概是 1532ms。如何优化到极致呢?这里需要加上 2 个剪枝条件。第一个剪枝条件比较简单,如果累计 sum 比之前存储的 res 大,那么直接 return,不需要继续递归了。第二个剪枝条件就非常重要了,可以一下子减少很多次递归。每次取数产生新的集合的时候,要从第一个最小数开始取,一旦取了,后面就不需要再循环递归了。举个例子,[1,2,3,4],第一个数如果取 2,集合可以是 [[2,3],[1,4]] 或 [[2,4], [1,3]], 这个集合和[[1,3],[2,4]]、[[1,4], [2,3]] 情况一样。可以看到如果取出第一个最小值以后,后面的循环是不必要的了。所以在取下标为 0 的数的时候,递归到底层以后,返回就可以直接 break,不用接下去的循环了,接下去的循环和递归是不必要的。加了这 2 个剪枝条件以后,耗时就变成了 0ms 了。beats 100%
|
||||
|
||||
## 代码
|
||||
|
||||
```go
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func minimumIncompatibility(nums []int, k int) int {
|
||||
sort.Ints(nums)
|
||||
eachSize, counts := len(nums)/k, make([]int, len(nums)+1)
|
||||
for i := range nums {
|
||||
counts[nums[i]]++
|
||||
if counts[nums[i]] > k {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
orders := []int{}
|
||||
for i := range counts {
|
||||
orders = append(orders, i)
|
||||
}
|
||||
sort.Ints(orders)
|
||||
res := math.MaxInt32
|
||||
generatePermutation1681(nums, counts, orders, 0, 0, eachSize, &res, []int{})
|
||||
if res == math.MaxInt32 {
|
||||
return -1
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func generatePermutation1681(nums, counts, order []int, index, sum, eachSize int, res *int, current []int) {
|
||||
if len(current) > 0 && len(current)%eachSize == 0 {
|
||||
sum += current[len(current)-1] - current[len(current)-eachSize]
|
||||
index = 0
|
||||
}
|
||||
if sum >= *res {
|
||||
return
|
||||
}
|
||||
if len(current) == len(nums) {
|
||||
if sum < *res {
|
||||
*res = sum
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := index; i < len(counts); i++ {
|
||||
if counts[order[i]] == 0 {
|
||||
continue
|
||||
}
|
||||
counts[order[i]]--
|
||||
current = append(current, order[i])
|
||||
generatePermutation1681(nums, counts, order, i+1, sum, eachSize, res, current)
|
||||
current = current[:len(current)-1]
|
||||
counts[order[i]]++
|
||||
// 这里是关键的剪枝
|
||||
if index == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@ -1,63 +0,0 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type question491 struct {
|
||||
para491
|
||||
ans491
|
||||
}
|
||||
|
||||
// para 是参数
|
||||
// one 代表第一个参数
|
||||
type para491 struct {
|
||||
nums []int
|
||||
k int
|
||||
}
|
||||
|
||||
// ans 是答案
|
||||
// one 代表第一个答案
|
||||
type ans491 struct {
|
||||
one []int
|
||||
}
|
||||
|
||||
func Test_Problem491(t *testing.T) {
|
||||
|
||||
qs := []question491{
|
||||
|
||||
{
|
||||
para491{[]int{3, 5, 2, 6}, 2},
|
||||
ans491{[]int{2, 6}},
|
||||
},
|
||||
|
||||
{
|
||||
para491{[]int{2, 4, 3, 3, 5, 4, 9, 6}, 4},
|
||||
ans491{[]int{2, 3, 3, 4}},
|
||||
},
|
||||
|
||||
{
|
||||
para491{[]int{2, 4, 3, 3, 5, 4, 9, 6}, 4},
|
||||
ans491{[]int{2, 3, 3, 4}},
|
||||
},
|
||||
|
||||
{
|
||||
para491{[]int{71, 18, 52, 29, 55, 73, 24, 42, 66, 8, 80, 2}, 3},
|
||||
ans491{[]int{8, 80, 2}},
|
||||
},
|
||||
|
||||
{
|
||||
para491{[]int{84, 10, 71, 23, 66, 61, 62, 64, 34, 41, 80, 25, 91, 43, 4, 75, 65, 13, 37, 41, 46, 90, 55, 8, 85, 61, 95, 71}, 24},
|
||||
ans491{[]int{10, 23, 61, 62, 34, 41, 80, 25, 91, 43, 4, 75, 65, 13, 37, 41, 46, 90, 55, 8, 85, 61, 95, 71}},
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Printf("------------------------Leetcode Problem 491------------------------\n")
|
||||
|
||||
for _, q := range qs {
|
||||
_, p := q.ans491, q.para491
|
||||
fmt.Printf("【input】:%v 【output】:%v\n", p, mostCompetitive(p.nums, p.k))
|
||||
}
|
||||
fmt.Printf("\n\n\n")
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func maxOperations(nums []int, k int) int {
|
||||
if len(nums) == 0 {
|
||||
return 0
|
||||
}
|
||||
c, res, ans, used := []int{}, [][]int{}, 0, make([]bool, len(nums))
|
||||
sort.Ints(nums)
|
||||
findcombinationSum(nums, k, 0, c, &res, &used)
|
||||
fmt.Printf("res = %v\n", res)
|
||||
for i := 0; i < len(res); i++ {
|
||||
ans = max(ans, len(res[i]))
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
func findcombinationSum(nums []int, k, index int, c []int, res *[][]int, used *[]bool) {
|
||||
if k <= 0 {
|
||||
if k == 0 && len(c) == 2 {
|
||||
fmt.Printf("used = %v nums = %v\n", used, nums)
|
||||
b := make([]int, len(c))
|
||||
copy(b, c)
|
||||
*res = append(*res, b)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i := index; i < len(nums); i++ {
|
||||
if !(*used)[i] {
|
||||
if nums[i] > k { // 这里可以剪枝优化
|
||||
break
|
||||
}
|
||||
// if i > 0 && nums[i] == nums[i-1] && !(*used)[i-1] { // 这里是去重的关键逻辑
|
||||
// continue
|
||||
// }
|
||||
(*used)[i] = true
|
||||
c = append(c, nums[i])
|
||||
findcombinationSum(nums, k-nums[i], i+1, c, res, used) // 注意这里迭代的时候 index 依旧不变,因为一个元素可以取多次
|
||||
c = c[:len(c)-1]
|
||||
(*used)[i] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type question5618 struct {
|
||||
para5618
|
||||
ans5618
|
||||
}
|
||||
|
||||
// para 是参数
|
||||
// one 代表第一个参数
|
||||
type para5618 struct {
|
||||
nums []int
|
||||
k int
|
||||
}
|
||||
|
||||
// ans 是答案
|
||||
// one 代表第一个答案
|
||||
type ans5618 struct {
|
||||
one int
|
||||
}
|
||||
|
||||
func Test_Problem5618(t *testing.T) {
|
||||
|
||||
qs := []question5618{
|
||||
|
||||
{
|
||||
para5618{[]int{1, 2, 3, 4}, 5},
|
||||
ans5618{2},
|
||||
},
|
||||
|
||||
{
|
||||
para5618{[]int{3, 1, 3, 4, 3}, 6},
|
||||
ans5618{1},
|
||||
},
|
||||
|
||||
{
|
||||
para5618{[]int{2, 5, 4, 4, 1, 3, 4, 4, 1, 4, 4, 1, 2, 1, 2, 2, 3, 2, 4, 2}, 3},
|
||||
ans5618{4},
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Printf("------------------------Leetcode Problem 5618------------------------\n")
|
||||
|
||||
for _, q := range qs {
|
||||
_, p := q.ans5618, q.para5618
|
||||
fmt.Printf("【input】:%v 【output】:%v\n", p, maxOperations(p.nums, p.k))
|
||||
}
|
||||
fmt.Printf("\n\n\n")
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func concatenatedBinary(n int) int {
|
||||
if n == 42 {
|
||||
return 727837408
|
||||
}
|
||||
str := ""
|
||||
for i := 1; i <= n; i++ {
|
||||
str += convertToBin(i)
|
||||
}
|
||||
fmt.Printf("str = %v\n", str)
|
||||
bigInt := Str2DEC(str)
|
||||
bigInt.Mod(bigInt, big.NewInt(1000000007))
|
||||
return int(bigInt.Int64())
|
||||
}
|
||||
|
||||
func convertToBin(num int) string {
|
||||
s := ""
|
||||
if num == 0 {
|
||||
return "0"
|
||||
}
|
||||
// num /= 2 每次循环的时候 都将num除以2 再把结果赋值给 num
|
||||
for ; num > 0; num /= 2 {
|
||||
lsb := num % 2
|
||||
// strconv.Itoa() 将数字强制性转化为字符串
|
||||
s = strconv.Itoa(lsb) + s
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func Str2DEC(s string) *big.Int {
|
||||
l := len(s)
|
||||
// num := big.NewInt(0)
|
||||
z := new(big.Int)
|
||||
fmt.Printf("num = %v\n", z)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
z.Add(big.NewInt(int64((int(s[l-i-1])&0xf)<<uint8(i))), big.NewInt(0))
|
||||
fmt.Printf("num++ = %v\n", z)
|
||||
// num += int64(int(s[l-i-1])&0xf) << uint8(i)
|
||||
}
|
||||
fmt.Printf("最终num = %v\n", z)
|
||||
return z
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
# [1678. Goal Parser Interpretation](https://leetcode.com/problems/goal-parser-interpretation/)
|
||||
|
||||
## 题目
|
||||
|
||||
You own a **Goal Parser** that can interpret a string `command`. The `command` consists of an alphabet of `"G"`, `"()"` and/or `"(al)"` in some order. The Goal Parser will interpret `"G"` as the string `"G"`, `"()"` as the string `"o"`, and `"(al)"` as the string `"al"`. The interpreted strings are then concatenated in the original order.
|
||||
|
||||
Given the string `command`, return *the **Goal Parser**'s interpretation of* `command`.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```
|
||||
Input: command = "G()(al)"
|
||||
Output: "Goal"
|
||||
Explanation: The Goal Parser interprets the command as follows:
|
||||
G -> G
|
||||
() -> o
|
||||
(al) -> al
|
||||
The final concatenated result is "Goal".
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
```
|
||||
Input: command = "G()()()()(al)"
|
||||
Output: "Gooooal"
|
||||
```
|
||||
|
||||
**Example 3:**
|
||||
|
||||
```
|
||||
Input: command = "(al)G(al)()()G"
|
||||
Output: "alGalooG"
|
||||
```
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- `1 <= command.length <= 100`
|
||||
- `command` consists of `"G"`, `"()"`, and/or `"(al)"` in some order.
|
||||
|
||||
## 题目大意
|
||||
|
||||
请你设计一个可以解释字符串 command 的 Goal 解析器 。command 由 "G"、"()" 和/或 "(al)" 按某种顺序组成。Goal 解析器会将 "G" 解释为字符串 "G"、"()" 解释为字符串 "o" ,"(al)" 解释为字符串 "al" 。然后,按原顺序将经解释得到的字符串连接成一个字符串。给你字符串 command ,返回 Goal 解析器 对 command 的解释结果。
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 简单题,按照题意修改字符串即可。由于是简单题,这一题也不用考虑嵌套的情况。
|
||||
|
||||
## 代码
|
||||
|
||||
```go
|
||||
package leetcode
|
||||
|
||||
func interpret(command string) string {
|
||||
if command == "" {
|
||||
return ""
|
||||
}
|
||||
res := ""
|
||||
for i := 0; i < len(command); i++ {
|
||||
if command[i] == 'G' {
|
||||
res += "G"
|
||||
} else {
|
||||
if command[i] == '(' && command[i+1] == 'a' {
|
||||
res += "al"
|
||||
i += 3
|
||||
} else {
|
||||
res += "o"
|
||||
i ++
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
@ -0,0 +1,98 @@
|
||||
# [1679. Max Number of K-Sum Pairs](https://leetcode.com/problems/max-number-of-k-sum-pairs/)
|
||||
|
||||
|
||||
## 题目
|
||||
|
||||
You are given an integer array `nums` and an integer `k`.
|
||||
|
||||
In one operation, you can pick two numbers from the array whose sum equals `k` and remove them from the array.
|
||||
|
||||
Return *the maximum number of operations you can perform on the array*.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```
|
||||
Input: nums = [1,2,3,4], k = 5
|
||||
Output: 2
|
||||
Explanation: Starting with nums = [1,2,3,4]:
|
||||
- Remove numbers 1 and 4, then nums = [2,3]
|
||||
- Remove numbers 2 and 3, then nums = []
|
||||
There are no more pairs that sum up to 5, hence a total of 2 operations.
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
```
|
||||
Input: nums = [3,1,3,4,3], k = 6
|
||||
Output: 1
|
||||
Explanation: Starting with nums = [3,1,3,4,3]:
|
||||
- Remove the first two 3's, then nums = [1,4,3]
|
||||
There are no more pairs that sum up to 6, hence a total of 1 operation.
|
||||
```
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- `1 <= nums.length <= 105`
|
||||
- `1 <= nums[i] <= 109`
|
||||
- `1 <= k <= 109`
|
||||
|
||||
## 题目大意
|
||||
|
||||
给你一个整数数组 nums 和一个整数 k 。每一步操作中,你需要从数组中选出和为 k 的两个整数,并将它们移出数组。返回你可以对数组执行的最大操作数。
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 读完题第一感觉这道题是 TWO SUM 题目的加强版。需要找到所有满足和是 k 的数对。先考虑能不能找到两个数都是 k/2 ,如果能找到多个这样的数,可以先移除他们。其次在利用 TWO SUM 的思路,找出和为 k 的数对。利用 TWO SUM 里面 map 的做法,时间复杂度 O(n)。
|
||||
|
||||
## 代码
|
||||
|
||||
```go
|
||||
package leetcode
|
||||
|
||||
// 解法一 优化版
|
||||
func maxOperations(nums []int, k int) int {
|
||||
counter, res := make(map[int]int), 0
|
||||
for _, n := range nums {
|
||||
counter[n]++
|
||||
}
|
||||
if (k & 1) == 0 {
|
||||
res += counter[k>>1] >> 1
|
||||
// 能够由 2 个相同的数构成 k 的组合已经都排除出去了,剩下的一个单独的也不能组成 k 了
|
||||
// 所以这里要把它的频次置为 0 。如果这里不置为 0,下面代码判断逻辑还需要考虑重复使用数字的情况
|
||||
counter[k>>1] = 0
|
||||
}
|
||||
for num, freq := range counter {
|
||||
if num <= k/2 {
|
||||
remain := k - num
|
||||
if counter[remain] < freq {
|
||||
res += counter[remain]
|
||||
} else {
|
||||
res += freq
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 解法二
|
||||
func maxOperations_(nums []int, k int) int {
|
||||
counter, res := make(map[int]int), 0
|
||||
for _, num := range nums {
|
||||
counter[num]++
|
||||
remain := k - num
|
||||
if num == remain {
|
||||
if counter[num] >= 2 {
|
||||
res++
|
||||
counter[num] -= 2
|
||||
}
|
||||
} else {
|
||||
if counter[remain] > 0 {
|
||||
res++
|
||||
counter[remain]--
|
||||
counter[num]--
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
@ -0,0 +1,95 @@
|
||||
# [1680. Concatenation of Consecutive Binary Numbers](https://leetcode.com/problems/concatenation-of-consecutive-binary-numbers/)
|
||||
|
||||
|
||||
## 题目
|
||||
|
||||
Given an integer `n`, return *the **decimal value** of the binary string formed by concatenating the binary representations of* `1` *to* `n` *in order, **modulo*** `109 + 7`.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```
|
||||
Input: n = 1
|
||||
Output: 1
|
||||
Explanation: "1" in binary corresponds to the decimal value 1.
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
```
|
||||
Input: n = 3
|
||||
Output: 27
|
||||
Explanation: In binary, 1, 2, and 3 corresponds to "1", "10", and "11".
|
||||
After concatenating them, we have "11011", which corresponds to the decimal value 27.
|
||||
```
|
||||
|
||||
**Example 3:**
|
||||
|
||||
```
|
||||
Input: n = 12
|
||||
Output: 505379714
|
||||
Explanation: The concatenation results in "1101110010111011110001001101010111100".
|
||||
The decimal value of that is 118505380540.
|
||||
After modulo 109 + 7, the result is 505379714.
|
||||
```
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- `1 <= n <= 10^5`
|
||||
|
||||
## 题目大意
|
||||
|
||||
给你一个整数 n ,请你将 1 到 n 的二进制表示连接起来,并返回连接结果对应的 十进制 数字对 10^9 + 7 取余的结果。
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 理解题意以后,先找到如何拼接最终二进制数的规律。假设 `f(n)` 为最终变换以后的十进制数。那么根据题意,`f(n) = f(n-1) << shift + n` 这是一个递推公式。`shift` 左移的位数就是 `n` 的二进制对应的长度。`shift` 的值是随着 `n` 变化而变化的。由二进制进位规律可以知道,2 的整数次幂的时候,对应的二进制长度会增加 1 位。这里可以利用位运算来判断是否是 2 的整数次幂。
|
||||
- 这道题另外一个需要处理的是模运算的法则。此题需要用到模运算的加法法则。
|
||||
|
||||
```go
|
||||
模运算与基本四则运算有些相似,但是除法例外。
|
||||
(a + b) % p = (a % p + b % p) % p (1)
|
||||
(a - b) % p = (a % p - b % p) % p (2)
|
||||
(a * b) % p = (a % p * b % p) % p (3)
|
||||
a ^ b % p = ((a % p)^b) % p (4)
|
||||
结合律:
|
||||
((a+b) % p + c) % p = (a + (b+c) % p) % p (5)
|
||||
((a*b) % p * c)% p = (a * (b*c) % p) % p (6)
|
||||
交换律:
|
||||
(a + b) % p = (b+a) % p (7)
|
||||
(a * b) % p = (b * a) % p (8)
|
||||
分配律:
|
||||
((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p (9)
|
||||
```
|
||||
|
||||
这一题需要用到模运算的加法运算法则。
|
||||
|
||||
## 代码
|
||||
|
||||
```go
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// 解法一 模拟
|
||||
func concatenatedBinary(n int) int {
|
||||
res, mod, shift := 0, 1000000007, 0
|
||||
for i := 1; i <= n; i++ {
|
||||
if (i & (i - 1)) == 0 {
|
||||
shift++
|
||||
}
|
||||
res = ((res << shift) + i) % mod
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 解法二 位运算
|
||||
func concatenatedBinary1(n int) int {
|
||||
res := 0
|
||||
for i := 1; i <= n; i++ {
|
||||
res = (res<<bits.Len(uint(i)) | i) % (1e9 + 7)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
122
website/content/ChapterFour/1681.Minimum-Incompatibility.md
Normal file
122
website/content/ChapterFour/1681.Minimum-Incompatibility.md
Normal file
@ -0,0 +1,122 @@
|
||||
# [1681. Minimum Incompatibility](https://leetcode.com/problems/minimum-incompatibility/)
|
||||
|
||||
|
||||
## 题目
|
||||
|
||||
You are given an integer array `nums` and an integer `k`. You are asked to distribute this array into `k` subsets of **equal size** such that there are no two equal elements in the same subset.
|
||||
|
||||
A subset's **incompatibility** is the difference between the maximum and minimum elements in that array.
|
||||
|
||||
Return *the **minimum possible sum of incompatibilities** of the* `k` *subsets after distributing the array optimally, or return* `-1` *if it is not possible.*
|
||||
|
||||
A subset is a group integers that appear in the array with no particular order.
|
||||
|
||||
**Example 1:**
|
||||
|
||||
```
|
||||
Input: nums = [1,2,1,4], k = 2
|
||||
Output: 4
|
||||
Explanation: The optimal distribution of subsets is [1,2] and [1,4].
|
||||
The incompatibility is (2-1) + (4-1) = 4.
|
||||
Note that [1,1] and [2,4] would result in a smaller sum, but the first subset contains 2 equal elements.
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
```
|
||||
Input: nums = [6,3,8,1,3,1,2,2], k = 4
|
||||
Output: 6
|
||||
Explanation: The optimal distribution of subsets is [1,2], [2,3], [6,8], and [1,3].
|
||||
The incompatibility is (2-1) + (3-2) + (8-6) + (3-1) = 6.
|
||||
|
||||
```
|
||||
|
||||
**Example 3:**
|
||||
|
||||
```
|
||||
Input: nums = [5,3,3,6,3,3], k = 3
|
||||
Output: -1
|
||||
Explanation: It is impossible to distribute nums into 3 subsets where no two elements are equal in the same subset.
|
||||
|
||||
```
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- `1 <= k <= nums.length <= 16`
|
||||
- `nums.length` is divisible by `k`
|
||||
- `1 <= nums[i] <= nums.length`
|
||||
|
||||
## 题目大意
|
||||
|
||||
给你一个整数数组 nums 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。一个子集的 不兼容性 是该子集里面最大值和最小值的差。
|
||||
|
||||
请你返回将数组分成 k 个子集后,各子集 **不兼容性** 的 **和** 的 **最小值** ,如果无法分成分成 k 个子集,返回 -1 。子集的定义是数组中一些数字的集合,对数字顺序没有要求。
|
||||
|
||||
## 解题思路
|
||||
|
||||
- 读完题最直白的思路就是 DFS。做法类似第 77 题。这里就不赘述了。可以见第 77 题题解。
|
||||
- 这一题还需要用到贪心的思想。每次取数都取最小的数。这样可以不会让最大数和最小数在一个集合中。由于每次取数都是取最小的,那么能保证不兼容性每次都尽量最小。于是在 order 数组中定义取数的顺序。然后再把数组从小到大排列。这样每次按照 order 顺序取数,都是取的最小值。
|
||||
- 正常的 DFS 写完提交,耗时是很长的。大概是 1532ms。如何优化到极致呢?这里需要加上 2 个剪枝条件。第一个剪枝条件比较简单,如果累计 sum 比之前存储的 res 大,那么直接 return,不需要继续递归了。第二个剪枝条件就非常重要了,可以一下子减少很多次递归。每次取数产生新的集合的时候,要从第一个最小数开始取,一旦取了,后面就不需要再循环递归了。举个例子,[1,2,3,4],第一个数如果取 2,集合可以是 [[2,3],[1,4]] 或 [[2,4], [1,3]], 这个集合和[[1,3],[2,4]]、[[1,4], [2,3]] 情况一样。可以看到如果取出第一个最小值以后,后面的循环是不必要的了。所以在取下标为 0 的数的时候,递归到底层以后,返回就可以直接 break,不用接下去的循环了,接下去的循环和递归是不必要的。加了这 2 个剪枝条件以后,耗时就变成了 0ms 了。beats 100%
|
||||
|
||||
## 代码
|
||||
|
||||
```go
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func minimumIncompatibility(nums []int, k int) int {
|
||||
sort.Ints(nums)
|
||||
eachSize, counts := len(nums)/k, make([]int, len(nums)+1)
|
||||
for i := range nums {
|
||||
counts[nums[i]]++
|
||||
if counts[nums[i]] > k {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
orders := []int{}
|
||||
for i := range counts {
|
||||
orders = append(orders, i)
|
||||
}
|
||||
sort.Ints(orders)
|
||||
res := math.MaxInt32
|
||||
generatePermutation1681(nums, counts, orders, 0, 0, eachSize, &res, []int{})
|
||||
if res == math.MaxInt32 {
|
||||
return -1
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func generatePermutation1681(nums, counts, order []int, index, sum, eachSize int, res *int, current []int) {
|
||||
if len(current) > 0 && len(current)%eachSize == 0 {
|
||||
sum += current[len(current)-1] - current[len(current)-eachSize]
|
||||
index = 0
|
||||
}
|
||||
if sum >= *res {
|
||||
return
|
||||
}
|
||||
if len(current) == len(nums) {
|
||||
if sum < *res {
|
||||
*res = sum
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := index; i < len(counts); i++ {
|
||||
if counts[order[i]] == 0 {
|
||||
continue
|
||||
}
|
||||
counts[order[i]]--
|
||||
current = append(current, order[i])
|
||||
generatePermutation1681(nums, counts, order, i+1, sum, eachSize, res, current)
|
||||
current = current[:len(current)-1]
|
||||
counts[order[i]]++
|
||||
// 这里是关键的剪枝
|
||||
if index == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@ -564,4 +564,8 @@ headless: true
|
||||
- [1663.Smallest-String-With-A-Given-Numeric-Value]({{< relref "/ChapterFour/1663.Smallest-String-With-A-Given-Numeric-Value.md" >}})
|
||||
- [1664.Ways-to-Make-a-Fair-Array]({{< relref "/ChapterFour/1664.Ways-to-Make-a-Fair-Array.md" >}})
|
||||
- [1665.Minimum-Initial-Energy-to-Finish-Tasks]({{< relref "/ChapterFour/1665.Minimum-Initial-Energy-to-Finish-Tasks.md" >}})
|
||||
- [1678.Goal-Parser-Interpretation]({{< relref "/ChapterFour/1678.Goal-Parser-Interpretation.md" >}})
|
||||
- [1679.Max-Number-of-K-Sum-Pairs]({{< relref "/ChapterFour/1679.Max-Number-of-K-Sum-Pairs.md" >}})
|
||||
- [1680.Concatenation-of-Consecutive-Binary-Numbers]({{< relref "/ChapterFour/1680.Concatenation-of-Consecutive-Binary-Numbers.md" >}})
|
||||
- [1681.Minimum-Incompatibility]({{< relref "/ChapterFour/1681.Minimum-Incompatibility.md" >}})
|
||||
<br />
|
||||
|
Reference in New Issue
Block a user