├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── doc ├── CodeGenerator.java ├── db │ ├── db.sql │ └── problem-insert.sql ├── markdown │ ├── class-chedule.md │ └── images │ │ ├── index.png │ │ └── problem-list.png └── ziliao.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── aoeai │ │ └── lcsr │ │ ├── LeetCodeStudyRecordApplication.java │ │ ├── bo │ │ ├── user │ │ │ └── RegistOrLoginBo.java │ │ └── userproblem │ │ │ └── UserProblemBo.java │ │ ├── config │ │ ├── HandlerConfig.java │ │ └── MVCConfiguration.java │ │ ├── constant │ │ ├── AoeHttpStatus.java │ │ ├── KeyConstant.java │ │ ├── ResponseText.java │ │ └── TextConstant.java │ │ ├── controller │ │ ├── IndexController.java │ │ ├── ProblemController.java │ │ ├── UserController.java │ │ └── UserProblemController.java │ │ ├── dao │ │ ├── entity │ │ │ ├── LcsrProblem.java │ │ │ ├── LcsrProblemRecord.java │ │ │ ├── LcsrUser.java │ │ │ └── LcsrUserProblem.java │ │ ├── mapper │ │ │ ├── LcsrProblemMapper.java │ │ │ ├── LcsrProblemRecordMapper.java │ │ │ ├── LcsrUserMapper.java │ │ │ └── LcsrUserProblemMapper.java │ │ └── service │ │ │ ├── ILcsrProblemRecordService.java │ │ │ ├── ILcsrProblemService.java │ │ │ ├── ILcsrUserProblemService.java │ │ │ ├── ILcsrUserService.java │ │ │ └── impl │ │ │ ├── LcsrProblemRecordServiceImpl.java │ │ │ ├── LcsrProblemServiceImpl.java │ │ │ ├── LcsrUserProblemServiceImpl.java │ │ │ └── LcsrUserServiceImpl.java │ │ ├── enums │ │ ├── ProblemDifficultyEnum.java │ │ └── ProblemStatusEnum.java │ │ ├── form │ │ └── problem │ │ │ └── ProblemListForm.java │ │ ├── handler │ │ └── ErrorPageRegistrarHandler.java │ │ ├── service │ │ ├── ProblemRecordService.java │ │ ├── ProblemService.java │ │ ├── UserProblemService.java │ │ └── UserService.java │ │ ├── utils │ │ ├── Cipher.java │ │ ├── DateUtils.java │ │ ├── TextUtils.java │ │ └── page │ │ │ ├── Page.java │ │ │ ├── PageHelper.java │ │ │ └── Pagination.java │ │ └── vo │ │ ├── user │ │ ├── ProblemVo.java │ │ └── RegistOrLoginVo.java │ │ └── userproblem │ │ └── CurrentDoCountVo.java └── resources │ ├── application.yml │ ├── logback-spring.xml │ ├── mapper │ ├── LcsrProblemMapper.xml │ ├── LcsrProblemRecordMapper.xml │ ├── LcsrUserMapper.xml │ └── LcsrUserProblemMapper.xml │ ├── static │ ├── css │ │ └── signin.css │ └── images │ │ └── logo.png │ └── templates │ ├── common │ └── base.html │ ├── error.html │ ├── index.html │ └── problem │ └── list.html └── test └── java └── com └── aoeai └── lcsr └── LeetCodeStudyRecordApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | 27 | ### 过滤日志 ### 28 | /logging.path_IS_UNDEFINED/ 29 | /logs/ 30 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.5"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aoeai/leet-code-study-record/a9a40929527887e31aca3a69f5db7eb800419d42/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeetCode 刷题记录 助力无毒神掌学习 2 | 3 | - 感谢覃超小魔王传授无毒学习法 4 | - [课程表](doc/markdown/class-chedule.md) 5 | - [课程表小助手](https://github.com/aoeai/lcsr-helper) 6 | 7 | ## [在线地址](https://leetcode.aoeai.com/) 8 | 9 | ## 功能简介 10 | 11 | 1. LeetCode刷题记录工具。 12 | 2. 快速知道今天要刷哪道题(根据无毒法推算,半自动,但比记事本快很多)。 13 | 3. 适合对象:极客时间算法训练营学员、希望记录LeetCode刷题记录的朋友。 14 | 15 | ## 特别说明 16 | 1. 只做过简单测试,满足日常需求。 17 | 2. 注册用户时请慎重,因为没有修改用户名、密码的功能(最短均为1位)。 18 | 3. 个人开发,不能保证数据不丢失,不能作为重要数据存证。 19 | 4. 只有2个页面。 20 | 5. 主要功能需要登录后使用。 21 | 22 | ## 页面展示 23 | 24 | - 首页 25 | 26 | ![avatar](doc/markdown/images/index.png) 27 | 28 | 29 | - 问题列表 30 | ![avatar](doc/markdown/images/problem-list.png) 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /doc/CodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr; 2 | 3 | import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; 4 | import com.baomidou.mybatisplus.core.toolkit.StringPool; 5 | import com.baomidou.mybatisplus.core.toolkit.StringUtils; 6 | import com.baomidou.mybatisplus.generator.AutoGenerator; 7 | import com.baomidou.mybatisplus.generator.InjectionConfig; 8 | import com.baomidou.mybatisplus.generator.config.*; 9 | import com.baomidou.mybatisplus.generator.config.po.TableInfo; 10 | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; 11 | import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Scanner; 16 | 17 | public class CodeGenerator { 18 | 19 | /** 20 | * 读取控制台内容 21 | */ 22 | public static String scanner(String tip) { 23 | Scanner scanner = new Scanner(System.in); 24 | StringBuilder help = new StringBuilder(); 25 | help.append("请输入" + tip + ":"); 26 | System.out.println(help.toString()); 27 | if (scanner.hasNext()) { 28 | String ipt = scanner.next(); 29 | if (StringUtils.isNotEmpty(ipt)) { 30 | return ipt; 31 | } 32 | } 33 | throw new MybatisPlusException("请输入正确的" + tip + "!"); 34 | } 35 | 36 | public static void main(String[] args) { 37 | // 代码生成器 38 | AutoGenerator mpg = new AutoGenerator(); 39 | 40 | // 全局配置 41 | GlobalConfig gc = new GlobalConfig(); 42 | String projectPath = System.getProperty("user.dir") + "/"; 43 | //System.getProperty("user.dir"); 44 | gc.setOutputDir(projectPath + "src/main/java"); 45 | gc.setAuthor("aoe"); 46 | gc.setOpen(false); 47 | gc.setSwagger2(false); 48 | mpg.setGlobalConfig(gc); 49 | 50 | // 数据源配置 51 | DataSourceConfig dsc = new DataSourceConfig(); 52 | dsc.setUrl("jdbc:mysql://localhost:3306/aoeai-leet-code-study-record?useUnicode=true&useSSL=false&characterEncoding=utf8"); 53 | // dsc.setSchemaName("public"); 54 | dsc.setDriverName("com.mysql.cj.jdbc.Driver"); 55 | dsc.setUsername("test"); 56 | dsc.setPassword("123456"); 57 | mpg.setDataSource(dsc); 58 | 59 | // 输入的模块名:xxx.dao 60 | // 包配置 61 | PackageConfig pc = new PackageConfig(); 62 | pc.setModuleName(scanner("模块名")); 63 | pc.setParent("com.aoeai.lcsr"); 64 | mpg.setPackageInfo(pc); 65 | 66 | // 自定义配置 67 | InjectionConfig cfg = new InjectionConfig() { 68 | @Override 69 | public void initMap() { 70 | // to do nothing 71 | } 72 | }; 73 | 74 | // 如果模板引擎是 freemarker 75 | String templatePath = "/templates/mapper.xml.ftl"; 76 | // 如果模板引擎是 velocity 77 | // String templatePath = "/templates/mapper.xml.vm"; 78 | 79 | // 自定义输出配置 80 | List focList = new ArrayList<>(); 81 | // 自定义配置会被优先输出 82 | focList.add(new FileOutConfig(templatePath) { 83 | @Override 84 | public String outputFile(TableInfo tableInfo) { 85 | // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! 86 | return projectPath + "src/main/resources/mapper/" 87 | + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; 88 | } 89 | }); 90 | cfg.setFileOutConfigList(focList); 91 | mpg.setCfg(cfg); 92 | 93 | // 配置模板 94 | TemplateConfig templateConfig = new TemplateConfig(); 95 | 96 | // 配置自定义输出模板 97 | //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别 98 | // templateConfig.setEntity("templates/entity2.java"); 99 | // templateConfig.setService(); 100 | templateConfig.setController(null); // 不生成controller 101 | 102 | templateConfig.setXml(null); 103 | mpg.setTemplate(templateConfig); 104 | 105 | // 策略配置 106 | StrategyConfig strategy = new StrategyConfig(); 107 | strategy.setNaming(NamingStrategy.underline_to_camel); 108 | strategy.setColumnNaming(NamingStrategy.underline_to_camel); 109 | strategy.setEntityLombokModel(true); 110 | strategy.setInclude(scanner("表名,多个英文逗号分割").split(",")); 111 | //strategy.setSuperEntityColumns("id"); 112 | // strategy.setControllerMappingHyphenStyle(false); 113 | strategy.setTablePrefix(pc.getModuleName() + "_"); 114 | mpg.setStrategy(strategy); 115 | mpg.setTemplateEngine(new FreemarkerTemplateEngine()); 116 | mpg.execute(); 117 | 118 | // lcsr_problem,lcsr_problem_record,lcsr_user,lcsr_user_problem 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /doc/db/db.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.13 Distrib 5.7.17, for macos10.12 (x86_64) 2 | -- 3 | -- Host: 127.0.0.1 Database: aoeai-leet-code-study-record 4 | -- ------------------------------------------------------ 5 | -- Server version 5.7.21-enterprise-commercial-advanced 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!40101 SET NAMES utf8 */; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | 18 | -- 19 | -- Table structure for table `lcsr_problem` 20 | -- 21 | 22 | DROP TABLE IF EXISTS `lcsr_problem`; 23 | /*!40101 SET @saved_cs_client = @@character_set_client */; 24 | /*!40101 SET character_set_client = utf8 */; 25 | CREATE TABLE `lcsr_problem` ( 26 | `id` smallint(6) NOT NULL, 27 | `problem` varchar(500) NOT NULL COMMENT '问题', 28 | `problem_en` varchar(500) NOT NULL COMMENT '问题的英文版', 29 | `difficulty` tinyint(4) NOT NULL DEFAULT '1' COMMENT '难度 1:简单;2:中等;3困难', 30 | `tag` varchar(200) NOT NULL COMMENT '类型 (类型i的集合,例如 1,2)', 31 | PRIMARY KEY (`id`) 32 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='LeetCode问题'; 33 | /*!40101 SET character_set_client = @saved_cs_client */; 34 | 35 | -- 36 | -- Table structure for table `lcsr_problem_record` 37 | -- 38 | 39 | DROP TABLE IF EXISTS `lcsr_problem_record`; 40 | /*!40101 SET @saved_cs_client = @@character_set_client */; 41 | /*!40101 SET character_set_client = utf8 */; 42 | CREATE TABLE `lcsr_problem_record` ( 43 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', 44 | `user_id` int(11) NOT NULL COMMENT '用户id', 45 | `problem_id` smallint(6) NOT NULL COMMENT '问题id', 46 | `add_time` datetime NOT NULL COMMENT '添加时间', 47 | `is_delete` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除 0:为删除; 1:已删除', 48 | PRIMARY KEY (`id`), 49 | KEY `user_id_index` (`user_id`), 50 | KEY `problem_id_index` (`problem_id`) 51 | ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='刷题记录'; 52 | /*!40101 SET character_set_client = @saved_cs_client */; 53 | 54 | -- 55 | -- Table structure for table `lcsr_user` 56 | -- 57 | 58 | DROP TABLE IF EXISTS `lcsr_user`; 59 | /*!40101 SET @saved_cs_client = @@character_set_client */; 60 | /*!40101 SET character_set_client = utf8 */; 61 | CREATE TABLE `lcsr_user` ( 62 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', 63 | `username` varchar(100) NOT NULL COMMENT '用户名', 64 | `password` char(64) NOT NULL COMMENT '密码', 65 | `salt` char(64) NOT NULL COMMENT '密码干扰因子', 66 | `add_time` datetime NOT NULL COMMENT '添加时间', 67 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 68 | PRIMARY KEY (`id`), 69 | UNIQUE KEY `username_index` (`username`) USING BTREE, 70 | KEY `salt_index` (`salt`) 71 | ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='用户'; 72 | /*!40101 SET character_set_client = @saved_cs_client */; 73 | 74 | -- 75 | -- Table structure for table `lcsr_user_problem` 76 | -- 77 | 78 | DROP TABLE IF EXISTS `lcsr_user_problem`; 79 | /*!40101 SET @saved_cs_client = @@character_set_client */; 80 | /*!40101 SET character_set_client = utf8 */; 81 | CREATE TABLE `lcsr_user_problem` ( 82 | `id` int(11) NOT NULL AUTO_INCREMENT, 83 | `user_id` int(11) NOT NULL COMMENT '用户id', 84 | `problem_id` smallint(6) NOT NULL COMMENT '问题id', 85 | `do_count` smallint(6) NOT NULL DEFAULT '0' COMMENT '刷题次数', 86 | `status` tinyint(2) NOT NULL DEFAULT '1' COMMENT '''状态 1:未解答;2:已解答;3:尝试过;4:略懂;5:掌握;6:精通', 87 | `last_do_time` datetime NOT NULL COMMENT '最后做题时间', 88 | `add_time` datetime NOT NULL COMMENT '添加时间', 89 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 90 | PRIMARY KEY (`id`), 91 | UNIQUE KEY `user_id_problem_id_idnex` (`user_id`,`problem_id`), 92 | KEY `user_id_index` (`user_id`), 93 | KEY `problem_id_index` (`problem_id`) 94 | ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='用户刷题记录概要'; 95 | /*!40101 SET character_set_client = @saved_cs_client */; 96 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 97 | 98 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 99 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 100 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 101 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 102 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 103 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 104 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 105 | 106 | -- Dump completed on 2019-12-24 12:52:23 107 | -------------------------------------------------------------------------------- /doc/markdown/class-chedule.md: -------------------------------------------------------------------------------- 1 | # 课程表 2 | ## 第一周 3 | ### 实战 4 | | 题号 | 名称 | 难度 | 分类 | 备注 | 5 | | --- | --- | --- | --- | --- | 6 | | [146](https://leetcode.com/problems/lru-cache/discuss/?currentPage=1&orderBy=most_votes&query=) | [LRU缓存机制](https://leetcode-cn.com/problems/lru-cache/)| 🟡 中等 | 链表 | - | 7 | | [11](https://leetcode.com/problems/container-with-most-water/discuss/?currentPage=1&orderBy=most_votes&query=) | [盛最多水的容器](https://leetcode-cn.com/problems/container-with-most-water/)| 🟡 中等 | 数组 | - | 8 | | [283](https://leetcode.com/problems/move-zeroes/discuss/?currentPage=1&orderBy=most_votes&query=) | [移动零](https://leetcode-cn.com/problems/move-zeroes/)| 🟢 简单 | 数组 | - | 9 | | [70](https://leetcode.com/problems/climbing-stairs/discuss/?currentPage=1&orderBy=most_votes&query=) | [爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/)| 🟢 简单 | 数组 | - | 10 | | [15](https://leetcode.com/problems/3sum/discuss/?currentPage=1&orderBy=most_votes&query=) | [三数之和](https://leetcode-cn.com/problems/3sum/)| 🟡 中等 | 数组 | 高频老题 | 11 | | [206](https://leetcode.com/problems/reverse-linked-list/discuss/?currentPage=1&orderBy=most_votes&query=) | [反转链表](https://leetcode-cn.com/problems/reverse-linked-list/)| 🟢 简单 | 链表 | - | 12 | | [24](https://leetcode.com/problems/swap-nodes-in-pairs/discuss/?currentPage=1&orderBy=most_votes&query=) | [两两交换链表中的节点](https://leetcode-cn.com/problems/swap-nodes-in-pairs/)| 🟡 中等 | 链表 | - | 13 | | [141](https://leetcode.com/problems/linked-list-cycle/discuss/?currentPage=1&orderBy=most_votes&query=) | [环形链表](https://leetcode-cn.com/problems/linked-list-cycle/)| 🟢 简单 | 链表 | - | 14 | | [142](https://leetcode.com/problems/linked-list-cycle-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [环形链表 II](https://leetcode-cn.com/problems/linked-list-cycle-ii/)| 🟡 中等 | 链表 | - | 15 | | [25](https://leetcode.com/problems/reverse-nodes-in-k-group/discuss/?currentPage=1&orderBy=most_votes&query=) | [K 个一组翻转链表](https://leetcode-cn.com/problems/reverse-nodes-in-k-group/)| 🔴️ 困难 | 链表 | - | 16 | | [20](https://leetcode.com/problems/valid-parentheses/discuss/?currentPage=1&orderBy=most_votes&query=) | [有效的括号](https://leetcode-cn.com/problems/valid-parentheses/)| 🟢 简单 | 栈、队列 | - | 17 | | [155](https://leetcode.com/problems/min-stack/discuss/?currentPage=1&orderBy=most_votes&query=) | [最小栈](https://leetcode-cn.com/problems/min-stack/)| 🟢 简单 | 栈、队列 | - | 18 | | [84](https://leetcode.com/problems/largest-rectangle-in-histogram/discuss/?currentPage=1&orderBy=most_votes&query=) | [柱状图中最大的矩形](https://leetcode-cn.com/problems/largest-rectangle-in-histogram/)| 🔴️ 困难 | 栈、队列 | - | 19 | | [239](https://leetcode.com/problems/sliding-window-maximum/discuss/?currentPage=1&orderBy=most_votes&query=) | [滑动窗口最大值](https://leetcode-cn.com/problems/sliding-window-maximum/)| 🔴️ 困难 | 栈、队列 | - | 20 | 21 | ### 课后作业 22 | | 题号 | 名称 | 难度 | 分类 | 备注 | 23 | | --- | --- | --- | --- | --- | 24 | | [26](https://leetcode.com/problems/remove-duplicates-from-sorted-array/discuss/?currentPage=1&orderBy=most_votes&query=) | [删除排序数组中的重复项](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/)| 🟢 简单 | 数组、链表、跳表 | - | 25 | | [189](https://leetcode.com/problems/rotate-array/discuss/?currentPage=1&orderBy=most_votes&query=) | [旋转数组](https://leetcode-cn.com/problems/rotate-array/)| 🟢 简单 | 数组、链表、跳表 | - | 26 | | [21](https://leetcode.com/problems/merge-two-sorted-lists/discuss/?currentPage=1&orderBy=most_votes&query=) | [合并两个有序链表](https://leetcode-cn.com/problems/merge-two-sorted-lists/)| 🟢 简单 | 数组、链表、跳表 | - | 27 | | [88](https://leetcode.com/problems/merge-sorted-array/discuss/?currentPage=1&orderBy=most_votes&query=) | [合并两个有序数组](https://leetcode-cn.com/problems/merge-sorted-array/)| 🟢 简单 | 数组、链表、跳表 | - | 28 | | [1](https://leetcode.com/problems/two-sum/discuss/?currentPage=1&orderBy=most_votes&query=) | [两数之和](https://leetcode-cn.com/problems/two-sum/)| 🟢 简单 | 数组、链表、跳表 | - | 29 | | [283](https://leetcode.com/problems/move-zeroes/discuss/?currentPage=1&orderBy=most_votes&query=) | [移动零](https://leetcode-cn.com/problems/move-zeroes/)| 🟢 简单 | 数组、链表、跳表 | - | 30 | | [66](https://leetcode.com/problems/plus-one/discuss/?currentPage=1&orderBy=most_votes&query=) | [加一](https://leetcode-cn.com/problems/plus-one/)| 🟢 简单 | 数组、链表、跳表 | - | 31 | | [641](https://leetcode.com/problems/design-circular-deque/discuss/?currentPage=1&orderBy=most_votes&query=) | [设计循环双端队列](https://leetcode-cn.com/problems/design-circular-deque/)| 🟡 中等 | 栈、队列 | - | 32 | | [42](https://leetcode.com/problems/trapping-rain-water/discuss/?currentPage=1&orderBy=most_votes&query=) | [接雨水](https://leetcode-cn.com/problems/trapping-rain-water/)| 🔴️ 困难 | 栈、队列 | - | 33 | 34 | ## 第二周 35 | ### 实战 36 | | 题号 | 名称 | 难度 | 分类 | 备注 | 37 | | --- | --- | --- | --- | --- | 38 | | [70](https://leetcode.com/problems/climbing-stairs/discuss/?currentPage=1&orderBy=most_votes&query=) | [爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/)| 🟢 简单 | 泛型递归、树的递归 | - | 39 | | [22](https://leetcode.com/problems/generate-parentheses/discuss/?currentPage=1&orderBy=most_votes&query=) | [括号生成](https://leetcode-cn.com/problems/generate-parentheses/)| 🟡 中等 | 泛型递归、树的递归 | - | 40 | | [226](https://leetcode.com/problems/invert-binary-tree/discuss/?currentPage=1&orderBy=most_votes&query=) | [翻转二叉树](https://leetcode-cn.com/problems/invert-binary-tree/)| 🟢 简单 | 泛型递归、树的递归 | - | 41 | | [98](https://leetcode.com/problems/validate-binary-search-tree/discuss/?currentPage=1&orderBy=most_votes&query=) | [验证二叉搜索树](https://leetcode-cn.com/problems/validate-binary-search-tree/)| 🟡 中等 | 泛型递归、树的递归 | - | 42 | | [104](https://leetcode.com/problems/maximum-depth-of-binary-tree/discuss/?currentPage=1&orderBy=most_votes&query=) | [二叉树的最大深度](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/)| 🟢 简单 | 泛型递归、树的递归 | - | 43 | | [111](https://leetcode.com/problems/minimum-depth-of-binary-tree/discuss/?currentPage=1&orderBy=most_votes&query=) | [二叉树的最小深度](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/)| 🟢 简单 | 泛型递归、树的递归 | - | 44 | | [297](https://leetcode.com/problems/serialize-and-deserialize-binary-tree/discuss/?currentPage=1&orderBy=most_votes&query=) | [二叉树的序列化与反序列化](https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/)| 🔴️ 困难 | 泛型递归、树的递归 | - | 45 | 46 | ### 课后作业 47 | | 题号 | 名称 | 难度 | 分类 | 备注 | 48 | | --- | --- | --- | --- | --- | 49 | | [242](https://leetcode.com/problems/valid-anagram/discuss/?currentPage=1&orderBy=most_votes&query=) | [有效的字母异位词](https://leetcode-cn.com/problems/valid-anagram/)| 🟢 简单 | 哈希表、映射、集合 | ⭐️ 也是实战题目 | 50 | | [49](https://leetcode.com/problems/group-anagrams/discuss/?currentPage=1&orderBy=most_votes&query=) | [字母异位词分组](https://leetcode-cn.com/problems/group-anagrams/)| 🟡 中等 | 哈希表、映射、集合 | ⭐️ 也是实战题目 | 51 | | [1](https://leetcode.com/problems/two-sum/discuss/?currentPage=1&orderBy=most_votes&query=) | [两数之和](https://leetcode-cn.com/problems/two-sum/)| 🟢 简单 | 哈希表、映射、集合 | ⭐️ 也是实战题目 | 52 | | [94](https://leetcode.com/problems/binary-tree-inorder-traversal/discuss/?currentPage=1&orderBy=most_votes&query=) | [二叉树的中序遍历](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/)| 🟡 中等 | 树、二叉树、二叉搜索树 | ⭐️ 也是实战题目 | 53 | | [144](https://leetcode.com/problems/binary-tree-preorder-traversal/discuss/?currentPage=1&orderBy=most_votes&query=) | [二叉树的前序遍历](https://leetcode-cn.com/problems/binary-tree-preorder-traversal/)| 🟡 中等 | 树、二叉树、二叉搜索树 | ⭐️ 也是实战题目 | 54 | | [590](https://leetcode.com/problems/n-ary-tree-postorder-traversal/discuss/?currentPage=1&orderBy=most_votes&query=) | [N叉树的后序遍历](https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/)| 🟢 简单 | 树、二叉树、二叉搜索树 | ⭐️ 也是实战题目 | 55 | | [589](https://leetcode.com/problems/n-ary-tree-preorder-traversal/discuss/?currentPage=1&orderBy=most_votes&query=) | [N叉树的前序遍历](https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/)| 🟢 简单 | 树、二叉树、二叉搜索树 | ⭐️ 也是实战题目 | 56 | | [429](https://leetcode.com/problems/n-ary-tree-level-order-traversal/discuss/?currentPage=1&orderBy=most_votes&query=) | [N叉树的层序遍历](https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/)| 🟡 中等 | 树、二叉树、二叉搜索树 | ⭐️ 也是实战题目 | 57 | | [236](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/discuss/?currentPage=1&orderBy=most_votes&query=) | [二叉树的最近公共祖先](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/)| 🟡 中等 | 泛型递归、树的递归 | - | 58 | | [105](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/discuss/?currentPage=1&orderBy=most_votes&query=) | [从前序与中序遍历序列构造二叉树](https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/)| 🟡 中等 | 泛型递归、树的递归 | - | 59 | | [77](https://leetcode.com/problems/combinations/discuss/?currentPage=1&orderBy=most_votes&query=) | [组合](https://leetcode-cn.com/problems/combinations/)| 🟡 中等 | 泛型递归、树的递归 | - | 60 | | [46](https://leetcode.com/problems/permutations/discuss/?currentPage=1&orderBy=most_votes&query=) | [全排列](https://leetcode-cn.com/problems/permutations/)| 🟡 中等 | 泛型递归、树的递归 | - | 61 | | [47](https://leetcode.com/problems/permutations-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [全排列 II](https://leetcode-cn.com/problems/permutations-ii/)| 🟡 中等 | 泛型递归、树的递归 | - | 62 | 63 | ## 第三周 64 | ### 实战 65 | | 题号 | 名称 | 难度 | 分类 | 备注 | 66 | | --- | --- | --- | --- | --- | 67 | | [50](https://leetcode.com/problems/powx-n/discuss/?currentPage=1&orderBy=most_votes&query=) | [Pow(x, n)](https://leetcode-cn.com/problems/powx-n/)| 🟡 中等 | 分治、回溯 | - | 68 | | [78](https://leetcode.com/problems/subsets/discuss/?currentPage=1&orderBy=most_votes&query=) | [子集](https://leetcode-cn.com/problems/subsets/)| 🟡 中等 | 分治、回溯 | - | 69 | | [169](https://leetcode.com/problems/majority-element/discuss/?currentPage=1&orderBy=most_votes&query=) | [多数元素](https://leetcode-cn.com/problems/majority-element/)| 🟢 简单 | 分治、回溯 | 简单、但是高频 | 70 | | [17](https://leetcode.com/problems/letter-combinations-of-a-phone-number/discuss/?currentPage=1&orderBy=most_votes&query=) | [电话号码的字母组合](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/)| 🟡 中等 | 分治、回溯 | - | 71 | | [51](https://leetcode.com/problems/n-queens/discuss/?currentPage=1&orderBy=most_votes&query=) | [N皇后](https://leetcode-cn.com/problems/n-queens/)| 🔴 困难 | 分治、回溯 | - | 72 | | [102](https://leetcode.com/problems/binary-tree-level-order-traversal/discuss/?currentPage=1&orderBy=most_votes&query=) | [二叉树的层次遍历](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/)| 🟡 中等 | 深度优先、广度优先 | - | 73 | | [433](https://leetcode.com/problems/minimum-genetic-mutation/discuss/?currentPage=1&orderBy=most_votes&query=) | [最小基因变化](https://leetcode-cn.com/problems/minimum-genetic-mutation/)| 🟡 中等 | 深度优先、广度优先 | - | 74 | | [22](https://leetcode.com/problems/generate-parentheses/discuss/?currentPage=1&orderBy=most_votes&query=) | [括号生成](https://leetcode-cn.com/problems/generate-parentheses/)| 🟡 中等 | 深度优先、广度优先 | - | 75 | | [515](https://leetcode.com/problems/find-largest-value-in-each-tree-row/discuss/?currentPage=1&orderBy=most_votes&query=) | [在每个树行中找最大值](https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/)| 🟡 中等 | 深度优先、广度优先 | - | 76 | | [69](https://leetcode.com/problems/sqrtx/discuss/?currentPage=1&orderBy=most_votes&query=) | [x 的平方根](https://leetcode-cn.com/problems/sqrtx/)| 🟢 简单 | 二分查找 | - | 77 | | [367](https://leetcode.com/problems/valid-perfect-square/discuss/?currentPage=1&orderBy=most_votes&query=) | [有效的完全平方数](https://leetcode-cn.com/problems/valid-perfect-square/)| 🟢 简单 | 二分查找 | - | 78 | 79 | 80 | ### 课后作业 81 | 82 | | 题号 | 名称 | 难度 | 分类 | 备注 | 83 | | --- | --- | --- | --- | --- | 84 | | [127](https://leetcode.com/problems/word-ladder/discuss/?currentPage=1&orderBy=most_votes&query=) | [单词接龙](https://leetcode-cn.com/problems/word-ladder/)| 🟡 中等 | 深度优先、广度优先 | 硅谷高频 | 85 | | [126](https://leetcode.com/problems/word-ladder-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [单词接龙 II](https://leetcode-cn.com/problems/word-ladder-ii/)| 🔴 困难 | 深度优先、广度优先 | 硅谷高频 | 86 | | [200](https://leetcode.com/problems/number-of-islands/discuss/?currentPage=1&orderBy=most_votes&query=) | [岛屿数量](https://leetcode-cn.com/problems/number-of-islands/)| 🟡 中等 | 深度优先、广度优先 | - | 87 | | [529](https://leetcode.com/problems/minesweeper/discuss/?currentPage=1&orderBy=most_votes&query=) | [扫雷游戏](https://leetcode-cn.com/problems/minesweeper/)| 🟡 中等 | 深度优先、广度优先 | - | 88 | | [860](https://leetcode.com/problems/lemonade-change/discuss/?currentPage=1&orderBy=most_votes&query=) | [柠檬水找零](https://leetcode-cn.com/problems/lemonade-change/)| 🟢 简单 | 贪心算法 | - | 89 | | [122](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [买卖股票的最佳时机 II](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/)| 🟢 简单 | 贪心算法 | - | 90 | | [455](https://leetcode.com/problems/assign-cookies/discuss/?currentPage=1&orderBy=most_votes&query=) | [分发饼干](https://leetcode-cn.com/problems/assign-cookies/)| 🟢 简单 | 贪心算法 | - | 91 | | [874](https://leetcode.com/problems/walking-robot-simulation/discuss/?currentPage=1&orderBy=most_votes&query=) | [模拟行走机器人](https://leetcode-cn.com/problems/walking-robot-simulation/)| 🟢 简单 | 贪心算法 | - | 92 | | [55](https://leetcode.com/problems/jump-game/discuss/?currentPage=1&orderBy=most_votes&query=) | [跳跃游戏](https://leetcode-cn.com/problems/jump-game/)| 🟡 中等 | 贪心算法 | - | 93 | | [33](https://leetcode.com/problems/search-in-rotated-sorted-array/discuss/?currentPage=1&orderBy=most_votes&query=) | [搜索旋转排序数组](https://leetcode-cn.com/problems/search-in-rotated-sorted-array/)| 🟡 中等 | 二分查找 | - | 94 | | [74](https://leetcode.com/problems/search-a-2d-matrix/discuss/?currentPage=1&orderBy=most_votes&query=) | [搜索二维矩阵](https://leetcode-cn.com/problems/search-a-2d-matrix/)| 🟡 中等 | 二分查找 | - | 95 | | [153](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/discuss/?currentPage=1&orderBy=most_votes&query=) | [寻找旋转排序数组中的最小值](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/)| 🟡 中等 | 二分查找 | - | 96 | 97 | ## 第五周 98 | 99 | ### 实战 100 | | 题号 | 名称 | 难度 | 分类 | 备注 | 101 | | --- | --- | --- | --- | --- | 102 | | [62](https://leetcode.com/problems/unique-paths/discuss/?currentPage=1&orderBy=most_votes&query=) | [不同路径](https://leetcode-cn.com/problems/unique-paths/)| 🟡 中等 | 动态规划 | - | 103 | | [63](https://leetcode.com/problems/unique-paths-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [不同路径 II](https://leetcode-cn.com/problems/unique-paths-ii/)| 🟡 中等 | 动态规划 | - | 104 | | [1143](https://leetcode.com/problems/longest-common-subsequence/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长公共子序列](https://leetcode-cn.com/problems/longest-common-subsequence/)| 🟡 中等 | 动态规划 | - | 105 | | [70](https://leetcode.com/problems/climbing-stairs/discuss/?currentPage=1&orderBy=most_votes&query=) | [爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/)| 🟢 简单 | 动态规划 | - | 106 | | [120](https://leetcode.com/problems/triangle/discuss/?currentPage=1&orderBy=most_votes&query=) | [三角形最小路径和](https://leetcode-cn.com/problems/triangle/)| 🟡 中等 | 动态规划 | - | 107 | | [53](https://leetcode.com/problems/maximum-subarray/discuss/?currentPage=1&orderBy=most_votes&query=) | [最大子序和](https://leetcode-cn.com/problems/maximum-subarray/)| 🟢 简单 | 动态规划 | - | 108 | | [152](https://leetcode.com/problems/maximum-product-subarray/discuss/?currentPage=1&orderBy=most_votes&query=) | [乘积最大子序列](https://leetcode-cn.com/problems/maximum-product-subarray/)| 🟡 中等 | 动态规划 | - | 109 | | [322](https://leetcode.com/problems/coin-change/discuss/?currentPage=1&orderBy=most_votes&query=) | [零钱兑换](https://leetcode-cn.com/problems/coin-change/)| 🟡 中等 | 动态规划 | - | 110 | | [198](https://leetcode.com/problems/house-robber/discuss/?currentPage=1&orderBy=most_votes&query=) | [打家劫舍](https://leetcode-cn.com/problems/house-robber/)| 🟢 简单 | 动态规划 | - | 111 | | [213](https://leetcode.com/problems/house-robber-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [打家劫舍 II](https://leetcode-cn.com/problems/house-robber-ii/)| 🟡 中等 | 动态规划 | - | 112 | | [121](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/discuss/?currentPage=1&orderBy=most_votes&query=) | [买卖股票的最佳时机](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/)| 🟢 简单 | 动态规划 | - | 113 | | [122](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [买卖股票的最佳时机 II](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/)| 🟢 简单 | 动态规划 | - | 114 | | [123](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/discuss/?currentPage=1&orderBy=most_votes&query=) | [买卖股票的最佳时机 III](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/)| 🔴️ 困难 | 动态规划 | - | 115 | | [309](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/discuss/?currentPage=1&orderBy=most_votes&query=) | [最佳买卖股票时机含冷冻期](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/)| 🟡 中等 | 动态规划 | - | 116 | | [188](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/discuss/?currentPage=1&orderBy=most_votes&query=) | [买卖股票的最佳时机 IV](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/)| 🔴️ 困难 | 动态规划 | - | 117 | | [714](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/discuss/?currentPage=1&orderBy=most_votes&query=) | [买卖股票的最佳时机含手续费](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/)| 🟡 中等 | 动态规划 | - | 118 | 119 | ### 高级 DP 实战 120 | | 题号 | 名称 | 难度 | 分类 | 备注 | 121 | | --- | --- | --- | --- | --- | 122 | | [279](https://leetcode.com/problems/perfect-squares/discuss/?currentPage=1&orderBy=most_votes&query=) | [完全平方数](https://leetcode-cn.com/problems/perfect-squares/)| 🟡 中等 | 动态规划 | - | 123 | | [72](https://leetcode.com/problems/edit-distance/discuss/?currentPage=1&orderBy=most_votes&query=) | [编辑距离](https://leetcode-cn.com/problems/edit-distance/)| 🔴️ 困难 | 动态规划 | 重点| 124 | | [55](https://leetcode.com/problems/jump-game/discuss/?currentPage=1&orderBy=most_votes&query=) | [跳跃游戏](https://leetcode-cn.com/problems/jump-game/)| 🟡 中等 | 动态规划 | - | 125 | | [45](https://leetcode.com/problems/jump-game-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [跳跃游戏 II](https://leetcode-cn.com/problems/jump-game-ii/)| 🔴️ 困难 | 动态规划 | - | 126 | | [62](https://leetcode.com/problems/unique-paths/discuss/?currentPage=1&orderBy=most_votes&query=) | [不同路径](https://leetcode-cn.com/problems/unique-paths/)| 🟡 中等 | 动态规划 | - | 127 | | [63](https://leetcode.com/problems/unique-paths-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [不同路径 II](https://leetcode-cn.com/problems/unique-paths-ii/)| 🟡 中等 | 动态规划 | - | 128 | | [980](https://leetcode.com/problems/unique-paths-iii/discuss/?currentPage=1&orderBy=most_votes&query=) | [不同路径 III](https://leetcode-cn.com/problems/unique-paths-iii/)| 🔴️ 困难 | 动态规划 | - | 129 | | [322](https://leetcode.com/problems/coin-change/discuss/?currentPage=1&orderBy=most_votes&query=) | [零钱兑换](https://leetcode-cn.com/problems/coin-change/)| 🟡 中等 | 动态规划 | - | 130 | | [518](https://leetcode.com/problems/coin-change-2/discuss/?currentPage=1&orderBy=most_votes&query=) | [零钱兑换 II](https://leetcode-cn.com/problems/coin-change-2/)| 🟡 中等 | 动态规划 | - | 131 | 132 | ### 课后作业 133 | | 题号 | 名称 | 难度 | 分类 | 备注 | 134 | | --- | --- | --- | --- | --- | 135 | | [32](https://leetcode.com/problems/longest-valid-parentheses/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长有效括号](https://leetcode-cn.com/problems/longest-valid-parentheses/)| 🔴️ 困难 | 动态规划 | - | 136 | | [64](https://leetcode.com/problems/minimum-path-sum/discuss/?currentPage=1&orderBy=most_votes&query=) | [最小路径和](https://leetcode-cn.com/problems/minimum-path-sum/)| 🟡 中等 | 动态规划 | - | 137 | | [72](https://leetcode.com/problems/edit-distance/discuss/?currentPage=1&orderBy=most_votes&query=) | [编辑距离](https://leetcode-cn.com/problems/edit-distance/)| 🔴️ 困难 | 动态规划 | - | 138 | | [91](https://leetcode.com/problems/decode-ways/discuss/?currentPage=1&orderBy=most_votes&query=) | [解码方法](https://leetcode-cn.com/problems/decode-ways/)| 🟡 中等 | 动态规划 | - | 139 | | [221](https://leetcode.com/problems/maximal-square/discuss/?currentPage=1&orderBy=most_votes&query=) | [最大正方形](https://leetcode-cn.com/problems/maximal-square/)| 🟡 中等 | 动态规划 | - | 140 | | [363](https://leetcode.com/problems/max-sum-of-rectangle-no-larger-than-k/discuss/?currentPage=1&orderBy=most_votes&query=) | [矩形区域不超过 K 的最大数值和](https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/)| 🔴️ 困难 | 动态规划 | - | 141 | | [403](https://leetcode.com/problems/frog-jump/discuss/?currentPage=1&orderBy=most_votes&query=) | [青蛙过河](https://leetcode-cn.com/problems/frog-jump/)| 🔴️ 困难 | 动态规划 | - | 142 | | [410](https://leetcode.com/problems/split-array-largest-sum/discuss/?currentPage=1&orderBy=most_votes&query=) | [分割数组的最大值](https://leetcode-cn.com/problems/split-array-largest-sum/)| 🔴️ 困难 | 动态规划 | - | 143 | | [552](https://leetcode.com/problems/student-attendance-record-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [学生出勤记录 II](https://leetcode-cn.com/problems/student-attendance-record-ii/)| 🔴️ 困难 | 动态规划 | - | 144 | | [621](https://leetcode.com/problems/task-scheduler/discuss/?currentPage=1&orderBy=most_votes&query=) | [任务调度器](https://leetcode-cn.com/problems/task-scheduler/)| 🟡 中等 | 动态规划 | - | 145 | | [647](https://leetcode.com/problems/palindromic-substrings/discuss/?currentPage=1&orderBy=most_votes&query=) | [回文子串](https://leetcode-cn.com/problems/palindromic-substrings/)| 🟡 中等 | 动态规划 | - | 146 | | [76](https://leetcode.com/problems/minimum-window-substring/discuss/?currentPage=1&orderBy=most_votes&query=) | [最小覆盖子串](https://leetcode-cn.com/problems/minimum-window-substring/)| 🔴️ 困难 | 动态规划 | - | 147 | | [312](https://leetcode.com/problems/burst-balloons/discuss/?currentPage=1&orderBy=most_votes&query=) | [戳气球](https://leetcode-cn.com/problems/burst-balloons/)| 🔴️ 困难 | 动态规划 | - | 148 | 149 | ### 补充学习 150 | - [MIT 动态规划课程最短路径算法](https://www.bilibili.com/video/av53233912?from=search&seid=2847395688604491997) 151 | 152 | ### 优秀解答 153 | - [120. 三角形最小路径和](https://leetcode.com/problems/triangle/discuss/38735/Python-easy-to-understand-solutions-(top-down-bottom-up)) 154 | - [121. 买卖股票的最佳时机](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/) 155 | 156 | ## 第六周 157 | ### 实战 158 | | 题号 | 名称 | 难度 | 分类 | 备注 | 159 | | --- | --- | --- | --- | --- | 160 | | [208](https://leetcode.com/problems/implement-trie-prefix-tree/discuss/?currentPage=1&orderBy=most_votes&query=) | [实现 Trie (前缀树)](https://leetcode-cn.com/problems/implement-trie-prefix-tree/)| 🟡 中等 | Trie树 | - | 161 | | [212](https://leetcode.com/problems/word-search-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [单词搜索 II](https://leetcode-cn.com/problems/word-search-ii/)| 🔴️ 困难 | Trie树 | - | 162 | | [547](https://leetcode.com/problems/friend-circles/discuss/?currentPage=1&orderBy=most_votes&query=) | [朋友圈](https://leetcode-cn.com/problems/friend-circles/)| 🟡 中等 | 并查集 | - | 163 | | [200](https://leetcode.com/problems/number-of-islands/discuss/?currentPage=1&orderBy=most_votes&query=) | [岛屿数量](https://leetcode-cn.com/problems/number-of-islands/)| 🟡 中等 | 并查集 | - | 164 | | [130](https://leetcode.com/problems/surrounded-regions/discuss/?currentPage=1&orderBy=most_votes&query=) | [被围绕的区域](https://leetcode-cn.com/problems/surrounded-regions/)| 🟡 中等 | 并查集 | - | 165 | | [70](https://leetcode.com/problems/climbing-stairs/discuss/?currentPage=1&orderBy=most_votes&query=) | [爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/)| 🟢 简单 | 剪枝 | - | 166 | | [22](https://leetcode.com/problems/generate-parentheses/discuss/?currentPage=1&orderBy=most_votes&query=) | [括号生成](https://leetcode-cn.com/problems/generate-parentheses/)| 🟡 中等 | 剪枝 | - | 167 | | [51](https://leetcode.com/problems/n-queens/discuss/?currentPage=1&orderBy=most_votes&query=) | [N皇后](https://leetcode-cn.com/problems/n-queens/)| 🔴️ 困难 | 剪枝 | - | 168 | | [36](https://leetcode.com/problems/valid-sudoku/discuss/?currentPage=1&orderBy=most_votes&query=) | [有效的数独](https://leetcode-cn.com/problems/valid-sudoku/)| 🟡 中等 | 剪枝 | - | 169 | | [37](https://leetcode.com/problems/sudoku-solver/discuss/?currentPage=1&orderBy=most_votes&query=) | [解数独](https://leetcode-cn.com/problems/sudoku-solver/)| 🔴️ 困难 | 剪枝 | - | 170 | | [127](https://leetcode.com/problems/word-ladder/discuss/?currentPage=1&orderBy=most_votes&query=) | [单词接龙](https://leetcode-cn.com/problems/word-ladder/)| 🟡 中等 | 双向BFS | - | 171 | | [433](https://leetcode.com/problems/minimum-genetic-mutation/discuss/?currentPage=1&orderBy=most_votes&query=) | [最小基因变化](https://leetcode-cn.com/problems/minimum-genetic-mutation/)| 🟡 中等 | 双向BFS | - | 172 | | [1091](https://leetcode.com/problems/shortest-path-in-binary-matrix/discuss/?currentPage=1&orderBy=most_votes&query=) | [二进制矩阵中的最短路径](https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/)| 🟡 中等 | 启发式搜索 | - | 173 | | [773](https://leetcode.com/problems/sliding-puzzle/discuss/?currentPage=1&orderBy=most_votes&query=) | [滑动谜题](https://leetcode-cn.com/problems/sliding-puzzle/)| 🔴️ 困难 | 启发式搜索 | - | 174 | | [37](https://leetcode.com/problems/sudoku-solver/discuss/?currentPage=1&orderBy=most_votes&query=) | [解数独](https://leetcode-cn.com/problems/sudoku-solver/)| 🔴️ 困难 | 启发式搜索 | - | 175 | 176 | ### 课后作业 177 | | 题号 | 名称 | 难度 | 分类 | 备注 | 178 | | --- | --- | --- | --- | --- | 179 | | [208](https://leetcode.com/problems/implement-trie-prefix-tree/discuss/?currentPage=1&orderBy=most_votes&query=) | [实现 Trie (前缀树)](https://leetcode-cn.com/problems/implement-trie-prefix-tree/)| 🟡 中等 | 字典树、并查集 | - | 180 | | [547](https://leetcode.com/problems/friend-circles/discuss/?currentPage=1&orderBy=most_votes&query=) | [朋友圈](https://leetcode-cn.com/problems/friend-circles/)| 🟡 中等 | 字典树、并查集 | - | 181 | | [200](https://leetcode.com/problems/number-of-islands/discuss/?currentPage=1&orderBy=most_votes&query=) | [岛屿数量](https://leetcode-cn.com/problems/number-of-islands/)| 🟡 中等 | 字典树、并查集 | - | 182 | | [130](https://leetcode.com/problems/surrounded-regions/discuss/?currentPage=1&orderBy=most_votes&query=) | [被围绕的区域](https://leetcode-cn.com/problems/surrounded-regions/)| 🟡 中等 | 字典树、并查集 | - | 183 | | [212](https://leetcode.com/problems/word-search-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [单词搜索 II](https://leetcode-cn.com/problems/word-search-ii/)| 🔴️ 困难 | 字典树、并查集 | - | 184 | | [70](https://leetcode.com/problems/climbing-stairs/discuss/?currentPage=1&orderBy=most_votes&query=) | [爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/)| 🟢 简单 | 高级搜索 | - | 185 | | [36](https://leetcode.com/problems/valid-sudoku/discuss/?currentPage=1&orderBy=most_votes&query=) | [有效的数独](https://leetcode-cn.com/problems/valid-sudoku/)| 🟡 中等 | 高级搜索 | - | 186 | | [22](https://leetcode.com/problems/generate-parentheses/discuss/?currentPage=1&orderBy=most_votes&query=) | [括号生成](https://leetcode-cn.com/problems/generate-parentheses/)| 🟡 中等 | 高级搜索 | - | 187 | | [127](https://leetcode.com/problems/word-ladder/discuss/?currentPage=1&orderBy=most_votes&query=) | [单词接龙](https://leetcode-cn.com/problems/word-ladder/)| 🟡 中等 | 高级搜索 | 硅谷高频 | 188 | | [433](https://leetcode.com/problems/minimum-genetic-mutation/discuss/?currentPage=1&orderBy=most_votes&query=) | [最小基因变化](https://leetcode-cn.com/problems/minimum-genetic-mutation/)| 🟡 中等 | 高级搜索 | - | 189 | | [51](https://leetcode.com/problems/n-queens/discuss/?currentPage=1&orderBy=most_votes&query=) | [N皇后](https://leetcode-cn.com/problems/n-queens/)| 🔴️ 困难 | 高级搜索 | - | 190 | | [37](https://leetcode.com/problems/sudoku-solver/discuss/?currentPage=1&orderBy=most_votes&query=) | [解数独](https://leetcode-cn.com/problems/sudoku-solver/)| 🔴️ 困难 | 高级搜索 | - | 191 | 192 | ## 第七周 193 | ### 实战 / 课后作业 194 | | 题号 | 名称 | 难度 | 分类 | 备注 | 195 | | --- | --- | --- | --- | --- | 196 | | [191](https://leetcode.com/problems/number-of-1-bits/discuss/?currentPage=1&orderBy=most_votes&query=) | [位1的个数](https://leetcode-cn.com/problems/number-of-1-bits/)| 🟢 简单 | 位运算 | - | 197 | | [231](https://leetcode.com/problems/power-of-two/discuss/?currentPage=1&orderBy=most_votes&query=) | [2的幂](https://leetcode-cn.com/problems/power-of-two/)| 🟢 简单 | 位运算 | - | 198 | | [190](https://leetcode.com/problems/reverse-bits/discuss/?currentPage=1&orderBy=most_votes&query=) | [颠倒二进制位](https://leetcode-cn.com/problems/reverse-bits/)| 🟢 简单 | 位运算 | - | 199 | | [51](https://leetcode.com/problems/n-queens/discuss/?currentPage=1&orderBy=most_votes&query=) | [N皇后](https://leetcode-cn.com/problems/n-queens/)| 🔴️ 困难 | 位运算 | - | 200 | | [52](https://leetcode.com/problems/n-queens-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [N皇后 II](https://leetcode-cn.com/problems/n-queens-ii/)| 🔴️ 困难 | 位运算 | - | 201 | | [338](https://leetcode.com/problems/counting-bits/discuss/?currentPage=1&orderBy=most_votes&query=) | [比特位计数](https://leetcode-cn.com/problems/counting-bits/)| 🟡 中等 | 位运算 | - | 202 | | [146](https://leetcode.com/problems/lru-cache/discuss/?currentPage=1&orderBy=most_votes&query=) | [LRU缓存机制](https://leetcode-cn.com/problems/lru-cache/)| 🟡 中等 | LRU Cache | - | 203 | | [1122](https://leetcode.com/problems/relative-sort-array/discuss/?currentPage=1&orderBy=most_votes&query=) | [数组的相对排序](https://leetcode-cn.com/problems/relative-sort-array/)| 🟢 简单 | 排序 | - | 204 | | [242](https://leetcode.com/problems/valid-anagram/discuss/?currentPage=1&orderBy=most_votes&query=) | [有效的字母异位词](https://leetcode-cn.com/problems/valid-anagram/)| 🟢 简单 | 排序 | - | 205 | | [1244](https://leetcode.com/problems/design-a-leaderboard/discuss/?currentPage=1&orderBy=most_votes&query=) | [力扣排行榜](https://leetcode-cn.com/problems/design-a-leaderboard/)| 🟡 中等 | 排序 | - | 206 | | [56](https://leetcode.com/problems/merge-intervals/discuss/?currentPage=1&orderBy=most_votes&query=) | [合并区间](https://leetcode-cn.com/problems/merge-intervals/)| 🟡 中等 | 排序 | - | 207 | | [493](https://leetcode.com/problems/reverse-pairs/discuss/?currentPage=1&orderBy=most_votes&query=) | [翻转对](https://leetcode-cn.com/problems/reverse-pairs/)| 🔴️ 困难 | 排序 | - | 208 | 209 | ## 第八周 210 | ### 课后作业 211 | | 题号 | 名称 | 难度 | 分类 | 备注 | 212 | | --- | --- | --- | --- | --- | 213 | | [300](https://leetcode.com/problems/longest-increasing-subsequence/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长上升子序列](https://leetcode-cn.com/problems/longest-increasing-subsequence/)| 🟡 中等 | 高级动态规划 | - | 214 | | [91](https://leetcode.com/problems/decode-ways/discuss/?currentPage=1&orderBy=most_votes&query=) | [解码方法](https://leetcode-cn.com/problems/decode-ways/)| 🟡 中等 | 高级动态规划 | - | 215 | | [32](https://leetcode.com/problems/longest-valid-parentheses/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长有效括号](https://leetcode-cn.com/problems/longest-valid-parentheses/)| 🔴️ 困难 | 高级动态规划 | - | 216 | | [85](https://leetcode.com/problems/maximal-rectangle/discuss/?currentPage=1&orderBy=most_votes&query=) | [最大矩形](https://leetcode-cn.com/problems/maximal-rectangle/)| 🔴️ 困难 | 高级动态规划 | - | 217 | | [115](https://leetcode.com/problems/distinct-subsequences/discuss/?currentPage=1&orderBy=most_votes&query=) | [不同的子序列](https://leetcode-cn.com/problems/distinct-subsequences/)| 🔴️ 困难 | 高级动态规划 | - | 218 | | [818](https://leetcode.com/problems/race-car/discuss/?currentPage=1&orderBy=most_votes&query=) | [赛车](https://leetcode-cn.com/problems/race-car/)| 🔴️ 困难 | 高级动态规划 | - | 219 | | [387](https://leetcode.com/problems/first-unique-character-in-a-string/discuss/?currentPage=1&orderBy=most_votes&query=) | [字符串中的第一个唯一字符](https://leetcode-cn.com/problems/first-unique-character-in-a-string/)| 🟢 简单 | 字符串匹配 | - | 220 | | [8](https://leetcode.com/problems/string-to-integer-atoi/discuss/?currentPage=1&orderBy=most_votes&query=) | [字符串转换整数 (atoi)](https://leetcode-cn.com/problems/string-to-integer-atoi/)| 🟡 中等 | 字符串匹配 | - | 221 | | [541](https://leetcode.com/problems/reverse-string-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [反转字符串 II](https://leetcode-cn.com/problems/reverse-string-ii/)| 🟢 简单 | 字符串匹配 | - | 222 | | [151](https://leetcode.com/problems/reverse-words-in-a-string/discuss/?currentPage=1&orderBy=most_votes&query=) | [翻转字符串里的单词](https://leetcode-cn.com/problems/reverse-words-in-a-string/)| 🟡 中等 | 字符串匹配 | - | 223 | | [557](https://leetcode.com/problems/reverse-words-in-a-string-iii/discuss/?currentPage=1&orderBy=most_votes&query=) | [反转字符串中的单词 III](https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/)| 🟢 简单 | 字符串匹配 | - | 224 | | [917](https://leetcode.com/problems/reverse-only-letters/discuss/?currentPage=1&orderBy=most_votes&query=) | [仅仅反转字母](https://leetcode-cn.com/problems/reverse-only-letters/)| 🟢 简单 | 字符串匹配 | - | 225 | | [438](https://leetcode.com/problems/find-all-anagrams-in-a-string/discuss/?currentPage=1&orderBy=most_votes&query=) | [找到字符串中所有字母异位词](https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/)| 🟡 中等 | 字符串匹配 | - | 226 | | [5](https://leetcode.com/problems/longest-palindromic-substring/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长回文子串](https://leetcode-cn.com/problems/longest-palindromic-substring/)| 🟡 中等 | 字符串匹配 | - | 227 | | [205](https://leetcode.com/problems/isomorphic-strings/discuss/?currentPage=1&orderBy=most_votes&query=) | [同构字符串](https://leetcode-cn.com/problems/isomorphic-strings/)| 🟢 简单 | 字符串匹配 | - | 228 | | [680](https://leetcode.com/problems/valid-palindrome-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [验证回文字符串 Ⅱ](https://leetcode-cn.com/problems/valid-palindrome-ii/)| 🟢 简单 | 字符串匹配 | - | 229 | | [44](https://leetcode.com/problems/wildcard-matching/discuss/?currentPage=1&orderBy=most_votes&query=) | [通配符匹配](https://leetcode-cn.com/problems/wildcard-matching/)| 🔴️ 困难 | 字符串匹配 | - | 230 | | [32](https://leetcode.com/problems/longest-valid-parentheses/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长有效括号](https://leetcode-cn.com/problems/longest-valid-parentheses/)| 🔴️ 困难 | 字符串匹配 | - | 231 | | [115](https://leetcode.com/problems/distinct-subsequences/discuss/?currentPage=1&orderBy=most_votes&query=) | [不同的子序列](https://leetcode-cn.com/problems/distinct-subsequences/)| 🔴️ 困难 | 字符串匹配 | - | 232 | 233 | 234 | ### 实战 235 | | 题号 | 名称 | 难度 | 分类 | 备注 | 236 | | --- | --- | --- | --- | --- | 237 | | [709](https://leetcode.com/problems/to-lower-case/discuss/?currentPage=1&orderBy=most_votes&query=) | [转换成小写字母](https://leetcode-cn.com/problems/to-lower-case/)| 🟢 简单 | 字符串基础 | - | 238 | | [58](https://leetcode.com/problems/length-of-last-word/discuss/?currentPage=1&orderBy=most_votes&query=) | [最后一个单词的长度](https://leetcode-cn.com/problems/length-of-last-word/)| 🟢 简单 | 字符串基础 | - | 239 | | [771](https://leetcode.com/problems/jewels-and-stones/discuss/?currentPage=1&orderBy=most_votes&query=) | [宝石与石头](https://leetcode-cn.com/problems/jewels-and-stones/)| 🟢 简单 | 字符串基础 | - | 240 | | [387](https://leetcode.com/problems/first-unique-character-in-a-string/discuss/?currentPage=1&orderBy=most_votes&query=) | [字符串中的第一个唯一字符](https://leetcode-cn.com/problems/first-unique-character-in-a-string/)| 🟢 简单 | 字符串基础 | - | 241 | | [8](https://leetcode.com/problems/string-to-integer-atoi/discuss/?currentPage=1&orderBy=most_votes&query=) | [字符串转换整数 (atoi)](https://leetcode-cn.com/problems/string-to-integer-atoi/)| 🟡 中等 | 字符串基础 | - | 242 | | [14](https://leetcode.com/problems/longest-common-prefix/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长公共前缀](https://leetcode-cn.com/problems/longest-common-prefix/)| 🟢 简单 | 字符串操作问题 | - | 243 | | [344](https://leetcode.com/problems/reverse-string/discuss/?currentPage=1&orderBy=most_votes&query=) | [反转字符串](https://leetcode-cn.com/problems/reverse-string/)| 🟢 简单 | 字符串操作问题 | - | 244 | | [541](https://leetcode.com/problems/reverse-string-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [反转字符串 II](https://leetcode-cn.com/problems/reverse-string-ii/)| 🟢 简单 | 字符串操作问题 | - | 245 | | [151](https://leetcode.com/problems/reverse-words-in-a-string/discuss/?currentPage=1&orderBy=most_votes&query=) | [翻转字符串里的单词](https://leetcode-cn.com/problems/reverse-words-in-a-string/)| 🟡 中等 | 字符串操作问题 | - | 246 | | [557](https://leetcode.com/problems/reverse-words-in-a-string-iii/discuss/?currentPage=1&orderBy=most_votes&query=) | [反转字符串中的单词 III](https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/)| 🟢 简单 | 字符串操作问题 | - | 247 | | [917](https://leetcode.com/problems/reverse-only-letters/discuss/?currentPage=1&orderBy=most_votes&query=) | [仅仅反转字母](https://leetcode-cn.com/problems/reverse-only-letters/)| 🟢 简单 | 字符串操作问题 | - | 248 | | [242](https://leetcode.com/problems/valid-anagram/discuss/?currentPage=1&orderBy=most_votes&query=) | [有效的字母异位词](https://leetcode-cn.com/problems/valid-anagram/)| 🟢 简单 | 异位词问题 | - | 249 | | [49](https://leetcode.com/problems/group-anagrams/discuss/?currentPage=1&orderBy=most_votes&query=) | [字母异位词分组](https://leetcode-cn.com/problems/group-anagrams/)| 🟡 中等 | 异位词问题 | - | 250 | | [438](https://leetcode.com/problems/find-all-anagrams-in-a-string/discuss/?currentPage=1&orderBy=most_votes&query=) | [找到字符串中所有字母异位词](https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/)| 🟡 中等 | 异位词问题 | - | 251 | | [125](https://leetcode.com/problems/valid-palindrome/discuss/?currentPage=1&orderBy=most_votes&query=) | [验证回文串](https://leetcode-cn.com/problems/valid-palindrome/)| 🟢 简单 | 回文串问题 | - | 252 | | [680](https://leetcode.com/problems/valid-palindrome-ii/discuss/?currentPage=1&orderBy=most_votes&query=) | [验证回文字符串 Ⅱ](https://leetcode-cn.com/problems/valid-palindrome-ii/)| 🟢 简单 | 回文串问题 | - | 253 | | [5](https://leetcode.com/problems/longest-palindromic-substring/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长回文子串](https://leetcode-cn.com/problems/longest-palindromic-substring/)| 🟡 中等 | 回文串问题 | - | 254 | | [1143](https://leetcode.com/problems/longest-common-subsequence/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长公共子序列](https://leetcode-cn.com/problems/longest-common-subsequence/)| 🟡 中等 | 最长子串、子序列问题 | - | 255 | | [72](https://leetcode.com/problems/edit-distance/discuss/?currentPage=1&orderBy=most_votes&query=) | [编辑距离](https://leetcode-cn.com/problems/edit-distance/)| 🔴️ 困难 | 最长子串、子序列问题 | - | 256 | | [5](https://leetcode.com/problems/longest-palindromic-substring/discuss/?currentPage=1&orderBy=most_votes&query=) | [最长回文子串](https://leetcode-cn.com/problems/longest-palindromic-substring/)| 🟡 中等 | 最长子串、子序列问题 | - | 257 | | [10](https://leetcode.com/problems/regular-expression-matching/discuss/?currentPage=1&orderBy=most_votes&query=) | [正则表达式匹配](https://leetcode-cn.com/problems/regular-expression-matching/)| 🔴️ 困难 | 字符串 +DP 问题 | - | 258 | | [10](https://leetcode.com/problems/regular-expression-matching/discuss/?currentPage=1&orderBy=most_votes&query=) | [正则表达式匹配](https://leetcode-cn.com/problems/regular-expression-matching/)| 🔴️ 困难 | 字符串 +DP 问题 | - | 259 | | [44](https://leetcode.com/problems/wildcard-matching/discuss/?currentPage=1&orderBy=most_votes&query=) | [通配符匹配](https://leetcode-cn.com/problems/wildcard-matching/)| 🔴️ 困难 | 字符串 +DP 问题 | - | 260 | | [115](https://leetcode.com/problems/distinct-subsequences/discuss/?currentPage=1&orderBy=most_votes&query=) | [不同的子序列](https://leetcode-cn.com/problems/distinct-subsequences/)| 🔴️ 困难 | 字符串 +DP 问题 | - | 261 | 262 | -------------------------------------------------------------------------------- /doc/markdown/images/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aoeai/leet-code-study-record/a9a40929527887e31aca3a69f5db7eb800419d42/doc/markdown/images/index.png -------------------------------------------------------------------------------- /doc/markdown/images/problem-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aoeai/leet-code-study-record/a9a40929527887e31aca3a69f5db7eb800419d42/doc/markdown/images/problem-list.png -------------------------------------------------------------------------------- /doc/ziliao.md: -------------------------------------------------------------------------------- 1 | - [js函数传参](https://cloud.tencent.com/developer/ask/193307) 2 | 3 | confirmDelete()函数需要字符串id 4 | 5 | ```js 6 | th:onclick="'javascript:confirmDelete(\'' + ${company.id} + '\');'" 7 | ``` 8 | 9 | 如果它需要一个数字ID 10 | ```js 11 | th:onclick="'javascript:confirmDelete(' + ${company.id} + ');'" 12 | ``` 13 | 14 | ## MySQL 15 | 16 | - 查看时区 17 | 18 | ```sql 19 | show variables like "%time_zone%"; 20 | ``` 21 | 22 | 23 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.aoeais 12 | leet-code-study-record 13 | 0.0.1 14 | leet-code-study-record 15 | LeetCode刷题记录 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-thymeleaf 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-web 33 | 34 | 35 | 36 | org.projectlombok 37 | lombok 38 | true 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-test 43 | test 44 | 45 | 46 | org.junit.vintage 47 | junit-vintage-engine 48 | 49 | 50 | 51 | 52 | 53 | 54 | com.baomidou 55 | mybatis-plus-boot-starter 56 | 3.3.0 57 | 58 | 59 | 60 | mysql 61 | mysql-connector-java 62 | runtime 63 | 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-starter-jdbc 69 | 70 | 71 | 72 | 73 | commons-codec 74 | commons-codec 75 | 1.13 76 | 77 | 78 | 79 | org.apache.commons 80 | commons-lang3 81 | 3.9 82 | 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-devtools 87 | true 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | org.springframework.boot 106 | spring-boot-maven-plugin 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/LeetCodeStudyRecordApplication.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @MapperScan("com.aoeai.lcsr.dao.mapper") 8 | @SpringBootApplication(scanBasePackages = {"com.aoeai"}) 9 | public class LeetCodeStudyRecordApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(LeetCodeStudyRecordApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/bo/user/RegistOrLoginBo.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.bo.user; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 用户注册或登录的结果 7 | */ 8 | @Data 9 | public class RegistOrLoginBo { 10 | 11 | /** 12 | * 处理结果 true:成功 13 | */ 14 | private boolean success; 15 | 16 | /** 17 | * 和密码一起使用的盐 18 | */ 19 | private String salt; 20 | 21 | /** 22 | * 错误原因 23 | */ 24 | private String errMsg; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/bo/userproblem/UserProblemBo.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.bo.userproblem; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 用户刷题记录概要 7 | */ 8 | @Data 9 | public class UserProblemBo { 10 | 11 | /** 12 | * 问题id 13 | */ 14 | private Integer problemId; 15 | 16 | /** 17 | * 刷题次数 18 | */ 19 | private Integer doCount; 20 | 21 | /** 22 | * '状态 1:未解答;2:已解答;3:尝试过;4:略懂;5:掌握;6:精通 23 | */ 24 | private String status; 25 | 26 | /** 27 | * 最后做题时间 28 | */ 29 | private String lastDoTime; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/config/HandlerConfig.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.config; 2 | 3 | import com.aoeai.lcsr.handler.ErrorPageRegistrarHandler; 4 | import org.springframework.boot.web.server.ErrorPageRegistrar; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * 助手工具配置 10 | */ 11 | @Configuration 12 | public class HandlerConfig { 13 | 14 | @Bean 15 | public ErrorPageRegistrar errorPageRegistrar(){ 16 | return new ErrorPageRegistrarHandler(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/config/MVCConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.http.converter.HttpMessageConverter; 6 | import org.springframework.http.converter.StringHttpMessageConverter; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | 9 | import java.nio.charset.StandardCharsets; 10 | import java.util.List; 11 | 12 | @Configuration 13 | public class MVCConfiguration implements WebMvcConfigurer { 14 | 15 | @Bean 16 | public HttpMessageConverter responseBodyStringConverter() { 17 | StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8); 18 | return converter; 19 | } 20 | 21 | /** 22 | * 修改StringHttpMessageConverter默认配置 23 | * @param converters 24 | */ 25 | @Override 26 | public void configureMessageConverters(List> converters){ 27 | converters.add(responseBodyStringConverter()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/constant/AoeHttpStatus.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.constant; 2 | 3 | public class AoeHttpStatus { 4 | 5 | /** 6 | * 处理失败 7 | */ 8 | public final static int FAIL = 560; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/constant/KeyConstant.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.constant; 2 | 3 | public class KeyConstant { 4 | 5 | /** 6 | * 错误提示 7 | */ 8 | public final static String ERROR_MSG = "errMsg"; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/constant/ResponseText.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.constant; 2 | 3 | /** 4 | * 页面返回文本 5 | */ 6 | public class ResponseText { 7 | // TODO 文字以后优化 8 | 9 | /** 10 | * 请求成功 11 | */ 12 | public final static String SUCCESS = "ok"; 13 | 14 | public final static String PLEASE_LOGIN = "请先登录"; 15 | 16 | public final static String ERROR_PROBLEM_STATUS = "错误的刷题状态"; 17 | 18 | public final static String OPERATION_FAILED_TRY_TO_LOGIN_AGAIN = "操作失败!请尝试重新登陆"; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/constant/TextConstant.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.constant; 2 | 3 | /** 4 | * 文本常量 5 | */ 6 | public class TextConstant { 7 | 8 | /** 9 | * 什么都没有 10 | */ 11 | public final static String NONE = "-"; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.controller; 2 | 3 | import com.aoeai.lcsr.constant.KeyConstant; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.ui.ModelMap; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | 9 | @Controller 10 | public class IndexController { 11 | 12 | @RequestMapping("/") 13 | public String index(@RequestParam(required = false) String errMsg, ModelMap model){ 14 | if(errMsg != null){ 15 | model.put(KeyConstant.ERROR_MSG, errMsg); 16 | } 17 | return "index"; 18 | } 19 | 20 | @RequestMapping("/nani") 21 | public String error(){ 22 | return "error"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/controller/ProblemController.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.controller; 2 | 3 | import com.aoeai.lcsr.constant.KeyConstant; 4 | import com.aoeai.lcsr.constant.ResponseText; 5 | import com.aoeai.lcsr.form.problem.ProblemListForm; 6 | import com.aoeai.lcsr.service.ProblemService; 7 | import com.aoeai.lcsr.service.UserService; 8 | import com.aoeai.lcsr.utils.TextUtils; 9 | import com.aoeai.lcsr.utils.page.Pagination; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Controller; 13 | import org.springframework.ui.ModelMap; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | 18 | @Controller 19 | @RequestMapping("problem") 20 | public class ProblemController { 21 | 22 | @Autowired 23 | private ProblemService problemService; 24 | 25 | @Autowired 26 | private UserService userService; 27 | 28 | @GetMapping("list") 29 | public String listGet(String salt, String username, ModelMap model){ 30 | ProblemListForm form = new ProblemListForm(); 31 | form.setSalt(salt); 32 | form.setUsername(username); 33 | 34 | return showProblemList(model, form); 35 | } 36 | 37 | @PostMapping("list") 38 | public String list(ProblemListForm form, ModelMap model){ 39 | return showProblemList(model, form); 40 | } 41 | 42 | private String showProblemList(ModelMap model, ProblemListForm form) { 43 | String errMsg = checkProblemListForm(form); 44 | if(errMsg != null){ 45 | return String.format("redirect:/?%s=%s",KeyConstant.ERROR_MSG, TextUtils.urlEncoder(errMsg)); 46 | } 47 | 48 | model.put("form", form); 49 | model.put("pagination", problemService.list(form, userService.getIdBySalt(form.getSalt()))); 50 | return "problem/list"; 51 | } 52 | 53 | private String checkProblemListForm(ProblemListForm form) { 54 | if (StringUtils.isBlank(form.getSalt()) || form.getSalt().length() != 64) { 55 | return ResponseText.PLEASE_LOGIN; 56 | } 57 | if (!userService.checkSalt(form.getSalt())){ 58 | return ResponseText.PLEASE_LOGIN; 59 | } 60 | return null; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.controller; 2 | 3 | import com.aoeai.lcsr.bo.user.RegistOrLoginBo; 4 | import com.aoeai.lcsr.constant.KeyConstant; 5 | import com.aoeai.lcsr.service.UserService; 6 | import com.aoeai.lcsr.utils.TextUtils; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | 13 | @Controller 14 | @RequestMapping("/user") 15 | public class UserController { 16 | 17 | @Autowired 18 | private UserService userService; 19 | 20 | @PostMapping("/registOrLogin") 21 | public String registOrLogin(String username, String password) { 22 | String errUsername = checkUsername(username); 23 | String errPassword = checkPassword(password); 24 | String errMsg = errUsername == null ? errPassword : errUsername; 25 | if (errMsg != null){ 26 | return String.format("redirect:/?%s=%s", 27 | KeyConstant.ERROR_MSG, TextUtils.urlEncoder(errMsg)); 28 | } 29 | 30 | RegistOrLoginBo result = userService.registOrLogin(username.trim(), password.trim()); 31 | if (result.isSuccess()) { 32 | return String.format("redirect:/problem/list?salt=%s&username=%s", 33 | result.getSalt(), TextUtils.urlEncoder(username)); 34 | } 35 | 36 | return String.format("redirect:/?%s=%s", 37 | KeyConstant.ERROR_MSG, TextUtils.urlEncoder(result.getErrMsg())); 38 | } 39 | 40 | private String checkUsername(String username) { 41 | if (StringUtils.isBlank(username)){ 42 | return "用户名不能为空"; 43 | } 44 | if (username.length() > 30){ 45 | return "用户名最大长度30"; 46 | } 47 | return null; 48 | } 49 | 50 | private String checkPassword(String password) { 51 | if (StringUtils.isBlank(password)){ 52 | return "密码不能为空"; 53 | } 54 | if (password.length() > Integer.MAX_VALUE - 1){ 55 | return "密码太长了"; 56 | } 57 | return null; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/controller/UserProblemController.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.controller; 2 | 3 | import com.aoeai.lcsr.constant.AoeHttpStatus; 4 | import com.aoeai.lcsr.constant.ResponseText; 5 | import com.aoeai.lcsr.enums.ProblemStatusEnum; 6 | import com.aoeai.lcsr.service.UserProblemService; 7 | import com.aoeai.lcsr.service.UserService; 8 | import com.aoeai.lcsr.vo.userproblem.CurrentDoCountVo; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.http.ResponseEntity; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | /** 16 | * 用户刷题概要记录 17 | */ 18 | @RestController 19 | @RequestMapping("userProblem") 20 | public class UserProblemController { 21 | 22 | @Autowired 23 | private UserService userService; 24 | 25 | @Autowired 26 | private UserProblemService userProblemService; 27 | 28 | /** 29 | * 更新刷题状态 30 | * @param id 问题id 31 | * @param status 刷题状态 32 | * @param salt 33 | * @return 34 | */ 35 | @GetMapping("changeStatus") 36 | public String changeStatus(int id, int status, String salt) { 37 | if (!userService.checkSalt(salt)) { 38 | return ResponseText.PLEASE_LOGIN; 39 | } 40 | if (!ProblemStatusEnum.check(status)) { 41 | return ResponseText.ERROR_PROBLEM_STATUS; 42 | } 43 | if (!userProblemService.updateStatus(id, status, salt)) { 44 | return ResponseText.OPERATION_FAILED_TRY_TO_LOGIN_AGAIN; 45 | } 46 | 47 | return ResponseText.SUCCESS; 48 | } 49 | 50 | /** 51 | * 更新刷题状态 52 | * @param id 问题id 53 | * @param salt 54 | * @return 55 | */ 56 | @GetMapping("plusDoCount") 57 | public ResponseEntity plusDoCount(int id, String salt){ 58 | if (!userService.checkSalt(salt)) { 59 | return ResponseEntity.status(AoeHttpStatus.FAIL) 60 | .body(ResponseText.PLEASE_LOGIN); 61 | } 62 | Integer userId = userService.getIdBySalt(salt); 63 | if (!userProblemService.plusDoCount(id, userId)) { 64 | return ResponseEntity.status(AoeHttpStatus.FAIL) 65 | .body(ResponseText.OPERATION_FAILED_TRY_TO_LOGIN_AGAIN); 66 | } 67 | CurrentDoCountVo currentDoCountVo = userProblemService.currentDoCountVo(id, userId); 68 | if (currentDoCountVo == null) { 69 | return ResponseEntity.status(AoeHttpStatus.FAIL) 70 | .body(ResponseText.OPERATION_FAILED_TRY_TO_LOGIN_AGAIN); 71 | } 72 | return ResponseEntity.ok(currentDoCountVo); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/entity/LcsrProblem.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.experimental.Accessors; 8 | 9 | /** 10 | *

