Add person data statistic

This commit is contained in:
YDZ
2021-01-12 23:34:07 +08:00
parent fbbc4ff73a
commit 4067a7858d
15 changed files with 843 additions and 522 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.toml

572
README.md

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
package models
type LeetCodeProblemAll struct {
UserName string `json:"user_name"`
NumSolved int32 `json:"num_solved"`
NumTotal int32 `json:"num_total"`
AcEasy int32 `json:"ac_easy"`
AcMedium int32 `json:"ac_medium"`
AcHard int32 `json:"ac_hard"`
StatStatusPairs []StatStatusPairs `json:"stat_status_pairs"`
FrequencyHigh int32 `json:"frequency_high"`
FrequencyMid int32 `json:"frequency_mid"`
CategorySlug string `json:"category_slug"`
}
type StatStatusPairs struct {
Stat Stat `json:"stat"`
Difficulty Difficulty `json:"difficulty"`
PaidOnly bool `json:"paid_only"`
IsFavor bool `json:"is_favor"`
Frequency float64 `json:"frequency"`
Progress float64 `json:"progress"`
}
type Stat struct {
QuestionTitle string `json:"question__title"`
QuestionTitleSlug string `json:"question__title_slug"`
TotalAcs float64 `json:"total_acs"`
TotalSubmitted float64 `json:"total_submitted"`
Acceptance string
Difficulty string
FrontendQuestionId int32 `json:"frontend_question_id"`
}
type Difficulty struct {
Level int32 `json:"level"`
}
var DifficultyMap = map[int32]string{
1: "Easy",
2: "Medium",
3: "Hard",
}

View File

