├── .github └── workflows │ └── jekyll-gh-pages.yml ├── .gitignore ├── .vscode └── settings.json ├── AI └── basic.md ├── Android ├── Java.md ├── Kotlin.md ├── feature.md ├── 内存.md ├── 基础知识.md └── 问题汇总.md ├── Back-end ├── DB.md ├── Docker.md ├── RESTful.md ├── Vapor.md ├── django.md ├── jwt.md ├── mysql.md ├── nginx.md ├── web服务器.md └── 后端学习.md ├── Base ├── C++.md ├── UML.md ├── algorithm-java.md ├── leetCode.md ├── leetcode │ ├── 两个排序数组的中位数.md │ ├── 两数之和.md │ ├── 两数相加.md │ ├── 无重复字符的最长子串.md │ └── 最长回文子串.md ├── nowCode.md ├── python.md ├── 操作系统.md └── 网络相关知识.md ├── Blockchain └── basic.md ├── Books └── iOS面试之道.md ├── CV └── basic.md ├── Flutter ├── Dart.md ├── Flutter_2.md ├── Flutter_3.md └── Flutter问题汇总.md ├── Front-end ├── CSS.md ├── FCC.md ├── JavaScript.md ├── Vue.md ├── basic.md ├── vue-context-mune.md ├── 前端学习.md └── 图解HTTP学习笔记.md ├── Game └── Cocos │ └── basic.md ├── Graphics ├── app.md └── metal.md ├── History ├── 2_Apple_History.md ├── 3_Mac_OS_X.md ├── 4_iOS.md └── images │ ├── iOS1.png │ ├── iOS10.png │ ├── iOS11.png │ ├── iOS2.png │ ├── iOS3.png │ ├── iOS4.png │ ├── iOS5.png │ ├── iOS6.png │ ├── iOS7.png │ ├── iOS8.png │ ├── iOS9.png │ ├── macOS1.jpg │ ├── macOS10.jpg │ ├── macOS11.jpg │ ├── macOS12.jpg │ ├── macOS13.jpg │ ├── macOS14.jpg │ ├── macOS15.jpg │ ├── macOS16.jpg │ ├── macOS17.jpg │ ├── macOS18.jpg │ ├── macOS19.jpg │ ├── macOS2.jpg │ ├── macOS3.jpg │ ├── macOS4.jpg │ ├── macOS5.jpg │ ├── macOS6.jpg │ ├── macOS7.jpg │ ├── macOS8.jpg │ ├── macOS9.jpg │ └── 斯卡利.jpg ├── LICENSE ├── Media ├── basic.md ├── feature.md └── images │ └── pts.jpg ├── MiniProgram ├── 小程序初探.md └── 小程序初探(二).md ├── NLP └── NLP.md ├── Others ├── header.png ├── myinterview.md ├── 招一个靠谱的iOS实习生(附参考答案).md ├── 简介.md └── 面试准备.md ├── Product └── Map.md ├── Project ├── Bonfire.md ├── CocosCreator——方块弹球.md ├── ONEUIKit-ONEProgressHUD.md ├── PFollow.md ├── PLook.md ├── coding-interview-university学习笔记.md ├── iBistu4-0(先导篇).md ├── iBistu4-0(地图).md ├── iBistu4-0(失物).md ├── iBistu4-0(新闻).md ├── iBistu4-0(黄页).md ├── 上架.md ├── 第三方库管理.md └── 翻译——ViewsprogrammingGuideforiOS.md ├── Qt ├── C++.md ├── UI.md ├── base.md ├── crossPlatform.md ├── images │ ├── 0.png │ ├── 1.png │ ├── 2.png │ ├── local_build_qt.jpg │ └── local_build_qt_fail.jpg ├── opt.md └── project.md ├── README.md ├── React-Native ├── React-Native记〇.md ├── React-Native记(一).md └── React-Native记(二).md ├── Test └── 单元测试.md ├── Tools ├── 2_百家汇.md ├── 3_GitHub.md ├── 4_Xcode.md ├── 5_Xcode.md ├── Playerground.md ├── Xcode.md ├── XcodeGuide.md ├── images │ ├── Dash 2.png │ ├── Dash 3.png │ ├── Dash 4.png │ ├── Dash 5.png │ ├── Dash.png │ ├── Flinto 1.png │ ├── Flinto 2.png │ ├── Flinto 5.png │ ├── Flinto 6.png │ ├── Flinto 7.png │ ├── Flinto.png │ ├── Flinto3.png │ ├── GitHub Desktop.png │ ├── GitHub.png │ ├── Postman 1.png │ ├── Postman 3.png │ ├── Postman2.png │ ├── Postman5.png │ ├── SourceTree 2.png │ ├── Swift playground.png │ ├── Swiftplayground.png │ ├── Swiftplayground1.png │ ├── Xcode 2.png │ ├── Xcode macos.png │ ├── Xcode.png │ ├── Xcode1.jpg │ ├── account.png │ ├── begintoxcode.png │ ├── c.png │ ├── cc.png │ ├── command Line Tool.png │ ├── error.png │ ├── error2.png │ ├── errorfix.png │ ├── imGitHub 2port.png │ ├── import.png │ ├── input.png │ ├── linus.png │ ├── newfile.png │ ├── openRank.png │ ├── paint.png │ ├── paintCode 1.png │ ├── paintCode.png │ ├── paintCode2.png │ ├── postman.png │ ├── selectfile.png │ ├── sourceTree.png │ ├── warning.png │ ├── xcode project.png │ ├── 偏好设计.png │ ├── 更改北京.png │ ├── 注释.png │ ├── 界面展示.png │ ├── 选择字号.png │ └── 选择背景.png └── 开发中可能会用到的内容.md ├── Toturial └── 剪刀石头布.md ├── UI ├── 3_StoryBoard.md └── images │ ├── Android 7.jpg │ ├── Android老.png │ └── iOS老.png ├── Weex └── Weex新手记.md ├── Win └── basic.md ├── iOS ├── Layout.md ├── More-弹幕.md ├── Objective-C │ ├── More-Audio.md │ ├── More-DesignPattern.md │ ├── More-iOS上的相机.md │ ├── More-iOS国际化一站式解决方案.md │ ├── More-视频相关.md │ ├── More-页面传值.md │ ├── Objective-C注意点.md │ ├── ping.md │ ├── runtime.md │ ├── tips-自定义tabBar大加号引发的思考.md │ ├── 并发编程.md │ └── 系统相关.md ├── Swift │ ├── Cache.md │ ├── CoreData.md │ ├── OC转Swift.md │ ├── PFollow.md │ ├── PJPickerView开发总结.md │ ├── PJPickerView开发总结.md).md │ ├── PhotosKit开发总结(一).md │ ├── Playgrounds.md │ ├── SpriteKit.md │ ├── SwiftUI.md │ ├── Swift注意点.md │ ├── UIDynamic.md │ ├── code.md │ ├── debug.md │ ├── landscapeandportrait.md │ ├── tips.md │ ├── 七牛图片上传助手.md │ ├── 品种选择器总结.md │ └── 自定义NavigationBar.md ├── Today_Extension.md ├── UI.md ├── UICollectionView.md ├── UITableView.md ├── basic.md ├── code.md ├── debug.md └── system.md ├── images └── render_pipline.jpg ├── macOS ├── TranslateP.md ├── basic.md ├── crash.md ├── kindle.md ├── macOS开发(词法分析器).md ├── performance.md ├── playground.md └── 一台设备多个git账号.md └── ruby └── basic.md /.github/workflows/jekyll-gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Deploy Jekyll with GitHub Pages dependencies preinstalled 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["master"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Build job 26 | build: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | - name: Setup Pages 32 | uses: actions/configure-pages@v4 33 | - name: Build with Jekyll 34 | uses: actions/jekyll-build-pages@v1 35 | with: 36 | source: ./ 37 | destination: ./_site 38 | - name: Upload artifact 39 | uses: actions/upload-pages-artifact@v3 40 | 41 | # Deployment job 42 | deploy: 43 | environment: 44 | name: github-pages 45 | url: ${{ steps.deployment.outputs.page_url }} 46 | runs-on: ubuntu-latest 47 | needs: build 48 | steps: 49 | - name: Deploy to GitHub Pages 50 | id: deployment 51 | uses: actions/deploy-pages@v4 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /AI/basic.md: -------------------------------------------------------------------------------- 1 | # AI 2 | 3 | ## 各种原则 4 | ### 金发姑娘原则 5 | * [相关链接](https://en.wikipedia.org/wiki/Goldilocks_principle) 6 | * 解释“金发姑娘原则”指出,凡事都必须有度,而不能超越极限。按照这一原则行事产生的效应就称为“金发姑娘效应”。 7 | 8 | ### 学习速率 9 | * 通过一个图来解释 10 | ![优化学习速率](https://i.loli.net/2019/07/18/5d3002110b29b87060.png) 11 | 12 | * 当「学习速率」过高,容易导致每一步都在曲线上进行跳跃,沿着曲线向上爬,而不是降到底部。 13 | 14 | 15 | ### 随机梯度下降法/ SGD 16 | 17 | ### 小批量随机梯度下降法/小批量 SGD 18 | 19 | ### 协同过滤 20 | * 基于用户的协同过滤算法 UserCF 21 | * 统计两个用户的相似度。两个用户阅读过的内容 ID 列表如果重合度越高,说明越相似。 22 | * 适合用在个性化需求不强,热点很明显的领域,比如新闻,电影推荐。 23 | * 基于物品的协同过滤算法 ItemCF 24 | * 适合用在个性化需求比较强,长尾比较长的领域,比如书、电商的推荐。 25 | 26 | ### 如何判断用户会不会点一个物品:特征 27 | * 用户特征 28 | * 历史上点击的文章列表 29 | * 历史上点击的文章的关键词分布 30 | * 历史上点击的文章的作者分布 31 | * 文章特征 32 | * 文章的作者,关键词 33 | * 用户和文章的交叉特征 34 | * 用户历史上有没有点过这篇文章的作者发表的其他文章 35 | * 用户历史上有没有点击过和这篇文章关键词类似的其他文章 36 | 37 | ### 文章冷启动 38 | * 推荐系统是所有的文章在一个候选池互相 PK,找到对当前用户兴趣最好的 39 | * 新文章因为展现少,在 PK 中往往落在下风 40 | * 要做一个专门的冷启动机制,保证新文章在展现小于 X 前在 PK 中取得更大的获胜概率,直到充分展现,可以在 PK 中公平竞争 -------------------------------------------------------------------------------- /Android/Java.md: -------------------------------------------------------------------------------- 1 | ## Java 2 | 3 | ### 注解 `@` 4 | 提到注解就要带上注释,注释是给开发者看的,而注解就是给程序自己看的。比较类似做一些小方法检查,压缩代码量,本质上与 Swift 5.5 引入的 `@PropertyWrapper` 作用一致。 5 | 6 | 注解分位编译期注解和运行时注解,作用范围不同。运行时注解可以通过反射进行获取使用,但反射本身有性能损耗。 -------------------------------------------------------------------------------- /Android/Kotlin.md: -------------------------------------------------------------------------------- 1 | # Kotlin 问题汇总 2 | 3 | ## 语法 4 | ### `var` 和 `val` 的区别 5 | `var` 与我们之前见到的 `var` 概念一致,但 `val` 取代了以往 `let` 作用。kotlin 中 `let` 另有他用。 6 | ```kotlin 7 | var a: String = "initial" // 1 8 | println(a) 9 | val b: Int = 1 // 2 10 | b = 2 11 | // 报错:Val cannot be reassigned 12 | ``` 13 | 14 | ### `vararg` 15 | 本质上是个 `Array` 的语法糖,但可以用“逗号”分隔开参数。在保证参数类型一致的情况下可以这么传参: 16 | ```kotlin 17 | class MutableStack(vararg items: E) { // 1 18 | 19 | private val elements = items.toMutableList() 20 | 21 | fun push(element: E) = elements.add(element) // 2 22 | 23 | fun peek(): E = elements.last() // 3 24 | 25 | fun pop(): E = elements.removeAt(elements.size - 1) 26 | 27 | fun isEmpty() = elements.isEmpty() 28 | 29 | fun size() = elements.size 30 | 31 | override fun toString() = "MutableStack(${elements.joinToString()})" 32 | } 33 | 34 | fun mutableStackOf(vararg elements: E) = MutableStack(*elements) 35 | 36 | fun main() { 37 | val stack = mutableStackOf(0.62, 3.14, 2.7) 38 | println(stack) 39 | } 40 | ``` 41 | 42 | ### class 43 | 44 | ```kotlin 45 | // 可以声明一个没有任何属性的 class,kotlin 会自动创建一个无参构造函数 46 | class Customer 47 | ``` 48 | 49 | * kotlin 的类默认是 `final`,如果该类想要被继承,需要用 `open` 进行修饰; 50 | * kotlin 的方法默认同样也是 `final`,在类中,如果想要的该方法可以被重载,需要用 `open` 进行修饰,并且在重载方法前加上 `override` 修饰; 51 | ```kotlin 52 | open class Dog { // 1 53 | open fun sayHello() { // 2 54 | println("wow wow!") 55 | } 56 | } 57 | 58 | class Yorkshire : Dog() { // 3 59 | override fun sayHello() { // 4 60 | println("wif wif!") 61 | } 62 | } 63 | 64 | fun main() { 65 | val dog: Dog = Yorkshire() 66 | dog.sayHello() 67 | } 68 | ``` 69 | #### 继承有参构造类 70 | 不得不说,这种写法真是太奇特了。 71 | 72 | ```kotlin 73 | open class Tiger(val origin: String) { 74 | fun sayHello() { 75 | println("A tiger from $origin says: grrhhh!") 76 | } 77 | } 78 | 79 | class SiberianTiger : Tiger("Siberia") // 1 80 | 81 | fun main() { 82 | val tiger: Tiger = SiberianTiger() 83 | tiger.sayHello() 84 | } 85 | ``` -------------------------------------------------------------------------------- /Android/feature.md: -------------------------------------------------------------------------------- 1 | ## feature 思考 2 | 3 | ### 拼多多自动拉起 app 4 | android 的四大基础组件中,只有 activity 是完整的用户可见应用程序入口,剩下的三大基础组件用户都不可见,可以通过 Service 来注册一个不可见的服务,在某些条件下唤起主 activity。 5 | 6 | 还有另外一种做法是 app 间互相拉起,接入一个中间层 SDK,目前猜测可能是友盟有类似的服务,在接入友盟后某个 app 被杀掉后,可以由另外的 app 拉起。 -------------------------------------------------------------------------------- /Android/内存.md: -------------------------------------------------------------------------------- 1 | ## 内存知识 2 | 3 | ### Java GC 4 | 大概流程详见:[https://zhuanlan.zhihu.com/p/23102625]() 5 | Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报 OOM(out of memory)的错误,Java应用将停止。 -------------------------------------------------------------------------------- /Android/基础知识.md: -------------------------------------------------------------------------------- 1 | # Android 基础 2 | 3 | 4 | ## 名词解释 5 | * APK:Android application package,Android 应用程序包; 6 | * 7 | 8 | ## APK 基础 9 | 应用安装到设备后,每个 APK 都运行在自己的**安全沙箱**中(这点与 ipa 一致): 10 | 11 | * Android 是一种多用户的 `Linux` 系统,其中每个应用都是一个不同的用户; 12 | * 默认情况下,系统会为每个应用分配一个**唯一的 Linux 用户 ID**(应用不知晓)。系统为应用中的所有文件设置权限,使得只有分配给该应用的用户 ID 才能访问这些文件; 13 | * 每个进程都具有自己的虚拟机,因此应用之间被隔离; 14 | * 默认情况下,每个应用都在自己的 Linux 进程内运行。 Android 会在需要执行任何应用组件时启动该进程,然后在不需要时将该进程或系统必须为其它应用程序恢复内存时杀掉该进程; 15 | 16 | Android 系统通过这种方式实现**最小权限原则**。默认情况下,每个英语都只能访问其工作所需的组件,而不能访问其它组件,在这个非常安全的环境中,应用无法访问系统中未获得权限的部分。但应用仍然可以通过一些途径与其它应用共享数据以及访问系统服务: 17 | 18 | * 可以让两个应用共享同一个 Linux 用户 ID,它们可以相互访问彼此的文件。为了节省资源,可以让具有**相同用户 ID **、**相同签名证书**的应用在同一 Linux 进程中运行,并共享同一虚拟机 19 | * 应用可以请求访问设备数据权限(联系人、相机、蓝牙等),用户必须明确授予这些权限。 20 | 21 | 22 | ## 应用组件(应用的基本构建基块) 23 | 系统都可以通过这些组件直接进入应用,但并非所以组件都是用户的实际入口。共有**四种不同的应用组件类型**,每种类型服务于不同的目的,并且具有定义组件创建和销毁方式的不同生命周期。 24 | 25 | 26 | * **`Activity`**:`Activity` 表示具有用户界面的单一屏幕。每一个 `Activity` 都独立于其它 `Activity` 而存在,其它应用可以启动其中任何一个 `Activity`。例如,相机应用可以启动 email 应用内用于撰写新电子邮件的 `Activity`,以共享图片。 27 | 28 | * **服务(`Service`)**:服务是一种在后台运行的组件,用于执行长时间运行的操作或为远程进程执行作业,且不提供用户界面。当用户设备前台处于其它应用时,服务可能在后台播放音乐或正在通过网络获取数据,此时并不会阻碍与 `Activity` 的交互。 `Activity` 等其它组件可以启动服务。 29 | 30 | * **内容提供程序(`ContentProvider`)**:内容提供程序管理一组共享的应用数据,您可以将数据存储在文件系统、SQLite 数据库、网络或其它可以被应用访问到的地方。其它应用可以通过内容提供程序查询、修改数据。任何具有适当权限的应用都可以查询内容提供程序的某一部分。 31 | 32 | * **广播接收器(`BroadcastReceiver`)**:广播接收器时一种用于响应系统范围广播通知的组件。许多广播都是由系统发起的,如通知屏幕已关闭、电池电量不足等,应用也可以发起广播,如其它应用某些数据已下载至该设备。同样,广播接收器也没有用户界面,但它们可以创建**状态栏通知**。 33 | 34 | 当系统启动某个组件时,会启动该应用的进程(如果还未运行),并实例化该组件所需的类。如果应用启动相机应用中拍摄照片的 `Activity` ,则该 `Activity` 会在属于相机应用的进程,而不是我们应用的进程中运行。所以,Android 应用并没有单一入口点(`main()` 函数)。 35 | 36 | 由于系统在单独的进程中运行每个应用,且其文件权限会限制对其它应用的访问,故我们的应用无法直接启动其它应用中的组件,但可通过 Android 系统传递消息,说明我们想要启动特定组件的 `intent`,系统随后便会启动。 37 | 38 | ### 启动组件 39 | `Activity` 、服务和广播接收器通过 `intent` 的异步消息进行启动。 `intent` 会在运行时将各个组件相互绑定(可将 `intent` 视为从其它组件请求操作的信使),无论该组件是否为我们的应用。 `intent` 可以是显式的也可以是隐式的。对 `Activity` 和服务, `intent` 定义要执行的操作,并且可以指定要执行操作数据的 URI。 40 | 41 | `intent` 不会启动内容提供程序组件,它会在成为 `ContentResolver` 的请求目标时启动,内容解析程序通过内容提供程序处理所有直接事物,使得通过提供程序执行事物的组件可以无需执行事物,而是改为在 `ContentResolver` 对象上调用方法,已留出一个抽象层确保安全。 42 | 43 | 每种类型的组件有不同的启动方法: 44 | 45 | * 可以通过将 `Intent` 传递到 `startActivity()` 或 `startActivityForResult()`(当您想让 `Activity` 返回结果时)来启动 `Activity`(或为其安排新任务)。 46 | 47 | * 可以通过将 `Intent` 传递到 `startService()` 来启动服务(或对执行中的服务下达新指令)。 或者,您也可以通过将 `Intent` 传递到 `bindService()` 来绑定到该服务。 48 | 49 | * 可以通过将 `Intent` 传递到 `sendBroadcast()`、`sendOrderedBroadcast()` 或 `sendStickyBroadcast()` 等方法来发起广播; 50 | 51 | * 可以通过在 `ContentResolver` 上调用 `query()` 来对内容提供程序执行查询。 52 | 53 | ## 清单文件 54 | 在 Android 系统启动应用组件之前,系统必须通过读取应用的 `AndroidManifest.xml` 文件(清单文件)来确认组件存在,应用必须在此文件中声明所有组件,该文件必须位于应用项目目录的根目录中。清单文件还有以下作用: 55 | 56 | * 确定应用需要的任何用户权限,如互联网访问权限或对用户联系人的读取权限; 57 | * 根据应用使用的 API,声明应用所需的最低 API 级别; 58 | * 声明应用使用或需要的硬件和软件功能,如相机、蓝牙服务; 59 | * 应用需要链接的 API 库(系统 API 除外); 60 | 61 | 通过以下方式声明所有应用组件: 62 | 63 | * Activity 的 `` 元素 64 | * 服务的 `` 元素 65 | * 广播接收器的 `` 元素 66 | * 内容提供程序的 `` 元素 67 | 68 | 如果在源码中写明的组件,但未再清单文件中声明的 `Activity`、服务和内容提供程序将对系统不可见且永远不会运行。不过广播接收器可以在清单文件中声明或在代码中动态创建,并在系统中注册即可。 69 | 70 | ### 声明组件功能 71 | 当在应用的清单文件中声明 `Activity` 时,可以选择性加入声明 `Activity` 功能的 `Intent` 过滤器,以便响应来自其它应用的 `Intent`,可以使用 `` 元素作为组件声明元素的子项进行添加来为您的组件声明 `intent` 过滤器。 72 | 73 | 例如,电子邮件应用包含一个用于撰写新电子邮件的 `Activity`,则可以像下面这样声明一个 `Intent` 过滤器来响应“send” Intent(以发送新电子邮件): 74 | 75 | ```xml 76 | 77 | ... 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | ``` 89 | 90 | 如果另一个应用创建了一个包含 `ACTION_SEND` 操作的 `Intent`,并将其传递到 `startActivity()`,则系统可能会启动您的 `Activity`,以便用户能够草拟并发送电子邮件。 91 | 92 | ### 声明应用要求 93 | 例如,如果您的应用需要相机,并使用 Android 2.1(API 级别 7)中引入的 API,您应该像下面这样在清单文件中以要求形式声明这些信息: 94 | 95 | ```xml 96 | 97 | 99 | 100 | ... 101 | 102 | ``` 103 | 104 | 现在,没有相机且 Android 版本低于 2.1 的设备将无法从 Google Play 安装您的应用。 105 | 106 | 不过,您也可以声明您的应用使用相机,但并不要求必须使用。 在这种情况下,您的应用必须将 `required` 属性设置为 "false",并在运行时检查设备是否具有相机,然后根据需要停用任何相机功能。 107 | 108 | 109 | ## 应用资源 110 | 如果应用包含一个名为 `logo.png` 的图像文件(保存在 `res/drawable/` 目录中),则 SDK 工具会生成一个名为 `R.drawable.logo` 的资源 ID,可以利用它来引用该图像并将其插入用户界面。 -------------------------------------------------------------------------------- /Android/问题汇总.md: -------------------------------------------------------------------------------- 1 | # Andriod 问题汇总 2 | ## 设备 3 | 新购了一台开发机 meizu 15。之前有考虑过小米6,但京东和淘宝上都没有找到靠谱的卖家,接着看了华为和三星,华为的低端机的外观实在是不敢恭维,三星的 A9 让我惊艳了一番,但价格有些稍贵,最后逛了 meizu,发现居然有了我当初高一高二时火爆的 meizu MX2 外观类似的机型!由于情怀因素,就购置了 meizu 15。 4 | 5 | ## 开发者模式 6 | Andriod 与 iOS 不一致的地方在于设备默认是“不可调试”的,必须打开“开发者模式”后才能进行调试,在 meizu 15 上,打开开发者模式的流程如下: 7 | * 设置-关于手机。滑动到最底下,找到“Andriod 版本”,连续点击 7 下,即可看到“已经打开开发者模式”的 toast 提示; 8 | * 设置-辅助功能-开发者选项(上一步未完成是看不到的)。开启开发者选型,且启动“USB 调试”。 -------------------------------------------------------------------------------- /Back-end/DB.md: -------------------------------------------------------------------------------- 1 | # 数据库相关知识点 2 | 3 | ## 备份 4 | * 先写日志,再写 SQL。这样可以保证当 SQL 写入出现问题时,可以查到日志。 5 | 6 | ### 备份策略 7 | 8 | 周日 | 周一 | 周二 | 周三 | 周四 | 周五 | 周六 | 9 | --- | --- | --- | --- | --- | --- | --- | 10 | 完全备份|增量备份|增量备份|增量备份|差量备份|增量备份|增量备份| 11 | 12 | 周四差量备份可以保证当周五或周六出现问题时,不用一次次的反复回复一二三的增量备份。 -------------------------------------------------------------------------------- /Back-end/RESTful.md: -------------------------------------------------------------------------------- 1 | # REST 2 | `HTTP` 是一种**应用层**协议,能从 `HTTP` 基础设施中获取多少收益,主要取决于把它用做应用层协议用得有多好。 3 | 4 | `HTTP` 实际上是为 `REST` 而生的,它能够表达状态和状态转移,者就是它位于应用层而非传输层的原因。 5 | 6 | ## 使用统一接口 7 | ### 如何保持交互的可见性 8 | 可见性是 `HTTP` 的一个核心特征。可见性是“一个组件能够对其他两个组件之间的交互进行监视或仲裁的能了”。当协议是可见的时,缓存、代理、防火墙等组件就可以监视甚至参与其中。 9 | 10 | `HTTP` 通过一下途径来实现可见性: 11 | * `HTTP` 的交互是无状态的,任何 `HTTP` 中介都可以推断出给定请求和响应的意义,而无须关联过去或将来的请求和响应。 12 | 13 | * `HTTP` 使用一个统一接口,包括有 `OPTIONS`,`GET`,`HEAD`,`POST`,`DELETE` 和 `TRACE` 方法。接口中的每一个方法操作一个且仅有一个资源。每个方法的语法和含义不会因应用程序或资源的不同而发生改变。 14 | 15 | * `HTTP` 使用一种与 [`MIME`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types) 类似的信封格式进行表述编码。这种格式明确区分标头和内容。标头时可见的,除了创建、处理消息的部分,软件的其他部分都可以不用关心消息的内容。 16 | 17 | 对于 `RESTful web` 服务,主要目标是尽可能保持可见性。保持可见性非常简单,使用 `HTTP` 方法时,其语义要与 `HTTP` 所规定的语义保持一致,并添加适当的标头来描述请求和响应。 18 | 19 | ## HTTP 方法的安全性和幂等性 20 | ### 安全性 21 | 安全性并不意味着服务器每次都必须返回同一结果。它只是表明客户端可以发送请求,并指导它不会改变资源的状态。 22 | ### 幂等性 23 | 幂等性保证客户的发起多次请求获取到的结果和一次请求获取到的结果一致。 24 | 25 | -------------------------------------------------------------------------------- /Back-end/jwt.md: -------------------------------------------------------------------------------- 1 | # JWT 2 | 这里将会记录我在学习 JWT 的过程中遇到的问题、思考和总结。 3 | 4 | ## JWT 简介 5 | 全称为 **J**SON **W**eb **T**oken。 6 | 7 | ## 彩虹表 -------------------------------------------------------------------------------- /Back-end/mysql.md: -------------------------------------------------------------------------------- 1 | # Mysql 2 | ## Mysql 的客户端/服务器架构 3 | `mysql` 的服务器进程默认名称为 `mysqld`,常用的 `mysql` 客户端进程的默认名称为 `mysql`。 4 | 5 | ## 启动 6 | `mysql -h主机名 -u用户名 -p密码` 7 | 8 | * `-h/--host=主机名`:后可跟服务器域名或 IP 地址,若 mysql 服务器进程运行在本机则可以省略; 9 | * `-u/--user=用户名`; 10 | * `-p/--password=密码`。 11 | 12 | ### 如果 mysql 默认端口号 3306 被占用 13 | 在启动 `mysql` 服务器时使用 `mysqld -P3307`,启动 `mysql` 客户端程序时使用 `mysql -u root -P3307 -p`,打写的 `-P` 代表选择 14 | 15 | ## 服务器处理客户端请求 16 | ### 连接管理 17 | 每当有一个客户端连接到 `mysql` 服务器进程时,服务器进程都会创建一个线程来处理与客户端的交互。当该客户端与服务器断开连接时,服务器并不会立即把该线程销毁,而是缓存起来供下一次使用。但线程开辟太多会影响系统性能,需要限制同时连接服务器的客户端数量。 18 | 19 | ### 查询缓存 20 | `mysql` 服务器会把已经处理过的查询请求和结果缓存起来,若下一次有相同的请求时,则从缓存中直接返回。但如果两个查询请求在任何自负上的不同,都会导致缓存不会命中。 21 | 22 | `mysql` 缓存系统会检测当前缓存中设计到的每张表,只要该表的结果或者数据被修改,则该表的所有高速缓存都将变为无效并删除。**从 mysql 8.0 中已移除**。 23 | 24 | 25 | ## 存储引擎 26 | 表,是有一行一行的记录组成的,但这只是逻辑上的概念,在物理上如何表示记录,怎么从表中读取数据,怎么把数据写入具体的物理存储器上,这都是存储引擎做的事情。我常用的 mysql 存储引擎为具备外键支持的事务存储引擎 **`InnoDB`** 。 27 | 28 | 其它常见的 `mysql` 存储引擎有: 29 | 30 | 存储引擎 | 描述 31 | ---- | ---- s 32 | MEMORY | 置于内存的表 33 | MyISAM | 主要的非事务处理存储引擎 34 | 35 | 36 | ### 设置表的存储引擎 37 | 存储引擎负责对表中的数据进行提取和写入工作的,可以**为不同的表设置白虎通你的存储引擎**,不同的表可以有不同的物理存储结构,不同的提取和写入方式。 38 | 39 | ## 启动选项和配置文件 40 | * mysql 服务器默认的客户端连接数量为:151; 41 | * 表的默认存储引擎为:`InnoDB`; 42 | * 通过 `-h` 方式来启动服务器程序时,客户端和服务器进程之间使用 `TCP/IP` 网络进行通信,如果想要禁止这种方式,可以在启动服务器命令选项中加上 `--skip_networking` 来禁止使用 `TCP/IP` 方式来进行连接。 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Back-end/nginx.md: -------------------------------------------------------------------------------- 1 | # nginx 2 | 3 | ## 错误日志地址 4 | `etc/log/nginx` 5 | 6 | ## -------------------------------------------------------------------------------- /Back-end/web服务器.md: -------------------------------------------------------------------------------- 1 | # 浅析 Web 服务器的工作原理(Java) 2 | ## 什么是 Web 服务器,应用服务器和 web 容器? 3 | ### web 服务器 4 | 在过去很长的一段时间中,它们是有区别的,但是这两个分类慢慢的合并了,而如今在大多情况下可以把它们看成一个整体。在早期,引发出“ web 服务器”的概念是因为通过了 HTTP 协议来提供静态页面内容和图片的服务,当时大部分内容都是静态的,并且 HTTP 1.0 只是一种传送文件的方式,但在不久后 web 服务器提供了 CGI 功能,意味着我们能够为每一个 web 请求启动一个进程来产生动态内容。现在 HTTP 协议已经非常成熟了并且 web 服务器变得更加复杂,拥有了例如缓存、安全和 session 管理等这些附加功能。 5 | 6 | ![WX20180930-155912@2x.png](https://i.loli.net/2018/09/30/5bb082c0d9a2e.png) 7 | 8 | ### 应用服务器 9 | 在同一时期,应用服务器已经存在并发展了很长一段时间了,大部分产品都指定了“封闭的”产品专用通信协议来互连胖客户端和服务器,在 90 年代,传统的应用服务器产品开始嵌入了 HTTP 通信功能,准备利用网关来实现。不久之后这两者的界限开始变得模糊。同时,web 服务器变得越来越成熟,可以处理更高的负载、更多的并发和拥有更好的特性;应用服务器开始添加越来越多的机遇 HTTP 的通信功能。所有的这些导致了 web 服务器与应用服务器的界线变得更窄了。 10 | 11 | 目前,应用服务器和 web 服务器之间的界线已经变得模糊不清了,但是人们还把这两个术语分开来。当有人说到 web 服务器时,我们通常要把它认为是以 HTTP 为核心、web UI 为向导的应用。当有人说到应用服务器时,你可能想到“高负载、企业级特性、事物和队列、多通道通行(HTTP 和更多的协议)”,但现在提供这些需求的基本上都是同一个产品。 12 | 13 | ### web 容器 14 | 在 java 中,web 容器一般就是指 Servlet 容器。Servlet 容器是与 Java Servlet 交互的 web 容器的组件。web 容器负责管理 Servlet 的生命周期、把 URL 映射到特定的 Servlet 、确保 URL 请求拥有正确的访问权限和更多类似的服务。综合来看,Servlet 容器就是用来运行你的 Servlet 和维护它的生命周期的运行环境。 15 | 16 | ![20180930161346.png](https://i.loli.net/2018/09/30/5bb085e59d02c.png) 17 | 18 | ### 什么是 Servlet?它们有什么用? 19 | 在 java 中,Servlet 使你能够编写根据请求动态生成内容的服务端组件。事实上,Servlet 是一个在 javax.servlet 包里定义的接口。它为 Servlet 的生命周期声明里三个基本方法 —— init()、service() 和 destroy() 。每个 Servlet 都要实现这些方法(在 SDK 里定义或者用户定义)并在它们的生命周期的特定时间由服务器来调用这些方法。 20 | 21 | 类加载器通过懒加载或者预加载自动地把 Service 类加载到容器里,每个请求都拥有自己的线程,而一个 Service 对象可以同时为多个线程服务。当 Service 对象不再被使用时,它就会被 JVM 当作垃圾回收掉。 22 | 23 | ### 什么是 ServletContext?它由谁创建 24 | 当 Servlet 容器启动时,它会部署并加载所有的 web 应用。当 web 应用被加载时,Servlet 容器会一次性为每个应用创建 Servlet 上下文(ServletContext)并把它保存在内存里。Servlet 容器会处理 web 应用的 web.xml 文件,并且一次性创建在 web.xml 文件里定义的 Servlet、Filter 和 Listener ,同样也会把它们保存在内存里。当 Servlet 容器关闭时,它会卸载所有的 web 应用和 ServletContext ,所有的 Servlet、Filter 和 Listener 实例都会被销毁。 25 | 26 | 从 java 的文档中可知,ServletContext 定义了一组方法,Servlet 使用这些方法来与它的 Servlet 容器进行通信。例如,用来获取文件的 MIME 类型、转发请求或编写日志文件。在 web 应用的部署文件(deployment describtor)标明“分布式”的情况下,web 应用的每一个虚拟机都拥有一个上下文实例。在这种情况下,不能把 Servlet 上下文当作共享全局信息的变量(因为它的信息已经不具有全局性了)。可以使用外部资源来代替,比如数据库。 27 | 28 | ### ServletRequest 和 ServletResponse 从哪里进入生命周期? 29 | Servlet 容器包含在 web 服务器中,web 服务器监听来自特定端口的 HTTP 请求,这个端口通常是 80 。当客户端发送一个 HTTP 请求时,Servlet 容器会创建新的 HttpServletRequest 和 HttpServletResponse 对象,并且把它们传递给已经创建的 Filter 和 URL 模式与请求 URL 匹配的 Servlet 实例的方法,所有的这些都使用同一个线程。 30 | 31 | request 对象提供了获取 HTTP 请求的所有信息的入口,比如请求头和请求实体。response 对象提供了控制和发送 HTTP 响应的便利方法,比如设置请求头和请求实体。response 对象提供了控制和发送 HTTP 响应的便利方法,比如设置响应头和响应实体(通常是 JSP 生成的 HTML 内容)。当 HTTP 响应被提交并结束后,request 和 response 对象都会被销毁。 32 | 33 | ### 如何管理 Session?cookie 呢? 34 | 当客户端第一次访问 web 应用或第一次使用 request.getSession() 获取 HttpSession 时,Servlet 容器会创建 Session,生成一个 long 类型的唯一 ID (可以使用 session.getId() 获取它)并把它保存在服务器的内存里。Servlet 容器同样会在 HTTP 响应里设置一个 Cookie ,cookie 的名字是 JSESSIONID 并且 cookie 的值是 session 的唯一 ID 。 35 | 36 | 根据 HTTP cookie 规范(正规的 web 浏览器和 web 服务器必须遵守的约定),在 cookie 的有效期间,客户端(浏览器)之后的每个请求都要把该 cookie 返回给服务器,Servlet 容器会利用带有名为 JSESSIONID 的 cookie 检测每一个到来的 HTTP 请求头,并使用 cookie 的值从服务器内容里获取相关的 HttpSession 。 37 | 38 | HttpSession 会一直存活着,除非超过一段时间没使用。可以在 web.xml 文件中设置该时间段,默认时间段是 30 分钟。因此,如果客户端已经超过 30 分钟没有访问 web 应用的话,Servlet 容器就会销毁 Session 。之后的每一个请求,即使带有特定的 cookie ,都再也不会访问到同一个 Session 了,ServletContainer 会创建一个新的 Session 。 39 | 40 | 另外,在客户端的 session cookie 拥有一个默认的存活时间,这个时间与浏览器的运行时间相同,因此,当用户关闭浏览器后(所以的标签或窗口),客户端的 Session 就会被销毁,重新打开浏览器后,与之前的 Session 关联的 cookie 就再也不会被发送出去了。再次使用 request.getSession() 会返回一个全新的 HttpSession 并且使用一个全新的 session ID 来设置 cookie 。 41 | 42 | ### 如何确保线程安全? 43 | 我们现在已经知道了所有的请求都在共享 Servlet 和 Filter 。它是多线程的并且不同的线程(HTTP 请求)可以使用同一个实例。否则,对每一个请求都重新创建一个实体会耗费很多的资源。同样也要知道,不应该使用 Servlet 或者 Filter 的实例变量来存放任何的请求或者会话范围内的数据,这些数据会被其它 Session 的所有请求共享,这是非线程安全的。 -------------------------------------------------------------------------------- /Back-end/后端学习.md: -------------------------------------------------------------------------------- 1 | ## 用户态与核心态 2 | 3 | ### 用户态与核心态是什么? 4 | 将内核程序和基于内核程序之上构建的用户程序分开处理,使其分别运行在用户态和核心态 5 | 6 | ### 为什么需要用户态和核心态? 7 | 在CPU的所有指令中,有一些指令是非常危险的(不是`rm -rf`这种),如果错用,将导致整个系统奔溃,比如:清空内存,修改时钟等。如果所有的程序代码都能够直接使用这些指令,那么很有可能我们的系统一天将会死n次。 8 | 9 | 所以,CPU将指令分为 **特权指令** 和 **非特权指令** ,对于较为危险的指令,只允许操作系统本身及其相关模块进行调用,普通的、用户自行编写的应用程序只能使用那些不会造成危险的指令。intel的CPU将指令级别分为了4个等级,分别是:`RING0`, `RING1`, `RING2`, `RING3`。 10 | 11 | 当一个程序或一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称该程序、该任务处于内核态,此时处理器处于特权级别最高的`RING0`内核代码中执行,当进程处于内核态时,执行的内核代码将会使用该进程的内核栈,每个进程都拥有自己的内核栈。 12 | 13 | 当程序、进程在执行用户自己的代码时,我们就称该程序、该进程处在用户态,此时处理器处在特权级别最低的`RING3`用户代码中运行。 14 | 15 | 当正在执行用户程序而突然被中断程序(被打断了),此时用户程序也可以象征性的称为处于核心态,因为中断处理程序将使用当前进程的内核栈。 16 | 17 | CPU总是处于以下状态中的一种: 18 | * 内核态:运行于进程上下文,内核代表进程运行于内核空间; 19 | * 内核态:运行于中断上下文,内核代表硬件运行于内核空间; 20 | * 用户态:运行于用户空间。 21 | 22 | ### 什么是系统调用? 23 | 处在用户空间的应用程序,通过系统调用,进入内核空间。此时用户空间的进程要传递很多变量、参数给内核,内核态运行的时候也要保存用户进程的一些寄存器值、变量等等。所谓的“进程上下文”,就是用户进程传递给内核的参数以及内核要保存的那一整套变量、寄存器值和当时的环境等。比如`fork()`开启一个新的进程。 24 | 25 | ### 什么是中断程序? 26 | 硬件通过触发信号,导致内核调用中断处理程序,进入内核的空间。在这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“中断上下文”,其实也可以看做就是硬件传递的参数和内核需要保存的一些其它环境信息(被打断执行的进程环境)。 27 | 28 | ### 什么是内核? 29 | 操作系统大致经历了无结构操作系统(第一代)、模块化操作系统(第二代)、分层式操作系统(第三代),它们操作系统被称为“传统操作系统结构”,而单内核和微内核是目前“线代操作系统结构”中最重要的两个。比如Linux是单内核,windows和macOS都是微内核的。 30 | 31 | 操作系统的内核作用是对软件、硬件资源的管理。内核的最重要的一个作用就是实现任务调度,让计算机的资源被均衡的调度。如果一个操作系统没有内核,那么所有的任务(进程)都是完全独占计算机的,聊天的同时不能刷浏览器。 32 | 33 | 没有操作系统的内核,内存的动态管理也不存在了,后果就是可能没有虚拟内存,也就是说,如果此时运行的程序需要占用内存2G,但此时计算机只有1G内存,这个程序就跑不起来了。同时,设备的管理功能也就不存在了,比如动态设备的插拔(U盘)等等,而且计算机启动的时间会将会非常漫长,因为需要检测并加载各种驱动。 34 | 35 | 没有操作系统内核,多线程的操作都不能支持,因为信号量、消息队列这些都是操作系统提供的,所以如果真的把操作系统的内核剔除掉,现在大部分应用程序都要彻底重写来支持无内核的操作系统。并且多核CPU也发挥不了作用。 36 | 37 | 早期的操作系统有些游戏和软件就是直接拿软盘启动,是因为那时操作系统很小、功能弱、系统资源紧缺,没有什么内核也是OK的,但是现在计算机的硬件资源非常丰富,操作系统很庞大,没有内核进行统一管理的话,要么太浪费要么这个应用程序的负担(要处理的事情)会很重。 38 | 39 | ### 什么是虚拟内存? 40 | 以下内容摘自wiki,我没理解好虚拟内存的大概实现思路,先把wiki的结果放在着: 41 | ``` 42 | 虚拟内存是电脑系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如RAM)的使用也更有效率。 43 | 44 | 注意:虚拟内存不只是“用磁盘空间来扩展物理内存”的意思——这只是扩充内存级别以使其包含硬盘驱动器而已。把内存扩展到磁盘只是使用虚拟内存技术的一个结果,它的作用也可以通过覆盖或者把处于不活动状态的程序以及它们的数据全部交换到磁盘上等方式来实现。对虚拟内存的定义是基于对地址空间的重定义的,即把地址空间定义为“连续的虚拟内存地址”,以借此“欺骗”程序,使它们以为自己正在使用一大块的“连续”地址。 45 | 46 | 现代所有用于一般应用的操作系统都对普通的应用程序使用虚拟内存技术,例如文字处理软件,电子制表软件,多媒体播放器等等。老一些的操作系统,如DOS和1980年代的Windows,或者那些1960年代的大型机,一般都没有虚拟内存的功能——但是Atlas,B5000和苹果公司的Lisa都是很值得注意的例外。[1] 47 | 48 | 那些需要快速访问或者反应时间非常一致的嵌入式系统,和其他的具有特殊应用的电脑系统,可能会为了避免让运算结果的可预测性降低,而选择不使用虚拟内存。 49 | ``` 50 | 在Linux中用户进程空间和内核进程控件占用的虚拟内存比例为3:1。32位机虚拟内存最高2^32 = 4 GB,64位机虚拟内存最高2^64 ≈ 16000 PB。 51 | 52 | ### 计算机启动,检测并加载各种驱动 53 | 差一篇讲计算器启动全流程的讲解。 54 | 55 | ### 中间件 56 | 中间件的概念挺容易理解,就是整体来看要把分布式集群之间联系起来,业界一直在发布新的轮子,知乎这篇文章供参考:[https://www.zhihu.com/question/19730582](https://www.zhihu.com/question/19730582) 57 | 58 | ### 并发和并行 59 | 引用:[https://www.zhihu.com/question/33515481](https://www.zhihu.com/question/33515481) 60 | ``` 61 | 你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。 62 | 你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。 63 | 你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。 64 | 65 | 并发的关键是你有处理多个任务的能力,不一定要同时。并行的关键是你有同时处理多个任务的能力。所以我认为它们最关键的点就是:是否是『同时』。 66 | ``` 67 | 68 | * 并发在于「发生」 69 | * 并行在于「运行」 70 | 71 | ### 生产者消费者模式 72 | 找到一篇讲解得比较细致的文章,但是文章本身内容太长,不易于总结,但实际上前后语义又通畅,就不做摘要了,原文链接:[https://www.jianshu.com/p/0d1c950e6614](https://www.jianshu.com/p/0d1c950e6614) 73 | 74 | ### C10K问题 75 | 留给自己以后看,这个问题不是目前自己需要考虑的。[https://blog.csdn.net/yeasy/article/details/43152115](https://blog.csdn.net/yeasy/article/details/43152115) 76 | 77 | ### kill 掉对应端口信息 78 | 以 `8000` 端口为例: 79 | ```shell 80 | lsof -i tcp:8000 81 | ``` 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /Base/C++.md: -------------------------------------------------------------------------------- 1 | ### ends 的差异 2 | ends 在 windows 和类 unix 系统下有差异,[http://www.cplusplus.com/reference/ostream/ends/](http://www.cplusplus.com/reference/ostream/ends/)上说的是加入了一个 '\0' ,而不是空格,之所以是空格是因为操作系统的原因 3 | 4 | * Qt 的信号槽机制是动态插入代码 -------------------------------------------------------------------------------- /Base/algorithm-java.md: -------------------------------------------------------------------------------- 1 | 1. `public static void`和`public void`的区别:`public static void`所标明的静态方法能够用类名直接调用,但是静态方法不能够调用非静态方法。 2 | 3 | 2. final关键字浅析:[https://www.cnblogs.com/dolphin0520/p/3736238.html](https://www.cnblogs.com/dolphin0520/p/3736238.html) 4 | 5 | 3. `const`和`static`关键词: 6 | * [http://blog.sina.com.cn/s/blog_668aae780101m4ex.html](http://blog.sina.com.cn/s/blog_668aae780101m4ex.html) 7 | * [https://www.jianshu.com/p/1598004e8215](https://www.jianshu.com/p/1598004e8215) 8 | 9 | `const` 修饰为只读常量,只能初始化一次,`static` 修饰的变量和函数只能在当前模块或文件中可见。 10 | 11 | 4. 如何才能将一个`double`变量初始化为无穷大?使用java内置常数,`Double.POSITIVE_INFINITY`和`Double.NEGATIVE_INFINITY` 12 | 13 | 5. 能够将`double`类型的值和`int`类型的值相互比较吗?不通过类型转换不行!但是java一般会自动进行所需的类型转换,例如,如果`int x = 3`,则`(x < 3.1)`为`true`,java会在比较前将x转换为`double`类型(因为3.1为`double`类型的字面量) 14 | 15 | 6. java二维数组表示:`int[][] arr = { {1,2,3}, {4,5,6} };` 16 | -------------------------------------------------------------------------------- /Base/leetCode.md: -------------------------------------------------------------------------------- 1 | - [x][两数相加](./leetcode/两数相加.md) 2 | - [x][两数之和](./leetcode/两数之和.md) 3 | - [x][无重复字符的最长子串](./leetcode/无重复字符的最长子串.md) 4 | - [x][两个排序数组的中位数](./leetcode/两个排序数组的中位数.md) 5 | - [ ][最长回文子串](./leetcode/最长回文子串.md) 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Base/leetcode/两个排序数组的中位数.md: -------------------------------------------------------------------------------- 1 | ## 两个排序数组的中位数 2 | 惊呆了,用自己最初的想法居然直接一把 AC 掉了困难题目,真不知道这困难是不是放错了哈哈哈,总之很开心就是了。刚开始想的巨多,一直在纠结怎么把两个有序的数组用一个较好的方法直接合并,然后又考虑到了题目是个有序数组,接着想到了用二分balabala,总之就是题还没开始写,我就已经想得乱七八糟,最后差点被自己吓屎去翻参考答案了,这又给了我一个提醒,做题之前确实是要好好的构思题目怎么来,但是要注意不要想太多,因为其实很多东西都是水到渠成的hhhh 3 | 4 | ```swift 5 | func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { 6 | var finalArray: Array = [] 7 | var i = 0, j = 0 8 | 9 | // 合并两个有序数组 10 | while (i < nums1.count && j < nums2.count) { 11 | if (nums1[i] < nums2[j]) { 12 | finalArray.append(nums1[i]) 13 | i += 1 14 | } else { 15 | finalArray.append(nums2[j]) 16 | j += 1 17 | } 18 | } 19 | 20 | // 添加剩余内容 21 | while true {1` 22 | if i < nums1.count { 23 | finalArray.append(nums1[i]) 24 | i += 1 25 | } 26 | if j < nums2.count { 27 | finalArray.append(nums2[j]) 28 | j += 1 29 | } 30 | if i >= nums1.count && j >= nums2.count { 31 | break 32 | } 33 | } 34 | 35 | // 返回中位数 36 | if finalArray.count % 2 != 0 { 37 | return Double(finalArray[finalArray.count / 2]) 38 | } else { 39 | let v = (finalArray[finalArray.count / 2] + finalArray[finalArray.count / 2 - 1]) 40 | if v % 2 != 0 { 41 | return Double(v / 2) + 0.5 42 | } 43 | return Double(v / 2) 44 | } 45 | } 46 | ``` -------------------------------------------------------------------------------- /Base/leetcode/两数之和.md: -------------------------------------------------------------------------------- 1 | ## TwoSum 2 | 3 | Given an array of integers, return indices of the two numbers such that they add up to a specific target. 4 | 5 | You may assume that each input would have exactly one solution, and you may not use the same element twice. 6 | 7 | ``` 8 | Example: 9 | Given nums = [2, 7, 11, 15], target = 9, 10 | 11 | Because nums[0] + nums[1] = 2 + 7 = 9, 12 | return [0, 1]. 13 | ``` 14 | 15 | ### AC Code 16 | 17 | ```swift 18 | class Solution { 19 | func twoSum(_ nums: [Int], _ target: Int) -> [Int] { 20 | var final: [Int] = [0, 0] 21 | var index: Int = 0 22 | for _ in nums { 23 | var index_i:Int = index+1 24 | for _ in index+1.. [Int] { 58 | var index = 0 59 | var final:[Int] = [0 ,0] 60 | for num in nums { 61 | let tempNum = target - num 62 | let tempNums = nums[index+1.. [Int] { 100 | var final = [Int]() 101 | var dict = [Int: Int]() 102 | for index in 0.. ListNode? { 22 | // 判断是否为空 23 | if l1 == nil && l2 != nil { 24 | return l2 25 | } else if l1 != nil && l2 == nil { 26 | return l1 27 | } else if (l1 == nil && l2 == nil) { 28 | return nil 29 | } else { 30 | var finalNode = ListNode(0) 31 | 32 | var tempNode = l1 33 | var otherNode = l2 34 | var currentNode = finalNode 35 | 36 | while true { 37 | // 判断当前是否为空 38 | if tempNode != nil { 39 | currentNode.val += (tempNode?.val)! 40 | } 41 | if otherNode != nil { 42 | currentNode.val += (otherNode?.val)! 43 | } 44 | 45 | tempNode = tempNode?.next 46 | otherNode = otherNode?.next 47 | 48 | if currentNode.val - 10 >= 0 { 49 | currentNode.val = currentNode.val - 10 50 | currentNode.next = ListNode(1) 51 | currentNode = currentNode.next! 52 | } else { 53 | if tempNode == nil && otherNode == nil { 54 | break 55 | } 56 | currentNode.next = ListNode(0) 57 | currentNode = currentNode.next! 58 | } 59 | } 60 | 61 | return finalNode 62 | } 63 | } 64 | } 65 | ``` -------------------------------------------------------------------------------- /Base/leetcode/无重复字符的最长子串.md: -------------------------------------------------------------------------------- 1 | ## 无重复字符的最长子串 2 | 3 | 啊哈哈,这道题真有趣,刚开始没看懂题意中为什么要指出 "pwke" 是 子序列 而不是子串 这句话,然后自己用 k-v 过了前两个样例后到这个样例才恍然大悟,原来是这么个意思哈哈。 4 | 5 | 6 | 7 | 8 | ### 搞笑的code 9 | ```swift 10 | func lengthOfLongestSubstring(_ s: String) -> Int { 11 | var dict = [Character: Character]() 12 | for c in s { 13 | guard dict[c] != nil else { 14 | dict[c] = c 15 | continue 16 | } 17 | } 18 | print(dict.values) 19 | return dict.keys.count 20 | } 21 | ``` 22 | 23 | 24 | ### 一次超时的代码 25 | ```Swift 26 | class Solution { 27 | func lengthOfLongestSubstring(_ s: String) -> Int { 28 | var dict = [Character: Character]() 29 | var longestSubStringLength = 0 30 | for c in s { 31 | if dict[c] != nil { 32 | if longestSubStringLength < dict.keys.count { 33 | longestSubStringLength = dict.keys.count 34 | } 35 | dict.removeValue(forKey: c) 36 | } 37 | dict[c] = c 38 | } 39 | if longestSubStringLength < dict.keys.count { 40 | longestSubStringLength = dict.keys.count 41 | } 42 | return longestSubStringLength 43 | } 44 | } 45 | ``` 46 | 47 | 48 | ### AC 代码 49 | ```swift 50 | func lengthOfLongestSubstring(_ s: String) -> Int { 51 | var longestSubStringLength = 0 52 | var finalString = "" 53 | var index = 0 54 | for c in s { 55 | if finalString.contains(c) { 56 | longestSubStringLength = max(longestSubStringLength, finalString.count) 57 | let endIndex = finalString.index(of: c) 58 | let stringRange = finalString.startIndex...endIndex! 59 | finalString.removeSubrange(stringRange) 60 | } 61 | finalString.append(c) 62 | index += 1 63 | } 64 | return max(longestSubStringLength, finalString.count) 65 | } 66 | ``` 67 | 68 | 其实挺惭愧的,看了官方题解没看懂哈哈哈,不过官方题解倒是给了三个大的解题方向,直接字符串暴力遍历、滑动窗口、Set 和 HashMap 三种。刚开始我受到了昨天(应该是前天)的结题思路影响,因为这道题的核心是返回“最长不重复子串”的长度,只需要知道个数就行,所以我就想到了直接刚 dictionary ,不过这也就给我后续的挖了一个巨大的坑,知道第二天早上(也就是今天)才解决掉,之前做的时候漏掉了一个问题,dictionary 没法删掉从某一个下标开始之前的所有字符,都是离散的,之前一直绕在这个里边,但是 dictionary 的解法是 O(1) 的,非常诱人。不过最后实在没绕出这个圈,又换了字符串再刚了一次,换了字符串直接暴力思路就非常顺畅了。 69 | 70 | 没错,因为受到了题解给的思路,就直接字符串做了,确实也 AC 了。AC 后我在想字符串按照我之前的经验不管是只要是遍历都是 O(n) 这一趟趟又 index(of:) 又 subRange 的早就 O(n^3) 了吧,岂能不超时?但实际上就是没超时 😑 。查阅了一波资料后才发现,原来 Apple 对 Swift 的 String 居然花了如此大的力气进行打磨,详见[这篇文章](https://github.com/apple/swift/blob/master/docs/StringManifesto.md#string-should-be-a-collection-of-characters-again),总结来说是 Swift 1.0 的时候只是字符的集合,相当于就是HashSet 了,Swift 2.0 后又把它移除掉了,一直到 Swift 4.0 又加了回来,在刚给出的那篇文章中,Apple 的开发团队写了不少为什么要加回来的思考,推荐阅读。 71 | 72 | 知道了 String 是 collection 后还是翻 collection 的文档,没想到不管是 index(of:) 还是 subRange() 等等得这些居然统统都是 O(1) !所以我写出了一个 O(n) 的解法 😑 。这还真是令人惊讶呢!(其实我觉得应该还是 O(n^2)) -------------------------------------------------------------------------------- /Base/leetcode/最长回文子串.md: -------------------------------------------------------------------------------- 1 | ## 最长回文子串 2 | 3 | 刚开始做的时候直接按照了自己的思路去搞,这一弄问题就出来了,因为没有考虑好回文字符串最重要的特点,导致最开始就想错了,大概的思路是这样的,还是一个字符一个字符的从目标字符串中读取,然后以当前读取到的字符出发,再起一个循环往后接着读取,一直读到下一个字符与当前字符相等,然后把从当前字符到下一个相等字符之间的字符串进行翻转,判断翻转前和翻转后是否相等,如果相等就记录下此时字符串和长度,然后接着循环。 4 | 5 | 好吧,其实看到这大家也都知道这种做法是一定会超时的,但是刚开始的时候因为我并不知道要考虑哪些测试样例,题目给的和自己想的一些简单样例都过了,交了一发,没报超时,只是一些边界条件没考虑好,加上这些边界条件后再交一发,好吧,从此一 wa 到底,统统超时。 6 | 7 | 8 | ### 超时代码1 9 | ```Swift 10 | func longestPalindrome(_ s: String) -> String { 11 | var stringindex = 0 12 | var finalString = "" 13 | var finalStringMaxLength = 0 14 | while true { 15 | if stringindex == s.count { 16 | break 17 | } 18 | var tempString = "" 19 | let currentStringStart = s.index(s.startIndex, offsetBy: stringindex) 20 | for c in s[currentStringStart.. tempString.count else { 25 | finalString = tempString 26 | continue 27 | } 28 | } 29 | } 30 | stringindex += 1 31 | } 32 | return finalString 33 | } 34 | ``` 35 | 36 | ### 超时代码2 37 | ```Swift 38 | func longestPalindrome(_ s: String) -> String { 39 | var stringindex = 0 40 | var finalString = "" 41 | var finalStringMaxLength = 0 42 | while true { 43 | if stringindex == s.count { 44 | break 45 | } 46 | var tempString = "" 47 | let currentStringStart = s.index(s.startIndex, offsetBy: stringindex) 48 | for c in s[currentStringStart.. tempString.count else { 55 | finalString = tempString 56 | continue 57 | } 58 | continue 59 | } 60 | if tempString.count < s.count - stringindex { 61 | continue 62 | } 63 | tempString = "" 64 | break 65 | } 66 | } 67 | tempString.append(c) 68 | } 69 | stringindex += 1 70 | } 71 | if finalString == "" { 72 | if s == "" { 73 | return "" 74 | } 75 | return String(s[s.startIndex]) 76 | } 77 | return finalString 78 | } 79 | ``` 80 | 81 | 思考了一下,我的做法就是循环太多,而且循环的次数也很多,赶紧试着调了一下,发现问题还是没解决,但是又不想看答案,接着再纠结了一波,还是超时。翻了参考的思路,才意识到自己的出发点出了,应该要从当前字符两侧同时出发,同时判断左右两个字符,但是一直没写起来。 82 | 83 | 看了道长写的一个答案,看上去是打表做的,但是这思路自己完全看不懂 🙄 ,真是不明白这种题是怎么打表做的hhh,等以后能力够了再去回味一番吧。[repo 在此](https://github.com/soapyigu/LeetCode-Swift/blob/master/DP/LongestPalindromicSubstring.swift) 84 | 85 | 今天下午又在 github 上翻到了一个自己能够看懂的方法,用的就是官方题解的思路,但实际上却是超时代码。😓 ,[repo 在此](https://github.com/lexrus/LeetCode.swift/blob/swift4/Tests/5.swift) 86 | 87 | 超时的样例实在是太好玩了。hhhh 88 | ``` 89 | "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 90 | ``` -------------------------------------------------------------------------------- /Base/python.md: -------------------------------------------------------------------------------- 1 | ## 模块 2 | 每个 `.py` 文件的主文件就是模块名称,想要导入模块时必须使用 `import` 关键词来制定模块名称。若要引用模块中定义的名称,则必须在名称前加上模块名称与一个 “`.`" 符号。 3 | 4 | ## __pycache__ 5 | CPython 将 .py 文件编译后的字节码文件,如果之后再次导入同一个模块,检测到源码文件没有更改过,就不会再对源码重头开始进行语义和语法解析等操作。 6 | 7 | ## 获取命令行参数 8 | 可通过 `sys` 模块中的 `argv` 列表,argv[0] 保存的是源码的文件名: 9 | 10 | ```python 11 | import sys 12 | print('hello', sys.argv[1]) 13 | ``` 14 | 15 | ## 包 16 | 文件夹中一定要有一个 `__init__.py` 文件,该文件夹才会被视为一个软件包,并且软件包名称会成为命名空间的一部分。 17 | 18 | ## python 中所有数据都是对象 19 | 20 | ## python3 之后,整数类型为 `int`,不再区分 `int` 和 `long` 21 | 22 | ## type() 23 | 想知道某个数据的类型可以使用 `type()` 函数: 24 | ```python 25 | >>>type(10) 26 | 27 | ``` 28 | 29 | ## python 支持复数的直接表示法 30 | ```python 31 | >>> a = 3 + 2j 32 | >>> b = 5 + 3j 33 | >>> a + b 34 | (8 + 5j) 35 | ``` 36 | 37 | ## 格式化字符串 38 | ### 旧方式 39 | ```python 40 | >>> 'hello, %s!' % 'world' 41 | ``` 42 | 43 | ### 新方式 44 | ```python 45 | >>> 'hello, {}!'.format('world') 46 | ``` 47 | 48 | ## 字典 49 | 当从字典中通过某个 key 取值时,当 key 不存在,则会报 `KeyError` 的错误,此时可以通过 `in` 来判断: 50 | 51 | ```python 52 | >>> nums = {'aha': 2333} 53 | >>> 'wow' in nums 54 | False 55 | >>> nums['wow'] 56 | Traceback (most recent call last): 57 | File "", line 1, in 58 | KeyError: 'wow' 59 | ``` 60 | 61 | ## 需要处理小数且还需要精确的结果 62 | `import decimal`,其它细节查资料 63 | 64 | ## 指数运算 65 | ```python 66 | >>> 2 ** 10 67 | 1024 68 | ``` 69 | 70 | ## 比较与赋值 71 | `== != < >` 等符号用来比较值,`is, is not` 用来比较两个对象的引用是否相等 72 | 73 | ## * 与 ** 74 | ### `*` 75 | 如果事先无法预期要传入的自变量个数,可以在定义函数的参数时使用 `*`,表示该参数接受不定长度的自变量: 76 | 77 | ```python 78 | def sum(*numbers): 79 | total = 0 80 | for number in numbers: 81 | total += number 82 | return total 83 | ``` 84 | 85 | ### `**` 86 | 让指定的关键词自变量收集为一个字典: 87 | 88 | ```python 89 | def ahaha(**user_settings): 90 | methon = user_settings.get('methon', 'GET') 91 | contents = user_settings.get('contents', '') 92 | ``` -------------------------------------------------------------------------------- /Blockchain/basic.md: -------------------------------------------------------------------------------- 1 | ## 区块链技术综述 2 | 3 | 1. 区块链是从比特币中脱离出来的。 4 | 2. 加密货币 5 | 3. 分布式共识 6 | * 想要生成一个加密货币,还要所有人去承认它 7 | 4. ecash 盲签名技术 8 | 5. hashcash 解决邮件系统中 DoS 攻击问题 9 | * 提出使用「工作量证明」(POW Proof of Work)机制来获取额度 10 | 6. B-money 引入数字货币生成过程。 11 | 7. 比特币 12 | * 加密基础理论发展:RSA 算法 & 公钥私钥加密体系 PPKC 13 | * P2P 技术开发成熟 14 | * hash 现金解决双重支付问题(痛点) 15 | 8. 量子计算机对 RSA 有破坏性 16 | 9. 分布式数据库存储 17 | * 没有中心系统 18 | 10. 如何保证每个节点的数据一致性问题? 19 | * 如果有中心系统的话,只需要保证中心系统这一个节点的数据一致性就好了。 20 | * 为什么要引入分布式? 21 | * 高可用、稳定性问题 22 | * 一致性 hash 23 | * 冗余存储 24 | * 强一致性、弱一致性、最终一致性。根据业务特征去选择 25 | * FLP 不可能性原理 26 | * 在一个分布式系统中不可能在同一个时刻保证数据一致性(强一致性 27 | * 通过「共识算法」解决 28 | * 拜占庭问题。打不打这个仗,需要五个将军来投票,超过 1/2 就打,而不是让一个将军自己去决定,防止被策反。 29 | * 通过 POW 算法进行优化 30 | * POW:工作量证明,通过计算来猜测一个数值,得以解决规定的 hash 问题。保证在一段时间内,系统中只能出现少数合法提案。 31 | 11. hash 算法 32 | 12. 加解密算法 33 | * 解决我发给你的消息,只有你才能知道 34 | 13. 数字签名 35 | * 解决大家都知道这个消息是我发的 36 | 14. 密钥、地址和钱包 37 | * 密钥 => 私钥,不需要在网络上进行传播 38 | * LevelDB 39 | * 钱包不存钱,钱包存的是交易记录,谁给你转了钱,你给谁转了钱 40 | * 基于椭圆曲线的公钥、私钥 41 | * 私钥丢了就是丢了!!!没人知道这个私钥是你的私钥 42 | 15. 交易 43 | * 创建一个交易 44 | * 在网络上广播这个交易 45 | * 比特币找零:别人给我输入了 15 个比特币,我给别人输出 13 个比特币,还剩 2 个比特币再输入给自己。产生三笔交易 46 | * 交易的确认 47 | * 确认 A 是 A,通过 A 的签名 48 | * 49 | 16. 挖矿 50 | * 把交易写入区块链,就是挖矿 51 | * 交易不产生比特币,挖矿产生比特币 52 | * 挖矿的过程中,回去监听比特币网络,正在挖 78 这个块时监听到其它矿工已经挖完了 78 这个块,自己必须要立马放弃,因为要让自己利益最大化,去挖 79 这个块。 53 | * 博弈论。 54 | 17. 贪心算法 55 | 18. 哈希二叉树。用作快速归纳和椒盐大规模数据完整性的数据结构,包含加密哈希值。 56 | 19. 图灵不完备系统 57 | 20. 智能合约 58 | -------------------------------------------------------------------------------- /Books/iOS面试之道.md: -------------------------------------------------------------------------------- 1 | ## 第一天 2 | 3 | ### 字典和集合 4 | 一般的字典和集合都要求它们的 Key 都必须实现 Hashable 协议,Cocoa中的基本数据类型都满足这一点。 5 | 6 | ### 字符串 7 | Swift 中的字符串为值类型,而不是 OC 中的引用类型。 8 | 9 | #### 判断字符串是否由数字构成 10 | ```Swift 11 | var str1 = "123ws" 12 | // nil 13 | Int(str1) 14 | 15 | var str2 = "123" 16 | // not nil 17 | Int(str2) 18 | ``` 19 | 20 | ### Swift 的访问修饰符 21 | `private`: 当前类内使用 22 | `fileprivate`:当前文件内使用 23 | `internal`:(默认访问级别)整个 module 里使用 24 | `public`:可被任何地方使用,但除了 ·mudule 外不可以被继承和 override 25 | `open`:可被任何地方使用 26 | 27 | ### 如何检测一个链表中是否有环? 28 | 用 **快行指针** 的做法,一个指针在前,一个在后,两个指针的间隔一般为 2 ,循环终止条件为链表尾,如果有快指针和慢指针走到一起了,则该链表成环。 29 | 30 | ### 栈和队列的转化 31 | 用栈实现队列(腾讯一面): 32 | 先写一个转换函数,把栈 A 的元素都 pop 到 栈 B 中,进队相当于给栈 A push ,出队之前先执行转换函数,然后再 pop 栈 B 元素。 33 | 34 | 用队列实现栈(腾讯一面): 35 | 先写一个转换函数,这个函数把队列 A 中的除了队尾元素外的所有元素都入队到队列 B 中,那么经过这个转换函数转换之后队列 A 中剩下的就是栈顶元素。 36 | 37 | 再写一个函数,把队列 B 和队列 A 进行对调,此时因为队列 A 已经全部出队,所以队列 B 为空,队列 A 为少了之前的队尾元素队列 38 | 39 | 40 | --- 41 | 42 | ## 第二天 43 | ### 二叉树的遍历 44 | 因为二叉树本身是由递归定义的,从原理上讲,所有二叉树的题目都可以用递归来解。二叉树的遍历主要由 `BFS` (前中后序遍历)和 `DFS` (层级遍历)两种组成,需要注意的是,广度优先遍历需要用队列进行搭配 45 | 46 | ### 排序算法 47 | 动画和代码展示:[https://www.cnblogs.com/onepixel/articles/7674659.html](https://www.cnblogs.com/onepixel/articles/7674659.html) 48 | 49 | 50 | ## 第三天 51 | ### 几乎都是算法 52 | 比如 排序、动态规划、二分查找等等。慢慢总结吧 53 | 54 | --- 55 | 56 | ## 第四天 57 | ### inout 关键字 58 | 使用 `inout` 关键字可以修改传入参数的原始值,调用的时候需要在对应的参数前加上符号 `&` ,类似 `C/C++` 中的指针。 59 | 60 | 61 | ### protocol 62 | 在转 `Swift` 将近三四个月的过程中,我居然一点都没有感到在写 `protocol` 时代理对象居然不加 `weak` 关键字感到奇怪。 63 | 64 | 举个例子,之前我是这么粗暴的写 `protocol` : 65 | ```Swift 66 | protocol PjhubsDelegate { 67 | func pjhubsDeleagteFunction() 68 | } 69 | 70 | class Pjhubs: UIView { 71 | var viewDelegate: PjhubsDelegate? 72 | } 73 | ``` 74 | 75 | 就这么写了三四个月,看书看着看着才猛的发现,为啥我要把 `weak` 去掉,遂改成了以下代码: 76 | 77 | ```swift 78 | weak var viewDelegate: PjhubsDelegate? 79 | ``` 80 | 81 | 此时,`Xcode` 给我报了个错, 82 | 83 | `'weak' must not be applied to non-class-bound 'PjhubsDelegate'; consider adding a protocol conformance that has a class bound` 84 | 85 | 也就是说:`weak` 只能能添加到非类绑定的 `PjhubsDelegate` 上,考虑给其添加上一个类绑定。根据提示,代码修改为: 86 | 87 | ```Swift 88 | protocol PjhubsDelegate: class { 89 | func pjhubsDeleagteFunction() 90 | } 91 | 92 | class Pjhubs: UIView { 93 | weak var viewDelegate: PjhubsDelegate? 94 | } 95 | ``` 96 | 97 | 总的来说, `weak` 修饰引用类型,而上文中我所定义的 `protocol` 为值类型,所以 `Xcode` 报了错。如果不加 `weak` 修饰,则表明我们的 `protocol` 可为枚举、结构体所使用,所以当我们使用 `weak` 修饰了代理对象,那么就要求代理(协议)为 `class-only` (只类使用) 98 | 99 | 100 | ### copy-on-write 101 | 值类型在复制时,新对象和原对象实际上在内存中指向同一块区域,只有当新对象发生改变时(增加或删除一个对象),才会给新对象开辟新内存区域。 102 | 103 | 104 | ### 属性观察 105 | 最开始的时候,我直接在 `Swift` 中拿了 `OC` 的思想做了 `setter & getter` ,但是当我想只要 `setter` 时,一定要把 `getter` 写上,就算 `getter` 什么也不做,只是返回一个存储属性的值而已。 106 | 107 | 后边理解到了 `Swift` 中的属性观察,即 `willSet & didSet` ,意思就是方法名所代表的意思。需要注意的是,在初始化器中对属性的设定,以及在 `willSet & didSet` 方法中对属性的再次设定,都会出发调用属性观察。 108 | 109 | 110 | ### @autoclosure 111 | [http://swifter.tips/autoclosure/](http://swifter.tips/autoclosure/) 112 | 113 | --- 114 | 115 | ## 第五天 116 | ### 柯里化(Curring) 117 | [http://swifter.tips/currying/](http://swifter.tips/currying/)。说实话,书中和喵神的这篇 blog 描述的代码都很简单,主要是这种神奇的写法根本没见过,书中的例子是这样的,要求写一个函数满足只传入一个整数参数,返回该整数 +2 的值,这很简单对吧,但是实际的要求是只写这么一个函数,然后满足 +2、+3、+4 等,其实我内心直接就冒出多态、模版、范型啦这些东西,但仔细一想,不对啊,只能有一个参数,瞬间缓过神来,柯里化牛逼啊。😂。 118 | ```Swift 119 | func add(_ num: Int) -> (Int) -> Int { 120 | return { val in 121 | return num + val 122 | } 123 | } 124 | 125 | let number2 = add(2) 126 | print(number2(2)) 127 | ``` 128 | 129 | ### 实现一个函数:求 0 ~ 100 (包括 0 和 100)中为偶数并且恰好是其他数字平方的数字 130 | 131 | ```Swift 132 | (0...100).map { $0 * $0 }.filter { $0 % 2 == 0 } 133 | ``` 134 | 135 | Swift 函数式编程的一些资料:[https://www.jianshu.com/p/7233f140e6c3](https://www.jianshu.com/p/7233f140e6c3) 136 | 137 | 138 | ### ARC 139 | ARC 和 Garbage Collection 的区别在于:Garbage Collection 在运行时管理内存,可以解决 retain cycle, 而 ARC 在编译时管理内存 140 | 141 | 142 | ### @property 关键字 143 | 在 OC 中基本数据类型的默认关键字是 `atomic`、`readwrite` 和 `assign`,普通属性的默认关键字为 `atomic`,`readwrite` 和 `strong` 144 | 145 | 146 | ### 关键字 automic 和 nonatomic 147 | * automic : 修饰的对象保证 setter 和 getter 的完整性,任何线程访问它都可以的哦大一个完整的初始化对象。正是因为要保证操作的完整性,所以速度较慢。automic 比 nonatomic 安全,但也不是绝对的线程安全,当多个线程同时调用 set 和 get 时,会导致获得的对象值不一样。想要获得线程绝对安全,使用 @synchronized (个人觉得 @synchronized 的做法也不好,这是 iOS 中最垃圾的锁哈哈) 148 | * nonatomic : 修饰的对象不保证 set 和 get 的完整性,所以当多个线程访问它时可能会返回未初始化的对象,故其速度会比 atomic 快,但线程也不是安全的。 149 | 150 | 151 | ### runloop 和 线程的关系 152 | runloop 是每一个线程一直运行的一个对象,它主要用来负责响应需要处理的各种事件和消息。每一个线程都有且仅有一个 runloop 与之对应,没有线程,就没有 runloop 。在所有线程中,只有主线程的 runloop 是默认启动的,main 函数会设置一个 NSRunLoop 对象,而其它线程的 runLoop 默认是没有启动的,可以通过 `[NSRunLoop currentRunLoop]` 启动。 153 | 154 | 155 | ### code show 156 | ```objc 157 | NSString *firstStr = @"helloworld"; 158 | NSString *secondStr = @"helloworld"; 159 | 160 | if (firstString == secondStr) { 161 | NSLog(@"Equal"); 162 | } else { 163 | NSLong(@"Not Equal"); 164 | } 165 | ``` 166 | 167 | 最终将打印出 "Equal",`==` 该符号是判断着两个指针是否指向同一个对象。上段代码尽管指向不同对象,但它们的值相同,iOS 编译器优化了内存分配,当两个指针指向两个值一样的 `NSString` 时,两者指向同一个内存地址。 168 | 169 | 170 | 171 | ## 后续内容已分门别类进行了归档。 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /CV/basic.md: -------------------------------------------------------------------------------- 1 | # 图形学 & 视觉 2 | 3 | ## 基础概念 4 | 5 | ### OpenGL 6 | OpenGL 本身不提供源码实现,其只是定义了一堆协议接口,各个平台自行根据统一规范好的协议,去实现各自平台上 OpenGL 协议接口,几乎没有不支持 OpenGL 协议的硬件平台。 7 | 8 | ## 微软的 Direct3D 9 | 一开始各家系统厂商都提供了 OpenGL 的实现,微软也实现了一份,但在当时的时代北京下,PC 无法良好的运行 OpenGL 相关的能力,单是跑起来事例程序就已经很慢了。再加上当时微软看上了 video game 的市场,想要做 3D 相关的事情,顺带收购了一家做 3D 渲染框架的公司,其中 Direct3D 就是这套框架的 API 集合。 10 | 11 | 在同时支持 OpenGL 时微软也在持续完善 D3D 的能力,使其成为 win 平台上的最佳图形 API,最终 OpenGL 的版本更新停滞在了 1.1,后续在 win 平台上都是通过 D3D 来完成图形操作。 12 | 13 | ## 一些小 case 14 | 15 | ### 如何去除视频封面的黑边? 16 | * 逐行检测去黑边,设置黑边的阈值为 <10 都是黑边 17 | * 如果遇到有水印的视频,做「腐蚀」 18 | 19 | ### 反转视频检测 20 | * 通过「人脸检测」去做这个事情; 21 | * 设原视频的人脸检测数据为 `face`,旋转 90 度之后视频的人脸检测为数据为 `face_r`; 22 | * 如果 `face` > `face_r` 说明原视频是反转的。 23 | 24 | 注意前提:人脸检测不经过调整的情况下只能检测正常角度。 25 | 26 | -------------------------------------------------------------------------------- /Flutter/Dart.md: -------------------------------------------------------------------------------- 1 | # Dart 2 | ## 语言 3 | ### 私有变量 4 | 变量以下划线(_)开头,在 `Dart` 语言中使用下划线前缀标识符,会强制其变成私有的。 5 | 6 | ### null 7 | dart 中任何类型变量都可以判 `null`。 -------------------------------------------------------------------------------- /Flutter/Flutter问题汇总.md: -------------------------------------------------------------------------------- 1 | # Flutter 问题汇总 2 | ## 环境配置 3 | 根据[ `flutter` 中文官网](https://flutterchina.club)上所引导的步骤进行配置,中途可以根据 `flutter doctor` 命令进行检查相关依赖是否配置完成。 4 | 5 | ### 设备 6 | * iOS: iPhone 7, iOS 12.1.2 7 | * Android: meizu 15, Andriod 7.1.1 8 | 9 | ### 遇到的问题 10 | * 在环境配置中,官方推荐使用 `Andriod Studio` 进行开发,因为体验是最好的,当然同时也支持 `VS Code` 和 `IntelliJ`。因为开发机“常年”连接公司内网,导致无法在 `Andriod Studio` 中下载 `Dart` 和 `Flutter` 插件,尝试好几次,网上的资料都翻遍了,突然灵光一闪!我特么这是在内网啊!切回外网后,一切顺畅...... 11 | 12 | ## 初体验 13 | Flutter 官方上说的优势之一为“热重载”,新建 flutter 测试项目分别运行在 iOS 和 Andriod 两台测试设备上,iOS 的热重载只要每次 `cmd + s` 即可,但 Andriod 需要执行两次,看第一次打印出来的信息提示已经完成 `hot reload`,但设备上什么都没出现,必须执行第二次 `cmd + s` 操作后,才能看到真正的 `hot reload` 的效果。 14 | 15 | ![左:iPhone 7,右:meizu 15](https://i.loli.net/2019/01/10/5c36f04c618e7.jpg) 16 | 17 | flutter 官网上对于“热重载”是这么描述的: 18 | 19 | > 通过将更新后的源代码文件注入正在运行的 `Dart` 虚拟机(VM)中来实现热重载。在虚拟机使用新的的字段和函数更新类后,`Flutter` 框架会自动重新构建 `widget` 树,以便您快速查看更改的效果。 20 | 21 | 所以对于在 meizu 15 上需要执行两次保存操作才能触发“热重载”后的效果展示,我的推测是,在第一次执行保存操作时要么没有把新更新后的代码注入进 `Dart` 虚拟机中,要么就是注入了但未触发重新自动构建 `widget` 树。 22 | 23 | ### 渲染 24 | ![Flutter 在 iOS 上的视图层级](https://i.loli.net/2019/01/10/5c37187ca736f.png) 25 | 26 | ### 差异点 27 | * 入口的 Main 函数入口使用了 `=>` 语法糖,官方说是“这是 `Dart` 中单行函数或方法的简写”: 28 | 29 | ```Dart 30 | void main() => runApp(new MyApp()); 31 | 32 | // 我的推测:上下两者相等,论简洁性,确实是好看一丢丢 33 | void main() { runApp(new MyApp()) } 34 | ``` 35 | 36 | * 每一个 `Widget` 都会有一个 `build()` 方法,用于描述如何根据其他较低级别的 `widget` 来显示自己。我的理解就是 `initView` 方法; 37 | 38 | * 在 `Dart` 中“万物”(包括布局)都是 `Widget`,这点就类似与 `Objective-C` 中的“万物”都是 `NSObject`; 39 | * `Scaffold Widget` 是 `Material library` 中的一个 `Widget`,提供了 `Material` 风格的基本组件。 40 | * Flutter 中并没有类似 iOS 中的 `UITableViewCell`,直接在 `ListView Widget` 中构建了 `cell`,正是因为没有 `cell` 的概念,所以原本每个 `cell` 之间的“分割线”也需要手动使用 `Divider Widget` 进行索引模拟。推荐一篇关于 `Scaffold Widget` 的[内容介绍](http://flutter.link/2018/03/20/Scaffold/) 41 | 42 | * Flutter 的 `Widget` 分为 `StatefulWidget(有状态)` 和 `StatelessWidget(无状态)` 两种,这跟在 iOS 中只要是继承了 `UIResponder` 就具备与用户产生交互进行状态的改变不一样。在 flutter 中如果我们需要实现设计要这个组件是否需要有状态的改变。 43 | 44 | ### 一些简单操作 45 | #### 当打开一个工程时 46 | `flutter packages get` 来下载工程中所依赖的库。 47 | 48 | #### 格式化代码 49 | `Dart` 疯狂嵌套的代码风格已经被吐槽烂了,好在可以在写完代码后,利用 `Android Studio` 中提供的 `Dart` 格式化代码工具:选择任何一个 `Dart` 代码文件,右键选择“Reformat Code with dartfmt”,代码格式立马变得好看了许多。 50 | 51 | ### 总结 52 | 经过这次对 Flutter 的初体验,对其惊叹的地方有: 53 | * 真的做到了一套代码可以“无脑”运行在 iOS 和 Android 两个平台上,使用 `Andriod Studio` 编写完主体代码后,完全不需要做任何平台差异化设置,直接选择不同平台设备直接运行即可,在加上真的脱离了 `JS Core` 的“热重载”技术,在 iOS 上的开发体验非常流畅和方便! 54 | * 在 iOS 上真的抛弃了 `UIKit` 的所有内容,全都基于 `Skia` 自己渲染,这点跟 `Texture` 在 UI 渲染上有异曲同工之处。 55 | * `Dart` 这门语言本身有着与 `JSX` 类似的代码风格痕迹,尤其是对 `Widget` 做属性的定义时,但从整体上来看因为前身是准备要替代 `JS`,所以在很多地方也有 `JS` 痕迹,在一些细节上又透露着 `Java` 的微小细节,所以从语言本身的上手难度不算大,并没有在语法层面上做出太多的革新。 56 | * 强烈推荐使用 `Android Studio` 进行开发!!! 57 | * 创建 Flutter 工程下的 iOS 平台工程居然主体基于 `Swift`,这点让我十分意外! 58 | 59 | 目前来看不满意的地方只有一个: 60 | * 在 iOS 上的长列表滑动卡顿十分严重!!!在快速滑动下,估计只有两三帧,而且每一个 `ListTitle Widget` 上只放了一个 `Text Widget` 啊!太辣眼睛了......[视频在此](https://www.bilibili.com/video/av40402669/) 61 | 62 | 63 | ## 二探 Flutter 64 | ### 一些细节 65 | * `MaterialApp` 下的 `title` 属性代表的是在 Android 任务管理器中的名称(iOS 下只看 app name),`home` 属性下的 `appBar` 中所返回的 `AppBar` 中 `title` 属性才是定义 app 当前页面的标题; 66 | 67 | ### http 68 | 想要在 `Flutter` 中使用 `http` 请求,需要先在 `pubspec.yaml` 文件中加入对应依赖: 69 | ```yaml 70 | dependencies: 71 | # ... 72 | http: ^0.12.0+1 73 | ``` 74 | 75 | 随后可在对应 `dart` 文件中进行引入: 76 | ```dart 77 | import 'package:http/http.dart' as http; 78 | ``` 79 | 80 | ## HTTP 相关 81 | ### 刷新数据 82 | 因为 Flutter 对数据和视图已经进行了绑定,如果想要在网络请求完成后刷新视图所绑定的数据源,需要使用 `setState` 方法进行数据源状态的刷新。当然,使用 `setState` 方法的前提得是我们的 `Widget` 得是一个 `StatefulWidget` ,具备“状态改变的能力”。 83 | 84 | ### 异步加载后获取数据 85 | 通过 flutter 的自带 HTTP 请求库开启异步获取数据后,要求把数据为 `Future` 类型格式,以便在组件中进行“懒加载”,对于 `Future` 类型数据的解析可以采用如下方法(): 86 | ```Dart 87 | class MovieAPI { 88 | Future getMovieList(int start) async { 89 | var client = HttpClient(); 90 | var request = await client.getUrl(Uri.parse( 91 | 'https://api.douban.com/v2/movie/top250?start=$start&count=100')); 92 | var response = await request.close(); 93 | var responseBody = await response.transform(utf8.decoder).join(); 94 | Map data = json.decode(responseBody); 95 | return Movies.fromJSON(data); 96 | } 97 | } 98 | 99 | // 上拉加载 100 | _requestMoreData(int page) { 101 | MovieAPI().getMovieList(page).then((moviesData) { 102 | setState(() { 103 | movies = moviesData.movies; 104 | }); 105 | }); 106 | } 107 | ``` 108 | 109 | ### 点击事件 110 | 在 iOS 和 Android 中所有的 `View` 都可以添加点击或其它多手势事件,但在 Flutter 中除了少数几个自带 `onPress` 或 `onTap` 事件的 `Widget` ,剩下绝大部分 `Widget` 都不带事件,需要我们自己使用 `GestureDetector Widget` 作为父组件进行包裹。 111 | 112 | ```Dart 113 | return GestureDetector( 114 | onTap: () { 115 | // 写下单机后触发的内容,当然还有双击、长按等事件 116 | }, 117 | child: yourWidget, 118 | ); 119 | ``` 120 | 121 | ### Flutter Widget Inspector 122 | 123 | ### 关于 `RaisedButton` 问题 124 | ```Dart 125 | new RaisedButton( 126 | onPressed: null, 127 | color: Colors.white, 128 | child: new Text('B'), 129 | textColor: Colors.black, 130 | ) 131 | ``` 132 | 133 | 如果不对 `onPressed` 设置处理事件,则对 `RaisedButton` 设置的所有修饰都不生效。 134 | -------------------------------------------------------------------------------- /Front-end/CSS.md: -------------------------------------------------------------------------------- 1 | # CSS 2 | ## 基本 3 | ### `