11 | * LeetCode问题 12 | *

13 | * 14 | * @author aoe 15 | * @since 2019-12-22 16 | */ 17 | @Data 18 | @EqualsAndHashCode(callSuper = false) 19 | @Accessors(chain = true) 20 | public class LcsrProblem implements Serializable { 21 | 22 | private static final long serialVersionUID = 1L; 23 | 24 | private Integer id; 25 | 26 | /** 27 | * 问题 28 | */ 29 | private String problem; 30 | 31 | /** 32 | * 问题的英文版 33 | */ 34 | private String problemEn; 35 | 36 | /** 37 | * 难度 1:简单;2:中等;3困难 38 | */ 39 | private Integer difficulty; 40 | 41 | /** 42 | * 类型 (类型i的集合,例如 1,2) 43 | */ 44 | private String tag; 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/entity/LcsrProblemRecord.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | 6 | import java.time.LocalDateTime; 7 | import java.io.Serializable; 8 | 9 | import lombok.Data; 10 | import lombok.EqualsAndHashCode; 11 | import lombok.experimental.Accessors; 12 | 13 | /** 14 | *

15 | * 刷题记录 16 | *

17 | * 18 | * @author aoe 19 | * @since 2019-12-22 20 | */ 21 | @Data 22 | @EqualsAndHashCode(callSuper = false) 23 | @Accessors(chain = true) 24 | public class LcsrProblemRecord implements Serializable { 25 | 26 | private static final long serialVersionUID = 1L; 27 | 28 | /** 29 | * 主键 30 | */ 31 | @TableId(value = "id", type = IdType.AUTO) 32 | private Integer id; 33 | 34 | /** 35 | * 用户id 36 | */ 37 | private Integer userId; 38 | 39 | /** 40 | * 问题id 41 | */ 42 | private Integer problemId; 43 | 44 | /** 45 | * 添加时间 46 | */ 47 | private LocalDateTime addTime; 48 | 49 | /** 50 | * 逻辑删除 0:为删除; 1:已删除 51 | */ 52 | private Boolean isDelete; 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/entity/LcsrUser.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | 6 | import java.time.LocalDateTime; 7 | import java.io.Serializable; 8 | 9 | import lombok.Data; 10 | import lombok.EqualsAndHashCode; 11 | import lombok.experimental.Accessors; 12 | 13 | /** 14 | *

15 | * 用户 16 | *

17 | * 18 | * @author aoe 19 | * @since 2019-12-22 20 | */ 21 | @Data 22 | @EqualsAndHashCode(callSuper = false) 23 | @Accessors(chain = true) 24 | public class LcsrUser implements Serializable { 25 | 26 | private static final long serialVersionUID = 1L; 27 | 28 | /** 29 | * 主键 30 | */ 31 | @TableId(value = "id", type = IdType.AUTO) 32 | private Integer id; 33 | 34 | /** 35 | * 用户名 36 | */ 37 | private String username; 38 | 39 | /** 40 | * 密码 41 | */ 42 | private String password; 43 | 44 | /** 45 | * 密码干扰因子 46 | */ 47 | private String salt; 48 | 49 | /** 50 | * 添加时间 51 | */ 52 | private LocalDateTime addTime; 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/entity/LcsrUserProblem.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | 6 | import java.time.LocalDateTime; 7 | import java.io.Serializable; 8 | 9 | import lombok.Data; 10 | import lombok.EqualsAndHashCode; 11 | import lombok.experimental.Accessors; 12 | 13 | /** 14 | *

15 | * 用户刷题记录概要 16 | *

17 | * 18 | * @author aoe 19 | * @since 2019-12-22 20 | */ 21 | @Data 22 | @EqualsAndHashCode(callSuper = false) 23 | @Accessors(chain = true) 24 | public class LcsrUserProblem implements Serializable { 25 | 26 | private static final long serialVersionUID = 1L; 27 | 28 | @TableId(value = "id", type = IdType.AUTO) 29 | private Integer id; 30 | 31 | /** 32 | * 用户id 33 | */ 34 | private Integer userId; 35 | 36 | /** 37 | * 问题id 38 | */ 39 | private Integer problemId; 40 | 41 | /** 42 | * 刷题次数 43 | */ 44 | private Integer doCount; 45 | 46 | /** 47 | * '状态 1:未解答;2:已解答;3:尝试过;4:略懂;5:掌握;6:精通 48 | */ 49 | private Integer status; 50 | 51 | /** 52 | * 最后做题时间 53 | */ 54 | private LocalDateTime lastDoTime; 55 | 56 | /** 57 | * 添加时间 58 | */ 59 | private LocalDateTime addTime; 60 | 61 | /** 62 | * 更新时间 63 | */ 64 | private LocalDateTime updateTime; 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/mapper/LcsrProblemMapper.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.mapper; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrProblem; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * LeetCode问题 Mapper 接口 9 | *

10 | * 11 | * @author aoe 12 | * @since 2019-12-22 13 | */ 14 | public interface LcsrProblemMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/mapper/LcsrProblemRecordMapper.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.mapper; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrProblemRecord; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 刷题记录 Mapper 接口 9 | *

10 | * 11 | * @author aoe 12 | * @since 2019-12-22 13 | */ 14 | public interface LcsrProblemRecordMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/mapper/LcsrUserMapper.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.mapper; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrUser; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 用户 Mapper 接口 9 | *

10 | * 11 | * @author aoe 12 | * @since 2019-12-22 13 | */ 14 | public interface LcsrUserMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/mapper/LcsrUserProblemMapper.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.mapper; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrUserProblem; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | /** 7 | *

8 | * 用户刷题记录概要 Mapper 接口 9 | *

10 | * 11 | * @author aoe 12 | * @since 2019-12-22 13 | */ 14 | public interface LcsrUserProblemMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/service/ILcsrProblemRecordService.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.service; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrProblemRecord; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | *

8 | * 刷题记录 服务类 9 | *

10 | * 11 | * @author aoe 12 | * @since 2019-12-22 13 | */ 14 | public interface ILcsrProblemRecordService extends IService { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/service/ILcsrProblemService.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.service; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrProblem; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | *

8 | * LeetCode问题 服务类 9 | *

10 | * 11 | * @author aoe 12 | * @since 2019-12-22 13 | */ 14 | public interface ILcsrProblemService extends IService { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/service/ILcsrUserProblemService.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.service; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrUserProblem; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | *

8 | * 用户刷题记录概要 服务类 9 | *

10 | * 11 | * @author aoe 12 | * @since 2019-12-22 13 | */ 14 | public interface ILcsrUserProblemService extends IService { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/service/ILcsrUserService.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.service; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrUser; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | *

8 | * 用户 服务类 9 | *

10 | * 11 | * @author aoe 12 | * @since 2019-12-22 13 | */ 14 | public interface ILcsrUserService extends IService { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/service/impl/LcsrProblemRecordServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.service.impl; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrProblemRecord; 4 | import com.aoeai.lcsr.dao.mapper.LcsrProblemRecordMapper; 5 | import com.aoeai.lcsr.dao.service.ILcsrProblemRecordService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | *

11 | * 刷题记录 服务实现类 12 | *

13 | * 14 | * @author aoe 15 | * @since 2019-12-22 16 | */ 17 | @Service 18 | public class LcsrProblemRecordServiceImpl extends ServiceImpl implements ILcsrProblemRecordService { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/service/impl/LcsrProblemServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.service.impl; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrProblem; 4 | import com.aoeai.lcsr.dao.mapper.LcsrProblemMapper; 5 | import com.aoeai.lcsr.dao.service.ILcsrProblemService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | *

11 | * LeetCode问题 服务实现类 12 | *

13 | * 14 | * @author aoe 15 | * @since 2019-12-22 16 | */ 17 | @Service 18 | public class LcsrProblemServiceImpl extends ServiceImpl implements ILcsrProblemService { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/service/impl/LcsrUserProblemServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.service.impl; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrUserProblem; 4 | import com.aoeai.lcsr.dao.mapper.LcsrUserProblemMapper; 5 | import com.aoeai.lcsr.dao.service.ILcsrUserProblemService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | *

11 | * 用户刷题记录概要 服务实现类 12 | *

13 | * 14 | * @author aoe 15 | * @since 2019-12-22 16 | */ 17 | @Service 18 | public class LcsrUserProblemServiceImpl extends ServiceImpl implements ILcsrUserProblemService { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/dao/service/impl/LcsrUserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.dao.service.impl; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrUser; 4 | import com.aoeai.lcsr.dao.mapper.LcsrUserMapper; 5 | import com.aoeai.lcsr.dao.service.ILcsrUserService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | *

11 | * 用户 服务实现类 12 | *

13 | * 14 | * @author aoe 15 | * @since 2019-12-22 16 | */ 17 | @Service 18 | public class LcsrUserServiceImpl extends ServiceImpl implements ILcsrUserService { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/enums/ProblemDifficultyEnum.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.enums; 2 | 3 | public enum ProblemDifficultyEnum { 4 | SIMPLE(1, "简单"), 5 | MEDIUM(2, "中等"), 6 | DIFFICULT(3, "困难"); 7 | 8 | private int value; 9 | 10 | private String title; 11 | 12 | ProblemDifficultyEnum(int value, String title) { 13 | this.value = value; 14 | this.title = title; 15 | } 16 | 17 | public static ProblemDifficultyEnum getDifficulty(int value){ 18 | for (ProblemDifficultyEnum v : ProblemDifficultyEnum.values()) { 19 | if (value == v.value) { 20 | return v; 21 | } 22 | } 23 | return null; 24 | } 25 | 26 | public int getValue() { 27 | return value; 28 | } 29 | 30 | public String getTitle() { 31 | return title; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/enums/ProblemStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.enums; 2 | 3 | /** 4 | * 刷题状态 5 | */ 6 | public enum ProblemStatusEnum { 7 | NOT_ANSWERED(1, "未解答"), 8 | ANSWERED(2, "已解答"), 9 | TRIED(3, "尝试过"), 10 | SLIGHTLY_UNDERSTAND(4, "略懂"), 11 | MASTER(5, "掌握"), 12 | MASTERY(6, "精通"); 13 | 14 | private int value; 15 | 16 | private String title; 17 | 18 | ProblemStatusEnum(int value, String title) { 19 | this.value = value; 20 | this.title = title; 21 | } 22 | 23 | public int getValue() { 24 | return value; 25 | } 26 | 27 | public String getTitle() { 28 | return title; 29 | } 30 | 31 | /** 32 | * 验证状态是否正确 33 | * @param status 34 | * @return true 正确 35 | */ 36 | public final static boolean check(int status){ 37 | for (ProblemStatusEnum ps : values()) { 38 | if (ps.value == status) { 39 | return true; 40 | } 41 | } 42 | return false; 43 | } 44 | 45 | public final static String title(Integer status){ 46 | for (ProblemStatusEnum ps : values()) { 47 | if (ps.value == status) { 48 | return ps.title; 49 | } 50 | } 51 | return "未知"; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/form/problem/ProblemListForm.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.form.problem; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 问题列表表单 7 | */ 8 | @Data 9 | public class ProblemListForm { 10 | 11 | private String salt; 12 | 13 | private String username; 14 | 15 | /** 16 | * 题目过滤id 17 | */ 18 | private String ids; 19 | 20 | /** 21 | * 几天前 22 | */ 23 | private Integer fewDaysAgo; 24 | 25 | /** 26 | * 当前状态 27 | */ 28 | private int status; 29 | 30 | /** 31 | * 当前页 32 | */ 33 | private int page; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/handler/ErrorPageRegistrarHandler.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.handler; 2 | 3 | import org.springframework.boot.web.server.ErrorPage; 4 | import org.springframework.boot.web.server.ErrorPageRegistrar; 5 | import org.springframework.boot.web.server.ErrorPageRegistry; 6 | import org.springframework.http.HttpStatus; 7 | 8 | /** 9 | * 页面错误拦截助手 10 | */ 11 | public class ErrorPageRegistrarHandler implements ErrorPageRegistrar { 12 | 13 | @Override 14 | public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { 15 | ErrorPage page404 = new ErrorPage(HttpStatus.NOT_FOUND, "/nani"); 16 | ErrorPage page500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/nani"); 17 | 18 | errorPageRegistry.addErrorPages(page404, page500); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/service/ProblemRecordService.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.service; 2 | 3 | import com.aoeai.lcsr.dao.entity.LcsrProblemRecord; 4 | import com.aoeai.lcsr.dao.service.ILcsrProblemRecordService; 5 | import com.aoeai.lcsr.utils.DateUtils; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * 刷题记录 11 | */ 12 | @Service 13 | public class ProblemRecordService { 14 | 15 | @Autowired 16 | private ILcsrProblemRecordService lcsrProblemRecordService; 17 | 18 | /** 19 | * 保存刷题记录 20 | * @param userId 21 | * @param problemId 22 | * @return 23 | */ 24 | public boolean insert(int userId, int problemId){ 25 | LcsrProblemRecord record = new LcsrProblemRecord(); 26 | record.setUserId(userId); 27 | record.setProblemId(problemId); 28 | record.setAddTime(DateUtils.now()); 29 | 30 | return lcsrProblemRecordService.save(record); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/service/ProblemService.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.service; 2 | 3 | import com.aoeai.lcsr.bo.userproblem.UserProblemBo; 4 | import com.aoeai.lcsr.constant.TextConstant; 5 | import com.aoeai.lcsr.dao.entity.LcsrProblem; 6 | import com.aoeai.lcsr.dao.service.ILcsrProblemService; 7 | import com.aoeai.lcsr.enums.ProblemDifficultyEnum; 8 | import com.aoeai.lcsr.enums.ProblemStatusEnum; 9 | import com.aoeai.lcsr.form.problem.ProblemListForm; 10 | import com.aoeai.lcsr.utils.page.Page; 11 | import com.aoeai.lcsr.utils.page.PageHelper; 12 | import com.aoeai.lcsr.utils.page.Pagination; 13 | import com.aoeai.lcsr.vo.user.ProblemVo; 14 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 15 | import org.apache.commons.lang3.StringUtils; 16 | import org.apache.commons.lang3.math.NumberUtils; 17 | import org.springframework.beans.BeanUtils; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.stereotype.Service; 20 | 21 | import java.util.*; 22 | 23 | /** 24 | * 问题 25 | */ 26 | @Service 27 | public class ProblemService { 28 | 29 | @Autowired 30 | private ILcsrProblemService lcsrProblemService; 31 | 32 | @Autowired 33 | private UserProblemService userProblemService; 34 | 35 | public Pagination list(ProblemListForm form, int userId) { 36 | Map map = userProblemService.getUserProblemMap(userId, 37 | form.getStatus(), form.getFewDaysAgo()); 38 | List problemIdsByUser = new ArrayList<>(); 39 | if (form.getStatus() > 0 || form.getFewDaysAgo() != null) { 40 | if (map.isEmpty()) { 41 | // 不应该查询出数据 42 | problemIdsByUser.add(Integer.MAX_VALUE); 43 | }else { 44 | for (Map.Entry e :map.entrySet()){ 45 | problemIdsByUser.add(e.getValue().getProblemId()); 46 | } 47 | } 48 | } 49 | 50 | List list = lcsrProblemService.list(getProblemListQuery(form, problemIdsByUser)); 51 | List records = new ArrayList<>(list.size()); 52 | for (LcsrProblem p : list) { 53 | ProblemVo pVo = new ProblemVo(); 54 | BeanUtils.copyProperties(p, pVo); 55 | pVo.setDifficulty(ProblemDifficultyEnum.getDifficulty(p.getDifficulty())); 56 | 57 | pVo.setUrlCN(String.format("https://leetcode-cn.com/problems/%s/", p.getProblemEn())); 58 | pVo.setUrlEN(String.format("https://leetcode.com/problems/%s/discuss/?currentPage=1&orderBy=most_votes&query=", p.getProblemEn())); 59 | 60 | UserProblemBo userProblem = map.get(p.getId()); 61 | if (userProblem != null) { 62 | pVo.setDoCount(userProblem.getDoCount() == null ? TextConstant.NONE : userProblem.getDoCount().toString()); 63 | pVo.setStatus(userProblem.getStatus()); 64 | pVo.setLastDoTime(userProblem.getLastDoTime() == null ? TextConstant.NONE : userProblem.getLastDoTime()); 65 | }else { 66 | pVo.setDoCount(TextConstant.NONE); 67 | pVo.setStatus(ProblemStatusEnum.NOT_ANSWERED.getTitle()); 68 | pVo.setLastDoTime(TextConstant.NONE); 69 | } 70 | 71 | records.add(pVo); 72 | } 73 | 74 | return pagingQuery(records, form.getPage()); 75 | } 76 | 77 | /** 78 | * 组装问题列表查询条件 79 | * @param form 80 | * @return 81 | */ 82 | private QueryWrapper getProblemListQuery(ProblemListForm form, List problemIdsByUser){ 83 | List problemIds = new ArrayList<>(); 84 | if (StringUtils.isNotBlank(form.getIds())) { 85 | for (String id : form.getIds().split(",")) { 86 | if (!NumberUtils.isDigits(id)) { 87 | continue; 88 | } 89 | problemIds.add(Integer.parseInt(id)); 90 | } 91 | } 92 | // 交集 93 | if(!problemIds.isEmpty() && !problemIdsByUser.isEmpty()){ 94 | problemIds.retainAll(problemIdsByUser); 95 | 96 | // 没有数据 97 | if (problemIds.isEmpty()) { 98 | problemIds.add(Integer.MAX_VALUE); 99 | } 100 | } 101 | if (problemIds.isEmpty()) { 102 | problemIds = problemIdsByUser; 103 | } 104 | 105 | QueryWrapper query = new QueryWrapper(); 106 | if (problemIds.size() > 0) { 107 | query.in("id", problemIds); 108 | } 109 | 110 | return query; 111 | } 112 | 113 | /** 114 | * 分页 115 | * @param records 116 | * @param currentNum 117 | * @return 118 | */ 119 | private Pagination pagingQuery(List records, int currentNum){ 120 | int pageSize = 20; 121 | Page page = new Page(pageSize, records.size()); 122 | page.setCurrentNum(currentNum); 123 | 124 | int start = (page.getCurrentNum() - 1) * pageSize; 125 | start = start < 0 ? 0 : start; 126 | int end = start + pageSize; 127 | end = end > records.size()? records.size(): end; 128 | end = end < 0 ? 0 : end; 129 | 130 | Pagination pagination = PageHelper.buildPagination(page, records.subList(start, end)); 131 | return pagination; 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/service/UserProblemService.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.service; 2 | 3 | import com.aoeai.lcsr.bo.userproblem.UserProblemBo; 4 | import com.aoeai.lcsr.constant.TextConstant; 5 | import com.aoeai.lcsr.dao.entity.LcsrUserProblem; 6 | import com.aoeai.lcsr.dao.service.ILcsrUserProblemService; 7 | import com.aoeai.lcsr.enums.ProblemStatusEnum; 8 | import com.aoeai.lcsr.utils.DateUtils; 9 | import com.aoeai.lcsr.utils.TextUtils; 10 | import com.aoeai.lcsr.vo.userproblem.CurrentDoCountVo; 11 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 12 | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; 13 | import org.springframework.beans.BeanUtils; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Service; 16 | 17 | import java.time.LocalDateTime; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | /** 23 | * 用户刷题概要记录 24 | */ 25 | @Service 26 | public class UserProblemService { 27 | 28 | @Autowired 29 | private ILcsrUserProblemService lcsrUserProblemService; 30 | 31 | @Autowired 32 | private UserService userService; 33 | 34 | @Autowired 35 | private ProblemRecordService problemRecordService; 36 | 37 | /** 38 | * 更新刷题状态 39 | * @param problemId 题目id 40 | * @param status 状态 41 | * @param salt 42 | * @return true 成功 43 | */ 44 | public boolean updateStatus(int problemId, int status, String salt){ 45 | Integer userId = userService.getIdBySalt(salt); 46 | if (!checkPrerequisite(userId, problemId, false)) { 47 | return false; 48 | } 49 | 50 | UpdateWrapper update = new UpdateWrapper(); 51 | update.eq("user_id", userId); 52 | update.eq("problem_id", problemId); 53 | update.set("status", status); 54 | 55 | return lcsrUserProblemService.update(update); 56 | } 57 | 58 | /** 59 | * 刷题次数+1 60 | * @param problemId 问题id 61 | * @param userId 用户id 62 | * @return true 成功 63 | */ 64 | public boolean plusDoCount(int problemId, Integer userId) { 65 | if (!checkPrerequisite(userId, problemId, true)) { 66 | return false; 67 | } 68 | 69 | UpdateWrapper update = new UpdateWrapper(); 70 | update.setSql("do_count = do_count + 1"); 71 | update.set("last_do_time", DateUtils.now()); 72 | update.eq("problem_id", problemId); 73 | update.eq("user_id", userId); 74 | 75 | problemRecordService.insert(userId, problemId); 76 | return lcsrUserProblemService.update(update); 77 | } 78 | 79 | public CurrentDoCountVo currentDoCountVo(int problemId, Integer userId){ 80 | QueryWrapper query = new QueryWrapper(); 81 | query.select("do_count", "last_do_time"); 82 | query.eq("user_id", userId); 83 | query.eq("problem_id", problemId); 84 | 85 | LcsrUserProblem up = lcsrUserProblemService.getOne(query); 86 | if (up == null) { 87 | return null; 88 | } 89 | 90 | CurrentDoCountVo countVo = new CurrentDoCountVo(); 91 | countVo.setDoCount(up.getDoCount()); 92 | countVo.setLastDoTime(DateUtils.YyyyMmDd(up.getLastDoTime())); 93 | return countVo; 94 | } 95 | 96 | /** 97 | * 用户刷题记录概要Map 98 | * @param userId 用户id 99 | * @param status 刷题状态 100 | * @param fewDaysAgo 几天前 101 | * @return key 题目id 102 | */ 103 | public Map getUserProblemMap(int userId, int status, Integer fewDaysAgo){ 104 | QueryWrapper query = new QueryWrapper(); 105 | query.select("problem_id", "do_count", "status", "last_do_time"); 106 | query.eq("user_id", userId); 107 | if (status > 0) { 108 | query.eq("status", status); 109 | } 110 | if (fewDaysAgo != null) { 111 | LocalDateTime time = DateUtils.now(); 112 | time = time.plusDays(-fewDaysAgo); 113 | query.apply("DATE_FORMAT(last_do_time,'%Y-%m-%d')='" + DateUtils.YyyyMmDd(time) + "'"); 114 | } 115 | 116 | List list = lcsrUserProblemService.list(query); 117 | if (list.isEmpty()) { 118 | return new HashMap<>(); 119 | } 120 | 121 | Map map = new HashMap<>(list.size()); 122 | for (LcsrUserProblem up : list) { 123 | UserProblemBo bo = new UserProblemBo(); 124 | BeanUtils.copyProperties(up, bo); 125 | bo.setLastDoTime(up.getLastDoTime().getYear() < 2019 ? TextConstant.NONE 126 | : DateUtils.YyyyMmDd(up.getLastDoTime())); 127 | bo.setStatus(ProblemStatusEnum.title(up.getStatus())); 128 | map.put(up.getProblemId(), bo); 129 | } 130 | return map; 131 | } 132 | 133 | /** 134 | * 检查并初始化前提条件:更新刷题状态、完成+1的数据 135 | * @param userId 用户id 136 | * @param problemId 问题id 137 | * @param initLastDoTime true 初始化刷题时间 138 | * @return true 初始化前提条件成功,可以继续操作 139 | */ 140 | private boolean checkPrerequisite(Integer userId, int problemId, boolean initLastDoTime){ 141 | if (userId == null) { 142 | return false; 143 | } 144 | 145 | boolean isExistProblem = isExistProblem(userId, problemId, initLastDoTime); 146 | if (!isExistProblem) { 147 | return false; 148 | } 149 | 150 | return true; 151 | } 152 | 153 | /** 154 | * 判断用户刷题概要记录是否已存在,如果不存在就新增一条记录 155 | * @param userId 用户id 156 | * @param problemId 问题id 157 | * @param initLastDoTime true 初始化刷题时间 158 | * @return true 已存在 159 | */ 160 | private boolean isExistProblem(int userId, int problemId, boolean initLastDoTime){ 161 | QueryWrapper query = new QueryWrapper(); 162 | query.eq("user_id", userId); 163 | query.eq("problem_id", problemId); 164 | boolean isExist = lcsrUserProblemService.count(query) > 0 ? true : false; 165 | 166 | if (isExist) { 167 | return true; 168 | } 169 | 170 | LcsrUserProblem up = new LcsrUserProblem(); 171 | up.setUserId(userId); 172 | up.setProblemId(problemId); 173 | up.setAddTime(DateUtils.now()); 174 | up.setDoCount(0); 175 | up.setLastDoTime(initLastDoTime ? up.getAddTime() : DateUtils.now().plusYears(-9)); 176 | 177 | return lcsrUserProblemService.save(up); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.service; 2 | 3 | import com.aoeai.lcsr.bo.user.RegistOrLoginBo; 4 | import com.aoeai.lcsr.dao.entity.LcsrUser; 5 | import com.aoeai.lcsr.dao.service.ILcsrUserService; 6 | import com.aoeai.lcsr.utils.Cipher; 7 | import com.aoeai.lcsr.utils.DateUtils; 8 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * 用户相关 17 | */ 18 | @Service 19 | @Slf4j 20 | public class UserService { 21 | 22 | @Autowired 23 | private ILcsrUserService lcsrUserService; 24 | 25 | /** 26 | * 注册或者登录 27 | * @param username 28 | * @param password 29 | * @return 30 | */ 31 | public RegistOrLoginBo registOrLogin(String username, String password){ 32 | QueryWrapper query = new QueryWrapper(); 33 | query.select("id", "username", "password", "salt"); 34 | query.eq("username", username); 35 | LcsrUser user = lcsrUserService.getOne(query); 36 | 37 | RegistOrLoginBo result = new RegistOrLoginBo(); 38 | // 注册 39 | if (user == null) { 40 | user = new LcsrUser(); 41 | user.setUsername(username); 42 | user.setSalt(Cipher.getSalt()); 43 | user.setPassword(getPassword(password, user.getSalt())); 44 | user.setAddTime(DateUtils.now()); 45 | 46 | boolean flag = lcsrUserService.save(user); 47 | user.setPassword(null); 48 | log.info("新增用户 结果={} 用户={}", flag, user); 49 | }else { 50 | boolean isOk = verifyPassword(password, user.getPassword(), user.getSalt()); 51 | if (!isOk) { 52 | result.setSuccess(false); 53 | // TODO 后期优化 54 | result.setErrMsg("用户已存在!用户名或密码错误"); 55 | return result; 56 | } 57 | // 登录后替换salt 58 | user.setSalt(Cipher.getSalt()); 59 | user.setPassword(getPassword(password, user.getSalt())); 60 | boolean flag = lcsrUserService.updateById(user); 61 | user.setPassword(null); 62 | log.info("用户登录 结果={} 用户={}", flag, user); 63 | } 64 | 65 | result.setSuccess(true); 66 | result.setSalt(user.getSalt()); 67 | return result; 68 | } 69 | 70 | /** 71 | * 校验salt是否有效 72 | * @param salt true 有效 73 | * @return 74 | */ 75 | public boolean checkSalt(String salt){ 76 | QueryWrapper query = new QueryWrapper(); 77 | query.eq("salt", salt); 78 | int count = lcsrUserService.count(query); 79 | return count > 0; 80 | } 81 | 82 | /** 83 | * 根据salt获得用户id 84 | * @param salt 85 | * @return null salt已失效;用户id 86 | */ 87 | public Integer getIdBySalt(String salt) { 88 | QueryWrapper query = new QueryWrapper(); 89 | query.select("id"); 90 | query.eq("salt", salt); 91 | 92 | List list = lcsrUserService.list(query); 93 | if (list.isEmpty()) { 94 | return null; 95 | } 96 | // 居然salt碰撞了 97 | if (list.size() > 1) { 98 | return null; 99 | } 100 | 101 | LcsrUser user = list.get(0); 102 | return user.getId(); 103 | } 104 | 105 | private String getPassword(String password, String salt) { 106 | return Cipher.sha256(password + salt); 107 | } 108 | 109 | /** 110 | * 验证密码 111 | * @param receivePwd 接收到的密码 112 | * @param dbPwd 数据存储的密码 113 | * @param salt 114 | * @return true 验证通过 115 | */ 116 | private boolean verifyPassword(String receivePwd, String dbPwd, String salt){ 117 | return dbPwd.equals(getPassword(receivePwd, salt)); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/utils/Cipher.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.utils; 2 | 3 | import org.apache.commons.codec.digest.DigestUtils; 4 | 5 | public class Cipher { 6 | 7 | public final static String sha256(String str) { 8 | return DigestUtils.sha256Hex(str); 9 | } 10 | 11 | public final static String getSalt(){ 12 | return sha256("" + System.currentTimeMillis()); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/utils/DateUtils.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.utils; 2 | 3 | import java.time.LocalDateTime; 4 | import java.time.format.DateTimeFormatter; 5 | 6 | public class DateUtils { 7 | 8 | private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); 9 | 10 | public final static LocalDateTime now(){ 11 | return LocalDateTime.now(); 12 | } 13 | 14 | public final static String YyyyMmDd(LocalDateTime time){ 15 | return time.format(formatter); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/utils/TextUtils.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.utils; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URLEncoder; 5 | import java.nio.charset.StandardCharsets; 6 | 7 | public class TextUtils { 8 | 9 | public final static String urlEncoder(String str) { 10 | try { 11 | return URLEncoder.encode(str, StandardCharsets.UTF_8.name()); 12 | } catch (UnsupportedEncodingException e) { 13 | e.printStackTrace(); 14 | return null; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/utils/page/Page.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.utils.page; 2 | 3 | /** 4 | * 5 | * 分页对象 6 | */ 7 | public class Page { 8 | 9 | /** 10 | * 每页显示的记录数 11 | */ 12 | private int pageSize; 13 | 14 | /** 15 | * 总记录数 16 | */ 17 | private int totalCount; 18 | 19 | /** 20 | * 总页数 21 | */ 22 | private int totalPages; 23 | 24 | /** 25 | * 当前页 26 | */ 27 | private int currentNum = 1; 28 | 29 | /** 30 | * Mysql limit 第一个参数 31 | */ 32 | private int offset; 33 | 34 | public Page(int pageSize, int totalCount){ 35 | if (pageSize < 1){ 36 | pageSize = 1; 37 | } 38 | if(totalCount < 0){ 39 | totalCount = 0; 40 | } 41 | 42 | this.pageSize = pageSize; 43 | this.totalCount = totalCount; 44 | } 45 | 46 | public int getPageSize() { 47 | return pageSize; 48 | } 49 | 50 | public void setPageSize(int pageSize) { 51 | this.pageSize = pageSize; 52 | } 53 | 54 | public int getTotalCount() { 55 | return totalCount; 56 | } 57 | 58 | public int getTotalPages() { 59 | // 其中 pageSize - 1 就是 totalCount / pageSize的最大的余数 60 | totalPages = (totalCount + pageSize -1) / pageSize; 61 | totalPages = totalPages < 1 ? 1 : totalPages; 62 | return totalPages; 63 | } 64 | 65 | public int getOffset() { 66 | offset = (currentNum - 1) * pageSize; 67 | return offset; 68 | } 69 | 70 | public Page setCurrentNum(int currentNum) { 71 | if(currentNum > getTotalPages()){ 72 | currentNum = getTotalPages(); 73 | } 74 | if(currentNum < 1){ 75 | currentNum =1; 76 | } 77 | this.currentNum = currentNum; 78 | 79 | return this; 80 | } 81 | 82 | public int getCurrentNum() { 83 | return currentNum; 84 | } 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/utils/page/PageHelper.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.utils.page; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 分页小能手 7 | */ 8 | public class PageHelper { 9 | 10 | public static final Pagination buildPagination(Page page, List records){ 11 | Pagination pagination = new Pagination(); 12 | pagination.setCurrentPage(page.getCurrentNum()); 13 | pagination.setPageSize(page.getPageSize()); 14 | pagination.setRecords(records); 15 | pagination.setTotalCount(page.getTotalCount()); 16 | pagination.setTotalPages(page.getTotalPages()); 17 | 18 | return pagination; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/utils/page/Pagination.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.utils.page; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 分页对象 7 | */ 8 | public class Pagination { 9 | 10 | /** 11 | * 每页显示的记录数 12 | */ 13 | private int pageSize; 14 | 15 | /** 16 | * 总记录数 17 | */ 18 | private int totalCount; 19 | 20 | /** 21 | * 总页数 22 | */ 23 | private int totalPages; 24 | 25 | /** 26 | * 当前页 27 | */ 28 | private int currentPage = 1; 29 | 30 | /** 31 | * 分页数据 32 | */ 33 | private List records; 34 | 35 | public int getPageSize() { 36 | return pageSize; 37 | } 38 | 39 | public Pagination setPageSize(int pageSize) { 40 | this.pageSize = pageSize; 41 | return this; 42 | } 43 | 44 | public int getTotalCount() { 45 | return totalCount; 46 | } 47 | 48 | public Pagination setTotalCount(int totalCount) { 49 | this.totalCount = totalCount; 50 | return this; 51 | } 52 | 53 | public int getTotalPages() { 54 | return totalPages; 55 | } 56 | 57 | public Pagination setTotalPages(int totalPages) { 58 | this.totalPages = totalPages; 59 | return this; 60 | } 61 | 62 | public int getCurrentPage() { 63 | return currentPage; 64 | } 65 | 66 | public Pagination setCurrentPage(int currentPage) { 67 | this.currentPage = currentPage; 68 | return this; 69 | } 70 | 71 | public List getRecords() { 72 | return records; 73 | } 74 | 75 | public Pagination setRecords(List records) { 76 | this.records = records; 77 | return this; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/vo/user/ProblemVo.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.vo.user; 2 | 3 | import com.aoeai.lcsr.enums.ProblemDifficultyEnum; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class ProblemVo { 8 | 9 | private Integer id; 10 | 11 | /** 12 | * 问题 13 | */ 14 | private String problem; 15 | 16 | /** 17 | * 问题的英文版 18 | */ 19 | private String problemEn; 20 | 21 | /** 22 | * 难度 1:简单;2:中等;3困难 23 | */ 24 | private ProblemDifficultyEnum difficulty; 25 | 26 | /** 27 | * 中文站链接 28 | */ 29 | private String urlCN; 30 | 31 | /** 32 | * 国际站链接 33 | */ 34 | private String urlEN; 35 | 36 | /** 37 | * 刷题次数 38 | */ 39 | private String doCount; 40 | 41 | /** 42 | * 当前状态 43 | */ 44 | private String status; 45 | 46 | /** 47 | * 最后做题时间 48 | */ 49 | private String lastDoTime; 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/vo/user/RegistOrLoginVo.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.vo.user; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 注册或登录返回给页面的处理结果 7 | */ 8 | @Data 9 | public class RegistOrLoginVo { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/aoeai/lcsr/vo/userproblem/CurrentDoCountVo.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr.vo.userproblem; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 当前刷题数据 7 | */ 8 | @Data 9 | public class CurrentDoCountVo { 10 | 11 | /** 12 | * 刷题次数 13 | */ 14 | private Integer doCount; 15 | 16 | /** 17 | * 最后刷题时间 18 | */ 19 | private String lastDoTime; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | # mybatisPlus 性能分析差价开关,自定义 5 | performance: 6 | enable: true 7 | 8 | spring: 9 | thymeleaf: 10 | # 发布时改成true 11 | cache: false 12 | mvc: 13 | static-path-pattern: /static/** 14 | # 数据库 15 | datasource: 16 | url: jdbc:mysql://localhost:3306/aoeai-leet-code-study-record?useSSL=false&jdbcCompliantTruncation=false&characterEncoding=UTF-8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai 17 | username: test 18 | password: 123456 19 | hikari: 20 | maximumPoolSize: 10 21 | minimumIdle: 2 22 | idleTimeout: 600000 23 | connectionTimeout: 30000 24 | maxLifetime: 1800000 25 | 26 | mybatis-plus: 27 | mapper-locations: classpath*:mapper/*.xml 28 | # type-aliases-package: com.aoeai.lcsr.dao.entity 29 | configuration: 30 | map-underscore-to-camel-case: true 31 | global-config: 32 | # 不重启刷新XML文件,开发开启,生产关闭 3.0.6 已关闭 33 | # refresh: true 34 | db-config: 35 | db-type: mysql 36 | #主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID"; 37 | id-type: id_worker 38 | # 逻辑已删除值,(逻辑删除下有效) 39 | logic-delete-value: 1 40 | # 逻辑未删除值,(逻辑删除下有效) 41 | logic-not-delete-value: 0 42 | # 字段策略 ignore:"忽略判断",not_null:"非 NULL 判断"),not_empty:"非空判断" 43 | field-strategy: not_null 44 | 45 | #logging: 46 | # level: 47 | # com: 48 | # aoeai: 49 | # lcsr: 50 | # dao: 51 | # mapper: debug 52 | 53 | #logback: 54 | # logdir: ~/test 55 | # appname: lcsr -------------------------------------------------------------------------------- /src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | %d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n 11 | 12 | 13 | 14 | 15 | 16 | true 17 | 18 | 19 | error 20 | ACCEPT 21 | DENY 22 | 23 | 24 | ${logging.path}/error.log 25 | 26 | 27 | 28 | ${logging.path}/error.log.%d{yyyy-MM-dd} 29 | 30 | 30 31 | 32 | 33 | 34 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 35 | 36 | UTF-8 37 | 38 | 39 | 40 | 41 | true 42 | 43 | INFO 44 | ACCEPT 45 | DENY 46 | 47 | ${logging.path}/catalina.log 48 | 49 | 50 | 51 | ${logging.path}/catalina.log.%d{yyyy-MM-dd} 52 | 53 | 54 | 30 55 | 56 | 57 | 58 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 59 | 60 | UTF-8 61 | 62 | 63 | 64 | 65 | 66 | true 67 | 68 | INFO 69 | 70 | ${logging.path}/mdc.log 71 | 72 | 73 | 74 | ${logging.path}/mdc.log.%d{yyyy-MM-dd} 75 | 76 | 77 | 30 78 | 79 | 80 | 81 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{SOFA-TraceId},%X{SOFA-SpanId}] %logger{50} - %msg%n 82 | 83 | UTF-8 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/main/resources/mapper/LcsrProblemMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/LcsrProblemRecordMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/LcsrUserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/LcsrUserProblemMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/static/css/signin.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | body { 7 | display: -ms-flexbox; 8 | display: flex; 9 | -ms-flex-align: center; 10 | align-items: center; 11 | padding-top: 40px; 12 | padding-bottom: 40px; 13 | background-color: #f5f5f5; 14 | } 15 | 16 | .form-signin { 17 | width: 100%; 18 | max-width: 330px; 19 | padding: 15px; 20 | margin: auto; 21 | } 22 | .form-signin .checkbox { 23 | font-weight: 400; 24 | } 25 | .form-signin .form-control { 26 | position: relative; 27 | box-sizing: border-box; 28 | height: auto; 29 | padding: 10px; 30 | font-size: 16px; 31 | } 32 | .form-signin .form-control:focus { 33 | z-index: 2; 34 | } 35 | .form-signin input[type="email"] { 36 | margin-bottom: -1px; 37 | border-bottom-right-radius: 0; 38 | border-bottom-left-radius: 0; 39 | } 40 | .form-signin input[type="password"] { 41 | margin-bottom: 10px; 42 | border-top-left-radius: 0; 43 | border-top-right-radius: 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/resources/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aoeai/leet-code-study-record/a9a40929527887e31aca3a69f5db7eb800419d42/src/main/resources/static/images/logo.png -------------------------------------------------------------------------------- /src/main/resources/templates/common/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 哦呦,出错了 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | Hello, world! 6 | 7 | 8 | 9 | 10 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/templates/problem/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | LeetCode问题列表 6 | 7 | 8 | 9 |
10 | 11 |
12 | 13 | 14 |
15 |
16 |
17 |
18 | 题目过滤 19 |
20 | 22 |
23 | Please choose a username. 24 |
25 |
26 |
27 |
28 |
29 |
30 | 几天前 31 |
32 | 37 |
38 | Please choose a username. 39 |
40 |
41 |
42 |
43 | 51 |
52 |
53 | 54 | 清 55 | 空 56 |
57 |
58 |

欢迎

59 |
60 |
61 | 62 | 63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 92 | 93 | 107 | 108 | 114 | 115 | 116 |
#标题难度刷题次数当前状态最后做题时间操作
82 | 85 | 88 | 91 | 1 94 |
95 | 100 | 105 |
106 |
2019-11-13 109 | 112 | 113 |
117 | 118 | 119 | 135 |
136 | 137 |
138 | 139 | 140 | 163 | 164 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /src/test/java/com/aoeai/lcsr/LeetCodeStudyRecordApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.aoeai.lcsr; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class LeetCodeStudyRecordApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------