@ -1,190 +0,0 @@
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
m "github.com/halfrost/LeetCode-Go/automation/models"
"html/template"
"io"
"io/ioutil"
"net/http"
"os"
"regexp"
"sort"
"strconv"
"strings"
)
var try int
func main() {
var (
result []m.StatStatusPairs
lpa m.LeetCodeProblemAll
)
body := getProblemAllList()
err := json.Unmarshal(body, &lpa)
if err != nil {
fmt.Println(err)
return
}
result = lpa.StatStatusPairs
mdrows := []m.Mdrow{}
for i := 0; i < len(result); i++ {
mdrows = append(mdrows, convertModel(result[i]))
}
sort.Sort(m.SortByQuestionId(mdrows))
solutionIds := loadSolutionsDir()
generateMdRows(solutionIds, mdrows)
// res, _ := json.Marshal(mdrows)
//writeFile("leetcode_problem", res)
mds := m.Mdrows{Mdrows: mdrows}
res, err := readFile("./template.markdown", "{{.AvailableTable}}", len(solutionIds), try, mds)
if err != nil {
fmt.Println(err)
return
}
writeFile("../README.md", res)
//makeReadmeFile(mds)
}
func getProblemAllList() []byte {
resp, err := http.Get("https://leetcode.com/api/problems/all/")
if err != nil {
fmt.Println(err)
return []byte{}
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return []byte{}
}
if resp.StatusCode == 200 {
fmt.Println("ok")
}
return body
}
func writeFile(fileName string, content []byte) {
file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0777)
if err != nil {
fmt.Println(err)
}
defer file.Close()
_, err = file.Write(content)
if err != nil {
fmt.Println(err)
}
fmt.Println("write file successful")
}
func convertModel(ssp m.StatStatusPairs) m.Mdrow {
res := m.Mdrow{}
res.FrontendQuestionId = ssp.Stat.FrontendQuestionId
res.QuestionTitle = ssp.Stat.QuestionTitle
res.QuestionTitleSlug = ssp.Stat.QuestionTitleSlug
res.Acceptance = fmt.Sprintf("%.1f%%", (ssp.Stat.TotalAcs/ssp.Stat.TotalSubmitted)*100)
res.Difficulty = m.DifficultyMap[ssp.Difficulty.Level]
res.Frequency = fmt.Sprintf("%f", ssp.Frequency)
return res
}
func loadSolutionsDir() []int {
files, err := ioutil.ReadDir("../leetcode/")
if err != nil {
fmt.Println(err)
}
solutionIds := []int{}
for _, f := range files {
if f.Name()[4] == '.' {
tmp, err := strconv.Atoi(f.Name()[:4])
if err != nil {
fmt.Println(err)
}
solutionIds = append(solutionIds, tmp)
}
}
sort.Ints(solutionIds)
try = len(files) - len(solutionIds)
fmt.Printf("读取了 %v 道题的题解,当前目录下有 %v 个文件(可能包含 .DS_Store),有 %v 道题在尝试中\n", len(solutionIds), len(files), len(files)-len(solutionIds))
return solutionIds
}
func generateMdRows(solutionIds []int, mdrows []m.Mdrow) {
for i := 0; i < len(solutionIds); i++ {
id := mdrows[solutionIds[i]-1].FrontendQuestionId
if solutionIds[i] == int(id) {
//fmt.Printf("id = %v i = %v solutionIds = %v\n", id, i, solutionIds[i])
mdrows[id-1].SolutionPath = fmt.Sprintf("[Go](https://github.com/halfrost/LeetCode-Go/tree/master/leetcode/%v)", fmt.Sprintf("%04d.%v", id, strings.Replace(mdrows[id-1].QuestionTitle, " ", "-", -1)))
} else {
fmt.Printf("序号出错了 solutionIds = %v id = %v\n", solutionIds[i], id)
}
}
fmt.Printf("")
}
func makeReadmeFile(mdrows m.Mdrows) {
file := "./README.md"
os.Remove(file)
var b bytes.Buffer
tmpl := template.Must(template.New("readme").Parse(readTMPL("template.markdown")))
err := tmpl.Execute(&b, mdrows)
if err != nil {
fmt.Println(err)
}
// 保存 README.md 文件
writeFile(file, b.Bytes())
}
func readTMPL(path string) string {
file, err := os.Open(path)
if err != nil {
fmt.Println(err)
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println(err)
}
return string(data)
}
func readFile(filePath, template string, total, try int, mdrows m.Mdrows) ([]byte, error) {
f, err := os.OpenFile(filePath, os.O_RDONLY, 0644)
if err != nil {
return nil, err
}
defer f.Close()
reader, output := bufio.NewReader(f), []byte{}
for {
line, _, err := reader.ReadLine()
if err != nil {
if err == io.EOF {
return output, nil
}
return nil, err
}
if ok, _ := regexp.Match(template, line); ok {
reg := regexp.MustCompile(template)
newByte := reg.ReplaceAll(line, []byte(mdrows.AvailableTable()))
output = append(output, newByte...)
output = append(output, []byte("\n")...)
} else if ok, _ := regexp.Match("{{.TotalNum}}", line); ok {
reg := regexp.MustCompile("{{.TotalNum}}")
newByte := reg.ReplaceAll(line, []byte(fmt.Sprintf("以下已经收录了 %v 道题的题解,还有 %v 道题在尝试优化到 beats 100%%", total, try)))
output = append(output, newByte...)
output = append(output, []byte("\n")...)
} else {
output = append(output, line...)
output = append(output, []byte("\n")...)
}
}
}

31
ctl/config.go Normal file
View File

@ -0,0 +1,31 @@
package main
import (
"fmt"
"log"
"github.com/BurntSushi/toml"
)
const (
configTOML = "config.toml"
)
type config struct {
Username string
Password string
Cookie string
}
func (c config) String() string {
return fmt.Sprintf("Username: %s, Password: %s", c.Username, c.Password)
}
func getConfig() *config {
cfg := new(config)
if _, err := toml.DecodeFile(configTOML, &cfg); err != nil {
log.Panicf(err.Error())
}
// log.Printf("get config: %s", cfg)
return cfg
}

103
ctl/models/lcproblems.go Normal file
View File

