├── .gitignore ├── assests ├── book.jpg ├── cpp │ ├── 01.png │ ├── 02.png │ ├── 03.png │ ├── 04.png │ ├── 05.png │ ├── 06.png │ ├── 07.png │ ├── 08.png │ ├── 09.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ └── 13.png ├── golang │ ├── 01.png │ ├── 02.png │ ├── 03.png │ ├── 04.png │ └── 05.png ├── linux │ ├── 01.png │ ├── 02.png │ ├── 03.png │ ├── 04.png │ ├── 05.png │ ├── 06.png │ ├── 07.png │ ├── 08.png │ ├── 09.png │ ├── 10.png │ ├── 11.jpg │ └── 11.png ├── mysql │ ├── 01.png │ ├── 02.png │ ├── 03.png │ ├── 04.png │ ├── 05.png │ ├── 06.png │ ├── 07.png │ ├── 08.png │ ├── 09.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ └── 20.png ├── networking │ ├── 01.png │ ├── 02.jpg │ └── 02.png └── redis │ └── 01.png ├── bill.py ├── cpp ├── C++意外的生命周期.md ├── Intro to the C++ Object Model.md ├── Lock-free programming with modern C++ .md ├── LockFreeQueue.hpp ├── stl │ ├── CMakeLists.txt │ └── src │ │ ├── SGI_alloc.hpp │ │ ├── lock_free_queue.hpp │ │ └── stl_iterator.hpp ├── 模板编程入门-sfinae基础.md ├── 模板编程入门-优雅的容器输出器.md ├── 给小学六年级的简易模板元“编程”入门-基础编程.md └── 聊聊boost--Operators和继承链.md ├── ddia └── ddia.md ├── golang └── golang.md ├── leetcode ├── 3sum.py ├── 3sum_closest.py ├── 4sum_ii.py ├── add-two-numbers-ii.py ├── add_two_numbers.py ├── basic-calculator-ii.py ├── best-time-to-buy-and-sell-stock-ii.py ├── best_sightseeing_pair.py ├── binary-tree-level-order-traversal.py ├── binary-tree-zigzag-level-order-traversal.py ├── binary.py ├── candy.py ├── coin-change.py ├── construct_binary_tree_from_inorder_and_postorder_traversal.py ├── container_with_most_water.py ├── copy-list-with-random-pointer │ └── submissions.py ├── decode-ways.py ├── divide_two_integers.py ├── evaluate-reverse-polish-notation.py ├── find_first_and_last_position_of_element_in_sorted_array.py ├── find_minimum_in_rotated_sorted_array.py ├── first-unique-character-in-a-string.py ├── flatten-binary-tree-to-linked-list.py ├── generate_parentheses.py ├── house-robber.py ├── implement-trie-prefix-tree.py ├── increasing-triplet-subsequence.py ├── insert-into-a-cyclic-sorted-list │ └── submissions.py ├── integer_break.py ├── integer_to_roman.py ├── intersection-of-two-linked-lists.py ├── interview │ ├── bilibili │ │ ├── 01.py │ │ ├── 02.py │ │ └── 03.py │ ├── fast-speak-english │ │ ├── 01.py │ │ └── 02.py │ └── little-red-book │ │ ├── 01.py │ │ ├── 02.py │ │ ├── 03.py │ │ └── 04.py ├── invert_binary_tree.py ├── k_th_smallest_in_lexicographical_order.py ├── kth-smallest-element-in-a-bst.py ├── lcs.py ├── letter_combinations_of_a_phone_number.py ├── linked_list_cycle_ii.py ├── longest-consecutive-sequence.py ├── longest-string-chain.py ├── longest-substring-with-at-least-k-repeating-characters.py ├── longest-substring_without_repeating_characters.py ├── longest_increasing_subsequence.py ├── longest_palindromic_substring.py ├── longest_repeating_character_replacement.py ├── lowest-common-ancestor-of-a-binary-tree.py ├── lru_cache.py ├── majority-element.py ├── maximum-product-subarray.py ├── merge-sorted-array.py ├── min_stack.py ├── minimum_window_substring.py ├── next_node_bin_tree.py ├── next_permutation.py ├── number-of-longest-increasing-subsequence.py ├── number_of_atoms.py ├── odd_even_linked_list.py ├── package.py ├── palindrome-partitioning.py ├── part_link.py ├── path_sum_ii.py ├── regular_expression_matching.py ├── remove_nth_node_from_end_of_list.py ├── reorder-list.py ├── repeated-string-match.py ├── restore_ip_addresses.py ├── reverse-linked-list-ii.py ├── reverse-linked-list │ └── submissions.py ├── reverse-nodes-in-k-group.py ├── reverse-string.py ├── reverse_linked_list.py ├── rotate-array.py ├── search-a-2d-matrix-ii.PY ├── search_in_rotated_sorted_array.py ├── serialize_and_deserialize_binary_tree.py ├── set-matrix-zeroes.py ├── single-number.py ├── sliding-window-maximum.py ├── string_to_integer_atoi.py ├── super-egg-drop.py ├── symmetric_tree.py ├── trapping_rain_water.py ├── unique-paths-ii.py ├── unique-paths.py ├── utf_8_validation.py ├── valid-anagram.py ├── valid-palindrome.py ├── valid_sudoku.py ├── validate_stack_sequences.py ├── verify_preorder_sequence_in_binary_search_tree.py ├── wildcard-matching.py ├── word-break.py ├── word-search-ii.py └── zigzag_conversion.py ├── linux ├── linux.md ├── 中断和系统调用.md ├── 内核初始化.md ├── 启动引导.md └── 锁和进程间通信.md ├── mysql └── mysql复习重点.md ├── networking ├── tcp.md ├── 协程-事件循环-异步io并发.md └── 理解有栈协程.md ├── nginx └── nginx.md ├── other ├── CPU 你要知道的.md ├── parser.py ├── 思考cpu占用.md ├── 错误处理.md └── 闭包, call-cc和 cps 变换.md ├── python 源码 └── python.md ├── quic └── rfc.md ├── readme.md ├── redis ├── ae │ └── ae.h └── redis.md ├── 分布式 ├── tanlent_plan │ ├── 一条 sql 的旅行.md │ └── 进阶数据库-逻辑优化.md ├── 分布式学习笔记(一).md ├── 分布式学习笔记(三).md └── 分布式学习笔记(二).md ├── 基础算法 ├── binary_tree.md ├── heap.py ├── sort.md ├── 二分法.md └── 字符串 │ └── kmp.py ├── 杂谈 ├── 你会变成你的人设.md ├── 吐槽一下大学CS教育.md ├── 家长式政府的公信力和开放意识的觉醒.md └── 没有优秀, 也没必要优秀.md ├── 毕设.md ├── 秋招 ├── 岗位选择.md ├── 怎么写一份好看的校招简历.md ├── 秋招Q&A.md ├── 秋招总结.md ├── 给计算机相关专业找实习的朋友的一些话.md └── 面试速成.md ├── 面筋 └── 字节跳动_广告.md └── 面试迷思--理解内存管理从 Python 到 malloc 再到 linux(上).md /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | 35 | 36 | .idea 37 | .vscode 38 | bin 39 | obj 40 | debug 41 | 42 | __pycache__ 43 | 44 | cmake-build-debug 45 | 46 | .DS_Sotre 47 | -------------------------------------------------------------------------------- /assests/book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/book.jpg -------------------------------------------------------------------------------- /assests/cpp/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/01.png -------------------------------------------------------------------------------- /assests/cpp/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/02.png -------------------------------------------------------------------------------- /assests/cpp/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/03.png -------------------------------------------------------------------------------- /assests/cpp/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/04.png -------------------------------------------------------------------------------- /assests/cpp/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/05.png -------------------------------------------------------------------------------- /assests/cpp/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/06.png -------------------------------------------------------------------------------- /assests/cpp/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/07.png -------------------------------------------------------------------------------- /assests/cpp/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/08.png -------------------------------------------------------------------------------- /assests/cpp/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/09.png -------------------------------------------------------------------------------- /assests/cpp/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/10.png -------------------------------------------------------------------------------- /assests/cpp/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/11.png -------------------------------------------------------------------------------- /assests/cpp/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/12.png -------------------------------------------------------------------------------- /assests/cpp/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/cpp/13.png -------------------------------------------------------------------------------- /assests/golang/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/golang/01.png -------------------------------------------------------------------------------- /assests/golang/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/golang/02.png -------------------------------------------------------------------------------- /assests/golang/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/golang/03.png -------------------------------------------------------------------------------- /assests/golang/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/golang/04.png -------------------------------------------------------------------------------- /assests/golang/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/golang/05.png -------------------------------------------------------------------------------- /assests/linux/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/01.png -------------------------------------------------------------------------------- /assests/linux/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/02.png -------------------------------------------------------------------------------- /assests/linux/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/03.png -------------------------------------------------------------------------------- /assests/linux/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/04.png -------------------------------------------------------------------------------- /assests/linux/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/05.png -------------------------------------------------------------------------------- /assests/linux/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/06.png -------------------------------------------------------------------------------- /assests/linux/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/07.png -------------------------------------------------------------------------------- /assests/linux/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/08.png -------------------------------------------------------------------------------- /assests/linux/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/09.png -------------------------------------------------------------------------------- /assests/linux/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/10.png -------------------------------------------------------------------------------- /assests/linux/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/11.jpg -------------------------------------------------------------------------------- /assests/linux/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/linux/11.png -------------------------------------------------------------------------------- /assests/mysql/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/01.png -------------------------------------------------------------------------------- /assests/mysql/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/02.png -------------------------------------------------------------------------------- /assests/mysql/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/03.png -------------------------------------------------------------------------------- /assests/mysql/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/04.png -------------------------------------------------------------------------------- /assests/mysql/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/05.png -------------------------------------------------------------------------------- /assests/mysql/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/06.png -------------------------------------------------------------------------------- /assests/mysql/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/07.png -------------------------------------------------------------------------------- /assests/mysql/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/08.png -------------------------------------------------------------------------------- /assests/mysql/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/09.png -------------------------------------------------------------------------------- /assests/mysql/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/10.png -------------------------------------------------------------------------------- /assests/mysql/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/11.png -------------------------------------------------------------------------------- /assests/mysql/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/12.png -------------------------------------------------------------------------------- /assests/mysql/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/13.png -------------------------------------------------------------------------------- /assests/mysql/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/14.png -------------------------------------------------------------------------------- /assests/mysql/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/15.png -------------------------------------------------------------------------------- /assests/mysql/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/16.png -------------------------------------------------------------------------------- /assests/mysql/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/17.png -------------------------------------------------------------------------------- /assests/mysql/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/18.png -------------------------------------------------------------------------------- /assests/mysql/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/19.png -------------------------------------------------------------------------------- /assests/mysql/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/mysql/20.png -------------------------------------------------------------------------------- /assests/networking/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/networking/01.png -------------------------------------------------------------------------------- /assests/networking/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/networking/02.jpg -------------------------------------------------------------------------------- /assests/networking/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/networking/02.png -------------------------------------------------------------------------------- /assests/redis/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IcyCC/effective_note/d55074032217c48e3d872d4524ba6cea94613b86/assests/redis/01.png -------------------------------------------------------------------------------- /bill.py: -------------------------------------------------------------------------------- 1 | 2 | from datetime import datetime, date 3 | 4 | 5 | template = """ 6 | #猪猪攒钱史# Day {days} {today} 7 | 已花费总计:👸🏼 {girl_total}元 🐷 {boy_total}元 8 | 🌸🌸🌼🌼🌻🌻🌸🌸🌼🌼🌻🌻 9 | 👸🏼: 10 | {girl_cost_text} 11 | ——————————— 12 | 💰: {girl_today_total} 13 | 14 | 🐷: 15 | {boy_cost_text} 16 | —————————— 17 | 💰: {boy_today_total} 18 | """ 19 | 20 | today = date.today() 21 | start_day = date(year=2022, month=1, day=18) 22 | days = (today - start_day).days + 1 23 | 24 | def get_emoji_day(num): 25 | res = "" 26 | emoji_list = ["0️⃣","1️⃣","2️⃣","3️⃣","4️⃣","5️⃣","6️⃣","7️⃣","8️⃣","9️⃣"] 27 | for i in str(num): 28 | res = res + emoji_list[int(i)] 29 | return res 30 | 31 | def stand_str(s): 32 | return s.replace(":", ",").replace(" ","").replace(",", ",") 33 | 34 | gril_bill = """ 35 | 早餐,2.5 36 | 交通, 3 37 | Vintage耳饰,399 38 | 咖啡, 22 39 | 晚饭, 吃了筑底食堂(日料),120 40 | 草莓🍓, 13.5 41 | 房租,2990 42 | """ 43 | gril_pre= 635.8 44 | 45 | boy_bill = """ 46 | 早饭,馒头片, 1 47 | 今天公司调休,午饭晚饭免费,0 48 | 剪头发,35 49 | """ 50 | boy_pre = 3548 51 | 52 | def pareser(bill:str, pre_total): 53 | bill = stand_str(bill) 54 | result = [] 55 | total = 0 56 | bill_lines = bill.splitlines() 57 | for line in bill_lines: 58 | if not line: 59 | continue 60 | blocks = line.split(",") 61 | if len(blocks) == 2: 62 | (name, cost) = blocks 63 | total = total + float(cost) 64 | result.append("{name}:{cost} 元".format(name=name, cost=cost)) 65 | if len(blocks) == 3: 66 | (name, note, cost) = blocks 67 | total = total + float(cost) 68 | result.append("{name}: {note} {cost}元".format(name=name, cost=cost, note=note)) 69 | return { 70 | "today_total": total, 71 | "total": pre_total + total, 72 | "cost_text": "\n".join(result) 73 | } 74 | 75 | girl = {"girl_"+k:v for k,v in pareser(gril_bill, gril_pre).items()} 76 | boy = {"boy_"+k:v for k,v in pareser(boy_bill, boy_pre).items()} 77 | print(days) 78 | print(template.format( 79 | today=today.strftime("%Y.%m.%d"), 80 | days=get_emoji_day(days), 81 | **girl, **boy)) 82 | -------------------------------------------------------------------------------- /cpp/C++意外的生命周期.md: -------------------------------------------------------------------------------- 1 | # C++ 意外的生命周期 2 | 3 | ## 什么是对象? 4 | 5 | 对象类型就是 一个 不是 函数, 不是 引用, 不是空的 类型. 6 | 7 | ## 生命周期 8 | 9 | 开始: 一个对象被非空初始化的时候 10 | 11 | 结束: 一个对象被 重要的析构 析构 或者 占据的空间被释放 12 | 13 | 14 | ### 引用没有生命周期 15 | 16 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227110523.png) 17 | 18 | 第一个没什么可说的 19 | 20 | 21 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227110707.png) 22 | 23 | 第二个可以看出, 引用没生命周期 24 | 25 | > [[maybe_unused]] 取消对没有使用的 warnning 26 | 27 | 28 | 29 | ### 用标准库简单包裹一下, 会引发编译器识别错误 30 | 31 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227111428.png) 32 | 33 | 返回一个 local 的 refrence 是一个未定义的行为, 34 | 一般会给警告, 返回了一个 stack memory 类似的 35 | 36 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227113108.png) 37 | 38 | 也是一个未定义行为. 不过大部分编译器不会给警告 39 | 40 | ## 例子 41 | 42 | ### 字符串 43 | 44 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227113713.png) 45 | 46 | 这个一切正常, 因为字面量在 static 段 47 | 48 | **重点: 字面量的生命周期比想的长,** 49 | 50 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227113933.png) 51 | 52 | > string_view 是一个简单的指针 53 | 54 | 这个一切正常 55 | 56 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227114051.png) 57 | 58 | 这个是一个未定义行为, 实际上返回了stack 的 内存, 不会得到 warning, 但是会乱码或者不输出.. 59 | 60 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227114614.png) 61 | 62 | 这个一切没有警告, 打印了空, 因为 s 是一个数组 在 stack 上 63 | 64 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227115957.png) 65 | 66 | 这样就正常了 可以输出, 因为指向了 常量区 67 | 68 | **重点: 字符串数组不长**: 69 | 70 | ### 容器 71 | 72 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227115518.png) 73 | 74 | 结果: 75 | 76 | ``` 77 | S(int) 78 | S(&&) 79 | ~S() 80 | ~S() 81 | ``` 82 | 83 | **重点: move 后的对象仍然需要析构, 所以在析构的时候要判断一下是否重复清理** 84 | 85 | 86 | ### 临时量 87 | 88 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227120536.png) 89 | 90 | 结果: 91 | 92 | ``` 93 | S() 94 | "Hello World" 95 | ~S() 96 | ``` 97 | 98 | **重点: 临时量的生命周期 可以通过给一个引用来延长** 99 | 100 | 101 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227121454.png) 102 | 103 | 104 | 返回值是 1 , m 被正常的初始化了 105 | 106 | **重点: 临时量的生命周期延长是可以递归的起作用** 107 | 108 | 109 | ### 列表初始化 110 | 111 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227122215.png) 112 | 113 | 这个是 1 次内存分配, 因为 使用了 **小字符串优化** . 所以只有 vector 的内存.. 114 | 115 | 116 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227122320.png) 117 | 118 | 这个是 5 次分配, 119 | 120 | > initializer_list 的实现方式是 创建了一个预期类型 const 的隐藏数组 的 数组 121 | 122 | 所以 先建立了一个数组 const string, 分配了俩个空间, 然后 vector 一个空间之后, 建了俩个string空间, 拷贝过去 123 | 124 | **重点: initializer_list创建隐藏数组** 125 | 126 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227172022.png) 127 | 128 | 这个分配 0 次, 可以认为是 std::array 129 | 130 | 131 | std::array 实现方式类似 132 | 133 | ``` 134 | template 135 | struct array 136 | { 137 | T _M_elems[Size]; 138 | } 139 | ``` 140 | 141 | 所以没用 initializer_list, 他会直接褚淑华内部的数组. 142 | 143 | 144 | **重点: std::array<> 没有构造函数 多使用不同参数的构造函数** 145 | 146 | ## for 147 | 148 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227173119.png) 149 | 150 | 未知行为, 因为这个语句展开 151 | 152 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227173547.png) 153 | 154 | auto && 只会延长 get_s() 的生命周期 ,不会延长 get_data() 的生命周期, 155 | 156 | 157 | **重点: range-for loop 会创建影藏变量, 所以要考虑他们的生命周期** 158 | 159 | 160 | 161 | ### RVO 返回值优化 162 | 163 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227174124.png) 164 | 165 | 打印结果 166 | 167 | ``` 168 | S() 169 | ~S() 170 | ``` 171 | 因为触发了 RVO. 172 | 173 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227174240.png) 174 | 175 | 这个在 C++17 以后就支持了 所以结果同上 176 | 177 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227174356.png) 178 | 179 | 这个会触发 NRVO 所以 也同上 180 | 181 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20191227174640.png) 182 | 183 | 这个是 184 | 185 | ``` 186 | S() 187 | S(S&&) 188 | ~S() 189 | ~S() 190 | ``` 191 | 192 | 返回值触发了 RVO, 所以没有额外构造, 赋值的时候触发了移动构造 193 | 194 | **重点: 编译器会自己处理右值的移动** 195 | -------------------------------------------------------------------------------- /cpp/Intro to the C++ Object Model.md: -------------------------------------------------------------------------------- 1 | 2 | # C++ 对象模型简介 3 | 4 | > 来源 https://www.youtube.com/watch?v=iLiDezv_Frk 的视频 5 | 6 | ## POD(plain old data) 7 | 8 | 9 | 10 | ![例子](../assests/cpp/01.png) 11 | 12 | c的内存布局, 字段从下到上占据从高到底位置的内存 13 | 14 | 15 | ## CPP 16 | 17 | ### 原始 18 | 19 | ![例子](../assests/cpp/02.png) 20 | 21 | 这个是和 pod 等价的只是访问权限不同 22 | 23 | 24 | ### 简单继承 25 | 26 | ![例子](../assests/cpp/03.png) 27 | 28 | 原因如下 29 | 30 | ![例子](../assests/cpp/04.png) 31 | 32 | 33 | ### 带有函数 34 | 35 | ![例子](../assests/cpp/05.png) 36 | 37 | 类是如何处理成员函数? 38 | 39 | ![例子](../assests/cpp/07.png) 40 | 41 | 主要是增加一个参数 表示对象, 并且换了个名字, 所以 42 | 43 | ![例子](../assests/cpp/08.png) 44 | 45 | ### 虚函数 + 继承 46 | 47 | ![例子](../assests/cpp/09.png) 48 | 49 | 编译器是如何处理这个的? 50 | 51 | 首先我们看这么一个调用 52 | 53 | ![例子](../assests/cpp/10.png) 54 | 55 | 编译器会转换成如下的格式 56 | 57 | ![例子](../assests/cpp/11.png) 58 | 59 | 1. 增加一个 vtable 的指针 指向一个 tbl 60 | 2. 具体实现放入 tbl 61 | 3. 调用的时候通过 vtable 偏移 为 tbl 中函数所在的位置 62 | 63 | 64 | 当我们有个继承类的时候, 内存布局如下: 65 | ![例子](../assests/cpp/12.png) 66 | 67 | 那我们怎么决定 vtable 指针的指向呢? 答案是靠 构造函数 68 | 69 | ![例子](../assests/cpp/13.png) 70 | 71 | 每个构造函数里会添加: 72 | 1. 父类的构造 73 | 2. 修改 vtable 指向, 指向一个常量 74 | 75 | > 所以 构造函数中不可以调用虚函数, 尤其是父类, 因为此时 vtable 没有初始化, 会导致指向错误, 调用错误的函数 76 | 77 | -------------------------------------------------------------------------------- /cpp/Lock-free programming with modern C++ .md: -------------------------------------------------------------------------------- 1 | # C++ 无锁编程 2 | 3 | ## 4 | 5 | ![](https://user-gold-cdn.xitu.io/2019/7/27/16c32c7ed2eb88d8?w=676&h=274&f=png&s=12819) -------------------------------------------------------------------------------- /cpp/LockFreeQueue.hpp: -------------------------------------------------------------------------------- 1 | 2 | template 3 | class LockFreeMultiQueue { 4 | // 单个消费者的实现 5 | private: 6 | static constexpr size_t ringBufferSize = size + 1; 7 | std::array, ringBufferSize> ringBuffer; 8 | std::atomic readPos = {0}, wirtePos = {0}; 9 | 10 | static constexpr size_t getPosiitionAfter(size_t pos) noexcept { 11 | return ++pos == ringBufferSize? 0: pos; 12 | } 13 | public: 14 | bool push (const T & newElement) { 15 | auto oldWritePos = wirtePos.load(); 16 | auto newWritePos = getPosiitionAfter(oldWritePos); 17 | 18 | if (newWritePos == readPos.load()) { 19 | return false; 20 | } 21 | 22 | ringBuffer[oldWritePos].store(newElement); 23 | } 24 | 25 | bool pop (T & resElement) { 26 | while (true) { 27 | auto oldWritePos = wirtePos.load(); 28 | auto oldReadPos = readPos.load(); 29 | if (oldWritePos == oldReadPost) { 30 | return false; 31 | } 32 | resElement = ringBuffer[oldReadPos].load(); 33 | if (readPos.compare_exchange_strong(oldReadPos, getPosiitionAfter(oldReadPos))){ 34 | return true; 35 | } 36 | } 37 | 38 | return true; 39 | } 40 | 41 | }; -------------------------------------------------------------------------------- /cpp/stl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(stl) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | add_executable(stl src/SGI_alloc.hpp src/stl_iterator.hpp) -------------------------------------------------------------------------------- /cpp/stl/src/lock_free_queue.hpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | template 6 | class LockFreeMultiQueue { 7 | private: 8 | static constexpr size_t ringBufferSize = size + 1; 9 | std::array, ringBufferSize> ringBuffer; 10 | std::atomic readPos = {0}, writePos = {0}; 11 | 12 | static constexpr size_t getPositionAfter(size_t pos) noexcept { 13 | return ++pos == ringBufferSize? 0: pos; 14 | } 15 | public: 16 | bool push (const T & newElement) { 17 | auto oldWritePos = writePos.load(); 18 | auto newWritePos = getPositionAfter(oldWritePos); 19 | 20 | if (newWritePos == readPos.load()) { 21 | return false; 22 | } 23 | 24 | ringBuffer[oldWritePos].store(newElement); 25 | writePos.store(newWritePos); 26 | return true; 27 | } 28 | 29 | bool pop (T & resElement) { 30 | while (true) { 31 | auto oldWritePos = writePos.load(); 32 | auto oldReadPos = readPos.load(); 33 | if (oldWritePos == oldReadPos) { 34 | return false; 35 | } 36 | resElement = ringBuffer[oldReadPos].load(); 37 | if (readPos.compare_exchange_strong(oldReadPos, getPositionAfter(oldReadPos))){ 38 | return true; 39 | } 40 | } 41 | } 42 | 43 | }; -------------------------------------------------------------------------------- /cpp/模板编程入门-sfinae基础.md: -------------------------------------------------------------------------------- 1 | # 模板编程入门-sfinae基础 2 | 3 | 4 | 本文的内容来自 极客时间 [现代C++实战 30 讲](https://time.geekbang.org/column/intro/256?code=TjUT9y8QEechQ9EIIAVu9Kilsx5u1FrzLLQaF8n3X8A%3D), 是对其中内容的一个自己咀嚼后的理解. 5 | 6 | ## 基础定义 7 | 8 | ```c++ 9 | 10 | template 11 | void f(typename T::foo) { 12 | 13 | } 14 | 15 | template 16 | void f( T) { 17 | 18 | } 19 | 20 | ``` 21 | 22 | 这个例子里, 如果 T 没有 foo, 当没有 sfinae 的时候, 就会直接编译错误, 因为展开的结果不合法, 不过因为现在有 sfinae 第一个展开发现不合法了不会立刻编译错误, 而是会尝试别的重载展开. 23 | 24 | 这个是 sfinae 的基础定义. 25 | 26 | ## 编译期成员检测 27 | 28 | 我们有个需求是检测 类是否有 resserve, 类型为 size_t 的对象. 29 | 我们可以写一个 has_reserve 对象, 代码如下 30 | 31 | ```c++ 32 | 33 | template 34 | struct has_reserve { 35 | struct good {char dummy;}; 36 | struct bad{ char dummy[2]; }; 37 | 38 | 39 | template 40 | struct SFINAE{}; 41 | 42 | template 43 | static good reserve(SFINAE*) 44 | 45 | template 46 | static bad reserve(...); 47 | 48 | static const bool vallue = sizeof(reserve(nullptr) == sizeof(good)) 49 | }; 50 | 51 | ``` 52 | 53 | 这个的逻辑就是, 如果 类型 T 有 符合要求的 reserve, 就会选择 good 的重载, 没有就会 bad 根据类型大小的区别可以 在 编译时确定 value 的值 54 | 55 | ## 利用 enable_if 来阻止展开 56 | 57 | 利用这个 has_reserve 可以用来配合 enale_if 实现编译期的阻断 58 | 59 | 看起来形式如下: 60 | 61 | ```c++ 62 | 63 | template 64 | enable_if_t::value, 65 | void> 66 | append(C& container, T* ptr, 67 | size_t size) 68 | { 69 | container.reserve( 70 | container.size() + size); 71 | ... 72 | } 73 | 74 | template 75 | enable_if_t::value, 76 | void> 77 | append(C& container, T* ptr, 78 | size_t size) 79 | { 80 | .... 81 | } 82 | ``` 83 | 84 | 这个的实现原理: 85 | 86 | 首先 enable_if_t 的实现 87 | 88 | ``` c++ 89 | template< bool B, class T = void > 90 | using enable_if_t = typename enable_if::type; 91 | ``` 92 | 93 | 获得了一个 enable_if 的 type 字段, 也就是说, 如果他 可以 模板 **展开**, 他就能获得一个 enable_if_t 的 值 就是一个 type, 94 | 95 | 那么 enable_if 的实现就显而易见了: 96 | 97 | 成功的时候, 特化 98 | 99 | ```c++ 100 | template 101 | struct enable_if { typedef T type; }; 102 | ``` 103 | 104 | 根据 enable_if_t 进行展开. type 就是 类型 T. 105 | 106 | 失败的时候: 107 | 108 | ```c++ 109 | template 110 | struct enable_if {}; 111 | ``` 112 | 113 | 没有这个字段, 影响模板的展开, 触发 sfinae 机制, 尝试下一个展开. 114 | 115 | 116 | ## 利用 void_t 标签分发分发 117 | 118 | 119 | void_t 的定义是这样的. 120 | 121 | ```c++ 122 | template 123 | using void_t = void; 124 | ``` 125 | 126 | 这个看起来没什么用的模板, 是为了诱导编译器, 检查 void_t 形式的 T的合法性, 来使用 sfinae 机制. 127 | 128 | ```c++ 129 | 130 | template > 132 | struct has_reserve : false_type {}; 133 | 134 | template 135 | struct has_reserve< 136 | T, void_t().reserve(1U))>> 138 | : true_type {}; 139 | 140 | ``` 141 | 142 | 这里解释一下, declval 这个东西, 是为了 能让 decltype 在没有默认构造函数的时候使用, 所以 可以先假装 这个就是 decltype, 143 | 144 | 这里会检查里面有没有能满足 145 | 146 | ```c++ 147 | declval().reserve(1U) 148 | ``` 149 | 150 | 没有的话 根据 sfinae 原则, 他不会报编译错误, 而是会接着尝试别的展开. 变成一个 false_type 151 | 152 | 有了这个机制, 我们就可以利用简单的函数重载, 实现如下代码 153 | 154 | ```c++ 155 | 156 | template 157 | void _append(C& container, T* ptr, 158 | size_t size, 159 | true_type) 160 | { 161 | .... 162 | } 163 | 164 | template 165 | void _append(C& container, T* ptr, 166 | size_t size, 167 | false_type) 168 | { 169 | .... 170 | } 171 | 172 | template 173 | void append(C& container, T* ptr, 174 | size_t size) 175 | { 176 | _append( 177 | container, ptr, size, 178 | integral_constant< 179 | bool, 180 | has_reserve::value>{}); 181 | } 182 | ``` 183 | 184 | 185 | ## 利用 if constexp 做编译时 if 186 | 187 | 在 cpp 中, 我们不能写如下代码 188 | 189 | ```c++ 190 | 191 | template 192 | void append(C& container, T* ptr, 193 | size_t size) 194 | { 195 | if (has_reserve::value) { 196 | container.reserve( 197 | container.size() + size); 198 | } 199 | 200 | } 201 | ``` 202 | 203 | 204 | 这是一个运行时的代码, container 没有 reserve , 这个会被编译器的类型检查检查出来, 直接报错... 205 | 206 | 207 | 208 | ```c++ 209 | 210 | template 211 | void append(C& container, T* ptr, 212 | size_t size) 213 | { 214 | if constexp (has_reserve::value) { 215 | container.reserve( 216 | container.size() + size); 217 | } 218 | } 219 | ``` 220 | 221 | 可以通过如下方法让 这个 if 变成编译时的判断, 根据不同的调节, 展开不同的代码, 这个做法的可读性要比之前的好很多.. 222 | 223 | 224 | ## 总结 225 | 226 | 227 | * sfinae 说白了就是一个机制, **当一个模板展开失败的时候, 会尝试用其他的重载进行展开, 而不是直接报错**, 228 | 229 | * 利用这个特性, 我们可以手工诱导发生 sfinae, 来实现编译器的一个类型判断. 230 | 231 | * 常见的做法有 enable_if 和 标签分发. 232 | 233 | * if constexp 为我们的这种代码增加了更多的可读性 234 | 235 | 236 | 237 | 238 | 239 | 240 | [1]. 现代 C++30讲: https://time.geekbang.org/column/intro/256?code=TjUT9y8QEechQ9EIIAVu9Kilsx5u1FrzLLQaF8n3X8A%3D 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /ddia/ddia.md: -------------------------------------------------------------------------------- 1 | 2 | # 数据复制 3 | 4 | ## 主从复制: 5 | 只有主节点可写的 6 | 7 | ## 同步和异步复制 8 | 是否等从节点确认 9 | 10 | ## 不停机配置新的从节点流程: 11 | 1. 对主节点进行一致性快照 12 | 2. 快照到新节点 13 | 3. 向主节点请求快照点位置之后所有日志 14 | 4. 进行处理 15 | 16 | ## 节点切换 17 | 1. 确认失效 18 | 2. 选举新的主节点 19 | 3. 配置新的节点 20 | 问题: 21 | 1. 异步复制, 新节点成为主节点时, 旧节点比新节点数据新. 旧节点给新节点同步数据冲突. 22 | 2. 基于问题 1, 如果丢弃数据会导致外部系统不一致. 如同一个 key 的数据缓存和 db 不一致. 23 | 3. 两个节点同时成为主节点 发生脑裂 24 | 4. 如何检测主节点失效? 25 | 26 | ## 复制日志的实现 27 | 28 | 1. 语句级别: 存在非确定函数, 自增列数据, 副总用函数的问题 29 | 2. wal 日志: 泰国底层, 贴近物理描述 30 | 3. 逻辑日志: 解耦逻辑日志和物理日志 31 | 32 | ## 复制滞后 33 | 34 | 写后读一致性 35 | * 强制从主节点 36 | * 记录更新时间, 看时间范围决定是否从主节点读 37 | 38 | ## 单调读 39 | 用户看到的值不会比之前看到的值更旧, 实现用哈希到固定的分库 40 | 41 | ## 一致前缀读 42 | 由于不同分区延迟不同 导致写入的前后不同破坏了因果性 43 | 要保证因果性相关的写入一个分区。 44 | 45 | ## 多主复制 46 | 47 | 问题: 多主写入的数据冲突。 48 | * 避免冲突 通过路由让一个用户的数据只访问一个主 49 | * 收敛到一致 例如 保留最后一个方式 或者 记录流水业务处理 50 | * 自定义业务冲突 写执行 读执行 51 | 52 | 拓扑结构: 53 | 1. 环状 2. 星型 3. 全连接 54 | 55 | ## 无主复制 56 | 57 | 核心思想: 法定人数 多份写入 多份读 58 | 59 | 60 | # 数据分区 61 | 62 | ## 分区方法 63 | 64 | * 关键字区间: 支持高效查询, 哈希分区 65 | * 哈希分区: 分布均匀. 66 | 67 | ## 二级索引 68 | 69 | 基于文档: 每个分区独立 便于写入 70 | 基于词条: 便于读取 71 | 72 | ## 分区平衡 73 | 74 | 取模: 会导致每次扩展都有很多 key 需要迁移 75 | 固定数量分区: 把分区数量定高, 之后再平衡分区, key 的计算分区是固定的, 只会动这些分区. 76 | 动态分区: 类似一致性哈希的思想 77 | 78 | ## 请求路由 79 | * 中心化调度: zookeeper 80 | * gossip: 类似路由协议 每个节点负责转发 81 | 82 | ## 事务 83 | 84 | ### 脏读 85 | 读到了另一个事务未提交的内容 86 | 防止脏读: 读提交 87 | 危害:1.多对象更新,防止外界观察到部分更新 2.事务回滚, 防止发现写入的事务。 88 | 实现: 语句级别的快照。 89 | 90 | ## 脏写 91 | 92 | 未提交的写入被另一个事务覆盖。 93 | 危害: 1. 一个事务的两个写入操作 被其他事务覆盖其中一个写入操作造成不一致。 94 | 解决方法: 行级别写锁 95 | 96 | ## 不可重复读 97 | 98 | 一个事务开始后, 两次读取结果不一样。 99 | 危害: 出现短暂的不一致。 备份场景, 数据分析场景 不接受不一致。 100 | 解决方法: mvcc 事务级别快照。 101 | 102 | ## mvcc 索引优化 103 | 104 | ## 幻读 105 | 危害: 认为自己修改了要修改的全部数据 106 | 解决方式: 间隙锁 107 | 108 | ## 串行化 109 | 110 | * 2pl协议 事务开始不断上锁, 事务结束不断释放锁 111 | 112 | # 共识和一致性 113 | 114 | ### 可线性 115 | 116 | 让系统看起来只有一个副本 117 | 118 | > 区分线性化和串行 119 | > 串行: 事务执行的顺序看起来和串行执行差不多 120 | > 线性: 每次读取单个对象的最新值 121 | 122 | 目标: 满足约束 一旦读返回了新值 后续所有的读操作都要返回新值 123 | 124 | 必须线性化的场景 125 | * 主节点选取时分布式锁: 必须保证只有一个主节点 126 | * 约束和唯一约束: 类似锁 127 | * 存在不同的传输通道需要保持一致 128 | 129 | ### 实现 130 | 131 | * 主从复制(部分线性化): 保证从主节点上读数据可以线性化 132 | * 共识算法(可线性化): 133 | * 多主复制(不可线性化): 多个节点并发写入 存在冲突 134 | * 无主复制(可以认为不线性化): (r + w > n) 存在网络延迟可能不线性化 135 | 136 | ### 代价 137 | 网络延迟, 就没有可用性 代价. 138 | 139 | ## 顺序保证 140 | 141 | ### 因果全序并非全序 142 | 143 | #### Lamport 时间戳 144 | 145 | > (操作号, 节点号) 每个节点保存自己见过最大的编号 146 | 147 | 每个节点看完新的就不会看旧的 148 | 149 | ## 分布式事务和共识 150 | 151 | ### 两阶段提交(2pc) 152 | 153 | 先问节点能不能接受 节点一旦承诺能接受就要必须完成. 154 | 155 | 无法处理协调者崩溃. 156 | 157 | 关键点: 协调者可用性 158 | 159 | 160 | ### 共识 161 | 162 | 共识算法: 一个或者多个节点提议值, 共识算法决定最终值 163 | 164 | 满足性质: 165 | 166 | * 协商一致: 节点接受相同提议 167 | * 诚实: 节点不能反悔 168 | * 合法: 值 v 是由某个节点提议的 169 | * 可终止: 最终一定能打成决议 170 | 171 | 2pc 不满足 可终止性(协调者故障) 172 | 173 | 实际使用中会用全序广播, 一次决定多个值 174 | 175 | 主节点唯一比较困难, 共识算法往往只保证每个世代的主节点唯一 176 | 和 2pc 对比, 2pc 需要所有节点都返回是, 共识只需要大部分节点返回是 177 | 178 | #### 局限性 179 | 180 | 好处: 一致性, 完整性, 有效性, 支持容错(大多数节点工作) 181 | 代价: 182 | 183 | * 节点投票是同步复制, 性能有损耗 184 | * 分区故障会导致少数节点所在分区不可用 185 | * 扩容繁琐 186 | * 无法准确监控主节点异常 (对网络敏感) 187 | 188 | ## 协调服务 189 | 190 | zookeeper 191 | 192 | * 任务分配 193 | * 服务发现 194 | * 成员服务 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /leetcode/3sum.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def threeSum(self, nums): 3 | """ 4 | :type nums: List[int] 5 | :rtype: List[List[int]] 6 | """ 7 | nums.sort() 8 | res = [] 9 | for flag in range(len(nums)): 10 | if flag != 0 and nums[flag-1] == nums[flag]: 11 | continue 12 | left = flag + 1 13 | right = len(nums) - 1 14 | 15 | while left 0: 27 | while left int: 5 | nums.sort() 6 | print(nums) 7 | min_gap = None 8 | min_sum = None 9 | for flag in range(len(nums)): 10 | left = flag + 1 11 | right = len(nums) - 1 12 | 13 | while left < right: 14 | r = nums[left] + nums[flag] + nums[right] 15 | v = r - target 16 | if min_gap is None: 17 | min_gap = abs(target-r) 18 | min_sum = r 19 | if v > 0: 20 | right = right - 1 21 | elif v<0: 22 | left = left + 1 23 | elif v == 0: 24 | break 25 | else: 26 | if min_gap > abs(v): 27 | min_gap = abs(v) 28 | min_sum = r 29 | if v > 0: 30 | right = right - 1 31 | elif v<0: 32 | left = left + 1 33 | elif v == 0: 34 | break 35 | return min_sum -------------------------------------------------------------------------------- /leetcode/4sum_ii.py: -------------------------------------------------------------------------------- 1 | 2 | class Solution: 3 | def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int: 4 | counter_ab = {} 5 | res = 0 6 | for a in A: 7 | for b in B: 8 | counter_ab[a+b] = counter_ab.get(a+b, 0) + 1 9 | 10 | counter_cd = {} 11 | for c in C: 12 | for d in D: 13 | counter_cd[c+d] = counter_cd.get(c+d, 0) + 1 14 | 15 | for k1 in counter_ab.keys(): 16 | if (0-k1) in counter_cd.keys(): 17 | res = res + counter_ab[k1] * counter_cd[0-k1] 18 | return res 19 | -------------------------------------------------------------------------------- /leetcode/add-two-numbers-ii.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | class ListNode: 3 | def __init__(self, x): 4 | self.val = x 5 | self.next = None 6 | 7 | 8 | class Solution: 9 | def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: 10 | l1 = self.reserve(l1) 11 | l2 = self.reserve(l2) 12 | head = ListNode(0) 13 | res = head 14 | add_flag = 0 15 | 16 | while l1 is not None or l2 is not None: 17 | val = add_flag 18 | if l1: 19 | val = val + l1.val 20 | l1 = l1.next 21 | if l2: 22 | val = val + l2.val 23 | l2 = l2.next 24 | add_flag = 0 25 | if val >= 10: 26 | val = val - 10 27 | add_flag = 1 28 | head.next = ListNode(val) 29 | head = head.next 30 | if add_flag: 31 | head.next = ListNode(add_flag) 32 | head = head.next 33 | return self.reserve(res.next) 34 | 35 | def reserve(self, head): 36 | 37 | pre = None 38 | _next = None 39 | while head is not None: 40 | _next = head.next 41 | head.next = pre 42 | pre = head 43 | head = _next 44 | return pre 45 | -------------------------------------------------------------------------------- /leetcode/add_two_numbers.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | 3 | 4 | class ListNode: 5 | def __init__(self, x): 6 | self.val = x 7 | self.next = None 8 | 9 | 10 | def get_longest_tuple(l1, l2): 11 | n1 = l1 12 | n2 = l2 13 | while True: 14 | yield (n1, n2) 15 | 16 | if n1.next is None and n2.next is None: 17 | return 18 | 19 | if n1.next: 20 | n1 = n1.next 21 | else: 22 | n1 = ListNode(0) 23 | 24 | if n2.next: 25 | n2 = n2.next 26 | else: 27 | n2 = ListNode(0) 28 | 29 | 30 | class Solution: 31 | def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: 32 | up = 0 33 | res = None 34 | tmp = None 35 | for n1, n2 in get_longest_tuple(l1, l2): 36 | v = n1.val + n2.val 37 | v = v + up 38 | up = v // 10 39 | v = v % 10 40 | if res is None: 41 | res = ListNode(v) 42 | tmp = res 43 | else: 44 | tmp.next = ListNode(v) 45 | tmp = tmp.next 46 | if up: 47 | tmp.next = ListNode(up) 48 | return res 49 | 50 | 51 | def build_list(): 52 | l1_head = ListNode(5) 53 | l1 = l1_head 54 | 55 | l2_head = ListNode(5) 56 | l2 = l2_head 57 | 58 | return l1_head, l2_head 59 | -------------------------------------------------------------------------------- /leetcode/basic-calculator-ii.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | class Solution: 5 | def calculate(self, s: str) -> int: 6 | op_order = { 7 | '*': 4, 8 | "/": 4, 9 | '+' : 1, 10 | '-': 1 11 | } 12 | 13 | op_func = { 14 | '*': lambda a,b: a*b, 15 | '-': lambda a,b: a-b, 16 | '+':lambda a,b: a+b, 17 | '/':lambda a,b: a//b, 18 | } 19 | if not s: 20 | return 0 21 | num_stack = list() 22 | op_stack = list() 23 | pos = 0 24 | res = 0 25 | while pos= op_order[s[pos]]: 31 | op = op_stack.pop() 32 | b = num_stack.pop() 33 | a = num_stack.pop() 34 | num_stack.append(op_func[op](a,b)) 35 | op_stack.append(s[pos]) 36 | pos = pos +1 37 | continue 38 | else: 39 | tmp = '' 40 | while pos < len(s) and s[pos] not in op_order.keys(): 41 | tmp = tmp + s[pos] 42 | pos = pos + 1 43 | num_stack.append(int(tmp.strip())) 44 | while op_stack: 45 | op = op_stack.pop() 46 | b = num_stack.pop() 47 | a= num_stack.pop() 48 | r = op_func[op](a,b) 49 | num_stack.append(op_func[op](a,b)) 50 | 51 | return num_stack[-1] 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /leetcode/best-time-to-buy-and-sell-stock-ii.py: -------------------------------------------------------------------------------- 1 | 2 | class Solution: 3 | def maxProfit(self, prices: List[int]) -> int: 4 | res = 0 5 | hold = False 6 | for p in range(len(prices)-1): 7 | if prices[p] < prices[p+1] and not hold: 8 | # 买入 9 | res = res - prices[p] 10 | hold = True 11 | elif prices[p] > prices[p+1] and hold: 12 | res = res + prices[p] 13 | hold = False 14 | 15 | if hold: 16 | res = res + prices[p+1] 17 | 18 | return res -------------------------------------------------------------------------------- /leetcode/best_sightseeing_pair.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | class Solution: 4 | def maxScoreSightseeingPair(self, A: List[int]) -> int: 5 | if A: 6 | li = [A[i] + i for i in range(len(A))] 7 | lj = [A[j] - j for j in range(len(A))] 8 | 9 | res = 0 10 | max_li = li[0] 11 | for j in range(1, len(A)): 12 | if max_li + lj[j] > res: 13 | res = max_li + lj[j] 14 | max_li = max(li[j], max_li) 15 | return res 16 | else: 17 | return 0 18 | 19 | print(Solution().maxScoreSightseeingPair([8,1,5,2,6])) -------------------------------------------------------------------------------- /leetcode/binary-tree-level-order-traversal.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | class Solution: 8 | def levelOrder(self, root: TreeNode) -> List[List[int]]: 9 | q = list() 10 | current_num = 0 11 | next_num = 0 12 | q.append(root) 13 | current_num = current_num + 1 14 | res=list() 15 | tmp = list() 16 | while q: 17 | node = q.pop(0) 18 | current_num = current_num -1 19 | if node is not None: 20 | tmp.append(node.val) 21 | q.append(node.left) 22 | q.append(node.right) 23 | next_num = next_num + 2 24 | if current_num == 0: 25 | if tmp: 26 | res.append(list(tmp)) 27 | tmp.clear() 28 | current_num = next_num 29 | next_num = 0 30 | return res -------------------------------------------------------------------------------- /leetcode/binary-tree-zigzag-level-order-traversal.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Solution: 9 | def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]: 10 | stacks = [list(), list()] 11 | current_stack = 0 12 | next_stack = 1 13 | stacks[current_stack].append(root) 14 | tmp = list() 15 | res = list() 16 | while stacks[current_stack]: 17 | node = stacks[current_stack].pop() 18 | if node: 19 | tmp.append(node.val) 20 | if next_stack == 1: 21 | stacks[next_stack].append(node.left) 22 | stacks[next_stack].append(node.right) 23 | else: 24 | stacks[next_stack].append(node.right) 25 | stacks[next_stack].append(node.left) 26 | if not stacks[current_stack]: 27 | # 为空反转 28 | if tmp: 29 | res.append(list(tmp)) 30 | tmp.clear() 31 | current_stack, next_stack = next_stack, current_stack 32 | return res 33 | 34 | -------------------------------------------------------------------------------- /leetcode/binary.py: -------------------------------------------------------------------------------- 1 | def lower_bound(arrary, fist, last, value): 2 | while fist < last: 3 | mid = fist + (last- fist) // 2 4 | if arrary[mid] < value: 5 | fist = mid + 1 6 | else: 7 | last = mid 8 | return fist -------------------------------------------------------------------------------- /leetcode/candy.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def candy(self, ratings: List[int]) -> int: 3 | l = [1 for i in ratings] 4 | r = [1 for i in ratings] 5 | res = 0 6 | for i in range(1, len(ratings)): 7 | l[i] = 1 if ratings[i] <= ratings[i - 1] else l[i - 1] + 1 8 | 9 | for i in range(len(ratings) - 2, -1, -1): 10 | r[i] = 1 if ratings[i] <= ratings[i + 1] else r[i + 1] + 1 11 | t = [] 12 | for i in zip(l, r): 13 | res = res + max(i[0], i[1]) 14 | t.append(max(i[0], i[1])) 15 | return res 16 | 17 | -------------------------------------------------------------------------------- /leetcode/coin-change.py: -------------------------------------------------------------------------------- 1 | # class Solution: 2 | # def coinChange(self, coins: List[int], amount: int) -> int: 3 | # f = [9999999 for i in range(amount + 1)] 4 | # f[0] = 0 5 | # for i in range(len(f)): 6 | # for c in coins: 7 | # if c <= i: 8 | # f[i] = min(f[i], f[i - c] + 1) 9 | # 10 | # return f[-1] if f[-1] < 9999999 else -1 11 | 12 | def partion(A, low, high, povit): 13 | A[high], A[povit] = A[povit], A[high] 14 | start = low 15 | for i in range(low, high): 16 | if A[i] <= A[high]: 17 | A[i], A[start] = A[start],A[i] 18 | start = start + 1 19 | A[start], A[high] = A[high], A[start] 20 | return start 21 | 22 | def quick_sort(A, low, high): 23 | if low < high: 24 | p = partion(A,low, high, (low+high)//2) 25 | quick_sort(A, low, p-1) 26 | quick_sort(A, p+1, high) 27 | A = [54,35,48,36,27,12,44,44,8,14,26,17,28] 28 | quick_sort(A, 0, len(A) - 1) -------------------------------------------------------------------------------- /leetcode/construct_binary_tree_from_inorder_and_postorder_traversal.py: -------------------------------------------------------------------------------- 1 | # from typing import * 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Solution: 9 | def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode: 10 | postorder_flag = len(postorder)-1 11 | if postorder: 12 | def slove(root:TreeNode,left:List[int], right:List[int]): 13 | nonlocal postorder_flag 14 | # left 15 | if right: 16 | right_root = TreeNode(postorder[postorder_flag]) 17 | postorder_flag = postorder_flag - 1 18 | root.right = slove(right_root, 19 | right[:right.index(right_root.val)], 20 | right[right.index(right_root.val)+1:]) 21 | # left 22 | if left: 23 | left_root = TreeNode(postorder[postorder_flag]) 24 | postorder_flag = postorder_flag - 1 25 | root.left = slove(left_root, 26 | left[:left.index(left_root.val)], 27 | left[left.index(left_root.val)+1:]) 28 | return root 29 | 30 | root = TreeNode(postorder[postorder_flag]) 31 | postorder_flag = postorder_flag-1 32 | right = inorder[inorder.index(root.val)+1:] 33 | left = inorder[:inorder.index(root.val)] 34 | root = slove(root,left, right) 35 | return root 36 | else: 37 | return None 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /leetcode/container_with_most_water.py: -------------------------------------------------------------------------------- 1 | import typing 2 | def slove(start, end, height): 3 | max_v = 0 4 | while start < end: 5 | max_v = max(max_v, min(height[start], height[end]) * (end-start) ) 6 | print(max_v) 7 | if height[start] < height[end]: 8 | start = start +1 9 | else: 10 | end = end - 1 11 | return max_v 12 | 13 | 14 | 15 | class Solution: 16 | def maxArea(self, height: typing.List[int]) -> int: 17 | 18 | return slove(0, len(height) -1 , height) 19 | -------------------------------------------------------------------------------- /leetcode/copy-list-with-random-pointer/submissions.py: -------------------------------------------------------------------------------- 1 | """ 2 | # Definition for a Node. 3 | class Node: 4 | def __init__(self, val, next, random): 5 | self.val = val 6 | self.next = next 7 | self.random = random 8 | """ 9 | class Solution: 10 | def copyRandomList(self, head: 'Node') -> 'Node': 11 | if (not head): 12 | return head 13 | node = head 14 | node = head 15 | while node: 16 | next_node = node.next 17 | node.next = Node(node.val, next_node, None) 18 | node = next_node 19 | copy_head = None 20 | node = head 21 | while node: 22 | copy_node = node.next # 找到复制的节点 23 | next_node = node.next.next 24 | if node.random: 25 | copy_node.random = node.random.next 26 | node = next_node 27 | node = head 28 | while node: 29 | copy_node = node.next # 找到复制的节点 30 | if not copy_head: 31 | copy_head = copy_node 32 | next_node = copy_node.next 33 | node.next = next_node 34 | if copy_node.next: 35 | copy_node.next = next_node.next 36 | node = next_node 37 | # copy_node = copy_head 38 | # while copy_node: 39 | # print(id(copy_node)) 40 | # copy_node = copy_node.next 41 | return copy_head 42 | -------------------------------------------------------------------------------- /leetcode/decode-ways.py: -------------------------------------------------------------------------------- 1 | 2 | class Solution: 3 | def numDecodings(self, s: str) -> int: 4 | can_code = ['{}'.format(i) for i in range(1, 27)] 5 | print(can_code) 6 | if not s : 7 | return 0 8 | f = [0 for i in range(len(s)+1)] 9 | f[0] = 0 10 | for d in range(1,len(s)+1): 11 | if s[:d] in can_code: 12 | f[d] = 1 13 | for p in range(1,d): 14 | if s[p:d] in can_code: 15 | f[d] = f[d] + f[p] 16 | return f[-1] 17 | -------------------------------------------------------------------------------- /leetcode/divide_two_integers.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def divide(self, dividend, divisor): 3 | absDividend, absDivisor, ret = abs(dividend), abs(divisor), 0 4 | while absDividend >= absDivisor: 5 | tmp, tmpDivisor = 1, abs(divisor) 6 | while absDividend >= tmpDivisor: 7 | absDividend -= tmpDivisor 8 | ret += tmp 9 | tmpDivisor = tmpDivisor << 1 10 | tmp = tmp << 1 11 | if dividend * divisor > 0: 12 | return min(2147483647,ret) 13 | else: 14 | return -ret -------------------------------------------------------------------------------- /leetcode/evaluate-reverse-polish-notation.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def evalRPN(self, tokens: List[str]) -> int: 3 | op_func = { 4 | '*': lambda a,b: a*b, 5 | '-': lambda a,b: a-b, 6 | '+':lambda a,b: a+b, 7 | '/':lambda a,b: int(a/b), 8 | } 9 | stack = list() 10 | for t in tokens: 11 | if t in op_func.keys(): 12 | b = stack.pop() 13 | a = stack.pop() 14 | res = op_func[t](a,b) 15 | stack.append(res) 16 | else: 17 | stack.append(int(t)) 18 | return stack[-1] -------------------------------------------------------------------------------- /leetcode/find_first_and_last_position_of_element_in_sorted_array.py: -------------------------------------------------------------------------------- 1 | 2 | class Solution: 3 | def searchRange(self, nums: List[int], target: int) -> List[int]: 4 | lo, hi = 0, len(nums) -1 5 | if not nums: 6 | return [-1, -1] 7 | if len(nums) == 1: 8 | if target == nums[0]: 9 | return [0,0] 10 | else: 11 | return [-1,-1] 12 | 13 | while lo != hi: 14 | if nums[lo]== nums[hi]: 15 | break 16 | 17 | mid = (lo + hi) //2 18 | if nums[mid] > target: 19 | hi = mid 20 | elif nums[mid]0 and nums[lo] == nums[lo -1]: 26 | lo = lo - 1 27 | while hi < len(nums) - 1 and nums[hi] == nums[hi + 1]: 28 | hi = hi + 1 29 | 30 | 31 | if nums[lo] != target: 32 | return [-1, -1] 33 | else: 34 | return [lo, hi] 35 | -------------------------------------------------------------------------------- /leetcode/find_minimum_in_rotated_sorted_array.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def findMin(self, nums: List[int]) -> int: 3 | l = 0 4 | r = len(nums) 5 | if r>1: 6 | mid = (l + r) // 2 7 | while l < r and nums[l] > nums[r-1]: 8 | mid = (l + r) // 2 9 | if nums[mid] > nums[l]: 10 | l = mid + 1 11 | else: 12 | r = mid 13 | return nums[l] if nums[l] < nums[mid] else nums[mid] 14 | elif r==1: 15 | return nums[0] 16 | else: 17 | return None -------------------------------------------------------------------------------- /leetcode/first-unique-character-in-a-string.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def firstUniqChar(self, s: str) -> int: 3 | counter = {} 4 | for i in s: 5 | counter[i] = counter.get(i,0) + 1 6 | for i,c in enumerate(s): 7 | if counter[c] == 1: 8 | return i 9 | 10 | return -1 -------------------------------------------------------------------------------- /leetcode/flatten-binary-tree-to-linked-list.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | def trans(node): 9 | if not node: 10 | return None 11 | right_node = node.right 12 | node.right = trans(node.left) 13 | tail = node # 找到尾巴节点 14 | while tail.right: 15 | tail = tail.right 16 | tail.right = trans(right_node) 17 | node.left = None 18 | return node 19 | 20 | 21 | class Solution: 22 | def flatten(self, root: TreeNode) -> None: 23 | """ 24 | Do not return anything, modify root in-place instead. 25 | """ 26 | 27 | if not root: 28 | return 29 | 30 | trans(root) 31 | -------------------------------------------------------------------------------- /leetcode/generate_parentheses.py: -------------------------------------------------------------------------------- 1 | def push_stk(stk:list, e): 2 | if e == '(': 3 | stk.append(e) 4 | return True 5 | else: 6 | if not stk: 7 | return False 8 | p = stk.pop() 9 | if p == '(': 10 | return True 11 | else: 12 | return False 13 | 14 | class Solution: 15 | def generateParenthesis(self, n: int) -> List[str]: 16 | if n == 1: 17 | return ['()'] 18 | res = list() 19 | def slove(flag, stk:list, tmp:str): 20 | if flag == n * 2: 21 | if push_stk(stk, ')'): 22 | if not stk: 23 | tmp = tmp + ')' 24 | res.append(tmp) 25 | else: 26 | return 27 | else: 28 | 29 | stk_l = list(stk) 30 | if push_stk(stk_l, '('): 31 | tmp_l = str(tmp) 32 | tmp_l = tmp_l + '(' 33 | slove(flag+1, stk_l, tmp_l) 34 | 35 | stk_r = list(stk) 36 | if push_stk(stk_r, ')'): 37 | tmp_r = str(tmp) 38 | tmp_r = tmp_r + ')' 39 | slove(tmp_r, stk_r, tmp_r) 40 | return 41 | 42 | slove(1,list(), str()) 43 | return res 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /leetcode/house-robber.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def rob(self, nums: List[int]) -> int: 3 | if not nums: 4 | return 0 5 | f = [0 for i in range(len(nums) + 1)] 6 | pick = 0 7 | f[1] = nums[0] 8 | for i in range(2, len(nums)+1): 9 | idx = i - 1 10 | v = nums[idx] 11 | if f[i-2]+ v > f[i-1]: 12 | # 选取 13 | f[i] = f[i-2] + v 14 | else: 15 | f[i] = f[i-1] 16 | return f[-1] 17 | -------------------------------------------------------------------------------- /leetcode/implement-trie-prefix-tree.py: -------------------------------------------------------------------------------- 1 | class TrieNode: 2 | def __init__(self, val): 3 | self.val = val 4 | self.word = False 5 | self.node = {} 6 | 7 | 8 | class Trie: 9 | 10 | def __init__(self): 11 | """ 12 | Initialize your data structure here. 13 | """ 14 | self.root = TrieNode('') 15 | 16 | 17 | 18 | def insert(self, word: str) -> None: 19 | """ 20 | Inserts a word into the trie. 21 | """ 22 | pre = self.root 23 | for w in word: 24 | if pre.node.get(w) is None: 25 | pre.node[w] = TrieNode(w) 26 | pre = pre.node[w] 27 | pre.word = True 28 | 29 | 30 | def search(self, word: str) -> bool: 31 | """ 32 | Returns if the word is in the trie. 33 | """ 34 | pre = self.root 35 | for w in word: 36 | if pre.node.get(w) is None: 37 | return False 38 | else: 39 | pre = pre.node[w] 40 | if not pre.word: 41 | return False 42 | return True 43 | 44 | 45 | 46 | 47 | def startsWith(self, prefix: str) -> bool: 48 | """ 49 | Returns if there is any word in the trie that starts with the given prefix. 50 | """ 51 | pre = self.root 52 | for w in prefix: 53 | if pre.node.get(w) is None: 54 | return False 55 | else: 56 | pre = pre.node[w] 57 | return True 58 | 59 | 60 | 61 | # Your Trie object will be instantiated and called as such: 62 | # obj = Trie() 63 | # obj.insert(word) 64 | # param_2 = obj.search(word) 65 | # param_3 = obj.startsWith(prefix) -------------------------------------------------------------------------------- /leetcode/increasing-triplet-subsequence.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def increasingTriplet(self, nums: List[int]) -> bool: 3 | if len(nums) < 3: 4 | return False 5 | fist = float('inf') 6 | second = float('inf') 7 | for i in nums: 8 | if i <= fist: 9 | fist = i 10 | elif i <= second: 11 | second = i 12 | elif i > second: 13 | return True 14 | return False 15 | 16 | 17 | -------------------------------------------------------------------------------- /leetcode/insert-into-a-cyclic-sorted-list/submissions.py: -------------------------------------------------------------------------------- 1 | """ 2 | # Definition for a Node. 3 | class Node: 4 | def __init__(self, val, next): 5 | self.val = val 6 | self.next = next 7 | """ 8 | class Solution: 9 | def insert(self, head: 'Node', insertVal: int) -> 'Node': 10 | if not head: 11 | node = Node(insertVal, None) 12 | node.next = node 13 | return node 14 | current_node = head 15 | start_current = head 16 | next_node = head.next 17 | if current_node == next_node: 18 | node = Node(insertVal, None) 19 | current_node.next = node 20 | node.next = current_node 21 | return head 22 | 23 | tail = None 24 | while True: 25 | if next_node.val >= insertVal and current_node.val <= insertVal: 26 | # 找到插入位置 27 | node = Node(insertVal, next_node) 28 | current_node.next = node 29 | return head 30 | if next_node.val <= current_node.val: 31 | tail = current_node 32 | next_node = next_node.next 33 | current_node = current_node.next 34 | if current_node == start_current: 35 | if tail is None: 36 | # 没找到 说明相同 37 | tail = current_node 38 | node = Node(insertVal, tail.next) 39 | tail.next = node 40 | return head -------------------------------------------------------------------------------- /leetcode/integer_break.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def integerBreak(self, n: int) -> int: 3 | cache = [0 for i in range(n+1)] 4 | cache[0] = 1 5 | cache[1] = 1 6 | cache[2] = 1 7 | def slove(num): 8 | nonlocal cache 9 | if cache[num]: 10 | return cache[num] 11 | res = [max(slove(num-i) * i, (num-i)*i) for i in range(1, num)] 12 | cache[num] = max(res) 13 | return cache[num] 14 | return slove(n) 15 | 16 | 17 | class Solution: 18 | """ 19 | f[x] = max { 20 | n * f[x-n], 21 | n * (x-n) 22 | } 23 | // n->(1,x) 24 | """ 25 | def integerBreak(self, n: int) -> int: 26 | dp = [0 for i in range(n+1)] 27 | dp[0] = 1 28 | dp[1] = 1 29 | for i in range(2,n+1): 30 | for j in range(1,i): 31 | dp[i] = max(dp[i], dp[j]*(i-j), (i-j)*j) 32 | return dp[n] -------------------------------------------------------------------------------- /leetcode/integer_to_roman.py: -------------------------------------------------------------------------------- 1 | 2 | NUMBER_MAP = { 3 | 1: 'I', 4 | 5: 'V', 5 | 10: 'X', 6 | 50: 'L', 7 | 100: 'C', 8 | 500: 'D', 9 | 1000: 'M', 10 | } 11 | 12 | SP_MAP= { 13 | 4: "IV", 14 | 9: "IX", 15 | 40: "XL", 16 | 90: "XC", 17 | 400: "CD", 18 | 900: "CM" 19 | } 20 | 21 | class Solution: 22 | def intToRoman(self, num: int) -> str: 23 | answer = '' 24 | if num in SP_MAP: 25 | return SP_MAP[num] 26 | romans = list(NUMBER_MAP.keys()) 27 | romans.sort(reverse=True) 28 | 29 | for r in romans: 30 | n = num // r 31 | if n: 32 | answer =answer + ''.join([NUMBER_MAP[r] for i in range(n)]) 33 | num = num - n * r 34 | 35 | return answer -------------------------------------------------------------------------------- /leetcode/intersection-of-two-linked-lists.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode(object): 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Solution(object): 8 | def getIntersectionNode(self, headA, headB): 9 | """ 10 | :type head1, head1: ListNode 11 | :rtype: ListNode 12 | """ 13 | nodeA = headA 14 | nodeB = headB 15 | start_head = None 16 | fix_node = None 17 | if (not nodeA) or (not nodeB): 18 | return None 19 | if nodeA is nodeB: 20 | return nodeA 21 | while nodeA.next and nodeB.next: 22 | nodeA = nodeA.next 23 | nodeB = nodeB.next 24 | if nodeA.next is None: 25 | while nodeB.next: 26 | nodeB = nodeB.next 27 | nodeB.next = headA 28 | fix_node = nodeB 29 | start_head = headB 30 | else: 31 | while nodeA.next: 32 | nodeA = nodeA.next 33 | nodeA.next = headB 34 | fix_node = nodeA 35 | start_head = headA 36 | slow = start_head 37 | fast = start_head 38 | while fast and fast.next: 39 | slow = slow.next 40 | fast = fast.next.next 41 | if slow is fast: 42 | slow = start_head 43 | while True: 44 | slow = slow.next 45 | fast = fast.next 46 | if slow is fast: 47 | fix_node.next = None 48 | return slow 49 | 50 | fix_node.next = None 51 | 52 | return None 53 | -------------------------------------------------------------------------------- /leetcode/interview/bilibili/01.py: -------------------------------------------------------------------------------- 1 | N = int(input()) 2 | C = int(input()) 3 | W = [int(i) for i in input().split()] 4 | V = [int(i) for i in input().split()] 5 | 6 | f = [[ 0 for c in range(C+1)] for i in range(N+1)] 7 | 8 | for c in range(1, C + 1): 9 | for i in range(1, N+1): 10 | if c >= W[i-1]: 11 | f[i][c] = max(f[i-1][c], f[i-1][c-W[i-1]] + V[i-1]) 12 | print(f[N][C]) 13 | -------------------------------------------------------------------------------- /leetcode/interview/bilibili/02.py: -------------------------------------------------------------------------------- 1 | nums = input().split(',') 2 | 3 | def mycmp(a,b): 4 | l = min(len(a), len(b)) 5 | i = 0 6 | for i in range(l): 7 | if int(a[i]) < int(b[i]): 8 | return True 9 | elif int(a[i]) > int(b[i]): 10 | return False 11 | if l < len(a): 12 | return a[i+1] < a[i] 13 | elif l < len(b): 14 | return b[i+1] > b[i] 15 | else: 16 | return True 17 | 18 | for i in range(len(nums)): 19 | for j in range(i, len(nums)): 20 | if not mycmp(nums[i], nums[j]): 21 | nums[i], nums[j] = nums[j], nums[i] 22 | 23 | 24 | print(''.join(nums)) 25 | 26 | -------------------------------------------------------------------------------- /leetcode/interview/bilibili/03.py: -------------------------------------------------------------------------------- 1 | s = input().split() 2 | start = 0 3 | end = len(s) - 1 4 | 5 | while start < end: 6 | s[start], s[end] = s[end], s[start] 7 | start = start + 1 8 | end = end - 1 9 | 10 | print(" ".join(s)) 11 | -------------------------------------------------------------------------------- /leetcode/interview/fast-speak-english/01.py: -------------------------------------------------------------------------------- 1 | n = int(input()) 2 | f = [0 for i in range(n+1)] 3 | f[1] = 1 4 | f[0] = 1 5 | for i in range(2, n+1): 6 | f[i] = f[i-1] + f[i - 2] 7 | print(f[-1]) -------------------------------------------------------------------------------- /leetcode/interview/fast-speak-english/02.py: -------------------------------------------------------------------------------- 1 | 2 | timer = {} 3 | for i in range(0,2400): 4 | timer[i] = 0 5 | 6 | starts = input().split() 7 | ends = input().split() 8 | 9 | for i in range(len(starts)): 10 | for t in range(int(starts[i]), int(ends[i])): 11 | timer[t] = timer[t] + 1 12 | 13 | print(max(timer.values())) -------------------------------------------------------------------------------- /leetcode/interview/little-red-book/01.py: -------------------------------------------------------------------------------- 1 | target, nums_str = [i for i in input().split()] 2 | target = int(target) 3 | nums_str = nums_str[1:] 4 | nums_str = nums_str[:-1] 5 | nums = [int(n) for n in nums_str.split(',')] 6 | 7 | res = 0 8 | 9 | res_set = set() 10 | 11 | def slove(target, current, current_set): 12 | global res 13 | if current > target: 14 | return 15 | elif current == target: 16 | current_set.sort() 17 | t = tuple(current_set) 18 | if t not in res_set: 19 | res_set.add(t) 20 | res = res + 1 21 | return 22 | for idx,n in enumerate(nums): 23 | next_set = list(current_set) 24 | next_set.append(idx) 25 | slove(target=target, current=current + n, current_set=list(next_set)) 26 | 27 | slove(target,0, list()) 28 | print(res) -------------------------------------------------------------------------------- /leetcode/interview/little-red-book/02.py: -------------------------------------------------------------------------------- 1 | res = input().split() 2 | 3 | def reverseString(s) -> None: 4 | if not s or len(s) == 1: 5 | return 6 | l = 0 7 | h = len(s) - 1 8 | while l < h: 9 | s[l], s[h] = s[h], s[l] 10 | l = l + 1 11 | h = h - 1 12 | 13 | if res: 14 | reverseString(res) 15 | print(' '.join(res)) -------------------------------------------------------------------------------- /leetcode/interview/little-red-book/03.py: -------------------------------------------------------------------------------- 1 | # from functools import lru_cache 2 | # num = int(input()) 3 | # notes = [int(i) for i in input().split()] 4 | # 5 | # _max_res = 0 6 | # _min_pick = 0 7 | # 8 | # @lru_cache(10000) 9 | # def slove(current_idx, current_res, current_pick): 10 | # global _max_res 11 | # global _min_pick 12 | # if current_idx >= len(notes): 13 | # return 14 | # 15 | # current_res = current_res + notes[current_idx] 16 | # current_pick = current_pick + 1 17 | # 18 | # if current_res > _max_res: 19 | # _max_res = current_res 20 | # _min_pick = current_pick 21 | # elif current_res == _max_res: 22 | # _min_pick = min(_min_pick, current_pick) 23 | # 24 | # for next_idx in range(current_idx + 2, len(notes)): 25 | # slove(next_idx, current_res, current_pick) 26 | # 27 | # 28 | # 29 | # for i in range(0, len(notes)): 30 | # slove(i, 0, 0) 31 | # 32 | # print("{} {}".format(_max_res, _min_pick)) 33 | # 34 | # 35 | # 36 | 37 | 38 | num = int(input()) 39 | notes = [int(i) for i in input().split()] 40 | 41 | f = [(0,0) for i in range(len(notes) + 1)] 42 | pick = 0 43 | f[1] = (notes[0], 1) 44 | for i in range(2, len(notes)+1): 45 | idx = i - 1 46 | v = notes[idx] 47 | if f[i-2][0]+ v > f[i-1][0]: 48 | # 选取 49 | f[i] = (f[i-2][0] + v, f[i-2][1] + 1) 50 | else: 51 | f[i] = (f[i-1][0] + 0, f[i-1][1] +0) 52 | 53 | print("{} {}".format(f[len(notes)][0], f[len(notes)][1])) 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /leetcode/interview/little-red-book/04.py: -------------------------------------------------------------------------------- 1 | N,T,M = [int(i) for i in input().split()] 2 | monsters = [int(i) for i in input().split()] 3 | if len(monsters) > T: 4 | print(-1) 5 | else: 6 | total = sum(monsters) 7 | min_res =( (sum(monsters) - T) // M ) + 1 8 | max_res = max(monsters) 9 | if (total-M)< T: 10 | print(-1) 11 | else: 12 | monsters.sort(reverse=True) 13 | has = False 14 | for h in range(min_res, max_res + 1): 15 | mp = M 16 | l = list() 17 | t = T 18 | for hp in monsters: 19 | if hp < h: 20 | l.append(hp) 21 | break 22 | cost = hp // h 23 | if hp == 0: 24 | break 25 | if(mp - cost) >= 0: 26 | mp = mp - cost 27 | t = t - cost 28 | new_hp = hp - cost * h 29 | if new_hp != 0: 30 | l.append(new_hp) 31 | else: 32 | t = t - mp 33 | if hp-mp != 0: 34 | l.append(hp-mp) 35 | mp = 0 36 | break 37 | if t <=0: 38 | break 39 | l.sort(reverse=True) 40 | leave = l[mp:] 41 | t = t - mp 42 | if sum(leave) <= t: 43 | print(h) 44 | has = True 45 | break 46 | if not has: 47 | print(-1) 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /leetcode/invert_binary_tree.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode(object): 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Solution(object): 9 | def invertTree(self, root): 10 | """ 11 | :type root: TreeNode 12 | :rtype: TreeNode 13 | """ 14 | 15 | def slove(r): 16 | r.left, r.right = r.right, r.right 17 | slove(r.right) 18 | slove(r.left) 19 | return r 20 | return slove(root) 21 | -------------------------------------------------------------------------------- /leetcode/k_th_smallest_in_lexicographical_order.py: -------------------------------------------------------------------------------- 1 | 2 | class TireNode: 3 | 4 | def __init__(self, v): 5 | self.val = v 6 | self.nodes = [] 7 | 8 | 9 | class Solution: 10 | def findKthNumber(self, n: int, k: int) -> int: 11 | root = TireNode('') 12 | _order = 0 13 | exit = False 14 | res = 0 15 | def build_tire(parent): 16 | nonlocal _order 17 | nonlocal res 18 | nonlocal exit 19 | if exit: 20 | return 21 | for i in range(0, 10): 22 | if exit: 23 | return 24 | if (not parent.val) and i == 0: 25 | continue 26 | node = TireNode(parent.val + str(i)) 27 | 28 | if int(node.val) > n: 29 | return 30 | else: 31 | _order = _order + 1 32 | root.nodes.append(node) 33 | if _order == k: 34 | res = int(node.val) 35 | exit = True 36 | else: 37 | build_tire(node) 38 | build_tire(root) 39 | return res 40 | 41 | Solution().findKthNumber(4289384,1922239) -------------------------------------------------------------------------------- /leetcode/kth-smallest-element-in-a-bst.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | def in_order_travel(root): 9 | if root.left: 10 | yield in_order_travel(root.left) 11 | yield root 12 | if root.right: 13 | yield in_order_travel(root.right) 14 | 15 | 16 | 17 | class Solution: 18 | def kthSmallest(self, root: TreeNode, k: int) -> int: 19 | g = in_order_travel(root) 20 | for i in range(k): 21 | next(g) 22 | return n.val -------------------------------------------------------------------------------- /leetcode/lcs.py: -------------------------------------------------------------------------------- 1 | int f[1001][1001]; 2 | int LCS(int *a, int m, int *b, int n) { 3 | memset(f,0,sizeof(f)); for (int i=1; i<=m; i++) 4 | for (int j=1; j<=n; j++) { 5 | // a中m个元素,b中n个元素 6 | if (a[i]==b[j]) f[i][j]=f[i-1][j-1]+1; 7 | f[i][j] = max(f[i][j], max(f[i-1][j], f[i][j-1])); } 8 | return f[m][n]; } -------------------------------------------------------------------------------- /leetcode/letter_combinations_of_a_phone_number.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | lookup = { 4 | "2":"abc", 5 | "3":"def", 6 | "4":"ghi", 7 | "5":"jkl", 8 | "6":"mno", 9 | "7":"pqrs", 10 | "8":"tuv", 11 | "9":"wxyz" 12 | } 13 | 14 | class Solution: 15 | def letterCombinations(self, digits: str) -> List[str]: 16 | res = list() 17 | if not digits: 18 | return res 19 | def slove(tmp_res:str, flag, alpha): 20 | nonlocal res 21 | tmp_res = tmp_res + alpha 22 | if flag == len(digits) - 1: 23 | res.append(tmp_res) 24 | return 25 | else: 26 | next_d = lookup[digits[flag + 1]] 27 | for a in next_d: 28 | slove(str(tmp_res), flag + 1, a) 29 | return 30 | for a in lookup[digits[0]]: 31 | slove('', 0, a) 32 | return res 33 | -------------------------------------------------------------------------------- /leetcode/linked_list_cycle_ii.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode(object): 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Solution(object): 8 | def detectCycle(self, head): 9 | """ 10 | :type head: ListNode 11 | :rtype: ListNode 12 | """ 13 | node = head 14 | res = set() 15 | if node: 16 | while node.next is not None: 17 | if node in res: 18 | return node 19 | else: 20 | res.add(node) 21 | node = node.next 22 | return None -------------------------------------------------------------------------------- /leetcode/longest-consecutive-sequence.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def longestConsecutive(self, nums: List[int]) -> int: 3 | num_set = set(nums) 4 | have_set = set() 5 | _max = 0 6 | for n in num_set: 7 | if n not in have_set: 8 | have_set.add(n) 9 | v = n + 1 10 | tmp_max = 1 11 | while v in num_set: 12 | have_set.add(v) 13 | v = v + 1 14 | tmp_max = tmp_max + 1 15 | _max = max(_max, tmp_max) 16 | return _max 17 | 18 | 19 | -------------------------------------------------------------------------------- /leetcode/longest-substring-with-at-least-k-repeating-characters.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | class Solution: 5 | def longestSubstring(self, s: str, k: int) -> int: 6 | def slove(s): 7 | c = Counter(s) 8 | for idx, v in enumerate(s): 9 | if c[v] < k: 10 | return max(slove(s[:idx]), slove(s[idx + 1:])) 11 | return len(s) 12 | 13 | return slove(s) 14 | 15 | -------------------------------------------------------------------------------- /leetcode/longest-substring_without_repeating_characters.py: -------------------------------------------------------------------------------- 1 | 2 | def slove(s, l, f): 3 | if l == 0: 4 | f.append(1) 5 | return 1 6 | else: 7 | res = slove(s, l-1, f) 8 | p = s[l-res:l].rfind(s[l]) + l-res 9 | if p != -1: 10 | f.append(l-p) 11 | return l - p 12 | else: 13 | f.append(res+1) 14 | return res + 1 15 | 16 | 17 | class Solution: 18 | def lengthOfLongestSubstring(self, s: str) -> int: 19 | if s: 20 | f = list() 21 | slove(s, len(s)-1, f) 22 | return max(f) 23 | else: 24 | return 0 -------------------------------------------------------------------------------- /leetcode/longest_increasing_subsequence.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def lengthOfLIS(self, nums: List[int]) -> int: 3 | if not nums: 4 | return 0 5 | dp = list([1 for i in range(len(nums) + 1)]) 6 | dp[1] = 1 7 | dp[0] = 0 8 | for i in range(2, len(nums) + 1): 9 | v = nums[i - 1] 10 | for n in range(1,i): 11 | if nums[n-1] < v and dp[n] >= dp[i]: 12 | dp[i] = dp[n] + 1 13 | return max(dp) -------------------------------------------------------------------------------- /leetcode/longest_palindromic_substring.py: -------------------------------------------------------------------------------- 1 | 2 | def is_back_str(s1): 3 | return s1 == s1[::-1] 4 | 5 | 6 | def get_end_poses(s, p, start_pos): 7 | res= [] 8 | for i in range(start_pos, len(s)): 9 | if s[i] == p: 10 | if i >= start_pos: 11 | res.append(i) 12 | return res 13 | 14 | def slove(s): 15 | results = [] 16 | res = '' 17 | for start_pos in range(len(s)): 18 | end_poss = get_end_poses(s, s[start_pos], start_pos) 19 | end_poss.reverse() 20 | for e in end_poss: 21 | if e - start_pos < len(res): 22 | break 23 | if is_back_str(s[start_pos:e+1]): 24 | results.append(s[start_pos: e+1]) 25 | if len(res) < len(s[start_pos: e+1]): 26 | res = s[start_pos: e+1] 27 | for r in results: 28 | if len(r) > len(res): 29 | res = r 30 | return res 31 | 32 | 33 | 34 | class Solution: 35 | def longestPalindrome(self, s: str) -> str: 36 | r = slove(s) 37 | return r 38 | -------------------------------------------------------------------------------- /leetcode/longest_repeating_character_replacement.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | 3 | def characterReplacement(self, s: str, k: int) -> int: 4 | if not s: 5 | return 0 6 | 7 | l = 0 8 | r = 1 9 | tmp_counter = {} 10 | tmp_counter[s[l]] = 1 11 | max_ch = (s[l], 1) 12 | tmp_total = 1 13 | res = 1 14 | 15 | def get_max_item(data): 16 | _max = None 17 | for k in data.keys(): 18 | if not _max: 19 | _max = (k,data[k]) 20 | else: 21 | _max = _max if _max[1] > data[k] else (k,data[k]) 22 | return _max 23 | 24 | while r < len(s): 25 | if tmp_total - max_ch[1] >= k: 26 | while r < len(s) and s[r] == max_ch[0] : 27 | tmp_counter[s[r]] = tmp_counter[s[r]] + 1 28 | tmp_total = tmp_total + 1 29 | max_ch = (max_ch[0], max_ch[1] + 1) 30 | r = r + 1 31 | # 不能换了 32 | res = max(r - l, res) 33 | while tmp_total - max_ch[1] >= k and l < r: 34 | tmp_counter[s[l]] = tmp_counter[s[l]] - 1 35 | max_ch = get_max_item(tmp_counter) 36 | tmp_total = tmp_total - 1 37 | l = l + 1 38 | if l > r: 39 | r = l 40 | if r < len(s): 41 | tmp_counter[s[r]] = tmp_counter.get(s[r], 0) + 1 42 | if tmp_counter[s[r]] > max_ch[1]: 43 | max_ch = (s[r], tmp_counter[s[r]]) 44 | tmp_total = tmp_total + 1 45 | r = r + 1 46 | return max(res, r - l) 47 | 48 | 49 | print(Solution().characterReplacement("AABABBA", 1)) 50 | print(Solution().characterReplacement("AABABBA", 1)) 51 | 52 | print(Solution().characterReplacement("ABAB", 2)) 53 | print(Solution().characterReplacement("AABA", 0)) 54 | print(Solution().characterReplacement("AABBBBB", 0)) 55 | 56 | print(Solution().characterReplacement("AAAA", 0)) 57 | print(Solution().characterReplacement("KRSCDCSONAJNHLBMDQGIFCPEKPOHQIHLTDIQGEKLRLCQNBOHNDQGHJPNDQPERNFSSSRDEQLFPCCCARFMDLHADJADAGNNSBNCJQOF", 4)) 58 | 59 | 60 | -------------------------------------------------------------------------------- /leetcode/lowest-common-ancestor-of-a-binary-tree.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | def slove(node, a, b): 9 | if node is None: 10 | return None 11 | if node is a or node is b: 12 | right = slove(node.right, a, b) 13 | left = slove(node.left, a, b) 14 | return node 15 | else: 16 | right = slove(node.right, a, b) 17 | left = slove(node.left, a, b) 18 | if right and left: 19 | return node 20 | elif right and not left: 21 | return right 22 | elif left and not right: 23 | return left 24 | 25 | 26 | 27 | class Solution: 28 | def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': 29 | return slove(root, p, q) 30 | -------------------------------------------------------------------------------- /leetcode/lru_cache.py: -------------------------------------------------------------------------------- 1 | class LinkNode: 2 | 3 | def __init__(self, key, v): 4 | self.key = key 5 | self.v = v 6 | self.next = None 7 | self.pre = None 8 | 9 | 10 | class LRUCache: 11 | 12 | def __init__(self, capacity: int): 13 | self.hash = dict() 14 | self.link_head = LinkNode(-1, -1) 15 | self.link_tail = LinkNode(-1, -2) 16 | self.link_tail.pre = self.link_head 17 | self.link_head.next = self.link_tail 18 | 19 | self.capacity = capacity 20 | self.num = 0 21 | 22 | def up(self, node): 23 | next = self.link_head.next 24 | if next != node: 25 | node.pre.next = node.next 26 | node.next.pre = node.pre 27 | next.pre = node 28 | self.link_head.next= node 29 | node.next = next 30 | node.pre = self.link_head 31 | 32 | def get(self, key: int) -> int: 33 | node = self.hash.get(key, None) 34 | if node: 35 | self.up(node) 36 | return node.v 37 | else: 38 | return -1 39 | 40 | def put(self, key: int, value: int) -> None: 41 | if key not in self.hash: 42 | if self.num < self.capacity: 43 | self.num = self.num + 1 44 | else: 45 | node = self.link_tail.pre 46 | del self.hash[node.key] 47 | node.pre.next = self.link_tail 48 | self.link_tail.pre = node.pre 49 | node = LinkNode(key, value) 50 | node.pre = self.link_head 51 | node.next = self.link_head.next 52 | node.next.pre = node 53 | self.link_head.next = node 54 | self.hash[node.key] = node 55 | else: 56 | self.hash[key].v = value 57 | self.up(self.hash[key]) 58 | 59 | -------------------------------------------------------------------------------- /leetcode/majority-element.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def majorityElement(self, nums: List[int]) -> int: 3 | counter = 1 4 | res = nums[0] 5 | for i in nums[1:]: 6 | if res != i: 7 | counter = counter - 1 8 | else: 9 | counter = counter + 1 10 | if counter == 0: 11 | res = i 12 | counter = 1 13 | return res -------------------------------------------------------------------------------- /leetcode/maximum-product-subarray.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def maxProduct(self, nums: List[int]) -> int: 3 | if not nums : 4 | return 0 5 | t_min = nums[0] 6 | t_max = nums[0] 7 | res = nums[0] 8 | for i in nums[1:]: 9 | if i < 0: 10 | # 遇到负数反转 11 | t_max, t_min = t_min, t_max 12 | t_max = max(i, i*t_max) # 核心思路 要么一直乘过来 要么从i开始乘 13 | t_min = min(i, i*t_min) # 负数 14 | res = max (res ,t_max) 15 | return res -------------------------------------------------------------------------------- /leetcode/merge-sorted-array.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: 3 | """ 4 | Do not return anything, modify nums1 in-place instead. 5 | """ 6 | i = m-1 7 | j = n-1 8 | for flag in range(m+n-1, -1, -1): 9 | if i < 0: 10 | nums1[flag] = nums2[j] 11 | j = j - 1 12 | elif j <0: 13 | nums1[flag] = nums1[i] 14 | i = i -1 15 | else: 16 | if nums1[i] > nums2[j]: 17 | nums1[flag] = nums1[i] 18 | i = i - 1 19 | else: 20 | nums1[flag] = nums2[j] 21 | j = j -1 22 | 23 | 24 | -------------------------------------------------------------------------------- /leetcode/min_stack.py: -------------------------------------------------------------------------------- 1 | class MinStack(object): 2 | 3 | def __init__(self): 4 | """ 5 | initialize your data structure here. 6 | """ 7 | self.min = None 8 | self._s = [] 9 | 10 | def push(self, x): 11 | """ 12 | :type x: int 13 | :rtype: None 14 | """ 15 | self._s.append(x) 16 | self.min = min(self._s) 17 | 18 | def pop(self): 19 | """ 20 | :rtype: None 21 | """ 22 | self._s.pop(-1) 23 | if self._s: 24 | self.min = min(self._s) 25 | else: 26 | self.min = None 27 | 28 | def top(self): 29 | """ 30 | :rtype: int 31 | """ 32 | return self._s[-1] 33 | 34 | def getMin(self): 35 | """ 36 | :rtype: int 37 | """ 38 | return self.min 39 | 40 | # Your MinStack object will be instantiated and called as such: 41 | # obj = MinStack() 42 | # obj.push(x) 43 | # obj.pop() 44 | # param_3 = obj.top() 45 | # param_4 = obj.getMin() -------------------------------------------------------------------------------- /leetcode/minimum_window_substring.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | class Solution: 4 | def minWindow(self, s: str, t: str) -> str: 5 | l = 0 6 | r = 0 7 | 8 | res = '' 9 | tmp = list() 10 | t_set = list(t) 11 | t_counter= Counter(t) 12 | reqired = sum(t_counter.values()) 13 | has_num = 0 14 | has = dict() 15 | while r < len(s): 16 | ch = s[r] 17 | if ch in t_counter and has.get(ch, 0) < t_counter[ch]: 18 | has_num = has_num + 1 19 | has[ch] = has.get(ch, 0) + 1 20 | if has_num == reqired: 21 | while l <= r: 22 | ch = s[l] 23 | has[ch] = has[ch] - 1 24 | if has[ch] < t_counter[ch]: 25 | has_num = has_num - 1 26 | if res: 27 | res = res if len(res) < (r - l + 1) else s[l:r + 1] 28 | else: 29 | res = s[l:r + 1] 30 | l = l + 1 31 | break 32 | l = l + 1 33 | r = r + 1 34 | return res -------------------------------------------------------------------------------- /leetcode/next_node_bin_tree.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def GetNext(self, pNode): 3 | # write code here 4 | if pNode.right: 5 | r = pNode.right 6 | while r.left: 7 | r = r.left 8 | return r 9 | 10 | else: 11 | while pNode.next is not None: 12 | p = pNode.next 13 | if p.left == pNode: 14 | return p 15 | pNode = pNode.next 16 | return None -------------------------------------------------------------------------------- /leetcode/next_permutation.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | 4 | 5 | def bubble_sort(blist, start): 6 | count = len(blist) 7 | for i in range(start, count): 8 | for j in range(i + 1, count): 9 | if blist[i] > blist[j]: 10 | blist[i], blist[j] = blist[j], blist[i] 11 | 12 | class Solution: 13 | def nextPermutation(self, nums: List[int]) -> None: 14 | """ 15 | Do not return anything, modify nums in-place instead. 16 | """ 17 | if not nums: 18 | return 19 | if len(nums) == 1: 20 | return 21 | if len(nums) == 2: 22 | if nums[0] < nums[1]: 23 | nums[0],nums[1] = nums[1], nums[0] 24 | return 25 | nums.sort() 26 | return 27 | length = len(nums) - 1 28 | n = len(nums) - 1 29 | changed = False 30 | # 交换 31 | flag = 0 32 | while n > 0: 33 | if nums[n -1] < nums[n]: 34 | flag = n - 1 35 | changed = True 36 | break 37 | n = n -1 38 | min_value = nums[flag+1] 39 | min_flag = flag+1 40 | 41 | if changed: 42 | n = flag + 1 43 | while n <= length: 44 | if nums[n] > nums[flag]: 45 | if nums[n] < min_value: 46 | min_value = nums[n] 47 | min_flag = n 48 | n = n + 1 49 | print(flag, min_flag) 50 | if flag != min_flag: 51 | nums[flag], nums[min_flag] = nums[min_flag], nums[flag] 52 | bubble_sort(nums, flag+1) 53 | return 54 | else: 55 | nums.sort() 56 | return 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /leetcode/number-of-longest-increasing-subsequence.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def findNumberOfLIS(self, nums: List[int]) -> int: 3 | if not nums: 4 | return 0 5 | f = [0 for n in nums] 6 | C = [1 for n in range(len(nums))] 7 | for idx, v in enumerate(nums): 8 | f[idx] = 1 9 | for j in range(1, idx + 1): 10 | if nums[idx - j] < v: 11 | if f[idx - j] >= f[idx]: 12 | C[idx] = C[idx - j] 13 | f[idx] = f[idx - j] + 1 14 | elif f[idx - j] + 1 == f[idx]: 15 | C[idx] = C[idx] + C[idx - j] 16 | 17 | res = 0 18 | _max = max(f) 19 | for idx, v in enumerate(f): 20 | if v == _max: 21 | res = res + C[idx] 22 | return res 23 | 24 | -------------------------------------------------------------------------------- /leetcode/number_of_atoms.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | from collections import defaultdict 3 | 4 | 5 | def pop_unitl_empty(s): 6 | res = [] 7 | while s: 8 | res.append(s.pop()) 9 | res.reverse() 10 | return ''.join(res) 11 | 12 | 13 | class Solution: 14 | def countOfAtoms(self, formula: str) -> str: 15 | _symbol_stack = [] 16 | _atom_stack = [] 17 | count = defaultdict(lambda: 0) 18 | 19 | def slove(s: str, base): 20 | print(s, base) 21 | nonlocal count 22 | nonlocal _atom_stack 23 | nonlocal _symbol_stack 24 | i = 0 25 | while i < len(s): 26 | if s[i] == '(': 27 | if not _symbol_stack: 28 | f = pop_unitl_empty(_atom_stack) 29 | if f: 30 | count[f] = count[f] + base 31 | _symbol_stack.append(s[i]) 32 | _atom_stack.append(s[i]) 33 | i = i + 1 34 | elif s[i] == ')': 35 | _symbol_stack.pop() 36 | if not _symbol_stack: 37 | num = 1 38 | num_s = '' 39 | i = i + 1 40 | while i < len(s) and s[i].isdigit(): 41 | num_s = num_s + s[i] 42 | i = i + 1 43 | if num_s: 44 | num = int(num_s) 45 | f = pop_unitl_empty(_atom_stack) 46 | slove(f[1:], num * base) 47 | else: 48 | _atom_stack.append(s[i]) 49 | i = i + 1 50 | else: 51 | if s[i].isupper(): 52 | if _atom_stack and (not _symbol_stack): 53 | f = pop_unitl_empty(_atom_stack) 54 | if f: 55 | count[f] = count[f] + base 56 | _atom_stack.append(s[i]) 57 | i = i + 1 58 | 59 | elif s[i].isdigit(): 60 | if _symbol_stack: 61 | _atom_stack.append(s[i]) 62 | i = i + 1 63 | else: 64 | num = 1 65 | num_s = s[i] 66 | i = i + 1 67 | while i < len(s) and s[i].isdigit(): 68 | num_s = num_s + s[i] 69 | i = i + 1 70 | if num_s: 71 | num = int(num_s) 72 | f = pop_unitl_empty(_atom_stack) 73 | if f: 74 | count[f] = count[f] + base * num 75 | else: 76 | _atom_stack.append(s[i]) 77 | i = i + 1 78 | if _atom_stack: 79 | f = pop_unitl_empty(_atom_stack) 80 | if f: 81 | count[f] = count[f] + base 82 | 83 | slove(formula, 1) 84 | print(count) 85 | 86 | result = [atom_name + ("" if count[atom_name] == 1 else str(count[atom_name])) for atom_name in 87 | count.keys()] 88 | result.sort() 89 | return "".join(result) 90 | 91 | 92 | print(Solution().countOfAtoms("K4(ON(SO3)2)2")) 93 | -------------------------------------------------------------------------------- /leetcode/odd_even_linked_list.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode(object): 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Solution(object): 8 | def oddEvenList(self, head): 9 | """ 10 | :type head: ListNode 11 | :rtype: ListNode 12 | """ 13 | if not head or not head.next or not head.next.next: 14 | return head 15 | i = 1 16 | pre_node = head 17 | node = head.next 18 | tail = head 19 | length = 0 20 | while True: 21 | length = length + 1 22 | if tail.next: 23 | tail = tail.next 24 | else: 25 | break 26 | 27 | print(length) 28 | while i < length: 29 | if (i + 1) % 2 : 30 | # 奇数 31 | node = node.next 32 | pre_node = pre_node.next 33 | else: 34 | # 偶数 35 | pre_node.next = node.next 36 | tail.next = node 37 | node.next = None 38 | tail = tail.next 39 | node = pre_node.next 40 | i = i + 1 41 | return head 42 | -------------------------------------------------------------------------------- /leetcode/package.py: -------------------------------------------------------------------------------- 1 | for (int i=1;i<=n;i++) 2 | for (int c=0;c<=C;c++) { 3 | f[i][c]=f[i-1][c]; 4 | if (c>=w[i]) f[i][c] = max(f[i][c], f[i-1][c-w[i]] + v[i]); } 5 | 6 | // 内层的for和外层的for可以互换。 for (int i=1;i<=n;i++) 7 | for (int c=0;c<=C;c++) // 这里发生了变化——循环次序变了 if (c>=w[i]) f[c] = max(f[c], f[c-w[i]] + v[i]); -------------------------------------------------------------------------------- /leetcode/palindrome-partitioning.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | class Solution: 3 | def partition(self, s: str) -> List[List[str]]: 4 | res = [] 5 | 6 | def slove(s, tmp): 7 | if not s: 8 | res.append(tmp) 9 | return 10 | for i in range(1,len(s)+1): 11 | if self.isPalindrome(s[:i]): 12 | slove(s[i:], [*tmp, s[:i]]) 13 | 14 | slove(s, list()) 15 | return res 16 | 17 | 18 | def isPalindrome(self, s: str) -> bool: 19 | l = 0 20 | r = len(s) - 1 21 | while l < r: 22 | if not (s[l].isdigit() or s[l].isalpha()): 23 | l = l + 1 24 | continue 25 | if not (s[r].isdigit() or s[r].isalpha()): 26 | r = r - 1 27 | continue 28 | if (r > l): 29 | if s[l].upper() != s[r].upper(): 30 | return False 31 | else: 32 | l = l + 1 33 | r = r - 1 34 | return True 35 | 36 | print(Solution().partition("aab")) -------------------------------------------------------------------------------- /leetcode/part_link.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Divide: 8 | def listDivide(self, head, val): 9 | # write code here 10 | node = head 11 | lte = ListNode(0) 12 | gte = ListNode(0) 13 | lte_head = lte 14 | gte_head = gte 15 | while node: 16 | next_node = node.next 17 | if node.val <= val: 18 | lte.next = node 19 | lte = lte.next 20 | else: 21 | gte.next = node 22 | gte = gte.next 23 | node.next = None 24 | node = next_node 25 | lte.next = gte_head.next 26 | return lte_head.next 27 | 28 | -------------------------------------------------------------------------------- /leetcode/path_sum_ii.py: -------------------------------------------------------------------------------- 1 | left_v+right_v+node.val,# Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Solution: 9 | def maxPathSum(self, root: TreeNode) -> int: 10 | _max = None 11 | cache = list() 12 | def get_max(node): 13 | nonlocal _max 14 | if not node: 15 | return 0 16 | left_v = get_max(node.left) 17 | right_v = get_max(node.right) 18 | #1 要 19 | res = max(left_v+node.val, right_v+node.val, node.val) 20 | if _max is None: 21 | _max = res 22 | _max = max(left_v+right_v+node.val, res, _max) 23 | return res 24 | 25 | get_max(root) 26 | 27 | if _max is None: 28 | return 0 29 | else: 30 | return _max 31 | 32 | -------------------------------------------------------------------------------- /leetcode/regular_expression_matching.py: -------------------------------------------------------------------------------- 1 | def match_simple(s, p): 2 | s_flag = 0 3 | p_flag = 0 4 | if not p: 5 | return not s 6 | 7 | while p_flag < len(p): 8 | if p_flag + 1 < len(p) and p[p_flag + 1] == '*': 9 | p_flag = p_flag + 1 10 | continue 11 | else: 12 | if p[p_flag] == '.': 13 | if s_flag >= len(s): 14 | return False 15 | s_flag = s_flag + 1 16 | elif p[p_flag] != '*': 17 | if s_flag >= len(s): 18 | return False 19 | if p[p_flag] != s[s_flag]: 20 | return False 21 | else: 22 | s_flag = s_flag + 1 23 | else: 24 | pre = p[p_flag - 1] 25 | while s_flag < len(s) and (s[s_flag] == pre or pre == '.'): 26 | res = match_simple(s[s_flag:], p[p_flag + 1:]) 27 | if res: 28 | return True 29 | s_flag = s_flag + 1 30 | p_flag = p_flag + 1 31 | if p_flag >= len(p): 32 | if s_flag >= len(s): 33 | return True 34 | else: 35 | return False 36 | return False 37 | 38 | 39 | class Solution: 40 | def isMatch(self, s: str, p: str) -> bool: 41 | return match_simple(s, p) 42 | -------------------------------------------------------------------------------- /leetcode/remove_nth_node_from_end_of_list.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | # Definition for singly-linked list. 4 | class ListNode: 5 | def __init__(self, x): 6 | self.val = x 7 | self.next = None 8 | 9 | class Solution: 10 | def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode: 11 | link_map = {} 12 | length = 0 13 | node = head 14 | while node: 15 | length = length + 1 16 | link_map[length] = node 17 | node = node.next 18 | 19 | r = length - n + 1 20 | 21 | if r == 1: 22 | return link_map[1].next 23 | elif r == length: 24 | link_map[r -1].next = None 25 | return head 26 | else: 27 | link_map[r-1].next = link_map[r+1] 28 | link_map[r].next = None 29 | return head -------------------------------------------------------------------------------- /leetcode/reorder-list.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | 8 | def get_link_mid(node): 9 | slow = node 10 | quick = node 11 | while quick and quick.next: 12 | quick = quick.next.next 13 | slow = slow.next 14 | return slow 15 | 16 | 17 | def reserve_link_list(head): 18 | pre = None 19 | node = head 20 | while node: 21 | node_next = node.next 22 | node.next = pre 23 | pre = node 24 | node = node_next 25 | return pre 26 | 27 | class Solution: 28 | def reorderList(self, head: ListNode) -> None: 29 | """ 30 | Do not return anything, modify head in-place instead. 31 | """ 32 | if not head: 33 | return head 34 | mid_node = get_link_mid(head) 35 | mid_node_next = mid_node.next 36 | mid_node.next = None 37 | mid_node = reserve_link_list(mid_node_next) 38 | node = head 39 | while mid_node: 40 | node_next = node.next 41 | mid_node_next = mid_node.next 42 | node.next = mid_node 43 | mid_node.next = node_next 44 | mid_node = mid_node_next 45 | node = node_next 46 | 47 | 48 | -------------------------------------------------------------------------------- /leetcode/repeated-string-match.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def repeatedStringMatch(self, A: str, B: str) -> int: 3 | 4 | if not B: 5 | return 1 6 | if not A: 7 | return -1 8 | # 初始化 9 | res = 1 10 | index_a = 0 11 | index_b = 0 12 | pre = 0 13 | while index_b < len(B): 14 | if B[index_b] not in A: 15 | return -1 16 | if index_a >= len(A): 17 | res = res + 1 18 | index_a = 0 19 | if B[index_b] == A[index_a]: 20 | index_b = index_b + 1 21 | elif A[index_a] != B[index_b]: 22 | if pre >= len(A): 23 | return -1 24 | if res > 1: 25 | res = res - 1 26 | index_a = pre 27 | index_b = 0 28 | pre = pre + 1 29 | index_a = index_a + 1 30 | return res 31 | -------------------------------------------------------------------------------- /leetcode/restore_ip_addresses.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | 4 | class Solution: 5 | def restoreIpAddresses(self, s: str) -> List[str]: 6 | res = set() 7 | 8 | def slove(s, tmp): 9 | nonlocal res 10 | if len(tmp) == 4: 11 | if not s: 12 | res.add('.'.join([str(t) for t in tmp])) 13 | return 14 | if not s: 15 | return 16 | for i in range(1, 4): 17 | v_s = s[:i] 18 | if (not v_s): 19 | return 20 | else: 21 | v = int(v_s) 22 | if len(v_s) > 1 and v_s.startswith('0'): 23 | return 24 | if not 0 <= v <= 255: 25 | return 26 | tmp.append(v) 27 | slove(s[i:], list(tmp)) 28 | tmp.pop() 29 | 30 | slove(s, []) 31 | return list(res) 32 | -------------------------------------------------------------------------------- /leetcode/reverse-linked-list-ii.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode: 3 | start_head = ListNode(0) 4 | start_head.next = head 5 | start = None 6 | flag = 0 7 | if m == n: 8 | return head 9 | while head is not None: 10 | flag = flag + 1 11 | if flag == m - 1: 12 | start = head 13 | if flag == m: 14 | s = self.reverseList(head, n - m) 15 | if start: 16 | start.next = s 17 | if m == 1: 18 | start_head.next = s 19 | break 20 | head = head.next 21 | return start_head.next 22 | 23 | def reverseList(self, head: ListNode, n) -> ListNode: 24 | if not head: 25 | return head 26 | pre = None 27 | _next = None 28 | end = head 29 | flag = 0 30 | if n == 0: 31 | return head 32 | while head is not None and flag <= n: 33 | if flag <= n: 34 | _next = head.next 35 | head.next = pre 36 | pre = head 37 | head = _next 38 | flag = flag + 1 39 | end.next = head 40 | return pre -------------------------------------------------------------------------------- /leetcode/reverse-linked-list/submissions.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Solution: 8 | def reverseList(self, head: ListNode) -> ListNode: 9 | if not head: 10 | return head 11 | pre = None 12 | _next = None 13 | while head: 14 | _next = head.next 15 | head.next = pre 16 | pre = head 17 | head = _next 18 | return pre -------------------------------------------------------------------------------- /leetcode/reverse-nodes-in-k-group.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Solution: 8 | def reverseKGroup(self, head: ListNode, k: int) -> ListNode: 9 | _stack = list() 10 | node = head 11 | if k == 0 or k == 1: 12 | return head 13 | tmp_head = None 14 | pre_tail = None 15 | while node is not None: 16 | _stack.append(node) 17 | node = node.next 18 | if len(_stack) == k: 19 | # 满足全部弹出逆序 20 | tmp = _stack.pop() 21 | pre_head = tmp 22 | if not tmp_head: 23 | tmp_head = tmp 24 | while _stack: 25 | n = _stack.pop() 26 | tmp.next = n 27 | tmp = tmp.next 28 | if pre_tail: 29 | pre_tail.next = pre_head 30 | tmp.next = node 31 | pre_tail = tmp 32 | if tmp_head: 33 | return tmp_head 34 | else: 35 | return head -------------------------------------------------------------------------------- /leetcode/reverse-string.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def reverseString(self, s: List[str]) -> None: 3 | """ 4 | Do not return anything, modify s in-place instead. 5 | """ 6 | if not s or len(s) == 1: 7 | return 8 | l = 0 9 | h = len(s) -1 10 | while l ListNode: 9 | if not head: 10 | return head 11 | r_node = ListNode(head.val) 12 | next_node = head.next 13 | while next_node: 14 | node = ListNode(next_node.val) 15 | node.next=r_node 16 | r_node = node 17 | next_node = next_node.next 18 | return r_node -------------------------------------------------------------------------------- /leetcode/rotate-array.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def rotate(self, nums: List[int], k: int) -> None: 3 | """ 4 | Do not return anything, modify nums in-place instead. 5 | """ 6 | if len(nums) <=1: 7 | return 8 | count = 0 9 | for start in range(k): 10 | if count >= len(nums): 11 | return 12 | slow = start 13 | if slow >= len(nums): 14 | slow = slow % len(nums) 15 | tmp = nums[slow] 16 | while True: 17 | count = count + 1 18 | quick = slow + k 19 | quick = quick %len(nums) 20 | nums[quick],tmp = tmp, nums[quick] 21 | slow = quick 22 | slow = slow % len(nums) 23 | if slow == start: 24 | break 25 | start = start + 1 26 | -------------------------------------------------------------------------------- /leetcode/search-a-2d-matrix-ii.PY: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def searchMatrix(self, matrix, target): 3 | """ 4 | :type matrix: List[List[int]] 5 | :type target: int 6 | :rtype: bool 7 | """ 8 | if not matrix: 9 | return False 10 | def search(row_end, cow_start): 11 | nonlocal matrix 12 | nonlocal target 13 | if cow_start == len(matrix): 14 | return False 15 | l = 0 16 | h = row_end 17 | while l < h: 18 | print(l, h) 19 | mid = (l+h)//2 20 | if matrix[cow_start][mid] < target: 21 | l = mid + 1 22 | elif matrix[cow_start][mid] > target: 23 | h = mid 24 | else: 25 | return True 26 | return search(h, cow_start + 1) 27 | return search(len(matrix[0]), 0) -------------------------------------------------------------------------------- /leetcode/search_in_rotated_sorted_array.py: -------------------------------------------------------------------------------- 1 | def binary_search(lis, num): 2 | left = 0 3 | right = len(lis) - 1 4 | while left <= right: 5 | mid = (left + right) // 2 6 | if num < lis[mid]: 7 | right = mid - 1 8 | elif num > lis[mid]: 9 | left = mid + 1 10 | else: 11 | return mid 12 | return -1 13 | class Solution: 14 | def search(self, nums: List[int], target: int) -> int: 15 | if not nums: 16 | return -1 17 | if len(nums) == 1: 18 | if nums[0] == target: 19 | return 0 20 | else: 21 | return -1 22 | lo, hi = 0, len(nums) -1 23 | 24 | def search(l, h): 25 | nonlocal nums 26 | nonlocal target 27 | if l == h: 28 | return -1 29 | if nums[l] == target: 30 | return l 31 | if nums[h] == target: 32 | return h 33 | povit = (h + l) // 2 34 | if nums[povit] == target: 35 | return povit 36 | if nums[povit] < nums[l]: 37 | # 右半区 38 | p = binary_search(nums[povit:h+1], target) 39 | if p != -1: 40 | return povit+p 41 | else: 42 | if povit == h: 43 | return -1 44 | return search(l,povit) 45 | 46 | elif nums[povit] > nums[hi]: 47 | # 左半区 48 | p = binary_search(nums[l:povit+1], target) 49 | if p != -1: 50 | return l+p 51 | else: 52 | if povit == l: 53 | return -1 54 | return search(povit,h) 55 | else: 56 | p = binary_search(nums[l:h+1], target) 57 | if p == -1: 58 | return -1 59 | return p + l 60 | 61 | return search(lo,hi) -------------------------------------------------------------------------------- /leetcode/serialize_and_deserialize_binary_tree.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode(object): 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Codec: 9 | 10 | def serialize(self, root): 11 | """Encodes a tree to a single string. 12 | 13 | :type root: TreeNode 14 | :rtype: str 15 | """ 16 | 17 | def mserialize(node): 18 | res = 'None' 19 | if node: 20 | if node.val is not None: 21 | res = str(node.val) 22 | res = res + ',' + mserialize(node.left) 23 | res = res + ',' + mserialize(node.right) 24 | return res 25 | return mserialize(root) 26 | 27 | def deserialize(self, data): 28 | """Decodes your encoded data to tree. 29 | 30 | :type data: str 31 | :rtype: TreeNode 32 | """ 33 | 34 | def mdeserialize(l): 35 | if not l: 36 | return None 37 | value = l.pop(0) 38 | if value != 'None': 39 | node = TreeNode(None) 40 | node.val = int(value) 41 | node.left = mdeserialize(l) 42 | node.right = mdeserialize(l) 43 | return node 44 | return None 45 | 46 | return mdeserialize(data.split(',')) 47 | 48 | # Your Codec object will be instantiated and called as such: 49 | # codec = Codec() 50 | # codec.deserialize(codec.serialize(root)) -------------------------------------------------------------------------------- /leetcode/set-matrix-zeroes.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def setZeroes(self, matrix: List[List[int]]) -> None: 3 | """ 4 | Do not return anything, modify matrix in-place instead. 5 | """ 6 | row = set() 7 | cow = set() 8 | for i in range(len(matrix)): 9 | for j in range(len(matrix[i])): 10 | if matrix[i][j] == 0: 11 | row.add(i) 12 | cow.add(j) 13 | 14 | 15 | for i in row: 16 | for j in range(len(matrix[i])): 17 | matrix[i][j] = 0 18 | 19 | for j in cow: 20 | for i in range(len(matrix)): 21 | matrix[i][j] = 0 -------------------------------------------------------------------------------- /leetcode/single-number.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def singleNumber(self, nums: List[int]) -> int: 3 | res = 0 4 | for n in nums: 5 | res = res ^ n 6 | return res -------------------------------------------------------------------------------- /leetcode/sliding-window-maximum.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: 3 | q = list() 4 | res = [] 5 | for i, v in enumerate(nums): 6 | start = i - k + 1 7 | while q: 8 | if nums[q[-1]] <= v: 9 | q.pop() 10 | else: 11 | break 12 | q.append(i) 13 | if start >= 0: 14 | while q: 15 | idx = q[0] 16 | if idx >= start: 17 | res.append(nums[idx]) 18 | break 19 | else: 20 | q.pop(0) 21 | return res 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /leetcode/string_to_integer_atoi.py: -------------------------------------------------------------------------------- 1 | import re 2 | class Solution: 3 | def myAtoi(self, s: str) -> int: 4 | return max(min(int(*re.findall('^[\+\-]?\d+', s.lstrip())), 2**31 - 1), -2**31) -------------------------------------------------------------------------------- /leetcode/super-egg-drop.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def superEggDrop(self, K: int, N: int) -> int: 3 | dp = [[0 for j in range(N+1)] for i in range(K+1)] 4 | for step in range(1, N+1): 5 | dp[0][step] = 0 6 | for k in range(1,K+1): 7 | dp[k][step] = dp[k-1][step-1] + dp[k][step-1] + 1 8 | if dp[k][step] >= N: 9 | return step 10 | return N 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /leetcode/symmetric_tree.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode(object): 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Solution(object): 9 | def isSymmetric(self, root): 10 | """ 11 | :type root: TreeNode 12 | :rtype: bool 13 | """ 14 | if not root: 15 | return True 16 | left_q = list() 17 | right_q = list() 18 | left_q.append(root.left) 19 | right_q.append(root.right) 20 | while left_q and right_q: 21 | left = left_q.pop(0) 22 | right = right_q.pop(0) 23 | if left == right: 24 | pass 25 | else: 26 | if left is None or right is None: 27 | return False 28 | if right.val != left.val: 29 | return False 30 | left_q.append(left.right) 31 | left_q.append(left.left) 32 | 33 | right_q.append(right.left) 34 | right_q.append(right.right) 35 | 36 | if (not left_q) and (not right_q): 37 | return True 38 | else: 39 | return False 40 | -------------------------------------------------------------------------------- /leetcode/trapping_rain_water.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | class Solution: 4 | def trap(self, height: List[int]) -> int: 5 | i = 0 6 | res = 0 7 | while i < len(height)-1: 8 | if height[i] > 0: 9 | max_value = (0, i) 10 | break_flag = False 11 | for j in range(i + 1, len(height)): 12 | if height[j] > height[i]: 13 | # 大 计算面积 14 | for n in height[i + 1:j]: 15 | res = res + (height[i] - n) 16 | i = j 17 | break_flag = True 18 | break 19 | max_value = (max_value[0], max_value[1]) if max_value[0] > height[j] else (height[j], j) 20 | if not break_flag: 21 | # 没找到 22 | for n in height[i + 1:max_value[1]]: 23 | res = res + (max_value[0] - n) 24 | i = max_value[1] 25 | else: 26 | i = i +1 27 | 28 | return res 29 | 30 | print( 31 | Solution().trap([0,1,0,2,1,0,1,3,2,1,2,1]) 32 | ) 33 | 34 | 35 | -------------------------------------------------------------------------------- /leetcode/unique-paths-ii.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: 3 | f = [[0 for j in range(len(i))] for i in obstacleGrid] 4 | f[0][0] = 1 5 | for x in range(len(obstacleGrid)): 6 | for y in range(len(obstacleGrid[x])): 7 | if x > 0: 8 | f[x][y] = f[x-1][y] + f[x][y] 9 | if y > 0: 10 | f[x][y] = f[x][y-1] + f[x][y] 11 | if obstacleGrid[x][y] == 1: 12 | f[x][y] = 0 13 | return f[-1][-1] 14 | -------------------------------------------------------------------------------- /leetcode/unique-paths.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def uniquePaths(self, m: int, n: int) -> int: 3 | if m == 0 or n == 0: 4 | return 0 5 | f = [[0 for j in range(n)] for i in range(m)] 6 | f[0][0] = 1 7 | for x in range(0, m): 8 | for y in range(0, n): 9 | if x > 0: 10 | f[x][y] = f[x-1][y] + f[x][y] 11 | if y > 0: 12 | f[x][y] = f[x][y-1] + f[x][y] 13 | return f[-1][-1] 14 | -------------------------------------------------------------------------------- /leetcode/utf_8_validation.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def validUtf8(self, data: List[int]) -> bool: 3 | 4 | bin_data = [format(i, '#010b')[-8:] for i in data] 5 | n = 0 6 | while n < len(bin_data): 7 | nbyte = 1 8 | if bin_data[n][0] != '0': 9 | nbyte = 0 10 | for i in bin_data[n]: 11 | if i != '1': 12 | break 13 | nbyte = nbyte + 1 14 | 15 | if nbyte == 1 or nbyte > 4: 16 | return False 17 | if len(bin_data[n + 1: n + nbyte + 1]) < nbyte-1: 18 | return False 19 | if nbyte != 1: 20 | for b in bin_data[n + 1: n + nbyte]: 21 | if not b.startswith("10"): 22 | return False 23 | n = n + nbyte 24 | 25 | return True -------------------------------------------------------------------------------- /leetcode/valid-anagram.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def isAnagram(self, s: str, t: str) -> bool: 3 | counter_s = {} 4 | counter_t = {} 5 | if len(s) != len(t): 6 | return False 7 | 8 | for i in s: 9 | counter_s[i] = counter_s.get(i, 0) + 1 10 | for i in t: 11 | counter_t[i] = counter_t.get(i, 0) + 1 12 | 13 | for i in set(s+t): 14 | if counter_s.get(i,0) != counter_t.get(i,0): 15 | return False 16 | return True 17 | -------------------------------------------------------------------------------- /leetcode/valid-palindrome.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def isPalindrome(self, s: str) -> bool: 3 | l = 0 4 | r = len(s)-1 5 | while l < r: 6 | if not (s[l].isdigit() or s[l].isalpha()): 7 | l = l + 1 8 | continue 9 | if not (s[r].isdigit() or s[r].isalpha()): 10 | r = r - 1 11 | continue 12 | if (r > l): 13 | if s[l].upper() != s[r].upper(): 14 | return False 15 | else: 16 | l = l + 1 17 | r = r - 1 18 | return Trues -------------------------------------------------------------------------------- /leetcode/valid_sudoku.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | 3 | nums = list([ str(i) for i in range(1 ,10)]) 4 | 5 | grid = [(0,0), (0, 3), (0, 6), 6 | (3,0), (3, 3), (3,6), 7 | (6,0), (6,3), (6,6)] 8 | class Solution: 9 | def isValidSudoku(self, board: List[List[str]]) -> bool: 10 | 11 | #检查每一行 12 | for i in range(0, 9): 13 | line = board[i] 14 | for n in nums: 15 | if line.count(n) > 1: 16 | return False 17 | 18 | for i in range(0 , 9): 19 | line = list() 20 | for j in range(0,9): 21 | line.append(board[j][i]) 22 | for n in nums: 23 | if line.count(n) > 1: 24 | return False 25 | 26 | for g in grid: 27 | line = list() 28 | for i in range(g[0], g[0] + 3): 29 | line.extend(board[i][g[1]:g[1] +3]) 30 | for n in nums: 31 | if line.count(n) > 1: 32 | return False 33 | return True -------------------------------------------------------------------------------- /leetcode/validate_stack_sequences.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def validateStackSequences(self, pushed, popped): 3 | """ 4 | :type pushed: List[int] 5 | :type popped: List[int] 6 | :rtype: bool 7 | """ 8 | pop_flag = 0 9 | stack = list() 10 | for i in pushed: 11 | stack.append(i) 12 | while stack and stack[-1] == popped[pop_flag]: 13 | stack.pop() 14 | pop_flag = pop_flag + 1 15 | if not pop_flag < len(popped): 16 | break 17 | 18 | if pop_flag == len(pop_flag): 19 | return True 20 | else: 21 | return False 22 | -------------------------------------------------------------------------------- /leetcode/verify_preorder_sequence_in_binary_search_tree.py: -------------------------------------------------------------------------------- 1 | 2 | class Solution(object): 3 | def verifyPreorder(self, preorder): 4 | """ 5 | :type preorder: List[int] 6 | :rtype: bool 7 | """ 8 | def build_bst(start, end, limit_min): 9 | if start == end: 10 | return True 11 | root = preorder[start] 12 | if root < limit_min: 13 | return False 14 | if end - start == 1: 15 | return True 16 | for i in range(start+1, end): 17 | if end < limit_min: 18 | return False 19 | if preorder[i] > root: 20 | left = build_bst(start + 1, i, limit_min) 21 | limit_min = root 22 | right = build_bst(i, end, limit_min) 23 | return left and right 24 | return build_bst(start+1,end, limit_min) 25 | 26 | return build_bst(0,len(preorder), 0) 27 | 28 | 29 | 30 | class Solution(object): 31 | def verifyPreorder(self, preorder): 32 | """ 33 | :type preorder: List[int] 34 | :rtype: bool 35 | """ 36 | _stack = [] 37 | limit_min = 0 38 | for i in preorder: 39 | if i < limit_min: 40 | return False 41 | while(_stack and i > _stack[-1]): 42 | limit_min = _stack.pop() 43 | _stack.append(i) 44 | return True 45 | -------------------------------------------------------------------------------- /leetcode/wildcard-matching.py: -------------------------------------------------------------------------------- 1 | from functools import lru_cache 2 | 3 | @lru_cache(10000) 4 | def match_simple(s, p): 5 | if not p and s: 6 | return False 7 | if not s and not p: 8 | return True 9 | s_index = 0 10 | p_index = 0 11 | p_ch = p[p_index] 12 | if p_ch == '*': 13 | p_index = p_index + 1 14 | while p_index < len(p) and p[p_index] == '*': 15 | p_index = p_index + 1 16 | p_index = p_index - 1 17 | 18 | while s_index <= len(s): 19 | res = match_simple(s[s_index:], p[p_index+1:]) 20 | if res == True: 21 | return True 22 | s_index = s_index + 1 23 | return False 24 | elif p_ch == '?': 25 | if not s: 26 | return False 27 | return match_simple(s[s_index+1:], p[p_index+1:]) 28 | else: 29 | if not s: 30 | return False 31 | if s[s_index] == p_ch: 32 | return match_simple(s[s_index+1:], p[p_index+1:]) 33 | else: 34 | return False 35 | class Solution(object): 36 | def isMatch(self, s, p): 37 | """ 38 | :type s: str 39 | :type p: str 40 | :rtype: bool 41 | """ 42 | return match_simple(s,p) -------------------------------------------------------------------------------- /leetcode/word-break.py: -------------------------------------------------------------------------------- 1 | from typing import * 2 | from functools import lru_cache 3 | 4 | # 5 | class Solution: 6 | def wordBreak(self, s: str, wordDict: List[str]) -> bool: 7 | @lru_cache(1000) 8 | def slove(s): 9 | nonlocal wordDict 10 | buf = [] 11 | if not s: 12 | return True 13 | for i in range(len(s)): 14 | buf.append(s[i]) 15 | if buf in wordDict: 16 | flag = slove(s[i + 1:]) 17 | if flag: 18 | return True 19 | return False 20 | 21 | return slove(s) 22 | 23 | class Solution: 24 | def wordBreak(self, s: str, wordDict: List[str]) -> bool: 25 | f = [False for i in range(len(s) + 1)] 26 | 27 | f[0] = True 28 | 29 | for i in range(1, len(s) + 1): 30 | for k in range(1, i+1): 31 | if s[k-1:i]in wordDict and f[k-1]: 32 | f[i] = True 33 | break 34 | 35 | return f[len(s)] 36 | 37 | print(Solution().wordBreak("leetcode", 38 | ["leet","code"])) 39 | 40 | -------------------------------------------------------------------------------- /leetcode/word-search-ii.py: -------------------------------------------------------------------------------- 1 | class TrieNode: 2 | def __init__(self, val): 3 | self.val = val 4 | self.word = False 5 | self.node = {} 6 | 7 | 8 | class Trie: 9 | 10 | def __init__(self): 11 | """ 12 | Initialize your data structure here. 13 | """ 14 | self.root = TrieNode('') 15 | 16 | 17 | 18 | def insert(self, word: str) -> None: 19 | """ 20 | Inserts a word into the trie. 21 | """ 22 | pre = self.root 23 | for w in word: 24 | if pre.node.get(w) is None: 25 | pre.node[w] = TrieNode(w) 26 | pre = pre.node[w] 27 | pre.word = True 28 | 29 | 30 | def search(self, word: str) -> bool: 31 | """ 32 | Returns if the word is in the trie. 33 | """ 34 | pre = self.root 35 | for w in word: 36 | if pre.node.get(w) is None: 37 | return False 38 | else: 39 | pre = pre.node[w] 40 | if not pre.word: 41 | return False 42 | return True 43 | 44 | 45 | 46 | 47 | def startsWith(self, prefix: str) -> bool: 48 | """ 49 | Returns if there is any word in the trie that starts with the given prefix. 50 | """ 51 | pre = self.root 52 | for w in prefix: 53 | if pre.node.get(w) is None: 54 | return False 55 | else: 56 | pre = pre.node[w] 57 | return True 58 | 59 | class Solution: 60 | def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: 61 | tree = Trie() 62 | if not board: 63 | return [] 64 | for w in words: 65 | tree.insert(w) 66 | visted = [[False for j in i] for i in board] 67 | head_q = list() 68 | head_q.append((0, 0)) 69 | visted[0][0] = True 70 | res = list() 71 | 72 | def in_board(r,c): 73 | nonlocal board 74 | if r >= len(board) or r < 0 or c >= len(board[0]) or c< 0: 75 | return False 76 | return True 77 | 78 | def slove(r,c, tmp_str,res:set, visted): 79 | nonlocal board 80 | nonlocal tree 81 | if tree.search(tmp_str): 82 | res.append(tmp_str) 83 | 84 | if in_board(r, c+1) and (not visted[r][c+1]) and tree.startsWith(tmp_str + board[r][c+1]) : 85 | # 下拓展 86 | down_visted = [[j for j in i] for i in visted] 87 | down_visted[r][c+1] = True 88 | slove(r, c+1, tmp_str + board[r][c+1], res, down_visted) 89 | 90 | if in_board(r, c-1) and (not visted[r][c-1]) and tree.startsWith(tmp_str + board[r][c-1]) : 91 | # 上拓展 92 | up_visted = [[j for j in i] for i in visted] 93 | up_visted[r][c-1] = True 94 | slove(r, c-1, tmp_str + board[r][c-1], res, up_visted) 95 | 96 | if in_board(r+1, c) and (not visted[r+1][c]) and tree.startsWith(tmp_str + board[r+1][c]): 97 | # 右拓展 98 | right_visted = [[j for j in i] for i in visted] 99 | right_visted[r+1][c]=True 100 | slove(r+1, c, tmp_str + board[r+1][c],res ,right_visted) 101 | 102 | if in_board(r-1, c)and (not visted[r-1][c]) and tree.startsWith(tmp_str + board[r-1][c]): 103 | # 左拓展 104 | left_visted = [[j for j in i] for i in visted] 105 | left_visted[r-1][c] = True 106 | slove(r-1, c, tmp_str + board[r-1][c],res ,left_visted) 107 | 108 | while head_q: 109 | pos = head_q.pop(0) 110 | 111 | tmp_str = '' 112 | if tree.startsWith(board[pos[0]][pos[1]]): 113 | tmp_visted = [[False for j in i] for i in board] 114 | tmp_visted[pos[0]][pos[1]] = True 115 | slove(r=pos[0], c=pos[1], tmp_str=board[pos[0]][pos[1]], res=res,visted = tmp_visted) 116 | r= pos[0] 117 | c= pos[1] 118 | if in_board(r, c+1) and (not visted[r][c+1]): 119 | visted[r][c+1] = True 120 | head_q.append((r, c+1)) 121 | if in_board(r+1, c) and (not visted[r+1][c]): 122 | visted[r+1][c] = True 123 | head_q.append((r+1, c)) 124 | 125 | return set(res) -------------------------------------------------------------------------------- /leetcode/zigzag_conversion.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def convert(self, s: str, numRows: int) -> str: 3 | answer = '' 4 | res = [list() for i in range(numRows)] 5 | pos_p = list( [i for i in range(numRows - 1)]) 6 | pos_p.append(numRows - 1) 7 | t = list([i for i in range(1, numRows - 1)]) 8 | t.reverse() 9 | pos_p.extend(t) 10 | print(pos_p) 11 | for i, a in enumerate(s): 12 | r = i % len(pos_p) 13 | print("R",r,pos_p[r]) 14 | res[pos_p[r]].append(a) 15 | for i in res: 16 | answer = answer + ''.join(i) 17 | return answer -------------------------------------------------------------------------------- /linux/linux.md: -------------------------------------------------------------------------------- 1 | # X86 2 | 3 | ## 8086 实模式 4 | 5 | ![例子](../assests/linux/01.png) 6 | 7 | IP: 下一条指令的寄存器 8 | 9 | 段寄存器 10 | 11 | CS: 代码段寄存器 可以找到代码在内存中的位置 12 | DS: 数据段寄存器 可以找到数据在内存中的位置 13 | SS: 栈寄存器 14 | 15 | 物理地址 = 段基址<<4 + 段内偏移 16 | 17 | ## 32 位 保护模式 18 | 19 | 通过段选择子访问 20 | 21 | # 启动流程 22 | 23 | 1. 加电 重置 CS 和 IP 找到对应 BIOS 程序 24 | 2. 映射到 Rom, Bios 做三件事: 25 | - 检查硬件 26 | - 提供中断服务, 建 立中断程序和中断表 27 | - 加载 MBR 执行 grub 28 | 3. boot.img 加载 core.img 29 | 4. core.img 包括 diskroot.img, lzma_decompress.img, kernel.img 以及其他模块 30 | 5. boot.img 先加载运行 diskroot.img, 再由 diskroot.img 加载 core.img 的其他内容 31 | 6. diskroot.img 解压运行 lzma_compress.img, 由 lzma_compress.img 切换到保护模式 32 | 33 | - 切换到保护模式需要做以下三件事: 34 | - 启用分段, 辅助进程管理 35 | - 启动分页, 辅助内存管理 36 | - 打开其他地址线 37 | - lzma_compress.img 解压运行 grub 内核 kernel.img, kernel.img 做以下四件事: 38 | - 解析 grub.conf 文件 39 | - 选择操作系统 40 | - 例如选择 linux16, 会先读取内核头部数据进行检查, 检查通过后加载完整系统内核 41 | - 启动系统内核 42 | 43 | # 内核初始化 44 | 45 | 1. 初始化 0 号进程 使用 set_task_tack_end_magic 46 | 2. 初始化中断门, 系统调用通过触发中断完成 trap_init 47 | 3. 初始化 内存管理(mm_init), 调度模型初始化(sched_init), 文件系统初始化.... 48 | 49 | 区域: 50 | 51 | ![例子](../assests/linux/02.png) 52 | 53 | 1. ring 0 内核态 54 | 2. ring 3 用户态 55 | 56 | 系统调用流程: 57 | 58 | ![例子](../assests/linux/03.png) 59 | 60 | > do\_ 系统调用的内核实现 61 | 62 | # 系统调用的封装 63 | 64 | 请求参数放入寄存器中, 根据系统调用名称 得到系统调用号, 放入 eax 65 | 66 | 触发软中断 进入内核: 67 | 68 | ``` 69 | # define ENTER_KERNEL int $0x80 70 | ``` 71 | 72 | 调用 iret 恢复现场 73 | 74 | ``` 75 | #define INTERRUPT_RETURN iret 76 | 77 | ``` 78 | 79 | 流程描述 80 | 81 | ![例子](../assests/linux/04.png) 82 | 83 | # 进程 84 | 85 | ## ELF 86 | 87 | - o 格式 ELF 88 | 89 | ![例子](../assests/linux/05.png) 90 | 91 | .text 二进制代码 92 | .data 初始化好的全局变量 93 | .rdata 只读数据 94 | .bss 未初始化 95 | .symtable 符号表 96 | .strable 字符串表 97 | .rel.xxx 重定位 不再本.o 的名字 放入这里 98 | 99 | - 可执行文件 100 | 101 | ![例子](../assests/linux/06.png) 102 | 103 | # .so 104 | 105 | > -L 链接自己的 -l 链接系统 106 | 107 | .plt 链接过程表 108 | .got 全局 offset 表 109 | 110 | 工作流程: 111 | 112 | > 调用 create_precess 113 | 114 | 1. PLT[X] 放入定位代码 115 | 2. 找到 GOT 里的地址 116 | 117 | ## linux 进程结构 118 | 119 | ![例子](../assests/linux/07.png) 120 | 121 | pid1: 用户的进程 122 | pid2: 内核态的进程 123 | 124 | ## linux task_structure 125 | 126 | ![例子](../assests/linux/08.png) 127 | 128 | ### 状态 129 | 130 | ![例子](../assests/linux/09.png) 131 | 132 | - TASK_INTERRUPTIBLE 可打断休息 133 | - TASK_UNINTERRUPTIBLE 不可打断 忽略 kill 134 | - TASK_KILLABLE 不可打断 不忽略 kill 135 | 136 | ## 调度 137 | 138 | ### 调度方式 139 | 140 | ``` 141 | #define SCHED_NORMAL 0 142 | #define SCHED_FIFO 1 143 | #define SCHED_RR 2 144 | #define SCHED_BATCH 3 145 | #define SCHED_IDLE 5 146 | #define SCHED_DEADLINE 6 147 | ``` 148 | 149 | 进程分成实时进程 和 普通进程 150 | 151 | 实时进程有如下: 152 | 153 | - SCHED_FIFO 相同优先级排队 高优先级优先 154 | - SCHED_PR 相同时间片 高优先级优先 155 | - SCHED_DEADLINE 最近 ddl 156 | 157 | 普通策略: 158 | 159 | - SCHED_NORMAL 普通进程 160 | - SCHED_BATCH 后台进程 161 | - SCHED_IDLE 只有空闲的搞 162 | 163 | CFS: 公平调度算法 164 | 165 | 1. 记录进程运行时间 vruntime = vruntime + 实际运行时间 \* NICE / weight 166 | 167 | 2. 使用红黑树, 找出 vruntime 最小的 168 | 169 | ![例子](../assests/linux/10.png) 170 | 171 | # 内存管理 172 | 173 | ## 分段 174 | 175 | ![例子](../assests/linux/11.png) 176 | 177 | 1. 请求结构: 178 | 179 | 段选择子 + 和段内偏移 180 | 181 | 2. 段选择子包括: 段号 + 特权等标志 182 | 183 | 3. 通过段奥 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /linux/启动引导.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # 操作系统习笔记(1) -- 一个操作系统的引导 11 | 12 | 本文以 xv6 的代码为主, 学习一个写操作系统设计到的内容, 参考: 13 | 14 | * xv6 的文档: https://github.com/ranxian/xv6-chinese 15 | 16 | * xv6 代码: https://github.com/mit-pdos/xv6-public 17 | 18 | 这个系列会日更, 用作自我学习, 如果说对你可能有什么帮助的话, 我这里会吧补充一些周边的相关信息, 可以让文档看起来更省力吧 大概. 19 | 20 | ## x86 实模式 21 | 22 | 寄存器都用来干啥: 23 | 24 | * AX、BX、CX、DX、SP、BP、SI、DI 8 个通用寄存器 25 | * CS、DS、SS、ES 上下文寄存器 CS(内存中代码段的位置) DS(内存中数据段的位置) SS(栈寄存器的位置) ES(平常不用的数据段寄存器) 26 | 27 | 通过 段寄存器 位移 4 位 + 偏移量 可以访问分段所有1m 的内存, 每个段大小是偏移量 也就是 16 位, 64k. 28 | 29 | 30 | ## 保护模式 31 | 32 | 保护模式的核心, 是: 33 | 34 | 1. 支持 32 位的寄存器, 35 | 36 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200311234119.png) 37 | 38 | 2. 改变寻址方式, 从 段寄存器 * 16 + 偏移, 变成 通过 段寄存器 访问 gdt 表, 然后找到后, 可以 知道 这个段的基地址, 边界, 和 属性(数据代码, 级别) 39 | 40 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200311230805.png) 41 | 42 | 进入保护模式的方法: 43 | 44 | 通过给 cr0 寄存器赋值 1 可以开启保护模式, 通过把 cs 寄存器跳转到一个 32 位的代码段, 可以开启用 gdt 翻译地址的模式. 45 | 46 | 47 | ## 引导系统 48 | 49 | 可以分成几个步骤: 50 | 51 | 1. 在实模式中, 关闭中断, 防止打断引导程序 52 | 53 | ``` 54 | cli 55 | ``` 56 | 57 | 2. 初始化所有段选择器 为 0 58 | 59 | 3. 加载 并初始化 gdt 为 gdtdesc 60 | 61 | ``` 62 | lgdt gdtdesc 63 | 64 | gdt: 65 | 设置 gdt 的每个段(空指针, 数据, 代码)的初始状态, 给每个设置成 4g, 因为 xv6 几乎不分段用分页 66 | 67 | gdtdesc: 68 | .word (gdtdesc - gdt - 1) # sizeof(gdt) - 1 69 | .long gdt # address gdt 70 | ``` 71 | 72 | 4. 进入保护模式 并跳转到 保护模式的寻址方式执行 73 | 74 | ``` 75 | orl $CR0_PE, %eax 76 | movl %eax, %cr0 # 给 cr0 赋值 1 开启保护模式 77 | ljmp $(SEG_KCODE<<3), $start32 78 | ``` 79 | 80 | 5. 初始化 32 位寄存器, 并分配一个段, 执行c语言的引导程序 81 | 82 | ``` 83 | movl $start, %esp # 用 start 代码的位置作为栈顶 84 | call bootmain 85 | ``` 86 | 87 | 6. bootmain 中, 先从硬盘读4096 个字节, 读到 elf里, elf 是内存的 0x10000地址 88 | 89 | ``` 90 | elf = (struct elfhdr*)0x10000; // scratch space 91 | readseg((uchar*)elf, 4096, 0); 92 | ``` 93 | 94 | 7. 检查合法性没有问题以后, 读完整个内核代码, 然后进入 elf 的入口 95 | 96 | 结合这个图和这个代码 97 | 98 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200311233226.png) 99 | 100 | ```c 101 | struct elfhdr { 102 | uint magic; // must equal ELF_MAGIC 103 | uchar elf[12]; 104 | ushort type; 105 | ushort machine; 106 | uint version; 107 | uint entry; 108 | }; 109 | ``` 110 | 111 | 可以猜出来 entry 就是代码段的地址, 调用就完事了 112 | 113 | ```c 114 | entry = (void(*)(void))(elf->entry); 115 | entry(); 116 | ``` 117 | 118 | 按照惯例, elf 的入口就是 _start 符号, 至此 进入内核程序. 引导完成. 119 | -------------------------------------------------------------------------------- /linux/锁和进程间通信.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # 操作系统习笔记(4) 完结-- xv6的锁, 进程间通信 11 | 12 | 啊, 本系列最后一篇了, 最后一节的内容很水, 没啥可讲的. 算是完结散花了. 13 | 14 | ## 锁的实现 15 | 16 | xv6 的锁是一个自旋锁. 用来协调 17 | 18 | ```c 19 | struct spinlock { 20 | uint locked; // Is the lock held? 21 | 22 | // For debugging: 23 | char *name; // Name of lock. 24 | struct cpu *cpu; // The cpu holding the lock. 25 | uint pcs[10]; // The call stack (an array of program counters) 26 | // that locked the lock. 27 | }; 28 | ``` 29 | 30 | 除了 locked, 别的字段都没啥用. 所以很明确的能知道, 只要cpu 一直忙等待检查和修改这个变量的状态就可以. 31 | 32 | 我们看加锁和解锁, 先说加锁: 33 | 34 | ```c++ 35 | // other CPUs to waste time spinning to acquire it. 36 | void 37 | acquire(struct spinlock *lk) 38 | { 39 | pushcli(); // disable interrupts to avoid deadlock. 40 | // The xchg is atomic. 41 | while(xchg(&lk->locked, 1) != 0) 42 | ; 43 | // Record info about lock acquisition for debugging. 44 | } 45 | ``` 46 | 47 | 几个步骤: 48 | 49 | * 禁止中断 50 | * 用 xchg 来修改 lk->locked 的值 ,其实就是 cas 51 | 52 | 解锁也简单: 53 | 54 | 55 | ```c++ 56 | void 57 | release(struct spinlock *lk) 58 | { 59 | asm volatile("movl $0, %0" : "+m" (lk->locked) : ); 60 | 61 | popcli(); 62 | } 63 | ``` 64 | 65 | * 直接设置成0 66 | * 允许中断 67 | 68 | 69 | ## weak 和 sleep 70 | 71 | sleep 干的事情, 很简单: 72 | 73 | ```c++ 74 | void 75 | sleep(void *chan, struct spinlock *lk) 76 | { 77 | struct proc *p = myproc(); 78 | if(lk != &ptable.lock){ //DOC: sleeplock0 79 | acquire(&ptable.lock); //DOC: sleeplock1 80 | release(lk); 81 | } 82 | // Go to sleep. 83 | p->chan = chan; 84 | p->state = SLEEPING; 85 | sched(); 86 | p->chan = 0; 87 | 88 | if(lk != &ptable.lock){ //DOC: sleeplock2 89 | release(&ptable.lock); 90 | acquire(lk); 91 | } 92 | } 93 | 94 | ``` 95 | 96 | * 拿到当前进程以后, 检查一下锁, 上好ptable 也就是进程表锁, 如果 lk 等于 ptable 锁, 那就认为这个锁已经锁好了 97 | * 改进程的状态为 sleep, 赋好 chan 的值, chan 就是判断 weak 的时候要不要唤醒, 相同 chan 的进程 weak 一起醒 98 | * 出让进程, 完事了删掉 chan 释放锁 99 | 100 | 101 | weakup, 同理: 102 | 103 | ```c++ 104 | static void 105 | wakeup1(void *chan) 106 | { 107 | struct proc *p; 108 | 109 | for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) 110 | if(p->state == SLEEPING && p->chan == chan) 111 | p->state = RUNNABLE; 112 | } 113 | 114 | // Wake up all processes sleeping on chan. 115 | void 116 | wakeup(void *chan) 117 | { 118 | acquire(&ptable.lock); 119 | wakeup1(chan); 120 | release(&ptable.lock); 121 | } 122 | ``` 123 | 124 | 就先上进程表锁(因为要切换进程), 然后找到 sleep 并且chan 相同的唤醒就行 125 | 126 | ### 实现 pipe 127 | 128 | 思路也很简单了 129 | 130 | ```c++ 131 | struct pipe { 132 | struct spinlock lock; 133 | char data[PIPESIZE]; 134 | uint nread; // number of bytes read 135 | uint nwrite; // number of bytes written 136 | .... 137 | }; 138 | ``` 139 | 140 | 读的时候, 加上锁, 有内容就读, 没有就睡, 读完了以后唤醒没读的, 并且解锁. 141 | 142 | 写的时候,加上锁, 有空就写, 没空就睡, 写完了唤醒读, 解锁. 143 | 144 | 没啥可说的.. 145 | 146 | 147 | ## 感悟 148 | 149 | 读这个的目的, 是想让自己看一些不在舒适区范围内的东西, 源码之下无神秘, 即使是os 内核那些想不出来实现机制的东西, 知道了里面人为约定的背景知识以后, 代码读起来就和自己写的一样自然而然. 150 | 151 | 读 demo 级别的东西有个好处是直接指向最核心的实现, 没有复杂的 Corner case, 读起来效率高收获也很大, 可以直接知道某个机制的实现原理和自己所缺乏的背景知识. 感觉是一个不错的学习方法, 之后也会多通过读 demo 项目代码来学习. (主要太菜了,生产的实现那么复杂实在看不懂) 152 | 153 | 接下来会忙一段时间毕设和项目, 有机会的话想康康 tcp/ip 协议栈的实现. 挖个坑吧~ -------------------------------------------------------------------------------- /networking/tcp.md: -------------------------------------------------------------------------------- 1 | # 流量控制 2 | 3 | 通过滑动窗口: 4 | 5 | 1. 发送窗口 通过对端 接受窗口大小控制 rwnd 6 | 2. 0 窗口报文: 7 | 1. 发送方不再发送 并且打开持续计时器 8 | 2. 到期了发送 0 窗口探测报文 9 | > 即使接受窗口为 0 也要接受 0窗口 确认 紧急数据 10 | 11 | # 可靠传输 12 | 13 | ## 滑动窗口 14 | 15 | * 发送方可根据拥塞情况, 缩小发送窗口 16 | * 对于不安序到达的, 会缓存 17 | * Tcp 要求接受方有累计确认 和 稍带确认. 18 | 1. 累计确认尝试等待 多确认一个 19 | 2. 捎带确认, 自己发数据的时候确认 20 | 3. 确认不能推迟 0.5s 以上 21 | 22 | ## 超时重传 23 | 24 | 超时重传时间: 25 | 26 | * rtt 往返时间 27 | * rto 超时重穿 28 | 29 | 利用每次测得的 rtt 加权计算 rtt (s) 30 | 31 | RTTs = (1 - a) * RTT(old) + a * RTT(new) 32 | 33 | ( 0 <= A < 1) : 34 | 35 | 一般 a 取 0.125 表示新 RTT 对现在 RTT 影响 36 | 37 | RTO 略大于 RTTS 38 | 39 | ``` 40 | RTO = RTT(s) + 4 * RTTD 41 | RTTD = RTT1 / 2 42 | 43 | newRTTD = (1-b) * RTTD + b * (RTT(s) - newRTT) 44 | 45 | 0 < b < 1: 46 | b = 0.25 47 | ``` 48 | 49 | ### 测量 RTT 50 | 51 | 1. 方法一: 只要报文段重传就不采用 RTT 52 | 2. 方法二: 报文段每次重传 就 增大 RTO 53 | 54 | ## 拥塞控制 55 | 56 | * 发送方维护拥塞滑动窗口 cwnd, 根据网络拥塞情况 动态调整 57 | * 出现拥塞的依据是 发生重传 58 | * 发送方维护 窗口和慢开始门限 ssthresh 59 | 1. cwnd < ssthresh 使用慢开始 60 | 2. cwnd > ssthresh 使用拥塞避免算法 61 | 62 | ### 流程 63 | 64 | 1. 慢开始: 每次翻倍 65 | 2. 拥塞避免: 每次 + 1 66 | 3. 发生拥塞直接衰落到 1, 开始慢开始, 拥塞窗口是发生拥塞的窗口的一半 67 | 68 | 69 | ### 快重传算法 70 | 71 | * 接受方立即发送确认 72 | * 发送方接受到了三个重复确认 立刻重传 73 | 74 | 75 | 发送方收到了三个确认, 说明网络中只丢失了个别报文, 不启动慢开始, 而是快恢复, 从 ssthresh 开始 +1 恢复 76 | 77 | ![例子](../assests/networking/02.png) 78 | 79 | 80 | # MTU 和 MSS 81 | 82 | ## MTU 83 | 84 | 查看 85 | ``` 86 | netstat -i 87 | ``` 88 | 89 | 链路层最大 90 | 91 | IP 数据包会分段 92 | 93 | 通过 Fragement offset 来偏移 94 | 95 | ## MSS 96 | 97 | MSS TCP最大传输 , 可以通过网卡分片 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /networking/协程-事件循环-异步io并发.md: -------------------------------------------------------------------------------- 1 | # 从协程-事件循环-异步 io 谈并发 2 | 3 | 当我们讨论异步编程的解决方案 类似 python 的 gevent asyncio 之类的基础库 和 aiomysql 等扩展, 我们总会涉及到 协程, 事件循环, 非阻塞 io 这几个概念. 其实他们是几个没什么关系的东西, 只是 把这些东西 组合起来 成为了现在用的最多的模式. 4 | 5 | ## 概念 6 | 7 | 首先是这几个概念: 8 | 9 | 1. 协程是一个可以保留上下文进行切换的功能 10 | 11 | 类似 12 | 13 | ```python 14 | 15 | yield 16 | await 17 | 18 | ``` 19 | 20 | 或者使用 setjump 等方式完成上下文的保存和切换 21 | 22 | 2. 事件循环就是一个事件机制的循环 23 | 一个简单的实现 24 | 25 | ```python 26 | class EventLoop(object): 27 | listener = {} 28 | event_source = None 29 | 30 | def add_listener(self, event, listner): 31 | self.listener[event.name] = listener 32 | 33 | def run(self): 34 | for event in self.event_source.run(): 35 | for l in self.listener[event.name]: 36 | l(event) 37 | ``` 38 | 39 | 3. 非阻塞 io 是 指进行读写等操作, 不阻塞 直接继续运行, 一般会报个错 40 | 41 | 4. io 复用, 通过 select 可以查看那些 文件描述符 准备就绪 可以用这个产生事件 42 | 43 | 知道了这些, 我们可以看看 asyncio 这个包 就是上述内容的组合 44 | 45 | - 首先 python 提供了协程的切换的语法 async/await 46 | - 其次 可以使用 eventloop api 进行事件处理 47 | - 内部封装了一个非阻塞的 io 包 并且 把 io 复用的事件放入事件循环 48 | 49 | ## 其他的模式 50 | 51 | 既然这几个概念没有关系, 我们可不可以有别的并发模式? 当然可以. 比如 52 | 53 | - 单独的协程, 这个一般情况下没什么意义 54 | 55 | ``` 56 | def async_sum(f_id, n): 57 | res = 0 58 | for i in range(n): 59 | res = i+res 60 | print("Functino id : {} , step: {}".format(f_id, i)) 61 | yield 62 | return res 63 | 64 | a = async_sum(1,3) 65 | b = async_sum(2,4) 66 | 67 | next(a) 68 | next(b) 69 | next(a) 70 | next(b) 71 | next(a) 72 | next(b) 73 | ``` 74 | 75 | 这个可以让这俩并发的执行 76 | 77 | - 单独事件循环 78 | 79 | 典型例子 redis 80 | 81 | 我们提供了 aeEventLoop 这个事件循环 和 aeCreateTimeEvent 来创建涉及到定时间的任务. 通过不断的更新系统的时间 和 查看最近的任务的时间来进行处理 82 | 83 | - 单独事件循环加 + io 复用 84 | 85 | 典型例子还是 redis, 还有一票基于 callback 的异步方案 86 | 87 | - 其他异步 io 88 | 89 | 类似信号+io 复用 也可以实现类似的效果 90 | 91 | ## 总结 92 | 93 | 本质上 非阻塞 io+io 复用 减少阻塞, 事件循环让 io 可以操作并发, 协程让异步代码写起来像同步. 94 | 95 | 针对不同的部分有不同的操作, 比如 协程可以通过各种方法实现 大致分成有栈和无栈俩种(python 有栈 lua 无栈). 通过对协程和事件循环的包装, 可以产生 future 这种更时候使用的对象 等等.. 96 | -------------------------------------------------------------------------------- /networking/理解有栈协程.md: -------------------------------------------------------------------------------- 1 | # 理解无栈协程 2 | 3 | > 可能会有错误, 只是自己简单的理解 4 | 5 | 之前一直没想明白了一个问题, 就是关于协程如何进行上下文切换. 6 | 7 | 众所周知, 协程是分为有栈协程和无栈协程俩种. 区别在于是否有自己的调用栈来进行函数调用等操作. 8 | 9 | ## 有栈协程 10 | 11 | 有栈协程这里的做法比较好理解, 一般来说有俩种做法: 12 | 13 | 1. 采用操作系统提供的api 类似 ucontext 或者 setjump longjump 14 | 15 | 2. 用汇编操控寄存器保存状态 典型的例子 16 | 17 | ```c 18 | static void context_swap(struct Context* prev_, struct Context* next_) 19 | { 20 | // store in .data, avoid copying stack frame to the new stack 21 | static uint64_t eip; 22 | static volatile struct Context* prev; 23 | static volatile struct Context* next; 24 | 25 | prev = prev_; 26 | next = next_; 27 | eip = next->regs.rip; 28 | 29 | // store current context in prev 30 | REG_STORE(rax, prev); 31 | REG_STORE(rbx, prev); 32 | REG_STORE(rcx, prev); 33 | REG_STORE(rdx, prev); 34 | REG_STORE(rsi, prev); 35 | REG_STORE(rdi, prev); 36 | REG_STORE(r8, prev); 37 | REG_STORE(r9, prev); 38 | REG_STORE(r10, prev); 39 | REG_STORE(r11, prev); 40 | REG_STORE(r12, prev); 41 | REG_STORE(r13, prev); 42 | REG_STORE(r14, prev); 43 | REG_STORE(r15, prev); 44 | REG_STORE(rbp, prev); 45 | REG_STORE(rsp, prev); 46 | // jump to $eip_to_store 47 | asm volatile ("movq $eip_to_store, %0" : "=m" (prev->regs.rip)); 48 | 49 | // resotre context from next 50 | REG_RESTORE(rax, next); 51 | REG_RESTORE(rbx, next); 52 | REG_RESTORE(rcx, next); 53 | REG_RESTORE(rdx, next); 54 | REG_RESTORE(rsi, next); 55 | REG_RESTORE(rdi, next); 56 | REG_RESTORE(r8, next); 57 | REG_RESTORE(r9, next); 58 | REG_RESTORE(r10, next); 59 | REG_RESTORE(r11, next); 60 | REG_RESTORE(r12, next); 61 | REG_RESTORE(r13, next); 62 | REG_RESTORE(r14, next); 63 | REG_RESTORE(r15, next); 64 | REG_RESTORE(rbp, next); 65 | REG_RESTORE(rsp, next); 66 | asm volatile ("jmpq *%0\n\t" : : "m" (eip)); 67 | 68 | // label: eip_to_store 69 | asm volatile("eip_to_store:\n"); 70 | } 71 | ``` 72 | 73 | ( 来源同班大佬同学 的代码 https://github.com/cyyzero/coroutine/blob/master/src/coroutine.c) 74 | 75 | 这样每个协程切换的时候, 整个栈都会被切换, 看起来和线程没啥区别, 只是调度一个发生在用户态可以由用户控制, 一个发生在内核态由系统控制. 76 | 77 | 78 | ## 无栈协程 79 | 80 | 有栈协程的做法比较好理解, 那无栈线程是怎么做的呢?无栈协程是怎么利用vm自带的栈完成上下文切换? 他的状态报存在哪里呢? 81 | 82 | 首先, 先说结论, 无栈协程的实现, 要几个条件: 1. 栈帧内保存的不是状态而是指向状态的指针. ** 2. 所有帧的状态保存在堆上 ** 83 | 84 | 为什么说第二点比较重要, 因为理解了第二点, 就发现, 其实根本不需要上下文切换, 因为全局的上下文就没变过, 改变他们的调用关系就行(栈) 85 | 86 | 87 | 例子: 88 | 89 | 我们有几行这个代码 假设每个函数都是10行字节码 90 | 91 | ```python 92 | 93 | def gen(): 94 | # code 95 | yield # 第3行字节码 96 | #code 97 | return # 第10行字节码 98 | 99 | def f1(): 100 | #code 101 | g1 = gen() 102 | next(g1) # 第3行字节码 103 | #code 104 | next(g1) # 第8行字节码 105 | #code 106 | return # 第10行字节码 107 | 108 | f1() 109 | ``` 110 | 111 | 我们把每个代码的执行的状态(帧) 叫PyFrame, 112 | 113 | ```c 114 | 115 | struct PyFrame { 116 | // 别的不重要 117 | *state //状态 118 | code // 当前执行到了第几行 119 | } 120 | 121 | ``` 122 | 123 | 我们栈的状态大致如下 124 | 125 | ![例子](../assests/networking/01.png) 126 | 127 | 注意第4步 g1的第二次入栈, 这时候, g1代表的PyFrame 的状态 在堆上, 所以压进来的时候 code就到了上次执行的第三行加一第四行了 128 | 129 | 130 | ## 区别 131 | 132 | 有栈协程可以随意的切换, 因为他所有状态都在他协程内部, 可以并行, 133 | 无栈协程只能手动切换, 不过效率要高 -------------------------------------------------------------------------------- /nginx/nginx.md: -------------------------------------------------------------------------------- 1 | # Nginx 2 | 3 | ## 使用 4 | 5 | ### 热升级 6 | 7 | 步骤 8 | 1. 备份 9 | ``` 10 | cp nginx nginx.bak 11 | ``` 12 | 13 | 2. 发送 USR2 14 | 15 | ``` 16 | kill -USR2 pid 17 | ``` 18 | 19 | 此时nginx 新老都在 20 | 21 | 3. 发送 -WINCH 22 | 23 | ``` 24 | kill -WINCH pid 25 | ``` 26 | 27 | 此时老的work退出 master还在 可以通过 reload 来启动 28 | 29 | ### 日志切割 30 | 31 | 使用 reopen 开启新的日志 32 | 33 | ## 内部机制 34 | 35 | ### 进程结构 36 | 37 | * 分为 master worker cacheManager(管理) cacheLoader(载入) 38 | * 基于共享内存通信 39 | 40 | ### 进程管理 41 | 42 | * master 43 | 44 | ``` 45 | 监控 worker CHLD 重启 46 | 管理 worker 47 | ``` 48 | 49 | 50 | ## 网络事件 51 | 52 | 读事件: 53 | 54 | * Accept 55 | * Read 56 | * 对端关闭 57 | 58 | 写事件: 59 | 60 | * 写消息 61 | 62 | 63 | ## 连接池 64 | 65 | ## work通信 66 | 67 | -------------------------------------------------------------------------------- /other/CPU 你要知道的.md: -------------------------------------------------------------------------------- 1 | # 关于 CPU 你要知道的--并发和 Cache 2 | 3 | > 本文旨在用人话解释一些概念, 快速让你知道这些概念的意思, 不做深入研究. 4 | 5 | CPU 一条指令的主要的工作流程 是 : 6 | 7 | 取指令 -> 译码 -> 执行 -> 访存 -> 写回 -> 更新程序计数寄存器 8 | 9 | 每一个步骤需要一个时钟周期. 10 | 11 | 而现代 cpu 加速的思路, 也是从这几个步骤下手: 12 | 13 | 1. 通过缓存 加快 准备数据的流程 14 | 2. 执行指令的时候 同时让多条指令运行 15 | 3. 写回结果的时候, 保证数据的同步 16 | 17 | 我们先不管 cache 看看同时多条指令运行的办法有哪些 18 | 19 | ## 多条指令执行--流水线, 多发射, 超线程, SIMD 20 | 21 | ### 流水线 22 | 23 | 正常情况下 我们执行指令是这样的: 24 | 25 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200229170505.png) 26 | 27 | 我们可以把一个指令分到多成多个步骤, 这样前一个步骤做完空闲了就可以处理别的指令. 28 | 29 | 比如 我们把一个指令 分成 1,2,3 三步, 当做到 2 步的时候, 负责 1 的流水线就空闲了, 可以处理下一个指令的 1, 类似下图 30 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200229170701.png) 31 | 32 | 而不采用流水线, 只能一次执行完一整条指令. 33 | 34 | 流水线也有副作用, 引入流水线, 要把上一道工序的结果暂存供下一道工序时候, 会有一些额外的开销. 35 | 36 | 37 | 流水线的核心目的, 是想 **要每次能取指令的时候(一个时钟周期)** 都可以取出来指令. 38 | 39 | ### 多发射 40 | 41 | 多发射指 利用复制相同功能的单元, 并行的执行多条指令. 42 | 43 | 这个 首先会一次拿多个指令, 然后会并行的译码执行, 44 | 45 | 因为 即使有流水线的存在, 如果一个周期只能取一条指令, 那么这个 Cpu 的一个时钟能执行的指令数还是 1 , 同时取多个就可以超过 1 了. 46 | 47 | 多发射技术有俩种模式, 如果是编译代码的时候, 进行多发射的调度, 也可以动态的进行多发射调度, 后者这种方式叫做( **超标量**) 48 | 49 | 流水线和多发射是所谓的 **指令级并行** 当然, 这里也存在很多问题: 50 | 51 | 1. 要同时发射那些指令才不会出问题? 52 | 2. 指令之间互相存在依赖怎么办? 53 | 54 | 这个稍后会解决. 55 | 56 | ### 超线程 57 | 58 | 超线程的思路是这样的: 59 | 60 | 1. 我们可以找出一组不会互相有依赖的指令, 比如俩个程序的指令 可以方便的让他们并行执行 61 | 2. cpu 中有俩种硬件, 一种是一个程序执行就会一直占用的硬件(程序计数寄存器, 指令寄存器,条件码寄存器 ), 62 | 另一种是可能会空闲的, 比如ALU 单元, 一个程序不计算执行别的过程时, 会空闲, 所以只有重复很少的一直占用的单元, 就可以实现并行执行的效果 63 | 64 | 最终效果这样. 65 | 66 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200229181734.png) 67 | 68 | 通过少部分硬件的重复并行利用大部分重复的硬件 69 | 70 | 71 | ### SIMD 单指令多数据流 72 | 73 | 这是一套和硬件配套的指令集, 需要编程的时候使用特定的指令, 74 | 75 | 简单的说, 就是一条指令, 可以同时取多个数据, 同时算多个数据. 76 | 77 | ### 冒险和预测--解决流水钱和多发射的问题 78 | 79 | 无论流水线还是多发射, 本意都是让指令并发的执行, 一但并发, 就存在几个问题: 80 | 81 | 1. 资源的竞争 我们这里成为 **结构冒险** 82 | 2. 数据的依赖 成为 **数据冒险** 83 | 3. 可以并发哪些 称为 **控制冒险** 84 | 85 | #### 结构冒险 86 | 87 | 当我们几条指令在*一个发射的流水线上执行的时候*, 在某个特定的时钟周期, 某两个指令都需要竞争一个结构资源, 比如主存 88 | 89 | 典型情况: 90 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200229214027.png) 91 | 92 | 我们称这种情况为结构冒险. 93 | 94 | #### 数据冒险 95 | 96 | 数据冒险就是同时指向多个指令的时候, 存在数据的依赖: 97 | 98 | 根据依赖的情况, 可以分为: 99 | 100 | 1. 先写后读 101 | 102 | ``` 103 | a = a + 1 104 | b = a + 3 105 | ``` 106 | 107 | 这个情况要等 第一句把新的 a 的值写回才能执行下一句 108 | 109 | 2. 先读后写 110 | 111 | ``` 112 | a = b + 2 113 | b= a + b 114 | ``` 115 | 116 | 读取 b 的值, 才能 执行第二句的写入 117 | 118 | 3. 写后再写 119 | 120 | ``` 121 | a = 1 122 | a = 2 123 | ``` 124 | 125 | 必须先写后一句再写前一句 126 | 127 | 128 | #### 控制冒险 129 | 130 | 流水线和多发射中, 要求上一条指令没完就要取下一条指令, 取那条指令就是一件很难判断的事 131 | 132 | ``` 133 | 1: if a: 134 | 2: .... 135 | 3: else: 136 | 4: .... 137 | 138 | ``` 139 | 140 | 比如这种情况, 需要 根据 1 的结果, 才能决定下一条并行 2还是4 141 | 142 | 为了解决上述问题, 我们想到了一些解决方案: 143 | 144 | #### 增加资源 145 | 146 | 现代 cpu 会采用混合架构, 把内存分为数据缓存和指令缓存, 这样取指令和读存的两个指令, 就不会冲突了. 147 | 148 | 类似的, 结构冒险都可以考虑用增加资源的办法 149 | 150 | ### 指令对齐 151 | 152 | 由于指令的长度不一样, 流水线进行排序的时候 会出现这样的情况, 先开始的长指令. 和后开始的短指令, 同时指向到一个步骤, 比如写回内存, 产生了对同一资源的竞争, 比如, 153 | 154 | 155 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200229215408.png) 156 | 157 | 我们可以对指令的长度进行填充, 插入 NOP(什么都不干), 让他们一样长来避免这个问题. 158 | 159 | #### 停顿 160 | 161 | 当发生依赖的时候, 我们可以通过在这个周期什么都不干 ,来等待锁依赖的数据就绪, 这个有点像并发编程轮询的办法 162 | 163 | 164 | #### 操作数前推 165 | 166 | 这是一种可以减少停顿时间的办法, 167 | 168 | ``` 169 | 1: add $t0, $s2,$s1 170 | 2: add $s2, $s1,$t0 171 | ``` 172 | 173 | 比如这样的代码, 理论上说, 代码 2 要等到代码 1 将结果写回才可以进入执行阶段, 174 | 175 | 通过一些硬件上的构造, 我们可以把代码 1 *执行*阶段的结果直接发送给代码 2, 而不用等 1 *写回* 完成. 176 | 177 | #### 乱序执行 178 | 179 | 我们可以把解释好的指令存起来, 放到一个地方, 等满足依赖条件直接畅通无阻的发出去, 再搜集好结果排成原来的顺序 180 | 181 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200229220224.png) 182 | 183 | 184 | #### 分支预测 185 | 186 | 就是猜猜下一个可能的指令是什么, 来解决控制冒险, 猜错了就再卡住执行对的 187 | 188 | 189 | ## 加快存取速度--缓存 190 | 191 | 冯诺曼依瓶颈: cpu 执行代码的速度远远快于从主存取数据 192 | 193 | ### 通用的结构 194 | 195 | 196 | 会分成组, 组里有行, 每行会对应内存中的一个数据, 有一个有效,标记 和数据, 首先 加载数据的单位是 2^b 197 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200229232601.png) 198 | 199 | 200 | 201 | 有效位, 用来判断这个缓存是不是 dirty, 202 | 203 | 根据索引, 查到组, 组内部找到 标记 相同的行, 说明这行的数据是缓存, 缓存了2^b个, 利用后 b个位的数字的 偏移就可以找到具体的数据 204 | 205 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200229233031.png) 206 | 207 | 208 | 也就是说 一个行对应的是 所有 **组索引** 相同的数据内存, 根据 **标记** 看看存的是不是对应的一块, 通过 **块偏移拿到具体数据** 209 | 210 | 我们可以根据通用结构的特例, 找到几种不同的链接方式: 211 | 212 | 1. 直接映射 每个组只有一行 213 | 2. 组关联 有多个组 每个组多行 214 | 3. 全相连 只有一个组 215 | 216 | 217 | ### 写入策略 218 | 219 | 读没什么问题, 问题是写, 写了一个 缓存行, 什么时候把这个行写回主存? 220 | 221 | 1. 写直达 write-through 222 | 223 | 核心思想就是数据一定要阻塞的写回内存. 如果缓存命中, 就写缓存, 然后等缓存写回主存, 才能完成这次 224 | 225 | 2. 写回 write-back 226 | 227 | 写回策略的核心 是 延迟写入, 当一个缓存行要被替换掉的时候才写回到 ram 中. 228 | 229 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200301000134.png) 230 | 231 | 232 | ### 多核缓存一致性 和 MESI协议 233 | 234 | 满足能让多核缓存一致的办法 有俩个理论条件; 235 | 236 | 1. 写传播, 写入的信息可以传播到别的 cpu 核心 237 | 238 | 2. 事务串行化, 每个核心看对一个缓存的操作的顺序都是一样的, 反例: 239 | 240 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200301001119.png) 241 | 242 | 243 | 244 | ## MESI协议 245 | 246 | MESI 是 M(修改) E(独占) S(共享) I(失效的缩写)的缩写, 当发现缓存被共享且要写入的时候, 会广播一个写失效的消息. 标记别的核心的缓存失效. 247 | 248 | 为了节约广播的信息, MESI协议会监听别的 cpu 对内存的读取信息, 第一次获取这个内存, 会把内存信息标记成独占, 如果监听到了其他读内存的信息, 就改成共享, 对共享的修改 要传播给其他核心失效. 思路想读写锁. 249 | 250 | 251 | ## 小结 252 | 253 | 学习计算机的本质是复读机, 这里出现的思路, 都是在更高层级的地方不断出现的内容, 从各个层级不断复读这些思路, 从而多角度的理解, 这可能是业务码农学习底层原理的一个用处吧. 254 | 255 | 256 | 参考资料: 257 | 258 | [1]. 极客时间 深入浅出计算机组成原理. http://gk.link/a/10gq7 259 | [2]. <深入理解计算机系统>. 260 | [3]. <并行程序设计导论>. -------------------------------------------------------------------------------- /other/parser.py: -------------------------------------------------------------------------------- 1 | # E -> E + T 2 | # | T 3 | # T -> T * F 4 | # | F 5 | # F -> num 6 | 7 | tokens = [('1', 'num'), ('+','add'), ('2', 'num'),('*','puls'), ('5','num')] 8 | flag = 0 9 | def parser_F(): 10 | global flag 11 | if tokens[flag][1] == 'num': 12 | v = int(tokens[flag][0]) 13 | flag = flag + 1 14 | return v 15 | else: 16 | raise Exception("F") 17 | 18 | 19 | def parser_T(): 20 | global flag 21 | res = parser_F() 22 | token = tokens[flag] 23 | while token[0] =='*': 24 | flag = flag + 1 25 | res = res * parser_F() 26 | if flag >= len(tokens): 27 | break 28 | token = tokens[flag] 29 | return res 30 | 31 | 32 | def pareser_E(): 33 | global flag 34 | res = parser_T() 35 | token = tokens[flag] 36 | while token[0] =='+': 37 | flag = flag + 1 38 | if flag >= len(tokens): 39 | break 40 | res = res + parser_T() 41 | token = tokens[flag] 42 | return res 43 | 44 | print(pareser_E()) -------------------------------------------------------------------------------- /other/思考cpu占用.md: -------------------------------------------------------------------------------- 1 | # cpu占用 2 | 3 | * 操作系统怎么计算 cpu 占用? 4 | * 如何分析 cpu 占用?用到哪些命令? 5 | * 线程和进程对于 cpu 占用的影响? 6 | * 实际使用 7 | 8 | -------------------------------------------------------------------------------- /python 源码/python.md: -------------------------------------------------------------------------------- 1 | # code 2 | 3 | 是一个代码段, 一个函数,模块,类, 迭代器 4 | 5 | ## 字段: 6 | 7 | * co_argcount 参数个数 8 | * co_stacksize 栈空间 9 | * co_nlocals 局部变量数量 10 | * co_code 字节码 11 | 12 | # frame 13 | 14 | 栈帧, 一个执行环境 用 sys._current_frames() 获得 15 | 16 | ## 字段: 17 | 18 | * f_values/ f_stacktop... 栈的位置 19 | * f_back 前一个栈帧 20 | 21 | ## 机制: 22 | 23 | * 复用, 代码相同的栈帧不会构造直接复用 24 | 25 | # gil 26 | 27 | 释放: 28 | 只有一个线程, 不会释放 gil 29 | 等待 gil 的线程看到 gil 为 1 直接申请要, 持有的下次执行释放, 超时的置为 0 重新等待 30 | 条件变量获取线程 31 | 32 | 33 | # 内存管理 34 | 35 | # arean 链表 256k 36 | # pool 4kb 37 | # block -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Effective Node - 2019 本科生秋招后端进阶笔记 2 | 3 | > 非入门, 进阶之路 4 | 5 | 作为一个大三的学生, 马上就面临秋招找工作的问题, 这时候发现自己,对很多知识理解太过表面, 都停留在会用的层次. 而更进阶的的用法和原理却不太知晓. 所以打算用一段时间完成会用到进阶的过程, 把其中的学习内容记录成笔记.目标是通过一段时间学习具备对后端基础设施有进阶程度的了解并具备开发中间件的能力. 6 | 7 | 本次复习笔记记录内容主要包括: 8 | 9 | - mysql 10 | - 缓存 11 | - golang 12 | - 数据结构算法 13 | - 容器 14 | - 计算机科学通识 15 | 16 | 因为时间舍弃但很想添加的内容(顺序有优先级): 17 | 18 | - 网络协议 19 | - 消息队列 20 | - 操作系统 21 | 22 | ## Mysql 23 | 24 | - [mysql 复习重点](https://github.com/IcyCC/effective_note/blob/master/mysql/mysql%E5%A4%8D%E4%B9%A0%E9%87%8D%E7%82%B9.md) 对极客时间 mysql 内容的复习总结, 对 mysql 的日志, 锁, 缓存 机制有个基本概念 25 | 26 | ## Golang 27 | 28 | - [golang 极客时间](https://github.com/IcyCC/effective_note/blob/master/golang/golang.md) 对极客时间 golang 内容的复习总结, 没啥干货内容 29 | -------------------------------------------------------------------------------- /redis/ae/ae.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // 一些函数的定义 4 | typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask); 5 | typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData); 6 | typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData); 7 | typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop); 8 | 9 | typedef struct aeFileEvent 10 | { 11 | int mask; // 捕获的掩码 读/写 12 | aeFileProc *rfileProc; 13 | aeFileProc *wfileProc; 14 | void *clientData; 15 | } aeFileEvent; 16 | 17 | /* 准备就绪的事件 */ 18 | typedef struct aeFiredEvent 19 | { 20 | int fd; 21 | int mask; 22 | } aeFiredEvent; 23 | 24 | typedef struct aeTimeEvent 25 | { 26 | long long id; /* time event identifier. */ 27 | long when_sec; /* seconds */ 28 | long when_ms; /* milliseconds */ 29 | aeTimeProc *timeProc; // 处理 30 | aeEventFinalizerProc *finalizerProc; 31 | void *clientData; 32 | struct aeTimeEvent *next; // 链表 33 | } aeTimeEvent; 34 | 35 | typedef struct aeEeventLoop 36 | { 37 | /* data */ 38 | int maxfd; // 注册的最大的文件描述符 39 | int setsize; // 关注的最大文件描述符数量 40 | long long timeEventNextId; // 下一个timer 的 ID 41 | time_t lastTime; // 诊断系统时间差 42 | aeFileEvent *events; // 关注的event 43 | aeFiredEvent *fired; 44 | aeTimeEvent *timeEventHead; // 链表链接时间事件 45 | int stop; // 运行状态 46 | void *apidata; //特别数据 47 | aeBeforeSleepProc *beforesleep; // 钩子 下个事件发生执行 48 | } aeEeventLoop; 49 | 50 | -------------------------------------------------------------------------------- /分布式/tanlent_plan/进阶数据库-逻辑优化.md: -------------------------------------------------------------------------------- 1 | # 进阶数据库-逻辑优化 2 | 3 | > 学习最好的方法就是把他讲给别人。 4 | 5 | 这是学习, pingcap的 [talent-plan](https://github.com/pingcap/talent-plan) 作业四的学习笔记。 主要讲解优化器相关的知识。 6 | 7 | ## 逻辑优化的基础 8 | 9 | 我们有这样一条 sql **select a, max(b) from t groub by a having a>1 and b>2**. 10 | 11 | 这条 sql 经过解析过程成为了一颗 ast 树, ast 树有 sql 的所有信息。 只凭借这课 ast 树, 我们其实是可以执行所有的 sql. 例如我之前学生时代做的大作业, 简易 db : [chidb](http://chi.cs.uchicago.edu/chidb/index.html) 就是这样的一个数据库。 12 | 13 | 然而,我们现在要做一个有追求的 db, 就要不仅能用, 还要性能好。 14 | 15 | 其实这条 sql 有不同的执行方式, 这些执行方式, 这些执行方法和具体的数据库物理实现无关,无论是硬盘型内存型,无论数据分布, 只要按这种方式执行, 就可以获得优化, 这是关系代数保证的。 16 | 17 | 比如可以先执行 过滤 a>1 再执行 groub by a. 也可以先执行 group by a 再执行 a >1. 这些不同的执行过程的结果是一样的,但是效率天差地别, 如何从这些等价的执行方法中, 选取出最佳的执行方法, 就是逻辑优化要做的事情。 18 | 19 | 所以我们要对这条 sql 的执行过程做一个抽象, 这个抽象就是 logic plan. 20 | 21 | 一个逻辑计划由逻辑算子组成。 可以参考 tidb 的[文档说明](https://docs.pingcap.com/zh/tidb/v3.0/query-execution-plan). 他里面定义了如下的算子, 我这里直接引用了 tidb 的[原文](https://pingcap.com/zh/blog/tidb-source-code-reading-7) 22 | 23 | 24 | > * DataSource 这个就是数据源,也就是表,select * from t里面的 t。 25 | > * Selection 选择,例如 select xxx from t where xx = 5里面的 where 过滤条件。 26 | > * Projection 投影, select c from t里面的取 c 列是投影操作。 27 | > * Join 连接, select xx from t1, t2 where t1.c = t2.c就是把 t1 t2 两个表做 Join。 28 | > * Sort 就是 select xx from xx order by里面的 order by。 29 | > * Aggregation,在 select sum(xx) from xx group by yy中的 group by操作,按某些列分组。分组之后,可能带一些聚合函数,比如 Max/Min/Sum/Count/Average 等,这个例子里面是一个 sum。 30 | > * Apply 这个是用来做子查询的。 31 | 32 | 他这里用了 sql 举例, 实际上逻辑算子是一层单独的抽象, 他是从关系代数的概念演化而来, 和 sql 的具体语法无关系。 比如聚合算子(Aggregation) 不一定是用 gourp by。 别的一个方法也需要聚合算子。 33 | 34 | 通过这些逻辑算子, 我们就能构造出逻辑计划树。 针对这课逻辑计划树, 我们有一些具体的优化算法 35 | 36 | ## 逻辑优化算法 37 | 38 | tidb 实现了一些具体的逻辑优化算法, 可以参考[这个文档](https://docs.pingcap.com/zh/tidb/stable/sql-logical-optimization). 我这里讲解一下作业要求实现的谓词下推算法。 39 | 40 | 谓词下推的思路就是, 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /分布式/分布式学习笔记(一).md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # 分布式学习 11 | 12 | 本文是对 MIT6.824的一个笔记 标注出要看的 paper 和对 paper 的一个简单描述. 用作个人复习和简单知道要讲啥,带着内容去听课. 13 | 14 | ## MapReduce 15 | 16 | 此论文比较好理解 略. 17 | 18 | ## GFS 19 | 20 | > The Google File System https://static.googleusercontent.com/media/research.google.com/zh-CN//archive/gfs-sosp2003.pdf 21 | 22 | ### 架构 23 | 24 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200530152755.png) 25 | 26 | master 存放 元数据: 27 | 28 | 1. 文件名和 chunk 对应 29 | 2. chunk 和 chunk servers 的 的对应 30 | 31 | chunk server 存放: 32 | 33 | 1. chunk 的 偏移 34 | 2. 具体的 chunk 35 | 36 | ### 发现数据异常 37 | 38 | chunk 由 block 组成 一个block 64kb 39 | 40 | block 保存 32bit 的校验和 检查校验和. 41 | 42 | ### 减少 chunk 挂掉的损失 43 | 44 | 复制 chunk 放三个地方, 2+1 45 | 46 | ### 恢复 chunk 47 | 48 | 损坏的 cs 向 mster 求助, 找别的 cs 求助 49 | 50 | ### cs 挂点 51 | 52 | * 用心跳检测 53 | * 排工作列表 优先修复最紧急的 54 | 55 | ### 读文件 56 | 57 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200530152300.png) 58 | 59 | 1. clint 问 master 在哪里 (filename, chunkid[可用偏移计算]) 60 | 2. master 告诉 client 在哪里(cs) 61 | 3. client 读 cs (chunkid,offset) 62 | 4. cs 返回数据 63 | 64 | ### 写文件 65 | 66 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200530152700.png) 67 | 68 | 1. client 向 master 要所有副本cs 69 | 2. master 告诉 client 副本 cs 70 | 3. client 向 cs 发送数据 71 | 4. cs 之间数据同步, 给 client 响应 72 | 5. client 向primary cs 发送写请求 73 | 6. 由 primary cs 负责管理别人写 74 | 7. 完成后给 client 响应 75 | 76 | 出错了让客户端重试 77 | 78 | ## 主从备份 79 | 80 | > The Design of a 81 | > Practical System for 82 | > Fault-Tolerant Virtual Machines https://pdos.csail.mit.edu/6.824/papers/vm-ft.pdf 83 | 84 | 主要实现有两种: 85 | 86 | 1. state transfer 状态转义: 87 | 88 | 主节点发送新的状态给从节点 89 | 90 | 2. replicated state machine 备份状态机: 91 | 92 | 主节点客户端执行的操作 发送给备份节点. 93 | 要求: 在相同的其实状态,相同的操作, 相同的顺序, 确定的, 到相同的结束状态 94 | 95 | 96 | state transfer 简单, 但是流量大 97 | 98 | replicated state machine 流量少, 但是复杂 99 | 100 | 思考的问题: 101 | 102 | * 那些状态要同步? 103 | * 主节点是否需要等从节点同步? 104 | * 什么时间切换? 105 | * 怎么提高切换速度? 106 | 107 | 而在 Fault-Tolerant Virtual Machines 论文中, 目标是备用机代替主机后,客户端感受不到这个切换. 108 | 109 | 状态转义就是 x86指令的转转移 110 | 111 | 由于主备机存在延迟, 所以存在如下情况: 112 | 113 | 主机操作 [a,b,c,out] 此时主机已经执行out了, 而备机只是收到了a,b, 如果此时挂掉, 那么 c 就没执行完,且因为客户端已经收到 out 的结果,对此并不知情, 就出现了不一致. 114 | 115 | 为了解决这个问题, 论文提出了输出要求. 116 | 即 到了输出指令不输出, 知道确认备机收完全部指令再输出. 但是这样不能避免客户端会看到两次输出, 而在论文里认为这样是可以接受的,应用会处理. 117 | 118 | 对于脑裂问题, 即主备机互相因为网络故障,无法通讯,都认为自己主节点, 论文提出了共享一个虚拟磁盘,然后往磁盘里写 test-and-set 锁, 谁不能访问这个磁盘谁就算挂了. 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /分布式/分布式学习笔记(三).md: -------------------------------------------------------------------------------- 1 | 9 | # 科班分布式学习(三)- 一致性和Zookeeper & CRAQ 10 | 11 | ## Zookeeper 12 | 13 | > 这个没太看懂要阐述的知识点, 都是系统设计和使用上的, 所以提出里面的一致性做个讨论 14 | 15 | zookeeper 这里保持共识的 zab 协议和 raft 很像. 16 | 17 | zookeeper 这论文的讲了两点: 18 | 19 | 1. zookeeper 的一致性 20 | 2. 一种类似文件系统的 api 设计 21 | 22 | 通过一致性保证和 api 构造锁等分布式常见业务 23 | 24 | ### 分布式一致性 25 | 26 | zk 写情况下是线性一致性, 读写情况下是顺序一致性. 那这些一致性是什么意思. 27 | 28 | 我们把复制数据之间的同步叫一致性, 一般来说 我们有以下一致性模型(参考维基百科的版本 网上版本较多): 29 | 30 | #### 线性一致性 31 | 32 | 首先是强一致性模型,我们也称 **线性一致性(Linearizable Consistency)**: 33 | 34 | 要求如下: 35 | 36 | 1. 任何一次读都能读到最近写入的值 37 | 2. 对于所有 client 其像按照统一的时间串行的执行了这些操作 38 | 39 | 这个要求的意思就是, 比如有 a,b 两个节点 40 | 41 | ``` 42 | a: A------B 43 | b: ----C-----D 44 | ``` 45 | 46 | 分别执行 ABCD, 并行执行, 那么最终落盘的顺序就是 ACBD 严格按照某个时钟顺序来 47 | 48 | #### 顺序一致性 49 | 50 | 有一种比强一致性稍微弱一些的一致性, 叫 **顺序一致性** 51 | 52 | 要求: 53 | 54 | 1. 执行指令为编程顺序,不同client 没有严格的顺序要求 55 | 2. 对所有节点来看整个系统是一个单一的顺序 56 | 57 | 这个要求的意思就是 还是 ab, 58 | 59 | ``` 60 | a: A------B 61 | b: ----C-----D 62 | ``` 63 | 64 | 那么落盘的顺序可以是 ABCD 也可以 CABD....但是 不能 BADC这样不按照编程顺序, 而且如果确定了 ABCD那么所有节点读到的顺序都是 ABCD 65 | 66 | 想比较强一致性, 该要求少了对不同节点相同时间顺序的要求 67 | 68 | 69 | ### 因果一致性 70 | 71 | 这个要求比较好理解, 他要求有因果关系的操作的顺序一致即可: 72 | 73 | 比如 ab 节点: 74 | 75 | ``` 76 | a: A------B(C) 77 | b: ----C-----D 78 | ``` 79 | 80 | 这里 B对 C有依赖 B 一定在 C 的后面, 但是对于 AD 没有任何要求.只要满足 B 在 C 的后面的顺序都可以,对于别的节点读取也不做要求 81 | 82 | 在 zookeeper 里, 写操作都是线性一致性, 客户端通过 fifo 来保证顺序一致性 83 | 84 | 85 | ** 其余部分没有看出论文要阐述的设计的点 ** 86 | 87 | > 有一些讲了怎么用 api 做锁啥的 思路太直接了 不做讨论 88 | 89 | ## CRAQ 90 | 91 | 论文首先介绍了一个简单的强一直性的系统设计: **链复制** 92 | 93 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200611222327.png) 94 | 95 | 这是一个链表, 写请求写在链表头, 读请求在链表尾巴. 96 | 97 | 写请求来了, 会逐个向后传播, 并且此时这个数据的状态是 未提交, 98 | 等到传到了末节点, 才会提交这个修改, 并且提交的确认信息向前传播. 99 | 100 | 而读取只能从尾结点读取. 读取到的一定是已经达成了一致的消息. 101 | 102 | ### 故障 103 | 104 | * 头结点挂 提交确认消息 没有到 不影响一致 105 | * 尾结点宕机, 新成为尾结点的节点提交自己 106 | * 中间节点宕机 没影响 107 | 108 | 然后因为业务普遍读多写少,而这样容易有读瓶颈, 所以提出了 **分配查询链复制** 109 | 110 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200611230548.png) 111 | 112 | 写请求还是写在 头结点, 写的时候带一个版本号, 版本号初始化为dirty 状态, 然后传播写到尾结点, 尾结点把这个版本标记成 clean 再反向传播. 113 | 114 | 而读的时候, 可以 如果是 clean 直接返回, 如果不是,就向最后一个节点问最新的版本号, 把这个版本号的数据返回. 115 | 116 | 针对读多写少这个方案很划算, 如果写多的话会常常读到 dirty 版本导致效率下降, 但是因为只读一个版本号, 对尾结点负担还是比较 *链复制CR* 小. 117 | 118 | 119 | 此外通过细小的变化可以支持多种一致性模型: 120 | 121 | * 强一致性模型, 之前聊得都是. 122 | 123 | * 最终一致性 读的时候直接返回最新的版本就行, 这样会破坏读取的单调性 124 | 125 | * 最大边界的最终一致性 返回最新的, 但是说明这是多少时间以内的不一致 126 | 127 | 对比 Raft 128 | 129 | Raft 只要半数, CR 需要等节点逐个传递, 万一不可用要等 130 | 131 | 后面是一些实践的内容了 不做过多讨论. 132 | 133 | ## 参考文献 134 | 135 | [1] https://iswade.github.io/translate/zookeeper zookeeeper 论文翻译 136 | 137 | [2] https://pdos.csail.mit.edu/6.824/papers/craq.pdf crqa 论文 138 | 139 | [3] https://en.wikipedia.org/wiki/Consistency_model 一致性模型 wiki 140 | 141 | [4] https://zhuanlan.zhihu.com/p/57315959 一致性模型 -------------------------------------------------------------------------------- /分布式/分布式学习笔记(二).md: -------------------------------------------------------------------------------- 1 | 9 | # 科班分布式学习(二)-Raft 10 | 11 | 阅读指南: 最重要的还是论文!!!! 讲的十分清楚 12 | 13 | > https://github.com/maemual/raft-zh_cn/blob/master/raft-zh_cn.md raft 中文论文 14 | 15 | 本文是对论文中不太好理解的一些内容的标注和解释. 可以阅读本文一遍再阅读论文在看一遍本文. 16 | 17 | 18 | ## 关注点 19 | 20 | * 领导选取 21 | * 日志复制 22 | 23 | ## Raft 基础 24 | 25 | * 状态机 26 | 27 | ![](https://static001.infoq.cn/resource/image/07/94/0758bfb601f9f39ee3f18bc170f55b94.jpg) 28 | 29 | 对每一个节点, 有 领导人, 候选人, 追随者三个身份. 30 | 31 | 为防止脑裂 采用大多数投票法 32 | 33 | ## 正常流程 34 | 35 | 1. 启动时所有节点为 follower, 且每个节点随机 选举计时器, follower 响应candidate 和 leader 请求. 如果 36 | 2. 选举定时器超时后 成为响应candidate: 37 | * 自增任期 38 | * 给自己偷拍 39 | * 重置选举计时器 40 | * 发送投票 rpc 给其他 41 | 42 | 3. 收到大部分人的投票后成为 leader, 收到新的 leader 的日志附加 rpc 就成为 follower. leader 持续不断给 follower 发心跳检测 43 | 44 | 45 | 原则: 46 | 47 | 1. 收到比自己大的 term 的消息就把自己变成 follower , 并且让自己的 term 等于其 term. 48 | 2. 每个 term 只有一张票, 投票的原则是先来先得, 不给投票的情况有: 49 | * 先给自己投票并成为 candidate, 50 | * 发现对方持久化的日志没有自己新, 评价标准 先对比 最大的term, 如果一样数量多的是最新的 51 | 52 | 53 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200607184126.png) 54 | 55 | 如图 S2 开始选举, 收到请求的节点 term 立刻变成 2 并给出选票 56 | 57 | ## 日志同步 58 | 59 | 1. leader 接收日志, 发送给其他节点. 60 | 2. 其他节点收到后给 leader 发送确认, 61 | 3. leader 收到大多数的确认后将日志 commit 62 | 4. 之后 commit 信息随着只有的日志附加 rpc 同步给各个节点 63 | 64 | ### 异常情况 65 | 66 | 1. 发生 leader 切换. 67 | 68 | leader 负责把自己的日志同步给其他节点, 流程先和其他节点确定最近一致的日志(即对应下标的日志 term 相同), 然后将之后的日志覆盖为自己的日志 69 | 70 | 这样做没问题的前提是, 我们确保成为 leader 的节点以及是拥有最新已提交日志的节点, 我们可以保证已经提交的日志的一致性. 71 | 72 | 每个 leader 只会提交自己 term 的日志, 之前 term 的日志只会捎带的提交 73 | 74 | 2. 收到日志后未同步给其他节点, 发生了 leader 切换. 75 | 76 | 这个情况下, 日志未提交, 日志会被新的 leader 覆盖掉,如图 77 | 我们给当前 leader S5 发送请求后, 关闭其 请求此时为发生 78 | 79 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200607190022.png) 80 | 81 | 这时s1 开始了竞选, 并 S5 恢复, S5日志比 S1新 不投票, 但是其还是获得大多数投票成为 leader 82 | 83 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200607190143.png) 84 | 85 | 这是请求 S1, 会覆盖S5节点的日志, 完成同步 86 | 87 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200607190516.png) 88 | 89 | 3. 收到日志同步给其他节点, 但是leader 未提交发生 leader 切换 90 | 91 | leader 节点 S4 收到请求后, 同步给其他节点, 但是未收到响应的时候就挂了 92 | 93 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200607190756.png) 94 | 95 | 随后 S5 成为了新的 leader, term2 的日志不会提交 96 | 97 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200607190927.png) 98 | 99 | 之后 term 3 的日志出现会随着 term3 的日志提交之前 term2 的日志 100 | 101 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200607191134.png) 102 | 103 | 这个设计是为了解决论文 5.4.2 提出的问题. 即由于一个节点故障恢复又故障再恢复, 造成同时有俩个无法区分优先度的**中间的提交**过程, 发生冲突, 新的 leader 的日志覆盖了之前已经提交的日志 104 | 105 | 而只能提交本 term 的这个限制保证 必须有新的日志写入才能提交, 保证了拥有了提交日志的节点的 leader 不会被其他的节点的日志覆盖, 因为没它新, 而覆盖的都是未提交的. 106 | 107 | 4. 日志已经提交了但是提交信息伟同步给其他节点. 108 | 这个情况当上 leader 的节点一定是拥有全日志的节点,因为满足大多数的情况. 等下条新日志到来时, 直接合并提交. 109 | 110 | 111 | ## 协议信息分析 112 | 113 | 114 | **请求投票 RPC**: 115 | 116 | 由候选人负责调用用来征集选票(5.2 节) 117 | 118 | | 参数 | 解释| 119 | |---|---| 120 | |term| 候选人的任期号| 121 | |candidateId| 请求选票的候选人的 Id | 122 | |lastLogIndex| 候选人的最后日志条目的索引值| 123 | |lastLogTerm| 候选人最后日志条目的任期号| 124 | 125 | | 返回值| 解释| 126 | |---|---| 127 | |term| 当前任期号,以便于候选人去更新自己的任期号| 128 | |voteGranted| 候选人赢得了此张选票时为真| 129 | 130 | lastLogIndex 和 lastLogTerm 用于确定日志有没有自己新 131 | 132 | **附加日志 RPC**: 133 | 134 | 由领导人负责调用来复制日志指令;也会用作heartbeat 135 | 136 | | 参数 | 解释 | 137 | |----|----| 138 | |term| 领导人的任期号| 139 | |leaderId| 领导人的 Id,以便于跟随者重定向请求| 140 | |prevLogIndex|新的日志条目紧随之前的索引值| 141 | |prevLogTerm|prevLogIndex 条目的任期号| 142 | |entries[]|准备存储的日志条目(表示心跳时为空;一次性发送多个是为了提高效率)| 143 | |leaderCommit|领导人已经提交的日志的索引值| 144 | 145 | | 返回值| 解释| 146 | |---|---| 147 | |term|当前的任期号,用于领导人去更新自己| 148 | |success|跟随者包含了匹配上 prevLogIndex 和 prevLogTerm 的日志时为真| 149 | 150 | prevLogIndex prevLogTerm 用于表示新的日志写入的位置 151 | 如果这个位置位置不一致, follower会返回失败, leader 会提前这俩值, 直到找到一致的. 152 | 153 | 154 | 155 | 156 | ## 参考资料 157 | 158 | [1] https://raft.github.io/ raft 动画 159 | 160 | [2] https://github.com/maemual/raft-zh_cn/blob/master/raft-zh_cn.md raft 中文论文 161 | 162 | [3] https://zhuanlan.zhihu.com/p/27910576 知乎1620秒入门Raft 163 | 164 | -------------------------------------------------------------------------------- /基础算法/binary_tree.md: -------------------------------------------------------------------------------- 1 | # 非递归便利 2 | 3 | ## 前序 4 | 5 | 最好想 不多解释 6 | 7 | ```python 8 | class Solution: 9 | def preorderTraversal(self, root: TreeNode) -> List[int]: 10 | if not root: 11 | return [] 12 | s = list() 13 | s.append(root) 14 | res = [] 15 | while s: 16 | node = s.pop() 17 | res.append(node.val) 18 | if node.right: 19 | s.append(node.right) 20 | if node.left: 21 | s.append(node.left) 22 | return res 23 | 24 | 25 | ``` 26 | 27 | ## 中序 28 | 29 | 一个栈 一只压 left, 没了 弹出 记录, 压 right 30 | 31 | ```python 32 | class Solution: 33 | def inorderTraversal(self, root: TreeNode) -> List[int]: 34 | s = list() 35 | cur = root 36 | res = [] 37 | while cur: 38 | s.append(cur) 39 | if cur.left: 40 | cur = cur.left 41 | else: 42 | while s: 43 | node = s.pop() 44 | res.append(node.val) 45 | cur = node.right 46 | if node.right: 47 | break 48 | 49 | return res 50 | ``` 51 | 52 | ## 后序 53 | 54 | 按照 根-右-左 遍历 然后反方向 55 | 56 | ``` 57 | class Solution: 58 | def postorderTraversal(self, root: TreeNode) -> List[int]: 59 | s1 = list() 60 | s2 = list() 61 | res = list() 62 | if not root: 63 | return [] 64 | s1.append(root) 65 | while s1: 66 | node = s1.pop() 67 | s2.append(node) 68 | if node.left: 69 | s1.append(node.left) 70 | if node.right: 71 | s1.append(node.right) 72 | 73 | while s2: 74 | node = s2.pop() 75 | res.append(node.val) 76 | return res 77 | ``` 78 | 79 | ## 按层 80 | 81 | 利用特性 遍历完上一行最右的时候的, next_last 一定是下一行最右的 82 | 83 | ``` 84 | class Solution: 85 | def levelOrderBottom(self, root: TreeNode) -> List[List[int]]: 86 | q = Queue() 87 | last = root 88 | res = list() 89 | tmp = list() 90 | if not root: 91 | return [] 92 | q.put(root) 93 | next_last = root 94 | while not q.empty(): 95 | node = q.get() 96 | tmp.append(node.val) 97 | if node.left: 98 | q.put(node.left) 99 | next_last = node.left 100 | if node.right: 101 | q.put(node.right) 102 | next_last = node.right 103 | if node == last: 104 | # 当前行最后一个节点 105 | last = next_last 106 | res.append(list(tmp)) 107 | tmp.clear() 108 | return res[::-1] 109 | ``` 110 | 111 | ## Z 字遍历二叉树 112 | 113 | ``` 114 | class Solution: 115 | def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]: 116 | stacks = [list(), list()] 117 | current_stack = 0 118 | next_stack = 1 119 | stacks[current_stack].append(root) 120 | tmp = list() 121 | res = list() 122 | while stacks[current_stack]: 123 | node = stacks[current_stack].pop() 124 | if node: 125 | tmp.append(node.val) 126 | if next_stack == 1: 127 | stacks[next_stack].append(node.left) 128 | stacks[next_stack].append(node.right) 129 | else: 130 | stacks[next_stack].append(node.right) 131 | stacks[next_stack].append(node.left) 132 | if not stacks[current_stack]: 133 | # 为空反转 134 | if tmp: 135 | res.append(list(tmp)) 136 | tmp.clear() 137 | current_stack, next_stack = next_stack, current_stack 138 | return res 139 | ``` 140 | -------------------------------------------------------------------------------- /基础算法/heap.py: -------------------------------------------------------------------------------- 1 | from functools import cmp_to_key 2 | import random 3 | 4 | 5 | class Headq: 6 | def __init__(self, max_size=-1, key=None, revser=False): 7 | if key is None: 8 | def key(item): return item 9 | self._key = key 10 | self._data = [] 11 | self._max_size = max_size 12 | self._op = 1 13 | if revser: 14 | self._op = 0 15 | 16 | self._op_table = (lambda a, b: self._key(a) > self._key( 17 | b), lambda a, b: self._key(a) < self._key(b)) 18 | 19 | @staticmethod 20 | def _get_left(i): 21 | return 2 * i + 1 22 | 23 | @staticmethod 24 | def _get_right(i): 25 | return 2 * i + 2 26 | 27 | @staticmethod 28 | def _get_parent(i): 29 | return (i - 1) // 2 30 | 31 | def _percolate_up(self, i): 32 | 33 | while self._get_parent(i) >= 0: 34 | parent = self._get_parent(i) 35 | if self._op_table[self._op](self._data[parent], self._data[i]): 36 | break 37 | else: 38 | # 交换位置 39 | self._data[parent], self._data[i] = self._data[i], self._data[parent] 40 | i = parent 41 | return i 42 | 43 | def _percolate_down(self, i): 44 | while self._get_left(i) < len(self._data): 45 | left_idx = self._get_left(i) 46 | swap_idx = left_idx 47 | # 有左孩子 48 | if not self._get_right(i) >= len(self._data): 49 | right_idx = self._get_right(i) 50 | if self._op_table[self._op](self._data[right_idx], self._data[left_idx]): 51 | swap_idx = right_idx 52 | 53 | if self._op_table[self._op](self._data[swap_idx], self._data[i]): 54 | self._data[swap_idx], self._data[i] = self._data[i], self._data[swap_idx] 55 | i = swap_idx 56 | else: 57 | break 58 | return i 59 | 60 | def push(self, e): 61 | if self._max_size != -1: 62 | if len(self._data) >= self._max_size: 63 | self.pop() 64 | self._data.append(e) 65 | self._percolate_up(len(self._data) - 1) 66 | 67 | def pop(self): 68 | e = self.top() 69 | self._data[0], self._data[len( 70 | self._data) - 1] = self._data[len(self._data) - 1], self._data[0] 71 | self._data.pop() 72 | self._percolate_down(0) 73 | return e 74 | 75 | def top(self): 76 | return self._data[0] 77 | 78 | def heapfiy(self, data): 79 | """ 80 | 直接根据data建立堆 81 | :param data: 82 | :return: 83 | """ 84 | self._data = data[:] 85 | for i in range(len(self._data)-1, -1, -1): 86 | self._percolate_down(i) 87 | 88 | # 测试 1 89 | h = Headq() 90 | 91 | 92 | l = [random.randint(1, 100) for j in range(10)] 93 | 94 | print(l) 95 | 96 | for i in l: 97 | h.push(i) 98 | 99 | res = [] 100 | for j in l: 101 | res.append(h.pop()) 102 | print(res) 103 | 104 | 105 | h.heapfiy(l) 106 | res = [] 107 | for j in l: 108 | res.append(h.pop()) 109 | print(res) -------------------------------------------------------------------------------- /基础算法/sort.md: -------------------------------------------------------------------------------- 1 | # 冒泡排序 2 | 3 | ```python 4 | class BubbleSort: 5 | def bubbleSort(self, A, n): 6 | # write code here 7 | for i in range(n): 8 | for j in range(n-i-1): 9 | if A[j] > A[j+1]: 10 | A[j], A[j+1] = A[j+1], A[j] 11 | return A 12 | ``` 13 | 14 | # 选择排序 15 | 16 | ```python 17 | class SelectionSort: 18 | def selectionSort(self, A, n): 19 | # write code here 20 | for i in range(n): 21 | for j in range(i+1,n): 22 | if A[j] < A[i]: 23 | A[i], A[j] = A[j], A[i] 24 | return A 25 | ``` 26 | 27 | # 插入排序 28 | 29 | ```python 30 | class InsertionSort: 31 | def insertionSort(self, A, n): 32 | # write code here 33 | for i in range(1,n): 34 | for j in range(0,i): 35 | if A[i-j] < A[i-j-1]: 36 | A[i-j], A[i-j-1] = A[i-j-1], A[i-j] 37 | return A 38 | ``` 39 | 40 | # 归并 41 | 42 | ```python 43 | class MergeSort: 44 | def mergeSort(self, A, n): 45 | # write code here 46 | def merge_sort(A): 47 | l = len(A) 48 | if l == 1: 49 | return A 50 | a = merge_sort(A[:l//2]) 51 | b = merge_sort(A[l//2:]) 52 | res = [] 53 | a_idx = 0 54 | b_idx = 0 55 | while a_idx < len(a) and b_idx < len(b): 56 | if a[a_idx] > b[b_idx]: 57 | res.append(b[b_idx]) 58 | b_idx = b_idx + 1 59 | else: 60 | res.append(a[a_idx]) 61 | a_idx = a_idx + 1 62 | res.extend(a[a_idx:]) 63 | res.extend(b[b_idx:]) 64 | return res 65 | return merge_sort(A) 66 | ``` 67 | 68 | # 快速排序 69 | 70 | ```python 71 | def partion(A, low, high, povit): 72 | A[high], A[povit] = A[povit], A[high] 73 | start = low 74 | for i in range(low, high): 75 | if A[i] <= A[high]: 76 | A[i], A[start] = A[start],A[i] 77 | start = start + 1 78 | A[start], A[high] = A[high], A[start] 79 | return start 80 | 81 | def quick_sort(A, low, high): 82 | if low < high: 83 | p = partion(A,low, high, (low+high)//2) 84 | quick_sort(A, low, p-1) 85 | quick_sort(A, p+1, high) 86 | ``` 87 | -------------------------------------------------------------------------------- /基础算法/二分法.md: -------------------------------------------------------------------------------- 1 | ## 二分法速记 2 | 3 | 基础写法 找到了大于等于的左边界 4 | 5 | ```c++ 6 | int binarySearch(std::vector nums, int target) { 7 | int left = 0; 8 | int right = nums.size(); 9 | while (left < right>) { 10 | mid = (left + right) / 2; 11 | if (nums[mid] < target>){ 12 | left = mid + 1; 13 | } else { 14 | right = mid; 15 | } 16 | } 17 | return left; 18 | } 19 | ``` 20 | 21 | 找到了大于等于的右边界 22 | ```c++ 23 | int binarySearch(std::vector nums, int target) { 24 | int left = 0; 25 | int right = nums.size(); 26 | while (left < right>) { 27 | mid = (left + right) / 2; 28 | if (nums[mid] <= target>){ 29 | left = mid + 1; 30 | } else { 31 | right = mid; 32 | } 33 | } 34 | return left - 1; 35 | } 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /基础算法/字符串/kmp.py: -------------------------------------------------------------------------------- 1 | 2 | def get_next(s2): 3 | if len(s2) == 1: 4 | return [-1] 5 | next_arr = [0 for i in s2] 6 | next_arr[0] = -1 7 | i = 2 8 | cn = 0 9 | while i 0: 15 | cn = next_arr[cn] 16 | else: 17 | next_arr[i] = 0 18 | i = i + 1 19 | return next_arr 20 | 21 | 22 | def get_match(s1, s2): 23 | if ( (not s1) or (not s2)): 24 | return -1 25 | next_arr = get_next(s2) 26 | s1_idx = 0 27 | s2_idx = 0 28 | while s1_idx < len(s1) and s2_idx < len(s2): 29 | if s1[s1_idx ] == s2[s2_idx] : 30 | s1_idx = s1_idx + 1 31 | s2_idx = s2_idx + 1 32 | elif next_arr[s2_idx] == -1: 33 | s1_idx = s1_idx + 1 34 | else: 35 | s2_idx = next_arr[s2_idx] 36 | 37 | return s1_idx - s2_idx if s2_idx == len(s2) else -1 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /杂谈/你会变成你的人设.md: -------------------------------------------------------------------------------- 1 | # 你会变成你的人设 2 | 3 | 六年前, 如果有个人穿越过来, 和我说, 你会变成一个和异性交流困难, 每天唯一的乐趣就是写代码搞技术, 唯一的成就也是写代码搞技术 和一个**技术宅一样, 我一定呵呵一笑然后给他一拳, 告诉他, 劳资那么喜欢小姑娘, 游戏一打饭都不想吃, 那种只专注于写代码啥都不想干的人, 只在 xx 大神的访谈里看过, 活着心中的传说里. 我死都不可能成为这样的人. 然而.... 4 | 5 | 今天下午写完代码回来, 宿舍只有我一个人, 喝了一罐啤酒, 想想本来是找完工作准备放松的, 结果每天的日常成了翻了翻微信, 约不出来人, 看了看美团, 没人一起玩, 看剧没意思, 游戏费时间, 只能写代码, 一写一整天. 看看舍友A, 都计划好了考完研和那个妹子出去玩. 又看了看舍友B, 哦, 他已经和女朋友出去玩了...... 顿时觉得人生凄凉异常, 想想自己的人生做错了什么, 或许学编程就是个错误. 恍惚间, 突然想起了自己高中的时候. 6 | 7 | 高中的时候自己, 明白自己有个特别大的问题---所谓的三分钟热度. 这个导致了自己没有什么一技之长, 学画画, 画了俩笔丑的自己都看不下去, 只能放弃, 弹吉他又手疼, F和弦按不出来只能放弃..折腾了半天, 啥都不会, 学习也一般. 所以当我开始学编程的时候, 我也觉得自己应该很快就会放弃, 那是候常常看到一些帖子, 讲的是一些大神还未出名的时候, 就醉心于自己热爱的代码, 大学期间每天待在机房抱着电脑写代码, 不怎么参与社交, 甚至连个女朋友都没, 觉得都没有写代码有意思, 最后做出了什么什么样的成就,让别人觉得他很厉害. 我就很羡慕这种人, 感觉他们就像 武侠小说里的扫地僧, 身上透露的专注的气息, 有股神秘的芳香. 但是, 当时三分钟热度严重的自己, 应该是绝无可能成为这样的人, 即便如此, 还是会看很多帖子去刻意的模仿他们的行为, 比如: 8 | 他们会随身抱着一本编程书, 一有时间就投入进去. 那好了, 我也随身带一本, 虽然众所周知编程书沉如砖石, 我还是会每天书包里背上, 在感受知识的重量的同事, 一有时间就**假装**投入进去. 9 | 10 | 还比如, 他们会随身带电脑写代码, 那好了, 我也随身带电脑写代码, 我可能是我们高中唯一个在大家都上课偷玩手机的年级,我打开电脑偷偷写代码的人. 11 | 12 | 其实, 这些行为, 大部分都没有什么实际的效果, 看书没看进去, 代码没写明白,技术还是菜的要死, 但是给了周围人和自己一个, 我看起来像一个编程大佬的错觉, 直到 6 年后的今天, 我才知道一个词: 人设. 13 | 14 | 对,没得问题, 我就是在给自己立一个编程大佬的人设, 但是这真的是一个不好的事情吗. 15 | 16 | 6 年后的今天, 我拿到了某个之前不敢想的厂的顶薪offer, 懂了很多之前以为自己这辈子都不会理解的技术, 负责了 N 个项目, 和周围一群热爱技术的小伙伴天天张口闭口高并发, 编译器谈笑风声, 周围也越来越多的人认为我技术牛逼, 并且还找不到女朋友的时候, 我突然发现, 我好像慢慢变成了我之前给自己立的人设. 17 | 18 | 回过头来, 想想这几年的时间, 我之前为了装样子每天看书, 结果后来真的看进去了(当然算法导论还是没看进去). 之前为了装模做样写代码, 结果不知不觉代码量就上去了, 到现在几乎全年无休每天都在 coding. 为了维护别人心中编程技术好的情况下, 我会认真的研究大家遇到的各种问题, 结果最后真的可以快速解决别人遇到的问题, 我之前看大佬的博客, 来解决自己的问题, 慢慢的自己也可以输出内容帮别人解决问题. 享受正反馈的同时, 会更小心的维护自己的人设. 后来已经分不清楚这是人设, 还是自己本该这样. 19 | 20 | 前些日子, 和几个技术牛逼人也超好的大佬聊天时候, 突然想到为什么感觉大家搞技术的总都是习惯性的装B的同时还小心翼翼的自黑, 突然想到了, 也许大家也在以为自己是在维护人设吧, 我们都是一样的, -------------------------------------------------------------------------------- /杂谈/吐槽一下大学CS教育.md: -------------------------------------------------------------------------------- 1 | # 吐槽一下大学 CS 教育 2 | 3 | 事情是这样的, 最近总是有人问: 我该怎么入门计算机? 4 | 5 | 这个让我想起了一些自己的经历, 当初也是入门编程, 于是上知乎和各大论坛上搜: 怎么入门计算机? 结果回答的也是五花八门: 6 | 7 | 有的说, 数学是计算机的灵魂, 学计算机得数学好, 先从高数离散看起. 8 | 9 | 有的说, 所有语言最后都是汇编的, 要打基础, 所以先从汇编学起. 10 | 11 | 还有的, 直接说, 不用多想, 直接看 大理石系列封面的书!!! 12 | 13 | ![传说中的大理石](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200103121942.png) 14 | 15 | 他们给的路线这叫个难啊, 我网上看这些资料, 对码农们油然而生的敬佩, 这入门也太难了, 我是不是智商不够. 16 | 17 | 后来时过境迁, 我靠着自己的办法可以说入门了编程, 在这个行业的同龄人里做的还算不错, 返回头看这些 "大佬" 们给的答案, 忍不住想提刀砍他们: 18 | 19 | **你们不装X能死吗? 你们自己看这些能入门吗?** 20 | 21 | 这些大佬们, 给出一套理论上听起来很合理, 很专业, 很高大上的路线来显得自己很专业很牛X. 然而这个路线, 从根本上讲就是**反人性**的, **反学习规律的**!!! 除非你是神仙, 不是人, 否则根本不可能走得了他给的路线. 22 | 23 | ## 学习的人性 24 | 25 | 其实大学的 cs 教育的路线, 和知乎大佬给的回答也很相似, 都是反人性的. 很多老师听到你在做应用, 看不起你. 听到你在学习python, 看不起你...... 和知乎大佬的画风如出一辙. 26 | 27 | 仔细回想一下, 大部分人学习的核心无非俩点: **重复** 和 **正反馈**, 28 | 29 | 如果不是天才, 很少有人在第一次学习某个知识的时候, 就掌握他. 不断的重复, 让陌生的概念标的收悉, 不断的收悉让知识形成框架, 框架可以让你快速的收悉新的知识. 然而, 重复是枯燥的, 是反人性的, 能让人坚持下来重复, 靠的就是正反馈. 30 | 31 | 所谓的正反馈, 可以归结成: 能让我们做到以前做不到的事情, 和解决自己一直困惑的问题. 32 | 33 | 然而, 回忆大学的教育, 连重复做的都有问题更别说正反馈了. 34 | 35 | 很多重要的课, 只有一次让大家因为考试驱动学习的机会, 比如计网, os 除了当时学的时候考试的时候大家会多看看, 后续课程中对其的重复十分的少, 让很多人产生了基础课没有用的错觉. 36 | 37 | 38 | 另一个是大家对基础知识学习的兴趣也比较低, 理想的途径应该是: 39 | 40 | 1. 先能学一些快速出来成果的东西, 让人可以用保持兴趣(**正反馈**), 并且在学习过程中留下一些问题. 41 | 42 | 2. 带着问题, 去学习难以下咽的基础, 因为之前在做好上手的东西过程中用哪个了这些基础知识的应用, 对基础产生了熟悉的感觉(**重复**), 并且在学习过程解决了之前遗留的问题(**正反馈**). 43 | 44 | 3. 学完基础后, 可以把之前做的成果往高级做(**正反馈**), 并且产生新的疑问, 再回头看之前遗漏的基础(**重复**) 45 | 46 | 47 | 这样的途径才是合理的, 符合人性的, 48 | 49 | 事实上我当初高中入门编程的时候, 连堆栈都分不清楚, 就用 c++写游戏, 最后磕磕碰碰写出了一个小手游. 虽然拙劣, 但是那个做出东西快乐让我坚持学了计算机. 50 | 51 | 在大学的时候, 在做东西在不断的发现自己的不足的过程中, 来回好几遍的基础. 基础的书, 每一次读都有新的体会, 远远不是一个学期 一门课的就能掌握好的程度. 不断的时间发现问题才能掌握他. 52 | 53 | 所以当我给别人推荐入门路线的时候, 一定是: **先学能动手做的**. 54 | 55 | 虽然刚开始做的东西很垃圾, 很拙劣, 没关系, 动手做出来, 享受解决问题和做出成果的快乐. 带着快乐去攻克基础! 56 | 57 | 不要管别人的优越感, 学东西是为了享受刺激大脑的正反馈, 不是用来秀优越. 自己学会才是硬道理. 58 | 59 | 60 | 链接符给大家写的春招指南, 也可以结合自身情况用来入门: 61 | 62 | https://zhuanlan.zhihu.com/p/98778982 63 | -------------------------------------------------------------------------------- /杂谈/家长式政府的公信力和开放意识的觉醒.md: -------------------------------------------------------------------------------- 1 | 2 | ## 家长模式的危机和公民开放意识的觉醒 3 | 4 | > 思考一下, 疫情过后, 我们社会会有什么么变化? 5 | 6 | 7 | 武汉肺炎是 2020 年度关注最大的公共事件, 前线的医护, 物资情况牵动着所有人的心. 然而 当地政府团队在关注之下, 却暴露出了诸多问题, 引发舆论的大面积反弹. 8 | 9 | 我们可以简单整理一下造成舆论反弹的事件: 10 | 11 | 1. 武汉 8 君子谣言事件 12 | 13 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200204113117.png) 14 | 15 | 官方在未公布任何能证明他们所说为谣言的证据情况下, 大家出于 **信任**, 相信这是谣言, 舆论谴责这些造谣的人. 结果后来的事情大家都懂, wh 封城, 扩散全国. 16 | 17 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200204113442.png) 18 | 19 | 事后最高法平反, 其中之一李医生感染, 舆论大面积反弹. 20 | 21 | 2. 物资匮乏问题. 22 | 23 | 事件发生后, 大量人开始向 武汉捐赠物资, 与此同时, 当地要求所有物资捐赠给某会, 24 | 25 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200204113833.png) 26 | 27 | 在某会**不公开**的前提下, 人们发现物资迟迟到不了一线工作人员手中, 甚至一线不得不绕考当地直接向社会求助. 28 | 29 | 随后央视采访被掐断, 公示材料错误, 车牌等问题一一曝光. 30 | 31 | 人们发现高薪样的工作人员毫无能力规范, 不干事情, 占得权利不拉屎, 引发第二次反弹. 32 | 33 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200204114225.png) 34 | 35 | 随后阿里和国家开始直接绕开当地进行物资分配. 当地物资分配相关的机构再无法得到**信任**. 36 | 谴责某会成为舆论主流. 37 | 38 | 39 | 3. 官僚团队**水平低下** 40 | 41 | 在新闻发布会中, 人们发现当地一把手二把手, 口罩带错, 这个很容易让大家怀疑这些人有没有去过一线. 42 | 43 | 之后人们又发现, 一个文科生, 毫无公共医疗背景, 居然能成为当地卫健委主任, 在公共卫生领域替大家做决策. 并且一问三不知. 44 | 45 | 各地城市, 武汉归乡个人信息大规模泄漏, 基层公务员法律意识极其淡薄. 46 | 47 | 武汉是一线城市, 政治官僚话语权如此之高,水平又是如此低下, 这立刻导致了舆论对 官僚团队素质的 **不信任**. 48 | 49 | 50 | 4. 权威机构的不负责任 51 | 52 | 随后, 人民日报 ,两地药物所 这三家权威机构,发布双黄连的消息, 53 | 54 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200204115151.png) 55 | 56 | 引发药物学领域从事着, 科普大V, 受过良好科学的人的大面积辟谣. 57 | 人们对权威的**不信任**开始产生. 58 | 59 | 随后, 某所被爆出美女所长一事, 不信任彻底爆发 60 | 61 | .... 62 | 63 | 64 | 回顾以上事件, 我们发现了一个问题, 那就是现在的舆论完全就是**信任**危机. 65 | 66 | 甚至从某件事讲, 这个危机要比疫情本身影响更大. 这要从当下家长式政府说起. 67 | 68 | 69 | ## 家长式的危机 70 | 71 | 我国目前政府大体而言是家长式的, 家长式的定义: 72 | 73 | ``` 74 | 家长式领导(英语:paternalism 或 parentalism,又称父爱主义、父权主义、温情主义、家长式作风、家长式管治)是一种行为,由个人、组织、或国家,图以替一些人或群体的好处设想,去限制该些人或群体的自由或自主权。[1] 家长作风也可以意味着该行为是对抗或忽视一个人的意志,或者该行为表现出优越感的态度。[2] 75 | 76 | 通常指的是一个指导者(“父亲”)代表其他人(“妻子”或“儿子”)替他们作出“为他们好的”决策,即便这样的决策违背他们的愿望。简而言之,是“管你,是为你好”的思维,是旧式父权体制遗留下来的作风[来源请求]。 77 | 78 | ``` 79 | 80 | 这个我们有很多体会, 就不细说了. 81 | 82 | 83 | 这个模式听起来不好,然而其实之前的舆论主流是认可这种模式的, 常见的类似 "阿中哥哥", "厉害了我的国", "xx 这么做考虑的不比你多?", "xx 里面有高人" 84 | 85 | 这个感觉很像家长和孩子, 父亲总会说, 我是为你好, 我吃的盐比你吃的米多, 你不听话就是不孝不乖, 你不要质疑我的决策. 86 | 87 | 然而, 这次事件中, 这种模式受到了危机: 88 | 89 | 1. 人们发现, 你说的谣言不一定是谣言, 对我们有害的东西可能在救我. 你们为了保全某些利益, **出发点不一定在对我好**. 90 | 91 | 2. 人们发现, 你们团队的**素质**未必有多高, wh 是一线,是国家中心, 是这个水平, 我们三线小城市呢?靠抽签靠运气赌自己所在地团队素质高? 92 | 93 | 94 | 不仅如此, 最要命的是, 你们决策的失误, 不是你们的事情, 是全社会的事情, 一个决策失误是全国人在买单. 95 | 96 | 无数人为了你们决策付出生命. 97 | 98 | 整个社会为了你们付出经济代价. 99 | 100 | 人们不想看感动了, 人们没办法信任你们了, 你们决策和人们息息相关, 人们开始要求: 101 | 102 | 你做出这个决策的依据, 可不可以给我们看一下. 103 | 104 | 105 | 于是, 舆论的主流成为了, 对公开的渴求, 红十字不能不透明, 请公开; 武汉医院修建, 请公开; 106 | 疫情进展, 请公开.... 舆论, 带节奏,对社会有影响的谣言, 都是倒闭公开的推力. 107 | 108 | 我们不只见证团结, 不只见证灾难, 109 | 110 | **也在见证家长式的瓦解, 公开的觉醒和进步** 111 | -------------------------------------------------------------------------------- /杂谈/没有优秀, 也没必要优秀.md: -------------------------------------------------------------------------------- 1 | # 没有优秀 也没必要优秀 2 | 3 | 4 | > 每个青春期的失败少年想过屌丝逆袭高富帅, 让女神后悔的戏码, 殊不知, 这个想法就是你失败的开始, 也是遗憾的开始 5 | 6 | 故事发生在高一, 他有个朋友, 管他叫萌萌好了, 萌萌是一个可爱的男孩子,他有个小女神, 不过小女神换了三个男朋友都没有考虑萌萌. 和正常的青春期男孩子一样, 萌萌也开始反思为什么, 当时流行的一个理论: 只要你变优秀了, 什么都会有了. 7 | 8 | 当时的萌萌开始也想开始变优秀, 于是他读了很多书, 主要的收获是俩种观点: 9 | 10 | 一个是所谓的 新古典主义经济学 和 进化心理学, 主要是来源是 曼昆的 <经济学原理> , 薛兆丰的 <经济学通识>, 理查德·道金斯的<自私的基因>. 学了什么不重要, 重要的是这些观点让他形成了有一个用市场和博弈理解恋爱的模型: 11 | 12 | 1. **恋爱首先是一个市场, 市场就存在需求, 满足女生的需求才会有价值. 而大多女生需要的不是一个工具人的所谓关心, 她需要的是来自基因内部的吸引, 如果你做的事情不满足女生的需求, 不好意思, 你就算再舔都没有用.** 所以舔狗不得好死 13 | 14 | 2. 舔狗不值得同情, 他能喜欢的普遍是价值比自己高的人, 出于自己的需求, 一些抱着希望用一些不值钱关心来获得他想要的东西(满足, sex, 成就), 简直蠢. 15 | 16 | 3. 既然是市场, 就有有能满足大部分的需求, 就会有高价格, 而从自私的基因里可以明白, 女生刻在基因的需求是安全感. 能满足这点你的价格会变高. 17 | 18 | 这些观点从好的方面来看, 让他明白了他为什么追不到女神, 告别了当一个可悲舔狗的人. 然而另一方面, 也给他埋下了不关心人只关心市场的想法. 19 | 20 | 第二个收获当然是找到了自己的职业, 就是发现对于当时处于底层工薪阶级家庭的 没任何关系 智商普通看 不懂数学的他, 唯一的逆袭道路就是 去互联网**写代码**. 而且写代码是真的挣钱. 21 | 22 | 抱着这俩个想法, 萌萌开始写代码, 并且努力学习, 如愿以偿考入了一个帝都 211学了计算机. 这时候, 萌萌喜欢上了一个和他一起到帝都的女孩子. 23 | 24 | 那是一个可爱的女孩子, 除了不喜欢萌萌, 简直哪里都好. 他心理也清楚, 自己能喜欢这个妹子, 是因为妹子价值高, 没什么特别的, 以后还会有价值高的妹子让自己喜欢, 现在重要的是提升自己, 让自己变优秀. 大一的时候, 他找到了第一个写代码小公司的实习, 妹子开始不和他说话了; 大二的时候, 他开始做外包一个月稳定几千的收入,比他的三线城市工薪族挣得都多; 妹子却约不出来了;大三的时候, 他毕业拿了 BAT 的 offer, 妹子, 妹子已经不回消息了..萌萌把妹子删了, 他也没认识他以为能遇到的高价值妹子. 25 | 26 | 有个逻辑, 抱着和萌萌相同想法用于没相同, 之所以自己一直抱着变优秀想法, 是因为现在失败了. 太失败了, 所以迫切的想要优秀. 然而, 优秀没有尽头, 失败缺永恒存在, 你一直抱着变优秀的想法, 你就一直失败. 没人喜欢失败的人, 你自己都觉得自己失败, 你怎么不让妹子觉得你失败?? 妹子为什么会喜欢一个失败的人? 27 | 28 | 恋爱也不是完全的市场, 基因的价值也不完全是价格, 理论是没错的. 但是遗憾不会因为理论正确而消失, 如果萌萌可以和妹子一起玩玩农药, 节约一些写代码的时间看看妹子喜欢的剧, 再花点时间享受一下生活, 会不会少一点焦虑, 会不会生活会好一点, 会不会不那么遗憾. 29 | 30 | 目的性错了, 一切都会错, 目的是让享受生活, 还是拜托失败, 是一个要思考的事情. 不是活在 offer 的焦虑, 不活在 白菜和 sp 的对比焦虑, 不活在大厂小厂的光环的焦虑, 多看看自己的生活,, 建设生活, 享受生活, 多看看身边的人, 他们不是市场的商品, 不是价签上的数字, 他们是你的人生. 关系生活, 关心身边的人, 少点遗憾吧~ -------------------------------------------------------------------------------- /毕设.md: -------------------------------------------------------------------------------- 1 | # 基于 P2P 技术的客户端长连接流量分发技术 2 | 3 | 主要用于降低直播等长连接下的大流量分发服务时服务器的压力, 节约服务器带宽. 4 | 5 | ## 协议设计 6 | 7 | 协议包括三个角色: 8 | 9 | * S: 服务器, 掌握所有的节点信息 10 | * C (src;to1.to2): 负责接收 分发的客户端节点 C (x) 表示链接 x 11 | 12 | 13 | 协议流程: 14 | 15 | 整体树形结构, 16 | 17 | 1. 每个节点掌握所有下级节点的信息, 包括负载情况等. 整体呈树形状, 节点汇总的过程中, 计算最佳节点列表. 每个树有俩个主节点 18 | 19 | 2. 链接的时候, 根节点直接转发到最佳节点, 弱建立链接失败, 从最佳列表中依次选取 20 | 21 | 3. 断开或者链接建立时, 立刻向上层节点发送拓扑更新命令 22 | 23 | 24 | 25 | 26 | 27 | v1: 28 | 29 | 核心要点: 30 | 31 | 1. 标识唯一的资源 32 | 2. 所有进行分发的节点(包括 S) 记录该资源下 C 节点情况 包括负载情况等信息, 所有 C节点同步此消息 33 | 3. 挑选最合适的节点 34 | 3. 检测当前 M的存活状态 35 | 4. M挂掉后 新的 M 产生的策略 36 | 37 | 38 | 39 | 40 | ## 协议细节 41 | 42 | MSG\r\n\r\n 43 | 44 | ### MSG 45 | 46 | CONNECT [RESOURCE_ID] # 请求建立链接 资源编号 47 | 48 | REDIRECT [LEN] [IP:PORT] [...] # 重定向 目的数量 目的地址1 目的地址2 ... 49 | 50 | OK [DATA_SRC_IP] [DATA_SRC_PORT] # 链接成功 51 | 52 | PING # 心跳 53 | 54 | PONG # 回应 55 | 56 | TOPOLOGY-SYNC root[c1[child] c2[child] ...] # 拓扑创建 同步拓扑信息 57 | 58 | ##### 节点属性 59 | IP:PORT:BLANCE:RNAK 60 | 61 | TOPOLOGY-OP [OP](DELETE, ADD, UPDATE) [PATH_LEN] [p1] .... [node] # 操作 路径 每经过一层就修改, node 操作的节点 62 | 63 | ATTR [SET] [KEY] [TYPE] [VALUE] # 属性 64 | 65 | ERROR CODE MSG 66 | 67 | ## 接口 68 | 69 | 70 | 71 | D2SDK.Connect(server, port , resource_id)); // 隐藏 72 | 73 | D2SDK.OnConnect((D2SDKConn,DataSocket)=>{}) 74 | 75 | D2SDK.OnDataRead((conn,data)=>{}) 76 | 77 | D2SDK.Wirte(); 78 | 79 | D2SDK.DisConnect(); 80 | 81 | ## 内部过程 82 | 83 | ### 链接 84 | 85 | C 86 | 87 | ``` 88 | D2SDK.Connect(server) 89 | -> 和服务器建立 控制 socket 链接 90 | -> 根据控制指令的回报 和 正确的目的服务器链接 91 | -> 返回响应 92 | -> 建立数据 socket 93 | -> 触发 OnCennect 回调 94 | 95 | ``` 96 | 97 | S 98 | 99 | ``` 100 | 内部逻辑 101 | 102 | 根据当前最优列表进行选择 103 | 104 | 发送转发代码 105 | 106 | 链接成功之后 107 | 108 | 返回 109 | ``` 110 | 111 | 112 | ### 维护 113 | 114 | 当 C 链接的断开后 链接 BACKUP, 同一树的兄弟节点的 BACKUP 是一个 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /秋招/岗位选择.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # 技术岗方向选择 11 | 12 | 算法?后台开发?客户端?测开?选哪个? 13 | 14 | ## 算法 15 | 16 | 先放结论, 劝退一切AI算法岗. 特别是 cv 和 nlp. 17 | 18 | 985 硕士, 顶会, 大厂实习. 如果你没有其中俩个,建议换个方向. 19 | 20 | 算法岗如此内卷原因在于, 各个厂真正需求的是计算机基础和开发能力好的并有落地业务的 **算法开发**, 而不是整体搭模型复现 paper 的 **算法研究**. 21 | 22 | 算法研究只有少数几个大厂和 AI 独角兽能养的起,需要量很少的, 最顶尖的那部分供给已经足够. 23 | 24 | 而算法开发类, 包括大数据技术栈, 音视频, 图形, 这些因为供给不足反到要好找一些. 不过相对的也更要求对特定业务领域的知识和足够好的计算机基础. 25 | 26 | 如果你不满足我说的条件还头铁去投AI算法,那只能祝你好运了,这个上岸真的是要运气. 27 | 28 | ## 后台开发 29 | 30 | 相对而言,如果你足够优秀, 后台开发岗要好的多. 你背景优秀到想投算法岗的时候, 不妨试试开发. 保证你会成为 offer 收割机, 大厂 sp, ssp 的无情渣男. 31 | 32 | 因为后台开发需求量大, 同时投的人最多. 但是优秀的人永远是少的, 对大厂来说合格的后台开发其实是供小于求的. 只要你 **计算机基础** 和 **刷题** 的够了, 再加上 33 | 一个不拉胯的背景. 就可以超过绝大多数人获得大厂的青睐. 我本人也是后台开发. 34 | 35 | 36 | ## 客户端 37 | 38 | 这时,要隆重推出秋招技术岗上岸神器,大厂 offer 捡漏王 ---- 客户端开发. 客户端开发需求量不小于后台开发, 但是供给量远远小于后台开发. 主要原因: 39 | 40 | **学校不教.** 41 | 42 | 这个很重要. 一般自己学客户端的人,容易只沉迷于安卓 ios 的表面技术, 忽略了最最最重要的计算机基础. 43 | 44 | 而对大厂来说, 计算机基础才是核心竞争力. 45 | 46 | 基础好的人都去面后台开发了, 自己学的人基础又大多不好(主要原因是数量少, 能自学还自学客户端的是少数) 47 | 48 | 所以导致了这个岗位非常容易上岸. 类似字节之类的公司,甚至只要你基础好无需客户端经验都能上岸. 49 | 50 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200514110819.png) 51 | 52 | 这就是真正的上岸神器, 所以兄弟, 如果你不是那么优秀. 那么可以好好打打基础, 刷刷题, 然后看一些客户端提高的东西, 比如客户端 native 开发,类似 安卓里用c++写高性能组件. 53 | 保证轻松上岸大厂冲击 sp. 54 | 55 | ## 测开 56 | 57 | 同为上岸神器不过发展弱于客户端. 而且弄不好会干一堆杂活,有一点风险, 如果准备时间不够了可以考虑. 58 | 59 | ## 总结 60 | 61 | 所有岗位最重要的是计算机基础和刷题. 各位校招生一定要准备好哦. -------------------------------------------------------------------------------- /秋招/怎么写一份好看的校招简历.md: -------------------------------------------------------------------------------- 1 | # 怎么写一份好看的校招简历 2 | 3 | 春招快要到了, 各位同学有木有准备好自己的简历? 如果还木有, 这里给大家准备了一份简历编写指南, 以技术岗为例, 希望可以帮到大家~ 4 | 5 | 这里附一下我的简历 6 | 7 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200210155556.png) 8 | 9 | 随后我会慢慢讲讲我写简历的思路. 10 | 11 | 12 | ## 简历的作用 13 | 14 | 首先要明确, 简历是干什么的? 15 | 16 | 其实无外乎俩点: 17 | 18 | 1. 展示自己 19 | 2. **限制面试官的提问范围!!!** 20 | 21 | 22 | 很多人只注意到了第一点, 却忽略了第二点. 这会导致, 面试官拿到你的简历: "嗯, 感觉不错, 没想起来问啥, 随便问吧, 刚刚上厕所看了个问题, 这么优秀的人应该会", 然后结果你不会 gg. 23 | 24 | 这也是我们有时候常常感觉面试官在漫天发问的原因, 所以, 如果你也遇到了类似的情况, 请检查你的简历!! 25 | 26 | 所以, 好的简历不只要展示自己, 还要引导面试官提问, 让面试官一看到你的简历, 下意识的就问出你想让他问的东西. 并且一定不能出现自己容易被问卡住的内容!!! 27 | 28 | 要做到这点, 就要在排版和文案上下功夫了. 29 | 30 | ## 简历的排版 31 | 32 | 排版的要点有俩个: 33 | 34 | 1. 好看 35 | 2. 轻重分明! 36 | 37 | 好看是一个比较容易达到的东西, 主要是挑一个不错的模板, 并把他**填满**!!! 排版一定要经凑. 38 | 39 | 这里推荐俩个模板, 一个是我用的latex 的模板: [简历模板](https://github.com/billryan/resume) 40 | 41 | > https://github.com/billryan/resume 42 | 43 | 这个需要搭环境比较麻烦, 需要你有一点技术能力, 但是定制效果好 44 | 45 | 还有就是: 46 | 47 | [超级简历](https://www.wondercv.com/) 48 | 49 | >https://www.wondercv.com/ 50 | 51 | 也很好用. 52 | 53 | 重点是第二个, 就是轻重分明. 54 | 55 | 我们简历上的内容往往就是: 56 | 57 | 1. 基本信息 58 | 2. 学历 59 | 3. 实习 60 | 4. 竞赛奖项论文 61 | 62 | 6. 技能 63 | 5. 项目和成果 64 | 65 | 这些东西 66 | 67 | 他们需要一个主次, 不是优点的东西 一笔带过, 亮点篇幅要长. 68 | 69 | 以我的简历为例子: 70 | 71 | 首先 学历,实习,竞赛奖项论文 这几点比较特殊, 这是一些硬通货. 或者我们说**光环**, 可以扫一眼就知道你还不错, 所以一定要放在前面!!! 如果你这里有亮点那么面试官对看你剩下的简历的内容耐心会变大~ 72 | 73 | 74 | 1. 基本信息一般都是一笔带过, 能联系到你这个人就行, 这里为了联系到你是肯定会看的, 所以博客你觉得不错的话也放上来 75 | 76 | 2. 学历, 我的学历比较一般, 成绩也不太好, 所以一笔带过 77 | 78 | 3. 实习, 我的实习开始的比较早, 有倆家,公司也不错, 但做的活一般, 所以篇幅中等. 让人一眼看到对我接下来的长篇有兴趣看. 79 | 80 | 4. 竞赛只有给钱就有奖的垃圾比赛, 也没论文, 写上去纯属占地方 所以不写. 81 | 82 | 然后 就是技能和项目, 83 | 84 | 项目是我的亮点, 所以占了接近一半的篇幅, 为了不让面试官疲劳, 我还特地把项目拆分了一下, 让他的可读性更好. 85 | 86 | 我一些想要引导面试官提问的内容, 基本就在这里了. 87 | 88 | 接下来我们谈谈怎么写这些内容. 89 | 90 | ## 怎么写? 91 | 92 | ### 学历怎么写? 93 | 94 | 如果想让学校这里好看点, 学校什么的就不说了, 排名好看就把排名写上, GPA 好看就把 gpa 写上, 实在没有就把和目标岗位相关的分数好看的专业课写上. 95 | 96 | 如果你是技术岗, 千万别把团支书班长,学生会经历写上去, 浪费空间, 非技术岗可以结合目标岗位的情况来写. 97 | 98 | 99 | ### 实习怎么写? 100 | 101 | 除了给出公司, 职位等信息, 最重要的是写工作内容. 102 | 103 | 这里分俩个情况, 如果你觉得你实习可以说的多, 特别是有明确的数字的情况下, 一定要把数字写上, 节约空间的参考话术是: 104 | 105 | 负责 xxx 项目, 解决了 XXX 问题 , 达到了 (提升%多少速度/增长了多少用户) 效果 106 | 107 | 当然 , 技术岗为了节约空间, 可以只写负责的项目, 让面试官来提问, 对我来说我不太希望面试官问太多实习的内容, 因为不算特别硬核的技术, 所以写的就比较简单. 108 | 109 | ## 技能怎么写? 110 | 111 | 技能的写法, 首先有个原则, 就是不熟悉的不要写. 112 | 113 | 要明确简历上的每一个字都是有可能被问到的, 所以上面每一个字都要准备好. 114 | 115 | 其次就是句式, 这里建议的句式是: 116 | 117 | ``` 118 | 119 | 掌握 (技能名字), 掌握程度(包含知识点), 证据(做过xx 项目). 120 | 121 | ``` 122 | 123 | 举个例子 124 | 125 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200210163008.png) 126 | 127 | 比如我写的这句话, 128 | 129 | 1. 掌握 C++,点出技能名字 130 | 131 | 2. 表明掌握的程度, 里面要包含知识点, 这样做一个是增加可信度, 一个是让面试官去提问这些知识点 132 | 133 | 3. 在个人项目实际, 我接下来的项目里有个 c++ 的项目, 作为证据,增加可信度 134 | 135 | 再感觉感觉这个: 136 | 137 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200210163729.png) 138 | 139 | 核心思想, 就是增加可信度 和 引导面试官提问. 140 | 141 | 142 | ## 项目怎么写 143 | 144 | 首先, 要明确写这个项目是为了干嘛. 145 | 146 | 项目最大的用处, 是给你的技能增加证据和可信度, 所以项目的内容一定要和技能同步, 并且把里面的知识点重复, 加强对面试官的引导. 147 | 148 | 写法可以参考,如下: 149 | 150 | 首先是技术性不强的项目, 更多的是为了表面自己的 **软技能**: 151 | 152 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200210163429.png) 153 | 154 | 这里主要是一句话说清楚这个项目干了啥, 然后就是重点是强调这个项目**达到的效果**!!!! 最后有数字, 比如这里的百家. 155 | 156 | 157 | 另一种是技术性质强的项目: 158 | 159 | ![](https://gitee.com/IcyCC/PicHouse/raw/master/assests/20200210163622.png) 160 | 161 | 这里重点是引导提问, 表达了你解决项目的核心问题用到的技术. 162 | 163 | 这里也要和面试结合, 比如 提提到 io 复用, 就好好准备 io 编程相关的知识, 类似事件循环, 协程, epoll 之类的. 164 | 165 | 还有就是, 隐藏亮点, 比如, 这里写 SafeQueue 就为了让他问我实现, 我可以说我这个写的有锁的, 但是我还会无锁的, 当场写一个, 并比较优缺点, 很是加分. 166 | 167 | 168 | ## 总结 169 | 170 | 最后做个总结: 171 | 172 | 简历最重要的事情, 就是把你积累的东西展示出来, 并且用上面的知识点引导面试官提问!! 173 | 174 | 希望大家可以写出一份漂亮的简历战胜春招. 175 | 176 | -------------------------------------------------------------------------------- /秋招/秋招Q&A.md: -------------------------------------------------------------------------------- 1 | 9 | # 基本情况 10 | 11 | 我是北京林业大学大四的学生, 同时也是一个Python/Cpp 服务器端开发者, 略懂些客户端, 在秋招里, 凭借运气和一些准备 12 | 13 | # Q&A 14 | 15 | ## 看成绩or 学历吗? 你在学校成绩怎么样? 16 | 17 | 比较尴尬, 我不是一个学霸, 我上的不是一个特别好的大学, 成绩在学校里也是下游, 个人感觉面试官也不是很在意这个, 重要的还是你对你所做技术的热情要更重要一些. 18 | 19 | 20 | ## 普通本科生的收入范围? 21 | 22 | 校招薪资基本都差不多: 23 | 24 | 白菜 25-28w 25 | sp 30-36w 26 | ssp 40-60w 27 | 28 | 本科生是有可能拿到ssp的 29 | 30 | ## Q:是怎么一个流程? 31 | 32 | 7月份开始提前批, 8月份密集的投简历笔试, 9月份密集的面试, 10月分出正式的谈薪结果. 33 | 34 | ## Q: 面试比较看中什么? 35 | 36 | A: 秋招对于应届生的要求往往是相似的, 大体可以分为以下几点: 37 | 38 | 1. 经历(主要包括竞赛, 项目, 实习, 博客...) 39 | 40 | 和你的面试的知识不一样, 这些东西是没办法速成, 需要花费大量时间精力长期积累的东西, 对你简历的分数是至关重要的 41 | 42 | 2. 基础知识 43 | 44 | 主要指你学校里的那基本大砖头的掌握情况, 对于后台开发岗位or或者说是全体 计算机科学学生来说, 你的基础知识的核心就是, (网络, 操作系统, 数据库, 编程语言, 算法数据结构) 45 | 46 | 3. 亮点* 47 | 当你准备从sp或者ssp等更高级别的offer的时候, 亮点就尤为重要了, 你出了课本中和常见项目中, 还自己研究了什么技术, 能甩开你的候选者, 这个是高薪的重要加分项. 48 | 49 | ## Q: 你的简历是怎么写的? 50 | 51 | A: 52 | 53 | > https://github.com/IcyCC/AboutMe/blob/master/%E8%8B%8F%E7%95%85%E7%9A%84%E7%AE%80%E5%8E%86.pdf 54 | 55 | 首先就是排版, 我用的是一个latex的模板: 56 | 57 | > https://github.com/billryan/resume 58 | 59 | 简洁大方, 用过的人都说好, 其次是不要贴照片, 太占空间, 争取写一页简历, 把自己最精华的东西留在上面, 很多人有个误区是简历是用来展示自己的工具, 其实并不是, 简历最大的作用, 是限制面试官提问范围, 把他引导到你擅长的东西, 太多内容的简历, 让面试官失去重点, 就会随意发问了. 60 | 61 | 62 | 我的简历其实就是对上述内容的一个展示: 63 | 64 | 1. 经历部分, 我着重强调了 我的实习经历, 虽然没有大厂, 但是胜在开始的早并且能看出来成长性, 所以算是加分点, 放在了第一位. 其次是我的项目经验, 我的项目经验比较丰富, 分为个人的玩具 和 简单的商业项目, 个人的玩具主要是想展示我对技术的兴趣, 商业项目是想展示我的做事方式, 并且技术栈能和我个人技能部分一一对应. 剩下的就是我的知乎专栏, 虽然文章质量不一定多高, 但是开始的比较早, 所以算是加分项, 也放在了简历上. 65 | 66 | ![知乎专栏第一篇文章](https://i.loli.net/2019/11/01/8qVPxgIwUCr4FLt.png) 67 | 68 | 69 | 而基础知识和亮点, 主要体现在我个人技能: 70 | 71 | * 编程语言方面, 我强调了我很擅长Python这一有vm的语言和c++这一没vm的语言, 并且以我的项目经历作为作证, 把 C++/Python 混合开发 作为了我一个亮点 72 | 73 | * 网络方面, 我强调了我对http TCP ssl协议 的理解, 和用网络库和web项目加以作证 74 | 75 | * 操作系统, 主要是并发编程这里, 我把协程作为了一个亮点, 用在知乎的文章加以作证 76 | 77 | * 数据库和缓存, 这里强调了我对redis源码的理解 78 | 79 | 80 | 81 | ## Q:如何学习基础知识? 82 | 83 | A: 84 | 85 | 基础知识的学习, 有个通用的思路, 就是 **把书读薄, 做起来, 在读厚** , 很多人一上来就推荐经典大部头, 其实违反人性的. 就算知道这个东西很好, 在没有正反馈的前提下, 也是很难读下去. 所以 我个人建议的思路是, 先大致了解这个知识的内容, 然后开始做, 做的过程中, 有了思考, 再回头看经典大部头, 会有种恍然大悟的感觉, 带着开拓的思路连带着把其他内容看看, 慢慢的 大部头就没那么难啃了. 86 | 87 | 针对不同的基础知识, 有不同的学习方法, 这里举几个例子: 88 | 89 | * 网络 90 | 91 | 网络这里核心要关注协议 和 流程, 协议部分就是 这个协议提供了什么功能, 比如http协议来说, http协议提供了什么功能, 传参数怎么传, 保存登陆状态怎么搞.... 流程就是一些常见的功能的实习, 比如 网页请求, 数据包路由等流程, 用到多个协议分层负责不同的步骤. 92 | 93 | 这里给大家推荐的资料: 94 | [1]: https://developer.mozilla.org/zh-CN/docs/Web/HTTP "http 的mdn文档" 95 | [2]: https://www.bilibili.com/video/av34135819 "湖大教书匠的计算机网络课程" 96 | [3]: https://item.jd.com/11163782.html "Linux多线程服务端编程 使用muduo C++网络库" 97 | 98 | * 编程语言 99 | 100 | 这个要看个人的技术栈, 建议一个带虚拟机语言和一个不带虚拟机语言搭配, 侧重了解以下方面: 101 | 102 | 1. 编程语言的语法 103 | 2. 编程语言的机制, 比如虚拟机语言的虚拟机机制的实现(垃圾回收, 内存分配, 函数协程栈), 非虚拟机语言的(反射, 资源管理, 编译时运行时工作等) 104 | 3. 编程语言理论* 如果让你实现一个 dsl 你会根据业务涉及哪些语法, 怎么理解用的编程语言的异常处理, 类型等机制 105 | 106 | 107 | 这里的参考资料: 108 | [1]: https://www.liaoxuefeng.com/wiki/1016959663602400 "廖雪峰的 Python 教程" 109 | [2]: https://zh.cppreference.com/w/cpp "Cpp renfence" 110 | [3]: https://www.ituring.com.cn/book/1564 "流畅的 Python" 111 | [4]: https://book.douban.com/subject/3117898 "Python 源码剖析" 112 | 113 | 114 | * 操作系统 115 | 116 | 我学的不太好, 看课本就行, 理解一下 117 | * 内存管理 注意分层的思想 118 | * 进程调度 lru, lfu 等算法思想的实践 *cfs 是加分项 119 | * 并发编程 理解资源的概念, 进程 线程 协程的资源和优缺点 120 | * io操作 121 | * 进程间通信 122 | 等内容就可以, 这里要注意的是和前面学的 含有虚拟机语言的设计的思想对应上 123 | 124 | 这里的参考资料: 125 | [1]: https://book.douban.com/subject/1390650/ "现代操作系统" 126 | [2]: https://book.douban.com/subject/3652388/ "程序员的自我修养" 127 | 128 | 129 | 130 | * 数据库 131 | 132 | mysql 主要理解 锁 , 索引, 日志, 缓存的机制的设计和使用 133 | 134 | redis 看源码就行, 代码质量高可读性好, 理解常见数据结构和reactor 并发模型 135 | 136 | 参考资料: 137 | [1]: https://book.douban.com/subject/24708143/ "MySQL技术内幕" 138 | [2]: https://time.geekbang.org/column/intro/139 "极客时间 MySQL实战45讲" 139 | 140 | -------------------------------------------------------------------------------- /秋招/给计算机相关专业找实习的朋友的一些话.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # 给计算机找实习的朋友的一些话 11 | 12 | 最近正在暑期实习生的招聘中, 然而我发现由于大部分学校的就业指导基本一片空白, 导致了大部分人基本是毫无准备的投入到了一场竞争中, 13 | 连一些行业的基本常识都不知道就忙着导出投简历, 这里给计算机相关专业说一说找实习和工作必备的知识, 特别的针对本科生一下: 14 | 15 | 1. 暑期实习生很重要, 现在是校招最容易进大厂的时候, 只有实习生能进去,转正的概率是很高的, 并且,由于互联网越来越内卷, 没有实习基本和大厂上岸无缘了, 所以一定要重视暑期实习. 16 | 17 | 18 | 2. 目前技术岗竞争的难易程度: 算法 >> 后台/后端开发 > 前端 > 客户端 > 测开, 目前已经极其不推荐找算法的工作了, 基本都是神仙打架普通人很难参与进去. 而客户端和测开其实需求量大的很, 是一个不错的上岸选择, 特别是客户端. 19 | 20 | 3. 无论找什么, 最重要的东西是计算机基础 和 **刷题** 21 | 22 | 4. 计算机基础, 包括操作系统, 网络, 数据库. 就课本上的内容好好看 23 | 24 | 5. 刷题包括数据结构算法基础的题, 和 一些套路题(类似剑指 offer 的题), 前者是基础, 经常笔试和口述思路. 后者是那种很讨厌的你没做过基本很难想出最优解, 做过很容易做出来的题, 有点脑筋急转弯, 但是这类题手撕代码基本必考几道, 挂了直接凉凉. 25 | 26 | 6. 如果你背景不错部门又缺人往往刷题刷对了就让你过.(类似字节的客户端) 27 | 28 | 7. 面试的基础知识, 是要专门总结的, 牛客上的 面试宝典十分重要, 基本是超高频的考点 (https://www.nowcoder.com/interview/center) 29 | 30 | 8. http 协议 和 数据库相关的内容, 还有语言基础 是面试超高频且学校教的不好的内容, 一定要多刷面经上的题来补足 31 | 32 | ## 算法 33 | 34 | **!!!不推荐投** 35 | 36 | ## 后台开发 37 | 38 | * 后台开发数据库要求很高, 一定要熟悉 mysql 的内容, 重点是索引, 缓存, 锁, 日志, 事务的内容, 索引是重点中的重点 39 | 40 | * linux 相关的操作要熟悉, 最好自己买个云服务器部署个项目看看. 41 | 42 | * 后台开发会强调 tcp/ip 协议的内容, 多看看 43 | 44 | * http 协议就不说了,重点的重点, 要明白 https 的机制, 怎么 http 协议实现登录, 怎么用 http 协议传参数等内容 45 | 46 | * python 或者 java 选一门 多刷刷语言特性相关的面试题 47 | 48 | ## 前端 49 | 50 | * html js css 基础 51 | 52 | * js es6 的特性 和 js 常见的恶心人坑, 高频 53 | 54 | * vue react 框架中的一个和其背后简单的原理 55 | 56 | * 再次强调 http 协议重点的重点, 要明白 https 的机制, 怎么 http 协议实现登录, 怎么用 http 协议传参数等内容 57 | 58 | * 如果有余力, 把浏览器当做一个操作系统, 看看这个系统给你提供了那些接口, 这个进阶前端的必须内容 59 | 60 | 61 | ## 客户端 62 | 63 | 类似前端 64 | 65 | ## 测开 66 | 67 | * python selenium 和 单测, 压测多看看 68 | 69 | 70 | * *无论你投什么刚 刷题 和 cs 基础是重中之重* 71 | 72 | * 建议要有个简单的项目, 爬虫 , 小网站都是不错的项目 73 | 74 | * 有余力最好造个轮子, 比如 web 框架的 demo, orm 的 demo 75 | 76 | ## 投递和面试 77 | 78 | * 不要浪费机会, 很多公司瞎投完挂了就没机会了, 面试评价还会被记录, 影响秋招 79 | 80 | * 能找内推一定要找内推, 特别是那种可以投递到对应部门的人的内推, 大概率可以免掉笔试 81 | 82 | * 简历好好写, 多找有经验的人问问, 和目标岗位匹配度要高, 重点要突出, 可以参考 https://mp.weixin.qq.com/s/Gtgcx99O0yrsyhQUG-_Nww 这个文章来写 83 | 84 | * 手撕代码的时候, 多问问具体的需求, 比如数据范围, 边界条件, 输入输出, 问清需求会留下好感, 命名和注释不能少, 写的时候多交流思路 85 | 86 | * 万一基础答得不好不要慌, 一定要和面试官主动说自己的长处, 往自己擅长的引导. 87 | 88 | * 但是最基础的算法和最基础的基础到常识基础知识千万不能不会, 多看看面经, 把那些教科书上眼熟的东西多看看 89 | 90 | 没什么了, 大家加油! 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /面筋/字节跳动_广告.md: -------------------------------------------------------------------------------- 1 | ## 一面 2 | 3 | * 自我介绍 4 | * 聊聊项目 (聊(chui)了很长时间) 5 | * 进程间通信手段 6 | * golang python 错误处理比较 7 | * 三道算法题 跳方块 (贪心, 上升子序列 dp变种, 背包问题变种, 比较简单直接秒了) 8 | 9 | ## 二面 10 | 11 | * 一道用到翻转链表竖式相加的题(md, 本垃圾状态不好写了好久, 总觉得写的有问题,差点没写出来) 12 | * 那个编程语言学的比较好, (python): 13 | * python 内存管理 (没清楚问的那层,本垃圾答得 高级对象内部池 中层arean, pool, block, 面试官说不对,,当时懵逼了然后他提示 jmalloc ,问了解不, 我说不太了解原理) 14 | * 垃圾回收怎么做的(本垃圾简单讲了讲引用计数和分代回收, 讲了讲和 shared_ptr 区别, 感觉答得不太清楚, 米娜使馆不满意...) 15 | * 并发手段, gil, 我答了 进程, 线程, 有栈协程gevent, 无栈协程 asyncio, 然后问我 python 的线程是真的线程吗, 我说是, 因为虚拟机里 Python的线程和系统线程一一对应, 然后本垃圾好像误解他的意思了, 他的意思好像是能不能同时执行... 16 | 17 | * sql python 的区别, 懵逼了, 不知道该回答啥... 18 | 19 | * 操作系统: 20 | * ctrl+c ctrl+v 区别, 本垃圾只知道发的信号不一样, 具体也不清楚, 被教育了 21 | * 怎么弄一个后台进程( 本垃圾以为是守护进程, 说 fork balbal, 然后面试官说是命令行怎么搞, 我回答了 nohup ,然后又问怎么进入, 我给忘了...没怎么用过) 22 | * 又问了问进程间通信的手段, 老问题不谈了 23 | * 然后看了看我会 redis, 然后问了 redis 特别大的一个 key 会有啥影响, 我想了想, 回答了过期删除比较慢, 不过觉得删除 是放在 背景线程里, 影响应该不大, 也不知道回答啥了, 回来了想想可能 rehash 比较慢... 24 | * 网络编程: 25 | * 老问题 epoll, poll 区别 26 | * 阻塞套接字非阻塞套接字 io复用的关系 27 | * 问我懂不懂 rpc, 我说不懂, 但是可以随便问问, 他就问, 大量数据下, rpc 应该用阻塞套接字还是非阻塞套接字, 懵逼了... 28 | * 大数据量下, 非阻塞套接字性能不如阻塞套接字, 为啥? (没想出来, 凉了, 面试官让我回去好好学学....) 29 | * 项目: 看见本垃圾写了个垃圾网络库, 就问我, 这个压测过没, 我说没(目的是为了学习网络库写法, 确实没压测过)...然后又问了别的类似的方案, 我说 muduo, libevent,然后又问了一些, 想不起来了, 基本这个话题答凉了 30 | 31 | ## 总结 32 | 33 | 我以为我复习的还可以, 结果还是凉了, 有些东西真的很难准备. 我以为我 redis 复习的很好了, 内部机制都还了解, 结果问了一个问题还是不会....我感觉网络编程学的还行,结果问了一个问题还是不会, 准备了很久的 c++ mysql 也没考, 动态规划做出来结果链表翻转给卡了....真的很心累....感觉校招真的很艰难... 34 | 35 | -------------------------------------------------------------------------------- /面试迷思--理解内存管理从 Python 到 malloc 再到 linux(上).md: -------------------------------------------------------------------------------- 1 | 写这个的也是面试官的一道题, 问 python 中内存是怎么分配的, 其实这个问题是一个很复杂的问题, 因为涉及到好多个层次, 分别包括: 2 | 3 | * Python 对象内部的内存管理 4 | * **Python 虚拟机的内存管理 (memory allocator)** 5 | * **malloc 内存管理** 6 | * linux 的内存管理 7 | 8 | 这次就从机制上, 用代码, 介绍一下这几层内存管理的大致实现. 9 | 10 | 阅读的过程中, 可以重点关注单独自己层要解决的和其它层不一样的问题和他与其他层的相似之处. 11 | 12 | ## Python 内部对象的内存管理 13 | 14 | 这里能说的比较少, 每个对象的面临的场景不一样, 简单来说, 比如 Python 的 List, 15 | list 每次发现容量满了的时候, 都会预先申请一些空间, 我们在 Objects/listobject.c 中 的 repr 方法里查看一下 list 的状态 16 | 17 | ![image.png](http://note.youdao.com/yws/res/4875/WEBRESOURCEa7f4d3cb2207c07830eb03252895ae3d) 18 | 19 | 这样 每次打印的时候 就能看的 list 状态 20 | 21 | 试一下 22 | 23 | ![image.png](http://note.youdao.com/yws/res/4879/WEBRESOURCEbcba5c48064932422c616bbf814a0a03) 24 | 25 | 可以看到 只插了一个元素 却申请了 4 个元素空间 26 | 27 | ![image.png](http://note.youdao.com/yws/res/4881/WEBRESOURCEadee6576094428a9dd5b0f80c719de1c) 28 | 29 | 在插了到了 5 个元素空间变成了 8 30 | 31 | 其实其他的对象也有类似的机制, 会提前申请大一些的内存, 用来插入. 这样的目的也是减少从下级的内存分配器申请内存 32 | 33 | 那我们申请内存的下一级在哪里呢? 34 | 35 | 我们看 listobject.c 的代码 36 | 37 | 我们看到 38 | ![image.png](http://note.youdao.com/yws/res/4898/WEBRESOURCE8afe65c255575229543dd1d4940c18dc) 39 | 40 | 大致猜想一下, PyObject_GC_New 这个应该就是下一层的内存分配器的接口, _PyObject_GC_TRACK 这个应该是处理垃圾回收的 暂时不管 41 | 42 | ## Python 虚拟机的内存管理 (memory allocator) 43 | 44 | 不断的紧跟函数调用关系 在Objects/obmalloc.c 中 我们发现了 45 | ![image.png](http://note.youdao.com/yws/res/4902/WEBRESOURCE6f4d1a7b7be45d388b2675ff4d8219cf) 46 | 47 | 这个, 这个应该是 python 垃圾分配器的接口, 看了一堆麻烦的调用关系以后, 48 | ![image.png](http://note.youdao.com/yws/res/4910/WEBRESOURCEa8aa3fe18a7e7aad42c969003346b110) 49 | 我们 找到了这个接口的实现, 首先他也是分层的, 分为 raw 和 mem, obj 三层, 由于 mem,obj用的一个分配器, 我们把它当做一个来看, 去看一下 PYMALLOC_ALLOC的实现 50 | 51 | 可以看到 52 | 53 | ![image.png](http://note.youdao.com/yws/res/4920/WEBRESOURCEcb0601cddb2145f6d4403beff6b7c5a3) 54 | 55 | 红线一组目测就是我们要的东西 56 | ![image.png](http://note.youdao.com/yws/res/4922/WEBRESOURCE445e9cb839e786fecf13327db23ed697) 57 | 58 | 点开发现 同样的思想又来了, 先看看能不能申请成功不能就去下一层, 下一层就是我们的刚刚看到的 raw_alloc 跟一下看到了 59 | 60 | ![image.png](http://note.youdao.com/yws/res/4927/WEBRESOURCE77c46d43d18adac805e87c994eebae16) 61 | 62 | 熟悉的 malloc 这里就不管了, 我们把重点放在 63 | --------------------------------------------------------------------------------