|
| 1 | +--- |
| 2 | +title: ARTS(第1周) |
| 3 | +category: ARTS |
| 4 | +tags: arts |
| 5 | +--- |
| 6 | + |
| 7 | +# ARTS(第1周) |
| 8 | + |
| 9 | +> 每周完成一个ARTS: |
| 10 | +> 1. Algorithm:每周至少做一个 leetcode 的算法题 |
| 11 | +> 2. Review:阅读并点评至少一篇英文技术文章 |
| 12 | +> 3. Tip:学习至少一个技术技巧 |
| 13 | +> 4. Share:分享一篇有观点和思考的技术文章 |
| 14 | +
|
| 15 | +> **本周提纲:** |
| 16 | +> 1. Algorithm: 最长回文子串 |
| 17 | +> 2. Review: Go语言中什么时候该使用 |
| 18 | +> 3. Tip: 一个vim插件`vim-surround`使用 |
| 19 | +> 4. Share: 我必须告诉大家的MySQL优化原理 |
| 20 | +
|
| 21 | +<!-- more --> |
| 22 | + |
| 23 | +## Algorithm |
| 24 | + |
| 25 | +[最长回文子串](https://leetcode-cn.com/problems/longest-palindromic-substring/) |
| 26 | + |
| 27 | +**描述** |
| 28 | + |
| 29 | +> 给定一个字符串,找出最大的回文字符串(回文字符串:正读反读都一样的字符串.eg: a aba abba ...) |
| 30 | +> |
| 31 | +> 示例 1: |
| 32 | +> |
| 33 | +>> 输入: "babad" |
| 34 | +>> 输出: "bab" |
| 35 | +>> 注意: "aba" 也是一个有效答案。 |
| 36 | +> 示例 2: |
| 37 | +> |
| 38 | +>> 输入: "cbbd" |
| 39 | +>> 输出: "bb" |
| 40 | +> |
| 41 | +
|
| 42 | +**实现的思路** |
| 43 | + |
| 44 | +> 设置一个头指针和一个尾指针 |
| 45 | +> * 尾指针每次前移一个位置,检查头尾指针间的字符串是否为回文字符串直到头尾指针所指的位置一致停止 |
| 46 | +> + 检测到回文字符串则记录当前回文字符串是否是最长的,如果是则重置最大回文字符串的值,然后将头指针指向尾指针所指的位置(因为在这之间不可能再有最大回文字符串了) |
| 47 | +> + 未检测到回文字符串尾指针前移 |
| 48 | +
|
| 49 | +```python |
| 50 | +class Solution: |
| 51 | + def longestPalindrome(self, s: str) -> str: |
| 52 | + """ |
| 53 | + :type s:str |
| 54 | + :rtype: int |
| 55 | + """ |
| 56 | + strLen = len(s) |
| 57 | + i = 0 |
| 58 | + maxPdr = "" |
| 59 | + for i in range(0,strLen): |
| 60 | + iEnd = strLen |
| 61 | + while i < iEnd: |
| 62 | + temp = s[i:iEnd] |
| 63 | + reverTemp = temp[::-1] |
| 64 | + if temp == reverTemp: |
| 65 | + maxPdr = temp if len(maxPdr) < len(temp) else maxPdr |
| 66 | + i = iEnd - 1 |
| 67 | + break |
| 68 | + else: |
| 69 | + iEnd = iEnd - 1 |
| 70 | + return maxPdr |
| 71 | +``` |
| 72 | + |
| 73 | +## Review |
| 74 | + |
| 75 | +[When and Why to use a Least Frequently Used (LFU) cache with an implementation in Golang](https://ieftimov.com/post/when-why-least-frequently-used-cache-implementation-golang/) |
| 76 | + |
| 77 | +**一个谷歌工程师编码解决问题的过程** |
| 78 | + |
| 79 | +给出的例子: |
| 80 | +> 给定两个字符串`sourceString`和`searchString`,返回`sourceString`第一次出现`searchString`的位置,如果不包含`searchString`则返回`-1` |
| 81 | +
|
| 82 | +解决的过程: |
| 83 | + |
| 84 | +1. 画出来 |
| 85 | +拿到问题就开始编码,可能是一种低效的解决问题的方式,作者建议我们首先要分析问题,甚至不要使用写代码的方式来思考问题,把问题画下来,针对一些具体的问题来画出解决的方案(算法)。 |
| 86 | + |
| 87 | +2. 写出解决的逻辑步骤 |
| 88 | +用语言描述需要解决的问题步骤: |
| 89 | +> 1. 从字符串的开头开始扫描 |
| 90 | +> 2. 查找`searchString`长度的字符串数组 |
| 91 | +> 3. 找到返回当前字符串的数组下标 |
| 92 | +> 4. 如果查询到最后没找到则返回`-1` |
| 93 | +
|
| 94 | +3. 伪代码 |
| 95 | +``` |
| 96 | +for each index in sourceString, |
| 97 | + N = searchString.length |
| 98 | + POSSIBLE_MATCH = sourceString[index to index+N] |
| 99 | + if POSSIBLE_MATCH === searchString: |
| 100 | + return index |
| 101 | +return -1 |
| 102 | +``` |
| 103 | +4. 转换成代码 |
| 104 | +这一步可能存在一些实际的函数和方法的使用问题,完成主要的逻辑后再来回过头处理这些需要解决的细节问题 |
| 105 | +5. 明确代码中每一步的逻辑 |
| 106 | +每一句代码都要明确它的目的,否则这很可能会是以后冒出bug的地方 |
| 107 | +> 就像前面的 **Algorithm**部分的代码`tempMaxLen = index - i# tempMaxLen = index - i + 1`,以前有个`+1`的运算,如果Hash表中的当前字符的历史位置在现在统计子字符串起始位置之后需要那么新的自字符串的长度为当前的新的字符位置`index` - `i`,为什么不`+1`(上面的if的逻辑中有`+1`),就是因为`startCharIndex = i + 1`(这里`+1`了) |
| 108 | +
|
| 109 | +## Tip |
| 110 | +介绍一个vim的快速添加‘环绕字符’(eg: '',"",xml标签),省去了来回移动光标的操作 |
| 111 | +[vim-surround](https://github.com/tpope/vim-surround) |
| 112 | + |
| 113 | +```shell |
| 114 | +#常用操作 |
| 115 | + |
| 116 | +# 替换: cs"' |
| 117 | +"Hello world!" -> 'Hello world!' |
| 118 | + |
| 119 | +# 替换-标签(t=tag): cst" |
| 120 | +<a>abc</a> -> "abc" |
| 121 | + |
| 122 | +cst<html> |
| 123 | +<a>abc</a> -> <html>abc</html> |
| 124 | + |
| 125 | +# 删除: ds" |
| 126 | +"Hello world!" -> Hello world! |
| 127 | + |
| 128 | +# 添加(ys=you surround): ysiw" |
| 129 | +Hello -> "Hello" |
| 130 | + |
| 131 | +# 添加: csw" |
| 132 | +Hello -> "Hello" |
| 133 | + |
| 134 | +# 添加-整行: yss" |
| 135 | +Hello world -> "Hello world" |
| 136 | + |
| 137 | +# 添加段落: ySS" |
| 138 | +Hello world -> |
| 139 | +" |
| 140 | + hello world |
| 141 | + " |
| 142 | + |
| 143 | +# 添加-两个词: veeS" |
| 144 | +hello world -> "hello world" |
| 145 | + |
| 146 | +# 添加-当前到行尾: ys$" |
| 147 | + |
| 148 | +# 左符号/右符号 => 带不带空格 |
| 149 | +cs([ |
| 150 | + (hello) -> [ hello ] |
| 151 | + |
| 152 | +cs(] |
| 153 | + (hello) -> [hello] |
| 154 | +``` |
| 155 | +## Share |
| 156 | +[我必须告诉大家的MySQL优化原理](https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247487949&idx=1&sn=511adecca65154fd9fc7f9cf5047e5ff&chksm=ebd62ee1dca1a7f7330ebcd9429a8bb0c274c9b621b39256042043a017723fd80b5249302e24&mpshare=1&scene=24&srcid=&pass_ticket=lMXQ4p26y6CqIePcjTdYn9yazMYtVCmHy8HFY3vHcl3ymry0kK6Oq1qSonPO4Jk8#rd) |
| 157 | +
|
| 158 | +MySQL查询优化的建议: |
| 159 | +
|
| 160 | +1. 首先了解MySQL的逻辑架构 |
| 161 | + |
| 162 | +2. MySQL的查询过程 |
| 163 | + |
| 164 | + * 客户端/服务端通信协议 |
| 165 | + + 客户端和服务端的通信是“半双工”,所以两端不能同时发送数据 |
| 166 | + + 如果查询缓存是打开的,那么MySQL会检查是否命中缓存 |
| 167 | + * 查询缓存 |
| 168 | + * 语法解析和预处理 |
| 169 | + * 查询优化 |
| 170 | + + 重新定义表关联 |
| 171 | + + 优化`MIN()` 和 `MAX()`函数 |
| 172 | + + 提前终止查询 |
| 173 | + + 优化排序 |
| 174 | + + ... ... |
| 175 | + * 查询执行引擎 |
| 176 | + * 返回结果给客户端 |
| 177 | + + 查询结果缓存(缓存被打开) |
| 178 | +> 回头总结一下MySQL整个查询执行过程,总的来说分为5个步骤: |
| 179 | +> |
| 180 | +> * 客户端向MySQL服务器发送一条查询请求 |
| 181 | +> * 服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段 |
| 182 | +> * 服务器进行SQL解析、预处理、再由优化器生成对应的执行计划 |
| 183 | +> * MySQL根据执行计划,调用存储引擎的API来执行查询 |
| 184 | +> * 将结果返回给客户端,同时缓存查询结果 |
| 185 | +
|
| 186 | +3. 性能优化建议 |
| 187 | +> 不要听信你看到的关于优化的“绝对真理”(试用自己的才是最好的,业务!业务!业务!) |
| 188 | + * Scheme设计与数据类型优化 |
| 189 | + + 小而简单的数据类型 |
| 190 | + + `NULL` 列改为 `NOT NULL`不会明显提升性能,只有计划在该列上创建索引时,就应该将列设置为`NOT NULL` |
| 191 | + + 对整数类型设置宽度是没有作用的,数据类型的大小是确定的(只有字段使用`ZEROFILL`,在显示的时候如果位数不够是会添加前导零的) |
| 192 | + + `DATETIME`使用8个字节存储空间,`TIMESTAMP`使用4个字节因而,TIMESTAMP只能表示1970 - 2038年,比DATETIME表示的范围小得多,而且TIMESTAMP的值因时区不同而不同。 |
| 193 | + + schema列不要太多 |
| 194 | + * 创建高性能索引 |
| 195 | +  |
| 196 | + + 带有表达式计算的不会使用索引 |
| 197 | + + 前缀索引可以降低索引空间提高效率 |
| 198 | + + 多列索引和索引顺序 |
| 199 | +
|
| 200 | + > 当出现多个索引做相交操作时(多个AND条件),通常来说一个包含所有相关列的索引要优于多个独立索引。 |
| 201 | + > 当出现多个索引做联合操作时(多个OR条件),对结果集的合并、排序等操作需要耗费大量的CPU和内存资源,特别是当其中的某些索引的选择性不高,需要返回合并大量数据时,查询成本更高。所以这种情况下还不如走全表扫描。 |
| 202 | +
|
| 203 | + + 多条件那个能更好的缩减数据量那个索引列放在前面 |
| 204 | + + 避免多个范围条件 |
| 205 | + + 覆盖索引(结果列都是索引中的值) |
| 206 | + + 避免冗余和重复索引 |
| 207 | + + 删除长期未使用的索引 |
| 208 | + * 特定类型优化 |
| 209 | + + 优化count()查询 |
| 210 | + + 优化关联查询 |
| 211 | + > 只需要在关联顺序中第二张表的相应列上创建索引 |
| 212 | + > 确保`GROUP BY` 和 `ORDER BY` 中的列只涉及到一个表的列 |
| 213 | + + 优化UNION |
| 214 | +
|
0 commit comments