@ -0,0 +1,103 @@
package models
import (
"fmt"
)
// LeetCodeProblemAll define
type LeetCodeProblemAll struct {
UserName string `json:"user_name"`
NumSolved int32 `json:"num_solved"`
NumTotal int32 `json:"num_total"`
AcEasy int32 `json:"ac_easy"`
AcMedium int32 `json:"ac_medium"`
AcHard int32 `json:"ac_hard"`
StatStatusPairs []StatStatusPairs `json:"stat_status_pairs"`
FrequencyHigh int32 `json:"frequency_high"`
FrequencyMid int32 `json:"frequency_mid"`
CategorySlug string `json:"category_slug"`
AcEasyTotal int32
AcMediumTotal int32
AcHardTotal int32
}
// ConvertUserInfoModel define
func ConvertUserInfoModel(lpa LeetCodeProblemAll) UserInfo {
info := UserInfo{}
info.UserName = lpa.UserName
info.NumSolved = lpa.NumSolved
info.NumTotal = lpa.NumTotal
info.AcEasy = lpa.AcEasy
info.AcMedium = lpa.AcMedium
info.AcHard = lpa.AcHard
info.FrequencyHigh = lpa.FrequencyHigh
info.FrequencyMid = lpa.FrequencyMid
info.CategorySlug = lpa.CategorySlug
return info
}
// StatStatusPairs define
type StatStatusPairs struct {
Stat Stat `json:"stat"`
Status string `json:"status"`
Difficulty Difficulty `json:"difficulty"`
PaidOnly bool `json:"paid_only"`
IsFavor bool `json:"is_favor"`
Frequency float64 `json:"frequency"`
Progress float64 `json:"progress"`
}
// ConvertMdModel define
func ConvertMdModel(problems []StatStatusPairs) []Mdrow {
mdrows := []Mdrow{}
for _, problem := range problems {
res := Mdrow{}
res.FrontendQuestionID = problem.Stat.FrontendQuestionID
res.QuestionTitle = problem.Stat.QuestionTitle
res.QuestionTitleSlug = problem.Stat.QuestionTitleSlug
res.Acceptance = fmt.Sprintf("%.1f%%", (problem.Stat.TotalAcs/problem.Stat.TotalSubmitted)*100)
res.Difficulty = DifficultyMap[problem.Difficulty.Level]
res.Frequency = fmt.Sprintf("%f", problem.Frequency)
mdrows = append(mdrows, res)
}
return mdrows
}
// ConvertMdModelFromIds define
func ConvertMdModelFromIds(problemsMap map[int]StatStatusPairs, ids []int) []Mdrow {
mdrows := []Mdrow{}
for _, v := range ids {
res, problem := Mdrow{}, problemsMap[v]
res.FrontendQuestionID = problem.Stat.FrontendQuestionID
res.QuestionTitle = problem.Stat.QuestionTitle
res.QuestionTitleSlug = problem.Stat.QuestionTitleSlug
res.Acceptance = fmt.Sprintf("%.1f%%", (problem.Stat.TotalAcs/problem.Stat.TotalSubmitted)*100)
res.Difficulty = DifficultyMap[problem.Difficulty.Level]
res.Frequency = fmt.Sprintf("%f", problem.Frequency)
mdrows = append(mdrows, res)
}
return mdrows
}
// Stat define
type Stat struct {
QuestionTitle string `json:"question__title"`
QuestionTitleSlug string `json:"question__title_slug"`
TotalAcs float64 `json:"total_acs"`
TotalSubmitted float64 `json:"total_submitted"`
Acceptance string
Difficulty string
FrontendQuestionID int32 `json:"frontend_question_id"`
}
// Difficulty define
type Difficulty struct {
Level int32 `json:"level"`
}
// DifficultyMap define
var DifficultyMap = map[int32]string{
1: "Easy",
2: "Medium",
3: "Hard",
}

View File

