From 092ab582761454908268e8d1b5b56b926c81d2ce Mon Sep 17 00:00:00 2001 From: Huangzj Date: Fri, 26 Mar 2021 09:13:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(Go-Tool)=EF=BC=9A2021/03/26:=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=85=A8=E6=8E=92=E5=88=97=E7=9A=84=E9=80=92=E5=BD=92?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=81=E5=AD=97=E5=85=B8=E5=BA=8F=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E3=80=81=E9=80=92=E5=A2=9E=E8=BF=9B=E5=88=B6=E4=BD=8D?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=81=E9=80=92=E5=87=8F=E8=BF=9B=E5=88=B6?= =?UTF-8?q?=E4=BD=8D=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 2 + util/FullPermutation/DictionaryOrder.go | 56 +++++++++++++++ util/FullPermutation/DictionaryOrder_test.go | 52 ++++++++++++++ util/FullPermutation/DigitDecrease.go | 71 ++++++++++++++++++++ util/FullPermutation/DigitDecrease_test.go | 59 ++++++++++++++++ util/FullPermutation/DigitIncrease.go | 71 ++++++++++++++++++++ util/FullPermutation/DigitIncrease_test.go | 57 ++++++++++++++++ util/FullPermutation/Recursion.go | 39 +++++++++++ util/FullPermutation/Recursion_test.go | 45 +++++++++++++ util/sort/QuickSort.go | 27 ++++++++ 10 files changed, 479 insertions(+) create mode 100644 util/FullPermutation/DictionaryOrder.go create mode 100644 util/FullPermutation/DictionaryOrder_test.go create mode 100644 util/FullPermutation/DigitDecrease.go create mode 100644 util/FullPermutation/DigitDecrease_test.go create mode 100644 util/FullPermutation/DigitIncrease.go create mode 100644 util/FullPermutation/DigitIncrease_test.go create mode 100644 util/FullPermutation/Recursion.go create mode 100644 util/FullPermutation/Recursion_test.go diff --git a/readme.md b/readme.md index 8d97a62..dc9a792 100644 --- a/readme.md +++ b/readme.md @@ -81,6 +81,8 @@ 2021/03/18:新增超过半数数字系列算法题,新增出现次数不同的数字系列算法题 +2021/03/26: 新增全排列的递归实现、字典序实现、递增进制位实现、递减进制位实现 + # 修复日志 2020/11/23:修改项目案例(按照一定规则对一组数据进行排序分组) diff --git a/util/FullPermutation/DictionaryOrder.go b/util/FullPermutation/DictionaryOrder.go new file mode 100644 index 0000000..38e2c34 --- /dev/null +++ b/util/FullPermutation/DictionaryOrder.go @@ -0,0 +1,56 @@ +/* + * @Author : huangzj + * @Time : 2021/3/22 15:29 + * @Description: + */ + +package FullPermutation + +import ( + sort2 "Go-Tool/util/sort" +) + +//字典序获取全排列 +func (per *Permutation) DictionaryOrder(b []byte) { + //先排序 + sort2.QuickSortByte(b, 0, len(b)-1) + for { + bef := 0 + afr := 0 + result := make([]byte, len(b)) + copy(result, b) + per.bytes = append(per.bytes, result) + + //从右往左找到第一个左边比右边小的数字 + for bef = len(b) - 2; ; bef-- { + if bef < 0 { + return + } + if b[bef] < b[bef+1] { + break + } + } + + //知道q的位置之后 + //从q开始向右边查找比位置q的数字大的第一个数字的位置 + for afr = len(b) - 1; afr > 0; afr-- { + if b[afr] > b[bef] { + break + } + } + + //交换两个数字 + b[bef], b[afr] = b[afr], b[bef] + //把后面的数字进行转置成递增顺序 + b = per.Reverse(b, bef+1, len(b)-1) + } +} + +func (per *Permutation) Reverse(b []byte, start, end int) []byte { + for start <= end { + b[start], b[end] = b[end], b[start] + start++ + end-- + } + return b +} diff --git a/util/FullPermutation/DictionaryOrder_test.go b/util/FullPermutation/DictionaryOrder_test.go new file mode 100644 index 0000000..2b046f4 --- /dev/null +++ b/util/FullPermutation/DictionaryOrder_test.go @@ -0,0 +1,52 @@ +/* + * @Author : huangzj + * @Time : 2021/3/22 15:29 + * @Description: + */ + +package FullPermutation + +import ( + "fmt" + "testing" +) + +func TestDictionaryOrder(t *testing.T) { + p := NewPermutation() + + p.DictionaryOrder([]byte("1234")) + fmt.Println() + for _, bs := range p.bytes { + fmt.Println(string(bs)) + } + p.Reset() + + p.DictionaryOrder([]byte("12345")) + fmt.Println() + for _, bs := range p.bytes { + fmt.Println(string(bs)) + } + p.Reset() + + p.DictionaryOrder([]byte("abcde")) + fmt.Println() + for _, bs := range p.bytes { + fmt.Println(string(bs)) + } + p.Reset() + + p.DictionaryOrder([]byte("abcdea")) + fmt.Println() + for _, bs := range p.bytes { + fmt.Println(string(bs)) + } + p.Reset() +} + +func TestPermutation_Reverse(t *testing.T) { + p := NewPermutation() + fmt.Println(p.Reverse([]byte{1, 2, 3, 4}, 0, 3)) + fmt.Println(p.Reverse([]byte{1, 2, 3, 4, 5}, 0, 4)) + fmt.Println(p.Reverse([]byte{1, 2, 3, 4, 5, 6}, 0, 5)) + fmt.Println(p.Reverse([]byte{1, 2, 3, 4, 5, 6, 7}, 0, 6)) +} diff --git a/util/FullPermutation/DigitDecrease.go b/util/FullPermutation/DigitDecrease.go new file mode 100644 index 0000000..0e9740b --- /dev/null +++ b/util/FullPermutation/DigitDecrease.go @@ -0,0 +1,71 @@ +/* + * @Author : huangzj + * @Time : 2021/3/23 17:06 + * @Description: + */ + +package FullPermutation + +func DigitDecreases(b []int) [][]int { + result := make([][]int, 0) + bit := make([]int, len(b)-1) + sum := 1 + //计算中的结果数,阶乘 + for i := 1; i <= len(b); i++ { + sum = sum * i + } + for i := 0; i < sum; i++ { + result = append(result, getRangeBySpace1(b, bit)) + bit = decreaseBit(bit) + } + return result +} + +//根据递增进制位,并且根据【数空格法】在原来的数组中求得全排列的一种可能实现 +//origin 原始数组 +//increaseBit 递增进制位,比原始数组长度小1,这里通过数组实现,更简单 +func getRangeBySpace1(origin []int, increaseBit []int) []int { + permutation := make([]int, len(origin)) + flag := make(map[int]bool, 0) + //排列数组从左往右,即从大到小 + for i := 0; i < len(origin)-1; i++ { + p := increaseBit[i] //从右到左,对应数字应该填充的位置 + j := len(origin) - 1 //该数字在本次排列的位置 + for ; ; j-- { + //该位置未被填充 + if !flag[j] { + p-- + } + //找到对应位置需要推出循环 + if p < 0 { + flag[j] = true + break + } + } + permutation[j] = origin[i] + } + for i := 0; i < len(origin); i++ { + if !flag[i] { + permutation[i] = origin[len(origin)-1] + } + } + + return permutation +} + +//递减进制位 +//每次加一,计算新的数组结果 +func decreaseBit(bit []int) []int { + + //数组下标从小到大,进制位从大到小 + for i := 0; i < len(bit); i++ { + if bit[i]+1 >= len(bit)+1-i { + bit[i] = (bit[i] + 1) % (len(bit) + 1 - i) + } else { + bit[i] += 1 + break + } + } + + return bit +} diff --git a/util/FullPermutation/DigitDecrease_test.go b/util/FullPermutation/DigitDecrease_test.go new file mode 100644 index 0000000..74da334 --- /dev/null +++ b/util/FullPermutation/DigitDecrease_test.go @@ -0,0 +1,59 @@ +/* + * @Author : huangzj + * @Time : 2021/3/23 19:53 + * @Description: + */ + +package FullPermutation + +import ( + "fmt" + "testing" +) + +func TestDecreaseBit(t *testing.T) { + + bit := []int{0, 0} + for i := 0; i < 6; i++ { + fmt.Println(bit) + bit = decreaseBit(bit) + } + + fmt.Println() + bit = []int{0, 0, 0} + for i := 0; i < 24; i++ { + fmt.Println(bit) + bit = decreaseBit(bit) + } + + fmt.Println() + bit = []int{0, 0, 0, 0} + for i := 0; i < 120; i++ { + fmt.Print(bit) + bit = decreaseBit(bit) + } + +} +func TestGetRangeBySpace1(t *testing.T) { + fmt.Println(getRangeBySpace1([]int{1, 2, 3}, []int{0, 0})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3}, []int{1, 0})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3}, []int{2, 0})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3}, []int{0, 1})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3}, []int{1, 1})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3}, []int{2, 1})) + + fmt.Println(getRangeBySpace1([]int{1, 2, 3, 4, 5}, []int{0, 0, 0, 0})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3, 4, 5}, []int{0, 0, 0, 1})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3, 4, 5}, []int{4, 3, 2, 1})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3, 4, 5}, []int{3, 0, 0, 0})) + fmt.Println(getRangeBySpace1([]int{1, 2, 3, 4, 5}, []int{1, 3, 2, 1})) + + fmt.Println(getRangeBySpace1([]int{1, 2, 3, 4, 5, 6, 7}, []int{3, 4, 2, 2, 2, 1})) +} + +func TestDigitDecrease(t *testing.T) { + fmt.Println(DigitDecreases([]int{1, 2, 3})) + fmt.Println(DigitDecreases([]int{20, 50, 30, 67})) + fmt.Println(DigitDecreases([]int{20, 50, 30, 99, 18213})) + fmt.Println(DigitDecreases([]int{20, 50, 30, 78321, 2321, 432})) +} diff --git a/util/FullPermutation/DigitIncrease.go b/util/FullPermutation/DigitIncrease.go new file mode 100644 index 0000000..a806c51 --- /dev/null +++ b/util/FullPermutation/DigitIncrease.go @@ -0,0 +1,71 @@ +/* + * @Author : huangzj + * @Time : 2021/3/23 17:05 + * @Description: + */ + +package FullPermutation + +func DigitIncrease(b []int) [][]int { + result := make([][]int, 0) + bit := make([]int, len(b)-1) + sum := 1 + //计算中的结果数,阶乘 + for i := 1; i <= len(b); i++ { + sum = sum * i + } + for i := 0; i < sum; i++ { + result = append(result, getRangeBySpace(b, bit)) + bit = increaseBit(bit) + } + return result +} + +//根据递增进制位,并且根据【数空格法】在原来的数组中求得全排列的一种可能实现 +//origin 原始数组 +//increaseBit 递增进制位,比原始数组长度小1,这里通过数组实现,更简单 +func getRangeBySpace(origin []int, increaseBit []int) []int { + permutation := make([]int, len(origin)) + flag := make(map[int]bool, 0) + //排列数组从左往右,即从大到小 + for i := len(origin) - 1; i > 0; i-- { + p := increaseBit[i-1] //从右到左,对应数字应该填充的位置 + j := len(origin) - 1 //该数字在本次排列的位置 + //中介数计算从左到右,即从大到小 + for ; ; j-- { + //该位置未被填充 + if !flag[j] { + p-- + } + //找到对应位置需要推出循环 + if p < 0 { + flag[j] = true + break + } + } + permutation[j] = origin[i] + } + for i := 0; i < len(origin); i++ { + if !flag[i] { + permutation[i] = origin[0] + } + } + + return permutation +} + +//递增进制位 +//根据递增进制位进行+1操作,返回递增的结果 +func increaseBit(bit []int) []int { + //最开始是从二进制开始 + for i, num := range bit { + if num+1 >= i+2 { + bit[i] = (num + 1) % (i + 2) + } else { + bit[i] = num + 1 + break + } + } + + return bit +} diff --git a/util/FullPermutation/DigitIncrease_test.go b/util/FullPermutation/DigitIncrease_test.go new file mode 100644 index 0000000..b36268a --- /dev/null +++ b/util/FullPermutation/DigitIncrease_test.go @@ -0,0 +1,57 @@ +/* + * @Author : huangzj + * @Time : 2021/3/23 19:54 + * @Description: + */ + +package FullPermutation + +import ( + "fmt" + "testing" +) + +func TestGetRangeBySpace(t *testing.T) { + fmt.Println(getRangeBySpace([]int{1, 2, 3}, []int{0, 0})) //123 + fmt.Println(getRangeBySpace([]int{1, 2, 3}, []int{1, 0})) // + fmt.Println(getRangeBySpace([]int{1, 2, 3}, []int{0, 1})) // + fmt.Println(getRangeBySpace([]int{1, 2, 3}, []int{1, 1})) // + fmt.Println(getRangeBySpace([]int{1, 2, 3}, []int{0, 2})) // + fmt.Println(getRangeBySpace([]int{1, 2, 3}, []int{1, 2})) //321 + + //fmt.Println(getRangeBySpace([]int{1, 2, 3, 4, 5}, []int{0, 0, 0, 0})) //12345 + //fmt.Println(getRangeBySpace([]int{1, 2, 3, 4, 5}, []int{0, 0, 0, 1})) //21354 + fmt.Println(getRangeBySpace([]int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4})) //54321 + fmt.Println(getRangeBySpace([]int{1, 2, 3, 4, 5}, []int{0, 0, 0, 3})) //12534 + fmt.Println(getRangeBySpace([]int{1, 2, 3, 4, 5}, []int{1, 2, 3, 1})) //43251 + + fmt.Println(getRangeBySpace([]int{1, 2, 3, 4, 5, 6, 7}, []int{1, 2, 2, 2, 4, 3})) //3647521 +} + +func TestIncreaseBit(t *testing.T) { + bit := []int{0, 0} + for i := 0; i < 6; i++ { + fmt.Println(bit) + bit = increaseBit(bit) + } + fmt.Println() + + bit = []int{0, 0, 0, 0} + for i := 0; i < 120; i++ { + bit = increaseBit(bit) + fmt.Println(bit) + } + + bit = []int{0, 0, 0} + for i := 0; i < 24; i++ { + bit = increaseBit(bit) + fmt.Println(bit) + } +} + +func TestDigitIncrease(t *testing.T) { + fmt.Println(DigitIncrease([]int{1, 2, 3})) + fmt.Println(DigitIncrease([]int{20, 50, 30, 67})) + fmt.Println(DigitIncrease([]int{20, 50, 30, 99, 18213})) + fmt.Println(DigitIncrease([]int{20, 50, 30, 78321, 2321, 432})) +} diff --git a/util/FullPermutation/Recursion.go b/util/FullPermutation/Recursion.go new file mode 100644 index 0000000..8e1d8f1 --- /dev/null +++ b/util/FullPermutation/Recursion.go @@ -0,0 +1,39 @@ +/* + * @Author : huangzj + * @Time : 2021/3/22 11:09 + * @Description: + */ + +package FullPermutation + +type Permutation struct { + bytes [][]byte +} + +func NewPermutation() *Permutation { + return &Permutation{ + bytes: [][]byte{}, + } +} + +func (per *Permutation) Recursion(b []byte, start int) { + //递归交换到最后一个位置结束 + if start == len(b)-1 { + bCopy := make([]byte, len(b)) + copy(bCopy, b) + per.bytes = append(per.bytes, bCopy) + } + + for i := start; i < len(b); i++ { + //交换固定位置 + b[i], b[start] = b[start], b[i] + //固定某一个数字位置,递归后面的其他数字 + per.Recursion(b, start+1) + //还原固定位置,进行下一次操作 + b[i], b[start] = b[start], b[i] + } +} + +func (per *Permutation) Reset() { + per.bytes = [][]byte{} +} diff --git a/util/FullPermutation/Recursion_test.go b/util/FullPermutation/Recursion_test.go new file mode 100644 index 0000000..768e965 --- /dev/null +++ b/util/FullPermutation/Recursion_test.go @@ -0,0 +1,45 @@ +/* + * @Author : huangzj + * @Time : 2021/3/22 11:22 + * @Description: + */ + +package FullPermutation + +import ( + "fmt" + "testing" +) + +func TestRecursion(t *testing.T) { + p := NewPermutation() + + p.Recursion([]byte("123"), 0) + fmt.Println() + for _, bs := range p.bytes { + fmt.Println(string(bs)) + } + p.Reset() + + p.Recursion([]byte("12345"), 0) + fmt.Println() + for _, bs := range p.bytes { + fmt.Println(string(bs)) + } + p.Reset() + + p.Recursion([]byte("abcde"), 0) + fmt.Println() + for _, bs := range p.bytes { + fmt.Println(string(bs)) + } + p.Reset() + + p.Recursion([]byte("abcdea"), 0) + fmt.Println() + for _, bs := range p.bytes { + fmt.Println(string(bs)) + } + p.Reset() + +} diff --git a/util/sort/QuickSort.go b/util/sort/QuickSort.go index cf97fdb..e35be7e 100644 --- a/util/sort/QuickSort.go +++ b/util/sort/QuickSort.go @@ -17,6 +17,14 @@ func QuickSort(list []int, start, end int) { } } +func QuickSortByte(list []byte, start, end int) { + if start < end { + position := hoarePartition1(list, start, end) + QuickSortByte(list, start, position) //注意这边结束的下表是position,而不是position + 1 + QuickSortByte(list, position+1, end) + } +} + //通过lomuto划分来实现快速排序 func QuickSort1(list []int, start, end int) { if start < end { @@ -26,6 +34,25 @@ func QuickSort1(list []int, start, end int) { } } +func hoarePartition1(list []byte, start int, end int) int { + value := list[start] //比较的元素 + s := start + e := end + for s < e { + //找到数组终止前,比目标数(value)大的数字 + for ; s < end && list[s] < value; s++ { + } + //找到数组结束前,比目标数(value)小的数字 + for ; e > start && list[e] >= value; e-- { + } + if s < e { + list[s], list[e] = list[e], list[s] + } + } + list[start], list[e] = list[e], list[start] + return e +} + func hoarePartition(list []int, start int, end int) int { value := list[start] //比较的元素 s := start