Add solution 0368、0377、0696

This commit is contained in:
YDZ
2021-04-24 21:04:28 +08:00
parent 1cdbefdc9c
commit 45fb40ee7f
38 changed files with 1371 additions and 665 deletions

View File

@ -0,0 +1,33 @@
package leetcode
import "sort"
func largestDivisibleSubset(nums []int) []int {
sort.Ints(nums)
dp, res := make([]int, len(nums)), []int{}
for i := range dp {
dp[i] = 1
}
maxSize, maxVal := 1, 1
for i := 1; i < len(nums); i++ {
for j, v := range nums[:i] {
if nums[i]%v == 0 && dp[j]+1 > dp[i] {
dp[i] = dp[j] + 1
}
}
if dp[i] > maxSize {
maxSize, maxVal = dp[i], nums[i]
}
}
if maxSize == 1 {
return []int{nums[0]}
}
for i := len(nums) - 1; i >= 0 && maxSize > 0; i-- {
if dp[i] == maxSize && maxVal%nums[i] == 0 {
res = append(res, nums[i])
maxVal = nums[i]
maxSize--
}
}
return res
}

View File

@ -0,0 +1,47 @@
package leetcode
import (
"fmt"
"testing"
)
type question368 struct {
para368
ans368
}
// para 是参数
// one 代表第一个参数
type para368 struct {
one []int
}
// ans 是答案
// one 代表第一个答案
type ans368 struct {
one []int
}
func Test_Problem368(t *testing.T) {
qs := []question368{
{
para368{[]int{1, 2, 3}},
ans368{[]int{1, 2}},
},
{
para368{[]int{1, 2, 4, 8}},
ans368{[]int{1, 2, 4, 8}},
},
}
fmt.Printf("------------------------Leetcode Problem 368------------------------\n")
for _, q := range qs {
_, p := q.ans368, q.para368
fmt.Printf("【input】:%v 【output】:%v\n", p, largestDivisibleSubset(p.one))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,86 @@
# [368. Largest Divisible Subset](https://leetcode.com/problems/largest-divisible-subset/)
## 题目
Given a set of **distinct** positive integers `nums`, return the largest subset `answer` such that every pair `(answer[i], answer[j])` of elements in this subset satisfies:
- `answer[i] % answer[j] == 0`, or
- `answer[j] % answer[i] == 0`
If there are multiple solutions, return any of them.
**Example 1:**
```
Input: nums = [1,2,3]
Output: [1,2]
Explanation: [1,3] is also accepted.
```
**Example 2:**
```
Input: nums = [1,2,4,8]
Output: [1,2,4,8]
```
**Constraints:**
- `1 <= nums.length <= 1000`
- `1 <= nums[i] <= 2 * 109`
- All the integers in `nums` are **unique**.
## 题目大意
给你一个由 无重复 正整数组成的集合 nums ,请你找出并返回其中最大的整除子集 answer ,子集中每一元素对 (answer[i], answer[j]) 都应当满足:
- answer[i] % answer[j] == 0 ,或
- answer[j] % answer[i] == 0
如果存在多个有效解子集,返回其中任何一个均可。
## 解题思路
- 根据题目数据规模 1000可以估计此题大概率是动态规划并且时间复杂度是 O(n^2)。先将集合排序,以某一个小的数作为基准,不断的选择能整除的数加入集合。按照这个思路考虑,此题和第 300 题经典的 LIS 解题思路一致。只不过 LIS 每次选择更大的数,此题除了选择更大的数,只不过多了一个判断,这个更大的数能否整除当前集合里面的所有元素。按照此法一定可以找出最大的集合。
- 剩下的问题是如何输出最大集合。这道题的集合具有重叠子集的性质,例如 [2,4,8,16] 这个集合,长度是 4它一定包含长度为 3 的子集,因为从它里面随便取 3 个数形成的子集也满足元素相互能整除的条件。同理,它也一定包含长度为 2长度为 1 的子集。由于有这个性质,可以利用 dp 数组里面的数据,输出最大集合。例如,[2,4,6,8,9,13,16,40],由动态规划可以找到最大集合是 [2,4,8,16]。长度为 4 的找到了,再找长度为 3 的,[2,4,8][2,4,40]。在最大集合中,最大元素是 16所以 [2,4,40] 这个集合排除,它的最大元素大于 16。选定 [2,4,8] 这个集合,此时最大元素是 8 。以此类推,筛选到最后,便可以输出 [16,8,4,2] 这个组最大集合的答案了。
## 代码
```go
package leetcode
import "sort"
func largestDivisibleSubset(nums []int) []int {
sort.Ints(nums)
dp, res := make([]int, len(nums)), []int{}
for i := range dp {
dp[i] = 1
}
maxSize, maxVal := 1, 1
for i := 1; i < len(nums); i++ {
for j, v := range nums[:i] {
if nums[i]%v == 0 && dp[j]+1 > dp[i] {
dp[i] = dp[j] + 1
}
}
if dp[i] > maxSize {
maxSize, maxVal = dp[i], nums[i]
}
}
if maxSize == 1 {
return []int{nums[0]}
}
for i := len(nums) - 1; i >= 0 && maxSize > 0; i-- {
if dp[i] == maxSize && maxVal%nums[i] == 0 {
res = append(res, nums[i])
maxVal = nums[i]
maxSize--
}
}
return res
}
```

View File

@ -1,6 +1,20 @@
package leetcode
func combinationSum4(nums []int, target int) int {
dp := make([]int, target+1)
dp[0] = 1
for i := 1; i <= target; i++ {
for _, num := range nums {
if i-num >= 0 {
dp[i] += dp[i-num]
}
}
}
return dp[target]
}
// 暴力解法超时
func combinationSum41(nums []int, target int) int {
if len(nums) == 0 {
return 0
}

View File

@ -34,7 +34,7 @@ func Test_Problem377(t *testing.T) {
{
para377{[]int{1, 2, 3}, 32},
ans377{7},
ans377{181997601},
},
}

View File

@ -0,0 +1,98 @@
# [377. Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/)
## 题目
Given an array of **distinct** integers `nums` and a target integer `target`, return *the number of possible combinations that add up to* `target`.
The answer is **guaranteed** to fit in a **32-bit** integer.
**Example 1:**
```
Input: nums = [1,2,3], target = 4
Output: 7
Explanation:
The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
Note that different sequences are counted as different combinations.
```
**Example 2:**
```
Input: nums = [9], target = 3
Output: 0
```
**Constraints:**
- `1 <= nums.length <= 200`
- `1 <= nums[i] <= 1000`
- All the elements of `nums` are **unique**.
- `1 <= target <= 1000`
**Follow up:** What if negative numbers are allowed in the given array? How does it change the problem? What limitation we need to add to the question to allow negative numbers?
## 题目大意
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。题目数据保证答案符合 32 位整数范围。
## 解题思路
- Combination Sum 这是系列问题。拿到题目,笔者先用暴力解法 dfs 尝试了一版,包含的重叠子问题特别多,剪枝条件也没有写好,果然超时。元素只有 [1,2,3] 这三种target = 32这组数据居然有 181997601 这么多种情况。仔细看了题目数据规模 1000基本可以断定此题是动态规划并且时间复杂度是 O(n^2)。
- 本题和完全背包有点像,但是还是有区别。完全背包的取法内部不区分顺序。例如 5 = 1 + 2 + 2。但是本题是 3 种答案 (122)(212)(221)。定义 dp[i] 为总和为 target = i 的组合总数。最终答案存在 dp[target] 中。状态转移方程为:
$$dp[i] =\left\{\begin{matrix}1,i=0\\ \sum dp[i-j],i\neq 0\end{matrix}\right.$$
- 这道题最后有一个进阶问题。如果给定的数组中含有负数,则会导致出现无限长度的排列。例如,假设数组 nums 中含有正整数 a 和负整数 b其中 a>0,b>0,-b<0则有 a×b+(b)×a=0对于任意一个元素之和等于 target 的排列在该排列的后面添加 b a a b 之后得到的新排列的元素之和仍然等于 target而且还可以在新排列的后面继续 b a a b因此只要存在元素之和等于 target 的排列就能构造出无限长度的排列如果允许负数出现则必须限制排列的最大长度不然会出现无限长度的排列
## 代码
```go
package leetcode
func combinationSum4(nums []int, target int) int {
dp := make([]int, target+1)
dp[0] = 1
for i := 1; i <= target; i++ {
for _, num := range nums {
if i-num >= 0 {
dp[i] += dp[i-num]
}
}
}
return dp[target]
}
// 暴力解法超时
func combinationSum41(nums []int, target int) int {
if len(nums) == 0 {
return 0
}
c, res := []int{}, 0
findcombinationSum4(nums, target, 0, c, &res)
return res
}
func findcombinationSum4(nums []int, target, index int, c []int, res *int) {
if target <= 0 {
if target == 0 {
*res++
}
return
}
for i := 0; i < len(nums); i++ {
c = append(c, nums[i])
findcombinationSum4(nums, target-nums[i], i, c, res)
c = c[:len(c)-1]
}
}
```

View File

@ -0,0 +1,21 @@
package leetcode
func countBinarySubstrings(s string) int {
last, res := 0, 0
for i := 0; i < len(s); {
c, count := s[i], 1
for i++; i < len(s) && s[i] == c; i++ {
count++
}
res += min(count, last)
last = count
}
return res
}
func min(a, b int) int {
if a < b {
return a
}
return b
}

View File

@ -0,0 +1,57 @@
package leetcode
import (
"fmt"
"testing"
)
type question696 struct {
para696
ans696
}
// para 是参数
// one 代表第一个参数
type para696 struct {
one string
}
// ans 是答案
// one 代表第一个答案
type ans696 struct {
one int
}
func Test_Problem696(t *testing.T) {
qs := []question696{
{
para696{"00110011"},
ans696{6},
},
{
para696{"10101"},
ans696{4},
},
{
para696{"0110001111"},
ans696{6},
},
{
para696{"0001111"},
ans696{3},
},
}
fmt.Printf("------------------------Leetcode Problem 696------------------------\n")
for _, q := range qs {
_, p := q.ans696, q.para696
fmt.Printf("【input】:%v 【output】:%v\n", p, countBinarySubstrings(p.one))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,69 @@
# [696. Count Binary Substrings](https://leetcode.com/problems/count-binary-substrings/)
## 题目
Give a string `s`, count the number of non-empty (contiguous) substrings that have the same number of 0's and 1's, and all the 0's and all the 1's in these substrings are grouped consecutively.
Substrings that occur multiple times are counted the number of times they occur.
**Example 1:**
```
Input: "00110011"
Output: 6
Explanation: There are 6 substrings that have equal number of consecutive 1's and 0's: "0011", "01", "1100", "10", "0011", and "01".
Notice that some of these substrings repeat and are counted the number of times they occur.
Also, "00110011" is not a valid substring becauseall the 0's (and 1's) are not grouped together.
```
**Example 2:**
```
Input: "10101"
Output: 4
Explanation: There are 4 substrings: "10", "01", "10", "01" that have equal number of consecutive 1's and 0's.
```
**Note:**
- `s.length` will be between 1 and 50,000.
- `s` will only consist of "0" or "1" characters.
## 题目大意
给定一个字符串 s计算具有相同数量 0 和 1 的非空(连续)子字符串的数量,并且这些子字符串中的所有 0 和所有 1 都是连续的。重复出现的子串要计算它们出现的次数。
## 解题思路
- 简单题。先分组统计 0 和 1 的个数,例如,`0110001111` 按照 0 和 1 分组统计出来的结果是 [1, 2, 3, 4]。再拼凑结果。相邻 2 组取两者最短的,例如 `0110001111`,凑成的结果应该是 min(1,2)min(2,3)min(3,4),即 `01``01``10``1100``0011``000111`。时间复杂度 O(n),空间复杂度 O(1)。
## 代码
```go
package leetcode
func countBinarySubstrings(s string) int {
last, res := 0, 0
for i := 0; i < len(s); {
c, count := s[i], 1
for i++; i < len(s) && s[i] == c; i++ {
count++
}
res += min(count, last)
last = count
}
return res
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
```