@ -4,8 +4,9 @@ import (
"fmt" "fmt"
) )
// Mdrow define
type Mdrow struct { type Mdrow struct {
FrontendQuestionId int32 `json:"question_id"` FrontendQuestionID int32 `json:"question_id"`
QuestionTitle string `json:"question__title"` QuestionTitle string `json:"question__title"`
QuestionTitleSlug string `json:"question__title_slug"` QuestionTitleSlug string `json:"question__title_slug"`
SolutionPath string `json:"solution_path"` SolutionPath string `json:"solution_path"`
@ -16,18 +17,19 @@ type Mdrow struct {
// | 0001 | Two Sum | [Go](https://github.com/halfrost/LeetCode-Go/tree/master/leetcode/0001.Two-Sum)| 45.6% | Easy | | // | 0001 | Two Sum | [Go](https://github.com/halfrost/LeetCode-Go/tree/master/leetcode/0001.Two-Sum)| 45.6% | Easy | |
func (m Mdrow) tableLine() string { func (m Mdrow) tableLine() string {
return fmt.Sprintf("|%04d|%v|%v|%v|%v||\n", m.FrontendQuestionId, m.QuestionTitle, m.SolutionPath, m.Acceptance, m.Difficulty) return fmt.Sprintf("|%04d|%v|%v|%v|%v||\n", m.FrontendQuestionID, m.QuestionTitle, m.SolutionPath, m.Acceptance, m.Difficulty)
} }
// SortByQuestionId define // SortByQuestionID define
type SortByQuestionId []Mdrow type SortByQuestionID []Mdrow
func (a SortByQuestionId) Len() int { return len(a) } func (a SortByQuestionID) Len() int { return len(a) }
func (a SortByQuestionId) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a SortByQuestionID) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SortByQuestionId) Less(i, j int) bool { func (a SortByQuestionID) Less(i, j int) bool {
return a[i].FrontendQuestionId < a[j].FrontendQuestionId return a[i].FrontendQuestionID < a[j].FrontendQuestionID
} }
// Mdrows define
type Mdrows struct { type Mdrows struct {
Mdrows []Mdrow Mdrows []Mdrow
} }
@ -45,6 +47,7 @@ func (mds Mdrows) table() string {
return res return res
} }
// AvailableTable define
func (mds Mdrows) AvailableTable() string { func (mds Mdrows) AvailableTable() string {
return mds.table() return mds.table()
} }

44
ctl/models/user.go Normal file
View File

@ -0,0 +1,44 @@
package models
import (
"fmt"
)
// UserInfo define
type UserInfo struct {
UserName string `json:"user_name"`
NumSolved int32 `json:"num_solved"`
NumTotal int32 `json:"num_total"`
AcEasy int32 `json:"ac_easy"`
AcMedium int32 `json:"ac_medium"`
AcHard int32 `json:"ac_hard"`
EasyTotal int32
MediumTotal int32
HardTotal int32
OptimizingEasy int32
OptimizingMedium int32
OptimizingHard int32
FrequencyHigh int32 `json:"frequency_high"`
FrequencyMid int32 `json:"frequency_mid"`
CategorySlug string `json:"category_slug"`
}
// | | Easy | Medium | Hard | Total | optimizing |
// |:--------:|:--------------------------------------------------------------|:--------:|:--------:|:--------:|:--------:|
func (ui UserInfo) table() string {
res := "| | Easy | Medium | Hard | Total |\n"
res += "|:--------:|:--------:|:--------:|:--------:|:--------:|\n"
res += fmt.Sprintf("|Optimizing|%v|%v|%v|%v|\n", ui.OptimizingEasy, ui.OptimizingMedium, ui.OptimizingHard, ui.OptimizingEasy+ui.OptimizingMedium+ui.OptimizingHard)
res += fmt.Sprintf("|Accepted|**%v**|**%v**|**%v**|**%v**|\n", ui.AcEasy, ui.AcMedium, ui.AcHard, ui.AcEasy+ui.AcMedium+ui.AcHard)
res += fmt.Sprintf("|Total|%v|%v|%v|%v|\n", ui.EasyTotal, ui.MediumTotal, ui.HardTotal, ui.EasyTotal+ui.MediumTotal+ui.HardTotal)
res += fmt.Sprintf("|Perfection Rate|%.1f%%|%.1f%%|%.1f%%|%.1f%%|\n", (1-float64(ui.OptimizingEasy)/float64(ui.AcEasy))*100, (1-float64(ui.OptimizingMedium)/float64(ui.AcMedium))*100, (1-float64(ui.OptimizingHard)/float64(ui.AcHard))*100, (1-float64(ui.OptimizingEasy+ui.OptimizingMedium+ui.OptimizingHard)/float64(ui.AcEasy+ui.AcMedium+ui.AcHard))*100)
res += fmt.Sprintf("|Completion Rate|%.1f%%|%.1f%%|%.1f%%|%.1f%%|\n", float64(ui.AcEasy)/float64(ui.EasyTotal)*100, float64(ui.AcMedium)/float64(ui.MediumTotal)*100, float64(ui.AcHard)/float64(ui.HardTotal)*100, float64(ui.AcEasy+ui.AcMedium+ui.AcHard)/float64(ui.EasyTotal+ui.MediumTotal+ui.HardTotal)*100)
// 加这一行是为了撑开整个表格
res += "|------------|----------------------------|----------------------------|----------------------------|----------------------------|"
return res
}
// PersonalData define
func (ui UserInfo) PersonalData() string {
return ui.table()
}

