Add Weekly Contest 218

This commit is contained in:
YDZ
2020-12-14 20:20:08 +08:00
parent 3881a5a214
commit 7c6a8bd33d
21 changed files with 1076 additions and 222 deletions

View File

@ -14,7 +14,7 @@ func interpret(command string) string {
i += 3
} else {
res += "o"
i += 1
i++
}
}
}

View File

@ -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")
}

View 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
}
```

View File

@ -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
}

View File

@ -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")
}

View 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
}
```

View File

@ -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
}

View File

@ -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
}
```

View File

@ -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
}
}
}

View File

@ -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")
}

View 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
}
}
}
```

View File

@ -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")
}

View File

@ -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
}
}

View File

@ -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")
}

View File

@ -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
}

View 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
}
```

View 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
}
```

View File

@ -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
}
```

View 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
}
}
}
```

View File

@ -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 />