Add solution 0031、0987、1675

This commit is contained in:
YDZ
2021-02-13 03:18:06 +08:00
parent 0881edff66
commit 5e1c45cb84
35 changed files with 1205 additions and 219 deletions

View File

@ -0,0 +1,31 @@
package leetcode
func nextPermutation(nums []int) {
i, j := 0, 0
for i = len(nums) - 2; i >= 0; i-- {
if nums[i] < nums[i+1] {
break
}
}
if i >= 0 {
for j = len(nums) - 1; j > i; j-- {
if nums[j] > nums[i] {
break
}
}
swap(&nums, i, j)
}
reverse(&nums, i+1, len(nums)-1)
}
func reverse(nums *[]int, i, j int) {
for i < j {
swap(nums, i, j)
i++
j--
}
}
func swap(nums *[]int, i, j int) {
(*nums)[i], (*nums)[j] = (*nums)[j], (*nums)[i]
}

View File

@ -0,0 +1,58 @@
package leetcode
import (
"fmt"
"testing"
)
type question31 struct {
para31
ans31
}
// para 是参数
// one 代表第一个参数
type para31 struct {
nums []int
}
// ans 是答案
// one 代表第一个答案
type ans31 struct {
one []int
}
func Test_Problem31(t *testing.T) {
qs := []question31{
{
para31{[]int{1, 2, 3}},
ans31{[]int{1, 3, 2}},
},
{
para31{[]int{3, 2, 1}},
ans31{[]int{1, 2, 3}},
},
{
para31{[]int{1, 1, 5}},
ans31{[]int{1, 5, 1}},
},
{
para31{[]int{1}},
ans31{[]int{1}},
},
}
fmt.Printf("------------------------Leetcode Problem 31------------------------\n")
for _, q := range qs {
_, p := q.ans31, q.para31
fmt.Printf("【input】:%v ", p)
nextPermutation(p.nums)
fmt.Printf("【output】:%v\n", p.nums)
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,89 @@
# [31. Next Permutation](https://leetcode.com/problems/next-permutation/)
## 题目
Implement **next permutation**, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such an arrangement is not possible, it must rearrange it as the lowest possible order (i.e., sorted in ascending order).
The replacement must be **[in place](http://en.wikipedia.org/wiki/In-place_algorithm)** and use only constant extra memory.
**Example 1:**
```
Input: nums = [1,2,3]
Output: [1,3,2]
```
**Example 2:**
```
Input: nums = [3,2,1]
Output: [1,2,3]
```
**Example 3:**
```
Input: nums = [1,1,5]
Output: [1,5,1]
```
**Example 4:**
```
Input: nums = [1]
Output: [1]
```
**Constraints:**
- `1 <= nums.length <= 100`
- `0 <= nums[i] <= 100`
## 题目大意
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。必须 原地 修改,只允许使用额外常数空间。
## 解题思路
- 题目有 3 个问题需要解决。如何找到下一个排列。不存在下一个排列的时候如何生成最小的排列。如何原地修改。先解决第一个问题,如何找到下一个排列。下一个排列是找到一个大于当前排序的字典序,且变大的幅度最小。那么只能将较小的数与较大数做一次原地交换。并且较小数的下标要尽量靠右,较大数也要尽可能小。原地交换以后,还需要将较大数右边的数按照升序重新排列。这样交换以后,才能生成下一个排列。以排列 [8,9,6,10,7,2] 为例:能找到的符合条件的一对「较小数」与「较大数」的组合为 6 与 7满足「较小数」尽量靠右而「较大数」尽可能小。当完成交换后排列变为 [8,9,7,10,6,2],此时我们可以重排「较小数」右边的序列,序列变为 [8,9,7,2,6,10]。
- 第一步:在 `nums[i]` 中找到 `i` 使得 `nums[i] < nums[i+1]`,此时较小数为 `nums[i]`,并且 `[i+1, n)` 一定为下降区间。第二步:如果找到了这样的 `i` ,则在下降区间 `[i+1, n)` 中从后往前找到第一个 `j` ,使得 `nums[i] < nums[j]` ,此时较大数为 `nums[j]`。第三步,交换 `nums[i]``nums[j]`,此时区间 `[i+1, n)` 一定为降序区间。最后原地交换 `[i+1, n)` 区间内的元素,使其变为升序,无需对该区间进行排序。
- 如果第一步找不到符合条件的下标 `i`,说明当前序列已经是一个最大的排列。那么应该直接执行第三步,生成最小的排列。
## 代码
```go
package leetcode
func nextPermutation(nums []int) {
i, j := 0, 0
for i = len(nums) - 2; i >= 0; i-- {
if nums[i] < nums[i+1] {
break
}
}
if i >= 0 {
for j = len(nums) - 1; j > i; j-- {
if nums[j] > nums[i] {
break
}
}
swap(&nums, i, j)
}
reverse(&nums, i+1, len(nums)-1)
}
func reverse(nums *[]int, i, j int) {
for i < j {
swap(nums, i, j)
i++
j--
}
}
func swap(nums *[]int, i, j int) {
(*nums)[i], (*nums)[j] = (*nums)[j], (*nums)[i]
}
```

View File

@ -0,0 +1,59 @@
package leetcode
import (
"sort"
"github.com/halfrost/LeetCode-Go/structures"
)
// TreeNode define
type TreeNode = structures.TreeNode
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
type node struct {
x, y, val int
}
func verticalTraversal(root *TreeNode) [][]int {
nodes := []*node{}
inorder(root, 0, 0, &nodes)
sort.Slice(nodes, func(i, j int) bool {
if nodes[i].y == nodes[j].y {
if nodes[i].x < nodes[j].x {
return true
} else if nodes[i].x > nodes[j].x {
return false
}
return nodes[i].val < nodes[j].val
}
return nodes[i].y < nodes[j].y
})
res, currY, currColumn := [][]int{}, nodes[0].y, []int{nodes[0].val}
for i := 1; i < len(nodes); i++ {
if currY == nodes[i].y {
currColumn = append(currColumn, nodes[i].val)
} else {
res = append(res, currColumn)
currColumn = []int{nodes[i].val}
currY = nodes[i].y
}
}
res = append(res, currColumn)
return res
}
func inorder(root *TreeNode, x, y int, nodes *[]*node) {
if root != nil {
*nodes = append(*nodes, &node{x, y, root.Val})
inorder(root.Left, x+1, y-1, nodes)
inorder(root.Right, x+1, y+1, nodes)
}
}

View File

@ -0,0 +1,56 @@
package leetcode
import (
"fmt"
"testing"
"github.com/halfrost/LeetCode-Go/structures"
)
type question987 struct {
para987
ans987
}
// para 是参数
// one 代表第一个参数
type para987 struct {
one []int
}
// ans 是答案
// one 代表第一个答案
type ans987 struct {
one [][]int
}
func Test_Problem987(t *testing.T) {
qs := []question987{
{
para987{[]int{3, 9, 20, structures.NULL, structures.NULL, 15, 7}},
ans987{[][]int{{9}, {3, 15}, {20}, {7}}},
},
{
para987{[]int{1, 2, 3, 4, 5, 6, 7}},
ans987{[][]int{{4}, {2}, {1, 5, 6}, {3}, {7}}},
},
{
para987{[]int{1, 2, 3, 4, 6, 5, 7}},
ans987{[][]int{{4}, {2}, {1, 5, 6}, {3}, {7}}},
},
}
fmt.Printf("------------------------Leetcode Problem 987------------------------\n")
for _, q := range qs {
_, p := q.ans987, q.para987
fmt.Printf("【input】:%v ", p)
root := structures.Ints2TreeNode(p.one)
fmt.Printf("【output】:%v \n", verticalTraversal(root))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,138 @@
# [987. Vertical Order Traversal of a Binary Tree](https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/)
## 题目
Given the `root` of a binary tree, calculate the **vertical order traversal** of the binary tree.
For each node at position `(row, col)`, its left and right children will be at positions `(row + 1, col - 1)` and `(row + 1, col + 1)` respectively. The root of the tree is at `(0, 0)`.
The **vertical order traversal** of a binary tree is a list of top-to-bottom orderings for each column index starting from the leftmost column and ending on the rightmost column. There may be multiple nodes in the same row and same column. In such a case, sort these nodes by their values.
Return *the **vertical order traversal** of the binary tree*.
**Example 1:**
![https://assets.leetcode.com/uploads/2021/01/29/vtree1.jpg](https://assets.leetcode.com/uploads/2021/01/29/vtree1.jpg)
```
Input: root = [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]
Explanation:
Column -1: Only node 9 is in this column.
Column 0: Nodes 3 and 15 are in this column in that order from top to bottom.
Column 1: Only node 20 is in this column.
Column 2: Only node 7 is in this column.
```
**Example 2:**
![https://assets.leetcode.com/uploads/2021/01/29/vtree2.jpg](https://assets.leetcode.com/uploads/2021/01/29/vtree2.jpg)
```
Input: root = [1,2,3,4,5,6,7]
Output: [[4],[2],[1,5,6],[3],[7]]
Explanation:
Column -2: Only node 4 is in this column.
Column -1: Only node 2 is in this column.
Column 0: Nodes 1, 5, and 6 are in this column.
1 is at the top, so it comes first.
5 and 6 are at the same position (2, 0), so we order them by their value, 5 before 6.
Column 1: Only node 3 is in this column.
Column 2: Only node 7 is in this column.
```
**Example 3:**
![https://assets.leetcode.com/uploads/2021/01/29/vtree3.jpg](https://assets.leetcode.com/uploads/2021/01/29/vtree3.jpg)
```
Input: root = [1,2,3,4,6,5,7]
Output: [[4],[2],[1,5,6],[3],[7]]
Explanation:
This case is the exact same as example 2, but with nodes 5 and 6 swapped.
Note that the solution remains the same since 5 and 6 are in the same location and should be ordered by their values.
```
**Constraints:**
- The number of nodes in the tree is in the range `[1, 1000]`.
- `0 <= Node.val <= 1000`
## 题目大意
给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。
对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row + 1, col - 1) 和 (row + 1, col + 1) 。树的根结点位于 (0, 0) 。二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。返回二叉树的 垂序遍历 序列。
## 解题思路
- 题目要求按照一列一列的遍历二叉树。需要解决 2 个问题。第一个问题,二叉树上每个结点的二维坐标如何计算。第二个问题,同一个二维坐标点上摞起来多个结点,需要按照从小到大的顺序排序,如例子二和例子三,同一个二维坐标点 (20) 上,摞了 2 个不同的结点。
- 先解决第一个问题,由于题目要求根结点是 (00) ,即根结点是坐标原点,它的左子树的 x 坐标都是负数,它的右子树的 x 坐标都是正数。按照先序遍历,就可以将这些结点的二维坐标计算出来。再进行一次排序,按照 x 坐标从小到大排序,坐标相同的情况对应着结点摞起来的情况,摞起来的结点按照 val 值的大小从小到大排序。这样在 x 轴方向,所有结点就排列好了。排序完成,也顺便解决了第二个问题。
- 最后一步只需要扫描一遍这个排好序的数组,按照列的顺序,依次将同一列的结点打包至一个一维数组中。最终输出的二维数组即为题目所求。
## 代码
```go
package leetcode
import (
"sort"
"github.com/halfrost/LeetCode-Go/structures"
)
// TreeNode define
type TreeNode = structures.TreeNode
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
type node struct {
x, y, val int
}
func verticalTraversal(root *TreeNode) [][]int {
nodes := []*node{}
inorder(root, 0, 0, &nodes)
sort.Slice(nodes, func(i, j int) bool {
if nodes[i].y == nodes[j].y {
if nodes[i].x < nodes[j].x {
return true
} else if nodes[i].x > nodes[j].x {
return false
}
return nodes[i].val < nodes[j].val
}
return nodes[i].y < nodes[j].y
})
res, currY, currColumn := [][]int{}, nodes[0].y, []int{nodes[0].val}
for i := 1; i < len(nodes); i++ {
if currY == nodes[i].y {
currColumn = append(currColumn, nodes[i].val)
} else {
res = append(res, currColumn)
currColumn = []int{nodes[i].val}
currY = nodes[i].y
}
}
res = append(res, currColumn)
return res
}
func inorder(root *TreeNode, x, y int, nodes *[]*node) {
if root != nil {
*nodes = append(*nodes, &node{x, y, root.Val})
inorder(root.Left, x+1, y-1, nodes)
inorder(root.Right, x+1, y+1, nodes)
}
}
```

View File

@ -0,0 +1,40 @@
package leetcode
func minimumDeviation(nums []int) int {
min, max := 0, 0
for i := range nums {
if nums[i]%2 == 1 {
nums[i] *= 2
}
if i == 0 {
min = nums[i]
max = nums[i]
} else if nums[i] < min {
min = nums[i]
} else if max < nums[i] {
max = nums[i]
}
}
res := max - min
for max%2 == 0 {
tmax, tmin := 0, 0
for i := range nums {
if nums[i] == max || (nums[i]%2 == 0 && min <= nums[i]/2) {
nums[i] /= 2
}
if i == 0 {
tmin = nums[i]
tmax = nums[i]
} else if nums[i] < tmin {
tmin = nums[i]
} else if tmax < nums[i] {
tmax = nums[i]
}
}
if tmax-tmin < res {
res = tmax - tmin
}
min, max = tmin, tmax
}
return res
}

View File

@ -0,0 +1,52 @@
package leetcode
import (
"fmt"
"testing"
)
type question1675 struct {
para1675
ans1675
}
// para 是参数
// one 代表第一个参数
type para1675 struct {
nums []int
}
// ans 是答案
// one 代表第一个答案
type ans1675 struct {
one int
}
func Test_Problem1675(t *testing.T) {
qs := []question1675{
{
para1675{[]int{1, 2, 4, 3}},
ans1675{1},
},
{
para1675{[]int{4, 1, 5, 20, 3}},
ans1675{3},
},
{
para1675{[]int{2, 10, 8}},
ans1675{3},
},
}
fmt.Printf("------------------------Leetcode Problem 1675------------------------\n")
for _, q := range qs {
_, p := q.ans1675, q.para1675
fmt.Printf("【input】:%v 【output】:%v\n", p, minimumDeviation(p.nums))
}
fmt.Printf("\n\n\n")
}

View File

@ -0,0 +1,105 @@
# [1675. Minimize Deviation in Array](https://leetcode.com/problems/minimize-deviation-in-array/)
## 题目
You are given an array `nums` of `n` positive integers.
You can perform two types of operations on any element of the array any number of times:
- If the element is **even**, **divide** it by `2`.
- For example, if the array is `[1,2,3,4]`, then you can do this operation on the last element, and the array will be `[1,2,3,2].`
- If the element is **odd**, **multiply** it by `2`.
- For example, if the array is `[1,2,3,4]`, then you can do this operation on the first element, and the array will be `[2,2,3,4].`
The **deviation** of the array is the **maximum difference** between any two elements in the array.
Return *the **minimum deviation** the array can have after performing some number of operations.*
**Example 1:**
```
Input: nums = [1,2,3,4]
Output: 1
Explanation: You can transform the array to [1,2,3,2], then to [2,2,3,2], then the deviation will be 3 - 2 = 1.
```
**Example 2:**
```
Input: nums = [4,1,5,20,3]
Output: 3
Explanation: You can transform the array after two operations to [4,2,5,5,3], then the deviation will be 5 - 2 = 3.
```
**Example 3:**
```
Input: nums = [2,10,8]
Output: 3
```
**Constraints:**
- `n == nums.length`
- `2 <= n <= 105`
- `1 <= nums[i] <= 10^9`
## 题目大意
给你一个由 n 个正整数组成的数组 nums 。你可以对数组的任意元素执行任意次数的两类操作:
- 如果元素是 偶数 ,除以 2。例如如果数组是 [1,2,3,4] ,那么你可以对最后一个元素执行此操作,使其变成 [1,2,3,2]
- 如果元素是 奇数 ,乘上 2。例如如果数组是 [1,2,3,4] ,那么你可以对第一个元素执行此操作,使其变成 [2,2,3,4]
数组的 偏移量 是数组中任意两个元素之间的 最大差值 。
返回数组在执行某些操作之后可以拥有的 最小偏移量 。
## 解题思路
- 要找到最小偏移量,即需要令最大值变小,最小值变大。要想达到这个要求,需要对奇数偶数做乘法和除法。这里特殊的是,奇数一旦乘以 2 以后,就变成偶数了。偶数除以 2 以后可能是奇数也可能是偶数。所以可以先将所有的奇数都乘以 2 统一变成偶数。
- 第二轮不断的将最大值除 2直到最大值为奇数不能再操作了。每轮循环中把比 min 值大的偶数也都除以 2 。这里除以 2 有 2 个目的,一个目的是将第一步奇数乘 2 还原回去,另一个目的是将本来的偶数除以 2 。可能有人有疑问,为什么只把最大值变小,没有将最小值变大呢?如果最小值是奇数,那么它一定是由上一个偶数除以 2 变过来的,我们在上一个状态已经计算过这个偶数了,因此没必要扩大它;如果最小值是偶数,那么它一定会在某一轮的除 2 操作中,不操作,即它不会满足 `min <= nums[i]/2` 这个条件。每次循环都更新该次循环的最大值和最小值,并记录偏移量。不断的循环,直到最大值为奇数,退出循环。最终输出最小偏移量。
## 代码
```go
package leetcode
func minimumDeviation(nums []int) int {
min, max := 0, 0
for i := range nums {
if nums[i]%2 == 1 {
nums[i] *= 2
}
if i == 0 {
min = nums[i]
max = nums[i]
} else if nums[i] < min {
min = nums[i]
} else if max < nums[i] {
max = nums[i]
}
}
res := max - min
for max%2 == 0 {
tmax, tmin := 0, 0
for i := range nums {
if nums[i] == max || (nums[i]%2 == 0 && min <= nums[i]/2) {
nums[i] /= 2
}
if i == 0 {
tmin = nums[i]
tmax = nums[i]
} else if nums[i] < tmin {
tmin = nums[i]
} else if tmax < nums[i] {
tmax = nums[i]
}
}
if tmax-tmin < res {
res = tmax - tmin
}
min, max = tmin, tmax
}
return res
}
```