36
ctl/rangking.go Normal file
View File

@ -0,0 +1,36 @@
package main
import (
"fmt"
"strconv"
"strings"
)
// getRanking 让这个方法优雅一点
func getRanking() int {
// 获取网页数据
URL := fmt.Sprintf("https://leetcode.com/%s/", getConfig().Username)
data := getRaw(URL)
str := string(data)
// 通过不断裁剪 str 获取排名信息
fmt.Println(str)
i := strings.Index(str, "ng-init")
j := i + strings.Index(str[i:], "ng-cloak")
str = str[i:j]
i = strings.Index(str, "(")
j = strings.Index(str, ")")
str = str[i:j]
// fmt.Println("2\n", str)
strs := strings.Split(str, ",")
str = strs[6]
// fmt.Println("1\n", str)
i = strings.Index(str, "'")
j = 2 + strings.Index(str[2:], "'")
// fmt.Println("0\n", str)
str = str[i+1 : j]
r, err := strconv.Atoi(str)
if err != nil {
fmt.Printf("无法把 %s 转换成数字Ranking", str)
}
return r
}

108
ctl/render.go Normal file
View File

@ -0,0 +1,108 @@
package main
import (
"bufio"
"encoding/json"
"fmt"
m "github.com/halfrost/LeetCode-Go/ctl/models"
"io"
"os"
"regexp"
"sort"
"strings"
)
func main() {
var (
problems []m.StatStatusPairs
lpa m.LeetCodeProblemAll
info m.UserInfo
)
// 请求所有题目信息
body := getProblemAllList(AllProblemURL)
problemsMap, optimizingIds := map[int]m.StatStatusPairs{}, []int{}
err := json.Unmarshal(body, &lpa)
if err != nil {
fmt.Println(err)
return
}
//writeFile("leetcode_problem.json", body)
// 拼凑 README 需要渲染的数据
problems = lpa.StatStatusPairs
info = m.ConvertUserInfoModel(lpa)
for _, v := range problems {
problemsMap[int(v.Stat.FrontendQuestionID)] = v
}
mdrows := m.ConvertMdModel(problems)
sort.Sort(m.SortByQuestionID(mdrows))
solutionIds, try := loadSolutionsDir()
generateMdRows(solutionIds, mdrows)
info.EasyTotal, info.MediumTotal, info.HardTotal, info.OptimizingEasy, info.OptimizingMedium, info.OptimizingHard, optimizingIds = statisticalData(problemsMap, solutionIds)
omdrows := m.ConvertMdModelFromIds(problemsMap, optimizingIds)
sort.Sort(m.SortByQuestionID(omdrows))
// 按照模板渲染 README
res, err := renderReadme("./template.markdown", len(solutionIds), try, m.Mdrows{Mdrows: mdrows}, m.Mdrows{Mdrows: omdrows}, info)
if err != nil {
fmt.Println(err)
return
}
writeFile("../README.md", res)
//makeReadmeFile(mds)
}
func generateMdRows(solutionIds []int, mdrows []m.Mdrow) {
for i := 0; i < len(solutionIds); i++ {
id := mdrows[solutionIds[i]-1].FrontendQuestionID
if solutionIds[i] == int(id) {
//fmt.Printf("id = %v i = %v solutionIds = %v\n", id, i, solutionIds[i])
mdrows[id-1].SolutionPath = fmt.Sprintf("[Go](https://github.com/halfrost/LeetCode-Go/tree/master/leetcode/%v)", fmt.Sprintf("%04d.%v", id, strings.Replace(mdrows[id-1].QuestionTitle, " ", "-", -1)))
} else {
fmt.Printf("序号出错了 solutionIds = %v id = %v\n", solutionIds[i], id)
}
}
}
func renderReadme(filePath string, total, try int, mdrows, omdrows m.Mdrows, user m.UserInfo) ([]byte, error) {
f, err := os.OpenFile(filePath, os.O_RDONLY, 0644)
if err != nil {
return nil, err
}
defer f.Close()
reader, output := bufio.NewReader(f), []byte{}
for {
line, _, err := reader.ReadLine()
if err != nil {
if err == io.EOF {
return output, nil
}
return nil, err
}
if ok, _ := regexp.Match("{{.AvailableTable}}", line); ok {
reg := regexp.MustCompile("{{.AvailableTable}}")
newByte := reg.ReplaceAll(line, []byte(mdrows.AvailableTable()))
output = append(output, newByte...)
output = append(output, []byte("\n")...)
} else if ok, _ := regexp.Match("{{.TotalNum}}", line); ok {
reg := regexp.MustCompile("{{.TotalNum}}")
newByte := reg.ReplaceAll(line, []byte(fmt.Sprintf("以下已经收录了 %v 道题的题解,还有 %v 道题在尝试优化到 beats 100%%", total, try)))
output = append(output, newByte...)
output = append(output, []byte("\n")...)
} else if ok, _ := regexp.Match("{{.PersonalData}}", line); ok {
reg := regexp.MustCompile("{{.PersonalData}}")
newByte := reg.ReplaceAll(line, []byte(user.PersonalData()))
output = append(output, newByte...)
output = append(output, []byte("\n")...)
} else if ok, _ := regexp.Match("{{.OptimizingTable}}", line); ok {
reg := regexp.MustCompile("{{.OptimizingTable}}")
newByte := reg.ReplaceAll(line, []byte(fmt.Sprintf("以下 %v 道题还需要优化到 100%% 的题目列表\n\n%v", (user.OptimizingEasy+user.OptimizingMedium+user.OptimizingHard), omdrows.AvailableTable())))
output = append(output, newByte...)
output = append(output, []byte("\n")...)
} else {
output = append(output, line...)
output = append(output, []byte("\n")...)
}
}
}

