diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..4e7ebbd Binary files /dev/null and b/.DS_Store differ diff --git a/.gitattributes b/.gitattributes index 5e442c2..0cab8a6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,2 @@ - *.js linguist-language=java - *.css linguist-language=java - *.html linguist-language=java - *.md linguist-language=java - +*.md text=auto diff --git a/.github/workflows/check_dead_links.yml b/.github/workflows/check_dead_links.yml new file mode 100644 index 0000000..e30b929 --- /dev/null +++ b/.github/workflows/check_dead_links.yml @@ -0,0 +1,21 @@ +name: Check Markdown links + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +jobs: + test-and-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + persist-credentials: false + fetch-depth: 0 + + - uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' \ No newline at end of file diff --git a/.github/workflows/restructure_files.yml b/.github/workflows/restructure_files.yml new file mode 100644 index 0000000..d0b6311 --- /dev/null +++ b/.github/workflows/restructure_files.yml @@ -0,0 +1,33 @@ +name: Restructure files + +on: + push: + branches: [ main ] + workflow_dispatch: + +jobs: + test-and-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Install Prettier + run: npm install --save-dev --save-exact prettier + + - name: Restructure files + run: node_modules/.bin/prettier --write README.md animation-simulation/ + + - name: Commit files + run: | + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git diff-index --quiet HEAD -- || git commit -am "代码重构 【Github Actions】" + + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ github.ref }} diff --git a/README.md b/README.md index c3e235a..241720d 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,34 @@ # **algorithm-base** -
 @算法基地     -  @袁厨的算法小屋 + +
 @程序厨     +  @程序厨        @算法基地
-### **❤️致各位题友的一封信(使用仓库前必读)** - -大家刚开始刷题时,会有不知道该从何刷起,也看不懂别人题解的情况 - -不要着急,这是正常的。 - -当你刷题一定数量之后,你就会有自己的刷题思维。 - -知道这个题目属于何种类型,使用什么解题方法。 - -刷题速度也会大幅提升。 - -我现在想做的就是尽量把一些基础但很经典的问题细化,理清逻辑。 - -为后面的师弟师妹提供一丢丢帮助。 - -毕竟刚开始刷题时,不知道从哪开始和看不懂题解,是很打击自信心的, - -我就想着帮助大家尽快度过这段时期,让刷题初期的你对刷题没有那么排斥 - -所以基地里的题解都尽量用动画模拟,加深大家对题目的理解。往下看吧 +### **❤️ 致各位题友的一封信(使用仓库前必读)** -另外因为一个人的精力有限,所以基地目前只有 JAVA 代码,欢迎大家贡献其他版本代码。 +推荐在线阅读,更稳定[www.chengxuchu.com](https://www.chengxuchu.com) -贡献仓库注意事项 +![](https://files.mdnice.com/user/8139/e26facfd-4009-4bed-9009-8f2062b81bfd.png) -- 提交的代码必须符合编码规范 -- 必须经过测试,可以在刷题网站上面 AC -- 符合动画思想 -- 可以对代码进行简写,难懂的地方注意添加注释,因为我们的基地主要是为刚刷题的同学服务,所以就尽量让大家容易理解一些。 +![](https://files.mdnice.com/user/8139/da380ce8-d912-417d-ac4b-7cfbcd909105.png) -如果想要贡献代码的大佬可以添加我的微信 **[chefyuan105](https://cdn.jsdelivr.net/gh/tan45du/test@master/美化.1kdnk85ce5c0.png)** 备注贡献仓库即可。 +如果想要贡献代码的大佬可以添加我的微信 **[iamchuzi](https://cdn.jsdelivr.net/gh/tan45du/test@master/美化.1kdnk85ce5c0.png)** 备注贡献仓库即可。 在这里先替所有使用仓库的同学,谢谢各位贡献者啦。 如果老哥觉得仓库很用心的话,麻烦大佬帮忙点个 star ,这也是我们一直更新下去的动力。 -感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助, +感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助. -> 另外我和几位老哥,给刚开始刷题,但是不知道从哪里开始刷的同学,整理了一份 【刷题大纲 】可以先按这个顺序刷,刷完之后应该就能入门,当然该仓库的大部分题解也是来自那个大纲。 -> -> 需要的同学可以扫描下方二维码回复【刷题大纲】获取 - -我把我之前学习算法时,**对我帮助很大的算法书籍,谷歌大神的刷题笔记,面经等整理在了云盘**,需要进阶的同学,可以自己下载,比较适合有一定基础的同学。 - -> [**下载地址**](https://wwr.lanzoui.com/iSGhjox0yne) - -想要手机阅读的大佬,可以来我的[公众号:袁厨的算法小屋](https://cdn.jsdelivr.net/gh/tan45du/test@master/微信图片_20210320152235.wp1ysdbibsw.png)进行阅读,两个平台同步更新,另外想要和题友们一起刷题**的同学可以来我的小屋,**点击**刷题小队**进入,另外群里老哥还会不定期发布内推消息,面经等,需要的可以进一下,不过来的时候**记得备注**,希望这个群能对你们有一丢丢帮助吧,一起加油。 +如果你需要加入**刷题/秋招小队**的话,可以扫描下方二维码,点击与我联系/交流小队,该小队永不收费,也不会有人发广告,仅仅用作交流,但是希望大家进入时,可以备注自身情况,并做一个简短的自我介绍。
+## 另外如果你需要 C++ 项目的话,可以看下这些项目介绍 [www.chengxuchu.com/cppcamp.html](https://www.chengxuchu.com/cppcamp.html) - ------- - - - -### 📢数据结构(前置知识) +### 📢 数据结构(前置知识) - [【动画模拟】哈希表详解,万字长文](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/Hash%E8%A1%A8%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B.md) - [【动画模拟】栈和队列详解](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%85%B3%E4%BA%8E%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B.md) @@ -70,13 +36,13 @@ - [【绘图描述】递归详解](https://mp.weixin.qq.com/s/A4xG9IbQUjFwQoy9YcneCw) - [【动画模拟】树](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E5%9F%BA%E7%A1%80.md) -### 🔋字符串匹配算法 +### 🔋 字符串匹配算法 - [【动画模拟】字符串匹配 BF 算法](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/BF%E7%AE%97%E6%B3%95.md) - [【动画模拟】字符串匹配 BM 算法](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/BM.md) - [【动画模拟】字符串匹配 KMP 算法](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/KMP.md) -### 🧮排序算法 +### 🧮 排序算法 - [【动画模拟】冒泡排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F.md) - [【动画模拟】简单选择排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E7%AE%80%E5%8D%95%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F.md) @@ -87,16 +53,16 @@ - [【动画模拟】堆排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%A0%86%E6%8E%92%E5%BA%8F.md) - [【动画模拟】计数排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E8%AE%A1%E6%95%B0%E6%8E%92%E5%BA%8F.md) -### 🍺二叉树 +### 🍺 二叉树 -- [【动画模拟】前序遍历(迭代)](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%89%8D%E5%BA%8F%E9%81%8D%E5%8E%86(%E6%A0%88).md) -- [【动画模拟】前序遍历(Morris)](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%89%8D%E5%BA%8F%E9%81%8D%E5%8E%86(Morris).md) +- [【动画模拟】前序遍历(迭代)]() +- [【动画模拟】前序遍历(Morris)]() - [【动画模拟】中序遍历(迭代)](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%EF%BC%88%E8%BF%AD%E4%BB%A3%EF%BC%89.md) - [【动画模拟】中序遍历(Morris)](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%EF%BC%88Morris%EF%BC%89.md) -- [【动画模拟】后序遍历(迭代)](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%90%8E%E7%BB%AD%E9%81%8D%E5%8E%86%20(%E8%BF%AD%E4%BB%A3).md) +- [【动画模拟】后序遍历(迭代)]() - [【动画模拟】后序遍历(Morris)](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%90%8E%E7%BB%AD%E9%81%8D%E5%8E%86%EF%BC%88Morris%EF%BC%89.md) -### 🍗排序算法秒杀题目 +### 🍗 排序算法秒杀题目 - [【动画模拟】荷兰国旗](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E8%8D%B7%E5%85%B0%E5%9B%BD%E6%97%97.md) - [【反证解决】数组合成最小的数,最大数](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%90%88%E6%88%90.md) @@ -104,59 +70,62 @@ - [【动画模拟】翻转对问题](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E7%BF%BB%E8%BD%AC%E5%AF%B9.md) - [【动画模拟】链表插入排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode147%E5%AF%B9%E9%93%BE%E8%A1%A8%E8%BF%9B%E8%A1%8C%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F.md) -### 🍖数组篇 +### 🍖 数组篇 - [【动画模拟】leetcode 1 两数之和](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode1%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.md) - [【动画模拟】leetcode 27 移除元素](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode27%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.md) - [【动画模拟】leetcode 41 缺失的第一个正数](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode41%E7%BC%BA%E5%A4%B1%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%AD%A3%E6%95%B0.md) - [【动画模拟】leetcode 485 最大连续 1 的个数](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode485%E6%9C%80%E5%A4%A7%E8%BF%9E%E7%BB%AD1%E7%9A%84%E4%B8%AA%E6%95%B0.md) - [【绘图描述】leetcode 1052 爱生气的书店老板](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode1052%E7%88%B1%E7%94%9F%E6%B0%94%E7%9A%84%E4%B9%A6%E5%BA%97%E8%80%81%E6%9D%BF.md) -- [【动画模拟】剑指offer 3 数组中重复的数字](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/%E5%89%91%E6%8C%87offer3%E6%95%B0%E7%BB%84%E4%B8%AD%E9%87%8D%E5%A4%8D%E7%9A%84%E6%95%B0.md) -- [【动画模拟】leetcode 219 数组中重复元素2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode219%E6%95%B0%E7%BB%84%E4%B8%AD%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A02.md) -- [【动画模拟】leetcode 560 和为K的子数组](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode560%E5%92%8C%E4%B8%BAK%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.md) +- [【动画模拟】剑指 offer 3 数组中重复的数字](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/%E5%89%91%E6%8C%87offer3%E6%95%B0%E7%BB%84%E4%B8%AD%E9%87%8D%E5%A4%8D%E7%9A%84%E6%95%B0.md) +- [【动画模拟】leetcode 219 数组中重复元素 2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode219%E6%95%B0%E7%BB%84%E4%B8%AD%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A02.md) +- [【动画模拟】leetcode 560 和为 K 的子数组](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode560%E5%92%8C%E4%B8%BAK%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.md) - [【绘图描述】leetcode 66 加一](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode66%E5%8A%A0%E4%B8%80.md) - [【动画模拟】leetcode 75 颜色分类](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode75%E9%A2%9C%E8%89%B2%E5%88%86%E7%B1%BB.md) - [【动画模拟】leetcode 54 螺旋矩阵](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode54%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5.md) -- [【动画模拟】leetcode 59 螺旋矩阵2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode59%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B52.md) +- [【动画模拟】leetcode 59 螺旋矩阵 2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode59%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B52.md) - [【动画模拟】leetcode 233 数字 1 的个数](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%89%91%E6%8C%87offer/1%E7%9A%84%E4%B8%AA%E6%95%B0.md) -### 🦞求和问题 +### 🦞 求和问题 - [【动画模拟】leetcode 01 两数之和](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%B1%82%E5%92%8C%E9%97%AE%E9%A2%98/%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.md) - [【动画模拟】leetcode 15 三数之和](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%B1%82%E5%92%8C%E9%97%AE%E9%A2%98/%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.md) - [【动画模拟】leetcode 18 四数之和](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%B1%82%E5%92%8C%E9%97%AE%E9%A2%98/%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C.md) -### 🍓求次数问题 +### 🍓 求次数问题 - [【动画模拟】leetcode 136 只出现一次的数](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%B1%82%E6%AC%A1%E6%95%B0%E9%97%AE%E9%A2%98/%E5%8F%AA%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E7%9A%84%E6%95%B0.md) -- [【动画模拟】leetcode 137 只出现一次的数字 II](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%B1%82%E6%AC%A1%E6%95%B0%E9%97%AE%E9%A2%98/%E5%8F%AA%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E7%9A%84%E6%95%B02.md) +- [【动画模拟】leetcode 137 只出现一次的数字 II](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%B1%82%E6%AC%A1%E6%95%B0%E9%97%AE%E9%A2%98/%E5%8F%AA%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E7%9A%84%E6%95%B02.md) - [【动画模拟】leetcode 260 只出现一次的数字 III](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%B1%82%E6%AC%A1%E6%95%B0%E9%97%AE%E9%A2%98/%E5%8F%AA%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E7%9A%84%E6%95%B03.md) -### 🍅链表篇 +### 🍅 链表篇 -- [【动画模拟】剑指 offer 2 倒数第 k 个节点](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/%E5%89%91%E6%8C%87offer2%E5%80%92%E6%95%B0%E7%AC%ACk%E4%B8%AA%E8%8A%82%E7%82%B9.md) +- [【动画模拟】剑指 offer 22 倒数第 k 个节点](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/%E5%89%91%E6%8C%87offer22%E5%80%92%E6%95%B0%E7%AC%ACk%E4%B8%AA%E8%8A%82%E7%82%B9.md) - [【动画模拟】面试题 02.03. 链表中间节点](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/%E9%9D%A2%E8%AF%95%E9%A2%98%2002.03.%20%E9%93%BE%E8%A1%A8%E4%B8%AD%E9%97%B4%E8%8A%82%E7%82%B9.md) -- [【动画模拟】剑指 offer 52 两个链表的第一个公共节点](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/%E5%89%91%E6%8C%87Offer52%E4%B8%A4%E4%B8%AA%E9%93%BE%E8%A1%A8%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%AC%E5%85%B1%E8%8A%82%E7%82%B9.md) +- [【动画模拟】剑指 offer 52 两个链表的第一个公共节点 & leetcode 160 相交链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/%E5%89%91%E6%8C%87Offer52%E4%B8%A4%E4%B8%AA%E9%93%BE%E8%A1%A8%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%AC%E5%85%B1%E8%8A%82%E7%82%B9.md) - [【动画模拟】leetcode 234 回文链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/234.%20%E5%9B%9E%E6%96%87%E9%93%BE%E8%A1%A8.md) - [【动画模拟】leetcode 206 反转链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode206%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8.md) -- [【动画模拟】leetcode92反转链表2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode92%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A82.md) -- [【动画模拟】leetcode 142 环形链表2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode142%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A82.md) +- [【动画模拟】leetcode 92 反转链表 2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode92%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A82.md) +- [【动画模拟】leetcode 141 环形链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode141%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.md) +- [【动画模拟】leetcode 142 环形链表 2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode142%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A82.md) - [【动画模拟】leetcode 86 分隔链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode86%E5%88%86%E9%9A%94%E9%93%BE%E8%A1%A8.md) +- [【动画模拟】leetcode 328 奇偶链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode328%E5%A5%87%E5%81%B6%E9%93%BE%E8%A1%A8.md) - [【动画模拟】剑指 offer 25 合并两个排序链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/%E5%89%91%E6%8C%87Offer25%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%8E%92%E5%BA%8F%E7%9A%84%E9%93%BE%E8%A1%A8.md) -- [【动画模拟】leetcode 82 删除排序链表的重复元素2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode82%E5%88%A0%E9%99%A4%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0II.md) +- [【动画模拟】leetcode 82 删除排序链表的重复元素 2](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode82%E5%88%A0%E9%99%A4%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0II.md) +- [【动画模拟】leetcode 147 对链表进行插入排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode147%E5%AF%B9%E9%93%BE%E8%A1%A8%E8%BF%9B%E8%A1%8C%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F.md) - [【动画模拟】面试题 02.05 链表求和](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/%E9%9D%A2%E8%AF%95%E9%A2%98%2002.05.%20%E9%93%BE%E8%A1%A8%E6%B1%82%E5%92%8C.md) -### 🚁双指针 +### 🚁 双指针 - [【动画模拟】二分查找详解](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E8%AF%A6%E8%A7%A3.md) - [【动画模拟】leetcode 35 搜索插入位置](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/leetcode35%E6%90%9C%E7%B4%A2%E6%8F%92%E5%85%A5%E4%BD%8D%E7%BD%AE.md) - [【动画模拟】leetcode 27 移除元素](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/leetcode27%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.md) - [【动画模拟】leetcode 209 长度最小的子数组](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E7%BB%84%E7%AF%87/%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.md) - [【动画模拟】leetcode 141 环形链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode141%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.md) -- [【动画模拟】leetcode 160 相交链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode%E7%9B%B8%E4%BA%A4%E9%93%BE%E8%A1%A8.md) +- [【动画模拟】剑指 offer 52 两个链表的第一个公共节点 & leetcode 160 相交链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/%E5%89%91%E6%8C%87Offer52%E4%B8%A4%E4%B8%AA%E9%93%BE%E8%A1%A8%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%AC%E5%85%B1%E8%8A%82%E7%82%B9.md) - [【动画模拟】leetcode 328 奇偶链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode328%E5%A5%87%E5%81%B6%E9%93%BE%E8%A1%A8.md) -### 🏳‍🌈栈和队列 +### 🏳‍🌈 栈和队列 - [【动画模拟】leetcode 225 队列实现栈](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97/225.%E7%94%A8%E9%98%9F%E5%88%97%E5%AE%9E%E7%8E%B0%E6%A0%88.md) - [【动画模拟】剑指 Offer 09. 用两个栈实现队列](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97/%E5%89%91%E6%8C%87Offer09%E7%94%A8%E4%B8%A4%E4%B8%AA%E6%A0%88%E5%AE%9E%E7%8E%B0%E9%98%9F%E5%88%97.md) @@ -164,18 +133,18 @@ - [【动画模拟】leetcode1047 删除字符串中的所有相邻重复项](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97/leetcode1047%20%E5%88%A0%E9%99%A4%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E7%9B%B8%E9%82%BB%E9%87%8D%E5%A4%8D%E9%A1%B9.md) - [【动画模拟】leetcode 402 移掉 K 位数字](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97/leetcode402%E7%A7%BB%E6%8E%89K%E4%BD%8D%E6%95%B0%E5%AD%97.md) -### 🏬二分查找及其变种 +### 🏬 二分查找及其变种 - [【动画模拟】二分查找详解](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E8%AF%A6%E8%A7%A3.md) - [【动画模拟】leetcode 35 搜索插入位置](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/leetcode35%E6%90%9C%E7%B4%A2%E6%8F%92%E5%85%A5%E4%BD%8D%E7%BD%AE.md) - [【动画模拟】leetcode 34 查找元素的第一个位置和最后一个位置](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/leetcode34%E6%9F%A5%E6%89%BE%E7%AC%AC%E4%B8%80%E4%B8%AA%E4%BD%8D%E7%BD%AE%E5%92%8C%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E4%BD%8D%E7%BD%AE.md) - [【绘图描述】找出第一个大于或小于目标元素的索引](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/%E6%89%BE%E5%87%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%A4%A7%E4%BA%8E%E6%88%96%E5%B0%8F%E4%BA%8E%E7%9B%AE%E6%A0%87%E7%9A%84%E7%B4%A2%E5%BC%95.md) -- [【动画模拟】leetcode 33 旋转数组中查找目标元素(不含重复元素)](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/leetcode33%E4%B8%8D%E5%AE%8C%E5%85%A8%E6%9C%89%E5%BA%8F%E6%9F%A5%E6%89%BE%E7%9B%AE%E6%A0%87%E5%85%83%E7%B4%A0(%E4%B8%8D%E5%8C%85%E5%90%AB%E9%87%8D%E5%A4%8D%E5%80%BC).md) -- [【绘图描述】leetcode 81 旋转数组中查找目标元素(包含重复元素)](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/leetcode%2081%E4%B8%8D%E5%AE%8C%E5%85%A8%E6%9C%89%E5%BA%8F%E6%9F%A5%E6%89%BE%E7%9B%AE%E6%A0%87%E5%85%83%E7%B4%A0(%E5%8C%85%E5%90%AB%E9%87%8D%E5%A4%8D%E5%80%BC)%20.md) +- [【动画模拟】leetcode 33 旋转数组中查找目标元素(不含重复元素)]() +- [【绘图描述】leetcode 81 旋转数组中查找目标元素(包含重复元素)]() - [【绘图描述】leetcode 153 寻找旋转数组中的最小值](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/leetcode153%E6%90%9C%E7%B4%A2%E6%97%8B%E8%BD%AC%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%B0%8F%E5%80%BC.md) - [【动画模拟】leetcode 74 二维数组的二分查找](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E5%8F%8A%E5%85%B6%E5%8F%98%E7%A7%8D/%E4%BA%8C%E7%BB%B4%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.md) -### 💒单调队列单调栈 +### 💒 单调队列单调栈 - [【动画模拟】剑指 Offer 59 - II. 队列的最大值](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%8D%95%E8%B0%83%E9%98%9F%E5%88%97%E5%8D%95%E8%B0%83%E6%A0%88/%E5%89%91%E6%8C%87offer59%E9%98%9F%E5%88%97%E7%9A%84%E6%9C%80%E5%A4%A7%E5%80%BC.md) - [【动画模拟】剑指 Offer 59 - I. 滑动窗口的最大值](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%8D%95%E8%B0%83%E9%98%9F%E5%88%97%E5%8D%95%E8%B0%83%E6%A0%88/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E7%9A%84%E6%9C%80%E5%A4%A7%E5%80%BC.md) @@ -184,7 +153,7 @@ - [【动画模拟】leetcode 739 每日温度](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%8D%95%E8%B0%83%E9%98%9F%E5%88%97%E5%8D%95%E8%B0%83%E6%A0%88/leetcode739%E6%AF%8F%E6%97%A5%E6%B8%A9%E5%BA%A6.md) - [【动画模拟】leetcode 42 接雨水](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%8D%95%E8%B0%83%E9%98%9F%E5%88%97%E5%8D%95%E8%B0%83%E6%A0%88/%E6%8E%A5%E9%9B%A8%E6%B0%B4.md) -### 🛳前缀和 +### 🛳 前缀和 - [【动画模拟】leetcode 724 寻找数组的中心索引](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%89%8D%E7%BC%80%E5%92%8C/leetcode724%E5%AF%BB%E6%89%BE%E6%95%B0%E7%BB%84%E7%9A%84%E4%B8%AD%E5%BF%83%E7%B4%A2%E5%BC%95.md) - [【动画模拟】leetcode 523 连续的子数组和](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%89%8D%E7%BC%80%E5%92%8C/leetcode523%E8%BF%9E%E7%BB%AD%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84%E5%92%8C.md) @@ -192,82 +161,32 @@ - [【绘图描述】leetcode1248 统计「优美子数组」](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%89%8D%E7%BC%80%E5%92%8C/leetcode1248%E5%AF%BB%E6%89%BE%E4%BC%98%E7%BE%8E%E5%AD%90%E6%95%B0%E7%BB%84.md) - [【绘图描述】leetcode 974 和可被 K 整除的子数组](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E5%89%8D%E7%BC%80%E5%92%8C/leetcode974%E5%92%8C%E5%8F%AF%E8%A2%ABK%E6%95%B4%E9%99%A4%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.md) -### 🥥递归 +### 🥥 递归 - 敬请期待。。。 -### 🍒贪心 +### 🍒 贪心 - 敬请期待。。。 -### 🚃回溯 +### 🚃 回溯 - 敬请期待。。。 -### 🌆分治 +### 🌆 分治 - 敬请期待。。。 -### 🧭动态规划 +### 🧭 动态规划 - 敬请期待。。。 -### 🌋并查集 - - +### 🌋 并查集 ------- - - - -### 🛬一些分享 - -- [刷题时常用函数](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/Leetcode%E5%B8%B8%E7%94%A8%E7%B1%BB%E5%92%8C%E5%87%BD%E6%95%B0.md) -- [厨子的2020](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%B8%80%E4%BA%9B%E5%88%86%E4%BA%AB/%E5%8E%A8%E5%AD%90%E7%9A%842020.md) -- [在家如何高效学习](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%B8%80%E4%BA%9B%E5%88%86%E4%BA%AB/%E5%AD%A6%E4%B9%A0.md) -- [比特币原理详解](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%B8%80%E4%BA%9B%E5%88%86%E4%BA%AB/%E5%8C%BA%E5%9D%97%E9%93%BE%E8%AF%A6%E8%A7%A3.md) -- [github 年报](https://mp.weixin.qq.com/s/_-6h9D8VaXUtNenTXbTp5w) -- [如何在电脑同时登陆两个微信](https://mp.weixin.qq.com/s/HpdMxTvR_0XxIUbaRja6cw) -- [那些贼好用的写作软件](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E4%B8%80%E4%BA%9B%E5%88%86%E4%BA%AB/%E8%BD%AF%E4%BB%B6%E5%88%86%E4%BA%AB.md) -- [那些贼牛皮的办公工具](https://mp.weixin.qq.com/s/mJL1xCGZ3zJEPsrwg5d7oQ) - -### 🧊阅读分享 - -- [高效阅读法](https://mp.weixin.qq.com/s/ZJZyZFM4qCjOnz14CVYbmg) - -### 🍭面经 - -- [校招进腾讯,二本也可以?](https://mp.weixin.qq.com/s/GZtdcHB94bwKVyaopSODuQ) - -- [一个半月拿到阿里字节拼多多美团offer总结](https://mp.weixin.qq.com/s/YziTP0jqYSNS0mP18qGlAw) -- [从大学到秋招,我如何拿下腾讯offer](https://mp.weixin.qq.com/s/-Uez375ECoBda_a3coOegw) -- [在腾讯连拿六个五星](https://mp.weixin.qq.com/s/tgSgZ-VeZwqyQYiMu2a4HQ) - -### 🍖其他知识 - -- [C++程序喵大人 ](https://github.com/fightingwangzq/cpp-learning) -- [C++拓跋阿秀](https://github.com/forthespada/InterviewGuide) -- [编程资源](https://www.code-nav.cn) -- [腾讯云开发鱼皮](https://github.com/liyupi) -- [架构雷架](https://github.com/smileArchitect/JavaMap) - -### 🍰数据库学习 - -- [100道mysql经典面试题](https://mp.weixin.qq.com/s/aFoFHGFJXhP4gMWzYhB0Tw) -- [Redis 为什么那么快?](https://mp.weixin.qq.com/s/iyA9IppYtvHuLGbWtU84_w) - -### 🍫计算机基础 - -- [操作系统](https://mp.weixin.qq.com/s/lh6an9l6av7XitrVLLyEKw) - - - -拼命更新中。。。。。。 - ------- +- 敬请期待。。。 +> > > > > > > +---
- -###### #### \ No newline at end of file diff --git a/animation-simulation/.DS_Store b/animation-simulation/.DS_Store new file mode 100644 index 0000000..b91fd42 Binary files /dev/null and b/animation-simulation/.DS_Store differ diff --git "a/animation-simulation/Leetcode\345\270\270\347\224\250\347\261\273\345\222\214\345\207\275\346\225\260.md" "b/animation-simulation/Leetcode\345\270\270\347\224\250\347\261\273\345\222\214\345\207\275\346\225\260.md" index 82a8528..8d70f31 100644 --- "a/animation-simulation/Leetcode\345\270\270\347\224\250\347\261\273\345\222\214\345\207\275\346\225\260.md" +++ "b/animation-simulation/Leetcode\345\270\270\347\224\250\347\261\273\345\222\214\345\207\275\346\225\260.md" @@ -1,4 +1,4 @@ -# Leetcode常用函数 +# Leetcode 常用函数 ## 链表篇 @@ -7,14 +7,14 @@ ### ListNode ```java -ListNode list=new ListNode(0) +ListNode list=new ListNode(0) ``` -初始化一个值为0的空节点,提倡的写法 +初始化一个值为 0 的空节点,提倡的写法 ### HashSet -HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合但是允许有null值,HashSet 是无序的,即不会记录插入的顺序。HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。 +HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合但是允许有 null 值,HashSet 是无序的,即不会记录插入的顺序。HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。 ```java HashSet sites = new HashSet(); @@ -22,7 +22,7 @@ HashSet sites = new HashSet(); #### add() -往HashSet里添加元素 +往 HashSet 里添加元素 ``` sites.add("我是袁厨,大家快快关注我吧"); @@ -32,7 +32,7 @@ sites.add("我是袁厨,大家快快关注我吧"); #### remove() -remover()size()也是会用到的函数,具体用法和ArrayList一样 +remover()size()也是会用到的函数,具体用法和 ArrayList 一样 #### contains() @@ -44,13 +44,11 @@ System.out.println(sites.contains("我是袁厨,大家快快关注我吧")); > 输出:true; - - ## 数组篇 ### length -该函数是用来得到数组长度的函数,这里需要注意的是length后面没有括号 +该函数是用来得到数组长度的函数,这里需要注意的是 length 后面没有括号 ### sort() @@ -85,7 +83,7 @@ return array; ### Arrays.copyOfRange() -将一个原始的数组,从下标0开始复制,复制到上标2,生成一个新的数组 +将一个原始的数组,从下标 0 开始复制,复制到上标 2,生成一个新的数组 ``` int[] array = {1,2,3,4}; @@ -94,7 +92,7 @@ return ar; ``` -> array2: 1 , 2 ; +> array2: 1 , 2 ; ### System.arraycopy(); @@ -125,11 +123,11 @@ length:想要复制的长度 ### 逻辑运算符 -#### x | 0 +#### x | 0 得到的仍然是他本身, -例:1001|0000=1001;或运算代表的是如果两位其中有一个1则返回1,否则为0; +例:1001|0000=1001;或运算代表的是如果两位其中有一个 1 则返回 1,否则为 0; ```java public static void main(String[] args) { @@ -142,9 +140,9 @@ public static void main(String[] args) { #### x & 0 -无论任何数都会输出0,这个也很好理解。 +无论任何数都会输出 0,这个也很好理解。 -例:1001&0000=0000;两位都为1才能返回1 +例:1001&0000=0000;两位都为 1 才能返回 1 ``` public static void main(String[] args) { @@ -157,9 +155,9 @@ public static void main(String[] args) { #### x ^ 0 -得到的还是他本身,这个也很好理解,异或的含义就是如果相同输出0,如果不同输出1 +得到的还是他本身,这个也很好理解,异或的含义就是如果相同输出 0,如果不同输出 1 -例:0111^0000=0111第一位相同,其余位不同 +例:0111^0000=0111 第一位相同,其余位不同 ```java public static void main(String[] args) { @@ -172,7 +170,7 @@ public static void main(String[] args) { #### x | 1 -如果是奇数的话,还是它本身,偶数的话则加1; +如果是奇数的话,还是它本身,偶数的话则加 1; ```java int x =-9 ; @@ -185,7 +183,7 @@ System.out.println(y|1); #### x ^ 1 -如果是偶数则加1,如果是奇数则减1; +如果是偶数则加 1,如果是奇数则减 1; ```java int x =-9 ; @@ -198,7 +196,7 @@ System.out.println(y^1); #### x & 1 -得出最后一位是0还是1,通常会用来判断奇偶 +得出最后一位是 0 还是 1,通常会用来判断奇偶 ```java int x =-9 ; @@ -211,7 +209,7 @@ System.out.println(y&1); #### 1<<3 -代表的含义是将1左移3位,即0001 ---->1000则为2^3为8 +代表的含义是将 1 左移 3 位,即 0001 ---->1000 则为 2^3 为 8 ```java System.out.println(1<<3); @@ -221,36 +219,34 @@ System.out.println(1<<3); #### HashMap -创建一个HashMap,两种数据类型 +创建一个 HashMap,两种数据类型 ``` HashMap map = new HashMap(); ``` -往hashmap里面插入数据 +往 hashmap 里面插入数据 ```java for (int num : arr){ map.put(num, map.getOrDefault(num, 0) + 1);//如果没有则添加,如果有则加1 - } + } ``` -遍历Hashmap,查询值为k的元素 +遍历 Hashmap,查询值为 k 的元素 ``` for (int k : hashmap.keySet()) if (hashmap.get(k) == 1) return k; - + ``` -遍历 HashSet +遍历 HashSet ``` set.iterator().next();//迭代器 ``` - - ## 树篇 ### ArrayList> @@ -274,14 +270,14 @@ ArrayList 类是一个可以动态修改的数组,与普通数组的区别就 ```java public class Test { public static void main(String[] args) { - List array = new ArrayList<>(); + List array = new ArrayList<>(); array.add("大家好我是袁厨"); System.out.println(array); } } ``` -> 输出:大家好我是袁厨 +> 输出:大家好我是袁厨 #### get() @@ -290,7 +286,7 @@ get()函数用于获取动态数组的元素,括号内为索引值 ```java public class Test { public static void main(String[] args) { - List array = new ArrayList<>(); + List array = new ArrayList<>(); array.add("大家好我是袁厨"); System.out.println(array.get(0));//获取第一个元素 } @@ -298,7 +294,7 @@ public class Test { ``` -> 输出:大家好我是袁厨 +> 输出:大家好我是袁厨 #### set() @@ -307,7 +303,7 @@ set()用于修改元素,括号内为索引值 ``` public class Test { public static void main(String[] args) { - List array = new ArrayList<>(); + List array = new ArrayList<>(); array.add("大家好我是袁厨"); array.set(0,"祝大家天天开心") System.out.println(array.get(0));//获取第一个元素 @@ -324,7 +320,7 @@ public class Test { ``` public class Test { public static void main(String[] args) { - List array = new ArrayList<>(); + List array = new ArrayList<>(); array.add("大家好我是袁厨"); array.add("祝大家天天开心"); array.remove(0); @@ -337,7 +333,7 @@ public class Test { #### isEmpty() -isEmpty()函数判断是否为空,这个函数用到的地方很多,队列和栈的时候总会用。总是会在while循环中使用 +isEmpty()函数判断是否为空,这个函数用到的地方很多,队列和栈的时候总会用。总是会在 while 循环中使用 while(!queue.isEmpty()){ @@ -348,7 +344,7 @@ while(!queue.isEmpty()){ ``` public class Test { public static void main(String[] args) { - List array = new ArrayList<>(); + List array = new ArrayList<>(); array.add("大家好我是袁厨"); array.add("祝大家天天开心"); array.remove(0); @@ -411,14 +407,14 @@ public class Test{ sBuffer.append("是"); sBuffer.append("袁厨"); sBuffer.append("大家点个关注吧"); - System.out.println(sBuffer); + System.out.println(sBuffer); } } ``` > 输出:我的名字是袁厨大家点个关注吧 -String中的字符串是不允许修改的,这个StringBuffer可以进行修改,做字符串的题目时会经常用到,树的题目中也偶尔会遇到 +String 中的字符串是不允许修改的,这个 StringBuffer 可以进行修改,做字符串的题目时会经常用到,树的题目中也偶尔会遇到 ### charAt(i) @@ -438,9 +434,9 @@ public class Test { 这个函数的用法,就跟我们根据数组的索引输出值一样。在字符串题目中也比较常用。 -### s.charAt(index)-'0' +### s.charAt(index)-'0' -这个函数的用途是将字符串索引值变成int型。知道这个可以大大提高刷题效率。大家可以掌握一下。 +这个函数的用途是将字符串索引值变成 int 型。知道这个可以大大提高刷题效率。大家可以掌握一下。 ```java public class Test { @@ -457,16 +453,16 @@ public class Test { > 输出:java.lang.Integer -### Integer.toString() +### Integer.toString() -该函数用于将int型变为string型,比如这个**第9题求回文数**的题目,我们就是先将x变为字符串,然后再遍历字符串 +该函数用于将 int 型变为 string 型,比如这个**第 9 题求回文数**的题目,我们就是先将 x 变为字符串,然后再遍历字符串 ```java class Solution { public boolean isPalindrome(int x) { if(x<0){ return false; - } + } //将int型变成string型,然后遍历字符串,不再需要使用额外数组进行存储 String t = Integer.toString(x); int i = 0; @@ -495,12 +491,12 @@ public String substring(int beginIndex); public String substring(int beginIndex, int endIndex); ``` -表示两种情况,一种是从beginIndex到结尾,一种是从beginIndex ->endIndex; +表示两种情况,一种是从 beginIndex 到结尾,一种是从 beginIndex ->endIndex; ``` String Str = new String("程序员爱做饭"); System.out.println(Str.substring(3) ); - System.out.println(Str.substring(4, 5) ); + System.out.println(Str.substring(4, 5) ); ``` > 输出:爱做饭,做 @@ -515,8 +511,8 @@ public static void main(String args[]){ Integer y = 10; Integer z =5; Short a = 5; - System.out.println(x.equals(y)); - System.out.println(x.equals(z)); + System.out.println(x.equals(y)); + System.out.println(x.equals(z)); System.out.println(x.equals(a)); } ``` @@ -533,14 +529,12 @@ System.out.println(s); > 输出:12345 -### char数组变为String +### char 数组变为 String ```java String newstr = new String (arr2,start,end); ``` - - ### indexOf - **int indexOf(String str):** 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。 @@ -561,7 +555,7 @@ return s.indexOf("LLL"); Stack stack = new Stack();//创建栈 ``` -上面的是创建新栈,栈的变量类型为TreeNode,我们用深度优先遍历树来举例 +上面的是创建新栈,栈的变量类型为 TreeNode,我们用深度优先遍历树来举例 #### push() @@ -576,7 +570,7 @@ Stack stack = new Stack();//创建栈 移除堆栈顶部的对象,并作为此函数的值返回该对象。 ```java -TreeNode temp = stack.pop();//将栈顶元素出栈,赋值TreeNode变量temp +TreeNode temp = stack.pop();//将栈顶元素出栈,赋值TreeNode变量temp ``` peek() @@ -600,4 +594,3 @@ while(!stack.isEmpty()){ //反转并变为字符串 return str.reverse().toString(); ``` - diff --git "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\214\272\345\235\227\351\223\276\350\257\246\350\247\243.md" "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\214\272\345\235\227\351\223\276\350\257\246\350\247\243.md" index 45aea82..933ebda 100644 --- "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\214\272\345\235\227\351\223\276\350\257\246\350\247\243.md" +++ "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\214\272\345\235\227\351\223\276\350\257\246\350\247\243.md" @@ -1,4 +1,4 @@ -最近总是能在一些网站上看到比特币大涨的消息,诺,这不都涨破20000美元啦。 +最近总是能在一些网站上看到比特币大涨的消息,诺,这不都涨破 20000 美元啦。 最近比特币涨势喜人,牵动着每一位股民的心,持有的老哥后悔说当时我咋就没多买点呢,不然明天早饭又能多加个鸡蛋啦,没持有的呢,就在懊恼后悔当时为啥就没买入呢?这不我女朋友也看到新闻了,说比特币最近涨那么厉害,咱们要不买两个呀!然后这个总是听到的比特币到底是什么东西呀? @@ -10,7 +10,7 @@ 我先给你说一下比特币的历史吧。 -> 2008年爆发全球金融危机,同年11月1日,一个自称中本聪(Satoshi Nakamoto)的人在P2P foundation网站上发布了比特币白皮书《比特币:一种点对点的电子现金系统》 陈述了他对电子货币的新设想——比特币就此面世。2009年1月3日,比特币创世区块诞生。 +> 2008 年爆发全球金融危机,同年 11 月 1 日,一个自称中本聪(Satoshi Nakamoto)的人在 P2P foundation 网站上发布了比特币白皮书《比特币:一种点对点的电子现金系统》 陈述了他对电子货币的新设想——比特币就此面世。2009 年 1 月 3 日,比特币创世区块诞生。 你平时不是会把每天的收入和支出记在自己的小本本上,我们称之为记账。我们平常在消费的时候,银行也会为我们记录这条交易记录及交易后银行卡里的余额。然后我们会通过银行卡里数字来评估自己拥有的财富。所以我们拥有多少财富都通过银行的记账本来决定的。 @@ -20,32 +20,31 @@ ### 1.那你说的那个区块链到底是什么东西呀,我不是很懂哎? -我们对上图进行解析,A,B,C,D,四个小伙伴进行交易,首先 A 支付 5 个比特币给 B,那么他需要将这条交易信息发送给每位小伙伴,同理 B 和 C,C 和 D的交易也要传送给所有的小伙伴,用户会将这些交易信息记录下来,并打包成块,我们称之为**区块**,(区块大小约为1M,约4000条左右交易记录),当块存满时我们将这个块接到以前的交易记录上,形成一条链,过一段时间再把新的块接到它后面,我们称这条链为**区块链**,如下图。 +我们对上图进行解析,A,B,C,D,四个小伙伴进行交易,首先 A 支付 5 个比特币给 B,那么他需要将这条交易信息发送给每位小伙伴,同理 B 和 C,C 和 D 的交易也要传送给所有的小伙伴,用户会将这些交易信息记录下来,并打包成块,我们称之为**区块**,(区块大小约为 1M,约 4000 条左右交易记录),当块存满时我们将这个块接到以前的交易记录上,形成一条链,过一段时间再把新的块接到它后面,我们称这条链为**区块链**,如下图。 ![区块链](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/区块链.2s1tuiwa4ba0.png) - 好啦,我们大概了解什么是区块链了。 ### 2.好啦我知道什么是区块链了,但是那些用户为什么要记录交易信息呢? -记账奖励:每个用户都可以去记账,如果某个用户进行记帐则会奖励他一些手续费,比如A 和 B 交易 10 个比特币,A 就需要多支出一点点给为其记录的人。其实现实生活中,我们使用银行卡时也会有手续费,这里的手续费是支付给银行。 +记账奖励:每个用户都可以去记账,如果某个用户进行记帐则会奖励他一些手续费,比如 A 和 B 交易 10 个比特币,A 就需要多支出一点点给为其记录的人。其实现实生活中,我们使用银行卡时也会有手续费,这里的手续费是支付给银行。 打包(将交易记录打包成块)奖励:打包者只能有一位,完成打包的那一位能够获得**打包奖励**, ### 3.哦,知道了,那打包一次能获得多少奖励呢? -2008年刚提出这个系统时,奖励方案如下 +2008 年刚提出这个系统时,奖励方案如下 -每十分钟打一个包,最开始的时候,每打一个包会奖励打包者 50 个比特币,过了四年之后,每打一个包奖励 25 个比特币,再过四年的则奖励 12.5个比特币,以此类推。 +每十分钟打一个包,最开始的时候,每打一个包会奖励打包者 50 个比特币,过了四年之后,每打一个包奖励 25 个比特币,再过四年的则奖励 12.5 个比特币,以此类推。 ### 4.哇,那么多,那世界上一共有多少个比特币呢? -一个包奖励 50 个比特币,一个小时 6 个包,一天 24 小时,一年 365天 ,每隔四年减半,则计算公式如下 +一个包奖励 50 个比特币,一个小时 6 个包,一天 24 小时,一年 365 天 ,每隔四年减半,则计算公式如下 ![微信图片_20201218150122](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/微信图片_20201218150122.1hx8euiaa9uo.png) -总数大概为 2100万个比特币。 +总数大概为 2100 万个比特币。 ### 5.因为我们有手续费和打包费的奖励机制,所以大家都抢着打包,但是打包者只能有一个人,那么我们应该让谁打包呢? @@ -53,7 +52,7 @@ ### 6.你说的那个挖矿的原理是怎样的呢,我想不通? -刚才我们说挖矿的原理其实是让我们做一道数学题,谁先做出来算谁的,这个题目还不拼智商,需要我们一个一个的试,取决于咱们CPU的运行速度。那么具体原理是什么呢? +刚才我们说挖矿的原理其实是让我们做一道数学题,谁先做出来算谁的,这个题目还不拼智商,需要我们一个一个的试,取决于咱们 CPU 的运行速度。那么具体原理是什么呢? **这里可以选择性阅读,不感兴趣可以直接跳到第 8 个问题** @@ -67,7 +66,6 @@ ![sha256](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/sha256.5veoxktednk0.png) - 我们已经了解了生成摘要的过程,那么挖矿的具体原理是什么样呢? 刚才我们说到,区块链其实是一大堆交易信息,其实我们的区块里面不只有交易信息,还有头部。目前有很多人记录了系统的交易信息,然后想把自己记录的交易信息打包成块,并连接到区块链上,获得打包费。那么多人想打包,但是只能有一个人可以获得打包权,那么具体是解决了怎样的数学问题获得打包权的呢? @@ -78,19 +76,19 @@ 主要有以上信息组成,前块的头部,你所记录的账单信息,时间戳,随机数组成。那么我们看,这里的组成部分对于所用用户来说,只有前块头部是固定的,账单信息因为每个人记录顺序不同也是不固定的,每个人开始的时间不一样,那么时间也是不固定的,随机数也不固定,那么既然我们的输入都是不固定的,那这个题应该怎么答呀,那怎么保证公平呢?主要通过以下方法 -刚才我们也说了,经过 SHA256 加密之后会得到一个 256位的二进制数。 +刚才我们也说了,经过 SHA256 加密之后会得到一个 256 位的二进制数。 -获得打包权的那个难题就是让我们把字符串经过两次 SHA256 运算之后得到一个哈希值,哈希值要求**前 n 位**为0,意思就是谁先算出那个前 n 位为 0 的哈希值,谁就能获得打包权。 +获得打包权的那个难题就是让我们把字符串经过两次 SHA256 运算之后得到一个哈希值,哈希值要求**前 n 位**为 0,意思就是谁先算出那个前 n 位为 0 的哈希值,谁就能获得打包权。 因为每个人的输入是不固定的,但是对于个人来说,他开始运算的时间是固定的,头部也是固定的,他所记录内容也是固定的,所以他只能依靠调整**随机数**来修改最后的哈希值,只能挨个试,但是如果人品爆发可能试的第一个数就能得到符合要求的哈希值,但是总的来说还是一个考察算力的题目。 ![两次哈希函数](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/两次哈希函数.3dv6ep2rqh00.png) -### 7.那哈希值前 n 位为 0 ,这个 n 是依据什么决定的呢? +### 7.那哈希值前 n 位为 0 ,这个 n 是依据什么决定的呢? 这个 n 越大计算难度就越大,因为我们不能反算,只能挨个去试,每一位上出现 0 或 1 的概率都为 1/2,那么我们获得前 n 位为 0 的哈希值概率也就是 1/2 的 n 次方。 -当时中本聪在设计时,为了保证每十分钟出一个块,所以就会适当的调整 n, 比特币系统每过2016个区块之后,就会自动调整一次难度目标。如果上一个难度目标调整周期(也就是之前2016个区块),平均出块时间大于10分钟,说明挖矿难度偏高,需要降低挖矿难度;反之,前一个难度目标调整周期,平均出块时间小于10分钟,说明挖矿难度偏低,需要提高挖矿难度。难度目标上调和下调的范围都有4倍的限制。 +当时中本聪在设计时,为了保证每十分钟出一个块,所以就会适当的调整 n, 比特币系统每过 2016 个区块之后,就会自动调整一次难度目标。如果上一个难度目标调整周期(也就是之前 2016 个区块),平均出块时间大于 10 分钟,说明挖矿难度偏高,需要降低挖矿难度;反之,前一个难度目标调整周期,平均出块时间小于 10 分钟,说明挖矿难度偏低,需要提高挖矿难度。难度目标上调和下调的范围都有 4 倍的限制。 所以这个 n 是根据挖矿难度(算力)进行调整的,也就是我们矿机的算力和矿机数量等进行调整。 @@ -106,21 +104,21 @@ 我们在传输记录时通过私钥加密,然后通过公钥解密,加密和解密的钥匙不一样,所以我们称之为非对称加密 -具体交易流程如下,例 A支付 5 个比特币给 B +具体交易流程如下,例 A 支付 5 个比特币给 B ![广播](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/广播.3y66ai91qa00.png) -我们其他用户接收到了这个支付消息,那其他用户怎么判断这条信息是不是A发出的呢?不是他人冒充 A 发的呢?具体流程如下 +我们其他用户接收到了这个支付消息,那其他用户怎么判断这条信息是不是 A 发出的呢?不是他人冒充 A 发的呢?具体流程如下 ![广播对比](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/广播对比.76soh60sm2s0.png) -其他用户进行对比,如果一致则认可这条消息是A发的,不一致则认为是别人冒充,所有用户则会拒绝这条消息。这里可能会不明白了,公钥和私钥你都发出来了解密肯定的呀,刚才我们说公钥的公开的,但是公钥是由私钥加密得到的,私钥是私密的唯一的,只有 A 用户知道自己的私钥。 +其他用户进行对比,如果一致则认可这条消息是 A 发的,不一致则认为是别人冒充,所有用户则会拒绝这条消息。这里可能会不明白了,公钥和私钥你都发出来了解密肯定的呀,刚才我们说公钥的公开的,但是公钥是由私钥加密得到的,私钥是私密的唯一的,只有 A 用户知道自己的私钥。 ### 9.哇,好神奇啊,我知道了,那要是我只有 5 个比特币,同时支付给两个人咋办,每个人五个,那我岂不是赚了呀。 厉害呀,这你都能想到,但是你想多啦。 -比如A只有五个比特币,他同时发了两个消息,分别是给 B 五个比特币,给 C 五个比特币,但是他总数只有 5 个,这样显然是不行的,我们称之为**双重支付**。 +比如 A 只有五个比特币,他同时发了两个消息,分别是给 B 五个比特币,给 C 五个比特币,但是他总数只有 5 个,这样显然是不行的,我们称之为**双重支付**。 那么我们如何解决呢? @@ -128,15 +126,15 @@ ![追溯](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/追溯.4lbdktlb5re0.png)追溯 -用户在接收到这个消息时,会先从区块链里,进行查询A的交易记录,得出A的余额是否大于交易数额,如果大于则接收,反之则拒绝。 +用户在接收到这个消息时,会先从区块链里,进行查询 A 的交易记录,得出 A 的余额是否大于交易数额,如果大于则接收,反之则拒绝。 ##### 解决双重支付 -首先我们来了解下什么是双重支付,打个比方哈,袁记菜馆第963家分店因为店长经营不善,要进行出售,出售的时候店长将这个房子同时卖给了两个人,但是只有一个房子,这就是**双重支付**。 +首先我们来了解下什么是双重支付,打个比方哈,袁记菜馆第 963 家分店因为店长经营不善,要进行出售,出售的时候店长将这个房子同时卖给了两个人,但是只有一个房子,这就是**双重支付**。 ![双重支付](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/双重支付.2ff4ejsp3esk.png)双重支付 -在比特币系统中是如何解决双重支付问题的呢?我们 A 用户只有 5 个比特币,但是他几乎同时发布了两条广播,此时有些用户会先接收到第一条广播,然后进行追溯,发现 A 只有5个比特币,则会拒绝第二条。同理先接收到第二条广播的用户也会如此。就好比形成了两个阵营,然后两个阵营的用户进行答题,然后获得了打包权,则会将自己打的包接到区块链上,那么他所接收到的那条消息则会被整个系统认可。另一条则会放弃。 +在比特币系统中是如何解决双重支付问题的呢?我们 A 用户只有 5 个比特币,但是他几乎同时发布了两条广播,此时有些用户会先接收到第一条广播,然后进行追溯,发现 A 只有 5 个比特币,则会拒绝第二条。同理先接收到第二条广播的用户也会如此。就好比形成了两个阵营,然后两个阵营的用户进行答题,然后获得了打包权,则会将自己打的包接到区块链上,那么他所接收到的那条消息则会被整个系统认可。另一条则会放弃。 比如用户 D 先接收到了第二条广播 ,A 支付给 C,然后 D 用户获得了打包权,则 D 将包接到链上,那么其余用户则会放弃自己的包,全部都认可 D 所记录的交易信息。所以此时 C 收入 5 个比特币,B 没有收入。所以我们接收到别人交易消息时,不能认为当时已经到账,要等新的块已经形成,消息被记录到主链上才可以。 @@ -156,7 +154,6 @@ ![红色块分支](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/红色块分支.72gt7kf4gzo0.png) - A 此时想要修改红色块里的交易记录,则 A 需要重新计算重新打包,创造出一个支链来,但是大家不会承认你这个支链,因为这个支链不是最长的,所以不会承认你伪造的信息,如果你非要继续往下算,什么时候你自己创造的支链长度大于世界上所有人的打包的链的长度,那么恭喜你,你伪造成功了,大家都认可你的伪造信息了,所以说理论上是可以篡改的,但是你改了之后不会被大家承认,除非你的计算能力超过了世界上其余所有的人。大家试想一下一个掌握全世界一半以上算力的人,会去干这种无聊的事吗? 这下我全都懂了,那咱们快去买两个吧! @@ -165,8 +162,4 @@ A 此时想要修改红色块里的交易记录,则 A 需要重新计算重新 -另外给大家建了一个寒假刷题互相监督群,需要的可以联系我,公众号内点击一起刷题即可,为了防止广告党进入,大家记得备注【刷题】,目前人数大概有200来人。大家可以自行组成小队,也可以一起商量题目。多个人一起走,才能走得更远 - - - - +另外给大家建了一个寒假刷题互相监督群,需要的可以联系我,公众号内点击一起刷题即可,为了防止广告党进入,大家记得备注【刷题】,目前人数大概有 200 来人。大家可以自行组成小队,也可以一起商量题目。多个人一起走,才能走得更远 diff --git "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\216\250\345\255\220\347\232\2042020.md" "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\216\250\345\255\220\347\232\2042020.md" index 3ad22af..406f38c 100644 --- "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\216\250\345\255\220\347\232\2042020.md" +++ "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\216\250\345\255\220\347\232\2042020.md" @@ -1,15 +1,11 @@ ## 我的那些牛 X 的事 -在火车上无聊,写下了这篇随笔,2020年已经过去了一段时间,这篇年度总结好像来的略微晚了一些,因为实在不知道写些什么,感觉这一年没有特别突出的成绩,也没有特别大的突破,平平淡淡。下面我试着说一下我的2020,希望不会浪费你们的这几分钟。 +在火车上无聊,写下了这篇随笔,2020 年已经过去了一段时间,这篇年度总结好像来的略微晚了一些,因为实在不知道写些什么,感觉这一年没有特别突出的成绩,也没有特别大的突破,平平淡淡。下面我试着说一下我的 2020,希望不会浪费你们的这几分钟。 - - -### **2020印象最难忘的一件事** +### **2020 印象最难忘的一件事** 印象最深的一件事,应该是我疫情期间参加志愿者吧,做一些很简单的工作,站岗,登记,测温,消毒,宣传抗疫知识,虽没有什么技术含量,但也要细心严谨。 - - 参加志愿者的时间是在一月下旬,算是疫情最严重的时候,爸妈虽然担心,但还算支持,就这样安然无恙的工作了两个多星期,但是某天晚上睡觉前,总感觉身体不舒服,当时心想,我去,该不是发烧了吧, 我就拿起体温计,测了一下体温,37.8!不对不对,肯定是温度计整错了,再来。我就又测了一遍,38.1!坏了,我该不会被感染了吧!说实话,当时我真以为我被感染了,真的把自己吓坏了。 @@ -20,33 +16,23 @@ 抽完之后,地上湿了一小片,不是我的血,是因为医生额头上豆大的汗珠滴落在地。(没有夸张,因为我们是先在小医院初检,所以医生的心理素质没有那么高)我当时的心情却格外平静,(可能该吓得都吓完了)之后又做了一些别的检查,最后发现我没有被传染,而是得了水痘。 -就是那种小朋友容易得的小水泡,我也想不明白我20多岁的大小伙子,咋就得了水痘了。不过万幸没有被传染。然后在家休息了两个星期,痊愈之后,又继续干了一段时间的志愿者,直到解封。 +就是那种小朋友容易得的小水泡,我也想不明白我 20 多岁的大小伙子,咋就得了水痘了。不过万幸没有被传染。然后在家休息了两个星期,痊愈之后,又继续干了一段时间的志愿者,直到解封。 这件事算是给我上了一课,现在想想当时真的太幼稚啦,不过也算是给我的 2020 增添了一些别样的色彩。 - - -### **2020最正确的一件事** - - +### **2020 最正确的一件事** 最正确的事应该是学会书写,在此之前我是以读者的角度思考问题,想方设法将别人的知识搞懂,搞懂之后也就不在理会。 现在的我想方设法的让别人弄懂,努力将一些不是特别容易理解的问题,包装加工,让其变的生动活泼,尽全力让其变的通俗易懂。在这个过程中我的收获是巨大的,让我对问题的理解更加透彻,注意到了之前忽略掉的一些细节。 - - 写文章从来不是一件容易的事情,把文章写好更是如此,这是之前的我没有体会到的。每次写完一篇文章,都会给自己带来满满的自豪感,就好像辛苦拉扯大了一个孩子。 前辈们的每一次转载,读者的每一次点赞,都会让我感觉到努力得到了认可,促使我更加积极,用心的去输出,所以希望读者以后遇到对你们有帮助的文章(不仅仅是我的),不要吝啬你的点赞,多多鼓励一下他们。借用小林的一句话,利他必利己。 +### **2020 最遗憾的一件事** - -### **2020最遗憾的一件事** - - - -2020最遗憾的事,是自己没有利用好疫情居家期间那段可以自由支配的时间,没有那时候就开始写作。 +2020 最遗憾的事,是自己没有利用好疫情居家期间那段可以自由支配的时间,没有那时候就开始写作。 在家里学习的效率是很低的,没有很强的自制力,只是按部就班的上网课,写实验报告,做课设。因为上半学期有一门课考的很差劲,所以下半学期就需要使劲学,去填那一门的坑。 @@ -54,24 +40,17 @@ 不过人成长的标志就是开始学着“身不由己”,做一些自己不是那么想做,甚至说有点讨厌的事。所以希望我以后可以合理利用我能利用的时间。控制好我所能控制的事。 -以上就是我的2020,在你们看来或许都是很平常的事,但做为亲身经历者的我而言,就是我的那些牛 X 的事。 - - - -### **2021 想要做的一些事** - - - - 多打打球,自从写了公众号之后,把运动和娱乐的时间都用到了写作上,虽然体 型变化不大,但是明显感觉到了打球时的体力下降。 +以上就是我的 2020,在你们看来或许都是很平常的事,但做为亲身经历者的我而言,就是我的那些牛 X 的事。 +### **2021 想要做的一些事** +多打打球,自从写了公众号之后,把运动和娱乐的时间都用到了写作上,虽然体 型变化不大,但是明显感觉到了打球时的体力下降。 - 2021 保证一周打两次球。 -- 和女朋友毕业后能在同一座城市找到满意的工作。 -- 坚持写作,希望 2021 可以完成 70 篇高质量原创。 -- 理财收益 2020 大概百分之 27,希望 2021 可以继续保持。 -- 完成一次半马,一直想参加,但还没有参加过,希望今年可以实现 +- 和女朋友毕业后能在同一座城市找到满意的工作。 +- 坚持写作,希望 2021 可以完成 70 篇高质量原创。 +- 理财收益 2020 大概百分之 27,希望 2021 可以继续保持。 +- 完成一次半马,一直想参加,但还没有参加过,希望今年可以实现 好啦,就这么些吧,多了我也完成不了,感谢各位阅读,拜了个拜。 - diff --git "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\255\246\344\271\240.md" "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\255\246\344\271\240.md" index cadd5bf..2548b88 100644 --- "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\255\246\344\271\240.md" +++ "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\345\255\246\344\271\240.md" @@ -2,11 +2,11 @@ 每天早上醒来,先给自己打个气,今天我一定要好好学习。打完气之后,就开始躺在床上玩手机。吃了睡,睡了吃,好不容易打开电脑学个习,看了半个小时就再次倒下。 -还有的时候呢?2:45啦,我再玩一会吧,凑个整,到 3 点再学习,玩着玩着,那边你妈喊你吃晚饭了。 +还有的时候呢?2:45 啦,我再玩一会吧,凑个整,到 3 点再学习,玩着玩着,那边你妈喊你吃晚饭了。 晚上,躺在床上,再一次给自己打气,我明天一定要早起好好学习,然后一个没忍住继续玩手机,第二天又睡过头了,继续复制昨天的生活。 -相信大家放假之前都有在假期里大干一场的想法,可谁知回到家之后,身体开始不受控制,总想躺着。给大家总结了一波小技巧,希望对大家有一丢丢帮助。 +相信大家放假之前都有在假期里大干一场的想法,可谁知回到家之后,身体开始不受控制,总想躺着。给大家总结了一波小技巧,希望对大家有一丢丢帮助。 **拒绝舒适** @@ -86,7 +86,7 @@ img -**软件名称:番茄ToDo** +**软件名称:番茄 ToDo** 这是一款锁机软件,我们可以用它来**强制锁机,只保留通话功能,**设定好锁机时间之后,手机就变成了一块板砖,只有等到时间结束之后,才能使用手机。如果手机**没有禅定模式**的话,则可以用这个软件代替 @@ -96,4 +96,4 @@ 这也是一款能够**帮助我们自律**的软件,我们可以设定学习时长,**如果期间玩手机,则会让你的小树枯萎,完成目标则会让小树长大**,有点类似养成型游戏。这是同学推荐的,他经常用,听说效果还不错,感兴趣的同学可以试试。 -好啦,我知道的大概就这么多啦,希望大家可以利用好寒假,冲冲冲! \ No newline at end of file +好啦,我知道的大概就这么多啦,希望大家可以利用好寒假,冲冲冲! diff --git "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\350\200\203\347\240\224\345\210\206\344\272\253.md" "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\350\200\203\347\240\224\345\210\206\344\272\253.md" index 3a2e57a..cc72e03 100644 --- "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\350\200\203\347\240\224\345\210\206\344\272\253.md" +++ "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\350\200\203\347\240\224\345\210\206\344\272\253.md" @@ -4,9 +4,9 @@ 下面是学弟的分享 ------- +--- -先说明一下自己的情况,南开材料跨考浙大计算机学硕,初试411分,已经拟录取,接受算法基地老哥的邀请,分享一下自己关于考研的一点点经验 +先说明一下自己的情况,南开材料跨考浙大计算机学硕,初试 411 分,已经拟录取,接受算法基地老哥的邀请,分享一下自己关于考研的一点点经验 主要分三个部分来说吧,择校,初试科目复习以及整个过程中的心态。 @@ -30,7 +30,7 @@ 因为疫情,去年上半年直接在家里,而我又是一个在家里从来不学的人,一本张宇的基础三十讲,从过年到六月份看了十二章, -408也是只买了王道的课压根就没打开,在家里每天就是打游戏和吃东西,等到6.8号返校开始全面复习时,才发现自己的进度非常的慢, +408 也是只买了王道的课压根就没打开,在家里每天就是打游戏和吃东西,等到 6.8 号返校开始全面复习时,才发现自己的进度非常的慢, 导致一直都有一点点担心自己的进度(但是也不要一味的赶进度,我还是踏踏实实的学,后来的结果也没有很差)开始全面复习之后作息就比较规律了。 @@ -38,7 +38,7 @@ ### 政治 -关于具体的每个学科的复习,首先,政治,我的政治很差,一千题刷了两遍,知识点精讲精练也过了三遍,但是最后客观题还是扣了十五分,导致只有67,不过主要是错在时政的选择题(我个人属于有点喜欢钻牛角尖的,所以会纠结一些很奇怪的方面), +关于具体的每个学科的复习,首先,政治,我的政治很差,一千题刷了两遍,知识点精讲精练也过了三遍,但是最后客观题还是扣了十五分,导致只有 67,不过主要是错在时政的选择题(我个人属于有点喜欢钻牛角尖的,所以会纠结一些很奇怪的方面), 虽然我政治考的很差,但我觉得 **1000 题和肖四肖八 **还是很重要的,毕竟大题接近于进场默写,时政方面我确实没有去管于是也在这里吃了亏。 @@ -46,7 +46,7 @@ ### 英语 -然后就是英语一,我的英语很烂,虽然高考的时候有137分,但是就属于那种,短时间的应试,并不是自己语言能力的提高,四级四百多分,六级考了两遍最终也是四百九十多分,英语就死抓着真题硬啃就够了,再搭配上单词的背记。 +然后就是英语一,我的英语很烂,虽然高考的时候有 137 分,但是就属于那种,短时间的应试,并不是自己语言能力的提高,四级四百多分,六级考了两遍最终也是四百九十多分,英语就死抓着真题硬啃就够了,再搭配上单词的背记。 但我太懒了,单词背了一遍就没背了最终也是吃了亏,刚开始刷真题的时候,一套题客观题基本就拿个二十几分,那段时间每天做完英语对答案就会心慌,害怕自己因为英语拖后腿考不上研究生,我是两天一个周期,第一天做完对答案,第二天整张卷子翻译并且找出生词。 @@ -54,7 +54,7 @@ 第二轮刷真题就不怎么在意选项是啥了,毕竟题都背的下来,主要就是看自己能否顺畅在心中翻译理解卷子中的文章,再有就是分析阅读题出题逻辑的角度,其实如果文章意思能读懂,每个人会出错的方面基本不会变,多分析自己错的题,找出自己逻辑与正确答案逻辑的差异,并且让自己的逻辑往正确答案靠,养成试卷的思维,我认为是很重要的。 -我把97年到15年的英语真题都刷了两边,最后冲刺刷16到20的卷子每张卷子客观题都只错了十分之内,不过今年的题还是给我上了一课hhhh,惩罚了我不去背单词,搞得自己阅读题很多都没有看懂,最终拿了70分也算是很一般了,大家一定可以做的比我更好。 +我把 97 年到 15 年的英语真题都刷了两边,最后冲刺刷 16 到 20 的卷子每张卷子客观题都只错了十分之内,不过今年的题还是给我上了一课 hhhh,惩罚了我不去背单词,搞得自己阅读题很多都没有看懂,最终拿了 70 分也算是很一般了,大家一定可以做的比我更好。 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210406105202.4xbxgtbai5q0.png) @@ -64,27 +64,25 @@ 哦对了,关于考研跟哪位数学老师,我觉得这是很个人的事情,市面上比较有名的老师教学肯定都是没问题的,得看你自己喜欢什么样的风格,我最终选择了张宇,因为他讲课很有意思,不会让我打瞌睡,我从六月份开始花了一个半月把基础课程看完。 -这期间跟着视频做例题和书上的习题,然后第二轮看提高的教材和提高的视频,这期间除了做提高的教材,还搭配刷配套的1000题,关于题集的选择也是很个人的,我刚开始选的是1800题,但是做的太不顺了,后来换成了1000题,1000题刚开始只做AB,最后冲刺的时候才做的C。 +这期间跟着视频做例题和书上的习题,然后第二轮看提高的教材和提高的视频,这期间除了做提高的教材,还搭配刷配套的 1000 题,关于题集的选择也是很个人的,我刚开始选的是 1800 题,但是做的太不顺了,后来换成了 1000 题,1000 题刚开始只做 AB,最后冲刺的时候才做的 C。 -第三轮就是开始刷真题和模拟卷以及开始收集错题,因为我的基础太差了,导致我的数学进度一直很赶,最后半个月才把错题整理完,导致我线代复习的还不是很好,最后也确实错了一个选择题和线代大题的第二问,真题我从87年还是多少年开始刷的,一直刷到20年,一天一套,做完就对答案然后整理错题,整理错题是很重要的一环. +第三轮就是开始刷真题和模拟卷以及开始收集错题,因为我的基础太差了,导致我的数学进度一直很赶,最后半个月才把错题整理完,导致我线代复习的还不是很好,最后也确实错了一个选择题和线代大题的第二问,真题我从 87 年还是多少年开始刷的,一直刷到 20 年,一天一套,做完就对答案然后整理错题,整理错题是很重要的一环. -我觉得对于应试数学的提高还是很有效的,毕竟题是做不完的,但是题型只有这么多,如果能做到做一题而通一类,对于数学分数的提高还是很有作用的,模拟题我做了李林和张宇的模拟题,但是还有其他的模拟题比如**合工大**,但我实在是时间太赶了,所以就没有再做,最后的结果141也算还不错。 +我觉得对于应试数学的提高还是很有效的,毕竟题是做不完的,但是题型只有这么多,如果能做到做一题而通一类,对于数学分数的提高还是很有作用的,模拟题我做了李林和张宇的模拟题,但是还有其他的模拟题比如**合工大**,但我实在是时间太赶了,所以就没有再做,最后的结果 141 也算还不错。 ![图片来源于网络](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210406105545.5fnxma7jbs80.png) - - ### 专业课 -最后是408,408我也是从六月份开始复习的,刚开始拿着王道的教材和王道的视频过一遍,做王道书上的选择题,因为408的知识很系统,所以刚开始做题痛苦的一比,一章错一半是常有,第二轮自己细读教材,把知识点自己提炼写在笔记本上. +最后是 408,408 我也是从六月份开始复习的,刚开始拿着王道的教材和王道的视频过一遍,做王道书上的选择题,因为 408 的知识很系统,所以刚开始做题痛苦的一比,一章错一半是常有,第二轮自己细读教材,把知识点自己提炼写在笔记本上. -同时二刷选择题然后把王道书上的大题过一遍,最后第三轮的时候刷408真题和王道的模拟题,我觉得408很像理综,数据结构和计组像物理,有思维逻辑思考的过程,操作系统和计网就和化学生物一样,一定要基础的知识稳固才能做出题,对了,如果时间充裕,基础教材也是很重要的. +同时二刷选择题然后把王道书上的大题过一遍,最后第三轮的时候刷 408 真题和王道的模拟题,我觉得 408 很像理综,数据结构和计组像物理,有思维逻辑思考的过程,操作系统和计网就和化学生物一样,一定要基础的知识稳固才能做出题,对了,如果时间充裕,基础教材也是很重要的. -我就因为完全没看过基础教材,搞得今年那些很基础很基础的概念题错了,408只要选择题不出问题,大题基本上不会错多少分,最多是数据结构的算法题有一些障碍,但直接用暴力算法也只会扣几分无伤大雅,最终我错了六个选择题ORZ,大家不要学习我基础薄弱,最后133分也算不错。 +我就因为完全没看过基础教材,搞得今年那些很基础很基础的概念题错了,408 只要选择题不出问题,大题基本上不会错多少分,最多是数据结构的算法题有一些障碍,但直接用暴力算法也只会扣几分无伤大雅,最终我错了六个选择题 ORZ,大家不要学习我基础薄弱,最后 133 分也算不错。 噢对了,如果目标院校有机试的兄弟,机试也是很重要的一部分,建议尽早复习,机试复习对于数据结构的复习帮助也是很大的。 -而关于复习时的时间安排,我是完全按照考试时间来的,**所有的上午都是用来复习数学,下午用来复习408,晚上则前期安排英语卷子,后面就是政治背记和写题(晚上经常因为数学学不完被挪用时间写数学)所以我觉得大伙可以比我更早开始,比如四月五月,也不至于像我一样到最后手忙脚乱。** +而关于复习时的时间安排,我是完全按照考试时间来的,**所有的上午都是用来复习数学,下午用来复习 408,晚上则前期安排英语卷子,后面就是政治背记和写题(晚上经常因为数学学不完被挪用时间写数学)所以我觉得大伙可以比我更早开始,比如四月五月,也不至于像我一样到最后手忙脚乱。** ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210406120028.uw608tnatkw.png) @@ -106,9 +104,6 @@ 之前复习的时候还 yy 如果上岸了,该怎么来装逼,到了现在只想说,考研确实挺辛苦的,但做出选择就得有所行动,对于年级还低的兄弟,我的建议只有一个,好好学习,争取保研,考研太苦了,我这辈子不想再体验一次这样的备考,就这么多了,祝福各位心想事成,早日上岸! - - ------- +--- 厨子寄语:考研备考的过程真的很苦,深有体会,尽人事,听天命,你越渴望,机会越大。愿努力考研的你们,都能成功上岸心仪的院校。 - diff --git "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\350\275\257\344\273\266\345\210\206\344\272\253.md" "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\350\275\257\344\273\266\345\210\206\344\272\253.md" index 5d21086..d3e55d8 100644 --- "a/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\350\275\257\344\273\266\345\210\206\344\272\253.md" +++ "b/animation-simulation/\344\270\200\344\272\233\345\210\206\344\272\253/\350\275\257\344\273\266\345\210\206\344\272\253.md" @@ -2,7 +2,7 @@ PS:这期很多利器,大家不要错过哈,总有一款适合你。 ------- +--- ## **Typora** @@ -16,15 +16,13 @@ PS:这期很多利器,大家不要错过哈,总有一款适合你。 https://www.typora.io/ -另外还有 notion也是贼好用的软件,我哥们一直在用,我也早就下载了,一直放着没用,得抽空学学,真的很不错。 +另外还有 notion 也是贼好用的软件,我哥们一直在用,我也早就下载了,一直放着没用,得抽空学学,真的很不错。 还有一个国产软件 wolai,是读者推荐的,功能和 notion 差不多,也非常不错,大家可以都试一下,挑选适合自己的。 推荐指数:⭐⭐⭐⭐⭐ ------- - - +--- ## draw.io @@ -42,15 +40,13 @@ https://app.diagrams.net/ 推荐指数:⭐⭐⭐⭐⭐ ------- - - +--- ## picx 我是用的 GitHub 当的图床,所以这个神器可帮了我大忙了,是一款贼好用的图床神器, -图片外链使用 jsDelivr 进行 CDN 加速。不用下载和安装,只需要一个 Github 账号,打开 PicX 官网即可配置使用 +图片外链使用 jsDelivr 进行 CDN 加速。不用下载和安装,只需要一个 Github 账号,打开 PicX 官网即可配置使用 ![img](https://img-blog.csdnimg.cn/img_convert/f59d97a8d786309d2e822d07b66ec208.png)img @@ -64,9 +60,7 @@ GitHub 配置图床大家可以搜索一哈,跟着做就行啦,很简单的 推荐指数:⭐⭐⭐⭐⭐ ------- - - +--- ## mdnice @@ -82,9 +76,7 @@ www.mdnice.com 推荐指数:⭐⭐⭐⭐⭐ ------- - - +--- ## carbon @@ -98,9 +90,7 @@ carbon.now.sh 推荐指数:⭐⭐⭐⭐ ------- - - +--- ## **Free Video to GIF Converter** @@ -116,8 +106,5 @@ carbon.now.sh 大家可以自己下载,拜了个拜。 -链接:https://pan.baidu.com/s/1oQi1OECYagZyCjKtxPog9A -提取码:jrnb - - - +链接:https://pan.baidu.com/s/1oQi1OECYagZyCjKtxPog9A +提取码:jrnb diff --git "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode 81\344\270\215\345\256\214\345\205\250\346\234\211\345\272\217\346\237\245\346\211\276\347\233\256\346\240\207\345\205\203\347\264\240(\345\214\205\345\220\253\351\207\215\345\244\215\345\200\274) .md" "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode 81\344\270\215\345\256\214\345\205\250\346\234\211\345\272\217\346\237\245\346\211\276\347\233\256\346\240\207\345\205\203\347\264\240(\345\214\205\345\220\253\351\207\215\345\244\215\345\200\274) .md" index 48622c6..d9d4294 100644 --- "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode 81\344\270\215\345\256\214\345\205\250\346\234\211\345\272\217\346\237\245\346\211\276\347\233\256\346\240\207\345\205\203\347\264\240(\345\214\205\345\220\253\351\207\215\345\244\215\345\200\274) .md" +++ "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode 81\344\270\215\345\256\214\345\205\250\346\234\211\345\272\217\346\237\245\346\211\276\347\233\256\346\240\207\345\205\203\347\264\240(\345\214\205\345\220\253\351\207\215\345\244\215\345\200\274) .md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ## **查找目标元素(含重复元素)** @@ -14,14 +14,12 @@ ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321134336356.png) -所以我们需要对其进行改进,我们只需将重复元素去掉即可,当我们的 nums[left] == nums[mid] 时,让 left ++ 即可,比如 1,3,1,1,1此时 nums[mid] == nums[left] 则 left ++,那我们此时会不会错过目标值呢?其实并不会,只是去掉了某些重复元素,如果此时我们的目标元素是3,则我们left++,之后情况就变为了上题中的情况。 +所以我们需要对其进行改进,我们只需将重复元素去掉即可,当我们的 nums[left] == nums[mid] 时,让 left ++ 即可,比如 1,3,1,1,1 此时 nums[mid] == nums[left] 则 left ++,那我们此时会不会错过目标值呢?其实并不会,只是去掉了某些重复元素,如果此时我们的目标元素是 3,则我们 left++,之后情况就变为了上题中的情况。 #### [81. 搜索旋转排序数组 II](https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/) #### **题目描述** - - 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 ( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。 @@ -42,10 +40,12 @@ #### **题目代码** +Java Code: + ```java class Solution { public boolean search(int[] nums, int target) { - int left = 0; + int left = 0; int right = nums.length - 1; while (left <= right) { int mid = left+((right-left)>>1); @@ -61,7 +61,7 @@ class Solution { right = mid - 1; } else if (target > nums[mid] || target < nums[left]) { left = mid + 1; - } + } }else if (nums[mid] < nums[left]) { if (nums[mid] < target && target <= nums[right]) { @@ -69,11 +69,9 @@ class Solution { } else if (target < nums[mid] || target > nums[right]) { right = mid - 1; } - } + } } return false; - } + } } ``` - - diff --git "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode153\346\220\234\347\264\242\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\345\200\274.md" "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode153\346\220\234\347\264\242\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\345\200\274.md" index 7e165f4..a58cf5f 100644 --- "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode153\346\220\234\347\264\242\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\345\200\274.md" +++ "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode153\346\220\234\347\264\242\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\345\200\274.md" @@ -1,12 +1,12 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ## **寻找最小值** -这种情况也很容易处理,和咱们的leetcode33搜索旋转排序数组,题目类似,只不过一个需要搜索目标元素,一个搜索最小值,我们搜索目标元素很容易处理,但是我们搜索最小值应该怎么整呢?见下图 +这种情况也很容易处理,和咱们的 leetcode33 搜索旋转排序数组,题目类似,只不过一个需要搜索目标元素,一个搜索最小值,我们搜索目标元素很容易处理,但是我们搜索最小值应该怎么整呢?见下图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321134701939.png) @@ -22,22 +22,16 @@ - left 和 mid 在一个都在前半部分,单调递增区间内,所以需要移动 left,继续查找,left = mid + 1; -- left 在前半部分,mid在后半部分,则最小值必在 left 和 mid 之间(见下图)。则需要移动right ,right = mid,我们见上图,如果我们 right = mid - 1,则会漏掉我们的最小值,因为此时 mid 指向的可能就是我们的最小值。所以应该是 right = mid 。 - - +- left 在前半部分,mid 在后半部分,则最小值必在 left 和 mid 之间(见下图)。则需要移动 right ,right = mid,我们见上图,如果我们 right = mid - 1,则会漏掉我们的最小值,因为此时 mid 指向的可能就是我们的最小值。所以应该是 right = mid 。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321134748668.png) - - #### [153. 寻找旋转排序数组中的最小值](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) #### **题目描述** 假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] 。 - - 请找出其中最小的元素。 示例 1: @@ -70,10 +64,10 @@ class Solution { int right = nums.length - 1; while (left < right) { - + if (nums[left] < nums[right]) { return nums[left]; - } + } int mid = left + ((right - left) >> 1); if (nums[left] > nums[mid]) { right = mid; @@ -91,14 +85,14 @@ C++ Code: ```cpp class Solution { -public: +public: int findMin(vector & nums) { int left = 0; int right = nums.size() - 1; while (left < right) { if (nums[left] < nums[right]) { return nums[left]; - } + } int mid = left + ((right - left) >> 1); if (nums[left] > nums[mid]) { right = mid; @@ -110,4 +104,3 @@ public: } }; ``` - diff --git "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode33\344\270\215\345\256\214\345\205\250\346\234\211\345\272\217\346\237\245\346\211\276\347\233\256\346\240\207\345\205\203\347\264\240(\344\270\215\345\214\205\345\220\253\351\207\215\345\244\215\345\200\274).md" "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode33\344\270\215\345\256\214\345\205\250\346\234\211\345\272\217\346\237\245\346\211\276\347\233\256\346\240\207\345\205\203\347\264\240(\344\270\215\345\214\205\345\220\253\351\207\215\345\244\215\345\200\274).md" index a1055df..3dbb662 100644 --- "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode33\344\270\215\345\256\214\345\205\250\346\234\211\345\272\217\346\237\245\346\211\276\347\233\256\346\240\207\345\205\203\347\264\240(\344\270\215\345\214\205\345\220\253\351\207\215\345\244\215\345\200\274).md" +++ "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode33\344\270\215\345\256\214\345\205\250\346\234\211\345\272\217\346\237\245\346\211\276\347\233\256\346\240\207\345\205\203\347\264\240(\344\270\215\345\214\205\345\220\253\351\207\215\345\244\215\345\200\274).md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 # **不完全有序** @@ -14,9 +14,7 @@ ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/案例1.2wan88b4sdk0.png) - - -上面的新数组虽然不是完全有序,但是也可以看成是由一个完全有序的数组翻折得到的。或者可以理解成两个有序数组,且第二个数组的最大值小于第一的最小值,我们将其拼接,拼接成了一个不完全有序的数组,在这个数组中我们需要找到 target ,找到后返回其索引,如果没有找到则返回 -1; +上面的新数组虽然不是完全有序,但是也可以看成是由一个完全有序的数组翻折得到的。或者可以理解成两个有序数组,且第二个数组的最大值小于第一的最小值,我们将其拼接,拼接成了一个不完全有序的数组,在这个数组中我们需要找到 target ,找到后返回其索引,如果没有找到则返回 -1; 我们第一次看到这种题目时,可能会想到,我们只需要挨个遍历就好啦,发现后返回索引即可,这样做当然是可以滴,那么我们可不可以使用二分查找呢? @@ -24,31 +22,31 @@ 首先我们设想一下 mid 值会落到哪里,我们一起来想一下。 -是不是只有两种情况,和 left 在一个数组,同时落在 数组1 或同时在 数组2,或者不在一个数组, left 在数组1,mid 在数组2。想到这里咱们这个题目已经完成一半了。 +是不是只有两种情况,和 left 在一个数组,同时落在 数组 1 或同时在 数组 2,或者不在一个数组, left 在数组 1,mid 在数组 2。想到这里咱们这个题目已经完成一半了。 ![mid值情况](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/mid值情况.3879bq8s3xk0.png) -那么我们先来思考一下,?我们可以根据 nums[mid] 和 nums[left] 判断,是因为我们的 mid 一定是会落在 left 和 right 之间,那如果 nums[mid] >= nums[left] 时,说明他俩落在一个数组里了,如果 nums[mid] < nums[left] 时,说明他俩落在了不同的数组,此时left 在数组1 mid在数组2. +那么我们先来思考一下,?我们可以根据 nums[mid] 和 nums[left] 判断,是因为我们的 mid 一定是会落在 left 和 right 之间,那如果 nums[mid] >= nums[left] 时,说明他俩落在一个数组里了,如果 nums[mid] < nums[left] 时,说明他俩落在了不同的数组,此时 left 在数组 1 mid 在数组 2. -注:left 和 mid 落在同一数组时,不能是 left 在 数组2 ,mid 在 数组1 呢?因为咱们的 mid 是通过 left 和 right 的下标求得,所以应该在 left 和 right 中间 +注:left 和 mid 落在同一数组时,不能是 left 在 数组 2 ,mid 在 数组 1 呢?因为咱们的 mid 是通过 left 和 right 的下标求得,所以应该在 left 和 right 中间 -如果我们的 mid 和 left 在同一个数组内时?咱们的 target 会有几种情况呢?我们通过都落在 数组1 举例。 +如果我们的 mid 和 left 在同一个数组内时?咱们的 target 会有几种情况呢?我们通过都落在 数组 1 举例。 ![left左](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/left左.6kl90uroee40.png) 无非也是两种情况,用我们上面的例子来说, -1.**落在 mid 的左边**,当前例子中 情况是落在 [4,7)区间内,即 4 <= target < 7 ,也就是 target >= nums[left] && target < nums[mid],此时我们让 right = mid -1,让 left 和 right 都落到数组 1 中,下次查找我们就是在数组1中进行了,完全有序, +1.**落在 mid 的左边**,当前例子中 情况是落在 [4,7)区间内,即 4 <= target < 7 ,也就是 target >= nums[left] && target < nums[mid],此时我们让 right = mid -1,让 left 和 right 都落到数组 1 中,下次查找我们就是在数组 1 中进行了,完全有序, -2.**落在 mid 的右边**,此时例子中 target 不落在 [4,7)区间内,那就 target = 8 或 0 <= target <= 2 (此时我们的 target 均小于 nums[left]) 两种情况,也就是target > nums[mid] || target < nums[left] 此时我们让 left = mid + 1即可,也是为了慢慢将left 和 right 指针赶到一个有序数组内。 +2.**落在 mid 的右边**,此时例子中 target 不落在 [4,7)区间内,那就 target = 8 或 0 <= target <= 2 (此时我们的 target 均小于 nums[left]) 两种情况,也就是 target > nums[mid] || target < nums[left] 此时我们让 left = mid + 1 即可,也是为了慢慢将 left 和 right 指针赶到一个有序数组内。 -那我们在来思考一下当 mid 值落在 **数组2** 中时,target 会有几种情况呢?其实和上面的例子思路一致,情况相反而已。 +那我们在来思考一下当 mid 值落在 **数组 2** 中时,target 会有几种情况呢?其实和上面的例子思路一致,情况相反而已。 ![right右](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/right右.3yvrwxloi3c0.png) 1. target <= nums[right] && target > nums[mid] - > 这里和上面的对应,此时的情况就是整个落在右半部分,我们下次就可以在数组2内进行查找。 + > 这里和上面的对应,此时的情况就是整个落在右半部分,我们下次就可以在数组 2 内进行查找。 2. target > nums[right] || target < nums[mid] @@ -66,7 +64,6 @@ 请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 - 示例 1: > 输入:nums = [4,5,6,7,0,1,2], target = 0 @@ -86,12 +83,14 @@ 这个题目的解答方法,咱们在上面已经有所描述,下面我们来看一下下面这个例子的代码执行过程吧. -> 输入 nums = [4,5,6,7,8,0,1,2] target = 8 +> 输入 nums = [4,5,6,7,8,0,1,2] target = 8 下面我们看题目代码吧,如果还没有完全理解的同学,可以仔细阅读 if ,else if 里面的语句,还有注释,一定可以整透的。 #### 题目代码 +Java Code: + ```java class Solution { public int search(int[] nums, int target) { @@ -111,7 +110,7 @@ class Solution { // target 落在right和 mid 之间,有可能在数组1, 也有可能在数组2 } else if (target > nums[mid] || target < nums[left]) { left = mid + 1; - } + } //不落在同一数组的情况,left 在数组1, mid 落在 数组2 }else if (nums[mid] < nums[left]) { //有序的一段区间,target 在 mid 和 right 之间 @@ -121,7 +120,7 @@ class Solution { } else if (target < nums[mid] || target > nums[right]) { right = mid - 1; } - } + } } //没有查找到 return -1; @@ -129,5 +128,3 @@ class Solution { } } ``` - -## \ No newline at end of file diff --git "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode34\346\237\245\346\211\276\347\254\254\344\270\200\344\270\252\344\275\215\347\275\256\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.md" "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode34\346\237\245\346\211\276\347\254\254\344\270\200\344\270\252\344\275\215\347\275\256\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.md" index 32ca910..aa8d006 100644 --- "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode34\346\237\245\346\211\276\347\254\254\344\270\200\344\270\252\344\275\215\347\275\256\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.md" +++ "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode34\346\237\245\346\211\276\347\254\254\344\270\200\344\270\252\344\275\215\347\275\256\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ## 查找元素第一个位置和最后一个位置 @@ -10,8 +10,6 @@ ![二分查找变种一](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/二分查找变种一.3axfe8rq0ei0.png) - - 此时我们数组里含有多个 5 ,我们查询是否含有 5 可以很容易查到,但是我们想获取第一个 5 和 最后一个 5 的位置应该怎么实现呢?哦!我们可以使用遍历,当查询到第一个 5 时,我们设立一个指针进行定位,然后到达最后一个 5 时返回,这样我们就能求的第一个和最后一个五了?因为我们这个文章的主题就是二分查找,我们可不可以用二分查找来实现呢?当然是可以的。 #### [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/) @@ -22,7 +20,6 @@ > > 如果数组中不存在目标值 target,返回 [-1, -1]。 - 示例 1: > 输入:nums = [5,7,7,8,8,10], target = 8 @@ -53,28 +50,24 @@ }else if (nums[mid] > target) { //这里需要注意,移动右指针 right = mid - 1; - } + } ``` -我们只需在这段代码中修改即可,我们再来剖析一下这块代码,nums[mid] == target 时则返回,nums[mid] < target 时则移动左指针,在右区间进行查找, nums[mid] > target时则移动右指针,在左区间内进行查找。 +我们只需在这段代码中修改即可,我们再来剖析一下这块代码,nums[mid] == target 时则返回,nums[mid] < target 时则移动左指针,在右区间进行查找, nums[mid] > target 时则移动右指针,在左区间内进行查找。 那么我们思考一下,如果此时我们的 nums[mid] = target ,但是我们不能确定 mid 是否为该目标数的左边界,所以此时我们不可以返回下标。例如下面这种情况。![二分查找下边界](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/二分查找下边界.m9m083jempc.png) - - 此时 mid = 4 ,nums[mid] = 5,但是此时的 mid 指向的并不是第一个 5,所以我们需要继续查找 ,因为我们要找 -的是数的下边界,所以我们需要在 mid 的值的左区间继续寻找 5 ,那我们应该怎么做呢?我们只需在 +的是数的下边界,所以我们需要在 mid 的值的左区间继续寻找 5 ,那我们应该怎么做呢?我们只需在 -target <= nums[mid] 时,让 right = mid - 1即可,这样我们就可以继续在 mid 的左区间继续找 5 。是不是听着有点绕,我们通过下面这组图进行描述。 +target <= nums[mid] 时,让 right = mid - 1 即可,这样我们就可以继续在 mid 的左区间继续找 5 。是不是听着有点绕,我们通过下面这组图进行描述。 ![左边界1](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/左边界1.5o2ihokjfg80.png) ![左边界2](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/左边界2.5wazlfm298s0.png) - - -其实原理很简单,就是我们将小于和等于合并在一起处理,当 target <= nums[mid] 时,我们都移动右指针,也就是 right = mid -1,还有一个需要注意的就是,我们计算下边界时最后的返回值为 left ,当上图结束循环时,left = 3,right = 2,返回 left 刚好时我们的下边界。我们来看一下求下边界的具体执行过程。 +其实原理很简单,就是我们将小于和等于合并在一起处理,当 target <= nums[mid] 时,我们都移动右指针,也就是 right = mid -1,还有一个需要注意的就是,我们计算下边界时最后的返回值为 left ,当上图结束循环时,left = 3,right = 2,返回 left 刚好时我们的下边界。我们来看一下求下边界的具体执行过程。 **动图解析** @@ -100,13 +93,11 @@ int lowerBound(int[] nums, int target) { } ``` - - 计算上边界时算是和计算上边界时条件相反, -计算下边界时,当 target <= nums[mid] 时,right = mid -1;target > nums[mid] 时,left = mid + 1; +计算下边界时,当 target <= nums[mid] 时,right = mid -1;target > nums[mid] 时,left = mid + 1; -计算上边界时,当 target < nums[mid] 时,right = mid -1; target >= nums[mid] 时 left = mid + 1;刚好和计算下边界时条件相反,返回right。 +计算上边界时,当 target < nums[mid] 时,right = mid -1; target >= nums[mid] 时 left = mid + 1;刚好和计算下边界时条件相反,返回 right。 **计算上边界代码** @@ -118,12 +109,12 @@ int upperBound(int[] nums, int target) { int mid = left + ((right - left) >> 1); //移动左指针情况 if (target >= nums[mid]) { - left = mid + 1; + left = mid + 1; //移动右指针情况 }else if (target < nums[mid]) { right = mid - 1; } - + } return left; } @@ -131,11 +122,13 @@ int upperBound(int[] nums, int target) { #### **题目完整代码** +Java Code: + ```java class Solution { public int[] searchRange (int[] nums, int target) { int upper = upperBound(nums,target); - int low = lowerBound(nums,target); + int low = lowerBound(nums,target); //不存在情况 if (upper < low) { return new int[]{-1,-1}; @@ -163,16 +156,15 @@ class Solution { //计算上边界 int upperBound(int[] nums, int target) { int left = 0, right = nums.length - 1; - while (left <= right) { + while (left <= right) { int mid = left + ((right - left) >> 1); if (target >= nums[mid]) { - left = mid + 1; + left = mid + 1; }else if (target < nums[mid]) { right = mid - 1; - } + } } return right; } } ``` - diff --git "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode35\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.md" "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode35\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.md" index 30f4bbd..2f7c45e 100644 --- "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode35\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.md" +++ "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/leetcode35\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [35. 搜索插入位置](https://leetcode-cn.com/problems/search-insert-position/) @@ -40,6 +40,8 @@ #### 题目代码 +Java Code: + ```java class Solution { public int searchInsert(int[] nums, int target) { @@ -52,10 +54,10 @@ class Solution { //查询成功 if (target == nums[mid]) { return mid; - //右区间 + //右区间 } else if (nums[mid] < target) { - left = mid + 1; - //左区间 + left = mid + 1; + //左区间 } else if (nums[mid] > target) { right = mid - 1; } @@ -66,5 +68,4 @@ class Solution { } ``` - - +Go Code: diff --git "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\344\272\214\345\210\206\346\237\245\346\211\276\350\257\246\350\247\243.md" "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\344\272\214\345\210\206\346\237\245\346\211\276\350\257\246\350\247\243.md" index 74398a9..0a3f84d 100644 --- "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\344\272\214\345\210\206\346\237\245\346\211\276\350\257\246\350\247\243.md" +++ "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\344\272\214\345\210\206\346\237\245\346\211\276\350\257\246\350\247\243.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### 什么是二分? @@ -14,25 +14,25 @@ > > 袁厨:那是,这是我今天从咱们江边买的,之前一直去菜市场买,那里的老贵了,你猜猜我今天买的多少钱一条。 > -> 店小二:之前的鱼,30个铜板一条,今天的我猜26个铜板。 +> 店小二:之前的鱼,30 个铜板一条,今天的我猜 26 个铜板。 > > 袁厨:贵了。 > -> 店小二:还贵呀!那我猜20个铜板! +> 店小二:还贵呀!那我猜 20 个铜板! > > 袁厨:还是贵了。 > -> 店小二:15个铜板。 +> 店小二:15 个铜板。 > > 袁厨:便宜了 > -> 店小二:18个铜板 +> 店小二:18 个铜板 > > 袁厨:恭喜你猜对了 上面的例子就用到了我们的二分查找思想,如果你玩过类似的游戏,那二分查找理解起来肯定很轻松啦,下面我们一起征服二分查找吧! -# **完全有序** +# **完全有序** ## 二分查找 @@ -40,141 +40,160 @@ 通过上面二分查找的定义,我们知道了二分查找算法的作用及要求,那么该算法的具体执行过程是怎样的呢? -下面我们通过一个例子来帮助我们理解。我们需要在 nums 数组中,查询元素 8 的索引 +下面我们通过一个例子来帮助我们理解。我们需要在 nums 数组中,查询元素 8 的索引 ```java -int[ ] nums = {1,3,4,5,6,8,12,14,16}; target = 8 +int[ ] nums = {1,3,4,5,6,8,12,14,16}; target = 8 ``` > (1)我们需要定义两个指针分别指向数组的头部及尾部,这是我们在整个数组中查询的情况,当我们在数组 > > 某一区间进行查询时,可以输入数组,起始位置,终止位置进行查询。 - - ![二分查找1](https://img-blog.csdnimg.cn/img_convert/b58d55a34b32a342f652792297a1e4d7.png) - - -> (2)找出mid,该索引为 mid =(left + right)/ 2,但是这样写有可能溢出,所以我们需要改进一下写成 +> (2)找出 mid,该索引为 mid =(left + right)/ 2,但是这样写有可能溢出,所以我们需要改进一下写成 > -> mid = left +(right - left)/ 2 或者 left + ((right - left ) >> 1) 两者作用是一样的,都是为了找到两指针的中 +> mid = left +(right - left)/ 2 或者 left + ((right - left ) >> 1) 两者作用是一样的,都是为了找到两指针的中 > -> 间索引,使用位运算的速度更快。那么此时的 mid = 0 + (8-0) / 2 = 4 - - +> 间索引,使用位运算的速度更快。那么此时的 mid = 0 + (8-0) / 2 = 4 ![二分查找2](https://img-blog.csdnimg.cn/img_convert/5354d4c9ea5e5bd28a77a202b4dd3445.png) - - -> (3)此时我们的 mid = 4,nums[mid] = 6 < target,那么我们需要移动我们的 left 指针,让left = mid + 1,下次则可以在新的 left 和 right 区间内搜索目标值,下图为移动前和移动后 - - +> (3)此时我们的 mid = 4,nums[mid] = 6 < target,那么我们需要移动我们的 left 指针,让 left = mid + 1,下次则可以在新的 left 和 right 区间内搜索目标值,下图为移动前和移动后 ![](https://img-blog.csdnimg.cn/img_convert/97c584c48d6c1c06dffb94c6481f82c6.png) - - -> (4)我们需要在 left 和 right 之间计算 mid 值,mid = 5 + (8 - 5)/ 2 = 6 然后将 nums[mid] 与 target 继续比较,进而决定下次移动left 指针还是 right 指针,见下图 - - +> (4)我们需要在 left 和 right 之间计算 mid 值,mid = 5 + (8 - 5)/ 2 = 6 然后将 nums[mid] 与 target 继续比较,进而决定下次移动 left 指针还是 right 指针,见下图 ![二分查找3](https://img-blog.csdnimg.cn/img_convert/471b4093db0233e41d4875fc6b2e4359.png) - - > (5)我们发现 nums[mid] > target,则需要移动我们的 right 指针, 则 right = mid - 1;则移动过后我们的 left 和 right 会重合,这里是我们的一个重点大家需要注意一下,后面会对此做详细叙述。 - - ![二分查找4](https://img-blog.csdnimg.cn/img_convert/2145730bf3a6373f1cf60da628bf85e6.png) - - -> (6)我们需要在 left 和 right 之间继续计算 mid 值,则 mid = 5 +(5 - 5)/ 2 = 5 ,见下图,此时我们将 nums[mid] 和 target 比较,则发现两值相等,返回 mid 即可 ,如果不相等则跳出循环,返回 -1。 - - +> (6)我们需要在 left 和 right 之间继续计算 mid 值,则 mid = 5 +(5 - 5)/ 2 = 5 ,见下图,此时我们将 nums[mid] 和 target 比较,则发现两值相等,返回 mid 即可 ,如果不相等则跳出循环,返回 -1。 ![二分查找6](https://img-blog.csdnimg.cn/img_convert/0aba81887cfbc25ce9a859ba8137cd4a.png) - - 二分查找的执行过程如下 1.从已经排好序的数组或区间中,取出中间位置的元素,将其与我们的目标值进行比较,判断是否相等,如果相等 则返回。 -2.如果 nums[mid] 和 target 不相等,则对 nums[mid] 和 target 值进行比较大小,通过比较结果决定是从 mid +2.如果 nums[mid] 和 target 不相等,则对 nums[mid] 和 target 值进行比较大小,通过比较结果决定是从 mid -的左半部分还是右半部分继续搜索。如果 target > nums[mid] 则右半区间继续进行搜索,即 left = mid + 1; 若 +的左半部分还是右半部分继续搜索。如果 target > nums[mid] 则右半区间继续进行搜索,即 left = mid + 1; 若 -target < nums[mid] 则在左半区间继续进行搜索,即 right = mid -1; +target < nums[mid] 则在左半区间继续进行搜索,即 right = mid -1; **动图解析** ![二分查找2](https://img-blog.csdnimg.cn/img_convert/eb648f86b4ada5b32afc7a52e78d9953.gif) -下面我们来看一下二分查找的代码,可以认真思考一下 if 语句的条件,每个都没有简写。 +下面我们来看一下二分查找的代码,可以认真思考一下 if 语句的条件,每个都没有简写。 + +Java Code: ```java - public static int binarySearch(int[] nums,int target,int left, int right) { - //这里需要注意,循环条件 - while (left <= right) { - //这里需要注意,计算mid - int mid = left + ((right - left) >> 1); - if (nums[mid] == target) { - return mid; - }else if (nums[mid] < target) { - //这里需要注意,移动左指针 - left = mid + 1; - }else if (nums[mid] > target) { - //这里需要注意,移动右指针 - right = mid - 1; - } +public static int binarySearch(int[] nums,int target,int left, int right) { + //这里需要注意,循环条件 + while (left <= right) { + //这里需要注意,计算mid + int mid = left + ((right - left) >> 1); + if (nums[mid] == target) { + return mid; + }else if (nums[mid] < target) { + //这里需要注意,移动左指针 + left = mid + 1; + }else if (nums[mid] > target) { + //这里需要注意,移动右指针 + right = mid - 1; } - //没有找到该元素,返回 -1 - return -1; } + //没有找到该元素,返回 -1 + return -1; +} ``` - +Go Code: + +```go +func binarySearch(nums []int, target, left, right int) int { + //这里需要注意,循环条件 + for left <= right { + //这里需要注意,计算mid + mid := left + ((right - left) >> 1) + if nums[mid] == target { + return mid + } else if nums[mid] < target { + //这里需要注意,移动左指针 + left = mid + 1 + } else if nums[mid] > target { + //这里需要注意,移动右指针 + right = mid - 1 + } + } + //没有找到该元素,返回 -1 + return -1 +} +``` 二分查找的思路及代码已经理解了,那么我们来看一下实现时容易出错的地方 1.计算 mid 时 ,不能使用 (left + right )/ 2,否则有可能会导致溢出 -2.while (left < = right) { } 注意括号内为 left <= right ,而不是 left < right ,我们继续回顾刚才的例子,如果我们设置条件为 left < right 则当我们执行到最后一步时,则我们的 left 和 right 重叠时,则会跳出循环,返回 -1,区间内不存在该元素,但是不是这样的,我们的 left 和 right 此时指向的就是我们的目标元素 ,但是此时 left = right 跳出循环 +2.while (left < = right) { } 注意括号内为 left <= right ,而不是 left < right ,我们继续回顾刚才的例子,如果我们设置条件为 left < right 则当我们执行到最后一步时,则我们的 left 和 right 重叠时,则会跳出循环,返回 -1,区间内不存在该元素,但是不是这样的,我们的 left 和 right 此时指向的就是我们的目标元素 ,但是此时 left = right 跳出循环 -3. left = mid + 1,right = mid - 1 而不是 left = mid 和 right = mid。我们思考一下这种情况,见下图,当我们的target 元素为 16 时,然后我们此时 left = 7 ,right = 8,mid = left + (right - left) = 7 + (8-7) = 7,那如果设置 left = mid 的话,则会进入死循环,mid 值一直为7 。 +3. left = mid + 1,right = mid - 1 而不是 left = mid 和 right = mid。我们思考一下这种情况,见下图,当我们的 target 元素为 16 时,然后我们此时 left = 7 ,right = 8,mid = left + (right - left) = 7 + (8-7) = 7,那如果设置 left = mid 的话,则会进入死循环,mid 值一直为 7 。 ![二分查找出差](https://img-blog.csdnimg.cn/img_convert/d7ff6aba9a1e9d673ae24667823d5770.png) - - 下面我们来看一下二分查找的递归写法 +Java Code: + ```java public static int binarySearch(int[] nums,int target,int left, int right) { - - if (left <= right) { - int mid = left + ((right - left) >> 1); - if (nums[mid] == target) { - //查找成功 - return mid; - }else if (nums[mid] > target) { - //新的区间,左半区间 - return binarySearch(nums,target,left,mid-1); - }else if (nums[mid] < target) { - //新的区间,右半区间 - return binarySearch(nums,target,mid+1,right); - } + + if (left <= right) { + int mid = left + ((right - left) >> 1); + if (nums[mid] == target) { + //查找成功 + return mid; + }else if (nums[mid] > target) { + //新的区间,左半区间 + return binarySearch(nums,target,left,mid-1); + }else if (nums[mid] < target) { + //新的区间,右半区间 + return binarySearch(nums,target,mid+1,right); } - //不存在返回-1 - return -1; } + //不存在返回-1 + return -1; +} ``` - - +Go Code: + +```go +func binarySearch(nums []int, target, left, right int) int { + + if left <= right { + mid := left + ((right - left) >> 1) + if nums[mid] == target { + //查找成功 + return mid + } else if nums[mid] > target { + //新的区间,左半区间 + return binarySearch(nums, target, left, mid-1) + } else if nums[mid] < target { + //新的区间,右半区间 + return binarySearch(nums, target, mid+1, right) + } + } + //不存在返回-1 + return -1 +} +``` diff --git "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\344\272\214\347\273\264\346\225\260\347\273\204\347\232\204\344\272\214\345\210\206\346\237\245\346\211\276.md" "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\344\272\214\347\273\264\346\225\260\347\273\204\347\232\204\344\272\214\345\210\206\346\237\245\346\211\276.md" index b5a27dd..6189140 100644 --- "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\344\272\214\347\273\264\346\225\260\347\273\204\347\232\204\344\272\214\345\210\206\346\237\245\346\211\276.md" +++ "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\344\272\214\347\273\264\346\225\260\347\273\204\347\232\204\344\272\214\345\210\206\346\237\245\346\211\276.md" @@ -1,22 +1,22 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -#### [74. 搜索二维矩阵](https://leetcode-cn.com/problems/search-a-2d-matrix/)**** +#### [74. 搜索二维矩阵](https://leetcode-cn.com/problems/search-a-2d-matrix/)\*\*\*\* 下面我们来看一下另外一种变体,如何在二维矩阵里使用二分查找呢? 其实这个很简单,只要学会了二分查找,这个完全可以解决,我们先来看一个例子 -我们需要从一个二维矩阵中,搜索是否含有元素 7,我们如何使用二分查找呢?其实我们可以完全将二维矩阵想象成一个有序的一维数组,然后用二分,,比如我们的二维矩阵中,共有 9 个元素,那定义我们的 left = 0,right = 9 - 1= 8,是不是和一维数组定义相同,然后我们求我们的 mid 值, mid = left +((right - left) >> 1)此时 mid = 4 ,但是我们的二维矩阵下标最大是,nums[2,2]呀,你这求了一个 4 ,让我们怎么整呀。如果我们理解了二分查找,那么这个题目考察我们的应该是如何将一维数组的下标,变为 二维坐标。其实也很简单,咱们看哈,此时咱们的 mid = 4,咱们的二维矩阵共有 3行, 3列,那我们 mid =4,肯定在第二行,那么这个应该怎么求得呢? +我们需要从一个二维矩阵中,搜索是否含有元素 7,我们如何使用二分查找呢?其实我们可以完全将二维矩阵想象成一个有序的一维数组,然后用二分,,比如我们的二维矩阵中,共有 9 个元素,那定义我们的 left = 0,right = 9 - 1= 8,是不是和一维数组定义相同,然后我们求我们的 mid 值, mid = left +((right - left) >> 1)此时 mid = 4 ,但是我们的二维矩阵下标最大是,nums[2,2]呀,你这求了一个 4 ,让我们怎么整呀。如果我们理解了二分查找,那么这个题目考察我们的应该是如何将一维数组的下标,变为 二维坐标。其实也很简单,咱们看哈,此时咱们的 mid = 4,咱们的二维矩阵共有 3 行, 3 列,那我们 mid =4,肯定在第二行,那么这个应该怎么求得呢? -我们可以直接用 (mid/列数),即可,因为我们 mid = 4,4 /3 = 1,说明在 在第二行,那如果 mid = 7 ,7/3=2,在第三行,我们第几行知道了,那么我们如何知道第几列呢?我们可以直接根据 (mid % 列数 )来求得呀,比如我们此时 mid = 7,7%3 = 1,那么在我们一维数组索引为 7 的元素,其处于二维数组的第2列,大家看看下图是不是呀! +我们可以直接用 (mid/列数),即可,因为我们 mid = 4,4 /3 = 1,说明在 在第二行,那如果 mid = 7 ,7/3=2,在第三行,我们第几行知道了,那么我们如何知道第几列呢?我们可以直接根据 (mid % 列数 )来求得呀,比如我们此时 mid = 7,7%3 = 1,那么在我们一维数组索引为 7 的元素,其处于二维数组的第 2 列,大家看看下图是不是呀! ![二维数组](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/二维数组.63nd4jlj0v00.png) -下面我们来看一下 leetcode 74题,让我们给他整个通透 +下面我们来看一下 leetcode 74 题,让我们给他整个通透 ### 搜索二维矩阵 @@ -27,24 +27,24 @@ 每行中的整数从左到右按升序排列。 每行的第一个整数大于前一行的最后一个整数。 -示例1 +示例 1 > 输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 3 > 输出:true -示例2 +示例 2 > 输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 13 > 输出:false -示例3 +示例 3 > 输入:matrix = [], target = 0 > 输出:false #### 题目解析 -在上面我们已经解释了如何在二维矩阵中进行搜索,这里我们再对其进行一个总结,就是我们凭空想象一个一维数组,这个数组是有二维数组一层一层拼接来的,也是完全有序,然后我们定义两个指针一个指向一维数组头部,一个指向尾部,我们求得 mid 值然后将 mid 变成二维坐标,然后和 target 进行比较,如果大于则移动 left ,如果小于则移动 right 。 +在上面我们已经解释了如何在二维矩阵中进行搜索,这里我们再对其进行一个总结,就是我们凭空想象一个一维数组,这个数组是有二维数组一层一层拼接来的,也是完全有序,然后我们定义两个指针一个指向一维数组头部,一个指向尾部,我们求得 mid 值然后将 mid 变成二维坐标,然后和 target 进行比较,如果大于则移动 left ,如果小于则移动 right 。 动图解析 @@ -52,10 +52,12 @@ #### 题目代码 +Java Code: + ```java class Solution { public boolean searchMatrix(int[][] matrix, int target) { - + if (matrix.length == 0) { return false; } @@ -83,4 +85,3 @@ class Solution { } } ``` - diff --git "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\346\211\276\345\207\272\347\254\254\344\270\200\344\270\252\345\244\247\344\272\216\346\210\226\345\260\217\344\272\216\347\233\256\346\240\207\347\232\204\347\264\242\345\274\225.md" "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\346\211\276\345\207\272\347\254\254\344\270\200\344\270\252\345\244\247\344\272\216\346\210\226\345\260\217\344\272\216\347\233\256\346\240\207\347\232\204\347\264\242\345\274\225.md" index c58d6cc..388e044 100644 --- "a/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\346\211\276\345\207\272\347\254\254\344\270\200\344\270\252\345\244\247\344\272\216\346\210\226\345\260\217\344\272\216\347\233\256\346\240\207\347\232\204\347\264\242\345\274\225.md" +++ "b/animation-simulation/\344\272\214\345\210\206\346\237\245\346\211\276\345\217\212\345\205\266\345\217\230\347\247\215/\346\211\276\345\207\272\347\254\254\344\270\200\344\270\252\345\244\247\344\272\216\346\210\226\345\260\217\344\272\216\347\233\256\346\240\207\347\232\204\347\264\242\345\274\225.md" @@ -1,19 +1,17 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ## 找出第一个大于目标元素的索引 -我们在上面的变种中,描述了如何找出目标元素在数组中的上下边界,然后我们下面来看一个新的变种,如何从数组或区间中找出第一个大于或最后一个小于目标元素的数的索引,例 nums = {1,3,5,5,6,6,8,9,11} 我们希望找出第一个大于 5的元素的索引,那我们需要返回 4 ,因为 5 的后面为 6,第一个 6 的索引为 4,如果希望找出最后一个小于 6 的元素,那我们则会返回 3 ,因为 6 的前面为 5 最后一个 5 的索引为 3。好啦题目我们已经了解,下面我们先来看一下如何在数组或区间中找出第一个大于目标元素的数吧。 +我们在上面的变种中,描述了如何找出目标元素在数组中的上下边界,然后我们下面来看一个新的变种,如何从数组或区间中找出第一个大于或最后一个小于目标元素的数的索引,例 nums = {1,3,5,5,6,6,8,9,11} 我们希望找出第一个大于 5 的元素的索引,那我们需要返回 4 ,因为 5 的后面为 6,第一个 6 的索引为 4,如果希望找出最后一个小于 6 的元素,那我们则会返回 3 ,因为 6 的前面为 5 最后一个 5 的索引为 3。好啦题目我们已经了解,下面我们先来看一下如何在数组或区间中找出第一个大于目标元素的数吧。 找出第一个大于目标元素的数,大概有以下几种情况 ![模糊边界情况](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/模糊边界情况.4k45gb16fhy0.png) - - 1.数组包含目标元素,找出在他后面的第一个元素 2.目标元素不在数组中,数组内的部分元素大于它,此时我们需要返回第一个大于他的元素 @@ -24,77 +22,128 @@ 既然我们已经分析完所有情况,那么这个题目对咱们就没有难度了,下面我们描述一下案例的执行过程 -> nums = {1,3,5,5,6,6,8,9,11} target = 7 +> nums = {1,3,5,5,6,6,8,9,11} target = 7 上面的例子中,我们需要找出第一个大于 7 的数,那么我们的程序是如何执行的呢? ![二分查找模糊边界目标值](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/二分查找模糊边界目标值.4d27nsldwcy0.png) -上面的例子我们已经弄懂了,那么我们看一下,当 target = 0时,程序应该怎么执行呢? +上面的例子我们已经弄懂了,那么我们看一下,当 target = 0 时,程序应该怎么执行呢? ![模糊边界目标0](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/模糊边界目标0.1n579314c8ao.png) - - OK!我们到这一步就能把这个变种给整的明明白白的了,下面我们看一哈程序代码吧,也是非常简单的。 - +Java Code: ```java public static int lowBoundnum(int[] nums,int target,int left, int right) { - while (left <= right) { - //求中间值 - int mid = left + ((right - left) >> 1); - //大于目标值的情况 - if (nums[mid] > target) { - //返回 mid - if (mid == 0 || nums[mid-1] <= target) { - return mid; - } - else{ - right = mid -1; - } - - } else if (nums[mid] <= target){ - left = mid + 1; + while (left <= right) { + //求中间值 + int mid = left + ((right - left) >> 1); + //大于目标值的情况 + if (nums[mid] > target) { + //返回 mid + if (mid == 0 || nums[mid-1] <= target) { + return mid; + } + else{ + right = mid -1; + } + + } else if (nums[mid] <= target){ + left = mid + 1; + } + } + //所有元素都小于目标元素 + return -1; +} +``` + +Go Code: + +```go +func lowBoundnum(nums []int, target, left, right int) int { + + for (left <= right) { + //求中间值 + mid := left + ((right - left) >> 1); + //大于目标值的情况 + if (nums[mid] > target) { + //返回 mid + if (mid == 0 || nums[mid-1] <= target) { + return mid + }else{ + right = mid -1 } + + } else if (nums[mid] <= target){ + left = mid + 1 } - //所有元素都小于目标元素 - return -1; } + //所有元素都小于目标元素 + return -1 +} ``` ## **找出最后一个小于目标元素的索引** 通过上面的例子我们应该可以完全理解了那个变种,下面我们继续来看以下这种情况,那就是如何找到最后一个小于目标数的元素。还是上面那个例子 -> nums = {1,3,5,5,6,6,8,9,11} target = 7 +> nums = {1,3,5,5,6,6,8,9,11} target = 7 查找最后一个小于目标数的元素,比如我们的目标数为 7 ,此时他前面的数为 6,最后一个 6 的索引为 5,此时我们返回 5 即可,如果目标数元素为 12,那么我们最后一个元素为 11,仍小于目标数,那么我们此时返回 8,即可。这个变种其实算是上面变种的相反情况,上面的会了,这个也完全可以搞定了,下面我们看一下代码吧。 +Java Code: + ```java public static int upperBoundnum(int[] nums,int target,int left, int right) { - while (left <= right) { - - int mid = left + ((right - left) >> 1); - //小于目标值 - if (nums[mid] < target) { - //看看是不是当前区间的最后一位,如果当前小于,后面一位大于,返回当前值即可 - if (mid == right || nums[mid+1] >= target) { - return mid; - } - else{ - left = mid + 1; - } - - } else if (nums[mid] >= target){ - right = mid - 1; + while (left <= right) { + + int mid = left + ((right - left) >> 1); + //小于目标值 + if (nums[mid] < target) { + //看看是不是当前区间的最后一位,如果当前小于,后面一位大于,返回当前值即可 + if (mid == right || nums[mid+1] >= target) { + return mid; + } + else{ + left = mid + 1; } + + } else if (nums[mid] >= target){ + right = mid - 1; } - //没有查询到的情况 - return -1; } + //没有查询到的情况 + return -1; +} ``` +Go Code: + +```go +func upperBoundnum(nums []int, target, left, right int) int { + + for left <= right { + + mid := left + ((right - left) >> 1) + //小于目标值 + if nums[mid] < target { + //看看是不是当前区间的最后一位,如果当前小于,后面一位大于,返回当前值即可 + if mid == right || nums[mid+1] >= target { + return mid + } else { + left = mid + 1 + } + + } else if nums[mid] >= target { + right = mid - 1 + } + } + //没有查询到的情况 + return -1 +} +``` diff --git "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\344\270\255\345\272\217\351\201\215\345\216\206\357\274\210Morris\357\274\211.md" "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\344\270\255\345\272\217\351\201\215\345\216\206\357\274\210Morris\357\274\211.md" index 3c6ff79..97b90e2 100644 --- "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\344\270\255\345\272\217\351\201\215\345\216\206\357\274\210Morris\357\274\211.md" +++ "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\344\270\255\345\272\217\351\201\215\345\216\206\357\274\210Morris\357\274\211.md" @@ -33,7 +33,7 @@ class Solution { //对应 right 指针存在的情况,则去掉 right 指针 p2.right = null; //标注2 - } else { + } else { list.add(p1.val); } //移动 p1 @@ -58,14 +58,12 @@ class Solution { 我们在前序遍历时,遇到 `p2.right == p1`的情况时,则会执行 `p2.right == null` 并让 `p1 = p1.right`,这样做是因为,我们此时 p1 指向的值已经遍历完毕,为了防止重复遍历。 -但是呢,在我们的中序 Morris 中我们遇到`p2.right == p1`此时 p1 还未遍历,所以我们需要在上面两条代码之间添加一行代码`list.add(p1.val);` +但是呢,在我们的中序 Morris 中我们遇到`p2.right == p1`此时 p1 还未遍历,所以我们需要在上面两条代码之间添加一行代码`list.add(p1.val);` 好啦,到这里我们就基本上就搞定了中序遍历的 Morris 方法,下面我们通过动画来加深一下印象吧,当然我也会把前序遍历的动画放在这里,大家可以看一下哪里有所不同。 ![二叉树中序](https://img-blog.csdnimg.cn/20210622155624486.gif) - - ![二叉树前序Morris](https://img-blog.csdnimg.cn/20210622155959185.gif) **参考代码:** @@ -89,7 +87,7 @@ class Solution { if (p2.right == null) { p2.right = p1; p1 = p1.left; - continue; + continue; } else { p2.right = null; } @@ -102,3 +100,34 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + func inorderTraversal(_ root: TreeNode?) -> [Int] { + var list:[Int] = [] + guard root != nil else { + return list + } + var p1 = root, p2: TreeNode? + while p1 != nil { + p2 = p1!.left + if p2 != nil { + while p2!.right != nil && p2!.right !== p1 { + p2 = p2!.right + } + if p2!.right == nil { + p2!.right = p1 + p1 = p1!.left + continue + } else { + p2!.right = nil + } + } + list.append(p1!.val) + p1 = p1!.right + } + return list + } +} +``` diff --git "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\344\270\255\345\272\217\351\201\215\345\216\206\357\274\210\350\277\255\344\273\243\357\274\211.md" "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\344\270\255\345\272\217\351\201\215\345\216\206\357\274\210\350\277\255\344\273\243\357\274\211.md" index adbec99..fbfb0eb 100644 --- "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\344\270\255\345\272\217\351\201\215\345\216\206\357\274\210\350\277\255\344\273\243\357\274\211.md" +++ "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\344\270\255\345\272\217\351\201\215\345\216\206\357\274\210\350\277\255\344\273\243\357\274\211.md" @@ -2,7 +2,7 @@ > 注:数据结构掌握不熟练的同学,阅读该文章之前,可以先阅读这两篇文章,二叉树基础,前序遍历另外喜欢电脑阅读的同学,可以在小屋后台回复仓库地址,获取 Github 链接进行阅读。 -中序遍历的顺序是, `对于树中的某节点,先遍历该节点的左子树, 然后再遍历该节点, 最后遍历其右子树`。老规矩,上动画,我们先通过动画回忆一下二叉树的中序遍历。 +中序遍历的顺序是, `对于树中的某节点,先遍历该节点的左子树, 然后再遍历该节点, 最后遍历其右子树`。老规矩,上动画,我们先通过动画回忆一下二叉树的中序遍历。 ![中序遍历](https://cdn.jsdelivr.net/gh/tan45du/test@master/photo/中序遍历.7gct7ztck8k0.gif) @@ -34,7 +34,7 @@ class Solution { TreeNode cur = new TreeNode(-1); cur = root; Stack stack = new Stack<>(); - while (!stack.isEmpty() || cur != null) { + while (!stack.isEmpty() || cur != null) { //找到当前应该遍历的那个节点 while (cur != null) { stack.push(cur); @@ -47,9 +47,61 @@ class Solution { cur = temp.right; } return arr; - } + } } ``` -### +Swift Code: +```swift +class Solution { + func inorderTraversal(_ root: TreeNode?) -> [Int] { + var arr:[Int] = [] + var cur = root + var stack:[TreeNode] = [] + + while !stack.isEmpty || cur != nil { + //找到当前应该遍历的那个节点 + while cur != nil { + stack.append(cur!) + cur = cur!.left + } + //此时指针指向空,也就是没有左子节点,则开始执行出栈操作 + if let temp = stack.popLast() { + arr.append(temp.val) + //指向右子节点 + cur = temp.right + } + } + return arr + } +} +``` + +Go Code: + +```go +func inorderTraversal(root *TreeNode) []int { + res := []int{} + if root == nil { + return res + } + stk := []*TreeNode{} + cur := root + for len(stk) != 0 || cur != nil { + // 找到当前应该遍历的那个节点,并且把左子节点都入栈 + for cur != nil { + stk = append(stk, cur) + cur = cur.Left + } + // 没有左子节点,则开始执行出栈操作 + temp := stk[len(stk) - 1] + stk = stk[: len(stk) - 1] + res = append(res, temp.Val) + cur = temp.Right + } + return res +} +``` + +### diff --git "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\345\237\272\347\241\200.md" "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\345\237\272\347\241\200.md" index 17fca26..e7cbc7a 100644 --- "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\345\237\272\347\241\200.md" +++ "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\345\237\272\347\241\200.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 这假期咋就唰的一下就没啦,昨天还跟放假第一天似的,今天就开始上班了。 @@ -28,8 +28,6 @@ PS:本篇文章内容较基础,对于没有学过数据结构的同学会有 ![image](https://cdn.jsdelivr.net/gh/tan45du/test@master/image.1ein9cz4oips.png) - - > 注:可能有的同学不喜欢手机阅读,所以将这篇同步在了我的仓库,大家可以去 Github 进行阅读,点击文章最下方的阅读原文即可 ## 树 @@ -51,7 +49,7 @@ PS:本篇文章内容较基础,对于没有学过数据结构的同学会有 有且仅有一个特定的节点称为根节点,也就是上图中的`橙色节点`。 -当节点数目大于 1 时,除根节点以外的节点,可分为 m 个`互不相交`的有限集 T1,T2........Tm。 +当节点数目大于 1 时,除根节点以外的节点,可分为 m 个`互不相交`的有限集 T1,T2........Tm。 例如上图中,我们将根节点以外的节点,分为了 T1 (2,3,4,5,6,7),T2(8,9)两个有限集。 @@ -59,13 +57,13 @@ PS:本篇文章内容较基础,对于没有学过数据结构的同学会有 我们拆解之后发现,我们上图中的例子符合树的要求,另外不知道大家有没有注意到这个地方。 -除根节点以外的节点,可分为 m 个`互不相交`的有限集。 +除根节点以外的节点,可分为 m 个`互不相交`的有限集。 那么这个互不相交又是什么含义呢?见下图。 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/幻灯片1.3wt8kt6ewj20.PNG) -我们将 (A) , (B) , (C) , (D) 代入上方定义中发现,(A) , (B) 符合树的定义,(C), (D) 不符合,这是因为 (C) , (D) 它们都有相交的子树。 +我们将 (A) , (B) , (C) , (D) 代入上方定义中发现,(A) , (B) 符合树的定义,(C), (D) 不符合,这是因为 (C) , (D) 它们都有相交的子树。 好啦,到这里我们知道如何辨别树啦,下面我们通过下面两张图再来深入了解一下树。 @@ -73,10 +71,6 @@ PS:本篇文章内容较基础,对于没有学过数据结构的同学会有 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/幻灯片2.4gvv5tql9cw0.PNG) - - - - ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/幻灯片3.17o6v5lqd9xc.PNG) 这里节点的高度和深度可能容易记混,我们代入到现实即可。 @@ -103,9 +97,7 @@ PS:本篇文章内容较基础,对于没有学过数据结构的同学会有 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/二叉树举例.1mavhkdbs8xs.png) - - -上图共为 5 种不同的二叉树,在二叉树的定义中提到,二叉树的左子树和右子树是有顺序的,所以 B,C 是两个不同的二叉树,故上图为 5 种不同的二叉树。 +上图共为 5 种不同的二叉树,在二叉树的定义中提到,二叉树的左子树和右子树是有顺序的,所以 B,C 是两个不同的二叉树,故上图为 5 种不同的二叉树。 ## 特殊的二叉树 @@ -113,7 +105,7 @@ PS:本篇文章内容较基础,对于没有学过数据结构的同学会有 ### 满二叉树 -满二叉树:在一棵二叉树中,`所有分支节点都存在左子树和右子树`,并且`所有的叶子都在同一层`,这种树我们称之为完全二叉树.见下图 +满二叉树:在一棵二叉树中,`所有分支节点都存在左子树和右子树`,并且`所有的叶子都在同一层`,这种树我们称之为满二叉树.见下图 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/image.2k1tlbtywzu0.png) @@ -139,7 +131,7 @@ PS:本篇文章内容较基础,对于没有学过数据结构的同学会有 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/image.6u1n2j3jmu80.png) -另外还有 一些二叉树的性质, 比如第 i 层至多有多少节点,通过叶子节点求度为 2 的节点, 通过节点树求二叉树的深度等, 这些是考研常考的知识, 就不在这里进行赘述,需要的同学可以看一下王道或者天勤的数据结构, 上面描述的很具体, 并附有证明过程. +另外还有 一些二叉树的性质, 比如第 i 层至多有多少节点,通过叶子节点求度为 2 的节点, 通过节点树求二叉树的深度等, 这些是考研常考的知识, 就不在这里进行赘述,需要的同学可以看一下王道或者天勤的数据结构, 上面描述的很具体, 并附有证明过程. 好啦,我们已经了解了二叉树,那么二叉树如何存储呢? @@ -159,13 +151,13 @@ PS:本篇文章内容较基础,对于没有学过数据结构的同学会有 我们发现其中的关系了吗? -数组中,某节点(非叶子节点)的下标为 i , 那么其`左子节点下标为 2*i `(这里可以直接通过相乘得到左孩子, 也就是为什么空出第一个位置, 如果从 0 开始存,则需要 2*i+1 才行), 右子节点为 2*i+1,其父节点为 i/2 。既然我们完全可以根据索引找到某节点的 `左子节点` 和` 右子节点`,那么我们用数组存储是完全没有问题的。 +数组中,某节点(非叶子节点)的下标为 i , 那么其`左子节点下标为 2*i `(这里可以直接通过相乘得到左孩子, 也就是为什么空出第一个位置, 如果从 0 开始存,则需要 2*i+1 才行), 右子节点为 2*i+1,其父节点为 i/2 。既然我们完全可以根据索引找到某节点的 `左子节点` 和` 右子节点`,那么我们用数组存储是完全没有问题的。 但是,我们再考虑一下这种情景,如果我们用数组存储`斜树`时会出现什么情况? ![](https://cdn.jsdelivr.net/gh/tan45du/test@master/image.780as9g3ofs0.png) -通过 2*i 进行存储左子节点的话,如果遇到斜树时,则会浪费很多的存储空间,这样显然是不合适的, +通过 2\*i 进行存储左子节点的话,如果遇到斜树时,则会浪费很多的存储空间,这样显然是不合适的, 所以说当存储完全二叉树时,我们用数组存储,无疑是最省内存的,但是存储斜树时,则就不太合适。 @@ -198,7 +190,7 @@ public class BinaryTree { } ``` -另外我们在刷题的时候, 可以`自己实现一下数据结构`, 加深我们的理解, 提升基本功, 而且面试考的也越来越多. +另外我们在刷题的时候, 可以`自己实现一下数据结构`, 加深我们的理解, 提升基本功, 而且面试考的也越来越多. 好啦,下面我们说一下树的遍历, @@ -216,12 +208,8 @@ public class BinaryTree { 只看文字有点生硬, 下面我们直接看动画吧 - - ![前序遍历](https://img-blog.csdnimg.cn/20210504155755565.gif) - - **测试题目: leetcode 144. 二叉树的前序遍历** **代码实现(递归版)** @@ -245,18 +233,16 @@ class Solution { } ``` -时间复杂度 : O(n) 空间复杂度 : O(n) 为递归过程中栈的开销,平均为 O(logn),但是当二叉树为斜树时则为 O(n) +时间复杂度 : O(n) 空间复杂度 : O(n) 为递归过程中栈的开销,平均为 O(logn),但是当二叉树为斜树时则为 O(n) 为了控制文章篇幅, 二叉树的迭代遍历形式, 会在下篇文章进行介绍。 ### 中序遍历 -中序遍历的顺序是, `对于树中的某节点,先遍历该节点的左子树, 然后再遍历该节点, 最后遍历其右子树` +中序遍历的顺序是, `对于树中的某节点,先遍历该节点的左子树, 然后再遍历该节点, 最后遍历其右子树` 继续看动画吧, 如果有些遗忘或者刚开始学数据结构的同学可以自己模拟一下执行步骤. - - ![中序遍历](https://cdn.jsdelivr.net/gh/tan45du/test@master/photo/中序遍历.7gct7ztck8k0.gif) **测试题目: leetcode 94 题 二叉树的中序遍历** @@ -266,7 +252,7 @@ class Solution { ```java class Solution { public List inorderTraversal(TreeNode root) { - + List res = new ArrayList<>(); inorder(root, res); return res; @@ -284,7 +270,7 @@ class Solution { } ``` -时间复杂度 : O(n) 空间复杂度 : O(n) +时间复杂度 : O(n) 空间复杂度 : O(n) ### 后序遍历 @@ -317,7 +303,7 @@ class Solution { } ``` -时间复杂度 : O(n) 空间复杂度 : O(n) +时间复杂度 : O(n) 空间复杂度 : O(n) ### 层序遍历 @@ -331,22 +317,20 @@ class Solution { 我们可以利用队列先进先出的特性,使用队列来帮助我们完成层序遍历, 具体操作如下 -让二叉树的每一层入队, 然后再依次执行出队操作, +让二叉树的每一层入队, 然后再依次执行出队操作, -对`该层节点执行出队操作时, 需要将该节点的左孩子节点和右孩子节点进行入队操作`, +对`该层节点执行出队操作时, 需要将该节点的左孩子节点和右孩子节点进行入队操作`, -这样当该层的所有节点出队结束后, 下一层也就入队完毕, +这样当该层的所有节点出队结束后, 下一层也就入队完毕, - 不过我们需要考虑的就是, 我们`需要通过一个变量来保存每一层节点的数量`. +不过我们需要考虑的就是, 我们`需要通过一个变量来保存每一层节点的数量`. -这样做是为了防止, 一直执行出队操作, 使输出不能分层 +这样做是为了防止, 一直执行出队操作, 使输出不能分层 -好啦,下面我们直接看动画吧, +好啦,下面我们直接看动画吧, ![](https://img-blog.csdnimg.cn/20210504155603953.gif) - - **测试题目: leetcode 102 二叉树的层序遍历** Java Code: @@ -354,12 +338,12 @@ Java Code: ```java class Solution { public List> levelOrder(TreeNode root) { - + List> res = new ArrayList<>(); if (root == null) { return res; - } - //入队 root 节点,也就是第一层 + } + //入队 root 节点,也就是第一层 Queue queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { @@ -386,7 +370,7 @@ class Solution { public: vector> levelOrder(TreeNode* root) { vector> res; - if (!root) return res; + if (!root) return res; queue q; q.push(root); while (!q.empty()) { @@ -406,6 +390,70 @@ public: }; ``` +Swift Code: + +```swift +class Solution { + func levelOrder(_ root: TreeNode?) -> [[Int]] { + var res:[[Int]] = [] + guard root != nil else { + return res + } + var queue:[TreeNode?] = [] + queue.append(root!) + + while !queue.isEmpty { + let size = queue.count + var list:[Int] = [] + + for i in 0.. [Int] { + var list:[Int] = [] + guard root != nil else { + return list + } + var p1 = root, p2: TreeNode? + while p1 != nil { + p2 = p1!.left + if p2 != nil { + //找到左子树的最右叶子节点 + while p2!.right != nil && p2!.right !== p1 { + p2 = p2!.right + } + //添加 right 指针,对应 right 指针为 null 的情况 + if p2!.right == nil { + list.append(p1!.val) + p2!.right = p1 + p1 = p1!.left + continue + } + //对应 right 指针存在的情况,则去掉 right 指针 + p2!.right = nil + } else { + list.append(p1!.val) + } + //移动 p1 + p1 = p1!.right + } + return list + } +} +``` + +好啦,今天就看到这里吧,咱们下期见! diff --git "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206(\346\240\210).md" "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206(\346\240\210).md" index e81749b..1675589 100644 --- "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206(\346\240\210).md" +++ "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206(\346\240\210).md" @@ -38,9 +38,9 @@ 看到这里你已经能够自己编写出代码了,不信你去试试。 -时间复杂度:O(n) 需要对所有节点遍历一次 +时间复杂度:O(n) 需要对所有节点遍历一次 -空间复杂度:O(n) 栈的开销,平均为 O(logn) 最快情况,即斜二叉树时为 O(n) +空间复杂度:O(n) 栈的开销,平均为 O(logn) 最快情况,即斜二叉树时为 O(n) **参考代码** @@ -49,10 +49,10 @@ class Solution { public List preorderTraversal(TreeNode root) { List list = new ArrayList<>(); Stack stack = new Stack<>(); - if (root == null) return list; + if (root == null) return list; stack.push(root); while (!stack.isEmpty()) { - TreeNode temp = stack.pop(); + TreeNode temp = stack.pop(); if (temp.right != null) { stack.push(temp.right); } @@ -67,3 +67,55 @@ class Solution { } ``` +Swift Code: + +```swift +class Solution { + + func preorderTraversal(_ root: TreeNode?) -> [Int] { + var list:[Int] = [] + var stack:[TreeNode] = [] + + guard root != nil else { + return list + } + stack.append(root!) + while !stack.isEmpty { + let temp = stack.popLast() + if let right = temp?.right { + stack.append(right) + } + if let left = temp?.left { + stack.append(left) + } + //这里也可以放到前面 + list.append((temp?.val)!) + } + return list + } +} +``` + +Go Code: + +```go +func preorderTraversal(root *TreeNode) []int { + res := []int{} + if root == nil { + return res + } + stk := []*TreeNode{root} + for len(stk) != 0 { + temp := stk[len(stk) - 1] + stk = stk[: len(stk) - 1] + if temp.Right != nil { + stk = append(stk, temp.Right) + } + if temp.Left != nil { + stk = append(stk, temp.Left) + } + res = append(res, temp.Val) + } + return res +} +``` diff --git "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\347\273\255\351\201\215\345\216\206 (\350\277\255\344\273\243).md" "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\347\273\255\351\201\215\345\216\206 (\350\277\255\344\273\243).md" index f9b4265..a7197a4 100644 --- "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\347\273\255\351\201\215\345\216\206 (\350\277\255\344\273\243).md" +++ "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\347\273\255\351\201\215\345\216\206 (\350\277\255\344\273\243).md" @@ -12,7 +12,7 @@ 我们知道后序遍历的顺序是,` 对于树中的某节点, 先遍历该节点的左子树, 再遍历其右子树, 最后遍历该节点`。 -那么我们如何利用栈来解决呢? +那么我们如何利用栈来解决呢? 我们直接来看动画,看动画之前,但是我们`需要带着问题看动画`,问题搞懂之后也就搞定了后序遍历。 @@ -34,7 +34,7 @@ 2.为什么有的节点出栈后又入栈了呢? -> 出栈又入栈的原因是,我们发现 cur 节点的 right 不为 null ,并且 cur.right 也没有被访问过。因为 `cur.right != preNode `,所以当前我们还不能够遍历该节点,应该先遍历其右子树中的节点。 +> 出栈又入栈的原因是,我们发现 cur 节点的 right 不为 null ,并且 cur.right 也没有被访问过。因为 `cur.right != preNode `,所以当前我们还不能够遍历该节点,应该先遍历其右子树中的节点。 > > 所以我们将其入栈后,然后`cur = cur.right` @@ -71,11 +71,71 @@ class Solution { } ``` -当然也可以修改下代码逻辑将 `cur = stack.pop()` 改成 `cur = stack.peek()`,下面再修改一两行代码也可以实现,这里这样写是方便动画模拟,大家可以随意发挥。 +Swift Code: + +```swift +class Solution { + func postorderTraversal(_ root: TreeNode?) -> [Int] { + var list:[Int] = [] + var stack:[TreeNode] = [] + var cur = root, preNode: TreeNode? + while !stack.isEmpty || cur != nil { + //和之前写的中序一致 + while cur != nil { + stack.append(cur!) + cur = cur!.left + } + //1.出栈,可以想一下,这一步的原因。 + cur = stack.popLast() + //2.if 里的判断语句有什么含义? + if cur!.right === nil || cur!.right === preNode { + list.append(cur!.val) + //更新下 preNode,也就是定位住上一个访问节点。 + preNode = cur + cur = nil + } else { + //3.再次压入栈,和上面那条 1 的关系? + stack.append(cur!) + cur = cur!.right + } + } + return list + } +} +``` -时间复杂度 O(n), 空间复杂度O(n) +Go Code: -这里二叉树的三种迭代方式到这里就结束啦,大家可以进行归纳总结,三种遍历方式大同小异,建议各位,掌握之后,自己手撕一下,从搭建二叉树开始。 +```go +func postorderTraversal(root *TreeNode) []int { + res := []int{} + if root == nil { + return res + } + stk := []*TreeNode{} + cur := root + var pre *TreeNode + for len(stk) != 0 || cur != nil { + for cur != nil { + stk = append(stk, cur) + cur = cur.Left + } + // 这里符合本文最后的说法,使用先获取栈顶元素但是不弹出,根据栈顶元素的情况进行响应的处理。 + temp := stk[len(stk) - 1] + if temp.Right == nil || temp.Right == pre { + stk = stk[: len(stk) - 1] + res = append(res, temp.Val) + pre = temp + } else { + cur = temp.Right + } + } + return res +} +``` +当然也可以修改下代码逻辑将 `cur = stack.pop()` 改成 `cur = stack.peek()`,下面再修改一两行代码也可以实现,这里这样写是方便动画模拟,大家可以随意发挥。 +时间复杂度 O(n), 空间复杂度 O(n) +这里二叉树的三种迭代方式到这里就结束啦,大家可以进行归纳总结,三种遍历方式大同小异,建议各位,掌握之后,自己手撕一下,从搭建二叉树开始。 diff --git "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\347\273\255\351\201\215\345\216\206\357\274\210Morris\357\274\211.md" "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\347\273\255\351\201\215\345\216\206\357\274\210Morris\357\274\211.md" index 4cd9ce3..b2fd849 100644 --- "a/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\347\273\255\351\201\215\345\216\206\357\274\210Morris\357\274\211.md" +++ "b/animation-simulation/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\347\273\255\351\201\215\345\216\206\357\274\210Morris\357\274\211.md" @@ -14,7 +14,7 @@ ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210622142148928.png) -由上图可知,仅仅有三处不同,后序遍历里少了 `list.add()`,多了一个函数` postMorris() ` ,那后序遍历的 list.add() 肯定是在 postMorris 函数中的。所以我们搞懂了 postMorris 函数,也就搞懂了后序遍历的 Morris 方法(默认大家看了之前的文章,没有看过的同学,可以点击文首的链接) +由上图可知,仅仅有三处不同,后序遍历里少了 `list.add()`,多了一个函数`postMorris()` ,那后序遍历的 list.add() 肯定是在 postMorris 函数中的。所以我们搞懂了 postMorris 函数,也就搞懂了后序遍历的 Morris 方法(默认大家看了之前的文章,没有看过的同学,可以点击文首的链接) 下面我们一起来剖析下 postMorris 函数.代码如下 @@ -82,7 +82,7 @@ class Solution { p2.right = null; postMorris(p1.left); } - } + } p1 = p1.right; } //以根节点为起点的链表 @@ -113,14 +113,67 @@ class Solution { return pre; } -} +} ``` -时间复杂度 O(n)空间复杂度 O(1) +Swift Code: -总结:后序遍历比起前序和中序稍微复杂了一些,所以我们解题的时候,需要好好注意一下,迭代法的核心是利用一个指针来定位我们上一个遍历的节点,Morris 的核心是,将某节点的右子节点,看成是一条链表,进行反向遍历。 +```swift +class Solution { + var list:[Int] = [] + func postorderTraversal(_ root: TreeNode?) -> [Int] { + guard root != nil else { + return list + } + var p1 = root, p2: TreeNode? + while p1 != nil { + p2 = p1!.left + if p2 != nil { + while p2!.right != nil && p2!.right !== p1 { + p2 = p2!.right + } + if p2!.right == nil { + p2!.right = p1 + p1 = p1!.left + continue + } else { + p2!.right = nil + postMorris(p1!.left) + } + } + p1 = p1!.right + } + //以根节点为起点的链表 + postMorris(root!) + return list + } -好啦,今天就唠到这吧,拜了个拜。 + func postMorris(_ root: TreeNode?) { + let reverseNode = reverseList(root) + //从后往前遍历 + var cur = reverseNode + while cur != nil { + list.append(cur!.val) + cur = cur!.right + } + reverseList(reverseNode) + } + func reverseList(_ head: TreeNode?) -> TreeNode? { + var cur = head, pre: TreeNode? + while cur != nil { + let next = cur?.right + cur?.right = pre + pre = cur + cur = next + } + return pre + } +} +``` +时间复杂度 O(n)空间复杂度 O(1) + +总结:后序遍历比起前序和中序稍微复杂了一些,所以我们解题的时候,需要好好注意一下,迭代法的核心是利用一个指针来定位我们上一个遍历的节点,Morris 的核心是,将某节点的右子节点,看成是一条链表,进行反向遍历。 +好啦,今天就唠到这吧,拜了个拜。 diff --git "a/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/.DS_Store" "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/.DS_Store" new file mode 100644 index 0000000..0ebafba Binary files /dev/null and "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/.DS_Store" differ diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode148\351\223\276\350\241\250\346\216\222\345\272\217.md" "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\344\271\246\345\215\225.md" similarity index 100% rename from "animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode148\351\223\276\350\241\250\346\216\222\345\272\217.md" rename to "animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\344\271\246\345\215\225.md" diff --git "a/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\246\202\344\275\225\345\255\246\344\271\240.md" "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\246\202\344\275\225\345\255\246\344\271\240.md" new file mode 100644 index 0000000..f588c24 --- /dev/null +++ "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\246\202\344\275\225\345\255\246\344\271\240.md" @@ -0,0 +1,112 @@ +如何面向面试学习? + +我们提到面试,大多数人脑子里蹦出的第一个词,那就是八股文。但是面试真的可以**只**靠八股文吗? + +那面试八股文重要吗?重要,非常重要! + +那你这不是前后矛盾吗?一会说不能只靠八股文,一会又说八股文非常重要。 + +哎嘛,不要着急,听我慢慢说。 + +以下仅仅是我的一家之言。 + +我们先来看一下,一位 Javaer 校招需要准备的东西有哪些。 + +- 数据结构与算法 + +- 操作系统 + +- 计算机网络 + +- Java 基础 + +- MySQL + +- Redis + +- Java 并发编程 + +- Spring 全家桶 + +- Linux + +- 设计模式 +- 1-2 两个能拿得出手的项目。 + +上面的内容或多或少会在面试中问到,有的面试官侧重于项目,有的面试官喜欢问基础知识,也就是我们常说的八股,还有的面试官喜欢问实际开发中遇到的问题也就是场景题。但是我认为面试官在提问之前,他们心里已经有他们的答案,你如果能说出他心里的那个点,然后再对其延伸,则有可能让面试官眼前一亮的。但是如果你一直没有说出他想要的那个点,一昧的对其拓展,这个答案或许就有点些冗余。 + +或许面试时,面试官想要的状态是,看到你对技术的自信,知其然知其所以然。这样自然而然能够得到一个好的面评。 + +那么我们如何才能做到上面提到的呢?那就是看书,你会发现看过某个科目 2-3 遍书之后,你对这个科目是有自信的,因为你有这门科目的知识架构,有自己的理解,知道它们之间的联系,那么你回答时则会得心应手。记住是看 2-3 遍哦,一遍的话,只能大概了解大致脉络,不能让自己深刻理解,所以到重复看,你会发现那些好书,每次看的时候都会有新的收获。 + +那么面向面试,我们应该如何学习一项新科目呢?我们就以 MySQL(高频考点)来举例吧。 + +第一步:调研 + +这一步很好理解,我们需要了解该项技术的经典书籍,这样能我们学习时,事半功倍。我一般是自己进行搜索。现在是开源的时代,大家都很喜欢分享自己的心得,你可以通过知乎,论坛等搜索到某项科目的经典书籍,但是不要只看一个帖子,多看几个,这些帖子中多次提到的书籍。就是我们的学习目标。 + +![](https://img-blog.csdnimg.cn/a3bc62b23f994897a01d2f3a55b7463a.png) + +另外你也可以问师兄师姐们,毕竟他们是过来人,知道哪些书籍值得读。 + +这里给大家推荐几本我读过的 MySQL 书籍,没有基础的同学可以按这个路线学习。 + +- MySQL 必知必会 + + 一本小册子,一天就能搞定,帮你快速入门 MySQL,另外大家在学习时,可以自己下载一下 MySQL 官方的学习库,然后自己动手实践一下,虽然速度慢了一些,但是能够让你学习的更加扎实。 + + ![在这里插入图片描述](https://img-blog.csdnimg.cn/94505d023f6e4cf9ab179925ac7420a6.png) + + 官方的 employees 库,我们可以用来练习一下,连接,explains 命令等。 + +- 数据库系统概论 + + 玫红色书皮的那本书,很多学校用来当作教材,这本书对数据库基础知识,查询语句,范式等讲的比较详细。这本书因为我之前学过几遍,后面再看的时候很快就读完了。个人认为还不错的一本书。有的学校研究生复试会考数据库,那么可以看下这本书,考点全面覆盖。 + +- 高性能 MySQL + + 非常牛皮的一本书,很多知识点在里面讲的很细,适合进阶的同学,如果你看了这本书,面试时,常考的那些知识点,你就可以得心应手啦。 + +- MySQL 技术内幕 + + 这本书我没有完整的看下来,看了部分章节,比如那些常考的知识点,事务,索引等。也是非常棒的一本书,推荐给面试的同学。 + +- MySQL 45 讲 + + 这门课我看了大概百分之七十,前面的十几讲 看了大概 3-4 遍,每次都有新收获,这门课适合有一定基础的同学,如果没有学过 MySQL 的话,看的时候可能会有些吃力。 + +- 从根上理解 MySQL + + 这个是掘金小册,也非常棒,但是我发现的有点晚了,后面抽着看了大概 1/2 吧。小册子对某个知识点说的很细,很透。 + +视频的话,我看的比较少,之前看过 MOOC 哈工大,战德臣 老师的课程,非常牛的一位老师,讲课风格也很棒,没有基础的同学可以看一下这个视频。 + +好啦,第一步一不小心扯多了,下面我们来说第二步。 + +第二步:看面经(八股) + +啥?你刚才还说不能只看八股,这刚调研完经典书籍,就开始看八股了?这不是自己打自己脸吗?先别骂,先别骂,听我接着往下说。 + +这时的八股和面试题,是为了让你知道面试时的重点,哪些知识点常考,这样我们就可以重点看那些常考的章节。 + +那些不常考的知识点就不用看了吗?当然也是需要看的,因为每个章节之间是有联系的,通过前面的章节引出后面的,可以帮助我们更好的理解,形成自己的体系结构。不过这些不是重点的章节,可以粗略学习,了解即可。 + +第三步:看书 + +这一步我建议大家看纸质书,我们可以在书上标注,后面二刷三刷的时候,也可以根据标注帮我们回忆。大家可以在看书的时候,自己做一下思维导图,帮助我们构建自己的知识体系。推荐的软件是 Xmind,ProcessOn。 + +第四步:看面经和八股 + +注意,这里是看不是背,我们通过面经里的问题来进行归纳整理,对面经的问题进行分类,然后自己通过翻阅书籍和文章来找到答案进行整理,记住哈,记得分类,后面便于补充,也有利于搭建我们的知识体系。比如下面这样 + +![](https://img-blog.csdnimg.cn/92c846fe20ac4162960927a964b29bac.png) + +第五步:回溯 + +哈哈,这个回溯不是我们刷题的那个回溯,而是我们对每次面试的总结,建议大家刚开始面试的时候可以对自己的面试过程进行录屏,面试结束后,查看录像,看看自己的言行举止等,是否有摇头晃脑,回答不自信等情况。 + +后面的话则只需录音即可,思考一下自己哪块回答的不太好,需要迭代,思考一下某个问题,面试官想要考察的点是什么。经历几次之后,就能找到自己的面试节奏和风格。 + +大家是不是发现学好一门课并不容易,也比较耗时,所以我们需要尽早的准备面试,早就是优势! + +好啦,我要说的大概就这些啦,希望可以对学弟学妹们有一丢丢帮助。大家可以在评论区进行补充,推荐一下自己认为不错的书籍,今天就唠到这吧,拜了个拜。如果你需要我整理的面经 PDF ,可以添加我的微信,备注你需要的科目和 PDF ,例如 数据库 PDF。 diff --git "a/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\255\246\345\274\237\351\227\256\344\272\206\346\210\221\344\270\200\344\270\252\351\227\256\351\242\230.md" "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\255\246\345\274\237\351\227\256\344\272\206\346\210\221\344\270\200\344\270\252\351\227\256\351\242\230.md" new file mode 100644 index 0000000..eb7e640 --- /dev/null +++ "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\255\246\345\274\237\351\227\256\344\272\206\346\210\221\344\270\200\344\270\252\351\227\256\351\242\230.md" @@ -0,0 +1,139 @@ +一位学弟,问了我一个问题。 + +![问题描述](https://img-blog.csdnimg.cn/93cb8f9ccbe442a1bec05fff68a2e8e3.png) + +我在这里说一下我的看法,希望能够对有相同问题的学弟学妹,有一丢丢帮助。 + +回想自身 + +我似乎从来没想过这个问题? + +读大学的时候,每天的想法不是,不是今天学点啥,吃点啥,玩个啥游戏开心开心,每天想的是,我怎么练球才能把我哥们打爆,斗牛时,说垃圾话,怎么才能不落下风。寒暑假的时候,能够大冬天搁水泥地(不是篮球场,是一块空地)拍球,拍两三个小时,就是为了开学的时候,把他们斩于马下。 + +就这样打着打着篮球,忽然就到大三下学期了,然后就听到谁谁谁去哪个大厂实习啦,谁谁谁参加什么比赛得奖啦。 + +好家伙,我慌了啊。 + +突然不知道自己该干啥了,打球打球,打个锤子球,马上就毕业啦,心里咋就没数呢? + +那天晚上我失眠了,也在那天晚上,做了一个可能影响我一生的决定。 + +嗯,我决定考研! + +其实说白了,也就是为了逃避就业,为自己的菜找个借口。 + +第二天醒来,就直接背着书去了自习室,开始了朝 8 晚 10 的复习之路。从决定考研到考研前夕,为期八个多月的备考,我打球的次数不会超过 5 次,休息的总天数不会超过 3 天。 + +每次哥们叫我打球,我总是找一些借口推掉了,渐渐的他们打球的时候也就不喊我了,我也就安心准备考研啦。 + +备考的这段时间,我一直没有忘记锻炼,我会隔一天去一次健身房,每次锻炼一个半小时。我觉得我能坚持到考研,健身房也有很大的功劳。 + +毕竟备考还是很累的,一坐就是一整天,中午也不回宿舍睡觉,就在桌子上趴一会。所以要有一个好身体,才能扛得住。 + +读者:你这说了一堆,和你学弟问的问题也没啥关系啊! + +厨子:哎嘛,别急别急,即然说啦,肯定是有用的的,马上就说到重点啦。 + +通过上面我的例子,我认为完成某个目标需要具备这几个特点。 + +- 抹平信息差 +- 执行力 +- 持之以恒 + +**抹平信息差** + +其实很多时候,我们和别人都有信息差距,进而导致思维上的差距,然而思维上的差距是最难缩短的。 + +我们为什么考大学考研究生时,想要考好大学,毕业后想去大公司。 + +大公司好呀,钱多,福利好,技术氛围好。 + +嗯是的,进入好学校和好公司都可以理解成进入了一个好的平台。之前和一位 HR 聊了挺久,交谈中的一句话,让我仍记忆犹新。 + +应届生入职时,平台带给你的,远远大于你自身技术带给你的。 + +暂且不论这句话是对是错,聊天结束后我思考了这句话的含义,以下是我对这句话,某一个方面的理解。 + +在好的平台里,你会多了很多和大牛们交流的机会,相当于进入了一个好的圈子。**在什么样的圈子里,以后就做什么样的事情,但是你现在所做的事,决定你以后能够进入什么样的圈子。** + +这个过程中,你可能意识不到你的进步,但是如果你养成记录的习惯,回过头来再看的话,你会发现自己真的进步很大,而且进步的过程本来就是悄无声息,而是在之后的某一时刻,你才会发现你进步了。 + +当然好的平台带给我们的远远不止这一点,而且我们每个人对 “好” 的定义也不相同,就不在这详细说啦。 + +我认为抹平信息差是完成某个目标的要做的第一件事,完成目标前,我们要先定下目标。 + +本科的时候,我们很多人甚至都不知道有保研,秋招,比赛这一说,你敢信? + +**作为大学生的你们则可以通过一下几种方法帮助你们抹平信息差** + +1.请教往届的师兄师姐,他们的经验分享或许对你帮助很大。 + +2.通过某些途径,看一些前辈的分享求职分享或者学习路线等,比如知乎,牛客,脉脉等。 + +就拿考研来说,如果你看过,其他师兄师姐的考研心得,那么你就有可能少走很多弯路,复习的更加充分,上岸的几率则更大。 + +有的时候,我们缺少和前辈面对面交流的机会,但是从他们的文字中,也能够学到很多。 + +3.多和比你优秀的人交流。 + +就比如《孔子家语》中的一句话,与善人居,如入芝兰之室,久而不闻其香,即与之化矣。这句话的意思是,与品行优良的人共同居住,就好比是进入栽满了芝兰香草的雅室,时间久了就闻不到香味了,因为他已经被同化了,变得同样的品行优良。 + +思维高度亦是如此。 + +**执行力** + +如果我们将抹平信息差,看成是通过前辈们的指导,找到了满是成熟果实的果园,那么执行力就可以比做摘果子的竹竿。 + +我们不要想着我们找到了果园,就能够硕果累累。果实是有成熟期的,如果在特定的时间不摘的话,就会腐烂(机会流逝)。 + +所以我们想到什么事有搞头,就抓紧去做吧,不然,只会让机会白白流走。 + +种一棵树最好的时间是十年前,其次是现在。 + +这句话,没毛病,但是我们为什么不把握最好的时间,而是要退而求其次呢? + +很多时候,我们都是通过和身边人的比较,而知道自身水平。 + +所以如果身边的人都在进步,你停滞不前,到你发现的时候, 欲望更大,需要的更多,所承受的压力则会更大。 + +所以现在觉得有搞头,就快闷着头往前冲吧! + +**持之以恒** + +写到这的时候,感觉要写不下去了,说的这些感觉大家都知道,但是没有经历过的话,很难有深刻理解。本科时,我浪费掉了太多时间,所以真的希望学弟学妹们能够把握当下,这四年真的能够学到太多东西。 + +还是接着往下说吧。 + +我们现在已经在**满是成熟果实**的果园里打果子啦。如果我们三天打鱼两天晒网,别人果园的果实都打完了,开始找下一个果园了,你的这个还没打一半,这可咋整。 + +所以我们在给自己定下目标之后,坚持下去。 + +我们可以通过一下几种方法帮助我们坚持。 + +**正反馈** + +设立奖励机制,我们完成某个小目标之后,则可以奖励给自己某些东西,比如吃些自己想吃的,买些自己之前想买,但是没买的东西。就比如我之前考研的时候,我会在每天早上,给自己设定好,自己今天要做的题目。 + +设定过今天的学习目标之后,则能让我学习效率大幅度提升,努力完成今天的目标,完成之后,则会在回宿舍的时候,奖励自己好吃的。 + +**闭关** + +是的,闭关。无论是考研的时候,还是准备秋招的时候,我都是自己一人去图书馆,然后将手机锁机,开始学习。 + +我觉得最好的学习状态就是,保证作息规律,每天重复同样的事,吃饭,学习,睡觉。 + +进入这个状态之后,你会非常的想学习,对学习之外的事,兴趣就变得没有之前那么大,自然而然的就坚持下来啦。 + +**回溯** + +其实这个也和正反馈一致,我们可以每天晚上,整理今日所学。整理过后,你会发现你今天学到了很多东西,就会非常充实和踏实。感觉今天一天没有白过。自然而然的形成良性循环,帮助你坚持下去。 + +当然我们一定要注意锻炼,身体是革命的本钱,身体和脑子有一个动就好啦。 + +授人以鱼,不如授人以渔。希望这篇文章,能够对迷茫的学弟学妹有一丢丢帮助。这篇文章不是假大空,是我经历过,感觉浪费掉的大把时间真的可惜。 + +虽然人生是个长跑,不是冲刺跑。某个时期对你的影响,没有你想象的那么大,只要我们保持向上的心就好。 + +如果给我重新读大学的机会,我仍然会和哥们们好好打球,不过我会努力抹平信息差,对自己的职业生涯好好规划。 + +如果觉得这篇文章对你有点用,那就帮忙转发给你的朋友吧。好啦,今天就唠到这吧,拜了个拜。 diff --git "a/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\270\270\347\234\213\347\232\204UP\344\270\273.md" "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\270\270\347\234\213\347\232\204UP\344\270\273.md" new file mode 100644 index 0000000..3a71838 --- /dev/null +++ "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\345\270\270\347\234\213\347\232\204UP\344\270\273.md" @@ -0,0 +1,77 @@ +今天不和大家吹牛玩了,唠唠嗑吧,说几个我逛 B 站经常看的几位 UP 主吧。看看里面有没有你关注滴。我知道在做的各位,很多都是在 B 站学跳舞的 🐶,我看的比较多的则是搞笑区 UP,他们可都太逗了。 + +### 导演小策 + +入坑作品,是那个贼牛的《一块劳力士的回家路》,现在已经一千多万播放了,当时感觉小策真的太有才了,短短三分钟,剧情跌宕起伏,既隐晦又深刻。 + +![在这里插入图片描述](https://img-blog.csdnimg.cn/ee00701440eb42b7a993fbd1a7dc4a32.png) + +后面他又拍了《广场往事》系列,每个视频都让我笑出鹅叫,甚至连恰饭都恰的那么清新脱俗。 + +![](https://img-blog.csdnimg.cn/27b3da9294ee4378a8b392adae3bfe5f.png) + +广场舞巨头鹅姨,鹅姨的跟班二花,会说 rap 的烫嘴阿姨,爱和三舅合影的三炮。每个人物都个性鲜明,绝了。 + +![2021-09-13 21.56.41](/Users/yuanbangjie/Documents/动画/2021-09-13 21.56.41.gif) + +### 才疏学浅的才浅 + +这个真的是巨佬,也是我关注特别久的 UP 刚开始关注的时候才几千粉丝,现在已经 350 万了。 + +当时还跟着他的视频,给女朋友做了两个印章,(不知道咋回事,视频找不到了)。 + +![我做的印章](https://img-blog.csdnimg.cn/e2294dac7350447b8fe0d572e2cd9d34.png) + +可是后来,他开始做刀了。 + +![](https://img-blog.csdnimg.cn/d7f25b635d80406eb406bd34e4cc55f1.png) + +再后来,他开始做面具,开始制杖了! + +![](/Users/yuanbangjie/Library/Application Support/typora-user-images/image-20210913224757736.png) + +这下我真的搞不定了,才浅做面具和制杖的视频还登上了央视,真的太牛了,也喜欢手工的老哥可以去看一哈,非常牛的一位 UP 主。 + +### 小潮院长 + +哈哈,小潮 TEAM 的大哥大,他的不要做挑战真的太好笑啦,来回看了好几遍,每次都笑的肚子痛。 + +这个还掀起了 B 站的模仿热潮。真的是一个既有才又有趣的 UP。 + +![](https://img-blog.csdnimg.cn/5f0d27231c5b4d46b8a85d0f14c52683.png) + +### 张若宇 + +张若宇一个喜欢敷面膜的老哥,他的视频有一个特点,那就是短,短短一分钟的视频,节奏把握的特别好,BGM 配的也恰到好处,属实让他玩明白了。视频中最喜欢看的就是陶陶,一个酷爱吃肘子的 “活宝”。 + +![](https://img-blog.csdnimg.cn/9d9034a4af114924bdf7516164eeef7e.png) + +亲切的口音和热闹的家庭氛围,让我很喜欢看他们的视频。也是一个非常有才 UP 主。 + +### 野球帝 + +很久很久之前就关注了野球帝,当时的我还很小,一看就看到现在。 + +野球帝团队的人也越来越多,也越来越热闹。 + +说实话真的很羡慕他们那种氛围,既可以和兄弟们一起打球,又能一起工作。 + +和喵哥说的似的,等退休之后,开个篮球场和烧烤店,和兄弟们打完球,一起撸撸串吹吹牛,好不惬意。 + +![](https://img-blog.csdnimg.cn/fd31c23d431b470f99a769a62ec332f6.png) + +依旧干货满满,另外多说一句,别让通演傻子啦,他快改不过来啦。哈哈 + +喜欢篮球的哥们可以关注一波。 + +KBT 篮球训练营 + +这不和喵哥约了国庆节决一死战,我俩每天都在群里说一些垃圾话,都觉得能把对方打爆。不能光吹牛批不干活,所以咱们得把训练安排上。一位干货满满的 UP ,为你指出平常没有注意到的细节。都是很实用的动作,打喵哥应该足够了。 + +![](https://img-blog.csdnimg.cn/059dfed9cd2b4fd3bd16cc28f926b429.png) + +好啦,今天是纯唠嗑局,大家也可以把自己常看的优质 UP 打在评论区。 + +后面会继续给大家更新一些关于面试事,另外多说一句,2023 秋招的学弟学妹们,要尽快准备起来啦,早就是优势。 + +今天就唠到这吧,拜了个拜。 diff --git "a/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\351\200\201\344\271\246.md" "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\351\200\201\344\271\246.md" new file mode 100644 index 0000000..935dd75 --- /dev/null +++ "b/animation-simulation/\345\206\231\345\206\231\346\260\264\346\226\207/\351\200\201\344\271\246.md" @@ -0,0 +1,19 @@ +好久不见 + +哈喽大家好,我是厨子,好久不见啊。 + +主要是这段时间太忙啦,所以没有进行更新,不过后面会慢慢更新起来,继续更之前的专题。 + +那么我今天是来干什么的呢?给大家送点福利,送几本我们经常用的《剑指 offer》。呐,就是下面这一本啦。 + +《剑指 offer 专项突破版》 + +感谢博文视点杨老师的赠书 + +大概翻了一下,这本书的目录和内容,这本书不仅仅是根据专题来进行编写,另外还将每个专题的解题方法进行了总结,个人感觉是非常不错的,能够帮助我们高效刷题。书中的题目也都是比较经典,高频的题目,对于我们面试也很有帮助。 + +下面是专项版和经典版的一些对比。 + +![在这里插入图片描述](https://img-blog.csdnimg.cn/e5ee04d996d24fad9804749557f8e87b.png) + +杨老师这里赞助了我六本,送给读者朋友,大家需要的可以参与下。 diff --git "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode1248\345\257\273\346\211\276\344\274\230\347\276\216\345\255\220\346\225\260\347\273\204.md" "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode1248\345\257\273\346\211\276\344\274\230\347\276\216\345\255\220\346\225\260\347\273\204.md" index 55e3405..f91b15b 100644 --- "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode1248\345\257\273\346\211\276\344\274\230\347\276\216\345\255\220\346\225\260\347\273\204.md" +++ "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode1248\345\257\273\346\211\276\344\274\230\347\276\216\345\255\220\346\225\260\347\273\204.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [1248. 统计「优美子数组」](https://leetcode-cn.com/problems/count-number-of-nice-subarrays/) @@ -12,7 +12,7 @@ > > 如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。 > -> 请返回这个数组中「优美子数组」的数目。 +> 请返回这个数组中「优美子数组」的数目。 **示例 1:** @@ -33,22 +33,22 @@ 如果上面那个题目我们完成了,这个题目做起来,分分钟的事,不信你去写一哈,百分百就整出来了,我们继续按上面的思想来解决。 - **HashMap** +**HashMap** **解析** -上个题目我们是求和为 K 的子数组,这个题目是让我们求 恰好有 k 个奇数数字的连续子数组,这两个题几乎是一样的,上个题中我们将前缀区间的和保存到哈希表中,这个题目我们只需将前缀区间的奇数个数保存到区间内即可,只不过将 sum += x 改成了判断奇偶的语句,见下图。 +上个题目我们是求和为 K 的子数组,这个题目是让我们求 恰好有 k 个奇数数字的连续子数组,这两个题几乎是一样的,上个题中我们将前缀区间的和保存到哈希表中,这个题目我们只需将前缀区间的奇数个数保存到区间内即可,只不过将 sum += x 改成了判断奇偶的语句,见下图。 ![微信截图_20210114222339](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210114222339.c0gwtdh8m94.png) -我们来解析一下哈希表,key 代表的是含有 1 个奇数的前缀区间,value 代表这种子区间的个数,含有两个,也就是nums[0],nums[0,1].后面含义相同,那我们下面直接看代码吧,一下就能读懂。 +我们来解析一下哈希表,key 代表的是含有 1 个奇数的前缀区间,value 代表这种子区间的个数,含有两个,也就是 nums[0],nums[0,1].后面含义相同,那我们下面直接看代码吧,一下就能读懂。 Java Code: ```java class Solution { public int numberOfSubarrays(int[] nums, int k) { - + if (nums.length == 0) { return 0; } @@ -95,10 +95,10 @@ public: } //存入 if(m.find(oddnum) != m.end()) m[oddnum]++; - else m[oddnum] = 1; + else m[oddnum] = 1; } return count; - } + } }; ``` @@ -108,7 +108,7 @@ Java Code: ```java class Solution { - public int numberOfSubarrays(int[] nums, int k) { + public int numberOfSubarrays(int[] nums, int k) { int len = nums.length; int[] map = new int[len + 1]; map[0] = 1; @@ -147,7 +147,6 @@ public: map[oddnum]++; } return count; - } + } }; ``` - diff --git "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode523\350\277\236\347\273\255\347\232\204\345\255\220\346\225\260\347\273\204\345\222\214.md" "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode523\350\277\236\347\273\255\347\232\204\345\255\220\346\225\260\347\273\204\345\222\214.md" index c84d13b..44c6d80 100644 --- "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode523\350\277\236\347\273\255\347\232\204\345\255\220\346\225\260\347\273\204\345\222\214.md" +++ "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode523\350\277\236\347\273\255\347\232\204\345\255\220\346\225\260\347\273\204\345\222\214.md" @@ -1,14 +1,14 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [523. 连续的子数组和](https://leetcode-cn.com/problems/continuous-subarray-sum/) **题目描述** -> 给定一个包含 非负数 的数组和一个目标 整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,且总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数。 +> 给定一个包含 非负数 的数组和一个目标 整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,且总和为 k 的倍数,即总和为 n\*k,其中 n 也是一个整数。 **示例 1:** @@ -30,15 +30,15 @@ ![微信截图_20210115174825](https://img-blog.csdnimg.cn/img_convert/953d09fbfffab9298152e143a39c85c0.png) -此时我们 K = 6, presum % 6 = 4 也找到了相同余数的前缀子数组 [0,1] 但是我们此时指针指向为 2,我们的前缀子区间 [0,1]的下界为1,所以 2 - 1 = 1,但我们的中间区间的长度小于2,所以不能返回 true,需要继续遍历,那我们有两个区间[0,1],[0,2]都满足 presum % 6 = 4,那我们哈希表中保存的下标应该是 1 还是 2 呢?我们保存的是1,如果我们保存的是较大的那个索引,则会出现下列情况,见下图。 +此时我们 K = 6, presum % 6 = 4 也找到了相同余数的前缀子数组 [0,1] 但是我们此时指针指向为 2,我们的前缀子区间 [0,1]的下界为 1,所以 2 - 1 = 1,但我们的中间区间的长度小于 2,所以不能返回 true,需要继续遍历,那我们有两个区间[0,1],[0,2]都满足 presum % 6 = 4,那我们哈希表中保存的下标应该是 1 还是 2 呢?我们保存的是 1,如果我们保存的是较大的那个索引,则会出现下列情况,见下图。 -![微信截图_20210115175122](https://img-blog.csdnimg.cn/img_convert/7bbd04ac578074d5fbccae7ab384f061.png) +![微信截图_20210115175122](https://img-blog.csdnimg.cn/img_convert/7bbd04ac578074d5fbccae7ab384f061.png) 此时,仍会显示不满足子区间长度至少为 2 的情况,仍会继续遍历,但是我们此时的 [2,3]区间已经满足该情况,返回 true,所以我们往哈希表存值时,只存一次,即最小的索引即可。下面我们看一下该题的两个细节 -细节1:我们的 k 如果为 0 时怎么办,因为 0 不可以做除数。所以当我们 k 为 0 时可以直接存到数组里,例如输入为 [0,0] , K = 0 的情况 +细节 1:我们的 k 如果为 0 时怎么办,因为 0 不可以做除数。所以当我们 k 为 0 时可以直接存到数组里,例如输入为 [0,0] , K = 0 的情况 -细节2:另外一个就是之前我们都是统计个数,value 里保存的是次数,但是此时我们加了一个条件就是长度至少为 2,保存的是索引,所以我们不能继续 map.put(0,1),应该赋初值为 map.put(0,-1)。这样才不会漏掉一些情况,例如我们的数组为[2,3,4],k = 1,当我们 map.put(0,-1) 时,当我们遍历到 nums[1] 即 3 时,则可以返回 true,因为 1-(-1)= 2,5 % 1=0 , 同时满足。 +细节 2:另外一个就是之前我们都是统计个数,value 里保存的是次数,但是此时我们加了一个条件就是长度至少为 2,保存的是索引,所以我们不能继续 map.put(0,1),应该赋初值为 map.put(0,-1)。这样才不会漏掉一些情况,例如我们的数组为[2,3,4],k = 1,当我们 map.put(0,-1) 时,当我们遍历到 nums[1] 即 3 时,则可以返回 true,因为 1-(-1)= 2,5 % 1=0 , 同时满足。 **视频解析** @@ -64,9 +64,9 @@ class Solution { return true; } //因为我们需要保存最小索引,当已经存在时则不用再次存入,不然会更新索引值 - continue; - } - map.put(key,i); + continue; + } + map.put(key,i); } return false; } @@ -92,12 +92,43 @@ public: return true; } //因为我们需要保存最小索引,当已经存在时则不用再次存入,不然会更新索引值 - continue; - } - m.insert({key, i}); + continue; + } + m.insert({key, i}); } return false; } }; ``` +Go Code: + +```go +func checkSubarraySum(nums []int, k int) bool { + m := map[int]int{} + // 由于前缀和%k可能为0,所以需要给出没有元素的时候,索引位置,即-1 + m[0] = -1 + sum := 0 + for i, num := range nums { + sum += num + key := sum % k + /* + // 题目中告诉k >= 1 + key := sum + if k != 0 { + key = sum % k + } + */ + if v, ok := m[key]; ok { + if i - v >= 2 { + return true + } + // 避免更新最小索引 + continue + } + // 保存的是最小的索引 + m[key] = i + } + return false +} +``` diff --git "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode560\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204.md" "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode560\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204.md" index cf52022..54e84f1 100644 --- "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode560\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204.md" +++ "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode560\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204.md" @@ -1,10 +1,10 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -#### [560. 和为K的子数组](https://leetcode-cn.com/problems/subarray-sum-equals-k/) +#### [560. 和为 K 的子数组](https://leetcode-cn.com/problems/subarray-sum-equals-k/) **题目描述** @@ -51,7 +51,7 @@ presum [2] = presum[1] + nums[1],presum[3] = presum[2] + nums[2] ... 所以我 例如我们需要获取 nums[2] 到 nums[4] 这个区间的和,我们则完全根据 presum 数组得到,是不是有点和我们之前说的字符串匹配算法中 BM,KMP 中的 next 数组和 suffix 数组作用类似。 -那么我们怎么根据presum 数组获取 nums[2] 到 nums[4] 区间的和呢?见下图 +那么我们怎么根据 presum 数组获取 nums[2] 到 nums[4] 区间的和呢?见下图 ![前缀和](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/前缀和.77twdj3gpkg0.png) @@ -102,7 +102,7 @@ class Solution { //一次遍历 for (int i = 0; i < nums.length; ++i) { //存在时,我们用数组得值为 key,索引为 value - if (map.containsKey(target - nums[i])){ + if (map.containsKey(target - nums[i])){ return new int[]{i,map.get(target-nums[i])}; } //存入值 @@ -160,7 +160,7 @@ public: if (nums.size() == 0) { return 0; } - map m; + map m; //细节,这里需要预存前缀和为 0 的情况,会漏掉前几位就满足的情况 //例如输入[1,1,0],k = 2 如果没有这行代码,则会返回0,漏掉了1+1=2,和1+1+0=2的情况 //输入:[3,1,1,0] k = 2时则不会漏掉 @@ -183,3 +183,23 @@ public: }; ``` +Go Code: + +```GO +func subarraySum(nums []int, k int) int { + m := map[int]int{} + // m存的是前缀和,没有元素的时候,和为0,且有1个子数组(空数组)满足条件,即m[0] = 1 + m[0] = 1 + sum := 0 + cnt := 0 + for _, num := range nums { + sum += num + if v, ok := m[sum - k]; ok { + cnt += v + } + // 更新满足前缀和的子数组数量 + m[sum]++ + } + return cnt +} +``` diff --git "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode724\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.md" "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode724\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.md" index 37ce953..a389837 100644 --- "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode724\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.md" +++ "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode724\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### 前缀和详解 @@ -10,13 +10,13 @@ 下面我们先来了解一下什么是前缀和。 -前缀和其实我们很早之前就了解过的,我们求数列的和时,Sn = a1+a2+a3+...an; 此时Sn就是数列的前 n 项和。例 S5 = a1 + a2 + a3 + a4 + a5; S2 = a1 + a2。所以我们完全可以通过 S5-S2 得到 a3+a4+a5 的值,这个过程就和我们做题用到的前缀和思想类似。我们的前缀和数组里保存的就是前 n 项的和。见下图 +前缀和其实我们很早之前就了解过的,我们求数列的和时,Sn = a1+a2+a3+...an; 此时 Sn 就是数列的前 n 项和。例 S5 = a1 + a2 + a3 + a4 + a5; S2 = a1 + a2。所以我们完全可以通过 S5-S2 得到 a3+a4+a5 的值,这个过程就和我们做题用到的前缀和思想类似。我们的前缀和数组里保存的就是前 n 项的和。见下图 ![](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210113193831.4wk2b9zc8vm0.png) 我们通过前缀和数组保存前 n 位的和,presum[1]保存的就是 nums 数组中前 1 位的和,也就是 **presum[1]** = nums[0], **presum[2]** = nums[0] + nums[1] = **presum[1]** + nums[1]. 依次类推,所以我们通过前缀和数组可以轻松得到每个区间的和。 -例如我们需要获取 nums[2] 到 nums[4] 这个区间的和,我们则完全根据 presum 数组得到,是不是有点和我们之前说的字符串匹配算法中 BM,KMP 中的 next 数组和 suffix 数组作用类似。那么我们怎么根据 presum 数组获取 nums[2] 到 nums[4] 区间的和呢?见下图 +例如我们需要获取 nums[2] 到 nums[4] 这个区间的和,我们则完全根据 presum 数组得到,是不是有点和我们之前说的字符串匹配算法中 BM,KMP 中的 next 数组和 suffix 数组作用类似。那么我们怎么根据 presum 数组获取 nums[2] 到 nums[4] 区间的和呢?见下图 ![前缀和](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/前缀和.77twdj3gpkg0.png) @@ -61,7 +61,7 @@ 理解了我们前缀和的概念(不知道好像也可以做,这个题太简单了哈哈)。我们可以一下就能把这个题目做出来,先遍历一遍求出数组的和,然后第二次遍历时,直接进行对比左半部分和右半部分是否相同,如果相同则返回 true,不同则继续遍历。 -Java Code: +Java Code: ```java class Solution { @@ -70,14 +70,14 @@ class Solution { //数组的和 for (int x : nums) { presum += x; - } + } int leftsum = 0; for (int i = 0; i < nums.length; ++i) { //发现相同情况 if (leftsum == presum - nums[i] - leftsum) { return i; } - leftsum += nums[i]; + leftsum += nums[i]; } return -1; } @@ -94,17 +94,36 @@ public: //数组的和 for (int x : nums) { presum += x; - } + } int leftsum = 0; for (int i = 0; i < nums.size(); ++i) { //发现相同情况 if (leftsum == presum - nums[i] - leftsum) { return i; } - leftsum += nums[i]; + leftsum += nums[i]; } return -1; } }; ``` +Go Code: + +```go +func pivotIndex(nums []int) int { + presum := 0 + for _, num := range nums { + presum += num + } + var leftsum int + for i, num := range nums { + // 比较左半和右半是否相同 + if presum - leftsum - num == leftsum { + return i + } + leftsum += num + } + return -1 +} +``` diff --git "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode974\345\222\214\345\217\257\350\242\253K\346\225\264\351\231\244\347\232\204\345\255\220\346\225\260\347\273\204.md" "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode974\345\222\214\345\217\257\350\242\253K\346\225\264\351\231\244\347\232\204\345\255\220\346\225\260\347\273\204.md" index a6991ba..079e9ac 100644 --- "a/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode974\345\222\214\345\217\257\350\242\253K\346\225\264\351\231\244\347\232\204\345\255\220\346\225\260\347\273\204.md" +++ "b/animation-simulation/\345\211\215\347\274\200\345\222\214/leetcode974\345\222\214\345\217\257\350\242\253K\346\225\264\351\231\244\347\232\204\345\255\220\346\225\260\347\273\204.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [974. 和可被 K 整除的子数组](https://leetcode-cn.com/problems/subarray-sums-divisible-by-k/) @@ -24,23 +24,23 @@ **解析** -我们在该文的第一题 **和为K的子数组 **中,我们需要求出满足条件的区间,见下图 +我们在该文的第一题 **和为 K 的子数组 **中,我们需要求出满足条件的区间,见下图 ![微信截图_20210115194113](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210115194113.5e56re9qdic0.png) -我们需要找到满足,和为 K 的区间。我们此时 presum 是已知的,k 也是已知的,我们只需要找到 presum - k区间的个数,就能得到 k 的区间个数。但是我们在当前题目中应该怎么做呢?见下图。 +我们需要找到满足,和为 K 的区间。我们此时 presum 是已知的,k 也是已知的,我们只需要找到 presum - k 区间的个数,就能得到 k 的区间个数。但是我们在当前题目中应该怎么做呢?见下图。 ![微信截图_20210115150520](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210115150520.3kh5yiwwmlm0.png) -我们在之前的例子中说到,presum[j+1] - presum[i] 可以得到 nums[i] + nums[i+1]+.... nums[j],也就是[i,j]区间的和。 +我们在之前的例子中说到,presum[j+1] - presum[i] 可以得到 nums[i] + nums[i+1]+.... nums[j],也就是[i,j]区间的和。 那么我们想要判断区间 [i,j] 的和是否能整除 K,也就是上图中紫色那一段是否能整除 K,那么我们只需判断 (presum[j+1] - presum[i] ) % k 是否等于 0 即可, -我们假设 (presum[j+1] - presum[i] ) % k == 0;则 +我们假设 (presum[j+1] - presum[i] ) % k == 0;则 -presum[j+1] % k - presum[i] % k == 0; +presum[j+1] % k - presum[i] % k == 0; presum[j +1] % k = presum[i] % k ; @@ -48,8 +48,6 @@ presum[j +1] % k = presum[i] % k ; ![微信截图_20210115152113](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210115152113.606bcpexpww0.png) - - **题目代码** ```java @@ -83,9 +81,9 @@ int key = (presum % K + K) % K; 这是为什么呢?不能直接用 presum % k 吗? -这是因为当我们 presum 为负数时,需要对其纠正。纠正前(-1) %2 = (-1),纠正之后 ( (-1) % 2 + 2) % 2=1 保存在哈希表中的则为 1.则不会漏掉部分情况,例如输入为 [-1,2,9],K = 2如果不对其纠正则会漏掉区间 [2] 此时 2 % 2 = 0,符合条件,但是不会被计数。 +这是因为当我们 presum 为负数时,需要对其纠正。纠正前(-1) %2 = (-1),纠正之后 ( (-1) % 2 + 2) % 2=1 保存在哈希表中的则为 1.则不会漏掉部分情况,例如输入为 [-1,2,9],K = 2 如果不对其纠正则会漏掉区间 [2] 此时 2 % 2 = 0,符合条件,但是不会被计数。 -那么这个题目我们可不可以用数组,代替 map 呢?当然也是可以的,因为此时我们的哈希表存的是余数,余数最大也只不过是 K-1所以我们可以用固定长度 K 的数组来模拟哈希表。 +那么这个题目我们可不可以用数组,代替 map 呢?当然也是可以的,因为此时我们的哈希表存的是余数,余数最大也只不过是 K-1 所以我们可以用固定长度 K 的数组来模拟哈希表。 Java Code: @@ -102,7 +100,7 @@ class Solution { //求key int key = (presum % K + K) % K; //count添加次数,并将当前的map[key]++; - count += map[key]++; + count += map[key]++; } return count; } @@ -125,10 +123,27 @@ public: //求key int key = (presum % K + K) % K; //count添加次数,并将当前的map[key]++; - count += (map[key]++); + count += (map[key]++); } return count; } }; ``` +Go Code: + +```go +func subarraysDivByK(nums []int, k int) int { + m := make(map[int]int) + cnt := 0 + sum := 0 + m[0] = 1 + for _, num := range nums { + sum += num + key := (sum % k + k) % k + cnt += m[key] + m[key]++ + } + return cnt +} +``` diff --git "a/animation-simulation/\345\211\221\346\214\207offer/1\347\232\204\344\270\252\346\225\260.md" "b/animation-simulation/\345\211\221\346\214\207offer/1\347\232\204\344\270\252\346\225\260.md" index 79c2f31..f4f7cec 100644 --- "a/animation-simulation/\345\211\221\346\214\207offer/1\347\232\204\344\270\252\346\225\260.md" +++ "b/animation-simulation/\345\211\221\346\214\207offer/1\347\232\204\344\270\252\346\225\260.md" @@ -1,10 +1,10 @@ # 我太喜欢这个题了 -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 今天我们来看一道贼棒的题目,题目不长,很经典,也很容易理解,我们一起来看一哈吧, @@ -44,19 +44,15 @@ 我们假设 n = abcd,某个四位数。 - - ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/1的次数1.1s5l5k3qy3y8.png) - - 那我们完全可以统计每一位上 1 出现的次数,个数上 1 出现的次数,十位上 1 出现的次数,百位 ,千位。。。 也就是说**小于等于 n 的所有数字中**,个位上出现 1 的次数 + 十位出现 1 的次数 + 。。。最后得到的就是总的出现次数。 见下图 -我们假设 n = 13 (用个小点的数,比较容易举例) +我们假设 n = 13 (用个小点的数,比较容易举例) ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/1的次数2.1horkktykr7k.png) @@ -69,25 +65,20 @@ > 另外我们发现 11 这个数,会被统计 2 次,它的十位和个位都为 1 , > > 而我们这个题目是要统计 1 出现的次数,而不是统计包含 1 的整数,所以上诉方法不会出现重复统计的情况。 -> 我们题目已经有大概思路啦,下面的难点就是如何统计每一位中 1 出现的次数呢? 我们完全可以通过遍历 n 的每一位来得到总个数,见下图 - - ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/1的次数3.21nr01qnlz40.png) - - 假设我们想要得到十位上 1 出现的次数,当前我们指针指向十位, 我们称之为当前位。num 则代表当前位的位因子,当前位为个位时 num = 1,十位时为 10,百位时为 100.... 那我们将**当前位左边的定义为高位**,**当前位右边的定义位低位**。 -> 例:n = 1004 ,此时指针指向十位(当前位)num = 10,高位为百位,千位,低位为个位 +> 例:n = 1004 ,此时指针指向十位(当前位)num = 10,高位为百位,千位,低位为个位 而且我们某一位的取值范围为 0 ~ 9,那么我们可以将这 10 个数分为 3 类,小于 1 (当前位数字为 0 ),等于 1(当前位数字为 1 ) ,大于 1(当前位上数字为 2 ~ 9),下面我们就来分别考虑三种情况。 @@ -95,7 +86,7 @@ > > 注:该比喻来自与网友 ryan0414,看到的时候,不禁惊呼可太贴切了! -### **n = 1004** +### **n = 1004** 我们想要计算出**小于等于 1004 的非负整数中**,十位上出现 1 的次数。 @@ -103,13 +94,13 @@ ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/位数1.2x7xcbxtkjo0.png) -> 解析:为什么我们可以直接通过高位数字 * num,得到 1 出现的次数 +> 解析:为什么我们可以直接通过高位数字 \* num,得到 1 出现的次数 > > 因为我们高位为 10,可变范围为 0 ~ 10,但是我们的十位为 0 ,所以高位为 10 的情况取不到,所以共有 10 种情况。 > -> 又当前位为十位,低位共有 1 位,可选范围为 0 ~ 9 共有 10 种情况,所以直接可以通过 10 * 10 得到。 +> 又当前位为十位,低位共有 1 位,可选范围为 0 ~ 9 共有 10 种情况,所以直接可以通过 10 \* 10 得到。 -其实不难理解,我们可以设想成行李箱的密码盘,在一定范围内,也就是上面的 0010 ~ 0919 , 固定住一位为 1 ,只能移动其他位,看共有多少种组合。 +其实不难理解,我们可以设想成行李箱的密码盘,在一定范围内,也就是上面的 0010 ~ 0919 , 固定住一位为 1 ,只能移动其他位,看共有多少种组合。 好啦,这个情况我们已经搞明白啦,下面我们看另一种情况。 @@ -119,27 +110,27 @@ 也就是当前位为十位,数字为 1 时,十位上出现 1 的次数。 -我们在小于 1014 的非负整数中,十位上为 1 的最小数字为 10,最大数字为 1014,所以我们需要在 10 ~ 1014 这个范围内固定住十位上的 1 ,移动其他位。 +我们在小于 1014 的非负整数中,十位上为 1 的最小数字为 10,最大数字为 1014,所以我们需要在 10 ~ 1014 这个范围内固定住十位上的 1 ,移动其他位。 其实然后我们可以将 1014 看成是 1004 + 10 = 1014 - 则可以将 10 ~ 1014 拆分为两部分 0010 ~ 0919 (小于 1004 ),1010 ~ 1014。 +则可以将 10 ~ 1014 拆分为两部分 0010 ~ 0919 (小于 1004 ),1010 ~ 1014。 见下图 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/次数为1十位.4e6s2zqwtsw0.png) -> 解析:为什么我们可以直接通过 高位数字 * num + 低位数字 + 1 即 10 * 10 + 4 + 1 +> 解析:为什么我们可以直接通过 高位数字 _ num + 低位数字 + 1 即 10 _ 10 + 4 + 1 > > 得到 1 出现的次数 > -> 高位数字 * num 是得到第一段的次数,第二段为 低位数字 + 1,求第二段时我们高位数字和当前位已经固定, +> 高位数字 \* num 是得到第一段的次数,第二段为 低位数字 + 1,求第二段时我们高位数字和当前位已经固定, > > 我们可以改变的只有低位。 可以继续想到密码盘,求第二段时,把前 3 位固定,只能改变最后一位。最后一位最大能到 4 ,那么共有几种情况? -### n = 1024 +### n = 1024 我们想要计算出**小于等于 1024 的非负整数中**,十位上出现 1 的次数。 @@ -147,11 +138,9 @@ 我们也可以将其拆成两段 0010 ~ 0919,1010 ~ 1019 - - ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/高位.1wn8di6g1t6.png) -> 解析:为什么我们可以直接通过高位数字 * num + num, 10 * 10 + 10 得到 1 出现的次数 +> 解析:为什么我们可以直接通过高位数字 _ num + num, 10 _ 10 + 10 得到 1 出现的次数 > > 第一段和之前所说一样,第二段的次数,我们此时已经固定了高位和当前位,当前位为 1,低位可以随意取值,上诉例子中,当前位为 10,低位为位数为 1,则可以取值 0 ~ 9 的任何数,则共有 10 (num) 种可能。 @@ -161,12 +150,10 @@ > 注:蓝色高位,橙色当前位,绿色低位 > -> 初始化:low = 0, cur = n % 10, num = 1, count = 0, high = n / 10; +> 初始化:low = 0, cur = n % 10, num = 1, count = 0, high = n / 10; ![1的个数](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/1的个数.5yccejufzc80.gif) - - 好啦,下面我们看一下题目代码吧 注:下方代码没有简写,也都标有注释,大家可以结合动画边思考边阅读。 @@ -187,12 +174,12 @@ class Solution { while (high != 0 || cur != 0) { cur = high % 10; high /= 10; - //这里我们可以提出 high * num 因为我们发现无论为几,都含有它 + //这里我们可以提出 high * num 因为我们发现无论为几,都含有它 if (cur == 0) count += high * num; - else if (cur == 1) count += high * num + 1 + low; + else if (cur == 1) count += high * num + 1 + low; else count += (high + 1) * num; //低位 - low = cur * num + low; + low = cur * num + low; num *= 10; } return count; @@ -200,7 +187,64 @@ class Solution { } ``` -时间复杂度 : O(logn) 空间复杂度 O(1) +Swift Code: +```swift +class Solution { + func countDigitOne(_ n: Int) -> Int { + var high = n, low = 0, cur = 0, count = 0, num = 1 + while high != 0 || cur != 0 { + cur = high % 10 + high /= 10 + //这里我们可以提出 high * num 因为我们发现无论为几,都含有它 + if cur == 0 { + count += high * num + } else if cur == 1 { + count += high * num + 1 + low + } else { + count += (high + 1) * num + } + low = cur * num + low + num *= 10 + } + return count + } +} +``` +时间复杂度 : O(logn) 空间复杂度 O(1) +C++ Code: + +```C++ +class Solution +{ +public: + int countDigitOne(int n) + { + // 高位, 低位, 当前位 + int high = n, low = 0, cur = 0; + int count = 0, num = 1; + + //数字是0的时候完全没必要继续计算 + while (high != 0) + { + cur = high % 10; + high /= 10; + //这里我们可以提出 high * num 因为我们发现无论为几,都含有它 + if (cur == 0) + count += (high * num); + else if (cur == 1) + count += (high * num + 1 + low); + else + count += ((high + 1) * num); + //低位 + low = cur * num + low; + //提前检查剩余数字, 以免溢出 + if (high != 0) + num *= 10; + } + return count; + } +}; +``` diff --git "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/leetcode739\346\257\217\346\227\245\346\270\251\345\272\246.md" "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/leetcode739\346\257\217\346\227\245\346\270\251\345\272\246.md" index 697457d..789d8dd 100644 --- "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/leetcode739\346\257\217\346\227\245\346\270\251\345\272\246.md" +++ "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/leetcode739\346\257\217\346\227\245\346\270\251\345\272\246.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [739. 每日温度](https://leetcode-cn.com/problems/daily-temperatures/) @@ -10,38 +10,32 @@ > 请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。 -示例1: +示例 1: > 输入: temperatures = [73, 74, 75, 71, 69, 72, 76, 73] > -> 输出:arr = [1, 1, 4, 2, 1, 1, 0, 0] +> 输出:arr = [1, 1, 4, 2, 1, 1, 0, 0] -示例2: +示例 2: > 输入:temperatures = [30,30,31,45,31,34,56] > -> 输出:arr = [2,1,1,3,1,1,0] +> 输出:arr = [2,1,1,3,1,1,0] #### 题目解析 -其实我们可以换种方式理解这个题目,比如我们 temperatures[0] = 30,则我们需要找到后面第一个比 30 大的数,也就是 31,31的下标为 2,30 的下标为 0 ,则我们的返回数组 arr[0] = 2。 +其实我们可以换种方式理解这个题目,比如我们 temperatures[0] = 30,则我们需要找到后面第一个比 30 大的数,也就是 31,31 的下标为 2,30 的下标为 0 ,则我们的返回数组 arr[0] = 2。 理解了题目之后我们来说一下解题思路。 遍历数组,数组中的值为待入栈元素,待入栈元素入栈时会先跟栈顶元素进行对比,如果小于该值则入栈,如果大于则将栈顶元素出栈,新的元素入栈。 -例如栈顶为69,新的元素为72,则69出栈,72入栈。并赋值给 arr,69 的索引为4,72的索引为5,则 arr[4] = 5 - 4 = 1,这个题目用到的是单调栈的思想,下面我们来看一下视频解析。 - - +例如栈顶为 69,新的元素为 72,则 69 出栈,72 入栈。并赋值给 arr,69 的索引为 4,72 的索引为 5,则 arr[4] = 5 - 4 = 1,这个题目用到的是单调栈的思想,下面我们来看一下视频解析。 ![](https://img-blog.csdnimg.cn/20210319163137996.gif) - - 注:栈中的括号内的值,代表索引对应的元素,我们的入栈的为索引值,为了便于理解将其对应的值写在了括号中 - - ```java class Solution { public int[] dailyTemperatures(int[] T) { @@ -55,8 +49,8 @@ class Solution { for (int i = 0; i < len; i++) { //单调栈 while (!stack.isEmpty() && T[i] > T[stack.peek()]){ - arr[stack.peek()] = i - stack.pop(); - } + arr[stack.peek()] = i - stack.pop(); + } stack.push(i); } return arr; @@ -65,4 +59,25 @@ class Solution { } ``` +GO Code: +```go +func dailyTemperatures(temperatures []int) []int { + l := len(temperatures) + if l == 0 { + return temperatures + } + stack := []int{} + arr := make([]int, l) + for i := 0; i < l; i++ { + for len(stack) != 0 && temperatures[i] > temperatures[stack[len(stack) - 1]] { + idx := stack[len(stack) - 1] + arr[idx] = i - idx + stack = stack[: len(stack) - 1] + } + // 栈保存的是索引 + stack = append(stack, i) + } + return arr +} +``` diff --git "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\345\211\221\346\214\207offer59\351\230\237\345\210\227\347\232\204\346\234\200\345\244\247\345\200\274.md" "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\345\211\221\346\214\207offer59\351\230\237\345\210\227\347\232\204\346\234\200\345\244\247\345\200\274.md" index 2a6e34d..bb57952 100644 --- "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\345\211\221\346\214\207offer59\351\230\237\345\210\227\347\232\204\346\234\200\345\244\247\345\200\274.md" +++ "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\345\211\221\346\214\207offer59\351\230\237\345\210\227\347\232\204\346\234\200\345\244\247\345\200\274.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 今天我们好好说说单调栈和单调队列。其实很容易理解,单调栈就是单调递增或单调递减的栈,栈内元素是有序的,单调队列同样也是。 @@ -20,15 +20,13 @@ **示例 1:** -> 输入: ["MaxQueue","push_back","push_back","max_value","pop_front","max_value"] -> [[],[1],[2],[],[],[]] +> 输入: ["MaxQueue","push_back","push_back","max_value","pop_front","max_value"] > [[],[1],[2],[],[],[]] > 输出: [null,null,null,2,1,2] **示例 2:** -> 输入: -> ["MaxQueue","pop_front","max_value"] -> [[],[],[]] +> 输入: +> ["MaxQueue","pop_front","max_value"] > [[],[],[]] > 输出: [null,-1,-1] #### 题目解析: @@ -41,22 +39,12 @@ 下面我们来说一下双端队列。我们之前说过的队列,遵守先进先出的规则,双端队列则可以从队头出队,也可以从队尾出队。我们先通过一个视频来简单了解下双端队列。 - - ![](https://img-blog.csdnimg.cn/20210319154950406.gif) - - 我们可以用双端队列做辅助队列,用辅助队列来保存当前队列的最大值。我们同时定义一个普通队列和一个双端单调队列。普通队列就正常执行入队,出队操作。max_value 操作则返回咱们的双端队列的队头即可。下面我们来看一下代码的具体执行过程吧。 - - ![](https://img-blog.csdnimg.cn/20210319154716931.gif) - - - - 我们来对视频进行解析 1.我们需要维护一个单调双端队列,上面的队列则执行正常操作,下面的队列队头元素则为上面队列的最大值 @@ -74,10 +62,10 @@ class MaxQueue { public MaxQueue() { que = new LinkedList<>(); deq = new LinkedList<>(); - } - //获取最大值值,返回我们双端队列的对头即可,因为我们双端队列是单调递减的嘛 + } + //获取最大值值,返回我们双端队列的对头即可,因为我们双端队列是单调递减的嘛 public int max_value() { - return deq.isEmpty() ? -1 : deq.peekFirst(); + return deq.isEmpty() ? -1 : deq.peekFirst(); } //入队操作 public void push_back(int value) { @@ -94,11 +82,63 @@ class MaxQueue { public int pop_front() { if(que.isEmpty()) return -1; if (que.peek().equals(deq.peekFirst())) { - deq.pollFirst(); + deq.pollFirst(); } return que.poll(); } } ``` -### \ No newline at end of file +GO Code: + +```go +type MaxQueue struct { + que []int // 普通队列 + deq []int // 双端队列 + size int // que的队列长度 +} + + +func Constructor() MaxQueue { + return MaxQueue{ + que: []int{}, + deq: []int{}, + } +} + +// Is_empty 表示队列是否为空 +func (mq *MaxQueue) Is_empty() bool { + return mq.size == 0 +} + +// Max_value 取最大值值,返回我们双端队列的对头即可,因为我们双端队列是单调递减的嘛 +func (mq *MaxQueue) Max_value() int { + if mq.Is_empty() { return -1 } + return mq.deq[0] +} + +// Push_back 入队 +func (mq *MaxQueue) Push_back(value int) { + mq.que = append(mq.que, value) + // 维护单调递减队列 + for len(mq.deq) != 0 && mq.deq[len(mq.deq) - 1] < value { + mq.deq = mq.deq[:len(mq.deq) - 1] + } + mq.deq = append(mq.deq, value) + mq.size++ +} + +// Pop_front 弹出队列头元素,并且返回其值。 +func (mq *MaxQueue) Pop_front() int { + if mq.Is_empty() { return -1 } + ans := mq.que[0] + mq.que = mq.que[1:] + if mq.deq[0] == ans { + mq.deq = mq.deq[1:] + } + mq.size-- + return ans +} +``` + +### diff --git "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\216\245\351\233\250\346\260\264.md" "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\216\245\351\233\250\346\260\264.md" index 2bfce79..092f329 100644 --- "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\216\245\351\233\250\346\260\264.md" +++ "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\216\245\351\233\250\346\260\264.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [42. 接雨水](https://leetcode-cn.com/problems/trapping-rain-water/) @@ -24,58 +24,56 @@ 输出:9 ``` -示例3: +示例 3: ``` 输入:[4,3,2,0,1,1,5] 输出:13 ``` -> 上面是由数组 [4,3,2,0,1,1,5]表示的高度图,在这种情况下,可以接 13个单位的雨水(见下图)。 +> 上面是由数组 [4,3,2,0,1,1,5]表示的高度图,在这种情况下,可以接 13 个单位的雨水(见下图)。 ### 题目解析: -看了上面的示例刚开始刷题的同学可能有些懵逼,那我们结合图片来理解一下,我们就用示例3的例子进行举例,他的雨水到底代表的是什么。 +看了上面的示例刚开始刷题的同学可能有些懵逼,那我们结合图片来理解一下,我们就用示例 3 的例子进行举例,他的雨水到底代表的是什么。 ![](https://img-blog.csdnimg.cn/2021032013412768.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) - - 上图则为我们的题目描述,是不是理解了呢?你也可以这样理解我们在地上放置了若干高度的黄色箱子,他们中间有空隙,然后我们想在他们里面插入若干蓝色箱子,并保证插入之后,这些箱子的左视图和右视图都不能看到蓝色箱子。 好啦题目我们已经理解了,下面我们看一下解题思路。做这个这前我们可以先去看一下我们之前做过的另一道题目每日温度。这两道题目的思路差不多,都是利用了单调栈的思想,下面我们来看一下具体思路吧。 -这里我们也系统的说一下单调栈,单调栈含义就是栈内的元素是单调的,我们这两个题目用到的都是递减栈(相同也可以),我们依次将元素压入栈,如果当前元素小于等于栈顶元素则入栈,如果大于栈顶元素则先将栈顶不断出栈,直到当前元素小于或等于栈顶元素为止,然后再将当前元素入栈。就比如下图的4,想入栈的话则需要2,3出栈之后才能入栈,因为4大于他俩。 +这里我们也系统的说一下单调栈,单调栈含义就是栈内的元素是单调的,我们这两个题目用到的都是递减栈(相同也可以),我们依次将元素压入栈,如果当前元素小于等于栈顶元素则入栈,如果大于栈顶元素则先将栈顶不断出栈,直到当前元素小于或等于栈顶元素为止,然后再将当前元素入栈。就比如下图的 4,想入栈的话则需要 2,3 出栈之后才能入栈,因为 4 大于他俩。 在这里插入图片描述 -我们了解单调栈的含义下面我们来看一下接雨水问题到底该怎么做,其实原理也很简单,我们通过我们的例3来进行说明。 +我们了解单调栈的含义下面我们来看一下接雨水问题到底该怎么做,其实原理也很简单,我们通过我们的例 3 来进行说明。 -首先我们依次入栈4,3,2,0我们的数组前四个元素是符合单调栈规则的。但是我们的第五个1,是大于0的。那我们就需要0出栈1入栈。但是我们这样做是为了什么呢?有什么意义呢?别急我们来看下图。 +首先我们依次入栈 4,3,2,0 我们的数组前四个元素是符合单调栈规则的。但是我们的第五个 1,是大于 0 的。那我们就需要 0 出栈 1 入栈。但是我们这样做是为了什么呢?有什么意义呢?别急我们来看下图。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210320134213324.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) -上图我们的,4,3,2,0已经入栈了,我们的另一个元素为1,栈顶元素为0,栈顶下的元素为2。那么我们在这一层接到的雨水数量怎么算呢?2,0,1这三个元素可以接住的水为一个单位(见下图)这是我们第一层接到水的数量。 +上图我们的,4,3,2,0 已经入栈了,我们的另一个元素为 1,栈顶元素为 0,栈顶下的元素为 2。那么我们在这一层接到的雨水数量怎么算呢?2,0,1 这三个元素可以接住的水为一个单位(见下图)这是我们第一层接到水的数量。 注:能接到水的情况,肯定是中间低两边高,这样才可以。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210320134228696.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) -因为我们需要维护一个单调栈,所以我们则需要将0出栈1入栈,那么此时栈内元素为4,3,2,1。下一位元素为1,我们入栈,此时栈内元素为4,3,2,1,1。下一元素为5,栈顶元素为1,栈顶的下一元素仍为1,则需要再下一个元素,为2,那我们求当前层接到的水的数量。 +因为我们需要维护一个单调栈,所以我们则需要将 0 出栈 1 入栈,那么此时栈内元素为 4,3,2,1。下一位元素为 1,我们入栈,此时栈内元素为 4,3,2,1,1。下一元素为 5,栈顶元素为 1,栈顶的下一元素仍为 1,则需要再下一个元素,为 2,那我们求当前层接到的水的数量。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210320134249605.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) -我们是通过2,1,1,5这四个元素求得第二层的接水数为1*3=3;1是因为min(2-1,5-1)=min(1,4)得来的,大家可以思考一下木桶效应。装水的多少,肯定是按最短的那个木板来的,所以高度为1,3的话是因为5的索引为6,2的索引为2,他们之间共有三个元素(3,4,5)也就是3个单位。所以为6-2-1=3。 +我们是通过 2,1,1,5 这四个元素求得第二层的接水数为 1\*3=3;1 是因为 min(2-1,5-1)=min(1,4)得来的,大家可以思考一下木桶效应。装水的多少,肯定是按最短的那个木板来的,所以高度为 1,3 的话是因为 5 的索引为 6,2 的索引为 2,他们之间共有三个元素(3,4,5)也就是 3 个单位。所以为 6-2-1=3。 -将1出栈之后,我们栈顶元素就变成了2,下一元素变成了3,那么3,2,5这三个元素同样也可以接到水。 +将 1 出栈之后,我们栈顶元素就变成了 2,下一元素变成了 3,那么 3,2,5 这三个元素同样也可以接到水。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210320134307389.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) -这是第三层的接水情况,能够接到4个单位的水,下面我们继续出栈2,那么我们的4,3,5仍然可以接到水啊。 +这是第三层的接水情况,能够接到 4 个单位的水,下面我们继续出栈 2,那么我们的 4,3,5 仍然可以接到水啊。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210320134319646.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) -这是我们第四层接水的情况,一共能够接到5个单位的水,那么我们总的接水数加起来,那就是 +这是我们第四层接水的情况,一共能够接到 5 个单位的水,那么我们总的接水数加起来,那就是 1+3+4+5=13。你学会了吗?别急还有视频我们,我们再来深入理解一哈。 @@ -91,7 +89,7 @@ class Solution { //特殊情况 if(height.length <3){ return 0; - } + } for(int i = 0; i < height.length; i++){ while(!stack.isEmpty() && height[i] > height[stack.peek()]){ //栈顶元素 @@ -119,15 +117,35 @@ class Solution { } ``` +GO Code: + +```go +func trap(height []int) int { + stack := []int{} + water := 0 + // 最左边部分不会接雨水,左边持续升高时,stack都会弹出所有元素。 + for i := 0; i< len(height); i++ { + for len(stack) != 0 && height[i] > height[stack[len(stack) - 1]] { + popnum := stack[len(stack) - 1] + // 出现相同高度的情况(其实也可以不用处理,如果不处理,相同高度时后面的hig为0,会产生很多无效的计算) + for len(stack) != 0 && height[popnum] == height[stack[len(stack) - 1]] { + stack = stack[:len(stack) - 1] + } + if len(stack) == 0 { break } + le, ri := stack[len(stack) - 1], i + hig := min(height[ri], height[le]) - height[popnum] + wid := ri - le - 1 + water += wid * hig + } + stack = append(stack, i) + } + return water +} +func min(a, b int) int { + if a < b { return a } + return b +} +``` - - - - - - -### - - - +### diff --git "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\234\200\345\260\217\346\240\210.md" "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\234\200\345\260\217\346\240\210.md" index 7a01d73..c4a63e0 100644 --- "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\234\200\345\260\217\346\240\210.md" +++ "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\234\200\345\260\217\346\240\210.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [155. 最小栈](https://leetcode-cn.com/problems/min-stack/) @@ -15,8 +15,7 @@ 输入: -> ["MinStack","push","push","push","getMin","pop","top","getMin"] -> [[],[-2],[0],[-3],[],[],[],[]] +> ["MinStack","push","push","push","getMin","pop","top","getMin"] > [[],[-2],[0],[-3],[],[],[],[]] 输出: @@ -24,20 +23,15 @@ #### 题目解析 -感觉这个题目的难度就在读懂题意上面,读懂之后就没有什么难的了,我们在上面的滑动窗口的最大值已经进行了详细描述,其实这个题目和那个题目思路一致。该题让我们设计一个栈,该栈具有的功能有,push,pop,top等操作,并且能够返回栈的最小值。比如此时栈中的元素为 5,1,2,3。我们执行 getMin() ,则能够返回 1。这块是这个题目的精髓所在,见下图。 +感觉这个题目的难度就在读懂题意上面,读懂之后就没有什么难的了,我们在上面的滑动窗口的最大值已经进行了详细描述,其实这个题目和那个题目思路一致。该题让我们设计一个栈,该栈具有的功能有,push,pop,top 等操作,并且能够返回栈的最小值。比如此时栈中的元素为 5,1,2,3。我们执行 getMin() ,则能够返回 1。这块是这个题目的精髓所在,见下图。 ![单调栈](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/单调栈.46hlqk2xqza0.png) 我们一起先通过一个视频先看一下具体解题思路,通过视频一定可以整懂的,我们注意观察栈 B 内的元素。 - - ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210319162722440.gif) - - -我们来对视频进行解析 -1.我们执行入栈操作时,先观察需要入栈的元素是否小于栈 B 的栈顶元素,如果小于则两个栈都执行入栈操作。 +我们来对视频进行解析 1.我们执行入栈操作时,先观察需要入栈的元素是否小于栈 B 的栈顶元素,如果小于则两个栈都执行入栈操作。 2.栈 B 的栈顶元素则是栈 A 此时的最小值。则 getMin() 只需返回栈 B 的栈顶元素即可。 @@ -52,7 +46,7 @@ class MinStack { public MinStack() { A = new Stack<>(); B = new Stack<>(); - } + } //入栈,如果插入值,当前插入值小于栈顶元素,则入栈,栈顶元素保存的则为当前栈的最小元素 public void push(int x) { A.push(x); @@ -60,15 +54,15 @@ class MinStack { B.push(x); } - } + } //出栈,如果A出栈等于B栈顶元素,则说明此时栈内的最小元素改变了。 //这里需要使用 equals() 代替 == 因为 Stack 中存储的是 int 的包装类 Integer public void pop() { if (A.pop().equals(B.peek()) ) { B.pop(); } - } - //A栈的栈顶元素 + } + //A栈的栈顶元素 public int top() { return A.peek(); } @@ -79,4 +73,48 @@ class MinStack { } ``` -### \ No newline at end of file +GO Code: + +```go +type MinStack struct { + stack []int + minStk []int +} + +/** initialize your data structure here. */ +func Constructor() MinStack { + return MinStack{ + stack: []int{}, + minStk: []int{}, + } +} + +// Push 入栈,如果插入值,当前插入值小于栈顶元素,则入栈,栈顶元素保存的则为当前栈的最小元素 +func (m *MinStack) Push(x int) { + m.stack = append(m.stack, x) + if len(m.minStk) == 0 || m.minStk[len(m.minStk) - 1] >= x { + m.minStk = append(m.minStk, x) + } +} + +// Pop 出栈,如果stack出栈等于minStk栈顶元素,则说明此时栈内的最小元素改变了。 +func (m *MinStack) Pop() { + temp := m.stack[len(m.stack) - 1] + m.stack = m.stack[: len(m.stack) - 1] + if temp == m.minStk[len(m.minStk) - 1] { + m.minStk = m.minStk[: len(m.minStk) - 1] + } +} + +// Top stack的栈顶元素 +func (m *MinStack) Top() int { + return m.stack[len(m.stack) - 1] +} + +// GetMin minStk的栈顶元素 +func (m *MinStack) GetMin() int { + return m.minStk[len(m.minStk) - 1] +} +``` + +### diff --git "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274.md" "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274.md" index 3eb7fb3..28b0583 100644 --- "a/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274.md" +++ "b/animation-simulation/\345\215\225\350\260\203\351\230\237\345\210\227\345\215\225\350\260\203\346\240\210/\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [剑指 Offer 59 - I. 滑动窗口的最大值](https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/) @@ -16,18 +16,12 @@ ![](https://img-blog.csdnimg.cn/20210319154950406.gif) - - 好啦,我们了解双端队列是什么东东了,下面我们通过一个动画,来看一下代码的执行过程吧,相信各位一下就能够理解啦。 -我们就通过题目中的例子来表述。nums = [1,3,-1,-3,5,3,6,7], k = 3 - - +我们就通过题目中的例子来表述。nums = [1,3,-1,-3,5,3,6,7], k = 3 ![](https://img-blog.csdnimg.cn/20210319162114967.gif) - - 不知道通过上面的例子能不能给各位描述清楚,如果不能的话,我再加把劲,各位看官,请接着往下看。 我们将执行过程进行拆解。 @@ -79,3 +73,36 @@ class Solution { } ``` +GO Code: + +```go +func maxSlidingWindow(nums []int, k int) []int { + l := len(nums) + if l == 0 { + return nums + } + + arr := []int{} + // 维护一个单调递减的双向队列 + deque := []int{} + for i := 0; i < k; i++ { + for len(deque) != 0 && deque[len(deque) - 1] < nums[i] { + deque = deque[:len(deque) - 1] + } + deque = append(deque, nums[i]) + } + + arr = append(arr, deque[0]) + for i := k; i < l; i++ { + if nums[i - k] == deque[0] { + deque = deque[1:] + } + for len(deque) != 0 && deque[len(deque) - 1] < nums[i] { + deque = deque[:len(deque) - 1] + } + deque = append(deque, nums[i]) + arr = append(arr, deque[0]) + } + return arr +} +``` diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/BF\347\256\227\346\263\225.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/BF\347\256\227\346\263\225.md" index 8c2db36..f29f9f9 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/BF\347\256\227\346\263\225.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/BF\347\256\227\346\263\225.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 > 为保证代码严谨性,文中所有代码均在 leetcode 刷题网站 AC ,大家可以放心食用。 @@ -24,21 +24,17 @@ 通过上面的一个例子,让我们简单了解了字符串匹配。 -字符串匹配:设 S 和 T 是给定的两个串,在主串 S 中找到模式串 T 的过程称为字符串匹配,如果在主串 S 中找到 模式串 T ,则称匹配成功,函数返回 T 在 S 中首次出现的位置,否则匹配不成功,返回 -1。 +字符串匹配:设 S 和 T 是给定的两个串,在主串 S 中找到模式串 T 的过程称为字符串匹配,如果在主串 S 中找到 模式串 T ,则称匹配成功,函数返回 T 在 S 中首次出现的位置,否则匹配不成功,返回 -1。 例: - - ![字符串匹配](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/字符串匹配.3q9wqbh8ws40.png) - - 在上图中,我们试图找到模式 T = baab,在主串 S = abcabaabcabac 中第一次出现的位置,即为红色阴影部分, T 第一次在 S 中出现的位置下标为 4 ( 字符串的首位下标是 0 ),所以返回 4。如果模式串 T 没有在主串 S 中出现,则返回 -1。 解决上面问题的算法我们称之为字符串匹配算法,今天我们来介绍三种字符串匹配算法,大家记得打卡呀,说不准面试的时候就问到啦。 -## BF算法(Brute Force) +## BF 算法(Brute Force) 这个算法很容易理解,就是我们将模式串和主串进行比较,一致时则继续比较下一字符,直到比较完整个模式串。不一致时则将模式串后移一位,重新从模式串的首位开始对比,重复刚才的步骤下面我们看下这个方法的动图解析,看完肯定一下就能搞懂啦。 @@ -50,7 +46,7 @@ #### 题目描述 -给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。 +给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从 0 开始)。如果不存在,则返回 -1。 示例 1: @@ -74,7 +70,7 @@ Java Code: class Solution { public int strStr(String haystack, String needle) { int haylen = haystack.length(); - int needlen = needle.length(); + int needlen = needle.length(); //特殊情况 if (haylen < needlen) { return -1; @@ -95,7 +91,7 @@ class Solution { //匹配成功 if (j == needlen) { return i; - } + } } return -1; @@ -105,7 +101,7 @@ class Solution { Python Code: -```python +```python from typing import List class Solution: def strStr(self, haystack: str, needle: str)->int: @@ -130,8 +126,7 @@ class Solution: return -1 ``` - -我们看一下BF算法的另一种算法(显示回退),其实原理一样,就是对代码进行了一下修改,只要是看完咱们的动图,这个也能够一下就能看懂,大家可以结合下面代码中的注释和动图进行理解。 +我们看一下 BF 算法的另一种算法(显示回退),其实原理一样,就是对代码进行了一下修改,只要是看完咱们的动图,这个也能够一下就能看懂,大家可以结合下面代码中的注释和动图进行理解。 Java Code: diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/BM.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/BM.md" index cc2bddc..1ce7885 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/BM.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/BM.md" @@ -1,17 +1,15 @@ -## BM算法(Boyer-Moore) +## BM 算法(Boyer-Moore) -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 我们刚才说过了 BF 算法,但是 BF 算法是有缺陷的,比如我们下面这种情况 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210401200433751.png) - - 如上图所示,如果我们利用 BF 算法,遇到不匹配字符时,每次右移一位模式串,再重新从头进行匹配,我们观察一下,我们的模式串 abcdex 中每个字符都不一样,但是我们第一次进行字符串匹配时,abcde 都匹配成功,到 x 时失败,又因为模式串每位都不相同,所以我们不需要再每次右移一位,再重新比较,我们可以直接跳过某些步骤。如下图 ![BM2](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/BM2.141fhslg6vek.png) @@ -24,7 +22,7 @@ 我们之前的 BF 算法是从前往后进行比较 ,BM 算法是从后往前进行比较,我们来看一下具体过程,我们还是利用上面的例子。 -![BM4](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/BM4.2mayfaccj3i0.png) +![BM4](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/BM4.2mayfaccj3i0.png) BM 算法是从后往前进行比较,此时我们发现比较的第一个字符就不匹配,我们将**主串**这个字符称之为**坏字符**,也就是 f ,我们发现坏字符之后,模式串 T 中查找是否含有该字符(f),我们发现并不存在 f,此时我们只需将模式串右移到坏字符的后面一位即可。如下图 @@ -56,16 +54,10 @@ BM 算法是从后往前进行比较,此时我们发现比较的第一个字 我们上面一共介绍了三种移动情况,分别是下方的模式串中没有发现与坏字符对应的字符,发现一个对应字符,发现两个。这三种情况我们分别移动不同的位数,那我们是根据依据什么来决定移动位数的呢?下面我们给图中的字符加上下标。见下图 - - ![坏字符移动规则](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/坏字符移动规则.48oh1msdypy0.png) - - 下面我们来考虑一下这种情况。 - - ![换字符bug](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/换字符bug.24av6jslzh40.png) 此时这种情况肯定是不行的,不往右移动,甚至还有可能左移,那么我们有没有什么办法解决这个问题呢?继续往下看吧。 @@ -78,7 +70,7 @@ BM 算法是从后往前进行比较,此时我们发现比较的第一个字 这里如果我们按照坏字符进行移动是不合理的,这时我们可以使用好后缀规则,那么什么是好后缀呢? -BM 算法是从右往左进行比较,发现坏字符的时候此时 cac 已经匹配成功,在红色阴影处发现坏字符。此时已经匹配成功的 cac 则为我们的好后缀,此时我们拿它在模式串中查找,如果找到了另一个和好后缀相匹配的串,那我们就将另一个和**好后缀相匹配**的串 ,滑到和好后缀对齐的位置。 +BM 算法是从右往左进行比较,发现坏字符的时候此时 cac 已经匹配成功,在红色阴影处发现坏字符。此时已经匹配成功的 cac 则为我们的好后缀,此时我们拿它在模式串中查找,如果找到了另一个和好后缀相匹配的串,那我们就将另一个和**好后缀相匹配**的串 ,滑到和好后缀对齐的位置。 是不是感觉有点拗口,没关系,我们看下图,红色代表坏字符,绿色代表好后缀 @@ -114,8 +106,6 @@ BM 算法是从右往左进行比较,发现坏字符的时候此时 cac 已 > Boyer R S,Moore J S. A fast string searching algorithm[J]. Communications of the ACM,1977,10: 762-772. - - 之前我们刚开始说坏字符的时候,是不是有可能会出现负值的情况,即往左移动的情况,所以我们为了解决这个问题,我们可以分别计算好后缀和坏字符往后滑动的位数**(好后缀不为 0 的情况)**,然后取两个数中最大的,作为模式串往后滑动的位数。 ![五好后缀](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/五好后缀.6wvqxa4um040.png) @@ -226,7 +216,7 @@ class Solution: haylen = len(haystack) needlen = len(needle) return self.bm(haystack, haylen, needle, needlen) - + # 用来求坏字符情况下移动位数 def badChar(self, b: str, m: int, bc: List[int]): # 初始化 @@ -236,7 +226,7 @@ class Solution: for i in range(0, m,): ascii = ord(b[i]) bc[ascii] = i# 下标 - + # 用来求好后缀条件下的移动位数 def goodSuffix(self, b: str, m: int, suffix: List[int], prefix: List[bool]): # 初始化 @@ -252,7 +242,7 @@ class Solution: suffix[k] = j + 1 if j == -1: prefix[k] = True - + def bm(self, a: str, n: int, b: str, m: int)->int: bc = [0] * 256# 创建一个数组用来保存最右边字符的下标 self.badChar(b, m, bc) @@ -283,7 +273,7 @@ class Solution: # 移动 i += max(x, y) return -1 - + # j代表坏字符的下标 def move(j: int, m: int, suffix_index: List[int], ispre: List[bool])->int: # 好后缀长度 @@ -303,4 +293,3 @@ class Solution: 我们来理解一下我们代码中用到的两个数组,因为两个规则的移动位数,只与模式串有关,与主串无关,所以我们可以提前求出每种情况的移动情况,保存到数组中。 ![头缀函数](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/头缀函数.145da63ig3s0.png) - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/Hash\350\241\250\347\232\204\351\202\243\344\272\233\344\272\213.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/Hash\350\241\250\347\232\204\351\202\243\344\272\233\344\272\213.md" index ec3fe4f..d9a26d7 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/Hash\350\241\250\347\232\204\351\202\243\344\272\233\344\272\213.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/Hash\350\241\250\347\232\204\351\202\243\344\272\233\344\272\213.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 # 散列(哈希)表总结 @@ -18,8 +18,6 @@ ![image-20201117132633797](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201117132633797.5dlsgarvplc0.png) - - 上面的后期结账的过程则模拟了我们的散列表查找,那么在计算机中是如何使用进行查找的呢? ### 散列表查找步骤 @@ -36,16 +34,14 @@ 我们假设某个函数为 **f**,使得 -​ **存储位置 = f (关键字)** +​ **存储位置 = f (关键字)** -**输入:关键字** **输出:存储位置(散列地址)** +**输入:关键字** **输出:存储位置(散列地址)** 那样我们就能通过查找关键字**不需要比较**就可获得需要的记录的存储位置。这种存储技术被称为散列技术。散列技术是在通过记录的存储位置和它的关键字之间建立一个确定的对应关系 **f** ,使得每个关键字 **key** 都对应一个存储位置 **f(key)**。见下图 ![image-20201117145348616](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201117145348616.7l7om0vd7ww0.png) - - 这里的 **f** 就是我们所说的散列函数(哈希)函数。我们利用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间就是我们本文的主人公------**散列(哈希)表** 上图为我们描述了用散列函数将关键字映射到散列表,但是大家有没有考虑到这种情况,那就是将关键字映射到同一个槽中的情况,即 **f(k4) = f(k3)** 时。这种情况我们将其称之为**冲突**,**k3** 和 **k4**则被称之为散列函数 **f** 的**同义词**,如果产生这种情况,则会让我们查找错误。幸运的是我们能找到有效的方法解决冲突。 @@ -64,7 +60,7 @@ #### 直接定址法 -如果我们对盈利为0-9的菜品设计哈希表,我们则直接可以根据作为地址,则 **f(key) = key**; +如果我们对盈利为 0-9 的菜品设计哈希表,我们则直接可以根据作为地址,则 **f(key) = key**; 即下面这种情况。 @@ -72,9 +68,9 @@ 有没有感觉上面的图很熟悉,没错我们经常用的数组其实就是一张哈希表,关键码就是数组的索引下标,然后我们通过下标直接访问数组中的元素。 -另外我们假设每道菜的成本为50块,那我们还可以根据盈利+成本来作为地址,那么则 f(key) = key + 50。也就是说我们可以根据线性函数值作为散列地址。 +另外我们假设每道菜的成本为 50 块,那我们还可以根据盈利+成本来作为地址,那么则 f(key) = key + 50。也就是说我们可以根据线性函数值作为散列地址。 -​ **f(key) = a * key + b** **a,b均为常数** +​ **f(key) = a \* key + b** **a,b 均为常数** 优点:简单、均匀、无冲突。 @@ -94,7 +90,7 @@ 其实这个方法也很简单,也是处理我们的关键字然后用作我们的散列地址,主要思路是将关键字从左到右分割成位数相等的几部分,然后叠加求和,并按散列表表长,取后几位作为散列地址。 -比如我们的关键字是123456789,则我们分为三部分 123 ,456 ,789 然后将其相加得 1368 然后我们再取其后三位 368 作为我们的散列地址。 +比如我们的关键字是 123456789,则我们分为三部分 123 ,456 ,789 然后将其相加得 1368 然后我们再取其后三位 368 作为我们的散列地址。 优点:事先不需要知道关键字情况 @@ -104,26 +100,26 @@ 在用来设计散列函数的除法散列法中,通过取 key 除以 p 的余数,将关键字映射到 p 个槽中的某一个上,对于散列表长度为 m 的散列函数公式为 -​ **f(k) = k mod p (p <= m)** +​ **f(k) = k mod p (p <= m)** -例如,如果散列表长度为 12,即 m = 12 ,我们的参数 p 也设为12,**那 k = 100时 f(k) = 100 % 12 = 4** +例如,如果散列表长度为 12,即 m = 12 ,我们的参数 p 也设为 12,**那 k = 100 时 f(k) = 100 % 12 = 4** 由于只需要做一次除法操作,所以除法散列法是非常快的。 -由上面的公式可以看出,该方法的重点在于 p 的取值,如果 p 值选的不好,就可能会容易产生同义词。见下面这种情况。我们哈希表长度为6,我们选择6为p值,则有可能产生这种情况,所有关键字都得到了0这个地址数。![image-20201117191635083](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201117191635083.4z4tf8bvv2g0.png) +由上面的公式可以看出,该方法的重点在于 p 的取值,如果 p 值选的不好,就可能会容易产生同义词。见下面这种情况。我们哈希表长度为 6,我们选择 6 为 p 值,则有可能产生这种情况,所有关键字都得到了 0 这个地址数。![image-20201117191635083](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201117191635083.4z4tf8bvv2g0.png) 那我们在选用除法散列法时选取 p 值时应该遵循怎样的规则呢? -- m 不应为 2 的幂,因为如果 m = 2^p ,则 f(k) 就是 k 的 p 个最低位数字。例 12 % 8 = 4 ,12的二进制表示位1100,后三位为100。 -- 若散列表长为 m ,通常 p 为 小于或等于表长(最好接近m)的最小质数或不包含小于 20 质因子的合数。 +- m 不应为 2 的幂,因为如果 m = 2^p ,则 f(k) 就是 k 的 p 个最低位数字。例 12 % 8 = 4 ,12 的二进制表示位 1100,后三位为 100。 +- 若散列表长为 m ,通常 p 为 小于或等于表长(最好接近 m)的最小质数或不包含小于 20 质因子的合数。 -> **合数:**合数是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。 +> **合数:**合数是指在大于 1 的整数中除了能被 1 和本身整除外,还能被其他数(0 除外)整除的数。 > > **质因子**:质因子(或质因数)在数论里是指能整除给定正整数的质数。 ![质因子](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/质因子.75q2ya0sdts0.png) -这里的2,3,5为质因子 +这里的 2,3,5 为质因子 还是上面的例子,我们根据规则选择 5 为 p 值,我们再来看。这时我们发现只有 6 和 36 冲突,相对来说就好了很多。 @@ -142,17 +138,17 @@ 散列函数为 -​ **f (k) = ⌊ m(kA mod 1) ⌋** +​ **f (k) = ⌊ m(kA mod 1) ⌋** 这里的 **kA mod 1** 的含义是取 keyA 的小数部分,即 **kA - ⌊kA⌋** 。 -优点:对 m 的选择不是特别关键,一般选择它为 2 的某个幂次(m = 2 ^ p ,p为某个整数) +优点:对 m 的选择不是特别关键,一般选择它为 2 的某个幂次(m = 2 ^ p ,p 为某个整数) 应用场景:不知道关键字情况 #### 平方取中法 -这个方法就比较简单了,假设关键字是 321,那么他的平方就是 103041,再抽取中间的 3 位就是 030 或 304 用作散列地址。再比如关键字是 1234 那么它的平方就是 1522756 ,抽取中间 3 位就是 227 用作散列地址. +这个方法就比较简单了,假设关键字是 321,那么他的平方就是 103041,再抽取中间的 3 位就是 030 或 304 用作散列地址。再比如关键字是 1234 那么它的平方就是 1522756 ,抽取中间 3 位就是 227 用作散列地址. 优点:灵活,适用范围广泛 @@ -160,13 +156,13 @@ #### 随机数法 -故名思意,取关键字的随机函数值为它的散列地址。也就是 **f(key) = random(key)**。这里的random是 随机函数。 +故名思意,取关键字的随机函数值为它的散列地址。也就是 **f(key) = random(key)**。这里的 random 是 随机函数。 优点:易实现 适用场景:关键字的长度不等时 -上面我们的例子都是通过数字进行举例,那么如果是字符串可不可以作为键呢?当然也是可以的,各种各样的符号我们都可以转换成某种数字来对待,比如我们经常接触的ASCII 码,所以是同样适用的。 +上面我们的例子都是通过数字进行举例,那么如果是字符串可不可以作为键呢?当然也是可以的,各种各样的符号我们都可以转换成某种数字来对待,比如我们经常接触的 ASCII 码,所以是同样适用的。 以上就是常用的散列函数构造方法,其实他们的中心思想是一致的,将关键字经过加工处理之后变成另外一个数字,而这个数字就是我们的存储位置,是不是有一种间谍传递情报的感觉。 @@ -200,29 +196,25 @@ 下面我们先来看一下线性探测,公式: -> **f,(key) = ( f(key) + di ) MOD m(di = 1,2,3,4,5,6....m-1)** +> **f,(key) = ( f(key) + di ) MOD m(di = 1,2,3,4,5,6....m-1)** -我们来看一个例子,我们的关键字集合为{12,67,56,16,25,37,22,29,15,47,48,21},表长为12,我们再用散列函数 **f(key) = key mod 12。** +我们来看一个例子,我们的关键字集合为{12,67,56,16,25,37,22,29,15,47,48,21},表长为 12,我们再用散列函数 **f(key) = key mod 12。** 我们求出每个 key 的 f(key)见下表 ![image-20201118121740324](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201118121740324.26hu17vbf5fk.png) -我们查看上表发现,前五位的 **f(key)** 都不相同,即没有冲突,可以直接存入,但是到了第六位 **f(37) = f(25) = 1**,那我们就需要利用上面的公式 **f(37) = f (f(37) + 1 ) mod 12 = 2**,这其实就是我们的订包间的做法。下面我们看一下将上面的所有数存入哈希表是什么情况吧。 +我们查看上表发现,前五位的 **f(key)** 都不相同,即没有冲突,可以直接存入,但是到了第六位 **f(37) = f(25) = 1**,那我们就需要利用上面的公式 **f(37) = f (f(37) + 1 ) mod 12 = 2**,这其实就是我们的订包间的做法。下面我们看一下将上面的所有数存入哈希表是什么情况吧。 ![image-20201118121801671](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201118121801671.6g0iqe60o9c0.png) - - 我们把这种解决冲突的开放地址法称为**线性探测法**。下面我们通过视频来模拟一下线性探测法的存储过程。 - - ![线性探测法](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/线性探测法.36c7dqr0r120.gif) 另外我们在解决冲突的时候,会遇到 48 和 37 虽然不是同义词,却争夺一个地址的情况,我们称其为**堆积**。因为堆积使得我们需要不断的处理冲突,插入和查找效率都会大大降低。 -通过上面的视频我们应该了解了线性探测的执行过程了,那么我们考虑一下这种情况,若是我们的最后一位不为21,为 34 时会有什么事情发生呢? +通过上面的视频我们应该了解了线性探测的执行过程了,那么我们考虑一下这种情况,若是我们的最后一位不为 21,为 34 时会有什么事情发生呢? ![image-20201118133459372](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201118133459372.2vdk7gxr7hg0.png) @@ -230,15 +222,15 @@ ##### 二次探测法 -其实理解了我们的上个例子之后,这个一下就能整明白了,根本不用费脑子,这个方法就是更改了一下di的取值 +其实理解了我们的上个例子之后,这个一下就能整明白了,根本不用费脑子,这个方法就是更改了一下 di 的取值 -> **线性探测: f,(key) = ( f(key) + di ) MOD m(di = 1,2,3,4,5,6....m-1)** +> **线性探测: f,(key) = ( f(key) + di ) MOD m(di = 1,2,3,4,5,6....m-1)** > -> **二次探测:** **f,(key) = ( f(key) + di ) MOD m(di =1^2 , -1^2 , 2^2 , -2^2 .... q^2, -q^2, q<=m/2)** +> **二次探测:** **f,(key) = ( f(key) + di ) MOD m(di =1^2 , -1^2 , 2^2 , -2^2 .... q^2, -q^2, q<=m/2)** -**注:这里的是 -1^2 为负值 而不是 (-1)^2** +**注:这里的是 -1^2 为负值 而不是 (-1)^2** -所以对于我们的34来说,当di = -1时,就可以找到空位置了。 +所以对于我们的 34 来说,当 di = -1 时,就可以找到空位置了。 ![image-20201118142851095](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201118142851095.5hdys12bsgg0.png) @@ -266,9 +258,9 @@ 这个方法其实也特别简单,利用不同的哈希函数再求得一个哈希地址,直到不出现冲突为止。 -> **f,(key) = RH,( key ) (i = 1,2,3,4.....k)** +> **f,(key) = RH,( key ) (i = 1,2,3,4.....k)** -这里的RH,就是不同的散列函数,你可以把我们之前说过的那些散列函数都用上,每当发生冲突时就换一个散列函数,相信总有一个能够解决冲突的。这种方法能使关键字不产生聚集,但是代价就是增加了计算时间。是不是很简单啊。 +这里的 RH,就是不同的散列函数,你可以把我们之前说过的那些散列函数都用上,每当发生冲突时就换一个散列函数,相信总有一个能够解决冲突的。这种方法能使关键字不产生聚集,但是代价就是增加了计算时间。是不是很简单啊。 #### 链地址法 @@ -286,14 +278,12 @@ 上面我们都是遇到冲突之后,就换地方。那么我们有没有不换地方的办法呢?那就是我们现在说的链地址法。 -还记得我们说过得同义词吗?就是 key 不同 f(key) 相同的情况,我们将这些同义词存储在一个单链表中,这种表叫做同义词子表,散列表中只存储同义词子表的头指针。我们还是用刚才的例子,关键字集合为{12,67,56,16,25,37,22,29,15,47,48,21},表长为12,我们再用散列函数 **f(key) = key mod 12。**我们用了链地址法之后就再也不存在冲突了,无论有多少冲突,我们只需在同义词子表中添加结点即可。下面我们看下链地址法的存储情况。 +还记得我们说过得同义词吗?就是 key 不同 f(key) 相同的情况,我们将这些同义词存储在一个单链表中,这种表叫做同义词子表,散列表中只存储同义词子表的头指针。我们还是用刚才的例子,关键字集合为{12,67,56,16,25,37,22,29,15,47,48,21},表长为 12,我们再用散列函数 **f(key) = key mod 12。**我们用了链地址法之后就再也不存在冲突了,无论有多少冲突,我们只需在同义词子表中添加结点即可。下面我们看下链地址法的存储情况。 ![image-20201118161354566](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/image-20201118161354566.139yir8z205s.png) 链地址法虽然能够不产生冲突,但是也带来了查找时需要遍历单链表的性能消耗,有得必有失嘛。 - - #### 公共溢出区法 下面我们再来看一种新的方法,这回大鹏又要来吃饭了。 @@ -318,7 +308,7 @@ 下面我们来看一下散列表查找算法的实现 -首先需要定义散列列表的结构以及一些相关常数,其中elem代表散列表数据存储数组,count代表的是当前插入元素个数,size代表哈希表容量,NULLKEY散列表初始值,然后我们如果查找成功就返回索引,如果不存在该元素就返回元素不存在。 +首先需要定义散列列表的结构以及一些相关常数,其中 elem 代表散列表数据存储数组,count 代表的是当前插入元素个数,size 代表哈希表容量,NULLKEY 散列表初始值,然后我们如果查找成功就返回索引,如果不存在该元素就返回元素不存在。 我们将哈希表初始化,为数组元素赋初值。 @@ -336,7 +326,7 @@ (1)通过哈希函数(同插入时一样),将 key 转成数组下标 -(2)通过数组下标找到 key值,如果 key 一致,则查找成功,否则利用线性探测法继续查找。 +(2)通过数组下标找到 key 值,如果 key 一致,则查找成功,否则利用线性探测法继续查找。 ![第三张](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/第三张.4iqbtyns3li0.png) @@ -346,7 +336,7 @@ ### 散列表性能分析 -如果没有冲突的话,散列查找是我们查找中效率最高的,时间复杂度为O(1),但是没有冲突的情况是一种理想情况,那么散列查找的平均查找长度取决于哪些方面呢? +如果没有冲突的话,散列查找是我们查找中效率最高的,时间复杂度为 O(1),但是没有冲突的情况是一种理想情况,那么散列查找的平均查找长度取决于哪些方面呢? **1.散列函数是否均匀** @@ -360,8 +350,6 @@ 本来想在上文中提到装填因子的,但是后来发现即使没有说明也不影响我们对哈希表的理解,下面我们来看一下装填因子的总结 -> 装填因子 α = 填入表中的记录数 / 散列表长度 - -散列因子则代表着散列表的装满程度,表中记录越多,α就越大,产生冲突的概率就越大。我们上面提到的例子中 表的长度为12,填入记录数为6,那么此时的 α = 6 / 12 = 0.5 所以说当我们的 α 比较大时再填入元素那么产生冲突的可能性就非常大了。所以说散列表的平均查找长度取决于装填因子,而不是取决于记录数。所以说我们需要做的就是选择一个合适的装填因子以便将平均查找长度限定在一个范围之内。 - +> 装填因子 α = 填入表中的记录数 / 散列表长度 +散列因子则代表着散列表的装满程度,表中记录越多,α 就越大,产生冲突的概率就越大。我们上面提到的例子中 表的长度为 12,填入记录数为 6,那么此时的 α = 6 / 12 = 0.5 所以说当我们的 α 比较大时再填入元素那么产生冲突的可能性就非常大了。所以说散列表的平均查找长度取决于装填因子,而不是取决于记录数。所以说我们需要做的就是选择一个合适的装填因子以便将平均查找长度限定在一个范围之内。 diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/KMP.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/KMP.md" index d811406..3359fdb 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/KMP.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/KMP.md" @@ -1,10 +1,10 @@ -## KMP算法(Knuth-Morris-Pratt) +## KMP 算法(Knuth-Morris-Pratt) -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 我们刚才讲了 BM 算法,虽然不是特别容易理解,但是如果你用心看的话肯定可以看懂的,我们再来看一个新的算法,这个算法是考研时必考的算法。实际上 BM 和 KMP 算法的本质是一样的,你理解了 BM 再来理解 KMP 那就是分分钟的事啦。 @@ -30,7 +30,7 @@ ![原理](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/原理.bghc3ecm4z4.png) -好啦,看完上面的图,KMP的核心原理已经基本搞定了,但是我们现在的问题是,我们应该怎么才能知道他的最长公共前后缀的长度是多少呢?怎么知道移动多少位呢? +好啦,看完上面的图,KMP 的核心原理已经基本搞定了,但是我们现在的问题是,我们应该怎么才能知道他的最长公共前后缀的长度是多少呢?怎么知道移动多少位呢? 刚才我们在 BM 中说到,我们移动位数跟主串无关,只跟模式串有关,跟我们的 bc,suffix,prefix 数组的值有关,我们通过这些数组就可以知道我们每次移动多少位啦,其实 KMP 也有一个数组,这个数组叫做 next 数组,那么这个 next 数组存的是什么呢? @@ -141,7 +141,7 @@ class Solution: nelen = len(needle) # 返回下标 return self.kmp(haystack, halen, needle, nelen) - + def kmp(self, hasyarr: str, halen: int, nearr: str, nelen: int)->int: # 获取next 数组 next = self.next(nearr, nelen) @@ -183,5 +183,3 @@ class Solution: next[i] = k return next ``` - - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/read.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/read.md" index 8d977ca..5ebc33f 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/read.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/read.md" @@ -18,13 +18,9 @@ **所以基地里的题解都尽量用动画模拟,加深大家对题目的理解。往下看吧** - - > **PS:基地的所有代码均在刷题网站 AC 大家可以放心食用** - - -**如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 [tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg) ,备注 github + 题目 + 问题 向我反馈** +**如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 [tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg) ,备注 github + 题目 + 问题 向我反馈** **如果老哥觉得仓库很用心的话,麻烦老哥点个 star ,这也是我一直更新下去的动力!感谢支持。** @@ -32,9 +28,8 @@ **另外想要进阶的老哥可以看下我之前看过的这个谷歌大神的刷题笔记。** -**刷题笔记**:链接:https://pan.baidu.com/s/1gNIhOv83ZMxDEEFXLWChuA 提取码:chef +**刷题笔记**:链接:https://pan.baidu.com/s/1gNIhOv83ZMxDEEFXLWChuA 提取码:chef -**希望手机阅读的同学可以来我的 [公众号:袁厨的算法小屋](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信图片_20210320152235.2c1f5hy6gmas.png)两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[刷题小队](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。** +**希望手机阅读的同学可以来我的 [公众号:程序厨](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信图片_20210320152235.2c1f5hy6gmas.png)两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[刷题小队](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。**
- diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\205\263\344\272\216\346\240\210\345\222\214\351\230\237\345\210\227\347\232\204\351\202\243\344\272\233\344\272\213.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\205\263\344\272\216\346\240\210\345\222\214\351\230\237\345\210\227\347\232\204\351\202\243\344\272\233\344\272\213.md" index c839880..ff4489a 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\205\263\344\272\216\346\240\210\345\222\214\351\230\237\345\210\227\347\232\204\351\202\243\344\272\233\344\272\213.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\205\263\344\272\216\346\240\210\345\222\214\351\230\237\345\210\227\347\232\204\351\202\243\344\272\233\344\272\213.md" @@ -1,10 +1,10 @@ # 希望这篇文章能合你的胃口 -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 大家在学习数据结构的时候应该都学习过栈和队列,对他俩的原理应该很熟悉了,栈是先进后出,队列是后进后出。下面我们通过这篇文章来帮助小伙伴们回忆一下栈和队列的那些事。 @@ -24,11 +24,11 @@ ### 栈模型 -**栈(stack)是限制插入和删除只能在一个位置上进行的表**,该位置是表的末端叫做栈的顶(top),对栈的基本操作有push(进栈)和pop(出栈),前者相当于插入,后者则是删除最后插入的元素。 +**栈(stack)是限制插入和删除只能在一个位置上进行的表**,该位置是表的末端叫做栈的顶(top),对栈的基本操作有 push(进栈)和 pop(出栈),前者相当于插入,后者则是删除最后插入的元素。 -栈的另一个名字是LIFO(先进后出)表。普通的清空栈的操作和判断是否空栈的测试都是栈的操作指令系统的一部分,我们对栈能做的基本上也就是push和pop操作。 +栈的另一个名字是 LIFO(先进后出)表。普通的清空栈的操作和判断是否空栈的测试都是栈的操作指令系统的一部分,我们对栈能做的基本上也就是 push 和 pop 操作。 -注:该图描述的模型只象征着push是输入操作,pop和top是输出操作 +注:该图描述的模型只象征着 push 是输入操作,pop 和 top 是输出操作 ![栈和队列1](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/栈和队列1.1wjbrl9iudk0.png) @@ -38,9 +38,9 @@ ### 栈的实现 -因为栈是一个表,因此能够实现表的方法都可以实现栈,ArrayList和LinkedList都可以支持栈操作。 +因为栈是一个表,因此能够实现表的方法都可以实现栈,ArrayList 和 LinkedList 都可以支持栈操作。 -刷题时我们可以直接使用Stack类来进行创建一个栈。刷题时我们可以通过下列代码创建一个栈。下面两种方式哪种都可以使用。 +刷题时我们可以直接使用 Stack 类来进行创建一个栈。刷题时我们可以通过下列代码创建一个栈。下面两种方式哪种都可以使用。 ``` Deque stack = new LinkedList();//类型为TreeNode @@ -53,7 +53,7 @@ Stack stack = new Stack(); 不知道大家是否还记得那句口令,先乘除,后加减,从左算到右,有括号的话就先算括号里面的。这是我们做小学数学所用到的。四则运算中括号也是其中的一部分,先乘除后加减使运算变的复杂,加上括号后甚之,那么我们有什么办法可以让其变的更好处理呢?波兰数学家**Jan Łukasiewicz**想到了一种不需要括号的后缀表达式,,我们也将它称之为逆波兰表示。不用数学家名字命名的原因有些尴尬,居然是因为他的名字太复杂了,所以用了国籍来表示而不是姓名。所以各位小伙伴以后给孩子起名字的时候不要太复杂啊。 -> 扬·武卡谢维奇([波兰语](https://baike.baidu.com/item/波兰语):*Jan Łukasiewicz*,1878年12月21日[乌克兰](https://baike.baidu.com/item/乌克兰)利沃夫 - 1956年2月13日爱尔兰都柏林),[波兰](https://baike.baidu.com/item/波兰)数学家,主要致力于[数理逻辑](https://baike.baidu.com/item/数理逻辑)的研究。著名的波兰表示法逆波兰表示法就是他的研究成果。 +> 扬·武卡谢维奇([波兰语](https://baike.baidu.com/item/波兰语):_Jan Łukasiewicz_,1878 年 12 月 21 日[乌克兰](https://baike.baidu.com/item/乌克兰)利沃夫 - 1956 年 2 月 13 日爱尔兰都柏林),[波兰](https://baike.baidu.com/item/波兰)数学家,主要致力于[数理逻辑](https://baike.baidu.com/item/数理逻辑)的研究。著名的波兰表示法逆波兰表示法就是他的研究成果。 #### 中缀表达式转为后缀表达式 @@ -61,9 +61,9 @@ Stack stack = new Stack(); 例 -中缀:9 + ( 3 - 1 ) * 3 + 10 / 2 +中缀:9 + ( 3 - 1 ) \* 3 + 10 / 2 -后缀:9 3 1 - 3 * + 10 2 / + +后缀:9 3 1 - 3 \* + 10 2 / + 规则 @@ -79,11 +79,11 @@ Stack stack = new Stack(); #### 后缀表达式计算结果 -中缀:9 + ( 3 - 1 ) * 3 + 10 / 2=20 +中缀:9 + ( 3 - 1 ) \* 3 + 10 / 2=20 -后缀:9 3 1 - 3 * + 10 2 / + +后缀:9 3 1 - 3 \* + 10 2 / + -后缀表达式的值也为20,那么我们来了解一下计算机是如何将后缀表达式计算为20的。 +后缀表达式的值也为 20,那么我们来了解一下计算机是如何将后缀表达式计算为 20 的。 规则: @@ -95,8 +95,6 @@ Stack stack = new Stack(); ![后缀运算](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/后缀运算.38havvkp8k40.gif) - - 注:为了用动图把逻辑整的清晰明了,十几秒的动图,就要整半个多小时,改进好几遍。如果觉得图片对你有帮助的话就点个赞和在看吧。 ## 这是队列 @@ -117,7 +115,7 @@ Stack stack = new Stack(); ### 队列的实现 -队列我们在树的层次遍历时经常使用,后面我们写到树的时候会给大家整理框架。队列同样也可以由数组和LinkedList实现,刷题时比较常用的方法是 +队列我们在树的层次遍历时经常使用,后面我们写到树的时候会给大家整理框架。队列同样也可以由数组和 LinkedList 实现,刷题时比较常用的方法是 ``` Queue queue = new LinkedList(); @@ -125,7 +123,7 @@ Stack stack = new Stack(); ### 循环队列 -循环队列的出现就是为了解决队列的假溢出问题。何为假溢出呢?我们运用数组实现队列时,数组长度为5,我们放入了[1,2,3,4,5],我们将1,2出队,此时如果继续加入6时,因为数组末尾元素已经被占用,再向后加则会溢出,但是我们的下标0,和下标1还是空闲的。所以我们把这种现象叫做“假溢出”。 +循环队列的出现就是为了解决队列的假溢出问题。何为假溢出呢?我们运用数组实现队列时,数组长度为 5,我们放入了[1,2,3,4,5],我们将 1,2 出队,此时如果继续加入 6 时,因为数组末尾元素已经被占用,再向后加则会溢出,但是我们的下标 0,和下标 1 还是空闲的。所以我们把这种现象叫做“假溢出”。 例如,我们在学校里面排队洗澡一人一个格,当你来到澡堂发现前面还有两个格,但是后面已经满了,你是去前面洗,还是等后面格子的哥们洗完再洗?肯定是去前面的格子洗。除非澡堂的所有格子都满了。我们才会等。 @@ -133,13 +131,11 @@ Stack stack = new Stack(); ![循环队列](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/循环队列.1841k3lsp7cw.gif) - - -我们发现队列为空时front == rear,队列满时也是front == rear,那么问题来了,我们应该怎么区分满和空呢? +我们发现队列为空时 front == rear,队列满时也是 front == rear,那么问题来了,我们应该怎么区分满和空呢? 我们可以通过以下两种方法进行区分, -1.设置标记变量flag;当front==rear 时且flag==0时为空,当front==rear且rear为1时且flag==1时为满 +1.设置标记变量 flag;当 front==rear 时且 flag==0 时为空,当 front==rear 且 rear 为 1 时且 flag==1 时为满 2.当队列为空时,front==rear,当队列满是我们保留一个元素空间,也就是说,队列满时,数组内还有一个空间。 @@ -147,17 +143,14 @@ Stack stack = new Stack(); ![image-20201102222857190](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201102222857190.4trq9b6gfjc0.png) - - ![image-20201102222914762](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201102222914762.34b1o0cqwse0.png) 然后我们再根据以下公式则能够判断队列满没满了。 -(rear+1)%queuesize==front +(rear+1)%queuesize==front -queuesize,代表队列的长度,上图为5。我们来判断上面两张图是否满。(4+1)%5==0,(1+1)%5==3 +queuesize,代表队列的长度,上图为 5。我们来判断上面两张图是否满。(4+1)%5==0,(1+1)%5==3 两种情况都是满的,over。 注:为了用动图把逻辑整的清晰明了,十几秒的动图,就要整半个多小时,改进好几遍。如果觉得图片对你有帮助的话就点个赞和在看吧。 - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\205\263\344\272\216\351\223\276\350\241\250\347\232\204\351\202\243\344\272\233\344\272\213.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\205\263\344\272\216\351\223\276\350\241\250\347\232\204\351\202\243\344\272\233\344\272\213.md" index f857d15..cae2cc0 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\205\263\344\272\216\351\223\276\350\241\250\347\232\204\351\202\243\344\272\233\344\272\213.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\205\263\344\272\216\351\223\276\350\241\250\347\232\204\351\202\243\344\272\233\344\272\213.md" @@ -1,10 +1,10 @@ # 链表详解 -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 阅读完本文你会有以下收获 @@ -28,7 +28,7 @@ > 定义:链表是一种递归的数据结构,他或者为空(null),或者是指向一个结点(node)的引用,该结点含有一个泛型的元素和一个指向另一条链表的引用。 -我们来对其解读一下,链表是一种常见且基础的数据结构,是一种线性表,但是他不是按线性顺序存取数据,而是在每一个节点里存到下一个节点的地址。我们可以这样理解,链表是通过指针串联在一起的线性结构,每一个链表结点由两部分组成,数据域及指针域,链表的最后一个结点指向null。也就是我们所说的空指针。 +我们来对其解读一下,链表是一种常见且基础的数据结构,是一种线性表,但是他不是按线性顺序存取数据,而是在每一个节点里存到下一个节点的地址。我们可以这样理解,链表是通过指针串联在一起的线性结构,每一个链表结点由两部分组成,数据域及指针域,链表的最后一个结点指向 null。也就是我们所说的空指针。 ### 链表的几种类型 @@ -46,21 +46,19 @@ ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321125110539.png) - - #### 双向链表 上面提到了单链表的节点只能指向节点的下一个节点。而双向链表有三个整数值: 数值、向后的节点链接、向前的节点链接,所以双链表既能向前查询也可以向后查询。 ![双链表](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/双链表.3cw4hra1g3q0.png) -#### +#### -还有一个常用的链表则为循环单链表,则单链表尾部的指针指向头节点。例如在leetcode61旋转链表中,我们就是先将链表闭合成环,找到新的打开位置,并定义新的表头和表尾。 +还有一个常用的链表则为循环单链表,则单链表尾部的指针指向头节点。例如在 leetcode61 旋转链表中,我们就是先将链表闭合成环,找到新的打开位置,并定义新的表头和表尾。 ### 构造链表 -java是面向对象语言,实现链表很容易。我们首先用一个嵌套类来定义节点的抽象数据类型 +java 是面向对象语言,实现链表很容易。我们首先用一个嵌套类来定义节点的抽象数据类型 ```java private class Node { @@ -69,7 +67,7 @@ private class Node { } ``` -现在我们需要构造一条含有one,two,three的链表,我们首先为每个元素创造一个节点 +现在我们需要构造一条含有 one,two,three 的链表,我们首先为每个元素创造一个节点 ```java Node first = new Node(); @@ -77,7 +75,7 @@ Node second = new Node(); Node third = new Node(); ``` -将每个节点的item域设为所需的值 +将每个节点的 item 域设为所需的值 ```java first.item = "one"; @@ -85,14 +83,14 @@ second.item = "two"; third.item = "three"; ``` -然后我们设置next域来构造链表 +然后我们设置 next 域来构造链表 ```java first.next = second; second.next = third; ``` -注:此时third的next仍为null,即被初始化的值。 +注:此时 third 的 next 仍为 null,即被初始化的值。 ### 链表的存储方式 @@ -106,7 +104,7 @@ second.next = third; ### 遍历链表 -链表的遍历我们通常使用while循环(for循环也可以但是代码不够简洁)下面我们来看一下链表的遍历代码 +链表的遍历我们通常使用 while 循环(for 循环也可以但是代码不够简洁)下面我们来看一下链表的遍历代码 for: @@ -132,19 +130,17 @@ while (x!=null) { ![image-20201101155937520](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201101155937520.my13cevp2cg.png) - - #### 删除节点 -删除B节点,如图所示 +删除 B 节点,如图所示 ![image-20201101155003257](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201101155003257.4onlntrwj2i0.png) -我们只需将A节点的next指针指向C节点即可。 +我们只需将 A 节点的 next 指针指向 C 节点即可。 -有的同学可能会有这种疑问,B节点这样不会留着内存里吗?java含有自己的内存回收机制,不用自己手动释放内存了,但是C++,则需要手动释放。 +有的同学可能会有这种疑问,B 节点这样不会留着内存里吗?java 含有自己的内存回收机制,不用自己手动释放内存了,但是 C++,则需要手动释放。 -我们通过上图的删除和插入都是O(1)操作。 +我们通过上图的删除和插入都是 O(1)操作。 链表和数组的比较 @@ -152,6 +148,3 @@ while (x!=null) { | ---- | ------------------------- | ------------------ | ------------ | | 数组 | O(n) | O(1) | 内存连续分布 | | 链表 | O(1) | O(n) | 内存散乱分布 | - - - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\206\222\346\263\241\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\206\222\346\263\241\346\216\222\345\272\217.md" index 2e06dac..a4c5e62 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\206\222\346\263\241\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\206\222\346\263\241\346\216\222\345\272\217.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 **写在前面** @@ -36,8 +36,6 @@ ![](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210119171706.xe5v3t5wjw0.png) - - 第一次排序之后,所有的职工按照**红豆数**从少到多有序。 第二次排序中,我们使用**稳定的排序算法**,所以经过第二次排序之后,年终奖相同的职工,仍然保持着红豆的有序(想对位置不变),红豆仍是从小到大排序。我们使用稳定的排序算法,只需要两次排序即可。 @@ -94,7 +92,7 @@ class Solution { } } return nums; - + } public void swap(int[] nums,int i,int j) { int temp = nums[i]; @@ -142,7 +140,7 @@ class Solution { } } } - return nums; + return nums; } public void swap(int[] nums,int i,int j) { int temp = nums[i]; @@ -182,10 +180,10 @@ class Solution { //发生交换,则变为true,下次继续判断 flag = true; } - } + } } return nums; - + } public void swap(int[] nums,int i,int j) { int temp = nums[i]; @@ -227,9 +225,9 @@ class Solution: 最好情况,就是要排序的表完全有序的情况下,根据改进后的代码,我们只需要一次遍历即可, -只需 n -1 次比较,时间复杂度为 O(n)。最坏情况时,即待排序表逆序的情况,则需要比较(n-1) + (n-2) +.... + 2 + 1= n*(n-1)/2 ,并等量级的交换,则时间复杂度为O(n^2)。* +只需 n -1 次比较,时间复杂度为 O(n)。最坏情况时,即待排序表逆序的情况,则需要比较(n-1) + (n-2) +.... + 2 + 1= n*(n-1)/2 ,并等量级的交换,则时间复杂度为 O(n^2)。* -*平均情况下,需要 n*(n-1)/4 次交换操作,比较操作大于等于交换操作,而复杂度的上限是 O(n^2),所以平均情况下的时间复杂度就是 O(n^2)。 +_平均情况下,需要 n_(n-1)/4 次交换操作,比较操作大于等于交换操作,而复杂度的上限是 O(n^2),所以平均情况下的时间复杂度就是 O(n^2)。 **冒泡排序空间复杂度分析** @@ -239,9 +237,6 @@ class Solution: 那么冒泡排序是稳定的吗?当然是稳定的,我们代码中,当 nums[j] > nums[j + 1] 时,才会进行交换,相等时不会交换,相等元素的相对位置没有改变,所以冒泡排序是稳定的。 - - | 算法名称 | 最好时间复杂度 | 最坏时间复杂度 | 平均时间复杂度 | 空间复杂度 | 是否稳定 | | -------- | -------------- | -------------- | -------------- | ---------- | -------- | | 冒泡排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 | - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\220\210\346\210\220.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\220\210\346\210\220.md" index e6647bc..0ba447b 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\220\210\346\210\220.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\220\210\346\210\220.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 之前我们说过了如何利用快速排序解决荷兰国旗问题,下面我们看下这两个题目 @@ -22,7 +22,7 @@ > 输入: [3,30,34,5,9] > 输出: "3033459" -题目很容易理解,就是让我们找出拼接的所有数字中最小的一个,但是我们需要注意的是,因为输出结果较大,所以我们不能返回 int 应该将数字转换成字符串,所以这类问题还是隐形的大数问题。 +题目很容易理解,就是让我们找出拼接的所有数字中最小的一个,但是我们需要注意的是,因为输出结果较大,所以我们不能返回 int 应该将数字转换成字符串,所以这类问题还是隐形的大数问题。 我们看到这个题目时,可能想到的是这种解题思路,我们首先求出数组中所有数字的全排列,然后将排列拼起来,最后再从中取出最小的值,但是我们共有 n 个数,则有 n !个排列,显然数目是十分庞大的,那么我们有没有其他更高效的方法呢? @@ -30,17 +30,17 @@ 我们假设两个数字 m , n 可以拼接成 mn 和 nm 那么我们怎么返回最小的那个数字呢? -我们需要比较 mn 和 nm ,假设 mn < nm 则此时我们求得的最小数字就是 mn +我们需要比较 mn 和 nm ,假设 mn < nm 则此时我们求得的最小数字就是 mn > 注:mn 代表 m 和 n 进行拼接,例如 m = 10, n = 1,mn = 101 -当 mn < nm 时,得到最小数字 mn, 因为在最小数字 mn 中 ,m 排在 n 的前面,我们此时定义 m "小于" n。 +当 mn < nm 时,得到最小数字 mn, 因为在最小数字 mn 中 ,m 排在 n 的前面,我们此时定义 m "小于" n。 -**注意:此时的 "小于" ,并不是数值的 < 。是我们自己定义,因为 m 在最小数字 mn 中位于 n 的前面,所以我们定义 m 小于 n。** +**注意:此时的 "小于" ,并不是数值的 < 。是我们自己定义,因为 m 在最小数字 mn 中位于 n 的前面,所以我们定义 m 小于 n。** 下面我们通过一个例子来加深下理解。 -假设 m = 10,n = 1 则有 mn = 101 和 nm = 110 +假设 m = 10,n = 1 则有 mn = 101 和 nm = 110 我们比较 101 和 110 ,发现 101 < 110 所以此时我们的最小数字为 101 ,又因为在最小数字中 10 (m) 排在 1(n) 的前面,我们根据定义则是 10 “小于” 1,反之亦然。 @@ -60,29 +60,29 @@ 如果 A“小于” B,则 AB < BA, 假设 A 和 B 用十进制表示时分别有 a 位和 b 位 -则 AB = A * 10 ^ b + B , BA = B * 10 ^ a + A +则 AB = A _ 10 ^ b + B , BA = B _ 10 ^ a + A > 例 A = 10, a = 2 (两位数) B = 1, b = 1 (一位数) > -> AB = A * 10 ^ b + B = 10 * 10 ^ 1 + 1 = 101 +> AB = A _ 10 ^ b + B = 10 _ 10 ^ 1 + 1 = 101 > -> BA = B * 10 ^ a + A = 1 * 10 ^ 2 + 10 = 110 +> BA = B _ 10 ^ a + A = 1 _ 10 ^ 2 + 10 = 110 - AB < BA 则 **A * 10 ^ b + B < BA = B * 10 ^ a + A** 整理得 +AB < BA 则 **A _ 10 ^ b + B < BA = B _ 10 ^ a + A** 整理得 -A / (10^a - 1) < B / (10 ^ b - 1) +A / (10^a - 1) < B / (10 ^ b - 1) 同理,如果 B “小于” C 则 BC < CB ,C 用十进制表示时有 c 位,和前面推导过程一样 -BC = B * 10 ^ c + C +BC = B \* 10 ^ c + C -CB = C * 10 ^ b + B +CB = C \* 10 ^ b + B -BC < CB 整理得 B / (10 ^ b - 1) < C / (10 ^ c - 1); +BC < CB 整理得 B / (10 ^ b - 1) < C / (10 ^ c - 1); -我们通过 A / (10 ^ a - 1) < B / (10 ^ b - 1) ,B / (10 ^ b - 1) < C / (10 ^ c - 1); +我们通过 A / (10 ^ a - 1) < B / (10 ^ b - 1) ,B / (10 ^ b - 1) < C / (10 ^ c - 1); -可以得到 A / (10^a - 1) < C / (10 ^ c - 1) +可以得到 A / (10^a - 1) < C / (10 ^ c - 1) 则可以得到 AC < CA 即 A “小于” C @@ -96,25 +96,23 @@ BC < CB 整理得 B / (10 ^ b - 1) < C / (10 ^ c - 1); > 当 mn < nm 时,得到最小数字 mn, 因为在最小数字 mn 中 ,m 排在 n 的前面, > -> 我们此时定义 m "小于" n。 +> 我们此时定义 m "小于" n。 我们假设我们根据上诉规则得到的数字为 xxxxxxxx -存在这么一对字符串 A B ,虽然 AB < BA, 按照规则 A 应该排在 B 的前面,但是在最后结果中 A 排在 B 的后面。则此时共有这么几种情况 +存在这么一对字符串 A B ,虽然 AB < BA, 按照规则 A 应该排在 B 的前面,但是在最后结果中 A 排在 B 的后面。则此时共有这么几种情况 见下图 ![](https://cdn.jsdelivr.net/gh/tan45du/test@master/photo/微信截图_20210306160015.5x1o7nyb6c40.png) - - 其实我们可以归结为两大类, B 和 A 之间没有其他值, B 和 A 之间有其他值。 我们先来看**没有其他值**的情况 -假设我们求得的最小值为 XXXXBA, 虽然 A "小于" B,但是在最后结果中 B 排在了 A 的前面,这和我们之前定义的规则是冲突的,大家思考一下这个值为最小值吗? +假设我们求得的最小值为 XXXXBA, 虽然 A "小于" B,但是在最后结果中 B 排在了 A 的前面,这和我们之前定义的规则是冲突的,大家思考一下这个值为最小值吗? -假设 XXXXBA为最小值,但是因为 A "小于" B ,则 AB < BA , +假设 XXXXBA 为最小值,但是因为 A "小于" B ,则 AB < BA , 所以 XXXXAB 一定小于 XXXXBA 。 @@ -136,11 +134,11 @@ BC < CB 整理得 B / (10 ^ b - 1) < C / (10 ^ c - 1); 根据我们之前证明的传递性 -则 B "小于" A +则 B "小于" A 但是我们假设是 A “小于” B ,与假设冲突,证得 -综上所述,得出假设不成立,从而得出结论:对于排成的最小数字,不存在满足下述关系的一对字符串:虽然 A "小于" B , 但是在最后结果中 B 排在了 A 的前面. +综上所述,得出假设不成立,从而得出结论:对于排成的最小数字,不存在满足下述关系的一对字符串:虽然 A "小于" B , 但是在最后结果中 B 排在了 A 的前面. 好啦,我们证明我们定义的规则有效下面我们直接看代码吧。继续使用我们的三向切分来解决 @@ -148,7 +146,7 @@ Java Code: ```java class Solution { - public String minNumber(int[] nums) { + public String minNumber(int[] nums) { String[] arr = new String[nums.length]; //解决大数问题,将数字转换为字符串 for (int i = 0 ; i < nums.length; ++i) { @@ -157,7 +155,7 @@ class Solution { quickSort(arr,0,arr.length-1); StringBuffer str = new StringBuffer(); - + for (String x : arr) { str.append(x); } @@ -182,10 +180,10 @@ class Solution { i++; } } - + quickSort(arr,left,low-1); quickSort(arr,high+1,right); - + } public void swap(String[] arr, int i, int j) { String temp = arr[i]; @@ -201,7 +199,7 @@ Python Code: from typing import List class Solution: def minNumber(self, nums: List[int])->str: - + arr = [''] * len(nums) # 解决大数问题,将数字转换为字符串 for i in range(0, len(nums)): @@ -212,7 +210,7 @@ class Solution: for x in arr: s += x return s - + def quickSort(self, arr: List[str], left: int, right: int): if left >= right: return @@ -220,7 +218,7 @@ class Solution: high = right i = low + 1 pivot = arr[low] - + while i <= high: # 比较大小 if int(pivot + arr[i]) > int(arr[i] + pivot): @@ -232,7 +230,7 @@ class Solution: high -= 1 else: i += 1 - + self.quickSort(arr, left, low - 1) self.quickSort(arr, high + 1, right) @@ -241,18 +239,3 @@ class Solution: arr[i] = arr[j] arr[j] = temp ``` - - - - - - - - - - - - - - - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\240\206\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\240\206\346\216\222\345\272\217.md" index 7cd0125..5ea2930 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\240\206\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\240\206\346\216\222\345\272\217.md" @@ -1,10 +1,10 @@ ### **堆排序** -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 ->刷题网站 -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 刷题网站 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 说堆排序之前,我们先简单了解一些什么是堆?堆这种数据结构应用场景非常多,所以我们需要熟练掌握呀! @@ -46,15 +46,13 @@ ![](https://cdn.jsdelivr.net/gh/tan45du/test@master/photo/微信截图_20210223223621.3juf4t4hc9a0.png) - - 我们来看一下为什么我们可以用数组来存储堆呢? 我们首先看根节点,也就是值为 1 的节点,它在数组中的下标为 1 ,它的左子节点,也就是值为 4 的节点,此时索引为 2,右子节点也就是值为 2 的节点,它的索引为 3。 我们发现其中的关系了吗? -数组中,某节点(非叶子节点)的下标为 i , 那么其**左子节点下标为 2*i** (这里可以直接通过相乘得到左孩子,如果从0 开始存,需要 2*i+1 才行), 右子节点为 2*i+1**,**其父节点为 i/2 。既然我们完全可以根据索引找到某节点的 **左子节点** 和 **右子节点**,那么我们用数组存储是完全没有问题的。 +数组中,某节点(非叶子节点)的下标为 i , 那么其**左子节点下标为 2\*i** (这里可以直接通过相乘得到左孩子,如果从 0 开始存,需要 2*i+1 才行), 右子节点为 2*i+1**,**其父节点为 i/2 。既然我们完全可以根据索引找到某节点的 **左子节点** 和 **右子节点**,那么我们用数组存储是完全没有问题的。 好啦,我们知道了什么是堆和如何用数组存储堆,那我们如何完成堆排序呢? @@ -77,7 +75,7 @@ ![](https://img-blog.csdnimg.cn/20210317193005203.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70#pic_center) -假设让我们插入新的元素 1 (绿色节点),我们发现此时 1 小于其父节点 的值 7 ,并不遵守小顶堆的规则,那我们则需要移动元素 1 。让 1 与 7 交换,(如果新插入元素大于父节点的值,则说明插入新节点后仍满足小顶堆规则,无需交换)。 +假设让我们插入新的元素 1 (绿色节点),我们发现此时 1 小于其父节点 的值 7 ,并不遵守小顶堆的规则,那我们则需要移动元素 1 。让 1 与 7 交换,(如果新插入元素大于父节点的值,则说明插入新节点后仍满足小顶堆规则,无需交换)。 之前我们说过,我们可以用数组保存堆,并且可以通过 i/2 得到其父节点的值,那么此时我们就明白怎么做啦。 @@ -139,7 +137,7 @@ def swim(nums: int, index: int): 那我们怎么判断节点找到属于它的位置了呢?主要有两个情况 -- 待下沉元素小于(大于)两个子节点,此时符合堆的规则,无序下沉,例如上图中的 6 +- 待下沉元素小于(大于)两个子节点,此时符合堆的规则,无序下沉,例如上图中的 6 - 下沉为叶子节点,此时没有子节点,例如 7 下沉到最后变成了叶子节点。 我们将上面的操作称之为下沉操作。 @@ -171,7 +169,7 @@ public void sink (int[] nums, int index,int len) { swap(nums,index,j); } else { break; - } + } //继续下沉 index = j; } @@ -202,7 +200,7 @@ def sink(nums: list, index: int, len: int): ![](https://cdn.jsdelivr.net/gh/tan45du/test@master/photo/微信截图_20210309200153.3jx6dvweliq0.png) -假设我们想要去除堆顶的 11 ,那我们则需要将其与堆的最后一个节点交换也就是 2 ,2然后再执行下沉操作,执行完毕后仍能满足堆的要求,见下图 +假设我们想要去除堆顶的 11 ,那我们则需要将其与堆的最后一个节点交换也就是 2 ,2 然后再执行下沉操作,执行完毕后仍能满足堆的要求,见下图 ![](https://cdn.jsdelivr.net/gh/tan45du/test@master/photo/微信截图_20210309200301.5zqydpf44mo0.png) @@ -229,7 +227,7 @@ class Solution { for (int i = 0; i < nums.length; ++i) { a[i+1] = nums[i]; - } + } //下沉建堆 for (int i = len/2; i >= 1; --i) { sink(a,i,len); @@ -267,7 +265,7 @@ class Solution { nums[i] = nums[j]; nums[j] = temp; } - + } ``` @@ -287,7 +285,7 @@ def sortArray(nums: list)->list: swap(a, 1, k) k -= 1 sink(a, 1, k) - + for i in range(1, leng + 1): nums[i - 1] = a[i] return nums @@ -319,7 +317,7 @@ def sink(nums: list, k: int, end: int): **堆排序空间复杂度分析** -这里需要注意,我们上面的描述过程中,为了更直观的描述,空出数组的第一位,这样我们就可以通过 i * 2 和 i * 2+1 来求得左孩子节点和右孩子节点 。我们也可以根据 i * 2 + 1 和 i * 2 + 2 来获取孩子节点,这样则不需要临时数组来处理原数组,将所有元素后移一位,所以堆排序的空间复杂度为 O(1),是原地排序算法。 +这里需要注意,我们上面的描述过程中,为了更直观的描述,空出数组的第一位,这样我们就可以通过 i _ 2 和 i _ 2+1 来求得左孩子节点和右孩子节点 。我们也可以根据 i _ 2 + 1 和 i _ 2 + 2 来获取孩子节点,这样则不需要临时数组来处理原数组,将所有元素后移一位,所以堆排序的空间复杂度为 O(1),是原地排序算法。 **堆排序稳定性分析** @@ -334,4 +332,3 @@ def sink(nums: list, k: int, end: int): 所以上面两条也就说明了在实际开发中,堆排序的性能不如快速排序性能好。 好啦,今天的内容就到这里啦,咱们下期见。 - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215\347\256\227\346\263\225.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215\347\256\227\346\263\225.md" index 6c556b0..06de4fe 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215\347\256\227\346\263\225.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215\347\256\227\346\263\225.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 > 为保证代码严谨性,文中所有代码均在 leetcode 刷题网站 AC ,大家可以放心食用。 @@ -24,21 +24,17 @@ 通过上面的一个例子,让我们简单了解了字符串匹配。 -字符串匹配:设 S 和 T 是给定的两个串,在主串 S 中找到模式串 T 的过程称为字符串匹配,如果在主串 S 中找到 模式串 T ,则称匹配成功,函数返回 T 在 S 中首次出现的位置,否则匹配不成功,返回 -1。 +字符串匹配:设 S 和 T 是给定的两个串,在主串 S 中找到模式串 T 的过程称为字符串匹配,如果在主串 S 中找到 模式串 T ,则称匹配成功,函数返回 T 在 S 中首次出现的位置,否则匹配不成功,返回 -1。 例: - - ![字符串匹配](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/字符串匹配.3q9wqbh8ws40.png) - - 在上图中,我们试图找到模式 T = baab,在主串 S = abcabaabcabac 中第一次出现的位置,即为红色阴影部分, T 第一次在 S 中出现的位置下标为 4 ( 字符串的首位下标是 0 ),所以返回 4。如果模式串 T 没有在主串 S 中出现,则返回 -1。 解决上面问题的算法我们称之为字符串匹配算法,今天我们来介绍三种字符串匹配算法,大家记得打卡呀,说不准面试的时候就问到啦。 -## BF算法(Brute Force) +## BF 算法(Brute Force) 这个算法很容易理解,就是我们将模式串和主串进行比较,一致时则继续比较下一字符,直到比较完整个模式串。不一致时则将模式串后移一位,重新从模式串的首位开始对比,重复刚才的步骤下面我们看下这个方法的动图解析,看完肯定一下就能搞懂啦。 @@ -52,7 +48,7 @@ #### 题目描述 -给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。 +给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从 0 开始)。如果不存在,则返回 -1。 示例 1: @@ -76,7 +72,7 @@ Java Code: class Solution { public int strStr(String haystack, String needle) { int haylen = haystack.length(); - int needlen = needle.length(); + int needlen = needle.length(); //特殊情况 if (haylen < needlen) { return -1; @@ -97,7 +93,7 @@ class Solution { //匹配成功 if (j == needlen) { return i; - } + } } return -1; @@ -132,7 +128,7 @@ class Solution: return -1 ``` -我们看一下BF算法的另一种算法(显示回退),其实原理一样,就是对代码进行了一下修改,只要是看完咱们的动图,这个也能够一下就能看懂,大家可以结合下面代码中的注释和动图进行理解。 +我们看一下 BF 算法的另一种算法(显示回退),其实原理一样,就是对代码进行了一下修改,只要是看完咱们的动图,这个也能够一下就能看懂,大家可以结合下面代码中的注释和动图进行理解。 Java Code: @@ -165,7 +161,7 @@ class Solution { Python Code: -```python +```python from typing import List class Solution: def strStr(self, haystack: str, needle: str)->int: @@ -190,14 +186,11 @@ class Solution: return renum ``` - -## BM算法(Boyer-Moore) +## BM 算法(Boyer-Moore) 我们刚才说过了 BF 算法,但是 BF 算法是有缺陷的,比如我们下面这种情况 -![BF第一次](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/BF第一次.2qo0876qvs80.png) - - +![BF第一次](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/BF第一次.2qo0876qvs80.png) 如上图所示,如果我们利用 BF 算法,遇到不匹配字符时,每次右移一位模式串,再重新从头进行匹配,我们观察一下,我们的模式串 abcdex 中每个字符都不一样,但是我们第一次进行字符串匹配时,abcde 都匹配成功,到 x 时失败,又因为模式串每位都不相同,所以我们不需要再每次右移一位,再重新比较,我们可以直接跳过某些步骤。如下图 @@ -211,7 +204,7 @@ class Solution: 我们之前的 BF 算法是从前往后进行比较 ,BM 算法是从后往前进行比较,我们来看一下具体过程,我们还是利用上面的例子。 -![BM4](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/BM4.2mayfaccj3i0.png) +![BM4](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/BM4.2mayfaccj3i0.png) BM 算法是从后往前进行比较,此时我们发现比较的第一个字符就不匹配,我们将**主串**这个字符称之为**坏字符**,也就是 f ,我们发现坏字符之后,模式串 T 中查找是否含有该字符(f),我们发现并不存在 f,此时我们只需将模式串右移到坏字符的后面一位即可。如下图 @@ -243,16 +236,10 @@ BM 算法是从后往前进行比较,此时我们发现比较的第一个字 我们上面一共介绍了三种移动情况,分别是下方的模式串中没有发现与坏字符对应的字符,发现一个对应字符,发现两个。这三种情况我们分别移动不同的位数,那我们是根据依据什么来决定移动位数的呢?下面我们给图中的字符加上下标。见下图 - - ![坏字符移动规则](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/坏字符移动规则.48oh1msdypy0.png) - - 下面我们来考虑一下这种情况。 - - ![换字符bug](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/换字符bug.24av6jslzh40.png) 此时这种情况肯定是不行的,不往右移动,甚至还有可能左移,那么我们有没有什么办法解决这个问题呢?继续往下看吧。 @@ -265,7 +252,7 @@ BM 算法是从后往前进行比较,此时我们发现比较的第一个字 这里如果我们按照坏字符进行移动是不合理的,这时我们可以使用好后缀规则,那么什么是好后缀呢? -BM 算法是从右往左进行比较,发现坏字符的时候此时 cac 已经匹配成功,在红色阴影处发现坏字符。此时已经匹配成功的 cac 则为我们的好后缀,此时我们拿它在模式串中查找,如果找到了另一个和好后缀相匹配的串,那我们就将另一个和**好后缀相匹配**的串 ,滑到和好后缀对齐的位置。 +BM 算法是从右往左进行比较,发现坏字符的时候此时 cac 已经匹配成功,在红色阴影处发现坏字符。此时已经匹配成功的 cac 则为我们的好后缀,此时我们拿它在模式串中查找,如果找到了另一个和好后缀相匹配的串,那我们就将另一个和**好后缀相匹配**的串 ,滑到和好后缀对齐的位置。 是不是感觉有点拗口,没关系,我们看下图,红色代表坏字符,绿色代表好后缀 @@ -289,16 +276,8 @@ BM 算法是从右往左进行比较,发现坏字符的时候此时 cac 已 下面我们通过动图来看一下某一例子的具体的执行过程 - - - - - - 视频 - - 说到这里,坏字符和好后缀规则就算说完了,坏字符很容易理解,我们对好后缀总结一下 1.如果模式串**含有好后缀**,无论是中间还是头部可以按照规则进行移动。如果好后缀在模式串中出现多次,则以**最右侧的好后缀**为基准。 @@ -309,8 +288,6 @@ BM 算法是从右往左进行比较,发现坏字符的时候此时 cac 已 > Boyer R S,Moore J S. A fast string searching algorithm[J]. Communications of the ACM,1977,10: 762-772. - - 之前我们刚开始说坏字符的时候,是不是有可能会出现负值的情况,即往左移动的情况,所以我们为了解决这个问题,我们可以分别计算好后缀和坏字符往后滑动的位数**(好后缀不为 0 的情况)**,然后取两个数中最大的,作为模式串往后滑动的位数。 ![五好后缀](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/五好后缀.6wvqxa4um040.png) @@ -421,7 +398,7 @@ class Solution: haylen = len(haystack) needlen = len(needle) return self.bm(haystack, haylen, needle, needlen) - + # 用来求坏字符情况下移动位数 def badChar(self, b: str, m: int, bc: List[int]): # 初始化 @@ -431,7 +408,7 @@ class Solution: for i in range(0, m,): ascii = ord(b[i]) bc[ascii] = i# 下标 - + # 用来求好后缀条件下的移动位数 def goodSuffix(self, b: str, m: int, suffix: List[int], prefix: List[bool]): # 初始化 @@ -447,7 +424,7 @@ class Solution: suffix[k] = j + 1 if j == -1: prefix[k] = True - + def bm(self, a: str, n: int, b: str, m: int)->int: bc = [0] * 256# 创建一个数组用来保存最右边字符的下标 self.badChar(b, m, bc) @@ -478,7 +455,7 @@ class Solution: # 移动 i += max(x, y) return -1 - + # j代表坏字符的下标 def move(j: int, m: int, suffix_index: List[int], ispre: List[bool])->int: # 好后缀长度 @@ -499,7 +476,7 @@ class Solution: ![头缀函数](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/头缀函数.145da63ig3s0.png) -## KMP算法(Knuth-Morris-Pratt) +## KMP 算法(Knuth-Morris-Pratt) 我们刚才讲了 BM 算法,虽然不是特别容易理解,但是如果你用心看的话肯定可以看懂的,我们再来看一个新的算法,这个算法是考研时必考的算法。实际上 BM 和 KMP 算法的本质是一样的,你理解了 BM 再来理解 KMP 那就是分分钟的事啦。 @@ -507,12 +484,6 @@ class Solution: 视频 - - - - - - 为了让读者更容易理解,我们将指针移动改成了模式串移动,两者相对与主串的移动是一致的,重新比较时都是从指针位置继续比较。 通过上面的实例是不是很快就能理解 KMP 算法的思想了,但是 KMP 的难点不是在这里,不过多思考,认真看理解起来也是很轻松的。 @@ -531,7 +502,7 @@ class Solution: ![原理](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/原理.bghc3ecm4z4.png) -好啦,看完上面的图,KMP的核心原理已经基本搞定了,但是我们现在的问题是,我们应该怎么才能知道他的最长公共前后缀的长度是多少呢?怎么知道移动多少位呢? +好啦,看完上面的图,KMP 的核心原理已经基本搞定了,但是我们现在的问题是,我们应该怎么才能知道他的最长公共前后缀的长度是多少呢?怎么知道移动多少位呢? 刚才我们在 BM 中说到,我们移动位数跟主串无关,只跟模式串有关,跟我们的 bc,suffix,prefix 数组的值有关,我们通过这些数组就可以知道我们每次移动多少位啦,其实 KMP 也有一个数组,这个数组叫做 next 数组,那么这个 next 数组存的是什么呢? @@ -644,7 +615,7 @@ class Solution: nelen = len(needle) # 返回下标 return self.kmp(haystack, halen, needle, nelen) - + def kmp(self, hasyarr: str, halen: int, nearr: str, nelen: int)->int: # 获取next 数组 next = self.next(nearr, nelen) @@ -687,5 +658,4 @@ class Solution: return next ``` -这篇文章真的写了很久很久,觉得还不错的话,就麻烦您点个赞吧,大家也可以去我的公众号看我的所有文章,每个都有动图解析,公众号:[袁厨的算法小屋](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/qrcode_for_gh_1f36d2ef6df9_258.5lojyphpkso0.jpg) - +这篇文章真的写了很久很久,觉得还不错的话,就麻烦您点个赞吧,大家也可以去我的公众号看我的所有文章,每个都有动图解析,公众号:[程序厨](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/qrcode_for_gh_1f36d2ef6df9_258.5lojyphpkso0.jpg) diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\270\214\345\260\224\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\270\214\345\260\224\346\216\222\345\272\217.md" index c1f016e..fb5e301 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\270\214\345\260\224\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\270\214\345\260\224\346\216\222\345\272\217.md" @@ -1,12 +1,12 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### **希尔排序 (Shell's Sort)** -我们在之前说过直接插入排序在记录基本有序的时候和元素较少时效率是很高的,基本有序时,只需执行少量的插入操作,就可以完成整个记录的排序工作。当元素较少时,效率也很高,就比如我们经常用的 Arrays.sort (),当元素个数少于47时,使用的排序算法就是直接插入排序。那么直接希尔排序和直接插入排序有什么关系呢? +我们在之前说过直接插入排序在记录基本有序的时候和元素较少时效率是很高的,基本有序时,只需执行少量的插入操作,就可以完成整个记录的排序工作。当元素较少时,效率也很高,就比如我们经常用的 Arrays.sort (),当元素个数少于 47 时,使用的排序算法就是直接插入排序。那么直接希尔排序和直接插入排序有什么关系呢? 希尔排序是**插入排序**的一种,又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序的高级变形,其思想简单点说就是有跨度的插入排序,这个跨度会逐渐变小,直到变为 1,变为 1 时记录也就基本有序,这时用到的也就是我们之前讲的直接插入排序了。 @@ -87,7 +87,6 @@ class Solution: return nums ``` - 我们刚才说,我们的增量可以自己设置的,我们上面的例子是用的希尔增量,下面我们看这个例子,看看使用希尔增量会出现什么问题。 ![](https://cdn.jsdelivr.net/gh/tan45du/bedphoto2@master/20210122/微信截图_20210127212901.62c3o3ss6pg0.png) @@ -104,21 +103,21 @@ Sedgewick 增量序列如下: 通项公式 9*4^k - 9*2^ -利用此种增量方式的希尔排序,最坏时间复杂度是O(n^(4/3)) +利用此种增量方式的希尔排序,最坏时间复杂度是 O(n^(4/3)) -Hibbard增量序列如下: +Hibbard 增量序列如下: 1,3,7,15...... -通项公式2 ^ k-1 +通项公式 2 ^ k-1 -利用此种增量方式的希尔排序,最坏时间复杂度为O(n^(3/2)) +利用此种增量方式的希尔排序,最坏时间复杂度为 O(n^(3/2)) -上面是两种比较具有代表性的增量方式,可究竟应该选取怎样的增量才是最好,目前还是一个数学难题。不过我们需要注意的一点,就是增量序列的最后一个增量值必须等于1才行。 +上面是两种比较具有代表性的增量方式,可究竟应该选取怎样的增量才是最好,目前还是一个数学难题。不过我们需要注意的一点,就是增量序列的最后一个增量值必须等于 1 才行。 **希尔排序时间复杂度分析** -希尔排序的时间复杂度跟增量序列的选择有关,范围为 O(n^(1.3-2)) 在此之前的排序算法时间复杂度基本都是O(n^2),希尔排序是突破这个时间复杂度的第一批算法之一。 +希尔排序的时间复杂度跟增量序列的选择有关,范围为 O(n^(1.3-2)) 在此之前的排序算法时间复杂度基本都是 O(n^2),希尔排序是突破这个时间复杂度的第一批算法之一。 **希尔排序空间复杂度分析** @@ -133,4 +132,3 @@ Hibbard增量序列如下: 通过上图,可知,如果我们选用 4 为跨度的话,交换后,两个相同元素 2 的相对位置会发生改变,所以希尔排序是一个不稳定的排序 ![](https://cdn.jsdelivr.net/gh/tan45du/bedphoto2@master/20210122/微信截图_20210128084911.6tmdmz51m2c0.png) - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\275\222\345\271\266\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\275\222\345\271\266\346\216\222\345\272\217.md" index 0d9adfe..2173f61 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\275\222\345\271\266\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\275\222\345\271\266\346\216\222\345\272\217.md" @@ -1,10 +1,10 @@ ### **归并排序** -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 归并排序是必须要掌握的排序算法,也算是面试高频考点,下面我们就一起来扒一扒归并排序吧,原理很简单,大家一下就能搞懂。 @@ -12,13 +12,13 @@ 第 23 届食神争霸赛开赛啦! -袁厨想在自己排名前4的分店中,挑选一个最优秀的厨师来参加食神争霸赛,选拔规则如下。 +袁厨想在自己排名前 4 的分店中,挑选一个最优秀的厨师来参加食神争霸赛,选拔规则如下。 第一场 PK:每个分店选出两名厨师,首先进行店内 PK,选出店内里的胜者 -第二场 PK: 然后店内的优胜者代表分店挑战其他某一分店的胜者(半决赛) +第二场 PK: 然后店内的优胜者代表分店挑战其他某一分店的胜者(半决赛) -第三场 PK:最后剩下的两名胜者进行PK,选出最后的胜者。 +第三场 PK:最后剩下的两名胜者进行 PK,选出最后的胜者。 示意图如下 @@ -69,7 +69,7 @@ class Solution { mergeSort(arr,mid+1,right); merge(arr,left,mid,right); } - } + } //归并 public void merge(int[] arr,int left, int mid, int right) { //第一步,定义一个新的临时数组 @@ -87,7 +87,7 @@ class Solution { //对应第三步,将某一小集合的剩余元素存到大集合中 if (temp1 <= mid) System.arraycopy(arr, temp1, temparr, index, mid - temp1 + 1); if (temp2 <= right) System.arraycopy(arr, temp2, temparr, index, right -temp2 + 1); //将大集合的元素复制回原数组 - System.arraycopy(temparr,0,arr,0+left,right-left+1); + System.arraycopy(temparr,0,arr,0+left,right-left+1); } } ``` @@ -106,8 +106,8 @@ class Solution: mid = left + ((right - left) >> 1) self.mergeSort(arr, left, mid) self.mergeSort(arr, mid + 1, right) - self.merge(arr, left, mid, right) - + self.merge(arr, left, mid, right) + # 归并 def merge(self, arr: List[int], left: int, mid: int, right: int): # 第一步,定义一个新的临时数组 @@ -128,15 +128,16 @@ class Solution: # 对应第三步,将某一集合的剩余元素存到大集合中 if temp1 <= mid: temparr[index: index + mid - temp1 + 1] = arr[temp1: temp1 + mid - temp1 + 1] - if temp2 <= right: + if temp2 <= right: temparr[index: index + right - temp2 + 1] = arr[temp2: temp2 + right - temp2 + 1] - + # 将大集合的元素复制回原数组 arr[left: left + right- left + 1] = temparr[0: right - left + 1] ``` + **归并排序时间复杂度分析** -我们一趟归并,需要将两个小集合的长度放到大集合中,则需要将待排序序列中的所有记录扫描一遍所以时间复杂度为O(n)。归并排序把集合一层一层的折半分组,则由完全二叉树的深度可知,整个排序过程需要进行 logn(向上取整)次,则总的时间复杂度为 O(nlogn)。另外归并排序的执行效率与要排序的原始数组的有序程度无关,所以在最好,最坏,平均情况下时间复杂度均为 O(nlogn) 。虽然归并排序时间复杂度很稳定,但是他的应用范围却不如快速排序广泛,这是因为归并排序不是原地排序算法,空间复杂度不为 O(1),那么他的空间复杂度为多少呢? +我们一趟归并,需要将两个小集合的长度放到大集合中,则需要将待排序序列中的所有记录扫描一遍所以时间复杂度为 O(n)。归并排序把集合一层一层的折半分组,则由完全二叉树的深度可知,整个排序过程需要进行 logn(向上取整)次,则总的时间复杂度为 O(nlogn)。另外归并排序的执行效率与要排序的原始数组的有序程度无关,所以在最好,最坏,平均情况下时间复杂度均为 O(nlogn) 。虽然归并排序时间复杂度很稳定,但是他的应用范围却不如快速排序广泛,这是因为归并排序不是原地排序算法,空间复杂度不为 O(1),那么他的空间复杂度为多少呢? **归并排序的空间复杂度分析** @@ -144,7 +145,7 @@ class Solution: **归并排序的稳定性分析** -归并排序的稳定性,要看我们的 merge 函数,我们代码中设置了 arr[temp1] <= arr[temp2] ,当两个元素相同时,先放入arr[temp1] 的值到大集合中,所以两个相同元素的相对位置没有发生改变,所以归并排序是稳定的排序算法。 +归并排序的稳定性,要看我们的 merge 函数,我们代码中设置了 arr[temp1] <= arr[temp2] ,当两个元素相同时,先放入 arr[temp1] 的值到大集合中,所以两个相同元素的相对位置没有发生改变,所以归并排序是稳定的排序算法。 | 算法名称 | 最好时间复杂度 | 最坏时间复杂度 | 平均时间复杂度 | 空间复杂度 | 是否稳定 | | -------- | -------------- | -------------- | -------------- | ---------- | -------- | @@ -164,8 +165,6 @@ class Solution: ![](https://cdn.jsdelivr.net/gh/tan45du/bedphoto2@master/20210122/微信截图_20210203205336.4j443ciyj7u0.png) - - 比如此时小集合大小为 1 。两个小集合分别为 [3],[1]。然后我们根据合并规则,见第一个视频,将[3],[1]合并到临时数组中,则小的先进,则实现了排序,然后再将临时数组的元素复制到原来数组中。则实现了一次合并。 下面则继续合并[4],[6]。具体步骤一致。所有的小集合合并完成后,则小集合的大小变为 2,继续执行刚才步骤,见下图。 @@ -176,7 +175,7 @@ class Solution: 下面我们直接看代码吧。 -注:递归法和迭代法的 merge函数代码一样。 +注:递归法和迭代法的 merge 函数代码一样。 Java Code: @@ -221,9 +220,9 @@ class Solution { } //对应第三步,将某一小集合的剩余元素存到大集合中 if (temp1 <= mid) System.arraycopy(arr, temp1, temparr, index, mid - temp1 + 1); - if (temp2 <= right) System.arraycopy(arr, temp2, temparr, index, right -temp2 + 1); + if (temp2 <= right) System.arraycopy(arr, temp2, temparr, index, right -temp2 + 1); //将大集合的元素复制回原数组 - System.arraycopy(temparr,0,arr,0+left,right-left+1); + System.arraycopy(temparr,0,arr,0+left,right-left+1); } } ``` @@ -249,7 +248,7 @@ class Solution: # 归并 self.merge(array, i, i + k - 1, i + 2 * k - 1) i += 2 * k - + # 归并最后两个序列 if i + k < leng: self.merge(array, i, i + k - 1, leng - 1) @@ -274,9 +273,9 @@ class Solution: # 对应第三步,将某一集合的剩余元素存到大集合中 if temp1 <= mid: temparr[index: index + mid - temp1 + 1] = arr[temp1: temp1 + mid - temp1 + 1] - if temp2 <= right: + if temp2 <= right: temparr[index: index + right - temp2 + 1] = arr[temp2: temp2 + right - temp2 + 1] - + # 将大集合的元素复制回原数组 arr[left: left + right- left + 1] = temparr[0: right - left + 1] ``` diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\277\253\351\200\237\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\277\253\351\200\237\346\216\222\345\272\217.md" index e514d53..877d94c 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\277\253\351\200\237\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\345\277\253\351\200\237\346\216\222\345\272\217.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### 快速排序 @@ -50,23 +50,23 @@ Java Code: ```java class Solution { - public int[] sortArray(int[] nums) { - + public int[] sortArray(int[] nums) { + quickSort(nums,0,nums.length-1); return nums; - + } public void quickSort (int[] nums, int low, int high) { - + if (low < high) { int index = partition(nums,low,high); quickSort(nums,low,index-1); quickSort(nums,index+1,high); - } - + } + } public int partition (int[] nums, int low, int high) { - + int pivot = nums[low]; while (low < high) { //移动hight指针 @@ -84,7 +84,7 @@ class Solution { //基准数放到合适的位置 nums[low] = pivot; return low; - } + } } ``` @@ -102,11 +102,11 @@ class Solution { ```java class Solution { - public int[] sortArray (int[] nums) { - + public int[] sortArray (int[] nums) { + quickSort(nums,0,nums.length-1); return nums; - + } public void quickSort (int[] nums, int low, int high) { @@ -115,30 +115,30 @@ class Solution { int index = partition(nums,low,high); quickSort(nums,low,index-1); quickSort(nums,index+1,high); - } - + } + } public int partition (int[] nums, int low, int high) { - + int pivot = nums[low]; int start = low; - + while (low < high) { - while (low < high && nums[high] >= pivot) high--; + while (low < high && nums[high] >= pivot) high--; while (low < high && nums[low] <= pivot) low++; if (low >= high) break; - swap(nums, low, high); + swap(nums, low, high); } //基准值归位 swap(nums,start,low); return low; - } - public void swap (int[] nums, int i, int j) { + } + public void swap (int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; - } + } } ``` @@ -150,7 +150,7 @@ class Solution { **快速排序的空间复杂度分析** -快速排序主要时递归造成的栈空间的使用,最好情况时其空间复杂度为O (logn),对应递归树的深度。最坏情况时则需要 n-1 次递归调用,此时空间复杂度为O(n). +快速排序主要时递归造成的栈空间的使用,最好情况时其空间复杂度为 O (logn),对应递归树的深度。最坏情况时则需要 n-1 次递归调用,此时空间复杂度为 O(n). **快速排序的稳定性分析** @@ -158,7 +158,7 @@ class Solution { ![稳定性](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210218165440.17ovoc8246gw.png) -此时无论使用哪一种方法,第一次排序后,黄色的 1 都会跑到红色 1 的前面,所以快速排序是不稳定的排序算法。 +此时无论使用哪一种方法,第一次排序后,黄色的 1 都会跑到红色 1 的前面,所以快速排序是不稳定的排序算法。 ![性能分析](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210218170306.6oe0mbb5gr40.png) @@ -170,7 +170,7 @@ class Solution { ```java class Solution { - + public int[] sortArray(int[] nums) { Stack stack = new Stack<>(); stack.push(nums.length - 1); @@ -191,25 +191,25 @@ class Solution { } public int partition (int[] nums, int low, int high) { - + int pivot = nums[low]; int start = low; while (low < high) { - while (low < high && nums[high] >= pivot) high--; + while (low < high && nums[high] >= pivot) high--; while (low < high && nums[low] <= pivot) low++; if (low >= high) break; - swap(nums, low, high); + swap(nums, low, high); } swap(nums,start,low); return low; - } - public void swap (int[] nums, int i, int j) { + } + public void swap (int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; - } + } } ``` @@ -231,7 +231,7 @@ class Solution { int mid = low + ((high-low) >> 1); if (nums[low] > nums[high]) swap(nums,low,high); if (nums[mid] > nums[high]) swap(nums,mid,high); - if (nums[mid] > nums[low]) swap(nums,mid,low); + if (nums[mid] > nums[low]) swap(nums,mid,low); ``` 其含义就是让我们将中间元素放到 nums[low] 位置做为基准值,最大值放到 nums[high],最小值放到 nums[mid],即 [4,2,3] 经过上面代码处理后,则变成了 [3,2,4].此时我们选取 3 做为基准值,这样也就避免掉了选取最大或最小值做为基准值的情况。 @@ -240,7 +240,7 @@ class Solution { ```java class Solution { - public int[] sortArray(int[] nums) { + public int[] sortArray(int[] nums) { quickSort(nums,0,nums.length-1); return nums; } @@ -249,7 +249,7 @@ class Solution { int index = partition(nums,low,high); quickSort(nums,low,index-1); quickSort(nums,index+1,high); - } + } } public int partition (int[] nums, int low, int high) { @@ -257,24 +257,24 @@ class Solution { int mid = low + ((high-low) >> 1); if (nums[low] > nums[high]) swap(nums,low,high); if (nums[mid] > nums[high]) swap(nums,mid,high); - if (nums[mid] > nums[low]) swap(nums,mid,low); + if (nums[mid] > nums[low]) swap(nums,mid,low); //下面和之前一样,仅仅是多了上面几行代码 int pivot = nums[low]; int start = low; while (low < high) { - while (low < high && nums[high] >= pivot) high--; + while (low < high && nums[high] >= pivot) high--; while (low < high && nums[low] <= pivot) low++; if (low >= high) break; - swap(nums, low, high); + swap(nums, low, high); } swap(nums,start,low); return low; - } - public void swap (int[] nums, int i, int j) { + } + public void swap (int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; - } + } } ``` @@ -287,43 +287,43 @@ class Solution { ```java class Solution { private static final int INSERTION_SORT_MAX_LENGTH = 7; - - public int[] sortArray(int[] nums) { + + public int[] sortArray(int[] nums) { quickSort(nums,0,nums.length-1); return nums; } - + public void quickSort (int[] nums, int low, int high) { - + if (high - low <= INSERTION_SORT_MAX_LENGTH) { insertSort(nums,low,high); return; - } + } int index = partition(nums,low,high); quickSort(nums,low,index-1); - quickSort(nums,index+1,high); + quickSort(nums,index+1,high); } - + public int partition (int[] nums, int low, int high) { //三数取中,大家也可以使用其他方法 int mid = low + ((high-low) >> 1); if (nums[low] > nums[high]) swap(nums,low,high); if (nums[mid] > nums[high]) swap(nums,mid,high); - if (nums[mid] > nums[low]) swap(nums,mid,low); + if (nums[mid] > nums[low]) swap(nums,mid,low); int pivot = nums[low]; int start = low; while (low < high) { - while (low < high && nums[high] >= pivot) high--; + while (low < high && nums[high] >= pivot) high--; while (low < high && nums[low] <= pivot) low++; if (low >= high) break; - swap(nums, low, high); + swap(nums, low, high); } swap(nums,start,low); return low; - } - + } + public void insertSort (int[] nums, int low, int high) { - + for (int i = low+1; i <= high; ++i) { int temp = nums[i]; int j; @@ -331,18 +331,18 @@ class Solution { if (temp < nums[j]) { nums[j+1] = nums[j]; continue; - } + } break; } nums[j+1] = temp; } - } + } public void swap (int[] nums, int i, int j) { - + int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; - } + } } ``` @@ -362,7 +362,7 @@ class Solution { ![三向切分](https://img-blog.csdnimg.cn/20210317190456320.gif#pic_center) -我们来剖析一下视频,其实原理很简单,我们利用探路指针也就是 i,遇到比 pivot 大的元素,则和 right 指针进行交换,此时 right 指向的元素肯定比 pivot 大,则 right--,但是,此时我们的 nums[i] 指向的元素并不知道情况,所以我们的 i 指针不动,如果此时 nums[i] < pivot 则与 left 指针交换,注意此时我们的 left 指向的值肯定是 等于 povit的,所以交换后我们要 left++,i++, nums[i] == pivot 时,仅需要 i++ 即可,继续判断下一个元素。 我们也可以借助这个思想来解决经典的荷兰国旗问题。 +我们来剖析一下视频,其实原理很简单,我们利用探路指针也就是 i,遇到比 pivot 大的元素,则和 right 指针进行交换,此时 right 指向的元素肯定比 pivot 大,则 right--,但是,此时我们的 nums[i] 指向的元素并不知道情况,所以我们的 i 指针不动,如果此时 nums[i] < pivot 则与 left 指针交换,注意此时我们的 left 指向的值肯定是 等于 povit 的,所以交换后我们要 left++,i++, nums[i] == pivot 时,仅需要 i++ 即可,继续判断下一个元素。 我们也可以借助这个思想来解决经典的荷兰国旗问题。 好啦,我们下面直接看代码吧。 @@ -408,7 +408,7 @@ class Solution { quickSort(nums,right+1,high); } public void insertSort (int[] nums, int low, int high) { - + for (int i = low+1; i <= high; ++i) { int temp = nums[i]; int j; @@ -416,12 +416,12 @@ class Solution { if (temp < nums[j]) { nums[j+1] = nums[j]; continue; - } + } break; } nums[j+1] = temp; } - } + } public void swap (int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; @@ -432,7 +432,7 @@ class Solution { Python Code: -```python +```python from typing import List class Solution: INSERTION_SORT_MAX_LENGTH = 7 @@ -489,6 +489,4 @@ class Solution: nums[j] = temp ``` - 好啦,一些常用的优化方法都整理出来啦,还有一些其他的优化算法九数取中,优化递归操作等就不在这里进行描述啦,感兴趣的可以自己看一下。好啦,这期的文章就到这里啦,我们下期见,拜了个拜。 - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\346\241\266\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\346\241\266\346\216\222\345\272\217.md" index bb08712..4d7fa8a 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\346\241\266\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\346\241\266\346\216\222\345\272\217.md" @@ -6,7 +6,7 @@ 但是当我们遇到 double 类型的数怎么办呢? -例如每日温度,26.2, 21.2, 19.8 等 +例如每日温度,26.2, 21.2, 19.8 等 所以我们今天来学一个新的线性排序算法,大家继续往下看吧 @@ -66,8 +66,6 @@ ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210331162409.6gz2xev8lgg0.png) - - 那么桶排序是完全适用于任何情况的吗?当然不是,我们思考下这种情况 ![微信截图_20210331173942](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210331173942.5w8mixnni5k0.png) @@ -80,7 +78,7 @@ **桶排序的空间复杂度分析** -桶排序使用了辅助空间所以空间复杂度为 O(n) +桶排序使用了辅助空间所以空间复杂度为 O(n) **桶排序的稳定性分析** @@ -102,4 +100,3 @@ ``` 好啦,大致含义我们就搞定啦,另外桶排序的原理很容易理解,但是代码不是特别容易实现,大家可以选择性阅读。 - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.md" index e2fd1eb..5a07a95 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### **直接插入排序(Straight Insertion Sort)** @@ -38,7 +38,7 @@ class Solution { if (temp < nums[j]) { nums[j+1] = nums[j]; continue; - } + } //跳出循环 break; } @@ -77,19 +77,18 @@ class Solution: **直接插入排序时间复杂度分析** -最好情况时,也就是有序的时候,我们不需要移动元素,每次只需要比较一次即可找到插入位置,那么最好情况时的时间复杂度为O(n)。 +最好情况时,也就是有序的时候,我们不需要移动元素,每次只需要比较一次即可找到插入位置,那么最好情况时的时间复杂度为 O(n)。 -最坏情况时,即待排序表是逆序的情况,则此时需要比较2+3+....+n = (n+2)*(n-1)/2,移动次数也达到了最大值,3 +4+5+....n+1 = (n+4)*(n-1)/2,时间复杂度为O(n^2). +最坏情况时,即待排序表是逆序的情况,则此时需要比较 2+3+....+n = (n+2)_(n-1)/2,移动次数也达到了最大值,3 +4+5+....n+1 = (n+4)_(n-1)/2,时间复杂度为 O(n^2). -我们每次插入一个数据的时间复杂度为O(n),那么循环执行 n 次插入操作,平均时间复杂度为O(n^2)。 +我们每次插入一个数据的时间复杂度为 O(n),那么循环执行 n 次插入操作,平均时间复杂度为 O(n^2)。 **直接插入排序空间复杂度分析** -根据动画可知,插入排序不需要额外的存储空间,所以其空间复杂度为O(1) +根据动画可知,插入排序不需要额外的存储空间,所以其空间复杂度为 O(1) **直接插入排序稳定性分析** 我们根据代码可知,我们只会移动比 temp 值大的元素,所以我们排序后可以保证相同元素的相对位置不变。所以直接插入排序为稳定性排序算法。 ![](https://cdn.jsdelivr.net/gh/tan45du/bedphoto2@master/20210122/微信截图_20210128084750.6911k6mnrac0.png) - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.md" index 01a909d..2c461bd 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### **简单选择排序** @@ -10,8 +10,6 @@ ![](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210120150816.4za4u7331sw0.png) - - 例如上图,绿色代表已经排序的元素,红色代表未排序的元素。我们当前指针指向 4 ,则我们遍历红色元素,从中找到最小值,然后与 4 交换。我们发现选择排序执行完一次循环也至少可以将 1 个元素归位。 下面我们来看一下代码的执行过程,看过之后肯定能写出代码的。 @@ -33,10 +31,10 @@ class Solution { for (int i = 0; i < len; ++i) { min = i; //遍历到最小值 - for (int j = i + 1; j < len; ++j) { - if (nums[min] > nums[j]) min = j; + for (int j = i + 1; j < len; ++j) { + if (nums[min] > nums[j]) min = j; } - if (min != i) swap(nums,i,min); + if (min != i) swap(nums,i,min); } return nums; } @@ -72,10 +70,9 @@ class Solution: nums[j] = temp ``` - **简单选择排序时间复杂度分析** -从简单选择排序的过程来看,他最大的特点就是交换移动数据次数相当少,这样也就节省了排序时间,简单选择和冒泡排序不一样,我们发现无论最好情况和最坏情况,元素间的比较次数是一样的,第 i 次排序,需要 n - i 次比较,n 代表数组长度,则一共需要比较(n-1) + (n-2) +.... + 2 + 1= n*(n-1)/2 次,对于交换而言,最好情况交换 0 次,最坏情况(逆序时)交换 n - 1次。那么简单选择排序时间复杂度也为 O(n^2) 但是其交换次数远小于冒泡排序,所以其效率是好于冒泡排序的。 +从简单选择排序的过程来看,他最大的特点就是交换移动数据次数相当少,这样也就节省了排序时间,简单选择和冒泡排序不一样,我们发现无论最好情况和最坏情况,元素间的比较次数是一样的,第 i 次排序,需要 n - i 次比较,n 代表数组长度,则一共需要比较(n-1) + (n-2) +.... + 2 + 1= n\*(n-1)/2 次,对于交换而言,最好情况交换 0 次,最坏情况(逆序时)交换 n - 1 次。那么简单选择排序时间复杂度也为 O(n^2) 但是其交换次数远小于冒泡排序,所以其效率是好于冒泡排序的。 **简单选择排序空间复杂度分析** @@ -89,9 +86,6 @@ class Solution: 此时我们需要从后面元素中找到最小的元素与指针指向元素交换,也就是元素 2 。但是我们交换后发现,两个相等元素 3 的相对位置发生了改变,所以简单选择排序是不稳定的排序算法。 - - | 算法名称 | 最好时间复杂度 | 最坏时间复杂度 | 平均时间复杂度 | 空间复杂度 | 是否稳定 | | ------------ | -------------- | -------------- | -------------- | ---------- | -------- | | 简单选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 | - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\277\273\350\275\254\345\257\271.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\277\273\350\275\254\345\257\271.md" index 909b55d..81d652f 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\277\273\350\275\254\345\257\271.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\347\277\273\350\275\254\345\257\271.md" @@ -1,14 +1,14 @@ #### [leetcode 493 翻转对](https://leetcode-cn.com/problems/reverse-pairs/) -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 **题目描述** -给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。 +给定一个数组 nums ,如果 i < j 且 nums[i] > 2\*nums[j] 我们就将 (i, j) 称作一个重要翻转对。 你需要返回给定数组中的重要翻转对的数量。 @@ -30,11 +30,11 @@ ![翻转对](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210214121010.50g9z0xgda80.png) -此时我们发现 6 > 2 * 2,所以此时是符合情况的,因为小数组是单调递增的,所以 6 后面的元素都符合条件,所以我们 count += mid - temp1 + 1;则我们需要移动紫色指针,判断后面是否还存在符合条件的情况。 +此时我们发现 6 > 2 \* 2,所以此时是符合情况的,因为小数组是单调递增的,所以 6 后面的元素都符合条件,所以我们 count += mid - temp1 + 1;则我们需要移动紫色指针,判断后面是否还存在符合条件的情况。 ![翻转对](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210214121711.77crljdzra00.png) -我们此时发现 6 = 3 * 2,不符合情况,因为小数组都是完全有序的,所以我们可以移动红色指针,看下后面的数有没有符合条件的情况。这样我们就可以得到翻转对的数目啦。下面我们直接看动图加深下印象吧! +我们此时发现 6 = 3 \* 2,不符合情况,因为小数组都是完全有序的,所以我们可以移动红色指针,看下后面的数有没有符合条件的情况。这样我们就可以得到翻转对的数目啦。下面我们直接看动图加深下印象吧! ![](https://img-blog.csdnimg.cn/20210317192545806.gif#pic_center) @@ -45,7 +45,7 @@ Java Code: ```java class Solution { private int count; - + public int reversePairs(int[] nums) { count = 0; merge(nums, 0, nums.length - 1); @@ -128,7 +128,7 @@ class Solution: temp2 += 1 else: temp1 += 1 - + # 记得归位,我们还要继续使用 temp1 = left temp2 = mid + 1 @@ -145,8 +145,7 @@ class Solution: # 照旧 if temp1 <= mid: temparr[index: index + mid - temp1 + 1] = nums[temp1: temp1 + mid - temp1 + 1] - if temp2 <= right: + if temp2 <= right: temparr[index: index + right - temp2 + 1] = nums[temp2: temp2 + right - temp2 + 1] nums[left: left + right- left + 1] = temparr[0: right - left + 1] ``` - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\350\215\267\345\205\260\345\233\275\346\227\227.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\350\215\267\345\205\260\345\233\275\346\227\227.md" index 71078f3..3fde3ad 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\350\215\267\345\205\260\345\233\275\346\227\227.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\350\215\267\345\205\260\345\233\275\346\227\227.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 今天我们一起来看一下可以用快速排序秒杀的经典题,或许这些题目大家已经做过,不过可以再来一起复习一遍,加深印象。 @@ -16,7 +16,7 @@ 问题描述: -荷兰国旗是由红白蓝3种颜色的条纹拼接而成,如下图所示: +荷兰国旗是由红白蓝 3 种颜色的条纹拼接而成,如下图所示: ![荷兰国旗](https://cdn.jsdelivr.net/gh/tan45du/test@master/photo/微信截图_20210305145819.4jrud8f8xny0.png) @@ -24,15 +24,13 @@ ![荷兰国旗问题](https://cdn.jsdelivr.net/gh/tan45du/test@master/photo/7789414-8baf85cac6228621.62ygbgv09ek0.png) - - 需求是:把这些条纹按照颜色排好,红色的在上半部分,白色的在中间部分,蓝色的在下半部分,我们把这类问题称作荷兰国旗问题。 我们把荷兰国旗问题用数组的形式表达一下是这样的: -给定一个整数数组,给定一个值K,这个值在原数组中一定存在,要求把数组中小于 K 的元素放到数组的左边,大于K的元素放到数组的右边,等于K的元素放到数组的中间,最终返回一个整数数组,其中只有两个值,分别是等于K的数组部分的左右两个下标值。 +给定一个整数数组,给定一个值 K,这个值在原数组中一定存在,要求把数组中小于 K 的元素放到数组的左边,大于 K 的元素放到数组的右边,等于 K 的元素放到数组的中间,最终返回一个整数数组,其中只有两个值,分别是等于 K 的数组部分的左右两个下标值。 -例如,给定数组:[2, 3, 1, 9, 7, 6, 1, 4, 5],给定一个值4,那么经过处理原数组可能得一种情况是:[2, 3, 1, 1, 4, 9, 7, 6, 5],需要注意的是,小于4的部分不需要有序,大于4的部分也不需要有序,返回等于4部分的左右两个下标,即[4, 4] +例如,给定数组:[2, 3, 1, 9, 7, 6, 1, 4, 5],给定一个值 4,那么经过处理原数组可能得一种情况是:[2, 3, 1, 1, 4, 9, 7, 6, 5],需要注意的是,小于 4 的部分不需要有序,大于 4 的部分也不需要有序,返回等于 4 部分的左右两个下标,即[4, 4] 这不就是我们之前说过的三向切分吗?一模一样! @@ -68,7 +66,7 @@ **做题思路** -这个题目我们使用 Arrays.sort() 解决,哈哈,但是那样太无聊啦,题目含义就是让我们将所有的 0 放在前面,2放在后面,1 放在中间,是不是和我们上面说的荷兰国旗问题一样。我们仅仅将 1 做为 pivot 值。 +这个题目我们使用 Arrays.sort() 解决,哈哈,但是那样太无聊啦,题目含义就是让我们将所有的 0 放在前面,2 放在后面,1 放在中间,是不是和我们上面说的荷兰国旗问题一样。我们仅仅将 1 做为 pivot 值。 下面我们直接看代码吧,和三向切分基本一致。 @@ -82,7 +80,7 @@ class Solution { //这里和三向切分不完全一致 int i = left; int right = len-1; - + while (i <= right) { if (nums[i] == 2) { swap(nums,i,right--); @@ -91,7 +89,7 @@ class Solution { } else { i++; } - } + } } public void swap (int[] nums, int i, int j) { int temp = nums[i]; @@ -112,7 +110,7 @@ public: //这里和三向切分不完全一致 int i = left; int right = len-1; - + while (i <= right) { if (nums[i] == 2) { swap(nums,i,right--); @@ -137,7 +135,7 @@ Python Code: ```python from typing import List class Solution: - def sortColors(self, nums: List[int]): + def sortColors(self, nums: List[int]): leng = len(nums) left = 0 # 这里和三向切分不完全一致 @@ -153,17 +151,18 @@ class Solution: left += 1 else: i += 1 - + def swap(self, nums: List[int], i: int, j: int): temp = nums[i] nums[i] = nums[j] nums[j] = temp ``` + 另外我们看这段代码,有什么问题呢?那就是我们即使完全符合时,仍会交换元素,这样会大大降低我们的效率。 例如:[0,0,0,1,1,1,2,2,2] -此时我们完全符合情况,不需要交换元素,但是按照我们上面的代码,0,2 的每个元素会和自己进行交换,所以这里我们可以根据 i 和 left 的值是否相等来决定是否需要交换,大家可以自己写一下。 +此时我们完全符合情况,不需要交换元素,但是按照我们上面的代码,0,2 的每个元素会和自己进行交换,所以这里我们可以根据 i 和 left 的值是否相等来决定是否需要交换,大家可以自己写一下。 下面我们看一下另外一种写法 @@ -187,7 +186,7 @@ class Solution { int len = nums.length; int right = len - 1; for (int i = 0; i <= right; ++i) { - if (nums[i] == 0) { + if (nums[i] == 0) { swap(nums,i,left); left++; } @@ -200,7 +199,7 @@ class Solution { } } } - + } public void swap (int[] nums,int i, int j) { int temp = nums[i]; @@ -220,7 +219,7 @@ public: int len = nums.size(); int right = len - 1; for (int i = 0; i <= right; ++i) { - if (nums[i] == 0) { + if (nums[i] == 0) { swap(nums,i,left); left++; } @@ -233,7 +232,7 @@ public: } } } - + } void swap (vector& nums, int i, int j) { int temp = nums[i]; @@ -268,4 +267,3 @@ class Solution: ``` 好啦,这个问题到这就结束啦,是不是很简单啊,我们明天见! - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\350\256\241\346\225\260\346\216\222\345\272\217.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\350\256\241\346\225\260\346\216\222\345\272\217.md" index 1f99359..0463fdc 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\350\256\241\346\225\260\346\216\222\345\272\217.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\350\256\241\346\225\260\346\216\222\345\272\217.md" @@ -1,26 +1,26 @@ # 计数排序 -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 今天我们就一起来看看线性排序里的计数排序到底是怎么回事吧。 我们将镜头切到袁记菜馆 -因为今年袁记菜馆的效益不错,所以袁厨就想给员工发些小福利,让小二根据员工工龄进行排序,但是菜馆共有 100000 名员工,菜馆开业 10 年,员工工龄从 0 - 10 不等。看来这真是一个艰巨的任务啊。 +因为今年袁记菜馆的效益不错,所以袁厨就想给员工发些小福利,让小二根据员工工龄进行排序,但是菜馆共有 100000 名员工,菜馆开业 10 年,员工工龄从 0 - 10 不等。看来这真是一个艰巨的任务啊。 当然我们可以借助之前说过的 归并排序 和 快速排序解决,但是我们有没有其他更好的方法呢? 了解排序算法的老哥可能已经猜到今天写什么啦。是滴,我们今天来写写用空间换时间的线性排序。 -说之前我们先来回顾一下之前的排序算法,最好的时间复杂度为 O(nlogn) ,且都基于元素之间的比较来进行排序, +说之前我们先来回顾一下之前的排序算法,最好的时间复杂度为 O(nlogn) ,且都基于元素之间的比较来进行排序, 我们来说一下非基于元素比较的排序算法,且时间复杂度为 O(n),时间复杂度是线性的,所以我们称其为线性排序算法。 -其优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k),此时的 k 则代表整数的范围。快于任何一种比较类排序算法,不过也是需要牺牲一些空间来换取时间。 +其优势在于在对一定范围内的整数排序时,它的复杂度为 Ο(n+k),此时的 k 则代表整数的范围。快于任何一种比较类排序算法,不过也是需要牺牲一些空间来换取时间。 下面我们先来看看什么是计数排序,这个计数的含义是什么? @@ -50,10 +50,6 @@ ![微信截图_20210327202256](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210327202256.7g3nka7n0p40.png) - - - - 虽然喵哥和杰哥工龄相同,如果我们按照上面的操作输出之后,我们不能知道工龄为 4 的两个员工,哪个是喵哥哪个是杰哥。 所以我们需要借助其他方法来对元素进行排序。 @@ -62,13 +58,9 @@ ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210328131226.3x42hsrnna80.png) - - - - 因为我们是通过统计次数的数组得到了前缀和数组,那么我们来分析一下 presum 数组里面值的含义。 -例如我们的 presum[2] = 5 ,代表的则是原数组小于等于 2 的值共有 5 个。presum[4] = 7 代表小于等于 4 的元素共有 7 个。 +例如我们的 presum[2] = 5 ,代表的则是原数组小于等于 2 的值共有 5 个。presum[4] = 7 代表小于等于 4 的元素共有 7 个。 是不是感觉计数排序的含义要慢慢显现出来啦。 @@ -88,7 +80,7 @@ ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210328133401.23fulpjowbnk.png) -我们继续查询 presum 数组,发现 presum[5] = 9,则说明小于等于 5 的数共有 9 个,我们将其放入到 temp 数组的第 9 个位置,也就是 +我们继续查询 presum 数组,发现 presum[5] = 9,则说明小于等于 5 的数共有 9 个,我们将其放入到 temp 数组的第 9 个位置,也就是 temp[8] = 5。然后再将 presum[5] 减 1 。 @@ -106,7 +98,7 @@ temp[8] = 5。然后再将 presum[5] 减 1 。 但是到现在就完了吗?显然没有,我们思考下这个情况。 -假如我们的数字为 90,93,94,91,92 如果我们根据上面方法设置 presum 数组的长度,那我们则需要设置数组长度为 95(因为最大值是94),这样显然是不合理的,会浪费掉很多空间。 +假如我们的数字为 90,93,94,91,92 如果我们根据上面方法设置 presum 数组的长度,那我们则需要设置数组长度为 95(因为最大值是 94),这样显然是不合理的,会浪费掉很多空间。 还有就是当我们需要对负数进行排序时同样会出现问题,因为我们求次数的时候是根据 nums[index] 的值来填充 presum 数组的,所以当 nums[index] 为负数时,填充 presum 数组时则会报错。而且此时通过最大值来定义数组长度也不合理。 @@ -114,7 +106,7 @@ temp[8] = 5。然后再将 presum[5] 减 1 。 下面我们来说一下偏移量的概念。 -例如 90,93,94,91,92,我们 可以通过 max ,min 的值来设置数组长度即 94 - 90 + 1 = 5 。偏移量则为 min 值,也就是 90。 +例如 90,93,94,91,92,我们 可以通过 max ,min 的值来设置数组长度即 94 - 90 + 1 = 5 。偏移量则为 min 值,也就是 90。 见下图。 @@ -133,7 +125,7 @@ Java Code: ```java class Solution { public int[] sortArray(int[] nums) { - + int len = nums.length; if (nums.length < 1) { return nums; @@ -142,8 +134,8 @@ class Solution { int max = nums[0]; int min = nums[0]; for (int x : nums) { - if (max < x) max = x; - if (min > x) min = x; + if (max < x) max = x; + if (min > x) min = x; } //设置 presum 数组长度,然后求出我们的前缀和数组, //这里我们可以把求次数数组和前缀和数组用一个数组处理 @@ -152,7 +144,7 @@ class Solution { presum[x-min]++; } for (int i = 1; i < presum.length; ++i) { - presum[i] = presum[i-1]+presum[i]; + presum[i] = presum[i-1]+presum[i]; } //临时数组 int[] temp = new int[len]; @@ -162,7 +154,7 @@ class Solution { int index = presum[nums[i]-min]-1; temp[index] = nums[i]; //相应位置减一 - presum[nums[i]-min]--; + presum[nums[i]-min]--; } //copy回原数组 System.arraycopy(temp,0,nums,0,len); @@ -174,7 +166,7 @@ class Solution { Python Code: ```python -from typing import List +from typing import List class Solution: def sortArray(self,nums: List[int])->List[int]: leng = len(nums) @@ -230,4 +222,3 @@ class Solution: - 当待排序的元素非整数时,也不适用,大家思考一下这是为什么呢? 好啦,今天的文章就到这啦,我们下期再见,拜了个拜. - diff --git "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\351\200\206\345\272\217\345\257\271\351\227\256\351\242\230.md" "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\351\200\206\345\272\217\345\257\271\351\227\256\351\242\230.md" index 26f393e..941a5cf 100644 --- "a/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\351\200\206\345\272\217\345\257\271\351\227\256\351\242\230.md" +++ "b/animation-simulation/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/\351\200\206\345\272\217\345\257\271\351\227\256\351\242\230.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [剑指 offer 51 数组中的逆序对](https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof) @@ -10,13 +10,13 @@ ![逆序对](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/逆序对.2p9sfhlbkaw0.png) -是不是很容易理解,因为数组是无序的,当较大的数,出现在较小数前面的时候,它俩则可以组成逆序对。因为数组的(有序度+逆序度)= n (n-1) / 2,逆序对个数 = 数组的逆序度,有序对个数 = 数组的有序度,所以我们知道有序对个数的话,也能得到逆序对的个数。另外我们如何通过归并排序来计算逆序对个数呢? +是不是很容易理解,因为数组是无序的,当较大的数,出现在较小数前面的时候,它俩则可以组成逆序对。因为数组的(有序度+逆序度)= n (n-1) / 2,逆序对个数 = 数组的逆序度,有序对个数 = 数组的有序度,所以我们知道有序对个数的话,也能得到逆序对的个数。另外我们如何通过归并排序来计算逆序对个数呢? 关键点在我们的**归并过程中**,我们先来看下归并过程中是怎么计算逆序对个数的。见下图 ![逆序对举例](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/微信截图_20210212200744.1upng86ndbr4.png) -我们来拆解下上图,我们此时 temp1 指向元素为 6,temp2 指向元素为 2, nums[temp1] > temp[temp2],则此时我们需要将 temp2 指向的元素存入临时数组中,又因为每个小集合中的元素都是有序的,所以 temp1 后面的元素也一定大于 2,那么我们就可以根据 temp1 的索引得出逆序对中包含 2 的逆序对个数,则是 mid - temp + 1。 +我们来拆解下上图,我们此时 temp1 指向元素为 6,temp2 指向元素为 2, nums[temp1] > temp[temp2],则此时我们需要将 temp2 指向的元素存入临时数组中,又因为每个小集合中的元素都是有序的,所以 temp1 后面的元素也一定大于 2,那么我们就可以根据 temp1 的索引得出逆序对中包含 2 的逆序对个数,则是 mid - temp + 1。 好啦这个题目你已经会做啦,下面我们一起来做下吧。 @@ -31,7 +31,7 @@ **题目解析** -各位如果忘记归并排序的话,可以再看一下咱们之前的文章回顾一下 [归并排序详解](https://mp.weixin.qq.com/s/YK43J73UNFRjX4r0vh13ZA),这个题目我们仅仅在归并排序的基础上加了一行代码。那就是在归并过程时,nums[temp2] < nums[temp1] 时统计个数。下面我们直接看代码吧。 +各位如果忘记归并排序的话,可以再看一下咱们之前的文章回顾一下 [归并排序详解](https://mp.weixin.qq.com/s/YK43J73UNFRjX4r0vh13ZA),这个题目我们仅仅在归并排序的基础上加了一行代码。那就是在归并过程时,nums[temp2] < nums[temp1] 时统计个数。下面我们直接看代码吧。 **题目代码** @@ -40,9 +40,9 @@ Java Code: ```java class Solution { //全局变量 - private int count; + private int count; public int reversePairs(int[] nums) { - count = 0; + count = 0; merge(nums,0,nums.length-1); return count; } @@ -65,7 +65,7 @@ class Solution { int temp1 = left, temp2 = mid+1; while (temp1 <= mid && temp2 <= right) { - + if (nums[temp1] <= nums[temp2]) { temparr[index++] = nums[temp1++]; } else { @@ -74,7 +74,7 @@ class Solution { temparr[index++] = nums[temp2++]; } } - + if (temp1 <= mid) System.arraycopy(nums,temp1,temparr,index,mid-temp1+1); if (temp2 <= right) System.arraycopy(nums,temp2,temparr,index,right-temp2+1); System.arraycopy(temparr,0,nums,left,right-left+1); @@ -98,8 +98,8 @@ class Solution: mid = left + ((right - left) >> 1) self.mergeSort(arr, left, mid) self.mergeSort(arr, mid + 1, right) - self.merge(arr, left, mid, right) - + self.merge(arr, left, mid, right) + # 归并 def merge(self, arr: List[int], left: int, mid: int, right: int): # 第一步,定义一个新的临时数组 @@ -121,20 +121,15 @@ class Solution: # 对应第三步,将某一集合的剩余元素存到大集合中 if temp1 <= mid: temparr[index: index + mid - temp1 + 1] = arr[temp1: temp1 + mid - temp1 + 1] - if temp2 <= right: + if temp2 <= right: temparr[index: index + right - temp2 + 1] = arr[temp2: temp2 + right - temp2 + 1] - + # 将大集合的元素复制回原数组 arr[left: left + right- left + 1] = temparr[0: right - left + 1] ``` 好啦,这个题目我们就解决啦,哦对,大家也可以顺手去解决下这个题目。leetcode 912 排序数组,这个题目大家可以用来练手,因为有些排序算法是面试高频考点,所以大家可以防止遗忘,多用这个题目进行练习,防止手生。下面则是我写文章时代码的提交情况,冒泡排序怎么优化都会超时,其他排序算法倒是都可以通过。 - - ![排序](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/排序.1unok1gcygtc.png) - - 好啦,下面我们继续做一个题目吧,也完全可以用归并排序解决,稍微加了一丢丢代码,但是也是很好理解的。感谢支持 - diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1052\347\210\261\347\224\237\346\260\224\347\232\204\344\271\246\345\272\227\350\200\201\346\235\277.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1052\347\210\261\347\224\237\346\260\224\347\232\204\344\271\246\345\272\227\350\200\201\346\235\277.md" index b9a94ad..6f41ccc 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1052\347\210\261\347\224\237\346\260\224\347\232\204\344\271\246\345\272\227\350\200\201\346\235\277.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1052\347\210\261\347\224\237\346\260\224\347\232\204\344\271\246\345\272\227\350\200\201\346\235\277.md" @@ -1,10 +1,8 @@ - - -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [1052. 爱生气的书店老板](https://leetcode-cn.com/problems/grumpy-bookstore-owner/) @@ -18,7 +16,6 @@ 请你返回这一天营业下来,最多有多少客户能够感到满意的数量。 - 示例: > 输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3 @@ -28,8 +25,6 @@ 书店老板在最后 3 分钟保持冷静。 感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16. - - 该题目思想就是,我们将 customer 数组的值分为三部分, leftsum, winsum, rightsum。我们题目的返回值则是三部分的最大和。 注意这里的最大和,我们是怎么计算的。 @@ -48,9 +43,9 @@ rightsum 是窗口右区间的值,和左区间加和方式一样。那么我 我们此时移动了窗口, -则左半区间范围扩大,但是 leftsum 的值没有变,这时因为新加入的值,所对应的 grumpy[i] == 1,所以其值不会发生改变,因为我们只统计 grumpy[i] == 0 的值, +则左半区间范围扩大,但是 leftsum 的值没有变,这时因为新加入的值,所对应的 grumpy[i] == 1,所以其值不会发生改变,因为我们只统计 grumpy[i] == 0 的值, -右半区间范围减少,rightsum 值也减少,因为右半区间减小的值,其对应的 grumpy[i] == 0,所以 rightsum -= grumpy[i]。 +右半区间范围减少,rightsum 值也减少,因为右半区间减小的值,其对应的 grumpy[i] == 0,所以 rightsum -= grumpy[i]。 winsum 也会发生变化, winsum 需要加上新加入窗口的值,减去刚离开窗口的值, 也就是 customer[left-1],left 代表窗口左边缘。 @@ -72,15 +67,15 @@ class Solution { } } //窗口的值 - for (int i = 0; i < X; ++i) { - winsum += customers[i]; + for (int i = 0; i < X; ++i) { + winsum += customers[i]; } int leftsum = 0; //窗口左边缘 int left = 1; //窗口右边缘 int right = X; - int maxcustomer = winsum + leftsum + rightsum; + int maxcustomer = winsum + leftsum + rightsum; while (right < customers.length) { //重新计算左区间的值,也可以用 customer 值和 grumpy 值相乘获得 if (grumpy[left-1] == 0) { @@ -97,7 +92,7 @@ class Solution { //移动窗口 left++; right++; - } + } return maxcustomer; } } @@ -114,5 +109,91 @@ class Solution: ans = max(ans, t) return ans ``` - +Swift Code + +```swift +class Solution { + func maxSatisfied(_ customers: [Int], _ grumpy: [Int], _ minutes: Int) -> Int { + let len = customers.count + var winSum = 0, rightSum = 0, leftSum = 0 + // 右区间的值 + for i in minutes.. &customers, vector &grumpy, int minutes) + { + for_each(grumpy.begin(), grumpy.end(), [](auto &g){ g = !g; }); + vector osum(customers.size(), 0); + + //先初始化第一个元素 + osum[0] = customers[0] * grumpy[0]; + //计算前缀和, osum是origin sum + for (int i = 1; i < osum.size(); i++) + { + osum[i] = osum[i - 1] + customers[i] * grumpy[i]; + } + + //计算连续minutes的和 + vector msum(customers.size() - minutes + 1, 0); + for (int i = 0; i < minutes; i++) + { + msum[0] += customers[i]; + } + for (int i = 1; i < msum.size(); i++) + { + msum[i] = msum[i - 1] - customers[i - 1] + customers[i + minutes - 1]; + } + + //分成三段计算 + int result = 0; + for (int i = 0; i < msum.size(); i++) + { + //左 中 右 + //注意左的边界条件, 可以使用边界测试 + int sum = ((i - 1 >= 0) ? osum[i - 1] : 0) + msum[i] + osum[osum.size() - 1] - osum[i + minutes - 1]; + if (sum > result) + result = sum; + } + + return result; + } +}; +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1438\347\273\235\345\257\271\345\200\274\344\270\215\350\266\205\350\277\207\351\231\220\345\210\266\347\232\204\346\234\200\351\225\277\345\255\220\346\225\260\347\273\204.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1438\347\273\235\345\257\271\345\200\274\344\270\215\350\266\205\350\277\207\351\231\220\345\210\266\347\232\204\346\234\200\351\225\277\345\255\220\346\225\260\347\273\204.md" index 000facd..f9cc37c 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1438\347\273\235\345\257\271\345\200\274\344\270\215\350\266\205\350\277\207\351\231\220\345\210\266\347\232\204\346\234\200\351\225\277\345\255\220\346\225\260\347\273\204.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1438\347\273\235\345\257\271\345\200\274\344\270\215\350\266\205\350\277\207\351\231\220\345\210\266\347\232\204\346\234\200\351\225\277\345\255\220\346\225\260\347\273\204.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [1438. 绝对差不超过限制的最长连续子数组](https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/) @@ -13,7 +13,7 @@ 示例 > 输入:nums = [10,1,2,4,7,2], limit = 5 -> 输出:4 +> 输出:4 > 解释:满足题意的最长子数组是 [2,4,7,2],其最大绝对差 |2-7| = 5 <= 5 。 **提示:** @@ -48,7 +48,7 @@ Java Code: ```java class Solution { public int longestSubarray(int[] nums, int limit) { - + Deque maxdeque = new LinkedList<>(); Deque mindeque = new LinkedList<>(); int len = nums.length; @@ -61,9 +61,9 @@ class Solution { while (!mindeque.isEmpty() && mindeque.peekLast() > nums[right]) { mindeque.removeLast(); } - //需要更多视频解算法,可以来我的公众号:袁厨的算法小屋 + //需要更多视频解算法,可以来我的公众号:程序厨 maxdeque.addLast(nums[right]); - mindeque.addLast(nums[right]); + mindeque.addLast(nums[right]); while (maxdeque.peekFirst() - mindeque.peekFirst() > limit) { if (maxdeque.peekFirst() == nums[left]) maxdeque.removeFirst(); if (mindeque.peekFirst() == nums[left]) mindeque.removeFirst(); @@ -96,7 +96,7 @@ class Solution: maxdeque.pop() while len(mindeque) != 0 and mindeque[-1] > nums[right]: mindeque.pop() - + maxdeque.append(nums[right]) mindeque.append(nums[right]) while (maxdeque[0] - mindeque[0]) > limit: @@ -111,3 +111,195 @@ class Solution: return maxwin ``` +Swift Code + +Swift:数组模拟,超时(58 / 61 个通过测试用例) + +```swift +class Solution { + func longestSubarray(_ nums: [Int], _ limit: Int) -> Int { + var maxQueue:[Int] = [] + var minQueue:[Int] = [] + let len = nums.count + var right = 0, left = 0, maxWin = 0 + while right < len { + while !maxQueue.isEmpty && (maxQueue.last! < nums[right]) { + maxQueue.removeLast() + } + while !minQueue.isEmpty && (minQueue.last! > nums[right]) { + minQueue.removeLast() + } + maxQueue.append(nums[right]) + minQueue.append(nums[right]) + while (maxQueue.first! - minQueue.first!) > limit { + if maxQueue.first! == nums[left] { + maxQueue.removeFirst() + } + if minQueue.first! == nums[left] { + minQueue.removeFirst() + } + left += 1 + } + maxWin = max(maxWin, right - left + 1) + right += 1 + } + return maxWin + } +} +``` + +Swift:使用双端队列(击败了 100.00%) + +```swift +class Solution { + func longestSubarray(_ nums: [Int], _ limit: Int) -> Int { + var maxQueue = Deque.init() + var minQueue = Deque.init() + let len = nums.count + var right = 0, left = 0, maxWin = 0 + while right < len { + while !maxQueue.isEmpty && (maxQueue.peekBack()! < nums[right]) { + maxQueue.dequeueBack() + } + while !minQueue.isEmpty && (minQueue.peekBack()! > nums[right]) { + minQueue.dequeueBack() + } + maxQueue.enqueue(nums[right]) + minQueue.enqueue(nums[right]) + while (maxQueue.peekFront()! - minQueue.peekFront()!) > limit { + if maxQueue.peekFront()! == nums[left] { + maxQueue.dequeue() + } + if minQueue.peekFront()! == nums[left] { + minQueue.dequeue() + } + left += 1 + } + maxWin = max(maxWin, right - left + 1) + right += 1 + } + return maxWin + } + + // 双端队列数据结构 + public struct Deque { + private var array: [T?] + private var head: Int + private var capacity: Int + private let originalCapacity: Int + + public init(_ capacity: Int = 10) { + self.capacity = max(capacity, 1) + originalCapacity = self.capacity + array = [T?](repeating: nil, count: capacity) + head = capacity + } + + public var isEmpty: Bool { + return count == 0 + } + + public var count: Int { + return array.count - head + } + + public mutating func enqueue(_ element: T) { + array.append(element) + } + + public mutating func enqueueFront(_ element: T) { + if head == 0 { + capacity *= 2 + let emptySpace = [T?](repeating: nil, count: capacity) + array.insert(contentsOf: emptySpace, at: 0) + head = capacity + } + + head -= 1 + array[head] = element + } + + public mutating func dequeue() -> T? { + guard head < array.count, let element = array[head] else { return nil } + + array[head] = nil + head += 1 + + if capacity >= originalCapacity && head >= capacity*2 { + let amountToRemove = capacity + capacity/2 + array.removeFirst(amountToRemove) + head -= amountToRemove + capacity /= 2 + } + return element + } + + public mutating func dequeueBack() -> T? { + if isEmpty { + return nil + } else { + return array.removeLast() + } + } + + public func peekFront() -> T? { + if isEmpty { + return nil + } else { + return array[head] + } + } + + public func peekBack() -> T? { + if isEmpty { + return nil + } else { + return array.last! + } + } + } +} +``` + +Go Code: + +```go +func longestSubarray(nums []int, limit int) int { + maxdeq := []int{} // 递减队列 + mindeq := []int{} // 递增队列 + + length := len(nums) + left, right, maxwin := 0, 0, 0 + for right < length { + for len(maxdeq) != 0 && maxdeq[len(maxdeq) - 1] < nums[right] { + maxdeq = maxdeq[: len(maxdeq) - 1] + } + maxdeq = append(maxdeq, nums[right]) + + for len(mindeq) != 0 && mindeq[len(mindeq) - 1] > nums[right] { + mindeq = mindeq[: len(mindeq) - 1] + } + mindeq = append(mindeq, nums[right]) + + for maxdeq[0] - mindeq[0] > limit { + if maxdeq[0] == nums[left] { + maxdeq = maxdeq[1:] + } + if mindeq[0] == nums[left] { + mindeq = mindeq[1:] + } + left++ + } + maxwin = max(maxwin, right - left + 1) + right++ + } + return maxwin +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1\344\270\244\346\225\260\344\271\213\345\222\214.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1\344\270\244\346\225\260\344\271\213\345\222\214.md" index 89db733..d2980cd 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1\344\270\244\346\225\260\344\271\213\345\222\214.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode1\344\270\244\346\225\260\344\271\213\345\222\214.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [1. 两数之和](https://leetcode-cn.com/problems/two-sum/) @@ -25,11 +25,11 @@ **解析** -双指针(L,R)法的思路很简单,L指针用来指向第一个值,R指针用来从第L指针的后面查找数组中是否含有和L指针指向值和为目标值的数。见下图 +双指针(L,R)法的思路很简单,L 指针用来指向第一个值,R 指针用来从第 L 指针的后面查找数组中是否含有和 L 指针指向值和为目标值的数。见下图 ![图示](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信图片_20210104150003.3unncifeoe80.jpg) -例:绿指针指向的值为3,蓝指针需要在绿指针的后面遍历查找是否含有 target - 3 = 2的元素,若含有返回即可。 +例:绿指针指向的值为 3,蓝指针需要在绿指针的后面遍历查找是否含有 target - 3 = 2 的元素,若含有返回即可。 **题目代码** @@ -76,11 +76,37 @@ class Solution: return rearr ``` +Swift Code: + +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + let count = nums.count + if count < 2 { + return [0] + } + + var rearr: [Int] = [] + // 查询元素 + for i in 0..List[int]: @@ -159,3 +185,35 @@ class Solution: return [0] ``` +Swift Code: + +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var m:[Int:Int] = [:] + for i in 0.. 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -### [219 数组中重复元素2](https://leetcode-cn.com/problems/contains-duplicate-ii/) +### [219 数组中重复元素 2](https://leetcode-cn.com/problems/contains-duplicate-ii/) **题目描述** @@ -27,7 +27,7 @@ **Hashmap** -这个题目和我们上面那个数组中的重复数字几乎相同,只不过是增加了一个判断相隔是否小于K位的条件,我们先用 HashMap 来做一哈,和刚才思路一致,我们直接看代码就能整懂 +这个题目和我们上面那个数组中的重复数字几乎相同,只不过是增加了一个判断相隔是否小于 K 位的条件,我们先用 HashMap 来做一哈,和刚才思路一致,我们直接看代码就能整懂 Java Code: @@ -45,7 +45,7 @@ class Solution { if (map.containsKey(nums[i])) { //判断是否小于K,如果小于等于则直接返回 int abs = Math.abs(i - map.get(nums[i])); - if (abs <= k) return true;//小于等于则返回 + if (abs <= k) return true;//小于等于则返回 } //更新索引,此时有两种情况,不存在,或者存在时,将后出现的索引保存 map.put(nums[i],i); @@ -72,12 +72,54 @@ class Solution: # 判断是否小于K,如果小于等于则直接返回 a = abs(i - m[nums[i]]) if a <= k: - return True# 小于等于则返回 + return True# 小于等于则返回 # 更新索引,此时有两种情况,不存在,或者存在时,将后出现的索引保存 m[nums[i]] = i return False ``` +C++ Code: + +```cpp +class Solution { +public: + bool containsNearbyDuplicate(vector& nums, int k) { + unordered_map m; + for(int i = 0; i < nums.size(); ++i){ + if(m.count(nums[i]) && i - m[nums[i]] <= k) return true; + m[nums[i]] = i; + } + return false; + } +}; +``` + +Swift Code + +```swift +class Solution { + func containsNearbyDuplicate(_ nums: [Int], _ k: Int) -> Bool { + if nums.count == 0 { + return false + } + var dict:[Int:Int] = [:] + for i in 0.. k: s.remove(nums[i - k]) return False -``` +``` + +C++ Code: + +```cpp +class Solution { +public: + bool containsNearbyDuplicate(vector& nums, int k) { + multiset S; + for(int i = 0; i < nums.size(); ++i){ + if(S.count(nums[i])) return true; + S.insert(nums[i]); + if(S.size() > k) S.erase(nums[i - k]); + } + return false; + } +}; +``` + +Swift Code + +```swift +class Solution { + func containsNearbyDuplicate(_ nums: [Int], _ k: Int) -> Bool { + if nums.count == 0 { + return false + } + var set:Set = [] + for i in 0.. k { + set.remove(nums[i - k]) + } + } + return false + } +} +``` + +Go Code: + +```go +func containsNearbyDuplicate(nums []int, k int) bool { + length := len(nums) + if length == 0 { + return false + } + m := map[int]int{} + for i := 0; i < length; i++ { + if v, ok := m[nums[i]]; ok { + if i - v <= k { + return true + } + } + m[nums[i]] = i + } + return false +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode27\347\247\273\351\231\244\345\205\203\347\264\240.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode27\347\247\273\351\231\244\345\205\203\347\264\240.md" index db107bc..a9f9ddc 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode27\347\247\273\351\231\244\345\205\203\347\264\240.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode27\347\247\273\351\231\244\345\205\203\347\264\240.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [27. 移除元素](https://leetcode-cn.com/problems/remove-element/) @@ -36,17 +36,15 @@ **解析** -该题目也算是简单题目,适合新手来做,然后大家也不要看不起暴力解法,我们可以先写出暴力解法,然后再思考其他方法,这对于我们的编码能力有很大的帮助。我们来解析一下这个题目的做题思路,他的含义就是让我们删除掉数组中的元素,然后将数组后面的元素跟上来。最后返回删除掉元素的数组长度即可。比如数组长度为 10,里面有2个目标值,我们最后返回的长度为 8,但是返回的 8 个元素,需要排在数组的最前面。那么暴力解法的话则就需要两个 for 循环,一个用来找到删除,另一个用来更新数组。 +该题目也算是简单题目,适合新手来做,然后大家也不要看不起暴力解法,我们可以先写出暴力解法,然后再思考其他方法,这对于我们的编码能力有很大的帮助。我们来解析一下这个题目的做题思路,他的含义就是让我们删除掉数组中的元素,然后将数组后面的元素跟上来。最后返回删除掉元素的数组长度即可。比如数组长度为 10,里面有 2 个目标值,我们最后返回的长度为 8,但是返回的 8 个元素,需要排在数组的最前面。那么暴力解法的话则就需要两个 for 循环,一个用来找到删除,另一个用来更新数组。 ![移除数组元素暴力法](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/移除数组元素.lhuefelqd5o.png) - - 总体思路就是这样的,后面的会不断往前覆盖。暴力解法也是不超时的,实现也不算太简单主要需要注意两个地方。 -(1)需要先定义变量len获取数组长度,因为后面我们的返回的数组长度是改变的,所以不可以用 nums.length 作为上界 +(1)需要先定义变量 len 获取数组长度,因为后面我们的返回的数组长度是改变的,所以不可以用 nums.length 作为上界 -(2)我们每找到一个需要删除的值的时候,需要i--,防止出现多个需要删除的值在一起的情况,然后漏删。 +(2)我们每找到一个需要删除的值的时候,需要 i--,防止出现多个需要删除的值在一起的情况,然后漏删。 **题目代码** @@ -54,7 +52,7 @@ Java Code: ```java class Solution { - public int removeElement(int[] nums, int val) { + public int removeElement(int[] nums, int val) { //获取数组长度 int len = nums.length; if (len == 0) { @@ -72,7 +70,7 @@ class Solution { len--; } } - return i; + return i; } } ``` @@ -164,3 +162,43 @@ public: }; ``` +Swift Code + +```swift +class Solution { + func removeElement(_ nums: inout [Int], _ val: Int) -> Int { + if nums.count == 0 { + return 0 + } + var i = 0 + for j in 0.. 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [41. 缺失的第一个正数](https://leetcode-cn.com/problems/first-missing-positive/) @@ -31,7 +31,7 @@ ![微信截图_20210109135536](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210109135536.41h4amio2me0.png) -上图中,我们遍历一遍原数组,将正整数保存到新数组中,然后遍历新数组,第一次发现 newnum[i] != i 时,则说明该值是缺失的,返回即可,例如我上图中的第一个示例中的 2,如果遍历完新数组,发现说所有值都对应,说明缺失的是 新数组的长度对应的那个数,比如第二个示例中 ,新数组的长度为 5,此时缺失的为 5,返回长度即可,很容易理解。 +上图中,我们遍历一遍原数组,将正整数保存到新数组中,然后遍历新数组,第一次发现 newnum[i] != i 时,则说明该值是缺失的,返回即可,例如我上图中的第一个示例中的 2,如果遍历完新数组,发现说所有值都对应,说明缺失的是 新数组的长度对应的那个数,比如第二个示例中 ,新数组的长度为 5,此时缺失的为 5,返回长度即可,很容易理解。 注:我们发现我们新的数组长度比原数组大 1,是因为我们遍历新数组从 1,开始遍历。 @@ -53,15 +53,15 @@ class Solution { for (int x : nums) { if (x > 0 && x < res.length) { res[x] = x; - } + } } //遍历查找,发现不一样时直接返回 for (int i = 1; i < res.length; i++) { if (res[i] != i) { return i; - } + } } - //缺少最后一个,例如 1,2,3此时缺少 4 ,细节2 + //缺少最后一个,例如 1,2,3此时缺少 4 ,细节2 return res.length; } } @@ -85,10 +85,37 @@ class Solution: for i in range(1, len(res)): if res[i] != i: return i - # 缺少最后一个,例如 1,2,3此时缺少 4 ,细节2 + # 缺少最后一个,例如 1,2,3此时缺少 4 ,细节2 return len(res) ``` +Swift Code + +```swift +class Solution { + func firstMissingPositive(_ nums: [Int]) -> Int { + if nums.count == 0 { + return 1 + } + // 因为是返回第一个正整数,不包括 0,所以需要长度加1,细节1 + var res:[Int] = Array.init(repeating: 0, count: nums.count + 1) + // 将数组元素添加到辅助数组中 + for x in nums { + if x > 0 && x < res.count { + res[x] = x + } + } + // 遍历查找,发现不一样时直接返回 + for i in 1.. 0 && nums[i] < len + 1 && nums[i] != i+1 && nums[i] != nums[nums[i]-1]) { - swap(nums,i,nums[i] - 1); + swap(nums,i,nums[i] - 1); } } //遍历寻找缺失的正整数 @@ -166,3 +193,106 @@ class Solution: return n + 1 ``` +Swift Code + +```swift +class Solution { + func firstMissingPositive(_ nums: [Int]) -> Int { + var nums = nums + let len = nums.count + if len == 0 { + return 1 + } + // 遍历数组 + for i in 0.. 0 + && nums[i] < len + 1 + && nums[i] != i + 1 + && nums[i] != nums[nums[i] - 1] + { + //nums.swapAt(i, (nums[i] - 1)) // 系统方法 + self.swap(&nums, i, (nums[i] - 1)) // 自定义方法 + } + } + // 遍历寻找缺失的正整数 + for i in 0.. &nums) + { + int size = nums.size(); + //判断范围是否符合要求 + auto inRange = [](auto s, auto e) + { + return [s, e](auto &n) + { + return e >= n && n >= s; + }; + }; + auto cusInRange = inRange(1, size); + //增加数组长度, 便于计算, 不需要再转换 + nums.push_back(0); + + for (int i = 0; i < size; i++) + { + //将不在正确位置的元素放到正确位置上 + while (cusInRange(nums[i]) && nums[i] != i && nums[nums[i]] != nums[i]) + { + swap(nums[i], nums[nums[i]]); + } + } + + //找出缺失的元素 + for (int i = 1; i <= size; i++) + { + if (nums[i] != i) + return i; + } + return size + 1; + } +}; +``` + +Go Code: + +```go +func firstMissingPositive(nums []int) int { + length := len(nums) + if length == 0 { return 1 } + for i := 0; i < length; i++ { + // 将不在正确位置的元素放在正确的位置上。 + for nums[i] > 0 && nums[i] < length + 1 && nums[i] != i + 1 && nums[i] != nums[nums[i] - 1] { + j := nums[i] - 1 + nums[i], nums[j] = nums[j], nums[i] + } + } + // 第一个不在正确位置上的元素就是结果。 + for i := 0; i < length; i++ { + if nums[i] != i + 1 { + return i + 1 + } + } + return length + 1 +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode485\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode485\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.md" index dfdfa01..e82bb38 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode485\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode485\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.md" @@ -1,32 +1,28 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [485. 最大连续 1 的个数](https://leetcode-cn.com/problems/max-consecutive-ones/) -给定一个二进制数组, 计算其中最大连续1的个数。 +给定一个二进制数组, 计算其中最大连续 1 的个数。 示例 1: > 输入: [1,1,0,1,1,1] > 输出: 3 -> 解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3. +> 解释: 开头的两位和最后的三位都是连续 1,所以最大连续 1 的个数是 3. 我的这个方法比较奇怪,但是效率还可以,战胜了 100% , 尽量减少了 Math.max()的使用,我们来看一下具体思路,利用 right 指针进行探路,如果遇到 1 则继续走,遇到零时则停下,求当前 1 的个数。 -这时我们可以通过 right - left 得到 1 的 个数,因为此时我们的 right 指针指在 0 处,所以不需要和之前一样通过 right - left + 1 获得窗口长度。 +这时我们可以通过 right - left 得到 1 的 个数,因为此时我们的 right 指针指在 0 处,所以不需要和之前一样通过 right - left + 1 获得窗口长度。 然后我们再使用 while 循环,遍历完为 0 的情况,跳到下一段为 1 的情况,然后移动 left 指针。 left = right,站在同一起点,继续执行上诉过程。 下面我们通过一个视频模拟代码执行步骤大家一下就能搞懂了。 - ![leetcode485最长连续1的个数](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/leetcode485最长连续1的个数.7avzcthkit80.gif) - - - - +![leetcode485最长连续1的个数](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/leetcode485最长连续1的个数.7avzcthkit80.gif) 下面我们直接看代码吧 @@ -84,6 +80,32 @@ class Solution: return max(maxcount, right - left) ``` +Swift Code + +```swift +class Solution { + func findMaxConsecutiveOnes(_ nums: [Int]) -> Int { + + var left = 0, right = 0, res = 0 + let len = nums.count + while right < len { + if nums[right] == 1 { + right += 1 + continue + } + // 保存最大值 + res = max(res, right - left) + // 跳过 0 的情况 + while right < len && nums[right] == 0 { + right += 1 + } + // 同一起点继续遍历 + left = right + } + return max(res, right - left) + } +} +``` 刚才的效率虽然相对高一些,但是代码不够优美,欢迎各位改进,下面我们说一下另外一种情况,一个特别容易理解的方法。 @@ -99,7 +121,7 @@ class Solution { int count = 0; int maxcount = 0; - + for (int i = 0; i < nums.length; ++i) { if (nums[i] == 1) { count++; @@ -117,7 +139,6 @@ class Solution { Python3 Code: - ```py class Solution: def findMaxConsecutiveOnes(self, nums: List[int]) -> int: @@ -132,3 +153,81 @@ class Solution: return ans ``` +Swift Code + +```swift +class Solution { + func findMaxConsecutiveOnes(_ nums: [Int]) -> Int { + let len = nums.count + var maxCount = 0, count = 0 + for i in 0.. &nums) + { + int s = 0; + int e = 0; + int result = 0; + int size = nums.size(); + + while (s < size && e < size) + { + while (s < size && nums[s++] == 1) + { + e = s; + while (e < size && nums[e] == 1) + { + e++; + }; + //注意需要加1, 可以使用极限条件测试 + int r = e - s + 1; + if (r > result) + result = r; + s = e; + } + } + + return result; + } +}; +``` + +Go Code: + +```go +func findMaxConsecutiveOnes(nums []int) int { + cnt, maxCnt := 0, 0 + for i := 0; i < len(nums); i++ { + if nums[i] == 1 { + cnt++ + } else { + maxCnt = max(maxCnt, cnt) + cnt = 0 + } + } + return max(maxCnt, cnt) +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode54\350\236\272\346\227\213\347\237\251\351\230\265.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode54\350\236\272\346\227\213\347\237\251\351\230\265.md" index cb3c678..7bfdfe2 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode54\350\236\272\346\227\213\347\237\251\351\230\265.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode54\350\236\272\346\227\213\347\237\251\351\230\265.md" @@ -1,16 +1,14 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [54. 螺旋矩阵](https://leetcode-cn.com/problems/spiral-matrix/) 题目描述 -*给定一个包含 m* x n个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 - - +_给定一个包含 m_ x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 示例一 @@ -22,24 +20,14 @@ > 输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] > 输出:[1,2,3,4,8,12,11,10,9,5,6,7] - - 这个题目很细非常细,思路很容易想到,但是要是完全实现也不是特别容易,我们一起分析下这个题目,我们可以这样理解,我们像剥洋葱似的一步步的剥掉外皮,直到遍历结束,见下图。 - - -![](https://img-blog.csdnimg.cn/img_convert/cfa0192601dcc185e77125adc35e1cc5.png)* - - +![](https://img-blog.csdnimg.cn/img_convert/cfa0192601dcc185e77125adc35e1cc5.png)\* 题目很容易理解,但是要想完全执行出来,也是不容易的,因为这里面的细节太多了,我们需要认真仔细的考虑边界。 - - 我们也要考虑重复遍历的情况即什么时候跳出循环。刚才我们通过箭头知道了我们元素的遍历顺序,这个题目也就完成了一大半了,下面我们来讨论一下什么时候跳出循环,见下图。 - - 注:这里需要注意的是,框框代表的是每个边界。 ![](https://img-blog.csdnimg.cn/20210318095839543.gif) @@ -55,7 +43,7 @@ class Solution { List arr = new ArrayList<>(); int left = 0, right = matrix[0].length-1; int top = 0, down = matrix.length-1; - + while (true) { for (int i = left; i <= right; ++i) { arr.add(matrix[top][i]); @@ -77,7 +65,7 @@ class Solution { } left++; if (left > right) break; - + } return arr; } @@ -85,6 +73,42 @@ class Solution { ``` +C++ Code: + +```cpp +class Solution { +public: + vector spiralOrder(vector>& matrix) { + vector arr; + int left = 0, right = matrix[0].size()-1; + int top = 0, down = matrix.size()-1; + while (true) { + for (int i = left; i <= right; ++i) { + arr.emplace_back(matrix[top][i]); + } + top++; + if (top > down) break; + for (int i = top; i <= down; ++i) { + arr.emplace_back(matrix[i][right]); + } + right--; + if (left > right) break; + for (int i = right; i >= left; --i) { + arr.emplace_back(matrix[down][i]); + } + down--; + if (top > down) break; + for (int i = down; i >= top; --i) { + arr.emplace_back(matrix[i][left]); + } + left++; + if (left > right) break; + } + return arr; + } +}; +``` + Python3 Code: ```python @@ -120,5 +144,76 @@ class Solution: return arr ``` +Swift Code +```swift +class Solution { + func spiralOrder(_ matrix: [[Int]]) -> [Int] { + var arr:[Int] = [] + var left = 0, right = matrix[0].count - 1 + var top = 0, down = matrix.count - 1 + while (true) { + for i in left...right { + arr.append(matrix[top][i]) + } + top += 1 + if top > down { break } + for i in top...down { + arr.append(matrix[i][right]) + } + right -= 1 + if left > right { break} + for i in stride(from: right, through: left, by: -1) { + arr.append(matrix[down][i]) + } + down -= 1 + if top > down { break} + for i in stride(from: down, through: top, by: -1) { + arr.append(matrix[i][left]) + } + left += 1 + if left > right { break} + } + + return arr + } +} +``` + +Go Code: + +```go +func spiralOrder(matrix [][]int) []int { + res := []int{} + left, right := 0, len(matrix[0]) - 1 + top, down := 0, len(matrix) - 1 + + for { + for i := left; i <= right; i++ { + res = append(res, matrix[top][i]) + } + top++ + if top > down { break } + + for i := top; i <= down; i++ { + res = append(res, matrix[i][right]) + } + right-- + if left > right { break } + + for i := right; i >= left; i-- { + res = append(res, matrix[down][i]) + } + down-- + if top > down { break } + + for i := down; i >= top; i-- { + res = append(res, matrix[i][left]) + } + left++ + if left > right { break } + } + return res +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode560\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode560\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204.md" index 8e81e3e..7f1f38b 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode560\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode560\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204.md" @@ -1,10 +1,10 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -### [leetcode560. 和为K的子数组](https://leetcode-cn.com/problems/subarray-sum-equals-k/) +### [leetcode560. 和为 K 的子数组](https://leetcode-cn.com/problems/subarray-sum-equals-k/) **题目描述** @@ -43,7 +43,9 @@ class Solution { } ``` -Python3版本的代码会超时 +Python3 版本的代码会超时 + +Swift 版本的代码会超时 下面我们我们使用前缀和的方法来解决这个题目,那么我们先来了解一下前缀和是什么东西。其实这个思想我们很早就接触过了。见下图 @@ -55,7 +57,7 @@ presum [2] = presum[1] + nums[1],presum[3] = presum[2] + nums[2] ... 所以我 例如我们需要获取 nums[2] 到 nums[4] 这个区间的和,我们则完全根据 presum 数组得到,是不是有点和我们之前说的字符串匹配算法中 BM,KMP 中的 next 数组和 suffix 数组作用类似。 -那么我们怎么根据presum 数组获取 nums[2] 到 nums[4] 区间的和呢?见下图 +那么我们怎么根据 presum 数组获取 nums[2] 到 nums[4] 区间的和呢?见下图 ![前缀和](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/前缀和.77twdj3gpkg0.png) @@ -92,7 +94,7 @@ class Solution { } ``` -Python3版本的代码也会超时 +Python3 版本的代码也会超时 我们通过上面的例子我们简单了解了前缀和思想,那么我们如果继续将其优化呢? @@ -112,7 +114,7 @@ class Solution { //一次遍历 for (int i = 0; i < nums.length; ++i) { //存在时,我们用数组得值为 key,索引为 value - if (map.containsKey(target - nums[i])){ + if (map.containsKey(target - nums[i])){ return new int[]{i,map.get(target-nums[i])}; } //存入值 @@ -160,3 +162,77 @@ class Solution { } ``` +Swift Code + +```swift +class Solution { + func subarraySum(_ nums: [Int], _ k: Int) -> Int { + if nums.count == 0 { + return 0 + } + var map: [Int: Int] = [:] + map[0] = 1 // 需要添加入一个元素垫底,已支持前几位就满足的情况 + var presum = 0, count = 0 + + for x in nums { + presum += x + //当前前缀和已知,判断是否含有 presum - k的前缀和,那么我们就知道某一区间的和为 k 了。 + if let v = map[presum - k] { + count += v //获取presum-k前缀和出现次数 + } + map[presum] = (map[presum] ?? 0) + 1 + } + return count + } +} +``` + +C++ Code + +```C++ +class Solution +{ +public: + int subarraySum(vector &nums, int k) + { + unordered_map smp; + int sum = 0; + //初始化"最外面"的0 + smp[0] = 1; + int result = 0; + for(int i = 0; i < nums.size(); i++) + { + sum += nums[i]; + auto mp = smp.find(sum - k); + if (mp != smp.end()) + { + //map里面存的一定是在前面的元素 + //可以尝试将map的value换为数组 + result += mp->second; + } + smp[sum]++; + } + + return result; + } +}; +``` + +Go Code: + +```go +func subarraySum(nums []int, k int) int { + m := map[int]int{} + m[0] = 1 + sum := 0 + cnt := 0 + for _, num := range nums { + sum += num + if v, ok := m[sum - k]; ok { + cnt += v + } + m[sum]++ + } + return cnt +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode59\350\236\272\346\227\213\347\237\251\351\230\2652.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode59\350\236\272\346\227\213\347\237\251\351\230\2652.md" index 50cf94c..4d72797 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode59\350\236\272\346\227\213\347\237\251\351\230\2652.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode59\350\236\272\346\227\213\347\237\251\351\230\2652.md" @@ -1,10 +1,8 @@ - - -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### [59.螺旋矩阵 II](https://leetcode-cn.com/problems/spiral-matrix-ii) @@ -22,15 +20,11 @@ 其实我们只要做过了螺旋矩阵 第一题,这个题目我们完全可以一下搞定,几乎没有进行更改,我们先来看下 **leetcode 54** 题的解析。 - - ### leetcode 54 螺旋矩阵 题目描述 -*给定一个包含 m* x n个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 - - +_给定一个包含 m_ x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 示例一 @@ -42,24 +36,14 @@ > 输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] > 输出:[1,2,3,4,8,12,11,10,9,5,6,7] - - 这个题目很细非常细,思路很容易想到,但是要是完全实现也不是特别容易,我们一起分析下这个题目,我们可以这样理解,我们像剥洋葱似的一步步的剥掉外皮,直到遍历结束,见下图。 - - -*![螺旋矩阵](https://pic.leetcode-cn.com/1615813563-uUiWlF-file_1615813563382)* - - +_![螺旋矩阵](https://pic.leetcode-cn.com/1615813563-uUiWlF-file_1615813563382)_ 题目很容易理解,但是要想完全执行出来,也是不容易的,因为这里面的细节太多了,我们需要认真仔细的考虑边界。 - - 我们也要考虑重复遍历的情况即什么时候跳出循环。刚才我们通过箭头知道了我们元素的遍历顺序,这个题目也就完成了一大半了,下面我们来讨论一下什么时候跳出循环,见下图。 - - 注:这里需要注意的是,框框代表的是每个边界。 ![](https://img-blog.csdnimg.cn/20210318095839543.gif) @@ -75,7 +59,7 @@ class Solution { List arr = new ArrayList<>(); int left = 0, right = matrix[0].length-1; int top = 0, down = matrix.length-1; - + while (true) { for (int i = left; i <= right; ++i) { arr.add(matrix[top][i]); @@ -97,7 +81,7 @@ class Solution { } left++; if (left > right) break; - + } return arr; } @@ -140,6 +124,79 @@ class Solution: return arr ``` +C++ Code: + +```cpp +class Solution { +public: + vector spiralOrder(vector>& matrix) { + vector arr; + int left = 0, right = matrix[0].size()-1; + int top = 0, down = matrix.size()-1; + while (true) { + for (int i = left; i <= right; ++i) { + arr.emplace_back(matrix[top][i]); + } + top++; + if (top > down) break; + for (int i = top; i <= down; ++i) { + arr.emplace_back(matrix[i][right]); + } + right--; + if (left > right) break; + for (int i = right; i >= left; --i) { + arr.emplace_back(matrix[down][i]); + } + down--; + if (top > down) break; + for (int i = down; i >= top; --i) { + arr.emplace_back(matrix[i][left]); + } + left++; + if (left > right) break; + } + return arr; + } +}; +``` + +Swift Code: + +```swift +class Solution { + func spiralOrder(_ matrix: [[Int]]) -> [Int] { + var arr:[Int] = [] + var left = 0, right = matrix[0].count - 1 + var top = 0, down = matrix.count - 1 + + while (true) { + for i in left...right { + arr.append(matrix[top][i]) + } + top += 1 + if top > down { break } + for i in top...down { + arr.append(matrix[i][right]) + } + right -= 1 + if left > right { break} + for i in stride(from: right, through: left, by: -1) { + arr.append(matrix[down][i]) + } + down -= 1 + if top > down { break} + for i in stride(from: down, through: top, by: -1) { + arr.append(matrix[i][left]) + } + left += 1 + if left > right { break} + } + + return arr + } +} +``` + 我们仅仅是将 54 反过来了,往螺旋矩阵里面插值,下面我们直接看代码吧,大家可以也可以对其改进,大家可以思考一下,如果修改能够让代码更简洁! Java Code: @@ -147,7 +204,7 @@ Java Code: ```java class Solution { public int[][] generateMatrix(int n) { - + int[][] arr = new int[n][n]; int left = 0; int right = n-1; @@ -157,13 +214,13 @@ class Solution { int numsize = n*n; while (true) { for (int i = left; i <= right; ++i) { - arr[top][i] = num++; + arr[top][i] = num++; } top++; if (num > numsize) break; for (int i = top; i <= buttom; ++i) { arr[i][right] = num++; - + } right--; if (num > numsize) break; @@ -177,7 +234,7 @@ class Solution { } left++; if (num > numsize) break; - + } return arr; } @@ -226,3 +283,124 @@ class Solution: return arr.tolist() ``` +C++ Code: + +```cpp +class Solution { +public: + vector> generateMatrix(int n) { + vector > arr(n, vector (n)); + int left = 0, right = n-1, top = 0, buttom = n - 1, num = 1, numsize = n * n; + while (true) { + for (int i = left; i <= right; ++i) { + arr[top][i] = num++; + } + top++; + if (num > numsize) break; + for (int i = top; i <= buttom; ++i) { + arr[i][right] = num++; + } + right--; + if (num > numsize) break; + for (int i = right; i >= left; --i) { + arr[buttom][i] = num++; + } + buttom--; + if (num > numsize) break; + for (int i = buttom; i >= top; --i) { + arr[i][left] = num++; + } + left++; + if (num > numsize) break; + + } + return arr; + } +}; +``` + +Swift Code: + +```swift +class Solution { + func generateMatrix(_ n: Int) -> [[Int]] { + var arr:[[Int]] = Array.init(repeating: Array.init(repeating: 0, count: n), count: n) + var left = 0, right = n - 1 + var top = 0, bottom = n - 1 + var num = 1, numSize = n * n + + while true { + for i in left...right { + arr[top][i] = num + num += 1 + } + top += 1 + if num > numSize { break} + for i in top...bottom { + arr[i][right] = num + num += 1 + } + right -= 1 + if num > numSize { break} + for i in stride(from: right, through: left, by: -1) { + arr[bottom][i] = num + num += 1 + } + bottom -= 1 + if num > numSize { break} + for i in stride(from: bottom, through: top, by: -1) { + arr[i][left] = num + num += 1 + } + left += 1 + if num > numSize { break} + } + + return arr + } +} +``` + +Go Code: + +```go +func generateMatrix(n int) [][]int { + res := make([][]int, n) + for i := 0; i < n; i++ { + res[i] = make([]int, n) + } + left, right := 0, n - 1 + top, buttom := 0, n - 1 + size, num := n * n, 1 + for { + for i := left; i <= right; i++ { + res[top][i] = num + num++ + } + top++ + if num > size { break } + + for i := top; i <= buttom; i++ { + res[i][right] = num + num++ + } + right-- + if num > size { break } + + for i := right; i >= left; i-- { + res[buttom][i] = num + num++ + } + buttom-- + if num > size { break } + + for i := buttom; i >= top; i-- { + res[i][left] = num + num++ + } + left++ + if num > size { break } + } + return res +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode66\345\212\240\344\270\200.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode66\345\212\240\344\270\200.md" index 3030fee..ed3c5e7 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode66\345\212\240\344\270\200.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode66\345\212\240\344\270\200.md" @@ -1,9 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -> +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [66. 加一](https://leetcode-cn.com/problems/plus-one/) @@ -42,7 +41,7 @@ 则我们根据什么来判断属于第几种情况呢? -我们可以根据当前位 余10来判断,这样我们就可以区分属于第几种情况了,大家直接看代码吧,很容易理解的。 +我们可以根据当前位 余 10 来判断,这样我们就可以区分属于第几种情况了,大家直接看代码吧,很容易理解的。 Java Code: @@ -57,10 +56,10 @@ class Solution { if (digits[i] != 0) { return digits; } - + } //第三种情况,因为数组初始化每一位都为0,我们只需将首位设为1即可 - int[] arr = new int[len+1]; + int[] arr = new int[len+1]; arr[0] = 1; return arr; } @@ -85,3 +84,57 @@ class Solution: arr[0] = 1 return arr ``` + +C++ Code: + +```cpp +class Solution { +public: + vector plusOne(vector& digits) { + for(int i = digits.size() - 1; i >= 0; --i){ + digits[i] = (digits[i] + 1)%10; + if(digits[i]) return digits; + } + for(int & x: digits) x = 0; + digits.emplace_back(1); + reverse(digits.begin(), digits.end()); + return digits; + } +}; +``` + +Swift Code: + +```swift +class Solution { + func plusOne(_ digits: [Int]) -> [Int] { + let count = digits.count + var digits = digits + for i in stride(from: count - 1, through: 0, by: -1) { + digits[i] = (digits[i] + 1) % 10 + if digits[i] != 0 { + return digits + } + } + var arr: [Int] = Array.init(repeating: 0, count: count + 1) + arr[0] = 1 + return arr + } +} +``` + +Go Code: + +```go +func plusOne(digits []int) []int { + l := len(digits) + for i := l - 1; i >= 0; i-- { + digits[i] = (digits[i] + 1) % 10 + if digits[i] != 0 { + return digits + } + } + digits = append([]int{1}, digits...) + return digits +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode75\351\242\234\350\211\262\345\210\206\347\261\273.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode75\351\242\234\350\211\262\345\210\206\347\261\273.md" index 7f125f1..e69e4bd 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode75\351\242\234\350\211\262\345\210\206\347\261\273.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/leetcode75\351\242\234\350\211\262\345\210\206\347\261\273.md" @@ -1,10 +1,10 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -### [75 颜色分类](https://leetcode-cn.com/problems/sort-colors/) +### [75 颜色分类](https://leetcode-cn.com/problems/sort-colors/) 题目描述: @@ -34,7 +34,7 @@ **做题思路** -这个题目我们使用 Arrays.sort() 解决,哈哈,但是那样太无聊啦,题目含义就是让我们将所有的 0 放在前面,2放在后面,1 放在中间,是不是和我们上面说的荷兰国旗问题一样。我们仅仅将 1 做为 pivot 值。 +这个题目我们使用 Arrays.sort() 解决,哈哈,但是那样太无聊啦,题目含义就是让我们将所有的 0 放在前面,2 放在后面,1 放在中间,是不是和我们上面说的荷兰国旗问题一样。我们仅仅将 1 做为 pivot 值。 下面我们直接看代码吧,和三向切分基本一致。 @@ -48,7 +48,7 @@ class Solution { //这里和三向切分不完全一致 int i = left; int right = len-1; - + while (i <= right) { if (nums[i] == 2) { swap(nums,i,right--); @@ -57,7 +57,7 @@ class Solution { } else { i++; } - } + } } public void swap (int[] nums, int i, int j) { int temp = nums[i]; @@ -72,7 +72,7 @@ Python3 Code: ```python from typing import List class Solution: - def sortColors(self, nums: List[int]): + def sortColors(self, nums: List[int]): leng = len(nums) left = 0 # 这里和三向切分不完全一致 @@ -89,18 +89,95 @@ class Solution: else: i += 1 return nums - + def swap(self, nums: List[int], i: int, j: int): temp = nums[i] nums[i] = nums[j] nums[j] = temp ``` +C++ Code: + +```cpp +class Solution { +public: + void sortColors(vector& nums) { + int len = nums.size(), left = 0; + int i = left, right = len-1; + while (i <= right) { + if (nums[i] == 2) { + swap(nums[i],nums[right--]); + } else if (nums[i] == 0) { + swap(nums[i++],nums[left++]); + } else { + i++; + } + } + } +}; +``` + +Swift Code: + +```swift +class Solution { + func sortColors(_ nums: inout [Int]) { + + let count = nums.count + var left = 0, i = left, right = count - 1 + while i <= right { + if nums[i] == 2 { + //nums.swapAt(i, right) 直接调用系统方法 + self.swap(&nums, i, right) // 保持风格统一走自定义交换 + right -= 1 + } else if nums[i] == 0 { + //nums.swapAt(i, left) 直接调用系统方法 + self.swap(&nums, i, left) // 保持风格统一走自定义交换 + i += 1 + left += 1 + } else { + i += 1 + } + } + } + + func swap(_ nums: inout [Int], _ i: Int, _ j: Int) { + let temp = nums[i] + nums[i] = nums[j] + nums[j] = temp + } +} +``` + +Go Code: + +```go +func sortColors(nums []int) { + length := len(nums) + left, right := 0, length - 1 + i := left + for i <= right { + if nums[i] == 2 { + // 把2换到最后 + nums[i], nums[right] = nums[right], nums[i] + right-- + } else if nums[i] == 0 { + // 把0换到最前面 + nums[i], nums[left] = nums[left], nums[i] + i++ + left++ + } else { + i++ + } + } +} +``` + 另外我们看这段代码,有什么问题呢?那就是我们即使完全符合时,仍会交换元素,这样会大大降低我们的效率。 例如:[0,0,0,1,1,1,2,2,2] -此时我们完全符合情况,不需要交换元素,但是按照我们上面的代码,0,2 的每个元素会和自己进行交换,所以这里我们可以根据 i 和 left 的值是否相等来决定是否需要交换,大家可以自己写一下。 +此时我们完全符合情况,不需要交换元素,但是按照我们上面的代码,0,2 的每个元素会和自己进行交换,所以这里我们可以根据 i 和 left 的值是否相等来决定是否需要交换,大家可以自己写一下。 下面我们看一下另外一种写法 @@ -124,7 +201,7 @@ class Solution { int len = nums.length; int right = len - 1; for (int i = 0; i <= right; ++i) { - if (nums[i] == 0) { + if (nums[i] == 0) { swap(nums,i,left); left++; } @@ -137,7 +214,7 @@ class Solution { } } } - + } public void swap (int[] nums,int i, int j) { int temp = nums[i]; @@ -167,11 +244,93 @@ class Solution: # 如果不等于 1 则需要继续判断,所以不移动 i 指针,i-- if nums[i] != 1: i -= 1 - i += 1 + i += 1 return nums def swap(self, nums: List[int], i: int, j: int): temp = nums[i] nums[i] = nums[j] nums[j] = temp -``` \ No newline at end of file +``` + +C++ Code: + +```cpp +class Solution { +public: + void sortColors(vector& nums) { + int left = 0, len = nums.size(); + int right = len - 1; + for (int i = 0; i <= right; ++i) { + if (nums[i] == 0) { + swap(nums[i],nums[left++]); + } + if (nums[i] == 2) { + swap(nums[i],nums[right--]); + if (nums[i] != 1) { + i--; + } + } + } + } +}; +``` + +Swift Code: + +```swift +class Solution { + func sortColors(_ nums: inout [Int]) { + + let count = nums.count + var left = 0, i = left, right = count - 1 + while i <= right { + if nums[i] == 0 { + //nums.swapAt(i, left) 直接调用系统方法 + self.swap(&nums, i, left) // 保持风格统一走自定义交换 + left += 1 + } + if nums[i] == 2 { + //nums.swapAt(i, right) 直接调用系统方法 + self.swap(&nums, i, right) // 保持风格统一走自定义交换 + right -= 1 + //如果不等于 1 则需要继续判断,所以不移动 i 指针,i-- + if nums[i] != 1 { + i -= 1 + } + } + i += 1 + } + } + + func swap(_ nums: inout [Int], _ i: Int, _ j: Int) { + let temp = nums[i] + nums[i] = nums[j] + nums[j] = temp + } +} +``` + +Go Code: + +```go +func sortColors(nums []int) { + length := len(nums) + left, right := 0, length - 1 + for i := 0; i <= right; i++ { + if nums[i] == 0 { + // 为0时,和头交换 + nums[i], nums[left] = nums[left], nums[i] + left++ + } else if nums[i] == 2 { + // 为2时,和尾交换 + nums[i], nums[right] = nums[right], nums[i] + right-- + // 不为1时,需要把i减回去 + if nums[i] != 1 { + i-- + } + } + } +} +``` diff --git "a/animation-simulation/\346\225\260\347\273\204\347\257\207/\345\211\221\346\214\207offer3\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260.md" "b/animation-simulation/\346\225\260\347\273\204\347\257\207/\345\211\221\346\214\207offer3\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260.md" index 9d09871..036fc69 100644 --- "a/animation-simulation/\346\225\260\347\273\204\347\257\207/\345\211\221\346\214\207offer3\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260.md" +++ "b/animation-simulation/\346\225\260\347\273\204\347\257\207/\345\211\221\346\214\207offer3\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [剑指 Offer 03. 数组中重复的数字](https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/) @@ -10,14 +10,13 @@ 找出数组中重复的数字。 - -在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。 +在一个长度为 n 的数组 nums 里的所有数字都在 0 ~ n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。 示例 1: 输入: [2, 3, 1, 0, 2, 5, 3] -输出:2 或 3 +输出:2 或 3 #### **HashSet** @@ -61,6 +60,24 @@ class Solution: return -1 ``` +Swift Code: + +```swift +class Solution { + func findRepeatNumber(_ nums: [Int]) -> Int { + var set: Set = [] + for n in nums { + if set.contains(n) { // 如果发现某元素存在,则返回 + return n + } + set.insert(n) // 存入集合 + } + + return -1 + } +} +``` + #### **原地置换** **解析** @@ -69,8 +86,6 @@ class Solution: ![剑指offer3数组中重复的数](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/剑指offer3数组中重复的数.2p6cd5os0em0.gif) - - **题目代码** Java Code: @@ -136,3 +151,47 @@ class Solution: nums[temp] = temp return -1 ``` + +Swift Code: + +```swift +class Solution { + func findRepeatNumber(_ nums: [Int]) -> Int { + if nums.isEmpty { + return -1 + } + var nums = nums; + for i in 0.. 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [209. 长度最小的子数组](https://leetcode-cn.com/problems/minimum-size-subarray-sum/) @@ -14,12 +14,10 @@ 示例: -> 输入:s = 7, nums = [2,3,1,2,4,3] +> 输入:s = 7, nums = [2,3,1,2,4,3] > 输出:2 > 解释:子数组 [4,3] 是该条件下的长度最小的子数组。 - - #### 题目解析 滑动窗口:**就是通过不断调节子数组的起始位置和终止位置,进而得到我们想要的结果**,滑动窗口也是双指针的一种。 @@ -28,14 +26,10 @@ ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321131617533.png) - - 好啦,该题的解题思路我们已经了解啦,下面我们看一下,代码的运行过程吧。 ![](https://img-blog.csdnimg.cn/2021032111513777.gif) - - #### 题目代码 Java Code: @@ -55,7 +49,7 @@ class Solution { sum -= nums[i]; i++; } - } + } return windowlen == Integer.MAX_VALUE ? 0 : windowlen; } @@ -84,7 +78,7 @@ public: Python3 Code: -```python +```python from typing import List import sys class Solution: @@ -99,10 +93,59 @@ class Solution: windowlen = min(windowlen, j - i + 1) sum -= nums[i] i += 1 - + if windowlen == sys.maxsize: return 0 else: return windowlen ``` +Swift Code + +```swift +class Solution { + func minSubArrayLen(_ target: Int, _ nums: [Int]) -> Int { + + var sum = 0, windowlen = Int.max, i = 0 + for j in 0..= target { + windowlen = min(windowlen, j - i + 1) + sum -= nums[i] + i += 1 + } + } + return windowlen == Int.max ? 0 : windowlen + } +} +``` + +Go Code: + +```go +func minSubArrayLen(target int, nums []int) int { + length := len(nums) + winLen := length + 1 + i := 0 + sum := 0 + for j := 0; j < length; j++ { + sum += nums[j] + for sum >= target { + winLen = min(winLen, j - i + 1) + sum -= nums[i] + i++ + } + } + if winLen == length + 1 { + return 0 + } + return winLen +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} +``` diff --git "a/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/225.\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.md" "b/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/225.\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.md" index db69b8b..5a8b904 100644 --- "a/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/225.\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.md" +++ "b/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/225.\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [225. 用队列实现栈](https://leetcode-cn.com/problems/implement-stack-using-queues/) @@ -10,7 +10,7 @@ 其实原理也很简单,我们利用队列先进先出的特点,每次队列模拟入栈时,我们先将队列之前入队的元素都出列,仅保留最后一个进队的元素。 -然后再重新入队,这样就实现了颠倒队列中的元素。比如我们首先入队1,然后再入队2,我们需要将元素1出队,然后再重新入队,则实现了队列内元素序列变成了2,1。 +然后再重新入队,这样就实现了颠倒队列中的元素。比如我们首先入队 1,然后再入队 2,我们需要将元素 1 出队,然后再重新入队,则实现了队列内元素序列变成了 2,1。 废话不多说,我们继续看动图 @@ -21,14 +21,15 @@ #### 题目代码 Java Code: + ```java class MyStack { //初始化队列 Queue queue; public MyStack() { - queue = new LinkedList<>(); + queue = new LinkedList<>(); } - + //模拟入栈操作 public void push(int x) { queue.offer(x); @@ -37,18 +38,18 @@ class MyStack { queue.offer(queue.poll()); } - } + } //模拟出栈 public int pop() { return queue.poll(); } - + //返回栈顶元素 public int top() { return queue.peek(); - } + } //判断是否为空 public boolean empty() { return queue.isEmpty(); @@ -59,33 +60,33 @@ class MyStack { ``` JS Code: + ```javascript -var MyStack = function() { - this.queue = []; +var MyStack = function () { + this.queue = []; }; -MyStack.prototype.push = function(x) { - this.queue.push(x); - if (this.queue.length > 1) { - let i = this.queue.length - 1; - while (i) { - this.queue.push(this.queue.shift()); - i--; - } +MyStack.prototype.push = function (x) { + this.queue.push(x); + if (this.queue.length > 1) { + let i = this.queue.length - 1; + while (i) { + this.queue.push(this.queue.shift()); + i--; } + } }; -MyStack.prototype.pop = function() { - return this.queue.shift(); +MyStack.prototype.pop = function () { + return this.queue.shift(); }; -MyStack.prototype.top = function() { - return this.empty() ? null : this.queue[0]; - +MyStack.prototype.top = function () { + return this.empty() ? null : this.queue[0]; }; -MyStack.prototype.empty = function() { - return !this.queue.length; +MyStack.prototype.empty = function () { + return !this.queue.length; }; ``` @@ -94,7 +95,7 @@ C++ Code: ```cpp class MyStack { queue q; -public: +public: void push(int x) { q.push(x); for(int i = 1;i < q.size();i++){ @@ -111,10 +112,9 @@ public: } int top() { return q.front(); - } + } bool empty() { return q.empty(); } }; ``` - diff --git "a/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/leetcode1047 \345\210\240\351\231\244\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\346\211\200\346\234\211\347\233\270\351\202\273\351\207\215\345\244\215\351\241\271.md" "b/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/leetcode1047 \345\210\240\351\231\244\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\346\211\200\346\234\211\347\233\270\351\202\273\351\207\215\345\244\215\351\241\271.md" index c5184fa..3b31056 100644 --- "a/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/leetcode1047 \345\210\240\351\231\244\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\346\211\200\346\234\211\347\233\270\351\202\273\351\207\215\345\244\215\351\241\271.md" +++ "b/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/leetcode1047 \345\210\240\351\231\244\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\346\211\200\346\234\211\347\233\270\351\202\273\351\207\215\345\244\215\351\241\271.md" @@ -1,38 +1,32 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [1047. 删除字符串中的所有相邻重复项](https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/) 今天给大家带来一个栈的经典题目,删除字符串中的相邻重复项,下面我们先来看一下题目描述。 -给出由小写字母组成的字符串S,重复项操作会选择**两个相邻且相同**的字母,并删除他们。 +给出由小写字母组成的字符串 S,重复项操作会选择**两个相邻且相同**的字母,并删除他们。 -在S上反复执行重复项删除操作,直到无法继续删除。在完成所有重复项删除操作后返回最终字符串。答案保证唯一 +在 S 上反复执行重复项删除操作,直到无法继续删除。在完成所有重复项删除操作后返回最终字符串。答案保证唯一 -示例1: +示例 1: > 输入:“abbaca” > 输出:”ca“ -​ 我们在之前的文章中介绍过删除重复项的思想,当时我们介绍的重复项可能是两个或更多,今天的题目更加简单是两字母相邻且相同。这个题目我们可以使用双指针思想解决,用来判断两个字符是否相同,但是我们这个板块的主题是栈和队列,那么我们就详细介绍一下如何用栈解答这个题目。 +​ 我们在之前的文章中介绍过删除重复项的思想,当时我们介绍的重复项可能是两个或更多,今天的题目更加简单是两字母相邻且相同。这个题目我们可以使用双指针思想解决,用来判断两个字符是否相同,但是我们这个板块的主题是栈和队列,那么我们就详细介绍一下如何用栈解答这个题目。 ## 解题思路: 我们将字符入栈,然后新的字符入栈之前先于栈顶元素对比,判断是否和栈顶元素一致,如果一致则栈顶元素出栈,指针移到下一位,则就实现了去除重复元素。如果和栈顶元素不同或栈为空则将当前元素入栈。直至字符串遍历结束,另外我们需要注意的是栈是先进后出,最后我们元素出栈的时候,我们需要对字符串反转一下才为我们的答案。 - - ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210320141506967.gif) - - **题目代码** - - Java Code: ```java @@ -47,7 +41,7 @@ class Solution { //遍历数组 for (int i= 0; i 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [20. 有效的括号](https://leetcode-cn.com/problems/valid-parentheses/) @@ -35,15 +35,13 @@ > 输入: "()]" > 输出: false -示例4: +示例 4: > 输入:"()[" > > 输出:false - - -我这里用了两种方法进行解决,第一种是利用ArrayList,第二种是利用栈,今天主要讲 一下用栈的方法。思路很简单,我们遇到左括号就将其入栈,遇到右括号就和栈顶元素进行比较,如果是对应的则pop栈顶元素,不对应直接返回false即可。另外我们还需要考虑的就是示例3和示例4这两种情况,需要我们好好思考一下。 +我这里用了两种方法进行解决,第一种是利用 ArrayList,第二种是利用栈,今天主要讲 一下用栈的方法。思路很简单,我们遇到左括号就将其入栈,遇到右括号就和栈顶元素进行比较,如果是对应的则 pop 栈顶元素,不对应直接返回 false 即可。另外我们还需要考虑的就是示例 3 和示例 4 这两种情况,需要我们好好思考一下。 下面我们直接上动图。 @@ -87,14 +85,10 @@ class Solution { } ``` - - -另外我们看下另一种方法,这个方法很有趣,,我们遇到 ‘ [ ’ 时,则入栈 ' ] ' ,这样当我们遇到 ‘]’ 时只需判断栈顶元素是否和其一致即可,一致则出,继续遍历下一个,否则返回 false 。 +另外我们看下另一种方法,这个方法很有趣,,我们遇到 ‘ [ ’ 时,则入栈 ' ] ' ,这样当我们遇到 ‘]’ 时只需判断栈顶元素是否和其一致即可,一致则出,继续遍历下一个,否则返回 false 。 这个方法有些巧妙,大家第一次看时可能不是那么容易理解,所以大家可以自己打一下,动脑子想一下代码逻辑。 - - ```java class Solution { public boolean isValid(String s) { @@ -112,4 +106,3 @@ class Solution { } } ``` - diff --git "a/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/leetcode402\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.md" "b/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/leetcode402\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.md" index 0b85c14..bc36721 100644 --- "a/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/leetcode402\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.md" +++ "b/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/leetcode402\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.md" @@ -1,12 +1,12 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -#### [402. 移掉K位数字](https://leetcode-cn.com/problems/remove-k-digits/) +#### [402. 移掉 K 位数字](https://leetcode-cn.com/problems/remove-k-digits/) -今天给大家带来一个栈的中等题目,移掉K位数字,题目很简单,但是很有趣。另外明天继续给大家带来一道栈和队列题目(困难),那么咱们的栈和队列模块就结束啦,下周开始整字符串的题目啦! +今天给大家带来一个栈的中等题目,移掉 K 位数字,题目很简单,但是很有趣。另外明天继续给大家带来一道栈和队列题目(困难),那么咱们的栈和队列模块就结束啦,下周开始整字符串的题目啦! ### 题目描述 @@ -33,25 +33,25 @@ > 输入: num = "10", k = 2 > 输出: "0" -> 解释: 从原数字移除所有的数字,剩余为空就是0 +> 解释: 从原数字移除所有的数字,剩余为空就是 0 题目很容易理解,而且也很容易实现,因为在示例中几乎把所有特殊情况都进行了举例,我们直接代码实现就好啦。 ### 栈(贪心) -下面我们来看一下用栈的解题思路,因为我们需要删除掉K位数字得到最小值,那么我们需要注意的是,删除的数字应该尽量在高位,则当前位小于前一位时,对前一位出栈,当前位入栈。大家思考一下思路是不是这样呢? +下面我们来看一下用栈的解题思路,因为我们需要删除掉 K 位数字得到最小值,那么我们需要注意的是,删除的数字应该尽量在高位,则当前位小于前一位时,对前一位出栈,当前位入栈。大家思考一下思路是不是这样呢? -另外我们需要注意的是,仅删除K位数字,得到最小值,比如54321,我们删除3位,得到21。但是刚才我们说当前位小于前一位时,则前一位出栈,当前位入栈,所以我们需要加上删除K位的规则。 +另外我们需要注意的是,仅删除 K 位数字,得到最小值,比如 54321,我们删除 3 位,得到 21。但是刚才我们说当前位小于前一位时,则前一位出栈,当前位入栈,所以我们需要加上删除 K 位的规则。 废话不多说我们直接上动图,把该题吃透! ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210320141440557.gif) -PPT中的文字 +PPT 中的文字 -> 这里需要注意的是,我们不需要将0入栈,因为0如果处于栈底,没有比它更小的值所以它不会被移除,我们只有在最后才有机会处理它。因为我们的010 = 10 ,首位0是需要在最后去掉的。所以我们这里可以直接不让其入栈,continue掉这次循环,也不改变K值,这样我们最后出栈处理时就不用考虑啦。这样逻辑就比官方题解好理解一些,也简洁一些。 +> 这里需要注意的是,我们不需要将 0 入栈,因为 0 如果处于栈底,没有比它更小的值所以它不会被移除,我们只有在最后才有机会处理它。因为我们的 010 = 10 ,首位 0 是需要在最后去掉的。所以我们这里可以直接不让其入栈,continue 掉这次循环,也不改变 K 值,这样我们最后出栈处理时就不用考虑啦。这样逻辑就比官方题解好理解一些,也简洁一些。 -> 这里需要注意的是,我们的K值还为2,我们目前仅删除2位数字,但是我们需要删除4位,但是后面的几位都是当前位大于前一位。所以我们需要在遍历结束后再移除后面最大的两位数字 +> 这里需要注意的是,我们的 K 值还为 2,我们目前仅删除 2 位数字,但是我们需要删除 4 位,但是后面的几位都是当前位大于前一位。所以我们需要在遍历结束后再移除后面最大的两位数字 ```java class Solution { @@ -93,4 +93,3 @@ class Solution { ``` 这个题目也是很不错的,题目是精心挑选的,然后动图里面的例子也是精心构思过的。所以大家记得打卡呀! - diff --git "a/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/\345\211\221\346\214\207Offer09\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" "b/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/\345\211\221\346\214\207Offer09\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" index 63d9c10..2da8332 100644 --- "a/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/\345\211\221\346\214\207Offer09\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" +++ "b/animation-simulation/\346\240\210\345\222\214\351\230\237\345\210\227/\345\211\221\346\214\207Offer09\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.md" @@ -1,14 +1,12 @@ - - -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [剑指 Offer 09. 用两个栈实现队列](https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/) -今天给大家带来一个有意思的题目,思路很easy,但是刚刷题的小伙伴,示例理解起来可能会有点费劲,花里胡哨一大堆是啥意思啊。在之前的文章《不知道这篇文章合不合你的胃口》中写了栈是先进后出,队列是先进先出。本题让我们用两个先进后出的栈,完成一个先进先出的队列。我们应该怎么实现呢? +今天给大家带来一个有意思的题目,思路很 easy,但是刚刷题的小伙伴,示例理解起来可能会有点费劲,花里胡哨一大堆是啥意思啊。在之前的文章《不知道这篇文章合不合你的胃口》中写了栈是先进后出,队列是先进先出。本题让我们用两个先进后出的栈,完成一个先进先出的队列。我们应该怎么实现呢? 废话不多说,大家看图 @@ -42,7 +40,6 @@ class CQueue { 输出:[null,null,3,-1] ``` - 示例 2: ```java @@ -52,13 +49,14 @@ class CQueue { 输出:[null,-1,null,null,5,2] ``` -其实也很容易理解,输入有两行第一行,为执行的函数,Cqueue代表创建队列(代表我们初始化两个栈),appendTail代表入队操作(代表stackA入栈),deleteHead代表出队操作(代表我们stackB出栈) +其实也很容易理解,输入有两行第一行,为执行的函数,Cqueue 代表创建队列(代表我们初始化两个栈),appendTail 代表入队操作(代表 stackA 入栈),deleteHead 代表出队操作(代表我们 stackB 出栈) -第二行输入代表值,分别给每个函数传入的参数,我们发现只有appendTail函数下有对应值,因为只有该函数传入参数。 +第二行输入代表值,分别给每个函数传入的参数,我们发现只有 appendTail 函数下有对应值,因为只有该函数传入参数。 大家可以点击该链接[剑指 Offer 09. 用两个栈实现队列](https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/)去实现一下,下面我们看代码。 Java Code: + ```java class CQueue { //初始化两个栈 @@ -66,7 +64,7 @@ class CQueue { public CQueue() { stack1 = new Stack<>(); stack2 = new Stack<>(); - + } //入队,我们往第一个栈压入值 public void appendTail (int value) { @@ -91,23 +89,23 @@ class CQueue { ``` JS Code: + ```javascript -var CQueue = function() { - this.stack1 = []; - this.stack2 = []; +var CQueue = function () { + this.stack1 = []; + this.stack2 = []; }; -CQueue.prototype.appendTail = function(value) { - this.stack1.push(value); +CQueue.prototype.appendTail = function (value) { + this.stack1.push(value); }; -CQueue.prototype.deleteHead = function() { - if (!this.stack2.length) { - while(this.stack1.length) { - this.stack2.push(this.stack1.pop()); - } +CQueue.prototype.deleteHead = function () { + if (!this.stack2.length) { + while (this.stack1.length) { + this.stack2.push(this.stack1.pop()); } - return this.stack2.pop() || -1; + } + return this.stack2.pop() || -1; }; ``` - diff --git "a/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\344\270\211\346\225\260\344\271\213\345\222\214.md" "b/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\344\270\211\346\225\260\344\271\213\345\222\214.md" index c2dbffd..f481a51 100644 --- "a/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\344\270\211\346\225\260\344\271\213\345\222\214.md" +++ "b/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\344\270\211\346\225\260\344\271\213\345\222\214.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [15. 三数之和](https://leetcode-cn.com/problems/3sum/) @@ -10,7 +10,7 @@ > 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 > -> 注意:答案中不可以包含重复的三元组。 +> 注意:答案中不可以包含重复的三元组。 示例: @@ -30,7 +30,7 @@ 我们这个题目的哈希表解法是很容易理解的,我们首先将数组排序,排序之后我们将排序过的元素存入哈希表中,我们首先通过两层遍历,确定好前两位数字,那么我们只需要哈希表是否存在符合情况的第三位数字即可,跟暴力解法的思路类似,很容易理解, -但是这里我们需要注意的情况就是,例如我们的例子为[-2 , 1 , 1],如果我们完全按照以上思路来的话,则会出现两个解,[-2 , 1 , 1]和[1 , 1, -2]。具体原因,确定 -2,1之后发现 1 在哈希表中,存入。确定 1 ,1 之后发现 -2 在哈希表中,存入。 +但是这里我们需要注意的情况就是,例如我们的例子为[-2 , 1 , 1],如果我们完全按照以上思路来的话,则会出现两个解,[-2 , 1 , 1]和[1 , 1, -2]。具体原因,确定 -2,1 之后发现 1 在哈希表中,存入。确定 1 ,1 之后发现 -2 在哈希表中,存入。 所以我们需要加入一个约束避免这种情况,那就是我们第三个数的索引大于第二个数时才存入。 @@ -56,7 +56,7 @@ class Solution { } Integer t; int target = 0; - for (int i = 0; i < nums.length; ++i) { + for (int i = 0; i < nums.length; ++i) { target = -nums[i]; //去重 if (i > 0 && nums[i] == nums[i-1]) { @@ -65,17 +65,17 @@ class Solution { for (int j = i + 1; j < nums.length; ++j) { if (j > i+1 && nums[j] == nums[j-1]) { continue; - } + } if ((t = map.get(target - nums[j])) != null) { //符合要求的情况,存入 - if (t > j) { + if (t > j) { resultarr.add(new ArrayList<> (Arrays.asList(nums[i], nums[j], nums[t]))); - } + } else { break; - } + } } } } @@ -84,8 +84,6 @@ class Solution { } ``` - - ### 多指针 #### 解析: @@ -96,8 +94,6 @@ class Solution { ![三数之和起始](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/三数之和起始.44vete07oy80.png) - - 初始情况见上图,我们看当前情况,三数之和为 -3 ,很显然不是 0 ,那么我们应该怎么做呢? 我们设想一下,我们当前的三数之和为 -3 < 0 那么我们如果移动橙色指针的话则会让我们的三数之和变的更小,因为我们的数组是有序的,所以我们移动橙色指针(蓝色不动)时和会变小,如果移动蓝色指针(橙色不动)的话,三数之和则会变大,所以这种情况则需要向右移动我们的蓝色指针, @@ -110,7 +106,7 @@ class Solution { 这里我们发现 0 - 1 + 1 = 0,当前情况是符合的,所以我们需要存入该三元组,存入后,蓝色指针向后移动一步,橙色指针向前移动一步,我们发现仍为 0 -1 + 1 = 0 仍然符合,但是如果继续存入该三元组的话则不符合题意,所以我们需要去重。 -这里可以借助HashSet但是效率太差,不推荐。 +这里可以借助 HashSet 但是效率太差,不推荐。 这里我们可以使用 while 循环将蓝色指针移动到不和刚才相同的位置,也就是直接移动到元素 0 上,橙色指针同样也是。则是下面这种情况, @@ -149,10 +145,10 @@ class Solution { //存入符合要求的值 arr.add(new ArrayList<>(Arrays.asList(nums[i], nums[l], nums[r]))); //这里需要注意顺序 - while(l < r && nums[l] == nums[l+1]) l++; - while(l < r && nums[r] == nums[r-1]) r--; + while(l < r && nums[l] == nums[l+1]) l++; + while(l < r && nums[r] == nums[r-1]) r--; l++; - r--; + r--; } else if(nums[l] + nums[r] > target){ r--; @@ -167,3 +163,49 @@ class Solution { } ``` +Go Code: + +```go +func threeSum(nums []int) [][]int { + res := [][]int{} + length := len(nums) + if length < 3 { + return res + } + + sort.Ints(nums) + for i := 0; i < length - 2; i++ { + // 去重 + if i != 0 && nums[i] == nums[i - 1] { + continue + } + l, r := i + 1, length - 1 + for l < r { + /* + // 下面两个for循环的去重也可以用下面的代码替换 + if l != i + 1 && nums[l] == nums[l - 1] { + l++ + continue + } + */ + if nums[i] + nums[l] + nums[r] == 0 { + res = append(res, []int{nums[i], nums[l], nums[r]}) + for l < r && nums[l] == nums[l + 1] { + l++ + } + for l < r && nums[r] == nums[r - 1] { + r-- + } + l++ + r-- + } else if nums[i] + nums[l] + nums[r] < 0 { + l++ + } else { + r-- + } + + } + } + return res +} +``` diff --git "a/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\344\270\244\346\225\260\344\271\213\345\222\214.md" "b/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\344\270\244\346\225\260\344\271\213\345\222\214.md" index e546bc9..c2f9c94 100644 --- "a/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\344\270\244\346\225\260\344\271\213\345\222\214.md" +++ "b/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\344\270\244\346\225\260\344\271\213\345\222\214.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [1. 两数之和](https://leetcode-cn.com/problems/two-sum/) @@ -25,7 +25,7 @@ #### 解析 -哈希表的做法很容易理解,我们只需通过一次循环即可,假如我们的 target 值为 9,当前指针指向的值为 2 ,我们只需从哈希表中查找是否含有 7,因为9 - 2 =7 。如果含有 7 我们直接返回即可,如果不含有则将当前的2存入哈希表中,指针移动,指向下一元素。注: key 为元素值,value 为元素索引。 +哈希表的做法很容易理解,我们只需通过一次循环即可,假如我们的 target 值为 9,当前指针指向的值为 2 ,我们只需从哈希表中查找是否含有 7,因为 9 - 2 =7 。如果含有 7 我们直接返回即可,如果不含有则将当前的 2 存入哈希表中,指针移动,指向下一元素。注: key 为元素值,value 为元素索引。 动图解析: @@ -54,19 +54,30 @@ class Solution { } ``` +Go Code: +```go +func twoSum(nums []int, target int) []int { + m := make(map[int]int) + for i, num := range nums { + if v, ok := m[target - num]; ok { + return []int{v, i} + } + m[num] = i + } + return []int{} +} +``` ### 双指针(暴力)法 #### 解析 -双指针(L,R)法的思路很简单,L指针用来指向第一个值,R指针用来从第L指针的后面查找数组中是否含有和L指针指向值和为目标值的数。见下图 +双指针(L,R)法的思路很简单,L 指针用来指向第一个值,R 指针用来从第 L 指针的后面查找数组中是否含有和 L 指针指向值和为目标值的数。见下图 ![](https://img-blog.csdnimg.cn/20210319151826855.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) -例:绿指针指向的值为3,蓝指针需要在绿指针的后面遍历查找是否含有 target - 3 = 2的元素,若含有返回即可。 - - +例:绿指针指向的值为 3,蓝指针需要在绿指针的后面遍历查找是否含有 target - 3 = 2 的元素,若含有返回即可。 #### 题目代码 @@ -90,4 +101,3 @@ class Solution { } } ``` - diff --git "a/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\345\233\233\346\225\260\344\271\213\345\222\214.md" "b/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\345\233\233\346\225\260\344\271\213\345\222\214.md" index b9f550d..60f6dab 100644 --- "a/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\345\233\233\346\225\260\344\271\213\345\222\214.md" +++ "b/animation-simulation/\346\261\202\345\222\214\351\227\256\351\242\230/\345\233\233\346\225\260\344\271\213\345\222\214.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [18. 四数之和](https://leetcode-cn.com/problems/4sum/) @@ -20,9 +20,9 @@ > > 满足要求的四元组集合为: > [ -> [-1, 0, 0, 1], +> [-1, 0, 0, 1], > [-2, -1, 1, 2], -> [-2, 0, 0, 2] +> [-2, 0, 0, 2] > ] 我们已经完成了两数之和和三数之和,这个题目应该就手到擒来了,因为我们已经知道这类题目的解题框架,两数之和呢,我们就先固定第一个数 ,然后移动指针去找第二个符合的,三数之和,固定一个数,双指针去找符合情况的其他两位数,那么我们四数之和,也可以先固定两个数,然后利用双指针去找另外两位数。所以我们来搞定他吧。 @@ -51,7 +51,7 @@ class Solution { public List> fourSum(int[] nums, int target) { if(nums.length < 4){ - return new ArrayList<>(); + return new ArrayList<>(); } Arrays.sort(nums); List> arr = new ArrayList<>(); @@ -96,7 +96,56 @@ class Solution { } ``` +Go Code: +```go +func fourSum(nums []int, target int) [][]int { + res := [][]int{} + length := len(nums) + if length < 4 { + return res + } - - + sort.Ints(nums) + for i := 0; i < length - 3; i++ { + // 去重 + if i != 0 && nums[i] == nums[i - 1] { + continue + } + for j := i + 1; j < length - 2; j++ { + // 去重 + if j != i + 1 && nums[j] == nums[j - 1] { + continue + } + l, r := j + 1, length - 1 + for l < r { + /* + // 下面两个for循环的去重也可以用下面的代码替换 + if l != i + 1 && nums[l] == nums[l - 1] { + l++ + continue + } + */ + sum := nums[i] + nums[j] + nums[l] + nums[r] + if sum == target { + res = append(res, []int{nums[i], nums[j], nums[l], nums[r]}) + for l < r && nums[l] == nums[l + 1] { + l++ + } + for l < r && nums[r] == nums[r - 1] { + r-- + } + l++ + r-- + } else if sum < target { + l++ + } else { + r-- + } + + } + } + } + return res +} +``` diff --git "a/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260.md" "b/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260.md" index ce31252..41b8cc9 100644 --- "a/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260.md" +++ "b/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [136. 只出现一次的数字](https://leetcode-cn.com/problems/single-number/) @@ -18,18 +18,20 @@ > 输入: [4,1,2,1,2] > 输出: 4 -这个题目非常容易理解,就是让我们找出那个只出现一次的数字,那么下面我们来看一下这几种解题方法吧 +这个题目非常容易理解,就是让我们找出那个只出现一次的数字,那么下面我们来看一下这几种解题方法吧~ ### HashMap #### 解析 -用 HashMap 的这个方法是很容易实现的,题目要求不是让我们求次数嘛,那我们直接遍历数组将每个数字和其出现的次数存到 哈希表里 就可以了,然后我们再从哈希表里找出出现一次的那个数返回即可。 +用 HashMap 的这个方法是很容易实现的,题目要求不是让我们求次数嘛,那我们直接遍历数组将每个数字和其出现的次数存到哈希表里就可以了,然后我们再从哈希表里找出出现一次的那个数返回即可。 ![哈希表解法](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/哈希表解法.1kefww8xsig0.png) #### 题目代码 +Java Code: + ```java class Solution { public int singleNumber(int[] nums) { @@ -39,7 +41,7 @@ class Solution { } //HashMap HashMap map = new HashMap(); - //将其存入哈希表中,含义为,若该元素不存在则存入表中,并计数为1,若已经存在获取次数并加1. + //将其存入哈希表中,含义为,若该元素不存在则存入表中,并计数为1,若已经存在获取次数并加1 for (int x : nums) { map.put(x , map.getOrDefault(x,0) + 1); } @@ -48,10 +50,104 @@ class Solution { if(map.get(y) == 1){ return y; } - } - return 0; + } + } +} +``` +C++ Code: + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + //特殊情况 + if (nums.size() == 1) { + return nums[0]; + } + //HashMap + unordered_map map; + //将其存入哈希表中,含义为,若该元素不存在则存入表中,并计数为1,若已经存在获取次数并加1 + for (int x : nums) { + if (map.find(x) == map.end()) { + map.insert({x, 0}); + } + map[x] += 1; + } + //遍历出出现次数为1的情况 + for (int y : nums) { + if(map.at(y) == 1){ + return y; + } + } + return -1; + } +}; +``` + +JS Code: + +```javascript +var singleNumber = function (nums) { + //特殊情况 + if (nums.length === 1) { + return nums[0]; + } + //HashMap + map = {}; + //将其存入哈希表中,含义为,若该元素不存在则存入表中,并计数为1,若已经存在获取次数并加1 + for (let x of nums) { + if (!(x in map)) { + map[x] = 0; + } + map[x] += 1; + } + //遍历出出现次数为1的情况 + for (let key in map) { + if (map[key] === 1) { + return key; + } + } +}; +``` + +Python Code: + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> int: + # 特殊情况 + if len(nums) == 1: + return nums[0] + # HashMap + map_ = {} + # 将其存入哈希表中,含义为,若该元素不存在则存入表中,并计数为1,若已经存在获取次数并加1 + for x in nums: + map_.setdefault(x, 0) + map_[x] += 1 + # 遍历出出现次数为1的情况 + for y, count in map_.items(): + if count == 1: + return y +``` + +Go Code: + +```go +func singleNumber(nums []int) int { + if len(nums) == 1 { + return nums[0] + } + m := map[int]int{} + for _, x := range nums { + m[x]++ } + for k, v := range m { + if v == 1 { + return k + } + } + return 0 } ``` @@ -65,6 +161,8 @@ class Solution { #### 题目代码 +Java Code: + ```java class Solution { public int singleNumber(int[] nums) { @@ -74,9 +172,7 @@ class Solution { //排序 Arrays.sort(nums); for (int i = 1; i < nums.length-1; i+=2){ - if (nums[i] == nums[i-1]){ - continue; - }else{ + if (nums[i] != nums[i-1]){ return nums[i-1]; } } @@ -86,7 +182,70 @@ class Solution { } ``` +C++ Code: +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + //排序 + sort(nums.begin(), nums.end()); + for (int i = 1; i < nums.size() - 1; i += 2){ + if (nums[i] != nums[i - 1]){ + return nums[i - 1]; + } + } + return nums[nums.size() - 1]; + } +}; +``` + +JS Code: + +```javascript +var singleNumber = function (nums) { + // 排序 + nums.sort(); + for (let i = 1; i < nums.length - 1; i += 2) { + if (nums[i] != nums[i - 1]) { + return nums[i - 1]; + } + } + return nums[nums.length - 1]; +}; +``` + +Python Code: + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> int: + # 排序 + nums.sort() + for i in range(1, len(nums), 2): + if nums[i] != nums[i - 1]: + return nums[i - 1] + return nums[len(nums) - 1] +``` + +Go Code: + +```go +func singleNumber(nums []int) int { + if len(nums) == 1 { + return nums[0] + } + sort.Ints(nums) + for i := 1; i < len(nums) - 1; i+=2 { + if nums[i] == nums[i - 1] { + continue + } else { + return nums[i - 1] + } + } + return nums[len(nums) - 1] +} +``` ### HashSet @@ -98,21 +257,19 @@ class Solution { #### 题目代码 +Java Code: + ```java class Solution { public int singleNumber(int[] nums) { - if (nums.length == 1){ - return nums[0]; - } HashSet set = new HashSet<>(); //循环遍历 for (int x : nums){ //已经存在,则去除 if(set.contains(x)){ set.remove(x); - } //否则存入 - else{ + } else { set.add(x); } } @@ -122,7 +279,65 @@ class Solution { } ``` +C++ Code: + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + unordered_set set; + //循环遍历 + for (int x : nums) { + //已经存在,则去除 + if (set.find(x) == set.end()) { + set.insert(x); + //否则存入 + } else { + set.erase(x); + } + } + //返回仅剩的一个元素 + return *set.begin(); + } +}; +``` +JS Code: + +```javascript +var singleNumber = function (nums) { + let set = new Set(); + //循环遍历 + for (let x of nums) { + //已经存在,则去除 + if (set.has(x)) { + set.delete(x); + //否则存入 + } else { + set.add(x); + } + } + return set.values().next().value; +}; +``` + +Python Code: + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> int: + set_ = set() + # 循环遍历 + for x in nums: + # 已经存在,则去除 + if x in set_: + set_.remove(x) + # 否则存入 + else: + set_.add(x) + # 返回仅剩的一个元素 + return set_.pop() +``` ### 栈 @@ -134,12 +349,11 @@ class Solution { #### 题目代码 +Java Code: + ```java class Solution { public int singleNumber(int[] nums) { - if (nums.length == 1) { - return nums[0]; - } Arrays.sort(nums); Stack stack = new Stack<>(); for (int x : nums){ @@ -147,57 +361,175 @@ class Solution { stack.push(x); continue; } - //不同时直接跳出 + //不同时直接跳出 if (stack.peek() != x) { break; } - //相同时出栈 - stack.pop(); + //相同时出栈 + stack.pop(); } return stack.peek(); } } ``` +C++ Code: + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + sort(nums.begin(), nums.end()); + stack stack; + for (int x: nums) { + if (stack.empty()) { + stack.push(x); + continue; + } + //不同时直接跳出 + if (stack.top() != x) { + break; + } + //相同时出栈 + stack.pop(); + } + return stack.top(); + } +}; +``` + +JS Code: + +```javascript +var singleNumber = function (nums) { + nums.sort(); + let stack = []; + for (let x of nums) { + if (!stack.length) { + stack.push(x); + continue; + } + //不同时直接跳出 + if (stack[0] !== x) { + break; + } + //相同时出栈 + stack.pop(); + } + return stack[0]; +}; +``` +Python Code: + +```python +from collections import deque + +class Solution: + def singleNumber(self, nums: List[int]) -> int: + if len(nums) == 1: + return nums[0] + nums.sort() + stack = deque() + for x in nums: + if not stack: + stack.append(x) + continue + # 不同时直接跳出 + if stack[-1] != x: + break + # 相同时出栈 + stack.pop() + return stack[-1] +``` ### 求和法 #### 解析 -这个方法也比较简单,也是借助咱们的 HashSet ,具体思路如下,我们通过 HashSet 保存数组内的元素,然后进行求和(setsum),那么得到的这个和则为去除掉重复元素的和,我们也可以得到所有元素和(numsum)。因为我们其他元素都出现两次,仅有一个元素出现一次,那我们通过 setsum * 2 - numsum 得到的元素则为出现一次的数。 +这个方法也比较简单,也是借助咱们的 HashSet ,具体思路如下,我们通过 HashSet 保存数组内的元素,然后进行求和(setsum),那么得到的这个和则为去除掉重复元素的和,我们也可以得到所有元素和(numsum)。因为我们其他元素都出现两次,仅有一个元素出现一次,那我们通过 setsum \* 2 - numsum 得到的元素则为出现一次的数。 ![求和解法](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/求和解法.2tds49a3vzq0.png) -上面我们的 SetSum * 2 - NumSum = z 也就是我们所求的值, 是不是感觉很简单呀。 +上面我们的 SetSum \* 2 - NumSum = z 也就是我们所求的值, 是不是感觉很简单呀。 #### 题目代码 +Java Code: + ```java class Solution { public int singleNumber(int[] nums) { - if (nums.length == 1){ - return nums[0]; - } HashSet set = new HashSet<>(); int setsum = 0; int numsum = 0; for (int x : nums) { //所有元素的和 - numsum += x; + numsum += x; if (!set.contains(x)) { //HashSet内元素的和 - setsum += x; + setsum += x; } set.add(x); - } + } //返回值 return setsum * 2 - numsum; } } ``` +C++ Code: + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + unordered_set set; + int setsum = 0; + int numsum = 0; + for (int x : nums) { + //所有元素的和 + numsum += x; + if (set.find(x) == set.end()) { + //HashSet内元素的和 + setsum += x; + } + set.insert(x); + } + //返回值 + return setsum * 2 - numsum; + } +}; +``` + +JS Code: + +```javascript +var singleNumber = function (nums) { + let set = new Set(); + let setsum = 0; + let numsum = 0; + for (let x of nums) { + //所有元素的和 + numsum += x; + if (!set.has(x)) { + setsum += x; + } + //HashSet内元素的和 + set.add(x); + } + //返回值 + return 2 * setsum - numsum; +}; +``` +Python Code: + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> int: + return 2 * sum(set(nums)) - sum(nums) +``` ### 位运算 @@ -205,10 +537,10 @@ class Solution { 这个方法主要是借助咱们的位运算符 ^ 按位异或,我们先来了解一下这个位运算符。 -> 按位异或(XOR)运算符“^”是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。相同时为0。 +> 按位异或(XOR)运算符“^”是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为 1。相同时为 0。 -> 任何数和0异或,仍为本身:a⊕0 = a -> 任何数和本身异或,为0:a⊕a = 0 +> 任何数和 0 异或,仍为本身:a⊕0 = a +> 任何数和本身异或,为 0:a⊕a = 0 > 异或运算满足交换律和结合律:a⊕b⊕a = (a⊕a)⊕b = 0⊕b = b 例: @@ -221,12 +553,14 @@ class Solution { #### 题目代码 +Java Code: + ```java class Solution { public int singleNumber(int[] nums) { int num = 0; //异或 - for (int x : nums) { + for (int x : nums) { num ^= x; } return num; @@ -234,4 +568,53 @@ class Solution { } ``` -本题一共介绍了6种解题方法,肯定还有别的方法,欢迎大家讨论。大家可以在做题的时候一题多解。这样能大大提高自己解题能力。下面我们来看一下这些方法如何应用到其他题目上。 \ No newline at end of file +C++ Code: + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + int num = 0; + //异或 + for (vector::iterator x = nums.begin(); x != nums.end(); x++) { + num ^= *x; + } + return num; + } +}; +``` + +JS Code: + +```javascript +var singleNumber = function (nums) { + //异或 + return nums.reduce((num, x) => (num ^= x)); +}; +``` + +Python Code: + +```python +from functools import reduce + +class Solution: + def singleNumber(self, nums: List[int]) -> int: + # 异或 + return reduce(lambda num, x: num ^ x, nums, 0) +``` + +Go Code: + +```go +func singleNumber(nums []int) int { + res := 0 + for _, x := range nums { + res ^= x + } + return res + +} +``` + +本题一共介绍了 6 种解题方法,肯定还有别的方法,欢迎大家讨论。大家可以在做题的时候一题多解。这样能大大提高自己解题能力。下面我们来看一下这些方法如何应用到其他题目上。 diff --git "a/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\2602.md" "b/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\2602.md" index 31b47e1..bef6429 100644 --- "a/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\2602.md" +++ "b/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\2602.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [137. 只出现一次的数字 II](https://leetcode-cn.com/problems/single-number-ii/) @@ -28,88 +28,262 @@ 1.通过遍历数组获取所有元素的和以及 HashSet 内元素的和。 -2.(SumSet * 3 - SumNum)/ 2即可,除以 2 是因为我们减去之后得到的是 2 倍的目标元素。 +2.(SumSet \* 3 - SumNum)/ 2 即可,除以 2 是因为我们减去之后得到的是 2 倍的目标元素。 注:这个题目中需要注意溢出的情况 。 #### 题目代码 +Java Code: + ```java class Solution { public int singleNumber(int[] nums) { HashSet set = new HashSet<>(); - long sumset = 0; - long sumnum = 0; + long setsum = 0; + long numsum = 0; for (int x : nums) { //所有元素的和 - sumnum += x; - if (set.contains(x)) { - continue; - } - //HashSet元素和 - sumset += x; + numsum += x; + if (!set.contains(x)) { + //HashSet元素和 + setsum += x; + } set.add(x); } //返回只出现一次的数 - return (int)((3 * sumset - sumnum) / 2); + return (int)((3 * setsum - numsum) / 2); } } ``` +C++ Code: + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + unordered_set set; + long setsum = 0; + long numsum = 0; + for (int x : nums) { + //所有元素的和 + numsum += x; + if (set.find(x) == set.end()) { + //HashSet内元素的和 + setsum += x; + } + set.insert(x); + } + //返回值 + return (3 * setsum - numsum) / 2; + } +}; +``` + +JS Code: + +```javascript +var singleNumber = function (nums) { + let set = new Set(); + let setsum = 0; + let numsum = 0; + for (let x of nums) { + //所有元素的和 + numsum += x; + if (!set.has(x)) { + setsum += x; + } + //HashSet内元素的和 + set.add(x); + } + //返回值 + return (3 * setsum - numsum) / 2; +}; +``` + +Python Code: + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> int: + return (3 * sum(set(nums)) - sum(nums)) // 2 +``` + 这个题目用 HashMap 和排序查找肯定也是可以的,大家可以自己写一下,另外我们在第一题中有个利用异或求解的方法,但是这个题目是出现三次,我们则不能利用直接异或来求解,那还有其他方法吗? ### 位运算 #### 解析 -这个方法主要做法是将我们的数的二进制位每一位相加,然后对其每一位的和取余 ,我们看下面的例子。 +这个方法主要做法是将我们的数的二进制位每一位相加,然后对其每一位的和与 3 取余 ,我们看下面的例子。 ![只出现一次的数字2](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/只出现一次的数字2.5p4wxbiegxc0.png) -那么我们为什么要这样做呢?大家想一下,如果其他数都出现 3 次,只有目标数出现 1 次,那么每一位的 1 的个数无非有这2种情况,为 3 的倍数(全为出现三次的数) 或 3 的倍数 +1(包含出现一次的数)。这个 3 的倍数 +1 的情况也就是我们的目标数的那一位。 +那么我们为什么要这样做呢?大家想一下,如果其他数都出现 3 次,只有目标数出现 1 次,那么每一位的 1 的个数无非有这两种情况,为 3 的倍数(全为出现三次的数)或 3 的倍数 +1(包含出现一次的数)。这个 3 的倍数 +1 的情况也就是我们的目标数的那一位。 #### 题目代码 +Java Code: + ```java class Solution { public int singleNumber(int[] nums) { int res = 0; for(int i = 0; i < 32; i++){ int count = 0; - for (int j = 0; j < nums.length; j++) { - //先将数右移,并求出最后一位为 1 的个数 - if ((nums[j] >> i & 1) == 1) { + for (int num: nums) { + //检查第 i 位是否为 1 + if ((num >> i & 1) == 1) { count++; - } + } } - //找到某一位取余为 1 的数,并左移,为了将这一位循环结束后移至原位 if (count % 3 != 0) { + // 将第 i 位设为 1 res = res | 1 << i; } } - return res; + return res; } } ``` -我们来解析一下我们的代码 +C++ Code: -> **<<** 左移动运算符:运算数的各二进位全部左移若干位,由 **<<** 右边的数字指定了移动的位数,高位丢弃,低位补0。 -> -> **>>** 右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,**>>** 右边的数字指定了移动的位数 +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + int res = 0; + for(int i = 0; i < 32; i++){ + int count = 0; + for (int num: nums) { + //检查第 i 位是否为 1 + if ((num >> i & 1) == 1) { + count++; + } + } + if (count % 3 != 0) { + // 将第 i 位设为 1 + res = res | 1 << i; + } + } + return res; + } +}; +``` -另外我们的代码中还包含了 a & 1 和 a | 1 这有什么作用呢?继续看下图 +JS Code: + +```javascript +var singleNumber = function (nums) { + let res = 0; + for (let i = 0; i < 32; i++) { + let count = 0; + for (let num of nums) { + //检查第 i 位是否为 1 + if (((num >> i) & 1) == 1) { + count++; + } + } + if (count % 3 != 0) { + // 将第 i 位设为 1 + res = res | (1 << i); + } + } + return res; +}; +``` + +Python Code: + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> int: + res = 0 + for i in range(32): + count = 0 + for num in nums: + # 检查第 i 位是否为 1 + if (num >> i & 1) == 1: + count += 1 + if count % 3 != 0: + # 将第 i 位设为 1 + res = res | 1 << i + # 这里的做法稍有不同,见下方解释 + if (res >> 31 & 1) == 1: + res = ~(res ^ 4294967295) + return res +``` + +Go Code: + +```go +func singleNumber(nums []int) int { + res := 0 + // Go语言中,int占32位以上 + for i := 0; i < 64; i++ { + cnt := 0 + for j := 0; j < len(nums); j++ { + if (nums[j] >> i & 1) == 1 { + cnt++ + } + } + if cnt % 3 != 0{ + res = res | 1 << i + } + } + return res +} +``` + +我们来解析一下我们的代码: -> **&** 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 +> **<<** 左移运算符:运算数的各二进位全部左移若干位,由 **<<** 右边的数字指定了移动的位数,高位丢弃,低位补 0。 +> +> **>>** 右移运算符:**>> ** 左边的运算数的各二进位全部右移若干位,**>>** 右边的数字指定了移动的位数。 +另外我们的代码中还包含了 a & 1 和 a | 1 这有什么作用呢?继续看下图。 +> **&** 按位与运算符:参与运算的两个值,如果两个相应位都为 1,则该位的结果为 1,否则为 0。 ![只出现一次的数位运算且](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/只出现一次的数位运算且.vq3lcgv0rbk.png) -因为我们 a & 1 中 1 只有最后一位为 1,其余位皆为 0 ,所以我们发现 a & 1的作用就是判断 a 的最后一位是否为 1 ,如果 a 的最后一位为 1 ,a & 1 = 1,否则为 0 。所以我们还可以通过这个公式来判断 a 的奇偶性。 +因为我们 a & 1 中 1 只有最后一位为 1,其余位皆为 0 ,所以我们发现 **a & 1 的作用就是判断 a 的最后一位是否为 1** ,如果 a 的最后一位为 1 ,a & 1 = 1,否则为 0 。所以我们还可以通过这个公式来判断 a 的奇偶性。 -> **|** 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。 +> **|** 按位或运算符:只要对应的二个二进位有一个为 1 时,结果位就为 1。 ![或运算](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/或运算.6orep3gsrxc0.png) -这个公式的作用就是将我们移位后的 res 的最后一位 0 变为 1。这个 1 也就代表着我们只出现一次元素的某一位。 \ No newline at end of file +这个公式的作用就是**将我们移位后的 res 的最后一位 0 变为 1**。这个 1 也就代表着我们只出现一次元素的某一位。 + +> 贡献者[@jaredliw](https://github.com/jaredliw)注: +> +> 这里我想解释一下 python 里的这两行: +> +> ```python +> if (res >> 31 & 1) == 1: +> res = ~(res ^ 4294967295) +> ``` +> +> int 的的符号是由最高位(这题用的是 32 位)的值决定,1 就是负数,0 就是正数。由于 python 的 int 类型理论上是无限大的,这题里的 res 都会被认定为是正数。举个例子,32 位的 -4 是这样的: +> +> > 11111111111111111111111111111100 (最高位是 1 )= -4 +> +> python 里的则是这样的: +> +> > ...000000000000 11111111111111111111111111111100 (前面跟着无限个 0,最高位是 0 )= 4294967292 +> +> 怎么办呢? +> +> 我们可以先将 res 的后 32 位取反(与 4294967295 异或,4294967295 的二进制是 32 个 1),得到: +> +> > ...000000000000 00000000000000000000000000000011(最高位是 0)= 3 +> +> 之后再用波浪号按位取反,得到: +> +> > ...111111111111 11111111111111111111111111111100 (前面跟着无限个 1,最高位是 1)= -4 +> +> 大家可以自行验证看看:`(res >> n & 1) == 1` ,n 随便填个大于 31 的数字,之前是 false,之后就变成 true (代表第 33 位,第 34 位,……都转成 1 了)。 +> +> 虽然说这种方法有一种脱裤子放屁的感觉 ,而且`res -= 2 ** 32` 也能办到,但由于涉及到 int 存储的问题(我省略了许多,大家自行度娘哈),我觉得还是有必要知道的。 diff --git "a/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\2603.md" "b/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\2603.md" index a33da9e..6e40167 100644 --- "a/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\2603.md" +++ "b/animation-simulation/\346\261\202\346\254\241\346\225\260\351\227\256\351\242\230/\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\2603.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [260. 只出现一次的数字 III](https://leetcode-cn.com/problems/single-number-iii/) @@ -13,7 +13,7 @@ > 输入: [1,2,1,3,2,5] > 输出: [3,5] -这个也很容易理解,算是对第一题的升级,第一题有 1 个出现 1次的数,其余出现两次,这个题目中有 2 个出现 1次的数,其余数字出现两次。那么这个题目我们怎么做呢?我们看一下能不能利用第一题中的做法解决。 +这个也很容易理解,算是对第一题的升级,第一题有 1 个出现一次的数,其余出现两次,这个题目中有 2 个出现一次的数,其余数字出现两次。那么这个题目我们怎么做呢?我们看一下能不能利用第一题中的做法解决。 ### HashSet @@ -23,6 +23,8 @@ #### 题目代码 +Java Code: + ```java class Solution { public int[] singleNumber(int[] nums) { @@ -31,22 +33,91 @@ class Solution { //存在的则移除 if (set.contains(x)) { set.remove(x); - continue; + //不存在则存入 + } else { + set.add(x); } - //不存在存入 - set.add(x); } //存到数组里,然后返回 int[] arr = new int[2]; int i = 0; for (int y : set) { - arr[i++] = y; + arr[i++] = y; } return arr; } } ``` +C++ Code: + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + unordered_set set; + for (int x : nums) { + //存在的则移除 + if (set.find(x) == set.end()) { + set.insert(x); + //不存在则存入 + } else { + set.erase(x); + } + } + //存到数组里,然后返回 + vector arr; + for (int y : set) { + arr.push_back(y); + } + return arr; + } +}; +``` + +JS Code: + +```javascript +var singleNumber = function (nums) { + let set = new Set(); + for (let x of nums) { + //存在的则移除 + if (set.has(x)) { + set.delete(x); + //不存在则存入 + } else { + set.add(x); + } + } + //存到数组里,然后返回 + let arr = []; + for (let y of set) { + arr.push(y); + } + return arr; +}; +``` + +Python Code: + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + set_ = set() + for x in nums: + # 存在的则移除 + if x in set_: + set_.remove(x) + # 不存在则存入 + else: + set_.add(x) + # 存到数组里,然后返回 + arr = [] + for y in set_: + arr.append(y) + return arr +``` + ### 位运算 #### 解析 @@ -55,53 +126,59 @@ class Solution { 我们试想一下,如果我们先将元素分成两组,然后每组包含一个目标值,那么异或之后,每组得到一个目标值,那么我们不就将两个目标值求出了吗? -> 例: **a,b,a,b,c,d,e,f,e,f ** 分组后 +> 例: **a, b, a, b, c, d, e, f, e, f ** +> +> 分组后: > -> A组:a, a , b, b, c 异或得到 c +> ​ A 组:a, a, b, b, c 异或得到 c > -> B组:e, e, f, f, d 异或得到 d +> ​ B 组:e, e, f, f, d 异或得到 d 原理懂了,那么我们应该依据什么规则对其进行分类呢? -c , d 两个不同的数,那么二进制上必定有一位是不同的,那么我们就可以根据这一位(分组位)来将 c , d 分到两个组中,数组中的其他元素,要么在 A 组中,要么在 B 组中。 +c,d 两个不同的数,那么二进制上必定有一位是不同的,那么我们就可以根据这一位(分组位)来将 c,d 分到两个组中,数组中的其他元素,要么在 A 组中,要么在 B 组中。 我们应该怎么得到分组位呢? -我们让 c , d 异或即可,异或运算就是对应位不同时得 1 ,异或之后值为 1 的其中一位则为我们分组。 +我们让 c,d 异或即可,异或运算就是对应位不同时得 1,异或之后值为 1 的其中一位则为我们分组。 -例 001 ⊕ 100 = 101,我们可以用最右边的 1 或最左边的 1 做为分组位,数组元素中,若我们将最右边的 1 作为我们的分组位,最后一位为 0 的则进入 A 组,为 1 的进入 B 组。 +例 001 ⊕ 100 = 101,我们可以用最右边的 1 或最左边的 1 做为分组位,数组元素中,若我们将最右边的 1 作为我们的分组位,最后一位为 0 的则进入 A 组,为 1 的进入 B 组。 那么我们应该怎么借助分组位进行分组呢? -我们处理 c , d 的异或值,可以仅保留异或值的分组位,其余位变为 0 ,例如 101 变成 001或 100 +我们处理 c , d 的异或值,可以仅保留异或值的分组位,其余位变为 0 ,例如 101 变成 001 或 100。 -为什么要这么做呢?在第二题提到,我们可以根据 a & 1 来判断 a 的最后一位为 0 还是为 1,所以我们将 101 变成 001 之后,然后数组内的元素 x & 001 即可对 x 进行分组 。同样也可以 x & 100 进行分组. +为什么要这么做呢?在第二题提到,我们可以根据 a & 1 来判断 a 的最后一位为 0 还是为 1,所以我们将 101 变成 001 之后,然后数组内的元素 x & 001 即可对 x 进行分组 。同样也可以 x & 100 进行分组。 -那么我们如何才能仅保留分组位,其余位变为 0 呢?例 101 变为 001 +那么我们如何才能仅保留分组位,其余位变为 0 呢?例 101 变为 001。 -我们可以利用 x & (-x) 来保留最右边的 1 +我们可以利用 x & (-x) 来保留最右边的 1。 ![分组位](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/分组位.25gbi25kv7c0.png) #### 题目代码: +Java Code: + ```java class Solution { public int[] singleNumber(int[] nums) { - int temp = 0; + //小心溢出 + long temp = 0; //求出异或值 for (int x : nums) { temp ^= x; } + System.out.println(temp); + System.out.println(-temp); //保留最右边的一个 1 - int group = temp & (-temp); - System.out.println(group); + long group = temp & (-temp); int[] arr = new int[2]; - for (int y : nums) { - //分组位为0的组,组内异或 + for (int y : nums) { + //分组位为 0 的组,组内异或 if ((group & y) == 0) { arr[0] ^= y; - //分组位为 1 的组,组内异或 + //分组位为 1 的组,组内异或 } else { arr[1] ^= y; } @@ -111,3 +188,101 @@ class Solution { } ``` +C++ Code: + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + //小心 -temp 溢出 + long temp = 0; + //求出异或值 + for (int x : nums) { + temp ^= x; + } + //保留最右边的一个 1 + int group = temp & (-temp); + vector arr(2, 0); + for (int y : nums) { + //分组位为 0 的组,组内异或 + if ((group & y) == 0) { + arr[0] ^= y; + //分组位为 1 的组,组内异或 + } else { + arr[1] ^= y; + } + } + return arr; + } +}; +``` + +JS Code: + +```javascript +var singleNumber = function (nums) { + let temp = 0; + //求出异或值 + for (let x of nums) { + temp ^= x; + } + //保留最右边的一个 1 + let group = temp & -temp; + let arr = [0, 0]; + for (let y of nums) { + //分组位为 0 的组,组内异或 + if ((group & y) == 0) { + arr[0] ^= y; + //分组位为 1 的组,组内异或 + } else { + arr[1] ^= y; + } + } + return arr; +}; +``` + +Python Code: + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + temp = 0 + # 求出异或值 + for x in nums: + temp ^= x + # 保留最右边的一个 1 + group = temp & (-temp) + arr = [0, 0] + for y in nums: + # 分组位为 0 的组,组内异或 + if (group & y) == 0: + arr[0] ^= y + # 分组位为 1 的组,组内异或 + else: + arr[1] ^= y + return arr +``` + +Go Code: + +```go +func singleNumber(nums []int) []int { + temp := 0 + for _, x := range nums { + temp ^= x + } + // 保留最后那个1,为了区分两个数 + group := temp & (^temp + 1) + + res := make([]int, 2) + for _, x := range nums { + if group & x == 0{ + res[0] ^= x + } else { + res[1] ^= x + } + } + return res +} +``` diff --git "a/animation-simulation/\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225/LFU.md" "b/animation-simulation/\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225/LFU.md" new file mode 100644 index 0000000..e69de29 diff --git "a/animation-simulation/\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225/LRU.md" "b/animation-simulation/\347\274\223\345\255\230\346\267\230\346\261\260\347\256\227\346\263\225/LRU.md" new file mode 100644 index 0000000..e69de29 diff --git "a/animation-simulation/\350\256\276\350\256\241/LRU.md" "b/animation-simulation/\350\256\276\350\256\241/LRU.md" index 76ad876..6270f77 100644 --- "a/animation-simulation/\350\256\276\350\256\241/LRU.md" +++ "b/animation-simulation/\350\256\276\350\256\241/LRU.md" @@ -4,11 +4,11 @@ 说起**缓存淘汰策略**我们也很熟悉。 -例如先进先出策略FIFO(First In,First Out),最少使用策略LFU(Least Frequently Used),最近最少使用策略LRU(Least Recently Used) +例如先进先出策略 FIFO(First In,First Out),最少使用策略 LFU(Least Frequently Used),最近最少使用策略 LRU(Least Recently Used) 看到这里大家是不是想到我们今天要说什么啦。 -我们就来说一下其中的一个缓存淘汰策略,**最近最少使用策略LRU** +我们就来说一下其中的一个缓存淘汰策略,**最近最少使用策略 LRU** LRU 的含义很容易理解,我们可以这样思考,最近使用过的我们则认为其是有用的,很久没用过的则认为是无用的,因为我们的内存有限,当我们内存满的时候,肯定是先清除那些很久没用过的数据。 @@ -32,4 +32,4 @@ LRU 的含义很容易理解,我们可以这样思考,最近使用过的我 数组? -数组当然可以,但是我们使用数组需要 \ No newline at end of file +数组当然可以,但是我们使用数组需要 diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/234. \345\233\236\346\226\207\351\223\276\350\241\250.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/234. \345\233\236\346\226\207\351\223\276\350\241\250.md" index fe3e1ed..d7bd24b 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/234. \345\233\236\346\226\207\351\223\276\350\241\250.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/234. \345\233\236\346\226\207\351\223\276\350\241\250.md" @@ -1,10 +1,8 @@ - - -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [234. 回文链表](https://leetcode-cn.com/problems/palindrome-linked-list/) @@ -17,7 +15,6 @@ 输出: false ``` - 示例 2: ```java @@ -27,7 +24,7 @@ 题目解析: -题目理解起来很简单,判断是否为回文,如果单纯判断一个字符串或者数组是不是回文很容易。因为数组查询元素的时间复杂度为O(1),但是链表的查询时间复杂度为O(n),而且题目中的链表为单链表,指针只能后移不能前移。所以我们判断起来会比较困难。 +题目理解起来很简单,判断是否为回文,如果单纯判断一个字符串或者数组是不是回文很容易。因为数组查询元素的时间复杂度为 O(1),但是链表的查询时间复杂度为 O(n),而且题目中的链表为单链表,指针只能后移不能前移。所以我们判断起来会比较困难。 巧用数组法: @@ -35,6 +32,8 @@ **题目代码** +Java Code: + ```java class Solution { public boolean isPalindrome(ListNode head) { @@ -46,7 +45,7 @@ class Solution { arr.add(copynode.val); copynode = copynode.next; } - // 双指针遍历数组 + //双指针遍历数组 int back = 0; int pro = arr.size() - 1; while (back < pro) { @@ -61,12 +60,146 @@ class Solution { return true; } } +``` + +C++ Code: +```cpp +class Solution { +public: + bool isPalindrome(ListNode* head) { + //这里需要用动态数组,因为我们不知道链表的长度 + vector arr; + ListNode* copynode = head; + //将链表的值复制到数组中 + while (copynode) { + arr.push_back(copynode->val); + copynode = copynode->next; + } + //双指针遍历数组 + int back = 0; + int pro = arr.size() - 1; + while (back < pro) { + //判断两个指针的值是否相等 + if (arr[back] != arr[pro]) { + return false; + } + //移动指针 + back++; + pro--; + } + return true; + } +}; +``` + +JS Code: + +```js +var isPalindrome = function (head) { + let arr = []; + let copynode = head; + //将链表的值复制到数组中 + while (copynode) { + arr.push(copynode.val); + copynode = copynode.next; + } + //双指针遍历数组 + let back = 0; + let pro = arr.length - 1; + while (back < pro) { + //判断两个指针的值是否相等 + if (arr[back] !== arr[pro]) { + return false; + } + //移动指针 + back += 1; + pro -= 1; + } + return true; +}; +``` + +Python Code: + +```python +class Solution: + def isPalindrome(self, head: ListNode) -> bool: + arr = [] + copynode = head + # 将链表的值复制到数组中 + while copynode is not None: + arr.append(copynode.val) + copynode = copynode.next + # 双指针遍历数组 + back = 0 + pro = len(arr) - 1 + while back < pro: + # 判断两个指针的值是否相等 + if arr[back] != arr[pro]: + return False + # 移动指针 + back += 1 + pro -= 1 + return True +``` + +Swift Code: + +```swift +class Solution { + func isPalindrome(_ head: ListNode?) -> Bool { + // 这里需要用动态数组,因为我们不知道链表的长度 + var arr:[Int?] = [] + var copynode = head + // 将链表的值复制到数组中 + while copynode != nil { + arr.append(copynode?.val) + copynode = copynode?.next + } + // 双指针遍历数组 + var back = 0, pro = arr.count - 1 + while back < pro { + // 判断两个指针的值是否相等 + if arr[pro] != arr[back] { + return false + } + // 移动指针 + back += 1 + pro -= 1 + } + return true + } +} +``` + +Go Code: + +```go +func isPalindrome(head *ListNode) bool { + // 将节点中的值按顺序放在arr中。 + arr := []int{} + node := head + for node != nil { + arr = append(arr, node.Val) + node = node.Next + } + // 双指针判断是否为回文 + l, r := 0, len(arr) - 1 + for l < r { + if arr[l] != arr[r] { + return false + } + l++ + r-- + } + return true +} ``` 这个方法可以直接通过,但是这个方法需要辅助数组,那我们还有其他更好的方法吗? -双指针翻转链表法 +**双指针翻转链表法** 在上个题目中我们知道了如何找到链表的中间节点,那我们可以在找到中间节点之后,对后半部分进行翻转,翻转之后,重新遍历前半部分和后半部分进行判断是否为回文。 @@ -82,53 +215,50 @@ Java Code: class Solution { public boolean isPalindrome(ListNode head) { if (head==null || head.next==null) { - return true; + return true; } //找到中间节点,也就是翻转的头节点,这个在昨天的题目中讲到 //但是今天和昨天有一些不一样的地方就是,如果有两个中间节点返回第一个,昨天的题目是第二个 - ListNode midenode = searchmidnode(head); + ListNode midnode = searchmidnode(head); //原地翻转链表,需要两个辅助指针。这个也是面试题目,大家可以做一下 //这里我们用的是midnode.next需要注意,因为我们找到的是中点,但是我们翻转的是后半部分 - - ListNode backhalf = reverse(midenode.next); + ListNode backhalf = reverse(midnode.next); //遍历两部分链表,判断值是否相等 ListNode p1 = head; - ListNode p2 = backhalf; + ListNode p2 = backhalf; while (p2 != null) { if (p1.val != p2.val) { - return false; + //若要还原,记得这里也要reverse + midnode.next = reverse(backhalf); + return false; } p1 = p1.next; p2 = p2.next; - } - // 还原链表并返回结果,这一步是需要注意的,我们不可以破坏初始结构,我们只是判断是否为回文, + } + //还原链表并返回结果,这一步是需要注意的,我们不可以破坏初始结构,我们只是判断是否为回文, //当然如果没有这一步也是可以AC,但是面试的时候题目要求可能会有这一条。 - midenode.next = reverse(backhalf); - return true; + midnode.next = reverse(backhalf); + return true; } - //找到中间的部分 - public ListNode searchmidnode (ListNode head) { - ListNode fast = new ListNode(-1); - ListNode slow = new ListNode(-1); - fast = head; - slow = head; - //找到中点 + //找到中点 + public ListNode searchmidnode (ListNode head) { + ListNode fast = head; + ListNode slow = head; while (fast.next != null && fast.next.next != null) { fast = fast.next.next; slow = slow.next; - } + } return slow; } //翻转链表 public ListNode reverse (ListNode slow) { ListNode low = null; ListNode temp = null; - //翻转链表 while (slow != null) { - temp = slow.next; - slow.next = low; - low = slow; - slow = temp; + temp = slow.next; + slow.next = low; + low = slow; + slow = temp; } return low; } @@ -144,54 +274,259 @@ public: if (head == nullptr || head->next == nullptr) { return true; } - //找到中间节点,也就是翻转的头节点,这个在昨天的题目中讲到 + //找到中间节点,也就是翻转的头节点,这个在昨天的题目中讲到 //但是今天和昨天有一些不一样的地方就是,如果有两个中间节点返回第一个,昨天的题目是第二个 - ListNode * midenode = searchmidnode(head); + ListNode * midnode = searchmidnode(head); //原地翻转链表,需要两个辅助指针。这个也是面试题目,大家可以做一下 //这里我们用的是midnode->next需要注意,因为我们找到的是中点,但是我们翻转的是后半部分 - - ListNode * backhalf = reverse(midenode->next); + ListNode * backhalf = reverse(midnode->next); //遍历两部分链表,判断值是否相等 ListNode * p1 = head; - ListNode * p2 = backhalf; + ListNode * p2 = backhalf; while (p2 != nullptr) { if (p1->val != p2->val) { - return false; + //若要还原,记得这里也要reverse + midnode->next = reverse(backhalf); + return false; } p1 = p1->next; p2 = p2->next; - } - // 还原链表并返回结果,这一步是需要注意的,我们不可以破坏初始结构,我们只是判断是否为回文, + } + //还原链表并返回结果,这一步是需要注意的,我们不可以破坏初始结构,我们只是判断是否为回文, //当然如果没有这一步也是可以AC,但是面试的时候题目要求可能会有这一条。 - midenode->next = reverse(backhalf); - return true; + midnode->next = reverse(backhalf); + return true; } //找到中间的部分 - ListNode * searchmidnode (ListNode * head) { - ListNode * fast = new ListNode(-1); - ListNode * slow = new ListNode(-1); - fast = head; - slow = head; - //找到中点 + ListNode * searchmidnode (ListNode * head) { + ListNode * fast = head; + ListNode * slow = head; while (fast->next != nullptr && fast->next->next != nullptr) { fast = fast->next->next; slow = slow->next; - } + } return slow; } //翻转链表 ListNode * reverse (ListNode * slow) { ListNode * low = nullptr; ListNode * temp = nullptr; - //翻转链表 while (slow != nullptr) { - temp = slow->next; - slow->next = low; - low = slow; - slow = temp; + temp = slow->next; + slow->next = low; + low = slow; + slow = temp; } return low; } }; ``` +JS Code: + +```javascript +var isPalindrome = function (head) { + if (head === null || head.next === null) { + return true; + } + //找到中间节点,也就是翻转的头节点,这个在昨天的题目中讲到 + //但是今天和昨天有一些不一样的地方就是,如果有两个中间节点返回第一个,昨天的题目是第二个 + let midnode = searchmidnode(head); + //原地翻转链表,需要两个辅助指针。这个也是面试题目,大家可以做一下 + //这里我们用的是midnode.next需要注意,因为我们找到的是中点,但是我们翻转的是后半部分 + let backhalf = reverse(midnode.next); + //遍历两部分链表,判断值是否相等 + let p1 = head; + let p2 = backhalf; + while (p2 != null) { + if (p1.val != p2.val) { + //若要还原,记得这里也要reverse + midnode.next = reverse(backhalf); + return false; + } + p1 = p1.next; + p2 = p2.next; + } + //还原链表并返回结果,这一步是需要注意的,我们不可以破坏初始结构,我们只是判断是否为回文, + //当然如果没有这一步也是可以AC,但是面试的时候题目要求可能会有这一条。 + midnode.next = reverse(backhalf); + return true; +}; + +//找到中点 +var searchmidnode = function (head) { + let fast = head; + let slow = head; + while (fast.next != null && fast.next.next != null) { + fast = fast.next.next; + slow = slow.next; + } + return slow; +}; + +//翻转链表 +var reverse = function (slow) { + let low = null; + let temp = null; + while (slow != null) { + temp = slow.next; + slow.next = low; + low = slow; + slow = temp; + } + return low; +}; +``` + +Python Code: + +```python +class Solution: + def isPalindrome(self, head: ListNode) -> bool: + if head is None or head.next is None: + return True + # 找到中间节点,也就是翻转的头节点,这个在昨天的题目中讲到 + # 但是今天和昨天有一些不一样的地方就是,如果有两个中间节点返回第一个,昨天的题目是第二个 + midnode = self.searchmidnode(head) + # 原地翻转链表,需要两个辅助指针。这个也是面试题目,大家可以做一下 + # 这里我们用的是midnode.next需要注意,因为我们找到的是中点,但是我们翻转的是后半部分 + backhalf = self.reverse(midnode.next) + # 遍历两部分链表,判断值是否相等 + p1 = head + p2 = backhalf + while p2 is not None: + if p1.val != p2.val: + # 若要还原,记得这里也要reverse + midnode.next = self.reverse(backhalf) + return False + p1 = p1.next + p2 = p2.next + # 还原链表并返回结果,这一步是需要注意的,我们不可以破坏初始结构,我们只是判断是否为回文, + # 当然如果没有这一步也是可以AC,但是面试的时候题目要求可能会有这一条。 + midnode.next = self.reverse(backhalf) + return True + + # 找到中点 + def searchmidnode(self, head): + fast = head + slow = head + while fast.next is not None and fast.next.next is not None: + fast = fast.next.next + slow = slow.next + return slow + + # 翻转链表 + def reverse(self, slow): + low = None + temp = None + while slow is not None: + temp = slow.next + slow.next = low + low = slow + slow = temp + return low +``` + +Swift Code: + +```swift +class Solution { + func isPalindrome(_ head: ListNode?) -> Bool { + if head == nil || head?.next == nil { + return true + } + //找到中间节点,也就是翻转的头节点,这个在昨天的题目中讲到 + //但是今天和昨天有一些不一样的地方就是,如果有两个中间节点返回第一个,昨天的题目是第二个 + var midnode = searchmidnode(head) + //原地翻转链表,需要两个辅助指针。这个也是面试题目,大家可以做一下 + //这里我们用的是midnode.next需要注意,因为我们找到的是中点,但是我们翻转的是后半部分 + var backhalf = reverse(midnode?.next); + //遍历两部分链表,判断值是否相等 + var p1 = head + var p2 = backhalf + while p2 != nil { + if p1?.val != p2?.val { + midnode?.next = reverse(backhalf) + return false + } + p1 = p1?.next + p2 = p2?.next + } + //还原链表并返回结果,这一步是需要注意的,我们不可以破坏初始结构,我们只是判断是否为回文, + //当然如果没有这一步也是可以AC,但是面试的时候题目要求可能会有这一条。 + midnode?.next = reverse(backhalf) + return true + } + //找到中点 + func searchmidnode(_ head: ListNode?) -> ListNode? { + var fast = head, slow = head + while fast?.next != nil && fast?.next?.next != nil { + fast = fast?.next?.next + slow = slow?.next + } + return slow + } + //翻转链表 + func reverse(_ slow: ListNode?) -> ListNode? { + var slow = slow + var low: ListNode? + var temp: ListNode? + while slow != nil { + temp = slow?.next + slow?.next = low + low = slow + slow = temp + } + return low + } +} +``` + +Go Code: + +```go +func isPalindrome(head *ListNode) bool { + if head == nil || head.Next == nil { + return true + } + + midNode := searchMidNode(head) + backHalf := reverse(midNode.Next) + + // 判断左右两边是否一样(回文) + p1, p2 := head, backHalf + for p2 != nil { + if p1.Val != p2.Val { + midNode.Next = reverse(backHalf) + return false + } + p1 = p1.Next + p2 = p2.Next + } + // 不破坏原来的数据 + midNode.Next = reverse(backHalf) + return true +} + +// searchMidNode 求中间的节点 +func searchMidNode(head *ListNode) *ListNode { + fast, slow := head, head + for fast.Next != nil && fast.Next.Next != nil { + fast = fast.Next.Next + slow = slow.Next + } + return slow +} + +// reverse 反转链表 +func reverse(node *ListNode) *ListNode { + var pre *ListNode + for node != nil { + nxt := node.Next + node.Next = pre + pre = node + node = nxt + } + return pre +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode141\347\216\257\345\275\242\351\223\276\350\241\250.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode141\347\216\257\345\275\242\351\223\276\350\241\250.md" index 2992b60..8dba278 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode141\347\216\257\345\275\242\351\223\276\350\241\250.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode141\347\216\257\345\275\242\351\223\276\350\241\250.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### [141. 环形链表](https://leetcode-cn.com/problems/linked-list-cycle/) @@ -10,11 +10,11 @@ #### 题目描述 -> 给定一个链表,判断链表中是否有环。pos代表环的入口,若为-1,则代表无环 +> 给定一个链表,判断链表中是否有环。pos 代表环的入口,若为-1,则代表无环。 > -> 如果链表中存在环,则返回 true 。 否则,返回 false 。 +> 如果链表中存在环,则返回 true 。否则,返回 false 。 -示例1: +示例 1: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321131949755.png) @@ -28,21 +28,19 @@ ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321132015849.png) -好啦,做题思路已经有了,让我们一起看一下代码的执行过程吧。\ +好啦,做题思路已经有了,让我们一起看一下代码的执行过程吧。 **动画模拟** ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321115836276.gif) - - **题目代码** Java Code: + ```java public class Solution { public boolean hasCycle(ListNode head) { - ListNode fast = head; ListNode low = head; while (fast != null && fast.next != null) { @@ -57,22 +55,6 @@ public class Solution { } ``` -JS Code: -```javascript -var hasCycle = function(head) { - let fast = head; - let slow = head; - while (fast && fast.next) { - fast = fast.next.next; - slow = slow.next; - if (fast === slow) { - return true; - } - } - return false; -}; -``` - C++ Code: ```cpp @@ -80,11 +62,11 @@ class Solution { public: bool hasCycle(ListNode *head) { ListNode * fast = head; - ListNode * low = head; + ListNode * slow = head; while (fast != nullptr && fast->next != nullptr) { fast = fast->next->next; - low = low->next; - if (fast == low) { + slow = slow->next; + if (fast == slow) { return true; } } @@ -93,3 +75,69 @@ public: }; ``` +JS Code: + +```javascript +var hasCycle = function (head) { + let fast = head; + let slow = head; + while (fast && fast.next) { + fast = fast.next.next; + slow = slow.next; + if (fast === slow) { + return true; + } + } + return false; +}; +``` + +Python Code: + +```python +class Solution: + def hasCycle(self, head: ListNode) -> bool: + fast = head + slow = head + while fast and fast.next: + fast = fast.next.next + slow = slow.next + if fast == slow: + return True + return False +``` + +Swift Code: + +```swift +class Solution { + func hasCycle(_ head: ListNode?) -> Bool { + var fast = head, slow = head + while fast != nil && fast?.next != nil { + fast = fast?.next?.next + slow = slow?.next + if fast === slow { + return true + } + } + return false + } +} +``` + +Go Code: + +```go +func hasCycle(head *ListNode) bool { + if head == nil { return false } + s, f := head, head + for f != nil && f.Next != nil { + s = s.Next + f = f.Next.Next + if s == f { + return true + } + } + return false +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode142\347\216\257\345\275\242\351\223\276\350\241\2502.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode142\347\216\257\345\275\242\351\223\276\350\241\2502.md" index 29ed3da..b7d33f2 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode142\347\216\257\345\275\242\351\223\276\350\241\2502.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode142\347\216\257\345\275\242\351\223\276\350\241\2502.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [142. 环形链表 II](https://leetcode-cn.com/problems/linked-list-cycle-ii/) @@ -18,80 +18,117 @@ 我们可以这样假设,两个孩子在操场顺时针跑步,一个跑的快,一个跑的慢,跑的快的那个孩子总会追上跑的慢的孩子。 -环形链表: - -```java -public class Solution { - public boolean hasCycle(ListNode head) { - //特殊情况,无节点或只有一个节点的情况 - if(head == null || head.next == null){ - return false; - } - //设置快慢指针 - ListNode pro = head.next; - ListNode last = head; - //循环条件 - while( pro != null && pro.next!=null){ - pro=pro.next.next; - last=last.next; - //两指针相遇 - if(pro == last){ - return true; - } - } - //循环结束,指针没有相遇,说明没有环。相当于快指针遍历了一遍链表 - return false; - - } -} -``` +代码请参考[【动画模拟】leetcode 141 环形链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode141%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.md)。 判断链表是不是含有环很简单,但是我们想找到环的入口可能就没有那么容易了。(入口则为下图绿色节点) -然后我们返回的则为绿色节点的索引,则返回2。 +然后我们返回的则为绿色节点的索引,则返回 2。 ![image-20201027180921770](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201027180921770.21fh8pt3cuv4.png) - - ### HashSet -我们可以利用HashSet来做,之前的文章说过HashSet是一个不允许有重复元素的集合。所以我们通过HashSet来保存链表节点,对链表进行遍历,如果链表不存在环则每个节点都会被存入环中,但是当链表中存在环时,则会发重复存储链表节点的情况,所以当我们发现HashSet中含有某节点时说明该节点为环的入口,返回即可。 +我们可以利用 HashSet 来做,之前的文章说过 HashSet 是一个不允许有重复元素的集合。所以我们通过 HashSet 来保存链表节点,对链表进行遍历,如果链表不存在环则每个节点都会被存入环中,但是当链表中存在环时,则会发重复存储链表节点的情况,所以当我们发现 HashSet 中含有某节点时说明该节点为环的入口,返回即可。 -下图中,存储顺序为 0,1,2,3,4,5,6,**2 **因为2已经存在,则返回。 +下图中,存储顺序为 0,1,2,3,4,5,6,**2 **因为 2 已经存在,则返回。 ![image-20201027182649669](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201027182649669.2g8gq4ik6xs0.png) - +Java Code: ```java public class Solution { public ListNode detectCycle(ListNode head) { - if (head == null) { return head; } if (head.next == null) { return head.next; } - //创建新的HashSet,用于保存节点 + //创建新的HashSet,用于保存节点 HashSet hash = new HashSet(); //遍历链表 while (head != null) { - //判断哈希表中是否含有某节点,没有则保存,含有则返回该节点 + //判断哈希表中是否含有某节点,没有则保存,含有则返回该节点 if (hash.contains(head)) { return head; } //不含有,则进行保存,并移动指针 hash.add(head); head = head.next; - } + } return head; } } ``` +C++ Code: + +```cpp +class Solution { +public: + ListNode *detectCycle(ListNode *head) { + if (head == nullptr) return head; + if (head->next == nullptr) return head->next; + //创建新的HashSet,用于保存节点 + set hash; + //遍历链表 + while (head != nullptr) { + //判断哈希表中是否含有某节点,没有则保存,含有则返回该节点 + if (hash.count(head)) { + return head; + } + //不含有,则进行保存,并移动指针 + hash.insert(head); + head = head->next; + } + return head; + } +}; +``` + +JS Code: + +```javascript +var detectCycle = function (head) { + if (head === null) return head; + if (head.next === null) return head.next; + //创建新的HashSet,用于保存节点 + let hash = new Set(); + //遍历链表 + while (head !== null) { + //判断哈希表中是否含有某节点,没有则保存,含有则返回该节点 + if (hash.has(head)) { + return head; + } + //不含有,则进行保存,并移动指针 + hash.add(head); + head = head.next; + } + return head; +}; +``` +Python Code: + +```python +class Solution: + def detectCycle(self, head: ListNode) -> ListNode: + if head is None: + return head + if head.next is None: + return head.next + # 创建新的HashSet,用于保存节点 + hash = set() + while head is not None: + # 判断哈希表中是否含有某节点,没有则保存,含有则返回该节点 + if head in hash: + return head + # 不含有,则进行保存,并移动指针 + hash.add(head) + head = head.next + return head +``` ### 快慢指针 @@ -101,25 +138,25 @@ public class Solution { 上图黄色节点为快慢指针相遇的节点,此时 -快指针走的距离:**a+(b+c)n+b** +快指针走的距离:**a+(b+c)n+b**,n 代表圈数。 -很容易理解b+c为环的长度,a为直线距离,b为绕了n圈之后又走了一段距离才相遇,所以相遇时走的总路程为a+(b+c)n+b,合并同类项得a+(n+1)b+nc。 +很容易理解 b+c 为环的长度,a 为直线距离,b 为绕了 n 圈之后又走了一段距离才相遇,所以相遇时走的总路程为 a+(b+c)n+b,合并同类项得 a+(n+1)b+nc。 -慢指针走的距离:**a+(b+c)m+b**,m代表圈数。 +慢指针走的距离:**a+(b+c)m+b**,m 代表圈数。 -然后我们设快指针得速度是慢指针的2倍,含义为相同时间内,快指针走过的距离是慢指针的2倍。 +然后我们设快指针得速度是慢指针的 2 倍,含义为相同时间内,快指针走过的距离是慢指针的 2 倍。 -**a+(n+1)b+nc=2[a+(m+1)b+mc]**整理得**a+b=(n-2m)(b+c),**那么我们可以从这个等式上面发现什么呢?**b+c** +**a+(n+1)b+nc=2[a+(m+1)b+mc]**整理得**a+b=(n-2m)(b+c),**那么我们可以从这个等式上面发现什么呢? -为一圈的长度。也就是说a+b等于n-2m个环的长度。为了便于理解我们看一种特殊情况,当n-2m等于1,那么a+b=b+c整理得,a=c此时我们只需重新释放两个指针,一个从head释放,一个从相遇点释放,速度相同,因为a=c所以他俩必会在环入口处相遇,则求得入口节点索引。 +**b+c**为一圈的长度。也就是说 a+b 等于 n-2m 个环的长度。为了便于理解我们看一种特殊情况,当 n-2m 等于 1,那么 a+b=b+c 整理得,a=c。此时我们只需重新释放两个指针,一个从 head 释放,一个从相遇点释放,速度相同,因为 a=c 所以他俩必会在环入口处相遇,则求得入口节点索引。 算法流程: -1.设置快慢指针,快指针速度为慢指针的2倍 +1.设置快慢指针,快指针速度为慢指针的 2 倍。 -2.找出相遇点 +2.找出相遇点。 -3.在head处和相遇点同时释放相同速度且速度为1的指针,两指针必会在环入口处相遇 +3.在 head 处和相遇点同时释放相同速度且速度为 1 的指针,两指针必会在环入口处相遇。 ![环形链表2](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/环形链表2.elwu1pw2lw0.gif) @@ -132,25 +169,24 @@ public class Solution { public ListNode detectCycle(ListNode head) { //快慢指针 ListNode fast = head; - ListNode low = head; + ListNode slow = head; //设置循环条件 while (fast != null && fast.next != null) { fast = fast.next.next; - low = low.next; + slow = slow.next; //相遇 - if (fast == low) { + if (fast == slow) { //设置一个新的指针,从头节点出发,慢指针速度为1,所以可以使用慢指针从相遇点出发 - ListNode newnode = head; - while (newnode != low) { - low = low.next; - newnode = newnode.next; + ListNode newptr = head; + while (newptr != slow) { + slow = slow.next; + newptr = newptr.next; } //在环入口相遇 - return low; + return slow; } - } + } return null; - } } ``` @@ -163,26 +199,125 @@ public: ListNode *detectCycle(ListNode *head) { //快慢指针 ListNode * fast = head; - ListNode * low = head; + ListNode * slow = head; //设置循环条件 while (fast != nullptr && fast->next != nullptr) { fast = fast->next->next; - low = low->next; + slow = slow->next; //相遇 - if (fast == low) { + if (fast == slow) { //设置一个新的指针,从头节点出发,慢指针速度为1,所以可以使用慢指针从相遇点出发 ListNode * newnode = head; - while (newnode != low) { - low = low->next; + while (newnode != slow) { + slow = slow->next; newnode = newnode->next; } //在环入口相遇 - return low; + return slow; } - } + } return nullptr; - } }; ``` +JS Code: + +```js +var detectCycle = function (head) { + //快慢指针 + let fast = head; + let slow = head; + //设置循环条件 + while (fast && fast.next) { + fast = fast.next.next; + slow = slow.next; + //相遇 + if (fast == slow) { + let newptr = head; + //设置一个新的指针,从头节点出发,慢指针速度为1,所以可以使用慢指针从相遇点出发 + while (newptr != slow) { + slow = slow.next; + newptr = newptr.next; + } + //在环入口相遇 + return slow; + } + } + return null; +}; +``` + +Python Code: + +```python +class Solution: + def detectCycle(self, head: ListNode) -> ListNode: + # 快慢指针 + fast = head + slow = head + # 设置循环条件 + while fast is not None and fast.next is not None: + fast = fast.next.next + slow = slow.next + # 相遇 + if fast is slow: + # 设置一个新的指针,从头节点出发,慢指针速度为1,所以可以使用慢指针从相遇点出发 + newptr = head + while newptr is not slow: + slow = slow.next + newptr = newptr.next + # 在环入口相遇 + return slow +``` + +Swift Code: + +```swift +class Solution { + func detectCycle(_ head: ListNode?) -> ListNode? { + // 快慢指针 + var fast = head, slow = head + while fast != nil && fast?.next != nil { + fast = fast?.next?.next + slow = slow?.next + // 相遇 + if fast === slow { + // 设置一个新的指针,从头节点出发,慢指针速度为1,所以可以使用慢指针从相遇点出发 + // 此处也可以不创新结点,直接将 fast = head + var newNode = head + while newNode !== slow { + slow = slow?.next + newNode = newNode?.next + } + return slow + } + } + return nil + } +} +``` + +Go Code: + +```go +func detectCycle(head *ListNode) *ListNode { + if head == nil { return nil } + s, f := head, head + for f != nil && f.Next != nil { + s = s.Next + f = f.Next.Next + // 快慢指针相遇 + if f == s { + // 快指针从头开始一步一步走,也可以用一个新的指针 + f = head + for f != s { + f = f.Next + s = s.Next + } + return f + } + } + return nil +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode147\345\257\271\351\223\276\350\241\250\350\277\233\350\241\214\346\217\222\345\205\245\346\216\222\345\272\217.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode147\345\257\271\351\223\276\350\241\250\350\277\233\350\241\214\346\217\222\345\205\245\346\216\222\345\272\217.md" index a21f825..84c4587 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode147\345\257\271\351\223\276\350\241\250\350\277\233\350\241\214\346\217\222\345\205\245\346\216\222\345\272\217.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode147\345\257\271\351\223\276\350\241\250\350\277\233\350\241\214\346\217\222\345\205\245\346\216\222\345\272\217.md" @@ -1,14 +1,14 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -有的老哥说链表的排序搞不明白,让我写一下,一不小心给忘记了,今天咱们就安排上。没有学过数据结构的同学可以先看下这个文章 +有的老哥说链表的排序搞不明白,让我写一下,一不小心给忘记了,今天咱们就安排上。没有学过数据结构的同学可以先看下这个文章: [【绘图解析】链表详解](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%85%B3%E4%BA%8E%E9%93%BE%E8%A1%A8%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B.md) -另外大家如果忘记了[【动画模拟】插入排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E7%9B%B4%E6%8E%A5%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F.md)和[【动画模拟】归并排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F.md)思想的话,可以先复习一下,不然这两道题目会看的云里雾里。 +另外大家如果忘记了[【动画模拟】插入排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E7%9B%B4%E6%8E%A5%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F.md)和[【动画模拟】归并排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F.md)思想的话,可以先复习一下,不然这两道题目会看得云里雾里。 #### [147. 对链表进行插入排序](https://leetcode-cn.com/problems/insertion-sort-list/) @@ -26,19 +26,15 @@ ![直接插入排序](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/直接插入排序.2marc4epuzy0.gif) - - 我们的指针在数组时,可以随意的前后移动,将指针指向值和新元素的值比较后,将新元素插入到合适的位置。 -我们知道链表查询元素的时间复杂度为 O(n),我们只能够通过遍历链表查询元素。 - -那么我们怎么才能将新元素放到合适的位置呢? +我们知道链表查询元素的时间复杂度为 O(n),我们只能够通过遍历链表查询元素。 -**见下图** +那么我们怎么才能将新元素放到合适的位置呢?见下图。 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210325113449.75knzw7zmyg0.png) -此时我们不能通过移动绿色指针来寻找 5 的合适位置,那么我们应该怎么做呢?见下图 +此时我们不能通过移动绿色指针来寻找 5 的合适位置,那么我们应该怎么做呢?见下图。 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210325131349.14mi2ap89uxs.png) @@ -48,29 +44,25 @@ ```java while (temphead.next.val <= pre.val) { - temphead = temphead.next; - } + temphead = temphead.next; + } ``` 下面我们再来看动画模拟具体过程。 -**注:为了更好的表达算法思想,让过程更流畅,特省略了指针的移动细节,直接插入到合适位置,后面会详细说明插入操作的具体步骤** +**注:为了更好的表达算法思想,让过程更流畅,特省略了指针的移动细节,直接插入到合适位置,后面会详细说明插入操作的具体步骤。** ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/链表的插入排序.4hnc4shp5le0.gif) 我们通过上面的动画知道了大致过程,那么我们的是如何将新元素插入到指定位置的呢? -见下图 - - +见下图。 ![插入排序](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210325132359.1hc2axzks3k0.png) +我们想要将 3 插入到 2 和 4 的中间,此时我们三个指针分别指向 2,4,3。 - -我们想要将 3 插入到 2 和 4 的中间,此时我们三个指针分别指向 2,4,3 - -我们共分 4 步,来完成这个操作,见下图 +我们共分 4 步,来完成这个操作,见下图。 ![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/44444444.29mvcvs4yrms.png) @@ -87,7 +79,6 @@ Java Code: ```java class Solution { public ListNode insertionSortList(ListNode head) { - if (head == null && head.next == null) { return head; } @@ -98,32 +89,31 @@ class Solution { //判断是否需要执行插入操作 ListNode pre = head.next; ListNode last = head; - ListNode temphead = dummyNode; while (pre != null) { //不需要插入到合适位置,则继续往下移动 if (last.val <= pre.val) { pre = pre.next; last = last.next; continue; - } + } //开始出发,查找新元素的合适位置 - temphead = dummyNode; + ListNode temphead = dummyNode; while (temphead.next.val <= pre.val) { temphead = temphead.next; - } + } //此时我们已经找到了合适位置,我们需要进行插入,大家可以画一画 last.next = pre.next; pre.next = temphead.next; temphead.next = pre; + //继续往下移动 pre = last.next; } return dummyNode.next; - } } ``` - C++ Code: +C++ Code: ```cpp class Solution { @@ -139,23 +129,23 @@ public: //判断是否需要执行插入操作 ListNode * pre = head->next; ListNode * last = head; - ListNode * temphead = dummyNode; while (pre != nullptr) { //不需要插入到合适位置,则继续往下移动 if (last->val <= pre->val) { pre = pre->next; last = last->next; continue; - } + } //开始出发,查找新元素的合适位置 - temphead = dummyNode; + ListNode * temphead = dummyNode; while (temphead->next->val <= pre->val) { temphead = temphead->next; - } + } //此时我们已经找到了合适位置,我们需要进行插入,大家可以画一画 last->next = pre->next; pre->next = temphead->next; temphead->next = pre; + //继续往下移动 pre = last->next; } return dummyNode->next; @@ -163,5 +153,138 @@ public: }; ``` +JS Code: + +```javascript +var insertionSortList = function (head) { + if (head === null || head.next === null) return head; + //哑节点 + let dummyNode = new ListNode(-1, head); + let pre = head.next; + //pre负责指向新元素,last 负责指向新元素的前一元素 + //判断是否需要执行插入操作 + let last = head; + while (pre) { + //不需要插入到合适位置,则继续往下移动 + if (last.val <= pre.val) { + last = last.next; + pre = pre.next; + continue; + } + //开始出发,查找新元素的合适位置 + let tempHead = dummyNode; + while (tempHead.next.val <= pre.val) { + tempHead = tempHead.next; + } + //此时我们已经找到了合适位置,我们需要进行插入,大家可以画一画 + last.next = pre.next; + pre.next = tempHead.next; + tempHead.next = pre; + //继续往下移动 + pre = last.next; + } + return dummyNode.next; +}; +``` +Python Code: + +```python +class Solution: + def insertionSortList(self, head: ListNode) -> ListNode: + if head is None or head.next is None: + return head + # 哑节点 + dummyNode = ListNode(-1, head) + # pre负责指向新元素,last 负责指向新元素的前一元素 + # 判断是否需要执行插入操作 + pre = head.next + last = head + while pre is not None: + # 不需要插入到合适位置,则继续往下移动 + if last.val <= pre.val: + pre = pre.next + last = last.next + continue + # 开始出发,查找新元素的合适位置 + temphead = dummyNode + while temphead.next.val <= pre.val: + temphead = temphead.next + # 此时我们已经找到了合适位置,我们需要进行插入,大家可以画一画 + last.next = pre.next + pre.next = temphead.next + temphead.next = pre + # 继续往下移动 + pre = last.next + return dummyNode.next +``` +Swift Code: + +```swift +class Solution { + func insertionSortList(_ head: ListNode?) -> ListNode? { + if head == nil && head?.next == nil { + return head + } + //哑节点 + var dummyNode = ListNode(-1) + dummyNode.next = head + //pre负责指向新元素,last 负责指向新元素的前一元素 + //判断是否需要执行插入操作 + var pre = head?.next + var last = head + while pre != nil { + //不需要插入到合适位置,则继续往下移动 + if last!.val <= pre!.val { + pre = pre?.next + last = last?.next + continue + } + //开始出发,查找新元素的合适位置 + var temphead = dummyNode + while temphead.next!.val <= pre!.val { + temphead = temphead.next! + } + //此时我们已经找到了合适位置,我们需要进行插入,大家可以画一画 + last?.next = pre?.next + pre?.next = temphead.next + temphead.next = pre + //继续往下移动 + pre = last?.next + } + return dummyNode.next + } +} +``` + +Go Code: + +```go +func insertionSortList(head *ListNode) *ListNode { + if head == nil || head.Next == nil { return head } + root := &ListNode{ + Next: head, + } + cur, nxt := head, head.Next + for nxt != nil { + // 有序的不需要换位置 + if cur.Val <= nxt.Val { + cur = cur.Next + nxt = nxt.Next + continue + } + temp := root + for temp.Next.Val <= nxt.Val { + temp = temp.Next + } + // 此时找到合适的位置 + cur.Next = nxt.Next + nxt.Next = temp.Next + temp.Next = nxt + // 继续向下 + nxt = cur.Next + } + return root.Next +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode206\345\217\215\350\275\254\351\223\276\350\241\250.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode206\345\217\215\350\275\254\351\223\276\350\241\250.md" index 3811f23..6690adc 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode206\345\217\215\350\275\254\351\223\276\350\241\250.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode206\345\217\215\350\275\254\351\223\276\350\241\250.md" @@ -1,6 +1,12 @@ +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> +> 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 +> +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 + 今天咱们说一道非常简单但是很经典的面试题,思路很容易,但是里面细节挺多,所以我们还是需要注意。 -我们先来看一下题目描述 +我们先来看一下题目描述。 #### [206. 反转链表](https://leetcode-cn.com/problems/reverse-linked-list/) @@ -19,37 +25,29 @@ 原理很容易理解,我们首先将 low 指针指向空节点, pro 节点指向 head 节点, -然后我们定义一个临时节点指向 pro 节点, +然后我们定义一个临时节点 temp 指向 pro 节点, -此时我们就记住了 pro 节点的位置,然后 pro = pro.next.这样我们三个指针指向三个不同的节点。 +此时我们就记住了 pro 节点的位置,然后 pro = pro.next,这样我们三个指针指向三个不同的节点。 则我们将 temp 指针指向 low 节点,此时则完成了反转。 -反转之后我们继续反转下一节点,则 - -low = temp 即可。然后重复执行上诉操作直至最后,这样则完成了反转链表。 +反转之后我们继续反转下一节点,则 low = temp 即可。然后重复执行上诉操作直至最后,这样则完成了反转链表。 -我们下面看代码吧 +我们下面看代码吧。 我会对每个关键点进行注释,大家可以参考动图理解。 - - **题目代码** Java Code: + ```java class Solution { public ListNode reverseList(ListNode head) { - //特殊情况 + //特殊情况 if (head == null || head.next == null) { return head; } - //反转 - return reverse(head); - } - public ListNode reverse (ListNode head) { - ListNode low = null; ListNode pro = head; while (pro != null) { @@ -61,45 +59,22 @@ class Solution { temp.next = low; //移动黄色指针 low = temp; - } + } return low; } - } ``` -JS Code: -```javascript -var reverseList = function(head) { - if(!head || !head.next) { - return head; - } - let low = null; - let pro = head; - while (pro) { - let temp = pro; - pro = pro.next; - temp.next = low; - low = temp; - } - return low; -}; -``` -C++代码 +C++ Code: ```cpp class Solution { public: ListNode* reverseList(ListNode* head) { - //特殊情况 + //特殊情况 if (head == nullptr || head->next == nullptr) { return head; } - //反转 - return reverse(head); - } - ListNode * reverse (ListNode * head) { - ListNode * low = nullptr; ListNode * pro = head; while (pro != nullptr) { @@ -111,19 +86,111 @@ public: temp->next = low; //移动黄色指针 low = temp; - } + } return low; } }; ``` -上面的迭代写法是不是搞懂啦,现在还有一种递归写法,不是特别容易理解,刚开始刷题的同学,可以只看迭代解法。 +JS Code: + +```javascript +var reverseList = function (head) { + //特殊情况 + if (!head || !head.next) { + return head; + } + let low = null; + let pro = head; + while (pro) { + //代表橙色指针 + let temp = pro; + //移动绿色指针 + pro = pro.next; + //反转节点 + temp.next = low; + //移动黄色指针 + low = temp; + } + return low; +}; +``` + +Python Code: + +```python +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + # 特殊情况 + if head is None or head.next is None: + return head + low = None + pro = head + while pro is not None: + # 代表橙色指针 + temp = pro + # 移动绿色指针 + pro = pro.next + # 反转节点 + temp.next = low + # 移动黄色指针 + low = temp + return low +``` + +Swift Code: + +```swift +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + // 边界条件 + if head == nil || head?.next == nil { + return head + } + var pro = head + var low: ListNode? + while pro != nil { + // 代表橙色指针 + var temp = pro + // 移动绿色指针 + pro = pro?.next + // 反转节点 + temp?.next = low + // 移动黄色指针 + low = temp + } + return low + } +} +``` +Go Code: + +```go +func reverseList(head *ListNode) *ListNode { + if head == nil || head.Next == nil { return head } + cur := head + var pre *ListNode + for cur != nil { + nxt := cur.Next + cur.Next = pre + pre = cur + cur = nxt + if nxt == nil { + return pre + } + nxt = nxt.Next + } + return pre +} +``` +上面的迭代写法是不是搞懂啦,现在还有一种递归写法,不是特别容易理解,刚开始刷题的同学,可以只看迭代解法。 **题目代码** Java Code: + ```java class Solution { public ListNode reverseList(ListNode head) { @@ -133,8 +200,8 @@ class Solution { } //保存最后一个节点 ListNode pro = reverseList(head.next); - //将节点进行反转。我们可以这样理解 4.next.next = 4; - //4.next = 5; + //将节点进行反转。我们可以这样理解 4.next.next = 4 + //4.next = 5 //则 5.next = 4 则实现了反转 head.next.next = head; //防止循环 @@ -142,23 +209,9 @@ class Solution { return pro; } } - -``` - -JS Code: -```javascript -var reverseList = function(head) { - if (!head || !head.next) { - return head; - } - let pro = reverseList(head.next); - head.next.next = head; - head.next = null; - return pro; -}; ``` -C++代码: +C++ Code: ```cpp class Solution { @@ -170,8 +223,8 @@ public: } //保存最后一个节点 ListNode * pro = reverseList(head->next); - //将节点进行反转。我们可以这样理解 4->next->next = 4; - //4->next = 5; + //将节点进行反转。我们可以这样理解 4->next->next = 4 + //4->next = 5 //则 5->next = 4 则实现了反转 head->next->next = head; //防止循环 @@ -181,3 +234,79 @@ public: }; ``` +JS Code: + +```javascript +var reverseList = function (head) { + //结束条件 + if (!head || !head.next) { + return head; + } + //保存最后一个节点 + let pro = reverseList(head.next); + //将节点进行反转。我们可以这样理解 4.next.next = 4 + //4.next = 5 + //则 5.next = 4 则实现了反转 + head.next.next = head; + //防止循环 + head.next = null; + return pro; +}; +``` + +Python Code: + +```python +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + # 结束条件 + if head is None or head.next is None: + return head + # 保存最后一个节点 + pro = self.reverseList(head.next) + # 将节点进行反转。我们可以这样理解 4->next->next = 4 + # 4->next = 5 + # 则 5->next = 4 则实现了反转 + head.next.next = head + # 防止循环 + head.next = None + return pro +``` + +Swift Code: + +```swift +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + // 结束条件 + if head == nil || head?.next == nil { + return head + } + var pro = reverseList(head?.next) + // 将节点进行反转 + head?.next?.next = head + // 防止循环 + head?.next = nil + return pro + } +} +``` + +
+ +> 贡献者[@jaredliw](https://github.com/jaredliw)注: +> +> 这里提供一个比较直观的递归写法供大家参考。由于代码比较直白,其它语言的我就不写啦。 +> +> ```python +> class Solution: +> def reverseList(self, head: ListNode, prev_nd: ListNode = None) -> ListNode: +> # 结束条件 +> if head is None: +> return prev_nd +> # 记录下一个节点并反转 +> next_nd = head.next +> head.next = prev_nd +> # 给定下一组该反转的节点 +> return self.reverseList(next_nd, head) +> ``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode328\345\245\207\345\201\266\351\223\276\350\241\250.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode328\345\245\207\345\201\266\351\223\276\350\241\250.md" index 83f4cd9..de19c55 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode328\345\245\207\345\201\266\351\223\276\350\241\250.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode328\345\245\207\345\201\266\351\223\276\350\241\250.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 ### [328. 奇偶链表](https://leetcode-cn.com/problems/odd-even-linked-list/) @@ -21,12 +21,12 @@ 示例 2: -> 输入: 2->1->3->5->6->4->7->NULL +> 输入: 2->1->3->5->6->4->7->NULL > 输出: 2->3->6->7->1->5->4->NULL #### 题目解析 -题目也很容易理解就是让我们将原来奇数位的结点放一起,偶数位的结点放一起。这里需要注意,和结点值无关,是奇数位和偶数位结点。 +题目也很容易理解就是让我们将原来奇数位的结点放一起,偶数位的结点放一起。这里需要注意,题目和结点值无关,是奇数位和偶数位结点。 我们可以先将奇数位和在一起,再将偶数位和在一起,最后再将两个链表合并很简单,我们直接看动画模拟吧。 @@ -46,7 +46,7 @@ class Solution { } ListNode odd = head; ListNode even = head.next; - ListNode evenhead = even; + ListNode evenHead = even; while (odd.next != null && even.next != null) { //将偶数位合在一起,奇数位合在一起 @@ -54,9 +54,9 @@ class Solution { odd = odd.next; even.next = odd.next; even = even.next; - } + } //链接 - odd.next = evenhead; + odd.next = evenHead; return head; } } @@ -73,7 +73,7 @@ public: } ListNode * odd = head; ListNode * even = head->next; - ListNode * evenhead = even; + ListNode * evenHead = even; while (odd->next != nullptr && even->next != nullptr) { //将偶数位合在一起,奇数位合在一起 @@ -81,27 +81,97 @@ public: odd = odd->next; even->next = odd->next; even = even->next; - } + } //链接 - odd->next = evenhead; + odd->next = evenHead; return head; } }; ``` JS Code: + ```javascript -var oddEvenList = function(head) { - if(!head || !head.next) return head; - let odd = head, even = head.next, evenHead = even; - while(odd.next && even.next){ - odd.next = even.next; - odd = odd.next; - even.next = odd.next; - even = even.next; - } - odd.next = evenHead; - return head; +var oddEvenList = function (head) { + if (!head || !head.next) return head; + let odd = head, + even = head.next, + evenHead = even; + while (odd.next && even.next) { + //将偶数位合在一起,奇数位合在一起 + odd.next = even.next; + odd = odd.next; + even.next = odd.next; + even = even.next; + } + //链接 + odd.next = evenHead; + return head; }; ``` +Python Code: + +```python +class Solution: + def oddEvenList(self, head: ListNode) -> ListNode: + if head is None or head.next is None: + return head + odd = head + even = head.next + evenHead = even + while odd.next is not None and even.next is not None: + # 将偶数位合在一起,奇数位合在一起 + odd.next = even.next + odd = odd.next + even.next = odd.next + even = even.next + # 链接 + odd.next = evenHead + return head +``` + +Swift Code: + +```swift +class Solution { + func oddEvenList(_ head: ListNode?) -> ListNode? { + if head == nil || head?.next == nil { + return head + } + var odd = head + var even = head?.next + var evenHead = even + while odd?.next != nil && even?.next != nil { + //将偶数位合在一起,奇数位合在一起 + odd?.next = even?.next + odd = odd?.next + even?.next = odd?.next + even = even?.next + } + //链接 + odd?.next = evenHead + return head + } +} +``` + +Go Code: + +```go +func oddEvenList(head *ListNode) *ListNode { + if head == nil || head.Next == nil { + return head + } + odd, even := head, head.Next + evenHead := even + for odd.Next != nil && even.Next != nil { + odd.Next = even.Next + odd = odd.Next + even.Next = odd.Next + even = even.Next + } + odd.Next = evenHead + return head +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode82\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode82\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.md" index 983b3db..71f47a2 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode82\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode82\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.md" @@ -1,12 +1,12 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [82. 删除排序链表中的重复元素 II](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/) -题目描述 +**题目描述** 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字。 @@ -17,7 +17,6 @@ 输出: 1->2->5 ``` - 示例 2: ```java @@ -25,7 +24,7 @@ 输出: 2->3 ``` -> 注意这里会将重复的值全部删除,1,1,2,3最后只会保留2,3。 +> 注意这里会将重复的值全部删除,1,1,2,3 最后只会保留 2,3。 这道题目还是很简单的,更多的是考察大家的代码完整性,删除节点也是题库中的一类题目,我们可以可以通过这个题目举一反三。去完成其他删除阶段的题目。 @@ -35,7 +34,7 @@ 这个题目也是利用我们的双指针思想,一个走在前面,一个在后面紧跟,前面的指针就好比是侦察兵,当发现重复节点时,后面指针停止移动,侦察兵继续移动,直到移动完重复节点,然后将该节点赋值给后节点。思路是不是很简单啊,那么我们来看一下动图模拟吧。 -注:这里为了表达更直观,所以仅显示了该链表中存在的节点 +注:这里为了表达更直观,所以仅显示了该链表中存在的节点。 ![删除重复节点2](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/删除重复节点2.3btmii5cgxa0.gif) @@ -46,28 +45,30 @@ Java Code: ```java class Solution { public ListNode deleteDuplicates(ListNode head) { - if(head == null||head.next==null){ - return head; - } + //侦察兵指针 ListNode pre = head; - ListNode low = new ListNode(0); - low.next = pre; - ListNode ret = new ListNode(-1); - ret = low; + //创建哑节点,接上head + ListNode dummy = new ListNode(-1); + dummy.next = head; + //跟随的指针 + ListNode low = dummy; while(pre != null && pre.next != null) { if (pre.val == pre.next.val) { + //移动侦察兵指针直到找到与上一个不相同的元素 while (pre != null && pre.next != null && pre.val == pre.next.val) { pre = pre.next; } + //while循环后,pre停留在最后一个重复的节点上 pre = pre.next; - low.next = pre; + //连上新节点 + low.next = pre; } else{ pre = pre.next; low = low.next; } } - return ret.next; + return dummy.next;//注意,这里传回的不是head,而是虚拟节点的下一个节点,head有可能已经换了 } } ``` @@ -78,29 +79,145 @@ C++ Code: class Solution { public: ListNode* deleteDuplicates(ListNode* head) { - if(head == nullptr || head->next == nullptr){ - return head; - } + //侦察兵指针 ListNode * pre = head; - ListNode * low = new ListNode(0); - low->next = pre; - ListNode * ret = new ListNode(-1); - ret = low; + //创建哑节点,接上head + ListNode * dummy = new ListNode(-1); + dummy->next = head; + //跟随的指针 + ListNode * low = dummy; while(pre != nullptr && pre->next != nullptr) { if (pre->val == pre->next->val) { + //移动侦察兵指针直到找到与上一个不相同的元素 while (pre != nullptr && pre->next != nullptr && pre->val == pre->next->val) { pre = pre->next; } + //while循环后,pre停留在最后一个重复的节点上 pre = pre->next; - low->next = pre; + //连上新节点 + low->next = pre; } else{ pre = pre->next; low = low->next; } } - return ret->next; + return dummy->next;//注意,这里传回的不是head,而是虚拟节点的下一个节点,head有可能已经换了 + } +}; +``` + +JS Code: + +```javascript +var deleteDuplicates = function (head) { + //侦察兵指针 + let pre = head; + //创建虚拟头节点,接上head + let dummy = new ListNode(-1); + dummy.next = pre; + //跟随的指针 + let low = dummy; + while (pre != null && pre.next != null) { + if (pre.val == pre.next.val) { + //移动侦察兵指针直到找到与上一个不相同的元素 + while (pre != null && pre.next != null && pre.val === pre.next.val) { + pre = pre.next; + } + //while循环后,pre停留在最后一个重复的节点上 + pre = pre.next; + //连上新节点 + low.next = pre; + } else { + pre = pre.next; + low = low.next; } + } + return dummy.next; //注意,这里传回的不是head,而是虚拟节点的下一个节点,head有可能已经换了 }; ``` +Python Code: + +```python +class Solution: + def deleteDuplicates(self, head: ListNode) -> ListNode: + # 侦察兵指针 + pre = head + # 创建虚拟头节点,接上head + dummy = ListNode(-1, head) + # 跟随的指针 + low = dummy + while pre is not None and pre.next is not None: + if pre.val == pre.next.val: + # 移动侦察兵指针直到找到与上一个不相同的元素 + while pre is not None and pre.next is not None and pre.val == pre.next.val: + pre = pre.next + # while循环后,pre停留在最后一个重复的节点上 + pre = pre.next + # 连上新节点 + low.next = pre + else: + pre = pre.next + low = low.next + return dummy.next # 注意,这里传回的不是head,而是虚拟节点的下一个节点,head有可能已经换了 +``` + +Swift Code: + +```swift +class Solution { + func deleteDuplicates(_ head: ListNode?) -> ListNode? { + // 侦察兵指针 + var pre = head + // 创建哑节点,接上head + var dummy = ListNode(-1) + dummy.next = head + // 跟随的指针 + var low:ListNode? = dummy + while pre != nil && pre?.next != nil { + if pre?.val == pre?.next?.val { + // 移动侦察兵指针直到找到与上一个不相同的元素 + while pre != nil && pre?.next != nil && pre?.val == pre?.next?.val { + pre = pre?.next + } + // while循环后,pre停留在最后一个重复的节点上 + pre = pre?.next + // 连上新节点 + low?.next = pre + } else { + pre = pre?.next + low = low?.next + } + } + return dummy.next // 注意,这里传回的不是head,而是虚拟节点的下一个节点,head有可能已经换了 + } +} +``` + +Go Code: + +```go +func deleteDuplicates(head *ListNode) *ListNode { + // 新建一个头结点,他的下一个节点才是开始 + root := &ListNode{ + Next: head, + } + pre, cur := root, head + for cur != nil && cur.Next != nil { + if cur.Val == cur.Next.Val { + // 相等的话,cur就一直向后移动 + for cur != nil && cur.Next != nil && cur.Val == cur.Next.Val { + cur = cur.Next + } + // 循环后移动到了最后一个相同的节点。 + cur = cur.Next + pre.Next = cur + } else { + cur = cur.Next + pre = pre.Next + } + } + return root.Next +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode86\345\210\206\351\232\224\351\223\276\350\241\250.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode86\345\210\206\351\232\224\351\223\276\350\241\250.md" index 6412931..5a2b98d 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode86\345\210\206\351\232\224\351\223\276\350\241\250.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode86\345\210\206\351\232\224\351\223\276\350\241\250.md" @@ -1,8 +1,8 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [86. 分隔链表](https://leetcode-cn.com/problems/partition-list/) @@ -10,11 +10,10 @@ 你应当 保留 两个分区中每个节点的初始相对位置。 -![](https://img-blog.csdnimg.cn/20210319190335143.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) +![](https://img-blog.csdnimg.cn/20210319190335143.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzODg1OTI0,size_16,color_FFFFFF,t_70) 示例 1: - 输入:head = [1,4,3,2,5,2], x = 3 输出:[1,2,2,4,3,5] 示例 2: @@ -24,7 +23,7 @@ 来源:力扣(LeetCode) -这个题目我的做题思路是这样的,我们先创建一个侦察兵,侦察兵负责比较链表值和 x 值,如果 >= 的话则接在 big 链表上,小于则接到 small 链表上,最后一个细节就是我们的 big 链表尾部要加上 null,不然会形成环。这是这个题目的一个小细节,很重要。 +这个题目我的做题思路是这样的,我们先创建一个侦察兵,侦察兵负责比较链表值和 x 值,如果 >= 的话则接在 big 链表上,小于则接到 small 链表上,最后一个细节就是我们的 big 链表尾部要加上 null,不然会形成环。这是这个题目的一个小细节,很重要。 中心思想就是,将链表先分后合。 @@ -37,31 +36,20 @@ Java Code: ```java -/** - * Definition for singly-linked list. - * public class ListNode { - * int val; - * ListNode next; - * ListNode(int x) { val = x; } - * } - */ class Solution { public ListNode partition(ListNode head, int x) { - if (head == null) { - return head; - } ListNode pro = head; ListNode big = new ListNode(-1); - ListNode small = new ListNode(-1); - ListNode headbig = big; - ListNode headsmall =small; - //分 - while (pro != null) { + ListNode small = new ListNode(-1); + ListNode headbig = big; + ListNode headsmall = small; + //分 + while (pro != null) { //大于时,放到 big 链表上 if (pro.val >= x) { big.next = pro; big = big.next; - // 小于放到 small 链表上 + //小于时,放到 small 链表上 }else { small.next = pro; small = small.next; @@ -83,21 +71,18 @@ C++ Code: class Solution { public: ListNode* partition(ListNode* head, int x) { - if (head == nullptr) { - return head; - } ListNode * pro = head; ListNode * big = new ListNode(-1); - ListNode * small = new ListNode(-1); - ListNode * headbig = big; - ListNode * headsmall =small; - //分 - while (pro != nullptr) { + ListNode * small = new ListNode(-1); + ListNode * headbig = big; + ListNode * headsmall = small; + //分 + while (pro != nullptr) { //大于时,放到 big 链表上 if (pro->val >= x) { big->next = pro; big = big->next; - // 小于放到 small 链表上 + //小于时,放到 small 链表上 }else { small->next = pro; small = small->next; @@ -113,5 +98,118 @@ public: }; ``` +JS Code: + +```js +var partition = function (head, x) { + let pro = head; + let big = new ListNode(-1); + let small = new ListNode(-1); + let headbig = big; + let headsmall = small; + //分 + while (pro) { + //大于时,放到 big 链表上 + if (pro.val >= x) { + big.next = pro; + big = big.next; + //小于时,放到 small 链表上 + } else { + small.next = pro; + small = small.next; + } + pro = pro.next; + } + //细节 + big.next = null; + //合 + small.next = headbig.next; + return headsmall.next; +}; +``` +Python Code: + +```python +class Solution: + def partition(self, head: ListNode, x: int) -> ListNode: + pro = head + big = ListNode(-1) + small = ListNode(-1) + headbig = big + headsmall = small + # 分 + while pro is not None: + # 大于时,放到 big 链表上 + if pro.val >= x: + big.next = pro + big = big.next + # 小于时,放到 small 链表上 + else: + small.next = pro + small = small.next + pro = pro.next + # 细节 + big.next = None + # 合 + small.next = headbig.next + return headsmall.next +``` + +Swift Code: + +```swift +class Solution { + func partition(_ head: ListNode?, _ x: Int) -> ListNode? { + var pro = head + var big = ListNode(-1) + var small = ListNode(-1) + var headbig = big + var headsmall = small + //分 + while pro != nil { + //大于时,放到 big 链表上 + if pro!.val >= x { + big.next = pro + big = big.next! + //小于时,放到 small 链表上 + } else { + small.next = pro + small = small.next! + } + pro = pro?.next + } + //细节 + big.next = nil + //合 + small.next = headbig.next + return headsmall.next + } +} +``` +Go Code: + +```go +func partition(head *ListNode, x int) *ListNode { + big, small := &ListNode{}, &ListNode{} + headBig, headSmall := big, small + temp := head + for temp != nil { + // 分开存 + if temp.Val < x { + small.Next = temp + small = small.Next + } else { + big.Next = temp + big = big.Next + } + temp = temp.Next + } + // 最后一个节点指向nil + big.Next = nil + // 存小数的链表和存大数的连起来 + small.Next = headBig.Next + return headSmall.Next +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode92\345\217\215\350\275\254\351\223\276\350\241\2502.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode92\345\217\215\350\275\254\351\223\276\350\241\2502.md" index 13b3af2..3776fe3 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode92\345\217\215\350\275\254\351\223\276\350\241\2502.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode92\345\217\215\350\275\254\351\223\276\350\241\2502.md" @@ -1,17 +1,15 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -今天我们来说一下反转链表 2,其实这个和 1 的思路差不多,今天先说一个比较好理解的方法,完全按照反转链表 1 的方法来解决,大家看这个题目之前要先看一下[【动画模拟】leetcode 206 反转链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode206%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8.md) +今天我们来说一下反转链表 2,其实这个和 1 的思路差不多,今天先说一个比较好理解的方法,完全按照反转链表 1 的方法来解决,大家看这个题目之前要先看一下[【动画模拟】leetcode 206 反转链表](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E9%93%BE%E8%A1%A8%E7%AF%87/leetcode206%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8.md)。 下面我们先来看一下题目。 #### [92. 反转链表 II](https://leetcode-cn.com/problems/reverse-linked-list-ii/) -难度中等836 - 给你单链表的头指针 `head` 和两个整数 `left` 和 `right` ,其中 `left <= right` 。请你反转从位置 `left` 到位置 `right` 的链表节点,返回 **反转后的链表** 。 **示例 1:** @@ -34,8 +32,6 @@ 是不是很容易理解,下面我们来看代码吧。 - - **题目代码** Java Code: @@ -43,7 +39,6 @@ Java Code: ```java class Solution { public ListNode reverseBetween(ListNode head, int left, int right) { - //虚拟头节点 ListNode temp = new ListNode(-1); temp.next = head; @@ -53,33 +48,35 @@ class Solution { for (; i < left-1; ++i) { pro = pro.next; } - // 保存 left 节点前的第一个节点 + //保存 left 节点前的一个节点 ListNode leftNode = pro; + //来到 right 节点 for (; i < right; ++i) { pro = pro.next; } - // 保存 right 节点后的节点 + //保存 right 节点后的一个节点 ListNode rightNode = pro.next; //切断链表 - pro.next = null; - ListNode newhead = leftNode.next; - leftNode.next = null; - leftNode.next = rever(newhead); + pro.next = null;//切断 right 后的部分 + ListNode newhead = leftNode.next;//保存 left 节点 + leftNode.next = null;//切断 left 前的部分 + //反转 + leftNode.next = reverse(newhead); //重新接头 newhead.next = rightNode; return temp.next; } //和反转链表1代码一致 - public ListNode rever (ListNode head) { - ListNode low = null; + public ListNode reverse (ListNode head) { + ListNode low = null; ListNode pro = head; while (pro != null) { ListNode temp = pro; pro = pro.next; temp.next = low; low = temp; - } + } return low; } } @@ -91,6 +88,7 @@ C++ Code: class Solution { public: ListNode* reverseBetween(ListNode* head, int left, int right) { + //虚拟头节点 ListNode * temp = new ListNode(-1); temp->next = head; ListNode * pro = temp; @@ -99,23 +97,26 @@ public: for (; i < left-1; ++i) { pro = pro->next; } - // 保存 left 节点前的第一个节点 + //保存 left 节点前的一个节点 ListNode * leftNode = pro; + //来到 right 节点 for (; i < right; ++i) { pro = pro->next; } - // 保存 right 节点后的节点 + //保存 right 节点后的一个节点 ListNode * rightNode = pro->next; //切断链表 - pro->next = nullptr; - ListNode * newhead = leftNode->next; - leftNode->next = nullptr; - leftNode->next = rever(newhead); + pro->next = nullptr;//切断 right 后的部分 + ListNode * newhead = leftNode->next;//保存 left 节点 + leftNode->next = nullptr;//切断 left 前的部分 + //反转 + leftNode->next = reverse(newhead); //重新接头 newhead->next = rightNode; return temp->next; } - ListNode * rever (ListNode * head) { + //和反转链表1代码一致 + ListNode * reverse (ListNode * head) { ListNode * low = nullptr; ListNode * pro = head; while (pro != nullptr) { @@ -123,9 +124,185 @@ public: pro = pro->next; temp->next = low; low = temp; - } + } return low; } }; ``` +JS Code: + +```js +var reverseBetween = function (head, left, right) { + //虚拟头节点 + let temp = new ListNode(-1); + temp.next = head; + let pro = temp; + //来到 left 节点前的一个节点 + let i = 0; + for (; i < left - 1; ++i) { + pro = pro.next; + } + //保存 left 节点前的一个节点 + let leftNode = pro; + //来到 right 节点 + for (; i < right; ++i) { + pro = pro.next; + } + //保存 right 节点后的一个节点 + let rightNode = pro.next; + //切断链表 + pro.next = null; //切断 right 后的部分 + let newhead = leftNode.next; //保存 left 节点 + leftNode.next = null; //切断 left 前的部分 + //反转 + leftNode.next = reverse(newhead); + //重新接头 + newhead.next = rightNode; + return temp.next; +}; + +//和反转链表1代码一致 +var reverse = function (head) { + let low = null; + let pro = head; + while (pro) { + let temp = pro; + pro = pro.next; + temp.next = low; + low = temp; + } + return low; +}; +``` + +Python Code: + +```python +class Solution: + def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode: + # 虚拟头节点 + temp = ListNode(-1) + temp.next = head + pro = temp + # 来到 left 节点前的一个节点 + for _ in range(left - 1): + pro = pro.next + # 保存 left 节点前的第一个节点 + leftNode = pro + for _ in range(right - left + 1): + pro = pro.next + # 保存 right 节点后的节点 + rightNode = pro.next + # 切断链表 + pro.next = None # 切断 right 后的部分 + newhead = leftNode.next # 保存 left 节点 + leftNode.next = None # 切断 left 前的部分 + # 反转 + leftNode.next = self.reverse(newhead) + # 重新接头 + newhead.next = rightNode + return temp.next + + # 和反转链表1代码一致 + def reverse(self, head): + low = None + pro = head + while pro is not None: + temp = pro + pro = pro.next + temp.next = low + low = temp + return low +``` + +Swift Code: + +```swift +class Solution { + func reverseBetween(_ head: ListNode?, _ left: Int, _ right: Int) -> ListNode? { + // 虚拟头结点 + var temp = ListNode(-1) + temp.next = head + var pro:ListNode? = temp + // 来到 left 节点前的一个节点 + var i = 0 + for n in i.. ListNode? { + var low:ListNode? + var pro = head + while pro != nil { + var temp = pro + pro = pro?.next + temp?.next = low + low = temp + } + return low + } +} +``` + +GoCode: + +```go +func reverseBetween(head *ListNode, left int, right int) *ListNode { + root := &ListNode{ + Next: head, + } + temp := root + i := 0 + // left的前一个节点 + for ; i < left - 1; i++ { + temp = temp.Next + } + leftNode := temp + // right的后一个节点 + for ; i < right; i++ { + temp = temp.Next + } + rightNode := temp.Next + // 切断链表 + temp.Next = nil + newhead := leftNode.Next + leftNode.Next = nil + + // 反转后将3段链表接上。 + leftNode.Next = reverse(newhead) + newhead.Next = rightNode + return root.Next +} + +func reverse(head *ListNode) *ListNode { + var pre *ListNode + cur := head + for cur != nil { + temp := cur + cur = cur.Next + temp.Next = pre + pre = temp + } + return pre +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode\347\233\270\344\272\244\351\223\276\350\241\250.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode\347\233\270\344\272\244\351\223\276\350\241\250.md" deleted file mode 100644 index 2f84214..0000000 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/leetcode\347\233\270\344\272\244\351\223\276\350\241\250.md" +++ /dev/null @@ -1,172 +0,0 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 -> -> 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 -> -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 - -#### [160. 相交链表](https://leetcode-cn.com/problems/intersection-of-two-linked-lists/) - -### 前言 - -今天给大家带来一个不是那么难的题目,这个题目的解答方法很多,只要能AC的就是好方法,虽然题目不是特别难但是也是剑指offer上的经典题目所以大家要记得打卡呀。 - -然后今天我们的链表板块就算结束啦。周末的时候我会对链表的题目做一个总结,俗话说温故而知新嘛。好啦废话不多说,我们一起来看一下今天的题目吧 - -题目描述: - -输入两个链表,找出它们的第一个公共节点。如下图,返回黄色结点即可。 - - - -![image-20201029215837844](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201029215837844.7ezoerpghyk0.png) - - - -题目表达是不是也很简单,这个题目我的方法一共有两个,一种就是用HashSet进行存储,一种就是利用双指针,大家有更好的可以在下面讨论呀。 - -### HashSet - -这个方法是比较简单的,主要思路就是,先遍历一个链表将链表的所有值都存到Hashset中,然后再遍历另一个链表,如果发现某个结点在Hashset中已经存在那我们直接返回该节点即可,代码也很简单。 - -**题目代码** - -Java Code: - -```java -public class Solution { - public ListNode getIntersectionNode (ListNode headA, ListNode headB) { - ListNode tempa = headA; - ListNode tempb = headB; - //定义Hashset - HashSet arr = new HashSet(); - while (tempa != null) { - arr.add(tempa); - tempa = tempa.next; - } - while (tempb != null) { - if (arr.contains(tempb)) { - return tempb; - } - tempb = tempb.next; - } - return tempb; - } -} -``` - -C++ Code: - -```cpp -class Solution { -public: - ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { - ListNode * tempa = headA; - ListNode * tempb = headB; - //定义Hashset, cpp对应set - set arr; - while (tempa != nullptr) { - arr.insert(tempa); - tempa = tempa->next; - } - while (tempb != nullptr) { - if (arr.find(tempb) != arr.end()) { - return tempb; - } - tempb = tempb->next; - } - return tempb; - } -}; -``` - -JS Code: -```javascript -var getIntersectionNode = function(headA, headB) { - let tempa = headA, tempb = headB - const map = new Map() - while(tempa){ - map.set(tempa, 1) - tempa = tempa.next - } - while(tempb){ - if(map.get(tempb)) - return tempb - tempb = tempb.next - } - return tempb -}; -``` - -下面这个方法比较巧妙,不是特别容易想到,大家可以自己实现一下,这个方法也是利用我们的双指针思想。 - -下面我们直接看动图吧,特别直观,一下就可以搞懂。 - -![第一次相交的点](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/第一次相交的点.5nbxf5t3hgk0.gif) - -是不是一下就懂了呀,我们利用双指针,当某一指针遍历完链表之后,然后掉头去另一个链表的头部,继续遍历。因为速度相同所以他们第二次遍历的时候肯定会相遇,是不是很浪漫啊! - -**题目代码** - -Java Code: - -```java -public class Solution { - public ListNode getIntersectionNode (ListNode headA, ListNode headB) { - //定义两个节点 - ListNode tempa = headA; - ListNode tempb = headB; - //循环 - while (tempa != tempb) { - //如果不为空就指针下移,为空就跳到另一链表的头部 - tempa = tempa != null ? tempa.next:headB; - tempb = tempb != null ? tempb.next:headA; - } - return tempa; - } -} -``` - -C++ Code: - -```cpp -class Solution { -public: - ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { - //定义两个节点 - ListNode * tempa = headA; - ListNode * tempb = headB; - //循环 - while (tempa != tempb) { - //如果不为空就指针下移,为空就跳到另一链表的头部 - tempa = tempa != nullptr ? tempa->next: headB; - tempb = tempb != nullptr ? tempb->next: headA; - } - return tempa; - } -}; -``` - -JS Code: -```javascript -var getIntersectionNode = function(headA, headB) { - let tempa = headA, tempb = headB - while(tempa !== tempb){ - tempa = tempa ? tempa.next : headB - tempb = tempb ? tempb.next : headA - } - return tempa -}; -``` - -好啦,链表的题目就结束啦,希望大家能有所收获,下周就要更新新的题型啦,继续坚持,肯定会有收获的。 - - - - - - - - - - - diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207Offer25\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207Offer25\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.md" index 7f03b6c..1ff1083 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207Offer25\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207Offer25\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.md" @@ -1,12 +1,12 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [剑指 Offer 25. 合并两个排序的链表](https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof/) -将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 +将两个升序链表合并为一个新的 **升序** 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: @@ -15,11 +15,11 @@ 输出:1->1->2->3->4->4 ``` -今天的题目思路很简单,但是一遍AC也是不容易的。链表大部分题目考察的都是考生代码的完整性和鲁棒性,所以有些题目我们看着思路很简单,但是想直接通过还是需要下一翻工夫的,所以建议大家将所有链表的题目都自己写一下。实在没有时间做的同学,可以自己在脑子里打一遍代码,想清没一行代码的作用。 +今天的题目思路很简单,但是一遍 AC 也是不容易的。链表大部分题目考察的都是考生代码的完整性和鲁棒性,所以有些题目我们看着思路很简单,但是想直接通过还是需要下一翻工夫的,所以建议大家将所有链表的题目都自己写一下。实在没有时间做的同学,可以自己在脑子里打一遍代码,想清每一行代码的作用。 迭代法: -因为我们有两个升序链表,我们需要将其合并,那么我们需要创建一个新节点headpre,然后我们利用双指针思想,每个链表放置一个指针,然后进行遍历并对比当前指针指向的值。然后headpre.next指向较小值的那个节点,不断迭代,直至到达某一有序链表底部,此时一个链表遍历完成,然后我们将未完全遍历的链表接在我们接在合并链表之后即可。 +因为我们有两个升序链表,我们需要将其合并,那么我们需要创建一个新节点 headpre,然后我们利用双指针思想,每个链表放置一个指针,然后进行遍历并对比当前指针指向的值。然后 headpre.next 指向较小值的那个节点,不断迭代,直至到达某一有序链表底部,此时一个链表遍历完成,然后我们将未完全遍历的链表接在我们接在合并链表之后即可。 这是我们迭代做法,另外这个题目还有一个递归方法,目前先不写,等链表掌握差不多的时候会单独写一篇关于递归的文章,也算是为树的题目做铺垫。 @@ -47,7 +47,7 @@ Java Code: l1 = l1.next; } headpro = headpro.next; - } + } headpro.next = l1 != null ? l1:l2; return headtemp.next; } @@ -73,10 +73,102 @@ public: l1 = l1->next; } headpro = headpro->next; - } + } headpro->next = l1 != nullptr ? l1: l2; return headtemp->next; } }; ``` +JS Code: + +```js +var mergeTwoLists = function (l1, l2) { + let headpro = new ListNode(-1); + let headtemp = headpro; + while (l1 && l2) { + //接上大的那个 + if (l1.val >= l2.val) { + headpro.next = l2; + l2 = l2.next; + } else { + headpro.next = l1; + l1 = l1.next; + } + headpro = headpro.next; + } + headpro.next = l1 != null ? l1 : l2; + return headtemp.next; +}; +``` + +Python Code: + +```python +class Solution: + def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: + headpro = ListNode(-1) + headtemp = headpro + while l1 and l2: + # 接上大的那个 + if l1.val >= l2.val: + headpro.next = l2 + l2 = l2.next + else: + headpro.next = l1 + l1 = l1.next + headpro = headpro.next + headpro.next = l1 if l1 is not None else l2 + return headtemp.next +``` + +Swift Code: + +```swift +class Solution { + func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + var l1 = l1, l2 = l2 + var headpro: ListNode? = ListNode(-1) + var headtemp = headpro + while l1 != nil && l2 != nil { + //接上大的那个 + if l1!.val >= l2!.val { + headpro?.next = l2 + l2 = l2!.next + } else { + headpro?.next = l1 + l1 = l1!.next + } + headpro = headpro?.next + } + headpro?.next = l1 != nil ? l1 : l2 + return headtemp?.next + } +} +``` + +Go Code: + +```go +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + root := &ListNode{} + node := root + for l1 != nil && l2 != nil { + if l1.Val < l2.Val { + node.Next = l1 + l1 = l1.Next + } else { + node.Next = l2 + l2 = l2.Next + } + node = node.Next + } + // node接上l1或l2剩下的节点 + if l1 != nil { + node.Next = l1 + } else { + node.Next = l2 + } + return root.Next +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207Offer52\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\350\212\202\347\202\271.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207Offer52\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\350\212\202\347\202\271.md" index d045c60..e3c09e3 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207Offer52\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\350\212\202\347\202\271.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207Offer52\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\350\212\202\347\202\271.md" @@ -1,34 +1,28 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -#### [剑指 Offer 52. 两个链表的第一个公共节点](https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/) +#### [剑指 Offer 52. 两个链表的第一个公共节点](https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/) & [160. 相交链表](https://leetcode-cn.com/problems/intersection-of-two-linked-lists/) ### 前言 -今天给大家带来一个不是那么难的题目,这个题目的解答方法很多,只要能AC的就是好方法,虽然题目不是特别难但是也是剑指offer上的经典题目所以大家要记得打卡呀。 +今天给大家带来一个不是那么难的题目,这个题目的解答方法很多,只要能 AC 的就是好方法,虽然题目不是特别难但是也是剑指 offer 上的经典题目所以大家要记得打卡呀。 -然后今天我们的链表板块就算结束啦。周末的时候我会对链表的题目做一个总结,俗话说温故而知新嘛。好啦废话不多说,我们一起来看一下今天的题目吧 +然后今天我们的链表板块就算结束啦。周末的时候我会对链表的题目做一个总结,俗话说温故而知新嘛。好啦废话不多说,我们一起来看一下今天的题目吧! 题目描述: 输入两个链表,找出它们的第一个公共节点。如下图,返回黄色结点即可。 - - ![image-20201029215837844](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/image-20201029215837844.7ezoerpghyk0.png) - - -题目表达是不是也很简单,这个题目我的方法一共有两个,一种就是用HashSet进行存储,一种就是利用双指针,大家有更好的可以在下面讨论呀。 +题目表达是不是也很简单,这个题目我的方法一共有两个,一种就是用 HashSet 进行存储,一种就是利用双指针,大家有更好的可以在下面讨论呀。 ### HashSet -这个方法是比较简单的,主要思路就是,先遍历一个链表将链表的所有值都存到Hashset中,然后再遍历另一个链表,如果发现某个结点在Hashset中已经存在那我们直接返回该节点即可,代码也很简单。 - - +这个方法是比较简单的,主要思路就是,先遍历一个链表将链表的所有值都存到 Hashset 中,然后再遍历另一个链表,如果发现某个结点在 Hashset 中已经存在那我们直接返回该节点即可,代码也很简单。 **题目代码** @@ -41,18 +35,21 @@ public class Solution { ListNode tempb = headB; //定义Hashset HashSet arr = new HashSet(); + //遍历链表A,将所有值都存到arr中 while (tempa != null) { arr.add(tempa); tempa = tempa.next; } + //遍历列表B,如果发现某个结点已在arr中则直接返回该节点 while (tempb != null) { if (arr.contains(tempb)) { return tempb; } tempb = tempb.next; } + //若上方没有返回,此刻tempb为null return tempb; - + } } ``` @@ -67,21 +64,106 @@ public: ListNode * tempb = headB; //定义Hashset set arr; + //遍历链表A,将所有值都存到arr中 while (tempa != nullptr) { arr.insert(tempa); tempa = tempa->next; } + //遍历列表B,如果发现某个结点已在arr中则直接返回该节点 while (tempb != nullptr) { if (arr.find(tempb) != arr.end()) { return tempb; } tempb = tempb->next; } + //若上方没有返回,此刻tempb为null return tempb; } }; ``` +JS Code: + +```js +var getIntersectionNode = function (headA, headB) { + let tempa = headA; + let tempb = headB; + //定义Hashset + let arr = new Set(); + //遍历链表A,将所有值都存到arr中 + while (tempa) { + arr.add(tempa); + tempa = tempa.next; + } + //遍历列表B,如果发现某个结点已在arr中则直接返回该节点 + while (tempb) { + if (arr.has(tempb)) { + return tempb; + } + tempb = tempb.next; + } + //若上方没有返回,此刻tempb为null + return tempb; +}; +``` + +Python Code: + +```python +class Solution: + def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode: + tempa = headA + tempb = headB + # 定义Hashset + arr = set() + # 遍历链表A,将所有值都存到arr中 + while tempa is not None: + arr.add(tempa) + tempa = tempa.next + # 遍历列表B,如果发现某个结点已在arr中则直接返回该节点 + while tempb is not None: + if tempb in arr: + return tempb + tempb = tempb.next + # 若上方没有返回,此刻tempb为null + return tempb +``` + +Swift Code: + +```swift +class Solution { + func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? { + var tempa = headA + var tempb = headB + var arr:Set = [] + //遍历链表A,将所有值都存到arr中 + while tempa != nil { + arr.insert(tempa!) + tempa = tempa?.next + } + //遍历列表B,如果发现某个结点已在arr中则直接返回该节点 + while tempb != nil { + if arr.contains(tempb!) { + return tempb + } + tempb = tempb?.next + } + //若上方没有返回,此刻tempb为null + return tempb + } +} +extension ListNode: Hashable, Equatable { + public func hash(into hasher: inout Hasher) { + hasher.combine(val) + hasher.combine(ObjectIdentifier(self)) + } + public static func ==(lhs: ListNode, rhs: ListNode) -> Bool { + return lhs === rhs + } +} +``` + 下面这个方法比较巧妙,不是特别容易想到,大家可以自己实现一下,这个方法也是利用我们的双指针思想。 下面我们直接看动图吧,特别直观,一下就可以搞懂。 @@ -90,8 +172,6 @@ public: 是不是一下就懂了呀,我们利用双指针,当某一指针遍历完链表之后,然后掉头去另一个链表的头部,继续遍历。因为速度相同所以他们第二次遍历的时候肯定会相遇,是不是很浪漫啊! - - **题目代码** Java Code: @@ -108,7 +188,7 @@ public class Solution { tempa = tempa != null ? tempa.next: headB; tempb = tempb != null ? tempb.next: headA; } - return tempa; + return tempa;//返回tempb也行 } } ``` @@ -124,24 +204,96 @@ public: ListNode * tempb = headB; //循环 while (tempa != tempb) { - //如果不为空就指针下移,为空就跳到另一链表的头部 + //如果不为空就指针下移,为空就跳到另一链表的头部 tempa = tempa != nullptr ? tempa->next: headB; tempb = tempb != nullptr ? tempb->next: headA; } - return tempa; + return tempa;//返回tempb也行 } }; ``` -好啦,链表的题目就结束啦,希望大家能有所收获,下周就要更新新的题型啦,继续坚持,肯定会有收获的。 - - - - +JS Code: + +```js +var getIntersectionNode = function (headA, headB) { + //定义两个节点 + let tempa = headA; + let tempb = headB; + //循环 + while (tempa != tempb) { + //如果不为空就指针下移,为空就跳到另一链表的头部 + tempa = tempa != null ? tempa.next : headB; + tempb = tempb != null ? tempb.next : headA; + } + return tempa; //返回tempb也行 +}; +``` +Python Code: + +```python +class Solution: + def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode: + # 定义两个节点 + tempa = headA + tempb = headB + # 循环 + while tempa is not tempb: + # 如果不为空就指针下移,为空就跳到另一链表的头部 + tempa = tempa.next if tempa is not None else headB + tempb = tempb.next if tempb is not None else headA + return tempa # 返回tempb也行 +``` +Swift Code: +```swift +class Solution { + func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? { + //定义两个节点 + var tempa = headA + var tempb = headB + //循环 + while tempa != tempb { + // 如果不为空就指针下移,为空就跳到另一链表的头部 + tempa = tempa != nil ? tempa?.next : headB + tempb = tempb != nil ? tempb?.next : headA + } + return tempa //返回tempb也行 + } +} +``` +Go Code: + +```go +func getIntersectionNode(headA, headB *ListNode) *ListNode { + tempA, tempB := headA, headB + for tempA != tempB { + // 如果不为空就指针下移,为空就跳到另一链表的头部 + if tempA == nil { + tempA = headB + } else { + tempA = tempA.Next + } + if tempB == nil { + tempB = headA + } else { + tempB = tempB.Next + } + } + return tempA +} +``` +好啦,链表的题目就结束啦,希望大家能有所收获,下周就要更新新的题型啦,继续坚持,肯定会有收获的。 +
+> 贡献者[@jaredliw](https://github.com/jaredliw)注: +> +> 在这里带大家来看看一些其他的解题方法,虽然没有双指针有效,但还是值得一试。 +> +> 1. 两个链表各遍历一次,找出长度。根据长度差 k,让较长的那个链表先走 k 步。之后再两个指针一起走,由于起点一样,两个指针必将一起到达公共节点。 +> 2. 将其中一条链表的头和尾相连,公共节点就是环的入口,直接套用之前学过的算法就可以啦。(这解法看得我拍腿叫好) diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207offer22\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207offer22\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.md" index 2666add..e85962d 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207offer22\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/\345\211\221\346\214\207offer22\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.md" @@ -1,30 +1,30 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 -#### [剑指 Offer 22. 链表中倒数第k个节点](https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) +#### [剑指 Offer 22. 链表中倒数第 k 个节点](https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) 题目: -输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。 +输入一个链表,输出该链表中倒数第 k 个节点。为了符合大多数人的习惯,本题从 1 开始计数,即链表的尾节点是倒数第 1 个节点。例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。 题目分析: -自己思考一下 +自己思考一下: 我们遇到这个题目,可能会有什么答题思路呢? -你看我说的对不对,是不是会想到先遍历一遍链表知道 链表节点的个数,然后再计算出倒数第n个节点。 +你看我说的对不对,是不是会想到先遍历一遍链表知道 链表节点的个数,然后再计算出倒数第 n 个节点。 -比如链表长度为10,倒数第3个节点,不就是正数第8个节点呀,这种方法当然可以啦,是可以实现的,那么我们再思考一下有没有其他方法呢?哦,对,我们可以将链表元素保存到数组里面,然后直接就可以知道倒数第K个节点了。这个方法确实比刚才那个方法省时间了,但是所耗的空间更多了,那我们还有什么方法吗? +比如链表长度为 10,倒数第 3 个节点,不就是正数第 8 个节点呀,这种方法当然可以啦,是可以实现的,那么我们再思考一下有没有其他方法呢?哦,对,我们可以将链表元素保存到数组里面,然后直接就可以知道倒数第 k 个节点了。这个方法确实比刚才那个方法省时间了,但是所耗的空间更多了,那我们还有什么方法吗? 我们可以继续利用我们的双指针呀,但是我们应该怎么做呢? 双指针法: -首先一个指针移动K-1位(这里可以根据你的初始化指针决定),然后另一个指针开始启动,他俩移动速度一样,所以他俩始终相差K-1位,当第一个指针到达链表尾部时,第二个指针的指向则为倒数第K个节点。 +首先一个指针移动 K-1 位(这里可以根据你的初始化指针决定),然后另一个指针开始启动,他俩移动速度一样,所以他俩始终相差 K-1 位,当第一个指针到达链表尾部时,第二个指针的指向则为倒数第 K 个节点。 ![](https://img-blog.csdnimg.cn/img_convert/506c4d70f4c50c66994711c8506462a8.gif) @@ -50,7 +50,7 @@ class Solution { //先移动绿指针到指定位置 for (int i = 0; i < k-1; i++) { pro = pro.next; - } + } //两个指针同时移动 while (pro.next != null) { pro = pro.next; @@ -81,7 +81,7 @@ public: //先移动绿指针到指定位置 for (int i = 0; i < k-1; i++) { pro = pro->next; - } + } //两个指针同时移动 while (pro->next != nullptr) { pro = pro->next; @@ -94,17 +94,90 @@ public: ``` JS Code: + ```javascript -var getKthFromEnd = function(head, k) { - if(!head) return head; - let pro = head, after = head; - for(let i = 0; i < k - 1; i++){ - pro = pro.next; +var getKthFromEnd = function (head, k) { + //特殊情况 + if (!head) return head; + //初始化两个指针, 定义指针指向 + let pro = head, + after = head; + //先移动绿指针到指定位置 + for (let i = 0; i < k - 1; i++) { + pro = pro.next; + } + //两个指针同时移动 + while (pro.next) { + pro = pro.next; + after = after.next; + } + //返回倒数第k个节点 + return after; +}; +``` + +Python Code: + +```python +class Solution: + def getKthFromEnd(self, head: ListNode, k: int) -> ListNode: + # 特殊情况 + if head is None: + return head + # 初始化两个指针, 定义指针指向 + pro = head + after = head + # 先移动绿指针到指定位置 + for _ in range(k - 1): + pro = pro.next + # 两个指针同时移动 + while pro.next is not None: + pro = pro.next + after = after.next + # 返回倒数第k个节点 + return after +``` + +Swift Code: + +```swift +class Solution { + func getKthFromEnd(_ head: ListNode?, _ k: Int) -> ListNode? { + //特殊情况 + if head == nil { + return head + } + //初始化两个指针 + var pro = head, after = head + //先移动绿指针到指定位置 + for i in 0.. 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [876. 链表的中间结点](https://leetcode-cn.com/problems/middle-of-the-linked-list/) -给定一个头结点为 head的非空单链表,返回链表的中间结点。 +给定一个头结点为 head 的非空单链表,返回链表的中间结点。 -如果有两个中间结点,则返回第二个中间结点。 +如果有两个中间结点,则返回第二个中间结点。 **示例 1:** @@ -17,7 +17,7 @@ 输出:3 ``` -> 说明:因为只有一个中间节点 +> 说明:因为只有一个中间节点。 **示例 2:** @@ -26,25 +26,25 @@ 输出:4 ``` -> 说明:有两个中间节点所以返回后面那个 +> 说明:有两个中间节点所以返回后面那个。 -## 题目解析: +**题目解析:** 又精心筛选了一个题目,本来想写一下删除节点的题目,然后发现这个题目更符合目前的节奏,所以先写一下这个题目,明天再给大家写删除节点的题目。 -大家先不要看我的题解,先自己想一下怎么做。这个这个题目是想让我们找出中间节点,昨天的题目是让我们倒数第K个节点,想一下这两个题目有什么联系呢? +大家先不要看我的题解,先自己想一下怎么做。这个这个题目是想让我们找出中间节点,昨天的题目是让我们倒数第 K 个节点,想一下这两个题目有什么联系呢? 先说一下刚开始刷题的小伙伴可能会想到的题解,两次遍历链表,第一次遍历获取链表长度,第二次遍历获取中间链表。 -这个方法很OK,利用数组先将所有链表元素存入数组里,然后再直接获得中间节点。这个也很OK,那么我们有没有一次遍历,且不开辟辅助空间的方法呢? +这个方法很 OK,利用数组先将所有链表元素存入数组里,然后再直接获得中间节点。这个也很 OK,那么我们有没有一次遍历,且不开辟辅助空间的方法呢? -昨天的题目是一前一后双指针,两个指针之间始终相差k-1位,我们今天也利用一下双指针的做法吧。 +昨天的题目是一前一后双指针,两个指针之间始终相差 k-1 位,我们今天也利用一下双指针的做法吧。 这种类型的双指针是我们做链表的题目经常用到的,叫做快慢指针。 一个指针走的快,一个指针走的慢,这个题目我们可以让快指针一次走两步,慢指针一次走一步,当快指针到达链表尾部的时候,慢指针不就到达中间节点了吗? -链表中节点的个数有可能为奇数也有可能为偶数,这是两种情况,但是我们输出是相同的,那就是输出slow指针指向的节点 +链表中节点的个数有可能为奇数也有可能为偶数,这是两种情况,但是我们输出是相同的,那就是输出 slow 指针指向的节点,也就是两个中间节点的第二个。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321131249789.gif) @@ -63,7 +63,7 @@ class Solution { slow = slow.next; } //返回slow指针指向的节点 - return slow; + return slow; } } ``` @@ -71,6 +71,7 @@ class Solution { C++ Code: ```cpp +class Solution { public: ListNode* middleNode(ListNode* head) { ListNode * fast = head;//快指针 @@ -81,8 +82,70 @@ public: slow = slow->next; } //返回slow指针指向的节点 - return slow; + return slow; } }; ``` +JS Code: + +```js +var middleNode = function (head) { + let fast = head; //快指针 + let slow = head; //慢指针 + //循环条件,思考一下跳出循环的情况 + while (fast && fast.next) { + fast = fast.next.next; + slow = slow.next; + } + //返回slow指针指向的节点 + return slow; +}; +``` + +Python Code: + +```python +class Solution: + def middleNode(self, head: ListNode) -> ListNode: + fast = head # 快指针 + slow = head # 慢指针 + # 循环条件,思考一下跳出循环的情况 + while fast is not None and fast.next is not None: + fast = fast.next.next + slow = slow.next + # 返回slow指针指向的节点 + return slow +``` + +Swift Code: + +```swift +class Solution { + func middleNode(_ head: ListNode?) -> ListNode? { + var fast = head //快指针 + var slow = head //慢指针 + //循环条件,思考一下跳出循环的情况 + while fast != nil && fast?.next != nil { + fast = fast?.next?.next + slow = slow?.next + } + //返回slow指针指向的节点 + return slow + } +} +``` + +Go Code: + +```go +func middleNode(head *ListNode) *ListNode { + // 快慢指针 + fast, slow := head, head + for fast != nil && fast.Next != nil { + fast = fast.Next.Next + slow = slow.Next + } + return slow +} +``` diff --git "a/animation-simulation/\351\223\276\350\241\250\347\257\207/\351\235\242\350\257\225\351\242\230 02.05. \351\223\276\350\241\250\346\261\202\345\222\214.md" "b/animation-simulation/\351\223\276\350\241\250\347\257\207/\351\235\242\350\257\225\351\242\230 02.05. \351\223\276\350\241\250\346\261\202\345\222\214.md" index af5aa66..71bf721 100644 --- "a/animation-simulation/\351\223\276\350\241\250\347\257\207/\351\235\242\350\257\225\351\242\230 02.05. \351\223\276\350\241\250\346\261\202\345\222\214.md" +++ "b/animation-simulation/\351\223\276\350\241\250\347\257\207/\351\235\242\350\257\225\351\242\230 02.05. \351\223\276\350\241\250\346\261\202\345\222\214.md" @@ -1,12 +1,12 @@ -> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 +> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > -> 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 +> 另外希望手机阅读的同学可以来我的 [**公众号:程序厨**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [面试题 02.05. 链表求和](https://leetcode-cn.com/problems/sum-lists-lcci/) -之前我们一起做了链表中的几个经典题型,找到倒数第k个节点,找链表中点,判断链表中环的起点,合并链表,反转链表,删除链表中重复值。这些是链表中的经典问题,面试中也经常会考的问题,然后下面我们继续做一道链表题目,也是面试中经常会考的题目,链表求和问题。 +之前我们一起做了链表中的几个经典题型,找到倒数第 k 个节点,找链表中点,判断链表中环的起点,合并链表,反转链表,删除链表中重复值。这些是链表中的经典问题,面试中也经常会考的问题,然后下面我们继续做一道链表题目,也是面试中经常会考的题目,链表求和问题。 另外有一些小伙伴说,虽然一天一道题不算多,但是每天读题,做题加消化稍微有点跟不上,所以我打算每个周的工作日进行更新题目,到周末的时候对本周的题目进行总结,然后为大家再写一些别的东西。下面我们一起来看一下今天的题目吧。 @@ -18,27 +18,27 @@ 这些数位是反向存放的,也就是个位排在链表首部。 -编写函数对这两个整数求和,并用链表形式返回结果。 +编写函数对这两个整数求和,并用链表形式返回结果。 -示例1: +示例 1: ```java -输入:(7 -> 1 -> 6) + (5 -> 9 -> 2),即617 + 295 -输出:2 -> 1 -> 9,即912 +输入:(7 -> 1 -> 6) + (5 -> 9 -> 2),即 617 + 295 +输出:2 -> 1 -> 9,即 912 ``` -示例2: +示例 2: ```java -输入:(9 -> 9) + (9 -> 9),即99+99 -输出:8->9->1 +输入:(9 -> 9) + (9 -> 9),即 99 + 99 +输出:8 -> 9 -> 1 ``` -示例3: +示例 3: ```java -输入:(5)+(5),即5+5 -输出:0->1 +输入:(5) + (5),即 5 + 5 +输出:0 -> 1 ``` **题目解析:** @@ -51,25 +51,23 @@ 我们应该对链表的每一位进行相加,然后通过链表的和,判断是否需要像下一位进行传递, -就好比小时候我们用竖式进行加法一样,判断两位相加是否大于10,大于10则进1。 +就好比小时候我们用竖式进行加法一样,判断两位相加是否大于 10,大于 10 则进 1。 了解了思路,但是想完全实现代码也不是特别容易,这里需要注意的三个点就是, -1.我们需要根据两个链表的长度,不断对新链表添加节点 +1. 我们需要根据两个链表的长度,不断对新链表添加节点。 -2.需要创建一个变量用来保存进位值。 +2. 需要创建一个变量用来保存进位值。 -3.当跳出循环之后,需要根据进位值来判断需不需要再对链表长度加1. +3. 当跳出循环之后,需要根据进位值来判断需不需要再对链表长度加 1。 这三条可以结合代码理解进行。 -注:进位值只能是0或1,因为每一位最大为9,9+9=18; +注:进位值只能是 0 或 1,因为每一位最大为 9,9+9=18; ![链表求和](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/链表求和.1yh4ymdee3k0.gif) -注:这里需要注意得时,链表遍历结束,我们应该跳出循环,但是我们的nlist仍在尾部添加了1节点,那是因为跳出循环时,summod值为1,所以我们需要在尾部再添加一个节点。 - - +注:这里需要注意得时,链表遍历结束,我们应该跳出循环,但是我们的 nlist 仍在尾部添加了 1 节点,那是因为跳出循环时,summod 值为 1,所以我们需要在尾部再添加一个节点。 **题目代码** @@ -78,8 +76,8 @@ Java Code: ```java class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { - //返回链表 - ListNode nList = new ListNode(-1); + //待会儿要返回的链表 + ListNode nList = new ListNode(-1);//哑节点 ListNode tempnode = nList; //用来保存进位值,初始化为0 int summod = 0; @@ -92,8 +90,8 @@ class Solution { int sum = l1num+l2num+summod; //更新进位值,例18/10=1,9/10=0 summod = sum/10; - //新节点保存的值,18 % 8=2,则添加2 - sum = sum%10; + //新节点保存的值,18%8=2,则添加2 + sum = sum%10; //添加节点 tempnode.next = new ListNode(sum); //移动指针 @@ -103,13 +101,13 @@ class Solution { } if (l2 != null) { l2 = l2.next; - } + } } //最后根据进位值判断需不需要继续添加节点 - if (summod == 1) { + if (summod != 0) { tempnode.next = new ListNode(summod); } - return nList.next; + return nList.next;//去除哑节点 } } ``` @@ -120,8 +118,8 @@ C++ Code: class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { - //返回链表 - ListNode * nList = new ListNode(-1); + //待会儿要返回的链表 + ListNode * nList = new ListNode(-1);//哑节点 ListNode * tempnode = nList; //用来保存进位值,初始化为0 int summod = 0; @@ -134,8 +132,8 @@ public: int sum = l1num + l2num + summod; //更新进位值,例18/10=1,9/10=0 summod = sum / 10; - //新节点保存的值,18 % 8=2,则添加2 - sum = sum % 10; + //新节点保存的值,18%8=2,则添加2 + sum = sum % 10; //添加节点 tempnode->next = new ListNode(sum); //移动指针 @@ -145,14 +143,164 @@ public: } if (l2 != nullptr) { l2 = l2->next; - } + } } //最后根据进位值判断需不需要继续添加节点 - if (summod == 1) { + if (summod != 0) { tempnode->next = new ListNode(summod); } - return nList->next; + return nList->next;//哑节点 } }; ``` +JS Code: + +```js +var addTwoNumbers = function (l1, l2) { + //待会儿要返回的链表 + let nList = new ListNode(-1); //哑节点 + let tempnode = nList; + //用来保存进位值,初始化为0 + let summod = 0; + while (l1 || l2) { + //如果l1的链表为空则l1num为0,若是不为空,则为链表的节点值 + //判断是否为空,为空就设为0 + let l1num = l1 === null ? 0 : l1.val; + let l2num = l2 === null ? 0 : l2.val; + //将链表的值和进位值相加,得到为返回链表的值 + let sum = l1num + l2num + summod; + //更新进位值,例18/10=1,9/10=0 + summod = ~~(sum / 10); + //新节点保存的值,18%8=2,则添加2 + sum = sum % 10; + //添加节点 + tempnode.next = new ListNode(sum); + //移动指针 + tempnode = tempnode.next; + if (l1) { + l1 = l1.next; + } + if (l2) { + l2 = l2.next; + } + } + //最后根据进位值判断需不需要继续添加节点 + if (summod !== 0) { + tempnode.next = new ListNode(summod); + } + return nList.next; //去除哑节点 +}; +``` + +Python Code: + +```python +class Solution: + def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: + # 待会儿要返回的链表 + nList = ListNode(-1) # 哑节点 + tempnode = nList + # 用来保存进位值,初始化为0 + summod = 0 + while l1 is not None o l2 is not None: + # 如果l1的链表为空则l1num为0,若是不为空,则为链表的节点值 + # 判断是否为空,为空就设为0 + l1num = 0 if l1 is None else l1.val + l2num = 0 if l2 is None else l2.val + # 将链表的值和进位值相加,得到为返回链表的值 + sum_ = l1num + l2num + summod + # 更新进位值,例18/10=1,9/10=0 + # 新节点保存的值,1 %8=2,则添加2 + # 注:这里使用divmod函数,对上方的代码进行了一丢丢的简化 + summod, sum_ = divmod(sum_, 10) + # 添加节点 + tempnode.next = ListNode(sum_) + # 移动指针 + tempnode = tempnode.next + if l1 is not None: + l1 = l1.next + if l2 is not None: + l2 = l2.next + # 最后根据进位值判断需不需要继续添加节点 + if summod != 0: + tempnode.next = ListNode(summod) + return nList.next # 去除哑节点 +``` + +Swift Code: + +```swift +class Solution { + func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + var l1 = l1, l2 = l2 + var nList = ListNode(-1) // 哑节点 + var tempnode = nList + // 用来保存进位值,初始化为0 + var summod = 0 + while l1 != nil || l2 != nil { + // 链表的节点值 + let l1num = l1?.val ?? 0 + let l2num = l2?.val ?? 0 + // 将链表的值和进位值相加,得到为返回链表的值 + var sum = l1num + l2num + summod + // 更新进位值,例18/10=1,9/10=0 + summod = sum / 10 + // 新节点保存的值,18%8=2,则添加2 + sum = sum % 10 + // 添加节点 + tempnode.next = ListNode(sum) + // 移动指针 + tempnode = tempnode.next! + if l1 != nil { + l1 = l1?.next + } + if l2 != nil { + l2 = l2?.next + } + } + // 最后根据进位值判断需不需要继续添加节点 + if (summod != 0) { + tempnode.next = ListNode(summod) + } + return nList.next //去除哑节点 + } +} +``` + +Go Code: + +```go +func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { + root := &ListNode{} + temp := root + // 用来保存进位值,初始化为0 + mod := 0 + for (l1 != nil || l2 != nil) { + l1num := 0 + if l1 != nil { l1num = l1.Val } + l2num := 0 + if l2 != nil { l2num = l2.Val } + // 将链表的值和进位值相加,得到为返回链表的值 + sum := l1num + l2num + mod + // 更新进位值,例18/10=1,9/10=0 + mod = sum / 10 + // 新节点保存的值,18%8=2,则添加2 + sum = sum % 10 + newNode := &ListNode{ + Val: sum, + } + temp.Next = newNode + temp = temp.Next + if l1 != nil { l1 = l1.Next } + if l2 != nil { l2 = l2.Next } + } + if mod != 0 { + newNode := &ListNode{ + Val: mod, + } + temp.Next = newNode + } + return root.Next +} +```