commit
8665c3f7b5
@ -0,0 +1,105 @@ |
|||||||
|
# If you prefer the allow list template instead of the deny list, see community template: |
||||||
|
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore |
||||||
|
# |
||||||
|
# Binaries for programs and plugins |
||||||
|
*.exe |
||||||
|
*.exe~ |
||||||
|
*.dll |
||||||
|
*.so |
||||||
|
*.dylib |
||||||
|
|
||||||
|
# Test binary, built with `go test -c` |
||||||
|
*.test |
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE |
||||||
|
*.out |
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it) |
||||||
|
# vendor/ |
||||||
|
|
||||||
|
# Go workspace file |
||||||
|
go.work |
||||||
|
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider |
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 |
||||||
|
|
||||||
|
.idea |
||||||
|
|
||||||
|
# User-specific stuff |
||||||
|
.idea/**/workspace.xml |
||||||
|
.idea/**/tasks.xml |
||||||
|
.idea/**/usage.statistics.xml |
||||||
|
.idea/**/dictionaries |
||||||
|
.idea/**/shelf |
||||||
|
|
||||||
|
# AWS User-specific |
||||||
|
.idea/**/aws.xml |
||||||
|
|
||||||
|
# Generated files |
||||||
|
.idea/**/contentModel.xml |
||||||
|
|
||||||
|
# Sensitive or high-churn files |
||||||
|
.idea/**/dataSources/ |
||||||
|
.idea/**/dataSources.ids |
||||||
|
.idea/**/dataSources.local.xml |
||||||
|
.idea/**/sqlDataSources.xml |
||||||
|
.idea/**/dynamic.xml |
||||||
|
.idea/**/uiDesigner.xml |
||||||
|
.idea/**/dbnavigator.xml |
||||||
|
|
||||||
|
# Gradle |
||||||
|
.idea/**/gradle.xml |
||||||
|
.idea/**/libraries |
||||||
|
|
||||||
|
# Gradle and Maven with auto-import |
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files, |
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using |
||||||
|
# auto-import. |
||||||
|
.idea/artifacts |
||||||
|
.idea/compiler.xml |
||||||
|
.idea/jarRepositories.xml |
||||||
|
.idea/modules.xml |
||||||
|
.idea/*.iml |
||||||
|
.idea/modules |
||||||
|
*.iml |
||||||
|
*.ipr |
||||||
|
|
||||||
|
# CMake |
||||||
|
cmake-build-*/ |
||||||
|
|
||||||
|
# Mongo Explorer plugin |
||||||
|
.idea/**/mongoSettings.xml |
||||||
|
|
||||||
|
# File-based project format |
||||||
|
*.iws |
||||||
|
|
||||||
|
# IntelliJ |
||||||
|
out/ |
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin |
||||||
|
.idea_modules/ |
||||||
|
|
||||||
|
# JIRA plugin |
||||||
|
atlassian-ide-plugin.xml |
||||||
|
|
||||||
|
# Cursive Clojure plugin |
||||||
|
.idea/replstate.xml |
||||||
|
|
||||||
|
# SonarLint plugin |
||||||
|
.idea/sonarlint/ |
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ) |
||||||
|
com_crashlytics_export_strings.xml |
||||||
|
crashlytics.properties |
||||||
|
crashlytics-build.properties |
||||||
|
fabric.properties |
||||||
|
|
||||||
|
# Editor-based Rest Client |
||||||
|
.idea/httpRequests |
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file |
||||||
|
.idea/caches/build_file_checksums.ser |
||||||
|
|
||||||
|
*.log |
||||||
|
|
||||||
|
/config.yml |
@ -0,0 +1,32 @@ |
|||||||
|
# Lavos |
||||||
|
|
||||||
|
算法设计与分析例题/作业代码合集,使用go编写实现 |
||||||
|
|
||||||
|
## 目录结构 |
||||||
|
|
||||||
|
包代码目录格式为,`cap{x}`,对应的是第x章的例题和作业代码,其中每个例题/作业代码文件均命名为`ex{x}.go`以及`work{x}.go`。 |
||||||
|
|
||||||
|
如第三章例6,位于`cap3/ex6.go`中,第四章作业5,位于`cap4/ex5.go`中。 |
||||||
|
|
||||||
|
## 运行/测试 |
||||||
|
|
||||||
|
要运行测试,需要go开发环境。[Go installation instructions: https://go.dev/doc/install](https://go.dev/doc/install) |
||||||
|
|
||||||
|
完成后,运行 |
||||||
|
```shell |
||||||
|
go test lavos/cap3 |
||||||
|
``` |
||||||
|
|
||||||
|
即可运行该章节下所有的例题和作业的test用例,例题和作业的test代码位于`example_test.go`和`work_test.go`中。 |
||||||
|
|
||||||
|
如果需要单独测试某一个题目,运行 |
||||||
|
```shell |
||||||
|
go test lavos/cap3 -v '-test.run' 'Ex6$' |
||||||
|
go test lavos/cap3 -v '-test.run' 'Work1$' |
||||||
|
``` |
||||||
|
即可运行对应的题目,如示例中将会运行第三章例题6的test和作业1 |
||||||
|
|
||||||
|
## 其他细节 |
||||||
|
|
||||||
|
由于习惯原因,我并不是很喜欢在算法代码中进行具体的输出操作,或者直接将输出输入放置于算法代码中,而是使用了类似于leetcode中的核心代码模式,因此`ex{x}.go`和`work{x}.go`中的代码模式均为核心代码,不负责输出输入, |
||||||
|
如有需要输出的算法,通过callback实现,传入能够实现输出的callback函数,在核心中调用callback来实现输出,核心代码不关心也不区负责输出输入,输出输入由test负责实现。 |
@ -0,0 +1,17 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex1 例题1
|
||||||
|
// 求1/1! - 1/3! + 1/5! - 1/7! + ... + (-1)^(n+1)/(2n-1)!
|
||||||
|
func Ex1(n int) float64 { |
||||||
|
sum, fab := 0.0, uint64(1) |
||||||
|
for i := 1; i <= n; i++ { |
||||||
|
fab *= 2*uint64(i) + 1 |
||||||
|
if i%2 == 0 { |
||||||
|
sum += -1.0 / float64(fab) |
||||||
|
} else { |
||||||
|
sum += 1.0 / float64(fab) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return sum |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex10 从0~n的整数中取r个不同的数做一组,求所有可能的组合
|
||||||
|
func Ex10(n, r int, callback func(nums []int)) int { |
||||||
|
if r > n { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
|
||||||
|
count := 0 |
||||||
|
combine := make([]int, r) |
||||||
|
|
||||||
|
var findCombine func(m, k int) |
||||||
|
findCombine = func(n, k int) { |
||||||
|
// 从n开始往下遍历组合
|
||||||
|
for i := n; i >= k; i-- { |
||||||
|
combine[k-1] = i |
||||||
|
if k > 1 { |
||||||
|
// k-1和n-1,继续深入遍历,处理子问题
|
||||||
|
findCombine(i-1, k-1) |
||||||
|
} else { |
||||||
|
count++ |
||||||
|
callback(combine) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
findCombine(n, r) |
||||||
|
return count |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
type Candidate int // 候选人
|
||||||
|
type Vote int // 票数
|
||||||
|
|
||||||
|
// Ex11 投票统计,有调整,这里不使用数组存储结果,使用hashmap表存结果
|
||||||
|
func Ex11(votes []Candidate, numOfCandidate int) map[Candidate]Vote { |
||||||
|
result := map[Candidate]Vote{} |
||||||
|
for _, candidate := range votes { |
||||||
|
// 无效的投票
|
||||||
|
if candidate <= 0 || int(candidate) > numOfCandidate { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
if _, exists := result[candidate]; !exists { |
||||||
|
result[candidate] = 1 |
||||||
|
} else { |
||||||
|
result[candidate]++ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
type HeightGrade int |
||||||
|
|
||||||
|
// Ex12 身高统计,这里也是用的hashmap存结果
|
||||||
|
func Ex12(heights []int) []int { |
||||||
|
result := make([]int, 8) |
||||||
|
for _, height := range heights { |
||||||
|
// 身高映射,上下限调整
|
||||||
|
mapping := height/5 - 29 |
||||||
|
if mapping < 0 { |
||||||
|
mapping = 0 |
||||||
|
} else if mapping > 7 { |
||||||
|
mapping = 7 |
||||||
|
} |
||||||
|
|
||||||
|
result[mapping]++ |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
type Subject int |
||||||
|
type Student int |
||||||
|
|
||||||
|
func Ex14(subjectPassedStudentMap map[Subject]Student) []Student { |
||||||
|
result := make([]Student, 0) |
||||||
|
|
||||||
|
// 学生及格科目数记录
|
||||||
|
studentRecord := map[Student]int{} |
||||||
|
for _, student := range subjectPassedStudentMap { |
||||||
|
// 对当前学生及格科目计数
|
||||||
|
if _, exists := studentRecord[student]; !exists { |
||||||
|
studentRecord[student] = 1 |
||||||
|
} else { |
||||||
|
studentRecord[student]++ |
||||||
|
} |
||||||
|
|
||||||
|
// 学生及格科目数已达到传入的科目数,即为全科及格
|
||||||
|
if studentRecord[student] == len(subjectPassedStudentMap) { |
||||||
|
result = append(result, student) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
var _numberTexts = []string{ |
||||||
|
"zero", "one", "two", "three", "four", |
||||||
|
"five", "six", "seven", "eight", "nine", |
||||||
|
} |
||||||
|
|
||||||
|
// Ex14NumInput 输入数字,输出英文
|
||||||
|
func Ex14NumInput(num uint64, callback func(str string)) { |
||||||
|
digits := make([]uint8, 0, 20) |
||||||
|
for i := num; i >= 1; i /= 10 { |
||||||
|
digits = append(digits, uint8(i%10)) |
||||||
|
} |
||||||
|
|
||||||
|
for i := len(digits) - 1; i >= 0; i-- { |
||||||
|
callback(_numberTexts[digits[i]]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Ex14StrInput 输入数字字符串,输出英文
|
||||||
|
func Ex14StrInput(num string, callback func(str string)) { |
||||||
|
for _, char := range num { |
||||||
|
callback(_numberTexts[char-48]) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
var ( |
||||||
|
cashes = []int{50, 20, 10, 5, 2, 1} |
||||||
|
) |
||||||
|
|
||||||
|
// Ex15 最少的纸币找零钱
|
||||||
|
func Ex15(amount, paid int) map[int]int { |
||||||
|
result := map[int]int{} |
||||||
|
|
||||||
|
// 还要找的钱
|
||||||
|
change := paid - amount |
||||||
|
for i, cash := range cashes { |
||||||
|
// 当前面额需要找的张数,整除后结果为0说明当前面额不足以找零
|
||||||
|
cashNum := change / cash |
||||||
|
if cashNum != 0 { |
||||||
|
result[i] = cashNum |
||||||
|
// 当前面额找完后更新剩余未找余额
|
||||||
|
change = change - cashNum*cash |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex16 求x,其平方为一个各位数字互不相同的九位数
|
||||||
|
func Ex16(callback func(x, x2 int)) { |
||||||
|
Next: |
||||||
|
for x := 10000; x < 32000; x++ { |
||||||
|
numCntMap := map[int]bool{} |
||||||
|
|
||||||
|
x2 := x * x |
||||||
|
for i := x2; i >= 1; i /= 10 { |
||||||
|
digit := i % 10 |
||||||
|
// 当前数字已经出现过,直接跳过,找下一个x,如果没出现过,则做标记后看下一位数字情况
|
||||||
|
if _, exists := numCntMap[digit]; exists { |
||||||
|
continue Next |
||||||
|
} |
||||||
|
|
||||||
|
numCntMap[digit] = true |
||||||
|
} |
||||||
|
|
||||||
|
callback(x, x2) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// _node 链表节点,单向循环链表
|
||||||
|
type _node struct { |
||||||
|
Value int |
||||||
|
Next *_node |
||||||
|
} |
||||||
|
|
||||||
|
// 初始化长度为n的环
|
||||||
|
func _initCircle(n int) *_node { |
||||||
|
head := &_node{0, nil} |
||||||
|
current := head |
||||||
|
for i := 1; i < n; i++ { |
||||||
|
newNode := &_node{i, nil} |
||||||
|
current.Next = newNode |
||||||
|
current = newNode |
||||||
|
} |
||||||
|
|
||||||
|
// 头尾相连成环
|
||||||
|
current.Next = head |
||||||
|
return head |
||||||
|
} |
||||||
|
|
||||||
|
// Ex17Normal 小朋友游戏(约瑟夫问题),一般解法(非数学解法),n: 总人数(节点数),k:出队报数
|
||||||
|
func Ex17Normal(n, k int) int { |
||||||
|
circle := _initCircle(n) |
||||||
|
current := circle |
||||||
|
for current.Next != current { |
||||||
|
for i := 1; i < k-1; i++ { |
||||||
|
current = current.Next |
||||||
|
} |
||||||
|
|
||||||
|
// 报到k-1时移除下一个节点
|
||||||
|
next := current.Next |
||||||
|
current.Next = next.Next |
||||||
|
current = current.Next |
||||||
|
|
||||||
|
// 避免内存泄露
|
||||||
|
next.Next = nil |
||||||
|
} |
||||||
|
|
||||||
|
return current.Value |
||||||
|
} |
||||||
|
|
||||||
|
// Ex17Math 小朋友游戏(约瑟夫问题),公式递推解法,n: 总人数(节点数),k:出队报数
|
||||||
|
func Ex17Math(n, k int) int { |
||||||
|
idx := 0 |
||||||
|
for i := 2; i <= n; i++ { |
||||||
|
idx = (idx + k) % i |
||||||
|
} |
||||||
|
|
||||||
|
return idx |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
import ( |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
// Ex18 超长整数乘法(都超长)
|
||||||
|
func Ex18(a, b string) string { |
||||||
|
result := make([]uint8, len(a)+len(b)) |
||||||
|
resultEndIdx := len(result) - 1 |
||||||
|
for i := 0; i < len(b); i++ { |
||||||
|
carry := uint8(0) |
||||||
|
aEnd, bEnd, resultIdx := len(a)-1, len(b)-1, 0 |
||||||
|
bDigit := b[bEnd-i] - 48 |
||||||
|
for j := 0; j < len(a); j++ { |
||||||
|
// 字符转数字
|
||||||
|
aDigit := a[aEnd-j] - 48 |
||||||
|
// 当前位计算结果 = 当前结果 + aDigit*bDigit + 进位
|
||||||
|
resultIdx = resultEndIdx - (i + j) |
||||||
|
num := result[resultIdx] + aDigit*bDigit + carry |
||||||
|
// 当前位为计算结果的个位,进位为十位上的数字
|
||||||
|
result[resultIdx] = num % 10 |
||||||
|
carry = num / 10 |
||||||
|
} |
||||||
|
|
||||||
|
// 如果还有进位,则对下一个结果位添加进位,此时不会再有进位
|
||||||
|
if carry != 0 { |
||||||
|
resultIdx-- |
||||||
|
result[resultIdx] += carry |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
zeroPrefix := true |
||||||
|
sb := strings.Builder{} |
||||||
|
for _, num := range result { |
||||||
|
if zeroPrefix && num == 0 { |
||||||
|
continue |
||||||
|
} else { |
||||||
|
zeroPrefix = false |
||||||
|
} |
||||||
|
|
||||||
|
sb.WriteByte(num + 48) |
||||||
|
} |
||||||
|
|
||||||
|
return sb.String() |
||||||
|
} |
||||||
|
|
||||||
|
// Ex18type2 超长整数乘法(都超长),a和b都是大端序的数字数组/切片
|
||||||
|
func Ex18type2(a, b []uint8) []uint8 { |
||||||
|
result := make([]uint8, len(a)+len(b)) |
||||||
|
resultEndIdx := len(result) - 1 |
||||||
|
for i := 0; i < len(b); i++ { |
||||||
|
carry := uint8(0) |
||||||
|
aEnd, bEnd, resultIdx := len(a)-1, len(b)-1, 0 |
||||||
|
bDigit := b[bEnd-i] |
||||||
|
for j := 0; j < len(a); j++ { |
||||||
|
// 字符转数字
|
||||||
|
aDigit := a[aEnd-j] |
||||||
|
// 当前位计算结果 = 当前结果 + aDigit*bDigit + 进位
|
||||||
|
resultIdx = resultEndIdx - (i + j) |
||||||
|
num := result[resultIdx] + aDigit*bDigit + carry |
||||||
|
// 当前位为计算结果的个位,进位为十位上的数字
|
||||||
|
result[resultIdx] = num % 10 |
||||||
|
carry = num / 10 |
||||||
|
} |
||||||
|
|
||||||
|
// 如果还有进位,则对下一个结果位添加进位,此时不会再有进位
|
||||||
|
if carry != 0 { |
||||||
|
resultIdx-- |
||||||
|
result[resultIdx] += carry |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
// Ex18type3 超长整数乘法(都超长),a是大端序的数字数组/切片,b为uint64
|
||||||
|
func Ex18type3(a []uint8, b uint64) []uint8 { |
||||||
|
result := make([]uint8, len(a)+22) |
||||||
|
resultEndIdx := len(result) - 1 |
||||||
|
bOffset := 0 |
||||||
|
for i := b; i >= 1; i /= 10 { |
||||||
|
carry := uint8(0) |
||||||
|
bDigit := uint8(i % 10) |
||||||
|
aEnd, resultIdx := len(a)-1, 0 |
||||||
|
for j := 0; j < len(a); j++ { |
||||||
|
// 字符转数字
|
||||||
|
aDigit := a[aEnd-j] |
||||||
|
// 当前位计算结果 = 当前结果 + aDigit*bDigit + 进位
|
||||||
|
resultIdx = resultEndIdx - (bOffset + j) |
||||||
|
num := result[resultIdx] + aDigit*bDigit + carry |
||||||
|
// 当前位为计算结果的个位,进位为十位上的数字
|
||||||
|
result[resultIdx] = num % 10 |
||||||
|
carry = num / 10 |
||||||
|
} |
||||||
|
|
||||||
|
// 如果还有进位,则对下一个结果位添加进位,此时不会再有进位
|
||||||
|
if carry != 0 { |
||||||
|
resultIdx-- |
||||||
|
result[resultIdx] += carry |
||||||
|
} |
||||||
|
|
||||||
|
bOffset++ |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,137 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
import "strings" |
||||||
|
|
||||||
|
// Ex19 高精度阶乘
|
||||||
|
func Ex19(n uint64) string { |
||||||
|
result := []uint8{1} |
||||||
|
for i := uint64(2); i <= n; i++ { |
||||||
|
result = multiply(result, i) |
||||||
|
} |
||||||
|
|
||||||
|
return DigitSlice2String(result) |
||||||
|
} |
||||||
|
|
||||||
|
func multiply(a []uint8, b uint64) []uint8 { |
||||||
|
result := make([]uint8, len(a)+22) |
||||||
|
resultEndIdx := len(result) - 1 |
||||||
|
bOffset := 0 |
||||||
|
for i := b; i >= 1; i /= 10 { |
||||||
|
carry := uint8(0) |
||||||
|
bDigit := uint8(i % 10) |
||||||
|
aEnd, resultIdx := len(a)-1, 0 |
||||||
|
for j := 0; j < len(a); j++ { |
||||||
|
// 字符转数字
|
||||||
|
aDigit := a[aEnd-j] |
||||||
|
// 当前位计算结果 = 当前结果 + aDigit*bDigit + 进位
|
||||||
|
resultIdx = resultEndIdx - (bOffset + j) |
||||||
|
num := result[resultIdx] + aDigit*bDigit + carry |
||||||
|
// 当前位为计算结果的个位,进位为十位上的数字
|
||||||
|
result[resultIdx] = num % 10 |
||||||
|
carry = num / 10 |
||||||
|
} |
||||||
|
|
||||||
|
// 如果还有进位,则对下一个结果位添加进位,此时不会再有进位
|
||||||
|
if carry != 0 { |
||||||
|
resultIdx-- |
||||||
|
result[resultIdx] += carry |
||||||
|
} |
||||||
|
|
||||||
|
bOffset++ |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
func multiply2(a []uint8, b uint64) []uint8 { |
||||||
|
result := make([]uint8, len(a)+22) |
||||||
|
resultEndIdx := len(result)*2 - 1 |
||||||
|
bOffset := 0 |
||||||
|
for i := b; i >= 1; i /= 10 { |
||||||
|
carry := uint8(0) |
||||||
|
bDigit := uint8(i % 10) |
||||||
|
aEnd, resultIdx := len(a)*2-1, 0 |
||||||
|
for j := 0; j < len(a); j++ { |
||||||
|
// 字符转数字
|
||||||
|
aDigit := uint8(0) |
||||||
|
// 4,5 -> 37(0010,0101)
|
||||||
|
aIdx := aEnd - j |
||||||
|
if aIdx%2 == 0 { |
||||||
|
aDigit = a[aIdx/2] >> 4 |
||||||
|
} else { |
||||||
|
aDigit = a[aIdx/2] & 0b00001111 |
||||||
|
} |
||||||
|
|
||||||
|
// 当前位计算结果 = 当前结果 + aDigit*bDigit + 进位
|
||||||
|
resultIdx = resultEndIdx - (bOffset + j) |
||||||
|
bitIdx := resultIdx / 2 |
||||||
|
if resultIdx%2 == 0 { |
||||||
|
num := (result[bitIdx] >> 4) + aDigit*bDigit + carry |
||||||
|
// 清位
|
||||||
|
// 4,5 -> 37(0010,0101) => 0,5 -> 5(0000,0101)
|
||||||
|
result[bitIdx] &= 0b00001111 |
||||||
|
// 位赋值
|
||||||
|
// 0,5 -> 5(0000,0101) => 5,5 -> 5(0101,0101)
|
||||||
|
// 5(0000,0101) << 4 => 80(0101,0000)
|
||||||
|
// 5(0000,0101) | 80(0101,0000) => 5,5 -> 5(0101,0101)
|
||||||
|
result[bitIdx] |= (num % 10) << 4 |
||||||
|
carry = num / 10 |
||||||
|
} else { |
||||||
|
num := (result[bitIdx] & 0b00001111) + aDigit*bDigit + carry |
||||||
|
// 清位
|
||||||
|
// 4,5 -> 37(0010,0101) => 4,0 -> 32(0010,0000)
|
||||||
|
result[bitIdx] &= 0b11110000 |
||||||
|
// 赋值
|
||||||
|
// 4,0 -> 32(0010,0000) => 4,5 -> 37(0010,0101)
|
||||||
|
// 32(0010,0000) | 5(0000,0101) => 4,5 -> 37(0010,0101)
|
||||||
|
result[bitIdx] |= num % 10 |
||||||
|
carry = num / 10 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 如果还有进位,则对下一个结果位添加进位,此时不会再有进位
|
||||||
|
if carry != 0 { |
||||||
|
resultIdx-- |
||||||
|
bitIdx := resultIdx / 2 |
||||||
|
if resultIdx%2 == 0 { |
||||||
|
// 4,5 -> 37(0010,0101) => 5,5 -> 37(0101,0101)
|
||||||
|
// 4+1 -> 5(0000,0101) << 4 => 80(0101,0000)
|
||||||
|
// 5(0000,0101) | 80(0101,0000) => 5,5 -> 5(0101,0101)
|
||||||
|
result[bitIdx] &= 0b00001111 |
||||||
|
num := (result[bitIdx] >> 4) + carry |
||||||
|
result[bitIdx] |= num << 4 |
||||||
|
} else { |
||||||
|
result[bitIdx] &= 0b11110000 |
||||||
|
num := (result[bitIdx] & 0b00001111) + carry |
||||||
|
result[bitIdx] |= num |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bOffset++ |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
// Ex19LowMem 低内存使用版,两位数字结果按位存在同一个uint8中,一个0~9数字只使用四字节,uint8可存两位,一个字节拆成两半用
|
||||||
|
func Ex19LowMem(n uint64) string { |
||||||
|
result := []uint8{1} |
||||||
|
for i := uint64(2); i <= n; i++ { |
||||||
|
result = multiply2(result, i) |
||||||
|
} |
||||||
|
|
||||||
|
zeroPrefix := true |
||||||
|
sb := strings.Builder{} |
||||||
|
for _, num := range result { |
||||||
|
if zeroPrefix && num == 0 { |
||||||
|
continue |
||||||
|
} else { |
||||||
|
zeroPrefix = false |
||||||
|
} |
||||||
|
|
||||||
|
sb.WriteByte((num >> 4) + 48) |
||||||
|
sb.WriteByte((num & 0b00001111) + 48) |
||||||
|
} |
||||||
|
|
||||||
|
return sb.String() |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex2 例2 求1000以内的完数,返回一个map,key为完数,value为其因数的数组
|
||||||
|
func Ex2() map[int][]int { |
||||||
|
result := map[int][]int{} |
||||||
|
for i := range 1000 { |
||||||
|
if i < 2 { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
sum := 0 |
||||||
|
factors := make([]int, 0, 20) |
||||||
|
for j := 1; j <= i/2; j++ { |
||||||
|
if i%j == 0 { |
||||||
|
factors = append(factors, j) |
||||||
|
sum += j |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if sum == i { |
||||||
|
result[i] = factors |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex3 求鞍点数,行上最小,列上最大
|
||||||
|
func Ex3(matrix [][]int) (int, int, int) { |
||||||
|
rowMinIdx := map[int]int{} // key: 行索引, value: 最小值所在列
|
||||||
|
colMaxIdx := map[int]int{} // key: 列索引, value: 最大值所在行
|
||||||
|
for rowIdx, row := range matrix { |
||||||
|
rowMinIdx[rowIdx] = 0 |
||||||
|
for colIdx, currNum := range row { |
||||||
|
if currNum < row[rowMinIdx[rowIdx]] { |
||||||
|
rowMinIdx[rowIdx] = colIdx |
||||||
|
} |
||||||
|
|
||||||
|
if _, has := colMaxIdx[colIdx]; !has { |
||||||
|
colMaxIdx[colIdx] = rowIdx |
||||||
|
} else if currNum > matrix[colMaxIdx[colIdx]][colIdx] { |
||||||
|
colMaxIdx[colIdx] = rowIdx |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for rowIdx, colIdx := range rowMinIdx { |
||||||
|
if rowIdx == colMaxIdx[colIdx] { |
||||||
|
return rowIdx, colIdx, matrix[rowIdx][colIdx] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return -1, -1, 0 |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
package cap3 |
@ -0,0 +1,69 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
import "lavos/common" |
||||||
|
|
||||||
|
// Ex5 例题5 汉诺塔问题,输出移动的步骤,可指定算法类型,每做出一步移动操作都将会调用callback
|
||||||
|
func Ex5(beadNum int, algoType AlgoType, callback func(from string, to string)) { |
||||||
|
switch algoType { |
||||||
|
case AlgoTypeRecursion: |
||||||
|
Ex5Recursive(beadNum, "A", "B", "C", callback) |
||||||
|
default: |
||||||
|
Ex5NonRecursive(beadNum, "A", "B", "C", callback) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func Ex5Recursive(beadNum int, a, b, c string, callback func(from string, to string)) { |
||||||
|
if beadNum == 1 { |
||||||
|
// 如果只有一颗珠子,直接从 A 移动到 C,结束
|
||||||
|
callback(a, c) |
||||||
|
} else { |
||||||
|
// 第二步:将所有在 N 之上的珠子(即 N-1 颗珠子)从 A 移动到 B。此时 C 是中转站
|
||||||
|
Ex5Recursive(beadNum-1, a, c, b, callback) |
||||||
|
|
||||||
|
// 第二步:将 A 的珠子移动到 C
|
||||||
|
callback(a, c) |
||||||
|
|
||||||
|
// 第三步:将剩余的 N-1 颗珠子从 B 移动到 C。此时 A 是中转站
|
||||||
|
Ex5Recursive(beadNum-1, b, a, c, callback) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type _step struct { |
||||||
|
n int |
||||||
|
from, transit, to string |
||||||
|
} |
||||||
|
|
||||||
|
func Ex5NonRecursive(beadNum int, a, b, c string, callback func(from string, to string)) { |
||||||
|
stack := common.NewStack[_step](beadNum * 5) |
||||||
|
// 最终状态:a->c,b作为中转
|
||||||
|
stack.Push(&_step{ |
||||||
|
n: beadNum, |
||||||
|
from: a, transit: b, to: c, |
||||||
|
}) |
||||||
|
for !stack.Empty() { |
||||||
|
status := stack.Pop() |
||||||
|
if status.n == 1 { |
||||||
|
callback(status.from, status.to) |
||||||
|
} else { |
||||||
|
// 把子问题的三个基本步骤压入栈
|
||||||
|
stack.Push(&_step{ |
||||||
|
n: status.n - 1, |
||||||
|
from: status.transit, |
||||||
|
transit: status.from, |
||||||
|
to: status.to, |
||||||
|
}) |
||||||
|
stack.Push(&_step{ |
||||||
|
n: 1, |
||||||
|
from: status.from, |
||||||
|
transit: status.transit, |
||||||
|
to: status.to, |
||||||
|
}) |
||||||
|
stack.Push(&_step{ |
||||||
|
n: status.n - 1, |
||||||
|
from: status.from, |
||||||
|
transit: status.to, |
||||||
|
to: status.transit, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,103 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex6Output 例六的带输出结果
|
||||||
|
func Ex6Output(num int, callback func(nums []int)) { |
||||||
|
Ex6RecursionOutput(num, callback) |
||||||
|
} |
||||||
|
|
||||||
|
// Ex6NoneOutput 例六的不带输出结果版本,只求数量
|
||||||
|
func Ex6NoneOutput(num int, algoType AlgoType, callback func(nums []int)) int { |
||||||
|
switch algoType { |
||||||
|
case AlgoTypeRecursion: |
||||||
|
return Ex6Recursion(num) |
||||||
|
default: |
||||||
|
return Ex6NoneRecursion(num) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Ex6Recursion 整数划分,递归写法,只计算结果,但对算法经过调整以适合输出
|
||||||
|
func Ex6Recursion(num int) int { |
||||||
|
count := 0 |
||||||
|
var divider func(num, m int) |
||||||
|
divider = func(num, m int) { |
||||||
|
// num == 0 来源会有两种:递归中num==m,以及传入的num本身就是0,此时可以作为一个划分
|
||||||
|
if num == 0 { |
||||||
|
count++ |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 最大划分大小m逐级-1求划分数
|
||||||
|
if m > 1 { |
||||||
|
divider(num, m-1) |
||||||
|
} |
||||||
|
|
||||||
|
// m <= num,对剩余未加的数进行划分
|
||||||
|
if m <= num { |
||||||
|
divider(num-m, m) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
divider(num, num) |
||||||
|
return count |
||||||
|
} |
||||||
|
|
||||||
|
// Ex6RecursionOutput 整数划分,由上面的递归写法修改而来,可求划分情况,对算法经过调整以适合输出
|
||||||
|
func Ex6RecursionOutput(num int, callback func(dividedNums []int)) { |
||||||
|
var divider func(num, m int, dividedNums []int, callback func(dividedNums []int)) |
||||||
|
divider = func(num, m int, dividedNums []int, callback func(dividedNums []int)) { |
||||||
|
// num==0时,当前已划分完毕,回调输出
|
||||||
|
if num == 0 { |
||||||
|
callback(dividedNums) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 最大划分大小m逐级-1求划分数
|
||||||
|
if m > 1 { |
||||||
|
divider(num, m-1, dividedNums, callback) |
||||||
|
} |
||||||
|
|
||||||
|
if m <= num { |
||||||
|
// m <= num,对剩余未加的数进行划分,当前的m已经是划分中的一个成员,将其添加进dividedNums中
|
||||||
|
divider(num-m, m, append(dividedNums, m), callback) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
divider(num, num, make([]int, 0, num), callback) |
||||||
|
} |
||||||
|
|
||||||
|
// Ex6NoneRecursion 整数划分,非递归写法,由递归法改写而来,模拟递归过程
|
||||||
|
func Ex6NoneRecursion(num int) int { |
||||||
|
divider := func(num, divideMax int) int { |
||||||
|
// 初始化
|
||||||
|
result := make([][]int, num+1) |
||||||
|
for i := 0; i < num+1; i++ { |
||||||
|
result[i] = make([]int, num+1) |
||||||
|
} |
||||||
|
for i := 1; i <= num; i++ { |
||||||
|
result[0][i] = 1 |
||||||
|
} |
||||||
|
|
||||||
|
// i从1开始到num进行划分计算,
|
||||||
|
// 里层j从1开始到m(最大划分大小)开始计算子问题的划分
|
||||||
|
// 从1开始,自底向上计算
|
||||||
|
// 此处为非递归写法,当前的结果依赖上一个结果,因此需要先计算上一个结果,
|
||||||
|
// 因此整个问题过程需要从最小的问题开始计算
|
||||||
|
divideMax = min(num, divideMax) |
||||||
|
for n := 1; n <= num; n++ { |
||||||
|
for m := 1; m <= divideMax; m++ { |
||||||
|
if n <= m { |
||||||
|
// 对应 Q(n,n) = 1 + Q(n, n-1) 的情况
|
||||||
|
// n < m (n < m) 时均看作i == m (n == m)
|
||||||
|
result[n][m] = 1 + result[n][n-1] |
||||||
|
} else { |
||||||
|
// 对应 Q(n,m) = Q(n, m-1) + Q(n-m, m) 的情况
|
||||||
|
result[n][m] = result[n][m-1] + result[n-m][m] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return result[num][divideMax] |
||||||
|
} |
||||||
|
|
||||||
|
return divider(num, num) |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex7 低位到高位输出正整数的数字
|
||||||
|
func Ex7(num uint64, algoType AlgoType, callback func(digit uint8)) { |
||||||
|
switch algoType { |
||||||
|
case AlgoTypeRecursion: |
||||||
|
Ex7Recursion(num, callback) |
||||||
|
default: |
||||||
|
Ex7NoneRecursion(num, callback) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func Ex7Recursion(num uint64, callback func(digit uint8)) { |
||||||
|
if num < 10 { |
||||||
|
callback(uint8(num)) |
||||||
|
} else { |
||||||
|
callback(uint8(num % 10)) |
||||||
|
Ex7Recursion(num/10, callback) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func Ex7NoneRecursion(num uint64, callback func(digit uint8)) { |
||||||
|
for i := num; i >= 1; i /= 10 { |
||||||
|
callback(uint8(i % 10)) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex8 高位到低位输出正整数的数字
|
||||||
|
func Ex8(num uint64, algoType AlgoType, callback func(digit uint8)) { |
||||||
|
switch algoType { |
||||||
|
case AlgoTypeRecursion: |
||||||
|
Ex8Recursion(num, callback) |
||||||
|
default: |
||||||
|
Ex8NoneRecursion(num, callback) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Ex8Recursion 高位到低位输出正整数的数字(递归)
|
||||||
|
func Ex8Recursion(num uint64, callback func(digit uint8)) { |
||||||
|
if num < 10 { |
||||||
|
callback(uint8(num)) |
||||||
|
} else { |
||||||
|
// 跟ex7的小区别
|
||||||
|
Ex8Recursion(num/10, callback) |
||||||
|
callback(uint8(num % 10)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Ex8NoneRecursion 高位到低位输出正整数的数字(非递归)
|
||||||
|
func Ex8NoneRecursion(num uint64, callback func(digit uint8)) { |
||||||
|
digits := make([]uint8, 0, 20) |
||||||
|
for i := num; i >= 1; i /= 10 { |
||||||
|
digits = append(digits, uint8(i%10)) |
||||||
|
} |
||||||
|
|
||||||
|
for i := len(digits) - 1; i >= 0; i-- { |
||||||
|
callback(digits[i]) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Ex9t1 整数拆解为2的幂之和(返回整数的二进制bit取值情况,bit的idx对应相应的幂)
|
||||||
|
func Ex9t1(num int) []bool { |
||||||
|
// 传进来的是int,一般是32bit,这里就用64来存bit,肯定够了
|
||||||
|
bits := make([]bool, 0, 64) |
||||||
|
for i := 0; num != 0; i++ { |
||||||
|
bits = append(bits, num%2 == 1) |
||||||
|
num /= 2 |
||||||
|
} |
||||||
|
|
||||||
|
return bits |
||||||
|
} |
||||||
|
|
||||||
|
// Ex9t2 整数拆解为2的幂之和(返回幂取值)
|
||||||
|
func Ex9t2(num int) []uint8 { |
||||||
|
// 传进来的是int,一般是32bit,这里就用64来存bit,肯定够了
|
||||||
|
bits := make([]uint8, 0, 64) |
||||||
|
for i := uint8(0); num != 0; i++ { |
||||||
|
if num%2 == 1 { |
||||||
|
bits = append(bits, i) |
||||||
|
} |
||||||
|
|
||||||
|
num /= 2 |
||||||
|
} |
||||||
|
|
||||||
|
return bits |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
import "strings" |
||||||
|
|
||||||
|
type AlgoType int |
||||||
|
|
||||||
|
const ( |
||||||
|
AlgoTypeRecursion AlgoType = iota |
||||||
|
AlgoTypeNoneRecursion |
||||||
|
) |
||||||
|
|
||||||
|
func DigitSlice2String(nums []uint8) string { |
||||||
|
zeroPrefix := true |
||||||
|
sb := strings.Builder{} |
||||||
|
for _, num := range nums { |
||||||
|
if zeroPrefix && num == 0 { |
||||||
|
continue |
||||||
|
} else { |
||||||
|
zeroPrefix = false |
||||||
|
} |
||||||
|
|
||||||
|
sb.WriteByte(num + 48) |
||||||
|
} |
||||||
|
|
||||||
|
return sb.String() |
||||||
|
} |
@ -0,0 +1,217 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"strconv" |
||||||
|
"testing" |
||||||
|
) |
||||||
|
|
||||||
|
func TestEx1(t *testing.T) { |
||||||
|
fmt.Println(Ex1(1)) |
||||||
|
fmt.Println(Ex1(2)) |
||||||
|
fmt.Println(Ex1(3)) |
||||||
|
fmt.Println(Ex1(4)) |
||||||
|
fmt.Println(Ex1(5)) |
||||||
|
fmt.Println(Ex1(6)) |
||||||
|
fmt.Println(Ex1(7)) |
||||||
|
fmt.Println(Ex1(8)) |
||||||
|
fmt.Println(Ex1(9)) |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx2(t *testing.T) { |
||||||
|
result := Ex2() |
||||||
|
for num, factors := range result { |
||||||
|
fmt.Printf("%d's factors are %+v\n", num, factors) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx3(t *testing.T) { |
||||||
|
matrix := [][]int{ |
||||||
|
{1, 4, 5, 1}, |
||||||
|
{8, 9, 6, 7}, |
||||||
|
{1, 1, 4, 2}, |
||||||
|
{0, 8, 2, 9}, |
||||||
|
} |
||||||
|
|
||||||
|
row, col, val := Ex3(matrix) |
||||||
|
if row != -1 && col != -1 { |
||||||
|
fmt.Printf("(%d,%d): %d\n", row, col, val) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx5(t *testing.T) { |
||||||
|
beadsNum := 5 |
||||||
|
step := 0 |
||||||
|
|
||||||
|
fmt.Println("NoneRecursive: ") |
||||||
|
Ex5(beadsNum, AlgoTypeNoneRecursion, func(from string, to string) { |
||||||
|
step++ |
||||||
|
fmt.Printf("step %d: %s -> %s\n", step, from, to) |
||||||
|
}) |
||||||
|
|
||||||
|
fmt.Println("----------------") |
||||||
|
|
||||||
|
step = 0 |
||||||
|
fmt.Println("Recursive: ") |
||||||
|
Ex5(beadsNum, AlgoTypeRecursion, func(from string, to string) { |
||||||
|
step++ |
||||||
|
fmt.Printf("step %d: %s -> %s\n", step, from, to) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx6(t *testing.T) { |
||||||
|
prev := 0 |
||||||
|
Ex6RecursionOutput(6, func(dividedNums []int) { |
||||||
|
for i, num := range dividedNums { |
||||||
|
if i == 0 { |
||||||
|
if prev != num { |
||||||
|
prev = num |
||||||
|
fmt.Println() |
||||||
|
} |
||||||
|
fmt.Printf("%d", num) |
||||||
|
} else { |
||||||
|
fmt.Printf("+%d", num) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fmt.Print("\t\t\t") |
||||||
|
}) |
||||||
|
|
||||||
|
fmt.Println() |
||||||
|
fmt.Println("------------") |
||||||
|
|
||||||
|
result := Ex6Recursion(6) |
||||||
|
fmt.Println(result) |
||||||
|
|
||||||
|
result = Ex6NoneRecursion(6) |
||||||
|
fmt.Println(result) |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx7(t *testing.T) { |
||||||
|
num := uint64(123456) |
||||||
|
Ex7(num, AlgoTypeNoneRecursion, func(digit uint8) { |
||||||
|
fmt.Printf("%d ", digit) |
||||||
|
}) |
||||||
|
fmt.Println() |
||||||
|
|
||||||
|
Ex7(num, AlgoTypeRecursion, func(digit uint8) { |
||||||
|
fmt.Printf("%d ", digit) |
||||||
|
}) |
||||||
|
fmt.Println() |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx8(t *testing.T) { |
||||||
|
num := uint64(123456) |
||||||
|
Ex8(num, AlgoTypeNoneRecursion, func(digit uint8) { |
||||||
|
fmt.Printf("%d ", digit) |
||||||
|
}) |
||||||
|
fmt.Println() |
||||||
|
|
||||||
|
Ex8(num, AlgoTypeRecursion, func(digit uint8) { |
||||||
|
fmt.Printf("%d ", digit) |
||||||
|
}) |
||||||
|
fmt.Println() |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx9(t *testing.T) { |
||||||
|
bits := Ex9t1(137) |
||||||
|
fmt.Printf("%d=", 137) |
||||||
|
for i, bit := range bits { |
||||||
|
if bit { |
||||||
|
fmt.Printf("2^%d + ", i) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
println() |
||||||
|
|
||||||
|
pows := Ex9t2(137) |
||||||
|
fmt.Printf("%d=", 137) |
||||||
|
for _, pow := range pows { |
||||||
|
fmt.Printf("2^%d + ", pow) |
||||||
|
} |
||||||
|
|
||||||
|
println() |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx10(t *testing.T) { |
||||||
|
Ex10(5, 3, func(nums []int) { |
||||||
|
fmt.Printf("%+v\n", nums) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx14(t *testing.T) { |
||||||
|
num := uint64(8734112) |
||||||
|
Ex14StrInput(strconv.FormatUint(num, 10), func(str string) { |
||||||
|
fmt.Printf("%s-", str) |
||||||
|
}) |
||||||
|
fmt.Println() |
||||||
|
|
||||||
|
Ex14NumInput(num, func(str string) { |
||||||
|
fmt.Printf("%s-", str) |
||||||
|
}) |
||||||
|
fmt.Println() |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx15(t *testing.T) { |
||||||
|
result := Ex15(60, 70) |
||||||
|
for cash, cashNum := range result { |
||||||
|
fmt.Printf("%d->%d, ", cashes[cash], cashNum) |
||||||
|
} |
||||||
|
fmt.Println() |
||||||
|
|
||||||
|
result = Ex15(60, 100) |
||||||
|
for cash, cashNum := range result { |
||||||
|
fmt.Printf("%d->%d, ", cashes[cash], cashNum) |
||||||
|
} |
||||||
|
fmt.Println() |
||||||
|
|
||||||
|
result = Ex15(60, 74) |
||||||
|
for cash, cashNum := range result { |
||||||
|
fmt.Printf("%d->%d, ", cashes[cash], cashNum) |
||||||
|
} |
||||||
|
fmt.Println() |
||||||
|
|
||||||
|
result = Ex15(60, 130) |
||||||
|
for cash, cashNum := range result { |
||||||
|
fmt.Printf("%d->%d, ", cashes[cash], cashNum) |
||||||
|
} |
||||||
|
|
||||||
|
fmt.Println() |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx16(t *testing.T) { |
||||||
|
count := 0 |
||||||
|
Ex16(func(x, x2 int) { |
||||||
|
count++ |
||||||
|
fmt.Printf("%d: %d, x^2=%d\n", count, x, x2) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx17(t *testing.T) { |
||||||
|
n, k := 10, 2 |
||||||
|
result := Ex17Normal(n, k) |
||||||
|
fmt.Println(result) |
||||||
|
|
||||||
|
result = Ex17Math(n, k) |
||||||
|
fmt.Println(result) |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx18(t *testing.T) { |
||||||
|
fmt.Println(Ex18("6451", "6637") == "42815287") |
||||||
|
fmt.Println(Ex18("1111", "2") == "2222") |
||||||
|
|
||||||
|
// 来个夸张点的
|
||||||
|
ans := "59431035264803873745814101793588195732295068254603339623610036212240642359886400430165726959529476600423448130231213495885200101414878403047792277609642" |
||||||
|
fmt.Println(Ex18( |
||||||
|
"953249582974085793083245237450927435989430572386540298743509843545728475284751234", |
||||||
|
"62345723854798175908734905872984724974984398572942345324535728479275413") == ans, |
||||||
|
) |
||||||
|
|
||||||
|
result := Ex18type3([]uint8{6, 4, 5, 1}, 6637) |
||||||
|
fmt.Println(DigitSlice2String(result) == "42815287") |
||||||
|
} |
||||||
|
|
||||||
|
func TestEx19(t *testing.T) { |
||||||
|
fmt.Println(Ex19(10)) |
||||||
|
fmt.Println(Ex19(100)) |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
package cap3 |
@ -0,0 +1,27 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Work1 求 2 + 22 + 222 + 2222 + ...22...22(n个2)的精确值,返回大端序结果,高位在前存放结果
|
||||||
|
// 按位直接计算结果,从最低位(结果索引的末尾)开始,
|
||||||
|
// 每一位(索引i)的计算结果为2*(i+1)加上进位,该位的数字即为结果%10,进位即为结果/10取整。
|
||||||
|
// 如n=10,则最低位(i=9)的计算结果为(9+1)*2 + 0 = 20,该位数字为result[i]=20%10=0,进位carry=20/10=2,
|
||||||
|
// 下一位(i=8)计算结果为(8+1)*2 + 2 = 20,该位数字为result[i]=20%10=0,进位carry=20/10=2,
|
||||||
|
// 下一位(i=7)计算结果为(7+1)*2 + 2 = 18,该位数字为result[i]=18%10=8,进位carry=18/10=1,
|
||||||
|
// 以此类推
|
||||||
|
func Work1(n int) []uint8 { |
||||||
|
// 大端序,高位在前存放结果
|
||||||
|
result := make([]uint8, n) |
||||||
|
carry := 0 |
||||||
|
for i := n - 1; i >= 0; i-- { |
||||||
|
num := (i+1)*2 + carry |
||||||
|
carry = num / 10 |
||||||
|
result[i] = uint8(num % 10) |
||||||
|
} |
||||||
|
|
||||||
|
if carry != 0 { |
||||||
|
result = append(result, 0) |
||||||
|
copy(result[1:], result[0:]) |
||||||
|
result[0] = uint8(carry) |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Work2 返回给定数组的偏移布局矩阵
|
||||||
|
func Work2(nums []int) [][]int { |
||||||
|
n := len(nums) |
||||||
|
result := make([][]int, n) |
||||||
|
for i := 0; i < n; i++ { |
||||||
|
result[i] = make([]int, n) |
||||||
|
} |
||||||
|
|
||||||
|
colStart := 0 |
||||||
|
for _, num := range nums { |
||||||
|
for row, col := 0, colStart; row < n; row++ { |
||||||
|
result[row][col%n] = num |
||||||
|
col++ |
||||||
|
} |
||||||
|
|
||||||
|
colStart++ |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
// Work2type2 返回给定数组的偏移布局矩阵,另一种写法
|
||||||
|
func Work2type2(nums []int) [][]int { |
||||||
|
n := len(nums) |
||||||
|
result := make([][]int, n) |
||||||
|
for i := 0; i < n; i++ { |
||||||
|
result[i] = make([]int, n) |
||||||
|
} |
||||||
|
|
||||||
|
offset := 0 |
||||||
|
for row := 0; row < n; row++ { |
||||||
|
for col := 0; col < n; col++ { |
||||||
|
result[row][(offset+col)%n] = nums[col] |
||||||
|
} |
||||||
|
offset++ |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
// Work3 从外到里填充矩阵
|
||||||
|
func Work3(n int) [][]int { |
||||||
|
matrix := make([][]int, n) |
||||||
|
for i := range matrix { |
||||||
|
matrix[i] = make([]int, n) |
||||||
|
} |
||||||
|
|
||||||
|
// 逐层往里填充
|
||||||
|
num := 1 |
||||||
|
for layer := 0; layer < n/2; layer++ { |
||||||
|
// 方阵上边
|
||||||
|
for i := layer; i < n-layer; i++ { |
||||||
|
matrix[layer][i] = num |
||||||
|
num++ |
||||||
|
} |
||||||
|
|
||||||
|
// 方阵右边
|
||||||
|
for i := layer + 1; i < n-layer; i++ { |
||||||
|
matrix[i][n-layer-1] = num |
||||||
|
num++ |
||||||
|
} |
||||||
|
|
||||||
|
// 方阵下边
|
||||||
|
for i := n - layer - 2; i >= layer; i-- { |
||||||
|
matrix[n-layer-1][i] = num |
||||||
|
num++ |
||||||
|
} |
||||||
|
|
||||||
|
// 方阵左边
|
||||||
|
for i := n - layer - 2; i > layer; i-- { |
||||||
|
matrix[i][layer] = num |
||||||
|
num++ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 奇数阶中间位置需要手动设置
|
||||||
|
if n%2 != 0 { |
||||||
|
matrix[n/2][n/2] = n * n |
||||||
|
} |
||||||
|
|
||||||
|
return matrix |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
func Work4(n int) [][]int { |
||||||
|
matrix := make([][]int, n) |
||||||
|
// 逐行长度递减的上三角矩阵
|
||||||
|
for i := range matrix { |
||||||
|
matrix[i] = make([]int, n-i) |
||||||
|
} |
||||||
|
|
||||||
|
// 沿右上方向斜向上填充
|
||||||
|
num := 1 |
||||||
|
for i := 0; i < n; i++ { |
||||||
|
for j := 0; j <= i; j++ { |
||||||
|
matrix[i-j][j] = num |
||||||
|
num++ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return matrix |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
func Work5(n int) [][]int { |
||||||
|
matrix := make([][]int, n) |
||||||
|
for i := range matrix { |
||||||
|
matrix[i] = make([]int, n) |
||||||
|
} |
||||||
|
|
||||||
|
// 逐层往里填充
|
||||||
|
for layer := 0; layer < n/2; layer++ { |
||||||
|
// 方阵上边
|
||||||
|
for i := layer; i < n-layer; i++ { |
||||||
|
matrix[layer][i] = layer + 1 |
||||||
|
} |
||||||
|
|
||||||
|
// 方阵右边
|
||||||
|
for i := layer + 1; i < n-layer; i++ { |
||||||
|
matrix[i][n-layer-1] = layer + 1 |
||||||
|
} |
||||||
|
|
||||||
|
// 方阵下边
|
||||||
|
for i := n - layer - 2; i >= layer; i-- { |
||||||
|
matrix[n-layer-1][i] = layer + 1 |
||||||
|
} |
||||||
|
|
||||||
|
// 方阵左边
|
||||||
|
for i := n - layer - 2; i > layer; i-- { |
||||||
|
matrix[i][layer] = layer + 1 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 奇数阶中间位置需要手动设置
|
||||||
|
if n%2 != 0 { |
||||||
|
matrix[n/2][n/2] = n/2 + 1 |
||||||
|
} |
||||||
|
|
||||||
|
return matrix |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
package cap3 |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"testing" |
||||||
|
) |
||||||
|
|
||||||
|
func TestWork1(t *testing.T) { |
||||||
|
result := Work1(100) |
||||||
|
for _, b := range result { |
||||||
|
fmt.Print(b) |
||||||
|
} |
||||||
|
|
||||||
|
fmt.Println() |
||||||
|
} |
||||||
|
|
||||||
|
func _printMatrix(matrix [][]int) { |
||||||
|
for _, row := range matrix { |
||||||
|
for _, element := range row { |
||||||
|
fmt.Printf("%d\t", element) |
||||||
|
} |
||||||
|
fmt.Println() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestWork2(t *testing.T) { |
||||||
|
matrix := Work2([]int{5, 7, 4, 8, 9, 1}) |
||||||
|
_printMatrix(matrix) |
||||||
|
|
||||||
|
println("----------------") |
||||||
|
|
||||||
|
matrix = Work2type2([]int{5, 7, 4, 8, 9, 1}) |
||||||
|
_printMatrix(matrix) |
||||||
|
} |
||||||
|
|
||||||
|
func TestWork3(t *testing.T) { |
||||||
|
matrix := Work3(7) |
||||||
|
_printMatrix(matrix) |
||||||
|
|
||||||
|
fmt.Println("----------------") |
||||||
|
|
||||||
|
matrix = Work3(6) |
||||||
|
_printMatrix(matrix) |
||||||
|
} |
||||||
|
|
||||||
|
func TestWork4(t *testing.T) { |
||||||
|
matrix := Work4(5) |
||||||
|
_printMatrix(matrix) |
||||||
|
} |
||||||
|
|
||||||
|
func TestWork5(t *testing.T) { |
||||||
|
matrix := Work5(6) |
||||||
|
_printMatrix(matrix) |
||||||
|
|
||||||
|
fmt.Println("----------------") |
||||||
|
|
||||||
|
matrix = Work5(5) |
||||||
|
_printMatrix(matrix) |
||||||
|
|
||||||
|
fmt.Println("----------------") |
||||||
|
|
||||||
|
matrix = Work5(10) |
||||||
|
_printMatrix(matrix) |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
package cap4 |
@ -0,0 +1 @@ |
|||||||
|
package cap4 |
@ -0,0 +1 @@ |
|||||||
|
package cap5 |
@ -0,0 +1 @@ |
|||||||
|
package cap5 |
@ -0,0 +1,55 @@ |
|||||||
|
package common |
||||||
|
|
||||||
|
type Stack[T any] struct { |
||||||
|
data []*T |
||||||
|
} |
||||||
|
|
||||||
|
func NewStack[T any](size int) *Stack[T] { |
||||||
|
stack := Stack[T]{} |
||||||
|
if size != 0 { |
||||||
|
stack.data = make([]*T, 0, size) |
||||||
|
} else { |
||||||
|
stack.data = make([]*T, 0, 16) |
||||||
|
} |
||||||
|
|
||||||
|
return &stack |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Stack[T]) Push(element *T) *Stack[T] { |
||||||
|
s.data = append(s.data, element) |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Stack[T]) Pop() *T { |
||||||
|
if s.Size() == 0 { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
element := s.Top() |
||||||
|
s.data = s.data[:len(s.data)-1] |
||||||
|
return element |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Stack[T]) Top() *T { |
||||||
|
if s.Size() == 0 { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
return s.data[len(s.data)-1] |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Stack[T]) Bottom() *T { |
||||||
|
if s.Size() == 0 { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
return s.data[0] |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Stack[T]) Size() int { |
||||||
|
return len(s.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Stack[T]) Empty() bool { |
||||||
|
return s.Size() == 0 |
||||||
|
} |
Loading…
Reference in new issue