72
ctl/request.go Normal file
View File

@ -0,0 +1,72 @@
package main
import (
"fmt"
"github.com/mozillazg/request"
"io/ioutil"
"net/http"
)
const (
// AllProblemURL define
AllProblemURL = "https://leetcode.com/api/problems/all/"
// LoginPageURL define
LoginPageURL = "https://leetcode.com/accounts/login/"
// AlgorithmsURL define
AlgorithmsURL = "https://leetcode.com/api/problems/Algorithms/"
)
var req *request.Request
func newReq() *request.Request {
if req == nil {
req = signin()
}
return req
}
func signin() *request.Request {
cfg := getConfig()
req := request.NewRequest(new(http.Client))
req.Headers = map[string]string{
"Content-Type": "application/json",
"Accept-Encoding": "",
"cookie": cfg.Cookie,
"Referer": "https://leetcode.com/accounts/login/",
"origin": "https://leetcode.com",
}
return req
}
func getRaw(URL string) []byte {
req := newReq()
resp, err := req.Get(URL)
if err != nil {
fmt.Printf("getRaw: Get Error: " + err.Error())
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("getRaw: Read Error: " + err.Error())
}
return body
}
func getProblemAllList(URL string) []byte {
req := newReq()
resp, err := req.Get(URL)
if err != nil {
fmt.Println(err)
return []byte{}
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return []byte{}
}
if resp.StatusCode == 200 {
fmt.Println("ok")
}
return body
}

40
ctl/statistic.go Normal file
View File

