[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# dotenv\n.env\n\n# virtualenv\n.venv\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.DS_Store\n\n# gitbook\n_book\n\n# node.js\nnode_modules\n\n# windows\nThumbs.db\n\n# word\n~$*.docx\n~$*.doc\n"
  },
  {
    "path": ".nojekyll",
    "content": ""
  },
  {
    "path": "404.html",
    "content": "---\npermalink: /404.html\n---\n<script>window.location.href = '/';</script>\n"
  },
  {
    "path": "CNAME",
    "content": "algo.apachecn.org"
  },
  {
    "path": "Dockerfile",
    "content": "FROM httpd:2.4\nCOPY ./ /usr/local/apache2/htdocs/"
  },
  {
    "path": "NAV.md",
    "content": "+   编程\n    +   [JavaTPoint 编程语言中文教程📚](https://apachecn.github.io/javatpoint-prog-zh)\n    +   [JavaTPoint .NET 中文教程📚](https://apachecn.github.io/javatpoint-dotnet-zh)\n    +   [JavaTPoint Java 中文教程📚](https://apachecn.github.io/javatpoint-java-zh)\n    +   [JavaTPoint Python 中文教程📚](https://apachecn.github.io/javatpoint-python-zh)\n    +   [GeeksForGeeks 编程语言杂项中文教程📚](https://apachecn.github.io/geeksforgeeks-lang-misc-zh)\n    +   [GeeksForGeeks C# 中文教程📚](https://apachecn.github.io/geeksforgeeks-csharp-zh)\n    +   [GeeksForGeeks Scala 中文教程📚](https://apachecn.github.io/geeksforgeeks-scala-zh)\n    +   [GeeksForGeeks Python 中文教程📚](https://apachecn.github.io/geeksforgeeks-python-zh)\n    +   [GeeksForGeeks C/C++ 中文教程📚](https://apachecn.github.io/geeksforgeeks-c-cpp-zh)\n    +   [GeeksForGeeks Java 中文教程📚](https://apachecn.github.io/geeksforgeeks-java-zh)\n    +   [GeeksForGeeks JavaScript 中文教程📚](https://apachecn.github.io/geeksforgeeks-js-zh)\n    +   [ApacheCN C# 译文集📚](https://apachecn.github.io/apachecn-csharp-zh)\n    +   [ApacheCN C# 译文集（二）📚](https://apachecn.github.io/apachecn-csharp-zh-pt2)\n    +   [ApacheCN C# 译文集（三）📚](https://apachecn.github.io/apachecn-csharp-zh-pt3)\n    +   [ApacheCN C# 译文集（四）📚](https://apachecn.github.io/apachecn-csharp-zh-pt4)\n    +   [ApacheCN Golang 译文集📚](https://apachecn.github.io/apachecn-golang-zh)\n    +   [ApacheCN Golang 译文集（二）📚](https://apachecn.github.io/apachecn-golang-zh-pt2)\n    +   [ApacheCN C/C++ 译文集📚](https://apachecn.github.io/apachecn-c-cpp-zh)\n    +   [ApacheCN C/C++ 译文集（二）📚](https://apachecn.github.io/apachecn-c-cpp-zh-pt2)\n    +   [ApacheCN C/C++ 译文集（三）📚](https://apachecn.github.io/apachecn-c-cpp-zh-pt3)\n    +   [ApacheCN Java 译文集📚](https://apachecn.github.io/apachecn-java-zh)\n    +   [ApacheCN Java 译文集（二）📚](https://apachecn.github.io/apachecn-java-zh-pt2)\n    +   [ApacheCN Java 译文集（三）📚](https://apachecn.github.io/apachecn-java-zh-pt3)\n    +   [ApacheCN JavaScript 译文集📚](https://apachecn.github.io/apachecn-js-zh)\n    +   [ApacheCN JavaScript 译文集（二）📚](https://apachecn.github.io/apachecn-js-zh-pt2)\n    +   [ApacheCN JavaScript 译文集（三）📚](https://apachecn.github.io/apachecn-js-zh-pt3)\n    +   [ApacheCN JavaScript 译文集（四）📚](https://apachecn.github.io/apachecn-js-zh-pt4)\n    +   [ApacheCN Python 译文集📚](https://apachecn.github.io/apachecn-python-zh)\n    +   [ApacheCN Python 译文集（二）📚](https://apachecn.github.io/apachecn-python-zh-pt2)\n    +   [ApacheCN Python 译文集（三）📚](https://apachecn.github.io/apachecn-python-zh-pt3)\n    +   [ApacheCN Python 译文集（四）📚](https://apachecn.github.io/apachecn-python-zh-pt4)\n    +   [ApacheCN Ruby 译文集📚](https://apachecn.github.io/apachecn-ruby-zh)\n    +   [BeginnersBook 中文系列教程📚](https://apachecn.github.io/beginnersbook-zh)\n    +   [JavaScript 编程精解 中文第三版](https://apachecn.github.io/eloquent-js-3e-zh)\n    +   [Guru99 中文系列教程📚🚧](https://apachecn.github.io/guru99-zh)\n    +   [HowToDoInJava 中文系列教程📚](https://apachecn.github.io/howtodoinjava-zh)\n    +   [OverIQ 中文系列教程📚](https://apachecn.github.io/overiq-zh)\n    +   [LearnETutroials 中文系列教程📚](https://apachecn.github.io/learnetutorials-zh)\n    +   [StudyTonight 中文系列教程📚](https://apachecn.github.io/studytonight-zh)\n    +   [TutorialGateway 中文系列教程📚](https://apachecn.github.io/tutorialgateway-zh)\n    +   [TutorialGateway BI 中文系列教程📚](https://apachecn.github.io/tutorialgateway-bi-zh)\n    +   [TutorialsTeacher 中文系列教程📚](https://apachecn.github.io/tutorialsteacher-zh)\n    +   [通过示例学 Golang 2020 中文版](https://apachecn.github.io/golang-by-example-2020-zh)\n    +   [写给不耐烦程序员的 JavaScript🚧](https://apachecn.github.io/impatient-js-zh)\n    +   [JavaBeginnersTutorial 中文系列教程📚](https://apachecn.github.io/jbt-zh)\n    +   [JavaTutorialNetwork 中文系列教程📚](https://apachecn.github.io/jtn-zh)\n    +   [笨办法学C 中文版](https://apachecn.github.io/lcthw-zh)\n    +   [笨办法学 Python · 续 中文版](https://apachecn.github.io/lmpythw-zh)\n    +   [Programiz 中文系列教程📚](https://apachecn.github.io/programiz-zh)\n    +   [PythonBasics 中文系列教程📚](https://apachecn.github.io/pythonbasics-zh)\n    +   [PythonGuru 中文系列教程📚](https://apachecn.github.io/pythonguru-zh)\n    +   [PythonSpot 中文系列教程📚](https://apachecn.github.io/pythonspot-zh)\n    +   [Think Python](https://apachecn.github.io/think-py-2e-zh)\n    +   [ZetCode 中文系列教程📚](https://apachecn.github.io/zetcode-zh)\n+   前端\n    +   [JavaTPoint 移动开发中文教程📚](https://apachecn.github.io/javatpoint-mobi-zh)\n    +   [GeeksForGeeks Web 杂项中文教程📚](https://apachecn.github.io/geeksforgeeks-web-misc-zh)\n    +   [GeeksForGeeks Angular/Vue/React 中文教程📚](https://apachecn.github.io/geeksforgeeks-ng-vue-react-zh)\n    +   [GeeksForGeeks jQuery 中文教程📚](https://apachecn.github.io/geeksforgeeks-jquery-zh)\n    +   [GeeksForGeeks CSS 中文教程📚](https://apachecn.github.io/geeksforgeeks-css-zh)\n    +   [GeeksForGeeks HTML 中文教程📚](https://apachecn.github.io/geeksforgeeks-html-zh)\n    +   [ApacheCN Vue 译文集📚](https://apachecn.github.io/apachecn-vue-zh)\n    +   [ApacheCN Angular 译文集📚](https://apachecn.github.io/apachecn-angular-zh)\n    +   [ApacheCN React 译文集📚](https://apachecn.github.io/apachecn-react-zh)\n    +   [ApacheCN jQuery 译文集📚](https://apachecn.github.io/apachecn-jquery-zh)\n    +   [ApacheCN jQuery 译文集（二）📚](https://apachecn.github.io/apachecn-jquery-zh-pt2)\n+   后端/大数据\n    +   [JavaTPoint 大数据中文教程📚](https://apachecn.github.io/javatpoint-bigdata-zh)\n    +   [JavaTPoint Web 开发中文教程📚](https://apachecn.github.io/javatpoint-web-zh)\n    +   [JavaTPoint 数据库中文教程📚](https://apachecn.github.io/javatpoint-db-zh)\n    +   [JavaTPoint PHP 中文教程📚](https://apachecn.github.io/javatpoint-php-zh)\n    +   [GeeksForGeeks ASP 中文教程📚](https://apachecn.github.io/geeksforgeeks-asp-zh)\n    +   [GeeksForGeeks SQL 中文教程📚](https://apachecn.github.io/geeksforgeeks-sql-zh)\n    +   [GeeksForGeeks NodeJS 中文教程📚](https://apachecn.github.io/geeksforgeeks-nodejs-zh)\n    +   [GeeksForGeeks PHP 中文教程📚](https://apachecn.github.io/geeksforgeeks-php-zh)\n    +   [ApacheCN 数据库译文集📚](https://apachecn.github.io/apachecn-db-zh)\n    +   [ApacheCN 数据库译文集（二）📚](https://apachecn.github.io/apachecn-db-zh-pt2)\n    +   [ApacheCN Python Web 译文集📚](https://apachecn.github.io/apachecn-pythonweb-zh)\n    +   [ApacheCN Python Web 译文集（二）📚](https://apachecn.github.io/apachecn-pythonweb-zh-pt2)\n    +   [ApacheCN Asp.NET 译文集📚](https://apachecn.github.io/apachecn-asp-dotnet-zh)\n    +   [ApacheCN Asp.NET 译文集（二）📚](https://apachecn.github.io/apachecn-asp-dotnet-zh-pt2)\n    +   [ApacheCN Asp.NET 译文集（三）📚](https://apachecn.github.io/apachecn-asp-dotnet-zh-pt3)\n    +   [ApacheCN Asp.NET 译文集（四）📚](https://apachecn.github.io/apachecn-asp-dotnet-zh-pt4)\n    +   [ApacheCN NodeJS 译文集📚](https://apachecn.github.io/apachecn-node-zh)\n    +   [ApacheCN NodeJS 译文集（二）📚](https://apachecn.github.io/apachecn-node-zh-pt2)\n    +   [ApacheCN PHP 译文集📚](https://apachecn.github.io/apachecn-php-zh)\n    +   [ApacheCN PHP 译文集（二）📚](https://apachecn.github.io/apachecn-php-zh-pt2)\n    +   [ApacheCN 大数据译文集（二）📚](https://apachecn.github.io/apachecn-bigdata-zh-pt2)\n    +   [ApacheCN 大数据译文集（三）📚](https://apachecn.github.io/apachecn-bigdata-zh-pt3)\n    +   [ApacheCN 大数据译文集📚](https://apachecn.github.io/apachecn-bigdata-zh)\n    +   [ApacheCN Java Web 译文集📚](https://apachecn.github.io/apachecn-javaweb-zh)\n    +   [ApacheCN Java Web 译文集（二）📚](https://apachecn.github.io/apachecn-javaweb-zh-pt2)\n    +   [Airflow 中文文档](https://apachecn.github.io/airflow-doc-zh)\n    +   [Elasticsearch 5.4 中文文档](https://apachecn.github.io/elasticsearch-doc-zh)\n    +   [Flink 中文文档](https://apachecn.github.io/flink-doc-zh)\n    +   [HBase™ 中文参考指南 3.0🚧](https://apachecn.github.io/hbase-doc-zh)\n    +   [HighScalability 中文示例📚🚧](https://apachecn.github.io/highscalability-examples-zh)\n    +   [Kibana 5.2 中文文档](https://apachecn.github.io/kibana-doc-zh)\n    +   [Kudu 1.4.0 中文文档](https://apachecn.github.io/kudu-doc-zh)\n    +   [Apache Spark 官方文档中文版](https://apachecn.github.io/spark-doc-zh)\n    +   [Apache Kafka 官方文档中文版](https://apachecn.github.io/kafka-site-zh)\n    +   [Spring Boot 1.5.2 中文文档](https://apachecn.github.io/spring-boot-doc-zh)\n    +   [Storm 1.1.0 中文文档](https://apachecn.github.io/storm-doc-zh)\n    +   [Zeppelin 0.7.2 中文文档](https://apachecn.github.io/zeppelin-doc-zh)\n+   工具\n    +   [JavaTPoint 实用工具中文教程📚](https://apachecn.github.io/javatpoint-util-zh)\n    +   [ApacheCN DevOps 译文集📚](https://apachecn.github.io/apachecn-devops-zh)\n    +   [ApacheCN DevOps 译文集（二）📚](https://apachecn.github.io/apachecn-devops-zh-pt2)\n    +   [ApacheCN DevOps 译文集（三）📚](https://apachecn.github.io/apachecn-devops-zh-pt3)\n    +   [ApacheCN DevOps 译文集（四）📚](https://apachecn.github.io/apachecn-devops-zh-pt4)\n    +   [ApacheCN DevOps 译文集（五）📚](https://apachecn.github.io/apachecn-devops-zh-pt5)\n    +   [ApacheCN Linux 译文集📚](https://apachecn.github.io/apachecn-linux-zh)\n    +   [ApacheCN Linux 译文集（二）📚](https://apachecn.github.io/apachecn-linux-zh-pt2)\n    +   [ApacheCN Linux 译文集（三）📚](https://apachecn.github.io/apachecn-linux-zh-pt3)\n    +   [Cython 3.0 中文文档🚧](https://apachecn.github.io/cython-doc-zh)\n    +   [Git 中文参考🚧](https://apachecn.github.io/git-doc-zh)\n    +   [Gitlab 中文文档🚧](https://apachecn.github.io/gitlab-doc-zh)\n    +   [笨办法学 Linux 中文版](https://apachecn.github.io/llthw-zh)\n    +   [Numba 0.44 中文文档🚧](https://apachecn.github.io/numba-doc-zh)\n    +   [PyQt4 中文文档🚧](https://apachecn.github.io/pyqt4-doc-zh)\n    +   [Scrapy 1.6 中文文档](https://apachecn.github.io/scrapy-doc-zh)\n+   数据科学\n    +   [ApacheCN 数据科学译文集📚](https://apachecn.github.io/apachecn-ds-zh)\n    +   [ApacheCN 数据科学译文集（二）📚](https://apachecn.github.io/apachecn-ds-zh-pt2)\n    +   [ApacheCN 数据科学译文集（三）📚](https://apachecn.github.io/apachecn-ds-zh-pt3)\n    +   [ApacheCN 数据科学译文集📚](https://apachecn.github.io/apachecn-ds-zh)\n    +   [MIT 18.03 面向初学者的微积分🚧](https://apachecn.github.io/calc4b-zh)\n    +   [UCB Data8 计算与推断思维](https://apachecn.github.io/data8-textbook-zh)\n    +   [数据可视化的基础知识](https://apachecn.github.io/dataviz-zh)\n    +   [数据科学和人工智能技术笔记](https://apachecn.github.io/ds-ai-tech-notes)\n    +   [数据科学 IPython 笔记本📚](https://apachecn.github.io/ds-ipynb-zh)\n    +   [UCB DS100 数据科学的原理与技巧🚧](https://apachecn.github.io/ds100-textbook-zh)\n    +   [ApacheCN 数据科学和人工智能知识库](https://apachecn.github.io/dsai-wiki)\n    +   [Matplotlib 用户指南](https://apachecn.github.io/matplotlib-doc-zh)\n    +   [MIT 18.06 线性代数笔记](https://apachecn.github.io/mit-18.06-linalg-notes)\n    +   [利用 Python 进行数据分析 · 第 2 版](https://apachecn.github.io/pyda-2e-zh)\n    +   [QuantLearning](https://apachecn.github.io/quant-learning)\n    +   [seaborn 0.9 中文文档](https://apachecn.github.io/seaborn-doc-zh)\n    +   [社交媒体挖掘 - 翻译版](https://apachecn.github.io/socialmediamining-zh)\n    +   [斯坦福 Stats60 21 世纪的统计思维🚧](https://apachecn.github.io/stats-thinking-21-zh)\n    +   [复杂性思维 中文第二版](https://apachecn.github.io/think-comp-2e-zh)\n    +   [PyMiner 开发者指南](https://apachecn.github.io/pyminer-dev-guide)\n+   人工智能\n    +   [JavaTPoint 数据科学与人工智能中文教程📚](https://apachecn.github.io/javatpoint-dsai-zh)\n    +   [GeeksForGeeks 人工智能中文教程📚](https://apachecn.github.io/geeksforgeeks-ai-zh)\n    +   [AILearning📚](https://apachecn.github.io/ailearning)\n    +   [ApacheCN 计算机视觉译文集📚](https://apachecn.github.io/apachecn-cv-zh)\n    +   [ApacheCN 计算机视觉译文集（二）📚](https://apachecn.github.io/apachecn-cv-zh-pt2)\n    +   [ApacheCN 深度学习译文集📚](https://apachecn.github.io/apachecn-dl-zh)\n    +   [ApacheCN 深度学习译文集（二）📚](https://apachecn.github.io/apachecn-dl-zh-pt2)\n    +   [ApacheCN 深度学习译文集（三）📚](https://apachecn.github.io/apachecn-dl-zh-pt3)\n    +   [ApacheCN 机器学习译文集📚](https://apachecn.github.io/apachecn-ml-zh)\n    +   [ApacheCN 机器学习译文集（二）📚](https://apachecn.github.io/apachecn-ml-zh-pt2)\n    +   [ApacheCN 机器学习译文集（三）📚](https://apachecn.github.io/apachecn-ml-zh-pt3)\n    +   [FastText 中文文档](https://apachecn.github.io/fasttext-doc-zh)\n    +   [面向机器学习的特征工程](https://apachecn.github.io/fe4ml-zh)\n    +   [Gensim 中文文档](https://apachecn.github.io/gensim-doc-zh)\n    +   [Sklearn 与 TensorFlow 机器学习实用指南第二版](https://apachecn.github.io/hands-on-ml-2e-zh)\n    +   [LightGBM 中文文档](https://apachecn.github.io/lightgbm-doc-zh)\n    +   [Machine Learning Mastery 博客文章翻译📚🚧](https://apachecn.github.io/ml-mastery-zh)\n    +   [Machine Learning Mastery 博客文章翻译（二）📚🚧](https://apachecn.github.io/ml-mastery-zh-pt2)\n    +   [Python 自然语言处理 第二版](https://apachecn.github.io/nlp-py-2e-zh)\n    +   [PyTorch 自然语言处理](https://apachecn.github.io/nlp-pytorch-zh)\n    +   [台湾大学林轩田机器学习笔记](https://apachecn.github.io/ntu-hsuantienlin-ml)\n    +   [OpenCV 中文文档 4.0.0](https://apachecn.github.io/opencv-doc-zh)\n    +   [PythonProgramming.net 系列教程📚](https://apachecn.github.io/python-programming-net-zh)\n    +   [PyTorch 中文教程](https://apachecn.github.io/pytorch-doc-zh)\n    +   [scikit-learn (sklearn) 官方文档中文版](https://apachecn.github.io/sklearn-doc-zh)\n    +   [XGBoost 中文文档](https://apachecn.github.io/xgboost-doc-zh)\n+   计算机科学\n    +   [JavaTPoint 计算机科学中文教程📚](https://apachecn.github.io/javatpoint-cs-zh)\n    +   [ApacheCN 数据结构与算法译文集📚](https://apachecn.github.io/apachecn-algo-zh)\n    +   [ApacheCN 计算机系统译文集📚](https://apachecn.github.io/apachecn-sys-zh)\n    +   [NUS CS1101s SICP JavaScript 描述🚧](https://apachecn.github.io/sicp-js-zh)\n    +   [UCB CS61a SICP Python 描述](https://apachecn.github.io/sicp-py-zh)\n    +   [数据结构思维中文版](https://apachecn.github.io/think-dast-zh)\n    +   [UIUC CS241 系统编程中文讲义🚧](https://apachecn.github.io/uiuc-cs241-notes-zh)\n+   安全\n    +   [ApacheCN Kali Linux 译文集📚](https://apachecn.github.io/apachecn-kali-zh)\n    +   [ApacheCN 网络安全译文集📚](https://apachecn.github.io/apachecn-sec-zh)\n    +   [ApacheCN 网络安全译文集（二）📚](https://apachecn.github.io/apachecn-sec-zh-pt2)\n    +   [SecLearning——零组文库备份📚](https://apachecn.github.io/sec-learning)\n    +   [ApacheCN 安全知识库📚](https://apachecn.github.io/sec-wiki)\n    +   [Web Hacking 101 中文版](https://apachecn.github.io/web-hacking-101-zh)\n+   其它\n    +   [生化环材劝退文集](https://apachecn.github.io/bio-chem-env-mat-discourage)\n    +   [5 分钟商学院精细笔记](https://apachecn.github.io/business-5min-notes)\n    +   [iBooker 布客](https://apachecn.github.io/home)\n    +   [iBooker 布客老实人报](https://apachecn.github.io/ibooker-plain-dealer)\n    +   [使用 Qiskit 学习量子计算 - 翻译版](https://apachecn.github.io/lqcuq-zh)\n    +   [原则 · 中文版](https://apachecn.github.io/principles-zh)\n    +   [斯坦福 CS183 & YC 创业课系列中文笔记📚](https://apachecn.github.io/stanford-cs183-notes)\n    +   [iBooker 团队知识库📚](https://apachecn.github.io/team-wiki)\n    +   [ApacheCN 技术评论](https://apachecn.github.io/tech-review)\n    +   [通往财富自由之路精细笔记](https://apachecn.github.io/the-way-to-wealth-freedom-notes)\n"
  },
  {
    "path": "README.md",
    "content": "# ApacheCN 数据结构与算法译文集\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n> \n> 程序员的双手是魔术师的双手，他们把枯燥无味的代码变成了丰富多彩的软件。——《疯狂的程序员》\n\n* [在线阅读](https://algo.apachecn.org)\n* [在线阅读（Gitee）](https://apachecn.gitee.io/apachecn-algo-zh/)\n* [ApacheCN 学习资源](http://docs.apachecn.org/)\n\n## 目录\n\n+   [数据结构思维中文版](docs/think-dast-zh/SUMMARY.md)\n+   [Leetcode C++ 题解](docs/leetcode/cpp/SUMMARY.md)\n+   [Leetcode Java 题解](docs/leetcode/java/SUMMARY.md)\n+   [Leetcode JavaScript 题解](docs/leetcode/javascript/SUMMARY.md)\n+   [Leetcode Python 题解](docs/leetcode/python/SUMMARY.md)\n+   [剑指 Offer Java 题解](docs/jianzhioffer/java/SUMMARY.md)\n\n## 贡献指南\n\n为了不断改进翻译质量，我们特此启动了【翻译、校对、笔记整理活动】，开设了多个校对项目。贡献者校对一章之后可以领取千字2\\~4元的奖励。进行中的校对活动请见[活动列表](https://home.apachecn.org/#/docs/activity/docs-activity)。更多详情请联系飞龙（Q562826179，V:wizardforcel）。\n\n## 联系方式\n\n### 负责人\n\n* [飞龙](https://github.com/wizardforcel): 562826179\n\n### 其他\n\n*   在我们的 [apachecn/apachecn-algo-zh](https://github.com/apachecn/apachecn-algo-zh) github 上提 issue.\n*   发邮件到 Email: `apachecn@163.com`.\n*   在我们的 [组织学习交流群](http://www.apachecn.org/organization/348.html) 中联系群主/管理员即可.\n\n## 下载\n\n### Docker\n\n```\ndocker pull apachecn0/apachecn-algo-zh\ndocker run -tid -p <port>:80 apachecn0/apachecn-algo-zh\n# 访问 http://localhost:{port} 查看文档\n```\n\n### PYPI\n\n```\npip install apachecn-algo-zh\napachecn-algo-zh <port>\n# 访问 http://localhost:{port} 查看文档\n```\n\n### NPM\n\n```\nnpm install -g apachecn-algo-zh\napachecn-algo-zh <port>\n# 访问 http://localhost:{port} 查看文档\n```\n\n## 赞助我们\n\n![](http://data.apachecn.org/img/about/donate.jpg)\n"
  },
  {
    "path": "SUMMARY.md",
    "content": "+   [数据结构思维中文版](docs/think-dast-zh/README.md)\n    +   [前言](docs/think-dast-zh/0.md)\n    +   [第一章 接口](docs/think-dast-zh/1.md)\n    +   [第二章 算法分析](docs/think-dast-zh/2.md)\n    +   [第三章 `ArrayList`](docs/think-dast-zh/3.md)\n    +   [第四章 `LinkedList`](docs/think-dast-zh/4.md)\n    +   [第五章 双链表](docs/think-dast-zh/5.md)\n    +   [第六章 树的遍历](docs/think-dast-zh/6.md)\n    +   [第七章 到达哲学](docs/think-dast-zh/7.md)\n    +   [第八章 索引器](docs/think-dast-zh/8.md)\n    +   [第九章 `Map`接口](docs/think-dast-zh/9.md)\n    +   [第十章 哈希](docs/think-dast-zh/10.md)\n    +   [第十一章 `HashMap`](docs/think-dast-zh/11.md)\n    +   [第十二章 `TreeMap`](docs/think-dast-zh/12.md)\n    +   [第十三章 二叉搜索树](docs/think-dast-zh/13.md)\n    +   [第十四章 持久化](docs/think-dast-zh/14.md)\n    +   [第十五章 爬取维基百科](docs/think-dast-zh/15.md)\n    +   [第十六章 布尔搜索](docs/think-dast-zh/16.md)\n    +   [第十七章 排序](docs/think-dast-zh/17.md)\n+   [Leetcode C++ 题解](docs/leetcode/cpp/README.md)\n    +   [1. Two Sum](docs/leetcode/cpp/0001._Two_Sum.md)\n    +   [2. Add Two Numbers](docs/leetcode/cpp/0002._Add_Two_Numbers.md)\n    +   [3. Longest Substring Without Repeating Characters](docs/leetcode/cpp/0003._Longest_Substring_Without_Repeating_Characters.md)\n    +   [004. Median of Two Sorted Arrays](docs/leetcode/cpp/0004._Median_of_Two_Sorted_Arrays.md)\n    +   [5. Longest Palindromic Substring](docs/leetcode/cpp/0005._Longest_Palindromic_Substring.md)\n    +   [6. ZigZag Conversion](docs/leetcode/cpp/0006._ZigZag_Conversion.md)\n    +   [7. Reverse Integer](docs/leetcode/cpp/0007._Reverse_Integer.md)\n    +   [8. String to Integer (atoi)](docs/leetcode/cpp/0008._String_to_Integer_(atoi).md)\n    +   [9. Palindrome Number](docs/leetcode/cpp/0009._Palindrome_Number.md)\n    +   [10. Regular Expression Matching](docs/leetcode/cpp/0010._Regular_Expression_Matching.md)\n    +   [11. container with most water](docs/leetcode/cpp/0011._Container_With_Most_Water.md)\n    +   [12. Integer to Roman](docs/leetcode/cpp/0012._Integer_to_Roman.md)\n    +   [14. Longest Common Prefix](docs/leetcode/cpp/0014._Longest_Common_Prefix.md)\n    +   [15. 3sum](docs/leetcode/cpp/0015._3sum.md)\n    +   [16. 3Sum Closest](docs/leetcode/cpp/0016._3Sum_Closest.md)\n    +   [17. Letter Combinations of a Phone Number](docs/leetcode/cpp/0017._Letter_Combinations_of_a_Phone_Number.md)\n    +   [18. 4Sum](docs/leetcode/cpp/0018._4Sum.md)\n    +   [19. Remove Nth Node From End of List](docs/leetcode/cpp/0019._Remove_Nth_Node_From_End_of_List.md)\n    +   [20. Valid Parentheses](docs/leetcode/cpp/0020._Valid_Parentheses.md)\n    +   [21. Merge Two Sorted Lists](docs/leetcode/cpp/0021._Merge_Two_Sorted_Lists.md)\n    +   [22. Generate Parentheses](docs/leetcode/cpp/0022._Generate_Parentheses.md)\n    +   [23. merge k sorted lists](docs/leetcode/cpp/0023._Merge_K_Sorted_Lists.md)\n    +   [24. Swap Nodes in Pairs](docs/leetcode/cpp/0024._Swap_Nodes_in_Pairs.md)\n    +   [25.reverse nodes in k group](docs/leetcode/cpp/0025._Reverse_Nodes_In_K_Group.md)\n    +   [26.Remove Duplicates From Sorted Array](docs/leetcode/cpp/0026._Remove_Duplicates_From_Sorted_Array.md)\n    +   [27.Remove Element](docs/leetcode/cpp/0027._Remove_Element.md)\n    +   [28.implement strstr](docs/leetcode/cpp/0028._Implement_Strstr.md)\n    +   [29.divide two integers](docs/leetcode/cpp/0029._Divide_Two_Integers.md)\n    +   [30.substring with concatenation of all words](docs/leetcode/cpp/0030._Substring_With_Concatenation_Of_All_Words.md)\n    +   [31.Next Permutatio](docs/leetcode/cpp/0031._Next_Permutatio.md)\n    +   [32. Longest Valid Parentheses](docs/leetcode/cpp/0032._Longest_Valid_Parentheses.md)\n    +   [033. Search in Rotated Sorted Array](docs/leetcode/cpp/0033._Search_in_Rotated_Sorted_Array.md)\n    +   [34. Find First and Last Position of Element in Sorted Array](docs/leetcode/cpp/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md)\n    +   [???????](docs/leetcode/cpp/0035._Search_Insert_Position.md)\n    +   [36. Valid Sudoku](docs/leetcode/cpp/0036._Valid_Sudoku.md)\n    +   [38. Count and Say](docs/leetcode/cpp/0038._Count_and_Say.md)\n    +   [39. Combination Sum](docs/leetcode/cpp/0039._Combination_Sum.md)\n    +   [40. Combination Sum II](docs/leetcode/cpp/0040._Combination_Sum_II.md)\n    +   [041.First Missing Positive](docs/leetcode/cpp/0041._First_Missing_Positive.md)\n    +   [42. Trapping Rain Water](docs/leetcode/cpp/0042._Trapping_Rain_Water.md)\n    +   [43. Multiply Strings](docs/leetcode/cpp/0043._Multiply_Strings.md)\n    +   [44. Wildcard Matching](docs/leetcode/cpp/0044._Wildcard_Matching.md)\n    +   [045. Jump Game II](docs/leetcode/cpp/0045._Jump_Game_II.md)\n    +   [46. Permutations](docs/leetcode/cpp/0046._Permutations.md)\n    +   [47. Permutations II](docs/leetcode/cpp/0047._Permutations_II.md)\n    +   [49. Group Anagrams](docs/leetcode/cpp/0048._Rotate_Image.md)\n    +   [49. Group Anagrams](docs/leetcode/cpp/0049._Group_Anagrams.md)\n    +   [50. powx n](docs/leetcode/cpp/0050._powx_n.md)\n    +   [51. N-Queens](docs/leetcode/cpp/0051._N-Queens.md)\n    +   [52. N-Queens II](docs/leetcode/cpp/0052._N-Queens_II.md)\n    +   [053. Maximum Subarray](docs/leetcode/cpp/0053._Maximum_Subarray.md)\n    +   [54. Spiral Matrix](docs/leetcode/cpp/0054._Spiral_Matrix.md)\n    +   [55. Jump Game](docs/leetcode/cpp/0055._Jump_Game.md)\n    +   [56. Merge Intervals](docs/leetcode/cpp/0056._Merge_Intervals.md)\n    +   [57. Insert Interval](docs/leetcode/cpp/0057._Insert_Interval.md)\n    +   [058. Length of Last Word](docs/leetcode/cpp/0058._Length_of_Last_Word.md)\n    +   [59. Spiral Matrix II](docs/leetcode/cpp/0059._Spiral_Matrix_II.md)\n    +   [60. Permutation Sequence](docs/leetcode/cpp/0060._Permutation_Sequence.md)\n    +   [61. Rotate List](docs/leetcode/cpp/0061._Rotate_List.md)\n    +   [62. Unique Paths](docs/leetcode/cpp/0062._Unique_Paths.md)\n    +   [63. Unique Paths II](docs/leetcode/cpp/0063._Unique_Paths_II.md)\n    +   [64. Minimum Path Sum](docs/leetcode/cpp/0064._Minimum_Path_Sum.md)\n    +   [65. Valid Number](docs/leetcode/cpp/0065._Valid_Number.md)\n    +   [66. Plus One](docs/leetcode/cpp/0066._Plus_One.md)\n    +   [68. Text Justification](docs/leetcode/cpp/0068._Text_Justification.md)\n    +   [69. Sqrt(x)](docs/leetcode/cpp/0069._Sqr(x).md)\n    +   [72. Edit Distance](docs/leetcode/cpp/0072._Edit_Distance.md)\n    +   [75. Sort Colors](docs/leetcode/cpp/0075._Sort_Colors.md)\n    +   [76. Minimum Window Substring](docs/leetcode/cpp/0076._Minimum_Window_Substring.md)\n    +   [77. Combinations](docs/leetcode/cpp/0077._combinations.md)\n    +   [78. Subsets](docs/leetcode/cpp/0078._subsets.md)\n    +   [81. Search in Rotated Sorted Array II](docs/leetcode/cpp/0081._Search_in_Rotated_Sorted_Array_II.md)\n    +   [???????](docs/leetcode/cpp/0083._Remove_Duplicates_From_Sorted_Lists.md)\n    +   [84. Largest Rectangle in Histogram](docs/leetcode/cpp/0084._Largest_Rectangle_in_Histogram.md)\n    +   [85. Maximal Rectangle](docs/leetcode/cpp/0085._Maximal_Rectangle.md)\n    +   [87. Scramble String](docs/leetcode/cpp/0087._Scramble_String.md)\n    +   [88.Merge Sorted Array](docs/leetcode/cpp/0088._Merge_Sorted_Array.md)\n    +   [90. Subsets II](docs/leetcode/cpp/0090._Subsets_II.md)\n    +   [94. Binary Tree Inorder Traversal](docs/leetcode/cpp/0094._binary_tree_inorder_traversal.md)\n    +   [96. Unique Binary Search Trees](docs/leetcode/cpp/0096._Unique_Binary_Search_Trees.md)\n    +   [97. Interleaving String](docs/leetcode/cpp/0097._Interleaving_String.md)\n    +   [99. Recover Binary Search Tree](docs/leetcode/cpp/0099._Recover_Binary_Search_Tree.md)\n    +   [100. same tree](docs/leetcode/cpp/0100._same_tree.md)\n    +   [101. Symmetric Tree](docs/leetcode/cpp/0101._Symmetric_Tree.md)\n    +   [102. Binary Tree Level Order Traversal](docs/leetcode/cpp/0102._Binary_Tree_Level_Order_Traversal.md)\n    +   [104. Maximum Depth of Binary Tree](docs/leetcode/cpp/0104._Maximum_Depth_of_Binary_Tree.md)\n    +   [105. Construct Binary Tree from Preorder and Inorder Traversal](docs/leetcode/cpp/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md)\n    +   [106. Construct Binary Tree from Inorder and Postorder Traversal](docs/leetcode/cpp/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md)\n    +   [107.Binary Tree Level Order Traversal II](docs/leetcode/cpp/0107._Binary_Tree_Level_Order_Traversal_II.md)\n    +   [108. Convert Sorted Array to Binary Search Tree](docs/leetcode/cpp/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md)\n    +   [109. Convert Sorted List to Binary Search Tree](docs/leetcode/cpp/0109._Convert_Sorted_List_to_Binary_Search_Tree.md)\n    +   [110.Balanced Binary Tree](docs/leetcode/cpp/0110._Balanced_Binary_Tree.md)\n    +   [111. Minimum Depth of Binary Tree](docs/leetcode/cpp/0111._Minimum_Depth_Of_Binary_Tree.md)\n    +   [112. Path Sum](docs/leetcode/cpp/0112._Path_Sum.md)\n    +   [114. Flatten Binary Tree to Linked List](docs/leetcode/cpp/0114._Flatten_Binary_Tree_to_Linked_List.md)\n    +   [115.Distinct Subsequences](docs/leetcode/cpp/0115._Distinct_Subsequences.md)\n    +   [118. Pascal's Triangle](docs/leetcode/cpp/0118._Pascals_Triangle.md)\n    +   [119. Pascal's Triangle II](docs/leetcode/cpp/0119._Pascals_Triangle-II.md)\n    +   [120. Triangle](docs/leetcode/cpp/0120._Triangle.md)\n    +   [121. Best Time to Buy and Sell Stock](docs/leetcode/cpp/0121._Best_Tim_to_Buy_and_Sell_Stock.md)\n    +   [122. Best Time to Buy and Sell Stock II](docs/leetcode/cpp/0122._Best_Time_to_Buy_and_Sell_Stock_II.md)\n    +   [123. Best Time to Buy and Sell Stock III](docs/leetcode/cpp/0123._Best_Time_to_Buy_and_Sell_Stock_III.md)\n    +   [124. Binary Tree Maximum Path Sum](docs/leetcode/cpp/0124._Binary_Tree_Maximum_Path_Sum.md)\n    +   [127. Word Ladder](docs/leetcode/cpp/0127._Word_Ladde.md)\n    +   [128. Longest Consecutive Sequence](docs/leetcode/cpp/0128._Longest_Consecutive_Sequence.md)\n    +   [129. Sum Root to Leaf Numbers](docs/leetcode/cpp/0129._Sum_Root_to_Leaf_Numbers.md)\n    +   [131. Palindrome Paritionaing](docs/leetcode/cpp/0131._Palindrome_Partitioning.md)\n    +   [136. Single Numbe](docs/leetcode/cpp/0136._Single_Numbe.md)\n    +   [137.Single Number II](docs/leetcode/cpp/0137._Single_Number_II.md)\n    +   [???????](docs/leetcode/cpp/0141._Linked_List_Cycle.md)\n    +   [142. linked list cycle II](docs/leetcode/cpp/0142._Linked_List_Cycle_II.md)\n    +   [144. Binary Tree Preorder Traversal](docs/leetcode/cpp/0144._Binary_Tree_Preorder_Traversal.md)\n    +   [145. Binary Tree Postorder Traversal](docs/leetcode/cpp/0145._Binary_Tree_Postorder_Traversal.md)\n    +   [147. Insertion Sort List](docs/leetcode/cpp/0147._Insert_on_Sort_List.md)\n    +   [148.Sort list](docs/leetcode/cpp/0148._Sort_list.md)\n    +   [151. Reverse Words in a String](docs/leetcode/cpp/0151._Reverse_Words_in_a_String.md)\n    +   [153. Find Minimum in Rotated Sorted Array](docs/leetcode/cpp/0153._Find_Minimum_in_Rotated_Sorted_Array.md)\n    +   [154. Find Minimum in Rotated Sorted Array II](docs/leetcode/cpp/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md)\n    +   [160 intersection_of_Two_Linked_Lists](docs/leetcode/cpp/0160._Intersection_Of_Two_Linked_Lists.md)\n    +   [164. Maximum Gap](docs/leetcode/cpp/0164._Maximum_Gap.md)\n    +   [166. Fraction to Recurring Decimal](docs/leetcode/cpp/0166._Fraction_to_Recurring_Decimal.md)\n    +   [167. Two Sum II - Input array is sorted](docs/leetcode/cpp/0167._Two_Sum_II-Input_array_is_sorted.md)\n    +   [199. Binary Tree Right Side View](docs/leetcode/cpp/0199._Binary_Tree_Right_Side_View.md)\n    +   [216. Combination Sum III](docs/leetcode/cpp/0216._Combination_Sum_III.md)\n    +   [230. Kth Smallest Element in a BST](docs/leetcode/cpp/0230._Kth_Smallest_Element_in_a_BST.md)\n    +   [260. Single Number III](docs/leetcode/cpp/0260._Single_Number_III.md)\n    +   [287. Find the Duplicate Number](docs/leetcode/cpp/0287._Find_the_Duplicate_Number.md)\n    +   [326. Power_of_Three](docs/leetcode/cpp/0326._Power_Of_Three.md)\n    +   [328. Odd Even Linked List](docs/leetcode/cpp/0328._Odd_Even_Linked_List.md)\n    +   [329. Longest Increasing Path in a Matrix](docs/leetcode/cpp/0329._Longest_Increasing_Path_in_a_Matrix.md)\n    +   [338. Counting Bits ](docs/leetcode/cpp/0338._Counting_Bits.md)\n    +   [413. Arithmetic Slices](docs/leetcode/cpp/0413._Arithmetic_Slices.md)\n    +   [442. Find All Duplicates in an Array](docs/leetcode/cpp/0442._Find_All_Duplicates_in_an_Array.md)\n    +   [513. Find Bottom Left Tree Value](docs/leetcode/cpp/0513._Find_Bottom_Left_Tree_Value.md)\n    +   [515. Find Largest Value in Each Tree Row](docs/leetcode/cpp/0515._Find_Largest_Value_in_Each_Tree_Row.md)\n    +   [540. Single Element in a Sorted Array](docs/leetcode/cpp/0540._Single_Element_in_a_Sorted_Array.md)\n    +   [581. Shortest Unsorted Continuous Subarray](docs/leetcode/cpp/0581._Shortest_Unsorted_Continuous_Subarray.md)\n    +   [793. K Inverse Pairs Array](docs/leetcode/cpp/0629._K_Inverse_Pairs_Array.md)\n    +   [632. Smallest Range](docs/leetcode/cpp/0632._Smallest_Range.md)\n    +   [654. Maximum Binary Tree ](docs/leetcode/cpp/0654._maximum_binary_tree.md)\n    +   [668. Kth Smallest Number in Multiplication Table](docs/leetcode/cpp/0668._Kth_Smallest_Number_in_Multiplication_Table.md)\n    +   [701. Insert into a Binary Search Tree](docs/leetcode/cpp/0701._Insert_into_a_Binary_Search_Tree.md)\n    +   [715. Range Module](docs/leetcode/cpp/0715._Range_Module.md)\n    +   [793. Find K-th Smallest Pair Distance](docs/leetcode/cpp/0719._Find_K-th_Smallest_Pair_Distance.md)\n    +   [739. Daily Temperatures](docs/leetcode/cpp/0739._Daily_Temperatures.md)\n    +   [797. All Paths From Source to Target](docs/leetcode/cpp/0797._All_Paths_From_Source_To_Target.md)\n    +   [814. Binary Tree Pruning](docs/leetcode/cpp/0814._Binary_Tree_Pruning.md)\n    +   [841. Keys and Rooms](docs/leetcode/cpp/0841._Keys_and_Rooms.md)\n    +   [877. Stone Game](docs/leetcode/cpp/0877._Stone_Game.md)\n    +   [945. Minimum Increment to Make Array Unique](docs/leetcode/cpp/0945._Minimum_Increment_to_Make_Array_Unique.md)\n    +   [946. Validate Stack Sequences](docs/leetcode/cpp/0946._Validate_Stack_Sequences.md)\n    +   [947. Most Stones Removed with Same Row or Column](docs/leetcode/cpp/0947._Most_Stones_Removed_with_Same_Row_or_Column.md)\n    +   [948. Bag of Tokens](docs/leetcode/cpp/0948._Bag_of_Tokens.md)\n    +   [949. Largest Time for Given Digits](docs/leetcode/cpp/0949._Largest_Time_for_Given_Digits.md)\n    +   [950. Reveal Cards In Increasing Order](docs/leetcode/cpp/0950._Reveal_Cards_In_Increasing_Order.md)\n    +   [951. Flip Equivalent Binary Trees](docs/leetcode/cpp/0951._Flip_Equivalent_Binary_Trees.md)\n    +   [952. Largest Component Size by Common Factor](docs/leetcode/cpp/0952._Largest_Component_Size_by_Common_Factor.md)\n+   [Leetcode Java 题解](docs/leetcode/java/README.md)\n    +   [1. Two Sum](docs/leetcode/java/0001._Two_Sum.md)\n    +   [2. Add Two Numbers](docs/leetcode/java/0002._add_two_numbers.md)\n    +   [3. Longest Substring Without Repeating Characters](docs/leetcode/java/0003._Longest_Substring_Without_Repeating_Characters.md)\n    +   [4. Median of Two Sorted Arrays](docs/leetcode/java/0004._Median_of_Two_Sorted_Arrays.md)\n    +   [5. Longest Palindromic Substring](docs/leetcode/java/0005._Longest_Palindromic_Substring.md)\n    +   [6. ZigZag Conversion](docs/leetcode/java/0006._ZigZag_Conversion.md)\n    +   [7. Reverse Integer](docs/leetcode/java/0007._Reverse_Integer.md)\n    +   [23. Merge K Sorted Lists](docs/leetcode/java/0023._Merge_K_Sorted_Lists.md)\n    +   [141. Linked List Cycle](docs/leetcode/java/0141._linked_list_cycle.md)\n    +   [218. The Skyline Problem](docs/leetcode/java/0218._The_Skyline_Problem.md)\n    +   [238. Product of Array Except Self](docs/leetcode/java/0238._product_of_array_except_self.md)\n    +   [342. Power of Four](docs/leetcode/java/0342._Power_of_Four.md)\n    +   [403. Frog Jump](docs/leetcode/java/0403._Frog_Jump.md)\n    +   [757. Set Intersection Size At Least Two](docs/leetcode/java/0757._Set_Intersection_Size_At_Least_Two.md)\n    +   [768. Max Chunks To Make Sorted II](docs/leetcode/java/0768._Max_Chunks_To_Make_Sorted_II.md)\n    +   [780. Reaching Points](docs/leetcode/java/0780._Reaching_Points.md)\n    +   [793. Preimage Size of Factorial Zeroes Function](docs/leetcode/java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md)\n    +   [827. Making A Large Island](docs/leetcode/java/0827._Making_A_Large_Island.md)\n    +   [828. Unique Letter String](docs/leetcode/java/0828._Unique_Letter_String.md)\n    +   [834. Sum of Distances in Tree](docs/leetcode/java/0834._Sum_of_Distances_in_Tree.md)\n    +   [843. Guess the Word](docs/leetcode/java/0843._Guess_the_Word.md)\n    +   [847. Shortest Path Visiting All Nodes](docs/leetcode/java/0847._Shortest_Path_Visiting_All_Nodes.md)\n    +   [850. Rectangle Area II](docs/leetcode/java/0850._Rectangle_Area_II.md)\n    +   [854. K-Similar Strings](docs/leetcode/java/0854._K-Similar_Strings.md)\n    +   [857. Minimum Cost to Hire K Workers](docs/leetcode/java/0857._Minimum_Cost_to_Hire_K_Workers.md)\n    +   [862. Shortest Subarray with Sum at Least K](docs/leetcode/java/0862._Shortest_Subarray_with_Sum_at_Least_K.md)\n    +   [864. Shortest Path to Get All Keys](docs/leetcode/java/0864._Shortest_Path_to_Get_All_Keys.md)\n    +   [871. Minimum Number of Refueling Stops](docs/leetcode/java/0871._Minimum_Number_of_Refueling_Stops.md)\n    +   [878. Nth Magical Number](docs/leetcode/java/0878._Nth_Magical_Number.md)\n    +   [879. Profitable Schemes](docs/leetcode/java/0879._Profitable_Schemes.md)\n    +   [899. Reachable Nodes In Subdivided Graph](docs/leetcode/java/0882._Reachable_Nodes_In_Subdivided_Graph.md)\n    +   [887. Super Egg Drop](docs/leetcode/java/0887._Super_Egg_Drop.md)\n    +   [891. Sum of Subsequence Widths](docs/leetcode/java/0891._Sum_of_Subsequence_Widths.md)\n    +   [895. Maximum Frequency Stack](docs/leetcode/java/0895._Maximum_Frequency_Stack.md)\n    +   [899. Orderly Queue](docs/leetcode/java/0899._Orderly_Queue.md)\n    +   [902. Numbers At Most N Given Digit Set](docs/leetcode/java/0902._Numbers_At_Most_N_Given_Digit_Set.md)\n    +   [903. Valid Permutations for DI Sequence](docs/leetcode/java/0903._Valid_Permutations_for_DI_Sequence.md)\n    +   [906. Super Palindromes](docs/leetcode/java/0906._Super_Palindromes.md)\n    +   [913. Cat and Mouse](docs/leetcode/java/0913._Cat_and_Mouse.md)\n    +   [920. Number of Music Playlists](docs/leetcode/java/0920._Number_of_Music_Playlists.md)\n+ [Leetcode JavaScript 题解](docs/leetcode/javascript/README.md)\n    + [0001 Two Sum](docs/leetcode/javascript/0001._Two_Sum.md)\n    + [0002 Add Two Numbers](docs/leetcode/javascript/0002._Add_Two_Numbers.md)\n    + [0003 Longest Substring without Repeating Characters](docs/leetcode/javascript/0003._Longest_Substring_without_Repeating_Characters.md)\n    + [0007 Reverse Integer](docs/leetcode/javascript/0007._Reverse_Integer.md)\n    + [0008 String to Integer](docs/leetcode/javascript/0008._String_to_Integer.md)\n    + [0009 Palindrome Number](docs/leetcode/javascript/0009._Palindrome_Number.md)\n    + [0011 Container With Most Water](docs/leetcode/javascript/0011._Container_With_Most_Water.md)\n    + [0012 Integer To Roman](docs/leetcode/javascript/0012._Integer_To_Roman.md)\n    + [0013 Roman To Integer](docs/leetcode/javascript/0013._Roman_To_Integer.md)\n    + [0014 Longest Common Prefix](docs/leetcode/javascript/0014._Longest_Common_Prefix.md)\n    + [0015 Three Sum](docs/leetcode/javascript/0015._Three_Sum.md)\n    + [0016 3 Sum Closest](docs/leetcode/javascript/0016._3_Sum_Closest.md)\n    + [0017 Letter Combinations Of A Phone Number](docs/leetcode/javascript/0017._Letter_Combinations_Of_A_Phone_Number.md)\n    + [0019 Remove Nth Node From End Of List](docs/leetcode/javascript/0019._Remove_Nth_Node_From_End_Of_List.md)\n    + [0020 Valid Parentheses](docs/leetcode/javascript/0020._Valid_Parentheses.md)\n    + [0021 Merge Two Sorted Lists](docs/leetcode/javascript/0021._Merge_Two_Sorted_Lists.md)\n    + [0022 Generate Parentheses](docs/leetcode/javascript/0022._Generate_Parentheses.md)\n    + [0024 Swap Nodes In Pairs](docs/leetcode/javascript/0024._Swap_Nodes_In_Pairs.md)\n    + [0027 Remove Element](docs/leetcode/javascript/0027._Remove_Element.md)\n    + [0031 Next Permutation](docs/leetcode/javascript/0031._Next_Permutation.md)\n    + [0035 Search Insert Position](docs/leetcode/javascript/0035._Search_Insert_Position.md)\n    + [0054 Spiral Matrix](docs/leetcode/javascript/0054._Spiral_Matrix.md)\n    + [0055 Jump Game](docs/leetcode/javascript/0055._Jump_Game.md)\n    + [0056 Merge Intervals](docs/leetcode/javascript/0056._Merge_Intervals.md)\n    + [0058 Length of Last Word](docs/leetcode/javascript/0058._Length_of_Last_Word.md)\n    + [0061 Rotate List](docs/leetcode/javascript/0061._Rotate_List.md)\n    + [0062 Unique Paths](docs/leetcode/javascript/0062._Unique_Paths.md)\n    + [0066 Plus One](docs/leetcode/javascript/0066._Plus_One.md)\n    + [0067 Add Binary](docs/leetcode/javascript/0067._Add_Binary.md)\n    + [0074 Search a 2D Matrix](docs/leetcode/javascript/0074._Search_a_2D_Matrix.md)\n    + [0079 Search Word](docs/leetcode/javascript/0079._Search_Word.md)\n    + [0083 Remove Duplicates From Sorted List](docs/leetcode/javascript/0083._Remove_Duplicates_From_Sorted_List.md)\n    + [0094 Binary Tree Inorder Traversal](docs/leetcode/javascript/0094._Binary_Tree_Inorder_Traversal.md)\n    + [0098 Validate Binary Search Tree](docs/leetcode/javascript/0098._Validate_Binary_Search_Tree.md)\n    + [0100 Same Tree](docs/leetcode/javascript/0100._Same_Tree.md)\n    + [0101 Symmetric Tree](docs/leetcode/javascript/0101._Symmetric_Tree.md)\n    + [0104 Maximum Depth of Binary Tree](docs/leetcode/javascript/0104._Maximum_Depth_of_Binary_Tree.md)\n    + [0106 Construct Binary Tree From Inorder And Postorder Traversal](docs/leetcode/javascript/0106._Construct_Binary_Tree_From_Inorder_And_Postorder_Traversal.md)\n    + [0141 Linked List Cycle](docs/leetcode/javascript/0141._Linked_List_Cycle.md)\n    + [0146 LRU Cache](docs/leetcode/javascript/0146._LRU_Cache.md)\n    + [0167 Two Sum II - Input array is sorted](docs/leetcode/javascript/0167._Two_Sum_II_-_Input_array_is_sorted.md)\n    + [0167 Two Sum II Input Array is Sorted](docs/leetcode/javascript/0167._Two_Sum_II_Input_Array_is_Sorted.md)\n    + [0171 Excel Sheet Column Number](docs/leetcode/javascript/0171._Excel_Sheet_Column_Number.md)\n    + [0179 Largest Number](docs/leetcode/javascript/0179._Largest_Number.md)\n    + [0203 Remove Linked List Elements](docs/leetcode/javascript/0203._Remove_Linked_List_Elements.md)\n    + [0206 Reverse-Linked-List](docs/leetcode/javascript/0206._Reverse-Linked-List.md)\n    + [0209 Minimum Size Subarray Sum](docs/leetcode/javascript/0209._Minimum_Size_Subarray_Sum.md)\n    + [0258 Add Digits](docs/leetcode/javascript/0258._Add_Digits.md)\n    + [0347 Top K Frequent Elements](docs/leetcode/javascript/0347._Top_K_Frequent_Elements.md)\n    + [0402 Remove K Digits](docs/leetcode/javascript/0402._Remove_K_Digits.md)\n    + [0406 Queue Reconstruction By Height](docs/leetcode/javascript/0406._Queue_Reconstruction_By_Height.md)\n    + [0485 Max Consecutive Ones](docs/leetcode/javascript/0485._Max_Consecutive_Ones.md)\n    + [0539 Minimum Time Difference](docs/leetcode/javascript/0539._Minimum_Time_Difference.md)\n    + [0581 Shortest Unsorted Continuous Subarray](docs/leetcode/javascript/0581._Shortest_Unsorted_Continuous_Subarray.md)\n    + [0881 Boats to Save People](docs/leetcode/javascript/0881._Boats_to_Save_People.md)\n    + [0997 Find The Town Judge](docs/leetcode/javascript/0997._Find_The_Town_Judge.md)\n    + [1130 Minimum Cost Tree From Leaf Values](docs/leetcode/javascript/1130._Minimum_Cost_Tree_From_Leaf_Values.md)\n+   [Leetcode Python 题解](docs/leetcode/python/README.md)\n    +   [001 two sum](docs/leetcode/python/001._two_sum.md)\n    +   [002 add two numbers](docs/leetcode/python/002._add_two_numbers.md)\n    +   [003 longest substring without repeating characters](docs/leetcode/python/003._longest_substring_without_repeating_characters.md)\n    +   [004 median of two sorted arrays](docs/leetcode/python/004._median_of_two_sorted_arrays.md)\n    +   [005 longest palindromic substring](docs/leetcode/python/005._longest_palindromic_substring.md)\n    +   [006 ZigZag Conversion](docs/leetcode/python/006._ZigZag_Conversion.md)\n    +   [007 Reverse Integer](docs/leetcode/python/007._Reverse_Integer.md)\n    +   [008 string to integer (atoi)](docs/leetcode/python/008._string_to_integer_(atoi).md)\n    +   [009 Palindrome Number](docs/leetcode/python/009._Palindrome_Number.md)\n    +   [010 regular expression matching](docs/leetcode/python/010._regular_expression_matching.md)\n    +   [011 container with most water](docs/leetcode/python/011._container_with_most_water.md)\n    +   [012 Integer to Roman](docs/leetcode/python/012._Integer_to_Roman.md)\n    +   [013 Roman to Integer](docs/leetcode/python/013._Roman_to_Integer.md)\n    +   [014 longest common prefix](docs/leetcode/python/014._longest_common_prefix.md)\n    +   [015 3sum](docs/leetcode/python/015._3sum.md)\n    +   [016 3sum closest](docs/leetcode/python/016._3sum_closest.md)\n    +   [017 letter combinations of a phone number](docs/leetcode/python/017._letter_combinations_of_a_phone_number.md)\n    +   [018 4sum](docs/leetcode/python/018._4sum.md)\n    +   [019 remove nth node from end of list](docs/leetcode/python/019._remove_nth_node_from_end_of_list.md)\n    +   [020 valid parentheses](docs/leetcode/python/020._valid_parentheses.md)\n    +   [021 merge two sorted lists](docs/leetcode/python/021._merge_two_sorted_lists.md)\n    +   [022 generate parentheses](docs/leetcode/python/022._generate_parentheses.md)\n    +   [023 merge k sorted lists](docs/leetcode/python/023._merge_k_sorted_lists.md)\n    +   [024 swap nodes in pairs](docs/leetcode/python/024._swap_nodes_in_pairs.md)\n    +   [026 Remove Duplicates from Sorted Array](docs/leetcode/python/026._Remove_Duplicates_from_Sorted_Array.md)\n    +   [027 Remove Element](docs/leetcode/python/027._Remove_Element.md)\n    +   [028 implement strstr()](docs/leetcode/python/028._implement_strstr.md)\n    +   [030 Substring with Concatenation of All Words](docs/leetcode/python/030._Substring_with_Concatenation_of_All_Words.md)\n    +   [031 next permutation](docs/leetcode/python/031._next_permutation.md)\n    +   [032 longest valid parentheses](docs/leetcode/python/032._longest_valid_parentheses.md)\n    +   [033 search in rotated sorted array](docs/leetcode/python/033._search_in_rotated_sorted_array.md)\n    +   [034 Search for a Range](docs/leetcode/python/034._Search_for_a_Range.md)\n    +   [035 search insert position](docs/leetcode/python/035._search_insert_position.md)\n    +   [038 Count and Say](docs/leetcode/python/038._Count_and_Say.md)\n    +   [039 combination sum](docs/leetcode/python/039._combination_sum.md)\n    +   [040 combination sum ii](docs/leetcode/python/040._combination_sum_ii.md)\n    +   [041 First Missing Positive](docs/leetcode/python/041._First_Missing_Positive.md)\n    +   [042 trapping rain water](docs/leetcode/python/042._trapping_rain_water.md)\n    +   [043 multiply strings](docs/leetcode/python/043._multiply_strings.md)\n    +   [044 wildcard matching](docs/leetcode/python/044._wildcard_matching.md)\n    +   [045 Jump Game II](docs/leetcode/python/045._Jump_Game_II.md)\n    +   [046 permutations](docs/leetcode/python/046._permutations.md)\n    +   [047 permutations ii](docs/leetcode/python/047._permutations_ii.md)\n    +   [048 rotate image](docs/leetcode/python/048._rotate_image.md)\n    +   [049 group anagrams python](docs/leetcode/python/049._group_anagrams_python.md)\n    +   [050 pow(x, n)](docs/leetcode/python/050._pow(x,_n).md)\n    +   [051 n-queens](docs/leetcode/python/051._n-queens.md)\n    +   [052 n-queens ii](docs/leetcode/python/052._n-queens_ii.md)\n    +   [053 maximum subarray](docs/leetcode/python/053._maximum_subarray.md)\n    +   [054 spiral matrix](docs/leetcode/python/054._spiral_matrix.md)\n    +   [055 jump game](docs/leetcode/python/055._jump_game.md)\n    +   [056 Merge Intervals](docs/leetcode/python/056._Merge_Intervals.md)\n    +   [058 length of last word](docs/leetcode/python/058._length_of_last_word.md)\n    +   [059 spiral matrix ii](docs/leetcode/python/059._spiral_matrix_ii.md)\n    +   [060 permutation sequence](docs/leetcode/python/060._permutation_sequence.md)\n    +   [061 rotate list](docs/leetcode/python/061._rotate_list.md)\n    +   [062 unique paths](docs/leetcode/python/062._unique_paths.md)\n    +   [064 minimum path sum](docs/leetcode/python/064._minimum_path_sum.md)\n    +   [065 unique paths ii](docs/leetcode/python/065.unique_paths_ii.md)\n    +   [066 plus one](docs/leetcode/python/066._plus_one.md)\n    +   [067 add binary](docs/leetcode/python/067._add_binary.md)\n    +   [069 sqrt(x)](docs/leetcode/python/069._sqrt(x).md)\n    +   [070 Climbing Stairs](docs/leetcode/python/070._Climbing_Stairs.md)\n    +   [072 edit distance](docs/leetcode/python/072._edit_distance.md)\n    +   [073 Set Matrix Zeroes](docs/leetcode/python/073._Set_Matrix_Zeroes.md)\n    +   [074 search a 2d matrix](docs/leetcode/python/074._search_a_2d_matrix.md)\n    +   [075 sort colors](docs/leetcode/python/075._sort_colors.md)\n    +   [076 Minimum Window Substring](docs/leetcode/python/076._Minimum_Window_Substring.md)\n    +   [077 combinations](docs/leetcode/python/077._combinations.md)\n    +   [078 Subsets](docs/leetcode/python/078._Subsets.md)\n    +   [079 word search](docs/leetcode/python/079._word_search.md)\n    +   [082 remove duplicates from sorted list ii](docs/leetcode/python/082._remove_duplicates_from_sorted_list_ii.md)\n    +   [083 remove duplicates from sorted list](docs/leetcode/python/083._remove_duplicates_from_sorted_list.md)\n    +   [086 partition list](docs/leetcode/python/086._partition_list.md)\n    +   [088 merge sorted array](docs/leetcode/python/088._merge_sorted_array.md)\n    +   [089 gray code](docs/leetcode/python/089._gray_code.md)\n    +   [090 subsets ii](docs/leetcode/python/090._subsets_ii.md)\n    +   [091 decode ways](docs/leetcode/python/091._decode_ways.md)\n    +   [092 reverse linked list ii](docs/leetcode/python/092._reverse_linked_list_ii.md)\n    +   [093 restore ip addresses](docs/leetcode/python/093._restore_ip_addresses.md)\n    +   [094 binary tree inorder traversal](docs/leetcode/python/094._binary_tree_inorder_traversal.md)\n    +   [096 unique binary search trees](docs/leetcode/python/096._unique_binary_search_trees.md)\n    +   [098 validate binary search tree](docs/leetcode/python/098._validate_binary_search_tree.md)\n    +   [100 same tree](docs/leetcode/python/100._same_tree.md)\n    +   [101 symmetric tree](docs/leetcode/python/101._symmetric_tree.md)\n    +   [102 binary tree level order traversal](docs/leetcode/python/102._binary_tree_level_order_traversal.md)\n    +   [103 binary tree zigzag level order traversal](docs/leetcode/python/103._binary_tree_zigzag_level_order_traversal.md)\n    +   [104 maximum depth of binary tree](docs/leetcode/python/104._maximum_depth_of_binary_tree.md)\n    +   [105 construct binary tree from preorder and inorder traversal](docs/leetcode/python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md)\n    +   [106 construct binary tree from inorder and postorder traversal](docs/leetcode/python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md)\n    +   [107 binary tree level order traversal ii](docs/leetcode/python/107._binary_tree_level_order_traversal_ii.md)\n    +   [108 convert sorted array to binary search tree](docs/leetcode/python/108._convert_sorted_array_to_binary_search_tree.md)\n    +   [109 convert sorted list to binary search tree](docs/leetcode/python/109._convert_sorted_list_to_binary_search_tree.md)\n    +   [110 balanced binary tree](docs/leetcode/python/110._balanced_binary_tree.md)\n    +   [111 minimum depth of binary tree](docs/leetcode/python/111._minimum_depth_of_binary_tree.md)\n    +   [112 path sum](docs/leetcode/python/112._path_sum.md)\n    +   [113 path sum ii](docs/leetcode/python/113._path_sum_ii.md)\n    +   [114 flatten binary tree to linked list](docs/leetcode/python/114._flatten_binary_tree_to_linked_list.md)\n    +   [116 populating next right pointers in each node](docs/leetcode/python/116._populating_next_right_pointers_in_each_node.md)\n    +   [117 Populating Next Right Pointers in Each Node II](docs/leetcode/python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md)\n    +   [118 pascal's triangle](docs/leetcode/python/118._pascal's_triangle.md)\n    +   [119 Pascal's Triangle II](docs/leetcode/python/119._Pascal's_Triangle_II.md)\n    +   [120 Triangle](docs/leetcode/python/120._Triangle.md)\n    +   [121 Best Time to Buy and Sell Stock](docs/leetcode/python/121._Best_Time_to_Buy_and_Sell_Stock.md)\n    +   [124 Binary Tree Maximum Path Sum](docs/leetcode/python/124._Binary_Tree_Maximum_Path_Sum.md)\n    +   [125 valid palindrome](docs/leetcode/python/125._valid_palindrome.md)\n    +   [126 Word Ladder II](docs/leetcode/python/126._Word_Ladder_II.md)\n    +   [127 word ladder](docs/leetcode/python/127._word_ladder.md)\n    +   [128 Longest Consecutive Sequence](docs/leetcode/python/128._Longest_Consecutive_Sequence.md)\n    +   [129 sum root to leaf numbers](docs/leetcode/python/129._sum_root_to_leaf_numbers.md)\n    +   [130 surrounded regions](docs/leetcode/python/130._surrounded_regions.md)\n    +   [131 palindrome partitioning](docs/leetcode/python/131._palindrome_partitioning.md)\n    +   [133 clone graph](docs/leetcode/python/133._clone_graph.md)\n    +   [136 single number](docs/leetcode/python/136._single_number.md)\n    +   [139 word break](docs/leetcode/python/139._word_break.md)\n    +   [140 word break ii](docs/leetcode/python/140._word_break_ii.md)\n    +   [141 linked list cycle](docs/leetcode/python/141._linked_list_cycle.md)\n    +   [142_Linked_List_Cycle_II md](docs/leetcode/python/142_Linked_List_Cycle_II.md)\n    +   [143 reorder list](docs/leetcode/python/143._reorder_list.md)\n    +   [144 binary tree preorder traversal](docs/leetcode/python/144._binary_tree_preorder_traversal.md)\n    +   [145 binary tree postorder traversal](docs/leetcode/python/145._binary_tree_postorder_traversal.md)\n    +   [147 insertion sort list](docs/leetcode/python/147._insertion_sort_list.md)\n    +   [148 sort list](docs/leetcode/python/148._sort_list.md)\n    +   [150 evaluate reverse polish notation](docs/leetcode/python/150._evaluate_reverse_polish_notation.md)\n    +   [151 reverse words in a string](docs/leetcode/python/151._reverse_words_in_a_string.md)\n    +   [152 maximum product subarray](docs/leetcode/python/152._maximum_product_subarray.md)\n    +   [153 find minimum in rotated sorted array](docs/leetcode/python/153._find_minimum_in_rotated_sorted_array.md)\n    +   [155 min stack](docs/leetcode/python/155._min_stack.md)\n    +   [157 Read N Characters Given Read4](docs/leetcode/python/157._Read_N_Characters_Given_Read4.md)\n    +   [158 Read N Characters Given Read4 II - Call multiple times](docs/leetcode/python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md)\n    +   [159 Longest Substring with At Most Two Distinct Characters](docs/leetcode/python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md)\n    +   [160 intersection of two linked lists](docs/leetcode/python/160._intersection_of_two_linked_lists.md)\n    +   [162 find peak element](docs/leetcode/python/162._find_peak_element.md)\n    +   [165 compare version numbers](docs/leetcode/python/165._compare_version_numbers.md)\n    +   [166 Fraction to Recurring Decimal](docs/leetcode/python/166._Fraction_to_Recurring_Decimal.md)\n    +   [167 two sum ii - input array is sorted](docs/leetcode/python/167._two_sum_ii_-_input_array_is_sorted.md)\n    +   [168 excel sheet column title](docs/leetcode/python/168._excel_sheet_column_title.md)\n    +   [169 majority element](docs/leetcode/python/169._majority_element.md)\n    +   [171 excel sheet column number](docs/leetcode/python/171._excel_sheet_column_number.md)\n    +   [173 binary search tree iterator](docs/leetcode/python/173._binary_search_tree_iterator.md)\n    +   [179 Largest Number](docs/leetcode/python/179._Largest_Number.md)\n    +   [182 duplicate emails](docs/leetcode/python/182._duplicate_emails.md)\n    +   [189 rotate array](docs/leetcode/python/189._rotate_array.md)\n    +   [191 number of 1 bits](docs/leetcode/python/191._number_of_1_bits.md)\n    +   [198 house robber](docs/leetcode/python/198._house_robber.md)\n    +   [199 binary tree right side view](docs/leetcode/python/199._binary_tree_right_side_view.md)\n    +   [200 number of islands](docs/leetcode/python/200._number_of_islands.md)\n    +   [203 remove linked list elements](docs/leetcode/python/203._remove_linked_list_elements.md)\n    +   [204 count primes](docs/leetcode/python/204._count_primes.md)\n    +   [205 isomorphic strings](docs/leetcode/python/205._isomorphic_strings.md)\n    +   [206 reverse linked list](docs/leetcode/python/206._reverse_linked_list.md)\n    +   [207 course schedule](docs/leetcode/python/207._course_schedule.md)\n    +   [208 implement trie (prefix tree)](docs/leetcode/python/208._implement_trie_(prefix_tree).md)\n    +   [210 course schedule ii](docs/leetcode/python/210._course_schedule_ii.md)\n    +   [211 Add and Search Word - Data structure design](docs/leetcode/python/211._Add_and_Search_Word_-_Data_structure_design.md)\n    +   [213 house robber ii](docs/leetcode/python/213._house_robber_ii.md)\n    +   [216 combination sum iii](docs/leetcode/python/216._combination_sum_iii.md)\n    +   [217 contains duplicate](docs/leetcode/python/217._contains_duplicate.md)\n    +   [218 The Skyline Problem](docs/leetcode/python/218._The_Skyline_Problem.md)\n    +   [219 contains duplicate ii](docs/leetcode/python/219._contains_duplicate_ii.md)\n    +   [221 maximal square](docs/leetcode/python/221._maximal_square.md)\n    +   [222 count complete tree nodes](docs/leetcode/python/222._count_complete_tree_nodes.md)\n    +   [223 rectangle area](docs/leetcode/python/223._rectangle_area.md)\n    +   [224 Basic Calculator](docs/leetcode/python/224._Basic_Calculator.md)\n    +   [225 implement stack using queues](docs/leetcode/python/225._implement_stack_using_queues.md)\n    +   [226 invert binary tree](docs/leetcode/python/226._invert_binary_tree.md)\n    +   [227 basic calculator ii](docs/leetcode/python/227._basic_calculator_ii.md)\n    +   [228 summary ranges](docs/leetcode/python/228._summary_ranges.md)\n    +   [229 majority element ii](docs/leetcode/python/229._majority_element_ii.md)\n    +   [230 kth smallest element in a bst](docs/leetcode/python/230._kth_smallest_element_in_a_bst.md)\n    +   [231 Power of Two](docs/leetcode/python/231._Power_of_Two.md)\n    +   [232 implement queue using stacks](docs/leetcode/python/232._implement_queue_using_stacks.md)\n    +   [234 palindrome linked list](docs/leetcode/python/234._palindrome_linked_list.md)\n    +   [235 lowest common ancestor of a binary search tree](docs/leetcode/python/235._lowest_common_ancestor_of_a_binary_search_tree.md)\n    +   [236 lowest common ancestor of a binary tree](docs/leetcode/python/236._lowest_common_ancestor_of_a_binary_tree.md)\n    +   [237 delete node in a linked list](docs/leetcode/python/237._delete_node_in_a_linked_list.md)\n    +   [238 product of array except self](docs/leetcode/python/238._product_of_array_except_self.md)\n    +   [240 search a 2d matrix ii](docs/leetcode/python/240._search_a_2d_matrix_ii.md)\n    +   [242 valid anagram](docs/leetcode/python/242._valid_anagram.md)\n    +   [249 Group Shifted Strings](docs/leetcode/python/249._Group_Shifted_Strings.md)\n    +   [252 Meeting Rooms](docs/leetcode/python/252._Meeting_Rooms.md)\n    +   [255 Verify Preorder Sequence in Binary Search Tree](docs/leetcode/python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md)\n    +   [256 Paint House](docs/leetcode/python/256._Paint_House.md)\n    +   [257 binary tree paths](docs/leetcode/python/257._binary_tree_paths.md)\n    +   [258_Add_Digits md](docs/leetcode/python/258._Add_Digits.md)\n    +   [261 Graph Valid Tree](docs/leetcode/python/261._Graph_Valid_Tree.md)\n    +   [263 ugly number](docs/leetcode/python/263._ugly_number.md)\n    +   [264 ugly number ii](docs/leetcode/python/264._ugly_number_ii.md)\n    +   [265 Paint House II](docs/leetcode/python/265._Paint_House_II.md)\n    +   [266 Palindrome Permutation](docs/leetcode/python/266._Palindrome_Permutation.md)\n    +   [267 Palindrome Permutation II](docs/leetcode/python/267._Palindrome_Permutation_II.md)\n    +   [268 missing number](docs/leetcode/python/268._missing_number.md)\n    +   [270 Closest Binary Search Tree Value](docs/leetcode/python/270._Closest_Binary_Search_Tree_Value.md)\n    +   [276 Paint Fence](docs/leetcode/python/276._Paint_Fence.md)\n    +   [277 Find the Celebrity](docs/leetcode/python/277._Find_the_Celebrity.md)\n    +   [278 First Bad Version](docs/leetcode/python/278._First_Bad_Version.md)\n    +   [279 perfect squares](docs/leetcode/python/279._perfect_squares.md)\n    +   [280 Wiggle Sort](docs/leetcode/python/280._Wiggle_Sort.md)\n    +   [283 move zeroes](docs/leetcode/python/283._move_zeroes.md)\n    +   [285 inorder successor in bst](docs/leetcode/python/285._inorder_successor_in_bst.md)\n    +   [286 Walls and Gates](docs/leetcode/python/286._Walls_and_Gates.md)\n    +   [287 Find the Duplicate Number](docs/leetcode/python/287._Find_the_Duplicate_Number.md)\n    +   [289 game of life](docs/leetcode/python/289._game_of_life.md)\n    +   [290 word pattern](docs/leetcode/python/290._word_pattern.md)\n    +   [292 nim game](docs/leetcode/python/292._nim_game.md)\n    +   [293 Flip Game](docs/leetcode/python/293._Flip_Game.md)\n    +   [296 Best Meeting Point](docs/leetcode/python/296._Best_Meeting_Point.md)\n    +   [298 Binary Tree Longest Consecutive Sequence](docs/leetcode/python/298._Binary_Tree_Longest_Consecutive_Sequence.md)\n    +   [299 bulls and cows](docs/leetcode/python/299._bulls_and_cows.md)\n    +   [300 longest increasing subsequence](docs/leetcode/python/300._longest_increasing_subsequence.md)\n    +   [303 range sum query - immutable](docs/leetcode/python/303._range_sum_query_-_immutable.md)\n    +   [316 Remove Duplicate Letters](docs/leetcode/python/316._Remove_Duplicate_Letters.md)\n    +   [319 Bulb Switcher](docs/leetcode/python/319._Bulb_Switcher.md)\n    +   [322 Coin Change](docs/leetcode/python/322._Coin_Change.md)\n    +   [323 number of connected components in an undirected graph](docs/leetcode/python/323._number_of_connected_components_in_an_undirected_graph.md)\n    +   [324 Wiggle Sort II](docs/leetcode/python/324._Wiggle_Sort_II.md)\n    +   [326 power of three](docs/leetcode/python/326._power_of_three.md)\n    +   [328 odd even linked list](docs/leetcode/python/328._odd_even_linked_list.md)\n    +   [334 increasing triplet subsequence](docs/leetcode/python/334._increasing_triplet_subsequence.md)\n    +   [337 house robber iii](docs/leetcode/python/337._house_robber_iii.md)\n    +   [338 Counting Bits](docs/leetcode/python/338._Counting_Bits.md)\n    +   [339 Nested List Weight Sum](docs/leetcode/python/339._Nested_List_Weight_Sum.md)\n    +   [341 Flatten Nested List Iterator](docs/leetcode/python/341._Flatten_Nested_List_Iterator.md)\n    +   [342 Power of Four](docs/leetcode/python/342._Power_of_Four.md)\n    +   [344 reverse string](docs/leetcode/python/344._reverse_string.md)\n    +   [345 Reverse Vowels of a String](docs/leetcode/python/345._Reverse_Vowels_of_a_String.md)\n    +   [349 intersection of two arrays](docs/leetcode/python/349._intersection_of_two_arrays.md)\n    +   [350 intersection of two arrays ii](docs/leetcode/python/350._intersection_of_two_arrays_ii.md)\n    +   [353 Design Snake Game](docs/leetcode/python/353._Design_Snake_Game.md)\n    +   [361 Bomb Enemy](docs/leetcode/python/361._Bomb_Enemy.md)\n    +   [364 Nested List Weight Sum II](docs/leetcode/python/364._Nested_List_Weight_Sum_II.md)\n    +   [366 Find Leaves of Binary Tree](docs/leetcode/python/366._Find_Leaves_of_Binary_Tree.md)\n    +   [367 valid perfect square](docs/leetcode/python/367._valid_perfect_square.md)\n    +   [369 Plus One Linked List](docs/leetcode/python/369._Plus_One_Linked_List.md)\n    +   [371 sum of two integers](docs/leetcode/python/371._sum_of_two_integers.md)\n    +   [374 Guess Number Higher or Lower](docs/leetcode/python/374._Guess_Number_Higher_or_Lower.md)\n    +   [377 combination sum iv](docs/leetcode/python/377._combination_sum_iv.md)\n    +   [378 kth smallest element in a sorted matrix](docs/leetcode/python/378._kth_smallest_element_in_a_sorted_matrix.md)\n    +   [380 Insert Delete GetRandom O(1)](docs/leetcode/python/380._Insert_Delete_GetRandom_O(1).md)\n    +   [381 Insert Delete GetRandom O(1) - Duplicates allowed](docs/leetcode/python/381._Insert_Delete_GetRandom_O(1)_-_Duplicates_allowed.md)\n    +   [382 linked list random node](docs/leetcode/python/382._linked_list_random_node.md)\n    +   [383 ransom note](docs/leetcode/python/383._ransom_note.md)\n    +   [384 Shuffle an Array](docs/leetcode/python/384._Shuffle_an_Array.md)\n    +   [386 Lexicographical Numbers](docs/leetcode/python/386._Lexicographical_Numbers.md)\n    +   [387 first unique character in a string](docs/leetcode/python/387._first_unique_character_in_a_string.md)\n    +   [388 Longest Absolute File Path](docs/leetcode/python/388._Longest_Absolute_File_Path.md)\n    +   [389 find the difference](docs/leetcode/python/389._find_the_difference.md)\n    +   [392 is subsequence](docs/leetcode/python/392._is_subsequence.md)\n    +   [394 decode string](docs/leetcode/python/394._decode_string.md)\n    +   [400 Nth Digit](docs/leetcode/python/400._Nth_Digit.md)\n    +   [401 binary watch](docs/leetcode/python/401._binary_watch.md)\n    +   [404 sum of left leaves](docs/leetcode/python/404._sum_of_left_leaves.md)\n    +   [405 Convert a Number to Hexadecimal](docs/leetcode/python/405._Convert_a_Number_to_Hexadecimal.md)\n    +   [406 Queue Reconstruction by Height](docs/leetcode/python/406._Queue_Reconstruction_by_Height.md)\n    +   [412 fizz buzz](docs/leetcode/python/412._fizz_buzz.md)\n    +   [413 Arithmetic Slices](docs/leetcode/python/413._Arithmetic_Slices.md)\n    +   [414 third maximum number](docs/leetcode/python/414._third_maximum_number.md)\n    +   [415 add strings](docs/leetcode/python/415._add_strings.md)\n    +   [416 Partition Equal Subset Sum](docs/leetcode/python/416._Partition_Equal_Subset_Sum.md)\n    +   [421 Maximum XOR of Two Numbers in an Array](docs/leetcode/python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md)\n    +   [422 Valid Word Square](docs/leetcode/python/422._Valid_Word_Square.md)\n    +   [434 number of segments in a string](docs/leetcode/python/434._number_of_segments_in_a_string.md)\n    +   [435 Non-overlapping Intervals](docs/leetcode/python/435._Non-overlapping_Intervals.md)\n    +   [437 path sum iii](docs/leetcode/python/437._path_sum_iii.md)\n    +   [438 Find All Anagrams in a String](docs/leetcode/python/438._Find_All_Anagrams_in_a_String.md)\n    +   [439 Ternary Expression Parser](docs/leetcode/python/439._Ternary_Expression_Parser.md)\n    +   [441 arranging coins](docs/leetcode/python/441._arranging_coins.md)\n    +   [448 Find All Numbers Disappeared in an Array](docs/leetcode/python/448._Find_All_Numbers_Disappeared_in_an_Array.md)\n    +   [450 Delete Node in a BST](docs/leetcode/python/450._Delete_Node_in_a_BST.md)\n    +   [453 Minimum Moves to Equal Array Elements](docs/leetcode/python/453._Minimum_Moves_to_Equal_Array_Elements.md)\n    +   [459 Repeated Substring Pattern](docs/leetcode/python/459._Repeated_Substring_Pattern.md)\n    +   [461 Hamming Distance](docs/leetcode/python/461._Hamming_Distance.md)\n    +   [463 Island Perimeter](docs/leetcode/python/463._Island_Perimeter.md)\n    +   [467 Unique Substrings in Wraparound String](docs/leetcode/python/467._Unique_Substrings_in_Wraparound_String.md)\n    +   [469 Convex Polygon](docs/leetcode/python/469._Convex_Polygon.md)\n    +   [476 Number Complement](docs/leetcode/python/476._Number_Complement.md)\n    +   [477 Total Hamming Distance](docs/leetcode/python/477._Total_Hamming_Distance.md)\n    +   [485 Max Consecutive Ones](docs/leetcode/python/485._Max_Consecutive_Ones.md)\n    +   [494 Target Sum](docs/leetcode/python/494._Target_Sum.md)\n    +   [536 Construct Binary Tree from String](docs/leetcode/python/536._Construct_Binary_Tree_from_String.md)\n    +   [587 Erect the Fence](docs/leetcode/python/587._Erect_the_Fence.md)\n    +   [599 Minimum Index Sum of Two Lists](docs/leetcode/python/599._Minimum_Index_Sum_of_Two_Lists.md)\n    +   [606 Construct String from Binary Tree](docs/leetcode/python/606._Construct_String_from_Binary_Tree.md)\n    +   [611 Valid Triangle Number](docs/leetcode/python/611._Valid_Triangle_Number.md)\n    +   [646 Maximum Length of Pair Chain](docs/leetcode/python/646._Maximum_Length_of_Pair_Chain.md)\n    +   [647 Palindromic Substrings](docs/leetcode/python/647._Palindromic_Substrings.md)\n    +   [657 Judge Route Circle](docs/leetcode/python/657._Judge_Route_Circle.md)\n    +   [665 Non-decreasing Array](docs/leetcode/python/665._Non-decreasing_Array.md)\n    +   [672 Bulb Switcher II](docs/leetcode/python/672._Bulb_Switcher_II.md)\n    +   [681 Next Closest Time](docs/leetcode/python/681._Next_Closest_Time.md)\n    +   [682 Baseball Game](docs/leetcode/python/682._Baseball_Game.md)\n    +   [685 Redundant Connection II](docs/leetcode/python/685._Redundant_Connection_II.md)\n    +   [687 Longest Univalue Path](docs/leetcode/python/687._Longest_Univalue_Path.md)\n    +   [693 Binary Number with Alternating Bits](docs/leetcode/python/693._Binary_Number_with_Alternating_Bits.md)\n    +   [701 Insert into a Binary Search Tree](docs/leetcode/python/701._Insert_into_a_Binary_Search_Tree.md)\n    +   [707 Design Linked List](docs/leetcode/python/707._Design_Linked_List.md)\n    +   [740 delete and earn](docs/leetcode/python/740._delete_and_earn.md)\n    +   [760 Find Anagram Mappings](docs/leetcode/python/760._Find_Anagram_Mappings.md)\n    +   [774 Minimize Max Distance to Gas Station](docs/leetcode/python/774._Minimize_Max_Distance_to_Gas_Station.md)\n    +   [777 Swap Adjacent in LR String](docs/leetcode/python/777._Swap_Adjacent_in_LR_String.md)\n    +   [844 Backspace String Compare](docs/leetcode/python/844._Backspace_String_Compare.md)\n+   [剑指 Offer Java 题解](docs/jianzhioffer/java/README.md)\n    +   [找出数组中重复的数字](docs/jianzhioffer/java/03_01_DuplicationInArray.md)\n    +   [不修改数组找出重复的数字](docs/jianzhioffer/java/03_02_DuplicationInArrayNoEdit.md)\n    +   [二维数组中的查找](docs/jianzhioffer/java/04_FindInPartiallySortedMatrix.md)\n    +   [替换空格](docs/jianzhioffer/java/05_ReplaceSpaces.md)\n    +   [从尾到头打印链表](docs/jianzhioffer/java/06_PrintListInReversedOrder.md)\n    +   [重建二叉树](docs/jianzhioffer/java/07_ConstructBinaryTree.md)\n    +   [二叉树的下一个结点](docs/jianzhioffer/java/08_NextNodeInBinaryTrees.md)\n    +   [用两个栈实现队列](docs/jianzhioffer/java/09_01_QueueWithTwoStacks.md)\n    +   [用两个队列实现栈](docs/jianzhioffer/java/09_02_StackWithTwoQueues.md)\n    +   [斐波那契数列](docs/jianzhioffer/java/10_01_Fibonacci.md)\n    +   [跳台阶](docs/jianzhioffer/java/10_02_JumpFloor.md)\n    +   [变态跳台阶](docs/jianzhioffer/java/10_03_JumpFloorII.md)\n    +   [矩形覆盖](docs/jianzhioffer/java/10_04_RectCover.md)\n    +   [旋转数组的最小数字](docs/jianzhioffer/java/11_MinNumberInRotatedArray.md)\n    +   [矩阵中的路径](docs/jianzhioffer/java/12_StringPathInMatrix.md)\n    +   [机器人的移动范围](docs/jianzhioffer/java/13_RobotMove.md)\n    +   [剪绳子](docs/jianzhioffer/java/14_CuttingRope.md)\n    +   [二进制中 1 的个数](docs/jianzhioffer/java/15_NumberOf1InBinary.md)\n    +   [数值的整数次方](docs/jianzhioffer/java/16_Power.md)\n    +   [打印从 1 到最大的 n 位数](docs/jianzhioffer/java/17_Print1ToMaxOfNDigits.md)\n    +   [在O(1)时间内删除链表节点](docs/jianzhioffer/java/18_01_DeleteNodeInList.md)\n    +   [删除链表中重复的节点](docs/jianzhioffer/java/18_02_DeleteDuplicatedNode.md)\n    +   [正则表达式匹配](docs/jianzhioffer/java/19_RegularExpressionsMatching.md)\n    +   [表示数值的字符串](docs/jianzhioffer/java/20_NumericStrings.md)\n    +   [调整数组顺序使奇数位于偶数前面](docs/jianzhioffer/java/21_ReorderArray.md)\n    +   [链表中倒数第k个结点](docs/jianzhioffer/java/22_KthNodeFromEnd.md)\n    +   [链表中环的入口结点](docs/jianzhioffer/java/23_EntryNodeInListLoop.md)\n    +   [反转链表](docs/jianzhioffer/java/24_ReverseList.md)\n    +   [合并两个排序的链表](docs/jianzhioffer/java/25_MergeSortedLists.md)\n    +   [树的子结构](docs/jianzhioffer/java/26_SubstructureInTree.md)\n    +   [二叉树的镜像](docs/jianzhioffer/java/27_MirrorOfBinaryTree.md)\n    +   [对称的二叉树](docs/jianzhioffer/java/28_SymmetricalBinaryTree.md)\n    +   [顺时针打印矩阵](docs/jianzhioffer/java/29_PrintMatrix.md)\n    +   [包含min函数的栈](docs/jianzhioffer/java/30_MinInStack.md)\n    +   [栈的压入、弹出序列](docs/jianzhioffer/java/31_StackPushPopOrder.md)\n    +   [不分行从上到下打印二叉树](docs/jianzhioffer/java/32_01_PrintTreeFromTopToBottom.md)\n    +   [把二叉树打印成多行](docs/jianzhioffer/java/32_02_PrintTreesInLines.md)\n    +   [按之字形打印二叉树](docs/jianzhioffer/java/32_03_PrintTreesInZigzag.md)\n    +   [二叉搜索树的后序遍历序列](docs/jianzhioffer/java/33_SquenceOfBST.md)\n    +   [二叉树中和为某一值的路径](docs/jianzhioffer/java/34_PathInTree.md)\n    +   [复杂链表的复制](docs/jianzhioffer/java/35_CopyComplexList.md)\n    +   [二叉搜索树与双向链表](docs/jianzhioffer/java/36_ConvertBinarySearchTree.md)\n    +   [序列化二叉树](docs/jianzhioffer/java/37_SerializeBinaryTrees.md)\n    +   [字符串的排列](docs/jianzhioffer/java/38_StringPermutation.md)\n    +   [数组中出现次数超过一半的数字](docs/jianzhioffer/java/39_MoreThanHalfNumber.md)\n    +   [获取数组中最小的k个数](docs/jianzhioffer/java/40_KLeastNumbers.md)\n    +   [数据流中的中位数](docs/jianzhioffer/java/41_StreamMedian.md)\n    +   [连续子数组的最大和](docs/jianzhioffer/java/42_GreatestSumOfSubarrays.md)\n    +   [整数中1出现的次数](docs/jianzhioffer/java/43_NumberOf1.md)\n    +   [数字序列中某一位的数字](docs/jianzhioffer/java/44_DigitsInSequence.md)\n    +   [把数组排成最小的数](docs/jianzhioffer/java/45_SortArrayForMinNumber.md)\n    +   [把数字翻译成字符串](docs/jianzhioffer/java/46_TranslateNumbersToStrings.md)\n    +   [礼物的最大价值](docs/jianzhioffer/java/47_MaxValueOfGifts.md)\n    +   [最长不含重复字符的子字符串](docs/jianzhioffer/java/48_LongestSubstringWithoutDup.md)\n    +   [丑数](docs/jianzhioffer/java/49_UglyNumber.md)\n    +   [第一个只出现一次的字符](docs/jianzhioffer/java/50_01_FirstNotRepeatingChar.md)\n    +   [字符流中第一个不重复的字符](docs/jianzhioffer/java/50_02_FristCharacterInStream.md)\n    +   [两个链表的第一个公共结点](docs/jianzhioffer/java/52_FirstCommonNodesInLists.md)\n    +   [数字在排序数组中出现的次数](docs/jianzhioffer/java/53_01_NumberOfK.md)\n    +   [0到n-1中缺失的数字](docs/jianzhioffer/java/53_02_MissingNumber.md)\n    +   [数组中数值和下标相等的元素](docs/jianzhioffer/java/53_03_IntegerIdenticalToIndex.md)\n    +   [二叉搜索树的第k个结点](docs/jianzhioffer/java/54_KthNodeInBST.md)\n    +   [二叉树的深度](docs/jianzhioffer/java/55_01_TreeDepth.md)\n    +   [平衡二叉树](docs/jianzhioffer/java/55_02_BalancedBinaryTree.md)\n    +   [数组中只出现一次的两个数字](docs/jianzhioffer/java/56_01_NumbersAppearOnce.md)\n    +   [数组中唯一只出现一次的数字](docs/jianzhioffer/java/56_02_NumberAppearingOnce.md)\n    +   [和为S的两个数字](docs/jianzhioffer/java/57_01_TwoNumbersWithSum.md)\n    +   [和为S的连续正数序列](docs/jianzhioffer/java/57_02_ContinuousSquenceWithSum.md)\n    +   [翻转单词顺序](docs/jianzhioffer/java/58_01_ReverseWordsInSentence.md)\n    +   [左旋转字符串](docs/jianzhioffer/java/58_02_LeftRotateString.md)\n    +   [滑动窗口的最大值](docs/jianzhioffer/java/59_01_MaxInSlidingWindow.md)\n    +   [扑克牌的顺子](docs/jianzhioffer/java/61_ContinousCards.md)\n"
  },
  {
    "path": "asset/back-to-top.css",
    "content": "#scroll-btn {\n    position: fixed;\n    right: 15px;\n    bottom: 10px;\n    width: 35px;\n    height: 35px;\n    background-repeat: no-repeat;\n    background-size: cover;\n    cursor: pointer;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    background-image: url(up.svg);\n\tbackground-position-y: -1px;\n\tdisplay: none;\n\tborder: 2px solid;\n\tborder-radius: 4px;\t\n}"
  },
  {
    "path": "asset/back-to-top.js",
    "content": "document.addEventListener('DOMContentLoaded', function() {\n\tvar scrollBtn = document.createElement('div')\n\tscrollBtn.id = 'scroll-btn'\n\tdocument.body.append(scrollBtn)\n\t\n\twindow.addEventListener('scroll', function() {\n\t\tvar offset = window.document.documentElement.scrollTop;\n        scrollBtn.style.display = offset >= 500 ? \"block\" : \"none\";\n\t})\n\tscrollBtn.addEventListener('click', function(e) {\n\t\te.stopPropagation();\n\t\tvar step = window.scrollY / 15;\n\t\tvar hdl = setInterval(function() {\n\t\t\twindow.scrollTo(0, window.scrollY - step);\n\t\t\tif(window.scrollY <= 0) {\n\t\t\t\tclearInterval(hdl)\n\t\t\t}\n\t\t}, 15)\n\t})\n})"
  },
  {
    "path": "asset/dark-mode.css",
    "content": "#dark-mode-btn {\n\tposition: fixed;\n\tright: 15px;\n\ttop: 100px;\n\twidth: 35px;\n\theight: 35px;\n\tbackground-repeat: no-repeat;\n\tbackground-size: cover;\n\tcursor: pointer;\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n\ttransition: background-image .15s ease-in-out .15s;\n}\n\n.dark-logo {\t\n\tbackground-image: url('sun.svg');\t\n}\n\n.light-logo {\n\tbackground-image: url('moon.svg');\n}"
  },
  {
    "path": "asset/dark-mode.js",
    "content": "document.addEventListener('DOMContentLoaded', function() {\n\tvar style = document.querySelector('#invert')\n\tif (style == null) {\n\t\tstyle = document.createElement('style')\n\t\tstyle.id = 'invert'\n\t\tdocument.head.append(style)\n\t}\n\tvar btn = document.querySelector('#dark-mode-btn')\n\tif (btn == null) {\n\t\tbtn = document.createElement('div')\n\t\tbtn.id = 'dark-mode-btn'\n\t\tbtn.classList.add('light-logo')\n\t\tdocument.body.append(btn)\n\t}\n\t\n\tvar enableDarkMode = function() {\n\t\tstyle.innerText = 'html,img,pre,#dark-mode-btn{filter:invert(100%)}'\n\t\tbtn.classList.remove('light-logo')\n\t\tbtn.classList.add('dark-logo')\n\t\tlocalStorage.darkLight = 'dark'\n\t\t\n\t}\n\tvar disableDarkMode = function() {\n\t\tstyle.innerText = ''\t\t\n\t\tbtn.classList.remove('dark-logo')\n\t\tbtn.classList.add('light-logo')\n\t\tlocalStorage.darkLight = 'light'\n\t}\n\t\n\tbtn.addEventListener('click', function(){\n\t\tvar currMode = localStorage.darkLight || 'light'\n\t\tif (currMode == 'light')\n\t\t\tenableDarkMode()\n\t\telse \n\t\t\tdisableDarkMode()\n\t})\n\t\n\tif (localStorage.darkLight == 'dark')\n\t\tenableDarkMode()\n\t\n})\n\n"
  },
  {
    "path": "asset/docsify-apachecn-footer.js",
    "content": "(function(){\n\tvar cnzzId = window.$docsify.cnzzId\n\tvar unRepo = window.$docsify.repo || ''\n\tvar [un, repo] = unRepo.split('/')\n    var footer = `\n        <hr/>\n        <div align=\"center\">\n          <p><a href=\"http://www.apachecn.org/\" target=\"_blank\"><font face=\"KaiTi\" size=\"6\" color=\"red\">我们一直在努力</font></a><p>\n          <p><a href=\"https://github.com/${unRepo}\" target=\"_blank\">${unRepo}</a></p>\n          <p><iframe align=\"middle\" src=\"https://ghbtns.com/github-btn.html?user=${un}&repo=${repo}&type=watch&count=true&v=2\" frameborder=\"0\" scrolling=\"0\" width=\"100px\" height=\"25px\"></iframe>\n          <iframe align=\"middle\" src=\"https://ghbtns.com/github-btn.html?user=${un}&repo=${repo}&type=star&count=true\" frameborder=\"0\" scrolling=\"0\" width=\"100px\" height=\"25px\"></iframe>\n          <iframe align=\"middle\" src=\"https://ghbtns.com/github-btn.html?user=${un}&repo=${repo}&type=fork&count=true\" frameborder=\"0\" scrolling=\"0\" width=\"100px\" height=\"25px\"></iframe>\n          <a target=\"_blank\" href=\"https://jq.qq.com/?_wv=1027&k=fgYM7eMw\"><img border=\"0\" src=\"//pub.idqqimg.com/wpa/images/group.png\" alt=\"iBooker 面试求职\" title=\"iBooker 面试求职\"></a></p>\n          <p><span id=\"cnzz_stat_icon_${cnzzId}\"></span></p>\n          <div style=\"text-align:center;margin:0 0 10.5px;\">\n            <ins class=\"adsbygoogle\"\n                 style=\"display:inline-block;width:728px;height:90px\"\n                 data-ad-client=\"ca-pub-3565452474788507\"\n                 data-ad-slot=\"2543897000\"></ins>\n          </div>\n        </div>\n\t`\n    var plugin = function(hook) {\n      hook.afterEach(function(html) {\n        return html + footer\n      })\n      hook.doneEach(function() {\n        (adsbygoogle = window.adsbygoogle || []).push({})\n      })\n    }\n    var plugins = window.$docsify.plugins || []\n    plugins.push(plugin)\n    window.$docsify.plugins = plugins\n})()"
  },
  {
    "path": "asset/docsify-baidu-push.js",
    "content": "(function(){\n    var plugin = function(hook) {\n        hook.doneEach(function() {\n            new Image().src = \n                '//api.share.baidu.com/s.gif?r=' + \n                encodeURIComponent(document.referrer) + \n                \"&l=\" + encodeURIComponent(location.href)\n        })\n    }\n    var plugins = window.$docsify.plugins || []\n    plugins.push(plugin)\n    window.$docsify.plugins = plugins\n})()"
  },
  {
    "path": "asset/docsify-baidu-stat.js",
    "content": "(function(){\n    var plugin = function(hook) {\n        hook.doneEach(function() {\n            window._hmt = window._hmt || []\n            var hm = document.createElement(\"script\")\n            hm.src = \"https://hm.baidu.com/hm.js?\" + window.$docsify.bdStatId\n            document.querySelector(\"article\").appendChild(hm)\n        })\n    }\n    var plugins = window.$docsify.plugins || []\n    plugins.push(plugin)\n    window.$docsify.plugins = plugins\n})()"
  },
  {
    "path": "asset/docsify-clicker.js",
    "content": "(function() {\n    var ids = [\n        '109577065', '108852955', '102682374', '100520874', '92400861', '90312982', \n        '109963325', '109323014', '109301511', '108898970', '108590722', '108538676', \n        '108503526', '108437109', '108402202', '108292691', '108291153', '108268498', \n        '108030854', '107867070', '107847299', '107827334', '107825454', '107802131', \n        '107775320', '107752974', '107735139', '107702571', '107598864', '107584507', \n        '107568311', '107526159', '107452391', '107437455', '107430050', '107395781', \n        '107325304', '107283210', '107107145', '107085440', '106995421', '106993460', \n        '106972215', '106959775', '106766787', '106749609', '106745967', '106634313', \n        '106451602', '106180097', '106095505', '106077010', '106008089', '106002346', \n        '105653809', '105647855', '105130705', '104837872', '104706815', '104192620', \n        '104074941', '104040537', '103962171', '103793502', '103783460', '103774572', \n        '103547748', '103547703', '103547571', '103490757', '103413481', '103341935', \n        '103330191', '103246597', '103235808', '103204403', '103075981', '103015105', \n        '103014899', '103014785', '103014702', '103014540', '102993780', '102993754', \n        '102993680', '102958443', '102913317', '102903382', '102874766', '102870470', \n        '102864513', '102811179', '102761237', '102711565', '102645443', '102621845', \n        '102596167', '102593333', '102585262', '102558427', '102537547', '102530610', \n        '102527017', '102504698', '102489806', '102372981', '102258897', '102257303', \n        '102056248', '101920097', '101648638', '101516708', '101350577', '101268149', \n        '101128167', '101107328', '101053939', '101038866', '100977414', '100945061', \n        '100932401', '100886407', '100797378', '100634918', '100588305', '100572447', \n        '100192249', '100153559', '100099032', '100061455', '100035392', '100033450', \n        '99671267', '99624846', '99172551', '98992150', '98989508', '98987516', '98938304', \n        '98937682', '98725145', '98521688', '98450861', '98306787', '98203342', '98026348', \n        '97680167', '97492426', '97108940', '96888872', '96568559', '96509100', '96508938', \n        '96508611', '96508374', '96498314', '96476494', '96333593', '96101522', '95989273', \n        '95960507', '95771870', '95770611', '95766810', '95727700', '95588929', '95218707', \n        '95073151', '95054615', '95016540', '94868371', '94839549', '94719281', '94401578', \n        '93931439', '93853494', '93198026', '92397889', '92063437', '91635930', '91433989', \n        '91128193', '90915507', '90752423', '90738421', '90725712', '90725083', '90722238', \n        '90647220', '90604415', '90544478', '90379769', '90288341', '90183695', '90144066', \n        '90108283', '90021771', '89914471', '89876284', '89852050', '89839033', '89812373', \n        '89789699', '89786189', '89752620', '89636380', '89632889', '89525811', '89480625', \n        '89464088', '89464025', '89463984', '89463925', '89445280', '89441793', '89430432', \n        '89429877', '89416176', '89412750', '89409618', '89409485', '89409365', '89409292', \n        '89409222', '89399738', '89399674', '89399526', '89355336', '89330241', '89308077', \n        '89222240', '89140953', '89139942', '89134398', '89069355', '89049266', '89035735', \n        '89004259', '88925790', '88925049', '88915838', '88912706', '88911548', '88899438', \n        '88878890', '88837519', '88832555', '88824257', '88777952', '88752158', '88659061', \n        '88615256', '88551434', '88375675', '88322134', '88322085', '88321996', '88321978', \n        '88321950', '88321931', '88321919', '88321899', '88321830', '88321756', '88321710', \n        '88321661', '88321632', '88321566', '88321550', '88321506', '88321475', '88321440', \n        '88321409', '88321362', '88321321', '88321293', '88321226', '88232699', '88094874', \n        '88090899', '88090784', '88089091', '88048808', '87938224', '87913318', '87905933', \n        '87897358', '87856753', '87856461', '87827666', '87822008', '87821456', '87739137', \n        '87734022', '87643633', '87624617', '87602909', '87548744', '87548689', '87548624', \n        '87548550', '87548461', '87463201', '87385913', '87344048', '87078109', '87074784', \n        '87004367', '86997632', '86997466', '86997303', '86997116', '86996474', '86995899', \n        '86892769', '86892654', '86892569', '86892457', '86892347', '86892239', '86892124', \n        '86798671', '86777307', '86762845', '86760008', '86759962', '86759944', '86759930', \n        '86759922', '86759646', '86759638', '86759633', '86759622', '86759611', '86759602', \n        '86759596', '86759591', '86759580', '86759572', '86759567', '86759558', '86759545', \n        '86759534', '86749811', '86741502', '86741074', '86741059', '86741020', '86740897', \n        '86694754', '86670104', '86651882', '86651875', '86651866', '86651828', '86651790', \n        '86651767', '86651756', '86651735', '86651720', '86651708', '86618534', '86618526', \n        '86594785', '86590937', '86550497', '86550481', '86550472', '86550453', '86550438', \n        '86550429', '86550407', '86550381', '86550359', '86536071', '86536035', '86536014', \n        '86535988', '86535963', '86535953', '86535932', '86535902', '86472491', '86472298', \n        '86472236', '86472191', '86472108', '86471967', '86471899', '86471822', '86439022', \n        '86438972', '86438902', '86438887', '86438867', '86438836', '86438818', '85850119', \n        '85850075', '85850021', '85849945', '85849893', '85849837', '85849790', '85849740', \n        '85849661', '85849620', '85849550', '85606096', '85564441', '85547709', '85471981', \n        '85471317', '85471136', '85471073', '85470629', '85470456', '85470169', '85469996', \n        '85469877', '85469775', '85469651', '85469331', '85469033', '85345768', '85345742', \n        '85337900', '85337879', '85337860', '85337833', '85337797', '85322822', '85322810', \n        '85322791', '85322745', '85317667', '85265742', '85265696', '85265618', '85265350', \n        '85098457', '85057670', '85009890', '84755581', '84637437', '84637431', '84637393', \n        '84637374', '84637355', '84637338', '84637321', '84637305', '84637283', '84637259', \n        '84629399', '84629314', '84629233', '84629124', '84629065', '84628997', '84628933', \n        '84628838', '84628777', '84628690', '84591581', '84591553', '84591511', '84591484', \n        '84591468', '84591416', '84591386', '84591350', '84591308', '84572155', '84572107', \n        '84503228', '84500221', '84403516', '84403496', '84403473', '84403442', '84075703', \n        '84029659', '83933480', '83933459', '83933435', '83903298', '83903274', '83903258', \n        '83752369', '83345186', '83116487', '83116446', '83116402', '83116334', '83116213', \n        '82944248', '82941023', '82938777', '82936611', '82932735', '82918102', '82911085', \n        '82888399', '82884263', '82883507', '82880996', '82875334', '82864060', '82831039', \n        '82823385', '82795277', '82790832', '82775718', '82752022', '82730437', '82718126', \n        '82661646', '82588279', '82588267', '82588261', '82588192', '82347066', '82056138', \n        '81978722', '81211571', '81104145', '81069048', '81006768', '80788365', '80767582', \n        '80759172', '80759144', '80759129', '80736927', '80661288', '80616304', '80602366', \n        '80584625', '80561364', '80549878', '80549875', '80541470', '80539726', '80531328', \n        '80513257', '80469816', '80406810', '80356781', '80334130', '80333252', '80332666', \n        '80332389', '80311244', '80301070', '80295974', '80292252', '80286963', '80279504', \n        '80278369', '80274371', '80249825', '80247284', '80223054', '80219559', '80209778', \n        '80200279', '80164236', '80160900', '80153046', '80149560', '80144670', '80061205', \n        '80046520', '80025644', '80014721', '80005213', '80004664', '80001653', '79990178', \n        '79989283', '79947873', '79946002', '79941517', '79938786', '79932755', '79921178', \n        '79911339', '79897603', '79883931', '79872574', '79846509', '79832150', '79828161', \n        '79828156', '79828149', '79828146', '79828140', '79828139', '79828135', '79828123', \n        '79820772', '79776809', '79776801', '79776788', '79776782', '79776772', '79776767', \n        '79776760', '79776753', '79776736', '79776705', '79676183', '79676171', '79676166', \n        '79676160', '79658242', '79658137', '79658130', '79658123', '79658119', '79658112', \n        '79658100', '79658092', '79658089', '79658069', '79658054', '79633508', '79587857', \n        '79587850', '79587842', '79587831', '79587825', '79587819', '79547908', '79477700', \n        '79477692', '79440956', '79431176', '79428647', '79416896', '79406699', '79350633', \n        '79350545', '79344765', '79339391', '79339383', '79339157', '79307345', '79293944', \n        '79292623', '79274443', '79242798', '79184420', '79184386', '79184355', '79184269', \n        '79183979', '79100314', '79100206', '79100064', '79090813', '79057834', '78967246', \n        '78941571', '78927340', '78911467', '78909741', '78848006', '78628917', '78628908', \n        '78628889', '78571306', '78571273', '78571253', '78508837', '78508791', '78448073', \n        '78430940', '78408150', '78369548', '78323851', '78314301', '78307417', '78300457', \n        '78287108', '78278945', '78259349', '78237192', '78231360', '78141031', '78100357', \n        '78095793', '78084949', '78073873', '78073833', '78067868', '78067811', '78055014', \n        '78041555', '78039240', '77948804', '77879624', '77837792', '77824937', '77816459', \n        '77816208', '77801801', '77801767', '77776636', '77776610', '77505676', '77485156', \n        '77478296', '77460928', '77327521', '77326428', '77278423', '77258908', '77252370', \n        '77248841', '77239042', '77233843', '77230880', '77200256', '77198140', '77196405', \n        '77193456', '77186557', '77185568', '77181823', '77170422', '77164604', '77163389', \n        '77160103', '77159392', '77150721', '77146204', '77141824', '77129604', '77123259', \n        '77113014', '77103247', '77101924', '77100165', '77098190', '77094986', '77088637', \n        '77073399', '77062405', '77044198', '77036923', '77017092', '77007016', '76999924', \n        '76977678', '76944015', '76923087', '76912696', '76890184', '76862282', '76852434', \n        '76829683', '76794256', '76780755', '76762181', '76732277', '76718569', '76696048', \n        '76691568', '76689003', '76674746', '76651230', '76640301', '76615315', '76598528', \n        '76571947', '76551820', '74178127', '74157245', '74090991', '74012309', '74001789', \n        '73910511', '73613471', '73605647', '73605082', '73503704', '73380636', '73277303', \n        '73274683', '73252108', '73252085', '73252070', '73252039', '73252025', '73251974', \n        '73135779', '73087531', '73044025', '73008658', '72998118', '72997953', '72847091', \n        '72833384', '72830909', '72828999', '72823633', '72793092', '72757626', '71157154', \n        '71131579', '71128551', '71122253', '71082760', '71078326', '71075369', '71057216', \n        '70812997', '70384625', '70347260', '70328937', '70313267', '70312950', '70255825', \n        '70238893', '70237566', '70237072', '70230665', '70228737', '70228729', '70175557', \n        '70175401', '70173259', '70172591', '70170835', '70140724', '70139606', '70053923', \n        '69067886', '69063732', '69055974', '69055708', '69031254', '68960022', '68957926', \n        '68957556', '68953383', '68952755', '68946828', '68483371', '68120861', '68065606', \n        '68064545', '68064493', '67646436', '67637525', '67632961', '66984317', '66968934', \n        '66968328', '66491589', '66475786', '66473308', '65946462', '65635220', '65632553', \n        '65443309', '65437683', '63260222', '63253665', '63253636', '63253628', '63253610', \n        '63253572', '63252767', '63252672', '63252636', '63252537', '63252440', '63252329', \n        '63252155', '62888876', '62238064', '62039365', '62038016', '61925813', '60957024', \n        '60146286', '59523598', '59489460', '59480461', '59160354', '59109234', '59089006', \n        '58595549', '57406062', '56678797', '55001342', '55001340', '55001336', '55001330', \n        '55001328', '55001325', '55001311', '55001305', '55001298', '55001290', '55001283', \n        '55001278', '55001272', '55001265', '55001262', '55001253', '55001246', '55001242', \n        '55001236', '54907997', '54798827', '54782693', '54782689', '54782688', '54782676', \n        '54782673', '54782671', '54782662', '54782649', '54782636', '54782630', '54782628', \n        '54782627', '54782624', '54782621', '54782620', '54782615', '54782613', '54782608', \n        '54782604', '54782600', '54767237', '54766779', '54755814', '54755674', '54730253', \n        '54709338', '54667667', '54667657', '54667639', '54646201', '54407212', '54236114', \n        '54234220', '54233181', '54232788', '54232407', '54177960', '53991319', '53932970', \n        '53888106', '53887128', '53885944', '53885094', '53884497', '53819985', '53812640', \n        '53811866', '53790628', '53785053', '53782838', '53768406', '53763191', '53763163', \n        '53763148', '53763104', '53763092', '53576302', '53576157', '53573472', '53560183', \n        '53523648', '53516634', '53514474', '53510917', '53502297', '53492224', '53467240', \n        '53467122', '53437115', '53436579', '53435710', '53415115', '53377875', '53365337', \n        '53350165', '53337979', '53332925', '53321283', '53318758', '53307049', '53301773', \n        '53289364', '53286367', '53259948', '53242892', '53239518', '53230890', '53218625', \n        '53184121', '53148662', '53129280', '53116507', '53116486', '52980893', '52980652', \n        '52971002', '52950276', '52950259', '52944714', '52934397', '52932994', '52924939', \n        '52887083', '52877145', '52858258', '52858046', '52840214', '52829673', '52818774', \n        '52814054', '52805448', '52798019', '52794801', '52786111', '52774750', '52748816', \n        '52745187', '52739313', '52738109', '52734410', '52734406', '52734401', '52515005', \n        '52056818', '52039757', '52034057', '50899381', '50738883', '50726018', '50695984', \n        '50695978', '50695961', '50695931', '50695913', '50695902', '50695898', '50695896', \n        '50695885', '50695852', '50695843', '50695829', '50643222', '50591997', '50561827', \n        '50550829', '50541472', '50527581', '50527317', '50527206', '50527094', '50526976', \n        '50525931', '50525764', '50518363', '50498312', '50493019', '50492927', '50492881', \n        '50492863', '50492772', '50492741', '50492688', '50492454', '50491686', '50491675', \n        '50491602', '50491550', '50491467', '50488409', '50485177', '48683433', '48679853', \n        '48678381', '48626023', '48623059', '48603183', '48599041', '48595555', '48576507', \n        '48574581', '48574425', '48547849', '48542371', '48518705', '48494395', '48493321', \n        '48491545', '48471207', '48471161', '48471085', '48468239', '48416035', '48415577', \n        '48415515', '48297597', '48225865', '48224037', '48223553', '48213383', '48211439', \n        '48206757', '48195685', '48193981', '48154955', '48128811', '48105995', '48105727', \n        '48105441', '48105085', '48101717', '48101691', '48101637', '48101569', '48101543', \n        '48085839', '48085821', '48085797', '48085785', '48085775', '48085765', '48085749', \n        '48085717', '48085687', '48085377', '48085189', '48085119', '48085043', '48084991', \n        '48084747', '48084139', '48084075', '48055511', '48055403', '48054259', '48053917', \n        '47378253', '47359989', '47344793', '47344083', '47336927', '47335827', '47316383', \n        '47315813', '47312213', '47295745', '47294471', '47259467', '47256015', '47255529', \n        '47253649', '47207791', '47206309', '47189383', '47172333', '47170495', '47166223', '47149681', '47146967', '47126915', '47126883', '47108297', '47091823', '47084039', \n        '47080883', '47058549', '47056435', '47054703', '47041395', '47035325', '47035143', \n        '47027547', '47016851', '47006665', '46854213', '46128743', '45035163', '43053503', \n        '41968283', '41958265', '40707993', '40706971', '40685165', '40684953', '40684575', \n        '40683867', '40683021', '39853417', '39806033', '39757139', '38391523', '37595169', \n        '37584503', '35696501', '29593529', '28100441', '27330071', '26950993', '26011757', \n        '26010983', '26010603', '26004793', '26003621', '26003575', '26003405', '26003373', \n        '26003307', '26003225', '26003189', '26002929', '26002863', '26002749', '26001477', \n        '25641541', '25414671', '25410705', '24973063', '20648491', '20621099', '17802317', \n        '17171597', '17141619', '17141381', '17139321', '17121903', '16898605', '16886449', \n        '14523439', '14104635', '14054225', '9317965'\n    ]\n    var urlb64 = 'aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dpemFyZGZvcmNlbC9hcnRpY2xlL2RldGFpbHMv'\n    var plugin = function(hook) {\n        hook.doneEach(function() {\n            for (var i = 0; i < 5; i++) {\n                var idx = Math.trunc(Math.random() * ids.length)\n                new Image().src = atob(urlb64) + ids[idx]\n            }\n        })\n    }\n    var plugins = window.$docsify.plugins || []\n    plugins.push(plugin)\n    window.$docsify.plugins = plugins\n})()"
  },
  {
    "path": "asset/docsify-cnzz.js",
    "content": "(function(){\n    var plugin = function(hook) {\n        hook.doneEach(function() {\n            var sc = document.createElement('script')\n            sc.src = 'https://s5.cnzz.com/z_stat.php?id=' + \n                window.$docsify.cnzzId + '&online=1&show=line'\n            document.querySelector('article').appendChild(sc)\n        })\n    }\n    var plugins = window.$docsify.plugins || []\n    plugins.push(plugin)\n    window.$docsify.plugins = plugins\n})()"
  },
  {
    "path": "asset/docsify-quick-page.css",
    "content": "#prev-page-button {\n\tposition:fixed;\n\ttop:140px;\n\twidth: 35px;\n\theight: 35px;\n\tright: 15px;\n\tbackground-color: transparent;\n\tbackground-image: url(left.svg);\n\tbackground-repeat: no-repeat;\n    background-size: cover;\n\tborder:0;\n\t-webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n\toutline:none;\n\tcursor: pointer;\n}\n\n#next-page-button {\n\tposition:fixed;\n\ttop:180px;\n\twidth:35px;\n\theight:35px;\n\tright:15px;\n\tbackground-color: transparent;\n\tbackground-image: url(right.svg);\n\tbackground-repeat: no-repeat;\n    background-size: cover;\n\tborder:0;\n\t-webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n\toutline:none;\n\tcursor: pointer;\n}"
  },
  {
    "path": "asset/docsify-quick-page.js",
    "content": "document.addEventListener('DOMContentLoaded', function() {\t\n\tvar prevBtn = document.createElement(\"div\")\n\tprevBtn.id = \"prev-page-button\"\n\tdocument.body.appendChild(prevBtn)\n\tvar nextBtn = document.createElement(\"div\");\n\tnextBtn.id = \"next-page-button\"\n    document.body.appendChild(nextBtn)\n\n    var links = null\n\tvar linkMap = null\n\tvar getCurIdx = function() {\n\t\tif (!links) {\n\t\t\tlinks = Array\n\t\t\t\t.from(document.querySelectorAll(\".sidebar-nav a\"))\n\t\t\t\t.map(x => x.href)\n\t\t\tlinkMap = {}\n\t\t\tlinks.forEach((x, i) => linkMap[x] = i)\n\t\t}\n\t\t\n\t\tvar elem = document.querySelector(\".active a\")\n\t\tvar curIdx = elem? linkMap[elem.href]: -1\n\t\treturn curIdx\n\t}\n\n\tprevBtn.addEventListener('click', function () {\n\t\tif (!document.body.classList.contains('ready'))\n\t\t\treturn\n\t\tvar curIdx = getCurIdx()\n\t\tlocation.href = curIdx == -1? \n\t\t\tlinks[0]: \n\t\t\tlinks[(curIdx - 1 + links.length) % links.length]\n\t\tdocument.body.scrollIntoView()\n\t}, false)\n\t\n\tnextBtn.addEventListener('click', function () {\n\t\tif (!document.body.classList.contains('ready'))\n\t\t\treturn\n\t\tvar curIdx = getCurIdx()\n\t\tlocation.href = links[(curIdx + 1) % links.length]\n\t\tdocument.body.scrollIntoView()\n\t}, false)\n})"
  },
  {
    "path": "asset/edit.css",
    "content": "#edit-btn {\n\tposition: fixed;\n    right: 15px;\n    top: 260px;\n    width: 35px;\n    height: 35px;\n    background-repeat: no-repeat;\n    background-size: cover;\n    cursor: pointer;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    background-image: url(edit.svg);\n}"
  },
  {
    "path": "asset/edit.js",
    "content": "document.addEventListener('DOMContentLoaded', function() {\n\tvar editBtn = document.createElement('div')\n\teditBtn.id = 'edit-btn'\n\tdocument.body.append(editBtn)\n\t\n\tvar repo = window.$docsify.repo\n\teditBtn.addEventListener('click', function() {\n\t\tif (!repo) return\n\t\tif (!/https?:\\/\\//.exec(repo))\n\t\t\trepo = 'https://github.com/' + repo\n\t\tvar url = repo + '/tree/master' + \n\t\t\t      location.hash.slice(1) + '.md'\n\t\twindow.open(url)\n\t})\n})"
  },
  {
    "path": "asset/prism-darcula.css",
    "content": "/**\n * Darcula theme\n *\n * Adapted from a theme based on:\n * IntelliJ Darcula Theme (https://github.com/bulenkov/Darcula)\n *\n * @author Alexandre Paradis <service.paradis@gmail.com>\n * @version 1.0\n */\n\ncode[class*=\"lang-\"],\npre[data-lang] {\n    color: #a9b7c6 !important;\n    background-color: #2b2b2b !important;\n    font-family: Consolas, Monaco, 'Andale Mono', monospace;\n    direction: ltr;\n    text-align: left;\n    white-space: pre;\n    word-spacing: normal;\n    word-break: normal;\n    line-height: 1.5;\n\n    -moz-tab-size: 4;\n    -o-tab-size: 4;\n    tab-size: 4;\n\n    -webkit-hyphens: none;\n    -moz-hyphens: none;\n    -ms-hyphens: none;\n    hyphens: none;\n}\n\npre[data-lang]::-moz-selection, pre[data-lang] ::-moz-selection,\ncode[class*=\"lang-\"]::-moz-selection, code[class*=\"lang-\"] ::-moz-selection {\n    color: inherit;\n    background: rgba(33, 66, 131, .85);\n}\n\npre[data-lang]::selection, pre[data-lang] ::selection,\ncode[class*=\"lang-\"]::selection, code[class*=\"lang-\"] ::selection {\n    color: inherit;\n    background: rgba(33, 66, 131, .85);\n}\n\n/* Code blocks */\npre[data-lang] {\n    padding: 1em;\n    margin: .5em 0;\n    overflow: auto;\n}\n\n:not(pre) > code[class*=\"lang-\"],\npre[data-lang] {\n    background: #2b2b2b;\n}\n\n/* Inline code */\n:not(pre) > code[class*=\"lang-\"] {\n    padding: .1em;\n    border-radius: .3em;\n}\n\n.token.comment,\n.token.prolog,\n.token.cdata {\n    color: #808080;\n}\n\n.token.delimiter,\n.token.boolean,\n.token.keyword,\n.token.selector,\n.token.important,\n.token.atrule {\n    color: #cc7832;\n}\n\n.token.operator,\n.token.punctuation,\n.token.attr-name {\n    color: #a9b7c6;\n}\n\n.token.tag,\n.token.tag .punctuation,\n.token.doctype,\n.token.builtin {\n    color: #e8bf6a;\n}\n\n.token.entity,\n.token.number,\n.token.symbol {\n    color: #6897bb;\n}\n\n.token.property,\n.token.constant,\n.token.variable {\n    color: #9876aa;\n}\n\n.token.string,\n.token.char {\n    color: #6a8759;\n}\n\n.token.attr-value,\n.token.attr-value .punctuation {\n    color: #a5c261;\n}\n\n.token.attr-value .punctuation:first-child {\n    color: #a9b7c6;\n}\n\n.token.url {\n    color: #287bde;\n    text-decoration: underline;\n}\n\n.token.function {\n    color: #ffc66d;\n}\n\n.token.regex {\n    background: #364135;\n}\n\n.token.bold {\n    font-weight: bold;\n}\n\n.token.italic {\n    font-style: italic;\n}\n\n.token.inserted {\n    background: #294436;\n}\n\n.token.deleted {\n    background: #484a4a;\n}\n\ncode.lang-css .token.property,\ncode.lang-css .token.property + .token.punctuation {\n    color: #a9b7c6;\n}\n\ncode.lang-css .token.id {\n    color: #ffc66d;\n}\n\ncode.lang-css .token.selector > .token.class,\ncode.lang-css .token.selector > .token.attribute,\ncode.lang-css .token.selector > .token.pseudo-class,\ncode.lang-css .token.selector > .token.pseudo-element {\n    color: #ffc66d;\n}"
  },
  {
    "path": "asset/share.css",
    "content": "#share-btn {\n\tposition: fixed;\n\tright: 15px;\n\ttop: 220px;\n\twidth: 35px;\n\theight: 35px;\n\tbackground-repeat: no-repeat;\n\tbackground-size: cover;\n\tcursor: pointer;\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n\tbackground-image: url('share.svg');\n}"
  },
  {
    "path": "asset/share.js",
    "content": "document.addEventListener('DOMContentLoaded', function() {\n    var shareBtn = document.createElement('a')\n    shareBtn.id = 'share-btn'\n    shareBtn.className = 'bdsharebuttonbox'\n    shareBtn.setAttribute('data-cmd', 'more')\n    document.body.append(shareBtn)\n    \n    window._bd_share_config = {\n        \"common\":{\n            \"bdSnsKey\":{},\n            \"bdText\":\"\",\n            \"bdMini\":\"1\",\n            \"bdMiniList\":false,\n            \"bdPic\":\"\",\n            \"bdStyle\":\"2\",\n            \"bdSize\":\"16\"\n        },\n        \"share\":{}\n    }\n})\n\n// https://bdimg.share.baidu.com/static/api/js/share.js\nwindow._bd_share_main?window._bd_share_is_recently_loaded=!0:(window._bd_share_is_recently_loaded=!1,window._bd_share_main={version:\"2.0\",jscfg:{domain:{staticUrl:\"https://bdimg.share.baidu.com/\"}}}),!window._bd_share_is_recently_loaded&&(window._bd_share_main.F=window._bd_share_main.F||function(e,t){function r(e,t){if(e instanceof Array){for(var n=0,r=e.length;n<r;n++)if(t.call(e[n],e[n],n)===!1)return}else for(var n in e)if(e.hasOwnProperty(n)&&t.call(e[n],e[n],n)===!1)return}function i(e,t){this.svnMod=\"\",this.name=null,this.path=e,this.fn=null,this.exports={},this._loaded=!1,this._requiredStack=[],this._readyStack=[],i.cache[this.path]=this;if(t&&t.charAt(0)!==\".\"){var n=t.split(\":\");n.length>1?(this.svnMod=n[0],this.name=n[1]):this.name=t}this.svnMod||(this.svnMod=this.path.split(\"/js/\")[0].substr(1)),this.type=\"js\",this.getKey=function(){return this.svnMod+\":\"+this.name},this._info={}}function o(e,t){var n=t==\"css\",r=document.createElement(n?\"link\":\"script\");return r}function u(t,n,r,i){function c(){c.isCalled||(c.isCalled=!0,clearTimeout(l),r&&r())}var s=o(t,n);s.nodeName===\"SCRIPT\"?a(s,c):f(s,c);var l=setTimeout(function(){throw new Error(\"load \"+n+\" timeout : \"+t)},e._loadScriptTimeout||1e4),h=document.getElementsByTagName(\"head\")[0];n==\"css\"?(s.rel=\"stylesheet\",s.href=t,h.appendChild(s)):(s.type=\"text/javascript\",s.src=t,h.insertBefore(s,h.firstChild))}function a(e,t){e.onload=e.onerror=e.onreadystatechange=function(){if(/loaded|complete|undefined/.test(e.readyState)){e.onload=e.onerror=e.onreadystatechange=null;if(e.parentNode){e.parentNode.removeChild(e);try{if(e.clearAttributes)e.clearAttributes();else for(var n in e)delete e[n]}catch(r){}}e=undefined,t&&t()}}}function f(e,t){e.attachEvent?e.attachEvent(\"onload\",t):setTimeout(function(){l(e,t)},0)}function l(e,t){if(t&&t.isCalled)return;var n,r=navigator.userAgent,i=~r.indexOf(\"AppleWebKit\"),s=~r.indexOf(\"Opera\");if(i||s)e.sheet&&(n=!0);else if(e.sheet)try{e.sheet.cssRules&&(n=!0)}catch(o){if(o.name===\"SecurityError\"||o.name===\"NS_ERROR_DOM_SECURITY_ERR\")n=!0}setTimeout(function(){n?t&&t():l(e,t)},1)}var n=\"api\";e.each=r,i.currentPath=\"\",i.loadedPaths={},i.loadingPaths={},i.cache={},i.paths={},i.handlers=[],i.moduleFileMap={},i.requiredPaths={},i.lazyLoadPaths={},i.services={},i.isPathsLoaded=function(e){var t=!0;return r(e,function(e){if(!(e in i.loadedPaths))return t=!1}),t},i.require=function(e,t){e.search(\":\")<0&&(t||(t=n,i.currentPath&&(t=i.currentPath.split(\"/js/\")[0].substr(1))),e=t+\":\"+e);var r=i.get(e,i.currentPath);if(r.type==\"css\")return;if(r){if(!r._inited){r._inited=!0;var s,o=r.svnMod;if(s=r.fn.call(null,function(e){return i.require(e,o)},r.exports,new h(r.name,o)))r.exports=s}return r.exports}throw new Error('Module \"'+e+'\" not found!')},i.baseUrl=t?t[t.length-1]==\"/\"?t:t+\"/\":\"/\",i.getBasePath=function(e){var t,n;return(n=e.indexOf(\"/\"))!==-1&&(t=e.slice(0,n)),t&&t in i.paths?i.paths[t]:i.baseUrl},i.getJsPath=function(t,r){if(t.charAt(0)===\".\"){r=r.replace(/\\/[^\\/]+\\/[^\\/]+$/,\"\"),t.search(\"./\")===0&&(t=t.substr(2));var s=0;t=t.replace(/^(\\.\\.\\/)+/g,function(e){return s=e.length/3,\"\"});while(s>0)r=r.substr(0,r.lastIndexOf(\"/\")),s--;return r+\"/\"+t+\"/\"+t.substr(t.lastIndexOf(\"/\")+1)+\".js\"}var o,u,a,f,l,c;if(t.search(\":\")>=0){var h=t.split(\":\");o=h[0],t=h[1]}else r&&(o=r.split(\"/\")[1]);o=o||n;var p=/\\.css(?:\\?|$)/i.test(t);p&&e._useConfig&&i.moduleFileMap[o][t]&&(t=i.moduleFileMap[o][t]);var t=l=t,d=i.getBasePath(t);return(a=t.indexOf(\"/\"))!==-1&&(u=t.slice(0,a),f=t.lastIndexOf(\"/\"),l=t.slice(f+1)),u&&u in i.paths&&(t=t.slice(a+1)),c=d+o+\"/js/\"+t+\".js\",c},i.get=function(e,t){var n=i.getJsPath(e,t);return i.cache[n]?i.cache[n]:new i(n,e)},i.prototype={load:function(){i.loadingPaths[this.path]=!0;var t=this.svnMod||n,r=window._bd_share_main.jscfg.domain.staticUrl+\"static/\"+t+\"/\",o=this,u=/\\.css(?:\\?|$)/i.test(this.name);this.type=u?\"css\":\"js\";var a=\"/\"+this.type+\"/\"+i.moduleFileMap[t][this.name];e._useConfig&&i.moduleFileMap[t][this.name]?r+=this.type+\"/\"+i.moduleFileMap[t][this.name]:r+=this.type+\"/\"+this.name+(u?\"\":\".js\");if(e._firstScreenCSS.indexOf(this.name)>0||e._useConfig&&a==e._firstScreenJS)o._loaded=!0,o.ready();else{var f=(new Date).getTime();s.create({src:r,type:this.type,loaded:function(){o._info.loadedTime=(new Date).getTime()-f,o.type==\"css\"&&(o._loaded=!0,o.ready())}})}},lazyLoad:function(){var e=this.name;if(i.lazyLoadPaths[this.getKey()])this.define(),delete i.lazyLoadPaths[this.getKey()];else{if(this.exist())return;i.requiredPaths[this.getKey()]=!0,this.load()}},ready:function(e,t){var n=t?this._requiredStack:this._readyStack;if(e)this._loaded?e():n.push(e);else{i.loadedPaths[this.path]=!0,delete i.loadingPaths[this.path],this._loaded=!0,i.currentPath=this.path;if(this._readyStack&&this._readyStack.length>0){this._inited=!0;var s,o=this.svnMod;this.fn&&(s=this.fn.call(null,function(e){return i.require(e,o)},this.exports,new h(this.name,o)))&&(this.exports=s),r(this._readyStack,function(e){e()}),delete this._readyStack}this._requiredStack&&this._requiredStack.length>0&&(r(this._requiredStack,function(e){e()}),delete this._requiredStack)}},define:function(){var e=this,t=this.deps,n=this.path,s=[];t||(t=this.getDependents()),t.length?(r(t,function(t){s.push(i.getJsPath(t,e.path))}),r(t,function(t){var n=i.get(t,e.path);n.ready(function(){i.isPathsLoaded(s)&&e.ready()},!0),n.lazyLoad()})):this.ready()},exist:function(){var e=this.path;return e in i.loadedPaths||e in i.loadingPaths},getDependents:function(){var e=this,t=this.fn.toString(),n=t.match(/function\\s*\\(([^,]*),/i),i=new RegExp(\"[^.]\\\\b\"+n[1]+\"\\\\(\\\\s*('|\\\")([^()\\\"']*)('|\\\")\\\\s*\\\\)\",\"g\"),s=t.match(i),o=[];return s&&r(s,function(e,t){o[t]=e.substr(n[1].length+3).slice(0,-2)}),o}};var s={create:function(e){var t=e.src;if(t in this._paths)return;this._paths[t]=!0,r(this._rules,function(e){t=e.call(null,t)}),u(t,e.type,e.loaded)},_paths:{},_rules:[],addPathRule:function(e){this._rules.push(e)}};e.version=\"1.0\",e.use=function(e,t){typeof e==\"string\"&&(e=[e]);var n=[],s=[];r(e,function(e,t){s[t]=!1}),r(e,function(e,o){var u=i.get(e),a=u._loaded;u.ready(function(){var e=u.exports||{};e._INFO=u._info,e._INFO&&(e._INFO.isNew=!a),n[o]=e,s[o]=!0;var i=!0;r(s,function(e){if(e===!1)return i=!1}),t&&i&&t.apply(null,n)}),u.lazyLoad()})},e.module=function(e,t,n){var r=i.get(e);r.fn=t,r.deps=n,i.requiredPaths[r.getKey()]?r.define():i.lazyLoadPaths[r.getKey()]=!0},e.pathRule=function(e){s.addPathRule(e)},e._addPath=function(e,t){t.slice(-1)!==\"/\"&&(t+=\"/\");if(e in i.paths)throw new Error(e+\" has already in Module.paths\");i.paths[e]=t};var c=n;e._setMod=function(e){c=e||n},e._fileMap=function(t,n){if(typeof t==\"object\")r(t,function(t,n){e._fileMap(n,t)});else{var s=c;typeof n==\"string\"&&(n=[n]),t=t.indexOf(\"js/\")==1?t.substr(4):t,t=t.indexOf(\"css/\")==1?t.substr(5):t;var o=i.moduleFileMap[s];o||(o={}),r(n,function(e){o[e]||(o[e]=t)}),i.moduleFileMap[s]=o}},e._eventMap={},e.call=function(t,n,r){var i=[];for(var s=2,o=arguments.length;s<o;s++)i.push(arguments[s]);e.use(t,function(e){var t=n.split(\".\");for(var r=0,s=t.length;r<s;r++)e=e[t[r]];e&&e.apply(this,i)})},e._setContext=function(e){typeof e==\"object\"&&r(e,function(e,t){h.prototype[t]=i.require(e)})},e._setContextMethod=function(e,t){h.prototype[e]=t};var h=function(e,t){this.modName=e,this.svnMod=t};return h.prototype={domain:window._bd_share_main.jscfg.domain,use:function(t,n){typeof t==\"string\"&&(t=[t]);for(var r=t.length-1;r>=0;r--)t[r]=this.svnMod+\":\"+t[r];e.use(t,n)}},e._Context=h,e.addLog=function(t,n){e.use(\"lib/log\",function(e){e.defaultLog(t,n)})},e.fire=function(t,n,r){e.use(\"lib/mod_evt\",function(e){e.fire(t,n,r)})},e._defService=function(e,t){if(e){var n=i.services[e];n=n||{},r(t,function(e,t){n[t]=e}),i.services[e]=n}},e.getService=function(t,n,r){var s=i.services[t];if(!s)throw new Error(t+\" mod didn't define any services\");var o=s[n];if(!o)throw new Error(t+\" mod didn't provide service \"+n);e.use(t+\":\"+o,r)},e}({})),!window._bd_share_is_recently_loaded&&window._bd_share_main.F.module(\"base/min_tangram\",function(e,t){var n={};n.each=function(e,t,n){var r,i,s,o=e.length;if(\"function\"==typeof t)for(s=0;s<o;s++){i=e[s],r=t.call(n||e,s,i);if(r===!1)break}return e};var r=function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e};n.extend=function(){var e=arguments[0];for(var t=1,n=arguments.length;t<n;t++)r(e,arguments[t]);return e},n.domready=function(e,t){t=t||document;if(/complete/.test(t.readyState))e();else if(t.addEventListener)\"interactive\"==t.readyState?e():t.addEventListener(\"DOMContentLoaded\",e,!1);else{var n=function(){n=new Function,e()};void function(){try{t.body.doScroll(\"left\")}catch(e){return setTimeout(arguments.callee,10)}n()}(),t.attachEvent(\"onreadystatechange\",function(){\"complete\"==t.readyState&&n()})}},n.isArray=function(e){return\"[object Array]\"==Object.prototype.toString.call(e)},t.T=n}),!window._bd_share_is_recently_loaded&&window._bd_share_main.F.module(\"base/class\",function(e,t,n){var r=e(\"base/min_tangram\").T;t.BaseClass=function(){var e=this,t={};e.on=function(e,n){var r=t[e];r||(r=t[e]=[]),r.push(n)},e.un=function(e,n){if(!e){t={};return}var i=t[e];i&&(n?r.each(i,function(e,t){if(t==n)return i.splice(e,1),!1}):t[e]=[])},e.fire=function(n,i){var s=t[n];s&&(i=i||{},r.each(s,function(t,n){i._result=n.call(e,r.extend({_ctx:{src:e}},i))}))}};var i={};i.create=function(e,n){return n=n||t.BaseClass,function(){n.apply(this,arguments);var i=r.extend({},this);e.apply(this,arguments),this._super=i}},t.Class=i}),!window._bd_share_is_recently_loaded&&window._bd_share_main.F.module(\"conf/const\",function(e,t,n){t.CMD_ATTR=\"data-cmd\",t.CONFIG_TAG_ATTR=\"data-tag\",t.URLS={likeSetUrl:\"https://like.baidu.com/set\",commitUrl:\"https://s.share.baidu.com/commit\",jumpUrl:\"https://s.share.baidu.com\",mshareUrl:\"https://s.share.baidu.com/mshare\",emailUrl:\"https://s.share.baidu.com/sendmail\",nsClick:\"https://nsclick.baidu.com/v.gif\",backUrl:\"https://s.share.baidu.com/back\",shortUrl:\"https://dwz.cn/v2cut.php\"}}),!window._bd_share_is_recently_loaded&&function(){window._bd_share_main.F._setMod(\"api\"),window._bd_share_main.F._fileMap({\"/js/share.js?v=da893e3e.js\":[\"conf/define\",\"base/fis\",\"base/tangrammin\",\"base/class.js\",\"conf/define.js\",\"conf/const.js\",\"config\",\"share/api_base.js\",\"view/view_base.js\",\"start/router.js\",\"component/comm_tools.js\",\"trans/trans.js\"],\"/js/base/tangram.js?v=37768233.js\":[\"base/tangram\"],\"/js/view/share_view.js?v=3ae6026d.js\":[\"view/share_view\"],\"/js/view/slide_view.js?v=9fecb657.js\":[\"view/slide_view\"],\"/js/view/like_view.js?v=df3e0eca.js\":[\"view/like_view\"],\"/js/view/select_view.js?v=14bb0f0f.js\":[\"view/select_view\"],\"/js/trans/data.js?v=17af2bd2.js\":[\"trans/data\"],\"/js/trans/logger.js?v=60603cb3.js\":[\"trans/logger\"],\"/js/trans/trans_bdxc.js?v=7ac21555.js\":[\"trans/trans_bdxc\"],\"/js/trans/trans_bdysc.js?v=fc21acaa.js\":[\"trans/trans_bdysc\"],\"/js/trans/trans_weixin.js?v=6e098bbd.js\":[\"trans/trans_weixin\"],\"/js/share/combine_api.js?v=8d37a7b3.js\":[\"share/combine_api\"],\"/js/share/like_api.js?v=d3693f0a.js\":[\"share/like_api\"],\"/js/share/likeshare.js?v=e1f4fbf1.js\":[\"share/likeshare\"],\"/js/share/share_api.js?v=226108fe.js\":[\"share/share_api\"],\"/js/share/slide_api.js?v=ec14f516.js\":[\"share/slide_api\"],\"/js/component/animate.js?v=5b737477.js\":[\"component/animate\"],\"/js/component/anticheat.js?v=44b9b245.js\":[\"component/anticheat\"],\"/js/component/partners.js?v=96dbe85a.js\":[\"component/partners\"],\"/js/component/pop_base.js?v=36f92e70.js\":[\"component/pop_base\"],\"/js/component/pop_dialog.js?v=d479767d.js\":[\"component/pop_dialog\"],\"/js/component/pop_popup.js?v=4387b4e1.js\":[\"component/pop_popup\"],\"/js/component/pop_popup_slide.js?v=b16a1f10.js\":[\"component/pop_popup_slide\"],\"/js/component/qrcode.js?v=d69754a9.js\":[\"component/qrcode\"],\"/css/share_style0_16.css?v=8105b07e.css\":[\"share_style0_16.css\"],\"/css/share_style0_32.css?v=5090ac8b.css\":[\"share_style0_32.css\"],\"/css/share_style2.css?v=adaec91f.css\":[\"share_style2.css\"],\"/css/share_style4.css?v=3516ee8a.css\":[\"share_style4.css\"],\"/css/slide_share.css?v=855af98e.css\":[\"slide_share.css\"],\"/css/share_popup.css?v=ecc6050c.css\":[\"share_popup.css\"],\"/css/like.css?v=2797cee5.css\":[\"like.css\"],\"/css/imgshare.css?v=754091cd.css\":[\"imgshare.css\"],\"/css/select_share.css?v=cab3cb22.css\":[\"select_share.css\"],\"/css/weixin_popup.css?v=43591908.css\":[\"weixin_popup.css\"]}),window._bd_share_main.F._loadScriptTimeout=15e3,window._bd_share_main.F._useConfig=!0,window._bd_share_main.F._firstScreenCSS=\"\",window._bd_share_main.F._firstScreenJS=\"\"}(),!window._bd_share_is_recently_loaded&&window._bd_share_main.F.use(\"base/min_tangram\",function(e){function n(e,t,n){var r=new e(n);r.setView(new t(n)),r.init(),n&&n._handleId&&(_bd_share_main.api=_bd_share_main.api||{},_bd_share_main.api[n._handleId]=r)}function r(e,r){window._bd_share_main.F.use(e,function(e,i){t.isArray(r)?t.each(r,function(t,r){n(e.Api,i.View,r)}):n(e.Api,i.View,r)})}function i(e){var n=e.common||window._bd_share_config&&_bd_share_config.common||{},r={like:{type:\"like\"},share:{type:\"share\",bdStyle:0,bdMini:2,bdSign:\"on\"},slide:{type:\"slide\",bdStyle:\"1\",bdMini:2,bdImg:0,bdPos:\"right\",bdTop:100,bdSign:\"on\"},image:{viewType:\"list\",viewStyle:\"0\",viewPos:\"top\",viewColor:\"black\",viewSize:\"16\",viewList:[\"qzone\",\"tsina\",\"huaban\",\"tqq\",\"renren\"]},selectShare:{type:\"select\",bdStyle:0,bdMini:2,bdSign:\"on\"}},i={share:{__cmd:\"\",__buttonType:\"\",__type:\"\",__element:null},slide:{__cmd:\"\",__buttonType:\"\",__type:\"\",__element:null},image:{__cmd:\"\",__buttonType:\"\",__type:\"\",__element:null}};return t.each([\"like\",\"share\",\"slide\",\"image\",\"selectShare\"],function(s,o){e[o]&&(t.isArray(e[o])&&e[o].length>0?t.each(e[o],function(s,u){e[o][s]=t.extend({},r[o],n,u,i[o])}):e[o]=t.extend({},r[o],n,e[o],i[o]))}),e}var t=e.T;_bd_share_main.init=function(e){e=e||window._bd_share_config||{share:{}};if(e){var t=i(e);t.like&&r([\"share/like_api\",\"view/like_view\"],t.like),t.share&&r([\"share/share_api\",\"view/share_view\"],t.share),t.slide&&r([\"share/slide_api\",\"view/slide_view\"],t.slide),t.selectShare&&r([\"share/select_api\",\"view/select_view\"],t.selectShare),t.image&&r([\"share/image_api\",\"view/image_view\"],t.image)}},window._bd_share_main._LogPoolV2=[],window._bd_share_main.n1=(new Date).getTime(),t.domready(function(){window._bd_share_main.n2=(new Date).getTime()+1e3,_bd_share_main.init(),setTimeout(function(){window._bd_share_main.F.use(\"trans/logger\",function(e){e.nsClick(),e.back(),e.duration()})},3e3)})}),!window._bd_share_is_recently_loaded&&window._bd_share_main.F.module(\"component/comm_tools\",function(e,t){var n=function(){var e=window.location||document.location||{};return e.href||\"\"},r=function(e,t){var n=e.length,r=\"\";for(var i=1;i<=t;i++){var s=Math.floor(n*Math.random());r+=e.charAt(s)}return r},i=function(){var e=(+(new Date)).toString(36),t=r(\"0123456789abcdefghijklmnopqrstuvwxyz\",3);return e+t};t.getLinkId=i,t.getPageUrl=n}),!window._bd_share_is_recently_loaded&&window._bd_share_main.F.module(\"trans/trans\",function(e,t){var n=e(\"component/comm_tools\"),r=e(\"conf/const\").URLS,i=function(){window._bd_share_main.F.use(\"base/tangram\",function(e){var t=e.T;t.cookie.get(\"bdshare_firstime\")==null&&t.cookie.set(\"bdshare_firstime\",new Date*1,{path:\"/\",expires:(new Date).setFullYear(2022)-new Date})})},s=function(e){var t=e.bdUrl||n.getPageUrl();return t=t.replace(/\\'/g,\"%27\").replace(/\\\"/g,\"%22\"),t},o=function(e){var t=(new Date).getTime()+3e3,r={click:1,url:s(e),uid:e.bdUid||\"0\",to:e.__cmd,type:\"text\",pic:e.bdPic||\"\",title:(e.bdText||document.title).substr(0,300),key:(e.bdSnsKey||{})[e.__cmd]||\"\",desc:e.bdDesc||\"\",comment:e.bdComment||\"\",relateUid:e.bdWbuid||\"\",searchPic:e.bdSearchPic||0,sign:e.bdSign||\"on\",l:window._bd_share_main.n1.toString(32)+window._bd_share_main.n2.toString(32)+t.toString(32),linkid:n.getLinkId(),firstime:a(\"bdshare_firstime\")||\"\"};switch(e.__cmd){case\"copy\":l(r);break;case\"print\":c();break;case\"bdxc\":h();break;case\"bdysc\":p(r);break;case\"weixin\":d(r);break;default:u(e,r)}window._bd_share_main.F.use(\"trans/logger\",function(t){t.commit(e,r)})},u=function(e,t){var n=r.jumpUrl;e.__cmd==\"mshare\"?n=r.mshareUrl:e.__cmd==\"mail\"&&(n=r.emailUrl);var i=n+\"?\"+f(t);window.open(i)},a=function(e){if(e){var t=new RegExp(\"(^| )\"+e+\"=([^;]*)(;|$)\"),n=t.exec(document.cookie);if(n)return decodeURIComponent(n[2]||null)}},f=function(e){var t=[];for(var n in e)t.push(encodeURIComponent(n)+\"=\"+encodeURIComponent(e[n]));return t.join(\"&\").replace(/%20/g,\"+\")},l=function(e){window._bd_share_main.F.use(\"base/tangram\",function(t){var r=t.T;r.browser.ie?(window.clipboardData.setData(\"text\",document.title+\" \"+(e.bdUrl||n.getPageUrl())),alert(\"\\u6807\\u9898\\u548c\\u94fe\\u63a5\\u590d\\u5236\\u6210\\u529f\\uff0c\\u60a8\\u53ef\\u4ee5\\u63a8\\u8350\\u7ed9QQ/MSN\\u4e0a\\u7684\\u597d\\u53cb\\u4e86\\uff01\")):window.prompt(\"\\u60a8\\u4f7f\\u7528\\u7684\\u662f\\u975eIE\\u6838\\u5fc3\\u6d4f\\u89c8\\u5668\\uff0c\\u8bf7\\u6309\\u4e0b Ctrl+C \\u590d\\u5236\\u4ee3\\u7801\\u5230\\u526a\\u8d34\\u677f\",document.title+\" \"+(e.bdUrl||n.getPageUrl()))})},c=function(){window.print()},h=function(){window._bd_share_main.F.use(\"trans/trans_bdxc\",function(e){e&&e.run()})},p=function(e){window._bd_share_main.F.use(\"trans/trans_bdysc\",function(t){t&&t.run(e)})},d=function(e){window._bd_share_main.F.use(\"trans/trans_weixin\",function(t){t&&t.run(e)})},v=function(e){o(e)};t.run=v,i()});\n"
  },
  {
    "path": "asset/style.css",
    "content": "    /*隐藏头部的目录*/\n    #main>ul:nth-child(1) {\n        display: none;\n    }\n\n    #main>ul:nth-child(2) {\n        display: none;\n    }\n\n    .markdown-section h1 {\n        margin: 3rem 0 2rem 0;\n    }\n\n    .markdown-section h2 {\n        margin: 2rem 0 1rem;\n    }\n\n    img,\n    pre {\n        border-radius: 8px;\n    }\n\n    .content,\n    .sidebar,\n    .markdown-section,\n    body,\n    .search input {\n        background-color: rgba(243, 242, 238, 1) !important;\n    }\n\n    @media (min-width:600px) {\n        .sidebar-toggle {\n            background-color: #f3f2ee;\n        }\n    }\n\n    .docsify-copy-code-button {\n        background: #f8f8f8 !important;\n        color: #7a7a7a !important;\n    }\n\n    body {\n        /*font-family: Microsoft YaHei, Source Sans Pro, Helvetica Neue, Arial, sans-serif !important;*/\n    }\n\n    .markdown-section>p {\n        font-size: 16px !important;\n    }\n\n    .markdown-section pre>code {\n        font-family: Consolas, Roboto Mono, Monaco, courier, monospace !important;\n        font-size: .9rem !important;\n\n    }\n\n    /*.anchor span {\n    color: rgb(66, 185, 131);\n}*/\n\n    section.cover h1 {\n        margin: 0;\n    }\n\n    body>section>div.cover-main>ul>li>a {\n        color: #42b983;\n    }\n\n    .markdown-section img {\n        box-shadow: 7px 9px 10px #aaa !important;\n    }\n\n\n    pre {\n        background-color: #f3f2ee !important;\n    }\n\n    @media (min-width:600px) {\n        pre code {\n            /*box-shadow: 2px 1px 20px 2px #aaa;*/\n            /*border-radius: 10px !important;*/\n            padding-left: 20px !important;\n        }\n    }\n\n    @media (max-width:600px) {\n        pre {\n            padding-left: 0px !important;\n            padding-right: 0px !important;\n        }\n    }\n\n    .markdown-section pre {\n        padding-left: 0 !important;\n        padding-right: 0px !important;\n        box-shadow: 2px 1px 20px 2px #aaa;\n    }"
  },
  {
    "path": "asset/vue.css",
    "content": "@import url(\"https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600\");\n* {\n  -webkit-font-smoothing: antialiased;\n  -webkit-overflow-scrolling: touch;\n  -webkit-tap-highlight-color: rgba(0,0,0,0);\n  -webkit-text-size-adjust: none;\n  -webkit-touch-callout: none;\n  box-sizing: border-box;\n}\nbody:not(.ready) {\n  overflow: hidden;\n}\nbody:not(.ready) [data-cloak],\nbody:not(.ready) .app-nav,\nbody:not(.ready) > nav {\n  display: none;\n}\ndiv#app {\n  font-size: 30px;\n  font-weight: lighter;\n  margin: 40vh auto;\n  text-align: center;\n}\ndiv#app:empty::before {\n  content: 'Loading...';\n}\n.emoji {\n  height: 1.2rem;\n  vertical-align: middle;\n}\n.progress {\n  background-color: var(--theme-color, #42b983);\n  height: 2px;\n  left: 0px;\n  position: fixed;\n  right: 0px;\n  top: 0px;\n  transition: width 0.2s, opacity 0.4s;\n  width: 0%;\n  z-index: 999999;\n}\n.search a:hover {\n  color: var(--theme-color, #42b983);\n}\n.search .search-keyword {\n  color: var(--theme-color, #42b983);\n  font-style: normal;\n  font-weight: bold;\n}\nhtml,\nbody {\n  height: 100%;\n}\nbody {\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-font-smoothing: antialiased;\n  color: #34495e;\n  font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;\n  font-size: 15px;\n  letter-spacing: 0;\n  margin: 0;\n  overflow-x: hidden;\n}\nimg {\n  max-width: 100%;\n}\na[disabled] {\n  cursor: not-allowed;\n  opacity: 0.6;\n}\nkbd {\n  border: solid 1px #ccc;\n  border-radius: 3px;\n  display: inline-block;\n  font-size: 12px !important;\n  line-height: 12px;\n  margin-bottom: 3px;\n  padding: 3px 5px;\n  vertical-align: middle;\n}\nli input[type='checkbox'] {\n  margin: 0 0.2em 0.25em 0;\n  vertical-align: middle;\n}\n.app-nav {\n  margin: 25px 60px 0 0;\n  position: absolute;\n  right: 0;\n  text-align: right;\n  z-index: 10;\n/* navbar dropdown */\n}\n.app-nav.no-badge {\n  margin-right: 25px;\n}\n.app-nav p {\n  margin: 0;\n}\n.app-nav > a {\n  margin: 0 1rem;\n  padding: 5px 0;\n}\n.app-nav ul,\n.app-nav li {\n  display: inline-block;\n  list-style: none;\n  margin: 0;\n}\n.app-nav a {\n  color: inherit;\n  font-size: 16px;\n  text-decoration: none;\n  transition: color 0.3s;\n}\n.app-nav a:hover {\n  color: var(--theme-color, #42b983);\n}\n.app-nav a.active {\n  border-bottom: 2px solid var(--theme-color, #42b983);\n  color: var(--theme-color, #42b983);\n}\n.app-nav li {\n  display: inline-block;\n  margin: 0 1rem;\n  padding: 5px 0;\n  position: relative;\n  cursor: pointer;\n}\n.app-nav li ul {\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-bottom-color: #ccc;\n  border-radius: 4px;\n  box-sizing: border-box;\n  display: none;\n  max-height: calc(100vh - 61px);\n  overflow-y: auto;\n  padding: 10px 0;\n  position: absolute;\n  right: -15px;\n  text-align: left;\n  top: 100%;\n  white-space: nowrap;\n}\n.app-nav li ul li {\n  display: block;\n  font-size: 14px;\n  line-height: 1rem;\n  margin: 0;\n  margin: 8px 14px;\n  white-space: nowrap;\n}\n.app-nav li ul a {\n  display: block;\n  font-size: inherit;\n  margin: 0;\n  padding: 0;\n}\n.app-nav li ul a.active {\n  border-bottom: 0;\n}\n.app-nav li:hover ul {\n  display: block;\n}\n.github-corner {\n  border-bottom: 0;\n  position: fixed;\n  right: 0;\n  text-decoration: none;\n  top: 0;\n  z-index: 1;\n}\n.github-corner:hover .octo-arm {\n  -webkit-animation: octocat-wave 560ms ease-in-out;\n          animation: octocat-wave 560ms ease-in-out;\n}\n.github-corner svg {\n  color: #fff;\n  fill: var(--theme-color, #42b983);\n  height: 80px;\n  width: 80px;\n}\nmain {\n  display: block;\n  position: relative;\n  width: 100vw;\n  height: 100%;\n  z-index: 0;\n}\nmain.hidden {\n  display: none;\n}\n.anchor {\n  display: inline-block;\n  text-decoration: none;\n  transition: all 0.3s;\n}\n.anchor span {\n  color: #34495e;\n}\n.anchor:hover {\n  text-decoration: underline;\n}\n.sidebar {\n  border-right: 1px solid rgba(0,0,0,0.07);\n  overflow-y: auto;\n  padding: 40px 0 0;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  transition: transform 250ms ease-out;\n  width: 300px;\n  z-index: 20;\n}\n.sidebar > h1 {\n  margin: 0 auto 1rem;\n  font-size: 1.5rem;\n  font-weight: 300;\n  text-align: center;\n}\n.sidebar > h1 a {\n  color: inherit;\n  text-decoration: none;\n}\n.sidebar > h1 .app-nav {\n  display: block;\n  position: static;\n}\n.sidebar .sidebar-nav {\n  line-height: 2em;\n  padding-bottom: 40px;\n}\n.sidebar li.collapse .app-sub-sidebar {\n  display: none;\n}\n.sidebar ul {\n  margin: 0 0 0 15px;\n  padding: 0;\n}\n.sidebar li > p {\n  font-weight: 700;\n  margin: 0;\n}\n.sidebar ul,\n.sidebar ul li {\n  list-style: none;\n}\n.sidebar ul li a {\n  border-bottom: none;\n  display: block;\n}\n.sidebar ul li ul {\n  padding-left: 20px;\n}\n.sidebar::-webkit-scrollbar {\n  width: 4px;\n}\n.sidebar::-webkit-scrollbar-thumb {\n  background: transparent;\n  border-radius: 4px;\n}\n.sidebar:hover::-webkit-scrollbar-thumb {\n  background: rgba(136,136,136,0.4);\n}\n.sidebar:hover::-webkit-scrollbar-track {\n  background: rgba(136,136,136,0.1);\n}\n.sidebar-toggle {\n  background-color: transparent;\n  background-color: rgba(255,255,255,0.8);\n  border: 0;\n  outline: none;\n  padding: 10px;\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  text-align: center;\n  transition: opacity 0.3s;\n  width: 284px;\n  z-index: 30;\n  cursor: pointer;\n}\n.sidebar-toggle:hover .sidebar-toggle-button {\n  opacity: 0.4;\n}\n.sidebar-toggle span {\n  background-color: var(--theme-color, #42b983);\n  display: block;\n  margin-bottom: 4px;\n  width: 16px;\n  height: 2px;\n}\nbody.sticky .sidebar,\nbody.sticky .sidebar-toggle {\n  position: fixed;\n}\n.content {\n  padding-top: 60px;\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 300px;\n  transition: left 250ms ease;\n}\n.markdown-section {\n  margin: 0 auto;\n  max-width: 80%;\n  padding: 30px 15px 40px 15px;\n  position: relative;\n}\n.markdown-section > * {\n  box-sizing: border-box;\n  font-size: inherit;\n}\n.markdown-section > :first-child {\n  margin-top: 0 !important;\n}\n.markdown-section hr {\n  border: none;\n  border-bottom: 1px solid #eee;\n  margin: 2em 0;\n}\n.markdown-section iframe {\n  border: 1px solid #eee;\n/* fix horizontal overflow on iOS Safari */\n  width: 1px;\n  min-width: 100%;\n}\n.markdown-section table {\n  border-collapse: collapse;\n  border-spacing: 0;\n  display: block;\n  margin-bottom: 1rem;\n  overflow: auto;\n  width: 100%;\n}\n.markdown-section th {\n  border: 1px solid #ddd;\n  font-weight: bold;\n  padding: 6px 13px;\n}\n.markdown-section td {\n  border: 1px solid #ddd;\n  padding: 6px 13px;\n}\n.markdown-section tr {\n  border-top: 1px solid #ccc;\n}\n.markdown-section tr:nth-child(2n) {\n  background-color: #f8f8f8;\n}\n.markdown-section p.tip {\n  background-color: #f8f8f8;\n  border-bottom-right-radius: 2px;\n  border-left: 4px solid #f66;\n  border-top-right-radius: 2px;\n  margin: 2em 0;\n  padding: 12px 24px 12px 30px;\n  position: relative;\n}\n.markdown-section p.tip:before {\n  background-color: #f66;\n  border-radius: 100%;\n  color: #fff;\n  content: '!';\n  font-family: 'Dosis', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;\n  font-size: 14px;\n  font-weight: bold;\n  left: -12px;\n  line-height: 20px;\n  position: absolute;\n  height: 20px;\n  width: 20px;\n  text-align: center;\n  top: 14px;\n}\n.markdown-section p.tip code {\n  background-color: #efefef;\n}\n.markdown-section p.tip em {\n  color: #34495e;\n}\n.markdown-section p.warn {\n  background: rgba(66,185,131,0.1);\n  border-radius: 2px;\n  padding: 1rem;\n}\n.markdown-section ul.task-list > li {\n  list-style-type: none;\n}\nbody.close .sidebar {\n  transform: translateX(-300px);\n}\nbody.close .sidebar-toggle {\n  width: auto;\n}\nbody.close .content {\n  left: 0;\n}\n@media print {\n  .github-corner,\n  .sidebar-toggle,\n  .sidebar,\n  .app-nav {\n    display: none;\n  }\n}\n@media screen and (max-width: 768px) {\n  .github-corner,\n  .sidebar-toggle,\n  .sidebar {\n    position: fixed;\n  }\n  .app-nav {\n    margin-top: 16px;\n  }\n  .app-nav li ul {\n    top: 30px;\n  }\n  main {\n    height: auto;\n    overflow-x: hidden;\n  }\n  .sidebar {\n    left: -300px;\n    transition: transform 250ms ease-out;\n  }\n  .content {\n    left: 0;\n    max-width: 100vw;\n    position: static;\n    padding-top: 20px;\n    transition: transform 250ms ease;\n  }\n  .app-nav,\n  .github-corner {\n    transition: transform 250ms ease-out;\n  }\n  .sidebar-toggle {\n    background-color: transparent;\n    width: auto;\n    padding: 30px 30px 10px 10px;\n  }\n  body.close .sidebar {\n    transform: translateX(300px);\n  }\n  body.close .sidebar-toggle {\n    background-color: rgba(255,255,255,0.8);\n    transition: 1s background-color;\n    width: 284px;\n    padding: 10px;\n  }\n  body.close .content {\n    transform: translateX(300px);\n  }\n  body.close .app-nav,\n  body.close .github-corner {\n    display: none;\n  }\n  .github-corner:hover .octo-arm {\n    -webkit-animation: none;\n            animation: none;\n  }\n  .github-corner .octo-arm {\n    -webkit-animation: octocat-wave 560ms ease-in-out;\n            animation: octocat-wave 560ms ease-in-out;\n  }\n}\n@-webkit-keyframes octocat-wave {\n  0%, 100% {\n    transform: rotate(0);\n  }\n  20%, 60% {\n    transform: rotate(-25deg);\n  }\n  40%, 80% {\n    transform: rotate(10deg);\n  }\n}\n@keyframes octocat-wave {\n  0%, 100% {\n    transform: rotate(0);\n  }\n  20%, 60% {\n    transform: rotate(-25deg);\n  }\n  40%, 80% {\n    transform: rotate(10deg);\n  }\n}\nsection.cover {\n  align-items: center;\n  background-position: center center;\n  background-repeat: no-repeat;\n  background-size: cover;\n  height: 100vh;\n  width: 100vw;\n  display: none;\n}\nsection.cover.show {\n  display: flex;\n}\nsection.cover.has-mask .mask {\n  background-color: #fff;\n  opacity: 0.8;\n  position: absolute;\n  top: 0;\n  height: 100%;\n  width: 100%;\n}\nsection.cover .cover-main {\n  flex: 1;\n  margin: -20px 16px 0;\n  text-align: center;\n  position: relative;\n}\nsection.cover a {\n  color: inherit;\n  text-decoration: none;\n}\nsection.cover a:hover {\n  text-decoration: none;\n}\nsection.cover p {\n  line-height: 1.5rem;\n  margin: 1em 0;\n}\nsection.cover h1 {\n  color: inherit;\n  font-size: 2.5rem;\n  font-weight: 300;\n  margin: 0.625rem 0 2.5rem;\n  position: relative;\n  text-align: center;\n}\nsection.cover h1 a {\n  display: block;\n}\nsection.cover h1 small {\n  bottom: -0.4375rem;\n  font-size: 1rem;\n  position: absolute;\n}\nsection.cover blockquote {\n  font-size: 1.5rem;\n  text-align: center;\n}\nsection.cover ul {\n  line-height: 1.8;\n  list-style-type: none;\n  margin: 1em auto;\n  max-width: 500px;\n  padding: 0;\n}\nsection.cover .cover-main > p:last-child a {\n  border-color: var(--theme-color, #42b983);\n  border-radius: 2rem;\n  border-style: solid;\n  border-width: 1px;\n  box-sizing: border-box;\n  color: var(--theme-color, #42b983);\n  display: inline-block;\n  font-size: 1.05rem;\n  letter-spacing: 0.1rem;\n  margin: 0.5rem 1rem;\n  padding: 0.75em 2rem;\n  text-decoration: none;\n  transition: all 0.15s ease;\n}\nsection.cover .cover-main > p:last-child a:last-child {\n  background-color: var(--theme-color, #42b983);\n  color: #fff;\n}\nsection.cover .cover-main > p:last-child a:last-child:hover {\n  color: inherit;\n  opacity: 0.8;\n}\nsection.cover .cover-main > p:last-child a:hover {\n  color: inherit;\n}\nsection.cover blockquote > p > a {\n  border-bottom: 2px solid var(--theme-color, #42b983);\n  transition: color 0.3s;\n}\nsection.cover blockquote > p > a:hover {\n  color: var(--theme-color, #42b983);\n}\nbody {\n  background-color: #fff;\n}\n/* sidebar */\n.sidebar {\n  background-color: #fff;\n  color: #364149;\n}\n.sidebar li {\n  margin: 6px 0 6px 0;\n}\n.sidebar ul li a {\n  color: #505d6b;\n  font-size: 14px;\n  font-weight: normal;\n  overflow: hidden;\n  text-decoration: none;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.sidebar ul li a:hover {\n  text-decoration: underline;\n}\n.sidebar ul li ul {\n  padding: 0;\n}\n.sidebar ul li.active > a {\n  border-right: 2px solid;\n  color: var(--theme-color, #42b983);\n  font-weight: 600;\n}\n.app-sub-sidebar li::before {\n  content: '-';\n  padding-right: 4px;\n  float: left;\n}\n/* markdown content found on pages */\n.markdown-section h1,\n.markdown-section h2,\n.markdown-section h3,\n.markdown-section h4,\n.markdown-section strong {\n  color: #2c3e50;\n  font-weight: 600;\n}\n.markdown-section a {\n  color: var(--theme-color, #42b983);\n  font-weight: 600;\n}\n.markdown-section h1 {\n  font-size: 2rem;\n  margin: 0 0 1rem;\n}\n.markdown-section h2 {\n  font-size: 1.75rem;\n  margin: 45px 0 0.8rem;\n}\n.markdown-section h3 {\n  font-size: 1.5rem;\n  margin: 40px 0 0.6rem;\n}\n.markdown-section h4 {\n  font-size: 1.25rem;\n}\n.markdown-section h5 {\n  font-size: 1rem;\n}\n.markdown-section h6 {\n  color: #777;\n  font-size: 1rem;\n}\n.markdown-section figure,\n.markdown-section p {\n  margin: 1.2em 0;\n}\n.markdown-section p,\n.markdown-section ul,\n.markdown-section ol {\n  line-height: 1.6rem;\n  word-spacing: 0.05rem;\n}\n.markdown-section ul,\n.markdown-section ol {\n  padding-left: 1.5rem;\n}\n.markdown-section blockquote {\n  border-left: 4px solid var(--theme-color, #42b983);\n  color: #858585;\n  margin: 2em 0;\n  padding-left: 20px;\n}\n.markdown-section blockquote p {\n  font-weight: 600;\n  margin-left: 0;\n}\n.markdown-section iframe {\n  margin: 1em 0;\n}\n.markdown-section em {\n  color: #7f8c8d;\n}\n.markdown-section code {\n  background-color: #f8f8f8;\n  border-radius: 2px;\n  color: #e96900;\n  font-family: 'Roboto Mono', Monaco, courier, monospace;\n  font-size: 0.8rem;\n  margin: 0 2px;\n  padding: 3px 5px;\n  white-space: pre-wrap;\n}\n.markdown-section pre {\n  -moz-osx-font-smoothing: initial;\n  -webkit-font-smoothing: initial;\n  background-color: #f8f8f8;\n  font-family: 'Roboto Mono', Monaco, courier, monospace;\n  line-height: 1.5rem;\n  margin: 1.2em 0;\n  overflow: auto;\n  padding: 0 1.4rem;\n  position: relative;\n  word-wrap: normal;\n}\n/* code highlight */\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n  color: #8e908c;\n}\n.token.namespace {\n  opacity: 0.7;\n}\n.token.boolean,\n.token.number {\n  color: #c76b29;\n}\n.token.punctuation {\n  color: #525252;\n}\n.token.property {\n  color: #c08b30;\n}\n.token.tag {\n  color: #2973b7;\n}\n.token.string {\n  color: var(--theme-color, #42b983);\n}\n.token.selector {\n  color: #6679cc;\n}\n.token.attr-name {\n  color: #2973b7;\n}\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string {\n  color: #22a2c9;\n}\n.token.attr-value,\n.token.control,\n.token.directive,\n.token.unit {\n  color: var(--theme-color, #42b983);\n}\n.token.keyword,\n.token.function {\n  color: #e96900;\n}\n.token.statement,\n.token.regex,\n.token.atrule {\n  color: #22a2c9;\n}\n.token.placeholder,\n.token.variable {\n  color: #3d8fd1;\n}\n.token.deleted {\n  text-decoration: line-through;\n}\n.token.inserted {\n  border-bottom: 1px dotted #202746;\n  text-decoration: none;\n}\n.token.italic {\n  font-style: italic;\n}\n.token.important,\n.token.bold {\n  font-weight: bold;\n}\n.token.important {\n  color: #c94922;\n}\n.token.entity {\n  cursor: help;\n}\n.markdown-section pre > code {\n  -moz-osx-font-smoothing: initial;\n  -webkit-font-smoothing: initial;\n  background-color: #f8f8f8;\n  border-radius: 2px;\n  color: #525252;\n  display: block;\n  font-family: 'Roboto Mono', Monaco, courier, monospace;\n  font-size: 0.8rem;\n  line-height: inherit;\n  margin: 0 2px;\n  max-width: inherit;\n  overflow: inherit;\n  padding: 2.2em 5px;\n  white-space: inherit;\n}\n.markdown-section code::after,\n.markdown-section code::before {\n  letter-spacing: 0.05rem;\n}\ncode .token {\n  -moz-osx-font-smoothing: initial;\n  -webkit-font-smoothing: initial;\n  min-height: 1.5rem;\n  position: relative;\n  left: auto;\n}\npre::after {\n  color: #ccc;\n  content: attr(data-lang);\n  font-size: 0.6rem;\n  font-weight: 600;\n  height: 15px;\n  line-height: 15px;\n  padding: 5px 10px 0;\n  position: absolute;\n  right: 0;\n  text-align: right;\n  top: 0;\n}\n"
  },
  {
    "path": "docs/jianzhioffer/java/03_01_DuplicationInArray.md",
    "content": "## 找出数组中重复的数字\n\n### 题目描述\n在一个长度为 `n` 的数组里的所有数字都在 `0` 到 `n-1` 的范围内。数组中某些数字是重复的，但不知道有几个数字重复了，也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如，如果输入长度为 `7` 的数组 `{2, 3, 1, 0, 2, 5, 3}`，那么对应的输出是重复的数字 `2` 或者 `3`。\n\n\n### 解法\n#### 解法一\n排序后，顺序扫描，判断是否有重复，时间复杂度为 `O(n²)`。\n\n#### 解法二\n利用哈希表，遍历数组，如果哈希表中没有该元素，则存入哈希表中，否则返回重复的元素。时间复杂度为 `O(n)`，空间复杂度为 `O(n)`。\n\n#### 解法三\n长度为 `n`，元素的数值范围也为 `n`，如果没有重复元素，那么数组每个下标对应的值与下标相等。\n\n从头到尾遍历数组，当扫描到下标 `i` 的数字 `nums[i]`：\n- 如果等于 `i`，继续向下扫描；\n- 如果不等于 `i`，拿它与第 `nums[i]` 个数进行比较，如果相等，说明有重复值，返回 `nums[i]`。如果不相等，就把第 `i` 个数 和第 `nums[i]` 个数交换。重复这个比较交换的过程。\n\n此算法时间复杂度为 `O(n)`，因为每个元素最多只要两次交换，就能确定位置。空间复杂度为 `O(1)`。\n\n```java\n\n/**\n * @author bingo\n * @since 2018/10/27\n */\n\npublic class Solution {\n    /**\n     * 查找数组中的重复元素\n     * @param numbers 数组\n     * @param length 数组长度\n     * @param duplication duplication[0]存储重复元素\n     * @return boolean\n     */\n    public boolean duplicate(int[] numbers, int length, int[] duplication) {\n        if (numbers == null || length < 1) {\n            return false;\n        }\n        for (int e : numbers) {\n            if (e >= length) {\n                return false;\n            }\n        }\n\n        for (int i = 0; i < length; ++i) {\n            while (numbers[i] != i) {\n                if (numbers[i] == numbers[numbers[i]]) {\n                    duplication[0] = numbers[i];\n                    return true;\n                }\n                swap(numbers, i, numbers[i]);\n            }\n        }\n\n        return false;\n    }\n\n    private void swap(int[] numbers, int i, int j) {\n        int t = numbers[i];\n        numbers[i] = numbers[j];\n        numbers[j] = t;\n    }\n}\n```\n\n### 测试用例\n1. 长度为 n 的数组中包含一个或多个重复的数字；\n2. 数组中不包含重复的数字；\n3. 无效测试输入用例（输入空指针；长度为 n 的数组中包含 0~n-1 之外的数字）。"
  },
  {
    "path": "docs/jianzhioffer/java/03_02_DuplicationInArrayNoEdit.md",
    "content": "## 不修改数组找出重复的数字\n\n### 题目描述\n在一个长度为 `n+1` 的数组里的所有数字都在 `1` 到 `n` 的范围内，所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字，但不能修改输入的数组。例如，如果输入长度为 `8` 的数组 `{2, 3, 5, 4, 3, 2, 6, 7}`，那么对应的输出是重复的数字 `2` 或者 `3`。\n\n\n### 解法\n#### 解法一\n创建长度为 `n+1` 的辅助数组，把原数组的元素复制到辅助数组中。如果原数组被复制的数是 `m`，则放到辅助数组第 `m` 个位置。这样很容易找出重复元素。空间复杂度为 `O(n)`。\n\n#### 解法二\n数组元素的取值范围是 `[1, n]`，对该范围对半划分，分成 `[1, middle]`, `[middle+1, n]`。计算数组中有多少个(count)元素落在 `[1, middle]` 区间内，如果 count 大于 middle-1+1，那么说明这个范围内有重复元素，否则在另一个范围内。继续对这个范围对半划分，继续统计区间内元素数量。\n\n时间复杂度 `O(n * log n)`，空间复杂度 `O(1)`。\n\n注意，此方法无法找出所有重复的元素。\n\n```java\n/**\n * @author bingo\n * @since 2018/10/27\n */\n\npublic class Solution {\n    /**\n     * 不修改数组查找重复的元素，没有则返回-1\n     * @param numbers 数组\n     * @return 重复的元素\n     */\n    public int getDuplication(int[] numbers) {\n        if (numbers == null || numbers.length < 1) {\n            return -1;\n        }\n\n        int start = 1;\n        int end = numbers.length - 1;\n        while (end >= start) {\n            int middle = start + ((end - start) >> 1);\n\n            // 调用 log n 次\n            int count = countRange(numbers, start, middle);\n            if (start == end) {\n                if (count > 1) {\n                    return start;\n                }\n                break;\n            } else {\n                // 无法找出所有重复的数\n                if (count > (middle - start) + 1) {\n                    end = middle;\n                } else {\n                    start = middle + 1;\n                }\n            }\n        }\n        return -1;\n    }\n\n\n    /**\n     * 计算整个数组中有多少个数的取值在[start, end] 之间\n     * 时间复杂度 O(n)\n     * @param numbers 数组\n     * @param start 左边界\n     * @param end 右边界\n     * @return 数量\n     */\n    private int countRange(int[] numbers, int start, int end) {\n        if (numbers == null) {\n            return 0;\n        }\n        int count = 0;\n        for(int e : numbers) {\n            if (e >= start && e <= end) {\n                ++count;\n            }\n        }\n        return count;\n    }\n}\n```\n\n### 测试用例\n1. 长度为 n 的数组中包含一个或多个重复的数字；\n2. 数组中不包含重复的数字；\n3. 无效测试输入用例（输入空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/04_FindInPartiallySortedMatrix.md",
    "content": "## 二维数组中的查找\n\n### 题目描述\n在一个二维数组中（每个一维数组的长度相同），每一行都按照从左到右递增的顺序排序，每一列都按照从上到下递增的顺序排序。请完成一个函数，输入这样的一个二维数组和一个整数，判断数组中是否含有该整数。\n\n\n### 解法\n从二维数组的右上方开始查找：\n- 若元素值等于 `target`，返回 `true`；\n- 若元素值大于 `target`，砍掉这一列，即 `--j`；\n- 若元素值小于 `target`，砍掉这一行，即 `++i`。\n\n也可以从二维数组的左下方开始查找，以下代码使用左下方作为查找的起点。\n\n注意，不能选择左上方或者右下方的数字，因为这样无法缩小查找的范围。\n\n```java\n/**\n * @author bingo\n * @since 2018/10/27\n */\n\npublic class Solution {\n    /**\n     * 二维数组中的查找\n     * @param target 目标值\n     * @param array 二维数组\n     * @return boolean\n     */\n    public boolean find(int target, int[][] array) {\n        if (array == null) {\n            return false;\n        }\n        int rows = array.length;\n        int columns = array[0].length;\n        \n        int i = rows - 1;\n        int j = 0;\n        while (i >= 0 && j < columns) {\n            if (array[i][j] == target) {\n                return true;\n            }\n            if (array[i][j] < target) {\n                ++j;\n            } else {\n                --i;\n            }\n        }\n        return false;\n    }\n}\n```\n\n### 测试用例\n1. 二维数组中包含查找的数字（查找的数字是数组中的最大值和最小值；查找的数字介于数组中的最大值和最小值之间）；\n2. 二维数组中没有查找的数字（查找的数字大于/小于数组中的最大值；查找的数字在数组的最大值和最小值之间但数组中没有这个数字）；\n3. 特殊输入测试（输入空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/05_ReplaceSpaces.md",
    "content": "## 替换空格\n\n### 题目描述\n请实现一个函数，将一个字符串中的每个空格替换成 `%20`。例如，当字符串为 `We Are Happy`，则经过替换之后的字符串为 `We%20Are%20Happy`。\n\n\n### 解法\n#### 解法一\n创建 `StringBuilder`，遍历原字符串，遇到非空格，直接 append 到 `StringBuilder` 中，遇到空格则将 `%20` append 到 `StringBuilder` 中。\n```java\n/**\n * @author bingo\n * @since 2018/10/27\n */\n\npublic class Solution {\n    /**\n     * 将字符串中的所有空格替换为%20\n     * @param str 字符串\n     * @return 替换后的字符串\n     */\n    public String replaceSpace(StringBuffer str) {\n        if (str == null || str.length() == 0) {\n            return str.toString();\n        }\n        StringBuilder sb = new StringBuilder();\n        int len = str.length();\n        for (int i = 0; i < len; ++i) {\n            char ch = str.charAt(i);\n            sb.append(ch == ' ' ? \"%20\" : ch);\n        }\n\n        return sb.toString();\n    }\n}\n```\n\n#### 解法二【推荐】\n先遍历原字符串，遇到空格，则在原字符串末尾 `append` 任意两个字符，如两个空格。\n\n用指针 `p` 指向原字符串末尾，`q` 指向现字符串末尾，`p`, `q` 从后往前遍历，当 `p` 遇到空格，`q` 位置依次要 `append` '02%'，若不是空格，直接 `append` `p` 指向的字符。\n\n> 🤔思路扩展：\n在合并两个数组（包括字符串）时，如果从前往后复制每个数字（或字符）需要重复移动数字（或字符）多次，那么我们可以考虑从后往前复制，这样就能减少移动的次数，从而提高效率。\n\n```java\n/**\n * @author bingo\n * @since 2018/10/27\n */\n\npublic class Solution {\n    /**\n     * 将字符串中的所有空格替换为%20\n     * @param str 字符串\n     * @return 替换后的字符串\n     */\n    public String replaceSpace(StringBuffer str) {\n        if (str == null || str.length() == 0) {\n            return str.toString();\n        }\n        \n        int len = str.length();\n        for (int i = 0; i < len; ++i) {\n            if (str.charAt(i) == ' ') {\n                // append 两个空格\n                str.append(\"  \");\n            }\n        }\n\n        // p 指向原字符串末尾\n        int p = len - 1;\n\n        // q 指向现字符串末尾\n        int q = str.length() - 1;\n\n        while (p >= 0) {\n            char ch = str.charAt(p--);\n            if (ch == ' ') {\n                str.setCharAt(q--, '0');\n                str.setCharAt(q--, '2');\n                str.setCharAt(q--, '%');\n            } else {\n                str.setCharAt(q--, ch);\n            }\n        }\n\n        return str.toString();\n\n    }\n}\n```\n\n\n### 测试用例\n1. 输入的字符串包含空格（空格位于字符串的最前面/最后面/中间；字符串有多个连续的空格）；\n2. 输入的字符串中没有空格；\n3. 特殊输入测试（字符串是一个空指针；字符串是一个空字符串；字符串只有一个空格字符；字符串中有多个连续空格）。"
  },
  {
    "path": "docs/jianzhioffer/java/06_PrintListInReversedOrder.md",
    "content": "## 从尾到头打印链表\n\n### 题目描述\n输入一个链表，按链表值从尾到头的顺序返回一个 `ArrayList`。\n\n\n### 解法\n#### 解法一【推荐】\n遍历链表，每个链表结点值 `push` 进栈，最后将栈中元素依次 `pop` 到 `list` 中。\n```java\n/**\n*    public class ListNode {\n*        int val;\n*        ListNode next = null;\n*\n*        ListNode(int val) {\n*            this.val = val;\n*        }\n*    }\n*\n*/\nimport java.util.ArrayList;\nimport java.util.Stack;\n\n/**\n * @author bingo\n * @since 2018/10/28\n */\npublic class Solution {\n    /**\n     * 从尾到头打印链表\n     * @param listNode 链表头节点\n     * @return list\n     */\n    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {\n        ArrayList<Integer> res = new ArrayList<>();\n        if (listNode == null) {\n            return res;\n        }\n        Stack<Integer> stack = new Stack<>();\n        while (listNode != null) {\n            stack.push(listNode.val);\n            listNode = listNode.next;\n        }\n        while (!stack.isEmpty()) {\n            res.add(stack.pop());\n        }\n        \n        return res;\n    }\n}\n```\n\n#### 解法二【不推荐】\n利用递归方式：\n- 若不是链表尾结点，继续递归；\n- 若是，添加到 `list` 中。\n\n这种方式不推荐，当递归层数过多时，容易发生 `Stack Overflow`。\n\n```java\n/**\n*    public class ListNode {\n*        int val;\n*        ListNode next = null;\n*\n*        ListNode(int val) {\n*            this.val = val;\n*        }\n*    }\n*\n*/\nimport java.util.ArrayList;\nimport java.util.Stack;\n\n/**\n * @author bingo\n * @since 2018/10/28\n */\npublic class Solution {\n    /**\n     * 从尾到头打印链表\n     * @param listNode 链表头结点\n     * @return list\n     */\n    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {\n        ArrayList<Integer> res = new ArrayList<>();\n        if (listNode == null) {\n            return res;\n        }\n        \n        addElement(listNode, res);\n        return res;\n        \n    }\n    \n    private void addElement(ListNode listNode, ArrayList<Integer> res) {\n        if (listNode.next != null) {\n            // 递归调用\n            addElement(listNode.next, res);\n        }\n        res.add(listNode.val);\n    }\n}\n```\n\n\n### 测试用例\n1. 功能测试（输入的链表有多个结点；输入的链表只有一个结点）；\n2. 特殊输入测试（输入的链表结点指针为空）。"
  },
  {
    "path": "docs/jianzhioffer/java/07_ConstructBinaryTree.md",
    "content": "## 重建二叉树\n\n### 题目描述\n输入某二叉树的前序遍历和中序遍历的结果，请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 `{1,2,4,7,3,5,6,8}` 和中序遍历序列 `{4,7,2,1,5,3,8,6}`，则重建二叉树并返回。\n\n\n### 解法\n在二叉树的前序遍历序列中，第一个数字总是根结点的值。在中序遍历序列中，根结点的值在序列的中间，左子树的结点位于根结点左侧，而右子树的结点位于根结点值的右侧。\n\n遍历中序序列，找到根结点，递归构建左子树与右子树。\n\n注意添加特殊情况的 `if` 判断。\n\n```java\n/**\n * Definition for binary tree\n * public class TreeNode {\n *     int val;\n *     TreeNode left;\n *     TreeNode right;\n *     TreeNode(int x) { val = x; }\n * }\n */\n\n/**\n * @author bingo\n * @since 2018/10/28\n */\n\npublic class Solution {\n    /**\n     * 重建二叉树\n     * \n     * @param pre 先序序列\n     * @param in  中序序列\n     * @return 二叉树根结点\n     */\n    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {\n        if (pre == null || in == null || pre.length != in.length) {\n            return null;\n        }\n        int n = pre.length;\n        return constructBinaryTree(pre, 0, n - 1, in, 0, n - 1);\n    }\n\n    private TreeNode constructBinaryTree(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) {\n        TreeNode node = new TreeNode(pre[startPre]);\n        if (startPre == endPre) {\n            if (startIn == endIn) {\n                return node;\n            }\n            throw new IllegalArgumentException(\"Invalid input!\");\n        }\n\n        int inOrder = startIn;\n        while (in[inOrder] != pre[startPre]) {\n            ++inOrder;\n            if (inOrder > endIn) {\n                new IllegalArgumentException(\"Invalid input!\");\n            }\n        }\n        int len = inOrder - startIn;\n        if (len > 0) {\n            // 递归构建左子树\n            node.left = constructBinaryTree(pre, startPre + 1, startPre + len, in, startIn, inOrder - 1);\n        }\n\n        if (inOrder < endIn) {\n            // 递归构建右子树\n            node.right = constructBinaryTree(pre, startPre + len + 1, endPre, in, inOrder + 1, endIn);\n        }\n        return node;\n\n    }\n}\n```\n\n\n### 测试用例\n1. 普通二叉树（完全二叉树；不完全二叉树）；\n2. 特殊二叉树（所有结点都没有左/右子结点；只有一个结点的二叉树）；\n3. 特殊输入测试（二叉树根结点为空；输入的前序序列和中序序列不匹配）。"
  },
  {
    "path": "docs/jianzhioffer/java/08_NextNodeInBinaryTrees.md",
    "content": "## 二叉树的下一个结点\n\n### 题目描述\n给定一个二叉树和其中的一个结点，请找出中序遍历顺序的下一个结点并且返回。注意，树中的结点不仅包含左右子结点，同时包含指向父结点的指针。\n\n\n### 解法\n对于结点 `pNode`：\n- 如果它有右子树，则**右子树的最左结点**就是它的下一个结点；\n- 如果它没有右子树，判断它与父结点 `pNode.next` 的位置情况：\n    - 如果它是父结点的左孩子，那么父结点 `pNode.next` 就是它的下一个结点；\n    - 如果它是父结点的右孩子，一直向上寻找，直到找到某个结点，它是它父结点的左孩子，那么该父结点就是 `pNode` 的下一个结点。\n\n```java\n/*\npublic class TreeLinkNode {\n    int val;\n    TreeLinkNode left = null;\n    TreeLinkNode right = null;\n    TreeLinkNode next = null;\n\n    TreeLinkNode(int val) {\n        this.val = val;\n    }\n}\n*/\n\n/**\n * @author bingo\n * @since 2018/10/28\n */\n\npublic class Solution {\n    /**\n     * 获取中序遍历结点的下一个结点\n     * @param pNode 某个结点\n     * @return pNode的下一个结点\n     */\n    public TreeLinkNode GetNext(TreeLinkNode pNode) {\n        if (pNode == null) {\n            return null;\n        }\n        \n        if (pNode.right != null) {\n            TreeLinkNode t = pNode.right;\n            while (t.left != null) {\n                t = t.left;\n            }\n            return t;\n        }\n        \n        // 须保证 pNode.next 不为空，否则会出现 NPE\n        if (pNode.next != null && pNode.next.left == pNode) {\n            return pNode.next;\n        }\n        \n        while (pNode.next != null) {\n            if (pNode.next.left == pNode) {\n                return pNode.next;\n            }\n            pNode = pNode.next;\n        }\n        \n        return null;\n        \n    }\n}\n```\n\n\n### 测试用例\n1. 普通二叉树（完全二叉树；不完全二叉树）；\n2. 特殊二叉树（所有结点都没有左/右子结点；只有一个结点的二叉树；二叉树的根结点为空）；\n3. 不同位置的结点的下一个结点（下一个结点为当前结点的右子结点、右子树的最左子结点、父结点、跨层的父结点等；当前结点没有下一个结点）。"
  },
  {
    "path": "docs/jianzhioffer/java/09_01_QueueWithTwoStacks.md",
    "content": "## 用两个栈实现队列\n\n### 题目描述\n用两个栈来实现一个队列，完成队列的 `Push` 和 `Pop` 操作。 队列中的元素为 `int` 类型。\n\n\n### 解法\n`Push` 操作，每次都存入 `stack1`；\n`Pop` 操作，每次从 `stack2` 取：\n- `stack2` 栈不为空时，不能将 `stack1` 元素倒入；\n- `stack2` 栈为空时，需要一次将 `stack1` 元素全部倒入。\n\n```java\nimport java.util.Stack;\n\n/**\n * @author bingo\n * @since 2018/10/28\n */\n\npublic class Solution {\n    Stack<Integer> stack1 = new Stack<Integer>();\n    Stack<Integer> stack2 = new Stack<Integer>();\n    \n    public void push(int node) {\n        stack1.push(node);\n    }\n    \n    public int pop() {\n        if (stack2.isEmpty()) {\n            if (stack1.isEmpty()) {\n                return -1;\n            }\n            while (!stack1.isEmpty()) {\n                stack2.push(stack1.pop());\n            }\n        }\n        return stack2.pop();\n    }\n}\n```\n\n\n### 测试用例\n1. 往空的队列里添加、删除元素；\n2. 往非空的队列添加、删除元素；\n3. 连续删除元素直至队列为空。"
  },
  {
    "path": "docs/jianzhioffer/java/09_02_StackWithTwoQueues.md",
    "content": "## 用两个队列实现栈\n\n### 题目描述\n用两个队列来实现一个栈，完成栈的 `Push` 和 `Pop` 操作。 栈中的元素为 `int` 类型。\n\n\n### 解法\n`Push` 操作，每次都存入 `queue1`；\n`Pop` 操作，每次从 `queue1` 取：\n- 将 `queue1` 中的元素依次倒入 `queue2`，直到 `queue1` 剩下一个元素，这个元素就是要 `pop` 出去的；\n- 将 `queue1` 与 `queue2` 进行交换，这样保证每次都从 `queue1` 中存取元素，`queue2` 只起到辅助暂存的作用。\n\n```java\nimport java.util.LinkedList;\nimport java.util.Queue;\n\n/**\n * @author bingo\n * @since 2018/10/29\n */\n\npublic class Solution {\n\n    private Queue<Integer> queue1 = new LinkedList<>();\n    private Queue<Integer> queue2 = new LinkedList<>();\n\n    public void push(int node) {\n        queue1.offer(node);\n    }\n\n    public int pop() {\n        if (queue1.isEmpty()) {\n            throw new RuntimeException(\"Empty stack!\");\n        }\n\n        while (queue1.size() > 1) {\n            queue2.offer(queue1.poll());\n        }\n\n        int val = queue1.poll();\n\n        Queue<Integer> t = queue1;\n        queue1 = queue2;\n        queue2 = t;\n        return val;\n\n    }\n}\n```\n\n\n### 测试用例\n1. 往空的栈里添加、删除元素；\n2. 往非空的栈添加、删除元素；\n3. 连续删除元素直至栈为空。"
  },
  {
    "path": "docs/jianzhioffer/java/10_01_Fibonacci.md",
    "content": "## 斐波那契数列\n\n### 题目描述\n大家都知道斐波那契数列，现在要求输入一个整数n，请你输出斐波那契数列的第 `n` 项（从 `0` 开始，第 `0` 项为 `0`）。`n<=39`\n\n\n### 解法\n#### 解法一\n采用递归方式，简洁明了，但效率很低，存在大量的重复计算。\n```\n                  f(10)\n               /        \\\n            f(9)         f(8)\n          /     \\       /    \\\n       f(8)     f(7)  f(7)   f(6)\n      /   \\     /   \\ \n   f(7)  f(6)  f(6) f(5)\n```\n\n```java\n\n/**\n * @author bingo\n * @since 2018/10/29\n */\n\npublic class Solution {\n    /**\n     * 求斐波那契数列的第n项，n从0开始\n     * @param n 第n项\n     * @return 第n项的值\n     */\n    public int Fibonacci(int n) {\n        if (n < 2) {\n            return n;\n        }\n        // 递归调用\n        return Fibonacci(n - 1) + Fibonacci(n - 2);\n    }\n}\n```\n\n#### 解法二\n从下往上计算，递推，时间复杂度 `O(n)`。\n\n```java\n\n/**\n * @author bingo\n * @since 2018/10/29\n */\n\npublic class Solution {\n    /**\n     * 求斐波那契数列的第n项，n从0开始\n     * @param n 第n项\n     * @return 第n项的值\n     */\n    public int Fibonacci(int n) {\n        if (n < 2) {\n            return n;\n        }\n        int[] res = new int[n + 1];\n        res[0] = 0;\n        res[1] = 1;\n        for (int i = 2; i <= n; ++i) {\n            res[i] = res[i - 1] + res[i - 2];\n        }\n        return res[n];\n\n    }\n}\n```\n\n\n### 测试用例\n1. 功能测试（如输入 3、5、10 等）；\n2. 边界值测试（如输入 0、1、2）；\n3. 性能测试（输入较大的数字，如 40、50、100 等）。"
  },
  {
    "path": "docs/jianzhioffer/java/10_02_JumpFloor.md",
    "content": "## 跳台阶\n\n### 题目描述\n一只青蛙一次可以跳上`1`级台阶，也可以跳上`2`级。求该青蛙跳上一个`n`级的台阶总共有多少种跳法（先后次序不同算不同的结果）。\n\n### 解法\n跳上 `n` 级台阶，可以从 `n-1` 级跳 `1` 级上去，也可以从 `n-2` 级跳 `2` 级上去。所以\n```\nf(n) = f(n-1) + f(n-2)\n```\n\n```java\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\npublic class Solution {\n    /**\n     * 青蛙跳台阶\n     * @param target 跳上的那一级台阶\n     * @return 多少种跳法\n     */\n    public int JumpFloor(int target) {\n        if (target < 3) {\n            return target;\n        }\n        int[] res = new int[target + 1];\n        res[1] = 1;\n        res[2] = 2;\n        for (int i = 3; i <= target; ++i) {\n            res[i] = res[i - 1] + res[i - 2];\n        }\n        return res[target];\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（如输入 3、5、10 等）；\n2. 边界值测试（如输入 0、1、2）；\n3. 性能测试（输入较大的数字，如 40、50、100 等）。"
  },
  {
    "path": "docs/jianzhioffer/java/10_03_JumpFloorII.md",
    "content": "## 变态跳台阶\n\n### 题目描述\n一只青蛙一次可以跳上`1`级台阶，也可以跳上`2`级……它也可以跳上`n`级。求该青蛙跳上一个`n`级的台阶总共有多少种跳法。\n\n### 解法\n跳上 `n-1` 级台阶，可以从 `n-2` 级跳 `1` 级上去，也可以从 `n-3` 级跳 `2` 级上去...也可以从 `0` 级跳上去。那么\n```\nf(n-1) = f(0) + f(1) + ... + f(n-2) ①\n```\n\n跳上 `n` 级台阶，可以从 `n-1` 级跳 `1` 级上去，也可以从 `n-2` 级跳 `2` 级上去...也可以从 `0` 级跳上去。那么\n```\nf(n) = f(0) + f(1) + ... + f(n-2) + f(n-1)  ②\n\n②-①：\nf(n) - f(n-1) = f(n-1)\nf(n) = 2f(n-1)\n```\n\n所以 f(n) 是一个等比数列：\n```\nf(n) = 2^(n-1)\n```\n\n\n```java\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\npublic class Solution {\n    /**\n     * 青蛙跳台阶II\n     * @param target 跳上的那一级台阶\n     * @return 多少种跳法\n     */\n    public int JumpFloorII(int target) {\n        return (int) Math.pow(2, target - 1);\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（如输入 3、5、10 等）；\n2. 边界值测试（如输入 0、1、2）；\n3. 性能测试（输入较大的数字，如 40、50、100 等）。"
  },
  {
    "path": "docs/jianzhioffer/java/10_04_RectCover.md",
    "content": "## 矩形覆盖\n\n### 题目描述\n我们可以用`2*1`的小矩形横着或者竖着去覆盖更大的矩形。请问用`n`个`2*1`的小矩形无重叠地覆盖一个`2*n`的大矩形，总共有多少种方法？\n\n### 解法\n覆盖 `2*n` 的矩形：\n- 可以先覆盖 `2*n-1` 的矩形，再覆盖一个 `2*1` 的矩形；\n- 也可以先覆盖 `2*(n-2)` 的矩形，再覆盖两个 `1*2` 的矩形。\n\n#### 解法一：利用数组存放结果\n```java\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\npublic class Solution {\n    /**\n     * 矩形覆盖\n     * @param target 2*target大小的矩形\n     * @return 多少种覆盖方法\n     */\n    public int RectCover(int target) {\n        if (target < 3) {\n            return target;\n        }\n        int[] res = new int[target + 1];\n        res[1] = 1;\n        res[2] = 2;\n        for (int i = 3; i <= target; ++i) {\n            res[i] = res[i - 1] + res[i - 2];\n        }\n        return res[target];\n    }\n}\n```\n\n#### 解法二：直接用变量存储结果\n```java\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\npublic class Solution {\n    /**\n     * 矩形覆盖\n     * @param target 2*target大小的矩形\n     * @return 多少种覆盖方法\n     */\n    public int RectCover(int target) {\n        if (target < 3) {\n            return target;\n        }\n        int res1 = 1;\n        int res2 = 2;\n        int res = 0;\n        for (int i = 3; i <= target; ++i) {\n            res = res1 + res2;\n            res1 = res2;\n            res2 = res;\n        }\n        return res;\n    }\n}\n```\n\n\n### 测试用例\n1. 功能测试（如输入 3、5、10 等）；\n2. 边界值测试（如输入 0、1、2）；\n3. 性能测试（输入较大的数字，如 40、50、100 等）。"
  },
  {
    "path": "docs/jianzhioffer/java/11_MinNumberInRotatedArray.md",
    "content": "## 旋转数组的最小数字\n\n### 题目描述\n把一个数组最开始的若干个元素搬到数组的末尾，我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转，输出旋转数组的最小元素。 例如数组 `{3,4,5,1,2}` 为 `{1,2,3,4,5}` 的一个旋转，该数组的最小值为 `1`。 \n\n**NOTE：**给出的所有元素都大于 `0`，若数组大小为 `0`，请返回 `0`。\n\n\n### 解法\n#### 解法一\n直接遍历数组找最小值，时间复杂度 `O(n)`，不推荐。\n\n```java\n\n/**\n * @author bingo\n * @since 2018/10/30\n */\n\npublic class Solution {\n    /**\n     * 获取旋转数组的最小元素\n     * @param array 旋转数组\n     * @return 数组中的最小值\n     */\n    public int minNumberInRotateArray(int[] array) {\n        if (array == null || array.length == 0) {\n            return 0;\n        }\n\n        int n = array.length;\n        if (n == 1 || array[0] < array[n - 1]) {\n            return array[0];\n        }\n\n        int min = array[0];\n        for (int i = 1; i < n; ++i) {\n            min = array[i] < min ? array[i] : min;\n        }\n\n        return min;\n    }\n\n}\n```\n\n#### 解法二\n利用指针 `p`,`q` 指向数组的首尾，如果 `array[p] < array[q]`，说明数组是递增数组，直接返回 `array[p]`。否则进行如下讨论。\n\n计算中间指针 `mid`：\n- 如果此时 `array[p]`, `array[q]`, `array[mid]` 两两相等，此时无法采用二分方式，只能通过遍历区间 `[p,q]` 获取最小值；\n- 如果此时 `p`,`q` 相邻，说明此时 `q` 指向的元素是最小值，返回 `array[q]`；\n- 如果此时 `array[mid] >= array[p]`，说明 `mid` 位于左边的递增数组中，最小值在右边，因此，把 `p` 指向 `mid`，此时保持了 `p` 指向左边递增子数组；\n- 如果此时 `array[mid] <= array[q]`，说明 `mid` 位于右边的递增数组中，最小值在左边，因此，把 `q` 指向 `mid`，此时保持了 `q` 指向右边递增子数组。\n\n```java\n\n\n/**\n * @author bingo\n * @since 2018/10/30\n */\n\npublic class Solution {\n    /**\n     * 获取旋转数组的最小元素\n     * @param array 旋转数组\n     * @return 数组中的最小值\n     */\n    public int minNumberInRotateArray(int[] array) {\n        if (array == null || array.length == 0) {\n            return 0;\n        }\n\n        int p = 0;\n        // mid初始为p，为了兼容当数组是递增数组(即不满足 array[p] >= array[q])时，返回 array[p]\n        int mid = p;\n        int q = array.length - 1;\n        while (array[p] >= array[q]) {\n            if (q - p == 1) {\n                // 当p,q相邻时(距离为1)，那么q指向的元素就是最小值\n                mid = q;\n                break;\n            }\n            mid = p + ((q - p) >> 1);\n\n            // 当p,q,mid指向的值相等时，此时只能通过遍历查找最小值\n            if (array[p] == array[q] && array[mid] == array[p]) {\n                mid = getMinIndex(array, p, q);\n                break;\n            }\n\n            if (array[mid] >= array[p]) {\n                p = mid;\n            } else if (array[mid] <= array[q]) {\n                q = mid;\n            }\n        }\n\n        return array[mid];\n\n\n    }\n\n    private int getMinIndex(int[] array, int p, int q) {\n        int minIndex = p;\n        for (int i = p + 1; i <= q; ++i) {\n            minIndex = array[i] < array[minIndex] ? i : minIndex;\n        }\n        return minIndex;\n    }\n}\n```\n\n\n### 测试用例\n1. 功能测试（输入的数组是升序排序数组的一个旋转，数组中有重复数字或者没有重复数字）；\n2. 边界值测试（输入的数组是一个升序排序的数组，只包含一个数字的数组）；\n3. 特殊输入测试（输入空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/12_StringPathInMatrix.md",
    "content": "## 矩阵中的路径\n\n### 题目描述\n请设计一个函数，用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始，每一步可以在矩阵中向左，向右，向上，向下移动一个格子。如果一条路径经过了矩阵中的某一个格子，则之后不能再次进入这个格子。 例如 `a b c e s f c s a d e e` 这样的 `3 X 4` 矩阵中包含一条字符串`\"bcced\"`的路径，但是矩阵中不包含`\"abcb\"`路径，因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后，路径不能再次进入该格子。\n\n### 解法\n回溯法。首先，任选一个格子作为路径起点。假设格子对应的字符为 ch，并且对应路径上的第 i 个字符。若相等，到相邻格子寻找路径上的第 i+1 个字符。重复这一过程。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/20\n */\n\npublic class Solution {\n    /**\n     * 判断矩阵中是否包含某条路径\n     * @param matrix 矩阵\n     * @param rows 行数\n     * @param cols 列数\n     * @param str 路径\n     * @return bool\n     */\n    public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {\n        if (matrix == null || rows < 1 || cols < 1 || str == null) {\n            return false;\n        }\n        boolean[] visited = new boolean[matrix.length];\n        int pathLength = 0;\n        for (int i = 0; i < rows; ++i) {\n            for (int j = 0; j < cols; ++j) {\n                if (hasPath(matrix, rows, cols, str, i, j, pathLength, visited)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    private boolean hasPath(char[] matrix, int rows, int cols, char[] str, int i, int j, int pathLength, boolean[] visited) {\n        if (pathLength == str.length) {\n            return true;\n        }\n        boolean hasPath = false;\n        if (i >= 0 && i < rows && j >= 0 && j < cols && matrix[i * cols + j] == str[pathLength] && !visited[i * cols + j]) {\n            ++pathLength;\n            visited[i * cols + j] = true;\n            hasPath = hasPath(matrix, rows, cols, str, i - 1, j, pathLength, visited)\n                    || hasPath(matrix, rows, cols, str, i + 1, j, pathLength, visited)\n                    || hasPath(matrix, rows, cols, str, i, j - 1, pathLength, visited)\n                    || hasPath(matrix, rows, cols, str, i, j + 1, pathLength, visited);\n            if (!hasPath) {\n                --pathLength;\n                visited[i * cols + j] = false;\n            }\n        }\n        return hasPath;\n    }\n}\n\n```\n\n### 测试用例\n1. 功能测试（在多行多列的矩阵中存在或者不存在路径）；\n2. 边界值测试（矩阵只有一行或者一列；矩阵和路径中的所有字母都是相同的）；\n3. 特殊输入测试（输入空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/13_RobotMove.md",
    "content": "## 机器人的移动范围\n\n### 题目描述\n地上有一个`m`行和`n`列的方格。一个机器人从坐标`0,0`的格子开始移动，每一次只能向左，右，上，下四个方向移动一格，但是不能进入行坐标和列坐标的数位之和大于`k`的格子。 例如，当`k`为`18`时，机器人能够进入方格`（35,37）`，因为`3+5+3+7 = 18`。但是，它不能进入方格`（35,38）`，因为`3+5+3+8 = 19`。请问该机器人能够达到多少个格子？\n\n### 解法\n从坐标(0, 0) 开始移动，当它准备进入坐标(i, j)，判断是否能进入，如果能，再判断它能否进入 4 个相邻的格子 (i-1, j), (i+1, j), (i, j-1), (i, j+1)。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/20\n */\n\npublic class Solution {\n    /**\n     * 计算能到达的格子数\n     * @param threshold 限定的数字\n     * @param rows 行数\n     * @param cols 列数\n     * @return 格子数\n     */\n    public int movingCount(int threshold, int rows, int cols) {\n        if (threshold < 0 || rows < 1 || cols < 1) {\n            return 0;\n        }\n        boolean[] visited = new boolean[rows * cols];\n        return getCount(threshold, 0, 0, rows, cols, visited);\n    }\n\n    private int getCount(int threshold, int i, int j, int rows, int cols, boolean[] visited) {\n        if (check(threshold, i, j, rows, cols, visited)) {\n            visited[i * cols + j] = true;\n            return 1\n                    + getCount(threshold, i - 1, j, rows, cols, visited)\n                    + getCount(threshold, i + 1, j, rows, cols, visited)\n                    + getCount(threshold, i, j - 1, rows, cols, visited)\n                    + getCount(threshold, i, j + 1, rows, cols, visited);\n        }\n        return 0;\n    }\n\n    private boolean check(int threshold, int i, int j, int rows, int cols, boolean[] visited) {\n        return i >= 0\n                && i < rows\n                && j >= 0\n                && j < cols\n                && !visited[i * cols + j]\n                && getDigitSum(i) + getDigitSum(j) <= threshold;\n    }\n\n    private int getDigitSum(int i) {\n        int res = 0;\n        while (i > 0) {\n            res += i % 10;\n            i /= 10;\n        }\n        return res;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（方格为多行多列；k 为正数）；\n2. 边界值测试（方格只有一行或者一列；k = 0）；\n3. 特殊输入测试（k < 0）。"
  },
  {
    "path": "docs/jianzhioffer/java/14_CuttingRope.md",
    "content": "## 剪绳子\n\n### 题目描述\n给你一根长度为`n`绳子，请把绳子剪成`m`段（`m`、`n`都是整数，`n>1`并且`m≥1`）。每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]*k[1]*…*k[m]可能的最大乘积是多少？例如当绳子的长度是 8 时，我们把它剪成长度分别为 `2、3、3` 的三段，此时得到最大的乘积`18`。\n\n### 解法\n#### 解法一：动态规划法\n时间复杂度`O(n²)`，空间复杂度`O(n)`。\n\n- 长度为 2，只可能剪成长度为 1 的两段，因此 f(2)=1\n- 长度为 3，剪成长度分别为 1 和 2 的两段，乘积比较大，因此 f(3) = 2\n- 长度为 n，在剪第一刀的时候，有 n-1 种可能的选择，剪出来的绳子又可以继续剪，可以看出，原问题可以划分为子问题，子问题又有重复子问题。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/20\n */\n\npublic class Solution {\n\n    /**\n     * 剪绳子求最大乘积\n     * @param length 绳子长度\n     * @return 乘积最大值\n     */\n    public int maxProductAfterCutting(int length) {\n        if (length < 2) {\n            return 0;\n        }\n        if (length < 4) {\n            return length - 1;\n        }\n\n        // res[i] 表示当长度为i时的最大乘积\n        int[] res = new int[length + 1];\n        res[1] = 1;\n        res[2] = 2;\n        res[3] = 3;\n        // 从长度为4开始计算\n        for (int i = 4; i <= length; ++i) {\n            int max = 0;\n            for (int j = 1; j <= i / 2; ++j) {\n                max = Math.max(max, res[j] * res[i - j]);\n            }\n            res[i] = max;\n        }\n\n        return res[length];\n\n    }\n}\n\n```\n\n#### 贪心算法\n时间复杂度`O(1)`，空间复杂度`O(1)`。\n\n贪心策略：\n- 当 n>=5 时，尽可能多地剪长度为 3 的绳子\n- 当剩下的绳子长度为 4 时，就把绳子剪成两段长度为 2 的绳子。\n\n**证明：**\n- 当 n>=5 时，可以证明 2(n-2)>n，并且 3(n-3)>n。也就是说，当绳子剩下长度大于或者等于 5 的时候，可以把它剪成长度为 3 或者 2 的绳子段。\n- 当 n>=5 时，3(n-3)>=2(n-2)，因此，应该尽可能多地剪长度为 3 的绳子段。\n- 当 n=4 时，剪成两根长度为 2 的绳子，其实没必要剪，只是题目的要求是至少要剪一刀。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/20\n */\n\npublic class Solution {\n\n    /**\n     * 剪绳子求最大乘积\n     * @param length 绳子长度\n     * @return 乘积最大值\n     */\n    public int maxProductAfterCutting(int length) {\n        if (length < 2) {\n            return 0;\n        }\n        if (length < 4) {\n            return length - 1;\n        }\n\n        int timesOf3 = length / 3;\n        if (length % 3 == 1) {\n            --timesOf3;\n        }\n        int timesOf2 = (length - timesOf3 * 3) >> 1;\n        return (int) (Math.pow(3, timesOf3) * Math.pow(2, timesOf2));\n    }\n}\n\n```\n\n### 测试用例\n1. 功能测试（绳子的初始长度大于 5）；\n2. 边界值测试（绳子的初始长度分别为 0、1、2、3、4）。"
  },
  {
    "path": "docs/jianzhioffer/java/15_NumberOf1InBinary.md",
    "content": "## 二进制中 1 的个数\n\n### 题目描述\n输入一个整数，输出该数二进制表示中1的个数。其中负数用补码表示。\n\n### 解法\n#### 解法一\n利用整数 1，依次左移每次与 n 进行与运算，若结果不为0，说明这一位上数字为 1，++cnt。\n\n此解法 i 需要左移 32 次。\n\n不要用 n 去右移并与 1 进行与运算，因为n 可能为负数，右移时会陷入死循环。\n\n```java\npublic class Solution {\n    public int NumberOf1(int n) {\n        int cnt = 0;\n        int i = 1;\n        while (i != 0) {\n            if ((n & i) != 0) {\n                ++cnt;\n            }\n            i <<= 1;\n        }\n        return cnt;\n    }\n}\n```\n\n#### 解法二（推荐）\n- 运算 (n - 1) & n，直至 n 为 0。运算的次数即为 n 的二进制中 1 的个数。\n\n因为 n-1 会将 n 的最右边一位 1 改为 0，如果右边还有 0，则所有 0 都会变成 1。结果与 n 进行与运算，会去除掉最右边的一个1。\n\n举个栗子：\n```\n若 n = 1100，\nn - 1 = 1011\nn & (n - 1) = 1000\n\n即：把最右边的 1 变成了 0。\n```\n\n> 把一个整数减去 1 之后再和原来的整数做位与运算，得到的结果相当于把整数的二进制表示中最右边的 1 变成 0。很多二进制的问题都可以用这种思路解决。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/20\n */\n\npublic class Solution {\n    /**\n     * 计算整数的二进制表示里1的个数\n     * @param n 整数\n     * @return 1的个数\n     */\n    public int NumberOf1(int n) {\n        int cnt = 0;\n        while (n != 0) {\n            n = (n - 1 ) & n;\n            ++cnt;\n        }\n        return cnt;\n    }\n}\n\n```\n\n### 测试用例\n1. 正数（包括边界值 1、0x7FFFFFFF）；\n2. 负数（包括边界值 0x80000000、0xFFFFFFFF）；\n3. 0。"
  },
  {
    "path": "docs/jianzhioffer/java/16_Power.md",
    "content": "## 数值的整数次方\n\n### 题目描述\n给定一个 `double` 类型的浮点数 `base` 和 `int` 类型的整数 `exponent`。求 `base`的 `exponent` 次方。\n\n### 解法\n注意判断值数是否小于 0。另外 0 的 0 次方没有意义，也需要考虑一下，看具体题目要求。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/20\n */\n\npublic class Solution {\n    /**\n     * 计算数值的整数次方\n     * @param base 底数\n     * @param exponent 指数\n     * @return 数值的整数次方\n     */\n    public double Power(double base, int exponent) {\n        double result = 1.0;\n        int n = Math.abs(exponent);\n        for (int i = 0; i < n; ++i) {\n            result *= base;\n        }\n\n        return exponent < 0 ? 1.0 / result : result;\n    }\n}\n\n```\n\n### 测试用例\n1. 把底数和指数分别设为正数、负数和零。"
  },
  {
    "path": "docs/jianzhioffer/java/17_Print1ToMaxOfNDigits.md",
    "content": "## 打印从 1 到最大的 n 位数\n\n### 题目描述\n输入数字 `n`，按顺序打印出从 `1` 最大的 `n` 位十进制数。比如输入 `3`，则打印出 `1、2、3` 一直到最大的 3 位数即 999。\n\n### 解法\n此题需要注意 n 位数构成的数字可能超出最大的 int 或者 long long 能表示的范围。因此，采用字符数组来存储数字。\n\n关键是：\n- 对字符数组表示的数进行递增操作\n- 输出数字（0开头的需要把0去除）\n\n```java\n/**\n * @author bingo\n * @since 2018/11/20\n */\n\npublic class Solution {\n\n    /**\n     * 打印从1到最大的n位数\n     * @param n n位\n     */\n    public void print1ToMaxOfNDigits(int n) {\n        if (n < 1) {\n            return;\n        }\n\n        char[] chars = new char[n];\n        for (int i = 0; i < n; ++i) {\n            chars[i] = '0';\n        }\n\n        while (!increment(chars)) {\n            printNumber(chars);\n        }\n    }\n\n    /**\n     * 打印数字（去除前面的0）\n     * @param chars 数字数组\n     */\n    private void printNumber(char[] chars) {\n        int index = 0;\n        int n = chars.length;\n        for (char ch : chars) {\n            if (ch != '0') {\n                break;\n            }\n            ++index;\n        }\n        StringBuilder sb = new StringBuilder();\n        for (int i = index; i < n; ++i) {\n            sb.append(chars[i]);\n        }\n        System.out.println(sb.toString());\n    }\n\n    /**\n     * 数字加1\n     * @param chars 数字数组\n     * @return 是否溢出\n     */\n    private boolean increment(char[] chars) {\n        boolean flag = false;\n        int n = chars.length;\n        int carry = 1;\n        for (int i = n - 1; i >= 0; --i) {\n\n            int num = chars[i] - '0' + carry;\n            if (num > 9) {\n                if (i == 0) {\n                    flag = true;\n                    break;\n                }\n                chars[i] = '0';\n            } else {\n                ++chars[i];\n                break;\n            }\n        }\n        return flag;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入 1、2、3......）；\n2. 特殊输入测试（输入 -1、0）。"
  },
  {
    "path": "docs/jianzhioffer/java/18_01_DeleteNodeInList.md",
    "content": "## 在O(1)时间内删除链表节点\n\n### 题目描述\n给定单向链表的头指针和一个节点指针，定义一个函数在 O(1) 时间内删除该节点。\n\n### 解法\n判断要删除的节点是否是尾节点，若是，直接删除；若不是，把要删除节点的下一个节点赋给要删除的节点即可。\n\n### ```进行n次操作，平均时间复杂度为：( (n-1) * O(1) + O(n) ) / n = O(1)，所以符合题目上说的O(1)```\n\n```java\n/**\n * @author bingo\n * @since 2018/11/20\n */\n\npublic class Solution {\n\n    class ListNode {\n        int val;\n        ListNode next;\n    }\n\n    /**\n     * 删除链表的节点\n     * @param head 链表头节点\n     * @param tobeDelete 要删除的节点\n     */\n    public ListNode deleteNode(ListNode head, ListNode tobeDelete) {\n        if (head == null || tobeDelete == null) {\n            return head;\n        }\n\n        // 删除的不是尾节点\n        if (tobeDelete.next != null) {\n            tobeDelete.val = tobeDelete.next.val;\n            tobeDelete.next = tobeDelete.next.next;\n        }\n        // 链表中仅有一个节点\n        else if (head == tobeDelete) {\n            head = null;\n        }\n        // 删除的是尾节点\n        else {\n            ListNode ptr = head;\n            while (ptr.next != tobeDelete) {\n                ptr = ptr.next;\t\n          \t}\n            ptr.next = null;\n        }\n\n        return head;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（从有多个节点的链表的中间/头部/尾部删除一个节点；从只有一个节点的链表中删除唯一的节点）；\n2. 特殊输入测试（指向链表头节点的为空指针；指向要删除节点的为空指针）。\n"
  },
  {
    "path": "docs/jianzhioffer/java/18_02_DeleteDuplicatedNode.md",
    "content": "## 删除链表中重复的节点\n\n### 题目描述\n在一个排序的链表中，存在重复的结点，请删除该链表中重复的结点，重复的结点不保留，返回链表头指针。 例如，链表`1->2->3->3->4->4->5` 处理后为 `1->2->5`。\n\n### 解法\n#### 解法一：递归\n\n```java\n/**\n * @author bingo\n * @since 2018/11/21\n */\n\n/*\n public class ListNode {\n    int val;\n    ListNode next = null;\n\n    ListNode(int val) {\n        this.val = val;\n    }\n}\n*/\npublic class Solution {\n    /**\n     * 删除链表重复的节点\n     * @param pHead 链表头节点\n     * @return 删除节点后的链表\n     */\n    public ListNode deleteDuplication(ListNode pHead) {\n        if (pHead == null || pHead.next == null) {\n            return pHead;\n        }\n\n        if (pHead.val == pHead.next.val) {\n            if (pHead.next.next == null) {\n                return null;\n            }\n            if (pHead.next.next.val == pHead.val) {\n                return deleteDuplication(pHead.next);\n            }\n            return deleteDuplication(pHead.next.next);\n        }\n        pHead.next = deleteDuplication(pHead.next);\n        return pHead;\n    }\n}\n```\n\n#### 解法二\n```java\n/*\n public class ListNode {\n    int val;\n    ListNode next = null;\n\n    ListNode(int val) {\n        this.val = val;\n    }\n}\n*/\npublic class Solution {\n    public ListNode deleteDuplication(ListNode pHead) {\n        if (pHead == null || pHead.next == null) {\n            return pHead;\n        }\n        \n        ListNode pre = null;\n        ListNode cur = pHead;\n        while (cur != null) {\n            if (cur.next != null && cur.next.val == cur.val) {\n                int val = cur.val;\n                while (cur.next != null && cur.next.val == val) {\n                    cur = cur.next;\n                }\n                if (pre == null) {\n                    pHead = cur.next;\n                } else {\n                    pre.next = cur.next;\n                }\n            } else {\n                pre = cur;\n            }\n            cur = cur.next;\n        }\n        return pHead;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（重复的节点位于链表的头部/中间/尾部；链表中没有重复的节点）；\n2. 特殊输入测试（指向链表头节点的为空指针；链表中所有节点都是重复的）。"
  },
  {
    "path": "docs/jianzhioffer/java/19_RegularExpressionsMatching.md",
    "content": "## 正则表达式匹配\n\n### 题目描述\n请实现一个函数用来匹配包括`.`和`*`的正则表达式。模式中的字符`.`表示任意一个字符，而`*`表示它前面的字符可以出现任意次（包含`0`次）。 在本题中，匹配是指字符串的所有字符匹配整个模式。例如，字符串`aaa`与模式`a.a`和`ab*ac*a`匹配，但是与`aa.a`和`ab*a`均不匹配。\n\n### 解法\n判断模式中第二个字符是否是 `*`：\n- 若是，看如果模式串第一个字符与字符串第一个字符是否匹配：\n    - 1. 若不匹配，在模式串上向右移动两个字符`j+2`，相当于 a* 被忽略\n    - 2. 若匹配，字符串后移`i+1`。此时模式串可以移动两个字符`j+2`，也可以不移动`j`。\n- 若不是，看当前字符与模式串的当前字符是否匹配，即 str[i] == pattern[j] || pattern[j] == '.'：\n    - 1. 若匹配，则字符串与模式串都向右移动一位，`i+1`，`j+1`。\n    - 2. 若不匹配，返回 fasle。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/21\n */\n\npublic class Solution {\n    /**\n     * 判断字符串是否与模式串匹配\n     * @param str 字符串\n     * @param pattern 模式串\n     * @return 是否匹配\n     */\n    public boolean match(char[] str, char[] pattern) {\n        if (str == null || pattern == null) {\n            return false;\n        }\n        return match(str, 0, str.length, pattern, 0, pattern.length);\n    }\n\n    private boolean match(char[] str, int i, int len1,\n                          char[] pattern, int j, int len2) {\n        if (i == len1 && j == len2) {\n            return true;\n        }\n\n        // \"\",\".*\"\n        if (i != len1 && j == len2) {\n            return false;\n        }\n\n        if (j + 1 < len2 && pattern[j + 1] == '*') {\n            if (i < len1 && (str[i] == pattern[j] || pattern[j] == '.')) {\n                return match(str, i, len1, pattern, j + 2, len2)\n                        || match(str, i + 1, len1, pattern, j, len2)\n                        || match(str, i + 1, len1, pattern,j + 2, len2);\n            }\n\n            // \"\",\".*\"\n            return match(str, i, len1, pattern, j + 2, len2);\n\n        }\n        if (i < len1 && (str[i] == pattern[j] || pattern[j] == '.')) {\n            return match(str, i + 1, len1, pattern, j + 1, len2);\n        }\n        return false;\n\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（模式字符串里包含普通字符、`.`、`*`；模式字符串和输入字符串匹配/不匹配）；\n2. 特殊输入测试（输入字符串和模式字符串是空指针、空字符串）。"
  },
  {
    "path": "docs/jianzhioffer/java/20_NumericStrings.md",
    "content": "## 表示数值的字符串\n\n### 题目描述\n请实现一个函数用来判断字符串是否表示数值（包括整数和小数）。例如，字符串\"+100\",\"5e2\",\"-123\",\"3.1416\"和\"-1E-16\"都表示数值。 但是\"12e\",\"1a3.14\",\"1.2.3\",\"+-5\"和\"12e+4.3\"都不是。\n\n### 解法\n\n#### 解法一\n\n利用正则表达式匹配即可。\n```\n[]  ： 字符集合\n()  ： 分组\n?   ： 重复 0 ~ 1\n+   ： 重复 1 ~ n\n*   ： 重复 0 ~ n\n.   ： 任意字符\n\\\\. ： 转义后的 .\n\\\\d ： 数字\n```\n\n```java\n/**\n * @author bingo\n * @since 2018/11/21\n */\n\npublic class Solution {\n    /**\n     * 判断是否是数字\n     * @param str\n     * @return\n     */\n    public boolean isNumeric(char[] str) {\n        return str != null \n                && str.length != 0 \n                && new String(str).matches(\"[+-]?\\\\d*(\\\\.\\\\d+)?([eE][+-]?\\\\d+)?\");\n    }\n}\n```\n\n#### 解法二【剑指offer解法】\n\n表示数值的字符串遵循模式`A[.[B]][e|EC]`或者`.B[e|EC]`，其中A为数值的整数部分，B紧跟小数点为数值的小数部分，C紧跟着e或者E为数值的指数部分。上述A和C都有可能以 `+` 或者 `-` 开头的0~9的数位串，B也是0~9的数位串，但前面不能有正负号。\n\n```java\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2018/12/29\n * @description\n */\npublic class Solution {\n\n    private int index = 0;\n\n    /**\n     * 判断是否是数值\n     * @param  str \n     * @return \n     */\n    public boolean isNumeric(char[] str) {\n        if (str == null || str.length < 1) {\n            return false;\n        }\n\n        // 判断是否存在整数\n        boolean flag = scanInteger(str);\n\n        // 小数部分\n        if (index < str.length && str[index] == '.') {\n            index++;\n            // 小数部分可以有整数或者没有整数\n            // 所以使用 ||\n            flag = scanUnsignedInteger(str) || flag;\n        }\n\n        if (index < str.length && (str[index] == 'e' || str[index] == 'E')) {\n            index++;\n            // e或E前面必须有数字\n            // e或者E后面必须有整数\n            // 所以使用 &&\n            flag = scanInteger(str) && flag;\n        }\n\n        return flag && index == str.length;\n\n    }\n\n    private boolean scanInteger(char[] str) {\n        // 去除符号\n        while (index < str.length && (str[index] == '+' || str[index] == '-')) {\n            index++;\n        }\n\n        return scanUnsignedInteger(str);\n    }\n\n    private boolean scanUnsignedInteger(char[] str) {\n        int start = index;\n        while (index < str.length && str[index] >= '0' && str[index] <= '9') {\n            index++;\n        }\n        // 判断是否存在整数\n        return index > start;\n    }\n}\n```\n\n\n\n### 测试用例\n\n1. 功能测试（正数或者负数；包含或者不包含整数部分的数值；包含或者不包含效数部分的值；包含或者不包含指数部分的值；各种不能表达有效数值的字符串）；\n2. 特殊输入测试（输入字符串和模式字符串是空指针、空字符串）。"
  },
  {
    "path": "docs/jianzhioffer/java/21_ReorderArray.md",
    "content": "## 调整数组顺序使奇数位于偶数前面\n\n### 题目描述\n输入一个整数数组，实现一个函数来调整该数组中数字的顺序，使得所有的奇数位于数组的前半部分，所有的偶数位于数组的后半部分，并保证奇数和奇数，偶数和偶数之间的相对位置不变。\n\n### 解法\n#### 解法一\n计算出奇数的个数，就很容易写出来了。\n\n```java\nimport java.util.Arrays;\n\n/**\n * @author bingo\n * @since 2018/11/21\n */\n\npublic class Solution {\n    /**\n     * 调整数组元素顺序，使得奇数元素位于偶数元素前面，且保证奇数和奇数，偶数和偶数之间的相对位置不变。\n     * @param array 数组\n     */\n    public void reOrderArray(int [] array) {\n        if (array == null || array.length < 2) {\n            return;\n        }\n\n        int numsOfOdd = 0;\n        for (int val : array) {\n            if (val % 2 == 1) {\n                ++numsOfOdd;\n            }\n        }\n        int[] bak = Arrays.copyOf(array, array.length);\n        int i = 0, j = numsOfOdd;\n        for (int val : bak) {\n            if (val % 2 == 1) {\n                array[i++] = val;\n            } else {\n                array[j++] = val;\n            }\n        }\n    }\n\n}\n```\n\n#### 解法二\n```java\nimport java.util.Arrays;\n\npublic class Solution {\n    public void reOrderArray(int [] array) {\n        if (array == null || array.length < 2) {\n            return;\n        }\n        Integer[] bak = new Integer[array.length];\n        Arrays.setAll(bak, i -> array[i]);\n        Arrays.sort(bak, (x, y) -> (y & 1) - (x & 1));\n        Arrays.setAll(array, i -> bak[i]);\n    }\n    \n}\n```\n\n### 测试用例\n1. 功能测试（输入数组中的奇数、偶数交替出现；输入的数组中所有偶数都出现在奇数的前面；输入的数组中所有偶数都出现在奇数的前面；输入的数组中所有奇数都出现在偶数的前面）；\n2. 特殊输入测试（输入空指针；输入的数组只包含一个数字）。"
  },
  {
    "path": "docs/jianzhioffer/java/22_KthNodeFromEnd.md",
    "content": "## 链表中倒数第k个结点\n\n### 题目描述\n输入一个链表，输出该链表中倒数第k个结点。\n\n### 解法\npre 指针走 `k-1` 步。之后 cur 指针指向 phead，然后两个指针同时走，直至 pre 指针到达尾结点。\n\n> 当用一个指针遍历链表不能解决问题的时候，可以尝试用两个指针来遍历链表。可以让其中一个指针遍历的速度快一些。\n\n此题需要考虑一些特殊情况。比如 k 的值小于 0 或者大于链表长度。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/21\n */\n\n/*\npublic class ListNode {\n    int val;\n    ListNode next = null;\n\n    ListNode(int val) {\n        this.val = val;\n    }\n}*/\npublic class Solution {\n    /**\n     * 找出链表倒数第k个节点，k从1开始\n     * @param head 链表头部\n     * @param k 第k个节点\n     * @return 倒数第k个节点\n     */\n    public ListNode FindKthToTail(ListNode head,int k) {\n        if (head == null || k < 1) {\n            return null;\n        }\n\n        ListNode pre = head;\n        for (int i = 0; i < k - 1; ++i) {\n            if (pre.next != null) {\n                pre = pre.next;\n            } else {\n                return null;\n            }\n        }\n\n        ListNode cur = head;\n        while (pre.next != null) {\n            pre = pre.next;\n            cur = cur.next;\n        }\n        return cur;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（第 k 个节点在链表的中间/头部/尾部）；\n2. 特殊输入测试（输入空指针；链表的节点总数小于 k；k=0）。"
  },
  {
    "path": "docs/jianzhioffer/java/23_EntryNodeInListLoop.md",
    "content": "## 链表中环的入口结点\n\n### 题目描述\n给一个链表，若其中包含环，请找出该链表的环的入口结点，否则，输出`null`。\n\n### 解法\n- 先利用快慢指针。若能相遇，说明存在环，且相遇点一定是在环上；若没有相遇，说明不存在环，返回 `null`。\n- 固定当前相遇点，用一个指针继续走，同时累积结点数。计算出环的结点个数 `cnt`。\n- 指针 p1 先走 `cnt` 步，p2 指向链表头部，之后 `p1`,`p2` 同时走，相遇时，相遇点一定是在环的入口处。因为 `p1` 比 `p2` 多走了环的一圈。\n\n```java\n\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n/*\n public class ListNode {\n    int val;\n    ListNode next = null;\n\n    ListNode(int val) {\n        this.val = val;\n    }\n}\n*/\npublic class Solution {\n\n    /**\n     * 求链表环的入口，若没有环，返回null\n     * @param pHead 链表头\n     * @return 环的入口点\n     */\n    public ListNode EntryNodeOfLoop(ListNode pHead) {\n        if (pHead == null || pHead.next == null) {\n            return null;\n        }\n        ListNode fast = pHead;\n        ListNode slow = pHead;\n        boolean flag = false;\n        while (fast != null && fast.next != null) {\n            slow = slow.next;\n            fast = fast.next.next;\n            if (fast == slow) {\n                flag = true;\n                break;\n            }\n        }\n\n        // 快指针与慢指针没有相遇，说明无环，返回 null\n        if (!flag) {\n            return null;\n        }\n\n        ListNode cur = slow.next;\n        // 求出环中结点个数\n        int cnt = 1;\n        while (cur != slow) {\n            cur = cur.next;\n            ++cnt;\n        }\n\n        // 指针p1先走cnt步\n        ListNode p1 = pHead;\n        for (int i = 0; i < cnt; ++i) {\n            p1 = p1.next;\n        }\n\n        // p2指向链表头，然后p1/p2同时走，首次相遇的地方就是环的入口\n        ListNode p2 = pHead;\n        while (p1 != p2) {\n            p1 = p1.next;\n            p2 = p2.next;\n        }\n        return p1;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（链表中包含/不包含环；链表中有多个或者只有一个节点）；\n2. 特殊输入测试（链表头节点为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/24_ReverseList.md",
    "content": "## 反转链表\n\n### 题目描述\n输入一个链表，反转链表后，输出新链表的表头。\n\n### 解法\n#### 解法一\n利用头插法解决。\n\n```java\n\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n/*\npublic class ListNode {\n    int val;\n    ListNode next = null;\n\n    ListNode(int val) {\n        this.val = val;\n    }\n}*/\npublic class Solution {\n    /**\n     * 反转链表\n     * @param head 链表头部\n     * @return 反转后的链表\n     */\n    public ListNode ReverseList(ListNode head) {\n        if (head == null || head.next == null) {\n            return head;\n        }\n\n        ListNode dummy = new ListNode(-1);\n        dummy.next = null;\n        ListNode p1 = head;\n        ListNode p2 = p1.next;\n        while (p1 != null) {\n            p1.next = dummy.next;\n            dummy.next = p1;\n            p1 = p2;\n            if (p1 == null) {\n                break;\n            }\n            p2 = p1.next;\n        }\n\n        return dummy.next;\n    }\n}\n```\n\n#### 解法二：递归\n\n```java\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n\n/*\npublic class ListNode {\n    int val;\n    ListNode next = null;\n\n    ListNode(int val) {\n        this.val = val;\n    }\n}*/\npublic class Solution {\n    public ListNode ReverseList(ListNode head) {\n        if (head == null || head.next == null) {\n            return head;\n        }\n        \n        ListNode next = ReverseList(head.next);\n        ListNode cur = next;\n        while (cur.next != null) {\n            cur = cur.next;\n        }\n        cur.next = head;\n        head.next = null;\n        return next;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（链表中有多个结点/只有一个节点）；\n2. 特殊输入测试（链表头节点为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/25_MergeSortedLists.md",
    "content": "## 合并两个排序的链表\n\n### 题目描述\n输入两个单调递增的链表，输出两个链表合成后的链表，当然我们需要合成后的链表满足单调不减规则。\n\n### 解法\n#### 解法一\n同时遍历两链表进行 `merge`。\n\n```java\n\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n/*\npublic class ListNode {\n    int val;\n    ListNode next = null;\n\n    ListNode(int val) {\n        this.val = val;\n    }\n}*/\npublic class Solution {\n    /**\n     * 合并两个排序链表\n     * @param list1 链表1\n     * @param list2 链表2\n     * @return 合并后的单调不递减链表\n     */\n    public ListNode Merge(ListNode list1, ListNode list2) {\n        if (list1 == null) {\n            return list2;\n        }\n        if (list2 == null) {\n            return list1;\n        }\n\n        ListNode dummy = new ListNode(-1);\n        ListNode cur = dummy;\n        ListNode p1 = list1;\n        ListNode p2 = list2;\n        while (p1 != null && p2 != null) {\n            if (p1.val < p2.val) {\n                ListNode t = p1.next;\n                cur.next = p1;\n                p1.next = null;\n                p1 = t;\n            } else {\n                ListNode t = p2.next;\n                cur.next = p2;\n                p2.next = null;\n                p2 = t;\n            }\n            cur = cur.next;\n        }\n\n        cur.next = p1 == null ? p2 : p1;\n        return dummy.next;\n\n    }\n}\n```\n\n#### 解法二：递归\n```java\n\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n/*\npublic class ListNode {\n    int val;\n    ListNode next = null;\n\n    ListNode(int val) {\n        this.val = val;\n    }\n}*/\npublic class Solution {\n    /**\n     * 合并两个排序链表\n     * @param list1 链表1\n     * @param list2 链表2\n     * @return 合并后的单调不递减链表\n     */\n    public ListNode Merge(ListNode list1, ListNode list2) {\n        if (list1 == null) {\n            return list2;\n        }\n        if (list2 == null) {\n            return list1;\n        }\n\n        if (list1.val < list2.val) {\n            list1.next = Merge(list1.next, list2);\n            return list1;\n        }\n\n        list2.next = Merge(list1, list2.next);\n        return list2;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的两个链表有多个节点；节点的值互不相同或者存在值相等的多个节点）；\n2. 特殊输入测试（两个链表的一个或者两个头节点为空指针；两个链表中只有一个节点）。"
  },
  {
    "path": "docs/jianzhioffer/java/26_SubstructureInTree.md",
    "content": "## 树的子结构\n\n### 题目描述\n输入两棵二叉树`A`，`B`，判断`B`是不是`A`的子结构。（ps：我们约定空树不是任意一个树的子结构）\n\n### 解法\n递归方式遍历：\n\n- 在树A中找到和树B的根结点值一样的结点R\n- 判断树A以R为根结点的子树是否包含与树B一样的结构\n\n这道题的time complexity应该为O(n * m)，其中n为root1的节点数，m为root2的节点数。\n\n```java\n/**\npublic class TreeNode {\n    int val = 0;\n    TreeNode left = null;\n    TreeNode right = null;\n\n    public TreeNode(int val) {\n        this.val = val;\n\n    }\n}\n*/\n\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2019/01/01\n * @description\n */\npublic class Solution {\n\n    public boolean HasSubtree(TreeNode root1, TreeNode root2) {\n\n        if (root1 == null || root2 == null) {\n            return false;\n        }\n\n        return isSame(root1, root2) || \n                HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);\n    }\n\n    private boolean isSame(TreeNode root1, TreeNode root2) {\n\n        if (root2 == null) {\n            return true;\n        }\n\n        // 在root2，root1遍历完成后，仍未找到符合的结构，返回false\n        if (root1 == null) {\n            return false;\n        }\n\n        if (root1.val != root2.val) {\n            return false;\n        }\n\n        return isSame(root1.left, root2.left) && isSame(root1.right, root2.right);\n    }\n\n}\n```\n\n### 测试用例\n1. 功能测试（树A和树B都是普通的二叉树；树B是/不是树A的子结构）；\n2. 特殊输入测试（两棵二叉树的一个或者两个根结点为空指针，二叉树的所有结点都没有左/右子树）。"
  },
  {
    "path": "docs/jianzhioffer/java/27_MirrorOfBinaryTree.md",
    "content": "## 二叉树的镜像\n\n### 题目描述\n操作给定的二叉树，将其变换为源二叉树的镜像。\n\n```\n源二叉树 \n    \t    8\n    \t   /  \\\n    \t  6   10\n    \t / \\  / \\\n    \t5  7 9 11\n\n镜像二叉树\n    \t    8\n    \t   /  \\\n    \t  10   6\n    \t / \\  / \\\n    \t11 9 7  5\n```\n\n### 解法\n将根结点的左右孩子互换，之后递归左右孩子。\n\n```java\n\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n/*\n public class TreeNode {\n int val = 0;\n TreeNode left = null;\n TreeNode right = null;\n\n public TreeNode(int val) {\n this.val = val;\n\n }\n\n }\n */\npublic class Solution {\n    /**\n     * 将二叉树转换为它的镜像\n     * @param root 二叉树的根结点\n     */\n    public void Mirror(TreeNode root) {\n        if (root == null || !hasChild(root)) {\n            return;\n        }\n\n        TreeNode t = root.left;\n        root.left = root.right;\n        root.right = t;\n        Mirror(root.left);\n        Mirror(root.right);\n    }\n\n    private boolean hasChild(TreeNode root) {\n        return root.left != null || root.right != null;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（普通的二叉树；二叉树的所有结点都没有左/右子树；只有一个结点的二叉树）；\n2. 特殊输入测试（二叉树的根结点为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/28_SymmetricalBinaryTree.md",
    "content": "## 对称的二叉树\n\n### 题目描述\n请实现一个函数，用来判断一颗二叉树是不是对称的。注意，如果一个二叉树同此二叉树的镜像是同样的，定义其为对称的。\n\n### 解法\n比较二叉树的前序遍历序列和对称前序遍历序列是否一样，若是，说明是对称的。\n\n```java\n\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n/*\npublic class TreeNode {\n    int val = 0;\n    TreeNode left = null;\n    TreeNode right = null;\n\n    public TreeNode(int val) {\n        this.val = val;\n\n    }\n\n}\n*/\npublic class Solution {\n    /**\n     * 判断是否是对称二叉树\n     * @param pRoot 二叉树的根结点\n     * @return 是否为对称二叉树\n     */\n    boolean isSymmetrical(TreeNode pRoot) {\n        return isSymmetrical(pRoot, pRoot);\n    }\n\n    private boolean isSymmetrical(TreeNode pRoot1, TreeNode pRoot2) {\n        if (pRoot1 == null && pRoot2 == null) {\n            return true;\n        }\n        if (pRoot1 == null || pRoot2 == null) {\n            return false;\n        }\n        if (pRoot1.val != pRoot2.val) {\n            return false;\n        }\n\n        return isSymmetrical(pRoot1.left, pRoot2.right) && isSymmetrical(pRoot1.right, pRoot2.left);\n\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（对称的二叉树；因结构而不对称的二叉树；结构对称但节点的值不对称的二叉树）；\n2. 特殊输入测试（二叉树的根结点为空指针；只有一个节点的二叉树；所有节点的值都相同的二叉树）。"
  },
  {
    "path": "docs/jianzhioffer/java/29_PrintMatrix.md",
    "content": "## 顺时针打印矩阵\n\n### 题目描述\n输入一个矩阵，按照从外向里以顺时针的顺序依次打印出每一个数字，例如，如果输入如下 `4 X 4` 矩阵： \n```\n1   2   3   4\n5   6   7   8\n9   10  11  12\n13  14  15  16\n```\n\n则依次打印出数字：\n```\n1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.\n```\n### 解法\n剑指offer上的思路有点复杂，需要考虑坐标变换太多，考虑用另一种思路来解决。\n\n在矩阵中，使用左上角坐标(tR,tC)和右下角的坐标(dR,dC)就可以表示一个矩阵。比如题目中的矩阵，当(tR,tC) = (0,0)和(dR,dC) = (3,3)时，表示的子矩阵就是整个矩阵：\n\n```java\n1\t2\t3\t4\n5\t\t\t8\n9\t\t\t12\n13\t14\t15\t16    \n```\n\n当外层循环遍历后，可以令tR和tC加1，dR和dC减1，执行内层循环。当左上角的坐标跑到右下角坐标的右方或者下方，则整个过程就终止。\n\n```java\n/**\n * @author mcrwayfun\n * @version 1.0\n * @description\n * @date Created in 2019/1/2\n */\npublic class Solution {\n    /**\n     * 转圈打印矩阵\n     * @param matrix 矩阵\n     * @return 存放结果的list\n     */\n    public ArrayList<Integer> printMatrix(int[][] matrix) {\n        ArrayList<Integer> reList = new ArrayList<>();\n        if (matrix == null) {\n            return reList;\n        }\n\n        int tR = 0;\n        int tC = 0;\n        int dR = matrix.length - 1;\n        int dC = matrix[0].length - 1;\n\n        while (tR <= dR && tC <= dC) {\n            printMatrix(matrix, tR++, tC++, dR--, dC--, reList);\n        }\n\n        return reList;\n    }\n\n    public void printMatrix(int[][] matrix, int tR, int tC, int dR, int dC, ArrayList<Integer> reList) {\n        // 只有一行\n        if (tR == dR) {\n            for (int i = tC; i <= dC; i++) {\n                reList.add(matrix[tR][i]);\n            }\n        }\n        // 只有一列\n        else if (tC == dC) {\n            for (int i = tR; i <= dR; i++) {\n                reList.add(matrix[i][tC]);\n            }\n        } else {\n            int curR = tR;\n            int curC = tC;\n            // 从左到右\n            while (curC != dC) {\n                reList.add(matrix[tR][curC]);\n                curC++;\n            }\n            // 从上到下\n            while (curR != dR) {\n                reList.add(matrix[curR][dC]);\n                curR++;\n            }\n            // 从右到左\n            while (curC != tC) {\n                reList.add(matrix[dR][curC]);\n                curC--;\n            }\n            // 从下到上\n            while (curR != tR) {\n                reList.add(matrix[curR][tC]);\n                curR--;\n            }\n        }\n\n    }\n}\n```\n\n### 测试用例\n1. 数组中有多行多列；数组中只有一行；数组中只有一列；数组中只有一行一列。"
  },
  {
    "path": "docs/jianzhioffer/java/30_MinInStack.md",
    "content": "## 包含min函数的栈\n\n### 题目描述\n定义栈的数据结构，请在该类型中实现一个能够得到栈中所含最小元素的min函数（时间复杂度应为`O(1)`）。\n\n### 解法\n定义两个`stack`。\n\n压栈时，先将元素`node`压入`stack1`。然后判断`stack2`的情况：\n- `stack2`栈为空或者栈顶元素大于`node`，则将`node`压入`stack2`中。\n- `stack2`栈不为空且栈定元素小于`node`，则重复压入栈顶元素。\n\n获取最小元素时，从`stack2`中获取栈顶元素即可。\n\n```java\nimport java.util.Stack;\n\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n\npublic class Solution {\n\n    private Stack<Integer> stack1 = new Stack<>();\n    private Stack<Integer> stack2 = new Stack<>();\n\n    /**\n     * 压栈\n     * @param node 待压入的元素\n     */\n    public void push(int node) {\n        stack1.push(node);\n        if (stack2.isEmpty() || stack2.peek() >= node) {\n            stack2.push(node);\n        } else {\n            stack2.push(stack2.peek());\n        }\n    }\n\n    public void pop() {\n        stack1.pop();\n        stack2.pop();\n    }\n\n    public int top() {\n        return stack2.peek();\n    }\n\n    /**\n     * O(1)获取栈中最小值\n     * @return 最小值\n     */\n    public int min() {\n        return stack2.peek();\n    }\n}\n```\n\n### 测试用例\n1. 新压入栈的数字比之前的最小值大/小。\n2. 弹出栈的数字是/不是最小元素。"
  },
  {
    "path": "docs/jianzhioffer/java/31_StackPushPopOrder.md",
    "content": "## 栈的压入、弹出序列\n\n### 题目描述\n输入两个整数序列，第一个序列表示栈的压入顺序，请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列`1,2,3,4,5`是某栈的压入顺序，序列`4,5,3,2,1`是该压栈序列对应的一个弹出序列，但`4,3,5,1,2`就不可能是该压栈序列的弹出序列。（注意：这两个序列的长度是相等的）\n\n### 解法\n判断下一个要弹出的元素：\n- 如果刚好是栈顶元素，直接弹出。\n- 如果不在栈顶，则把压栈序列中还没有入栈的数字压入栈，直到待弹出的数字压入栈顶。\n- 如果所有数字都压入栈顶后依然没有后找到下一个弹出的数字，则不可能是弹出序列。\n\n```java\nimport java.util.Stack;\n\n/**\n * @author bingo\n * @since 2018/11/22\n */\n\n\npublic class Solution {\n    /**\n     * 判断是否是弹出序列\n     * @param pushA 压栈序列\n     * @param popA 弹栈序列\n     * @return 是否是弹出序列\n     */\n    public boolean IsPopOrder(int[] pushA,int[] popA) {\n        if (pushA == null || popA == null || pushA.length != popA.length) {\n            return false;\n        }\n\n        Stack<Integer> stack = new Stack<>();\n        int i = 0;\n        int n = pushA.length;\n        boolean flag = false;\n        for (int val : popA) {\n            while (stack.isEmpty() || stack.peek() != val) {\n                if (i >= n) {\n                    flag = true;\n                    break;\n                }\n                stack.push(pushA[i++]);\n            }\n            if (flag) {\n                break;\n            }\n            stack.pop();\n        }\n\n        return stack.isEmpty();\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的两个数组含有多个数字或者只有一个数字：第二个数组是/不是第一个数组表示的压入序列对应的栈的弹出序列）；\n2. 特殊输入测试（输入两个空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/32_01_PrintTreeFromTopToBottom.md",
    "content": "## 不分行从上到下打印二叉树\n\n### 题目描述\n从上往下打印出二叉树的每个节点，同层节点从左至右打印。\n\n### 解法\n先将根节点进入队列。\n\n队头元素出队，将值存入 list，判断该元素是否有左/右子树，有的话依次进入队列中。队列为空时结束。\n\n```java\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.Queue;\n\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\n/**\n public class TreeNode {\n int val = 0;\n TreeNode left = null;\n TreeNode right = null;\n\n public TreeNode(int val) {\n this.val = val;\n\n }\n\n }\n */\npublic class Solution {\n    /**\n     * 从上到下打印二叉树\n     * @param root 二叉树根节点\n     * @return 结果list\n     */\n    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {\n        ArrayList<Integer> list = new ArrayList<>();\n        if (root == null) {\n            return list;\n        }\n        Queue<TreeNode> queue = new LinkedList<>();\n        queue.offer(root);\n        while (!queue.isEmpty()) {\n            TreeNode node = queue.poll();\n            if (node.left != null) {\n                queue.offer(node.left);\n            }\n            if (node.right != null) {\n                queue.offer(node.right);\n            }\n            list.add(node.val);\n        }\n        return list;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（完全二叉树；所有节点只有左/右子树）；\n2. 特殊输入测试（二叉树根节点为空指针；只有一个节点的二叉树）。"
  },
  {
    "path": "docs/jianzhioffer/java/32_02_PrintTreesInLines.md",
    "content": "## 把二叉树打印成多行\n\n### 题目描述\n从上到下按层打印二叉树，同一层结点从左至右输出。每一层输出一行。\n\n### 解法\n与上一题类似，只不过需要用变量记录每一层要打印多少个节点。\n\n```java\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.Queue;\n\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\n/*\npublic class TreeNode {\n    int val = 0;\n    TreeNode left = null;\n    TreeNode right = null;\n\n    public TreeNode(int val) {\n        this.val = val;\n\n    }\n\n}\n*/\npublic class Solution {\n    /**\n     * 把二叉树打印成多行\n     * @param pRoot 二叉树根节点\n     * @return 结果list\n     */\n    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {\n        ArrayList<ArrayList<Integer>> list = new ArrayList<>();\n        if (pRoot == null) {\n            return list;\n        }\n\n        Queue<TreeNode> queue = new LinkedList<>();\n        queue.offer(pRoot);\n        int cnt = 1;\n        while (cnt > 0) {\n            int num = cnt;\n            cnt = 0;\n            ArrayList<Integer> res = new ArrayList<>();\n            for (int i = 0; i < num; ++i) {\n                TreeNode node = queue.poll();\n                if (node.left != null) {\n                    queue.offer(node.left);\n                    ++cnt;\n                }\n                if (node.right != null) {\n                    queue.offer(node.right);\n                    ++cnt;\n                }\n                res.add(node.val);\n            }\n            list.add(res);\n        }\n        return list;\n    }\n\n}\n```\n\n### 测试用例\n1. 功能测试（完全二叉树；所有节点只有左/右子树）；\n2. 特殊输入测试（二叉树根节点为空指针；只有一个节点的二叉树）。"
  },
  {
    "path": "docs/jianzhioffer/java/32_03_PrintTreesInZigzag.md",
    "content": "## 按之字形打印二叉树\n\n### 题目描述\n请实现一个函数按照之字形打印二叉树，即第一行按照从左到右的顺序打印，第二层按照从右至左的顺序打印，第三行按照从左到右的顺序打印，其他行以此类推。\n\n如二叉树：\n```\n            1\n    \t   /  \\\n    \t  2    3\n    \t / \\  / \\\n    \t4  5 6  7\n```\n\n打印结果为：\n```\n1\n3 2\n4 5 6 7\n```\n\n### 解法\n对于上述二叉树：\n\n首先访问根结点，之后把2、3存入某结构。打印的时候，先打印3、2。这不就是栈？\n\n依次弹出栈元素，分别是3、2。弹出时需要把3、2的子结点存入结构。由于访问时顺序是`4 5 6 7`。所以也需要用栈来存放。而且，此时需要先存放右孩子，再存放左孩子。（奇数层/偶数层存放左右孩子的顺序不同）\n\n这里需要用两个栈来实现。如果只用一个栈，那么当弹出3、2 时，先将 3 的孩子节点压入栈。之后弹栈的时候不是先弹出 2，而是弹出了 3 的 孩子节点，就错了。\n\n\n```java\nimport java.util.ArrayList;\nimport java.util.Stack;\n\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\n/*\npublic class TreeNode {\n    int val = 0;\n    TreeNode left = null;\n    TreeNode right = null;\n\n    public TreeNode(int val) {\n        this.val = val;\n\n    }\n\n}\n*/\npublic class Solution {\n    /**\n     * 按之字形打印二叉树\n     * @param pRoot 二叉树的根节点\n     * @return 结果list\n     */\n    public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {\n        ArrayList<ArrayList<Integer>> res = new ArrayList<>();\n        if (pRoot == null) {\n            return res;\n        }\n        Stack<TreeNode> stack1 = new Stack<>();\n        Stack<TreeNode> stack2 = new Stack<>();\n        stack1.push(pRoot);\n        int i = 1;\n        Stack<TreeNode> stack = stack1;\n        while (!stack.isEmpty()) {\n            ArrayList<Integer> list = new ArrayList<>();\n            while (!stack.isEmpty()) {\n                TreeNode node = stack.pop();\n                list.add(node.val);\n                if (i % 2 == 1) {\n                    if (node.left != null) {\n                        stack2.push(node.left);\n                    }\n                    if (node.right != null) {\n                        stack2.push(node.right);\n                    }\n                } else {\n                    if (node.right != null) {\n                        stack1.push(node.right);\n                    }\n                    if (node.left != null) {\n                        stack1.push(node.left);\n                    }\n                }\n            }\n            res.add(list);\n            ++i;\n            stack = stack1.isEmpty() ? stack2 : stack1;\n        }\n\n        return res;\n    }\n\n}\n```\n\n### 测试用例\n1. 功能测试（完全二叉树；所有节点只有左/右子树）；\n2. 特殊输入测试（二叉树根节点为空指针；只有一个节点的二叉树）。"
  },
  {
    "path": "docs/jianzhioffer/java/33_SquenceOfBST.md",
    "content": "## 二叉搜索树的后序遍历序列\n\n### 题目描述\n输入一个整数数组，判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出`Yes`,否则输出`No`。假设输入的数组的任意两个数字都互不相同。\n\n### 解法\n序列的最后一个元素是二叉搜索树的根节点。\n\n在序列中从左到右找到根节点的左子树(比根节点小)、右子树(比根节点大)。\n- 如果右子树中出现比根节点小的元素，那么为 false。\n- 否则递归左右子树。\n\n\n```java\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\npublic class Solution {\n    /**\n     * 判断数组是否是某个二叉搜索树的后序遍历序列\n     *\n     * @param sequence 数组\n     * @return 是否属于某二叉搜索树的后序遍历序列\n     */\n    public boolean VerifySquenceOfBST(int[] sequence) {\n        if (sequence == null || sequence.length < 1) {\n            return false;\n        }\n        return verify(sequence, 0, sequence.length - 1);\n    }\n\n    private boolean verify(int[] sequence, int start, int end) {\n        if (start >= end) {\n            return true;\n        }\n        int val = sequence[end];\n        int i = start;\n        for (; i <= end; ++i) {\n            if (sequence[i] >= val) {\n                break;\n            }\n        }\n\n        for (int j = i; j < end; ++j) {\n            if (sequence[j] < val) {\n                return false;\n            }\n        }\n\n        return verify(sequence, start, i - 1) && verify(sequence, i, end - 1);\n\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的后序遍历序列对应一棵二叉树，包括完全二叉树、所有节点都没有左/右子树的二叉树、只有一个节点的二叉树；输入的后续遍历序列没有对应一棵二叉树）；\n2. 特殊输入测试（后序遍历序列为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/34_PathInTree.md",
    "content": "## 二叉树中和为某一值的路径\n\n### 题目描述\n输入一颗二叉树的根节点和一个整数，打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的`list`中，数组长度大的数组靠前)\n\n### 解法\n\n```java\nimport java.util.ArrayList;\n\n/**\n * @author bingo\n * @since 2018/11/23\n */\n\n/**\n public class TreeNode {\n int val = 0;\n TreeNode left = null;\n TreeNode right = null;\n\n public TreeNode(int val) {\n this.val = val;\n\n }\n\n }\n */\npublic class Solution {\n    \n    private ArrayList<ArrayList<Integer>> res = new ArrayList<>();\n\n    /**\n     * 找出二叉树中和为某一值的路径（必须从根节点到叶节点）\n     * \n     * @param root  二叉树的根结点\n     * @param target 目标值\n     * @return 结果list\n     */\n    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {\n        findPath(root, target, new ArrayList<>());\n        return res;\n    }\n\n    private void findPath(TreeNode root, int target, ArrayList<Integer> list) {\n        if (root == null) {\n            return;\n        }\n        list.add(root.val);\n        target -= root.val;\n        if (target == 0 && root.left == null && root.right == null) {\n            res.add(new ArrayList<>(list));\n        } else {\n            findPath(root.left, target, list);\n            findPath(root.right, target, list);\n        }\n        list.remove(list.size() - 1);\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（二叉树中有一条、多条符合要求的路径；二叉树中没有符合要求的路径）；\n2. 特殊输入测试（指向二叉树根节点的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/35_CopyComplexList.md",
    "content": "## 复杂链表的复制\n\n### 题目描述\n输入一个复杂链表（每个节点中有节点值，以及两个指针，一个指向下一个节点，另一个特殊指针指向任意一个节点），返回结果为复制后复杂链表的 `head`。（注意，输出结果中请不要返回参数中的节点引用，否则判题程序会直接返回空）\n\n### 解法\n可以分为3步：\n\n1. 复制每个节点，并插入到被复制节点的后面。比如1->2->3 clone 1->1->2->2->3->3\n2. 复制随机节点。当遍历到的当前节点存在随机节点时，则其复制节点也应该存在随机节点。比如当前节点`cur.random != null`，则`RandomListNode clone = cur.next;clone.random = cur.random.next;`\n3. 分离两个链表。其中奇数链表为原链表，偶数链表为复制的链表\n\n这道题的time complexity为O(n)。\n\n```java\n/**\n * @author bingo\n * @since 2018/11/24\n */\n\n/*\npublic class RandomListNode {\n    int label;\n    RandomListNode next = null;\n    RandomListNode random = null;\n\n    RandomListNode(int label) {\n        this.label = label;\n    }\n}\n*/\npublic class Solution {\n    /**\n     * 复杂链表的复制\n     * @param pHead 链表头结点\n     * @return 复制的链表\n     */\n    public RandomListNode Clone(RandomListNode pHead) {\n        if (pHead == null) {\n            return null;\n        }\n        RandomListNode cur = pHead;\n        while (cur != null) {\n            RandomListNode node = new RandomListNode(cur.label);\n            node.next = cur.next;\n            cur.next = node;\n            cur = node.next;\n        }\n\n        cur = pHead;\n        while (cur != null) {\n            RandomListNode clone = cur.next;\n            if (cur.random != null) {\n                clone.random = cur.random.next;\n            }\n            cur = clone.next;\n        }\n\n        cur = pHead;\n        RandomListNode cloneHead = pHead.next;\n        while (cur.next != null) {\n            RandomListNode clone = cur.next;\n            cur.next = clone.next;\n            cur = clone;\n        }\n        return cloneHead;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（结点中的 random 指针指向结点自身；两个结点的 random 形成环状结构；链表中只有一个结点）；\n2. 特殊输入测试（指向链表头结点的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/36_ConvertBinarySearchTree.md",
    "content": "## 二叉搜索树与双向链表\n\n### 题目描述\n输入一棵二叉搜索树，将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点，只能调整树中结点指针的指向。\n\n### 解法\n由于是二叉搜索树，因此中序遍历的结果就是排序的。\n\n中序遍历利用栈来实现。遍历时，前一个结点的 right 指向后一个结点，后一个结点的 left 指向前一个结点。\n```java\npre.right = cur\ncur.left = pre\n```\n\n```java\nimport java.util.Stack;\n\n/**\n * @author bingo\n * @since 2018/11/24\n */\n\n/**\n public class TreeNode {\n int val = 0;\n TreeNode left = null;\n TreeNode right = null;\n\n public TreeNode(int val) {\n this.val = val;\n\n }\n\n }\n */\npublic class Solution {\n    /**\n     * 将二叉搜索树转换为双向链表\n     * \n     * @param pRootOfTree\n     * @return\n     */\n    public TreeNode Convert(TreeNode pRootOfTree) {\n        if (pRootOfTree == null) {\n            return null;\n        }\n        Stack<TreeNode> stack = new Stack<>();\n        TreeNode cur = pRootOfTree;\n        TreeNode res = null;\n        TreeNode pre = null;\n        while (cur != null || !stack.isEmpty()) {\n            if (cur != null) {\n                stack.push(cur);\n                cur = cur.left;\n            } else {\n                cur = stack.pop();\n                if (pre == null) {\n                    pre = cur;\n                    res = pre;\n                } else {\n                    pre.right = cur;\n                    cur.left = pre;\n                    pre = cur;\n                }\n                cur = cur.right;\n\n            }\n        }\n        return res;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的二叉树是完全二叉树；所有结点都没有左/右子树；只有一个结点的二叉树）；\n2. 特殊输入测试（指向二叉树根结点的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/37_SerializeBinaryTrees.md",
    "content": "## 序列化二叉树\n\n### 题目描述\n请实现两个函数，分别用来序列化和反序列化二叉树。使用前序遍历实现，空节点使用字符`#` 表示。\n\n比如有如下二叉树：\n\n```java\n\t\t\t1\n\t\t2\t \t3\n\t4\t  #\t 5\t\t6\n #\t  #\t   #   #  #   #\t\n```\n\n序列化的结果为 `1,2,4,#,#,#,3,5,#,#,6,#,#` \n\n反序列化的结果为上述二叉树\n\n### 解法\n使用前序遍历进行序列化和反序列化。对格式没有要求，只要序列化得到的结果，再反序列化后能与原树相同即可。\n```java\n/**\n * @author mcrwayfun\n * @version 1.0\n * @description\n * @date Created in 2019/1/12\n */\npublic class Solution {\n\n\n    public String Serialize(TreeNode root) {\n\n        StringBuilder res = new StringBuilder();\n        if (root == null) {\n            return res.toString();\n        }\n\n        serializeHelper(root, res);\n        // 移除最后一个的符号\",\"\n        res.deleteCharAt(res.lastIndexOf(\",\"));\n        return res.toString();\n    }\n\n    private void serializeHelper(TreeNode root, StringBuilder res) {\n\n        if (root == null) {\n            res.append(\"#\");\n            res.append(\",\");\n            return;\n        }\n\n        res.append(root.val);\n        res.append(\",\");\n        serializeHelper(root.left, res);\n        serializeHelper(root.right, res);\n    }\n\n    private int index = -1;\n\n    public TreeNode Deserialize(String str) {\n\n        if (str == null || str.length() == 0) {\n            return null;\n        }\n\n        String[] treeNodeStr = str.split(\",\");\n        return deserializeHelper(treeNodeStr);\n    }\n\n    private TreeNode deserializeHelper(String[] treeNodeStr) {\n\n        index++;\n        TreeNode node = null;\n\n        // index不越界并且当前节点不为#\n        if (index < treeNodeStr.length && !\"#\".equals(treeNodeStr[index])) {\n            node = new TreeNode(Integer.valueOf(treeNodeStr[index]));\n            node.left = deserializeHelper(treeNodeStr);\n            node.right = deserializeHelper(treeNodeStr);\n        }\n\n        return node;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的二叉树是完全二叉树；所有节点都没有左/右子树的二叉树；只有一个节点的二叉树；所有节点的值都相同的二叉树）；\n2. 特殊输入测试（指向二叉树根结点的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/38_StringPermutation.md",
    "content": "## 字符串的排列\n\n### 题目描述\n输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。(输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母)。ps：牛客上的测试用例对返回的list要排序。\n\n### 解法\n对整个字符串的排列可以看成两部分。第一步求所有可能出现在第一个位置的字符，即把第一个字符与后面所有非重复的字符进行交换。第二步固定第一个字符，求后面所有字符的排列；第二步中后面的所有字符又可以看成一个完整的字符，继续执行这两个步骤。\n\n注意存在重复值得情况，比如输入字符串bab，将首字符b作为固定字符串，对于将第2个下标的b换到首位仍然是bab，所有这种情况无需输出。\n\n**这道题的时间复杂度应该为O(n!)**\n\n```java\n/**\n * @author mcrwayfun\n * @version 1.0\n * @description\n * @date Created in 2019/1/14\n */\npublic class Solution {\n\n    public ArrayList<String> Permutation(String str) {\n\n        ArrayList<String> reList = new ArrayList<>();\n\n        if (str == null || str.length() == 0) {\n            return reList;\n        }\n\n        char[] chars = str.toCharArray();\n\n        // 递归输出字符串排列\n        permutationHelper(chars, 0, reList);\n        Collections.sort(reList);\n        return reList;\n    }\n\n    private void permutationHelper(char[] chars, int index, ArrayList<String> list) {\n\n        if (index == chars.length - 1) {\n            list.add(new String(chars));\n            return;\n        }\n\n        Set<Character> set = new HashSet<>();\n        // 确定交换的字符，包括自己[index,length-1]\n        for (int i = index; i < chars.length; i++) {\n\n            // 排除出现重复字符\n            // hash表，查询花费O(1)\n            if (!set.contains(chars[i])) {\n                set.add(chars[i]);\n                // 固定字符index\n                swap(chars, i, index);\n                // 递归固定剩余字符[index+1,length-1]\n                permutationHelper(chars, index + 1, list);\n                // 恢复原数组\n                swap(chars, index, i);\n            }\n        }\n    }\n\n    private void swap(char[] chars, int x, int y) {\n\n        char temp = chars[x];\n        chars[x] = chars[y];\n        chars[y] = temp;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的字符串有一个或多个字符）；\n2. 特殊输入测试（输入的字符串为nullptr指针或者内容为空）。"
  },
  {
    "path": "docs/jianzhioffer/java/39_MoreThanHalfNumber.md",
    "content": "## 数组中出现次数超过一半的数字\n\n### 题目描述\n数组中有一个数字出现的次数超过数组长度的一半，请找出这个数字。例如输入一个长度为 9 的数组 `{1,2,3,2,2,2,5,4,2}`。由于数字 2 在数组中出现了 5 次，超过数组长度的一半，因此输出 2。如果不存在则输出 0。\n\n### 解法\n#### 解法一\n利用快排中的 partition 思想。\n\n数组中有一个数字出现次数超过了数组长度的一半，那么排序后，数组中间的数字一定就是我们要找的数字。我们随机选一个数字，利用 partition() 函数，使得比选中数字小的数字都排在它左边，比选中数字大的数字都排在它的右边。\n\n判断选中数字的下标 `index`：\n\n- 如果 `index = n/2`，那么这个数字就是中位数。\n- 如果 `index > n/2`，那么接着在 index 的左边进行 partition。\n- 如果 `index < n/2`，则在 index 的右边继续进行 partition。\n\n**注意：**这种方法会修改输入的数组。时间复杂度为 `O(n)`。\n\n```java\n/**\n * @author bingo\n * @since 2018/12/6\n */\n\npublic class Solution {\n    /**\n     * 查找数组中出现次数超过一次的数字\n     *\n     * @param array 数组\n     * @return 返回该数，不存在则返回0\n     */\n    public int MoreThanHalfNum_Solution(int[] array) {\n        if (array == null || array.length == 0) {\n            return 0;\n        }\n        int n = array.length;\n        int start = 0, end = n - 1;\n        int mid = n >> 1;\n        int index = partition(array, start, end);\n        while (index != mid) {\n            if (index > mid) {\n                end = index - 1;\n            } else {\n                start = index + 1;\n            }\n            index = partition(array, start, end);\n        }\n\n        return isMoreThanHalf(array, array[index]) ? array[index] : 0;\n    }\n\n    /**\n     * 快排中的 partition 方法\n     *\n     * @param array 数组\n     * @param start 开始位置\n     * @param end 结束位置\n     * @return\n     */\n    private int partition(int[] array, int start, int end) {\n        int small = start - 1;\n        for (int i =  start; i < end; ++i) {\n            if (array[i] < array[end]) {\n                swap(array, i, ++small);\n            }\n        }\n        ++small;\n        swap(array, small, end);\n        return small;\n\n    }\n\n    private void swap(int[] array, int i, int j) {\n        int t = array[i];\n        array[i] = array[j];\n        array[j] = t;\n    }\n\n    /**\n     * 判断val元素是否真的超过数组元素个数的一半\n     *\n     * @param array 数组\n     * @param val 某元素\n     * @return boolean\n     */\n    private boolean isMoreThanHalf(int[] array, int val) {\n        int cnt = 0;\n        for (int e : array) {\n            if (e == val) {\n                ++cnt;\n            }\n        }\n        \n        return cnt * 2 > array.length;\n    }\n}\n```\n\n#### 解法二\n利用多数投票算法，从头到尾遍历数组，遇到两个不一样的数就把这两个数同时除去。除去的两个数可能都不是 majority，也可能一个是 majority 另一个不是，但是因为 majority 总数大于一半，所以这么删完最后剩下的肯定是 majority。\n\n此方法时间复杂度为 `O(n)`，且不会改变数组。\n\n```java\n/**\n * @author bingo\n * @since 2018/12/6\n */\n\npublic class Solution {\n    /**\n     * 查找数组中出现次数超过一次的数字\n     *\n     * @param array 数组\n     * @return 返回该数，不存在则返回0\n     */\n    public int MoreThanHalfNum_Solution(int[] array) {\n        if (array == null || array.length == 0) {\n            return 0;\n        }\n        \n        int res = array[0];\n        int times = 1;\n        for (int i = 1; i < array.length; ++i) {\n            if (times == 0) {\n                res = array[i];\n                times = 1;\n            } else if (array[i] == res) {\n                ++times;\n            } else {\n                --times;\n            }\n        }\n\n        return isMoreThanHalf(array, res) ? res : 0;\n    }\n\n\n    /**\n     * 判断val元素是否真的超过数组元素个数的一半\n     *\n     * @param array 数组\n     * @param val 某元素\n     * @return boolean\n     */\n    private boolean isMoreThanHalf(int[] array, int val) {\n        int cnt = 0;\n        for (int e : array) {\n            if (e == val) {\n                ++cnt;\n            }\n        }\n\n        return cnt * 2 > array.length;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的数组中存在/不存在一个出现次数超过数组长度一半的数字）；\n2. 特殊输入测试（输入的数组只有一个数字；输入空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/40_KLeastNumbers.md",
    "content": "## 获取数组中最小的k个数\n\n### 题目描述\n输入 n 个整数，找出其中最小的 K 个数。例如输入 `4,5,1,6,2,7,3,8` 这 8 个数字，则最小的 4 个数字是 `1,2,3,4`。\n\n### 解法\n#### 解法一\n利用快排中的 partition 思想。\n\n数组中有一个数字出现次数超过了数组长度的一半，那么排序后，数组中间的数字一定就是我们要找的数字。我们随机选一个数字，利用 partition() 函数，使得比选中数字小的数字都排在它左边，比选中数字大的数字都排在它的右边。\n\n判断选中数字的下标 `index`：\n\n- 如果 `index = k-1`，结束循环，返回前 k 个数。\n- 如果 `index > k-1`，那么接着在 index 的左边进行 partition。\n- 如果 `index < k-1`，则在 index 的右边继续进行 partition。\n\n**注意**，这种方法会修改输入的数组。时间复杂度为 `O(n)`。\n\n```java\nimport java.util.ArrayList;\n\n/**\n * @author bingo\n * @since 2018/12/6\n */\n\npublic class Solution {\n\n    /**\n     * 获取数组中最小的k个数\n     *\n     * @param input 输入的数组\n     * @param k 元素个数\n     * @return 最小的k的数列表\n     */\n    public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {\n        ArrayList<Integer> res = new ArrayList<>();\n        if (input == null || input.length == 0 || input.length < k || k < 1) {\n            return res;\n        }\n        int n = input.length;\n        int start = 0, end = n - 1;\n        int index = partition(input, start, end);\n        while (index != k - 1) {\n            if (index > k - 1) {\n                end = index - 1;\n            } else {\n                start = index + 1;\n            }\n            index = partition(input, start, end);\n        }\n        for (int i = 0; i < k; ++i) {\n            res.add(input[i]);\n        }\n        return res;\n    }\n\n    private int partition(int[] input, int start, int end) {\n        int index = start - 1;\n        for (int i = start; i < end; ++i) {\n            if (input[i] < input[end]) {\n                swap(input, i, ++index);\n            }\n        }\n        ++index;\n        swap(input, index, end);\n        return index;\n    }\n\n    private void swap(int[] array, int i, int j) {\n        int t = array[i];\n        array[i] = array[j];\n        array[j] = t;\n    }\n}\n```\n\n#### 解法二\n利用大根堆，存储最小的 k 个数，最后返回即可。\n\n此方法时间复杂度为 `O(nlogk)`。虽然慢一点，但是它不会改变输入的数组，并且它**适合海量数据的输入**。\n\n假设题目要求从海量的数据中找出最小的 k 个数，由于内存的大小是有限的，有可能不能把这些海量的数据一次性全部载入内存。这个时候，用这种方法是最合适的。就是说它适合 n 很大并且 k 较小的问题。\n\n```java\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.PriorityQueue;\n\n/**\n * @author bingo\n * @since 2018/12/6\n */\n\npublic class Solution {\n\n    /**\n     * 获取数组中最小的k个数\n     *\n     * @param input 输入的数组\n     * @param k 元素个数\n     * @return 最小的k的数列表\n     */\n    public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {\n        ArrayList<Integer> res = new ArrayList<>();\n        if (input == null || input.length == 0 || input.length < k || k < 1) {\n            return res;\n        }\n\n        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, Comparator.reverseOrder());\n        System.out.println(maxHeap.size());\n        for (int e : input) {\n            if (maxHeap.size() < k) {\n                maxHeap.add(e);\n            } else {\n                if (maxHeap.peek() > e) {\n                    maxHeap.poll();\n                    maxHeap.add(e);\n                }\n\n            }\n        }\n        res.addAll(maxHeap);\n        return res;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的数组中存在/不存在一个出现次数超过数组长度一半的数字）；\n2. 特殊输入测试（输入的数组只有一个数字；输入空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/41_StreamMedian.md",
    "content": "## 数据流中的中位数\n\n### 题目描述\n如何得到一个数据流中的中位数？如果从数据流中读出奇数个数值，那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值，那么中位数就是所有数值排序之后中间两个数的平均值。我们使用`Insert()`方法读取数据流，使用`GetMedian()`方法获取当前读取数据的中位数。\n\n### 解法\n利用大根堆存放较小的一半元素，小根堆存放较大的一半元素。维持大小堆的元素个数差不超过 1。\n\n\n```java\nimport java.util.Comparator;\nimport java.util.PriorityQueue;\n\n/**\n * @author bingo\n * @since 2018/12/7\n */\n\npublic class Solution {\n\n    private PriorityQueue<Integer> minHeap = new PriorityQueue<>();\n    private PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());\n\n    /**\n     * 插入一个数\n     *\n     * @param num 数\n     */\n    public void Insert(Integer num) {\n\n        if (maxHeap.isEmpty() || num < maxHeap.peek()) {\n            maxHeap.offer(num);\n            if (maxHeap.size() - minHeap.size() > 1) {\n                minHeap.offer(maxHeap.poll());\n            }\n\n        } else {\n            minHeap.offer(num);\n            if (minHeap.size() - maxHeap.size() > 1) {\n                maxHeap.offer(minHeap.poll());\n            }\n        }\n    }\n\n    /**\n     * 获取中位数\n     *\n     * @return 中位数\n     */\n    public Double GetMedian() {\n        int size1 = maxHeap.size();\n        int size2 = minHeap.size();\n        if (size1 > size2) {\n            return (double) maxHeap.peek();\n        }\n        if (size1 < size2) {\n            return (double) minHeap.peek();\n        }\n\n        return (maxHeap.peek() + minHeap.peek()) / 2.0;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（从数据流中读出奇数/偶数个数字）；\n2. 边界值测试（从数据流中读出 0/1/2 个数字）。"
  },
  {
    "path": "docs/jianzhioffer/java/42_GreatestSumOfSubarrays.md",
    "content": "## 连续子数组的最大和\n\n### 题目描述\n输入一个**非空**整型数组，数组里的数可能为正，也可能为负。\n数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。\n\n要求时间复杂度为`O(n)`。\n\n### 解法\n动态规划法。\n\nres[i] 表示以第 i 个数字结尾的子数组的最大和，那么求出 `max(res[i])` 即可。\n\n- `res[i] = array[i]`, if `res[i - 1] < 0`\n- `res[i] = res[i - 1] + array[i]`, if `res[i - 1] >= 0`\n\n```java\n\n/**\n * @author bingo\n * @since 2018/12/7\n */\n\npublic class Solution {\n    /**\n     * 求连续子数组的最大和\n     *\n     * @param array 数组\n     * @return 最大和\n     */\n    public int FindGreatestSumOfSubArray(int[] array) {\n        int n = array.length;\n        int[] res = new int[n];\n        res[0] = array[0];\n        int max = res[0];\n        for (int i = 1; i < n; ++i) {\n            res[i] = res[i - 1] > 0 ? res[i - 1] + array[i] : array[i];\n            max = Math.max(max, res[i]);\n        }\n        return max;\n    }\n}\n\n\n```\n\n### 测试用例\n1. 功能测试（输入的数组中有正数也有负数；输入的数组中全是正数；输入的数组中全是负数）；\n2. 特殊输入测试（表示数组的指针位为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/43_NumberOf1.md",
    "content": "## 整数中1出现的次数\n\n### 题目描述\n求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数？为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数（从1 到 n 中1出现的次数）。\n\n### 解法\n- 编程之美上给出的规律：\n\n  1. 如果第i位（自右至左，从1开始标号）上的数字为0，则第i位可能出现1的次数由更高位决定（若没有高位，视高位为0），等于更高位数字X当前位数的权重10^(i-1)。\n  2. 如果第i位上的数字为1，则第i位上可能出现1的次数不仅受更高位影响，还受低位影响（若没有低位，视低位为0），等于更高位数字X当前位数的权重10^(i-1)+（低位数字+1）。\n  3. 如果第i位上的数字大于1，则第i位上可能出现1的次数仅由更高位决定（若没有高位，视高位为0），等于（更高位数字+1）X当前位数的权重10^(i-1)。\n\n  总结一下以上的算法，可以看到，当计算右数第 i 位包含的 X 的个数时：\n\n  1. 取第 i 位左边（高位）的数字，乘以 10i−1，得到**基础值** a。\n  2. 取第 i 位数字，计算**修正值**：\n     1. 如果大于 X，则结果为 a+10i−1。\n     2. 如果小于 X，则结果为 a。\n     3. 如果等 X，则取第 i 位右边（低位）数字，设为 b，最后结果为 a+b+1。\n\n  相应的代码非常简单，效率也非常高，时间复杂度只有 O(logn)。\n\n```java\n\n/**\n * @author mcrwayfun\n * @version 1.0\n * @description\n * @date Created in 2019/1/17\n */\npublic class Solution {\n    \n    public int NumberOf1Between1AndN_Solution(int n) {\n\n        if (n < 1) {\n            return 0;\n        }\n\n        int high, low, curr, tmp, i = 1;\n        high = n;\n        int number = 0;\n        while (high != 0) {\n            // 获取第i位的高位\n            high = n / (int) Math.pow(10, i);\n            tmp = n % (int) Math.pow(10, i);\n            // 获取第i位\n            curr = tmp / (int) Math.pow(10, i - 1);\n            // 获取第i位的低位\n            low = tmp % (int) Math.pow(10, i - 1);\n            if (curr == 1) {\n                number += high * (int) Math.pow(10, i - 1) + low + 1;\n            } else if (curr < 1) {\n                number += high * (int) Math.pow(10, i - 1);\n            } else {\n                number += (high + 1) * (int) Math.pow(10, i - 1);\n            }\n            i++;\n        }\n        return number;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入1~n的数字）；\n2. 特殊输入测试（输入的数字小于0）。"
  },
  {
    "path": "docs/jianzhioffer/java/44_DigitsInSequence.md",
    "content": "## 数字序列中某一位的数字\n\n### 题目描述\n数字以 `0123456789101112131415…` 的格式序列化到一个字符序列中。\n\n在这个序列中，第 5 位（从 0 开始计数）是 5，第 13 位是 1，第 19 位是 4，等等。\n\n请写一个函数求任意位对应的数字。\n\n### 解法\n举个栗子，求序列第 1001 位。\n\n序列的前 10 位是 `0~9`， 这 10 个只有一位的数字。显然第 1001 位在这 10 个数字之后，因此这 10 个数字可以直接跳过。再从后面序列中找第 991（991=1001-10） 位的数字。接下来有 90 个两位数，共 180 位，由于 991>180，所以继续跳过。从 881 找...最后可以找到对应的数字以及数字的某一位。\n\n```java\n/**\n * @author bingo\n * @since 2018/12/7\n */\n\npublic class Solution {\n    /**\n     * 求数字序列中某一位的数字\n     *\n     * @param n 第n位\n     * @return 第n位的数字\n     */\n    public int digitAtIndex(int n) {\n        if (n < 0) {\n            return -1;\n        }\n        int digits = 1;\n        while (true) {\n            long numbers = countOfIntegers(digits);\n            if (n < digits * numbers) {\n                break;\n            }\n            n -= numbers * digits;\n            ++digits;\n        }\n        return digitAtIndex(digits, n);\n\n    }\n\n    private long countOfIntegers(int digits) {\n        return digits == 1\n                ? 10\n                : (int) (9 * Math.pow(10, digits - 1));\n    }\n\n    private int digitAtIndex(int digits, int n) {\n        int beginNumber = getBeginNumber(digits);\n        int val =  beginNumber + n / digits;\n        int indexFromRight = digits - n % digits;\n        for (int i = 1; i < indexFromRight; ++i) {\n            val /= 10;\n        }\n        return val % 10;\n    }\n\n    private int getBeginNumber(int digits) {\n        return digits == 1\n                ? 0\n                : (int) Math.pow(10, digits - 1);\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入 10、190、1000）；\n2. 边界值测试（输入 0、1）。"
  },
  {
    "path": "docs/jianzhioffer/java/45_SortArrayForMinNumber.md",
    "content": "## 把数组排成最小的数\n\n### 题目描述\n输入一个正整数数组，把数组里所有数字拼接起来排成一个数，打印能拼接出的所有数字中最小的一个。\n\n例如输入数组 `[3, 32, 321]`，则打印出这3个数字能排成的最小数字`321323`。\n\n### 解法\n\n\n```java\nimport java.util.Arrays;\n\n/**\n * @author bingo\n * @since 2018/12/8\n */\n\nclass Solution {\n\n    /**\n     * 打印数组元素组成的最小的数字\n     *\n     * @param nums 数组\n     * @return 最小的数字\n     */\n    public String printMinNumber(int[] nums) {\n        if (nums == null || nums.length == 0) {\n            return \"\";\n        }\n        int n = nums.length;\n        String[] strNums = new String[n];\n        for (int i = 0; i < n; ++i) {\n            strNums[i] = String.valueOf(nums[i]);\n        }\n\n        Arrays.sort(strNums, (o1, o2) -> (o1 + o2).compareTo(o2 + o1));\n\n        StringBuilder sb = new StringBuilder();\n        for (String str : strNums) {\n            sb.append(str);\n        }\n        return sb.toString();\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的数组中有多个数字；输入的数组中的数字有重复的数位；输入的数组中只有一个数字）；\n2. 特殊输入测试（表示数组的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/46_TranslateNumbersToStrings.md",
    "content": "## 把数字翻译成字符串\n\n### 题目描述\n给定一个数字，我们按照如下规则把它翻译为字符串：\n\n0 翻译成 ”a”，1 翻译成 ”b”，……，11 翻译成 ”l”，……，25 翻译成 ”z”。\n\n一个数字可能有多个翻译。例如 12258 有 5 种不同的翻译，它们分别是 ”bccfi”、”bwfi”、”bczi”、”mcfi”和”mzi”。\n\n请编程实现一个函数用来计算一个数字有多少种不同的翻译方法。\n\n### 解法\n先写入递推式，res 表示共有多少种翻译方法。看最后一个字符，判断它与前一个字符能否构成有效翻译，计算 res[i]：\n\n- 能，那么 `res[i] = res[i - 1] + res[i - 2]`；\n- 不能，那么 `res[i] = res[i - 1]`。\n\n\n```java\n/**\n * @author bingo\n * @since 2018/12/8\n */\n\nclass Solution {\n    /**\n     * 获取翻译字符串的方法个数\n     *\n     * @param s 字符串\n     * @return 个数\n     */\n    public int getTranslationCount(String s) {\n        if (s == null || s.length() < 2) {\n            return 1;\n        }\n        char[] chars = s.toCharArray();\n        int n = chars.length;\n        int[] res = new int[n];\n        res[0] = 1;\n        res[1] = isInRange(chars[0], chars[1]) ? 2 : 1;\n        for (int i = 2; i < n; ++i) {\n            res[i] = res[i - 1] + (isInRange(chars[i - 1], chars[i]) ? res[i - 2] : 0);\n        }\n        return res[n - 1];\n    }\n\n    private boolean isInRange(char a, char b) {\n        int s = (a - '0') * 10 + (b -'0');\n        return s >= 10 && s <= 25;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（只有一位数字；包含多位数字）；\n2. 特殊输入测试（负数；0；包含 25、26 的数字）。"
  },
  {
    "path": "docs/jianzhioffer/java/47_MaxValueOfGifts.md",
    "content": "## 礼物的最大价值\n\n### 题目描述\n在一个 `m×n` 的棋盘的每一格都放有一个礼物，每个礼物都有一定的价值（价值大于 0）。\n\n你可以从棋盘的左上角开始拿格子里的礼物，并每次向左或者向下移动一格直到到达棋盘的右下角。\n\n给定一个棋盘及其上面的礼物，请计算你最多能拿到多少价值的礼物？\n\n### 解法\n写出递推式，res 表示获得的最大礼物。\n\n```java\nres[i][j] = Math.max(res[i - 1][j], res[i][j - 1]) + grid[i][j];\n```\n\n\n```java\n/**\n * @author bingo\n * @since 2018/12/8\n */\n\nclass Solution {\n    /**\n     * 获取礼物的最大价值\n     *\n     * @param grid 数组\n     * @return 最大价值\n     */\n    public int getMaxValue(int[][] grid) {\n        if (grid == null || grid.length == 0) {\n            return 0;\n        }\n        int m = grid.length;\n        int n = grid[0].length;\n        int[][] res = new int[m][n];\n        res[0][0] = grid[0][0];\n        for (int j = 1; j < n; ++j) {\n            res[0][j] = res[0][j - 1] + grid[0][j];\n        }\n        for (int i = 1; i < m; ++i) {\n            res[i][0] = res[i - 1][0] + grid[i][0];\n        }\n        for (int i = 1; i < m; ++i) {\n            for (int j = 1; j < n; ++j) {\n                res[i][j] = Math.max(res[i - 1][j], res[i][j - 1]) + grid[i][j];\n            }\n        }\n        return res[m - 1][n - 1];\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（多行多列的矩阵；一行或者一列的矩阵；只有一个数字的矩阵）；\n2. 特殊输入测试（指向矩阵数组的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/48_LongestSubstringWithoutDup.md",
    "content": "## 最长不含重复字符的子字符串\n\n### 题目描述\n请从字符串中找出一个最长的不包含重复字符的子字符串，计算该最长子字符串的长度。\n\n假设字符串中只包含从 `a` 到 `z`的字符。\n\n### 解法\n动态规划。\n\n`res[i]` 表示以 `s[i]` 字符结尾的最长不重复字符串的长度。判断 `s[i]`：\n- 若 `s[i]` 在前面没出现过，那么 `res[i] = res[i - 1] + 1`；\n- 若 `s[i]` 在前面有出现过，判断它上一次出现的位置 `index` 到 `i` 的距离 `d` 与 `res[i - 1]` 的大小关系：\n    - 若 `d <= res[i - 1]`，说明它被包含在 `res[i - 1]` 构成的子串中，那么 `res[i] = d`；\n    - 若 `d > res[i - 1]`，说明它在 `res[i - 1]` 构成的子串的左侧，那么 `res[i] = res[i - 1] + 1`。\n\n需要用一个数组 t 记录一下当前出现的字符在哪个位置。\n\n```java\n/**\n * @author bingo\n * @since 2018/12/8\n */\n\nclass Solution {\n    /**\n     * 最长不含重复字符的子字符串\n     *\n     * @param s 字符串\n     * @return 最长不重复字符子串\n     */\n    public int longestSubstringWithoutDuplication(String s) {\n        if (s == null || s.length() == 0) {\n            return 0;\n        }\n        char[] chars = s.toCharArray();\n        int[] t = new int[26];\n        for (int i = 0; i < 26; ++i) {\n            t[i] = -1;\n        }\n        t[chars[0] - 'a'] = 0;\n        int n = chars.length;\n        int[] res = new int[n];\n        res[0] = 1;\n        int max = res[0];\n        for (int i = 1; i < n; ++i) {\n            int index = t[chars[i] - 'a'];\n            int d = i - index;\n            res[i] = (index == -1 || d > res[i - 1])\n                    ? res[i - 1] + 1\n                    : d;\n\n            t[chars[i] - 'a'] = i;\n            max = Math.max(max, res[i]);\n        }\n        return max;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（包含多个字符的字符串；只有一个字符的字符串；所有字符都唯一的字符串；所有字符都相同的字符串）；\n2. 特殊输入测试（空字符串）。"
  },
  {
    "path": "docs/jianzhioffer/java/49_UglyNumber.md",
    "content": "## 丑数\n\n### 题目描述\n把只包含质因子2、3和5的数称作丑数（Ugly Number）。例如6、8都是丑数，但14不是，因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。\n\n### 解法1\n由题目可以得知，丑数必定可以整除2、3或者5（除了丑数1之外），也就是说，如果一个数能够被2整除，就连续除以2；能够被3整除，就连续除以3；能够被5整除，就连续除以5；如果最后得到1，那么这个数便是丑数。因此我们可以使用暴力的方式遍历到第N个丑数。\n\n该解法的time complexity为O(count)，比如第1500个丑数为859963392，那么就需要枚举1到859963392\n\n```java\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2019/01/23\n * @description\n */\npublic class Solution {\n    \n    private boolean isUgly(int number){\n        if(number % 2 == 0)\n            number /= 2;\n        if(number % 3 == 0)\n            number /= 3;\n        if(number % 5 == 0)\n            number /= 5;\n        return number == 1;\n    }\n    \n    public int GetUglyNumber_Solution(int index){\n        if(index <= 0)\n            return 0;\n        \n        int number = 0;\n        int count = 0;\n        while(count < index){\n            number++;\n            if(isUgly(number)){\n                count++;\n            }\n        }\n        \n        return number;\n    }\n}\n```\n\n### 解法2\n\n把15以内的丑数列出来：`1、2、3、4、5、6、8、9、10、12、15` ，你会发现新丑数必定是旧丑数乘以因子2、3或者5得来的。所以可以使用一个list来存储已经出现的丑数以此来计算出新的丑数，从而避免对非丑数的计算。\n\n通过维护3个下标i2，i3，i5和它们对应的值m2，m3，m5，每次向list中添加的为m2，m3，m5中的最小值，以此来维护list的有序性。\n\n该解法的time complexity为O(n)，space complexity为O(n)，属于典型的用空间换时间的解决方法。\n\n```java\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2019/01/23\n * @description\n */\npublic class Solution {\n\n    public int GetUglyNumber_Solution(int index) {\n\n        if (index <= 0)\n            return 0;\n\n        List<Integer> reList = new ArrayList<>();\n        // 第一个丑数为1\n        reList.add(1);\n        int i2 = 0, i3 = 0, i5 = 0;\n        while (reList.size() < index) {\n\n            int m2 = reList.get(i2) * 2;\n            int m3 = reList.get(i3) * 3;\n            int m5 = reList.get(i5) * 5;\n\n            // 求出m2、m3、m5中的最小值，该值为加入list的丑数\n            int min = Math.min(m2, Math.min(m3, m5));\n\n            if (m2 == min) {\n                i2++;\n            }\n            if (m3 == min) {\n                i3++;\n            }\n            if (m5 == min) {\n                i5++;\n            }\n\n            reList.add(min);\n        }\n\n        // O(1)\n        return reList.get(reList.size() - 1);\n    }\n}\n```\n\n### 测试用例\n\n1. 功能测试（输入2、3、4、5、6等）。\n2. 特殊输入测试（边界值1；无效输入0）。\n3. 性能测试（输入较大的数字，比如1500）。"
  },
  {
    "path": "docs/jianzhioffer/java/50_01_FirstNotRepeatingChar.md",
    "content": "## 第一个只出现一次的字符\n\n### 题目描述\n在一个字符串(0<=字符串长度<=10000，全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1（需要区分大小写）.\n\n### 解法1\n使用HashMap来统计字符出现的次数，因为字符的多少是固定的（大小写字母一共52个），所以可以认为使用HashMap的空间复杂度为O(1)。该解法时间复杂度为O(n)。\n\n```java\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2019/01/24\n * @description\n */\npublic class Solution {\n    \n    public int FirstNotRepeatingChar(String str) {\n\n        if (str == null || str.length() == 0) {\n            return -1;\n        }\n\n        Map<Character, Integer> characterMap = new HashMap<>();\n        // hashMap is HashTable，search cost O(1)\n        for (int i = 0; i < str.length(); i++) {\n            characterMap.put(str.charAt(i), characterMap.getOrDefault(str.charAt(i), 0) + 1);\n        }\n\n        for (int i = 0; i < str.length(); i++) {\n            if (characterMap.get(str.charAt(i)) == 1) {\n                return i;\n            }\n        }\n\n        return -1;\n    }\n}\n```\n### 测试用例\n\n1. 功能测试（字符串中仅存在只出现一次的字符；字符串中不存在只出现一次的字符；字符串中所有字符都只出现一次）。\n2. 特殊输入测试（字符串为null）。"
  },
  {
    "path": "docs/jianzhioffer/java/50_02_FristCharacterInStream.md",
    "content": "## 字符流中第一个不重复的字符\n\n### 题目描述\n\n请实现一个函数用来找出字符流中第一个只出现一次的字符。例如，当从字符流中只读出前两个字符\"go\"时，第一个只出现一次的字符是\"g\"。当从该字符流中读出前六个字符“google\"时，第一个只出现一次的字符是\"l\"。如果当前字符流没有存在出现一次的字符，返回#字符。\n\n\n### 解法1\n与上一道题的思路是一致的。\n\n```java\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2019/01/25\n * @description\n */\npublic class Solution {\n    \n    private StringBuilder res = new StringBuilder();\n    private Map<Character, Integer> characterMap = new HashMap<>();\n\n    // Insert one char from stringstream\n    public void Insert(char ch) {\n        res.append(ch);\n        characterMap.put(ch, characterMap.getOrDefault(ch, 0) + 1);\n    }\n\n    // return the first appearence once char in current stringstream\n    public char FirstAppearingOnce() {\n\n        for (char c : res.toString().toCharArray()) {\n            if (characterMap.get(c) == 1) {\n                return c;\n            }\n        }\n\n        return '#';\n    }\n}\n```\n### 测试用例\n\n1. 功能测试（读入一个字符；读入多个字符；读入的所有字符都是唯一的；读入的所有字符都是重复出现的）。\n2. 特殊输入测试（读入0个字符）。"
  },
  {
    "path": "docs/jianzhioffer/java/52_FirstCommonNodesInLists.md",
    "content": "## 两个链表的第一个公共结点\n\n### 题目描述\n输入两个链表，找出它们的第一个公共结点。\n\n**样例**\n```\n给出两个链表如下所示：\nA：        a1 → a2\n                   ↘\n                     c1 → c2 → c3\n                   ↗            \nB:     b1 → b2 → b3\n\n输出第一个公共节点c1\n```\n\n### 解法\n先遍历两链表，求出两链表的长度，再求长度差 `|n1 - n2|`。\n\n较长的链表先走 `|n1 - n2|` 步，之后两链表再同时走，首次相遇时的节点即为两链表的第一个公共节点。\n\n\n```java\n/**\n * @author bingo\n * @since 2018/12/8\n */\n\n/**\n * Definition for singly-linked list.\n * public class ListNode {\n *     int val;\n *     ListNode next;\n *     ListNode(int x) {\n *         val = x;\n *         next = null;\n *     }\n * }\n */\nclass Solution {\n\n    /**\n     * 求两链表第一个公共节点\n     *\n     * @param headA 链表A\n     * @param headB 链表B\n     * @return 第一个公共节点\n     */\n    public ListNode findFirstCommonNode(ListNode headA, ListNode headB) {\n        if (headA == null || headB == null) {\n            return null;\n        }\n        int n1 = len(headA), n2 = len(headB);\n        ListNode p1 = headA, p2 = headB;\n        if (n1 > n2) {\n            for (int i = 0; i < n1 - n2; ++i) {\n                p1 = p1.next;\n            }\n        } else if (n1 < n2) {\n            for (int i = 0; i < n2 - n1; ++i) {\n                p2 = p2.next;\n            }\n        }\n        while (p1 != p2 && p1 != null && p2 != null) {\n            p1 = p1.next;\n            p2 = p2.next;\n        }\n        return (p1 == null || p2 == null) ? null : p1;\n    }\n\n    private int len(ListNode head) {\n        int n = 0;\n        ListNode cur = head;\n        while (cur != null) {\n            ++n;\n            cur = cur.next;\n        }\n        return n;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入的两个链表有公共节点；第一个公共节点在链表的中间，第一个公共节点在链表的末尾，第一个公共节点是链表的头节点；输入的两个链表没有公共节点）；\n2. 特殊输入测试（输入的链表头节点是空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/53_01_NumberOfK.md",
    "content": "## 数字在排序数组中出现的次数\n\n### 题目描述\n统计一个数字在排序数组中出现的次数。\n\n例如输入排序数组 `[1, 2, 3, 3, 3, 3, 4, 5]` 和数字 3，由于 3 在这个数组中出现了 4 次，因此输出 4。\n\n**样例**\n\n```\n输入：[1, 2, 3, 3, 3, 3, 4, 5] ,  3\n\n输出：4\n```\n\n### 解法\n找出第一个 k 和最后一个 k 出现的位置。\n\n找第一个 k 时，利用二分法，如果 `nums[m] == k`，判断它的前一个位置是不是也是 k，如果不是，说明这是第一个 k，直接返回。如果是，那么递归在左边查找第一个 k。\n\n找最后一个 k 也同理。\n\n\n```java\n/**\n * @author bingo\n * @since 2018/12/8\n */\n\nclass Solution {\n    /**\n     * 求数字k在排序数组中出现的次数\n     *\n     * @param nums 数组\n     * @param k 数字k\n     * @return k在数组中出现的次数\n     */\n    public int getNumberOfK(int[] nums, int k) {\n        if (nums == null || nums.length == 0) {\n            return 0;\n        }\n        int start = 0, end = nums.length - 1;\n        int first = getFirstK(nums, start, end, k);\n        int last = getLastK(nums, start, end, k);\n        if (first > -1 && last > -1) {\n            return last - first + 1;\n        }\n        return 0;\n    }\n\n    private int getFirstK(int[] nums, int start, int end, int k) {\n        if (start > end) {\n            return -1;\n        }\n        int m = start + ((end - start) >> 1);\n        if (nums[m] == k) {\n            if (m == 0 || (m > 0 && nums[m - 1] != k)) {\n                return m;\n            } else {\n                end = m - 1;\n            }\n        } else {\n            if (nums[m] > k) {\n                end = m - 1;\n            } else {\n                start = m + 1;\n            }\n        }\n        return getFirstK(nums, start, end, k);\n    }\n\n    private int getLastK(int[] nums, int start, int end, int k) {\n        if (start > end) {\n            return -1;\n        }\n        int m = start + ((end - start) >> 1);\n        if (nums[m] == k) {\n            if (m == nums.length - 1 || (m < nums.length - 1 && nums[m + 1] != k)) {\n                return m;\n            } else {\n                start = m + 1;\n            }\n        } else {\n            if (nums[m] > k) {\n                end = m - 1;\n            } else {\n                start = m + 1;\n            }\n        }\n        return getLastK(nums, start, end, k);\n\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（数组中包含要查找的数字；数组中没有要查找的数字；要查找的数字在数组中出现一次/多次）；\n2. 边界值测试（查找数组中的最大值、最小值；数组中只有一个数字）；\n3. 特殊输入测试（表示数组的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/53_02_MissingNumber.md",
    "content": "## 0到n-1中缺失的数字\n\n### 题目描述\n一个长度为 `n-1` 的递增排序数组中的所有数字都是唯一的，并且每个数字都在范围 `0` 到 `n-1` 之内。\n\n在范围 `0` 到 `n-1` 的 `n` 个数字中有且只有一个数字不在该数组中，请找出这个数字。\n\n**样例**\n```\n输入：[0,1,2,4]\n\n输出：3\n```\n\n### 解法\n找出第一个与下标不对应的数字即可。\n\n特殊情况：\n- 下标都对应，那么应该返回 `最后一个数+1`；\n- 缺失的数字是第一个，那么返回 0。\n\n\n```java\n/**\n * @author bingo\n * @since 2018/12/8\n */\n\nclass Solution {\n    /**\n     * 获取0~n-1缺失的数字\n     *\n     * @param nums 数组\n     * @return 缺失的数字\n     */\n    public int getMissingNumber(int[] nums) {\n        if (nums == null || nums.length == 0) {\n            return 0;\n        }\n        int n = nums.length;\n        int start = 0, end = n - 1;\n        while (start <= end) {\n            int mid = start + ((end - start) >> 1);\n            if (nums[mid] != mid) {\n                if (mid == 0 || nums[mid - 1] == mid - 1) {\n                    return mid;\n                }\n                end = mid - 1;\n            } else {\n                start = mid + 1;\n            }\n        }\n        return start == n ? n : -1;\n\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（缺失的数字位于数组的开始、中间或者末尾）；\n2. 边界值测试（数组中只有一个数字 0）；\n3. 特殊输入测试（表示数组的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/53_03_IntegerIdenticalToIndex.md",
    "content": "## 数组中数值和下标相等的元素\n\n### 题目描述\n假设一个单调递增的数组里的每个元素都是整数并且是唯一的。\n\n请编程实现一个函数找出数组中任意一个数值等于其下标的元素。\n\n例如，在数组 `[-3, -1, 1, 3, 5]` 中，数字 3 和它的下标相等。\n\n**样例**\n```\n输入：[-3, -1, 1, 3, 5]\n\n输出：3\n```\n\n**注意**:如果不存在，则返回 -1。\n\n### 解法\n二分法查找。\n- 当前元素等于对应的下标，直接返回该下标；\n- 当前元素大于该下标，在左边查找；\n- 当前元素小于该下标，在右边查找。\n\n\n```java\n/**\n * @author bingo\n * @since 2018/12/10\n */\n\nclass Solution {\n    /**\n     * 找出单调递增数组中数值和下标相等的元素\n     *\n     * @param nums 数组\n     * @return 数值与下标相等的元素\n     */\n    public int getNumberSameAsIndex(int[] nums) {\n        if (nums == null || nums.length == 0) {\n            return -1;\n        }\n        int start = 0, end = nums.length - 1;\n        while (start <= end) {\n            int mid = start + ((end - start) >> 1);\n            if (nums[mid] == mid) {\n                return mid;\n            }\n            if (nums[mid] < mid) {\n                start = mid + 1;\n            } else {\n                end = mid - 1;\n            }\n        }\n        return -1;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（数组中包含或者不包含数值和下标相等的元素）；\n2. 边界值测试（数组中只有一个数字；数值和下标相等的元素位于数组的开头或者结尾）；\n3. 特殊输入测试（表示数组的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/54_KthNodeInBST.md",
    "content": "## 二叉搜索树的第k个结点\n\n### 题目描述\n给定一棵二叉搜索树，请找出其中的第k小的结点。例如， （5，3，7，2，4，6，8）    中，按结点数值大小顺序第三小结点的值为4\n\n### 解法\n因为BST的中序遍历得到的是一个升序的列表，所以在进行中序遍历行进行判断即可。所以该算法的时间复杂度为O(logn)\n\n\n```java\n/**\n * @author mcrwayfun\n * @version 1.0\n * @description\n * @date Created in 2019/1/28\n */\nclass Solution {\n    \n    private int count = 0;\n\n    public TreeNode KthNode(TreeNode pRoot, int k) {\n\n        if (pRoot == null || k == 0) {\n            return null;\n        }\n\n        // 左递归\n        TreeNode retNode = KthNode(pRoot.left, k);\n\n        if (retNode != null) {\n            return retNode;\n        }\n\n        // 符合条件则返回\n        count++;\n        if (count == k) {\n            return pRoot;\n        }\n\n        // 右递归\n        retNode = KthNode(pRoot.right, k);\n        if (retNode != null) {\n            return retNode;\n        }\n\n        return null;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（各种形态不同的二叉搜索树）；\n2. 边界值测试（输入k为0、1、二叉搜索树的结点数、二叉搜索树的结点数+1）；\n3. 特殊输入测试（指向二叉搜索树的节点的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/55_01_TreeDepth.md",
    "content": "## 二叉树的深度\n\n### 题目描述\n输入一棵二叉树的根结点，求该树的深度。\n\n从根结点到叶结点依次经过的结点（含根、叶结点）形成树的一条路径，最长路径的长度为树的深度。\n\n**样例**\n```\n输入：二叉树[8, 12, 2, null, null, 6, 4, null, null, null, null]如下图所示：\n    8\n   / \\\n  12  2\n     / \\\n    6   4\n\n输出：3\n```\n\n### 解法\n递归即可。\n\n\n```java\n/**\n * @author bingo\n * @since 2018/12/10\n */\n\n/**\n * Definition for a binary tree node.\n * public class TreeNode {\n *     int val;\n *     TreeNode left;\n *     TreeNode right;\n *     TreeNode(int x) { val = x; }\n * }\n */\nclass Solution {\n    /**\n     * 求二叉树的深度\n     * \n     * @param root 二叉树根结点\n     * @return 深度\n     */\n    public int treeDepth(TreeNode root) {\n        if (root == null) {\n            return 0;\n        }\n        int lDepth = treeDepth(root.left);\n        int rDepth = treeDepth(root.right);\n        return 1 + Math.max(lDepth, rDepth);\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入普通的二叉树；二叉树中所有节点都没有左/右子树）；\n2. 特殊输入测试（二叉树只有一个节点；二叉树的头节点为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/55_02_BalancedBinaryTree.md",
    "content": "## 平衡二叉树\n\n### 题目描述\n输入一棵二叉树的根结点，判断该树是不是平衡二叉树。\n\n如果某二叉树中任意结点的左右子树的深度相差不超过1，那么它就是一棵平衡二叉树。\n\n**注意：**\n\n- 规定空树也是一棵平衡二叉树。\n\n**样例**\n```\n输入：二叉树[5,7,11,null,null,12,9,null,null,null,null]如下所示，\n    5\n   / \\\n  7  11\n    /  \\\n   12   9\n\n输出：true\n```\n\n### 解法\n#### 解法一\n求每个节点左右孩子的深度，判断该节点是否平衡。\n\n这种方法需要重复遍历节点多次，不推荐。\n\n\n```java\n/**\n * @author bingo\n * @since 2018/12/10\n */\n\n/**\n * Definition for a binary tree node.\n * public class TreeNode {\n *     int val;\n *     TreeNode left;\n *     TreeNode right;\n *     TreeNode(int x) { val = x; }\n * }\n */\nclass Solution {\n    /**\n     * 判断是否是平衡二叉树\n     * \n     * @param root 二叉树根结点\n     * @return 是否是平衡二叉树\n     */\n    public boolean isBalanced(TreeNode root) {\n        if (root == null) {\n            return true;\n        }\n        if (Math.abs(treeDepth(root.left) - treeDepth(root.right)) > 1) {\n            return false;\n        }\n        return isBalanced(root.left) && isBalanced(root.right);\n    }\n\n    private int treeDepth(TreeNode root) {\n        if (root == null) {\n            return 0;\n        }\n        int lDepth = treeDepth(root.left);\n        int rDepth = treeDepth(root.right);\n        return 1 + Math.max(lDepth, rDepth);\n    }\n}\n```\n\n#### 解法二\n\n```java\n/**\n * @author bingo\n * @since 2018/12/10\n */\n\n/**\n * Definition for a binary tree node.\n * public class TreeNode {\n *     int val;\n *     TreeNode left;\n *     TreeNode right;\n *     TreeNode(int x) { val = x; }\n * }\n */\nclass Solution {\n    private boolean isBalanced;\n\n    /**\n     * 判断是否是平衡二叉树\n     *\n     * @param root 二叉树根结点\n     * @return 是否是平衡二叉树\n     */\n    public boolean isBalanced(TreeNode root) {\n        if (root == null) {\n            return true;\n        }\n        isBalanced = true;\n        treeDepth(root);\n        return isBalanced;\n    }\n\n    private int treeDepth(TreeNode root) {\n        if (root == null || !isBalanced) {\n            return 0;\n        }\n        int lDepth = treeDepth(root.left);\n        int rDepth = treeDepth(root.right);\n        if (Math.abs(lDepth - rDepth) > 1) {\n            isBalanced = false;\n        }\n        return 1 + Math.max(lDepth, rDepth);\n\n    }\n}\n```\n\n\n### 测试用例\n1. 功能测试（平衡的二叉树；不是平衡的二叉树；二叉树中所有节点都没有左/右子树）；\n2. 特殊输入测试（二叉树只有一个节点；二叉树的头节点为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/56_01_NumbersAppearOnce.md",
    "content": "## 数组中只出现一次的两个数字\n\n### 题目描述\n一个整型数组里除了两个数字之外，其他的数字都出现了两次。\n\n请写程序找出这两个只出现一次的数字。\n\n你可以假设这两个数字一定存在。\n\n**样例**\n```\n输入：[1,2,3,3,4,4]\n\n输出：[1,2]\n```\n\n### 解法\n如果数组有一个数字出现一次，其它数字都出现两次。那么我们很容易通过异或 `^` 运算求出来。\n\n而现在是有两个数字出现一次，那么我们考虑一下怎么将这两个数字隔开，之后我们对隔开的数组分别进行异或，不就求出来了？\n\n我们先异或，求得的结果是两个不相同的数字异或的结果，结果一定不为 0。那么它的二进制表示中一定有 1。我们根据这个 1 在二进制中出现的位置。将数组划分，这样，两个只出现一次的数字就会被隔开，之后求异或即可。\n\n```java\n/**\n * @author bingo\n * @since 2018/12/10\n */\n\nclass Solution {\n    /**\n     * 求数组中只出现一次的两个数字\n     * \n     * @param nums 数字\n     * @return 两个数字组成的数组\n     */\n    public int[] findNumsAppearOnce(int[] nums) {\n        if (nums == null || nums.length < 2) {\n            return null;\n        }\n        int xorRes = 0;\n        for (int e : nums) {\n            xorRes ^= e;\n        }\n        int[] res = new int[2];\n        int index = indexOf1(xorRes);\n        for (int e : nums) {\n            if (isBit1(e, index)) {\n                res[0] ^= e;\n            } else {\n                res[1] ^= e;\n            }\n        }\n        return res;\n\n\n    }\n\n    private int indexOf1(int val) {\n        int index = 0;\n        while ((val & 1) == 0) {\n            val = val >> 1;\n            ++index;\n        }\n        return index;\n    }\n\n    private boolean isBit1(int val, int index) {\n        val = val >> index;\n        return (val & 1) == 1;\n    }\n}\n```\n\n\n### 测试用例\n1. 功能测试（数组中有多对重复的数字；数组中没有重复的数字）。"
  },
  {
    "path": "docs/jianzhioffer/java/56_02_NumberAppearingOnce.md",
    "content": "## 数组中唯一只出现一次的数字\n\n### 题目描述\n在一个数组中除了一个数字只出现一次之外，其他数字都出现了三次。\n\n请找出那个只出现一次的数字。\n\n你可以假设满足条件的数字一定存在。\n\n**思考题：**\n\n- 如果要求只使用 `O(n)` 的时间和额外 `O(1)` 的空间，该怎么做呢？\n\n### 解法\n分别累加数组中每个元素的二进制中出现的数字，那么出现三次的数字，二进制位上最后累加的结果一定能被 3 整除。不能被 3 整除的位，就属于只出现一次的数字。\n\n```java\n/**\n * @author bingo\n * @since 2018/12/10\n */\n\nclass Solution {\n    /**\n     * 找出数组中只出现一次的数字，其它数字都出现三次\n     *\n     * @param nums 数字\n     * @return 只出现一次的数字\n     */\n    public int findNumberAppearingOnce(int[] nums) {\n        if (nums == null || nums.length == 0) {\n            return 0;\n        }\n        int[] bits = new int[32];\n        int n = nums.length;\n        for (int i = 0; i < n; ++i) {\n            int val = nums[i];\n            for (int j = 0; j < 32; ++j) {\n                bits[j] += (val & 1);\n                val = val >> 1;\n            }\n        }\n        int res = 0;\n        for (int i = 0; i < 32; ++i) {\n            if (bits[i] % 3 != 0) {\n                res += Math.pow(2, i);\n            }\n        }\n        return res;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（唯一只出现一次的数字分别是 0、正数、负数；重复出现三次的数字分别是 0、正数、负数）。"
  },
  {
    "path": "docs/jianzhioffer/java/57_01_TwoNumbersWithSum.md",
    "content": "## 和为S的两个数字\n\n### 题目描述\n输入一个递增排序的数组和一个数字S，在数组中查找两个数，使得他们的和正好是S，如果有多对数字的和等于S，输出两个数的乘积最小的。ps：对应每个测试案例，输出两个数，小的先输出。\n\n### 解法\n定义两个指针，start指向数组头，end指向数组末尾。如果：\n\n- `sum == array[start] + array[end]`，则返回结果\n- `sum > array[start] + array[end]`，则start++，因为数组是递增的，所以从小数右边找一个大数与 `array[end]` 求和再次判断\n- 否则 end--\n\n```java\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2019/02/02\n * @description\n */\npublic class Solution {\n    \n    public ArrayList<Integer> FindNumbersWithSum(int[] array, int sum) {\n\n        ArrayList<Integer> reList = new ArrayList<>();\n\n        if (array == null || array.length < 2 || sum <= array[0]) {\n            return reList;\n        }\n\n        int start = 0;\n        int end = array.length - 1;\n\n        while (start < end) {\n\n            int curSum = array[start] + array[end];\n            if (curSum == sum) {\n                reList.add(array[start]);\n                reList.add(array[end]);\n                return reList;\n            } else if (curSum < sum) {\n                start++;\n            } else {\n                end--;\n            }\n        }\n\n        // 查无\n        return reList;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（数组中存在和为 s 的两个数；数组中不存在和为 s 的两个数）；\n2. 特殊输入测试（表示数组的指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/57_02_ContinuousSquenceWithSum.md",
    "content": "## 和为S的连续正数序列\n\n### 题目描述\n输入一个正数 s，打印出所有和为 s 的连续正数序列（至少含有两个数）。\n\n例如输入 15，由于 `1+2+3+4+5=4+5+6=7+8=15`，所以结果打印出 3 个连续序列 1～5、4～6 和 7～8。\n\n**样例**\n```\n输入：15\n\n输出：[[1,2,3,4,5],[4,5,6],[7,8]]\n```\n\n### 解法\n这道题同样利用两个指针left和right，将(1,2)作为初始序列。当序列和大于所求值，则left向前走，把最小的数排除了；当序列和小于所求值，则right向前走，把一个更大的数包进序列中；如果序列和等于所求值，则求值区间[left,right]中的所有数并加入到列表中，并且right向前走，把一个更大的值包入序列中。循环直到 `left < (sum + 1)/2`  。\n\n这道题的time complexity为O(n^2)，space complexity为O(1)\n\n```java\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2019/02/03\n * @description\n */\npublic class Solution {\n    \n    public List<List<Integer>> findContinuousSequence(int sum) {\n\n        List<List<Integer>> reList = new ArrayList<>();\n\n        if (sum < 3) {\n            return reList;\n        }\n\n        int left = 1;\n        int right = 2;\n        int mid = (sum + 1) / 2;\n        int curSum = left + right;\n\n        // left小于sum一半即可(1/2n)\n        while (left < mid) {\n\n            // 等与sum则加入列表中(2~1/2n)\n            if (curSum == sum) {\n                reList.add(getListFromleftToright(left, right));\n                // right增加并重新寻找序列\n                right++;\n                curSum += right;\n            } else if (curSum > sum) {\n                curSum -= left;\n                left++;\n            } else {\n                right++;\n                curSum += right;\n            }\n        }\n\n        return reList;\n    }\n\n    private List<Integer> getListFromleftToright(int left, int right) {\n\n        List<Integer> tempList = new ArrayList<>();\n        for (int i = left; i <= right; i++) {\n            tempList.add(i);\n        }\n\n        return tempList;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（存在和为 s 的连续序列，如 9、100 等；不存在和为 s 的连续序列，如 4、0 等）；\n2. 边界值测试（连续序列的最小和 3）。"
  },
  {
    "path": "docs/jianzhioffer/java/58_01_ReverseWordsInSentence.md",
    "content": "##  翻转单词顺序\n\n### 题目描述\n输入一个英文句子，翻转句子中单词的顺序，但单词内字符的顺序不变。\n\n为简单起见，标点符号和普通字母一样处理。\n\n例如输入字符串 `\"I am a student.\"`，则输出 `\"student. a am I\"`。\n\n**样例**\n```\n输入：\"I am a student.\"\n\n输出：\"student. a am I\"\n```\n\n### 解法\n先对字符串按空格切割成数组，再逆序数组后，最后将元素拼接并返回。\n\n```java\n/**\n * @author bingo\n * @since 2018/12/12\n */\n\nclass Solution {\n    /**\n     * 翻转单词\n     * \n     * @param s 字符串\n     * @return 翻转后的字符串\n     */\n    public String reverseWords(String s) {\n        if (s == null || s.length() == 0 || s.trim().equals(\"\")) {\n            return s;\n        }\n\n        String[] arr = s.split(\" \");\n        int p = 0, q = arr.length - 1;\n        while (p < q) {\n            swap(arr, p++, q--);\n        }\n        return String.join(\" \", arr);\n    }\n    private void swap(String[] arr, int p, int q) {\n        String t = arr[p];\n        arr[p] = arr[q];\n        arr[q] = t;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（句子中有多个单词；句子中只有一个单词）；\n2. 特殊输入测试（字符串指针为空指针；字符串的内容为空；字符串中只有空格）。"
  },
  {
    "path": "docs/jianzhioffer/java/58_02_LeftRotateString.md",
    "content": "## 左旋转字符串\n\n### 题目描述\n字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。\n\n请定义一个函数实现字符串左旋转操作的功能。\n\n比如输入字符串 `\"abcdefg\"` 和数字 2，该函数将返回左旋转 2 位得到的结果 `\"cdefgab\"`。\n\n**注意：**\n\n- 数据保证 n 小于等于输入字符串的长度。\n\n**样例**\n```\n输入：\"abcdefg\" , n=2\n\n输出：\"cdefgab\"\n```\n\n### 解法\n先翻转前 n 个字符，再翻转后面的字符，最后整体翻转。\n\n```java\n/**\n * @author bingo\n * @since 2018/12/12\n */\n\nclass Solution {\n\n    /**\n     * 左旋转字符串\n     * \n     * @param str 字符串\n     * @param n 左旋的位数\n     * @return 旋转后的字符串\n     */\n    public String leftRotateString(String str, int n) {\n        if (str == null || n < 1 || n > str.length()) {\n            return str;\n        }\n        char[] chars = str.toCharArray();\n        int len = chars.length;\n        reverse(chars, 0, n - 1);\n        reverse(chars, n, len - 1);\n        reverse(chars, 0, len - 1);\n        return new String(chars);\n    }\n\n    private void reverse(char[] chars, int p, int q) {\n        while (p < q) {\n            swap(chars, p++, q--);\n        }\n    }\n\n    private void swap(char[] chars, int p, int q) {\n        char t = chars[p];\n        chars[p] = chars[q];\n        chars[q] = t;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（把长度为 n 的字符串左旋转 0/1/2/n-1/n/n+1 个字符）；\n2. 特殊输入测试（字符串指针为空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/59_01_MaxInSlidingWindow.md",
    "content": "## 滑动窗口的最大值\n\n### 题目描述\n给定一个数组和滑动窗口的大小，请找出所有滑动窗口里的最大值。\n\n例如，如果输入数组 `[2, 3, 4, 2, 6, 2, 5, 1]` 及滑动窗口的大小 3,那么一共存在 6 个滑动窗口，它们的最大值分别为 `[4, 4, 6, 6, 6, 5]`。\n\n**注意：**\n\n- 数据保证 k 大于 0，且 k 小于等于数组长度。\n\n**样例**\n\n```\n输入：[2, 3, 4, 2, 6, 2, 5, 1] , k=3\n\n输出: [4, 4, 6, 6, 6, 5]\n```\n\n### 解法\n使用一个双端队列，保证队首存放的是窗口最大值的下标。遍历数组，\n\n1. 队尾元素比要入队的元素小，则把其移除（因为不可能成为窗口最大值）。\n2. 队首下标对应的元素不在窗口内（即窗口最大值），将其从队列中移除。\n3. 把每次滑动值的下标加入队列中（经过步骤1、2，此时加入队列的下标要么是当前窗口最大值的下标，要么是小于窗口最大值的下标）。\n4. 滑动窗口的首地址i大于size就写入窗口最大值。\n\ntime complexity:O(n)\n\nspace complexity:O(k) , k is the size\n\n```java\n/**\n * @author mcrwayfun\n * @version v1.0\n * @date Created in 2019/02/05\n * @description\n */\nclass Solution {\n    \n    public ArrayList<Integer> maxInWindows(int[] num, int size) {\n\n        ArrayList<Integer> reList = new ArrayList<>();\n        if (num == null || num.length < size || size < 1) {\n            return reList;\n        }\n\n        Deque<Integer> deque = new LinkedList<>();\n        for (int i = 0; i < num.length; i++) {\n\n            // 队尾元素比要入队的元素小，则把其移除（因为不可能成为窗口最大值）\n            while (!deque.isEmpty() && num[deque.getLast()] <= num[i]) {\n                deque.pollLast();\n            }\n            // 队首下标对应的元素不在窗口内（即窗口最大值），将其从队列中移除\n            while (!deque.isEmpty() && (i - deque.getFirst() + 1 > size)) {\n                deque.pollFirst();\n            }\n            // 把每次滑动的值加入到队列中\n            deque.add(i);\n            // 滑动窗口的首地址i大于size就写入窗口最大值\n            if (!deque.isEmpty() && i + 1 >= size) {\n                reList.add(num[deque.getFirst()]);\n            }\n        }\n\n        return reList;\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（输入数组的数字大小无序；输入数组的数字单调递增；输入数组的数字单调递减）；\n2. 边界值测试（滑动窗口的大小为 0、1、等于输入数组的长度、大于输入数组的长度）；\n3. 特殊输入测试（输入数组为空）。"
  },
  {
    "path": "docs/jianzhioffer/java/61_ContinousCards.md",
    "content": "## 扑克牌的顺子\n\n### 题目描述\n从扑克牌中随机抽 `5` 张牌，判断是不是一个顺子，即这5张牌是不是连续的。\n\n`2～10` 为数字本身，`A` 为`1`，`J` 为 `11`，`Q` 为 `12`，`K` 为 `13`，大小王可以看做任意数字。\n\n为了方便，大小王均以 `0` 来表示，并且假设这副牌中大小王均有两张。\n\n**样例1**\n```\n输入：[8,9,10,11,12]\n\n输出：true\n```\n\n**样例2**\n```\n输入：[0,8,9,11,12]\n\n输出：true\n```\n\n### 解法\n- 对数组排序；\n- 计算出 0 的个数 `zeroCount`；\n- 从第一个不是 0 的数字开始遍历，与后一个数字比较，如果相等，直接返回 `false`；否则累计 `gap`；\n- 判断 `zeroCount` 是否大于等于 `gap`。\n\n\n```java\nimport java.util.Arrays;\n\n/**\n * @author bingo\n * @since 2018/12/12\n */\n\nclass Solution {\n\n    /**\n     * 判断是否是连续的数字\n     *\n     * @param numbers 数组\n     * @return 是否是顺子\n     */\n    public boolean isContinuous(int [] numbers) {\n        if (numbers == null || numbers.length == 0) {\n            return false;\n        }\n        int zeroCount = 0;\n        Arrays.sort(numbers);\n        for (int e : numbers) {\n            if (e > 0) {\n                break;\n            }\n            ++zeroCount;\n        }\n\n        int p = zeroCount, q = p + 1, n = numbers.length;\n        int gap = 0;\n        while (q < n) {\n            if (numbers[p] == numbers[q]) {\n                return false;\n            }\n            gap += (numbers[q] - numbers[p] - 1);\n            p = q;\n            ++q;\n        }\n        return gap <= zeroCount;\n\n    }\n}\n```\n\n### 测试用例\n1. 功能测试（抽出的牌中有一个或者多个大、小王；抽出的牌中没有大、小王；抽出的牌中有对子）；\n2. 特殊输入测试（输入空指针）。"
  },
  {
    "path": "docs/jianzhioffer/java/README.md",
    "content": "# 剑指 Offer Java 题解\n\n> 来源：[《剑指 Offer》 Java 版实现](https://github.com/doocs/coding-interview)\n\n| # | Title |\n|---|---|\n| 03_01 | [Find Duplication In Array](/docs/剑指offer/Java/03_01_DuplicationInArray) |\n| 03_02 | [Find Duplication In Array II](/docs/剑指offer/Java/03_02_DuplicationInArrayNoEdit) |\n| 04 | [Find In Partially Sorted Matrix](/docs/剑指offer/Java/04_FindInPartiallySortedMatrix) |\n| 05 | [Replace Spaces](/docs/剑指offer/Java/05_ReplaceSpaces) |\n| 06 | [Print List In Reversed Order](/docs/剑指offer/Java/06_PrintListInReversedOrder) |\n| 07 | [Construct Binary Tree](/docs/剑指offer/Java/07_ConstructBinaryTree) |\n| 08 | [Next Node In Binary Trees](/docs/剑指offer/Java/08_NextNodeInBinaryTrees) |\n| 09_01 | [Queue With Two Stacks](/docs/剑指offer/Java/09_01_QueueWithTwoStacks) |\n| 09_02 | [Stack With Two Queues](/docs/剑指offer/Java/09_02_StackWithTwoQueues) |\n| 10_01 | [Fibonacci](/docs/剑指offer/Java/10_01_Fibonacci) |\n| 10_02 | [Jump Floor](/docs/剑指offer/Java/10_02_JumpFloor) |\n| 10_03 | [Jump Floor II](/docs/剑指offer/Java/10_03_JumpFloorII) |\n| 10_04 | [Rect Cover](/docs/剑指offer/Java/10_04_RectCover) |\n| 11 | [Min Number In Rotated Array](/docs/剑指offer/Java/11_MinNumberInRotatedArray) |\n| 12 | [String Path In Matrix](/docs/剑指offer/Java/12_StringPathInMatrix) |\n| 13 | [Robot Move](/docs/剑指offer/Java/13_RobotMove) |\n| 14 | [Cutting Rope](/docs/剑指offer/Java/14_CuttingRope) |\n| 15 | [Number Of 1 In Binary](/docs/剑指offer/Java/15_NumberOf1InBinary) |\n| 16 | [Power](/docs/剑指offer/Java/16_Power) |\n| 17 | [Print 1 To Max Of N Digits](/docs/剑指offer/Java/17_Print1ToMaxOfNDigits) |\n| 18_01 | [Delete Node In List](/docs/剑指offer/Java/18_01_DeleteNodeInList) |\n| 18_02 | [Delete Duplicated Node](/docs/剑指offer/Java/18_02_DeleteDuplicatedNode) |\n| 19 | [Regular Expressions Matching](/docs/剑指offer/Java/19_RegularExpressionsMatching) |\n| 20 | [Numeric Strings](/docs/剑指offer/Java/20_NumericStrings) |\n| 21 | [Reorder Array](/docs/剑指offer/Java/21_ReorderArray) |\n| 22 | [Kth Node From End](/docs/剑指offer/Java/22_KthNodeFromEnd) |\n| 23 | [Entry Node In List Loop](/docs/剑指offer/Java/23_EntryNodeInListLoop) |\n| 24 | [Reverse List](/docs/剑指offer/Java/24_ReverseList) |\n| 25 | [Merge Sorted Lists](/docs/剑指offer/Java/25_MergeSortedLists) |\n| 26 | [Substructure In Tree](/docs/剑指offer/Java/26_SubstructureInTree) |\n| 27 | [Mirror Of Binary Tree](/docs/剑指offer/Java/27_MirrorOfBinaryTree) |\n| 28 | [Symmetrical Binary Tree](/docs/剑指offer/Java/28_SymmetricalBinaryTree) |\n| 29 | [Print Matrix](/docs/剑指offer/Java/29_PrintMatrix) |\n| 30 | [Min In Stack](/docs/剑指offer/Java/30_MinInStack) |\n| 31 | [Stack Push Pop Order](/docs/剑指offer/Java/31_StackPushPopOrder) |\n| 32_01 | [Print Tree From Top To Bottom](/docs/剑指offer/Java/32_01_PrintTreeFromTopToBottom) |\n| 32_02 | [Print Trees In Lines](/docs/剑指offer/Java/32_02_PrintTreesInLines) |\n| 32_03 | [Print Trees In Zigzag](/docs/剑指offer/Java/32_03_PrintTreesInZigzag) |\n| 33 | [Squence Of BST](/docs/剑指offer/Java/33_SquenceOfBST) |\n| 34 | [Path In Tree](/docs/剑指offer/Java/34_PathInTree) |\n| 35 | [Copy Complex List](/docs/剑指offer/Java/35_CopyComplexList) |\n| 36 | [Convert Binary Search Tree](/docs/剑指offer/Java/36_ConvertBinarySearchTree) |\n| 39 | [More Than Half Number](/docs/剑指offer/Java/39_MoreThanHalfNumber) |\n| 40 | [K Least Numbers](/docs/剑指offer/Java/40_KLeastNumbers) |\n| 41 | [Stream Median](/docs/剑指offer/Java/41_StreamMedian) |\n| 42 | [Greatest Sum Of Subarrays](/docs/剑指offer/Java/42_GreatestSumOfSubarrays) |\n| 44 | [Digits In Sequence](/docs/剑指offer/Java/44_DigitsInSequence) |\n| 45 | [Sort Array For Min Number](/docs/剑指offer/Java/45_SortArrayForMinNumber) |\n| 46 | [Translate Numbers To Strings](/docs/剑指offer/Java/46_TranslateNumbersToStrings) |\n| 47 | [Max Value Of Gifts](/docs/剑指offer/Java/47_MaxValueOfGifts) |\n| 48 | [Longest Substring Without Dup](/docs/剑指offer/Java/48_LongestSubstringWithoutDup) |\n| 52 | [First Common Nodes In Lists](/docs/剑指offer/Java/52_FirstCommonNodesInLists) |\n| 53_01 | [Number Of K](/docs/剑指offer/Java/53_01_NumberOfK) |\n| 53_02 | [Missing Number](/docs/剑指offer/Java/53_02_MissingNumber) |\n| 53_03 | [Integer Identical To Index](/docs/剑指offer/Java/53_03_IntegerIdenticalToIndex) |\n| 55_01 | [Tree Depth](/docs/剑指offer/Java/55_01_TreeDepth) |\n| 55_02 | [Balanced Binary Tree](/docs/剑指offer/Java/55_02_BalancedBinaryTree) |\n| 56_01 | [Numbers Appear Once](/docs/剑指offer/Java/56_01_NumbersAppearOnce) |\n| 56_02 | [Number Appearing Once](/docs/剑指offer/Java/56_02_NumberAppearingOnce) |\n| 57_01 | [Two Numbers With Sum](/docs/剑指offer/Java/57_01_TwoNumbersWithSum) |\n| 57_02 | [Continuous Squence With Sum](/docs/剑指offer/Java/57_02_ContinuousSquenceWithSum) |\n| 58_01 | [Reverse Words In Sentence](/docs/剑指offer/Java/58_01_ReverseWordsInSentence) |\n| 58_02 | [Left Rotate String](/docs/剑指offer/Java/58_02_LeftRotateString) |\n| 59_01 | [Max In Sliding Window](/docs/剑指offer/Java/59_01_MaxInSlidingWindow) |\n| 61 | [Continous Cards](/docs/剑指offer/Java/61_ContinousCards) |\n"
  },
  {
    "path": "docs/jianzhioffer/java/SUMMARY.md",
    "content": "+   [剑指 Offer Java 题解](README.md)\n+   [找出数组中重复的数字](03_01_DuplicationInArray.md)\n+   [不修改数组找出重复的数字](03_02_DuplicationInArrayNoEdit.md)\n+   [二维数组中的查找](04_FindInPartiallySortedMatrix.md)\n+   [替换空格](05_ReplaceSpaces.md)\n+   [从尾到头打印链表](06_PrintListInReversedOrder.md)\n+   [重建二叉树](07_ConstructBinaryTree.md)\n+   [二叉树的下一个结点](08_NextNodeInBinaryTrees.md)\n+   [用两个栈实现队列](09_01_QueueWithTwoStacks.md)\n+   [用两个队列实现栈](09_02_StackWithTwoQueues.md)\n+   [斐波那契数列](10_01_Fibonacci.md)\n+   [跳台阶](10_02_JumpFloor.md)\n+   [变态跳台阶](10_03_JumpFloorII.md)\n+   [矩形覆盖](10_04_RectCover.md)\n+   [旋转数组的最小数字](11_MinNumberInRotatedArray.md)\n+   [矩阵中的路径](12_StringPathInMatrix.md)\n+   [机器人的移动范围](13_RobotMove.md)\n+   [剪绳子](14_CuttingRope.md)\n+   [二进制中 1 的个数](15_NumberOf1InBinary.md)\n+   [数值的整数次方](16_Power.md)\n+   [打印从 1 到最大的 n 位数](17_Print1ToMaxOfNDigits.md)\n+   [在O(1)时间内删除链表节点](18_01_DeleteNodeInList.md)\n+   [删除链表中重复的节点](18_02_DeleteDuplicatedNode.md)\n+   [正则表达式匹配](19_RegularExpressionsMatching.md)\n+   [表示数值的字符串](20_NumericStrings.md)\n+   [调整数组顺序使奇数位于偶数前面](21_ReorderArray.md)\n+   [链表中倒数第k个结点](22_KthNodeFromEnd.md)\n+   [链表中环的入口结点](23_EntryNodeInListLoop.md)\n+   [反转链表](24_ReverseList.md)\n+   [合并两个排序的链表](25_MergeSortedLists.md)\n+   [树的子结构](26_SubstructureInTree.md)\n+   [二叉树的镜像](27_MirrorOfBinaryTree.md)\n+   [对称的二叉树](28_SymmetricalBinaryTree.md)\n+   [顺时针打印矩阵](29_PrintMatrix.md)\n+   [包含min函数的栈](30_MinInStack.md)\n+   [栈的压入、弹出序列](31_StackPushPopOrder.md)\n+   [不分行从上到下打印二叉树](32_01_PrintTreeFromTopToBottom.md)\n+   [把二叉树打印成多行](32_02_PrintTreesInLines.md)\n+   [按之字形打印二叉树](32_03_PrintTreesInZigzag.md)\n+   [二叉搜索树的后序遍历序列](33_SquenceOfBST.md)\n+   [二叉树中和为某一值的路径](34_PathInTree.md)\n+   [复杂链表的复制](35_CopyComplexList.md)\n+   [二叉搜索树与双向链表](36_ConvertBinarySearchTree.md)\n+   [序列化二叉树](37_SerializeBinaryTrees.md)\n+   [字符串的排列](38_StringPermutation.md)\n+   [数组中出现次数超过一半的数字](39_MoreThanHalfNumber.md)\n+   [获取数组中最小的k个数](40_KLeastNumbers.md)\n+   [数据流中的中位数](41_StreamMedian.md)\n+   [连续子数组的最大和](42_GreatestSumOfSubarrays.md)\n+   [整数中1出现的次数](43_NumberOf1.md)\n+   [数字序列中某一位的数字](44_DigitsInSequence.md)\n+   [把数组排成最小的数](45_SortArrayForMinNumber.md)\n+   [把数字翻译成字符串](46_TranslateNumbersToStrings.md)\n+   [礼物的最大价值](47_MaxValueOfGifts.md)\n+   [最长不含重复字符的子字符串](48_LongestSubstringWithoutDup.md)\n+   [丑数](49_UglyNumber.md)\n+   [第一个只出现一次的字符](50_01_FirstNotRepeatingChar.md)\n+   [字符流中第一个不重复的字符](50_02_FristCharacterInStream.md)\n+   [两个链表的第一个公共结点](52_FirstCommonNodesInLists.md)\n+   [数字在排序数组中出现的次数](53_01_NumberOfK.md)\n+   [0到n-1中缺失的数字](53_02_MissingNumber.md)\n+   [数组中数值和下标相等的元素](53_03_IntegerIdenticalToIndex.md)\n+   [二叉搜索树的第k个结点](54_KthNodeInBST.md)\n+   [二叉树的深度](55_01_TreeDepth.md)\n+   [平衡二叉树](55_02_BalancedBinaryTree.md)\n+   [数组中只出现一次的两个数字](56_01_NumbersAppearOnce.md)\n+   [数组中唯一只出现一次的数字](56_02_NumberAppearingOnce.md)\n+   [和为S的两个数字](57_01_TwoNumbersWithSum.md)\n+   [和为S的连续正数序列](57_02_ContinuousSquenceWithSum.md)\n+   [翻转单词顺序](58_01_ReverseWordsInSentence.md)\n+   [左旋转字符串](58_02_LeftRotateString.md)\n+   [滑动窗口的最大值](59_01_MaxInSlidingWindow.md)\n+   [扑克牌的顺子](61_ContinousCards.md)\n"
  },
  {
    "path": "docs/leetcode/cpp/0001._Two_Sum.md",
    "content": "# 1. Two Sum\n **<font color=red>难度: Easy</font>**\n ## 刷题内容\n > 原题连接\n * https://leetcode.com/problems/two-sum\n* https://leetcode-cn.com/problems/two-sum\n > 内容描述\n ```\n给定 nums = [2, 7, 11, 15], target = 9\n 因为 nums[0] + nums[1] = 2 + 7 = 9\n所以返回 [0, 1]\n```\n ## 解题方案\n > 思路 1\n******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)******\n 采用双指针法，先将数组排序形成了一个有序的区间，指针i，j分别指向头尾，\n```\n当 nums1[i] + nums[j] > traget 时，j--，\nnums[i] + nums[j] < target 时，i++，\n直到 nums[i] + nums[j] == target\n```\n```cpp\nclass Solution \n{\npublic:\n    vector<int> twoSum(vector<int>& nums, int target)\n    {\n        vector<pair<int,int> > nums1;\n        for(int i = 0;i < nums.size();++i)\n            nums1.push_back(make_pair(nums[i],i));\n        sort(nums1.begin(),nums1.end());\n        int i = 0,j = nums1.size() - 1;\n        vector<int> ret;\n        while(i < j)\n        {\n            if(nums1[i].first + nums1[j].first == target)\n            {\n                ret.push_back(nums1[i].second);\n                ret.push_back(nums1[j].second);\n                return ret;\n            }\n            nums1[i].first +nums1[j].first < target ? ++i : --j;\n        }\n    }\n};\n```\n> 思路 2\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n c++中提供了 unordered_map 的容器，unordered_map 中的元素没有按照它们的键值或映射值的任何顺序排序，\n而是根据它们的散列值组织成桶以允许通过它们的键值直接快速访问单个元素（具有常数平均时间复杂度）\n将先出现的元素储存在 unorder_map 中，遍历数组，每次查找 target - nums[i] 是否存在即可。\n ```cpp\nclass Solution \n{\npublic:\n    vector<int> twoSum(vector<int>& nums, int target)\n    {\n        unordered_map<int, int> m;\n        vector<int> res;\n        for (int i = 0; i < nums.size(); ++i) {\n            m[nums[i]] = i;\n        }\n        for (int i = 0; i < nums.size(); ++i) {\n            int t = target - nums[i];\n            if (m.count(t) && m[t] != i) {\n                res.push_back(i);\n                res.push_back(m[t]);\n                break;\n            }\n        }\n        return res;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0002._Add_Two_Numbers.md",
    "content": "# 2. Add Two Numbers\n\n**<font color=red>难度:Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/add-two-numbers\n\n> 内容描述\n\n```\n给定两个链表代表两个非负数，求这两个数的和\n(2 -> 4 -> 3) + (5 -> 6 -> 4)\n因为 342 + 465 = 807\n所以返回 7 -> 0 -> 8\n```\n\n## 解题方案\n\n> 思路\n\n\n这题的的关键在于链表的数储存是倒序的，因此只要从链表头相加，再将所得数挨个储存即可，但是要注意两数相加有可能大于10要进一位。\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {\n\tListNode* current;\n\tListNode* ret = nullptr;\n\tint num = 0;\n\twhile(l1 && l2)\n\t{\n\t\tint sum = l1 ->val + l2 ->val + num;\n\t\tListNode* node = new ListNode(sum % 10);\n\t\tnum = sum / 10;\n\t\tret ? current ->next = node : ret = node;\n\t\tcurrent = node;\n\t\tl1 = l1 ->next;\n\t\tl2 = l2 ->next;\n\t}\n\tif(l2)\n\t\tl1 = l2;\n\twhile(l1)\n\t{\n\t\tint sum = num + l1 ->val;\n\t\tListNode* node = new ListNode(sum % 10);\n\t\tnum = sum / 10;\n\t\tcurrent ->next = node;\n\t\tcurrent = node;\n\t\tl1 = l1 ->next;\n\t}\n\tif(num)\n\t{\n\t\tListNode* node = new ListNode(num);\n\t\tcurrent ->next = node;\n\t}\n\treturn ret;\n\t}\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0003._Longest_Substring_Without_Repeating_Characters.md",
    "content": "# 3. Longest Substring Without Repeating Characters\n\n**<font color=red>难度:Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/longest-substring-without-repeating-characters\n\n> 内容描述\n\n```\n\nGiven a string, find the length of the longest substring without repeating characters.\n\nExample 1:\n\nInput: \"abcabcbb\"\nOutput: 3 \nExplanation: The answer is \"abc\", with the length of 3. \nExample 2:\n\nInput: \"bbbbb\"\nOutput: 1\nExplanation: The answer is \"b\", with the length of 1.\nExample 3:\n\nInput: \"pwwkew\"\nOutput: 3\nExplanation: The answer is \"wke\", with the length of 3. \n             Note that the answer must be a substring, \"pwke\" is a subsequence and not a substring.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)******\n\n\n用 map储存 key为字符，value 为这个字符的位置，我们可以维护一个子字符串(无重复字符)，记录它的起始位置，遍历 string s 当无法在map中找到字符或者小于子字符串的起始位置，就是没有在这个字符串中出现，反之则字符重复，不过 map查找为 O(lgn)，因此总的时间复杂度为O(NlgN)\n```cpp\nclass Solution {\npublic:\n    int lengthOfLongestSubstring(string s) {\n    map<int,int> m;\n    int beg = 0,length = s.length(),ll = 0,ans = 0;\n    for(int i = 0;i < length;++i)\n    {\n        if(m.find(s[i]) == m.end() || m[s[i]] < beg)\n            ll++;\n        else\n        {\n            int pos = m[s[i]];\n            ans = max(ll,ans);\n            ll = ll - (pos - beg);\n            beg = pos + 1;\n        }\n        m[s[i]] = i;\n    }\n    ans = max(ans,ll);\n    return ans;\n    }\n};\n```\n\n> 思路 2\n******- 时间复杂度: O(NlgN)******- 空间复杂度: O(1)******\n\n这个思路和上面差不多，用到了一个小窍门，因为储存的是字符，char为8位，因此能储存的最大数为256，这样空间复杂度就为O(1)\n\n```cpp\nclass Solution {\npublic:\n    int lengthOfLongestSubstring(string s) {\n        int m[256];\n    for(int i = 0;i < 256;++i)\n        m[i] = -1;\n    int beg = 0,length = s.length(),ll = 0,ans = 0;\n    for(int i = 0;i < length;++i)\n    {\n        if(m[s[i]] < beg)\n            ll++;\n        else\n        {\n            int pos = m[s[i]];\n            ans = max(ll,ans);\n            ll = ll - (pos - beg);\n            beg = pos + 1;\n        }\n        m[s[i]] = i;\n    }\n    ans = max(ans,ll);\n    return ans;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0004._Median_of_Two_Sorted_Arrays.md",
    "content": "# 004. Median of Two Sorted Arrays\n\n**<font color=red>难度Hard<font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/median-of-two-sorted-arrays/submissions/\n\n> 内容描述\n\n```\nThere are two sorted arrays nums1 and nums2 of size m and n respectively.\n\nFind the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).\n\nYou may assume nums1 and nums2 cannot be both empty.\n\nExample 1:\n\nnums1 = [1, 3]\nnums2 = [2]\n\nThe median is 2.0\nExample 2:\n\nnums1 = [1, 2]\nnums2 = [3, 4]\n\nThe median is (2 + 3)/2 = 2.5\n```\n\n> 思路1\n******- 时间复杂度: O(n + m)******- 空间复杂度: O(1)******\n\n直接用暴利搜索，类似与归并两个有序的数组。遍历两个数组，当总长度等于（m+n）/ 2，注意区分总长度奇数和偶数\n```cpp\nclass Solution {\npublic:\n    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {\n        int temp = (nums1.size() + nums2.size()) / 2,count1 = 0,i = 0,j = 0,current,pre;\n        while(i < nums1.size() && j < nums2.size() && count1 <= temp)\n        {\n            pre = current;\n            if(nums1[i] > nums2[j])\n                current = nums2[j++];\n            else\n                current = nums1[i++];\n            ++count1;\n        }\n        if(count1 <= temp)\n        {\n            if(i < nums1.size())\n                while(count1 <= temp)\n                {\n                    pre = current;\n                    current = nums1[i++];\n                    ++count1;\n                }\n            else\n                while(count1 <= temp)\n                {\n                    pre = current;\n                    current = nums2[j++];\n                    ++count1;\n                }\n        }\n        if((nums1.size() + nums2.size()) % 2)\n            return current;\n        double ans = (current + pre) / 2.0;\n        return ans;\n    }\n};\n```\n> 思路2\n******- 时间复杂度: O(lg(min(n.m)))******- 空间复杂度: O(1)******\n\n我们可以通过二分查找优化算法，利用中位数的定义，将两个数组划分为左右两个部分，nums1左半部分加nums2左半部分等于nums1右半部分加nums2的右半部分，如果总长度为偶数，那么nums1左半部分加nums2左半部分等于nums1右半部分加nums2的右半部分加1。并且```max(nums1[i],nums2[j]) <= max(nums1[i + 1],nums2[j + 1])```，接下来我们只要二分查找找i，并且要注意边界情况\n\n```cpp\nclass Solution {\npublic:\n    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {\n        int m = nums1.size(),n = nums2.size(),sum = m + n;\n        if(!nums1.size())\n            return sum % 2 ? nums2[sum / 2] : (nums2[sum /2] + nums2[sum / 2 - 1]) / 2.0;\n        if(!nums2.size())\n            return sum % 2 ? nums1[sum / 2] : (nums1[sum /2] + nums1[sum / 2 - 1]) / 2.0;\n        if(m > n)\n            return findMedianSortedArrays(nums2,nums1);\n        int l = 0,r = m - 1;\n        while(l < r)\n        {\n            int mid = (l + r) / 2;\n            int j = (sum + 1) / 2 - mid - 2;\n            int min1 = max(nums1[mid],nums2[j]),max1 = min(nums1[mid + 1],nums2[j + 1]);\n            if(min1 <= max1)\n                return sum % 2 ? min1 : (min1 + max1) / 2.0;\n            else if(nums1[mid] > nums2[j])\n                r = mid - 1;\n            else\n                l = mid + 1;\n        }\n        int j = (sum + 1) / 2 - l - 2;\n        int min1,max1;\n        if(j < 0)\n           min1 = nums1[l];\n        else\n           min1 = max(nums1[l],nums2[j]);\n        if(l == nums1.size() - 1)\n            max1 = nums2[j + 1];\n        else\n            max1 = min(nums1[l + 1],nums2[j + 1]);\n        if(min1 <= max1)\n            return sum % 2 ? min1 : (min1 + max1) / 2.0;\n        j++;\n        if(j < nums2.size() - 1)\n            max1 = min(nums1[l],nums2[j + 1]);\n        else\n            max1 = nums1[l];\n        min1 = nums2[j];\n        return sum % 2 ? min1 : (min1 + max1) / 2.0;\n    }\n};\n```\n> 思路3\n******- 时间复杂度: O(lg(n+m))******- 空间复杂度: O(1)******\n\n由于题目中建议我们在时间复杂度O(lg(m+n))中完成，我们可以把这题看成寻找第k大的值，这样我们可以递归的去做，每次查找k/2，知道k等于1，注意边界值的处理\n```cpp\nclass Solution {\npublic:\nint getKth(vector<int> nums1, int start1, int end1, vector<int> nums2, int start2, int end2, int k) {\n        int len1 = end1 - start1 + 1;\n        int len2 = end2 - start2 + 1;\n        if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);\n        if (len1 == 0) return nums2[start2 + k - 1];\n\n        if (k == 1) return min(nums1[start1], nums2[start2]);\n\n        int i = start1 + min(len1, k / 2) - 1;\n        int j = start2 + min(len2, k / 2) - 1;\n\n        if (nums1[i] > nums2[j]) {\n            return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));\n        }\n        else {\n            return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));\n        }\n    }\ndouble findMedianSortedArrays(vector<int> nums1, vector<int> nums2) {\n    int n = nums1.size();\n    int m = nums2.size();\n    int left = (n + m + 1) / 2;\n    int right = (n + m + 2) / 2;\n    return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;\n}\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0005._Longest_Palindromic_Substring.md",
    "content": "# 5. Longest Palindromic Substring\n\n**<font color=red>难度:Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/longest-palindromic-substring\n\n> 内容描述\n\n```\nGiven a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.\n\nExample 1:\n\nInput: \"babad\"\nOutput: \"bab\"\nNote: \"aba\" is also a valid answer.\nExample 2:\n\nInput: \"cbbd\"\nOutput: \"bb\"\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)******\n\n\n这题如果用单纯暴力的解法，时间复杂度为 O(n ^ 3)，肯定超时，那么就要对这个算法进行优化，这里采用的是DP思想，定义 p(i,j)为s中的第i个数到s中的第j个数的子串，不难看出 p(i，j)中的子串有重复计算，接下来就可以写出状态转移方程 P(i,j)=(P(i+1,j?1) and S[i] == S[j])\n\n```cpp\nclass Solution {\npublic:\n    int dp[1000][1000] = {0};\n    string longestPalindrome(string s) {\n\t\t int beg = 0,en = 1,ans = 0;\n\t\tint length = s.length();\n\t\tfor(int i = 0;i < length;++i)\n\t\t{\n\t\t\tdp[i][i] = 1;\n\t\t\tif(i + 1 < length && s[i] == s[i + 1])\n\t\t\t\tdp[i][i + 1] = 1;\n\t\t}\n\t\tfor(int i = 0;i < length;++i)\n\t\t\tfor(int j = 0;j <= i;++j)\n\t\t\t{\n\t\t\t\tif(i > j + 1)\n\t\t\t\t\tdp[j][i] = (dp[j + 1][i - 1] && s[i] == s[j]);\n\t\t\t\tif(dp[j][i] && i - j + 1 > ans)\n\t\t\t\t{\n\t\t\t\t\tans = i - j + 1;\n\t\t\t\t\tbeg = j;\n\t\t\t\t\ten = i + 1;\n\t\t\t\t}\n\t\t\t}\n\t\tstring ret(s.begin() + beg,s.begin() + en);\n\t\treturn ret;\n\t\t}\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0006._ZigZag_Conversion.md",
    "content": "# 6. ZigZag Conversion\n\n**<font color=red>难度:Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n*https://leetcode.com/problems/zigzag-conversion\n* \n> 内容描述\n\n```\nThe string \"PAYPALISHIRING\" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)\n\nP   A   H   N\nA P L S I I G\nY   I   R\nAnd then read line by line: \"PAHNAPLSIIGYIR\"\n\nWrite the code that will take a string and make this conversion given a number of rows:\n\nstring convert(string s, int numRows);\nExample 1:\n\nInput: s = \"PAYPALISHIRING\", numRows = 3\nOutput: \"PAHNAPLSIIGYIR\"\nExample 2:\n\nInput: s = \"PAYPALISHIRING\", numRows = 4\nOutput: \"PINALSIGYAHRPI\"\nExplanation:\n\nP     I    N\nA   L S  I G\nY A   H R\nP     I\n```\n\n## 解题方案\n\n> 思路1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N + numRows)******\n\n\n这道题理解了题目意思其实不难，一般人可能会开一个二维数组，然后就按题目意思储存，这样做的话时间复杂度和空间复杂度都比较大，这里我用的方法先用一个 string 类型变量 str ，resize 和输入的 s 长度相等，接着只要遍历找到 s[i] 在 str 中的位置即可\n\n\n```cpp\nclass Solution {\npublic:\n    string convert(string s, int numRows) {\n         string newStr;\n    if(!s.length() || numRows == 1)\n        return s;\n    newStr.resize(s.length());\n    int num = numRows * 2 - 2,col = s.length() / num,rem = (s.length() - 1) % num;\n    vector<int> rowNum;\n    for(int i = 0;i < numRows;++i)\n        if(!i)\n            s.length() % num ? rowNum.push_back(col + 1) : rowNum.push_back(col);\n        else\n        {\n            if(i == numRows - 1)\n                rem >= i ? rowNum.push_back(rowNum[i - 1] + (s.length() - 1) / num + 1) : rowNum.push_back(rowNum[i - 1] + (s.length() - 1) / num);\n            else\n            {\n                int temp = 2 * numRows - i - 2,col1 = (s.length() - 1) / num;\n                if(rem >= temp)\n                    rowNum.push_back(rowNum[i - 1] + (col1 + 1) * 2);\n                else if(rem >= i)\n                    rowNum.push_back(rowNum[i - 1] + col1 * 2 + 1);\n                else\n                    rowNum.push_back(rowNum[i - 1] + col1 * 2);\n            }\n        }\n    for(int i = 0;i < s.length();++i)\n    {\n        int index1 = i % num;\n        int index2 = i / num;\n        if(!index1)\n            newStr[index2] = s[i];\n        else if(index1 == numRows - 1)\n            newStr[index2 + rowNum[index1 - 1]] = s[i];\n        else if(index1 < numRows)\n            newStr[index2 * 2 + rowNum[index1 - 1]] = s[i];\n        else\n        {\n            int index3 = 2 * numRows - index1 - 2;\n            newStr[index2 * 2 + 1 + rowNum[index3 - 1]] = s[i];\n        }\n    }\n    return newStr;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0007._Reverse_Integer.md",
    "content": "# 7. Reverse Integer\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/reverse-integer/\n\n> \n\n```\nGiven a 32-bit signed integer, reverse digits of an integer.\n\nExample 1:\n\nInput: 123\nOutput: 321\nExample 2:\n\nInput: -123\nOutput: -321\nExample 3:\n\nInput: 120\nOutput: 21\nNote:\nAssume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [?231,  231 ? 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nһeasyĿμλҪעⳬintķΧ\n\n```cpp\nclass Solution {\npublic:\n    int reverse(int x) {\n        long long val = 0;\n        do \n        {\n            val = val * 10 + x % 10;\n            x /= 10;\n        } while (x);\n\n        return (val > INT_MAX || val < INT_MIN) ? 0 : val;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0008._String_to_Integer_(atoi).md",
    "content": "# 8. String to Integer (atoi)\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/string-to-integer-atoi/\n\n> \n\n```\nImplement atoi which converts a string to an integer.\n\nThe function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.\n\nThe string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.\n\nIf the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.\n\nIf no valid conversion could be performed, a zero value is returned.\n\nNote:\n\nOnly the space character ' ' is considered as whitespace character.\nAssume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [?231,  231 ? 1]. If the numerical value is out of the range of representable values, INT_MAX (231 ? 1) or INT_MIN (?231) is returned.\nExample 1:\n\nInput: \"42\"\nOutput: 42\nExample 2:\n\nInput: \"   -42\"\nOutput: -42\nExplanation: The first non-whitespace character is '-', which is the minus sign.\n             Then take as many numerical digits as possible, which gets 42.\nExample 3:\n\nInput: \"4193 with words\"\nOutput: 4193\nExplanation: Conversion stops at digit '3' as the next character is not a numerical digit.\nExample 4:\n\nInput: \"words and 987\"\nOutput: 0\nExplanation: The first non-whitespace character is 'w', which is not a numerical \n             digit or a +/- sign. Therefore no valid conversion could be performed.\nExample 5:\n\nInput: \"-91283472332\"\nOutput: -2147483648\nExplanation: The number \"-91283472332\" is out of the range of a 32-bit signed integer.\n             Thefore INT_MIN (?231) is returned.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)******\n\nһַתַֻֻ֣Ҫַתint͵ּɣģҪעֵ߽жֵΪЧʡȼ1032η10nηֵ\n\n```cpp\nclass Solution {\npublic:\n    int myAtoi(string str) {\n        int i = 0,count1 = 0;\n        long long arr[34];\n        arr[0] = 1;\n        for(int i = 1;i < 34;++i)\n            arr[i] = arr[i - 1] * 10;\n        while(str[i] == ' ')\n            i++;\n        if(str[i] == '-' || str[i] == '+')\n        {\n            if(str[i] == '-')\n                count1 = 1;\n            i++;\n        }\n        if(!isdigit(str[i]))\n            return 0;\n        while(str[i] == '0')\n            i++;\n        long long num = 0;\n        int j = i;\n        while(j < str.length() && isdigit(str[j]))\n            j++;\n        if(j - i > 33)\n            return count1 ? INT_MIN : INT_MAX;\n        j--;\n        int t = 0;\n        while(j >= i)\n        {\n            num += (str[j] - '0') * arr[t++];\n            if(!count1 && num > INT_MAX)\n                return  INT_MAX;\n            if(count1 && num * -1 < INT_MIN)\n                return INT_MIN;\n            j--;\n        }\n        if(count1)\n            num *= -1;\n        return num;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0009._Palindrome_Number.md",
    "content": "# 9. Palindrome Number\n\n**<font color=red>难度:Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/palindrome-number\n* \n> 内容描述\n\n```\nDetermine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.\n\nExample 1:\n\nInput: 121\nOutput: true\nExample 2:\n\nInput: -121\nOutput: false\nExplanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.\nExample 3:\n\nInput: 10\nOutput: false\nExplanation: Reads 01 from right to left. Therefore it is not a palindrome.\nFollow up:\n\nCoud you solve it without converting the integer to a string?\n```\n\n## 解题方案\n\n> 思路1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n\n这题的难度不大，由于是数字，判断回文只需要求出倒过来的数字，判断两者是否相等，不过要注意负数一定不是回文\n\n\n```cpp\nclass Solution {\npublic:\n    bool isPalindrome(int x) {\n        long long ret = 0;\n        int num = x;\n        if(x < 0)\n            return false;\n        while(num)\n        {\n            ret = 10 * ret + num % 10;\n            num /= 10;\n        }\n        if(ret == x)\n            return true;\n        return false; \n        }\n};\n```\n> 思路2\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n\n计算出数字的长度，用双指针法，一个指针指向头，另一个指向尾，相等就前一个指针加一，后一个指针减一，若不相等则返回 false\n\n\n```cpp\nclass Solution {\npublic:\n    bool isPalindrome(int x) {\n        if (x < 0)\n            return false;\n        \n        int cnt = 0;\n        long fac = 1;\n        int div = INT_MAX;\n        while (div != 0) {\n            cnt++;\n            fac *= 10;\n            div = x/fac;\n        }\n        \n        fac /= 10;\n        for (int i=0; i<cnt/2; i++) {\n            int last = x%10;\n            int first = x/fac;\n            if (first != last)\n                return false;\n            x = x % fac;\n            x = (x-last)/10;\n            fac /= 100;\n        }\n        \n        return true;\n    }\n};\n\n```\n这两种方法的时间复杂度都取决于输入的数字的长度\n"
  },
  {
    "path": "docs/leetcode/cpp/0010._Regular_Expression_Matching.md",
    "content": "# 10. Regular Expression Matching\n\n**<font color=red>难度: Hard</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/regular-expression-matching\n\n> 内容描述\n\n```\nGiven an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'.\n\n'.' Matches any single character.\n'*' Matches zero or more of the preceding element.\nThe matching should cover the entire input string (not partial).\n\nNote:\n\ns could be empty and contains only lowercase letters a-z.\np could be empty and contains only lowercase letters a-z, and characters like . or *.\n\nExample 1:\n\nInput:\ns = \"aa\"\np = \"a\"\nOutput: false\nExplanation: \"a\" does not match the entire string \"aa\".\n\nExample 2:\n\nInput:\ns = \"aa\"\np = \"a*\"\nOutput: true\nExplanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes \"aa\".\n\nExample 3:\n\nInput:\ns = \"ab\"\np = \".*\"\nOutput: true\nExplanation: \".*\" means \"zero or more (*) of any character (.)\".\n\nExample 4:\n\nInput:\ns = \"aab\"\np = \"c*a*b\"\nOutput: true\nExplanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches \"aab\".\n\nExample 5:\n\nInput:\ns = \"mississippi\"\np = \"mis*is*p*.\"\nOutput: false\n```\n\n## 解题方案\n\n> 思路1\n******- 时间复杂度: O(n^2)******- 空间复杂度: O(n^2)******\n\n用动态规划的思路去解，dp[i][j]代表字符串s中第i个字符之前的字符串与p中第j个字符串之前的字符是否匹配。写出状态转移方程。当```s[i] == p[j] || p[j] == '.'```时。```dp[i + 1][j + 1] = dp[i][j]```。当```p[j] == '*'```时，可以匹配0个，1个或多个之前相同的字符。当之前的字符```s[i] == p[j - 1] || p[j - 1] == '*'```时。```dp[i + 1][j + 1] = dp[i][j] || dp[i][j + 1]```表示匹配1个或者多个。还可匹配0个。因此```dp[i + 1][j + 1] = dp[i + 1][j + 1] || dp[i + 1][j - 1]```\n\n```cpp\nclass Solution {\npublic:\n    bool isMatch(string s, string p) {\n        s.push_back(' ');\n        p.push_back(' ');\n        int len1 = s.length(),len2 = p.length();\n        int dp[len1 + 1][len2 + 1];\n        memset(dp,0,sizeof(dp));\n        dp[0][0] = 1;\n        for(int i = 1;i < len2;++i)\n            if(p[i] == '*')\n                dp[0][i + 1] = dp[0][i - 1];\n        for(int i = 0;i < len1;++i)\n            for(int j = 0;j < len2;++j)\n                if(j && p[j] == '*')\n                {\n                    dp[i + 1][j + 1] = (p[j - 1] == s[i] || p[j - 1] == '.') && (dp[i][j] || dp[i][j + 1]);\n                    dp[i + 1][j + 1] = dp[i + 1][j + 1] || dp[i + 1][j - 1];\n                }\n                else if(s[i] == p[j] || p[j] == '.')\n                    dp[i + 1][j + 1] = dp[i][j];\n        return dp[len1][len2];\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0011._Container_With_Most_Water.md",
    "content": "# 11. container with most water\n\n**<font color=red>难度:Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n*https://leetcode.com/problems/container-with-most-water/\n* \n> 内容描述\n\n```\nGiven n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.\n\nNote: You may not slant the container and n is at least 2.\n```\n\n## 解题方案\n\n> 思路\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n这道题刚开始很容易想到用暴力的方法去解，但是时间复杂度为 O(n^2) 测试之后发现是 TLE，那么我们就要对算法进行优化，这里我们用双指针法，定义两个指针，一个指向头，另一个指向尾部，比较两个指针指向的数的大小，若头部的大，则指向头部的指针向后移动一位，反之，则指向尾部的指针向前移动一位。\n\n\n```cpp\nclass Solution {\npublic:\n    int maxArea(vector<int>& height) {\n        int i = 0,j = height.size() - 1,ans = INT_MIN;\n\t\twhile(i < j)\n\t\t{\n\t\t\tint t = min(height[i],height[j]);\n\t\t\tans = max(ans,t * (j - i));\n\t\t\theight[i] < height[j] ? i++ : j--;\n\t\t}\n\t\treturn ans;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0012._Integer_to_Roman.md",
    "content": "# 12. Integer to Roman\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n\n> ԭ\n\n* https://leetcode.com/problems/rotate-list/\n\n> \n\n```\nRoman numerals are represented by seven different symbols: I, V, X, L, C, D and M.\n\nSymbol       Value\nI             1\nV             5\nX             10\nL             50\nC             100\nD             500\nM             1000\nFor example, two is written as II in Roman numeral, just two one's added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.\n\nRoman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:\n\nI can be placed before V (5) and X (10) to make 4 and 9. \nX can be placed before L (50) and C (100) to make 40 and 90. \nC can be placed before D (500) and M (1000) to make 400 and 900.\nGiven an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999.\n\nExample 1:\n\nInput: 3\nOutput: \"III\"\nExample 2:\n\nInput: 4\nOutput: \"IV\"\nExample 3:\n\nInput: 9\nOutput: \"IX\"\nExample 4:\n\nInput: 58\nOutput: \"LVIII\"\nExplanation: L = 50, V = 5, III = 3.\nExample 5:\n\nInput: 1994\nOutput: \"MCMXCIV\"\nExplanation: M = 1000, CM = 900, XC = 90 and IV = 4.\n\n```\n\n\n\n> ˼·1\n\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)******\n\nĿѣֱһֱд\n\n```cpp\nclass Solution {\npublic:\n    string intToRoman(int num) {\n        string ans;\n        vector<string> table;\n        int a = 0;\n        int count = 0;\n        while(num){\n            a = num%10;\n            num /= 10;\n            ++count;\n            if(count==1){\n                if(a==1) table.push_back(\"I\");\n                else if(a==2) table.push_back(\"II\");\n                else if(a==3) table.push_back(\"III\");\n                else if(a==4) table.push_back(\"IV\");\n                else if(a==5) table.push_back(\"V\");\n                else if(a==6) table.push_back(\"VI\");\n                else if(a==7) table.push_back(\"VII\");\n                else if(a==8) table.push_back(\"VIII\");\n                else if(a==9) table.push_back(\"IX\");\n            }\n            else if(count==2){\n                if(a==1) table.push_back(\"X\");\n                else if(a==2) table.push_back(\"XX\");\n                else if(a==3) table.push_back(\"XXX\");\n                else if(a==4) table.push_back(\"XL\");\n                else if(a==5) table.push_back(\"L\");\n                else if(a==6) table.push_back(\"LX\");\n                else if(a==7) table.push_back(\"LXX\");\n                else if(a==8) table.push_back(\"LXXX\");\n                else if(a==9) table.push_back(\"XC\");\n            }\n            else if(count==3){\n                if(a==1) table.push_back(\"C\");\n                else if(a==2) table.push_back(\"CC\");\n                else if(a==3) table.push_back(\"CCC\");\n                else if(a==4) table.push_back(\"CD\");\n                else if(a==5) table.push_back(\"D\");\n                else if(a==6) table.push_back(\"DC\");\n                else if(a==7) table.push_back(\"DCC\");\n                else if(a==8) table.push_back(\"DCCC\");\n                else if(a==9) table.push_back(\"CM\");\n            }\n            else if(count==4){\n                if(a==1) table.push_back(\"M\");\n                else if(a==2) table.push_back(\"MM\");\n                else if(a==3) table.push_back(\"MMM\");\n            }\n        }\n        for(int i = table.size()-1; i >= 0; --i){\n            ans += table[i];\n        }\n        return ans;\n    }\n};\n```\n\n> ˼·2\n\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\n̫if elseĲÿǿԻһָŵдôÿ\n\n```cpp\nclass Solution {\npublic:\n    int arr[7] = {'I','V','X','L','C','D','M'};\n    int arr1[13] = {1,4,5,9,10,40,50,90,100,400,500,900,1000};\n    void f(int& num,int i,string& ans)\n    {\n        if(i % 2)\n        {\n            ans.push_back(arr[i / 4 * 2]);\n            ans.push_back(arr[i / 2 + 1]);\n        }\n        else\n            ans.push_back(arr[i / 2]);\n        num -= arr1[i];\n    }\n    string intToRoman(int num) {\n        string ans;\n        while(num)\n        {\n            int i;\n            for(i = 0;i < 13;++i)\n                if(num < arr1[i])\n                {\n                    f(num,i - 1,ans);\n                    break;\n                }\n            if(i == 13)\n                f(num,i - 1,ans);\n        }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0014._Longest_Common_Prefix.md",
    "content": "# 14. Longest Common Prefix\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/longest-common-prefix/\n\n> \n\n```\nWrite a function to find the longest common prefix string amongst an array of strings.\n\nIf there is no common prefix, return an empty string \"\".\n\nExample 1:\n\nInput: [\"flower\",\"flow\",\"flight\"]\nOutput: \"fl\"\nExample 2:\n\nInput: [\"dog\",\"racecar\",\"car\"]\nOutput: \"\"\nExplanation: There is no common prefix among the input strings.\nNote:\n\nAll given inputs are in lowercase letters a-z.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(1)******\n\nǰ׺ӴֻбӴӴɣҪעܴڿַ\n\n```cpp\nclass Solution {\npublic:\n    string longestCommonPrefix(vector<string>& strs) {            \n        string temp;\n        if(!strs.size() || !strs[0].length())\n            return temp;\n        int j = 0;\n        while(1)\n        {\n            int i = 0;\n            int ch = strs[0][j];\n            for(;i < strs.size();++i)\n                if(j >= strs[i].length() || strs[i][j] != ch)\n                    break;\n            if(i != strs.size())\n                break;\n            temp.push_back(strs[0][j++]);\n        }\n        return temp;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0015._3sum.md",
    "content": "# 15. 3sum\n\n**<font color=red>难度:Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n*https://leetcode.com/problems/3sum\n* \n> 内容描述\n\n```\nGiven an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.\n\nNote:\n\nThe solution set must not contain duplicate triplets.\n```\n\n## 解题方案\n\n> 思路\n******- 时间复杂度: O(N ^ 2)******- 空间复杂度: O(N)******\n\n之前做过两个数之和等于某个数的题目，其实这题也差不多，三数之和等于0，那么我们只要让另外两个数之和等于第三个数的相反数即可，不过这里要注意会存在重复，所以要去重\n\n\n```cpp\nclass Solution {\npublic:\n    vector<vector<int>> threeSum(vector<int>& nums) {\n   vector<vector<int> > ret;\n    sort(nums.begin(),nums.end());\n    for(int i = 0;i < nums.size();++i)\n    {\n        int t1 = i + 1,t2 = nums.size() - 1;\n        if(i && nums[i] == nums[i - 1])\n            continue;\n        while(t1 < t2)\n            if(nums[t1] + nums[t2] == -nums[i])\n            {\n                vector<int> v;\n                v.push_back(nums[i]);\n                v.push_back(nums[t1]);\n                v.push_back(nums[t2]);\n                ret.push_back(v);\n                ++t1;\n                --t2;\n            }\n            else if(nums[t1] + nums[t2] < -nums[i])\n                ++t1;\n            else\n                --t2;\n    }\n    auto pos = unique(ret.begin(),ret.end());\n    ret.erase(pos,ret.end());\n    return ret;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0016._3Sum_Closest.md",
    "content": "## 16. 3Sum Closest\n\n难度：Medium\n\n## 内容\n\n> 原题链接：https://leetcode.com/problems/3sum-closest\n\nGiven an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.\n\nExample:\n\n```\nGiven array nums = [-1, 2, 1, -4], and target = 1.\n\nThe sum that is closest to the target is 2. (-1 + 2 + 1 = 2).\n```\n\n## 思路\n\n先排序，遍历第一个数，第二和第三个数通过双指针查找，转化为2sum closest的问题。如果遇到和等于target的三个数，直接返回target。\n\n## 代码\n\n```\nclass Solution {\npublic:\n    int threeSumClosest(vector<int>& nums, int target) {\n        std::sort(nums.begin(), nums.end());\n        int min_distance{INT_MAX}, sum{0}, cur_sum{0};\n        for (auto it = nums.cbegin(); it != nums.cend(); ++it)\n            for (auto left_idx = std::next(it), right_idx = std::prev(nums.cend()); left_idx < right_idx; cur_sum > target ? --right_idx : ++left_idx) {\n                cur_sum = *it + *left_idx + *right_idx;\n                auto cur_distance = std::abs(cur_sum - target);\n                if (cur_sum == target)\n                    return target;\n                else if (cur_distance < min_distance) {\n                    min_distance = cur_distance;\n                    sum = cur_sum;\n                }\n            }\n        return sum;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0017._Letter_Combinations_of_a_Phone_Number.md",
    "content": "# 17. Letter Combinations of a Phone Number\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/letter-combinations-of-a-phone-number/\n\n> \n\n```\nGiven a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.\n\nA mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.\n\n\n\nExample:\n\nInput: \"23\"\nOutput: [\"ad\", \"ae\", \"af\", \"bd\", \"be\", \"bf\", \"cd\", \"ce\", \"cf\"].\nNote:\n\nAlthough the above answer is in lexicographical order, your answer could be in any order you want.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(2^n)******- ռ临Ӷ: O(1)******\n\nûݷȥ⣬Ƚַת֡79ֶ֮3ĸÿִĸûݷ\n\n```cpp\nclass Solution {\npublic:\n    void DFS(string& s,int i,vector<string>& ans,string& temp)\n    {\n        if(i == s.length())\n        {\n            ans.push_back(temp);\n            return;\n        }\n        int t = s[i] - '2';\n        int ch_beg;\n        if(t < 6)\n            ch_beg = 'a' + t * 3;\n        else\n            ch_beg = 'a' + (t - 1) * 3 + 4;\n        int en = 3;\n        if(t == 5 || t == 7)\n            en = 4;\n        for(int j = 0;j < en;++j)\n        {\n            temp.push_back(ch_beg + j);\n            DFS(s,i + 1,ans,temp);\n            temp.pop_back();\n        }\n    }\n    vector<string> letterCombinations(string digits) {\n        vector<string> ans;\n        if(!digits.size())\n            return ans;\n        string temp;\n        DFS(digits,0,ans,temp);\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0018._4Sum.md",
    "content": "## 18. 4Sum\n\n难度：Medium\n\n## 内容\n\n题目链接：https://leetcode.com/problems/4sum\n\nGiven an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.\n\nNote:\n\nThe solution set must not contain duplicate quadruplets.\n\nExample:\n\n```\nGiven array nums = [1, 0, -1, 0, -2, 2], and target = 0.\n\nA solution set is:\n[\n  [-1,  0, 0, 1],\n  [-2, -1, 1, 2],\n  [-2,  0, 0, 2]\n]\n```\n\n## 思路\n\n思路和 3Sum 类似，多了一层for循环。为了避免重复，在存储结果的时候使用STL的set。\n\n## 代码\n\n```\nclass Solution {\npublic:\n    vector<vector<int>> fourSum(vector<int>& nums, int target) {\n        if (nums.size() < 4) return vector<vector<int>>{};\n        std::set<vector<int>> res;\n        std::sort(nums.begin(), nums.end());\n        for (size_t i = 0; i < nums.size() - 3; ++i)\n            for (size_t j = i + 1; j < nums.size() - 2; ++j) {\n                auto left_idx = j + 1; auto right_idx = nums.size() - 1;\n                int sum = 0;\n                for (left_idx = j + 1, right_idx = nums.size() - 1; left_idx < right_idx; sum > target ? --right_idx : ++left_idx) {\n                    sum = nums[i] + nums[j] + nums[left_idx] + nums[right_idx];\n                    if (sum == target) {\n                        vector<int> res_single{nums[i], nums[j], nums[left_idx], nums[right_idx]};\n                        res.insert(res_single);\n                    }\n\n                }\n            }\n        return vector<vector<int>>(res.begin(), res.end());\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0019._Remove_Nth_Node_From_End_of_List.md",
    "content": "# 19. Remove Nth Node From End of List\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/remove-nth-node-from-end-of-list/\n\n> \n\n```\nGiven a linked list, remove the n-th node from the end of list and return its head.\n\nExample:\n\nGiven linked list: 1->2->3->4->5, and n = 2.\n\nAfter removing the second node from the end, the linked list becomes 1->2->3->5.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nɾnΪ˷ֹΪ1ʱĿָ쳣ȲһͷֻҪȱܳȣܳȼȥ n ҪɾǰһͷĳȣֻҪøѭҵɾҪɾĽڵ㼴ɡ\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode* removeNthFromEnd(ListNode* head, int n) {\n       ListNode* current = head;\n        int num = 0;\n        while(current)\n        {\n            num++;\n            current = current ->next;\n        }\n        ListNode* n1 = new ListNode(0);\n        n1 ->next = head;\n        current = n1;\n        num -= n;\n        while(num)\n        {\n            num--;\n            current = current ->next;\n        }\n        ListNode* temp = current ->next;\n        current ->next = temp ->next;\n        return n1 ->next;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0020._Valid_Parentheses.md",
    "content": "## 20. Valid Parentheses\n **<font color=red>难度: Easy</font>**\n## 刷题内容\n> 原题连接\n* https://leetcode-cn.com/problems/valid-parentheses/\n> 内容描述\n```\nGiven a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.\n\nAn input string is valid if:\n\nOpen brackets must be closed by the same type of brackets.\nOpen brackets must be closed in the correct order.\nNote that an empty string is also considered valid.\n\n### Example\n1. Input: \"()\"   -> Output: true\n\n2. Input: \"()[]{}\" -> Output: true\n\n3. Input: \"(]\" -> Output: false\n\n4. Input: \"([)]\" -> Output: false\n\n5. Input: \"{[]}\" -> Output: true\n```\n## 解题方案\n> 思路：\n```\n利用栈先进后出的先天优势，解决匹配问题。\n```\n```cpp\nbool isValid(string s) {\n        stack<char> stacks;\n        for(int i=0;i<s.length();i++){\n            if(s[i]=='('||s[i]=='{'||s[i]=='[')\n                stacks.push(s[i]);\n            else if(stacks.empty()){\n                return false;\n            }else{\n                char ch = stacks.top();\n                stacks.pop();\n                if(s[i]==')'&&ch=='('||s[i]==']'&&ch=='['||s[i]=='}'&&ch=='{')\n                    continue;\n                else\n                    return false;\n            }\n        }\n        if(stacks.empty())\n            return true;\n        else\n            return false;\n    }\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0021._Merge_Two_Sorted_Lists.md",
    "content": "# 21. Merge Two Sorted Lists\n\n**<font color=red>难度:Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/merge-two-sorted-lists\n* \n> 内容描述\n\n```\nMerge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.\n\nExample:\n\nInput: 1->2->4, 1->3->4\nOutput: 1->1->2->3->4->4\n```\n\n## 解题方案\n\n> 思路\n******- 时间复杂度: O(N + M)******- 空间复杂度: O(1)******\n\n首先这两个链表是排序好的，那么我们先定义一个空链表，再定义两个指针 i，j，按照顺序比较两个链表，如果 i 指向的数字小于 j指向的数字，i 指向的节点插入新链表中，i = i -> next，反之则操作 j。不过要注意其中一个链表可能会先结束，所以另一个未结束的链表直接插入新链表即可\n\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {\n         ListNode* h1 = l1;\n        ListNode* h2 = l2;\n        ListNode* t = new ListNode(0);\n        ListNode* curr = t;\n        while (h1 && h2)\n        {\n            if (h1->val <= h2->val) {\n                curr->next = h1; \n                h1 = h1->next;\n            }\n            else{\n                curr->next = h2;\n                h2 = h2->next;\n            }\n            curr = curr->next;\n        }\n        while (h1)\n        {\n            curr->next = h1;\n            h1 = h1->next;\n            curr = curr->next;\n        }\n        while(h2)\n        {\n            curr->next = h2;\n            h2 = h2->next;\n            curr = curr->next;\n        }\n        ListNode* res = t->next;\n        delete t;\n        return res;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0022._Generate_Parentheses.md",
    "content": "# 22. Generate Parentheses\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/generate-parentheses/\n  \n > 内容描述\n \n ```\n给出 n 代表生成括号的对数，请你写出一个函数，使其能够生成所有可能的并且有效的括号组合。\n\n例如，给出 n = 3，生成结果为：\n\n[\n  \"((()))\",\n  \"(()())\",\n  \"(())()\",\n  \"()(())\",\n  \"()()()\"\n]\n ```\n\n## 解题方案\n> 思路 1\n```\n回溯法\n```\n\n```cpp\nvoid dfs(int left, int total, string path, vector<string>& ans){\n    if(total==0&&left==0){\n        ans.push_back(path);\n        return ;\n    }\n    if(left>0)\n        dfs(left-1, total-1, path+\"(\", ans);\n    if(left<total-left)\n        dfs(left, total-1, path+\")\", ans);\n}\nvector<string> generateParenthesis(int n) {\n    vector<string> ans;\n    string path=\"\";\n    dfs(n, n*2, path, ans);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0023._Merge_K_Sorted_Lists.md",
    "content": "# 23. merge k sorted lists\n\n**<font color=red>难度: Hard</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/merge-k-sorted-lists/\n\n> 内容描述\n\n```\nMerge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.\n\nExample:\n\nInput:\n[\n  1->4->5,\n  1->3->4,\n  2->6\n]\nOutput: 1->1->2->3->4->4->5->6\n```\n\n## 解题方案\n\n> 思路1\n******- 时间复杂度: O(Nlg(K))******- 空间复杂度: O(K)******\n\n这里运用最小堆，先去每个链表的第一个元素构建最小堆，由于链表都是已排序的，因此，每次堆的顶部都是最小的元素，这里用优先队列实现最小堆。\n\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n\tstruct cmp\n\t{\n\t\tbool operator()(ListNode* a, ListNode* b) const\n\t\t{\n\t\t\treturn a ->val > b ->val;\n\t\t}\n\t};\n    ListNode* mergeKLists(vector<ListNode*>& lists) {  \n\t\tpriority_queue<ListNode*,vector<ListNode*>,cmp> pq;\n\t\tListNode* ret = nullptr;\n\t\tListNode* current = nullptr;\n\t\tfor(int i = 0;i < lists.size();++i)\n\t\t\tif(lists[i])\n\t\t\t\tpq.push(lists[i]);\n\t\twhile(pq.size())\n\t\t{\n\t\t\tListNode* temp = pq.top();\n\t\t\tpq.pop();\n\t\t\tif(!ret)\n\t\t\t\tret = temp;\n\t\t\telse\n\t\t\t\tcurrent ->next = temp;\n\t\t\tcurrent = temp;\n\t\t\tif(temp ->next)\n\t\t\t\tpq.push(temp ->next);\n\t\t}\n\t\treturn ret;\n    }\n};\n```\n> 思路2\n******- 时间复杂度: O(Nlg(K))******- 空间复杂度: O(1)******\n\n这个思路用分治思想，我们可以通过归并排序解决，首先前面已经做过了两个有序链表的排序，我们可以把链表看做元素，只要对数组 Lists进行归并排序即可。\n\n```cpp\nclass Solution {\npublic:\n    ListNode* merge(ListNode* list1, ListNode* list2) {\n        ListNode head(0);\n        ListNode* tail = &head;\n        auto cur1 = list1;\n        auto cur2 = list2;\n        while (cur1 != nullptr && cur2 != nullptr) {\n            if (cur1->val < cur2->val) {\n                tail->next = cur1;\n                tail = tail->next;\n                cur1 = cur1->next;\n            } else {\n                tail->next = cur2;\n                tail = tail->next;\n                cur2 = cur2->next;\n            }\n        }\n        auto cur = cur1 == nullptr ? cur2 : cur1;\n        while (cur != nullptr) {\n            tail->next = cur;\n            tail = tail->next;\n            cur = cur->next;\n        }\n        return head.next;\n    }\n    ListNode* mergeSort(vector<ListNode*>& lists, int start, int end) {\n        if (start > end) {\n            return nullptr;\n        }\n        if (start == end) {\n            return lists[start];\n        }\n        int mid = start + (end - start) / 2;\n        auto list1 = mergeSort(lists, start, mid);\n        auto list2 = mergeSort(lists, mid + 1, end);\n        return merge(list1, list2);\n    }\n    ListNode* mergeKLists(vector<ListNode*>& lists) {\n        int n = lists.size();\n        return mergeSort(lists, 0, n - 1);\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0024._Swap_Nodes_in_Pairs.md",
    "content": "# 24. Swap Nodes in Pairs\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/swap-nodes-in-pairs/\n  \n > 内容描述\n \n ```\n给定一个链表，两两交换其中相邻的节点，并返回交换后的链表。\n\n示例:\n\n给定 1->2->3->4, 你应该返回 2->1->4->3.\n说明:\n\n你的算法只能使用常数的额外空间。\n你不能只是单纯的改变节点内部的值，而是需要实际的进行节点交换。\n ```\n\n## 解题方案\n> 思路 1\n```\n链表反转\n```\n\n```cpp\nListNode* swapPairs(ListNode* head) {\n    if(head==NULL||head->next==NULL)\n        return head;\n    \n    ListNode* slow=head;\n    ListNode* fast=head->next;\n    ListNode* pre=new ListNode(0);\n    ListNode* ans = pre;\n    while(slow&&fast){\n        slow->next = fast->next;\n        fast->next = slow;\n        pre->next = fast;\n        if(slow->next==NULL||slow->next->next==NULL){\n            break;\n        }\n        fast = slow->next->next;\n        pre = slow;\n        slow = slow->next; \n    }\n    return ans->next;\n}\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0025._Reverse_Nodes_In_K_Group.md",
    "content": "# 25.reverse nodes in k group\n\n**<font color=red>ѶHard</font>**\n\n## ˢ\n\n> ԭ\n\n* https://leetcode.com/problems/reverse-nodes-in-k-group/\n\n> \n\n```\nGiven a linked list, reverse the nodes of a linked list k at a time and return its modified list.\n\nk is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.\n\nExample:\n\nGiven this linked list: 1->2->3->4->5\n\nFor k = 2, you should return: 2->1->4->3->5\n\nFor k = 3, you should return: 3->2->1->4->5\n\nNote:\n\nOnly constant extra memory is allowed.\nYou may not alter the values in the list's nodes, only nodes itself may be changed.\n```\n> ˼·1\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\nĿѣ˵ݹķȥ⣬Ŀеnote˵жĴռ䣬ݹɸĿռ䣬԰ѵݹĳѭ»ǵݹİ汾\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode* reverseKGroup(ListNode* head, int k) {\n        if(!head)\n        return head;\n    ListNode* current = head,*next1,*pre = nullptr;\n    int m = 1;\n    while(m <= k && current)\n    {\n        next1 = current ->next;\n        current ->next = pre;\n        pre = current;\n        current = next1;\n        ++m;\n    }\n    if(m <= k)\n    {\n        while(current != head)\n        {\n            ListNode* temp = pre ->next;\n            pre ->next = current;\n            current = pre;\n            pre = temp;\n        }\n        pre = head;\n    }\n    else\n        head ->next = reverseKGroup(current,k);\n    return pre;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0026._Remove_Duplicates_From_Sorted_Array.md",
    "content": "# 26.Remove Duplicates From Sorted Array\n\n**<font color=red>ѶEasy</font>**\n\n## ˢ\n\n> ԭ\n\n* https://leetcode.com/problems/remove-duplicates-from-sorted-array/\n> \n\n```\nGiven a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.\n\nDo not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.\n\nExample 1:\n\nGiven nums = [1,1,2],\n\nYour function should return length = 2, with the first two elements of nums being 1 and 2 respectively.\n\nIt doesn't matter what you leave beyond the returned length.\nExample 2:\n\nGiven nums = [0,0,1,1,1,2,2,3,3,4],\n\nYour function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively.\n\nIt doesn't matter what values are set beyond the returned length.\nClarification:\n\nConfused why the returned value is an integer but your answer is an array?\n\nNote that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.\n\nInternally you can think of this:\n\n// nums is passed in by reference. (i.e., without making a copy)\nint len = removeDuplicates(nums);\n\n// any modification to nums in your function would be known by the caller.\n// using the length returned by your function, it prints the first len elements.\nfor (int i = 0; i < len; i++) {\n    print(nums[i]);\n}\n```\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\nѾõģֱӱ飬һָ i ָʼһ j ָڶ j ָ i ָ```++i,++j```ֻ```++j```\n\n```cpp\nclass Solution {\npublic:\n    int removeDuplicates(vector<int>& nums) {\n        int j = 0;\n        if(!nums.size())\n            return 0;\n        for(int i = 1;i < nums.size();)\n        {\n            while(nums[j] == nums[i] && i < nums.size())\n               ++i;\n            if(i == nums.size())\n                break;\n            swap(nums[++j],nums[i++]);\n        }\n        return j + 1;\n        }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0027._Remove_Element.md",
    "content": "# 27.Remove Element\n\n**<font color=red>ѶEasy</font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/remove-element/\n\n> \n\n```\nGiven an array nums and a value val, remove all instances of that value in-place and return the new length.\n\nDo not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.\n\nThe order of elements can be changed. It doesn't matter what you leave beyond the new length.\n\nExample 1:\n\nGiven nums = [3,2,2,3], val = 3,\n\nYour function should return length = 2, with the first two elements of nums being 2.\n\nIt doesn't matter what you leave beyond the returned length.\nExample 2:\n\nGiven nums = [0,1,2,2,3,0,4,2], val = 2,\n\nYour function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4.\n\nNote that the order of those five elements can be arbitrary.\n\nIt doesn't matter what values are set beyond the returned length.\nClarification:\n\nConfused why the returned value is an integer but your answer is an array?\n\nNote that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.\n\nInternally you can think of this:\n\n// nums is passed in by reference. (i.e., without making a copy)\nint len = removeElement(nums, val);\n\n// any modification to nums in your function would be known by the caller.\n// using the length returned by your function, it prints the first len elements.\nfor (int i = 0; i < len; i++) {\n    print(nums[i]);\n}\n```\n> ˼·\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nǿԱ飬ѵ val ŵĺ벿־Сǿ˫ָʵ֡ nums[i] != val ʱnums[j++] = nums[i]\n```cpp\nclass Solution {\npublic:\n    int removeElement(vector<int>& nums, int val) {\n        int i ,count = 0,j = 0,numsSize = nums.size();\n        for(i = 0;i < numsSize;i++)\n        {\n            if(nums[i] == val)\n            { \n                count++;\n            }\n            else\n                nums[j++] = nums[i];\n        }\n        return numsSize - count;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0028._Implement_Strstr.md",
    "content": "# 28.implement strstr\n\n**<font color=red>ѶEasy</font>**\n\n## ˢ\n\n> ԭ\n\n* https://leetcode.com/problems/implement-strstr/\n> \n\n```\nImplement strStr().\n\nReturn the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.\n\nExample 1:\n\nInput: haystack = \"hello\", needle = \"ll\"\nOutput: 2\nExample 2:\n\nInput: haystack = \"aaaaa\", needle = \"bba\"\nOutput: -1\nClarification:\n\nWhat should we return when needle is an empty string? This is a great question to ask during an interview.\n\nFor the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C's strstr() and Java's indexOf().\n```\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\nֱӱ haystack ƥ䵽 needle һַʱͱ needleȽַ\n\n```cpp\nclass Solution {\npublic:\n    int strStr(string haystack, string needle) {\n        int j = 0,i = 0,index= 0;\n        while(i < haystack.size() && j < needle.size())\n        {\n            if(haystack[i] == needle[j])\n            {\n                if(!j)\n                    index = i;\n                j++;\n                i++;\n            }\n            else\n            {\n                i = ++index;\n                j = 0;\n            }\n        }\n        if(j == needle.size())\n            return index;\n        return -1;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0029._Divide_Two_Integers.md",
    "content": "# 29.divide two integers\n\n**<font color=red>ѶMedium</font>**\n\n## ˢ\n\n> ԭ\n\n* https://leetcode.com/problems/divide-two-integers/\n> \n\n```\nGiven two integers dividend and divisor, divide two integers without using multiplication, division and mod operator.\n\nReturn the quotient after dividing dividend by divisor.\n\nThe integer division should truncate toward zero.\n\nExample 1:\n\nInput: dividend = 10, divisor = 3\nOutput: 3\nExample 2:\n\nInput: dividend = 7, divisor = -3\nOutput: -2\nNote:\n\nBoth dividend and divisor will be 32-bit signed integers.\nThe divisor will never be 0.\nAssume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [?231,  231 ? 1]. For the purpose of this problem, assume that your function returns 231 ? 1 when the division result overflows.\n\n```\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\nֱñķ϶ʱ˿ռ任ʱ䣬 int Ϊ2^31 - 1 ĴСҲǹ̶ġñȶһres = 0ÿζ res += divisor * 2^n ֱdividend ٴ res = divisor * 2^(n-1)ʼֱĳres + divisor > dividend\n\n\n```cpp\nclass Solution {\npublic:\n    int divide(int dividend, int divisor) {\n        if(!dividend)\n        return 0;\n        long long arr[33];\n        arr[0] = 1;\n        for(int i = 1;i < 33;++i)\n            arr[i] = arr[i - 1] * 2;\n        long long temp1 = dividend,temp2 = divisor;\n        if(temp1 < 0)\n            temp1 *= -1;\n        if(temp2 < 0)\n            temp2 *= -1;\n        long long res,pre = 0,ret = 0;\n        int count1 = 0;\n        while(1)\n        {\n            res = pre + arr[count1] * temp2;\n            if(res > temp1)\n            {\n                if(!count1)\n                    break;\n                pre = pre + arr[count1 - 1] * temp2;\n                ret += arr[count1 - 1];\n                count1 = 0;\n            }\n            else\n                count1++;\n        }\n        if(dividend < 0)\n            ret *= -1;\n        if(divisor < 0)\n            ret *= -1;\n        if(ret == 2147483648)\n            return ret - 1;\n        return ret;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0030._Substring_With_Concatenation_Of_All_Words.md",
    "content": "# 30.substring with concatenation of all words\n\n**<font color=red>难度Hard</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/substring-with-concatenation-of-all-words/\n\n> 内容描述\n\n```\nYou are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.\n\nExample 1:\n\nInput:\n  s = \"barfoothefoobarman\",\n  words = [\"foo\",\"bar\"]\nOutput: [0,9]\nExplanation: Substrings starting at index 0 and 9 are \"barfoor\" and \"foobar\" respectively.\nThe output order does not matter, returning [9,0] is fine too.\nExample 2:\n\nInput:\n  s = \"wordgoodstudentgoodword\",\n  words = [\"word\",\"student\"]\nOutput: []\n\n```\n> 思路\n******- 时间复杂度: O(mlgn)******- 空间复杂度: O(m+n)******\n\n这题可以两个 map 来解决，第一个 map 中存放了 words 中的所有单词和出现的次数，接下来遍历字符串，固定区间的大小为 words 的长度，存入另一个map，两个 map 相等就放入返回数组中\n\n```cpp\nclass Solution {\npublic:\n    vector<int> findSubstring(string s, vector<string>& words) {\n        vector<int> ans;\n        if(!s.length() || !words.size())\n            return ans;\n        unordered_map<string,int> m1;\n        int len = words.size(),wl = words[0].length(),sl = s.length();\n        for(int i = 0;i < words.size();++i)\n            m1[words[i]]++;\n        int count1 = 0,reLen = wl * len,left = 0;\n        for(int i = 0;i < sl - wl * len + 1;++i)\n        {\n            unordered_map<string,int> m2;\n            for(int j = 0,left = i;j < len;j ++)\n            {\n                string temp = s.substr(left,wl);\n                left += wl;\n                m2[temp]++;\n            }\n            if(m2 == m1)\n                ans.push_back(i);\n        }\n        return ans;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0031._Next_Permutatio.md",
    "content": "# 31.Next Permutatio\n\n**<font color=red>难度Medium</font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/next-permutation/\n\n> 内容描述\n\n```\nImplement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.\n\nIf such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).\n\nThe replacement must be in-place and use only constant extra memory.\n\nHere are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.\n\n1,2,3 → 1,3,2\n3,2,1 → 1,2,3\n1,1,5 → 1,5,1\n```\n> 思路\n******- 时间复杂度: O(n)******- 空间复杂度: O(1)******\n\n我们可以用两个指针表示需要交换的两个数，遍历数组。这题的最坏的情况下，数组降序排列，排序算法的复杂度也是O(n)。\n\n```cpp\nclass Solution {\npublic:\n    void nextPermutation(vector<int>& nums) {\n        int n1 = 0,n2 = 0;\n        for(int i = 1;i < nums.size();++i)\n            if(nums[i] > nums[n2])\n            {\n                n1 = n2;\n                n2 = i;\n            }\n            else if((nums[i] < nums[n2] && nums[i] > nums[n1]) || nums[i] == nums[n2])\n                n2 = i;\n            else if(nums[i] <= nums[n1])\n            {\n                int j = i;\n                for(;j < nums.size() - 1;++j)\n                    if(nums[j + 1] > nums[j])\n                    {\n                        n1 = j;\n                        n2 = j + 1;\n                        break;\n                    }\n                i = j + 1;\n            }\n        if(n1 == n2)\n            sort(nums.begin(),nums.end());\n        else\n        {\n            swap(nums[n1],nums[n2]);\n            sort(nums.begin() + n1 + 1,nums.end());\n        }\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0032._Longest_Valid_Parentheses.md",
    "content": "# 32. Longest Valid Parentheses\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/longest-valid-parentheses/\n\n> \n\n```\nGiven a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.\n\nExample 1:\n\nInput: \"(()\"\nOutput: 2\nExplanation: The longest valid parentheses substring is \"()\"\nExample 2:\n\nInput: \")()())\"\nOutput: 4\nExplanation: The longest valid parentheses substring is \"()()\"\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)******\n\nDPķ⡣һջȥߵĲ֣'('λãֱһ')'ʱͼ¼ջ'('λãǾͿд״̬תƷ̡dp[i]ַеiԶλáһ')'ʱdp[i] = ջ'('λáڿԴţdp[dp[i] - 1]ڣdp[i] = dp[dp[i] - 1]Ҫע߽缴ɡ\n\n```cpp\nclass Solution {\npublic:\n    int longestValidParentheses(string s) {\n        int len = s.length();\n        if(!len)\n            return 0;\n        int dp[len];\n        memset(dp,-1,sizeof(dp));\n        int ans = 0;\n        vector<int> v;\n        for(int i = 0;i < len;++i)\n            if(s[i] == '(')\n                v.push_back(i);\n            else if(s[i] == ')' && v.size())\n            {\n                dp[i] = v[v.size() - 1];\n                if(dp[i] && dp[dp[i] - 1] >= 0)\n                    dp[i] = dp[dp[i] - 1];\n                ans = max(ans,i - dp[i] + 1);\n                v.pop_back();\n            }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0033._Search_in_Rotated_Sorted_Array.md",
    "content": "# 033. Search in Rotated Sorted Array\n\n**<font color=red>难度Medium<font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/search-in-rotated-sorted-array/\n\n> 内容描述\n\n```\nSuppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.\n\n(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).\n\nYou are given a target value to search. If found in the array return its index, otherwise return -1.\n\nYou may assume no duplicate exists in the array.\n\nYour algorithm's runtime complexity must be in the order of O(log n).\n\nExample 1:\n\nInput: nums = [4,5,6,7,0,1,2], target = 0\nOutput: 4\nExample 2:\n\nInput: nums = [4,5,6,7,0,1,2], target = 3\nOutput: -1\n```\n> 思路1\n******- 时间复杂度: O(n)******- 空间复杂度: O(1)******\n\n第一个方法是直接遍历数组，找到返回数组下标，找不到就返回-1\n\n```cpp\nclass Solution {\npublic:\n    int search(vector<int>& nums, int target) {\n        for(int i = 0;i < nums.size();++i)\n            if(nums[i] == target)\n                return i;\n        return -1;\n    }\n};\n```\n> 思路2\n******- 时间复杂度: O(lgn)*****- 空间复杂度: O(1)******\n\n第二个方法是用二分法找到旋转轴，再用二分法找到目标数\n```cpp\nclass Solution {\npublic:\n    int search(vector<int>& nums, int target) {\n       int i = 0,j = nums.size() - 1;\n    if(!nums.size())\n        return -1;\n    while(i < j - 1)\n    {\n        int mid = (i + j) / 2;\n        if(nums[i] < nums[mid])\n            i = mid;\n        else\n            j = mid;\n    //cout << i << j << endl;\n    }\n    if(nums[i] <= nums[j])\n        j = i;\n    //cout << j;\n    auto pos = lower_bound(nums.begin(),nums.begin() + j,target);\n    if(pos != nums.end() && (*pos) == target)\n        return pos - nums.begin();\n    pos = lower_bound(nums.begin() + j,nums.end(),target);\n    if(pos != nums.end() && (*pos) == target)\n        return pos - nums.begin();\n    return -1;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md",
    "content": "# 34. Find First and Last Position of Element in Sorted Array\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/\n\n> \n\n```\nGiven an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.\n\nYour algorithm's runtime complexity must be in the order of O(log n).\n\nIf the target is not found in the array, return [-1, -1].\n\nExample 1:\n\nInput: nums = [5,7,7,8,8,10], target = 8\nOutput: [3,4]\nExample 2:\n\nInput: nums = [5,7,7,8,8,10], target = 6\nOutput: [-1,-1]\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(lgn)******- ռ临Ӷ: O(1)******\n\n͵ĶȲĿǷtargetڷֱҵһֵtargetһtarget\n\n```cpp\nclass Solution {\npublic:\n    vector<int> searchRange(vector<int>& nums, int target) {\n        int l = 0,r = nums.size();\n        vector<int> ans = {-1,-1};\n        int mid = -1;\n        while(l < r)\n        {\n            mid = (r + l) / 2;\n            if(nums[mid] < target)\n                l = mid + 1;\n            else if(nums[mid] > target)\n                r = mid;\n            else\n                break;\n        }\n        if(mid == -1 || nums[mid] != target)\n            return ans;\n        int mid1 = l = mid;\n        r = nums.size();\n        while(l < r)\n        {\n            mid = (r + l) / 2;\n            if(mid == nums.size())\n                break;\n            if(nums[mid] > target)\n                r = mid;\n            else\n                l = mid + 1;\n        }\n        if(nums[mid] > target)\n            mid--;\n        ans[1] = mid;\n        l = 0;\n        r = mid1 + 1;\n        while(l < r)\n        {\n            mid = (r + l) / 2;\n            if(nums[mid] < target)\n                l = mid + 1;\n            else\n                r = mid;\n        }\n        if(nums[mid] < target)\n            mid++;\n        ans[0] = mid;\n        return ans;\n    }\n};\n```\n\n> ˼·2\n******- ʱ临Ӷ: O(lgn)******- ռ临Ӷ: O(1)******\n\nõc++lower_boundupper_bound\n\n```cpp\nclass Solution {\npublic:\n    vector<int> searchRange(vector<int>& nums, int target) {\n     \tauto pos1 = lower_bound(nums.begin(),nums.end(),target);\n        vector<int> ans = {-1,-1};\n        if(pos1 == nums.end() || (*pos1) != target)\n            return ans;\n        ans[0] = pos1 - nums.begin();\n        auto pos2 = upper_bound(nums.begin(),nums.end(),target);\n        ans[1] = pos2 - nums.begin() - 1;\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0035._Search_Insert_Position.md",
    "content": "# 35.search insert position\n\n**<font color=red>难度:Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n*https://leetcode.com/problems/search-insert-position/\n* \n> 内容描述\n\n```\nGiven a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.\n\nYou may assume no duplicates in the array.\n```\n> 思路1\n******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)******\n\n由于数组是已经排序好的，这就是一个很典型的二分法\n\n```cpp\nclass Solution {\npublic:\n    int searchInsert(vector<int>& nums, int target) {\n        int first = 0,last = nums.size() - 1;\n        while(last > (first + 1))\n        {\n            int medium = (last + first) / 2;\n            if(nums[medium] == target)\n                return medium;\n            else if(nums[medium] < target)\n                first = medium;\n            else\n                last = medium;\n        }\n        if(target > nums[last])\n            return last + 1;\n        else if((target < nums[first]) || (target == nums[first]))\n            return first;\n        else\n            return last;\n    }\n};\n```\n> 思路2\n******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)******\n\n其实这个思路也是二分法，只不过c++中已经给我们封装好了lower_bound，我们直接调用即可\n代码看上去也简洁很多\n```cpp\nclass Solution {\npublic:\n    int searchInsert(vector<int>& nums, int target) {\n        auto pos = lower_bound(nums.begin(),nums.end(),target);\n        return pos - nums.begin();\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0036._Valid_Sudoku.md",
    "content": "# 36. Valid Sudoku\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/valid-sudoku/\n\n> \n\n```\nDetermine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:\n\nEach row must contain the digits 1-9 without repetition.\nEach column must contain the digits 1-9 without repetition.\nEach of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition.\nA partially filled sudoku which is valid.\n\nThe Sudoku board could be partially filled, where empty cells are filled with the character '.'.\nExample 1:\n\nInput:\n[\n  [\"5\",\"3\",\".\",\".\",\"7\",\".\",\".\",\".\",\".\"],\n  [\"6\",\".\",\".\",\"1\",\"9\",\"5\",\".\",\".\",\".\"],\n  [\".\",\"9\",\"8\",\".\",\".\",\".\",\".\",\"6\",\".\"],\n  [\"8\",\".\",\".\",\".\",\"6\",\".\",\".\",\".\",\"3\"],\n  [\"4\",\".\",\".\",\"8\",\".\",\"3\",\".\",\".\",\"1\"],\n  [\"7\",\".\",\".\",\".\",\"2\",\".\",\".\",\".\",\"6\"],\n  [\".\",\"6\",\".\",\".\",\".\",\".\",\"2\",\"8\",\".\"],\n  [\".\",\".\",\".\",\"4\",\"1\",\"9\",\".\",\".\",\"5\"],\n  [\".\",\".\",\".\",\".\",\"8\",\".\",\".\",\"7\",\"9\"]\n]\nOutput: true\nExample 2:\n\nInput:\n[\n  [\"8\",\"3\",\".\",\".\",\"7\",\".\",\".\",\".\",\".\"],\n  [\"6\",\".\",\".\",\"1\",\"9\",\"5\",\".\",\".\",\".\"],\n  [\".\",\"9\",\"8\",\".\",\".\",\".\",\".\",\"6\",\".\"],\n  [\"8\",\".\",\".\",\".\",\"6\",\".\",\".\",\".\",\"3\"],\n  [\"4\",\".\",\".\",\"8\",\".\",\"3\",\".\",\".\",\"1\"],\n  [\"7\",\".\",\".\",\".\",\"2\",\".\",\".\",\".\",\"6\"],\n  [\".\",\"6\",\".\",\".\",\".\",\".\",\"2\",\"8\",\".\"],\n  [\".\",\".\",\".\",\"4\",\"1\",\"9\",\".\",\".\",\"5\"],\n  [\".\",\".\",\".\",\".\",\"8\",\".\",\".\",\"7\",\"9\"]\n]\nOutput: false\nExplanation: Same as Example 1, except with the 5 in the top left corner being \n    modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.\nNote:\n\nA Sudoku board (partially filled) could be valid but is not necessarily solvable.\nOnly the filled cells need to be validated according to the mentioned rules.\nThe given board contain only digits 1-9 and the character '.'.\nThe given board size is always 9x9.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(1)******\n\nboard9x9ģʵʵʱ临ӶҲ9x9ġֻҪֱжÿÿкÿ9СǷظɡѶȲ\n\n\n```cpp\nclass Solution {\npublic:\n    bool isValidSudoku(vector<vector<char>>& board) {\n              int arr[9][9];\n        int arr1[9][9];\n        int arr2[9][9];\n        memset(arr,0,sizeof(arr));\n        memset(arr2,0,sizeof(arr1));\n        memset(arr1,0,sizeof(arr1));\n        for(int i = 0;i < 9;++i)\n            for(int j = 0;j < 9;++j)\n                if(board[i][j] != '.')\n                {\n                    if(arr[i][board[i][j] - '1'] || arr1[j][board[i][j] -'1'] ||  arr2[3 * (i / 3) + (j / 3)][board[i][j] -'1'])\n                     return 0;\n                    arr[i][board[i][j] - '1'] = 1;\n                    arr1[j][board[i][j] -'1'] = 1;\n                    arr2[3 * (i / 3) + (j / 3)][board[i][j] -'1'] = 1;\n                }\n        return 1;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0038._Count_and_Say.md",
    "content": "# 38. Count and Say\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/count-and-say/\n\n> \n\n```\nThe count-and-say sequence is the sequence of integers with the first five terms as following:\n\n1.     1\n2.     11\n3.     21\n4.     1211\n5.     111221\n1 is read off as \"one 1\" or 11.\n11 is read off as \"two 1s\" or 21.\n21 is read off as \"one 2, then one 1\" or 1211.\n\nGiven an integer n where 1  n  30, generate the nth term of the count-and-say sequence.\n\nNote: Each term of the sequence of integers will be represented as a string.\n\n\nExample 1:\n\nInput: 1\nOutput: \"1\"\nExample 2:\n\nInput: 4\nOutput: \"1211\"\n```\n\n> ˼·\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nҪŪĿ˼n == 1ʱ1һ1 one 1n == 2ʱǡ1121 two 1n == 3ʱǡ211211 one 2 one 1n == 4ʱǡ1211ƣдѭģĲɡ\n\n```cpp\nclass Solution {\npublic:\n    string countAndSay(int n) {\n        string str;\n        str.push_back('0' + 1);\n        n--;\n        while(n)\n        {\n            string temp;\n            for(int i = 0;i < str.length();)\n            {\n                int j = 0;\n                while(i + j < str.length() && str[i] == str[j + i])\n                    ++j;\n                temp.push_back('0' + j);\n                temp.push_back(str[i]);\n                i += j;\n            }\n            --n;\n            str = temp;\n        }\n        return str;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0039._Combination_Sum.md",
    "content": "# 39. Combination Sum\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/combination-sum/\n  \n > 内容描述\n \n ```\n给定一个无重复元素的数组 candidates 和一个目标数 target ，找出 candidates 中所有可以使数字和为 target 的组合。\n\ncandidates 中的数字可以无限制重复被选取。\n\n说明：\n\n所有数字（包括 target）都是正整数。\n解集不能包含重复的组合。 \n示例 1:\n\n输入: candidates = [2,3,6,7], target = 7,\n所求解集为:\n[\n  [7],\n  [2,2,3]\n]\n示例 2:\n\n输入: candidates = [2,3,5], target = 8,\n所求解集为:\n[\n  [2,2,2,2],\n  [2,3,3],\n  [3,5]\n]\n ```\n\n## 解题方案\n> 思路 1\n```\n回溯\n```\n\n```cpp\nvoid dfs(vector<int>& candidates, int target, int index, vector<int>& path, vector<vector<int>>& ans){\n    if(target<0)\n        return ;\n    if(target == 0){\n        ans.push_back(path);\n        return ;\n    }\n    for(int i=index;i<candidates.size();++i){\n        path.push_back(candidates[i]);\n        dfs(candidates, target-candidates[i], i, path, ans);\n        path.pop_back();\n    }\n    \n}\nvector<vector<int>> combinationSum(vector<int>& candidates, int target) {\n    sort(candidates.begin(), candidates.end());\n    vector<vector<int>> ans;\n    vector<int> path;\n    dfs(candidates, target, 0, path, ans);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0040._Combination_Sum_II.md",
    "content": "# 40. Combination Sum II\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/combination-sum-ii/\n  \n > 内容描述\n \n ```\n给定一个数组 candidates 和一个目标数 target ，找出 candidates 中所有可以使数字和为 target 的组合。\n\ncandidates 中的每个数字在每个组合中只能使用一次。\n\n说明：\n\n所有数字（包括目标数）都是正整数。\n解集不能包含重复的组合。 \n示例 1:\n\n输入: candidates = [10,1,2,7,6,1,5], target = 8,\n所求解集为:\n[\n  [1, 7],\n  [1, 2, 5],\n  [2, 6],\n  [1, 1, 6]\n]\n示例 2:\n\n输入: candidates = [2,5,2,1,2], target = 5,\n所求解集为:\n[\n  [1,2,2],\n  [5]\n]\n ```\n\n## 解题方案\n> 思路 1\n```\n回溯\n```\n\n```cpp\nvoid dfs(vector<int>& candidates, int target, int index, vector<int>& path, vector<vector<int>>& ans){\n    if(target<0)\n        return ;\n    if(target == 0){\n        ans.push_back(path);\n        return ;\n    }\n    for(int i=index;i<candidates.size();i++){\n        if (i > index && candidates[i] == candidates[i - 1]) continue;\n        path.push_back(candidates[i]);\n        dfs(candidates, target-candidates[i], i+1, path, ans);\n        path.pop_back();\n    }\n}\nvector<vector<int>> combinationSum2(vector<int>& candidates, int target) {\n    vector<vector<int>> ans;\n    vector<int> path;\n    sort(candidates.begin(), candidates.end());\n    dfs(candidates, target, 0, path, ans);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0041._First_Missing_Positive.md",
    "content": "# 041.First Missing Positive\n\n**<font color=red>ѶHard</font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/first-missing-positive/\n\n> \n\n```\nGiven an unsorted integer array, find the smallest missing positive integer.\n\nExample 1:\n\nInput: [1,2,0]\nOutput: 3\nExample 2:\n\nInput: [3,4,-1,1]\nOutput: 2\nExample 3:\n\nInput: [7,8,9,11,12]\nOutput: 1\n```\n> ˼·\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nտʼĿ˼ˣ֮ACˡʵĴռ䣬Ӧû뵽ֱ hash УǿԱ飬1ĵһ12ڣĵڶλӣ\n\n```cpp\nclass Solution {\npublic:\n    int firstMissingPositive(vector<int>& nums) {\n        if(!nums.size())\n            return 1;\n        for(int i = 0;i < nums.size();)\n        {\n            if(nums[i] < nums.size() && nums[i] != nums[nums[i] - 1])\n                swap(nums[i],nums[nums[i] - 1]);\n            else\n                ++i;\n        }\n        for(int i = 0;i < nums.size();++i)\n            if(nums[i] != i + 1)\n                return i + 1;\n        return nums.size() + 1;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0042._Trapping_Rain_Water.md",
    "content": "# 42. Trapping Rain Water\n\n**<font color=red>ѶHard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/trapping-rain-water/\n\n> \n\n```\nGiven n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.\n\nExample:\n\nInput: [0,1,0,2,1,0,1,3,2,1,2,1]\nOutput: 6\n```\n\n¼ l = 0飬 height[i] < height[l],˵λ޷ˮ¼޷ˮ height[i] >= height[l]˵[i,l]ڿԻˮȻȥ޷ˮǻˮ֮ l != height.size() - 1飬衣 \n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\n```cpp\nclass Solution {\npublic:\n    int trap(vector<int>& height) {\n        int l = 0,sum1 = 0,water = 0,i;\n        for(i = 1;i < height.size();++i)\n            if(height[i] >= height[l])\n            {\n                water = water + height[l] * (i - l - 1) - sum1;\n                l = i;\n                sum1 = 0;\n            }\n            else\n                sum1 += height[i];\n        if(l !=  (height.size() - 1))\n        {\n            int temp = l;\n            sum1 = 0;\n            for(i = height.size() - 2,l = height.size() - 1;i >= temp;--i)\n                if(height[i] >= height[l])\n                {\n                    water = water + height[l] * (l- i - 1) - sum1;\n                    l = i;\n                    sum1 = 0;\n                }\n                else\n                    sum1 += height[i];\n        }\n        return water;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0043._Multiply_Strings.md",
    "content": "# 43. Multiply Strings\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/multiply-strings/\n\n> \n\n```\nGiven two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.\n\nExample 1:\n\nInput: num1 = \"2\", num2 = \"3\"\nOutput: \"6\"\nExample 2:\n\nInput: num1 = \"123\", num2 = \"456\"\nOutput: \"56088\"\nNote:\n\nThe length of both num1 and num2 is < 110.\nBoth num1 and num2 contain only digits 0-9.\nBoth num1 and num2 do not contain any leading zero, except the number 0 itself.\nYou must not use any built-in BigInteger library or convert the inputs to integer directly.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(1)******\n\nֱȽϴ󳬹long longֵ˲ת֣ģֵĳ˷ÿһλ¼һַС\n\n```cpp\nclass Solution {\npublic:\n    string multiply(string num1, string num2) {\n                string ans;\n        int d[120][120];\n        memset(d,0,sizeof(d));\n        for(int i = num2.size() - 1;i >= 0;--i)\n        {\n            int count1 = 0;\n            for(int j = num1.size()- 1;j >= 0;--j)\n            {\n                int pro_ans = (num1[j] - '0') * (num2[i] - '0');\n                d[num2.size() - 1 - i][num1.size() - j - 1] = pro_ans % 10 + count1;\n                count1 = pro_ans / 10;\n                if(d[num2.size() - 1 - i][num1.size() - j - 1] >= 10)\n                {\n                    count1++;\n                    d[num2.size() - 1 - i][num1.size() - j - 1] %= 10;\n                }\n            }\n            d[num2.size() - 1 - i][num1.size()] = count1;\n        }\n        int count1 = 0;\n        for(int j = 0;j < num1.size() + num2.size();++j)\n        {\n            for(int i = 0;i <= num2.size();++i)\n                if(j - i >= 0  && j - i <= num1.size())\n                    count1 += d[i][j - i];\n            ans.push_back(count1 % 10 + '0');\n            count1 /= 10;\n        }\n        while(ans.length() > 1 && ans[ans.length() - 1] == '0')\n            ans.pop_back();\n        reverse(ans.begin(),ans.end());\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0044._Wildcard_Matching.md",
    "content": "# 44. Wildcard Matching\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/wildcard-matching/\n\n> \n\n```\nGiven an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*'.\n\n'?' Matches any single character.\n'*' Matches any sequence of characters (including the empty sequence).\nThe matching should cover the entire input string (not partial).\n\nNote:\n\ns could be empty and contains only lowercase letters a-z.\np could be empty and contains only lowercase letters a-z, and characters like ? or *.\nExample 1:\n\nInput:\ns = \"aa\"\np = \"a\"\nOutput: false\nExplanation: \"a\" does not match the entire string \"aa\".\nExample 2:\n\nInput:\ns = \"aa\"\np = \"*\"\nOutput: true\nExplanation: '*' matches any sequence.\nExample 3:\n\nInput:\ns = \"cb\"\np = \"?a\"\nOutput: false\nExplanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.\nExample 4:\n\nInput:\ns = \"adceb\"\np = \"*a*b\"\nOutput: true\nExplanation: The first '*' matches the empty sequence, while the second '*' matches the substring \"dce\".\nExample 5:\n\nInput:\ns = \"acdcb\"\np = \"a*c?b\"\nOutput: false\n```\n\n> ˼·\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n^2)******\n\nտʼʱΪһģ⣬ʱŷֿDPʹDPʱҵ״̬תƷ̡Ƕdp[i][j]ʾַ p е i - 1ĸ֮ǰַַ s еĵ j - 1ĸ֮ǰӴƥ䣬ǾͿдӦ״̬תƷ̵p[i] == '?'p[i] == s[j]ʱdp[i + 1][j + 1] = dp[i][j],p[i] == '*'ʱj < p.length(),dp[i + 1][j + 1] = dp[i][j],dp[i + 1][j] = dp[i][j],󷵻dp[p.length()][s.length() - 1]\n\n```cpp\nclass Solution {\npublic:\n    bool isMatch(string s, string p) {\n    if(!p.length())\n        return !s.length();\n    s.push_back(' ');\n    int dp[p.length() + 1][s.length() + 1];\n    for(int i =0;i <= p.length();++i)\n        for(int j = 0;j <= s.length();++j)\n            dp[i][j] = 0;\n\n    int count1 = 1;\n    dp[0][0] = 1;\n    for(int i = 0;i < p.length();++i)\n    {\n        for(int j  = 0;j < s.length();++j)\n            if(p[i] == '?' || p[i] == s[j])\n                    dp[i + 1][j + 1] = dp[i][j];\n            else if(p[i] == '*' && dp[i][j])\n            {\n                dp[i + 1][j + 1] = 1;\n                dp[i + 1][j] = 1;\n                ++j;\n                while(j < s.length())\n                {\n                    dp[i + 1][j + 1] = 1;\n                    ++j;\n                }\n            }\n    }\n        return dp[p.length()][s.length() - 1];\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0045._Jump_Game_II.md",
    "content": "# 045. Jump Game II\n\n**<font color=red>ѶHard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/jump-game-ii/\n\n> \n\n```\nGiven an array of non-negative integers, you are initially positioned at the first index of the array.\n\nEach element in the array represents your maximum jump length at that position.\n\nYour goal is to reach the last index in the minimum number of jumps.\n\nExample:\n\nInput: [2,3,1,1,4]\nOutput: 2\nExplanation: The minimum number of jumps to reach the last index is 2.\n    Jump 1 step from index 0 to 1, then 3 steps to the last index.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(n)*****- ռ临Ӷ: O(1)******\n\nտʼ뵽ʹö̬滮ʱ临ӶΪO(n)TLEˣʵO(n)ʱ临Ӷɵġ飬ÿζߵnums[i]ķΧߵԶľ롣¼ans\n```cpp\nclass Solution {\npublic:\n    int jump(vector<int>& nums) {\n        int i = 0,length = nums.size(),next = nums[0],ans = 0;\n        if(length < 2)\n            return 0;\n        while(i < length)\n        {\n             ++ans;\n            if(next >= length - 1)\n                    return ans;\n            int current = i;\n            for(int j = current+1;j <= min(next,length - 1);++j)\n            {\n                i = max(i,nums[j] + j);\n                cout << i << \" \";\n            }\n            swap(i,next);\n            cout << i << \" \"<< next << endl;\n        }\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0046._Permutations.md",
    "content": "# 46. Permutations\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/permutations/\n\n> \n\n```\nGiven a collection of distinct integers, return all possible permutations.\n\nExample:\n\nInput: [1,2,3]\nOutput:\n[\n  [1,2,3],\n  [1,3,2],\n  [2,1,3],\n  [2,3,1],\n  [3,1,2],\n  [3,2,1]\n]\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n!*n)******- ռ临Ӷ: O(n)******\n\nܲĿݹһ⣬ÿζһ֮ɡ\n\n```cpp\nclass Solution {\npublic: \n   vector<vector<int>> permute(vector<int>& nums) {\n        vector<vector<int> > ans;\n        if(!nums.size())\n            return ans;\n        if(nums.size() == 1)\n            ans.push_back(nums);\n        for(int i = 0;i < nums.size();++i)\n       {\n            swap(nums[0],nums[i]);\n            vector<int> v(nums.begin() + 1,nums.end());\n            vector<vector<int> > ret = permute(v);\n            for(int i = 0;i < ret.size();++i)\n            {\n                ret[i].push_back(nums[0]);\n                ans.push_back(ret[i]);\n            }\n            swap(nums[0],nums[i]);\n        }\n        return ans;\n    }\n};\n```\n> ˼·2\n******- ʱ临Ӷ: O(n!)******- ռ临Ӷ: O(n)******\n\nǿԶ㷨ŻDFSķÿμ¼Ѿֽеݹ鼴\n\n```cpp\nclass Solution {\npublic: \nvoid DFS(int* visited,vector<int>& nums,vector<vector<int> >& ans,vector<int> temp)\n{\n    int count1 = 0;\n    for(int i = 0;i < nums.size();++i)\n        if(!visited[i])\n        {\n            temp.push_back(nums[i]);\n            visited[i] = 1;\n            DFS(visited,nums,ans,temp);\n            temp.pop_back();\n            visited[i] = 0;\n            count1 = 1;\n        }\n    if(!count1)\n        ans.push_back(temp);\n}\nvector<vector<int>> permute(vector<int>& nums) {\n        vector<vector<int> > ans;\n        int visited[nums.size()];\n        memset(visited,0,sizeof(visited));\n        vector<int> temp;\n        for(int i = 0; i < nums.size();++i)\n        {\n            visited[i] = 1;\n            temp.push_back(nums[i]);\n            DFS(visited,nums,ans,temp);\n            temp.pop_back();\n            visited[i] = 0;\n        }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0047._Permutations_II.md",
    "content": "# 47. Permutations II\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/permutations-ii/\n\n> \n\n```\nGiven a collection of numbers that might contain duplicates, return all possible unique permutations.\n\nExample:\n\nInput: [1,1,2]\nOutput:\n[\n  [1,1,2],\n  [1,2,1],\n  [2,1,1]\n]\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n!*nlgn)******- ռ临Ӷ: O(n)******\n\nǰǵеƣԲο֮ǰĽ֮ⷨǰĿֱӾsetȥˣȻͨˣʱ临ӶȱȽϸߣҪŻ\n\n```cpp\nclass Solution {\npublic:\n    void DFS(int* visited,vector<int>& nums,set<vector<int> >& ans,vector<int> temp)\n    {\n         int count1 = 0;\n    for(int i = 0;i < nums.size();++i)\n        if(!visited[i])\n        {\n            temp.push_back(nums[i]);\n            visited[i] = 1;\n            DFS(visited,nums,ans,temp);\n            temp.pop_back();\n            visited[i] = 0;\n            count1 = 1;\n        }\n    if(!count1)\n        ans.insert(temp);\n    }\n    vector<vector<int>> permuteUnique(vector<int>& nums) {\n               vector<vector<int> > ans;\n        int visited[nums.size()];\n        memset(visited,0,sizeof(visited));\n        set<vector<int> > s;\n        vector<int> temp;\n        for(int i = 0; i < nums.size();++i)\n        {\n            visited[i] = 1;\n            temp.push_back(nums[i]);\n            DFS(visited,nums,s,temp);\n            temp.pop_back();\n            visited[i] = 0;\n        }\n        for(auto pos = s.begin();pos != s.end();++pos)\n            ans.push_back(*pos);\n        return ans;\n    }\n};\n```\n> ˼·2\n******- ʱ临Ӷ: O(n!)******- ռ临Ӷ: O(n)******\n\n֮ǰǵľ顣ҲͨDFSķȥ⣬и⣬ͬ־ͻظȶͬ־ͻһȻDFSʱǴҽеģ˵һ֮ǰȲ֮ǰѾˣôǾͲ\n\n```cpp\nclass Solution {\npublic:\n    vector<vector<int>> permuteUnique(vector<int>& nums) {\n        const int n = nums.size();\n        sort(nums.begin(), nums.end());\n        vector<vector<int>> ret;\n        vector<int> visited(n, 0), arr;\n        dfs(nums, ret, arr, visited);\n        return ret;\n    }\n    void dfs(vector<int>& nums, vector<vector<int>>& ret, vector<int>& arr, vector<int>& visited) {\n        if (arr.size() == nums.size()) {\n            ret.push_back(arr);\n            return;\n        }\n        for (int i = 0; i < nums.size(); ++i) {\n            if (visited[i]) {continue;}\n            if (i -1 >= 0 && nums[i] == nums[i-1] && !visited[i-1]) {continue;}\n            arr.push_back(nums[i]);\n            visited[i] = 1;\n            dfs(nums, ret, arr, visited);\n            arr.pop_back();\n            visited[i] = 0;\n        }\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0048._Rotate_Image.md",
    "content": "# 49. Group Anagrams\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode.com/problems/rotate-image/submissions/\n  \n > 内容描述\n \n ```\n给你一个矩阵，让你顺时针旋转90° 思路： 不讨论复制一个数组然后在旋转的方法，因为太简单了。 下面的方法都是in-place的：。\n\n示例:\n\n输入:\n[\n  [1,2,3],\n  [4,5,6],\n  [7,8,9]\n],\n\n输出:\n[\n  [7,4,1],\n  [8,5,2],\n  [9,6,3]\n]\n说明：\n\n必须直接修改输入的2D矩阵。 \n不要分配另一个2D矩阵并进行旋转。\n ```\n\n## 解题方案\n> 思路 1\n```\n直接设置top, bottom, left, right四个变量，表示圈定当前要旋转的正方形范围，\n然后按偏移计算位置，比如左上角的先和右上角交换，然后继续左上角和右下角交换这样即可.\n```\n\n```cpp\nclass Solution {\npublic:\n    void rotate(vector<vector<int>>& matrix) {\n        if(matrix.empty())\n            return;\n        int top = 0, bottom = matrix.size() - 1;\n        int left = 0, right = matrix[0].size() - 1;\n        for(;top < bottom && left < right; ++top, ++left, --bottom, --right){\n            for(int i = left; i < right; ++i){\n                int dis = i - left;\n                \n                int row = top + dis;\n                int col = right;\n                swap(matrix[top][i], matrix[row][col]);\n                \n                row = bottom;\n                col = right - dis;\n                swap(matrix[top][i], matrix[row][col]);\n                \n                row = bottom - dis;\n                col = left;\n                swap(matrix[top][i], matrix[row][col]);\n            }\n        }\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0049._Group_Anagrams.md",
    "content": "# 49. Group Anagrams\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/group-anagrams/submissions/\n  \n > 内容描述\n \n ```\n给定一个字符串数组，将字母异位词组合在一起。字母异位词指字母相同，但排列不同的字符串。\n\n示例:\n\n输入: [\"eat\", \"tea\", \"tan\", \"ate\", \"nat\", \"bat\"],\n输出:\n[\n  [\"ate\",\"eat\",\"tea\"],\n  [\"nat\",\"tan\"],\n  [\"bat\"]\n]\n说明：\n\n所有输入均为小写字母。\n不考虑答案输出的顺序。\n ```\n\n## 解题方案\n> 思路 1\n```\n不同的组别字符串元素相同，顺序不同，所以排序后相同\n把排序后相同的元素映射到同一个vector\n所有vector的组合就是结果\n```\n\n```cpp\nvector<vector<string>> groupAnagrams(vector<string>& strs) {\n    vector<vector<string>> ans;\n    map<string, vector<string>> maps;\n    for(int i=0;i<strs.size();i++){\n        string tmp = strs[i];\n        sort(tmp.begin(), tmp.end());\n        maps[tmp].push_back(strs[i]);\n    }\n    for(auto item:maps){\n        ans.push_back(item.second);\n    }\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0050._powx_n.md",
    "content": "# 50. powx n\n\n**<font color=red>难度:Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/powx-n/\n\n> 内容描述\n\n```\nmplement pow(x, n), which calculates x raised to the power n (xn).\n\nExample 1:\n\nInput: 2.00000, 10\nOutput: 1024.00000\nExample 2:\n\nInput: 2.10000, 3\nOutput: 9.26100\nExample 3:\n\nInput: 2.00000, -2\nOutput: 0.25000\nExplanation: 2-2 = 1/22 = 1/4 = 0.25\nNote:\n\n-100.0 < x < 100.0\nn is a 32-bit signed integer, within the range [?2^31, 2^31 ? 1]\n```\n\n> 思路1\n******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)******\n\n求一个数的n次方是我们经常用的函数，一般刚开始可能会用暴力的方法去求，做了n次循环，但由于这里的n非常大，单纯的暴力会TLE，这里可以用分治的思想，比如``2*2*2*2``，我们前面已经计算过``2*2``了，那么后面就不用再计算依次，就相当于``2*2*（2*2）``,这样时间复杂度就变成了lgN，接下来只要主要幂次是负数的情况即可\n\n```cpp\nclass Solution {\npublic:\n    double Pow(double x, long long n)\n    {\n        if(!n)\n            return 1;\n        if(n == 1)\n            return x;\n        double temp = Pow(x,(n)/ 2);\n         double ret;\n        if(n&1)\n            ret = temp * temp * x;\n        else\n            ret = temp * temp;\n        return ret;\n    }\n    double myPow(double x, int n) {\n        long long k = n;\n        if(n < 0)\n            x = 1 / x;\n        return Pow(x,n);\n        }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0051._N-Queens.md",
    "content": "# 51. N-Queens\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/n-queens/\n\n> \n\n```\nThe n-queens puzzle is the problem of placing n queens on an nn chessboard such that no two queens attack each other.\n\n\n\nGiven an integer n, return all distinct solutions to the n-queens puzzle.\n\nEach solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.\n\nExample:\n\nInput: 4\nOutput: [\n [\".Q..\",  // Solution 1\n  \"...Q\",\n  \"Q...\",\n  \"..Q.\"],\n\n [\"..Q.\",  // Solution 2\n  \"Q...\",\n  \"...Q\",\n  \".Q..\"]\n]\nExplanation: There exist two distinct solutions to the 4-queens puzzle as shown above.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(2^n)******- ռ临Ӷ: O(n)******\n\nûݷȥ⡣ʵľͼʵľͻˣֱ¼ֱбϷбϷǷлʺ\n\n```cpp\nclass Solution {\npublic:\n    void travel(int* d,vector<string>& ret,int level,int n,vector<vector<string> >& ans,int* l,int* r)\n    {\n        if(level >= n)\n            ans.push_back(ret);\n        for(int i = 0;i < n;++i)\n            if(!d[i] && !r[level + i] && !l[i - level + n])\n            {\n                d[i] = 1;\n                r[level + i] = 1;\n                l[i- level + n] = 1;\n                ret[level][i] = 'Q';\n                travel(d,ret,level + 1,n,ans,l,r);\n                d[i] = 0;\n                r[level + i] = 0;\n                l[i- level + n] = 0;\n                ret[level][i] = '.';\n            }\n    }\n    vector<vector<string>> solveNQueens(int n) {\n        int d[n];\n        int l[2 * n];\n        int r[2 * n];\n        memset(d,0,sizeof(d));\n        memset(l,0,sizeof(l));\n        memset(r,0,sizeof(r));\n        vector<string> temp;\n        vector<vector<string> > ans;\n        string s(n,'.');\n        for(int i = 0;i < n;++i)\n            temp.push_back(s);\n        for(int i = 0;i < n;++i)\n        {\n            temp[0][i] ='Q';\n            d[i] = 1;\n            r[i] = 1;\n            l[i + n] = 1;\n            travel(d,temp,1,n,ans,l,r);\n            temp[0][i] = '.';\n            d[i] = 0;\n            r[i] = 0;\n            l[i + n] = 0;\n        }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0052._N-Queens_II.md",
    "content": "# 52. N-Queens II\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/n-queens-ii/\n\n> \n\n```\nThe n-queens puzzle is the problem of placing n queens on an nn chessboard such that no two queens attack each other.\n\n\n\nGiven an integer n, return the number of distinct solutions to the n-queens puzzle.\n\nExample:\n\nInput: 4\nOutput: 2\nExplanation: There are two distinct solutions to the 4-queens puzzle as shown below.\n[\n [\".Q..\",  // Solution 1\n  \"...Q\",\n  \"Q...\",\n  \"..Q.\"],\n\n [\"..Q.\",  // Solution 2\n  \"Q...\",\n  \"...Q\",\n  \".Q..\"]\n]\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(2^n)******- ռ临Ӷ: O(n)******\n\nһһֻ΢Ķһ¾ͺãĲ˵\n\n```cpp\nclass Solution {\npublic:\n    int travel(int* d,int level,int n,int* l,int* r)\n    {\n        if(level >= n)\n            return 1;\n        int ans = 0;\n        for(int i = 0;i < n;++i)\n            if(!d[i] && !r[level + i] && !l[i - level + n])\n            {\n                d[i] = 1;\n                r[level + i] = 1;\n                l[i- level + n] = 1;\n                ans += travel(d,level + 1,n,l,r);\n                d[i] = 0;\n                r[level + i] = 0;\n                l[i- level + n] = 0;\n            }\n        return ans;\n    }\n    int totalNQueens(int n) {\n        int d[n];\n        int l[2 * n];\n        int r[2 * n];\n        memset(d,0,sizeof(d));\n        memset(l,0,sizeof(l));\n        memset(r,0,sizeof(r));\n        int ans = 0;\n        for(int i = 0;i < n;++i)\n        {\n            d[i] = 1;\n            r[i] = 1;\n            l[i + n] = 1;\n            ans += travel(d,1,n,l,r);\n            d[i] = 0;\n            r[i] = 0;\n            l[i + n] = 0;\n        }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0053._Maximum_Subarray.md",
    "content": "# 053. Maximum Subarray\n\n**<font color=red>ѶEasy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/maximum-subarray/\n\n> \n\n```\nGiven an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.\n\nExample:\n\nInput: [-2,1,-3,4,-1,2,1,-5,4],\nOutput: 6\nExplanation: [4,-1,2,1] has the largest sum = 6.\nFollow up:\n\nIf you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(lgn)*****- ռ临Ӷ: O(1)******\n\nñķȥ⣬󲿷˶뵽ǿԶ㷨Ż÷η˼룬԰Ϊ飬ֵ[left,mid]䣬[mid + 1,right]ںmidڣֻҪȡֵɡ\n```cpp\nclass Solution {\npublic:\n    int findArray(vector<int>& nums,int beg,int en)\n    {\n        if(beg == en)\n            return nums[en];\n        int mid = (beg + en) / 2;\n        int temp = max(findArray(nums,beg,mid),findArray(nums,mid + 1,en));\n        int sum = 0,max1 = INT_MIN,max2 = INT_MIN;\n        for(int i = mid;i >= beg;--i)\n        {\n            sum += nums[i];\n            max1 = max(max1,sum);\n        }\n        sum = 0;\n        for(int i = mid + 1;i <= en;++i)\n        {\n            sum += nums[i];\n            max2 = max(max2,sum);\n        }\n        return max(temp,max1 + max2);\n    }\n    int maxSubArray(vector<int>& nums) {\n        return findArray(nums,0,nums.size() - 1);\n    }\n};\n```\n> ˼·2\n******- ʱ临Ӷ: O(n)*****- ռ临Ӷ: O(1)******\n\nﻹO(n)ʱ临Ӷ⣬飬ret > 0,ret =nums[i]\nret += nums[i]\n\n```cpp\nclass Solution {\npublic:\n    int maxSubArray(vector<int>& nums) {\n        int length = nums.size(),ret = nums[0],ans = nums[0];\n    for(int i = 1;i < length;++i)\n    {\n        if(ret <= 0)\n            ret = nums[i];\n        else\n            ret += nums[i];\n        ans = max(ans,ret);\n    }\n    return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0054._Spiral_Matrix.md",
    "content": "# 54. Spiral Matrix\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/spiral-matrix/submissions/\n\n> \n\n```\nGiven a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.\n\nExample 1:\n\nInput:\n[\n [ 1, 2, 3 ],\n [ 4, 5, 6 ],\n [ 7, 8, 9 ]\n]\nOutput: [1,2,3,6,9,8,7,4,5]\nExample 2:\n\nInput:\n[\n  [1, 2, 3, 4],\n  [5, 6, 7, 8],\n  [9,10,11,12]\n]\nOutput: [1,2,3,4,8,12,11,10,9,5,6,7]\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n*m)******- ռ临Ӷ: O(1)******\n\n飬ҵɾУûʲôѶ\n\n```cpp\nclass Solution {\npublic:\n    vector<int> spiralOrder(vector<vector<int>>& matrix) {\n        vector<int> ans;\n        if(!matrix.size())\n            return ans;\n        int row = matrix[0].size(),colunm = matrix.size();\n        for(int i = 0;i < (matrix.size() + 1) / 2;++i)\n        {\n            if(row < 1 || colunm < 1)\n                break;\n            for(int j = 0;j < row;++j)\n                ans.push_back(matrix[i][i + j]);\n            if(colunm <= 1)\n                break;\n            for(int j = 1;j < colunm;++j)\n                ans.push_back(matrix[i + j][row + i - 1]);\n            if(row <= 1)\n                break;\n            for(int j = 1;j < row;++j)\n                ans.push_back(matrix[i + colunm - 1][row + i - 1 - j]);\n            for(int j = 1;j < colunm - 1;++j)\n                ans.push_back(matrix[i + colunm - 1 - j][i]);\n            row -= 2;\n            colunm -= 2;\n        }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0055._Jump_Game.md",
    "content": "# 55. Jump Game\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/jump-game/submissions/\n\n> \n\n```\nGiven an array of non-negative integers, you are initially positioned at the first index of the array.\n\nEach element in the array represents your maximum jump length at that position.\n\nDetermine if you are able to reach the last index.\n\nExample 1:\n\nInput: [2,3,1,1,4]\nOutput: true\nExplanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.\nExample 2:\n\nInput: [3,2,1,0,4]\nOutput: false\nExplanation: You will always arrive at index 3 no matter what. Its maximum\n             jump length is 0, which makes it impossible to reach the last index.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\nտʼ뵽ľDPķDPĻʱ临ӶΪO(n^2)ȻǿԶ㷨Ż,ʱ临ӶO(n)ɡֻҪжÿһߵԶľ뼴ɣ[2,3,1,1,4]һֻߵ0ڶ[12]ԶľΪ4\n\n```cpp\nclass Solution {\npublic:\n    bool canJump(vector<int>& nums) {\n        if(nums.size() <= 1)\n            return 1;\n        for(int i = 0,r = 0;i < nums.size() - 1;)\n        {\n            int max1 = 0;\n            while(i <= r)\n            {\n                max1 = max(max1,i + nums[i]);\n                ++i;\n            }\n            //cout << max1 << endl;\n            if(max1 >= nums.size() - 1)\n                return 1;\n            if(max1 <= r)\n                return 0;\n            r = max1;\n        }\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0056._Merge_Intervals.md",
    "content": "# 56. Merge Intervals\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/merge-intervals/\n\n> \n\n```\nGiven a collection of intervals, merge all overlapping intervals.\n\nExample 1:\n\nInput: [[1,3],[2,6],[8,10],[15,18]]\nOutput: [[1,6],[8,10],[15,18]]\nExplanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].\nExample 2:\n\nInput: [[1,4],[4,5]]\nOutput: [[1,5]]\nExplanation: Intervals [1,4] and [4,5] are considered overlapping.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(nlgn)******- ռ临Ӷ: O(1)******\n\nҪȶ򣬰start򡣽ͱõ飬ཻͽ䶼ansཻͽϲĲans\n\n```cpp\n/**\n * Definition for an interval.\n * struct Interval {\n *     int start;\n *     int end;\n *     Interval() : start(0), end(0) {}\n *     Interval(int s, int e) : start(s), end(e) {}\n * };\n */\nclass Solution {\npublic:\n    vector<Interval> merge(vector<Interval>& intervals) {\n         vector<Interval> ans;\n        if(!intervals.size())\n            return ans;\n        sort(intervals.begin(),intervals.end(),[](Interval a, Interval b){return a.start < b.start;});\n        for(int i = 0;i < intervals.size() - 1;++i)\n            if(intervals[i + 1].start <= intervals[i].end)\n            {\n                intervals[i + 1].start = intervals[i].start;\n                intervals[i].end = max(intervals[i].end,intervals[i + 1].end);\n                intervals[i + 1].end = intervals[i].end;\n            }\n            else\n                ans.push_back(intervals[i]);\n        ans.push_back(intervals[intervals.size() - 1]);\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0057._Insert_Interval.md",
    "content": "# 57. Insert Interval\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/insert-interval/\n\n> \n\n```\nGiven a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).\n\nYou may assume that the intervals were initially sorted according to their start times.\n\nExample 1:\n\nInput: intervals = [[1,3],[6,9]], newInterval = [2,5]\nOutput: [[1,5],[6,9]]\nExample 2:\n\nInput: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]\nOutput: [[1,2],[3,10],[12,16]]\nExplanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)******\n\nȼԭеλá飬αȽ䡣¼ l rֱҪӵյ㡣õλ֮ҵ intervals[i].end < l,ӽ飬[l,r] intervals[i].start > r䡣 \n\n```cpp\n/**\n * Definition for an interval.\n * struct Interval {\n *     int start;\n *     int end;\n *     Interval() : start(0), end(0) {}\n *     Interval(int s, int e) : start(s), end(e) {}\n * };\n */\nclass Solution {\npublic:\n    vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {\n         int beg = newInterval.start,en = newInterval.end,l = beg,r = en;\n        int comp = beg;\n        for(int i = 0;i < intervals.size();++i)\n        {\n            if(comp < intervals[i].start)\n            {\n                comp == beg ? l = beg : r = en;\n                comp = comp == beg ? en : beg;\n                if(comp == en && en < intervals[i].start)\n                {\n                    r = en;\n                    break;\n                }\n                if(comp == beg)\n                    break;\n            }\n            if(comp <= intervals[i].end)\n            {\n\n                comp == beg ? l = intervals[i].start : r = intervals[i].end;\n                comp = comp == beg ? en : beg;\n                if(comp == en && en <= intervals[i].end)\n                {\n                    r = intervals[i].end;\n                    break;\n                }\n                if(comp == beg)\n                    break;\n            }\n        }\n        int i = 0;\n        vector<Interval> ans;\n        for(;i < intervals.size();++i)\n            if(intervals[i].end < l)\n                ans.push_back(intervals[i]);\n            else\n                break;\n        Interval i1(l,r);\n        ans.push_back(i1);\n        for(;i < intervals.size();++i)\n            if(intervals[i].start > r)\n                break;\n        for(;i < intervals.size();++i)\n            ans.push_back(intervals[i]);\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0058._Length_of_Last_Word.md",
    "content": "# 058. Length of Last Word\n\n**<font color=red>难度Easy<font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/length-of-last-word/\n\n> 内容描述\n\n```\nGiven a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string.\n\nIf the last word does not exist, return 0.\n```\n\n> 思路\n******- 时间复杂度: O(n)*****- 空间复杂度: O(1)******\n\n这题我们只要从字符串的末尾开始向前找到第一个单词即可\n```cpp\nclass Solution {\npublic:\n    int lengthOfLastWord(string s) {\n        int i = s.length() - 1,length = s.length() - 1;\n        while((s[i] == ' ') &&(i >= 0))\n        {\n            --i;\n            --length;\n        }\n        while((s[i] != ' ') && (i >= 0))\n            --i;\n        return length- i;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0059._Spiral_Matrix_II.md",
    "content": "# 59. Spiral Matrix II\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/spiral-matrix-ii/\n\n> \n\n```\nGiven a positive integer n, generate a square matrix filled with elements from 1 to n2 in spiral order.\n\nExample:\n\nInput: 3\nOutput:\n[\n [ 1, 2, 3 ],\n [ 8, 9, 4 ],\n [ 7, 6, 5 ]\n]\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n^2)******\n\n֮ǰתһķֻҪȷһ󴢴棬Ϊvector鲻ò\n\n```cpp\nclass Solution {\npublic:\n    vector<vector<int>> generateMatrix(int n) {\n        int temp[n][n];\n        int range = n,cur = 1;\n        for(int i = 0;i < (n + 1) / 2 ;++i)\n        {\n            for(int j = 0;j < range;++j)\n                temp[i][j + i] = cur++;\n            for(int j = 1;j < range;++j)\n                temp[i + j][i + range - 1] = cur++;\n            for(int j = 1;j < range;++j)\n                temp[i + range - 1][range + i - 1 -j] = cur++;\n            for(int j = 1;j < range - 1;++j)\n                temp[range + i - 1 - j][i] = cur++;\n            range -= 2;\n        }\n        vector<vector<int> > ans;\n        for(int i = 0;i < n;++i)\n        {\n            vector<int> v;\n            for(int j = 0;j < n;++j)\n                v.push_back(temp[i][j]);\n            ans.push_back(v);\n        }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0060._Permutation_Sequence.md",
    "content": "# 60. Permutation Sequence\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/permutation-sequence/\n\n> \n\n```\nThe set [1,2,3,...,n] contains a total of n! unique permutations.\n\nBy listing and labeling all of the permutations in order, we get the following sequence for n = 3:\n\n\"123\"\n\"132\"\n\"213\"\n\"231\"\n\"312\"\n\"321\"\nGiven n and k, return the kth permutation sequence.\n\nNote:\n\nGiven n will be between 1 and 9 inclusive.\nGiven k will be between 1 and n! inclusive.\nExample 1:\n\nInput: n = 3, k = 3\nOutput: \"213\"\nExample 2:\n\nInput: n = 4, k = 9\nOutput: \"2314\"\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n)******\n\nȽ˳иַУȻѭnΣÿҵȷearseʱ临ӶΪnܵʱ临ӶΪn^2\n\n```cpp\nclass Solution {\npublic:\n    string getPermutation(int n, int k){\n        int arr[n + 1];\n        string ans,org;\n        for(int i = 1;i <= n;++i)\n        {\n            org.push_back(i + '0');\n            i == 1 ? arr[i] = 1 : arr[i] = arr[i - 1] * i;\n        }\n        for(int i = n - 1;i > 0;--i)\n        {\n            int t = k / arr[i];\n            cout<< t<< endl;\n            k = (k) % arr[i];\n            if(!k)\n            {\n                k = arr[i];\n                t--;\n            }\n            ans.push_back(org[t]);\n            org.erase(org.begin() + t);\n            arr[i] = 0;\n        }\n        ans.push_back(org[0]);\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0061._Rotate_List.md",
    "content": "# 61. Rotate List\n\n\n\n**<font color=red>Ѷ:Medium<font>**\n\n\n\n## ˢ\n\n> ԭ\n\n\n* https://leetcode.com/problems/rotate-list/\n\n\n\n> \n\n\n\n```\n\nGiven a linked list, rotate the list to the right by k places, where k is non-negative.\n\n\n\nExample 1:\n\n\n\nInput: 1->2->3->4->5->NULL, k = 2\n\nOutput: 4->5->1->2->3->NULL\n\nExplanation:\n\nrotate 1 steps to the right: 5->1->2->3->4->NULL\n\nrotate 2 steps to the right: 4->5->1->2->3->NULL\n\n\nExample 2:\n\n\nInput: 0->1->2->NULL, k = 4\n\nOutput: 2->0->1->NULL\n\nExplanation:\n\nrotate 1 steps to the right: 2->0->1->NULL\n\nrotate 2 steps to the right: 1->2->0->NULL\n\nrotate 3 steps to the right: 0->1->2->NULL\n\nrotate 4 steps to the right: 2->0->1->NULL\n\n```\n\n\n\n> ˼·1\n\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)******\n\n\n\nnָĳȣknĳȡ࣬Ϊkĳ֮һѭҪظ\n\n\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode* rotateRight(ListNode* head, int k) {\n        int len = 0;\n        ListNode* h = head;\n        ListNode* pre;\n        while(h)\n        {\n            ++len;\n            pre = h;\n            h = h ->next;\n        }\n        if(!len)\n            return head;    \n        int count1 = len - k % len;\n        if(count1 == len)\n            return head;\n        h = head;\n        ListNode* tail;\n        while(count1)\n        {\n            tail = h;\n            h = h ->next;\n            --count1;\n        }\n        pre ->next = head;\n        tail ->next = nullptr;\n        return h;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0062._Unique_Paths.md",
    "content": "# 62. Unique Paths\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/unique-paths/\n  \n > 内容描述\n \n ```\n一个机器人位于一个 m x n 网格的左上角 （起始点在下图中标记为“Start” ）。\n\n机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角（在下图中标记为“Finish”）。\n\n问总共有多少条不同的路径？\n\n\n\n例如，上图是一个7 x 3 的网格。有多少可能的路径？\n\n说明：m 和 n 的值均不超过 100。\n\n示例 1:\n\n输入: m = 3, n = 2\n输出: 3\n解释:\n从左上角开始，总共有 3 条路径可以到达右下角。\n1. 向右 -> 向右 -> 向下\n2. 向右 -> 向下 -> 向右\n3. 向下 -> 向右 -> 向右\n示例 2:\n\n输入: m = 7, n = 3\n输出: 28\n ```\n\n## 解题方案\n> 思路 1\n```\n动态规划，走到(i,j)可以从(i-1,j),(i, j-1)两个方向\n最优子结构：\n    dp[i, j] = dp[i-1, j]+dp[i, j-1]\n```\n\n```cpp\nint uniquePaths(int m, int n) {\n    vector<vector<int>> dp(m, vector<int>(n, 0));\n    for(int i=0;i<m;i++)\n        dp[i][0] = 1;\n    for(int i=0;i<n;i++)\n        dp[0][i] = 1;\n    for(int i=1;i<m;i++){\n        for(int j=1;j<n;j++){\n            dp[i][j]=dp[i-1][j]+dp[i][j-1];\n        }\n    }\n    return dp[m-1][n-1];\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0063._Unique_Paths_II.md",
    "content": "# 63. Unique Paths II\n\n**<font color=red>难度:Medium<font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/unique-paths-ii/\n\n> 内容描述\n\n```\nA robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).\n\nThe robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).\n\nNow consider if some obstacles are added to the grids. How many unique paths would there be?\n\n\n\nAn obstacle and empty space is marked as 1 and 0 respectively in the grid.\n\nNote: m and n will be at most 100.\n\nExample 1:\n\nInput:\n[\n  [0,0,0],\n  [0,1,0],\n  [0,0,0]\n]\nOutput: 2\nExplanation:\nThere is one obstacle in the middle of the 3x3 grid above.\nThere are two ways to reach the bottom-right corner:\n1. Right -> Right -> Down -> Down\n2. Down -> Down -> Right -> Right\n\n```\n\n\n> 思路1\n\n******- 时间复杂度: O(n^2)******- 空间复杂度: O(n^2)******\n\n运用动态规划的思想，写出状态转移方程，d(i,j) = d(i + 1,j) + d(i,j + 1)，不过要注意边界值\n\n```cpp\nclass Solution {\npublic:\n    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {\n        int length1 = obstacleGrid.size(),length2 = obstacleGrid[0].size();\n        long long dp[length1][length2];\n        memset(dp,0,sizeof(dp));\n        for(int i = length1 - 1;i >= 0;--i)\n            for(int j = length2 - 1;j >= 0;--j)\n            {\n                if(!obstacleGrid[i][j])\n                {\n                    if(i == length1 - 1 && j == length2 - 1)\n                    dp[i][j] = 1;\n                else\n                {\n                    if(i == length1 - 1)\n                        dp[i][j] = dp[i][j + 1];\n                    else if(j == length2 - 1)\n                        dp[i][j] = dp[i + 1][j];\n                    else\n                        dp[i][j] = dp[i][j + 1] + dp[i + 1][j];\n                }\n            }\n        }\n    return dp[0][0];\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0064._Minimum_Path_Sum.md",
    "content": "# 64. Minimum Path Sum\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/minimum-path-sum/\n  \n > 内容描述\n \n ```\n给定一个包含非负整数的 m x n 网格，请找出一条从左上角到右下角的路径，使得路径上的数字总和为最小。\n\n说明：每次只能向下或者向右移动一步。\n\n示例:\n\n输入:\n[\n  [1,3,1],\n  [1,5,1],\n  [4,2,1]\n]\n输出: 7\n解释: 因为路径 1→3→1→1→1 的总和最小。\n ```\n\n## 解题方案\n> 思路 1\n```\ndp:\n1. 首行首列的路径只有一种，累加\n2. 其他都有两种方法，走到i，j的最小路径等于min(sum[i][j-1], sum[i-1][j])+grid[i][j]\n```\n\n```cpp\nint minPathSum(vector<vector<int>>& grid) {\n    int m = grid.size(), n = grid[0].size();\n    int dp[m][n];\n    dp[0][0] = grid[0][0];\n    for (int i = 1; i < m; ++i) dp[i][0] = grid[i][0] + dp[i - 1][0];\n    for (int i = 1; i < n; ++i) dp[0][i] = grid[0][i] + dp[0][i - 1];\n    for (int i = 1; i < m; ++i) {\n        for (int j = 1; j < n; ++j) {\n            dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]);\n        }\n    }\n    return dp[m - 1][n - 1];\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0065._Valid_Number.md",
    "content": "# 65. Valid Number\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/valid-number/\n\n> \n\n```\nValidate if a given string can be interpreted as a decimal number.\n\nSome examples:\n\"0\" => true\n\" 0.1 \" => true\n\"abc\" => false\n\"1 a\" => false\n\"2e10\" => true\n\" -90e3   \" => true\n\" 1e\" => false\n\"e3\" => false\n\" 6e-1\" => true\n\" 99e2.5 \" => false\n\"53.5e93\" => true\n\" --6 \" => false\n\"-+3\" => false\n\"95a54e53\" => false\nNote: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one. However, here is a list of characters that can be in a valid decimal number:\n\nNumbers 0-9\nExponent - \"e\"\nPositive/negative sign - \"+\"/\"-\"\nDecimal point - \".\"\nOf course, the context of these characters also matters in the input.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\nõģĿʵҪַҪ󼴿ɣҪеǽȥnumberǰɸո񣬡.1\"1.ںϷ֡\n\n```cpp\nclass Solution {\npublic:\n    void blank(int& i,string& s)\n    {\n        while(i < s.length() && s[i] == ' ')\n            i++;\n    }\n    bool firstHalf(int& i,string& s)\n    {\n        int num = 0;\n        for(;i < s.length();++i)\n            if(isdigit(s[i]))\n                continue;\n            else if(s[i] == '.')\n            {\n                if(num)\n                    return 0;\n                num++;\n            }\n            else if(s[i] == 'e' || s[i] == ' ')\n                return 1;\n            else\n                return 0;\n        return 1;\n    }\n    bool secondHalf(int& i,string& s)\n    {\n        if(i == s.length())\n            return 0;\n        if(s[i] =='-' || s[i] == '+')\n            ++i;\n        if(!isdigit(s[i]))\n            return 0;\n        for(;i < s.length();++i)\n            if(!isdigit(s[i]))\n            {\n                if(s[i] == ' ')\n                    return 1;\n                return 0;\n            }\n        return 1;\n    }\n    bool isNumber(string s) {\n        int i = 0;\n        if(!s.length())\n            return 0;\n        blank(i,s);\n        if(i == s.length())\n            return 0;\n        if(s[i] == '-' || s[i] == '+')\n            ++i;\n        int temp = i;\n        if(!firstHalf(i,s))\n            return 0;\n        if(i == temp)\n            return 0;\n        if(i - 1 == temp && s[i - 1] == '.')\n            return 0;\n        if(i == s.length())\n            return 1;\n        if(s[i] == 'e')\n        {\n            i++;\n            if(!secondHalf(i,s))\n                return 0;\n        }\n        blank(i,s);\n        return i == s.length();\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0066._Plus_One.md",
    "content": "# 66. Plus One\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n\n> ԭ\n\n* https://leetcode.com/problems/plus-one/\n\n> \n\n```\nGiven a non-empty array of digits representing a non-negative integer, plus one to the integer.\n\nThe digits are stored such that the most significant digit is at the head of the list, and each element in the array contain a single digit.\n\nYou may assume the integer does not contain any leading zero, except the number 0 itself.\n\nExample 1:\n\nInput: [1,2,3]\nOutput: [1,2,4]\nExplanation: The array represents the integer 123.\nExample 2:\n\nInput: [4,3,2,1]\nOutput: [4,3,2,2]\nExplanation: The array represents the integer 4321.\n\n```\n\n\n> ˼·1\n\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nַתּɣҪעпܻһ\n\n```cpp\nclass Solution {\npublic:\n    vector<int> plusOne(vector<int>& digits) {\n        int i = digits.size() - 1;\n        while((i >= 0) &&  (digits[i] == 9))\n        {\n            digits[i] = 0;\n            --i;\n        }\n        if(i < 0)\n            digits.insert(digits.begin(),1);\n        else\n            ++digits[i];\n        return digits;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0068._Text_Justification.md",
    "content": "# 68. Text Justification\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/text-justification/\n\n> \n\n```\nGiven an array of words and a width maxWidth, format the text such that each line has exactly maxWidth characters and is fully (left and right) justified.\n\nYou should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly maxWidth characters.\n\nExtra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right.\n\nFor the last line of text, it should be left justified and no extra space is inserted between words.\n\nNote:\n\nA word is defined as a character sequence consisting of non-space characters only.\nEach word's length is guaranteed to be greater than 0 and not exceed maxWidth.\nThe input array words contains at least one word.\nExample 1:\n\nInput:\nwords = [\"This\", \"is\", \"an\", \"example\", \"of\", \"text\", \"justification.\"]\nmaxWidth = 16\nOutput:\n[\n   \"This    is    an\",\n   \"example  of text\",\n   \"justification.  \"\n]\nExample 2:\n\nInput:\nwords = [\"What\",\"must\",\"be\",\"acknowledgment\",\"shall\",\"be\"]\nmaxWidth = 16\nOutput:\n[\n  \"What   must   be\",\n  \"acknowledgment  \",\n  \"shall be        \"\n]\nExplanation: Note that the last line is \"shall be    \" instead of \"shall     be\",\n             because the last line must be left-justified instead of fully-justified.\n             Note that the second line is also left-justified becase it contains only one word.\nExample 3:\n\nInput:\nwords = [\"Science\",\"is\",\"what\",\"we\",\"understand\",\"well\",\"enough\",\"to\",\"explain\",\n         \"to\",\"a\",\"computer.\",\"Art\",\"is\",\"everything\",\"else\",\"we\",\"do\"]\nmaxWidth = 20\nOutput:\n[\n  \"Science  is  what we\",\n  \"understand      well\",\n  \"enough to explain to\",\n  \"a  computer.  Art is\",\n  \"everything  else  we\",\n  \"do                  \"\n]\n```\n\n> ˼·\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)******\n\nĿѣĿ˼ȼһɶٵʣÿ֮һոָͿԼÿɶٵʡÿеȷʽܹĿոԼܿոԼΪ0Ϊ֮Ŀո r Ϊ0ͷʼ r ո1ʣµĲ䡣һҪעÿ֮ĿոΪ1ַmaxWidthʣµÿո񲹳䡣\n\n```cpp\nclass Solution {\npublic:\n    vector<string> fullJustify(vector<string>& words, int maxWidth) {\n        int l = 0,r = 0,sum = 0;\n        vector<string> ans;\n        for(int i = 0;i < words.size();++i)\n        {\n            sum += words[i].length();\n            if(sum <= maxWidth)\n            {\n                sum += 1;\n                r++;\n            }\n            else\n            {\n                string temp;\n                sum -= (r - l + words[i].length());\n                int residue = 0, divide = (maxWidth - words[l].length());\n                if(l + 1 != r)\n                {\n                    residue = (maxWidth - sum) % (r - l - 1);\n                    divide = (maxWidth - sum - residue) / (r - l - 1);\n                }\n                temp.append(words[l].begin(),words[l].end());\n                for(int j = l + 1;j < r - 1;++j)\n                {\n                    int k = residue > 0 ? divide + 1 : divide;\n                    while(k)\n                    {\n                        temp.push_back(' ');\n                        --k;\n                    }\n                    temp.append(words[j].begin(),words[j].end());\n                    residue--;\n                }\n                int k = residue > 0 ? divide +1 : divide;\n                while(k)\n                {\n                    temp.push_back(' ');\n                    --k;\n                }\n                if(l + 1 != r)\n                    temp.append(words[r - 1].begin(),words[r - 1].end());\n                ans.push_back(temp);\n                l = r++;\n                sum = words[i].length() + 1;\n            }\n        }\n        sum -= 1;\n        string temp;\n        temp.append(words[l].begin(),words[l].end());\n        for(int i = l + 1;i < r;++i)\n        {\n            temp.push_back(' ');\n            temp.append(words[i].begin(),words[i].end());\n        }\n        int k = maxWidth - sum;\n        while(k)\n        {\n            temp.push_back(' ');\n            --k;\n        }\n        ans.push_back(temp);\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0069._Sqr(x).md",
    "content": "# 69. Sqrt(x)\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/sqrtx/\n\n> \n\n```\nImplement int sqrt(int x).\n\nCompute and return the square root of x, where x is guaranteed to be a non-negative integer.\n\nSince the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned.\n\nExample 1:\n\nInput: 4\nOutput: 2\nExample 2:\n\nInput: 8\nOutput: 2\nExplanation: The square root of 8 is 2.82842..., and since \n             the decimal part is truncated, 2 is returned.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\n0xЩƽֱx\n\n```cpp\nclass Solution {\npublic:\n    int mySqrt(int x) {\n        int i = 0;\n        if(!x || x == 1)\n            return x;\n        for(;i < x;++i)\n             if((long long)i * i > x)\n                 break;\n        return i - 1;\n    }\n};\n```\n> ˼·2\n******- ʱ临Ӷ: O(lgn)******- ռ临Ӷ: O(1)******\n\nԣҿԽһŻöַ0Ϊ½磬xΪϽ磬ͿԽж\n\n```cpp\nclass Solution {\npublic:\n    int mySqrt(int x) {\n        int l = 0, r= x;\n        while(l < r)\n        {\n            long long mid = (l + r) / 2,temp = mid * mid;\n            if(temp == x)\n                return mid;\n            if(temp < x)\n                l = mid + 1;\n            else\n                r = mid - 1;\n        }\n        return l * l <= x ? l : l - 1;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0072._Edit_Distance.md",
    "content": "# 72. Edit Distance\n\n**<font color=red>难度Hard</font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/edit-distance/\n\n> 内容描述\n\n```\nYou are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.\n\nExample 1:\n\nInput:\n  s = \"barfoothefoobarman\",\n  words = [\"foo\",\"bar\"]\nOutput: [0,9]\nExplanation: Substrings starting at index 0 and 9 are \"barfoor\" and \"foobar\" respectively.\nThe output order does not matter, returning [9,0] is fine too.\nExample 2:\n\nInput:\n  s = \"wordgoodstudentgoodword\",\n  words = [\"word\",\"student\"]\nOutput: []\n\n```\n> 思路\n******- 时间复杂度: O(n^2)******- 空间复杂度: O(n^2)******\n\n这题可以动态规划的思想去解决，首先定义两个指针 i 和 j，分别指向字符串的末尾。从两个字符串的末尾开始比较，相等，则```--i,--j```。若不相等，有三种情况，删除 i 指向的字符，在 i 指向的字符之后增加一个字符，替换 i 指向的字符， 接着比较这三次的操作的次数，取最小值即可，不过这里要注意递归操作时会重复计算，所以我们用一个数组 dp[i][j]，表示 i 在words1中的位置，j 在 words2 的位置。由于c++对动态数组的支持不是很好，这里我用 vector 代替，在效率上可能较欠缺。\n\n```cpp\nclass Solution {\npublic:\n    vector<vector<int> > dp;\n    int minLen(string& w1,string& w2,int i,int j)\n    {\n\t   if(i < 0)\n            return j + 1;\n        if(j < 0)\n            return i + 1;\n        if(dp[i][j])\n            return dp[i][j];\n        if(w1[i] == w2[j])\n        {\n            dp[i][j] = minLen(w1,w2,i - 1,j - 1);\n            return dp[i][j];\n        }\n        int temp1 = min(minLen(w1,w2,i - 1,j) + 1,minLen(w1,w2,i - 1,j - 1) + 1);\n        dp[i][j] = min(minLen(w1,w2,i,j - 1) + 1,temp1);\n        return dp[i][j];\n    }\n    int minDistance(string word1, string word2) {\n        int i = word1.length() - 1,j = word2.length() - 1;\n        for(int t1 = 0;t1 <= i;++t1)\n        {\n            vector<int> v1;\n            for(int t2 = 0;t2 <= j;++t2)\n                v1.push_back(0);\n            dp.push_back(v1);\n        }\n        int m = minLen(word1,word2,i,j);\n        return m;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0075._Sort_Colors.md",
    "content": "# 75. Sort Colors\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/sort-colors/submissions/\n  \n > 内容描述\n \n ```\n给定一个包含红色、白色和蓝色，一共 n 个元素的数组，原地对它们进行排序，使得相同颜色的元素相邻，并按照红色、白色、蓝色顺序排列。\n\n此题中，我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。\n\n注意:\n不能使用代码库中的排序函数来解决这道题。\n\n示例:\n\n输入: [2,0,2,1,1,0]\n输出: [0,0,1,1,2,2]\n进阶：\n\n一个直观的解决方案是使用计数排序的两趟扫描算法。\n首先，迭代计算出0、1 和 2 元素的个数，然后按照0、1、2的排序，重写当前数组。\n你能想出一个仅使用常数空间的一趟扫描算法吗？\n ```\n\n## 解题方案\n> 思路 1\n```\n记录两个指针，一个是0部分的后一位，另一个是2开头的前一个位置。\n遍历数组，遇到2，就和后一个指针交换（交换回来的有可能还是2，所以这个位置要再次判断）\n遇到0则和最后一个数的下一个位置交换。\n\n```\n\n```cpp\nvoid sortColors(vector<int>& nums) {\n    int left = 0;\n    int right = nums.size()-1;\n    for(int i=0;i<=right;i++){\n        if(nums[i]==0){\n            int tmp = nums[left];\n            nums[left] = nums[i];\n            nums[i] = tmp;\n            left++;\n        }\n        else if(nums[i]==2){\n            int tmp = nums[i];\n            nums[i] = nums[right];\n            nums[right] = tmp;\n            right--;\n            i--;\n        }\n    }\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0076._Minimum_Window_Substring.md",
    "content": "# 76. Minimum Window Substring\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/minimum-window-substring/\n\n> \n\n```\nGiven a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).\n\nExample:\n\nInput: S = \"ADOBECODEBANC\", T = \"ABC\"\nOutput: \"BANC\"\nNote:\n\nIf there is no such window in S that covers all characters in T, return the empty string \"\".\nIf there is such window, you are guaranteed that there will always be only one unique minimum window in S.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)******\n\nտʼ뵽 map ȥļֵַ˿ȥʱ临ӶΪO(n)һÿֵַĴű s̶һ䣬ʹڵַַ tͬҲһ鴢䡣ƶ伴ɡҵ̵䡣\n\n```cpp\nclass Solution {\npublic:\n    string minWindow(string s, string t) {\n        int arr[128],alNum = t.length();\n        memset(arr,0,sizeof(arr));\n        for(int i = 0;i < t.length();++i)\n            arr[t[i]]++;\n        vector<int> v;\n        for(int i = 0;i < s.length();++i)\n            if(arr[s[i]])\n                v.push_back(i);\n        int s_map[128],beg = -1,en,ans = INT_MAX,count1 = 0,l,r;\n        memset(s_map,0,sizeof(s_map));\n        for(int i = 0;i < v.size();++i)\n        {\n            if(count1 != alNum)\n            {\n                if(beg == -1)\n                    beg = i;\n                s_map[s[v[i]]]++;\n                if(s_map[s[v[i]]] <= arr[s[v[i]]])\n                    count1++;\n            }\n            for(int j = beg;count1 == alNum;)\n            {\n                en = v[i];\n                s_map[s[v[j]]]--;\n                if(ans > en - v[beg])\n                {\n                    l = v[beg];\n                    r = en;\n                    ans = en - v[beg];\n                }\n                if(s_map[s[v[j]]] < arr[s[v[j]]])\n                    count1--;\n                beg = ++j;\n            }\n       }\n        if(ans == INT_MAX)\n            return \"\";\n        return s.substr(l,r - l + 1);\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0077._combinations.md",
    "content": "# 77. Combinations\n\n**<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/combinations/\n  \n > 内容描述\n ```\n给定两个整数 n 和 k，返回 1 ... n 中所有可能的 k 个数的组合。\n\n示例:\n\n输入: n = 4, k = 2\n输出:\n[\n  [2,4],\n  [3,4],\n  [2,3],\n  [1,2],\n  [1,3],\n  [1,4],\n]\n ```\n\n## 解题方案\n> 思路 1\n```\n回溯寻找所有组合。\n```\n\n```cpp\n void dfs(int k, int index, int n, vector<int>& path, vector<vector<int>>& ans){\n    if(k==0){\n        ans.push_back(path);\n        return ;\n    }\n    for(int i=index;i<=n;i++){\n        path.push_back(i);\n        dfs(k-1, i+1, n, path, ans);\n        path.pop_back();\n    }\n}\nvector<vector<int>> combine(int n, int k) {\n    vector<vector<int>> ans;\n    vector<int> path;\n    dfs(k, 1, n, path, ans);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0078._subsets.md",
    "content": "# 78. Subsets\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/subsets/\n  \n > 内容描述\n ```\n给定一组不含重复元素的整数数组 nums，返回该数组所有可能的子集（幂集）。\n\n说明：解集不能包含重复的子集。\n\n示例:\n\n输入: nums = [1,2,3]\n输出:\n[\n  [3],\n  [1],\n  [2],\n  [1,2,3],\n  [1,3],\n  [2,3],\n  [1,2],\n  []\n]\n ```\n\n## 解题方案\n> 思路 1\n```\n每个元素有两种选择，选与不选，可以使用K位二进制数组表示K个元素的选与不选。\n```\n\n```cpp\nvector<vector<int>> subsets(vector<int>& nums) {\n    vector<vector<int>> ans;\n    for(int i=0;i<pow(2, nums.size());i++){\n        vector<int> tmp;\n        int index = 0;\n        int j=i;\n        while(j){\n            if(j%2==1)\n                tmp.push_back(nums[index]);\n            index++;\n            j/=2;\n        }\n        ans.push_back(tmp);\n    }\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0081._Search_in_Rotated_Sorted_Array_II.md",
    "content": "# 81. Search in Rotated Sorted Array II\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/search-in-rotated-sorted-array-ii/submissions/\n\n> \n\n```\nSuppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.\n\n(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).\n\nYou are given a target value to search. If found in the array return true, otherwise return false.\n\nExample 1:\n\nInput: nums = [2,5,6,0,0,1,2], target = 0\nOutput: true\nExample 2:\n\nInput: nums = [2,5,6,0,0,1,2], target = 3\nOutput: false\n```\n\n> ˼·\n******- ʱ临Ӷ: O(lgN)******- ռ临Ӷ: O(1)******\n\nתһʼ뵽ľöַʵҲѣؼж l = mid  j = mid⻹Ҫһµnums[mid] == nums[l] nums[l] == nums[mid]ʱֱ[l,mid][mid,r]Ƿtarget\n\n```cpp\nclass Solution {\npublic:\n    bool searchInternal( const vector<int>& Nums, const int Target, int Left, int Right )\n    {\n        if ( Right <= Left )\n\t\t\treturn false;\n        while ( Left < Right - 1 )\n        {\n            int Middle = (Left + Right) / 2;\n            if ( Nums[Left] == Nums[Middle] )\n            {\n                return searchInternal( Nums, Target, Left, Middle )\n                    || searchInternal( Nums, Target, Middle, Right );\n            }\n            if ( Target < Nums[Middle] )\n            {\n                if ( Nums[Left] < Nums[Middle] && Nums[Left] > Target )\n                {\n                    Left = Middle;\n                }\n                else\n                {\n                    Right = Middle;\n                }\n            }\n            else if ( Target > Nums[Middle] )\n            {\n                if ( Nums[Left] > Nums[Middle] && Nums[Left] <= Target )\n                {\n                    Right = Middle;\n                }\n                else\n                {\n                    Left = Middle;\n                }\n            }\n            else\n            {\n                return true;\n            }\n        }\n        return Nums[Left] == Target;\n    }\n    bool search(vector<int>& nums, int target) {\n        return searchInternal(nums,target,0,nums.size());\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0083._Remove_Duplicates_From_Sorted_Lists.md",
    "content": "#83. remove-duplicates-from-sorted-list\n\n**<font color=red>Ѷ:Easy</font>**\n\n## ˢ\n\n> ԭ\n\n*https://leetcode.com/problems/remove-duplicates-from-sorted-list/\n* \n> \n\n```\nGiven a sorted linked list, delete all duplicates such that each element appear only once.\n\nExample 1:\n\nInput: 1->1->2\nOutput: 1->2\nExample 2:\n\nInput: 1->1->2->3->3\nOutput: 1->2->3\n```\n\n## ⷽ\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\n\nĿиѾõģôֻҪһڵڵǰڵģɾȥ\n\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode* deleteDuplicates(ListNode* head) {\n        ListNode* l = head;\n        ListNode* l1 = head;\n        if(l != nullptr)\n        {\n                while(l ->next != nullptr)\n            {\n                if(l ->val == (l ->next ->val))\n                    l ->next = l ->next ->next;\n                else\n                    l = l ->next;\n            }\n        }\n           return l1;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0084._Largest_Rectangle_in_Histogram.md",
    "content": "# 84. Largest Rectangle in Histogram\n\n**<font color=red>难度:Hard<font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/largest-rectangle-in-histogram/\n\n> 内容描述\n\n```\nGiven n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.\n\nAbove is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].\n\nThe largest rectangle is shown in the shaded area, which has area = 10 unit.\n\nExample:\n\nInput: [2,1,5,6,2,3]\nOutput: 10\n```\n\n> 思路1\n******- 时间复杂度: O(n^2)******- 空间复杂度: O(n)******\n\n这题第一种思路就是用暴力的方法去解。时间复杂度为O(n^2)。遍历数组，对数组中每个元素分别向右向左找到最远，计算最大值得到结果\n\n```cpp\nclass Solution {\npublic:\n    int largestRectangleArea(vector<int>& heights) {\n        long long ans = 0;\n        for(int i = 0;i < heights.size();++i)\n        {\n            int j = i + 1;\n            long long l,r;\n            for(;j < heights.size();++j)\n                if(heights[j] < heights[i])\n                {\n                    r = (long long)heights[i] * (j - i);\n                    break;\n                }\n            if(j == heights.size())\n                r = (long long)heights[i] * (heights.size() - i);\n            for(j = i - 1;j >= 0;--j)\n                if(heights[j] < heights[i])\n                {\n                    l = (long long)heights[i] * (i - j - 1);\n                    break;\n                }\n            if(j < 0)\n                l = (long long)heights[i] * i;\n            ans = max(ans,l + r);\n        }\n        return ans;\n    }\n};\n```\n> 思路2\n******- 时间复杂度: O(n)******- 空间复杂度: O(n)******\n\n上面第一种方法的实现中有重复计算的过程，我们用栈去解决这个问题就很好的剔除了重复计算的过程，时间复杂度降到了O(n)。先定义一个栈，我们要保证栈中的数是递增的，遍历数组，若这个数小于栈顶的数，则将栈顶的数弹出，并计算栈顶元素的最大距离，直到栈为空或者比这个数小\n\n```cpp\nclass Solution {\npublic:\n    int largestRectangleArea(vector<int>& heights) {\n        long long ans = 0;\n        heights.push_back(0);\n        vector<pair<long long,int> > v;\n        for(int i = 0;i < heights.size();++i)\n        {\n            if(!v.size() || heights[i] > v[v.size() - 1].first)\n                    v.push_back(make_pair(heights[i],i));\n            else\n            {\n                int j = v.size() - 1;\n                while(j > 0 && v[j].first > heights[i])\n                {\n                    ans = max(ans,v[j].first * (i - v[j - 1].second - 1));\n                    v.pop_back();\n                    --j;\n                }\n                if(!j && v[j].first > heights[i])\n                {\n                    ans = max(ans,v[j].first * (i));\n                    v.pop_back();\n                }\n                v.push_back(make_pair(heights[i],i));\n            }\n        }\n        return ans;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0085._Maximal_Rectangle.md",
    "content": "# 85. Maximal Rectangle\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/maximal-rectangle/\n\n> \n\n```\nGiven a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.\n\nExample:\n\nInput:\n[\n  [\"1\",\"0\",\"1\",\"0\",\"0\"],\n  [\"1\",\"0\",\"1\",\"1\",\"1\"],\n  [\"1\",\"1\",\"1\",\"1\",\"1\"],\n  [\"1\",\"0\",\"0\",\"1\",\"0\"]\n]\nOutput: 6\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n^3)******- ռ临Ӷ: O(1)******\n\nһֱķȥ⣬ÿһжٸ1¼³count1λѰңĳСcount1count1ȡСֵΪ0ͼĴСֱе\n\n```cpp\nclass Solution {\npublic:\n    int maximalRectangle(vector<vector<char>>& matrix) {\n        int len1 = matrix.size();\n        if(!len1)\n            return 0;\n        int len2 = matrix[0].size();\n        int ans = 0;\n        for(int t = 0;t < len1;++t)\n        for(int i = 0;i < len2;++i)\n        {\n            int count1 = 0;\n            while(i + count1 < len2 && matrix[t][i + count1] - '0')\n                ++count1;\n            if(count1)\n            {\n                int row = 1;\n                ans = max(ans,row * count1);\n                for(int j = t + 1;j < len1;++j)\n                {\n                    int count2 = 0;\n                    while(count2  <= count1 && matrix[j][i + count2] - '0')\n                        ++count2;\n                    if(!count2)\n                        break;\n                    if(count1 > count2)\n                        count1 = count2;\n                    ++row;\n                    ans = max(ans,row * count1);\n                }\n            }\n        }\n    return ans;\n    }\n};\n```\n> ˼·2\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n)******\n\n㷨Żÿĸ߶Ⱥ߶λúҵλãֻҪO(n^2)ʱ临ھ\n\n```cpp\nclass Solution {\npublic:\n    int maximalRectangle(vector<vector<char>>& matrix) {\n              int len1 = matrix.size();\n        if(!len1)\n            return 0;\n        int len2 = matrix[0].size();\n        int height[len2],l[len2],r[len2];\n        memset(height,0,sizeof(height));\n        memset(l,0,sizeof(l));\n        for(int i = 0;i < len2;++i)\n            r[i]  = len2;\n        int ans = 0;\n        for(int i = 0;i < len1;++i)\n        {\n            int t_l = 0,t_r = len2;\n            for(int j = 0;j < len2;++j)\n                if(matrix[i][j]-'0')\n                    height[j] = height[j] + 1;\n                else\n                    height[j] = 0;\n            for(int j = 0;j < len2;++j)\n                if(matrix[i][j]-'0')\n                    l[j] = max(l[j],t_l);\n                else\n                {\n                    t_l = j + 1;\n                    l[j] = 0;\n                }\n            for(int j = len2 - 1;j >= 0;--j)\n                if(matrix[i][j]-'0')\n                    r[j] = min(r[j],t_r);\n                else\n                {\n                    t_r = j;\n                    r[j] = len2;\n                }\n            for(int j = 0;j < len2;++j)\n                ans = max(ans,(r[j] - l[j]) * height[j]);\n        }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0087._Scramble_String.md",
    "content": "# 87. Scramble String\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/scramble-string/\n\n> \n\n```\nGiven a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.\n\nBelow is one possible representation of s1 = \"great\":\n\n    great\n   /    \\\n  gr    eat\n / \\    /  \\\ng   r  e   at\n           / \\\n          a   t\nTo scramble the string, we may choose any non-leaf node and swap its two children.\n\nFor example, if we choose the node \"gr\" and swap its two children, it produces a scrambled string \"rgeat\".\n\n    rgeat\n   /    \\\n  rg    eat\n / \\    /  \\\nr   g  e   at\n           / \\\n          a   t\nWe say that \"rgeat\" is a scrambled string of \"great\".\n\nSimilarly, if we continue to swap the children of nodes \"eat\" and \"at\", it produces a scrambled string \"rgtae\".\n\n    rgtae\n   /    \\\n  rg    tae\n / \\    /  \\\nr   g  ta  e\n       / \\\n      t   a\nWe say that \"rgtae\" is a scrambled string of \"great\".\n\nGiven two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.\n\nExample 1:\n\nInput: s1 = \"great\", s2 = \"rgeat\"\nOutput: true\nExample 2:\n\nInput: s1 = \"abcde\", s2 = \"caebd\"\nOutput: false\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(2^n)******- ռ临Ӷ: O(1)******\n\nտʼʱĿ˼ûΪǰַ԰룬ʵַкܶĶʾһַǵݹķÿεݹʱȽilen֮ӴǷs2еӴֱͬȽϷʽs2ʼͽβֱȽϷʽһ㼴ɣֻҪжӴĸǷͬͬͽһεݹ顣\n\n```cpp\nclass Solution {\npublic:\n    bool isScramble(string s1, string s2) {\n        if(s1==s2)\n            return true;\n        int len = s1.length();\n        int count[26] = {0};\n        for(int i=0; i<len; i++)\n        {\n            count[s1[i]-'a']++;\n            count[s2[i]-'a']--;\n        }\n        for(int i=0; i<26; i++)\n        {\n            if(count[i]!=0)\n                return false;\n        }\n        for(int i=1; i<=len-1; i++)\n        {\n            if(isScramble(s1.substr(0,i), s2.substr(0,i)) && isScramble(s1.substr(i), s2.substr(i)))\n                return true;\n            if(isScramble(s1.substr(0,i), s2.substr(len-i)) && isScramble(s1.substr(i), s2.substr(0,len-i)))\n                return true;\n        }\n        return false;\n    }\n};\n```\n\n> ˼·2\n******- ʱ临Ӷ: O(n^4)******- ռ临Ӷ: O(n^3\n\nڶֵķʹDPdp[i][j][t],ʾs1[i]s2[j]ʼĳΪtַǷΪscramble string\n\n```cpp\nclass Solution {\npublic:\n    bool isScramble(string s1, string s2) {\n    int len = s1.length();\n    int dp[len][len][len + 1] = {0};\n    for(int i = len - 1;i >= 0;--i)\n        for(int j = len - 1;j >= 0;--j)\n            for(int t = 1;t <= min(len - i,len - j);++t)\n                if(t == 1)\n                    dp[i][j][t] = (s1[i] == s2[j]);\n                else\n                {\n                    int k = 1;\n                    for(;k < t;++k)\n                        if((dp[i][j][k] && dp[i + k][j + k][t - k]) || (dp[i][j + t - k][k] && dp[i + k][j][t - k]))\n                            break;\n                    dp[i][j][t] = k == t ? 0 : 1;\n                }\n    return dp[0][0][len];\n\n}\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0088._Merge_Sorted_Array.md",
    "content": "# 88.Merge Sorted Array\n\n**<font color=red>ѶEasy</font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/merge-sorted-array/\n\n> \n\n```\nGiven two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.\n\nNote:\n\nThe number of elements initialized in nums1 and nums2 are m and n respectively.\nYou may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2.\nExample:\n\nInput:\nnums1 = [1,2,3,0,0,0], m = 3\nnums2 = [2,5,6],       n = 3\n\nOutput: [1,2,2,3,5,6]\n```\n> ˼·\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nѾõģǿָ ij ָĵһԪأnums[i] < nums[j],++i ++j,jָԪزnums1Ҫעĳȡ\n\n```cpp\nclass Solution {\npublic:\n    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {\n        int i = 0,j = 0;\n        while((i < m) && (j < n))\n        {\n            if(nums1[i] < nums2[j])\n                i++;\n            else\n            {\n                nums1.insert(nums1.begin() + i,nums2[j++]);\n                i++;\n                m++;\n            }\n        }\n        if(j < n)\n        {\n            nums1.erase(nums1.begin() + m,nums1.end());\n            nums1.insert(nums1.end(),nums2.begin() + j,nums2.begin() + n);\n        }\n        else\n            nums1.erase(nums1.begin() + m,nums1.end());\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0090._Subsets_II.md",
    "content": "# 90. Subsets II\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/subsets-ii/submissions/\n  \n > 内容描述\n \n ```\n给定一个可能包含重复元素的整数数组 nums，返回该数组所有可能的子集（幂集）。\n\n说明：解集不能包含重复的子集。\n\n示例:\n\n输入: [1,2,2]\n输出:\n[\n  [2],\n  [1],\n  [1,2,2],\n  [2,2],\n  [1,2],\n  []\n]\n ```\n\n## 解题方案\n> 思路 1\n```\n回溯搜索\n```\n\n```cpp\nvoid dfs(vector<int> nums, int index, vector<int> subset, vector<vector<int>>& ans){\n    ans.push_back(subset);\n    if(index == nums.size()){\n        return ;\n    }\n    for(int i=index;i<nums.size();i++){ \n        if(nums[i-1]==nums[i]&&i>index)\n            continue;\n        subset.push_back(nums[i]);\n        dfs(nums, i+1, subset, ans);\n        subset.pop_back();\n    }\n}\nvector<vector<int>> subsetsWithDup(vector<int>& nums) {\n    vector<vector<int>> ans;\n    vector<int> subset;\n    sort(nums.begin(), nums.end());\n    dfs(nums, 0, subset, ans);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0094._binary_tree_inorder_traversal.md",
    "content": "# 94. Binary Tree Inorder Traversal\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n > 原题连接\n\n* https://leetcode-cn.com/problems/binary-tree-inorder-traversal/\n\n > 内容描述\n ```\n给定一个二叉树，返回它的中序 遍历。\n\n示例:\n\n输入: [1,null,2,3]\n   1\n    \\\n     2\n    /\n   3\n\n输出: [1,3,2]\n\n进阶: 递归算法很简单，你可以通过迭代算法完成吗？\n ```\n\n## 解题方案\n> 思路 1\n```\n递归。\n```\n\n```cpp\nvoid dfs(TreeNode* root, vector<int>& ans){\n    if(root==NULL)\n        return ;\n    dfs(root->left, ans);\n    ans.push_back(root->val);\n    dfs(root->right, ans);\n}\nvector<int> inorderTraversal(TreeNode* root) {\n    vector<int> ans;\n    dfs(root, ans);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0096._Unique_Binary_Search_Trees.md",
    "content": "# 96. Unique Binary Search Trees\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/unique-binary-search-trees/\n  \n > 内容描述\n \n ```\n给定一个整数 n，求以 1 ... n 为节点组成的二叉搜索树有多少种？\n\n示例:\n\n输入: 3\n输出: 5\n解释:\n给定 n = 3, 一共有 5 种不同结构的二叉搜索树:\n\n   1         3     3      2      1\n    \\       /     /      / \\      \\\n     3     2     1      1   3      2\n    /     /       \\                 \\\n   2     1         2                 3\n ```\n\n## 解题方案\n> 思路 1\n```\n假设有n个节点，左右子树有（0，n-1）(1,n-2)...(n-1, 0)等情况\n子结构：\ndp[i] = dp[0]*dp[i-1]+...+dp[i-1]*dp[0]\n```\n\n```cpp\nint numTrees(int n) {\n    vector<int> dp(n+1, 0);\n    dp[0]=1;\n    dp[1]=1;\n    for(int i=2;i<=n;i++){\n        for(int j=0;j<i;j++){\n            dp[i] += dp[i-j-1]*dp[j];\n        }\n    }\n    return dp[n];\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0097._Interleaving_String.md",
    "content": "# 97. Interleaving String\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/interleaving-string/\n\n> \n\n```\nGiven s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.\n\nExample 1:\n\nInput: s1 = \"aabcc\", s2 = \"dbbca\", s3 = \"aadbbcbcac\"\nOutput: true\nExample 2:\n\nInput: s1 = \"aabcc\", s2 = \"dbbca\", s3 = \"aadbbbaccc\"\nOutput: false\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N^2)******- ռ临Ӷ: O(N^2)******\n\nһñķȥ⣬ʱ临ӶΪO(2^n)ʱ临ӶΪָ϶ʱǿö̬滮ʱ临ӶŻO(n^2)⶯̬滮Ĺؼҵ״̬תƷ̣ά dp[i][j]ʾ s1[i] s2[j]֮ӴǷs3[i + j]Ǿд״̬תƷ̣``` dp[i][j] = (s1[i] == s3[i + j] && dp[i + 1][j]) || (s2[j] == s3[i + j] && dp[i][j + 1])```\n\n```cpp\nclass Solution {\npublic:\n    bool isInterleave(string s1, string s2, string s3) {\n        int l1 = s1.length(),l2 = s2.length(),l3 = s3.length();\n        if(l1 + l2 != s3.length())\n            return 0;\n        int dp[l1 + 2][l2 + 2];\n        memset(dp,0,sizeof(dp));\n        dp[l1][l2] = 1;\n        for(int i = l1;i >= 0;--i)\n            for(int j = l2;j >= 0;--j)\n            {\n                if(i < l1 && s1[i] == s3[i + j] && dp[i + 1][j])\n                    dp[i][j] = 1;\n                if(j < l2 && s2[j] == s3[i + j] && dp[i][j + 1])\n                    dp[i][j] = 1;\n            }\n        return dp[0][0];\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0099._Recover_Binary_Search_Tree.md",
    "content": "# 99. Recover Binary Search Tree\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/recover-binary-search-tree/\n\n> \n\n```\nTwo elements of a binary search tree (BST) are swapped by mistake.\n\nRecover the tree without changing its structure.\n\nExample 1:\n\nInput: [1,3,null,null,2]\n\n   1\n  /\n 3\n  \\\n   2\n\nOutput: [3,1,null,null,2]\n\n   3\n  /\n 1\n  \\\n   2\nExample 2:\n\nInput: [3,1,4,null,null,2]\n\n  3\n / \\\n1   4\n   /\n  2\n\nOutput: [2,1,4,null,null,3]\n\n  2\n / \\\n1   4\n   /\n  3\n```\n\n> ˼·\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nҪ㶮ƽʱġʺֻҪԶҵĸɣһ֮Ϊ 32131ڶ֮Ϊ 132432\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\nTreeNode* n1;\nTreeNode* n2;\nTreeNode* pre = new TreeNode(INT_MIN);\nvoid travel(TreeNode* root){\n      if(!root)\n        return;\n    travel(root ->left);\n    if(!n1 && root ->val <= pre ->val)\n        n1 = pre;\n    if(pre && n1 && root ->val <= pre ->val)\n        n2 = root;\n    pre = root;\n    travel(root ->right);\n}\nvoid recoverTree(TreeNode* root) {\n    travel(root);\n    swap(n1 ->val,n2 ->val);\n}\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0100._same_tree.md",
    "content": "# 100. same tree\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/same-tree/\n* \n> 内容描述\n\n```\nGiven two binary trees, write a function to check if they are the same or not.\n\nTwo binary trees are considered the same if they are structurally identical and the nodes have the same value.\n\nExample 1:\n\nInput:  1         1\n          / \\       / \\\n         2   3     2   3\n\n        [1,2,3],   [1,2,3]\n\nOutput: true\nExample 2:\n\nInput:  1         1\n          /           \\\n         2             2\n\n        [1,2],     [1,null,2]\n\nOutput: false\nExample 3:\n\nInput:  1         1\n          / \\       / \\\n         2   1     1   2\n\n        [1,2,1],   [1,1,2]\n\nOutput: false\n```\n> 思路1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n这道题直接从两颗树的根节点开始递归比较，如果不同就返回false，反之则true\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    bool isSameTree(TreeNode* p, TreeNode* q) {\n        if(p != nullptr && q != nullptr)\n        {\n            if(p ->val != q ->val)\n                return false;\n            return isSameTree(p ->left,q ->left) && isSameTree(p ->right,q ->right);\n        }\n        return p == q ? true : false;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0101._Symmetric_Tree.md",
    "content": "# 101. Symmetric Tree\n\n**<font color=red>ѶEasy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/symmetric-tree/\n\n> \n\n```\nGiven a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).\n\nFor example, this binary tree [1,2,2,3,4,4,3] is symmetric:\n\n    1\n   / \\\n  2   2\n / \\ / \\\n3  4 4  3\nBut the following [1,2,2,null,3,null,3] is not:\n    1\n   / \\\n  2   2\n   \\   \\\n   3    3\n```\n\nֱDFSȽǷȣȷtrueȣfalse\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    bool judge(TreeNode* oTree,TreeNode* mTree){\n        if((oTree != nullptr) && (mTree != nullptr))\n        {\n            if((oTree ->val == mTree  ->val) && (oTree ->val == mTree ->val))\n                return judge(oTree ->left,mTree ->right) && judge(oTree ->right,mTree ->left);\n                return false;\n        }\n        if(oTree == mTree)\n            return true;\n        return false;\n    }\n    bool isSymmetric(TreeNode* root) {\n      if(root != nullptr)\n        return judge(root ->left,root ->right);\n    return true;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0102._Binary_Tree_Level_Order_Traversal.md",
    "content": "# 102. Binary Tree Level Order Traversal\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/binary-tree-level-order-traversal/\n  \n > 内容描述\n \n ```\n给定一个二叉树，返回其按层次遍历的节点值。 （即逐层地，从左到右访问所有节点）。\n\n例如:\n给定二叉树: [3,9,20,null,null,15,7],\n\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\n返回其层次遍历结果：\n\n[\n  [3],\n  [9,20],\n  [15,7]\n]\n ```\n\n## 解题方案\n> 思路 1\n```\n层次遍历\n```\n\n```cpp\nvector<vector<int>> levelOrder(TreeNode* root) {\n    vector<vector<int>> ans;\n    if(root==NULL)\n        return ans;\n    vector<TreeNode*> level;\n    level.push_back(root);\n    while(!level.empty()){\n        vector<TreeNode*> tmp;\n        vector<int> level_val;\n        for(int i=0;i<level.size();i++){\n            if(level[i]->left)\n                tmp.push_back(level[i]->left);\n            if(level[i]->right)\n                tmp.push_back(level[i]->right);\n            level_val.push_back(level[i]->val);\n        }\n        ans.push_back(level_val);\n        level = tmp;\n    }\n    return ans;\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0104._Maximum_Depth_of_Binary_Tree.md",
    "content": "# 104. Maximum Depth of Binary Tree\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/maximum-depth-of-binary-tree/\n\n> \n\n```\nGiven a binary tree, find its maximum depth.\n\nThe maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.\n\nNote: A leaf is a node with no children.\n\nExample:\n\nGiven binary tree [3,9,20,null,null,15,7],\n\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\nreturn its depth = 3.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)******\n\nDFSݹֱҵ depthȽ depthĴС\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    int maxDepth(TreeNode* root) {\n        return max(root,0);\n    }\n    int max(TreeNode* ptr,int deep)\n    {\n        if(ptr != nullptr)\n        {\n            int ldeep = max(ptr ->left,deep + 1);\n            int rdeep = max(ptr ->right,deep + 1);\n            if(ldeep > rdeep) \n                deep = ldeep; \n            else\n                deep = rdeep;\n        }\n        return deep;\n    }\n};"
  },
  {
    "path": "docs/leetcode/cpp/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md",
    "content": "# 105. Construct Binary Tree from Preorder and Inorder Traversal\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/\n  \n > 内容描述\n \n ```\n根据一棵树的前序遍历与中序遍历构造二叉树。\n\n注意:\n你可以假设树中没有重复的元素。\n\n例如，给出\n\n前序遍历 preorder = [3,9,20,15,7]\n中序遍历 inorder = [9,3,15,20,7]\n返回如下的二叉树：\n\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\n ```\n\n## 解题方案\n> 思路 1\n```\n和106思路一致\n```\n\n```cpp\nTreeNode* dfs(vector<int>& preorder, vector<int>& inorder, int start, int end, int& index){\n    int post = preorder[index];\n    int i=start;\n    for(;i<end;i++)\n        if(post == inorder[i])\n            break;\n    TreeNode* node = new TreeNode(post);\n    if(i>start)\n        node->left = dfs(preorder, inorder, start, i-1, ++index);\n    if(i<end)\n        node->right = dfs(preorder, inorder, i+1, end, ++index);\n    return node;\n}\nTreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {\n    if(preorder.empty()||inorder.empty())\n        return NULL;\n    int index =0;\n    return dfs(preorder, inorder, 0, preorder.size()-1, index);\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md",
    "content": "# 106. Construct Binary Tree from Inorder and Postorder Traversal\n\n **<font color=red>难度: Medium</font>**\n\n ## 原题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/\n  \n > 内容描述\n \n ```\n根据一棵树的中序遍历与后序遍历构造二叉树。\n\n注意:\n你可以假设树中没有重复的元素。\n\n例如，给出\n\n中序遍历 inorder = [9,3,15,20,7]\n后序遍历 postorder = [9,15,7,20,3]\n返回如下的二叉树：\n\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\n ```\n\n## 解题方案\n> 思路 1\n```\n后序二叉树最后访问根节点\n中序二叉树的节点在中间，左边是左子树，反之是右子树。\n通过后序二叉树找到子树根节点，然后到中序二叉树中区分左右子树，递归求解。\n```\n\n```cpp\n TreeNode* dfs(int start, int end, vector<int>& inorder, vector<int>& postorder, int& val){\n    int post = postorder[val];\n    int i=start;\n    for(; i<end;i++){\n        if(inorder[i]==post)\n            break;\n    }  \n    TreeNode* root=new TreeNode(post);\n    if(end>=i+1)\n        root->right=dfs(i+1, end, inorder, postorder, --val);\n    if(i-1>=start)\n        root->left = dfs(start, i-1, inorder, postorder, --val);\n    return root;\n}\nTreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {\n    if(inorder.empty()||postorder.empty())\n        return NULL;\n    int index = inorder.size()-1;\n    return dfs(0, index, inorder, postorder, index);\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0107._Binary_Tree_Level_Order_Traversal_II.md",
    "content": "# 107.Binary Tree Level Order Traversal II\n\n**<font color=red>ѶEasy</font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/binary-tree-level-order-traversal-ii/\n\n> \n\n```\nGiven a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).\n\nFor example:\nGiven binary tree [3,9,20,null,null,15,7],\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\nreturn its bottom-up level order traversal as:\n[\n  [15,7],\n  [9,20],\n  [3]\n]\n```\n> ˼·1\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)******\n\nһ͵BFSĿһַõǵݹķȽ\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    vector<vector<int> > levelOrderBottom(TreeNode* root) {\n        if(!root)\n        {\n            vector<vector<int> > ret;\n            return ret;\n        }\n        vector<int> v;\n        v.push_back(root ->val);\n        vector<vector<int> > temp1 = levelOrderBottom(root ->left);\n        vector<vector<int> > temp2 = levelOrderBottom(root ->right);\n        int pos1 = temp1.size() - 1;\n        int pos2 = temp2.size() - 1;\n        while(pos1 >= 0  && pos2 >= 0)\n        {\n            temp1[pos1].insert(temp1[pos1].end(),temp2[pos2].begin(),temp2[pos2].end());\n            --pos1;\n            --pos2;\n        }\n        if(pos2 >= 0)\n        {\n            auto pos = temp2.begin() + pos2 + 1;\n            temp1.insert(temp1.begin(),temp2.begin(),pos);\n        }\n        temp1.push_back(v);\n        return temp1;\n    }\n};\n```\n> ˼·2\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)******\n\nڶָĽķõջĴ淽ʽ\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    vector<vector<int>> levelOrderBottom(TreeNode* root) {\n        vector<vector<int> > ret;\n        if(root != nullptr)\n        {\n            vector<TreeNode> v;\n            v.push_back(*root);\n            judge(v,ret);\n        }\n        return ret;\n    }\n    void judge(vector<TreeNode>& v,vector<vector<int> >& ret)\n    {\n        vector<TreeNode> v1;\n        vector<int> v2;\n        for(int i = 0;i < v.size();i++)\n        {\n            v2.push_back(v[i].val);\n            if(v[i].left != nullptr)\n                v1.push_back(*(v[i].left));\n            if(v[i].right != nullptr)\n                v1.push_back(*(v[i].right));\n        }\n        if(v1.size())\n            judge(v1,ret);\n        ret.push_back(v2);\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md",
    "content": "# 108. Convert Sorted Array to Binary Search Tree\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/\n\n> \n\n```\nGiven an array where elements are sorted in ascending order, convert it to a height balanced BST.\n\nFor this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.\n\nExample:\n\nGiven the sorted array: [-10,-3,0,5,9],\n\nOne possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST:\n\n      0\n     / \\\n   -3   9\n   /   /\n -10  5\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nǸõ飬ƽҪĲľֵܴ1ֻÿν԰룬һΪһΪɡassignvecrtorֵ\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    TreeNode* sortedArrayToBST(vector<int>& nums) {\n        if(!nums.size())\n            return nullptr;\n        TreeNode* root = new TreeNode(nums[nums.size() / 2]);\n        vector<int> v1,v2;\n        if(nums.size() / 2 >= 0)\n            v1.assign(nums.begin(),nums.begin() + nums.size() / 2);\n        root ->left = sortedArrayToBST(v1);\n        if(nums.size() / 2 + 1 < nums.size())\n            v2.assign(nums.begin() + nums.size() / 2 + 1,nums.end());\n        root ->right = sortedArrayToBST(v2);\n        return root;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0109._Convert_Sorted_List_to_Binary_Search_Tree.md",
    "content": "# 109. Convert Sorted List to Binary Search Tree\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/\n  \n > 内容描述\n \n ```\n给定一个单链表，其中的元素按升序排序，将其转换为高度平衡的二叉搜索树。\n\n本题中，一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。\n\n示例:\n\n给定的有序链表： [-10, -3, 0, 5, 9],\n\n一个可能的答案是：[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树：\n\n      0\n     / \\\n   -3   9\n   /   /\n -10  5\n ```\n\n## 解题方案\n> 思路 1\n```\n1. 用快慢指针找链表中点\n2. 断开前半部分和后半部分\n3. 迭代构造左右子树\n```\n\n```cpp\nTreeNode* dfs(ListNode* node){\n    if(node == NULL)\n        return NULL;\n    if(node->next==NULL)\n        return new TreeNode(node->val);\n    ListNode* fast=node;\n    ListNode* slow=node;\n    ListNode* last = slow;\n    while(fast&&fast->next){\n        last = slow;\n        fast = fast->next->next;\n        slow = slow->next;\n    }\n    fast = slow->next;\n    last->next = NULL;\n    TreeNode* root = new TreeNode(slow->val);\n    if (node != slow) \n        root->left=dfs(node);\n    root->right=dfs(fast);\n    return root;\n}\nTreeNode* sortedListToBST(ListNode* head) {\n    return dfs(head);\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0110._Balanced_Binary_Tree.md",
    "content": "# 110.Balanced Binary Tree\n\n**<font color=red>ѶEasy</font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/balanced-binary-tree/\n\n> \n\n```\nGiven a binary tree, determine if it is height-balanced.\n\nFor this problem, a height-balanced binary tree is defined as:\n\na binary tree in which the depth of the two subtrees of every node never differ by more than 1.\n\nExample 1:\n\nGiven the following tree [3,9,20,null,null,15,7]:\n\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\nReturn true.\n\nExample 2:\n\nGiven the following tree [1,2,2,3,3,null,null,4,4]:\n\n       1\n      / \\\n     2   2\n    / \\\n   3   3\n  / \\\n 4   4\nReturn false.\n```\n> ˼·\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\nжиƽֻҪĸ߶ȲжǷ1ٷֱжǷΪƽ\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    bool isBalanced(TreeNode* root) {\n        if(root == nullptr)\n            return true;\n        return abs(height(root ->left) - height(root ->right)) <= 1 && isBalanced(root ->left) && isBalanced(root ->right);\n    }\n    int height(TreeNode* root){\n        if(root == nullptr)\n            return 0;\n        return max(height(root ->left),height(root ->right)) + 1;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0111._Minimum_Depth_Of_Binary_Tree.md",
    "content": "# 111. Minimum Depth of Binary Tree\n **<font color=red>难度: Easy</font>**\n## 刷题内容\n> 原题连接\n* https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/\n> 内容描述\n```\nGiven a binary tree, find its minimum depth.\n\nThe minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.\n\nNote: A leaf is a node with no children.\n```\n## 解题方案\n> 思路 1\n```\n遍历树，找出最小深度的分支\n```\n```cpp\nvoid dfs(TreeNode* root, int depth, int& ans){\n    if(root == NULL)\n        return ;\n    if(root->left==NULL && root->right==NULL){\n        if(depth<ans)\n            ans = depth;\n        return;\n    }\n    dfs(root->left, depth+1, ans);\n    dfs(root->right, depth+1, ans);\n}\nint minDepth(TreeNode* root) {\n    int ans = 10000;\n    if(root==NULL)\n        return 0;\n    dfs(root, 1, ans);\n    return ans;\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0112._Path_Sum.md",
    "content": "# 112. Path Sum\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/path-sum/\n\n> \n\n```\nGiven a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.\n\nNote: A leaf is a node with no children.\n\nExample:\n\nGiven the below binary tree and sum = 22,\n\n      5\n     / \\\n    4   8\n   /   / \\\n  11  13  4\n /  \\      \\\n7    2      1\nreturn true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\nDFSֱǷ sum - val ·\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    bool hasPathSum(TreeNode* root, int sum) {\n        if(root == nullptr)\n            return false;\n        if(root ->right == nullptr && root ->left == nullptr)\n            return sum - root ->val ? false : true;\n        return hasPathSum(root ->left,sum - root ->val) || hasPathSum(root ->right,sum - root ->val); \n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0114._Flatten_Binary_Tree_to_Linked_List.md",
    "content": "# 114. Flatten Binary Tree to Linked List\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/\n  \n > 内容描述\n \n ```\n给定一个二叉树，原地将它展开为链表。\n\n例如，给定二叉树\n\n    1\n   / \\\n  2   5\n / \\   \\\n3   4   6\n将其展开为：\n\n1\n \\\n  2\n   \\\n    3\n     \\\n      4\n       \\\n        5\n         \\\n          6\n ```\n\n## 解题方案\n> 思路 1\n```\n后续遍历二叉树\n```\n\n```cpp\nvoid dfs(TreeNode* root){\n    if(root==NULL)\n        return ;\n    dfs(root->left);\n    dfs(root->right);\n    TreeNode* tmp=root->right;\n    root->right=root->left;\n    root->left=NULL;\n    while(root->right)\n        root=root->right;\n    root->right = tmp;\n}\nvoid flatten(TreeNode* root) {\n    dfs(root);\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0115._Distinct_Subsequences.md",
    "content": "# 115.Distinct Subsequences\n\n**<font color=red>ѶHard</font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/distinct-subsequences/\n\n> \n\n```\nGiven a string S and a string T, count the number of distinct subsequences of S which equals T.\n\nA subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, \"ACE\" is a subsequence of \"ABCDE\" while \"AEC\" is not).\n\nExample 1:\n\nInput: S = \"rabbbit\", T = \"rabbit\"\nOutput: 3\nExplanation:\n\nAs shown below, there are 3 ways you can generate \"rabbit\" from S.\n(The caret symbol ^ means the chosen letters)\n\nrabbbit\n^^^^ ^^\nrabbbit\n^^ ^^^^\nrabbbit\n^^^ ^^^\nExample 2:\n\nInput: S = \"babgbag\", T = \"bag\"\nOutput: 5\nExplanation:\n\nAs shown below, there are 5 ways you can generate \"bag\" from S.\n(The caret symbol ^ means the chosen letters)\n\nbabgbag\n^^ ^\nbabgbag\n^^    ^\nbabgbag\n^    ^^\nbabgbag\n  ^  ^^\nbabgbag\n    ^^^\n```\n> ˼·\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n^2)******\n\nһ̬滮⣬̬Ĺؼľд״̬תƷ̡Ƕһ dp[m][n],ʾ s[m]  t[n] ֮ǰмƥУǿд״̬תƷ\n s[m] != t[n]dp[m][n] = dp[m - 1][n]else dp[m][n] += (dp[m - 1][n] + dp[m - 1][n - 1])\n\n```cpp\nclass Solution {\npublic:\n    int numDistinct(string s, string t) {\n            int l1 = s.length(),l2 = t.length();\n    int dp[l1 + 1][l2 + 1];\n    memset(dp,0,sizeof(dp));\n    for(int i = 1;i <= l1;++i)\n        if(s[i - 1] == t[0])\n            dp[i][1] = 1;\n    for(int i = 1;i <= l1;++i)\n        for(int j = 1;j <= l2;++j)\n        {\n            if(s[i - 1] != t[j - 1])\n                dp[i][j] = dp[i - 1][j];\n            else\n                dp[i][j] += (dp[i - 1][j - 1] + dp[i - 1][j]);\n            //cout << dp[i][j] << \" \";\n        }\n    return dp[l1][l2];\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0118._Pascals_Triangle.md",
    "content": "## 118. Pascal's Triangle\n\n难度：Easy\n\n## 内容\n\n题目链接：https://leetcode.com/problems/pascals-triangle\n\nGiven a non-negative integer *numRows*, generate the first *numRows* of Pascal's triangle.\n\n![img](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif)\nIn Pascal's triangle, each number is the sum of the two numbers directly above it.\n\n**Example:**\n\n```\nInput: 5\nOutput:\n[\n     [1],\n    [1,1],\n   [1,2,1],\n  [1,3,3,1],\n [1,4,6,4,1]\n]\n```\n\n## 思路\n\n该题比较简单，杨辉三角形，从第三行开始，除了首尾，中间元素的值可通过如下公式计算：`cur[i] = prev[i] + prev[i-1]`\n\n计算当前行实现要点如下：\n\n* 拷贝上一行，并在末尾添加元素1\n* 倒着开始计算，除了首尾，`cur[i] += cur[i-1]`\n\n## 代码\n\n```\nclass Solution {\npublic:\n    vector<vector<int>> generate(int numRows) {\n        vector<vector<int>> res;\n        for (auto i = 0; i < numRows; ++i) {\n            vector<int> row;\n            if (!res.empty()) \n                row.assign(res.at(i-1).begin(), res.at(i-1).end());\n            row.emplace_back(1);\n            for (auto j = i - 1; j > 0; --j)\n                row[j] += row[j-1];\n            res.emplace_back(row);\n        }\n        return res;\n    }\n};\n```\n\n来源：https://github.com/xiaqunfeng/leetcode"
  },
  {
    "path": "docs/leetcode/cpp/0119._Pascals_Triangle-II.md",
    "content": "## 119. Pascal's Triangle II\n\n难度：Easy\n\n## 内容\n\n题目链接：https://leetcode.com/problems/pascals-triangle-ii\n\nGiven a non-negative index *k* where *k* ≤ 33, return the *k*th index row of the Pascal's triangle.\n\nNote that the row index starts from 0.\n\n![img](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif)\nIn Pascal's triangle, each number is the sum of the two numbers directly above it.\n\n**Example:**\n\n```\nInput: 3\nOutput: [1,3,3,1]\n```\n\n**Follow up:**\n\nCould you optimize your algorithm to use only *O*(*k*) extra space?\n\n## 思路\n\n思路和[上一题](118._Pascals_Triangle.md)一样，只不过这里不需要存每一行的数据。\n\n注意：和上一题相比，这里的 `rowIndex + 1 = numRows`\n\n## 代码\n\n```\nclass Solution {\npublic:\n    vector<int> getRow(int rowIndex) {\n        vector<int> res(rowIndex+1, 0);\n        res[0] = 1;\n        for (auto i = 0; i <= rowIndex; ++i) \n            for (auto j = i; j > 0; --j)\n                res[j] += res[j-1];\n        return res;\n    }\n};\n```\n\n来源：https://github.com/xiaqunfeng/leetcode"
  },
  {
    "path": "docs/leetcode/cpp/0120._Triangle.md",
    "content": "# 120. Triangle\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/triangle/\n  \n > 内容描述\n \n ```\n给定一个三角形，找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。\n\n例如，给定三角形：\n\n[\n     [2],\n    [3,4],\n   [6,5,7],\n  [4,1,8,3]\n]\n自顶向下的最小路径和为 11（即，2 + 3 + 5 + 1 = 11）。\n ```\n\n## 解题方案\n> 思路 1\n```\ndfs超时\n采用dp，自底向上更新每个数，每个数加上向下路径的最小和，更新到第一层既为第一层向下路径的最小和。\n```\n\n```cpp\n\nint minimumTotal(vector<vector<int>>& triangle) {\n    for (int i = triangle.size() - 2; i >= 0; i--)\n        for (int j = 0; j < triangle[i].size(); j++)\n            triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1]);\n    return triangle[0][0];\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0121._Best_Tim_to_Buy_and_Sell_Stock.md",
    "content": "# 121. Best Time to Buy and Sell Stock\n\n**<font color=red>ѶEasy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/best-time-to-buy-and-sell-stock/submissions/\n\n> \n\n```\n\n\nSay you have an array for which the ith element is the price of a given stock on day i.\n\nIf you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.\n\nNote that you cannot sell a stock before you buy one.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(n)*****- ռ临Ӷ: O(1)******\nֱӱ飬ÿμ¼СֵʱpriceСֵͱȽ```min(ans,prices[i] - min)```\n```cpp\nclass Solution {\npublic:\n    int maxProfit(vector<int>& prices) {\n        int min1 = INT_MAX;\n        int ans = 0;\n        for(int i = 0;i < prices.size();++i)\n            if(prices[i] > min1)\n                ans = max(ans,prices[i] - min1);\n            else\n                min1 = prices[i];\n        return ans;\n    }\n                \n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0122._Best_Time_to_Buy_and_Sell_Stock_II.md",
    "content": "# 122. Best Time to Buy and Sell Stock II\n\n**<font color=red>Ѷ:Easy<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/\n\n> \n\n```\nSay you have an array for which the ith element is the price of a given stock on day i.\n\nDesign an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).\n\nNote: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).\n\nExample 1:\n\nInput: [7,1,5,3,6,4]\nOutput: 7\nExplanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.\n             Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.\nExample 2:\n\nInput: [1,2,3,4,5]\nOutput: 4\nExplanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.\n             Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are\n             engaging multiple transactions at the same time. You must sell before buying again.\nExample 3:\n\nInput: [7,6,4,3,1]\nOutput: 0\nExplanation: In this case, no transaction is done, i.e. max profit = 0.\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\nñĽⷨܿͿ⣬ǿøõķO(N)ʱ临ӶȽ⡣i = 1顣 prices[i] > prices[i - 1]ans += prices[i] - prices[i - 1]\n\n```cpp\nclass Solution {\npublic:\n    int maxProfit(vector<int>& prices) {\n        int maxRet = 0; \n        for(int i = 1;i < prices.size();++i)\n            if(prices[i] > prices[i - 1])\n                maxRet += (prices[i] - prices[i - 1]);\n        return maxRet;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0123._Best_Time_to_Buy_and_Sell_Stock_III.md",
    "content": "# 123. Best Time to Buy and Sell Stock III\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/\n\n> \n\n```\nSay you have an array for which the ith element is the price of a given stock on day i.\n\nDesign an algorithm to find the maximum profit. You may complete at most two transactions.\n\nNote: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).\n\nExample 1:\n\nInput: [3,3,5,0,0,3,1,4]\nOutput: 6\nExplanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.\n             Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.\nExample 2:\n\nInput: [1,2,3,4,5]\nOutput: 4\nExplanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.\n             Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are\n             engaging multiple transactions at the same time. You must sell before buying again.\nExample 3:\n\nInput: [7,6,4,3,1]\nOutput: 0\nExplanation: In this case, no transaction is done, i.e. max profit = 0.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n)******\n\n֮ǰĲͬҪΣü仯ķ¼µi֮׵ֵǵڶÿ콻ֵֻ֮Ҫ飬һ콻ֵһöÿνףֵ\n\n```cpp\nclass Solution {\npublic:\n    int maxProfit(vector<int>& prices) {\n        int len = prices.size();\n        if(!len)\n            return 0;\n        int arr[len + 1];\n        memset(arr,0,sizeof(arr));\n        int max1 = prices[len - 1],price = 0;\n        for(int j = len - 2;j >= 0;--j)\n        {\n            if(prices[j] > max1)\n                max1 = prices[j];\n            arr[j] = max(arr[j + 1],max1 - prices[j]);\n        }\n        int ret = 0;\n        for(int i = 0;i < len;++i)\n            for(int j = i + 1;j < len;++j)\n                if(prices[j] > prices[i])\n                    ret = max(ret,prices[j] - prices[i] + arr[j + 1]);\n        return ret;\n    }\n};\n```\n> ˼·2\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)******\n\nڶַǶ˼·1ŻһνʱһСֵmin1˵i֮ǰСֵ֮飬ÿθmin1prices[i] - min1ֵ\n\n```cpp\nclass Solution {\npublic:\n    int maxProfit(vector<int>& prices) {\n        int len = prices.size();\n        if(!len)\n            return 0;\n        int arr[len + 1];\n        memset(arr,0,sizeof(arr));\n        int max1 = prices[len - 1],price = 0;\n        for(int j = len - 2;j >= 0;--j)\n        {\n            if(prices[j] > max1)\n                max1 = prices[j];\n            arr[j] = max(arr[j + 1],max1 - prices[j]);\n        }\n        int ret = 0;\n        int min1 = prices[0];\n        for(int i = 0;i < len;++i)\n        {\n            if(prices[i] < min1)\n                min1 = prices[i];\n            ret = max(ret,prices[i] - min1 + arr[i + 1]);\n        }\n        return ret;\n    }\n};"
  },
  {
    "path": "docs/leetcode/cpp/0124._Binary_Tree_Maximum_Path_Sum.md",
    "content": "# 124. Binary Tree Maximum Path Sum\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/binary-tree-maximum-path-sum/\n\n> \n\n```\nGiven a non-empty binary tree, find the maximum path sum.\n\nFor this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.\n\nExample 1:\n\nInput: [1,2,3]\n\n       1\n      / \\\n     2   3\n\nOutput: 6\nExample 2:\n\nInput: [-10,9,20,null,null,15,7]\n\n   -10\n   / \\\n  9  20\n    /  \\\n   15   7\n\nOutput: 42\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\n뵽DPʱ临ӶΪO(n^2)ǶֻˣǿøŻ㷨úȻ¼ڵ· ansȽϡ max(l,r) ڵֵ\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    int ans = INT_MIN;\n    int travel(TreeNode* root)\n    {\n        if(!root)\n            return 0;\n        int l = travel(root ->left);\n        int r = travel(root ->right);\n        if(l < 0)\n            l = 0;\n        if(r < 0)\n            r = 0;\n        int temp = r + l + root ->val;\n        ans = max(ans,temp);\n        return max(l,r) + root ->val;\n    }\n    int maxPathSum(TreeNode* root) {\n        travel(root);\n        if(ans == INT_MIN)\n            return 0;\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0127._Word_Ladde.md",
    "content": "# 127. Word Ladder\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n\n> ԭ\n\n* https://leetcode.com/problems/word-ladder/\n\n> \n\n```\nGiven two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:\n\nOnly one letter can be changed at a time.\nEach transformed word must exist in the word list. Note that beginWord is not a transformed word.\nNote:\n\nReturn 0 if there is no such transformation sequence.\nAll words have the same length.\nAll words contain only lowercase alphabetic characters.\nYou may assume no duplicates in the word list.\nYou may assume beginWord and endWord are non-empty and are not the same.\nExample 1:\n\nInput:\nbeginWord = \"hit\",\nendWord = \"cog\",\nwordList = [\"hot\",\"dot\",\"dog\",\"lot\",\"log\",\"cog\"]\n\nOutput: 5\n\nExplanation: As one shortest transformation is \"hit\" -> \"hot\" -> \"dot\" -> \"dog\" -> \"cog\",\nreturn its length 5.\nExample 2:\n\nInput:\nbeginWord = \"hit\"\nendWord = \"cog\"\nwordList = [\"hot\",\"dot\",\"dog\",\"lot\",\"log\"]\n\nOutput: 0\n\nExplanation: The endWord \"cog\" is not in wordList, therefore no possible transformation.\n\n```\n> ˼·1\n\n******- ʱ临Ӷ: O(EV+V^3)******- ռ临Ӷ: O(n^2)******\n\nһ⣬һBFS⣬ǹһͼöά鴢棬ȻBFSһһEǱߵvǽڵ\n\n```cpp\nclass Solution {\npublic:\n    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {\n        wordList.push_back(beginWord);\n        int len = wordList[0].length(),length = wordList.size();\n        queue<int> q;\n        vector<int> d[length];\n        int min_l[length];\n        for(int i = 0;i < length;++i)\n            min_l[i] = INT_MAX;\n        for(int i = 0;i < length;++i)\n            for(int j = i + 1;j <length;++j)\n            {\n                int count1 = 0;\n                for(int t = 0;t < len;++t)\n                    if(wordList[i][t] != wordList[j][t])\n                        count1++;\n                if(count1 == 1)\n                {\n                    d[i].push_back(j);\n                    d[j].push_back(i);\n                }\n            }\n        int exit = -1;\n        for(int i = 0;i < length;++i)\n            if(wordList[i] == endWord)\n            {\n                exit = i;\n                min_l[i] = 0;\n                q.push(i);\n            }\n        if(exit == -1)\n            return 0;\n        while(q.size())\n        {\n            int t = q.front();\n            for(int i = 0;i < d[t].size();++i)\n                if(min_l[d[t][i]] > min_l[t] + 1)\n                {\n                    q.push(d[t][i]);\n                    min_l[d[t][i]] = min_l[t] + 1;\n                    if(d[t][i] == length - 1)\n                        return min_l[length - 1] + 1;\n                }\n            q.pop();\n        }\n        return 0;\n    }\n};\n```\n\n\n> ˼·2\n\n******- ʱ临Ӷ: O(EV*len)******- ռ临Ӷ: O(V)******\n\nķЧʲߣ˿Ըunordered_setеַȻÿֻĶһַsetвǷڼɡlenÿʵĳȡ\n\n```cpp\nclass Solution {\npublic:\n    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {\n        wordList.push_back(beginWord);\n        int len = wordList[0].length(),length = wordList.size();\n        queue<string> q;\n        unordered_set<string> s(wordList.begin(),wordList.end());\n        int min_l[length];\n        auto pos = s.find(endWord);\n        if(pos == s.end())\n            return 0;\n        q.push(*pos);\n        int level = 1;\n        string count1 = endWord;\n        while(q.size())\n        {\n            string temp1 = q.front();\n            for(int j = 0;j < temp1.size();++j)\n            {\n                string temp = temp1;           \n                for(int i = 'a';i <= 'z';++i)\n                {\n                    temp[j] = i;\n                    if(temp != temp1 && s.find(temp) != s.end())\n                    {\n                        q.push(temp);\n                        if(temp == beginWord)\n                            return level + 1;\n                        s.erase(temp);\n                    }\n                    temp = temp1;\n                }\n            }\n            if(count1 == temp1)\n            {\n                count1 = q.back();\n                level++;\n            }\n            s.erase(temp1);\n            q.pop();\n        }\n        return 0;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0128._Longest_Consecutive_Sequence.md",
    "content": "# 128. Longest Consecutive Sequence\n\n**<font color=red>难度:Hard<font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/longest-consecutive-sequence/\n\n> 内容描述\n\n```\nGiven an unsorted array of integers, find the length of the longest consecutive elements sequence.\n\nYour algorithm should run in O(n) complexity.\n\nExample:\n\nInput: [100, 4, 200, 1, 3, 2]\nOutput: 4\nExplanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.\n```\n\n> 思路1\n******- 时间复杂度: O(n)******- 空间复杂度: O(1)******\n\n先对数组进行排序。在用unique()函数去除重复的数字。在遍历数组，找到最长的连续数字。时间复杂度为O(nlgn)。\n\n```cpp\nclass Solution {\npublic:\n    int longestConsecutive(vector<int>& nums) {\n        if(!nums.size())\n            return 0;\n        sort(nums.begin(),nums.end());\n        auto end_pos = unique(nums.begin(),nums.end());\n        int j = end_pos - nums.begin();\n        int ans = 1,sum = 1;\n        for(int i = 1;i < j;++i)\n        {\n            if(nums[i] == nums[i - 1] + 1)\n                sum++;\n            else\n                sum = 1;\n            ans = max(ans,sum);\n        }\n        return ans;\n    }\n};\n```\n> 思路2\n******- 时间复杂度: O(nlgn)******- 空间复杂度: O(1)******\nc++中的unordered_map是用hash桶实现的，所以可以在线性时间内完成。县遍历数组，用nums[i]作为unordered_map的键值。0作为 value。0表示此时的nums[i]还没被遍历过。接着遍历数组，用DFS搜索每个nums[i]的最长连续数字。被遍历过的nums[i]的unordered_map值设为1\n```cpp\nclass Solution {\npublic:\n    int longestConsecutive(vector<int>& nums) {\n        if(!nums.size())\n            return 0;\n        unordered_map<int,int> m;\n        for(int i = 0;i < nums.size();++i)\n            m[nums[i]] = 0;\n        int ans = 0;\n        for(int i = 0;i < nums.size();++i)\n        {\n            if(m[nums[i]])\n                continue;\n            m[nums[i]] = 1;\n            int temp = nums[i] + 1,sum = 0;\n            while(m.find(temp) != m.end())\n                m[temp++] = 1;\n            sum = temp - nums[i];\n            temp = nums[i] - 1;\n            //cout << temp << endl;\n            while(m.find(temp) != m.end())\n                m[temp--] = 1;\n            sum += (nums[i] - temp - 1);\n            ans = max(ans,sum);\n        }\n        return ans;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0129._Sum_Root_to_Leaf_Numbers.md",
    "content": "# 129. Sum Root to Leaf Numbers\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/\n  \n > 内容描述\n \n ```\n给定一个二叉树，它的每个结点都存放一个 0-9 的数字，每条从根到叶子节点的路径都代表一个数字。\n\n例如，从根到叶子节点路径 1->2->3 代表数字 123。\n\n计算从根到叶子节点生成的所有数字之和。\n\n说明: 叶子节点是指没有子节点的节点。\n\n示例 1:\n\n输入: [1,2,3]\n    1\n   / \\\n  2   3\n输出: 25\n解释:\n从根到叶子节点路径 1->2 代表数字 12.\n从根到叶子节点路径 1->3 代表数字 13.\n因此，数字总和 = 12 + 13 = 25.\n示例 2:\n\n输入: [4,9,0,5,1]\n    4\n   / \\\n  9   0\n / \\\n5   1\n输出: 1026\n解释:\n从根到叶子节点路径 4->9->5 代表数字 495.\n从根到叶子节点路径 4->9->1 代表数字 491.\n从根到叶子节点路径 4->0 代表数字 40.\n因此，数字总和 = 495 + 491 + 40 = 1026.\n ```\n\n## 解题方案\n> 思路 1\n```\n深搜，记录路径，到叶子节点相加\n```\n\n```cpp\nvoid dfs(TreeNode* root, string path, int& sum){\n    if(root==NULL){\n        return;\n    }\n    if(root->left==NULL && root->right==NULL){\n        path = path+std::to_string(root->val);\n        int tmp = std::stoi(path);\n        sum+=tmp;\n        return ;\n    }\n    dfs(root->left, path+std::to_string(root->val), sum);\n    dfs(root->right, path+std::to_string(root->val), sum);\n}\nint sumNumbers(TreeNode* root) {\n    int sum=0;\n    dfs(root, \"\", sum);\n    return sum;\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0131._Palindrome_Partitioning.md",
    "content": "# 131. Palindrome Paritionaing\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/palindrome-partitioning/\n  \n > 内容描述\n \n ```\n给定一个字符串 s，将 s 分割成一些子串，使每个子串都是回文串。\n\n返回 s 所有可能的分割方案。\n\n示例:\n\n输入: \"aab\"\n输出:\n[\n  [\"aa\",\"b\"],\n  [\"a\",\"a\",\"b\"]\n]\n ```\n\n## 解题方案\n> 思路 1\n```\n回溯，判断是否回文。\n```\n\n```cpp\nbool isValid(string str){\n    for(int i=0;i<str.length()/2;i++){\n        if(str[i]!=str[str.length()-i-1])\n            return false;\n    }\n    return true;\n}\nvoid dfs(int start, vector<string>& path, vector<vector<string>>& ans, string s){\n    if(start == s.length()){\n        ans.push_back(path);\n        return ;\n    }\n    for(int i=start;i<s.length();i++){\n        if(isValid(s.substr(start, i-start+1))){\n            path.push_back(s.substr(start, i-start+1));\n            dfs(i+1, path, ans, s);\n            path.pop_back();\n        }\n    }\n    \n}\nvector<vector<string>> partition(string s) {\n    vector<vector<string>> ans;\n    if(s.length()==0)\n        return ans;\n    vector<string> path;\n    dfs(0, path, ans, s);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0136._Single_Numbe.md",
    "content": "# 136. Single Numbe\n\n**<font color=red>难度:Easy<font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/single-number/\n\n> 内容描述\n\n```\nGiven a non-empty array of integers, every element appears twice except for one. Find that single one.\n\nNote:\n\nYour algorithm should have a linear runtime complexity. Could you implement it without using extra memory?\n\nExample 1:\n\nInput: [2,2,1]\nOutput: 1\nExample 2:\n\nInput: [4,1,2,1,2]\nOutput: 4\n```\n\n> 思路1\n******- 时间复杂度: O(n)******- 空间复杂度: O(1)******\n\n用异或运算解决这道题，这里用了异或运算的几个性质，异或的交换和结合律，还有两个相同的数异或的值为0，任何数异或0为它本身。有了这些基本只是之后，我们只要对数组进行异或运算得到的数就是答案。因为只有一个数是 single number，其余的数都成双，那么最后就相当于single number异或0\n\n```cpp\nclass Solution {\npublic:\n    int singleNumber(vector<int>& nums) {\n        int ans = nums[0];\n        for(int i = 1;i < nums.size();++i)\n            ans ^= nums[i];\n        return ans;\n    }\n};\n```\n> 思路2\n******- 时间复杂度: O(n)******- 空间复杂度: O(1)******\n\n第二种思路将所有数转成二进制，记录下每一位不为2的倍数，这些位为1，其余为0，求出最后的数就是答案。\n\n```cpp\nclass Solution {\npublic:\n    int singleNumber(vector<int>& nums) {\n         int arr[32][2],t = 1;\n        memset(arr,0,sizeof(arr));\n        for(int i = 0;i < nums.size();++i)\n        {\n            int count1 = 0;\n            if(nums[i] < 0)\n            {\n                t *= -1;\n                nums[i] *= -1;\n            }\n            while(nums[i])\n            {\n                arr[count1++][nums[i] % 2]++;\n                nums[i] /= 2;\n            }\n        }\n        int ans = 0;\n        for(int i = 0;i < 32;++i)\n            if(arr[i][1] % 2)\n                ans += pow(2,i);\n        if(t < 0)\n            ans *= -1;\n        return ans;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0137._Single_Number_II.md",
    "content": "# 137.Single Number II\n\n**<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n > 原题连接\n* https://leetcode.com/problems/single-number-ii/\n > 内容描述\n ```\nGiven a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.\n\nNote:\n\nYour algorithm should have a linear runtime complexity. Could you implement it without using extra memory?\n\nExample 1:\n\nInput: [2,2,3,2]\nOutput: 3\nExample 2:\n\nInput: [0,1,0,1,0,1,99]\nOutput: 99\n ```\n\n## 解题方案\n> 思路\n```\n相同的数有相同的二进制，相同位置有相同的1，0；所以如果都出现3次，那么相同位上出现的1和0都是3的倍数\n所以，统计不同位上1、0的个数，如果不是3的倍数，说明出现次数不是3的倍数。\n所有不为3倍数的位加起来就是结果。\n```\n\n```cpp\nclass Solution {\npublic:\n    int singleNumber(vector<int>& nums) {\n        int arr[32][2],t = 0;\n        memset(arr,0,sizeof(arr));\n        for(int i = 0;i < nums.size();++i)\n        {\n            int count1 = 0;\n            long long temp = nums[i];\n            if(nums[i] < 0)\n            {\n                t++;\n                temp *= -1;\n            }\n            while(temp)\n            {\n                arr[count1++][temp % 2]++;\n                temp /= 2;\n            }\n        }\n        int ans = 0;\n        for(int i = 0;i < 32;++i)\n            if(arr[i][1] % 3)\n                ans += pow(2,i);\n        if(t % 3)\n            ans *= -1;\n        return ans;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0141._Linked_List_Cycle.md",
    "content": "#141. linked list cycle\n\n**<font color=red>Ѷ:Easy</font>**\n\n## ˢ\n\n> ԭ\n\n*https://leetcode.com/problems/linked-list-cycle/\n* \n> \n\n```\nGiven a linked list, determine if it has a cycle in it.\n\nFollow up:\nCan you solve it without using extra space?\n```\n\n## ⷽ\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\n͵Ŀָеãָ룬ÿѭһ1һ2ָл\n\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    bool hasCycle(ListNode *head) {\n        if(head == nullptr)\n            return false;\n        ListNode* l1 = head,*l2 = head ->next;\n        while(true)\n        {\n            if(l2 == nullptr || l2 ->next == nullptr)\n                return false;\n            if(l1 == l2)\n                return true;\n            l1 = l1 ->next;\n            l2 = l2 ->next ->next;\n        }\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0142._Linked_List_Cycle_II.md",
    "content": "# 142. linked list cycle II\n\n***<font color=red>难度:Medium</font>***\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/linked-list-cycle-ii/\n\n> 内容描述\n\n```\nGiven a linked list, return the node where the cycle begins. If there is no cycle, return null.\n\nNote: Do not modify the linked list.\n\nFollow up:\nCan you solve it without using extra space?\n```\n\n## 解题方案\n\n> 思路\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n上一道题已经解决了链表是否有环的问题，那么如何判断环的入口在哪里，我们先设入口链表的头的距离为m，两个人指针相遇的节点距离入口为x，l2比l1多走 n 圈，环部分的链表长度为p。这样，我们就得到了如下公式。 \n```\n2(m + x) = m + n * p + x\n\n```\n化简得到\n```\nm = n * p - x\n\n```\n接着我们再定义一个指针 ret，当 ret 移动 m 个，l1刚好移动 n * p - x，就是二者相遇的地方即为入口\n\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode *detectCycle(ListNode *head) {\n        if(head == nullptr)\n        return nullptr;\n    ListNode* l1 = head,*l2 = head;\n    int count1 = 0,count2 = 0;\n    while(1)\n    {\n        if(l2 == nullptr || l2 ->next == nullptr)\n            return nullptr;\n        l1 = l1 ->next;\n        ++count1;\n        l2 = l2 ->next ->next;\n\n        ++count2;\n        if(l1 == l2)\n            break;\n    }\n    ListNode* ret = head;\n    while(1)\n    {\n        if(l1 == ret)\n            return ret;\n        ret = ret ->next;\n        l1 = l1 ->next;\n    }\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0144._Binary_Tree_Preorder_Traversal.md",
    "content": "# 144. Binary Tree Preorder Traversal\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/binary-tree-preorder-traversal/\n  \n > 内容描述\n \n ```\n 给定一个二叉树，返回它的 前序 遍历。\n\n 示例:\n\n输入: [1,null,2,3]  \n   1\n    \\\n     2\n    /\n   3 \n\n输出: [1,2,3]\n\n ```\n\n## 解题方案\n> 思路 1\n```\n递归\n```\n\n```cpp\nvoid dfs(TreeNode* root, vector<int> &ans){\n    if(root==NULL)\n        return ;\n    ans.push_back(root->val);\n    dfs(root->left, ans);\n    dfs(root->right, ans);\n}\nvector<int> preorderTraversal(TreeNode* root) {\n    vector<int> ans;\n    dfs(root, ans);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0145._Binary_Tree_Postorder_Traversal.md",
    "content": "# 145. Binary Tree Postorder Traversal\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/binary-tree-postorder-traversal/\n\n> \n\n```\nGiven a binary tree, return the postorder traversal of its nodes' values.\n\nExample:\n\nInput: [1,null,2,3]\n   1\n    \\\n     2\n    /\n   3\n\nOutput: [3,2,1]\nFollow up: Recursive solution is trivial, could you do it iteratively?\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)******\n\nж治ڣж治ڣroot->valɡ\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    void travel(TreeNode* root,vector<int>& v)\n    {\n        if(!root)\n            return;\n        if(root ->left)\n            travel(root ->left,v);   \n        if(root ->right)\n            travel(root ->right,v);\n        v.push_back(root ->val);\n    }\n    vector<int> postorderTraversal(TreeNode* root) {\n        vector<int> v;\n        travel(root,v);\n        return v;\n    }\n};\n```\n> ˼·2\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)******\n\nĿᵽ˲õݹñķʽȥ⡣ôǾҪջȥԪأʱǻҪһջԪǷӦ pop\n\n```cpp\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    vector<int> postorderTraversal(TreeNode* root) {\n            vector<TreeNode*> v;\n        vector<int> ans;\n        vector<int> count1;\n        if(root)\n        {\n            v.push_back(root);\n            count1.push_back(0);\n        }\n        while(v.size())\n        {\n            int index = v.size();\n            if(!count1[index - 1] && v[index -1] ->left)\n            {\n                count1[index - 1] = 1;\n                v.push_back(v[index - 1] ->left);\n                count1.push_back(0);\n            }\n            else if(count1[index - 1] != 2 && v[index - 1] ->right)\n            {\n                count1[index - 1] = 2;\n                v.push_back(v[index - 1] ->right);\n                count1.push_back(0);\n            }\n            else\n            {\n                ans.push_back(v[index - 1] ->val);\n                count1.pop_back();\n                v.pop_back();\n            }\n        }\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0147._Insert_on_Sort_List.md",
    "content": "# 147. Insertion Sort List\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/insertion-sort-list/\n\n> \n\n```\nSort a linked list using insertion sort.\n\n\nA graphical example of insertion sort. The partial sorted list (black) initially contains only the first element in the list.\nWith each iteration one element (red) is removed from the input data and inserted in-place into the sorted list\n \n\nAlgorithm of Insertion Sort:\n\nInsertion sort iterates, consuming one input element each repetition, and growing a sorted output list.\nAt each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there.\nIt repeats until no input elements remain.\n\nExample 1:\n\nInput: 4->2->1->3\nOutput: 1->2->3->4\nExample 2:\n\nInput: -1->5->3->4->0\nOutput: -1->0->3->4->5\n```\n\n> ˼·\n******- ʱ临Ӷ: O(N^2)******- ռ临Ӷ: O(1)******\n\nв򡣺ͨĲһҪעҪĲϤĳֵеλʱҪڵ뵽ʵλãִĲɾ\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode* insertionSortList(ListNode* head) {\n        if(!head)\n            return head;\n            ListNode* current = head ->next;\n        ListNode* pre = head;\n        while(current)\n        {\n            ListNode* temp2 = head;\n            ListNode* temp1 = head;\n            while(temp2 ->val < current ->val)\n            {\n                temp1 = temp2;\n                temp2 = temp2 ->next;\n            }\n            if(temp1 != temp2)\n                temp1 ->next = current;\n            else\n                head = current;\n            if(temp2 != current)\n            {\n                pre ->next = current ->next;\n                current ->next = temp2;\n                current = pre ->next;\n            }\n            else\n            {\n                pre = current;\n                current = current ->next;\n            }\n        }\n        return head;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0148._Sort_list.md",
    "content": "# 148.Sort list\n\n**<font color=red>ѶMedium</font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/sort-list/\n\n> \n\n```\nSort a linked list in O(n log n) time using constant space complexity.\n\nExample 1:\n\nInput: 4->2->1->3\nOutput: 1->2->3->4\nExample 2:\n\nInput: -1->5->3->4->0\nOutput: -1->0->3->4->5\n```\n> ˼·\n******- ʱ临Ӷ: O(nlgn)******- ռ临Ӷ: O(n)******\n\n˼·ͷ͵˸c++е sort() 㷨ֽе val δУ򡣽ٰемɡ\n\n```cpp\n/**\n * Definition for singly-linked list.\n * struct ListNode {\n *     int val;\n *     ListNode *next;\n *     ListNode(int x) : val(x), next(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    ListNode* sortList(ListNode* head) {\n        vector<int> v;\n        ListNode* current = head;\n        while(current)\n        {\n            v.push_back(current ->val);\n            current = current ->next;\n        }\n        sort(v.begin(),v.end());\n        current = head;\n        int i = 0;\n        while(current)\n        {\n            current ->val = v[i++];\n            current = current ->next;\n        }\n        return head;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0151._Reverse_Words_in_a_String.md",
    "content": "# 151. Reverse Words in a String\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/reverse-words-in-a-string/\n\n> \n\n```\nGiven an input string, reverse the string word by word.\n\nExample:  \n\nInput: \"the sky is blue\",\nOutput: \"blue is sky the\".\nNote:\n\nA word is defined as a sequence of non-space characters.\nInput string may contain leading or trailing spaces. However, your reversed string should not contain leading or trailing spaces.\nYou need to reduce multiple spaces between two words to a single space in the reversed string.\n```\n\n\n> ˼·\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)******\n\nűȱ飬ոΪһʣעڱ߽жϣڿһµ string ոյĵʣֵ sܵ˵ѡǻһСģ֮ĿոǶģַĿͷĩβҲжոҪдѭո\n\n```cpp\nclass Solution {\npublic:\n    void reverseWords(string &s) {\n        int i = 0,j = s.length();\n        while(i < j && s[i] == ' ')\n            i++;\n        j--;\n        while(j >= i && s[j] == ' ')\n            j--;\n        j++;\n        string s1;\n        while(j >= i)\n        {\n            int temp = j - 1;\n            while(temp >= 0 && s[temp] != ' ')\n                temp--;\n            int t = temp;\n            temp++;\n            while(j > temp)\n                s1.push_back(s[temp++]);\n            j = t - 1;\n            while(j >= i && s[j] == ' ')\n                j--;\n            j++;\n            if(j >= i)\n                s1.push_back(' ');\n        }\n        s = s1;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0153._Find_Minimum_in_Rotated_Sorted_Array.md",
    "content": "## 153. Find Minimum in Rotated Sorted Array\n\n难度：Medium\n\n## 内容\n\n题目链接：https://leetcode.com/problems/find-minimum-in-rotated-sorted-array\n\nSuppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.\n\n(i.e.,  `[0,1,2,4,5,6,7]` might become  `[4,5,6,7,0,1,2]`).\n\nFind the minimum element.\n\nYou may assume no duplicate exists in the array.\n\n**Example 1:**\n\n```\nInput: [3,4,5,1,2] \nOutput: 1\n```\n\n**Example 2:**\n\n```\nInput: [4,5,6,7,0,1,2]\nOutput: 0\n```\n\n## 思路\n\n最简单的方法，挨个遍历，如果当前值小于前一个值，那么输出当前值即可，时间复杂度为O(n)。\n二分查找法，时间复杂度为O(log(n))。\n\n## 代码\n\n快速简单的写了一个，提交，过了。\n\n```\nclass Solution {\npublic:\n    int findMin(vector<int>& nums) {\n        int res_idx = 0;\n        for (int i = 1; i < nums.size(); ++i)\n            if (nums[i] < nums[i-1]) {\n                res_idx = i;\n                break;\n            }\n        return nums[res_idx];\n    }\n};\n```\n\n二分查找的简单实现\n\n```\nclass Solution {\npublic:\n    int findMin(vector<int>& nums) {\n        int left = 0, right = nums.size() - 1;\n        while (nums[left] > nums[right]) {\n            int mid = (right + left) >> 1;\n            if (nums[mid] >= nums[left])\n                left = mid + 1;\n            else\n                right = mid;\n        }\n        return nums[left];\n    }\n};\n```\n\n用迭代器来实现\n\n```\nclass Solution {\npublic:\n    int findMin(vector<int>& nums) {\n        auto begin = nums.begin();\n        auto end = std::prev(nums.end());\n        while (*begin > *end) {\n            auto gap = (end - begin) >> 1;\n            *next(begin, gap) >= *begin ? advance(begin, gap + 1) : advance(end, -gap); \n        }\n        return *begin;\n    }\n};\n```\n\n来源：https://github.com/xiaqunfeng/leetcode"
  },
  {
    "path": "docs/leetcode/cpp/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md",
    "content": "## 154. Find Minimum in Rotated Sorted Array II\n\n难度：Hard\n\n## 内容\n\n题目链接：https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii\n\nSuppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.\n\n(i.e.,  `[0,1,2,4,5,6,7]` might become  `[4,5,6,7,0,1,2]`).\n\nFind the minimum element.\n\nThe array may contain duplicates.\n\n**Example 1:**\n\n```\nInput: [1,3,5]\nOutput: 1\n```\n\n**Example 2:**\n\n```\nInput: [2,2,2,0,1]\nOutput: 0\n```\n\n**Note:**\n\n- This is a follow up problem to [Find Minimum in Rotated Sorted Array](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array).\n- Would allow duplicates affect the run-time complexity? How and why?\n\n## 思路\n\n这题竟然是hard，好尴尬。最简单时间复杂度为O(n)的方法，我把前一题的代码一行不动的挪过来，Accepted。\n二分查找法，时间复杂度为O(log(n))。\n\n## 代码\n\nO(n)，和前一题代码一样\n\n```\nclass Solution {\npublic:\n    int findMin(vector<int>& nums) {\n        int res_idx = 0;\n        for (int i = 1; i < nums.size(); ++i)\n            if (nums[i] < nums[i-1]) {\n                res_idx = i;\n                break;\n            }\n        return nums[res_idx];\n    }\n};\n```\n\n二分法实现\n\n```\nclass Solution {\npublic:\n    int findMin(vector<int>& nums) {\n        int left = 0, right = nums.size() - 1;\n\n        while (left < right && nums[left] >= nums[right]) {\n            int mid = left + (right - left) / 2;\n            if (nums[mid] == nums[left]) {\n                ++left;\n            } else if (nums[mid] < nums[left]) {\n                right = mid;\n            } else {\n                left = mid + 1;\n            }\n        }\n\n        return nums[left];\n    }\n};\n```\n\n迭代器二分查找的实现\n\n```\nclass Solution {\npublic:\n    int findMin(vector<int>& nums) {\n        auto left = nums.begin();\n        auto right = std::prev(nums.end());\n        while (*left >= *right && left < right) {\n            auto gap = (right - left) >> 1;\n            if (*next(left, gap) == *left)\n                advance(left, 1);\n            else if (*next(left, gap) < *left)\n                advance(right, -gap);\n            else\n                advance(left, gap + 1);\n        }\n        return *left;\n};\n```\n\n来源：https://github.com/xiaqunfeng/leetcode"
  },
  {
    "path": "docs/leetcode/cpp/0160._Intersection_Of_Two_Linked_Lists.md",
    "content": "# 160 intersection_of_Two_Linked_Lists\n **<font color=red>难度: Easy</font>**\n## 刷题内容\n>原题连接\n* https://leetcode-cn.com/problems/intersection-of-two-linked-lists/\n>内容描述\n```\nWrite a program to find the node at which the intersection of two singly linked lists begins.\n```\n\n## 解题方案\n> 思路 1\n```\n1.  求长度差\n2.  长的链表先走掉长的部分\n3.  一起走，相遇即为交点 \n```\n```cpp\n    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {\n        int lena=0;\n        int lenb=0;\n        ListNode *a = headA;\n        ListNode *b = headB;\n        while(a){\n            lena++;\n            a=a->next;\n        }\n        while(b){\n            lenb++;\n            b=b->next;\n        }\n        if(a!=b)\n            return NULL;\n        int sub=abs(lena-lenb);\n        if(lena>lenb){\n            while(sub--)\n                headA=headA->next;\n        }else\n            while(sub--)\n                headB=headB->next;\n        while(headA!=headB){\n            headA = headA->next;\n            headB = headB->next;\n        }\n        return headA;\n    }\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0164._Maximum_Gap.md",
    "content": "# 164. Maximum Gap\n\n**<font color=red>Ѷ:Hard<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/maximum-gap/\n\n> \n\n```\nGiven an unsorted array, find the maximum difference between the successive elements in its sorted form.\n\nReturn 0 if the array contains less than 2 elements.\n\nExample 1:\n\nInput: [3,6,9,1]\nOutput: 3\nExplanation: The sorted form of the array is [1,3,6,9], either\n             (3,6) or (6,9) has the maximum difference 3.\nExample 2:\n\nInput: [10]\nOutput: 0\nExplanation: The array contains less than 2 elements, therefore return 0.\nNote:\n\nYou may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.\nTry to solve it in linear time/space.\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(NlgN)******- ռ临Ӷ: O(1)******\n\nͨķȥʵѣȶٱ飬μ nums[i] - nums[i - 1] ֵ\n\n```cpp\nclass Solution {\npublic:\n    int maximumGap(vector<int>& nums) {\n        if(nums.size() < 2)\n            return 0;\n        sort(nums.begin(),nums.end());\n        int ans = INT_MIN;\n        for(int i = 1;i < nums.size();++i)\n            ans = max(ans,nums[i] - nums[i - 1]);\n        return ans;\n    }\n};\n```\n\n> ˼·2\n******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)******\n\nĿеnoteѾʾԵʱͿռ临ӶɡڵֵĴС32bitsڵģôǿͰ߻򣬾㷨͸ӶȵƵԲο㷨ۡǲ˻\n```cpp\nclass Solution {\npublic:\n    int maximumGap(vector<int>& nums) {\n        if(nums.size() < 2)\n            return 0;\n        int res[nums.size()];\n        int t[nums.size()][10];\n        for(int i = 0;i < nums.size();++i)\n        {\n            res[i] = i;\n            for(int j = 0;j < 10;++j)\n                t[i][j] = 0;\n            int temp = nums[i],j = 9;\n            while(temp)\n            {\n                t[i][j--] = temp % 10;\n                temp /= 10;\n            }\n        }\n        for(int i = 9;i >= 0;--i)\n        {\n            int bucket[nums.size()],count1[10];\n            memset(count1,0,sizeof(count1));\n            for(int j = 0;j < nums.size();++j)\n                count1[t[res[j]][i]]++;\n            for(int j = 1;j < 10;++j)\n                count1[j] += count1[j - 1];\n            for(int j = nums.size() - 1;j >= 0;--j)\n                bucket[--count1[t[res[j]][i]]] = res[j];\n            for(int j = 0;j < nums.size();++j)\n                res[j] = bucket[j];\n        }\n        int ans INT_MIN;\n        for(int i = 1;i < nums.size();++i)\n            ans = max(ans,nums[res[i]] - nums[res[i - 1]]);\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0166._Fraction_to_Recurring_Decimal.md",
    "content": "# 166. Fraction to Recurring Decimal\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/fraction-to-recurring-decimal/\n\n> \n\n```\nGiven two integers representing the numerator and denominator of a fraction, return the fraction in string format.\n\nIf the fractional part is repeating, enclose the repeating part in parentheses.\n\nExample 1:\n\nInput: numerator = 1, denominator = 2\nOutput: \"0.5\"\nExample 2:\n\nInput: numerator = 2, denominator = 1\nOutput: \"2\"\nExample 3:\n\nInput: numerator = 2, denominator = 3\nOutput: \"0.(6)\"\n```\n\n> ˼·\n******- ʱ临Ӷ: O(nlgn)******- ռ临Ӷ: O(n)******\n\n⿼ǵĵȽ϶࣬mapÿεԼõĴַеλãֻҪmapгֹˣʾʼѭҪעõĴпǸҪעӸšӦΪintСֵ-1intֵlong longͱ\n\n```cpp\nclass Solution {\npublic:\n    void join_str(string& str,long long num,int t)\n    {\n        if(!num)\n        {\n            if(t < 0)\n                str.push_back('-');\n            str.push_back('0');\n            return;\n        }\n        while(num)\n        {\n            str.push_back(num % 10 + '0');\n            num /= 10;\n        }\n        if(t < 0)\n            str.push_back('-');\n        reverse(str.begin(),str.end());\n    }\n    string fractionToDecimal(int numerator, int denominator) {\n        map<long long,int> m;\n        if(!numerator)\n            return \"0\";\n        int t = 1;\n        long long n1 = numerator,d1 = denominator;\n        if(numerator < 0)\n        {\n            t *= -1;\n            n1 *= -1;\n        }\n        if(denominator < 0)\n        {\n            t *= -1;\n            d1 *= -1;\n        }\n        long long num = n1 / d1;\n        string ans;\n        join_str(ans,num,t);\n        long long quotient = n1 % d1;\n        if(quotient)\n            ans.push_back('.');\n        string temp;\n        int count1 = 0;\n        while(quotient)\n        {\n            long long new_num = quotient * 10;\n            if(m[new_num])\n            {\n                temp.push_back(')');\n                count1 = m[new_num];\n                break;\n            }\n            m[new_num] = temp.length() + 1;\n            temp.push_back(new_num / d1 + '0');\n            quotient = new_num % d1;\n        }\n        if(count1)\n        {\n            ans.append(temp.begin(),temp.begin() + count1 - 1);\n            ans.push_back('(');\n            ans.append(temp.begin() + count1 - 1,temp.end());\n        }\n        else\n            ans.append(temp.begin(),temp.end());\n        return ans;\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0167._Two_Sum_II-Input_array_is_sorted.md",
    "content": "## 167. Two Sum II - Input array is sorted\n\n难度：Easy\n\n## 内容\n\n原题链接：https://leetcode.com/problems/two-sum-ii-input-array-is-sorted\n\nGiven an array of integers that is already **sorted in ascending order**, find two numbers such that they add up to a specific target number.\n\nThe function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.\n\n**Note:**\n\n- Your returned answers (both index1 and index2) are not zero-based.\n- You may assume that each input would have *exactly* one solution and you may not use the *same* element twice.\n\n**Example:**\n\n```\nInput: numbers = [2,7,11,15], target = 9\nOutput: [1,2]\nExplanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.\n```\n\n## 思路\n\n关键点：\n\n- 升序排列\n- 一定有解\n\n## 代码\n\n```\nclass Solution {\npublic:\n    vector<int> twoSum(vector<int>& numbers, int target) {\n        int left = 0, right = numbers.size() - 1;\n        while (left < right) {\n            int sum = numbers[left] + numbers[right];\n            if (sum < target) \n                left++;\n            else if (sum > target) \n                right--;\n            else \n                return {left + 1, right + 1};\n        }\n        return {0, 0};\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0199._Binary_Tree_Right_Side_View.md",
    "content": "# 199. Binary Tree Right Side View\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/binary-tree-right-side-view/\n  \n > 内容描述\n \n ```\n给定一棵二叉树，想象自己站在它的右侧，按照从顶部到底部的顺序，返回从右侧所能看到的节点值。\n\n示例:\n\n输入: [1,2,3,null,5,null,4]\n输出: [1, 3, 4]\n解释:\n\n   1            <---\n /   \\\n2     3         <---\n \\     \\\n  5     4       <---\n ```\n\n## 解题方案\n> 思路 1\n```\n二叉树层次遍历\n```\n\n```cpp\nvector<int> rightSideView(TreeNode* root) {\n    vector<int> ans;\n    if(root==NULL)\n        return ans;\n    vector<TreeNode*> stack;\n    stack.push_back(root);\n    \n    while(!stack.empty()){\n        vector<TreeNode*> tmp;\n        TreeNode* node;\n        for(int i=0;i<stack.size();i++){\n            node = stack[i];\n            if(node->left)\n                tmp.push_back(node->left);\n            if(node->right)\n                tmp.push_back(node->right);\n        }\n        ans.push_back(node->val);\n        stack = tmp;\n    }\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0216._Combination_Sum_III.md",
    "content": "# 216. Combination Sum III\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/combination-sum-iii/\n  \n > 内容描述\n \n ```\n找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数，并且每种组合中不存在重复的数字。\n\n说明：\n\n所有数字都是正整数。\n解集不能包含重复的组合。 \n示例 1:\n\n输入: k = 3, n = 7\n输出: [[1,2,4]]\n示例 2:\n\n输入: k = 3, n = 9\n输出: [[1,2,6], [1,3,5], [2,3,4]]\n ```\n\n## 解题方案\n> 思路 1\n```\n回溯\n```\n\n```cpp\n void dfs(int n, int k, int index, vector<int>& path, vector<vector<int>>& ans){\n    if(n<0||k<0)\n        return;\n    if(n==0&&k==0){\n        ans.push_back(path);\n        return ;\n    }\n    for(int i=index;i<=9;i++){\n        path.push_back(i);\n        dfs(n-i, k-1, i+1, path, ans);\n        path.pop_back();\n    }\n}\nvector<vector<int>> combinationSum3(int k, int n) {\n    vector<vector<int>> ans;\n    vector<int> path;\n    dfs(n, k, 1, path, ans);\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0230._Kth_Smallest_Element_in_a_BST.md",
    "content": "# 230. Kth Smallest Element in a BST\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/\n  \n > 内容描述\n \n ```\n给定一个二叉搜索树，编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。\n\n说明：\n你可以假设 k 总是有效的，1 ≤ k ≤ 二叉搜索树元素个数。\n\n示例 1:\n\n输入: root = [3,1,4,null,2], k = 1\n   3\n  / \\\n 1   4\n  \\\n   2\n输出: 1\n示例 2:\n\n输入: root = [5,3,6,2,4,null,null,1], k = 3\n       5\n      / \\\n     3   6\n    / \\\n   2   4\n  /\n 1\n输出: 3\n进阶：\n如果二叉搜索树经常被修改（插入/删除操作）并且你需要频繁地查找第 k 小的值，你将如何优化 kthSmallest 函数？\n ```\n\n## 解题方案\n> 思路 1\n```\n遍历树后排序\n```\n```\n```cpp\nvoid dfs(TreeNode* root, vector<int>& nums){\n    if(root==NULL)\n        return ;\n    nums.push_back(root->val);\n    dfs(root->left, nums);\n    dfs(root->right, nums);\n}\nint kthSmallest(TreeNode* root, int k) {\n    vector<int> nums;\n    dfs(root, nums);\n    sort(nums.begin(), nums.end());\n    return  nums[k-1];\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0260._Single_Number_III.md",
    "content": "# 260. Single Number III\n\n**<font color=red>Ѷ:Medium<font>**\n\n## ˢ\n> ԭ\n\n* https://leetcode.com/problems/single-number-iii/\n\n> \n\n```\nGiven an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.\n\nExample:\n\nInput:  [1,2,1,3,2,5]\nOutput: [3,5]\nNote:\n\nThe order of the result is not important. So in the above example, [5, 3] is also correct.\nYour algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?\n```\n\n> ˼·1\n******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)******\n\n֮ǰвͬ single number֮ǰ˼άȥĻڶ֮õӦ single number ֵaXorbaXorbתɶƣӵ0λ𣬵һΪ1λ˵λa  bȣеֳ֣λΪ0һ֣Ϊ1һ֣Ͱֵ˲ͬСŷֱܵõ\n\n```cpp\nclass Solution {\npublic:\n    vector<int> singleNumber(vector<int>& nums) {\n        int aXorB = 0;\n        for (int num : nums) {\n            aXorB ^= num;\n        }\n        int differingBit = 1;\n        while ((differingBit & aXorB) == 0) {\n            differingBit <<= 1;\n        }\n        int a = 0;\n        int b = 0;\n        for (int num : nums) {\n            if ((num & differingBit) == 0) {\n                a ^= num;\n            } else {\n                b ^= num;\n            }\n        }\n        return {a, b};\n    }\n};\n```"
  },
  {
    "path": "docs/leetcode/cpp/0287._Find_the_Duplicate_Number.md",
    "content": "# 287. Find the Duplicate Number\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/find-the-duplicate-number/\n  \n > 内容描述\n \n ```\n给定一个包含 n + 1 个整数的数组 nums，其数字都在 1 到 n 之间（包括 1 和 n），可知至少存在一个重复的整数。假设只有一个重复的整数，找出这个重复的数。\n\n示例 1:\n\n输入: [1,3,4,2,2]\n输出: 2\n示例 2:\n\n输入: [3,1,3,4,2]\n输出: 3\n说明：\n\n不能更改原数组（假设数组是只读的）。\n只能使用额外的 O(1) 的空间。\n时间复杂度小于 O(n2) 。\n数组中只有一个重复的数字，但它可能不止重复出现一次。\n ```\n\n## 解题方案\n> 思路 1\n```\n采用下标取反标记，假设下标数字为负，则为ans\n```\n\n```cpp\nint findDuplicate(vector<int>& nums) {\n    for(int i=0;i<nums.size();i++){\n        int index = abs(nums[i])-1;\n        if(nums[index]<0)\n            return index+1;\n        nums[index] = - nums[index];\n    }\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0326._Power_Of_Three.md",
    "content": "# 326. Power_of_Three\n**<font color=red>难度: Easy</font>**\n## 刷题内容\n> 原题连接\n* https://leetcode-cn.com/problems/power-of-three/\n> 内容描述\n```\nGiven an integer, write a function to determine if it is a power of three.\n\n###example \n1. Input: 27  -> Output: true\n\n2. Input: 0 -> Output: false\n\n3. Input: 9 -> Output: true\n\n4. Input: 45 -> Output: false\n```\n### 题解方案\n```\n只要是3的幂次，一定能够被3的最大次方整除\n```\n### coding\n```cpp\n    bool isPowerOfThree(int n) {\n        return n > 0 and 1162261467 % n ==0;\n    }\n```"
  },
  {
    "path": "docs/leetcode/cpp/0328._Odd_Even_Linked_List.md",
    "content": "# 328. Odd Even Linked List\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/odd-even-linked-list/\n  \n > 内容描述\n \n ```\n给定一个单链表，把所有的奇数节点和偶数节点分别排在一起。请注意，这里的奇数节点和偶数节点指的是节点编号的奇偶性，而不是节点的值的奇偶性。\n\n请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1)，时间复杂度应为 O(nodes)，nodes 为节点总数。\n\n示例 1:\n\n输入: 1->2->3->4->5->NULL\n输出: 1->3->5->2->4->NULL\n示例 2:\n\n输入: 2->1->3->5->6->4->7->NULL \n输出: 2->3->6->7->1->5->4->NULL\n ```\n\n## 解题方案\n> 思路 1\n```\n如题\n```\n\n```cpp\nListNode* oddEvenList(ListNode* head) {\n    if(head==NULL || head->next==NULL)\n        return head;\n    ListNode* link = head->next;\n    ListNode* slow=head;\n    ListNode* fast=head->next;\n    while(fast&&fast->next){\n        slow->next = fast->next;\n        fast->next = fast->next->next;\n        slow=slow->next;\n        fast=fast->next;\n    }\n    cout<<slow->val<<endl;\n    slow->next = link;\n    return head;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0329._Longest_Increasing_Path_in_a_Matrix.md",
    "content": "# 329. Longest Increasing Path in a Matrix\n\n**<font color=red>难度Hard<font>**\n\n## 刷题内容\n> 原题连接\n\n* https://leetcode.com/problems/longest-increasing-path-in-a-matrix/\n\n> 内容描述\n\n```\nGiven an integer matrix, find the length of the longest increasing path.\n\nFrom each cell, you can either move to four directions: left, right, up or down. You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not allowed).\n\nExample 1:\n\nInput: nums = \n[\n  [9,9,4],\n  [6,6,8],\n  [2,1,1]\n] \nOutput: 4 \nExplanation: The longest increasing path is [1, 2, 6, 9].\nExample 2:\n\nInput: nums = \n[\n  [3,4,5],\n  [3,2,6],\n  [2,2,1]\n] \nOutput: 4 \nExplanation: The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.\n```\n\n> 思路\n******- 时间复杂度: O(n * m)******-空间复杂度: O(n * m)******\n\n如果直接用DFS去做，时间复杂度为O(n^4)，我们就需要对算法进行优化，定义一个二维数组用记忆化的方法去记录进行剪枝\n```cpp\nclass Solution {\npublic:\n    int** dp;\n    int len1,len2,ans;\n    int dfs(vector<vector<int> >&matrix,int i,int j)\n    {\n        if(dp[i][j] != -1)\n            return dp[i][j];\n        //cout << i << j << endl;\n        if(i && matrix[i][j] < matrix[i - 1][j])\n            dp[i][j] = max(dp[i][j],dfs(matrix,i - 1,j) + 1);\n        if(j < len2 - 1 && matrix[i][j] < matrix[i][j + 1])\n            dp[i][j] = max(dp[i][j],dfs(matrix,i,j + 1) + 1);\n        if(i < len1 - 1 && matrix[i][j] < matrix[i + 1][j])\n            dp[i][j] = max(dp[i][j],dfs(matrix,i + 1,j) + 1);\n        if(j && matrix[i][j] < matrix[i][j - 1])\n            dp[i][j] = max(dp[i][j],dfs(matrix,i,j - 1) + 1);\n        //cout << dp[i][j];\n        if(dp[i][j] == -1)\n            dp[i][j] = 1;\n        ans = max(ans,dp[i][j]);\n        return dp[i][j];\n    }\n    int longestIncreasingPath(vector<vector<int>>& matrix) {\n        len1 = matrix.size();\n        if(!len1)\n            return 0;\n        len2 = matrix[0].size();\n        ans = 0;\n        dp = new int*[len1];\n        for(int i = 0; i < len1; ++i){\n            dp[i] = new int[len2];\n            for(int j=0;j<len2;j++)\n                dp[i][j]= -1;\n        }\n        //cout << 1;\n        for(int i = 0;i < matrix.size();++i)\n            for(int j = 0;j < matrix[i].size();++j)\n                if(dp[i][j] == -1)\n                {\n                    //cout << 1;\n                    dfs(matrix,i,j);\n                }\n        reverse(matrix.begin(),matrix.end());\n        for(int i = 0;i < matrix.size();++i)\n            reverse(matrix[i].begin(),matrix[i].end());\n        for(int i = 0;i < len1;++i)\n            for(int j = 0;j < len2;++j)\n                dp[i][j] = -1;\n        for(int i = 0;i < matrix.size();++i)\n            for(int j = 0;j < matrix[i].size();++j)\n                if(dp[i][j] == -1)\n                    dfs(matrix,i,j);\n        return ans;\n    }\n};\n```\n"
  },
  {
    "path": "docs/leetcode/cpp/0338._Counting_Bits.md",
    "content": "# 338. Counting Bits \n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n > 原题连接\n \n* https://leetcode-cn.com/problems/counting-bits/\n > 内容描述\n ```\n给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ，计算其二进制数中的 1 的数目并将它们作为数组返回。\n\n示例 1:\n\n输入: 2\n输出: [0,1,1]\n示例 2:\n\n输入: 5\n输出: [0,1,1,2,1,2]\n进阶:\n\n给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗？\n要求算法的空间复杂度为O(n)。\n你能进一步完善解法吗？要求在C++或任何其他语言中不使用任何内置函数（如 C++ 中的 __builtin_popcount）来执行此操作。\n ```\n\n## 解题方案\n> 思路 1\n```\n第i个数的二进制中数含1的个数等于等于第（i&i-1）个数中二进制数中1的个数加1\n```\n\n```cpp\nvector<int> countBits(int num) {\n    vector<int> res(num+1,0);\n    for(int i=1;i<=num;i++){\n        res[i]=res[i&(i-1)]+1;\n    }\n    return res;\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0413._Arithmetic_Slices.md",
    "content": "# 413. Arithmetic Slices\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/arithmetic-slices/\n  \n > 内容描述\n \n ```\n如果一个数列至少有三个元素，并且任意两个相邻元素之差相同，则称该数列为等差数列。\n\n例如，以下数列为等差数列:\n\n1, 3, 5, 7, 9\n7, 7, 7, 7\n3, -1, -5, -9\n以下数列不是等差数列。\n\n1, 1, 2, 5, 7\n \n\n数组 A 包含 N 个数，且索引从0开始。数组 A 的一个子数组划分为数组 (P, Q)，P 与 Q 是整数且满足 0<=P<Q<N 。\n\n如果满足以下条件，则称子数组(P, Q)为等差数组：\n\n元素 A[P], A[p + 1], ..., A[Q - 1], A[Q] 是等差的。并且 P + 1 < Q 。\n\n函数要返回数组 A 中所有为等差数组的子数组个数。\n\n \n\n示例:\n\nA = [1, 2, 3, 4]\n\n返回: 3, A 中有三个子等差数组: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。\n ```\n\n## 解题方案\n> 思路 1\n```\ndp[i]记录以i开头任意结尾的等差数列的个数\n如果A[i+1]-A[i]==A[i]-A[i-1],那么A[i+1]，则dp[i+1]=dp[i]+1\n最后所有位置开头的等差数列的和为结果。\n```\n\n```cpp\nint numberOfArithmeticSlices(vector<int>& A) {\n    vector<int> dp(A.size(), 0);\n    for(int i=2;i<A.size();i++){\n        if(A[i]-A[i-1]==A[i-1]-A[i-2]){\n            dp[i]=dp[i-1]+1;\n        }\n    }\n    int ans=0;\n    for(int i=0;i<dp.size();i++){\n        ans+=dp[i];\n    }\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0442._Find_All_Duplicates_in_an_Array.md",
    "content": "# 442. Find All Duplicates in an Array\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/find-all-duplicates-in-an-array/\n  \n > 内容描述\n \n ```\n给定一个整数数组 a，其中1 ≤ a[i] ≤ n （n为数组长度）, 其中有些元素出现两次而其他元素出现一次。\n\n找到所有出现两次的元素。\n\n你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗？\n\n示例：\n\n输入:\n[4,3,2,7,8,2,3,1]\n\n输出:\n[2,3]\n ```\n\n## 解题方案\n> 思路 1\n```\n数值在1-n之间，可以对相应数值-1的下标位置取反，如果出现两次，就为正值，否则为负。\n```\n\n```cpp\nvector<int> findDuplicates(vector<int>& nums) {\n    vector<int> ans;\n    for(int i=0;i<nums.size();i++){\n        int index = abs(nums[i])-1;\n        if(nums[index]<0)\n            ans.push_back(index+1);\n        nums[index] = - nums[index];\n    }\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0513._Find_Bottom_Left_Tree_Value.md",
    "content": "# 513. Find Bottom Left Tree Value\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/find-bottom-left-tree-value/\n  \n > 内容描述\n \n ```\n给定一个二叉树，在树的最后一行找到最左边的值。\n\n示例 1:\n\n输入:\n\n    2\n   / \\\n  1   3\n\n输出:\n1\n \n\n示例 2:\n\n输入:\n\n        1\n       / \\\n      2   3\n     /   / \\\n    4   5   6\n       /\n      7\n\n输出:\n7\n \n\n注意: 您可以假设树（即给定的根节点）不为 NULL。\n ```\n\n## 解题方案\n> 思路 1\n```\n从左到右层次遍历二叉树\n```\n\n```cpp\n int findBottomLeftValue(TreeNode* root) {\n    vector<TreeNode*> que;\n    que.push_back(root);\n    while(que.size()>0){\n        vector<TreeNode*> tmp;\n        int len = que.size();\n        for(int i=0;i<len;i++){\n            if(que[i]->left)\n                tmp.push_back(que[i]->left);\n            if(que[i]->right)\n                tmp.push_back(que[i]->right);\n        }\n        if(tmp.size()==0)\n            break;\n        que = tmp;\n    }\n    return que[0]->val;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0515._Find_Largest_Value_in_Each_Tree_Row.md",
    "content": "# 515. Find Largest Value in Each Tree Row\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/\n  \n > 内容描述\n \n ```\n您需要在二叉树的每一行中找到最大的值。\n\n示例：\n\n输入: \n\n          1\n         / \\\n        3   2\n       / \\   \\  \n      5   3   9 \n\n输出: [1, 3, 9]\n ```\n\n## 解题方案\n> 思路 1\n```\n层次遍历二叉树\n```\n\n```cpp\nvector<int> largestValues(TreeNode* root) { \n    vector<int> ans;\n    if(root==NULL)\n        return ans;\n    vector<TreeNode*> level;\n    level.push_back(root);\n    while(level.size()>0){\n        vector<TreeNode*> tmp;\n        int n = level.size();\n        int maxnum = INT_MIN;\n        for(int i=0;i<n;i++){\n            if(maxnum<level[i]->val)\n                maxnum=level[i]->val;\n            if(level[i]->left)\n                tmp.push_back(level[i]->left);\n            if(level[i]->right)\n                tmp.push_back(level[i]->right);\n        }\n        ans.push_back(maxnum);\n        level=tmp;\n    }\n    return ans;\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0540._Single_Element_in_a_Sorted_Array.md",
    "content": "# 540. Single Element in a Sorted Array\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/single-element-in-a-sorted-array/\n  \n > 内容描述\n \n ```\n给定一个只包含整数的有序数组，每个元素都会出现两次，唯有一个数只会出现一次，找出这个数。\n\n示例 1:\n\n输入: [1,1,2,3,3,4,4,8,8]\n输出: 2\n示例 2:\n\n输入: [3,3,7,7,10,11,11]\n输出: 10\n注意: 您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。\n ```\n\n## 解题方案\n> 思路 1\n```\n时间复杂度选择二分\n\n```\n\n```cpp\nint singleNonDuplicate(vector<int>& nums) {\n    int start=0, end=nums.size()/2;\n    while(start<end){\n        int mid = (end+start)/2;\n        if(nums[mid*2]!=nums[mid*2+1]){\n            end = mid;\n        }else\n            start = mid+1;\n    }\n    return nums[2*start];\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0581._Shortest_Unsorted_Continuous_Subarray.md",
    "content": "# 581. Shortest Unsorted Continuous Subarray\n\n **<font color=red>难度: Easy</font>**\n\n ## 刷题内容\n > 原题连接\n* https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/\n > 内容描述\n ```\n 给定一个整数数组，你需要寻找一个连续的子数组，如果对这个子数组进行升序排序，那么整个数组都会变为升序排序。\n\n你找到的子数组应是最短的，请输出它的长度。\n\n示例 1:\n\n输入: [2, 6, 4, 8, 10, 9, 15]\n输出: 5\n解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序，那么整个表都会变为升序排序。\n ```\n\n## 解题方案\n> 思路 1\n```\n1. 拷贝数组，排序\n2. 计算两个数组不同的起始位置和末端位置\n3. 计算差值\n```\n\n```cpp\nint findUnsortedSubarray(vector<int>& nums) {\n    vector<int> tmp(nums.begin(), nums.end());\n    sort(tmp.begin(), tmp.end());\n    int start=-1, end=-1;\n    for(int i=0;i<nums.size();i++){\n        if(tmp[i]!=nums[i]){\n            start = i;\n            break;\n        }\n    }\n    for(int i=nums.size()-1;i>=0;i--){\n        if(tmp[i]!=nums[i]){\n            end = i;\n            break;\n        }\n    }\n    if(start==-1&&end==-1)\n        return 0;\n    return end-start+1;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0629._K_Inverse_Pairs_Array.md",
    "content": "### 793. K Inverse Pairs Array\n\n\n\n题目:\nhttps://leetcode.com/problems/k-inverse-pairs-array\n\n难度:\nHard\n\n题意：\n\n1. 给定一个数n和一个数k\n2. 求n个元素，逆序对数等于k的序列数\n\n思路：\n\n- 最容易想到的是动态规划\n- 我们一个数一个数丢进去，假设已经存在n-1个元素的序列，我们要放一个比他们都小的数，这时候根据插入的位置不同就会产生0到(n-1)的逆序对数\n- 设`dp[n][k]`表示n个元素，逆序对数等于k的序列数，有状态转移方程`dp[n][k]=sum{dp[n-1][k - (0..(n-1))]}`\n- 如果直接求的话，复杂度是o(n^3)\n- 注意观察算`dp[n][k]`，用到的是`dp[n-1][k]`到`dp[n-1][k-(n-1)]`，算`dp[n][k-1]`，用到的是`dp[n-1][k-1]`到`dp[n-1][k-1-(n-1)]`，于是我们可以保存这个和，然后算`dp[n][i]`的时候只需要加一个数减一个数就可以维护这个和\n- 复杂度是o(n^2)\n\n解法：\n\n```c++\n#include<cstdio>\n#include<cstring>\n\nclass Solution {\npublic:\n    int a[1001][1001];\n    int MOD = 1000000007;\n    int kInversePairs(int n, int k) {\n        memset(a, 0, sizeof(a));\n        a[0][0] = 1;\n        for (int i = 1;i <= n;i++) {\n            int s = 0;\n            for (int j = 0;j <= k;j++) {\n                s += a[i - 1][j];\n                if (s >= MOD) {\n                    s -= MOD;\n                }\n                if (j - i >= 0) {\n                    s -= a[i - 1][j - i];\n                    if (s < 0) {\n                        s += MOD;\n                    }\n                }\n                a[i][j] = s;\n            }\n        }\n        return a[n][k];\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0632._Smallest_Range.md",
    "content": "### 632. Smallest Range\n\n\n\n题目:\nhttps://leetcode.com/problems/smallest-range/\n\n难度:\nHard\n\n题意：\n\n1. 给定n个序列，求一个最小区间，使得每个序列至少一个数在这个区间里面\n\n思路：\n\n- 采用移动区间的做法。如果区间左端点为l，那么我们需要在所有的序列中寻找比l大的最小数，构成一个区间[l, r]\n- 首先，将所有序列的第一个数字入堆，我们记录一个最大值。这时候堆里面的数形成一个区间，判断和记录下来。接着区间开始移动，将堆里面的最小数弹出丢掉，再从这个最小数所在的序列取出下一个数放进堆，又形成一个区间，判断和记录下来。如此循环，直到其中一个序列没有数可以进堆\n\n解法：\n\n```c++\nclass Solution {\npublic:\n    struct myData {\n        int x, y, value;\n        myData(int _x = 0, int _y = 0, int _value = 0): x(_x), y(_y), value(_value) {}\n        bool operator<(const myData &b) const {\n            return value > b.value;\n        }\n    };\n    vector<int> smallestRange(vector<vector<int>>& nums) {\n        int l = -10000000, r = -10000000;\n        priority_queue<myData> q;\n        int res = -10000000;\n        for (int i = 0;i < nums.size();i++) {\n            q.push(myData(i, 0, nums[i][0]));\n            res = res > nums[i][0] ? res : nums[i][0];\n        }\n        while (q.size() == nums.size()) {            \n            myData t = q.top();\n            q.pop();\n            if (l == -10000000 || (res - t.value) < (r - l)) {\n                l = t.value;\n                r = res;\n            }\n            if (t.y + 1 < nums[t.x].size()) {\n                q.push(myData(t.x, t.y + 1, nums[t.x][t.y + 1]));\n                res = res > nums[t.x][t.y + 1] ? res : nums[t.x][t.y + 1];\n            }\n        }\n        vector<int> ret;\n        ret.push_back(l);\n        ret.push_back(r);\n        return ret;\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0654._maximum_binary_tree.md",
    "content": "# 654. Maximum Binary Tree \n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n > 原题连接\n* https://leetcode-cn.com/problems/maximum-binary-tree/\n > 内容描述\n ```\n给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下：\n\n二叉树的根是数组中的最大元素。\n左子树是通过数组中最大值左边部分构造出的最大二叉树。\n右子树是通过数组中最大值右边部分构造出的最大二叉树。\n通过给定的数组构建最大二叉树，并且输出这个树的根节点。\n\nExample 1:\n\n输入: [3,2,1,6,0,5]\n输入: 返回下面这棵树的根节点：\n\n      6\n    /   \\\n   3     5\n    \\    / \n     2  0   \n       \\\n        1\n ```\n\n## 解题方案\n> 思路 1\n```\n深搜构建二叉树\n```\n\n```cpp\nTreeNode* dfs(vector<int>& nums, int start, int end){\n    int root_val = 0, max=INT_MIN;\n    if(start==end)\n        return NULL;\n    for(int i=start;i<end;i++){\n        if(max<nums[i]){\n            max = nums[i];\n            root_val = i;\n        }\n    } \n    TreeNode* root = new TreeNode(max);\n    root->left = dfs(nums, start, root_val);\n    root->right = dfs(nums, root_val+1, end);\n    return root;\n}\nTreeNode* constructMaximumBinaryTree(vector<int>& nums) {\n    return dfs(nums, 0, nums.size());\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0668._Kth_Smallest_Number_in_Multiplication_Table.md",
    "content": "### 668. Kth Smallest Number in Multiplication Table\n\n\n\n题目:\nhttps://leetcode.com/problems/kth-smallest-number-in-multiplication-table/\n\n难度:\nHard\n\n题意：\n\n1. 给定一个m和n，表示生成m*n的矩阵，矩阵里面的值为a(i,j) = i * j\n2. 求这个矩阵所有数中第k小是哪个数\n\n思路：\n\n- 由于m，n，k都很大，因此不能用排序或者堆排序的方式进行解答\n- 我们可以二分结果，因为结果肯定是在0到n*m之间的某个数\n- 假设二分值是p，我们需要判断整个矩阵中小于p有多少个，只需要遍历一遍，根据p/i来判断第i行小于p有多少个，累加\n\n解法：\n\n```c++\n#include<cstdio>\n#include<cstring>\n\nclass Solution {\npublic:\n    int a[1001][1001];\n    int MOD = 1000000007;\n    int kInversePairs(int n, int k) {\n        memset(a, 0, sizeof(a));\n        a[0][0] = 1;\n        for (int i = 1;i <= n;i++) {\n            int s = 0;\n            for (int j = 0;j <= k;j++) {\n                s += a[i - 1][j];\n                if (s >= MOD) {\n                    s -= MOD;\n                }\n                if (j - i >= 0) {\n                    s -= a[i - 1][j - i];\n                    if (s < 0) {\n                        s += MOD;\n                    }\n                }\n                a[i][j] = s;\n            }\n        }\n        return a[n][k];\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0701._Insert_into_a_Binary_Search_Tree.md",
    "content": "# 701. Insert into a Binary Search Tree\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/\n  \n > 内容描述\n \n ```\n给定二叉搜索树（BST）的根节点和要插入树中的值，将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 保证原始二叉搜索树中不存在新值。\n\n注意，可能存在多种有效的插入方式，只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。\n\n例如, \n\n给定二叉搜索树:\n\n        4\n       / \\\n      2   7\n     / \\\n    1   3\n\n和 插入的值: 5\n你可以返回这个二叉搜索树:\n\n         4\n       /   \\\n      2     7\n     / \\   /\n    1   3 5\n或者这个树也是有效的:\n\n         5\n       /   \\\n      2     7\n     / \\   \n    1   3\n         \\\n          4\n ```\n\n## 解题方案\n> 思路 1\n```\n二分查找，记录父节点和大小关系\n```\n\n```cpp\nTreeNode* insertIntoBST(TreeNode* root, int val) {\n    TreeNode* pre;\n    TreeNode* head = root;\n    int side = 0;\n    while(root){\n        pre = root;\n        if(root->val>val){\n            root = root->left;\n            side = 1;\n        }\n        else if(root->val<val){\n            side = 0;\n            root = root->right;\n        }\n    }\n    TreeNode* node = new TreeNode(val);\n    if(side==1)\n        pre->left = node;\n    else\n        pre->right = node;\n    return head;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0715._Range_Module.md",
    "content": "### 715. Range Module\n\n\n\n题目:\nhttps://leetcode.com/problems/range-module/\n\n难度:\nHard\n\n题意：\n\n1. 设计一种数据结构\n2. 操作1：向该数据结构插入一个线段（的所有实数）\n3. 操作2：向该数据结构删除一个线段（的所有实数）\n4. 操作3：查询一个线段包含的所有实数是否都在这个数据结构中\n\n思路：\n\n- 线段与线段之间有三种关系，包含，相交，相离。插入一个线段，我们需要寻找可能包含和相交的线段来合并\n- 假设插入的线段为[a,b)，我们需要在已有的线段中寻找包含和相交的线段。假设已有线段为[i,j)，当j<a，这个线段肯定不需要判断。所以我们需要寻找左端点跟a相等，或者比a小的最大值。然后遍历，一个个线段判断，直到i > b\n- 我们需要一种数据结构，可以遍历，可以快速定位到比某个数小的最大值。平衡树满足我们的需求。\n- 平衡树的key是线段的左端点，value是线段的右端点\n- 剩下的操作就是线段合并和线段删除了，用笔模拟一下就可以得到结果\n\n解法：\n\n```c++\nclass RangeModule {\npublic:\n    map<int, int> range;\n    RangeModule() {\n        \n    }\n     \n    struct Range {\n        int x, y;\n        Range(int _x = 0, int _y = 0) : x(_x), y(_y) {}\n    };\n    \n    int min(int a, int b) {\n        return a < b ? a : b;\n    }\n    \n    int max(int a, int b) {\n        return a < b ? b : a;\n    }\n    \n    void addRange(int left, int right) {\n        if (range.size() == 0) {\n            range[left] = right;\n            return;\n        }\n        map<int, int>::iterator it;\n        vector<int> forDelete;\n        it = range.upper_bound(left);\n        if (it != range.begin()) {\n            it--;\n        }\n        while (it != range.end() && it->first <= right) {\n            if ((it -> second >= right && it -> first <= right) || (right >= it -> second && left <= it -> second)) {\n                forDelete.push_back(it -> first);\n                left = min(left, it -> first);\n                right = max(right, it -> second);\n            }\n            it++;\n        }\n        for (int i = 0;i < forDelete.size();i++) {\n            range.erase(forDelete[i]);\n        }\n        range[left] = right;\n    }\n    \n    bool queryRange(int left, int right) {\n        if (range.size() == 0) {\n            return false;\n        }\n        map<int, int>::iterator it;\n        it = range.upper_bound(left);\n        if (it != range.begin()) {\n            it--;\n        }\n        if (it -> first <= left && it -> second >= right) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n    \n    void removeRange(int left, int right) {\n        if (range.size() == 0) {\n            return;\n        }\n        map<int, int>::iterator it;\n        vector<int> forDelete;\n        vector<Range> forInsert;\n        it = range.upper_bound(left);\n            if (it != range.begin()) {\n            it--;\n        }\n        while (it != range.end() && it->first <= right) {\n            if (it -> first >= left && it -> second <= right) {\n                forDelete.push_back(it->first);\n            } else if (it -> first < left && it -> second > right) {\n                forDelete.push_back(it->first);\n                forInsert.push_back(Range(it -> first, left));\n                forInsert.push_back(Range(right, it -> second));\n            } else if(it -> first < left && it -> second >= left) {\n                forDelete.push_back(it->first);\n                forInsert.push_back(Range(it -> first, left));\n            } else if (it -> first <= right && it -> second > right) {\n                forDelete.push_back(it->first);\n                forInsert.push_back(Range(right, it -> second));\n            } \n            it++;\n        }\n        for (int i = 0;i < forDelete.size();i++) {\n            range.erase(forDelete[i]);\n        }\n        for (int i = 0;i < forInsert.size();i++) {\n            range[forInsert[i].x] = forInsert[i].y;\n        }\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0719._Find_K-th_Smallest_Pair_Distance.md",
    "content": "### 793. Find K-th Smallest Pair Distance\n\n\n\n题目:\nhttps://leetcode.com/problems/find-k-th-smallest-pair-distance/\n\n难度:\nHard\n\n题意：\n\n1. 给定一个数组\n2. 计算数组总所有点对的差\n3. 求第k大是多少\n\n思路：\n\n- 暴力枚举肯定不行\n- 换种思路，我们可以二分结果，数组所有点对的差的取值范围是1到最大值-最小值\n- 二分结果，计算点对的差小于或等于这个结果有多少个，跟k比是大还是小\n- 计算点对的差小于或等于某个值p有多少个，需要遍历数组，对于每个数a，判断数组中有多少个数小于或等于a+p，累加即可\n- 复杂度是o(nlogn*logn)\n\n解法：\n\n```java\nclass Solution {\npublic:\n    int findIndex(vector<int>& nums, int left, int right, int k) {\n        while (right - left > 1) {\n            int mid = (left + right) / 2;\n            if (nums[mid] <= k) {\n                left = mid;\n            } else {\n                right = mid;\n            }\n        }\n        return left;\n    }\n    int judge(vector<int>& nums, int p) {\n        int ret = 0;\n        for (int i = 0;i < nums.size();i++) {\n            ret += findIndex(nums, i, nums.size(), p + nums[i]) - i;\n        }\n        return ret;\n    }\n    int bsearch(vector<int>& nums, int left, int right, int k) {\n        left--;\n        while (right - left > 1) {\n            int mid = (left + right) / 2;\n            if (judge(nums, mid) >= k) {\n                right = mid;\n            } else {\n                left = mid;\n            }\n        }\n        return right;\n    }\n    int smallestDistancePair(vector<int>& nums, int k) {\n        sort(nums.begin(), nums.end());\n        return bsearch(nums, 0, nums[nums.size() - 1] - nums[0], k);\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0739._Daily_Temperatures.md",
    "content": "# 739. Daily Temperatures\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/daily-temperatures/\n  \n > 内容描述\n \n ```\n根据每日 气温 列表，请重新生成一个列表，对应位置的输入是你需要再等待多久温度才会升高的天数。如果之后都不会升高，请输入 0 来代替。\n\n例如，给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73]，你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。\n\n提示：气温 列表长度的范围是 [1, 30000]。每个气温的值的都是 [30, 100] 范围内的整数。\n ```\n\n## 解题方案\n> 思路 1\n```\n暴力超时。\n采用递减栈思维，用栈存下表\n当前值小于栈顶值，入栈\n否则出站，出栈index的结果为当前处理下表和出栈下标的差值。\n```\n\n```cpp\nvector<int> dailyTemperatures(vector<int>& temperatures) {\n    if(temperatures.size()==0)\n        return temperatures;\n    vector<int> ans(temperatures.size(), 0);\n    stack<int> index;\n    for(int i=0;i<temperatures.size();i++){\n        \n        while(!index.empty() && temperatures[i]>temperatures[index.top()]){\n            int tmp = index.top();\n            index.pop();\n            ans[tmp]=i-tmp;\n        }\n        index.push(i);  \n    }\n    return ans;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0797._All_Paths_From_Source_To_Target.md",
    "content": "# 797. All Paths From Source to Target\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n > 原题连接\n* https://leetcode-cn.com/problems/all-paths-from-source-to-target/\n > 内容描述\n ```\n给一个有 n 个结点的有向无环图，找到所有从 0 到 n-1 的路径并输出（不要求按顺序）\n\n二维数组的第 i 个数组中的单元都表示有向图中 i 号结点所能到达的下一些结点（译者注：有向图是有方向的，即规定了a→b你就不能从b→a）空就是没有下一个结点了。\n\n示例:\n输入: [[1,2], [3], [3], []] \n输出: [[0,1,3],[0,2,3]] \n解释: 图是这样的:\n0--->1\n|    |\nv    v\n2--->3\n这有两条路: 0 -> 1 -> 3 和 0 -> 2 -> 3.\n提示:\n\n结点的数字会在范围 [2, 15] 内。\n你可以把路径以任意顺序输出，但在路径内的结点的顺序必须保证。\n ```\n\n## 解题方案\n> 思路 1\n```\n深搜二叉树，记录路径，当i==graph.size()-1，停止。\n```\n\n```cpp\nvoid dfs(int i, vector<int>& path, int target, vector<vector<int>>& ans, vector<vector<int>>& graph){\n    if(i==target){\n        ans.push_back(path);\n        return ;\n    }\n    for(int j=0;j<graph[i].size();j++){\n        path.push_back(graph[i][j]);\n        dfs(graph[i][j], path, target, ans, graph);\n        path.pop_back();\n    }\n}\nvector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {\n    vector<vector<int>> ans;\n    vector<int> path;\n    path.push_back(0);\n    dfs(0, path, graph.size()-1, ans, graph);\n    return ans;\n}\n\n```"
  },
  {
    "path": "docs/leetcode/cpp/0814._Binary_Tree_Pruning.md",
    "content": "# 814. Binary Tree Pruning\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n > 原题连接\n* https://leetcode-cn.com/problems/binary-tree-pruning/\n > 内容描述\n ```\n给定二叉树根结点 root ，此外树的每个结点的值要么是 0，要么是 1。\n\n返回移除了所有不包含 1 的子树的原二叉树。\n\n( 节点 X 的子树为 X 本身，以及所有 X 的后代。)\n\n示例1:\n输入: [1,null,0,0,1]\n输出: [1,null,0,null,1]\n ```\n\n## 解题方案\n> 思路 1\n```\n遍历二叉树，切除左右子树中无1的子树。\n```\n\n```cpp\nbool dfs(TreeNode* root){\n    if(root==NULL)\n        return false;\n    bool left = dfs(root->left);\n    bool right = dfs(root->right);\n    if(left==false)\n        root->left=NULL;\n    if(right==false)\n        root->right=NULL;\n    return root->val==1||left||right;\n}\nTreeNode* pruneTree(TreeNode* root) {\n    dfs(root);\n    return root;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0841._Keys_and_Rooms.md",
    "content": "# 841. Keys and Rooms\n\n **<font color=red>难度: Medium</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/keys-and-rooms/submissions/\n  \n > 内容描述\n \n ```\n有 N 个房间，开始时你位于 0 号房间。每个房间有不同的号码：0，1，2，...，N-1，并且房间里可能有一些钥匙能使你进入下一个房间。\n\n在形式上，对于每个房间 i 都有一个钥匙列表 rooms[i]，每个钥匙 rooms[i][j] 由 [0,1，...，N-1] 中的一个整数表示，其中 N = rooms.length。 钥匙 rooms[i][j] = v 可以打开编号为 v 的房间。\n\n最初，除 0 号房间外的其余所有房间都被锁住。\n\n你可以自由地在房间之间来回走动。\n\n如果能进入每个房间返回 true，否则返回 false。\n\n示例 1：\n\n输入: [[1],[2],[3],[]]\n输出: true\n解释:  \n我们从 0 号房间开始，拿到钥匙 1。\n之后我们去 1 号房间，拿到钥匙 2。\n然后我们去 2 号房间，拿到钥匙 3。\n最后我们去了 3 号房间。\n由于我们能够进入每个房间，我们返回 true。\n示例 2：\n\n输入：[[1,3],[3,0,1],[2],[0]]\n输出：false\n解释：我们不能进入 2 号房间。\n提示：\n\n1 <= rooms.length <= 1000\n0 <= rooms[i].length <= 1000\n所有房间中的钥匙数量总计不超过 3000。\n ```\n\n## 解题方案\n> 思路 1\n```\n广搜遍历可以到达房间, 记录开启房间个数。\n```\n\n```cpp\nbool canVisitAllRooms(vector<vector<int>>& rooms) {\n    queue<int> keys;\n    vector<bool> unlocked(rooms.size(), false);\n    keys.push(0);\n    unlocked[0]=true;\n    int locked=rooms.size()-1;\n    while(!keys.empty()){\n        int key = keys.front();\n        keys.pop();\n        for(int i=0;i<rooms[key].size();i++){\n            int tmp = rooms[key][i];\n            if(unlocked[tmp]==false){\n                keys.push(tmp);\n                unlocked[tmp]=true;\n                locked--;\n            }\n        }\n    }\n    if(locked==0)\n        return true;\n    else\n        return false;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0877._Stone_Game.md",
    "content": "# 877. Stone Game\n\n **<font color=red>难度: Middle</font>**\n\n ## 刷题内容\n\n > 原题连接\n\n* https://leetcode-cn.com/problems/stone-game/\n  \n > 内容描述\n \n ```\n亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行，每堆都有正整数颗石子 piles[i] 。\n\n游戏以谁手中的石子最多来决出胜负。石子的总数是奇数，所以没有平局。\n\n亚历克斯和李轮流进行，亚历克斯先开始。 每回合，玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止，此时手中石子最多的玩家获胜。\n\n假设亚历克斯和李都发挥出最佳水平，当亚历克斯赢得比赛时返回 true ，当李赢得比赛时返回 false 。\n\n \n\n示例：\n\n输入：[5,3,4,5]\n输出：true\n解释：\n亚历克斯先开始，只能拿前 5 颗或后 5 颗石子 。\n假设他取了前 5 颗，这一行就变成了 [3,4,5] 。\n如果李拿走前 3 颗，那么剩下的是 [4,5]，亚历克斯拿走后 5 颗赢得 10 分。\n如果李拿走后 5 颗，那么剩下的是 [3,4]，亚历克斯拿走后 4 颗赢得 9 分。\n这表明，取前 5 颗石子对亚历克斯来说是一个胜利的举动，所以我们返回 true 。\n \n ```\n\n## 解题方案\n> 思路 1\n```\ndp: \ndp[i][j]表示从i-j之间alex和lee拿的总数差\ndp[i][j]>0: alex赢，否则lee赢\n从i==j时：dp[i][i]为piles[i]\ni!=j时：dp[i][j] = max(piles[i]-dp[i+1][j], piles[j]-dp[i][j-1])\n两个人交错拿石子，所以上一步的赢为下一步的输，所以本次取减去上一次的差，为本次过后总的比分，取较大。\n\n```\n\n```cpp\nbool stoneGame(vector<int>& piles) {\n    int len = piles.size();\n    vector<vector<int>> dp(len, vector<int>(len, 0));\n    for(int i=0;i<len;i++)\n        dp[i][i]=piles[i];\n    for(int i=1;i<=len;i++){\n        for(int j=0;j<len-i;j++){\n            dp[j][j+i]=max(piles[j]-dp[j+1][j+i], piles[j+i]-dp[j][j+i-1]);\n        }\n    }\n    return dp[0][len-1]>0;\n}\n```"
  },
  {
    "path": "docs/leetcode/cpp/0945._Minimum_Increment_to_Make_Array_Unique.md",
    "content": "### 945. Minimum Increment to Make Array Unique\n\n题目:\nhttps://leetcode.com/problems/minimum-increment-to-make-array-unique/\n\n难度:\nMedium\n\n题意：\n\n1. 给定一个数组\n2. 每次操作，数组中的元素只能+1\n3. 求最少多少次操作，数组中所有元素都不相同\n\n思路：\n\n- 注意看题意，数组中的元素只能+1，所以数组需要先排序，从小到大，因为小的数处理好，大的数不管怎么+1都不会冲突\n- 从小到大循环，需要操作的只可能是跟前一个相同的，或者比前一个小(因为前一个也有可能跟前前一个相同)，因此我们跟前面一个比较，如果比前面一个大，那么啥事都没，如果跟前一个相同，或者比前一个小，那么我们就把他加到比前面一个数大1即可\n\n解法：\n\n```c++\nclass Solution {\npublic:\n    int minIncrementForUnique(vector<int>& A) {\n        sort(A.begin(), A.end());\n        int ret = 0;\n        for (int i= 1;i < A.size();i++) {\n            if (A[i] <= A[i - 1]) {\n                ret += A[i - 1] - A[i] + 1;\n                A[i] = A[i - 1] + 1;\n            }\n        }\n        return ret;\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0946._Validate_Stack_Sequences.md",
    "content": "### 946. Validate Stack Sequences\n\n题目:\nhttps://leetcode.com/problems/validate-stack-sequences/\n\n难度:\nMedium\n\n题意：\n\n1. 两个数组\n2. 问入栈顺序为pushed数组，是否可能出栈顺序为popped数组\n\n思路：\n\n- 模拟即可。我们把新建一个栈，按照pushed数组的顺序一个一个丢进去，并且，检查popped数组前面的数组，如果可以弹出就弹出。到最后判断栈是否为空即可\n\n解法：\n\n```c++\nclass Solution {\npublic:\n    int stack[1010];\n    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {\n        int n = 0, j = 0;\n        for (int i = 0;i < pushed.size();i++) {\n            stack[n++] = pushed[i];\n            while (n > 0 && stack[n - 1] == popped[j]) {\n                n--;\n                j++;\n            }\n        }\n        if (n == 0) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0947._Most_Stones_Removed_with_Same_Row_or_Column.md",
    "content": "### 947. Most Stones Removed with Same Row or Column\n\n题目:\nhttps://leetcode.com/problems/most-stones-removed-with-same-row-or-column/\n\n难度:\nMedium\n\n题意：\n\n1. 给平面上n个点\n2. 每次操作都可以挑选其中x坐标相等或者y坐标相等的两个点，划掉一个\n3. 求最多能划掉多少个\n\n思路：\n\n- 我们平面上的点想象成图论上的一个几点，如果两个点之间，x坐标相等或者y坐标相等，那么连边\n- 题目就可以转为，求这个图的联通分量，因为只要两个团不联通，是无论如何无法进行操作的，所以剩下的个数必是联通分量的个数\n- 剩下就是dfs即可\n\n解法：\n\n```c++\nclass Solution {\npublic:\n    bool flag[1010];\n    void dfs(vector<vector<int>>& stones, int idx) {\n        for (int i = 0;i < stones.size();i++) {\n            if (flag[i]) {\n                continue;\n            }\n            if (stones[idx][0] != stones[i][0] && stones[idx][1] != stones[i][1]) {\n                continue;\n            }\n            flag[i] = true;\n            dfs(stones, i);\n        }\n    }\n    int removeStones(vector<vector<int>>& stones) {\n        memset(flag, false, sizeof(flag));\n        int ret = 0;\n        for (int i = 0;i < stones.size();i++) {\n            if (!flag[i]) {\n                ret++;\n                dfs(stones, i);\n            }\n        }\n        return stones.size() - ret;\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0948._Bag_of_Tokens.md",
    "content": "### 948. Bag of Tokens\n\n题目:\nhttps://leetcode.com/problems/bag-of-tokens/\n\n难度:\nMedium\n\n题意：\n\n1. 玩个游戏，有n个游戏币，游戏币有权值，初始能量为P\n2. 每个游戏币只能被选择一次，每次只能在两种操作中选择其中一个操作\n   1. 如果当前能量大于或等于该游戏币的权值，那么可以将能量减掉该游戏币的权值，分数+1\n   2. 如果当前分数大于或等于1，那么可以将分数-1，将能量加上该游戏币的权值\n3. 问最多能得到多少分\n\n思路：\n\n- 假设只有第一种操作，那么这个题就是个贪心题，排序，从小到大选择游戏币，直到能量用完\n- 第二种操作，相当于找一个权重小于或等于P的游戏币（命名为游戏币B），跟另一个游戏币（命名为游戏币A）同时去掉，然后能量加上游戏币A的能量\n- 游戏币A很容易想，肯定选择权重最大的那个，那游戏币B要挑哪个呢？\n- 答案是任意挑，因为对结果无影响。大家可以想一想，贪心算法相当于要求A[0]+A[1]+...A[k]<=P，k的最大，假设我们挑中了游戏币B来对冲游戏币A，那么下一轮的贪心问题就是A[0]+A[1]+...+A[k]-values(B)<=P+(values(A)-values(B))，可以看出，values(B)是被消去的\n- 所以解法就是，枚举所有的操作，每次操作把最小的置换最大的，剩下的就是求解贪心问题A[0]+A[1]+...A[k]<=P\n\n解法：\n\n```c++\nclass Solution {\npublic:\n    int sum[10010];\n    int getSum(int idx) {\n        if (idx < 0) {\n            return 0;\n        } else {\n            return sum[idx];\n        }\n    }\n    int bagOfTokensScore(vector<int>& tokens, int P) {\n        if (tokens.size() == 0) {\n            return 0;\n        }\n        \n        sort(tokens.begin(), tokens.end());\n        sum[0] = tokens[0];\n        for (int i = 1;i < tokens.size();i++) {\n            sum[i] = sum[i - 1] + tokens[i];\n        }\n        \n        int left = 0, right = tokens.size() - 1;\n        \n        int ret = 0;\n        int res = 0;\n        while (left <= right) {\n            while (res <= right && getSum(res) - getSum(left - 1) <= P) {\n                res++;\n            }\n            ret = ret > res - left ? ret : res - left;\n            \n            if (left == right) {\n                break;\n            }\n            if (P >= tokens[left]) {\n                P += tokens[right--] - tokens[left++];\n            } else {\n                break;\n            }\n        }\n        return ret;\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0949._Largest_Time_for_Given_Digits.md",
    "content": "### 949. Largest Time for Given Digits\n\n 题目:\nhttps://leetcode.com/problems/largest-time-for-given-digits/\n\n难度:\nEasy\n\n题意：\n\n1. 给4个0-9的数字\n2. 求能组成最大的时间，时间格式是hh:mm\n\n思路：\n\n- 枚举所有的hh:mm的格式\n- 判断是否符合时间的要求，hh<24，mm<60\n- 寻找最大的时间\n\n解法：\n\n```c++\nclass Solution {\npublic:\n    string largestTimeFromDigits(vector<int>& A) {\n        string ret = \"\";\n        for (int i = 0;i < 4;i++) {\n            for (int j = 0;j < 4;j++) {\n                if (i == j) continue;\n                if (A[i] * 10 + A[j] >= 24) continue;\n                for (int k = 0;k < 4;k++) {\n                    if (i == k || j == k) continue;\n                    for (int l = 0;l < 4;l++) {\n                        if (i == l || j == l || k == l) continue;\n                        string s = \"\";\n                        if (A[k] * 10 + A[l] >= 60) continue;\n                        s = string(\"\") + char(A[i] + '0') + char(A[j] + '0') + \":\" + char(A[k] + '0') + char(A[l] + '0');\n                        if (ret < s) {\n                            ret = s;\n                        }\n                    }\n                }\n            }\n        }\n        return ret;\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0950._Reveal_Cards_In_Increasing_Order.md",
    "content": "### 950. Reveal Cards In Increasing Order\n\n题目:\nhttps://leetcode.com/problems/reveal-cards-in-increasing-order/\n\n难度:\nMedium\n\n题意：\n\n1. 有这么个操作\n2. 将牌的第一张拿出来，把下一张放到底部\n3. 重复这种操作\n4. 到最后拿出来的是一个严格递增数列\n5. 求牌开始的顺序\n\n思路：\n\n- 反过来操作即可\n- 对牌排个序，备选\n- 把底部的牌放到第一张，从备选的牌中选择最大的一张放在顶部\n- 重复这种操作\n\n解法：\n\n```c++\nclass Solution {\npublic:\n    int list[10000];\n    int front, back;\n    \n    void add(int val) {\n        list[front++] = val;\n        if (front == 10000) {\n            front = 0;\n        }\n    }\n    \n    int remove() {\n        int ret = list[back];\n        back++;\n        if (back == 10000) {\n            back = 0;\n        } \n        return ret;\n    }\n    \n    vector<int> deckRevealedIncreasing(vector<int>& deck) {\n        front = back = 0;\n        sort(deck.begin(), deck.end());\n        add(deck[deck.size() - 1]);\n        for (int i = deck.size() - 2;i >= 0;i--) {\n            int x = remove();\n            add(x);\n            x = deck[i];\n            add(x);\n        }\n        vector<int> ret;\n        int i = back;\n        while (i != front) {\n            ret.push_back(list[i]);\n            i++;\n            if (i == 10000) {\n                i = 0;\n            }\n        }\n        reverse(ret.begin(), ret.end());\n        return ret;\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0951._Flip_Equivalent_Binary_Trees.md",
    "content": "### 951. Flip Equivalent Binary Trees\n\n题目:\nhttps://leetcode.com/problems/flip-equivalent-binary-trees/\n\n难度:\nMedium\n\n题意：\n\n1. 给两棵树\n2. 两棵树可以做交换左右子树的操作\n3. 求两棵树是否能通过某些操作，使得两棵树一模一样\n\n思路：\n\n- 递归判断\n  - 两个都为空，返回true\n  - 一个为空，返回false\n  - 根的值不同，返回false\n  - 递归判断左子树和右子树，判断左右两棵对应的子树是否为true，或者交换下子树，判断是否为true，返回true\n  - 其他情况返回false\n\n解法：\n\n```c++\n/**\n * Definition for a binary tree node.\n * struct TreeNode {\n *     int val;\n *     TreeNode *left;\n *     TreeNode *right;\n *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}\n * };\n */\nclass Solution {\npublic:\n    bool flipEquiv(TreeNode* root1, TreeNode* root2) {\n        if (!root1 && !root2) {\n            return true;\n        }\n        if (!root1 || !root2) {\n            return false;\n        } \n        if (root1->val != root2->val) {\n            return false;\n        }\n        if (flipEquiv(root1->left, root2->left) && flipEquiv(root1->right, root2->right)) {\n            return true;\n        }\n        if (flipEquiv(root1->left, root2->right) && flipEquiv(root1->right, root2->left)) {\n            return true;\n        }\n        return false;\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/0952._Largest_Component_Size_by_Common_Factor.md",
    "content": "### 952. Largest Component Size by Common Factor\n\n题目:\nhttps://leetcode.com/problems/largest-component-size-by-common-factor/\n\n难度:\nHard\n\n题意：\n\n1. 给n个数\n2. 将n个数设定为n个节点，如果两个数之间的最大公约数大于1，则连边\n3. 求图的最大联通分量的大小\n\n思路：\n\n- n的数据量高达2w，如果两两节点计算最大公约数，复杂度是o(n^2logn)\n- 我们可以使用素数筛法来取出需要两两画线的数列，比如：取出被2整除的数，被3整除的数。。。\n- 求图的最大联通分量可以用并查集来做\n- 过程是这样的\n  - 枚举所有的素数\n  - 假设当前枚举的素数是i\n  - 从n个数中取出所有能被i整除的数\n  - 假设有m个数，那么第1个数跟第m-1个数都跟第0个数做下合并\n  - 枚举结束后，求最大的集合的大小\n- 素数筛法的复杂度是o(nlogn)，这里需要做下优化，如果枚举每个素数都得从n个数寻找能被它整除的数，复杂度还是o(nk)，k是素数的个数，但如果我们把n个数映射到1-100000的数组中，就可以套用素数筛法了\n\n解法：\n\n```c++\nbool isPrime[100100];\nbool hasValue[100100];\nint p[100100];\nint size[100100];\nclass Solution {\npublic:\n    bool inited = false;\n    \n    void init() {\n        memset(isPrime, true, sizeof(isPrime));\n        for (int i = 2;i <= 100000;i++) {\n            if (!isPrime[i]) {\n                continue;\n            }\n            for (int j = i + i;j <= 100000;j += i) {\n                isPrime[j] = false;\n            }\n        }\n    }\n    \n    int find_set(int x) {\n        vector<int> temp;\n        while (p[x] != x) {\n            temp.push_back(x);\n            x = p[x];\n        }\n        for (int i = 0;i < temp.size();i++) {\n            p[temp[i]] = x;\n        }\n        return x;\n    }\n    \n    void union_set(int x, int y) {\n        x = find_set(x);\n        y = find_set(y);\n        if (x == y) {\n            return;\n        }\n        p[x] = y;\n        size[y] += size[x];\n    }\n    \n    vector<int> find(int prime) {\n        vector<int> ret;\n        for (int i = prime;i <= 100000;i += prime) {\n            if (hasValue[i]) {\n                ret.push_back(i);\n            }\n        }\n        return ret;\n    }\n    \n    int largestComponentSize(vector<int>& A) {\n        if (!inited) {\n            init();\n            inited = true;\n        }\n        \n        memset(hasValue, false, sizeof(hasValue));\n        for (int i = 0;i < A.size();i++) {\n            hasValue[A[i]] = true;\n        }\n        for (int i = 0;i <= 100000;i++) {\n            p[i] = i;\n            size[i] = 1;\n        }\n        for (int i = 2;i <= 100000;i++) {\n            if(isPrime[i]) {\n                vector<int> temp = find(i);\n                \n                if (temp.size() == 0){\n                    continue;\n                }\n                \n                for (int j = 1;j < temp.size();j++) {\n                    union_set(temp[0], temp[j]);\n                }\n            }\n        }\n        \n        int ret = 0;\n        for (int i = 0;i <= 100000;i++) {\n            if (!hasValue[i]) {\n                continue;\n            }\n            int x = find_set(i);\n            if (size[x] > ret) {\n                ret = size[x];\n            }\n        }\n        return ret;\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/cpp/README.md",
    "content": "# Leetcode C++ 题解\n"
  },
  {
    "path": "docs/leetcode/cpp/SUMMARY.md",
    "content": "+   [Leetcode C++ 题解](README.md)\n+   [1. Two Sum](0001._Two_Sum.md)\n+   [2. Add Two Numbers](0002._Add_Two_Numbers.md)\n+   [3. Longest Substring Without Repeating Characters](0003._Longest_Substring_Without_Repeating_Characters.md)\n+   [004. Median of Two Sorted Arrays](0004._Median_of_Two_Sorted_Arrays.md)\n+   [5. Longest Palindromic Substring](0005._Longest_Palindromic_Substring.md)\n+   [6. ZigZag Conversion](0006._ZigZag_Conversion.md)\n+   [7. Reverse Integer](0007._Reverse_Integer.md)\n+   [8. String to Integer (atoi)](0008._String_to_Integer_(atoi).md)\n+   [9. Palindrome Number](0009._Palindrome_Number.md)\n+   [10. Regular Expression Matching](0010._Regular_Expression_Matching.md)\n+   [11. container with most water](0011._Container_With_Most_Water.md)\n+   [12. Integer to Roman](0012._Integer_to_Roman.md)\n+   [14. Longest Common Prefix](0014._Longest_Common_Prefix.md)\n+   [15. 3sum](0015._3sum.md)\n+   [16. 3Sum Closest](0016._3Sum_Closest.md)\n+   [17. Letter Combinations of a Phone Number](0017._Letter_Combinations_of_a_Phone_Number.md)\n+   [18. 4Sum](0018._4Sum.md)\n+   [19. Remove Nth Node From End of List](0019._Remove_Nth_Node_From_End_of_List.md)\n+   [20. Valid Parentheses](0020._Valid_Parentheses.md)\n+   [21. Merge Two Sorted Lists](0021._Merge _Two _Sorted _Lists.md)\n+   [22. Generate Parentheses](0022._Generate_Parentheses.md)\n+   [23. merge k sorted lists](0023._Merge_K_Sorted_Lists.md)\n+   [24. Swap Nodes in Pairs](0024._Swap_Nodes_in_Pairs.md)\n+   [25.reverse nodes in k group](0025._Reverse_Nodes_In_K_Group.md)\n+   [26.Remove Duplicates From Sorted Array](0026._Remove_Duplicates_From_Sorted_Array.md)\n+   [27.Remove Element](0027._Remove_Element.md)\n+   [28.implement strstr](0028._Implement_Strstr.md)\n+   [29.divide two integers](0029._Divide_Two_Integers.md)\n+   [30.substring with concatenation of all words](0030._Substring_With_Concatenation_Of_All_Words.md)\n+   [31.Next Permutatio](0031._Next_Permutatio.md)\n+   [32. Longest Valid Parentheses](0032._Longest_Valid_Parentheses.md)\n+   [033. Search in Rotated Sorted Array](0033._Search_in_Rotated_Sorted_Array.md)\n+   [34. Find First and Last Position of Element in Sorted Array](0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md)\n+   [35.search insert position](0035._Search_Insert_Position.md)\n+   [36. Valid Sudoku](0036._Valid_Sudoku.md)\n+   [38. Count and Say](0038._Count_and_Say.md)\n+   [39. Combination Sum](0039._Combination_Sum.md)\n+   [40. Combination Sum II](0040._Combination_Sum_II.md)\n+   [041.First Missing Positive](0041._First_Missing_Positive.md)\n+   [42. Trapping Rain Water](0042._Trapping_Rain_Water.md)\n+   [43. Multiply Strings](0043._Multiply_Strings.md)\n+   [44. Wildcard Matching](0044._Wildcard_Matching.md)\n+   [045. Jump Game II](0045._Jump_Game_II.md)\n+   [46. Permutations](0046._Permutations.md)\n+   [47. Permutations II](0047._Permutations_II.md)\n+   [49. Group Anagrams](0048._Rotate_Image.md)\n+   [49. Group Anagrams](0049._Group_Anagrams.md)\n+   [50. powx n](0050._powx_n.md)\n+   [51. N-Queens](0051._ N-Queens.md)\n+   [52. N-Queens II](0052._N-Queens_II.md)\n+   [053. Maximum Subarray](0053._Maximum_Subarray.md)\n+   [54. Spiral Matrix](0054._Spiral_Matrix.md)\n+   [55. Jump Game](0055._Jump_Game.md)\n+   [56. Merge Intervals](0056._Merge_Intervals.md)\n+   [57. Insert Interval](0057._Insert_Interval.md)\n+   [058. Length of Last Word](0058._Length_of_Last_Word.md)\n+   [59. Spiral Matrix II](0059._Spiral_Matrix_II.md)\n+   [60. Permutation Sequence](0060._Permutation_Sequence.md)\n+   [61. Rotate List](0061._Rotate_List.md)\n+   [62. Unique Paths](0062._Unique_Paths.md)\n+   [63. Unique Paths II](0063._Unique_Paths_II.md)\n+   [64. Minimum Path Sum](0064._Minimum_Path_Sum.md)\n+   [65. Valid Number](0065._Valid_Number.md)\n+   [66. Plus One](0066._Plus_One.md)\n+   [68. Text Justification](0068._Text_Justification.md)\n+   [69. Sqrt(x)](0069._Sqr(x).md)\n+   [72. Edit Distance](0072._Edit_Distance.md)\n+   [75. Sort Colors](0075._Sort_Colors.md)\n+   [76. Minimum Window Substring](0076._Minimum_Window_Substring.md)\n+   [77. Combinations](0077._combinations.md)\n+   [78. Subsets](0078._subsets.md)\n+   [81. Search in Rotated Sorted Array II](0081._Search_in_Rotated_Sorted_Array_II.md)\n+   [ˢ������](0083._Remove_Duplicates_From_Sorted_Lists.md)\n+   [84. Largest Rectangle in Histogram](0084._Largest_Rectangle_in_Histogram.md)\n+   [85. Maximal Rectangle](0085._Maximal_Rectangle.md)\n+   [87. Scramble String](0087._Scramble_String.md)\n+   [88.Merge Sorted Array](0088._Merge_Sorted_Array.md)\n+   [90. Subsets II](0090._Subsets_II.md)\n+   [94. Binary Tree Inorder Traversal](0094._binary_tree_inorder_traversal.md)\n+   [96. Unique Binary Search Trees](0096._Unique_Binary_Search_Trees.md)\n+   [97. Interleaving String](0097._Interleaving_String.md)\n+   [99. Recover Binary Search Tree](0099._Recover_Binary_Search_Tree.md)\n+   [100. same tree](0100._same_tree.md)\n+   [101. Symmetric Tree](0101._Symmetric_Tree.md)\n+   [102. Binary Tree Level Order Traversal](0102._Binary_Tree_Level_Order_Traversal.md)\n+   [104. Maximum Depth of Binary Tree](0104._Maximum_Depth_of_Binary_Tree.md)\n+   [105. Construct Binary Tree from Preorder and Inorder Traversal](0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md)\n+   [106. Construct Binary Tree from Inorder and Postorder Traversal](0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md)\n+   [107.Binary Tree Level Order Traversal II](0107._Binary_Tree_Level_Order_Traversal_II.md)\n+   [108. Convert Sorted Array to Binary Search Tree](0108._Convert_Sorted_Array_to_Binary_Search_Tree.md)\n+   [109. Convert Sorted List to Binary Search Tree](0109._Convert_Sorted_List_to_Binary_Search_Tree.md)\n+   [110.Balanced Binary Tree](0110._Balanced_Binary_Tree.md)\n+   [111. Minimum Depth of Binary Tree](0111._Minimum_Depth_Of_Binary_Tree.md)\n+   [112. Path Sum](0112._Path_Sum.md)\n+   [114. Flatten Binary Tree to Linked List](0114._Flatten_Binary_Tree_to_Linked_List.md)\n+   [115.Distinct Subsequences](0115._Distinct_Subsequences.md)\n+   [118. Pascal's Triangle](0118._Pascals_Triangle.md)\n+   [119. Pascal's Triangle II](0119._Pascals_Triangle-II.md)\n+   [120. Triangle](0120._Triangle.md)\n+   [121. Best Time to Buy and Sell Stock](0121._Best_Tim_to_Buy_and_Sell_Stock.md)\n+   [122. Best Time to Buy and Sell Stock II](0122._Best_Time_to_Buy_and_Sell_Stock_II.md)\n+   [123. Best Time to Buy and Sell Stock III](0123._Best_Time_to_Buy _and_Sell_Stock_III.md)\n+   [124. Binary Tree Maximum Path Sum](0124._Binary_Tree_Maximum_Path_Sum.md)\n+   [127. Word Ladder](0127._Word_Ladde.md)\n+   [128. Longest Consecutive Sequence](0128._Longest_Consecutive_Sequence.md)\n+   [129. Sum Root to Leaf Numbers](0129._Sum_Root_to_Leaf_Numbers.md)\n+   [131. Palindrome Paritionaing](0131._Palindrome_Partitioning.md)\n+   [136. Single Numbe](0136._Single_Numbe.md)\n+   [137.Single Number II](0137._Single_Number_II.md)\n+   [ˢ������](0141._Linked_List_Cycle.md)\n+   [142. linked list cycle II](0142._Linked_List_Cycle_II.md)\n+   [144. Binary Tree Preorder Traversal](0144._Binary_Tree_Preorder_Traversal.md)\n+   [145. Binary Tree Postorder Traversal](0145._Binary_Tree_Postorder_Traversal.md)\n+   [147. Insertion Sort List](0147._Insert_on_Sort_List.md)\n+   [148.Sort list](0148._Sort _list.md)\n+   [151. Reverse Words in a String](0151._Reverse_Words_in_a_String.md)\n+   [153. Find Minimum in Rotated Sorted Array](0153._Find_Minimum_in_Rotated_Sorted_Array.md)\n+   [154. Find Minimum in Rotated Sorted Array II](0154._Find_Minimum_in_Rotated_Sorted_Array-II.md)\n+   [160 intersection_of_Two_Linked_Lists](0160._Intersection_Of_Two_Linked_Lists.md)\n+   [164. Maximum Gap](0164._Maximum_Gap.md)\n+   [166. Fraction to Recurring Decimal](0166._Fraction_to_Recurring_Decimal.md)\n+   [167. Two Sum II - Input array is sorted](0167._Two_Sum_II-Input_array_is_sorted.md)\n+   [199. Binary Tree Right Side View](0199._Binary_Tree_Right_Side_View.md)\n+   [216. Combination Sum III](0216._Combination_Sum_III.md)\n+   [230. Kth Smallest Element in a BST](0230._Kth_Smallest_Element_in_a_BST.md)\n+   [260. Single Number III](0260._Single_Number_III.md)\n+   [287. Find the Duplicate Number](0287._Find_the_Duplicate_Number.md)\n+   [326. Power_of_Three](0326._Power_Of_Three.md)\n+   [328. Odd Even Linked List](0328._Odd_Even_Linked_List.md)\n+   [329. Longest Increasing Path in a Matrix](0329._Longest_Increasing_Path_in_a_Matrix.md)\n+   [338. Counting Bits ](0338._Counting_Bits.md)\n+   [413. Arithmetic Slices](0413._Arithmetic_Slices.md)\n+   [442. Find All Duplicates in an Array](0442._Find_All_Duplicates_in_an_Array.md)\n+   [513. Find Bottom Left Tree Value](0513._Find_Bottom_Left_Tree_Value.md)\n+   [515. Find Largest Value in Each Tree Row](0515._Find_Largest_Value_in_Each_Tree_Row.md)\n+   [540. Single Element in a Sorted Array](0540._Single_Element_in_a_Sorted_Array.md)\n+   [581. Shortest Unsorted Continuous Subarray](0581._Shortest_Unsorted_Continuous_Subarray.md)\n+   [793. K Inverse Pairs Array](0629._K_Inverse_Pairs_Array.md)\n+   [632. Smallest Range](0632._Smallest_Range.md)\n+   [654. Maximum Binary Tree ](0654._maximum_binary_tree.md)\n+   [668. Kth Smallest Number in Multiplication Table](0668._Kth_Smallest_Number_in_Multiplication_Table.md)\n+   [701. Insert into a Binary Search Tree](0701._Insert_into_a_Binary_Search_Tree.md)\n+   [715. Range Module](0715._Range_Module.md)\n+   [793. Find K-th Smallest Pair Distance](0719._Find_K-th_Smallest_Pair_Distance.md)\n+   [739. Daily Temperatures](0739._Daily_Temperatures.md)\n+   [797. All Paths From Source to Target](0797._All_Paths_From_Source_To_Target.md)\n+   [814. Binary Tree Pruning](0814._Binary_Tree_Pruning.md)\n+   [841. Keys and Rooms](0841._Keys_and_Rooms.md)\n+   [877. Stone Game](0877._Stone_Game.md)\n+   [945. Minimum Increment to Make Array Unique](0945._Minimum_Increment_to_Make_Array_Unique.md)\n+   [946. Validate Stack Sequences](0946._Validate_Stack_Sequences.md)\n+   [947. Most Stones Removed with Same Row or Column](0947._Most_Stones_Removed_with_Same_Row_or_Column.md)\n+   [948. Bag of Tokens](0948._Bag_of_Tokens.md)\n+   [949. Largest Time for Given Digits](0949._Largest_Time_for_Given_Digits.md)\n+   [950. Reveal Cards In Increasing Order](0950._Reveal_Cards_In_Increasing_Order.md)\n+   [951. Flip Equivalent Binary Trees](0951._Flip_Equivalent_Binary_Trees.md)\n+   [952. Largest Component Size by Common Factor](0952._Largest_Component_Size_by_Common_Factor.md)"
  },
  {
    "path": "docs/leetcode/java/0001._Two_Sum.md",
    "content": "# 1. Two Sum\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/two-sum\n\n> 内容描述\n\n```\nGiven an array of integers, return indices of the two numbers such that they add up to a specific target.\n\nYou may assume that each input would have exactly one solution, and you may not use the same element twice.\n\nExample:\n\nGiven nums = [2, 7, 11, 15], target = 9,\n\nBecause nums[0] + nums[1] = 2 + 7 = 9,\nreturn [0, 1].\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n\n```java\nclass Solution {\n    public int[] twoSum(int[] nums, int target) {\n        Map<Integer, Integer> lookup = new HashMap<>();\n        int[] res = new int[2];\n        for (int i = 0; i < nums.length; i++) {\n            if (lookup.containsKey(target - nums[i])) {\n                res = new int[] { lookup.get(target - nums[i]), i };\n                break;\n            } else {\n                lookup.put(nums[i], i);\n            }\n        }\n        return res;\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0002._add_two_numbers.md",
    "content": "#  2. Add Two Numbers\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/add-two-numbers\n\n> 内容描述\n\n```\nYou are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.\n\nYou may assume the two numbers do not contain any leading zero, except the number 0 itself.\n\nExample:\n\nInput: (2 -> 4 -> 3) + (5 -> 6 -> 4)\nOutput: 7 -> 0 -> 8\nExplanation: 342 + 465 = 807.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n迭代，每次只算个位数的相加\n\n```java\nclass Solution {\n    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {\n        if (l1 == null) {\n            return l2;\n        }\n        if (l2 == null) {\n            return l1;\n        }\n\n        ListNode head = new ListNode(0);\n        ListNode p = head;\n\n        int tmp = 0;\n        while(l1 != null || l2 != null || tmp != 0) {\n            if(l1 != null) {\n                tmp += l1.val;\n                l1 = l1.next;\n            }\n            if(l2 != null) {\n                tmp += l2.val;\n                l2 = l2.next;\n            }\n\n            p.next = new ListNode(tmp % 10);\n            p = p.next;\n            tmp = tmp / 10;\n        }\n        return head.next;\n    }\n}\n```\n> 思路 2\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n可以使用递归，每次算一位的相加, beats 70.66%\n\n\n```java\nclass Solution {\n    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {\n        if (l1 == null && l2 == null) {\n            return null;\n        } else if (l1 == null || l2 == null) {\n            return l1 != null ? l1: l2;\n        } else {\n            ListNode l3;\n            if (l1.val + l2.val < 10) {\n                l3 = new ListNode(l1.val + l2.val);\n                l3.next = addTwoNumbers(l1.next, l2.next);\n            } else {\n                l3 = new ListNode(l1.val + l2.val - 10);\n                l3.next = addTwoNumbers(l1.next, addTwoNumbers(l2.next, new ListNode(1)));\n            }\n            return l3;\n        }\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0003._Longest_Substring_Without_Repeating_Characters.md",
    "content": "# 3. Longest Substring Without Repeating Characters\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/longest-substring-without-repeating-characters\n\n> 内容描述\n\n```\nGiven a string, find the length of the longest substring without repeating characters.\n\nExample 1:\n\nInput: \"abcabcbb\"\nOutput: 3 \nExplanation: The answer is \"abc\", with the length of 3. \nExample 2:\n\nInput: \"bbbbb\"\nOutput: 1\nExplanation: The answer is \"b\", with the length of 1.\nExample 3:\n\nInput: \"pwwkew\"\nOutput: 3\nExplanation: The answer is \"wke\", with the length of 3. \n             Note that the answer must be a substring, \"pwke\" is a subsequence and not a substring.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n```java\nclass Solution {\n    public int lengthOfLongestSubstring(String s) {\n        int stIdx = 0, maxLen = 0;\n        int arr[] = new int[128];\n        for(int i=0;i<s.length();i++){\n            stIdx = Math.max(arr[s.charAt(i)],stIdx);\n            maxLen = Math.max(maxLen, i-stIdx+1);\n            arr[s.charAt(i)] = i+1;\n        }\n        return maxLen;\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0004._Median_of_Two_Sorted_Arrays.md",
    "content": "#  4. Median of Two Sorted Arrays\n\n**<font color=red>难度: Hard</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/median-of-two-sorted-arrays\n\n> 内容描述\n\n```\nThere are two sorted arrays nums1 and nums2 of size m and n respectively.\n\nFind the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).\n\nYou may assume nums1 and nums2 cannot be both empty.\n\n\nExample 1:\n\nnums1 = [1, 3]\nnums2 = [2]\n\nThe median is 2.0\n\nExample 2:\n\nnums1 = [1, 2]\nnums2 = [3, 4]\n\nThe median is (2 + 3)/2 = 2.5\n\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(log(m + n))******- 空间复杂度: O(1)******\n\n将问题转化为两个有序数组，找出其中的第K大的数, beats 99.80%\n\n```java\nclass Solution {\n// 寻找两个有序数组的中位数\n    // 问题转换为求第K大的数\n    public double findMedianSortedArrays(int[] nums1, int[] nums2) {\n        if(nums1 == null || nums1.length == 0){\n            // 求nums2的中位数\n            return nums2.length % 2 == 0 ? (nums2[nums2.length / 2] + nums2[nums2.length / 2 - 1]) / 2.0 : nums2[nums2.length / 2];\n        }\n        if(nums2 == null || nums2.length == 0){\n            return nums1.length % 2 == 0 ? (nums1[nums1.length / 2] + nums1[nums1.length / 2 - 1]) / 2.0 : nums1[nums1.length / 2];\n        }\n        int len = nums1.length + nums2.length;\n        return len % 2 == 0 ? (topK(nums1,nums2,0,0,len/2)+topK(nums1,nums2,0,0,len/2+1))/2.0 : topK(nums1,nums2,0,0,len/2 + 1);\n    }\n    // 找两个有序数组的topk小的数\n    public int topK(int[] nums1,int[] nums2,int start1,int start2,int k){\n        if(start1 >= nums1.length){\n            return nums2[start2 + k - 1];\n        }\n        if(start2 >= nums2.length){\n            return nums1[start1 + k - 1];\n        }\n\n        if(k == 1){\n            return Math.min(nums1[start1] , nums2[start2]);\n        }\n\n        if(start1 + k / 2 > nums1.length){ // 肯定不会在nums2的前 k / 2\n            return topK(nums1,nums2,start1,start2 + k / 2,k - k / 2);\n        }else if(start2 + k / 2 > nums2.length){\n            return topK(nums1,nums2,start1 + k / 2,start2,k - k / 2);\n        }\n\n        int mid1 = nums1[start1 + k / 2 - 1];\n        int mid2 = nums2[start2 + k / 2 - 1];\n        if(mid1 > mid2){ // 移除nums2的前k/2\n            return topK(nums1,nums2,start1,start2 + k / 2,k - k / 2);\n        }else {\n            return topK(nums1,nums2,start1 + k / 2,start2,k - k/2);\n        }\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0005._Longest_Palindromic_Substring.md",
    "content": "#  5. Longest Palindromic Substring\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/longest-palindromic-substring\n\n> 内容描述\n\n```\nGiven a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.\n\n\nExample 1:\n\nInput: \"babad\"\nOutput: \"bab\"\nNote: \"aba\" is also a valid answer.\n\n\nExample 2:\n\nInput: \"cbbd\"\nOutput: \"bb\"\n\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(n^2)******- 空间复杂度: O(n^2)******\n\n使用动态规划的思路,用一个二维数组cache[i][j]记录i到j是否为回文串, beats 54.36%\n\n```java\nclass Solution {\n    // 采用动态规划\n    // 如果 i == j ，则只有一个字母 肯定是回文串\n    // 如果 char[i] == char[j] && j == i + 1 , 两个字母相等 肯定是回文串\n    // 如果 char[i] == char[j] && j > i + 1 && cache[i+1][j-1]为true，则肯定是回文串\n    public String longestPalindrome(String s) {\n        if(s == null || s.length() <2){\n            return s;\n        }\n        boolean[][] cache = new boolean[s.length()][s.length()]; // 记录 i ~ j 是否是回文串\n        char[] chars = s.toCharArray();\n        int len = s.length();\n        int start = 0;\n        int end = 0;\n        // 采用至底向上的动态规划，也可以采用递归方式\n        for(int i = len - 1; i >= 0; i --){\n            for(int j = i; j < len; j ++){\n                if(i == j){\n                    cache[i][j] = true;    \n                }else if(j == i + 1 && chars[i] == chars[j]){\n                    cache[i][j] = true;\n                    if(end - start + 1 < 2){\n                        end = j;\n                        start = i;\n                    }\n                }else if(chars[i] == chars[j] && cache[i + 1][j-1]){\n                    cache[i][j] = true;\n                    if(end - start  < j-i){\n                        start = i;\n                        end = j;\n                    }\n                }else{\n                    cache[i][j] = false;\n                }\n            }\n        }\n        return s.substring(start,end+1);\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0006._ZigZag_Conversion.md",
    "content": "#  5. ZigZag Conversion\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/zigzag-conversion\n\n> 内容描述\n\n```\nThe string \"PAYPALISHIRING\" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)\n\nP   A   H   N\nA P L S I I G\nY   I   R\n\nAnd then read line by line: \"PAHNAPLSIIGYIR\"\n\nWrite the code that will take a string and make this conversion given a number of rows:\n\nstring convert(string s, int numRows);\n\nExample 1:\n\nInput: s = \"PAYPALISHIRING\", numRows = 3\nOutput: \"PAHNAPLSIIGYIR\"\n\n\n\nExample 2:\n\nInput: s = \"PAYPALISHIRING\", numRows = 4\nOutput: \"PINALSIGYAHRPI\"\nExplanation:\n\nP     I    N\nA   L S  I G\nY A   H R\nP     I\n\n\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(len(s))******- 空间复杂度: O(len(s))******\n\n需要将字符串s转换为按N排列，总共有numRows行，直接将字符串转换为N字形，然后输出, beats 74.18%\n\n```java\nclass Solution {\n    // 将字符串进行z子排列,行数为numRows\n    public String convert(String s, int numRows) {\n       // 思路：先转换为z字\n        List[] arr = new List[numRows]; // 保存每一行元素\n        for(int i = 0; i < numRows; i ++){\n            arr[i] = new ArrayList();\n        }\n        char[] chars = s.toCharArray();\n        for(int i = 0; i < chars.length;){\n            // 每次打印两列\n            for(int j = 0; j < numRows && i < chars.length; j++,i++){\n                List list = arr[j];\n                list.add(chars[i]);\n            }\n            for(int j = numRows - 1; j >= 0 && i < chars.length; j --){\n                if(j == numRows - 1 || j == 0){\n                    arr[j].add(' ');\n                }else{\n                    arr[j].add(chars[i]);\n                    i++;\n                }\n            }\n        }\n        // 输出最终字符串\n        char[] result = new char[chars.length];\n        int index = 0;\n        for(int i = 0; i < numRows; i ++){\n            List list = arr[i];\n            for(int j = 0; j < list.size(); j ++){\n                if(' ' != (char)list.get(j)){\n                    result[index++] = (char) list.get(j);\n                }\n            }\n        }\n        return new String(result);\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0007._Reverse_Integer.md",
    "content": "#  5. Reverse Integer\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/reverse-integer\n\n> 内容描述\n\n```\nGiven a 32-bit signed integer, reverse digits of an integer.\n\nExample 1:\n\nInput: 123\nOutput: 321\n\nExample 2:\n\nInput: -123\nOutput: -321\n\nExample 3:\n\nInput: 120\nOutput: 21\n\n\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(n)******- 空间复杂度: O(1)******\n\n将整数翻转，翻转后是否溢出了, beats 95.35%\n\n```java\nclass Solution {\n    public int reverse(int x) {\n        // 使用一个long型变量来保存\n        long index = 0;\n        while (x != 0){\n            index = index * 10 + x %10;\n            x = x / 10;\n        }\n        int result = (int) index;\n        if(result != index){\n            return 0;\n        }\n        return (int)index;\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0023._Merge_K_Sorted_Lists.md",
    "content": "# 23. Merge K Sorted Lists\n\n**<font color=red>难度： Hard</font>**\n\n## 刷题内容\n\n> 原题链接\n\n* https://leetcode.com/problems/merge-k-sorted-lists\n\n> 内容描述\n\n```\nMerge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.\n\nExample:\n\n\nInput:\n[\n  1->4->5,\n  1->3->4,\n  2->6\n]\n```\n\n## 解题方案\n\n> 思路 1\n*****- 时间复杂度：O(NlogK) *****- 空间复杂度：O(N)*****\n\nK为链表的数量，N为所有链表的节点的总个数\n\n此题在于一分一合，将K个有序链表通过二分，拆成两两一组的链表，就变成了leetcode  21题中的合并两个有序链表了，随后将所有链表逐层合并，就像从二叉树的叶子节点开始，不断向上合并，此题就求解完毕了。\n\n此题需要用到的技巧就是二分，以及递归合并两个有序链表（当然迭代合并两个有序列表也是可以的）\n\nBeats 100%\n\n```java\npublic ListNode mergeKLists(ListNode[] lists) {\n    if (lists == null || lists.length == 0) return null;\n    return sort(lists, 0, lists.length - 1);\n}\n\n// 二分K个链表\nListNode sort(ListNode[] lists, int lo, int hi) {\n    if (lo >= hi) return lists[lo];\n    int mid = (hi -lo) / 2 + lo;\n    ListNode l1 = sort(lists, lo, mid);\n    ListNode l2 = sort(lists, mid + 1, hi);\n    return merge(l1, l2);\n}\n\n// 合并两个有序链表的递归写法\nListNode merge(ListNode l1, ListNode l2) {\n    if (l1 == null) return l2;\n    if (l2 == null) return l1;\n\n    if (l1.val < l2.val) {\n        l1.next = merge(l1.next, l2);\n        return l1;\n    }\n\n    l2.next = merge(l2.next, l1);\n    return l2;\n}\n\n```\n"
  },
  {
    "path": "docs/leetcode/java/0141._linked_list_cycle.md",
    "content": "# 141. Linked List Cycle\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/linked-list-cycle\n\n> 内容描述\n\n```\nGiven a linked list, determine if it has a cycle in it.\n\nFollow up:\nCan you solve it without using extra space?\n```\n\n## 解题方案\n\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n\n快慢指针\n\n\n\n```java\njava\npublic class Solution {\n    public boolean hasCycle(ListNode head) {\n        if (head == null){\n            return false;\n        }\n        ListNode fast = head;\n        ListNode slow = head;\n        while (fast != null && slow != null && fast.next != null){\n            fast = fast.next.next;\n            slow = slow.next;\n            if (slow == fast){\n                return true;\n            }\n        }\n        return false;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0218._The_Skyline_Problem.md",
    "content": "# 218. The Skyline Problem\n\n**<font color=red>难度: Hard</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/the-skyline-problem\n\n> 内容描述\n\n```\nA city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Now suppose you are given the locations and height of all the buildings as shown on a cityscape photo (Figure A), write a program to output the skyline formed by these buildings collectively (Figure B).\n```\n\n<div>\n    <img src=\"https://github.com/apachecn/Interview/tree/master/docs/Algorithm/img/218/skyline1.jpg\" width=400 height=350> \n    <img src=\"https://github.com/apachecn/Interview/tree/master/docs/Algorithm/img/218/skyline2.jpg\" width=400 height=350>\n</div>\n\n```\nBuildings  Skyline Contour\nThe geometric information of each building is represented by a triplet of integers [Li, Ri, Hi], where Li and Ri are the x coordinates of the left and right edge of the ith building, respectively, and Hi is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX, and Ri - Li > 0. You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.\n\nFor instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] .\n\nThe output is a list of \"key points\" (red dots in Figure B) in the format of [ [x1,y1], [x2, y2], [x3, y3], ... ] that uniquely defines a skyline. A key point is the left endpoint of a horizontal line segment. Note that the last key point, where the rightmost building ends, is merely used to mark the termination of the skyline, and always has zero height. Also, the ground in between any two adjacent buildings should be considered part of the skyline contour.\n\nFor instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ].\n\nNotes:\n\nThe number of buildings in any input list is guaranteed to be in the range [0, 10000].\nThe input list is already sorted in ascending order by the left x position Li.\nThe output list must be sorted by the x position.\nThere must be no consecutive horizontal lines of equal height in the output skyline. For instance, [...[2 3], [4 5], [7 5], [11 5], [12 7]...] is not acceptable; the three lines of height 5 should be merged into one in the final output as such: [...[2 3], [4 5], [12 7], ...]\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)******\n\n观察发现，skyline的points的横坐标一定是某个building的左边界或者右边界。\n\n开始，假设只有2个建筑物，拿出第一个buiding B1，我们先把它的左上顶点加进我们的output结果skyline中，然后继续拿下一个building B2，我们现在需要将B2的左上顶点对应的x coordinate与B1的右上顶点所对应的x coordinate做比较：\n\n- 如果前者小且B2的高度大于B1的高度，则我们将B2的左上顶点也加入skyline中去。\n- 如果前者小且B2的高度小于等于B1的高度，则忽略B2的左上顶点\n\n接下来考虑更多建筑物的情况，从左到右扫描，当我们遇到第一个楼的左边界时，把它push到一个heap中。如果后面扫描的楼的高度比heap中最高的楼还高，那么它的左上顶点一定会被加入到skyline中。当我们遇到一个building的右边界时,我们需要将其从heap中pop掉，如果heap中max height有变化，则push到结果中。\n\n参考[Brian Gordon的blog](https://briangordon.github.io/2014/08/the-skyline-problem.html)\n和  [Stefan大神的题解](https://leetcode.com/problems/the-skyline-problem/discuss/61194)\n  \n  \n\n```Java\npublic class Solution {\n    public List<int[]> getSkyline(int[][] buildings) {\n        List<int[]> result = new ArrayList<int[]>();\n        if (buildings == null || buildings.length == 0 || buildings[0].length == 0) {\n            return result;\n        }\n        \n        List<Height> heights = new ArrayList<Height>();\n        for (int[] building : buildings) {\n            heights.add(new Height(building[0], -building[2]));\n            heights.add(new Height(building[1], building[2]));\n        }\n        Collections.sort(heights, new Comparator<Height>() {\n            @Override\n            public int compare(Height h1, Height h2) {\n                return h1.index != h2.index ? h1.index - h2.index : h1.height - h2.height;\n            }\n        });\n        \n        PriorityQueue<Integer> pq = new PriorityQueue<Integer>(1000, Collections.reverseOrder());\n        pq.offer(0);\n        int prev = 0;\n        for (Height h : heights) {\n            if (h.height < 0) {\n                pq.offer(-h.height);\n            } else {\n                pq.remove(h.height);\n            }\n            int cur = pq.peek();\n            if (cur != prev) {\n                result.add(new int[]{h.index, cur});\n                prev = cur;\n            }\n        }\n        \n        return result;\n    }\n    \n    class Height {\n        int index;\n        int height;\n        Height(int index, int height) {\n            this.index = index;\n            this.height = height;\n        }\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0238._product_of_array_except_self.md",
    "content": "# 238. Product of Array Except Self\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/two-sum\n\n> 内容描述\n\n```\nGiven an array nums of n integers where n > 1,  return an array output such that output[i] is equal to the product of all the elements of nums except nums[i].\n\nExample:\n\nInput:  [1,2,3,4]\nOutput: [24,12,8,6]\nNote: Please solve it without division and in O(n).\n\nFollow up:\nCould you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.)\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n前缀积和后缀积, 懒得实现了\n\n\n# Follow up:\nCould you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.)\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n还是一样的思想，只不过不记录下来，而是采用边循环边更新的方式\n\nbeats 100.00%\n\n\n```java\nclass Solution {\n    public int[] productExceptSelf(int[] nums) {\n        int[] res = new int[nums.length];\n        \n        for (int i = 0; i < nums.length; i++) {\n            res[i] = 1;\n        }\n        \n        int left = 1;\n        for (int i = 0; i < nums.length - 1; i++) {\n            left *= nums[i];\n            res[i+1] *= left;\n        }\n        \n        int right = 1;\n        for (int i = nums.length - 1; i > 0; i--) {\n            right *= nums[i];\n            res[i-1] *= right;\n        }\n\n        return res;\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0342._Power_of_Four.md",
    "content": "# 342. Power of Four\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/power-of-four\n\n> 内容描述\n\n```\nGiven an integer (signed 32 bits), write a function to check whether it is a power of 4.\n\nExample 1:\n\nInput: 16\nOutput: true\nExample 2:\n\nInput: 5\nOutput: false\nFollow up: Could you solve it without loops/recursion?\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(1)******- 空间复杂度: O(1)******\n\nrecursive\n\n```java\nclass Solution {\n    public boolean isPowerOfFour(int num) {\n        if (num <= 0)\n        \treturn false;\n        if (num == 1)\n        \treturn true;\n        if (num % 4 == 0)\n        \treturn isPowerOfFour(num/4);\n        return false;\n    }\n}\n```\n"
  },
  {
    "path": "docs/leetcode/java/0403._Frog_Jump.md",
    "content": "# 403. Frog Jump\n\n**<font color=red>难度: hard</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/frog-jump\n\n> 内容描述\n\n```\nA frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water.\n\nGiven a list of stones' positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit.\n\nIf the frog's last jump was k units, then its next jump must be either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction.\n\nNote:\n\nThe number of stones is ≥ 2 and is < 1,100.\nEach stone's position will be a non-negative integer < 231.\nThe first stone's position is always 0.\nExample 1:\n\n[0,1,3,5,6,8,12,17]\n\nThere are a total of 8 stones.\nThe first stone at the 0th unit, second stone at the 1st unit,\nthird stone at the 3rd unit, and so on...\nThe last stone at the 17th unit.\n\nReturn true. The frog can jump to the last stone by jumping \n1 unit to the 2nd stone, then 2 units to the 3rd stone, then \n2 units to the 4th stone, then 3 units to the 6th stone, \n4 units to the 7th stone, and 5 units to the 8th stone.\nExample 2:\n\n[0,1,2,3,4,8,9,11]\n\nReturn false. There is no way to jump to the last stone as \nthe gap between the 5th and 6th stone is too large.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* 关注点放在数据范围。\n\n* 判断是否能够到达y点（因为问题就是到达最后一个点），需要两个条件：\n\n  * 能够到达x点（x<y）\n  * x点能够跳到y点\n\n* 由于条件2需要前面一个点的跳动情况，所以这个题的子问题是\n\n  `flag[x][y]=true`表示当青蛙能够跳到x，并且能够跳到y点\n\n* 状态转移是\n\n  假设`flag[x][y]=true`，枚举所有的z>y，如果`|(z-y) - (y-x)|<=1`，那么`flag[y][z]=true`\n\n* 这里有个需要注意的优化点，可以固定y，枚举x<y，和z>y，这样对于每个y，只需要扫一遍点数组就可以成功执行转移\n\n* 复杂度是o(n^2)\n\n代码：\n\n```java\nclass Solution {\n    public boolean canCross(int[] stones) {\n        int n = stones.length;\n\n        if (stones[1] != 1) {\n            return false;\n        }\n\n        boolean[][] flag = new boolean[n][n];\n        for (int i = 0;i < n;i++) {\n            for (int j = 0;j < n;j++) {\n                flag[i][j] = false;\n            }\n        }\n\n        flag[1][0] = true;\n\n        for (int i = 1;i < n;i++) {\n            int left = i - 1;\n            int right = i + 1;\n\n            while (left >= 0 && right < n) {\n                while (left >= 0 && !flag[i][left]) left--;\n                if (left >= 0) {\n                    while (right < n && stones[right] - stones[i] <= stones[i] - stones[left] + 1) {\n                        if (stones[right] - stones[i] == stones[i] - stones[left] - 1\n                                || stones[right] - stones[i] == stones[i] - stones[left]\n                                || stones[right] - stones[i] == stones[i] - stones[left] + 1) {\n                            flag[right][i] = true;\n                        }\n                        right++;\n                    }\n                    left--;\n                }\n            }\n        }\n\n        for (int i = 0;i < n;i++) {\n            if (flag[n - 1][i]) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0757._Set_Intersection_Size_At_Least_Two.md",
    "content": "### 757. Set Intersection Size At Least Two\n\n\n\n题目:\nhttps://leetcode.com/problems/set-intersection-size-at-least-two/\n\n难度:\nHard\n\n题意：\n\n1. 给定n个区间\n2. 求一个最小集合，使得每个区间，集合中至少有两个数在区间里面\n\n思路：\n\n- 这题是贪心题\n- 先对区间右端点排序。再从右端点小的开始贪心。每次先判断当前集合中是否有两个数在这个区间中，如果有，直接跳过，没有，从右端点开始往集合丢数，直到有两个数在这个区间中\n- 直观的解释就是，为了满足前面的区间的条件，而丢进集合的数一定是越大越好，这样跟后面的区间共用一个数的几率会更大\n\n解法：\n\n```java\nclass Solution {\n\t public int intersectionSizeTwo(int[][] intervals) {\n        Integer[] array = new Integer[intervals.length];\n        for (int i = 0;i < array.length;i++) {\n            array[i] = i;\n        }\n        Arrays.sort(array, new Comparator<Integer>() {\n            @Override\n            public int compare(Integer o1, Integer o2) {\n                return Integer.compare(intervals[o1][1], intervals[o2][1]);\n            }\n        });\n        List<Integer> result = new ArrayList<Integer>();\n        int[] t = new int[2];\n        for (int i = 0;i < array.length;i++) {\n            int n = 0;\n            if (result.size() > 0 && result.get(result.size() - 1) >= intervals[array[i]][0]) {\n                t[n++] = result.get(result.size() - 1);\n            }\n            if (result.size() > 1 && result.get(result.size() - 2) >= intervals[array[i]][0]) {\n                t[n++] = result.get(result.size() - 2);\n            }\n            int res = n;\n            int j = intervals[array[i]][1];\n            while (n != 2) {\n                boolean found = false;\n                for (int k = 0;k < n;k++) {\n                    if (t[k] == j) {\n                        found = true;\n                        break;\n                    }\n                }\n                if (found) {\n                    j--;\n                } else {\n                    t[n++] = j--;\n                }\n            }\n            if (res == 0) {\n                result.add(t[1]);\n                result.add(t[0]);\n            }\n            if (res == 1) {\n                result.add(t[1]);\n            }\n        }\n        return result.size();\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0768._Max_Chunks_To_Make_Sorted_II.md",
    "content": "### 768. Max Chunks To Make Sorted II\n\n\n\n题目:\nhttps://leetcode.com/problems/max-chunks-to-make-sorted-ii/\n\n难度:\nHard\n\n题意：\n\n1. 给定一个数组，求最多能够将数组分成多少段，使得每段排序之后连接起来，是一个有序数组\n\n思路：\n\n- 显而易见，数据能否分的条件是，分出来的左边数组的最大值不大于比右边数组的最小值\n- 只需要扫描一下，先把最大值和最小值数组预处理出来，然后遍历就可以得出结果\n\n解法：\n\n```java\nclass Solution {\n\t public int maxChunksToSorted(int[] arr) {\n        int[] min = new int[arr.length];\n        int[] max = new int[arr.length];\n        max[0] = arr[0];\n        for (int i = 1;i < arr.length;i++) {\n            max[i] = Math.max(arr[i], max[i - 1]);\n        }\n        min[arr.length - 1] = arr[arr.length - 1];\n        for (int i = arr.length - 2;i >= 0;i--) {\n            min[i] = Math.min(arr[i], min[i + 1]);\n        }\n        int ret = 1;\n        for (int i = 0;i + 1 < arr.length;i++) {\n            if (max[i] <= min[i + 1]) {\n                ret++;\n            }\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0780._Reaching_Points.md",
    "content": "### 780. Reaching Points\n\n题目:\nhttps://leetcode.com/problems/reaching-points/\n\n难度:\nHard\n\n题意：\n\n1. 给定一个点对(x,y)，每次操作可以变换成(x,x+y)或者(x+y,y)\n2. 给定两个点对(sx, sy)，和(tx, ty)，问能否通过任意次操作，使前一个点对可以变换成后一个点对\n\n思路：\n\n- 我们反正来，如果得到一个点对(x,y)，最有可能是从哪些点对来的\n- 假设tx<ty，反之亦然\n- 那么点对可以从(tx,ty),(tx, ty-tx),(tx,ty-k*tx)。。。得来的\n- 我们可以得出一个递归方式\n- 如果sx>tx，直接返回false，因为sx不管怎么变换，都不能比sx小\n- 如果sx=tx，判断(ty-sy)是否不小于0，并且可以被sx整除\n- 如果sx<tx，那么我们需要判断(sx, sy)和(tx, ty % tx)是否可以变换\n- 这个算法叫做辗转相除法，也叫欧几里得算法，计算最大公约数也是这个算法\n\n解法：\n\n    class Solution {\n    \t private boolean solve(int sx, int sy, int tx, int ty) {\n            if (tx < ty) {\n                if (tx < sx) {\n                    return false;\n                }\n                if (tx == sx) {\n                    if (ty >= sy && (ty - sy) % sx == 0) {\n                        return true;\n                    } else {\n                        return false;\n                    }\n                }\n                return solve(sx, sy, tx, ty % tx);\n            } else {\n                if (ty < sy) {\n                    return false;\n                }\n                if (ty == sy) {\n                    if (tx >= sx && (tx - sx) % sy == 0) {\n                        return true;\n                    } else {\n                        return false;\n                    }\n                }\n                return solve(sx, sy, tx % ty, ty);\n            }\n        }\n    \n        public boolean reachingPoints(int sx, int sy, int tx, int ty) {\n            return solve(sx, sy, tx, ty);\n        }\n    }"
  },
  {
    "path": "docs/leetcode/java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md",
    "content": "### 793. Preimage Size of Factorial Zeroes Function\n\n\n\n题目:\nhttps://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/\n\n难度:\nHard\n\n题意：\n\n1. 求n!末尾有k个0的n有多少个\n\n思路：\n\n- 因式分解，末尾有0肯定是2*5，不管n是多大，n!分解因式后，2的个数肯定比5的个数多\n- 假设给定n，如何求n!分解因式后有多少个5？每隔5个数贡献一个5因子，每隔25个数有多贡献一个5因子。。。统计能得到结果\n- 这个题的做法是二分一个范围区间，求出n!分解因式后因子5的个数等于k的上下界，相减所得\n- 这个题有个可优化的点，答案要么是0，要么是5，因为每隔5个数肯定会贡献一个5因子。那么我们只需要一个二分，找出是否有一个n，分解因式后有k个5因子，就可以返回5，否则返回0\n\n解法：\n\n```java\nclass Solution {\n\t private long cal5(long n) {\n        long ret = 0;\n        while (n != 0) {\n            ret += n / 5;\n            n /= 5;\n        }\n        return ret;\n    }\n\n    private long upper(long left, long right, int k) {\n        while (right - left > 1) {\n            long mid = (left + right) / 2;\n            if (cal5(mid) <= k) {\n                left = mid;\n            } else {\n                right = mid;\n            }\n        }\n        if (cal5(left) == k) {\n            return left;\n        } else {\n            return -1;\n        }\n    }\n\n    private long lower(long left, long right, int k) {\n        while (right - left > 1) {\n            long mid = (left + right) / 2;\n            if (cal5(mid) >= k) {\n                right = mid;\n            } else {\n                left = mid;\n            }\n        }\n        if (cal5(right) == k) {\n            return right;\n        } else {\n            return -1;\n        }\n    }\n\n    public int preimageSizeFZF(int K) {\n        long n = upper(1, 6000000000L, K);\n        if (n == -1) {\n            return 0;\n        } else {\n            long m = lower(-1, n, K);\n            return (int) (n - m + 1);\n        }\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0827._Making_A_Large_Island.md",
    "content": "### 827. Making A Large Island\n\n\n\n题目:\nhttps://leetcode.com/problems/making-a-large-island/\n\n难度:\nHard\n\n题意：\n\n1. 给定一张矩阵图\n2. 如果两个点相邻且都为1，这两个点连通\n3. 至多把一个0改为1，问最大的连通岛的面积是多大\n\n思路：\n\n- 看数据结构，横竖最大是50，整个图最多才2500个点，直接枚举所有的0，改成1之后做dfs判断连通图，都可以解决\n- 两个连通岛其实是两个集合，如果将一个0改成1，意味着把上下左右所在的岛都合并在一个集合中，我们需要一个数据结构，既可以将集合合并，又可以判断某两个元素是否在同一个集合中，这种数据结构就是并查集\n\n解法：\n\n```java\nclass Solution {\n\t private class Set {\n\n        int[] s;\n        int[] num;\n        int r;\n        int c;\n\n        private Set(int r, int c) {\n            this.r = r;\n            this.c = c;\n            this.s = new int[r * c];\n            this.num = new int[r * c];\n            for (int i = 0;i < this.s.length;i++) {\n                this.s[i] = i;\n                this.num[i] = 1;\n            }\n        }\n\n        private int calIdx(int x, int y) {\n            return x * c + y;\n        }\n\n        private int find(int idx) {\n            if (this.s[idx] == idx) {\n                return idx;\n            } else {\n                return this.s[idx] = find(this.s[idx]);\n            }\n        }\n\n        private void merge(int x1, int y1, int x2, int y2) {\n            int p1 = find(calIdx(x1, y1));\n            int p2 = find(calIdx(x2, y2));\n            if (p1 != p2) {\n                this.s[p1] = p2;\n                this.num[p2] += this.num[p1];\n            }\n        }\n\n    }\n\n    public int largestIsland(int[][] grid) {\n        int[] dx = new int[]{0,0,1,-1};\n        int[] dy = new int[]{1,-1,0,0};\n        Set set = new Set(grid.length, grid[0].length);\n        for (int i = 0;i < grid.length;i++) {\n            for (int j = 0;j < grid[0].length;j++) {\n                if (grid[i][j] == 0) {\n                    continue;\n                }\n                for (int k = 0;k < 4;k++) {\n                    if (i + dx[k] < 0 || i + dx[k] >= grid.length) {\n                        continue;\n                    }\n                    if (j + dy[k] < 0 || j + dy[k] >= grid[0].length) {\n                        continue;\n                    }\n                    if (grid[i + dx[k]][j + dy[k]] == 0) {\n                        continue;\n                    }\n                    set.merge(i, j, i + dx[k], j + dy[k]);\n                }\n            }\n        }\n\n        int max = 0;\n        for (int i = 0;i < grid.length;i++) {\n            for (int j = 0; j < grid[0].length; j++) {\n                if (grid[i][j] == 1) {\n                    continue;\n                }\n\n                HashSet<Integer> t = new HashSet<>();\n                for (int k = 0;k < 4;k++) {\n                    if (i + dx[k] < 0 || i + dx[k] >= grid.length) {\n                        continue;\n                    }\n                    if (j + dy[k] < 0 || j + dy[k] >= grid[0].length) {\n                        continue;\n                    }\n                    if (grid[i + dx[k]][j + dy[k]] == 0) {\n                        continue;\n                    }\n\n                    t.add(set.find(set.calIdx(i + dx[k], j + dy[k])));\n                }\n\n                int ret = 0;\n                for (Integer p: t) {\n                    ret += set.num[p];\n                }\n                ret ++;\n                max = Math.max(ret, max);\n            }\n        }\n        if (max == 0) {\n            max = grid.length * grid[0].length;\n        }\n        return max;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0828._Unique_Letter_String.md",
    "content": "### 828. Unique Letter String\n\n\n\n题目:\nhttps://leetcode.com/problems/unique-letter-string\n\n难度:\nHard\n\n题意：\n\n1. 求一个字符串中的所有非空子字符串，这些字符串当中的唯一字符数的总和\n2. 唯一字符数就是在字符串中出现只有一次的字符的个数\n\n思路：\n\n- 枚举左右端点，暴力统计子字符串的唯一字符数，复杂度是o(n^3)\n- 枚举左端点，然后遍历右端点，每次保存上一次的字符统计个数，和唯一字符数，并更新为当前的数值，复杂度是o(n^2)\n- 注意到，当某个字符出现次数大于1个后，后面不管怎么遍历，该字符都不会是唯一字符，因此，有个剪枝动作，如果此时某个字符出现次数大于1个后，后面直接跳过该字符\n- 因此我们需要实现把每个字符出现的位置记录下来，以便可以跳过某些字符\n- 枚举左端点，然后遍历右端点，加上剪枝之后，每个字符至多被扫描2次。把字符串拆成26个字符后，从左边遍历到右边，就需要一个堆来维持，类似于归并排序的merge操作，这个堆最多26个元素，时间复杂度是o(52nlog26)\n- 我们可以另外想一种解决方案。假设我们把26个字母全部拆开，当某个字符第一次出现到第二次出现中间，它就能贡献一个唯一字符。假设A这个字符，第一次出现是位置1，第二次出现是位置10，于是1-10中间就可以增加一个唯一字符，同理，其他字符也是这样的。假设左端点移动，所需要改变的，也只有一个字符而已，这个字符的第一次出现的位置，到第二次出现的位置，改变了位置。我们不要想着每个字符串有多少唯一字符，而是从总体来看，每个字符贡献了多少次唯一字符。还是上面那个例子，A这个字符，第一次出现是位置1，第二次出现是位置10，那么贡献了10-1=9次唯一字符。扫描左端点时，只需要不断用上一个左端点字符移动来更新总唯一字符数即可。复杂度是o(n)\n\n解法一：\n\n```java\nclass Solution {\n\t private class Item implements Comparable<Item> {\n        int alph;\n        int idx;\n        int pos;\n\n        public Item(int alph, int idx, int pos) {\n            this.alph = alph;\n            this.idx = idx;\n            this.pos = pos;\n        }\n\n        @Override\n        public int compareTo(Item o) {\n            return Integer.compare(pos, o.pos);\n        }\n    }\n\n    private int solve(List[] idxList, int start, int len, int[] init) {\n        PriorityQueue<Item> queue = new PriorityQueue<Item>();\n        boolean[] flag = new boolean[26];\n        for (int i = 0;i < 26;i++) {\n            flag[i] = false;\n        }\n        int ret = 0;\n        int res = 0;\n        int pre = start - 1;\n\n        for (int i = 0;i < 26;i++) {\n            int idx = init[i];\n            if (idx != idxList[i].size()) {\n                queue.add(new Item(i, idx, (Integer) idxList[i].get(idx)));\n            }\n        }\n\n        while (!queue.isEmpty()) {\n            Item top = queue.poll();\n            ret += (long) res * (top.pos - pre) % MOD;\n            if (ret >= MOD) {\n                ret -= MOD;\n            }\n            if (flag[top.alph]) {\n                res--;\n            } else {\n                flag[top.alph] = true;\n                if (top.idx + 1 != idxList[top.alph].size()) {\n                    queue.add(new Item(top.alph, top.idx + 1, (Integer) idxList[top.alph].get(top.idx + 1)));\n                }\n                res++;\n            }\n            pre = top.pos;\n        }\n\n        ret += (long) res * (len - pre) % MOD;\n        if (ret >= MOD) {\n            ret -= MOD;\n        }\n        return ret;\n    }\n\n    private static int MOD = 1000000007;\n\n    public int uniqueLetterString(String S) {\n        List[] idxList = new List[26];\n        int[] init = new int[26];\n        for (int i = 0;i < 26;i++) {\n            idxList[i] = new ArrayList<Integer>();\n            init[i] = 0;\n        }\n        for (int i = 0;i < S.length();i++) {\n            idxList[S.charAt(i) - 'A'].add(i);\n        }\n\n        int ret = 0;\n        for (int i = 0;i < S.length();i++) {\n            ret += solve(idxList, i, S.length(), init);\n            if (ret >= MOD) {\n                ret -= MOD;\n            }\n            init[S.charAt(i) - 'A']++;\n        }\n\n        return ret;\n    }\n}\n```\n\n解法二：\n\n```java\nclass Solution {\n\t private static int MOD = 1000000007;\n\n    public int uniqueLetterString(String S) {\n        List<Integer>[] idxList = new List[26];\n        int[] pos = new int[26];\n        for (int i = 0;i < 26;i++) {\n            idxList[i] = new ArrayList<Integer>();\n            pos[i] = 0;\n        }\n        for (int i = 0;i < S.length();i++) {\n            idxList[S.charAt(i) - 'A'].add(i);\n        }\n\n        int ret = 0;\n        int res = 0;\n        for (int i = 0;i < 26;i++) {\n            if (pos[i] < idxList[i].size()) {\n                if (pos[i] + 1 < idxList[i].size()) {\n                    res += idxList[i].get(pos[i] + 1) - idxList[i].get(pos[i]);\n                } else {\n                    res += S.length() - idxList[i].get(pos[i]);\n                }\n            }\n        }\n\n        for (int i = 0;i < S.length();i++) {\n            ret += res;\n            if (ret >= MOD) {\n                ret -= MOD;\n            }\n            int j = S.charAt(i) - 'A';\n            if (pos[j] + 1 < idxList[j].size()) {\n                res -= idxList[j].get(pos[j] + 1) - idxList[j].get(pos[j]);\n            } else {\n                res -= S.length() - idxList[j].get(pos[j]);\n            }\n            pos[j]++;\n            if (pos[j] < idxList[j].size()) {\n                if (pos[j] + 1 < idxList[j].size()) {\n                    res += idxList[j].get(pos[j] + 1) - idxList[j].get(pos[j]);\n                } else {\n                    res += S.length() - idxList[j].get(pos[j]);\n                }\n            }\n        }\n\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0834._Sum_of_Distances_in_Tree.md",
    "content": "### 834. Sum of Distances in Tree\n\n\n\n题目:\nhttps://leetcode.com/problems/sum-of-distances-in-tree/\n\n难度:\nHard\n\n题意：\n\n1. 给定一棵树\n2. 问每个节点到其他节点的距离之和是多少\n3. N <= 10000\n\n思路：\n\n- 最简单的方法，假设我们要求节点0与其他节点的距离之和，只需要一遍dfs即可，其他节点同理。复杂度是o(n^2)\n\n- 注意到，树中每个边都是一个桥（就是去掉这个边图就变成非连通了），树中的任意两个节点都是一个固定的路径。当我们计算不同节点的dfs，其实是有一部分路径是重复计算的（自己拿笔画一下）\n\n- 来看看分析的思路。从问题出发，要问每个节点到其他节点的距离和，想象这个点A是树根（每个点都可以是树根），那么我们遍历一下所有连接这个节点的边。想象一下某个边e连接的是一个子树，点A跟这个子树所有的点都得经过边e，因此我们把问题下推，计算这个子树的树根与其他节点的距离之和，然后加上这个子树的数量就等于点A跟这个子树所有的点的距离和\n\n- 有个点需要注意的，由于边是无向的，我们动态规划的方向也需要两个方向，怎么理解呢。比如说，假设A和B连着。以A为树根计算子问题的时候，顺序是A->B，以B为树根计算子问题的时候，顺序是B->A，相当于对边进行动态规划，规划两个方向\n\n- 解法知道了，就需要编码。注意到，N <= 10000，如果递归的话，小心stack over flow。需要自己模拟栈\n\n\n代码：\n\n```java\nclass Solution {\n\t private class Edge {\n        private int x;\n        private int y;\n        private int num;\n        private int dist;\n\n        public Edge(int x, int y, int num, int dist) {\n            this.x = x;\n            this.y = y;\n            this.num = num;\n            this.dist = dist;\n        }\n\n        public int getX() {\n            return x;\n        }\n\n        public void setX(int x) {\n            this.x = x;\n        }\n\n        public int getY() {\n            return y;\n        }\n\n        public void setY(int y) {\n            this.y = y;\n        }\n\n        public int getNum() {\n            return num;\n        }\n\n        public void setNum(int num) {\n            this.num = num;\n        }\n\n        public int getDist() {\n            return dist;\n        }\n\n        public void setDist(int dist) {\n            this.dist = dist;\n        }\n    }\n\n    private void solve(Edge edge, List[] edgeList) {\n        if (edge.num != -1) {\n            return;\n        }\n\n        LinkedList<Edge> queue = new LinkedList<Edge>();\n        Stack<Edge> stack = new Stack<Edge>();\n\n        queue.addLast(edge);\n        stack.add(edge);\n\n        while (!queue.isEmpty()) {\n            Edge e = queue.pollFirst();\n            for (Edge next: (List<Edge>) edgeList[e.y]) {\n                if (next.y == e.x) {\n                    continue;\n                }\n                if (next.num != -1) {\n                    continue;\n                }\n                queue.addLast(next);\n                stack.add(next);\n            }\n        }\n\n        while (!stack.empty()) {\n            Edge e = stack.pop();\n            e.num = e.dist = 0;\n            for (Edge next: (List<Edge>) edgeList[e.y]) {\n                if (next.y == e.x) {\n                    continue;\n                }\n                e.num += next.num;\n                e.dist += next.num + next.dist;\n            }\n            e.num ++;\n        }\n    }\n\n    public int[] sumOfDistancesInTree(int N, int[][] edges) {\n        List[] edgeList = new List[N];\n        for (int i = 0;i < edgeList.length;i++) {\n            edgeList[i] = new ArrayList<Edge>();\n        }\n\n        for (int i = 0;i < edges.length;i++) {\n            edgeList[edges[i][0]].add(new Edge(edges[i][0], edges[i][1], -1, -1));\n            edgeList[edges[i][1]].add(new Edge(edges[i][1], edges[i][0], -1, -1));\n        }\n\n        int[] result = new int[N];\n        for (int i = 0;i < N;i++) {\n            result[i] = 0;\n            for (Edge next: (List<Edge>) edgeList[i]) {\n                if (next.dist == -1) {\n                    solve(next, edgeList);\n                }\n                result[i] += next.dist + next.num;\n            }\n        }\n        return result;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0843._Guess_the_Word.md",
    "content": "### 843. Guess the Word\n\n\n\n题目:\nhttps://leetcode.com/problems/guess-the-word/\n\n难度:\nHard\n\n题意：\n\n1. 给定最多100个长度为6的字符串\n2. 有一个字符串为秘密字符串，需要从这些字符串中猜出秘密字符串是哪个\n3. 每一轮猜会给出你猜的跟秘密字符串的不同字符数\n4. 最多猜10轮\n\n思路：\n\n- 这个题就纯模拟，挑一个字符串，然后根据返回的数，来决定下一轮的备选字符串\n- 加快速度的话，可以枚举所有的字符串，判断这个字符串跟其他字符串的字符差的统计值，取统计值差异最大的字符串来作为这一轮的猜测\n- 类似决策树\n\n代码：\n\n```java\nclass Solution {\n\t private int calDiff(String word1, String word2) {\n        int ret = 0;\n        for (int i = 0;i < word1.length();i++) {\n            if (word1.charAt(i) == word2.charAt(i)) {\n                ret++;\n            }\n        }\n        return ret;\n    }\n\n    private int select(int idx, List<Integer> pre, int[][] cache) {\n        int[] dist = new int[7];\n        Arrays.fill(dist, 0);\n        for (int x: pre) {\n            dist[cache[idx][x]] ++;\n        }\n        int ret = 0;\n        for (int i = 0;i < 6;i++) {\n            ret = Math.max(ret, dist[i]);\n        }\n        return ret;\n    }\n\n    private int select(List<Integer> pre, int[][] cache) {\n        int value = 1000000;\n        int ret = -1;\n        for (int idx: pre) {\n            int tmp = select(idx, pre, cache);\n            if (tmp < value) {\n                value = tmp;\n                ret = idx;\n            }\n        }\n        return ret;\n    }\n\n    public void findSecretWord(String[] wordlist, Master master) {\n        int[][] cache = new int[wordlist.length][wordlist.length];\n        for (int i = 0;i < wordlist.length;i++) {\n            for (int j = 0;j < wordlist.length;j++) {\n                cache[i][j] = calDiff(wordlist[i], wordlist[j]);\n            }\n        }\n\n        List<Integer> pre = new ArrayList<Integer>();\n        for (int i = 0;i < wordlist.length;i++) {\n            pre.add(i);\n        }\n        while (pre.size() != 0) {\n            int first = select(pre, cache);\n\n            int diff = master.guess(wordlist[first]);\n            if (diff == 6) {\n                return;\n            }\n            List<Integer> post = new ArrayList<Integer>();\n            for (int x: pre) {\n                if (cache[first][x] == diff) {\n                    post.add(x);\n                }\n            }\n            pre = post;\n        }\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0847._Shortest_Path_Visiting_All_Nodes.md",
    "content": "### 847. Shortest Path Visiting All Nodes\n\n\n\n题目:\nhttps://leetcode.com/problems/shortest-path-visiting-all-nodes/\n\n难度:\nHard\n\n题意：\n\n1. 给定一个图，问走遍所有的点的最短距离是多少\n\n思路：\n\n- 这个题首先考虑一下dfs的做法。假设我们已经到达了m个点，下个点，我们需要枚举所有下个点没有被访问的点，进行访问遍历，直到所有的点都被访问到\n- 我们注意到，枚举的过程中，需要枚举所有下个点没有被访问的点，而这个跟先前访问的顺序无关，也就是状态是一个访问集合，和当前到达的点共同组合而成的\n- 我们注意到，枚举的过程中，状态是需要重复访问，因此我们利用记忆化搜索，保存中间结果，进行动态规划\n- 这里需要注意的，我们可以预先把图形中两两最短距离先求出来缓存起来，这一部分只需要o(n^3)的复杂度\n- 子问题是：f(set, last)，set是访问集合，last是当前到达的点，函数值是达到当前状态最短距离\n- 这里有个代码的实现方式，集合如何用实现？当然如果想实现一个具备集合特性的数据结构也是可以的，最简单的方式就是用bitset，也就是把集合的信息压缩在一个二进制串中，这个题的数据范围是n<=12，因此一个int就可以表达状态，状态总量是`2^n*n`，因此这个动态规划的时间复杂度是`o(2^n*n^2)`\n\n代码：\n\n```java\nclass Solution {\n\t private int solve(int set, int last, int[][] dist, int[][] cache) {\n        if (cache[set][last] != -1) {\n            return cache[set][last];\n        }\n\n        if (set == (1 << dist.length) - 1) {\n            return cache[set][last] = 0;\n        }\n\n        int ret = 0x3fffffff;\n        for (int i = 0;i < dist.length;i++) {\n            if ((set & (1 << i)) == 0) {\n                ret = Math.min(ret, dist[last][i] + solve(set + (1 << i), i, dist, cache));\n            }\n        }\n        return cache[set][last] = ret;\n    }\n\n    private int[][] calDist(int[][] graph) {\n        int[][] dist = new int[graph.length][graph.length];\n        for (int i = 0;i < graph.length;i++) {\n            for (int j = 0;j < graph.length;j++) {\n                dist[i][j] = 0x3fffffff;\n            }\n        }\n        for (int i = 0;i < graph.length;i++) {\n            dist[i][i] = 0;\n            for (int j = 0;j < graph[i].length;j++) {\n                dist[i][graph[i][j]] = 1;\n            }\n        }\n        for (int k = 0;k < graph.length;k++) {\n            for (int i = 0;i < graph.length;i++) {\n                for (int j = 0;j < graph.length;j++) {\n                    dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);\n                }\n            }\n        }\n        return dist;\n    }\n\n    public int shortestPathLength(int[][] graph) {\n        int[][] cache = new int[1 << graph.length][graph.length];\n        for (int i = 0;i < (1 << graph.length);i++) {\n            for (int j = 0;j < graph.length;j++) {\n                cache[i][j] = -1;\n            }\n        }\n        int[][] dist = calDist(graph);\n        int ret = 0x3fffffff;\n        for (int i = 0;i < graph.length;i++) {\n            ret = Math.min(ret, solve((1 << i), i, dist, cache));\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0850._Rectangle_Area_II.md",
    "content": "### 850. Rectangle Area II\n\n\n\n题目:\nhttps://leetcode.com/problems/rectangle-area-ii/\n\n难度:\nHard\n\n题意：\n\n1. 给n个矩阵，求这n个矩阵覆盖的区域面积有多大\n\n思路：\n\n- 把x坐标和y坐标id化，将n个矩阵覆盖的区域分成r*c个小矩阵，这些小矩阵的距离都可以不相等\n- 遍历所有的矩阵，把这些小矩阵填充满\n- 遍历小矩阵，统计面积\n- 复杂度是o(n^3)\n- 这个题目可以将x坐标id化后，构建线段树来查询和更新面积区域，复杂度可以降为o(n^2logn)，当n>=1000使用\n\n代码：\n\n```java\nclass Solution {\n\t private int[] setToArray(TreeSet<Integer> set) {\n        int[] ret = new int[set.size()];\n        int idx = 0;\n        for (Integer e: set) {\n            ret[idx++] = e;\n        }\n        return ret;\n    }\n\n    private static int MOD = 1000000007;\n\n    public int rectangleArea(int[][] rectangles) {\n        TreeSet<Integer> set = new TreeSet<Integer>();\n        for (int i = 0;i < rectangles.length;i++) {\n            set.add(rectangles[i][0]);\n            set.add(rectangles[i][2]);\n        }\n        int[] x = setToArray(set);\n\n        set.clear();\n        for (int i = 0;i < rectangles.length;i++) {\n            set.add(rectangles[i][1]);\n            set.add(rectangles[i][3]);\n        }\n        int[] y = setToArray(set);\n\n        boolean[][] area = new boolean[x.length][y.length];\n        for (int i = 0;i < x.length;i++) {\n            for (int j = 0;j < y.length;j++) {\n                area[i][j] = false;\n            }\n        }\n        for (int i = 0;i < rectangles.length;i++) {\n            int lx = Arrays.binarySearch(x, rectangles[i][0]);\n            int rx = Arrays.binarySearch(x, rectangles[i][2]);\n\n            int ly = Arrays.binarySearch(y, rectangles[i][1]);\n            int ry = Arrays.binarySearch(y, rectangles[i][3]);\n\n            for (int j = lx;j < rx;j++) {\n                for (int k = ly;k < ry;k++) {\n                    area[j][k] = true;\n                }\n            }\n        }\n        int ret = 0;\n        for (int i = 0;i < x.length;i++) {\n            for (int j = 0;j < y.length;j++) {\n                if (area[i][j]) {\n                    ret += (long)(x[i + 1] - x[i]) * (y[j + 1] - y[j]) % MOD;\n                    if (ret >= MOD) {\n                        ret -= MOD;\n                    }\n                }\n            }\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0854._K-Similar_Strings.md",
    "content": "### 854. K-Similar Strings\n\n\n\n题目:\nhttps://leetcode.com/problems/k-similar-strings\n\n难度:\nHard\n\n题意：\n\n1. 给定两个字符串，问最少要交换多少次，使得A变成了B，A和B里面的字母都是a-f\n\n思路：\n\n- 将字符串A到字符串B的变换看成图，那么这张图就是一个一个环构成的。环上，交换的次数等于环的长度-1，所以这个题目变成了，将图拆成环，使环的个数最大\n- 后面就是纯搜索，注意状态合并。状态定义为，当前图的状态（6*6的矩阵），然后在图上寻找所有的可行环，分别去掉，转成下一个状态\n\n代码：\n\n```java\nclass Solution {\n\tprivate class State implements Comparable<State> {\n        int[] a;\n        int total;\n\n        State() {\n            a = new int[6];\n            Arrays.fill(a, 0);\n            total = 0;\n        }\n\n        State(int[] a, int total) {\n            this.a = Arrays.copyOf(a, a.length);\n            this.total = total;\n        }\n\n        private int get(int x, int y) {\n            return (a[x] >> (y * 4)) & 15;\n        }\n\n        private void minus(int x, int y) {\n            a[x] -= 1 << (y * 4);\n            total--;\n        }\n\n        private void add(int x, int y) {\n            a[x] += 1 << (y * 4);\n            total++;\n        }\n\n        @Override\n        public int compareTo(State o) {\n            if (Integer.compare(total, o.total) == 0) {\n                for (int i = 0;i < 6;i++) {\n                    if (Integer.compare(a[i], o.a[i]) != 0) {\n                        return Integer.compare(a[i], o.a[i]);\n                    }\n                }\n                return 0;\n            } else {\n                return -Integer.compare(total, o.total);\n            }\n        }\n    }\n\n    private void extand(boolean[] flag, int[] pos, TreeMap<State, Integer> stateMap, State current, int idx) {\n        if (current.get(pos[idx - 1], pos[0]) != 0) {\n            State next = new State(current.a, current.total);\n            for (int i = 0;i < idx - 1;i++) {\n                next.minus(pos[i], pos[i + 1]);\n            }\n            next.minus(pos[idx - 1], pos[0]);\n            int value = stateMap.get(current);\n            value += idx - 1;\n            if (stateMap.containsKey(next)) {\n                value = value < stateMap.get(next) ? value : stateMap.get(next);\n                stateMap.put(next, value);\n            } else {\n                stateMap.put(next, value);\n            }\n        }\n\n        if (idx == 6) {\n            return;\n        }\n        for (int i = 0;i < 6;i++) {\n            if (!flag[i] && current.get(pos[idx - 1], i) != 0) {\n                flag[i] = true;\n                pos[idx] = i;\n                extand(flag, pos, stateMap, current, idx + 1);\n                flag[i] = false;\n            }\n        }\n    }\n\n    private void solve(TreeMap<State, Integer> stateMap, State current) {\n        boolean[] flag = new boolean[6];\n        Arrays.fill(flag, false);\n        int[] pos = new int[6];\n        int min = -1;\n        for (int i = 0;i < 6;i++) {\n            if (current.a[i] != 0) {\n                min = i;\n                break;\n            }\n        }\n        if (min == -1) {\n            return;\n        }\n        flag[min] = true;\n        pos[0] = min;\n        extand(flag, pos, stateMap, current, 1);\n    }\n\n    public int kSimilarity(String A, String B) {\n        TreeMap<State, Integer> stateMap = new TreeMap<State, Integer>();\n        State start = new State();\n        for (int i = 0;i < A.length();i++) {\n            if (A.charAt(i) != B.charAt(i)) {\n                start.add(A.charAt(i) - 'a', B.charAt(i) - 'a');\n            }\n        }\n        int ret = 0x3fffffff;\n        stateMap.put(start, 0);\n\n        while (!stateMap.isEmpty()) {\n            State current = stateMap.firstKey();\n            if (current.total == 0) {\n                ret = ret < stateMap.get(current) ? ret : stateMap.get(current);\n            } else {\n                solve(stateMap, current);\n            }\n            stateMap.remove(current);\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0857._Minimum_Cost_to_Hire_K_Workers.md",
    "content": "### 857. Minimum Cost to Hire K Workers\n\n\n\n题目:\nhttps://leetcode.com/problems/minimum-cost-to-hire-k-workers/\n\n难度:\nHard\n\n题意：\n\n1. n个工人，有一个工作量数组quality，有个最低工资数组wage\n2. 要聘用K个工人，工资最低。要求，这n个工人的工资必须不低于他们的最低工资要求，并且他们的工资跟工作量成正比\n\n思路：\n\n- 由于工资跟工作量成正比，假设这个比率是r。第i工人愿意被聘用的条件是r>=wage[i]/quality[i]\n- 令ratio[i]=wage[i]/quality[i]，对ratio[i]排序，遍历数组ratio，i每递曾一个，就有一个工人愿意被聘用\n- 假设现在有p个工人愿意被聘用(p>=K)，现在轮到我们来挑选K个人，由于工资总和要最低，且工资=工作量*p，所以在这p个人中挑选工作量最低的K个人\n- 子问题是，求数列中前K小的数，需要最小堆\n- 复杂度是o(nlogn)\n\n代码：\n\n```java\nclass Solution {\n\tpublic double mincostToHireWorkers(int[] quality, int[] wage, int K) {\n        double[] ratio = new double[quality.length];\n        Integer[] pos = new Integer[quality.length];\n        for (int i = 0;i < quality.length;i++) {\n            ratio[i] = (double) wage[i] / quality[i];\n            pos[i] = i;\n        }\n        Arrays.sort(pos, new Comparator<Integer>() {\n            @Override\n            public int compare(Integer o1, Integer o2) {\n                return Double.compare(ratio[o1], ratio[o2]);\n            }\n        });\n        double ret = 1e40;\n        int maxK = 0;\n        PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>() {\n            @Override\n            public int compare(Integer o1, Integer o2) {\n                return -Integer.compare(o1, o2);\n            }\n        });\n        for (int i = 0;i < pos.length;i++) {\n            maxK += quality[pos[i]];\n            queue.add(quality[pos[i]]);\n            if (queue.size() > K) {\n                maxK -= queue.poll();\n            }\n            if (queue.size() == K) {\n                ret = ret > maxK * ratio[pos[i]] ? maxK * ratio[pos[i]] : ret;\n            }\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0862._Shortest_Subarray_with_Sum_at_Least_K.md",
    "content": "### 862. Shortest Subarray with Sum at Least K\n\n\n\n题目:\nhttps://leetcode.com/problems/shortest-subarray-with-sum-at-least-k\n\n难度:\nHard\n\n题意：\n\n1. 给定一个数组A\n2. 求A的所有连续子数组中，和大于K，最短的一个，长度是多少\n\n思路：\n\n- 如果A里面都是正整数，那就是一个妥妥的移动区间，可惜有负数\n- 换种思路，A[i...j] = sum[1..j] - sum[1..i-1]，我们可以从前往后累加，当累加到j时，我们只需要把前面sum[1..1]到sum[1..j-1]的累加值中寻找一个最大的i，使得sum[1..j] - sum[1..i-1] >= K，复杂度是o(n^2)，是不可接受的\n- 注意到，当我们累加到j，如果存在一个i，使得sum[1..i] <= sum[1..i + 1]，那么，假设sum[1..j] - sum[1..i] >= K，那么sum[1..j] - sum[1..i + 1] 肯定也是 >= K，所以当sum[1..i + 1]存在时，sum[1..i] 没有存在的意义。因此，我们只需要维护一个单调递增队列sum[1..a1],sum[1..a2],...sum[1..am]，其中sum[1..a1] < sum[1..a2] < .... ，a1 < a2 < ...\n- 有了单调递增队列，当遍历到j，我们只需要二分这个队列，就可以找到一个最大的i，使的sum[1..j]-sum[1..i] >= K，插入一个数到单调队列，只需要从队列尾开始比较，把比要插入的数大的都出列，维持单调递增特性\n- 复杂度是o(nlogn)\n\n代码：\n\n```java\nclass Solution {\n\tprivate class Node {\n        int sum;\n        int pos;\n\n        public Node(int sum, int pos) {\n            this.sum = sum;\n            this.pos = pos;\n        }\n    }\n\n    private int find(Node[] incrQueue, int n, int value) {\n        int left = -1;\n        int right = n;\n        while (right - left > 1) {\n            int mid = (left + right) / 2;\n            if (incrQueue[mid].sum <= value) {\n                left = mid;\n            } else {\n                right = mid;\n            }\n        }\n        return left;\n    }\n\n    public int shortestSubarray(int[] A, int K) {\n        Node[] incrQueue = new Node[A.length + 1];\n        int n = 0;\n        int ret = 0x3fffffff;\n        incrQueue[n++] = new Node(0, -1);\n        int sum = 0;\n        for (int i = 0;i < A.length;i++) {\n            sum += A[i];\n            int pos = find(incrQueue, n, sum - K);\n            if (pos != -1) {\n                ret = ret < (i - incrQueue[pos].pos) ? ret : (i - incrQueue[pos].pos);\n            }\n            while (n != 0 && incrQueue[n - 1].sum > sum) {\n                n--;\n            }\n            incrQueue[n++] = new Node(sum, i);\n        }\n        if (ret == 0x3fffffff) {\n            return -1;\n        } else {\n            return ret;\n        }\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0864._Shortest_Path_to_Get_All_Keys.md",
    "content": "### 864. Shortest Path to Get All Keys\n\n\n\n题目:\nhttps://leetcode.com/problems/shortest-path-to-get-all-keys/\n\n难度:\nHard\n\n题意：\n\n1. 给一个最大30*30的地图\n2. 其中有6个钥匙6个锁，锁要拿到相应的钥匙才能开\n3. 上下左右四个方向走，问最少要走多少步，才能拿到所有的钥匙\n\n思路：\n\n- 这个题比较暴力，就是广度优先搜索\n- 注意搜索空间，总共最多才6个钥匙6个锁，定义状态为：去过的钥匙集合（二进制压缩），去过的锁集合（二进制压缩），当前位置。我们需要从这个状态转移到另一个状态，从这个状态开始广度优先搜索。转移到另一个状态，合并下一轮的搜索空间\n- 复杂度是o(k * 2 ^ 6 * 2 ^ 6 *30 * 30)，k是搜索空间所用数据结构的复杂度\n- 这个题我写的比较差，主要是用了哈希表来保存搜索空间，引入了不必要的复杂度，超时了。大家写的时候直接用数组来保存搜索空间即可\n- 这道题优化空间很大，可以剪枝，大家可以当做练习\n\n代码：\n\n```java\nclass Solution {\n    private int[] dx = new int[]{1, -1, 0, 0};\n    private int[] dy = new int[]{0, 0, 1, -1};\n\n    private class State {\n        int setKey;\n        int setLock;\n        int posX;\n        int posY;\n\n        public State() {\n        }\n\n        public State(int setKey, int setLock, int posX, int posY) {\n            this.setKey = setKey;\n            this.setLock = setLock;\n            this.posX = posX;\n            this.posY = posY;\n        }\n\n        @Override\n        public int hashCode() {\n            int hashCode = 0;\n            hashCode = hashCode * 31 + Integer.hashCode(setKey);\n            hashCode = hashCode * 31 + Integer.hashCode(setLock);\n            hashCode = hashCode * 31 + Integer.hashCode(posX);\n            hashCode = hashCode * 31 + Integer.hashCode(posY);\n            return hashCode;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (!(obj instanceof State)) {\n                return false;\n            }\n            State state = (State) obj;\n            return setKey == state.setKey && setLock == state.setLock &&\n                    posX == state.posX && posY == state.posY;\n        }\n    }\n\n    private class Point {\n        int x;\n        int y;\n\n        public Point(int x, int y) {\n            this.x = x;\n            this.y = y;\n        }\n    }\n\n    public int shortestPathAllKeys(String[] grid) {\n        Map<State, Integer> currentMap = new HashMap<State, Integer>();\n        State start = new State();\n        int numKey = 0;\n        for (int i = 0;i < grid.length;i++) {\n            for (int j = 0;j < grid[i].length();j++) {\n                if (grid[i].charAt(j) == '@') {\n                    start.posX = i;\n                    start.posY = j;\n                }\n                if (grid[i].charAt(j) <= 'f' && grid[i].charAt(j) >= 'a') {\n                    numKey ++;\n                }\n            }\n        }\n        start.setKey = start.setLock = ((1 << numKey) - 1);\n        currentMap.put(start, 0);\n        if (numKey == 0) {\n            return 0;\n        }\n\n        int ret = 0x3fffffff;\n        while (!currentMap.isEmpty()) {\n            Map<State, Integer> nextMap = new HashMap<State, Integer>();\n\n            for (State state: currentMap.keySet()) {\n\n                int curValue = currentMap.get(state);\n                if (state.setKey == 0) {\n                    ret = ret < curValue ? ret : curValue;\n                    continue;\n                }\n\n                int[][] dis = new int[grid.length][grid[0].length()];\n                for (int i = 0;i < grid.length;i++) {\n                    for (int j = 0;j < grid[0].length();j++) {\n                        dis[i][j] = 0x3fffffff;\n                    }\n                }\n                dis[state.posX][state.posY] = 0;\n                LinkedList<Point> queue = new LinkedList<Point>();\n                queue.addLast(new Point(state.posX, state.posY));\n                while (!queue.isEmpty()) {\n                    Point point = queue.pollFirst();\n                    for (int i = 0;i < 4;i++) {\n                        Point next = new Point(point.x + dx[i], point.y + dy[i]);\n                        if (next.x < 0 || next.y < 0 || next.x >= grid.length || next.y >= grid[0].length()) {\n                            continue;\n                        }\n                        char c = grid[next.x].charAt(next.y);\n                        if (c == '#') {\n                            continue;\n                        }\n                        if (c <= 'F' && c >= 'A' && (state.setKey & (1 << (c - 'A'))) != 0) {\n                            continue;\n                        }\n\n                        if (dis[next.x][next.y] == 0x3fffffff) {\n                            dis[next.x][next.y] = dis[point.x][point.y] + 1;\n                            queue.addLast(next);\n\n                            if (c <= 'f' && c >= 'a' && (state.setKey & (1 << (c - 'a'))) != 0) {\n                                State nextState = new State(\n                                        state.setKey - (1 << (c - 'a')),\n                                        state.setLock,\n                                        next.x,\n                                        next.y\n                                );\n                                int value = currentMap.get(state) + dis[next.x][next.y];\n                                if (!nextMap.containsKey(nextState) || value < nextMap.get(nextState)) {\n                                    nextMap.put(nextState, value);\n                                }\n                            }\n\n                            if (c <= 'F' && c >= 'A' && (state.setLock & (1 << (c - 'A'))) != 0) {\n                                State nextState = new State(\n                                        state.setKey,\n                                        state.setLock - (1 << (c - 'A')),\n                                        next.x,\n                                        next.y\n                                );\n                                int value = curValue + dis[next.x][next.y];\n                                if (!nextMap.containsKey(nextState) || value < nextMap.get(nextState)) {\n                                    nextMap.put(nextState, value);\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            currentMap = nextMap;\n        }\n        if (ret == 0x3fffffff) {\n            return -1;\n        } else {\n            return ret;\n        }\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0871._Minimum_Number_of_Refueling_Stops.md",
    "content": "### 871. Minimum Number of Refueling Stops\n\n\n\n题目:\nhttps://leetcode.com/problems/minimum-number-of-refueling-stops/\n\n难度:\nHard\n\n题意：\n\n1. 一辆车要从start跑到target，带着fuel单位的油\n2. 中间有很多个加油站，给定加油站的坐标和油量。到了加油站你可以选择到站加油和直接过站\n3. 求最少需要停几个加油站\n\n思路：\n\n- 看起来是不是跟403的Frog jump很像啊，看数据范围，确实也是个动态规划的题目，动态规划的解法留给大家做，这里说一个更简单的方法\n- 我们可以换种思路。每次到站之后，把所有加油站的油都带上。先不加，等到有需要的时候再加。如果发现不够油到下个加油站，那么我们就优先选择油多的加油站的油来加，相当于我们在那个加油站停了。这里为什么优先选择油多的加油站呢？因为油多也是一站，油少也是一站。\n- 如果把所有的油加满都达不到下个加油站，那么，输出-1\n- 如果可以到target之后，我们就输出加了多少个加油站的油即可\n- 中间那部分，优先选择油多，我们需要维护一个优先队列（即最大堆），复杂度o(nlogn)，当然按照数据范围，就算是用一个链表啊，数组啊，o(n^2)照样能过，这道题的数据范围出错了，应该是stations.length<=100000\n- 这种算法叫贪心\n\n代码：\n\n```java\nclass Solution {\n    private int runTo(int start, int fuel, int target, PriorityQueue<Integer> queue) {\n        fuel -= target - start;\n        while (fuel < 0) {\n            Integer top = queue.poll();\n            if (top == null) {\n                return -1;\n            }\n            fuel += top;\n        }\n        return fuel;\n    }\n\n    public int minRefuelStops(int target, int startFuel, int[][] stations) {\n        PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {\n            @Override\n            public int compare(Integer o1, Integer o2) {\n                return -Integer.compare(o1, o2);\n            }\n        });\n        int start = 0;\n        int fuel = startFuel;\n\n        for (int i = 0;i < stations.length;i++) {\n            fuel = runTo(start, fuel, stations[i][0], queue);\n            if (fuel == -1) {\n                return fuel;\n            }\n            queue.add(stations[i][1]);\n            start = stations[i][0];\n        }\n\n        if (runTo(start, fuel, target, queue) != -1) {\n            return stations.length - queue.size();\n        } else {\n            return -1;\n        }\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0878._Nth_Magical_Number.md",
    "content": "# 878. Nth Magical Number\n\n**<font color=red>难度: Hard</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/nth-magical-number\n\n> 内容描述\n\n```\nA positive integer is magical if it is divisible by either A or B.\n\nReturn the N-th magical number.  Since the answer may be very large, return it modulo 10^9 + 7.\n\n \n\nExample 1:\n\nInput: N = 1, A = 2, B = 3\nOutput: 2\nExample 2:\n\nInput: N = 4, A = 2, B = 3\nOutput: 6\nExample 3:\n\nInput: N = 5, A = 2, B = 4\nOutput: 10\nExample 4:\n\nInput: N = 3, A = 6, B = 4\nOutput: 8\n \n\nNote:\n\n1 <= N <= 10^9\n2 <= A <= 40000\n2 <= B <= 40000\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(log(A*B))******- 空间复杂度: O(N)******\n\n* 从数据范围看来，N高达10^9，直接遍历不现实\n* 注意到魔法数是有循环的，我们令P=A和B的最小公倍数，那么在每P个数中，魔法数的数量和位置都是相同的，因此我们只需要计算1-P中间的魔法数\n* 1~P的魔法数数量是 P/A+P/B-1，注意到，P是A和B的最小公倍数，因此1~P中，既能被A整除，也能被B整除，只有一个数，就是P\n* 现在问题变成，在1~P中，求第n个魔法数\n* 解法一：A和B的数据范围只有40000，因此，1~P中魔法数，不超过80000个，只需要把所有的魔法数求出来，排个序，就能求出第n个魔法数，复杂度是O(A+B)\n* 解法二：注意到，我们在1~p中任取一个数x（x<p），1~x中魔法数的数量是x/A+x/B，注意这个是整除。因此我们可以对1~p进行二分，就能求出第n个魔法数，复杂度是O(log(A*B))\n\n\n\n```java\nclass Solution {\n    private int gcd(int a, int b) {\n        if (b == 0) {\n            return a;\n        } else {\n            return gcd(b, a % b);\n        }\n    }\n\n    private int lcm(int a, int b) {\n        return a * b / gcd(a, b);\n    }\n\n    public static int MOD = 1000000007;\n\n    private int find(int a, int b, int n) {\n        int left = 1, right = lcm(a, b);\n\n        while (right - left > 1) {\n            int mid = (left + right) / 2;\n            if (mid / a + mid / b >= n) {\n                right = mid;\n            } else {\n                left = mid;\n            }\n        }\n\n        return right;\n    }\n\n    public int nthMagicalNumber(int N, int A, int B) {\n        int repeat = lcm(A, B);\n        int num = repeat / A + repeat / B - 1;\n\n        int ret = find(A, B, (N - 1) % num + 1);\n        ret += (long)((N - 1) / num) * repeat % MOD;\n        if (ret > MOD) {\n            ret -= MOD;\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0879._Profitable_Schemes.md",
    "content": "### 879. Profitable Schemes\n\n\n\n题目:\nhttps://leetcode.com/problems/profitable-schemes/\n\n难度:\nHard\n\n题意：\n\n1. 给定一个集合，每个集合都有一个group和profile，给定两个数G和P\n2. 求在集合所有的子集合中，group和不大于G，并且profile和不小于P的子集合个数\n\n思路：\n\n- 这是一个01背包模型的变种\n- 大家思考一下，01背包是说，给定一个集合，每个集合有一个成本和一个收益，求成本和不大于总成本的最大收益\n- 这个题有两个条件，因此有两个规划方向。这两个方向还不一样，group是约束条件，规划长度是1-G，而profile是下限，规划长度也是1-P（因为超过P再记录P的具体的值已经没有意义了，所以一切>=P都可用P代替）\n- 最后的结果就是总group在1-G中，并且总profile>=p的子集合个数\n- 复杂度是o(NGP)，看数据范围，是不是正好在10^6的量级里面？\n\n代码：\n\n```java\nclass Solution {\n    private static int MOD = 1000000007;\n\n    public int profitableSchemes(int G, int P, int[] group, int[] profit) {\n        int[][] dp = new int[G + 1][P + 1];\n        for(int i = 0;i <= G;i++) {\n            for (int j = 0;j <= P;j++) {\n                dp[i][j] = 0;\n            }\n        }\n        dp[0][0] = 1;\n        for (int k = 0;k < group.length;k++) {\n            for (int i = G;i >= 0;i--) {\n                if (i + group[k] > G) {\n                    continue;\n                }\n                for (int j = 0;j <= P;j++) {\n                    int p = j + profit[k];\n                    if (p > P) {\n                        p = P;\n                    }\n                    dp[i + group[k]][p] += dp[i][j];\n                    if (dp[i + group[k]][p] >= MOD) {\n                        dp[i + group[k]][p] -= MOD;\n                    }\n                }\n            }\n        }\n        int ret = 0;\n        for (int i = 1;i <= G;i++) {\n            ret += dp[i][P];\n            if (ret >= MOD) {\n                ret -= MOD;\n            }\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0882._Reachable_Nodes_In_Subdivided_Graph.md",
    "content": "### 899. Reachable Nodes In Subdivided Graph\n\n\n\n题目:\nhttps://leetcode.com/problems/reachable-nodes-in-subdivided-graph/\n\n难度:\nHard\n\n题意：\n\n1. 给定一张图，图上有无向边，边上有等距的点\n2. 从0出发，最长路径能够访问M个点，问总共能访问多少个点\n\n思路：\n\n- 这个题是最短路的变种\n- 边上面点的个数就是边的权值，先做一遍最短路\n- 扫描每个边，判断左右两个端点的值，进行累加\n  - 左/右 端点大于M的，不累加\n  - 左/右 端点分别向边里面访问点，假设左端点能访问a个点，右端点能访问b个点，那么能访问的点数就是min(a + b, 该边点数)\n- 统计完边，再统计点，只需要扫描所有点，根据最短路的端点值，判断是否不大于M，累加\n- 最短路复杂度是o(n^2)，最短路中间有一个步骤，每一轮寻找当前最小的点开扩展，这一步骤是可以用一个堆来优化，复杂度是o(n log e)，e是边的个数。这个做法留给大家做练习\n\n代码：\n\n```java\nclass Solution {\n    private static int MAX = 2000000000;\n\n    private class Edge {\n        int src;\n        int dest;\n        int value;\n\n        public Edge(int src, int dest, int value) {\n            this.src = src;\n            this.dest = dest;\n            this.value = value;\n        }\n    }\n\n    public int reachableNodes(int[][] edges, int M, int N) {\n        List<Edge>[] edgeList = new List[N];\n        for (int i = 0;i < edgeList.length;i++) {\n            edgeList[i] = new ArrayList<Edge>();\n        }\n\n        for (int i = 0;i < edges.length;i++) {\n            edgeList[edges[i][0]].add(new Edge(edges[i][0], edges[i][1], edges[i][2] + 1));\n            edgeList[edges[i][1]].add(new Edge(edges[i][1], edges[i][0], edges[i][2] + 1));\n        }\n\n        int ret = 0;\n\n        boolean[] flag = new boolean[N];\n        int[] min = new int[N];\n        for (int i = 0;i < N;i++) {\n            flag[i] = false;\n            min[i] = MAX;\n        }\n\n        min[0] = 0;\n        while (true) {\n            int idx = -1;\n            for (int i = 0;i < N;i++) {\n                if (!flag[i] && min[i] != MAX) {\n                    if (idx == -1 || min[i] < min[idx]) {\n                        idx = i;\n                    }\n                }\n            }\n            if (idx == -1) {\n                break;\n            }\n\n            flag[idx] = true;\n            for (int i = 0;i < edgeList[idx].size();i++) {\n                Edge edge = edgeList[idx].get(i);\n                if (!flag[edge.dest]) {\n                    min[edge.dest] = Math.min(min[edge.dest], min[edge.src] + edge.value);\n                }\n            }\n        }\n\n        for (int i = 0;i < edges.length;i++) {\n            if (min[edges[i][0]] + edges[i][2] <= M || min[edges[i][1]] + edges[i][2] <= M) {\n                ret += edges[i][2];\n                continue;\n            }\n            int left = 0, right = 0;\n            if (min[edges[i][0]] <= M) {\n                left = M - min[edges[i][0]];\n            }\n            if (min[edges[i][1]] <= M) {\n                right = M - min[edges[i][1]];\n            }\n            if (left + right >= edges[i][2]) {\n                ret += edges[i][2];\n            } else {\n                ret += left + right;\n            }\n        }\n\n        for (int i = 0;i < N;i++) {\n            if (min[i] <= M) {\n                ret++;\n            }\n        }\n\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0887._Super_Egg_Drop.md",
    "content": "### 887. Super Egg Drop\n\n\n\n题目:\nhttps://leetcode.com/problems/super-egg-drop\n\n难度:\nHard\n\n题意：\n\n1. 已知蛋从F楼丢下会坏\n2. 现在给你K个蛋，在N层楼中，请问最坏情况最少要试验几次才能知道F的精确值\n3. 如果蛋丢下来不会坏，那么可以捡起来继续丢\n\n思路：\n\n- 又是一个脑筋急转弯的题目，我们来看看K=1的情况。由于只有一个蛋，坏了就没了，所以只能一层一层往下丢。一层丢下，蛋坏了，说明F=1，反之，继续去二层丢，所以K=1时，最坏情况要试验N次\n- 当K>=2时，由于蛋有多余，可以大胆的去中间丢，这样就可以少丢几次\n- 因此，令`cache[K][N]`表示K个蛋在N层试验最少要试验的次数，假设第一次要在i层丢蛋，那么分成了两个子问题，如果蛋没碎了，那么最少次数等于`cache[k][N-i]+1`，如果蛋碎了，那么最少次数等于`cache[k-1][i-1]+1`\n- 那么这个题就变成了`cache[k][N] = min[1<=i<=N]{max{cache[k][N-i], cache[k - 1][i - 1] + 1} + 1}`，时间复杂度是o(kNN)\n- 但是看数据范围，k<=100，N<=10000，o(kNN)肯定是过不了的\n- 注意到，`cache[k][N]`是非严格递增输了，且递增值不会超过1，即`0<=cache[k][i+1]-cache[k][i]<=1`\n- 计算过程中令`cache[k][N]`最优解的i，跟`cache[k][N+1]`最优解的j，关系是`0<=j-i<=1`\n- 因此在处理的过程，固定k，递推N，保存上一个最优解i，继续推出下一个最优解\n\n代码：\n\n```java\nclass Solution {\n    private static int[][] cache;\n\n    private static void init() {\n        if (cache == null) {\n            cache = new int[101][10001];\n\n            for (int i = 1;i <= 10000;i++) {\n                cache[1][i] = i;\n            }\n\n            for (int i = 2;i <= 100;i++) {\n                cache[i][1] = 0;\n                cache[i][1] = 1;\n                cache[i][2] = 2;\n\n                int idx = 1;\n                for (int j = 3;j <= 10000;j++) {\n\n                    while (cache[i - 1][idx + 1] <= cache[i][j - idx - 2]) {\n                        idx++;\n                    }\n\n                    cache[i][j] = Math.max(cache[i - 1][idx], cache[i][j - idx - 1]) + 1;\n                }\n            }\n        }\n    }\n\n    public int superEggDrop(int K, int N) {\n        init();\n        return cache[K][N];\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0891._Sum_of_Subsequence_Widths.md",
    "content": "# 891. Sum of Subsequence Widths\n\n**<font color=red>难度: Hard</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/sum-of-subsequence-widths\n\n> 内容描述\n\n```\n\nGiven an array of integers A, consider all non-empty subsequences of A.\n\nFor any sequence S, let the width of S be the difference between the maximum and minimum element of S.\n\nReturn the sum of the widths of all subsequences of A. \n\nAs the answer may be very large, return the answer modulo 10^9 + 7.\n\n \n\nExample 1:\n\nInput: [2,1,3]\nOutput: 6\nExplanation:\nSubsequences are [1], [2], [3], [2,1], [2,3], [1,3], [2,1,3].\nThe corresponding widths are 0, 0, 0, 1, 1, 2, 2.\nThe sum of these widths is 6.\n \n\nNote:\n\n1 <= A.length <= 20000\n1 <= A[i] <= 20000\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)******\n\n* 我们逆向思路解决这个问题。结果要求最大数减去最小数的差之和，我们可以认为是，把所有的子序列的最大值累加，减去所有的子序列的最小值的累加值\n* 数组中最大数，在子数组中也是最大数的，有2^(n-1)个子数组，同理，第二大数，在子数组是最大数的，有2^(n-2)个子数组，以此类推\n* 同理，最小数也是这样计算\n* 复杂度是O(nlgn)\n\n代码：\n\n```java\nclass Solution {\n    private static int MOD = 1000000007;\n\n    private static int[] pow2;\n\n    private void init() {\n        if (pow2 == null) {\n            pow2 = new int[20000];\n            pow2[0] = 1;\n            for (int i = 1;i < pow2.length;i++) {\n                pow2[i] = pow2[i - 1] * 2;\n                if (pow2[i] >= MOD) {\n                    pow2[i] -= MOD;\n                }\n            }\n        }\n    }\n\n    public int sumSubseqWidths(int[] A) {\n        init();\n        Arrays.sort(A);\n        int ret = 0;\n        for (int i = 0;i < A.length;i++) {\n            ret += (long)A[i] * pow2[i] % MOD;\n            if (ret >= MOD) {\n                ret -= MOD;\n            }\n            ret -= (long)A[i] * pow2[A.length - i - 1] % MOD;\n            if (ret < 0) {\n                ret += MOD;\n            }\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0895._Maximum_Frequency_Stack.md",
    "content": "### 895. Maximum Frequency Stack\n\n\n\n题目:\nhttps://leetcode.com/problems/maximum-frequency-stack/\n\n难度:\nHard\n\n题意：\n\n1. 一个特殊的类栈数据结构，具有两种操作\n2. push x：表示将x入栈\n3. pop：表示将栈中最多的数弹出，相同数量的数弹出最近入栈的一个数\n\n思路：\n\n- 这个题的数据结构中，x是key，既需要根据x来操作，又需要根据x的数量和入栈时间来出栈，典型的双向查找表\n\n- 维护一个x到x的入栈时间的映射关系，入栈时间我们定义为第几次push操作，即x->[t1,t2,t3]\n\n- 维护一个**有序**的x的入栈时间到x的对应表，比较函数定义为：栈中元素个数，和栈顶时间\n\n代码：\n\n```java\nclass FreqStack {\n\n    int _count;\n    private class Item implements Comparable<Item> {\n        LinkedList<Integer> time;\n\n        public Item(LinkedList<Integer> time) {\n            this.time = time;\n        }\n\n        public LinkedList<Integer> getTime() {\n            return time;\n        }\n\n        @Override\n        public int compareTo(Item o) {\n            if (time.size() == o.time.size()) {\n                return Integer.compare(o.time.getLast(), time.getLast());\n            } else {\n                return Integer.compare(o.time.size(), time.size());\n            }\n        }\n    }\n\n    TreeMap<Item, Integer> freqToId;\n    Map<Integer, Item>  idToFreq;\n\n    public FreqStack() {\n        _count = 0;\n        freqToId = new TreeMap<Item, Integer>();\n        idToFreq = new HashMap<Integer, Item>();\n    }\n\n    public void push(int x) {\n        if (!idToFreq.containsKey(x)) {\n            LinkedList<Integer> time = new LinkedList<Integer>();\n            time.addLast(_count++);\n            Item item = new Item(time);\n            freqToId.put(item, x);\n            idToFreq.put(x, item);\n        } else {\n            Item origin = idToFreq.get(x);\n            freqToId.remove(origin);\n            LinkedList<Integer> time = origin.time;\n            time.addLast(_count++);\n            Item item = new Item(time);\n            idToFreq.put(x, item);\n            freqToId.put(item, x);\n        }\n    }\n\n    public int pop() {\n        Map.Entry<Item, Integer> first = freqToId.firstEntry();\n        freqToId.remove(first.getKey());\n        idToFreq.remove(first.getValue());\n\n        LinkedList<Integer> time = first.getKey().time;\n        time.removeLast();\n        if (time.size() != 0) {\n            Item item = new Item(time);\n            idToFreq.put(first.getValue(), item);\n            freqToId.put(item, first.getValue());\n        }\n\n        return first.getValue();\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0899._Orderly_Queue.md",
    "content": "### 899. Orderly Queue\n\n\n\n题目:\nhttps://leetcode.com/problems/orderly-queue/\n\n难度:\nHard\n\n题意：\n\n1. 给定一个字符串S和一个数K\n2. 每一轮可以选择字符串的前K个数的其中一个，把它移到放在最后面\n3. 无限次数后，问生成的最小字符串是什么\n\n思路：\n\n- 不要考虑暴力了，由于是无限次数，连暴力搜索都无从下手，除非出动启发式搜索\n- 这是个脑筋急转弯的题目，分为两种情况\n- 当K=1时，由于每次只能取第一个放在最后面，这种情况是暴力搜索，时间复杂度是o(nk)，k是字符串的长度\n- 当K>=2时，我们拿K=2出来考虑，证明当K=2时，可以生成任一字符串。\n  - 固定第一个数，不断的把第二个数放在最后面，这种做法可以使第一个数插入到队列的任一位置\n  - 假设队列A1-Ak有序，我们要把第A(k+1)插入到Ak的后面，只需要把A(k+1)固定在第一个数，重复第一个做法即可\n  - 根据数据归纳法，当K=2时，可以生成任一字符串\n- 因此当K>=2时，只需要排序字符串里面的字符即可\n\n拓展：\n\n- 这道题有o(nlogn)的解法，当k=1时，可以用o(nlogn)的排序算法，找到最小的字符串。有兴趣的同学可以百度一下“后缀数组”，一百行代码左右，这里就不展示了\n\n代码：\n\n```java\nclass Solution {\n    public String orderlyQueue(String S, int K) {\n        if (K == 1) {\n            String min = S;\n            for (int i = 0;i < S.length();i++) {\n                S = S.substring(1, S.length()) + S.charAt(0);\n                if (min.compareTo(S) > 0) {\n                    min = S;\n                }\n            }\n            return min;\n        } else {\n            char[] c = S.toCharArray();\n            Arrays.sort(c);\n            return new String(c);\n        }\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0902._Numbers_At_Most_N_Given_Digit_Set.md",
    "content": "### 902. Numbers At Most N Given Digit Set\n\n\n\n题目:\nhttps://leetcode.com/problems/numbers-at-most-n-given-digit-set/\n\n难度:\nHard\n\n题意：\n\n1. 给定一个1-9的集合S，和一个上限k\n2. 求这个集合中能构成多少个数，并且不大于k\n\n思路：\n\n- 分情况计算\n  - 当构成的数的位数小于k的位数，那么能构成的数数量为|S|^位数\n  - 当构成的数的位数等于k的位数，遍历集合S的数a，判断a\n    - 如果小于k的最高位，那么能够成的数数量为|S|^(k的位数-1)\n    - 如果等于k的最高位，继续判断下一位\n    - 如果不存在等于k的最高位的数，不判断下一位，直接跳出循环\n\n代码：\n\n```java\nclass Solution {\n    private int[] split(int a) {\n        int[] ret = new int[10];\n        int idx = 0;\n        while (a != 0) {\n            ret[idx++] = a % 10;\n            a /= 10;\n        }\n        return Arrays.copyOf(ret, idx);\n    }\n\n    public int atMostNGivenDigitSet(String[] D, int N) {\n        int[] d = new int[D.length];\n        for (int i = 0;i < D.length;i++) {\n            d[i] = Integer.parseInt(D[i]);\n        }\n\n        int[] length = new int[10];\n        length[0] = 1;\n        for (int i = 1;i < 10;i++) {\n            length[i] = length[i - 1] * D.length;\n        }\n\n        int[] a = split(N);\n        int ret = 0;\n        for (int i = 1;i < a.length;i++) {\n            ret += length[i];\n        }\n        int i;\n        for (i = a.length - 1;i >= 0;i--) {\n            boolean find = false;\n            for (int j = 0;j < d.length;j++) {\n                if (a[i] == d[j]) {\n                    find = true;\n                }\n                if (d[j] < a[i]) {\n                    ret += length[i];\n                }\n            }\n            if (!find) {\n                break;\n            }\n        }\n        if (i < 0) {\n            ret++;\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0903._Valid_Permutations_for_DI_Sequence.md",
    "content": "### 903. Valid Permutations for DI Sequence\n\n\n\n题目:\nhttps://leetcode.com/problems/valid-permutations-for-di-sequence\n\n难度:\nHard\n\n题意：\n\n1. 给定一个字符串，长度为n，D代表前一个数比下一个数大而I代表前一个数比下一个数小\n2. 求出在所有0-n的排列中，满足上面字符串所代表的排列两两之间大小比较的排列的个数\n\n思路：\n\n- 最大的那个数，可能出现在下面三种情况：\n  - 出现在位置0，a[0]>a[1]\n  - 出现在位置i，a[i]>a[i+1]且a[i]<a[i-1]\n  - 出现在位置n，a[n]>a[n-1]\n- 枚举最大的数出现的位置，假设为i，当i选定为最大的数后，剩下的数要分配给左右两边，有c(n, i)种情况，并且左右两边的队列互相独立\n- 这时候左右两边分别成了一个命题相同的子问题，求出即可\n- 注意：需要注意的是，不是所有的动态规划都需要用递推的方式求解。这道题可以选择另一种写法，就是递归+缓存，代码量会少不少\n\n代码：\n\n```java\nclass Solution {\n    private static int[][] c;\n    private static int MOD = 1000000007;\n    private static int[][] cache = new int[202][202];\n\n    private void init() {\n        c = new int[202][202];\n        c[0][0] = 1;\n        for (int i = 1;i <= 201;i++) {\n            c[i][0] = 1;\n            for (int j = 1;j < i;j++) {\n                c[i][j] = c[i - 1][j - 1] + c[i - 1][j];\n                if (c[i][j] >= MOD) {\n                    c[i][j] -= MOD;\n                }\n            }\n            c[i][i] = 1;\n        }\n    }\n\n    public int find(String S, int left, int right) {\n        int ret = 0;\n        if (right - left == 0) {\n            return 1;\n        }\n        if (cache[left][right] != -1) {\n            return cache[left][right];\n        }\n        if (S.charAt(left) == 'D') {\n            ret += find(S, left + 1, right);\n            if (ret >= MOD) {\n                ret -= MOD;\n            }\n        }\n        if (S.charAt(right - 1) == 'I') {\n            ret += find(S, left, right - 1);\n            if (ret >= MOD) {\n                ret -= MOD;\n            }\n        }\n        for (int i = left + 1;i < right;i++) {\n            if (S.charAt(i) == 'D' && S.charAt(i - 1) == 'I') {\n                ret += ((long) find(S, left, i - 1) * find(S, i + 1, right) % MOD) * c[right - left][i - left] % MOD;\n                if (ret >= MOD) {\n                    ret -= MOD;\n                }\n            }\n        }\n        if (ret == 0) {\n            return cache[left][right] = 1;\n        }\n        return cache[left][right] = ret;\n    }\n\n    public int numPermsDISequence(String S) {\n        init();\n        for (int i = 0;i < 202;i++) {\n            for (int j = 0;j < 202;j++) {\n                cache[i][j] = -1;\n            }\n        }\n        int ret = find(S, 0, S.length());\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0906._Super_Palindromes.md",
    "content": "### 906. Super Palindromes\n\n\n\n题目:\nhttps://leetcode.com/problems/super-palindromes/\n\n难度:\nHard\n\n题意：\n\n1. 定义超级回文数为，是回文数，并且是回文数的平方\n2. 给定范围[L,R]，求出超级回文数的个数\n\n思路：\n\n- 看数据范围，L和R都在10^18内\n- 令a为其中一个超级回文数，那么a=b*b，b也是一个回文数，由于超级回文数在10^18以内，b的取值范围是10^9以内\n- 由于b是回文数，只有两种情况，如果长度为奇数的话，那么b就是(abcd)x(dcba)，如果长度为偶数的话，那么b就是(abcd)(dcba)，那么小于10^9的回文数个数，不超过11w个\n- 那么这个题的解题方案就是把所有的超级回文数枚举出来\n- 当然要挑战速度的话，注意到超级回文数才70个，写死在代码里面绝对秒杀各种预处理代码\n\n代码：\n\n```java\nclass Solution {\n    private static List<Long> allSuper;\n\n    private int[] split(int a) {\n        int[] ret = new int[10];\n        int idx = 0;\n        while (a != 0) {\n            ret[idx++] = a % 10;\n            a /= 10;\n        }\n        return Arrays.copyOf(ret, idx);\n    }\n\n    private int[] split(long a) {\n        int[] ret = new int[20];\n        int idx = 0;\n        while (a != 0) {\n            ret[idx++] = (int) (a % 10);\n            a /= 10;\n        }\n        return Arrays.copyOf(ret, idx);\n    }\n\n    private int joinToInt(int[] a) {\n        int ret = 0;\n        for (int i = a.length - 1;i >= 0;i--) {\n            ret = ret * 10 + a[i];\n        }\n        return ret;\n    }\n\n    private long joinToLong(int[] a) {\n        long ret = 0;\n        for (int i = a.length - 1;i >= 0;i--) {\n            ret = ret * 10 + a[i];\n        }\n        return ret;\n    }\n\n    private int[] reverse(int[] a) {\n        int[] ret = new int[a.length];\n        for (int i = 0;i < ret.length;i++) {\n            ret[i] = a[ret.length - i - 1];\n        }\n        return ret;\n    }\n\n    private int join(int[] a, int e) {\n        int[] ret = new int[a.length * 2 + 1];\n        for (int i = 0;i < a.length;i++) {\n            ret[i] = a[i];\n        }\n        ret[a.length] = e;\n        a = reverse(a);\n        for (int i = 0;i < a.length;i++) {\n            ret[a.length + i + 1] = a[i];\n        }\n        return joinToInt(ret);\n    }\n\n    private int join(int[] a) {\n        int[] ret = new int[a.length * 2];\n        for (int i = 0;i < a.length;i++) {\n            ret[i] = a[i];\n        }\n        a = reverse(a);\n        for (int i = 0;i < a.length;i++) {\n            ret[a.length + i] = a[i];\n        }\n        return joinToInt(ret);\n    }\n\n    private boolean isPalindrome(int[] a) {\n        int left = 0;\n        int right = a.length - 1;\n        while (right > left) {\n            if (a[right] != a[left]) {\n                return false;\n            }\n            right--;\n            left++;\n        }\n        return true;\n    }\n\n    private void judgeAndAdd(int x) {\n        long t = (long)x * x;\n        if (isPalindrome(split(t))) {\n            allSuper.add(t);\n        }\n    }\n\n    private void init() {\n        allSuper = new ArrayList<Long>();\n        allSuper.add(1L);\n        allSuper.add(4L);\n        allSuper.add(9L);\n        for (int i = 1;i <= 9999;i++) {\n            int[] a = split(i);\n            a = reverse(a);\n            judgeAndAdd(join(a));\n\n            for (int j = 0;j <= 9;j++) {\n                judgeAndAdd(join(a, j));\n            }\n        }\n    }\n\n    public int superpalindromesInRange(String L, String R) {\n        init();\n\n        long l = Long.valueOf(L);\n        long r = Long.valueOf(R);\n\n        int count = 0;\n        for (int i = 0;i < allSuper.size();i++) {\n            if (allSuper.get(i) >= l && allSuper.get(i) <= r) {\n                count++;\n            }\n        }\n        return count;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0913._Cat_and_Mouse.md",
    "content": "### 913. Cat and Mouse\n\n\n\n题目:\nhttps://leetcode.com/problems/cat-and-mouse/\n\n难度:\nHard\n\n题意：\n\n1. 给定一张图，猫和鼠轮流走动，每一次可以走到当前点的下一个节点\n2. 猫胜利的条件是猫和老鼠在同一个位置\n3. 老鼠胜利的条件是到达0号节点\n4. 如果猫和老鼠所到达的状态是先前他们走过的状态，则平局\n5. 猫和鼠都是选择对它们最优的策略走\n\n思路：\n\n- 零和博弈\n- 轮到猫走的时候，猫会选择一个状态，使得这个状态下猫必胜利\n- 如果找不到一个子状态必胜，那么猫会找一个平局的状态进行游戏\n- 如果找不到一个必胜和一个平局的状态，那么这个状态下只能鼠胜出\n- 轮到鼠走时也是如此\n- 令状态表达式是`f[first][cat][mouse]`表示猫或者鼠先走时，猫在cat的位置，鼠在mouse的位置的状态，状态值是猫(2)或鼠(1)胜利，或者平局(0)\n- 根据博弈的条件，可以得出状态转移公式和初始状态\n- 这个题最难的地方不在公式，而是无子问题。无法用递推或者递归的方式解决问题。借助一下最短路松弛算法，我们可以从初始状态出发，然后影响周边状态，假设某个状态值改变了，需要对这个状态的周边状态进行重新计算，直到收敛\n\n代码：\n\n```java\nclass Solution {\n\tprivate class Node {\n        int first;\n        int mouse;\n        int cat;\n\n        public Node(int first, int cat, int mouse) {\n            this.first = first;\n            this.mouse = mouse;\n            this.cat = cat;\n        }\n\n        public int getFirst() {\n            return first;\n        }\n\n        public void setFirst(int first) {\n            this.first = first;\n        }\n\n        public int getMouse() {\n            return mouse;\n        }\n\n        public void setMouse(int mouse) {\n            this.mouse = mouse;\n        }\n\n        public int getCat() {\n            return cat;\n        }\n\n        public void setCat(int cat) {\n            this.cat = cat;\n        }\n    }\n\n    private int solve(int[][] graph) {\n        int[][][] cache = new int[2][graph.length][graph.length];\n        for (int first = 0;first < 2;first++) {\n            for (int cat = 0;cat < graph.length;cat++) {\n                for (int mouse = 0;mouse < graph.length;mouse++) {\n                    cache[first][cat][mouse] = 0;\n                }\n            }\n        }\n\n        Queue<Node> nodes = new LinkedList<>();\n\n        for (int first = 0;first < 2;first++) {\n            for (int cat = 1; cat < graph.length; cat++) {\n                for (int mouse = 0; mouse < graph.length; mouse++) {\n                    if (mouse == 0) {\n                        cache[first][cat][mouse] = 1;\n                        nodes.add(new Node(first, cat, mouse));\n                    }\n                    if (cat == mouse) {\n                        cache[first][cat][mouse] = 2;\n                        nodes.add(new Node(first, cat, mouse));\n                    }\n                }\n            }\n        }\n\n        while (!nodes.isEmpty()) {\n            Node node = nodes.poll();\n\n            if (node.first == 0) {\n                for (int i = 0;i < graph[node.mouse].length;i++) {\n                    int x = graph[node.mouse][i];\n\n                    int pre = cache[1][node.cat][x];\n                    if (x == 0 || node.cat == x) {\n                        continue;\n                    }\n\n                    boolean findWin = false;\n                    boolean findDraw = false;\n                    for (int j = 0;j < graph[x].length;j++) {\n                        int y = graph[x][j];\n                        if (cache[0][node.cat][y] == 1) {\n                            findWin = true;\n                        } else if (cache[0][node.cat][y] == 0) {\n                            findDraw = true;\n                        }\n                    }\n                    if (findWin) {\n                        cache[1][node.cat][x] = 1;\n                    } else if (!findDraw) {\n                        cache[1][node.cat][x] = 2;\n                    } else {\n                        cache[1][node.cat][x] = 0;\n                    }\n\n                    if (cache[1][node.cat][x] != pre) {\n                        nodes.add(new Node(1, node.cat, x));\n                    }\n                }\n            } else {\n                for (int i = 0;i < graph[node.cat].length;i++) {\n                    int x = graph[node.cat][i];\n\n                    int pre = cache[0][x][node.mouse];\n\n                    if (x == 0 || node.mouse == x) {\n                        continue;\n                    }\n\n                    boolean findWin = false;\n                    boolean findDraw = false;\n                    for (int j = 0;j < graph[x].length;j++) {\n                        int y = graph[x][j];\n                        if (y == 0) {\n                            continue;\n                        }\n                        if (cache[1][y][node.mouse] == 2) {\n                            findWin = true;\n                        } else if (cache[1][y][node.mouse] == 0) {\n                            findDraw = true;\n                        }\n                    }\n                    if (findWin) {\n                        cache[0][x][node.mouse] = 2;\n                    } else if (!findDraw) {\n                        cache[0][x][node.mouse] = 1;\n                    } else {\n                        cache[0][x][node.mouse] = 0;\n                    }\n\n                    if (pre != cache[0][x][node.mouse]) {\n                        nodes.add(new Node(0, x, node.mouse));\n                    }\n                }\n            }\n        }\n\n        return cache[1][2][1];\n    }\n\n    public int catMouseGame(int[][] graph) {\n        int ret = solve(graph);\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/0920._Number_of_Music_Playlists.md",
    "content": "### 920. Number of Music Playlists\n\n\n\n题目:\nhttps://leetcode.com/problems/number-of-music-playlists\n\n难度:\nHard\n\n题意：\n\n1. 排一张长度为L首的有顺序的歌单，有N首歌可以选择\n2. 每N首歌必须出现一次\n3. 两个相同的歌必须隔K首歌才能再次出现\n4. 问有多少种排列方式\n\n思路：\n\n- 排列组合的题目，最重要的是找准排列方向，避免计算重复\n- 先解决第一个条件，每首歌必须出现一次，那么我们先把N首歌放进歌单中，不管顺序先\n- 我们假定已经把N首歌放进歌单，那么其他的位置就随意放，只要满足相同的歌必须隔K个位置\n- 为了避免计算重复，我们规定，这N首歌不管是放在什么位置，都是这首歌在歌单的第一次出现\n- 剩下的就是动态规划了。定义`dp[l][n]`为歌单的前l个位置中，填入了n首唯一的歌\n- 状态转移有两种情况，\n  - 这个位置已经有歌放进来了(因为我们事先填入了N首歌)，排序方式为`dp[l-1][n-1]`\n  - 这个位置没有歌放进来。由于我们的设定，这个位置只能有n首歌选择（因为其他歌还没有第一次出现在歌单）。注意有隔K首歌的问题，前面有K首歌不能选，这K首歌还不一样，为什么呢，因为这K首歌里面，两两之间肯定相隔小于K。所以只有n-k首歌选择，排序方式为`dp[l-1][n-1]*(n-K)`\n- 由于我们事先把N首歌放进去，这N首歌肯定会有顺序排列。于是最后的结果就等于`dp[L][N]*n!`\n\n代码：\n\n```java\nclass Solution {\n\tprivate static int MOD = 1000000007;\n\n    public int numMusicPlaylists(int N, int L, int K) {\n        int[][] dp = new int[L + 1][N + 1];\n        dp[0][0] = 1;\n        for (int i = 1;i <= N;i++) {\n            dp[0][i] = 0;\n        }\n        for (int i = 1;i <= L;i++) {\n            dp[i][0] = 0;\n            for (int j = 1;j <= N;j++) {\n                int p = j - Math.min(i - 1, K);\n                if (p < 0) {\n                    p = 0;\n                }\n                dp[i][j] = (int) ((long)dp[i - 1][j] * p % MOD);\n                dp[i][j] += dp[i - 1][j - 1];\n                if (dp[i][j] >= MOD) {\n                    dp[i][j] -= MOD;\n                }\n            }\n        }\n        int ret = dp[L][N];\n        for (int i = 1;i <= N;i++) {\n            ret = (int) ((long) ret * i % MOD);\n        }\n        return ret;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/java/README.md",
    "content": "# Leetcode Java 题解"
  },
  {
    "path": "docs/leetcode/java/SUMMARY.md",
    "content": "+   [Leetcode Java 题解](README.md)\n+   [1. Two Sum](0001._Two_Sum.md)\n+   [2. Add Two Numbers](0002._add_two_numbers.md)\n+   [3. Longest Substring Without Repeating Characters](0003._Longest_Substring_Without_Repeating_Characters.md)\n+   [4. Median of Two Sorted Arrays](0004._Median_of_Two_Sorted_Arrays.md)\n+   [5. Longest Palindromic Substring](0005._Longest_Palindromic_Substring.md)\n+   [6. ZigZag Conversion](0006._ZigZag_Conversion.md)\n+   [7. Reverse Integer](0007._Reverse_Integer.md)\n+   [23. Merge K Sorted Lists](0023._Merge_K_Sorted_Lists.md)\n+   [141. Linked List Cycle](0141._linked_list_cycle.md)\n+   [218. The Skyline Problem](0218._The_Skyline_Problem.md)\n+   [238. Product of Array Except Self](0238._product_of_array_except_self.md)\n+   [342. Power of Four](0342._Power_of_Four.md)\n+   [403. Frog Jump](0403._Frog_Jump.md)\n+   [757. Set Intersection Size At Least Two](0757._Set_Intersection_Size_At_Least_Two.md)\n+   [768. Max Chunks To Make Sorted II](0768._Max_Chunks_To_Make_Sorted_II.md)\n+   [780. Reaching Points](0780._Reaching_Points.md)\n+   [793. Preimage Size of Factorial Zeroes Function](0793._Preimage_Size_of_Factorial_Zeroes_Function.md)\n+   [827. Making A Large Island](0827._Making_A_Large_Island.md)\n+   [828. Unique Letter String](0828._Unique_Letter_String.md)\n+   [834. Sum of Distances in Tree](0834._Sum_of_Distances_in_Tree.md)\n+   [843. Guess the Word](0843._Guess_the_Word.md)\n+   [847. Shortest Path Visiting All Nodes](0847._Shortest_Path_Visiting_All_Nodes.md)\n+   [850. Rectangle Area II](0850._Rectangle_Area_II.md)\n+   [854. K-Similar Strings](0854._K-Similar_Strings.md)\n+   [857. Minimum Cost to Hire K Workers](0857._Minimum_Cost_to_Hire_K_Workers.md)\n+   [862. Shortest Subarray with Sum at Least K](0862._Shortest_Subarray_with_Sum_at_Least_K.md)\n+   [864. Shortest Path to Get All Keys](0864._Shortest_Path_to_Get_All_Keys.md)\n+   [871. Minimum Number of Refueling Stops](0871._Minimum_Number_of_Refueling_Stops.md)\n+   [878. Nth Magical Number](0878._Nth_Magical_Number.md)\n+   [879. Profitable Schemes](0879._Profitable_Schemes.md)\n+   [899. Reachable Nodes In Subdivided Graph](0882._Reachable_Nodes_In_Subdivided_Graph.md)\n+   [887. Super Egg Drop](0887._Super_Egg_Drop.md)\n+   [891. Sum of Subsequence Widths](0891._Sum_of_Subsequence_Widths.md)\n+   [895. Maximum Frequency Stack](0895._Maximum_Frequency_Stack.md)\n+   [899. Orderly Queue](0899._Orderly_Queue.md)\n+   [902. Numbers At Most N Given Digit Set](0902._Numbers_At_Most_N_Given_Digit_Set.md)\n+   [903. Valid Permutations for DI Sequence](0903._Valid_Permutations_for_DI_Sequence.md)\n+   [906. Super Palindromes](0906._Super_Palindromes.md)\n+   [913. Cat and Mouse](0913._Cat_and_Mouse.md)\n+   [920. Number of Music Playlists](0920._Number_of_Music_Playlists.md)"
  },
  {
    "path": "docs/leetcode/javascript/0001._Two_Sum.md",
    "content": "# 001. Two Sum\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/two-sum\n\n> 内容描述\n\n```\nGiven an array of integers, return indices of the two numbers such that they add up to a specific target.\n\nYou may assume that each input would have exactly one solution, and you may not use the same element twice.\n\nExample:\n\nGiven nums = [2, 7, 11, 15], target = 9,\n\nBecause nums[0] + nums[1] = 2 + 7 = 9,\nreturn [0, 1].\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n算法来源于知乎文章——[趣味算法思想](https://zhuanlan.zhihu.com/p/46223775)\n\n先定义一个Object类型的数据结构obj，它的key为target - numbers[i]（比如数组第一项为2），value为索引。然后每次都看看obj[numbers[i]] 是否存在，如果存在，那我们就找到了这样的一组数据，返回当前索引以及obj[numbers[i]]。\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @param {number} target\n * @return {number[]}\n */\nvar twoSum = function(nums, target) {\n   var obj = {};\n\n  for(var i=0; i< nums.length;i++) {\n    const item = nums[i];\n    if(obj[item] >= 0) {\n      return [obj[item], i]\n    } else {\n      obj[target - item] = i;\n    }\n  }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0002._Add_Two_Numbers.md",
    "content": "# 002. Add Two Numbers\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/add-two-numbers\n\n> 内容描述\n\nYou are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.\n\nYou may assume the two numbers do not contain any leading zero, except the number 0 itself.\n\n\n#### Example:\n    \n    Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)\n    Output: 7 -> 0 -> 8\n    Explanation: 342 + 465 = 807.\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(max(m,n))******- 空间复杂度: O(max(m,n))******\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} l1\n * @param {ListNode} l2\n * @return {ListNode}\n */\nlet addTwoNumbers = function (l1,l2) {\n    let result = new ListNode(0),\n        node = result;\n    while(l1 || l2){\n        let r = node.val,\n            i = (l1 && l1.val) || 0,\n            j = (l2 && l2.val) || 0,\n            sum = r + i + j,\n            m,n;\n        if(sum >= 10){\n            m = 1;\n            n = sum - 10;\n        }else{\n            m = 0;\n            n = sum;\n        }\n        l1 = l1 && l1.next;\n        l2 = l2 && l2.next;\n        node.val = n;\n        if(m || l1 || l2){\n            node.next = new ListNode(m);\n            node = node.next\n        }\n    }\n    return result;\n};\n\nfunction ListNode(val) {\n    this.val = val;\n    this.next = null;\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0003._Longest_Substring_without_Repeating_Characters.md",
    "content": "# 003. Longest Substring Without Repeating Characters\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/longest-substring-without-repeating-characters/\n\n> 内容描述\n\n```\nGiven a string, find the length of the longest substring without repeating characters.\n\nExample 1:\n\nInput: \"abcabcbb\"\nOutput: 3 \nExplanation: The answer is \"abc\", with the length of 3. \nExample 2:\n\nInput: \"bbbbb\"\nOutput: 1\nExplanation: The answer is \"b\", with the length of 1.\nExample 3:\n\nInput: \"pwwkew\"\nOutput: 3\nExplanation: The answer is \"wke\", with the length of 3. \n             Note that the answer must be a substring, \"pwke\" is a subsequence and not a substring.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)******\n\n#### 暴力解法\n\n代码：\n\n```javascript\n/**\n * @param {string} s\n * @return {number}\n */\nlet lengthOfLongestSubstring = function (s) {\n    let result = 0;\n    for (let i = 0, len = s.length; i < len; i++) {\n        let set = new Set();\n        set.add(s.charAt(i));\n        for (let j = i + 1; j < len; j++) {\n            if (set.has(s.charAt(j))) {\n                break;\n            }\n            set.add(s.charAt(j));\n        }\n        result = Math.max(result,set.size);\n    }\n    return result;\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0005._Longest_Palindromic_Substring.md",
    "content": "# 0005. Longest Palindromic Substring\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n[https://leetcode-cn.com/problems/longest-palindromic-substring/](https://leetcode-cn.com/problems/longest-palindromic-substring/)\n\n> 内容描述\n\n给定一个字符串 `s`，找到 `s` 中最长的回文子串。你可以假设 `s` 的最大长度为 1000。\n\n#### 示例1:\n     \n     输入: \"babad\"\n     输出: \"bab\"\n     注意: \"aba\" 也是一个有效答案。\n\n\n#### 示例2:\n     \n     输入: \"cbbd\"\n     输出: \"bb\"\n     \n     \n#### 进阶:\n\n如果你已经实现复杂度为 O(n) 的解法，尝试使用更为精妙的分治法求解。\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(N)******- 空间复杂度: O(2N)******\n\n\n解法DP\n\n```javascript\n/**\n * @param {string} s\n * @return {string}\n */\nvar longestPalindrome = function(s) {\n  let len = s.length;\n  if (len < 2) {\n    return s;\n  }\n  \n  dp = Array.from({length:len}).map(() => []);\n\n// 初始化\n  for (let i = 0; i < len; i++) {\n    dp[i][i] = true;\n  }\n  \n  let maxLen = 1;\n  let start = 0;\n  \n  for (let j = 1; j < len; j++) {\n    for (let i = 0; i < j; i++) {\n      \n      if (s[i] === s[j]) {\n        if (j - i < 3) {\n          dp[i][j] = true;\n        } else {\n          dp[i][j] = dp[i + 1][j - 1];\n        }\n      } else {\n        dp[i][j] = false;\n      }\n      \n      if (dp[i][j]) {\n        let curLen = j - i + 1;\n        if (curLen > maxLen) {\n          maxLen = curLen;\n          start = i;\n        }\n      }\n    }\n  }\n  return s.substring(start, start + maxLen)\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0007._Reverse_Integer.md",
    "content": "# 007. Reverse Integer\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/reverse-integer\n\n> 内容描述\n\nGiven a 32-bit signed integer, reverse digits of an integer.\n\n#### Example 1:\n     \n     Input: 123\n     Output: 321\n\n#### Example 2:\n     \n     Input: -123\n     Output: -321\n     \n#### Example 3:\n     \n     Input: 120\n     Output: 21\n\n#### Note:\n     Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231,  231 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(1)******- 空间复杂度: O(N)******\n\n#### 思路：通过将数字转成数组，然后翻转再转回数字\n\n代码：\n\n```javascript\n/**\n * @param {number} x\n * @return {number}\n */\nvar reverse = function(x) {\n    var num = parseInt(x.toString().split('').reverse().join(''))\n    if(num > Math.pow(2, 31)) {\n        return 0\n    }\n    if(x < 0){\n        return num*(-1)\n    } else {\n        return num\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0008._String_to_Integer.md",
    "content": "# 008. String to Integer (atoi)\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/string-to-integer-atoi\n\n> 内容描述\n\n```\nImplement atoi which converts a string to an integer.\n\nThe function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.\n\nThe string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.\n\nIf the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.\n\nIf no valid conversion could be performed, a zero value is returned.\n\nNote:\n\nOnly the space character ' ' is considered as whitespace character.\nAssume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231,  231 − 1]. If the numerical value is out of the range of representable values, INT_MAX (231 − 1) or INT_MIN (−231) is returned.\n\n```\n#### Example 1:\n```\nInput: \"42\"\nOutput: 42\n```\n\n#### Example 2:\n```\nInput: \"   -42\"\nOutput: -42\nExplanation: The first non-whitespace character is '-', which is the minus sign.\n             Then take as many numerical digits as possible, which gets 42.\n\n```\n#### Example 3:\n```\nInput: \"4193 with words\"\nOutput: 4193\nExplanation: Conversion stops at digit '3' as the next character is not a numerical digit.\n```\n\n#### Example 4:\n```\nInput: \"words and 987\"\nOutput: 0\nExplanation: The first non-whitespace character is 'w', which is not a numerical \n             digit or a +/- sign. Therefore no valid conversion could be performed.\n\n```\n\n#### Example 5:\n```\nInput: \"-91283472332\"\nOutput: -2147483648\nExplanation: The number \"-91283472332\" is out of the range of a 32-bit signed integer.\n             Thefore INT_MIN (−231) is returned.\n\n```\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(1)******- 空间复杂度: O(N)******\n\n代码：\n\n```javascript\n/**\n * @param {string} str\n * @return {number}\n */\nvar myAtoi = function(str) {\n    const INT_MAX = 2 ** 31 - 1;\n    const INT_MIN = -(2 ** 31);\n    str = str.match(/^\\s*([-+]?\\d+)/);\n    let strNum = str ? Number(str[0]) : 0;\n    if(strNum < INT_MIN ){\n        return INT_MIN\n    }else if(strNum > INT_MAX){\n        return INT_MAX\n    }else{\n        return strNum\n    }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0009._Palindrome_Number.md",
    "content": "# 9. Palindrome Number\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/palindrome-number\n\n> 内容描述\n\n```\nDetermine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.\n\nExample 1:\n\nInput: 121\nOutput: true\nExample 2:\n\nInput: -121\nOutput: false\nExplanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.\nExample 3:\n\nInput: 10\nOutput: false\nExplanation: Reads 01 from right to left. Therefore it is not a palindrome.\nFollow up:\n\nCoud you solve it without converting the integer to a string?\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(log2 N)******- 空间复杂度: O(1)******\n\n* 不使用字符串,使用除法分别从首尾获得数字，最后对比是否相同\n\n代码：\n\n```javascript\n/**\n * @param {number} x\n * @return {boolean}\n */\nvar isPalindrome = function(x) {\n    if(x<0||x!==0&&x%10===0)\n        return false;\n    var reverse = 0;\n    while (x>reverse){\n        reverse = reverse*10 +x%10;\n        x = Math.floor(x/10);\n    }\n    return reverse === x||Math.floor(reverse/10) === x;\n};\n```\n\n> 思路 2\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* 转化为字符串，reverse字符串\n\n代码：\n\n```javascript\nvar isPalindrome = function(x) {\n    return x.toString().split('').reverse().join('')==x.toString()?true:false;\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0011._Container_With_Most_Water.md",
    "content": "# 11. Container With Most Water\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/container-with-most-water\n\n> 内容描述\n\n```\nGiven n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.\n\nNote: You may not slant the container and n is at least 2.\n```\n![img](https://s3-lc-upload.s3.amazonaws.com/uploads/2018/07/17/question_11.jpg)\n```\nThe above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.\n```\n\n```\nExample:\n\nInput: [1,8,6,2,5,4,8,3,7]\nOutput: 49\n```\n\n## 解题方案\n\n> 对撞指针\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n* 从数组两层对向查找，直到找到最大乘积\n\n代码：\n\n```javascript\nvar maxArea = function (list) {\n    let i = 0,j = list.length -1,result = 0;\n    while(i < j){\n        result = Math.max(result ,(j - i ) * Math.min(list[i],list[j]))\n        if(list[i] < list[j]){\n            i++;\n        }else{\n            j--;\n        }\n    }\n    return result;\n};\n```\n\n> 暴力解法\n******- 时间复杂度: O(N²)******- 空间复杂度: O(1)******\n\n代码\n\n```javascript\nvar maxArea = function (list) {\n    let result = 0;\n    for(let i = 0,len = list.length; i<len; i++){\n        for(let j = i+1; j<len; j++){\n            let x = (j - i);\n            let y = Math.min(list[i],list[j]);\n            result = Math.max(result,x*y)\n        }\n    }\n    return result;\n};\n```"
  },
  {
    "path": "docs/leetcode/javascript/0012._Integer_To_Roman.md",
    "content": "# 12. Integer to Roman\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/integer-to-roman\n\n> 内容描述\n\nRoman numerals are represented by seven different symbols: `I`, `V`, `X`, `L`, `C`, `D` and `M`.\n```\nSymbol       Value\nI             1\nV             5\nX             10\nL             50\nC             100\nD             500\nM             1000\n```\n\nFor example, two is written as `II` in Roman numeral, just two one's added together. Twelve is written as, `XII`, which is simply `X` + `II`. The number twenty seven is written as `XXVII`, which is `XX` + `V` + `II`.\n\nRoman numerals are usually written largest to smallest from left to right. However, the numeral for four is not `IIII`. Instead, the number four is written as `IV`. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as `IX`. There are six instances where subtraction is used:\n * `I` can be placed before `V` (5) and `X` (10) to make 4 and 9. \n * `X` can be placed before `L` (50) and `C` (100) to make 40 and 90. \n * `C` can be placed before `D` (500) and `M` (1000) to make 400 and 900.\n\nGiven an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999.\n\n##### Example 1:\n```\nInput: 3\nOutput: \"III\"\n```\n\n##### Example 2:\n```\nInput: 4\nOutput: \"IV\"\n```\n\n##### Example 3:\n```\nInput: 9\nOutput: \"IX\"\n```\n\n##### Example 4:\n```\nInput: 58\nOutput: \"LVIII\"\nExplanation: L = 50, V = 5, III = 3.\n```\n\n##### Example 5:\n```\nInput: 1994\nOutput: \"MCMXCIV\"\nExplanation: M = 1000, CM = 900, XC = 90 and IV = 4.\n```\n\n\n## 解题方案\n\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n\n代码：\n\n```javascript\nlet getMap = function () {\n    return {\n        1:'I',\n        4:'IV',\n        5:'V',\n        9:'IX',\n        10:'X',\n        40:'XL',\n        50:'L',\n        90:'XC',\n        100:'C',\n        400:'CD',\n        500:'D',\n        900:'CM',\n        1000:'M'\n    };\n};\n\nlet match = function (result,num) {\n    let obj = getMap();\n    while (result.num >= num){\n        let n = parseInt(result.num /num);\n        result.num = result.num % num;\n        result.str = result.str + obj[num].repeat(n);\n    }\n};\n\n/**\n * @param {number} num\n * @return {string}\n */\nvar intToRoman = function (num) {\n    if(num < 1 || num > 3999) throw Error('error');\n    let obj = getMap();\n    if(num in obj) return obj[num];\n    let result = {\n        str:'',\n        num\n    };\n    match(result,1000);\n    match(result,900);\n    match(result,500);\n    match(result,400);\n    match(result,100);\n    match(result,90);\n    match(result,50);\n    match(result,40);\n    match(result,10);\n    match(result,9);\n    match(result,5);\n    match(result,4);\n    match(result,1);\n\n    return result.str;\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0013._Roman_To_Integer.md",
    "content": "# 13. Roman to Integer\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/roman-to-integer\n\n> 内容描述\n\nRoman numerals are represented by seven different symbols: `I`, `V`, `X`, `L`, `C`, `D` and `M`.\n```\nSymbol       Value\nI             1\nV             5\nX             10\nL             50\nC             100\nD             500\nM             1000\n```\n\nFor example, two is written as `II` in Roman numeral, just two one's added together. Twelve is written as, `XII`, which is simply `X` + `II`. The number twenty seven is written as `XXVII`, which is `XX` + `V` + `II`.\n\nRoman numerals are usually written largest to smallest from left to right. However, the numeral for four is not `IIII`. Instead, the number four is written as `IV`. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as `IX`. There are six instances where subtraction is used:\n * `I` can be placed before `V` (5) and `X` (10) to make 4 and 9. \n * `X` can be placed before `L` (50) and `C` (100) to make 40 and 90. \n * `C` can be placed before `D` (500) and `M` (1000) to make 400 and 900.\n\nGiven a roman numeral, convert it to an integer. Input is guaranteed to be within the range from `1` to `3999`.\n\n##### Example 1:\n```\nInput: \"III\"\nOutput: 3\n```\n\n##### Example 2:\n```\nInput: \"IV\"\nOutput: 4\n```\n\n##### Example 3:\n```\nInput: \"IX\"\nOutput: 9\n```\n\n##### Example 4:\n```\nInput: \"LVIII\"\nOutput: 58\nExplanation: L = 50, V= 5, III = 3.\n```\n\n##### Example 5:\n```\nInput: \"MCMXCIV\"\nOutput: 1994\nExplanation: M = 1000, CM = 900, XC = 90 and IV = 4.\n```\n\n\n## 解题方案\n\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n\n代码：\n\n```javascript\n/**\n * @param {string} roman\n * @return {number}\n */\nlet romanToInt = function (roman) {\n    let result = 0;\n    let obj = {\n        'I':1,\n        'IV':4,\n        'V':5,\n        'IX':9,\n        'X':10,\n        'XL':40,\n        'L':50,\n        'XC':90,\n        'C':100,\n        'CD':400,\n        'D':500,\n        'CM':900,\n        'M':1000\n    };\n    for(let len = roman.length,i = len -1;i>=0; i--){\n       if(i - 1 >= 0 && `${roman.charAt(i - 1)}${roman.charAt(i)}` in obj){\n           result = result + obj[`${roman.charAt(i - 1)}${roman.charAt(i)}`];\n           i--;\n       }else{\n           result = result + obj[roman.charAt(i)];\n       }\n    }\n    return result;\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0014._Longest_Common_Prefix.md",
    "content": "# 014. Longest Common Prefix\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/two-sum\n\n> 内容描述\n\nWrite a function to find the longest common prefix string amongst an array of strings.\n\nIf there is no common prefix, return an empty string `\"\"`.\n\n#### Example 1:\n```markdown\nInput: [\"flower\",\"flow\",\"flight\"]\nOutput: \"fl\"\n```\n\n#### Example 2:\n```markdown\nInput: [\"dog\",\"racecar\",\"car\"]\nOutput: \"\"\nExplanation: There is no common prefix among the input strings.\n```\n\n##### Note:\nAll given inputs are in lowercase letters `a-z`.\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n\n代码：\n\n```javascript\n/**\n * @param {string[]} strs\n * @return {string}\n */\nlet longestCommonPrefix = function(strs) {\n    let firstStr = strs[0];\n    let result ='';\n    if(!strs.length){\n        return result;\n    }\n    for (let i = 0; i < firstStr.length; i++) {\n        for (let j =  1; j < strs.length; j++) {\n            if(firstStr.charAt(i) !== strs[j].charAt(i)){\n                return result;\n            }\n        }\n        result = result + firstStr.charAt(i);\n    }\n    return result;\n\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0015._Three_Sum.md",
    "content": "# 015. 3Sum\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/3sum\n\n> 内容描述\n\nGiven an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.\n\n#### Note:\n     \n     The solution set must not contain duplicate triplets.\n\n#### Example:\n     \n     Given array nums = [-1, 0, 1, 2, -1, -4],\n     \n     A solution set is:\n     [\n       [-1, 0, 1],\n       [-1, -1, 2]\n     ]\n\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(N²)******- 空间复杂度: O(N)******\n\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @return {number[][]}\n */\nlet threeSum = function(nums, n = 0) {\n    let result = [];\n    let len = nums.length;\n    if(!len) return result;\n    // 对数组进行排序\n    nums.sort((a,b)=>a-b);\n    for(let k = 0; k<len; k++){\n        //重复的元素则结果也一样，所以跳过该循环\n        if(k>0 && nums[k-1] === nums[k]){\n            continue;\n        }\n        let target = n - nums[k];\n        let i = k + 1;\n        let j = len -1;\n        while(i<j){\n            if(nums[i] + nums[j] === target){\n                result.push([nums[k],nums[i],nums[j]]);\n                while (i<j && nums[i] === nums[i+1]) i++;\n                while (i<j && nums[j] === nums[j-1]) j--;\n                i++;\n                j--;\n            }else if(nums[i] + nums[j] > target){\n                j--;\n            }else{\n                i++\n            }\n        }\n    }\n    return result;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0016._3_Sum_Closest.md",
    "content": "# 016. 3Sum Closest\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/3sum-closest\n\n> 内容描述\n\nGiven an array `nums` of n integers and an integer `target`, find three integers in `nums` such that the sum is closest to `target`. Return the sum of the three integers. You may assume that each input would have exactly one solution.\n\n#### Example:\n     \n     Given array nums = [-1, 2, 1, -4], and target = 1.\n     \n     The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(N²)******- 空间复杂度: O(N)******\n\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @param {number} target\n * @return {number}\n */\nvar threeSumClosest = function(nums, target) {\n    let result = Infinity;\n    let len = nums.length;\n    if(len <= 3){\n        return nums.reduce((a,b)=>a+b,0);\n    }\n    nums.sort((a,b)=>a-b);\n    for(let k = 0; k<len-2; k++){\n        if(k>0 && nums[k-1] === nums[k]){\n            continue;\n        }\n        let i = k + 1;\n        let j = len -1;\n        while(i<j){\n            let count = nums[k] + nums[i] + nums[j];\n            if(count === target){\n                return target;\n            }\n            if(Math.abs(result - target) > Math.abs(count - target)){\n                result = count;\n            }\n            if(count > target){\n                j--\n            }else{\n                i ++\n            }\n        }\n    }\n    return result;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0017._Letter_Combinations_Of_A_Phone_Number.md",
    "content": "# 017. Letter Combinations of a Phone Number\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/letter-combinations-of-a-phone-number/\n\n> 内容描述\n\nGiven a string containing digits from `2-9` inclusive, return all possible letter combinations that the number could represent.\n\nA mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.\n\n![img](http://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Telephone-keypad2.svg/200px-Telephone-keypad2.svg.png)\n\n#### Example:\n     \n     Input: \"23\"\n     Output: [\"ad\", \"ae\", \"af\", \"bd\", \"be\", \"bf\", \"cd\", \"ce\", \"cf\"].\n     \n#### Note:\nAlthough the above answer is in lexicographical order, your answer could be in any order you want.\n\n\n## 解题方案\n\n> 递归版本\n******- 时间复杂度: O(N²)******- 空间复杂度: O(N)******\n\n代码：\n\n```javascript\n/**\n * 递归函数\n * @param digits 传入的数字\n * @param index 当前是第几个数字\n * @param str 当前已拼装的字符串\n * @param list 结果集\n */\nlet helper = function (digits, index, str, list) {\n    let map = {\n        2: 'abc',\n        3: 'def',\n        4: 'ghi',\n        5: 'jkl',\n        6: 'mno',\n        7: 'pqrs',\n        8: 'tuv',\n        9: 'wxyz'\n    };\n    if (str.length === digits.length) {\n        list.push(str);\n        return false;\n    }\n    let strs = map[digits[index]];\n    for (let i = 0; i < strs.length; i++) {\n        helper(digits, index + 1, str + strs.charAt(i), list)\n    }\n};\nlet letterCombinations = function (digits) {\n    let list = [];\n    if (digits) {\n        helper(digits, 0, '', list);\n    }\n    return list;\n};\n```\n\n> 非递归版本\n******- 时间复杂度: O(N²)******- 空间复杂度: O(N)******\n\n```javascript\n/**\n * @param {string} digits\n * @return {string[]}\n */\nlet letterCombinations = function (digits) {\n   let map = {\n       2: 'abc',\n       3: 'def',\n       4: 'ghi',\n       5: 'jkl',\n       6: 'mno',\n       7: 'pqrs',\n       8: 'tuv',\n       9: 'wxyz'\n   };\n   let res = [];\n   for(let i = 0,len = digits.length; i<len; i++){\n       let str = map[digits.charAt(i)];\n       if(!res.length){\n           for(let i = 0,len = str.length; i<len; i++){\n               res.push(str.charAt(i));\n           }\n       }else{\n           let r = [];\n           for(let j = 0,length = res.length; j<length; j++){\n               for(let i = 0,len = str.length; i<len; i++){\n                   r.push(res[j] + str.charAt(i));\n               }\n           }\n           res = r;\n       }\n   }\n   return res;\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0019._Remove_Nth_Node_From_End_Of_List.md",
    "content": "# 019. Remove Nth Node From End Of List\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/\n\n> 内容描述\n\n给定一个链表，删除链表的倒数第 n 个节点，并且返回链表的头结点。\n\n示例：\n\n     给定一个链表: 1->2->3->4->5, 和 n = 2.\n\n     当删除了倒数第二个节点后，链表变为 1->2->3->5.\n说明：\n\n给定的 n 保证是有效的。\n\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n转化为数组，通过数组下标来确定删除的节点\n代码：\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @param {number} n\n * @return {ListNode}\n */\nvar removeNthFromEnd = function(head, n) {\n    if (!head || n === 0) {\n        return head;\n    }\n    const list = [];\n    let cur = head;\n    while (cur) {\n        list.push(cur);\n        cur = cur.next;\n    }\n    const index = list.length - n;\n\n    if (list.length === 1 && n === 1) {\n        return null;\n    }\n\n    if (index === 0) {\n        return list[1]\n    } else {\n        list[index-1].next = list[index+1];\n        return list[0];\n    }\n};\n```\n\n\n> 思路2 \n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n使用快慢指针的方式，先让fast走n步，再让slow开始和fast一起走，当fast走完的时候，就是slow走到了正确的位置。\n\n```javascript\nvar removeNthFromEnd = function(head, n) {\n    if (!head || n === 0) {\n        return head;\n    }\n    let dummy = new ListNode(-1);\n    dummy.next = head;\n    let fast = dummy;\n    let slow = dummy;\n    Array.from(({length:n+1})).forEach(() => {\n        fast = fast.next;\n    })\n    while(fast) {\n        fast = fast.next;\n        slow = slow.next;\n    }\n    slow.next = slow.next.next;\n    return dummy.next;\n};\n\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0020._Valid_Parentheses.md",
    "content": "# 020. Valid Parentheses\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/two-sum\n\n> 内容描述\n\n```\nGiven a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.\n\nAn input string is valid if:\n\nOpen brackets must be closed by the same type of brackets.\nOpen brackets must be closed in the correct order.\nNote that an empty string is also considered valid.\n```\n\n#### Example 1:\n```bash\nInput: \"()\"\nOutput: true\n```\n\n#### Example 2:\n```bash\nInput: \"()[]{}\"\nOutput: true\n```\n\n#### Example 3:\n```bash\nInput: \"(]\"\nOutput: false\n```\n\n#### Example 4:\n```bash\nInput: \"([)]\"\nOutput: false\n```\n\n#### Example 5:\n```bash\nInput: \"{[]}\"\nOutput: true\n```\n\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n代码：\n\n```javascript\n/**\n * @param {string} s\n * @return {boolean}\n */\nvar isValid = function(s) {\n        if(!s){\n            return true;\n        }\n        let array = [];\n        for(let i = 0,len = s.length; i<len; i++){\n            let cur = s.charAt(i);\n            if(cur === '(' || cur === '{' || cur === '['){\n                array.push(cur);\n            }else if(!array.length){\n                return false;\n            }else{\n                let pre = array.pop();\n                if(pre === '(' && cur !== ')'){\n                    return false;\n                }\n                if(pre === '{' && cur !== '}'){\n                    return false;\n                }\n                if(pre === '[' && cur !== ']'){\n                    return false;\n                }\n            }\n        }\n        return !array.length\n    };\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0021._Merge_Two_Sorted_Lists.md",
    "content": "# 021. Merge Two Sorted Lists\n\n**<font color=green>难度: Easy</font>**\n\n> 原题连接\n\n* https://leetcode.com/problems/merge-two-sorted-lists/\n\n> 内容描述\n\n```\nMerge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.\n\nExample:\n\nInput: 1->2->4, 1->3->4\nOutput: 1->1->2->3->4->4\n\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n代码：\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} l1\n * @param {ListNode} l2\n * @return {ListNode}\n */\nvar mergeTwoLists = function(l1, l2) {\n    if(l2 == null) return l1;\n    if(l1 == null) return l2;\n    if(l1.val<l2.val){\n        l1.next = mergeTwoLists(l1.next,l2);\n        return l1;\n    }else{\n        l2.next = mergeTwoLists(l2.next,l1);\n        return l2;\n    }\n};\n```\n\n\n\n> 思路 2: 暴力解法\n> ******- 时间复杂度: O(2N)******- 空间复杂度: O(2N)******\n\n由于是有序的链表，所以可以用数组中转的方式。把两个数组全部转成数组，再将两个数组合并再排序，最后再将两个数组转化为链表。\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} l1\n * @param {ListNode} l2\n * @return {ListNode}\n */\nvar mergeTwoLists = function(l1, l2) {\n  if (!l1 && !l2) {\n    return null\n  }\n  let array1 = listNodeToArray(l1)\n  let array2 = listNodeToArray(l2)\n  let array = array1.concat(array2)\n  array.sort((a, b) => (a - b))\n  \n  return arrayToListNode(array)\n};\n\n\nfunction listNodeToArray (head) {\n  let array = []\n  while (head) {\n    array.push(head.val)\n    head = head.next\n  }\n  return array\n}\n\nfunction arrayToListNode(array) {\n  if(!array || !array.length) {\n    return null\n  }\n  \n  let node\n  let head = new ListNode(array[0])\n  let pnode = head\n  \n  for(let i = 1; i < array.length; i++) {\n    node = new ListNode(array[i])\n    pnode.next = node\n    pnode = node\n  }\n  \n  return head\n}\n```\n\n\n\n> 思路 3: 单次循环遍历\n> ******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} l1\n * @param {ListNode} l2\n * @return {ListNode}\n */\nlet mergeTwoLists = function(l1, l2) {\n    if(!l1 || !l2){\n        return (l1 || l2)\n    }\n    let result = new ListNode;\n    let preNode = result;\n    while (l1 || l2){\n        let currentNode = new ListNode;\n        if(!l2){\n            currentNode.val = l1.val;\n            l1 = l1.next;\n        }else if(!l1){\n            currentNode.val = l2.val;\n            l2 = l2.next;\n        }else{\n            if(l1.val < l2.val){\n                currentNode.val = l1.val;\n                l1 = l1.next;\n            }else{\n                currentNode.val = l2.val;\n                l2 = l2.next;\n            }\n        }\n        preNode.next = currentNode;\n        preNode = currentNode;\n    }\n    return result.next;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0022._Generate_Parentheses.md",
    "content": "# 022. generate-parentheses\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/generate-parentheses/\n\n> 内容描述\n\nGiven `n` pairs of parentheses, write a function to generate all combinations of well-formed parentheses.\n\nFor example, given n = 3, a solution set is:\n\n```javascript\n\n[\n  \"((()))\",\n  \"(()())\",\n  \"(())()\",\n  \"()(())\",\n  \"()()()\"\n]\n```\n\n## 解题方案\n\n******- 时间复杂度: O(2N)******- 空间复杂度: O(N)******\n\n代码：\n\n```javascript\n/**\n * 递归函数\n * @param left  剩余的左括号\n * @param right 剩余的又括号\n * @param str  当前已拼装括号的字符串\n * @param list  最终结果集\n */\nlet helper = function (left,right,str,list) {\n    //当前右括号大于左括号\n    if (left > right){\n        return ;\n    }\n    //左括号，右括号均无剩余，作为终值填充\n    if(left === 0 && right === 0){\n        list.push(str);\n        return ;\n    }\n    //左括号有剩余\n    if(left > 0){\n        helper(left - 1,right,str + '(',list);\n    }\n    //右括号有剩余\n    if(right > 0){\n        helper(left,right - 1,str + ')',list);\n    }\n};\n/**\n * @param {number} n\n * @return {string[]}\n */\nlet generateParenthesis = function(n) {\n    let list = [];\n    helper(n,n,'',list);\n    return list;\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0024._Swap_Nodes_In_Pairs.md",
    "content": "# 0024. Swap Nodes In Pairs\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/swap-nodes-in-pairs/\n\n> 内容描述\n\n给定一个链表，两两交换其中相邻的节点，并返回交换后的链表。\n\n**你不能只是单纯的改变节点内部的值**，而是需要实际的进行节点交换。\n\n \n示例:\n\n     给定 1->2->3->4, 你应该返回 2->1->4->3.\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n递归方式：思路主要是每次`swapPairs`返回的都是替换后的头指针，所以每次只替换两个，然后当前`head.next`指向的是移动两次指针后的`swapParis`返回结果\n\n代码：\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @return {ListNode}\n */\nconst swapPairs = function(head) {\n  if (!head || !head.next) {\n    return head;\n  }\n  \n  let root = head.next;\n  head.next = swapPairs(head.next.next);\n  root.next = head;\n  return root;\n};\n```\n\n\n\n> 思路 2\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n这里借鉴了Python的解题思路\n```javascript\n/**\n * @param {ListNode} head\n * @return {ListNode}\n */\nconst swapPairs = function(head) {\n  if (!head || !head.next) {\n    return head;\n  }\n  \n  let tmp = new ListNode();\n  tmp.next = head;\n  \n  let current = tmp;\n  while (current.next && current.next.next) {\n    let next1 = current.next;\n    let next2 = current.next.next;\n    let next3 = current.next.next.next;\n    current.next = next2;\n    next2.next = next1;\n    next1.next = next3;\n    current = next1;\n  }\n  \n  return tmp.next;\n};\n\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0027._Remove_Element.md",
    "content": "# 027. Remove Element\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/remove-element\n\n> 内容描述\n\nGiven an array nums and a value val, remove all instances of that value in-place and return the new length.\n\nDo not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.\n\nThe order of elements can be changed. It doesn't matter what you leave beyond the new length.\n\n#### Example 1:\n\n     Given nums = [3,2,2,3], val = 3,\n\n     Your function should return length = 2, with the first two elements of nums being 2.\n\n     It doesn't matter what you leave beyond the returned length.\n\n#### Example 2:\n\n     Given nums = [0,1,2,2,3,0,4,2], val = 2,\n\n     Your function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4.\n\n     Note that the order of those five elements can be arbitrary.\n\n     It doesn't matter what values are set beyond the returned length.\n\n#### Clarification:\n\nConfused why the returned value is an integer but your answer is an array?\n\nNote that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.\n\nInternally you can think of this:\n\n     // nums is passed in by reference. (i.e., without making a copy)\n     int len = removeElement(nums, val);\n\n     // any modification to nums in your function would be known by the caller.\n     // using the length returned by your function, it prints the first len elements.\n     for (int i = 0; i < len; i++) {\n         print(nums[i]);\n     }\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n保留两个指针 i 和 j，其中 i 是慢指针，j 是快指针。当 nums[j] 与给定的值相等时，递增 j 以跳过该元素。只要 nums[j] !== val,我们就复制 nums[j] 到 nums[i] 并同时递增两个索引。重复这一过程，直到 j 到达数组的末尾，该数组的新长度为 i。\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @param {number} val\n * @return {number}\n */\nvar removeElement = function (nums,val) {\n    let j = 0;\n    for(let i = 0,len = nums.length; i<len; i++){\n        if(nums[i] !== val){\n            nums[j] = nums[i];\n            j++\n        }\n    }\n    return j;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0031._Next_Permutation.md",
    "content": "# 031. Next Permutation\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/next-permutation/submissions/\n\n> 内容描述\n\n实现获取下一个排列的函数，算法需要将给定数字序列重新排列成字典序中下一个更大的排列。\n\n如果不存在下一个更大的排列，则将数字重新排列成最小的排列（即升序排列）。\n\n必须原地修改，只允许使用额外常数空间。\n\n以下是一些例子，输入位于左侧列，其相应输出位于右侧列。\n`1,2,3` → `1,3,2`\n`3,2,1` → `1,2,3`\n`1,1,5` → `1,5,1`\n\n\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n下一个排序与当前排序的关系是`尽可能多的共用前面的位数`\n\n以`[1,2,4,6,5,3]`为例：\n\n分为三个步骤\n\n1. 从后向前查找，找到第一个升序排列的组合，即`[4,6]`，保存**这个位置**`2`（即`4`所在的位置）\n2. 在**这个位置**上后面找到一个比他的数字进行调换——`5`，数组变为`[1,2,5,6,4,3]`，如果没有找到，则说明数组已经为最大的排列方式，直接翻转即可\n3. 对于**这个位置**后面的数组(`[6,4,2]`)进行升序排列，数组变为`[1,2,5,3,4,6]`\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @return {void} Do not return anything, modify nums in-place instead.\n */\nvar nextPermutation = function(nums) {\n  if (!nums || !nums.length || nums.length <= 1) {\n    return nums\n  }\n  \n  let index = -1;\n  \n  // step 1: 找到最大共有位置\n  for (let i = nums.length - 1; i > 0; i--) {\n    if (nums[i-1] < nums[i]) {\n      index = i - 1;\n      break;\n    }\n  }\n  \n  // 未找到的情况，翻转即可\n  if (index === -1) {\n    return nums.reverse();\n  }\n  \n  // step 2: 替换最大共有位置上的值\n  for (let i = nums.length - 1; i > index; i--) {\n    if (nums[i] > nums[index]) {\n      [nums[i], nums[index]] = [nums[index], nums[i]]\n      break;\n    }\n  }\n  \n  // step 3: 最大共有位置之后的数据进行升序排列\n  const afterList = nums.slice(index + 1)\n  afterList.reverse()\n  for (let i = index + 1; i < nums.length; i ++) {\n    nums[i] = afterList[i - index - 1]\n  }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0035._Search_Insert_Position.md",
    "content": "# 035. Search Insert Position\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/search-insert-position/\n\n> 内容描述\n\n```\nGiven a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.\n\nYou may assume no duplicates in the array.\n\nExample 1:\n\nInput: [1,3,5,6], 5\nOutput: 2\nExample 2:\n\nInput: [1,3,5,6], 2\nOutput: 1\nExample 3:\n\nInput: [1,3,5,6], 7\nOutput: 4\nExample 4:\n\nInput: [1,3,5,6], 0\nOutput: 0\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(logN)******- 空间复杂度: O(N)******\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @param {number} target\n * @return {number}\n */\nlet searchInsert = function(nums, target) {\n    let lo = 0,high = nums.length-1;\n    while(lo<=high){\n         let mid = Math.floor((high-lo)/2)+lo;\n         if(nums[mid]===target)\n             return mid;\n         if(nums[mid]>target)\n             high = mid-1;\n         else lo = mid+1;\n    }\n    return lo;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0053._Maximum_Subarray.md",
    "content": "# 053. Maximum Subarray\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n[https://leetcode-cn.com/problems/maximum-subarray/](https://leetcode-cn.com/problems/maximum-subarray/)\n\n> 内容描述\n\n给定一个整数数组 `nums` ，找到一个具有最大和的连续子数组（子数组最少包含一个元素），返回其最大和。\n\n#### 示例:\n     \n     输入: [-2,1,-3,4,-1,2,1,-5,4],\n     输出: 6\n     解释: 连续子数组 [4,-1,2,1] 的和最大，为 6。\n     \n#### 进阶:\n\n如果你已经实现复杂度为 O(n) 的解法，尝试使用更为精妙的分治法求解。\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(N)******- 空间复杂度: O(2N)******\n\n\n解法DP\n\n```javascript\n/**\n * @param {number[]} nums\n * @return {number}\n */\nvar maxSubArray = function(nums) {\n  if(nums.length === 1) {\n    return nums[0]\n  }\n  let sum = nums[0]\n  let dp = nums[0]\n  for (let i = 1; i < nums.length; i++) {\n    dp = Math.max(dp + nums[i], nums[i])\n    sum = Math.max(sum, dp)\n  }\n  return sum;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0054._Spiral_Matrix.md",
    "content": "# 054.Spiral Matrix\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/search-insert-position/\n\n> 内容描述\n\n给定一个包含 m x n 个元素的矩阵（m 行, n 列），请按照顺时针螺旋顺序，返回矩阵中的所有元素。\n\n\n**示例 1：**\n\n```\n输入:\n[\n [ 1, 2, 3 ],\n [ 4, 5, 6 ],\n [ 7, 8, 9 ]\n]\n输出: [1,2,3,6,9,8,7,4,5]\n```\n\n**示例 2：**\n\n```\n输入:\n[\n  [1, 2, 3, 4],\n  [5, 6, 7, 8],\n  [9,10,11,12]\n]\n输出: [1,2,3,4,8,12,11,10,9,5,6,7]\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n代码：\n递归思路：\n\n 1. 取矩阵的第一行\n 2. 将矩阵逆时针反转90°\n 3. 递归\n \n \n终止条件：\n 矩阵为空 => 返回空矩阵\n 矩阵只剩下一行 => 返回这一行\n\n```javascript\n/**\n * @param {number[][]} matrix\n * @return {number[]}\n */\nvar spiralOrder = function(matrix) {\n  if (!matrix || !matrix.length) {\n    return matrix\n  } else if (matrix.length === 1 && Array.isArray(matrix[0])) {\n    return matrix[0]\n  } else {\n    return matrix.shift().concat(spiralOrder(rotate(matrix)))\n  }\n};\n\n\nvar rotate = function(matrix) {\n  if (!matrix || !matrix.length) {\n    return null\n  }\n  let newMatrix = []\n  let m = matrix[0].length\n  let n = matrix.length\n  for (let y = m - 1; y >= 0; y--) {\n    let newLine = []\n    for (let x = n - 1; x >= 0; x--) {\n      newLine.unshift(matrix[x][y])\n    }\n    newMatrix.push(newLine);\n  }\n  return newMatrix;\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0055._Jump_Game.md",
    "content": "# 0055. Jump Game\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/jump-game/](https://leetcode-cn.com/problems/jump-game/)\n\n> 内容描述\n\n给定一个非负整数数组，你最初位于数组的第一个位置。\n\n数组中的每个元素代表你在该位置可以跳跃的最大长度。\n\n判断你是否能够到达最后一个位置。\n\n#### 示例1:\n     \n     输入: [2,3,1,1,4]\n     输出: true\n     解释: 我们可以先跳 1 步，从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。\n     \n#### 示例2：\n\n     输入: [3,2,1,0,4]\n     输出: false\n     解释: 无论怎样，你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 ， 所以你永远不可能到达最后一个位置。\n\n  \n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n 1. 如果数组中没有`0`，那么结果一定为`true`\n 2. `reach`代表目前能跳到的最远位置（数组下标）\n 3. 每轮循环，数组下标固定向有移动一位\n 4. `start`代表本轮循环的位置\n 5. 每轮循环更新一次最远可达的位置——`reach`，`reach`的值为**当前循环的值**+**当前的数组下标**与之前`reach`值的最大值\n 6. 循环终止条件：\n  * 当前下标值大于可达最远位置时，代表当前下标永远达到不了\n  * 可达最远位置已经大于数组长度，代表已经能跳到最后位置了\n  \n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @return {boolean}\n */\nvar canJump = function(nums) {\n  let start = 0;\n  let reach = 0;\n  if (nums.every(i => i)) {\n    return true\n  }\n  while (start <= reach && reach < nums.length - 1) {\n    reach = Math.max(reach, nums[start] + start);\n    start++;\n  }\n  return reach >= nums.length-1;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0056._Merge_Intervals.md",
    "content": "# 056. Merge Intervals\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/merge-intervals/\n\n> 内容描述\n\n给出一个区间的集合，请合并所有重叠的区间。\n\n示例 1:\n\n     输入: [[1,3],[2,6],[8,10],[15,18]]\n     输出: [[1,6],[8,10],[15,18]]\n     解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].\n     \n示例 2:\n\n     输入: [[1,4],[4,5]]\n     输出: [[1,5]]\n     解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(2N)******- 空间复杂度: O(N)******\n\n先对输入进行排序，然后判断是存在间隔\n\n代码：\n\n```javascript\n/**\n * @param {number[][]} intervals\n * @return {number[][]}\n */\n\nvar merge = function(intervals) {\n    if (!intervals || !intervals.length) {\n        return intervals;\n    }\n    intervals.sort((a, b) => (a[0] - b[0]))\n    return intervals.reduce((acc, [ currentLeft, currentRight ]) => {\n        if (currentLeft > acc[acc.length - 1][1]) {\n            acc.push([ currentLeft, currentRight ]);\n        } else if (currentRight > acc[acc.length - 1][1]){\n            acc[acc.length - 1][1] = currentRight;\n        }\n        return acc;\n\n    }, [intervals[0]]);\n};\n\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0058._Length_of_Last_Word.md",
    "content": "# 58. Length of Last Word\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/length-of-last-word\n\n> 内容描述\n\n```\nGiven a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string.\n\nIf the last word does not exist, return 0.\n\nNote: A word is defined as a character sequence consists of non-space characters only.\n\nExample:\n\nInput: \"Hello World\"\n\nOutput: 5\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* 将数组以空格分割，找到最后一个字符串输出长度\n* 注意以空格结尾以及输入空字符串\n\n代码：\n\n```javascript\n/**\n * @param {string} s\n * @return {number}\n */\nvar lengthOfLastWord = function(s) {\n    var temp = s.split(' ').filter(function (value) {\n        return value!='';\n    });\n    return temp.length>0?temp.pop().length:0;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0061._Rotate_List.md",
    "content": "# 061.  Rotate List\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/rotate-list/\n\n> 内容描述\n\n给定一个链表，旋转链表，将链表每个节点向右移动 `k` 个位置，其中 `k` 是非负数。\n\n示例 1:\n\n     输入: 1->2->3->4->5->NULL, k = 2\n     输出: 4->5->1->2->3->NULL\n     解释:\n     向右旋转 1 步: 5->1->2->3->4->NULL\n     向右旋转 2 步: 4->5->1->2->3->NULL\n\n示例 2:\n\n     输入: 0->1->2->NULL, k = 4\n     输出: 2->0->1->NULL\n     解释:\n     向右旋转 1 步: 2->0->1->NULL\n     向右旋转 2 步: 1->2->0->NULL\n     向右旋转 3 步: 0->1->2->NULL\n     向右旋转 4 步: 2->0->1->NULL\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n将链表存储到数组中，再选择数组，然后再将数组转回链表\n\n代码：\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @param {number} k\n * @return {ListNode}\n */\nvar rotateRight = function(head, k) {\n    if (!head || !head.next || k === 0) {\n        return head;\n    }\n    const list = [];\n    let cur = head;\n\n    while (cur) {\n        list.push(cur)\n        cur = cur.next;\n    }\n\n    const index = k%list.length;\n    list.unshift(...list.splice(list.length - index, list.length))\n    list.forEach((node, index) => {\n        if (index < list.length) {\n            node.next = list[index+1]\n        } else {\n            node.next = null;\n        }\n    })\n    return list[0]\n};\n\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0062._Unique_Paths.md",
    "content": "# 62. Unique Paths 不同路径\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/unique-paths/\n\n> 内容描述\n\n一个机器人位于一个 m x n 网格的左上角 （起始点在下图中标记为“Start” ）。\n\n机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角（在下图中标记为“Finish”）。\n\n问总共有多少条不同的路径？\n![img](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/10/22/robot_maze.png)\n\n例如，上图是一个7 x 3 的网格。有多少可能的路径？\n\n**说明**：m 和 n 的值均不超过 100。\n\n**示例 1**:\n```\n输入: m = 3, n = 2\n输出: 3\n解释:\n从左上角开始，总共有 3 条路径可以到达右下角。\n1. 向右 -> 向右 -> 向下\n2. 向右 -> 向下 -> 向右\n3. 向下 -> 向右 -> 向右\n\n```\n**示例 2:**\n\n```\n输入: m = 7, n = 3\n输出: 28\n```\n\n\n## 解题方案\n\n> 思路 1 排列组合方式\n\n例子中，m=7、n=3，也就是说，可以向右走6步（`m-1`）和向下走2步（`n-2`）；\n如果用符号`→`表示向右走，符号`↓`表示向下走，那么这道题就变成了，(m-1)个`→`和(n-1)个`↓`有多少种排列组合方式，也就是最终\n```\n计算公式：(m-1 + n-1)! ÷ （(m-1)! × （n-1）!）\n\n```\n自行实现阶乘计算函数——`factorial`即可\n\n\n代码：\n\n```javascript\n/**\n * @param {number} m\n * @param {number} n\n * @return {number}\n */\n// 为了提高算法效率，利用cache缓存计算结果\nlet cache = {\n  1: 1\n}\nvar uniquePaths = function(m, n) {\n  return factorial(m + n - 2) / factorial(m - 1) / factorial(n - 1)\n};\n\nfunction factorial(num){\n  if(num <= 1) {\n    return 1;\n  } else if (cache[num]) {\n    return cache[num]\n  }else{\n    let value = num * factorial(num-1);\n    cache[num] = value;\n    return value\n  }\n}\n\n```\n\n> 思路 2 模拟矩阵\n> **- 时间复杂度: O(N)** \n>\n> **- 空间复杂度: O(N)**\n\n如果用每个格子上的值表示，当前格子到左上角格子的走法数量的话，那么右下角格子的值就是最终结果，样子如下\n| | | |\n| - | - | - |\n| 1 | 1 | 1 |\n| 1 | 2 | 3 |\n| 1 | 3 | 6 |\n| 1 | 4 | 10 |\n| 1 | 5 | 15 |\n| 1 | 6 | 21 |\n| 1 | 7 | 28 |\n\n发现规律，每个格子的值等于`左侧格子值 + 上方格子值`，所以用双层循环绘制表格，再去最后的值即可。\n\n```javascript\n\n/**\n * @param {number} m\n * @param {number} n\n * @return {number}\n */\nvar uniquePaths = function(m, n) {\n  let metrics = [];\n  for (let x = 0; x < m; x++) {\n    for (let y = 0; y < n; y++) {\n      if (!metrics[x]) {\n        metrics[x] = []\n      }\n      if (y === 0 || x === 0) {\n        metrics[x][y] = 1\n      } else {\n        metrics[x][y] = metrics[x][y - 1] + metrics[x - 1][y]\n      }\n    }\n  }\n  return metrics[m-1][n-1];\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0064._Minimum_Path_Sum.md",
    "content": "# 62. Unique Paths 不同路径\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/minimum-path-sum/](https://leetcode-cn.com/problems/minimum-path-sum/)\n\n> 内容描述\n\n给定一个包含非负整数的 m x n 网格，请找出一条从左上角到右下角的路径，使得路径上的数字总和为最小。\n\n**说明**：每次只能向下或者向右移动一步。\n\n#### 示例:\n\n     输入:\n     [\n       [1,3,1],\n       [1,5,1],\n       [4,2,1]\n     ]\n     输出: 7\n     解释: 因为路径 1→3→1→1→1 的总和最小。\n\n\n## 解题方案\n\n******- 时间复杂度: O(M*N)******- 空间复杂度: O(1)******\n\n每个坐标的最小期望 = Min(上侧的最小期望， 左侧的最小期望) + 当前坐标值。\n\n这样一次循环即可。\n\n代码：\n\n```javascript\n/**\n * @param {number[][]} grid\n * @return {number}\n */\nvar minPathSum = function(grid) {\n  const height = grid.length\n  const width = grid[0].length\n  if (width === 1) {\n    return grid.reduce((cur, pre) => (cur + pre[0]), 0)\n  }\n  if (height === 1) {\n    return grid[0].reduce((cur, pre) => (cur + pre), 0)\n  }\n  let min = 0\n  for (let i = 0; i < width; i++) {\n    for (let j = 0; j < height; j++) {\n      if (j === 0 && i === 0) {\n        grid[j][i] = grid[j][i]\n      } else if (j === 0) {\n        grid[j][i] = grid[j][i] + grid[j][i - 1]\n      } else if (i === 0) {\n        grid[j][i] = grid[j][i] + grid[j - 1][i]\n      } else {\n        grid[j][i] = grid[j][i] + Math.min(grid[j][i - 1], grid[j - 1][i])\n      }\n      min = grid[j][i]\n    }\n  }\n  return min\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0066._Plus_One.md",
    "content": "# 66. Plus One\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/plus-one\n\n> 内容描述\n\n```\nGiven a non-empty array of digits representing a non-negative integer, plus one to the integer.\n\nThe digits are stored such that the most significant digit is at the head of the list, and each element in the array contain a single digit.\n\nYou may assume the integer does not contain any leading zero, except the number 0 itself.\n\nExample 1:\n\nInput: [1,2,3]\nOutput: [1,2,4]\nExplanation: The array represents the integer 123.\nExample 2:\n\nInput: [4,3,2,1]\nOutput: [4,3,2,2]\nExplanation: The array represents the integer 4321.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n* 如果数字小于9则不会发生进位，仅当前位置++即可\n* 因进位和plus one 都是数字加一\n* 数字大于9则进位与初始加一的处理方式一样\n\n代码：\n\n```javascript\n/**\n * @param {number[]} digits\n * @return {number[]}\n */\nvar plusOne = function(digits) {\n    for(var i=digits.length-1;i>=0;i--){\n        if(digits[i]<9){\n            digits[i]++;\n            return digits;\n        }\n        digits[i]=0;\n    }\n    digits.unshift(1);\n    return digits;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0067._Add_Binary.md",
    "content": "# 67. Add Binary\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/add-binary\n\n> 内容描述\n\n```\nGiven two binary strings, return their sum (also a binary string).\n\nThe input strings are both non-empty and contains only characters 1 or 0.\n\nExample 1:\n\nInput: a = \"11\", b = \"1\"\nOutput: \"100\"\nExample 2:\n\nInput: a = \"1010\", b = \"1011\"\nOutput: \"10101\"\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* 对于每一位数进行加法，如有进位单独计算\n* 注意需使用字符串进行存储，整型无法计算大型数据\n\n代码：\n\n```javascript\n/**\n * @param {string} a\n * @param {string} b\n * @return {string}\n */\nvar addBinary = function(a, b) {\n    var tempA = a.split('');\n    var tempB = b.split('');\n    var result =[];\n    var aLen=tempA.length,bLen=tempB.length;\n    var carry = 0;\n    while(aLen>0||bLen>0){\n        var charA=0,charB=0;\n        if(aLen>0)\n            charA = tempA[--aLen]-0;\n        if(bLen>0)\n            charB = tempB[--bLen]-0;\n        var temp = charA + charB + carry;\n        carry = temp>1?1:0;\n        result.unshift(temp%2);\n    }\n    if(carry===1)\n        result.unshift(1);\n    return result.toString().replace(/,/g,'');\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0074._Search_a_2D_Matrix.md",
    "content": "# 074. Search a 2D Matrix\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/search-a-2d-matrix/\n\n> 内容描述\n\n```\nWrite an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:\n\nIntegers in each row are sorted from left to right.\nThe first integer of each row is greater than the last integer of the previous row.\nExample 1:\n\nInput:\nmatrix = [\n  [1,   3,  5,  7],\n  [10, 11, 16, 20],\n  [23, 30, 34, 50]\n]\ntarget = 3\nOutput: true\nExample 2:\n\nInput:\nmatrix = [\n  [1,   3,  5,  7],\n  [10, 11, 16, 20],\n  [23, 30, 34, 50]\n]\ntarget = 13\nOutput: false\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* 可以将这个二维数组看做一个数组，以二分法查找为最优算法\n\n代码：\n\n```javascript\n/**\n * @param {number[][]} matrix\n * @param {number} target\n * @return {boolean}\n */\nvar searchMatrix = function(matrix, target) {\n    if(matrix.length===0)\n        return false;\n    var row=0,col=matrix[0].length-1;\n    while(row<matrix.length&&col>=0){\n        if(matrix[row][col]===target)\n            return true;\n        else if(matrix[row][col]>target)\n            col--;\n        else\n            row++;\n    }\n    return false;\n};\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0077._Combinations.md",
    "content": "# 077. Combinations\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n[https://leetcode-cn.com/problems/combinations/](https://leetcode-cn.com/problems/combinations/)\n\n> 内容描述\n\n给定两个整数 n 和 k，返回 1 ... n 中所有可能的 k 个数的组合。\n\n#### 示例:\n     \n     输入: n = 4, k = 2\n     输出:\n     [\n       [2,4],\n       [3,4],\n       [2,3],\n       [1,2],\n       [1,3],\n       [1,4],\n     ]\n     \n#### 进阶:\n\n如果你已经实现复杂度为 O(n) 的解法，尝试使用更为精妙的分治法求解。\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(Nlogn)******- 空间复杂度: O(N)******\n\n\n回溯算法，算法参考：[leetCode回溯算法+剪枝](https://leetcode-cn.com/problems/combinations/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-ma-/)\n\n```javascript\n/**\n * @param {number} n\n * @param {number} k\n * @return {number[][]}\n */\n\nvar combine = function(n, k) {\n  const result = []\n  if (n <= 0 || k <= 0 || n < k) {\n    return result;\n  }\n  findCombinations(n, k, 1, [])\n  function findCombinations(n, k, index, list) {\n    list = [...list]\n    if (list.length === k) {\n      result.push(list);\n      return;\n    }\n    for (let i = index; i <= n - (k - list.length) + 1; i++) {\n      list.push(i);\n      findCombinations(n, k, i + 1, list);\n      list.pop();\n    }\n  }\n  \n  return result\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0079._Search_Word.md",
    "content": "# 0079. Word Seach\n\n**<font color=Orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/word-search/\n\n> 内容描述\n\n给定一个二维网格和一个单词，找出该单词是否存在于网格中。\n\n单词必须按照字母顺序，通过相邻的单元格内的字母构成，其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。\n\n示例:\n\n     board =\n     [\n       ['A','B','C','E'],\n       ['S','F','C','S'],\n       ['A','D','E','E']\n     ]\n\n     给定 word = \"ABCCED\", 返回 true.\n     给定 word = \"SEE\", 返回 true.\n     给定 word = \"ABCB\", 返回 false.\n\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(?)******- 空间复杂度: O(1)******\n\n这个时间复杂度我不知道如何分析\n\n思路是深度优先搜索\n\n代码：\n\n```javascript\n/**\n * @param {character[][]} board\n * @param {string} word\n * @return {boolean}\n */\nvar exist = function(board, word) {\n    let height = board.length;\n    let width = board[0].length;\n    let result = false;\n    for(let x = 0; x < height; x++) {\n        for(let y = 0; y < width; y++) {\n            if (board[x][y] === word[0]) {\n                result = result || searchDFS(board, [ x, y ], shiftWord(word), [[x,y]])\n            }\n        }\n    }\n    return result;\n};\n\nvar searchDFS = function (board, [x,y], word, useList = []) {\n    const list = [...useList];\n    let result = false;\n    if(!word || !word.length) {\n        return true;\n    }\n\n    // 上\n    if(x > 0 && board[x-1][y] === word[0] && !positionInList([x-1,y], list)) {\n        const l = [...list]\n        l.push([x-1, y]);\n        result = result || searchDFS(board, [x-1,y], shiftWord(word), l);\n    }\n\n    // 下\n    if (x < board.length-1 && board[x+1][y] === word[0] && !positionInList([x+1,y], list)) {\n        const l  = [...list]\n        l.push([x+1, y]);\n        result = result || searchDFS(board, [x+1,y], shiftWord(word), l);\n    }\n\n    // 左\n    if (y > 0 && board[x][y-1] === word[0] && !positionInList([x,y-1], list)) {\n        const l = [...list]\n        l.push([x, y-1]);\n        result = result || searchDFS(board, [x,y-1], shiftWord(word), l);\n    }\n\n    // 右\n    if (y < board[0].length-1 && board[x][y+1] === word[0] && !positionInList([x,y+1], list)) {\n        const l = [...list]\n        l.push([x, y+1]);\n        result = result || searchDFS(board, [x,y+1], shiftWord(word), l);\n    }\n\n    return result;\n}\n\nvar positionInList = function ([x, y], list = []) {\n    return list.some(([oX, oY]) => (oX === x && oY === y))\n}\n\nvar shiftWord = function (word) {\n    return Array.prototype.slice.call(word, 1).join('')\n}\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0083._Remove_Duplicates_From_Sorted_List.md",
    "content": "# 083. Remove Duplicates From Sorted List\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/)\n\n> 内容描述\n\n\n\n给定一个排序链表，删除所有重复的元素，使得每个元素只出现一次。\n\n**示例 1:**\n\n```\n输入: 1->1->2\n输出: 1->2\n```\n\n**示例 2:**\n\n```\n输入: 1->1->2->3->3\n输出: 1->2->3\n```\n\n\n\n## 解题方案\n\n> 思路 1\n> **- 时间复杂度: O(N)** \n>\n> **- 空间复杂度: O(2N)**\n\n**暴力解法**：将链表转化为数组，对数组去重，然后数组转换为链表\n\n> 执行用时 :**100 ms**, 在所有 JavaScript 提交中击败了**75.87%**的用户\n>\n> 内存消耗 :**36.7 MB**, 在所有 JavaScript 提交中击败了**7.05%**的用户\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @return {ListNode}\n */\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @return {ListNode}\n */\nvar deleteDuplicates = function(head) {\n  if (!head) {\n    return null\n  }\n  let array = listNodeToArray(head)\n  return arrayToListNode([...new Set(array)])\n};\n\n\nfunction listNodeToArray (head) {\n  let array = []\n  while (head) {\n    array.push(head.val)\n    head = head.next\n  }\n  return array\n}\n\nfunction  arrayToListNode(array) {\n  if(!array || !array.length) {\n    return null\n  }\n  \n  let node\n  let head = new ListNode(array[0])\n  let pnode = head  //pnode变量用来保存前一个节点\n  \n  for(let i = 1; i < array.length; i++) {\n    node = new ListNode(array[i])\n    pnode.next = node   //将前一个节点的next指向当前节点\n    pnode = node   //将node赋值给pnode\n  }\n  \n  return head\n}\n```\n\n\n> 思路 2\n> **- 时间复杂度: O(N)** \n>\n> **- 空间复杂度: O(1)**\n\n**快慢指针**：每次循环，判断当前的值与下一个是否相等，如果**相等**，快指针(`head`)向前移动，慢指针（`slow`）原地不动；如果**不等**则把下一个节点连接到慢指针后，再将快慢指针都向前移动。\n\n> 执行用时 :**92 ms**, 在所有 JavaScript 提交中击败了**91.01%**的用户\n>\n> 内存消耗 :**35.7 MB**, 在所有 JavaScript 提交中击败了**69.46%**的用户\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @return {ListNode}\n */\nvar deleteDuplicates = function(head) {\n  if (!head) {\n    return null\n  }\n  let slow = head\n  let result = slow\n  while (head) {\n    if (head.next && (head.val === head.next.val)) {\n      head = head.next\n    } else {\n      slow.next = head.next\n      slow = slow.next\n      head = head.next\n    }\n  }\n  return result\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0094._Binary_Tree_Inorder_Traversal.md",
    "content": "# 094. Binary Tree Inorder Traversal\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/binary-tree-inorder-traversal/](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/)\n\n> 内容描述\n\n给定一个二叉树，返回它的*中序* 遍历。\n\n**示例:**\n\n```\n输入: [1,null,2,3]\n   1\n    \\\n     2\n    /\n   3\n\n输出: [1,3,2]\n```\n\n\n## 解题方案\n\n> 思路 1 迭代\n> **- 时间复杂度: O(3N)** \n>\n> **- 空间复杂度: O(N)**\n\n> 执行用时 :**64 ms**, 在所有 JavaScript 提交中击败了**97.85%**的用户\n>\n> 内存消耗 :**33.7 MB**, 在所有 JavaScript 提交中击败了**34.70%**的用户\n\n```javascript\n/**\n * Definition for a binary tree node.\n * function TreeNode(val) {\n *     this.val = val;\n *     this.left = this.right = null;\n * }\n */\n/**\n * @param {TreeNode} root\n * @return {number[]}\n */\nconst inorderTraversal = node => {\n  const valueList = []\n  forEachTree(node)\n  return valueList\n  function forEachTree (node) {\n    if (!node) {\n      return\n    }\n    forEachTree(node.left)\n    valueList.push(node.val)\n    forEachTree(node.right)\n  }\n}\n```\n\n\n\n> 思路 2 迭代\n>\n> - 时间复杂度: O(N²) \n> -  空间复杂度: O(N²)\n\n>执行用时 :**76 ms**, 在所有 JavaScript 提交中击败了**69.05%**的用户\n>\n>内存消耗 :**33.7 MB**, 在所有 JavaScript 提交中击败了**36.57%**的用户\n\n```javascript\n/**\n * Definition for a binary tree node.\n * function TreeNode(val) {\n *     this.val = val;\n *     this.left = this.right = null;\n * }\n */\n/**\n * @param {TreeNode} root\n * @return {number[]}\n */\nconst inorderTraversal = (node) => {\n  const valList = []\n  const stack = []\n  while (node || stack.length) {\n    if (node) {\n      stack.push(node)\n      node = node.left\n    } else {\n      node = stack.pop()\n      valList.push(node.val)\n      node = node.right\n    }\n  }\n  return valList\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0098._Validate_Binary_Search_Tree.md",
    "content": "# 098. Validate Binary Search Tree\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode.com/problems/validate-binary-search-tree/](https://leetcode.com/problems/validate-binary-search-tree/)\n\n> 内容描述\n\n给定一个二叉树，判断其是否是一个有效的二叉搜索树。\n\n假设一个二叉搜索树具有如下特征：\n\n节点的左子树只包含小于当前节点的数。\n节点的右子树只包含大于当前节点的数。\n所有左子树和右子树自身必须也是二叉搜索树。\n\n\n**示例 1:**\n\n```\n输入:\n    2\n   / \\\n  1   3\n输出: true\n```\n\n**示例 2:**\n\n```\n输入:\n         5\n        / \\\n       1   4\n          / \\\n         3   6\n输出: false\n解释: 输入为: [5,1,4,null,null,3,6]。\n     根节点的值为 5 ，但是其右子节点值为 4 。\n```\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(2N)******- 空间复杂度: O(2N)******\n\n一个思路简单的算法，二叉搜索树的中序遍历结果是个有序数组。\n\n1. 获取当前二叉树的中序遍历结果数组\n2. 判断上步的数组是否是一个有序数组\n\n\n\n代码：\n\n```javascript\n/**\n * Definition for a binary tree node.\n * function TreeNode(val) {\n *     this.val = val;\n *     this.left = this.right = null;\n * }\n */\n/**\n * @param {TreeNode} root\n * @return {boolean}\n */\nvar isValidBST = function(root) {\n  var list = inorderTraversal(root)\n  var base = list.join(',')\n  return base === [...new Set(list)].sort((a, b) => (a - b)).join(',')\n};\n\n// 获取中序遍历\nvar inorderTraversal = function (root) {\n  if (root === null) return []\n  return [...inorderTraversal(root.left), root.val, ...inorderTraversal(root.right)]\n};\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0100._Same_Tree.md",
    "content": "# 100. Same Tree\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/same-tree/](https://leetcode-cn.com/problems/same-tree/)\n\n> 内容描述\n\n给定两个二叉树，编写一个函数来检验它们是否相同。\n\n如果两个树在结构上相同，并且节点具有相同的值，则认为它们是相同的。\n\n\n\n**示例 1:**\n\n```\n输入:       1         1\n          / \\       / \\\n         2   3     2   3\n\n        [1,2,3],   [1,2,3]\n\n输出: true\n```\n\n**示例 2:**\n\n```\n输入:      1          1\n          /           \\\n         2             2\n\n        [1,2],     [1,null,2]\n\n输出: false\n```\n\n**示例 3:**\n\n```\n输入:       1         1\n          / \\       / \\\n         2   1     1   2\n\n        [1,2,1],   [1,1,2]\n\n输出: false\n```\n\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n递归解法\n\n1. 获取当前二叉树的中序遍历结果数组\n2. 判断上步的数组是否是一个有序数组\n\n代码：\n\n```javascript\n/**\n * Definition for a binary tree node.\n * function TreeNode(val) {\n *     this.val = val;\n *     this.left = this.right = null;\n * }\n */\n/**\n * @param {TreeNode} p\n * @param {TreeNode} q\n * @return {boolean}\n */\nvar isSameTree = function(p, q) {\n  if (p) {\n    return p && !!q && (p.val === q.val) && isSameTree(p.left, q.left) && isSameTree(p.right,q.right)\n  } else {\n    return !q\n  }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0101._Symmetric_Tree.md",
    "content": "# 101. Symmetric Tree\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode.com/problems/symmetric-tree/](https://leetcode.com/problems/symmetric-tree/)\n\n> 内容描述\n\n给定一个二叉树，检查它是否是镜像对称的。\n\n例如，二叉树 `[1,2,2,3,4,4,3]` 是对称的。\n\n```\n    1\n   / \\\n  2   2\n / \\ / \\\n3  4 4  3\n```\n\n但是下面这个 `[1,2,2,null,3,null,3]` 则不是镜像对称的:\n\n```\n    1\n   / \\\n  2   2\n   \\   \\\n   3    3\n```\n\n**说明:**\n\n如果你可以运用递归和迭代两种方法解决这个问题，会很加分。\n\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n递归解法\n\n代码：\n\n```javascript\n/**\n * Definition for a binary tree node.\n * function TreeNode(val) {\n *     this.val = val;\n *     this.left = this.right = null;\n * }\n */\n/**\n * @param {TreeNode} root\n * @return {boolean}\n */\nvar isSymmetric = function(root) {\n    if (!root) {\n        return true\n    }\n    return isMirror(root, root)\n};\n\nfunction isMirror(t1, t2) {\n  if (t1 == null && t2 == null) return true;\n  if (t1 == null || t2 == null) return false;\n  return (t1.val == t2.val)\n    && isMirror(t1.right, t2.left)\n    && isMirror(t1.left, t2.right);\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0104._Maximum_Depth_of_Binary_Tree.md",
    "content": "# 104. Maximum Depth of Binary Tree\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/maximum-depth-of-binary-tree\n\n> 内容描述\n\n```\nGiven a binary tree, find its maximum depth.\n\nThe maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.\n\nNote: A leaf is a node with no children.\n\nExample:\n\nGiven binary tree [3,9,20,null,null,15,7],\n\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\nreturn its depth = 3.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(log2 N)******- 空间复杂度: O(N)******\n\n* 这道题使用递归进行解决，因为对于树的每一个儿子的处理方法是一致的。\n* 将左儿子和右儿子中最大的数进行返回再加上当前的深度1即可解决。\n\n代码：\n\n```javascript\nvar maxDepth = function(root) {\n    if(root===null||root === undefined)\n        return 0;\n    return Math.max(maxDepth(root.left),maxDepth(root.right))+1;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0106._Construct_Binary_Tree_From_Inorder_And_Postorder_Traversal.md",
    "content": "# 106. Construct Binary Tree From Inorder And Postorder Traversal\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/\n\n> 内容描述\n\n根据一棵树的中序遍历与后序遍历构造二叉树。\n\n注意:\n你可以假设树中没有重复的元素。\n\n例如，给出\n\n中序遍历 inorder = [9,3,15,20,7]\n后序遍历 postorder = [9,15,7,20,3]\n返回如下的二叉树：\n\n        3\n       / \\\n      9  20\n        /  \\\n       15   7\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* \n\n代码：\n\n```javascript\nvar buildTree = function(inorder, postorder) {\n  if (!inorder.length || !postorder.length) {\n    return null\n  }\n  let rootVal = postorder[postorder.length - 1]\n  let root = new TreeNode(rootVal)\n  let k = inorder.indexOf(rootVal)\n  root.left = buildTree(inorder.slice(0, k), postorder.slice(0, k))\n  root.right = buildTree(inorder.slice(k+1), postorder.slice(k, postorder.length - 1))\n  return root\n};\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0120._Triangle.md",
    "content": "# 62. Triangle\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/minimum-path-sum/](https://leetcode-cn.com/problems/minimum-path-sum/)\n\n> 内容描述\n\n给定一个三角形，找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。\n\n例如，给定三角形：\n\n     [\n          [2],\n         [3,4],\n        [6,5,7],\n       [4,1,8,3]\n     ]\n\n自顶向下的最小路径和为 11（即，2 + 3 + 5 + 1 = 11）。\n\n#### 说明：\n\n如果你可以只使用 O(n) 的额外空间（n 为三角形的总行数）来解决这个问题，那么你的算法会很加分。\n\n## 解题方案\n\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n每个坐标的最小期望 = Min(左上的最小期望， 右上的最小期望) + 当前坐标值。\n\n这样一次循环即可。\n\n**Tips：**\n\n特殊情况：\n\n * 顶点的最小期望是自己\n * 最左侧的点的期望 = 当前坐标值 + 上方的值\n * 最右侧的点的期望 = 当前坐标值 + 上方的值\n\n代码：\n\n```javascript\n/**\n * @param {number[][]} triangle\n * @return {number}\n */\nvar minimumTotal = function(triangle) {\n  if (triangle[triangle.length - 1].length === 1) {\n    return triangle[0][0]\n  }\n  triangle.forEach((list, height) => {\n    list.forEach((n, i) => {\n      if (height === 0) {\n        triangle[height][i] = triangle[height][i]\n      } else if (i === 0) {\n        triangle[height][i] = triangle[height][i] + triangle[height - 1][0]\n      } else if (i === list.length - 1) {\n        triangle[height][i] = triangle[height][i] + triangle[height - 1][i - 1]\n      } else {\n        triangle[height][i] = triangle[height][i] + Math.min(triangle[height - 1][i], triangle[height - 1][i - 1])\n      }\n    })\n  })\n  return Math.min(...triangle[triangle.length - 1])\n};\n\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0121._Best_Time_To_Buy_And_Sell_Stock.md",
    "content": "# 0121. Best Time To Buy And Sell Stock\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/)\n\n> 内容描述\n\n给定一个数组，它的第 i 个元素是一支给定股票第 i 天的价格。\n\n如果你最多只允许完成一笔交易（即买入和卖出一支股票），设计一个算法来计算你所能获取的最大利润。\n\n注意你不能在买入股票前卖出股票。\n\n\n#### 示例1\n\n     输入: [7,1,5,3,6,4]\n     输出: 5\n     解释: 在第 2 天（股票价格 = 1）的时候买入，在第 5 天（股票价格 = 6）的时候卖出，最大利润 = 6-1 = 5 。\n          注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。\n     \n#### 示例2\n\n     输入: [7,6,4,3,1]\n     输出: 0\n     解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。\n\n\n## 解题方案\n\n> 思路1：DP\n******- 时间复杂度: O(N)******- 空间复杂度: O(2N)******\n\n```javascript\n/**\n * @param {number[]} prices\n * @return {number}\n */\nvar maxProfit = function(prices) {\n  var lowestPrice = prices.shift()\n  var maxProfitCount = 0\n  while (prices.length) {\n    var current = prices.shift()\n    lowestPrice = Math.min(lowestPrice, current)\n    maxProfitCount = Math.max(current - lowestPrice, maxProfitCount)\n  }\n  return maxProfitCount\n};\n\n```\n\n\n\n> 思路 2： 暴力穷举法\n******- 时间复杂度: O(N²)******- 空间复杂度: O(2N)******\n\n```javascript\n/**\n * @param {number[]} prices\n * @return {number}\n */\nvar maxProfit = function(prices) {\n  var profitList = []\n  while (prices.length) {\n    var cur = prices.shift()\n    profitList.push(Math.max(...prices) - cur)\n  }\n  var maxProfit = Math.max(...profitList)\n  return maxProfit > 0 ? maxProfit : 0\n};\n\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0141._Linked_List_Cycle.md",
    "content": "# 0141. Linked List Cycle\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/linked-list-cycle/\n\n> 内容描述\n\n```\nGiven a linked list, determine if it has a cycle in it.\n\nTo represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.\n```\n\n**Example 1:**\n\n```\nInput: head = [3,2,0,-4], pos = 1\nOutput: true\nExplanation: There is a cycle in the linked list, where tail connects to the second node.\n```\n\n![img](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png)\n\n**Example 2:**\n\n```\nInput: head = [1,2], pos = 0\nOutput: true\nExplanation: There is a cycle in the linked list, where tail connects to the first node.\n```\n\n![img](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test2.png)\n\n**Example 3:**\n\n```\nInput: head = [1], pos = -1\nOutput: false\nExplanation: There is no cycle in the linked list.\n```\n\n![img](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test3.png)\n\n \n\n**Follow up:**\n\nCan you solve it using *O(1)* (i.e. constant) memory?\n\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n使用`快慢指针`的思路进行解题。就像两个运动员在同一个环形赛道上赛跑，如果一个运动员跑的快，一个跑得慢，最后两个运动员一定会相遇。\n\n下面代码中的`fast`每次会走两步，而`slow`每次会走一步，如果`fast`没有`next`节点，自然没有环；如果`fast`等于`slow`说明二者相遇，最终为表明存在环。\n\n\n\n#### 执行结果\n\n执行用时 :**92 ms**, 在所有 JavaScript 提交中击败了94.16%的用户\n\n内存消耗 :**36.6 MB**, 在所有 JavaScript 提交中击败了51.93%\n\n\n\n代码：\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n\n/**\n * @param {ListNode} head\n * @return {boolean}\n */\nvar hasCycle = function(head) {\n  if (head === null || head.next === null) {\n    return false\n  }\n  \n  let slow = head\n  let fast = head.next\n  \n  while (slow !== fast) {\n    if (fast === null || fast.next === null) {\n      return false\n    }\n    slow = slow.next\n    fast = fast.next.next\n  }\n  return true\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0146._LRU_Cache.md",
    "content": "# 0146. LRU Cache\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题链接\n\n* https://leetcode.com/problems/lru-cache/\n\n> 内容描述\n\nDesign and implement a data structure for [Least Recently Used (LRU) cache](https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU). It should support the following operations: `get` and `put`.\n\n`get(key)` - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.\n`put(key, value)` - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.\n\nThe cache is initialized with a **positive** capacity.\n\n**Follow up:**\nCould you do both operations in **O(1)** time complexity?\n\n**Example:**\n\n```\nLRUCache cache = new LRUCache( 2 /* capacity */ );\n\ncache.put(1, 1);\ncache.put(2, 2);\ncache.get(1);       // returns 1\ncache.put(3, 3);    // evicts key 2\ncache.get(2);       // returns -1 (not found)\ncache.put(4, 4);    // evicts key 1\ncache.get(1);       // returns -1 (not found)\ncache.get(3);       // returns 3\ncache.get(4);       // returns 4\n```\n\n \n\n## 解题方案\n\n> 思路1\n\n******- 时间复杂度: O(1)******- 空间复杂度: O(N)******\n\n这是一道数据结构的考题。\n\n简单的获取和插入，顺序不做考虑，所以数据结构用Object即可。\n\n但是重要的考点——[LRU](https://baike.baidu.com/item/LRU/1269842?fr=aladdin)，也就是删除最近没有使用的数据。所以想到用`队列`存在key列表：\n\n* 未超过存储上限时，每次`put`一个新数据时，向队列末尾插入当前`key`\n* 每次`get`时，如果key存在，则将对应的key从的队列中，移到对末尾\n* 在超过存储上限时，如进行`put`操作，则将队列首位删除掉\n\n> 执行用时 :492 ms, 在所有 JavaScript 提交中击败了35.29%的用户\n>\n> 内存消耗 :59.7 MB, 在所有 JavaScript 提交中击败了16.36%的用户\n\n```javascript\n/**\n * @param {number} capacity\n */\nvar LRUCache = function(capacity) {\n  this.limit = capacity || 2\n  this.storage = {}\n  this.keyList = []\n};\n\n/**\n * @param {number} key\n * @return {number}\n */\nLRUCache.prototype.get = function(key) {\n  if (this.storage.hasOwnProperty(key)) {\n    let index = this.keyList.findIndex(k => k === key)\n    this.keyList.splice(index, 1)\n    this.keyList.push(key)\n    return this.storage[key]\n  } else {\n    return -1\n  }\n};\n\n/**\n * @param {number} key\n * @param {number} value\n * @return {void}\n */\nLRUCache.prototype.put = function(key, value) {\n  // 判断容量\n  if (this.keyList.length >= this.limit && !this.storage.hasOwnProperty(key)) {\n    this.deleteLRU()\n  }\n  \n  // 存储数据\n  this.updateKeyList(key)\n  this.storage[key] = value\n};\n\nLRUCache.prototype.deleteLRU = function () {\n  delete this.storage[this.keyList.shift()]\n}\n\nLRUCache.prototype.updateKeyList = function (key) {\n  if (this.storage.hasOwnProperty(key)) {\n    var index = this.keyList.findIndex(k => key === k)\n    this.keyList.splice(index, 1)\n  }\n  this.keyList.push(key)\n}\n\n/**\n * Your LRUCache object will be instantiated and called as such:\n * var obj = new LRUCache(capacity)\n * var param_1 = obj.get(key)\n * obj.put(key,value)\n */\n\n\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0167._Two_Sum_II_-_Input_array_is_sorted.md",
    "content": "# 167. Two Sum II - Input array is sorted\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/two-sum-ii-input-array-is-sorted   \n\n> 内容描述\n\n```\nGiven an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.\n\nThe function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.\n\nNote:\n\nYour returned answers (both index1 and index2) are not zero-based.\nYou may assume that each input would have exactly one solution and you may not use the same element twice.\nExample:\n\nInput: numbers = [2,7,11,15], target = 9\nOutput: [1,2]\nExplanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(log2 N)******- 空间复杂度: O(n)******\n\n* 使用贪心算法，用左右的数字开始加，如果数字大于目标right--，反之left++\n\n代码：\n\n```javascript\n/**\n * @param {number[]} numbers\n * @param {number} target\n * @return {number[]}\n */\nvar twoSum = function(numbers, target) {\n    if(numbers.length===0)\n        return [];\n    var left = 0,right = numbers.length-1;\n    while(right>left){\n        if(numbers[right]+numbers[left]>target)\n            right--;\n        else if(numbers[right]+numbers[left]<target)\n            left++;\n        else return [left+1,right+1];\n    }\n    return [];\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0167._Two_Sum_II_Input_Array_is_Sorted.md",
    "content": "# 167. Two Sum II - Input array is sorted\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/two-sum-ii-input-array-is-sorted\n\n> 内容描述\n\n```\nGiven an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.\n\nThe function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.\n\nNote:\n\nYour returned answers (both index1 and index2) are not zero-based.\nYou may assume that each input would have exactly one solution and you may not use the same element twice.\nExample:\n\nInput: numbers = [2,7,11,15], target = 9\nOutput: [1,2]\nExplanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n算法来源于知乎文章——[趣味算法思想](https://zhuanlan.zhihu.com/p/46223775)\n* 由于数组是有序的，所以可以从两边向中间逐渐收敛地进行查找，好处在于避免了双重循环\n* 如果最两端的和小于目标数，则可以让左侧下标+1，然后重新进行运算比较\n* 如果最两端的和大于目标数，则可以让右侧下标-1，然后重新进行运算比较\n\n代码：\n\n```javascript\n/**\n * @param {number[]} numbers\n * @param {number} target\n * @return {number[]}\n */\nvar twoSum = function(nums, target) {\n    var number=[];\n    var left = 0;\n    var right = nums.length - 1 ;\n    while(left < right ) {\n        if(nums[left] + nums[right] === target) {\n            return [left+1, right+1]\n        } else if(nums[left] + nums[right] > target ) {\n            right--;\n        } else {\n            left++;\n        }\n    } \n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0171._Excel_Sheet_Column_Number.md",
    "content": "# 0171. Excel Sheet Column Number\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/excel-sheet-column-number/\n\n> 内容描述\n\n给定一个Excel表格中的列名称，返回其相应的列序号。\n\n例如，\n\n     A -> 1\n     B -> 2\n     C -> 3\n     ...\n     Z -> 26\n     AA -> 27\n     AB -> 28 \n     ...\n     \n示例 1:\n\n     输入: \"A\"\n     输出: 1\n\n示例 2:\n\n     输入: \"AB\"\n     输出: 28\n\n示例 3:\n\n     输入: \"ZY\"\n     输出: 701\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n利用parseInt可以按照进制来解析的特性，可以将英文字母轻松转换成数字\n\n代码：\n\n```javascript\n/**\n * @param {string} s\n * @return {number}\n */\nvar titleToNumber = function(s) {\n    if (!s) {\n        return 0\n    }\n    let list = s.split('')\n    list = list.map((alpha, index) => (parseInt(alpha, 36) - 9) * Math.pow(26, list.length - index - 1))\n    return list.reduce((acc, cur) => (acc + cur), 0)\n}\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0179._Largest_Number.md",
    "content": "# 0179. Largest Number\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/largest-number/\n\n> 内容描述\n\n给定一组非负整数，重新排列它们的顺序使之组成一个最大的整数。\n\n示例 1:\n\n     输入: [10,2]\n     输出: 210\n示例 2:\n\n     输入: [3,30,34,5,9]\n     输出: 9534330\n     \n说明: 输出结果可能非常大，所以你需要返回一个字符串而不是整数。\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(1)******\n\n排序时，计算两个数字谁在前面组成的数字比较大即可\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @return {string}\n */\nvar largestNumber = function(nums) {\n    if (nums.every(n => !n)) {\n        return '0'\n    }\n    return nums.sort((a, b) => {\n        return Number('' + b + a) - Number('' + a + b)\n    }).join('')\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0198._House_Robber.md",
    "content": "# 0198. House Robber\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/house-robber/](https://leetcode-cn.com/problems/house-robber/)\n\n> 内容描述\n\n你是一个专业的小偷，计划偷窃沿街的房屋。每间房内都藏有一定的现金，影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统，**如果两间相邻的房屋在同一晚上被小偷闯入，系统会自动报警**。\n\n给定一个代表每个房屋存放金额的非负整数数组，计算你**在不触动警报装置的情况下**，能够偷窃到的最高金额。\n\n示例 1:\n\n     输入: [1,2,3,1]\n     输出: 4\n     解释: 偷窃 1 号房屋 (金额 = 1) ，然后偷窃 3 号房屋 (金额 = 3)。\n          偷窃到的最高金额 = 1 + 3 = 4 。\n     \n     \n示例 2:\n\n     输入: [2,7,9,3,1]\n     输出: 12\n     解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9)，接着偷窃 5 号房屋 (金额 = 1)。\n          偷窃到的最高金额 = 2 + 9 + 1 = 12 。\n     \n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\nDP动态规划\n\n一次循环，循环到每个房间时都做一个选择：偷？还是不偷？\n\n * 偷：那么当前最大的收益（`DP[i]`） 为 `DP[i-2] + Vi`,其中为`Vi`代表当前房间的价值\n * 不偷：那么当前最大的收益（`DP[i]`）为`DP[i-1]`\n \n 所以`DP[i] = Max(DP[i-2] + Vi, DP[i-1]) `\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @return {number}\n */\nvar rob = function(nums) {\n  let dp = []\n  if(!nums.length) {\n      return 0\n  }\n  nums.forEach((n, i) => {\n    dp[i] = Math.max((dp[i-2] || 0) + n, (dp[i-1] || 0))\n  })\n  return dp[nums.length - 1]\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0203._Remove_Linked_List_Elements.md",
    "content": "# 203. Remove Linked List Elements\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/remove-linked-list-elements/](https://leetcode-cn.com/problems/remove-linked-list-elements/)\n\n> 内容描述\n\n删除链表中等于给定值 **val** 的所有节点。\n\n**示例:**\n\n```\n输入: 1->2->6->3->4->5->6, val = 6\n输出: 1->2->3->4->5\n```\n\n\n## 解题方案\n\n> 思路 1\n> **- 时间复杂度: O(3N)** \n>\n> **- 空间复杂度: O(2N)**\n\n**暴力解法**：\n\n1. 将链表转化为数组\n2. 对数组进行过滤\n3. 将过滤后的数组重新转化为数组\n\n> 执行用时 :**160 ms**, 在所有 JavaScript 提交中击败了**10.71%**的用户\n>\n> 内存消耗 :**38.4 MB**, 在所有 JavaScript 提交中击败了**5.13%**的用户\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @param {number} val\n * @return {ListNode}\n */\nvar removeElements = function(head, val) {\n  if (!head) {\n    return head\n  }\n  let array = listNodeToArray(head)\n  array = array.filter(i => (i !== val))\n  return arrayToListNode(array)\n};\n\n\nfunction listNodeToArray (head) {\n  let array = []\n  while (head) {\n    array.push(head.val)\n    head = head.next\n  }\n  return array\n}\n\nfunction  arrayToListNode(array) {\n  if(!array || !array.length) {\n    return null\n  }\n  \n  let node\n  let head = new ListNode(array[0])\n  let pnode = head  //pnode变量用来保存前一个节点\n  \n  for(let i = 1; i < array.length; i++) {\n    node = new ListNode(array[i])\n    pnode.next = node   //将前一个节点的next指向当前节点\n    pnode = node   //将node赋值给pnode\n  }\n  \n  return head\n}\n```\n\n\n> 思路 2\n> **- 时间复杂度: O(N)** \n>\n> **- 空间复杂度: O(1)**\n\n**快慢指针**：\n\n1. 快指针(`head`)每次循环都向前移动一个\n2. 慢指针(`slow`)只有在快指针当前节点的值不等于给定值时，才会向前移动，并在此之前将快指针当前节点指向慢指针的`next`\n\n> 执行用时 :**108 ms**, 在所有 JavaScript 提交中击败了**77.37%**的用户\n>\n> 内存消耗 :**37.9 MB**, 在所有 JavaScript 提交中击败了**11.11%**的用户\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @param {number} val\n * @return {ListNode}\n */\nvar removeElements = function(head, val) {\n  if (!head) {\n    return head\n  }\n  let slow = new ListNode()\n  let result = slow\n  while (head) {\n    if (head.val !== val) {\n      slow.next = head\n      slow = slow.next\n    } else if (!head.next) {\n      slow.next = null\n    }\n    head = head.next\n  }\n  return result.next\n};\n\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0206._Reverse_Linked_List.md",
    "content": "# 206. Reverse Linked List(反转链表)\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/reverse-linked-list/](https://leetcode-cn.com/problems/reverse-linked-list/)\n\n> 内容描述\n\n反转一个单链表。\n\n**示例:**\n\n```\n输入: 1->2->3->4->5->NULL\n输出: 5->4->3->2->1->NULL\n```\n\n\n## 解题方案\n * 思路1 ：暴力解法\n\n将链表转化为数组，再利用数组重建数组。\n\n> 思路\n> **- 时间复杂度: O(N²)** \n>\n> **- 空间复杂度: O(N)**\n\n> 执行用时 :**96 ms**, 在所有 JavaScript 提交中击败了**54.77%**的用户\n>\n> 内存消耗 :**35.2 MB**, 在所有 JavaScript 提交中击败了**30.19%**的用户\n\n```javascript\n\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @return {ListNode}\n */\nvar reverseList = function(head) {\n  var nodeList = []\n  if (!head) {\n    return head\n  }\n  while (head.next) {\n    nodeList.push(head)\n    head = head.next\n  }\n  nodeList.push(head)\n  nodeList.forEach((node, index) => {\n    if (nodeList[index - 1]) {\n      node.next = nodeList[index - 1]\n    } else {\n      node.next = null\n    }\n  })\n  return nodeList[nodeList.length - 1]\n};\n\n```\n\n\n\n* 思路2： 迭代法\n\n使用`parentNode`缓存上次循环的结果，每次循环都生成两个新的`ListNode`用来翻转链表各个元素，一次迭代即可完成链表反转。\n\n> 思路\n> **- 时间复杂度: O(N)** \n>\n> **- 空间复杂度: O(1)**\n\n> 执行用时 :**116 ms**, 在所有 JavaScript 提交中击败了**20.19%**的用户\n>\n> 内存消耗 :**35.5 MB**, 在所有 JavaScript 提交中击败了**14.78%**的用户\n\n```javascript\n/**\n * Definition for singly-linked list.\n * function ListNode(val) {\n *     this.val = val;\n *     this.next = null;\n * }\n */\n/**\n * @param {ListNode} head\n * @return {ListNode}\n */\nvar reverseList = function(head) {\n  if (!head) {\n    return head\n  }\n  let parentNode = null\n  while (head) {\n    let current = new ListNode(head.val)\n    current.next = parentNode\n    if (head.next) {\n      let next = new ListNode(head.next.val)\n      next.next = current\n    } else {\n      let next = null\n      return current\n    }\n    parentNode = current\n    head = head.next\n  }\n  return head\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0209._Minimum_Size_Subarray_Sum.md",
    "content": "# 209. Minimum Size Subarray Sum\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/minimum-size-subarray-sum\n\n> 内容描述\n\n```\nGiven an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead.\n\nExample: \n\nInput: s = 7, nums = [2,3,1,2,4,3]\nOutput: 2\nExplanation: the subarray [4,3] has the minimal length under the problem constraint.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n算法来源于知乎文章——[趣味算法思想](https://zhuanlan.zhihu.com/p/46223775)\n * 这里可以看到由于需要找连续的子数组，所以依旧可以设置两个指针，往同一方向移动。\n * 如果两个指针中间的值加起来>sum的时候，记录此时数组的长度，接着左指针移动，减小sum的值 ；\n * 如果< sum的话，右指针移动扩大范围。\n * 最后返回最短的长度值。\n\n\n\n代码：\n\n```javascript\n/**\n * @param {number} s\n * @param {number[]} nums\n * @return {number}\n */\nvar minSubArrayLen = function(s, nums) {\n  var left = 0;\n  var right = -1; // right 的起始位置很重要，这里选择-1 [left, right]这个区间刚开始是没有值的\n  var tmpSum = 0;\n  var minLength;\n\n  // 循环停止的条件是左指针小于长度\n  while (left < nums.length - 1) {\n    if(tmpSum < s) {\n      // 这里要注意边界的处理，当右指针移动到最后一个元素的时候结束\n      if(right >= nums.length -1) {\n        return minLength || 0;\n      }\n      right ++;\n      // 这里tmpSum的计算也很巧妙，直接用累加的方式，节省计算量\n      tmpSum = tmpSum + nums[right]\n    } else {\n      var tmp = right - left + 1;\n      if(minLength) {\n        if(tmp < minLength) {\n          minLength = tmp;\n        }\n      } else {\n        minLength = tmp;\n      }\n      // 左边指针移动减少sum的值\n      tmpSum = tmpSum - nums[left];\n      left ++;\n    } \n  }\n  if(!minLength) {\n    return 0;\n  }\n  return minLength;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0258._Add_Digits.md",
    "content": "# 258. Add Digits\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/add-digits\n\n> 内容描述\n\n```\nGiven a non-negative integer num, repeatedly add all its digits until the result has only one digit.\n\nExample:\n\nInput: 38\nOutput: 2 \nExplanation: The process is like: 3 + 8 = 11, 1 + 1 = 2. \n             Since 2 has only one digit, return it.\n             \nFollow up:\nCould you do it without any loop/recursion in O(1) runtime?\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(1)******- 空间复杂度: O(1)******\n\n* 原理：\n* 假设输入的数字是一个5位数字num，则num的各位分别为a、b、c、d、e \n* 有如下关系：num = a * 10000 + b * 1000 + c * 100 + d * 10 + e\n* 即：num = (a + b + c + d + e) + (a * 9999 + b * 999 + c * 99 + d * 9)  \n* 因为 a * 9999 + b * 999 + c * 99 + d * 9 一定可以被9整除，因此num模除9的结果与 a + b + c + d + e 模除9的结果是一样的。\n* 对数字 a + b + c + d + e 反复执行同类操作，最后的结果就是一个 1-9 的数字加上一串数字，最左边的数字是 1-9 之间的，右侧的数字永远都是可以被9整除的。\n* 这道题最后的目标，就是不断将各位相加，相加到最后，当结果小于10时返回。因为最后结果在1-9之间，得到9之后将不会再对各位进行相加，因此不会出现结果为0的情况。\n* 因为 (x + y) % z = (x % z + y % z) % z，又因为 x % z % z = x % z，因此结果为 (num - 1) % 9 + 1，只模除9一次，并将模除后的结果加一返回。\n \n代码：\n\n```javascript\n/**\n * @param {number} num\n * @return {number}\n */\nvar addDigits = function(num) {\n    if(num==0)\n        return num;\n    if(num%9==0)\n        return 9;\n    else return num%9;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0320._Coin_Change.md",
    "content": "# 322. Coin Change\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/coin-change/](https://leetcode-cn.com/problems/coin-change/)\n\n> 内容描述\n\n给定不同面额的硬币 `coins` 和一个总金额 `amount`。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额，返回 `-1`。\n\n#### 示例1：\n\n     输入: coins = [1, 2, 5], amount = 11\n     输出: 3 \n     解释: 11 = 5 + 5 + 1\n\n#### 示例2：\n\n     输入: coins = [2], amount = 3\n     输出: -1\n     \n\n#### 说明\n\n你可以认为每种硬币的数量是无限的。\n\n## 解题方案\n\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n动态规划，思路参考：[链接](https://leetcode-cn.com/problems/coin-change/solution/javadi-gui-ji-yi-hua-sou-suo-dong-tai-gui-hua-by-s/)\n\n代码：\n\n```javascript\n/**\n * @param {number[]} coins\n * @param {number} amount\n * @return {number}\n */\n\nvar coinChange = function(coins, amount) {\n  // 自底向上的动态规划\n  if(coins.length === 0){\n    return -1;\n  }\n  \n  // memo[n]的值： 表示的凑成总金额为n所需的最少的硬币个数\n  let memo = Array.from({ length: amount+1 });\n  memo[0] = 0;\n  for(let i = 1; i <= amount; i++){\n    let min = Number.MAX_VALUE;\n    for(let j = 0; j < coins.length; j++){\n      if(i - coins[j] >= 0 && memo[i-coins[j]] < min){\n        min = memo[i-coins[j]] + 1;\n      }\n    }\n    // memo[i] = (min == Integer.MAX_VALUE ? Integer.MAX_VALUE : min);\n    memo[i] = min;\n  }\n  \n  return memo[amount] === Number.MAX_VALUE ? -1 : memo[amount];\n};\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0347._Top_K_Frequent_Elements.md",
    "content": "# 0347. Top K Frequent Elements\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/top-k-frequent-elements/](https://leetcode-cn.com/problems/top-k-frequent-elements/)\n\n> 内容描述\n\n给定一个非空的整数数组，返回其中出现频率前 k 高的元素。\n\n\n#### 示例 1:\n\n     输入: nums = [1,1,1,2,2,3], k = 2\n     输出: [1,2]\n\n#### 示例 2:\n\n     输入: nums = [1], k = 1\n     输出: [1]\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N*k)******- 空间复杂度: O(N)******\n\n利用原生的sort方法，\n 1. 遍历原有数组，推导出每个数字出现的频率。\n 2. 根据出现的频率，利用sort进行排序\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @param {number} k\n * @return {number[]}\n */\nvar topKFrequent = function(nums, k) {\n  var list = {}\n  if (nums.length === k) {\n    return nums\n  }\n  while (nums.length) {\n    var num = nums.pop()\n    if (list[num]) {\n      list[num]++\n    } else {\n      list[num] = 1\n    }\n  }\n  \n  return Object.keys(list).sort((a, b) => {\n    return list[b] - list[a]\n  }).slice(0, k).map(n => Number(n))\n};\n```\n\n\n> 思路 2\n******- 时间复杂度: O(N*k)******- 空间复杂度: O(N)******\n\n自行实现的排序方式\n 1. 遍历原有数组，推导出每个数字出现的频率。\n 2. 利用快排实现排序\n\n```javascript\nlet partion = function(arr, left, right){\n    let i = left;\n    let j = right;\n    let base = arr[left];\n    while(i<j){\n        while(arr[j].freq<=base.freq && i<j){\n            j--;\n        }\n        while(arr[i].freq>=base.freq && i<j){\n            i++;\n        }\n        let tmp = arr[i];\n        arr[i] = arr[j];\n        arr[j] = tmp;\n    }\n    arr[left] = arr[i];\n    arr[i] = base;\n    return i;\n}\n\nlet quickSort = function(arr, left, right, k){\n    if(left < right){\n        let m = partion(arr, left, right);\n        if(m<k-1){\n            quickSort(arr, m+1, right, k);\n        }else if(m>k-1){\n            quickSort(arr, left, m-1, k);\n        }\n    }\n}\n\nlet Node = function(val, freq){\n    this.val = val;\n    this.freq = freq;\n}\nvar topKFrequent = function(nums, k) {\n    let map = {};\n    nums.forEach(e=>{\n        if(map[e]){\n            map[e].freq += 1;\n        }else{\n            map[e] = new Node(e, 1);\n        }\n    });\n    let arr = [];\n    for(let i in map){\n        arr.push(map[i]);\n    }\n    quickSort(arr, 0, arr.length-1, k);\n    let res = [];\n    for(let i=0; i<k; i++){\n        res.push(arr[i].val);\n    }\n    return res;\n};\n\n```\n"
  },
  {
    "path": "docs/leetcode/javascript/0402._Remove_K_Digits.md",
    "content": "# 402. Remove K Digits\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/remove-k-digits\n\n> 内容描述\n\n```\nGiven a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible.\n\nNote:\nThe length of num is less than 10002 and will be ≥ k.\nThe given num does not contain any leading zero.\nExample 1:\n\nInput: num = \"1432219\", k = 3\nOutput: \"1219\"\nExplanation: Remove the three digits 4, 3, and 2 to form the new number 1219 which is the smallest.\nExample 2:\n\nInput: num = \"10200\", k = 1\nOutput: \"200\"\nExplanation: Remove the leading 1 and the number is 200. Note that the output must not contain leading zeroes.\nExample 3:\n\nInput: num = \"10\", k = 2\nOutput: \"0\"\nExplanation: Remove all the digits from the number and it is left with nothing which is 0.\n\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* 使用栈的思路\n* 如果n是num的长度，我们要去除k个，那么需要剩下n-k个数，定义一个result数组用于保存剩下的字符，与result中最后一个字符相比，比它小，\n* 栈中最后一个字符出栈，该字符进栈，否则该字符直接进栈。值得注意的是在删除k个数之后，若剩下的数前面有0，应该去掉。\n\n代码：\n\n```javascript\n/**\n * @param {string} num\n * @param {number} k\n * @return {string}\n */\nvar removeKdigits = function(num, k) {\n    let stack = [], numDigits = num.length;\n    for (let i = 0; i < numDigits; i++) {\n        while(k > 0 && stack.length && stack[stack.length - 1] > num[i]) {\n            stack.pop();\n            k--;\n        }\n        stack.push(num[i]);\n    }\n    stack = k > 0 ? stack.slice(0, -k) : stack;\n    return stack.join('').replace(/^0+/, '') || '0';\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0406._Queue_Reconstruction_By_Height.md",
    "content": "# 406. Queue Reconstruction By Height\n\n**<font color=orange>难度: medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/queue-reconstruction-by-height/](https://leetcode-cn.com/problems/queue-reconstruction-by-height/)\n\n> 内容描述\n\n假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示，其中h是这个人的身高，k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。\n\n**注意：**\n总人数少于1100人。\n\n**示例 1:**\n\n```\n输入:\n[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]\n\n输出:\n[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]\n```\n\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N²)******- 空间复杂度: O(N)******\n\n贪心算法\n**思路**\n个子矮的人的位置不会影响到其他人，他的位置不会影响到其他人。\n\n**操作步骤**\n 1. 对人群排序，由高到低，身高相同再由低到高\n 2. 建立一个空队列\n 3. 对排序后的人群进行遍历，将当前遍历的人 按照他的索引（n）插入到队列第n的位置\n\n代码：\n\n```javascript\nvar reconstructQueue = function(people) {\n  people.sort((a, b) => ((b[0] - a[0]) || (a[1] - b[1])));\n  let queue = [];\n  people.forEach(person => {\n    queue.splice([person[1]], 0, person);\n  })\n  return queue\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0485._Max_Consecutive_Ones.md",
    "content": "# 485. Max Consecutive Ones\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/max-consecutive-ones\n\n> 内容描述\n\n```\nGiven a binary array, find the maximum number of consecutive 1s in this array.\n\nExample 1:\nInput: [1,1,0,1,1,1]\nOutput: 3\nExplanation: The first two digits or the last three digits are consecutive 1s.\n    The maximum number of consecutive 1s is 3.\nNote:\n\nThe input array will only contain 0 and 1.\nThe length of input array is a positive integer and will not exceed 10,000\n\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* 使用temp保存每个0之间的差值\n* 找出最大的差值即可\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @return {number}\n */\nvar findMaxConsecutiveOnes = function(nums) {\n    var max = 0,temp = 0;\n    for(var i =0;i<nums.length;i++){\n        nums[i]===0?temp=0:temp++;\n        max = Math.max(temp,max);\n    }\n    return max;\n};\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0539._Minimum_Time_Difference.md",
    "content": "# 539. Minimum Time Difference\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/minimum-time-difference\n\n> 内容描述\n\n```\nGiven a list of 24-hour clock time points in \"Hour:Minutes\" format, find the minimum minutes difference between any two time points in the list.\n\nExample 1:\nInput: [\"23:59\",\"00:00\"]\nOutput: 1\n\nNote:\nThe number of time points in the given list is at least 2 and won't exceed 20000.\nThe input time is legal and ranges from 00:00 to 23:59.\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N)******- 空间复杂度: O(N)******\n\n* 将所有时间转换成分钟数，然后进行sort排序\n* 计算两个数之间的差值，找出最小差值即可\n* 不要忘记第一个时间与最后一个时间相比较\n\n代码：\n\n```javascript\n/**\n * @param {string[]} timePoints\n * @return {number}\n */\nvar findMinDifference = function(timePoints) {\n    var dayTime = 24*60;\n    var minTime = 24*60;\n    var temp = timePoints.map(function (value) {\n        var t = value.split(':');\n        return parseInt(t[0])*60+parseInt(t[1]);\n    });\n    temp.sort(function (a,b) {\n        return a-b;\n    });\n    for(var i =0;i<temp.length;i++){\n        var diff;\n        var f=i-1,b=i;\n        if(i==0)\n            f=temp.length-1;\n        if((temp[f]-temp[b])>(dayTime/2)){\n            diff = Math.abs(temp[f]-(temp[b]+dayTime));\n            minTime = diff<minTime?diff:minTime;\n        }else {\n            diff = Math.abs(temp[f]-temp[b]);\n            minTime = diff<minTime?diff:minTime;\n        }\n    }\n    return minTime===1440?0:minTime;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0581._Shortest_Unsorted_Continuous_Subarray.md",
    "content": "# 581. 最短无序连续子数组\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* [https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/](https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/)\n\n> 内容描述\n\n给定一个整数数组，你需要寻找一个**连续的子数组**，如果对这个子数组进行升序排序，那么整个数组都会变为升序排序。\n\n你找到的子数组应是最短的，请输出它的长度。\n\n#### 示例1:\n     \n     输入: [2, 6, 4, 8, 10, 9, 15]\n     输出: 5\n     解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序，那么整个表都会变为升序排序。\n     \n#### 说明 :\n\n 1. 输入的数组长度范围在 [1, 10,000]。\n 2. 输入的数组可能包含重复元素 ，所以升序的意思是<=。\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(1)******- 空间复杂度: O(N)******\n\n#### 省空间的算法，但是耗时间\n\n每次循环，如果当前数组的第一位是最小值，则将其“弹出”；如果最后一位是最大值，则也将其“弹出”；如果以上两种情况都没有，则说明剩下的数组是最短无序连续子数组\n\n代码：\n\n```javascript\n/**\n * @param {number[]} nums\n * @return {number}\n */\nvar findUnsortedSubarray = function(nums) {\n  while (nums.length) {\n    if (nums[0] === Math.min(...nums)) {\n      nums.shift()\n    } else if (nums[nums.length - 1] === Math.max(...nums)) {\n      nums.pop()\n    } else {\n      return nums.length\n    }\n  }\n  return nums.length\n};\n```\n> 思路 2\n******- 时间复杂度: O(1)******- 空间复杂度: O(2N)******\n\n#### 省时间的算法，但是耗空间\n\n与上面方法比较，不用每次都计算最大值和最小值\n\n\n```javascript\nvar findUnsortedSubarray = function(nums) {\n  const newNums = [...nums]\n  nums.sort((a, b) => (a - b))\n  let startIndex = 0\n  let endIndex = 0\n//   正向查找\n  for (let i = 0; i < newNums.length; i++) {\n    if (nums[0] === newNums[i]) {\n      nums.shift()\n    } else {\n      break\n    }\n  }\n//  逆向查找\n  for (let j = newNums.length - 1; j > 0; j--) {\n    if (nums[nums.length - 1] === newNums[j]) {\n      nums.pop();\n    } else {\n      break\n    }\n  }\n  return nums.length;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0881._Boats_to_Save_People.md",
    "content": "# 881. Boats to Save People\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/boats-to-save-people\n\n> 内容描述\n\n```\nThe i-th person has weight people[i], and each boat can carry a maximum weight of limit.\n\nEach boat carries at most 2 people at the same time, provided the sum of the weight of those people is at most limit.\n\nReturn the minimum number of boats to carry every given person.  (It is guaranteed each person can be carried by a boat.)\n\n \n\nExample 1:\n\nInput: people = [1,2], limit = 3\nOutput: 1\nExplanation: 1 boat (1, 2)\nExample 2:\n\nInput: people = [3,2,2,1], limit = 3\nOutput: 3\nExplanation: 3 boats (1, 2), (2) and (3)\nExample 3:\n\nInput: people = [3,5,3,4], limit = 5\nOutput: 4\nExplanation: 4 boats (3), (3), (4), (5)\nNote:\n\n1 <= people.length <= 50000\n1 <= people[i] <= limit <= 30000\n\n```\n\n## 解题方案\n\n> 思路 1\n******- 时间复杂度: O(N logN)******- 空间复杂度: O(N)******\n\n* 使用贪心算法，将数组进行排序之后进行处理\n\n代码：\n\n```javascript\n/**\n * @param {number[]} people\n * @param {number} limit\n * @return {number}\n */\nvar numRescueBoats = function(people, limit) {\n    people.sort(function (a,b) { return a-b });\n    var num=0;\n    for(var left = 0,right = people.length-1;right-left>=0;right--){\n        if(people[left]+people[right]<=limit)\n            left++;\n        num++;\n    }\n    return num;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/0997._Find_The_Town_Judge.md",
    "content": "# 997. Find The Town Judge\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/find-the-town-judge/\n\n> 内容描述\n\n在一个小镇里，按从 1 到 N 标记了 N 个人。传言称，这些人中有一个是小镇上的秘密法官。\n\n如果小镇的法官真的存在，那么：\n\n1. 小镇的法官不相信任何人。\n2. 每个人（除了小镇法官外）都信任小镇的法官。\n3. 只有一个人同时满足属性 1 和属性 2 。\n\n给定数组 trust，该数组由信任对 trust[i] = [a, b] 组成，表示标记为 a 的人信任标记为 b 的人。\n\n如果小镇存在秘密法官并且可以确定他的身份，请返回该法官的标记。否则，返回 -1。\n\n**示例 1：**\n\n```\n输入：N = 2, trust = [[1,2]]\n输出：2\n```\n\n**示例 2：**\n\n```\n输入：N = 3, trust = [[1,3],[2,3]]\n输出：3\n```\n\n**示例 3：**\n\n```\n输入：N = 3, trust = [[1,3],[2,3],[3,1]]\n输出：-1\n```\n\n**示例 4：**\n\n```\n输入：N = 3, trust = [[1,2],[2,3]]\n输出：-1\n```\n\n**示例 5：**\n\n```\n输入：N = 4, trust = [[1,3],[1,4],[2,3],[2,4],[4,3]]\n输出：3\n```\n\n **提示：**\n\n1. `1 <= N <= 1000`\n2. `trust.length <= 10000`\n3. `trust[i]` 是完全不同的\n4. `trust[i][0] != trust[i][1]`\n5. `1 <= trust[i][0], trust[i][1] <= N`\n\n\n\n## 解题方案\n\n> 思路 \n> **- 时间复杂度: O(N)** \n>\n> **- 空间复杂度: O(N)**\n\n利用`trustedMap`来存储“被信任者”的列表，数组下标代表村民的“标记”，数组元素的值代表“被多少人信任”。\n\n利用`trustOtherMap`来存储“村民信任列表”，数组下标代表村民的“标记”，数组元素的值代表该村民“信任几个人”。\n\n根据题目，`每个人（除了小镇法官外）都信任小镇的法官。`所以`trustedMap`中值为`N-1`的那个元素下标即是法官；但是`小镇的法官不相信任何人。`所以上一步得到的标记所在`trustOtherMap`的值一定是空。\n\n> 执行用时 :**136 ms**, 在所有 JavaScript 提交中击败了**95.77%**的用户\n>\n> 内存消耗 :**43.4 MB**, 在所有 JavaScript 提交中击败了**68.00%**的用户\n\n代码：\n\n```javascript\n/**\n * @param {number} N\n * @param {number[][]} trust\n * @return {number}\n */\nvar findJudge = function(N, trust) {\n  let trustedMap = []\n  let trustOtherMap = []\n  if (N === 1 && trust.length === 0) {\n    return 1\n  }\n  trust.forEach(([person, trustedPerson]) => {\n    if (trustedMap[trustedPerson]) {\n      trustedMap[trustedPerson]++\n    } else {\n      trustedMap[trustedPerson] = 1\n    }\n    if (trustOtherMap[person]) {\n      trustOtherMap[person]++\n    } else {\n      trustOtherMap[person] = 1\n    }\n  })\n  const trustedPerson = trustedMap.findIndex(i => i === (N - 1))\n  if (trustedPerson !== -1 && !trustOtherMap[trustedPerson]) {\n    return trustedPerson\n  } else {\n    return -1\n  }\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/1025._Divisor_Game.md",
    "content": "# 1025. Divisor Game\n\n**<font color=green>难度: Esay</font>**\n\n## 刷题内容\n\n> 原题连接\n\n[https://leetcode-cn.com/problems/divisor-game/](https://leetcode-cn.com/problems/divisor-game/)\n\n> 内容描述\n\n爱丽丝和鲍勃一起玩游戏，他们轮流行动。爱丽丝先手开局。\n\n最初，黑板上有一个数字 N 。在每个玩家的回合，玩家需要执行以下操作：\n\n选出任一 x，满足 `0 < x < N` 且 `N % x == 0` 。\n用` N - x` 替换黑板上的数字` N `。\n如果玩家无法执行这些操作，就会输掉游戏。\n\n只有在爱丽丝在游戏中取得胜利时才返回 `True`，否则返回 `False`。假设两个玩家都以最佳状态参与游戏。\n\n#### 示例1:\n     \n     输入：2\n     输出：true\n     解释：爱丽丝选择 1，鲍勃无法进行操作。\n   \n   \n#### 示例2:\n     \n     输入：3\n     输出：false\n     解释：爱丽丝选择 1，鲍勃也选择 1，然后爱丽丝无法进行操作。\n\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(1)******- 空间复杂度: O(1)******\n\n\n```javascript\n/**\n * @param {number} N\n * @return {boolean}\n */\nvar divisorGame = function(N) {\n    return N % 2 === 0; \n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/1130._Minimum_Cost_Tree_From_Leaf_Values.md",
    "content": "# 1130. Minimum Cost Tree From Leaf Values\n\n**<font color=orange>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode-cn.com/problems/minimum-cost-tree-from-leaf-values/\n\n> 内容描述\n\n给你一个正整数数组 arr，考虑所有满足以下条件的二叉树：\n\n每个节点都有 0 个或是 2 个子节点。\n数组 arr 中的值与树的中序遍历中每个叶节点的值一一对应。（知识回顾：如果一个节点有 0 个子节点，那么该节点为叶节点。）\n每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积。\n在所有这样的二叉树中，返回每个非叶节点的值的最小可能总和。这个和的值是一个 32 位整数。\n\n**示例 1：**\n\n```\n输入：arr = [6,2,4]\n输出：32\n解释：\n有两种可能的树，第一种的非叶节点的总和为 36，第二种非叶节点的总和为 32。\n\n    24            24\n   /  \\          /  \\\n  12   4        6    8\n /  \\               / \\\n6    2             2   4\n```\n\n **提示：**\n\n- `2 <= arr.length <= 40`\n- `1 <= arr[i] <= 15`\n- 答案保证是一个 32 位带符号整数，即小于 `2^31`。\n\n## 解题方案\n\n> 思路 \n> **- 时间复杂度: O(N)** \n>\n> **- 空间复杂度: O(N)**\n\n> 执行用时 :**60 ms**, 在所有 javascript 提交中击败了**92.86%**的用户\n>\n> 内存消耗 :**33.5 MB**, 在所有 javascript 提交中击败了**100.00%**的用户\n\n代码：\n\n```javascript\n/**\n * @param {number[]} arr\n * @return {number}\n */\nvar mctFromLeafValues = function(arr) {\n  if (!arr.length || arr.length < 2) {\n    return 0\n  }\n  let res = 0;\n  let stack = [];\n  stack.unshift(Number.MAX_VALUE);\n  arr.forEach(num => {\n    while (stack[0] <= num) {\n      let mid = stack.shift()\n      res += mid * Math.min(stack[0], num);\n    }\n    stack.unshift(num);\n  })\n  \n  while (stack.length > 2) {\n    res += stack.shift() * stack[0]\n  }\n  return res;\n};\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/303._Range_Sum_Query_Immutable.md",
    "content": "# 303. Range Sum Query Immutable\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n[https://leetcode-cn.com/problems/range-sum-query-immutable/](https://leetcode-cn.com/problems/range-sum-query-immutable/)\n\n> 内容描述\n\n给定一个整数数组  nums，求出数组从索引 i 到 j  (i ≤ j) 范围内元素的总和，包含 i,  j 两点。\n\n#### 示例:\n     \n     给定 nums = [-2, 0, 3, -5, 2, -1]，求和函数为 sumRange()\n     \n     sumRange(0, 2) -> 1\n     sumRange(2, 5) -> -1\n     sumRange(0, 5) -> -3\n\n说明:\n\n 1. 你可以假设数组不可变。\n 2. 会多次调用 sumRange 方法。\n\n\n## 解题方案\n\n> 思路 \n******- 时间复杂度: O(1)******- 空间复杂度: O(N)******\n\n\n\n```javascript\n/**\n * @param {number[]} nums\n */\nvar NumArray = function(nums) {\n    this.value = nums\n};\n\n/** \n * @param {number} i \n * @param {number} j\n * @return {number}\n */\nNumArray.prototype.sumRange = function(i, j) {\n    return this.value.slice(i, j + 1).reduce((total, current) => total + current, 0)\n};\n\n/**\n * Your NumArray object will be instantiated and called as such:\n * var obj = new NumArray(nums)\n * var param_1 = obj.sumRange(i,j)\n */\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/javascript/README.md",
    "content": "# Leetcode JavaScript 题解\n\n> 看左侧栏，开始你的表演！\n"
  },
  {
    "path": "docs/leetcode/javascript/SUMMARY.md",
    "content": "+ [Leetcode JavaScript 题解](README.md)\n+ [0001 Two Sum](0001._Two_Sum.md)\n+ [0002 Add Two Numbers](0002._Add_Two_Numbers.md)\n+ [0003 Longest Substring without Repeating Characters](0003._Longest_Substring_without_Repeating_Characters.md)\n+ [0007 Reverse Integer](0007._Reverse_Integer.md)\n+ [0008 String to Integer](0008._String_to_Integer.md)\n+ [0009 Palindrome Number](0009._Palindrome_Number.md)\n+ [0011 Container With Most Water](0011._Container_With_Most_Water.md)\n+ [0012 Integer To Roman](0012._Integer_To_Roman.md)\n+ [0013 Roman To Integer](0013._Roman_To_Integer.md)\n+ [0014 Longest Common Prefix](0014._Longest_Common_Prefix.md)\n+ [0015 Three Sum](0015._Three_Sum.md)\n+ [0016 3 Sum Closest](0016._3_Sum_Closest.md)\n+ [0017 Letter Combinations Of A Phone Number](0017._Letter_Combinations_Of_A_Phone_Number.md)\n+ [0019 Remove Nth Node From End Of List](0019._Remove_Nth_Node_From_End_Of_List.md)\n+ [0020 Valid Parentheses](0020._Valid_Parentheses.md)\n+ [0021 Merge Two Sorted Lists](0021._Merge_Two_Sorted_Lists.md)\n+ [0022 Generate Parentheses](0022._Generate_Parentheses.md)\n+ [0024 Swap Nodes In Pairs](0024._Swap_Nodes_In_Pairs.md)\n+ [0027 Remove Element](0027._Remove_Element.md)\n+ [0031 Next Permutation](0031._Next_Permutation.md)\n+ [0035 Search Insert Position](0035._Search_Insert_Position.md)\n+ [0054 Spiral Matrix](0054._Spiral_Matrix.md)\n+ [0055 Jump Game](0055._Jump_Game.md)\n+ [0056 Merge Intervals](0056._Merge_Intervals.md)\n+ [0058 Length of Last Word](0058._Length_of_Last_Word.md)\n+ [0061 Rotate List](0061._Rotate_List.md)\n+ [0062 Unique Paths](0062._Unique_Paths.md)\n+ [0066 Plus One](0066._Plus_One.md)\n+ [0067 Add Binary](0067._Add_Binary.md)\n+ [0074 Search a 2D Matrix](0074._Search_a_2D_Matrix.md)\n+ [0079 Search Word](0079._Search_Word.md)\n+ [0083 Remove Duplicates From Sorted List](0083._Remove_Duplicates_From_Sorted_List.md)\n+ [0094 Binary Tree Inorder Traversal](0094._Binary_Tree_Inorder_Traversal.md)\n+ [0098 Validate Binary Search Tree](0098._Validate_Binary_Search_Tree.md)\n+ [0100 Same Tree](0100._Same_Tree.md)\n+ [0101 Symmetric Tree](0101._Symmetric_Tree.md)\n+ [0104 Maximum Depth of Binary Tree](0104._Maximum_Depth_of_Binary_Tree.md)\n+ [0106 Construct Binary Tree From Inorder And Postorder Traversal](0106._Construct_Binary_Tree_From_Inorder_And_Postorder_Traversal.md)\n+ [0141 Linked List Cycle](0141._Linked_List_Cycle.md)\n+ [0146 LRU Cache](0146._LRU_Cache.md)\n+ [0167 Two Sum II - Input array is sorted](0167._Two_Sum_II_-_Input_array_is_sorted.md)\n+ [0167 Two Sum II Input Array is Sorted](0167._Two_Sum_II_Input_Array_is_Sorted.md)\n+ [0171 Excel Sheet Column Number](0171._Excel_Sheet_Column_Number.md)\n+ [0179 Largest Number](0179._Largest_Number.md)\n+ [0203 Remove Linked List Elements](0203._Remove_Linked_List_Elements.md)\n+ [0206 Reverse-Linked-List](0206._Reverse-Linked-List.md)\n+ [0209 Minimum Size Subarray Sum](0209._Minimum_Size_Subarray_Sum.md)\n+ [0258 Add Digits](0258._Add_Digits.md)\n+ [0347 Top K Frequent Elements](0347._Top_K_Frequent_Elements.md)\n+ [0402 Remove K Digits](0402._Remove_K_Digits.md)\n+ [0406 Queue Reconstruction By Height](0406._Queue_Reconstruction_By_Height.md)\n+ [0485 Max Consecutive Ones](0485._Max_Consecutive_Ones.md)\n+ [0539 Minimum Time Difference](0539._Minimum_Time_Difference.md)\n+ [0581 Shortest Unsorted Continuous Subarray](0581._Shortest_Unsorted_Continuous_Subarray.md)\n+ [0881 Boats to Save People](0881._Boats_to_Save_People.md)\n+ [0997 Find The Town Judge](0997._Find_The_Town_Judge.md)\n+ [1130 Minimum Cost Tree From Leaf Values](1130._Minimum_Cost_Tree_From_Leaf_Values.md)\n"
  },
  {
    "path": "docs/leetcode/javascript/book.json",
    "content": "{\n    \"title\" : \"Pytorch 中文文档\",\n    \"author\" : \"ApacheCN\",\n    \"description\" : \"Pytorch 中文文档: 教程和文档\",\n    \"language\" : \"zh-hans\",\n    \"plugins\": [\n        \"github\",\n        \"github-buttons\",\n        \"-sharing\", \n        \"insert-logo\",\n        \"sharing-plus\",\n        \"back-to-top-button\",\n        \"code\",\n        \"copy-code-button\",\n        \"mathjax\",\n        \"pageview-count\",\n        \"edit-link\",\n        \"emphasize\",\n        \"alerts\",\n        \"auto-scroll-table\",\n        \"popup\",\n        \"hide-element\",\n        \"page-toc-button\",\n        \"tbfed-pagefooter\",\n        \"sitemap\",\n        \"advanced-emoji\",\n        \"expandable-chapters\",\n        \"splitter\",\n        \"search-pro\"\n    ],\n    \"pluginsConfig\": {\n        \"github\": {\n            \"url\": \"https://github.com/apachecn/Interview\"\n        },\n        \"github-buttons\": {\n            \"buttons\": [\n              {\n                \"user\": \"apachecn\",\n                \"repo\": \"Interview\", \n                \"type\": \"star\",\n                \"count\": true,\n                \"size\": \"small\"\n              }\n            ]\n        },\n        \"insert-logo\": {\n            \"url\": \"http://data.apachecn.org/img/logo.jpg\",\n            \"style\": \"background: none; max-height: 150px; min-height: 150px\"\n        },\n        \"hide-element\": {\n            \"elements\": [\".gitbook-link\"]\n        },\n        \"edit-link\": {\n            \"base\": \"https://github.com/apachecn/Interview/blob/master/docs/Algorithm/Leetcode/JavaScript\",\n            \"label\": \"编辑本页\"\n        },\n        \"sharing\": {\n            \"qzone\": true,\n            \"weibo\": true,\n            \"twitter\": false,\n            \"facebook\": false,\n            \"google\": false,\n            \"qq\": false,\n            \"line\": false,\n            \"whatsapp\": false,\n            \"douban\": false,\n            \"all\": [\n                \"qq\", \"douban\", \"facebook\", \"google\", \"linkedin\", \"twitter\", \"weibo\", \"whatsapp\"\n            ]\n        },\n        \"page-toc-button\": {\n            \"maxTocDepth\": 4,\n            \"minTocSize\": 4\n        },\n        \"tbfed-pagefooter\": {\n            \"copyright\":\"Copyright &copy ibooker.org.cn 2019\",\n            \"modify_label\": \"该文件修订时间： \",\n            \"modify_format\": \"YYYY-MM-DD HH:mm:ss\"\n        },\n        \"sitemap\": {\n            \"hostname\": \"http://pytorch.apachecn.org\"\n        }\n    },\n    \"my_links\" : {\n        \"sidebar\" : {\n            \"Home\" : \"https://www.baidu.com\"\n        }\n    },\n    \"my_plugins\": [\n        \"donate\",\n        \"todo\",\n        \"-lunr\",\n        \"-search\",\n        \"expandable-chapters-small\",\n        \"chapter-fold\",\n        \"expandable-chapters\",\n        \"expandable-chapters-small\",\n        \"back-to-top-button\",\n        \"ga\",\n        \"baidu\",\n        \"sitemap\",\n        \"tbfed-pagefooter\",\n        \"advanced-emoji\",\n        \"sectionx\",\n        \"page-treeview\",\n        \"simple-page-toc\",\n        \"ancre-navigation\",\n        \"theme-apachecn@git+https://github.com/apachecn/theme-apachecn#HEAD\",\n        \"pagefooter-apachecn@git+https://github.com/apachecn/gitbook-plugin-pagefooter-apachecn#HEAD\"\n    ],\n    \"my_pluginsConfig\": {\n        \"github-buttons\": {\n            \"buttons\": [\n              {\n                \"user\": \"apachecn\",\n                \"repo\": \"Interview\", \n                \"type\": \"star\",\n                \"count\": true,\n                \"size\": \"small\"\n              }, \n              {\n                \"user\": \"apachecn\",\n                \"width\": \"160\", \n                \"type\": \"follow\", \n                \"count\": true,\n                \"size\": \"small\"\n              }\n            ]\n        },\n        \"ignores\": [\"node_modules\"],\n        \"simple-page-toc\": {\n            \"maxDepth\": 3,\n            \"skipFirstH1\": true\n        },\n        \"page-toc-button\": {\n            \"maxTocDepth\": 2,\n            \"minTocSize\": 2\n        },\n        \"page-treeview\": {\n            \"copyright\": \"Copyright &#169; aleen42\",\n            \"minHeaderCount\": \"2\",\n            \"minHeaderDeep\": \"2\"\n        },\n        \"donate\": {\n        \t\"wechat\": \"微信收款的二维码URL\",\n        \t\"alipay\": \"支付宝收款的二维码URL\",\n        \t\"title\": \"\",\n        \t\"button\": \"赏\",\n        \t\"alipayText\": \"支付宝打赏\",\n        \t\"wechatText\": \"微信打赏\"\n    \t},\n        \"page-copyright\": {\n            \"description\": \"modified at\",\n            \"signature\": \"你的签名\",\n            \"wisdom\": \"Designer, Frontend Developer & overall web enthusiast\",\n            \"format\": \"YYYY-MM-dd hh:mm:ss\",\n            \"copyright\": \"Copyright &#169; 你的名字\",\n            \"timeColor\": \"#666\",\n            \"copyrightColor\": \"#666\",\n            \"utcOffset\": \"8\",\n            \"style\": \"normal\",\n            \"noPowered\": false\n          },\n          \"ga\": {\n              \"token\": \"UA-127082511-1\"\n          },\n          \"baidu\": {\n              \"token\": \"75439e2cbd22bdd813226000e9dcc12f\"\n          },\n        \"pagefooter-apachecn\": {\n            \"copyright\":\"Copyright &copy ibooker.org.cn 2019\",\n            \"modify_label\": \"该文件修订时间： \",\n            \"modify_format\": \"YYYY-MM-DD HH:mm:ss\"\n        }\n    }\n}\n"
  },
  {
    "path": "docs/leetcode/python/001._two_sum.md",
    "content": "# 1. Two Sum 两数之和\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/two-sum\n* https://leetcode-cn.com/problems/two-sum\n\n> 内容描述\n\n```\n给定 nums = [2, 7, 11, 15], target = 9\n\n因为 nums[0] + nums[1] = 2 + 7 = 9\n所以返回 [0, 1]\n```\n\n## 解题方案\n\n> 思路 1\n\n我们在找两个的和是否等于某一个值。\n\n如果是两两组合的笛卡尔积，相当于闭着眼碰运气，时间复杂度为: O(n^2) \n\n例如: \n\n```\n* 2+7     2+11    2+15\n* 7+11    7+15\n* 11+15\n```\n\n\n> 思路 2\n\n如果我们换一种方式: `target - 当前数字`, 需要的另外一个变量就变成已知！\n\n1. 通过字典(哈希 Hash)对nums建立词库表 loopup, 时间复杂度是 0(n)\n2. 判断差值是否存在 lookup 中, 时间复杂度是 0(1)\n3. 所以最后的结果就是: O(n) * O(1) = O(n)\n\n```python\nclass Solution(object):\n    def twoSum(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: List[int]\n        \"\"\"\n        lookup = {}\n        for i, num in enumerate(nums):\n            if target - num in lookup:\n                # 为什么先后顺序是 lookup[target - num], i\n                # 因为当前是i，而差值只能从 lookup 中找，而 lookup 是在 i 之前面入库的\n                # 所以 顺序是 lookup[target - num], i\n                return [lookup[target - num],i]\n            lookup[num] = i\n        return []\n\n    \nif __name__ == \"__main__\":\n\n    nums = [2, 7, 11, 15]\n    target = 9\n    so = Solution()\n    n = so.twoSum(nums, target)\n    print(\"结果: \", n)\n```\n"
  },
  {
    "path": "docs/leetcode/python/002._add_two_numbers.md",
    "content": "#  2. Add Two Numbers\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/add-two-numbers\n\n> 内容描述\n\n```\nYou are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.\n\nYou may assume the two numbers do not contain any leading zero, except the number 0 itself.\n\nExample:\n\nInput: (2 -> 4 -> 3) + (5 -> 6 -> 4)\nOutput: 7 -> 0 -> 8\nExplanation: 342 + 465 = 807.\n```\n\n## 解题方案\n\n> 思路 1\n\n全部变成数字做加法再换回去呗，这多暴力，爽！\n\n```python\nclass Solution(object):\n    def addTwoNumbers(self, l1, l2):\n        \"\"\"\n        :type l1: ListNode\n        :type l2: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if not l1:\n            return l2\n        if not l2:\n            return l1\n        \n        val1, val2 = [l1.val], [l2.val]\n        while l1.next:\n            val1.append(l1.next.val)\n            l1 = l1.next\n        while l2.next:\n            val2.append(l2.next.val)\n            l2 = l2.next\n            \n        num1 = ''.join([str(i) for i in val1[::-1]])\n        num2 = ''.join([str(i) for i in val2[::-1]])\n        \n        tmp = str(int(num1) + int(num2))[::-1]\n        res = ListNode(tmp[0])\n        run_res = res\n        for i in range(1, len(tmp)):\n            run_res.next = ListNode(tmp[i])\n            run_res = run_res.next\n        return res\n```\n> 思路 2\n\n可以使用递归，每次算一位的相加\n\n\n```python\nclass Solution(object):\n    def addTwoNumbers(self, l1, l2):\n        \"\"\"\n        :type l1: ListNode\n        :type l2: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if not l1:\n            return l2\n        if not l2:\n            return l1\n        \n        if l1.val + l2.val < 10:\n            l3 = ListNode(l1.val + l2.val)\n            l3.next = self.addTwoNumbers(l1.next, l2.next)\n\n        else:\n            l3 = ListNode(l1.val + l2.val - 10)\n            tmp = ListNode(1)\n            tmp.next = None\n            l3.next = self.addTwoNumbers(l1.next, self.addTwoNumbers(l2.next ,tmp))\n        return l3\n```\n"
  },
  {
    "path": "docs/leetcode/python/003._longest_substring_without_repeating_characters.md",
    "content": "### 3. Longest Substring Without Repeating Characters\n\n\n题目:\n<https://leetcode.com/problems/longest-substring-without-repeating-characters/>\n\n\n难度:\n\nMedium\n\n\n\n思路\n\n粗一看是dp，细一看是greedy\n\n我们先从第一个字符开始，只要碰到已经出现过的字符我们就必须从之前出现该字符的index开始重新往后看。\n\n例如‘xyzxlkjh’，当看到第二个‘x’时我们就应该从y开始重新往后看了。\n\n那么怎么判断字符已经出现过了呢？我们使用一个hashmap，将每一个已经阅读过的字符作为键，而它的值就是它在原字符串中的index，如果我们现在的字符不在hashmap里面我们就把它加进hashmap中去，因此，只要目前的这个字符在该hashmap中的值大于等于了这一轮字符串的首字符，就说明它已经出现过了，我们就将首字符的index加1，即从后一位又重新开始读，然后比较目前的子串长度与之前的最大长度，取大者。\n\n### 程序变量解释\n\n- l(字母L) 代表目前最大子串的长度\n- start 是这一轮未重复子串首字母的index\n- maps 放置每一个字符的index，如果maps.get(s[i], -1)大于等于start的话，就说明字符重复了，此时就要重置 l(字母L)  和start的值了，\n\n\n\n```python\nclass Solution(object):\n    def lengthOfLongestSubstring(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n\n        \"\"\"\n        l, start, n = 0, 0, len(s)\n        maps = {}\n        for i in range(n):\n            start = max(start, maps.get(s[i], -1)+1)\n            l = max(l, i - start+1)\n            maps[s[i]] = i\n        return l\n```\n\n```python\nclass Solution(object):\n    def lengthOfLongestSubstring(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        maps = {}\n        begin, end, counter, d = 0, 0, 0, 0\n        while end < len(s):\n            if s[end] in maps:\n                maps[s[end]] += 1\n            else:\n                maps[s[end]] = 1\n            if maps[s[end]] > 1:\n                counter += 1\n            end += 1\n            while counter > 0:\n                if maps[s[begin]] > 1:\n                    counter -= 1\n                maps[s[begin]] -= 1\n                begin += 1\n            d = max(d, end - begin)\n        return d\n```\n\n\n\n\n\n\nAuthor: Keqi Huang\n\nIf you like it, please spread your support\n\n![Support](/img/Algorithm/LeetCode/WechatIMG17.jpeg)\n"
  },
  {
    "path": "docs/leetcode/python/004._median_of_two_sorted_arrays.md",
    "content": "### 4. Median of Two Sorted Arrays\n\n题目:\n<https://leetcode.com/problems/median-of-two-sorted-arrays/>\n\n\n难度:\n\nHard\n\n\n一看到的时候，觉得跟CLRS书上的一道习题类似\n求X[1....n] Y[1....n] 的 median\n\n习题 9.3-8\n\n\nLet X[1..n] and Y [1..n] be two arrays, each containing n numbers already in sorted order. Give an O(lg n)-time algorithn to find the median of all 2n elements in arrays X and Y .\n\n\n> The median can be obtained recursively as follows. Pick the median of the sorted array A. This is just O(1) time as median is the n/2th element in the sorted array. Now compare the median of A, call is a∗ with median of B, b∗. We have two cases.\n\n- a∗ < b∗ : In this case, the elements in B[n/2 ···n] are also greater than a . So the median cannot lie in either A[1 · · · n/2 ] or B[n/2 · · · n]. So we can just throw these away and recursively\n\n- a∗ > b∗ : In this case, we can still throw away B[1··· n/2] and also A[ n/ · · · n] and solve a smaller subproblem recursively. \n\n\nIn either case, our subproblem size reduces by a factor of half and we spend only constant time to compare the medians of A and B. So the recurrence relation would be T (n) = T (n/2) + O(1) which has a solution T (n) = O(log n).\n\n\ndivide and conquer\n\n- 如果X[n/2] == Y[n/2]，则找到，return\n- 如果X[n/2] < Y[n/2],找X[n/2+1….n]和Y[1,2…n/2]之间\n- 否则找X[1..n/2]和Y[n/2…n]\n\n\n\n\n但是实际上不同，这里需要考虑的问题更多：\n\n- 两个数组长度不一样\n- 并不是只找一个median，如果median有两个，需要算平均\n\n思路\n\n把它转化成经典的findKth问题\n\n参考： <http://chaoren.is-programmer.com/posts/42890.html>\n\n\n首先转成求A和B数组中第k小的数的问题, 然后用k/2在A和B中分别找。\n\n\n比如k = 6, 分别看A和B中的第3个数, 已知 A1 < A2 < A3 < A4 < A5... 和 B1 < B2 < B3 < B4 < B5..., 如果A3 <＝ B3, 那么第6小的数肯定不会是A1, A2, A3, 因为最多有两个数小于A1, 三个数小于A2, 四个数小于A3。 关键点是从 k/2 开始来找。 \n\n\n\nB3至少大于5个数, 所以第6小的数有可能是B1 (A1 < A2 < A3 < A4 < A5 < B1), 有可能是B2 (A1 < A2 < A3 < B1 < A4 < B2), 有可能是B3 (A1 < A2 < A3 < B1 < B2 < B3)。那就可以排除掉A1, A2, A3, 转成求A4, A5, ... B1, B2, B3, ...这些数中第3小的数的问题, k就被减半了。每次都假设A的元素个数少, pa = min(k/2, lenA)的结果可能导致k == 1或A空, 这两种情况都是终止条件。 \n\n\n发问，为什么要从k/2开始寻找，依旧k = 6, 我可以比较A1 和 B5的关系么，可以这样做，但是明显的问题出现在如果A1 > B5，那么这个第6小的数应该存在于B6和A1中。\n\n如果A1 < B5，这个时间可能性就很多了，比如A1 < A2 < A3 < A4 < B1 < B2，各种可能，无法排除元素，所以还是要从k/2开始寻找。\n\n这个跟习题算法的区别是每次扔的东西明显少一些，但是k也在不断变小。下面的代码的时间复杂度是O(lg(m+n))\n\n\n```python\nclass Solution(object):\n    def findMedianSortedArrays(self, nums1, nums2):\n        \"\"\"\n        :type nums1: List[int]\n        :type nums2: List[int]\n        :rtype: float\n        \"\"\"\n        n = len(nums1) + len(nums2)\n        if n % 2 == 1:\n        \treturn self.findKth(nums1, nums2, n / 2 + 1)\n        else:\n        \tsmaller = self.findKth(nums1, nums2, n / 2)\n        \tbigger = self.findKth(nums1, nums2, n / 2 + 1)\n        \treturn (smaller + bigger) / 2.0\n\n\n    def findKth(self, A, B, k):\n    \tif len(A) == 0:\n    \t\treturn B[k-1]\n    \tif len(B) == 0:\n    \t\treturn A[k-1]\n    \tif k == 1 :\n    \t\treturn min(A[0],B[0])\n\n\n    \ta = A[ k / 2 - 1 ] if len(A) >= k / 2 else None\n    \tb = B[ k / 2 - 1 ] if len(B) >= k / 2 else None\n\n    \tif b is None or (a is not None and a < b):\n    \t\treturn self.findKth(A[k/2:], B, k - k/2)\n    \treturn self.findKth(A, B[k/2:],k - k/2)  #这里要注意：因为 k/2 不一定 等于 (k - k/2), \n\n\n```\n```python\n#python3里面要用向下取整函数才可以AC，否则报错，TypeError: list indices must be integers or slices, not float\n\nfrom math import floor\nclass Solution:\n    def findMedianSortedArrays(self, nums1, nums2):\n        \"\"\"\n        :type nums1: List[int]\n        :type nums2: List[int]\n        :rtype: float\n        \"\"\"\n        n = len(nums1) + len(nums2)\n        if n % 2 == 1:\n            return self.findKth(nums1, nums2, floor(n/2)+1)\n        else:\n            smaller = self.findKth(nums1, nums2, floor(n/2))\n            bigger = self.findKth(nums1, nums2, floor(n/2)+1)\n            return (smaller + bigger) / 2.0\n    def findKth(self, A, B, k):\n\n        if len(A) == 0:\n            return B[k-1]\n        if len(B) == 0:\n            return A[k-1]\n        if k == 1:\n            return min(A[0], B[0])\n        a = A[floor(k/2)-1] if len(A) >= k/2 else None\n        b = B[floor(k/2)-1] if len(B) >= k/2 else None\n        if b is None or (a is not None and a < b):\n            return self.findKth(A[floor(k/2):], B, k - floor(k/2))\n        else:\n            return self.findKth(A, B[floor(k/2):], k - floor(k/2))\n```\n\n这个findKth的算法单独抽出来也是题目。\n### 寻找最小的k个数\n\n题目描述\n\n输入n个整数，输出其中最小的k个。\n分析与解法\n\n## 解法一\n\n要求一个序列中最小的k个数，按照惯有的思维方式，则是先对这个序列从小到大排序，然后输出前面的最小的k个数。\n至于选取什么的排序方法，我想你可能会第一时间想到快速排序（我们知道，快速排序平均所费时间为n*logn），然后再遍历序列中前k个元素输出即可。因此，总的时间复杂度：```O（n * log n)+O(k)=O（n * log n）```。\n## 解法二\n\n咱们再进一步想想，题目没有要求最小的```k```个数有序，也没要求最后```n-k```个数有序。既然如此，就没有必要对所有元素进行排序。这时，咱们想到了用选择或交换排序，即：\n1. 遍历```n```个数，把最先遍历到的k个数存入到大小为```k```的数组中，假设它们即是最小的```k```个数；\n2. 对这```k```个数，利用选择或交换排序找到这k个元素中的最大值```kmax```（找最大值需要遍历这```k```个数，时间复杂度为```O（k））```；\n3. 继续遍历剩余```n-k```个数。假设每一次遍历到的新的元素的值为```x```，把```x```与```kmax```比较：如果```x``` < ```kmax``` ，用```x```替换```kmax```，并回到第二步重新找出k个元素的数组中最大元素kmax‘；如果```x >= kmax```，则继续遍历不更新数组。\n每次遍历，更新或不更新数组的所用的时间为```O（k）```或```O（0）```。故整趟下来，时间复杂度为```n*O（k）=O（n*k）```。\n## 解法三\n\n更好的办法是维护容量为k的最大堆，原理跟解法二的方法相似：\n1. 用容量为```k```的最大堆存储最先遍历到的```k```个数，同样假设它们即是最小的```k```个数；\n2. 堆中元素是有序的，令```k1<k2<...<kmax```（```kmax```设为最大堆中的最大元素）\n3. 遍历剩余n-k个数。假设每一次遍历到的新的元素的值为```x```，把```x```与堆顶元素```kmax```比较：如果```x < kmax```，用```x```替换```kmax```，然后更新堆（用时```logk```）；否则不更新堆。\n这样下来，总的时间复杂度:O（k+（n-k）*logk）=O（n*logk）。此方法得益于堆中进行查找和更新的时间复杂度均为：O(logk)（若使用解法二：在数组中找出最大元素，时间复杂度：O（k））。\n解法四\n\n在《数据结构与算法分析--c语言描述》一书，第7章第7.7.6节中，阐述了一种在平均情况下，时间复杂度为O（N）的快速选择算法。如下述文字：\n- 选取S中一个元素作为枢纽元v，将集合S-{v}分割成S1和S2，就像快速排序那样\n- 如果k <= |S1|，那么第k个最小元素必然在S1中。在这种情况下，返回QuickSelect(S1, k)。\n- 如果k = 1 + |S1|，那么枢纽元素就是第k个最小元素，即找到，直接返回它。\n- 否则，这第k个最小元素就在S2中，即S2中的第（k - |S1| - 1）个最小元素，我们递归调用并返回QuickSelect(S2, k - |S1| - 1)。此算法的平均运行时间为O(n)。\n\n示例代码如下：\n```C\n//QuickSelect 将第k小的元素放在 a[k-1]  \nvoid QuickSelect( int a[], int k, int left, int right )\n{\n    int i, j;\n    int pivot;\n\n    if( left + cutoff <= right )\n    {\n        pivot = median3( a, left, right );\n        //取三数中值作为枢纽元，可以很大程度上避免最坏情况\n        i = left; j = right - 1;\n        for( ; ; )\n        {\n            while( a[ ++i ] < pivot ){ }\n            while( a[ --j ] > pivot ){ }\n            if( i < j )\n                swap( &a[ i ], &a[ j ] );\n            else\n                break;\n        }\n        //重置枢纽元\n        swap( &a[ i ], &a[ right - 1 ] );  \n\n        if( k <= i )\n            QuickSelect( a, k, left, i - 1 );\n        else if( k > i + 1 )\n            QuickSelect( a, k, i + 1, right );\n    }\n    else  \n        InsertSort( a + left, right - left + 1 );\n}\n```\n这个快速选择SELECT算法，类似快速排序的划分方法。N个数存储在数组S中，再从数组中选取“中位数的中位数”作为枢纽元X，把数组划分为Sa和Sb俩部分，Sa<=X<=Sb，如果要查找的k个元素小于Sa的元素个数，则返回Sa中较小的k个元素，否则返回Sa中所有元素+Sb中小的k-|Sa|个元素，这种解法在平均情况下能做到O(n)的复杂度。\n更进一步，《算法导论》第9章第9.3节介绍了一个最坏情况下亦为O(n)时间的SELECT算法，有兴趣的读者可以参看。\n\n给定两个已经排序好的数组，求第k大的，算法有O(m+n).类似merge sort的原理。否则利用的就是之上提到的，利用已经有序的原理，然后每次丢。\n\n之所以这里还有一个丢弃条件是b is None 丢A的一部分，是因为B的数组长度是有限的，这个时候很明显丢A的k/2是不影响的，因为无论B[-1]是如何大或者小，因为整个B的长度没有达到k/2小，所以丢掉的这部分最大的A[k/2-1]也不可能是第k个，因为即使整个B都比A[k/2-1]小，拼起来也不能使A[k/2-1]第k大，所以可以放心丢弃。\n\n\n这里是两个sorted list/array findKth，想到了类似的题目，如果给一个n个linked list，findKth，能想到的办法也只能是用heap吧，类似merge k sorted lists.\n\n\n再写一个O(m+n)类似merge sort的也可以AC的代码\n\n```python\nclass Solution(object):\n    def findMedianSortedArrays(self, nums1, nums2):\n        \"\"\"\n        :type nums1: List[int]\n        :type nums2: List[int]\n        :rtype: float\n        \"\"\"\n        def findKth(A, pa, B, pb, k):\n            res = 0\n            m = 0\n            while pa < len(A) and pb < len(B) and m < k:\n                if A[pa] < B[pb]:\n                    res = A[pa]\n                    m += 1\n                    pa += 1\n                else:\n                    res = B[pb]\n                    m += 1\n                    pb += 1\n                    \n            while pa < len(A) and m < k:\n                res = A[pa]\n                pa += 1\n                m += 1\n\n\n            while pb < len(B) and m < k:\n                res = B[pb]\n                pb += 1\n                m += 1\n            return res\n\n        n = len(nums1) + len(nums2)\n        if n % 2 == 1:\n        \treturn findKth(nums1,0, nums2,0, n / 2 + 1)\n        else:\n        \tsmaller = findKth(nums1,0, nums2,0, n / 2)\n        \tbigger = findKth(nums1,0, nums2,0, n / 2 + 1)\n        \treturn (smaller + bigger) / 2.0\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/005._longest_palindromic_substring.md",
    "content": "### 5. Longest Palindromic Substring\n\n题目:\n\nhttps://leetcode.com/problems/longest-palindromic-substring/\n\n难度:\n\nMedium\n\n\n\n思路0:\n\n暴力解法绝对不行\n\n思路1:\n\n所以一个好的想法是 s 和 reverse(s) 共有的最长的 substring就是longest palindromic substring -> 问题转成求Longest common substring problem\n\n参见wikipedia\n\n，典型动归\n\nLCSuff(S1...p, T1...q) = LCS(S1...p1, T1...q-1) if S[p] = T[q] else 0\n\n\n\n伪码也有了，代码也有：\n\nhttps://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring#Python_2\n\n这样也超时？\n```python\n    class Solution(object):\n        def longestPalindrome(self, s):\n            \"\"\"\n            :type s: str\n            :rtype: str\n            \"\"\"\n            def lcs(s1, s2):\n                m = [[0] * (1 + len(s2)) for i in xrange(1 + len(s1))]\n                longest, x_longest = 0, 0\n                for x in xrange(1, 1 + len(s1)):\n                    for y in xrange(1, 1 + len(s2)):\n                        if s1[x - 1] == s2[y - 1]:\n                            m[x][y] = m[x - 1][y - 1] + 1\n                            if m[x][y] > longest:\n                                longest = m[x][y]\n                                x_longest = x\n                        else:\n                            m[x][y] = 0\n                return s1[x_longest - longest: x_longest]\n    \n            return lcs(s, s[::-1])\n```\n因为以为这样s[::-1]已经很快了.\n\n这个方法是buggy的，看字符串abcxgcba,它reverse之后是abcgxcba,它们有公共字符串，但是这里面没有回文，修复方式是：\n\nwe check if the substring’s indices are the same as the reversed substring’s original indices. If it is, then we attempt to update the longest palindrome found so far; if not, we skip this and find the next candidate.\n\n我觉得的修复方式这样么：\n\n    原本     翻转\n    ABXYBA   ABYXBA\n    \n    求出来的substring indices是 0:2 但是这个s1[0:2] 和 s2[0:2]一样，所以不行\n    同理common substring indices还是s[4:6] 和s2[4:6]一样，不行\n    \n    而比如ABAD和 DABA\n    \n    substring indice 一个是0：3， 一个是1:4，这样就没问题\n    \n\n\n\n思路2:\n\n\n\n依次把每一个字符当做回文字符串的中间字符，找到以该字符为中间字符的回文串的最大长度。分别对奇偶的情况进行讨论，接下来的关键就是对边界的把握，确保下标不要越界。当子串已经包含首字符或最后一个字符且此时还是回文串的时候，下标分别会向两边多移一位，需要补回来。\n\n参考https://shenjie1993.gitbooks.io/leetcode-python/content/005%20Longest%20Palindromic%20Substring.html\n```python\n    class Solution(object):\n        def longestPalindrome(self, s):\n            \"\"\"\n            :type s: str\n            :rtype: str\n            \"\"\"\n            n = len(s)\n    \n            # empty or one char\n            if n < 2:\n                return s\n    \n            # left index of the target substring\n            l = 0\n            # right index of the target substring\n            r = 0\n            # length of the longest palindromic substring for now\n            m = 0\n            # length of the current substring\n            c = 0\n    \n            # Whether the substring contains the first character or last character and is palindromic\n            b = True\n            for i in range(n):\n                # Odd situation\n                for j in range(min(n-i,i+1)):\n                    if s[i-j] != s [i+j]:\n                        b = False\n                        break\n                    else:\n                        c = 2 * j + 1\n    \n                if c > m :\n                    l = i - j + 1 - b\n                    r = i + j + b\n                    m = c \n                b = True\n    \n                # Even situation\n                for j in range(min(n - i - 1, i + 1)):\n                    if (s[i - j] != s[i + j + 1]):\n                        b = False\n                        break\n                    else:\n                        c = 2 * j + 2\n                if (c > m):\n                    l = i - j + 1 - b\n                    r = i + j + 1 + b\n                    m = c\n                b = True\n            return s[l:r]\n```\n以上是参考版本，自己写的版本：\n```python\n    class Solution(object):\n        def longestPalindrome(self, s):\n            \"\"\"\n            :type s: str\n            :rtype: str\n            \"\"\"\n            n = len(s)\n    \n            m,l,r = 0,0,0\n    \n            for i in range(n):\n                # odd case\n                for j in range(min(i+1,n-i)):\n                    if s[i-j] != s[i+j]:\n                        break\n                    if 2*j + 1 > m :\n                        m = 2 * j + 1\n                        l = i-j\n                        r = i+j\n    \n    \n                if i+1 < n and s[i] == s[i+1]:\n                    for j in range(min(i+1,n-i-1)):\n                        if s[i-j] != s[i+j+1]:\n                            break\n                        if 2 * j + 2 > m :\n                            m = 2*j +2\n                            l = i-j\n                            r = i+j+1\n    \n    \n            return s[l:r+1]\n```\n\n\n思路3:\n\n[Manacher算法](https://www.felix021.com/blog/read.php?2040) \n\nManacher算法增加两个辅助变量id和mx，其中id表示最大回文子串中心的位置，mx则为id+P[id]，也就是最大回文子串的边界。得到一个很重要的结论：\n\n- 如果mx > i，那么P[i] >= Min(P[2 * id - i], mx - i) . 为什么这样说呢，下面解释\n\n下面，令j = 2*id - i，也就是说j是i关于id的对称点。\n\n- 当 mx - i > P[j] 的时候，以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中，由于i和j对称，以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中，所以必有P[i] = P[j]；\n![](/img/Algorithm/LeetCode/manacher1.png)\n\n- 当 P[j] >= mx - i 的时候，以S[j]为中心的回文子串不一定完全包含于以S[id]为中心的回文子串中，但是基于对称性可知，下图中两个绿框所包围的部分是相同的，也就是说以S[i]为中心的回文子串，其向右至少会扩张到mx的位置，也就是说 P[i] >= mx - i。至于mx之后的部分是否对称，再具体匹配。\n![](/img/Algorithm/LeetCode/manacher2.png)\n所以P[i] >= Min(P[2 * id - i], mx - i)，因为以j为中心的绘回文子串的左边界可能会比mx关于id的对称点要大，此时只能证明P[i]=P[2 * id - i]\n- 此外，对于 mx <= i 的情况，因为无法对 P[i]做更多的假设，只能让P[i] = 1，然后再去匹配。\n\n在下面的程序中我的P数组保存的是，以当前字符为回文子串中心时，该回文子串的长度（不包含当前字符自身）\n\n\n简单地用一个小例子来解释：原字符串为'qacbcaw'，一眼就可以看出来最大回文子串是'acbca'，\n下面是我做的图，累shi了！\n\n![](/img/Algorithm/LeetCode/manacher3.jpg)\n\n\n\n所以最终代码中的max_i就是字符'b'所对应的index8，start的值就是(max_i - P[max_i] - 1) / 2 = 1,最终输出结果为s[1:6],即‘acbca’\n\n```python\nclass Solution(object):\n    def longestPalindrome(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        def preProcess(s):\n            if not s:\n                return ['^', '&']\n            T = ['^']\n            for i in s:\n                T += ['#', i]\n            T += ['#', '$']\n            return T\n        T = preProcess(s)\n        P = [0] * len(T)\n        id, mx = 0, 0\n        for i in range(1, len(T)-1):\n            j = 2 * id - i\n            if mx > i:\n                P[i] = min(P[j], mx-i)\n            else:\n                P[i]= 0\n            while T[i+P[i]+1] == T[i-P[i]-1]:\n                P[i] += 1\n            if i + P[i] > mx:\n                id, mx = i, i + P[i]\n        max_i = P.index(max(P))    #保存的是当前最大回文子串中心位置的index\n        start = (max_i - P[max_i] - 1) / 2\n        res = s[start:start+P[max_i]]\n        return res\n```\nrun code的时候结果会跟expected不一样，但是该input确实2个结果都可以，所以放心地submit吧\n还可以转到[647题](https://github.com/Lisanaaa/thinking_in_lc/blob/master/647._Palindromic_Substrings.md)去看一看，也可以用这个算法解\n\n\n"
  },
  {
    "path": "docs/leetcode/python/006._ZigZag_Conversion.md",
    "content": "# 6. ZigZag Conversion\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/zigzag-conversion/\n\n> 内容描述\n\n```\nThe string \"PAYPALISHIRING\" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)\n\nP   A   H   N\nA P L S I I G\nY   I   R\nAnd then read line by line: \"PAHNAPLSIIGYIR\"\n\nWrite the code that will take a string and make this conversion given a number of rows:\n\nstring convert(string s, int numRows);\nExample 1:\n\nInput: s = \"PAYPALISHIRING\", numRows = 3\nOutput: \"PAHNAPLSIIGYIR\"\nExample 2:\n\nInput: s = \"PAYPALISHIRING\", numRows = 4\nOutput: \"PINALSIGYAHRPI\"\nExplanation:\n\nP     I    N\nA   L S  I G\nY A   H R\nP     I\n```\n\n## 解题方案\n\n> 思路 1\n\n参考大神[pharrellyhy](https://leetcode.com/problems/zigzag-conversion/discuss/3404/Python-O(n)-Solution-in-96ms-(99.43)?page=2)的思路,\n纵向思维考虑，```index```从```0```开始，我们要一直***自增***直到```numRows-1```，此后又一直***自减***到```0```，重复执行。\n给个例子容易懂一些：```s = “abcdefghijklmn”```, ```numRows = 4```\n```\na   g   m\nb f h l n\nc e i k\nd   j\n```\n看明白了吗，下来上去，下来上去，zigzag\n\n\n```python\nclass Solution(object):\n    def convert(self, s, numRows):\n        \"\"\"\n        :type s: str\n        :type numRows: int\n        :rtype: str\n        \"\"\"\n        if numRows == 1 or numRows >= len(s):\n            return s\n        res = [''] * numRows\n        idx, step = 0, 1\n    \n        for x in s:\n            res[idx] += x\n            if idx == 0:  ## 第一行，一直向下走\n                step = 1\n            elif idx == numRows - 1: ## 最后一行了，向上走\n                step = -1\n            idx += step\n        return ''.join(res)\n```\n假设用我上面给的例子，并且在```L[index] += x```这一行后面打印出index, step, L的值, 输出结果如下：\n```\n(0, 1, ['a', '', '', ''])\n(1, 1, ['a', 'b', '', ''])\n(2, 1, ['a', 'b', 'c', ''])\n(3, 1, ['a', 'b', 'c', 'd'])\n(2, -1, ['a', 'b', 'ce', 'd'])\n(1, -1, ['a', 'bf', 'ce', 'd'])\n(0, -1, ['ag', 'bf', 'ce', 'd'])\n(1, 1, ['ag', 'bfh', 'ce', 'd'])\n(2, 1, ['ag', 'bfh', 'cei', 'd'])\n(3, 1, ['ag', 'bfh', 'cei', 'dj'])\n(2, -1, ['ag', 'bfh', 'ceik', 'dj'])\n(1, -1, ['ag', 'bfhl', 'ceik', 'dj'])\n(0, -1, ['agm', 'bfhl', 'ceik', 'dj'])\n(1, 1, ['agm', 'bfhln', 'ceik', 'dj'])\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/007._Reverse_Integer.md",
    "content": "# 7. Reverse Integer 整数反转\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/Reverse-Integer\n* https://leetcode-cn.com/problems/reverse-integer\n\n> 内容描述\n\n```python\n给定一个 32 位有符号整数，将整数中的数字进行反转\n\n> 示例 1:\n\n输入: 123\n输出: 321\n\n> 示例 2:\n\n输入: -123\n输出: -321\n\n> 示例 3:\n\n输入: 120\n输出: 21\n\n注意:\n假设我们的环境只能存储 32 位有符号整数，其数值范围是 [−2^31,  2^31 − 1]\n根据这个假设，如果反转后的整数溢出，则返回 0\n```\n\n## 解题方案\n\n* 翻转数字问题需要注意的就是溢出问题，为什么会存在溢出问题呢\n* 我们知道int型的数值范围是: -2147483648～2147483647(-2^31 ~ 2^31-1)\n* 那么如果我们要翻转 1000000009 这个在范围内的数得到 9000000001，而翻转后的数就超过了范围\n\n> 思路1\n\n1. 记录符号\n2. 将数字当字符串处理\n3. 判断是否阈值区间，进行比较就行\n\n```python\nclass Solution:\n    def reverse(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        mark = 1 if x>=0 else -1\n        x_abs = abs(x)\n        result = mark * int(str(x_abs)[::-1])\n        return result if -2**31 <= result <= 2**31-1 else 0\n\n\nif __name__ == \"__main__\":\n    num = -12395\n    so = Solution()\n    n = so.reverse(num)\n    print(\"结果: \", n)\n```\n\n> 思路2\n\n如果输入的是负数，就递归调用原函数，参数变成-x即可\n\n```python\nclass Solution(object):\n    def reverse(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        if x < 0:\n            return -self.reverse(-x)\n        res = 0\n        while x:\n            res = res * 10 + x % 10\n            x /= 10\n        return res if res <= 0x7fffffff else 0\n```\n\n> 思路3\n\n按照参数正负号先将其转成字符串，然后再反转，根据是否溢出决定输出0还是反转结果\n\n```python\nclass Solution(object):\n    def reverse(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"    \n        x = -int(str(x)[::-1][:-1]) if x < 0 else int(str(x)[::-1])   # [:-1]相当于把负号去掉\n        x = 0 if abs(x) > 0x7FFFFFFF else x\n        return x\n```\n\n> 思路4(StefanPochmann大神)：\n\n看这个解法前先看 [backticks](https://docs.python.org/2.7/reference/expressions.html#string-conversions)\n\ncmp函数在python3.x中用不了了，import operator用gt或者lt吧，或者回归if/else condition爸爸的怀抱吧！\n\n```python\nclass Solution(object):\n    def reverse(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        s = cmp(x, 0)\n        r = int(`s * x`[::-1])\n        return s * r * (r < 2 ** 31)\n```\n"
  },
  {
    "path": "docs/leetcode/python/008._string_to_integer_(atoi).md",
    "content": "### 8. String to Integer (atoi)\n\n题目:\n<https://leetcode.com/problems/string-to-integer-atoi/>\n\n\n难度:\nMedium\n\n\n需要考虑比较多的边界条件&特殊情况\n1. 首先输入可能会有空格，所以先去掉空格\n2. 去掉空格后要考虑空字符串情况\n3. 字符串首位可能会有正负号，要考虑\n4. 开始转换成数字，题目说只要遇到非数字就可以break了\n5. 结果太大或者太小超过```int```限制就要返回特定数字 ```2147483647``` 或者 ```-2147483648```\n6. 根据之前的正负号结果返回对应数值\n\n\n```python\nclass Solution(object):\n\tdef myAtoi(self, str):\n\t\t\"\"\"\n\t\t:type str: str\n\t\t:rtype: int\n\t\t\"\"\"\n\t\tstr = str.strip()\n\t\tstrNum = 0\n\t\tif len(str) == 0:\n\t\t\treturn strNum\n\n\t\tpositive = True\n\t\tif str[0] == '+' or str[0] == '-':\n\t\t\tif str[0] == '-':\n\t\t\t\tpositive = False\n\t\t\tstr = str[1:]\n\t\t\n\t\tfor char in str:\n\t\t\tif char >='0' and char <='9':\n\t\t\t\tstrNum = strNum * 10 +  ord(char) - ord('0')\n\t\t\tif char < '0' or char > '9':\n\t\t\t\tbreak\n\n\t\tif strNum > 2147483647:\n\t\t\tif positive == False:\n\t\t\t\treturn -2147483648\n\t\t\telse:\n\t\t\t\treturn 2147483647\n\t\tif not positive:\n\t\t\tstrNum = 0 - strNum\n\t\treturn strNum\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/009._Palindrome_Number.md",
    "content": "# 9. Palindrome Number 回文数\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/palindrome-number\n* https://leetcode-cn.com/problems/palindrome-number\n\n> 内容描述\n\n```\n判断一个整数是否是回文数。【回文数是指正序（从左向右）和倒序（从右向左）读都是一样的整数】\n\n示例 1:\n\n输入: 121\n输出: true\n\n\n示例 2:\n\n输入: -121\n输出: false\n解释: 从左向右读为 -121，从右向左读为 121-，因此它不是一个回文数\n\n\n示例 3:\n\n输入: 10\n输出: false\n解释: 从右向左读为01，因此它不是一个回文数\n```\n\n## 解题方案\n\n> 思路1\n\n* 排除小于0的数\n* 通过字符串进行反转，对比数字是否相等就行\n\n```python\nclass Solution:\n    def isPalindrome(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: bool\n        \"\"\"\n        if x < 0:\n            return False\n        elif x != int(str(x)[::-1]):\n            return False\n        else:\n            return True\n\n    \nif __name__ == \"__main__\":\n    target = 12421\n    so = Solution()\n    status = so.isPalindrome(target)\n    print(\"结果: \", status)\n```\n\n\n> 思路2\n\n* 排除小于0的数\n* 数字通过 % 10 求余数进行反转，进而得到最终反转的结果\n* 对比反转的结果是最初的结果是否相等\n\n```python\nclass Solution(object):\n    def isPalindrome(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: bool\n        \"\"\"\n        if x < 0:\n            return False\n        rev, y = 0, x\n        while x > 0:\n            rev = rev * 10 + x % 10\n            print(\"余数: %s - 余数反转结果: %s\" % (rev, x % 10))\n            x = int(x/10)\n        return y == rev\n\n    \nif __name__ == \"__main__\":\n    target = 12321\n    so = Solution()\n    n = so.isPalindrome(target)\n    print(\"结果: \", n)\n\"\"\"\n余数: 1 - 余数反转结果: 1\n余数: 12 - 余数反转结果: 2\n余数: 123 - 余数反转结果: 3\n余数: 1232 - 余数反转结果: 2\n余数: 12321 - 余数反转结果: 1\n结果:  True\n\"\"\"\n```\n"
  },
  {
    "path": "docs/leetcode/python/010._regular_expression_matching.md",
    "content": "### 010. Regular Expression Matching\n\n题目:\n<https://leetcode.com/problems/regular-expression-matching/>\n\n\n难度:\n\nHard\n\n\n\n\n先尝试暴力解法，难点就在 * 身上， * 不会单独出现，它一定是和前面一个字母或\".\"配成一对。看成一对后\"X*\"，它的性质就是：要不匹配0个，要不匹配连续的“X”.所以尝试暴力解法的时候一个trick是从后往前匹配.\n\n\n\n暴力解法居然也能AC?\n\n是这样来分情况看得:\n\n- 如果s[i] = p[j] 或者 p[j]= . ： 往前匹配一位\n- 如果p[j] = ' * ', 检查一下，如果这个时候p[j-1] = . 或者p[j-1] = s[i] ，那么就往前匹配，如果这样能匹配过，就return True， 否者我们忽略 ' X* ',这里注意里面的递推关系\n- 再处理一下边界状况：\n\t- s已经匹配完了， 如果此时p还有，那么如果剩下的是 X* 这种可以过，所以检查\n\t- p匹配完毕，如果s还有那么报错\n\n```python\nclass Solution(object):\n    def isMatch(self, s, p):\n        \"\"\"\n        :type s: str\n        :type p: str\n        :rtype: bool\n        \"\"\"\n        def helper(s, i, p, j):\n            if j == -1:\n                return i == -1\n            if i == -1:\n                if p[j] != '*':\n                    return False\n                return helper(s, i, p, j-2)\n            if p[j] == '*':\n                if p[j-1] == '.' or p[j-1] == s[i]:\n                    if helper(s, i-1, p, j):\n                        return True\n                return helper(s, i, p, j-2)\n            if p[j] == '.' or p[j] == s[i]:\n                return helper(s, i-1, p, j-1)\n            return False\n\n        return helper(s, len(s)-1, p, len(p)-1)\n```\n\n\n\n----------\n\ndp优化，感觉和edit distance很像。 DP优化待代码化，感觉学DP的一个重点除了递归学好以外，另一点是一定要会画表格。\n\n\n画一个表格来看一下状况\n\n```\n\t\t\tc\t*\ta\t*\tb\n\t\t0\t1\t2\t3\t4\t5\n\t0\t1\t0\t1\t0\t1\t0\t\t\na\t1\t0\t0\t0\t1\t1\t0\t\t\t\t\t\na\t2\t0\t0\t0\t0\t1\t0\t\t\t\t\t\nb\t3\t0\t0\t0\t0\t0\t1\t\t\t\n\n```\n\n这里有几个取巧/容易出问题的敌方，这里画的表用的是1-based string。一上来，做的事包括：\n\n-\t初始化，空字符匹配：dp[0][0] =1\n-\t第一行，c* 可以匹配空字符，c* a* 可以匹配空字符，p[j-1] != s[i]，匹配空字符\n-\t然后进入第二行再来看，实际上我们可以看到，如果没有碰到 * 匹配还是很朴素的，但是碰到 * ：\n\t- 1这个匹配可以从左侧传来，dp[i][j] = dp[i][j-1]，that is 匹配 1个\n\t- 1 也可以有上方传来，这种情况是p[j-1] = s[i]，匹配多个 dp[i][j] = dp[i-1][j]\n\t- 1 这个匹配也可以从间隔一个的左侧传来，that is也可以有个性的匹配0个,如同匹配空字符一样dp[i][j] = dp[i][j-2]，但是注意匹配0个实际上有两种状况，如果p[j-1]!=s[i],强制匹配0个，即使p[j-1] == s[i],我们也可以傲娇的用它来匹配0个。\n\n再代码化一点：\n\n- s[i] == p[j] 或者 p[j] == '.' : dp[i][j] = dp[i-1][j-1]\n- p[j] == '*': 然后分几种情况\n\t- p[j-1] != s[i] : dp[i][j] = dp[i][j-2]  匹配0个的状况\n\t- p[j-1] == s[i] or p[i-1] == '.':\n\t\t- dp[i][j] = dp[i-1][j] 匹配多个s[i]\n\t\t- dp[i][j] = dp[i][j-2] 匹配0个\n\nAC代码，注意一下，因为上表为了表达方便，用的是1-based string系统，实际写代码的时候我们心里还是清楚这个string还是从0开始的，不过也可以尝试往前面添东西来方便。\n\n\nAC代码\n\n```python\nclass Solution(object):\n    def isMatch(self, s, p):\n        \"\"\"\n        :type s: str\n        :type p: str\n        :rtype: bool\n        \"\"\"\n        m, n = len(s), len(p)\n        dp = [ [0 for i in range(n+1)] for j in range(m+1)]\n\n        dp[0][0] = 1\n\n        # init the first line\n        for i in range(2,n+1):\n            if p[i-1] == '*':\n                dp[0][i] = dp[0][i-2]\n\n        for i in range(1,m+1):\n            for j in range(1,n+1):\n                if p[j-1] == '*':\n                    if p[j-2] != s[i-1] and p[j-2] != '.':\n                        dp[i][j] = dp[i][j-2]\n                    elif p[j-2] == s[i-1] or p[j-2] == '.':\n                        dp[i][j] = dp[i-1][j] or dp[i][j-2]\n\n                elif s[i-1] == p[j-1] or p[j-1] == '.':\n                    dp[i][j] = dp[i-1][j-1]\n\n        return dp[m][n] == 1 \n```\n\n写个测试案例\n```python\nimport unittest\nclass Solution(object):\n    def isMatch(self, s, p):\n        \"\"\"\n        :type s: str\n        :type p: str\n        :rtype: bool\n        \"\"\"\n        m, n = len(s), len(p)\n        dp = [ [0 for i in range(n+1)] for j in range(m+1)]\n\n        dp[0][0] = 1\n\n        # init the first line\n        for i in range(2,n+1):\n            if p[i-1] == '*':\n                dp[0][i] = dp[0][i-2]\n\n        for i in range(1,m+1):\n            for j in range(1,n+1):\n                if p[j-1] == '*':\n                    if p[j-2] != s[i-1] and p[j-2] != '.':\n                        dp[i][j] = dp[i][j-2]\n                    elif p[j-2] == s[i-1] or p[j-2] == '.':\n                        dp[i][j] = dp[i-1][j] or dp[i][j-2]\n\n                elif s[i-1] == p[j-1] or p[j-1] == '.':\n                    dp[i][j] = dp[i-1][j-1]\n\n        return dp[m][n] == 1\n\n\nclass TestSolution(unittest.TestCase):\n    def test_none_0(self):\n        s = \"\"\n        p = \"\"\n        self.assertTrue(Solution().isMatch(s, p))\n\n    def test_none_1(self):\n        s = \"\"\n        p = \"a\"\n        self.assertFalse(Solution().isMatch(s, p))\n\n    def test_no_symbol_equal(self):\n        s = \"abcd\"\n        p = \"abcd\"\n        self.assertTrue(Solution().isMatch(s, p))\n\n    def test_no_symbol_not_equal_0(self):\n        s = \"abcd\"\n        p = \"efgh\"\n        self.assertFalse(Solution().isMatch(s, p))\n\n    def test_no_symbol_not_equal_1(self):\n        s = \"ab\"\n        p = \"abb\"\n        self.assertFalse(Solution().isMatch(s, p))\n\n    def test_symbol_0(self):\n        s = \"\"\n        p = \"a*\"\n        self.assertTrue(Solution().isMatch(s, p))\n\n    def test_symbol_1(self):\n        s = \"a\"\n        p = \"ab*\"\n        self.assertTrue(Solution().isMatch(s, p))\n\n    def test_symbol_2(self):\n        # E.g.\n        #   s a b b\n        # p 1 0 0 0\n        # a 0 1 0 0\n        # b 0 0 1 0\n        # * 0 1 1 1\n        s = \"abb\"\n        p = \"ab*\"\n        self.assertTrue(Solution().isMatch(s, p))\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n    \n    \n\n输出：\n........\n\nRan 8 tests in 0.001s\n\nOK\n```\n\n参考:\n\n\n[动态规划](https://hk029.gitbooks.io/leetbook/content/动态规划/010.%20Regular%20Expression%20Matching/010.%20Regular%20Expression%20Matching.html)\n\n\n"
  },
  {
    "path": "docs/leetcode/python/011._container_with_most_water.md",
    "content": "### 11. Container With Most Water\n\n\n\n题目:\n<https://leetcode.com/problems/container-with-most-water/>\n\n\n难度:\nMedium\n\n思路：\n\n\n首先理解花了我一点时间，因为一开始写出来，给了一个例子：\n\n```\n\nheight = [3,2,1,3]\n解是 9\n\n\n|\t\t\t|\n|\t|\t\t|\n|\t|\t|\t|\n1       2       3       4\n    \n 一开始我的理解走偏的地方是这个9是如何得到的，因为根据最短板原理，明显不可能得到9啊，后来发现是·Find two lines, which together with x-axis forms a container, such that the container contains the most water.\n```\n\n所以代码写起来就简单了,AC无能，超时，时间复杂度O(N^2)\n\n\n```\nclass Solution(object):  # 此法超时\n    def maxArea(self, height):\n        \"\"\"\n        :type height: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(height)\n        most_water = 0\n        for i in range(n-1):\n            for j in range(i, n):\n                water = (j-i) * min(height[i], height[j])\n                most_water = max(water, most_water)\n        return most_water\n\n```\n\n题目给的tag是 two pointer，所以上边的策略肯定可以改进，改进的地方就不能是这个一次走一边，而可能是两边都要走。\n\n\n\n参考 <http://bangbingsyb.blogspot.com/2014/11/leetcode-container-with-most-water.html>\n\n\n思路：\n\n由于ai和aj (i<j) 组成的container的面积：S(i,j) = min(ai, aj) * (j-i)\n\n所以对于任何```S(i'>=i, j'<=j) >= S(i,j)```，由于```j'-i' <= j-i```，必然要有```min(ai',aj')>=min(ai,aj)```才行。同样可以采用头尾双指针向中间移动：\n\n当```a(left) < a(right)```时，对任何```j<right```来说\n\n1. ```min(a(left),aj) <= a(left) = min(a(left), a(right))```\n2. ```j-left < right-left```\n\n所以S(left, right) > S(left, j<right)。\n\n这就排除了所有以left为左边界的组合，因此需要右移left。`这里证明的非常好。` a[left] < a[right]，需要右移left.\n\n`同理，当a(left) > a(right)时，需要左移right`。\n\n`而当a(left) = a(right)时，需要同时移动left和right。`\n\n思路整理：\nleft = 0, right = n-1\n1. a[left] < a[right], left++\n2. a[left] > a[right], right--\n3. a[left] = a[right], left++, right--\n终止条件：left >= right\n\n这个证明大快人心\n\n\n这样写也能过:\n\n\n```python\nclass Solution(object):\n    def maxArea(self, height):\n        \"\"\"\n        :type height: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(height)\n        left, right = 0, n-1\n        most_water = 0\n        while left <= right:\n            water = (right - left) * min(height[left], height[right])\n            most_water = max(water, most_water)\n            if height[left] < height[right]:\n                left += 1\n            elif height[left] > height[right]:\n                right -= 1\n            else:\n                left += 1\n                right -= 1\n        return most_water\n        \n```\n"
  },
  {
    "path": "docs/leetcode/python/012._Integer_to_Roman.md",
    "content": "### 12. Integer to Roman\n\n\n题目:\n<https://leetcode.com/problems/integer-to-roman/>\n\n\n难度:\nMedium\n\n思路：\n\n首先我学习了一下罗马字母是如何表示的。然后感慨，这个阿拉伯数字是多么好的发明\n\n\n\n上图\n\n\n\n基于的是这些个Symbol：\n\n```\n1\t5\t10\t50\t100\t500\t1000\nI\tV\tX  \t L\t C\t D\t M\n```\n\n\n\n罗马数字表示法见[Leetcode 013](https://github.com/Lisanaaa/thinking_in_lc/blob/master/013._Roman_to_Integer.md)\n\n这里有一个很棒的[算法](https://gist.github.com/imilu/00f32c61e50b7ca296f91e9d96d8e976)\n\nAC代码\n\n```python\nclass Solution(object):\n    def intToRoman(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: str\n        \"\"\"\n        lookup = {\n            'M': 1000, \n            'CM': 900, \n            'D': 500, \n            'CD': 400, \n            'C': 100, \n            'XC': 90, \n            'L': 50, \n            'XL': 40, \n            'X': 10, \n            'IX': 9, \n            'V': 5, \n            'IV': 4, \n            'I': 1\n        }\n        romanStr = ''\n\n        for symbol, val in sorted(lookup.items(), key = lambda t: t[1], reverse = True):\n        \twhile num >= val:\n        \t\tromanStr += symbol\n        \t\tnum -= val\n        return romanStr\n```\n\n\n\n\n\n因为dict本身是无序的，这里做了一个排序的操作，否则可能会出现IIII这种状况。\n"
  },
  {
    "path": "docs/leetcode/python/013._Roman_to_Integer.md",
    "content": "### 13.Roman to Integer\n\n\n\n题目:\n<https://leetcode.com/problems/roman-to-integer/>\n\n难度:\nEasy\n\n思路：\n\n\n```        \n罗马数字是最古老的数字表示方式，比阿拉伯数组早2000多年，起源于罗马\n\n罗马数字有如下符号：\n\n基本字符\t        I       V\tX\tL\tC       D       M\n对应阿拉伯数字\t1\t5\t10\t50\t100\t500\t1000\n\n计数规则：\n- 相同的数字连写，所表示的数等于这些数字相加得到的数，例如：III = 3\n- 小的数字在大的数字右边，所表示的数等于这些数字相加得到的数，例如：VIII = 8\n- 小的数字，限于（I、X和C）在大的数字左边，所表示的数等于大数减去小数所得的数，例如：IV = 4,这条规则好像这题不管\n- 正常使用时，连续的数字重复不得超过三次\n- 在一个数的上面画横线，表示这个数扩大1000倍（本题只考虑3999以内的数，所以用不到这条规则）\n- 从前向后遍历罗马数字，如果某个数比前一个数小，则加上该数。反之，减去前一个数的两倍然后加上该数\n```\n\n\n\ninteger to Roman 是 Medium，这个roman to integer是easy\n\n\n-  从前往后扫描，用一个临时变量记录分段数字。\n-  如果当前比前一个大，说明这一段的值应当是这个值减去上一个值。比如IV = 5-1 =4; 否则，将当前值加入到结果中，然后开始下一段记录，比如VI = 5 + 1, II = 1 +1\n\n\n所以这也就是罗马数字的基础，感觉？这样才不会读串？\n\n\n\nAC代码\n\n```python\nclass Solution(object):\n    def romanToInt(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        lookup = {\n            'M': 1000,\n            'D': 500,\n            'C': 100,\n            'L': 50,\n            'X': 10,\n            'V': 5,\n            'I': 1\n        }\n        res = 0\n        for i in range(len(s)):\n            if i > 0 and lookup[s[i]] > lookup[s[i-1]]:\n                res = res + lookup[s[i]] - 2 * lookup[s[i-1]]\n            else:\n                res += lookup[s[i]]\n        return res\n```\n或者甚至可以建立一个新函数用于取对应数值：\n```\n        def table(x):\n            return {\n                   'I':1,\n                   'V':5,\n                   'X':10,\n                   'L':50,\n                   'C':100,\n                   'D':500,\n                   'M':1000\n                }.get(x)\n```\n"
  },
  {
    "path": "docs/leetcode/python/014._longest_common_prefix.md",
    "content": "### 14. Longest Common Prefix\n\n\n题目:\n<https://leetcode.com/problems/longest-common-prefix/>\n\n\n难度:\n\nEasy\n\n\n思路：\n\n#### 解法1:\n以一个小例子来解释，strs=['laa', 'lab', 'lac'], 如果存在LCP的话它肯定就在第一个字符串strs[0]中，并且LCP的长度肯定不会大于strs[0]的长度\n- 依次假设LCP长度为0到len(strs[0]),在每一轮循环中:\n   \n- 1. 只要strs中存在比当前长度i更短的string，立刻返回上一轮LCP，即strs[0][:i]\n  2. 只要strs中存在当前index字符与LCP该index不相同的字符串，立刻返回上一轮LCP，即strs[0][:i]\n- 如果一直没返回，说明strs[0]本身就是LCP，返回它\n\n\n```\nclass Solution(object):\n    def longestCommonPrefix(self, strs):\n        \"\"\"\n        :type strs: List[str]\n        :rtype: str\n        \"\"\"\n        if not strs:\n            return \"\"\n        for i in range(len(strs[0])):\n            for str in strs:\n                if len(str) <= i or strs[0][i] != str[i]:\n                    return strs[0][:i]\n        return strs[0]\n\n```\n\n#### 解法2:\n- dp[i]代表前i+1个字符串的最大前缀串，\n- 如果第i+2个字符串不以dp[i]为前缀，就去掉dp[i]的最后一个字符再试一次\n- 都去完了那么dp[i+1]肯定就是空串了，也就等于这时候的dp[i]，因为dp[i]的每个字符已经被去完了\n```python\nclass Solution(object):\n    def longestCommonPrefix(self, strs):\n        \"\"\"\n        :type strs: List[str]\n        :rtype: str\n        \"\"\"\n        if not strs:\n            return ''\n        dp = [strs[0]]*len(strs)\n        for i in range(1,len(strs)):\n            while not strs[i].startswith(dp[i-1]):\n                dp[i-1] = dp[i-1][:-1]\n            dp[i] = dp[i-1]\n        return dp[-1]\n```\n\n\n\n\n\n\n\npython无敌啊！！！有没有天理啊，手动滑稽😏😏😏😏！一行解法：\n```python\nclass Solution(object):\n    def longestCommonPrefix(self, strs):\n        \"\"\"\n        :type strs: List[str]\n        :rtype: str\n        \"\"\"\n        return os.path.commonprefix(strs)\n```\n"
  },
  {
    "path": "docs/leetcode/python/015._3sum.md",
    "content": "### 15. 3Sum\n\n题目:\n<https://leetcode.com/problems/3sum/>\n\n\n难度:\n\nMedium \n\n\n第一想法，先把nums排序，用三个loop，无法AC\n\n```\nclass Solution(object):\n    def threeSum(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        n = len(nums)\n        res = []\n        nums.sort()\n        for i in range(n):\n            for j in range(i,n):\n                for k in range(j,n):\n                    if nums[i] + nums[j] + nums[k] == 0 and j != i and k != j and k != i: \n                        curRes = [nums[i],nums[j],nums[k]]\n                        if curRes not in res:\n                            res.append(curRes)\n    \n        return res\n```\n\n\n然后查了一下2sum，用2sum的花样，因为要排除重复以及输出是按照从小到大的输出:但是还是超时\n\n\n```\nclass Solution(object):  # 此法也超时\n    def threeSum(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        def twoSum(nums, target):\n            \"\"\"\n            :type nums: List[int]\n            :type target: int\n            :rtype: List[int]\n            \"\"\"\n            lookup = {}\n            for num in nums:\n                if target - num in lookup:\n                    if (-target ,target - num, num) not in res:\n                        res.append((-target ,target - num, num))\n                lookup[num] = target - num\n\n        n = len(nums)\n        nums.sort()\n        res = []\n        for i in range(n):\n            twoSum(nums[i+1:], 0-nums[i])\n        return [list(i) for i in res]\n```\n\n\n谷歌看别人的代码，思路非常清晰的,运行起来比直接调用 Two Sum快.\n\n清晰的思路：\n\n- 排序\n- 固定左边，如果左边重复，继续\n- 左右弄边界，去重，针对不同的左右边界情况处理\n\n\n```python\nclass Solution(object):\n    def threeSum(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        n, res = len(nums), []\n        nums.sort()\n        for i in range(n):\n            if i > 0 and nums[i] == nums[i-1]:   # 因为i=0这个元素会直接往下执行\n                continue\n            l, r = i+1, n-1\n            while l < r:\n                tmp = nums[i] + nums[l] + nums[r]\n                if tmp == 0:\n                    res.append([nums[i], nums[l], nums[r]])\n                    l += 1\n                    r -= 1\n                    while l < r and nums[l] == nums[l-1]: \n                        l += 1\n                    while l < r and nums[r] == nums[r+1]: \n                        r -= 1\n                elif tmp > 0:\n                    r -= 1\n                else:\n                    l += 1\n        return res\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/016._3sum_closest.md",
    "content": "### 16. 3Sum Closest\n\n题目:\n<https://leetcode.com/problems/3sum-closest/>\n\n\n难度:\n\nMedium \n\n\n思路：\n跟3 Sum一样，固定一个元素\n\n用两个指针来循环\n\n\n```python\nclass Solution(object):\n    def threeSumClosest(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        n, res, diff = len(nums), None, float('inf')\n        nums.sort()\n        for i in range(n):\n            if i > 0 and nums[i] == nums[i-1]:\n                continue\n            l, r = i+1, n-1\n            while l < r:\n                tmp = nums[i] + nums[l] + nums[r]\n                if tmp == target:\n                    return target\n                elif tmp > target:\n                    r -= 1\n                    if abs(tmp-target) < diff:\n                        diff = abs(tmp-target)\n                        res = tmp\n                    while l < r and nums[r] == nums[r+1]:\n                        r -= 1    \n                else:\n                    l += 1\n                    if abs(tmp-target) < diff:\n                        diff = abs(tmp-target)\n                        res = tmp\n                    while l < r and nums[l] == nums[l-1]:\n                        l += 1 \n        return res\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/017._letter_combinations_of_a_phone_number.md",
    "content": "### 17. Letter Combinations of a Phone Number\n\n题目:\n\n<https://leetcode.com/problems/letter-combinations-of-a-phone-number/>\n\n\n难度:\n\nMedium\n\n\n思路：\n\n - hash table一个，用来对应digit -> letter\n - s用来记录结果，每次从digits里面去一个，然后寻找其可能的char，加到s中，digits长度减小\n - digits长度为0时候，把它加入结果\n\n\n\n```python\nclass Solution(object):\n    def letterCombinations(self, digits):\n        \"\"\"\n        :type digits: str\n        :rtype: List[str]\n        \"\"\"\n        if digits == '':\n            return []\n        self.res = []\n        self.singleResult('', digits)\n        return self.res\n        \n    def singleResult(self, s, digits):\n        if len(digits) == 0:\n            self.res.append(s)\n        else:\n            mapx = {'2':['a','b','c'],\n                '3':['d','e','f'],\n                '4':['g','h','i'],\n                '5':['j','k','l'],\n                '6':['m','n','o'],\n                '7':['p','q','r','s'],\n                '8':['t','u','v'],\n                '9':['w','x','y','z']}\n            cur_digit = digits[0]\n            for c in mapx[cur_digit]:\n                self.singleResult(s+c, digits[1:])\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/018._4sum.md",
    "content": "### 18. 4Sum\n\n题目:\n<https://leetcode.com/problems/4sum/>\n\n\n难度:\n\nMedium \n\n\n思路：\n\n用3sum改\n\n固定两个数，活动别的\n\n\n```python\nclass Solution(object):\n    def fourSum(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        n = len(nums)\n        nums.sort()\n        res = []\n        for i in range(n):\n        \tfor j in range(i+1,n):\n        \t\tl, r = j+1, n-1\n        \t\twhile l < r:\n        \t\t\ttemp = nums[i] + nums[j] + nums[l] + nums[r]\n        \t\t\tif temp == target:\n        \t\t\t\tif [nums[i],nums[j],nums[l],nums[r]] not in ans:\n        \t\t\t\t\tans.append([nums[i],nums[j],nums[l],nums[r]])\n        \t\t\t\tl += 1\n        \t\t\t\tr -= 1\n        \t\t\telif temp > target:\n        \t\t\t\tr -= 1\n        \t\t\telse:\n        \t\t\t\tl+=1\n        return ans\n```\n\n可以通过加判断条件，前后数字相等可以直接跳过，使得算法更快\n\n\n```python\nclass Solution(object):\n    def fourSum(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        n, res = len(nums), []\n        nums.sort()\n        for i in range(n):\n            if i > 0 and nums[i] == nums[i-1]:   # 因为i=0这个元素会直接往下执行\n                continue\n            for j in range(i+1, n):\n                if j > i+1 and nums[j] == nums[j-1]:   # 因为j=i+1这个元素会直接往下执行\n                    continue\n                l, r = j+1, n-1\n                while l < r:\n                    tmp = nums[i] + nums[j] + nums[l] + nums[r]\n                    if tmp == target:\n                        res.append([nums[i], nums[j], nums[l], nums[r]])\n                        l += 1\n                        r -= 1\n                        while l < r and nums[l] == nums[l-1]: \n                            l += 1\n                        while l < r and nums[r] == nums[r+1]: \n                            r -= 1\n                    elif tmp > target:\n                        r -= 1\n                    else:\n                        l += 1\n        return res\n\n```\n\n还可以再用一些判断来加速，比如枚举第一个数的时候\n\n- nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target: break\n这是当前能凑齐的最小的4个数，比target后面都不用做了\n- nums[i] + nums[n – 3] + nums[n – 2] + nums[n – 1] < target: continue\n这是当前凑齐的最大的4个数，比target小，说明第一个数不够大\n\n参考\n\n<https://www.hrwhisper.me/leetcode-2-sum-3-sum-4-sum-3-sum-closest-k-sum/>\n\n\n```python\nclass Solution(object):\n    def fourSum(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        n, res = len(nums), []\n        nums.sort()\n        for i in range(n):\n            if i > 0 and nums[i] == nums[i-1]:   # 因为i=0这个元素会直接往下执行\n                continue\n            if i+3 <= n-1:\n                if nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target:\n                    break\n            if i < n-3:\n                if nums[i] + nums[n-3] + nums[n-2] + nums[n-1] < target:\n                    continue\n            for j in range(i+1, n):\n                if j > i+1 and nums[j] == nums[j-1]:   # 因为j=i+1这个元素会直接往下执行\n                    continue\n                l, r = j+1, n-1\n                while l < r:\n                    tmp = nums[i] + nums[j] + nums[l] + nums[r]\n                    if tmp == target:\n                        res.append([nums[i], nums[j], nums[l], nums[r]])\n                        l += 1\n                        r -= 1\n                        while l < r and nums[l] == nums[l-1]: \n                            l += 1\n                        while l < r and nums[r] == nums[r+1]: \n                            r -= 1\n                    elif tmp > target:\n                        r -= 1\n                    else:\n                        l += 1\n        return res\n        \n```\n"
  },
  {
    "path": "docs/leetcode/python/019._remove_nth_node_from_end_of_list.md",
    "content": "### 19. Remove Nth Node From End of List\n\n题目： \n\n<https://leetcode.com/problems/remove-nth-node-from-end-of-list/>\n\n\n难度: Medium\n\n\nAC击败了95.80%的Python用户，技巧 dummy head 和双指针。\n\n切记最后要返回```dummy.next```而不是```head```，因为有这样一种情况，删掉节点后```linked list```空了，那返回```head```的话结果显然不同。如：\n输入链表为```[1]```, ```n = 1```, 应该返回```None```而不是```[1]```\n\n```python\nclass Solution(object):\n    def removeNthFromEnd(self, head, n):\n        \"\"\"\n        :type head: ListNode\n        :type n: int\n        :rtype: ListNode\n        \"\"\"\n        dummy = ListNode(-1)\n        dummy.next = head\n        p, q = dummy, dummy\n        \n        for i in range(n):\n            q = q.next\n            \n        while q.next:\n            p = p.next\n            q = q.next\n        \n        p.next = p.next.next\n        return dummy.next\n            \n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/020._valid_parentheses.md",
    "content": "# 20. Valid Parentheses 有效的括号\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/valid-parentheses\n* https://leetcode-cn.com/problems/valid-parentheses\n\n> 内容描述\n\n```\n给定一个只包括 '('，')'，'{'，'}'，'['，']' 的字符串，判断字符串是否有效。\n\n有效字符串需满足：\n\n左括号必须用相同类型的右括号闭合。\n左括号必须以正确的顺序闭合。\n注意空字符串可被认为是有效字符串。\n\n示例 1:\n\n输入: \"()\"\n输出: true\n示例 2:\n\n输入: \"()[]{}\"\n输出: true\n示例 3:\n\n输入: \"(]\"\n输出: false\n示例 4:\n\n输入: \"([)]\"\n输出: false\n示例 5:\n\n输入: \"{[]}\"\n输出: true\n```\n\n## 解题方案\n\n> 思路 1\n\n因为一共只有三种状况\"(\" -> \")\", \"[\" -> \"]\", \"{\" -> \"}\".\n\n一遇到左括号就入栈，右括号出栈，这样来寻找对应\n\n需要检查几件事：\n\n- 出现右括号时stack里还有没有东西\n- 出stack时是否对应\n- 最终stack是否为空\n\n```python\nclass Solution(object):\n    def isValid(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: bool\n        \"\"\"\n        leftP = '([{'\n        rightP = ')]}'\n        stack = []\n        for char in s:\n            if char in leftP:\n                stack.append(char)\n            if char in rightP:\n                if not stack:\n                    return False\n                tmp = stack.pop()\n                if char == ')' and tmp != '(':\n                    return False\n                if char == ']' and tmp != '[':\n                    return False       \n                if char == '}' and tmp != '{':\n                    return False\n        return stack == []\n```\n\n> 思路 2\n\n* 扩展性和可理解性强\n\n```python\nclass Solution:\n    def isValid(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: bool\n        \"\"\"\n        if len(s) % 2 == 1:\n            return False\n\n        index = 0\n        stack = [i for i in s]\n        map1 = {\"(\": \")\", \"[\": \"]\", \"{\": \"}\"}\n\n        while len(stack) > 0:\n            # 判断索引是否超过边界\n            if index >= len(stack)-1:\n                return False\n    \n            b = stack[index]\n            e = stack[index+1]\n\n            if b not in map1.keys():\n                return False\n            elif e in map1.keys():\n                index += 1\n            elif map1[b] == e:\n                stack.pop(index+1)\n                stack.pop(index)\n                index = 0 if index-1<0 else index-1\n            else:\n                return False\n\n        return stack == []\n```\n"
  },
  {
    "path": "docs/leetcode/python/021._merge_two_sorted_lists.md",
    "content": "### 21. Merge Two Sorted Lists\n\n题目： \n\n<https://leetcode.com/problems/merge-two-sorted-lists/>\n\n\n难度: Easy\n\n\n同样适用dummy head\n\n```python\nclass Solution(object):\n    def mergeTwoLists(self, l1, l2):\n        \"\"\"\n        :type l1: ListNode\n        :type l2: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if l1 == None:\n            return l2\n        if l2 == None:\n            return l1\n        \n        dummy = ListNode(-1)\n        cur = dummy\n        \n        while l1 and l2:\n            if l1.val < l2.val:\n                cur.next = l1\n                l1 = l1.next\n            else:\n                cur.next = l2\n                l2 = l2.next\n            cur = cur.next\n        \n        if l1:\n            cur.next = l1\n        else:\n            cur.next = l2\n        return dummy.next\n            \n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/022._generate_parentheses.md",
    "content": "### 22. Generate Parentheses\n\n题目:\n<https://leetcode.com/problems/generate-parentheses/>\n\n\n难度:\n\nMedium\n\n\n\n\n\n```python\nclass Solution(object):\n    def generateParenthesis(self,n):\n        \"\"\"\n        :type n: int\n        :rtype: List[str]\n        \"\"\"\n        self.res = []\n        self.singleStr('', 0, 0, n)\n        return self.res\n        \n    def singleStr(self, s, left, right, n):\n        if left == n and right == n:\n            self.res.append(s)\n        if left < n:\n            self.singleStr(s + '(',left + 1, right,n)\n        if right < left:\n            self.singleStr(s + ')',left, right + 1, n)\n                \n```\n\n\n非常牛逼的讲解，需要这样的人来给我们讲算法\n\n####以Generate Parentheses为例，backtrack的题到底该怎么去思考？\n\n\n所谓Backtracking都是这样的思路：在当前局面下，你有若干种选择。那么尝试每一种选择。如果已经发现某种选择肯定不行（因为违反了某些限定条件），就返回；如果某种选择试到最后发现是正确解，就将其加入解集\n\n所以你思考递归题时，只要明确三点就行：选择 (Options)，限制 (Restraints)，结束条件 (Termination)。即“ORT原则”（这个是我自己编的）\n\n\n\n\n对于这道题，在任何时刻，你都有两种选择：\n1. 加左括号。\n2. 加右括号。\n\n同时有以下限制：\n1. 如果左括号已经用完了，则不能再加左括号了。\n2. 如果已经出现的右括号和左括号一样多，则不能再加右括号了。因为那样的话新加入的右括号一定无法匹配。\n\n结束条件是：\n左右括号都已经用完。\n\n结束后的正确性：\n左右括号用完以后，一定是正确解。因为1. 左右括号一样多，2. 每个右括号都一定有与之配对的左括号。因此一旦结束就可以加入解集（有时也可能出现结束以后不一定是正确解的情况，这时要多一步判断）。\n\n递归函数传入参数：\n限制和结束条件中有“用完”和“一样多”字样，因此你需要知道左右括号的数目。\n当然你还需要知道当前局面sublist和解集res。\n\n因此，把上面的思路拼起来就是代码：\n\n\tif (左右括号都已用完) {\n\t  加入解集，返回\n\t}\n\t//否则开始试各种选择\n\tif (还有左括号可以用) {\n\t  加一个左括号，继续递归\n\t}\n\tif (右括号小于左括号) {\n\t  加一个右括号，继续递归\n\t}\n\t\n\t\n\t\n你帖的那段代码逻辑中加了一条限制：“3. 是否还有右括号剩余。如有才加右括号”。这是合理的。不过对于这道题，如果满足限制1、2时，3一定自动满足，所以可以不判断3。\n\n这题其实是最好的backtracking初学练习之一，因为ORT三者都非常简单明显。你不妨按上述思路再梳理一遍，还有问题的话再说。\n\n\n\n以上文字来自 1point3arces的牛人解答\n"
  },
  {
    "path": "docs/leetcode/python/023._merge_k_sorted_lists.md",
    "content": "### 23. Merge k Sorted Lists\n\n\n\n题目:\n<https://leetcode.com/problems/merge-k-sorted-lists/>\n\n\n难度:\nHard\n\n思路：\n\n看到思路有heap，similar question有ugly number|| -> 这个是用heapq来解决的\n\n那么就用heap吧？ heapsort\n\n最简单的做法是只要每个list里面还有node，就把他们扔到minheap里面去，然后再把minheap pop，一个一个node连起来，听起来时间复杂度和空间复杂度都蛮高的。\n直接merge必然是不好的，因为没有利用有序这个点，应该做的是每次取来一个，然后再把应该的下一个放入\n\n写到这里瞬间明白和ugly number ii像的点了，甚至感觉跟find in sorted matrix ii也像\n\n```python\nclass Solution(object):\n    def mergeKLists(self, lists):\n        \"\"\"\n        :type lists: List[ListNode]\n        :rtype: ListNode\n        \"\"\"\n        import heapq\n        h = []\n        for lst_head in lists:\n            if lst_head:\n                heapq.heappush(h, (lst_head.val, lst_head))\n        cur = ListNode(-1)\n        dummy = cur\n        while h:\n            smallest_node = heapq.heappop(h)[1]\n            cur.next = smallest_node\n            cur = cur.next\n            if smallest_node.next:\n                heapq.heappush(h, (smallest_node.next.val, smallest_node.next))\n        return dummy.next\n```\n\n当然还像merge two sorted list\n"
  },
  {
    "path": "docs/leetcode/python/024._swap_nodes_in_pairs.md",
    "content": "### 24. Swap Nodes in Pairs\n\n题目： \n<https://leetcode.com/problems/swap-nodes-in-pairs/>\n\n\n难度 : Medium\n\n一眼就知道这个用递归做，```beats 96.06%```\n```python\nclass Solution(object):\n    def swapPairs(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if not head:\n            return None\n        if not head.next:\n            return head\n        tmp = head.next\n        head.next = self.swapPairs(head.next.next)\n        tmp.next = head\n        return tmp\n```\n\n或者用```loop```做，每个```node```关系要弄清楚, 又是巧用```dummy```，```dummy```大法对于```nodeList```的题目简直无敌！！！🐂批, 但是只```beats```了```69.40%```\n\n\n```python\nclass Solution(object):\n    def swapPairs(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if head == None or head.next == None:\n            return head\n\n        dummy = ListNode(-1)\n        dummy.next = head\n        \n        cur = dummy\n\n        while cur.next and cur.next.next:\n            next_one, next_two, next_three = cur.next, cur.next.next, cur.next.next.next\n            cur.next = next_two\n            next_two.next = next_one\n            next_one.next = next_three\n            cur = next_one\n        return dummy.next\n```\n"
  },
  {
    "path": "docs/leetcode/python/026._Remove_Duplicates_from_Sorted_Array.md",
    "content": "### 26. Remove Duplicates from Sorted Array\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* ttps://leetcode.com/problems/remove-duplicates-from-sorted-array\n* https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array\n\n> 内容描述\n\n给定一个排序数组，你需要在 原地 删除重复出现的元素，使得每个元素只出现一次，返回移除后数组的新长度。\n\n不要使用额外的数组空间，你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。\n\n示例 1:\n\n```\n给定数组 nums = [1,1,2], \n\n函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 \n\n你不需要考虑数组中超出新长度后面的元素。\n```\n\n示例 2:\n\n```\n给定 nums = [0,0,1,1,1,2,2,3,3,4],\n\n函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。\n\n你不需要考虑数组中超出新长度后面的元素。\n```\n\n## 解题方案\n\n> 思路 1\n\n因为题目说了是 `sorted array`，所以只需要不停判断当前位置值和下一位置是否相等，\n\n若相等则 `pop掉当前值`，否则 `move` 到下一位置做重复判断\n\n```python\nclass Solution(object):\n    def removeDuplicates(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        i = 0\n        while i < (len(nums) - 1):\n            if nums[i] == nums[i+1]:\n                nums.remove(nums[i])\n            else:\n                i += 1\n        return len(nums)\n```\n\n这里代码用 `while loop` 而不用 `for loop` 是因为 `pop` 操作之后 `nums` 的长度会变化\n\n如： `for i in range(len(nums)-1)` 实际上固定了 `range` 里面的值了，不会二次判断\n\n```\nn = 10\nfor i in range(n):\n    n = n - 1  # 尽管n在变化\n    print(i)\n\n上面这段代码的输出结果为：\n\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n```\n"
  },
  {
    "path": "docs/leetcode/python/027._Remove_Element.md",
    "content": "### 27. Remove Element\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/remove-element\n* https://leetcode-cn.com/problems/remove-element/\n\n> 内容描述\n\n给你一个数组 nums 和一个值 val，你需要 原地 移除所有数值等于 val 的元素，并返回移除后数组的新长度。\n\n不要使用额外的数组空间，你必须仅使用 O(1) 额外空间并 原地 修改输入数组。\n\n元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。\n\n\n示例 1:\n\n```\n给定 nums = [3,2,2,3], val = 3,\n函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。\n你不需要考虑数组中超出新长度后面的元素。\n```\n\n示例 2:\n\n```\n给定 nums = [0,1,2,2,3,0,4,2], val = 2,\n函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。\n注意这五个元素可为任意顺序。\n你不需要考虑数组中超出新长度后面的元素。\n```\n\n## 解题方案\n\n> 思路 1\n\n瞬秒\n\n```python\nclass Solution(object):\n    def removeElement(self, nums, val):\n        \"\"\"\n        :type nums: List[int]\n        :type val: int\n        :rtype: int\n        \"\"\"\n        while val in nums:\n            nums.remove(val)\n        return len(nums)\n```\n"
  },
  {
    "path": "docs/leetcode/python/028._implement_strstr.md",
    "content": "### 28. Implement strStr()\n\n题目:\n\n<https://leetcode.com/problems/implement-strstr/>\n\n\n难度:\n\nEasy\n\n\n一行解法如何？\n```python\nclass Solution(object):\n    def strStr(self, haystack, needle):\n        \"\"\"\n        :type haystack: str\n        :type needle: str\n        :rtype: int\n        \"\"\"\n        return haystack.find(needle)\n```\n\n\n这个题目其实可以引来一大类，那就是关于string的算法，但是此处先用暴力算法来AC，然后再来细读/品味别的string相关算法吧。\n\n虽然是暴力算法，但是也不容易写对啊\n```python\nclass Solution(object):\n    def strStr(self, haystack, needle):\n        \"\"\"\n        :type haystack: str\n        :type needle: str\n        :rtype: int\n        \"\"\"\n        if not needle:\n            return 0\n        for i in xrange(len(haystack) - len(needle) + 1):\n            if haystack[i] == needle[0]:\n                j = 1\n                while j < len(needle) and haystack[i+j] == needle[j]:\n                    j += 1\n                if j == len(needle):\n                    return i\n        return -1\n```\n"
  },
  {
    "path": "docs/leetcode/python/030._Substring_with_Concatenation_of_All_Words.md",
    "content": "### 30. Substring with Concatenation of All Words\n\n题目： \n<https://leetcode.com/problems/substring-with-concatenation-of-all-words>\n\n\n难度 : Hard\n\n\n\n```python\nclass Solution(object):\n    def findSubstring(self, s, words):\n        \"\"\"\n        :type s: str\n        :type words: List[str]\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        if len(words) == 0 or len(s) < len(words) * len(words[0]):\n            return res\n        n, m, wl = len(s), len(words), len(words[0])\n        maps, cur_map = {}, {}\n        maps = collections.Counter(words)\n        for i in range(wl):\n            count, start, r = 0, i, i\n            while r + wl <= n:\n                string = s[r:r+wl]\n                if string in maps:\n                    cur_map[string] = cur_map.get(string, 0) + 1     \n                    if cur_map[string] <= maps[string]:\n                        count += 1\n                    while cur_map[string] > maps[string]:\n                        tmp = s[start:start+wl]\n                        cur_map[tmp] -= 1\n                        start += wl\n                        if cur_map[tmp] < maps[tmp]:\n                            count -= 1\n                    if count == m:\n                        res.append(start)\n                        tmp = s[start:start+wl]\n                        cur_map[tmp] -= 1\n                        start += wl\n                        count -= 1\n                else:\n                    cur_map = {}\n                    count = 0\n                    start = r + wl\n                r += wl\n            cur_map = {}\n        return res\n\n        \n```\n"
  },
  {
    "path": "docs/leetcode/python/031._next_permutation.md",
    "content": "\n### 31. Next Permutation\n\n\n题目:\n<https://leetcode.com/problems/next-permutation/>\n\n\n难度:\n\nMedium\n\n参照wikipedia：\n\n<https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order>\n\n首先，关于什么是全排列不做解释。如果一个排列为A，下一个排列为A_NEXT，那么A_NEXT一定与A有尽可能长的公共前缀。\n\n看具体例子，一个排列为124653，如何找到它的下一个排列，因为下一个排列一定与124653有尽可能长的前缀，所以，脑洞大开一下，从后面往前看这个序列，如果后面的若干个数字有下一个排列，问题就得到了解决。\n\n第一步：找最后面1个数字的下一个全排列。\n\n124653，显然最后1个数字3不具有下一个全排列。\n\n第二步：找最后面2个数字的下一个全排列。\n\n124653，显然最后2个数字53不具有下一个全排列。\n\n第三步：找最后面3个数字的下一个全排列。\n\n124653，显然最后3个数字653不具有下一个全排列。\n\n\n------插曲：到这里相信大家已经看出来，如果一个序列是递减的，那么它不具有下一个排列。\n\n\n第四步：找最后面4个数字的下一个全排列。\n\n124653，我们发现显然最后4个数字4653具有下一个全排列。因为它不是递减的，例如6453，5643这些排列都在4653的后面。\n\n\n我们总结上面的操作，并总结出重复上面操作的两种终止情况：\n\n1：从后向前比较相邻的两个元素，直到前一个元素小于后一个元素，停止\n\n2：如果已经没有了前一个元素，则说明这个排列是递减的，所以这个排列是没有下一个排列的。\n\n\n124653这个排列终止情况是上面介绍的第一种，从后向前比较相邻的2个元素，遇到4<6的情况停止。\n\n并且我们可以知道：\n\n1：124653和它的下一个排列的公共前缀为12(因为4653存在下一个排列，所以前面的数字12保持不变)\n\n2：4后面的元素是递减的(上面介绍的终止条件是前一个元素小于后一个元素，这里是4<6)\n\n\n现在，我们开始考虑如何找到4653的下个排列，首先明确4后面的几个数字中至少有一个大于4.\n\n4肯定要和653这3个数字中大于4的数字中(6，5)的某一个进行交换。这里就是4要和6，5中的某一个交换，很明显要和5交换，如果找到这样的元素呢，因为我们知道4后面的元素是递减的，所以在653中从后面往前查找，找到第一个大于4的数字，这就是需要和4进行交换的数字。这里我们找到了5，交换之后得到的临时序列为5643.，交换后得到的643也是一个递减序列。\n\n\n所以得到的4653的下一个临时序列为5643，但是既然前面数字变大了(4653--->5643)，后面的自然要变为升序才行，变换5643得到5346.\n\n所以124653的下一个序列为125346.\n\n看一个permutation，比如\n\n125430\n\n\n- 从末尾开始，找到decreasing subsequence，5430，因为来调5330无论怎么调，都不可能有比它更小的，数也被自然的分成两部分(1,2) 和 （5，4，3，0)\n- 下一步是找这个sequence里面第一个比前面部分，比2大的，3，也很容易理解，因为下一个必定是(1,3)打头\n- 交换 3和2 ，变成 (1,3,5,4,2,0),再把后面的部分reverse，得到后面部分可得到的最小的\n\n这个时候，得到下一个sequence 130245\n\nAC 代码\n\n```python\nclass Solution(object):\n    def nextPermutation(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        if len(nums) <= 1:\n            return\n        idx = 0\n        for i in range(len(nums)-1, 0, -1):\n            if nums[i] > nums[i-1]: # find first number which is smaller than it's after number\n                idx = i\n                break\n        if idx != 0: # if the number exist,which means that the nums not like{5,4,3,2,1}\n            for i in range(len(nums)-1, idx-1, -1):\n                if nums[i] > nums[idx-1]:\n                    nums[i], nums[idx-1] = nums[idx-1], nums[i]\n                    break\n\n        nums[idx:] = nums[idx:][::-1]\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/032._longest_valid_parentheses.md",
    "content": "# 32. longest-valid-parentheses 最长有效括号\n\n**<font color=red>难度: 困难</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/longest-valid-parentheses\n* https://leetcode-cn.com/problems/longest-valid-parentheses\n\n> 内容描述\n\n```\n给定一个只包含 '(' 和 ')' 的字符串，找出最长的包含有效括号的子串的长度。\n\n示例 1:\n\n输入: \"(()\"\n输出: 2\n解释: 最长有效括号子串为 \"()\"\n示例 2:\n\n输入: \")()())\"\n输出: 4\n解释: 最长有效括号子串为 \"()()\"\n```\n\n## 解题方案\n\n> 思路 1\n\n* 动态规划，参考[banananana](http://www.cnblogs.com/George1994/p/7531574.html)\n1. 用一个```dp```数组来存放以每个```index```为结尾的最长有效括号子串长度，例如：```dp[3] = 2```代表以```index为3```结尾的最长有效括号子串长度为```2```\n2. 很明显```dp[i]```和```dp[i-1]```之间是有关系的\n- 当```s[i] == ‘(’```时，```dp[i]```显然为```0```, 由于我们初始化dp的时候就全部设为0了，所以这种情况压根不用写\n- 当```s[i] == ')'```时， 如果在```dp[i-1]```的所表示的最长有效括号子串之前还有一个```'('```与```s[i]```对应，那么```dp[i] = dp[i-1] + 2```, 并且还可以继续往前追溯（如果前面还能连起来的话)\n\n```python\nclass Solution(object):\n    def longestValidParentheses(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        if len(s) == 0:\n            return 0\n        dp = [0 for i in range(len(s))]\n        for i in range(1, len(s)):\n            if s[i] == ')':\n                left = i - 1 - dp[i-1]\n                if left >= 0 and s[left] == '(':\n                    dp[i] = dp[i-1] + 2\n                    if left > 0: # 这个是判断 left 前面是否能与后面继续连起来\n                        dp[i] += dp[left-1]\n        return max(dp)\n```\n\n> 思路 2\n\n每当遇到一个左括号或者是无法成对的右括号，就将它压入栈中，可以成对的括号则从栈中 pop 出。这样栈中剩下的就是无法成对的括号的下标。这时我们可以判断这些下标间的距离来获得最大的成对括号长度。 在这里，我们需要先遍历一遍字符串，再遍历一下非空的堆栈。一定要注意，这里我们遍历的非空的栈存储的是没有匹配上的括号下标，匹配上的我们都已经做了pop 处理。\n\n\n```python\nclass Solution(object):\n    def longestValidParentheses(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        stack = []\n        for i in range(len(s)):\n            if s[i] == ')':\n                if stack and s[stack[-1]] == '(':    ## 这里要注意，不能想当然地用s[i-1]，因为我们有些下标直接continue了没有存到栈中去\n                    stack.pop()\n                    continue\n            stack.append(i)\n        max_length = 0\n        next_index = len(s)\n        while stack:\n            cur_index = stack.pop()\n            cur_length = next_index - cur_index - 1\n            max_length = max(cur_length, max_length)\n            next_index = cur_index\n        return max(next_index, max_length)\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/033._search_in_rotated_sorted_array.md",
    "content": "### 33. Search in Rotated Sorted Array\n\n题目:\n<https://leetcode.com/problems/search-in-rotated-sorted-array/>\n\n\n难度:\nMedium\n\n\n思路：\n\n\n\n下面是rotated-array图解，\n\n![rotated-array图解](/img/Algorithm/LeetCode/rotated-array12:09:2017.jpg)\n\n\n所以直接用二分，O(lg(n))\n- 如果是mid，return mid\n- 如果mid在绿色线上，就对绿色线进行二分\n- 如果mid在红色线上，就对红色线进行二分\n- 都没找到，return -1\n\n\n```python\nclass Solution(object):\n    def search(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        l, r = 0, len(nums) - 1\n        while l <= r:\n            mid = l + ((r - l) >> 2)\n            if nums[mid] == target:\n                return mid\n            if nums[mid] < nums[r]:\n                if nums[mid] < target <= nums[r]:\n                    l = mid + 1\n                else:\n                    r = mid - 1\n            else:\n                if nums[l] <= target < nums[mid]:\n                    r = mid - 1\n                else:\n                    l = mid + 1\n        return -1\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/034._Search_for_a_Range.md",
    "content": "### 34. Search for a Range\n\n\n\n题目：\n\n https://leetcode.com/problems/search-for-a-range/\n\n\n\n难度 : Medium\n\n\n\n思路：\n\n二分法，先找```target```出现的左边界，判断是否有```target```后再判断右边界\n\n- 找左边界：二分，找到一个```index```\n    - 该```index```对应的值为```target```  \n    - 并且它左边```index-1```对应的值不是```target```（如果```index```为```0```则不需要判断此条件）\n    - 如果存在```index```就将其```append```到```res```中\n- 判断此时```res```是否为空，如果为空，说明压根不存在```target```，返回```[-1, -1]```\n- 找右边界：二分，找到一个```index```（但是此时用于二分循环的```l```可以保持不变，```r```重置为```len(nums)-1```，这样程序可以更快一些）\n    - 该```index```对应的值为```target```\n    - 并且它右边```index+1```对应的值不是```target```（如果```index```为```len(nums)-1```则不需要判断此条件）   \n    - 如果存在```index```就将其```append```到```res```中\n\n\n\nAC 代码\n\n\n\n\n```python\nclass Solution(object):\n    def searchRange(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: List[int]\n        \"\"\"\n        if not nums : return [-1, -1]\n\n        res = []\n        l, r = 0, len(nums)-1\n        # search for left bound\n        while l <= r:\n            mid = l + ((r - l) >> 2)\n            if nums[mid] == target and (mid == 0 or nums[mid-1] != target):\n                res.append(mid)\n                break\n            if nums[mid] < target:\n                l = mid + 1\n            else:\n                r = mid - 1\n        if not res:\n            return [-1, -1]\n        # search for right bound\n        r = len(nums)-1\n        while l <= r:\n            mid = l + ((r - l) >> 2)\n            if nums[mid] == target and (mid == len(nums)-1 or nums[mid+1] != target):\n                res.append(mid)\n                break\n            if nums[mid] > target:\n                r = mid - 1\n            else:\n                l = mid + 1       \n        return res\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/035._search_insert_position.md",
    "content": "### 35. Search Insert Position\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/search-insert-position\n* https://leetcode-cn.com/problems/search-insert-position\n\n> 内容描述\n\n```\n给定一个排序数组和一个目标值，在数组中找到目标值，并返回其索引。如果目标值不存在于数组中，返回它将会被按顺序插入的位置。\n\n你可以假设数组中无重复元素。\n\n示例 1:\n输入: [1,3,5,6], 5\n输出: 2\n\n示例 2:\n输入: [1,3,5,6], 2\n输出: 1\n\n示例 3:\n输入: [1,3,5,6], 7\n输出: 4\n\n示例 4:\n输入: [1,3,5,6], 0\n输出: 0\n```\n\n## 解题方案\n\n> 思路 1: 暴力\n\n```python\nclass Solution(object):\n    def searchInsert(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        i = 0\n        while nums[i] < target:\n            i += 1\n            if i == len(nums):\n                return i\n        return i\n```\n\n> 思路 2: 二分\n\n```python\nclass Solution(object):\n    def searchInsert(self, nums, target):\n        \"\"\"\n        :type nums: List[int]\n        :type target: int\n        :rtype: int\n        \"\"\"\n        left = 0\n        right = len(nums) - 1\n        while left <= right:\n            mid = (left + right) // 2\n            print(\">>> %s: %s[%s], %s[%s], %s[%s]\" % (target, nums[left], left, nums[right], right, nums[mid], mid))\n            if nums[mid] > target:\n                right = mid - 1\n            elif nums[mid] < target:\n                left = mid + 1\n            else:\n                break\n\n        mid = mid+1 if left > mid else mid\n        print(\"结果: \", mid, left)\n        return mid\n```\n"
  },
  {
    "path": "docs/leetcode/python/038._Count_and_Say.md",
    "content": "### 38. Count and Say\n\n题目:\n<https://leetcode.com/problems/count-and-say/>\n\n\n难度:\n\nEasy\n\n\n思路\n\n\n1. i代表字符下标，从0开始取值，也就是从第一个字符开始，因为要让i取到最后一个字符，并且后面还要进行i+1的操作，所以将原字符串随意加上一个‘*’字符防止溢出\n2. count代表此时已经连续相同的字符个数\n3. res代表最终输出的字符串\n\n- 只要i下标对应的字符等于下一个字符，则sum和i都加1，无限循环\n- 如果i下标对应的字符不等于下一个字符了，则res应该加上str(sum)和i下标对应的那个字符，并且i加1，sum复原回0\n\n```\nExamples of nth sequence\n\n 1.     1\n 2.     11\n 3.     21\n 4.     1211\n 5.     111221 \n 6.     312211\n 7.     13112221\n 8.     1113213211\n 9.     31131211131221\n 10.   13211311123113112211\n \n```\n```python\n解法1\nclass Solution(object):\n    def countAndSay(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: str\n        \"\"\"\n        if n == 1:\n            return '1'\n        s = self.countAndSay(n-1) + '*'\n        res, count = '', 1\n        for i in range(len(s)-1):\n            if s[i] == s[i+1]:\n                count += 1\n            else:\n                res += str(count) + str(s[i])\n                count = 1\n        return res\n```\n```python\n解法2\nclass Solution(object):\n    def countAndSay(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: str\n        \"\"\"\n        res = '1'\n        for i in range(n-1):\n            res = ''.join([str(len(list(group))) + digit for digit, group in itertools.groupby(res)])\n        return res\n```\n详见[python进阶-ITERTOOLS模块小结](http://www.wklken.me/posts/2013/08/20/python-extra-itertools.html#itertoolsgroupbyiterable-key)\n\n```java\n解法3\nclass Solution {\n    public String countAndSay(int n) {\n        if(n == 1){  \n            return \"1\";  \n        }  \n        //递归调用，然后对字符串处理  \n        String str = countAndSay(n-1) + \"*\";//为了str末尾的标记，方便循环读数  \n        char[] c = str.toCharArray();  \n        int count = 1;  \n        String s = \"\";  \n        for(int i = 0; i < c.length - 1;i++){  \n            if(c[i] == c[i+1]){  \n                count++;//计数增加  \n            }else{  \n                s = s + count + c[i];//上面的*标记这里方便统一处理  \n                count = 1;//初始化  \n            }  \n        }  \n        return s;\n        \n    }\n}\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/039._combination_sum.md",
    "content": "### 39. Combination Sum\n\n题目:\n\n<https://leetcode.com/problems/combination-sum/>\n\n\n难度:\n\nMedium\n\n\n最初的思路：\n\n\n```\nres = []    \ndef combSum(candidates, target, valueList):\n    if target == 0:\n        res.append(valueList)\n    for candidate in candidates:\n        if candidate > target:\n            return\n        combSum(candidates, target - candidate, valueList + [candidate] )\n                \n```\n\n\n问题在于，有重复：\n\n```\ncombSum([2,3,6,7],7,[])\n\nres\nOut[9]: [[2, 2, 3], [2, 3, 2], [3, 2, 2], [7]]\n```\n\n然后看了hint，除[2, 2, 3] 和 [2, 3, 2]这种重复的方式是， 把candidates先sort，然后用index的方式来处理。\n\n\n所以最终的除重大法如下，根据hint做出：\n\n```python\nclass Solution(object):\n    def combinationSum(self, candidates, target):\n        \"\"\"\n        :type candidates: List[int]\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        def dfs(remain, combo, index):\n            if remain == 0:\n                res.append(combo)\n                return\n            for i in range(index, len(candidates)):\n                if candidates[i] > remain:\n                    break          \n                dfs(remain - candidates[i], combo + [candidates[i]], i)\n        candidates = list(set(candidates))\n        candidates.sort()\n        res = []\n        dfs(target, [], 0)\n        return res\n```\n"
  },
  {
    "path": "docs/leetcode/python/040._combination_sum_ii.md",
    "content": "### 40. Combination Sum II\n\n题目:\n\n<https://leetcode.com/problems/combination-sum-ii/>\n\n\n难度:\n\nMedium\n\n\nCombination Sum 已经AC，做了minor change.\n- 现在不需要```set```化```candidates```了\n- 但是递归的时候```index```要从```i+1```开始了\n- 要判断```combo not in res```才```append```到```res```中去\n\n```python\nclass Solution(object):\n    def combinationSum2(self, candidates, target):\n        \"\"\"\n        :type candidates: List[int]\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        def dfs(remain, combo, index):\n            if remain == 0 and combo not in res:\n                res.append(combo)\n                return\n            for i in range(index, len(candidates)):\n                if candidates[i] > remain:\n                    break          \n                dfs(remain - candidates[i], combo + [candidates[i]], i+1)\n        candidates.sort()\n        res = []\n        dfs(target, [], 0)\n        return res\n        \n```\n"
  },
  {
    "path": "docs/leetcode/python/041._First_Missing_Positive.md",
    "content": "#  41. First Missing Positive\n**<font color=red>难度: 困难</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/first-missing-positive\n\n> 内容描述\n\n```\nGiven an unsorted integer array, find the smallest missing positive integer.\n\nExample 1:\n\nInput: [1,2,0]\nOutput: 3\nExample 2:\n\nInput: [3,4,-1,1]\nOutput: 2\nExample 3:\n\nInput: [7,8,9,11,12]\nOutput: 1\nNote:\n\nYour algorithm should run in O(n) time and uses constant extra space.\n```\n\n## 解题方案\n\n> 思路 1\n\n题目要求O(n)时间和O(1)空间，所以我们知道先排序再循环找是不行的\n\n因此我们可以这样，第一轮循环，找1(因为1是最小的正整数)，如果1在，立马原地开始继续找2，以此类推，一轮循环结束后，我们记录下当前正在找的值i，\n并开始第二轮循环，但是这次从i开始找了，然后以此类推，直到有一次循环我们要找的值没有变过，则代表它没出现过，返回它即可\n\n可以看一个例子\n```\n[3,4,-1,1]\n\n第一轮循环：[1,1,1,2]\n第二轮循环：[2,2,2,2]\n\n然后我们发现第二轮循环2没有变过了，所以2就是我们要的结果\n```\n\n```python\nclass Solution(object):\n    def firstMissingPositive(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        old_missing, missing = 0, 1\n        while old_missing != missing:\n            old_missing = missing\n            for i in range(len(nums)):\n                if nums[i] == missing:\n                    missing += 1\n        return missing\n```\n\n> 思路 2\n\n如果不限制空间的话，我们用一个dict就可以解决, 时间是O(N)\n\n\n```python\nclass Solution(object):\n    def firstMissingPositive(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 1\n        lookup = {}\n        for i in nums:\n            lookup[i] = 1\n        for i in range(1, max(nums)+2):\n            if i not in lookup:\n                return i\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/042._trapping_rain_water.md",
    "content": "### 42. Trapping Rain Water\n\n\n\n题目:\n<https://leetcode.com/problems/trapping-rain-water/>\n\n\n难度:\nHard\n\n思路：\n\n题目有几个特性可用，bar width = 1,然后第一个和最后一个是不能trap water，其次中间的部分能trap多少水是看`左右高度差较低的那个 -  本身的高度`\n\nThe basic idea is that we set two pointers ```l``` and ```r``` to the left and right end of ```height```. Then we get the minimum height (```min_height```) of these pointers (similar to Container with Most Water due to the Leaking Bucket Effect) since the level of the water cannot be higher than it. Then we move the two pointers towards the center. If the coming level is less than ```min_height```, then it will hold some water. Fill the water until we meet some “barrier” (with height larger than ```min_height```) and update ```l``` and ```r``` to repeat this process in a new interval.\n\nAC代码：\n\n\n```python\nclass Solution(object):\n    def trap(self, height):\n        \"\"\"\n        :type height: List[int]\n        :rtype: int\n        \"\"\"\n        l, r, water, min_height = 0, len(height) - 1, 0, 0\n        while l < r:\n            min_height = min(height[l], height[r])\n            while l < r and height[l] <= min_height:\n                water += min_height - height[l] \n                l += 1\n            while l < r and height[r] <= min_height:\n                water += min_height - height[r]\n                r -= 1\n        return water\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/043._multiply_strings.md",
    "content": "# 43. Multiply Strings 字符串相乘\n\n## 刷题内容\n\n* https://leetcode.com/problems/multiply-strings\n* https://leetcode-cn.com/problems/multiply-strings\n\n## 难度: Medium \n\n\n参考了别人的思路：\n\n1. m位的数字乘以n位的数字的结果最大为m+n位：\n    * 999*99 < 1000*100 = 100000，最多为3+2 = 5位数。\n2. 先将字符串逆序便于从最低位开始计算。\n\n\n\n```python\nclass Solution(object):\n    def multiply(self, num1, num2):\n        \"\"\"\n        :type num1: str\n        :type num2: str\n        :rtype: str\n        \"\"\"\n        lookup = {\"0\":0,\"1\":1,\"2\":2,\"3\":3,\"4\":4,\"5\":5,\"6\":6,\"7\":7,\"8\":8,\"9\":9} # 节省查找时间，避免无休止使用ord函数来得到数字\n        if num1 == '0' or num2 == '0':\n            return '0'\n        num1, num2 = num1[::-1], num2[::-1]\n        \n        tmp_res = [0 for i in range(len(num1)+len(num2))]\n        for i in range(len(num1)):\n            for j in range(len(num2)):\n                tmp_res[i+j] += lookup[num1[i]] * lookup[num2[j]]\n\n        res = [0 for i in range(len(num1)+len(num2))]\n        for i in range(len(num1)+len(num2)):\n            res[i] = tmp_res[i] % 10\n            if i < len(num1)+len(num2)-1:\n                tmp_res[i+1] += tmp_res[i]/10 \n        return ''.join(str(i) for i in res[::-1]).lstrip('0')  # 去掉最终结果头部可能存在的‘0’\n```\n\n觉得这样写才是最容易理解的，看一个具体的🌰:\n```\ninput: num1, num2 = '91', '91'\ntmp_res = [1,18,81,0]\nres = [1,8,2,8]\n\n最终返回 \"8281\"\n\n要注意最终返回头部可能会有‘0’，所以我们用lstrip去除一下\n```\n"
  },
  {
    "path": "docs/leetcode/python/044._wildcard_matching.md",
    "content": "###44. Wildcard Matching\n\n题目:\n<https://leetcode.com/problems/wildcard-matching/>\n\n\n难度:\n\nHard\n\n\n\n做完Regular Expression Matching来做的这道题，按照DP思路run一下是超时，感觉是开心的，至少暂时没有报错了，有待优化，应该在dp的同时在贪心一下么。\n\n\n\n超时代码\n```\nclass Solution(object):\n    def isMatch(self, s, p):\n        \"\"\"\n        :type s: str\n        :type p: str\n        :rtype: bool\n        \"\"\"\n        m, n = len(s), len(p)\n        dp = [ [0 for i in xrange(n+1)] for j in xrange(m+1)]\n\n        dp[0][0] = 1\n\n        # init the first line\n        for i in xrange(1,n+1):\n            if p[i-1] == '*':\n                dp[0][i] = dp[0][i-1]\n\n        for i in xrange(1,m+1):\n            for j in xrange(1,n+1):\n                if p[j-1] == s[i-1] or p[j-1] == '?':\n                    dp[i][j] = dp[i-1][j-1]\n                elif p[j-1] == '*':\n                    dp[i][j] = dp[i][j-1] or dp[i-1][j]\n\n        return dp[m][n] == 1 \n```"
  },
  {
    "path": "docs/leetcode/python/045._Jump_Game_II.md",
    "content": "### 45. Jump Game II\n\n题目:\n<https://leetcode.com/problems/jump-game-ii/>\n\n\n难度:\n\nEasy\n\n\n思路\n\ngreedy solution, the current jump is ```[i, cur_end]```, and the ```cur_farthest``` is the farthest point \nthat all of point in ```[i, cur_end]``` can reach, whenever ```cur_farthest``` is larger than the last point' index, \nreturn current ```jump+1```; whenever ```i``` reaches ```cur_end```, update ```cur_end``` to ```current cur_farthest```.\n- Time: O(log(n))\n- Space: O(1)\n\n```python\nclass Solution(object):\n    def jump(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        # Note You can assume that you can always reach the last index.\n        cur_end, cur_farthest, step, n = 0, 0, 0, len(nums)\n        for i in range(n-1):\n            cur_farthest = max(cur_farthest, i + nums[i])\n            if cur_farthest >= n - 1:\n                step += 1\n                break\n            if i == cur_end:\n                cur_end = cur_farthest\n                step += 1\n        return step\n\n            \n        \n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/046._permutations.md",
    "content": "### 46. Permutations\n\n题目:\n<https://leetcode.com/problems/permutations/>\n\n\n难度:\n\nMedium \n\n\n每次取一个作为prefix, 剩下的继续做permutation，然后连接起来加入res中\n\n```python\nclass Solution(object):\n    def permute(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        if len(nums) == 0:\n            return []\n        if len(nums) == 1:\n            return [nums]\n        res = []\n        for i in range(len(nums)):\n            prefix = nums[i]\n            rest = nums[:i] + nums[i+1:]\n            for j in self.permute(rest):\n                res.append([prefix]+j)\n        return res\n```\n\n还有介绍的基本无memory使用的算法：\n\n\n```\nclass Solution:\n    def permute(self, num):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        if len(num) == 0: yield []\n        if len(num) == 1: yield [num]\n        res = []\n        for i in range(len(num)):\n            x  = num[i]\n            xs = num[:i] + num[i+1:]             \n            for j in self.permute(xs):\n                res.append([x] + j)\n        yield res\n\n```\n\n但是这个yield只是生产generator，要看结果还是要用for in 来查看res的。\n"
  },
  {
    "path": "docs/leetcode/python/047._permutations_ii.md",
    "content": "### 47. Permutations II\n\n题目:\n<https://leetcode.com/problems/permutations-ii/>\n\n\n难度:\n\nMedium \n\n跟第46题一样，就是最后append的时候不一样，只有没有结果里面没有的才加入\n\n\n```python\nclass Solution(object):\n    def permuteUnique(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        if len(nums) == 0:\n            return []\n        if len(nums) == 1:\n            return [nums]\n        res = []\n        for i in range(len(nums)):\n            prefix = nums[i]\n            rest = nums[:i] + nums[i+1:]\n            for j in self.permuteUnique(rest):\n                if [prefix]+j not in res:\n                    res.append([prefix]+j)\n        return res\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/048._rotate_image.md",
    "content": "### 48. Rotate Image\n\n\n题目:\n<https://leetcode.com/problems/rotate-image/>\n\n\n难度:\n\nMedium\n\n\n\n\n思路一：\n\n\n先将矩阵上下翻转，然后将矩阵中心对称翻转，即可实现顺时针90度旋转。\n\n\n- 上下翻转规律 [i][:] --> [n-1-i][:]\n- 对角线变换的规律是 [i][j] --> [j][i]\n\n\n例如：\n```\n1 1 1    3 3 3    3 2 1\n2 2 2 -> 2 2 2 -> 3 2 1\n3 3 3    1 1 1    3 2 1\n```\n\n\n```python\nclass Solution(object):\n    def rotate(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: void Do not return anything, modify matrix in-place instead.\n        \"\"\"\n        n = len(matrix)\n        # 上下翻转\n        for i in range(n/2):\n            matrix[i], matrix[n-1-i] = matrix[n-1-i], matrix[i]\n        # 主对角线翻转\n        for i in range(n):\n            for j in range(i+1,n):\n                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]\n```\n\n\n思路二：\n\n参考这里\n\n<http://www.lifeincode.net/programming/leetcode-rotate-image-java/>\n\n找规律，一次完成四个数的该有的变换\n\n```\n\n1 \t2 \t3 \t4 \t5 \t\t\t\t\t\n\n6 \t7 \t8 \t9 \t10 \t\n\n11 \t12 \t13 \t14 \t15 \t\n\n16 \t17 \t18 \t19 \t20 \t\n\n21 \t22 \t23 \t24 \t25 \n\n```\n\n在思路一的解法下观察得出，每个元素的变换是 [x][y] -> [n-1-x][y] -> [y][n-1-x] -> [n-1-y][x]\n\n\n```python\nclass Solution(object):\n    def rotate(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: void Do not return anything, modify matrix in-place instead.\n        \"\"\"\n        n = len(matrix)\n        for i in range(n/2):\n            for j in range(n-n/2):\n                matrix[i][j], matrix[~j][i], matrix[~i][~j], matrix[j][~i] = \\\n                         matrix[~j][i], matrix[~i][~j], matrix[j][~i], matrix[i][j]\n```\n这里的```[~i]``` 意思就是 ```[n-1-i]```\n\n思路三：\n\n直接用zip函数，一行, 😂\n\n```python\nclass Solution:\n    def rotate(self, A):\n        A[:] = zip(*A[::-1])\n        # A[:] = map(list, zip(*A[::-1]))\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/049._group_anagrams_python.md",
    "content": "### 49. Group Anagrams python\n\n题目： \n<https://leetcode.com/problems/anagrams/>\n\n\n难度 : Medium\n\npython大法好\n\n\n```python\nclass Solution(object):\n    def groupAnagrams(self, strs):\n        \"\"\"\n        :type strs: List[str]\n        :rtype: List[List[str]]\n        \"\"\"\n        mapx = {}\n        for i in strs:\n            x = ''.join(sorted(list(i)))\n            if x in mapx:\n                mapx[x].append(i)\n            else:\n                mapx[x] = [i]\n        return mapx.values()\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/050._pow(x,_n).md",
    "content": "### 50. Pow(x, n)\n\n题目:\n<https://leetcode.com/problems/powx-n/>\n\n\n难度:\n\nMedium\n\n\nRecursive\n\n```python\nclass Solution(object):\n    def myPow(self, x, n):\n        \"\"\"\n        :type x: float\n        :type n: int\n        :rtype: float\n        \"\"\"\n        if n == 0:\n            return 1\n        if n < 0:\n            return 1 / self.myPow(x, -n)\n        if n % 2 == 0:\n            return self.myPow(x*x, n/2)\n        else:\n            return x * self.myPow(x*x, n/2)\n        \n```\niterative\n\n\n```python\nclass Solution:\n    def myPow(self, x, n):\n        if n < 0:\n            x = 1 / x\n            n = -n\n        pow = 1\n        while n:\n            if n & 1:\n                pow *= x\n            x *= x\n            n >>= 1\n        return pow\n```\n"
  },
  {
    "path": "docs/leetcode/python/051._n-queens.md",
    "content": "### 51. N-Queens\n\n题目:\n<https://leetcode.com/problems/n-queens/>\n\n\n难度:\nHard\n\n八皇后问题是一个以国际象棋为背景的问题：如何能够在8×8的国际象棋棋盘上放置八个皇后，使得任何一个皇后都无法直接吃掉其他的皇后？为了达到此目的，任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题：这时棋盘的大小变为n×n，而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解[1]。\n\n对于任意(x,y),如果要让新的点和它不能处于同一条横行、纵行或斜线上，则新点(p,q)必须要满足p+q != x+y 和p-q!= x-y, 前者针对左下右上斜线，后者针对左上右下斜线，两者同时都保证了不在同一条横行和纵行上。 \n\n代码中变量的含义:\n- col_per_row: 每一行皇后的column位置组成的列表\n- cur_row：目前正在判断的row的index\n- xy_diff：所有x-y组成的列表\n- xy_sum：所有x+y组成的列表\n\n```python\nclass Solution(object):\n    def solveNQueens(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[List[str]]\n        \"\"\"\n        def dfs(col_per_row, xy_diff, xy_sum):\n            cur_row = len(col_per_row)\n            if cur_row == n:\n                ress.append(col_per_row)\n            for col in range(n):\n                if col not in col_per_row and cur_row-col not in xy_diff and cur_row+col not in xy_sum:\n                    dfs(col_per_row+[col], xy_diff+[cur_row-col], xy_sum+[cur_row+col])\n        ress = []\n        dfs([], [], [])\n        return [['.'*i + 'Q' + '.'*(n-i-1) for i in res] for res in ress]\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/052._n-queens_ii.md",
    "content": "### 52. N-Queens II\n\n题目:\n<https://leetcode.com/problems/n-queens-ii/>\n\n\n难度:\nHard\n\n思路参见recursion & backtracking\n\nn queens还是属于比较难的，需要花时间吃透的问题\n\n八皇后问题是一个以国际象棋为背景的问题：如何能够在8×8的国际象棋棋盘上放置八个皇后，使得任何一个皇后都无法直接吃掉其他的皇后？为了达到此目的，任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题：这时棋盘的大小变为n×n，而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解[1]。\n\n对于任意(x,y),如果要让新的点和它不能处于同一条横行、纵行或斜线上，则新点(p,q)必须要满足p+q != x+y 和p-q!= x-y, 前者针对左下右上斜线，后者针对左上右下斜线，两者同时都保证了不在同一条横行和纵行上。 \n\n代码中变量的含义:\n- col_per_row: 每一行皇后的column位置组成的列表\n- cur_row：目前正在判断的row的index\n- xy_diff：所有x-y组成的列表\n- xy_sum：所有x+y组成的列表\n\n```python\nclass Solution(object):\n    def totalNQueens(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        def dfs(col_per_row, xy_diff, xy_sum):\n            cur_row = len(col_per_row)\n            if cur_row == n:\n                ress.append(col_per_row)\n            for col in range(n):\n                if col not in col_per_row and cur_row-col not in xy_diff and cur_row+col not in xy_sum:\n                    dfs(col_per_row+[col], xy_diff+[cur_row-col], xy_sum+[cur_row+col])\n        ress = []\n        dfs([], [], [])\n        return len(ress)\n        \n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/053._maximum_subarray.md",
    "content": "# 53. Maximum Subarray 最大子序和\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/maximum-subarray\n* https://leetcode-cn.com/problems/maximum-subarray\n\n> 内容描述\n\n```\n给定一个整数数组 nums ，找到一个具有最大和的连续子数组（子数组最少包含一个元素），返回其最大和。\n\n示例:\n\n输入: [-2,1,-3,4,-1,2,1,-5,4],\n输出: 6\n解释: 连续子数组 [4,-1,2,1] 的和最大，为 6。\n\n进阶:\n\n如果你已经实现复杂度为 O(n) 的解法，尝试使用更为精妙的分治法求解。\n```\n\n## 解题方案\n\n> 思路 1\n\nO(N^2)\n\n从i开始，计算i到n，存比较大的sum，会超时\n\n```\nclass Solution(object):\n\tdef maxSubArray(self, nums):\n\t    \"\"\"\n\t    :type nums: List[int]\n\t    :rtype: int\n\t    \"\"\"\n\t    n = len(nums)\n\t    m = float('-inf')\n\t    for i in range(n):\n\t    \ts = 0\n\t    \tfor j in range(i,n):\n\t    \t\ts = s + nums[j]\n\t    \t\tm = max(m,s)\n\t    return m \n```\n\n> 思路 2\n\n* 动态规划（只关注：当然值 和 当前值+过去的状态，是变好还是变坏，一定是回看容易理解）\n* ms(i) = max(ms[i-1]+ a[i],a[i])\n* 到i处的最大值两个可能，一个是加上a[i], 另一个从a[i]起头，重新开始。可以AC\n\n```python\nclass Solution(object):\n    def maxSubArray(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(nums)\n        maxSum = [nums[0] for i in range(n)]\n        for i in range(1,n):\n        \tmaxSum[i] = max(maxSum[i-1] + nums[i], nums[i])\n        return max(maxSum)\n```\n\n> 思路 3\n\nKadane’s Algorithm wikipedia可以查到,然后一般的是负的可以还回0，这里需要稍作修改，参考\n\n<http://algorithms.tutorialhorizon.com/kadanes-algorithm-maximum-subarray-problem/>\n\n\n```\nstart:\n    max_so_far = a[0]\n    max_ending_here = a[0]\n\nloop i= 1 to n\n  (i) max_end_here = Max(arrA[i], max_end_here+a[i]);\n  (ii) max_so_far = Max(max_so_far,max_end_here);\n\nreturn max_so_far\n\n```\n\nAC代码：\n\n```python\nclass Solution(object):\n    def maxSubArray(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(nums)\n        maxSum , maxEnd = nums[0], nums[0]\n        \n        for i in range(1,n):\n        \tmaxEnd = max(nums[i],maxEnd + nums[i])\n        \tmaxSum = max(maxEnd,maxSum)\n        return maxSum\n```\n\n> 思路 4\n\n参见clrs 第71页，用divide and conquer，有伪码\n\n最大的subarray sum有三个可能，左半段或者右半段，或者跨越左右半段,\n\n速度比较慢，AC代码，复杂度O(NlogN)\n\n```\nclass Solution(object):\n\tdef maxSubArray(self, nums):\n\t\t\"\"\"\n\t\t:type nums: List[int]\n\t\t:rtype: int\n\t\t\"\"\"\n\t\tdef find_max_crossing_subarray(nums, low, mid, high):\n\t\t\tleft_sum = float('-inf')\n\t\t\tsum = 0\n\t\t\tfor i in xrange(mid,low-1,-1):\n\t\t\t\tsum = sum + nums[i]\n\t\t\t\tif sum > left_sum:\n\t\t\t\t\tleft_sum = sum\n\n\t\t\tright_sum = float('-inf')\n\t\t\tsum = 0\n\t\t\tfor j in range(mid+1,high+1):\n\t\t\t\tsum = sum + nums[j]\n\t\t\t\tif sum > right_sum:\n\t\t\t\t\tright_sum = sum\n\n\t\t\treturn left_sum + right_sum\n\n\t\tdef find_max_subarray(nums,low,high):\n\t\t\tif low == high: \n\t\t\t\treturn nums[low]\n\t\t\telse:\n\t\t\t\tmid = (low + high) / 2\n\t\t\t\tleft_sum = find_max_subarray(nums, low, mid)\n\t\t\t\tright_sum = find_max_subarray(nums,mid+1,high)\n\t\t\t\tcross_sum = find_max_crossing_subarray(nums,low,mid,high)\n\t\t\t\t# print left_sum, right_sum, cross_sum\n\t\t\t\t# print mid, low, high\n\t\t\t\treturn max(left_sum, right_sum, cross_sum)\n\n\t\treturn find_max_subarray(nums, 0, len(nums)-1)\n```\n"
  },
  {
    "path": "docs/leetcode/python/054._spiral_matrix.md",
    "content": "### 54. Spiral Matrix\n\n题目:\n<https://leetcode.com/problems/spiral-matrix/>\n\n\n难度:\nMedium\n\n\n参考别人的代码，一开始觉得很有递归性，根据奇偶不同来写，递归太难写。\n\n然后想到了loop，再想，可能有更优trick，事实证明并没有。\n\n用四个变量来控制边界，然后因为方向总是：→↓←↑ 左右下上\n\n\n\n\n```python\nclass Solution(object):\n    def spiralOrder(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: List[int]\n        \"\"\"\n        if matrix == [] : return []\n        res = []\n        maxUp = maxLeft = 0\n        maxDown = len(matrix) - 1\n        maxRight = len(matrix[0]) - 1 \n        direction = 0 # 0 go right, 1 go down, 2 go left, 3 up\n        while True:\n            if direction == 0: #go right\n                for i in range(maxLeft, maxRight+1):\n                    res.append(matrix[maxUp][i])\n                maxUp += 1\n            elif direction == 1: # go down\n                for i in range(maxUp, maxDown+1):\n                    res.append(matrix[i][maxRight])\n                maxRight -= 1\n            elif direction == 2: # go left\n                for i in reversed(range(maxLeft, maxRight+1)):\n                    res.append(matrix[maxDown][i])\n                maxDown -= 1\n            else: #go up\n                for i in reversed(range(maxUp, maxDown+1)):\n                    res.append(matrix[i][maxLeft])\n                maxLeft +=1\n            if maxUp > maxDown or maxLeft > maxRight:\n                return res\n            direction = (direction + 1 ) % 4 \n```\n\n以上的写法非常精妙，看看我自己用同样的思路写的||||\n\n```python\nclass Solution(object):\n    def spiralOrder(self, matrix):\n\t\t\"\"\"\n\t\t:type matrix: List[List[int]]\n\t\t:rtype: List[int]\n\t\t\"\"\"\n\t\tif len(matrix) == 0 : return []\n\n\t\tleft = 0\n\t\tup = 0\n\t\tdown = len(matrix) - 1\n\t\tright = len(matrix[0]) -1\n\n\t\t# 0 -> right, 1 -> down, 2-> left, 3 -> up\n\t\tdirection = 0\n\n\t\t# start location\n\t\tx, y = 0,0 \n\t\tres = []\n\n\t\twhile True:\n\t\t\tif left > right or up > down:\n\t\t\t\treturn res\n\n\t\t\tif direction == 0 :\n\t\t\t\twhile y <= right:\n\t\t\t\t\tres.append(matrix[up][y])\n\t\t\t\t\ty += 1\n\t\t\t\tup += 1\n\t\t\t\tx = up\n\t\t\t\tdirection = 1\n\t\t\t\tcontinue\n\n\t\t\tif direction == 1:\n\t\t\t\twhile x <= down:\n\t\t\t\t\tres.append(matrix[x][right])\n\t\t\t\t\tx += 1\n\t\t\t\tright -= 1\n\t\t\t\ty = right\n\t\t\t\tdirection = 2\n\t\t\t\tcontinue\n\n\t\t\tif direction == 2:\n\t\t\t\twhile y >= left:\n\t\t\t\t\tres.append(matrix[down][y])\n\t\t\t\t\ty -= 1\n\t\t\t\tdown -= 1\n\t\t\t\tx = down\n\t\t\t\tdirection = 3\n\t\t\t\tcontinue\n\n\t\t\tif direction == 3:\n\t\t\t\twhile x >= up:\n\t\t\t\t\tres.append(matrix[x][left])\n\t\t\t\t\tx -= 1\n\t\t\t\tleft += 1\n\t\t\t\ty = left\n\t\t\t\tdirection = 0\n\t\t\t\tcontinue\n\n```\n\n明显别人的代码写的更精妙，因为这里两个boundary都很明确，所以用for in range就能很好的解决问题了.\n\n\n\n\n\n-----------\n\n最后放一个无敌一行，怕你看完不想看上面的代码了\n```python\nclass Solution(object):\n    def spiralOrder(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: List[int]\n        \"\"\"\n        return matrix and list(matrix.pop(0)) + self.spiralOrder(zip(*matrix)[::-1])\n```\n\noh, my god!\n"
  },
  {
    "path": "docs/leetcode/python/055._jump_game.md",
    "content": "### 55. Jump Game\n\n题目:\n<https://leetcode.com/problems/jump-game/>\n\n\n难度:\n\nMedium\n\n\n问题出现在一旦有0，而且这个0是不可跨过的那么无解，无法达到\n\n\n看了hint，根本不用这个数组，直接用一个数来记录可达最远距离，非常巧妙\n\n\n```python\nclass Solution(object):\n    def canJump(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        if not nums:\n            return True\n        if len(nums) == 1:\n            return True\n        n = len(nums)\n        idx, reach = 0, 0\n        while idx < n-1 and idx <= reach:  # idx <= reach是为了处理nums[idx] == 0的情况，若idx>reach说明已经失败了\n            reach = max(reach, idx+nums[idx])\n            idx += 1\n        return reach >= n-1\n```\n\nidx记录当前loop位置，reach记录当前可到位置\n\n注意这里的while循环的条件是 `idx < n-1 and idx <= reach`，之所以加上 `idx <= reach` 是因为如果```idx > reach```说明```idx```层不可达，其实也可以直接terminate.\n"
  },
  {
    "path": "docs/leetcode/python/056._Merge_Intervals.md",
    "content": "### 56. Merge Intervals\n\n题目:\n<https://leetcode.com/problems/merge-intervals/>\n\n\n难度:\n\nMedium\n\n\nJust go through the intervals sorted by start coordinate and \neither combine the current interval with the previous one if they overlap, or add it to the output by itself if they don’t.\n\n```python\nclass Solution(object):\n    def merge(self, intervals):\n        \"\"\"\n        :type intervals: List[Interval]\n        :rtype: List[Interval]\n        \"\"\"\n        res = []\n        for i in sorted(intervals, key = lambda i: i.start):\n            if res and i.start <= res[-1].end:\n                res[-1].end = max(i.end, res[-1].end)\n            else:\n                res.append(i)\n        return res\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/058._length_of_last_word.md",
    "content": "### 58. Length of Last Word\n\n题目： \n<https://leetcode.com/problems/length-of-last-word/>\n\n\n难度 : Easy\n\n我的解法：\n\n```python\nclass Solution(object):\n    def lengthOfLastWord(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        s = s[::-1].strip()\n        return s.find(' ') if s.find(' ') != -1 else len(s)\n```\n作弊式做法\n\n```python\nclass Solution(object):\n    def lengthOfLastWord(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        lst = s.split()\n        if len(lst) >= 1:\n        \treturn len(lst[-1])\n        return 0\n```\nsplit()方法最低可以分0组，split(' ')最低可以分1组\n```python\n一行解法：\nclass Solution(object):\n    def lengthOfLastWord(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        return len(s.strip().split(\" \")[-1])\n```\n"
  },
  {
    "path": "docs/leetcode/python/059._spiral_matrix_ii.md",
    "content": "### 59. Spiral Matrix II\n\n题目:\n<https://leetcode.com/problems/spiral-matrix-ii/>\n\n\n难度:\nMedium\n\n和Spiral Matrix的思路基本一致\n\n也许还有待挖掘trick\n\n\n```python\nclass Solution(object):\n    def generateMatrix(self,n):\n        \"\"\"\n        :type n: int\n        :rtype: List[List[int]]\n        \"\"\"\n        curNum = 0\n        matrix = [[0 for i in range(n)] for j in range(n)]\n        maxUp = maxLeft = 0 \n        maxDown = maxRight = n - 1\n        direction = 0                \n        while True:\n            if direction == 0: #go right\n                for i in range(maxLeft, maxRight+1):\n                    curNum += 1\n                    matrix[maxUp][i] = curNum\n                maxUp += 1\n            elif direction == 1: # go down\n                for i in range(maxUp, maxDown+1):\n                    curNum += 1\n                    matrix[i][maxRight] = curNum\n                maxRight -= 1\n            elif direction == 2: # go left\n                for i in reversed(range(maxLeft, maxRight+1)):\n                    curNum += 1 \n                    matrix[maxDown][i] = curNum\n                maxDown -= 1\n            else: #go up\n                for i in reversed(range(maxUp, maxDown+1)):\n                    curNum += 1\n                    matrix[i][maxLeft] = curNum\n                maxLeft +=1\n            if curNum >= n*n:\n                return matrix\n            direction = (direction + 1 ) % 4\n```\n\nSame idea with [spiral matrix I](https://github.com/Lisanaaa/thinking_in_lc/blob/master/054._spiral_matrix.md)\n```python\nclass Solution(object):\n    def generateMatrix(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[List[int]]\n        \"\"\"\n        res = []\n        l = n * n + 1\n        while l > 1:\n            l, r = l - len(res), l\n            res = [range(l, r)] + zip(*res[::-1])\n        return res\n```\n"
  },
  {
    "path": "docs/leetcode/python/060._permutation_sequence.md",
    "content": "###60. Permutation Sequence\n\n题目:\n<https://leetcode.com/problems/permutation-sequence/>\n\n\n难度:\n\nMedium \n\n\n\n偷懒，用46的方法，会超时\n\n```\n\nclass Solution(object):\n    def getPermutation(self, n, k):\n        \"\"\"\n        :type n: int\n        :type k: int\n        :rtype: str\n        \"\"\"\n        self.result = []\n        s = \"\"\n        for i in range(1, n+1):\n          s += str(i)\n        self.recPermute(\"\",s,k)\n        return self.result[-1]\n        \n\n    def recPermute(self, sofar, rest, k):\n      if rest == \"\":\n        if len(self.result) == k:\n          return\n        self.result.append(sofar)\n      else:\n        for i in xrange(len(rest)):\n          nnext = sofar + rest[i]\n          remaining = rest[:i] + rest[i+1:]\n          self.recPermute(nnext, remaining, k)\n```\n\n\n然后其实有规律的，比如\n\n```\n1 \"123\"\n2 \"132\"\n3 \"213\"\n4 \"231\"\n5 \"312\"\n6 \"321\"\n```\n\n是第n个数 + 余下的n-1个数的permutation\n\n\nk = 1 就是所有的顺序排列\nk = n! 是所有的逆序排列\n\n对于余下的也是递归，比如\n\n\nk < (n-1)!  1 + (n-1)个数的全排列的第k个\nk < 2*(n-1)! 2 + (n-1)个数的顺序全排列的第k个\n\n\n发现思路对了，但是implement还有点困难.\n\n看了一个最为精妙的解法\n\n```\nclass Solution(object):\n    def getPermutation(self, n, k):\n        \"\"\"\n        :type n: int\n        :type k: int\n        :rtype: str\n        \"\"\"\n        seq, k, fact = '', k-1, math.factorial(n-1)\n        perm = [i for i in range(1, n+1)]\n        for i in reversed(xrange(n)):\n            curr = perm[k/fact]\n            seq += str(curr)\n            perm.remove(curr)\n            if i > 0:\n                k %= fact\n                fact /= i\n        return seq\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/061._rotate_list.md",
    "content": "\n###61. Rotate List\n\n\n题目:\n<https://leetcode.com/problems/rotate-list/>\n\n\n难度:\n\nMedium\n\n- k可能比list的size大，需要做一个取余准备\n- 计算list size的同时把tail也记录下来，方便之后把tail的next指向原本的head\n- 利用之前的到末端的kth node\n\n\nAC 代码\n\n```\nclass Solution(object):\n    def rotateRight(self, head, k):\n    \tif head == None or k == 0 :\n    \t\treturn head\n\n    \tcur = head\n    \tsize = 1\n    \twhile cur.next:\n    \t\tsize += 1\n    \t\tcur = cur.next\n\n    \ttail = cur\n\n    \tk = k % size\n\n        p = self.findKth(head,k)\n\n        tail.next = head\n        head = p.next\n        p.next = None\n        return head\n\n    def findKth(self,head, k):\n        dummy = ListNode(-1)\n        dummy.next = head\n        p = dummy\n        q = dummy\n        \n        for i in range(k):\n            q = q.next\n            \n        while q.next:\n            p = p.next\n            q = q.next\n        return p\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/062._unique_paths.md",
    "content": "# 62. unique paths 不同路径\n\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/unique-paths\n* https://leetcode-cn.com/problems/unique-paths\n\n> 内容描述\n\n```\n一个机器人位于一个 m x n 网格的左上角 （起始点在下图中标记为“Start” ）。\n\n机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角（在下图中标记为“Finish”）。\n\n问总共有多少条不同的路径？\n```\n\n![](https://leetcode-cn.com/img/problemset/robot_maze.png)\n\n```\n例如，上图是一个7 x 3 的网格。有多少可能的路径？\n\n说明：m 和 n 的值均不超过 100。\n\n> 示例 1:\n\n输入: m = 3, n = 2\n输出: 3\n解释:\n从左上角开始，总共有 3 条路径可以到达右下角。\n1. 向右 -> 向右 -> 向下\n2. 向右 -> 向下 -> 向右\n3. 向下 -> 向右 -> 向右\n\n> 示例 2:\n\n输入: m = 7, n = 3\n输出: 28\n```\n\n## 解题方案\n\n> 思路 1\n\n| | | |\n| - | - | - |\n| 1 | 1 | 1 |\n| 1 | 2 | 3 |\n| 1 | 3 | 6 |\n| 1 | 4 | 10 |\n| 1 | 5 | 15 |\n| 1 | 6 | 21 |\n| 1 | 7 | 28 |\n\n```python\nclass Solution:\n    def uniquePaths(self, m, n):\n        \"\"\"\n        :type m: int\n        :type n: int\n        :rtype: int\n        \"\"\"\n        if m < 1 or n < 1:\n            return 0\n        dp = [0] *n\n        dp[0] = 1    \n        for i in range(0,m):\n            for j in range(1,n):\n                dp[j] += dp[j-1]\n        return dp[n-1]\n```\n\n> 思路 2\n\n这道题我一看到就觉得这不就是排列组合吗，一共走m+n-2步, 其中m-1步是向右边走，所以不就是从m+n-2中选m-1个的问题吗，阶乘问题，so easy! 妈妈\n再也不用担心我的学习！！这个方法```beats 99.97%```\n\n```python\nclass Solution(object):\n    def uniquePaths(self, m, n):\n        \"\"\"\n        :type m: int\n        :type n: int\n        :rtype: int\n        \"\"\"\n        def factorial(num):\n            res = 1\n            for i in range(1, num+1):\n                res *= i\n            return res\n        return factorial(m+n-2)/factorial(n-1)/factorial(m-1)\n```\n另外补充一句，我发现math模块里面自带factorial函数，只要import math之后调用即可，\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/064._minimum_path_sum.md",
    "content": "# 64. Minimum Path Sum 最小路径和\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/minimum-path-sum\n* https://leetcode-cn.com/problems/minimum-path-sum\n\n> 内容描述\n\n```\n给定一个包含非负整数的 m x n 网格，请找出一条从左上角到右下角的路径，使得路径上的数字总和为最小。\n\n说明：每次只能向下或者向右移动一步。\n\n示例:\n\n输入:\n[\n  [1,3,1],\n  [1,5,1],\n  [4,2,1]\n]\n输出: 7\n解释: 因为路径 1→3→1→1→1 的总和最小。\n```\n\n## 解题方案\n\n> 思路 1\n\n* 经典的动态规划问题，和：72. 编辑距离 类似\n\n```python\nclass Solution(object):\n    def minPathSum(self, grid):\n        \"\"\"\n        :type grid: List[List[int]]\n        :rtype: int\n        \"\"\"\n        if not grid or len(grid) == 0:\n            return 0\n        row = len(grid)\n        col = len(grid[0]) if row else 0\n        dp = [[0 for j in range(col)] for i in range(row)]\n        for i in range(row):\n            for j in range(col):\n                if i > 0 and j > 0:\n                    dp[i][j] = min(dp[i-1][j]+grid[i][j], dp[i][j-1]+grid[i][j])\n                elif i > 0 and j == 0:\n                    dp[i][j] = sum([grid[k][0] for k in range(i+1)])\n                elif i == 0 and j > 0:\n                    dp[i][j] = sum([grid[0][k] for k in range(j+1)])\n                else:\n                    dp[i][j] = grid[0][0]\n        return dp[-1][-1]\n```\n"
  },
  {
    "path": "docs/leetcode/python/065.unique_paths_ii.md",
    "content": " ###65.Unique Paths II\n\n题目： \n<https://leetcode.com/problems/unique-paths-ii/>\n\n\n\ntag : DP\n\n难度 : Medium\n\n\n\n\n\n```\nBASE CASE（ i = 0 , j = 0）: \n//第一排和第一列，如果没有obstacle， 则走法为1， 一旦有了obstacle，则之后的格子走法都为0\n\n非BASE CASE ：\n//一旦有obstacle，则dp为0\ndp(i, j) = dp（i,j-1) + dp(i-1,j)\n\n```\n\nPython代码\n\n```\nclass Solution(object):\n    def uniquePathsWithObstacles(self, obstacleGrid):\n        \"\"\"\n        :type obstacleGrid: List[List[int]]\n        :rtype: int\n        \"\"\"\n        row = len(obstacleGrid)\n        col = len(obstacleGrid[0])\n        dp  = [[0 for i in range(col)] for j in range(row)]\n\n        dp[0][0] = int(obstacleGrid[0][0] == 0)\n\n        #first row    \n        for j in range(1,col):\n            if obstacleGrid[0][j] == 1:\n                dp[0][j] = 0\n            else:\n                dp[0][j] = dp[0][j-1]\n        #first col\n        for i in range(1,row):\n            if obstacleGrid[i][0] == 1:\n                dp[i][0] = 0\n            else:\n                dp[i][0] = dp[i-1][0]\n\n        for i in range(1,row):\n            for j in range(1,col):\n                if obstacleGrid[i][j] == 1:\n                    dp[i][j] = 0\n                else:\n                    dp[i][j] = dp[i-1][j] + dp[i][j-1]\n        return dp[row-1][col-1]\n            \n```\n\n犯了一个错，简直觉得不可思议。一开始初始化dp用的代码是 \n\n```\ndp  = [[0] * col] * row\n```\n\n问题在此：\n\n\n```\n>>> x = [[]] * 3\n>>> x[1].append(0)\n>>> x\n[[0], [0], [0]]\n```\n\n这样初始化是做了三个一样的object.\n\nThe problem is that they're all the same exact list in memory. When you use the [x]*n syntax, what you get is a list of n many x objects, but they're all references to the same object. They're not distinct instances, rather, just n references to the same instance.\n\n参见stackoverflow : <http://stackoverflow.com/questions/12791501/python-initializing-a-list-of-lists>\n"
  },
  {
    "path": "docs/leetcode/python/066._plus_one.md",
    "content": "### 66. Plus One\n\n题目： \n<https://leetcode.com/problems/plus-one/>\n\n\n难度 : Easy\n\n\n\n\n这里是用的递归，很容易理解，如果空列表直接加1，最后一位小于9，那么直接就最后一位加1，否则添加一个0，然后再把余下的递归加1\n\n\n```python\n\nclass Solution(object):\n    def plusOne(self, digits):\n        \"\"\"\n        :type digits: List[int]\n        :rtype: List[int]\n        \"\"\"\n        if digits == []:\n            return [1]\n        if digits[-1] < 9:\n            return digits[:-1] + [digits[-1] + 1]\n        else:\n            return self.plusOne(digits[:-1]) + [0]\n```\n\n\n其实可以考虑循环，效率更高，参考[此处](https://shenjie1993.gitbooks.io/leetcode-python/content/066%20Plus%20One.html)\n\n\n\n> 从低位到高位，如果后一位有进位的话，那么该位要加上一，否则退出循环。如果最高位也进位，那么在列表前要插入一个一。\n\n\n\n```\nclass Solution(object):\n    def plusOne(self, digits):\n        \"\"\"\n        :type digits: List[int]\n        :rtype: List[int]\n        \"\"\"\n        carry = 1\n\n        for i in range(len(digits)-1,-1,-1):\n            digits[i] += carry\n            if digits[i] < 10:\n                carry = 0\n                break\n            else:\n                digits[i] -= 10\n        if carry == 1:\n            digits.insert(0,1)\n        return digits\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/067._add_binary.md",
    "content": "###67. Add Binary\n\n题目： \n<https://leetcode.com/problems/add-binary/>\n\n\n难度 : Easy\n\n\n几种case：\n\n- a or b 为空，最简单\n- 唯一的问题是如果有进位的处理，进位的处理就是先让其中的一个数和```‘1’```做```addBinary```处理 ，然后再用```addBinary```\n\n```python     \nclass Solution(object):\n    def addBinary(self, a, b):\n        \"\"\"\n        :type a: str\n        :type b: str\n        :rtype: str\n        \"\"\"\n        if (a == '' or b == ''):\n            return a + b\n        elif a[-1] == '0' and b[-1] == '0':\n            return self.addBinary(a[:-1], b[:-1])  +  '0'\n        elif a[-1] == '1' and b[-1] == '1':\n            return self.addBinary(a[:-1], self.addBinary(b[:-1],'1')) + '0'\n        else:\n            return self.addBinary(a[:-1], b[:-1]) + '1'\n```\n"
  },
  {
    "path": "docs/leetcode/python/069._sqrt(x).md",
    "content": "### 69. Sqrt(x)\n\n\n题目:\n<https://leetcode.com/problems/sqrtx/>\n\n\n难度:\n\nMedium\n\n\n思路：\n\n一看，觉得很容易，一写，超时：\n\n```\nclass Solution(object):\n    def mySqrt(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        i = 0\n        while i * i <= x :\n        \tif i * i == x:\n        \t\treturn i \n        \telif i * i < x and (i+1) * (i+1) > x:\n        \t\treturn i\n        \ti += 1\n```\n\n看一眼tag， binary search，难道从x/2之类的开始搜起来？话说还想到求sqrt有个🐂的牛顿法？\n\n莫名其妙过了的代码：\n\n```python\nclass Solution(object):\n    def mySqrt(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        if x == 1 : return 1\n        if x == 0 : return 0\n        l, r =  0, x - 1\n        while l <= r:\n        \tmid = l + ((r - l) >> 2)\n        \tif mid * mid <= x and (mid+1)*(mid+1) > x:\n        \t\treturn mid\n        \telif mid * mid > x:\n        \t\tr = mid - 1 \n        \telse:\n        \t\tl = mid + 1 \n```\n\n或者\n```python\nclass Solution(object):\n    def mySqrt(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        if x == 1:\n            return 1\n        if x == 0:\n            return 0\n        l, r = 0, x-1\n        while l <= r:\n            mid = l + ((r - l) >> 2)\n            if (mid * mid - x == 0):\n                return mid\n            elif (mid * mid - x > 0):\n                r = mid - 1\n            else:\n                l = mid + 1\n        return r\n```\n\n\n\n牛顿法\n\n参见wikipedia，to be done：自己推导一遍\n<https://zh.wikipedia.org/wiki/牛顿法>\n\n\n```python\nclass Solution(object):\n    def mySqrt(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: int\n        \"\"\"\n        res = 1.0\n        while abs(res * res - x) > 0.1:\n            res = (res + x / res) / 2\n        return int(res)\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/070._Climbing_Stairs.md",
    "content": "### 70. Climbing Stairs\n\n\n题目:\n<https://leetcode.com/problems/climbing-stairs/>\n\n\n难度:\nEasy\n\n思路：\n\nFibonacci 的DP版本\n\n对于DP的不同理解造成不同的写法\t\nMemoization will usually add on your time-complexity to your space-complexity (e.g. with tabulation you have more liberty to throw away calculations, like using tabulation with Fib lets you use O(1) space, but memoization with Fib uses O(N) stack space).\n详看\n\n[Dynamic programming and memoization: bottom-up vs top-down approaches](https://awjin.me/algos-js/dp/tab-memo.html)\n\n[Tabulation vs Memoizatation](http://www.geeksforgeeks.org/tabulation-vs-memoizatation/)\n-  top-down(memorize)\n\n```\ndef memorize_fib(n): # n为第几个Fibonacci数\n    memo = {1:1, 2:1}\n    if n in memo:\n        return memo[n]\n    else:\n        memo[n] = memorize_fib(n-1) + memorize_fib(n-2)\n        return memo[n]\n\nprint(memorize_fib(4))\n```\n输出```3```\n\n\n- bottom up(tabulation)\n\n```\ndef tabulation_fib(n):  # n为第几个Fibonacci数\n    fib = [1, 1, 2]\n    if n < 4:\n        return fib[n-1]\n    for k in range(3, n+1):\n        fib[2] = fib[0] + fib[1]\n        fib[0], fib[1] = fib[1], fib[2]\n    return fib[2]\n\nprint(tabulation_fib(4))\n```\n输出```3```\n\n这里memo用dict，用array也一样。当然用bottom up还有一点，可以只存每次最后两个数，可以save space.，这样就只用到constant space.\n\nAC 代码(这里采用bottom up思想)\n\n```python\nclass Solution(object):\n    def climbStairs(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        fib = [1, 2, 3]\n        if n < 4:\n            return fib[n-1]\n        for k in range(3, n+1):\n            fib[2] = fib[0] + fib[1]              # 永远只存3个元素，save space\n            fib[0], fib[1] = fib[1], fib[2]\n        return fib[2]\n```\n- Complexity Analysis\n\n        - Time complexity : O(n)\n\n        - Space complexity : O(1). Constant space is used.\n另外还有一个公式法：\n\n![](/img/Algorithm/LeetCode/41512784914_.pic.jpg)\n\n由于这里面相当于```standard Fibonacci```函数向前进了一步，排列为1，2，3，5而非原本的1，1，2，3，所以代码中使用```n+1```\n```python\nclass Solution(object):\n    def climbStairs(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        import math\n        sqrt5 = math.sqrt(5)\n        fibn = pow((1 + sqrt5) / 2, n+1) - pow((1 - sqrt5) / 2, n+1)\n        return int(float(fibn/sqrt5))\n```\n- Complexity Analysis\n\n        - Time complexity : O(lg(n)). pow method takes log(n) time.\n\n        - Space complexity : O(1). Constant space is used.\n"
  },
  {
    "path": "docs/leetcode/python/072._edit_distance.md",
    "content": "### 72. Edit Distance\n\n题目:\n<https://leetcode.com/problems/edit-distance/>\n\n\n难度:\n\nHard\n\n可以做的操作：\n\n- insert\n- delete\n- replace\n\n动归典型，原来也是有wikipedia page的算法\n\n<https://en.wikipedia.org/wiki/Edit_distance#Common_algorithm>\n\n<https://en.wikipedia.org/wiki/Levenshtein_distance>\n\n\n看wikipedia 这解释\n\n```\t\n\t\t/ max(i,j) \tif min(i,j) = 0\n\t\t\t\n\t\t\t\t   / dp[i-1][j] + 1     word1[i]不在word2[0...j]中,所以删除\n dp[i][j] -  min  -- dp[i][j-1] + 1     insertion\n \t\t\t\t   \\ dp[i-1][j-1] + 1/0  word[i]与word[j]是否相等\n```\n\n上面的就不用解释了，min分别对应：删除、插入、以及替代（1/0取决 word1[i] == word2[j] ），反正也是tabular类型，画表来解决问题。\n\n简单说，就是这样：\n\n1.delete：dp[i-1][j] + 1 —— 保留了从 word1[0:i-1] 转变到 word2[0:j] 的最优操作次数，因为我们的 word1 的 0~i-1 已经能够转变到 word2 了，\n所以我们就直接把 word1 中的最后一个字符删除掉就行了。所以就需要额外进行一个 删除 操作。\n\n2.insert：dp[i][j-1] + 1 —— 保留了从 word1[0:i] 转变到 word2[0:j-1] 的最优操作次数，因为我们的 word1 的 0~i 只能转变到 word2 的倒数第二位，所以我们就直接在 word1 的末尾添加一个与 word2 的最后一个字符相同的字符就可以了。所以就需要额外进行一个 插入 操作。\n\n3.replace：dp[i-1][j-1] + 1 —— 保留了从 word1[0:i-1] 转变到 word2[0:j-1] 的最优操作次数，因为我们的 word1 的 0~i-1 只能转变到 word2 的倒数第二位，而 word1 的最后一位与 word2 的最后一位是不同的，所以现在的情况只需要额外的一个 替换 操作即可。\n\n无论我们选取上面 3 中操作的哪种操作，我们选其中最小的值就可以了。\n\n参考链接：http://www.cnblogs.com/pandora/archive/2009/12/20/levenshtein_distance.html\n\n***要始终明确一点，```dp[i][j]```的含义是使得```word1的前i字符子串```与```word2的前j字符子串```相等所需要的操作数，这也是为什么我们需要在初始化```dp矩阵```时需要行列数均加上```1```***\n\n用wikipedia上的伪码改造\n\n```\nfunction LevenshteinDistance(char s[1..m], char t[1..n]):\n  // for all i and j, d[i,j] will hold the Levenshtein distance between\n  // the first i characters of s and the first j characters of t\n  // note that d has (m+1)*(n+1) values\n  declare int d[0..m, 0..n]\n \n  set each element in d to zero\n \n  // source prefixes can be transformed into empty string by\n  // dropping all characters\n  for i from 1 to m:\n      d[i, 0] := i\n \n  // target prefixes can be reached from empty source prefix\n  // by inserting every character\n  for j from 1 to n:\n      d[0, j] := j\n \n  for j from 1 to n:\n      for i from 1 to m:\n          if s[i] = t[j]:\n            substitutionCost := 0\n          else:\n            substitutionCost := 1\n          d[i, j] := minimum(d[i-1, j] + 1,                   // deletion\n                             d[i, j-1] + 1,                   // insertion\n                             d[i-1, j-1] + substitutionCost)  // substitution\n \n  return d[m, n]\n```\n\n对应的例子表格图\n\n```\n\t\tk\ti\tt\tt\te\tn\n\t0\t1\t2\t3\t4\t5\t6\ns\t1\t1\t2\t3\t4\t5\t6\ni\t2\t2\t1\t2\t3\t4\t5\nt\t3\t3\t2\t1\t2\t3\t4\nt\t4\t4\t3\t2\t1\t2\t3\ni\t5\t5\t4\t3\t2\t2\t3\nn\t6\t6\t5\t4\t3\t3\t2\ng\t7\t7\t6\t5\t4\t4\t3\n```\n\n\nAC代码\n\n```python\nclass Solution(object):\n    def minDistance(self, word1, word2):\n        \"\"\"\n        :type word1: str\n        :type word2: str\n        :rtype: int\n        \"\"\"\n        if len(word1) == 0 or len(word2) == 0:  # corner cases\n            return max(len(word1), len(word2))\n        dp = [[i+j for j in range(len(word2)+1)] for i in range(len(word1)+1)]\n        for i in range(1, len(word1)+1):\n            for j in range(1, len(word2)+1):\n                tmp_dist = 0 if word1[i-1] == word2[j-1] else 1\n                dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+tmp_dist)\n        return dp[-1][-1]\n```\n"
  },
  {
    "path": "docs/leetcode/python/073._Set_Matrix_Zeroes.md",
    "content": "### 73. Set Matrix Zeroes\n\n\n\n题目： \n<https://leetcode.com/problems/set-matrix-zeroes/>\n\n\n\n难度 : Medium\n\n\n\n思路：\n\nNaive AC代码，一看类似那个 game of life，不用extra space，不用O(mn)，应该就是用状态转移机了（？），所以还是先naive AC把：\n\n```python\nclass Solution(object):\n    def setZeroes(self, matrix):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :rtype: void Do not return anything, modify matrix in-place instead.\n        \"\"\"\n        def setZero(i,j):\n            for m in range(col):\n                matrix[i][m] = 0\n            for n in range(row):\n                matrix[n][j] = 0\n        \n        row = len(matrix)\n        col = len(matrix[0]) if row else 0\n        new_matrix = [matrix[i][:] for i in range(row)]\n        \n        for i in range(row):\n            for j in range(col):\n                if new_matrix[i][j] == 0:\n                    setZero(i,j)\n```\n\n\n\n`正确思路`：\n\n一边遍历，一边将相应的行和列置为0是行不通的，会影响后面元素的遍历判断，所以要记录下哪些行和哪些列是要置为0的。为了节约空间，在原矩阵中借两条边，如果该行或者列要置为0，则把左边或者上边的相应位置置为0。如果左边和上边本来就有0，那么需要额外标记一下，最后把左边或者右边也全部置为0.\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/074._search_a_2d_matrix.md",
    "content": "### 74. Search a 2D Matrix\n\n题目:\n<https://leetcode.com/problems/search-a-2d-matrix/>\n\n\n难度:\nMedium\n\n\n思路：\n想过将```2D matrix```看成一个大```sorted list```，代码如下：\n```python\nclass Solution(object):\n    def searchMatrix(self, matrix, target):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :type target: int\n        :rtype: bool\n        \"\"\"\n        row = len(matrix)\n        col = len(matrix[0]) if row else 0\n        l, r = 0, row * col - 1\n        while l <= r:\n            mid = l + ((r - l) >> 2)\n            if target > matrix[mid/col][mid%col]:\n                l = mid + 1\n            elif target < matrix[mid/col][mid%col]:\n                r = mid - 1\n            else:\n                return True\n        return False\n```\n\n\n但是后面觉得不行,\n原因如下：\n1. m * n may overflow for large m and n; \n2. it will use multiple expensive operations such as / and %\n\n\n\n\n\n\n因此二分Search，``` binary search by row first, then binary search by column.```\n\n\n```python\nclass Solution(object):\n    def searchMatrix(self, matrix, target):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :type target: int\n        :rtype: bool\n        \"\"\"\n        if not matrix or not matrix[0]:\n            return False\n        row = len(matrix)\n        col = len(matrix[0]) if row else 0\n        l, r = 0, row - 1\n        while l <= r:\n            mid_row = l + ((r - l) >> 2)\n            if matrix[mid_row][0] <= target <= matrix[mid_row][-1]:\n                m, n = 0, col - 1\n                while m <= n:\n                    mid_col = m + ((n - m) >> 2)\n                    if matrix[mid_row][mid_col] > target:\n                        n = mid_col - 1\n                    elif matrix[mid_row][mid_col] < target:\n                        m = mid_col + 1\n                    else:\n                        return True\n                return False\n            elif target < matrix[mid_row][0]:\n                r = mid_row - 1\n            else:\n                l = mid_row + 1\n        return False\n            \n```\n"
  },
  {
    "path": "docs/leetcode/python/075._sort_colors.md",
    "content": "#  75. Sort Colors\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/sort-colors\n\n> 内容描述\n\n```\nGiven an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.\n\nHere, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.\n\nNote: You are not suppose to use the library's sort function for this problem.\n\nExample:\n\nInput: [2,0,2,1,1,0]\nOutput: [0,0,1,1,2,2]\nFollow up:\n\nA rather straight forward solution is a two-pass algorithm using counting sort.\nFirst, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.\nCould you come up with a one-pass algorithm using only constant space?\n```\n\n## 解题方案\n\n> 思路 1 \n\n先算一下0, 1, 2分别有多少个，然后in-place改呗，简单, beats 100%\n\n```python\nclass Solution(object):\n    def sortColors(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        red, white, blue = 0, 0, 0\n        for i in nums:\n            if i == 0:\n                red += 1\n            elif i == 1:\n                white += 1\n        for i in range(red):\n            nums[i] = 0\n        for i in range(red, red+white):\n            nums[i] = 1\n        for i in range(red+white, len(nums)):\n            nums[i] = 2\n```\n\n\n> 思路 2\n\n这个问题是 Dutch National Flag Problem， 荷兰旗问题\n<https://en.wikipedia.org/wiki/Dutch_national_flag_problem>\n\n\n思路其实是类似partition的，比x小的放左边，比x大的放右边。\n\n这里是用三个指针，begin, cur, end，cur需要遍历整个数组\n\n- cur 指向0，交换begin与cur， begin++,cur++\n- cur 指向1，不做任何交换，cur++\n- cur 指向2，交换end与cur，end--\n\n之所以cur指向2，交换之后不前进是因为我们end交换过来的是0或者1，如果是0那么明显我们需要做进一步的处理，所以最终判断条件是end < cur应该就结束了\n\n这样的three-way-partition也只是3-way好用吧？如果有4个数，那么这样则是无效的，或者如果是4-way，那么可以转换成3-way+2-way\n\n\n```python\nclass Solution(object):\n    def sortColors(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        begin, cur, end = 0, 0, len(nums) - 1\n\n        while cur <= end:\n        \tif nums[cur] == 0:\n        \t\tnums[begin], nums[cur] = nums[cur], nums[begin]\n        \t\tcur += 1\n        \t\tbegin += 1\n        \telif nums[cur] == 1:\n        \t\tcur += 1\n        \telse: # nums[cur] == 2\n        \t\tnums[cur], nums[end] = nums[end], nums[cur]\n        \t\tend -= 1\n```\n\n> 思路 3\n\n两个指针也可以\n\n```python\nclass Solution(object):\n    def sortColors(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        i, l, r = 0, 0, len(nums) - 1\n        while i < len(nums):\n            if nums[i] == 2 and i < r:\n                nums[i], nums[r] = nums[r], 2\n                r -= 1\n            elif nums[i] == 0 and i > l:\n                nums[i], nums[l] = nums[l], 0\n                l += 1\n            else:\n                i += 1\n```\n\n> 思路 4\n\n这个方法就很巧妙了，我们遍历整个数组，只要碰到了什么数字我们就把这个数字往右边推一下\n\n大家可以用例子[2,0,2,1,1,0]自己推导一下过程，看看是不是有一种向右推的感觉\n\n\n```python\nclass Solution(object):\n    def sortColors(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        n0, n1, n2 = -1, -1, -1\n        for i in range(len(nums)):\n            if nums[i] == 0:\n                n0, n1, n2 = n0+1, n1+1, n2+1\n                nums[n2] = 2\n                nums[n1] = 1\n                nums[n0] = 0\n            elif nums[i] == 1:\n                n1, n2 = n1+1, n2+1\n                nums[n2] = 2\n                nums[n1] = 1\n            else:\n                n2 += 1\n                nums[n2] = 2\n```\n"
  },
  {
    "path": "docs/leetcode/python/076._Minimum_Window_Substring.md",
    "content": "### 76. Minimum Window Substring\n题目： \n<https://leetcode.com/problems/minimum-window-substring/>\n\n\n难度 : Hard\n\n\n模板大法\n\n\n```python\nclass Solution(object):\n    def minWindow(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: str\n        \"\"\"\n        if len(t) > len(s):\n            return ''\n        maps = collections.Counter(t)\n        counter = len(maps.keys())\n        begin, end, head, length = 0, 0, 0, float('inf')\n        while end < len(s):\n            if s[end] in maps:\n                maps[s[end]] -= 1\n                if maps[s[end]] == 0:\n                    counter -= 1\n            end += 1\n            while counter == 0:\n                if s[begin] in maps:\n                    maps[s[begin]] += 1\n                    if maps[s[begin]] > 0:\n                        counter += 1\n                if end - begin < length:\n                    length = end - begin\n                    head = begin\n                begin += 1\n        if length == float('inf'):\n            return ''\n        return s[head:head+length]\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/077._combinations.md",
    "content": "###77. Combinations\n\n\n题目： \n<https://leetcode.com/problems/combinations/>\n\n\n难度 : Medium\n\n\n思路一：\npython作弊法\n\n```\nimport itertools\np = [4, 8, 15, 16, 23, 42]\nc = itertools.combinations(p, 4)\nfor i in c:\n  print i\n \n结果：\n\n(4, 8, 15, 16)\n(4, 8, 15, 23)\n(4, 8, 15, 42)\n(4, 8, 16, 23)\n(4, 8, 16, 42)\n(4, 8, 23, 42)\n(4, 15, 16, 23)\n(4, 15, 16, 42)\n(4, 15, 23, 42)\n(4, 16, 23, 42)\n(8, 15, 16, 23)\n(8, 15, 16, 42)\n(8, 15, 23, 42)\n(8, 16, 23, 42)\n(15, 16, 23, 42)\n```\n\n作弊AC代码:\n\n```\nclass Solution(object):\n    def combine(self, n, k):\n        \"\"\"\n        :type n: int\n        :type k: int\n        :rtype: List[List[int]]\n        \"\"\"\n        import itertools\n        return [list(i) for i in itertools.combinations(range(1,n+1), k)]\n```\n\n\n思路二：\n\n标准的recursion\n\n但是会超时\n\n\n```\nclass Solution(object):\n    def combine(self, n, k):\n        \"\"\"\n        :type n: int\n        :type k: int\n        :rtype: List[List[int]]\n        \"\"\"\n        ans = []\n        self.dfs(n, k, 1, [], ans)\n        return ans\n\n    def dfs(self, n, k ,start, lst, ans):\n    \tif k == 0 :\n    \t\tans.append(lst)\n    \t\treturn\n    \tfor i in range(start, n+1):\n    \t\tself.dfs(n, k - 1, i + 1,lst +[i], ans)\n```\n\n理解方式\n\n```\n\n\t\t\t\t\t1          2     3\n\t\t\t    12  13 14    23 24   34\t\t\t\n```\n\n可以参照这里\n\n\n<http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/>\n\n\n解法三：\n\n\n采用递归的方式，在n个数中选k个，如果n大于k，那么可以分类讨论，如果选了n，那么就是在1到(n-1)中选(k-1)个，否则就是在1到(n-1)中选k个。递归终止的条件是k为1，这时候1到n都符合要求。\n\n注意一开始这里的else part花了我一点时间来理解，因为n必定大于k，所以这样递归当 n == k的时候选法就是code原作者的写法，也就是直接[range(1,k+1)]\n\n参考这里： <https://shenjie1993.gitbooks.io/leetcode-python/content/077%20Combinations.html>\n\n\n```\nclass Solution(object):\n    def combine(self, n, k):\n        \"\"\"\n        :type n: int\n        :type k: int\n        :rtype: List[List[int]]\n        \"\"\"\n        if k == 1:\n            return [[i + 1] for i in range(n)]\n        result = []\n        if n > k:\n            result = [r + [n] for r in self.combine(n - 1, k - 1)] + self.combine(n - 1, k)\n        else: #n == k \n        \t# result = [r + [n] for r in self.combine(n - 1, k - 1)]\n            result = [range(1,k+1)]\n        return result\n```"
  },
  {
    "path": "docs/leetcode/python/078._Subsets.md",
    "content": "# 78. Subsets\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/subsets\n\n> 内容描述\n\n```\n\nGiven a set of distinct integers, nums, return all possible subsets (the power set).\n\nNote: The solution set must not contain duplicate subsets.\n\nExample:\n\nInput: nums = [1,2,3]\nOutput:\n[\n  [3],\n  [1],\n  [2],\n  [1,2,3],\n  [1,3],\n  [2,3],\n  [1,2],\n  []\n]\n```\n\n## 解题方案\n\n> 思路 1\n\n每次拿一个，跟res里面的每一个已有列表取并集再次插入res中\n\n```python\nclass Solution(object):\n    def subsets(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        res = [[]]\n        for num in nums:\n            res.extend([tmp+[num] for tmp in res])\n        return res     \n```\n\n> 思路 2\n\nBackTrack 标准解法版\n\n对每个元素，有两种可能，加入 cur_lst 和不加入 cur_lst，写起来思路还是很清爽的\n\n\n```python\nclass Solution(object):\n    def subsets(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        nums.sort()\n        res = []\n        \n        def search(cur_lst, idx):\n            if idx == len(nums):\n                res.append(cur_lst)\n                return\n            search(cur_lst + [nums[idx]], idx + 1)\n            search(cur_lst, idx + 1)\n        \n        search([], 0)\n        return res\n```\n\n\n> 思路 3\n\nDFS\n\n```python\nclass Solution(object):\n    def subsets(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        nums.sort()\n        res = []\n        def dfs(depth, start, lst):\n            res.append(lst)\n            if depth == len(nums):\n                return\n            for i in range(start, len(nums)):\n                dfs(depth+1, i+1, lst+[nums[i]])\n        dfs(0, 0, [])\n        return res      \n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/079._word_search.md",
    "content": "###79. Word Search\n\n\n\n题目:\n<https://leetcode.com/problems/word-search/>\n\n\n难度:\nMedium\n\n\n思路：\n\n其实这个题和number of islands类似，是backtracking基本功的考查,但是基本功非常有待提高|||\n\n比较核心的是dfs函数，然后这个函数有取巧的写法：如果outside of boundary就return False\n\nloop， 如果碰到跟word开头的字母一样，把这个扔进去loop，可以考查这个char在这个board的上下左右是否可以选择，补课使用则重置used， 然后return\n\n也还是之前摘录的，backtrack写法关键： 选择 (Options)，限制 (Restraints)，结束条件 (Termination)。\n\n\n\n\n```\nclass Solution(object):\n    def exist(self, board, word):\n        \"\"\"\n        :type board: List[List[str]]\n        :type word: str\n        :rtype: bool\n        \"\"\"\n\n        def dfs(board, used, row, col, x, y, word, idx):\n        \tif idx == len(word) :\n        \t\treturn True\n\n        \tif x < 0 or x > row -1 or y < 0 or y > col -1 :\n        \t\treturn False\n\n        \tif board[x][y] == word[idx] and not used[x][y]:\n        \t\tused[x][y] = 1 \n        \t\tleft = dfs(board,used,row,col,x-1,y,word,idx+1)\n        \t\tright = dfs(board,used,row,col,x+1,y,word,idx+1)\n        \t\tup = dfs(board,used,row,col,x,y-1,word,idx+1)\n        \t\tdown = dfs(board,used,row,col,x,y+1,word,idx+1)\n\n        \t\tused[x][y] = left or right or up or down\n        \t\treturn left or right or up or down\n        \treturn False\n\n\n        row = len(board)\n        col = len(board[0]) if row else 0\n        used = [ [0 for i in range(col)] for j in range(row)]\n\n        for i in range(row):\n        \tfor j in range(col):\n        \t\t\tif dfs(board,used,row,col,i,j,word,0):\n        \t\t\t\treturn True\n        return False\n```"
  },
  {
    "path": "docs/leetcode/python/082._remove_duplicates_from_sorted_list_ii.md",
    "content": "###82. Remove Duplicates from Sorted List II\n\n\n题目:\n\n<https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/>\n\n\n难度:\n\nMedium\n\n\n木有space 和 time的限制，第一想法，用dictionary存一下每个nodes的个数，这样只要看到它是大于1的，就删删删。\n\n虽然是笨办法。但是也可以AC\n\n```\nclass Solution(object):\n    def deleteDuplicates(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        dummy = ListNode(-1)\n        dummy.next = head\n\n        cur = dummy.next\n        nodeNumber = {}\n        while cur:\n        \tif cur.val in nodeNumber:\n        \t\tnodeNumber[cur.val] += 1\n        \telse:\n        \t\tnodeNumber[cur.val] = 1\n        \tcur = cur.next\n\n        cur = dummy\n        while cur.next:\n        \tif nodeNumber[cur.next.val] > 1:\n        \t\tcur.next = cur.next.next\n        \telse:\n        \t\tcur = cur.next\n        return dummy.next\n```\n\n\n谷歌一下，更省时间的方法是用一个prev 和 cur 指针，然后用一个bool来记录是否duplicate，这样loop一次即可解决问题。\n\nto be 写出来"
  },
  {
    "path": "docs/leetcode/python/083._remove_duplicates_from_sorted_list.md",
    "content": "### 83. Remove Duplicates from Sorted List\n\n题目:\n<https://leetcode.com/problems/remove-duplicates-from-sorted-list/>\n\n\n难度:\n\nEasy\n\n\ndummy 大法\n\n```python\nclass Solution(object):\n    def deleteDuplicates(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        dummy = head\n        while head:\n            while head.next and head.next.val == head.val:\n                head.next = head.next.next    # skip duplicated node\n            head = head.next     # not duplicate of current node, move to next node\n        return dummy\n                \n```\n"
  },
  {
    "path": "docs/leetcode/python/086._partition_list.md",
    "content": "###86. Partition List\n\n\n题目： \n<https://leetcode.com/problems/partition-list/>\n\n\n难度 : Medium\n\n\n思路一：\n\n\n最简单的思路就是两个dummy head，然后一个指向 小于的node，一个指向大于的node\n\n\n思路二：\n\n不走寻常路了，使用两个指针，一个指向小于的尾巴，一个一直往后走，指向大于，然后交换node\n\n完成比完美更重要啊，其实可以先试试用简单方法，因为我用我的不走寻常路画了比较久的图，写起来也稍显没那么美观，还在交换node的部分卡了一会\n\n\n\n```\nclass Solution(object):\n    def partition(self, head, x):\n        \"\"\"\n        :type head: ListNode\n        :type x: int\n        :rtype: ListNode\n        \"\"\"\n        dummy = ListNode(-1)\n        dummy.next = head\n\n        p1 = p2 = dummy\n\n        while p1.next and p1.next.val < x:\n            p1 = p1.next\n\n        p2 = p1.next\n\n        while p2:\n            while p2.next and p2.next.val >= x:\n                p2 = p2.next\n\n            if p2.next == None:\n                break\n            node = p2.next\n            p2.next = node.next\n            node.next = p1.next\n            p1.next = node\n            p1 = p1.next\n\n        return dummy.next\n```"
  },
  {
    "path": "docs/leetcode/python/088._merge_sorted_array.md",
    "content": "# 88. Merge Sorted Array\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/merge-sorted-array\n\n> 内容描述\n\n```\nGiven two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.\n\nNote:\n\nThe number of elements initialized in nums1 and nums2 are m and n respectively.\nYou may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2.\nExample:\n\nInput:\nnums1 = [1,2,3,0,0,0], m = 3\nnums2 = [2,5,6],       n = 3\n\nOutput: [1,2,2,3,5,6]\n```\n\n## 解题方案\n\n> 思路 1\n\n给的数组可能是这样的\n\n- nums1 : [0]\n- m : 0\n- nums2 : [1]\n- n : 1\n\n\n所以要判断m和n是不是仍然大于0, 但是m不需要了，因为我们本来就是要在nums1的基础上改，m如果还大于0的话我们不需要改nums1了，保留不变即可\n\n\nAC代码\n\n\n```python\nclass Solution:\n    def merge(self, nums1, m, nums2, n):\n        \"\"\"\n        :type nums1: List[int]\n        :type m: int\n        :type nums2: List[int]\n        :type n: int\n        :rtype: void Do not return anything, modify nums1 in-place instead.\n        \"\"\"\n        while m > 0 and n > 0:\n            if nums1[m-1] > nums2[n-1]:\n                nums1[m+n-1] = nums1[m-1]\n                m -= 1\n            else:\n                nums1[m+n-1] = nums2[n-1]\n                n -= 1\n        if n > 0:\n            nums1[:n] = nums2[:n]\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/089._gray_code.md",
    "content": "###89. Gray Code\n\n\n\n题目:\n<https://leetcode.com/problems/gray-code/>\n\n\n难度:\nMedium\n\n思路：\n\n首先不是从任何一个数开始都是有效的，所以naive的想法是从任何一个开始，然后如果能到2^n位，那么说明是有效的，问题解决.\n\nA gray code sequence must begin with 0. ->简化了一点\n\n先写了一段代码：\n\n```\ndef nextCode(curCode, res, n):\n        if curCode not in res:\n\t\tres.append(curCode)\n\telse:\n\t\treturn\n\tif len(res) == pow(2,n):\n\t\treturn res\n\tfor i in range(n):\n\t\tnCode = curCode[:]\n\t\tnCode[i] = 1 if curCode[i] == 0 else 0\n\t\tnextCode(nCode,res,n)\n\nres = []\nnextCode([0,0,0],res,3)\nprint res\n#[[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 0, 1], [0, 0, 1]]\n```\n实际上问题是这段代码的时间复杂度感觉很高，但是试试\n\n\n不失所望，到11就超时\n\n```\n\nclass Solution(object):\n    def grayCode(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[int]\n        \"\"\"\n        def nextCode(curCode, res, n):\n                if curCode not in res:\n                        res.append(curCode)\n                else:\n                        return\n                if len(res) == pow(2,n):\n                        return res\n                for i in xrange(n):\n                        nCode = curCode[:]\n                        nCode[i] = 1 if curCode[i] == 0 else 0\n                        nextCode(nCode, res, n)\n\n        def listoVal(curCode,n):\n                val = 0\n                for i in range(n-1,-1,-1):\n                        val += pow(2,i) * curCode[i]\n                return val\n\n\n        res = []\n        nextCode([0]*n, res, n)\n        # print res\n\n        val = []\n        for i in res:\n                val.append(listoVal(i,n))\n        return val\n```\n\n然后居然有这个东西：\nGray code，要用位运算！瞑目\n\n\n<https://en.wikipedia.org/wiki/Gray_code>\n\n服气，这个待研究\n```\nclass Solution(object):\n    def grayCode(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[int]\n        \"\"\"\n        result = [(i>>1)^i for i in range(pow(2,n))]\n        return results\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/090._subsets_ii.md",
    "content": "# 90. Subsets II\n\n**<font color=red>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/subsets-ii\n\n> 内容描述\n\n```\nGiven a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).\n\nNote: The solution set must not contain duplicate subsets.\n\nExample:\n\nInput: [1,2,2]\nOutput:\n[\n  [2],\n  [1],\n  [1,2,2],\n  [2,2],\n  [1,2],\n  []\n]\n```\n\n## 解题方案\n\n> 思路 1\n\n\n```\n[[],[1]] 是 [1] 的子集合\n[[],[1],[2],[1,2]] 是 [1,2] 的子集合，实际上就是1的子集合们加了一个2\n新来的2不能再从头开始加了，它需要从[ .., [2],[1,2] ]加 才是合理的\n\n****当出现多个重复数字时，应该从 已经拥有了新数字所出现全部次数的list开始加才是合理的****\n[[],[1]] 是 [1] 的子集合\n[[],[1],[2],[1,2]] 是 [1,2] 的子集合，实际上就是1的子集合们加了一个2\n[\n  [2],\n  [1],\n  [1,2,2],\n  [2,2],\n  [1,2],\n  []\n] 是 [1,2,2] 的子集和，实际上也就是[1,2]的子集合加了一个2\n新来的2不能再从头开始加了，它需要从[ .., [2,2],[1,2,2] ]加 才是合理的\n例如：\n```\n\n自己的解法，这里最关键的就是先对nums进行了排序，保证了我们插入相同的数字时都是相邻的\n```python\nclass Solution(object):\n    def subsetsWithDup(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        nums.sort()\n        res = [[]]\n        for i in range(len(nums)):\n            if any(nums[i] in tmp for tmp in res):\n                res.extend([tmp+[nums[i]] for tmp in res if tmp.count(nums[i]) == i - nums.index(nums[i])])\n            else:\n                res.extend([tmp+[nums[i]] for tmp in res])\n        return res\n```\n\n> 思路 2\n\n参考别人的\n\n现在来观察规律，与之前有不同之处是我们需要一个位置来mark，因为不再需要往之前出现过的地方再加了，看这个:\n这里这个start是来记录了之前一次数组的长度，temp_size记住目前数组的长度，然后用这个来达到去重的目的，非常聪明\n\n别人的解法，但是一个思路\n\n```python\nclass Solution(object):\n    def subsetsWithDup(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        nums.sort()\n        res = [[]]\n        tmp_size = 0\n        for i in range(len(nums)):\n            start = tmp_size if i >= 1 and nums[i] == nums[i-1] else 0\n            tmp_size = len(res)\n            for j in range(start, tmp_size):\n                res.append([nums[i]]+res[j])\n        return res\n```\n\n> 思路 3\n\n跟[leetcode第78题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/078._Subsets.md)一样，DFS, 只不过需要在dfs函数里加一个剪枝的条件，排除掉同样的子集。\n\n\n```python\nclass Solution(object):\n    def subsetsWithDup(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        nums.sort()\n        res = []\n        def dfs(depth, start, lst):\n            if lst not in res: \n                res.append(lst)\n            if depth == len(nums):\n                return\n            for i in range(start, len(nums)):\n                dfs(depth+1, i+1, lst+[nums[i]])\n        dfs(0, 0, [])\n        return res\n```\n\n\n\n> 思路 4\n\n跟[leetcode第78题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/078._Subsets.md)一样，backtrack\n\n\n```python\nclass Solution(object):\n    def subsetsWithDup(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[List[int]]\n        \"\"\"\n        nums.sort()\n        res = []\n        \n        def search(cur_lst, idx):\n            if idx == len(nums):\n                if cur_lst not in res:\n                    res.append(cur_lst)\n                return\n            search(cur_lst + [nums[idx]], idx + 1)\n            search(cur_lst, idx + 1)\n        \n        search([], 0)\n        return res\n\n```\n\n## References\n[南郭子綦](https://www.cnblogs.com/zuoyuan/p/3758346.html)\n"
  },
  {
    "path": "docs/leetcode/python/091._decode_ways.md",
    "content": "###91. Decode Ways\n\n题目： \n<https://leetcode.com/problems/decode-ways/>\n\n\n\ntag : DP\n\n难度 : Medium\n\n\n\n\n\n```\nBASE CASE（len(s) = 1 和 len(s) = 2 ）: \n直接check\n\n非BASE CASE ：\n先令 dp[i] = 0\n如果s[i]是可以map的话 -> dp[i] += dp[i-1] 原本的s[0..i]decode方式加上s[i]\n如果s[i-1,i]可以map的话 -> dp[i] += dp[i-2] 原本的s[0...i-1]decode方式加上s[i-1,i]\n```\n\n\nPython代码（可美化）\n\n```\nclass Solution(object):\n    def numDecodings(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9' ,'10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26']\n        values = ['A', 'B','C', 'D', 'E', 'F', 'G','H', 'I', 'J', 'K', 'L', 'M' , 'N', 'O', 'P','Q', 'S', 'R', 'T', 'U','V', 'W', 'X','Y','Z']\n        numbersToLetters = dict(zip(keys, values))\n    \n        ways = {}\n        n = len(s)\n        for i in range(n):\n            ways[i] = 0\n        if n == 0:\n            return 0\n        elif n == 1 :\n            ways[0] = int(s in numbersToLetters)\n        elif n == 2:\n            if (s[0] in numbersToLetters) and (s[1] in numbersToLetters):\n                ways[1] += 1\n            if (s in numbersToLetters):\n                ways[1] += 1\n        else:\n            #s[0]\n            ways[0] = int(s[0] in numbersToLetters)\n            #s[01]\n            if (s[0] in numbersToLetters) and (s[1] in numbersToLetters):\n                ways[1] += 1\n            if (s[:2] in numbersToLetters):\n                ways[1] += 1        \n            for i in range(2,n):\n                if s[i] in numbersToLetters:\n                    ways[i] += ways[i-1]\n                if (s[i-1:i+1] in numbersToLetters):\n                    ways[i] += ways[i-2]\n            \n        #print(ways[n-1])\n        return ways[n-1]\n            \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/092._reverse_linked_list_ii.md",
    "content": "###92. Reverse Linked List II \n\n题目:\n<https://leetcode.com/problems/reverse-linked-list-ii/>\n\n\n难度:\nMedium\n\n\n跟 reverse linked list一样\n\n思路： 找到 第 m 个node，然后开始reverse到第n个node，然后再把它们和原本的list连接起来\n\nAC 代码\n\n```\nclass Solution(object):\n    def reverseBetween(self, head, m, n):\n        \"\"\"\n        :type head: ListNode\n        :type m: int\n        :type n: int\n        :rtype: ListNode\n        \"\"\"\n        # m == n, not reverse\n        if m == n : return head\n\n        dummy = ListNode(-1)\n        dummy.next = head\n\n        mbefore = dummy\n        cnt = 1\n        \n        while mbefore and cnt < m:\n            mbefore = mbefore.next\n            cnt += 1\n\n        prev = None\n        cur = mbefore.next\n        tail1 = mbefore.next\n        \n\n        while cnt <= n :\n            nxt = cur.next\n            cur.next = prev\n            prev = cur\n            cur = nxt\n            cnt += 1\n\n\n\n        mbefore.next = prev\n        tail1.next = cur\n\n        return dummy.next \n```\n\n看了一下别人的代码，又比我写的好嘛，因为是保证m和n有效，用的是for循环先找到 m node:\n\n\n\tfor _ in range(m-1):\n\t\t....\n\t\t\n\tfor _ in range(n-m):\n\t\treverse 操作"
  },
  {
    "path": "docs/leetcode/python/093._restore_ip_addresses.md",
    "content": "###93. Restore IP Addresses\n\n题目:\n\n<https://leetcode.com/problems/restore-ip-addresses/>\n\n\n难度:\n\nMedium\n\n\n基本思路已达到，等待AC之路\n\n结果AC之路还是比较漫长的，因为不允许前缀为0困扰了一下\n\n```\nclass Solution(object):\n    def restoreIpAddresses(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: List[str]\n        \"\"\"\n        self.res = []\n        self.singgleAddresses([],s,4)\n        for i in range(len(self.res)):\n            self.res[i] = '.'.join(str(j) for j in self.res[i])\n        return self.res\n            \n        \n        \n    def singgleAddresses(self, curRes, s, k):\n        \"\"\"\n        :type s: str\n        :rtype: List[str]\n        \"\"\"\n        if len(s) == 0 and k == 0:\n            if curRes not in self.res:\n                self.res.append(curRes)\n        if len(s) == 0 or k < 0:\n            return\n        else:\n            if self.between0And255(s[:1]):\n                self.singgleAddresses(curRes + [int(s[:1])], s[1:], k-1) \n            if self.between0And255(s[:2]):\n                self.singgleAddresses(curRes + [int(s[:2])], s[2:], k-1)  \n            if self.between0And255(s[:3]):\n                self.singgleAddresses(curRes + [int(s[:3])], s[3:], k-1) \n            \n    def between0And255(self,s):\n        #前缀不允许为0\n        if int(s) == 0 :\n            if len(s) == 1 :\n                return True\n            else:\n                return False\n                \n        if int(s) > 0 and s[0] == '0':\n            return False\n        if int(s) > 0 and int(s) <= 255:\n            return True\n        return False\n                \n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/094._binary_tree_inorder_traversal.md",
    "content": "#  94. Binary Tree Inorder Traversal\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/binary-tree-inorder-traversal\n\n> 内容描述\n\n```\n\nGiven a binary tree, return the inorder traversal of its nodes' values.\n\nExample:\n\nInput: [1,null,2,3]\n   1\n    \\\n     2\n    /\n   3\n\nOutput: [1,3,2]\nFollow up: Recursive solution is trivial, could you do it iteratively?\n```\n\n## 解题方案\n\n> 思路 1\n\n\n递归，瞬秒\n\n\n```python\nclass Solution(object):\n    def inorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        if not root:\n            return res\n        if root.left: \n            res.extend(self.inorderTraversal(root.left))\n        res.append(root.val)\n        if root.right:\n            res.extend(self.inorderTraversal(root.right))\n        return res\n```\n> 思路 2\n\n或者我们可以先写一下中序遍历的函数，然后一个一个贴上去\n\n```python\nclass Solution(object):\n    def inorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        if root == None:\n            return []\n        res = []\n        self.inorder(root,res)\n        return res\n        \n        \n    def inorder(self,root,res):\n        if root == None:\n            return\n        self.inorder(root.left,res)\n        res.append(root.val)\n        self.inorder(root.right,res)               \n```\n> 思路 3\n\n迭代\n\n先一股脑把左边一条线全部push到底（即走到最左边），然后node最终为None了就开始pop stack了，然后因为pop出来的每一个node都是自己这棵树的root，所以看看它有没有右孩子，没有那肯定继续pop，有的话自然而然右孩子是下一个要被访问的节点。\n\n\n```python\nclass Solution(object):\n    def inorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        if not root:\n            return res\n        \n        stack = []\n        node = root\n        while node or (len(stack) > 0):\n            if node:\n                stack.append(node)\n                node = node.left\n            else:\n                node = stack.pop()\n                res.append(node.val)\n                node = node.right\n        return res\n```\n"
  },
  {
    "path": "docs/leetcode/python/096._unique_binary_search_trees.md",
    "content": "#  96. Unique Binary Search Trees\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/unique-binary-search-trees\n\n> 内容描述\n\n```\nGiven n, how many structurally unique BST's (binary search trees) that store values 1 ... n?\n\nExample:\n\nInput: 3\nOutput: 5\nExplanation:\nGiven n = 3, there are a total of 5 unique BST's:\n\n   1         3     3      2      1\n    \\       /     /      / \\      \\\n     3     2     1      1   3      2\n    /     /       \\                 \\\n   2     1         2                 3\n```\n\n## 解题方案\n\n> 思路 1\n\n\n参照此处hint:\n\nhttps://shenjie1993.gitbooks.io/leetcode-python/096%20Unique%20Binary%20Search%20Trees.html\n\n\n首先明确n个不等的数它们能构成的二叉搜索树的种类都是相等的。而且1到n都可以作为二叉搜索树的根节点，当k是根节点时，它的左边有k-1个不等的数，它的右边有n-k个不等的数。以k为根节点的二叉搜索树的种类就是左右可能的种类的乘积。用递推式表示就是 h(n) = h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)h(0) (其中n>=2) ，其中h(0)=h(1)=1，因为0个或者1个数能组成的形状都只有一个。从1到n依次算出h(x)的值即可。此外这其实就是一个卡特兰数，可以直接用数学公式计算，不过上面的方法更加直观一些。\n\n\n```python\nclass Solution(object):\n    def numTrees(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        dp = [1 for i in range(n+1)]\n        for i in range(2, n+1):\n            s = 0\n            for k in range(i):\n                s += dp[k]*dp[i-k-1]\n            dp[i] = s\n        return dp[-1]\n```\n"
  },
  {
    "path": "docs/leetcode/python/098._validate_binary_search_tree.md",
    "content": "###98. Validate Binary Search Tree\n\n题目:\n\n<https://leetcode.com/problems/validate-binary-search-tree/>\n\n\n难度:\n\nEasy\n\n\n以前做过这道题，valid binary tree，需要check两件事：\n\n\n```\n   \t\t\t10\n   \t\t   /  \\\n   \t\t  7   20\n   \t\t      / \\ \n   \t\t     5  40 \n```\n\n\n- node.left.val < node.val\n\t- right subtree of left child, value < node.val\n- node.right.val > node.val\n\t- left subtree of the right child, value > node.val\n\n\nwikipedia上有伪码：\n\n```\ntruct TreeNode {\n    int key;\n    int value;\n    struct TreeNode *left;\n    struct TreeNode *right;\n};\n\nbool isBST(struct TreeNode *node, int minKey, int maxKey) {\n    if(node == NULL) return true;\n    if(node->key < minKey || node->key > maxKey) return false;\n    \n    return isBST(node->left, minKey, node->key) && isBST(node->right, node->key, maxKey);\n}\n\n\nif(isBST(root, INT_MIN, INT_MAX)) {\n    puts(\"This is a BST.\");\n} else {\n    puts(\"This is NOT a BST!\");\n}\n```\n\n实际上就是每次往下看，node都确保被夹在一个范围。\n\n翻译了一下伪码，AC\n\n\n```\nclass Solution(object):\n    def isValidBST(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: bool\n        \"\"\"\n        return self.isBST(root, float('-inf'),float('inf'))\n            \n    def isBST(self, root, minKey, maxKey):\n        if root == None: return True\n        if root.val <= minKey or root.val >= maxKey : return False\n        return self.isBST(root.left,minKey,root.val) and self.isBST(root.right, root.val, maxKey)\n```\n"
  },
  {
    "path": "docs/leetcode/python/100._same_tree.md",
    "content": "### 100. Same Tree\n\n题目:\n\n<https://leetcode.com/problems/same-tree/>\n\n\n难度:\n\nEasy\n\n\n太简单了，递归一行！\n\n\n```python\n# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\nclass Solution(object):\n    def isSameTree(self, p, q):\n        \"\"\"\n        :type p: TreeNode\n        :type q: TreeNode\n        :rtype: bool\n        \"\"\"\n        return p.val == q.val and all(map(self.isSameTree, (p.left, p.right), (q.left, q.right))) if p and q else p is q\n```\n\n```python\nclass Solution(object):\n    def isSameTree(self, p, q):\n        \"\"\"\n        :type p: TreeNode\n        :type q: TreeNode\n        :rtype: bool\n        \"\"\"\n        if (not p and q) or (p and not q):\n            return False\n        if not p and not q:\n            return True\n        if p.val == q.val:\n            return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)\n        return False\n```\n"
  },
  {
    "path": "docs/leetcode/python/101._symmetric_tree.md",
    "content": "### 101. Symmetric Tree\n\n题目:\n\n<https://leetcode.com/problems/symmetric-tree/>\n\n\n难度:\n\nEasy\n\n\n两棵树symmetric， 有几种可能：\n\n- 均为none ，symmetric\n- 左孩子，右孩子都不存在，并且值相等， symmetric\n- 右子树 和 另一棵树的左子树相等，左子树 和另一颗树的右子树相等 🌲\n\n\n```python\nclass Solution(object):\n    def isSymmetric(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: bool\n        \"\"\"\n        if not root:\n            return True\n        return self.symmetric(root.left, root.right)\n        \n    def symmetric(self, l1, l2):\n        if not l1 or not l2:\n            if not l1 and not l2:\n                return True\n            else:\n                return False\n        if l1.val == l2.val:\n            return self.symmetric(l1.left, l2.right) and self.symmetric(l1.right, l2.left)\n        else:\n            return False\n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/102._binary_tree_level_order_traversal.md",
    "content": "#  102. Binary Tree Level Order Traversal\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/binary-tree-level-order-traversal\n\n> 内容描述\n\n```\nGiven a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).\n\nFor example:\nGiven binary tree [3,9,20,null,null,15,7],\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\nreturn its level order traversal as:\n[\n  [3],\n  [9,20],\n  [15,7]\n]\n```\n\n## 解题方案\n\n> 思路 1\n\n递归\n\n```python\nclass Solution(object):\n    def levelOrder(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[List[int]]\n        \"\"\"\n        res = []\n        self.recurHelper(root, 0, res)\n        return res\n    \n    def recurHelper(self, root, level, res):\n        if not root: return\n        if len(res) < level + 1:\n            res.append([])\n        res[level].append(root.val)\n        self.recurHelper(root.left, level+1, res)\n        self.recurHelper(root.right, level+1, res)\n```\n\n> 思路 2\n\n迭代，利用curLevel和nextLevel来记录，然后按层append.\n\n\n```python\nclass Solution(object):\n    def levelOrder(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[List[int]]\n        \"\"\"\n        if not root:\n            return []\n        res, cur_level = [], [root]\n        while cur_level:\n            next_level, tmp_res = [], []\n            for node in cur_level:\n                tmp_res.append(node.val)\n                if node.left:\n                    next_level.append(node.left)\n                if node.right:\n                    next_level.append(node.right)\n            res.append(tmp_res)\n            cur_level = next_level\n        return res\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/103._binary_tree_zigzag_level_order_traversal.md",
    "content": "### 103. Binary Tree Zigzag Level Order Traversal\n\n题目:\n\n<https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/>\n\n\n难度:\n\nMedium\n\n\n\n```python\nclass Solution(object):\n    def zigzagLevelOrder(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[List[int]]\n        \"\"\"\n        if not root:\n            return []\n        res, cur_level, level_count = [], [root], 0\n        while cur_level:\n            next_level, tmp_res = [], []\n            for node in cur_level:\n                tmp_res.append(node.val)\n                if node.left:\n                    next_level.append(node.left)\n                if node.right:\n                    next_level.append(node.right)\n            if level_count % 2 == 0:\n                res.append(tmp_res)  \n            else:\n                tmp_res.reverse()\n                res.append(tmp_res)\n            level_count += 1\n            cur_level = next_level\n            \n        return res\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/104._maximum_depth_of_binary_tree.md",
    "content": "### 104. Maximum Depth of Binary Tree\n\n题目:\n<https://leetcode.com/problems/maximum-depth-of-binary-tree/>\n\n\n难度:\n\nEasy\n\n\n简单题,但是这道题跟[leetcode111](https://github.com/Lisanaaa/thinking_in_lc/blob/master/111._minimum_depth_of_binary_tree.md)不一样，这道题没有特殊情况，所以一行就够了\n\n\n```python\nclass Solution(object):\n    def maxDepth(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        return 1 + max(map(self.maxDepth, (root.left, root.right))) if root else 0\n```\n"
  },
  {
    "path": "docs/leetcode/python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md",
    "content": "# 105. Construct Binary Tree from Preorder and Inorder Traversal 从前序与中序遍历序列构造二叉树\n\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal\n* https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal\n\n> 内容描述\n\n```\n根据一棵树的前序遍历与中序遍历构造二叉树。\n\n注意:\n你可以假设树中没有重复的元素。\n\n例如，给出\n\n前序遍历 preorder = [3,9,20,15,7]\n中序遍历 inorder = [9,3,15,20,7]\n返回如下的二叉树：\n\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\n```\n\n## 解题方案\n\n> 思路 1\n\n一句话，看到树🌲就要想到递归\n\n- preorder 是 根 -> 左 -> 右\n- inorder  是 左 -> 根 -> 右\n\n首先pre的第一个就是整个树的root, 假设 preorder[0] = inorder[k],那么inorder的前k-1个就是树的左子树，后面部分就是树的右子树\n\n```python\nclass Solution(object):\n    def buildTree(self, preorder, inorder):\n        \"\"\"\n        :type preorder: List[int]\n        :type inorder: List[int]\n        :rtype: TreeNode\n        \"\"\"\n        if not preorder or len(preorder) == 0:\n            return None\n        root = TreeNode(preorder[0])\n        k = inorder.index(preorder[0])\n        root.left = self.buildTree(preorder[1:k+1], inorder[0:k])\n        root.right = self.buildTree(preorder[k+1:], inorder[k+1:])\n        return root\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md",
    "content": "###106. Construct Binary Tree from Inorder and Postorder Traversal\n\n题目： \n<https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/>\n\n\n难度 : Medium\n\n\ninorder  是 左 -> 根 -> 右\npostorder 是 左 -> 右 -> 根\n\n\n跟105基本一样\n\n还是先弄了一个递归可用版本\n\n\n```\ndef buildTree(inorder, postorder):\n    \"\"\"\n    :type preorder: List[int]\n    :type inorder: List[int]\n    :rtype: TreeNode\n    \"\"\"\n    if postorder == inorder == []:\n        return None\n    else:\n        rootVal = postorder[-1]\n        root = TreeNode(rootVal)\n        k = inorder.index(rootVal)\n        root.left = buildTree(inorder[:k],postorder[:k])\n        root.right = buildTree(inorder[k+1:],postorder[k:-1])\n        return root\n        \n```\n照抄105\n\n\n```\nclass Solution(object):\n    def buildTree(self, inorder, postorder):\n        \"\"\"\n        :type inorder: List[int]\n        :type postorder: List[int]\n        :rtype: TreeNode\n        \"\"\"\n        def buildTree(inorder, postorder, li, ri ,lp, rp ):\n            if lp > rp or li > ri:\n                return None\n\n            root = TreeNode(postorder[rp])\n            k = inorder.index(postorder[rp])\n\n            # left node\n            left = buildTree(inorder, postorder, li, k-1, lp, lp + k - li - 1)\n            right = buildTree(inorder, postorder, k+1, ri, lp+k-li, rp-1)\n\n            root.left = left\n            root.right = right\n\n            return root\n\n        return buildTree(inorder, postorder, 0, len(inorder) - 1, 0, len(postorder) - 1)\n            \n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/107._binary_tree_level_order_traversal_ii.md",
    "content": "###107. Binary Tree Level Order Traversal II\n\n题目:\n\n<https://leetcode.com/problems/binary-tree-level-order-traversal-ii/>\n\n\n难度:\n\nEasy\n\n\n用102 的算法作弊\n\n\n```\n# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\nclass Solution(object):\n    def levelOrderBottom(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[List[int]]\n        \"\"\"\n        res = []\n        \n        if root == None: return []\n        \n        curLevel = [root]\n        while curLevel:\n            nextLevel = []\n            tmpRes = []\n            for node in curLevel:\n                tmpRes.append(node.val)\n                if node.left: nextLevel.append(node.left)\n                if node.right: nextLevel.append(node.right)\n            res.append(tmpRes)\n            curLevel = nextLevel\n        res.reverse()\n        return res\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/108._convert_sorted_array_to_binary_search_tree.md",
    "content": "### 108. Convert Sorted Array to Binary Search Tree\n\n题目:\n<https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/>\n\n\n难度:\nMedium\n\n\n思路：\n\n递归\n\n- nums为空，return None\n- nums非空，nums[n/2]为中间元素，根结点，nums[:mid]为左子树， nums[mid+1:]为右子树\n\n\n```python\nclass Solution(object):\n    def sortedArrayToBST(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: TreeNode\n        \"\"\"\n        if not nums:\n            return None\n        if nums:\n            mid = len(nums) / 2\n            root = TreeNode(nums[mid])\n            root.left = self.sortedArrayToBST(nums[:mid])\n            root.right = self.sortedArrayToBST(nums[mid+1:])\n            return root\n```\n"
  },
  {
    "path": "docs/leetcode/python/109._convert_sorted_list_to_binary_search_tree.md",
    "content": "### 109. Convert Sorted List to Binary Search Tree\n\n\n\n题目:\n<https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/>\n\n\n难度:\n\nMedium\n\n思路：\n\n跟第 108 题一样\n\n```python\nclass Solution(object):\n    def sortedListToBST(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: TreeNode\n        \"\"\"\n        def sortedArrayToBST(nums):\n            if not nums:\n                return None\n            if nums:\n                mid = len(nums) / 2\n                root = TreeNode(nums[mid])\n                root.left = sortedArrayToBST(nums[:mid])\n                root.right = sortedArrayToBST(nums[mid+1:])\n                return root\n        if not head:\n            return None\n        else:\n            lst = []\n            while head:\n                lst.append(head.val)\n                head = head.next\n            return sortedArrayToBST(lst)\n```\n"
  },
  {
    "path": "docs/leetcode/python/110._balanced_binary_tree.md",
    "content": "#  110. Balanced Binary Tree\n**<font color=red>难度: 简单</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/balanced-binary-tree\n\n> 内容描述\n\n```\nGiven a binary tree, determine if it is height-balanced.\n\nFor this problem, a height-balanced binary tree is defined as:\n\na binary tree in which the depth of the two subtrees of every node never differ by more than 1.\n\nExample 1:\n\nGiven the following tree [3,9,20,null,null,15,7]:\n\n    3\n   / \\\n  9  20\n    /  \\\n   15   7\nReturn true.\n\nExample 2:\n\nGiven the following tree [1,2,2,3,3,null,null,4,4]:\n\n       1\n      / \\\n     2   2\n    / \\\n   3   3\n  / \\\n 4   4\nReturn false.\n```\n\n## 解题方案\n\n> 思路 1\n\n递归,判断左右子树最大高度差不超过1且左右子树均为平衡树\n\n```python\nclass Solution(object):\n    def isBalanced(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: bool\n        \"\"\"\n        def height(node):\n            if not node:\n                return 0\n            return 1 + max(height(node.left), height(node.right))\n        if not root:\n            return True\n        return abs(height(root.left) - height(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right)\n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/111._minimum_depth_of_binary_tree.md",
    "content": "### 111. Minimum Depth of Binary Tree\n\n题目:\n<https://leetcode.com/problems/minimum-depth-of-binary-tree/>\n\n\n难度:\n\nEasy \n\n\n思路，看完题目我想当然的认为就是直接递归取最小的值，代码如下：\n```\nclass Solution(object):\n    def minDepth(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n        return 1 + min(map(self.minDepth, (root.left, root.right)))\n```\n\n\n但是没过，有一种特殊情况就是\n\n注意```leaf node```反正就是没有```left```和```right```的\n\n比如下图\n\n\n```\n1\n \\\n  2\n```\n\n```2```是一个孩子节点\n\n这种情况应该输出```2```而不是```1```\n\n\n\n唯一的特殊情况就是上面这种了，因为```root```下只有一个左节点或者是右节点，这样另外一边的空节点并不算是```leaf node```\n\n```leaf node: itself is not null but it has both children null```\n\n因此要避免这种情况，代码改成下面：\n\n\n```python\n# Definition for a binary tree node.\n# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\nclass Solution(object):\n    def minDepth(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n        depth_under_root = map(self.minDepth, (root.left, root.right))\n        return 1 + (min(depth_under_root) or max(depth_under_root))\n```\n\n\n所以还是要养成多写edge case的好习惯，也许就帮你避免了general写法的特例,代码如下\n```python\nclass Solution(object):\n    def minDepth(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if root == None:\n            return 0\n        elif root.left == None and root.right == None:\n            return 1\n        else :\n            if root.left == None:\n                return 1 + self.minDepth(root.right)\n            elif root.right == None:\n                return 1 + self.minDepth(root.left)\n            else:\n                return min(1+ self.minDepth(root.left), 1+ self.minDepth(root.right))\n        \n```\n"
  },
  {
    "path": "docs/leetcode/python/112._path_sum.md",
    "content": "### 112. Path Sum\n\n题目:\n<https://leetcode.com/problems/path-sum/>\n\n\n难度:\n\nEasy\n\n\n递归\n\n```python\nclass Solution(object):\n    def hasPathSum(self, root, sum):\n        \"\"\"\n        :type root: TreeNode\n        :type sum: int\n        :rtype: bool\n        \"\"\"\n        if not root:\n            return False\n        if root.left or root.right:\n            return self.hasPathSum(root.left, sum-root.val) or self.hasPathSum(root.right, sum-root.val)\n        else:\n            return root.val == sum          \n```\n"
  },
  {
    "path": "docs/leetcode/python/113._path_sum_ii.md",
    "content": "### 113. Path Sum II\n\n题目： \n\n\n<https://leetcode.com/problems/path-sum-ii/>\n\n\ntag : DFS\n\n\n难度 :  Medium\n\n\n注意宁愿写几次curList + [root.val] 也不要直接传一个list进去，因为list pass by reference的亏已经吃过了\n\n```python\nclass Solution(object):\n    def pathSum(self, root, sum):\n        \"\"\"\n        :type root: TreeNode\n        :type sum: int\n        :rtype: List[List[int]]\n        \"\"\"\n        res = []\n        self.auxPathSum(root, sum, [], res)\n        return res\n    def auxPathSum(self, root, sum, cur_list, cur_lists):\n        if not root:\n            return\n        sum -= root.val\n        if sum == 0 and not root.left and not root.right:\n            cur_lists.append(cur_list + [root.val])\n            return \n        if root.left:\n            self.auxPathSum(root.left, sum, cur_list + [root.val], cur_lists) \n        if root.right:\n            self.auxPathSum(root.right, sum, cur_list + [root.val], cur_lists)\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/114._flatten_binary_tree_to_linked_list.md",
    "content": "### 114. Flatten Binary Tree to Linked List\n\n题目:\n<https://leetcode.com/problems/flatten-binary-tree-to-linked-list/>\n\n\n难度:\n\nMedium\n\n这道题看了hint，说每个node的右节点都是相应先序遍历中它的下一个节点。\n所以我的思路是先把先序遍历的node顺序搞出来，然后对于这里面的每一个节点，只需要做两个操作：\n1. node.left = None\n2. node.right = 相应先序遍历中node的下一个节点\n\n```python\nclass Solution(object):\n    def flatten(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: void Do not return anything, modify root in-place instead.\n        \"\"\"\n        def preorder(root):\n            res = []\n            if not root:\n                return res\n            res.append(root)\n            if root.left: \n                res.extend(preorder(root.left))\n            if root.right:\n                res.extend(preorder(root.right))\n            return res\n        if not root:\n            return\n        node_order = preorder(root)\n        for i in range(len(node_order)-1):\n            node_order[i].left = None\n            node_order[i].right = node_order[i+1]\n        node_order[-1].left = None\n        node_order[-1].right = None\n```\nbeat 40.67%\n\n另外一种解法：\n1. copy the left and right subtree\n2. then cut root’s left subtree\n3. do DFS\n4. left and right has been flattened and connect them left and right back to the root\n\n```python\nclass Solution(object):\n    def flatten(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: void Do not return anything, modify root in-place instead.\n        \"\"\"\n        if not root:\n            return\n        left_node = root.left\n        right_node = root.right\n        root.left = None\n        self.flatten(left_node)\n        self.flatten(right_node)\n        if left_node:\n            root.right = left_node\n            while left_node.right:\n                left_node = left_node.right\n            left_node.right = right_node\n```\nbeat 32.18%\n\n"
  },
  {
    "path": "docs/leetcode/python/116._populating_next_right_pointers_in_each_node.md",
    "content": "#  116. Populating Next Right Pointers in Each Node\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/populating-next-right-pointers-in-each-node\n\n> 内容描述\n\n```\nGiven a binary tree\n\nstruct TreeLinkNode {\n  TreeLinkNode *left;\n  TreeLinkNode *right;\n  TreeLinkNode *next;\n}\nPopulate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.\n\nInitially, all next pointers are set to NULL.\n\nNote:\n\nYou may only use constant extra space.\nRecursive approach is fine, implicit stack space does not count as extra space for this problem.\nYou may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).\nExample:\n\nGiven the following perfect binary tree,\n\n     1\n   /  \\\n  2    3\n / \\  / \\\n4  5  6  7\nAfter calling your function, the tree should look like:\n\n     1 -> NULL\n   /  \\\n  2 -> 3 -> NULL\n / \\  / \\\n4->5->6->7 -> NULL\n```\n\n## 解题方案\n\n> 思路 1\n\n递归\n\n```python\nclass Solution:\n    # @param root, a tree link node\n    # @return nothing\n    def connect(self, root):\n        res = []\n        self.recurHelper(root, 0, res)\n        for level in res:\n            for i in range(len(level)-1):\n                level[i].next = level[i+1]\n        \n                \n    def recurHelper(self, root, level, res):\n        if not root:\n            return \n        if len(res) < level + 1:\n            res.append([])\n        res[level].append(root)\n        self.recurHelper(root.left, level+1, res)\n        self.recurHelper(root.right, level+1, res)\n```\n\n> 思路 2\n\n迭代，利用curLevel和nextLevel来记录，然后按层append.\n\n\n```python\nclass Solution:\n    # @param root, a tree link node\n    # @return nothing\n    def connect(self, root):\n        if not root:\n            return \n        res, cur_level = [], [root]\n        while cur_level:\n            next_level = []\n            for node in cur_level:\n                if node.left:\n                    next_level.append(node.left)\n                if node.right:\n                    next_level.append(node.right)\n            res.append(cur_level)\n            cur_level = next_level\n            \n        for cur_level in res:\n            for i in range(len(cur_level)-1):\n                cur_level[i].next = cur_level[i+1]\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md",
    "content": "#  117. Populating Next Right Pointers in Each Node II\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii\n\n> 内容描述\n\n```\nGiven a binary tree\n\nstruct TreeLinkNode {\n  TreeLinkNode *left;\n  TreeLinkNode *right;\n  TreeLinkNode *next;\n}\nPopulate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.\n\nInitially, all next pointers are set to NULL.\n\nNote:\n\nYou may only use constant extra space.\nRecursive approach is fine, implicit stack space does not count as extra space for this problem.\nExample:\n\nGiven the following binary tree,\n\n     1\n   /  \\\n  2    3\n / \\    \\\n4   5    7\nAfter calling your function, the tree should look like:\n\n     1 -> NULL\n   /  \\\n  2 -> 3 -> NULL\n / \\    \\\n4-> 5 -> 7 -> NULL\n```\n\n## 解题方案\n\n> 思路 1\n\n递归\n\n```python\nclass Solution:\n    # @param root, a tree link node\n    # @return nothing\n    def connect(self, root):\n        res = []\n        self.recurHelper(root, 0, res)\n        for cur_level in res:\n            for i in range(len(cur_level)-1):\n                cur_level[i].next = cur_level[i+1]     \n    \n    def recurHelper(self, root, level, res):\n        if not root: return\n        if len(res) < level + 1:\n            res.append([])\n        res[level].append(root)\n        self.recurHelper(root.left, level+1, res)\n        self.recurHelper(root.right, level+1, res)\n```\n\n> 思路 2\n\n迭代版本, beats 100%\n\n```python\nclass Solution:\n    # @param root, a tree link node\n    # @return nothing\n    def connect(self, root):\n        if not root:\n            return \n        res, cur_level = [], [root]\n        while cur_level:\n            next_level = []\n            for node in cur_level:\n                if node.left:\n                    next_level.append(node.left)\n                if node.right:\n                    next_level.append(node.right)\n            res.append(next_level)\n            cur_level = next_level\n            \n        for cur_level in res:\n            for i in range(len(cur_level)-1):\n                cur_level[i].next = cur_level[i+1]\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/118._pascal's_triangle.md",
    "content": "#  118. Pascal's Triangle\n**<font color=red>难度: 简单</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/pascals-triangle\n\n> 内容描述\n\n```\nGiven a non-negative integer numRows, generate the first numRows of Pascal's triangle.\n```\n![](https://github.com/apachecn/LeetCode/blob/master/images/118/PascalTriangleAnimated2.gif)\n\n```\nIn Pascal's triangle, each number is the sum of the two numbers directly above it.\n\nExample:\n\nInput: 5\nOutput:\n[\n     [1],\n    [1,1],\n   [1,2,1],\n  [1,3,3,1],\n [1,4,6,4,1]\n]\n```\n\n## 解题方案\n\n> 思路 1\n\n\n高中数学知识，把行数理理清楚就ok\n\n\n```python\nclass Solution(object):\n    def generate(self, numRows):\n        \"\"\"\n        :type numRows: int\n        :rtype: List[List[int]]\n        \"\"\"\n        if numRows == 0:\n            return []\n        res = [[1]]\n        for i in range(1, numRows):\n            tmp = [1]\n            for j in range(1, i):\n                tmp.append(res[-1][j-1]+res[-1][j])\n            tmp.append(1)\n            res.append(tmp)\n        return res         \n```\n或者可以写得更简单一些，这里谢谢荼靡大佬的想法，棒！\n\n```python\nclass Solution(object):\n    def generate(self, numRows):\n        \"\"\"\n        :type numRows: int\n        :rtype: List[List[int]]\n        \"\"\"\n        res = [[1]]\n        for i in range(1, numRows):\n            res.append(map(lambda x,y:x+y, [0]+res[-1], res[-1]+[0]))\n        return res[:numRows]\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/119._Pascal's_Triangle_II.md",
    "content": "### 119.  Pascal's Triangle II\n\n题目： \n<https://leetcode.com/problems/pascals-triangle-ii/>\n\n难度 : Easy\n\n\n\n思路：\n\n太简单了，注意一点算数就好\n\n\n```python\nclass Solution(object):\n    def getRow(self, rowIndex):\n        \"\"\"\n        :type rowIndex: int\n        :rtype: List[int]\n        \"\"\"\n        if rowIndex == 0:\n            return [1]\n        res = [1]\n        for i in range(1, rowIndex+1):\n            tmp = [1]\n            for j in range(1, i):\n                tmp.append(res[j-1]+res[j])\n            tmp.append(1)\n            res = tmp\n        return res\n```\n"
  },
  {
    "path": "docs/leetcode/python/120._Triangle.md",
    "content": "### 120. Triangle\n\n题目:\n\n<https://leetcode.com/problems/triangle/>\n\n难度:\nMedium\n\n思路：\n\n先是要注意下这句话：**Each step you may move to adjacent numbers on the row below**\n\n在考虑adjacent number的定义，并不是角标的adjacent，而是真的形态上的adjacent\n\n比如\n\n```\n\t\t-1\t\t\t\t\t\t\t\t-1\n\t2\t\t1\t\t\t最小\t\t\t1\t\t0\n-2\t\t2\t\t0\t\t\t\t-1\t\t2\t\t0\n```\n\n最小是-1， 而并不能从第二排的0跳到第三排的第一个造成-2.\n\n so AC代码\n\n感觉关于dp，我可能还需要补一些东西，因为我不能做到O(n) space\n\n```\nclass Solution(object):\n    def minimumTotal(self, triangle):\n        \"\"\"\n        :type triangle: List[List[int]]\n        :rtype: int\n        \"\"\"\n        # n total rows of triangle\n        n = len(triangle)\n        if n == 1: return triangle[0][0]\n        elif n == 2 : return min(triangle[0][0] + triangle[1][0], triangle[0][0] + triangle[1][1])\n        else:\n        \tres = []\n        \tfor i in range(n):\n        \t\tres.append(triangle[i])\n\n        \tres[0] = [triangle[0][0]]\n        \tres[1] = [triangle[0][0] + triangle[1][0], triangle[0][0] + triangle[1][1]]\n\n        \tfor i in range(2,n):\n        \t\tfor j in range(i+1):\n        \t\t\tif j == 0:\n        \t\t\t\tres[i][j] = res[i-1][j] + triangle[i][j]\n        \t\t\telif j == i:\n        \t\t\t\tres[i][j] = res[i-1][-1] + triangle[i][j]\n        \t\t\telse:\n        \t\t\t\tres[i][j] = min(res[i-1][j-1],res[i-1][j]) + triangle[i][j]\n\n        \treturn min(res[-1])\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/121._Best_Time_to_Buy_and_Sell_Stock.md",
    "content": "#  121. Best Time to Buy and Sell Stock\n\n**<font color=green>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/best-time-to-buy-and-sell-stock\n* https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock\n\n> 内容描述\n\n```\n给定一个数组，它的第 i 个元素是一支给定股票第 i 天的价格。\n\n如果你最多只允许完成一笔交易（即买入和卖出一支股票一次），设计一个算法来计算你所能获取的最大利润。\n\n注意：你不能在买入股票前卖出股票。\n\n示例 1:\n\n输入: [7,1,5,3,6,4]\n输出: 5\n解释: 在第 2 天（股票价格 = 1）的时候买入，在第 5 天（股票价格 = 6）的时候卖出，最大利润 = 6-1 = 5 。\n     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格；同时，你不能在买入前卖出股票。\n\n示例 2:\n\n输入: [7,6,4,3,1]\n输出: 0\n解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。\n```\n\n## 解题方案\n\n> 思路1\n\n1. 找到一个最低价格的位置，记录 index\n2. 找到一个最大卖出价格的位置，记录 利润\n\n```py\nclass Solution:\n    def maxProfit(self, prices):\n        n = len(prices)\n        if n == 0: return 0\n\n        result = 0\n        minprice = prices[0]\n        for i in range(1, n):\n            minprice = min(prices[i], minprice)\n            result = max(prices[i] - minprice, result)\n        return result\n```\n\n> 思路2\n\n1. 初始化 dp，用于存放目录结果\n2. 找到最小值，计算当前最大的利润，存放到 dp中\n3. 找到 dp 以后一个元素，就是当前结果的最大值\n\n```py\nclass Solution:\n    def maxProfit(self, prices):\n        n = len(prices)\n        if n == 0: return 0\n\n        dp = [0] * n\n        minprice = prices[0] \n        for i in range(1, n):\n            # 找到最小的值\n            minprice = min(minprice, prices[i])\n            dp[i] = max(dp[i - 1], prices[i] - minprice)\n\n        return dp[-1]\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/124._Binary_Tree_Maximum_Path_Sum.md",
    "content": "### 124. Binary Tree Maximum Path Sum\n\n题目:\n<https://leetcode.com/problems/binary-tree-maximum-path-sum/>\n\n\n难度:\n\nHard\n\n\n思路\n\n\n\n```python\nclass Solution(object):\n    \n    def maxPathSum(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        self.global_max = root.val if root else 0\n        self.findmax(root)\n        return self.global_max\n\n    def findmax(self, node):\n        if not node:\n            return 0\n        \n        left = self.findmax(node.left) \n        left = left if left > 0 else 0\n        \n        right = self.findmax(node.right)\n        right = right if right > 0 else 0\n        # 这句是精髓，只要判断出当前这个点作为root的path更长，就更新一下\n        self.global_max = max(left + right + node.val, self.global_max) \n        # 这里是因为sub_path只能为一条边，不然跟上面的root组合起来就不是path了\n        return max(left, right) + node.val \n```\n\n其实开始的时候我想当然的用了很傻的方法，并且是错误的，因为这样当[-10,9,20,null,null,15,7]的时候我们会取所有的点，返回41，然而我们可以取到42的，\n即15+7+20\n\n```\nclass Solution(object):\n    def maxPathSum(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n        if not root.left and not root.right:\n            return root.val\n        if not root.left:\n            return max(root.val, root.val+self.maxPathSum(root.right))\n        if not root.right:\n            return max(root.val, root.val+self.maxPathSum(root.left))\n        return max(root.val, \n                   root.val+self.maxPathSum(root.right), \n                   root.val+self.maxPathSum(root.left), \n                   root.val+self.maxPathSum(root.left)+self.maxPathSum(root.right))\n```\n"
  },
  {
    "path": "docs/leetcode/python/125._valid_palindrome.md",
    "content": "### 125. Valid Palindrome\n\n题目:\n<https://leetcode.com/problems/valid-palindrome/>\n\n\n难度:\n\nEasy\n\n\n\n就是比较reversed string 和原本的是否相等.\n\n\n```python\nclass Solution(object):\n    def isPalindrome(self,s):\n        \"\"\"\n        :type s: str\n        :rtype: bool\n        \"\"\"\n          \n        new=[]  \n        s = s.lower()  \n  \n        for i in s:  \n            if '0'<=i<='9' or 'a'<=i<='z':  \n                new.append(i)  \n  \n        return new == new[::-1]  \n```\n\n或者用正则,详见[re.sub()用法](http://blog.csdn.net/geekleee/article/details/75309433)\n瞬间```beats 97.71%```\n```python\nclass Solution(object):\n    def isPalindrome(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: bool\n        \"\"\"\n        newString = re.sub(\"[^0-9a-zA-Z]+\", \"\", s)\n        return newString.lower() == newString.lower()[::-1]\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/126._Word_Ladder_II.md",
    "content": "### 126. Word Ladder II\n\n题目:\n\n<https://leetcode.com/problems/word-ladder-ii/>\n\n难度:\n\nHard\n\n其实关键在于怎么优化和表示图\n\n\n\n思路来自1p3a：\n\n这题目实在是太适合python了  如此简洁\n\n就是基本的bfs，典型的level order traverse\n有两个坑：\n\n1. 不要判断字典里的某两个word是否只相差一个字母，而是要判断某个word的邻居（和他只相差一个字母的所有word）是否在字典里，这样的改进会使这一步的复杂度下降很多，否则超时妥妥\n2. 每一轮访问过的word一定要从字典中删除掉，否则一定会超时\n\n最后见到end word就收\n完成\n\n\n\n拿题目的例子来看：\n\n```\\\n\t\thit\n\t     |\n\t    hot\n       /   \\\n      dot   lot\n       |     |\n      dog   log\n        \\   /\n         cog\n```\n\nroutine 字典，然后再根据这个来寻找路径\n\n`{'cog': ['log', 'dog'], 'hit': [], 'log': ['lot'], 'dog': ['dot'], 'hot': ['hit'], 'lot': ['hot'], 'dot': ['hot']}`\n\n```'cog': ['log', 'dog']```这里的意思就是说在走到```'cog'```之前尝试过了```'log'```和```'dog'```，即previous tried node\n\n而生成字典的过程就是BFS的，此处保证寻找的路径就是最短的。\n\nAC代码：\n\n```python\nclass Solution(object):\n    def findLadders(self, beginWord, endWord, wordList):\n        \"\"\"\n        :type beginWord: str\n        :type endWord: str\n        :type wordList: List[str]\n        :rtype: List[List[str]]\n        \"\"\"\n\n        def backtrack(result, trace, path, word):\n            if len(trace[word]) == 0:\n                result.append([word] + path)\n            else:\n                for prev in trace[word]:\n                    backtrack(result, trace, [word] + path, prev)\n\n        lookup = set(wordList) | set([beginWord])\n        res, cur, routine = [], set([beginWord]), {word: [] for word in lookup}\n        while cur and endWord not in cur:\n            next_queue = set()\n            for word in cur:\n                lookup.remove(word)\n            for word in cur:\n                for i in range(len(word)):\n                    for j in 'abcdefghijklmnopqrstuvwxyz':\n                        candidate = word[:i] + j + word[i + 1:]\n                        if candidate in lookup:\n                            next_queue.add(candidate)\n                            routine[candidate].append(word)\n            cur = next_queue\n\n        if cur:\n            backtrack(res, routine, [], endWord)\n        return res\n```\n\n\n\n这样可以beat 69.09%\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/127._word_ladder.md",
    "content": "### 127. Word Ladder\n\n题目:\n\n<https://leetcode.com/problems/word-ladder/>\n\n\n难度:\n\nMedium\n\ntag可以算BFS，其实就是求shortest path的变体\n\nReference from [kamyu104](https://github.com/kamyu104/LeetCode/blob/71e0ba555ee49befa01fcd9fc78c3528e2ab63a9/Python/word-ladder.py)\n\n```python\nclass Solution(object):\n    def ladderLength(self, beginWord, endWord, wordList):\n        \"\"\"\n        :type beginWord: str\n        :type endWord: str\n        :type wordList: List[str]\n        :rtype: int\n        \"\"\"\n        distance, cur, visited, lookup = 0, [beginWord], set([beginWord]), set(wordList)\n        \n        while cur:\n            next_queue = []\n\n            for word in cur:\n                if word == endWord:\n                    return distance + 1\n                for i in xrange(len(word)):\n                    for j in 'abcdefghijklmnopqrstuvwxyz':\n                        candidate = word[:i] + j + word[i + 1:]\n                        if candidate not in visited and candidate in lookup:\n                            next_queue.append(candidate)\n                            visited.add(candidate)\n            distance += 1\n            cur = next_queue\n\n        return 0\n```\n"
  },
  {
    "path": "docs/leetcode/python/128._Longest_Consecutive_Sequence.md",
    "content": "### 128. Longest Consecutive Sequence\n\n题目:\n<https://leetcode.com/problems/longest-consecutive-sequence/>\n\n\n难度:\n\nHard\n\n\n### 思路\n首先去重复，时间```O(N)```,然后将所有元素都放到一个字典中，这样判断一个数字的后续在不在这个字典中，如果存在就一直判断下去，每次判断只要```O(1)```。\n\n对于每个数，如果他的前续已经判断过了，他就没有必要判断了，继续判断下一个数，即：\n```\nif num - 1 in nums:\n    continue\n```\n\n\nAC代码：\n\n```python\nclass Solution(object):\n    def longestConsecutive(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        nums = set(nums)\n        tmp = {}\n        for num in nums:\n            tmp[num] = 1\n        res = 0\n        for num in nums:\n            if num - 1 not in nums:\n                y = num + 1\n                while y in nums:\n                    y += 1\n                res = max(res, y - num)\n        return res\n```\n\n但其实```set```和字典的```in```判断都是```O(1)```\n\n```dict```与```set```实现原理是一样的，都是将实际的值放到```list```中。唯一不同的在于hash函数操作的对象，对于```dict```，```hash```函数操作的是其```key```，而对于```set```是直接操作的它的元素，假设操作内容为```x```，其作为因变量，放入```hash```函数，通过运算后取```list```的余数，转化为一个```list```的下标，此下标位置对于```set```而言用来放其本身，而对于```dict```则是创建了两个```list```，一个```list```该下表放此```key```，另一个```list```中该下标方对应的```value```。参考[python dict与set 的实现](http://www.cnblogs.com/pengsixiong/p/5326893.html)\n\n　　其中，我们把实现set的方式叫做Hash Set，实现dict的方式叫做Hash Map/Table(注：map指的就是通过key来寻找value的过程)\n\n```set```和```dict```的唯一区别仅在于没有存储对应的```value```，但是，```set```的原理和```dict```一样，所以，同样不可以放入可变对象，因为无法判断两个可变对象是否相等，也就无法保证```set```内部“不会有重复元素”。\n\n因此，代码也可以写成这样\n```python\nclass Solution(object):\n    def longestConsecutive(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        nums = set(nums)\n        res = 0\n        for num in nums:\n            if num - 1 not in nums:\n                y = num + 1\n                while y in nums:\n                    y += 1\n                res = max(res, y - num)\n        return res\n```\n"
  },
  {
    "path": "docs/leetcode/python/129._sum_root_to_leaf_numbers.md",
    "content": "###129. Sum Root to Leaf Numbers\n\n题目:\n<https://leetcode.com/problems/sum-root-to-leaf-numbers/>\n\n\n难度:\n\nMedium\n\n其实递归不难想到，不过我自己做错在细节方面\n\n如果只有单支，每朝下走一层，代表的数字都增加10， 10* 原本的 + 新节点的数字，最终也是用这个来解\n\n```\nclass Solution(object):\n    def sumNumbers(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        return self.calSum(root,0)\n    \n    \n    def calSum(self,root,curSum):\n        if root == None:\n            return 0\n        else:\n            curSum = curSum * 10 + root.val\n            if root.left == None and root.right == None:\n                return curSum\n            else:\n                return self.calSum(root.left, curSum) + self.calSum(root.right, curSum)\n        \n\n                \n```\n"
  },
  {
    "path": "docs/leetcode/python/130._surrounded_regions.md",
    "content": "###130. Surrounded Regions\n\n\n题目:\n\n<https://leetcode.com/problems/surrounded-regions>\n\n\n难度:\n\nMedium\n\n\n思路:\n\nloop，然后碰到O做DFS/BFS找出O所在区域:\n\n- 貌似只要O没有碰壁，O就总是被X包围着？\n- 所以找出O的范围，然后看它是否碰壁，没有碰壁则mark不需要修改\n\n但是这道题折磨我了很久，因为它有毛病。。。。\n它给的input例子是\n[\"XXX\",\"XOX\",\"XXX\"]\n也怪我 input写着List[List[str]]\n\n但实际上的输入是：\n[[u'X', u'X', u'X'], [u'X', u'X', u'X'], [u'X', u'X', u'X']]\n\n\n还要mark unicode\n\n还有就是学会了新的可以函数之下定义函数，这样就不用什么self了，用起来真方便，但是这样的思路做起来会超时。\n\n\n\n```\nclass Solution(object):\n    def solve(self, board):\n        \"\"\"\n        :type board: List[List[str]]\n        :rtype: void Do not return anything, modify board in-place instead.\n        \"\"\"\n\n\n        def shouldOChange(i, j):\n            \"\"\"\n            return x,y area and whether they shouldChange\n            \"\"\"\n            shouldChange = True\n            Oarea = []\n            s = []\n            s.append((i,j))\n            while s:\n                (x,y) = s.pop()\n                if x == 0 or x == row - 1 or y == 0 or y == col -1 :\n                    shouldChange = False\n                visited[x][y] = 1\n                Oarea.append((x,y))\n                if legal(x-1,y):\n                    s.append((x-1,y))\n                if legal(x+1,y):\n                    s.append((x+1,y))\n                if legal(x,y-1):\n                    s.append((x,y-1))\n                if legal(x,y-1):\n                    s.append((x,y+1))\n                return Oarea,shouldChange\n\n        def legal(x,y):\n            return x>=0 and x < row and y>=0 and y < col and board[x][y] == 'O' and visited[x][y] == 0\n\n        \n        row = len(board)\n        col = len(board[0]) if row else 0\n\n        visited = [[0 for i in range(col)] for j in range(row)]\n\n        for i in range(row):\n            for j in range(col):\n                if board[i][j] == 'O' and visited[i][j] == 0:\n                    Oarea, shouldChange = shouldOChange(i,j)\n                    print Oarea,shouldChange\n                    if shouldChange:\n                        for (x,y) in Oarea:\n                            board[x][y] = u'X'\n\n        print board\n```\n\n\n另一个思路就是对周围碰壁的O做BFS/DFS，碰壁的和碰壁相连的是不需要修改的。这样就时间复杂度降低很多了。\n\n原本是O(n^2)可能做DFS/BFS。现在是O(4n)做DFS/BFS,但是发现依旧超时，最后查看了别人的解法，因为我的解法里面多了一个存储工具，相当于，把需要更换location的位置存储起来，最后做loop的时候去查，然后这样还是很耗时。\n\n而一个简便的变法是把这些特别的碰壁的'O' mark出来，这样最后loop的时候不改变这些'O'，只改变不碰壁的'O',又可以减少工作量。同时依旧可以使用collection里面的queue\n\n\n\nAC代码\n\n```\nclass Solution(object):\n    def solve(self, board):\n        \"\"\"\n        :type board: List[List[str]]\n        :rtype: void Do not return anything, modify board in-place instead.\n        \"\"\"\n        def legal(x,y):\n            return x>=0 and x < row and y>=0 and y < col and board[x][y] == 'O' and visited[x][y] == 0\n\n        \n        row = len(board)\n        col = len(board[0]) if row else 0\n\n        visited = [[0 for i in range(col)] for j in range(row)]\n\n        notChangeOArea = []\n        queue = collections.deque()\n\n        for j in range(col):\n            if board[0][j] == 'O': queue.append((0,j))\n            if board[row-1][j] == 'O': queue.append((row-1,j))\n        for i in range(row):\n            if board[i][0] == 'O': queue.append((i,0))\n            if board[i][col-1] == 'O': queue.append((i,col-1))\n\n        while queue:\n            (x,y) = queue.popleft()\n            board[x][y] = '$'\n            visited[x][y] = 1\n            if legal(x-1,y):\n                queue.append((x-1,y))\n            if legal(x+1,y):\n                queue.append((x+1,y))\n            if legal(x,y-1):\n                queue.append((x,y-1))\n            if legal(x,y+1):\n                queue.append((x,y+1))\n\n        for i in range(row):\n            for j in range(col):\n                if board[i][j] == '$' : board[i][j] = 'O'\n                elif board[i][j] == 'O' : board[i][j] = 'X'\n```\n\n\n同时发现，用这种方式，无论是否使用collection里面的queue，都能AC"
  },
  {
    "path": "docs/leetcode/python/131._palindrome_partitioning.md",
    "content": "###131. Palindrome Partitioning\n\n题目:\n<https://leetcode.com/problems/palindrome-partitioning/>\n\n\n难度:\nMedium\n\n知道一定是用递归做，但是在怎么拆的部分疑惑了，然后看了hint\n\nkey部分长这样，拆法是类似于combination，然后这个len(s) == 0是确保能被拆为palindrome，因为这样剩下的string才是空的\n\n\n这个recursion tree是这样的，感觉时间复杂度是O(n!)，因为每次树都branch n个分支\n\n```\n\nclass Solution(object):\n    def partition(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: List[List[str]]\n        \"\"\"\n        self.res = []\n        self.dfs(s,[])\n        return self.res\n\n\n    def dfs(self, s, stringList):\n        if len(s) == 0:\n            self.res.append(stringList)\n        for i in range(1,len(s)+1):\n            if self.isPalindrome(s[:i]):\n                self.dfs(s[i:],stringList + [s[:i]])\n\n    def isPalindrome(self, s):\n        if len(s) <= 1:\n            return True\n        return s[0] == s[-1] and self.isPalindrome(s[1:-1])\n\na = Solution()\nprint a.partition(\"aab\")\n\n# [['a', 'a', 'b'], ['aa', 'b']]\n```\n\n输出是每次必定从单个char的list开始，然后单个char 配 palindrome word，然后palindrome word再来配char..."
  },
  {
    "path": "docs/leetcode/python/133._clone_graph.md",
    "content": "###133. Clone Graph\n\n\n题目:\n<https://leetcode.com/problems/clone-graph/>\n\n\n难度:\nMedium\n\n\n\n思路：\n\nDFS或者BFS把graph traverse一遍，边traverse边复制。因为nodes are labeled uniquely，这就是方便的地方，但是注意node可能重复和有self-loop.\n\n所以先建立新的root node，然后有一个dict把node label和node一一对应。\n\n用stack来存储原本的graph root node，对原本的graph做DFS，这个时候，如果这个node的neighbor是已经出现过，那么我们就是去修改原本的existNode，让它指向存在的neighbor，否则创建新的，再把它们联系起来，谷歌了一下，别人写的比我更简单。anyway，先AC。\n\n\n\n`if cur.label in createdNodes:`多余。\n\n\n\n\n```\nclass Solution(object):\n    def cloneGraph(self, node):\n        \"\"\"\n        :type node: UndirectedGraphNode\n        :rtype: UndirectedGraphNode\n        \"\"\"\n        if node == None: return None\n\n        root = UndirectedGraphNode(node.label)\n        # must 1 to 1\n        createdNodes = {}\n        createdNodes[root.label] = root \n\n        stack = []\n        stack.append(node)\n\n        while stack:\n        \tcur = stack.pop()\n        \tif cur.label in createdNodes:\n        \t\texistNode = createdNodes[cur.label]\n        \t\tfor neighbor in cur.neighbors:\n        \t\t\tif neighbor.label in createdNodes:\n        \t\t\t\texistNeighbor = createdNodes[neighbor.label]\n        \t\t\t\texistNode.neighbors.append(existNeighbor)\n        \t\t\telse:\n        \t\t\t\tnewNode = UndirectedGraphNode(neighbor.label)\n        \t\t\t\texistNode.neighbors.append(newNode)\n        \t\t\t\tcreatedNodes[neighbor.label] = newNode\n        \t\t\t\tstack.append(neighbor)\n        return root\n```\n\n\n\n看了别人的代码，貌似比我又写的简洁。\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/136._single_number.md",
    "content": "### 136. Single Number\n\n\n\n题目:\n<https://leetcode.com/problems/single-number/>\n\n\n难度:\n\nEasy\n\n\n思路：\n\n位运算，终于要take it了\n\n非常常见的一道算法题，将所有数字进行异或操作即可。对于异或操作明确以下三点：\n\n- 一个整数与自己异或的结果是0\n- 一个整数与0异或的结果是自己\n- 异或操作满足交换律，即a^b=b^a\n\nPython的位操作：\n<https://wiki.python.org/moin/BitwiseOperators>\n\n神奇的解法：\n\n\n```python\nclass Solution(object):\n    def singleNumber(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        res = nums[0]\n        for i in nums[1:]:\n            res ^= i\n        return res\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/139._word_break.md",
    "content": "### 139. Word Break\n\n**<font color=yellow>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/word-break\n* https://leetcode-cn.com/problems/word-break\n\n\n> 内容描述\n\n```\n给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict，判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。\n\n说明：\n拆分时可以重复使用字典中的单词。\n你可以假设字典中没有重复的单词。\n\n示例 1：\n输入: s = \"leetcode\", wordDict = [\"leet\", \"code\"]\n输出: true\n解释: 返回 true 因为 \"leetcode\" 可以被拆分成 \"leet code\"。\n\n示例 2：\n输入: s = \"applepenapple\", wordDict = [\"apple\", \"pen\"]\n输出: true\n解释: 返回 true 因为 \"applepenapple\" 可以被拆分成 \"apple pen apple\"。\n     注意你可以重复使用字典中的单词。\n\n示例 3：\n输入: s = \"catsandog\", wordDict = [\"cats\", \"dog\", \"sand\", \"and\", \"cat\"]\n输出: false\n```\n\n\n## 解题方案\n\n> 思路 1:\n\n```\nok[0] = True\n\ncatsandog => s[0:1] = c\nok[0] + s[0: 1] => False  表示 0 这个位置不可以拼接得到\n\ncatsandog => s[0:2] = ca\nok[0] + s[0: 2] => False  表示 0～1 这个位置不可以拼接得到\nok[1] + s[1: 2] => False  表示 1～1 这个位置不可以拼接得到\n\ncatsandog => s[0:3] = cat\nok[0] + s[0: 3] => True   表示 0～2 这个位置可以拼接得到\nok[1] + s[1: 3] => False  表示 1～2 这个位置不可以拼接得到\nok[2] + s[2: 3] => False  表示 2～2 这个位置不可以拼接得到\n\ncatsandog => s[0:4] = cats\nok[0] + s[0: 4] => True   表示 0～3 这个位置可以拼接得到\nok[1] + s[1: 4] => False  表示 1～3 这个位置不可以拼接得到\nok[2] + s[2: 4] => False  表示 2～3 这个位置不可以拼接得到\nok[3] + s[3: 4] => False  表示 3～3 这个位置不可以拼接得到\n```\n\n```python\nclass Solution(object)::\n    def wordBreak(self, s, wordDict):\n        \"\"\"\n        :type s: str\n        :type wordDict: List[str]\n        :rtype: bool\n        \"\"\"\n        ok = [True]\n        for i in range(1, len(s)+1):\n            ok += [any(ok[j] and s[j:i] in wordDict for j in range(i))]\n        return ok[-1]\n```\n"
  },
  {
    "path": "docs/leetcode/python/140._word_break_ii.md",
    "content": "\n### 140. Word Break II\n\n题目:\n<https://leetcode.com/problems/word-break-ii/>\n\n\n难度:\n\nMedium\n\n\n\n还是backtracking，会超时\n\n```\nclass Solution(object):  # 此法超时\n    def wordBreak(self, s, wordDict):\n        \"\"\"\n        :type s: str\n        :type wordDict: Set[str]\n        :rtype: bool\n        \"\"\"\n        self.res = []\n        self.wordBreakLst(\"\",s,wordDict)\n        return self.res\n                \n        \n    def wordBreakLst(self, lst, rest, wordDict):\n        if rest == '':\n            self.res.append(lst.rstrip())\n            # print lst\n        for i in range(1+len(rest)):\n            if rest[:i] in wordDict:\n                self.wordBreakLst(lst + rest[:i] + \" \",rest[i:],wordDict)\n\n```\n\n\n\n\n然后看到有把word break i 结合起来减少时间复杂度的作法。\n\n\n做法如下，聪明：\n\n就是对于每一个s，我们来check它是否可以break，如果不可以，就不用做相应的操作了\n \n \n```python\nclass Solution(object):\n    def wordBreak(self, s, wordDict):\n        \"\"\"\n        :type s: str\n        :type wordDict: List[str]\n        :rtype: List[str]\n        \"\"\"\n        self.res = []\n        self.wordBreakLst(s, wordDict, '')\n        return self.res\n    \n    def check(self, s, wordDict):\n        ok = [True]\n        for i in range(1, len(s) + 1):\n            ok += any(ok[j] and s[j:i] in wordDict for j in range(i)),\n        return ok[-1]\n\n        \n    def wordBreakLst(self, s, wordDict, stringLst):\n        if self.check(s, wordDict):\n            if len(s) == 0 : self.res.append(stringLst[1:])  # 因为最开始也加了一个空格\n            for i in range(1,len(s)+1):\n                if s[:i] in wordDict:\n                    self.wordBreakLst(s[i:], wordDict, stringLst + ' ' + s[:i])\n```\n\n\n但是其实\n\n```\ns = \"aaaaaa\"\nwordDict = [\"a\",\"aa\",\"aaa\"]\nprint a.wordBreak(s,wordDict)还是会loop很多次\n\n不过像\ns = \"aabbb\"\nwordDict = [\"a\",\"abbb\"]\n就会极其的减少loop次数\n```\n\n\n看看stefan大神的做法：\n\n```sentences(i)``` returns a list of all sentences that can be built from the suffix ```s[i:]```.\n\n```python\nclass Solution(object):\n    def wordBreak(self, s, wordDict):\n        \"\"\"\n        :type s: str\n        :type wordDict: List[str]\n        :rtype: List[str]\n        \"\"\"\n        memo = {len(s): ['']}\n        def sentences(i):\n            if i not in memo:\n                memo[i] = [s[i:j] + (tail and ' ' + tail)\n                           for j in range(i+1, len(s)+1)\n                           if s[i:j] in wordDict\n                           for tail in sentences(j)]\n            return memo[i]\n        return sentences(0)\n```\n"
  },
  {
    "path": "docs/leetcode/python/141._linked_list_cycle.md",
    "content": "### 141. Linked List Cycle\n\n题目:\n\n<https://leetcode.com/problems/linked-list-cycle/>\n\n\n难度:\n\nEasy\n\n\n想法一：\n\n直接超时\n\n```\nclass Solution(object):\n    def hasCycle(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        if head == None: return False\n        lst = []\n        cur = head\n        while cur:\n            if cur in lst:\n                return True\n            lst.append(cur)\n            cur = cur.next\n        return False\n```\n\n\n\n想法二：相当用boolean array记录某个点是否被访问过，时间，空间复杂度都是O（n）\n\n```\nclass Solution(object):\n    def hasCycle(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        if head == None: return False\n        dictx = {}\n        cur = head\n        while cur:\n            if cur in dictx:\n                return True\n            dictx[cur] = 1\n            cur = cur.next\n        return False\n```\n\n结果这种方法的run time还比较快\n\n查了一下，有解答说可以有空间复杂度O（1），时间复杂度O（n）。两个指针，一个快一个慢，快的每次走两步，慢的每次走一步，如果有环，最终会在某处相遇。这也是一个算法。这种快慢指针配合已经不是第一次遇到了，比如找linklist中间的node。\n\n\n\n但是并没有觉得这样的算法是O(n)， worst case time complexity is O(N+K), which is O(n).\n\n\n```python\npython\nclass Solution(object):\n    def hasCycle(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        slow = head\n        fast = head\n        while fast and fast.next:\n            slow = slow.next\n            fast = fast.next.next\n            if slow == fast:\n                return True\n        return False\n```\n\n\n```java\njava\npublic class Solution {\n    public boolean hasCycle(ListNode head) {\n        if (head == null){\n            return false;\n        }\n        ListNode fast = head;\n        ListNode slow = head;\n        while (fast != null && slow != null && fast.next != null){\n            fast = fast.next.next;\n            slow = slow.next;\n            if (slow == fast){\n                return true;\n            }\n        }\n        return false;\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/142_Linked_List_Cycle_II.md",
    "content": "### 142. Linked List Cycle II\n\n题目:\n\n<https://leetcode.com/problems/linked-list-cycle-ii/>\n\n\n难度:\n\nMedium\n\n思路：\n稍微改了一下[141](https://github.com/Lisanaaa/thinking_in_lc/blob/master/141._linked_list_cycle.md)，这里稍微注意一下```while-else clause```就行\n\nLet’s say, the first node is node ```0```, the cycle starts at node ```L```, and the length of the cycle is ```C```;\nMoreover, after ```t``` steps, ```fast``` catches ```slow```.\n\nNow we know that fast totally traveled ```2t``` nodes, and slow traveled ```t``` nodes\n\nThen we have:\n```2t - t = nC``` (where ```n``` is an positive integer.)\ni.e. ```t=nC```\n\nNow, think about that, at step ```t```, if we travels ```L``` more steps, where are we?\ni.e. if we travel ```L+t = L + nC``` steps in total, where are we?\n\nAbsolutely, at the start of the cycle, because we have covered the first ```L``` nodes once and the entire cycle ```n``` times.\n\nSo, if we travel ```L``` more steps at time ```t```, then we get the start of the cycle.\n\nHowever, how can we travel exactly ```L``` step?\nThe answer is to use an other pointer to travel from node ```0```, and when they meet together, it is exactly ```L``` steps and both of them are at the start of the cycle.\n\n参考[LostSummer233的解答](https://leetcode.com/problems/linked-list-cycle-ii/discuss/44833)\n```python\nclass Solution(object):\n    def detectCycle(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        slow = fast = head\n        while fast and fast.next:\n            slow = slow.next\n            fast = fast.next.next\n            if slow == fast:\n                break\n        else:\n            return None\n        while head != slow:\n            slow = slow.next\n            head = head.next\n        return head\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/143._reorder_list.md",
    "content": "###143. Reorder List\n\n题目:\n\n<https://leetcode.com/problems/reorder-list/>\n\n\n难度:\n\nMedium\n\n超时\n\n\n```\n\nclass Solution(object):\n    def reorderList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: void Do not return anything, modify head in-place instead.\n        \"\"\"\n        head = self.reorder(head)\n\n        \n    def reorder(self, head):\n        if head == None or head.next == None or head.next.next == None:\n            return head\n    \n        l0 = head\n        l1 = head.next\n        ln_1 = self.oneNodeTail(head)\n        ln =ln_1.next\n    \n        l0.next = ln\n        ln_1.next = None\n        ln.next = self.reorder(l1)\n        return l0\n        \n\n    def oneNodeTail(self, head):\n        if head == None or head.next == None or head.next.next == None:\n            return head\n        cur = head \n        while cur.next:\n            if cur.next.next:\n                cur = cur.next\n            else:\n                break\n        return cur\n                \n```\n\n\n取巧的办法是：\n\n找到中间节点，断开，把后半截linked list reverse，然后合并 √\n\n看了AC指南\n\n```\nclass Solution(object):\n    def reorderList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: void Do not return anything, modify head in-place instead.\n        \"\"\"\n        if head == None or head.next == None or head.next.next == None:\n            return\n        \n        slow = head\n        fast = head\n        prev = None\n        \n        while fast and fast.next:\n            prev = slow\n            slow = slow.next\n            fast = fast.next.next\n            \n        prev.next = None\n\n\n        slow = self.reverseList(slow)\n        \n        cur = head\n        while cur.next:\n            tmp = cur.next\n            cur.next = slow\n            slow = slow.next\n            cur.next.next = tmp\n            cur = tmp\n        cur.next = slow\n            \n        \n    \n    def reverseList(self,head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        prev = None \n        cur = head\n        while(cur):\n            nxt = cur.next\n            cur.next = prev\n            prev = cur\n            cur = nxt\n        return prev\n        \n        \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/144._binary_tree_preorder_traversal.md",
    "content": "#  144. Binary Tree Preorder Traversal\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/binary-tree-preorder-traversal\n\n> 内容描述\n\n```\nGiven a binary tree, return the preorder traversal of its nodes' values.\n\nExample:\n\nInput: [1,null,2,3]\n   1\n    \\\n     2\n    /\n   3\n\nOutput: [1,2,3]\nFollow up: Recursive solution is trivial, could you do it iteratively?\n```\n\n## 解题方案\n\n> 思路 1\n\nRecursive递归,瞬秒\n\n\n```python\nclass Solution(object):\n    def preorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        if not root:\n            return res\n        res.append(root.val)\n        if root.left: \n            res.extend(self.preorderTraversal(root.left))\n        if root.right:\n            res.extend(self.preorderTraversal(root.right))\n        return res\n```\n\n> 思路 2\n\n或者我们可以先写一下先序遍历的函数，然后一个一个贴上去\n\n```python\nclass Solution(object):\n    def preorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        if root == None:\n            return []\n        res = []\n        self.preorder(root,res)\n        return res\n        \n        \n    def preorder(self,root,res):\n        if root == None:\n            return\n        res.append(root.val)\n        self.preorder(root.left,res)\n        self.preorder(root.right,res)\n```\n\n\nIterative, 迭代\n\n\n```python\nclass Solution(object):\n    def preorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        if not root:  \n            return res  \n        stack = []  \n        stack.append(root)  \n          \n        while(len(stack) > 0):  \n            node = stack.pop()  \n            res.append(node.val)  \n            if node.right:  \n                stack.append(node.right)  \n            if node.left:  \n                stack.append(node.left)  \n        return res\n```\n"
  },
  {
    "path": "docs/leetcode/python/145._binary_tree_postorder_traversal.md",
    "content": "#  145. Binary Tree Postorder Traversal 二叉树的后序遍历\n**<font color=red>难度: 困难</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/binary-tree-postorder-traversal\n\n> 内容描述\n\n```\n给定一个二叉树，返回它的 后序 遍历。\n\n示例:\n\n输入: [1,null,2,3]  \n   1\n    \\\n     2\n    /\n   3 \n\n输出: [3,2,1]\n进阶: 递归算法很简单，你可以通过迭代算法完成吗？\n```\n\n## 解题方案\n\n> 思路 1\n\n递归，so easy\n\n```python\nclass Solution(object):\n    def postorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        if not root:\n            return res\n        \n        left = self.postorderTraversal(root.left)\n        right = self.postorderTraversal(root.right)\n        \n        if left:\n            res.extend(left)\n        if right:\n            res.extend(right)\n\n        res.append(root.val)\n        return res\n```\n\n> 思路 2\n\n也可以先写一下后序遍历的函数，然后一个一个贴上去\n\n\n```python\nclass Solution(object):\n    def postorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        def postOrder(root):\n            if not root : return\n            postOrder(root.left)\n            postOrder(root.right)\n            res.append(root.val)\n            \n        res = []\n        postOrder(root)\n        return res\n```\n\n> 思路 3\n\n迭代, 其实思路就一句话，后序遍历是左右中，因为我们第一个放进去的肯定是中（即root），所以我们逆向思维考虑一下，我们按照中右左的顺序放进去，然后返回res[::-1]就行了。这其实跟[leetcode第144题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/144._binary_tree_preorder_traversal.md)是一样的思路\n\n\n```python\nclass Solution(object):\n    def postorderTraversal(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        if not root:\n            return res\n        \n        stack1 = []\n        stack1.append(root)\n        \n        while len(stack1) > 0:\n            node = stack1.pop()\n            res.append(node.val)\n            if node.left:\n                stack1.append(node.left)\n            if node.right:\n                stack1.append(node.right)\n\n        return res[::-1]\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/147._insertion_sort_list.md",
    "content": "###147. Insertion Sort List\n\n题目:\n<https://leetcode.com/problems/insertion-sort-list/>\n\n\n难度:\nMedium\n\ninsertion sort 也是入门必备，一个元素本身被认为是sort的，一个简单的理解是打牌，然后进入第二个元素的时候，看它是比第一个元素大还是小，做排序，进入下一个元素的时候再看再移。\n\n伪码\n\n```\nfor i ← 1 to length(A)-1\n    j ← i\n    while j > 0 and A[j-1] > A[j]\n        swap A[j] and A[j-1]\n        j ← j - 1\n    end while\nend for\n```\n\n这个伪码对于list可能适用性没有那么强，则考虑，从第二个node开始，那么从开始开始看，找到这个node应该插入的位置，插入。\n\n\n\n就是这样，就是会超时||||\n\n```\nclass Solution(object):\n    def insertionSortList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if head == None or head.next == None:\n            return head\n\n        dummy = ListNode(-1)\n        dummy.next = head\n\n        prev = head \n        cur = head.next\n\n        while cur:\n            p = dummy\n            while p.next.val <= cur.val and p != prev:\n                p = p.next\n            if p != prev:\n                prev.next = cur.next\n                cur.next = p.next\n                p.next = cur\n            prev = cur\n            cur = cur.next\n\n        return dummy.next\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/148._sort_list.md",
    "content": "###148. Sort List\n\n题目:\n<https://leetcode.com/problems/sort-list/>\n\n\n难度:\nMedium\n\nMergeSort\n\nmerge sort是必备，divide & conquer的入门之物。\n\nmerge sort做两件事， sort 和 merge。\n\n看一看标准伪码：\n\n```\nfunction mergesort(m)\n   var list left, right, result\n   if length(m) ≤ 1\n       return m\n   else\n       var middle = length(m) / 2\n       for each x in m up to middle - 1\n           add x to left\n       for each x in m at and after middle\n           add x to right\n       left = mergesort(left)\n       right = mergesort(right)\n       if last(left) ≤ first(right) \n          append right to left\n          return left\n       result = merge(left, right)\n       return result\n\nfunction merge(left,right)\n   var list result\n   while length(left) > 0 and length(right) > 0\n       if first(left) ≤ first(right)\n           append first(left) to result\n           left = rest(left)\n       else\n           append first(right) to result\n           right = rest(right)\n   if length(left) > 0 \n       append rest(left) to result\n   if length(right) > 0 \n       append rest(right) to result\n   return result\n```\n\n另一处获得伪码\n\n```\nMergeSort(arr[], l,  r)\nIf r > l\n     1. Find the middle point to divide the array into two halves:  \n             middle m = (l+r)/2\n     2. Call mergeSort for first half:   \n             Call mergeSort(arr, l, m)\n     3. Call mergeSort for second half:\n             Call mergeSort(arr, m+1, r)\n     4. Merge the two halves sorted in step 2 and 3:\n             Call merge(arr, l, m, r)\n```\n\n\nmerge sort用在linked list上的好处是不用开辟空间，然后就处理node\n\n用旧的代码拼装出来的结果\n\n然后需要注意的一点是拆分链表，所以有设置left node 的tail为None的操作.\n\n```\nclass Solution(object):\n    def sortList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if head == None or head.next == None:\n            return head\n\n        mid = self.findMid(head)\n        # split the \n        l1 = head\n        l2 = mid.next\n        mid.next = None\n\n        l1 = self.sortList(l1)\n        l2 = self.sortList(l2)\n\n        return self.mergeTwoLists(l1, l2)\n\n    def mergeTwoLists(self, l1, l2):\n        \"\"\"\n        :type l1: ListNode\n        :type l2: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if l1 == None:\n            return l2\n        if l2 == None:\n            return l1\n        \n        dummy = ListNode(-1)\n        cur = dummy\n        \n        while l1 and l2:\n            if l1.val < l2.val:\n                cur.next = l1\n                l1 = l1.next\n            else:\n                cur.next = l2\n                l2 = l2.next\n            cur = cur.next\n        \n        if l1:\n            cur.next = l1\n        else:\n            cur.next = l2\n        return dummy.next\n\n    def findMid(self,head):\n        if head == None or head.next == None:\n            return head\n\n        slow = head\n        fast = head\n\n        while fast.next and fast.next.next:\n            slow = slow.next\n            fast = fast.next.next\n        \n        return slow\n\n```"
  },
  {
    "path": "docs/leetcode/python/150._evaluate_reverse_polish_notation.md",
    "content": "###150. Evaluate Reverse Polish Notation\n\n\n\n题目:\n<https://leetcode.com/problems/evaluate-reverse-polish-notation/>\n\n\n难度:\nMedium\n\n\n\nAC代码\n\n```\nclass Solution(object):\n    def evalRPN(self, tokens):\n        \"\"\"\n        :type tokens: List[str]\n        :rtype: int\n        \"\"\"\n        def cal(op, op1, op2):\n            if op == '*':\n                return op1 * op2\n            elif op == '/':\n                return op1 / float(op2)\n            elif op == '+':\n                return op1 + op2 \n            else:\n                return op1 - op2\n\n        operandStack = []\n\n        for token in tokens:\n            if token in '+-*/':\n                op2 = operandStack.pop()\n                op1 = operandStack.pop()\n                res = cal(token, op1, op2)\n                operandStack.append(int(res))\n            else:\n                operandStack.append(int(token)) \n\n        return operandStack.pop()\n```\n\n\n实际上这里有一个很奇（sha）怪（bi）的地方，看到了么，除法➗处，如果我不这么做，就是错的，这是python 2 和 python 3 的除法不一致导致的，所以最终我这样做了才能得到正确答案。\n\n思路：\n\n已经给了我们wikipedia的链接了<https://en.wikipedia.org/wiki/Reverse_Polish_notation>\n\n- While there are input tokens left\n\t- Read the next token from input.\n\t- If the token is a value\n\t\t- Push it onto the stack.\n\t-Otherwise, the token is an operator (operator here includes both operators and functions).\n\t\t- It is already known that the operator takes n arguments.\n\t\t- If there are fewer than n values on the stack\n\t\t\t- (Error) The user has not input sufficient values in the expression.\n\t\t- Else, Pop the top n values from the stack.\n\t\t- Evaluate the operator, with the values as arguments.\n\t\t- Push the returned results, if any, back onto the stack.\n- If there is only one value in the stack\n\t- That value is the result of the calculation.\n- Otherwise, there are more values in the stack\n\t- (Error) The user input has too many values.\n\n\n\n再参考这里\n\n<http://interactivepython.org/runestone/static/pythonds/BasicDS/InfixPrefixandPostfixExpressions.html>\n\n\n1. Create an empty stack called operandStack.\n2. Convert the string to a list by using the string method split.\n3. Scan the token list from left to right.\n\t- If the token is an operand, convert it from a string to an integer and push the value onto the operandStack.\n\t- If the token is an operator, *, /, +, or -, it will need two operands. Pop the operandStack twice. The first pop is the second operand and the second pop is the first operand. Perform the arithmetic operation. Push the result back on the operandStack.\n4. When the input expression has been completely processed, the result is on the stack. Pop the operandStack and return the value.\n\n"
  },
  {
    "path": "docs/leetcode/python/151._reverse_words_in_a_string.md",
    "content": "### 151. Reverse Words in a String\n\n题目:\n<https://leetcode.com/problems/reverse-words-in-a-string/>\n\n\n难度:\nMedium\n\n太简单了\n\n```python\nclass Solution(object):\n    def reverseWords(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        tmp = s.split()\n        res = \" \".join(tmp[::-1])\n        return res\n        \n```\n\n```python\nclass Solution(object):\n    def reverseWords(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        tmp = s.split()\n        tmp.reverse()\n        res = \" \".join(tmp)\n        return res\n        \n```\n"
  },
  {
    "path": "docs/leetcode/python/152._maximum_product_subarray.md",
    "content": "###152. Maximum Product Subarray\n\n\n\n题目:\n<https://leetcode.com/problems/maximum-product-subarray/>\n\n\n难度:\nMedium\n\n思路：\n\n粗一看， 一股浓烈的DP气息飘来，想要套用53题的思路和方程。但是这个跟sum是不一样的，因为乘积可以正负正负的跳，这样的动归方程肯定是不对的\n\ndp[i] = max(dp[i-1] * a[i],a[i])\n\n举个例子 ： [-2,3,-4]\n\n\n用O(N^2)超时,厉害啊！\n\n想，可不可以记录+的和-的，记录两个dp数组，我哭了，真的是这样做的\n\n最大值可能来源于最小值 -> 哲学般的句子\n\n```\nclass Solution(object):\n    def maxProduct(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(nums)\n        maxdp = [ nums[0] for i in range(n)]\n        mindp = [ nums[0] for i in range(n)]\n\n\n        for i in range(1,n):\n        \tmaxdp[i] = max(mindp[i-1]*nums[i], maxdp[i-1]*nums[i],nums[i])\n        \tmindp[i] = min(maxdp[i-1]*nums[i], mindp[i-1]*nums[i],nums[i])\n\n        return max(maxdp)\n```\n"
  },
  {
    "path": "docs/leetcode/python/153._find_minimum_in_rotated_sorted_array.md",
    "content": "###153. Find Minimum in Rotated Sorted Array\n\n\n题目:\n<https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/>\n\n\n难度:\n\nMedium\n\n\n\n思路一：\n\nO(N) 就不说了\n\n思路二：\n\n想的是分治，两段分别找出最小值，然后取最小值,但是依旧没有利用题目特性，并且也是O(N).\n\n> We can do it in O(logn) using Binary Search. If we take a closer look at above examples, we can easily figure out following pattern: The minimum element is the only element whose previous element is greater than it. If there is no such element, then there is no rotation and first element is the minimum element. \n\n\n上面提到了一个特性，就是minimum element唯一一个它之前的element比它大的，如果不存在这个element，那么就没有rotation.\n\n\n\n思路其实是判断前半部分或者后半部分是否有序，然后来剔除，这里需要注意有比较多的边界case，因为如果就两个，那么会有特殊case 0 ,1 mid = 0,所以可以看一下，它这个处理，最后一个elif 是来比较mid 和 end\n\n\n\n\n\n```\nclass Solution(object):\n    def findMin(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        def findRotatedMin(nums, start, end):\n            if end < start:\n                return nums[0]\n            if start == end:\n                return nums[start]\n            mid = (start + end) / 2\n            if mid > start and nums[mid] < nums[mid-1]:\n                return nums[mid]\n            elif mid < end and nums[mid+1] < nums[mid]:\n                return nums[mid+1]\n            elif nums[mid] < nums[end]:\n                return findRotatedMin(nums,start, mid -1)\n            return findRotatedMin(nums, mid+1, end)\n\n\n        return findRotatedMin(nums,0,len(nums)-1)\n\n```\n\n非递归\n\n```\nclass Solution(object):\n    def findMin(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        l,r = 0, len(nums) - 1\n        while l < r:\n            mid = (l+r) / 2\n            if mid > l and nums[mid] < nums[mid-1]:\n                return nums[mid]\n            elif mid < r and nums[mid] > nums[mid+1]:\n                return nums[mid+1]\n            elif nums[mid] < nums[r]:\n                r = mid -1\n            else:\n                l = mid +1\n        return nums[0]\n\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/155._min_stack.md",
    "content": "### 155. Min Stack\n\n题目:\n<https://leetcode.com/problems/min-stack/>\n\n\n难度:\n\nEasy\n\n思路一：\n\n懒，直接用系统的数据结构\n用lst和系统的heapq，提升一下，用deque和heapq,这样也没太大提升\n\n\n```python\nfrom heapq import *\n\nclass MinStack(object):\n\n    def __init__(self):\n        \"\"\"\n        initialize your data structure here.\n        \"\"\"\n        self.lst = []\n        self.h = []\n        \n\n    def push(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: void\n        \"\"\"\n        self.lst.append(x)\n        heappush(self.h,x)\n\n\n    def pop(self):\n        \"\"\"\n        :rtype: void\n        \"\"\"\n        val = self.lst.pop()\n        self.h.remove(val)\n        heapify(self.h)\n\n    def top(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.lst[-1]\n        \n\n    def getMin(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.h[0]\n\n```\n\n思路二：\n\n\n参考<http://www.geeksforgeeks.org/design-and-implement-special-stack-data-structure/>\n\n用两个stack，其中一个始终来记录到当前位置的最小值\n\n\n```\nWhen we insert 18, both stacks change to following.\nActual Stack\n18 <--- top     \nAuxiliary Stack\n18 <---- top\n\nWhen 19 is inserted, both stacks change to following.\nActual Stack\n19 <--- top     \n18\nAuxiliary Stack\n18 <---- top\n18\n\nWhen 29 is inserted, both stacks change to following.\nActual Stack\n29 <--- top     \n19\n18\nAuxiliary Stack\n18 <---- top\n18\n18\n\nWhen 15 is inserted, both stacks change to following.\nActual Stack\n15 <--- top     \n29\n19 \n18\nAuxiliary Stack\n15 <---- top\n18\n18\n18\n\nWhen 16 is inserted, both stacks change to following.\nActual Stack\n16 <--- top     \n15\n29\n19 \n18\nAuxiliary Stack\n15 <---- top\n15\n18\n18\n18\n```\n\n这样无论是用deque还是本身的lst都有一些提升\n\n\n```python\nfrom collections import deque\nclass MinStack(object):\n\n    def __init__(self):\n        \"\"\"\n        initialize your data structure here.\n        \"\"\"\n        self.lst = deque()\n        self.aux = deque()\n        \n\n    def push(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: void\n        \"\"\"\n        self.lst.append(x)\n        if not self.aux or self.aux[-1] > x:\n            self.aux.append(x)\n        else:\n            self.aux.append(self.aux[-1])\n\n\n\n    def pop(self):\n        \"\"\"\n        :rtype: void\n        \"\"\"\n        self.lst.pop()\n        self.aux.pop()\n\n    def top(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.lst[-1]\n        \n\n    def getMin(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.aux[-1]\n```\n"
  },
  {
    "path": "docs/leetcode/python/157._Read_N_Characters_Given_Read4.md",
    "content": "# 157. Read N Characters Given Read4 最长有效括号\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/read-n-characters-given-read4\n\n> 内容描述\n\n```\nThe API: int read4(char *buf) reads 4 characters at a time from a file.\n\nThe return value is the actual number of characters read. For example, it returns 3 if there is only 3 characters left in the file.\n\nBy using the read4 API, implement the function int read(char *buf, int n) that reads n characters from the file.\n\nExample 1:\n\nInput: buf = \"abc\", n = 4\nOutput: \"abc\"\nExplanation: The actual number of characters read is 3, which is \"abc\".\nExample 2:\n\nInput: buf = \"abcde\", n = 5 \nOutput: \"abcde\"\nNote:\nThe read function will only be called once for each test case.\n```\n\n## 解题方案\n\n> 思路 1\n\n讨论区有很多人说这道题很sb，给的例子和代码里面的input数据类型不一样，其实我也很懵逼\n然后我看到了这个解释，顿悟\n```\nIt took me several hours to understand what the problem is talking about.\n\nLet's look at the very first sentence of the description, \"The API: int read4(char *buf) reads 4 characters at a time from a file.\" I though this function read a file, which is represented by *buf. But I was wrong. The correct understanding should be like this: this function reads a file, and writes the first 4 characters to *buf, and if there are less than 4 characters to be read, then only the valid number of characters will be read and written to *buf.\n\nSimilarly, the function to be implemented, int read(char buf, int n) that reads n characters from the file, means n characters should be written to *buf.\n\nAlso the examples are very misleading. Let's say example 1,\nInput: buf = \"abc\", n = 4\nOutput: \"abc\"\nExplanation: The actual number of characters read is 3, which is \"abc\".\nThe input *buf is not \"abc\". The file to be read is \"abc\". The input, *buf , should be where the characters are written to. The output, is not the return value of read(buf, 4), but should be the actual characters in *buf after the function is called. And the return value should be an int, which is 3.\n\nHope this clarification helps :) \n```\n\n\n总结一下，就是```read4(*read4_buf)```这个函数的意思就是从文件当中读4个字符并将其写入到read4_buf中去，返回值是实际读取到的字符个数，即如果文件中只剩3个（不到4个字符了）\n，那么就只写3个字符到read4_buf中去，返回值是3\n\n所以我们要实现的read(*buf)函数也是这样，我们要读取n个字符并写入到buf中去并且返回实际读取到的字符个数，如果不够我们就有多少写多少，然后返回实际写入的个数\n\n\n那么现在我们有两种情况：\n\n- n大于文件中的字符数，我们检测文件结束并停止读取并返回文件中的字符数。\n- n小于或等于文件中的字符数，当读取足够的字符时返回（即n）\n\n代码中用eof代表'end of file'\n\n\n```python\nclass Solution(object):\n    def read(self, buf, n):\n        \"\"\"\n        :type buf: Destination buffer (List[str])\n        :type n: Maximum number of characters to read (int)\n        :rtype: The number of characters read (int)\n        \"\"\"\n        if n == 0 :\n            return 0\n        total_read, eof = 0, False\n        while not eof:\n            read4_buf = [''] * 4\n            cur_read = read4(read4_buf)\n            if (cur_read < 4):\n                eof = True\n            for i in range(cur_read):\n                buf[total_read] = read4_buf[i]\n                total_read += 1\n                if total_read == n:\n                    return total_read\n        return total_read\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md",
    "content": "# 158. Read N Characters Given Read4 II - Call multiple times\n\n**<font color=red>难度: 困难</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times\n\n> 内容描述\n\n```\nThe API: int read4(char *buf) reads 4 characters at a time from a file.\n\nThe return value is the actual number of characters read. For example, it returns 3 if there is only 3 characters left in the file.\n\nBy using the read4 API, implement the function int read(char *buf, int n) that reads n characters from the file.\n\nNote:\nThe read function may be called multiple times.\n\nExample 1: \n\nGiven buf = \"abc\"\nread(\"abc\", 1) // returns \"a\"\nread(\"abc\", 2); // returns \"bc\"\nread(\"abc\", 1); // returns \"\"\nExample 2: \n\nGiven buf = \"abc\"\nread(\"abc\", 4) // returns \"abc\"\nread(\"abc\", 1); // returns \"\"\n```\n\n## 解题方案\n\n> 思路 1\n\n这个题目的描述就是一坨屎💩，真的，sb。\n\n我来总结一下，跟第157题不一样的地方就是，157是就读一次，158是可以读好几次\n例如：\n文件是‘abcdefg’\n- 157题就读一次，给一个n就行了。n给1那buf就是‘a’, n给2那buf就是‘ab’\n- 但是158不一样，可以多次read，比如第一次n给1，那buf是‘a’，再read一次，n给2，那'a'已经读过了，所以现在buf是'bc'了，\n如果再来个n=3的话，buf就是‘def’,\n\n总之就是一个test case 中read函数可以调用一次和调用多次的区别\n\n```python\nclass Solution(object):\n    head, tail, buffer = 0, 0, [''] * 4 ## 定义全局变量\n    \n    def read(self, buf, n):\n        \"\"\"\n        :type buf: Destination buffer (List[str])\n        :type n: Maximum number of characters to read (int)\n        :rtype: The number of characters read (int)\n        \"\"\"\n        i = 0\n        while i < n:\n            if self.head == self.tail: ## read4 的缓存区为空的时候\n                self.head = 0\n                self.tail = read4(self.buffer) ## 开始进缓存区\n                if self.tail == 0:\n                    break\n            while i < n and self.head < self.tail:\n                buf[i] = self.buffer[self.head] ## 读出缓存区的变量\n                i += 1\n                self.head += 1\n        return i\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md",
    "content": "### 159. Longest Substring with At Most Two Distinct Characters\n\n题目： \n<https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/>\n\n\n难度 : Hard\n\n\n\n```python\nclass Solution(object):\n    def lengthOfLongestSubstringTwoDistinct(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        maps = {}\n        begin, end, counter, length = 0, 0, 0, 0\n        while end < len(s):\n            maps[s[end]] = maps.get(s[end], 0) + 1\n            if maps[s[end]] == 1:\n                counter += 1\n            end += 1   # end 永远指向下一个待处理的字符\n            while counter > 2:\n                maps[s[begin]] -= 1\n                if maps[s[begin]] == 0:\n                    counter -= 1\n                begin += 1\n            length = max(length, end - begin) # 因此这里是```end - begin```而不是```end - begin + 1```\n        return length\n```\n"
  },
  {
    "path": "docs/leetcode/python/160._intersection_of_two_linked_lists.md",
    "content": "### 160. Intersection of Two Linked Lists\n\n题目:\n<https://leetcode.com/problems/intersection-of-two-linked-lists/>\n\n\n难度:\n\nEasy\n\n\n如果两个linkedlist有intersection的话，可以看到，其实如果一开始我们就走到b2的话，那么我们就可以两个pointer一个一个的对比，到哪一个地址一样，接下来就是intersection部分。\n\n\n\n```\nA:          a1 → a2\n                   ↘\n                     c1 → c2 → c3\n                   ↗            \nB:     b1 → b2 → b3\n```\n比较巧妙的数学解法，看下面的解释和代码\n\n\n\nAC代码如下:\n\n```python\nclass Solution(object):\n    def getIntersectionNode(self, headA, headB):\n        \"\"\"\n        :type head1, head1: ListNode\n        :rtype: ListNode\n        \"\"\"\n        pA, pB = headA, headB\n        while pA is not pB:\n            pA = pA.next if pA else headB\n            pB = pB.next if pB else headA\n        return pA\n```\nJust count the number of moves by each pointer before they meet. One pointer will traverse entire list1 for N moves and then jump to the head of list1 to move (M-K) steps to intersection, where K represents the length of common part. Now the other pointer must also moved the same number of steps since they are both moved at the same time. The second pointer traverses the entire list2 for M steps and jumped to the head of list1 to move (N-K) steps. So the loop finished with M+N-K times.\n详见[zzg_zzm的评论](https://leetcode.com/problems/intersection-of-two-linked-lists/discuss/49799)\n\nThis algorithm is sooooo perfect!\n\nI was wonder if the running time is O(n+m), but later I figured out that the actually running time is just:\n\n- m+n for non-intersection case\n\nWith intersection:\n\n- Suppose for LL-A, it’s a+b=n, a is the # of nodes before intersection\n\n- Suppose for LL-B, it’s c+b=m, c is the # of nodes before intersection\n\nThus the actual running time is a+b+c = n+c = m+a.\n\nActually, when b=0, this just stands for the case with no intersection with a+b+c=n+m\n"
  },
  {
    "path": "docs/leetcode/python/162._find_peak_element.md",
    "content": "### 162. Find Peak Element\n\n题目:\n<https://leetcode.com/problems/find-peak-element/>\n\n\n难度:\nMedium\n\n\n思路：\n\n\n最直观的是O(N)解法\n\n```python\nclass Solution(object):\n    def findPeakElement(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        for i in range(1, len(nums)):\n            if nums[i] < nums[i-1]:\n                return i-1\n        return len(nums) - 1 \n```\n\nO(lgN) 解法\n\n这是一个经典题目\n\n- a[mid] < a[mid] only look at the left side\n- a[mid] < a[mid] only look at the right side\n- else peak found\n\n\n证明就是用反证法，或者看peak，因为这里已经限制了num[i] ≠ num[i+1]，所以peak element 一定存在。然后a[mid] < a[mid-1],那么说明这里一定是下降的，说明之前一定有一个peak存在，否则我们可以用反证法证明.\n\n写到这里，我非常相信就是binary search能写对其实不容易。\n\n\nAC代码\n\n```python \nclass Solution(object):\n    def findPeakElement(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        l, r = 0, len(nums) - 1\n        while l <= r:\n        \tif l == r : return l\n        \tmid = l + ((r - l) >> 2)\n        \tif nums[mid] < nums[mid+1]:\n        \t\tl = mid + 1\n        \telse:\n        \t\tr = mid\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/165._compare_version_numbers.md",
    "content": "###165. Compare Version Numbers\n\n题目:\n<https://leetcode.com/problems/compare-version-numbers/>\n\n\n难度:\n\nEasy\n\n\n其实我并不觉得这个很简单\n\n因为可能两个的位数不一样，首端或者尾端需要补0，同时我还考虑过可能有出现多个'.'的状况\n\n\n\n```\nclass Solution(object):\n    def compareVersion(self, version1, version2):\n        \"\"\"\n        :type version1: str\n        :type version2: str\n        :rtype: int\n        \"\"\"\n        v1 = version1.split('.')\n        v2 = version2.split('.')\n        v1 = [int(x) for x in v1]\n        v2 = [int(x) for x in v2]\n        \n        len1 = len(v1)\n        len2 = len(v2)\n        lenMax = max(len1, len2)\n        for x in range(lenMax):\n            v1Token = 0\n            if x < len1:\n                v1Token = v1[x]\n            v2Token = 0\n            if x < len2:\n                v2Token = v2[x]\n            if v1Token > v2Token:\n                return 1\n            elif v1Token < v2Token:\n                return -1\n        return 0\n                \n```\n"
  },
  {
    "path": "docs/leetcode/python/166._Fraction_to_Recurring_Decimal.md",
    "content": "### 166. Fraction to Recurring Decimal\n\n题目:\n<https://leetcode.com/problems/fraction-to-recurring-decima/>\n\n\n难度:\n\nMedium\n\n\n\n\n```python\nclass Solution:\n    # @return a string\n    def fractionToDecimal(self, n, d):\n        res = ''\n        if n == 0: # zero numerator\n            return str(n)\n        if (n < 0) ^ (d < 0): # determine the sign\n            res += '-'\n        n = abs(n) # remove sign of operands\n        d = abs(d) \n        res += str(n / d) # append integral part\n        if (n % d == 0): # in case no fractional part\n            return res\n        res += '.'\n        r = n % d\n        m = {}\n        while r: # simulate the division process\n            if r in m: # meet a known remainder\n                res = res[:m[r]] + '(' + res[m[r]:] + ')' # so we reach the end of the repeating part\n                break\n            m[r] = len(res) # if the remainder is first seen, remember the current position for it\n            r *= 10\n            res += str(r / d) # append the quotient digit\n            r %= d\n        return res\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/167._two_sum_ii_-_input_array_is_sorted.md",
    "content": "### 167. Two Sum II - Input array is sorted\n\n\n\n题目:\n<https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/>\n\n\n难度:\nMedium\n\n\n思路：\n\n\n双指针\n\n```python\nclass Solution(object):\n    def twoSum(self, numbers, target):\n        \"\"\"\n        :type numbers: List[int]\n        :type target: int\n        :rtype: List[int]\n        \"\"\"\n        l, r = 0, len(numbers) - 1\n        while l < r:\n            if numbers[l] + numbers[r] == target:\n                return [l+1, r+1]\n            elif numbers[l] + numbers[r] > target:\n                r -= 1\n            else:\n                l += 1\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/168._excel_sheet_column_title.md",
    "content": "###168. Excel Sheet Column Title\n\n题目:\n\n<https://leetcode.com/problems/excel-sheet-column-title/>\n\n\n难度:\n\nEasy\n\n依旧26进制的反击，不过这个反击我做的没之前那个好，看了hint\n\n```\nclass Solution(object):\n    def convertToTitle(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: str\n        \"\"\"\n        ans = ''\n        while n :\n            ans = chr(ord('A') + (n - 1) % 26) + ans\n            n = (n - 1) // 26\n        return ans\n        \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/169._majority_element.md",
    "content": "###169. Majority Element\n\n\n\n题目:\n<https://leetcode.com/problems/majority-element/>\n\n\n难度:\nEasy\n\n思路：\n\n其实这个我有点有想到过\n \n \n给定一个长度为 n的数组,其中有一个数，它出现的次数大于⎣n/2⎦，称为主要元素，找到它.\n\n这个很像之前做过的一道CLRS的题目，想法可以用divide & conquer.\n\n\n- 如果数组长度 <= 2,那么return第一个即解决问题\n- 如果长度 > 2，那么可以两两配对，对于配对一样的结果，删去\n \t- 如果最后余一个，这一个留下\n \t- shuffle之后再尝试两两配对，直到最后结果不再改变\n\n 这样肯定是能解决问题的，因为为了满足次数大于⎣n/2⎦这个条件。\n \n \n\n\n\n\n```\n\n\t 1 2        1 2          1 2         1 2\n\t 2 3        2 3          2 3         2 3\n\t 2          4 2          2 2         2 3\n\t\t\t\t2             4 2        3 3\n\t\t\t\t\t\t\t\t\t\t  3 2\n\t\t\t\t\t\t\t\t\t\t  2 2\n\t\t\t\t\t\t\t\t\t\t  2 2\n``` \n\n思路容易implement非常难啊.\n\n\n\n这个问题有一个很出名的算法\n\n\nBoyer-Moore众数(majority number) 问题\n\n在数组中找到两个不相同的元素并删除它们，不断重复此过程，直到数组中元素都相同，那么剩下的元素就是主要元素。\n\n\n这个算法的妙处在于不直接删除数组中的元素，而是利用一个计数变量.\n\n伪码\n\n\tdef majorityElement(self, nums):\n\t    count,major=0,0\n\t    for n in nums:\n\t        if count==0:\n\t            major=n\n\t        if major==n:\n\t            count+=1\n\t        else:\n\t            count-=1\n\t    return major\n\t \n \n \n "
  },
  {
    "path": "docs/leetcode/python/171._excel_sheet_column_number.md",
    "content": "###171. Excel Sheet Column Number\n\n题目:\n\n<https://leetcode.com/problems/excel-sheet-column-number/>\n\n\n难度:\n\nEasy\n\n\n26进制的反击\n\n```\nclass Solution(object):\n    def titleToNumber(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        maps = {}\n        for i in range(65,91):\n            maps[chr(i)] = i - 64\n        \n        lst = list(s)\n        lst.reverse()\n        num = 0\n        for idx,item in enumerate(lst):\n            num += maps[item] * (26 ** idx)\n        return num\n        \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/173._binary_search_tree_iterator.md",
    "content": "### 173. Binary Search Tree Iterator\n\n题目:\n<https://leetcode.com/problems/binary-search-tree-iterator/>\n\n\n难度:\nMedium\n\n\n同样没有听题目要求，一开始就取巧，用InOrder，这样得到BSF有序排列，然后使用\n\n\n```python\n\nclass BSTIterator(object):\n    def __init__(self, root):\n        \"\"\"\n        :type root: TreeNode\n        \"\"\"\n        self.root = root\n        self.lst = []\n        self.inOrder(root)\n        self.lst.reverse()\n            \n        \n\n    def hasNext(self):\n        \"\"\"\n        :rtype: bool\n        \"\"\"\n        return self.lst != []\n        \n\n    def next(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.lst.pop()\n    \n    def inOrder(self, root):\n        if root == None:\n            return\n        self.inOrder(root.left)\n        self.lst.append(root.val)\n        self.inOrder(root.right)\n        \n```\n\n谷歌了一下，得到如何满足题目要求的hint，从root开始，往左走，把左孩子压入stack，直到左边为空。\n\n然后开始取node，如果node有右孩子，则同样要把node的右孩子的所有左孩子全部append入stack，画了一个图，可行。\n\n\n\n\n\n```python\n\nclass BSTIterator(object):\n    def __init__(self, root):\n        \"\"\"\n        :type root: TreeNode\n        \"\"\"\n        self.root = root\n        self.stack = []\n        self.pushAllLeft(root)\n        \n\n    def hasNext(self):\n        \"\"\"\n        :rtype: bool\n        \"\"\"\n        return self.stack != []\n        \n\n    def next(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        if self.hasNext():\n            cur = self.stack.pop()\n            if cur.right:\n                self.pushAllLeft(cur.right)\n            return cur.val\n            \n    def pushAllLeft(self, node):\n        \"\"\"\n        :type node: TreeNode\n        \"\"\"\n        cur = node\n        while cur:\n            self.stack.append(cur)\n            cur = cur.left\n```\n"
  },
  {
    "path": "docs/leetcode/python/179._Largest_Number.md",
    "content": "### 179. Largest Number\n\n题目:\n<https://leetcode.com/problems/largest-number/>\n\n\n难度:\n\nMedium\n\n\n思路\n\n先排序，再合并，若最后为空字符串，则返回'0'\n\n其中排序思想为字符串的经典比较：\n```\n    \"\"\"\n    Replacement for built-in funciton cmp that was removed in Python 3\n\n    Compare the two objects x and y and return an integer according to\n    the outcome. The return value is negative if x < y, zero if x == y\n    and strictly positive if x > y.\n    \"\"\"\n```\n\n```python\nclass Solution(object):\n    def largestNumber(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: str\n        \"\"\"\n        nums = [str(num) for num in nums]\n        nums.sort(cmp=lambda x, y: cmp(y+x, x+y))\n        return ''.join(nums).lstrip('0') if ''.join(num).lstrip('0') else '0'\n```\n或者更简单一点\n\n```python\nclass Solution(object):\n    def largestNumber(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: str\n        \"\"\"\n        nums = [str(num) for num in nums]\n        nums.sort(cmp=lambda x, y: cmp(y+x, x+y))\n        return ''.join(nums).lstrip('0') or '0'\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/182._duplicate_emails.md",
    "content": "# 182. duplicate-emails 查找重复的电子邮箱\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/duplicate-emails\n* https://leetcode-cn.com/problems/duplicate-emails\n\n> 内容描述\n\n```\n编写一个 SQL 查询，查找 Person 表中所有重复的电子邮箱。\n\n示例：\n+----+---------+\n| Id | Email   |\n+----+---------+\n| 1  | a@b.com |\n| 2  | c@d.com |\n| 3  | a@b.com |\n+----+---------+\n\n根据以上输入，你的查询应返回以下结果：\n+---------+\n| Email   |\n+---------+\n| a@b.com |\n+---------+\n\n说明：所有电子邮箱都是小写字母。\n```\n\n## 解题方案\n\n> 思路 1\n\n```sql\nselect Email\nfrom Person\ngroup by Email\nhaving count(1)>1\n```\n或者\n```sql\nselect Email from Person group by Email having count(Email) > 1\n```\n"
  },
  {
    "path": "docs/leetcode/python/189._rotate_array.md",
    "content": "###189. Rotate Array\n\n题目： \n<https://leetcode.com/problems/rotate-array/>\n\n\n难度 : Easy\n\n首先，要知道一点，```k```如果大于```nums```的长度了，那么其实进行 ```k % len(nums)``` 次就行了\n\n其次，要注意```k 为0```的情况\n\n```python\nclass Solution(object):\n    def rotate(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        k = k % len(nums)\n        if k != 0:\n            tmp = nums[-k:]\n            for j in range(len(nums)-1, k-1, -1):\n                nums[j] = nums[j-k]\n            nums[:k] = tmp\n```\n\n\n还有作弊大法，贼🐂批\n\n```python\nclass Solution(object):\n    def rotate(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        k %= len(nums)\n        nums[:] = nums[-k:] + nums[:-k]\n```\n"
  },
  {
    "path": "docs/leetcode/python/191._number_of_1_bits.md",
    "content": "### 191. Number of 1 Bits\n\n题目:\n\n<https://leetcode.com/problems/number-of-1-bits/>\n\n\n难度:\n\nEasy\n\n\n转成二进制，数1的个数\n\n```python\nclass Solution(object):\n    def hammingWeight(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        return bin(n).count('1')\n```\n\n\n\n有wikipedia的题目 [Hamming Weight]((https://zh.wikipedia.org/wiki/汉明重量))\n\n\n\n用wikipedia的解法：\n\n原理是在于每次使用x & x-1 总会把低位的数字给置0\n\n比如 3 = 011  2 = 010  3 & 2 = 010 cnt =1\n\n​\t2 = 010  1 = 001  2 & 1 = 000 cnt = 2\n\n比如 9 = 1001  8 = 1000  9&8 = 1000 cnt =1\n\n​\t8 = 1000  7 = 0111  8&7 = 0000 cnt = 2\n\n> 减1操作将最右边的符号从0变到1，从1变到0，与操作将会移除最右端的1。如果最初X有N个1，那么经过N次这样的迭代运算，X将减到0。下面的算法就是根据这个原理实现的。\n\n所以关键点是每次都会把最右边的1变成0.\n\n \n\nAC代码\n\n\n\n```python\nclass Solution(object):\n    def hammingWeight(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        cnt = 0\n        while n != 0:\n        \tn &= n - 1\n        \tcnt += 1\n        return cnt \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/198._house_robber.md",
    "content": "\n### 198. House Robber\n\n\n题目:\n<https://leetcode.com/problems/house-robber/>\n\n\n难度:\n\nEasy\n\n\n状态转移方程:\n\ndp[i] = max(dp[i-1], dp[i-2] + nums[i])\n\n\nAC 代码\n\n```python\nclass Solution(object):\n    def rob(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(nums)\n        if n == 0 : return 0\n        elif n == 1 : return nums[0]\n        elif n == 2 : return max(nums[0], nums[1])\n        else:\n            dp = [0 for i in range(n)]\n            dp[0] = nums[0]\n            dp[1] = max(nums[0],nums[1])\n            for i in range(2,n):\n                dp[i] = max( dp[i-1], dp[i-2] + nums[i])\n        return dp[n-1]\n```\n\n```python\nclass Solution(object):\n    def rob(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        last, now = 0, 0\n        for i in nums: last, now = now, max(last + i, now)     \n        return now\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/199._binary_tree_right_side_view.md",
    "content": "###199. Binary Tree Right Side View\n\n题目:\n\n<https://leetcode.com/problems/binary-tree-right-side-view/>\n\n\n难度:\n\nMedium\n\n\n还是在玩第102题，level order traversal.\n\n```\nclass Solution(object):\n    def rightSideView(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[int]\n        \"\"\"\n        if root == None: return []\n      \n        res = []\n        curLevel = [root]\n        while curLevel:\n            nextLevel = []\n            tmpRes = []\n            for node in curLevel:\n                tmpRes.append(node.val)\n                if node.left: nextLevel.append(node.left)\n                if node.right: nextLevel.append(node.right)\n            res.append(tmpRes[-1])\n            curLevel = nextLevel\n        return res\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/200._number_of_islands.md",
    "content": "### 200. Number of Islands \n\n\n题目:\n<https://leetcode.com/problems/number-of-islands/>\n\n\n难度:\nMedium\n\n\n思路：\n\n\n一开始：\nnumberOfIslands = 0\nislandArea = []\n\n\n然后遇到（x,y） = 1的状况，更新numberOfIslands，并且把（x,y）放入islandArea，然后用BFS或者DFS查找岛屿范围，全部更如islandArea，做loop\n\n以上就是基本思路\n\n\n然后超时|||, 小改之后AC\n\n\n```\n\nclass Solution(object):\n    def numIslands(self, grid):\n        \"\"\"\n        :type grid: List[List[str]]\n        :rtype: int\n        \"\"\"\n        self.grid = grid[:]\n\n        self.row = len(self.grid)\n        self.col = len(self.grid[0]) if self.row else 0\n        self.visited = [[0 for i in range(self.col)]for j in range(self.row)]\n\n\n        self.numberOfIslands = 0\n\n        for i in range(self.row):\n        \tfor j in range(self.col):\n        \t\tif self.grid[i][j] == '1' and self.visited[i][j] == 0:\n        \t\t\t\tself.findArea(i,j)\n        \t\t\t\tself.numberOfIslands += 1\n\n        return self.numberOfIslands\n\n    def findArea(self, i, j):\n    \ts = []\n    \ts.append((i,j))\n    \twhile s:\n    \t\t(x,y) = s.pop()\n    \t\tself.visited[x][y] = 1\n    \t\tif self.legal(x-1,y):\n    \t\t\ts.append((x-1,y))\n    \t\tif self.legal(x+1,y):\n    \t\t\ts.append((x+1,y))\n    \t\tif self.legal(x,y-1):\n    \t\t\ts.append((x,y-1))\n    \t\tif self.legal(x,y+1):\n    \t\t\ts.append((x,y+1))\n\n    def legal(self,x,y):\n    \treturn x>= 0 and x < self.row and y >= 0 and y < self.col and self.grid[x][y] == '1' and self.visited[x][y] == 0\na = Solution()\nprint a.numIslands([\"11000\",\"11000\",\"00100\",\"00011\"])\n\n```\n\n\n看了别人的代码，写的真美 ╮(╯_╰)╭ 啊\n\n```\nclass Solution(object):\n    def numIslands(self, grid):\n        \"\"\"\n        :type grid: List[List[str]]\n        :rtype: int\n        \"\"\"\n        def dfs(gird, used, row, col, x, y):\n            if gird[x][y] == '0' or used[x][y]:\n                return \n            used[x][y] = True\n\n            if x!= 0:\n                dfs(grid, used, row,col, x-1,y)\n            if x!= row -1 :\n                dfs(grid, used, row,col, x+1, y)\n            if y!= 0:\n                dfs(grid, used, row,col, x, y-1)\n            if y!= col - 1:\n                dfs(grid, used, row,col, x, y+1)\n\n\n        row = len(grid)\n        col = len(grid[0]) if row else 0\n\n        used = [[0 for i in xrange(col)] for i in xrange(row)]\n\n        count = 0\n        for i in xrange(row):\n            for j in xrange(col):\n                if grid[i][j] == '1' and not used[i][j]:\n                    dfs(grid,used,row,col,i,j)\n                    count += 1\n        return count\n```\n\n厉害的解法：Sink and count the islands.\n```python\nclass Solution(object):\n    def numIslands(self, grid):\n        \"\"\"\n        :type grid: List[List[str]]\n        :rtype: int\n        \"\"\"\n        def sink(i, j):\n            if 0 <= i < len(grid) and 0 <= j < len(grid[0]) and grid[i][j] == '1':\n                grid[i][j] = '0'\n                map(sink, (i+1, i-1, i, i), (j, j, j+1, j-1))\n                return 1\n            return 0\n        return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[0])))\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/203._remove_linked_list_elements.md",
    "content": "###203. Remove Linked List Elements\n\n题目:\n<https://leetcode.com/problems/remove-linked-list-elements/>\n\n\n难度:\n\nEasy\n\n\nAC代码如下:\n\n\n\n```\nclass Solution(object):\n    def removeElements(self, head, val):\n        \"\"\"\n        :type head: ListNode\n        :type val: int\n        :rtype: ListNode\n        \"\"\"\n        dummy = ListNode(-1)\n        dummy.next = head\n    \n        cur = dummy\n    \n        while cur.next:\n            if cur.next.val == val:\n                cur.next = cur.next.next\n            else:\n                cur = cur.next\n    \n        return dummy.next\n            \n                \n```"
  },
  {
    "path": "docs/leetcode/python/204._count_primes.md",
    "content": "###204. Count Primes\n\n\n题目:\n<https://leetcode.com/problems/count-primes/>\n\n\n难度:\n\nEasy\n\n\n\n这个题的hint是已经把算法喂到嘴边了\n\n<https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes>\n\n\n```\nInput: an integer n > 1\n \nLet A be an array of Boolean values, indexed by integers 2 to n,\ninitially all set to true.\n \nfor i = 2, 3, 4, ..., not exceeding √n:\n  if A[i] is true:\n    for j = i^2, i^2+i, i^2+2*i, i^2+3i, ..., not exceeding n :\n      A[j] := false\n \nOutput: all i such that A[i] is true.\n```\n\n\n\npython算法\n\n\n```\nclass Solution(object):\n    def countPrimes(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        isPrime = [1 for i in range(n)]\n\n        i = 2\n        while i * i < n:\n        \tif isPrime[i]:\n        \t\tj = i * i \n        \t\twhile j < n :\n        \t\t\tisPrime[j] = 0\n        \t\t\tj += i\n        \ti += 1\n\n        return sum(isPrime[2:])\n```"
  },
  {
    "path": "docs/leetcode/python/205._isomorphic_strings.md",
    "content": "###205. Isomorphic Strings\n\n题目： \n<https://leetcode.com/problems/isomorphic-strings/>\n\n\n难度 : Easy\n\n\nAC之法，用dictionary，因为限制，所以确保s 和 t 是isomorphic 同时 t 和 s 是\n\n\n```\nclass Solution(object):\n    def isIsomorphic(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: bool\n        \"\"\"\n        return self.iso(s,t) and self.iso(t,s)\n        \n    def iso(self,s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: bool\n        \"\"\"\n        mapx = {}\n        for i in range(len(s)):\n            if s[i] not in mapx:\n                mapx[s[i]] = t[i]\n            elif s[i] in mapx:\n                if t[i] != mapx[s[i]]:\n                    return False\n        return True\n            \n            \n```\n"
  },
  {
    "path": "docs/leetcode/python/206._reverse_linked_list.md",
    "content": "### 206. Reverse Linked List\n\n题目:\n<https://leetcode.com/problems/reverse-linked-list/>\n\n\n难度:\nEasy\n\n用三个指针，分别指向prev，cur 和 nxt，然后loop一圈还算比较简单.\n\n\n\n\n```python\nclass Solution(object):\n    def reverseList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        prev = None \n        cur = head\n        while(cur):\n            nxt = cur.next\n            cur.next = prev\n            prev = cur\n            cur = nxt\n        return prev\n```\n其实一个指针就够了\n```python\nclass Solution(object):\n    def reverseList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if not head:\n            return head\n        prev = None\n        while head.next:\n            tmp = head.next\n            head.next = prev\n            prev = head\n            head = tmp\n        head.next = prev  \n        return head\n```\n\n递归版本，可以再消化一下.\n\n\n```python\nclass Solution(object):\n    def reverseList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        return self.reverseHelper(head, None)\n    \n    def reverseHelper(self, head, new_head):\n        if not head:\n            return new_head\n        nxt = head.next\n        head.next = new_head\n        return self.reverseHelper(nxt, head)\n```\n"
  },
  {
    "path": "docs/leetcode/python/207._course_schedule.md",
    "content": "###207. Course Schedule\n\n\n\n题目:\n<https://leetcode.com/problems/course-schedule/>\n\n\n难度:\nMedium\n\n思路：\n\n就是考topological sort，用来判断directed graph是否有cycle\n\nDFS 和 BFS都可以用来拓扑排序。\n\n最简单的想法是每次取出indegree是0的node，然后把它和与之相关的edge都删了。一开始觉得这样的时间复杂度会很高，然后看到了这样写，参照：\n\n<http://bookshadow.com/weblog/2015/05/07/leetcode-course-schedule/>\n\n很聪明的写法\n\n这里做了转成set以及添加removeList这样的操作是因为边list边做iterator这样的操作很危险\n\n\n\n\n```\nclass Solution(object):\n    def canFinish(self, numCourses, prerequisites):\n        \"\"\"\n        :type numCourses: int\n        :type prerequisites: List[List[int]]\n        :rtype: bool\n        \"\"\"\n        degrees = [ 0 for i in range(numCourses)]\n        childs = [[] for i in range(numCourses)]\n        for front, tail in prerequisites:\n        \tdegrees[front] += 1\n        \tchilds[tail].append(front)\n\n        courses = set(range(numCourses))\n        flag = True\n\n        while flag and len(courses):\n        \tflag = False\n        \tremoveList = []\n        \tfor x in courses:\n        \t\tif degrees[x] == 0:\n        \t\t\tfor child in childs[x]:\n        \t\t\t\tdegrees[child] -= 1\n        \t\t\tremoveList.append(x)\n        \t\t\tflag = True\n        \tfor x in removeList:\n        \t\tcourses.remove(x)\n        return len(courses) == 0 \n\n```\n\n因为CLRS里面明确提到涂色法来处理DFS\n\n搞了半天，写了一个涂色法，在超时的边缘。之所以超时边缘是因为每次都要去prerequisites里看，没有删减，不高效.\n\n```\nclass Solution(object):\n    def canFinish(self, numCourses, prerequisites):\n        \"\"\"\n        :type numCourses: int\n        :type prerequisites: List[List[int]]\n        :rtype: bool\n        \"\"\"\n        def dfs(i, colors, prerequisites):\n        \tcolors[i] = 'G'\n        \t#print i, colors\n        \tfor front, tail in prerequisites:\n        \t\tif tail == i:\n        \t\t\tif colors[front] == 'G':\n        \t\t\t\treturn False\n        \t\t\telif colors[front] == 'B':\n        \t\t\t\tcontinue\n        \t\t\telif dfs(front, colors, prerequisites) == False:\n        \t\t\t\treturn False\n        \tcolors[i] = 'B'\n        \treturn True\n\n        colors = ['W' for i in range(numCourses)]\n        for i in range(numCourses):\n        \tif colors[i] == 'W':\n        \t\tif dfs(i, colors, prerequisites) == False:\n        \t\t\treturn False\n        return True\n```\n"
  },
  {
    "path": "docs/leetcode/python/208._implement_trie_(prefix_tree).md",
    "content": "### 208. Implement Trie (Prefix Tree)\n\n题目:\n\n<https://leetcode.com/problems/implement-trie-prefix-tree/>\n\n\n难度:\n\nMedium\n\n这个Python实现也太精美了吧，谷歌复写之\n\n然后还unlock了一个solution，to read\n\nTrie整个都需要 to read，精美，可爱😊\n\n\n\n\n```python\nclass TrieNode(object):\n    def __init__(self):\n        \"\"\"\n        Initialize your data structure here.\n        \"\"\"\n        self.childs = dict()\n        self.isWord = False\n        \n        \n\nclass Trie(object):\n\n    def __init__(self):\n        self.root = TrieNode()\n\n    def insert(self, word):\n        \"\"\"\n        Inserts a word into the trie.\n        :type word: str\n        :rtype: void\n        \"\"\"\n        node = self.root\n        for letter in word:\n            child = node.childs.get(letter)\n            if child is None:\n                child = TrieNode()\n                node.childs[letter] = child\n            node = child\n        node.isWord = True\n\n    def search(self, word):\n        \"\"\"\n        Returns if the word is in the trie.\n        :type word: str\n        :rtype: bool\n        \"\"\"\n        node = self.root\n        for i in word:\n            child = node.childs.get(i)\n            if child is None:\n                return False\n            node = child\n        return node.isWord\n        \n\n    def startsWith(self, prefix):\n        \"\"\"\n        Returns if there is any word in the trie\n        that starts with the given prefix.\n        :type prefix: str\n        :rtype: bool\n        \"\"\"\n        node = self.root\n        for letter in prefix:\n            child = node.childs.get(letter)\n            if child is None:\n                return False\n            node = child\n        return True\n        \n\n# Your Trie object will be instantiated and called as such:\n# trie = Trie()\n# trie.insert(\"somestring\")\n# trie.search(\"key\")\n        \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/210._course_schedule_ii.md",
    "content": "###210. Course Schedule II\n\n\n\n题目:\n<https://leetcode.com/problems/course-schedule-ii/>\n\n\n难度:\nMedium\n\n思路：\n\n在207的基础上加了order，进击\n\n\n```\nclass Solution(object):\n    def findOrder(self, numCourses, prerequisites):\n        \"\"\"\n        :type numCourses: int\n        :type prerequisites: List[List[int]]\n        :rtype: List[int]\n        \"\"\"\n        degrees = [ 0 for i in range(numCourses)]\n        childs = [[] for i in range(numCourses)]\n        for front, tail in prerequisites:\n        \tdegrees[front] += 1\n        \tchilds[tail].append(front)\n\n\n        courses = set(range(numCourses))\n        flag = True\n        order = []\n\n        while flag and len(courses):\n        \tflag = False\n        \tremoveList = []\n        \tfor x in courses:\n        \t\tif degrees[x] == 0:\n        \t\t\tprint x\n        \t\t\tfor child in childs[x]:\n        \t\t\t\tdegrees[child] -= 1\n        \t\t\tremoveList.append(x)\n        \t\t\torder.append(x)\n        \t\t\tflag = True\n        \tfor x in removeList:\n        \t\tcourses.remove(x)\n\n        if len(courses) == 0:\n        \treturn order\n        else:\n        \treturn []\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/211._Add_and_Search_Word_-_Data_structure_design.md",
    "content": "### 211. Add and Search Word - Data structure design\n\n题目:\n\n<https://leetcode.com/problems/add-and-search-word-data-structure-design/>\n\n难度： Medium\n\n思路：\n\ntrie也是树，那么dfs/bfs同样适用。\n\n实际上是照抄208trie的题目再加上dfs\n\n\n\nAC代码\n\n\n\n```\nclass TrieNode(object):\n    \"\"\"docstring for TrieNode\"\"\"\n    def __init__(self):\n        self.childs = dict()\n        self.isWord = False\n        \nclass WordDictionary(object):\n    def __init__(self):\n        \"\"\"\n        initialize your data structure here.\n        \"\"\"\n        self.root = TrieNode()\n        \n\n    def addWord(self, word):\n        \"\"\"\n        Adds a word into the data structure.\n        :type word: str\n        :rtype: void\n        \"\"\"\n        node = self.root\n        for letter in word:\n            child = node.childs.get(letter)\n            if child is None:\n                child = TrieNode()\n                node.childs[letter] = child\n            node = child\n        node.isWord = True\n        \n\n    def search(self, word):\n        \"\"\"\n        Returns if the word is in the data structure. A word could\n        contain the dot character '.' to represent any one letter.\n        :type word: str\n        :rtype: bool\n        \"\"\"\n        def dfs(root, word):\n            if len(word) == 0:\n                return root.isWord\n            elif word[0] == '.':\n                for node in root.childs:\n                    if dfs(root.childs[node], word[1:]):\n                        return True\n                return False\n            else:\n                node = root.childs.get(word[0])\n                if node is None:\n                    return False\n                return dfs(node, word[1:])\n\n        return dfs(self.root, word)\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/213._house_robber_ii.md",
    "content": "###213. House Robber II\n\n\n题目:\n<https://leetcode.com/problems/house-robber-ii/>\n\n\n难度:\nMedium\n\n思路：\n\n跟house robber 1 类似，但是加了一些限制，抢到第 n-1 家最大两种可能，抢第 n-1 家和不抢第 n-1 家。\n\n\t0，\t1， 2， 3， 4， 5， 6 ... n-1\n\n\n所以状态转移方程写成二维的更好来求，从第i家抢到第j家的状态转移方程\n\n\n\t\t\t\tnums[j] ,j = i\n\tdp[i][j] = max(nums[i], nums[i+1]) , j = i +1\n\t\t\t\tmax(dp[i][j-2] + nums[j], dp[i][j-1]), j > i+1\n\t\t\t\t\n\t\t\t\t\n\nShow me the code \n\n\nAC代码\n\n```\nclass Solution(object):\n    def rob(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(nums)\n        if n == 0 : return 0\n        if n == 1 : return nums[0]\n        if n == 2 : return max(nums[0],nums[1])\n        \n        dp = [[0 for i in range(n)] for j in range(n)]\n\n        for i in range(n):\n            for j in range(i,n):\n                if j == i:\n                    dp[i][j] = nums[j]\n                elif j == i + 1:\n                    dp[i][j] = max(nums[i],nums[i+1])\n                else:\n                    dp[i][j] = max(dp[i][j-2] + nums[j], dp[i][j-1])\n\n        # print dp \n        # rob without n-1, or rob with  n-1\n        val = max(dp[0][n-2], dp[1][n-3] + nums[n-1])\n\n        return val\n\n```"
  },
  {
    "path": "docs/leetcode/python/216._combination_sum_iii.md",
    "content": "###216. Combination Sum III\n\n题目:\n\n<https://leetcode.com/problems/combination-sum-iii/>\n\n\n难度:\n\nMedium\n\n继续Combination Sum 系列\n\n\n```\nclass Solution(object):\n    def combinationSum3(self, k, n):\n        \"\"\"\n        :type k: int\n        :type n: int\n        :rtype: List[List[int]]\n        \"\"\"\n        candidates = [1,2,3,4,5,6,7,8,9]\n        self.res = []\n        self.combSum(candidates, n, [], k)\n        return self.res\n        \n        \n    def combSum(self,candidates, target, valueList, k):\n        if target == 0 and k == 0:\n            self.res.append(valueList)\n        length = len(candidates)\n        if length == 0 or k < 0 :\n            return \n        for i in range(length):\n            if candidates[i] > target:\n                return\n            self.combSum(candidates[i+1:], target - candidates[i], valueList + [candidates[i]], k-1)\n            \n```"
  },
  {
    "path": "docs/leetcode/python/217._contains_duplicate.md",
    "content": "#  217. Contains Duplicate\n**<font color=red>难度: 简单</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/contains-duplicate/\n\n> 内容描述\n\n```\n\nGiven an array of integers, find if the array contains any duplicates.\n\nYour function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.\n\nExample 1:\n\nInput: [1,2,3,1]\nOutput: true\nExample 2:\n\nInput: [1,2,3,4]\nOutput: false\nExample 3:\n\nInput: [1,1,1,3,3,4,3,2,4,2]\nOutput: true\n```\n\n## 解题方案\n\n> 思路 1\n\n利用set怎么可以这么简单。。。。\n\n\n```python\nclass Solution(object):\n    def containsDuplicate(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        return len(nums) != len(set(nums))\n```\n\n\n> 思路 2\n\n或者先 sort 也可以\n\n```python\nclass Solution(object):\n    def containsDuplicate(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        nums.sort()\n        for i in range(len(nums)-1):\n            if nums[i] == nums[i+1]:\n                return True\n        return False\n```\n"
  },
  {
    "path": "docs/leetcode/python/218._The_Skyline_Problem.md",
    "content": "### 218. The Skyline Problem\n\n题目:\n<https://leetcode.com/problems/The-Skyline-Problem/>\n\n\n难度:\n\nHard\n\n思路\n\n观察发现，skyline的points的横坐标一定是某个building的左边界或者右边界。\n\n开始，假设只有2个建筑物，拿出第一个buiding B1，我们先把它的左上顶点加进我们的output结果skyline中，然后继续拿下一个building B2，我们现在需要将B2的左上顶点对应的x coordinate与B1的右上顶点所对应的x coordinate做比较：\n\n- 如果前者小且B2的高度大于B1的高度，则我们将B2的左上顶点也加入skyline中去。\n- 如果前者小且B2的高度小于等于B1的高度，则忽略B2的左上顶点\n\n接下来考虑更多建筑物的情况，从左到右扫描，当我们遇到第一个楼的左边界时，把它push到一个heap中。如果后面扫描的楼的高度比heap中最高的楼还高，那么它的左上顶点一定会被加入到skyline中。当我们遇到一个building的右边界时,我们需要将其从heap中pop掉，如果heap中max height有变化，则push到结果中。\n\n参考[Brian Gordon的blog](https://briangordon.github.io/2014/08/the-skyline-problem.html)\n  和  [Stefan大神的题解](https://leetcode.com/problems/the-skyline-problem/discuss/61194)\n\n#### 程序代码解释\n\n- liveBuildings代表（左上顶点已经被加入output中但右上顶点还没有做判断的building）的右上顶点的集合，形式为[(height, x-coordinate)…..]\n- skyline是output\n- 程序里面的这句代码```while idx < n and buildings[idx][0] == start:```是为了防止有左右坐标完全相同但是height不同的building的存在，it's not useless!!!\n- python里面的heapq模块如果有不懂的同学可以看看这个文章：[heapq](http://blog.csdn.net/calling_wisdom/article/details/41676133)\n\n\n```python\nclass Solution(object):\n    def getSkyline(self, buildings):\n        \"\"\"\n        :type buildings: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        idx, n = 0, len(buildings)\n        liveBuildings, skyline = [], []\n        while idx < n or len(liveBuildings) > 0: # 只要所有的点没处理完就一直循环\n            if len(liveBuildings) == 0 or (idx < n and buildings[idx][0] <= -liveBuildings[0][1]):\n                start = buildings[idx][0]\n                while idx < n and buildings[idx][0] == start:\n                    heapq.heappush(liveBuildings, [-buildings[idx][2], -buildings[idx][1]])\n                    idx += 1\n            else:\n                start = -liveBuildings[0][1]\n                while len(liveBuildings) > 0 and -liveBuildings[0][1] <= start:\n                    heapq.heappop(liveBuildings)\n            height = len(liveBuildings) and -liveBuildings[0][0]\n            if len(skyline) == 0 or skyline[-1][1] != height:\n                skyline.append([start, height])\n        return skyline\n```\n#####另外还有一个超级6的大神的代码，但是今天我要赶报告，就只先贴代码了\n\n```python\nclass Solution(object):\n    def getSkyline(self, buildings):\n        \"\"\"\n        :type buildings: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        events = sorted([(L, -H, R) for L, R, H in buildings] + list(set((R, 0, None) for L, R, H in buildings)))\n        #events = sorted(event for L, R, H in buildings for event in ((L, -H, R), (R, 0, None)))\n        res, hp = [[0, 0]], [(0, float(\"inf\"))]\n        for x, negH, R in events:\n            while x >= hp[0][1]: \n                heapq.heappop(hp)\n            if negH: heapq.heappush(hp, (negH, R))\n            if res[-1][1] + hp[0][0]: \n                res += [x, -hp[0][0]],\n        return res[1:]\n```\n\n```Java\npublic class Solution {\n    public List<int[]> getSkyline(int[][] buildings) {\n        List<int[]> result = new ArrayList<int[]>();\n        if (buildings == null || buildings.length == 0 || buildings[0].length == 0) {\n            return result;\n        }\n        \n        List<Height> heights = new ArrayList<Height>();\n        for (int[] building : buildings) {\n            heights.add(new Height(building[0], -building[2]));\n            heights.add(new Height(building[1], building[2]));\n        }\n        Collections.sort(heights, new Comparator<Height>() {\n            @Override\n            public int compare(Height h1, Height h2) {\n                return h1.index != h2.index ? h1.index - h2.index : h1.height - h2.height;\n            }\n        });\n        \n        PriorityQueue<Integer> pq = new PriorityQueue<Integer>(1000, Collections.reverseOrder());\n        pq.offer(0);\n        int prev = 0;\n        for (Height h : heights) {\n            if (h.height < 0) {\n                pq.offer(-h.height);\n            } else {\n                pq.remove(h.height);\n            }\n            int cur = pq.peek();\n            if (cur != prev) {\n                result.add(new int[]{h.index, cur});\n                prev = cur;\n            }\n        }\n        \n        return result;\n    }\n    \n    class Height {\n        int index;\n        int height;\n        Height(int index, int height) {\n            this.index = index;\n            this.height = height;\n        }\n    }\n}\n```\n\n\n\nAuthor: Keqi Huang\n\nIf you like it, please spread your support\n\n![Support](/img/Algorithm/LeetCode/WechatIMG17.jpeg)\n"
  },
  {
    "path": "docs/leetcode/python/219._contains_duplicate_ii.md",
    "content": "#  219. Contains Duplicate II\n**<font color=red>难度: 简单</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/contains-duplicate-ii/\n\n> 内容描述\n\n```\nGiven an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the absolute difference between i and j is at most k.\n\nExample 1:\n\nInput: nums = [1,2,3,1], k = 3\nOutput: true\nExample 2:\n\nInput: nums = [1,0,1,1], k = 1\nOutput: true\nExample 3:\n\nInput: nums = [1,2,3,1,2,3], k = 2\nOutput: false\n```\n\n## 解题方案\n\n> 思路 1\n\n\n这道题虽然看似简单，但是我还是经历几次失败\n\n第一次我打算用最粗暴的方法来做，直接  Time Limit Exceeded，代码如下：\n```\nclass Solution(object):\n    def containsNearbyDuplicate(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: bool\n        \"\"\"\n        if k == 0:\n            return False\n        if k >= len(nums):\n            return len(nums) != len(set(nums))\n        for i in range(len(nums)-k):\n            for j in range(1, k+1):\n                if nums[i] == nums[i+j]:\n                    return True\n        for i in range(len(nums)-k, len(nums)):\n            for j in range(i+1, len(nums)):\n                if nums[i] == nums[j]:\n                    return True\n        return False\n```\n然后我打算用第 217 题的方法来一遍，还是报  Time Limit Exceeded  这个错，代码如下L：\n```\nclass Solution(object):\n    def containsNearbyDuplicate(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: bool\n        \"\"\"\n        if k == 0:\n            return False\n        if k >= len(nums):\n            return len(nums) != len(set(nums))\n        for i in range(len(nums)-k):\n            if len(nums[i:i+k+1]) != len(set(nums[i:i+k+1])):\n                return True\n        return len(nums[-k:]) != len(set(nums[-k:]))\n```\n\n终于我想到了用字典来存，这个元素还没出现过，就以 <num, index> 的形式存进字典里，如果 num 再次出现了，计算相邻距离，小于等于 k 则 return true，否则更新字典中元素的位置，\n\n\n```python\nclass Solution(object):\n    def containsNearbyDuplicate(self, nums, k):\n        \"\"\"\n        :type nums: List[int]\n        :type k: int\n        :rtype: bool\n        \"\"\"\n        lookup = {}\n        for i in range(len(nums)):\n            if nums[i] not in lookup:\n                lookup[nums[i]] = i\n            else:\n                if i - lookup[nums[i]] <= k:\n                    return True\n                else:\n                    lookup[nums[i]] = i\n        return False\n```\n"
  },
  {
    "path": "docs/leetcode/python/221._maximal_square.md",
    "content": "###221. Maximal Square\n\n\n题目:\n<https://leetcode.com/problems/maximal-square/>\n\n\n难度:\nMedium\n\ntag： DP\n\n\n递推公式，一开始想的很简单：\n\ndp[i][j] = dp[i-1][j-1] + 1 #如果dp[i-1][j-1]为1，dp[i-1][j]为1，dp[i][j-1]为1\n\n很明显的错误，一旦遇到更大的方块就会有问题\n\n然后看了hint，其实递推方程式是很有技巧的，左上角，左边，上面，相邻的三个部分最小的+1,当然，前提也是要这里dp[i][j] 为1，然后我们再会去看其他的部分。\n\n看个例子\n\n```\n原本的matrix                     DP\n\n1 0 1 0 0                     1 0 1 0 0\n1 0 1 1 1            →        1 0 1 1 1 \n1 1 1 1 1                     1 1 1 2 2\n1 0 0 1 0                     1 0 0 1 0\n\n```\n\n是非常make sense的，因为最小的必定包括了周边的1，然后再加1，否则如果是0的话那么就为0.\n\n而naïve的错误的递推公式是因为一个square考虑的部分是k * k的部分， k * k 部分都必定为1.\n\n而正确的递推公式\n\n\n\tdp[i][j] = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) + 1\n\n则完美的考虑了这一情况\n\n\n```\nclass Solution(object):\n\tdef maximalSquare(self, matrix):\n\t\t\"\"\"\n\t\t:type matrix: List[List[str]]\n\t\t:rtype: int\n\t\t\"\"\"\n\t\tdp = []\n\t\tfor i in matrix:\n\t\t\ttmp = []\n\t\t\tfor j in i:\n\t\t\t\ttmp.append(int(j))\n\t\t\tdp.append(tmp)\n\n\t\trow = len(dp)\n\t\tcol = len(dp[0]) if row else 0\n\n\n\t\tfor i in range(1,row):\n\t\t\tfor j in range(1,col):\n\t\t\t\tif dp[i][j] == 1:\n\t\t\t\t\tdp[i][j] = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) + 1\n\n\n\t\tmaxv = 0\n\t\tfor i in range(row):\n\t\t\tfor j in range(col):\n\t\t\t\tif dp[i][j] > maxv:\n\t\t\t\t\tmaxv = dp[i][j]\n\t\treturn maxv * maxv\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/222._count_complete_tree_nodes.md",
    "content": "###222. Count Complete Tree Nodes\n\n题目:\n<https://leetcode.com/problems/count-complete-tree-nodes/>\n\n\n难度:\nMedium\n\n\n思路：\n\n\n思路一： 超时，跟一般的树一样，递归的来数nodes数\n\n\n\n```\nclass Solution(object):\n    def countNodes(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if root == None:\n        \treturn 0\n        if root.left == None and root.right == None:\n        \treturn 1\n        return 1 + self.countNodes(root.left) + self.countNodes(root.right)\n```\n\n\n思路二：既然说了是 complete binary tree，那么必然有特性可用，complete binary tree的特性是除了最后一层，之前的就是perfect tree.\n\n\n所以寻找左子树的最左边的高度和右子树的最右边的node高度，如果相同就是perfect tree，高度2^h - 1， 否则递归的来看左子树和右子树\n\n\n```\n\nclass Solution(object):\n    def countNodes(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        if root == None:\n        \treturn 0\n        \n        p, q = root,root\n\n        leftHeight = 0\n        rightHeight = 0\n\n        while p:\n        \tp = p.left\n        \tleftHeight += 1\n\n        while q:\n        \tq = q.right\n        \trightHeight += 1\n\n        if leftHeight == rightHeight:\n        \treturn (int)(math.pow(2,leftHeight) - 1)\n        else:\n        \treturn 1 + self.countNodes(root.left) + self.countNodes(root.right)\n```"
  },
  {
    "path": "docs/leetcode/python/223._rectangle_area.md",
    "content": "#  223. Rectangle Area\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/rectangle-area\n\n> 内容描述\n\n```\nFind the total area covered by two rectilinear rectangles in a 2D plane.\n\nEach rectangle is defined by its bottom left corner and top right corner as shown in the figure.\n\nRectangle Area\n\nExample:\n\nInput: A = -3, B = 0, C = 3, D = 4, E = 0, F = -1, G = 9, H = 2\nOutput: 45\nNote:\n\nAssume that the total area is never beyond the maximum possible value of int.\n```\n\n## 解题方案\n\n> 思路 1\n\nsb题没什么好说的\n\n```python\nclass Solution(object):\n    def computeArea(self, A, B, C, D, E, F, G, H):\n        \"\"\"\n        :type A: int\n        :type B: int\n        :type C: int\n        :type D: int\n        :type E: int\n        :type F: int\n        :type G: int\n        :type H: int\n        :rtype: int\n        \"\"\"\n        return (C - A) * (D - B) + (H - F) * (G - E) - max(min(C, G) - max(A, E), 0) * max(min(D, H) - max(B, F), 0)\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/224._Basic_Calculator.md",
    "content": "### 224. Basic Calculator \n\n\n\n题目:\n<https://leetcode.com/problems/basic-calculator/>\n\n难度:\nMedium\n\n思路：\n\n基本跟227一样，只是这里加了括号\n\n瞄了一眼，基本上infix(中缀表达式)都是表达成postfix(后缀表达式)再来求值的。\n比如 A + B * C 写成 A B C * +\n\n| Infix Expression | Prefix Expression | Postfix Expression |\n| ---------------- | ----------------- | ------------------ |\n| A + B            | + A B             | A B +              |\n| A + B * C        | + A * B C         | A B C * +          |\n\n\n\ninfix 中缀转postfix 后缀还有专门的算法：<https://en.wikipedia.org/wiki/Shunting-yard_algorithm>\n\n\n\n1. Create an empty stack called opstack for keeping operators. Create an empty list for output.\n\n2. Convert the input infix string to a list by using the string method split.\n\n3. Scan the token list from left to right.\n\n4. - If the token is an operand, append it to the end of the output list.\n   - If the token is a left parenthesis, push it on the opstack.\n   - If the token is a right parenthesis, pop the opstack until the corresponding left parenthesis is removed. Append each operator to the end of the output list.\n   - If the token is an operator, *, /, +, or -, push it on the opstack. However, first remove any operators already on the opstack that have higher or equal precedence and append them to the output list.\n\n5. When the input expression has been completely processed, check the opstack. Any operators still on the stack can be removed and appended to the end of the output list.\n\n\n\n可以看到中缀转后缀一个重要的点是： 当我们把operator +-*/ 放到opstack上时候，我们需要考虑/看是否有之前的operator有更高或者相等的precedence，这个时候我们需要优先（计算）把它放到output list.\n\n\n\n参考\n\n<http://interactivepython.org/runestone/static/pythonds/BasicDS/InfixPrefixandPostfixExpressions.html>\n\n\n\nAC代码\n\n```\nclass Solution(object):\n    def calculate(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        def precedence(op):\n            if op == '*' or op == '/':\n                return 2\n            else:\n                return 1\n\n        def cal(op, op1, op2):\n            if op == '*':\n                return op1 * op2\n            elif op == '/':\n                return op1 / float(op2)\n            elif op == '+':\n                return op1 + op2 \n            else:\n                return op1 - op2\n\n\n        opstack = []\n        operands = []\n\n        # remove empty space and put operands and \n        idx = 0\n        for i in range(idx, len(s)):\n            if s[i] in '+-*/':\n                operands.append(s[idx:i])\n                while len(opstack) > 0 and precedence(s[i]) <= precedence(opstack[-1]) and len(operands) >= 2:\n                    op = opstack.pop()\n                    op2 = int(operands.pop())\n                    op1 = int(operands.pop())\n                    res = cal(op, op1, op2)\n                    operands.append(res)\n                opstack.append(s[i])\n                idx = i + 1\n        operands.append(s[idx:])\n\n        while opstack:\n             op = opstack.pop()\n             op2 = int(operands.pop())\n             op1 = int(operands.pop())\n             res = cal(op, op1, op2)\n             operands.append(res)\n\n        return int(operands[0])\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/225._implement_stack_using_queues.md",
    "content": "###225. Implement Stack using Queues\n\n题目:\n\n<https://leetcode.com/problems/implement-stack-using-queues/>\n\n\n难度:\n\nEasy\n\n\n又到了作弊神预言Python的强项\n\n\n```\nclass Stack(object):\n    def __init__(self):\n        \"\"\"\n        initialize your data structure here.\n        \"\"\"\n        self.lst = []\n        \n\n    def push(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: nothing\n        \"\"\"\n        self.lst.append(x)\n        \n\n    def pop(self):\n        \"\"\"\n        :rtype: nothing\n        \"\"\"\n        self.lst.remove(self.lst[-1])\n        \n\n    def top(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.lst[-1]\n\n    def empty(self):\n        \"\"\"\n        :rtype: bool\n        \"\"\"\n        return self.lst == []\n        \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/226._invert_binary_tree.md",
    "content": "### 226. Invert Binary Tree\n\n题目:\n<https://leetcode.com/problems/invert-binary-tree/>\n\n\n难度:\n\nEasy\n\n典型的递归题\n\n\n```python\nclass Solution(object):\n    def invertTree(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if not root:\n            return None\n        self.invertTree(root.left)\n        self.invertTree(root.right)\n        root.left, root.right = root.right, root.left\n        return root\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/227._basic_calculator_ii.md",
    "content": "###227. Basic Calculator II\n\n\n\n题目:\n<https://leetcode.com/problems/basic-calculator-ii/>\n\n\n难度:\nMedium\n\n思路：\n\n瞄了一眼，基本上infix(中缀表达式)都是表达成postfix(后缀表达式)再来求值的。\n比如 A + B * C 写成 A B C * +\n\n\n| Infix Expression | Prefix Expression | Postfix Expression |\n| ---------------- | ----------------- | ------------------ |\n| A + B            | + A B             | A B +              |\n| A + B * C        | + A * B C         | A B C * +          |\n\n\ninfix 中缀转postfix 后缀还有专门的算法：<https://en.wikipedia.org/wiki/Shunting-yard_algorithm>\n\n\n\n1. Create an empty stack called opstack for keeping operators. Create an empty list for output.\n\n2. Convert the input infix string to a list by using the string method split.\n\n3. Scan the token list from left to right.\n\n4. - If the token is an operand, append it to the end of the output list.\n   - If the token is a left parenthesis, push it on the opstack.\n   - If the token is a right parenthesis, pop the opstack until the corresponding left parenthesis is removed. Append each operator to the end of the output list.\n   - If the token is an operator, *, /, +, or -, push it on the opstack. However, first remove any operators already on the opstack that have higher or equal precedence and append them to the output list.\n\n5. When the input expression has been completely processed, check the opstack. Any operators still on the stack can be removed and appended to the end of the output list.\n\n\n\n可以看到中缀转后缀一个重要的点是： 当我们把operator +-*/ 放到opstack上时候，我们需要考虑/看是否有之前的operator有更高或者相等的precedence，这个时候我们需要优先（计算）把它放到output list.\n\n\n\n\n参考\n\n<http://interactivepython.org/runestone/static/pythonds/BasicDS/InfixPrefixandPostfixExpressions.html>\n\n\n\nAC代码\n\n```\nclass Solution(object):\n    def calculate(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        def precedence(op):\n            if op == '*' or op == '/':\n                return 2\n            else:\n                return 1\n\n        def cal(op, op1, op2):\n            if op == '*':\n                return op1 * op2\n            elif op == '/':\n                return op1 / float(op2)\n            elif op == '+':\n                return op1 + op2 \n            else:\n                return op1 - op2\n\n\n        opstack = []\n        operands = []\n\n        # remove empty space and put operands and \n        idx = 0\n        for i in range(idx, len(s)):\n            if s[i] in '+-*/':\n                operands.append(s[idx:i])\n                while len(opstack) > 0 and precedence(s[i]) <= precedence(opstack[-1]) and len(operands) >= 2:\n                    op = opstack.pop()\n                    op2 = int(operands.pop())\n                    op1 = int(operands.pop())\n                    res = cal(op, op1, op2)\n                    operands.append(res)\n                opstack.append(s[i])\n                idx = i + 1\n        operands.append(s[idx:])\n\n        while opstack:\n             op = opstack.pop()\n             op2 = int(operands.pop())\n             op1 = int(operands.pop())\n             res = cal(op, op1, op2)\n             operands.append(res)\n\n        return int(operands[0])\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/228._summary_ranges.md",
    "content": "### 228. Summary Ranges\n\n题目:\n<https://leetcode.com/problems/summary-ranges/>\n\n\n难度:\n\nMedium\n\n\nJust collect the ranges, then format and return them.\n\n```python\nclass Solution(object):\n    def summaryRanges(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[str]\n        \"\"\"\n        ranges = []\n        for i in nums:\n            if not ranges or i > ranges[-1][-1] + 1:\n                ranges += [],\n            ranges[-1][1:] = i,\n        return ['->'.join(map(str, r)) for r in ranges]                           \n```\nAbout the commas :-)\n\n```\nranges += [],\nr[1:] = n,\n```\nWhy the trailing commas? Because it turns the right hand side into a tuple and I get the same effects as these more common alternatives:\n```\nranges += [[]]\nor\nranges.append([])\n\nr[1:] = [n]\n```\nWithout the comma, …\n\n- ranges += [] wouldn’t add [] itself but only its elements, i.e., nothing.\n- r[1:] = n wouldn’t work, because my n is not an iterable.\n\nWhy do it this way instead of the more common alternatives I showed above? Because it’s shorter and faster (according to tests I did a while back).\n\n写到这里可能又有疑问了🤔️，为什么不可以直接写```ranges[-1][1] = i```呢，当然是会报```IndexError: list assignment index out of range```错误啦，那为什么```ranges[-1][1:] = i,```可以呢？\n\n简单来说\n\nL1=L 与 L1=L[:] \n- L1和L  都是对同一个对象的引用（所谓绑定的意思）。\n- L[:]  是生成了一个和L不同的新的对象，L1 变为了L[:] 这个对象的引用。\n\n\n参考[stefan](https://leetcode.com/problems/summary-ranges/discuss/63193)\n"
  },
  {
    "path": "docs/leetcode/python/229._majority_element_ii.md",
    "content": "###229. Majority Element II\n\n\n\n题目:\n<https://leetcode.com/problems/majority-element-ii/>\n\n\n难度:\nMedium\n\n思路：\n\nmajority element是两两比较扔掉不同的元素，然后最后会留下一个。\n\n这里变成三三比较来扔东西, find all elements that appear more than ⌊ n/3 ⌋ times，所以最多可以有两个majority element ii.\n\n\n最后再加一个比较来确认这些函数是majority element\n\n```\nclass Solution(object):\n    def majorityElement(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[int]\n        \"\"\"\n        cnt1 = 0\n        cnt2 = 0\n        maj1 = 0\n        maj2 = 0\n        for num in nums:\n        \tif maj1 == num:\n        \t\tcnt1 += 1\n        \telif maj2 == num:\n        \t\tcnt2 += 1\n        \telif cnt1 == 0:\n        \t\tmaj1 = num\n        \t\tcnt1 += 1\n        \telif cnt2 == 0:\n        \t\tmaj2 = num\n        \t\tcnt2 += 1\n        \telse:\n        \t\tcnt1 -= 1\n        \t\tcnt2 -= 1\n\n        cnt1 = 0\n        cnt2 = 0\n\n        n = len(nums)\n        res = []\n        for num in nums:\n        \tif maj1 == num:\n        \t\tcnt1 += 1\n        \telif maj2 == num:\n        \t\tcnt2 += 1\n        if cnt1 > n/3:\n        \tres.append(maj1)\n        if cnt2 > n/3:\n        \tres.append(maj2)\n        return res\n```"
  },
  {
    "path": "docs/leetcode/python/230._kth_smallest_element_in_a_bst.md",
    "content": "### 230. Kth Smallest Element in a BST\n\n题目:\n<https://leetcode.com/problems/kth-smallest-element-in-a-bst/>\n\n\n难度:\nMedium\n\n\n跟昨天做的一道题类似，一上来就走取巧之路。\n\nInOrder排序，输出，当然也完全可以用昨天的binary tree iterator,入stack,出stack,直到输出第k位\n\n\n```python\nclass Solution(object):\n    def kthSmallest(self, root, k):\n        \"\"\"\n        :type root: TreeNode\n        :type k: int\n        :rtype: int\n        \"\"\"\n        self.root = root\n        self.lst = []\n        self.inOrder(root)\n        return self.lst[k-1]\n\n    def inOrder(self, root):\n        if root == None:\n            return\n        self.inOrder(root.left)\n        self.lst.append(root.val)\n        self.inOrder(root.right)\n```\n\n\n现在看到kth 就条件反射的想用divide & conquer, 扫root的左子树看nodes量，如果nodes数量是k-1，那么node就刚好是第k个，如果大于k > 左子树数量，扫右子树，同时更新root为root.right。\n\n看到的言论：\n\n> If we can change the BST node structure, We can add a new Integer to mark the number of element in the left sub-tree.\n\nwhen the node is not null.\n\n- if k == node.leftNum + 1, return node\n- if k > node.leftNum + 1, make k -= node.leftNum + 1, and then node = node.right\n- otherwise, node = node.left\n"
  },
  {
    "path": "docs/leetcode/python/231._Power_of_Two.md",
    "content": "### 231.  Power of Two\n\n\n\n题目:\n\n<https://leetcode.com/problems/power-of-two/>\n\n难度:\n\nEasy\n\n\n\n思路：\n\n\n\npower of two 那是这个数字的binary 表示一定只有一个1\n\n套用以前的代码[leetcode191](https://github.com/Lisanaaa/thinking_in_lc/blob/master/191._number_of_1_bits.md)\n\n这样会超时\n\n```\nclass Solution(object):\n    def isPowerOfTwo(self, n): # 此法超时\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        cnt = 0\n        while n != 0:\n        \tn &= n - 1\n        \tcnt += 1\n        return cnt == 1\n```\n\n\n\n跟power of three一样递归，可以AC\n\n\n\n```python\nclass Solution(object):\n    def isPowerOfTwo(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        if n <= 0:\n            return False\n        if n == 1:\n            return True\n        if n % 2 == 0:\n            return self.isPowerOfTwo(n/2)\n        return False\n                \t\n```\n\n\n\n\n\n\n\n也是有[算法的wikipedia page](https://en.wikipedia.org/wiki/Power_of_two#Fast_algorithm_to_check_if_a_positive_number_is_a_power_of_two)\n\n> The [binary representation](https://en.wikipedia.org/wiki/Binary_numeral_system) of integers makes it possible to apply a very fast test to determine whether a given [positive integer](https://en.wikipedia.org/wiki/Positive_integer) *x* is a power of two:\n>\n> positive *x* is a power of two ⇔ (*x* & (*x* − 1)) is equal to zero.\n\n\n\n注意特殊case 0的处理\n\n```python\nclass Solution(object):\n    def isPowerOfTwo(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        return n & (n-1) == 0 if n != 0 else False\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/232._implement_queue_using_stacks.md",
    "content": "###232. Implement Queue using Stacks\n\n题目:\n<https://leetcode.com/problems/implement-queue-using-stacks/>\n\n\n难度:\nEasy\n\n这个题没有乖乖听话，不过因为当年做过用两个stack来模拟queue\n\n然后不得不说，我Python大法实在太厉害了\n\n这功能强大的，我简直要啧啧啧\n\n```\nclass Queue(object):\n    def __init__(self):\n        \"\"\"\n        initialize your data structure here.\n        \"\"\"\n        self.lst = []\n        \n\n    def push(self, x):\n        \"\"\"\n        :type x: int\n        :rtype: nothing\n        \"\"\"\n        self.lst.append(x)\n        \n\n    def pop(self):\n        \"\"\"\n        :rtype: nothing\n        \"\"\"\n        del self.lst[0]\n\n    def peek(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        return self.lst[0]\n        \n\n    def empty(self):\n        \"\"\"\n        :rtype: bool\n        \"\"\"\n        return self.lst == []\n```"
  },
  {
    "path": "docs/leetcode/python/234._palindrome_linked_list.md",
    "content": "### 234. Palindrome Linked List\n\n题目:\n<https://leetcode.com/problems/palindrome-linked-list/>\n\n\n难度:\nEasy\n\n蠢了一下，\n\n思路是：“先翻转整个链表（in-place），然后和之前的链表比较”，但是这样原链表都变了，肯定错。\n\n如果新建一个链表，然后改造成原来链表的翻转链表，还是可行的，但是空间复杂度就是O(n)了。那还不如直接把List中元素拷贝到数组中直接比较，ac代码如下：\n\n\n```python\nclass Solution(object):\n    def isPalindrome(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        vals = []\n        while head:\n            vals += head.val,\n            head = head.next\n        return vals == vals[::-1]\n```\n\n这道题并不能算Easy吧：\n\n思路二：\n要想实现O(1)的空间复杂度，可以找到中间的节点，把linked list拆成两个部分，后半部分linkedlist reverse，然后比较两个linked list值是否相同，看例子：\n\n\n```\n1 -> 3 -> 1 拆成 1 和 1\n\n1 -> 3 -> 5 ->5 -> 3 -> 1 拆成 1-> 3 -> 5 和 5 -> 3 -> 1\n\n```\n\n可以使用快慢指针来找到中间的节点。\n\n\n```python\nclass Solution(object):\n    def isPalindrome(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: bool\n        \"\"\"\n        fast = slow = head\n        # 找到中间节点\n        while fast and fast.next:\n            fast = fast.next.next\n            slow = slow.next\n        # 翻转后半部分\n        prev = None\n        while slow:\n            tmp = slow.next\n            slow.next = prev\n            prev = slow\n            slow = tmp\n        # 比较前后两部分\n        while prev: # while prev and head:\n            if prev.val != head.val:\n                return False\n            prev = prev.next\n            head = head.next\n        return True\n```\n\n给个最终状态的例子：\n```\n\n                       fast     tmp\n           None        prev     slow\n            ^           ^        ^\n            |           |        |\n1 --> 2 --> 3 <-- 2 <-- 1       None\n\n```\n但是注意最后的while prev不能换成while fast, 因为这是总节点数为奇数的情况，如果是偶数情况就不一样了，如下：\n```\n                          tmp\n                          slow    \n           None  prev     fast\n            ^     ^        ^\n            |     |        |\n1 --> 2 --> 2 <-- 1       None\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/235._lowest_common_ancestor_of_a_binary_search_tree.md",
    "content": "###235. Lowest Common Ancestor of a Binary Search Tree\n\n题目： \n<https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/>\n\n\n难度 : Easy\n\n- 两个node，一个大于root，一个小于root，那么必定root两边，共同的ancestor是root，同时再考虑同为空的状况\n- 两个node，都比node小，到左边去寻找，那么先找到那个必定是common ancestor\n- 两个node，都比node大，类似....\n\n\nAC解法\n\n```\nclass Solution(object):\n    def lowestCommonAncestor(self, root, p, q):\n        \"\"\"\n        :type root: TreeNode\n        :type p: TreeNode\n        :type q: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if root == None or root == p or root == q:\n            return root\n        elif p.val < root.val < q.val or q.val < root.val < p.val :\n            return root\n        elif p.val < root.val and q.val < root.val:\n            return self.lowestCommonAncestor(root.left,p,q)\n        else:\n            return self.lowestCommonAncestor(root.right,p,q)\n```\n"
  },
  {
    "path": "docs/leetcode/python/236._lowest_common_ancestor_of_a_binary_tree.md",
    "content": "\n###236. Lowest Common Ancestor of a Binary Tree\n\n\n题目:\n<https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/>\n\n\n难度:\n\nMedium\n\n\n\n思路\n\n求root到node的path，然后对比path，最后一个想同的点就是lowest common ancestor\n\n\n\n好开心，AC了\n\n\n但是我根本不能在Runtime Distribution 上找到我，因为太慢了||||\n\n\n\n\n```\n\nclass Solution(object):\n    def lowestCommonAncestor(self, root, p, q):\n        \"\"\"\n        :type root: TreeNode\n        :type p: TreeNode\n        :type q: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        pathP = self.pathTo(root,p)\n        pathQ = self.pathTo(root,q)\n        n = min(len(pathP), len(pathQ))\n\n        ans = root\n        for i in range(n):\n            if pathP[i] == pathQ[i]:\n                ans = pathP[i]\n            else:\n                break\n        return ans\n\n\n    def pathTo(self, root, goal):\n        # goal node ,path\n        if root == None: return root\n        stack = [(root, [root])]\n        while stack:\n            node, path = stack.pop()\n            if node == goal:\n                return path\n            if node.left: stack.append((node.left, path + [node.left]))\n            if node.right: stack.append((node.right, path + [node.right]))\n\n```\n\n递归解法，之所以我没有用递归因为有疑惑, BASE CASE 很容易想到，root 是none，或者p == root 或者q == root,那么LCA就是root，如果两个node一个在左边，一个在右边，那么LCA也是root，但是如果一个是6，另一个是4则有一点疑惑，但其实是没有问题的，因为这个时候给的总是他们的共同root，所以这个递归解法是没错的，总是想到递归是在那个状况下递归\n\n\n```\n        _______3______\n       /              \\\n    ___5__          ___1__\n   /      \\        /      \\\n   6      _2       0       8\n         /  \\\n         7   4\n```\n\nAC代码\n\n\n\n```\nclass Solution(object):\n    def lowestCommonAncestor(self, root, p, q):\n        \"\"\"\n        :type root: TreeNode\n        :type p: TreeNode\n        :type q: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        if root == None:\n            return None\n\n        if p == root or q == root:\n            return root\n\n        left = self.lowestCommonAncestor(self.left,p,q)\n        right = self.lowestCommonAncestor(self.right,p,q)\n\n        if left and right:\n            return root\n\n        return left if left is None else right\n```"
  },
  {
    "path": "docs/leetcode/python/237._delete_node_in_a_linked_list.md",
    "content": "### 237. Delete Node in a Linked List\n\n题目:\n<https://leetcode.com/problems/delete-node-in-a-linked-list/>\n\n\n难度:\nEasy\n\n\n\n这道题，第一感觉，像删链表一样来删，把所有的node val前移一个,但是有个问题，为什么tail那个node还是存在？哼(ˉ(∞)ˉ)唧..\n\n已经被解答：\n\n<http://stackoverflow.com/questions/38879291/python-delete-a-node-in-linked-list-given-just-access-to-that-node>\n\n\n\n另外一个O（1）的办法更好，把后一个node的val移到待删这个节点，并且把node.next = node.next.next\n        \n题目说了不会删最后一个点，所以node.next.next一定存在，所以直接让node的val等于它next的val，然后让node的next指向它的next的next，举个例子：\n        1->2->3->4->5->None,要删除第四个节点，就让4变成5，然后让第四个节点指向第五个节点的next，\n这样原来的第四个节点就不存在了，虽然原来的第五个节点仍然存在且指向None，变成了1->2->3->5->None-<5\n        \n\n\n```python\nO(1)时间\nclass Solution(object):\n    def deleteNode(self, node):\n        \"\"\"\n        :type node: ListNode\n        :rtype: void Do not return anything, modify node in-place instead.\n        \"\"\"\n        node.val = node.next.val\n        node.next = node.next.next\n```\n```python\nO(n)时间\nclass Solution(object):\n    def deleteNode(self, node):\n        \"\"\"\n        :type node: ListNode\n        :rtype: void Do not return anything, modify node in-place instead.\n        \"\"\"\n        while node.next:\n            node.val = node.next.val\n            prev, node = node, node.next\n        # clear reference to tail\n        prev.next = None\n```\n"
  },
  {
    "path": "docs/leetcode/python/238._product_of_array_except_self.md",
    "content": "###238. Product of Array Except Self\n\n题目:\n<https://leetcode.com/problems/product-of-array-except-self/>\n\n\n难度:\n\nMedium\n\n\n不使用division 并且O(n)\n\n\n想到的算法 O(n^2)\n\n会超时\n\n\n```\nclass Solution(object):\n        def productExceptSelf(self,nums):\n            \"\"\"\n            :type nums: List[int]\n            :rtype: List[int]\n            \"\"\"\n            lst = []\n            for i in range(len(nums)):\n                lst.append(self.productWithoutI(nums,i))\n            return lst\n        \n\n        def productWithoutI(self,nums,i):\n            product = 1\n            for j in range(len(nums)):\n                if j != i:\n                    product *= nums[j]\n            return product\n```\n\n如果用除法，也会有问题，如果有0出现也会变繁琐。\n\n谷歌一下：\n\n\n解法还是很棒的\n\n    output[i] =  { i 前面的数的乘积}  X  { i 后面的数的乘积}\n\n\n```\nclass Solution(object):\n        def productExceptSelf(self,nums):\n            \"\"\"\n            :type nums: List[int]\n            :rtype: List[int]\n            \"\"\"\n            if nums == [] : return []  \n            lft = [1]\n            rgt = [1]\n            product = 1 \n            for i in range(1,len(nums)):\n                product *= nums[i-1]\n                lft.append(product)\n            product = 1 \n            for i in reversed(range(1,len(nums))):\n                product *= nums[i]\n                rgt.append(product)\n            rgt.reverse()\n            result = []\n            for i in range(len(nums)):\n                result.append(lft[i]*rgt[i])\n            return result\n            \n```\n\n\n空间O（n），再看到满足要求的“标准解法”\n\n\n```\nclass Solution(object):\n        def productExceptSelf(self,nums):\n            \"\"\"\n            :type nums: List[int]\n            :rtype: List[int]\n            \"\"\"\n            if nums == [] : return []  \n            size = len(nums)\n            output = [1] * size\n            left = 1\n            for x in range(size-1):\n                left *= nums[x]\n                output[x+1] *= left\n            right = 1\n            for x in range(size - 1, 0, -1):\n                right *= nums[x]\n                output[x-1] *= right\n            return output\n```"
  },
  {
    "path": "docs/leetcode/python/240._search_a_2d_matrix_ii.md",
    "content": "### 240. Search a 2D Matrix II\n\n\n\n题目:\n<https://leetcode.com/problems/search-a-2d-matrix-ii/>\n\n\n难度:\nMedium\n\n思路：\n\n每行，每列都是sorted\n\n但是比较好的策略是从右上角开始搜索，比如这样：\n\n```\nmatrix = [\n  [1,   4,  7, 11, 15],\n  [2,   5,  8, 12, 19],\n  [3,   6,  9, 16, 22],\n  [10, 13, 14, 17, 24],\n  [18, 21, 23, 26, 30]\n]\n\nm, n =  0, col - 1\n更新策略：\n matrix[m][n] < target: 那么这一行到从左走到此都会小于target，row+1 ，往下走\n matrix[m][n] > target:  那么这一列往下走都会大于target，col - 1,往左走\n 否则找到\n```\n\n时间复杂度O(max(M,N))，因为每次都会往下或者往左走\n\n\n用的算法是Saddleback\n\n\n\n```python\nclass Solution(object):\n    def searchMatrix(self, matrix, target):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :type target: int\n        :rtype: bool\n        \"\"\"\n        if not matrix:\n            return False\n        row = len(matrix)\n        col = len(matrix[0]) if row else 0 \n        m, n = 0, col - 1\n        while m < row and n >= 0:\n            if matrix[m][n] < target:\n                m += 1\n            elif matrix[m][n] > target:\n                n -= 1\n            else:\n                return True\n        return False\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/242._valid_anagram.md",
    "content": "### 242. Valid Anagram\n\n题目： \n<https://leetcode.com/problems/valid-anagram/>\n\n\n难度 : Easy\n\n\n一行瞬秒：\n\n```python\nclass Solution(object):\n    def isAnagram(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: bool\n        \"\"\"\n        return collections.Counter(s) == collections.Counter(t)\n```\n\n```python\nclass Solution(object):\n    def isAnagram(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: bool\n        \"\"\"\n        return sorted(s) == sorted(t)\n            \n```\n\n\n用字数统计，因为只可能是26个字母\n\n\n```\n\nclass Solution(object):\n    def isAnagram(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: bool\n        \"\"\"\n        if len(s) != len(t):\n            return False\n        \n        charCnt = [0] * 26\n        \n        for i in range(len(s)):\n            charCnt[ord(s[i]) - 97] += 1\n            charCnt[ord(t[i]) - 97] -= 1 \n        \n        for cnt in charCnt:\n        \tif cnt != 0:\n        \t\treturn False\n        return True\n```\n"
  },
  {
    "path": "docs/leetcode/python/249._Group_Shifted_Strings.md",
    "content": "#  249. Group Shifted Strings\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/group-shifted-strings\n\n> 内容描述\n\n```\nGiven a string, we can \"shift\" each of its letter to its successive letter, for example: \"abc\" -> \"bcd\". We can keep \"shifting\" which forms the sequence:\n\n\"abc\" -> \"bcd\" -> ... -> \"xyz\"\nGiven a list of strings which contains only lowercase alphabets, group all strings that belong to the same shifting sequence.\n\nExample:\n\nInput: [\"abc\", \"bcd\", \"acef\", \"xyz\", \"az\", \"ba\", \"a\", \"z\"],\nOutput: \n[\n  [\"abc\",\"bcd\",\"xyz\"],\n  [\"az\",\"ba\"],\n  [\"acef\"],\n  [\"a\",\"z\"]\n]\n```\n\n## 解题方案\n\n> 思路 1\n\nhash table存储pattern\n\n```python\nclass Solution(object):\n    def groupStrings(self, strings):\n        \"\"\"\n        :type strings: List[str]\n        :rtype: List[List[str]]\n        \"\"\"\n        table = {}\n        for w in strings:\n            pattern = ''\n            for i in range(1, len(w)):\n                if ord(w[i]) - ord(w[i - 1]) >= 0:\n                    pattern += str(ord(w[i]) - ord(w[i - 1]))\n                else:\n                    pattern += str(ord(w[i]) - ord(w[i - 1]) + 26)  ## 这是为了处理'az'和'ba'的情况\n            \n            if pattern in table:\n                table[pattern].append(w)\n            else:\n                table[pattern] = [w]\n        return [table[pattern] for pattern in table]\n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/252._Meeting_Rooms.md",
    "content": "### 252. Meeting Rooms\n\n\n\n题目： \n<https://leetcode.com/problems/meeting-rooms/>\n\n\n\n难度 : Easy\n\n\n\n思路：\n\n学了一下如何根据attribute 来sort object `intervals.sort(key = lambda interval : interval.start)`\n\n\n\nAC 代码\n\n```\n# Definition for an interval.\n# class Interval(object):\n#     def __init__(self, s=0, e=0):\n#         self.start = s\n#         self.end = e\n\nclass Solution(object):\n    def canAttendMeetings(self, intervals):\n        \"\"\"\n        :type intervals: List[Interval]\n        :rtype: bool\n        \"\"\"\n        n = len(intervals)\n        if n < 2 : return True\n        intervals.sort(key = lambda interval : interval.start)\n        for i in range(1,n):\n        \tif intervals[i].start < intervals[i-1].end:\n        \t\treturn False\n        return True\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md",
    "content": "### 255. Verify Preorder Sequence in Binary Search Tree\n\n题目:\n<https://leetcode.com/problems/verify-preorder-sequence-in-binary-search-tree/>\n\n\n难度:\n\nMedium\n\n\n思路：\n\n这道题让给了我们一个一维数组，让我们验证其是否为一个二叉搜索树的先序遍历出的顺序，我们都知道二叉搜索树的性质是左<根<右，如果用中序遍历得到的结果就是有序数组，而先序遍历的结果就不是有序数组了，但是难道一点规律都没有了吗，其实规律还是有的，根据二叉搜索树的性质，当前节点的值一定大于其左子树中任何一个节点值，而且其右子树中的任何一个节点值都不能小于当前节点值，那么我们可以用这个性质来验证，举个例子，比如下面这棵二叉搜索树：\n```\n      10\n     /  \\\n    5    12\n   / \\\n  2   6\n  \n  preorder:[10, 5, 2, 6, 12]\n```\n\n如这个例子，我们先设一个最小值min_num，然后遍历数组，如果当前值小于这个最小值min_num，返回false，对于根节点，我们将其压入栈中，然后往后遍历，如果遇到的数字比栈顶元素小，说明是其左子树的点，继续压入栈中，直到遇到的数字比栈顶元素大，那么就是右边的值了，我们需要找到是哪个节点的右子树，所以我们更新low值并删掉栈顶元素，然后继续和下一个栈顶元素比较，如果还是大于，则继续更新low值和删掉栈顶，直到栈为空或者当前栈顶元素大于当前值停止，压入当前值，这样如果遍历完整个数组之前都没有返回false的话，最后返回true即可\n\n\n参考[Ethan Li 的技术专栏](https://segmentfault.com/a/1190000003874375)\n\nO(n) time, O(n) space\n```python\nclass Solution(object):\n    def verifyPreorder(self, preorder):\n        \"\"\"\n        :type preorder: List[int]\n        :rtype: bool\n        \"\"\"\n        stack = []\n        min_num = -1 << 31  # 初始化最小值为最小整数\n        for x in preorder:\n            if x < min_num: # 违反最小值限定则是无效的\n                return False \n            while stack and x > stack[-1]: # 将路径中所有小于当前的数pop出来并更新最小值\n                min_num = stack.pop()\n            stack.append(x) # 将当前值push进去\n        return True\n```\n\n### Follow up: \nO(n) time, O(1) space\n\nwe realize that the preorder array can be reused as the stack thus achieve O(1) extra space, since the scanned items of preorder array is always more than or equal to the length of the stack.\n```python\nclass Solution(object):\n    def verifyPreorder(self, preorder):\n        \"\"\"\n        :type preorder: List[int]\n        :rtype: bool\n        \"\"\"\n        # stack = preorder[:i], reuse preorder as stack\n        min_num = -1 << 31\n        i = 0\n        for x in preorder:\n            if x < min_num:\n                return False\n            while i > 0 and x > preorder[i - 1]:\n                min_num = preorder[i - 1]\n                i -= 1\n            preorder[i] = x\n            i += 1\n        return True\n```\n"
  },
  {
    "path": "docs/leetcode/python/256._Paint_House.md",
    "content": "### 256. Paint House\n\n题目:\n<https://leetcode.com/problems/paint-house/>\n\n难度:\nMedium\n\n\n\n其实这个题目有实际意义诶，至少我的故乡？在要申请啥东西的时候就把街上的房子全刷了。\n\n然后这个是相邻的房子不同色。\n\n\n\n其实我觉得paint fense更难一点\n\n\n\n思路：\n\n数组 dp\\[x][3] 代表第x个房子paint r/g/b的值\n\n\n\nAC代码\n\n```\nclass Solution(object):\n    def minCost(self, costs):\n        \"\"\"\n        :type costs: List[List[int]]\n        :rtype: int\n        \"\"\"\n        m = len(costs)\n        if m == 0 : return 0\n        elif m == 1 :  return min(costs[0][0], costs[0][1],costs[0][2])\n    \telse:\n\t        n = 3 if m else 0\n\t        dp = [[0 for i in range(3)] for j in range(m)]\n\n\t        dp[0] = costs[0]\n\n\t        \n\t        for i in range(1,m):\n\t        \tdp[i][0] = min(dp[i-1][1],dp[i-1][2]) + costs[i][0]\n\t        \tdp[i][1] = min(dp[i-1][0],dp[i-1][2]) + costs[i][1]\n\t        \tdp[i][2] = min(dp[i-1][0],dp[i-1][1]) + costs[i][2]\n\t        return min(dp[m-1][0], dp[m-1][1], dp[m-1][2])\n\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/257._binary_tree_paths.md",
    "content": "#  257. Binary Tree Paths\n**<font color=red>难度: 简单</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/binary-tree-paths\n\n> 内容描述\n\n```\nGiven a binary tree, return all root-to-leaf paths.\n\nNote: A leaf is a node with no children.\n\nExample:\n\nInput:\n\n   1\n /   \\\n2     3\n \\\n  5\n\nOutput: [\"1->2->5\", \"1->3\"]\n\nExplanation: All root-to-leaf paths are: 1->2->5, 1->3\n```\n\n## 解题方案\n\n> 思路 1\n\n递归+DFS\n\n```python\nclass Solution(object):\n    def binaryTreePaths(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[str]\n        \"\"\"\n        def helper(node, cur_path):\n            if not node.left and not node.right: ## 到leaf了\n                res.append(cur_path+[node.val])\n                return\n            if node.left:\n                helper(node.left, cur_path+[node.val])\n            if node.right:\n                helper(node.right, cur_path+[node.val])\n\n        res = []  \n        if not root:\n            return res\n        helper(root, [])\n        \n        return ['->'.join([str(val) for val in path]) for path in res]\n```\n注意一点，很多人可能看到这里有好几次cur_path+[node.val]，觉得干嘛不直接写在最开头了，事实是这样做的话cur_path就已经变化了，因为要执行完if node.left才去执行if node.right，此时cur_path就不是原来的cur_path了。\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/258._Add_Digits.md",
    "content": "### 258. Add Digits\n\n题目:\n<https://leetcode.com/problems/add-digits/>\n\n\n难度:\n\nEasy\n\n\n思路\n\n这就简单的一p了。。\n\n\n```python\nclass Solution(object):\n    def addDigits(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: int\n        \"\"\"\n        while num / 10 >= 1:\n            tmp = 0\n            while num / 10 >= 1:\n                tmp += num % 10\n                num /= 10\n            tmp += num % 10\n            num = tmp\n        return num\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/261._Graph_Valid_Tree.md",
    "content": "### 261. Graph Valid Tree\n\n\n\n题目： \n<https://leetcode.com/problems/graph-valid-tree/>\n\n\n\n难度 : Medium\n\n\n\n思路：\n\ngraph 为 tree 两个条件：\n\n- 这个图是connected\n- 没有cycle\n\n\n\n偷懒AC代码，直接在323题，Number of Connected Components in an Undirected Graph上改的AC代码：\n\n\n\n```\nclass Solution(object):\n    def validTree(self, n, edges):\n        \"\"\"\n        :type n: int\n        :type edges: List[List[int]]\n        :rtype: bool\n        \"\"\"\n        def find(x):\n        \tif uf[x] != x:\n        \t\tuf[x] = find(uf[x])\n        \treturn uf[x]\n\n        def union(x,y):\n        \txRoot = find(x)\n        \tyRoot = find(y)\n        \tuf[xRoot] = yRoot\n\n        uf = [i for i in range(n)]\n\n        for node1, node2 in edges:\n            # cycle exists\n            if find(node1) == find(node2):\n                print 'ha '\n                return False\n            else:\n                union(node1, node2)\n\n        res = set()\n        for i in range(n):\n        \tres.add(find(i))\n\n        return len(res) == 1\n```\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/263._ugly_number.md",
    "content": "###263. Ugly Number\n\n\n\n题目:\n<https://leetcode.com/problems/ugly-number/>\n\n\n难度:\nEasy\n\n\n思路：\n\n因为其prime factors 只包括 2, 3, 5，所以比如如果能被2 整除， n = n / 2， 直到不能被2整除，然后同样对3,5检验，如果最终结果为1，那么就是ugly number，否则不过关\n\n\n注意一下边界条件，当num为0的时候，return一下False\n\n```\nclass Solution(object):\n    def isUgly(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: bool\n        \"\"\"\n        if num == 0 : return False\n        while num % 2 == 0:\n        \tnum = num / 2\n        while num % 3 == 0:\n        \tnum = num / 3\n        while num % 5 == 0:\n        \tnum = num / 5\n        if num == 1:\n       \t\treturn True\n       \treturn False \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/264._ugly_number_ii.md",
    "content": "###264. Ugly Number II\n\n\n\n题目:\n<https://leetcode.com/problems/ugly-number-ii/>\n\n\n难度:\nMedium\n\n\n思路：\n\n暴力算法一定会超时\n\n\n\n\n先看一个非常🐂的帖子，当我知道python 除了有list之外还有collections就已经被刷新了一次了，然后数据结构 x 数据结构，就展示了数据结构的魅力\n\n<http://stackoverflow.com/questions/4098179/anyone-know-this-python-data-structure>\n\n\n看一下deque + rotate：\n\n\n```\nimport collections\na = collections.deque()\na.append(2)\na.append(5)\na.append(7)\na.append(9)  #a  deque([2, 5, 7, 9])\n\nimport bisect\nidx = bisect.bisect_left(a,3) #1\na.rotate(-idx) #deque([5, 7, 9, 2])\n\na.appendleft(3) #deque([3, 5, 7, 9, 2])\n\na.rotate(idx) # deque([2, 3, 5, 7, 9])\n```\n\n这个rotate -是往左边rotate，看官网的介绍.\n\n>Rotate the deque n steps to the right. If n is negative, rotate to the left. Rotating one step to the right is equivalent to: d.appendleft(d.pop()).\n\n所以这样造成可以🐂的数据结构\n\n用这个微调之后的fasttable来解决问题\n\n\n```\nimport collections\nimport bisect\n\nclass FastTable:\n\n    def __init__(self):\n        self.__deque = collections.deque()\n\n    def __len__(self):\n        return len(self.__deque)\n\n    def head(self):\n        return self.__deque.popleft()\n\n    def tail(self):\n        return self.__deque.pop()\n\n    def peek(self):\n        return self.__deque[-1]\n\n    def insert(self, obj):\n        if obj in self.__deque:\n            return\n        index = bisect.bisect_left(self.__deque, obj)\n        self.__deque.rotate(-index)\n        self.__deque.appendleft(obj)\n        self.__deque.rotate(index)\n\nclass Solution(object):\n   \n    def nthUglyNumber(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        q = FastTable()\n        q.insert(1)\n        while n > 0:\n        \tx = q.head()\n        \tq.insert(2*x)\n        \tq.insert(3*x)\n        \tq.insert(5*x)\n        \tn -= 1\n        return x\n```\n\n\n还可以优化：\n根据页面hint 来做的\n\n\n```\nclass Solution(object):\n    def nthUglyNumber(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        if n == 1:\n            return 1\n        else:\n            import collections\n            q2 = collections.deque()\n            q3 = collections.deque()\n            q5 = collections.deque()\n            q2.append(2)\n            q3.append(3)\n            q5.append(5)\n            while n > 1:\n                    x = min(q2[0],q3[0],q5[0])\n                    if x == q2[0]:\n                            x = q2.popleft()\n                            q2.append(2*x)\n                            q3.append(3*x)\n                            q5.append(5*x)\n                    elif x == q3[0]:\n                            x = q3.popleft()\n                            q3.append(3*x)\n                            q5.append(5*x)\n                    else:\n                            x = q5.popleft()\n                            q5.append(5*x)\n                    n -= 1\n            return x\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/265._Paint_House_II.md",
    "content": "### 265. Paint House II\n\n\n\n题目:\n<https://leetcode.com/problems/paint-house-ii/>\n\n难度:\n\nHard\n\n\n\n思路：\n\n感觉不像hard 题，知道为啥hard了，因为can you solve it in O(nk) runtime\n\n数组 dp\\[x][k] 代表第x个房子paint 0..k的值\n\n\n\n用paint house 1 改的AC代码：\n\n不过这个时间复杂度是O(nkk)吧\n\n\n\n```\nclass Solution(object):\n    def minCostII(self, costs):\n        \"\"\"\n        :type costs: List[List[int]]\n        :rtype: int\n        \"\"\"\n        n = len(costs)\n        if n == 0 : return 0\n        elif n == 1 :  return min (costs[0])\n        else:\n        \tk = len(costs[0]) if n else 0\n        \tdp = [[0 for i in range(k)] for j in range(n)]\n\n        \tdp[0] = costs[0]\n\n        \tfor i in range(1,n):\n        \t\tfor j in range(0,k):\n        \t\t\tminVal = float('inf')\n        \t\t\tfor m in range(0,k):\n        \t\t\t\tif m != j and dp[i-1][m] < minVal:\n        \t\t\t\t\tminVal = dp[i-1][m]\n        \t\t\tdp[i][j] = minVal + costs[i][j]\n\n        \treturn min(dp[-1])\n```\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/266._Palindrome_Permutation.md",
    "content": "### 266. Palindrome Permutation\n\n\n\n题目： \n<https://leetcode.com/problems/palindrome-permutation/>\n\n难度 : Easy\n\n\n\n思路：\n\nhint 已经提示的很明显。数单字个数来处理\n\n\n\nAC代码\n\n\n\n```\nclass Solution(object):\n    def canPermutePalindrome(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: bool\n        \"\"\"\n        lookup = {}\n\n        for char in s:\n        \tlookup[char] = lookup.get(char,0) + 1\n\n        res = 0\n\n        for char, cnt in lookup.items():\n        \tif cnt % 2 == 0 :\n        \t\tcontinue\n        \telse:\n        \t\tres += 1\n\n        return res < 2\n```\n\n​\t\n\n"
  },
  {
    "path": "docs/leetcode/python/267._Palindrome_Permutation_II.md",
    "content": "### 267. Palindrome Permutation II\n\n\n\n\n\n题目： \n<https://leetcode.com/problems/palindrome-permutation-ii/>\n\n\n\n难度 : Medium\n\n\n\n思路：\n\n首先这个题目有个简单版本，那就是判断是否可以permutate 为 palindrome. 问题的关键是最多只能一个odd character.\n\n\n\n写的这么不elegant，我也是服气！\n\nAC代码：\n\n\n\n```\nclass Solution(object):\n    def generatePalindromes(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: List[str]\n        \"\"\"\n        def permuteUnique(firstS):\n            if len(firstS) == 0 : return []\n            if len(firstS) == 1 : return [firstS]\n            res = []\n            for i in range(len(firstS)):\n                if i > 0 and firstS[i] == firstS[i-1]: continue\n                for j in permuteUnique(firstS[:i] + firstS[i+1:]):\n                    res.append([firstS[i]] + j)\n            return res\n\n        lookup = {}\n        for char in s:\n            lookup[char] = lookup.get(char, 0) + 1\n\n        res, firstS, oddChar = 0, [], ''\n        for char, cnt in lookup.items():\n            if cnt % 2 == 0:\n                for i in range(cnt/2):\n                    firstS.append(char)\n                continue\n            else:\n                for i in range(cnt / 2):\n                    firstS.append(char)\n                oddChar = char\n                res += 1\n        if res >= 2:\n            return []\n        else:\n            res = permuteUnique(firstS)\n            if len(res) == 0 and oddChar:\n                return [oddChar]\n            return map(lambda x: ''.join(x) + oddChar + ''.join(x[::-1]),res)\n\n```\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/268._missing_number.md",
    "content": "### 268. Missing Number\n\n题目:\n<https://leetcode.com/problems/missing-number/>\n\n\n难度:\n\nMedium \n\n\n\n等差数列前n项和减去数组之和,一行瞬秒\n```(注意题目input从0开始取值)```\n\n\n```python\nclass Solution(object):\n    def missingNumber(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        return len(nums) * (len(nums) + 1) / 2 - sum(nums)\n```\n\n\n\n第二种解法是位运算：位运算（异或运算）\n\n\n\n```python\nclass Solution(object):\n    def missingNumber(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        res = n = len(nums)\n        for i in range(n):\n            res ^= i\n            res ^= nums[i]\n        return res\n```\n\n        \n\n\n"
  },
  {
    "path": "docs/leetcode/python/270._Closest_Binary_Search_Tree_Value.md",
    "content": "#  270. Closest Binary Search Tree Value\n**<font color=red>难度: 简单</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/closest-binary-search-tree-value\n\n> 内容描述\n\n```\nGiven a non-empty binary search tree and a target value, find the value in the BST that is closest to the target.\n\nNote:\n\nGiven target value is a floating point.\nYou are guaranteed to have only one unique value in the BST that is closest to the target.\nExample:\n\nInput: root = [4,2,5,1,3], target = 3.714286\n\n    4\n   / \\\n  2   5\n / \\\n1   3\n\nOutput: 4\n```\n\n## 解题方案\n\n> 思路 1\n\n来个中序遍历，再判断哪个最close\n\n```python\nclass Solution(object):\n    def closestValue(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: float\n        :rtype: int\n        \"\"\"\n        res, diff = [], []\n        self.inorder(root, res)\n        \n        for i in res:\n            diff.append(abs(i-target))\n        return res[diff.index(min(diff))]\n            \n    def inorder(self, root, res):\n        if not root:\n            return \n        self.inorder(root.left, res)\n        res.append(root.val)\n        self.inorder(root.right, res)\n```\n\n> 思路 2\n\n或者可以用更节省空间的方式，只保留一个closet，不断比较\n\n```python\nclass Solution(object):\n    def closestValue(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: float\n        :rtype: int\n        \"\"\"\n        lst = []\n\n        def inorder(root):\n        \tif root:\n        \t\tinorder(root.left)\n        \t\tlst.append(root.val)\n        \t\tinorder(root.right)\n\n        inorder(root)\n\n        close = lst[0]\n        diff = abs(target - lst[0])\n\n        for i in lst:\n        \tif abs(target - i) < diff:\n        \t\tclose = i\n        \t\tdiff = abs(target - i )\n\n        return close\n```\n\n> 思路 3\n\nAC代码，跟binary search tree 寻值一样, loop 一遍树来寻找\n\n```python\nclass Solution(object):\n    def closestValue(self, root, target):\n        \"\"\"\n        :type root: TreeNode\n        :type target: float\n        :rtype: int\n        \"\"\"\n        close = root.val\n        \n        while root:\n            close = root.val if abs(target - root.val) < abs(target - close) else close\n            root = root.right if root.val < target else root.left\n        return close\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/276._Paint_Fence.md",
    "content": "### 276. Paint Fence\n\n题目:\n<https://leetcode.com/problems/paint-fence/>\n\n难度:\nEasy\n\n思路：\n\n先解释一下题目意思： fence 栅栏， post 柱子 , no more than two adjacent fence posts have the same color.（一开始看漏，没有看到more than，以为相邻就不能同色）。\n\n本来想画格子找规律，结果走偏了，所以老老实实写递推关系式，貌似是这样的\n\n- n = 0 : 全为0\n- n = 1 :  有 k种方式\n- n = 2 ：有 k * k 种 \n- 否则，第n个有两种可能， 跟 n-1 颜色不一样, 跟 n-1 颜色一样， fn = (k-1)fn-1 + (k-1) fn-2\n\n\n\n画一下表：对一下递推关系式，正确✅\n\n\n\n```\n\t\t\t\tn\n\t\t0\t1\t2\t3\t4\n\t0\t0\t0\t0\t0\t0\nt\t1\t0\t1\t1\t0\t0\n\t2\t0\t2\t4\t6\t10\n\t3\t0\t3\t9\t24\t.\n\t4\t0\t4\t16\t60\t.\n```\n\n\n\nAC 代码\n\n```\nclass Solution(object):\n    def numWays(self, n, k):\n        \"\"\"\n        :type n: int\n        :type k: int\n        :rtype: int\n        \"\"\"\n        if n == 0:\n        \treturn 0\n        else:\n            if k == 0: return 0\n            elif n == 1: return k \n            elif n == 2 : return k * k\n            else:\n            \tdp = [0 for i in range(n+1)]\n            \tdp[0] = 0\n            \tdp[1] = k\n            \tdp[2] = k * k \n\n            \tfor i in range(3,n+1):\n            \t\tdp[i] = (k-1) * dp [i-1] + (k-1) * dp [i-2]\n            \treturn dp[-1]\n\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/277._Find_the_Celebrity.md",
    "content": "### 277. Find the Celebrity\n\n\n\n题目： \n<https://leetcode.com/problems/find-the-celebrity/>\n\n\n\n难度 : Medium\n\n\n\n思路：\n\n算法考试考过\n\ncelebrity 是 每个人都知道他，而他不认识任何别的人。\n\n\n\n如果用图来看，那就每个别的人都有箭头指向c，而c没有任何出去的箭头。\n\nO(N^2)的代码还是还是很容易想到的\n\n但是我们可以有提升，那么就是可以check `knows(a,b)`，如果 a knows b，那么可以排除a是celebrity，否则可以排除b是celebrity.\n\n最后还要确认一遍是否这个是真的celebrity\n\n\n\nAC代码\n\n```\n# The knows API is already defined for you.\n# @param a, person a\n# @param b, person b\n# @return a boolean, whether a knows b\n# def knows(a, b):\n\nclass Solution(object):\n    def findCelebrity(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        if n == 0:\n        \treturn -1\n        c = 0\n        for i in xrange(1,n):\n        \tif not knows(i, c):\n        \t\tc = i\n    \tfor i in range(n):\n    \t\tif c != i:\n    \t\t\tif not knows(i,c) or knows(c,i):\n    \t\t\t\treturn -1\n    \treturn c\n\n\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/278._First_Bad_Version.md",
    "content": "### 278. First Bad Version\n\n\n\n\n\n题目： \n<https://leetcode.com/problems/first-bad-version/>\n\n\n\n难度 : Easy\n\n\n\n思路：\n\n根据 search for a range 改的\n\n\n\n```python\nclass Solution(object):\n    def firstBadVersion(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        l, r = 0, n - 1\n        while l <= r:\n            mid = l + ((r - l) >> 2)\n            if not isBadVersion(mid):\n                l = mid + 1\n            else:\n                r = mid - 1\n        return l\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/279._perfect_squares.md",
    "content": "### 279. Perfect Squares\n\n**<font color=yellow>难度: Medium</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/perfect-squares\n* https://leetcode-cn.com/problems/perfect-squares\n\n> 内容描述\n\n```\n给定正整数 n，找到若干个完全平方数（比如 1, 4, 9, 16, ...）使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。\n\n示例 1:\n\n输入: n = 12\n输出: 3 \n解释: 12 = 4 + 4 + 4.\n示例 2:\n\n输入: n = 13\n输出: 2\n解释: 13 = 4 + 9.\n```\n\n## 解题方案\n\n> 思路 1: 暴力破解\n\n```\n求某个数的最少平方加和的个数\n\n1. diff集合(小到大排序) = n - 平方根的平方的集合\n2. 每一层都在不断 - 平方根的平方\n3. 直到出现 0 代表得到结果\n\n当然，你可以提前: dp.append(count) => return count, 得到最小值\n\nn = 15 的时候\n    -9  -4  -1\n>>> [6, 11, 14]\n>>> [2, 5, 7, 10, 13]\n>>> [1, 3, 4, 6, 9, 12]\n>>> [0, 2, 3, 5, 8, 11]\n>>> [1, 2, 4, 7, 10]\n>>> [0, 1, 3, 6, 9]\n>>> [0, 2, 5, 8]\n>>> [1, 4, 7]\n>>> [0, 3, 6]\n>>> [2, 5]\n>>> [1, 4]\n>>> [0, 3]\n>>> [2]\n>>> [1]\n>>> [0]\n>>> []\n4  ---  [4, 6, 7, 9, 12, 15]\n```\n\n\n```python\nclass Solution(object):\n    def numSquares(self, n: int) -> int:\n        result = []\n        count = 1\n        diff_list = [n]\n        while len(diff_list):\n            diff_list = sorted(list(set([diff-i**2 for diff in diff_list for i in range(1, diff+1) if diff>=i**2])))\n            # print(\">>> %s\" % diff_list)\n            if len(diff_list) < 1:\n                break \n            elif 0 in diff_list:\n                result.append(count)\n            count += 1\n        # print(min(result), \" --- \", result)\n        return min(result) if len(result)>0 else -1\n```\n\n> 思路 2: 动态规划\n\n```\n1. 初始化 inf 从0开始，所以数组长度 n+1 \n2. 考虑到是平方，意味着他的间隔可能是跳跃性的，所以 \n        n  =   (n-j*j)  + j*j\n        dp[i] = dp[i-1] + 1\n3. 那么 min 就是未来找到最小值而存在的，因为需要遍历很多个平方， dp[i] 用户存储最小值\n4. 返回 dp[-1] 的结果，也就是最终 n 的值\n```\n\n```python\nclass Solution(object):\n    def numSquares(self, n: int) -> int:\n        square_nums = [i**2 for i in range(1, int(n**0.5)+1)]\n        dp = [float('inf')] * (n+1)\n        dp[0] = 0\n        for i in range(1, n+1):\n            for square in square_nums:\n                if i < square:\n                    break\n                # print(\"%s --- %s结果需要一次 --- %s结果需要%s次\" % (i, square, i-square, dp[i-square]))\n                dp[i] = min(dp[i], dp[i-square] + 1)\n        return dp[-1]\n```\n\n\n--- \n\n未测试 \n\n> 思路三：\n\n还是慢，有个数学方法, runtime beats 98.48%\n```python\nimport math\nclass Solution(object):\n    def numSquares(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        def isSquare(num):\n            tmp = int(math.sqrt(num))\n            return tmp * tmp == num\n        while n & 3 == 0: # n % 4 == 0 \n            n >>= 2\n        if n & 7 == 7: # n % 8 == 7\n            return 4\n        if isSquare(n):\n            return 1\n        sqrt_n = int(math.sqrt(n))\n        for i in range(1, sqrt_n + 1):\n            if isSquare(n-i*i):\n                return 2\n        return 3\n```\nin order to understand, I suggest u read:\n\nhere is the [Lagrange's Four Square theorem](https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem\n) - Limit the result to <= 4:\n\nAnd this [article](http://www.alpertron.com.ar/4SQUARES.HTM), in which you can also find the way to present a number as a sum of four squares:\n\n\n"
  },
  {
    "path": "docs/leetcode/python/280._Wiggle_Sort.md",
    "content": "### 280. Wiggle Sort\n\n\n\n\n\n题目： \n<https://leetcode.com/problems/wiggle-sort/>\n\n\n\n难度 : Medium\n\n\n\n思路：\n\n\n\n想的是比如bubble sort或者任何简单的比较sort，只是放数字的时候是按这样的大小顺序放：\n\n1, n, 2, n-1,3, n-2….\n\n或者每个pass其实做两个sort，找出最大的和最小的。然后分别放在头尾。\n\n\n\n这样的写法TLE:\n\n```\nclass Solution(object):\n    def wiggleSort(self, nums): # 此法超时\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        n = len(nums)\n        for i in range(n):\n        \t# small bubble sort\n        \tif i % 2 == 0:\n        \t\tfor j in range(n-1, i-1, -1):\n        \t\t\tif nums[j] > nums[j-1]:\n        \t\t\t\tnums[j], nums[j-1] = nums[j-1],nums[j]\n        \telse:\n        \t\tfor j in range(n-1, i-1, -1):\n        \t\t\tif nums[j] < nums[j-1]:\n        \t\t\t\tnums[j], nums[j-1] = nums[j-1],nums[j]\n```\n\n\n\n\n\n但是貌似想复杂了，其实对于这个简单化，要求只有一个：\n\n1. 如果i是奇数，nums[i] >= nums[i - 1]\n2. 如果i是偶数，nums[i] <= nums[i - 1]\n\n所以我们只要遍历一遍数组，把不符合的情况交换一下就行了。具体来说，如果nums[i] > nums[i - 1]， 则交换以后肯定有nums[i] <= nums[i - 1]。\n\n\n\nAC 代码\n\n```python\nclass Solution(object):\n    def wiggleSort(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        for i in xrange(1, len(nums)):\n            if ((i % 2) and nums[i] < nums[i-1]) or ((not i % 2) and nums[i] > nums[i-1]):\n                nums[i], nums[i-1] = nums[i-1], nums[i]\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/283._move_zeroes.md",
    "content": "### 283. Move Zeroes\n\n\n题目:\n<https://leetcode.com/problems/move-zeroes/>\n\n\n难度:\nEasy\n\n\n思路：\n\n### 思路一：暴力\n\n```python\nclass Solution(object):\n    def moveZeroes(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        i = 0\n        while 0 in nums:\n            nums.remove(0)\n            i += 1\n        nums.extend([0]*i)\n```\n\n### 思路二：\n\n一旦遇到不是0的就把它往前移动，移动非0完成，剩下的全部填0，看例子\n\n\n\n```\n0\t1\t0\t3\t12\n\n```\n\n也算双指针吧，\n首先cur = 0， idx = 0，为0，不变，然后idx = 1，不为0，前移，数组变成\n\n```\n1\t1\t0\t3\t12\n```\n\n继续idx 这个时候是2，不变，继续处理,碰到3可以变成\n\n```\n1\t3\t0\t3\t12\n```\n这样知道变换完成，简直逆天啊，因为cur 总是小于idx，所以总可以保持这样的稳定性\n\n\n```python\nclass Solution(object):\n    def moveZeroes(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        cur,idx = 0,0         \n        while idx < len(nums):\n        \t# cur is not 0\n        \tif nums[idx] != 0 :\n        \t\tnums[cur] = nums[idx]\n        \t\tcur += 1\n        \tidx += 1\n\n        while cur < len(nums):\n        \tnums[cur] = 0\n        \tcur += 1\n\n```\n\n\n### 思路三：\n\n传统的双指针，参考这里\n\n<http://fisherlei.blogspot.com/2015/10/leetcode-move-zeroes-solution.html>\n\n```此法最快，beats 90.50%```\n\n```python\nclass Solution(object):\n    def moveZeroes(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        p0, p1 = 0, 0  # P1指向非0，p0指向0\n        while p0 < len(nums) and p1 < len(nums):\n        \tif nums[p0] != 0:\n        \t\tp0 += 1\n        \t\tp1 = p0\n        \t\tcontinue\n        \tif nums[p1] == 0:\n        \t\tp1 += 1\n        \t\tcontinue\n        \tnums[p0],nums[p1] = nums[p1],nums[p0]\n        \tp0 += 1\n        \tp1 += 1\n```\n\n相反，我觉得这样双指针反而没有上面的代码容易理解\n\n### 思路四：\n\n一个比较巧妙的方法：\n```python\nclass Solution(object):\n    def moveZeroes(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        nums.sort(key= lambda x: 1 if x == 0 else 0)\n```\n原理就是原先为0的数优先级在此次sort中更高了，所以全部升序排列排到后面去了\n\n但是这个解法被人说是没有满足题目```no extra space```的条件，详见[Sayo](https://leetcode.com/problems/move-zeroes/discuss/72074/)\n```\ntimsort can require a temp array containing as many as N//2 pointers, which means as many as 2*N extra bytes on 32-bit boxes.\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/285._inorder_successor_in_bst.md",
    "content": "# 285. Inorder Successor in BST\n\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/inorder-successor-in-bst\n\n> 内容描述\n\n```\n\nGiven a binary search tree and a node in it, find the in-order successor of that node in the BST.\n\nNote: If the given node has no in-order successor in the tree, return null.\n\nExample 1:\n\nInput: root = [2,1,3], p = 1\n\n  2\n / \\\n1   3\n\nOutput: 2\nExample 2:\n\nInput: root = [5,3,6,2,4,null,null,1], p = 6\n\n      5\n     / \\\n    3   6\n   / \\\n  2   4\n /   \n1\n\nOutput: null\n```\n\n## 解题方案\n\n> 思路 1\n\n首先可以去看一下[二叉树的一些操作](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/Summarization/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E4%B8%80%E4%BA%9B%E6%93%8D%E4%BD%9C.md)\n\nBST的特性，对于一个node，它的所有左侧node都比它小，它的所有右侧node都比它大。最小的元素在最左边，最大的元素在最右边。\n\n一个node x它的successor y 是满足y > x的最小值。两种情况，如果node x有right child，那么这个right child 中的最小值就是它的successor，否则就要往上走，如果走上去的parent使得这个node是其左边的孩子的话，那么successor我们也找到了。\n\n\n因为状况可能是这样的：\n\n```\n\t\t3\n\t  /\n\t 1\n   /  \\\n  0\t   2\n```\n\n如果是寻找0的successor，那么我们往上一走，发现0的祖先是1，并且0是1的左孩子，找到，否则如果寻找2的successor，那么我们要往上走到3的部分，2是3的左subtree，这样才能解决问题。\n\n伪码\n\n```\nfunction Succ(x)\t\n\tif Right(x) ̸= NIL then\t\t\n\t\treturn Min(Right(x)) \t\n\telse\t\t\n\t\tp ← Parent(x)\t\t\n\t\twhile p ̸= NIL and x = Right(p) do\t\t\t\n\t\t\tx←p\t\t\t\n\t\t\tp ← Parent(p) \n\t\treturn p\n```\n\n这里伪码有点不适用是因为我们并没有这个parent指针，当然我们还是有trick方式的，就是我们从root开始走，直到找到这个node p，同时我们记录一路上看到的比p.val大的值，这样最后一个就是它的successor.其中最低的那一个就是他的successor.\n\n\n\n```python\nclass Solution(object):\n    def inorderSuccessor(self, root, p):\n        \"\"\"\n        :type root: TreeNode\n        :type p: TreeNode\n        :rtype: TreeNode\n        \"\"\"\n        def minNode(node):\n            while node.left:\n                node = node.left\n            return node\n            \n        def searchP(root, p):\n            if not root or root.val == p.val:\n                return None\n            else:\n                succ = None\n                while root != None and p.val != root.val:\n                    if p.val < root.val:\n                        succ = root\n                        root = root.left\n                    else:\n                        root = root.right\n                return succ\n\n        if p.right:\n            return minNode(p.right)\n        else:\n            return searchP(root, p)\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/286._Walls_and_Gates.md",
    "content": "### 286. Walls and Gates\n\n\n\n题目： \nhttps://leetcode.com/problems/walls-and-gates/\n\n\n\n难度 : Medium\n\n\n\n思路：\n\n乍一看feel like all pairs shortest path.\n\nnaive的想法是针对所有为0的点做all pairs shortest path，然后最终得到的就是把INF替换保留最小的。时间复杂度是0的个数* BFS\n\n\n\nnaive的想法AC \n\n```\nclass Solution(object):\n    def wallsAndGates(self, rooms):\n        \"\"\"\n        :type rooms: List[List[int]]\n        :rtype: void Do not return anything, modify rooms in-place instead.\n        \"\"\"\n        def legal(x,y):\n            return x >= 0 and x < row and y >= 0 and y < col and rooms[x][y] != -1\n\n        def bfs(rooms, i, j):\n            queue = []\n            queue.append((i,j))\n\n            while queue:\n                (x,y) = queue.pop()\n\n                if legal(x-1,y) and rooms[x-1][y] > rooms[x][y] + 1:\n                    rooms[x-1][y] = rooms[x][y] + 1\n                    queue.append((x-1,y))\n                if legal(x+1,y) and rooms[x+1][y] > rooms[x][y] + 1 :\n                    rooms[x+1][y] = rooms[x][y] + 1\n                    queue.append((x+1,y))\n                if legal(x,y-1) and rooms[x][y-1] > rooms[x][y] + 1:\n                    rooms[x][y-1] = rooms[x][y] + 1\n                    queue.append((x,y-1))\n                if legal(x,y+1) and rooms[x][y+1] > rooms[x][y] + 1  :\n                    rooms[x][y+1] = rooms[x][y] + 1\n                    queue.append((x,y+1))\n\n\n        row = len(rooms)\n        col = len(rooms[0]) if row else 0\n\n        for i in range(row):\n            for j in range(col):\n                if rooms[i][j] == 0:\n                    bfs(rooms,i,j)\n```\n\n\n\n复习一下BFS的伪码\n\nfrom wikipedia, 一开始有点小迷茫，那就是为什么没有keep一个visited的数据结构，但是随即反应过来，其实`n.distance == INFINITY` 已经是check它是否被visited 过了，我以上的代码并没有做这个操作，但是因为是格子状以及我仅在检查是否更小，所以也能AC.\n\n```\nBreadth-First-Search(Graph, root):\n    \n    for each node n in Graph:            \n        n.distance = INFINITY        \n        n.parent = NIL\n\n    create empty queue Q      \n\n    root.distance = 0\n    Q.enqueue(root)                      \n\n    while Q is not empty:        \n        current = Q.dequeue()\n        for each node n that is adjacent to current:\n            if n.distance == INFINITY:\n                n.distance = current.distance + 1\n                n.parent = current\n                Q.enqueue(n)\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/287._Find_the_Duplicate_Number.md",
    "content": "\n# 287.Find the Duplicate Number 找到重复的数\n\n### 难度：Medium\n\n## 刷题内容\n\n> 原题链接\n\n - 中文：https://leetcode-cn.com/problems/find-the-duplicate-number\n - 英文：https://leetcode.com/problems/find-the-duplicate-number\n \n> 内容描述\n\n```\n给定一个包含 n + 1 个整数的数组 nums，其数字都在 1 到 n 之间（包括 1 和 n），可知至少存在一个重复的整数。假设只有一个重复的整数，找出这个重复的数。\n\n示例 1:\n输入: [1,3,4,2,2]\n输出: 2\n\n示例 2:\n输入: [3,1,3,4,2]\n输出: 3\n\n说明：\n不能更改原数组（假设数组是只读的）。\n只能使用额外的 O(1) 的空间。\n时间复杂度小于 O(n2) 。\n数组中只有一个重复的数字，但它可能不止重复出现一次。\n```\n\n## 解题方案\n\n> 思路 1\n\n实际上，我们在阅读完题目的时候，直观感觉，题目不是很难。但是，在我们看到下面的说明，也就是对我们题目的限制条件的时候，会猛然发现，题目的难度瞬间提升了好多倍。\n\n下面我列出咱们需要注意的点：\n - 包含 n+1 个整数的数组\n - 数组中的数字都在 1 到 n 之间（包括 1 和 n ，但是可以不连续，比如 [1,4,4,3,4]）\n - 重复的数字，可以重复很多次，并不限于重复 1 次，2次，3次..\n - 不能更改原数组（这条是最要命的，原本我的想法是，我们可以排序完成之后，再进行二分查找法，碍于这个规定，无法进行）\n - 只能用额外的 O(1) 的空间。（O(1) 空间的意思是不会因数组的长度改变而改变，对应本题就是不管我们的数组多长，我们能用的额外控制只能是 m 这个m 是一个确定的数，不会随着 n 的改变而改变。）\n - 时间的复杂度小于 $O(n^2)$\n \n注意的点差不多就是上面所说的了。\n\n```\n这个思路我们使用 二分查找（binary search）+ 鸽笼原理（Pigeonhole Principle）\n参考维基百科关于鸽笼原理的词条链接：https://en.wikipedia.org/wiki/Pigeonhole_principle\n\n\"不允许修改数组\" 与 \"常数空间复杂度\" 这两个限制条件意味着：禁止排序，并且不能使用 Map 等数据结构\n\n小于 O(n^2) 的运行时间复杂度可以联想到使用二分将其中的一个 n 化简为 log n\n可以参考 LeetCode Discuss:https://leetcode.com/discuss/60830/python-solution-explanation-without-changing-input-array\n\n二分枚举答案范围，使用鸽笼原理进行检验\n\n根据鸽笼原理，给定 n+1 个范围为 [1, n]的整数，其中一定存在数字出现至少两次。\n假设枚举的数字为 n / 2 ：\n遍历数组，若数组中不大于 n / 2 的数字个数超过 n / 2 ，则可以确定 [1, n/2] 范围内一定有解，否则可以确定解落在 (n/2, n]范围内。\n```\n\n也可以这样分析一下：\n```\n\n如果n 是5，那么就会有1 2 3 4 5 一共5个数字的可能，而array size 是6，那么其中一个数字肯定会至少出现两次。\n\n如果没有重复的数字，小于等于1的数字 出现的次数 等于 1；\n\n小于等于2的数字 出现的次数 等于 2；\n\n... 同理3；4；5。\n\n如果有重复的数字，如果重复的是1，那么 小于等于1的数字 出现的次数 肯定大于1；\n\n基于这个理论，我们可以在1 2 3 4 5 选出一个 mid， 遍历array来count 小于等于mid 的数字个数 小于等于 它自己mid 还是 大于 mid？\n\n如果count 小于等于mid， 说明 1 到 mid 这些数字 没有重复项， 重复项在 右半边 mid 到n， 所以缩小到右半边继续搜索；\n\n如果count 大于mid， 说明  1 到 mid 这些数字中 有重复项，缩小到 左半边继续搜索。\n```\n\n\n```python\nclass Solution(object):\n    def findDuplicate(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        low, high = 1, len(nums) - 1\n        while low <= high:\n            mid = (low + high) >> 1\n            cnt = sum(x <= mid for x in nums)\n            if cnt > mid:\n                high = mid - 1\n            else:\n                low = mid + 1\n        return low\n    \ns = Solution()\nnums = [1,2,3,3]\nprint(s.findDuplicate(nums))\n```\n\n    3\n    \n\n思路 1 的解法是时间复杂度为 $O(nlogn)$ 的解法，思路 2 则是时间复杂度为 $O(n)$ ，但是相对来说，是投机取巧了些。\n> 思路 2\n\n一次遍历统计，另一次遍历输出即可。\n\n\n```python\nclass Solution(object):\n    def findDuplicate(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        dic = dict()\n        for n in nums:\n            dic[n] = dic.get(n, 0) + 1\n            if dic[n] >= 2:\n                return n\n\ns = Solution()\nnums = [1,2,3,3]\nprint(s.findDuplicate(nums))\n```\n\n    3\n    \n\n> 思路 3 \n\n思路 3 则是更加完整的 $O(n)$ 的解法，现在我还没有完全搞懂，我先写在下面吧，大佬们可以提前学习了解。\n\n\n```python\nclass Solution(object):\n    def findDuplicate(self, nums):\n        # The \"tortoise and hare\" step.  We start at the end of the array and try\n        # to find an intersection point in the cycle.\n        slow = 0\n        fast = 0\n    \n        # Keep advancing 'slow' by one step and 'fast' by two steps until they\n        # meet inside the loop.\n        while True:\n            slow = nums[slow]\n            fast = nums[nums[fast]]\n    \n            if slow == fast:\n                break\n    \n        # Start up another pointer from the end of the array and march it forward\n        # until it hits the pointer inside the array.\n        finder = 0\n        while True:\n            slow   = nums[slow]\n            finder = nums[finder]\n    \n            # If the two hit, the intersection index is the duplicate element.\n            if slow == finder:\n                return slow\n            \ns = Solution()\nnums = [1,2,3,3]\nprint(s.findDuplicate(nums))\n```\n\n    3\n    \n"
  },
  {
    "path": "docs/leetcode/python/289._game_of_life.md",
    "content": "### 289. Game of Life\n\n题目： \n<https://leetcode.com/problems/game-of-life/>\n\n\n难度 : Medium\n\n\n直接一上来就没有考虑solve it in-place,考虑的是便利，简直是born for 便利\n\n首先我把board拓宽了，宽，高各增加了两排。\n\n因为这样求neighbor方便，针对原来的borad，现在新的big 对于 1 -> n-1 的部分\n\n全都有八个neighbor，用了一个2d array来记录nbrs，再根据当下的nbr来判断更新，因为不能一边在board上loop一边更新.\n\nAC的效率还ok：\n\n```python\nclass Solution(object):\n    def gameOfLife(self, board):\n        \"\"\"\n        :type board: List[List[int]]\n        :rtype: void Do not return anything, modify board in-place instead.\n        \"\"\"\n        def liveNeighbors(i,j):\n            return big[i-1][j-1] + big[i-1][j] + big[i-1][j+1] + big[i][j-1] + big[i][j+1] + big[i+1][j-1] + big[i+1][j] + big[i+1][j+1]\n        \n        if board == [[]] : return\n        row = len(board)\n        col = len(board[0]) \n\n        nbrs = [[0 for j in range(col)] for i in range(row)]\n        big = [[ 0 for j in range(col+2) ] for i in range(row+2)]\n        for i in range(1,row+1):\n            for j in range(1,col+1):\n                big[i][j] = board[i-1][j-1]\n            \n        for i in range(1,row+1):\n            for j in range(1,col+1):\n                nbrs[i-1][j-1] = liveNeighbors(i,j)\n    \n        for i in range(row):\n            for j in range(col):\n                if board[i][j] == 1:                \n                    if nbrs[i][j] < 2:\n                        board[i][j] = 0\n                    elif nbrs[i][j] == 2 or nbrs[i][j] == 3:\n                        board[i][j] = 1\n                    else:\n                        board[i][j] = 0\n                else:\n                    if nbrs[i][j] == 3:\n                        board[i][j] = 1\n            \n```\n\n谷歌了一下，大家都用到了temp 2d array嘛，哼(ˉ(∞)ˉ)唧。好吧，空间复杂度比我小。\n\n\n\n很多的解法都是一样开了一个二维数组，即使没有像我一样扩展board.因为问题在于不能一边更新board 一边来做。\n\n看了一下这边的思路：\n\n<https://www.hrwhisper.me/leetcode-game-of-life/>\n\n<http://www.cnblogs.com/grandyang/p/4854466.html>\n\n\n\n不开数组\n\n我们可以使用状态机转换 o(╯□╰)o  感觉不知道在听什么 还是很迷茫的感觉， in-place AC代码\n\n```python\nclass Solution(object):\n    def gameOfLife(self, board):\n        \"\"\"\n        :type board: List[List[int]]\n        :rtype: void Do not return anything, modify board in-place instead.\n        \"\"\"\n        row = len(board)\n        col = len(board[0]) if row else 0\n\n        dx = [-1,-1,-1,0,1,1,1,0]\n        dy = [-1,0,1,1,1,0,-1,-1]\n    \n        for i in range(row):\n            for j in range(col):\n                cnt = 0\n                for k in range(8):\n                    x, y = i + dx[k], j + dy[k]\n                    if x >=0 and x < row and y >=0 and y < col and (board[x][y] == 1  or board[x][y] == 2):\n                        cnt += 1\n\n                if board[i][j] and (cnt < 2 or cnt > 3):\n                    board[i][j] = 2\n                elif board[i][j] == 0 and cnt == 3:\n                    board[i][j] = 3\n\n        for i in range(row):\n            for j in range(col):\n                board[i][j] %= 2\n                   \n   \n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/290._word_pattern.md",
    "content": "###290. Word Pattern\n\n题目： \n<https://leetcode.com/problems/word-pattern/>\n\n\n难度 : Easy\n\n4.pattern = \"abba\", str = \"dog dog dog dog\" should return false.\n\n因为这个的限制，所以中间加了一个loop用来查询是否这个a对应的已经出现过了。\n\n不过其实也可以用两个dictionary来处理，可以O(n^3) -> O(n^2)\n\n\n```\nclass Solution(object):\n    def wordPattern(self, pattern, str):\n        \"\"\"\n        :type pattern: str\n        :type str: str\n        :rtype: bool\n        \"\"\"\n        strList = str.split(' ')\n        if len(pattern) != len(strList):\n            return False\n        lookup = {}\n        for i in range(len(strList)):\n            if pattern[i] not in lookup:\n                for key in lookup:\n                    if lookup[key] == strList[i]:\n                        return False\n                lookup[pattern[i]] = strList[i]\n            elif lookup[pattern[i]] != strList[i]:\n                return False\n                \n        return True\n       \n```\n\n\n另外看到一段非常简短代码，使用了map函数，有待学习\n"
  },
  {
    "path": "docs/leetcode/python/292._nim_game.md",
    "content": "### 292. Nim Game\n\n题目:\n\n<https://leetcode.com/problems/nim-game/>\n\n\n难度:\n\nEasy\n\n\n对于总是优先开始的那方\n\n\n- 有一到三块，总是赢\n- 有四块，总是输\n- 有五块，总是赢\n\n所以如果自己想赢，总是要迫使对方拿之后，给自己遗留5块，或者三块以及以下。\n\n- 如果是六块：\n\t- 拿一块，对方五块，对方赢\n\t- 拿两块，对方余下四块，我方赢\n\t- 拿三块，余三块，对方赢\n\t\n- 七块：\n\t- 拿三块，余四块，迫使对方输，总是赢\n\n本打算用递归来看，因为对方也可以重复使用这个函数，但是会超时，所以就看了一下hint\n\n\n- n <= 3 能赢 √\n- n == 4 总输 \n- n = 5,6,7 总赢\n- n == 8， 先手如何选，总可以转成5,6,7 对方总会赢\n\n\n所以 n % 4 == 0 时候，先手必输\n\n简直是啊，有些游戏就是这样来必赢的啊，没想到你是这样的题目\n\n\n\n```\nclass Solution(object):\n    def canWinNim(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        return n % 4 != 0\n```\n        \n        \n"
  },
  {
    "path": "docs/leetcode/python/293._Flip_Game.md",
    "content": "### 293. Flip Game\n\n题目:\n<https://leetcode.com/problems/flip-game/>\n\n\n难度:\n\nEasy\n\n\n思路\n\n\n\n\n```python\nclass Solution(object):\n    def generatePossibleNextMoves(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: List[str]\n        \"\"\"\n        res = []\n        if not s or len(s) <= 1:\n            return res\n        for i in range(len(s)-1):\n            if s[i] == '+' and s[i+1] == '+':\n                res.append(s[:i]+'--'+s[i+2:])\n        return res\n```\n\n这里要注意一个点：s[i+2:] 虽然i+2取不到，但是s[i+2:]就是一个空字符串。\n\n"
  },
  {
    "path": "docs/leetcode/python/296._Best_Meeting_Point.md",
    "content": "### 296. Best Meeting Point\n\n题目： \n<https://leetcode.com/problems/best-meeting-point/>\n\n\n\n难度 : Hard\n\n\n\n思路：\n\n提示是先从一维开始，其实一开始是略迷茫的，因为如果两个点，那么只要在这两个之间，一定就是最小值，线段长度。\n\n不过倘若点增加到三个，那么就是第三个点处。\n\n\n\n然后发现了一个很棒的stackoverflow page\n\n<http://stackoverflow.com/questions/10402087/algorithm-for-minimum-manhattan-distance>\n\n\n\n因为一开始理解错误二维数组的输入，以为是给的locs这样的数组，所以直接这样写了，然后发现给的是格子，所以但是还是偷懒这样写了。\n\n\n\nAC 代码\n\n```\nclass Solution(object):\n    def minTotalDistance(self, grid):\n        \"\"\"\n        :type grid: List[List[int]]\n        :rtype: int\n        \"\"\"\n        res = 0\n        locs = []\n\n        m = len(grid)\n        n = len(grid[0]) if m else 0\n\n        for i in range(m):\n            for j in range(n):\n                if grid[i][j] == 1:\n                    locs.append([i,j])\n\n\n        locs.sort(key = lambda point: point[0])\n        x = locs[len(locs)/2][0]\n        for point in locs:\n        \tres += abs(point[0] - x)\n\n        locs.sort(key = lambda point: point[1])\n        y = locs[len(locs)/2][1]\n        for point in locs:\n        \tres += abs(point[1] - y)\n\n        return res\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/298._Binary_Tree_Longest_Consecutive_Sequence.md",
    "content": "### 298. Binary Tree Longest Consecutive Sequence\n\n\n\n\n\n题目： \nhttps://leetcode.com/problems/binary-tree-longest-consecutive-sequence/\n\n\n\n难度 : Medium\n\n\n\n思路：\n\n\n\nTLE代码，每个node求，然后求最大值\n\n```\n# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\nclass Solution(object):\n    def longestConsecutive(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        def consecutive(root):\n        \tif root == None:\n        \t\treturn 0\n        \telse:\n        \t\tleft, right = 0,0\n        \t\tif root.left:\n        \t\t\tif root.left.val == root.val + 1:\n        \t\t\t\tleft = 1 + consecutive(root.left)\n        \t\tif root.right:\n        \t\t\tif root.right.val == root.val + 1:\n        \t\t\t\tright = 1 + consecutive(root.right)\n        \t\treturn max(left, right, 1)\n\n        def dfs(root):\n        \ts = []\n        \ts.append(root)\n        \twhile s:\n        \t\troot = s.pop()\n        \t\tres.append(consecutive(root))\n        \t\tif root.left:\n        \t\t\ts.append(root.left)\n        \t\tif root.right:\n        \t\t\ts.append(root.right)\n        if not root:\n        \treturn 0\n\n        res = []\n        dfs(root)\n        return max(res)\n\n```\n\n\n\n\n\n其实第二次递归，也就是dfs其实是有点多余的？因为可以边走边保存最大值？\n\n因为可以\n\n> - recursion,在参数中包含当前的连续seq长度\n> - 如果left, right child的value是连续的，那么就将长度+1传入下一个call\n\n\n\n\n\nAC代码\n\n```\n# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\nclass Solution(object):\n    def longestConsecutive(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        def dfs(root, curLen):\n            self.result = max(curLen, self.result)\n            if root.left:\n                if root.left.val == root.val + 1:\n                    dfs(root.left, curLen + 1)\n                else:\n                    dfs(root.left, 1)\n            if root.right:\n                if root.right.val == root.val + 1:\n                    dfs(root.right, curLen + 1)\n                else:\n                    dfs(root.right,1)\n                    \n        if not root: return 0\n\n        self.result = 0\n        dfs(root, 1)\n        return self.result\n\n```\n\n\n\n这里值得注意的是这里的self.result其实相当于dfs的全局变量，也是利用了这个才做到边递归边记录边重置。\n\n"
  },
  {
    "path": "docs/leetcode/python/299._bulls_and_cows.md",
    "content": "###299. Bulls and Cows\n\n题目:\n\n<https://leetcode.com/problems/bulls-and-cows/>\n\n\n难度:\n\nEasy\n\n\n我花了很久时间来AC，因为想了边界条件\n\n\n```\nclass Solution(object):\n    def getHint(self, secret, guess):\n        \"\"\"\n        :type secret: str\n        :type guess: str\n        :rtype: str\n        \"\"\"\n        maps = {}\n        for i in range(len(secret)):\n            if secret[i] not in maps:\n                maps[secret[i]] = [i]\n            else:\n                maps[secret[i]].append(i)\n        mapg = {}\n        for i in range(len(guess)):\n            if guess[i] not in mapg:\n                mapg[guess[i]] = [i]\n            else:\n                mapg[guess[i]].append(i)\n\n        print maps, mapg\n\n        a,b = 0,0\n        for key in maps.keys():\n            if key in mapg.keys():\n                common = list(set(mapg[key]) & set(maps[key]))\n                #check for bull\n                a += len(common)\n                mapg[key] = [item for item in mapg[key] if item not in common]\n                maps[key] = [item for item in maps[key] if item not in common]\n                b += min(len(maps[key]), len(mapg[key]))\n        return str(a) + 'A' + str(b) + 'B'        \n```\n\n\n\n\n\n\n\n两种解法都.......\n\n都这么短。。。。。\n我Python还是用的不行啊\n\n\n```\nclass Solution(object):\n    def getHint(self, secret, guess):\n        \"\"\"\n        :type secret: str\n        :type guess: str\n        :rtype: str\n        \"\"\"\n        bull = sum(map(operator.eq, secret, guess))\n        sa = collections.Counter(secret)\n        sb = collections.Counter(guess)\n        cow = sum((sa & sb).values()) - bull\n        return str(bull) + 'A' + str(cow) + 'B'\n```\n\n\nbull = secret与guess下标与数值均相同的数字个数\n\ncow = secret与guess中出现数字的公共部分 - bull\n\n\n\n\n来分析一下这个解法\n\n```\ndef getHint(self, secret, guess):\n    bulls = sum(map(operator.eq, secret, guess))\n    both = sum(min(secret.count(x), guess.count(x)) for x in '0123456789')\n    return '%dA%dB' % (bulls, both - bulls)\n```\n\n首先map的用法是,对于iterable中的每个元素应用function方法，将结果作为list返回\n\n```\n>>> def add100(x):\n...     return x+100\n... \n>>> hh = [11,22,33]\n>>> map(add100,hh)\n[111, 122, 133]\n```\n\n\n\n\n用'1123','0111' 来测试：\n\n\n```\nmap(operator.eq, secret, guess)\n[False, True, False, False]\n```\n就是将equal函数并行应用在两个string上，然后后面的解法也是粗暴简约和厉害\n\n\n参考<http://my.oschina.net/zyzzy/blog/115096>\n"
  },
  {
    "path": "docs/leetcode/python/300._longest_increasing_subsequence.md",
    "content": "### 300. Longest Increasing Subsequence\n\n题目:\n<https://leetcode.com/problems/longest-increasing-subsequence/>\n\n\n难度:\nMedium\n\n\n思路：\n\n典型DP\n\n递推关系式：\n\n对于以num[i]结束的longest increasing subsequence的长度\n\ndp[i] = dp[j] + 1 if num[i] > num[j] else 1\n\n最后loop一圈，求出最长的 \n\nAC 代码\n\n```python\nclass Solution(object):\n    def lengthOfLIS(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        if not nums:\n            return 0\n        dp = [1 for i in range(len(nums))]\n        for i in range(1, len(nums)):\n            for j in range(i):\n                if nums[i] > nums[j]:\n                    dp[i] = max(dp[j]+1, dp[i])\n        return max(dp)\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/303._range_sum_query_-_immutable.md",
    "content": "###303. Range Sum Query - Immutable\n\n题目： \n<https://leetcode.com/problems/range-sum-query-immutable/>\n\n\ntag : DP\n难度 : Easy\n\n\n\n```\nsum(i, j) = nums[i]  j = i\nsum(i,j) = sum[i,j-1] + nums[j] j > i\n\n```\n\nPython代码\n\n```\n\nclass NumArray(object):\n    def __init__(self, nums):\n        \"\"\"\n        initialize your data structure here.\n        :type nums: List[int]\n        \"\"\"\n        self.sums = nums\n        for i in range(1, len(self.sums)):\n            self.sums[i] = self.sums[i-1] + self.sums[i]\n            \n        \n        \n\n    def sumRange(self, i, j):\n        \"\"\"\n        sum of elements nums[i..j], inclusive.\n        :type i: int\n        :type j: int\n        :rtype: int\n        \"\"\"\n        if i == 0 :\n            return self.sums[j]\n        else :\n            return self.sums[j] - self.sums[i-1]\n            \n```"
  },
  {
    "path": "docs/leetcode/python/316._Remove_Duplicate_Letters.md",
    "content": "### 316. Remove Duplicate Letters\n\n题目:\n<https://leetcode.com/problems/remove-duplicate-letters/>\n\n\n难度:\n\nHard\n\n\n思路\n\n这道题让我们移除重复字母，使得每个字符只能出现一次，而且结果要按最优的字母顺序排列，前提是不能打乱其原本的相对位置。\n- 先用remaining统计所有出现字母出现过的次数；\n- res就是输出结果的字母顺序(list)，最后用join连接起来作为返回值(str)；\n- 在stack(set)中的元素意味着其已经出现在最终结果中；\n\n对s中每个字母c，首先看它在stack中有没有出现过：\n1. 如果没有那么只要res最后一个字母的ASCII值大于c，且其剩余次数大于0，就将其在res和stack中删去，不停做此操作\n2. 如果有了那么说明已经出现在最终结果中，只需要将其统计次数减去1以防后面挪动位置要做判断\n\n做完这些后必须要把c加入到stack和res中去，代表c已经加入到最终结果中的目前应该处于的位置\n\n参考[python的colloections之defaultdict模块](https://docs.python.org/2/library/collections.html)\n\n```python\nclass Solution(object):\n    def removeDuplicateLetters(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        remaining = collections.defaultdict(int)\n        for c in s:\n            remaining[c] += 1\n        res, stack = [], set()\n        for c in s:\n            if c not in stack:\n                while res and res[-1] > c and remaining[res[-1]] > 0:\n                    stack.remove(res.pop())\n                res.append(c)\n                stack.add(c)\n            remaining[c] -= 1\n        return ''.join(res)\n```\n还有别的一些优美的解法，参考[stefan的回答](https://leetcode.com/problems/remove-duplicate-letters/discuss/76787)\n\n\n\n```python\n递归贪心版本\nclass Solution(object):\n    def removeDuplicateLetters(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        for c in sorted(set(s)):\n            suffix = s[s.index(c):]\n            if set(suffix) == set(s):\n                return c + self.removeDuplicateLetters(suffix.replace(c, ''))\n        return ''\n```\n```python\nclass Solution(object):\n    def removeDuplicateLetters(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        result = ''\n        while s:\n            i = min(map(s.rindex, set(s)))\n            c = min(s[:i+1])\n            result += c\n            s = s[s.index(c):].replace(c, '')\n        return result\n```\n\n```python\nclass Solution(object):\n    def removeDuplicateLetters(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        rindex = {c: i for i, c in enumerate(s)}\n        result = ''\n        for i, c in enumerate(s):\n            if c not in result:\n                while c < result[-1:] and i < rindex[result[-1]]:\n                    result = result[:-1]\n                result += c\n        return result\n```\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/319._Bulb_Switcher.md",
    "content": "### 319. Bulb Switcher\n\n题目:\n<https://leetcode.com/problems/Bulb-Switcher/>\n\n\n难度:\n\nMedium\n\n\n思路\n\nbulb代表第一轮结束后的所有灯亮灭的情况，从第二轮开始\n- 如果是最后一轮，则bulb的最后一个灯要switch\n- 对于其他轮，相应的第i-1+C(i)个灯要siwitch，且C为常数，i-1+C(i)必须<=n-1\n\n但是发现这样提交会超时\nLast executed input:\n999999\n\n\n```\nclass Solution(object):\n    def bulbSwitch(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        bulb = [1] * n\n        for i in range(2,n+1):\n            for x in range(i-1, n, i):\n                bulb[x] = 1 if bulb[x] == 0 else 0\n        return bulb.count(1)\n```\n\n原来，这是一道智商碾压题：\n\n> A bulb ends up on iff it is switched an odd number of times. \nBulb i is switched in round d iff d divides i. \nSo bulb i ends up on iff it has an odd number of >divisors. \nDivisors come in pairs, like i=12 has divisors 1 and 12, 2 and 6, and 3 and 4. \nExcept if i is a >square, like 36 has divisors 1 and 36, 2 and 18, 3 and 12, 4 and 9, \nand double divisor 6. So bulb >i ends up on iff and only if i is a square. So just count the square numbers.\n\n大概解释一下，当一个灯泡被执行偶数次switch操作时它是灭着的，当被执行奇数次switch操作时它是亮着的，那么这题就是要找出哪些编号的灯泡会被执行奇数次操作。\n\n现在假如我们执行第i次操作，即从编号i开始对编号每次+i进行switch操作，对于这些灯来说， \n如果其编号j（j=1,2,3,⋯,n）能够整除i，则编号j的灯需要执行switch操作。 \n具备这样性质的i是成对出现的，比如：\n- 12 = 1 * 12， \n- 12 = 2 * 6\n- 12 = 3 * 4\n\n所以编号为12的灯，在第1次，第12次；第2次，第6次；第3次，第4次一定会被执行Switch操作，这样的话，编号为12的灯执行偶数次switch，肯定为灭。 \n这样推出，完全平方数一定是亮着的，因为它有两个相同的因子，总因子数为奇数，如36 = 6 * 6，所以本题的关键在于找完全平方数的个数。\n\n```python\nclass Solution(object):\n    def bulbSwitch(self, n):\n        \"\"\"\n        type n: int\n        rtype: int\n        \"\"\"\n        # The number of full squares.\n        return int(math.sqrt(n))\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/322._Coin_Change.md",
    "content": "### 322. Coin Change\n\n\n\n题目:\n<https://leetcode.com/problems/coin-change/>\n\n难度:\n\nMedium \n\nDP入门\n\n递推方程式: dp[i] = min(dp[i-vj]+1)， vj 是硬币的面额\n\n伪码：\n\n```\nSet Min[i] equal to Infinity for all of i\nMin[0]=0\n\nFor i = 1 to S\n\tFor j = 0 to N - 1\n\tIf (Vj<=i AND Min[i-Vj]+1<Min[i]) \n\t\tThen Min[i]=Min[i-Vj]+1\nOutput Min[S]\n```\n\n\n\nAC代码\n\n```\nclass Solution(object):\n    def coinChange(self, coins, amount):\n        \"\"\"\n        :type coins: List[int]\n        :type amount: int\n        :rtype: int\n        \"\"\"\n        dp = [ float('inf') for i in range(amount+1)]\n\n        dp[0] = 0\n\n        for i in range(amount+1):\n        \tfor coin in coins:\n        \t\tif coin <= i and dp[i-coin] + 1 < dp[i]:\n        \t\t\tdp[i] = dp[i-coin] + 1\n\n        return dp[-1] if dp[-1] != float('inf') else -1\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/323._number_of_connected_components_in_an_undirected_graph.md",
    "content": "#  323. Number of Connected Components in an Undirected Graph\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph\n\n> 内容描述\n\n```\nGiven n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to find the number of connected components in an undirected graph.\n\nExample 1:\n\nInput: n = 5 and edges = [[0, 1], [1, 2], [3, 4]]\n\n     0          3\n     |          |\n     1 --- 2    4 \n\nOutput: 2\nExample 2:\n\nInput: n = 5 and edges = [[0, 1], [1, 2], [2, 3], [3, 4]]\n\n     0           4\n     |           |\n     1 --- 2 --- 3\n\nOutput:  1\nNote:\nYou can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.\n```\n\n## 解题方案\n\n> 思路 1\n\n经典并查集题目，可以去总结部分先看看并查集的概念已经优化\n\n\n```python\nclass Solution(object):\n    def countComponents(self, n, edges):\n        \"\"\"\n        :type n: int\n        :type edges: List[List[int]]\n        :rtype: int\n        \"\"\"\n        def find(x):\n        # if uf[x] != x:\n        # \tuf[x] = find(uf[x])\n            while x != uf[x]:\n                uf[x] = uf[uf[x]]\n                x = uf[x]\n            return uf[x]\n\n        def union(x, y):\n            x_root = find(x)\n            y_root = find(y)\n            uf[x_root] = y_root\n\n        uf = [i for i in range(n)]\n        \n        for (node1, node2) in edges:\n            union(node1, node2)\n\n        res = set([find(i) for i in range(n)])\n        return len(res)\n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/324._Wiggle_Sort_II.md",
    "content": "### 324. Wiggle Sort II\n\n\n\n题目:\n<https://leetcode.com/problems/wiggle-sort-ii/>\n\n\n难度:\nMedium\n\n思路：\n\n首先这道题和[Wiggle Sort](https://github.com/Lisanaaa/thinking_in_lc/blob/master/280._Wiggle_Sort.md)要求不一样，不能有等于，\n所以如果碰到一串```‘1,1,1,1,1,1’```，当调换顺序时候还是不会满足。\n\n因此我们用新方法，首先将原数组排序，然后大的那一半数字降序插在奇数```index```上，小的那一半数字降序插在偶数```index```上\n\n\n```python\nclass Solution(object):\n    def wiggleSort(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: void Do not return anything, modify nums in-place instead.\n        \"\"\"\n        nums.sort()\n        half = len(nums[::2])\n        nums[::2], nums[1::2] = nums[:half][::-1], nums[half:][::-1]\n```\n\n\n### Follow up\nO(n) time, O(1) space\n\n思路：\n首先想到的是将我们上面的排序方法用堆排序实现即可，建堆O(n)，调整堆O(lgN)\n\n\n```python\n\n```\n"
  },
  {
    "path": "docs/leetcode/python/326._power_of_three.md",
    "content": "### 326. Power of Three\n\n题目： \n<https://leetcode.com/problems/power-of-three/>\n\n\n\n\n难度 : Easy\n\n\n直接就上的递归\n\n```python\nclass Solution(object):\n    def isPowerOfThree(self,n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        if n <= 0:\n            return False\n        if n == 1:\n            return True\n        if n % 3 == 0:\n            return self.isPowerOfThree(n/3)\n        return False\n       \n```\n\n有一个follow up，可否不用 loop/recursion\n\n看到了取巧的办法，因为是Given an integer,是有范围的（<2147483648),存在能输入的最大的3的幂次，即 3^19=1162261467。\n\n只用检查是否能被这个数整除\n\n\n```python\nclass Solution(object):\n    def isPowerOfThree(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        return n > 0 and pow(3, 19) % n == 0\n        \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/328._odd_even_linked_list.md",
    "content": "###328. Odd Even Linked List\n\n题目:\n<https://leetcode.com/problems/odd-even-linked-list/>\n\n\n难度:\n\nMedium \n\n\n想法：因为相对顺序保持不变，所以可以拆list，然后再组合在一起？这样是满足题目要求的，因为linked list不像array，我们操作的时候只是用指向，没有分配新的空间。\n\n```\n\nclass Solution(object):\n    def oddEvenList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if head == None or head.next == None or head.next.next == None:\n        \treturn head\n\n        oddDummy = ListNode(-1)\n        oddDummy.next = head\n\n        evenDummy = ListNode(-1)\n        evenDummy.next = head.next\n\n        oddCur = oddDummy.next\n        evenCur = evenDummy.next\n\n        cur = head.next.next\n        while cur:\n        \toddCur.next = cur\n        \toddCur = oddCur.next\n        \tevenCur.next = cur.next\n        \tevenCur = evenCur.next\n        \tif cur.next:\n        \t\tcur = cur.next.next \n        \telse:\n        \t\tcur = cur.next\n        oddCur.next = evenDummy.next\n        # print oddDummy.next.val\n        return oddDummy.next\n\n```\n\n\n\n\n看别人的优雅代码\n\n```\nclass Solution(object):\n    def oddEvenList(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        if head == None:\n            return head\n\n        # odd used to keep track of the tail of odd nodes\n        odd = oddHead = head\n        # record how many swaps happend\n        even = evenHead = head.next\n        while even and even.next:\n            odd.next = even.next\n            odd = odd.next\n            even.next = odd.next \n            even = even.next\n        odd.next = evenHead\n        return head \n```\n\nintuitive and concise\n\n\n```\n1 → 2 → 3 → 4 → 5 → NULL\n\n一开始\n\n 1    → 2     → 3 →    4    → 5    → NULL\nodd   even     even.next\n\n\n1 → 3  →    4    → 5    → NULL\n    odd     ↑\n    2   -   \n    \n \n1 → 3  →    4    → 5    → NULL\n    odd     \n    2   -   even\n    \n\n再loop一次：\n\n            |   -----------  \n    |   ---------  ↓       ↓\n1 → 3       4      5    → NULL\n                 odd       ↑\n    2   -   ↑              even\n    \n\n最后一步，再将两个odd的最后一个和evenHead连接起来，完工\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/334._increasing_triplet_subsequence.md",
    "content": "###334. Increasing Triplet Subsequence\n\n题目:\n<https://leetcode.com/problems/increasing-triplet-subsequence/>\n\n\n难度:\nMedium\n\n\n思路：\n\n用longest increasing subsequence来求，超时\n\n```\nclass Solution(object):\n    def increasingTriplet(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        if not nums: return False\n        n = len(nums)\n        dp = [1 for i in range(n)]\n        for i in range(1,n):\n        \tfor j in range(i):\n        \t\tif nums[i] > nums[j] :\n        \t\t\tdp[i] = max(dp[i],dp[j] + 1)\n        \t\t\tif dp[i] >= 3:\n        \t\t\t\treturn True\n\n        return False\n```\n\n于是转而用Third Maximum Number的方法，维护一个当前最小和当前第二小，当碰到当前比较大，返回True，否则一圈走下来依旧不能满足，返回false.\n\n想一下，如果不是求三个增长，如果是求两个的话，那么一定想到的是保存当前最小值，那么一旦后方遇到一个比较大的，就这样处理掉了。\n\n所以对于任何一个num来说，有三种可能：\n\n- 小于当前的最小值，那么更新当前最小值\n- 小于当前第二小值，更新当前第二小值\n- 如果以上两种都不是，那么是大于当前第二小值和最小值，于是这样就true\n\n所以是求四个增长也是类似的么\n\nAC代码\n\n```\nclass Solution(object):\n    def increasingTriplet(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        # m - min, sm - second min\n        m, sm = float('inf'), float('inf')\n\n        for num in nums:\n        \tprint m, sm\n        \tif m >= num:\n        \t\tm = num\n        \telif sm >= num:\n        \t\tsm = num\n        \telse:\n        \t\treturn True\n        return False\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/337._house_robber_iii.md",
    "content": "###337. House Robber III\n\n\n题目:\n<https://leetcode.com/problems/house-robber-iii/>\n\n\n难度:\nMedium\n\n思路：\n\n参考\n<https://www.hrwhisper.me/leetcode-house-robber-iii/>\n\n这个解法好像有点厉害\n\n从root开始抢起来，最大能抢到的两个可能： 抢root和不抢root\n\n- rob_root = max(rob_L + rob_R , no_rob_L + no_nob_R + root.val)\n- no_rob_root = rob_L + rob_R\n\n\n这个递归写起来就很厉害了\n\n\n```\nclass Solution(object):\n    def rob(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        def dfs(root):\n            if not root: return 0, 0\n            rob_L, no_rob_L = dfs(root.left)\n            rob_R, no_rob_R = dfs(root.right)\n            return max(no_rob_R + no_rob_L + root.val , rob_L + rob_R), rob_L + rob_R\n\n        return dfs(root)[0]\n\n```\n\n对于每个node，我们return的是从这个node能抢到的最大值，以及不抢它能获得的最大值，这个递归简直我服\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/338._Counting_Bits.md",
    "content": "### 338. Counting Bits\n\n题目:\n\n<https://leetcode.com/problems/counting-bits/>\n\n难度:\nMedium\n\n\n\n**O(n\\*sizeof(integer))** 算法，其实就是把count of 1 bit拿来用：\n\n```\nclass Solution(object):\n    def countBits(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: List[int]\n        \"\"\"\n        def hammingWeight(n):\n        \tcnt = 0\n        \twhile n != 0:\n        \t\tn &= n -1\n        \t\tcnt += 1\n        \treturn cnt\n\n        res = []\n        for i in range(num+1):\n        \tres.append(hammingWeight(i))\n        return res\n\n```\n\n\n\nDP算法 - to be done\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/339._Nested_List_Weight_Sum.md",
    "content": "### 339. Nested List Weight Sum\n\n\n\n题目:\n<https://leetcode.com/problems/nested-list-weight-sum/>\n\n难度:\nEasy\n\n思路：\n\n一开始没认真读题，直接上手开写：\n\n```\nclass Solution(object):\n    def depthSum(self, nestedList):\n        \"\"\"\n        :type nestedList: List[NestedInteger]\n        :rtype: int\n        \"\"\"\n        def dfs(nestedList):\n        \tfor item in nestedList:\n        \t\tif item.isInteger():\n        \t\t\tself.res += item.getInteger()\n        \t\telse:\n        \t\t\tdfs(item.getList())\n        self.res = 0\n        dfs(nestedList)\n        return self.res\n```\n\n\n\n然后注意到要weight by its depth.\n\n\n\nAC\n\n```\nclass Solution(object):\n    def depthSum(self, nestedList):\n        \"\"\"\n        :type nestedList: List[NestedInteger]\n        :rtype: int\n        \"\"\"\n        def dfs(nestedList,depth):\n        \tfor item in nestedList:\n        \t\tif item.isInteger():\n        \t\t\tself.res += item.getInteger() * depth\n        \t\telse:\n        \t\t\tdfs(item.getList(), depth+1)\n        self.res = 0\n        dfs(nestedList,1)\n        return self.res\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/341._Flatten_Nested_List_Iterator.md",
    "content": "### 341. Flatten Nested List Iterator\n\n\n\n题目:\n<https://leetcode.com/problems/flatten-nested-list-iterator/>\n\n\n\n难度:\nMedium \n\n\n\n```python\nclass NestedIterator(object):\n\n    def __init__(self, nestedList):\n        \"\"\"\n        Initialize your data structure here.\n        :type nestedList: List[NestedInteger]\n        \"\"\"\n        def dfs(nestedList):\n            for item in nestedList:\n                if item.isInteger():\n                    self.stack.append(item.getInteger())\n                else:\n                    dfs(item.getList())\n        self.stack = []\n        dfs(nestedList)\n        \n\n    def next(self):\n        \"\"\"\n        :rtype: int\n        \"\"\"\n        if self.hasNext():\n            return self.stack.pop(0)\n\n\n    def hasNext(self):\n        \"\"\"\n        :rtype: bool\n        \"\"\"\n        return self.stack != []\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/342._Power_of_Four.md",
    "content": "### 342. Power of Four\n\n\n\n题目： \n<https://leetcode.com/problems/power-of-four/>\n\n\n\n难度 : Easy\n\n继续照抄power of three\n\n```python\nclass Solution(object):\n    def isPowerOfFour(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: bool\n        \"\"\"\n        if num <= 0 :\n        \treturn False\n        if num == 1:\n        \treturn True\n        if num % 4 == 0:\n        \treturn self.isPowerOfFour(num/4)\n        return False\n\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/344._reverse_string.md",
    "content": "### 344. Reverse String\n\n\n\n题目:\n<https://leetcode.com/problems/reverse-string/>\n\n\n难度:\nEasy\n\n思路：\n\n不要脸的python AC code:\n\n\n```python\nclass Solution(object):\n    def reverseString(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        return s[::-1]\n```\n\n因为python不支持item assignment\n\n所以如果非要用two pointer来做的话，那么会是这样\n\n```python\nclass Solution(object):\n    def reverseString(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        lst = list(s)\n        n = len(lst)\n        start, end = 0, n - 1\n\n        while start < end:\n        \tlst[end], lst[start]  = lst[start],lst[end]\n        \tstart += 1\n        \tend -= 1\n        return ''.join(lst)\n```\n"
  },
  {
    "path": "docs/leetcode/python/345._Reverse_Vowels_of_a_String.md",
    "content": "### 345. Reverse Vowels of a String\n\n\n题目:\n<https://leetcode.com/problems/Reverse-Vowels-of-a-String/>\n\n\n难度:\n\nEasy\n\n\n\n思路\n\n字符串不可变，所以用list代替，最后join\n\n\n\n```python\nclass Solution(object):\n    def reverseVowels(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        vowels = 'aeiou'\n        string = list(s)\n        i, j = 0, len(s) -1\n        while i <= j:\n            if string[i].lower() not in vowels:\n                i += 1\n            elif string[j].lower() not in vowels:\n                j -= 1\n            else:\n                string[i], string[j] = string[j], string[i]\n                i += 1\n                j -= 1\n        return ''.join(string)\n```\n\n正则版本\n\n```python\nclass Solution(object):\n    def reverseVowels(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        vowels = re.findall('(?i)[aeiou]', s)\n        return re.sub('(?i)[aeiou]', lambda m: vowels.pop(), s)\n```\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/349._intersection_of_two_arrays.md",
    "content": "### 349. Intersection of Two Arrays\n\n题目:\n<https://leetcode.com/problems/intersection-of-two-arrays/>\n\n\n难度:\n\nEasy\n\n\n\nPython一句话作弊\n\n```python\nclass Solution(object):\n    def intersection(self, nums1, nums2):\n        \"\"\"\n        :type nums1: List[int]\n        :type nums2: List[int]\n        :rtype: List[int]\n        \"\"\"\n        return list(set(nums1).intersection(nums2))\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/350._intersection_of_two_arrays_ii.md",
    "content": "### 350. Intersection of Two Arrays II\n\n题目:\n\n<https://leetcode.com/problems/intersection-of-two-arrays-ii/>\n\n\n难度:\n\nEasy\n\n\nsort之后用了双指针来走和看\n\n\n```python\nclass Solution(object):\n    def intersect(self, nums1, nums2):\n        \"\"\"\n        :type nums1: List[int]\n        :type nums2: List[int]\n        :rtype: List[int]\n        \"\"\"\n        nums1.sort()\n        nums2.sort()\n        \n        l1 = len(nums1)\n        l2 = len(nums2)\n        \n        p1 = 0\n        p2 = 0\n        \n        res = []\n        \n        while p1 < l1 and p2 < l2:\n            if nums1[p1] < nums2[p2]:\n                p1 += 1\n            elif nums1[p1] > nums2[p2]:\n                p2 += 1\n            else:\n                res.append(nums1[p1])\n                p1 += 1\n                p2 += 1\n        return res\n```\n\n两行版本\n```python\nclass Solution(object):\n    def intersect(self, nums1, nums2):\n        \"\"\"\n        :type nums1: List[int]\n        :type nums2: List[int]\n        :rtype: List[int]\n        \"\"\"\n        a, b = map(collections.Counter, (nums1, nums2))\n        return list((a & b).elements())\n```\n\n\n\n\n\n\n        \n"
  },
  {
    "path": "docs/leetcode/python/353._Design_Snake_Game.md",
    "content": "### 353.  Design Snake Game\n\n\n\n题目:\n\n<https://leetcode.com/problems/design-snake-game/>\n\n难度： Medium\n\n思路：\n\n纯正单纯方式\n\n在TLE边缘AC\n\nAC代码\n\n\n\n```\nclass SnakeGame(object):\n\n    def __init__(self, width,height,food):\n        \"\"\"\n        Initialize your data structure here.\n        @param width - screen width\n        @param height - screen height \n        @param food - A list of food positions\n        E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0].\n        :type width: int\n        :type height: int\n        :type food: List[List[int]]\n        \"\"\"\n        self.width = width\n        self.height = height\n        self.food = food\n        self.snake = [[0,0]]\n        self.score = 0\n        \n\n    def move(self, direction):\n        \"\"\"\n        Moves the snake.\n        @param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down \n        @return The game's score after the move. Return -1 if game over. \n        Game over when snake crosses the screen boundary or bites its body.\n        :type direction: str\n        :rtype: int\n        \"\"\"\n\n        nextx, nexty = self.snake[0]\n\n        if direction == 'U':\n            nextx -= 1\n        if direction == 'L':\n            nexty -=1\n        if direction == 'R':\n            nexty +=1\n        if direction == 'D':\n            nextx +=1\n\n        # nextx, nexty has food\n        if self.food and [nextx,nexty] == self.food[0]:\n            self.snake.insert(0,[nextx,nexty])\n            self.food = self.food[1:]\n            self.score += 1\n        # netx, nety outside boundary\n        else:\n            self.snake = self.snake[:-1]\n            self.snake.insert(0,[nextx,nexty])\n            if nextx < 0 or nextx > self.height - 1 or nexty < 0 or nexty > self.width - 1:\n                    return -1\n            noDupes = []\n\n            for snakePt in self.snake:\n                # print snakePt,\n                if snakePt not in noDupes:\n                    noDupes.append(snakePt)\n            # print 'snake', self.snake\n            # print 'noDpues', noDupes\n            if len(noDupes) < len(self.snake):\n                return -1\n        return self.score\n\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/361._Bomb_Enemy.md",
    "content": "### 361. Bomb Enemy\n\n题目:\n<https://leetcode.com/problems/bomb-enemy/>\n\n\n难度:\n\nMedium\n\n\n思路\n\n1. 首先，从每一行开始，从左到右，计算E的个数，然后一碰到W就将row_hits重置为0，一碰到0就将row_hits赋值给他\n2. 然后，从每一行开始，从右到左，原操作不变，唯一是碰到0的时候加上row_hits而不是直接等于row_hits\n3. 接下来，就是跟第二步一样的操作，只不过是变成了从每一列开始，从上到下\n4. 最后也是跟第二步一样的操作，只不过是变成了从每一列开始，并且是从下到上，然后就是每一次碰到0不但要加上col_hits的值还要决出max_hits\n5. 返回max_hits\n\n时间复杂度是 ```O(m*n) * (m+n)```\n\n\n```python\n        if not grid or len(grid) == 0:\n            return 0\n        max_hits = 0\n        nums = [[0 for i in range(len(grid[0]))] for j in range(len(grid))]\n        \n        for i in range(len(grid)):\n            row_hits = 0\n            for j in range(len(grid[0])):\n                if grid[i][j] == 'E':\n                    row_hits += 1\n                elif grid[i][j] == 'W':\n                    row_hits = 0\n                else:\n                    nums[i][j] = row_hits\n        \n        for i in range(len(grid)):\n            row_hits = 0\n            for j in range(len(grid[0])-1, -1, -1):\n                if grid[i][j] == 'E':\n                    row_hits += 1\n                elif grid[i][j] == 'W':\n                    row_hits = 0\n                else:\n                    nums[i][j] += row_hits\n                           \n        for i in range(len(grid[0])):\n            col_hits = 0\n            for j in range(len(grid)):\n                if grid[j][i] == 'E':\n                    col_hits += 1\n                elif grid[j][i] == 'W':\n                    col_hits = 0\n                else:\n                    nums[j][i] += col_hits\n\n        for i in range(len(grid[0])):\n            col_hits = 0\n            for j in range(len(grid)-1, -1, -1):\n                if grid[j][i] == 'E':\n                    col_hits +=1\n                elif grid[j][i] == 'W':\n                    col_hits = 0\n                else:\n                    nums[j][i] += col_hits\n                    max_hits = max(max_hits, nums[j][i])\n\n\n        return max_hits\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/364._Nested_List_Weight_Sum_II.md",
    "content": "### 364. Nested List Weight Sum II\n\n\n\n题目:\n<https://leetcode.com/problems/nested-list-weight-sum-ii/>\n\n难度:\nMedium \n\n思路：\n\n\n\n跟 Nested List Weight Sum I 的区别是这个是从不是数depth，是数层的高度：\n\n\n\n比较naive的AC代码：\n\n```\nclass Solution(object):\n    def depthSumInverse(self, nestedList):\n        \"\"\"\n        :type nestedList: List[NestedInteger]\n        :rtype: int\n        \"\"\"\n        def level(nestedList,height):\n            self.level = max(height, self.level)\n            for item in nestedList:\n                if not item.isInteger():\n                    level(item.getList(), height + 1)\n\n        def dfs(nestedList, height):\n        \tfor item in nestedList:\n        \t\tif item.isInteger():\n        \t\t\tself.res += item.getInteger() * height\n        \t\telse:\n        \t\t\tdfs(item.getList(),height - 1)\n        \n        self.level = 1\n        self.res = 0\n        level(nestedList,1)\n        dfs(nestedList, self.level)\n        return self.res\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/366._Find_Leaves_of_Binary_Tree.md",
    "content": "### 366.  Find Leaves of Binary Tree\n\n\n\n题目： \n\n<https://leetcode.com/problems/find-leaves-of-binary-tree/>\n\n\n\n难度 :Medium\n\n\n\n按照它的要求，老老实实写了两个递归 findleaf 和 deleteleaf， 再组合起来\n\n\n\nAC代码\n\n```python\nclass Solution(object):\n    def findLeaves(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: List[List[int]]\n        \"\"\"\n        def findLeaf(root):\n            if not root:\n                return []\n            elif not root.left and not root.right:\n                return [root.val]\n            else:\n                return findLeaf(root.left) + findLeaf(root.right)\n        def removeLeaf(root):\n            if not root:\n                return None\n            elif not root.left and not root.right:\n                return None\n            else:\n                if root.left:\n                    root.left = removeLeaf(root.left)\n                if root.right:\n                    root.right = removeLeaf(root.right)\n                return root\n        res = []\n        while root:\n            res.append(findLeaf(root))\n            root = removeLeaf(root)\n        return res\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/367._valid_perfect_square.md",
    "content": "###367. Valid Perfect Square\n\n题目:\n\n<https://leetcode.com/problems/valid-perfect-square/>\n\n\n难度:\n\nMedium\n\n\n直接用循环做也可以AC\n\n\n```\nclass Solution(object):\n    def isPerfectSquare(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: bool\n        \"\"\"\n        if num == 1 or num == 4 : return True\n        for i in xrange(num//2):\n            if i*i == num:\n                return True\n            elif i*i > num:\n                return False\n        return False\n                \n```\n\n然后发现有传说中的牛顿法\n\n有待阅读，然后还有二分法\n\n```\n    r = x\n    while r*r > x:\n        r = (r + x/r) / 2\n    return r*r == x\n```"
  },
  {
    "path": "docs/leetcode/python/369._Plus_One_Linked_List.md",
    "content": "### 369.Plus One Linked List\t\n\n题目： \n<https://leetcode.com/problems/plus-one-linked-list/>\n\n难度 : Medium\n\n\n\n类似题目： plus one，plus one 用递归和循环写了，对于linked list，因为most significant digit在首位，递归写起来不方便，用循环尝试，然后代码并没有实质上的区别。\n\n\n\n```\nclass Solution(object):\n    def plusOne(self, head):\n        \"\"\"\n        :type head: ListNode\n        :rtype: ListNode\n        \"\"\"\n        lst = []\n        cur = head \n\n        while cur:\n        \tlst.append(cur)\n        \tcur = cur.next\n\n        carry = 1\n        for i in range(len(lst)-1,-1,-1):\n        \tlst[i].val += carry\n        \tif lst[i].val < 10:\n        \t\tcarry = 0\n        \t\tbreak\n        \telse:\n        \t\tlst[i].val -= 10\n\n        if carry == 1:\n        \tnode = ListNode(1)\n        \tnode.next = head\n        \treturn node\n        else:\n        \treturn head \n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/371._sum_of_two_integers.md",
    "content": "###371. Sum of Two Integers\n\n题目:\n<https://leetcode.com/problems/sum-of-two-integers/>\n\n\n难度:\n\nEasy\n\n\n思路\n\n\n谷歌答案\n\n\n位运算\n\n```\nXOR\nx   y output\n0\t0\t0\n1 \t0\t1\n0\t1\t1\n1\t1\t0\n\n\nAND\nx\ty\toutput\n0\t0\t0\n1\t0\t1\n0\t1\t1\n1\t1\t1\t\n\n```\n\n如果对x和y来做加法（x和y都是一位的），那么末位会是x xor y，进位会是x and y\n\n\n\n\n\npython没有左移，用c++来看\n\n```\nclass Solution {\npublic:\n    int getSum(int a, int b) {\n        while (b != 0 ){\n            int c = a & b;\n            a = a ^ b;\n            b = c << 1;\n        }\n        return a;\n    }\n};\n```\n\n实际上看到答案还是没有那么明白的，还是动手算算\n\n\n\n```\na = 6 \t(0110)\nb = 15 \t(1111)\n\n\n1st\n---------\ncarry = a & b = 0110\na = a ^ b = 1001\nb = 1100\n\n\n2nd \n---------\ncarry = a & b = 1000\na = a ^ b =  0101\nb = 10000\n\n\n3rd\n----------\n\ncarry = a & b = 0\na = a ^ b = 10101\nb = 0\n\n这个时候a 的值是2^4 + 2^2 + 2^0 = 16+4+1 = 21  \n```\n\n虽然convence了我自己，但是表示依旧迷茫ing\n\n也知道位运算需要待补啊"
  },
  {
    "path": "docs/leetcode/python/374._Guess_Number_Higher_or_Lower.md",
    "content": "### 374. Guess Number Higher or Lower\n\n题目:\n<https://leetcode.com/problems/guess-number-higher-or-lower/>\n\n\n难度:\n\nEasy\n\n\n思路\n\n二分\n\n```python\nclass Solution(object):\n    def guessNumber(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        l, r = 1, n\n        while l <= r:\n            mid = l + ((r - l) >> 2)\n            if guess(mid) == 1:\n                l = mid + 1\n            elif guess(mid) == -1:\n                r = mid - 1\n            else:\n                return mid\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/377._combination_sum_iv.md",
    "content": "###377. Combination Sum IV\n\n题目:\n\n<https://leetcode.com/problems/combination-sum-iv/>\n\n\n难度:\n\nMedium\n\n\n直接用combination sum的思路： 超时\n\n```\nclass Solution(object):\n    def combinationSum4(self, candidates, target):\n        \"\"\"\n        :type candidates: List[int]\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        def combSum(candidates, target, start, valueList):\n            length = len(candidates)\n            if target == 0 :\n                res.append(valueList)\n            for i in range(start, length):\n                if target < candidates[i]:\n                    return \n                combSum(candidates, target - candidates[i], 0, valueList + [candidates[i]])\n\n        candidates = list(set(candidates))\n        candidates.sort()\n        res = []\n        combSum(candidates, target, 0, [])\n        return len(res)\n```\n\n\n\n\n\n说起来标签是dp,也知道是dp啊,状态转移方程：\n\n\n\n参考:\n\n<http://www.cnblogs.com/grandyang/p/5705750.html>\n\n> \n>\n> 我们需要一个一维数组dp，其中dp[i]表示目标数为i的解的个数，然后我们从1遍历到target，对于每一个数i，遍历nums数组，如果i>=x, dp[i] += dp[i - x]。这个也很好理解，比如说对于[1,2,3] 4，这个例子，当我们在计算dp[3]的时候，3可以拆分为1+x，而x即为dp[2]，3也可以拆分为2+x，此时x为dp[1]，3同样可以拆为3+x，此时x为dp[0]，我们把所有的情况加起来就是组成3的所有情况了\n\n\n\nAC代码\n\n```\nclass Solution(object):\n    def combinationSum4(self, candidates, target):\n        \"\"\"\n        :type candidates: List[int]\n        :type target: int\n        :rtype: List[List[int]]\n        \"\"\"\n        dp = [0 for i in range(target+1)]\n\n        dp[0] = 1\n\n        for i in range(target+1):\n            for candidate in candidates:\n                if i >= candidate:\n                    dp[i] += dp[i - candidate]\n        return dp[-1]\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/378._kth_smallest_element_in_a_sorted_matrix.md",
    "content": "### 378. Kth Smallest Element in a Sorted Matrix\n\n\n\n题目:\n<https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/>\n\n\n难度:\nMedium\n\n\n\n### 思路一：暴力法\n\n```python\nclass Solution(object):\n    def kthSmallest(self, matrix, k):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        tmp = []\n        for row in matrix:\n            for column in row:\n                tmp.append(column)\n        tmp.sort()\n        return tmp[k-1] if tmp and len(tmp)>0 else None\n```\n### 思路二：\n两个tag ： binary search， heap\n\n######先来heap\n\n1. 利用heap,先对第一行所有元素加入heap,每个元素下面同一列的元素必然比他们大\n2. 重复K-1次下面的过程\n\t- 取现在的root\n\t- 将root下面的元素加入heap\n\t\n可以手写一个例子来看\n\n参考：\n<https://lefttree.gitbooks.io/leetcode/content/dataStructure/heap/kthSmallestInMatrix.html>\n\t\n```python\nclass Solution(object):\n    def kthSmallest(self, matrix, k):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        if not matrix:\n        \treturn 0\n\n        heap = []\n        row = len(matrix)\n        col = len(matrix[0])\n\n        for i in range(col):\n        \t# heap store its value and location\n        \theapq.heappush(heap, (matrix[0][i], 0, i))\n\n        print heap\n\n        for j in range(k-1):\n        \tcur = heappop(heap)\n        \tx = cur[1]\n        \ty = cur[2]\n        \tif x+1 < row:\n        \t\theapq.heappush(heap, (matrix[x+1][y],x+1,y))\n\n        return heap[0][0]\n```\n\n### 思路三： heapq一行\n\n```python\nclass Solution(object):\n    def kthSmallest(self, matrix, k):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        return list(heapq.merge(*matrix))[k-1]\n```\n\n### 思路四； binary search\n```python\nclass Solution(object):\n    def kthSmallest(self, matrix, k):\n        \"\"\"\n        :type matrix: List[List[int]]\n        :type k: int\n        :rtype: int\n        \"\"\"\n        l, r = matrix[0][0], matrix[-1][-1]\n        while l <= r:\n            mid = l + ((r - l) >> 2)\n            if sum(bisect.bisect_right(row, mid) for row in matrix) < k:\n                l = mid + 1\n            else:\n                r = mid - 1\n        return l\n```\n"
  },
  {
    "path": "docs/leetcode/python/380._Insert_Delete_GetRandom_O(1).md",
    "content": "### 380. Insert Delete GetRandom O(1)\n\n\n\n题目： \n<https://leetcode.com/problems/insert-delete-getrandom-o1/>\n\n\n\n难度 : Hard\n\n\n\n我的naive TLE代码，关键还是在想这个getRandom,这就不是O(1)的：\n\n\n\n```\nclass RandomizedSet(object):\n\n    def __init__(self):\n        \"\"\"\n        Initialize your data structure here.\n        \"\"\"\n        self.container = {}\n        \n\n    def insert(self, val):\n        \"\"\"\n        Inserts a value to the set. Returns true if the set did not already contain the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        # 1 stands for present\n        if val in self.container and self.container[val] == 1:\n            return False\n        else:\n            self.container[val] = 1\n            return True\n        \n\n    def remove(self, val):\n        \"\"\"\n        Removes a value from the set. Returns true if the set contained the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        if self.container.get(val,0) == 1:\n            self.container[val] = 0\n            return True\n        else:\n            return False\n\n        \n\n    def getRandom(self):\n        \"\"\"\n        Get a random element from the set.\n        :rtype: int\n        \"\"\"\n        import random\n        keys = self.container.keys()\n        rd = random.randint(0, len(keys) - 1)\n        if self.container[keys[rd]] == 1:\n            return keys[rd]\n        elif self.container.get(keys[rd],0) == 0:\n            return self.getRandom()\n```\n\n\n\n也是有[stackoverflow问题界面的题目](http://stackoverflow.com/questions/5682218/data-structure-insert-remove-contains-get-random-element-all-at-o1#comment18171331_5684892)：\n\n> Consider a data structure composed of a hashtable H and an array A. The hashtable keys are the elements in the data structure, and the values are their positions in the array.\n>\n> 1.insert(value): append the value to array and let i be its index in A. Set H[value]=i.\n>\n> 2.remove(value): We are going to replace the cell that contains value in A with the last element in A. let d be the last element in the array A at index m. let i be H[value], the index in the array of the value to be removed. Set A[i]=d, H[d]=i, decrease the size of the array by one, and remove value from H.\n>\n> 3.contains(value): return H.contains(value)\n>\n> 4.getRandomElement(): let r=random(current size of A). return A[r].\n>\n> \n>\n> since the array needs to auto-increase in size, it's going to be amortize O(1) to add an element, but I guess that's OK.\n\n\n\n\n\n按照以答案AC代码\n\n```\nclass RandomizedSet(object):\n\n    def __init__(self):\n        \"\"\"\n        Initialize your data structure here.\n        \"\"\"\n        self.hashtable = {}\n        self.array = []\n        self.arraySize = 0\n\n    def insert(self, val):\n        \"\"\"\n        Inserts a value to the set. Returns true if the set did not already contain the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        # already in the set\n        if val in self.hashtable:\n            return False\n        else:\n            self.hashtable[val] = self.arraySize\n            self.array.append(val)\n            self.arraySize += 1\n            return True\n\n\n    def remove(self, val):\n        \"\"\"\n        Removes a value from the set. Returns true if the set contained the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        if val not in self.hashtable:\n            return False\n        else:\n            removeIdx = self.hashtable[val]\n            if self.arraySize == 1:\n                self.__init__()\n            else:\n                self.array[removeIdx] = self.array[-1]\n                self.hashtable[self.array[-1]] = removeIdx\n                self.arraySize -= 1\n                del self.hashtable[val]\n                del self.array[-1]\n            return True\n\n        \n\n    def getRandom(self):\n        \"\"\"\n        Get a random element from the set.\n        :rtype: int\n        \"\"\"\n        import random\n        rd = random.randint(0, self.arraySize-1)\n        return self.array[rd]\n```\n\n\n\n\n\n最后getRandom也可以写成：\n\n`return random.choice(self.array)`"
  },
  {
    "path": "docs/leetcode/python/381._Insert_Delete_GetRandom_O(1)_-_Duplicates_allowed.md",
    "content": "### 381. Insert Delete GetRandom O(1) - Duplicates allowed\n\n\n\n题目： \n<https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/>\n\n\n\n难度 : Hard\n\n\n\n一开始的想法是在380上面做简单的修改，比如用一个list来存每个数对应的location，但是这样remove会退化为O(N)，然后看到：\n\n- 用 set 这个数据结构就可以贴近O(1)\n- 学了一个新的东西`defaultdict`， 相当于 D.get('key',defaultvalue)\n\n\n\n这个defaultdict的好处就是添加的时候默认的值就是set，但是并不默认这个就存在\n\n\n\nAC代码\n\n```\nclass RandomizedCollection(object):\n\n    def __init__(self):\n        \"\"\"\n        Initialize your data structure here.\n        \"\"\"\n        import collections\n        self.hashtable = collections.defaultdict(set)\n        self.array = []\n\n    def insert(self, val):\n        \"\"\"\n        Inserts a value to the collection. Returns true if the collection did not already contain the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        valin = val not in self.hashtable\n        self.hashtable[val].add(len(self.array))\n        self.array.append(val)\n        return valin \n\n    def remove(self, val):\n        \"\"\"\n        Removes a value from the collection. Returns true if the collection contained the specified element.\n        :type val: int\n        :rtype: bool\n        \"\"\"\n        if val not in self.hashtable:\n            return False\n        else:\n            if self.array[-1] == val:\n                removeIdx = len(self.array) - 1\n                self.hashtable[val].remove(removeIdx)\n            else:\n                # set pop remove arbitrary element\n                removeIdx = self.hashtable[val].pop()\n                self.array[removeIdx] = self.array[-1]\n                self.hashtable[self.array[-1]].remove(len(self.array) - 1)\n                self.hashtable[self.array[-1]].add(removeIdx)\n            if len(self.hashtable[val]) == 0:\n                del self.hashtable[val]\n            del self.array[-1]\n            return True\n        \n\n    def getRandom(self):\n        \"\"\"\n        Get a random element from the collection.\n        :rtype: int\n        \"\"\"\n        import random\n        return random.choice(self.array)\n        \n```\n\n`"
  },
  {
    "path": "docs/leetcode/python/382._linked_list_random_node.md",
    "content": "\n###382. Linked List Random Node\n\n\n题目:\n<https://leetcode.com/problems/linked-list-random-node/>\n\n\n难度:\n\nMedium\n\n\n\ntag：reservoir sampling 水塘抽样 \n\n\n思路：\n\nn选k\n\n\n这样来看，有k个元素，那么这个时候全部选中,当第k+1个元素进来的时候，生成一个随机数r，如果 r <= k，那么用它来替换第r个元素\n\n那么r被替换掉的概率是 1 / k + 1, 不被替换掉的概率是 k / k + 1 (不生成r)\n\nk+2来继续： 被替换掉的概率  1 / k + 2, 不被替换掉的概率  (k + 1) / (k+2)\n\n所以最终被选中的（不被替换掉的概率是） k / n\n\n随机 √\n\n\n针对这道题目来看\n\n- 一开始选head为choice\n- 出现第二个，生成[1,2]之间的随机数，如果r = 2，则用新的来替换choice\n- 出现第三个，生成[1,2,3]之间的随机数，如果r = 3，则替换\n\n再写简单一点就是\n\n\n每次以 1/i 来决定是否用新的元素来替换选中元素，那么就是 i - 1 / i 不替换，它之前被选中的概率就是  1 / i-1 ，所以最终被选中的概率是 1/i\n\n这个对于linked list更优之处在于它不用reverse\n\n时间复杂度 O(N)， 空间复杂度O(K)\n\n\n然后AC\n\n\n```\nclass Solution(object):\n\n    def __init__(self, head):\n        \"\"\"\n        @param head The linked list's head.\n        Note that the head is guaranteed to be not null, so it contains at least one node.\n        :type head: ListNode\n        \"\"\"\n        self.head = head\n\n    def getRandom(self):\n        \"\"\"\n        Returns a random node's value.\n        :rtype: int\n        \"\"\"\n        choice = self.head \n        cur = self.head\n        i = 1\n        while cur.next:\n            cur = cur.next\n            i += 1\n            rd = random.randint(1,i)\n            if rd == i:\n                choice = cur\n        return choice.val\n```\n"
  },
  {
    "path": "docs/leetcode/python/383._ransom_note.md",
    "content": "### 383. Ransom Note\n\n题目： \n<https://leetcode.com/problems/ransom-note/>\n\n\n难度 : Easy\n\n\n\n略微想了一下，用了一个dictionary来存magazine里面的单字出现的个数，然后来对应check是否可以用来组成ransomNote\n\n\n```python\nclass Solution(object):\n    def canConstruct(self, ransomNote, magazine):\n        \"\"\"\n        :type ransomNote: str\n        :type magazine: str\n        :rtype: bool\n        \"\"\"\n        maps = {}\n        for i in magazine:\n            if i in maps:\n                maps[i] += 1\n            else:\n                maps[i] = 1\n        for i in ransomNote:\n            if i not in maps:\n                return False\n            else:\n                maps[i] -= 1\n                if maps[i] < 0:\n                    return False\n        return True\n```\n解法2：\n\n```python\nclass Solution(object):\n    def canConstruct(self, ransomNote, magazine):\n        \"\"\"\n        :type ransomNote: str\n        :type magazine: str\n        :rtype: bool\n        \"\"\"\n        magCounter = collections.Counter(magazine)\n        ranCounter = collections.Counter(ransomNote)\n        for k in ranCounter:\n            if ranCounter.get(k) > magCounter.get(k):\n                return False\n        return True\n```\n"
  },
  {
    "path": "docs/leetcode/python/384._Shuffle_an_Array.md",
    "content": "### 384. Shuffle an Array\n\n\n\n题目： \n<https://leetcode.com/problems/shuffle-an-array/>\n\n\n\n难度 : Medium\n\n\n\n思路：\n\n\n\n这就是洗牌算法吧，洗牌算法几种常见的：\n\n<http://www.cnblogs.com/tudas/p/3-shuffle-algorithm.html>\n\nhttp://www.matrix67.com/blog/archives/879\n\n\n\n也是有wikipedia page的: <https://en.wikipedia.org/wiki/Fisher–Yates_shuffle>\n\n最简单的算法是很容易想到的， O(N^2)\n\n然后就是modern 算法：\n\n\n\n```\n-- To shuffle an array a of n elements (indices 0..n-1):\nfor i from n−1 downto 1 do\n     j ← random integer such that 0 ≤ j ≤ i\n     exchange a[j] and a[i]\n```\n\n\n\n这个感觉还是比较容易证明的，一开始生成的数字 1/n 概率\n\n没选中，下一个 n-1 /n * 1/ n-1  =  1/n， 所以每个位置都是等概率的？\n\n\n\n这个有很妙的点：\n\n比如五个人顺序抽签，只要不uncover 结果，那么就是等概率的。\n\n\n\n但是第一个人抽奖之后uncover结果，比如他没有抽中 → 那么概率就会变。\n\n\n\n\n\n\n\nAC代码：\n\n```\nclass Solution(object):\n\n    def __init__(self, nums):\n        \"\"\"\n        \n        :type nums: List[int]\n        :type size: int\n        \"\"\"\n        self.lst = nums\n        \n\n    def reset(self):\n        \"\"\"\n        Resets the array to its original configuration and return it.\n        :rtype: List[int]\n        \"\"\"\n        return self.lst\n        \n\n    def shuffle(self):\n        \"\"\"\n        Returns a random shuffling of the array.\n        :rtype: List[int]\n        \"\"\"\n        import random\n        res = self.lst[:]\n        n = len(res)\n        for i in range(n-1,0,-1):\n            j = random.randint(0,i)\n            res[i], res[j] = res[j], res[i]\n        return res\n        \n```\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/386._Lexicographical_Numbers.md",
    "content": "# 386. Lexicographical Numbers 字典序排数\n\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/lexicographical-numbers\n* https://leetcode-cn.com/problems/lexicographical-numbers\n\n> 内容描述\n\n```\n\n给定一个整数 n, 返回从 1 到 n 的字典顺序。\n\n例如，\n\n给定 n =1 3，返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。\n\n请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 n 小于等于 5,000,000。\n```\n\n## 解题方案\n\n> 思路 1\n\n那当然是直接转换成string比较排序啊，多么暴力，简单明了, ```beats 66.87%```\n\n- 时间复杂度：O(NlogN)\n- 空间复杂度：O(N)\n```python\nclass Solution(object):\n    def lexicalOrder(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[int]\n        \"\"\"\n        return sorted(range(1, n+1), key=lambda x: str(x))\n```\n\n> 思路 2\n\n其实我们每次只要知道下一个数是啥就行了\n例如对于67这个数，\n- 它的下一个数要么是670（如果670 <= n ）的话\n- 要么是68（如果68 <= n ）的话, 同时还要注意，如果我们例子中n换成200的话，如果当前数字为199，那其实它的下一个数字应该是2而不是200，\n所以这里我们要多加一个判断```(cur + 1) % 10 != 0```, 然后对于尾数是9的数字我们要一直除以10让它尾数不是9之后再加1，即```199 --> 2```的过程\n- 要么是7（当然7肯定小于n了，因为67都出现了）\n\n- 时间复杂度：O(N)\n- 空间复杂度：O(1)\n\n这个方法```beats 94.59%```\n\n```python\nclass Solution(object):\n    def lexicalOrder(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        cur = 1\n        for i in range(n):\n            res.append(cur)\n            if (cur * 10 <= n):\n                cur *= 10\n            elif cur + 1 <= n and (cur + 1) % 10 != 0:\n                cur += 1\n            else:\n                while (cur/10) % 10 == 9:\n                    cur /= 10\n                cur = cur / 10 + 1\n        return res\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/387._first_unique_character_in_a_string.md",
    "content": "### 387. First Unique Character in a String\n\n题目:\n<https://leetcode.com/problems/first-unique-character-in-a-string/>\n\n\n难度:\nEasy\n\n\n\n思路一：\n\nPython作弊法\n\n用Python的Counter模块\n\n可以参考 \n\n<https://pymotw.com/2/collections/counter.html>\n\n\n```python\nclass Solution(object):\n    def firstUniqChar(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        d = collections.Counter(s)\n        for x,c in enumerate(s):\n        \tif d[c] == 1:\n        \t\treturn x\n        return -1\n```\n\n\n思路二：\n\n利用问题的特性，因为只有可能是小写字母，所以可以用一个长度为26的array, 先数一遍char的数量，然后enumerate从左往右又来\n\n```python\nclass Solution(object):\n    def firstUniqChar(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        cnt = [0 for i in range(26)]\n        for char in s:\n        \tcnt[ord(char) - ord('a')] += 1\n\n        for idx, char in enumerate(s):\n        \tif cnt[ord(char) - ord('a')] == 1:\n        \t\treturn idx\n        return -1 \n\n```\n"
  },
  {
    "path": "docs/leetcode/python/388._Longest_Absolute_File_Path.md",
    "content": "### 388. Longest Absolute File Path\n\n\n题目:\n<https://leetcode.com/problems/longest-absolute-file-path/>\n\n\n难度:\n\nMedium\n\n\n\n思路\n\n我们首先观察到每个```文件夹```或者是```文件```前面都会有一个```'\\n'```, 还有对应其层数个数的```'\\t'```. \n- 所以首先根据```'\\n'```分行，然后算出该```文件/文件夹```的层数```depth```\n- 如果是```文件```，我们需要更新```maxlen```\n- 如果是```文件夹```，我们需要更新该```depth```下的```pathlen```\n\n### 程序变量解释\n\n- ```maxlen``` 代表目前最大子串的长度\n- ```pathlen``` 每一个```depth```下对应的```path```长度\n\n#### 特别需要注意的是，```'\\t'```的长度是1\n有的人仍然会有疑问，每次碰到文件夹都直接更新```pathlen```会不会导致本来长的反而变得短了，但是我们可以看到字符串的排版格式，每层```path```都是严格有自己的分级的，\n因此不会出现这样的问题。\n例如:\n- The string ```\"dir\\n\\tsubdir1\\n\\t\\tfile1.ext\\n\\t\\tsubsubdir1\\n\\tsubdir2\\n\\t\\tsubsubdir2\\n\\t\\t\\tfile2.ext\"``` represents:\n```\ndir\n    subdir1\n        file1.ext\n        subsubdir1\n    subdir2\n        subsubdir2\n            file2.ext\n```  \n其最大长度是```32```, ```\"dir/subdir2/subsubdir2/file2.ext\"```\n\n- 如果变成```\"dir\\n\\tsubdir1\\n\\t\\tfile1.ext\\n\\t\\tsubsubdir1\\n\\tsubdir20\\n\\t\\tsubsubdir2\\n\\t\\t\\tfile2.ext\"```，\n\n```\ndir\n    subdir1\n        file1.ext\n        subsubdir1\n    subdir20\n        subsubdir2\n            file2.ext\n```\n\n最大长度就是```33```,\n```\"dir/subdir2/subsubdir20/file2.ext\"```\n\n\n- 如果变成\n```\"dir\\n\\tsubdir1000000000000\\n\\t\\tfile1.ext\\n\\t\\tsubsubdir1\\n\\tsubdir2\\n\\t\\tsubsubdir2\\n\\t\\t\\tfile2.ext\"```\n\n```\ndir\n    subdir10000000000000\n        file1.ext\n        subsubdir1\n    subdir20\n        subsubdir2\n            file2.ext\n```\n\n最大长度就是```34```,```\"dir/subdir10000000000000/file1.ext\"```\n         \n\n```python\nclass Solution(object):\n    def lengthLongestPath(self, input):\n        \"\"\"\n        :type input: str\n        :rtype: int\n        \"\"\"\n        maxlen = 0\n        pathlen = {0 : 0}\n        for line in input.splitlines():\n            name = line.lstrip('\\t')\n            depth = len(line) - len(name)        # 前面有几个'\\t', depth就是几\n            if '.' in name:\n                maxlen = max(maxlen, pathlen[depth] + len(name))\n            else:\n                pathlen[depth+1] = pathlen[depth] + len(name) + 1    #加1是为了加上一个path分隔符'/'的长度\n        return maxlen\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/389._find_the_difference.md",
    "content": "\n### 389. Find the Difference\n\n\n题目:\n<https://leetcode.com/problems/find-the-difference/>\n\n\n难度:\n\nEasy\n\n用个字典来记录，把s加进去，把t减掉，最后剩下那个要么个数为1，要么个数为-1\n\n```python\nclass Solution(object):\n    def findTheDifference(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: str\n        \"\"\"\n        res = {}\n        for i in s:\n            res[i] = res.get(i, 0) + 1\n        for j in t:\n            res[j] = res.get(j, 0) - 1\n        for key in res:\n            if abs(res[key]) == 1:  # 这里用 abs 是因为新增加的那个字母在 s 中可能未出现过\n                return key\n```\n还有一个简单的方法\n```python\nclass Solution(object):\n    def findTheDifference(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: str\n        \"\"\"\n        from collections import Counter\n        return list((Counter(t) - Counter(s)).keys()).pop()\n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/392._is_subsequence.md",
    "content": "#  392. Is Subsequence\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/is-subsequence\n\n> 内容描述\n\n```\n\nGiven a string s and a string t, check if s is subsequence of t.\n\nYou may assume that there is only lower case English letters in both s and t. t is potentially a very long (length ~= 500,000) string, and s is a short string (<=100).\n\nA subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, \"ace\" is a subsequence of \"abcde\" while \"aec\" is not).\n\nExample 1:\ns = \"abc\", t = \"ahbgdc\"\n\nReturn true.\n\nExample 2:\ns = \"axc\", t = \"ahbgdc\"\n\nReturn false.\n\nFollow up:\nIf there are lots of incoming S, say S1, S2, ... , Sk where k >= 1B, and you want to check one by one to see if T has its subsequence. In this scenario, how would you change your code?\n```\n\n## 解题方案\n\n> 思路 1\n\n\nfollow up question很有意思\n\n\n最naive的思路表现形式如下：\n\nbeats 53.74%\n\n```python\nclass Solution(object):\n    def isSubsequence(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: bool\n        \"\"\"\n        if s == '': return True\n        for i in xrange(len(t)):\n        \tif t[i] == s[0]:\n        \t\treturn self.isSubsequence(s[1:],t[i+1:])\n\n        return False\n```\n\n> 思路 2\n\n递归操作以及对字符串的操作太过于昂贵，所以用index来处理，节省了时间和空间\n\n\n```python\nclass Solution(object):\n    def isSubsequence(self, s, t):\n        \"\"\"\n        :type s: str\n        :type t: str\n        :rtype: bool\n        \"\"\"\n        if s == '': return True\n        ps, pt = 0, 0\n        while ps < len(s) and pt < len(t):\n            if s[ps] == t[pt]:\n                ps += 1\n            pt += 1\n        return ps >= len(s)\n```\n\n精妙绝伦！！\n\n\n"
  },
  {
    "path": "docs/leetcode/python/394._decode_string.md",
    "content": "###394. Decode String\n\n\n题目:\n\n<https://leetcode.com/problems/decode-string/>\n\n\n难度:\n\nMedium\n\n\n思路:\n\n感觉像用栈做运算。\n\ns = \"3[a2[c]]\"\n\n⬇️\n\ns = 3 *( a + 2 * ( c ) )\n\n\n遇到非右括号全部入栈，碰到右括号出栈直到左括号，这个就算运算符2 → op2\n然后检查，直到stack空掉或者碰到下一个非数字，这个就算运算符1 → op1\n\n算出op1 和 op2 之后把这个res继续入栈。然后接着处理\n\n\n代码不是很优美\n\n\n\n\n```\nclass Solution(object):\n    def decodeString(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n\n        s = list(s)\n        stack = []\n\n        while s:\n        \tchar = s.pop(0)\n        \tif char != ']':\n        \t\tstack.append(char)\n        \telse:\n        \t\top1, op2 = '',''\n        \t\tpopChar = stack.pop()\n        \t\twhile popChar != '[':\n        \t\t\top2 = popChar + op2\n        \t\t\tpopChar = stack.pop()\n\n        \t\twhile stack and stack[-1] in ['0','1','2','3','4','5','6','7','8','9']:\n        \t\t\tpopChar = stack.pop()\n        \t\t\top1 = popChar + op1\n\n        \t\tres = int(op1) * op2\n\n        \t\tfor char in res:\n        \t\t\tstack.append(char)\n\n        return ''.join(stack)\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/400._Nth_Digit.md",
    "content": "### 400. Nth Digit\n\n\n\n题目:\n<https://leetcode.com/problems/nth-digit/>\n\n难度:\n\nEasy\n\n思路：\n\n这道简单题我服， tag是math，找规律\n\n```\n1- 9 : 9 → 只占1位 9 \n10 - 99: 90 → 两位 90 * 2\n100 - 999: 900 → 三位 900 * 3\n1000 - 9999: 9000 → 四位 9000 * 4\n```\n\n\n\nAC代码来之不易，是参考别人的，这里的`for i in range(9)`， 其实无论`range`多少都可以吧\n\n\n\n```\nclass Solution(object):\n    def findNthDigit(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        for i in range(9):\n            d = 9 * 10 ** i\n            if n <= d * (i+1): break\n            n -= d *(i+1)\n        n -= 1\n\n        return int(str(10**i + n / (i+1))[n % (i+1)])\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/401._binary_watch.md",
    "content": "###401. Binary Watch\n\n\n\n题目:\n<https://leetcode.com/problems/binary-watch/>\n\n\n难度:\nEasy\n\n\n思路：\n\n\n一看到位操作，我的内心是拒绝的。\n\n我也有想这样的想法，因为其实可以的组合并没有那么多，干脆枚举算了，然而也没有动手来写，直到被发了题解的截屏。\n\n\n```\nclass Solution(object):\n    def readBinaryWatch(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: List[str]\n        \"\"\"\n        hour = { 0 : ['0'],\n        1:['1','2','4','8'],\n        2:['3','5','6','9','10'],\n        3:['7','11']\n        }\n\n        minute = { 0:['00'],\n        1: ['01','02','04','08','16','32'],\n        2: ['03','05','06','09','10','12','17','18','20','24','33','34','36','40','48'],\n        3: ['07','11','13','14','19','21','22','25','26','28','35','37','38','41','42','44','49','50','52','56'],\n        4: ['15','23','27','29','30','39','43','45','46','51','53','54','57','58'],\n        5: ['31','47','55','59']\n        }\n\n        res = []\n\n        #num = num for hour + num for minute\n        i = 0\n\n        while i <= 3 and i <= num:\n            if num - i <= 5:\n                for str1 in hour[i]:\n                    for str2 in minute[num-i]:\n                        res.append(str1 + ':' + str2)\n            i += 1\n        return res\n```\n\n\n关于循环那处，因为hour的led最多只有4个，所以这样写循环\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/404._sum_of_left_leaves.md",
    "content": "###404. Sum of Left Leaves\n\n\n\n题目:\n<https://leetcode.com/problems/sum-of-left-leaves/>\n\n\n难度:\nEasy\n\n\n思路：\n\n\n典型递归，检查root的左孩子是不是node，是的话加上它的值，不是的话递归去求它的孩子们的，对于右边，递归的求sum of left leaves\n\n\n\n```\nclass Solution(object):\n    def sumOfLeftLeaves(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        def isLeaf(node):\n        \tif node == None:\n        \t\treturn False\n        \tif node.left == None and node.right == None:\n        \t\treturn True\n        \treturn False\n\n        res = 0\n\n        if root:\n        \tif isLeaf(root.left):\n        \t\tres += root.left.val\n        \telse:\n        \t\tres += self.sumOfLeftLeaves(root.left)\n        \tif root.right:\n        \t    res += self.sumOfLeftLeaves(root.right)\n\n        return res\n```"
  },
  {
    "path": "docs/leetcode/python/405._Convert_a_Number_to_Hexadecimal.md",
    "content": "### 405. Convert a Number to Hexadecimal\n\n题目:\n\n<https://leetcode.com/problems/convert-a-number-to-hexadecimal/>\n\n难度:\n\nEasy\n\n\n\nwikipedia两个page:\n\n\n\n[十六进制](https://zh.wikipedia.org/wiki/十六进制#.E5.8D.81.E9.80.B2.E5.88.B6.E8.BD.89.E5.8D.81.E5.85.AD.E9.80.B2.E5.88.B6)\n\n例子：\n\n4877÷16=304....13(D)\n\n304÷16=19....0\n\n19÷16=1....3\n\n1÷16=0....1\n\n這樣就計到4877(10)=130D(16)\n\n\n\n[补码](https://zh.wikipedia.org/wiki/二補數)\n\n> 一個數字的二補數就是將該數字作[位元](https://zh.wikipedia.org/wiki/%E4%BD%8D%E5%85%83)[反相](https://zh.wikipedia.org/w/index.php?title=%E5%8F%8D%E7%9B%B8&action=edit&redlink=1)運算（即[一補數](https://zh.wikipedia.org/wiki/%E4%B8%80%E8%A3%9C%E6%95%B8)或[反码](https://zh.wikipedia.org/wiki/%E5%8F%8D%E7%A0%81)），再將結果加1。在二補數系統中，一個負數就是用其對應正數的二補數來表示\n\n\n\n看给的这个-1的例子\n\n\n\n0000 0000 0000 0000 0000 0000 0000 0001\n\n1111 1111 1111 1111 1111 1111 1111 1110   +1\n\n1111 1111 1111 1111 1111 1111 1111 1111\n\nf\tf\tf\tf\tf\tf\tf\tf\n\n\n\n\n\n也可以参考这里:\n\n[基础03：原码、反码、补码](https://higoge.github.io/2015/07/02/basic03/)\n\n\n\n这里我一开始迷茫和晕了一下，但是随后反应过来，这些数字在电脑里使用二进制存的，而负数也是用二进制的补码存的。所以其实AC代码应当很简单。\n\n参考：\n\n<https://github.com/kamyu104/LeetCode/blob/master/Python/convert-a-number-to-hexadecimal.py>\n\n\n\nAC代码：\n\n```\nclass Solution(object):\n    def toHex(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: str\n        \"\"\"\n        if not num :\n            return \"0\"\n\n        result = []\n        hexStr =\"0123456789abcdef\"\n        while num and len(result) != 8:\n            h = num & 15\n            result.append(hexStr[h])\n            num >>= 4\n\n        return ''.join(result[::-1])\n```\n\n\n\n每次看后四位的结果，把它存起来,比如还是是看4877\n\n它在计算机内部的表示是： \n\n```\n0b1001100001101\nnum & 15\t\t1101 & 15 = 13(d)\nnum >>=4\t\t0b100110000\nnum & 15\t\t0000 & 15 = 0\nnum >>=4\t\t0b10011\nnum & 15\t\t10011 & 15 = 9\nnum >>=4\t\t0001\nnum & 15\t\t0001 & 15 = 1\n\n```\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/406._Queue_Reconstruction_by_Height.md",
    "content": "### 406. Queue Reconstruction by Height\n\n题目:\n<https://leetcode.com/problems/queue-reconstruction-by-height/>\n\n\n难度:\n\nMedium\n\n\n思路：\nPeople are only counting (in their k-value) taller or equal-height others standing in front of them. \nSo a smallest person is completely irrelevant for all taller ones. And of all smallest people, \nthe one standing most in the back is even completely irrelevant for everybody else. Nobody is counting that person. \nSo we can first arrange everybody else, ignoring that one person. And then just insert that person appropriately. \nNow note that while this person is irrelevant for everybody else, everybody else is relevant for this person - \nthis person counts exactly everybody in front of them. So their count-value tells you exactly the index they must be standing.\n\nSo you can first solve the sub-problem with all but that one person and then just insert that person appropriately. \nAnd you can solve that sub-problem the same way, first solving the sub-sub-problem with all \nbut the last-smallest person of the subproblem. And so on. The base case is when you have the sub-…-sub-problem of zero people. \nYou’re then inserting the people in the reverse order, i.e., that overall last-smallest person in the very end \nand thus the first-tallest person in the very beginning. That’s what the above solution does, \nSorting the people from the first-tallest to the last-smallest, and inserting them one by one as appropriate.\n\n参考[stefan](https://leetcode.com/problems/queue-reconstruction-by-height/discuss/89359)\n\n```python\nclass Solution(object):\n    def reconstructQueue(self, people):\n        \"\"\"\n        :type people: List[List[int]]\n        :rtype: List[List[int]]\n        \"\"\"\n        people.sort(key=lambda (h, k): (-h, k))\n        queue = []\n        for p in people:\n            queue.insert(p[1], p)\n        return queue\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/412._fizz_buzz.md",
    "content": "### 412. Fizz Buzz\n\n题目:\n<https://leetcode.com/problems/fizz-buzz/>\n\n\n难度:\nEasy\n\n一行\n```python\nclass Solution(object):\n    def fizzBuzz(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[str]\n        \"\"\"\n        return [(not i%3)*\"Fizz\" + (not i%5)*\"Buzz\" or str(i) for i in range(1, n+1)]\n\n```\n```python\nclass Solution(object):\n    def fizzBuzz(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: List[str]\n        \"\"\"\n        return [str(i) if (i%3!=0 and i%5!=0) else (('Fizz'*(i%3==0)) + ('Buzz'*(i%5==0))) for i in range(1,n+1)]\n\n```\n\n\n就是easy，不过可以参见这里，有一些讨论\n\n<http://codereview.stackexchange.com/questions/763/two-fizzbuzz-solutions>\n\n我觉得这里一个用yield的想法还蛮不错\n```\n# the fizbuz logic, returns an iterator object that\n# calculates one value at a time, not all ot them at once\ndef fiz(numbers):\n    for i in numbers:\n        if i % 15 == 0:\n            yield 'fizbuz'\n        elif i % 5 == 0:\n            yield 'buz'\n        elif i % 3 == 0:\n            yield 'fiz'\n        else:\n            yield str(i)\n\n# xrange evaluates lazily, good for big numbers\n# matches well with the lazy-eval generator function\nnumbers = xrange(1,2**20)\n\n# this gets one number, turns that one number into fuz, repeat\nprint ' '.join(fiz(numbers))\n\n# returns: 1 2 fiz 4 buz fiz [...] fiz 1048573 1048574 fizbuz\n```\n- clearly separates fizbuz logic from concatenation\n- is as plain and readeable as possible\n- generator iterator does not keep all the array in memory\n- so that you can do it on arbitrary numbers (see Euler problem #10)\n\nWhat I do not like in this solution is the three ifs, whereas the problem can be solved with two.\n\nAnswer: because yield is efficient when you do not want to keep big arrays in memory just to iterate through them. But this question is not about big arrays.\n"
  },
  {
    "path": "docs/leetcode/python/413._Arithmetic_Slices.md",
    "content": "### 413. Arithmetic Slices\n\n\n\n题目： \n<https://leetcode.com/problems/arithmetic-slices/>\n\n\n\n难度 : Medium\n\n\n\n思路：\n\ntag 是DP\n\n数从 i 到 j 之间的这个arithmetic 数\n\n我的方法时间复杂度比较高O(N^2)，从 i 开始数它的arithmetic slice，每个i数一遍，到 j\n\nAC代码\n\n```\nclass Solution(object):\n    def numberOfArithmeticSlices(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(A)\n        if n < 3:\n        \treturn 0\n        else:\n        \tres = 0\n        \tfor i in range(n-2):\n        \t\tfor j in range(i+2,n):\n        \t\t\tif A[j] - A[j-1] == A[i+1] - A[i]:\n        \t\t\t\tres += 1\n        \t\t\telse:\n        \t\t\t\tbreak\n        \treturn res\n```\n\n\n\n应该可以优化到O(N)\n\n不需要每个每个开始数，可以边数边移动\n\n可以参考<http://www.cnblogs.com/grandyang/p/5968340.html>\n\n\n\nO(N) 代码\n\n```\nclass Solution(object):\n    def numberOfArithmeticSlices(self, A):\n        \"\"\"\n        :type A: List[int]\n        :rtype: int\n        \"\"\"\n        n = len(A)\n        if n < 3:\n        \treturn 0\n        else:\n        \tres, cnt = 0, 2\n        \tfor i in range(2, n):\n        \t\tif A[i] - A[i-1] == A[i-1] - A[i-2]:\n        \t\t\tprint i, i-1, i-2\n        \t\t\tcnt += 1\n        \t\telse:\n        \t\t\tif cnt > 2:\n        \t\t\t\tres += (cnt-1) * (cnt-2)  / 2\n        \t\t\tcnt = 2\n        \tif cnt > 2: res += (cnt-1) * (cnt-2)  / 2\n        \treturn res\n\n\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/414._third_maximum_number.md",
    "content": "###414. Third Maximum Number\n\n题目:\n<https://leetcode.com/problems/third-maximum-number/>\n\n\n难度:\n\nEasy \n\n\n思路:\n\n用三个变量来记录，max， secondmax, thirdmax，\n\n- 遇到比max还大的就更新，当前max降级为secondmax，当前secondmax降级为thirdmax\n- 遇到比max小但是比secondmax大的也这样做降级处理\n- 更thirdmax\n\n\nAC代码\n\n\n```\nclass Solution(object):\n    def thirdMax(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        m, sm, tm = float('-inf'), float('-inf'), float('-inf')\n\n        for num in nums:\n            if num > m:\n                tm = sm\n                sm = m \n                m = num\n            elif num < m and num > sm:\n                tm = sm\n                sm = num\n            elif num < m and num < sm and num > tm:\n                tm = num\n\n        return tm if tm != float('-inf') else m \n```\n\n"
  },
  {
    "path": "docs/leetcode/python/415._add_strings.md",
    "content": "# 415. Add Strings\n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/add-strings\n\n> 内容描述\n\n```\n\nGiven two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2.\n\nNote:\n\nThe length of both num1 and num2 is < 5100.\nBoth num1 and num2 contains only digits 0-9.\nBoth num1 and num2 does not contain any leading zero.\nYou must not use any built-in BigInteger library or convert the inputs to integer directly.\n```\n\n## 解题方案\n\n> 思路 1\n\n题目说不能直接将input转换为int，那我就一次只转换一位，真tm简单！\n\n```python\nclass Solution(object):\n    def addStrings(self, num1, num2):\n        \"\"\"\n        :type num1: str\n        :type num2: str\n        :rtype: str\n        \"\"\"\n        def str2int(num):\n            res = 0\n            for i in range(len(num)-1, -1, -1):\n                res += int(num[i]) * pow(10, len(num)-1-i)\n            return res\n        return str(str2int(num1) + str2int(num2))\n```\n"
  },
  {
    "path": "docs/leetcode/python/416._Partition_Equal_Subset_Sum.md",
    "content": "#  416. Partition Equal Subset Sum\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/partition-equal-subset-sum\n\n> 内容描述\n\n```\nGiven a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.\n\nNote:\nEach of the array element will not exceed 100.\nThe array size will not exceed 200.\nExample 1:\n\nInput: [1, 5, 11, 5]\n\nOutput: true\n\nExplanation: The array can be partitioned as [1, 5, 5] and [11].\nExample 2:\n\nInput: [1, 2, 3, 5]\n\nOutput: false\n\nExplanation: The array cannot be partitioned into equal sum subsets.\n```\n\n## 解题方案\n\n> 思路 1\n\n动态规划\n\ndp[i]代表nums中能否找出一个subset的sum等于i，例如dp[0] = True是必然的，因为我们只要取空子集，那么其sum一定为0\n\n```python\nclass Solution(object):\n    def canPartition(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        if not nums or len(nums) == 0:\n            return True\n        if sum(nums) % 2 != 0: ## 总和必须为偶数，否则肯定无法取两个集合的sum相等\n            return False\n        half_sum = sum(nums)/2\n        dp = [False] * (half_sum+1)\n        dp[0] = True\n        for i in range(len(nums)):\n            for j in range(half_sum, nums[i]-1, -1):\n                dp[j] = dp[j] or dp[j-nums[i]]\n        print(dp)\n        return dp[half_sum]\n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md",
    "content": "### 421. Maximum XOR of Two Numbers in an Array\n\n题目:\n<https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/>\n\n\n难度:\n\nMedium\n\n题目要求O(N)时间\n\n看了半天的解法居然超时，\n```python\nclass Solution(object): # 此法超时\n    def findMaximumXOR(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        '''The maxResult is a record of the largest XOR we got so far. if it's 11100 at i = 2, it means \n            before we reach the last two bits, 11100 is the biggest XOR we have, and we're going to explore\n            whether we can get another two '1's and put them into maxResult'''\n        max_res, mask = 0, 0\n        \n        '''This is a greedy part, since we're looking for the largest XOR, we start \n            from the very begining, aka, the 31st postition of bits.'''\n        for i in range(32)[::-1]:\n            \n            '''The mask will grow like  100..000 , 110..000, 111..000,  then 1111...111\n                for each iteration, we only care about the left parts'''\n            mask |= (1 << i)\n            tmp = []\n            for num in nums:\n                '''we only care about the left parts, for example, if i = 2, then we have\n                    {1100, 1000, 0100, 0000} from {1110, 1011, 0111, 0010}'''\n                tmp.append(num & mask)\n            \n                '''if i = 1 and before this iteration, the maxResult we have now is 1100, \n                    my wish is the maxResult will grow to 1110, so I will try to find a candidate\n                    which can give me the greedyTry;'''\n            greedy_try = max_res | (1 << i)\n                \n            for i in tmp:\n                '''This is the most tricky part, coming from a fact that if a ^ b = c, then a ^ c = b;\n                now we have the 'c', which is greedyTry, and we have the 'a', which is leftPartOfNum\n                If we hope the formula a ^ b = c to be valid, then we need the b, \n                and to get b, we need a ^ c, if a ^ c exisited in our set, then we're good to go'''\n                if i ^ greedy_try in tmp:\n                    max_res = greedy_try\n            '''If unfortunately, we didn't get the greedyTry, we still have our max, \n                So after this iteration, the max will stay at 1100.'''\n        return max_res\n```\n\n\n只好想别的办法\n\n\n参考[stefan](https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/discuss/91050?page=3)\n```python\nclass Solution(object):\n    def findMaximumXOR(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        answer = 0\n        for i in range(32)[::-1]:\n            answer <<= 1\n            prefixes = {num >> i for num in nums}\n            answer += any(answer^1 ^ p in prefixes for p in prefixes)\n        return answer\n```\n"
  },
  {
    "path": "docs/leetcode/python/422._Valid_Word_Square.md",
    "content": "### 422. Valid Word Square\n\n\n\n\n\n题目： \n<https://leetcode.com/problems/valid-word-square/>\n\n\n\n难度 : Easy\n\n\n\n思路：\n\n就是对比一个矩阵内 xy == yx?\n\ntry /except 真是好用\n\nAC代码\n\n\n\n```\nclass Solution(object):\n    def validWordSquare(self, words):\n        \"\"\"\n        :type words: List[str]\n        :rtype: bool\n        \"\"\"\n        n = len(words)\n        for i in xrange(n):\n        \tm = len(words[i])\n        \tfor j in xrange(m):\n        \t\ttry:\n        \t\t\tif words[i][j] != words[j][i]:\n        \t\t\t\treturn False\n        \t\texcept:\n        \t\t\treturn False\n        return True\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/434._number_of_segments_in_a_string.md",
    "content": "### 434. Number of Segments in a String\n\n题目:\n<https://leetcode.com/problems/number-of-segments-in-a-string/>\n\n\n难度:\n\nEasy\n\n\n作弊神器Python\n\n\n```python\nclass Solution(object):\n    def countSegments(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        return len(s.split())\n```\n\n不过对于比如C++这种语言来说，应该是O(N),扫一圈应该也能得到正确答案\n\n总之拿Python做string的题目就是作弊啊\n"
  },
  {
    "path": "docs/leetcode/python/435._Non-overlapping_Intervals.md",
    "content": "#  435. Non-overlapping Intervals\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/non-overlapping-intervals\n\n> 内容描述\n\n```\nGiven a collection of intervals, find the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.\n\nNote:\nYou may assume the interval's end point is always bigger than its start point.\nIntervals like [1,2] and [2,3] have borders \"touching\" but they don't overlap each other.\nExample 1:\nInput: [ [1,2], [2,3], [3,4], [1,3] ]\n\nOutput: 1\n\nExplanation: [1,3] can be removed and the rest of intervals are non-overlapping.\nExample 2:\nInput: [ [1,2], [1,2], [1,2] ]\n\nOutput: 2\n\nExplanation: You need to remove two [1,2] to make the rest of intervals non-overlapping.\nExample 3:\nInput: [ [1,2], [2,3] ]\n\nOutput: 0\n\nExplanation: You don't need to remove any of the intervals since they're already non-overlapping.\n```\n\n## 解题方案\n\n> 思路 1\n\n先按照start排序，然后每次如果下一个的start小于前一个的end的时候意味着我们需要删掉一个了，但是我们尽量留下end比较小的那个Interval，具体看代码会比较清晰\n\n```python\n# Definition for an interval.\n# class Interval(object):\n#     def __init__(self, s=0, e=0):\n#         self.start = s\n#         self.end = e\n\nclass Solution(object):\n    def eraseOverlapIntervals(self, intervals):\n        \"\"\"\n        :type intervals: List[Interval]\n        :rtype: int\n        \"\"\"\n        if not intervals or len(intervals) == 0:\n            return 0\n        res = 0\n        intervals = sorted(intervals, key=lambda x:x.start)\n        cur_end = intervals[0].end\n        for i in range(1, len(intervals)):\n            if intervals[i].start < cur_end: #overlap\n                res += 1   \n                cur_end = min(intervals[i].end, cur_end) ## 尽量留下end小的Interval\n            else:\n                cur_end = intervals[i].end\n        return res\n```\n\n> 思路 2\n\n又发现有大佬比我牛p多了，代码更nice，跟646题比较像\n\n首先按照end排序，我们可以知道的，一旦后面一个Interval的start比前一个的end小的话，这个时候我们就需要删除掉当前的这个Interval, \n反之则前面的那些Interval已经成立了，我们只需要更新cur_end为当前Interval的end\n\n\n```python\nclass Solution(object):\n    def eraseOverlapIntervals(self, intervals):\n        \"\"\"\n        :type intervals: List[Interval]\n        :rtype: int\n        \"\"\"\n        intervals.sort(key = lambda x: x.end)\n        res, cur_end = 0, -float(\"inf\")\n        for i in intervals:\n            if cur_end > i.start: res += 1\n            else: cur_end = i.end\n        return res\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/437._path_sum_iii.md",
    "content": "### 437. Path Sum III\n\n\n\n题目:\n<https://leetcode.com/problems/path-sum-iii/>\n\n\n难度:\nEasy\n\n思路：\n\n\n\n\n```python\nclass Solution(object):\n    def pathSum(self, root, sum):\n        \"\"\"\n        :type root: TreeNode\n        :type sum: int\n        :rtype: int\n        \"\"\"\n        if not root:\n            return 0\n        res = self.auxPathSum(root, sum)\n        res += self.pathSum(root.left, sum)\n        res += self.pathSum(root.right, sum)\n        return res\n    def auxPathSum(self, root, sum):\n        if not root:\n            return 0\n        if sum == root.val:\n            # 因为可能有负值, 所以sum为0也会有解, 必须加上\n            return 1 + self.auxPathSum(root.left, 0) + self.auxPathSum(root.right, 0) \n        else:\n            return self.auxPathSum(root.left, sum - root.val) + self.auxPathSum(root.right, sum - root.val)\n```\n"
  },
  {
    "path": "docs/leetcode/python/438._Find_All_Anagrams_in_a_String.md",
    "content": "### 438. Find All Anagrams in a String\n\n\n题目:\n<https://leetcode.com/problems/Find-All-Anagrams-in-a-String/>\n\n\n难度:\n\nEasy\n\n\n\n思路\n\n刚开始打算直接遍历整个s，时间复杂度为O(m*n),m和n分别为字符串p和s的长度，但是超时了\n\n\n\n```\n\nclass Solution(object):  # 此法超时\n    def findAnagrams(self, s, p):\n        \"\"\"\n        :type s: str\n        :type p: str\n        :rtype: List[int]\n        \"\"\"\n        l, res = len(p), []\n        for i in range(len(s)):\n            if collections.Counter(s[i:i+l]) == collections.Counter(p):\n                res.append(i)\n        return res\n```\n\n于是用双指针，left和right都从0开始往后遍历\n```\nclass Solution(object):\n    def findAnagrams(self, s, p):\n        \"\"\"\n        :type s: str\n        :type p: str\n        :rtype: List[int]\n        \"\"\"\n        res, cnts = [], [0] * 26\n        for c in p:\n            cnts[ord(c) - ord('a')] += 1\n            left, right = 0, 0\n        while right < len(s):\n            cnts[ord(s[right]) - ord('a')] -= 1\n            while left <= right and cnts[ord(s[right]) - ord('a')] < 0:\n                cnts[ord(s[left]) - ord('a')] += 1\n                left += 1\n            if right - left + 1 == len(p):\n                res.append(left)\n            right += 1\n        return res\n```\n模板大法好\n```python\nclass Solution(object):\n    def findAnagrams(self, s, p):\n        \"\"\"\n        :type s: str\n        :type p: str\n        :rtype: List[int]\n        \"\"\"\n        res = []\n        if len(p) > len(s):\n            return res\n        maps = collections.Counter(p)\n        counter = len(maps.keys())\n        begin, end, head, length = 0, 0, 0, sys.maxint\n        while end < len(s):\n            if s[end] in maps:\n                maps[s[end]] -= 1\n                if maps[s[end]] == 0:\n                    counter -= 1\n            end += 1\n            while counter == 0:\n                if s[begin] in maps:\n                    maps[s[begin]] += 1\n                    if maps[s[begin]] > 0:\n                        counter += 1\n                if end - begin == len(p):\n                    res.append(begin)\n                begin += 1\n        return res\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/439._Ternary_Expression_Parser.md",
    "content": "### 439. Ternary Expression Parser\n\n\n\n\n\n题目:\n<https://leetcode.com/problems/ternary-expression-parser/>\n\n\n\n难度:\nMedium \n\n思路：\n\n其实这个和算术运算蛮像，但是不同于运算，有operator precedence差别，这个是三目运算，并且需要检查是否符合运算规则。\n\n\n\n运用stack 然后每次查看是否形成运算式再来做处理\n\nAC代码：\n\n```\nclass Solution(object):\n    def parseTernary(self, expression):\n        \"\"\"\n        :type expression: str\n        :rtype: str\n        \"\"\"\n        n = len(expression)\n\n        stack = []\n\n        for i in range(n-1, -1, -1):\n            char = expression[i]\n            stack.append(char)\n\n            if len(stack) >= 5:\n                op0 = stack.pop()\n                op1 = stack.pop()\n                op2 = stack.pop()\n                op3 = stack.pop()\n                op4 = stack.pop()\n\n                if op1 == '?' and op3 == ':':\n                    res = op2 if op0 == 'T' else op4\n                    stack.append(res)\n                else:\n                    stack.append(op4)\n                    stack.append(op3)\n                    stack.append(op2)\n                    stack.append(op1)\n                    stack.append(op0)\n        return stack[0]\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/441._arranging_coins.md",
    "content": "###441. Arranging Coins\n\n题目:\n<https://leetcode.com/problems/arranging-coins/>\n\n\n难度:\nEasy\n\n\n可以直接O(1),公式：\n\ni(i+1)/2 = n\n\n解i\n\ni = ( sqrt(8*n+1) -1 )/ 2 \n\n\n```\nimport math\nclass Solution(object):\n    def arrangeCoins(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: int\n        \"\"\"\n        return int((math.sqrt( 8 * n + 1) - 1 )/ 2 )\n```"
  },
  {
    "path": "docs/leetcode/python/448._Find_All_Numbers_Disappeared_in_an_Array.md",
    "content": "### 448. Find All Numbers Disappeared in an Array\n\n题目:\n<https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/>\n\n\n难度:\n\nEasy\n\n\n\n\n\n```python\nclass Solution(object):\n    def findDisappearedNumbers(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: List[int]\n        \"\"\"\n        return list(set(range(1, len(nums)+1)) - set(nums))\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/450._Delete_Node_in_a_BST.md",
    "content": "### 450. Delete Node in a BST\n\n\n\n题目： \n<https://leetcode.com/problems/delete-node-in-a-bst/>\n\n难度 : Medium\n\n\n\n思路：\n\n从二叉搜索树中删除节点x的方法如下:\n\n• 如果x没有子节点，或者只有一个孩子，直接将x“切下”;\n\n• 否则，x有两个孩子，我们用其右子树中的最小值替换掉x，然后将右子树中的这一最小值递归的“切掉”。\t\n​\t\t\n\n\n\nAC代码\n\n\n\n```python\nclass Solution(object):\n    def deleteNode(self, root, key):\n        \"\"\"\n        :type root: TreeNode\n        :type key: int\n        :rtype: TreeNode\n        \"\"\"\n        def findmin(root):\n        \twhile root.left:\n        \t\troot = root.left\n        \treturn root\n\n\n        if not root : return None\n    \telif key < root.val: root.left = self.deleteNode(root.left, key)\n    \telif key > root.val : root.right = self.deleteNode(root.right, key)\n    \telse:\n    \t\tif root.left and root.right:\n    \t\t\ttmp = findmin(root.right)\n    \t\t\troot.val = tmp.val\n    \t\t\troot.right = self.deleteNode(root.right, tmp.val)\n    \t\telse:\n    \t\t\tif not root.left:\n    \t\t\t\troot = root.right\n    \t\t\telif not root.right:\n    \t\t\t\troot = root.left\n    \treturn root\n```\n\n​\t\n\n\n\n其实这个代码还是需要花点时间来理解，需要画个图，理解这个root是每个stack return回去然后被接在原来的树上的，if 这个node并不是在node左右。\n\n"
  },
  {
    "path": "docs/leetcode/python/453._Minimum_Moves_to_Equal_Array_Elements.md",
    "content": "### 453. Minimum Moves to Equal Array Elements\n\n\n\n\n\n题目： \n<https://leetcode.com/problems/minimum-moves-to-equal-array-elements/>\n\n\n\n难度 : Easy\n\n\n\n思路：\n\nnaive TLE 代码：\n\n每次都是给并不是最大的元素加1直到全部相等。\n\n```\nclass Solution(object):\n    def minMoves(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        res = 0\n        while(not all(x == nums[0] for x in nums)):\n        \tnums.sort()\n        \tfor i in range(len(nums) - 1):\n        \t\tnums[i] += 1\n        \tres += 1\n\n        return res\n```\n\n\n\n给的测试例子是 `[1,2147483647]`能不TLE么？tag 是Math，所以要用观察到的结果来做吧？\n\n所以就是每个和最小值来比，看到底要增加多少，这是观察，但不是证明\n\n\n\n\n\nAC代码\n\n```python\nclass Solution(object):\n    def minMoves(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        res = 0\n        minVal = min(nums)\n        for num in nums:\n        \tres += num -minVal\n        return res\n```\n\n\n\n类证明：\n\n\n\n> 其实给n-1个数字加1，效果等同于给那个未被选中的数字减1，比如数组[1，2，3], 给除去最大值的其他数字加1，变为[2，3，3]，我们全体减1，并不影响数字间相对差异，变为[1，2，2]，这个结果其实就是原始数组的最大值3自减1，那么问题也可能转化为，将所有数字都减小到最小值，这样难度就大大降低了，我们只要先找到最小值，然后累加每个数跟最小值之间的差值即可\n\n"
  },
  {
    "path": "docs/leetcode/python/459._Repeated_Substring_Pattern.md",
    "content": "### 459. Repeated Substring Pattern\n\n\n题目:\n<https://leetcode.com/problems/Repeated-Substring-Pattern/>\n\n\n难度:\n\nEasy\n\n\n思路\n\n- 如果存在这样的子串，那么子串的第一个字符和最后一个字符肯定跟父字符串```s```的相同。\n- 因此构建一个新字符串```s*2```（两个父字符串相加），去掉首尾字符\n- 如果此时能在其中找到```s```，说明存在这样的子串\n\n\n\n\n```python\nclass Solution(object):\n    def repeatedSubstringPattern(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: bool\n        \"\"\"\n        return (s*2)[1:-1].find(s) != -1\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/461._Hamming_Distance.md",
    "content": "### 461. Hamming Distance\n\n\n\n题目： \n<https://leetcode.com/problems/hamming-distance/\n\n\n\n难度 : Easy\n\n\n\n有wikipedia的page：\n\nhttps://en.wikipedia.org/wiki/Hamming_distance\n\n\n\n其实思路还是比较简单的\n\n\n\n先用异或，再求hamming weight\n\n>  For binary strings *a* and *b* the Hamming distance is equal to the number of ones ([Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight)) in *a* [XOR](https://en.wikipedia.org/wiki/Exclusive_or) *b*.\n>\n> \n\n\n\n一行无敌\n```python\nclass Solution(object):\n    def hammingDistance(self, x, y):\n        \"\"\"\n        :type x: int\n        :type y: int\n        :rtype: int\n        \"\"\"\n        return bin(x^y).count('1')\n```\nAC代码\n\n```python\nclass Solution(object):\n    def hammingDistance(self, x, y):\n        \"\"\"\n        :type x: int\n        :type y: int\n        :rtype: int\n        \"\"\"\n        dist = 0\n        val = x ^ y\n\n        while val:\n            dist += 1\n            val &= val - 1\n\n        return dist\n```\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/463._Island_Perimeter.md",
    "content": "### 463. Island Perimeter\n\n\n\n题目:\n<https://leetcode.com/problems/island-perimeter/>\n\n\n难度:\nEasy\n\n思路：\n\n\n\n\n```python\nclass Solution(object):\n    def islandPerimeter(self, grid):\n        \"\"\"\n        :type grid: List[List[int]]\n        :rtype: int\n        \"\"\"\n        # 每一个陆地单元格的周长为4，当两单元格上下或者左右相邻时，令周长减2\n        h = len(grid)\n        w = len(grid[0]) if h else 0\n        ans = 0\n        for x in range(h):\n            for y in range(w):\n                if grid[x][y] == 1:\n                    ans += 4\n                    # 因为x+1还在后面，所以不需要考虑，即只需要考虑左边和上边，因为循环已经出现过该点了\n                    if x > 0 and grid[x - 1][y]:   \n                        ans -= 2\n                    if y > 0 and grid[x][y - 1]:\n                        ans -= 2\n        return ans\n```\n"
  },
  {
    "path": "docs/leetcode/python/467._Unique_Substrings_in_Wraparound_String.md",
    "content": "### 467. Unique Substrings in Wraparound String\n\n题目:\n<https://leetcode.com/problems/Unique-Substrings-in-Wraparound-String/>\n\n\n难度:\n\nMedium\n\n\n思路:\n\n有个无限长的字符串s，是由无数个「abcdefghijklmnopqrstuvwxyz」组成的。现在给你一个字符串p，求多少个p的非空子串在s中出现了？\n　　\n  \n先考虑s的特性，满足条件（在s中）的p的子串只可能是abcd……z的连续序列（z后面是a）， 我们只需要处理p中连续的部分就可以了。但是 举个例子，h-k的序列出现了，a-z的序列也出现了，那么只需要计算a-z的子串个数就可以了，因为h-k已经包含在a-z里了。考虑所有包含的情况，似乎就变得复杂了，a-z还可能被包含在x-za-z中，甚至更长的序列中。\n  \n　　但是如果考虑以某个字母结尾的子串个数，那么p中以该字母结尾的连续序列长度，就是满足条件的子串个数。如果以字母x结尾的连续序列有多个， 我们只需要最长的一个即可，因为其他短的序列都已经被长的包含进去了，例如'bcd'和'abcd'，有了'abcd'就知道以d结尾的子串有4个，分别是‘d’,'cd','bcd','abcd'，‘bcd’已经被包含进去了。最后求和，问题就解决了。 这样思考就非常简单了，代码也可以很容易写出来。\n  \n\n\n```python\nclass Solution(object):\n    def findSubstringInWraproundString(self, p):\n        \"\"\"\n        :type p: str\n        :rtype: int\n        \"\"\"\n        letters = [0] * 26          #开始默认每个都是0\n        length = 0\n        for i in range(len(p)):\n            curr = ord(p[i]) - ord('a')\n            if i > 0 and ord(p[i-1]) != (curr-1)%26 + ord('a'):   #一旦开始不相等了就要将length重置为0\n                length = 0\n            length += 1                        #否则就说明继续与前面一个字符是连续的，length要加1才行\n            if length > letters[curr]:     #length一直加，如果到i这个字符length比它的目前的最大连续子串长度还要长，那么肯定要更新letters\n                letters[curr] = length\n        return sum(letters)\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/469._Convex_Polygon.md",
    "content": "### 469. Convex Polygon\n\n\n\n题目： \n<https://leetcode.com/problems/convex-polygon/\n\n\n\n难度 : Medium\n\n\n\n思路：\n\n凸多边形\n\n记得讲过convex hull，然而已经不知道是啥了。。。。\n\n看wikipedia它的性质 https://en.wikipedia.org/wiki/Convex_polygon\n\n- The polygon is entirely contained in a closed half-plane defined by each of its edges.\n\n\n\nhttp://stackoverflow.com/questions/471962/how-do-determine-if-a-polygon-is-complex-convex-nonconvex\n\n\n\n这个算法很有意思也很make sense，叫包礼物。不过也是对付convex hull的，看到有人提这个：\n\n\n\n> You can make things a lot easier than the Gift-Wrapping Algorithm... that's a good answer when you have a set of points w/o any particular boundary and need to find the convex hull.\n>\n> A polygon is a set of points in a list where the consecutive points form the boundary. It is much easier to figure out whether a polygon is convex or not (and you don't have to calculate any angles, either):\n>\n> \n>\n> For each consecutive pair of edges of the polygon (each triplet of points), compute the z-component of the cross product of the vectors defined by the edges pointing towards the points in increasing order. Take the cross product of these vectors:\n>\n> The polygon is convex if the z-components of the cross products are either all positive or all negative. Otherwise the polygon is nonconvex.\n>\n> given p[k], p[k+1], p[k+2] each with coordinates x, y:\n>\n>  dx1 = x[k+1]-x[k]\n>\n>  dy1 = y[k+1]-y[k]\n>\n>  dx2 = x[k+2]-x[k+1]\n>\n>  dy2 = y[k+2]-y[k+1]\n>\n>  zcrossproduct = dx1 * dy2 - dy1 * dx2\n>\n> If there are N points, make sure you calculate N cross products, e.g. be sure to use the triplets (p[N-2],p[N-1],p[0]) and (p[N-1],p[0],p[1]).\n\n\n\n所以根据这个答案AC代码\n\n```\nclass Solution(object):\n    def isConvex(self, points):\n        \"\"\"\n        :type points: List[List[int]]\n        :rtype: bool\n        \"\"\"\n        n = len(points)\n        zcrossproduct = None\n\n        for i in range(-2, n-2):\n            x = [ points[i][0], points[i+1][0], points[i+2][0] ]\n            y = [ points[i][1], points[i+1][1], points[i+2][1] ]\n\n            dx1 = x[1] - x[0]\n            dy1 = y[1] - y[0]\n\n            dx2 = x[2] - x[1]\n            dy2 = y[2] - y[1]\n\n            if not zcrossproduct:\n                zcrossproduct = dx1 * dy2 - dy1 * dx2\n            elif ( dx1 * dy2 - dy1 * dx2 ) * zcrossproduct < 0:\n                return False\n        return True\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/476._Number_Complement.md",
    "content": "### 476. Number Complement\n\n\n\n题目:\n<https://leetcode.com/problems/number-complement/>\n\n\n难度:\nEasy\n\n\n\n\n\n```python\nclass Solution(object):\n    def findComplement(self, num):\n        \"\"\"\n        :type num: int\n        :rtype: int\n        \"\"\"\n        i = 1 << (len(bin(num)) -2) # 因为bin函数转化成的格式是‘0bXXXX’，头两个‘0b’要减掉去\n        return (i - 1) ^ num\n        # return (i - 1) - num # 这样也可以\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/477._Total_Hamming_Distance.md",
    "content": "### 477. Total Hamming Distance\n\n\n\n题目:\n<https://leetcode.com/problems/total-hamming-distance/>\n\n\n难度:\nMedium\n\n思路：\n\n\n第一想法就是暴力，直接超时\n\n```\nclass Solution(object): # 此法超时\n    def totalHammingDistance(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        res = 0\n        for i in range(len(nums)):\n            for j in range(i+1, len(nums)):\n                res += bin(nums[i]^nums[j]).count('1')\n        return res\n```\n\n\n前面的解法是```O(n^2)```所以超时，所以我们想想有没有```O(n)```的解法\n对于所有的数字，我们先从右数第一位开始算，如果一共有```n```个数字，其中```k```个数字的右数第一位是```‘1’```，其他```n-k```个数字的右数第一位是```‘0’```，\n所以这一位对最终```res```的贡献就是```k*(n-k)```,这样我们的时间复杂度就是```O(32n)```，也就是```O(N)```了\n\n```\nfor each “column” or bit position, once you count the number of set bits you can figure out the number of pairs \nthat will contribute to the count using combination logic.\n\nConsider you have 10 numbers and only one of them is a 1 the rest are zeros. How many (1, 0) pairs can you make? \nClearly you can make 9, pair the 1 with each of the other 9 zeros. If you have 2 ones, \nyou can pair each of those with the other 8 zeros giving 2*8 = 16. \nKeep going and you see that you can pair each 1 with each zero so the number of pairs is just the number of 1’s times the number of 0’s.\n\nThis would be an O(32 * n) solution which is an O(n) solution, no space used.\n```\n\nAC代码\n\n```python\nclass Solution(object):\n    def totalHammingDistance(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        # iterate thru \"column\" or bit position\n        # Note: you could stop at 10^9 as stated in the problem if you want to optimize\n        res = 0\n        for i in range(32):\n            mask = 1 << i\n            count_ones, count_zeros = 0, 0\n            for num in nums:\n                if num & mask != 0:\n                    count_ones += 1\n                else:\n                    count_zeros += 1\n            res += count_ones * count_zeros\n        return res\n```\n\n上面的代码简化一下就是[stefan大神(老流氓罒ω罒)](https://leetcode.com/problems/total-hamming-distance/discuss/96229)的无敌一行了\n\n```python\nclass Solution(object): # 此法超时\n    def totalHammingDistance(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        return sum(b.count('0') * b.count('1') for b in zip(*map('{:032b}'.format, nums)))\n```\n"
  },
  {
    "path": "docs/leetcode/python/485._Max_Consecutive_Ones.md",
    "content": "### 485. Max Consecutive Ones\n\n\n\n题目:\n<https://leetcode.com/problems/max-consecutive-ones/>\n\n\n难度:\nEasy\n\n思路：\n\n\n一行无敌\n```python\nclass Solution(object):\n    def findMaxConsecutiveOnes(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        return len(max(''.join(map(str, nums)).split('0')))\n```\n\n```python\nclass Solution(object):\n    def findMaxConsecutiveOnes(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        res, count = [], 0\n        for x in nums:\n            count = 0 if x == 0 else count + 1\n            res.append(count)\n        return max(res)\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/494._Target_Sum.md",
    "content": "#  494. Target Sum\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/target-sum\n\n> 内容描述\n\n```\nYou are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and - as its new symbol.\n\nFind out how many ways to assign symbols to make sum of integers equal to target S.\n\nExample 1:\nInput: nums is [1, 1, 1, 1, 1], S is 3. \nOutput: 5\nExplanation: \n\n-1+1+1+1+1 = 3\n+1-1+1+1+1 = 3\n+1+1-1+1+1 = 3\n+1+1+1-1+1 = 3\n+1+1+1+1-1 = 3\n\nThere are 5 ways to assign symbols to make the sum of nums be target 3.\nNote:\nThe length of the given array is positive and will not exceed 20.\nThe sum of elements in the given array will not exceed 1000.\nYour output answer is guaranteed to be fitted in a 32-bit integer.\n```\n\n## 解题方案\n\n> 思路 1\n\n递归，findSum(s, start_idx) 函数的意思是从start_index开始向后的子集合能有几种得到s的方法\n\n```\nclass Solution(object):\n    def findTargetSumWays(self, nums, S):\n        \"\"\"\n        :type nums: List[int]\n        :type S: int\n        :rtype: int\n        \"\"\"\n        def findSum(s, start_idx):\n            if start_idx == len(nums):\n                return 1 if s == 0 else 0\n            return findSum(s+nums[start_idx], start_idx+1) + findSum(s-nums[start_idx], start_idx+1)\n        return findSum(S, 0)\n```\n\n但是这样会超时，所以用cache 记一下\n\n```python\nclass Solution(object):\n    def findTargetSumWays(self, nums, S):\n        \"\"\"\n        :type nums: List[int]\n        :type S: int\n        :rtype: int\n        \"\"\"\n        def findSum(s, start_idx):\n            if start_idx == len(nums):\n                return 1 if s == 0 else 0\n            if (s, start_idx) not in cache:\n                cache[(s, start_idx)] = findSum(s+nums[start_idx], start_idx+1) + findSum(s-nums[start_idx], start_idx+1)\n            return cache[(s, start_idx)]\n            \n        cache = {}\n        return findSum(S, 0)\n```\n\n> 思路 2\n\n首先我们要找到一个集合 X 的正sum和其补集 Y 的负sum之和为target.\n- 则有 sum(X) - sum(Y) = target\n- 又有 sum(X) + sum(Y) = sum(nums)\n- ---> 因此由 1 式和 2 式证得：sum(X) = (sum(nums) + target) / 2\n\n因此题目就变成了找到了一个subset的正sum为(sum(nums) + target) / 2\n\n于是动态规划，利用[leetcode416题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/416._Partition_Equal_Subset_Sum.md)的思想\n\n但是这次dp[i]代表的是能够找出几个subset的sum等于i, 例如dp[0] = 1是必然的，因为我们只能取空子集，才能得到sum为0\n\n```python\nclass Solution(object):\n    def findTargetSumWays(self, nums, S):\n        \"\"\"\n        :type nums: List[int]\n        :type S: int\n        :rtype: int\n        \"\"\" \n        def subsetSum(s):\n            dp = [0] * (s+1)\n            dp[0] = 1\n            for i in range(len(nums)):\n                for j in range(s, nums[i]-1, -1):\n                    dp[j] += dp[j-nums[i]]\n            return dp[-1]\n        \n        if sum(nums) < S or (S+sum(nums)) % 2 > 0:\n            return 0\n        return subsetSum((S+sum(nums))/2)\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/536._Construct_Binary_Tree_from_String.md",
    "content": "#  536. Construct Binary Tree from String\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/construct-binary-tree-from-string\n\n> 内容描述\n\n```\nYou need to construct a binary tree from a string consisting of parenthesis and integers.\n\nThe whole input represents a binary tree. It contains an integer followed by zero, one or two pairs of parenthesis. The integer represents the root's value and a pair of parenthesis contains a child binary tree with the same structure.\n\nYou always start to construct the left child node of the parent first if it exists.\n\nExample:\nInput: \"4(2(3)(1))(6(5))\"\nOutput: return the tree root node representing the following tree:\n\n       4\n     /   \\\n    2     6\n   / \\   / \n  3   1 5   \nNote:\nThere will only be '(', ')', '-' and '0' ~ '9' in the input string.\nAn empty tree is represented by \"\" instead of \"()\".\n```\n\n## 解题方案\n\n> 思路 1\n\n递归，每次先找到左子树，然后判断有无右子树，继续下去\n\n```python\nclass Solution(object):\n    def str2tree(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: TreeNode\n        \"\"\"\n        if not s or len(s) == 0:\n            return None\n        if '(' not in s:\n            return TreeNode(int(s))\n        \n        def paren_pair_idx(s):   \n            paren_count = 0\n            for i in range(len(s)):\n                if s[i] == '(':\n                    paren_count += 1\n                elif s[i] == ')':\n                    paren_count -= 1\n                if paren_count == 0 and i > s.find('('):\n                    return (s.find('('), i)\n                \n        root = TreeNode(int(s[:s.find('(')]))\n        (paren_left, paren_right) = paren_pair_idx(s)\n        root.left = self.str2tree(s[paren_left+1: paren_right])\n        if paren_right < len(s) - 1:\n            root.right = self.str2tree(s[paren_right+2:-1])  \n        else:\n            root.right = None\n        return root\n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/587._Erect_the_Fence.md",
    "content": "\n\n### 587. Erect the Fence\n\n\n题目:\n<https://leetcode.com/problems/Erect-the-Fence/>\n\n\n难度:\n\nHard\n\n\n\n思路\n\n题目要求用一个围栏把所有的点（🌲）围起来，然后求处于围栏上点（🌲）的集合。\n\n我们可以发现，从最左边的那个点一直往右走，只要一直都是走的逆时针方向，那么我们一定可以找到这条围栏。那么接下来就考虑最简单的情况，\n\n- 只有两个点```p```和```q```，我们从```p```走到```q```，当```p```到原点这条直线的斜率小于```q```到原点这条直线的斜率时，```p->q```就是沿逆时针方向走的；\n- 接下来考虑3个点:```p，q，r```，以```p```为参照点（即前面的原点），那么从```q```走到```r```的时候，只要```q```到```q```这条直线的斜率小于```r```到```p```这条直线的斜率，```q->r```就是沿逆时针方向走的。\n\n因此，我们只要构建一个```orientation```函数，就可以判断出目前我们的围栏是不是沿着逆时针在走下去了。\n\n我们用一个```stack```来存放目前认为在围栏上的点的集合，然后把所有的点按照指定规则排好序：```先按照点的x坐标升序排列，如果x相等则按照点的y坐标升序排列```。这样我们依次取点，只要```stack```里面的点大于等于```2```个我们就要无限进行判断是否走的是逆时针，如果不是就把```stack```里面最后那个点```pop```出去（可能一直```pop```到只剩一个点），否则就把目前的这个点加入到```stack```中去，因为目前它还是在逆时针方向上的。\n\n从左往右走完一遍```points```之后，我们围栏的下部分```lower hull```就构建好了，此时我们还要构建围栏的```upper hull```，因此我们将```points```逆序一下，从右往左再来一次遍历，仍然看是否走的是逆时针。但是这次遍历我们需要进行一个判断，就是之前放进```stack```的点，此时我们还是会经过它，如果它已经在```stack```里面了，我们就不需要再加进去了，同时这样也避免了我们把最左边的点重复加进去。\n\n\n\n```python\npython\n# import functools\nclass Solution:\n    def outerTrees(self, points):\n        \"\"\"\n        :type points: List[Point]\n        :rtype: List[Point]\n        \"\"\"\n        def orientation(p, q, r):\n            return (q.y - p.y)*(r.x - p.x) - (r.y - p.y)*(q.x - p.x)\n        # def myComparator(p,q):\n        #     return p.x - q.x if p.x != q.x else p.y - q.y\n        stack= []\n        # points.sort(key = functools.cmp_to_key(myComparator))\n        points.sort(key = lambda p: (p.x, p.y))\n        for i in range(len(points)):\n            while (len(stack) >= 2 and orientation(stack[-2],stack[-1],points[i]) > 0):\n                stack.pop()\n            stack.append(points[i])\n        points.reverse();\n        for i in range(len(points)):\n            while (len(stack) >= 2 and orientation(stack[-2],stack[-1],points[i]) > 0):\n                stack.pop()\n            if points[i] not in stack:\n                stack.append(points[i])\n        return stack\n```\n简化python版本\n```python\nclass Solution(object):\n    def outerTrees(self, points):\n        \"\"\"\n        :type points: List[Point]\n        :rtype: List[Point]\n        \"\"\"\n        def orientation(p, q, r):\n            return (q.y - p.y) * (r.x - q.x) - \\\n                   (q.x - p.x) * (r.y - q.y)\n\n        hull = []\n        points.sort(key=lambda p: (p.x, p.y))\n\n        for i in itertools.chain(xrange(len(points)), \\\n                                 reversed(xrange(len(points)))):\n            while len(hull) >= 2 and \\\n                  orientation(hull[-2], hull[-1],  points[i]) > 0:\n                hull.pop()\n            hull.append(points[i])\n\n        return list(set(hull))\n```\n\n下面是小傅大神的代码，本来想叫‘’傅神‘’的，结果这名字🤦‍♂️（手动捂脸）[小傅每日一题587](https://www.bilibili.com/video/av15446980/)\n\n另外其中的```stack.pop()```这行代码注释掉也是可以的\n\n```java\njava\nclass Solution {\n    public List<Point> outerTrees(Point[] points) {\n        List<Point> res = new ArrayList<Point>();\n        Arrays.sort(points, new Comparator<Point>(){\n            @Override\n            public int compare(Point p, Point q){\n                return p.x == q.x ? p.y - q.y : p.x - q.x;\n            }\n        });\n        Stack<Point> stack = new Stack<>();\n        for (int i = 0; i < points.length; i++){\n            while(stack.size() >= 2 && orientation(stack.get(stack.size() - 2), stack.peek(), points[i]) > 0){\n                stack.pop();\n            }\n            stack.push(points[i]);\n        }\n        //stack.pop();\n        for (int i = points.length - 1; i >= 0; i--){\n            while(stack.size() >= 2 && orientation(stack.get(stack.size() - 2), stack.peek(), points[i]) > 0){\n                stack.pop();\n            }\n            stack.push(points[i]);\n        }\n        res.addAll(new HashSet<>(stack));\n        return res;\n    }\n    \n    public int orientation(Point p, Point q, Point r){\n        return (q.y - p.y)*(r.x - p.x) - (r.y - p.y)*(q.x - p.x);\n    }\n}\n```\n\n\n\n\n\nAuthor: Keqi Huang\n\nIf you like it, please spread your support\n\n![Support](/img/Algorithm/LeetCode/WechatIMG17.jpeg)\n"
  },
  {
    "path": "docs/leetcode/python/599._Minimum_Index_Sum_of_Two_Lists.md",
    "content": "### 599. Minimum Index Sum of Two Lists\n\n\n题目:\n<https://leetcode.com/problems/Minimum-Index-Sum-of-Two-Lists/>\n\n\n难度:\n\nEasy\n\n\n\n思路\n\n两个list，我们首先要取得它们相同的部分，并且之后我们还要知道哪个相同的字符串在两个list中的index之和是最小的。\n- 所以我们首先遍历list1，只要目前这个字符串在list2中，我们就以[字符串，index之和]的形式将其存放到ress中，同时维护一个index保持为最小index之和的值\n- 对于ress，我们遍历，只要某一项的index之和等于最小index之和我们就将他的字符串以i[0]的形式append到res中去，\n- return res\n\n### 程序变量解释\n\n- ress format: [[string1, sumOfIndex1], [string2, sumOfIndex2]... ]\n- index 最小sunOfIndex值\n- res 最终结果，foramt: [string1, string2,. ...]\n\n\n\n\n```python\npython\nclass Solution:\n    def findRestaurant(self, list1, list2):\n        \"\"\"\n        :type list1: List[str]\n        :type list2: List[str]\n        :rtype: List[str]\n        \"\"\"\n        ress = []\n        index = 2000\n        for i in list1:\n            if i in list2:\n                ress.append([i, list1.index(i)+list2.index(i)])\n                index = min(index, list1.index(i)+list2.index(i))\n        res = []\n        for i in ress:\n            if i[1] == index:\n                res.append(i[0])\n        return res\n```\n\n\n\nAuthor: Keqi Huang\n\nIf you like it, please spread your support\n\n![Support](/img/Algorithm/LeetCode/WechatIMG17.jpeg)\n"
  },
  {
    "path": "docs/leetcode/python/606._Construct_String_from_Binary_Tree.md",
    "content": "#  606. Construct String from Binary Tree\n**<font color=red>难度: 简单</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/construct-string-from-binary-tree\n\n> 内容描述\n\n```\nYou need to construct a string consists of parenthesis and integers from a binary tree with the preorder traversing way.\n\nThe null node needs to be represented by empty parenthesis pair \"()\". And you need to omit all the empty parenthesis pairs that don't affect the one-to-one mapping relationship between the string and the original binary tree.\n\nExample 1:\nInput: Binary tree: [1,2,3,4]\n       1\n     /   \\\n    2     3\n   /    \n  4     \n\nOutput: \"1(2(4))(3)\"\n\nExplanation: Originallay it needs to be \"1(2(4)())(3()())\", \nbut you need to omit all the unnecessary empty parenthesis pairs. \nAnd it will be \"1(2(4))(3)\".\nExample 2:\nInput: Binary tree: [1,2,3,null,4]\n       1\n     /   \\\n    2     3\n     \\  \n      4 \n\nOutput: \"1(2()(4))(3)\"\n\nExplanation: Almost the same as the first example, \nexcept we can't omit the first parenthesis pair to break the one-to-one mapping relationship between the input and the output.\n```\n\n## 解题方案\n\n> 思路 1\n\n递归\n\n```python\nclass Solution(object):\n    def tree2str(self, t):\n        \"\"\"\n        :type t: TreeNode\n        :rtype: str\n        \"\"\"\n        if not t:\n            return ''\n        res = str(t.val)\n        if t.left and t.right:\n            res += '(' + self.tree2str(t.left) + ')' + '(' + self.tree2str(t.right) + ')'\n        elif not t.left and t.right:\n            res += '()(' + self.tree2str(t.right) + ')'\n        elif t.left and not t.right:\n            res += '(' + self.tree2str(t.left) + ')'\n        return res\n```\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/611._Valid_Triangle_Number.md",
    "content": "# 611. Valid Triangle Number 有效三角形的个数\n\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/valid-triangle-number\n* https://leetcode-cn.com/problems/valid-triangle-number\n\n> 内容描述\n\n```\n给定一个包含非负整数的数组，你的任务是统计其中可以组成三角形三条边的三元组个数。\n\n示例 1:\n\n输入: [2,2,3,4]\n输出: 3\n解释:\n有效的组合是: \n2,3,4 (使用第一个 2)\n2,3,4 (使用第二个 2)\n2,2,3\n注意:\n\n数组长度不超过1000。\n数组里整数的范围为 [0, 1000]。\n```\n\n## 解题方案\n\n> 思路 1\n\n明确一点，三角形三边为a, b, c，那么何时满足可以组成一个三角形呢？\n要同时满足以下3点：\n1. a + b > c\n2. a + c > b\n3. b + c > a\n\n首先对数组逆向排序，固定第一个数字，我们发现```nums[i] >= nums[j] >= nums[k]```, \n所以我们现在只需要保证```nums[j] + nums[k] > nums[i]```即可，\n因为```nums[i] + nums[j] > nums[k]```和```nums[i] + nums[k] > nums[j]```是肯定的\n\n后面开始二分，分两种情况：\n- 如果```nums[j] + nums[k] > nums[i]```，那么我们只需要将```j += 1```使得比较式前面变小继续判断，\n并且```res += k - j```，因为组合```i, j, [j+1...k]```都可以满足比较式，我们需要全部加起来，后面不会再次判断了\n- 如果```nums[j] + nums[k] <= nums[i]```，那么我们只需要将```k -= 1```使得比较式前面变大继续判断是否满足比较式\n\n\n```python\nclass Solution(object):\n    def triangleNumber(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        nums = sorted(nums)[::-1]\n        res = 0\n        for i in range(len(nums)-2):\n            j, k = i + 1, len(nums) - 1\n            while j < k:\n                if nums[k] + nums[j] > nums[i]:\n                    res += k - j\n                    j += 1                \n                else:\n                    k -= 1\n        return res\n```\n这里真的我遇到了两次坑，首先如果我们排序用的是正向排序的话，那么我们需要做的是固定最后一个数，否则会出现（假如固定第一个数）：\n- 等式满足，我们将```j -= 1``，那么就有可能漏掉了一种情况，就是原本组合```i, j, [j+1...k-1]```可以满足，但是我们这里没有加上\n- 等式满足，我们将```k += 1``，那么就有可能漏掉了一种情况，就是原本组合```i, [j+1...k-1], k```可以满足，但是我们这里没有加上\n\n所以二分法真的没有那么简单，我们需要充分根据实际场景去改变我们的固定位置和前后更新方向\n\n这里也给出正向排序的代码：\n\n\n```python\nclass Solution(object):\n    def triangleNumber(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        nums.sort()\n        res = 0\n        for k in range(len(nums)-1, 1, -1):\n            i, j = 0, k - 1\n            while i < j:\n                if nums[i] + nums[j] > nums[k]:\n                    res += j - i\n                    j -= 1\n                         \n                else:\n                    i += 1\n        return res\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/646._Maximum_Length_of_Pair_Chain.md",
    "content": "#  646. Maximum Length of Pair Chain\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/maximum-length-of-pair-chain\n\n> 内容描述\n\n```\nYou are given n pairs of numbers. In every pair, the first number is always smaller than the second number.\n\nNow, we define a pair (c, d) can follow another pair (a, b) if and only if b < c. Chain of pairs can be formed in this fashion.\n\nGiven a set of pairs, find the length longest chain which can be formed. You needn't use up all the given pairs. You can select pairs in any order.\n\nExample 1:\nInput: [[1,2], [2,3], [3,4]]\nOutput: 2\nExplanation: The longest chain is [1,2] -> [3,4]\nNote:\nThe number of given pairs will be in the range [1, 1000].\n```\n\n## 解题方案\n\n> 思路 1\n\n先按照start --> end中的end排序，即```pairs = sorted(pairs, key=lambda x:x[1])```\n\n原因在于，你想想看，如果我们已经取得了最长的那一条序列，end最小的那个pair肯定在里面对不对？\n如果你说不对，那假设它不在里面，现在max_chain的第一个pair是不是至少可以被end最小的那个pair替代，因为我的end比你更小，你都可以我为什么不可以，甚至如果我的\nend比你的start小的话，我还可以加在你前面呢，这样max_chain岂不是就不是最长的chain了？\n\n综上所述，我们只要先按照start --> end中的end排序，然后从第一个慢慢向下判断就行，如果不符合就跳过，符合我们就把长度加1，这样最后肯定是对的。\n\nAC代码如下：\n\n\n```python\nclass Solution(object):\n    def findLongestChain(self, pairs):\n        \"\"\"\n        :type pairs: List[List[int]]\n        :rtype: int\n        \"\"\"\n        if not pairs or len(pairs) == 0:\n            return 0\n        pairs = sorted(pairs, key=lambda x:x[1])\n        res, i = 0, -1\n        while i + 1 < len(pairs):\n            res += 1\n            i += 1\n            cur_end = pairs[i][1]\n            while i + 1 < len(pairs) and pairs[i+1][0] <= cur_end:\n                i += 1\n        return res\n```\n\n发现有大佬比我牛p多了，代码更nice\n\n```python\nclass Solution(object):\n    def findLongestChain(self, pairs):\n        \"\"\"\n        :type pairs: List[List[int]]\n        :rtype: int\n        \"\"\"\n        if not pairs or len(pairs) == 0:\n            return 0\n        cur, res = float('-inf'), 0\n        for p in sorted(pairs, key=lambda x: x[1]):\n            if cur < p[0]: cur, res = p[1], res + 1\n        return res\n```\n\n\n\n\n> 思路 2\n\n动态规划\n\n思路看代码就理解了，不宜多说\n\n\n\n```\nclass Solution(object):\n    def findLongestChain(self, pairs):\n        \"\"\"\n        :type pairs: List[List[int]]\n        :rtype: int\n        \"\"\"\n        if not pairs or len(pairs) == 0:\n            return 0\n        pairs = sorted(pairs, key=lambda x:x[0])\n        dp = [1] * len(pairs)\n        for i in range(1, len(pairs)):\n            for j in range(i):\n                dp[i] = max(dp[i], dp[j] + 1 if pairs[i][0] > pairs[j][1] else dp[j])\n        return dp[-1]\n```\n这样会超时，不知道为啥，然后改了下代码的写法就过了，beats 2.21% 哈哈哈哈哈, 管它呢，过了就行，代码如下：\n\n```python\nclass Solution(object):\n    def findLongestChain(self, pairs):\n        \"\"\"\n        :type pairs: List[List[int]]\n        :rtype: int\n        \"\"\"\n        if not pairs or len(pairs) == 0:\n            return 0\n        pairs = sorted(pairs, key=lambda x:x[0])\n        dp = [1] * len(pairs)\n        for i in range(1, len(pairs)):\n            dp[i] = max([dp[j] + 1 if pairs[i][0] > pairs[j][1] else dp[j] for j in range(i)])\n        return dp[-1]\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/647._Palindromic_Substrings.md",
    "content": "### 647. Palindromic Substrings\n\n题目:\n<https://leetcode.com/problems/Palindromic-Substrings/>\n\n\n难度:\n\nMedium\n\n\n思路\n\n这道题要求给定一个字符串中的所有回文子串的个数，所以我想到了Manacher算法，\n[Manacher算法](https://www.felix021.com/blog/read.php?2040) \n\nManacher算法增加两个辅助变量id和mx，其中id表示最大回文子串中心的位置，mx则为id+P[id]，也就是最大回文子串的边界。得到一个很重要的结论：\n\n- 如果mx > i，那么P[i] >= Min(P[2 * id - i], mx - i) . 为什么这样说呢，下面解释\n\n下面，令j = 2*id - i，也就是说j是i关于id的对称点。\n\n- 当 mx - i > P[j] 的时候，以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中，由于i和j对称，以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中，所以必有P[i] = P[j]；\n![](/img/Algorithm/LeetCode/manacher1.png)\n\n- 当 P[j] >= mx - i 的时候，以S[j]为中心的回文子串不一定完全包含于以S[id]为中心的回文子串中，但是基于对称性可知，下图中两个绿框所包围的部分是相同的，也就是说以S[i]为中心的回文子串，其向右至少会扩张到mx的位置，也就是说 P[i] >= mx - i。至于mx之后的部分是否对称，再具体匹配。\n![](/img/Algorithm/LeetCode/manacher2.png)\n所以P[i] >= Min(P[2 * id - i], mx - i)，因为以j为中心的绘回文子串的左边界可能会比mx关于id的对称点要大，此时只能证明P[i]=P[2 * id - i]\n- 此外，对于 mx <= i 的情况，因为无法对 P[i]做更多的假设，只能让P[i] = 1，然后再去匹配。\n此题还可以借鉴我leetcode第5题的解析，\n[thining-in-lc-5](https://github.com/Lisanaaa/thinking_in_lc/blob/master/005._longest_palindromic_substring.md)\n\n这道题的基本思想是将以每一个字符为中心的回文子串个数相加，还是用一个小例子来解释\n![](/img/Algorithm/LeetCode/manacher3.jpg)\n其实，以‘#’为中心的回文子串就代表这个子串的长度是偶数，类似于'abba'这种\n但是其实这个字符本身也是一个回文子串，所以叠加的形式是count += (P[i]+1)/2，为什么呢，以下是解释：\n- 对于每一个以字符‘#’为中心的回文子串，其P值绝对是偶数，所以```(P[i]+1)/2 = P[i]/2```，并不影响\n- 对于每一个以非字符‘#’为中心的回文子串，其P值绝对是奇数，这就保证了单个字母的回文子串(```例如'a'也算一个回文子串```)也被加起来了，因为```(P[i]+1)/2 = P[i]/2+1```\n\n\n```python\nclass Solution(object):\n    def countSubstrings(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: str\n        \"\"\"\n        def preProcess(s):\n            if not s:\n                return ['^', '$']\n            T = ['^']\n            for c in s:\n                T += ['#', c]\n            T += ['#', '$']\n            return T\n        T = preProcess(s)\n        P = [0] * len(T)\n        id, mx, count = 0, 0, 0\n        for i in range(1,len(T) - 1):\n            j = 2*id - i\n            if mx > i:\n                P[i] = min(mx - i, P[j])\n            else:\n                P[i] = 0\n            while T[i+P[i]+1] == T[i-P[i]-1]:\n                P[i] += 1\n            if (i + P[i]) > mx:\n                id, mx = i, i + P[i]\n        for i in range(len(P)):\n            count += (P[i]+1)/2\n        return count\n```\npython无敌啊！！！有没有天理啊，手动滑稽😏😏😏😏！一行解法：\n```python\nclass Solution(object):\n    def countSubstrings(self, s):\n        \"\"\"\n        :type s: str\n        :rtype: int\n        \"\"\"\n        return sum(len(os.path.commonprefix((s[:i][::-1], s[i:]))) \n                   + len(os.path.commonprefix((s[:i][::-1], s[i + 1:]))) + 1 \n                        for i in range(len(s)))\n```\n解释下为啥要加两次，因为回文串有以下两种形式：\n- ‘abcba’\n- 'abba'\n\n那为啥要加那个1呢，上面解释过了，单个字符也算是一个回文子串呀，嘻嘻😁\n"
  },
  {
    "path": "docs/leetcode/python/657._Judge_Route_Circle.md",
    "content": "### 657. Judge Route Circle\n题目:\n<https://leetcode.com/problems/judge-route-circle/>\n\n\n难度:\n\nEasy\n\n\n\n\n```python\nclass Solution(object):\n    def judgeCircle(self, moves):\n        \"\"\"\n        :type moves: str\n        :rtype: bool\n        \"\"\"\n        return moves.count('D') == moves.count('U') and moves.count('R') == moves.count('L')\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/665._Non-decreasing_Array.md",
    "content": "### 665. Non-decreasing Array\n\n题目:\n<https://leetcode.com/problems/Non-decreasing-Array/>\n\n\n难度:\n\nEasy\n\n\n思路\n\n从index=1的元素依次检查，只要不符合规则则让count+1，如果count>1则肯定不符合返回False\n但是我们在发现nums[i]小于nums[i-1]的时候，我们就必须要对原数组作出改变了，来让它的后面index部分尽可能满足条件\n下面就是两种情况：\n- 2,4,2,6\n\n如果是这种情况，当index=2时，不满足条件，但是i=0的元素是小于i=2处元素的，我们需要改变的是i-1处的元素，也就是将4改变成i=2处元素即2，最终变成2,2,2,6\n\n- 3,4,2,6\n\n这种情况如果我们将4变成2那么仍然是不满足条件的，此时我们需要将2变成4，即将i处元素变为i-1处元素\n\n在每一次不符合条件的时候我们都检查一下count，如果count大于1的话我们就返回False，否则最终就返回True\n\n```python\nclass Solution(object):\n    def checkPossibility(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: bool\n        \"\"\"\n        count = 0\n        for i in range(1,len(nums)):\n            if nums[i] < nums[i-1]:\n                count += 1\n                if count > 1:\n                    return False\n                if i - 2 < 0 or nums[i-2] <= nums[i]:\n                    nums[i-1] = nums[i]\n                else:\n                    nums[i] = nums[i-1]\n        return True\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/672._Bulb_Switcher_II.md",
    "content": "### 672. Bulb Switcher II\n\n题目:\n<https://leetcode.com/problems/Bulb-Switcher-II/>\n\n\n难度:\n\nMedium\n\n\n思路\n\n这道题又是一个数学题。找规律呀找规律。\n我们只需要考虑当 n<=2 and m < 3 的特殊情形。因为当 n >2 and m >=3, 结果肯定是 8.\nThe four buttons:\n\n- Flip all the lights.\n- Flip lights with even numbers.\n- Flip lights with odd numbers.\n- Flip lights with (3k + 1) numbers, k = 0, 1, 2, ...\n\n如果我们使用了 button 1 和 2, 其效果等同于使用 button 3 。\n类似的..\n\n- 1 + 2 --> 3\n- 1 + 3 --> 2\n- 2 + 3 --> 1\n\n所以，只有 8 种情形。\n\n***灯全亮, 操作1, 操作2, 操作3, 操作4, 操作1+4, 操作2+4, 操作3+4***\n\n并且当 n>2 and m>=3 时，我们就能够获得所有的情形。\n\n| m\\n  | 0  | 1  | 2  | 3 | 4 |\n ---   |----|--- |----|---|---|\n| 0    | 1  | 1  | 1  | 1 | 1 |\n| 1    | 1  | 2  | 3  | 4 | 4 |\n| 2    | 1  | 2  | 4  | 7 | 7 |\n| 3    | 1  | 2  | 3  | 8 | 8 |\n\n```python\nclass Solution(object):\n    def flipLights(self, n, m):\n        \"\"\"\n        :type n: int\n        :type m: int\n        :rtype: int\n        \"\"\"\n        if m * n == 0: return 1\n        if n == 1: return 2\n        if n == 2: return 4 - (m % 2)\n        if m == 1: return 4\n        if m == 2: return 7\n        return 8\n```\n\n还有两位大佬的两行解法：\n```python\nclass Solution(object):\n    def flipLights(self, n, m):\n        m, n = min(3, m), min(3, n)\n        return 1 if n * m == 0 else self.flipLights(n - 1,  m) + self.flipLights( n - 1, m - 1) \n```\n```python\nclass Solution(object):\n    def flipLights(self, n, m):\n        n = min(n, 3)\n        return min(1<<n, 1+m*n)\n\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/681._Next_Closest_Time.md",
    "content": "### 681. Next Closest Time\n\n\n题目:\n<https://leetcode.com/problems/next-closest-time/>\n\n\n难度:\n\nMedium\n\n\n\n思路\n\n题目说输入一个时间，format是HH:MM, 然后输出接下来最近的一个时间，且这个时间的数字必须要在输入的时间中可以找到，所以我们用```h```, ```m```\n分别代表输入时间的小时数和分钟数，然后可以计算出输入时间的总分钟数```curr```，在未来的一天之内，我们一分钟一分钟往下面试，第一个满足的就直接\n作为结果就行了.\n\n\n\n\n```python\nclass Solution(object):\n    def nextClosestTime(self, time):\n        \"\"\"\n        :type time: str\n        :rtype: str\n        \"\"\"\n        h, m = time.split(\":\")\n        curr = int(h) * 60 + int(m)  # 这里要注意h可能会是0开头的，如输入的时间为01:22，所以需要int(h)和int(m)\n        result = None\n        for i in xrange(curr+1, curr+1441):\n            t = i % 1440\n            h, m = t // 60, t % 60\n            result = \"%02d:%02d\" % (h, m)\n            if set(result) <= set(time):\n                break\n        return result\n```\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/682._Baseball_Game.md",
    "content": "### 682. Baseball Game\n\n题目:\n<https://leetcode.com/problems/Baseball-Game/>\n\n\n难度:\n\nEasy\n\n\n思路\n\npoints用来存放每一次的分数，最后求和。\n\n\n```python\nclass Solution(object):\n    def calPoints(self, ops):\n        \"\"\"\n        :type ops: List[str]\n        :rtype: int\n        \"\"\"\n        points = []\n        for i in ops:\n            if i == 'C':\n                points.pop()\n            elif i == 'D':\n                points.append(2 * points[-1])\n            elif i == '+':\n                points.append(points[-1] + points[-2])\n            else:\n                points.append(int(i))\n        return sum(points)\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/685._Redundant_Connection_II.md",
    "content": "### 685. Redundant Connection II\n\n题目： \n<https://leetcode.com/problems/redundant-connection-ii/>\n\n\n难度 : Hard\n\n\n\n我们先定义一下，每条边的第一个点是parent，第二个点是child，例如 2 -> 1 中 node 2 就是 parent，而 node 1 就是 child\n\n明确这个之后，我们要知道图中有一条边是 invalid 的，去除它之后整个图就变成了一棵树，那么什么情况下一个边会导致树变成图呢：\n\n1. 如果一个child 在此之前已经有过一个parent了，那么意味着它有两个parent，这在树中肯定是不合法的。\n在代码中体现为```node_parent[child] != child```，这说明在碰到此时的parent之前我们就已经更新过node_parent[child]了，即child之前已经有一个parent了\n2. 如果一个child 的 parent 的 parent（或者一直往上找） 就是 child 本身，那么这意味着有环，这在树中也肯定是不合法的。\n在代码中体现为```find(node_parents, parent) == child```, 这说明child的parent的parent或以上就是child本身，即有环。\n例如 ```1 --> 2 --> 1```或者```1 --> 2 --> 3 --> 1```\n\n因此我们可以定义一个列表 node_parent，在最开始的时候，此列表的 index 和 value 一一相等。\n\n然后我们对edges进行第一轮遍历（正序遍历），并且用count来计数不合法的边：\n- 如果只找到一条不合法的边，那么直接返回它即可\n- 如果有超过一条不合法的边，那么我们就进行第二轮遍历（逆序遍历），返回碰到的第一条不合法的边，\n这里是为了节约时间，因为如题意我们要返回的是最后一条出现的边，那么我们逆序就更省时间嘛\n\n\n```python\nclass Solution(object):\n    def findRedundantDirectedConnection(self, edges):\n        \"\"\"\n        :type edges: List[List[int]]\n        :rtype: List[int]\n        \"\"\"\n    \n        def find(node_parent, parent):\n            return parent if node_parent[parent] == parent else find(node_parent, node_parent[parent])\n        \n        n, count = len(edges), 0 # 用 count 来计数不合法的边\n        node_parent = [i for i in range(n+1)]\n        res = [0, 0]\n        \n        # 第一轮查找不合法的边 （正序）\n        for i in range(n):\n            parent, child = edges[i][0], edges[i][1]\n            if node_parent[child] != child or find(node_parent, parent) == child:\n                res = edges[i]\n                count += 1\n            else:\n                node_parent[child] = parent\n        if count == 1: # 如果只有一条不合法的边，直接返回\n            return res \n        \n        # 重置 node_parent 并开始第二轮查找 （逆序）\n        node_parent = [i for i in range(n+1)]\n        for i in range(n-1, -1, -1):\n            parent, child = edges[i][0], edges[i][1]\n            if node_parent[child] != child or find(node_parent, parent) == child:\n                return edges[i]\n            else:\n                node_parent[child] = parent\n        return res\n```\n这道题感谢[xyzxuyizhen](https://leetcode.com/problems/redundant-connection-ii/discuss/128596/Easy-to-understand-Java-Solution-Union-Find)大佬，\n看到他的思路才逃离了我之前的很复杂的想法。\n"
  },
  {
    "path": "docs/leetcode/python/687._Longest_Univalue_Path.md",
    "content": "### 687. Longest Univalue Path\n\n\n题目:\n<https://leetcode.com/problems/longest-univalue-path/>\n\n\n难度:\n\nEasy\n\n\n\n思路\n\n这道题也只能算个```easy```题目，根据传进来的```root```，我们只要从它的左右节点不停的递归下去，只要其```value```值与```root```一样，\n该方向上的```length```就加```1```，最后我们将左右方向上的```length```相加, 递归取最大值\n##### 很重要的一点就是，Note: The length of path between two nodes is represented by the number of edges between them.\n- 因此是```self.res = max(self.res, left_arrow + right_arrow)```, ```return max(left_arrow, right_arrow)```\n- 而不是```self.res = max(self.res, left_arrow + right_arrow + 1)```, ```return max(left_arrow + 1, right_arrow + 1)```\n\n\n\n\n\n```python\n# Definition for a binary tree node.\n# class TreeNode(object):\n#     def __init__(self, x):\n#         self.val = x\n#         self.left = None\n#         self.right = None\n\nclass Solution(object):\n    def longestUnivaluePath(self, root):\n        \"\"\"\n        :type root: TreeNode\n        :rtype: int\n        \"\"\"\n        self.res = 0\n        def dir_length(node):\n            if not node:\n                return 0\n            left_len = dir_length(node.left)     # 左节点的length\n            right_len = dir_length(node.right)   # 右节点的length\n            left_dir, right_dir = 0, 0\n            if node.left and node.left.val == node.val:\n                left_dir = left_len + 1          # 当前节点的左节点方向的length\n            if node.right and node.right.val == node.val:\n                right_dir = right_len + 1        # 当前节点的右边节点方向的length\n            self.res = max(self.res, left_dir + right_dir)\n            return max(left_dir, right_dir)\n        dir_length(root)\n        return self.res\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/693._Binary_Number_with_Alternating_Bits.md",
    "content": "# 693. Binary Number with Alternating Bits 交替位二进制数\n\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/binary-number-with-alternating-bits\n* https://leetcode-cn.com/problems/binary-number-with-alternating-bits\n\n> 内容描述\n\n```\n给定一个正整数，检查他是否为交替位二进制数：换句话说，就是他的二进制数相邻的两个位数永不相等。\n\n示例 1:\n\n输入: 5\n输出: True\n解释:\n5的二进制数是: 101\n示例 2:\n\n输入: 7\n输出: False\n解释:\n7的二进制数是: 111\n示例 3:\n\n输入: 11\n输出: False\n解释:\n11的二进制数是: 1011\n 示例 4:\n\n输入: 10\n输出: True\n解释:\n10的二进制数是: 1010\n```\n\n## 解题方案\n\n> 思路 1\n\n太简单了，可以一行秒，但是太难看了，还是多写几行吧\n\n调用bin函数转换成二进制以后再转换成字符串，注意二进制前面2为是‘0b’,要记得去掉\n\n```python\nclass Solution(object):\n    def hasAlternatingBits(self, n):\n        \"\"\"\n        :type n: int\n        :rtype: bool\n        \"\"\"\n        tmp = str(bin(n))[2:]\n        res = [tmp[i] != tmp[i-1] for i in range(1, len(tmp))]\n        return all(res)\n```\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/701._Insert_into_a_Binary_Search_Tree.md",
    "content": "# 701. Insert into a Binary Search Tree \n\n**<font color=red>难度: 困难</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/longest-valid-parentheses\n\n> 内容描述\n\n```\nGiven the root node of a binary search tree (BST) and a value to be inserted into the tree, insert the value into the BST. Return the root node of the BST after the insertion. It is guaranteed that the new value does not exist in the original BST.\n\nNote that there may exist multiple valid ways for the insertion, as long as the tree remains a BST after insertion. You can return any of them.\n\nFor example, \n\nGiven the tree:\n        4\n       / \\\n      2   7\n     / \\\n    1   3\nAnd the value to insert: 5\nYou can return this binary search tree:\n\n         4\n       /   \\\n      2     7\n     / \\   /\n    1   3 5\nThis tree is also valid:\n\n         5\n       /   \\\n      2     7\n     / \\   \n    1   3\n         \\\n          4\n```\n\n## 解题方案\n\n> 思路 1\n\n就一句话，看到树🌲就想到递归，太简单了，30秒敲完答案\n\n```python\nclass Solution(object):\n    def insertIntoBST(self, root, val):\n        \"\"\"\n        :type root: TreeNode\n        :type val: int\n        :rtype: TreeNode\n        \"\"\"\n        if not root:\n            return TreeNode(val)\n        if val < root.val:\n            root.left = self.insertIntoBST(root.left, val)\n        if val > root.val:\n            root.right = self.insertIntoBST(root.right, val)\n        return root\n```\n\n"
  },
  {
    "path": "docs/leetcode/python/707._Design_Linked_List.md",
    "content": "# 707. Design Linked List \n\n**<font color=red>难度: Easy</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/design-linked-list\n\n> 内容描述\n\n```\nDesign your implementation of the linked list. You can choose to use the singly linked list or the doubly linked list. A node in a singly linked list should have two attributes: val and next. val is the value of the current node, and next is a pointer/reference to the next node. If you want to use the doubly linked list, you will need one more attribute prev to indicate the previous node in the linked list. Assume all nodes in the linked list are 0-indexed.\n\nImplement these functions in your linked list class:\n\nget(index) : Get the value of the index-th node in the linked list. If the index is invalid, return -1.\naddAtHead(val) : Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.\naddAtTail(val) : Append a node of value val to the last element of the linked list.\naddAtIndex(index, val) : Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.\ndeleteAtIndex(index) : Delete the index-th node in the linked list, if the index is valid.\nExample:\n\nMyLinkedList linkedList = new MyLinkedList();\nlinkedList.addAtHead(1);\nlinkedList.addAtTail(3);\nlinkedList.addAtIndex(1, 2);  // linked list becomes 1->2->3\nlinkedList.get(1);            // returns 2\nlinkedList.deleteAtIndex(1);  // now the linked list is 1->3\nlinkedList.get(1);            // returns 3\nNote:\n\nAll values will be in the range of [1, 1000].\nThe number of operations will be in the range of [1, 1000].\nPlease do not use the built-in LinkedList library.\n```\n\n## 解题方案\n\n> 思路 1\n\n用list模拟，太简单了，🙄️🙄️🙄️\n\n```python\nclass MyLinkedList(object):\n\n    def __init__(self):\n        \"\"\"\n        Initialize your data structure here.\n        \"\"\"\n        self.lst = []\n        \n\n    def get(self, index):\n        \"\"\"\n        Get the value of the index-th node in the linked list. If the index is invalid, return -1.\n        :type index: int\n        :rtype: int\n        \"\"\"\n        if index > len(self.lst) - 1 or index < 0:\n            return -1\n        return self.lst[index]\n        \n\n    def addAtHead(self, val):\n        \"\"\"\n        Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.\n        :type val: int\n        :rtype: void\n        \"\"\"\n        self.lst.insert(0, val)\n        \n\n    def addAtTail(self, val):\n        \"\"\"\n        Append a node of value val to the last element of the linked list.\n        :type val: int\n        :rtype: void\n        \"\"\"\n        self.lst.append(val)\n        \n\n    def addAtIndex(self, index, val):\n        \"\"\"\n        Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.\n        :type index: int\n        :type val: int\n        :rtype: void\n        \"\"\"\n        if index > len(self.lst):\n            return \n        elif index == len(self.lst):\n            self.lst.append(val)\n        else:\n            self.lst.insert(index, val)\n        \n\n    def deleteAtIndex(self, index):\n        \"\"\"\n        Delete the index-th node in the linked list, if the index is valid.\n        :type index: int\n        :rtype: void\n        \"\"\"\n        if index > len(self.lst) - 1 or index < 0:\n            return \n        self.lst.pop(index)\n```\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/740._delete_and_earn.md",
    "content": "### 740. Delete and Earn\n\n题目:\n<https://leetcode.com/problems/delete-and-earn/>\n\n\n难度:\n\nMedium\n\n\n\n\n```python\nclass Solution(object):\n    def deleteAndEarn(self, nums):\n        \"\"\"\n        :type nums: List[int]\n        :rtype: int\n        \"\"\"\n        dp = [0] * 10001\n        for num in nums:\n            dp[num] += num\n        for i in range(2, 10001):\n            dp[i] = max(dp[i]+dp[i-2], dp[i-1])\n        return dp[-1]\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/760._Find_Anagram_Mappings.md",
    "content": "### 760. Find Anagram Mappings\n\n题目:\n<https://leetcode.com/problems/find-anagram-mappings/>\n\n\n难度:\n\nEasy\n\n\n\n\n\n```python\nclass Solution(object):\n    def anagramMappings(self, A, B):\n        \"\"\"\n        :type A: List[int]\n        :type B: List[int]\n        :rtype: List[int]\n        \"\"\"\n        if not A:\n            return []\n        res = []\n        for i in A:\n            res.append(B.index(i))\n        return res\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/774._Minimize_Max_Distance_to_Gas_Station.md",
    "content": "#  774. Minimize Max Distance to Gas Station\n**<font color=red>难度: 困难</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/minimize-max-distance-to-gas-station\n\n> 内容描述\n\n```\nOn a horizontal number line, we have gas stations at positions stations[0], stations[1], ..., stations[N-1], where N = stations.length.\n\nNow, we add K more gas stations so that D, the maximum distance between adjacent gas stations, is minimized.\n\nReturn the smallest possible value of D.\n\nExample:\n\nInput: stations = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], K = 9\nOutput: 0.500000\nNote:\n\nstations.length will be an integer in range [10, 2000].\nstations[i] will be an integer in range [0, 10^8].\nK will be an integer in range [1, 10^6].\nAnswers within 10^-6 of the true value will be accepted as correct.\n```\n\n## 解题方案\n\n> 思路 1\n\n首先明确一下题意，如果目前最大的一个距离是D的话，只要现在我们能够让最大的距离全都变小就行了，也就是说通过在最大距离的station之间再加一些station即可，\n加了之后现在原来的最大距离就变小了，就可以了。明确一点，我们需要返回的是我们用最多k个station所能构造出的最小的最大距离。\n\n于是我们判断一下需要我们额外加的stations数目是否小于等于k：\n- 若是，且当前最大距离小于10^-6则返回当前最大距离\n- 若不是，则继续追加stations数目，继续让最大距离变小\n\n```python\nclass Solution(object):\n    def minmaxGasDist(self, stations, K):\n        \"\"\"\n        :type stations: List[int]\n        :type K: int\n        :rtype: float\n        \"\"\"\n        def possible(D):\n            return sum(int((stations[i+1] - stations[i]) / D)\n                       for i in xrange(len(stations) - 1)) <= K\n\n        l, r = 0, 10**8\n        while r - l > 1e-6:\n            mid = (l + r) / 2.0\n            if possible(mid):\n                r = mid\n            else:\n                l = mid\n        return l\n```\n"
  },
  {
    "path": "docs/leetcode/python/777._Swap_Adjacent_in_LR_String.md",
    "content": "# 777. Swap Adjacent in LR String 在LR字符串中交换相邻字符\n\n**<font color=red>难度: 中等</font>**\n\n## 刷题内容\n\n> 原题连接\n\n* https://leetcode.com/problems/swap-adjacent-in-lr-string\n* https://leetcode-cn.com/problems/swap-adjacent-in-lr-string\n\n> 内容描述\n\n```\n\n在一个由 'L' , 'R' 和 'X' 三个字符组成的字符串（例如\"RXXLRXRXL\"）中进行移动操作。一次移动操作指用一个\"LX\"替换一个\"XL\"，或者用一个\"XR\"替换一个\"RX\"。现给定起始字符串start和结束字符串end，请编写代码，当且仅当存在一系列移动操作使得start可以转换成end时， 返回True。\n\n示例 :\n\n输入: start = \"RXXLRXRXL\", end = \"XRLXXRRLX\"\n输出: True\n解释:\n我们可以通过以下几步将start转换成end:\nRXXLRXRXL ->\nXRXLRXRXL ->\nXRLXRXRXL ->\nXRLXXRRXL ->\nXRLXXRRLX\n注意:\n\n1 <= len(start) = len(end) <= 10000。\nstart和end中的字符串仅限于'L', 'R'和'X'。\n```\n\n## 解题方案\n\n> 思路 1\n\n这道题就是一道坑比题，为什么我这么说，题目都说了是 **Adjacent**，然后XL换成LX的情况居然包括\"XXXXXLXXXX\"到\"LXXXXXXXXX\"，\n你说这是 **Adjacent**吗，XL不相邻也可以换，我去nm的，不好意思爆粗口了。\n\n先说一下XL必须相邻的解法吧，不能白费我功夫啊。\n\n动态规划：dp[i]代表以```index i```结尾的字串是否能够被替换成功，首先dp[0]必须等于False吧，所以我们初始化全部设为False，然后把dp[1]也先判断好\n\n那么很显然，对于dp[i]有下面的情况：\n1. dp[i-1] == True\n- 如果start[i] == end[i]，那么dp[i] = True\n- 如果start[i] != end[i]，那么这里我们不做操作，因为初始化就是False\n\n2. dp[i-1] == False\n- 如果start[i] == end[i]，那么dp[i] = False\n- 如果start[i] != end[i]，那么只有当最后两个字符可以转换且dp[i-2] == True的情况下dp[i]才为True\n\n最后返回dp[-1]\n\n\n```\nclass Solution(object):\n    def canTransform(self, start, end):\n        \"\"\"\n        :type start: str\n        :type end: str\n        :rtype: bool\n        \"\"\"\n        if not start or len(start) == 0:\n            return True\n        if len(start) == 1:\n            return False\n        \n        dp = [False for i in range(len(start))]\n        if start[:2] == 'XL' and end[:2] == 'LX' or start[:2] == 'RX' and end[:2] == 'XR' or start[:2] == end[:2]:\n            dp[1] = True\n        for i in range(2, len(dp)):\n            if dp[i-1]:\n                if start[i] == end[i]:\n                    dp[i] = True\n            else:\n                if start[i] == 'L' and start[i-1] == 'X' and end[i] == 'X' and end[i-1] == 'L' and dp[i-2]:\n                    dp[i] = True\n                if start[i] == 'X' and start[i-1] == 'R' and end[i] == 'R' and end[i-1] == 'X' and dp[i-2]:\n                    dp[i] = True\n        return dp[-1]\n```\n接下来说一下XL可以不相邻的情况吧。\n用```rx``` 和 ```xl```来存储出现了可以替换的可能性，即当start出现X或者R的时候,如果后面又开始出现结尾情况了，\n我们就要pop一下对应的```rx``` 和 ```xl```中的一个\n\n```python\nclass Solution(object):\n    def canTransform(self, start, end):\n        \"\"\"\n        :type start: str\n        :type end: str\n        :rtype: bool\n        \"\"\"\n        if not start or len(start) == 0 or start == end:\n            return True\n        if len(start) == 1:\n            return False\n        \n        xl, rx = [], []\n        for i in range(len(start)):\n            if start[i] == end[i]:\n                continue\n            elif start[i] == 'X' and end[i] == 'L':\n                xl.append('L')\n            elif start[i] == 'L' and end[i] == 'X':\n                if not xl:\n                    return False\n                xl.pop()\n            elif start[i] == 'R' and end[i] == 'X':\n                rx.append('R')\n            elif start[i] == 'X' and end[i] == 'R':\n                if not rx:\n                    return False\n                rx.pop()\n            else:\n                return False\n        return not rx and not xl\n```\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/leetcode/python/844._Backspace_String_Compare.md",
    "content": "### 844. Backspace String Compare\n\n题目:\n<https://leetcode.com/problems/backspace-string-compare/>\n\n\n难度:\n\nEasy\n\n\n思路\n\n就看一下两个字符串变化完之后是不是相等就行了，\n- 时间复杂度：O(n)\n- 空间复杂度：O(n)\n\n\n```python\nclass Solution(object):\n    def backspaceCompare(self, S, T):\n        \"\"\"\n        :type S: str\n        :type T: str\n        :rtype: bool\n        \"\"\"\n        def afterChange(s): \n            res = ''\n            for i in s:\n                if i == '#':\n                    res = '' if len(res) == 0 else res[:-1]\n                else:\n                    res += i\n            return res\n        return afterChange(S) == afterChange(T)\n```\n\n\n"
  },
  {
    "path": "docs/leetcode/python/README.md",
    "content": "# Leetcode Python 题解\n\n> 看左侧栏，开始你的表演！\n"
  },
  {
    "path": "docs/leetcode/python/SUMMARY.md",
    "content": "+ [Leetcode Python 题解](README.md)\n+ [001 two sum](001._two_sum.md)\n+ [002 add two numbers](002._add_two_numbers.md)\n+ [003 longest substring without repeating characters](003._longest_substring_without_repeating_characters.md)\n+ [004 median of two sorted arrays](004._median_of_two_sorted_arrays.md)\n+ [005 longest palindromic substring](005._longest_palindromic_substring.md)\n+ [006 ZigZag Conversion](006._ZigZag_Conversion.md)\n+ [007 Reverse Integer](007._Reverse_Integer.md)\n+ [008 string to integer (atoi)](008._string_to_integer_(atoi).md)\n+ [009 Palindrome Number](009._Palindrome_Number.md)\n+ [010 regular expression matching](010._regular_expression_matching.md)\n+ [011 container with most water](011._container_with_most_water.md)\n+ [012 Integer to Roman](012._Integer_to_Roman.md)\n+ [013 Roman to Integer](013._Roman_to_Integer.md)\n+ [014 longest common prefix](014._longest_common_prefix.md)\n+ [015 3sum](015._3sum.md)\n+ [016 3sum closest](016._3sum_closest.md)\n+ [017 letter combinations of a phone number](017._letter_combinations_of_a_phone_number.md)\n+ [018 4sum](018._4sum.md)\n+ [019 remove nth node from end of list](019._remove_nth_node_from_end_of_list.md)\n+ [020 valid parentheses](020._valid_parentheses.md)\n+ [021 merge two sorted lists](021._merge_two_sorted_lists.md)\n+ [022 generate parentheses](022._generate_parentheses.md)\n+ [023 merge k sorted lists](023._merge_k_sorted_lists.md)\n+ [024 swap nodes in pairs](024._swap_nodes_in_pairs.md)\n+ [026 Remove Duplicates from Sorted Array](026._Remove_Duplicates_from_Sorted_Array.md)\n+ [027 Remove Element](027._Remove_Element.md)\n+ [028 implement strstr()](028._implement_strstr.md)\n+ [030 Substring with Concatenation of All Words](030._Substring_with_Concatenation_of_All_Words.md)\n+ [031 next permutation](031._next_permutation.md)\n+ [032 longest valid parentheses](032._longest_valid_parentheses.md)\n+ [033 search in rotated sorted array](033._search_in_rotated_sorted_array.md)\n+ [034 Search for a Range](034._Search_for_a_Range.md)\n+ [035 search insert position](035._search_insert_position.md)\n+ [038 Count and Say](038._Count_and_Say.md)\n+ [039 combination sum](039._combination_sum.md)\n+ [040 combination sum ii](040._combination_sum_ii.md)\n+ [041 First Missing Positive](041._First_Missing_Positive.md)\n+ [042 trapping rain water](042._trapping_rain_water.md)\n+ [043 multiply strings](043._multiply_strings.md)\n+ [044 wildcard matching](044._wildcard_matching.md)\n+ [045 Jump Game II](045._Jump_Game_II.md)\n+ [046 permutations](046._permutations.md)\n+ [047 permutations ii](047._permutations_ii.md)\n+ [048 rotate image](048._rotate_image.md)\n+ [049 group anagrams python](049._group_anagrams_python.md)\n+ [050 pow(x, n)](050._pow(x,_n).md)\n+ [051 n-queens](051._n-queens.md)\n+ [052 n-queens ii](052._n-queens_ii.md)\n+ [053 maximum subarray](053._maximum_subarray.md)\n+ [054 spiral matrix](054._spiral_matrix.md)\n+ [055 jump game](055._jump_game.md)\n+ [056 Merge Intervals](056._Merge_Intervals.md)\n+ [058 length of last word](058._length_of_last_word.md)\n+ [059 spiral matrix ii](059._spiral_matrix_ii.md)\n+ [060 permutation sequence](060._permutation_sequence.md)\n+ [061 rotate list](061._rotate_list.md)\n+ [062 unique paths](062._unique_paths.md)\n+ [064 minimum path sum](064._minimum_path_sum.md)\n+ [065 unique paths ii](065.unique_paths_ii.md)\n+ [066 plus one](066._plus_one.md)\n+ [067 add binary](067._add_binary.md)\n+ [069 sqrt(x)](069._sqrt(x).md)\n+ [070 Climbing Stairs](070._Climbing_Stairs.md)\n+ [072 edit distance](072._edit_distance.md)\n+ [073 Set Matrix Zeroes](073._Set_Matrix_Zeroes.md)\n+ [074 search a 2d matrix](074._search_a_2d_matrix.md)\n+ [075 sort colors](075._sort_colors.md)\n+ [076 Minimum Window Substring](076._Minimum_Window_Substring.md)\n+ [077 combinations](077._combinations.md)\n+ [078 Subsets](078._Subsets.md)\n+ [079 word search](079._word_search.md)\n+ [082 remove duplicates from sorted list ii](082._remove_duplicates_from_sorted_list_ii.md)\n+ [083 remove duplicates from sorted list](083._remove_duplicates_from_sorted_list.md)\n+ [086 partition list](086._partition_list.md)\n+ [088 merge sorted array](088._merge_sorted_array.md)\n+ [089 gray code](089._gray_code.md)\n+ [090 subsets ii](090._subsets_ii.md)\n+ [091 decode ways](091._decode_ways.md)\n+ [092 reverse linked list ii](092._reverse_linked_list_ii.md)\n+ [093 restore ip addresses](093._restore_ip_addresses.md)\n+ [094 binary tree inorder traversal](094._binary_tree_inorder_traversal.md)\n+ [096 unique binary search trees](096._unique_binary_search_trees.md)\n+ [098 validate binary search tree](098._validate_binary_search_tree.md)\n+ [100 same tree](100._same_tree.md)\n+ [101 symmetric tree](101._symmetric_tree.md)\n+ [102 binary tree level order traversal](102._binary_tree_level_order_traversal.md)\n+ [103 binary tree zigzag level order traversal](103._binary_tree_zigzag_level_order_traversal.md)\n+ [104 maximum depth of binary tree](104._maximum_depth_of_binary_tree.md)\n+ [105 construct binary tree from preorder and inorder traversal](105._construct_binary_tree_from_preorder_and_inorder_traversal.md)\n+ [106 construct binary tree from inorder and postorder traversal](106._construct_binary_tree_from_inorder_and_postorder_traversal.md)\n+ [107 binary tree level order traversal ii](107._binary_tree_level_order_traversal_ii.md)\n+ [108 convert sorted array to binary search tree](108._convert_sorted_array_to_binary_search_tree.md)\n+ [109 convert sorted list to binary search tree](109._convert_sorted_list_to_binary_search_tree.md)\n+ [110 balanced binary tree](110._balanced_binary_tree.md)\n+ [111 minimum depth of binary tree](111._minimum_depth_of_binary_tree.md)\n+ [112 path sum](112._path_sum.md)\n+ [113 path sum ii](113._path_sum_ii.md)\n+ [114 flatten binary tree to linked list](114._flatten_binary_tree_to_linked_list.md)\n+ [116 populating next right pointers in each node](116._populating_next_right_pointers_in_each_node.md)\n+ [117 Populating Next Right Pointers in Each Node II](117._Populating_Next_Right_Pointers_in_Each_Node_II.md)\n+ [118 pascal's triangle](118._pascal's_triangle.md)\n+ [119 Pascal's Triangle II](119._Pascal's_Triangle_II.md)\n+ [120 Triangle](120._Triangle.md)\n+ [121 Best Time to Buy and Sell Stock](121._Best_Time_to_Buy_and_Sell_Stock.md)\n+ [124 Binary Tree Maximum Path Sum](124._Binary_Tree_Maximum_Path_Sum.md)\n+ [125 valid palindrome](125._valid_palindrome.md)\n+ [126 Word Ladder II](126._Word_Ladder_II.md)\n+ [127 word ladder](127._word_ladder.md)\n+ [128 Longest Consecutive Sequence](128._Longest_Consecutive_Sequence.md)\n+ [129 sum root to leaf numbers](129._sum_root_to_leaf_numbers.md)\n+ [130 surrounded regions](130._surrounded_regions.md)\n+ [131 palindrome partitioning](131._palindrome_partitioning.md)\n+ [133 clone graph](133._clone_graph.md)\n+ [136 single number](136._single_number.md)\n+ [139 word break](139._word_break.md)\n+ [140 word break ii](140._word_break_ii.md)\n+ [141 linked list cycle](141._linked_list_cycle.md)\n+ [142_Linked_List_Cycle_II md](142_Linked_List_Cycle_II.md)\n+ [143 reorder list](143._reorder_list.md)\n+ [144 binary tree preorder traversal](144._binary_tree_preorder_traversal.md)\n+ [145 binary tree postorder traversal](145._binary_tree_postorder_traversal.md)\n+ [147 insertion sort list](147._insertion_sort_list.md)\n+ [148 sort list](148._sort_list.md)\n+ [150 evaluate reverse polish notation](150._evaluate_reverse_polish_notation.md)\n+ [151 reverse words in a string](151._reverse_words_in_a_string.md)\n+ [152 maximum product subarray](152._maximum_product_subarray.md)\n+ [153 find minimum in rotated sorted array](153._find_minimum_in_rotated_sorted_array.md)\n+ [155 min stack](155._min_stack.md)\n+ [157 Read N Characters Given Read4](157._Read_N_Characters_Given_Read4.md)\n+ [158 Read N Characters Given Read4 II - Call multiple times](158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md)\n+ [159 Longest Substring with At Most Two Distinct Characters](159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md)\n+ [160 intersection of two linked lists](160._intersection_of_two_linked_lists.md)\n+ [162 find peak element](162._find_peak_element.md)\n+ [165 compare version numbers](165._compare_version_numbers.md)\n+ [166 Fraction to Recurring Decimal](166._Fraction_to_Recurring_Decimal.md)\n+ [167 two sum ii - input array is sorted](167._two_sum_ii_-_input_array_is_sorted.md)\n+ [168 excel sheet column title](168._excel_sheet_column_title.md)\n+ [169 majority element](169._majority_element.md)\n+ [171 excel sheet column number](171._excel_sheet_column_number.md)\n+ [173 binary search tree iterator](173._binary_search_tree_iterator.md)\n+ [179 Largest Number](179._Largest_Number.md)\n+ [182 duplicate emails](182._duplicate_emails.md)\n+ [189 rotate array](189._rotate_array.md)\n+ [191 number of 1 bits](191._number_of_1_bits.md)\n+ [198 house robber](198._house_robber.md)\n+ [199 binary tree right side view](199._binary_tree_right_side_view.md)\n+ [200 number of islands](200._number_of_islands.md)\n+ [203 remove linked list elements](203._remove_linked_list_elements.md)\n+ [204 count primes](204._count_primes.md)\n+ [205 isomorphic strings](205._isomorphic_strings.md)\n+ [206 reverse linked list](206._reverse_linked_list.md)\n+ [207 course schedule](207._course_schedule.md)\n+ [208 implement trie (prefix tree)](208._implement_trie_(prefix_tree).md)\n+ [210 course schedule ii](210._course_schedule_ii.md)\n+ [211 Add and Search Word - Data structure design](211._Add_and_Search_Word_-_Data_structure_design.md)\n+ [213 house robber ii](213._house_robber_ii.md)\n+ [216 combination sum iii](216._combination_sum_iii.md)\n+ [217 contains duplicate](217._contains_duplicate.md)\n+ [218 The Skyline Problem](218._The_Skyline_Problem.md)\n+ [219 contains duplicate ii](219._contains_duplicate_ii.md)\n+ [221 maximal square](221._maximal_square.md)\n+ [222 count complete tree nodes](222._count_complete_tree_nodes.md)\n+ [223 rectangle area](223._rectangle_area.md)\n+ [224 Basic Calculator](224._Basic_Calculator.md)\n+ [225 implement stack using queues](225._implement_stack_using_queues.md)\n+ [226 invert binary tree](226._invert_binary_tree.md)\n+ [227 basic calculator ii](227._basic_calculator_ii.md)\n+ [228 summary ranges](228._summary_ranges.md)\n+ [229 majority element ii](229._majority_element_ii.md)\n+ [230 kth smallest element in a bst](230._kth_smallest_element_in_a_bst.md)\n+ [231 Power of Two](231._Power_of_Two.md)\n+ [232 implement queue using stacks](232._implement_queue_using_stacks.md)\n+ [234 palindrome linked list](234._palindrome_linked_list.md)\n+ [235 lowest common ancestor of a binary search tree](235._lowest_common_ancestor_of_a_binary_search_tree.md)\n+ [236 lowest common ancestor of a binary tree](236._lowest_common_ancestor_of_a_binary_tree.md)\n+ [237 delete node in a linked list](237._delete_node_in_a_linked_list.md)\n+ [238 product of array except self](238._product_of_array_except_self.md)\n+ [240 search a 2d matrix ii](240._search_a_2d_matrix_ii.md)\n+ [242 valid anagram](242._valid_anagram.md)\n+ [249 Group Shifted Strings](249._Group_Shifted_Strings.md)\n+ [252 Meeting Rooms](252._Meeting_Rooms.md)\n+ [255 Verify Preorder Sequence in Binary Search Tree](255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md)\n+ [256 Paint House](256._Paint_House.md)\n+ [257 binary tree paths](257._binary_tree_paths.md)\n+ [258_ Add_Digits md](258._Add_Digits.md)\n+ [261 Graph Valid Tree](261._Graph_Valid_Tree.md)\n+ [263 ugly number](263._ugly_number.md)\n+ [264 ugly number ii](264._ugly_number_ii.md)\n+ [265 Paint House II](265._Paint_House_II.md)\n+ [266 Palindrome Permutation](266._Palindrome_Permutation.md)\n+ [267 Palindrome Permutation II](267._Palindrome_Permutation_II.md)\n+ [268 missing number](268._missing_number.md)\n+ [270 Closest Binary Search Tree Value](270._Closest_Binary_Search_Tree_Value.md)\n+ [276 Paint Fence](276._Paint_Fence.md)\n+ [277 Find the Celebrity](277._Find_the_Celebrity.md)\n+ [278 First Bad Version](278._First_Bad_Version.md)\n+ [279 perfect squares](279._perfect_squares.md)\n+ [280 Wiggle Sort](280._Wiggle_Sort.md)\n+ [283 move zeroes](283._move_zeroes.md)\n+ [285 inorder successor in bst](285._inorder_successor_in_bst.md)\n+ [286 Walls and Gates](286._Walls_and_Gates.md)\n+ [287 Find the Duplicate Number](287._Find_the_Duplicate_Number.md)\n+ [289 game of life](289._game_of_life.md)\n+ [290 word pattern](290._word_pattern.md)\n+ [292 nim game](292._nim_game.md)\n+ [293 Flip Game](293._Flip_Game.md)\n+ [296 Best Meeting Point](296._Best_Meeting_Point.md)\n+ [298 Binary Tree Longest Consecutive Sequence](298._Binary_Tree_Longest_Consecutive_Sequence.md)\n+ [299 bulls and cows](299._bulls_and_cows.md)\n+ [300 longest increasing subsequence](300._longest_increasing_subsequence.md)\n+ [303 range sum query - immutable](303._range_sum_query_-_immutable.md)\n+ [316 Remove Duplicate Letters](316._Remove_Duplicate_Letters.md)\n+ [319 Bulb Switcher](319._Bulb_Switcher.md)\n+ [322 Coin Change](322._Coin_Change.md)\n+ [323 number of connected components in an undirected graph](323._number_of_connected_components_in_an_undirected_graph.md)\n+ [324 Wiggle Sort II](324._Wiggle_Sort_II.md)\n+ [326 power of three](326._power_of_three.md)\n+ [328 odd even linked list](328._odd_even_linked_list.md)\n+ [334 increasing triplet subsequence](334._increasing_triplet_subsequence.md)\n+ [337 house robber iii](337._house_robber_iii.md)\n+ [338 Counting Bits](338._Counting_Bits.md)\n+ [339 Nested List Weight Sum](339._Nested_List_Weight_Sum.md)\n+ [341 Flatten Nested List Iterator](341._Flatten_Nested_List_Iterator.md)\n+ [342 Power of Four](342._Power_of_Four.md)\n+ [344 reverse string](344._reverse_string.md)\n+ [345 Reverse Vowels of a String](345._Reverse_Vowels_of_a_String.md)\n+ [349 intersection of two arrays](349._intersection_of_two_arrays.md)\n+ [350 intersection of two arrays ii](350._intersection_of_two_arrays_ii.md)\n+ [353 Design Snake Game](353._Design_Snake_Game.md)\n+ [361 Bomb Enemy](361._Bomb_Enemy.md)\n+ [364 Nested List Weight Sum II](364._Nested_List_Weight_Sum_II.md)\n+ [366 Find Leaves of Binary Tree](366._Find_Leaves_of_Binary_Tree.md)\n+ [367 valid perfect square](367._valid_perfect_square.md)\n+ [369 Plus One Linked List](369._Plus_One_Linked_List.md)\n+ [371 sum of two integers](371._sum_of_two_integers.md)\n+ [374 Guess Number Higher or Lower](374._Guess_Number_Higher_or_Lower.md)\n+ [377 combination sum iv](377._combination_sum_iv.md)\n+ [378 kth smallest element in a sorted matrix](378._kth_smallest_element_in_a_sorted_matrix.md)\n+ [380 Insert Delete GetRandom O(1)](380._Insert_Delete_GetRandom_O(1).md)\n+ [381 Insert Delete GetRandom O(1) - Duplicates allowed](381._Insert_Delete_GetRandom_O(1)_-_Duplicates_allowed.md)\n+ [382 linked list random node](382._linked_list_random_node.md)\n+ [383 ransom note](383._ransom_note.md)\n+ [384 Shuffle an Array](384._Shuffle_an_Array.md)\n+ [386 Lexicographical Numbers](386._Lexicographical_Numbers.md)\n+ [387 first unique character in a string](387._first_unique_character_in_a_string.md)\n+ [388 Longest Absolute File Path](388._Longest_Absolute_File_Path.md)\n+ [389 find the difference](389._find_the_difference.md)\n+ [392 is subsequence](392._is_subsequence.md)\n+ [394 decode string](394._decode_string.md)\n+ [400 Nth Digit](400._Nth_Digit.md)\n+ [401 binary watch](401._binary_watch.md)\n+ [404 sum of left leaves](404._sum_of_left_leaves.md)\n+ [405 Convert a Number to Hexadecimal](405._Convert_a_Number_to_Hexadecimal.md)\n+ [406 Queue Reconstruction by Height](406._Queue_Reconstruction_by_Height.md)\n+ [412 fizz buzz](412._fizz_buzz.md)\n+ [413 Arithmetic Slices](413._Arithmetic_Slices.md)\n+ [414 third maximum number](414._third_maximum_number.md)\n+ [415 add strings](415._add_strings.md)\n+ [416 Partition Equal Subset Sum](416._Partition_Equal_Subset_Sum.md)\n+ [421 Maximum XOR of Two Numbers in an Array](421._Maximum_XOR_of_Two_Numbers_in_an_Array.md)\n+ [422 Valid Word Square](422._Valid_Word_Square.md)\n+ [434 number of segments in a string](434._number_of_segments_in_a_string.md)\n+ [435 Non-overlapping Intervals](435._Non-overlapping_Intervals.md)\n+ [437 path sum iii](437._path_sum_iii.md)\n+ [438 Find All Anagrams in a String](438._Find_All_Anagrams_in_a_String.md)\n+ [439 Ternary Expression Parser](439._Ternary_Expression_Parser.md)\n+ [441 arranging coins](441._arranging_coins.md)\n+ [448 Find All Numbers Disappeared in an Array](448._Find_All_Numbers_Disappeared_in_an_Array.md)\n+ [450 Delete Node in a BST](450._Delete_Node_in_a_BST.md)\n+ [453 Minimum Moves to Equal Array Elements](453._Minimum_Moves_to_Equal_Array_Elements.md)\n+ [459 Repeated Substring Pattern](459._Repeated_Substring_Pattern.md)\n+ [461 Hamming Distance](461._Hamming_Distance.md)\n+ [463 Island Perimeter](463._Island_Perimeter.md)\n+ [467 Unique Substrings in Wraparound String](467._Unique_Substrings_in_Wraparound_String.md)\n+ [469 Convex Polygon](469._Convex_Polygon.md)\n+ [476 Number Complement](476._Number_Complement.md)\n+ [477 Total Hamming Distance](477._Total_Hamming_Distance.md)\n+ [485 Max Consecutive Ones](485._Max_Consecutive_Ones.md)\n+ [494 Target Sum](494._Target_Sum.md)\n+ [536 Construct Binary Tree from String](536._Construct_Binary_Tree_from_String.md)\n+ [587 Erect the Fence](587._Erect_the_Fence.md)\n+ [599 Minimum Index Sum of Two Lists](599._Minimum_Index_Sum_of_Two_Lists.md)\n+ [606 Construct String from Binary Tree](606._Construct_String_from_Binary_Tree.md)\n+ [611 Valid Triangle Number](611._Valid_Triangle_Number.md)\n+ [646 Maximum Length of Pair Chain](646._Maximum_Length_of_Pair_Chain.md)\n+ [647 Palindromic Substrings](647._Palindromic_Substrings.md)\n+ [657 Judge Route Circle](657._Judge_Route_Circle.md)\n+ [665 Non-decreasing Array](665._Non-decreasing_Array.md)\n+ [672 Bulb Switcher II](672._Bulb_Switcher_II.md)\n+ [681 Next Closest Time](681._Next_Closest_Time.md)\n+ [682 Baseball Game](682._Baseball_Game.md)\n+ [685 Redundant Connection II](685._Redundant_Connection_II.md)\n+ [687 Longest Univalue Path](687._Longest_Univalue_Path.md)\n+ [693 Binary Number with Alternating Bits](693._Binary_Number_with_Alternating_Bits.md)\n+ [701 Insert into a Binary Search Tree](701._Insert_into_a_Binary_Search_Tree.md)\n+ [707 Design Linked List](707._Design_Linked_List.md)\n+ [740 delete and earn](740._delete_and_earn.md)\n+ [760 Find Anagram Mappings](760._Find_Anagram_Mappings.md)\n+ [774 Minimize Max Distance to Gas Station](774._Minimize_Max_Distance_to_Gas_Station.md)\n+ [777 Swap Adjacent in LR String](777._Swap_Adjacent_in_LR_String.md)\n+ [844 Backspace String Compare](844._Backspace_String_Compare.md)\n"
  },
  {
    "path": "docs/think-dast-zh/0.md",
    "content": "# 前言\n\n> 原文：[Preface](http://greenteapress.com/thinkdast/html/thinkdast001.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n## 本书背后的哲学\n\n数据结构和算法是过去 50 年来最重要的发明之一，它们是软件工程师需要了解的基础工具。但是在我看来，这些话题的大部分书籍都过于理论，过于庞大，也是“自底向上”的：\n\n过于理论\n\n算法的数学分析基于许多简化假设，它们限制了实践中的可用性。这个话题的许多描述都掩盖了简化，并专注于数学。在这本书中，我介绍了这个话题的最实际的子集，并省略或不强调其余的内容。\n\n过于庞大\n\n这些话题的大多数书籍至少有 500 页，有些超过 1000 页。通过关注我认为对软件工程师最有用的话题，我把这本书限制在 200 页以下。\n\n过于“自底向上”\n\n许多数据结构的书籍着重于数据结构如何工作（实现），而不是使用它们（接口）。在这本书中，我从接口开始，“自顶向下”。读者在学习如何使用 Java 集合框架中的结构之后，再了解它们的工作原理。\n\n最后，有些书将这个材料展示在上下文之外，缺少动机：这只是另一个数据结构！我试图使之生动起来，通过围绕一个应用 - 网页搜索 - 来组织这些话题，它广泛使用数据结构，并且是一个有趣和重要的话题。\n\n这个应用激发了一些话题，通常不会在介绍性数据结构的课中涵盖，包括 Redis 的持久化数据结构。\n\n\n我已经做出了一些艰难的决定，来进行取舍，但我也做了一些妥协。我包括了大多数读者永远不会使用的一些话题，但是可能在技术面试中，你需要知道这些话题。对于这些话题，我提出了传统的观点和我怀疑的理由。\n\n本书还介绍了软件工程实践的基本方面，包括版本控制和单元测试。大多数章节都包括一个练习，允许读者应用他们学到的内容。每个练习都提供自动化测试，来检查解决方案。对于大多数练习，我在下一章的开头展示我的解决方案。\n\n### 0.1 预备条件\n\n本书面向计算机科学及相关领域的大学生，专业软件工程师，软件工程培训人员和技术面试准备人员。\n\n在你开始读这本书之前，你应该很熟悉 Java，尤其应该知道如何定义一个扩展现有类的新类，或实现一个`interface`。如果你不熟悉 Java 了，这里有两本书可以用于起步：\n\n+   Downey 和 Mayfield，《Think Java》（O'Reilly Media，2016），它面向以前从未编程过的人。\n+   Sierra 和 Bates，《Head First Java》（O'Reilly Media，2005），它适用于已经知道另一种编程语言的人。\n\n如果你不熟悉 Java 中的接口，你可能需要在 <http://thinkdast.com/interface> 上完成一个名为“什么是接口”的教程 。\n\n一个词汇注解：“接口”这个词可能会令人困惑。在应用编程接口（API）的上下文中，它指代一组提供某些功能的类和方法。\n\n在 Java 的上下文中，它还指代一个与类相似的语言特性，它规定了一组方法。为了避免混淆，我将使用正常字体中的“接口”来表示接口的一般思想，代码字体的`interface`用于 Java 语言特性。\n\n你还应该熟悉类型参数和泛型类型。例如，你应该知道如何使用类型参数创建对象，如`ArrayList<Integer>`。如果不是，你可以在 <http://thinkdast.com/types> 上了解类型参数。\n\n你应该熟悉 Java 集合框架（JCF​​），你可以阅读 <http://thinkdast.com/collections>。特别是，你应该知道`List interface`，以及`ArrayList`和`LinkedList`类。\n\n理想情况下，你应该熟悉 Apache Ant，它是 Java 的自动化构建工具。你可以在 <http://thinkdast.com/anttut> 上阅读 Ant 的更多信息。\n\n你应该熟悉 JUnit，它是 Java 的单元测试框架。你可以在 <http://thinkdast.com/junit> 上阅读更多信息。\n\n## 处理代码\n\n本书的代码位于 <http://thinkdast.com/repo> 上的 Git 仓库中 。\n\nGit 是一个“版本控制系统”，允许你跟踪构成项目的文件。Git 控制下的文件集合称为“仓库”。\n\nGitHub 是一个托管服务，为 Git 仓库提供存储和方便的 Web 界面。它提供了几种使用代码的方法：\n\n+   你可以通过按下`Fork`（派生）按钮，在 GitHub 上创建仓库的副本。如果你还没有 GitHub 帐户，则需要创建一个。派生之后，你可以在 GitHub 上拥有你自己的仓库，你可以使用它们来跟踪你编写的代码。然后，你可以“克隆”仓库，它将文件的副本下载到你的计算机。\n+   或者，你可以克隆仓库而不进行派生。如果你选择此选项，则不需要 GitHub 帐户，但你无法将更改保存在 GitHub 上。\n+   如果你不想使用 Git，你可以使用 GitHub 页面上的`Download`（下载）按钮或此链接<http://thinkdast.com/zip>，以 ZIP 压缩包格式下载代码。\n\n克隆仓库或解压 ZIP 文件后，你应该有一个名为`ThinkDataStructures`的目录，其中有一个名为`code`的子目录。\n\n本书中的示例是使用 Java SE 7 开发和测试的。如果你使用的是较旧的版本，一些示例将无法正常工作。如果你使用的是更新版本，那么它们都应该能用。\n\n## 贡献者\n\n这本书是我为纽约市 Flatiron School 写的课程的一个改编版，它提供了编程和网页开发相关的各种在线课程。他们提供基于这个材料的课程，提供在线开发环境，来自教师和其他学生的帮助，以及结业证书。你可以在 <http://flatironschool.com>上找到更多信息 。\n\n+   在 Flatiron School，Joe Burgess，Ann John 和 Charles Pletcher 通过实现和测试，提供了来自初始规范的指导，建议和更正。谢谢你们！\n+   我非常感谢我的技术审校员 Barry Whitman, Patrick White 和 Chris Mayfield，他提出了许多有用的建议，并捕获了许多错误。当然，任何剩余的错误都是我的错，而不是他们的错！\n+   感谢 Olin College 的数据结构和算法课程中的教师和学生，他们读了这本书并提供了有用的反馈。\n\n如果你对文本有任何意见或建议，请发送至：<feedback@greenteapress.com>。\n"
  },
  {
    "path": "docs/think-dast-zh/1.md",
    "content": "# 第一章 接口\n\n> 原文：[Chapter 1  Interfaces](http://greenteapress.com/thinkdast/html/thinkdast002.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n本书展示了三个话题：\n\n+   数据结构：从 Java 集合框架（JCF）中的结构开始，你将学习如何使用列表和映射等数据结构，你将看到它们的工作原理。\n+   算法分析：我提供了技术，来分析代码以及预测运行速度和需要多少空间（内存）。\n+   信息检索：为了激发前两个主题，并使练习更加有趣，我们将使用数据结构和算法构建简单的 Web 搜索引擎。\n\n以下是话题顺序的大纲：\n\n+   我们将从`List`接口开始，你将编写实现这个接口的两种不同的方式。然后我们将你的实现与 Java `ArrayList`和`LinkedList`类进行比较。\n+   接下来，我将介绍树形数据结构，你将处理第一个应用程序：一个程序，从维基百科页面读取页面，解析内容，并遍历生成的树来查找链接和其他特性。我们将使用这些工具来测试“到达哲学”的猜想（你可以通过阅读 <http://thinkdast.com/getphil> 来了解）。\n+   我们将了解 Java 的`Map`接口和`HashMap`实现。然后，你将使用哈希表和二叉搜索树来编写实现此接口的类。\n+   最后，你将使用这些（以及其他一些我之前介绍的）类来实现一个 Web 搜索引擎，其中包括：一个查找和读取页面的爬虫程序，一个存储网页内容的索引器，以便有效地搜索，以及一个从用户那里接受查询并返回相关结果的检索器。\n\n让我们开始吧。\n\n## 1.1 为什么有两种`List`？\n\n当人们开始使用 Java 集合框架时，有时候会混淆`ArrayList`和`LinkedList`。为什么 Java 提供两个`List interface`的实现呢？你应该如何选择使用哪一个？我们将在接下来的几章回答这些问题。\n\n我将以回顾`interface`和实现它们的类开始，我将介绍“面向接口编程”的概念。\n\n在最初的几个练习中，你将实现类似于`ArrayList`和`LinkedList`的类，这样你就会知道他们如何工作，我们会看到，他们每个类都有优点和缺点。对于`ArrayList`，一些操作更快或占用更少的空间；但对于`LinkedList`其他操作更快或空间更少。哪一个更适合于特定的应用程序，取决于它最常执行的操作。\n\n## 1.2 Java 中的接口\n\nJava `interface`规定了一组方法；任何实现这个`interface`的类都必须提供这些方法。例如，这里是`Comparable`的源代码，它是定义在`java.lang`包中的`interface`：\n\n```java\npublic interface Comparable<T> {\n    public int compareTo(T o);\n}\n```\n\n这个`interface`的定义使用类型参数`T`，这使得`Comparable`是个泛型类型。为了实现这个`interface`，一个类必须：\n\n+   规定类型`T`，以及，\n+   提供一个名为`compareTo`的方法，接受一个对象作为参数，并返回`int`。\n\n例如，以下是`java.lang.Integer`的源代码：\n\n```java\npublic final class Integer extends Number implements Comparable<Integer> {\n\n    public int compareTo(Integer anotherInteger) {\n        int thisVal = this.value;\n        int anotherVal = anotherInteger.value;\n        return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));\n    }\n\n    // other methods omitted\n}\n```\n\n> 译者注：根据[`Comparable<T>`的文档](http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html#compareTo%28T%29)，不必要这么复杂，直接返回`this.value - that.value`就足够了。\n\n这个类扩展了`Number`，所以它继承了`Number`的方法和实例变量；它实现`Comparable<Integer>`，所以它提供了一个名为`compareTo`的方法，接受`Integer`并返回一个`int`。\n\n当一个类声明它实现一个`interface`，编译器会检查，它提供了所有`interface`定义的方法。\n\n除此之外，这个`compareTo`的实现使用“三元运算符”，有时写作`?:`。如果你不熟悉，可以阅读 <http://thinkdast.com/ternary>。\n\n## 1.3 `List`接口\n\nJava集合框架（JCF）定义了一个`interface`，称为 `List`，并提供了两个实现方式，`ArrayList`和`LinkedList`。\n\n这个`interface`定义了`List`是什么意思；实现它的任何类`interface`必须提供一组特定的方法，包括`add`，`get`， `remove`，以及其它大约 20 个。\n\n`ArrayList`并`LinkedList`提供这些方法，因此可以互换使用。用于`List`也可用于`ArrayList`，`LinkedList`，或实现`List`的其它任何对象。\n\n这是一个人为的示例，展示了这一点：\n\n```java\npublic class ListClientExample {\n    private List list;\n    \n    public ListClientExample() {\n        list = new LinkedList();\n    }\n\n    private List getList() {\n        return list;        \n    }\n\n    public static void main(String[] args) {\n        ListClientExample lce = new ListClientExample();\n        List list = lce.getList();\n        System.out.println(list);\n    }\n}\n```\n\n`ListClientExample`没有任何有用的东西，但它封装了`List`，并具有一个类的基本要素。也就是说，它包含一个`List`实例变量。我会使用这个类来表达这个要点，然后你将在第一个练习中使用它。\n\n通过实例化（也就是创建）新的`LinkedList`，这个`ListClientExample`构造函数初始化`list`；读取器方法叫做`getList`，返回内部`List`对象的引用；并且`main`包含几行代码来测试这些方法。\n\n这个例子的要点是，它尽可能地使用`List`，避免指定`LinkedList`，`ArrayList`，除非有必要。例如，实例变量被声明为`List`，并且`getList`返回`List`，但都不指定哪种类型的列表。\n\n如果你改变主意并决定使用`ArrayList`，你只需要改变构造函数; 你不必进行任何其他更改。\n\n这种风格被称为基于接口的编程，或者更随意，“面向接口编程”（见 <http://thinkdast.com/interbaseprog>）。这里我们谈论接口的一般思想，而不是 Java 接口。\n\n当你使用库时，你的代码只依赖于类似“列表”的接口。它不应该依赖于一个特定的实现，像`ArrayList`。这样，如果将来的实现发生变化，使用它的代码仍然可以工作。\n\n另一方面，如果接口改变，依赖于它的代码也必须改变。 这就是为什么库的开发人员避免更改接口，除非绝对有必要。\n\n## 1.4 练习 1\n\n因为这是第一个练习，我们会保持简单。你将从上一节获取代码并交换实现；也就是说，你会将`LinkedList`替换为`ArrayList`。因为面向接口编写程序，你将能够通过更改一行并添加一个`import`语句来交换实现。\n\n以建立你的开发环境来开始。对于所有的练习，你需要能够编译和运行 Java 代码。我使用 JDK7 来开发示例。如果你使用的是更新的版本，则所有内容都应该仍然可以正常工作。如果你使用的是旧版本，可能会发现某些东西不兼容。\n\n我建议使用交互式开发环境（IDE）来获取语法检查，自动完成和源代码重构。这些功能可帮助你避免错误或快速找到它们。但是，如果你正在准备技术面试，请记住，在面试期间你不会拥有这些工具，因此你也可以在没有他们的情况下练习编写代码。\n\n如果你尚未下载本书的代码，请参阅 0.1 节中的指南。\n\n在名为`code`的目录中，你应该找到这些文件和目录：\n\n+   `build.xml`是一个 Ant 文件，可以更容易地编译和运行代码。\n+   `lib`包含你需要的库（对于这个练习，只是 JUnit）。\n+   `src`包含源代码。\n\n如果你浏览`src/com/allendowney/thinkdast`，你将找到此练习的源代码：\n\n+   `ListClientExample.java`包含上一节的代码。\n+   `ListClientExampleTest.java`包含一个 JUnit 测试`ListClientExample`。\n\n查看`ListClientExample`并确保你了解它的作用。然后编译并运行它。如果你使用 Ant，你可以访问代码目录并运行`ant ListClientExample`。\n\n你可能会得到一个警告。\n\n```\nList is a raw type. References to generic type List<E> \nshould be parameterized.\n```\n\n为了使这个例子保持简单，我没有留意在列表中指定元素的类型。如果此警告让你烦恼，你可以通过将`List`或`LinkedList`替换为`List<Integer>`或`LinkedList<Integer>`来修复。\n\n回顾`ListClientExampleTest`。它运行一个测试，创建一个`ListClientExample`，调用`getList`，然后检查结果是否是一个`ArrayList`。最初，这个测试会失败，因为结果是一个`LinkedList`，而不是一个`ArrayList`。运行这个测试并确认它失败。\n\n注意：这个测试对于这个练习是有意义的，但它不是测试的一个很好的例子。良好的测试应该检查被测类是否满足接口的要求；他们不应该依赖于实现的细节。\n\n在`ListClientExample`中，将`LinkedList`替换为`ArrayList`。你可能需要添加一个`import`语句。编译并运行`ListClientExample`。然后再次运行测试。修改了这个之后，测试现在应该通过了。\n\n为了这个此测试通过，你只需要在构造函数中更改`LinkedList`；你不必更改任何`List`出现的地方。如果你这样做会发生什么？来吧，将一个或者多个`List`替换为`ArrayList`。程序仍然可以正常工作，但现在是“过度指定”了。如果你将来改变主意，并希望再次交换接口，则必须更改代码。\n\n在`ListClientExample`构造函数中，如果将`ArrayList`替换为`List`，会发生什么？为什么不能实例化`List`？\n"
  },
  {
    "path": "docs/think-dast-zh/10.md",
    "content": "# 第十章 哈希\n\n> 原文：[Chapter 10  Hashing](http://greenteapress.com/thinkdast/html/thinkdast011.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n在本章中，我定义了一个比`MyLinearMap`更好的`Map`接口实现，`MyBetterMap`，并引入哈希，这使得`MyBetterMap`效率更高。\n\n## 10.1 哈希\n\n为了提高`MyLinearMap`的性能，我们将编写一个新的类，它被称为`MyBetterMap`，它包含`MyLinearMap`对象的集合。它在内嵌的映射之间划分键，因此每个映射中的条目数量更小，这加快了`findEntry`，以及依赖于它的方法的速度。\n\n这是类定义的开始：\n\n```java\npublic class MyBetterMap<K, V> implements Map<K, V> {\n    \n    protected List<MyLinearMap<K, V>> maps;\n    \n    public MyBetterMap(int k) {\n        makeMaps(k);\n    }\n\n    protected void makeMaps(int k) {\n        maps = new ArrayList<MyLinearMap<K, V>>(k);\n        for (int i=0; i<k; i++) {\n            maps.add(new MyLinearMap<K, V>());\n        }\n    }\n}\n```\n\n实例变量`maps`是一组`MyLinearMap`对象。构造函数接受一个参数`k`，决定至少最开始，要使用多少个映射。然后`makeMaps`创建内嵌的映射并将其存储在一个`ArrayList`中。\n\n现在，完成这项工作的关键是，我们需要一些方法来查看一个键，并决定应该进入哪个映射。当我们`put`一个新的键时，我们选择一个映射；当我们`get`同样的键时，我们必须记住我们把它放在哪里。\n\n\n一种可能性是随机选择一个子映射，并跟踪我们把每个键放在哪里。但我们应该如何跟踪？看起来我们可以用一个`Map`来查找键，并找到正确的子映射，但是练习的重点是编写一个有效的`Map`实现。我们不能假设我们已经有了。\n\n一个更好的方法是使用一个哈希函数，它接受一个`Object`，一个任意的`Object`，并返回一个称为哈希码的整数。重要的是，如果它不止一次看到相同的`Object`，它总是返回相同的哈希码。这样，如果我们使用哈希码来存储键，当我们查找时，我们将得到相同的哈希码。\n\n\n在Java中，每个`Object`都提供了`hashCode`，一种计算哈希函数的方法。这种方法的实现对于不同的对象是不同的；我们会很快看到一个例子。\n\n这是一个辅助方法，为一个给定的键选择正确的子映射：\n\n```java\nprotected MyLinearMap<K, V> chooseMap(Object key) {\n    int index = 0;\n    if (key != null) { \n        index = Math.abs(key.hashCode()) % maps.size();\n    }\n    return maps.get(index);\n}\n```\n\n如果`key`是`null`，我们任意选择索引为`0`的子映射。否则，我们使用`hashCode`获取一个整数，调用`Math.abs`来确保它是非负数，然后使用余数运算符`%`，这保证结果在`0`和`maps.size()-1`之间。所以`index`总是一个有效的`maps`索引。然后`chooseMap`返回为其所选的映射的引用。\n\n我们使用`chooseMap`的`put`和`get`，所以当我们查询键的时候，我们得到添加时所选的相同映射，我们选择了相同的映射。至少应该是 - 稍后我会解释为什么这可能不起作用。\n\n这是我的`put`和`get`的实现：\n\n```java\npublic V put(K key, V value) {\n  MyLinearMap<K, V> map = chooseMap(key);\n    return map.put(key, value);\n}\n\npublic V get(Object key) {\n    MyLinearMap<K, V> map = chooseMap(key);\n    return map.get(key);\n}\n```\n\n很简单，对吧？在这两种方法中，我们使用`chooseMap`来找到正确的子映射，然后在子映射上调用一个方法。这就是它的工作原理。现在让我们考虑一下性能。\n\n如果在`k`个子映射中分配了`n`个条目，则平均每个映射将有`n/k`个条目。当我们查找一个键时，我们必须计算其哈希码，这需要一些时间，然后我们搜索相应的子映射。\n\n因为`MyBetterMap`中的条目列表，比`MyLinearMap`中的短`k`倍，我们的预期是`ķ`倍的搜索速度。但运行时间仍然与`n`成正比，所以`MyBetterMap`仍然是线性的。在下一个练习中，你将看到如何解决这个问题。\n\n## 10.2 哈希如何工作？\n\n哈希函数的基本要求是，每次相同的对象应该产生相同的哈希码。对于不变的对象，这是比较容易的。对于具有可变状态的对象，我们必须花费更多精力。\n\n作为一个不可变对象的例子，我将定义一个`SillyString`类，它包含一个`String`：\n\n```java\npublic class SillyString {\n    private final String innerString;\n\n    public SillyString(String innerString) {\n        this.innerString = innerString;\n    }\n\n    public String toString() {\n        return innerString;\n    }\n```\n\n这个类不是很有用，所以它叫做`SillyString`。但是我会使用它来展示，一个类如何定义它自己的哈希函数：\n\n```java\n    @Override\n    public boolean equals(Object other) {\n        return this.toString().equals(other.toString());\n    }\n    \n    @Override\n    public int hashCode() {\n        int total = 0;\n        for (int i=0; i<innerString.length(); i++) {\n            total += innerString.charAt(i);\n        }\n        return total;\n    }\n```\n\n注意`SillyString`重写了`equals`和`hashCode`。这个很重要。为了正常工作，`equals`必须和`hashCode`一致，这意味着如果两个对象被认为是相等的 - 也就是说，`equals`返回`true` - 它们应该有相同的哈希码。但这个要求只是单向的；如果两个对象具有相同的哈希码，则它们不一定必须相等。\n\n`equals`通过调用`toString`来工作，返回`innerString`。因此，如果两个`SillyString`对象的`innerString`实例变量相等，它们就相等。\n\n\n`hashCode`的原理是，迭代`String`中的字符并将它们相加。当你向`int`添加一个字符时，Java 将使用其 Unicode 代码点，将字符转换为整数。你不需要了解 Unicode 的任何信息来弄清此示例，但如果你好奇，可以在 <http://thinkdast.com/codepoint> 上阅读更多内容。\n\n\n该哈希函数满足要求：如果两个`SillyString`对象包含相等的内嵌字符串，则它们将获得相同的哈希码。\n\n这可以正常工作，但它可能不会产生良好的性能，因为它为许多不同的字符串返回相同的哈希码。如果两个字符串以任何顺序包含相同的字母，它们将具有相同的哈希码。即使它们不包含相同的字母，它们可能会产生相同的总量，例如`\"ac\"`和`\"bb\"`。\n\n如果许多对象具有相同的哈希码，它们将在同一个子映射中。如果一些子映射比其他映射有更多的条目，那么当我们有`k`个映射时，加速比可能远远小于`k`。所以哈希函数的目的之一是统一；也就是说，以相等的可能性，在这个范围内产生任何值。你可以在 <http://thinkdast.com/hash> 上阅读更多设计完成的，散列函数的信息。\n\n## 10.3 哈希和可变性\n\n`String`是不可变的，`SillyString`也是不可变的，因为`innerString`定义为`final`。一旦你创建了一个`SillyString`，你不能使`innerString`引用不同的`String`，你不能修改所指向的`String`。因此，它将始终具有相同的哈希码。\n\n\n但是让我们看看一个可变对象会发生什么。这是一个`SillyArray`定义，它与`SillyString`类似，除了它使用一个字符数组而不是一个`String`：\n\n```java\npublic class SillyArray {\n    private final char[] array;\n\n    public SillyArray(char[] array) {\n        this.array = array;\n    }\n\n    public String toString() {\n        return Arrays.toString(array);\n    }\n    \n    @Override\n    public boolean equals(Object other) {\n        return this.toString().equals(other.toString());\n    }\n    \n    @Override\n    public int hashCode() {\n        int total = 0;\n        for (int i=0; i<array.length; i++) {\n            total += array[i];\n        }\n        System.out.println(total);\n        return total;\n    }\n```\n\n`SillyArray`也提供`setChar`，它能够修改修改数组内的字符。\n\n```java\npublic void setChar(int i, char c) {\n    this.array[i] = c;\n}\n```\n\n现在假设我们创建了一个`SillyArray`，并将其添加到`map`。\n\n```java\nSillyArray array1 = new SillyArray(\"Word1\".toCharArray());\nmap.put(array1, 1);\n```\n\n这个数组的哈希码是`461`。现在如果我们修改了数组内容，之后尝试查询它，像这样：\n\n```java\narray1.setChar(0, 'C');\nInteger value = map.get(array1);\n```\n\n修改之后的哈希码是`441`。使用不同的哈希码，我们就很可能进入了错误的子映射。这就很糟糕了。\n\n一般来说，使用可变对象作为散列数据结构中的键是很危险的，这包括`MyBetterMap`和`HashMap`。如果你可以保证映射中的键不被修改，或者任何更改都不会影响哈希码，那么这可能是正确的。但是避免这样做可能是一个好主意。\n\n## 10.4 练习 8\n\n在这个练习中，你将完成`MyBetterMap`的实现。在本书的仓库中，你将找到此练习的源文件：\n\n+   `MyLinearMap.java`包含我们在以前的练习中的解决方案，我们将在此练习中加以利用。\n+   `MyBetterMap.java`包含上一章的代码，你将填充一些方法。\n+   `MyHashMap.java`包含按需增长的哈希表的概要，你将完成它。\n+   `MyLinearMapTest.java`包含`MyLinearMap`的单元测试。\n+   `MyBetterMapTest.java`包含`MyBetterMap`的单元测试。\n+   `MyHashMapTest.java`包含`MyHashMap`的单元测试。\n+   `Profiler.java`包含用于测量和绘制运行时间与问题大小的代码。\n+   `ProfileMapPut.java`包含配置该`Map.put`方法的代码 。\n\n像往常一样，你应该运行`ant build`来编译源文件。然后运行`ant MyBetterMapTest`。几个测试应该失败，因为你有一些工作要做！\n\n从以前的章节回顾`put`和`get`的实现。然后填充`containsKey`的主体。提示：使用`chooseMap`。再次运行`ant MyBetterMapTest`并确认通过了`testContainsKey`。\n\n\n填充`containsValue`的主体。提示：不要使用`chooseMap`。`ant MyBetterMapTest`再次运行并确认通过了`testContainsValue`。请注意，比起找到一个键，我们必须做更多的操作才能找到一个值。\n\n类似`put`和`get`，这个实现的`containsKey`是线性的，因为它搜索了内嵌子映射之一。在下一章中，我们将看到如何进一步改进此实现。\n\n"
  },
  {
    "path": "docs/think-dast-zh/11.md",
    "content": "# 第十一章 `HashMap`\n\n> 原文：[Chapter 11  HashMap](http://greenteapress.com/thinkdast/html/thinkdast012.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n上一章中，我们写了一个使用哈希的`Map`接口的实现。我们期望这个版本更快，因为它搜索的列表较短，但增长顺序仍然是线性的。\n\n如果存在`n`个条目和`k`个子映射，则子映射的大小平均为`n/k`，这仍然与`n`成正比。但是，如果我们与`n`一起增加`k`，我们可以限制`n/k`的大小。\n\n例如，假设每次`n`超过`k`的时候，我们都使`k`加倍；在这种情况下，每个映射的条目的平均数量将小于`1`，并且几乎总是小于`10`，只要散列函数能够很好地展开键。\n\n\n如果每个子映射的条目数是不变的，我们可以在常数时间内搜索一个子映射。并且计算散列函数通常是常数时间（它可能取决于键的大小，但不取决于键的数量）。这使得`Map`的核心方法， `put`和`get`时间不变。\n\n在下一个练习中，你将看到细节。\n\n## 11.1 练习 9\n\n在`MyHashMap.java`中，我提供了哈希表的大纲，它会按需增长。这里是定义的起始：\n\n```java\npublic class MyHashMap<K, V> extends MyBetterMap<K, V> implements Map<K, V> {\n\n    // average number of entries per sub-map before we rehash\n    private static final double FACTOR = 1.0;\n\n    @Override\n    public V put(K key, V value) {\n        V oldValue = super.put(key, value);\n\n        // check if the number of elements per sub-map exceeds the threshold\n        if (size() > maps.size() * FACTOR) {\n            rehash();\n        }\n        return oldValue;\n    }\n}\n```\n\n`MyHashMap`扩展了`MyBetterMap`，所以它继承了那里定义的方法。它覆盖的唯一方法是`put`，它调用了超类中的`put` -- 也就是说，它调用了`MyBetterMap `中的`put`版本 -- 然后它检查它是否必须`rehash`。调用`size`返回总数量`n`。调用`maps.size`返回内嵌映射的数量`k`。\n\n常数`FACTOR`（称为负载因子）确定每个子映射的平均最大条目数。如果`n > k * FACTOR`，这意味着`n/k > FACTOR`，意味着每个子映射的条目数超过阈值，所以我们调用`rehash`。\n\n\n运行`ant build`来编译源文件。然后运行`ant MyHashMapTest`。它应该失败，因为执行`rehash`会抛出异常。你的工作是填充它。\n\n\n填充`rehash`的主体，来收集表中的条目，调整表的大小，然后重新放入条目。我提供了两种可能会派上用场的方法：`MyBetterMap.makeMaps`和`MyLinearMap.getEntries`。每次调用它时，你的解决方案应该使映射数量加倍。\n\n## 11.2 分析`MyHashMap`\n\n如果最大子映射中的条目数与`n/k`成正比，并且`k`与`n`成正比，那么多个核心方法就是常数时间的：\n\n```java\n    public boolean containsKey（Object target）{ \n        MyLinearMap <K，V> map = chooseMap（target）; \n        return map.containsKey（target）; \n    } \n\n    public V get（Object key）{ \n        MyLinearMap <K，V> map = chooseMap（key）; return map.get（key）; \n    } \n    public V remove（Object key）{ \n        MyLinearMap <K，V> map = chooseMap（key）; \n        return map.remove（key）; \n    }\n```\n\n每个方法都计算键的哈希，这是常数时间，然后在一个子映射上调用一个方法，这个方法是常数时间的。\n\n到现在为止还挺好。但另一个核心方法，`put`有点难分析。当我们不需要`rehash`时，它是不变的时间，但是当我们这样做时，它是线性的。这样，它与 3.2 节中我们分析的`ArrayList.add`类似。\n\n\n出于同样的原因，如果我们平摊一系列的调用，结果是常数时间。同样，论证基于摊销分析（见 3.2 节）。\n\n\n假设子映射的初始数量`k`为`2`，负载因子为`1`。现在我们来看看`put`一系列的键需要多少工作量。作为基本的“工作单位”，我们将计算对密钥哈希，并将其添加到子映射中的次数。\n\n\n我们第一次调用`put`时，它需要`1`个工作单位。第二次也需要`1`个单位。第三次我们需要`rehash`，所以需要`2`个单位重新填充现有的键，和`1`个单位来对新键哈希。\n\n> 译者注：可以单独计算`rehash`中转移元素的数量，然后将元素转移的复杂度和计算哈希的复杂度相加。\n\n现在哈希表的大小是`4`，所以下次调用`put`时 ，需要`1`个工作单位。但是下一次我们必须`rehash`，需要`4`个单位来`rehash`现有的键，和`1`个单位来对新键哈希。\n\n\n图 11.1 展示了规律，对新键哈希的正常工作量在底部展示，额外工作量展示为塔楼。\n\n![](img/11-1.jpg)\n\n图 11.1：向哈希表添加元素的工作量展示\n\n如箭头所示，如果我们把塔楼推倒，每个积木都会在下一个塔楼之前填满空间。结果似乎`2`个单位的均匀高度，这表明`put`的平均工作量约为`2`个单位。这意味着`put`平均是常数时间。\n\n这个图还显示了，当我们`rehash`的时候，为什么加倍子映射数量`k`很重要。如果我们只是加上`k`而不是加倍，那么这些塔楼会靠的太近，他们会开始堆积。这样就不会是常数时间了。\n\n## 11.3 权衡\n\n我们已经表明，`containsKey`，`get`和`remove`是常数时间，`put`平均为常数时间。我们应该花一点时间来欣赏它有多么出色。无论哈希表有多大，这些操作的性能几乎相同。算是这样吧。\n\n\n记住，我们的分析基于一个简单的计算模型，其中每个“工作单位”花费相同的时间量。真正的电脑比这更复杂。特别是，当处理足够小，适应高速缓存的数据结构时，它们通常最快；如果结构不适合高速缓存但仍适合内存，则稍慢一点；如果结构不适合在内存中，则非常慢。\n\n\n这个实现的另一个限制是，如果我们得到了一个值而不是一个键时，那么散列是不会有帮助的：`containsValue`是线性的，因为它必须搜索所有的子映射。查找一个值并找到相应的键（或可能的键），没有特别有效的方式。\n\n\n还有一个限制：`MyLinearMap`的一些常数时间的方法变成了线性的。例如：\n\n```java\n    public void clear() {\n        for (int i=0; i<maps.size(); i++) {\n            maps.get(i).clear();\n        }\n    }\n```\n\n`clear`必须清除所有的子映射，子映射的数量与`n`成正比，所以它是线性的。幸运的是，这个操作并不常用，所以在大多数应用中，这种权衡是可以接受的。\n\n## 11.4 分析`MyHashMap`\n\n在我们继续之前，我们应该检查一下，`MyHashMap.put`是否真的是常数时间。\n\n\n运行`ant build`来编译源文件。然后运行`ant ProfileMapPut`。它使用一系列问题规模，测量 `HashMap.put`（由 Java 提供）的运行时间，并在重对数比例尺上绘制运行时间与问题规模。如果这个操作是常数时间，`n`个操作的总时间应该是线性的，所以结果应该是斜率为`1`的直线。当我运行这个代码时，估计的斜率接近`1`，这与我们的分析一致。你应该得到类似的东西。\n\n修改`ProfileMapPut.java`，来测量你的`MyHashMap`实现，而不是 Java 的`HashMap`。再次运行分析器，查看斜率是否接近`1`。你可能需要调整`startN`和`endMillis`，来找到一系列问题规模，其中运行时间多于几毫秒，但不超过几秒。\n\n当我运行这个代码时，我感到惊讶：斜率大约为`1.7`，这表明这个实现不是一直都是常数的。它包含一个“性能错误”。\n\n\n在阅读下一节之前，你应该跟踪错误，修复错误，并确认现在`put`是常数时间，符合预期。\n\n## 11.5 修复`MyHashMap`\n\n`MyHashMap`的问题是`size`，它继承自`MyBetterMap`：\n\n```java\n    public int size() {\n        int total = 0;\n        for (MyLinearMap<K, V> map: maps) {\n            total += map.size();\n        }\n        return total;\n    }\n```\n\n为了累计整个大小，它必须迭代子映射。由于我们增加了子映射的数量`k`，随着条目数`n`增加，所以`k`与`n`成正比，所以`size`是线性的。\n\n`put`也是线性的，因为它使用`size`：\n\n```java\n    public V put(K key, V value) {\n        V oldValue = super.put(key, value);\n\n        if (size() > maps.size() * FACTOR) {\n            rehash();\n        }\n        return oldValue;\n    }\n```\n\n如果`size`是线性的，我们做的一切都浪费了。\n\n幸运的是，有一个简单的解决方案，我们以前看过：我们必须维护实例变量中的条目数，并且每当我们调用一个改变它的方法时更新它。\n\n你会在这本书的仓库中找到我的解决方案`MyFixedHashMap.java`。这是类定义的起始：\n\n```java\npublic class MyFixedHashMap<K, V> extends MyHashMap<K, V> implements Map<K, V> {\n\n    private int size = 0;\n\n    public void clear() {\n        super.clear();\n        size = 0;\n    }\n```\n\n我们不修改`MyHashMap`，我定义一个扩展它的新类。它添加一个新的实例变量`size`，它被初始化为零。\n\n更新`clear`很简单; 我们在超类中调用`clear`（清除子映射），然后更新`size`。\n\n\n更新`remove`和`put`有点困难，因为当我们调用超类的该方法，我们不能得知子映射的大小是否改变。这是我的解决方式：\n\n```java\n    public V remove(Object key) {\n        MyLinearMap<K, V> map = chooseMap(key);\n        size -= map.size();\n        V oldValue = map.remove(key);\n        size += map.size();\n        return oldValue;\n    }\n```\n\n`remove`使用`chooseMap`找到正确的子映射，然后减去子映射的大小。它会在子映射上调用`remove`，根据是否找到了键，它可以改变子映射的大小，也可能不会改变它的大小。但是无论哪种方式，我们将子映射的新大小加到`size`，所以最终的`size`值是正确的。\n\n重写的`put`版本是类似的：\n\n```java\n    public V put(K key, V value) {\n        MyLinearMap<K, V> map = chooseMap(key);\n        size -= map.size();\n        V oldValue = map.put(key, value);\n        size += map.size();\n\n        if (size() > maps.size() * FACTOR) {\n            size = 0;\n            rehash();\n        }\n        return oldValue;\n    }\n```\n\n我们在这里也有同样的问题：当我们在子地图上调用`put`时，我们不知道是否添加了一个新的条目。所以我们使用相同的解决方案，减去旧的大小，然后加上新的大小。\n\n现在`size`方法的实现很简单了：\n\n```java\n    public int size() {\n        return size;\n    }\n```\n\n并且正好是常数时间。\n\n当我测量这个解决方案时，我发现放入`n`个键的总时间正比于`n`，也就是说，每个`put`是常数时间的，符合预期。\n\n## 11.6 UML 类图\n\n在本章中使用代码的一个挑战是，我们有几个互相依赖的类。以下是类之间的一些关系：\n\n+   `MyLinearMap`包含一个`LinkedList`并实现了`Map`。\n+   `MyBetterMap`包含许多`MyLinearMap`对象并实现了`Map`。\n+   `MyHashMap`扩展了`MyBetterMap`，所以它也包含`MyLinearMap对象`，并实现了`Map`。\n+   `MyFixedHashMap`扩展了`MyHashMap`并实现了`Map`。\n\n为了有助于跟踪这些关系，软件工程师经常使用 UML 类图。UML 代表统一建模语言（见 <http://thinkdast.com/uml> ）。“类图”是由 UML 定义的几种图形标准之一。\n\n在类图中，每个类由一个框表示，类之间的关系由箭头表示。图  11.2 显示了使用在线工具 yUML（<http://yuml.me/>）生成的，上一个练习的 UML 类图。\n\n![](img/11-2.jpg)\n\n图11.2：本章中的 UML 类图\n\n不同的关系由不同的箭头表示：\n\n+   实心箭头表示 HAS-A 关系。例如，每个`MyBetterMap`实例包含多个`MyLinearMap`实例，因此它们通过实线箭头连接。\n+   空心和实线箭头表示 IS-A 关系。例如，`MyHashMap`扩展 了`MyBetterMap`，因此它们通过 IS-A 箭头连接。\n+   空心和虚线箭头表示一个类实现了一个接口;在这个图中，每个类都实现 `Map`。\n\nUML 类图提供了一种简洁的方式，来表示大量类集合的信息。在设计阶段中，它们用于交流备选设计，在实施阶段中，用于维护项目的共享思维导图，并在部署过程中记录设计。\n"
  },
  {
    "path": "docs/think-dast-zh/12.md",
    "content": "# 第十二章 `TreeMap`\n\n> 原文：[Chapter 12  TreeMap](http://greenteapress.com/thinkdast/html/thinkdast013.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n这一章展示了二叉搜索树，它是个`Map`接口的高效实现。如果我们想让元素有序，它非常实用。\n\n## 12.1 哈希哪里不对？\n\n此时，你应该熟悉 Java 提供的`Map`接口和`HashMap`实现。通过使用哈希表来制作你自己的`Map`，你应该了解`HashMap`的工作原理，以及为什么我们预计其核心方法是常数时间的。\n\n由于这种表现，`HashMap`被广泛使用，但并不是唯一的`Map`实现。有几个原因可能需要另一个实现：\n\n哈希可能很慢，所以即使`HashMap`操作是常数时间，“常数”可能很大。\n如果哈希函数将键均匀分配给子映射，效果很好。但设计良好的散列函数并不容易，如果太多的键在相同的子映射上，那么`HashMap`的性能可能会很差。\n哈希表中的键不以任何特定顺序存储；实际上，当表增长并且键被重新排列时，顺序可能会改变。对于某些应用程序，必须或至少保持键的顺序，这很有用。\n\n很难同时解决所有这些问题，但是 Java 提供了一个称为`TreeMap`的实现：\n\n+   它不使用哈希函数，所以它避免了哈希的开销和选择哈希函数的困难。\n+   在`TreeMap`之中，键被存储在二叉搜索树中，这使我们可以以线性时间顺序遍历键。\n+   核心方法的运行时间与`log(n)`成正比，并不像常数时间那样好，但仍然非常好。\n\n在下一节中，我将解释二进制搜索树如何工作，然后你将使用它来实现`Map`。另外，使用树实现时，我们将分析映射的核心方法的性能。\n\n## 12.2 二叉搜索树\n\n二叉搜索树（BST）是一个树，其中每个`node`（节点）包含一个键，并且每个都具有“BST 属性”：\n\n+   如果`node`有一个左子树，左子树中的所有键都必须小于`node`的键。\n+   如果`node`有一个右子树，右子树中的所有键都必须大于`node`的键。\n\n![](img/12-1.jpg)\n\n图 12.1：二叉搜索树示例\n\n图 12.1 展示了一个具有此属性的整数的树。这个图片来自二叉搜索树的维基百科页面，位于 <http://thinkdast.com/bst>，当你做这个练习时，你会发现它很实用。\n\n根节点中的键为`8`，你可以确认根节点左边的所有键小于`8`，右边的所有键都更大。你还可以检查其他节点是否具有此属性。\n\n\n在二叉搜索树中查找一个键是很快的，因为我们不必搜索整个树。从根节点开始，我们可以使用以下算法：\n\n+   将你要查找的键`target`，与当前节点的键进行比较。如果他们相等，你就完成了。\n+   如果`target`小于当前键，搜索左子树。如果没有，`target`不在树上。\n+   如果`target`大于当前键，搜索右子树。如果没有，`target`不在树上。\n\n在树的每一层，你只需要搜索一个子树。例如，如果你在上图中查找`target = 4`，则从根节点开始，它包含键`8`。因为`target`小于`8`，你走了左边。因为`target`大于`3`，你走了右边。因为`target`小于`6`，你走了左边。然后你找到你要找的键。\n\n在这个例子中，即使树包含九个键，它需要四次比较来找到目标。一般来说，比较的数量与树的高度成正比，而不是树中的键的数量。\n\n因此，我们可以计算树的高度`h`和节点个数`n`的关系。从小的数值开始，逐渐增加：\n\n如果`h=1`，树只包含一个节点，那么`n=1`。\n如果`h=2`，我们可以添加两个节点，总共`n=3`。\n如果`h=3`，我们可以添加多达四个节点，总共`n=7`。\n如果`h=4`，我们可以添加多达八个节点，总共`n=15`。\n\n现在你可能会看到这个规律。如果我们将树的层数从`1`数到`n`，第`i`层可以拥有多达`2^(n-1)`个节点。`h`层的树共有`2^h-1`个节点。如果我们有：\n\n```\nn = 2^h - 1\n```\n\n我们可以对两边取以`2`为底的对数：\n\n```\nlog2(n) ≈ h\n```\n\n意思是树的高度正比于`logn`，如果它是满的。也就是说，如果每一层包含最大数量的节点。\n\n所以我们预计，我们可以以正比于`logn`的时间，在二叉搜索树中查找节点。如果树是慢的，即使是部分满的，这是对的。但是并不总是对的，我们将会看到。\n\n时间正比于`logn`的算法是对数时间的，并且属于`O(logn)`的增长级别。\n\n\n## 12.3 练习 10\n\n对于这个练习，你将要使用二叉搜索树编写`Map`接口的一个实现。\n\n这里是实现的开头，叫做`MyTreeMap`：\n\n```java\npublic class MyTreeMap<K, V> implements Map<K, V> {\n\n    private int size = 0;\n    private Node root = null;\n```\n\n实例变量是`size`，它跟踪了键的数量，以及`root`，它是树中根节点的引用。树为空的时候，`root`是`null`，`size`是`0`。\n\n这里是`Node`的定义，它在`MyTreeMap`之中定义。\n\n```java\n    protected class Node {\n        public K key;\n        public V value;\n        public Node left = null;\n        public Node right = null;\n\n        public Node(K key, V value) {\n            this.key = key;\n            this.value = value;\n        }\n    }\n```\n\n每个节点包含一个键值对，以及两个子节点的引用，`left`和`right`。任意子节点都可以为`null`。\n\n一些`Map`方法易于实现，比如`size`和`clear`：\n\n```java\n    public int size() {\n        return size;\n    }\n\n    public void clear() {\n        size = 0;\n        root = null;\n    }\n```\n\n`size`显然是常数时间的。\n\n`clear`也是常数时间的，但是考虑这个：当`root`赋为`null`时，垃圾收集器回收了树中的节点，这是线性时间的。这个工作是否应该由垃圾收集器的计数来完成呢？我认为是的。\n\n下一节中，你会填充一些其它方法，包括最重要的`get`和`set`。\n\n## 12.4 实现`TreeMap`\n\n这本书的仓库中，你将找到这些源文件：\n\n+   `MyTreeMap.java`包含上一节的代码，其中包含缺失方法的大纲。\n+   `MyTreeMapTest.java`包含单元`MyTreeMap`的测试。\n\n运行`ant build`来编译源文件。然后运行`ant   MyTreeMapTest`。几个测试应该失败，因为你有一些工作要做！\n\n我已经提供了`get`和`containsKey`的大纲。他们都使用`findNode`，这是我定义的私有方法；它不是`Map`接口的一部分。以下是它的起始：\n\n```java\n    private Node findNode(Object target) {\n        if (target == null) {\n            throw new IllegalArgumentException();\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        Comparable<? super K> k = (Comparable<? super K>) target;\n\n        // TODO: FILL THIS IN!\n        return null;\n    }\n```\n\n参数`target`是我们要查找的键。如果`target`是`null`，`findNode`抛出异常。一些`Map`实现可以将`null`处理为一个键，但是在二叉搜索树中，我们需要能够比较键，所以处理`null`是有问题的。为了保持简单，这个实现不将`null`视为键。\n\n下一行显示如何将`target`与树中的键进行比较。按照`get`和`containsKey`的签名（名称和参数），编译器认为`target`是一个`Object`。但是，我们需要能够对键进行比较，所以我们将`target`强制转换为`Comparable<? super K>`，这意味着它可以与类型`K`（或任何超类）的示例比较。如果你不熟悉“类型通配符”的用法，可以在 <http://thinkdast.com/gentut> 上阅读更多内容。\n\n\n幸运的是，Java 的类型系统的处理不是这个练习的重点。你的工作是填写剩下的`findNode`。如果它发现一个包含`target`键的节点，它应该返回该节点。否则应该返回`null`。当你使其工作，`get`和`containsKey`的测试应该通过。\n\n请注意，你的解决方案应该只搜索通过树的一条路径，因此它应该与树的高度成正比。你不应该搜索整棵树！\n\n\n你的下一个任务是填充`containsValue`。为了让你起步，我提供了一个辅助方法`equals`，比较`target`和给定的键。请注意，树中的值（与键相反）不一定是可比较的，所以我们不能使用`compareTo`；我们必须在`target`上调用`equals`。\n\n\n不像你以前的`findNode`解决方案，你的`containsValue`解决方案应该搜索整个树，所以它的运行时间正比于键的数量`n`，而不是树的高度`h`。\n\n> 译者注：这里你可能想使用之前讲过的 DFS 迭代器。\n\n你应该填充的下一个方法是`put`。我提供了处理简单情况的起始代码：\n\n```java\n    public V put(K key, V value) {\n        if (key == null) {\n            throw new IllegalArgumentException();\n        }\n        if (root == null) {\n            root = new Node(key, value);\n            size++;\n            return null;\n        }\n        return putHelper(root, key, value);\n    }\n\n    private V putHelper(Node node, K key, V value) {\n        // TODO: Fill this in.\n    }\n```\n\n如果你尝试将`null`作为关键字，`put`则会抛出异常。\n\n如果树为空，则`put`创建一个新节点并初始化实例变量`root`。\n\n否则，它调用`putHelper`，这是我定义的私有方法；它不是`Map`接口的一部分。\n\n填写`putHelper`，让它搜索树，以及：\n\n+   如果`key`已经在树中，它将使用新值替换旧值，并返回旧值。\n+   如果`key`不在树中，它将创建一个新节点，找到正确的添加位置，并返回`null`。\n\n你的`put`实现的是时间应该与树的高度`h`成正比，而不是元素的数量`n`。理想情况下，你只需搜索一次树，但如果你发现两次更容易搜索，可以这样做：它会慢一些，但不会改变增长级别。\n\n最后，你应该填充`keySet`。根据 <http://thinkdast.com/mapkeyset> 的文档，该方法应该返回一个`Set`，可以按顺序迭代键；也就是说，按照`compareTo`方法，升序迭代。我们在 8.3 节中使用的`HashSet`实现不会维护键的顺序，但`LinkedHashSet`实现可以。你可以阅读 <http://thinkdast.com/linkedhashset>。\n\n\n我提供了一个`keySet`的大纲，创建并返回`LinkedHashSet`：\n\n```\n    public Set<K> keySet() {\n        Set<K> set = new LinkedHashSet<K>();\n        return set;\n    }\n```\n\n你应该完成此方法，使其以升序向`set`添加树中的键。提示：你可能想编写一个辅助程序；你可能想让它递归；你也可能想要阅读 <http://thinkdast.com/inorder> 上的树的中序遍历。\n\n当你完成时，所有测试都应该通过。下一章中，我会讲解我的解法，并测试核心方法的性能。\n"
  },
  {
    "path": "docs/think-dast-zh/13.md",
    "content": "# 第十三章 二叉搜索树\n\n> 原文：[Chapter 13  Binary search tree](http://greenteapress.com/thinkdast/html/thinkdast014.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n本章介绍了上一个练习的解决方案，然后测试树形映射的性能。我展示了一个实现的问题，并解释了 Java 的`TreeMap`如何解决它。\n\n## 13.1 简单的`MyTreeMap`\n\n上一个练习中，我给了你`MyTreeMap`的大纲，并让你填充缺失的方法。现在我会展示结果，从`findNode`开始：\n\n```java\nprivate Node findNode(Object target) {\n    // some implementations can handle null as a key, but not this one\n    if (target == null) {\n            throw new IllegalArgumentException();\n    }\n\n    // something to make the compiler happy\n    @SuppressWarnings(\"unchecked\")\n    Comparable<? super K> k = (Comparable<? super K>) target;\n\n    // the actual search\n    Node node = root;\n    while (node != null) {\n        int cmp = k.compareTo(node.key);\n        if (cmp < 0)\n            node = node.left;\n        else if (cmp > 0)\n            node = node.right;\n        else\n            return node;\n    }\n    return null;\n}\n```\n\n`findNode`是`containsKey`和`get`所使用的一个私有方法；它不是`Map`接口的一部分。参数`target`是我们要查找的键。我在上一个练习中解释了这种方法的第一部分：\n\n+   在这个实现中，`null`不是键的合法值。\n+   在我们可以在`target`上调用`compareTo`之前，我们必须把它强制转换为某种形式的`Comparable`。这里使用的“类型通配符”会尽可能允许；也就是说，它适用于任何实现`Comparable`类型，并且它的`compareTo`接受`K`或者任和`K`的超类。\n\n之后，实际搜索比较简单。我们初始化一个循环变量`node`来引用根节点。每次循环中，我们将目标与`node.key`比较。如果目标小于当前键，我们移动到左子树。如果它更大，我们移动到右子树。如果相等，我们返回当前节点。\n\n如果在没有找到目标的情况下，我们到达树的底部，我就认为，它不在树中并返回`null`。\n\n## 13.2 搜索值\n\n我在前面的练习中解释了，`findNode`运行时间与树的高度成正比，而不是节点的数量，因为我们不必搜索整个树。但是对于`containsValue`，我们必须搜索值，而不是键；BST 的特性不适用于值，因此我们必须搜索整个树。\n\n我的解法是递归的：\n\n```java\npublic boolean containsValue(Object target) {\n    return containsValueHelper(root, target);\n}\n\nprivate boolean containsValueHelper(Node node, Object target) {\n    if (node == null) {\n        return false;\n    }\n    if (equals(target, node.value)) {\n        return true;\n    }\n    if (containsValueHelper(node.left, target)) {\n        return true;\n    }\n    if (containsValueHelper(node.right, target)) {\n        return true;\n    }\n    return false;\n}\n```\n\n`containsValue`将目标值作为参数，并立即调用`containsValueHelper`，传递树的根节点作为附加参数。\n\n这是`containsValueHelper`的工作原理：\n\n+   第一个`if`语句检查递归的边界情况。如果`node`是`null`，那意味着我们已经递归到树的底部，没有找到`target`，所以我们应该返回`false`。请注意，这只意味着目标没有出现在树的一条路径上；它仍然可能会在另一条路径上被发现。\n+   第二种情况检查我们是否找到了我们正在寻找的东西。如果是这样，我们返回`true`。否则，我们必须继续。\n+   第三种情况是执行递归调用，在左子树中搜索`target`。如果我们找到它，我们可以立即返回`true`，而不搜索右子树。否则我们继续。\n+   第四种情况是搜索右子树。同样，如果我们找到我们正在寻找的东西，我们返回`true`。否则，我们搜索完了整棵树，返回`false`。\n\n该方法“访问”了树中的每个节点，所以它的所需时间与节点数成正比。\n\n## 13.3 实现`put`\n\n`put`方法比起`get`要复杂一些，因为要处理两种情况：（1）如果给定的键已经在树中，则替换并返回旧值；（2）否则必须在树中添加一个新的节点，在正确的地方。\n\n\n在上一个练习中，我提供了这个起始代码：\n\n```java\npublic V put(K key, V value) {\n    if (key == null) {\n        throw new IllegalArgumentException();\n    }\n    if (root == null) {\n        root = new Node(key, value);\n        size++;\n        return null;\n    }\n    return putHelper(root, key, value);\n}\n```\n\n并且让你填充`putHelper`。这里是我的答案：\n\n```java\nprivate V putHelper(Node node, K key, V value) {\n    Comparable<? super K> k = (Comparable<? super K>) key;\n    int cmp = k.compareTo(node.key);\n\n    if (cmp < 0) {\n        if (node.left == null) {\n            node.left = new Node(key, value);\n            size++;\n            return null;\n        } else {\n            return putHelper(node.left, key, value);\n        }\n    }\n    if (cmp > 0) {\n        if (node.right == null) {\n            node.right = new Node(key, value);\n            size++;\n            return null;\n        } else {\n            return putHelper(node.right, key, value);\n        }\n    }\n    V oldValue = node.value;\n    node.value = value;\n    return oldValue;\n}\n```\n\n第一个参数`node`最初是树的根，但是每次我们执行递归调用，它指向了不同的子树。就像`get`一样，我们用`compareTo`方法来弄清楚，跟随哪一条树的路径。如果`cmp < 0`，我们添加的键小于`node.key`，那么我们要走左子树。有两种情况：\n\n+   如果左子树为空，那就是，如果`node.left`是`null`，我们已经到达树的底部而没有找到`key`。这个时候，我们知道`key`不在树上，我们知道它应该放在哪里。所以我们创建一个新节点，并将它添加为`node`的左子树。\n+   否则我们进行递归调用来搜索左子树。\n\n如果`cmp > 0`，我们添加的键大于`node.key`，那么我们要走右子树。我们处理的两个案例与上一个分支相同。最后，如果`cmp == 0`，我们在树中找到了键，那么我们更改它并返回旧的值。\n\n我使用递归编写了这个方法，使它更易于阅读，但它可以直接用迭代重写一遍，你可能想留作练习。\n\n## 13.4 中序遍历\n\n我要求你编写的最后一个方法是`keySet`，它返回一个`Set`，按升序包含树中的键。在其他`Map`实现中，`keySet`返回的键没有特定的顺序，但是树形实现的一个功能是，对键进行简单而有效的排序。所以我们应该利用它。\n\n这是我的答案：\n\n```java\npublic Set<K> keySet() {\n    Set<K> set = new LinkedHashSet<K>();\n    addInOrder(root, set);\n    return set;\n}\n\nprivate void addInOrder(Node node, Set<K> set) {\n    if (node == null) return;\n    addInOrder(node.left, set);\n    set.add(node.key);\n    addInOrder(node.right, set);        \n}\n```\n\n在`keySet`中，我们创建一个`LinkedHashSet`，这是一个`Set`实现，使元素保持有序（与大多数其他`Set`实现不同）。然后我们调用`addInOrder`来遍历树。\n\n第一个参数`node`最初是树的根，但正如你的期望，我们用它来递归地遍历树。`addInOrder`对树执行经典的“中序遍历”。\n\n如果`node`是`null`，这意味着子树是空的，所以我们返回，而不向`set`添加任何东西。否则我们：\n\n1.  按顺序遍历左子树。\n1.  添加`node.key`。\n1.  按顺序遍历右子树。\n\n请记住，BST 的特性保证左子树中的所有节点都小于`node.key`，并且右子树中的所有节点都更大。所以我们知道，`node.key`已按正确的顺序添加。\n\n递归地应用相同的参数，我们知道左子树中的元素是有序的，右子树中的元素也一样。并且边界情况是正确的：如果子树为空，则不添加任何键。所以我们可以认为，该方法以正确的顺序添加所有键。\n\n因为`containsValue`方法访问树中的每个节点，所以所需时间与`n`成正比。\n\n## 13.5 对数时间的方法\n\n在`MyTreeMap`中，`get`和`put`方法所需时间与树的高度`h`成正比。在上一个练习中，我们展示了如果树是满的 - 如果树的每一层都包含最大数量的节点 - 树的高度与`log n`成横臂。\n\n\n我也说了，`get`和`put`是对数时间的；也就是说，他们的所需时间与`logn`成正比。但是对于大多数应用程序，不能保证树是满的。一般来说，树的形状取决于键和添加顺序。\n\n为了看看这在实践中是怎么回事，我们将用两个样本数据集来测试我们的实现：随机字符串的列表和升序的时间戳列表。\n\n\n这是生成随机字符串的代码：\n\n```java\nMap<String, Integer> map = new MyTreeMap<String, Integer>();\n\nfor (int i=0; i<n; i++) {\n    String uuid = UUID.randomUUID().toString();\n    map.put(uuid, 0);\n}\n```\n\n`UUID`是`java.util`中的类，可以生成随机的“通用唯一标识符”。UUID 对于各种应用是有用的，但在这个例子中，我们利用一种简单的方法来生成随机字符串。\n\n我使用`n=16384`来运行这个代码，并测量了最后的树的运行时间和高度。以下是输出：\n\n```\nTime in milliseconds = 151\nFinal size of MyTreeMap = 16384\nlog base 2 of size of MyTreeMap = 14.0\nFinal height of MyTreeMap = 33\n```\n\n我包含了“`MyTreeMap`大小的`2`为底的对数”，看看如果它已满，树将是多高。结果表明，高度为`14`的完整树包含`16384`个节点。\n\n随机字符串的树高度实际为33，这远大于理论上的最小值，但不是太差。要查找`16,384`个键中的一个，我们只需要进行`33`次比较。与线性搜索相比，速度快了近`500`倍。\n\n这种性能通常是随机字符串，或其他不按照特定顺序添加的键。树的最终高度可能是理论最小值的`2~3`倍，但它仍然与`log n`成正比，这远小于`n`。事实上，随着`n`的增加，`logn`会慢慢增加，在实践中，可能很难将对数时间与常数时间区分开。\n\n\n然而，二叉搜索树并不总是表现良好。让我们看看，当我们以升序添加键时会发生什么。下面是一个示例，以微秒为单位测量时间戳，并将其用作键：\n\n```java\nMyTreeMap<String, Integer> map = new MyTreeMap<String, Integer>();\n\nfor (int i=0; i<n; i++) {\n    String timestamp = Long.toString(System.nanoTime());\n    map.put(timestamp, 0);\n}\n```\n\n`System.nanoTime`返回一个`long`类型的整数，表示以微秒为单位的启动时间。每次我们调用它时，我们得到一个更大的数字。当我们将这些时间戳转换为字符串时，它们按字典序增加。\n\n让我们看看当我们运行它时会发生什么：\n\n```java\nTime in milliseconds = 1158\nFinal size of MyTreeMap = 16384\nlog base 2 of size of MyTreeMap = 14.0\nFinal height of MyTreeMap = 16384\n```\n\n运行时间是以前的时间的七倍多。时间更长。如果你想知道为什么，看看树的最后的高度：`16384`！\n\n![](img/13-1.jpg)\n\n图 13.1：二叉搜索树，平衡（左边）和不平衡（右边）\n\n如果你思考`put`如何工作，你可以弄清楚发生了什么。每次添加一个新的键时，它都大于树中的所有键，所以我们总是选择右子树，并且总是将新节点添加为，最右边的节点的右子节点。结果是一个“不平衡”的树，只包含右子节点。\n\n这种树的高度正比于`n`，不是`logn`，所以`get`和`put`的性能是线性的，不是对数的。\n\n\n图 13.1 显示了平衡和不平衡树的示例。在平衡树中，高度为`4`，节点总数为`2^4 - 1 = 15`。在节点数相同的不平衡树中，高度为`15`。\n\n## 13.6 自平衡树\n\n这个问题有两种可能的解决方案：\n\n你可以避免向`Map`按顺序添加键。但这并不总是可能的。\n你可以制作一棵树，如果碰巧按顺序处理键，那么它会更好地处理键。\n\n第二个解决方案是更好的，有几种方法可以做到。最常见的是修改`put`，以便它检测树何时开始变得不平衡，如果是，则重新排列节点。具有这种能力的树被称为“自平衡树”。普通的自平衡树包括 AVL 树（“AVL”是发明者的缩写），以及红黑树，这是 Java`TreeMap`所使用的。\n\n在我们的示例代码中，如果我们用 Java 的`MyTreeMap`替换，随机字符串和时间戳的运行时间大致相同。实际上，时间戳运行速度更快，即使它们有序，可能是因为它们花费的时间较少。\n\n\n总而言之，二叉搜索树可以以对数时间实现`get`和`put`，但是只能按照使得树足够平衡的顺序添加键。自平衡树通过每次添加新键时，进行一些额外的工作来避免这个问题。\n\n你可以在 <http://thinkdast.com/balancing> 上阅读自平衡树的更多信息。\n\n## 13.7 更多练习\n\n在上一个练习中，你不必实现`remove`，但你可能需要尝试。如果从树中央删除节点，则必须重新排列剩余的节点，来恢复 BST 的特性。你可以自己弄清楚如何实现，或者你可以阅读 <http://thinkdast.com/bstdel> 上的说明。\n\n删除一个节点并重新平衡一个树是类似的操作：如果你做这个练习，你将更好地了解自平衡树如何工作。\n"
  },
  {
    "path": "docs/think-dast-zh/14.md",
    "content": "# 第十四章 持久化\n\n> 原文：[Chapter 14  Persistence](http://greenteapress.com/thinkdast/html/thinkdast015.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n在接下来的几个练习中，我们将返回到网页搜索引擎的构建。为了回顾，搜索引擎的组件是：\n\n+   抓取：我们需要一个程序，可以下载一个网页，解析它，并提取文本和任何其他页面的链接。\n+   索引：我们需要一个索引，可以查找检索项并找到包含它的页面。\n+   检索：我们需要一种方法，从索引中收集结果，并识别与检索项最相关的页面。\n\n如果你做了练习 8.3，你使用 Java 映射实现了一个索引。在本练习中，我们将重新审视索引器，并创建一个新版本，将结果存储在数据库中。\n\n\n如果你做了练习 7.4，你创建了一个爬虫，它跟踪它找到的第一个链接。在下一个练习中，我们将制作一个更通用的版本，将其查找到的每个链接存储在队列中，并对其进行排序。\n\n然后，最后，你将处理检索问题。\n\n在这些练习中，我提供较少的起始代码，你将做出更多的设计决策。这些练习也更加开放。我会提出一些最低限度的目标，你应该尝试实现它们，但如果你想挑战自己，有很多方法可以让你更深入。\n\n现在，让我们开始编写一个新版本的索引器。\n\n## 14.1 Redis \n\n索引器的之前版本，将索引存储在两个数据结构中：`TermCounter`将检索词映射为网页上显示的次数，以及`Index`将检索词映射为出现的页面集合。\n\n这些数据结构存储在正在运行的 Java 程序的内存中，这意味着当程序停止运行时，索引会丢失。仅在运行程序的内存中存储的数据称为“易失的”，因为程序结束时会消失。\n\n\n在创建它的程序结束后，仍然存在的数据称为“持久的”。通常，存储在文件系统中的文件，以及存储在数据库中的数据是持久的。\n\n\n使数据持久化的一种简单方法是，将其存储在文件中。在程序结束之前，它可以将其数据结构转换为 JSON 格式（<http://thinkdast.com/json>），然后将它们写入文件。当它再次启动时，它可以读取文件并重建数据结构。\n\n但这个解决方案有几个问题：\n\n+   读取和写入大型数据结构（如 Web 索引）会很慢。\n+   整个数据结构可能不适合单个运行程序的内存。\n+   如果程序意外结束（例如，由于断电），则自程序上次启动以来所做的任何更改都将丢失。\n\n一个更好的选择是提供持久存储的数据库，并且能够读取和写入数据库的部分，而无需读取和写入整个数据。\n\n有多种数据库管理系统（DBMS）提供不同的功能。你可以在 <http://thinkdast.com/database> 阅读概述。\n\n\n我为这个练习推荐的数据库是 Redis，它提供了类似于 Java 数据结构的持久数据结构。具体来说，它提供：\n\n字符串列表，与 Java 的`List`类似。\n哈希，类似于 Java 的`Map`。\n字符串集合，类似于 Java 的`Set`。\n\n> 译者注：另外还有类似于 Java 的`LinkedHashSet`的有序集合。\n\nRedis 是一个“键值数据库”，这意味着它包含的数据结构（值）由唯一的字符串（键）标识。Redis 中的键与 Java 中的引用相同：它标识一个对象。我们稍后会看到一些例子。\n\n## 14.2 Redis 客户端和服务端\n\nRedis 通常运行为远程服务；其实它的名字代表“REmote DIctionary Server”（远程字典服务，字典其实就是映射）。为了使用 Redis，你必须在某处运行 Redis 服务器，然后使用 Redis 客户端连接到 Redis 服务器。有很多方法可用于设置服务器，也有许多你可以使用的客户端。对于这个练习，我建议：\n\n不要自己安装和运行服务器，请考虑使用像 RedisToGo（<http://thinkdast.com/redistogo>）这样的服务，它在云主机运行 Redis。他们提供了一个免费的计划（配置），有足够的资源用于练习。\n对于客户端，我推荐 Jedis，它是一个 Java 库，提供了使用 Redis 的类和方法。\n\n以下是更详细的说明，以帮助你开始使用：\n\n+   在 RedisToGo 上创建一个帐号，网址为 <http://thinkdast.com/redissign> ，并选择所需的计划（可能是免费的起始计划）。\n+   创建一个“实例”，它是运行 Redis 服务器的虚拟机。如果你单击“实例”选项卡，你将看到你的新实例，由主机名和端口号标识。例如，我有一个名为`dory-10534`的实例。\n+   单击实例名称来访问配置页面。记下页面顶部附近的网址，如下所示：\n    ```\n    redis://redistogo:1234567feedfacebeefa1e1234567@dory.redistogo.com:10534\n    ```\n\n这个 URL 包含服务器的主机名称`dory.redistogo.com`，端口号`10534`和连接到服务器所需的密码，它是中间较长的字母数字的字符串。你将需要此信息进行下一步。\n\n## 14.3 制作基于 Redis 的索引\n\n在本书的仓库中，你将找到此练习的源文件：\n\n+   `JedisMaker.java`包含连接到 Redis 服务器并运行几个 Jedis 方法的示例代码。\n+   `JedisIndex.java`包含此练习的起始代码。\n+   `JedisIndexTest.java`包含`JedisIndex`的测试代码。\n+   `WikiFetcher.java`包含我们在以前的练习中看到的代码，用于阅读网页并使用`jsoup`进行解析。\n\n你还将需要这些文件，你在以前的练习中碰到过：\n\n`Index.java`使用 Java 数据结构实现索引。\n`TermCounter.java`表示从检索项到其频率的映射。\n`WikiNodeIterable.java`迭代`jsoup`生成的 DOM 树中的节点。\n\n如果你有这些文件的有效版本，你可以使用它们进行此练习。如果你没有进行以前的练习，或者你对你的解决方案毫无信心，则可以从`solutions `文件夹复制我的解决方案。\n\n第一步是使用 Jedis 连接到你的 Redis 服务器。`JedisMaker.java`展示了如何实现。它从文件读取你的 Redis 服务器的信息，连接到它并使用你的密码登录，然后返回一个可用于执行 Redis 操作的 Jedis 对象。\n\n\n如果你打开`JedisMaker.java`，你应该看到`JedisMaker`类，它是一个帮助类，它提供静态方法`make`，它创建一个 Jedis 对象。一旦该对象认证完毕，你可以使用它来与你的 Redis 数据库进行通信。\n\n`JedisMaker`从名为`redis_url.txt`的文件读取你的 Redis 服务器信息，你应该放在目录`src/resources`中：\n\n+   使用文本编辑器创建并编辑`ThinkDataStructures/code/src/resources/redis_url.txt`。\n+   粘贴服务器的 URL。如果你使用的是 RedisToGo，则 URL 将如下所示：\n    ```\n    redis://redistogo:1234567feedfacebeefa1e1234567@dory.redistogo.com:10534\n    ```\n\n因为此文件包含你的 Redis 服务器的密码，你不应将此文件放在公共仓库中。为了帮助你避免意外避免这种情况，仓库包含`.gitignore`文件，使文件难以（但不是不可能）放入你的仓库。\n\n现在运行`ant build`来编译源文件，以及`ant JedisMaker`来运行`main`中的示例代码：\n\n```java\n    public static void main(String[] args) {\n\n        Jedis jedis = make();\n        \n        // String\n        jedis.set(\"mykey\", \"myvalue\");\n        String value = jedis.get(\"mykey\");\n        System.out.println(\"Got value: \" + value);\n        \n        // Set\n        jedis.sadd(\"myset\", \"element1\", \"element2\", \"element3\");\n        System.out.println(\"element2 is member: \" + \n                           jedis.sismember(\"myset\", \"element2\"));\n        \n        // List\n        jedis.rpush(\"mylist\", \"element1\", \"element2\", \"element3\");\n        System.out.println(\"element at index 1: \" + \n                           jedis.lindex(\"mylist\", 1));\n        \n        // Hash\n        jedis.hset(\"myhash\", \"word1\", Integer.toString(2));\n        jedis.hincrBy(\"myhash\", \"word2\", 1);\n        System.out.println(\"frequency of word1: \" + \n                           jedis.hget(\"myhash\", \"word1\"));\n        System.out.println(\"frequency of word1: \" + \n                            jedis.hget(\"myhash\", \"word2\"));\n        \n        jedis.close();\n    }\n```\n\n这个示例展示了数据类型和方法，你在这个练习中最可能使用它们。当你运行它时，输出应该是：\n\n```\nGot value: myvalue\nelement2 is member: true\nelement at index 1: element2\nfrequency of word1: 2\nfrequency of word2: 1\n```\n\n下一节中我会解释代码的工作原理。\n\n## 14.4 Redis 数据类型\n\n\nRedis 基本上是一个从键到值的映射，键是字符串，值可以是字符串，也可以是几种数据类型之一。最基本的 Redis 数据类型是字符串。我将用斜体书写 Redis 类型，来区别于 Java 类型。\n\n为了向数据库添加一个字符串，请使用`jedis.set`，类似于`Map.put`; 参数是新的键和相应的值。为了查找一个键并获取其值，请使用`jedis.get`：\n\n```java\n        jedis.set(\"mykey\", \"myvalue\");\n        String value = jedis.get(\"mykey\");\n```\n\n在这个例子中，键是`\"mykey\"`，值是`\"myvalue\"`。\n\nRedis 提供了一个集合结构，类似于 Java 的`Set<String>`。为了向 Redis 集合添加元素，你可以选择一个键来标识集合，然后使用`jedis.sadd`：\n\n```java\n        jedis.sadd(\"myset\", \"element1\", \"element2\", \"element3\");\n        boolean flag = jedis.sismember(\"myset\", \"element2\");\n```\n\n你不必用单独的步骤来创建集合。如果不存在，Redis 会创建它。在这种情况下，它会创建一个名为`myset`的集合，包含三个元素。\n\n`jedis.sismember`方法检查元素是否在一个集合中。添加元素和检查成员是常数时间的操作。\n\n\nRedis 还提供了一个列表结构，类似于 Java 的`List<String>`。`jedis.rpush`方法在末尾（右端）向列表添加元素：\n\n```java\n        jedis.rpush(\"mylist\", \"element1\", \"element2\", \"element3\");\n        String element = jedis.lindex(\"mylist\", 1);\n```\n\n同样，你不必在开始添加元素之前创建结构。此示例创建了一个名为`mylist`的列表，其中包含三个元素。\n\n`jedis.lindex`方法使用整数索引，并返回列表中指定的元素。添加和访问元素是常数时间的操作。\n\n最后，Redis 提供了一个哈希结构，类似于 Java 的`Map<String, String>`。`jedis.hset`方法为哈希表添加新条目：\n\n```java\n        jedis.hset(\"myhash\", \"word1\", Integer.toString(2));\n        String value = jedis.hget(\"myhash\", \"word1\");\n```\n\n此示例创建一个名为的`myhash`哈希表，其中包含一个条目，该条目从将键`word1`映射到值`\"2\"`。\n\n键和值都是字符串，所以如果我们要存储`Integer`，在我们调用`hset`之前，我们必须将它转换为`String`。当我们使用`hget`查找值时，结果是`String`，所以我们可能必须将其转换回`Integer`。\n\n\n使用 Redis 的哈希表可能会令人困惑，因为我们使用一个键来标识我们想要的哈希表，然后用另一个键标识哈希表中的值。在 Redis 的上下文中，第二个键被称为“字段”，这可能有助于保持清晰。所以类似`myhash`的“键”标志一个特定的哈希表，然后类似`word1`的“字段”标识一个哈希表中的值。\n\n对于许多应用程序，Redis 哈希表中的值是整数，所以 Redis 提供了一些特殊的方法，比如`hincrby`将值作为数字来处理：\n\n```java\n        jedis.hincrBy(\"myhash\", \"word2\", 1);\n```\n\n这个方法访问`myhash`，获取`word2`的当前值（如果不存在则为`0`），将其递增`1`，并将结果写回哈希表。\n\n在哈希表中，设置，获取和递增条目是常数时间的操作。\n\n你可以在 <http://thinkdast.com/redistypes> 上阅读 Redis 数据类型的更多信息。\n\n## 14.5 练习 11\n\n这个时候，你可以获取一些信息，你需要使用它们来创建搜索引擎的索引，它将结果储存在 Redis 数据库中。\n\n\n现在运行`ant JedisIndexTest`。它应该失败，因为你有一些工作要做！\n\n`JedisIndexTest`测试了这些方法：\n\n+   `JedisIndex`，这是构造器，它接受`Jedis`对象作为参数。\n+   `indexPage`，它将一个网页添加到索引中；它需要一个`StringURL`和一个`jsoup Elements`对象，该对象包含应该建立索引的页面元素。\n+   `getCounts`，它接收检索词，并返回`Map<String, Integer>`，包含检索词到它在页面上的出现次数的映射。\n\n以下是如何使用这些方法的示例：\n\n```java\n        WikiFetcher wf = new WikiFetcher();\n        String url1 = \n            \"http://en.wikipedia.org/wiki/Java_(programming_language)\";\n        Elements paragraphs = wf.readWikipedia(url1);\n\n        Jedis jedis = JedisMaker.make();\n        JedisIndex index = new JedisIndex(jedis);\n        index.indexPage(url1, paragraphs);\n        Map<String, Integer> map = index.getCounts(\"the\");\n```\n\n如果我们在结果`map`中查看`url1`，我们应该得到`339`，这是 Java 维基百科页面（即我们保存的版本）中，`the`出现的次数。\n\n如果我们再次索引相同的页面，新的结果将替换旧的结果。\n\n将数据结构从 Java 翻译成 Redis 的一个建议是：记住 Redis 数据库中的每个对象都以唯一的键标识，它是一个字符串。如果同一数据库中有两种对象，则可能需要向键添加前缀来区分它们。例如，在我们的解决方案中，我们有两种对象：\n\n+   我们将`URLSet`定义为 Redis 集合，它包含`URL`，`URL`又包含给定检索词。每个`URLSet`的键的起始是`\"URLSet:\"`，所以要获取包含单词`the`的 URL，我们使用键`\"URLSet:the\"`来访问该集合。\n+   我们将`TermCounter`定义为 Redis 哈希表，将出现在页面上的每个检索词映射到它的出现次数。`TermCounter`每个键的开头都以`\"TermCounter:\"`开头，以我们正在查找的页面的 URL 结尾。\n\n在我的实现中，每个检索词都有一个`URLSet`，每个索引页面都有一个`TermCounter`。我提供两个辅助方法，`urlSetKey`和`termCounterKey`来组装这些键。\n\n## 14.6 更多建议（如果你需要的话）\n\n到了这里，你拥有了完成练习所需的所有信息，所以如果准备好了就可以开始了。但是我有几个建议，你可能想先阅读它：\n\n+   对于这个练习，我提供的指导比以前的练习少。你必须做出一些设计决策；特别是，你将必须弄清楚如何将问题分解成，你可以一次性测试的部分，然后将这些部分组合成一个完整的解决方案。如果你尝试一次写出整个项目，而不测试较小的部分，调试可能需要很长时间。\n+   使用持久性数据的挑战之一是它是持久的。存储在数据库中的结构可能会在每次运行程序时发生更改。如果你弄乱了数据库，你将不得不修复它或重新开始，然后才能继续。为了帮助你控制住自己，我提供的方法叫`deleteURLSets`，`deleteTermCounters`和`deleteAllKeys`，你可以用它来清理数据库，并重新开始。你也可以使用`printIndex`来打印索引的内容。\n+   每次调用 Jedis 的方法时，你的客户端会向服务器发送一条消息，然后服务器执行你请求的操作并发回消息。如果执行许多小操作，可能需要很长时间。你可以通过将一系列操作分组为一个`Transaction`，来提高性能。\n\n例如，这是一个简单的`deleteAllKeys`版本：\n\n```java\n    public void deleteAllKeys() {\n        Set<String> keys = jedis.keys(\"*\");\n        for (String key: keys) {\n            jedis.del(key);\n        }\n    }\n```\n\n每次调用`del`时，都需要从客户端到服务器的双向通信。如果索引包含多个页面，则该方法需要很长时间来执行。我们可以使用`Transaction`对象来加速：\n\n```java\n    public void deleteAllKeys() {\n        Set<String> keys = jedis.keys(\"*\");\n        Transaction t = jedis.multi();\n        for (String key: keys) {\n            t.del(key);\n        }\n        t.exec();\n    }\n```\n\n`jedis.multi`返回一个`Transaction`对象，它提供`Jedis`对象的所有方法。但是当你调用`Transaction`的方法时，它不会立即执行该操作，并且不与服务器通信。在你调用`exec`之前，它会保存一批操作。然后它将所有保存的操作同时发送到服务器，这通常要快得多。\n\n## 14.7 几个设计提示\n\n现在你真的拥有了你需要的所有信息；你应该开始完成练习。但是如果你卡住了，或者如果你真的不知道如何开始，你可以再来一些提示。\n\n在运行测试代码之前，不要阅读以下内容，尝试一些基本的 Redis 命令，并在`JedisIndex.java`中编写几个方法。\n\n好的，如果你真的卡住了，这里有一些你可能想要处理的方法：\n\n```java\n    /**\n     * 向检索词相关的集合中添加 URL\n     */\n    public void add(String term, TermCounter tc) {}\n\n    /**\n     * 查找检索词并返回 URL 集合\n     */\n    public Set<String> getURLs(String term) {}\n\n    /**\n     * 返回检索词出现在给定 URL 中的次数\n     */\n    public Integer getCount(String url, String term) {}\n\n    /**\n     * 将 TermCounter 的内容存入 Redis\n     */\n    public List<Object> pushTermCounterToRedis(TermCounter tc) {}\n```\n\n这些是我在解决方案中使用的方法，但它们绝对不是将项目分解的唯一方法。所以如果他们有帮助，请接受这些建议，但是如果没有，请忽略它们。\n\n对于每种方法，请考虑首先编写测试。当你弄清楚如何测试一个方法时，你经常会了解如何编写它。\n\n祝你好运！\n"
  },
  {
    "path": "docs/think-dast-zh/15.md",
    "content": "# 第十五章 爬取维基百科\n\n> 原文：[Chapter 15  Crawling Wikipedia](http://greenteapress.com/thinkdast/html/thinkdast016.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n在本章中，我展示了上一个练习的解决方案，并分析了 Web 索引算法的性能。然后我们构建一个简单的 Web 爬虫。\n\n## 15.1 基于 Redis 的索引器\n\n在我的解决方案中，我们在 Redis 中存储两种结构：\n\n+   对于每个检索词，我们有一个`URLSet`，它是一个 Redis 集合，包含检索词的 URL。\n+   对于每个网址，我们有一个`TermCounter`，这是一个 Redis 哈希表，将每个检索词映射到它出现的次数。\n\n我们在上一章讨论了这些数据类型。你还可以在 <http://thinkdast.com/redistypes> 上阅读 Redis `Set和`Hash`的信息\n\n在`JedisIndex`中，我提供了一个方法，它可以接受一个检索词并返回 Redis 中它的`URLSet`的键：\n\n```java\nprivate String urlSetKey(String term) {\n    return \"URLSet:\" + term;\n}\n```\n\n以及一个方法，接受 URL 并返回 Redis 中它的`TermCounter`的键。\n\n```java\nprivate String termCounterKey(String url) {\n    return \"TermCounter:\" + url;\n}\n```\n\n这里是`indexPage`的实现。\n\n```java\npublic void indexPage(String url, Elements paragraphs) {\n    System.out.println(\"Indexing \" + url);\n\n    // make a TermCounter and count the terms in the paragraphs\n    TermCounter tc = new TermCounter(url);\n    tc.processElements(paragraphs);\n\n    // push the contents of the TermCounter to Redis\n    pushTermCounterToRedis(tc);\n}\n```\n\n为了索引页面，我们：\n\n+   为页面内容创建一个 Java 的`TermCounter`，使用上一个练习中的代码。\n+   将`TermCounter`的内容推送到 Redis。\n\n以下是将`TermCounter`的内容推送到 Redis 的新代码：\n\n```java\npublic List<Object> pushTermCounterToRedis(TermCounter tc) {\n    Transaction t = jedis.multi();\n\n    String url = tc.getLabel();\n    String hashname = termCounterKey(url);\n\n    // if this page has already been indexed, delete the old hash\n    t.del(hashname);\n\n    // for each term, add an entry in the TermCounter and a new\n    // member of the index\n    for (String term: tc.keySet()) {\n        Integer count = tc.get(term);\n        t.hset(hashname, term, count.toString());\n        t.sadd(urlSetKey(term), url);\n    }\n    List<Object> res = t.exec();\n    return res;\n}\n```\n\n该方法使用`Transaction`来收集操作，并将它们一次性发送到服务器，这比发送一系列较小操作要快得多。\n\n它遍历`TermCounter`中的检索词。对于每一个，它：\n\n+   在 Redis 上寻找或者创建`TermCounter`，然后为新的检索词添加字段。\n+   在 Redis 上寻找或创建`URLSet`，然后添加当前的 URL。\n\n如果页面已被索引，则`TermCounter`在推送新内容之前删除旧页面 。\n\n新的页面的索引就是这样。\n\n\n练习的第二部分要求你编写`getCounts`，它需要一个检索词，并从该词出现的每个网址返回一个映射。这是我的解决方案：\n\n```java\n    public Map<String, Integer> getCounts(String term) {\n        Map<String, Integer> map = new HashMap<String, Integer>();\n        Set<String> urls = getURLs(term);\n        for (String url: urls) {\n            Integer count = getCount(url, term);\n            map.put(url, count);\n        }\n        return map;\n    }\n```\n\n此方法使用两种辅助方法：\n\n+   `getURLs`接受检索词并返回该字词出现的网址集合。\n+   `getCount`接受 URL 和检索词，并返回该检索词在给定 URL 处显示的次数。\n\n以下是实现：\n\n```java\n    public Set<String> getURLs(String term) {\n        Set<String> set = jedis.smembers(urlSetKey(term));\n        return set;\n    }\n\n    public Integer getCount(String url, String term) {\n        String redisKey = termCounterKey(url);\n        String count = jedis.hget(redisKey, term);\n        return new Integer(count);\n    }\n```\n\n由于我们设计索引的方式，这些方法简单而高效。\n\n## 15.2 查找的分析\n\n假设我们索引了`N`个页面，并发现了`M`个唯一的检索词。检索词的查询需要多长时间？在继续之前，先考虑一下你的答案。\n\n要查找一个检索词，我们调用`getCounts`，其中：\n\n+   创建映射。\n+   调用`getURLs`来获取 URL 的集合。\n+   对于集合中的每个 URL，调用`getCount`并将条目添加到`HashMap`。\n\n`getURLs`所需时间与包含检索词的网址数成正比。对于罕见的检索词，这可能是一个很小的数字，但是对于常见检索词，它可能和`N`一样大。\n\n在循环中，我们调用了`getCount`，它在 Redis 上寻找`TermCounter`，查找一个检索词，并向`HashMap`添加一个条目。那些都是常数时间的操作，所以在最坏的情况下，`getCounts`的整体复杂度是`O(N)`。然而实际上，运行时间正比于包含检索词的页面数量，通常比`N`小得多。\n\n\n这个算法根据复杂性是有效的，但是它非常慢，因为它向 Redis 发送了许多较小的操作。你可以使用`Transaction`来加快速度 。你可能留作一个练习，或者你可以在`RedisIndex.java`中查看我的解决方案。\n\n## 15.3 索引的分析\n\n使用我们设计的数据结构，页面的索引需要多长时间？再次考虑你的答案，然后再继续。\n\n为了索引页面，我们遍历其 DOM 树，找到所有`TextNode`对象，并将字符串拆分成检索词。这一切都与页面上的单词数成正比。\n\n\n对于每个检索词，我们在`HashMap`中增加一个计数器，这是一个常数时间的操作。所以创建`TermCounter`的所需时间与页面上的单词数成正比。\n\n\n将`TermCounter`推送到 Redis ，需要删除`TermCounter`，对于唯一检索词的数量是线性的。那么对于每个检索词，我们必须：\n\n+   向`URLSet`添加元素，并且\n+   向 Redis`TermCounter`添加元素。\n\n这两个都是常数时间的操作，所以推送`TermCounter`的总时间对于唯一检索词的数量是线性的。\n\n总之，`TermCounter`的创建与页面上的单词数成正比。向 Redis 推送`TermCounter`与唯一检索词的数量成正比。\n\n\n由于页面上的单词数量通常超过唯一检索词的数量，因此整体复杂度与页面上的单词数成正比。理论上，一个页面可能包含索引中的所有检索词，因此最坏的情况是`O(M)`，但实际上我们并不期待看到更糟糕的情况。\n\n这个分析提出了一种提高效率的方法：我们应该避免索引很常见的词语。首先，他们占用了大量的时间和空间，因为它们出现在几乎每一个`URLSet`和`TermCounter`中。此外，它们不是很有用，因为它们不能帮助识别相关页面。\n\n大多数搜索引擎避免索引常用单词，这在本文中称为停止词（<http://thinkdast.com/stopword>）。\n\n## 15.4 图的遍历\n\n如果你在第七章中完成了“到达哲学”练习，你已经有了一个程序，它读取维基百科页面，找到第一个链接，使用链接加载下一页，然后重复。这个程序是一种专用的爬虫，但是当人们说“网络爬虫”时，他们通常意味着一个程序：\n\n加载起始页面并对内容进行索引，\n查找页面上的所有链接，并将链接的 URL 添加到集合中\n通过收集，加载和索引页面，以及添加新的 URL，来按照它的方式工作。\n如果它找到已经被索引的 URL，会跳过它。\n\n你可以将 Web 视为图，其中每个页面都是一个节点，每个链接都是从一个节点到另一个节点的有向边。如果你不熟悉图，可以阅读 <http://thinkdast.com/graph>。\n\n从源节点开始，爬虫程序遍历该图，访问每个可达节点一次。\n\n\n我们用于存储 URL 的集合决定了爬虫程序执行哪种遍历：\n\n+   如果它是先进先出（FIFO）的队列，则爬虫程序将执行广度优先遍历。\n+   如果它是后进先出（LIFO）的栈，则爬虫程序将执行深度优先遍历。\n+   更通常来说，集合中的条目可能具有优先级。例如，我们可能希望对尚未编入索引的页面给予较高的优先级。\n\n你可以在 <http://thinkdast.com/graphtrav> 上阅读图的遍历的更多信息 。\n\n## 15.5 练习 12\n\n现在是时候写爬虫了。在本书的仓库中，你将找到此练习的源文件：\n\n+   `WikiCrawler.java`，包含你的爬虫的其实代码。\n+   `WikiCrawlerTest.java`，包含`WikiCrawler`的测试代码。\n+   `JedisIndex.java`，这是我以前的练习的解决方案。\n\n你还需要一些我们以前练习中使用过的辅助类：\n\n+   `JedisMaker.java`\n+   `WikiFetcher.java`\n+   `TermCounter.java`\n+   `WikiNodeIterable.java`\n\n在运行`JedisMaker`之前，你必须提供一个文件，关于你的 Redis 服务器信息。如果你在上一个练习中这样做，你应该全部配置好了。否则，你可以在 14.3 节中找到说明。\n\n运行`ant build`来编译源文件，然后运行`ant JedisMaker`来确保它配置为连接到你的 Redis 服务器。\n\n现在运行`ant WikiCrawlerTest`。它应该失败，因为你有工作要做！\n\n这是我提供的`WikiCrawler`类的起始：\n\n```java\npublic class WikiCrawler {\n\n    public final String source;\n    private JedisIndex index;\n    private Queue<String> queue = new LinkedList<String>();\n    final static WikiFetcher wf = new WikiFetcher();\n\n    public WikiCrawler(String source, JedisIndex index) {\n        this.source = source;\n        this.index = index;\n        queue.offer(source);\n    }\n\n    public int queueSize() {\n        return queue.size();\n    }\n```\n\n实例变量是：\n\n+   `source`是我们开始抓取的网址。\n+   `index`是`JedisIndex`，结果应该放进这里。\n+   `queue`是`LinkedList`，这里面我们跟踪已发现但尚未编入索引的网址。\n+   `wf`是`WikiFetcher`，我们用来读取和解析网页。\n\n你的工作是填写`crawl`。这是原型：\n\n```java\npublic String crawl(boolean testing) throws IOException {}\n```\n\n当这个方法在`WikiCrawlerTest`中调用时，`testing`参数为`true`，否则为`false`。\n\n如果`testing`是`true`，`crawl`方法应该：\n\n+   以 FIFO 的顺序从队列中选择并移除一个 URL。\n+   使用`WikiFetcher.readWikipedia`读取页面的内容，它读取仓库中包含的，页面的缓存副本来进行测试（如果维基百科的版本更改，则避免出现问题）。\n+   它应该索引页面，而不管它们是否已经被编入索引。\n+   它应该找到页面上的所有内部链接，并按他们出现的顺序将它们添加到队列中。“内部链接”是指其他维基百科页面的链接。\n+   它应该返回其索引的页面的 URL。\n\n如果`testing`是`false`，这个方法应该：\n\n+   以 FIFO 的顺序从队列中选择并移除一个 URL。\n+   如果 URL 已经被编入索引，它不应该再次索引，并应该返回`null`。\n+   否则它应该使用`WikiFetcher.fetchWikipedia`读取页面内容，从 Web 中读取当前内容。\n+   然后，它应该对页面进行索引，将链接添加到队列，并返回其索引的页面的 URL。\n\n`WikiCrawlerTest`加载具有大约`200`个链接的队列，然后调用`crawl`三次。每次调用后，它将检查队列的返回值和新长度。\n\n当你的爬虫按规定工作时，此测试应通过。祝你好运！\n"
  },
  {
    "path": "docs/think-dast-zh/16.md",
    "content": "# 第十六章 布尔搜索\n\n> 原文：[Chapter 16  Boolean search](http://greenteapress.com/thinkdast/html/thinkdast017.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n在本章中，我展示了上一个练习的解决方案。然后，你将编写代码来组合多个搜索结果，并按照它与检索词的相关性进行排序。\n\n## 16.1 爬虫的答案\n\n首先，我们来解决上一个练习。我提供了一个`WikiCrawler`的大纲；你的工作是填写`crawl`。作为一个提醒，这里是`WikiCrawler`类中的字段：\n\n```java\npublic class WikiCrawler {\n    // keeps track of where we started\n    private final String source;\n\n    // the index where the results go\n    private JedisIndex index;\n\n    // queue of URLs to be indexed\n    private Queue<String> queue = new LinkedList<String>();\n\n    // fetcher used to get pages from Wikipedia\n    final static WikiFetcher wf = new WikiFetcher();\n}\n```\n\n当我们创建`WikiCrawler`时，我们传入`source`和 index。最初`queue`只包含一个元素，`source`。\n\n注意，`queue`的实现是`LinkedList`，所以我们可以在末尾添加元素，并从开头删除它们 - 以常数时间。通过将`LinkedList`对象赋给`Queue`变量，我们将使用的方法限制在`Queue`接口中；具体来说，我们将使用`offer`添加元素，以及`poll`来删除它们。\n\n这是我的`WikiCrawler.crawl`的实现：\n\n```java\n    public String crawl(boolean testing) throws IOException {\n        if (queue.isEmpty()) {\n            return null;\n        }\n        String url = queue.poll();\n        System.out.println(\"Crawling \" + url);\n\n        if (testing==false && index.isIndexed(url)) {\n            System.out.println(\"Already indexed.\");\n            return null;\n        }\n\n        Elements paragraphs;\n        if (testing) {\n            paragraphs = wf.readWikipedia(url);\n        } else {\n            paragraphs = wf.fetchWikipedia(url);\n        }\n        index.indexPage(url, paragraphs);\n        queueInternalLinks(paragraphs);\n        return url;\n    }\n```\n\n这个方法的大部分复杂性是使其易于测试。这是它的逻辑：\n\n+   如果队列为空，则返回`null`来表明它没有索引页面。\n+   否则，它将从队列中删除并存储下一个 URL。\n+   如果 URL 已经被索引，`crawl`不会再次对其进行索引，除非它处于测试模式。\n+   接下来，它读取页面的内容：如果它处于测试模式，它从文件读取；否则它从 Web 读取。\n+   它将页面索引。\n+   它解析页面并向队列添加内部链接。\n+   最后，它返回索引的页面的 URL。\n\n我在 15.1 节展示了`Index.indexPage`的一个实现。所以唯一的新方法是`WikiCrawler.queueInternalLinks`。\n\n我用不同的参数编写了这个方法的两个版本：一个是`Elements`对象，包含每个段落的 DOM 树，另一个是`Element`对象，包含大部分段落。\n\n\n第一个版本只是循环遍历段落。第二个版本是实际的逻辑。\n\n```java\n    void queueInternalLinks(Elements paragraphs) {\n        for (Element paragraph: paragraphs) {\n            queueInternalLinks(paragraph);\n        }\n    }\n\n    private void queueInternalLinks(Element paragraph) {\n        Elements elts = paragraph.select(\"a[href]\");\n        for (Element elt: elts) {\n            String relURL = elt.attr(\"href\");\n\n            if (relURL.startsWith(\"/wiki/\")) {\n                String absURL = elt.attr(\"abs:href\");\n                queue.offer(absURL);\n            }\n        }\n    }\n```\n\n要确定链接是否为“内部”链接，我们检查 URL 是否以`/wiki/`开头。这可能包括我们不想索引的一些页面，如有关维基百科的元页面。它可能会排除我们想要的一些页面，例如非英语语言页面的链接。但是，这个简单的测试足以起步了。\n\n这就是它的一切。这个练习没有很多新的材料；这主要是一个机会，把这些作品组装到一起。\n\n## 16.2 信息检索\n\n这个项目的下一个阶段是实现一个搜索工具。我们需要的部分包括：\n\n+   一个界面，其中用户可以提供检索词并查看结果。\n+   一种查找机制，它接收每个检索词并返回包含它的页面。\n+   用于组合来自多个检索词的搜索结果的机制。\n+   对搜索结果打分和排序的算法。\n\n用于这样的过程的通用术语是“信息检索”，你可以在 <http://thinkdast.com/infret> 上阅读更多信息 。\n\n在本练习中，我们将重点介绍步骤 3 和 4 。我们已经构建了一个 2 的简单的版本。如果你有兴趣构建 Web 应用程序，则可以考虑完成步骤 1。\n\n## 16.3 布尔搜索\n\n大多数搜索引擎可以执行“布尔搜索”，这意味着你可以使用布尔逻辑来组合来自多个检索词的结果。例如：\n\n+   搜索“java + 编程”（加号可省略）可能只返回包含两个检索词：“java”和“编程”的页面。\n+   “java OR 编程”可能会返回包含任一检索词但不一定同时出现的页面。\n+   “java -印度尼西亚”可能返回包含“java”，不包含“印度尼西亚”的页面。\n\n包含检索词和运算符的表达式称为“查询”。\n\n当应用给搜索结果时，布尔操作符`+`，`OR`和`-`对应于集合操作 交，并和差。例如，假设\n\n+   `s1`是包含“java”的页面集，\n+   `s2`是包含“编程”的页面集，以及\n+   `s3`是包含“印度尼西亚”的页面集。\n\n在这种情况下：\n\n+   `s1`和`s2`的交集是含有“java”和“编程”的页面集。\n+   `s1`和`s2`的并集是含有“java”或“编程”的页面集。\n+   `s1`与`s2`的差集是含有“java”而不含有“印度尼西亚”的页面集。\n\n在下一节中，你将编写实现这些操作的方法。\n\n## 16.4 练习 13\n\n在本书的仓库中，你将找到此练习的源文件：\n+   \n+   `WikiSearch.java`，它定义了一个对象，包含搜索结果并对其执行操作。\n+   `WikiSearchTest.java`，它包含`WikiSearch`的测试代码。\n+   `Card.java`，它演示了如何使用`java.util.Collections`的`sort`方法。\n\n你还将找到我们以前练习中使用过的一些辅助类。\n\n这是`WikiSearch`类定义的起始：\n\n```java\npublic class WikiSearch {\n\n    // map from URLs that contain the term(s) to relevance score\n    private Map<String, Integer> map;\n\n    public WikiSearch(Map<String, Integer> map) {\n        this.map = map;\n    }\n\n    public Integer getRelevance(String url) {\n        Integer relevance = map.get(url);\n        return relevance==null ? 0: relevance;\n    }\n}\n```\n\n`WikiSearch`对象包含 URL 到它们的相关性分数的映射。在信息检索的上下文中，“相关性分数”用于表示页面多么满足从查询推断出的用户需求。相关性分数的构建有很多种方法，但大部分都基于“检索词频率”，它是搜索词在页面上的显示次数。一种常见的相关性分数称为 TF-IDF，代表“检索词频率 - 逆向文档频率”。你可以在 <http://thinkdast.com/tfidf> 上阅读更多信息 。\n\n你可以选择稍后实现 TF-IDF，但是我们将从一些更简单的 TF 开始：\n\n+   如果查询包含单个检索词，页面的相关性就是其词频；也就是说该词在页面上出现的次数。\n+   对于具有多个检索词的查询，页面的相关性是检索词频率的总和；也就是说，任何检索词出现的总次数。\n\n现在你准备开始练习了。运行`ant build`来编译源文件，然后运行 `ant WikiSearchTest`。像往常一样，它应该失败，因为你有工作要做。\n\n在`WikiSearch.java`中，填充的`and`，`or`以及`minus`的主体，使相关测试通过。你不必担心`testSort`。\n\n\n你可以运行`WikiSearchTest`而不使用`Jedis`，因为它不依赖于 Redis 数据库中的索引。但是，如果要对索引运行查询，则必须向文件提供有关`Redis`服务器的信息。详见 14.3 节。\n\n\n运行`ant JedisMaker`来确保它配置为连接到你的 Redis 服务器。然后运行`WikiSearch`，它打印来自三个查询的结果：\n\n+   “java”\n+   “programming”\n+   “java AND programming”\n\n最初的结果不按照特定的顺序，因为`WikiSearch.sort`是不完整的。\n\n填充`sort`的主体，使结果以递增的相关顺序返回。我建议你使用`java.util.Collections`提供的`sort`方法，它可以排序任何种类的`List`。你可以阅读 <http://thinkdast.com/collections> 上的文档 。\n\n有两个`sort`版本：\n\n+   单参数版本接受列表并使用它的`compareTo`方法对元素进行排序，因此元素必须是`Comparable`。\n+   双参数版本接受任何对象类型的列表和一个`Comparator`，它是一个提供`compare`方法的对象，用于比较元素。\n\n如果你不熟悉`Comparable`和`Comparator`接口，我将在下一节中解释它们。\n\n## 16.5 `Comparable`和`Comparator`\n\n本书的仓库包含了`Card.java`，它演示了两个方式来排序`Card`对象的列表。这里是类定义的起始：\n\n```java\npublic class Card implements Comparable<Card> {\n\n    private final int rank;\n    private final int suit;\n\n    public Card(int rank, int suit) {\n        this.rank = rank;\n        this.suit = suit;\n    }\n```\n\n`Card`对象拥有两个整形字段，`rank`和`suit`。`Card`实现了`Comparable<Card>`，也就是说它提供`compareTo`：\n\n```java\n    public int compareTo(Card that) {\n        if (this.suit < that.suit) {\n            return -1;\n        }\n        if (this.suit > that.suit) {\n            return 1;\n        }\n        if (this.rank < that.rank) {\n            return -1;\n        }\n        if (this.rank > that.rank) {\n            return 1;\n        }\n        return 0;\n    }\n```\n\n`compareTo`规范表明，如果`this`小于`that`，则应该返回一个负数，如果它更大，则为正数，如果它们相等则为`0`。\n\n如果使用单参数版本的`Collections.sort`，它将使用元素提供的`compareTo`方法对它们进行排序。为了演示，我们可以列出`52`张卡，如下所示：\n\n```java\n    public static List<Card> makeDeck() {\n        List<Card> cards = new ArrayList<Card>();\n        for (int suit = 0; suit <= 3; suit++) {\n            for (int rank = 1; rank <= 13; rank++) {\n                Card card = new Card(rank, suit);\n                cards.add(card);\n            }\n        }\n        return cards;\n    }\n```\n\n并这样排序它们：\n\n```java\n        Collections.sort(cards);\n```\n\n这个版本的`sort`将元素按照所谓的“自然秩序”放置，因为它由对象本身决定。\n\n但是可以通过提供一个`Comparator`对象，来强制实现不同的排序。例如，`Card`对象的自然顺序将`Ace`视为最小的牌，但在某些纸牌游戏中，它的排名最高。我们可以定义一个`Comparator`，将`Ace`视为最大的牌，像这样：\n\n```java\n        Comparator<Card> comparator = new Comparator<Card>() {\n            @Override\n            public int compare(Card card1, Card card2) {\n                if (card1.getSuit() < card2.getSuit()) {\n                    return -1;\n                }\n                if (card1.getSuit() > card2.getSuit()) {\n                    return 1;\n                }\n                int rank1 = getRankAceHigh(card1);\n                int rank2 = getRankAceHigh(card2);\n\n                if (rank1 < rank2) {\n                    return -1;\n                }\n                if (rank1 > rank2) {\n                    return 1;\n                }\n                return 0;\n            }\n\n            private int getRankAceHigh(Card card) {\n                int rank = card.getRank();\n                if (rank == 1) {\n                    return 14;\n                } else {\n                    return rank;\n                }\n            }\n        };\n```\n\n该代码定义了一个匿名类，按需实现`compare`。然后它创建一个新定义的匿名类的实例。如果你不熟悉 Java 中的匿名类，可以在 <http://thinkdast.com/anonclass> 上阅读它们。\n\n使用这个`Comparator`，我们可以这样调用`sort`：\n\n```java\n        Collections.sort(cards, comparator);\n```\n\n\n在这个顺序中，黑桃的`Ace`是牌组上的最大的牌；梅花二是最小的。\n\n如果你想试验这个部分的代码，它们在`Card.java`中。作为一个练习，你可能打算写一个比较器，先按照`rank`，然后再按照`suit`，所以所有的`Ace`都应该在一起，所有的二也是。以此类推。\n\n## 16.6 扩展\n\n如果你完成了此练习的基本版本，你可能需要处理这些可选练习：\n\n+   请阅读 <http://thinkdast.com/tfidf> 上的 TF-IDF，并实现它。你可能需要修改`JavaIndex`来计算文档频率；也就是说，每个检索词在索引的所有页面上出现的总次数。\n+   对于具有多个检索词的查询，每个页面的总体相关性目前是每个检索词的相关性的总和。想想这个简单版本什么时候可能无法正常运行，并尝试一些替代方案。\n+   构建用户界面，允许用户输入带有布尔运算符的查询。解析查询，生成结果，然后按相关性排序，并显示评分最高的 URL。考虑生成“片段”，它显示了检索词出现在页面的哪里。如果要为用户界面制作 Web 应用程序，请考虑将 Heroku 作为简单选项，用于 开发和部署 Java Web应用程序。见 <http://thinkdast.com/heroku>。\n"
  },
  {
    "path": "docs/think-dast-zh/17.md",
    "content": "# 第十七章 排序\n\n> 原文：[Chapter 17  Sorting](http://greenteapress.com/thinkdast/html/thinkdast018.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n计算机科学领域过度痴迷于排序算法。根据 CS 学生在这个主题上花费的时间，你会认为排序算法的选择是现代软件工程的基石。当然，现实是，软件开发人员可以在很多年中，或者整个职业生涯中，不必考虑排序如何工作。对于几乎所有的应用程序，它们都使用它们使用的语言或库提供的通用算法。通常这样就行了。\n\n所以如果你跳过这一章，不了解排序算法，你仍然是一个优秀的开发人员。但是有一些原因你可能想要这样：\n\n+   尽管有绝大多数应用程序都可以使用通用算法，但你可能需要了解两种专用算法：基数排序和有界堆排序。\n+   一种排序算法，归并排序，是一个很好的教学示例，因为它演示了一个重要和实用的算法设计策略，称为“分治”。此外，当我们分析其表现时，你将了解到我们以前没有看到的增长级别，即线性对数。最后，一些最广泛使用的算法是包含归并排序的混合体。\n+   了解排序算法的另一个原因是，技术面试官喜欢询问它们。如果你想要工作，如果你能展示 CS 文化素养，就有帮助。\n\n因此，在本章中我们将分析插入排序，你将实现归并排序，我将给你讲解基数排序，你将编写有界堆排序的简单版本。\n\n## 17.1 插入排序\n\n我们将从插入排序开始，主要是因为它的描述和实现很简单。它不是很有效，但它有一些补救的特性，我们将看到它。\n\n\n我们不在这里解释算法，建议你阅读 <http://thinkdast.com/insertsort> 中的插入排序的维基百科页面 ，其中包括伪代码和动画示例。当你理解了它的思路再回来。\n\n这是 Java 中插入排序的实现：\n\n```java\npublic class ListSorter<T> {\n\n    public void insertionSort(List<T> list, Comparator<T> comparator) {\n\n        for (int i=1; i < list.size(); i++) {\n            T elt_i = list.get(i);\n            int j = i;\n            while (j > 0) {\n                T elt_j = list.get(j-1);\n                if (comparator.compare(elt_i, elt_j) >= 0) {\n                    break;\n                }\n                list.set(j, elt_j);\n                j--;\n            }\n            list.set(j, elt_i);\n        }\n    }\n}\n```\n\n我定义了一个类，`ListSorter`作为排序算法的容器。通过使用类型参数`T`，我们可以编写一个方法，它在包含任何对象类型的列表上工作。\n\n`insertionSort`需要两个参数，一个是任何类型的`List`，一个是`Comparator`，它知道如何比较类型`T`的对象。它对列表“原地”排序，这意味着它修改现有列表，不必分配任何新空间。\n\n下面的示例演示了，如何使用`Integer`的`List`对象，调用此方法：\n\n```java\n        List<Integer> list = new ArrayList<Integer>(\n            Arrays.asList(3, 5, 1, 4, 2));\n\n        Comparator<Integer> comparator = new Comparator<Integer>() {\n            @Override\n            public int compare(Integer elt1, Integer elt2) {\n                return elt1.compareTo(elt2);\n            }\n        };\n\n        ListSorter<Integer> sorter = new ListSorter<Integer>();\n        sorter.insertionSort(list, comparator);\n        System.out.println(list);\n```\n\n`insertionSort`有两个嵌套循环，所以你可能会猜到，它的运行时间是二次的。在这种情况下，一般是正确的，但你做出这个结论之前，你必须检查，每个循环的运行次数与`n`，数组的大小成正比。\n\n外部循环从`1`迭代到`list.size()`，因此对于列表的大小`n`是线性的。内循环从`i`迭代到`0`，所以在`n`中也是线性的。因此，两个循环运行的总次数是二次的。\n\n如果你不确定，这里是证明：\n\n第一次循环中，`i = 1`，内循环最多运行一次。\n第二次，`i = 2`，内循环最多运行两次。\n最后一次，`i = n - 1`，内循环最多运行`n`次。\n\n因此，内循环运行的总次数是序列`1, 2, ..., n - 1`的和，即`n(n - 1)/2`。该表达式的主项（拥有最高指数）为`n^2`。\n\n在最坏的情况下，插入排序是二次的。然而：\n\n+   如果这些元素已经有序，或者几乎这样，插入排序是线性的。具体来说，如果每个元素距离它的有序位置不超过`k`个元素，则内部循环不会运行超过`k`次，并且总运行时间是`O(kn)`。\n+   由于实现简单，开销较低；也就是，尽管运行时间是`an^2`，主项的系数`a`，也可能是小的。\n\n所以如果我们知道数组几乎是有序的，或者不是很大，插入排序可能是一个不错的选择。但是对于大数组，我们可以做得更好。其实要好很多。\n\n## 17.2 练习 14\n\n归并排序是运行时间优于二次的几种算法之一。同样，不在这里解释算法，我建议你阅读维基百科 <http://thinkdast.com/mergesort>。一旦你有了想法，反回来，你可以通过写一个实现来测试你的理解。\n\n\n在本书的仓库中，你将找到此练习的源文件：\n\n+   `ListSorter.java`\n+   `ListSorterTest.java`\n\n运行`ant build`来编译源文件，然后运行`ant ListSorterTest`。像往常一样，它应该失败，因为你有工作要做。\n\n在`ListSorter.java`中，我提供了两个方法的大纲，`mergeSortInPlace`以及`mergeSort`：\n\n```java\n    public void mergeSortInPlace(List<T> list, Comparator<T> comparator) {\n        List<T> sorted = mergeSortHelper(list, comparator);\n        list.clear();\n        list.addAll(sorted);\n    }\n\n    private List<T> mergeSort(List<T> list, Comparator<T> comparator) {\n       // TODO: fill this in!\n       return null;\n    }\n```\n\n这两种方法做同样的事情，但提供不同的接口。`mergeSort`获取一个列表，并返回一个新列表，具有升序排列的相同元素。`mergeSortInPlace`是修改现有列表的`void`方法。\n\n你的工作是填充`mergeSort`。在编写完全递归版本的合并排序之前，首先要这样：\n\n+   将列表分成两半。\n+   使用`Collections.sort`或`insertionSort`来排序这两部分。\n+   将有序的两部分合并为一个完整的有序列表中。\n\n这将给你一个机会来调试用于合并的代码，而无需处理递归方法的复杂性。\n\n接下来，添加一个边界情况（请参阅 < http://thinkdast.com/basecase> ）。如果你只提供一个列表，仅包含一个元素，则可以立即返回，因为它已经有序。或者如果列表的长度低于某个阈值，则可以使用`Collections.sort`或`insertionSort`。在进行前测试边界情况。\n\n最后，修改你的解决方案，使其进行两次递归调用来排序数组的两个部分。当你使其正常工作，`testMergeSort`和`testMergeSortInPlace`应该通过。\n\n## 17.3 归并排序的分析\n\n为了对归并排序的运行时间进行划分，对递归层级和每个层级上完成多少工作方面进行思考，是很有帮助的。假设我们从包含`n`个元素的列表开始。以下是算法的步骤：\n\n+   生成两个新数组，并将一半元素复制到每个数组中。\n+   排序两个数组。\n+   合并两个数组。\n\n图 17.1 显示了这些步骤。\n\n![](img/17-1.jpg)\n\n图 17.1：归并排序的展示，它展示了递归的一个层级。\n\n第一步复制每个元素一次，因此它是线性的。第三步也复制每个元素一次，因此它也是线性的。现在我们需要弄清楚步骤`2`的复杂性。为了做到这一点，查看不同的计算图片会有帮助，它展示了递归的层数，如图 17.2 所示。\n\n![](img/17-2.jpg)\n\n图 17.2：归并排序的展示，它展示了递归的所有层级。\n\n在顶层，我们有`1`个列表，其中包含`n`个元素。为了简单起见，我们假设`n`是`2`的幂。在下一层，有`2`个列表包含`n/2`个元素。然后是`4`个列表与`n/4`元素，以此类推，直到我们得到`n`个列表与`1`元素。\n\n在每一层，我们共有`n`个元素。在下降的过程中，我们必须将数组分成两半，这在每一层上都需要与`n`成正比的时间。在回来的路上，我们必须合并`n`个元素，这也是线性的。\n\n如果层数为`h`，算法的总工作量为`O(nh)`。那么有多少层呢？有两种方法可以考虑：\n\n+   我们用多少步，可以将`n`减半直到`1`？\n+   或者，我们用多少步，可以将`1`加倍直到`n`？\n\n第二个问题的另一种形式是“`2`的多少次方是`n`”？\n\n```\n2^h = n\n```\n\n对两边取以`2`为底的对数：\n\n```\nh = log2(n)\n```\n\n所以总时间是`O(nlogn)`。我没有纠结于对数的底，因为底不同的对数差别在于一个常数，所以所有的对数都是相同的增长级别。\n\n\n`O(nlogn)`中的算法有时被称为“线性对数”的，但大多数人只是说`n log n`。\n\n\n事实证明，`O(nlogn)`是通过元素比较的排序算法的理论下限。这意味着没有任何“比较排序”的增长级别比`n log n`好。请参见 <http://thinkdast.com/compsort>。\n\n但是我们将在下一节中看到，存在线性时间的非比较排序！\n\n## 基数排序\n\n在 2008 年美国总统竞选期间，候选人巴拉克·奥巴马在访问 Google 时，被要求进行即兴算法分析。首席执行长埃里克·施密特开玩笑地问他，“排序一百万个 32 位整数的最有效的方法”。显然有人暗中告诉了奥巴马，因为他很快就回答说：“我认为冒泡排序是错误的。”你可以在 <http://thinkdast.com/obama> 观看视频。\n\n奥巴马是对的：冒泡排序在概念上是简单的，但其运行时间是二次的; 即使在二次排序算法中，其性能也不是很好。见 <http://thinkdast.com/bubble>。\n\n\n施密特想要的答案可能是“基数排序”，这是一种非比较排序算法，如果元素的大小是有界的，例如 32 位整数或 20 个字符的字符串，它就可以工作。\n\n\n为了看看它是如何工作的，想象你有一堆索引卡，每张卡片包含三个字母的单词。以下是一个方法，可以对卡进行排序：\n\n+   根据第一个字母，将卡片放入桶中。所以以`a`开头的单词应该在一个桶中，其次是以`b`开头的单词，以此类推\n+   根据第二个字母再次将卡片放入每个桶。所以以`aa`开头的应该在一起，其次是以`ab`开头的，以此类推当然，并不是所有的桶都是满的，但是没关系。\n+   根据第三个字母再次将卡片放入每个桶。\n\n此时，每个桶包含一个元素，桶按升序排列。图  17.3 展示了三个字母的例子。\n\n![](img/17-3.jpg)\n\n图 17.3：三个字母的基数排序的例子\n\n最上面那行显示未排序的单词。第二行显示第一次遍历后的桶的样子。每个桶中的单词都以相同的字母开头。\n\n第二遍之后，每个桶中的单词以相同的两个字母开头。在第三遍之后，每个桶中只能有一个单词，并且桶是有序的。\n\n在每次遍历期间，我们遍历元素并将它们添加到桶中。只要桶允许在恒定时间内添加元素，每次遍历是线性的。\n\n遍历数量，我会称之为`w`，取决于单词的“宽度”，但不取决于单词的数量，`n`。所以增长级别是`O(wn)`，对于`n`是线性的。\n\n基数排序有许多变体，并有许多方法来实现每一个。你可以在 <http://thinkdast.com/radix> 上阅读他们的更多信息。作为一个可选的练习，请考虑编写基数排序的一个版本。\n\n## 17.5 堆排序\n\n基数排序适用于大小有界的东西，除了他之外，还有一种你可能遇到的其它专用排序算法：有界堆排序。如果你在处理非常大的数据集，你想要得到前 10 个或者前`k`个元素，其中`k`远小于`n`，它是很有用的。\n\n例如，假设你正在监视一 个Web 服务，它每天处理十亿次事务。在每一天结束时，你要汇报最大的`k`个事务（或最慢的，或者其它最 xx 的）。一个选项是存储所有事务，在一天结束时对它们进行排序，然后选择最大的`k`个。需要的时间与`nlogn`成正比，这非常慢，因为我们可能无法将十亿次交易记录在单个程序的内存中。我们必须使用“外部”排序算法。你可以在 <http://thinkdast.com/extsort> 上了解外部排序。\n\n\n使用有界堆，我们可以做得更好！以下是我们的实现方式：\n\n+   我会解释（无界）堆排序。\n+   你会实现它\n+   我将解释有界堆排序并进行分析。\n\n要了解堆排序，你必须了解堆，这是一个类似于二叉搜索树（BST）的数据结构。有一些区别：\n\n+   在 BST 中，每个节点`x`都有“BST 特性”：`x`左子树中的所有节点都小于`x`，右子树中的所有节点都大于`x`。\n+   在堆中，每个节点`x`都有“堆特性”：两个子树中的所有节点都大于`x`。\n+   堆就像平衡的 BST；当你添加或删除元素时，他们会做一些额外的工作来重新使树平衡。因此，可以使用元素的数组来有效地实现它们。\n\n> 译者注：这里先讨论最小堆。如果子树中所有节点都小于`x`，那么就是最大堆。\n\n堆中最小的元素总是在根节点，所以我们可以在常数时间内找到它。在堆中添加和删除元素需要的时间与树的高度`h`成正比。而且由于堆总是平衡的，所以`h`与`log n`成正比。你可以在 <http://thinkdast.com/heap> 上阅读更多堆的信息。\n\nJava`PriorityQueue`使用堆实现。`PriorityQueue`提供`Queue`接口中指定的方法，包括`offer`和`poll`：\n\n+   `offer`：将一个元素添加到队列中，更新堆，使每个节点都具有“堆特性”。需要`logn`的时间。\n+   `poll`：从根节点中删除队列中的最小元素，并更新堆。需要`logn`的时间。\n\n给定一个`PriorityQueue`，你可以像这样轻松地排序的`n`个元素的集合 ：\n\n+   使用`offer`，将集合的所有元素添加到`PriorityQueue`。\n+   使用`poll`从队列中删除元素并将其添加到`List`。\n\n因为`poll`返回队列中剩余的最小元素，所以元素按升序添加到`List`。这种排序方式称为堆排序 （请参阅 <http://thinkdast.com/heapsort>）。\n\n向队列中添加`n`个元素需要`nlogn`的时间。删除`n`个元素也是如此。所以堆排序的运行时间是`O(n logn)`。\n\n在本书的仓库中，你可以在`ListSorter.java`中找到`heapSort`方法的大纲。填充它，然后运行`ant ListSorterTest`来确认它可以工作。\n\n## 17.6 有界堆排序\n\n有界堆是一个限制为最多包含`k`个元素的堆。如果你有`n`个元素，你可以跟踪这个最大的`k`个元素：\n\n最初堆是空的。对于每个元素`x`：\n\n+   分支 1：如果堆不满，请添加`x`到堆中。\n+   分支 2：如果堆满了，请与堆中`x`的最小元素进行比较。如果`x`较小，它不能是最大的`k`个元素之一，所以你可以丢弃它。\n+   分支 3：如果堆满了，并且`x`大于堆中的最小元素，请从堆中删除最小的元素并添加`x`。\n\n使用顶部为最小元素的堆，我们可以跟踪最大的`k`个元素。我们来分析这个算法的性能。对于每个元素，我们执行以下操作之一：\n\n+   分支 1：将元素添加到堆是`O(log k)`。\n+   分支 2：找到堆中最小的元素是`O(1)`。\n+   分支 3：删除最小元素是`O(log k)`。添加`x`也是`O(log k)`。\n\n在最坏的情况下，如果元素按升序出现，我们总是执行分支 3。在这种情况下，处理`n`个元素的总时间是`O(n log k)`，对于`n`是线性的。\n\n在`ListSorter.java`中，你会发现一个叫做`topK`的方法的大纲，它接受一个`List`、`Comparator`和一个整数`k`。它应该按升序返回`List`的`k`个最大的元素 。填充它，然后运行`ant ListSorterTest`来确认它可以工作。\n\n## 17.7 空间复杂性\n\n到目前为止，我们已经谈到了很多运行时间的分析，但是对于许多算法，我们也关心空间。例如，归并排序的一个缺点是它会复制数据。在我们的实现中，它分配的空间总量是`O(n log n)`。通过更机智的实现，你可以将空间要求降至`O(n)`。\n\n相比之下，插入排序不会复制数据，因为它会原地排序元素。它使用临时变量来一次性比较两个元素，并使用一些其它局部变量。但它的空间使用不取决于`n`。\n\n我们的堆排序实现创建了新`PriorityQueue`，来存储元素，所以空间是`O(n)`; 但是如果你能够原地对列表排序，则可以使用`O(1)`的空间执行堆排序 。\n\n刚刚实现的有界堆栈算法的一个好处是，它只需要与`k`成正比的空间（我们要保留的元素的数量），而`k`通常比`n`小得多 。\n\n软件开发人员往往比空间更加注重运行时间，对于许多应用程序来说，这是适当的。但是对于大型数据集，空间可能同等或更加重要。例如：\n\n+   如果一个数据集不能放入一个程序的内存，那么运行时间通常会大大增加，或者根本不能运行。如果你选择一个需要较少空间的算法，并且这样可以将计算放入内存中，则可能会运行得更快。同样，使用较少空间的程序，可能会更好地利用 CPU 缓存并运行速度更快（请参阅 <http://thinkdast.com/cache>）。\n+   在同时运行多个程序的服务器上，如果可以减少每个程序所需的空间，则可以在同一台服务器上运行更多程序，从而降低硬件和能源成本。\n\n所以这些是一些原因，你应该至少了解一些算法的空间需求。\n"
  },
  {
    "path": "docs/think-dast-zh/2.md",
    "content": "# 第二章 算法分析\n\n> 原文：[Chapter 2  Analysis of Algorithms](http://greenteapress.com/thinkdast/html/thinkdast003.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n我们在前面的章节中看到，Java 提供了两种`List`接口的实现，`ArrayList`和`LinkedList`。对于一些应用，`LinkedList`更快；对于其他应用，`ArrayList`更快。\n\n要确定对于特定的应用，哪一个更好，一种方法是尝试它们，并看看它们需要多长时间。这种称为“性能分析”的方法有一些问题：\n\n+   在比较算法之前，你必须实现这两个算法。\n+   结果可能取决于你使用什么样的计算机。一种算法可能在一台机器上更好；另一个可能在不同的机器上更好。\n+   结果可能取决于问题规模或作为输入提供的数据。\n\n我们可以使用算法分析来解决这些问题中的一些问题。当它有效时，算法分析使我们可以比较算法而不必实现它们。但是我们必须做出一些假设：\n\n+   为了避免处理计算机硬件的细节，我们通常会识别构成算法的基本操作，如加法，乘法和数字比较，并计算每个算法所需的操作次数。\n+   为了避免处理输入数据的细节，最好的选择是分析我们预期输入的平均性能。如果不可能，一个常见的选择是分析最坏的情况。\n+   最后，我们必须处理一个可能性，一种算法最适合小问题，另一个算法适用于较大的问题。在这种情况下，我们通常专注于较大的问题，因为小问题的差异可能并不重要，但对于大问题，差异可能是巨大的。\n\n这种分析适用于简单的算法分类。例如，如果我们知道算法`A`的运行时间通常与输入规模成正比，即`n`，并且算法`B`通常与`n ** 2`成比例，我们预计`A`比`B`更快，至少对于`n`的较大值。\n\n大多数简单的算法只能分为几类。\n\n+   常数时间：如果运行时间不依赖于输入的大小，算法是“常数时间”。例如，如果你有一个`n`个元素的数组，并且使用下标运算符（`[]`）来访问其中一个元素，则此操作将执行相同数量的操作，而不管数组有多大。\n+   线性：如果运行时间与输入的大小成正比，则算法为“线性”的。例如，如果你计算数组的和，则必须访问`n`个元素并执行`n - 1`个添加。操作的总数（元素访问和加法）为`2 * n -1`，与`n`成正比。\n+   平方：如果运行时间与`n ** 2`成正比，算法是“平方”的。例如，假设你要检查列表中的任何元素是否多次出现。一个简单的算法是将每个元素与其他元素进行比较。如果有`n`个元素，并且每个元素与`n - 1`个其他元素进行比较，则比较的总数是`n ** 2 - n`，随着`n`增长它与`n ** 2`成正比。\n\n## 2.1 选择排序\n\n例如，这是一个简单算法的实现，叫做“选择排序”（请见 <http://thinkdast.com/selectsort>）：\n\n```java\npublic class SelectionSort {\n\n    /**\n     * Swaps the elements at indexes i and j.\n     */\n    public static void swapElements(int[] array, int i, int j) {\n        int temp = array[i];\n        array[i] = array[j];\n        array[j] = temp;\n    }\n\n    /**\n     * Finds the index of the lowest value\n     * starting from the index at start (inclusive)\n     * and going to the end of the array.\n     */\n    public static int indexLowest(int[] array, int start) {\n        int lowIndex = start;\n        for (int i = start; i < array.length; i++) {\n            if (array[i] < array[lowIndex]) {\n                lowIndex = i;\n            }\n        }\n        return lowIndex;\n    }\n\n    /**\n     * Sorts the elements (in place) using selection sort.\n     */\n    public static void selectionSort(int[] array) {\n        for (int i = 0; i < array.length; i++) {\n            int j = indexLowest(array, i);\n            swapElements(array, i, j);\n        }\n    }\n}\n```\n\n第一个方法`swapElements`交换数组的两个元素。元素的是常数时间的操作，因为如果我们知道元素的大小和第一个元素的位置，我们可以使用一个乘法和一个加法来计算任何其他元素的位置，这都是常数时间的操作。由于`swapElements`中的一切都是恒定的时间，整个方法是恒定的时间。\n\n第二个方法`indexLowest`从给定的索引`start`开始，找到数组中最小元素的索引。每次遍历循环的时候，它访问数组的两个元素并执行一次比较。由于这些都是常数时间的操作，因此我们计算什么并不重要。为了保持简单，我们来计算一下比较的数量。\n\n+   如果`start`为`0`，则`indexLowest`遍历整个数组，并且比较的总数是数组的长度，我称之为`n`。\n+   如果`start`为`1`，则比较数为`n - 1`。\n+   一般情况下，比较的次数是`n - start`，因此`indexLowest`是线性的。\n\n第三个方法`selectionSort`对数组进行排序。它从`0`循环到`n - 1`，所以循环执行了`n`次。每次调用`indexLowest`然后执行一个常数时间的操作`swapElements`。\n\n第一次`indexLowest`被调用的时候，它进行`n`次比较。第二次，它进行`n - 1`比较，依此类推。比较的总数是\n\n```\nn + n−1 + n−2 + ... + 1 + 0 \n```\n\n这个数列的和是`n(n+1)/2`，它（近似）与`n ** 2`成正比；这意味着`selectionSort`是平方的。\n\n为了得到同样的结果，我们可以将`indexLowest`看作一个嵌套循环。每次调用`indexLowest`时，操作次数与`n`成正比。我们调用它`n`次，所以操作的总数与`n ** 2`成正比。\n\n## 2.2 大 O 表示法\n\n所有常数时间算法属于称为`O(1)`的集合。所以，说一个算法是常数时间的另一个方法就是，说它是`O(1)`的。与之类似，所有线性算法属于`O(n)`，所有二次算法都属于`O(n ** 2)`。这种分类算法的方式被称为“大 O 表示法”。\n\n注意：我提供了一个大 O 符号的非专业定义。更多的数学处理请参见 <http://thinkdast.com/bigo>。\n\n这个符号提供了一个方便的方式，来编写通用的规则，关于算法在我们构造它们时的行为。例如，如果你执行线性时间算法，之后是常量算法，则总运行时间是线性的。`∈`表示“是...的成员”：\n\n```\nf ∈ O(n) && g ∈ O(1) => f + g ∈ O(n)\n```\n\n如果执行两个线性运算，则总数仍然是线性的：\n\n```\nf ∈ O(n) && g ∈ O(n) => f + g ∈ O(n)\n```\n\n事实上，如果你执行任何次数的线性运算，`k`，总数就是线性的，只要`k`是不依赖于`n`的常数。\n\n```\nf ∈ O(n) && k 是常数 => kf ∈ O(n)\n```\n\n但是，如果执行`n`次线性运算，则结果为平方：\n\n```\nf ∈ O(n) => nf ∈ O(n ** 2)\n```\n\n一般来说，我们只关心`n`的最大指数。所以如果操作总数为`2 * n + 1`，则属于`O(n)`。主要常数`2`和附加项`1`对于这种分析并不重要。与之类似，`n ** 2 + 100 * n + 1000`是`O(n ** 2)`的。不要被大的数值分心！\n\n“增长级别”是同一概念的另一个名称。增长级别是一组算法，其运行时间在同一个大 O 分类中；例如，所有线性算法都属于相同的增长级别，因为它们的运行时间为`O(n)`。\n\n在这种情况下，“级别”是一个团体，像圆桌骑士的阶级，这是一群骑士，而不是一种排队方式。因此，你可以将线性算法的阶级设想为一组勇敢，仗义，特别有效的算法。\n\n## 2.3 练习 2\n\n本章的练习是实现一个`List`，使用 Java 数组来存储元素。\n\n在本书的代码库（请参阅 0.1 节）中，你将找到你需要的源文件：\n\n+   `MyArrayList.java`包含`List`接口的部分实现。其中四个方法是不完整的；你的工作是填充他们。\n+   `MyArrayListTest.java`包含 JUnit 测试，可用于检查你的工作。\n\n你还会发现 Ant 构建文件`build.xml`。你应该可以从代码目录运行`ant MyArrayList`，来运行`MyArrayList.java`，其中包含一些简单的测试。或者你可以运行`ant MyArrayListTest`运行 JUnit 测试。\n\n当你运行测试时，其中几个应该失败。如果你检查源代码，你会发现四条 TODO 注释，表示你应该填充的方法。\n\n在开始填充缺少的方法之前，让我们来看看一些代码。这里是类定义，实例变量和构造函数。\n\n```java\npublic class MyArrayList<E> implements List<E> {\n    int size;                    // keeps track of the number of elements\n    private E[] array;           // stores the elements\n    \n    public MyArrayList() {\n        array = (E[]) new Object[10];\n        size = 0;\n    }\n}\n```\n\n正如注释所述，`size`跟踪`MyArrayList`中由多少元素，而且`array`是实际包含的元素的数组。\n\n构造函数创建一个 10 个元素的数组，这些元素最初为`null`，并且`size`设为`0`。·大多数时候，数组的长度大于`size`，所以数组中由未使用的槽。\n\nJava 的一个细节：你不能使用类型参数实例化数组；例如，这样不起作用：\n\n```\narray = new E [10];\n```\n\n要解决此限制，你必须实例化一个`Object`数组，然后进行类型转换。你可以在 <http://thinkdast.com/generics> 上阅读此问题的更多信息。\n\n接下来，我们将介绍添加元素到列表的方法：\n\n```java\npublic boolean add(E element) {\n    if (size >= array.length) {\n        // make a bigger array and copy over the elements\n        E[] bigger = (E[]) new Object[array.length * 2];\n        System.arraycopy(array, 0, bigger, 0, array.length);\n        array = bigger;\n    } \n    array[size] = element;\n    size++;\n    return true;\n}\n```\n\n如果数组中没有未使用的空间，我们必须创建一个更大的数组，并复制这些元素。然后我们可以将元素存储在数组中并递增`size`。\n\n为什么这个方法返回一个布尔值，这可能不明显，因为它似乎总是返回`true`。像之前一样，你可以在文档中找到答案：<http://thinkdast.com/colladd>。如何分析这个方法的性能也不明显。在正常情况下，它是常数时间的，但如果我们必须调整数组的大小，它是线性的。我将在 3.2 节中介绍如何处理这个问题。\n\n最后，让我们来看看`get`；之后你可以开始做这个练习了。\n\n```java\npublic T get(int index) {\n    if (index < 0 || index >= size) {\n        throw new IndexOutOfBoundsException();\n    }\n    return array[index];\n}\n```\n\n其实`get`很简单：如果索引超出范围，它会抛出异常; 否则读取并返回数组的元素。注意，它检查索引是否小于`size`，大于等于`array.length`，所以它不能访问数组的未使用的元素。\n\n在`MyArrayList.java`中，你会找到`set`的桩，像这样：\n\n```java\npublic T set(int index, T element) {\n    // TODO: fill in this method.\n    return null;\n}\n```\n\n阅读`set`的文档，在 <http://thinkdast.com/listset>，然后填充此方法的主体。如果再运行`MyArrayListTest`，`testSet`应该通过。\n\n提示：尽量避免重复索引检查的代码。\n\n你的下一个任务是填充`indexOf`。像往常一样，你应该阅读 <http://thinkdast.com/listindof> 上的文档，以便你知道应该做什么。特别要注意它应该如何处理`null`。\n\n我提供了一个辅助方法`equals`，它将数组中的元素与目标值进行比较，如果它们相等，返回`true`（并且正确处理`null`），则 返回。请注意，此方法是私有的，因为它仅在此类中使用；它不是`List`接口的一部分。\n\n完成后，`再次运行MyArrayListTest`；`testIndexOf`，以及依赖于它的其他测试现在应该通过。\n\n只剩下两个方法了，你需要完成这个练习。下一个是`add`的重载版本，它接受下标并将新值存储在给定的下标处，如果需要，移动其他元素来腾出空间。\n\n再次阅读 <http://thinkdast.com/listadd> 上的文档，编写一个实现，并运行测试进行确认。\n\n提示：避免重复扩充数组的代码。\n\n最后一个：填充`remove`的主体。文档位于 <http://thinkdast.com/listrem>。当你完成它时，所有的测试都应该通过。\n\n一旦你的实现能够工作，将其与我的比较，你可以在 <http://thinkdast.com/myarraylist> 上找到它。\n"
  },
  {
    "path": "docs/think-dast-zh/3.md",
    "content": "# 第三章 `ArrayList`\n\n> 原文：[Chapter 3  ArrayList](http://greenteapress.com/thinkdast/html/thinkdast004.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n本章一举两得：我展示了上一个练习的解法，并展示了一种使用摊销分析来划分算法的方法。\n\n## 3.1 划分`MyArrayList`的方法\n\n对于许多方法，我们不能通过测试代码来确定增长级别。例如，这里是`MyArrayList`的`get`的实现：\n\n```java\npublic E get(int index) {\n    if (index < 0 || index >= size) {\n        throw new IndexOutOfBoundsException();\n    }\n    return array[index];\n}\n```\n\n`get`中的每个东西都是常数时间的。所以`get`是常数时间，没问题。\n\n现在我们已经划分了`get`，我们可以使用它来划分`set`。这是我们以前的练习中的`set`：\n\n```java\npublic E set(int index, E element) {\n    E old = get(index);\n    array[index] = element;\n    return old;\n}\n```\n\n该解决方案的一个有些机智的部分是，它不会显式检查数组的边界；它利用`get`，如果索引无效则引发异常。\n\n`set`中的一切，包括`get`的调用都是常数时间，所以`set`也是常数时间。\n\n接下来我们来看一些线性的方法。例如，以下是我的实现`indexOf`：\n\n```java\npublic int indexOf(Object target) {\n    for (int i = 0; i<size; i++) {\n        if (equals(target, array[i])) {\n            return i;\n        }\n    }\n    return -1;\n}\n```\n\n每次在循环中，`indexOf`调用`equals`，所以我们首先要划分`equals`。这里就是：\n\n```java\nprivate boolean equals(Object target, Object element) {\n    if (target == null) {\n        return element == null;\n    } else {\n        return target.equals(element);\n    }\n}\n```\n\n此方法调用`target.equals`；这个方法的运行时间可能取决于`target`或`element`的大小，但它不依赖于该数组的大小，所以出于分析`indexOf`的目的,我们认为这是常数时间。\n\n回到之前的`indexOf`，循环中的一切都是常数时间，所以我们必须考虑的下一个问题是：循环执行多少次？\n\n如果我们幸运，我们可能会立即找到目标对象，并在测试一个元素后返回。如果我们不幸，我们可能需要测试所有的元素。平均来说，我们预计测试一半的元素，所以这种方法被认为是线性的（除了在不太可能的情况下，我们知道目标元素在数组的开头）。\n\n`remove`的分析也类似。这里是我的时间。\n\n```java\npublic E remove(int index) {\n    E element = get(index);\n    for (int i=index; i<size-1; i++) {\n        array[i] = array[i+1];\n    }\n    size--;\n    return element;\n}\n```\n\n它使用`get`，这是常数时间，然后从`index`开始遍历数组。如果我们删除列表末尾的元素，循环永远不会运行，这个方法是常数时间。如果我们删除第一个元素，我们遍历所有剩下的元素，它们是线性的。因此，这种方法同样被认为是线性的（除了在特殊情况下，我们知道元素在末尾，或到末尾距离恒定）。\n\n## 3.2 `add`的划分\n\n这里是`add`的一个版本，接受下标和元素作为参数：\n\n```java\npublic void add(int index, E element) {\n    if (index < 0 || index > size) {\n        throw new IndexOutOfBoundsException();\n    }\n    // add the element to get the resizing\n    add(element);\n    \n    // shift the other elements\n    for (int i=size-1; i>index; i--) {\n        array[i] = array[i-1];\n    }\n    // put the new one in the right place\n    array[index] = element;\n}\n```\n\n这个双参数的版本，叫做`add(int, E)`，它使用了单参数的版本，称为`add(E)`，它将新的元素放在最后。然后它将其他元素向右移动，并将新元素放在正确的位置。\n\n在我们可以划分双参数`add`之前，我们必须划分单参数`add`：\n\n```java\npublic boolean add(E element) {\n    if (size >= array.length) {\n        // make a bigger array and copy over the elements\n        E[] bigger = (E[]) new Object[array.length * 2];\n        System.arraycopy(array, 0, bigger, 0, array.length);\n        array = bigger;\n    } \n    array[size] = element;\n    size++;\n    return true;\n}\n```\n\n单参数版本很难分析。如果数组中存在未使用的空间，那么它是常数时间，但如果我们必须调整数组的大小，它是线性的，因为`System.arraycopy`所需的时间与数组的大小成正比。\n\n那么`add`是常数还是线性时间的？我们可以通过考虑一系列`n`个添加中，每次添加的平均操作次数，来分类此方法。为了简单起见，假设我们以一个有`2`个元素的空间的数组开始。\n\n+   我们第一次调用`add`时，它会在数组中找到未使用的空间，所以它存储`1`个元素。\n+   第二次，它在数组中找到未使用的空间，所以它存储`1`个元素。\n+   第三次，我们必须调整数组的大小，复制`2`个元素，并存储`1`个元素。现在数组的大小是`4`。\n+   第四次存储`1`个元素。\n+   第五次调整数组的大小，复制`4`个元素，并存储`1`个元素。现在数组的大小是`8`。\n+   接下来的`3`个添加储存`3`个元素。\n+   下一个添加复制`8`个并存储`1`个。现在的大小是`16`。\n+   接下来的`7`个添加复制了`7`个元素。\n\n以此类推，总结一下：\n\n+   `4`次添加之后，我们储存了`4`个元素，并复制了两个。\n+   `8`次添加之后，我们储存了`8`个元素，并复制了`6`个。\n+   `16`次添加之后，我们储存了`16`个元素，并复制了`14`个。\n\n现在你应该看到了规律：要执行`n`次添加，我们必须存储`n`个元素并复制`n-2`个。所以操作总数为`n + n - 2`，为`2 * n - 2`。\n\n为了得到每个添加的平均操作次数，我们将总和除以`n`；结果是`2 - 2 / n`。随着`n`变大，第二项`2 / n`变小。参考我们只关心`n`的最大指数的原则，我们可以认为`add`是常数时间的。\n\n有时线性的算法平均可能是常数时间，这似乎是奇怪的。关键是我们每次调整大小时都加倍了数组的长度。这限制了每个元素被复制的次数。否则 - 如果我们向数组的长度添加一个固定的数量，而不是乘以一个固定的数量 - 分析就不起作用。\n\n这种划分算法的方式，通过计算一系列调用中的平均时间，称为摊销分析。你可以在 <http://thinkdast.com/amort> 上阅读更多信息。重要的想法是，复制数组的额外成本是通过一系列调用展开或“摊销”的。\n\n现在，如果`add(E)`是常数时间，那么`add(int, E)`呢？调用`add(E)`后，它遍历数组的一部分并移动元素。这个循环是线性的，除了在列表末尾添加的特殊情况中。因此， `add(int, E)`是线性的。\n\n## 3.3 问题规模\n\n最后一个例子中，我们将考虑`removeAll`，这里是`MyArrayList`中的实现：\n\n```java\npublic boolean removeAll(Collection<?> collection) {\n    boolean flag = true;\n    for (Object obj: collection) {\n        flag &= remove(obj);\n    }\n    return flag;\n}\n```\n\n每次循环中，`removeAll`都调用`remove`，这是线性的。所以认为`removeAll`是二次的很诱人。但事实并非如此。\n\n在这种方法中，循环对于每个`collection`中的元素运行一次。如果`collection`包含`m`个元素，并且我们从包含`n`个元素的列表中删除，则此方法是`O(nm)`的。如果`collection`的大小可以认为是常数，`removeAll`相对于`n`是线性的。但是，如果集合的大小与`n`成正比，`removeAll`则是平方的。例如，如果`collection`总是包含`100`个或更少的元素， `removeAll`则是线性的。但是，如果`collection`通常包含的列表中的 1% 元素，`removeAll`则是平方的。\n\n当我们谈论问题规模时，我们必须小心我们正在讨论哪个大小。这个例子演示了算法分析的陷阱：对循环计数的诱人捷径。如果有一个循环，算法往往是 线性的。如果有两个循环（一个嵌套在另一个内），则该算法通常是平方的。不过要小心！你必须考虑每个循环运行多少次。如果所有循环的迭代次数与`n`成正比，你可以仅仅对循环进行计数之后离开。但是，如在这个例子中，迭代次数并不总是与`n`成正比，所以你必须考虑更多。\n\n## 3.4 链接数据结构\n\n对于下一个练习，我提供了`List`接口的部分实现，使用链表来存储元素。如果你不熟悉链表，你可以阅读 <http://thinkdast.com/linkedlist> ，但本部分会提供简要介绍。\n\n如果数据结构由对象（通常称为“节点”）组成，其中包含其他节点的引用，则它是“链接”的。在链表 中，每个节点包含列表中下一个节点的引用。其他链接结构包括树和图，其中节点可以包含多个其他节点的引用。\n\n这是一个简单节点的类定义：\n\n```java\npublic class ListNode {\n\n    public Object data;\n    public ListNode next;\n\n    public ListNode() {\n        this.data = null;\n        this.next = null;\n    }\n\n    public ListNode(Object data) {\n        this.data = data;\n        this.next = null;\n    }\n\n    public ListNode(Object data, ListNode next) {\n        this.data = data;\n        this.next = next;\n    }\n\n    public String toString() {\n        return \"ListNode(\" + data.toString() + \")\";\n    }\n}\n```\n\n该`ListNode`对象具有两个实例变量：`data`是某种类型的`Object`的引用，并且`next`是列表中下一个节点的引用。在列表中的最后一个节点中，按照惯例，`next`是`null`。\n\n`ListNode`提供了几个构造函数，可以让你为`data`和`next`提供值，或将它们初始化为默认值，`null`。\n\n你可以将每个`ListNode`看作具有单个元素的列表，但更通常，列表可以包含任意数量的节点。有几种方法可以制作新的列表。一个简单的选项是，创建一组`ListNode`对象，如下所示：\n\n```java\nListNode node1 = new ListNode(1);\nListNode node2 = new ListNode(2);\nListNode node3 = new ListNode(3);\n```\n\n之后将其链接到一起，像这样：\n\n```\nnode1.next = node2;\nnode2.next = node3;\nnode3.next = null;\n```\n\n或者，你可以创建一个节点并将其链接在一起。例如，如果要在列表开头添加一个新节点，可以这样做：\n\n```java\nListNode node0 = new ListNode(0, node1);\n```\n\n![](img/3-1.jpg)\n\n图 3.1 链表的对象图\n\n图 3.1 是一个对象图，展示了这些变量及其引用的对象。在对象图中，变量的名称出现在框内，箭头显示它们所引用的内容。对象及其类型（如ListNode和Integer）出现在框外面。\n\n## 3.5 练习 3\n\n这本书的仓库中，你会找到你需要用于这个练习的源代码：\n\n+   `MyLinkedList.java`包含`List`接口的部分实现，使用链表存储元素。\n+   `MyLinkedListTest.java`包含用于`MyLinkedList`的 JUnit 测试。\n\n运行`ant MyArrayList`来运行`MyArrayList.java`，其中包含几个简单的测试。\n\n然后可以运行`ant MyArrayListTest`来运行 JUnit 测试。其中几个应该失败。如果你检查源代码，你会发现三条 TODO 注释，表示你应该填充的方法。\n\n在开始之前，让我们来看看一些代码。以下是`MyLinkedList`的实例变量和构造函数：\n\n```java\npublic class MyLinkedList<E> implements List<E> {\n\n    private int size;            // keeps track of the number of elements\n    private Node head;           // reference to the first node\n\n    public MyLinkedList() {\n        head = null;\n        size = 0;\n    }\n}\n```\n\n如注释所示，`size`跟踪`MyLinkedList`有多少元素；`head`是列表中第一个`Node`的引用，或者如果列表为空则为`null`。\n\n存储元素数量不是必需的，并且一般来说，保留冗余信息是有风险的，因为如果没有正确更新，就有机会产生错误。它还需要一点点额外的空间。\n\n但是如果我们显式存储`size`，我们可以实现常数时间的`size`方法；否则，我们必须遍历列表并对元素进行计数，这需要线性时间。\n\n因为我们显式存储`size`明确地存储，每次添加或删除一个元素时，我们都要更新它，这样一来，这些方法就会减慢，但是它不会改变它们的增长级别，所以很值得。\n\n构造函数将`head`设为null，表示空列表，并将`size`设为`0`。\n\n这个类使用类型参数`E`作为元素的类型。如果你不熟悉类型参数，可能需要阅读本教程：<http://thinkdast.com/types>。\n\n类型参数也出现在`Node`的定义中，嵌套在`MyLinkedList`里面：\n\n```java\nprivate class Node {\n    public E data;\n    public Node next;\n\n    public Node(E data, Node next) {\n        this.data = data;\n        this.next = next;\n    }\n}\n```\n\n除了这个，`Node`类似于上面的`ListNode`。\n\n最后，这是我的`add`的实现：\n\n```java\npublic boolean add(E element) {\n    if (head == null) {\n        head = new Node(element);\n    } else {\n        Node node = head;\n        // loop until the last node\n        for ( ; node.next != null; node = node.next) {}\n        node.next = new Node(element);\n    }\n    size++;\n    return true;\n}\n```\n\n此示例演示了你需要的两种解决方案：\n\n对于许多方法，作为特殊情况，我们必须处理列表的第一个元素。在这个例子中，如果我们向列表添加列表第一个元素，我们必须修改`head`。否则，我们遍历列表，找到末尾，并添加新节点。\n此方法展示了，如何使用`for`循环遍历列表中的节点。在你的解决方案中，你可能会在此循环中写出几个变体。注意，我们必须在循环之前声明`node`，以便我们可以在循环之后访问它。\n\n现在轮到你了。填充`indexOf`的主体。像往常一样，你应该阅读文档，位于 <http://thinkdast.com/listindof>，所以你知道应该做什么。特别要注意它应该如何处理`null`。\n\n与上一个练习一样，我提供了一个辅助方法`equals`，它将数组中的一个元素与目标值进行比较，并检查它们是否相等，并正确处理`null`。这个方法是私有的，因为它在这个类中使用，但它不是`List`接口的一部分。\n\n完成后，再次运行测试；`testIndexOf`，以及依赖于它的其他测试现在应该通过。\n\n接下来，你应该填充双参数版本的add，它使用索引并将新值存储在给定索引处。再次阅读 <http://thinkdast.com/listadd> 上的文档，编写一个实现，并运行测试进行确认。\n\n最后一个：填写`remove`的主体。文档在这里：<http://thinkdast.com/listrem>。当你完成它时，所有的测试都应该通过。\n\n一旦你的实现能够工作，将它与仓库`solution`目录中的版本比较。\n\n## 3.6 垃圾回收的注解\n\n在`MyArrayList`以前的练习中，如果需要，数字会增长，但它不会缩小。该数组从不收集垃圾，并且在列表本身被销毁之前，元素不会收集垃圾。\n\n链表实现的一个优点是，当元素被删除时它会缩小，并且未使用的节点可以立即被垃圾回收。\n\n这是我的实现的`clear`方法：\n\n```java\npublic void clear() {\n    head = null;\n    size = 0;\n}\n```\n\n当我们将`head`设为`null`时，我们删除第一个`Node`的引用。如果没有其他`Node`的引用（不应该有），它将被垃圾收集。这个时候，第二个`Node`引用被删除，所以它也被垃圾收集。此过程一直持续到所有节点都被收集。\n\n那么我们应该如何划分`clear`？该方法本身包含两个常数时间的操作，所以它看起来像是常数时间。但是当你调用它时，你将使垃圾收集器做一些工作，它与元素数成正比。所以也许我们应该将其认为是线性的！\n\n这是一个有时被称为性能 bug 的例子：一个程序做了正确的事情，在这种意义上它是正确的，但它不属于我们预期的增长级别。在像 Java 这样的语言中，它在背后做了大量工作的，例如垃圾收集，这种 bug 可能很难找到。\n"
  },
  {
    "path": "docs/think-dast-zh/4.md",
    "content": "# 第四章 `LinkedList`\n\n> 原文：[Chapter 4  LinkedList](http://greenteapress.com/thinkdast/html/thinkdast005.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n这一章展示了上一个练习的解法，并继续讨论算法分析。\n\n## 4.1 `MyLinkedList`方法的划分\n\n我的`indexOf`实现在下面。在阅读说明之前，请阅读它，看看你是否可以确定其增长级别。\n\n```java\npublic int indexOf(Object target) {\n    Node node = head;\n    for (int i=0; i<size; i++) {\n        if (equals(target, node.data)) {\n            return i;\n        }\n        node = node.next;\n    }\n    return -1;\n}\n```\n\n最初`node`为`head`的副本，所以他们都指向相同的`Node`。循环变量`i`从`0`计数到`size-1`。每次在循环中，我们都用`equals`来看看我们是否找到了目标。如果是这样，我们立即返回`i`。否则我们移动到列表中的下一个`Node`。\n\n通常我们会检查以确保下一个`Node`不是`null`，但在这里，它是安全的，因为当我们到达列表的末尾时循环结束（假设与列表中`size`与实际节点数量一致）。\n\n如果我们走完了循环而没有找到目标，我们返回`-1`。\n\n那么这种方法的增长级别是什么？\n\n+   每次在循环中，我们调用了`equals`，这是一个常数时间（它可能取决于`target`或`data`大小，但不取决于列表的大小）。循环中的其他操作也是常数时间。\n+   循环可能运行`n`次，因为在更糟的情况下，我们可能必须遍历整个列表。\n\n所以这个方法的运行时间与列表的长度成正比。\n\n接下来，这里是我的双参数`add`方法的实现。同样，你应该尝试对其进行划分，然后再阅读说明。\n\n```java\npublic void add(int index, E element) {\n    if (index == 0) {\n        head = new Node(element, head);\n    } else {\n        Node node = getNode(index-1);\n        node.next = new Node(element, node.next);\n    }\n    size++;\n}\n```\n\n如果`index==0`，我们在开始添加新的`Node`，所以我们把它当作特殊情况。否则，我们必须遍历列表来查找`index-1`处的元素。我们使用辅助方法`getNode`：\n\n```java\nprivate Node getNode(int index) {\n    if (index < 0 || index >= size) {\n        throw new IndexOutOfBoundsException();\n    }\n    Node node = head;\n    for (int i=0; i<index; i++) {\n        node = node.next;\n    }\n    return node;\n}\n```\n\n`getNode`检查`index`是否超出范围；如果是这样，它会抛出异常。否则，它遍历列表并返回所请求的节点。\n\n我们回到`add`，一旦我们找到合适的`Node`，我创建新的`Node`，并把它插到`node`和`node.next`之间。你可能会发现，绘制此操作的图表有助于确保你了解此操作。\n\n那么，`add`的增长级别什么呢？\n\n+   `getNode`类似`indexOf`，出于同样的原因也是线性的。\n+   在`add`中，`getNode`前后的一切都是常数时间。\n\n所以放在一起，`add`是线性的。\n\n最后，我们来看看`remove`：\n\n```java\npublic E remove(int index) {\n    E element = get(index);\n    if (index == 0) {\n        head = head.next;\n    } else {\n        Node node = getNode(index-1);\n        node.next = node.next.next;\n    }\n    size--;\n    return element;\n}\n```\n\n`remove`使用了`get`查找和存储`index`处的元素。然后它删除包含它的`Node`。\n\n如果`index==0`，我们再次处理这个特殊情况。否则我们找到节点`index-1`并进行修改，来跳过`node.next`并直接链接到`node.next.next`。这有效地从列表中删除`node.next`，它可以被垃圾回收。\n\n最后，我们减少`size`并返回我们在开始时检索的元素。\n\n那么，`remove`的增长级别是什么呢？`remove`中的一切是常数时间，除了`get`和`getNode`，它们是线性的。因此，`remove`是线性的。\n\n当人们看到两个线性操作时，他们有时会认为结果是平方的，但是只有一个操作嵌套在另一个操作中才适用。如果你在一个操作之后调用另一个，运行时间会相加。如果它们都是`O(n)`的，则总和也是`O(n)`的。\n\n## 4.2 `MyArrayList`和`MyLinkedList`的对比\n\n下表总结了`MyArrayList`和`MyLinkedList`之间的差异，其中`1`表示`O(1)`或常数时间，和`n`表示`O(n)`或线性。\n\n|   | `MyArrayList` | `MyLinkedList` |\n| --- | --- | --- |\n| `add`（末尾） | 1 | n |\n| `add`（开头） | n | 1 |\n| `add`（一般） | n | n |\n| `get` / `set` | 1 | n |\n| `indexOf` / `lastIndexOf` | n | n |\n| `isEmpty` / `size` | 1 | 1 |\n| `remove`（末尾） | 1 | n |\n| `remove`（开头） | n | 1 |\n| `remove`（一般） | n | n |\n\n+   `MyArrayList`的优势操作是，插入末尾，移除末尾，获取和设置。\n+   `MyLinkedList`的优势操作是，插入开头，以及移动开头。\n\n对于其他操作，这两个实现方式的增长级别相同。\n\n哪个实现更好？这取决于你最有可能使用哪些操作。这就是为什么 Java 提供了多个实现，因为它取决于你。\n\n## 4.3 性能分析\n\n对于下一个练习，我提供了一个`Profiler`类，它包含代码，使用一系列问题规模运行方法，测量运行时间和绘制结果。\n\n你将使用`Profiler`，为 Java 的实现`ArrayList`和`LinkedList`，划分`add`方法的性能。\n\n以下是一个示例，展示了如何使用分析器：\n\n```java\npublic static void profileArrayListAddEnd() {\n    Timeable timeable = new Timeable() {\n        List<String> list;\n\n        public void setup(int n) {\n            list = new ArrayList<String>();\n        }\n\n        public void timeMe(int n) {\n            for (int i=0; i<n; i++) {\n                list.add(\"a string\");\n            }\n        }\n    };\n\n    String title = \"ArrayList add end\";\n    Profiler profiler = new Profiler(title, timeable);\n\n    int startN = 4000;\n    int endMillis = 1000;\n    XYSeries series = profiler.timingLoop(startN, endMillis);\n    profiler.plotResults(series);\n}\n```\n\n此方法测量在`ArrayList`上运行`add`所需的时间，它向末尾添加新元素。我将解释代码，然后展示结果。\n\n为了使用`Profiler`，我们需要创建一个`Timeable`，它提供两个方法：`setup`和`timeMe`。`setup`方法执行在启动计时之前所需的任何工作；这里它会创建一个空列表。然后`timeMe`执行我们试图测量的任何操作；这里它将`n`个元素添加到列表中。\n\n创建`timeable`的代码是一个匿名类，用于定义`Timeable`接口的新实现，并同时创建新类的实例。如果你不熟悉匿名类，你可以阅读这里：<http://thinkdast.com/anonclass>。\n\n但是下一次练习不需要太多的知识；即使你不喜欢匿名类，也可以复制和修改示例代码。\n\n下一步是创建`Profiler`对象，传递`Timeable`对象和标题作为参数。\n\n`Profiler`提供了`timingLoop`，它使用存储为实例变量的`Timeable`。它多次调用`Timeable`对象上的`timeMe`方法，使用一系列的`n`值。`timingLoop`接受两个参数：\n\n+   `startN`是`n`的值，计时循环应该从它开始。\n+   `endMillis`是以毫秒为单位的阈值。随着 `timingLoop`增加问题规模，运行时间增加；当运行时间超过此阈值时，`timingLoop`停止。\n\n当你运行实验时，你可能需要调整这些参数。如果`startN`太低，运行时间可能太短，无法准确测量。如果`endMillis`太低，你可能无法获得足够的数据，来查看问题规模和运行时间之间的明确关系。\n\n这段代码位于`ProfileListAdd.java`，你将在下一个练习中运行它。当我运行它时，我得到这个输出：\n\n```\n4000, 3\n8000, 0\n16000, 1\n32000, 2\n64000, 3\n128000, 6\n256000, 18\n512000, 30\n1024000, 88\n2048000, 185\n4096000, 242\n8192000, 544\n16384000, 1325\n```\n\n第一列是问题规模，`n`；第二列是以毫秒为单位的运行时间。前几个测量非常嘈杂；最好将`startN`设置在`64000`左右。\n\n`timingLoop`的结果是包含此数据的`XYSeries`。如果你将这个序列传给`plotResults`，它会产生一个如图 4.1 所示的图形。\n\n![](img/4-1.jpg)\n\n图 4.1 分析结果：将`n`个元素添加到`ArrayList`末尾的运行时间与问题规模。\n\n下一节解释了如何解释它。\n\n## 4.4 解释结果\n\n基于我们对`ArrayList`工作方式的理解，我们期望，在添加元素到最后时，`add`方法需要常数时间。所以添加`n`个元素的总时间应该是线性的。\n\n为了测试这个理论，我们可以绘制总运行时间和问题规模，我们应该看到一条直线，至少对于大到足以准确测量的问题规模。在数学上，我们可以为这条直线编写一个函数：\n\n```\nruntime = a + b * n \n```\n\n其中`a`是线的截距，`b`是斜率。\n\n另一方面，如果`add`是线性的，则`n`次添加的总时间将是平方。如果我们绘制运行时间与问题规模，我们预计会看到抛物线。或者在数学上，像：\n\n```\nruntime = a + b * n + c * n ** 2 \n```\n\n有了完美的数据，我们可能能够分辨直线和抛物线之间的区别，但如果测量结果很嘈杂，可能很难辨别。解释嘈杂的测量值的更好方法是，在重对数刻度上绘制的运行时间和问题规模。\n\n为什么？我们假设运行时间与`n ** k`成正比，但是我们不知道指数`k`是什么。我们可以将关系写成这样：\n\n```\nruntime = a + b * n + … + c * n ** k \n```\n\n对于`n`的较大值，最大指数项是最重要的，因此：\n\n```\nruntime ≈ c * n ** k \n```\n\n其中`≈`意思是“大致相等”。现在，如果我们对这个方程的两边取对数：\n\n```\nlog(runtime) ≈ log(c) + k * log(n) \n```\n\n这个方程式意味着，如果我们在重对数合度上绘制运行时间与`n`，我们预计看到一条直线，截距为`log(c)`，斜率为`k`。我们不太在意截距，但斜率表示增长级别：如果`k = 1`，算法是线性的；如果`k = 2`，则为平方的。\n\n看上一节中的数字，你可以通过眼睛来估计斜率。但是当你调用`plotResults`它时，会计算数据的最小二乘拟合并打印估计的斜率。在这个例子中：\n\n```\nEstimated slope = 1.06194352346708\n```\n\n它接近`1`；并且这表明`n`次添加的总时间是线性的，所以每个添加是常数时间，像预期的那样。\n\n其中重要的一点：如果你在图形看到这样的直线，这并不意味着该算法是线性的。如果对于任何指数`k`，运行时间与`n ** k`成正比，我们预计看到斜率为`k`的直线。如果斜率接近`1`，则表明算法是线性的。如果接近`2`，它可能是平方的。\n\n## 4.5 练习 4\n\n在本书的仓库中，你将找到此练习所需的源文件：\n\n+   `Profiler.java`包含上述`Profiler`类的实现。你会使用这个类，但你不必知道它如何工作。但可以随时阅读源码。\n+   `ProfileListAdd.java`包含此练习的起始代码，包括上面的示例，它测量了`ArrayList.add`。你将修改此文件来测量其他一些方法。\n\n此外，在`code`目录中，你将找到 Ant 构建文件`build.xml`。\n\n运行`ant ProfileListAdd`来运行`ProfileListAdd.java`。你应该得到类似图 4.1 的结果，但是你可能需要调整`startN`或`endMillis`。估计的斜率应该接近`1`，表明执行`n`个添加操作的所需时间与`n`成正比；也就是说，它是`O(n)`的。\n\n在`ProfileListAdd.java`中，你会发现一个空的方法`profileArrayListAddBeginning`。用测试`ArrayList.add`的代码填充这个方法的主体，总是把新元素放在开头。如果你以`profileArrayListAddEnd`的副本开始，你只需要进行一些更改。在`main`中添加一行来调用这个方法。\n\n再次运行`ant ProfileListAdd`并解释结果。基于我们对`ArrayList`工作方式的理解，我们期望，每个添加操作是线性的，所以`n`次添加的总时间应该是平方的。如果是这样，在重对数刻度中，直线的估计斜率应该接近`2`。是吗？\n\n现在我们来将其与`LinkedList`比较。当我们把新元素放在开头，填充`profileLinkedListAddBeginning`并使用它划分`LinkedList.add`。你期望什么性能？结果是否符合你的期望？\n\n最后，填充`profileLinkedListAddEnd`的主体，使用它来划分`LinkedList.add`。你期望什么性能？结果是否符合你的期望？\n\n我将在下一章中展示结果并回答这些问题。\n"
  },
  {
    "path": "docs/think-dast-zh/5.md",
    "content": "# 第五章 双链表\n\n> 原文：[Chapter 5  Doubly-linked list](http://greenteapress.com/thinkdast/html/thinkdast006.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n本章回顾了上一个练习的结果，并介绍了`List`接口的另一个实现，即双链表。\n\n## 5.1 性能分析结果\n\n在之前的练习中，我们使用了`Profiler.java`，运行`ArrayList`和`LinkedList`的各种操作，它们具有一系列的问题规模。我们将运行时间与问题规模绘制在重对数比例尺上，并估计所得曲线的斜率，它表示运行时间和问题规模之间的关系的主要指数。\n\n例如，当我们使用`add`方法将元素添加到`ArrayList`的末尾，我们发现，执行`n`次添加的总时间正比于`n`。也就是说，估计的斜率接近`1`。我们得出结论，执行`n`次添加是 `O(n)`的，所以平均来说，单个添加的时间是常数时间，或者`O(1)`，基于算法分析，这是我们的预期。\n\n\n这个练习要求你填充`profileArrayListAddBeginning`的主体，它测试了，在`ArrayList`头部添加一个新的元素的性能。根据我们的分析，我们预计每个添加都是线性的，因为它必须将其他元素向右移动；所以我们预计，`n`次添加是平方复杂度。\n\n\n这是一个解决方案，你可以在仓库的`solution`目录中找到它。\n\n```java\npublic static void profileArrayListAddBeginning() {\n    Timeable timeable = new Timeable() {\n        List<String> list;\n\n        public void setup(int n) {\n            list = new ArrayList<String>();\n        }\n\n        public void timeMe(int n) {\n            for (int i=0; i<n; i++) {\n                list.add(0, \"a string\");\n            }\n        }\n    };\n    int startN = 4000;\n    int endMillis = 10000;\n    runProfiler(\"ArrayList add beginning\", timeable, startN, endMillis);\n}\n```\n\n这个方法几乎和`profileArrayListAddEnd`相同。唯一的区别在于`timeMe`，它使用`add`的双参数版本，将新元素置于下标`0`处。同样，我们增加了`endMillis`，来获取一个额外的数据点。\n\n以下是时间结果（左侧是问题规模，右侧是运行时间，单位为毫秒）：\n\n```\n4000, 14\n8000, 35\n16000, 150\n32000, 604\n64000, 2518\n128000, 11555\n```\n\n图 5.1 展示了运行时间和问题规模的图形。\n\n![](img/5-1.jpg)\n\n图 5.1：分析结果：在`ArrayList`开头添加`n`个元素的运行时间和问题规模\n\n请记住，该图上的直线并不意味着该算法是线性的。相反，如果对于任何指数`k`，运行时间与`n ** k`成正比，我们预计会看到斜率为`k`的直线。在这种情况下，我们预计，`n`次添加的总时间与`n ** 2`成正比，所以我们预计会有一条斜率为`2`的直线。实际上，估计的斜率是`1.992`，非常接近。恐怕假数据才能做得这么好。\n\n## 5.2 分析`LinkedList`方法的性能\n\n在以前的练习中，你还分析了，在`LinkedList`头部添加新元素的性能。根据我们的分析，我们预计每个`add`都要花时间，因为在一个链表中，我们不必转移现有元素；我们可以在头部添加一个新节点。所以我们预计`n`次添加的总时间是线性的。\n\n\n这是一个解决方案：\n\n```java\npublic static void profileLinkedListAddBeginning() {\n    Timeable timeable = new Timeable() {\n        List<String> list;\n\n        public void setup(int n) {\n            list = new LinkedList<String>();\n        }\n\n        public void timeMe(int n) {\n            for (int i=0; i<n; i++) {\n                list.add(0, \"a string\");\n            }\n        }\n    };\n    int startN = 128000;\n    int endMillis = 2000;\n    runProfiler(\"LinkedList add beginning\", timeable, startN, endMillis);\n}\n```\n\n我们只做了一些修改，将`ArrayList`替换为`LinkedList`并调整`startN`和`endMillis`，来获得良好的数据范围。测量结果比上一批数据更加嘈杂；结果如下：\n\n```\n128000, 16\n256000, 19\n512000, 28\n1024000, 77\n2048000, 330\n4096000, 892\n8192000, 1047\n16384000, 4755\n```\n\n图 5.2 展示了这些结果的图形。\n\n![](img/5-2.jpg)\n\n图 5.2：分析结果：在`LinkedList`开头添加`n`个元素的运行时间和问题规模\n\n并不是一条很直的线，斜率也不是正好是`1`，最小二乘拟合的斜率是`1.23`。但是结果表示，`n`次添加的总时间至少近似于`O(n)`，所以每次添加都是常数时间。\n\n## 5.3 `LinkedList`的尾部添加\n\n在开头添加元素是一种操作，我们期望`LinkedList`的速度快于`ArrayList`。但是为了在末尾添加元素，我们预计`LinkedList`会变慢。在我的实现中，我们必须遍历整个列表来添加一个元素到最后，它是线性的。所以我们预计`n`次添加的总时间是二次的。\n\n但是不是这样。以下是代码：\n\n```\npublic static void profileLinkedListAddEnd() {\n    Timeable timeable = new Timeable() {\n        List<String> list;\n\n        public void setup(int n) {\n            list = new LinkedList<String>();\n        }\n\n        public void timeMe(int n) {\n            for (int i=0; i<n; i++) {\n                list.add(\"a string\");\n            }\n        }\n    };\n    int startN = 64000;\n    int endMillis = 1000;\n    runProfiler(\"LinkedList add end\", timeable, startN, endMillis);\n}\n```\n\n这里是结果：\n\n```\n64000, 9\n128000, 9\n256000, 21\n512000, 24\n1024000, 78\n2048000, 235\n4096000, 851\n8192000, 950\n16384000, 6160\n```\n\n图 5.3 展示了这些结果的图形。\n\n![](img/5-3.jpg)\n\n图 5.2：分析结果：在`LinkedList`末尾添加`n`个元素的运行时间和问题规模\n\n同样，测量值很嘈杂，线不完全是直的，但估计的斜率为`1.19`，接近于在头部添加元素，而并不非常接近`2`，这是我们根据分析的预期。事实上，它接近`1`，这表明在尾部添加元素是常数元素。这是怎么回事？\n\n## 5.4 双链表\n\n我的链表实现`MyLinkedList`，使用单链表；也就是说，每个元素都包含下一个元素的链接，并且`MyArrayList`对象本身具有第一个节点的链接。\n\n\n但是，如果你阅读`LinkedList`的文档，网址为 <http://thinkdast.com/linked>，它说：\n\n> `List`和`Deque`接口的双链表实现。[...] 所有的操作都能像双向列表那样执行。索引该列表中的操作将从头或者尾遍历列表，使用更接近指定索引的那个。\n\n如果你不熟悉双链表，你可以在 <http://thinkdast.com/doublelist> 上阅读更多相关信息，但简称为：\n\n+   每个节点包含下一个节点的链接和上一个节点的链接。\n+   `LinkedList`对象包含指向列表的第一个和最后一个元素的链接。\n\n所以我们可以从列表的任意一端开始，并以任意方向遍历它。因此，我们可以在常数时间内，在列表的头部和末尾添加和删除元素！\n\n下表总结了`ArrayList`，`MyLinkedList`（单链表）和`LinkedList`（双链表）的预期性能：\n\n\n|   | `MyArrayList` | `MyLinkedList` | `LinkedList` |\n| --- | --- | --- | --- |\n| `add`（尾部） | 1 | n | 1 |\n| `add`（头部） | n | 1 | 1 |\n| `add`（一般） | n | n | n |\n| `get`/`set` | 1 | n | n |\n| `indexOf`/ `lastIndexOf` | n | n | n |\n| `isEmpty`/`size` | 1 | 1 | 1 |\n| `remove`（尾部） | 1 | n | 1 |\n| `remove`（头部） | n | 1 | 1 |\n| `remove`（一般） | n | n | n |\n\n## 5.5 结构的选择\n\n对于头部插入和删除，双链表的实现优于`ArrayList`。对于尾部插入和删除，都是一样好。所以，`ArrayList`唯一优势是`get`和`set`，链表中它需要线性时间，即使是双链表。\n\n如果你知道，你的应用程序的运行时间取决于`get`和`set`元素的所需时间，则`ArrayList`可能是更好的选择。如果运行时间取决于在开头或者末尾附加添加和删除元素，`LinkedList`可能会更好。\n\n\n但请记住，这些建议是基于大型问题的增长级别。还有其他因素要考虑：\n\n+   如果这些操作不占用你应用的大部分运行时间 - 也就是说，如果你的应用程序花费大部分时间来执行其他操作 - 那么你对`List`实现的选择并不重要。\n+   如果你正在处理的列表不是很大，你可能无法获得期望的性能。对于小型问题，二次算法可能比线性算法更快，或者线性可能比常数时间更快。而对于小型问题，差异可能并不重要。\n+   另外，别忘了空间。到目前为止，我们专注于运行时间，但不同的实现需要不同的空间。在`ArrayList`中，这些元素并排存储在单个内存块中，所以浪费的空间很少，并且计算机硬件通常在连续的块上更快。在链表中，每个元素需要一个节点，带有一个或两个链接。链接占用空间（有时甚至超过数据！），并且节点分散在内存中，硬件效率可能不高。\n\n总而言之，算法分析为数据结构的选择提供了一些指南，但只有：\n\n+   你的应用的运行时间很重要，\n+   你的应用的运行时间取决于你选择的数据结构，以及，\n+   问题的规模足够大，增长级别实际上预测了哪个数据结构更好。\n\n作为一名软件工程师，在较长的职业生涯中，你几乎不必考虑这种情况。\n"
  },
  {
    "path": "docs/think-dast-zh/6.md",
    "content": "# 第六章 树的遍历\n\n> 原文：[Chapter 6  Tree traversal](http://greenteapress.com/thinkdast/html/thinkdast007.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n本章将介绍一个 Web 搜索引擎，我们将在本书其余部分开发它。我描述了搜索引擎的元素，并介绍了第一个应用程序，一个从维基百科下载和解析页面的 Web 爬行器。本章还介绍了深度优先搜索的递归实现，以及迭代实现，它使用 Java`Deque`实现“后入先出”的栈。\n\n## 6.1 搜索引擎\n\n网络搜索引擎，像谷歌搜索或 Bing，接受一组“检索项”，并返回一个网页列表，它们和这些项相关（之后我将讨论“相关”是什么意思）。你可以在 <http://thinkdast.com/searcheng> 上阅读更多内容，但是我会解释你需要什么。\n\n搜索引擎的基本组成部分是：\n\n抓取：我们需要一个程序，可以下载网页，解析它，并提取文本和任何其他页面的链接。\n索引：我们需要一个数据结构，可以查找一个检索项，并找到包含它的页面。\n检索：我们需要一种方法，从索引中收集结果，并识别与检索项最相关的页面。\n\n我们以爬虫开始。爬虫的目标是查找和下载一组网页。对于像 Google 和 Bing 这样的搜索引擎，目标是查找所有网页，但爬虫通常仅限于较小的域。在我们的例子中，我们只会读取维基百科的页面。\n\n作为第一步，我们将构建一个读取维基百科页面的爬虫，找到第一个链接，并跟着链接来到另一个页面，然后重复。我们将使用这个爬虫来测试“到达哲学”的猜想，它是：\n\n> 点击维基百科文章正文中的第一个小写的链接，然后对后续文章重复这个过程，通常最终会到达“哲学”的文章。\n\n这个猜想在 <http://thinkdast.com/getphil> 中阐述，你可以阅读其历史。\n\n测试这个猜想需要我们构建爬虫的基本部分，而不必爬取整个网络，甚至是所有维基百科。而且我觉得这个练习很有趣！\n\n在几个章节之内，我们将处理索引器，然后我们将到达检索器。\n\n## 6.2 解析 HTML\n\n当你下载网页时，内容使用超文本标记语言（即 HTML）编写。例如，这里是一个最小的 HTML 文档：\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <title>This is a title</title>\n  </head>\n  <body>\n    <p>Hello world!</p>\n  </body>\n</html>\n```\n\n短语`This is a title`和`Hello world!`是实际出现在页面上的文字；其他元素是指示文本应如何显示的标签。\n\n当我们的爬虫下载页面时，它需要解析 HTML，以便提取文本并找到链接。为此，我们将使用`jsoup`，它是一个下载和解析 HTML 的开源 Java 库。\n\n解析 HTML 的结果是文档对象模型（DOM）树，其中包含文档的元素，包括文本和标签。树是由节点组成的链接数据结构；节点表示文本，标签和其他文档元素。\n\n节点之间的关系由文档的结构决定。在上面的例子中，第一个节点称为根，是`<html>`标签，它包含指向所包含两个节点的链接， `<head>`和`<body>`；这些节点是根节点的子节点。\n\n`<head>`节点有一个子节点，`<title>`，`<body>`节点有一个子节点， `<p>`（代表“段落”）。图 6.1 以图形方式表示该树。\n\n![](img/6-1.jpg)\n\n图 6.1 简单 HTML 页面的 DOM 树\n\n每个节点包含其子节点的链接; 此外，每个节点都包含其父节点的链接，所以任何节点都可以向上或向下浏览树。实际页面的 DOM 树通常比这个例子更复杂。\n\n大多数网络浏览器提供了工具，用于检查你正在查看的页面的 DOM。在 Chrome 中，你可以右键单击网页的任何部分，然后从弹出的菜单中选择`Inspect`（检查）。在 Firefox 中，你可以右键单击并从菜单中选择`Inspect Element`（检查元素）。Safari 提供了一个名为 Web Inspector 的工具，你可以阅读 <http://thinkdast.com/safari>。对于 Internet Explorer，你可以阅读 <http://thinkdast.com/explorer> 上的说明 。\n\n![](img/6-2.jpg)\n\n图 6.2：Chrome DOM 查看器的截图\n\n图 6.2 展示了维基百科 Java 页面（<http://thinkdast.com/java>）的 DOM 截图。高亮的元素是文章正文的第一段，它包含在一个`<div>`元素中 ，带有`id=\"mw-content-text\"`。我们将使用这个元素 ID 来标识我们下载的每篇文章的正文。\n\n## 6.3 使用`jsoup`\n\n`jsoup`非常易于下载，和解析 Web 页面，以及访问 DOM 树。这里是一个例子：\n\n```java\nString url = \"http://en.wikipedia.org/wiki/Java_(programming_language)\";\n\n// download and parse the document\nConnection conn = Jsoup.connect(url);\nDocument doc = conn.get();\n\n// select the content text and pull out the paragraphs.\nElement content = doc.getElementById(\"mw-content-text\");\nElements paragraphs = content.select(\"p\");\n```\n\n`Jsoup.connect`接受`String`形式的`url`，并连接 Web 服务器。`get`方法下载 HTML，解析，并返回`Document`对象，他表示 DOM。\n\n`Document`提供了导航树和选择节点的方法。其实它提供了很多方法，可能会把人搞晕。此示例演示了两种选择节点的方式：\n\n+   `getElementById`接受`String`并在树中搜索匹配`id`字段的元素。在这里，它选择节点`<div id=\"mw-content-text\" lang=\"en\" dir=\"ltr\" class=\"mw-content-ltr\">`，它出现在每个维基页面上，来确定包含文章正文的`<div>`元素，而不是导航边栏和其他元素。`getElementById`的返回值是一个`Element`对象，代表这个`<div>`，并包含`<div>`中的元素作为后继节点。\n+   `select`接受`String`，遍历树，并返回与所有元素，它的标签与`String`匹配。在这个例子中，它返回所有`content`中的段落标签。返回值是一个`Elements`对象。\n\n> 译者注：`select`方法接受 CSS 选择器，不仅仅能按照标签选择。请见 <https://jsoup.org/apidocs/org/jsoup/select/Selector.html>。\n\n在你继续之前，你应该仔细阅读这些类的文档，以便知道他们能做什么。最重要的类是`Element`，`Elements`和`Node`，你可以阅读 <http://thinkdast.com/jsoupelt>，<http://thinkdast.com/jsoupelts> 和 <http://thinkdast.com/jsoupnode>。\n\n`Node`表示 DOM 树中的一个节点；有几个扩展`Node`的子类，其中包括 `Element`，`TextNode`，`DataNode`，和`Comment`。`Elements`是`Element`对象的`Collection`。\n\n![](img/6-3.jpg)\n\n图 6.3：被选类的 UML 图，由`jsoup`提供。编辑：<ttp://yuml.me/edit/4bc1c919>\n\n图 6.3 是一个 UML 图，展示了这些类之间的关系。在 UML 类图中，带有空心箭头的线表示一个类继承另一个类。例如，该图表示`Elements`继承`ArrayList`。我们将在第 11.6 节中再次接触 UML 图。\n\n## 6.4 遍历 DOM\n\n为了使你变得更轻松，我提供了一个`WikiNodeIterable`类，可以让你遍历 DOM 树中的节点。以下是一个示例，展示如何使用它：\n\n```java\nElements paragraphs = content.select(\"p\");\nElement firstPara = paragraphs.get(0);\n\nIterable<Node> iter = new WikiNodeIterable(firstPara);\nfor (Node node: iter) {\n    if (node instanceof TextNode) {\n        System.out.print(node);\n    }\n}\n```\n\n这个例子紧接着上一个例子。它选择`paragraphs`中的第一个段落，然后创建一个`WikiNodeIterable`，它实现`Iterable<Node>`。`WikiNodeIterable`执行“深度优先搜索”，它按照它们将出现在页面上的顺序产生节点。\n\n在这个例子中，仅当`Node`是`TextNode`时，我们打印它，并忽略其他类型的`Node`，特别是代表标签的`Element`对象。结果是没有任何标记的 HTML 段落的纯文本。输出为：\n\n```\nJava is a general-purpose computer programming language that is concurrent, class-based, object-oriented,[13] and specifically designed …\n```\n\n> Java 是一种通用的计算机编程语言，它是并发的，基于类的，面向对象的，[13] 和特地设计的...\n\n## 6.5 深度优先搜索\n\n有几种方式可以合理地遍历一个树，每个都有不同的应用。我们从“深度优先搜索”（DFS）开始。DFS 从树的根节点开始，并选择第一个子节点。如果子节点有子节点，则再次选择第一个子节点。当它到达没有子节点的节点时，它回溯，沿树向上移动到父节点，在那里它选择下一个子节点，如果有的话；否则它会再次回溯。当它探索了根节点的最后一个子节点，就完成了。\n\n有两种常用的方式来实现 DFS，递归和迭代。递归实现简单优雅：\n\n```java\nprivate static void recursiveDFS(Node node) {\n    if (node instanceof TextNode) {\n        System.out.print(node);\n    }\n    for (Node child: node.childNodes()) {\n        recursiveDFS(child);\n    }\n}\n```\n\n这个方法对树中的每一个`Node`调用，从根节点开始。如果`Node`是一个`TextNode`，它打印其内容。如果`Node`有任何子节点，它会按顺序在每一个子节点上调用`recursiveDFS`。\n\n在这个例子中，我们在遍历子节点之前打印每个`TextNode`的内容，所以这是一个“前序”遍历的例子。你可以在 <http://thinkdast.com/treetrav> 上了解“前序”，“后序”和“中序”遍历。对于此应用程序，遍历顺序并不重要。\n\n通过进行递归调用，`recursiveDFS`使用调用栈（<http://thinkdast.com/callstack>）来跟踪子节点并以正确的顺序处理它们。作为替代，我们可以使用栈数据结构自己跟踪节点；如果我们这样做，我们可以避免递归并迭代遍历树。\n\n## 6.6 Java 中的栈\n\n在我解释 DFS 的迭代版本之前，我将解释栈数据结构。我们将从栈的一般概念开始，我将使用小写`s`指代“栈”。然后我们将讨论两个 Java`interfaces`，它们定义了栈的方法：`Stack`和`Deque`。\n\n栈是与列表类似的数据结构：它是维护元素顺序的集合。栈和列表之间的主要区别是栈提供的方法较少。在通常的惯例中，它提供：\n\n`push`：它将一个元素添加到栈顶。\n`pop`：它从栈中删除并返回最顶部的元素。\n`peek`：它返回最顶部的元素而不修改栈。\n`isEmpty`：表示栈是否为空。\n因为`pop`总是返回最顶部的元素，栈也称为 LIFO，代表“后入先出”。栈的替代品是“队列”，它返回的元素顺序和添加顺序相同；即“先入先出（FIFO）。\n\n为什么栈和队列是有用的，可能不是很明显：它们不提供任何列表没有的功能；实际上它们提供的功能更少。那么为什么不使用列表的一切？有两个原因：\n\n+   如果你将自己限制于一小部分方法 - 也就是小型 API - 你的代码将更加易读，更不容易出错。例如，如果使用列表来表示栈，则可能会以错误的顺序删除元素。使用栈 API，这种错误在字面上是不可能的。避免错误的最佳方法是使它们不可能。\n+   如果一个数据结构提供了小型 API，那么它更容易实现。例如，实现栈的简单方法是单链表。当我们压入一个元素时，我们将它添加到列表的开头；当我们弹出一个元素时，我们在开头删除它。对于链表，在开头添加和删除是常数时间的操作，因此这个实现是高效的。相反，大型 API 更难实现高效。\n\n为了在 Java 中实现栈，你有三个选项：\n\n+   继续使用`ArrayList`或`LinkedList`。如果使用`ArrayList`，请务必从最后添加和删​​除，这是一个常数时间的操作。并且小心不要在错误的地方添加元素，或以错误的顺序删除它们。\n+   Java 提供了一个`Stack`类，它提供了一组标准的栈方法。但是这个类是 Java 的一个旧部分：它与 Java 集合框架不兼容，后者之后才出现。\n+   最好的选择可能是使用`Deque`接口的一个实现，如`ArrayDeque`。\n\n`Deque`代表“双向队列”；它应该被发音为“deck”，但有些人叫它“deek”。在 Java 中， `Deque`接口提供`push`，`pop`，`peek`和`isEmpty`，因此你可以将`Deque`用作栈。它提供了其他方法，你可以阅读 <http://thinkdast.com/deque>，但现在我们不会使用它们。\n\n## 6.7 迭代式 DFS\n\n这里是 DFS 的迭代版本，它使用`ArrayDeque`来表示`Node`对象的栈。\n\n```java\nprivate static void iterativeDFS(Node root) {\n    Deque<Node> stack = new ArrayDeque<Node>();\n    stack.push(root);\n\n    while (!stack.isEmpty()) {\n        Node node = stack.pop();\n        if (node instanceof TextNode) {\n            System.out.print(node);\n        }\n\n        List<Node> nodes = new ArrayList<Node>(node.childNodes());\n        Collections.reverse(nodes);\n\n        for (Node child: nodes) {\n            stack.push(child);\n        }\n    }\n}\n```\n\n参数`root`是我们想要遍历的树的根节点，所以我们首先创建栈并将根节点压入它。\n\n循环持续到栈为空。每次迭代，它会从栈中弹出`Node`。如果它得到`TextNode`，它打印内容。然后它把子节点们压栈。为了以正确的顺序处理子节点，我们必须以相反的顺序将它们压栈; 我们通过将子节点复制成一个`ArrayList`，原地反转元素，然后遍历反转的`ArrayList`。\n\nDFS 的迭代版本的一个优点是，更容易实现为 Java`Iterator`；你会在下一章看到如何实现。\n\n但是首先，有一个`Deque`接口的最后的注意事项：除了`ArrayDeque`，Java 提供另一个`Deque`的实现，我们的老朋友`LinkedList`。`LinkedList`实现两个接口，`List`和`Deque`（还有`Queue`）。你得到哪个接口，取决于你如何使用它。例如，如果将`LinkedList`对象赋给`Deque`变量，如下所示：\n\n```java\nDeqeue<Node> deque = new LinkedList<Node>();\n```\n\n你可以使用`Deque`接口中的方法，但不是所有`List`中的方法。如果你将其赋给`List`变量，像这样：\n\n```java\nList<Node> deque = new LinkedList<Node>();\n```\n\n你可以使用`List`接口中的方法，但不是所有`Deque`中的方法。并且如果像这样赋值：\n\n```java\nLinkedList<Node> deque = new LinkedList<Node>();\n```\n\n你可以使用所有方法，但是混合了来自不同接口的方法。你的代码会更不可读，并且更易于出错。\n"
  },
  {
    "path": "docs/think-dast-zh/7.md",
    "content": "# 第七章 到达哲学\n\n> 原文：[Chapter 7  Getting to Philosophy](http://greenteapress.com/thinkdast/html/thinkdast008.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n本章的目标是开发一个 Web 爬虫，它测试了第 6.1 节中提到的“到达哲学”猜想。\n\n## 7.1 起步\n\n在本书的仓库中，你将找到一些帮助你起步的代码：\n\n+   `WikiNodeExample.java`包含前一章的代码，展示了 DOM 树中深度优先搜索（DFS）的递归和迭代实现。\n+   `WikiNodeIterable.java`包含`Iterable`类，用于遍历 DOM 树。我将在下一节中解释这段代码。\n+   `WikiFetcher.java`包含一个工具类，使用`jsoup`从维基百科下载页面。为了帮助你遵守维基百科的服务条款，此类限制了你下载页面的速度；如果你每秒请求许多页，在下载下一页之前会休眠一段时间。\n+   `WikiPhilosophy.java`包含你为此练习编写的代码的大纲。我们将在下面进行说明。\n\n你还会发现 Ant 构建文件`build.xml`。如果你运行`ant WikiPhilosophy`，它将运行一些简单的启动代码。\n\n## 7.2 可迭代对象和迭代器\n\n在前一章中，我展示了迭代式深度优先搜索（DFS），并且认为与递归版本相比，迭代版本的优点在于，它更容易包装在`Iterator`对象中。在本节中，我们将看到如何实现它。\n\n如果你不熟悉`Iterator`和`Iterable`接口，你可以阅读 <http://thinkdast.com/iterator> 和 <http://thinkdast.com/iterable>。\n\n看看`WikiNodeIterable.java`的内容。外层的类`WikiNodeIterable`实现`Iterable<Node>`接口，所以我们可以在一个`for`循环中使用它：\n\n```java\nNode root = ...\nIterable<Node> iter = new WikiNodeIterable(root);\nfor (Node node: iter) {\n    visit(node);\n}\n```\n\n其中`root`是我们想要遍历的树的根节点，并且`visit`是一个方法，当我们“访问”`Node`时，做任何我们想要的事情。\n\n`WikiNodeIterable`的实现遵循以下惯例：\n\n+   构造函数接受并存储根`Node`的引用。\n+   `iterator`方法创建一个返回一个`Iterator`对象。\n\n这是它的样子：\n\n```java\npublic class WikiNodeIterable implements Iterable<Node> {\n\n    private Node root;\n\n    public WikiNodeIterable(Node root) {\n        this.root = root;\n    }\n\n    @Override\n    public Iterator<Node> iterator() {\n        return new WikiNodeIterator(root);\n    }\n}\n```\n\n内层的类`WikiNodeIterator`，执行所有实际工作。\n\n```java\nprivate class WikiNodeIterator implements Iterator<Node> {\n\n    Deque<Node> stack;\n\n    public WikiNodeIterator(Node node) {\n        stack = new ArrayDeque<Node>();\n        stack.push(root);\n    }\n\n    @Override\n    public boolean hasNext() {\n        return !stack.isEmpty();\n    }\n\n    @Override\n    public Node next() {\n        if (stack.isEmpty()) {\n            throw new NoSuchElementException();\n        }\n\n        Node node = stack.pop();\n        List<Node> nodes = new ArrayList<Node>(node.childNodes());\n        Collections.reverse(nodes);\n        for (Node child: nodes) {\n            stack.push(child);\n        }\n        return node;\n    }\n}\n```\n\n该代码与 DFS 的迭代版本几乎相同，但现在分为三个方法：\n\n+   构造函数初始化栈（使用一个`ArrayDeque`实现）并将根节点压入这个栈。\n+   `isEmpty`检查栈是否为空。\n+   `next`从`Node`栈中弹出下一个节点，按相反的顺序压入子节点，并返回弹出的`Node`。如果有人在空`Iterator`上调用`next`，则会抛出异常。\n\n可能不明显的是，值得使用两个类和五个方法，来重写一个完美的方法。但是现在我们已经完成了，在需要`Iterable`的任何地方，我们可以使用`WikiNodeIterable`，这使得它的语法整洁，易于将迭代逻辑（DFS）与我们对节点的处理分开。\n\n## 7.3 `WikiFetcher`\n\n编写 Web 爬虫时，很容易下载太多页面，这可能会违反你要下载的服务器的服务条款。为了帮助你避免这种情况，我提供了一个`WikiFetcher`类，它可以做两件事情：\n\n+   它封装了我们在上一章中介绍的代码，用于从维基百科下载页面，解析 HTML 以及选择内容文本。\n+   它测量请求之间的时间，如果我们在请求之间没有足够的时间，它将休眠直到经过了合理的间隔。默认情况下，间隔为`1`秒。\n\n这里是`WikiFetcher`的定义：\n\n```java\npublic class WikiFetcher {\n    private long lastRequestTime = -1;\n    private long minInterval = 1000;\n\n    /**\n     * Fetches and parses a URL string, \n     * returning a list of paragraph elements.\n     *\n     * @param url\n     * @return\n     * @throws IOException\n     */\n    public Elements fetchWikipedia(String url) throws IOException {\n        sleepIfNeeded();\n\n        Connection conn = Jsoup.connect(url);\n        Document doc = conn.get();\n        Element content = doc.getElementById(\"mw-content-text\");\n        Elements paragraphs = content.select(\"p\");\n        return paragraphs;\n    }\n\n    private void sleepIfNeeded() {\n        if (lastRequestTime != -1) {\n            long currentTime = System.currentTimeMillis();\n            long nextRequestTime = lastRequestTime + minInterval;\n            if (currentTime < nextRequestTime) {\n                try {\n                    Thread.sleep(nextRequestTime - currentTime);\n                } catch (InterruptedException e) {\n                    System.err.println(\n                        \"Warning: sleep interrupted in fetchWikipedia.\");\n                }\n            }\n        }\n        lastRequestTime = System.currentTimeMillis();\n    }\n}\n```\n\n唯一的公共方法是`fetchWikipedia`，接收`String`形式的 URL，并返回一个`Elements`集合，该集合包含的一个 DOM 元素表示内容文本中每个段落。这段代码应该很熟悉了。\n\n新的代码是`sleepIfNeeded`，它检查自上次请求以来的时间，如果经过的时间小于`minInterval`（毫秒），则休眠。\n\n这就是`WikiFetcher`全部。这是一个演示如何使用它的例子：\n\n```java\nWikiFetcher wf = new WikiFetcher();\n\nfor (String url: urlList) {\n    Elements paragraphs = wf.fetchWikipedia(url);\n    processParagraphs(paragraphs);\n}\n```\n\n在这个例子中，我们假设`urlList`是一个`String`的集合 ，并且`processParagraphs`是一个方法，对`Elements`做一些事情，它由`fetchWikipedia`返回。\n\n此示例展示了一些重要的东西：你应该创建一个`WikiFetcher`对象并使用它来处理所有请求。如果有多个`WikiFetcher`的实例，则它们不会确保请求之间的最小间隔。\n\n注意：我的`WikiFetcher`实现很简单，但是通过创建多个实例，人们很容易误用它。你可以通过制作`WikiFetcher`“单例” 来避免这个问题，你可以阅读 <http://thinkdast.com/singleton>。\n\n## 7.4 练习 5\n\n在`WikiPhilosophy.java`中，你会发现一个简单的`main`方法，展示了如何使用这些部分。从这个代码开始，你的工作是写一个爬虫：\n\n1.  获取维基百科页面的 URL，下载并分析。\n1.  它应该遍历所得到的 DOM 树来找到第一个 有效的链接。我会在下面解释“有效”的含义。\n1.  如果页面没有链接，或者如果第一个链接是我们已经看到的页面，程序应该指示失败并退出。\n1.  如果链接匹配维基百科页面上的哲学网址，程序应该提示成功并退出。\n1.  否则应该回到步骤`1`。\n\n该程序应该为它访问的 URL 构建`List`，并在结束时显示结果（无论成功还是失败）。\n\n那么我们应该认为什么是“有效的”链接？你在这里有一些选择 各种版本的“到达哲学”推测使用略有不同的规则，但这里有一些选择：\n\n+   这个链接应该在页面的内容文本中，而不是侧栏或弹出框。\n+   它不应该是斜体或括号。\n+   你应该跳过外部链接，当前页面的链接和红色链接。\n+   在某些版本中，如果文本以大写字母开头，则应跳过链接。\n\n你不必遵循所有这些规则，但我们建议你至少处理括号，斜体以及当前页面的链接。\n\n如果你有足够的信息来起步，请继续。或者你可能想要阅读这些提示：\n\n+   当你遍历树的时候，你将需要处理的两种`Node`是`TextNode`和`Element`。如果你找到一个`Element`，你可能需要转换它的类型，来访问标签和其他信息。\n+   当你找到包含链接的`Element`时，通过向上跟踪父节点链，可以检查是否是斜体。如果父节点链中有一个`<i>`或`<em>`标签，链接为斜体。\n+   为了检查链接是否在括号中，你必须在遍历树时扫描文本，并跟踪开启和闭合括号（理想情况下，你的解决方案应该能够处理嵌套括号（像这样））。\n\n如果你从 Java 页面开始，你应该在跟随七个链接之后到达哲学，除非我运行代码后发生了改变。\n\n好的，这就是你所得到的所有帮助。现在全靠你了。玩的开心！\n\n"
  },
  {
    "path": "docs/think-dast-zh/8.md",
    "content": "# 第八章 索引器\n\n> 原文：[Chapter 8  Indexer](http://greenteapress.com/thinkdast/html/thinkdast009.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n目前，我们构建了一个基本的 Web 爬虫；我们下一步将是索引。在网页搜索的上下文中，索引是一种数据结构，可以查找检索词并找到该词出现的页面。此外，我们想知道每个页面上显示检索词的次数，这将有助于确定与该词最相关的页面。\n\n例如，如果用户提交检索词“Java”和“编程”，我们将查找两个检索词并获得两组页面。带有“Java”的页面将包括 Java 岛屿，咖啡昵称以及编程语言的网页。具有“编程”一词的页面将包括不同编程语言的页面，以及该单词的其他用途。通过选择具有两个检索词的页面，我们希望消除不相关的页面，并找到 Java 编程的页面。\n\n现在我们了解索引是什么，它执行什么操作，我们可以设计一个数据结构来表示它。\n\n## 8.1 数据结构选取\n\n索引的基本操作是查找；具体来说，我们需要能够查找检索词并找到包含它的所有页面。最简单的实现将是页面的集合。给定一个检索词，我们可以遍历页面的内容，并选择包含检索词的内容。但运行时间与所有页面上的总字数成正比，这太慢了。\n\n一个更好的选择是一个映射（字典），它是一个数据结构，表示键值对的集合，并提供了一种方法，快速查找键以及相应值。例如，我们将要构建的第一个映射是`TermCounter`，它将每个检索词映射为页面中出现的次数。键是检索词，值是计数（也称为“频率”）。\n\nJava 提供了`Map`的调用接口，它指定映射应该提供的方法；最重要的是：\n\n+   `get(key)`：此方法查找一个键并返回相应的值。\n+   `put(key, value)`：该方法向`Map`添加一个新的键值对，或者如果该键已经在映射中，它将替换与`key`关联的值。\n\nJava 提供了几个`Map`实现，包括我们将关注的两个，`HashMap`以及`TreeMap`。在即将到来的章节中，我们将介绍这些实现并分析其性能。\n\n除了检索词到计数的映射`TermCounter`之外，我们将定义一个被称为`Index`的类，它将检索词映射为出现的页面的集合。而这又引发了下一个问题，即如何表示页面集合。同样，如果我们考虑我们想要执行的操作，它们就指导了我们的决定。\n\n在这种情况下，我们需要组合两个或多个集合，并找到所有这些集合中显示的页面。你可以将此操作看做集合的交集：两个集合的交集是出现在两者中的一组元素。\n\n你可能猜到了，Java 提供了一个`Set`接口，来定义集合应该执行的操作。它实际上并不提供设置交集，但它提供了方法，使我们能够有​​效地实现交集和其他结合操作。核心的`Set`方法是：\n\n+   `add(element)`：该方法将一个元素添加到集合中；如果元素已经在集合中，则它不起作用。\n+   `contains(element)`：该方法检查给定元素是否在集合中。\n\nJava 提供了几个`Set`实现，包括`HashSet`和`TreeSet`。\n\n现在我们自顶向下设计了我们的数据结构，我们将从内到外实现它们，从`TermCounter`开始。\n\n## 8.2 `TermCounter`\n\n`TermCounter`是一个类，表示检索词到页面中出现次数的映射。这是类定义的第一部分：\n\n```java\npublic class TermCounter {\n\n    private Map<String, Integer> map;\n    private String label;\n\n    public TermCounter(String label) {\n        this.label = label;\n        this.map = new HashMap<String, Integer>();\n    }\n}\n```\n\n实例变量`map`包含检索词到计数的映射，并且`label`标识检索词的来源文档；我们将使用它来存储 URL。\n\n为了实现映射，我选择了`HashMap`，它是最常用的`Map`。在几章中，你将看到它是如何工作的，以及为什么它是一个常见的选择。\n\n`TermCounter`提供`put`和`get`，定义如下：\n\n```java\n    public void put(String term, int count) {\n        map.put(term, count);\n    }\n\n    public Integer get(String term) {\n        Integer count = map.get(term);\n        return count == null ? 0 : count;\n    }\n```\n\n`put`只是一个包装方法；当你调用`TermCounter`的`put`时，它会调用内嵌映射的`put`。\n\n另一方面，`get`做了一些实际工作。当你调用`TermCounter`的`get`时，它会在映射上调用`get`，然后检查结果。如果该检索词没有出现在映射中，则`TermCount.get`返回`0`。`get`的这种定义方式使`incrementTermCount`的写入更容易，它需要一个检索词，并增加关联该检索词的计数器。\n\n```java\n    public void incrementTermCount(String term) {\n        put(term, get(term) + 1);\n    }\n```\n\n如果这个检索词未见过，则`get`返回`0`；我们设为`1`，然后使用`put`向映射添加一个新的键值对。如果该检索词已经在映射中，我们得到旧的计数，增加`1`，然后存储新的计数，替换旧的值。\n\n此外，`TermCounter`还提供了这些其他方法，来帮助索引网页：\n\n```java\n    public void processElements(Elements paragraphs) {\n        for (Node node: paragraphs) {\n            processTree(node);\n        }\n    }\n\n    public void processTree(Node root) {\n        for (Node node: new WikiNodeIterable(root)) {\n            if (node instanceof TextNode) {\n                processText(((TextNode) node).text());\n            }\n        }\n    }\n\n    public void processText(String text) {\n        String[] array = text.replaceAll(\"\\\\pP\", \" \").\n                              toLowerCase().\n                              split(\"\\\\s+\");\n\n        for (int i=0; i<array.length; i++) {\n            String term = array[i];\n            incrementTermCount(term);\n        }\n    }\n```\n\n最后，这里是一个例子，展示了如何使用`TermCounter`：\n\n```java\n    String url = \"http://en.wikipedia.org/wiki/Java_(programming_language)\";\n    WikiFetcher wf = new WikiFetcher();\n    Elements paragraphs = wf.fetchWikipedia(url);\n\n    TermCounter counter = new TermCounter(url);\n    counter.processElements(paragraphs);\n    counter.printCounts();\n```\n\n这个示例使用了`WikiFetcher`从维基百科下载页面，并解析正文。之后它创建了`TermCounter`并使用它来计数页面上的单词。\n\n下一节中，你会拥有一个挑战，来运行这个代码，并通过填充缺失的方法来测试你的理解。\n\n## 8.3 练习 6\n\n在本书的存储库中，你将找到此练习的源文件：\n\n+   `TermCounter.java`包含上一节中的代码。\n+   `TermCounterTest.java`包含测试代码`TermCounter.java`。\n+   `Index.java`包含本练习下一部分的类定义。\n+   `WikiFetcher.java`包含我们在上一个练习中使用的，用于下载和解析网页的类。\n+   `WikiNodeIterable.java`包含我们用于遍历 DOM 树中的节点的类。\n\n你还会发现 Ant 构建文件`build.xml`。\n\n运行`ant build`来编译源文件。然后运行`ant TermCounter`；它应该运行上一节中的代码，并打印一个检索词列表及其计数。输出应该是这样的：\n\n```\ngenericservlet, 2\nconfigurations, 1\nclaimed, 1\nservletresponse, 2\noccur, 2\nTotal of all counts = -1\n```\n\n运行它时，检索词的顺序可能不同。\n\n最后一行应该打印检索词计数的总和，但是由于方法`size`不完整而返回`-1`。填充此方法并`ant TermCounter`重新运行。结果应该是`4798`。\n\n运行`ant TermCounterTest`来确认这部分练习是否完整和正确。\n\n对于练习的第二部分，我将介绍`Index`对象的实现，你将填充一个缺失的方法。这是类定义的开始：\n\n```java\npublic class Index {\n\n    private Map<String, Set<TermCounter>> index = \n        new HashMap<String, Set<TermCounter>>();\n\n    public void add(String term, TermCounter tc) {\n        Set<TermCounter> set = get(term);\n\n        // if we're seeing a term for the first time, make a new Set\n        if (set == null) {\n            set = new HashSet<TermCounter>();\n            index.put(term, set);\n        }\n        // otherwise we can modify an existing Set\n        set.add(tc);\n    }\n\n    public Set<TermCounter> get(String term) {\n        return index.get(term);\n    }\n```\n\n实例变量`index`是每个检索词到一组`TermCounter`对象的映射。每个`TermCounter`表示检索词出现的页面。\n\n`add`方法向集合添加新的`TermCounter`，它与检索词关联。当我们索引一个尚未出现的检索词时，我们必须创建一个新的集合。否则我们可以添加一个新的元素到一个现有的集合。在这种情况下，`set.add`修改位于`index`里面的集合，但不会修改`index`本身。我们唯一修改`index`的时候是添加一个新的检索词。\n\n最后，`get`方法接受检索词并返回相应的`TermCounter`对象集。\n\n这种数据结构比较复杂。回顾一下，`Index`包含`Map`，将每个检索词映射到`TermCounter`对象的`Set`，每个`TermCounter`包含一个`Map`，将检索词映射到计数。\n\n![](img/8-1.jpg)\n\n图 8.1 `Index`的对象图\n\n图 8.1 是展示这些对象的对象图。`Index`对象具有一个名为`index` 的`Map`实例变量。在这个例子中，`Map`只包含一个字符串，`\"Java\"`，它映射到一个`Set`，包含两个`TermCounter`对象的，代表每个出现单词“Java”的页面。\n\n每个`TermCounter`包含`label`，它是页面的 URL，以及`map`，它是`Map`，包含页面上的单词和每个单词出现的次数。\n\n`printIndex`方法展示了如何解压缩此数据结构：\n\n```java\n    public void printIndex() {\n        // loop through the search terms\n        for (String term: keySet()) {\n            System.out.println(term);\n\n            // for each term, print pages where it appears and frequencies\n            Set<TermCounter> tcs = get(term);\n            for (TermCounter tc: tcs) {\n                Integer count = tc.get(term);\n                System.out.println(\"    \" + tc.getLabel() + \" \" + count);\n            }\n        }\n    }\n```\n\n外层循环遍历检索词。内层循环迭代`TermCounter`对象。\n\n运行`ant build`来确保你的源代码已编译，然后运行`ant Index`。它下载两个维基百科页面，对它们进行索引，并打印结果；但是当你运行它时，你将看不到任何输出，因为我们已经将其中一个方法留空。\n\n你的工作是填写`indexPage`，它需要一个 URL（一个`String`）和一个`Elements`对象，并更新索引。下面的注释描述了应该做什么：\n\n```java\npublic void indexPage(String url, Elements paragraphs) {\n    // 生成一个 TermCounter 并统计段落中的检索词\n\n    // 对于 TermCounter 中的每个检索词，将 TermCounter 添加到索引\n}\n```\n\n它能工作之后，再次运行`ant Index`，你应该看到如下输出：\n\n```java\n...\nconfigurations\n    http://en.wikipedia.org/wiki/Programming_language 1\n    http://en.wikipedia.org/wiki/Java_(programming_language) 1\nclaimed\n    http://en.wikipedia.org/wiki/Java_(programming_language) 1\nservletresponse\n    http://en.wikipedia.org/wiki/Java_(programming_language) 2\noccur\n    http://en.wikipedia.org/wiki/Java_(programming_language) 2\n```\n\n当你运行的时候，检索词的顺序可能有所不同。\n\n同样，运行`ant TestIndex`来确定完成了这部分练习。\n"
  },
  {
    "path": "docs/think-dast-zh/9.md",
    "content": "# 第九章 `Map`接口\n\n> 原文：[Chapter 9  The Map interface](http://greenteapress.com/thinkdast/html/thinkdast010.html)\n\n> 译者：[飞龙](https://github.com/wizardforcel)\n\n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n\n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n\n在接下来的几个练习中，我介绍了`Map`接口的几个实现。其中一个基于哈希表，这可以说是所发明的最神奇的数据结构。另一个是类似的`TreeMap`，不是很神奇，但它有附加功能，它可以按顺序迭代元素。\n\n你将有机会实现这些数据结构，然后我们将分析其性能。\n\n但是在我们可以解释哈希表之前，我们将从一个`Map`开始，它使用键值对的`List`来简单实现。\n\n## 9.1 实现`MyLinearMap`\n\n像往常一样，我提供启动代码，你将填写缺少的方法。这是`MyLinearMap`类定义的起始：\n\n```java\npublic class MyLinearMap<K, V> implements Map<K, V> {\n\n    private List<Entry> entries = new ArrayList<Entry>();\n```\n\n该类使用两个类型参数，`K`是键的类型，`V`是值的类型。`MyLinearMap`实现`Map`，这意味着它必须提供`Map`接口中的方法。\n\n`MyLinearMap`对象具有单个实例变量，`entries`，这是一个`Entry`的`ArrayList`对象。每个`Entry`都包含一个键值对。这里是定义：\n\n```java\n    public class Entry implements Map.Entry<K, V> {\n        private K key;\n        private V value;\n        \n        public Entry(K key, V value) {\n            this.key = key;\n            this.value = value;\n        }\n        \n        @Override\n        public K getKey() {\n            return key;\n        }\n        @Override\n        public V getValue() {\n            return value;\n        }\n    }\n```\n\n`Entry`没有什么，只是一个键和一个值的容器。该定义内嵌在`MyLinearList`中，因此它使用相同类型的参数，`K`和`V`。\n\n这就是你做这个练习所需的所有东西，所以让我们开始吧。\n\n## 9.2 练习 7\n\n在本书的仓库中，你将找到此练习的源文件：\n\n+   `MyLinearMap.java`包含练习的第一部分的起始代码。\n+   `MyLinearMapTest.java`包含`MyLinearMap`的单元测试。\n\n你还会找到 Ant 构建文件`build.xml`。\n\n运行`ant build`来编译源文件。然后运行`ant   MyLinearMapTest`；几个测试应该失败，因为你有一些任务要做。\n\n首先，填写`findEntry`的主体。这是一个辅助方法，不是`Map`接口的一部分，但是一旦你让它工作，你可以在几种方法中使用它。给定一个目标键（Key），它应该搜索条目（Entry）并返回包含目标的条目（按照键，而不是值），或者如果不存在则返回`null`。请注意，我提供了`equals`，正确比较两个键并处理`null`。\n\n\n你可以再次运行`ant MyLinearMapTest`，但即使你的`findEntry`是正确的，测试也不会通过，因为`put`不完整。\n\n\n填充`put`。你应该阅读`Map.put`的文档，<http://thinkdast.com/listput> ，以便你知道应该做什么。你可能希望从一个版本开始，其中`put`始终添加新条目，并且不会修改现有条目；这样你可以先测试简单的情况。或者如果你更加自信，你可以一次写出整个东西。\n\n一旦你`put`正常工作，测试`containsKey`应该通过。\n\n阅读`Map.get`的文档，<http://thinkdast.com/listget> ，然后填充方法。再次运行测试。\n\n最后，阅读`Map.remove`的文档，<http://thinkdast.com/maprem> 并填充方法。\n\n到了这里，所有的测试都应该通过。恭喜！\n\n## 9.3 分析`MyLinearMap`\n\n这一节中，我展示了上一个练习的答案，并分析核心方法的性能。这里是`findEntry`和`equals`。\n\n```java\nprivate Entry findEntry(Object target) {\n    for (Entry entry: entries) {\n        if (equals(target, entry.getKey())) {\n            return entry;\n        }\n    }\n    return null;\n}\n\nprivate boolean equals(Object target, Object obj) {\n    if (target == null) {\n        return obj == null;\n    }\n    return target.equals(obj);\n}\n```\n\n`equals`的运行时间可能取决于`target`键和键的大小 ，但通常不取决于条目的数量，`n`。那么`equals`是常数时间。\n\n在`findEntry`中，我们可能会很幸运，并在一开始就找到我们要找的键，但是我们不能指望它。一般来说，我们要搜索的条目数量与`n`成正比，所以`findEntry`是线性的。\n\n\n大部分的`MyLinearMap`核心方法使用`findEntry`，包括`put`，`get`，和`remove`。这就是他们的样子：\n\n```java\npublic V put(K key, V value) {\n    Entry entry = findEntry(key);\n    if (entry == null) {\n        entries.add(new Entry(key, value));\n        return null;\n    } else {\n        V oldValue = entry.getValue();\n        entry.setValue(value);\n        return oldValue;\n    }\n}\npublic V get(Object key) {\n    Entry entry = findEntry(key);\n    if (entry == null) {\n        return null;\n    }\n    return entry.getValue();\n}\npublic V remove(Object key) {\n    Entry entry = findEntry(key);\n    if (entry == null) {\n        return null;\n    } else {\n        V value = entry.getValue();\n        entries.remove(entry);\n        return value;\n    }\n}\n```\n\n`put`调用`findEntry`之后，其他一切都是常数时间。记住这个`entries`是一个`ArrayList`，所以向末尾添加元素平均是常数时间。如果键已经在映射中，我们不需要添加条目，但我们必须调用`entry.getValue`和`entry.setValue`，而这些都是常数时间。把它们放在一起，`put`是线性的。\n\n同样，`get`也是线性的。\n\n`remove`稍微复杂一些，因为`entries.remove`可能需要从一开始或中间删除`ArrayList`的一个元素，并且需要线性时间。但是没关系：两个线性运算仍然是线性的。\n\n\n总而言之，核心方法都是线性的，这就是为什么我们将这个实现称为`MyLinearMap`（嗒嗒！）。\n\n如果我们知道输入的数量很少，这个实现可能会很好，但是我们可以做得更好。实际上，`Map`所有的核心方法都是常数时间的实现。当你第一次听到这个消息时，可能似乎觉得不可能。实际上我们所说的是，你可以在常数时间内大海捞针，不管海有多大。这是魔法。\n\n我们不是将条目存储在一个大的`List`中，而是把它们分解成许多短的列表。对于每个键，我们将使用哈希码（在下一节中进行说明）来确定要使用的列表。\n使用大量的简短列表比仅仅使用一个更快，但正如我将解释的，它不会改变增长级别；核心功能仍然是线性的。但还有一个技巧：如果我们增加列表的数量来限制每个列表的条目数，就会得到一个恒定时间的映射。你会在下一个练习中看到细节，但是首先要了解哈希！\n\n在下一章中，我将介绍一种解决方案，分析`Map`核心方法的性能，并引入更有效的实现。\n"
  },
  {
    "path": "docs/think-dast-zh/README.md",
    "content": "# 数据结构思维中文版\n\n> 原书：[Think Data Structures: Algorithms and Information Retrieval in Java](http://greenteapress.com/thinkdast/html/index.html)\n> \n> 译者：[飞龙](https://github.com/wizardforcel)\n> \n> 版本：1.0.0\n> \n> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)\n> \n> 自豪地采用[谷歌翻译](https://translate.google.cn/)\n> \n> 任何你写的代码，超过 6 个月不去看它，当你再看时，都像是别人写的。——Eagleson 定律\n\n+   [ApacheCN 面试求职交流群 724187166](https://jq.qq.com/?_wv=1027&k=54ujcL3)\n+   [ApacheCN 学习资源](http://www.apachecn.org/)\n\n&zwj;\n\n+ [在线阅读](https://think-dast.apachecn.org)\n+ [在线阅读（Gitee）](https://apachecn.gitee.io/think-dast-zh/)\n+ [PDF格式](https://www.gitbook.com/download/pdf/book/wizardforcel/think-dast)\n+ [EPUB格式](https://www.gitbook.com/download/epub/book/wizardforcel/think-dast)\n+ [MOBI格式](https://www.gitbook.com/download/mobi/book/wizardforcel/think-dast)\n+ [代码仓库](http://github.com/apachecn/think-dast-zh)\n\n## 下载\n\n### Docker\n\n```\ndocker pull apachecn0/think-dast-zh\ndocker run -tid -p <port>:80 apachecn0/think-dast-zh\n# 访问 http://localhost:{port} 查看文档\n```\n\n### PYPI\n\n```\npip install think-dast-zh\nthink-dast-zh <port>\n# 访问 http://localhost:{port} 查看文档\n```\n\n### NPM\n\n```\nnpm install -g think-dast-zh\nthink-dast-zh <port>\n# 访问 http://localhost:{port} 查看文档\n```\n\n## 赞助我\n\n![](img/qr_alipay.png)\n"
  },
  {
    "path": "docs/think-dast-zh/SUMMARY.md",
    "content": "+   [数据结构思维中文版](README.md)\n+   [前言](0.md)\n+   [第一章 接口](1.md)\n+   [第二章 算法分析](2.md)\n+   [第三章 `ArrayList`](3.md)\n+   [第四章 `LinkedList`](4.md)\n+   [第五章 双链表](5.md)\n+   [第六章 树的遍历](6.md)\n+   [第七章 到达哲学](7.md)\n+   [第八章 索引器](8.md)\n+   [第九章 `Map`接口](9.md)\n+   [第十章 哈希](10.md)\n+   [第十一章 `HashMap`](11.md)\n+   [第十二章 `TreeMap`](12.md)\n+   [第十三章 二叉搜索树](13.md)\n+   [第十四章 持久化](14.md)\n+   [第十五章 爬取维基百科](15.md)\n+   [第十六章 布尔搜索](16.md)\n+   [第十七章 排序](17.md)"
  },
  {
    "path": "index.html",
    "content": "<!-- index.html -->\n\n<!DOCTYPE html>\n<html>\n<head>\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n  <meta charset=\"UTF-8\">\n  <link rel=\"stylesheet\" href=\"asset/vue.css\">\n  <link rel=\"stylesheet\" href=\"asset/style.css\">\n  <link rel=\"stylesheet\" href=\"asset/prism-darcula.css\">\n  <link rel=\"stylesheet\" href=\"asset/sidebar.min.css\">\n  \n  <!-- google ads -->\n  <script async src=\"//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js\"></script>\n  \n  <!-- google webmaster -->\n  <meta name=\"google-site-verification\" content=\"pyo9N70ZWyh8JB43bIu633mhxesJ1IcwWCZlM3jUfFo\" />\n\n  <link rel=\"stylesheet\" href=\"asset/dark-mode.css\">\n  <script src=\"asset/dark-mode.js\"></script>\n  <link rel=\"stylesheet\" href=\"asset/share.css\">\n  <script src=\"asset/share.js\"></script>\n  <link rel=\"stylesheet\" href=\"asset/edit.css\">\n  <script src=\"asset/edit.js\"></script>\n  <link rel=\"stylesheet\" href=\"asset/back-to-top.css\">\n  <script src=\"asset/back-to-top.js\"></script>\n</head>\n<body>\n  <div id=\"app\">now loading...</div>\n  <script>\n    window.$docsify = {\n      loadNavbar: 'NAV.md',\n      loadSidebar: 'SUMMARY.md',\n      name: 'ApacheCN 数据结构与算法译文集',\n      auto2top: true,\n      themeColor: '#dd9f05',\n      repo: 'apachecn/apachecn-algo-zh',\n      plugins: [window.docsPlugin],\n      alias: {\n        '/.*/SUMMARY.md': '/SUMMARY.md',\n      },\n      bdStatId: '38525fdac4b5d4403900b943d4e7dd91',\n      cnzzId: '1275211409',\n      search: {\n        paths: 'auto',\n        placeholder: '搜索',\n        noData: '没有结果',\n      },\n      copyCode: {\n        buttonText: '复制',\n        errorText: 'Error',\n        successText: 'OK!',\n      },\n    }\n  </script>\n  \n  <script src=\"asset/docsify.min.js\"></script>\n  <script src=\"asset/search.min.js\"></script>\n  <script src=\"asset/prism-java.min.js\"></script>\n  <script src=\"asset/prism-c.min.js\"></script>\n  <script src=\"asset/prism-cpp.min.js\"></script>\n  <script src=\"asset/prism-javascript.min.js\"></script>\n  <script src=\"asset/prism-sql.min.js\"></script>\n  <script src=\"asset/prism-kotlin.min.js\"></script>\n  <script src=\"asset/prism-perl.min.js\"></script>\n  <script src=\"asset/prism-python.min.js\"></script>\n  <script src=\"asset/docsify-copy-code.min.js\"></script>\n  <script src=\"asset/docsify-baidu-push.js\"></script>\n  <script src=\"asset/docsify-baidu-stat.js\"></script>\n  <script src=\"asset/docsify-cnzz.js\"></script>\n  <script src=\"asset/docsify-apachecn-footer.js\"></script>\n  <script src=\"asset/docsify-clicker.js\"></script>\n  <link rel=\"stylesheet\" href=\"asset/docsify-quick-page.css\">\n  <script src=\"asset/docsify-quick-page.js\"></script>\n  <script src=\"asset/docsify-sidebar-collapse.min.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "update.sh",
    "content": "git add -A\ngit commit -am \"$(date \"+%Y-%m-%d %H:%M:%S\")\"\ngit push"
  }
]