Add solution 0279、0518

This commit is contained in:
halfrost
2021-06-16 17:38:56 +08:00
parent 48cb642554
commit 5cf1b806b1
23 changed files with 507 additions and 44 deletions

View File

@ -0,0 +1,33 @@
package leetcode
import "math"
func numSquares(n int) int {
if isPerfectSquare(n) {
return 1
}
if checkAnswer4(n) {
return 4
}
for i := 1; i*i <= n; i++ {
j := n - i*i
if isPerfectSquare(j) {
return 2
}
}
return 3
}
// 判断是否为完全平方数
func isPerfectSquare(n int) bool {
sq := int(math.Floor(math.Sqrt(float64(n))))
return sq*sq == n
}
// 判断是否能表示为 4^k*(8m+7)
func checkAnswer4(x int) bool {
for x%4 == 0 {
x /= 4
}
return x%8 == 7
}

View File

@ -0,0 +1,46 @@
package leetcode
import (
"fmt"
"testing"
)
type question279 struct {
para279
ans279
}
// para 是参数
// one 代表第一个参数
type para279 struct {
n int
}
// ans 是答案
// one 代表第一个答案
type ans279 struct {
one int
}
func Test_Problem279(t *testing.T) {
qs := []question279{
{
para279{13},
ans279{2},
},
{
para279{12},
ans279{3},
},
}
fmt.Printf("------------------------Leetcode Problem 279------------------------\n")
for _, q := range qs {
_, p := q.ans279, q.para279
fmt.Printf("【input】:%v 【output】:%v\n", p, numSquares(p.n))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,78 @@
# [279. Perfect Squares](https://leetcode.com/problems/perfect-squares/)
## 题目
Given an integer `n`, return *the least number of perfect square numbers that sum to* `n`.
A **perfect square** is an integer that is the square of an integer; in other words, it is the product of some integer with itself. For example, `1`, `4`, `9`, and `16` are perfect squares while `3` and `11` are not.
**Example 1:**
```
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
```
**Example 2:**
```
Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.
```
**Constraints:**
- `1 <= n <= 104`
## 题目大意
给定正整数 n找到若干个完全平方数比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数其值等于另一个整数的平方换句话说其值等于一个整数自乘的积。例如1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
## 解题思路
- 由拉格朗日的四平方定理可得,每个自然数都可以表示为四个整数平方之和。 其中四个数字是整数。四平方和定理证明了任意一个正整数都可以被表示为至多四个正整数的平方和。这给出了本题的答案的上界。
- 四平方和定理可以推出三平方和推论:当且仅当 {{< katex >}} n \neq 4^{k} \times (8*m + 7){{< /katex >}} 时n 可以被表示为至多三个正整数的平方和。所以当 {{< katex >}} n = 4^{k} * (8*m + 7){{< /katex >}} 时n 只能被表示为四个正整数的平方和。此时我们可以直接返回 4。
- 当 {{< katex >}} n \neq 4^{k} \times (8*m + 7){{< /katex >}} 时,需要判断 n 到底可以分解成几个完全平方数之和。答案肯定是 123 中的一个。题目要求我们求最小的,所以从 1 开始一个个判断是否满足。如果答案为 1代表 n 为完全平方数,这很好判断。如果答案为 2代表 {{< katex >}} n = a^{2} + b^{2} {{< /katex >}},枚举 {{< katex >}} 1 \leqslant a \leqslant \sqrt{n} {{< /katex >}},判断 {{< katex >}} n - a^{2} {{< /katex >}} 是否为完全平方数。当 1 和 2 都排除了,剩下的答案只能为 3 了。
## 代码
```go
package leetcode
import "math"
func numSquares(n int) int {
if isPerfectSquare(n) {
return 1
}
if checkAnswer4(n) {
return 4
}
for i := 1; i*i <= n; i++ {
j := n - i*i
if isPerfectSquare(j) {
return 2
}
}
return 3
}
// 判断是否为完全平方数
func isPerfectSquare(n int) bool {
sq := int(math.Floor(math.Sqrt(float64(n))))
return sq*sq == n
}
// 判断是否能表示为 4^k*(8m+7)
func checkAnswer4(x int) bool {
for x%4 == 0 {
x /= 4
}
return x%8 == 7
}
```

View File

@ -0,0 +1,12 @@
package leetcode
func change(amount int, coins []int) int {
dp := make([]int, amount+1)
dp[0] = 1
for _, coin := range coins {
for i := coin; i <= amount; i++ {
dp[i] += dp[i-coin]
}
}
return dp[amount]
}

View File

@ -0,0 +1,53 @@
package leetcode
import (
"fmt"
"testing"
)
type question518 struct {
para518
ans518
}
// para 是参数
// one 代表第一个参数
type para518 struct {
amount int
coins []int
}
// ans 是答案
// one 代表第一个答案
type ans518 struct {
one int
}
func Test_Problem518(t *testing.T) {
qs := []question518{
{
para518{5, []int{1, 2, 5}},
ans518{4},
},
{
para518{3, []int{2}},
ans518{0},
},
{
para518{10, []int{10}},
ans518{1},
},
}
fmt.Printf("------------------------Leetcode Problem 518------------------------\n")
for _, q := range qs {
_, p := q.ans518, q.para518
fmt.Printf("【input】:%v 【output】:%v\n", p, change(p.amount, p.coins))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,73 @@
# [518. Coin Change 2](https://leetcode.com/problems/coin-change-2/)
## 题目
You are given an integer array `coins` representing coins of different denominations and an integer `amount` representing a total amount of money.
Return *the number of combinations that make up that amount*. If that amount of money cannot be made up by any combination of the coins, return `0`.
You may assume that you have an infinite number of each kind of coin.
The answer is **guaranteed** to fit into a signed **32-bit** integer.
**Example 1:**
```
Input: amount = 5, coins = [1,2,5]
Output: 4
Explanation: there are four ways to make up the amount:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
```
**Example 2:**
```
Input: amount = 3, coins = [2]
Output: 0
Explanation: the amount of 3 cannot be made up just with coins of 2.
```
**Example 3:**
```
Input: amount = 10, coins = [10]
Output: 1
```
**Constraints:**
- `1 <= coins.length <= 300`
- `1 <= coins[i] <= 5000`
- All the values of `coins` are **unique**.
- `0 <= amount <= 5000`
## 题目大意
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。假设每一种面额的硬币有无限个。题目数据保证结果符合 32 位带符号整数。
## 解题思路
- 此题虽然名字叫 Coin Change但是不是经典的背包九讲问题。题目中 coins 的每个元素可以选取多次,且不考虑选取元素的顺序,因此这道题实际需要计算的是选取硬币的组合数。定义 dp[i] 表示金额之和等于 i 的硬币组合数,目标求 dp[amount]。初始边界条件为 dp[0] = 1即不取任何硬币就这一种取法金额为 0 。状态转移方程 dp[i] += dp[i-coin]coin 为当前枚举的 coin。
- 可能有读者会有疑惑,上述做法会不会出现重复计算。答案是不会。外层循环是遍历数组 coins 的值,内层循环是遍历不同的金额之和,在计算 dp[i] 的值时,可以确保金额之和等于 i 的硬币面额的顺序,由于顺序确定,因此不会重复计算不同的排列。
- 和此题完全一致的解题思路的题有,第 377 题和第 494 题。
## 代码
```go
package leetcode
func change(amount int, coins []int) int {
dp := make([]int, amount+1)
dp[0] = 1
for _, coin := range coins {
for i := coin; i <= amount; i++ {
dp[i] += dp[i-coin]
}
}
return dp[amount]
}
```