@ -0,0 +1,40 @@
package main
import (
m "github.com/halfrost/LeetCode-Go/ctl/models"
"sort"
)
func statisticalData(problemsMap map[int]m.StatStatusPairs, solutionIds []int) (easyTotal, mediumTotal, hardTotal, optimizingEasy, optimizingMedium, optimizingHard int32, optimizingIds []int) {
easyTotal, mediumTotal, hardTotal, optimizingEasy, optimizingMedium, optimizingHard, optimizingIds = 0, 0, 0, 0, 0, 0, []int{}
for _, v := range problemsMap {
switch m.DifficultyMap[v.Difficulty.Level] {
case "Easy":
{
easyTotal++
if v.Status == "ac" && binarySearch(solutionIds, int(v.Stat.FrontendQuestionID)) == -1 {
optimizingEasy++
optimizingIds = append(optimizingIds, int(v.Stat.FrontendQuestionID))
}
}
case "Medium":
{
mediumTotal++
if v.Status == "ac" && binarySearch(solutionIds, int(v.Stat.FrontendQuestionID)) == -1 {
optimizingMedium++
optimizingIds = append(optimizingIds, int(v.Stat.FrontendQuestionID))
}
}
case "Hard":
{
hardTotal++
if v.Status == "ac" && binarySearch(solutionIds, int(v.Stat.FrontendQuestionID)) == -1 {
optimizingHard++
optimizingIds = append(optimizingIds, int(v.Stat.FrontendQuestionID))
}
}
}
}
sort.Ints(optimizingIds)
return easyTotal, mediumTotal, hardTotal, optimizingEasy, optimizingMedium, optimizingHard, optimizingIds
}

View File

@ -82,6 +82,9 @@
* [✅ Segment Tree](#segment-tree) * [✅ Segment Tree](#segment-tree)
* [✅ Binary Indexed Tree](#binary-indexed-tree) * [✅ Binary Indexed Tree](#binary-indexed-tree)
<br>
<br>
| 数据结构 | 变种 | 相关题目 | 讲解文章 | | 数据结构 | 变种 | 相关题目 | 讲解文章 |
|:-------:|:-------|:------|:------| |:-------:|:-------|:------|:------|
|顺序线性表:向量|||| |顺序线性表:向量||||
@ -118,7 +121,11 @@
## LeetCode Problems ## LeetCode Problems
## 一. 目录 ## 一. 个人数据
{{.PersonalData}}
## 二. 目录
{{.TotalNum}} {{.TotalNum}}
@ -133,7 +140,7 @@
------------------------------------------------------------------ ------------------------------------------------------------------
## .分类 ## .分类
## Array ## Array

37
ctl/template_render.go Normal file
View File

@ -0,0 +1,37 @@
package main
import (
"bytes"
"fmt"
m "github.com/halfrost/LeetCode-Go/ctl/models"
"html/template"
"io/ioutil"
"os"
)
func makeReadmeFile(mdrows m.Mdrows) {
file := "./README.md"
os.Remove(file)
var b bytes.Buffer
tmpl := template.Must(template.New("readme").Parse(readTMPL("template.markdown")))
err := tmpl.Execute(&b, mdrows)
if err != nil {
fmt.Println(err)
}
// 保存 README.md 文件
writeFile(file, b.Bytes())
}
func readTMPL(path string) string {
file, err := os.Open(path)
if err != nil {
fmt.Println(err)
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println(err)
}
return string(data)
}

58
ctl/util.go Normal file
View File

@ -0,0 +1,58 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"sort"
"strconv"
)
func loadSolutionsDir() ([]int, int) {
files, err := ioutil.ReadDir("../leetcode/")
if err != nil {
fmt.Println(err)
}
solutionIds := []int{}
for _, f := range files {
if f.Name()[4] == '.' {
tmp, err := strconv.Atoi(f.Name()[:4])
if err != nil {
fmt.Println(err)
}
solutionIds = append(solutionIds, tmp)
}
}
sort.Ints(solutionIds)
fmt.Printf("读取了 %v 道题的题解,当前目录下有 %v 个文件(可能包含 .DS_Store),目录中有 %v 道题在尝试中\n", len(solutionIds), len(files), len(files)-len(solutionIds))
return solutionIds, len(files) - len(solutionIds)
}
func writeFile(fileName string, content []byte) {
file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0777)
if err != nil {
fmt.Println(err)
}
defer file.Close()
_, err = file.Write(content)
if err != nil {
fmt.Println(err)
}
fmt.Println("write file successful")
}
func binarySearch(nums []int, target int) int {
low, high := 0, len(nums)-1
for low <= high {
mid := low + (high-low)>>1
if nums[mid] == target {
return mid
} else if nums[mid] > target {
high = mid - 1
} else {
low = mid + 1
}
}
return -1
}