From 97674a63680a0894947485b80a866327da7fc976 Mon Sep 17 00:00:00 2001 From: lensfrex Date: Tue, 14 May 2024 21:18:10 +0800 Subject: [PATCH] format code --- .gitignore | 210 ++++++++++++++++++++++----------------------- README.md | 62 +++++++------- cap3/ex10.go | 42 ++++----- cap3/ex11.go | 26 +++--- cap3/ex12.go | 24 +++--- cap3/ex13.go | 32 +++---- cap3/ex14.go | 24 +++--- cap3/ex15.go | 28 +++--- cap3/ex16.go | 26 +++--- cap3/ex17.go | 70 +++++++-------- cap3/ex18.go | 164 +++++++++++++++++------------------ cap3/ex19.go | 238 +++++++++++++++++++++++++-------------------------- cap3/ex5.go | 102 +++++++++++----------- cap3/ex6.go | 146 +++++++++++++++---------------- cap3/ex7.go | 30 +++---- cap3/ex8.go | 40 ++++----- cap3/ex9.go | 32 +++---- 17 files changed, 648 insertions(+), 648 deletions(-) diff --git a/.gitignore b/.gitignore index 1acc3cb..d907ce3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,105 +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 +# 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 diff --git a/README.md b/README.md index ad7ccd3..e81eec4 100644 --- a/README.md +++ b/README.md @@ -1,32 +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`中的代码模式均为核心代码,不负责输出输入, +# 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负责实现。 \ No newline at end of file diff --git a/cap3/ex10.go b/cap3/ex10.go index 1f22e4f..7ea2a66 100644 --- a/cap3/ex10.go +++ b/cap3/ex10.go @@ -2,28 +2,28 @@ package cap3 // Ex10 从0~n的整数中取r个不同的数做一组,求所有可能的组合 func Ex10(n, r int, callback func(nums []int)) int { - if r > n { - return 0 - } + if r > n { + return 0 + } - count := 0 - combine := make([]int, r) + 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) - } - } - } + 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 + findCombine(n, r) + return count } diff --git a/cap3/ex11.go b/cap3/ex11.go index 3d1750e..8d75390 100644 --- a/cap3/ex11.go +++ b/cap3/ex11.go @@ -5,19 +5,19 @@ 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 - } + 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]++ - } - } + if _, exists := result[candidate]; !exists { + result[candidate] = 1 + } else { + result[candidate]++ + } + } - return result + return result } diff --git a/cap3/ex12.go b/cap3/ex12.go index d0c51a6..c40bb3b 100644 --- a/cap3/ex12.go +++ b/cap3/ex12.go @@ -4,18 +4,18 @@ 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 := make([]int, 8) + for _, height := range heights { + // 身高映射,上下限调整 + mapping := height/5 - 29 + if mapping < 0 { + mapping = 0 + } else if mapping > 7 { + mapping = 7 + } - result[mapping]++ - } + result[mapping]++ + } - return result + return result } diff --git a/cap3/ex13.go b/cap3/ex13.go index 194d153..acc9f95 100644 --- a/cap3/ex13.go +++ b/cap3/ex13.go @@ -4,23 +4,23 @@ type Subject int type Student int func Ex14(subjectPassedStudentMap map[Subject]Student) []Student { - result := make([]Student, 0) + result := make([]Student, 0) - // 学生及格科目数记录 - studentRecord := map[Student]int{} - for _, student := range subjectPassedStudentMap { - // 对当前学生及格科目计数 - if _, exists := studentRecord[student]; !exists { - studentRecord[student] = 1 - } else { - studentRecord[student]++ - } + // 学生及格科目数记录 + 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) - } - } + // 学生及格科目数已达到传入的科目数,即为全科及格 + if studentRecord[student] == len(subjectPassedStudentMap) { + result = append(result, student) + } + } - return result + return result } diff --git a/cap3/ex14.go b/cap3/ex14.go index f7877b6..049c8d7 100644 --- a/cap3/ex14.go +++ b/cap3/ex14.go @@ -1,25 +1,25 @@ package cap3 var _numberTexts = []string{ - "zero", "one", "two", "three", "four", - "five", "six", "seven", "eight", "nine", + "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)) - } + 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]]) - } + 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]) - } + for _, char := range num { + callback(_numberTexts[char-48]) + } } diff --git a/cap3/ex15.go b/cap3/ex15.go index 177329d..8ca418c 100644 --- a/cap3/ex15.go +++ b/cap3/ex15.go @@ -1,24 +1,24 @@ package cap3 var ( - cashes = []int{50, 20, 10, 5, 2, 1} + cashes = []int{50, 20, 10, 5, 2, 1} ) // Ex15 最少的纸币找零钱 func Ex15(amount, paid int) map[int]int { - result := 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 - } - } + // 还要找的钱 + change := paid - amount + for i, cash := range cashes { + // 当前面额需要找的张数,整除后结果为0说明当前面额不足以找零 + cashNum := change / cash + if cashNum != 0 { + result[i] = cashNum + // 当前面额找完后更新剩余未找余额 + change = change - cashNum*cash + } + } - return result + return result } diff --git a/cap3/ex16.go b/cap3/ex16.go index 9404149..18c7d06 100644 --- a/cap3/ex16.go +++ b/cap3/ex16.go @@ -3,20 +3,20 @@ package cap3 // Ex16 求x,其平方为一个各位数字互不相同的九位数 func Ex16(callback func(x, x2 int)) { Next: - for x := 10000; x < 32000; x++ { - numCntMap := map[int]bool{} + 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 - } + x2 := x * x + for i := x2; i >= 1; i /= 10 { + digit := i % 10 + // 当前数字已经出现过,直接跳过,找下一个x,如果没出现过,则做标记后看下一位数字情况 + if _, exists := numCntMap[digit]; exists { + continue Next + } - numCntMap[digit] = true - } + numCntMap[digit] = true + } - callback(x, x2) - } + callback(x, x2) + } } diff --git a/cap3/ex17.go b/cap3/ex17.go index b9e7153..0b57292 100644 --- a/cap3/ex17.go +++ b/cap3/ex17.go @@ -2,52 +2,52 @@ package cap3 // _node 链表节点,单向循环链表 type _node struct { - Value int - Next *_node + 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 + 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 + 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 - } + idx := 0 + for i := 2; i <= n; i++ { + idx = (idx + k) % i + } - return idx + return idx } diff --git a/cap3/ex18.go b/cap3/ex18.go index c24565e..91b2d6a 100644 --- a/cap3/ex18.go +++ b/cap3/ex18.go @@ -1,107 +1,107 @@ package cap3 import ( - "strings" + "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 - } + 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 - } - } + // 如果还有进位,则对下一个结果位添加进位,此时不会再有进位 + if carry != 0 { + resultIdx-- + result[resultIdx] += carry + } + } - zeroPrefix := true - sb := strings.Builder{} - for _, num := range result { - if zeroPrefix && num == 0 { - continue - } else { - zeroPrefix = false - } + zeroPrefix := true + sb := strings.Builder{} + for _, num := range result { + if zeroPrefix && num == 0 { + continue + } else { + zeroPrefix = false + } - sb.WriteByte(num + 48) - } + sb.WriteByte(num + 48) + } - return sb.String() + 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 - } + 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 - } - } + // 如果还有进位,则对下一个结果位添加进位,此时不会再有进位 + if carry != 0 { + resultIdx-- + result[resultIdx] += carry + } + } - return result + 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 - } + 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 - } + // 如果还有进位,则对下一个结果位添加进位,此时不会再有进位 + if carry != 0 { + resultIdx-- + result[resultIdx] += carry + } - bOffset++ - } + bOffset++ + } - return result + return result } diff --git a/cap3/ex19.go b/cap3/ex19.go index 62f1e51..ade448f 100644 --- a/cap3/ex19.go +++ b/cap3/ex19.go @@ -4,134 +4,134 @@ import "strings" // Ex19 高精度阶乘 func Ex19(n uint64) string { - result := []uint8{1} - for i := uint64(2); i <= n; i++ { - result = multiply(result, i) - } + result := []uint8{1} + for i := uint64(2); i <= n; i++ { + result = multiply(result, i) + } - return DigitSlice2String(result) + 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 + 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 + 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() + 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() } diff --git a/cap3/ex5.go b/cap3/ex5.go index b11af1e..047fccb 100644 --- a/cap3/ex5.go +++ b/cap3/ex5.go @@ -4,66 +4,66 @@ 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) - } + 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) + 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) + // 第二步:将 A 的珠子移动到 C + callback(a, c) - // 第三步:将剩余的 N-1 颗珠子从 B 移动到 C。此时 A 是中转站 - Ex5Recursive(beadNum-1, b, a, c, callback) - } + // 第三步:将剩余的 N-1 颗珠子从 B 移动到 C。此时 A 是中转站 + Ex5Recursive(beadNum-1, b, a, c, callback) + } } type _step struct { - n int - from, transit, to string + 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, - }) - } - } + 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, + }) + } + } } diff --git a/cap3/ex6.go b/cap3/ex6.go index 46c6ec1..8e15441 100644 --- a/cap3/ex6.go +++ b/cap3/ex6.go @@ -2,102 +2,102 @@ package cap3 // Ex6Output 例六的带输出结果 func Ex6Output(num int, callback func(nums []int)) { - Ex6RecursionOutput(num, callback) + 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) - } + 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 - } + 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逐级-1求划分数 + if m > 1 { + divider(num, m-1) + } - // m <= num,对剩余未加的数进行划分 - if m <= num { - divider(num-m, m) - } - } + // m <= num,对剩余未加的数进行划分 + if m <= num { + divider(num-m, m) + } + } - divider(num, num) - return count + 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 - } + 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) - } + // 最大划分大小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) - } - } + if m <= num { + // m <= num,对剩余未加的数进行划分,当前的m已经是划分中的一个成员,将其添加进dividedNums中 + divider(num-m, m, append(dividedNums, m), callback) + } + } - divider(num, num, make([]int, 0, num), 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 - } + 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] - } - } - } + // 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 result[num][divideMax] + } - return divider(num, num) + return divider(num, num) } diff --git a/cap3/ex7.go b/cap3/ex7.go index 8af8c22..fa6d193 100644 --- a/cap3/ex7.go +++ b/cap3/ex7.go @@ -2,25 +2,25 @@ package cap3 // Ex7 低位到高位输出正整数的数字 func Ex7(num uint64, algoType AlgoType, callback func(digit uint8)) { - switch algoType { - case AlgoTypeRecursion: - Ex7Recursion(num, callback) - default: - Ex7NoneRecursion(num, callback) - } + 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) - } + 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)) - } + for i := num; i >= 1; i /= 10 { + callback(uint8(i % 10)) + } } diff --git a/cap3/ex8.go b/cap3/ex8.go index d1fae3b..1e40648 100644 --- a/cap3/ex8.go +++ b/cap3/ex8.go @@ -2,33 +2,33 @@ package cap3 // Ex8 高位到低位输出正整数的数字 func Ex8(num uint64, algoType AlgoType, callback func(digit uint8)) { - switch algoType { - case AlgoTypeRecursion: - Ex8Recursion(num, callback) - default: - Ex8NoneRecursion(num, callback) - } + 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)) - } + 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)) - } + 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]) - } + for i := len(digits) - 1; i >= 0; i-- { + callback(digits[i]) + } } diff --git a/cap3/ex9.go b/cap3/ex9.go index e1aa4f5..2c44642 100644 --- a/cap3/ex9.go +++ b/cap3/ex9.go @@ -2,27 +2,27 @@ 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 - } + // 传进来的是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 + 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) - } + // 传进来的是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 - } + num /= 2 + } - return bits + return bits }