├── .github └── workflows │ └── build.yml ├── .gitignore ├── CSS └── flex.md ├── Docker ├── Docker nginx proxy_pass 配置.md ├── Docker 磁盘占用过高排查.md ├── Docker-Compose │ ├── docker-compose 常用命令.md │ └── 个人用构建文件.md ├── Docker.md ├── Ubuntu 19.10 无法安装Docker.md └── k8s.md ├── ELK └── ELK.md ├── Git ├── Git.md ├── git访问慢问题.md └── 不常见的使用.md ├── Golang ├── GRPC.md ├── Go 开发 Module.md ├── Golang.md ├── circular-queue │ └── main.go ├── defer-test │ └── defer-test.go ├── go mod 设置代理.md ├── go-producer-consumer-demo │ └── main.go ├── golang Http请求.md ├── map.md ├── simpleserver │ └── main.go ├── string-bytes convert │ └── mian.go ├── viper dots key 问题.md ├── wpe │ ├── .gitignore │ ├── device │ │ ├── device.go │ │ └── device_test.go │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── process │ │ ├── process.go │ │ └── process_test.go ├── 交叉编译.md ├── 参考书籍.md ├── 常见错误.md ├── 源码分析 │ └── gin │ │ └── gin v1.7.7 源码分析.md └── 错误处理.md ├── LICENSE ├── Linux └── Linux.md ├── MacOS ├── MSI B360M 黑苹果.md └── brew使用.md ├── MySQL ├── MySQL 错误处理.md ├── MySQL.md ├── MySQL创建用户.md ├── MySQL导出及导入应用.md └── MySQL连接数.md ├── Nginx ├── Nginx.md └── nginx配置前后端分离.md ├── OS └── OS.md ├── PHP ├── FPM.md ├── IO复用下的单线程模型.php ├── PHP.md ├── Swoole │ └── Swoole.md ├── Zend虚拟机.md ├── conversion_pub_key.pem ├── rsa_public_key.pem ├── 加签.php ├── 变量.md ├── 命名空间.md ├── 扩展开发.md ├── 类.md └── 线程安全.md ├── Prometheus └── prometheus.md ├── README.md ├── RabbitMQ └── RabbitMQ.md ├── Redis └── Redis.md ├── SUMMARY.md ├── Tool ├── .DS_Store ├── Frp │ ├── frp 配置 smb.md │ └── 安装.md ├── Gitbook │ ├── Gitbook 起步.md │ └── 使用github Actions来自动build上传到服务器.md ├── Homebrew │ └── 切换源.md ├── Jenkins │ └── Jenkins 安装.md ├── OwnCloud │ ├── owncloud 配置 smb.md │ └── owncloud安装.md ├── PHPStorm │ └── 关闭自动保存.md ├── Tmux │ └── tmux安装.md ├── VSCode │ ├── linux下vscode terminal字体设置.md │ ├── ssh内网穿透.md │ └── ssh远程开发.md ├── dnsmasq │ └── dnsmasq.md ├── k8s │ └── CKA证书.md ├── rabbitmq │ └── rabbitmq操作命令.md └── 国内下载镜像慢的问题.md ├── _config.yml ├── book.json ├── k8s └── 工具推荐.md ├── leetcode-golang ├── array │ ├── 088_合并两个有序数组.go │ └── 167_两数之和_输入有序数组.go ├── bite │ └── 136_只出现一次的数.go ├── design │ ├── 001_两数相加.go │ ├── 002_两数之和.go │ ├── 002_两数之和_test.go │ ├── 007_整数反转.go │ ├── 009_回文数.go │ ├── 015_三数之和.go │ ├── 015_三数之和_test.go │ ├── 026_删除数组中的重复项.go │ ├── 027_移除元素.go │ ├── 053_最大子序和.go │ └── 069_x的平方根.go ├── dynamic │ ├── 070_爬楼梯.go │ ├── 121_买卖股票的最佳时机.go │ └── 122_买卖股票的最佳时机.go ├── list │ ├── 021_合并两个有序链表.go │ ├── 066_加一.go │ ├── 083_删除排序链表中重复的元素.go │ └── 160_相交链表.go ├── search │ ├── 035_搜索插入位置.go │ └── 038_最大子序和.go ├── stack │ ├── 020_有效的括号.go │ └── 155_最小栈.go ├── string │ ├── 013_罗马字符串转数字.go │ ├── 028_实现str_str.go │ ├── 038-外观数列.go │ ├── 058_最后一个单词的长度.go │ ├── 067_二进制求和.go │ └── 125_验证回文字符串.go └── tree │ ├── 100_相同的树.go │ ├── 101_对称二叉树.go │ ├── 104_二叉树的最大深度.go │ ├── 107_二叉树的层次遍历II.go │ ├── 110_平衡二叉树.go │ ├── 111_二叉树的最小深度.go │ ├── 112_路径总和.go │ ├── 118_杨辉三角.go │ ├── 119_杨辉三角 II.go │ └── tree.go ├── leetcode ├── Map │ └── Map.md ├── Top 100 │ ├── 155_最小栈.php │ ├── 160_相交链表.php │ ├── 169_多数元素.php │ ├── 198_打家劫舍.php │ ├── 206_反转链表.php │ ├── 226_翻转二叉树.php │ ├── 234_回文链表.php │ ├── 283_移动零.php │ ├── 437_路径总和.php │ ├── 448_找到所有数组中消失的数字.php │ ├── 461_汉明距离.php │ ├── 538_把二叉搜索数转换为累加树.php │ ├── 543_二叉树的直径.php │ ├── 581_最短无序连续子数组.php │ ├── 617_合并二叉树.php │ ├── easy │ │ ├── 001_两数之和.php │ │ ├── 020_有效的括号.php │ │ ├── 021_合并两个有序链表.php │ │ ├── 053_最大子序和.php │ │ ├── 070_爬楼梯.php │ │ ├── 101_对称二叉树.php │ │ ├── 104_二叉树的最大深度.php │ │ ├── 121_买卖股票的最佳时机.php │ │ ├── 136_只出现一次的数字.php │ │ └── 141_环形链表.php │ └── medium │ │ ├── 048_旋转图像.php │ │ ├── 049_字母异位词分组.php │ │ ├── 055_跳跃游戏.php │ │ ├── 056_区间合并.php │ │ ├── 060_第k个排列.php │ │ ├── 062_不同路径.php │ │ ├── 064_最小路径和.php │ │ ├── 075_颜色分类.php │ │ ├── 078_子集.php │ │ ├── 079_单词搜索.php │ │ ├── 096_不同的二叉搜索树.php │ │ ├── 098_验证二叉搜索树.php │ │ ├── 102_二叉树的层序遍历.php │ │ └── 148_排序链表.php ├── 二分查找 │ ├── 035_搜索插入位置.php │ ├── 069_x的平方根.php │ └── 二分查找.md ├── 二叉搜索树 │ ├── 108_将有序数组转换为二叉搜索树.php │ ├── 235_二叉搜索树的最近公共祖先.php │ └── 二叉搜索树.md ├── 位运算 │ ├── 029_两数相除.php │ ├── 067_二进制求和.php │ ├── 190_颠倒二进制位.php │ ├── 191_位1的个数.php │ ├── 231_2的幂.php │ ├── 268_缺失的数字.php │ ├── 371_两整数之和.php │ ├── 401_二进制手表.php │ ├── 461_汉明距离.php │ └── 位运算.md ├── 其它 │ ├── 分布式唯一id.md │ ├── 单链表处理.php │ ├── 有趣的两位数.php │ ├── 游戏币组合.php │ ├── 计算最大差值.php │ ├── 邀请码检测.php │ └── 部门优化.php ├── 分治法 │ └── 分治法.md ├── 分治算法 │ ├── 050_pow-x-n.php │ └── 分治算法.md ├── 动态规划 │ ├── 005_最长回文字符串.php │ ├── 053_最大子序和.php │ ├── 062_不同路径2.php │ ├── 070_爬楼梯.php │ ├── 118_杨辉三角.php │ ├── 119_杨辉三角II.php │ ├── 121_买卖股票的最佳时机.php │ ├── 198_打家劫舍.php │ └── 动态规划.md ├── 双指针 │ └── 双指针.md ├── 哈希表 │ ├── 001_两数之和.php │ └── 哈希表.md ├── 回溯算法 │ ├── 017_电话号码的字母组合.php │ ├── 022_括号生成.php │ ├── 039_组合总和.php │ ├── 040_数组总和.php │ ├── 046_全排列.php │ ├── 047_全排列2.php │ ├── 074_回溯算法.php │ └── 回溯算法.md ├── 图 │ └── 图.md ├── 堆 │ ├── 1046_最后一块石头的重量 │ │ └── index.php │ ├── 703_数据流中的第K大元素 │ │ └── index.php │ └── 堆.md ├── 字典树 │ └── 字典树.md ├── 字符串 │ ├── 003_无重复字符的最长子串.php │ ├── 007_整数反转.php │ ├── 008_字符串转换整数.php │ ├── 009_回文数.php │ ├── 012_整数转罗马数字.php │ ├── 013_罗马数字转整数.php │ ├── 014_最长公共前缀.php │ ├── 028_实现strStr().php │ ├── 058_最后一个单词的长度.php │ ├── 125_验证回文串.php │ ├── 168_Excel表列名称.php │ ├── 171_Excel表列序号.php │ ├── 205_同构字符串.php │ ├── 242_有效的字母异位词.php │ ├── 290_单词规律.php │ ├── 345_反转字符串中的元音字母.php │ ├── 387_字符串中的第一个唯一字符.php │ ├── 389_找不同.php │ ├── 405_数字转换为十六进制数.php │ ├── 409_最长回文字符串.php │ ├── 415_字符串相加.php │ ├── 434_字符串中的单词数.php │ ├── 459_重复的字符串.php │ ├── 557_反转字符串中的单词 III.php │ └── 字符串.md ├── 并差集 │ └── 并差集.md ├── 广度优先遍历 │ ├── 101_对称二叉树.php │ └── 广度优先遍历.md ├── 拓扑排序 │ └── 拓扑排序.md ├── 排序 │ ├── 034_在排序数组中查找元素的第一个和最后一个位置.php │ ├── 912_排序数组.php │ ├── 冒泡排序.php │ ├── 堆排序.php │ ├── 快速排序.php │ ├── 排序.md │ ├── 插入排序.php │ └── 选择排序.php ├── 数组 │ ├── 004_寻找两个有序数组的中位数.php │ ├── 026_删除排序数组中的重复项.php │ ├── 027_移除元素.php │ ├── 033_搜索旋转排序数组.php │ ├── 054_螺旋矩阵.php │ ├── 059_螺旋矩阵2.php │ ├── 066_加一.php │ ├── 073_矩阵置零.php │ ├── 074_搜索二维矩阵.php │ ├── 080_删除排序数组中的重复项II.php │ ├── 088_合并两个有序数组.php │ ├── 136_只出现一次的数字.php │ ├── 167_两数之和II - 输入有序数组.php │ ├── 169_多数数组.php │ ├── 189_旋转数组.php │ ├── 215_数组中的第k大个最大元素.php │ ├── 217_存在重复元素.php │ ├── 219_存在重复元素II.php │ ├── 283_移动0.php │ ├── 303_区域和检索-数组不可变.php │ ├── 344_反转字符串.php │ ├── 349_两个数组的交集.php │ ├── 350_两个数组的交集.php │ ├── 412_Fizz Buzz.php │ ├── 414_最三大的数.php │ ├── 443_压缩字符串.php │ ├── 448_找到数组中消失的数字.php │ ├── 453_最小移动次数使数组相等.php │ ├── 581_最短无序连续子数组.php │ └── 数组.md ├── 栈 │ ├── 1021_删最外层的括号 │ │ └── index.php │ ├── 103_二叉树的锯齿形层次遍历 │ │ └── index.php │ ├── 1047_删除字符串中所有相邻重复项 │ │ └── index.php │ ├── 1209_删除字符串中所有相邻重复项 │ │ └── index.php │ ├── 1249_移除无效的括号 │ │ └── index.php │ ├── 144_二叉树的前序遍历 │ │ └── index.php │ ├── 150_逆波兰表达式求值 │ │ └── index.php │ ├── 155_最小栈 │ │ └── index.php │ ├── 173_二叉搜索树迭代器 │ │ └── index.php │ ├── 20_有效的括号 │ │ └── index.php │ ├── 225_用队列实现栈 │ │ └── index.php │ ├── 232_使用栈实现队列 │ │ └── index.php │ ├── 496_下一个更大元素 │ │ └── index.php │ ├── 682_棒球比赛 │ │ └── index.php │ ├── 71_简化路径 │ │ └── index.php │ ├── 844_比较含退格符的字符串 │ │ └── index.php │ ├── 94_二叉树的中序遍历 │ │ └── index.php │ └── 栈排序.php ├── 树 │ ├── 100_相同的树.php │ ├── 104_二叉树的最大深度.php │ ├── 107_二叉树的层序遍历II.php │ ├── 110_平衡二叉树.php │ ├── 111_二叉树的最小深度.php │ ├── 112_路径总和.php │ ├── 226_翻转二叉树.php │ ├── 230_二叉搜索树中第k小的元素.php │ ├── 257_二叉树所有路径.php │ ├── 404_左叶子之和.php │ ├── 437_路径总和.php │ ├── 543_二叉树的直径.php │ ├── 582_把二叉树转换为累加树.php │ ├── 617_合并二叉树.php │ ├── 820_单词的压缩编码.php │ ├── 二叉树的中序遍历.php │ ├── 二叉树的先序遍历.php │ ├── 二叉树的后序遍历.php │ ├── 二叉树的广度优先搜索.php │ ├── 二叉树的深度优先搜索.php │ ├── 前缀树.php │ └── 树.md ├── 深度优先遍历 │ └── 深度优先遍历.md ├── 设计 │ ├── 006_Z字形变换.php │ ├── 011_盛最多水的容器.php │ ├── 016_最接近的三数之和.php │ ├── 017_按摩师.php │ ├── 018_四数之和.php │ ├── 031_下一个排列.php │ ├── 036_有效的数独.php │ ├── 043_字符串相乘.php │ ├── 1071_字符串的最大公因子.php │ ├── 1162_地图分析.php │ ├── 146_LRU缓存机制.php │ ├── 15_三数之和.php │ ├── 170_两数之和III.php │ ├── 172_阶乘后的零.php │ ├── 202_快乐数.php │ ├── 204_计数质数.php │ ├── 258_各位相加.php │ ├── 263_丑数.php │ ├── 278_第一个错误的版本.php │ ├── 292_Nim游戏.php │ ├── 299_猜数字游戏.php │ ├── 326_3的幂.php │ ├── 342_4的幂.php │ ├── 367_有效的完全平方数.php │ ├── 374_猜数字大小.php │ ├── 383_赎金信.php │ ├── 441_排列硬币.php │ ├── 463_岛屿的周长.php │ ├── 892_三维形体的表面积.php │ ├── 999_车的可用捕获量.php │ └── 设计.md ├── 贪心算法 │ ├── 122_买股票的最佳时机 │ │ └── index.php │ ├── 392_判断子序列 │ │ └── index.php │ ├── 455_分发饼干 │ │ └── index.php │ └── 贪心算法.md ├── 递归 │ ├── 038_外观数列.php │ └── 递归.md └── 链表 │ ├── 002_两数相加.php │ ├── 019_删除链表的倒数第N个节点.php │ ├── 021_合并两个有序链表.php │ ├── 023_合并k个排序链表.php │ ├── 024_两两交换链表中的节点.php │ ├── 061_旋转链表.php │ ├── 083_删除排序链表中的重复元素.php │ ├── 141_环形链表.php │ ├── 148_排序列表.php │ ├── 160_相交链表.php │ ├── 203_移除链表元素.php │ ├── 206_反转链表.php │ ├── 234_回文链表.php │ ├── 237_删除链表中的节点.php │ ├── 876_链表的中间节点.php │ ├── 链表.md │ └── 面试题62_圆圈中最后剩下的数字.php ├── programme ├── Java │ ├── maven发布到仓库.md │ ├── 如何开发一个Java SDK.md │ └── 学Java.md ├── K8S │ ├── k8s安装.md │ ├── 什么是云原生技术.md │ └── 学习过程中使用的集群结构.md ├── Linux │ ├── Centos 更改hostname.md │ ├── Linux 安全.md │ ├── Linux 常用命令.md │ ├── Linux将默认shell更改为vim.md │ ├── SCP下载上传文件.md │ ├── Supervisor.md │ ├── Ubuntu add-apt-repository command not found.md │ ├── Ubuntu上安装小飞机.md │ ├── Ubuntu安装.md │ ├── Ubuntu安装桌面配置工具.md │ ├── axel多线程下载.md │ ├── fail2ban.md │ ├── oh-my-zsh安装.md │ ├── ssh执行命令.md │ ├── ssh设置别名.md │ ├── tar.md │ ├── wine │ │ ├── wine-deepin_wechat_乱码问题解决.md │ │ └── 修复wine在高分屏下的问题.md │ ├── 公私钥对.md │ ├── 查看Linux信息.md │ ├── 查看所有crontab.md │ └── 用户相关.md ├── PHP │ ├── Composer │ │ ├── 国内切换阿里云源.md │ │ └── 多线程下载加速Composer.md │ ├── Laravel │ │ ├── Carbon问题.md │ │ ├── Laravel Faker 使用中文.md │ │ ├── docker部署生产环境.md │ │ └── tiner模式下方向键编程了字符的问题.md │ ├── Swoole │ │ ├── smproxy安装配置.md │ │ └── 安装.md │ ├── 常见错误.md │ └── 支付 │ │ └── QQ钱包 │ │ └── QQ 钱包 Laravel 扩展开发.md └── 前端 │ ├── CentOS安装node环境.md │ ├── MacOS_install_nodejs.md │ ├── Ubuntu安装node环境.md │ ├── dotenv │ └── dontenv配置.md │ ├── npm安装更新.md │ └── npm换源.md ├── rust └── tauri.md ├── temp ├── 001_两数之和.php ├── 007_整数反转.php ├── 009_回文数.php ├── 013_罗马数字转整数.php ├── 014_最长公共前缀.php ├── 020_有效的括号.php ├── 021_合并两个有序链表.php ├── 026_删除排序数组中的重复项.php ├── 027_移除元素.php ├── 028_实现 strStr().php ├── 101_对称二叉树.php ├── 155_最小栈.php ├── 206_反转链表.php ├── test.go └── 一个无限递归的错误.php ├── 分布式 └── 分布式.md ├── 剑指offer ├── 丑数.php ├── 两个栈来实现一个队列.php ├── 二叉搜索树与双向链表.php ├── 二叉搜索树的后序遍历序列.php ├── 二叉树中和为某一值的路径.php ├── 二叉树的镜像.php ├── 二维数组中的查找.php ├── 二进制中1的个数.php ├── 从上往下打印二叉树.php ├── 从尾到头打印链表.php ├── 包含min函数的栈.php ├── 反转链表.php ├── 变态跳台阶.php ├── 合并两个排序链表.php ├── 复杂链表的复制.php ├── 子树.php ├── 字符串的排列.php ├── 把数组排成最小的数.php ├── 数值的整数次方.php ├── 数组中出现次数超过一半的数字.php ├── 整数中1出现的次数(从1到n整数中1出现的次数).php ├── 斐波那契数列的第n项.php ├── 旋转数组的最小数字.php ├── 替换空格.php ├── 最小k的个数.php ├── 栈的压入,弹出序列.php ├── 树的子结构.php ├── 矩形覆盖.php ├── 第一个只出现一次的字符.php ├── 调整数组顺序使奇数位于偶数前面.php ├── 跳台阶.php ├── 连续子数组的最大和.php ├── 重建二叉树.php ├── 链表中倒数第k个节点.php └── 顺时针打印矩阵.php ├── 加密 └── 加密.md ├── 娱乐 ├── mincraft.md └── 工业2.md ├── 有感 └── 编程有感.md ├── 架构 └── 架构.md ├── 编程 └── .DS_Store ├── 网络 └── 网络.md ├── 设计 ├── 实时匿名通讯.md └── 设计.md ├── 设计模式 ├── Laravel中用到的设计模式.md ├── 中介者模式.md ├── 享元模式.md ├── 什么是接口.md ├── 代理模式.md ├── 单例模式.md ├── 原型模式.md ├── 外观模式.md ├── 对象池模式.md ├── 工厂模式.md ├── 建造者模式.md ├── 抽象工厂模式.md ├── 模板方法模式.md ├── 状态模式.md ├── 策略模式.md ├── 职责链模式.md ├── 装饰模式.md ├── 设计模式六大原则.md ├── 访问者模式.md ├── 适配器模式.md ├── 面向对象编程设计原则SOLID.md └── 领域驱动开发.md └── 面试 ├── 简历怎么写.md ├── 练手项目.md ├── 计算机概念.md └── 面试问题统计.md /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | /_book 3 | /.idea 4 | /node_modules 5 | go.mod 6 | go.sum 7 | vendor/ 8 | -------------------------------------------------------------------------------- /Docker/Docker nginx proxy_pass 配置.md: -------------------------------------------------------------------------------- 1 | # Docker nginx proxy_pass 配置连接到其它容器 2 | 3 | ```text 4 | resolver 127.0.0.11; 5 | proxy_pass http://php:1215; 6 | ``` 7 | -------------------------------------------------------------------------------- /Docker/Docker 磁盘占用过高排查.md: -------------------------------------------------------------------------------- 1 | # Docker 磁盘占用过高排查 2 | 3 | 磁盘文件在 `/var/lib/docker/overlay2/` 目录下 4 | 5 | ## 命令 6 | 7 | 查看 docker 磁盘占用情况: `docker system df` 8 | 9 | 查看是否有死掉没有删除的日志: `docker ps -a` 10 | 11 | 清理悬空镜像, 不会删除未使用的镜像 `docker system prune` 12 | 13 | 删除以下内容: `docker system prune -a` 14 | 已停止的容器(container) 15 | 未被任何容器所使用的卷(volume) 16 | 未被任何容器所关联的网络(network) 17 | 所有悬空镜像(image) 18 | 19 | 删除未被使用的 local volumns : `docker volume rm $(docker volume ls -q)` -------------------------------------------------------------------------------- /Docker/Docker-Compose/docker-compose 常用命令.md: -------------------------------------------------------------------------------- 1 | # docker-compose 常用命令 2 | 3 | https://yeasy.gitbook.io/docker_practice/compose/commands 4 | 5 | 创建并启动所有容器 `docker-compose up -d`, 默认会停止所有容器,然后重新创建。 6 | `--no-recreate` 只启动处于停止状态的容器,忽略已经运行的容器。 7 | `--no-deps` 只重新创建启动指定的服务,不影响其他服务。 8 | 9 | 停止所有容器 `docker-compose down` 10 | 验证 compose 配置文件是否征程 `docker-compose config` 11 | 打印某个容器端口所映射的公共端口: `docker-compose port [options] SERVICE PRIVATE_PORT` 12 | 13 | ## 常见问题 14 | 15 | services 之间无法通过 service_name 通信: attachable 配置在 v3 默认为 false, 需要单独配置为 true。 16 | 17 | https://docs.docker.com/compose/networking/ -------------------------------------------------------------------------------- /Docker/Docker-Compose/个人用构建文件.md: -------------------------------------------------------------------------------- 1 | # 个人使用的一些docker-compose配置 2 | 3 | - [nmpr](https://github.com/zhan3333/nmpr) 启动位于同一个网络的 Nginx + MySQL + PHP + Redis 环境 4 | - [rabbitmq](https://github.com/zhan3333/rabbitmq-docker) 启动一个RabbitMQ服务 5 | -------------------------------------------------------------------------------- /Docker/Docker.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | ## docker 预热 4 | 5 | 主要分为两部分 6 | 7 | 1. 镜像预拉取 8 | 9 | 类的下载需要一定的网络资源,较为耗时,可以使用一些方案来预先拉取对应主机中的需要部署的镜像。 10 | 11 | 2. 新启动服务刚开始运行的过程 12 | 13 | 服务刚启动时,有些类可能需要实例化,有些资源需要进行首次加载,均属于耗时操作,如果刚启动起来就大流量打到新起服务中的话,有可能压垮服务,这里可以采用加权的方式分配流量,依照启动时间的长短来按比例分配到达该服务的流量。 14 | 15 | ## Docker 原理 16 | 17 | 基于操作系统之上的轻量级虚拟机, 可以理解为是一种被限制了的特殊进程 18 | 19 | ### 优势 20 | 21 | 1. 模块化 22 | 2. 层和镜像的版本控制 23 | 3. 回滚 (镜像拥有多层, 可以回滚) 24 | 4. 快速部署 25 | 26 | ## Docker 对比虚拟机 27 | 28 | - 虚拟机 29 | 30 | 软件模拟硬件输入输出,使操作系统从硬件层面运行起来的机制。独立内核,文件进程等系统。 31 | 32 | 启动慢,效率低,安全性高 33 | 34 | - Docker 35 | 36 | 操作系统层虚拟化,与宿主机共享内核,共享文件进程等, 但容器中看不到宿主机的文件进程信息。 37 | 38 | 资源消耗少,启动快。 39 | 40 | -------------------------------------------------------------------------------- /Docker/Ubuntu 19.10 无法安装Docker.md: -------------------------------------------------------------------------------- 1 | https://github.com/docker/for-linux/issues/833 2 | 3 | 使用 disco 替代 $(lsb_release -cs) 4 | ```shell 5 | sudo add-apt-repository \ 6 | "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ 7 | disco \ 8 | stable" 9 | ``` 10 | 11 | 然后需要删除 `/etc/apt/sources.list` 中错误的 eoan 项 -------------------------------------------------------------------------------- /ELK/ELK.md: -------------------------------------------------------------------------------- 1 | # ELK 2 | 3 | ## 描述 4 | 5 | 通常用作分布式日志搜索引擎, 通常包含以下组件 6 | 7 | FileBate 8 | 消息队列(Redis) 9 | Logstash 10 | ElasticSearch 11 | Kibana 12 | 13 | ## hbase 14 | 15 | 开源非关系型分布式数据库, 使用 Java 实现, 运行于 HDFS 文件系统上. 16 | 17 | 优势: 提供了高并发的随机写和支持实时查询,这是HDFS不具备的。 18 | 19 | 对比 MongoDB: 20 | 21 | - Hbase 是列储存(适用于数据压缩, 对指定几个字段进行查询效率很高), MongoDB 是文档储存 (用类似 json 格式进行储存) 22 | - Hbase 适用于简单数据存储, 海量,结构简单数据查询 23 | - MongoDB 支持复杂查询 24 | - Hbase 基于 HDFS (分布式文件储存系统), 对于分布式数据储存有优势 25 | 26 | 对比 Redis: 27 | 28 | - Redis 支持的数据类型更多 29 | - HBase 只支持简单的字符串 30 | 31 | 场景: 32 | 33 | 储存 SMS 发送记录 34 | 储存 IM 系统记录 35 | 36 | 37 | ## elasticsearch 38 | 39 | 40 | -------------------------------------------------------------------------------- /Git/Git.md: -------------------------------------------------------------------------------- 1 | # Git 2 | 3 | ## 文件版本 4 | 5 | ## merge 和 rebase 使用顺序 6 | 7 | ## 回滚代码 8 | 9 | 回滚 commit 10 | 11 | `https://yijiebuyi.com/blog/8f985d539566d0bf3b804df6be4e0c90.html` 12 | 13 | 回滚 merge commit 14 | `https://blog.csdn.net/allanGold/article/details/103288645` 15 | 16 | ## gitlab CI 缓存 vendor 17 | 18 | https://docs.gitlab.com/ee/ci/caching/#cache-go-dependencies -------------------------------------------------------------------------------- /Git/git访问慢问题.md: -------------------------------------------------------------------------------- 1 | # git访问慢问题 2 | 3 | ## 配置hosts来加速访问 4 | 5 | ``` 6 | # GitHub Start updated 15-1-2019 7 | 192.30.253.112 github.com 8 | 192.30.253.118 gist.github.com 9 | 151.101.112.133 assets-cdn.github.com 10 | 151.101.184.133 raw.githubusercontent.com 11 | 151.101.112.133 gist.githubusercontent.com 12 | 151.101.184.133 cloud.githubusercontent.com 13 | 151.101.112.133 camo.githubusercontent.com 14 | 151.101.112.133 avatars0.githubusercontent.com 15 | 151.101.112.133 avatars1.githubusercontent.com 16 | 151.101.184.133 avatars2.githubusercontent.com 17 | 151.101.12.133 avatars3.githubusercontent.com 18 | 151.101.12.133 avatars4.githubusercontent.com 19 | 151.101.184.133 avatars5.githubusercontent.com 20 | 151.101.184.133 avatars6.githubusercontent.com 21 | 151.101.184.133 avatars7.githubusercontent.com 22 | 151.101.12.133 avatars8.githubusercontent.com 23 | # GitHub End 24 | ``` -------------------------------------------------------------------------------- /Git/不常见的使用.md: -------------------------------------------------------------------------------- 1 | # Git 不常见的命令 2 | 3 | ## 删除分支 4 | 5 | - 删除本地分支: `git tag -d tag_name` 6 | - 删除远程分支: `git push origin :refs/tags/tag_name` 7 | 8 | ## 删除远程仓库的文件 9 | 10 | 1. 预览要删除的文件 11 | 12 | ```bash 13 | git rm -r -n --cached 文件/文件夹名称 14 | 15 | 加上 -n 这个参数,执行命令时,是不会删除任何文件,而是展示此命令要删除的文件列表预览。 16 | ``` 17 | 18 | 2. 确认删除文件 19 | 20 | ```shell 21 | git rm -r --cached 文件/文件夹名称 22 | ``` 23 | 24 | 3. 提交本地并推送到远程服务器 25 | 26 | ```shell 27 | git commit -m "提交说明" 28 | git push origin master 29 | ``` 30 | 31 | 4. 修改本地 .gitignore 文件 并提交 32 | 33 | ```bash 34 | git commit -m "提交说明" 35 | git push origin master 36 | ``` 37 | 38 | 5. 查看 git 设置的用户名和邮箱地址 39 | 40 | ```shell 41 | git config user.name 42 | git config user.email 43 | ``` 44 | 45 | 6. 设置 git 用户名和邮箱 46 | 47 | ```shell 48 | git config --global user.name "username" 49 | git config --global user.email "email" 50 | ``` 51 | 52 | 7. clone 到一个非空目录 53 | 54 | ```shell 55 | 1. 进入非空目录,假设是 /workdir/proj1 56 | 57 | 2. git clone --no-checkout https://git.oschina.net/NextApp/platform.git tmp 58 | 59 | 3. mv tmp/.git . #将 tmp 目录下的 .git 目录移到当前目录 60 | 61 | 4. rmdir tmp 62 | 63 | 5. git reset --hard HEAD 64 | ``` 65 | 66 | 8. 拉取远程分支到本地 67 | 68 | ```shell 69 | git checkout -b 本地分支名x origin/远程分支名x 70 | ``` 71 | 72 | 9. 设置大小写敏感 73 | 74 | ```shell script 75 | git config core.ignorecase false 76 | ``` -------------------------------------------------------------------------------- /Golang/GRPC.md: -------------------------------------------------------------------------------- 1 | # GRPC 2 | 3 | ## 概念 4 | 5 | RPC 是一种远程过程调用. 常用与分布式系统. 6 | 7 | RPC 是一种设计\实现框架, 通讯协议只是其中一部分. 8 | 9 | gRPC 基于 HTTP2, 使用 ProtoBuf 序列化协议, 支持多种开发语言 10 | 11 | ## 相对于 HTTP 优势 12 | 13 | - 基于 TCP 协议的情况下, 本身是长连接, 减少网络开销 14 | - RPC 框架一般都有注册中心, 有丰富的监控管理; 发布, 下线接口, 动态扩展等, 对调用方无感知 15 | 16 | ## RPC 中主要解决的问题 17 | 18 | - 建立通信: 在客户端与服务端建立起数据传输通道, 大部分是 TCP 连接 (gRPC 使用了 HTTP2) 19 | 20 | ## gRPC 为什么是 HTTP2 21 | 22 | 优点: 23 | 24 | - 公开\经过时间检验的标准 25 | - 天然支持物联网\手机\浏览器 26 | - 基于 HTTP2 的多语言客户端实现容易 27 | - 支持 Stream 和流控 28 | - 天然支持 SSL 29 | - 鉴权成熟 30 | 31 | 缺点: 32 | 33 | - RPC 的元数据传输效率不够高效 34 | - 一次 gRPC 调用需要两次解码(Headers frame, Data frame) 35 | 36 | ## gRPC 还是 thrift 37 | 38 | - gRPC 39 | - 良好的文档\示例 40 | - 喜欢\习惯 HTTP2, ProtoBuf 41 | - 对网络传输带宽敏感 42 | - Thrift 43 | - 需要在非常多语言进行数据交换 44 | - 对 CPU 敏感 45 | - 协议层\传输层有多种控制要求 46 | - 需要稳定的版本 47 | - 不需要良好的文档和示例 -------------------------------------------------------------------------------- /Golang/Go 开发 Module.md: -------------------------------------------------------------------------------- 1 | # Go 开发 Module 2 | 3 | ## 检查包是否存在 4 | 5 | `https://sum.golang.org/lookup/github.com/zhan3333/glog@v1.0.0` 6 | 7 | `https://proxy.golang.org/github.com/zhan3333/gdb/@v/v1.0.0.info` 8 | 9 | ## 如何新增版本 10 | 11 | 1. 大版本使用新增目录的形式进行, 例如 `v2` 12 | 2. 小版本使用 tag 来进行, 例如 `v2.0.0` 13 | -------------------------------------------------------------------------------- /Golang/defer-test/defer-test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 函数的返回函数的执行是优先于 defer 的, 因为返回值的计算属于函数执行的一部分, 而 defer 属于函数结束后再执行的一部分 6 | // 7 | // 执行结果 8 | // f1 9 | // f2 10 | // defer 11 | 12 | func main() { 13 | f1() 14 | } 15 | 16 | func f1() bool { 17 | defer func() { 18 | fmt.Println("defer") 19 | }() 20 | fmt.Println("f1") 21 | return func() bool { 22 | fmt.Println("f2") 23 | return true 24 | }() 25 | } 26 | -------------------------------------------------------------------------------- /Golang/go mod 设置代理.md: -------------------------------------------------------------------------------- 1 | # go mod 设置代理 2 | 3 | `export GOPROXY=https://goproxy.io,direct` 4 | -------------------------------------------------------------------------------- /Golang/golang Http请求.md: -------------------------------------------------------------------------------- 1 | # Golang Http 请求发送 2 | 3 | ## 发送一个 POST 表单提交 4 | 5 | ```golang 6 | var request *http.Request 7 | payload := make(url.Values) 8 | payload.Add("wd", idCardIdentity.Name) 9 | request, err := http.NewRequest(http.MethodPost, "https://www.baidu.com/s", strings.NewReader(payload.Encode())) 10 | request.Header.Add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") 11 | response, err := http.DefaultClient.Do(request) 12 | if err != nil { 13 | return err 14 | } 15 | defer func() {_ = response.Body.Close()}() 16 | responseBody, err := ioutil.ReadAll(response.Body) 17 | if err != nil { 18 | return err 19 | } 20 | log.Printf("response: %d %s",response.StatusCode, responseBody) 21 | ``` 22 | 23 | ## POST json 数据 24 | 25 | ```golang 26 | bodyJson, _ := json.Marshal(map[string]interface{}{ 27 | "idNo": idCardIdentity.IdCard, 28 | "name": idCardIdentity.Name, 29 | }) 30 | request, err := http.NewRequest(http.MethodPost, "https://www.baidu.com/s", strings.NewReader(string(bodyJson))) 31 | ``` 32 | -------------------------------------------------------------------------------- /Golang/simpleserver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "sync" 8 | ) 9 | 10 | func HelloHandler(w http.ResponseWriter, r *http.Request) { 11 | fmt.Println(r.Method) 12 | _, _ = fmt.Fprintf(w, "Hello World") 13 | } 14 | 15 | 16 | func main() { 17 | var wg = sync.WaitGroup{} 18 | http.HandleFunc("/", HelloHandler) 19 | wg.Add(1) 20 | go func() { 21 | defer wg.Done() 22 | fmt.Println("8000 start") 23 | if err := http.ListenAndServe(":8000", nil); err != nil { 24 | panic(err) 25 | } 26 | }() 27 | wg.Add(1) 28 | go func() { 29 | defer wg.Done() 30 | fmt.Println("8001 start") 31 | if err := http.ListenAndServe(":8001", nil); err != nil { 32 | panic(err) 33 | } 34 | }() 35 | fmt.Printf("当前进程 pid: %d\n", os.Getpid()) 36 | wg.Wait() 37 | } 38 | -------------------------------------------------------------------------------- /Golang/string-bytes convert/mian.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var a = "abc" 7 | var b = []byte(a) 8 | fmt.Println(a, b) 9 | } 10 | -------------------------------------------------------------------------------- /Golang/wpe/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | vendor 3 | !go.mod 4 | !go.sum -------------------------------------------------------------------------------- /Golang/wpe/device/device.go: -------------------------------------------------------------------------------- 1 | package device 2 | 3 | import ( 4 | "fmt" 5 | "github.com/google/gopacket/pcap" 6 | "log" 7 | ) 8 | 9 | // 获取网卡设备 10 | func GetDevices() ([]pcap.Interface, error) { 11 | version := pcap.Version() 12 | fmt.Println(version) 13 | var err error 14 | var devices []pcap.Interface 15 | devices, err = pcap.FindAllDevs() 16 | return devices, err 17 | } 18 | 19 | //选择网卡 20 | func ScanDeviceName() string { 21 | //展示所有网卡 22 | devices, err := GetDevices() 23 | if err != nil { 24 | log.Panicf("获取网卡失败: %+v", err) 25 | } 26 | for i, dev := range devices { 27 | fmt.Printf("[%d]: %s %s", i+1, dev.Name, dev.Description) 28 | for _, address := range dev.Addresses { 29 | fmt.Printf(" %s", address.IP) 30 | } 31 | fmt.Println() 32 | } 33 | fmt.Println("输入选择的设备编号(默认1):") 34 | var selectDeviceIndex int 35 | for selectDeviceIndex == 0 { 36 | if _, err := fmt.Scanln(&selectDeviceIndex); err != nil { 37 | if err.Error() == "unexpected newline" { 38 | selectDeviceIndex = 1 39 | } else { 40 | fmt.Printf("读取用户输入失败: %+v\n", err) 41 | selectDeviceIndex = 0 42 | continue 43 | } 44 | } 45 | if selectDeviceIndex > len(devices) { 46 | fmt.Printf("有效值范围为: %d - %d\n", 1, len(devices)) 47 | selectDeviceIndex = 0 48 | } 49 | } 50 | return devices[selectDeviceIndex-1].Name 51 | } 52 | -------------------------------------------------------------------------------- /Golang/wpe/device/device_test.go: -------------------------------------------------------------------------------- 1 | package device_test 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | "wpe/device" 7 | ) 8 | 9 | func TestGetDevices(t *testing.T) { 10 | devices, err := device.GetDevices() 11 | assert.Nil(t, err) 12 | t.Logf("%+v", devices) 13 | assert.NotEqual(t, 0, len(devices)) 14 | } 15 | 16 | func TestScanDeviceName(t *testing.T) { 17 | dev := device.ScanDeviceName() 18 | assert.NotEmpty(t, dev) 19 | } 20 | -------------------------------------------------------------------------------- /Golang/wpe/go.mod: -------------------------------------------------------------------------------- 1 | module wpe 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect 7 | github.com/go-ole/go-ole v1.2.5 // indirect 8 | github.com/google/gopacket v1.1.19 9 | github.com/shirou/gopsutil v3.21.2+incompatible 10 | github.com/stretchr/testify v1.7.0 11 | github.com/tklauser/go-sysconf v0.3.4 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /Golang/wpe/process/process_test.go: -------------------------------------------------------------------------------- 1 | package process_test 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "io/ioutil" 6 | "os/exec" 7 | "os/user" 8 | "testing" 9 | "wpe/process" 10 | ) 11 | 12 | func TestProcesses(t *testing.T) { 13 | ps, err := process.Processes() 14 | assert.Nil(t, err) 15 | for _, p := range ps { 16 | name, _ := p.Name() 17 | username, _ := p.Username() 18 | t.Log(p.Pid, name, username) 19 | } 20 | u, err := user.Current() 21 | assert.Nil(t, err) 22 | t.Log(u.Username, u.Name, u.Uid) 23 | } 24 | 25 | func TestUserName(t *testing.T) { 26 | u, err := user.Current() 27 | assert.Nil(t, err) 28 | username := process.UserName() 29 | assert.Equal(t, u.Username, username) 30 | } 31 | 32 | func TestRunCommand(t *testing.T) { 33 | cmd := exec.Command("bash", "-c", "lsof -P -p72081 | grep -E 'IPv6|IPv4'| awk '{print $9}' | awk -F: '{print $2}'") 34 | stdout, err := cmd.StdoutPipe() 35 | assert.Nil(t, err) 36 | err = cmd.Start() 37 | assert.Nil(t, err) 38 | if err != nil { 39 | t.Log(err.Error()) 40 | } 41 | bytes, err := ioutil.ReadAll(stdout) 42 | t.Log(string(bytes)) 43 | } 44 | 45 | func TestGetProcessPorts(t *testing.T) { 46 | ports, err := process.GetProcessPorts(53777) 47 | assert.Nil(t, err) 48 | t.Log(ports) 49 | t.Log(len(ports)) 50 | } 51 | -------------------------------------------------------------------------------- /Golang/交叉编译.md: -------------------------------------------------------------------------------- 1 | # 交叉编译 2 | 3 | ## 编译指定平台的执行文件 4 | 5 | GOOS:目标平台的操作系统(darwin、freebsd、linux、windows) 6 | GOARCH:目标平台的体系架构(386、amd64、arm) 7 | 交叉编译不支持 CGO 所以要禁用它 8 | 9 | > Mac to Linux, Windows 10 | 11 | ```shell 12 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go 13 | CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go 14 | ``` 15 | 16 | > Linux to Mac, Windwos 17 | 18 | ```shell 19 | CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go 20 | CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go 21 | ``` 22 | 23 | > Windows to Mac, Linux 24 | 25 | ```shell 26 | SET CGO_ENABLED=0 27 | SET GOOS=darwin 28 | SET GOARCH=amd64 29 | go build main.go 30 | 31 | SET CGO_ENABLED=0 32 | SET GOOS=linux 33 | SET GOARCH=amd64 34 | go build main.go 35 | ``` 36 | -------------------------------------------------------------------------------- /Golang/参考书籍.md: -------------------------------------------------------------------------------- 1 | # Golang 参考书籍 2 | 3 | ## 初级 4 | 5 | > [Go 入门指南](https://github.com/unknwon/the-way-to-go_ZH_CN) 6 | 7 | Golang 基础语法入门 8 | 9 | > [Go 语言简明教程](https://geektutu.com/post/quick-golang.html) 10 | 11 | 适合入门,用很短的篇幅讲解了基础的 Go 使用方法 12 | 13 | ## 中级 14 | 15 | [Go 编程模式](https://coolshell.cn/articles/series/go%e7%bc%96%e7%a8%8b%e6%a8%a1%e5%bc%8f) 16 | 17 | ## 高级 18 | 19 | [Go 语言高级编程(Advanced Go Programming)](https://chai2010.cn/advanced-go-programming-book/) 20 | 21 | [Go 语言设计与实现](https://draveness.me/golang/docs) 22 | 23 | [Go 高性能编程](https://geektutu.com/post/high-performance-go.html) 24 | 25 | ## 查手册 26 | 27 | [Go CookBook 标准库笔记](https://www.kancloud.cn/mutouzhang/gocookbook/608898) 28 | 29 | [gin 框架文档](https://gin-gonic.com/zh-cn) 30 | 31 | ## 读博客 32 | 33 | [训练营](https://lailin.xyz/) 34 | 35 | [值得学习的 Go 开源项目](https://www.zhihu.com/question/20801814/answer/1534555951) 36 | 37 | [和煎鱼学 Go](https://eddycjy.gitbook.io/golang/) 38 | 39 | [推荐一些对职业生涯影响较大的书籍](https://v2ex.com/t/795885#reply66) -------------------------------------------------------------------------------- /Golang/常见错误.md: -------------------------------------------------------------------------------- 1 | # 常见错误及解决 2 | 3 | ## mod 4 | 5 | `go mod download` 报错 `unrecognized import path "golang.org/x/net"` 6 | 7 | 设置代理即可: ` export GOPROXY=https://goproxy.io` 8 | 9 | ## go get 报错 `go get: disabled by -mod=vendor` 10 | 11 | 使用 `GO111MODULE=off go get` 来下载 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 zhan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Linux/Linux.md: -------------------------------------------------------------------------------- 1 | # Linux 2 | 3 | ## 线程切换时,保存了什么信息 -------------------------------------------------------------------------------- /MacOS/MSI B360M 黑苹果.md: -------------------------------------------------------------------------------- 1 | # MSI 360M 微星主板黑苹果过程 2 | 3 | ## 参考 4 | 5 | [EFI 下载](https://github.com/SuperNG6/MSI-B360-Big-Sur-EFI) 6 | 7 | [安装教程](https://sleele.com/2019/07/14/gettingstartedtutorial/) 8 | 9 | ## 准备工作 10 | 11 | - U盘 >= 16G 12 | 13 | ## 过程 14 | 15 | 1. 下载 MacOS 镜像 16 | 17 | https://blog.daliansky.net/macOS-Mojave-10.14.5-18F132-official-version-with-Clover-4928-original-image.html 18 | 19 | 在黑果小兵的博客中,找到 EFI 允许版本的 MacOS 镜像。镜像自带什么 EFI 不重要,会被 github 上的 EFI 替换。 20 | 21 | 2. 用 Etcher 将下载好的镜像写入到 U盘中 22 | 23 | https://www.balena.io/etcher/ 24 | 25 | 3. Clover Configurator 加载 U盘 中的 EFI 分区 26 | 27 | 用 github 上下载的 EFI 替换 U盘中的 EFI 分区的 EFI 文件夹 28 | 29 | 4. U盘插入待安装主机,重启电脑从 U盘启动 30 | 31 | 5. 选择 Install MacOS 启动 32 | 33 | 启动后开始了安装过程,会有个苹果的大 logo 和进度条,中间会重启两到三次,每次重启需要选择从 U盘启动。 34 | 35 | 如果错过了可以手动重启再选择 U盘启动 36 | 37 | 6. 安装完毕 38 | 39 | 进入系统,下载 Clover Configurator, 加载 U盘 EFI 和 系统 EFI。 40 | 41 | 使用 U盘 EFI 替换系统 EFI,替换完后可以弹出 U盘不需要再使用了。 42 | 43 | 电脑重启选择从 Mac 盘启动即可进入 MacOS。 -------------------------------------------------------------------------------- /MacOS/brew使用.md: -------------------------------------------------------------------------------- 1 | # brew 使用 2 | 3 | 升级 brew: `brew update` 4 | 5 | ## 切换国内源 6 | 7 | ``` 8 | 替换brew.git: 9 | cd "$(brew --repo)" 10 | git remote set-url origin https://mirrors.ustc.edu.cn/brew.git 11 | 12 | 替换homebrew-core.git: 13 | cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" 14 | git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git 15 | ``` 16 | 17 | 腾讯源 18 | 19 | ``` 20 | # 替换brew.git: 21 | cd "$(brew --repo)" 22 | git remote set-url origin https://mirrors.cloud.tencent.com/homebrew/brew.git 23 | 24 | # 替换homebrew-core.git: 25 | cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" 26 | git remote set-url origin https://mirrors.cloud.tencent.com/homebrew/homebrew-core.git 27 | ``` 28 | 29 | ## brew 增加 services 管理功能 30 | 31 | 需要升级 brew 32 | -------------------------------------------------------------------------------- /MySQL/MySQL 错误处理.md: -------------------------------------------------------------------------------- 1 | # MySQL 错误处理 2 | 3 | ## MySQL: ERROR 1040: Too many connections 4 | 5 | 查看连接上限 6 | 7 | ```mysql 8 | show variables like "max_connections"; 9 | ``` 10 | 11 | 修改连接上限 12 | 13 | ```mysql 14 | set global max_connections = 200; 15 | ``` 16 | 17 | ## on dulicate key update deadlock bug 18 | 19 | https://mingwho.com/posts/insert-on-duplicate/ 20 | 21 | 主要是 next-key 导致的死锁,最好改为 insert 调用。 -------------------------------------------------------------------------------- /MySQL/MySQL连接数.md: -------------------------------------------------------------------------------- 1 | # MySQL 连接数 2 | 3 | 查看最大连接数 4 | 5 | ```sql 6 | show variables like '%max_connections%'; 7 | ``` 8 | 9 | 设置最大连接数 10 | 11 | ```sql 12 | set global max_connections=1000 13 | ``` 14 | 15 | 查看打开的连接数 16 | 17 | ```sql 18 | show status like 'Threads%'; 19 | ``` 20 | 21 | Threads_connected: 指打开的连接数 22 | Threads_running: 指激活的连接数 23 | 24 | 查看数据库连接超时时间 25 | 26 | ```sql 27 | show variables like "%timeout%" 28 | ``` 29 | 30 | or 31 | 32 | ```sql 33 | show global variables like '%wait_timeout'; --可以查看数据库空闲等待时间,默认8小时,最大2147483,接近24天 34 | ``` 35 | 36 | 设置超时时间 37 | 38 | ```sql 39 | set global wait_timeout=28800 40 | ``` 41 | 42 | wait_timeout 选项指默认连接经过 8 小时没有向服务器发送请求时, 它就会断开这个连接 43 | 44 | 查看自动提交开关 45 | 46 | ```sql 47 | show variables like 'autocommit'; 48 | ``` 49 | 50 | ```sql 51 | set AUTOCOMMIT=1 52 | ``` 53 | -------------------------------------------------------------------------------- /Nginx/Nginx.md: -------------------------------------------------------------------------------- 1 | # Nginx 2 | 3 | ## 配置优化 4 | 5 | ## 负载均衡算法 -------------------------------------------------------------------------------- /OS/OS.md: -------------------------------------------------------------------------------- 1 | # OS 操作系统 2 | 3 | ## 孤儿进程, 僵尸进程 4 | 5 | ## 死锁条件, 如何避免 6 | 7 | ## Linux 命令: 查看端口占用, cpu 负载, 内存占用, 发送信号给进程 8 | 9 | ## 守护进程是什么,怎么实现 10 | 11 | ## 进程间通信方式 12 | 13 | ## 共享内存实现 14 | 15 | ## 虚拟内存实现方式, 调度怎么做的 16 | 17 | ## malloc 怎么做的 -------------------------------------------------------------------------------- /PHP/IO复用下的单线程模型.php: -------------------------------------------------------------------------------- 1 | add($svrSock, EV_READ, function () use ($svrSock, $reactor) { 6 | $cliSock = stream_socket_accept($svrSock); 7 | $reactor->add($cliSock, EV_READ, function () use ($cliSock, $reactor) { 8 | $request = fread($cliSock, 8192); 9 | $reactor->add($cliSock, EV_WRITE, function () use ($cliSock, $request, $reactor) { 10 | fwrite($cliSock, "hello world \n"); 11 | $reactor->del($cliSock); 12 | fclose($cliSock); 13 | }); 14 | }); 15 | }); -------------------------------------------------------------------------------- /PHP/Swoole/Swoole.md: -------------------------------------------------------------------------------- 1 | # SWOOLE 2 | 3 | ## 常见问题 4 | 5 | ### swoole 特性 6 | 7 | Swoole 是一个 PHP 的协程高性能网络通信引擎, 使用 C/C++ 编写, 支持多种通信协议的网络服务器, 可以快速的在多种领域(TCP/UDP服务器, 高性能WEB, 8 | 实时通讯, 游戏, 微服务) 等, 使 PHP 不再局限于传统的 Web 领域. 9 | 10 | ### swoole 与 go 11 | 12 | - 优势 13 | - 动态语言, 更适合 PHP 开发者学习, 开发效率佳 14 | - 两者就能够实现的功能上来说几乎没有差别 15 | - 劣势 16 | - go 静态语言, 更适合底层软件的开发 17 | - go 协程是原生支持的, 而且支持多核利用 18 | 19 | ### 协程实现 20 | 21 | - 使用 C/C++ 来实现的协程 22 | - 核心使用栈结构来处理协程创建, 销毁, 切换时的操作 23 | 24 | ### 什么是协程 25 | 26 | 协程可以简单的理解为线程, 只不过这个线程是用户态的, 不需要操作系统参与, 创建销毁和切换的成本非常低, 和线程不同的是协程没有办法利用 27 | 多核 CPU 的, 想要利用多核 CPU 需要依赖 Swoole 的多进程模型 28 | 29 | ### 什么是通道 30 | 31 | channel 可以理解为消息队列, 只不过是协程间的消息队列, 多个协程通过 push pop 来操作生产和消费消息, 用来协程间通信. channel 无法跨进程 32 | 33 | ### 为什么协程只能利用单核, 多核怎么利用? 34 | 35 | 协程可以看做是轻量级的线程, 所以只能利用单核. 想要利用多核的话, 可以使用多进程+协程的方式. 36 | 37 | ### 协程调度机制 38 | 39 | Swoole 的协程调度方案: 40 | 1. 当执行某个协程过程中发现代码遇到了 `Co::sleep()` 或者网络IO(查询操作数据库, 读取写入文件)等, swoole 就会把这个连接的Fd放到 EventLoop 中 41 | - 然后让出这个协程的 CPU 给其它协程使用: 即 `yield` (挂起) 42 | - 扥带 MySQL 数据返回后就继续执行这个协程: 即 `resume` (恢复) 43 | 2. 其次, 如果协程的代码有 CPU 密集型代码, 我们可以开启 `enable_preemptive_scheduler` 44 | 45 | ### 全局变量不安全 46 | 47 | 协程使得原有的异步逻辑同步化,但是在协程的切换是隐式发生的,所以协程切换的前后不能保证全局变量以及 static 变量的一致性. -------------------------------------------------------------------------------- /PHP/Zend虚拟机.md: -------------------------------------------------------------------------------- 1 | # Zend 虚拟机 2 | 3 | ## PHP 代码的编译 4 | 5 | 1. Re2c 语法分析器将 PHP 代码转换为有意义的标识 Token 6 | 2. Bison 将 Token 和符合文法规则的代码生成抽象语法树 7 | 3. 抽象语法树生成对应的 opcode, 被虚拟机执行. opcode 是 php7 定义的一组指令标识,指令对应着相应的 handler. 当虚拟机调用 opcode,会找到 opcode 背后的处理函数,进行执行 8 | 9 | PHP 代码编译为 opcode 数组, 每一个 opcode 代码都有对应的 C 语言里的 struct, 执行过程就是引擎依次执行 opcode 10 | 11 | PHP 代码->抽象语法树(AST)->opcodes 12 | 13 | PHP 代码->AST: re2c, bison 14 | AST->opcodes: AST->zend_op_array 15 | 16 | - zend_op_array 17 | - zend_op \*opcodes opcode 指令数组 18 | - handler 每条 opcode 对应 C 语言编写的处理过程 19 | - op1 操作数 1 20 | - op2 操作数 2 21 | - result 返回值 22 | - opcode opcode 指令 23 | - op1_type 操作数 1 类型 24 | - op2_type 操作数 2 类型 25 | - result_type 返回值类型 26 | - zval \*literals 字面量数组 27 | - zend_string \*\*vars 在 AST 编译期间配合 last_var 用来确定各个变量的编号 28 | 29 | ## 函数实现 30 | 31 | PHP 自定义函数的实现就是将函数编译成独立的 opcode 数组,调用时分配独立执行栈依次执行 opcode. 简单可以理解为 opcode 进行了打包封装. 32 | 33 | 函数的结构 34 | 35 | - zend_function 36 | 37 | ## Zend 引擎执行流程 38 | 39 | opcode->execute 这个过程是在 `Zend 引擎`中进行的 40 | 41 | opcode 是将 PHP 代码编译产生 Zend 虚拟机可识别的指令,php7 共有 173 个 opcode,定义在`zend_vm_opcodes.h`中, PHP 中所有 42 | 43 | ## 面向对象实现 44 | 45 | ## 运行时的缓存 46 | 47 | ## Opcode 48 | -------------------------------------------------------------------------------- /PHP/conversion_pub_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3EfwYm3Mh+9dHenY56Cv 3 | eYkyFwV3HHfC/XWt8Vnip4yhxKUMEomh7HD5YIU61TvmAx9Ef5VwSM/SFYLImOLu 4 | ce9DMYG8+A9dWTL7ZG/nkFPer/HywBPbnGe6dfyerIU+Db/WHItQURJpKv5IVcI3 5 | Y+NLA+3LjnnZPcoO55MRqsOQJeJwJrRS/KP8LmpeIeEU1kpHyEEgEQzTDu+sd0X5 6 | 7f4fx9HSVsvhu3rMW6SN3b+IemJ3N1ShC/3oCrXSqEhL+paWaij9RR+fGWAFaUIY 7 | FX/D7gZGYO6pZuaqFt+2/qXB3W7NwmCbIl3+PDkgCxKQDcbly/0HGhqn+2VGj1ZU 8 | xwIDAQAB 9 | -----END RSA PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /PHP/rsa_public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyyxvr5r1C/N3XmjyY5l0 3 | jKTHSvO3Y33oukWjmHKw96fkSq+gIcmO7Pu07W/Ll9WOIyuatifdL/+AMzdBHZwe 4 | N70Y5eel/ksA34M2Jxwbnih84kxI1pZE2M7MAsBED/4qyBsWQNR/uOotFnOiFpG5 5 | SJXf/5AR66sBkr4yJ78aqpuFP58k+8Z2Qz/A3vkCRz2xlg5StEakjkwxMKouGyDf 6 | E6k/cjBKYTRW13y4PjN+5Iivg0CnQ/5Fvtr+tAazXHtR2ZCotRfU4Knee9InEs1C 7 | 25eQMetUIe+QO5wIuCVLLTJGq32IaLqCWdidjWB/gBM1gfxXsNYCL+7MKIk7tdSZ 8 | LwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /PHP/加签.php: -------------------------------------------------------------------------------- 1 | 动态用法 25 | 26 | 可以使用命名空间字符串来使用对应空间中的类,变量,常量等 27 | -------------------------------------------------------------------------------- /PHP/类.md: -------------------------------------------------------------------------------- 1 | # PHP 类 2 | 3 | ## 匿名类 4 | 5 | 可以创建一次性的简单对象. 6 | 7 | 匿名类一样可以使用 extend, implement, trait, interface 8 | 9 | 匿名类的名称是通过引擎赋予的. 10 | 11 | ## 重载 12 | 13 | PHP 重载是指动态地创建类属性和方法. 通过魔术方法来实现的. 14 | 15 | ## 遍历对象 16 | 17 | 默认情况下, 所有可见属性都将被用于遍历. 18 | 19 | 可以使用 Iterator 接口来自定义决定如何遍历以及每次遍历哪些值可用. 20 | 21 | ## Final 关键字 22 | 23 | 如果父类中的方法被声明为 final, 则子类无法覆盖该方法. 如果一个类被声明为 final, 则不能被继承. 24 | 25 | ## 对象复制 26 | 27 | 当对象被复制后, PHP5 会对对象的所有属性执行一个浅复制. 所有的引用属性仍然会是一个指向原来变量的引用. 28 | 29 | 当复制完成后, 如果定义了 `__clone()`, 则新创建的对象中的 `__clone()` 会被调用, 可用于修改属性的值. 30 | 31 | ## 对象比较 32 | 33 | `==`: 如果两个类都是同一个对象的实例, 且两个对象的属性和属性值都相等, 那么这两个对象相等. 34 | 35 | `===`: 这两个对象变量一定要指向某个类的同一个实例(即同一个对象). 36 | 37 | ## 对象和引用 38 | 39 | ```php 40 | $a = new A; 41 | $b = $a; // $a, $b 都是同一个标识符的拷贝 42 | // ($a) = ($b) = 43 | 44 | $c= new A; 45 | $d = &$c; 46 | 47 | // $c, $d 是引用 48 | // ($c, $d) = 49 | 50 | $e = new A; 51 | function foo($obj) { 52 | // ($obj) = ($e) = 53 | } 54 | foo($e); 55 | ``` 56 | 57 | 引用主要和 `unset()` 关联比较大 58 | 59 | ## 对象序列化 60 | 61 | `serialize()` 返回类的包含字节流的字符串表示 62 | `unserialize()` 反序列化一个类 63 | 64 | 序列化时不会保存方法, 反序列化后能够正常调用方法 -------------------------------------------------------------------------------- /PHP/线程安全.md: -------------------------------------------------------------------------------- 1 | # 线程安全 2 | 3 | ## 什么是线程安全 4 | 5 | 线程安全指的是多线程环境下如何安全的获取公共资源. 6 | 7 | 公共资源一般指函数之外声明的全局变量,不同线程在访问同一个全局变量, 修改全局变量时就会影响所有线程. 8 | 9 | ## 怎么解决线程安全 10 | 11 | PHP 的 SAPI 多数是单线程环境,比如 cli,fpm,cgi,每个进程只启动一个主线程,这种模式下不存在线程安全问题. 12 | 13 | 但是也有多线程的环境,比如 Apache,或用户自己嵌入 PHP 实现的环境. 14 | 15 | PHP 中有很多全局变量: EG, CG 等 16 | 17 | PHP 为多线程的应用模型提供了一个安全机制: Zend 线程安全(Zend Thread Safe, ZTS) 18 | 19 | `线程安全资源管理器(Thread Safe Resource Manager, TSRM)`: 各线程不再共享一份全局变量,而是各复制一份,使用数据时各线程各取自己的副本,互不干扰. 20 | 21 | TSRM 核心思想就是为不同线程分配独立的内存空间, 如果一个资源会被多线程使用,那么首先需要预先向 TSRM 注册资源, 然后 TSRM 为这个资源分配一个唯一的编号, 并把这种资源的大小,初始化函数等保存到一个`tsrm_resource_type`结构中,各线程只能通过 TSRM 分配的编号访问这个资源.然后当线程拿着这个编号获取资源时 TSRM 如果发现是第一次请求,则会根据注册时的资源大小分配一块内存,然后调用初始化函数进行初始化,并把这块资源保存下来供这个线程后续使用. 22 | -------------------------------------------------------------------------------- /Prometheus/prometheus.md: -------------------------------------------------------------------------------- 1 | # prometheus 2 | 3 | [doc](https://www.prometheus.wang/promql/prometheus-query-language.html) 4 | 5 | ## 概念 6 | 7 | ## 安装配置 8 | 9 | ## 数据模型 10 | 11 | Metric 类型 12 | 13 | Counter: 计数器 14 | 15 | 只增不减计数器 16 | 17 | Gauge: 仪表盘 18 | 19 | 可增可减的仪表盘 20 | 例如磁盘大小、内存大小等 21 | 22 | Histogram: 直方图 23 | 24 | Summary: 摘要 25 | 26 | ## 采集数据 27 | 28 | ## 监控目标 29 | 30 | ## 数据展示 31 | 32 | ## 报警和告警 33 | 34 | ## 高级主题 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 编程笔记 2 | 3 | [目录](SUMMARY.md) 4 | 5 | ## 记录编程生涯中经验 6 | 7 | - 算法 8 | - 设计模式 9 | - 数据库 10 | - 语言 Golang / PHP 11 | - 消息队列 12 | - 工具 13 | 14 | ## 欢迎 star 15 | 16 | - [go-framework](https://github.com/zhan3333/go-framework): gin 框架脚手架 17 | 18 | - [goutil](https://github.com/zhan3333/goutil): golang 泛型写的一些辅助开发方法 19 | 20 | - [nmpr](https://github.com/zhan3333/nmpr): LNMP 基于 Docker 快速拉起本地开发环境 21 | 22 | ## 其他 23 | 24 | [markdown 语法文档](https://markdown.com.cn/basic-syntax/links.html) 25 | 26 | [技术面试最后反问面试官的话](https://github.com/yifeikong/reverse-interview-zh) 27 | 28 | [编程习惯](http://daily.zhihu.com/story/9744766) 29 | 30 | [FFmpeg 视频处理入门教程](https://www.ruanyifeng.com/blog/2020/01/ffmpeg.html) 31 | 32 | [做了 6 年程序员,我学到的 10 条经验](https://lutaonan.com/blog/things-i-learnt-after-6-years-as-software-engineer/) 33 | 34 | [图标](https://blog.ralph.wang/articles/67cff6f8_%E5%B0%8F%E5%9B%BE%E6%A0%87_%E5%A4%A7%E5%AD%A6%E9%97%AE) 35 | 36 | [时间](https://blog.ralph.wang/articles/e76960f7_%E6%97%B6%E9%97%B4) -------------------------------------------------------------------------------- /Tool/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhan3333/note/1610b236fa253cc4004dc44ab7440b8584c6b6a0/Tool/.DS_Store -------------------------------------------------------------------------------- /Tool/Frp/frp 配置 smb.md: -------------------------------------------------------------------------------- 1 | # frp 配置 smb 2 | 3 | smba 使用的是 tpc 协议,并且默认使用 445 端口,所以应该如下配置 4 | 5 | ```config 6 | type = tcp 7 | local_ip = 127.0.0.1 8 | local_port = 445 9 | remote_port = 44500 10 | ``` 11 | -------------------------------------------------------------------------------- /Tool/Gitbook/Gitbook 起步.md: -------------------------------------------------------------------------------- 1 | # Gitbook 2 | 3 | ## 配置github同步到gitbook上 4 | 5 | 1. 登录 `gitbook` 6 | 2. 选择 `Integrations` 菜单 7 | 3. 打开`GitHub`按钮 8 | 4. 按照流程进行操作 9 | 10 | --- 11 | 12 | - 当git仓库更新后,`gitbook`将会相应更新 13 | - `gitbook`访问链接从`Advanced->Space URL`获取 14 | - 可以通过`Advanced->Custom Domain`来配置使用自己的域名 15 | 16 | ## 参考文档 17 | 18 | - [`gitbook` 中文文档](https://chrisniael.gitbooks.io/gitbook-documentation/content/) 19 | 20 | ## 提交SEO 21 | 22 | - [百度链接提交入口](https://ziyuan.baidu.com/linksubmit/url) 23 | - [Google网站登录口](https://www.google.com/webmasters/tools/submit-url) 24 | - [Bing](https://blogs.bing.com/webmaster/september-2018/Anonymous-URL-Submission-Tool-Being-Retired) 25 | -------------------------------------------------------------------------------- /Tool/Gitbook/使用github Actions来自动build上传到服务器.md: -------------------------------------------------------------------------------- 1 | # 使用github Actions来自动build上传到服务器 2 | 3 | ## 需要在项目的 `Settings->Secrets` 配置如下几项: 4 | 5 | - scp 6 | - HOST 你的主机地址 7 | - USERNAME 登录你的主机用的用户名 8 | - DIR 主机上的保存编译后文件的路径 9 | - KEY scp访问私钥 10 | 11 | ## 配置如下 12 | 13 | ```yml 14 | name: CI 15 | 16 | on: [push] 17 | 18 | jobs: 19 | build: 20 | 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | 25 | - name: Check out source code 26 | uses: actions/checkout@v1 27 | 28 | - name: Setup Node.js for use with actions 29 | uses: actions/setup-node@v1.1.0 30 | 31 | - name: install 32 | run: | 33 | npm install -g gitbook-cli 34 | gitbook install 35 | gitbook build 36 | 37 | - name: copy dir to remote server 38 | uses: appleboy/scp-action@master 39 | with: 40 | host: ${{ secrets.HOST }} 41 | username: ${{ secrets.USERNAME }} 42 | source: "_book" 43 | target: ${{secrets.DIR}} 44 | key: ${{secrets.KEY}} 45 | rm: true 46 | ``` 47 | -------------------------------------------------------------------------------- /Tool/Homebrew/切换源.md: -------------------------------------------------------------------------------- 1 | # Homebrew 切换源 2 | 3 | https://lug.ustc.edu.cn/wiki/mirrors/help/brew.git 4 | 5 | ```shell script 6 | # 替换brew.git: 7 | cd "$(brew --repo)" 8 | git remote set-url origin https://mirrors.ustc.edu.cn/brew.git 9 | 10 | # 替换homebrew-core.git: 11 | cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" 12 | git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git 13 | ``` -------------------------------------------------------------------------------- /Tool/Jenkins/Jenkins 安装.md: -------------------------------------------------------------------------------- 1 | # Jenkins 安装配置 2 | 3 | ## 通过 docker-compose 安装 4 | 5 | `https://github.com/zhan3333/docker-compose` 6 | 7 | ```shell script 8 | cd jenkins 9 | sudo docker-compose up 10 | ``` 11 | 12 | 安装完毕后访问 `http://localhost:8080` 13 | 14 | ## 选择推荐插件安装 15 | 16 | ## 安装其他插件 17 | 18 | ### Gitee 码云 19 | 20 | ### 飞书 Notification 21 | -------------------------------------------------------------------------------- /Tool/OwnCloud/owncloud 配置 smb.md: -------------------------------------------------------------------------------- 1 | # owncloud 配置 smb 2 | 3 | ## 配置选项 4 | 5 | - 主机:不需要带 smb:// 前缀 6 | - 共享:远程smb服务下的目录 7 | - 远程子文件夹:可选,指定共享目录下的子目录 8 | - 域名:WORKGROUP 通常空就可以了 9 | - 用户名:nobody 10 | - 密码:nobody 11 | 12 | 如果想要使用用户名密码的话,需要在SMB服务端用`smbpasswd $USER` 来配置一下该用户的SMB密码 13 | -------------------------------------------------------------------------------- /Tool/OwnCloud/owncloud安装.md: -------------------------------------------------------------------------------- 1 | # OwnCloud 安装 2 | 3 | ## 客户端安装 4 | 5 | `https://owncloud.org/download/#install-clients` 6 | -------------------------------------------------------------------------------- /Tool/PHPStorm/关闭自动保存.md: -------------------------------------------------------------------------------- 1 | # PHPStorm 设置问题 2 | 3 | ## 关闭自动保存 4 | 5 | 搜索 Editor Tabs 6 | 7 | - [x] `Mark modified` 8 | 9 | 搜索 `save files on frame` 10 | 11 | 取消勾选 12 | 13 | - [] `Save files on frame deactivation` 14 | - [] `Save files automatically if application is idle for` 15 | 16 | ## 修复`Ctrl+Alt+Left` 无效的问题 17 | 18 | `Setting->Keymap->Main menu->Navigate->Back` 19 | `Setting->Keymap->Main menu->Navigate->Back` 20 | -------------------------------------------------------------------------------- /Tool/VSCode/linux下vscode terminal字体设置.md: -------------------------------------------------------------------------------- 1 | # 用户设置 2 | 3 | ```shell 4 | "terminal.integrated.fontFamily": "Ubuntu Mono derivative Powerline", 5 | ``` 6 | -------------------------------------------------------------------------------- /Tool/VSCode/ssh内网穿透.md: -------------------------------------------------------------------------------- 1 | # ssh 内网穿透 2 | 3 | - L 代理远程端口到本地: 本地 IP:本地端口:远程 IP:远程端口 4 | - R 代理本地端口到远程: 远程 IP:远程端口:本地 IP:本地端口 5 | - f 后台运行 6 | - N 告诉`SSH`我们只建立隧道, 不会在远程服务器执行命令 7 | - T 告诉`SSH`我们只希望创建隧道,而不需要创建虚拟终端 8 | - C 允许`SSH`压缩数据 9 | 10 | ## 使用示例 11 | 12 | ### 代理远程服务器的 3306 端口到本地 3307 13 | 14 | ```shell 15 | ssh -fNTCL '*':3307:127.0.0.1:3306 user@remoteHost 16 | ``` 17 | 18 | ### 代理本地的 8888 端口到远程的 8889 端口 19 | 20 | ```shell 21 | ssh -NTCR 127.0.0.1:8889:'*':8888 user@remoteHost 22 | ``` 23 | -------------------------------------------------------------------------------- /Tool/VSCode/ssh远程开发.md: -------------------------------------------------------------------------------- 1 | # ssh远程开发 2 | 3 | ## 步骤 4 | 5 | 1. 安装 Remote Development 6 | 2. 设置ssh配置 `vim ~/.ssh/config` 增加远程主机 -------------------------------------------------------------------------------- /Tool/dnsmasq/dnsmasq.md: -------------------------------------------------------------------------------- 1 | # dnsmasq 2 | 3 | ## 配置文件 4 | 5 | `/etc/dnsmasq.conf` 6 | 7 | `address=/test.com/192.168.0.31` 8 | 9 | ## 操作 10 | 11 | `restart_dns` 12 | -------------------------------------------------------------------------------- /Tool/k8s/CKA证书.md: -------------------------------------------------------------------------------- 1 | # CKA 证书 2 | 3 | ## 考证经验 4 | 5 | `https://www.jianshu.com/p/135c1d618a79` 6 | 7 | ## k8s 中文指南 8 | 9 | `https://jimmysong.io/kubernetes-handbook/` 10 | 11 | ## cncf 证书描述页及报名地址 12 | 13 | `https://www.cncf.io/certification/cka/` 14 | 15 | ## 证书开源课程 16 | 17 | `https://github.com/cncf/curriculum` 18 | 19 | ## 考试大纲 20 | 21 | `https://github.com/cncf/curriculum/blob/master/certified_kubernetes_administrator_exam_v1.15.pdf` -------------------------------------------------------------------------------- /Tool/rabbitmq/rabbitmq操作命令.md: -------------------------------------------------------------------------------- 1 | # rabbitmq 操作命令 2 | 3 | ## 增加一个用户对一个 vhost 的权限 4 | 5 | `sudo rabbitmqctl set_permissions -p vhostname username '.*' '.*' '.*'` 6 | 7 | ## 查看用户在 vhost 中的权限 8 | 9 | `sudo rabbitmqctl list_permissions --vhost fuwu-openapi` 10 | 11 | ## 修改密码 12 | 13 | > 查看用户列表 14 | 15 | `rabbitmqctl list_users` 16 | 17 | > 修改用户 18 | 19 | `rabbitmqctl change_password Username 'Newpassword'` 20 | -------------------------------------------------------------------------------- /Tool/国内下载镜像慢的问题.md: -------------------------------------------------------------------------------- 1 | # 国内下载一些镜像很慢 2 | 3 | 通过访问 `https://mirrors.163.com/` 来下载国外的一些镜像 -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /k8s/工具推荐.md: -------------------------------------------------------------------------------- 1 | # 工具推荐 2 | 3 | ## k9s 命令行管理集群 4 | 5 | https://github.com/derailed/k9s 6 | 7 | 推荐原因:纯键盘操作,操作快捷键提示明显、简洁。包含 ctx 选择、pod exec shell、pod logs 等功能。 8 | 9 | ## kubeconfig 配置管理工具 10 | 11 | https://github.com/sunny0826/kubecm 12 | 13 | 推荐原因:支持管理、合并 config -------------------------------------------------------------------------------- /leetcode-golang/array/088_合并两个有序数组.go: -------------------------------------------------------------------------------- 1 | package array 2 | 3 | func merge(nums1 []int, m int, nums2 []int, n int) { 4 | for m > 0 && n > 0 { 5 | if nums1[m-1] > nums2[n-1] { 6 | nums1[m+n-1] = nums1[m-1] 7 | m-- 8 | } else { 9 | nums1[m+n-1] = nums2[n-1] 10 | n-- 11 | } 12 | } 13 | for n > 0 { 14 | nums1[n-1] = nums2[n-1] 15 | n-- 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /leetcode-golang/array/167_两数之和_输入有序数组.go: -------------------------------------------------------------------------------- 1 | package array 2 | 3 | func twoSum(numbers []int, target int) []int { 4 | l := 0 5 | r := len(numbers) - 1 6 | for l < r { 7 | sum := numbers[l] + numbers[r] 8 | if sum == target { 9 | return []int{l + 1, r + 1} 10 | } else if sum > target { 11 | r-- 12 | } else { 13 | l++ 14 | } 15 | } 16 | return []int{} 17 | } 18 | -------------------------------------------------------------------------------- /leetcode-golang/bite/136_只出现一次的数.go: -------------------------------------------------------------------------------- 1 | package bite 2 | 3 | func singleNumber(nums []int) int { 4 | ans := 0 5 | for _, a := range nums { 6 | ans ^= a 7 | } 8 | return ans 9 | } 10 | -------------------------------------------------------------------------------- /leetcode-golang/design/001_两数相加.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | //给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 4 | // 5 | //你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 6 | // 7 | // 8 | // 9 | //示例: 10 | // 11 | //给定 nums = [2, 7, 11, 15], target = 9 12 | // 13 | //因为 nums[0] + nums[1] = 2 + 7 = 9 14 | //所以返回 [0, 1] 15 | // 16 | //来源:力扣(LeetCode) 17 | //链接:https://leetcode-cn.com/problems/two-sum 18 | //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 19 | 20 | func twoSum(nums []int, target int) []int { 21 | hash := map[int]int{} 22 | for ix, v := range nums { 23 | s := v - target 24 | if hv, ok := hash[s]; ok { 25 | return []int{hv, ix} 26 | } 27 | hash[v] = ix 28 | } 29 | return []int{} 30 | } 31 | -------------------------------------------------------------------------------- /leetcode-golang/design/002_两数之和.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | type ListNode struct { 4 | Val int 5 | Next *ListNode 6 | } 7 | 8 | func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { 9 | up := 0 10 | c1 := l1 11 | c2 := l2 12 | l3 := &ListNode{ 13 | Val: 0, 14 | Next: nil, 15 | } 16 | c3 := l3 17 | for c1 != nil || c2 != nil { 18 | v := 0 19 | if c1 == nil { 20 | v = c2.Val + up 21 | c2 = c2.Next 22 | } else if c2 == nil { 23 | v = c1.Val + up 24 | c1 = c1.Next 25 | } else { 26 | v = c1.Val + c2.Val + up 27 | c1 = c1.Next 28 | c2 = c2.Next 29 | } 30 | up = v / 10 31 | v = v % 10 32 | c3.Next = &ListNode{ 33 | Val: v % 10, 34 | Next: nil, 35 | } 36 | c3 = c3.Next 37 | } 38 | if up == 1 { 39 | c3.Next = &ListNode{ 40 | Val: 1, 41 | Next: nil, 42 | } 43 | } 44 | return l3.Next 45 | } 46 | -------------------------------------------------------------------------------- /leetcode-golang/design/002_两数之和_test.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestAdd(t *testing.T) { 9 | l1 := &ListNode{ 10 | Val: 2, 11 | Next: &ListNode{ 12 | Val: 4, 13 | Next: &ListNode{ 14 | Val: 3, 15 | Next: nil, 16 | }, 17 | }, 18 | } 19 | l2 := &ListNode{ 20 | Val: 5, 21 | Next: &ListNode{ 22 | Val: 6, 23 | Next: &ListNode{ 24 | Val: 7, 25 | Next: nil, 26 | }, 27 | }, 28 | } 29 | l3 := addTwoNumbers(l1, l2) 30 | fmt.Printf("%v", l3) 31 | } 32 | -------------------------------------------------------------------------------- /leetcode-golang/design/007_整数反转.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | // 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 4 | // 5 | //示例 1: 6 | // 7 | //输入: 123 8 | //输出: 321 9 | // 示例 2: 10 | // 11 | //输入: -123 12 | //输出: -321 13 | //示例 3: 14 | // 15 | //输入: 120 16 | //输出: 21 17 | //注意: 18 | // 19 | //假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231,  231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。 20 | // 21 | //来源:力扣(LeetCode) 22 | //链接:https://leetcode-cn.com/problems/reverse-integer 23 | //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | 25 | // golang 取模运算的结果符号与原数相同, 所以不需要单独判断x的正负性 26 | func reverse(x int) int { 27 | res := 0 28 | for x != 0 { 29 | res = res*10 + x%10 30 | x = x / 10 31 | } 32 | if res < -(1<<31) || res > ((1<<31)-1) { 33 | return 0 34 | } 35 | return res 36 | } 37 | -------------------------------------------------------------------------------- /leetcode-golang/design/009_回文数.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | // 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 4 | // 5 | //示例 1: 6 | // 7 | //输入: 121 8 | //输出: true 9 | //示例 2: 10 | // 11 | //输入: -121 12 | //输出: false 13 | //解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 14 | //示例 3: 15 | // 16 | //输入: 10 17 | //输出: false 18 | //解释: 从右向左读, 为 01 。因此它不是一个回文数。 19 | 20 | /* 21 | * @lc app=leetcode.cn id=9 lang=golang 22 | * 23 | * [9] 回文数 24 | */ 25 | 26 | // @lc code=start 27 | func isPalindrome(x int) bool { 28 | if x < 0 { 29 | return false 30 | } 31 | n := x 32 | x1 := 0 33 | for n > 0 { 34 | x1 = x1*10 + n%10 35 | n /= 10 36 | } 37 | return x == x1 38 | } 39 | 40 | // @lc code=end 41 | -------------------------------------------------------------------------------- /leetcode-golang/design/015_三数之和.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | import "sort" 4 | 5 | // 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 6 | // 7 | //注意:答案中不可以包含重复的三元组。 8 | // 9 | // 10 | // 11 | //示例: 12 | // 13 | //给定数组 nums = [-1, 0, 1, 2, -1, -4], 14 | // 15 | //满足要求的三元组集合为: 16 | //[ 17 | // [-1, 0, 1], 18 | // [-1, -1, 2] 19 | //] 20 | 21 | func threeSum(nums []int) [][]int { 22 | var ans [][]int 23 | sort.Ints(nums) 24 | for i, _ := range nums { 25 | if i == 0 || nums[i] > nums[i-1] { 26 | l := i + 1 27 | r := len(nums) - 1 28 | for l < r { 29 | s := nums[i] + nums[l] + nums[r] 30 | if s == 0 { 31 | ans = append(ans, []int{nums[i], nums[l], nums[r]}) 32 | l++ 33 | r-- 34 | for l < r && (nums[l] == nums[l-1]) { 35 | l++ 36 | } 37 | for l < r && (nums[r] == nums[r+1]) { 38 | r-- 39 | } 40 | } else if s > 0 { 41 | r-- 42 | } else { 43 | l++ 44 | } 45 | } 46 | } 47 | } 48 | return ans 49 | } 50 | -------------------------------------------------------------------------------- /leetcode-golang/design/015_三数之和_test.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | import "testing" 4 | 5 | func TestThreeSum(t *testing.T) { 6 | sums := []int{ 7 | -1, 0, 1, 2, -1, -4, 8 | } 9 | ans := threeSum(sums) 10 | t.Log(ans) 11 | } 12 | -------------------------------------------------------------------------------- /leetcode-golang/design/026_删除数组中的重复项.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | // 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 4 | // 5 | //不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 6 | // 7 | // 8 | // 9 | //示例 1: 10 | // 11 | //给定数组 nums = [1,1,2], 12 | // 13 | //函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 14 | // 15 | //你不需要考虑数组中超出新长度后面的元素。 16 | //示例 2: 17 | // 18 | //给定 nums = [0,0,1,1,1,2,2,3,3,4], 19 | // 20 | //函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 21 | // 22 | //你不需要考虑数组中超出新长度后面的元素。 23 | 24 | func removeDuplicates(nums []int) int { 25 | // 保存点 26 | if len(nums) < 2 { 27 | return len(nums) 28 | } 29 | c := 1 30 | for i := 1; i < len(nums); i++ { 31 | if nums[i] != nums[i-1] { 32 | nums[c] = nums[i] 33 | c++ 34 | } 35 | } 36 | return c 37 | } 38 | -------------------------------------------------------------------------------- /leetcode-golang/design/027_移除元素.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | // 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 4 | // 5 | //不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 6 | // 7 | //元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 8 | // 9 | // 10 | // 11 | //示例 1: 12 | // 13 | //给定 nums = [3,2,2,3], val = 3, 14 | // 15 | //函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 16 | // 17 | //你不需要考虑数组中超出新长度后面的元素。 18 | //示例 2: 19 | // 20 | //给定 nums = [0,1,2,2,3,0,4,2], val = 2, 21 | // 22 | //函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 23 | // 24 | //注意这五个元素可为任意顺序。 25 | // 26 | //你不需要考虑数组中超出新长度后面的元素。 27 | 28 | func removeElement(nums []int, val int) int { 29 | cur := 0 30 | for i := 0; i < len(nums); i++ { 31 | if nums[i] != val { 32 | nums[cur] = nums[i] 33 | cur++ 34 | } 35 | } 36 | return cur 37 | } 38 | -------------------------------------------------------------------------------- /leetcode-golang/design/053_最大子序和.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | import "math" 4 | 5 | // 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 6 | // 7 | //示例: 8 | // 9 | //输入: [-2,1,-3,4,-1,2,1,-5,4], 10 | //输出: 6 11 | //解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 12 | //进阶: 13 | // 14 | //如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 15 | // 16 | //来源:力扣(LeetCode) 17 | //链接:https://leetcode-cn.com/problems/maximum-subarray 18 | //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 19 | 20 | func maxSubArray(nums []int) int { 21 | res := nums[0] 22 | sum := 0 23 | for _, num := range nums { 24 | if sum > 0 { 25 | sum += num 26 | } else { 27 | sum = num 28 | } 29 | res = int(math.Max(float64(res), float64(sum))) 30 | } 31 | return res 32 | } 33 | -------------------------------------------------------------------------------- /leetcode-golang/design/069_x的平方根.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | func mySqrt(x int) int { 4 | if x == 0 { 5 | return 0 6 | } 7 | if x < 4 { 8 | return 1 9 | } 10 | l := 2 11 | r := x - 1 12 | for l < r { 13 | m := (r-l)/2 + l 14 | mul := m * m 15 | if mul == x { 16 | return m 17 | } else if mul < x { 18 | l = m + 1 19 | } else { 20 | r = m - 1 21 | } 22 | } 23 | if l*l > x { 24 | return l - 1 25 | } else { 26 | return l 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /leetcode-golang/dynamic/070_爬楼梯.go: -------------------------------------------------------------------------------- 1 | package dynamic 2 | 3 | func climbStairs(n int) int { 4 | // dp[1] = 1 5 | // dp[2] = 2 6 | // dp[n] = dp[n - 1] + dp[n - 2] 7 | if n == 1 { 8 | return 1 9 | } 10 | d1 := 1 11 | d2 := 2 12 | for i := 3; i <= n; i++ { 13 | d2, d1 = d1+d2, d2 14 | } 15 | return d2 16 | } 17 | -------------------------------------------------------------------------------- /leetcode-golang/dynamic/121_买卖股票的最佳时机.go: -------------------------------------------------------------------------------- 1 | package dynamic 2 | 3 | import "math" 4 | 5 | func maxProfit(prices []int) int { 6 | res := 0 7 | min := prices[0] 8 | for i := 1; i < len(prices); i++ { 9 | if prices[i] > min { 10 | res = int(math.Max(float64(res), float64(prices[i]-min))) 11 | } else { 12 | min = prices[i] 13 | } 14 | } 15 | return res 16 | } 17 | -------------------------------------------------------------------------------- /leetcode-golang/dynamic/122_买卖股票的最佳时机.go: -------------------------------------------------------------------------------- 1 | package dynamic 2 | 3 | import "math" 4 | 5 | func maxProfit2(prices []int) int { 6 | if len(prices) < 2 { 7 | return 0 8 | } 9 | min := prices[0] 10 | sum := 0 11 | for i := 1; i < len(prices); i++ { 12 | if prices[i] > min { 13 | sum += prices[i] - min 14 | min = prices[i] 15 | } else { 16 | min = int(math.Min(float64(min), float64(prices[i]))) 17 | } 18 | } 19 | return sum 20 | } 21 | func maxProfit3(prices []int) int { 22 | sum := 0 23 | for i := 1; i < len(prices); i++ { 24 | if t := prices[i] - prices[i-1]; t > 0 { 25 | sum += t 26 | } 27 | } 28 | return sum 29 | } 30 | -------------------------------------------------------------------------------- /leetcode-golang/list/021_合并两个有序链表.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | //将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 4 | // 5 | //示例: 6 | // 7 | //输入:1->2->4, 1->3->4 8 | //输出:1->1->2->3->4->4 9 | 10 | type ListNode struct { 11 | Val int 12 | Next *ListNode 13 | } 14 | 15 | func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { 16 | res := &ListNode{ 17 | Val: 0, 18 | Next: nil, 19 | } 20 | cur := res 21 | for l1 != nil && l2 != nil { 22 | if l1.Val < l2.Val { 23 | cur.Next = l1 24 | l1 = l1.Next 25 | } else { 26 | cur.Next = l2 27 | l2 = l2.Next 28 | } 29 | cur = cur.Next 30 | } 31 | if l1 != nil { 32 | cur.Next = l1 33 | } 34 | if l2 != nil { 35 | cur.Next = l2 36 | } 37 | return res.Next 38 | } 39 | -------------------------------------------------------------------------------- /leetcode-golang/list/066_加一.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | // 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 4 | // 5 | //最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 6 | // 7 | //你可以假设除了整数 0 之外,这个整数不会以零开头。 8 | // 9 | //示例 1: 10 | // 11 | //输入: [1,2,3] 12 | //输出: [1,2,4] 13 | //解释: 输入数组表示数字 123。 14 | //示例 2: 15 | // 16 | //输入: [4,3,2,1] 17 | //输出: [4,3,2,2] 18 | //解释: 输入数组表示数字 4321。 19 | 20 | func plusOne(digits []int) []int { 21 | up := 1 22 | for i := len(digits) - 1; i >= 0; i-- { 23 | if up == 0 { 24 | break 25 | } 26 | t := digits[i] + up 27 | digits[i] = t % 10 28 | up = t / 10 29 | } 30 | if up != 0 { 31 | digits = append([]int{1}, digits...) 32 | } 33 | return digits 34 | } 35 | -------------------------------------------------------------------------------- /leetcode-golang/list/083_删除排序链表中重复的元素.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | func deleteDuplicates(head *ListNode) *ListNode { 4 | if head == nil { 5 | return nil 6 | } 7 | prev := head 8 | cur := head.Next 9 | for cur != nil { 10 | if cur.Val == prev.Val { 11 | // 删除 cur 节点 12 | prev.Next = cur.Next 13 | cur = prev.Next 14 | } else { 15 | prev = cur 16 | cur = cur.Next 17 | } 18 | } 19 | return head 20 | } 21 | -------------------------------------------------------------------------------- /leetcode-golang/list/160_相交链表.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | func getIntersectionNode(headA, headB *ListNode) *ListNode { 4 | cA := headA 5 | cB := headB 6 | changeA := false 7 | changeB := false 8 | for cA != nil && cB != nil { 9 | if cA == cB { 10 | return cA 11 | } 12 | cA = cA.Next 13 | cB = cB.Next 14 | if cA == nil && !changeA { 15 | changeA = true 16 | cA = headB 17 | } 18 | if cB == nil && !changeB { 19 | changeB = true 20 | cB = headA 21 | } 22 | } 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /leetcode-golang/search/035_搜索插入位置.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | // 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 4 | // 5 | //你可以假设数组中无重复元素。 6 | // 7 | //示例 1: 8 | // 9 | //输入: [1,3,5,6], 5 10 | //输出: 2 11 | //示例 2: 12 | // 13 | //输入: [1,3,5,6], 2 14 | //输出: 1 15 | //示例 3: 16 | // 17 | //输入: [1,3,5,6], 7 18 | //输出: 4 19 | //示例 4: 20 | // 21 | //输入: [1,3,5,6], 0 22 | //输出: 0 23 | 24 | func searchInsert(nums []int, target int) int { 25 | // 二分法找位置 26 | l := 0 27 | r := len(nums) - 1 28 | for l < r { 29 | m := l + (r-l)/2 30 | if nums[m] == target { 31 | return m 32 | } else if nums[m] > target { 33 | r = m - 1 34 | } else { 35 | l = m + 1 36 | } 37 | } 38 | if target > nums[l] { 39 | return l + 1 40 | } else { 41 | return l 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /leetcode-golang/search/038_最大子序和.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | //给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 8 | // 9 | //示例: 10 | // 11 | //输入: [-2,1,-3,4,-1,2,1,-5,4], 12 | //输出: 6 13 | //解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 14 | //进阶: 15 | // 16 | //如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 17 | 18 | func maxSubArray(nums []int) int { 19 | // dp[i] = max(nums[i], nums[i-1] + nums[i]) 20 | if len(nums) < 1 { 21 | return 0 22 | } 23 | max := nums[0] 24 | for i := 1; i < len(nums); i++ { 25 | nums[i] = int(math.Max(float64(nums[i]), float64(nums[i]+nums[i-1]))) 26 | max = int(math.Max(float64(max), float64(nums[i]))) 27 | } 28 | return max 29 | } 30 | -------------------------------------------------------------------------------- /leetcode-golang/stack/020_有效的括号.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | // 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 4 | // 5 | //有效字符串需满足: 6 | // 7 | //左括号必须用相同类型的右括号闭合。 8 | //左括号必须以正确的顺序闭合。 9 | //注意空字符串可被认为是有效字符串。 10 | // 11 | //示例 1: 12 | // 13 | //输入: "()" 14 | //输出: true 15 | //示例 2: 16 | // 17 | //输入: "()[]{}" 18 | //输出: true 19 | //示例 3: 20 | // 21 | //输入: "(]" 22 | //输出: false 23 | //示例 4: 24 | // 25 | //输入: "([)]" 26 | //输出: false 27 | //示例 5: 28 | // 29 | //输入: "{[]}" 30 | //输出: true 31 | // 32 | //来源:力扣(LeetCode) 33 | //链接:https://leetcode-cn.com/problems/valid-parentheses 34 | //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 35 | 36 | func isValid(s string) bool { 37 | stack := []string{} 38 | m := map[string]string{ 39 | ")": "(", 40 | "]": "[", 41 | "}": "{", 42 | } 43 | sLenDiv2 := len(s) >> 1 44 | for _, v := range s { 45 | c := string(v) 46 | if c == "(" || c == "[" || c == "{" { 47 | stack = append(stack, c) 48 | } else { 49 | if len(stack) == 0 { 50 | return false 51 | } 52 | if stack[len(stack)-1] != m[c] { 53 | return false 54 | } 55 | stack = stack[:len(stack)-1] 56 | } 57 | if len(stack) > sLenDiv2 { 58 | return false 59 | } 60 | } 61 | return len(stack) == 0 62 | } 63 | -------------------------------------------------------------------------------- /leetcode-golang/stack/155_最小栈.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | type MinStack struct { 4 | Nodes []Node 5 | } 6 | 7 | type Node struct { 8 | Val int 9 | Min int 10 | } 11 | 12 | 13 | /** initialize your data structure here. */ 14 | func Constructor() MinStack { 15 | return MinStack{ 16 | Nodes: []Node{}, 17 | } 18 | } 19 | 20 | 21 | func (this *MinStack) Push(x int) { 22 | var node Node 23 | node.Val = x 24 | if len(this.Nodes) == 0 { 25 | node.Min = x 26 | } else { 27 | node.Min = int(math.Min(float64(this.Nodes[len(this.Nodes) - 1].Min), float64(x))) 28 | } 29 | this.Nodes = append(this.Nodes, node) 30 | } 31 | 32 | 33 | func (this *MinStack) Pop() { 34 | if len(this.Nodes) > 0 { 35 | this.Nodes = this.Nodes[:len(this.Nodes)-1] 36 | } 37 | } 38 | 39 | 40 | func (this *MinStack) Top() int { 41 | if len(this.Nodes) == 0 { 42 | return 0 43 | } 44 | return this.Nodes[len(this.Nodes)-1].Val 45 | } 46 | 47 | 48 | func (this *MinStack) GetMin() int { 49 | if len(this.Nodes) == 0 { 50 | return 0 51 | } 52 | return this.Nodes[len(this.Nodes)-1].Min 53 | } 54 | 55 | 56 | /** 57 | * Your MinStack object will be instantiated and called as such: 58 | * obj := Constructor(); 59 | * obj.Push(x); 60 | * obj.Pop(); 61 | * param_3 := obj.Top(); 62 | * param_4 := obj.GetMin(); 63 | */ -------------------------------------------------------------------------------- /leetcode-golang/string/028_实现str_str.go: -------------------------------------------------------------------------------- 1 | package string 2 | 3 | // 实现 strStr() 函数。 4 | // 5 | //给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。 6 | // 7 | //示例 1: 8 | // 9 | //输入: haystack = "hello", needle = "ll" 10 | //输出: 2 11 | //示例 2: 12 | // 13 | //输入: haystack = "aaaaa", needle = "bba" 14 | //输出: -1 15 | //说明: 16 | // 17 | //当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 18 | // 19 | //对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 20 | 21 | func strStr(haystack string, needle string) int { 22 | if len(needle) == 0 { 23 | return 0 24 | } 25 | for i := 0; i <= len(haystack)-len(needle); i++ { 26 | for j := 0; j < len(needle); j++ { 27 | if needle[j] != haystack[i+j] { 28 | break 29 | } 30 | if j == len(needle)-1 { 31 | return i 32 | } 33 | } 34 | } 35 | return -1 36 | } 37 | -------------------------------------------------------------------------------- /leetcode-golang/string/038-外观数列.go: -------------------------------------------------------------------------------- 1 | package string 2 | 3 | import "fmt" 4 | 5 | // 「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下: 6 | // 7 | //1. 1 8 | //2. 11 9 | //3. 21 10 | //4. 1211 11 | //5. 111221 12 | //1 被读作 "one 1" ("一个一") , 即 11。 13 | //11 被读作 "two 1s" ("两个一"), 即 21。 14 | //21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。 15 | // 16 | //给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。 17 | // 18 | //注意:整数序列中的每一项将表示为一个字符串。 19 | // 20 | // 21 | // 22 | //示例 1: 23 | // 24 | //输入: 1 25 | //输出: "1" 26 | //解释:这是一个基本样例。 27 | //示例 2: 28 | // 29 | //输入: 4 30 | //输出: "1211" 31 | //解释:当 n = 3 时,序列是 "21",其中我们有 "2" 和 "1" 两组,"2" 可以读作 "12",也就是出现频次 = 1 而 值 = 2;类似 "1" 可以读作 "11"。所以答案是 "12" 和 "11" 组合在一起,也就是 "1211"。 32 | 33 | func countAndSay(n int) string { 34 | res := "1" 35 | for ; n > 1; n-- { 36 | res = say(res) 37 | } 38 | return res 39 | } 40 | 41 | func say(s string) string { 42 | count := 1 43 | c := s[0] 44 | res := "" 45 | for i := 1; i < len(s); i++ { 46 | if c == s[i] { 47 | count++ 48 | } else { 49 | res = fmt.Sprintf("%s%d%s", res, count, string(c)) 50 | count = 1 51 | c = s[i] 52 | } 53 | } 54 | res = fmt.Sprintf("%s%d%s", res, count, string(c)) 55 | return res 56 | } 57 | -------------------------------------------------------------------------------- /leetcode-golang/string/058_最后一个单词的长度.go: -------------------------------------------------------------------------------- 1 | package string 2 | 3 | import "strings" 4 | 5 | // 给定一个仅包含大小写字母和空格 ' ' 的字符串 s,返回其最后一个单词的长度。如果字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词。 6 | // 7 | //如果不存在最后一个单词,请返回 0 。 8 | // 9 | //说明:一个单词是指仅由字母组成、不包含任何空格字符的 最大子字符串。 10 | // 11 | //来源:力扣(LeetCode) 12 | //链接:https://leetcode-cn.com/problems/length-of-last-word 13 | //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 14 | 15 | func lengthOfLastWord(s string) int { 16 | s = strings.Trim(s, " ") 17 | count := 0 18 | for _, c := range s { 19 | if string(c) == " " { 20 | count = 0 21 | } else { 22 | count++ 23 | } 24 | } 25 | return count 26 | } 27 | -------------------------------------------------------------------------------- /leetcode-golang/string/067_二进制求和.go: -------------------------------------------------------------------------------- 1 | package string 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | func addBinary(a string, b string) string { 10 | if len(a) < len(b) { 11 | a = fmt.Sprintf("%s%s", strings.Repeat("0", len(b)-len(a)), a) 12 | } else { 13 | b = fmt.Sprintf("%s%s", strings.Repeat("0", len(a)-len(b)), b) 14 | } 15 | up := int64(0) 16 | ans := "" 17 | for i := len(a) - 1; i >= 0; i-- { 18 | n1, _ := strconv.ParseInt(string(a[i]), 10, 64) 19 | n2, _ := strconv.ParseInt(string(b[i]), 10, 64) 20 | t := n1 + n2 + up 21 | ans = strings.Join([]string{strconv.Itoa(int(t % 2)), ans}, "") 22 | up = t / 2 23 | } 24 | if up != 0 { 25 | return strings.Join([]string{"1", ans}, "") 26 | } 27 | return ans 28 | } 29 | -------------------------------------------------------------------------------- /leetcode-golang/string/125_验证回文字符串.go: -------------------------------------------------------------------------------- 1 | package string 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func isPalindrome(s string) bool { 9 | if s == "" { 10 | return true 11 | } 12 | l := 0 13 | r := len(s) - 1 14 | for l < r { 15 | for l < r && !allowChr(s[l]) { 16 | l++ 17 | } 18 | for l < r && !allowChr(s[r]) { 19 | r-- 20 | } 21 | fmt.Printf("%s:%s", string(s[l]), string(s[r])) 22 | fmt.Printf("%d:%d", s[l], s[r]) 23 | if strings.ToLower(string(s[l])) != strings.ToLower(string(s[r])) { 24 | return false 25 | } 26 | l++ 27 | r-- 28 | } 29 | return true 30 | } 31 | 32 | func allowChr(c uint8) bool { 33 | if 48 <= c && c <= 57 { 34 | return true 35 | } 36 | if 65 <= c && c <= 90 { 37 | return true 38 | } 39 | if 97 <= c && c <= 122 { 40 | return true 41 | } 42 | return false 43 | } 44 | -------------------------------------------------------------------------------- /leetcode-golang/tree/100_相同的树.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | func isSameTree(p *TreeNode, q *TreeNode) bool { 4 | // 结束条件 5 | if p == nil && q == nil { 6 | return true 7 | } else if p == nil || q == nil { 8 | return false 9 | } else { 10 | return p.Val == q.Val && isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right) 11 | } 12 | } 13 | 14 | // 非递归 15 | func isSameTree2(p *TreeNode, q *TreeNode) bool { 16 | // 先序遍历 17 | type s struct { 18 | p1 *TreeNode 19 | p2 *TreeNode 20 | } 21 | stack := []s{ 22 | { 23 | p1: p, 24 | p2: q, 25 | }, 26 | } 27 | for len(stack) > 0 { 28 | i := stack[0] 29 | stack = stack[1:] 30 | if i.p1 == nil && i.p2 == nil { 31 | continue 32 | } else if i.p1 == nil || i.p2 == nil { 33 | return false 34 | } else if i.p1.Val != i.p2.Val { 35 | return false 36 | } else { 37 | stack = append(stack, s{ 38 | p1: i.p1.Left, 39 | p2: i.p2.Left, 40 | }) 41 | stack = append(stack, s{ 42 | p1: i.p1.Right, 43 | p2: i.p2.Right, 44 | }) 45 | } 46 | } 47 | return true 48 | } 49 | -------------------------------------------------------------------------------- /leetcode-golang/tree/101_对称二叉树.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | func isSymmetric(root *TreeNode) bool { 4 | if root == nil { 5 | return true 6 | } 7 | return helper(root.Left, root.Right) 8 | } 9 | 10 | func helper(t1 *TreeNode, t2 *TreeNode) bool { 11 | if t1 == nil && t2 == nil { 12 | return true 13 | } 14 | if t1 == nil || t2 == nil { 15 | return false 16 | } 17 | return t1.Val == t2.Val && helper(t1.Left, t2.Right) && helper(t1.Right, t2.Left) 18 | } 19 | 20 | func isSymmetric2(root *TreeNode) bool { 21 | // 层序遍历 22 | if root == nil { 23 | return true 24 | } 25 | stack := []*TreeNode{root} 26 | for len(stack) > 0 { 27 | l := len(stack) 28 | for i := 0; i < l; i++ { 29 | j := l - i - 1 // 对称位置 30 | if stack[i] == nil && stack[j] == nil { 31 | continue 32 | } else if stack[i] == nil || stack[j] == nil { 33 | return false 34 | } else if stack[i].Val != stack[j].Val { 35 | return false 36 | } else { 37 | stack = append(stack, stack[i].Left) 38 | stack = append(stack, stack[i].Right) 39 | } 40 | } 41 | stack = stack[l:] 42 | } 43 | return true 44 | } 45 | -------------------------------------------------------------------------------- /leetcode-golang/tree/104_二叉树的最大深度.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import "math" 4 | 5 | func maxDepth(root *TreeNode) int { 6 | // 终止条件 7 | if root == nil { 8 | return 0 9 | } 10 | if root.Left == nil && root.Right == nil { 11 | return 1 12 | } 13 | // 返回 max(left, right) + 1, 为当前层的最高层数 14 | return int(math.Max(float64(maxDepth(root.Left)), float64(maxDepth(root.Right)))) + 1 15 | } 16 | 17 | func maxDepth2(root *TreeNode) int { 18 | // 深度优先遍历 19 | max := 0 20 | type s struct { 21 | Depth int 22 | Root *TreeNode 23 | } 24 | stack := []s{ 25 | { 26 | Depth: 0, 27 | Root: root, 28 | }, 29 | } 30 | for len(stack) > 0 { 31 | node := stack[len(stack)-1] 32 | stack = stack[:len(stack)-1] 33 | if node.Root != nil { 34 | max = int(math.Max(float64(node.Depth+1), float64(max))) 35 | if node.Root.Right != nil { 36 | stack = append(stack, s{ 37 | Depth: node.Depth + 1, 38 | Root: node.Root.Right, 39 | }) 40 | } 41 | if node.Root.Left != nil { 42 | stack = append(stack, s{ 43 | Depth: node.Depth + 1, 44 | Root: node.Root.Left, 45 | }) 46 | } 47 | } 48 | } 49 | return max 50 | } 51 | -------------------------------------------------------------------------------- /leetcode-golang/tree/107_二叉树的层次遍历II.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | func levelOrderBottom(root *TreeNode) [][]int { 4 | var ans [][]int 5 | if root == nil { 6 | return ans 7 | } 8 | queue := []*TreeNode{root} 9 | for len(queue) > 0 { 10 | l := len(queue) 11 | var levelData []int 12 | for i := 0; i < l; i++ { 13 | node := queue[0] 14 | queue = queue[1:] 15 | levelData = append(levelData, node.Val) 16 | if node.Left != nil { 17 | queue = append(queue, node.Left) 18 | } 19 | if node.Right != nil { 20 | queue = append(queue, node.Right) 21 | } 22 | } 23 | ans = append([][]int{levelData}, ans...) 24 | } 25 | return ans 26 | } 27 | -------------------------------------------------------------------------------- /leetcode-golang/tree/110_平衡二叉树.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import "math" 4 | 5 | func isBalanced(root *TreeNode) bool { 6 | if root == nil { 7 | return true 8 | } 9 | queue := []*TreeNode{root} 10 | for len(queue) > 0 { 11 | shift := queue[0] 12 | queue = queue[1:] 13 | if math.Abs(float64(height(shift.Left)-height(shift.Right))) > 1 { 14 | return false 15 | } 16 | if shift.Left != nil { 17 | queue = append(queue, shift.Left) 18 | } 19 | if shift.Right != nil { 20 | queue = append(queue, shift.Right) 21 | } 22 | } 23 | return true 24 | } 25 | 26 | func height(node *TreeNode) int { 27 | if node == nil { 28 | return 0 29 | } 30 | return int(math.Max(float64(height(node.Left)), float64(height(node.Right)))) + 1 31 | } 32 | -------------------------------------------------------------------------------- /leetcode-golang/tree/111_二叉树的最小深度.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import "math" 4 | 5 | func minDepth(root *TreeNode) int { 6 | if root == nil { 7 | return 0 8 | } 9 | // left 不参与比较 10 | if root.Left == nil && root.Right != nil { 11 | return 1 + minDepth(root.Right) 12 | } 13 | // right 不参与比较 14 | if root.Left != nil && root.Right == nil { 15 | return 1 + minDepth(root.Left) 16 | } 17 | return int(math.Min(float64(minDepth(root.Left)), float64(minDepth(root.Right)))) + 1 18 | } 19 | -------------------------------------------------------------------------------- /leetcode-golang/tree/112_路径总和.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | func hasPathSum(root *TreeNode, sum int) bool { 4 | if root == nil { 5 | return false 6 | } 7 | type t struct { 8 | Node *TreeNode 9 | Sum int 10 | } 11 | stack := []t{ 12 | { 13 | Node: root, 14 | Sum: root.Val, 15 | }, 16 | } 17 | for len(stack) > 0 { 18 | n := stack[len(stack)-1] 19 | stack = stack[:len(stack)-1] 20 | if n.Node.Left == nil && n.Node.Right == nil && n.Sum == sum { 21 | return true 22 | } 23 | if n.Node.Right != nil { 24 | stack = append(stack, t{ 25 | Node: n.Node.Right, 26 | Sum: n.Sum + n.Node.Right.Val, 27 | }) 28 | } 29 | if n.Node.Left != nil { 30 | stack = append(stack, t{ 31 | Node: n.Node.Left, 32 | Sum: n.Sum + n.Node.Left.Val, 33 | }) 34 | } 35 | } 36 | return false 37 | } 38 | -------------------------------------------------------------------------------- /leetcode-golang/tree/118_杨辉三角.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | func generate(numRows int) [][]int { 4 | ans := [][]int{ 5 | {1}, 6 | {1, 1}, 7 | } 8 | if numRows < 1 { 9 | return [][]int{} 10 | } 11 | if numRows == 1 { 12 | return [][]int{{1}} 13 | } 14 | for len(ans) < numRows { 15 | l := len(ans) 16 | t := []int{} 17 | for i := 0; i <= l; i++ { 18 | if i == 0 || i == l { 19 | t = append(t, 1) 20 | } else { 21 | t = append(t, ans[l-1][i-1]+ans[l-1][i]) 22 | } 23 | } 24 | ans = append(ans, t) 25 | } 26 | return ans 27 | } 28 | -------------------------------------------------------------------------------- /leetcode-golang/tree/119_杨辉三角 II.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | func getRow(rowIndex int) []int { 4 | if rowIndex < 0 { 5 | return []int{} 6 | } 7 | ans := []int{} 8 | for len(ans) <= rowIndex { 9 | t := []int{} 10 | l := len(ans) 11 | for i := 0; i <= l; i++ { 12 | if i == 0 || i == l { 13 | t = append(t, 1) 14 | } else { 15 | t = append(t, ans[i-1]+ans[i]) 16 | } 17 | } 18 | ans = t 19 | } 20 | return ans 21 | } 22 | -------------------------------------------------------------------------------- /leetcode-golang/tree/tree.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | type TreeNode struct { 4 | Val int 5 | Left *TreeNode 6 | Right *TreeNode 7 | } 8 | -------------------------------------------------------------------------------- /leetcode/Map/Map.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhan3333/note/1610b236fa253cc4004dc44ab7440b8584c6b6a0/leetcode/Map/Map.md -------------------------------------------------------------------------------- /leetcode/Top 100/226_翻转二叉树.php: -------------------------------------------------------------------------------- 1 | right; 43 | $root->right = $this->invertTree($root->left); 44 | $root->left = $this->invertTree($right); 45 | return $root; 46 | } 47 | } -------------------------------------------------------------------------------- /leetcode/Top 100/538_把二叉搜索数转换为累加树.php: -------------------------------------------------------------------------------- 1 | convertBST($root->right); 36 | $root->val += $this->sum; 37 | $this->sum = $root->val; 38 | $this->convertBST($root->left); 39 | } 40 | return $root; 41 | } 42 | 43 | 44 | } -------------------------------------------------------------------------------- /leetcode/Top 100/543_二叉树的直径.php: -------------------------------------------------------------------------------- 1 | deep($root); 37 | return $this->ans; 38 | } 39 | 40 | /** 41 | * 返回节点的最大深度 42 | * @param $node 43 | * @return int|mixed 44 | */ 45 | function deep($node) 46 | { 47 | if ($node === null) { 48 | return -1; 49 | } 50 | $left = $node->left ? $this->deep($node->left) + 1 : 0; 51 | $right = $node->right ? $this->deep($node->right) + 1 : 0; 52 | $this->ans = max($left + $right, $this->ans); 53 | return max($left, $right); 54 | } 55 | } -------------------------------------------------------------------------------- /leetcode/Top 100/easy/001_两数之和.php: -------------------------------------------------------------------------------- 1 | center, 则 start = center + 1 14 | 1.3. target < center, 则 end = center - 1 15 | 2. 循环条件: start < end 16 | 17 | ## 优势 18 | 19 | 遍历查找时间复杂度: O(n) 20 | 二分查找时间复杂度: O(logn) 21 | 22 | 在数据量很大的时候, 性能相差很明显 -------------------------------------------------------------------------------- /leetcode/二叉搜索树/二叉搜索树.md: -------------------------------------------------------------------------------- 1 | # 二叉搜索树 (Binary Search Tree) (BST) 2 | 3 | ## 二叉搜索树特点 4 | 5 | 1. 对每一个节点, 若左子树不为空, 则左子树所有节点的值均小于根节点的值. 若右子树不为空, 则右子树的所有节点的值都大于根节点的值 6 | 2. 左右子树也为二叉搜索树 7 | 8 | ## 有序数组转二叉搜索树 9 | 10 | - 使用递归, 取数组的中点作为树的根节点, 左右两边分别为树左右子树, 依次下行 -------------------------------------------------------------------------------- /leetcode/位运算/190_颠倒二进制位.php: -------------------------------------------------------------------------------- 1 | >= 1; 35 | } 36 | return $ans; 37 | } 38 | } 39 | 40 | $s = new Solution(); 41 | 42 | var_dump($s->reverseBits(43261596)); // 964176192 -------------------------------------------------------------------------------- /leetcode/位运算/231_2的幂.php: -------------------------------------------------------------------------------- 1 | 0) { 43 | if ($n === 1) { 44 | return true; 45 | } 46 | if ($n >> 1 !== $n / 2) { 47 | return false; 48 | } 49 | $n >>= 1; 50 | } 51 | return false; 52 | } 53 | } 54 | 55 | $s = new Solution(); 56 | var_dump($s->isPowerOfTwo(1)); // true 57 | var_dump($s->isPowerOfTwo(8)); // true 58 | var_dump($s->isPowerOfTwo(9)); // false 59 | var_dump($s->isPowerOfTwo(16)); // true 60 | var_dump($s->isPowerOfTwo(218)); // false -------------------------------------------------------------------------------- /leetcode/位运算/268_缺失的数字.php: -------------------------------------------------------------------------------- 1 | missingNumber([9, 6, 4, 2, 3, 5, 7, 0, 1])); // 8 -------------------------------------------------------------------------------- /leetcode/位运算/371_两整数之和.php: -------------------------------------------------------------------------------- 1 | getSum($sum, $carry); 34 | } 35 | return $sum; 36 | } 37 | } 38 | 39 | $s = new Solution(); 40 | 41 | var_dump($s->getSum(1, 2)); // 3 42 | var_dump($s->getSum(-2, 3)); // 1 -------------------------------------------------------------------------------- /leetcode/位运算/461_汉明距离.php: -------------------------------------------------------------------------------- 1 | 0) { 42 | if ($sum % 2 === 1) { 43 | $count++; 44 | } 45 | $sum >>= 1; 46 | } 47 | return $count; 48 | } 49 | } 50 | 51 | $s = new Solution(); 52 | 53 | var_dump($s->hammingDistance(1, 4)); // 2 -------------------------------------------------------------------------------- /leetcode/其它/有趣的两位数.php: -------------------------------------------------------------------------------- 1 | funTwoNum()); -------------------------------------------------------------------------------- /leetcode/其它/游戏币组合.php: -------------------------------------------------------------------------------- 1 | backtrace($m, $n, $trace, $ans); 15 | return count($ans); 16 | } 17 | 18 | function backtrace($m, $n, $trace, &$ans) 19 | { 20 | $sum = array_sum($trace); 21 | $count = count($trace); 22 | if ($sum > $m || $count > $n) { 23 | return; 24 | } 25 | if ($sum === $m && $count === $n) { 26 | sort($trace); 27 | if (!in_array($trace, $ans, false)) { 28 | $ans[] = $trace; 29 | } 30 | return; 31 | } 32 | $arr = [1, 2, 5, 10]; 33 | for ($i = 0; $i < 4; $i++) { 34 | $trace[] = $arr[$i]; 35 | $this->backtrace($m, $n, $trace, $ans); 36 | array_pop($trace); 37 | } 38 | } 39 | } 40 | 41 | 42 | $s = new Solution(); 43 | 44 | //var_dump($s->all(1, 1)); // 1 45 | //var_dump($s->all(3, 3)); // 1 46 | var_dump($s->all(5, 10)); // 1 -------------------------------------------------------------------------------- /leetcode/分治法/分治法.md: -------------------------------------------------------------------------------- 1 | # 分治法 2 | 3 | ## 含义 4 | 5 | 分而治之 6 | 7 | 将原问题分解成与原问题相同但是规模更小的子问题,可以反复执行这个过程, 使得问题规模减小到可以求解为止. 8 | 9 | ## 案例 10 | 11 | 1. 快速排序 12 | 13 | 给定1000个数, 从小到大进行排序 14 | 15 | 2. 凯苏傅里叶变换算法 16 | 3. Karatsuba 大数乘法算法 17 | 18 | ## 关键点 19 | 20 | 1. 数学归纳是使用分治思想 21 | 22 | 只要出现可以用数学归纳公式来表示的大规模问题, 第一反应就是分治算法,通过特定的函数参数安排, 肯定可以套用递归结构 23 | 24 | 2. 分治思想不一定使用递归结构 25 | 26 | 递归结构是循环结构的一种, 所以分治思想也可以是循环结构 27 | 28 | 3. 分治思想的核心是如何分 29 | 30 | ## 流程 31 | 32 | - 划分问题: 整个问题划分成多个无关联的子问题 33 | - 递归求解: 递归调用求解各个子问题 34 | - 合并问题: 合并子问题的解, 形成原始问题的解 35 | 36 | ## 使用条件 37 | 38 | 1. 问题缩小到一定规模就可以很容易解决 39 | 2. 问题可以拆分成若干个小问题 40 | 3. 子问题的解可以合并成该问题的解 41 | 4. 同一层分解出来的子问题是相互独立的(子问题之间不包含公共的子问题)(非必须) 42 | 43 | 条件2, 3 是分治的前提, 即必要条件. 第4条, 对于存在公共子问题的问题, 使用分治算法会存在重复计算的问题, 使用DP较为合适 44 | 45 | ## 分治和DP的共同点和不同点 46 | 47 | ### 分治法 48 | 49 | 各子问题独立 50 | 51 | ### 动态规划 52 | 53 | 各子问题重叠 -------------------------------------------------------------------------------- /leetcode/分治算法/050_pow-x-n.php: -------------------------------------------------------------------------------- 1 | power($x, -$n); 42 | } else { 43 | return $this->power($x, $n); 44 | } 45 | } 46 | 47 | // $n > 0 48 | function power($x, $n) 49 | { 50 | if ($n === 1) { 51 | return $x; 52 | } 53 | if (($n & 1) === 1) { 54 | return $this->power($x, ($n - 1) >> 1) ** 2 * $x; 55 | } else { 56 | return $this->power($x, $n >> 1) ** 2; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /leetcode/分治算法/分治算法.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /leetcode/动态规划/062_不同路径2.php: -------------------------------------------------------------------------------- 1 | 0 ? $obstacleGrid[$i - 1][$j] : 0; 33 | $left = $j > 0 ? $obstacleGrid[$i][$j - 1] : 0; 34 | $obstacleGrid[$i][$j] = $top + $left; 35 | } 36 | } 37 | 38 | } 39 | } 40 | return $obstacleGrid[$h - 1][$w - 1]; 41 | } 42 | } 43 | // @lc code=end 44 | 45 | -------------------------------------------------------------------------------- /leetcode/动态规划/119_杨辉三角II.php: -------------------------------------------------------------------------------- 1 | getRow(3)); -------------------------------------------------------------------------------- /leetcode/动态规划/121_买卖股票的最佳时机.php: -------------------------------------------------------------------------------- 1 | maxProfit([7, 1, 5, 3, 6, 4])); // 5 -------------------------------------------------------------------------------- /leetcode/双指针/双指针.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhan3333/note/1610b236fa253cc4004dc44ab7440b8584c6b6a0/leetcode/双指针/双指针.md -------------------------------------------------------------------------------- /leetcode/哈希表/哈希表.md: -------------------------------------------------------------------------------- 1 | # 哈希表 2 | 3 | ## 关键词 4 | 5 | 1. 哈希表是一种数据结构 6 | 2. 哈希表表示了关键码和记录的映射关系 7 | 3. 哈希表可以加快查找速度 8 | 4. 哈希表通过hash函数来做映射关系 9 | 10 | ## 解决hash碰撞 11 | 12 | 1. 对于冲突的hash值, 使用链表来储存 13 | 14 | ## 负载因子 15 | 16 | 定义: hash表中已存有的元素与哈希表长度的比值, 一般 0.7-0.8 最佳 17 | -------------------------------------------------------------------------------- /leetcode/回溯算法/022_括号生成.php: -------------------------------------------------------------------------------- 1 | backtrack($ans, '', 0, 0, $n); 31 | return $ans; 32 | } 33 | 34 | function backtrack(&$ans, $cur, $open, $close, $max) 35 | { 36 | if (strlen($cur) === $max * 2) { 37 | $ans[] = $cur; 38 | return; 39 | } 40 | if ($open < $max) { 41 | $this->backtrack($ans, $cur . '(', $open + 1, $close, $max); 42 | } 43 | if ($close < $open) { 44 | $this->backtrack($ans, $cur . ')', $open, $close + 1, $max); 45 | } 46 | } 47 | } 48 | 49 | $s = new Solution(); 50 | var_dump($s->generateParenthesis(3)); -------------------------------------------------------------------------------- /leetcode/回溯算法/074_回溯算法.php: -------------------------------------------------------------------------------- 1 | backtrack($n, $k, [], 1); 39 | return $this->ans; 40 | } 41 | 42 | function backtrack($n, $k, $trace, $start) 43 | { 44 | if (count($trace) === $k) { 45 | $this->ans[] = $trace; 46 | return; 47 | } 48 | for ($i = $start; $i <= $n; $i++) { 49 | $trace[] = $i; 50 | $this->backtrack($n, $k, $trace, $i + 1); 51 | array_pop($trace); 52 | } 53 | } 54 | } 55 | // @lc code=end 56 | 57 | -------------------------------------------------------------------------------- /leetcode/回溯算法/回溯算法.md: -------------------------------------------------------------------------------- 1 | # 回溯算法 2 | 3 | ## 描述 4 | 5 | 解决一个回溯问题, 实际上就是一个决策树的遍历流程 6 | 7 | 只需要考虑三个问题: 8 | 9 | 1. 路径: 也就是已经做出的选择 10 | 2. 选择列表: 当前可以做的选择 11 | 3. 结束条件: 也就是到达决策树的树低, 无法再做出选择 12 | 13 | ## 框架 14 | 15 | ``` 16 | $result = []; 17 | function backtrack(路径, 选择列表) { 18 | if (满足结束条件) { 19 | $result[] = 路径; 20 | return; 21 | } 22 | for 选择 in 选择列表 { 23 | 做选择; 24 | backtrack(路径, 选择列表); 25 | 撤销选择; 26 | } 27 | } 28 | ``` -------------------------------------------------------------------------------- /leetcode/图/图.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhan3333/note/1610b236fa253cc4004dc44ab7440b8584c6b6a0/leetcode/图/图.md -------------------------------------------------------------------------------- /leetcode/堆/堆.md: -------------------------------------------------------------------------------- 1 | # 堆 2 | 3 | 堆的本质是一棵完全二叉树, 可以通过数组来实现堆 4 | 5 | 完全二叉树中, 可以忽略掉指针, 所有节点编号都是有规律的 6 | 7 | 给定一个节点i, 左孩子节点下标就是 2i+1, 右孩子节点的下标就是 2i+2, 所以, 可以将堆储存在数组中 8 | 9 | ## 分类 10 | 11 | ### 最小堆 12 | 13 | 对于每个节点, 都小于两个子节点 14 | 15 | dui 16 | 17 | ### 最大堆 18 | 19 | 对于每个节点, 都大于两个子节点 -------------------------------------------------------------------------------- /leetcode/字典树/字典树.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhan3333/note/1610b236fa253cc4004dc44ab7440b8584c6b6a0/leetcode/字典树/字典树.md -------------------------------------------------------------------------------- /leetcode/字符串/007_整数反转.php: -------------------------------------------------------------------------------- 1 | 2147483647 || $rev < -2147483648) ? 0 : $rev; 44 | } 45 | } 46 | 47 | $s = new Solution(); 48 | var_dump($s->reverse(321)); // 123 49 | var_dump($s->reverse(-321)); // -123 50 | var_dump($s->reverse(1534236469)); // 0 -------------------------------------------------------------------------------- /leetcode/字符串/058_最后一个单词的长度.php: -------------------------------------------------------------------------------- 1 | = 0 && $s[$end] === ' ') { 29 | $end--; 30 | } 31 | if ($end < 0) return 0; 32 | while ($end >= 0 && $s[$end] !== ' ') { 33 | $count++; 34 | $end--; 35 | } 36 | return $count; 37 | } 38 | } 39 | 40 | $s = new Solution(); 41 | var_dump($s->lengthOfLastWord('Hello World')); // 5 42 | var_dump($s->lengthOfLastWord('a')); // 1 43 | var_dump($s->lengthOfLastWord('a ')); // 1 44 | var_dump($s->lengthOfLastWord(' ')); // 0 -------------------------------------------------------------------------------- /leetcode/字符串/168_Excel表列名称.php: -------------------------------------------------------------------------------- 1 | A 8 | // 2 -> B 9 | // 3 -> C 10 | // ... 11 | // 26 -> Z 12 | // 27 -> AA 13 | // 28 -> AB 14 | // ... 15 | //示例 1: 16 | // 17 | //输入: 1 18 | //输出: "A" 19 | //示例 2: 20 | // 21 | //输入: 28 22 | //输出: "AB" 23 | //示例 3: 24 | // 25 | //输入: 701 26 | //输出: "ZY" 27 | // 28 | //来源:力扣(LeetCode) 29 | //链接:https://leetcode-cn.com/problems/excel-sheet-column-title 30 | //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 31 | 32 | class Solution 33 | { 34 | 35 | /** 36 | * 注意原理, 取模运算算出来的是最后一位, 依次向左走 37 | * @param Integer $n 38 | * @return String 39 | */ 40 | function convertToTitle($n) 41 | { 42 | if ($n <= 0) { 43 | return ''; 44 | } 45 | $ans = ''; 46 | while ($n > 0) { 47 | $n--; 48 | $ans = chr($n % 26 + 65) . $ans; 49 | $n = (int)($n / 26); 50 | } 51 | return $ans; 52 | } 53 | } 54 | 55 | $s = new Solution(); 56 | 57 | var_dump($s->convertToTitle(1)); // A 58 | var_dump($s->convertToTitle(28)); // AB 59 | var_dump($s->convertToTitle(701)); // ZY 60 | -------------------------------------------------------------------------------- /leetcode/字符串/171_Excel表列序号.php: -------------------------------------------------------------------------------- 1 | 1 8 | // B -> 2 9 | // C -> 3 10 | // ... 11 | // Z -> 26 12 | // AA -> 27 13 | // AB -> 28 14 | // ... 15 | //示例 1: 16 | // 17 | //输入: "A" 18 | //输出: 1 19 | //示例 2: 20 | // 21 | //输入: "AB" 22 | //输出: 28 23 | //示例 3: 24 | // 25 | //输入: "ZY" 26 | //输出: 701 27 | // 28 | //来源:力扣(LeetCode) 29 | //链接:https://leetcode-cn.com/problems/excel-sheet-column-number 30 | //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 31 | 32 | class Solution 33 | { 34 | 35 | /** 36 | * @param String $s 37 | * @return Integer 38 | */ 39 | function titleToNumber($s) 40 | { 41 | $sum = 0; 42 | $len = strlen($s); 43 | for ($i = 0; $i < $len; $i++) { 44 | $sum += (ord($s[$i]) - 64) * (26 ** ($len - $i - 1)); 45 | } 46 | return $sum; 47 | } 48 | } 49 | 50 | $s = new Solution(); 51 | 52 | var_dump($s->titleToNumber('A')); // 1 53 | var_dump($s->titleToNumber('AB')); // 28 54 | var_dump($s->titleToNumber('ZY')); // 701 -------------------------------------------------------------------------------- /leetcode/字符串/387_字符串中的第一个唯一字符.php: -------------------------------------------------------------------------------- 1 | = 0; $i--) { 35 | if (!isset($hash[$s[$i]])) { 36 | $hash[$s[$i]] = 0; 37 | } 38 | $hash[$s[$i]]++; 39 | } 40 | for ($i = 0; $i < $len; $i++) { 41 | if ($hash[$s[$i]] === 1) { 42 | return $i; 43 | } 44 | } 45 | return -1; 46 | } 47 | } 48 | 49 | $s = new Solution(); 50 | 51 | var_dump($s->firstUniqChar('leetcode')); // 0 52 | var_dump($s->firstUniqChar('loveleetcode')); // 2 53 | -------------------------------------------------------------------------------- /leetcode/字符串/405_数字转换为十六进制数.php: -------------------------------------------------------------------------------- 1 | >= 4; 47 | } 48 | return $ans; 49 | } 50 | } 51 | 52 | $s = new Solution(); 53 | 54 | var_dump($s->toHex(26)); 55 | var_dump($s->toHex(-1)); -------------------------------------------------------------------------------- /leetcode/字符串/415_字符串相加.php: -------------------------------------------------------------------------------- 1 | = 0 || $j >= 0 || $carry !== 0) { 34 | $n1 = $i >= 0 ? (int)$num1[$i] : 0; 35 | $n2 = $j >= 0 ? (int)$num2[$j] : 0; 36 | $sum = $n1 + $n2 + $carry; 37 | $carry = $sum > 9 ? 1 : 0; 38 | $ans = ($sum % 10) . $ans; 39 | $i--; 40 | $j--; 41 | } 42 | return $ans; 43 | } 44 | } 45 | 46 | $s = new Solution(); 47 | 48 | var_dump($s->addStrings('123', '45')); // 168 49 | var_dump($s->addStrings('9', '1')); // 10 -------------------------------------------------------------------------------- /leetcode/字符串/459_重复的字符串.php: -------------------------------------------------------------------------------- 1 | repeatedSubstringPattern('abab')); // true 45 | var_dump($s->repeatedSubstringPattern('aba')); // false 46 | var_dump($s->repeatedSubstringPattern('aaaa')); // true 47 | var_dump(substr('aaaaaaaa', 1, -1)); -------------------------------------------------------------------------------- /leetcode/字符串/557_反转字符串中的单词 III.php: -------------------------------------------------------------------------------- 1 | reverseWords("Let's take LeetCode contest")); // "s'teL ekat edoCteeL tsetnoc" -------------------------------------------------------------------------------- /leetcode/字符串/字符串.md: -------------------------------------------------------------------------------- 1 | # 字符串 2 | 3 | ## 解题方法 4 | 5 | 1. 查找最长无重复字符子串, 可以使用滑动窗口的方式 003_无重复字符的最长子串 -------------------------------------------------------------------------------- /leetcode/并差集/并差集.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhan3333/note/1610b236fa253cc4004dc44ab7440b8584c6b6a0/leetcode/并差集/并差集.md -------------------------------------------------------------------------------- /leetcode/广度优先遍历/广度优先遍历.md: -------------------------------------------------------------------------------- 1 | # 广度优先遍历 2 | 3 | ## 框架代码 4 | 5 | > 普通的遍历 6 | 7 | ``` 8 | while queue 非空: 9 | node = queue.pop() 10 | for node 的所有相邻结点 m: 11 | if m 未访问过: 12 | queue.push(m) 13 | ``` 14 | 15 | > 带层数的遍历 (找最短路径) 16 | 17 | ``` 18 | depth = 0 # 记录遍历到第几层 19 | while queue 非空: 20 | depth++ 21 | n = queue 中的元素个数 22 | 循环 n 次: 23 | node = queue.pop() 24 | for node 的所有相邻结点 m: 25 | if m 未访问过: 26 | queue.push(m) 27 | ``` -------------------------------------------------------------------------------- /leetcode/拓扑排序/拓扑排序.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhan3333/note/1610b236fa253cc4004dc44ab7440b8584c6b6a0/leetcode/拓扑排序/拓扑排序.md -------------------------------------------------------------------------------- /leetcode/排序/冒泡排序.php: -------------------------------------------------------------------------------- 1 | $nums[$j + 1]) { 26 | $tmp = $nums[$j]; 27 | $nums[$j] = $nums[$j + 1]; 28 | $nums[$j + 1] = $tmp; 29 | $isOrdered = false; 30 | $lastExchangeIndex = $j; 31 | } 32 | } 33 | $unOrderBorder = $lastExchangeIndex; 34 | if ($isOrdered) { 35 | break; 36 | } 37 | } 38 | return $nums; 39 | } 40 | } 41 | 42 | $s = new Solution(); 43 | 44 | var_dump($s->popSort([2, 5, 3, 0, 1, 4])); // 0, 1, 2, 3, 4, 5 -------------------------------------------------------------------------------- /leetcode/排序/插入排序.php: -------------------------------------------------------------------------------- 1 | 0; $j--) { 18 | if ($nums[$j] < $nums[$j - 1]) { 19 | $tmp = $nums[$j]; 20 | $nums[$j] = $nums[$j - 1]; 21 | $nums[$j - 1] = $tmp; 22 | } 23 | } 24 | } 25 | return $nums; 26 | } 27 | } 28 | 29 | $s = new Solution(); 30 | var_dump($s->insertSort([3, 4, 1, 5, 0, 2])); // 0, 1, 2, 3, 4, 5 -------------------------------------------------------------------------------- /leetcode/排序/选择排序.php: -------------------------------------------------------------------------------- 1 | selectSort([5, 4, 0, 1, 3, 2])); // 0, 1, 2, 3, 4, 5 -------------------------------------------------------------------------------- /leetcode/数组/004_寻找两个有序数组的中位数.php: -------------------------------------------------------------------------------- 1 | findMedianSortedArrays([1, 3], [2])); // 2.0 47 | var_dump($s->findMedianSortedArrays([1, 2], [3, 4])); // 2.5 -------------------------------------------------------------------------------- /leetcode/数组/066_加一.php: -------------------------------------------------------------------------------- 1 | = 0) { 38 | $num = $digits[$i--] + $up; 39 | if ($up) { 40 | $stack[] = $num % 10; 41 | $up = (int)($num / 10); 42 | } else { 43 | $stack[] = $num; 44 | } 45 | } 46 | return array_reverse($stack); 47 | } 48 | } 49 | 50 | $s = new Solution(); 51 | 52 | var_dump($s->plusOne([1, 2, 3])); // 1, 2, 4 53 | var_dump($s->plusOne([4, 3, 2, 1])); // [4, 3, 2, 2] 54 | 55 | -------------------------------------------------------------------------------- /leetcode/数组/073_矩阵置零.php: -------------------------------------------------------------------------------- 1 | twoSum([2, 7, 11, 15], 9)); // [1, 2] -------------------------------------------------------------------------------- /leetcode/数组/169_多数数组.php: -------------------------------------------------------------------------------- 1 | $a) { 44 | return $nums[$i]; 45 | } 46 | } 47 | return -1; 48 | } 49 | } 50 | 51 | $s = new Solution(); 52 | 53 | var_dump($s->majorityElement([3, 2, 3])); // 3 54 | var_dump($s->majorityElement([2, 2, 1, 1, 1, 2, 2])); // 2 -------------------------------------------------------------------------------- /leetcode/数组/217_存在重复元素.php: -------------------------------------------------------------------------------- 1 | containsDuplicate([1, 2, 3, 1])); // true -------------------------------------------------------------------------------- /leetcode/数组/283_移动0.php: -------------------------------------------------------------------------------- 1 | moveZeroes($nums); 44 | var_dump($nums); // 1, 2, 0, 0 45 | 46 | $nums = [0, 0, 1]; 47 | $s->moveZeroes($nums); 48 | var_dump($nums); // 1, 0, 0 49 | 50 | $nums = [1]; 51 | $s->moveZeroes($nums); 52 | var_dump($nums); // 1 53 | 54 | 55 | $nums = [1, 0, 1]; 56 | $s->moveZeroes($nums); 57 | var_dump($nums); // 1 -------------------------------------------------------------------------------- /leetcode/数组/349_两个数组的交集.php: -------------------------------------------------------------------------------- 1 | intersection([1, 2, 2, 1], [2, 2])); // 2 -------------------------------------------------------------------------------- /leetcode/数组/448_找到数组中消失的数字.php: -------------------------------------------------------------------------------- 1 | 0) { 38 | $nums[$index] = -$nums[$index]; 39 | } 40 | } 41 | $ans = []; 42 | for ($i = 0; $i < $len; $i++) { 43 | if ($nums[$i] > 0) { 44 | $ans[] = $i + 1; 45 | } 46 | } 47 | return $ans; 48 | } 49 | } 50 | 51 | $s = new Solution(); 52 | 53 | var_dump($s->findDisappearedNumbers([4, 3, 2, 7, 8, 2, 3, 1])); // 5, 6 -------------------------------------------------------------------------------- /leetcode/数组/453_最小移动次数使数组相等.php: -------------------------------------------------------------------------------- 1 | [2,3,3] => [3,4,3] => [4,4,4] 17 | // 18 | //来源:力扣(LeetCode) 19 | //链接:https://leetcode-cn.com/problems/minimum-moves-to-equal-array-elements 20 | //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 21 | 22 | class Solution 23 | { 24 | 25 | /** 26 | * 数学办法, n-1 个数加1 相当于 1个数减1 27 | * 时间复杂度: O(n) 28 | * 空间复杂度: O(1) 29 | * @param Integer[] $nums 30 | * @return Integer 31 | */ 32 | function minMoves($nums) 33 | { 34 | $min = min($nums); 35 | $len = count($nums); 36 | $count = 0; 37 | for ($i = 0; $i < $len; $i++) { 38 | if ($nums[$i] !== $min) { 39 | $count += $nums[$i] - $min; 40 | } 41 | } 42 | return $count; 43 | } 44 | } 45 | 46 | $s = new Solution(); 47 | var_dump($s->minMoves([1, 2, 3])); // 3 -------------------------------------------------------------------------------- /leetcode/数组/数组.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /leetcode/栈/栈排序.php: -------------------------------------------------------------------------------- 1 | $stack2[count($stack2) - 1]) { 21 | $stack2[] = $pop; 22 | } else { 23 | while (!empty($stack2) && $stack2[count($stack2) - 1] > $pop) { 24 | $stack[] = array_pop($stack2); 25 | } 26 | $stack2[] = $pop; 27 | } 28 | } 29 | return $stack2; 30 | } 31 | } 32 | 33 | $s = new Solution(); 34 | 35 | var_dump($s->sortStack([4, 5, 1, 3, 2])); // 1,2,3,4,5 -------------------------------------------------------------------------------- /leetcode/树/二叉树的广度优先搜索.php: -------------------------------------------------------------------------------- 1 | val = $val; 14 | } 15 | } 16 | 17 | 18 | class Solution 19 | { 20 | /** 21 | * 广度优先搜索 22 | * @param TreeNode $tree 23 | * @return array 24 | */ 25 | function inOrderTraversal($tree) 26 | { 27 | 28 | } 29 | } 30 | 31 | $s = new Solution(); 32 | 33 | $tree = new TreeNode(3); 34 | $tree->left = new TreeNode(1); 35 | $tree->right = new TreeNode(4); 36 | $tree->left->right = new TreeNode(2); 37 | 38 | var_dump($s->inOrderTraversal($tree)); // 1, 2, 3, 4 39 | 40 | var_dump($s->inOrderTraversalRecursion($tree)); // 1, 2, 3, 4 41 | -------------------------------------------------------------------------------- /leetcode/树/前缀树.php: -------------------------------------------------------------------------------- 1 | 左->右 13 | 14 | 使用栈来遍历, 右子树先进栈, 左子树后进栈 15 | 16 | 时间复杂度: O(n) 17 | 空间复杂度: O(w) 18 | 19 | ### 中序遍历 20 | 21 | 左->根->右 22 | 23 | 时间复杂度: O(n) 24 | 空间复杂度: O() 25 | 26 | ### 后序遍历 27 | 28 | 左->右->根 29 | 30 | ### 层序遍历 (BFS) 广度优先搜索 31 | 32 | 使用队列来做, 入栈顺序为: 左->右 33 | 34 | ### 深度优先搜索 (DFS) 35 | 36 | 使用栈来实现, 入栈顺序为: 右->左 37 | 38 | ## 常见题 39 | 40 | 1. 判断两个二叉树是否相等: 100_相同的数 41 | - 递归做法 42 | - 两个栈的做法, 栈用来先序遍历树, 遍历的过程中进行比较 43 | 44 | 45 | 2. 判断二叉树是否对称: 101_对称二叉树 46 | - 递归￿做法 47 | - 栈做法, 每次pop两个节点出来比较, 入栈方式是重点 48 | 49 | 3. 求树的最大深度 50 | - 递归法 51 | - 队列层序遍历, 然后求深度 52 | 53 | ## 求树的高度 54 | 55 | 树的高度需要使用后序遍历, 每回归一层需要用 max(left, right) + 1 当做当前层的高度 56 | 57 | ```php 58 | function height($root) 59 | { 60 | if ($root === null) { 61 | return -1; 62 | } 63 | return 1 + max(height($root->left), height($root->right)); 64 | } 65 | ``` 66 | 67 | ## 二叉搜索树特性 68 | 69 | 若左子树不为空, 则左子树上的节点均小于根节点, 若右子树不为空, 则右子树上的节点均大于根节点. 70 | 左右子树也均为二叉排序树. -------------------------------------------------------------------------------- /leetcode/深度优先遍历/深度优先遍历.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /leetcode/设计/172_阶乘后的零.php: -------------------------------------------------------------------------------- 1 | 0) { 33 | $count += (int)($n / 5); 34 | $n = (int)($n / 5); 35 | } 36 | return $count; 37 | } 38 | } 39 | 40 | $s = new Solution(); 41 | 42 | var_dump($s->trailingZeroes(3)); // 0 43 | var_dump($s->trailingZeroes(5)); // 1 44 | var_dump($s->trailingZeroes(30)); // 7 -------------------------------------------------------------------------------- /leetcode/设计/202_快乐数.php: -------------------------------------------------------------------------------- 1 | squareSum($slow); 34 | $fast = $this->squareSum($fast); 35 | $fast = $this->squareSum($fast); 36 | } while ($slow !== $fast); 37 | return $slow === 1; 38 | } 39 | 40 | function squareSum($m) 41 | { 42 | $squareSum = 0; 43 | while ($m !== 0) { 44 | $squareSum += ($m % 10) * ($m % 10); 45 | $m = (int)($m / 10); 46 | } 47 | return $squareSum; 48 | } 49 | } 50 | 51 | $s = new Solution(); 52 | var_dump($s->isHappy(19)); // true -------------------------------------------------------------------------------- /leetcode/设计/258_各位相加.php: -------------------------------------------------------------------------------- 1 | 9) { 37 | $sum = 0; 38 | while ($num > 0) { 39 | $sum += $num % 10; 40 | $num = (int)($num / 10); 41 | } 42 | $num = $sum; 43 | } 44 | return $num; 45 | } 46 | } 47 | 48 | $s = new Solution(); 49 | 50 | var_dump($s->addDigits(38)); // 2 51 | var_dump($s->addDigits(10)); // 1 -------------------------------------------------------------------------------- /leetcode/设计/263_丑数.php: -------------------------------------------------------------------------------- 1 | >= 1; 51 | } 52 | return $num === 1; 53 | } 54 | } 55 | 56 | $s = new Solution(); 57 | 58 | var_dump($s->isUgly(14)); // false 59 | var_dump($s->isUgly(100)); // true -------------------------------------------------------------------------------- /leetcode/设计/292_Nim游戏.php: -------------------------------------------------------------------------------- 1 | canWinNim(4)); // false -------------------------------------------------------------------------------- /leetcode/设计/326_3的幂.php: -------------------------------------------------------------------------------- 1 | i = log3(n) => i = (logb(n) / logb(3)) 34 | * 要注意 % 取模会直接去掉小数点后, 得到的是一个整数 35 | * 需要小数取余用 fmod(), 返回值是一个浮点数, 与0判断时要写成 === 0.0 36 | * @param Integer $n 37 | * @return Boolean 38 | */ 39 | function isPowerOfThree($n) 40 | { 41 | if ($n < 1) { 42 | return false; 43 | } 44 | return fmod(log10($n) / log10(3), 1) === 0.0; 45 | } 46 | } 47 | 48 | $s = new Solution(); 49 | 50 | var_dump($s->isPowerOfThree(45)); // false 51 | var_dump($s->isPowerOfThree(1)); // true 52 | var_dump($s->isPowerOfThree(3)); // true 53 | var_dump($s->isPowerOfThree(9)); // true -------------------------------------------------------------------------------- /leetcode/设计/342_4的幂.php: -------------------------------------------------------------------------------- 1 | isPowerOfFour(1)); // true 38 | var_dump($s->isPowerOfFour(4)); // true 39 | var_dump($s->isPowerOfFour(12)); // false 40 | var_dump($s->isPowerOfFour(64)); // true -------------------------------------------------------------------------------- /leetcode/设计/441_排列硬币.php: -------------------------------------------------------------------------------- 1 | 0) { 56 | if ($n >= $i) { 57 | $count++; 58 | } 59 | $n -= $i; 60 | $i++; 61 | } 62 | return $count; 63 | } 64 | } 65 | 66 | $s = new Solution(); 67 | 68 | var_dump($s->arrangeCoins(5)); // 2 -------------------------------------------------------------------------------- /leetcode/设计/设计.md: -------------------------------------------------------------------------------- 1 | # 设计 2 | 3 | 集合各种没用到数据结构而是用到了技巧的题目 -------------------------------------------------------------------------------- /leetcode/贪心算法/贪心算法.md: -------------------------------------------------------------------------------- 1 | # 贪心算法 2 | 3 | ## 介绍 4 | 5 | > 贪心算法, 又叫贪婪算法, 是寻找**最优解问题**的常用办法 6 | > 这种模式一般将求解过程分成若干个步骤, 对每一个步骤应用贪心原则, 选取当前状态下的最好/最优的选择(局部最有利的选择), 并以此希望最后堆叠出的结果也是最好的/最优的解. 7 | 8 | ## 步骤 9 | 10 | 1. 从某个初始解出发; 11 | 2. 使用某个迭代的过程, 当可以向目标前进一步时, 就根据局部最优策略, 得到一部分的解, 缩小问题规模; 12 | 3. 将所有解综合起来; 13 | 14 | 在背包问题中, 局部最优解的评定标准很重 要, 比如说可以按照以下三种最优策略来, 可以得到不同的解 15 | 16 | - 物品最小重量 17 | - 物品最高价值 18 | - 物品的价格密度 19 | 20 | ## 使用贪心算法的前提 21 | 22 | 1. 原问题复杂度过高 23 | 2. 求全局最优解的数学模型难以建立 24 | 3. 求全局最优解的计算量过大 25 | 4. 没有太大必要一定求出全局最优解 26 | 27 | ## 如何把原问题分解为子问题 28 | 29 | 1. 按串行任务分 30 | 31 | 时间串的任务, 按照子任务分解, 即每一步都是在上一步的基础上再选择当前的最优解. 32 | 33 | 2. 按规模递减 34 | 35 | 规模较大的复杂问题, 可以借助递归的思想, 分解成一个规模小一点点的问题,循环解决, 当最后一步的求解完成后就得到了所谓的"全局最优解" 36 | 37 | 3. 按并行任务分 38 | 39 | 这种任务不分先后, 可能是并行, 可以分别求解后, 再按照一定的规则(比如某种配比公式)将其组合后得到最终解 40 | 41 | ## 如何知道贪心算法结果逼近了最优解 42 | 43 | 算法和数学不同, 并不追求绝得的最优值, 因为追求的过程需要考虑以下几个问题: 44 | 45 | 成本: 耗费多少资源, 花掉多少编程时间 46 | 速度: 计算量是否过大, 计算速度能否满足要求 47 | 价值: 得到了最优解与次优解是否真的有那么大差别, 还是说差别可以忽略 -------------------------------------------------------------------------------- /leetcode/递归/递归.md: -------------------------------------------------------------------------------- 1 | # 递归 2 | 3 | ## 递归的设计过程 4 | 5 | 1. 找到截止条件 6 | 2. 找到拆分问题的公式 (递推公式) -------------------------------------------------------------------------------- /leetcode/链表/061_旋转链表.php: -------------------------------------------------------------------------------- 1 | next; 24 | } 25 | // 优化: 减少遍历链表次数, 从 $k / len($head) 次优化到了 1 次 26 | $k %= $count; 27 | $fast = $head; 28 | $slow = $head; 29 | // 先走k步 30 | for ($i = 0; $i < $k; $i++) { 31 | $fast = $fast->next; 32 | } 33 | while ($fast->next !== null) { 34 | $fast = $fast->next; 35 | $slow = $slow->next; 36 | } 37 | if ($fast === $slow) { 38 | return $head; 39 | } 40 | // 断开节点前后, 并将后边节点移到前边 41 | $l1 = $head; 42 | $l2 = $slow->next; 43 | $slow->next = null; 44 | $fast->next = $l1; 45 | return $l2; 46 | } 47 | } -------------------------------------------------------------------------------- /leetcode/链表/148_排序列表.php: -------------------------------------------------------------------------------- 1 | 2->1->3 8 | //输出: 1->2->3->4 9 | //示例 2: 10 | // 11 | //输入: -1->5->3->4->0 12 | //输出: -1->0->3->4->5 13 | 14 | class ListNode 15 | { 16 | public $val = 0; 17 | public $next = null; 18 | 19 | function __construct($val) 20 | { 21 | $this->val = $val; 22 | } 23 | } 24 | 25 | /** 26 | * Definition for a singly-linked list. 27 | * class ListNode { 28 | * public $val = 0; 29 | * public $next = null; 30 | * function __construct($val) { $this->val = $val; } 31 | * } 32 | */ 33 | class Solution 34 | { 35 | 36 | /** 37 | * @param ListNode $head 38 | * @return ListNode 39 | */ 40 | function sortList($head) 41 | { 42 | 43 | } 44 | } 45 | 46 | $l = new ListNode(-1); 47 | $l->next = new ListNode(5); 48 | $l->next->next = new ListNode(3); 49 | $l->next->next->next = new ListNode(4); 50 | $l->next->next->next->next = new ListNode(0); 51 | 52 | $s = new Solution(); 53 | 54 | var_dump($s->sortList($l)); // -1, 0, 3, 4, 5 -------------------------------------------------------------------------------- /leetcode/链表/链表.md: -------------------------------------------------------------------------------- 1 | # 链表 2 | 3 | ## 概念 4 | 5 | ## 种类 6 | 7 | 1. 单项链表 8 | 2. 双向链表 9 | 3. 循环链表 10 | 11 | ## 技巧 12 | 13 | 1. 有些时候需要创建新链表, 并在之后连接数据, 而在创建时值为空, 可以直接 $list->next 使用, 最后=返回 $list->next 14 | 2. 使用数组或者hash表来缓存 list 中的值 15 | 3. 涉及到链表查询时, 使用双指针可能会解决一些找重合点的问题 16 | 4. 链表实现大数加法: 002_两数相加.php 17 | 5. 链表在修改时核心操作为, 修改next指向, 即可快速改变链表的属性 18 | 19 | ## 复杂度 20 | 21 | ### 插入删除 22 | 23 | 时间复杂度: O(1), 只需要考虑相邻的节点指针修改 24 | 25 | ### 查找 26 | 27 | 时间复杂度: O(n), 需要重头遍历查找 -------------------------------------------------------------------------------- /programme/Java/如何开发一个Java SDK.md: -------------------------------------------------------------------------------- 1 | # 如何开发一个Java SDK 2 | 3 | ## 参考 alipay 支付 SDK 4 | 5 | - SDK 地址: `https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java` -------------------------------------------------------------------------------- /programme/K8S/什么是云原生技术.md: -------------------------------------------------------------------------------- 1 | # 什么是云原生技术 2 | 3 | 云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。 4 | 5 | 这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统做出频繁的可预测的重大变更。 6 | -------------------------------------------------------------------------------- /programme/K8S/学习过程中使用的集群结构.md: -------------------------------------------------------------------------------- 1 | # 学习 k8s 过程中使用的集群结构 2 | 3 | - tencent: master 4 | - y9kx: node 5 | -------------------------------------------------------------------------------- /programme/Linux/Centos 更改hostname.md: -------------------------------------------------------------------------------- 1 | # CentOS 更改hostname 2 | 3 | 查看当前hostname 4 | 5 | ```shell 6 | hostnamectl 7 | ``` 8 | 9 | 修改hostname 10 | 11 | ```shell 12 | hostnamectl set-hostname test 13 | ``` 14 | -------------------------------------------------------------------------------- /programme/Linux/Linux 安全.md: -------------------------------------------------------------------------------- 1 | # Linux 安全 2 | 3 | ## 更新操作系统及软件 4 | 5 | 更新操作系统及软件能够很好的修复系统漏洞及软件漏洞。 6 | 7 | ```shell 8 | sudo apt update && sudo apt upgrade -y 9 | ``` 10 | 11 | ## 创建特权用户 12 | 13 | - 创建新的账户拥有`sudo`用户 14 | - 禁止`root`登录 15 | 16 | ## 禁止密码登录 17 | 18 | - 禁止使用密码登录,而使用秘钥登录 19 | 20 | `vim /etc/ssh/sshd_config` 21 | 22 | PasswordAuthentication no 23 | 24 | 重启服务: `systemctl restart sshd.service` 25 | 26 | ## 修改ssh默认端口 27 | 28 | ## 使用fail2ban 29 | -------------------------------------------------------------------------------- /programme/Linux/Linux 常用命令.md: -------------------------------------------------------------------------------- 1 | # Linux 常用命令 2 | 3 | ## 端口相关 4 | 5 | ### 查看使用端口的进程 pid 6 | 7 | ```shell 8 | lsof -i:8888 9 | ``` 10 | 11 | ### 根据 pid 杀进程 12 | 13 | ```shell 14 | kill -s 9 15555 15 | ``` 16 | 17 | ### 查看文件夹大小 18 | 19 | `du -hs *` 20 | 21 | ### 查看文件大小排行 22 | 23 | ```shell script 24 | du -hs * | sort -hr 25 | 26 | # 选出排在前面的10个 27 | du -sh * | sort -hr | head 28 | 29 | # 选出排在后面的10个 30 | du -sh * | sort -hr| tail 31 | ``` -------------------------------------------------------------------------------- /programme/Linux/Linux将默认shell更改为vim.md: -------------------------------------------------------------------------------- 1 | # Linux将默认编辑器更改为vim 2 | 3 | ## 更改默认编辑器 4 | 5 | ``` 6 | sudo update-alternatives --config editor 7 | ``` 8 | 9 | ## crontab -e 默认编辑器 10 | 11 | ``` 12 | select-editor 13 | ``` -------------------------------------------------------------------------------- /programme/Linux/SCP下载上传文件.md: -------------------------------------------------------------------------------- 1 | # SCP 2 | 3 | ## 从服务器下载文件夹 4 | 5 | ```shell 6 | scp -r zhan@fuwu.skysharing.cn:/home/wwwroot/page/admin ~/work/page/admin 7 | ``` 8 | 9 | ## 上传文件 10 | 11 | ```shell 12 | scp /path/local_filename username@servername:/path 13 | ``` 14 | -------------------------------------------------------------------------------- /programme/Linux/Ubuntu add-apt-repository command not found.md: -------------------------------------------------------------------------------- 1 | # add-apt-repository not found 2 | 3 | ```shell 4 | sudo apt-get install software-properties-common 5 | ``` 6 | -------------------------------------------------------------------------------- /programme/Linux/Ubuntu上安装小飞机.md: -------------------------------------------------------------------------------- 1 | # Ubuntu 安装小飞机 2 | 3 | 4 | 安装最新版本的 shadowsocks,旧版本可能会出现 `aes-255-gcm`找不到的问题 5 | ```shell 6 | sudo pip install https://github.com/shadowsocks/shadowsocks/archive/master.zip 7 | ``` 8 | 9 | ## 生成pac文件 10 | 11 | - 安装 `pacgen`: `sudo pip install -U genpac` 12 | - 生成`pac`: `enpac --proxy="SOCKS5 127.0.0.1:1090" --gfwlist-proxy="SOCKS5 127.0.0.1:1090" -o autoproxy.pac --gfwlist-url="https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"` -------------------------------------------------------------------------------- /programme/Linux/Ubuntu安装.md: -------------------------------------------------------------------------------- 1 | # Ubuntu 安装 2 | 3 | ## 分区 4 | 5 | 主分区最多四个 6 | 7 | boot ext4 主 4G 8 | swap swap 逻辑 内存的两倍大小 9 | / ext4 主 200G 10 | /tmp ext4 5G 11 | efi 1G 12 | home 剩余所有内容 13 | -------------------------------------------------------------------------------- /programme/Linux/Ubuntu安装桌面配置工具.md: -------------------------------------------------------------------------------- 1 | ``` 2 | sudo apt install gnome-tweaks 3 | ``` 4 | 5 | 然后通过 alt + F2 输入 gnome-tweaks 运行 -------------------------------------------------------------------------------- /programme/Linux/axel多线程下载.md: -------------------------------------------------------------------------------- 1 | # axel 多线程下载 2 | 3 | ## 安装 4 | 5 | ``` 6 | sudo apt install -y axel 7 | ``` 8 | 9 | ## 使用 10 | 11 | 开启100个进程进行下载 12 | ``` 13 | axel -n 100 http://down.com/path 14 | ``` -------------------------------------------------------------------------------- /programme/Linux/fail2ban.md: -------------------------------------------------------------------------------- 1 | # fail2ban 2 | 3 | ## 安装 4 | 5 | ```shell 6 | sudo apt install fail2ban 7 | ``` 8 | 9 | ## 为ssh服务配置fail2ban 10 | 11 | -------------------------------------------------------------------------------- /programme/Linux/ssh执行命令.md: -------------------------------------------------------------------------------- 1 | # ssh 执行命令 2 | 3 | ```shell 4 | ssh name@host "ls" 5 | ``` 6 | 7 | 执行多个命令,用 `<<标识` 来扩起命令 8 | 9 | ```shell 10 | #!/bin/bash 11 | ssh -tt user@remoteNode > /dev/null 2>&1 << eeooff 12 | cd /home 13 | touch abcdefg.txt 14 | exit 15 | eeooff 16 | echo done! 17 | ``` -------------------------------------------------------------------------------- /programme/Linux/ssh设置别名.md: -------------------------------------------------------------------------------- 1 | # SSH 设置别名访问 2 | 3 | `vim ~/.ssh/config` 4 | 5 | ```txt 6 | Host aliasName 7 | HostName 123.123.123.123 8 | User root 9 | Port 22 10 | ``` 11 | -------------------------------------------------------------------------------- /programme/Linux/tar.md: -------------------------------------------------------------------------------- 1 | # tar 命令 2 | 3 | - c 压缩 4 | - x 解压 5 | - v 显示过程 6 | - f 文件名 7 | 8 | ## 压缩文件夹 9 | 10 | - 压缩整个目录 11 | 12 | ```shell 13 | tar -zcvf test.tar.gz test 14 | ``` 15 | 16 | - 压缩文件夹中的指定文件 17 | 18 | ```shell 19 | tar -zcvf test.tar.gz a.txt b c.jpg 20 | ``` 21 | 22 | ## 解压文件夹 23 | 24 | ```bash 25 | tar -zxvf file.tar.gz 26 | ``` 27 | 28 | ## 查看压缩文件内容 29 | 30 | ```shell 31 | tar -tf file.tar.gz 32 | ``` -------------------------------------------------------------------------------- /programme/Linux/wine/wine-deepin_wechat_乱码问题解决.md: -------------------------------------------------------------------------------- 1 | # wine-deepin wechat 乱码问题解决 2 | 3 | ## 解决方案1 4 | 5 | ```shell 6 | vim /opt/deepinwine/tools/run.sh 7 | ``` 8 | 9 | 找到 `WINE_CMD`, 修改为 `WINE_CMD="LC_ALL=zh_CN.UTF-8 deepin-wine"` 10 | 11 | ## 解决方案2 12 | 13 | 1. 下载字体 `msyh.ttc` 14 | 2. 复制字体到目录中 `cp msyh.ttc ~/.deepinwine/Deepin-WeChat/drive_c/windows/Fonts` 15 | 3. 修改wechat系统注册表 `vim ~/.deepinwine/Deepin-WeChat/system.reg` 16 | 17 | 修改以下内容为 18 | ``` 19 | "MS Shell Dlg"="msyh" 20 | "MS Shell Dlg 2"="msyh" 21 | ``` 22 | 23 | 4. 字体注册 24 | 25 | `vim msyh_config.reg` 26 | 27 | 添加以下内容 28 | 29 | ``` 30 | REGEDIT4 31 | [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink] 32 | "Lucida Sans Unicode"="msyh.ttc" 33 | "Microsoft Sans Serif"="msyh.ttc" 34 | "MS Sans Serif"="msyh.ttc" 35 | "Tahoma"="msyh.ttc" 36 | "Tahoma Bold"="msyhbd.ttc" 37 | "msyh"="msyh.ttc" 38 | "Arial"="msyh.ttc" 39 | "Arial Black"="msyh.ttc" 40 | ``` 41 | 42 | 注册`deepin-wine regedit msyh_config.reg` 43 | 44 | 5. 重启 `wechat` -------------------------------------------------------------------------------- /programme/Linux/wine/修复wine在高分屏下的问题.md: -------------------------------------------------------------------------------- 1 | # WINE 问题 2 | 3 | ## 高分屏下的显示问题 4 | 5 | 6 | wechat 7 | 8 | ```shell 9 | WINEPREFIX=~/.deepinwine/Deepin-WeChat /usr/bin/deepin-wine winecfg 10 | ``` 11 | 12 | tim 13 | ```shell 14 | WINEPREFIX=~/.deepinwine/Deepin-TIM/ /usr/bin/deepin-wine winecfg 15 | ``` 16 | 17 | ## 中文问题 18 | 19 | 在`/opt/deepinwine/tools/run.sh`中添加LC_ALL="zh_CN.UTF-8" 即可 20 | 21 | ## Ubuntu 下的托盘问题 22 | 23 | 安装扩展即可:`https://extensions.gnome.org/extension/1031/topicons/` 24 | 25 | 或者Ubuntu 19.10 在系统的软件中安装 topicons 即可 -------------------------------------------------------------------------------- /programme/Linux/查看Linux信息.md: -------------------------------------------------------------------------------- 1 | # 查看Linux信息 2 | 3 | ## 查看系统版本 4 | 5 | ### 适用于Linux发行版本:Redhat、SuSE、Debian、CentOS 6 | 7 | ```shell 8 | cat /etc/redhat-release 9 | ``` 10 | 11 | ### 适用于 Ubuntu 12 | 13 | ```shell 14 | lsb_release -a 15 | ``` 16 | 17 | ### 适用于所有Linux 18 | 19 | ```shell 20 | cat /etc/issue 21 | ``` 22 | 23 | ## 查看内核版本 24 | 25 | ```shell 26 | cat /proc/version 27 | ``` 28 | 29 | ```shell 30 | uname -a 31 | ``` 32 | -------------------------------------------------------------------------------- /programme/Linux/查看所有crontab.md: -------------------------------------------------------------------------------- 1 | # 查看所有用户的crontab 2 | 3 | 有些时候需要查看所有用户设定的crontab配置来排查问题,用root身份执行以下命令即可。 4 | 5 | ```shell 6 | for user in $(cut -f1 -d: /etc/passwd); do echo $user; crontab -u $user -l; done 7 | ``` 8 | -------------------------------------------------------------------------------- /programme/Linux/用户相关.md: -------------------------------------------------------------------------------- 1 | # Linux 用户 2 | 3 | - 激活用户 4 | 5 | `This account is currently not available` 6 | `usermod -s /bin/bash username` 7 | 8 | - 创建用户并添加到sudo组 9 | 10 | ```shell 11 | useradd -m -s /bin/bash -p $(openssl passwd -1 ${UPWD}) -G sudo ${UNAME} 12 | ``` 13 | 14 | - 禁用账户 15 | 16 | ```shell 17 | sudo passwd -l username 18 | ``` 19 | 20 | - 启用账户 21 | 22 | ```shell 23 | sudo passwd -u username 24 | ``` 25 | 26 | - 增加用户到组 27 | 28 | `usermod -a -G groupName userName` 29 | 30 | - 组中移除用户 31 | 32 | `gpasswd -d user gorup``` 33 | 34 | - 显示用户所属的用户组 35 | 36 | `groups` -------------------------------------------------------------------------------- /programme/PHP/Composer/国内切换阿里云源.md: -------------------------------------------------------------------------------- 1 | # Composer 切换源 2 | 3 | 切换到阿里云源 4 | 5 | ```bash 6 | composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ 7 | ``` 8 | 9 | 取消配置 10 | 11 | ```bash 12 | composer config -g --unset repos.packagist 13 | ``` 14 | 15 | ## 使用包快捷切换源 16 | 17 | ```shell 18 | composer global require slince/composer-registry-manager 19 | composer repo:ls 20 | composer repo:use aliyun 21 | ``` 22 | -------------------------------------------------------------------------------- /programme/PHP/Composer/多线程下载加速Composer.md: -------------------------------------------------------------------------------- 1 | # 多进程加速 2 | 3 | ```shell 4 | composer global require hirak/prestissimo 5 | ``` -------------------------------------------------------------------------------- /programme/PHP/Laravel/Carbon问题.md: -------------------------------------------------------------------------------- 1 | # Carbon 问题 2 | 3 | ## 遇到 UTC 格式字符串时 make 方法无法正确处理时间 4 | 5 | 遇到这样的字符串 `2019-11-19T17:20:00.610Z`,是ISO时间格式之一,用make不能正确处理 6 | 7 | 应该使用 `Carbon::parse($str)->tz($timezone)` 来处理成正确的的时间及时区 -------------------------------------------------------------------------------- /programme/PHP/Laravel/Laravel Faker 使用中文.md: -------------------------------------------------------------------------------- 1 | # Laravel Faker 使用中文 2 | 3 | 有时候需要使用 faker 来生成中国的的手机号,所以需要修改 faker 为中文 4 | 5 | app.php 中配置 `'faker_locale' => 'zh_CN'` 来进行 6 | 7 | 获取 `$faker` 实例: `app(Faker\Generator::class)` 8 | -------------------------------------------------------------------------------- /programme/PHP/Laravel/docker部署生产环境.md: -------------------------------------------------------------------------------- 1 | # docker 部署 Laravel 生产环境 2 | 3 | ## 注意点 4 | 5 | - 6 | -------------------------------------------------------------------------------- /programme/PHP/Laravel/tiner模式下方向键编程了字符的问题.md: -------------------------------------------------------------------------------- 1 | # laravel tiner模式下方向键编程了字符的问题 2 | 3 | php 安装 readline 扩展 4 | 5 | ``` 6 | phpize 7 | ``` -------------------------------------------------------------------------------- /programme/PHP/Swoole/smproxy安装配置.md: -------------------------------------------------------------------------------- 1 | # smproxy 安装配置 2 | 3 | 文档: `https://smproxy.louislivi.com/` 4 | 5 | ## 安装 6 | 7 | ```shell 8 | git clone https://github.com/louislivi/SMProxy.git smproxy 9 | cd smproxy 10 | docker build -t smproxy . 11 | docker run -d --name=smproxy --network=app -v ${PWD}/conf/:/usr/local/smproxy/conf -v ${PWD}/logs/:/usr/local/smproxy/logs -p 3366:3366 smproxy 12 | ``` 13 | 14 | ## 配置 15 | 16 | 只选择了一些常用更改项 17 | 18 | ### server.json 19 | 20 | ```json 21 | { 22 | "swoole": { 23 | "worker_num": "必选,SWOOLE worker进程数,支持计算", 24 | "max_coro_num": "必选,SWOOLE 协程数,推荐不低于3000", 25 | "pid_file": "必选,worker进程和manager进程pid目录", 26 | "open_tcp_nodelay": "可选,关闭Nagle合并算法", 27 | "daemonize": "可选,守护进程化,true 为守护进程 false 关闭守护进程", 28 | "heartbeat_check_interval": "可选,心跳检测", 29 | "heartbeat_idle_time": "可选,心跳检测最大空闲时间", 30 | "reload_async": "可选,异步重启,true 开启异步重启 false 关闭异步重启", 31 | "log_file": "可选,SWOOLE日志目录" 32 | } 33 | } 34 | ``` 35 | 36 | ### database.json 37 | -------------------------------------------------------------------------------- /programme/PHP/Swoole/安装.md: -------------------------------------------------------------------------------- 1 | # Swoole 安装 2 | 3 | ## Release 安装 4 | 5 | ### 步骤 6 | 7 | 1. 下载 `https://github.com/swoole/swoole-src/releases`并解压 8 | 2. 简单编译 9 | 10 | ```bash 11 | cd swoole 12 | phpize (ubuntu 没有安装phpize可执行命令:sudo apt-get install php-dev来安装phpize) 13 | ./configure 14 | make 15 | sudo make install 16 | ``` 17 | 18 | ### 编译选项 19 | 20 | - `https://wiki.swoole.com/wiki/page/437.html` 21 | 22 | ### 可能遇到的问题 23 | 24 | - **`error: Cannot find php-config. Please use --with-php-config=PATH`** 25 | 26 | 需要指定 `php-config`, 一般在 `/usr/local/php/bin/php-config` 中: 27 | 28 | `./configure` => `./configure --with-php-config=/usr/local/php/bin/php-config` 29 | -------------------------------------------------------------------------------- /programme/PHP/常见错误.md: -------------------------------------------------------------------------------- 1 | # PHP 常见错误 2 | 3 | ## 扩展安装错误 4 | 5 | ### mongodb 6 | 7 | 错误: 8 | 9 | ``` 10 | The SCRAM_SHA_1 authentication mechanism requires libmongoc built with ENABLE_SSL 11 | ``` 12 | 13 | 解决方案: 14 | 15 | ```zsh 16 | sudo apt-get install -y libcurl4-openssl-dev pkg-config libssl-dev 17 | sudo pecl install mongodb 18 | ``` 19 | -------------------------------------------------------------------------------- /programme/PHP/支付/QQ钱包/QQ 钱包 Laravel 扩展开发.md: -------------------------------------------------------------------------------- 1 | # QQ 钱包 Laravel 扩展开发 2 | 3 | - [官方文档](https://qpay.qq.com/buss/doc.shtml) 4 | 5 | ## 接口列表 6 | 7 | - 扫码支付 8 | - 统一下单 9 | - 生成支付二维码 10 | - 处理支付回调 11 | - 订单查询 12 | - 关闭订单 13 | - 申请退款 14 | - 退款查询 15 | - 对账单下载 16 | - 企业付款 17 | - 付款给用户 18 | - 处理付款结果回调 19 | - 查询付款结果 20 | - 对账单下载 21 | 22 | ## 配置项 23 | 24 | - `app_id` 商户id 25 | - `secret_key` api 秘钥 26 | - `api_client_cert_path` 证书pem路径 27 | - `api_client_key_path` 证书秘钥pem路径 28 | - `root_ca_path` CA证书 29 | -------------------------------------------------------------------------------- /programme/前端/CentOS安装node环境.md: -------------------------------------------------------------------------------- 1 | # CentOS 安装node环境 2 | 3 | ## 安装 4 | 5 | ### yum 安装 6 | 7 | 该安装方法安装的版本一般非常的旧 8 | 9 | 1. 安装EPEL 仓库 `yum install epel-release` 10 | 2. 安装 nodejs: `yum install nodejs` 11 | 3. 安装 npm: `yum install npm` 12 | 13 | ### 下载安装 14 | 15 | 1. 在`https://nodejs.org/en/download/`上复制 `Linux Binaries(x64) ` 链接 16 | 2. `wget https://nodejs.org/dist/v12.13.1/node-v12.13.1-linux-x64.tar.xz` 17 | 3. `tar -xvf node-v12.13.1-linux-x64.tar.xz` 18 | 4. `cp -r node-v12.13.1-linux-x64 /usr/local/node` 19 | 5. `ln -s /usr/local/node/bin/node /usr/local/bin/node` 20 | 6. `ln -s /usr/local/node/bin/npm /usr/local/bin/npm` 21 | 22 | 这种安装方法需要使用root安装,并且需要设置相应的权限 23 | 24 | ## 更新 25 | 26 | `npm install -g npm` -------------------------------------------------------------------------------- /programme/前端/MacOS_install_nodejs.md: -------------------------------------------------------------------------------- 1 | # MacOS 安装 nodejs 环境 2 | 3 | 官网下载直接安装 https://nodejs.org/en/#download 4 | 5 | 安装目录为: /usr/local/bin 6 | 7 | ## 切换全局 node_modules 位置 8 | 9 | https://segmentfault.com/a/1190000019500608 10 | 11 | ## mac 使用 nvm 管理多版本 node 12 | 13 | https://juejin.cn/post/6844903896322670605 -------------------------------------------------------------------------------- /programme/前端/Ubuntu安装node环境.md: -------------------------------------------------------------------------------- 1 | # Ubuntu 安装 node 开发环境 2 | 3 | 1. 访问 `https://nodejs.org/en/download/` 页面 4 | 2. 选中 `Installing Node.js via package manager` 5 | 3. 找到相应的Linux发行版本进行安装 6 | 7 | ## 配置npm路径 8 | 9 | 1. ~/.npm 下新建 `node_modules`, `node_cache` 两个文件夹 10 | 11 | ```shell 12 | mkdir ~/.npm/node_modules 13 | mkdir ~/.npm/node_cache 14 | ``` 15 | 16 | 2. 设置npm 17 | 18 | ```shell 19 | npm config set prefix ~/.npm/node_modules 20 | npm config set prefix ~/.npm/node_cache 21 | ``` 22 | 23 | 3. 加入 bin 到环境变量中 24 | -------------------------------------------------------------------------------- /programme/前端/dotenv/dontenv配置.md: -------------------------------------------------------------------------------- 1 | # dotenv 配置 2 | 3 | .env: Default. 4 | .env.local: Local overrides. This file is loaded for all environments except test. 5 | .env.development, .env.test, .env.production: Environment-specific settings. 6 | .env.development.local, .env.test.local, .env.production.local: Local overrides of environment-specific settings. 7 | Files on the left have more priority than files on the right: 8 | 9 | npm start: .env.development.local, .env.development, .env.local, .env 10 | npm run build: .env.production.local, .env.production, .env.local, .env 11 | npm test: .env.test.local, .env.test, .env (note .env.local is missing) 12 | 13 | 14 | 必须是以REACT_APP开头的变量 才可以。 15 | -------------------------------------------------------------------------------- /programme/前端/npm安装更新.md: -------------------------------------------------------------------------------- 1 | # npm 安装更新 2 | 3 | ## 升级npm版本 4 | 5 | ```shell 6 | npm install -g npm 7 | ``` -------------------------------------------------------------------------------- /programme/前端/npm换源.md: -------------------------------------------------------------------------------- 1 | # NPM 换源 2 | 3 | ## 使用阿里云镜像 4 | 5 | 1. 临时使用 6 | npm --registry https://registry.npm.taobao.org install express 7 | 8 | 2. 持久使用 9 | npm config set registry https://registry.npm.taobao.org 10 | 11 | 3. 通过cnpm 12 | npm install -g cnpm --registry=https://registry.npm.taobao.org 13 | 14 | ## 使用官方镜像 15 | 16 | npm config set registry https://registry.npmjs.org/ 17 | 18 | ## 查看npm源地址 19 | 20 | npm config get registry 21 | -------------------------------------------------------------------------------- /rust/tauri.md: -------------------------------------------------------------------------------- 1 | # tauri 2 | 3 | ## 链接 4 | 5 | [文档](https://tauri.app/) 6 | [github](https://github.com/tauri-apps/tauri) 7 | 8 | ## 操作 9 | 10 | 创建程序: `yarn create tauri-app` -------------------------------------------------------------------------------- /temp/001_两数之和.php: -------------------------------------------------------------------------------- 1 | twoSum([2, 7, 11, 15], 9)); -------------------------------------------------------------------------------- /temp/007_整数反转.php: -------------------------------------------------------------------------------- 1 | $max || $num < $min) { 37 | return 0; 38 | } 39 | return $num; 40 | } 41 | } 42 | 43 | $s = new Solution(); 44 | 45 | var_dump($s->reverse(123)); // 321 46 | var_dump($s->reverse(-123)); // -321 47 | var_dump($s->reverse(120)); // 21 48 | var_dump($s->reverse(0)); // 0 49 | var_dump($s->reverse(4294967298)); // 0 50 | 51 | var_dump(2 << 1); -------------------------------------------------------------------------------- /temp/009_回文数.php: -------------------------------------------------------------------------------- 1 | $y) { 40 | $y = $y * 10 + $x % 10; 41 | if ($y === 0) { 42 | return false; 43 | } 44 | $x = (int)($x / 10); 45 | } 46 | return $x === $y || $x === (int)($y / 10); 47 | } 48 | } 49 | 50 | $s = new Solution(); 51 | var_dump($s->isPalindrome(121)); // true 52 | var_dump($s->isPalindrome(-121)); // false 53 | var_dump($s->isPalindrome(10)); // false -------------------------------------------------------------------------------- /temp/013_罗马数字转整数.php: -------------------------------------------------------------------------------- 1 | 1, 11 | 'V' => 5, 12 | 'X' => 10, 13 | 'L' => 50, 14 | 'C' => 100, 15 | 'D' => 500, 16 | 'M' => 1000, 17 | 'IV' => 4, 18 | 'IX' => 9, 19 | 'XL' => 50, 20 | 'XC' => 90, 21 | 'CD' => 400, 22 | 'CM' => 900, 23 | ]; 24 | for ($i = 0; $i < $len; $i++) { 25 | if ($i < $len - 1 && isset($map[$s[$i] . $s[$i + 1]])) { 26 | $sum += $map[$s[$i] . $s[$i + 1]]; 27 | $i++; 28 | } else { 29 | $sum += $map[$s[$i]]; 30 | } 31 | } 32 | return $sum; 33 | } 34 | } 35 | 36 | $s = new Solution(); 37 | 38 | var_dump($s->romanToInt('III')); // 3 39 | var_dump($s->romanToInt('IV')); // 4 40 | var_dump($s->romanToInt('IX')); // 9 41 | var_dump($s->romanToInt('LVIII')); // 58 42 | var_dump($s->romanToInt('MCMXCIV')); // 1994 -------------------------------------------------------------------------------- /temp/014_最长公共前缀.php: -------------------------------------------------------------------------------- 1 | longestCommonPrefix(["flower", "flow", "flight"])); // fl 24 | var_dump($s->longestCommonPrefix(["dog", "racecar", "car"])); // 25 | -------------------------------------------------------------------------------- /temp/020_有效的括号.php: -------------------------------------------------------------------------------- 1 | '(', 11 | ']' => '[', 12 | '}' => '{', 13 | ]; 14 | for ($i = 0; $i < $len; $i++) { 15 | if (in_array($s[$i], ['(', '[', '{'])) { 16 | $stack[] = $s[$i]; 17 | } else { 18 | if (empty($stack) || array_pop($stack) !== $map[$s[$i]]) { 19 | return false; 20 | } 21 | } 22 | } 23 | return empty($stack); 24 | } 25 | } 26 | 27 | $s = new Solution(); 28 | 29 | var_dump($s->isValid('()')); // true 30 | var_dump($s->isValid('[()]')); // true 31 | var_dump($s->isValid('(]')); // false -------------------------------------------------------------------------------- /temp/026_删除排序数组中的重复项.php: -------------------------------------------------------------------------------- 1 | removeDuplicates($nums1)); // 2 31 | var_dump($nums1); // 1, 2 -------------------------------------------------------------------------------- /temp/027_移除元素.php: -------------------------------------------------------------------------------- 1 | removeElement($nums1, 3)); // 2 32 | var_dump($nums1); // 2, 2 -------------------------------------------------------------------------------- /temp/028_实现 strStr().php: -------------------------------------------------------------------------------- 1 | strStr('hello', 'll')); // 2 -------------------------------------------------------------------------------- /temp/155_最小栈.php: -------------------------------------------------------------------------------- 1 | stack[count($this->stack) - 1][1] ?? null; 13 | } 14 | 15 | public function push($value) 16 | { 17 | $min = $this->getMin(); 18 | $this->stack[] = [$value, $min !== null ? min($value, $min) : $value]; 19 | } 20 | 21 | public function top() 22 | { 23 | return $this->stack[count($this->stack) - 1][0]; 24 | } 25 | 26 | public function pop() 27 | { 28 | $pop = array_pop($this->stack); 29 | return $pop[0]; 30 | } 31 | } 32 | 33 | $stack = new MinStack(); 34 | 35 | $stack->push(-2); 36 | $stack->push(0); 37 | $stack->push(-3); 38 | var_dump($stack->getMin()); // -3 39 | $stack->pop(); 40 | var_dump($stack->top()); // 0 41 | var_dump($stack->getMin()); // -2 -------------------------------------------------------------------------------- /temp/一个无限递归的错误.php: -------------------------------------------------------------------------------- 1 | 右->中 7 | // 二叉搜索树: 左 < 中 < 右 8 | // 后序遍历的二叉搜索树最后一个元素是根节点, 去除最后一个元素后, 前边的元素一半是左节点, 一半是右节点 9 | // 有 左节点 < 根 < 右节点, 如果不符合这个排序的, 就不是二叉搜索树 10 | 11 | 12 | function VerifySquenceOfBST($sequence) 13 | { 14 | $len = count($sequence); 15 | if ($len === 0) { 16 | return false; 17 | } 18 | return isBST($sequence, 0, $len - 1); 19 | } 20 | 21 | function isBST($sequence, $start, $end) 22 | { 23 | if ($start >= $end) { 24 | return true; 25 | } 26 | $endVal = $sequence[$end]; 27 | $mid = $start - 1; 28 | for ($i = $start; $i < $end; $i++) { 29 | if ($sequence[$i] < $endVal) { 30 | $mid = $i; 31 | } else { 32 | break; 33 | } 34 | } 35 | for ($i = $mid + 1; $i < $end; $i++) { 36 | if ($sequence[$i] < $endVal) { 37 | return false; 38 | } 39 | } 40 | return isBST($sequence, $start, $mid) && 41 | isBST($sequence, $mid + 1, $end - 1); 42 | } 43 | 44 | var_dump(VerifySquenceOfBST([2, 4, 3, 6, 8, 7, 5])); // true 45 | var_dump(VerifySquenceOfBST([4, 6, 7, 5])); // true 46 | var_dump(VerifySquenceOfBST([9, 4, 3, 6, 8, 7, 1])); // false -------------------------------------------------------------------------------- /剑指offer/二叉树的镜像.php: -------------------------------------------------------------------------------- 1 | val = $val; 15 | } 16 | } 17 | 18 | function Mirror(&$root) 19 | { 20 | if ($root === null) { 21 | return $root; 22 | } 23 | $temp = $root->left; 24 | $root->left = $root->right; 25 | $root->right = $temp; 26 | Mirror($root->left); 27 | Mirror($root->right); 28 | } 29 | 30 | $t = new TreeNode(8); 31 | $t->left = new TreeNode(6); 32 | $t->right = new TreeNode(10); 33 | $t->left->left = new TreeNode(5); 34 | $t->left->right = new TreeNode(7); 35 | $t->right->left = new TreeNode(9); 36 | $t->right->right = new TreeNode(11); 37 | 38 | Mirror($t); 39 | 40 | var_dump($t); -------------------------------------------------------------------------------- /剑指offer/二维数组中的查找.php: -------------------------------------------------------------------------------- 1 | = 0 && $j < $maxJ) { 18 | if ($array[$i][$j] < $target) { 19 | $j++; 20 | } elseif ($array[$i][$j] > $target) { 21 | $i--; 22 | } else { 23 | return true; 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | $target = 10; 30 | $array = [ 31 | [1, 2, 3, 4], 32 | [5, 6, 7, 8], 33 | [9, 10, 11, 12], 34 | [13, 14, 15, 16], 35 | ]; 36 | 37 | var_dump(Find($target, $array)); 38 | var_dump(Find(99, $array)); 39 | var_dump(Find(-1, $array)); -------------------------------------------------------------------------------- /剑指offer/二进制中1的个数.php: -------------------------------------------------------------------------------- 1 | 0) { 13 | if ($n % 2 === 1) { 14 | $count++; 15 | } 16 | $n >>= 1; 17 | } 18 | return $count; 19 | } 20 | 21 | var_dump(NumberOf1(2)); // 1 22 | var_dump(NumberOf1(-2)); // 1 23 | var_dump(NumberOf1(-2147483648)); // 1 -------------------------------------------------------------------------------- /剑指offer/从上往下打印二叉树.php: -------------------------------------------------------------------------------- 1 | val = $val; 15 | } 16 | } 17 | 18 | function PrintFromTopToBottom($root) 19 | { 20 | if (empty($root)) { 21 | return []; 22 | } 23 | $queue = [$root]; 24 | $ans = []; 25 | while (!empty($queue)) { 26 | $node = array_shift($queue); 27 | if ($node !== null) { 28 | $ans[] = $node->val; 29 | $queue[] = $node->left; 30 | $queue[] = $node->right; 31 | } 32 | } 33 | return $ans; 34 | } 35 | 36 | $t = new TreeNode(1); 37 | $t->left = new TreeNode(2); 38 | $t->right = new TreeNode(3); 39 | $t->left->left = new TreeNode(4); 40 | $t->left->right = new TreeNode(5); 41 | 42 | var_dump(PrintFromTopToBottom($t)); // 12345 -------------------------------------------------------------------------------- /剑指offer/从尾到头打印链表.php: -------------------------------------------------------------------------------- 1 | val = $x; 13 | } 14 | } 15 | 16 | function printListFromTailToHead($head) 17 | { 18 | $stack = []; 19 | $cur = $head; 20 | while ($cur !== null) { 21 | array_unshift($stack, $cur->val); 22 | $cur = $cur->next; 23 | } 24 | return $stack; 25 | } 26 | 27 | $l = new ListNode(1); 28 | $l->next = new ListNode(2); 29 | $l->next->next = new ListNode(3); 30 | $l->next->next->next = new ListNode(4); 31 | $l->next->next->next->next = new ListNode(5); 32 | 33 | var_dump(printListFromTailToHead($l)); // 5, 4, 3, 2, 1 -------------------------------------------------------------------------------- /剑指offer/包含min函数的栈.php: -------------------------------------------------------------------------------- 1 | $node, 'min' => $min]; 18 | } 19 | 20 | function mypop() 21 | { 22 | global $stack; 23 | $item = array_pop($stack); 24 | return $item['val']; 25 | } 26 | 27 | function mytop() 28 | { 29 | global $stack; 30 | $len = count($stack); 31 | if ($len === 0) { 32 | return null; 33 | } 34 | $item = $stack[$len - 1]; 35 | return $item['val']; 36 | } 37 | 38 | function mymin() 39 | { 40 | global $stack; 41 | $item = $stack[count($stack) - 1]; 42 | return $item['min']; 43 | } 44 | 45 | mypush(1); 46 | mypush(2); 47 | mypush(5); 48 | mypush(4); 49 | var_dump(mytop()); // 4 50 | var_dump(mymin()); // 1 51 | var_dump(mypop()); // 4 52 | var_dump(mytop()); // 5 53 | var_dump(mymin()); // 1 -------------------------------------------------------------------------------- /剑指offer/反转链表.php: -------------------------------------------------------------------------------- 1 | val = $x; 14 | } 15 | } 16 | 17 | function ReverseList($pHead) 18 | { 19 | $next = null; 20 | $cur = $pHead; 21 | while ($cur !== null) { 22 | $temp = $cur->next; 23 | $cur->next = $next; 24 | $next = $cur; 25 | $cur = $temp; 26 | } 27 | return $next; 28 | } 29 | 30 | $l = new ListNode(1); 31 | $l->next = new ListNode(2); 32 | $l->next->next = new ListNode(3); 33 | 34 | var_dump(ReverseList($l)); // 3, 2, 1 -------------------------------------------------------------------------------- /剑指offer/变态跳台阶.php: -------------------------------------------------------------------------------- 1 | val = $val; 12 | } 13 | } 14 | 15 | function HasSubtree($r1, $r2) 16 | { 17 | if ($r1 === null || $r2 === null) { 18 | return false; 19 | } 20 | return judgeTree($r1, $r2) || 21 | judgeTree($r1->left, $r2) || 22 | judgeTree($r1->right, $r2); 23 | } 24 | 25 | function judgeTree($r1, $r2) 26 | { 27 | if ($r1 === null && $r2 === null) { 28 | return true; 29 | } 30 | if ($r1 === null || $r2 === null) { 31 | return false; 32 | } 33 | if ($r1->val !== $r2->val) { 34 | return judgeTree($r1->left, $r2) || 35 | judgeTree($r1->right, $r2); 36 | } 37 | return judgeTree($r1->left, $r2->left) && 38 | judgeTree($r1->right, $r2->right); 39 | } 40 | 41 | 42 | $t1 = new TreeNode(1); 43 | $t1->left = new TreeNode(2); 44 | $t1->left->left = new TreeNode(3); 45 | $t1->left->right = new TreeNode(4); 46 | $t1->left->left->left = new TreeNode(5); 47 | $t1->right = new TreeNode(6); 48 | 49 | $t2 = $t1->left; 50 | 51 | var_dump(HasSubtree($t1, $t2)); // true -------------------------------------------------------------------------------- /剑指offer/字符串的排列.php: -------------------------------------------------------------------------------- 1 | $num2) { 15 | $temp = $numbers[$i]; 16 | $numbers[$i] = $numbers[$j]; 17 | $numbers[$j] = $temp; 18 | } 19 | } 20 | } 21 | return implode('', $numbers); 22 | } 23 | 24 | var_dump(PrintMinNumber([3, 32, 321])); // 321323 -------------------------------------------------------------------------------- /剑指offer/数值的整数次方.php: -------------------------------------------------------------------------------- 1 | > 1; 33 | if ($n % 2 === 0) { 34 | return PowerSoft($base, $div) * PowerSoft($base, $div); 35 | } else { 36 | return PowerSoft($base, $div) * PowerSoft($base, $div) * $base; 37 | } 38 | } 39 | 40 | var_dump(Power(1.1, 2)); // 1.21 41 | var_dump(Power(2, 3)); // 1.21 -------------------------------------------------------------------------------- /剑指offer/数组中出现次数超过一半的数字.php: -------------------------------------------------------------------------------- 1 | > 1; 13 | for ($i = 0; $i < $len; $i++) { 14 | if (!isset($hash[$numbers[$i]])) { 15 | $hash[$numbers[$i]] = 1; 16 | } else { 17 | $hash[$numbers[$i]]++; 18 | } 19 | if ($hash[$numbers[$i]] > $midLen) { 20 | return $numbers[$i]; 21 | } 22 | } 23 | return 0; 24 | } 25 | 26 | var_dump(MoreThanHalfNum_Solution([1, 2, 3, 2, 2, 2, 5, 4, 2])); -------------------------------------------------------------------------------- /剑指offer/整数中1出现的次数(从1到n整数中1出现的次数).php: -------------------------------------------------------------------------------- 1 | $rotateArray[$right]) { 22 | $left = $center; 23 | } 24 | } 25 | return min($rotateArray[$left], $rotateArray[$right]); 26 | } 27 | 28 | var_dump(minNumberInRotateArray([7, 8, 9, 1, 2, 3, 4, 5, 6])); // 1 -------------------------------------------------------------------------------- /剑指offer/替换空格.php: -------------------------------------------------------------------------------- 1 | $len) { 13 | return []; 14 | } 15 | $maxHeap = new SplMaxHeap(); 16 | for ($i = 0; $i < $len; $i++) { 17 | if ($maxHeap->count() < $k) { 18 | $maxHeap->insert($input[$i]); 19 | } else { 20 | if ($maxHeap->top() >= $input[$i]) { 21 | $maxHeap->extract(); 22 | $maxHeap->insert($input[$i]); 23 | } 24 | } 25 | } 26 | $ans = []; 27 | while ($maxHeap->valid()) { 28 | $ans[] = $maxHeap->current(); 29 | $maxHeap->next(); 30 | } 31 | return array_reverse($ans); 32 | } 33 | 34 | var_dump(GetLeastNumbers_Solution([4, 5, 1, 6, 2, 7, 3, 8], 4)); // 1,2,3,4 -------------------------------------------------------------------------------- /剑指offer/栈的压入,弹出序列.php: -------------------------------------------------------------------------------- 1 | val = $val; 15 | } 16 | } 17 | 18 | function HasSubtree($pRoot1, $pRoot2) 19 | { 20 | if ($pRoot1 === null || $pRoot2 === null) { 21 | return false; 22 | } 23 | return judgeTree($pRoot1, $pRoot2) || 24 | judgeTree($pRoot1->left, $pRoot2) || 25 | judgeTree($pRoot1->right, $pRoot2); 26 | } 27 | 28 | function judgeTree($r1, $r2) 29 | { 30 | if ($r2 === null) { 31 | return true; 32 | } 33 | if ($r1 === null) { 34 | return false; 35 | } 36 | if ($r1->val !== $r2->val) { 37 | return judgeTree($r1->left, $r2) || 38 | judgeTree($r1->right, $r2); 39 | } 40 | return judgeTree($r1->left, $r2->left) && 41 | judgeTree($r1->right, $r2->right); 42 | } 43 | 44 | 45 | $t1 = new TreeNode(1); 46 | $t1->left = new TreeNode(2); 47 | $t1->left->left = new TreeNode(3); 48 | $t1->left->right = new TreeNode(4); 49 | $t1->left->left->left = new TreeNode(5); 50 | $t1->right = new TreeNode(6); 51 | 52 | $t2 = $t1->left; 53 | 54 | var_dump(HasSubtree($t1, $t2)); // true -------------------------------------------------------------------------------- /剑指offer/矩形覆盖.php: -------------------------------------------------------------------------------- 1 | 2: f(n) = f(n - 1) + f(n - 2) 8 | // n = 2: f(n) = 2 9 | // n = 1: f(n) = 1 10 | 11 | function jumpFloor($number) 12 | { 13 | $dp = [1, 2]; 14 | $i = 2; 15 | while ($i < $number) { 16 | $dp[$i] = $dp[$i - 1] + $dp[$i - 2]; 17 | $i++; 18 | } 19 | return $dp[$number - 1]; 20 | } 21 | 22 | var_dump(jumpFloor(2)); // 1 23 | var_dump(jumpFloor(3)); // 2 -------------------------------------------------------------------------------- /剑指offer/连续子数组的最大和.php: -------------------------------------------------------------------------------- 1 | val = $val; 16 | } 17 | } 18 | 19 | function reConstructBinaryTree($pre, $vin) 20 | { 21 | if (empty($pre) || empty($vin)) { 22 | return null; 23 | } 24 | $tree = new TreeNode($pre[0]); 25 | $len = count($vin); 26 | for ($midIndex = 0; $midIndex < $len; $midIndex++) { 27 | if ($tree->val === $vin[$midIndex]) { 28 | break; 29 | } 30 | } 31 | var_dump($midIndex); 32 | $left = array_slice($vin, 0, $midIndex); 33 | $right = array_slice($vin, $midIndex + 1, count($vin) - $midIndex - 1); 34 | $tree->left = reConstructBinaryTree(array_slice($pre, 1, count($left)), $left); 35 | $tree->right = reConstructBinaryTree(array_slice($pre, count($left) + 1, count($right)), $right); 36 | 37 | return $tree; 38 | } 39 | 40 | var_dump(reConstructBinaryTree([1, 2, 4, 7, 3, 5, 6, 8], [4, 7, 2, 1, 5, 3, 8, 6])); -------------------------------------------------------------------------------- /剑指offer/链表中倒数第k个节点.php: -------------------------------------------------------------------------------- 1 | val = $x; 14 | } 15 | } 16 | 17 | function FindKthToTail($head, $k) 18 | { 19 | if (empty($head) || $k < 1) { 20 | return null; 21 | } 22 | $fast = $head; 23 | $n = $k - 1; 24 | while ($n > 0) { 25 | $fast = $fast->next; 26 | if ($fast === null) { 27 | return null; 28 | } 29 | $n--; 30 | } 31 | $slow = $head; 32 | while ($fast->next !== null) { 33 | $fast = $fast->next; 34 | $slow = $slow->next; 35 | } 36 | return $slow; 37 | } 38 | 39 | $l = new ListNode(1); 40 | 41 | $l->next = new ListNode(2); 42 | $l->next->next = new ListNode(3); 43 | $l->next->next->next = new ListNode(4); 44 | $l->next->next->next->next = new ListNode(5); 45 | 46 | var_dump(FindKthToTail($l, 3)); // 3 47 | var_dump(FindKthToTail($l, 5)); // 1, 2, 3, 4, 5 48 | -------------------------------------------------------------------------------- /加密/加密.md: -------------------------------------------------------------------------------- 1 | # 加密 -------------------------------------------------------------------------------- /娱乐/工业2.md: -------------------------------------------------------------------------------- 1 | # 工业2 2 | 3 | ## 风力发电耗材 4 | 5 | ### 风力动能发生机: 6 | 7 | 铁柄 * 2 = 铁块 * 2 = 铁 * 18 8 | 基础机械外壳 * 1 = 铁板 * 8 9 | 10 | ### 动能发电机 11 | 12 | 铁质外壳 * 6 = 铁板 * 3 13 | 火力发电机 * 1 = 电池 * 1 + 基础机械外壳 * 1 + 熔炉 * 1 14 | 铁柄 * 1 = 铁 * 9 15 | 电动马达 * 1 = 铁 * 1 + 锡外壳 * 2 + 线圈 * 2 16 | 17 | 电池 = 4锡外壳 + 1包锡线 + 2红石 18 | 19 | 合计: 20 | 21 | 铁:18 + 8 + 3 + 8 + 1 + 2 + 9 = 49 个铁 22 | 23 | 其中需要 24 | 25 | 铁 = 18 + 9 + 1 + 2 = 30 个 26 | 铁板 = 8 + 8 = 16 个 27 | 铁外壳 = 6 个 28 | 29 | 铜:4铜 = 16 铜线 30 | 锡:6 外壳 = 3 板 = 3锡 31 | -------------------------------------------------------------------------------- /有感/编程有感.md: -------------------------------------------------------------------------------- 1 | # 编程有感 2 | 3 | ## 业务代码不要抱侥幸心理, 一些注意到的地方因为懒得去改先用着, 结果一段时间后问题还是会暴露出来 4 | -------------------------------------------------------------------------------- /编程/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhan3333/note/1610b236fa253cc4004dc44ab7440b8584c6b6a0/编程/.DS_Store -------------------------------------------------------------------------------- /设计/实时匿名通讯.md: -------------------------------------------------------------------------------- 1 | # 实时匿名通讯 2 | 3 | ## 目标 4 | 5 | 使用端对端加密, 聊天房的形式实现加密匿名通信 6 | 7 | ## 基础流程 8 | 9 | 1. 打开应用 10 | 2. 输入昵称 11 | 3. 选择已有频道/创建频道 12 | 4. 开始发送消息/接收消息 13 | 14 | ## 技术栈 15 | 16 | 1. Golang 17 | 2. Redis 18 | 19 | 协议: UDP, 不需要保证到达, 实时通信 20 | 21 | ## 结构 22 | 23 | 客户端登录 -> 服务器 -> 客户端发送信息 -> 服务器接收信息 -> 推送到频道 -> 频道推送数据到客户端 -------------------------------------------------------------------------------- /设计模式/Laravel中用到的设计模式.md: -------------------------------------------------------------------------------- 1 | # Laravel 中使用到的设计模式 2 | 3 | ## 依赖注入模式 (Dependency Injection 实现 Inversion of Control) 4 | 5 | 在框架中,$app 对象是容器,其中的 $instances 数组保存已经实例化的对象,没有实例话的对象也有相对应的关联机制。使用一些服务对象时,将会从容器中取出,容器将按照设定好的解析规则返回实例化好的对象。 6 | 7 | ## 门面模式 (Facade) 8 | 9 | Laravel 通过使用门面以静态类的方式来提供容器中的服务。 10 | 11 | ## 装饰者模式 12 | 13 | 中间件使用的是装饰者模式。 14 | 15 | ## 单例模式 16 | 17 | ## 工厂模式 18 | -------------------------------------------------------------------------------- /设计模式/中介者模式.md: -------------------------------------------------------------------------------- 1 | # 中介者模式 2 | 3 | > 中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立的改变他们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。 4 | 5 | ## 举例 6 | 7 | 中介者模式将一个网状系统结构编程一个以中介者对象为中心的星型结构,在这个星型结构中,使用中介者对象与其它对象的一对多关系来取代原有对象之间的多对多关系。所有成员通过中介者交互,方便扩展新的成员,例如下面的例子,新增一个聊天室成员只需要新建一个成员实例,然后再在聊天室中介者那注册就可以加入聊天室了。 8 | 9 | ## 优点 10 | 11 | - 中介者模式简化了对象之间的交互,它用中介者和同事的一对多交互代替了原来同事之间的多对多交互,一对多关系更容易理解、维护和扩展,将原本难以理解的网状结构转换成相对简单的星型结构。 12 | - 中介者模式可将同事对象解耦。中介者有利于各同事之间的松耦合,我们可以独立的改变和复用每一个同事和中介者,增加新的中介和新的同事类都比较方便,更好地符合“开闭原则”。 13 | - 可以减少子类的生成,中介者将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成新的中介者子类即可,这使各个同事类可被重用,无需对同事类进行扩展。 14 | 15 | ## 缺点 16 | 17 | - 在具体中介类中包含了大量同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。 18 | -------------------------------------------------------------------------------- /设计模式/享元模式.md: -------------------------------------------------------------------------------- 1 | # 享元模式 2 | 3 | > 享元模式(Flyweight Pattern): 运用共享技术复用大量细粒度的对象,降低程序内存的占用,提高程序的性能。 4 | 5 | 举例: 例如`UITableViewCell`的缓存机制,大道降低内存消耗的目的。举例,音乐服务根据收费划分出免费用户和会员用户,免费用户只能听部分免费音乐,会员可以听全部的音乐,并且可以下载。虽然二者权限上有所区别,但是他们所享受的音乐是来自同一个音乐库,这样所有的音乐都只需要保存一份就可以了。另外,如果出现音乐库里没有的音乐时,则需要新增该音乐,然后其他服务也可以享受新增的音乐,相当于享元池或者缓存池的功能。 6 | 7 | 享元模式保证共享内部状态如音乐库,而外部状态根据不同需求定制各种访问权限,使用中不能去改变内部状态,以达到共享的目的。 8 | 9 | ## 优点 10 | 11 | - 使用享元模式可以减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份,降低系统的使用内存,也可以提升性能。 12 | - 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。 13 | 14 | ## 缺点 15 | 16 | - 使用享元模式需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。 17 | - 对象在缓冲池中的复用需要考虑线程问题。 18 | -------------------------------------------------------------------------------- /设计模式/什么是接口.md: -------------------------------------------------------------------------------- 1 | # 什么是接 2 | 3 | ## 对象接口 4 | 5 | 使用接口(`interface`),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。 6 | 7 | 接口是通过`interface`关键字来定义的,就想定义一个类一样,但是其中所有的方法都是空的。 8 | 9 | 接口中定义的所有方法都必须是公有,这是接口的特性。 10 | 11 | ## 实现 12 | 13 | 要实现一个接口,使用`implements`操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。 14 | 15 | 1. 实现多个接口时,接口中的方法不能有重名。 16 | 2. 接口也可以继承,通过使用`extends`操作符 17 | 3. 类要实现接口,必须使用接口中所定义的方法完全一致的方式。否则会导致致命错误。 18 | 19 | ## 常量 20 | 21 | 接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。 22 | 23 | ## 作用 24 | 25 | 接口加上类型约束,提供了一种很好的方式来确保某个对象包含有某些方法。参见`instanceof`操作符和类型约束。 26 | 27 | 例如 -------------------------------------------------------------------------------- /设计模式/代理模式.md: -------------------------------------------------------------------------------- 1 | # 代理模式 2 | 3 | > 代理模式(Proxy Pattern):为某个对象提供一个代理,并由这个代理对象控制对原对象的访问。 4 | 5 | 举例: 6 | 7 | 代理模式像一个房屋中介,卖家只能通过中介来买房,代理具备被代理类的所有功能,就像房东由卖房功能,中介也具有卖房功能。此外代理实例还可以帮助被代理实例进行一些额外处理,比如说中介可以帮助房东筛选优质买家的功能,帮助房东pass掉一些不符合条件的买家。还有消息队列也是该模式。 8 | -------------------------------------------------------------------------------- /设计模式/单例模式.md: -------------------------------------------------------------------------------- 1 | # 单例模式 2 | 3 | > 单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模属于创建型模式,它提供了一种创建对象的最佳方式。 4 | > 5 | > 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。 6 | > 7 | > 这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。 8 | 9 | **注意** 10 | 11 | - 单例类只能有一个实例。 12 | - 单例类必须自己创建自己的唯一实例。 13 | - 单例类必须给所有其他对象提供这一实例。 14 | 15 | ## 介绍 16 | 17 | 意图: 保证一个类仅有一个实例,并提供一个访问它的全局访问点 18 | 19 | 主要解决:一个全局使用的类频繁的创建与销毁 20 | 21 | 如何使用:当你想控制实例数目,节省系统资源的时候 22 | 23 | 关键代码:构造函数是私有的,且不允许克隆 24 | 25 | ### 应用实例 26 | 27 | 1. 一个班只有一个班主任。 28 | 2. Windows是多进程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。 29 | 3. 一些设备管理器常常设计为单例模式,比如一个电脑有两个打印机,咋输出的时候就要处理不能两台打印机打印同一个文件 30 | 31 | ### 优点 32 | 33 | 1. 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 34 | 2. 避免对资源的多重占用(比如写文件操作)。 35 | 36 | ### 缺点 37 | 38 | 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面真么样来实例化。 39 | 40 | ### 使用场景 41 | 42 | 1. 要求生产唯一序列号 43 | 2. WEB 中的计数器,不用每次刷新都要在数据库里加一次,用单例储存起来 44 | 3. 创建一个对象需要消耗的资源过多,比如`I/O`与数据库的连接等。 45 | 46 | **注意事项**: `getInstance()`方法中需要使用同步锁 synchronized (Singleton.class)防止多线程同时进入造成instance多次实例化(有多种方式来避免这样的情况,下文见) -------------------------------------------------------------------------------- /设计模式/外观模式.md: -------------------------------------------------------------------------------- 1 | # 外观模式 2 | 3 | > 外观模式(Facade Pattern):外观模式定义了一个高层接口,为子系统中的一组接口提供一个统一的接口。外观模式又称为门面模式,它是一种结构型设计模式。 4 | 5 | 举例: 6 | 7 | 外观模式提供了简单明确的接口,但是在内部众多子系统功能进行整合。就像图片缓存,内部包含了涉及到其它子系统的如缓存、下载处理,外观模式将这些错综复杂的逻辑都隐藏了。在`UIImageView`和`UIButton`调用的时候,你只需要调一个`setImageWithUrl:(NSString *)url`接口就可以了,达到了解耦的目的。 8 | 9 | 优点: 10 | 11 | - 实现了客户端与子系统之间的解耦:客户端无需知道子系统的接口,简化了客户端调用子系统的调用过程,使得子系统使用起来更加容易。同时便于子系统的扩展与维护。 12 | - 符合迪米特法则(最少知道原则):子系统只需要将外部调用的接口暴露给外观类即可,而且他的接口则可以隐藏起来。 13 | 14 | 缺点: 15 | 16 | - 违背了开闭原则:在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的代码。 17 | -------------------------------------------------------------------------------- /设计模式/对象池模式.md: -------------------------------------------------------------------------------- 1 | # 对象池模式 2 | 3 | > 对象池 (也称为资源池)被用来管理对象缓存。对象池是一组已经初始化过而且可以直接使用的对象集合,用户在使用对象时可以从对象池中获取对象,对其进行操作处理,并在不需要时归还给对象池而非销毁它。 4 | > 5 | > 若对象初始化、实例化的代价高,且经常需要实例化,但每次实例化的数量较少的情况下,使用对象池可以获得显著的性能提升。常见的使用对象池模式的技术包括线程池、数据库连接池、任务队列池、图片资源对象池等。 6 | > 7 | > 当然,如果实例化的对象较小,不需要多少资源开销,就没有必要使用对象池模式了,这非但不会提升性能,反而浪费内存空间,甚至降低性能。 8 | 9 | -------------------------------------------------------------------------------- /设计模式/工厂模式.md: -------------------------------------------------------------------------------- 1 | # 工厂模式 2 | 3 | >工厂模式(Factory Pattern)是最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 4 | 在工厂模式中,我们在创建对象时不会对客户暴露创建逻辑,而是用过使用一个共同的接口来指向新创建的对象。 5 | 6 | ## 介绍 7 | 8 | - **意图**: 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类中进行。 9 | 10 | - **主要解决**:主要解决接口选择的问题。 11 | 12 | - **何时使用**:我们明确计划不同条件下创建不同的实例时。 13 | 14 | - **如何使用**:我们明确地计划不同条件下创建不同实例时。 15 | 16 | - **如何解决**:让其子类实现工厂接口返回,返回的也是一个抽象的产品。 17 | 18 | - **关键代码**:创建过程在其子类执行。 19 | 20 | - **应用实例**: 21 | 22 | 1. 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 23 | 2. Hibernate 换数据库只需要换方言和驱动就可以。 24 | 3. Laravel Cache 驱动可以使用 MySQL,File,Redis,Mongodb,memcached, apc 等等 25 | 26 | - **优点**: 27 | 28 | 1. 一个调用者想要创建一个对象,只需要其名称就可以了。 29 | 2. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 30 | 3. 屏蔽产品的具体实现,调用者只关心产品的接口。 31 | 32 | - **缺点**: 33 | 34 | 1. 每增加一个产品时,都需要正加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。 35 | 36 | - **使用场景** 37 | 38 | 1. 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 39 | 2. 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 40 | 3. 设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。 41 | 42 | - **注意事项**: 作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。 43 | -------------------------------------------------------------------------------- /设计模式/建造者模式.md: -------------------------------------------------------------------------------- 1 | # 建造者模式 2 | 3 | > 建造者模式(Builder Pattern) 使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 4 | > 5 | > 一个Builder类会一步一步构造最终的对象。该Builder类是独立于其他对象的。 6 | 7 | ## 介绍 8 | 9 | 意图:将一个复杂的构建与其标示相分离,使得同样的构建过程可以创建不同的标示。 10 | 11 | 主要解决:主要解决在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的裱花,但是将他们组合在一起的算法却相对稳定。 12 | 13 | 何时使用:一些部分部件不会变,而其组合经常变化的时候。 14 | 15 | 如何解决:将变与不变分离开。 16 | 17 | 关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系 18 | 19 | 应用实例: 20 | 21 | 1. 去肯德基,汉堡、可乐、薯条、炸鸡等是不变的,而其组合是经常变化的,生成出所谓的“套餐”。 22 | 2. JAVA中的StringBuilder。 23 | 24 | 优点: 25 | 26 | 1. 建造者独立,易扩展。 27 | 2. 便于控制细节风险。 28 | 29 | 缺点: 30 | 31 | 1. 产品必须有共同点,范围有限制。 32 | 2. 如内部变化复杂,会有很多的建造类。 33 | 34 | 使用场景: 35 | 36 | 1. 需要生成的对象具有复杂的内部结构。 37 | 2. 需要生成的对象内部属性本身互相依赖。 38 | 39 | 注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。 -------------------------------------------------------------------------------- /设计模式/抽象工厂模式.md: -------------------------------------------------------------------------------- 1 | # 抽象工厂模式 2 | 3 | > 抽象工厂模式(Abstract Factory Pattern) 是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 4 | 5 | > 在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。 6 | 7 | > 简单理解:提供一个大工厂接口,其他工厂实现这个接口用于提供不同的产品组 8 | 9 | ## 介绍 10 | 11 | ### 意图 12 | 13 | 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们实现的类。 14 | 15 | ### 主要解决 16 | 17 | 主要解决接口选择的问题。 18 | 19 | ### 何时使用 20 | 21 | 系统的产品有多于一个的产品族,而系统只消费其中某一族的产品 22 | 23 | ### 如何解决 24 | 25 | 在一个产品族中,定义多个产品 26 | 27 | ### 关键代码 28 | 29 | 在一个工厂里聚合多个同类产品 30 | 31 | ### 应用实例 32 | 33 | 工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OO 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。 34 | 35 | ### 优点 36 | 37 | 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象 38 | 39 | ### 缺点 40 | 41 | 产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的Creator里加代码,又要在具体的里面加代码 42 | 43 | ### 使用场景 44 | 45 | 1. QQ换皮肤,一套一起换 46 | 47 | 2. 生成不同操作系统的程序 48 | 49 | ### 注意事项 50 | 51 | 产品族难扩展,产品等级易扩展 -------------------------------------------------------------------------------- /设计模式/模板方法模式.md: -------------------------------------------------------------------------------- 1 | # 模板方法模式 2 | 3 | > 模板方法模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 4 | 5 | ## 举例 6 | 7 | 模板方法模式在IOS中的应用也非常多,如UIViewController的生命周期函数,定义在父类,子类可以重写这些函数。 8 | 模板方法模式具体应用又分为三类: 9 | 10 | - 抽象方法:一个抽象方法由抽象类声明,由其具体子类实现。 11 | - 具体方法:一个具体方法由一个抽象类或具体类声明实现,其子类可以进行覆盖也可以直接继承。 12 | - 钩子方法:一个具体方法由一个抽象类或具体类声明并实现,而其子类可能会加以扩展。通常在父类中给出的是实现一个空实现,并以该空实现作为方法的默认实现,当然钩子方法也可以提供一个非空的默认实现。通过在子类中实现的钩子方法对父类方法的执行进行约束,实现子类对父类行为的反向控制。 13 | 14 | ## 优点 15 | 16 | - 在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。 17 | - 模板方法模式是一种代码复用技术,它在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类中 18 | - 可实现一种反向控制结构,通过子类覆盖父类父类的钩子方法来决定某一特定步骤是否需要执行。 19 | - 在模板方法模式中可以通过子类覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。 20 | 21 | ## 缺点 22 | 23 | - 需要为每一个基本方法的不同实现提供个一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象,此时,可结合桥接模式来进行设计。 24 | -------------------------------------------------------------------------------- /设计模式/状态模式.md: -------------------------------------------------------------------------------- 1 | # 状态模式 2 | 3 | > 状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。 4 | 5 | ## 举例 6 | 7 | 状态模式用于解决复杂对象的状态转换以及不同状态下的封装问题。当系统中某个对象存在多个状态,这些状态之间可以进行转化,所以对象在不同状态下具有不同行为时可以使用状态模式。状态模式将一个对象的状态从该对象中分离开来,封装到专门的状态类中,使得对象状态可以灵活变化。 8 | 9 | 我们可以做一个简单的例子,我设计了一个银行账户系统,根据存钱余额来自动设置账户的状态,银行账户在不同的状态下,进行存钱、取钱和借钱的行为。在不同状态下,这些行为的回复也不一样,比如说没有余额时无法取钱,只能借钱。 10 | 11 | ## 优点 12 | 13 | - 封装了状态的转换规则,在状态模中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。 14 | - 将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。 15 | - 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以放我们避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。 16 | - 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。 17 | 18 | ## 缺点 19 | 20 | - 状态模式的使用必然会增加系统中类和对象的个数,导致系统运行开销增大。 21 | - 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,增加系统设计的难度。 22 | - 状态模式对“开闭原则”的支持不太好,增加新的状态类需要修改那些负责状态转换的源代码,否则无法转换到自增状态;而且修改某个状态类的行为也需要改对应类的源代码。 23 | -------------------------------------------------------------------------------- /设计模式/策略模式.md: -------------------------------------------------------------------------------- 1 | # 策略模式 2 | 3 | > 策略模式(Strategy Pattern):定义一系列算法类,将每一个算法封装起来,并让它们可以互相替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为模式。 4 | 5 | ## 举例 6 | 7 | 使用策略模式时,我们可以定义一些策略类,每一个策略类中封装一种具体的算法。在这里,每一个封装算法的类我们都可以称之为一种策略,根据传入不同的策略类,使环境类执行不同策略类中的算法。 8 | 9 | 生活中也有很多类似的例子,就比如说商城的会员卡机制。我们去商城购物可以通过持有的会员卡打折,购买同一件商品时,持有不同等级的会员卡,就能得到不同力度的折扣。 10 | 11 | ## 优点 12 | 13 | - 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活的增加新的算法或行为。 14 | - 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族,恰当使用继承可以把公共的代码移到策略类中,从而避免重复代码。 15 | - 策略模式提供了一种可以替换继承关系的办法。如果不使用策略模式,那么使用算法的环境就可能会有一些子类,每一个子类提供一种不同的算法。但是,这样一来算法的使用就和算法本身混在一起,不符合“单一职责”原则,决定使用哪一种算法的逻辑和该算法本身混合在一起,从而不可能在独立化;而且使用继承无法实现算法或行为在程序运行时的动态切换。 16 | - 使用策略模式可以避免多重条件选择语句。多重条件选择语句不易维护,它把采取哪一种算法或行为的逻辑与算法或行为本身的实现逻辑混合在一起,将它们全部硬编码在一个庞大的多重条件中,比直接继承环境类的办法还要原始和落后。 17 | - 策略类模式提供了一种算法的复用机制,由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。 18 | 19 | ## 缺点 20 | 21 | - 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。换言之,策略模式只适合客户端知道所有的算法或行为的情况。 22 | - 策略模式将造成系统产生许多具体的策略类,任何细小的变化都将导致系统要增加一个新的具体的策略类。 23 | - 无法同时在客户端使用多个策略类,也就是说,在使用策略模式时,客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类来完成剩余功能的情况。 24 | -------------------------------------------------------------------------------- /设计模式/职责链模式.md: -------------------------------------------------------------------------------- 1 | # 职责链模式 2 | 3 | > 职责链模式(Chain of Responsibility Pattern):避免请求发送者与接受者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为模式。 4 | 5 | ## 举例 6 | 7 | 职责链模式在IOS中有大量应用,比如事件响应链,事件传递下来会先判断该事件是不是该有自己处理,如果不是由自己处理则传给下一位响应者区处理,如此循环下去。需要注意的是要避免响应链循环调用造成死循环,还有当所有的响应者都无法处理时的情况。 8 | 9 | ## 优点 10 | 11 | - 职责链模式使得一个对象无需指导是其他哪一个对象处理其请求,对象仅需指导该请求会被处理即可,接受者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度。 12 | - 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的后选择处理的引用,可简化对象的相互连接。 13 | - 在给对象分派指责时,职责链可以给我们更多灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。 14 | - 在系统中增加一个新的具体的请求处理者时无需修改原有系统代码,只需要在客户端重新建链即可,从这一点上来看是符合“开闭原则” 的。 15 | 16 | ## 缺点 17 | 18 | - 由于一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理。 19 | - 对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定的影响,而且在进行代码调试时不太方便。 20 | - 如果建链不当,可能会造成循环调用,将导致系统进入死循环。 -------------------------------------------------------------------------------- /设计模式/装饰模式.md: -------------------------------------------------------------------------------- 1 | # 装饰模式 2 | 3 | > 装饰模式 (Decorator Pattern): 不改变原有对象的前提下,动态地给一个对象增加一些额外的功能。 4 | 5 | ## 举例 6 | 7 | 装饰模式贴合开闭原则,在不改变原有类的情况下,对父类进行改造或新增功能。举例,定一个抽象类`Tea`,只能提供白开水,但是通过装饰类`BlackTea`装饰之后提供了新的功能,通过`BlackTea`类可以用白开水泡红茶,还可以选择加柠檬。 8 | 9 | ## 优点 10 | 11 | - 比继承更灵活:不同于在编译期起作用的继承;装饰者模式可以在运行时扩展一个对象的功能。另外也可以通过配置文件在运行时选择不同的装饰器,从而实现不同的行为。也可以通过不同的组合,可以实现不同的效果。 12 | 13 | - 符合开闭原则:装饰器和被装饰者可以独立变化。用户可以根据需要增加新的装饰类,在使用时再对其进行组合,原有代码无需改变。 14 | 15 | ## 缺点 16 | 17 | - 装饰者模式需要创建一些具体的装饰类,会增加系统的复杂度。 18 | -------------------------------------------------------------------------------- /设计模式/访问者模式.md: -------------------------------------------------------------------------------- 1 | # 访问者模式 2 | 3 | > 访问者模式(Visitor Pattern):提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下作用于这些元素的新操作。访问者模式是一种对象行为模式。 4 | 5 | ## 优点 6 | 7 | - 增加新的访问操作很方便。使用访问者模式,增加新的访问操作就意味着增加一个新的具体访问者类,实现简单,无需修改源代码,符合“开闭原则”。 8 | - 将有关元素的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以提供多个不同的访问者访问。 9 | - 让用户能够在不修改现有元素类层次结构的情况下,定义作用与该层次结构的操作。 10 | 11 | ## 缺点 12 | 13 | - 增加新的元素类很困难。在访问者模式中,每增加一个新的元素都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”的要求。 14 | - 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着对象元素有时候必须暴露一些自己的内部操作和内部状态,否则无法提供访问者访问。 15 | -------------------------------------------------------------------------------- /设计模式/适配器模式.md: -------------------------------------------------------------------------------- 1 | # 适配器模式 2 | 3 | > 适配器模式(Adapter Pattern):将一个接口转换客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式的别名是包装器模式(Wrapper),是一种结构型设计模式。 4 | 5 | ## 举例 6 | 7 | 适配器模式顾名思义,比如内地用像港版插头需要一个转接头。再比如iPhone的手机卡是特别小的Nano卡,把Nano卡拿到其他手机上不能贴合卡槽尺寸,所以我们需要加一个符合卡槽尺寸的卡套。 8 | 9 | ## 优点 10 | 11 | - 符合开闭原则:使用适配器而不需要改变现有类,提高类的复用性 12 | - 目标类和适配器解耦,提高程序扩展性 13 | 14 | ## 缺点 15 | 16 | - 增加了系统的复杂性 17 | -------------------------------------------------------------------------------- /设计模式/面向对象编程设计原则SOLID.md: -------------------------------------------------------------------------------- 1 | # SOLID 2 | 3 | **SOLID** 是 Michael Feathers 推荐的便于记忆的首字母简写 ,它代表了Robert Martin 命名的最重要的五个面向对象编程的设计原则: 4 | 5 | - S: 职责单一原则(SRP):对象应该仅具有一种单一功能 6 | - O: 开闭原则( OCP):软件本身应该是对于扩展开放的,但是对于修改是封闭的 7 | - L: 里氏替换原则(LSP):程序中的对象应该是可以在不改变程序正确性的前提下被它的子类所替换的 8 | - I: 接口隔离原则(ISP):多个特定客户端接口要好于一个宽泛用途的接口 9 | - D: 依赖反转原则(DIP):一个方法应该遵从“依赖与抽象而不是一个实例”,依赖注入是该原则的一种实现方式。 10 | -------------------------------------------------------------------------------- /面试/简历怎么写.md: -------------------------------------------------------------------------------- 1 | # 简历怎么写 2 | 3 | ## star 法则 4 | 5 | STAR法则:情境(situation)、任务(task)、行动(action)、结果(result) 6 | 7 | - Situation: 事情在什么情况下发生的 8 | - Task: 如果明确我的任务的 9 | - Action: 针对这样的情况分析, 我采用了什么行动方式 10 | - Result: 结果怎样, 再这样的情况下我学习到了什么 11 | 12 | ## FAB (Feature Advantage Benefit) 法则 13 | 14 | - Feature: 是什么 15 | - Advantage: 比别人好在哪里 16 | - 如果雇佣你, 招聘方会得到什么好处 17 | 18 | -------------------------------------------------------------------------------- /面试/练手项目.md: -------------------------------------------------------------------------------- 1 | # 整理一些练手的项目 2 | 3 | ## Golang 4 | 5 | - ffmpeg GUI 文件格式转换工具 6 | - office 文件格式转换工具 7 | - websocket 命令行聊天室 8 | - 实现内存型的 kv 数据库 --------------------------------------------------------------------------------