diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0a0b4382..00000000 --- a/.gitignore +++ /dev/null @@ -1,110 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class -.vscode -.DS_Store -Middleware -docs/Algorithm/Leetcode/*/book.json - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -_book/ -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -node_modules diff --git a/404.html b/404.html deleted file mode 100644 index 5705bebe..00000000 --- a/404.html +++ /dev/null @@ -1,4 +0,0 @@ ---- -permalink: /404.html ---- - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..ea0c7f0d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,15 @@ +# 比赛组队活动参与指南 + +> 如果你有想法,有热情参与某个比赛(或者复现某个现有比赛),但苦于没人一起组队的话,加入我们,成为比赛活动负责人吧!发起你的活动,招募队友,互相学习,争取更大的胜利! + +## 角色:负责人 + +在 [ISSUE](https://github.com/apachecn/kaggle/issues/260) 中提交“昵称 + QQ + 比赛名称”,示例:“飞龙+562826179+kaggle Leaf Classification”。 + +等待参与者联系你,协作平台由你自己决定。 + +活动结束后,每个小组提交一份 WriteUp 到`competitions/{比赛名称}/`。 + +## 角色:参与者 + +在 [ISSUE](https://github.com/apachecn/kaggle/issues/260) 中查看已有活动,选择自己喜欢的,联系负责人。 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md deleted file mode 100644 index 19e9af22..00000000 --- a/CONTRIBUTORS.md +++ /dev/null @@ -1,28 +0,0 @@ -# 贡献者名单 - -> 第一期 (2018-01-01) - -* [@片刻](https://github.com/jiangzhonglian) -* [@那伊抹微笑](https://github.com/wangyangting) -* [@瑶妹](https://github.com/chenyyx) -* [@loveSnowBest](https://github.com/zehuichen123) -* [@谈笑风生](https://github.com/zhu1040028623) -* [@诺木人](https://github.com/1mrliu) -* [@飞龙](https://github.com/wizardforcel) - -> 第二期 (2018-06-01) - -* [@KrisYu](https://github.com/KrisYu/LeetCode-CLRS-Python) -* 授权信息: -* [@Lisanaaa](https://github.com/Lisanaaa) -- 由于个人商业化原因,退出 -* [@片刻](https://github.com/jiangzhonglian) - [@小瑶](https://github.com/chenyyx) - [@cclauss](https://github.com/cclauss) - [@yudaer](https://github.com/yudaer) -* [@yuzhoujr](https://github.com/yuzhoujr) - [@wizardforcel](https://github.com/wizardforcel) - [@Stuming](https://github.com/Stuming) - [@GaofanHu](https://github.com/GaofanHu) -* [@er3456qi](https://github.com/er3456qi) - [@xshahq](https://github.com/xshahq) - [@xiaqunfeng](https://github.com/xiaqunfeng) - [@CaviarChen](https://github.com/CaviarChen) -* [@royIdoodle](https://github.com/royIdoodle) - [@MarsXue](https://github.com/MarsXue) - [@nature1995](https://github.com/nature1995) - -> 第三期 (2019-07-17) - -* [@片刻](https://github.com/jiangzhonglian) -* [@飞龙](https://github.com/wizardforcel) -* [@xixici](https://github.com/xixici) -* [@royIdoodle](https://github.com/royIdoodle) diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 65e2ef59..00000000 --- a/Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM httpd:2.4 -COPY ./ /usr/local/apache2/htdocs/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index 53202f12..9cecc1d4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,101 +1,674 @@ -Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License (CC BY-NC-SA 4.0) - -Copyright © 2020 ApacheCN(apachecn@163.com) - -By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. - -Section 1 – Definitions. - -a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. -b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. -c. BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. -d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. -e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. -f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. -g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike. -h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. -i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. -j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. -k. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. -l. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. -m. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. -n. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. - -Section 2 – Scope. - -a. License grant. - 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: - A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and - B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. - 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. - 3. Term. The term of this Public License is specified in Section 6(a). - 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. - 5. Downstream recipients. - A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. - B. Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. - C. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. - 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). -b. Other rights. - 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. - 2. Patent and trademark rights are not licensed under this Public License. - 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. - -Section 3 – License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the following conditions. - -a. Attribution. - 1. If You Share the Licensed Material (including in modified form), You must: - A. retain the following if it is supplied by the Licensor with the Licensed Material: - i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); - ii. a copyright notice; - iii. a notice that refers to this Public License; - iv. a notice that refers to the disclaimer of warranties; - v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; - B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and - C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. - 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. - 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. -b. ShareAlike. - In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. - 1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License. - 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. - 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. - -Section 4 – Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: - -a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; -b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and -c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. - -Section 5 – Disclaimer of Warranties and Limitation of Liability. - -a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. -b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. -c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. - -Section 6 – Term and Termination. - -a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. -b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: - 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or - 2. upon express reinstatement by the Licensor. - For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. -c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. -d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. - -Section 7 – Other Terms and Conditions. - -a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. -b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. - -Section 8 – Interpretation. - -a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. -b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. -c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. -d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. \ No newline at end of file + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index 5bd38a6a..48859dca 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,126 @@

-

Interview——IT 行业应试学知识库

+

Interview

+## 组织介绍 -> 程序员的双手是魔术师的双手,他们把枯燥无味的代码变成了丰富多彩的软件。——《疯狂的程序员》 +* 我们不是 Apache 的官方组织/机构/团体,只是 Apache 技术栈(以及 AI)的爱好者! +* 合作or侵权,请联系: apachecn@163.com +* [ApacheCN 组织资源](https://www.ibooker.org.cn/docs): +* **ApacheCN - 面试求职群【724187166】ApacheCN - 面试求职群[724187166]** -## 在线阅读 +> **欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远** -* 网址: https://interview.apachecn.org +## 参与须知 + +* 熟悉: [GitHub 入门操作指南](docs/GitHub/README.md) + +## 面试指南 + +> 简历直播系列 + +* 专栏: https://space.bilibili.com/97678687/channel/detail?cid=76174 +* 视频: https://www.bilibili.com/video/av53122083 + +## 面试经验 + +> 非组织链接推荐: + +* [【大数据面经】](https://github.com/WadeStack/BigDataIE) + +## [算法刷题](https://github.com/apachecn/Interview/tree/master/docs/Algorithm) + +1. [Leetcode](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode) + - [Python](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/Python) + - [Java](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/Java) + - [JavaScript](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/JavaScript) + - [C++](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/C++) + - [ipynb](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/ipynb) + - [GO](https://github.com/aQuaYi/LeetCode-in-Go) +2. [剑指 Offer](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer) + - [Python](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/Python) + - [Scala](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/Scala) + - [Java](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/Java) + - [JavaScript](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/JavaScript) + - [C++](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/C++) +2. [Algorithm Implementation](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure) + - [Python](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure/Python) + - [Java](https://github.com/apachecn/Interview/tree/master/docs/DataStructure/Java) + - [JavaScript](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure/JavaScript) + - [C++](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure/C++) + +> 非组织链接推荐: + +* [【2019年 阿里,腾讯,百度,美团,头条等技术面试题目,以及答案,专家出题人分析汇总。】](https://github.com/0voice/interview_internal_reference) + +## Kaggle + +### Kaggle直播系列 + +* 比赛专栏: +* 入门视频: + +> 比赛直播系列 + +* [视频: 2019ICME 抖音视频理解 top2 solution 分享及 数据比赛入门讲解](https://www.bilibili.com/video/av57385532) +* [文档: icme2019-top2.pptx](docs/简历指南/icme2019-top2.pptx) +* [昊神GitHub地址: https://github.com/Smilexuhc](https://github.com/Smilexuhc) +* [昊神整理比赛系列: https://github.com/Smilexuhc/Data-Competition-TopSolution](https://github.com/Smilexuhc/Data-Competition-TopSolution) + +## Kaggle教程文档 + +> 入门须知 + +* [GitHub 入门操作指南](docs/GitHub/README.md) +* [Kaggle 入门操作指南](docs/kaggle-quickstart.md) +* [AiLearning 机器学习 + 深度学习 + NLP](https://github.com/apachecn/AiLearning) + +> 项目实战: + +* [【Kaggle项目文档和项目代码: 点击查看全部】](https://github.com/apachecn/Interview/tree/master/docs/Kaggle) + +## 资料来源: + +* 【比赛收集平台】: + +## 联系方式 + +> 第一期 (2018-01-01) + +* [@片刻](https://github.com/jiangzhonglian) +* [@那伊抹微笑](https://github.com/wangyangting) +* [@瑶妹](https://github.com/chenyyx) +* [@loveSnowBest](https://github.com/zehuichen123) +* [@谈笑风生](https://github.com/zhu1040028623) +* [@诺木人](https://github.com/1mrliu) +* [@飞龙](https://github.com/wizardforcel) + +> 第二期 (2019-07-17) + +* [@片刻](https://github.com/jiangzhonglian) +* [@飞龙](https://github.com/wizardforcel) +* [@yudaer](https://github.com/yudaer) +* [@xixici](https://github.com/xixici) +* 空缺量很大,欢迎 + +-- 负责人要求: (欢迎一起为 求职面试 中文版本 做贡献) + +* 热爱开源,喜欢装逼 +* 擅长:刷题、面试、或职场套路 +* 能够有时间及时优化页面bug和用户issues +* 试用期: 2个月 +* 欢迎联系: 片刻 529815144 + +## 免责声明 - 【只供学习参考】 + +* ApacheCN 纯粹出于学习目的与个人兴趣整理 +* ApacheCN 保留对此版本译文的署名权及其它相关权利 ## **协议** -[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) +* 以各项目协议为准。 +* ApacheCN 账号下没有协议的项目,一律视为 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)。 ## 赞助我们 @@ -27,7 +135,6 @@ --- - + diff --git a/SUMMARY.md b/SUMMARY.md deleted file mode 100644 index 99f2f79a..00000000 --- a/SUMMARY.md +++ /dev/null @@ -1,37 +0,0 @@ -+ [Introduction](README.md) -+ 面试求职 - + [简历](docs/面试求职/简历.md) - + [简历范文](docs/面试求职/简历范文.md) - + [学历](docs/面试求职/学历.md) - + [刷题](docs/面试求职/刷题.md) - + [公司](docs/面试求职/公司.md) - + [职场](docs/面试求职/职场.md) - + [理财](docs/面试求职/理财.md) - + [年龄](docs/面试求职/年龄.md) -+ [算法刷题](docs/Algorithm/README.md) - + [数据结构](docs/Algorithm/DataStructure/README.md) - + [LeetCode C++ 版本↗](https://algo.apachecn.org/#/docs/leetcode/cpp/README) - + [LeetCode Java 版本↗](https://algo.apachecn.org/#/docs/leetcode/java/README) - + [LeetCode Python 版本↗](https://algo.apachecn.org/#/docs/leetcode/python/README) - + [LeetCode JavaScript 版本↗](https://algo.apachecn.org/#/docs/leetcode/javascript/README) - + [剑指offer↗](https://algo.apachecn.org/#/docs/jianzhioffer/java/README) -+ [IT 八股文↗](https://bgww.apachecn.org/#/) -+ [Kaggle比赛](docs/Kaggle/README.md) - + [Kernel 备份(一)↗](https://github.com/it-ebooks-0/kaggle-kernel-pt1) - + [Kernel 备份(二)↗](https://github.com/it-ebooks-0/kaggle-kernel-pt2) - + [Kernel 备份(三)↗](https://github.com/it-ebooks-0/kaggle-kernel-pt3) - + [Kernel 备份(四)↗](https://github.com/it-ebooks-0/kaggle-kernel-pt4) -+ 职业认证 - + [AQF↗](https://github.com/apachecn/interview-books/tree/master/AQF) - + [CCNA/NP/IE↗](https://github.com/apachecn/interview-books/tree/master/CCNA-NP-IE) - + [CEH↗](https://github.com/apachecn/interview-books/tree/master/CEH) - + [PMP↗](https://github.com/apachecn/interview-books/tree/master/PMP) -+ [职位数据库↗](https://github.com/apachecn/interview-books/tree/master/%E8%81%8C%E4%BD%8D%E6%95%B0%E6%8D%AE%E5%BA%93) -+ [面试译文集↗](https://itvw.apachecn.org) -+ [牛客面试题库↗](https://github.com/apachecn/interview-books/tree/master/NowCoder) -+ [GitHub快速入门](docs/GitHub/README.md) -+ [导师评价网备份↗](https://rms.apachecn.org/#/) -+ [校招污点公司记录↗](https://github.com/ShameCom/ShameCom) -+ [独立开发/自由职业/远程工作/数字游民知识库↗](https://idw.apachecn.org/#/) -+ [贡献者名单](CONTRIBUTORS.md) - diff --git a/asset/back-to-top.css b/asset/back-to-top.css deleted file mode 100644 index bcb3d5a7..00000000 --- a/asset/back-to-top.css +++ /dev/null @@ -1,19 +0,0 @@ -#scroll-btn { - position: fixed; - right: 15px; - bottom: 10px; - width: 35px; - height: 35px; - background-repeat: no-repeat; - background-size: cover; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-image: url(up.svg); - background-position-y: -1px; - display: none; - border: 2px solid; - border-radius: 4px; -} \ No newline at end of file diff --git a/asset/back-to-top.js b/asset/back-to-top.js deleted file mode 100644 index 3efad9be..00000000 --- a/asset/back-to-top.js +++ /dev/null @@ -1,20 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - var scrollBtn = document.createElement('div') - scrollBtn.id = 'scroll-btn' - document.body.append(scrollBtn) - - window.addEventListener('scroll', function() { - var offset = window.document.documentElement.scrollTop; - scrollBtn.style.display = offset >= 500 ? "block" : "none"; - }) - scrollBtn.addEventListener('click', function(e) { - e.stopPropagation(); - var step = window.scrollY / 15; - var hdl = setInterval(function() { - window.scrollTo(0, window.scrollY - step); - if(window.scrollY <= 0) { - clearInterval(hdl) - } - }, 15) - }) -}) \ No newline at end of file diff --git a/asset/dark-mode.css b/asset/dark-mode.css deleted file mode 100644 index 4aa47afc..00000000 --- a/asset/dark-mode.css +++ /dev/null @@ -1,23 +0,0 @@ -#dark-mode-btn { - position: fixed; - right: 15px; - top: 100px; - width: 35px; - height: 35px; - background-repeat: no-repeat; - background-size: cover; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - transition: background-image .15s ease-in-out .15s; -} - -.dark-logo { - background-image: url('sun.svg'); -} - -.light-logo { - background-image: url('moon.svg'); -} \ No newline at end of file diff --git a/asset/dark-mode.js b/asset/dark-mode.js deleted file mode 100644 index 471dcf80..00000000 --- a/asset/dark-mode.js +++ /dev/null @@ -1,42 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - var style = document.querySelector('#invert') - if (style == null) { - style = document.createElement('style') - style.id = 'invert' - document.head.append(style) - } - var btn = document.querySelector('#dark-mode-btn') - if (btn == null) { - btn = document.createElement('div') - btn.id = 'dark-mode-btn' - btn.classList.add('light-logo') - document.body.append(btn) - } - - var enableDarkMode = function() { - style.innerText = 'html,img,pre,#dark-mode-btn{filter:invert(100%)}' - btn.classList.remove('light-logo') - btn.classList.add('dark-logo') - localStorage.darkLight = 'dark' - - } - var disableDarkMode = function() { - style.innerText = '' - btn.classList.remove('dark-logo') - btn.classList.add('light-logo') - localStorage.darkLight = 'light' - } - - btn.addEventListener('click', function(){ - var currMode = localStorage.darkLight || 'light' - if (currMode == 'light') - enableDarkMode() - else - disableDarkMode() - }) - - if (localStorage.darkLight == 'dark') - enableDarkMode() - -}) - diff --git a/asset/docsify-apachecn-footer.js b/asset/docsify-apachecn-footer.js deleted file mode 100644 index 0723a6b4..00000000 --- a/asset/docsify-apachecn-footer.js +++ /dev/null @@ -1,34 +0,0 @@ -(function(){ - var cnzzId = window.$docsify.cnzzId - var unRepo = window.$docsify.repo || '' - var [un, repo] = unRepo.split('/') - var footer = ` -
-
-

我们一直在努力

-

${unRepo}

-

- - - iBooker 面试求职

-

-
- -
-
- ` - var plugin = function(hook) { - hook.afterEach(function(html) { - return html + footer - }) - hook.doneEach(function() { - (adsbygoogle = window.adsbygoogle || []).push({}) - }) - } - var plugins = window.$docsify.plugins || [] - plugins.push(plugin) - window.$docsify.plugins = plugins -})() \ No newline at end of file diff --git a/asset/docsify-baidu-push.js b/asset/docsify-baidu-push.js deleted file mode 100644 index 27b1f742..00000000 --- a/asset/docsify-baidu-push.js +++ /dev/null @@ -1,13 +0,0 @@ -(function(){ - var plugin = function(hook) { - hook.doneEach(function() { - new Image().src = - '//api.share.baidu.com/s.gif?r=' + - encodeURIComponent(document.referrer) + - "&l=" + encodeURIComponent(location.href) - }) - } - var plugins = window.$docsify.plugins || [] - plugins.push(plugin) - window.$docsify.plugins = plugins -})() \ No newline at end of file diff --git a/asset/docsify-baidu-stat.js b/asset/docsify-baidu-stat.js deleted file mode 100644 index 811aa35f..00000000 --- a/asset/docsify-baidu-stat.js +++ /dev/null @@ -1,13 +0,0 @@ -(function(){ - var plugin = function(hook) { - hook.doneEach(function() { - window._hmt = window._hmt || [] - var hm = document.createElement("script") - hm.src = "https://hm.baidu.com/hm.js?" + window.$docsify.bdStatId - document.querySelector("article").appendChild(hm) - }) - } - var plugins = window.$docsify.plugins || [] - plugins.push(plugin) - window.$docsify.plugins = plugins -})() \ No newline at end of file diff --git a/asset/docsify-clicker.js b/asset/docsify-clicker.js deleted file mode 100644 index 1b2a5729..00000000 --- a/asset/docsify-clicker.js +++ /dev/null @@ -1,197 +0,0 @@ -(function() { - var ids = [ - '109577065', '108852955', '102682374', '100520874', '92400861', '90312982', - '109963325', '109323014', '109301511', '108898970', '108590722', '108538676', - '108503526', '108437109', '108402202', '108292691', '108291153', '108268498', - '108030854', '107867070', '107847299', '107827334', '107825454', '107802131', - '107775320', '107752974', '107735139', '107702571', '107598864', '107584507', - '107568311', '107526159', '107452391', '107437455', '107430050', '107395781', - '107325304', '107283210', '107107145', '107085440', '106995421', '106993460', - '106972215', '106959775', '106766787', '106749609', '106745967', '106634313', - '106451602', '106180097', '106095505', '106077010', '106008089', '106002346', - '105653809', '105647855', '105130705', '104837872', '104706815', '104192620', - '104074941', '104040537', '103962171', '103793502', '103783460', '103774572', - '103547748', '103547703', '103547571', '103490757', '103413481', '103341935', - '103330191', '103246597', '103235808', '103204403', '103075981', '103015105', - '103014899', '103014785', '103014702', '103014540', '102993780', '102993754', - '102993680', '102958443', '102913317', '102903382', '102874766', '102870470', - '102864513', '102811179', '102761237', '102711565', '102645443', '102621845', - '102596167', '102593333', '102585262', '102558427', '102537547', '102530610', - '102527017', '102504698', '102489806', '102372981', '102258897', '102257303', - '102056248', '101920097', '101648638', '101516708', '101350577', '101268149', - '101128167', '101107328', '101053939', '101038866', '100977414', '100945061', - '100932401', '100886407', '100797378', '100634918', '100588305', '100572447', - '100192249', '100153559', '100099032', '100061455', '100035392', '100033450', - '99671267', '99624846', '99172551', '98992150', '98989508', '98987516', '98938304', - '98937682', '98725145', '98521688', '98450861', '98306787', '98203342', '98026348', - '97680167', '97492426', '97108940', '96888872', '96568559', '96509100', '96508938', - '96508611', '96508374', '96498314', '96476494', '96333593', '96101522', '95989273', - '95960507', '95771870', '95770611', '95766810', '95727700', '95588929', '95218707', - '95073151', '95054615', '95016540', '94868371', '94839549', '94719281', '94401578', - '93931439', '93853494', '93198026', '92397889', '92063437', '91635930', '91433989', - '91128193', '90915507', '90752423', '90738421', '90725712', '90725083', '90722238', - '90647220', '90604415', '90544478', '90379769', '90288341', '90183695', '90144066', - '90108283', '90021771', '89914471', '89876284', '89852050', '89839033', '89812373', - '89789699', '89786189', '89752620', '89636380', '89632889', '89525811', '89480625', - '89464088', '89464025', '89463984', '89463925', '89445280', '89441793', '89430432', - '89429877', '89416176', '89412750', '89409618', '89409485', '89409365', '89409292', - '89409222', '89399738', '89399674', '89399526', '89355336', '89330241', '89308077', - '89222240', '89140953', '89139942', '89134398', '89069355', '89049266', '89035735', - '89004259', '88925790', '88925049', '88915838', '88912706', '88911548', '88899438', - '88878890', '88837519', '88832555', '88824257', '88777952', '88752158', '88659061', - '88615256', '88551434', '88375675', '88322134', '88322085', '88321996', '88321978', - '88321950', '88321931', '88321919', '88321899', '88321830', '88321756', '88321710', - '88321661', '88321632', '88321566', '88321550', '88321506', '88321475', '88321440', - '88321409', '88321362', '88321321', '88321293', '88321226', '88232699', '88094874', - '88090899', '88090784', '88089091', '88048808', '87938224', '87913318', '87905933', - '87897358', '87856753', '87856461', '87827666', '87822008', '87821456', '87739137', - '87734022', '87643633', '87624617', '87602909', '87548744', '87548689', '87548624', - '87548550', '87548461', '87463201', '87385913', '87344048', '87078109', '87074784', - '87004367', '86997632', '86997466', '86997303', '86997116', '86996474', '86995899', - '86892769', '86892654', '86892569', '86892457', '86892347', '86892239', '86892124', - '86798671', '86777307', '86762845', '86760008', '86759962', '86759944', '86759930', - '86759922', '86759646', '86759638', '86759633', '86759622', '86759611', '86759602', - '86759596', '86759591', '86759580', '86759572', '86759567', '86759558', '86759545', - '86759534', '86749811', '86741502', '86741074', '86741059', '86741020', '86740897', - '86694754', '86670104', '86651882', '86651875', '86651866', '86651828', '86651790', - '86651767', '86651756', '86651735', '86651720', '86651708', '86618534', '86618526', - '86594785', '86590937', '86550497', '86550481', '86550472', '86550453', '86550438', - '86550429', '86550407', '86550381', '86550359', '86536071', '86536035', '86536014', - '86535988', '86535963', '86535953', '86535932', '86535902', '86472491', '86472298', - '86472236', '86472191', '86472108', '86471967', '86471899', '86471822', '86439022', - '86438972', '86438902', '86438887', '86438867', '86438836', '86438818', '85850119', - '85850075', '85850021', '85849945', '85849893', '85849837', '85849790', '85849740', - '85849661', '85849620', '85849550', '85606096', '85564441', '85547709', '85471981', - '85471317', '85471136', '85471073', '85470629', '85470456', '85470169', '85469996', - '85469877', '85469775', '85469651', '85469331', '85469033', '85345768', '85345742', - '85337900', '85337879', '85337860', '85337833', '85337797', '85322822', '85322810', - '85322791', '85322745', '85317667', '85265742', '85265696', '85265618', '85265350', - '85098457', '85057670', '85009890', '84755581', '84637437', '84637431', '84637393', - '84637374', '84637355', '84637338', '84637321', '84637305', '84637283', '84637259', - '84629399', '84629314', '84629233', '84629124', '84629065', '84628997', '84628933', - '84628838', '84628777', '84628690', '84591581', '84591553', '84591511', '84591484', - '84591468', '84591416', '84591386', '84591350', '84591308', '84572155', '84572107', - '84503228', '84500221', '84403516', '84403496', '84403473', '84403442', '84075703', - '84029659', '83933480', '83933459', '83933435', '83903298', '83903274', '83903258', - '83752369', '83345186', '83116487', '83116446', '83116402', '83116334', '83116213', - '82944248', '82941023', '82938777', '82936611', '82932735', '82918102', '82911085', - '82888399', '82884263', '82883507', '82880996', '82875334', '82864060', '82831039', - '82823385', '82795277', '82790832', '82775718', '82752022', '82730437', '82718126', - '82661646', '82588279', '82588267', '82588261', '82588192', '82347066', '82056138', - '81978722', '81211571', '81104145', '81069048', '81006768', '80788365', '80767582', - '80759172', '80759144', '80759129', '80736927', '80661288', '80616304', '80602366', - '80584625', '80561364', '80549878', '80549875', '80541470', '80539726', '80531328', - '80513257', '80469816', '80406810', '80356781', '80334130', '80333252', '80332666', - '80332389', '80311244', '80301070', '80295974', '80292252', '80286963', '80279504', - '80278369', '80274371', '80249825', '80247284', '80223054', '80219559', '80209778', - '80200279', '80164236', '80160900', '80153046', '80149560', '80144670', '80061205', - '80046520', '80025644', '80014721', '80005213', '80004664', '80001653', '79990178', - '79989283', '79947873', '79946002', '79941517', '79938786', '79932755', '79921178', - '79911339', '79897603', '79883931', '79872574', '79846509', '79832150', '79828161', - '79828156', '79828149', '79828146', '79828140', '79828139', '79828135', '79828123', - '79820772', '79776809', '79776801', '79776788', '79776782', '79776772', '79776767', - '79776760', '79776753', '79776736', '79776705', '79676183', '79676171', '79676166', - '79676160', '79658242', '79658137', '79658130', '79658123', '79658119', '79658112', - '79658100', '79658092', '79658089', '79658069', '79658054', '79633508', '79587857', - '79587850', '79587842', '79587831', '79587825', '79587819', '79547908', '79477700', - '79477692', '79440956', '79431176', '79428647', '79416896', '79406699', '79350633', - '79350545', '79344765', '79339391', '79339383', '79339157', '79307345', '79293944', - '79292623', '79274443', '79242798', '79184420', '79184386', '79184355', '79184269', - '79183979', '79100314', '79100206', '79100064', '79090813', '79057834', '78967246', - '78941571', '78927340', '78911467', '78909741', '78848006', '78628917', '78628908', - '78628889', '78571306', '78571273', '78571253', '78508837', '78508791', '78448073', - '78430940', '78408150', '78369548', '78323851', '78314301', '78307417', '78300457', - '78287108', '78278945', '78259349', '78237192', '78231360', '78141031', '78100357', - '78095793', '78084949', '78073873', '78073833', '78067868', '78067811', '78055014', - '78041555', '78039240', '77948804', '77879624', '77837792', '77824937', '77816459', - '77816208', '77801801', '77801767', '77776636', '77776610', '77505676', '77485156', - '77478296', '77460928', '77327521', '77326428', '77278423', '77258908', '77252370', - '77248841', '77239042', '77233843', '77230880', '77200256', '77198140', '77196405', - '77193456', '77186557', '77185568', '77181823', '77170422', '77164604', '77163389', - '77160103', '77159392', '77150721', '77146204', '77141824', '77129604', '77123259', - '77113014', '77103247', '77101924', '77100165', '77098190', '77094986', '77088637', - '77073399', '77062405', '77044198', '77036923', '77017092', '77007016', '76999924', - '76977678', '76944015', '76923087', '76912696', '76890184', '76862282', '76852434', - '76829683', '76794256', '76780755', '76762181', '76732277', '76718569', '76696048', - '76691568', '76689003', '76674746', '76651230', '76640301', '76615315', '76598528', - '76571947', '76551820', '74178127', '74157245', '74090991', '74012309', '74001789', - '73910511', '73613471', '73605647', '73605082', '73503704', '73380636', '73277303', - '73274683', '73252108', '73252085', '73252070', '73252039', '73252025', '73251974', - '73135779', '73087531', '73044025', '73008658', '72998118', '72997953', '72847091', - '72833384', '72830909', '72828999', '72823633', '72793092', '72757626', '71157154', - '71131579', '71128551', '71122253', '71082760', '71078326', '71075369', '71057216', - '70812997', '70384625', '70347260', '70328937', '70313267', '70312950', '70255825', - '70238893', '70237566', '70237072', '70230665', '70228737', '70228729', '70175557', - '70175401', '70173259', '70172591', '70170835', '70140724', '70139606', '70053923', - '69067886', '69063732', '69055974', '69055708', '69031254', '68960022', '68957926', - '68957556', '68953383', '68952755', '68946828', '68483371', '68120861', '68065606', - '68064545', '68064493', '67646436', '67637525', '67632961', '66984317', '66968934', - '66968328', '66491589', '66475786', '66473308', '65946462', '65635220', '65632553', - '65443309', '65437683', '63260222', '63253665', '63253636', '63253628', '63253610', - '63253572', '63252767', '63252672', '63252636', '63252537', '63252440', '63252329', - '63252155', '62888876', '62238064', '62039365', '62038016', '61925813', '60957024', - '60146286', '59523598', '59489460', '59480461', '59160354', '59109234', '59089006', - '58595549', '57406062', '56678797', '55001342', '55001340', '55001336', '55001330', - '55001328', '55001325', '55001311', '55001305', '55001298', '55001290', '55001283', - '55001278', '55001272', '55001265', '55001262', '55001253', '55001246', '55001242', - '55001236', '54907997', '54798827', '54782693', '54782689', '54782688', '54782676', - '54782673', '54782671', '54782662', '54782649', '54782636', '54782630', '54782628', - '54782627', '54782624', '54782621', '54782620', '54782615', '54782613', '54782608', - '54782604', '54782600', '54767237', '54766779', '54755814', '54755674', '54730253', - '54709338', '54667667', '54667657', '54667639', '54646201', '54407212', '54236114', - '54234220', '54233181', '54232788', '54232407', '54177960', '53991319', '53932970', - '53888106', '53887128', '53885944', '53885094', '53884497', '53819985', '53812640', - '53811866', '53790628', '53785053', '53782838', '53768406', '53763191', '53763163', - '53763148', '53763104', '53763092', '53576302', '53576157', '53573472', '53560183', - '53523648', '53516634', '53514474', '53510917', '53502297', '53492224', '53467240', - '53467122', '53437115', '53436579', '53435710', '53415115', '53377875', '53365337', - '53350165', '53337979', '53332925', '53321283', '53318758', '53307049', '53301773', - '53289364', '53286367', '53259948', '53242892', '53239518', '53230890', '53218625', - '53184121', '53148662', '53129280', '53116507', '53116486', '52980893', '52980652', - '52971002', '52950276', '52950259', '52944714', '52934397', '52932994', '52924939', - '52887083', '52877145', '52858258', '52858046', '52840214', '52829673', '52818774', - '52814054', '52805448', '52798019', '52794801', '52786111', '52774750', '52748816', - '52745187', '52739313', '52738109', '52734410', '52734406', '52734401', '52515005', - '52056818', '52039757', '52034057', '50899381', '50738883', '50726018', '50695984', - '50695978', '50695961', '50695931', '50695913', '50695902', '50695898', '50695896', - '50695885', '50695852', '50695843', '50695829', '50643222', '50591997', '50561827', - '50550829', '50541472', '50527581', '50527317', '50527206', '50527094', '50526976', - '50525931', '50525764', '50518363', '50498312', '50493019', '50492927', '50492881', - '50492863', '50492772', '50492741', '50492688', '50492454', '50491686', '50491675', - '50491602', '50491550', '50491467', '50488409', '50485177', '48683433', '48679853', - '48678381', '48626023', '48623059', '48603183', '48599041', '48595555', '48576507', - '48574581', '48574425', '48547849', '48542371', '48518705', '48494395', '48493321', - '48491545', '48471207', '48471161', '48471085', '48468239', '48416035', '48415577', - '48415515', '48297597', '48225865', '48224037', '48223553', '48213383', '48211439', - '48206757', '48195685', '48193981', '48154955', '48128811', '48105995', '48105727', - '48105441', '48105085', '48101717', '48101691', '48101637', '48101569', '48101543', - '48085839', '48085821', '48085797', '48085785', '48085775', '48085765', '48085749', - '48085717', '48085687', '48085377', '48085189', '48085119', '48085043', '48084991', - '48084747', '48084139', '48084075', '48055511', '48055403', '48054259', '48053917', - '47378253', '47359989', '47344793', '47344083', '47336927', '47335827', '47316383', - '47315813', '47312213', '47295745', '47294471', '47259467', '47256015', '47255529', - '47253649', '47207791', '47206309', '47189383', '47172333', '47170495', '47166223', '47149681', '47146967', '47126915', '47126883', '47108297', '47091823', '47084039', - '47080883', '47058549', '47056435', '47054703', '47041395', '47035325', '47035143', - '47027547', '47016851', '47006665', '46854213', '46128743', '45035163', '43053503', - '41968283', '41958265', '40707993', '40706971', '40685165', '40684953', '40684575', - '40683867', '40683021', '39853417', '39806033', '39757139', '38391523', '37595169', - '37584503', '35696501', '29593529', '28100441', '27330071', '26950993', '26011757', - '26010983', '26010603', '26004793', '26003621', '26003575', '26003405', '26003373', - '26003307', '26003225', '26003189', '26002929', '26002863', '26002749', '26001477', - '25641541', '25414671', '25410705', '24973063', '20648491', '20621099', '17802317', - '17171597', '17141619', '17141381', '17139321', '17121903', '16898605', '16886449', - '14523439', '14104635', '14054225', '9317965' - ] - var urlb64 = 'aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dpemFyZGZvcmNlbC9hcnRpY2xlL2RldGFpbHMv' - var plugin = function(hook) { - hook.doneEach(function() { - for (var i = 0; i < 5; i++) { - var idx = Math.trunc(Math.random() * ids.length) - new Image().src = atob(urlb64) + ids[idx] - } - }) - } - var plugins = window.$docsify.plugins || [] - plugins.push(plugin) - window.$docsify.plugins = plugins -})() \ No newline at end of file diff --git a/asset/docsify-cnzz.js b/asset/docsify-cnzz.js deleted file mode 100644 index cbfda89e..00000000 --- a/asset/docsify-cnzz.js +++ /dev/null @@ -1,13 +0,0 @@ -(function(){ - var plugin = function(hook) { - hook.doneEach(function() { - var sc = document.createElement('script') - sc.src = 'https://s5.cnzz.com/z_stat.php?id=' + - window.$docsify.cnzzId + '&online=1&show=line' - document.querySelector('article').appendChild(sc) - }) - } - var plugins = window.$docsify.plugins || [] - plugins.push(plugin) - window.$docsify.plugins = plugins -})() \ No newline at end of file diff --git a/asset/docsify-copy-code.min.js b/asset/docsify-copy-code.min.js deleted file mode 100644 index dee84c79..00000000 --- a/asset/docsify-copy-code.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * docsify-copy-code - * v2.1.0 - * https://github.com/jperasmus/docsify-copy-code - * (c) 2017-2019 JP Erasmus - * MIT license - */ -!function(){"use strict";function r(o){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o})(o)}!function(o,e){void 0===e&&(e={});var t=e.insertAt;if(o&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],c=document.createElement("style");c.type="text/css","top"===t&&n.firstChild?n.insertBefore(c,n.firstChild):n.appendChild(c),c.styleSheet?c.styleSheet.cssText=o:c.appendChild(document.createTextNode(o))}}(".docsify-copy-code-button,.docsify-copy-code-button span{cursor:pointer;transition:all .25s ease}.docsify-copy-code-button{position:absolute;z-index:1;top:0;right:0;overflow:visible;padding:.65em .8em;border:0;border-radius:0;outline:0;font-size:1em;background:grey;background:var(--theme-color,grey);color:#fff;opacity:0}.docsify-copy-code-button span{border-radius:3px;background:inherit;pointer-events:none}.docsify-copy-code-button .error,.docsify-copy-code-button .success{position:absolute;z-index:-100;top:50%;left:0;padding:.5em .65em;font-size:.825em;opacity:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.docsify-copy-code-button.error .error,.docsify-copy-code-button.success .success{opacity:1;-webkit-transform:translate(-115%,-50%);transform:translate(-115%,-50%)}.docsify-copy-code-button:focus,pre:hover .docsify-copy-code-button{opacity:1}"),document.querySelector('link[href*="docsify-copy-code"]')&&console.warn("[Deprecation] Link to external docsify-copy-code stylesheet is no longer necessary."),window.DocsifyCopyCodePlugin={init:function(){return function(o,e){o.ready(function(){console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.")})}}},window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(o,s){o.doneEach(function(){var o=Array.apply(null,document.querySelectorAll("pre[data-lang]")),c={buttonText:"Copy to clipboard",errorText:"Error",successText:"Copied"};s.config.copyCode&&Object.keys(c).forEach(function(t){var n=s.config.copyCode[t];"string"==typeof n?c[t]=n:"object"===r(n)&&Object.keys(n).some(function(o){var e=-1',''.concat(c.buttonText,""),''.concat(c.errorText,""),''.concat(c.successText,""),""].join("");o.forEach(function(o){o.insertAdjacentHTML("beforeend",e)})}),o.mounted(function(){document.querySelector(".content").addEventListener("click",function(o){if(o.target.classList.contains("docsify-copy-code-button")){var e="BUTTON"===o.target.tagName?o.target:o.target.parentNode,t=document.createRange(),n=e.parentNode.querySelector("code"),c=window.getSelection();t.selectNode(n),c.removeAllRanges(),c.addRange(t);try{document.execCommand("copy")&&(e.classList.add("success"),setTimeout(function(){e.classList.remove("success")},1e3))}catch(o){console.error("docsify-copy-code: ".concat(o)),e.classList.add("error"),setTimeout(function(){e.classList.remove("error")},1e3)}"function"==typeof(c=window.getSelection()).removeRange?c.removeRange(t):"function"==typeof c.removeAllRanges&&c.removeAllRanges()}})})}].concat(window.$docsify.plugins||[])}(); -//# sourceMappingURL=docsify-copy-code.min.js.map diff --git a/asset/docsify-katex.js b/asset/docsify-katex.js deleted file mode 100644 index 7aaf102a..00000000 --- a/asset/docsify-katex.js +++ /dev/null @@ -1 +0,0 @@ -!function(t){var e={};function r(a){if(e[a])return e[a].exports;var n=e[a]={i:a,l:!1,exports:{}};return t[a].call(n.exports,n,n.exports,r),n.l=!0,n.exports}r.m=t,r.c=e,r.d=function(t,e,a){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:a})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var a=Object.create(null);if(r.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)r.d(a,n,function(e){return t[e]}.bind(null,n));return a},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=1)}([function(t,e,r){var a;"undefined"!=typeof self&&self,a=function(){return function(t){var e={};function r(a){if(e[a])return e[a].exports;var n=e[a]={i:a,l:!1,exports:{}};return t[a].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=t,r.c=e,r.d=function(t,e,a){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:a})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var a=Object.create(null);if(r.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)r.d(a,n,function(e){return t[e]}.bind(null,n));return a},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=1)}([function(t,e,r){},function(t,e,r){"use strict";r.r(e),r(0);var a=function(){function t(t,e,r){this.lexer=void 0,this.start=void 0,this.end=void 0,this.lexer=t,this.start=e,this.end=r}return t.range=function(e,r){return r?e&&e.loc&&r.loc&&e.loc.lexer===r.loc.lexer?new t(e.loc.lexer,e.loc.start,r.loc.end):null:e&&e.loc},t}(),n=function(){function t(t,e){this.text=void 0,this.loc=void 0,this.text=t,this.loc=e}return t.prototype.range=function(e,r){return new t(r,a.range(this,e))},t}(),i=function t(e,r){this.position=void 0;var a,n="KaTeX parse error: "+e,i=r&&r.loc;if(i&&i.start<=i.end){var o=i.lexer.input;a=i.start;var s=i.end;a===o.length?n+=" at end of input: ":n+=" at position "+(a+1)+": ";var h=o.slice(a,s).replace(/[^]/g,"$&̲");n+=(a>15?"…"+o.slice(a-15,a):o.slice(0,a))+h+(s+15":">","<":"<",'"':""","'":"'"},l=/[&><"']/g,m=function t(e){return"ordgroup"===e.type||"color"===e.type?1===e.body.length?t(e.body[0]):e:"font"===e.type?t(e.body):e},c={contains:function(t,e){return-1!==t.indexOf(e)},deflt:function(t,e){return void 0===t?e:t},escape:function(t){return String(t).replace(l,(function(t){return h[t]}))},hyphenate:function(t){return t.replace(s,"-$1").toLowerCase()},getBaseElem:m,isCharacterBox:function(t){var e=m(t);return"mathord"===e.type||"textord"===e.type||"atom"===e.type},protocolFromUrl:function(t){var e=/^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(t);return null!=e?e[1]:"_relative"}},u=function(){function t(t){this.displayMode=void 0,this.output=void 0,this.leqno=void 0,this.fleqn=void 0,this.throwOnError=void 0,this.errorColor=void 0,this.macros=void 0,this.minRuleThickness=void 0,this.colorIsTextColor=void 0,this.strict=void 0,this.trust=void 0,this.maxSize=void 0,this.maxExpand=void 0,t=t||{},this.displayMode=c.deflt(t.displayMode,!1),this.output=c.deflt(t.output,"htmlAndMathml"),this.leqno=c.deflt(t.leqno,!1),this.fleqn=c.deflt(t.fleqn,!1),this.throwOnError=c.deflt(t.throwOnError,!0),this.errorColor=c.deflt(t.errorColor,"#cc0000"),this.macros=t.macros||{},this.minRuleThickness=Math.max(0,c.deflt(t.minRuleThickness,0)),this.colorIsTextColor=c.deflt(t.colorIsTextColor,!1),this.strict=c.deflt(t.strict,"warn"),this.trust=c.deflt(t.trust,!1),this.maxSize=Math.max(0,c.deflt(t.maxSize,1/0)),this.maxExpand=Math.max(0,c.deflt(t.maxExpand,1e3))}var e=t.prototype;return e.reportNonstrict=function(t,e,r){var a=this.strict;if("function"==typeof a&&(a=a(t,e,r)),a&&"ignore"!==a){if(!0===a||"error"===a)throw new o("LaTeX-incompatible input and strict mode is set to 'error': "+e+" ["+t+"]",r);"warn"===a?"undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+e+" ["+t+"]"):"undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to unrecognized '"+a+"': "+e+" ["+t+"]")}},e.useStrictBehavior=function(t,e,r){var a=this.strict;if("function"==typeof a)try{a=a(t,e,r)}catch(t){a="error"}return!(!a||"ignore"===a||!0!==a&&"error"!==a&&("warn"===a?("undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+e+" ["+t+"]"),1):("undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to unrecognized '"+a+"': "+e+" ["+t+"]"),1)))},e.isTrusted=function(t){t.url&&!t.protocol&&(t.protocol=c.protocolFromUrl(t.url));var e="function"==typeof this.trust?this.trust(t):this.trust;return Boolean(e)},t}(),p=function(){function t(t,e,r){this.id=void 0,this.size=void 0,this.cramped=void 0,this.id=t,this.size=e,this.cramped=r}var e=t.prototype;return e.sup=function(){return d[f[this.id]]},e.sub=function(){return d[g[this.id]]},e.fracNum=function(){return d[x[this.id]]},e.fracDen=function(){return d[v[this.id]]},e.cramp=function(){return d[b[this.id]]},e.text=function(){return d[y[this.id]]},e.isTight=function(){return this.size>=2},t}(),d=[new p(0,0,!1),new p(1,0,!0),new p(2,1,!1),new p(3,1,!0),new p(4,2,!1),new p(5,2,!0),new p(6,3,!1),new p(7,3,!0)],f=[4,5,4,5,6,7,6,7],g=[5,5,5,5,7,7,7,7],x=[2,3,4,5,6,7,6,7],v=[3,3,5,5,7,7,7,7],b=[1,1,3,3,5,5,7,7],y=[0,1,2,3,2,3,2,3],w={DISPLAY:d[0],TEXT:d[2],SCRIPT:d[4],SCRIPTSCRIPT:d[6]},k=[{name:"latin",blocks:[[256,591],[768,879]]},{name:"cyrillic",blocks:[[1024,1279]]},{name:"brahmic",blocks:[[2304,4255]]},{name:"georgian",blocks:[[4256,4351]]},{name:"cjk",blocks:[[12288,12543],[19968,40879],[65280,65376]]},{name:"hangul",blocks:[[44032,55215]]}],S=[];function M(t){for(var e=0;e=S[e]&&t<=S[e+1])return!0;return!1}k.forEach((function(t){return t.blocks.forEach((function(t){return S.push.apply(S,t)}))}));var z={doubleleftarrow:"M262 157\nl10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3\n 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28\n 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5\nc2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5\n 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87\n-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7\n-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z\nm8 0v40h399730v-40zm0 194v40h399730v-40z",doublerightarrow:"M399738 392l\n-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5\n 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88\n-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68\n-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18\n-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782\nc-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3\n-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z",leftarrow:"M400000 241H110l3-3c68.7-52.7 113.7-120\n 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8\n-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247\nc-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208\n 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3\n 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202\n l-3-3h399890zM100 241v40h399900v-40z",leftbrace:"M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117\n-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7\n 5-6 9-10 13-.7 1-7.3 1-20 1H6z",leftbraceunder:"M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13\n 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688\n 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7\n-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z",leftgroup:"M400000 80\nH435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0\n 435 0h399565z",leftgroupunder:"M400000 262\nH435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219\n 435 219h399565z",leftharpoon:"M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3\n-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5\n-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7\n-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z",leftharpoonplus:"M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5\n 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3\n-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7\n-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z\nm0 0v40h400000v-40z",leftharpoondown:"M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333\n 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5\n 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667\n-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z",leftharpoondownplus:"M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12\n 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7\n-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0\nv40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z",lefthook:"M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5\n-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3\n-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21\n 71.5 23h399859zM103 281v-40h399897v40z",leftlinesegment:"M40 281 V428 H0 V94 H40 V241 H400000 v40z\nM40 281 V428 H0 V94 H40 V241 H400000 v40z",leftmapsto:"M40 281 V448H0V74H40V241H400000v40z\nM40 281 V448H0V74H40V241H400000v40z",leftToFrom:"M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23\n-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8\nc28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3\n 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z",longequal:"M0 50 h400000 v40H0z m0 194h40000v40H0z\nM0 50 h400000 v40H0z m0 194h40000v40H0z",midbrace:"M200428 334\nc-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14\n-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7\n 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11\n 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z",midbraceunder:"M199572 214\nc100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14\n 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3\n 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0\n-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z",oiintSize1:"M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6\n-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z\nm368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8\n60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z",oiintSize2:"M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8\n-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z\nm502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2\nc0 110 84 276 504 276s502.4-166 502.4-276z",oiiintSize1:"M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6\n-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z\nm525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0\n85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z",oiiintSize2:"M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8\n-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z\nm770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1\nc0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z",rightarrow:"M0 241v40h399891c-47.3 35.3-84 78-110 128\n-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20\n 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7\n 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85\n-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n 151.7 139 205zm0 0v40h399900v-40z",rightbrace:"M400000 542l\n-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5\ns-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1\nc124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z",rightbraceunder:"M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3\n 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237\n-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z",rightgroup:"M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0\n 3-1 3-3v-38c-76-158-257-219-435-219H0z",rightgroupunder:"M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18\n 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z",rightharpoon:"M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3\n-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2\n-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58\n 69.2 92 94.5zm0 0v40h399900v-40z",rightharpoonplus:"M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11\n-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7\n 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z\nm0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z",rightharpoondown:"M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8\n 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5\n-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95\n-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z",rightharpoondownplus:"M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8\n 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3\n 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3\n-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z\nm0-194v40h400000v-40zm0 0v40h400000v-40z",righthook:"M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3\n 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0\n-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21\n 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z",rightlinesegment:"M399960 241 V94 h40 V428 h-40 V281 H0 v-40z\nM399960 241 V94 h40 V428 h-40 V281 H0 v-40z",rightToFrom:"M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23\n 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32\n-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142\n-167z M100 147v40h399900v-40zM0 341v40h399900v-40z",twoheadleftarrow:"M0 167c68 40\n 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69\n-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3\n-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19\n-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101\n 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z",twoheadrightarrow:"M400000 167\nc-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3\n 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42\n 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333\n-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70\n 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z",tilde1:"M200 55.538c-77 0-168 73.953-177 73.953-3 0-7\n-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0\n 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0\n 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128\n-68.267.847-113-73.952-191-73.952z",tilde2:"M344 55.266c-142 0-300.638 81.316-311.5 86.418\n-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9\n 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114\nc1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751\n 181.476 676 181.476c-149 0-189-126.21-332-126.21z",tilde3:"M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457\n-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0\n 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697\n 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696\n -338 0-409-156.573-744-156.573z",tilde4:"M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345\n-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409\n 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9\n 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409\n -175.236-744-175.236z",vec:"M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5\n3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11\n10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63\n-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1\n-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59\nH213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359\nc-16-25.333-24-45-24-59z",widehat1:"M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22\nc-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z",widehat2:"M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widehat3:"M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widehat4:"M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widecheck1:"M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1,\n-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z",widecheck2:"M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",widecheck3:"M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",widecheck4:"M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",baraboveleftarrow:"M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202\nc4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5\nc-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130\ns-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47\n121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6\ns2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11\nc0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z\nM100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z",rightarrowabovebar:"M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32\n-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0\n13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39\n-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5\n-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z",baraboveshortleftharpoon:"M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17\nc2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21\nc-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40\nc-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z\nM0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z",rightharpoonaboveshortbar:"M0,241 l0,40c399126,0,399993,0,399993,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z",shortbaraboveleftharpoon:"M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9,\n1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7,\n-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z\nM93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z",shortrightharpoonabovebar:"M53,241l0,40c398570,0,399437,0,399437,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z"},A=function(){function t(t){this.children=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.children=t,this.classes=[],this.height=0,this.depth=0,this.maxFontSize=0,this.style={}}var e=t.prototype;return e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){for(var t=document.createDocumentFragment(),e=0;e"},N=function(){function t(t,e,r,a){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.width=void 0,this.maxFontSize=void 0,this.style=void 0,B.call(this,t,r,a),this.children=e||[]}var e=t.prototype;return e.setAttribute=function(t,e){this.attributes[t]=e},e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){return C.call(this,"span")},e.toMarkup=function(){return q.call(this,"span")},t}(),O=function(){function t(t,e,r,a){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,B.call(this,e,a),this.children=r||[],this.setAttribute("href",t)}var e=t.prototype;return e.setAttribute=function(t,e){this.attributes[t]=e},e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){return C.call(this,"a")},e.toMarkup=function(){return q.call(this,"a")},t}(),I=function(){function t(t,e,r){this.src=void 0,this.alt=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.alt=e,this.src=t,this.classes=["mord"],this.style=r}var e=t.prototype;return e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){var t=document.createElement("img");for(var e in t.src=this.src,t.alt=this.alt,t.className="mord",this.style)this.style.hasOwnProperty(e)&&(t.style[e]=this.style[e]);return t},e.toMarkup=function(){var t=""+this.alt+"=n[0]&&t<=n[1])return r.name}return null}(this.text.charCodeAt(0));h&&this.classes.push(h+"_fallback"),/[îïíì]/.test(this.text)&&(this.text=R[this.text])}var e=t.prototype;return e.hasClass=function(t){return c.contains(this.classes,t)},e.toNode=function(){var t=document.createTextNode(this.text),e=null;for(var r in this.italic>0&&((e=document.createElement("span")).style.marginRight=this.italic+"em"),this.classes.length>0&&((e=e||document.createElement("span")).className=T(this.classes)),this.style)this.style.hasOwnProperty(r)&&((e=e||document.createElement("span")).style[r]=this.style[r]);return e?(e.appendChild(t),e):t},e.toMarkup=function(){var t=!1,e="0&&(r+="margin-right:"+this.italic+"em;"),this.style)this.style.hasOwnProperty(a)&&(r+=c.hyphenate(a)+":"+this.style[a]+";");r&&(t=!0,e+=' style="'+c.escape(r)+'"');var n=c.escape(this.text);return t?(e+=">",e+=n,e+=""):n},t}(),L=function(){function t(t,e){this.children=void 0,this.attributes=void 0,this.children=t||[],this.attributes=e||{}}var e=t.prototype;return e.toNode=function(){var t=document.createElementNS("http://www.w3.org/2000/svg","svg");for(var e in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,e)&&t.setAttribute(e,this.attributes[e]);for(var r=0;r":""},t}(),H=function(){function t(t){this.attributes=void 0,this.attributes=t||{}}var e=t.prototype;return e.toNode=function(){var t=document.createElementNS("http://www.w3.org/2000/svg","line");for(var e in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,e)&&t.setAttribute(e,this.attributes[e]);return t},e.toMarkup=function(){var t="",">"),j("math",Z,et,":",":"),j("math",Z,et,"≈","\\approx",!0),j("math",Z,et,"≅","\\cong",!0),j("math",Z,et,"≥","\\ge"),j("math",Z,et,"≥","\\geq",!0),j("math",Z,et,"←","\\gets"),j("math",Z,et,">","\\gt"),j("math",Z,et,"∈","\\in",!0),j("math",Z,et,"","\\@not"),j("math",Z,et,"⊂","\\subset",!0),j("math",Z,et,"⊃","\\supset",!0),j("math",Z,et,"⊆","\\subseteq",!0),j("math",Z,et,"⊇","\\supseteq",!0),j("math",K,et,"⊈","\\nsubseteq",!0),j("math",K,et,"⊉","\\nsupseteq",!0),j("math",Z,et,"⊨","\\models"),j("math",Z,et,"←","\\leftarrow",!0),j("math",Z,et,"≤","\\le"),j("math",Z,et,"≤","\\leq",!0),j("math",Z,et,"<","\\lt"),j("math",Z,et,"→","\\rightarrow",!0),j("math",Z,et,"→","\\to"),j("math",K,et,"≱","\\ngeq",!0),j("math",K,et,"≰","\\nleq",!0),j("math",Z,"spacing"," ","\\ "),j("math",Z,"spacing"," ","~"),j("math",Z,"spacing"," ","\\space"),j("math",Z,"spacing"," ","\\nobreakspace"),j("text",Z,"spacing"," ","\\ "),j("text",Z,"spacing"," ","~"),j("text",Z,"spacing"," ","\\space"),j("text",Z,"spacing"," ","\\nobreakspace"),j("math",Z,"spacing",null,"\\nobreak"),j("math",Z,"spacing",null,"\\allowbreak"),j("math",Z,"punct",",",","),j("math",Z,"punct",";",";"),j("math",K,J,"⊼","\\barwedge",!0),j("math",K,J,"⊻","\\veebar",!0),j("math",Z,J,"⊙","\\odot",!0),j("math",Z,J,"⊕","\\oplus",!0),j("math",Z,J,"⊗","\\otimes",!0),j("math",Z,"textord","∂","\\partial",!0),j("math",Z,J,"⊘","\\oslash",!0),j("math",K,J,"⊚","\\circledcirc",!0),j("math",K,J,"⊡","\\boxdot",!0),j("math",Z,J,"△","\\bigtriangleup"),j("math",Z,J,"▽","\\bigtriangledown"),j("math",Z,J,"†","\\dagger"),j("math",Z,J,"⋄","\\diamond"),j("math",Z,J,"⋆","\\star"),j("math",Z,J,"◃","\\triangleleft"),j("math",Z,J,"▹","\\triangleright"),j("math",Z,"open","{","\\{"),j("text",Z,"textord","{","\\{"),j("text",Z,"textord","{","\\textbraceleft"),j("math",Z,"close","}","\\}"),j("text",Z,"textord","}","\\}"),j("text",Z,"textord","}","\\textbraceright"),j("math",Z,"open","{","\\lbrace"),j("math",Z,"close","}","\\rbrace"),j("math",Z,"open","[","\\lbrack"),j("text",Z,"textord","[","\\lbrack"),j("math",Z,"close","]","\\rbrack"),j("text",Z,"textord","]","\\rbrack"),j("math",Z,"open","(","\\lparen"),j("math",Z,"close",")","\\rparen"),j("text",Z,"textord","<","\\textless"),j("text",Z,"textord",">","\\textgreater"),j("math",Z,"open","⌊","\\lfloor",!0),j("math",Z,"close","⌋","\\rfloor",!0),j("math",Z,"open","⌈","\\lceil",!0),j("math",Z,"close","⌉","\\rceil",!0),j("math",Z,"textord","\\","\\backslash"),j("math",Z,"textord","∣","|"),j("math",Z,"textord","∣","\\vert"),j("text",Z,"textord","|","\\textbar"),j("math",Z,"textord","∥","\\|"),j("math",Z,"textord","∥","\\Vert"),j("text",Z,"textord","∥","\\textbardbl"),j("text",Z,"textord","~","\\textasciitilde"),j("text",Z,"textord","\\","\\textbackslash"),j("text",Z,"textord","^","\\textasciicircum"),j("math",Z,et,"↑","\\uparrow",!0),j("math",Z,et,"⇑","\\Uparrow",!0),j("math",Z,et,"↓","\\downarrow",!0),j("math",Z,et,"⇓","\\Downarrow",!0),j("math",Z,et,"↕","\\updownarrow",!0),j("math",Z,et,"⇕","\\Updownarrow",!0),j("math",Z,tt,"∐","\\coprod"),j("math",Z,tt,"⋁","\\bigvee"),j("math",Z,tt,"⋀","\\bigwedge"),j("math",Z,tt,"⨄","\\biguplus"),j("math",Z,tt,"⋂","\\bigcap"),j("math",Z,tt,"⋃","\\bigcup"),j("math",Z,tt,"∫","\\int"),j("math",Z,tt,"∫","\\intop"),j("math",Z,tt,"∬","\\iint"),j("math",Z,tt,"∭","\\iiint"),j("math",Z,tt,"∏","\\prod"),j("math",Z,tt,"∑","\\sum"),j("math",Z,tt,"⨂","\\bigotimes"),j("math",Z,tt,"⨁","\\bigoplus"),j("math",Z,tt,"⨀","\\bigodot"),j("math",Z,tt,"∮","\\oint"),j("math",Z,tt,"∯","\\oiint"),j("math",Z,tt,"∰","\\oiiint"),j("math",Z,tt,"⨆","\\bigsqcup"),j("math",Z,tt,"∫","\\smallint"),j("text",Z,"inner","…","\\textellipsis"),j("math",Z,"inner","…","\\mathellipsis"),j("text",Z,"inner","…","\\ldots",!0),j("math",Z,"inner","…","\\ldots",!0),j("math",Z,"inner","⋯","\\@cdots",!0),j("math",Z,"inner","⋱","\\ddots",!0),j("math",Z,"textord","⋮","\\varvdots"),j("math",Z,"accent-token","ˊ","\\acute"),j("math",Z,"accent-token","ˋ","\\grave"),j("math",Z,"accent-token","¨","\\ddot"),j("math",Z,"accent-token","~","\\tilde"),j("math",Z,"accent-token","ˉ","\\bar"),j("math",Z,"accent-token","˘","\\breve"),j("math",Z,"accent-token","ˇ","\\check"),j("math",Z,"accent-token","^","\\hat"),j("math",Z,"accent-token","⃗","\\vec"),j("math",Z,"accent-token","˙","\\dot"),j("math",Z,"accent-token","˚","\\mathring"),j("math",Z,Q,"ı","\\imath",!0),j("math",Z,Q,"ȷ","\\jmath",!0),j("text",Z,"textord","ı","\\i",!0),j("text",Z,"textord","ȷ","\\j",!0),j("text",Z,"textord","ß","\\ss",!0),j("text",Z,"textord","æ","\\ae",!0),j("text",Z,"textord","æ","\\ae",!0),j("text",Z,"textord","œ","\\oe",!0),j("text",Z,"textord","ø","\\o",!0),j("text",Z,"textord","Æ","\\AE",!0),j("text",Z,"textord","Œ","\\OE",!0),j("text",Z,"textord","Ø","\\O",!0),j("text",Z,"accent-token","ˊ","\\'"),j("text",Z,"accent-token","ˋ","\\`"),j("text",Z,"accent-token","ˆ","\\^"),j("text",Z,"accent-token","˜","\\~"),j("text",Z,"accent-token","ˉ","\\="),j("text",Z,"accent-token","˘","\\u"),j("text",Z,"accent-token","˙","\\."),j("text",Z,"accent-token","˚","\\r"),j("text",Z,"accent-token","ˇ","\\v"),j("text",Z,"accent-token","¨",'\\"'),j("text",Z,"accent-token","˝","\\H"),j("text",Z,"accent-token","◯","\\textcircled");var rt={"--":!0,"---":!0,"``":!0,"''":!0};j("text",Z,"textord","–","--"),j("text",Z,"textord","–","\\textendash"),j("text",Z,"textord","—","---"),j("text",Z,"textord","—","\\textemdash"),j("text",Z,"textord","‘","`"),j("text",Z,"textord","‘","\\textquoteleft"),j("text",Z,"textord","’","'"),j("text",Z,"textord","’","\\textquoteright"),j("text",Z,"textord","“","``"),j("text",Z,"textord","“","\\textquotedblleft"),j("text",Z,"textord","”","''"),j("text",Z,"textord","”","\\textquotedblright"),j("math",Z,"textord","°","\\degree",!0),j("text",Z,"textord","°","\\degree"),j("text",Z,"textord","°","\\textdegree",!0),j("math",Z,Q,"£","\\pounds"),j("math",Z,Q,"£","\\mathsterling",!0),j("text",Z,Q,"£","\\pounds"),j("text",Z,Q,"£","\\textsterling",!0),j("math",K,"textord","✠","\\maltese"),j("text",K,"textord","✠","\\maltese"),j("text",Z,"spacing"," ","\\ "),j("text",Z,"spacing"," "," "),j("text",Z,"spacing"," ","~");for(var at=0;at<'0123456789/@."'.length;at++){var nt='0123456789/@."'.charAt(at);j("math",Z,"textord",nt,nt)}for(var it=0;it<'0123456789!@*()-=+[]<>|";:?/.,'.length;it++){var ot='0123456789!@*()-=+[]<>|";:?/.,'.charAt(it);j("text",Z,"textord",ot,ot)}for(var st="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",ht=0;ht=5?0:t>=3?1:2]){var r=Y[e]={cssEmPerMu:V.quad[e]/18};for(var a in V)V.hasOwnProperty(a)&&(r[a]=V[a][e])}return Y[e]}(this.size)),this._fontMetrics},e.getColor=function(){return this.phantom?"transparent":this.color},t}();kt.BASESIZE=6;var St=kt,Mt={pt:1,mm:7227/2540,cm:7227/254,in:72.27,bp:1.00375,pc:12,dd:1238/1157,cc:14856/1157,nd:685/642,nc:1370/107,sp:1/65536,px:1.00375},zt={ex:!0,em:!0,mu:!0},At=function(t){return"string"!=typeof t&&(t=t.unit),t in Mt||t in zt||"ex"===t},Tt=function(t,e){var r;if(t.unit in Mt)r=Mt[t.unit]/e.fontMetrics().ptPerEm/e.sizeMultiplier;else if("mu"===t.unit)r=e.fontMetrics().cssEmPerMu;else{var a;if(a=e.style.isTight()?e.havingStyle(e.style.text()):e,"ex"===t.unit)r=a.fontMetrics().xHeight;else{if("em"!==t.unit)throw new o("Invalid unit: '"+t.unit+"'");r=a.fontMetrics().quad}a!==e&&(r*=a.sizeMultiplier/e.sizeMultiplier)}return Math.min(t.number*r,e.maxSize)},Bt=["\\imath","ı","\\jmath","ȷ","\\pounds","\\mathsterling","\\textsterling","£"],Ct=function(t,e,r){return $[r][t]&&$[r][t].replace&&(t=$[r][t].replace),{value:t,metrics:G(t,e,r)}},qt=function(t,e,r,a,n){var i,o=Ct(t,e,r),s=o.metrics;if(t=o.value,s){var h=s.italic;("text"===r||a&&"mathit"===a.font)&&(h=0),i=new E(t,s.height,s.depth,h,s.skew,s.width,n)}else"undefined"!=typeof console&&console.warn("No character metrics for '"+t+"' in style '"+e+"' and mode '"+r+"'"),i=new E(t,0,0,0,0,0,n);if(a){i.maxFontSize=a.sizeMultiplier,a.style.isTight()&&i.classes.push("mtight");var l=a.getColor();l&&(i.style.color=l)}return i},Nt=function(t,e){if(T(t.classes)!==T(e.classes)||t.skew!==e.skew||t.maxFontSize!==e.maxFontSize)return!1;for(var r in t.style)if(t.style.hasOwnProperty(r)&&t.style[r]!==e.style[r])return!1;for(var a in e.style)if(e.style.hasOwnProperty(a)&&t.style[a]!==e.style[a])return!1;return!0},Ot=function(t){for(var e=0,r=0,a=0,n=0;ne&&(e=i.height),i.depth>r&&(r=i.depth),i.maxFontSize>a&&(a=i.maxFontSize)}t.height=e,t.depth=r,t.maxFontSize=a},It=function(t,e,r,a){var n=new N(t,e,r,a);return Ot(n),n},Rt=function(t,e,r,a){return new N(t,e,r,a)},Et=function(t){var e=new A(t);return Ot(e),e},Lt=function(t,e,r){var a="";switch(t){case"amsrm":a="AMS";break;case"textrm":a="Main";break;case"textsf":a="SansSerif";break;case"texttt":a="Typewriter";break;default:a=t}return a+"-"+("textbf"===e&&"textit"===r?"BoldItalic":"textbf"===e?"Bold":"textit"===e?"Italic":"Regular")},Pt={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathit:{variant:"italic",fontName:"Main-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}},Ht={vec:["vec",.471,.714],oiintSize1:["oiintSize1",.957,.499],oiintSize2:["oiintSize2",1.472,.659],oiiintSize1:["oiiintSize1",1.304,.499],oiiintSize2:["oiiintSize2",1.98,.659]},Dt={fontMap:Pt,makeSymbol:qt,mathsym:function(t,e,r,a){return void 0===a&&(a=[]),"boldsymbol"===r.font&&Ct(t,"Main-Bold",e).metrics?qt(t,"Main-Bold",e,r,a.concat(["mathbf"])):"\\"===t||"main"===$[e][t].font?qt(t,"Main-Regular",e,r,a):qt(t,"AMS-Regular",e,r,a.concat(["amsrm"]))},makeSpan:It,makeSvgSpan:Rt,makeLineSpan:function(t,e,r){var a=It([t],[],e);return a.height=Math.max(r||e.fontMetrics().defaultRuleThickness,e.minRuleThickness),a.style.borderBottomWidth=a.height+"em",a.maxFontSize=1,a},makeAnchor:function(t,e,r,a){var n=new O(t,e,r,a);return Ot(n),n},makeFragment:Et,wrapFragment:function(t,e){return t instanceof A?It([],[t],e):t},makeVList:function(t,e){for(var r=function(t){if("individualShift"===t.positionType){for(var e=t.children,r=[e[0]],a=-e[0].shift-e[0].elem.depth,n=a,i=1;i0&&(i.push(pe(o,e)),o=[]),i.push(n[s]));o.length>0&&i.push(pe(o,e)),r&&((a=pe(se(r,e,!0))).classes=["tag"],i.push(a));var l=re(["katex-html"],i);if(l.setAttribute("aria-hidden","true"),a){var m=a.children[0];m.style.height=l.height+l.depth+"em",m.style.verticalAlign=-l.depth+"em"}return l}function fe(t){return new A(t)}var ge=function(){function t(t,e){this.type=void 0,this.attributes=void 0,this.children=void 0,this.type=t,this.attributes={},this.children=e||[]}var e=t.prototype;return e.setAttribute=function(t,e){this.attributes[t]=e},e.getAttribute=function(t){return this.attributes[t]},e.toNode=function(){var t=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var e in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,e)&&t.setAttribute(e,this.attributes[e]);for(var r=0;r"},e.toText=function(){return this.children.map((function(t){return t.toText()})).join("")},t}(),xe=function(){function t(t){this.text=void 0,this.text=t}var e=t.prototype;return e.toNode=function(){return document.createTextNode(this.text)},e.toMarkup=function(){return c.escape(this.toText())},e.toText=function(){return this.text},t}(),ve={MathNode:ge,TextNode:xe,SpaceNode:function(){function t(t){this.width=void 0,this.character=void 0,this.width=t,this.character=t>=.05555&&t<=.05556?" ":t>=.1666&&t<=.1667?" ":t>=.2222&&t<=.2223?" ":t>=.2777&&t<=.2778?"  ":t>=-.05556&&t<=-.05555?" ⁣":t>=-.1667&&t<=-.1666?" ⁣":t>=-.2223&&t<=-.2222?" ⁣":t>=-.2778&&t<=-.2777?" ⁣":null}var e=t.prototype;return e.toNode=function(){if(this.character)return document.createTextNode(this.character);var t=document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");return t.setAttribute("width",this.width+"em"),t},e.toMarkup=function(){return this.character?""+this.character+"":''},e.toText=function(){return this.character?this.character:" "},t}(),newDocumentFragment:fe},be=function(t,e,r){return!$[e][t]||!$[e][t].replace||55349===t.charCodeAt(0)||rt.hasOwnProperty(t)&&r&&(r.fontFamily&&"tt"===r.fontFamily.substr(4,2)||r.font&&"tt"===r.font.substr(4,2))||(t=$[e][t].replace),new ve.TextNode(t)},ye=function(t){return 1===t.length?t[0]:new ve.MathNode("mrow",t)},we=function(t,e){if("texttt"===e.fontFamily)return"monospace";if("textsf"===e.fontFamily)return"textit"===e.fontShape&&"textbf"===e.fontWeight?"sans-serif-bold-italic":"textit"===e.fontShape?"sans-serif-italic":"textbf"===e.fontWeight?"bold-sans-serif":"sans-serif";if("textit"===e.fontShape&&"textbf"===e.fontWeight)return"bold-italic";if("textit"===e.fontShape)return"italic";if("textbf"===e.fontWeight)return"bold";var r=e.font;if(!r||"mathnormal"===r)return null;var a=t.mode;if("mathit"===r)return"italic";if("boldsymbol"===r)return"bold-italic";if("mathbf"===r)return"bold";if("mathbb"===r)return"double-struck";if("mathfrak"===r)return"fraktur";if("mathscr"===r||"mathcal"===r)return"script";if("mathsf"===r)return"sans-serif";if("mathtt"===r)return"monospace";var n=t.text;return c.contains(["\\imath","\\jmath"],n)?null:($[a][n]&&$[a][n].replace&&(n=$[a][n].replace),G(n,Dt.fontMap[r].fontName,a)?Dt.fontMap[r].variant:null)},ke=function(t,e,r){if(1===t.length){var a=Me(t[0],e);return r&&a instanceof ge&&"mo"===a.type&&(a.setAttribute("lspace","0em"),a.setAttribute("rspace","0em")),[a]}for(var n,i=[],o=0;o0&&(p.text=p.text.slice(0,1)+"̸"+p.text.slice(1),i.pop())}}}i.push(s),n=s}return i},Se=function(t,e,r){return ye(ke(t,e,r))},Me=function(t,e){if(!t)return new ve.MathNode("mrow");if(Jt[t.type])return Jt[t.type](t,e);throw new o("Got group of unknown type: '"+t.type+"'")};function ze(t,e,r,a){var n,i=ke(t,r);n=1===i.length&&i[0]instanceof ge&&c.contains(["mrow","mtable"],i[0].type)?i[0]:new ve.MathNode("mrow",i);var o=new ve.MathNode("annotation",[new ve.TextNode(e)]);o.setAttribute("encoding","application/x-tex");var s=new ve.MathNode("semantics",[n,o]),h=new ve.MathNode("math",[s]);h.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML");var l=a?"katex":"katex-mathml";return Dt.makeSpan([l],[h])}var Ae=function(t){return new St({style:t.displayMode?w.DISPLAY:w.TEXT,maxSize:t.maxSize,minRuleThickness:t.minRuleThickness})},Te=function(t,e){if(e.displayMode){var r=["katex-display"];e.leqno&&r.push("leqno"),e.fleqn&&r.push("fleqn"),t=Dt.makeSpan(r,[t])}return t},Be=function(t,e,r){var a,n=Ae(r);if("mathml"===r.output)return ze(t,e,n,!0);if("html"===r.output){var i=de(t,n);a=Dt.makeSpan(["katex"],[i])}else{var o=ze(t,e,n,!1),s=de(t,n);a=Dt.makeSpan(["katex"],[o,s])}return Te(a,r)},Ce={widehat:"^",widecheck:"ˇ",widetilde:"~",utilde:"~",overleftarrow:"←",underleftarrow:"←",xleftarrow:"←",overrightarrow:"→",underrightarrow:"→",xrightarrow:"→",underbrace:"⏟",overbrace:"⏞",overgroup:"⏠",undergroup:"⏡",overleftrightarrow:"↔",underleftrightarrow:"↔",xleftrightarrow:"↔",Overrightarrow:"⇒",xRightarrow:"⇒",overleftharpoon:"↼",xleftharpoonup:"↼",overrightharpoon:"⇀",xrightharpoonup:"⇀",xLeftarrow:"⇐",xLeftrightarrow:"⇔",xhookleftarrow:"↩",xhookrightarrow:"↪",xmapsto:"↦",xrightharpoondown:"⇁",xleftharpoondown:"↽",xrightleftharpoons:"⇌",xleftrightharpoons:"⇋",xtwoheadleftarrow:"↞",xtwoheadrightarrow:"↠",xlongequal:"=",xtofrom:"⇄",xrightleftarrows:"⇄",xrightequilibrium:"⇌",xleftequilibrium:"⇋"},qe={overrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],overleftarrow:[["leftarrow"],.888,522,"xMinYMin"],underrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],underleftarrow:[["leftarrow"],.888,522,"xMinYMin"],xrightarrow:[["rightarrow"],1.469,522,"xMaxYMin"],xleftarrow:[["leftarrow"],1.469,522,"xMinYMin"],Overrightarrow:[["doublerightarrow"],.888,560,"xMaxYMin"],xRightarrow:[["doublerightarrow"],1.526,560,"xMaxYMin"],xLeftarrow:[["doubleleftarrow"],1.526,560,"xMinYMin"],overleftharpoon:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoonup:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoondown:[["leftharpoondown"],.888,522,"xMinYMin"],overrightharpoon:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoonup:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoondown:[["rightharpoondown"],.888,522,"xMaxYMin"],xlongequal:[["longequal"],.888,334,"xMinYMin"],xtwoheadleftarrow:[["twoheadleftarrow"],.888,334,"xMinYMin"],xtwoheadrightarrow:[["twoheadrightarrow"],.888,334,"xMaxYMin"],overleftrightarrow:[["leftarrow","rightarrow"],.888,522],overbrace:[["leftbrace","midbrace","rightbrace"],1.6,548],underbrace:[["leftbraceunder","midbraceunder","rightbraceunder"],1.6,548],underleftrightarrow:[["leftarrow","rightarrow"],.888,522],xleftrightarrow:[["leftarrow","rightarrow"],1.75,522],xLeftrightarrow:[["doubleleftarrow","doublerightarrow"],1.75,560],xrightleftharpoons:[["leftharpoondownplus","rightharpoonplus"],1.75,716],xleftrightharpoons:[["leftharpoonplus","rightharpoondownplus"],1.75,716],xhookleftarrow:[["leftarrow","righthook"],1.08,522],xhookrightarrow:[["lefthook","rightarrow"],1.08,522],overlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],underlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],overgroup:[["leftgroup","rightgroup"],.888,342],undergroup:[["leftgroupunder","rightgroupunder"],.888,342],xmapsto:[["leftmapsto","rightarrow"],1.5,522],xtofrom:[["leftToFrom","rightToFrom"],1.75,528],xrightleftarrows:[["baraboveleftarrow","rightarrowabovebar"],1.75,901],xrightequilibrium:[["baraboveshortleftharpoon","rightharpoonaboveshortbar"],1.75,716],xleftequilibrium:[["shortbaraboveleftharpoon","shortrightharpoonabovebar"],1.75,716]},Ne=function(t,e,r,a){var n,i=t.height+t.depth+2*r;if(/fbox|color/.test(e)){if(n=Dt.makeSpan(["stretchy",e],[],a),"fbox"===e){var o=a.color&&a.getColor();o&&(n.style.borderColor=o)}}else{var s=[];/^[bx]cancel$/.test(e)&&s.push(new H({x1:"0",y1:"0",x2:"100%",y2:"100%","stroke-width":"0.046em"})),/^x?cancel$/.test(e)&&s.push(new H({x1:"0",y1:"100%",x2:"100%",y2:"0","stroke-width":"0.046em"}));var h=new L(s,{width:"100%",height:i+"em"});n=Dt.makeSvgSpan([],[h],a)}return n.height=i,n.style.height=i+"em",n},Oe=function(t){var e=new ve.MathNode("mo",[new ve.TextNode(Ce[t.substr(1)])]);return e.setAttribute("stretchy","true"),e},Ie=function(t,e){var r=function(){var r=4e5,a=t.label.substr(1);if(c.contains(["widehat","widecheck","widetilde","utilde"],a)){var n,i,o,s="ordgroup"===(d=t.base).type?d.body.length:1;if(s>5)"widehat"===a||"widecheck"===a?(n=420,r=2364,o=.42,i=a+"4"):(n=312,r=2340,o=.34,i="tilde4");else{var h=[1,1,2,2,3,3][s];"widehat"===a||"widecheck"===a?(r=[0,1062,2364,2364,2364][h],n=[0,239,300,360,420][h],o=[0,.24,.3,.3,.36,.42][h],i=a+h):(r=[0,600,1033,2339,2340][h],n=[0,260,286,306,312][h],o=[0,.26,.286,.3,.306,.34][h],i="tilde"+h)}var l=new P(i),m=new L([l],{width:"100%",height:o+"em",viewBox:"0 0 "+r+" "+n,preserveAspectRatio:"none"});return{span:Dt.makeSvgSpan([],[m],e),minWidth:0,height:o}}var u,p,d,f=[],g=qe[a],x=g[0],v=g[1],b=g[2],y=b/1e3,w=x.length;if(1===w)u=["hide-tail"],p=[g[3]];else if(2===w)u=["halfarrow-left","halfarrow-right"],p=["xMinYMin","xMaxYMin"];else{if(3!==w)throw new Error("Correct katexImagesData or update code here to support\n "+w+" children.");u=["brace-left","brace-center","brace-right"],p=["xMinYMin","xMidYMin","xMaxYMin"]}for(var k=0;k0&&(a.style.minWidth=n+"em"),a},Re=function(t,e){var r,a,n,i=Vt(t,"supsub");i?(r=(a=Ft(i.base,"accent")).base,i.base=r,n=function(t){if(t instanceof N)return t;throw new Error("Expected span but got "+String(t)+".")}(ue(i,e)),i.base=a):r=(a=Ft(t,"accent")).base;var o=ue(r,e.havingCrampedStyle()),s=0;if(a.isShifty&&c.isCharacterBox(r)){var h=c.getBaseElem(r);s=D(ue(h,e.havingCrampedStyle())).skew}var l,m=Math.min(o.height,e.fontMetrics().xHeight);if(a.isStretchy)l=Ie(a,e),l=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:o},{type:"elem",elem:l,wrapperClasses:["svg-align"],wrapperStyle:s>0?{width:"calc(100% - "+2*s+"em)",marginLeft:2*s+"em"}:void 0}]},e);else{var u,p;"\\vec"===a.label?(u=Dt.staticSvg("vec",e),p=Dt.svgData.vec[1]):((u=D(u=Dt.makeOrd({mode:a.mode,text:a.label},e,"textord"))).italic=0,p=u.width),l=Dt.makeSpan(["accent-body"],[u]);var d="\\textcircled"===a.label;d&&(l.classes.push("accent-full"),m=o.height);var f=s;d||(f-=p/2),l.style.left=f+"em","\\textcircled"===a.label&&(l.style.top=".2em"),l=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:o},{type:"kern",size:-m},{type:"elem",elem:l}]},e)}var g=Dt.makeSpan(["mord","accent"],[l],e);return n?(n.children[0]=g,n.height=Math.max(g.height,n.height),n.classes[0]="mord",n):g},Ee=function(t,e){var r=t.isStretchy?Oe(t.label):new ve.MathNode("mo",[be(t.label,t.mode)]),a=new ve.MathNode("mover",[Me(t.base,e),r]);return a.setAttribute("accent","true"),a},Le=new RegExp(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"].map((function(t){return"\\"+t})).join("|"));Qt({type:"accent",names:["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring","\\widecheck","\\widehat","\\widetilde","\\overrightarrow","\\overleftarrow","\\Overrightarrow","\\overleftrightarrow","\\overgroup","\\overlinesegment","\\overleftharpoon","\\overrightharpoon"],props:{numArgs:1},handler:function(t,e){var r=e[0],a=!Le.test(t.funcName),n=!a||"\\widehat"===t.funcName||"\\widetilde"===t.funcName||"\\widecheck"===t.funcName;return{type:"accent",mode:t.parser.mode,label:t.funcName,isStretchy:a,isShifty:n,base:r}},htmlBuilder:Re,mathmlBuilder:Ee}),Qt({type:"accent",names:["\\'","\\`","\\^","\\~","\\=","\\u","\\.",'\\"',"\\r","\\H","\\v","\\textcircled"],props:{numArgs:1,allowedInText:!0,allowedInMath:!1},handler:function(t,e){var r=e[0];return{type:"accent",mode:t.parser.mode,label:t.funcName,isStretchy:!1,isShifty:!0,base:r}},htmlBuilder:Re,mathmlBuilder:Ee}),Qt({type:"accentUnder",names:["\\underleftarrow","\\underrightarrow","\\underleftrightarrow","\\undergroup","\\underlinesegment","\\utilde"],props:{numArgs:1},handler:function(t,e){var r=t.parser,a=t.funcName,n=e[0];return{type:"accentUnder",mode:r.mode,label:a,base:n}},htmlBuilder:function(t,e){var r=ue(t.base,e),a=Ie(t,e),n="\\utilde"===t.label?.12:0,i=Dt.makeVList({positionType:"bottom",positionData:a.height+n,children:[{type:"elem",elem:a,wrapperClasses:["svg-align"]},{type:"kern",size:n},{type:"elem",elem:r}]},e);return Dt.makeSpan(["mord","accentunder"],[i],e)},mathmlBuilder:function(t,e){var r=Oe(t.label),a=new ve.MathNode("munder",[Me(t.base,e),r]);return a.setAttribute("accentunder","true"),a}});var Pe=function(t){var e=new ve.MathNode("mpadded",t?[t]:[]);return e.setAttribute("width","+0.6em"),e.setAttribute("lspace","0.3em"),e};Qt({type:"xArrow",names:["\\xleftarrow","\\xrightarrow","\\xLeftarrow","\\xRightarrow","\\xleftrightarrow","\\xLeftrightarrow","\\xhookleftarrow","\\xhookrightarrow","\\xmapsto","\\xrightharpoondown","\\xrightharpoonup","\\xleftharpoondown","\\xleftharpoonup","\\xrightleftharpoons","\\xleftrightharpoons","\\xlongequal","\\xtwoheadrightarrow","\\xtwoheadleftarrow","\\xtofrom","\\xrightleftarrows","\\xrightequilibrium","\\xleftequilibrium"],props:{numArgs:1,numOptionalArgs:1},handler:function(t,e,r){var a=t.parser,n=t.funcName;return{type:"xArrow",mode:a.mode,label:n,body:e[0],below:r[0]}},htmlBuilder:function(t,e){var r,a=e.style,n=e.havingStyle(a.sup()),i=Dt.wrapFragment(ue(t.body,n,e),e);i.classes.push("x-arrow-pad"),t.below&&(n=e.havingStyle(a.sub()),(r=Dt.wrapFragment(ue(t.below,n,e),e)).classes.push("x-arrow-pad"));var o,s=Ie(t,e),h=-e.fontMetrics().axisHeight+.5*s.height,l=-e.fontMetrics().axisHeight-.5*s.height-.111;if((i.depth>.25||"\\xleftequilibrium"===t.label)&&(l-=i.depth),r){var m=-e.fontMetrics().axisHeight+r.height+.5*s.height+.111;o=Dt.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:l},{type:"elem",elem:s,shift:h},{type:"elem",elem:r,shift:m}]},e)}else o=Dt.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:l},{type:"elem",elem:s,shift:h}]},e);return o.children[0].children[0].children[1].classes.push("svg-align"),Dt.makeSpan(["mrel","x-arrow"],[o],e)},mathmlBuilder:function(t,e){var r,a=Oe(t.label);if(t.body){var n=Pe(Me(t.body,e));if(t.below){var i=Pe(Me(t.below,e));r=new ve.MathNode("munderover",[a,i,n])}else r=new ve.MathNode("mover",[a,n])}else if(t.below){var o=Pe(Me(t.below,e));r=new ve.MathNode("munder",[a,o])}else r=Pe(),r=new ve.MathNode("mover",[a,r]);return r}}),Qt({type:"textord",names:["\\@char"],props:{numArgs:1,allowedInText:!0},handler:function(t,e){for(var r=t.parser,a=Ft(e[0],"ordgroup").body,n="",i=0;i","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"],Ke=[0,1.2,1.8,2.4,3],Je=[{type:"small",style:w.SCRIPTSCRIPT},{type:"small",style:w.SCRIPT},{type:"small",style:w.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}],Qe=[{type:"small",style:w.SCRIPTSCRIPT},{type:"small",style:w.SCRIPT},{type:"small",style:w.TEXT},{type:"stack"}],tr=[{type:"small",style:w.SCRIPTSCRIPT},{type:"small",style:w.SCRIPT},{type:"small",style:w.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}],er=function(t){if("small"===t.type)return"Main-Regular";if("large"===t.type)return"Size"+t.size+"-Regular";if("stack"===t.type)return"Size4-Regular";throw new Error("Add support for delim type '"+t.type+"' here.")},rr=function(t,e,r,a){for(var n=Math.min(2,3-a.style.size);ne)return r[n]}return r[r.length-1]},ar=function(t,e,r,a,n,i){var o;"<"===t||"\\lt"===t||"⟨"===t?t="\\langle":">"!==t&&"\\gt"!==t&&"⟩"!==t||(t="\\rangle"),o=c.contains(Ze,t)?Je:c.contains($e,t)?tr:Qe;var s=rr(t,e,o,a);return"small"===s.type?function(t,e,r,a,n,i){var o=Dt.makeSymbol(t,"Main-Regular",n,a),s=Ve(o,e,a,i);return r&&Ue(s,a,e),s}(t,s.style,r,a,n,i):"large"===s.type?Ge(t,s.size,r,a,n,i):We(t,e,r,a,n,i)},nr=function(t,e){var r,a,n=e.havingBaseSizing(),i=rr("\\surd",t*n.sizeMultiplier,tr,n),o=n.sizeMultiplier,s=Math.max(0,e.minRuleThickness-e.fontMetrics().sqrtRuleThickness),h=0,l=0,m=0;return"small"===i.type?(t<1?o=1:t<1.4&&(o=.7),l=(1+s)/o,(r=Xe("sqrtMain",h=(1+s+.08)/o,m=1e3+1e3*s+80,s,e)).style.minWidth="0.853em",a=.833/o):"large"===i.type?(m=1080*Ke[i.size],l=(Ke[i.size]+s)/o,h=(Ke[i.size]+s+.08)/o,(r=Xe("sqrtSize"+i.size,h,m,s,e)).style.minWidth="1.02em",a=1/o):(h=t+s+.08,l=t+s,m=Math.floor(1e3*t+s)+80,(r=Xe("sqrtTall",h,m,s,e)).style.minWidth="0.742em",a=1.056),r.height=l,r.style.height=h+"em",{span:r,advanceWidth:a,ruleWidth:(e.fontMetrics().sqrtRuleThickness+s)*o}},ir=function(t,e,r,a,n){if("<"===t||"\\lt"===t||"⟨"===t?t="\\langle":">"!==t&&"\\gt"!==t&&"⟩"!==t||(t="\\rangle"),c.contains($e,t)||c.contains(Ze,t))return Ge(t,e,!1,r,a,n);if(c.contains(je,t))return We(t,Ke[e],!1,r,a,n);throw new o("Illegal delimiter: '"+t+"'")},or=ar,sr=function(t,e,r,a,n,i){var o=a.fontMetrics().axisHeight*a.sizeMultiplier,s=5/a.fontMetrics().ptPerEm,h=Math.max(e-o,r+o),l=Math.max(h/500*901,2*h-s);return ar(t,l,!0,a,n,i)},hr={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}},lr=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","⌊","⌋","\\lceil","\\rceil","⌈","⌉","<",">","\\langle","⟨","\\rangle","⟩","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","⟮","⟯","\\lmoustache","\\rmoustache","⎰","⎱","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."];function mr(t,e){var r=Yt(t);if(r&&c.contains(lr,r.text))return r;throw new o("Invalid delimiter: '"+(r?r.text:JSON.stringify(t))+"' after '"+e.funcName+"'",t)}function cr(t){if(!t.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}Qt({type:"delimsizing",names:["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],props:{numArgs:1},handler:function(t,e){var r=mr(e[0],t);return{type:"delimsizing",mode:t.parser.mode,size:hr[t.funcName].size,mclass:hr[t.funcName].mclass,delim:r.text}},htmlBuilder:function(t,e){return"."===t.delim?Dt.makeSpan([t.mclass]):ir(t.delim,t.size,e,t.mode,[t.mclass])},mathmlBuilder:function(t){var e=[];"."!==t.delim&&e.push(be(t.delim,t.mode));var r=new ve.MathNode("mo",e);return"mopen"===t.mclass||"mclose"===t.mclass?r.setAttribute("fence","true"):r.setAttribute("fence","false"),r}}),Qt({type:"leftright-right",names:["\\right"],props:{numArgs:1},handler:function(t,e){var r=t.parser.gullet.macros.get("\\current@color");if(r&&"string"!=typeof r)throw new o("\\current@color set to non-string in \\right");return{type:"leftright-right",mode:t.parser.mode,delim:mr(e[0],t).text,color:r}}}),Qt({type:"leftright",names:["\\left"],props:{numArgs:1},handler:function(t,e){var r=mr(e[0],t),a=t.parser;++a.leftrightDepth;var n=a.parseExpression(!1);--a.leftrightDepth,a.expect("\\right",!1);var i=Ft(a.parseFunction(),"leftright-right");return{type:"leftright",mode:a.mode,body:n,left:r.text,right:i.delim,rightColor:i.color}},htmlBuilder:function(t,e){cr(t);for(var r,a,n=se(t.body,e,!0,["mopen","mclose"]),i=0,o=0,s=!1,h=0;h-1?"mpadded":"menclose",[Me(t.body,e)]);switch(t.label){case"\\cancel":a.setAttribute("notation","updiagonalstrike");break;case"\\bcancel":a.setAttribute("notation","downdiagonalstrike");break;case"\\sout":a.setAttribute("notation","horizontalstrike");break;case"\\fbox":a.setAttribute("notation","box");break;case"\\fcolorbox":case"\\colorbox":if(r=e.fontMetrics().fboxsep*e.fontMetrics().ptPerEm,a.setAttribute("width","+"+2*r+"pt"),a.setAttribute("height","+"+2*r+"pt"),a.setAttribute("lspace",r+"pt"),a.setAttribute("voffset",r+"pt"),"\\fcolorbox"===t.label){var n=Math.max(e.fontMetrics().fboxrule,e.minRuleThickness);a.setAttribute("style","border: "+n+"em solid "+String(t.borderColor))}break;case"\\xcancel":a.setAttribute("notation","updiagonalstrike downdiagonalstrike")}return t.backgroundColor&&a.setAttribute("mathbackground",t.backgroundColor),a};Qt({type:"enclose",names:["\\colorbox"],props:{numArgs:2,allowedInText:!0,greediness:3,argTypes:["color","text"]},handler:function(t,e,r){var a=t.parser,n=t.funcName,i=Ft(e[0],"color-token").color,o=e[1];return{type:"enclose",mode:a.mode,label:n,backgroundColor:i,body:o}},htmlBuilder:ur,mathmlBuilder:pr}),Qt({type:"enclose",names:["\\fcolorbox"],props:{numArgs:3,allowedInText:!0,greediness:3,argTypes:["color","color","text"]},handler:function(t,e,r){var a=t.parser,n=t.funcName,i=Ft(e[0],"color-token").color,o=Ft(e[1],"color-token").color,s=e[2];return{type:"enclose",mode:a.mode,label:n,backgroundColor:o,borderColor:i,body:s}},htmlBuilder:ur,mathmlBuilder:pr}),Qt({type:"enclose",names:["\\fbox"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!0},handler:function(t,e){return{type:"enclose",mode:t.parser.mode,label:"\\fbox",body:e[0]}}}),Qt({type:"enclose",names:["\\cancel","\\bcancel","\\xcancel","\\sout"],props:{numArgs:1},handler:function(t,e,r){var a=t.parser,n=t.funcName,i=e[0];return{type:"enclose",mode:a.mode,label:n,body:i}},htmlBuilder:ur,mathmlBuilder:pr});var dr={};function fr(t){for(var e=t.type,r=t.names,a=t.props,n=t.handler,i=t.htmlBuilder,o=t.mathmlBuilder,s={type:e,numArgs:a.numArgs||0,greediness:1,allowedInText:!1,numOptionalArgs:0,handler:n},h=0;h0&&(b+=.25),l.push({pos:b,isDashed:t[e]})}for(y(i[0]),r=0;r0&&(M<(B+=v)&&(M=B),B=0),t.addJot&&(M+=f),z.height=S,z.depth=M,b+=S,z.pos=b,b+=M+B,h[r]=z,y(i[r+1])}var C,q,N=b/2+e.fontMetrics().axisHeight,O=t.cols||[],I=[];for(a=0,q=0;a=s)){var H=void 0;(a>0||t.hskipBeforeAndAfter)&&0!==(H=c.deflt(R.pregap,p))&&((C=Dt.makeSpan(["arraycolsep"],[])).style.width=H+"em",I.push(C));var D=[];for(r=0;r0){for(var G=Dt.makeLineSpan("hline",e,m),Y=Dt.makeLineSpan("hdashline",e,m),_=[{type:"elem",elem:h,shift:0}];l.length>0;){var W=l.pop(),X=W.pos-N;W.isDashed?_.push({type:"elem",elem:Y,shift:X}):_.push({type:"elem",elem:G,shift:X})}h=Dt.makeVList({positionType:"individualShift",children:_},e)}return Dt.makeSpan(["mord"],[h],e)},yr={c:"center ",l:"left ",r:"right "},wr=function(t,e){var r=new ve.MathNode("mtable",t.body.map((function(t){return new ve.MathNode("mtr",t.map((function(t){return new ve.MathNode("mtd",[Me(t,e)])})))}))),a=.5===t.arraystretch?.1:.16+t.arraystretch-1+(t.addJot?.09:0);r.setAttribute("rowspacing",a+"em");var n="",i="";if(t.cols){var o=t.cols,s="",h=!1,l=0,m=o.length;"separator"===o[0].type&&(n+="top ",l=1),"separator"===o[o.length-1].type&&(n+="bottom ",m-=1);for(var c=l;c0?"left ":"",n+=g[g.length-1].length>0?"right ":"";for(var x=1;x0&&c&&(d=1),a[u]={type:"align",align:p,pregap:d,postgap:0}}return n.colSeparationType=c?"align":"alignat",n};fr({type:"array",names:["array","darray"],props:{numArgs:1},handler:function(t,e){var r={cols:(Yt(e[0])?[e[0]]:Ft(e[0],"ordgroup").body).map((function(t){var e=Gt(t).text;if(-1!=="lcr".indexOf(e))return{type:"align",align:e};if("|"===e)return{type:"separator",separator:"|"};if(":"===e)return{type:"separator",separator:":"};throw new o("Unknown column alignment: "+e,t)})),hskipBeforeAndAfter:!0};return xr(t.parser,r,vr(t.envName))},htmlBuilder:br,mathmlBuilder:wr}),fr({type:"array",names:["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix"],props:{numArgs:0},handler:function(t){var e={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[t.envName],r=xr(t.parser,{hskipBeforeAndAfter:!1},vr(t.envName));return e?{type:"leftright",mode:t.mode,body:[r],left:e[0],right:e[1],rightColor:void 0}:r},htmlBuilder:br,mathmlBuilder:wr}),fr({type:"array",names:["smallmatrix"],props:{numArgs:0},handler:function(t){var e=xr(t.parser,{arraystretch:.5},"script");return e.colSeparationType="small",e},htmlBuilder:br,mathmlBuilder:wr}),fr({type:"array",names:["subarray"],props:{numArgs:1},handler:function(t,e){var r=(Yt(e[0])?[e[0]]:Ft(e[0],"ordgroup").body).map((function(t){var e=Gt(t).text;if(-1!=="lc".indexOf(e))return{type:"align",align:e};throw new o("Unknown column alignment: "+e,t)}));if(r.length>1)throw new o("{subarray} can contain only one column");var a={cols:r,hskipBeforeAndAfter:!1,arraystretch:.5};if((a=xr(t.parser,a,"script")).body[0].length>1)throw new o("{subarray} can contain only one column");return a},htmlBuilder:br,mathmlBuilder:wr}),fr({type:"array",names:["cases","dcases"],props:{numArgs:0},handler:function(t){var e=xr(t.parser,{arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:1},{type:"align",align:"l",pregap:0,postgap:0}]},vr(t.envName));return{type:"leftright",mode:t.mode,body:[e],left:"\\{",right:".",rightColor:void 0}},htmlBuilder:br,mathmlBuilder:wr}),fr({type:"array",names:["aligned"],props:{numArgs:0},handler:kr,htmlBuilder:br,mathmlBuilder:wr}),fr({type:"array",names:["gathered"],props:{numArgs:0},handler:function(t){return xr(t.parser,{cols:[{type:"align",align:"c"}],addJot:!0},"display")},htmlBuilder:br,mathmlBuilder:wr}),fr({type:"array",names:["alignedat"],props:{numArgs:1},handler:kr,htmlBuilder:br,mathmlBuilder:wr}),Qt({type:"text",names:["\\hline","\\hdashline"],props:{numArgs:0,allowedInText:!0,allowedInMath:!0},handler:function(t,e){throw new o(t.funcName+" valid only within array environment")}});var Sr=dr;Qt({type:"environment",names:["\\begin","\\end"],props:{numArgs:1,argTypes:["text"]},handler:function(t,e){var r=t.parser,a=t.funcName,n=e[0];if("ordgroup"!==n.type)throw new o("Invalid environment name",n);for(var i="",s=0;s=w.SCRIPT.id?r.text():w.DISPLAY:"text"===t&&r.size===w.DISPLAY.size?r=w.TEXT:"script"===t?r=w.SCRIPT:"scriptscript"===t&&(r=w.SCRIPTSCRIPT),r},Or=function(t,e){var r,a=Nr(t.size,e.style),n=a.fracNum(),i=a.fracDen();r=e.havingStyle(n);var o=ue(t.numer,r,e);if(t.continued){var s=8.5/e.fontMetrics().ptPerEm,h=3.5/e.fontMetrics().ptPerEm;o.height=o.height0?3*c:7*c,d=e.fontMetrics().denom1):(m>0?(u=e.fontMetrics().num2,p=c):(u=e.fontMetrics().num3,p=3*c),d=e.fontMetrics().denom2),l){var y=e.fontMetrics().axisHeight;u-o.depth-(y+.5*m)0&&(e="."===(e=t)?null:e),e};Qt({type:"genfrac",names:["\\genfrac"],props:{numArgs:6,greediness:6,argTypes:["math","math","size","text","math","math"]},handler:function(t,e){var r=t.parser,a=e[4],n=e[5],i=Vt(e[0],"atom");i&&(i=Ut(e[0],"open"));var o=i?Er(i.text):null,s=Vt(e[1],"atom");s&&(s=Ut(e[1],"close"));var h,l=s?Er(s.text):null,m=Ft(e[2],"size"),c=null;h=!!m.isBlank||(c=m.value).number>0;var u="auto",p=Vt(e[3],"ordgroup");if(p){if(p.body.length>0){var d=Ft(p.body[0],"textord");u=Rr[Number(d.text)]}}else p=Ft(e[3],"textord"),u=Rr[Number(p.text)];return{type:"genfrac",mode:r.mode,numer:a,denom:n,continued:!1,hasBarLine:h,barSize:c,leftDelim:o,rightDelim:l,size:u}},htmlBuilder:Or,mathmlBuilder:Ir}),Qt({type:"infix",names:["\\above"],props:{numArgs:1,argTypes:["size"],infix:!0},handler:function(t,e){var r=t.parser,a=(t.funcName,t.token);return{type:"infix",mode:r.mode,replaceWith:"\\\\abovefrac",size:Ft(e[0],"size").value,token:a}}}),Qt({type:"genfrac",names:["\\\\abovefrac"],props:{numArgs:3,argTypes:["math","size","math"]},handler:function(t,e){var r=t.parser,a=(t.funcName,e[0]),n=function(t){if(!t)throw new Error("Expected non-null, but got "+String(t));return t}(Ft(e[1],"infix").size),i=e[2],o=n.number>0;return{type:"genfrac",mode:r.mode,numer:a,denom:i,continued:!1,hasBarLine:o,barSize:n,leftDelim:null,rightDelim:null,size:"auto"}},htmlBuilder:Or,mathmlBuilder:Ir});var Lr=function(t,e){var r,a,n=e.style,i=Vt(t,"supsub");i?(r=i.sup?ue(i.sup,e.havingStyle(n.sup()),e):ue(i.sub,e.havingStyle(n.sub()),e),a=Ft(i.base,"horizBrace")):a=Ft(t,"horizBrace");var o,s=ue(a.base,e.havingBaseStyle(w.DISPLAY)),h=Ie(a,e);if(a.isOver?(o=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:s},{type:"kern",size:.1},{type:"elem",elem:h}]},e)).children[0].children[0].children[1].classes.push("svg-align"):(o=Dt.makeVList({positionType:"bottom",positionData:s.depth+.1+h.height,children:[{type:"elem",elem:h},{type:"kern",size:.1},{type:"elem",elem:s}]},e)).children[0].children[0].children[0].classes.push("svg-align"),r){var l=Dt.makeSpan(["mord",a.isOver?"mover":"munder"],[o],e);o=a.isOver?Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:l},{type:"kern",size:.2},{type:"elem",elem:r}]},e):Dt.makeVList({positionType:"bottom",positionData:l.depth+.2+r.height+r.depth,children:[{type:"elem",elem:r},{type:"kern",size:.2},{type:"elem",elem:l}]},e)}return Dt.makeSpan(["mord",a.isOver?"mover":"munder"],[o],e)};Qt({type:"horizBrace",names:["\\overbrace","\\underbrace"],props:{numArgs:1},handler:function(t,e){var r=t.parser,a=t.funcName;return{type:"horizBrace",mode:r.mode,label:a,isOver:/^\\over/.test(a),base:e[0]}},htmlBuilder:Lr,mathmlBuilder:function(t,e){var r=Oe(t.label);return new ve.MathNode(t.isOver?"mover":"munder",[Me(t.base,e),r])}}),Qt({type:"href",names:["\\href"],props:{numArgs:2,argTypes:["url","original"],allowedInText:!0},handler:function(t,e){var r=t.parser,a=e[1],n=Ft(e[0],"url").url;return r.settings.isTrusted({command:"\\href",url:n})?{type:"href",mode:r.mode,href:n,body:ee(a)}:r.formatUnsupportedCmd("\\href")},htmlBuilder:function(t,e){var r=se(t.body,e,!1);return Dt.makeAnchor(t.href,[],r,e)},mathmlBuilder:function(t,e){var r=Se(t.body,e);return r instanceof ge||(r=new ge("mrow",[r])),r.setAttribute("href",t.href),r}}),Qt({type:"href",names:["\\url"],props:{numArgs:1,argTypes:["url"],allowedInText:!0},handler:function(t,e){var r=t.parser,a=Ft(e[0],"url").url;if(!r.settings.isTrusted({command:"\\url",url:a}))return r.formatUnsupportedCmd("\\url");for(var n=[],i=0;i0&&(a=Tt(t.totalheight,e)-r,a=Number(a.toFixed(2)));var n=0;t.width.number>0&&(n=Tt(t.width,e));var i={height:r+a+"em"};n>0&&(i.width=n+"em"),a>0&&(i.verticalAlign=-a+"em");var o=new I(t.src,t.alt,i);return o.height=r,o.depth=a,o},mathmlBuilder:function(t,e){var r=new ve.MathNode("mglyph",[]);r.setAttribute("alt",t.alt);var a=Tt(t.height,e),n=0;if(t.totalheight.number>0&&(n=(n=Tt(t.totalheight,e)-a).toFixed(2),r.setAttribute("valign","-"+n+"em")),r.setAttribute("height",a+n+"em"),t.width.number>0){var i=Tt(t.width,e);r.setAttribute("width",i+"em")}return r.setAttribute("src",t.src),r}}),Qt({type:"kern",names:["\\kern","\\mkern","\\hskip","\\mskip"],props:{numArgs:1,argTypes:["size"],allowedInText:!0},handler:function(t,e){var r=t.parser,a=t.funcName,n=Ft(e[0],"size");if(r.settings.strict){var i="m"===a[1],o="mu"===n.value.unit;i?(o||r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" supports only mu units, not "+n.value.unit+" units"),"math"!==r.mode&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" works only in math mode")):o&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" doesn't support mu units")}return{type:"kern",mode:r.mode,dimension:n.value}},htmlBuilder:function(t,e){return Dt.makeGlue(t.dimension,e)},mathmlBuilder:function(t,e){var r=Tt(t.dimension,e);return new ve.SpaceNode(r)}}),Qt({type:"lap",names:["\\mathllap","\\mathrlap","\\mathclap"],props:{numArgs:1,allowedInText:!0},handler:function(t,e){var r=t.parser,a=t.funcName,n=e[0];return{type:"lap",mode:r.mode,alignment:a.slice(5),body:n}},htmlBuilder:function(t,e){var r;"clap"===t.alignment?(r=Dt.makeSpan([],[ue(t.body,e)]),r=Dt.makeSpan(["inner"],[r],e)):r=Dt.makeSpan(["inner"],[ue(t.body,e)]);var a=Dt.makeSpan(["fix"],[]),n=Dt.makeSpan([t.alignment],[r,a],e),i=Dt.makeSpan(["strut"]);return i.style.height=n.height+n.depth+"em",i.style.verticalAlign=-n.depth+"em",n.children.unshift(i),n=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:n}]},e),Dt.makeSpan(["mord"],[n],e)},mathmlBuilder:function(t,e){var r=new ve.MathNode("mpadded",[Me(t.body,e)]);if("rlap"!==t.alignment){var a="llap"===t.alignment?"-1":"-0.5";r.setAttribute("lspace",a+"width")}return r.setAttribute("width","0px"),r}}),Qt({type:"styling",names:["\\(","$"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler:function(t,e){var r=t.funcName,a=t.parser,n=a.mode;a.switchMode("math");var i="\\("===r?"\\)":"$",o=a.parseExpression(!1,i);return a.expect(i),a.switchMode(n),{type:"styling",mode:a.mode,style:"text",body:o}}}),Qt({type:"text",names:["\\)","\\]"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler:function(t,e){throw new o("Mismatched "+t.funcName)}});var Hr=function(t,e){switch(e.style.size){case w.DISPLAY.size:return t.display;case w.TEXT.size:return t.text;case w.SCRIPT.size:return t.script;case w.SCRIPTSCRIPT.size:return t.scriptscript;default:return t.text}};Qt({type:"mathchoice",names:["\\mathchoice"],props:{numArgs:4},handler:function(t,e){return{type:"mathchoice",mode:t.parser.mode,display:ee(e[0]),text:ee(e[1]),script:ee(e[2]),scriptscript:ee(e[3])}},htmlBuilder:function(t,e){var r=Hr(t,e),a=se(r,e,!1);return Dt.makeFragment(a)},mathmlBuilder:function(t,e){var r=Hr(t,e);return Se(r,e)}});var Dr=function(t,e,r,a,n,i,o){var s,h,l;if(t=Dt.makeSpan([],[t]),e){var m=ue(e,a.havingStyle(n.sup()),a);h={elem:m,kern:Math.max(a.fontMetrics().bigOpSpacing1,a.fontMetrics().bigOpSpacing3-m.depth)}}if(r){var c=ue(r,a.havingStyle(n.sub()),a);s={elem:c,kern:Math.max(a.fontMetrics().bigOpSpacing2,a.fontMetrics().bigOpSpacing4-c.height)}}if(h&&s){var u=a.fontMetrics().bigOpSpacing5+s.elem.height+s.elem.depth+s.kern+t.depth+o;l=Dt.makeVList({positionType:"bottom",positionData:u,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:s.elem,marginLeft:-i+"em"},{type:"kern",size:s.kern},{type:"elem",elem:t},{type:"kern",size:h.kern},{type:"elem",elem:h.elem,marginLeft:i+"em"},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]},a)}else if(s){var p=t.height-o;l=Dt.makeVList({positionType:"top",positionData:p,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:s.elem,marginLeft:-i+"em"},{type:"kern",size:s.kern},{type:"elem",elem:t}]},a)}else{if(!h)return t;var d=t.depth+o;l=Dt.makeVList({positionType:"bottom",positionData:d,children:[{type:"elem",elem:t},{type:"kern",size:h.kern},{type:"elem",elem:h.elem,marginLeft:i+"em"},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]},a)}return Dt.makeSpan(["mop","op-limits"],[l],a)},Fr=["\\smallint"],Vr=function(t,e){var r,a,n,i=!1,o=Vt(t,"supsub");o?(r=o.sup,a=o.sub,n=Ft(o.base,"op"),i=!0):n=Ft(t,"op");var s,h=e.style,l=!1;if(h.size===w.DISPLAY.size&&n.symbol&&!c.contains(Fr,n.name)&&(l=!0),n.symbol){var m=l?"Size2-Regular":"Size1-Regular",u="";if("\\oiint"!==n.name&&"\\oiiint"!==n.name||(u=n.name.substr(1),n.name="oiint"===u?"\\iint":"\\iiint"),s=Dt.makeSymbol(n.name,m,"math",e,["mop","op-symbol",l?"large-op":"small-op"]),u.length>0){var p=s.italic,d=Dt.staticSvg(u+"Size"+(l?"2":"1"),e);s=Dt.makeVList({positionType:"individualShift",children:[{type:"elem",elem:s,shift:0},{type:"elem",elem:d,shift:l?.08:0}]},e),n.name="\\"+u,s.classes.unshift("mop"),s.italic=p}}else if(n.body){var f=se(n.body,e,!0);1===f.length&&f[0]instanceof E?(s=f[0]).classes[0]="mop":s=Dt.makeSpan(["mop"],Dt.tryCombineChars(f),e)}else{for(var g=[],x=1;x0){for(var h=n.body.map((function(t){var e=t.text;return"string"==typeof e?{type:"textord",mode:t.mode,text:e}:t})),l=se(h,e.withFont("mathrm"),!0),m=0;m=0?s.setAttribute("height","+"+n+"em"):(s.setAttribute("height",n+"em"),s.setAttribute("depth","+"+-n+"em")),s.setAttribute("voffset",n+"em"),s}});var Xr=["\\tiny","\\sixptsize","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"];Qt({type:"sizing",names:Xr,props:{numArgs:0,allowedInText:!0},handler:function(t,e){var r=t.breakOnTokenText,a=t.funcName,n=t.parser,i=n.parseExpression(!1,r);return{type:"sizing",mode:n.mode,size:Xr.indexOf(a)+1,body:i}},htmlBuilder:function(t,e){var r=e.havingSize(t.size);return Wr(t.body,r,e)},mathmlBuilder:function(t,e){var r=e.havingSize(t.size),a=ke(t.body,r),n=new ve.MathNode("mstyle",a);return n.setAttribute("mathsize",r.sizeMultiplier+"em"),n}}),Qt({type:"smash",names:["\\smash"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0},handler:function(t,e,r){var a=t.parser,n=!1,i=!1,o=r[0]&&Ft(r[0],"ordgroup");if(o)for(var s="",h=0;hr.height+r.depth+i&&(i=(i+c-r.height-r.depth)/2);var u=h.height-r.height-i-l;r.style.paddingLeft=m+"em";var p=Dt.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:r,wrapperClasses:["svg-align"]},{type:"kern",size:-(r.height+u)},{type:"elem",elem:h},{type:"kern",size:l}]},e);if(t.index){var d=e.havingStyle(w.SCRIPTSCRIPT),f=ue(t.index,d,e),g=.6*(p.height-p.depth),x=Dt.makeVList({positionType:"shift",positionData:-g,children:[{type:"elem",elem:f}]},e),v=Dt.makeSpan(["root"],[x]);return Dt.makeSpan(["mord","sqrt"],[v,p],e)}return Dt.makeSpan(["mord","sqrt"],[p],e)},mathmlBuilder:function(t,e){var r=t.body,a=t.index;return a?new ve.MathNode("mroot",[Me(r,e),Me(a,e)]):new ve.MathNode("msqrt",[Me(r,e)])}});var $r={display:w.DISPLAY,text:w.TEXT,script:w.SCRIPT,scriptscript:w.SCRIPTSCRIPT};Qt({type:"styling",names:["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],props:{numArgs:0,allowedInText:!0},handler:function(t,e){var r=t.breakOnTokenText,a=t.funcName,n=t.parser,i=n.parseExpression(!0,r),o=a.slice(1,a.length-5);return{type:"styling",mode:n.mode,style:o,body:i}},htmlBuilder:function(t,e){var r=$r[t.style],a=e.havingStyle(r).withFont("");return Wr(t.body,a,e)},mathmlBuilder:function(t,e){var r=$r[t.style],a=e.havingStyle(r),n=ke(t.body,a),i=new ve.MathNode("mstyle",n),o={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]}[t.style];return i.setAttribute("scriptlevel",o[0]),i.setAttribute("displaystyle",o[1]),i}}),te({type:"supsub",htmlBuilder:function(t,e){var r=function(t,e){var r=t.base;return r?"op"===r.type?r.limits&&(e.style.size===w.DISPLAY.size||r.alwaysHandleSupSub)?Vr:null:"operatorname"===r.type?r.alwaysHandleSupSub&&(e.style.size===w.DISPLAY.size||r.limits)?_r:null:"accent"===r.type?c.isCharacterBox(r.base)?Re:null:"horizBrace"===r.type&&!t.sub===r.isOver?Lr:null:null}(t,e);if(r)return r(t,e);var a,n,i,o=t.base,s=t.sup,h=t.sub,l=ue(o,e),m=e.fontMetrics(),u=0,p=0,d=o&&c.isCharacterBox(o);if(s){var f=e.havingStyle(e.style.sup());a=ue(s,f,e),d||(u=l.height-f.fontMetrics().supDrop*f.sizeMultiplier/e.sizeMultiplier)}if(h){var g=e.havingStyle(e.style.sub());n=ue(h,g,e),d||(p=l.depth+g.fontMetrics().subDrop*g.sizeMultiplier/e.sizeMultiplier)}i=e.style===w.DISPLAY?m.sup1:e.style.cramped?m.sup3:m.sup2;var x,v=e.sizeMultiplier,b=.5/m.ptPerEm/v+"em",y=null;if(n){var k=t.base&&"op"===t.base.type&&t.base.name&&("\\oiint"===t.base.name||"\\oiiint"===t.base.name);(l instanceof E||k)&&(y=-l.italic+"em")}if(a&&n){u=Math.max(u,i,a.depth+.25*m.xHeight),p=Math.max(p,m.sub2);var S=4*m.defaultRuleThickness;if(u-a.depth-(n.height-p)0&&(u+=M,p-=M)}var z=[{type:"elem",elem:n,shift:p,marginRight:b,marginLeft:y},{type:"elem",elem:a,shift:-u,marginRight:b}];x=Dt.makeVList({positionType:"individualShift",children:z},e)}else if(n){p=Math.max(p,m.sub1,n.height-.8*m.xHeight);var A=[{type:"elem",elem:n,marginLeft:y,marginRight:b}];x=Dt.makeVList({positionType:"shift",positionData:p,children:A},e)}else{if(!a)throw new Error("supsub must have either sup or sub.");u=Math.max(u,i,a.depth+.25*m.xHeight),x=Dt.makeVList({positionType:"shift",positionData:-u,children:[{type:"elem",elem:a,marginRight:b}]},e)}var T=me(l,"right")||"mord";return Dt.makeSpan([T],[l,Dt.makeSpan(["msupsub"],[x])],e)},mathmlBuilder:function(t,e){var r,a=!1,n=Vt(t.base,"horizBrace");n&&!!t.sup===n.isOver&&(a=!0,r=n.isOver),!t.base||"op"!==t.base.type&&"operatorname"!==t.base.type||(t.base.parentIsSupSub=!0);var i,o=[Me(t.base,e)];if(t.sub&&o.push(Me(t.sub,e)),t.sup&&o.push(Me(t.sup,e)),a)i=r?"mover":"munder";else if(t.sub)if(t.sup){var s=t.base;i=s&&"op"===s.type&&s.limits&&e.style===w.DISPLAY||s&&"operatorname"===s.type&&s.alwaysHandleSupSub&&(e.style===w.DISPLAY||s.limits)?"munderover":"msubsup"}else{var h=t.base;i=h&&"op"===h.type&&h.limits&&(e.style===w.DISPLAY||h.alwaysHandleSupSub)||h&&"operatorname"===h.type&&h.alwaysHandleSupSub&&(h.limits||e.style===w.DISPLAY)?"munder":"msub"}else{var l=t.base;i=l&&"op"===l.type&&l.limits&&(e.style===w.DISPLAY||l.alwaysHandleSupSub)||l&&"operatorname"===l.type&&l.alwaysHandleSupSub&&(l.limits||e.style===w.DISPLAY)?"mover":"msup"}return new ve.MathNode(i,o)}}),te({type:"atom",htmlBuilder:function(t,e){return Dt.mathsym(t.text,t.mode,e,["m"+t.family])},mathmlBuilder:function(t,e){var r=new ve.MathNode("mo",[be(t.text,t.mode)]);if("bin"===t.family){var a=we(t,e);"bold-italic"===a&&r.setAttribute("mathvariant",a)}else"punct"===t.family?r.setAttribute("separator","true"):"open"!==t.family&&"close"!==t.family||r.setAttribute("stretchy","false");return r}});var jr={mi:"italic",mn:"normal",mtext:"normal"};te({type:"mathord",htmlBuilder:function(t,e){return Dt.makeOrd(t,e,"mathord")},mathmlBuilder:function(t,e){var r=new ve.MathNode("mi",[be(t.text,t.mode,e)]),a=we(t,e)||"italic";return a!==jr[r.type]&&r.setAttribute("mathvariant",a),r}}),te({type:"textord",htmlBuilder:function(t,e){return Dt.makeOrd(t,e,"textord")},mathmlBuilder:function(t,e){var r,a=be(t.text,t.mode,e),n=we(t,e)||"normal";return r="text"===t.mode?new ve.MathNode("mtext",[a]):/[0-9]/.test(t.text)?new ve.MathNode("mn",[a]):"\\prime"===t.text?new ve.MathNode("mo",[a]):new ve.MathNode("mi",[a]),n!==jr[r.type]&&r.setAttribute("mathvariant",n),r}});var Zr={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},Kr={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};te({type:"spacing",htmlBuilder:function(t,e){if(Kr.hasOwnProperty(t.text)){var r=Kr[t.text].className||"";if("text"===t.mode){var a=Dt.makeOrd(t,e,"textord");return a.classes.push(r),a}return Dt.makeSpan(["mspace",r],[Dt.mathsym(t.text,t.mode,e)],e)}if(Zr.hasOwnProperty(t.text))return Dt.makeSpan(["mspace",Zr[t.text]],[],e);throw new o('Unknown type of space "'+t.text+'"')},mathmlBuilder:function(t,e){if(!Kr.hasOwnProperty(t.text)){if(Zr.hasOwnProperty(t.text))return new ve.MathNode("mspace");throw new o('Unknown type of space "'+t.text+'"')}return new ve.MathNode("mtext",[new ve.TextNode(" ")])}});var Jr=function(){var t=new ve.MathNode("mtd",[]);return t.setAttribute("width","50%"),t};te({type:"tag",mathmlBuilder:function(t,e){var r=new ve.MathNode("mtable",[new ve.MathNode("mtr",[Jr(),new ve.MathNode("mtd",[Se(t.body,e)]),Jr(),new ve.MathNode("mtd",[Se(t.tag,e)])])]);return r.setAttribute("width","100%"),r}});var Qr={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm"},ta={"\\textbf":"textbf","\\textmd":"textmd"},ea={"\\textit":"textit","\\textup":"textup"},ra=function(t,e){var r=t.font;return r?Qr[r]?e.withTextFontFamily(Qr[r]):ta[r]?e.withTextFontWeight(ta[r]):e.withTextFontShape(ea[r]):e};Qt({type:"text",names:["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textmd","\\textit","\\textup"],props:{numArgs:1,argTypes:["text"],greediness:2,allowedInText:!0},handler:function(t,e){var r=t.parser,a=t.funcName,n=e[0];return{type:"text",mode:r.mode,body:ee(n),font:a}},htmlBuilder:function(t,e){var r=ra(t,e),a=se(t.body,r,!0);return Dt.makeSpan(["mord","text"],Dt.tryCombineChars(a),r)},mathmlBuilder:function(t,e){var r=ra(t,e);return Se(t.body,r)}}),Qt({type:"underline",names:["\\underline"],props:{numArgs:1,allowedInText:!0},handler:function(t,e){return{type:"underline",mode:t.parser.mode,body:e[0]}},htmlBuilder:function(t,e){var r=ue(t.body,e),a=Dt.makeLineSpan("underline-line",e),n=e.fontMetrics().defaultRuleThickness,i=Dt.makeVList({positionType:"top",positionData:r.height,children:[{type:"kern",size:n},{type:"elem",elem:a},{type:"kern",size:3*n},{type:"elem",elem:r}]},e);return Dt.makeSpan(["mord","underline"],[i],e)},mathmlBuilder:function(t,e){var r=new ve.MathNode("mo",[new ve.TextNode("‾")]);r.setAttribute("stretchy","true");var a=new ve.MathNode("munder",[Me(t.body,e),r]);return a.setAttribute("accentunder","true"),a}}),Qt({type:"verb",names:["\\verb"],props:{numArgs:0,allowedInText:!0},handler:function(t,e,r){throw new o("\\verb ended by end of line instead of matching delimiter")},htmlBuilder:function(t,e){for(var r=aa(t),a=[],n=e.havingStyle(e.style.text()),i=0;i0&&(this.undefStack[this.undefStack.length-1][t]=e)}else{var n=this.undefStack[this.undefStack.length-1];n&&!n.hasOwnProperty(t)&&(n[t]=this.current[t])}this.current[t]=e},t}(),la={},ma=la;function ca(t,e){la[t]=e}ca("\\@firstoftwo",(function(t){return{tokens:t.consumeArgs(2)[0],numArgs:0}})),ca("\\@secondoftwo",(function(t){return{tokens:t.consumeArgs(2)[1],numArgs:0}})),ca("\\@ifnextchar",(function(t){var e=t.consumeArgs(3),r=t.future();return 1===e[0].length&&e[0][0].text===r.text?{tokens:e[1],numArgs:0}:{tokens:e[2],numArgs:0}})),ca("\\@ifstar","\\@ifnextchar *{\\@firstoftwo{#1}}"),ca("\\TextOrMath",(function(t){var e=t.consumeArgs(2);return"text"===t.mode?{tokens:e[0],numArgs:0}:{tokens:e[1],numArgs:0}}));var ua={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,A:10,b:11,B:11,c:12,C:12,d:13,D:13,e:14,E:14,f:15,F:15};ca("\\char",(function(t){var e,r=t.popToken(),a="";if("'"===r.text)e=8,r=t.popToken();else if('"'===r.text)e=16,r=t.popToken();else if("`"===r.text)if("\\"===(r=t.popToken()).text[0])a=r.text.charCodeAt(1);else{if("EOF"===r.text)throw new o("\\char` missing argument");a=r.text.charCodeAt(0)}else e=10;if(e){if(null==(a=ua[r.text])||a>=e)throw new o("Invalid base-"+e+" digit "+r.text);for(var n;null!=(n=ua[t.future().text])&&n":"\\dotsb","-":"\\dotsb","*":"\\dotsb",":":"\\dotsb","\\DOTSB":"\\dotsb","\\coprod":"\\dotsb","\\bigvee":"\\dotsb","\\bigwedge":"\\dotsb","\\biguplus":"\\dotsb","\\bigcap":"\\dotsb","\\bigcup":"\\dotsb","\\prod":"\\dotsb","\\sum":"\\dotsb","\\bigotimes":"\\dotsb","\\bigoplus":"\\dotsb","\\bigodot":"\\dotsb","\\bigsqcup":"\\dotsb","\\And":"\\dotsb","\\longrightarrow":"\\dotsb","\\Longrightarrow":"\\dotsb","\\longleftarrow":"\\dotsb","\\Longleftarrow":"\\dotsb","\\longleftrightarrow":"\\dotsb","\\Longleftrightarrow":"\\dotsb","\\mapsto":"\\dotsb","\\longmapsto":"\\dotsb","\\hookrightarrow":"\\dotsb","\\doteq":"\\dotsb","\\mathbin":"\\dotsb","\\mathrel":"\\dotsb","\\relbar":"\\dotsb","\\Relbar":"\\dotsb","\\xrightarrow":"\\dotsb","\\xleftarrow":"\\dotsb","\\DOTSI":"\\dotsi","\\int":"\\dotsi","\\oint":"\\dotsi","\\iint":"\\dotsi","\\iiint":"\\dotsi","\\iiiint":"\\dotsi","\\idotsint":"\\dotsi","\\DOTSX":"\\dotsx"};ca("\\dots",(function(t){var e="\\dotso",r=t.expandAfterFuture().text;return r in fa?e=fa[r]:("\\not"===r.substr(0,4)||r in $.math&&c.contains(["bin","rel"],$.math[r].group))&&(e="\\dotsb"),e}));var ga={")":!0,"]":!0,"\\rbrack":!0,"\\}":!0,"\\rbrace":!0,"\\rangle":!0,"\\rceil":!0,"\\rfloor":!0,"\\rgroup":!0,"\\rmoustache":!0,"\\right":!0,"\\bigr":!0,"\\biggr":!0,"\\Bigr":!0,"\\Biggr":!0,$:!0,";":!0,".":!0,",":!0};ca("\\dotso",(function(t){return t.future().text in ga?"\\ldots\\,":"\\ldots"})),ca("\\dotsc",(function(t){var e=t.future().text;return e in ga&&","!==e?"\\ldots\\,":"\\ldots"})),ca("\\cdots",(function(t){return t.future().text in ga?"\\@cdots\\,":"\\@cdots"})),ca("\\dotsb","\\cdots"),ca("\\dotsm","\\cdots"),ca("\\dotsi","\\!\\cdots"),ca("\\dotsx","\\ldots\\,"),ca("\\DOTSI","\\relax"),ca("\\DOTSB","\\relax"),ca("\\DOTSX","\\relax"),ca("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"),ca("\\,","\\tmspace+{3mu}{.1667em}"),ca("\\thinspace","\\,"),ca("\\>","\\mskip{4mu}"),ca("\\:","\\tmspace+{4mu}{.2222em}"),ca("\\medspace","\\:"),ca("\\;","\\tmspace+{5mu}{.2777em}"),ca("\\thickspace","\\;"),ca("\\!","\\tmspace-{3mu}{.1667em}"),ca("\\negthinspace","\\!"),ca("\\negmedspace","\\tmspace-{4mu}{.2222em}"),ca("\\negthickspace","\\tmspace-{5mu}{.277em}"),ca("\\enspace","\\kern.5em "),ca("\\enskip","\\hskip.5em\\relax"),ca("\\quad","\\hskip1em\\relax"),ca("\\qquad","\\hskip2em\\relax"),ca("\\tag","\\@ifstar\\tag@literal\\tag@paren"),ca("\\tag@paren","\\tag@literal{({#1})}"),ca("\\tag@literal",(function(t){if(t.macros.get("\\df@tag"))throw new o("Multiple \\tag");return"\\gdef\\df@tag{\\text{#1}}"})),ca("\\bmod","\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}\\mathbin{\\rm mod}\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}"),ca("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"),ca("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}"),ca("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1"),ca("\\pmb","\\html@mathml{\\@binrel{#1}{\\mathrlap{#1}\\kern0.5px#1}}{\\mathbf{#1}}"),ca("\\\\","\\newline"),ca("\\TeX","\\textrm{\\html@mathml{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}{TeX}}");var xa=F["Main-Regular"]["T".charCodeAt(0)][1]-.7*F["Main-Regular"]["A".charCodeAt(0)][1]+"em";ca("\\LaTeX","\\textrm{\\html@mathml{L\\kern-.36em\\raisebox{"+xa+"}{\\scriptstyle A}\\kern-.15em\\TeX}{LaTeX}}"),ca("\\KaTeX","\\textrm{\\html@mathml{K\\kern-.17em\\raisebox{"+xa+"}{\\scriptstyle A}\\kern-.15em\\TeX}{KaTeX}}"),ca("\\hspace","\\@ifstar\\@hspacer\\@hspace"),ca("\\@hspace","\\hskip #1\\relax"),ca("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax"),ca("\\ordinarycolon",":"),ca("\\vcentcolon","\\mathrel{\\mathop\\ordinarycolon}"),ca("\\dblcolon",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}{\\mathop{\\char"2237}}'),ca("\\coloneqq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2254}}'),ca("\\Coloneqq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2237\\char"3d}}'),ca("\\coloneq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"3a\\char"2212}}'),ca("\\Coloneq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"2237\\char"2212}}'),ca("\\eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2255}}'),ca("\\Eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"3d\\char"2237}}'),ca("\\eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2239}}'),ca("\\Eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"2212\\char"2237}}'),ca("\\colonapprox",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"3a\\char"2248}}'),ca("\\Colonapprox",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"2237\\char"2248}}'),ca("\\colonsim",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"3a\\char"223c}}'),ca("\\Colonsim",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"2237\\char"223c}}'),ca("∷","\\dblcolon"),ca("∹","\\eqcolon"),ca("≔","\\coloneqq"),ca("≕","\\eqqcolon"),ca("⩴","\\Coloneqq"),ca("\\ratio","\\vcentcolon"),ca("\\coloncolon","\\dblcolon"),ca("\\colonequals","\\coloneqq"),ca("\\coloncolonequals","\\Coloneqq"),ca("\\equalscolon","\\eqqcolon"),ca("\\equalscoloncolon","\\Eqqcolon"),ca("\\colonminus","\\coloneq"),ca("\\coloncolonminus","\\Coloneq"),ca("\\minuscolon","\\eqcolon"),ca("\\minuscoloncolon","\\Eqcolon"),ca("\\coloncolonapprox","\\Colonapprox"),ca("\\coloncolonsim","\\Colonsim"),ca("\\simcolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),ca("\\simcoloncolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}"),ca("\\approxcolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),ca("\\approxcoloncolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}"),ca("\\notni","\\html@mathml{\\not\\ni}{\\mathrel{\\char`∌}}"),ca("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}"),ca("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}"),ca("\\gvertneqq","\\html@mathml{\\@gvertneqq}{≩}"),ca("\\lvertneqq","\\html@mathml{\\@lvertneqq}{≨}"),ca("\\ngeqq","\\html@mathml{\\@ngeqq}{≱}"),ca("\\ngeqslant","\\html@mathml{\\@ngeqslant}{≱}"),ca("\\nleqq","\\html@mathml{\\@nleqq}{≰}"),ca("\\nleqslant","\\html@mathml{\\@nleqslant}{≰}"),ca("\\nshortmid","\\html@mathml{\\@nshortmid}{∤}"),ca("\\nshortparallel","\\html@mathml{\\@nshortparallel}{∦}"),ca("\\nsubseteqq","\\html@mathml{\\@nsubseteqq}{⊈}"),ca("\\nsupseteqq","\\html@mathml{\\@nsupseteqq}{⊉}"),ca("\\varsubsetneq","\\html@mathml{\\@varsubsetneq}{⊊}"),ca("\\varsubsetneqq","\\html@mathml{\\@varsubsetneqq}{⫋}"),ca("\\varsupsetneq","\\html@mathml{\\@varsupsetneq}{⊋}"),ca("\\varsupsetneqq","\\html@mathml{\\@varsupsetneqq}{⫌}"),ca("\\llbracket","\\html@mathml{\\mathopen{[\\mkern-3.2mu[}}{\\mathopen{\\char`⟦}}"),ca("\\rrbracket","\\html@mathml{\\mathclose{]\\mkern-3.2mu]}}{\\mathclose{\\char`⟧}}"),ca("⟦","\\llbracket"),ca("⟧","\\rrbracket"),ca("\\lBrace","\\html@mathml{\\mathopen{\\{\\mkern-3.2mu[}}{\\mathopen{\\char`⦃}}"),ca("\\rBrace","\\html@mathml{\\mathclose{]\\mkern-3.2mu\\}}}{\\mathclose{\\char`⦄}}"),ca("⦃","\\lBrace"),ca("⦄","\\rBrace"),ca("\\darr","\\downarrow"),ca("\\dArr","\\Downarrow"),ca("\\Darr","\\Downarrow"),ca("\\lang","\\langle"),ca("\\rang","\\rangle"),ca("\\uarr","\\uparrow"),ca("\\uArr","\\Uparrow"),ca("\\Uarr","\\Uparrow"),ca("\\N","\\mathbb{N}"),ca("\\R","\\mathbb{R}"),ca("\\Z","\\mathbb{Z}"),ca("\\alef","\\aleph"),ca("\\alefsym","\\aleph"),ca("\\Alpha","\\mathrm{A}"),ca("\\Beta","\\mathrm{B}"),ca("\\bull","\\bullet"),ca("\\Chi","\\mathrm{X}"),ca("\\clubs","\\clubsuit"),ca("\\cnums","\\mathbb{C}"),ca("\\Complex","\\mathbb{C}"),ca("\\Dagger","\\ddagger"),ca("\\diamonds","\\diamondsuit"),ca("\\empty","\\emptyset"),ca("\\Epsilon","\\mathrm{E}"),ca("\\Eta","\\mathrm{H}"),ca("\\exist","\\exists"),ca("\\harr","\\leftrightarrow"),ca("\\hArr","\\Leftrightarrow"),ca("\\Harr","\\Leftrightarrow"),ca("\\hearts","\\heartsuit"),ca("\\image","\\Im"),ca("\\infin","\\infty"),ca("\\Iota","\\mathrm{I}"),ca("\\isin","\\in"),ca("\\Kappa","\\mathrm{K}"),ca("\\larr","\\leftarrow"),ca("\\lArr","\\Leftarrow"),ca("\\Larr","\\Leftarrow"),ca("\\lrarr","\\leftrightarrow"),ca("\\lrArr","\\Leftrightarrow"),ca("\\Lrarr","\\Leftrightarrow"),ca("\\Mu","\\mathrm{M}"),ca("\\natnums","\\mathbb{N}"),ca("\\Nu","\\mathrm{N}"),ca("\\Omicron","\\mathrm{O}"),ca("\\plusmn","\\pm"),ca("\\rarr","\\rightarrow"),ca("\\rArr","\\Rightarrow"),ca("\\Rarr","\\Rightarrow"),ca("\\real","\\Re"),ca("\\reals","\\mathbb{R}"),ca("\\Reals","\\mathbb{R}"),ca("\\Rho","\\mathrm{P}"),ca("\\sdot","\\cdot"),ca("\\sect","\\S"),ca("\\spades","\\spadesuit"),ca("\\sub","\\subset"),ca("\\sube","\\subseteq"),ca("\\supe","\\supseteq"),ca("\\Tau","\\mathrm{T}"),ca("\\thetasym","\\vartheta"),ca("\\weierp","\\wp"),ca("\\Zeta","\\mathrm{Z}"),ca("\\argmin","\\DOTSB\\operatorname*{arg\\,min}"),ca("\\argmax","\\DOTSB\\operatorname*{arg\\,max}"),ca("\\plim","\\DOTSB\\mathop{\\operatorname{plim}}\\limits"),ca("\\blue","\\textcolor{##6495ed}{#1}"),ca("\\orange","\\textcolor{##ffa500}{#1}"),ca("\\pink","\\textcolor{##ff00af}{#1}"),ca("\\red","\\textcolor{##df0030}{#1}"),ca("\\green","\\textcolor{##28ae7b}{#1}"),ca("\\gray","\\textcolor{gray}{#1}"),ca("\\purple","\\textcolor{##9d38bd}{#1}"),ca("\\blueA","\\textcolor{##ccfaff}{#1}"),ca("\\blueB","\\textcolor{##80f6ff}{#1}"),ca("\\blueC","\\textcolor{##63d9ea}{#1}"),ca("\\blueD","\\textcolor{##11accd}{#1}"),ca("\\blueE","\\textcolor{##0c7f99}{#1}"),ca("\\tealA","\\textcolor{##94fff5}{#1}"),ca("\\tealB","\\textcolor{##26edd5}{#1}"),ca("\\tealC","\\textcolor{##01d1c1}{#1}"),ca("\\tealD","\\textcolor{##01a995}{#1}"),ca("\\tealE","\\textcolor{##208170}{#1}"),ca("\\greenA","\\textcolor{##b6ffb0}{#1}"),ca("\\greenB","\\textcolor{##8af281}{#1}"),ca("\\greenC","\\textcolor{##74cf70}{#1}"),ca("\\greenD","\\textcolor{##1fab54}{#1}"),ca("\\greenE","\\textcolor{##0d923f}{#1}"),ca("\\goldA","\\textcolor{##ffd0a9}{#1}"),ca("\\goldB","\\textcolor{##ffbb71}{#1}"),ca("\\goldC","\\textcolor{##ff9c39}{#1}"),ca("\\goldD","\\textcolor{##e07d10}{#1}"),ca("\\goldE","\\textcolor{##a75a05}{#1}"),ca("\\redA","\\textcolor{##fca9a9}{#1}"),ca("\\redB","\\textcolor{##ff8482}{#1}"),ca("\\redC","\\textcolor{##f9685d}{#1}"),ca("\\redD","\\textcolor{##e84d39}{#1}"),ca("\\redE","\\textcolor{##bc2612}{#1}"),ca("\\maroonA","\\textcolor{##ffbde0}{#1}"),ca("\\maroonB","\\textcolor{##ff92c6}{#1}"),ca("\\maroonC","\\textcolor{##ed5fa6}{#1}"),ca("\\maroonD","\\textcolor{##ca337c}{#1}"),ca("\\maroonE","\\textcolor{##9e034e}{#1}"),ca("\\purpleA","\\textcolor{##ddd7ff}{#1}"),ca("\\purpleB","\\textcolor{##c6b9fc}{#1}"),ca("\\purpleC","\\textcolor{##aa87ff}{#1}"),ca("\\purpleD","\\textcolor{##7854ab}{#1}"),ca("\\purpleE","\\textcolor{##543b78}{#1}"),ca("\\mintA","\\textcolor{##f5f9e8}{#1}"),ca("\\mintB","\\textcolor{##edf2df}{#1}"),ca("\\mintC","\\textcolor{##e0e5cc}{#1}"),ca("\\grayA","\\textcolor{##f6f7f7}{#1}"),ca("\\grayB","\\textcolor{##f0f1f2}{#1}"),ca("\\grayC","\\textcolor{##e3e5e6}{#1}"),ca("\\grayD","\\textcolor{##d6d8da}{#1}"),ca("\\grayE","\\textcolor{##babec2}{#1}"),ca("\\grayF","\\textcolor{##888d93}{#1}"),ca("\\grayG","\\textcolor{##626569}{#1}"),ca("\\grayH","\\textcolor{##3b3e40}{#1}"),ca("\\grayI","\\textcolor{##21242c}{#1}"),ca("\\kaBlue","\\textcolor{##314453}{#1}"),ca("\\kaGreen","\\textcolor{##71B307}{#1}");var va={"\\relax":!0,"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0},ba=function(){function t(t,e,r){this.settings=void 0,this.expansionCount=void 0,this.lexer=void 0,this.macros=void 0,this.stack=void 0,this.mode=void 0,this.settings=e,this.expansionCount=0,this.feed(t),this.macros=new ha(ma,e.macros),this.mode=r,this.stack=[]}var e=t.prototype;return e.feed=function(t){this.lexer=new sa(t,this.settings)},e.switchMode=function(t){this.mode=t},e.beginGroup=function(){this.macros.beginGroup()},e.endGroup=function(){this.macros.endGroup()},e.future=function(){return 0===this.stack.length&&this.pushToken(this.lexer.lex()),this.stack[this.stack.length-1]},e.popToken=function(){return this.future(),this.stack.pop()},e.pushToken=function(t){this.stack.push(t)},e.pushTokens=function(t){var e;(e=this.stack).push.apply(e,t)},e.consumeSpaces=function(){for(;" "===this.future().text;)this.stack.pop()},e.consumeArgs=function(t){for(var e=[],r=0;rthis.settings.maxExpand)throw new o("Too many expansions: infinite loop or need to increase maxExpand setting");var a=r.tokens;if(r.numArgs)for(var n=this.consumeArgs(r.numArgs),i=(a=a.slice()).length-1;i>=0;--i){var s=a[i];if("#"===s.text){if(0===i)throw new o("Incomplete placeholder at end of macro body",s);if("#"===(s=a[--i]).text)a.splice(i+1,1);else{if(!/^[1-9]$/.test(s.text))throw new o("Not a valid argument number",s);var h;(h=a).splice.apply(h,[i,2].concat(n[+s.text-1]))}}}return this.pushTokens(a),a},e.expandAfterFuture=function(){return this.expandOnce(),this.future()},e.expandNextToken=function(){for(;;){var t=this.expandOnce();if(t instanceof n){if("\\relax"!==t.text)return this.stack.pop();this.stack.pop()}}throw new Error},e.expandMacro=function(t){if(this.macros.get(t)){var e=[],r=this.stack.length;for(this.pushToken(new n(t));this.stack.length>r;)this.expandOnce()instanceof n&&e.push(this.stack.pop());return e}},e.expandMacroAsText=function(t){var e=this.expandMacro(t);return e?e.map((function(t){return t.text})).join(""):e},e._getExpansion=function(t){var e=this.macros.get(t);if(null==e)return e;var r="function"==typeof e?e(this):e;if("string"==typeof r){var a=0;if(-1!==r.indexOf("#"))for(var n=r.replace(/##/g,"");-1!==n.indexOf("#"+(a+1));)++a;for(var i=new sa(r,this.settings),o=[],s=i.lex();"EOF"!==s.text;)o.push(s),s=i.lex();return o.reverse(),{tokens:o,numArgs:a}}return r},e.isDefined=function(t){return this.macros.has(t)||na.hasOwnProperty(t)||$.math.hasOwnProperty(t)||$.text.hasOwnProperty(t)||va.hasOwnProperty(t)},t}(),ya={"́":{text:"\\'",math:"\\acute"},"̀":{text:"\\`",math:"\\grave"},"̈":{text:'\\"',math:"\\ddot"},"̃":{text:"\\~",math:"\\tilde"},"̄":{text:"\\=",math:"\\bar"},"̆":{text:"\\u",math:"\\breve"},"̌":{text:"\\v",math:"\\check"},"̂":{text:"\\^",math:"\\hat"},"̇":{text:"\\.",math:"\\dot"},"̊":{text:"\\r",math:"\\mathring"},"̋":{text:"\\H"}},wa={"á":"á","à":"à","ä":"ä","ǟ":"ǟ","ã":"ã","ā":"ā","ă":"ă","ắ":"ắ","ằ":"ằ","ẵ":"ẵ","ǎ":"ǎ","â":"â","ấ":"ấ","ầ":"ầ","ẫ":"ẫ","ȧ":"ȧ","ǡ":"ǡ","å":"å","ǻ":"ǻ","ḃ":"ḃ","ć":"ć","č":"č","ĉ":"ĉ","ċ":"ċ","ď":"ď","ḋ":"ḋ","é":"é","è":"è","ë":"ë","ẽ":"ẽ","ē":"ē","ḗ":"ḗ","ḕ":"ḕ","ĕ":"ĕ","ě":"ě","ê":"ê","ế":"ế","ề":"ề","ễ":"ễ","ė":"ė","ḟ":"ḟ","ǵ":"ǵ","ḡ":"ḡ","ğ":"ğ","ǧ":"ǧ","ĝ":"ĝ","ġ":"ġ","ḧ":"ḧ","ȟ":"ȟ","ĥ":"ĥ","ḣ":"ḣ","í":"í","ì":"ì","ï":"ï","ḯ":"ḯ","ĩ":"ĩ","ī":"ī","ĭ":"ĭ","ǐ":"ǐ","î":"î","ǰ":"ǰ","ĵ":"ĵ","ḱ":"ḱ","ǩ":"ǩ","ĺ":"ĺ","ľ":"ľ","ḿ":"ḿ","ṁ":"ṁ","ń":"ń","ǹ":"ǹ","ñ":"ñ","ň":"ň","ṅ":"ṅ","ó":"ó","ò":"ò","ö":"ö","ȫ":"ȫ","õ":"õ","ṍ":"ṍ","ṏ":"ṏ","ȭ":"ȭ","ō":"ō","ṓ":"ṓ","ṑ":"ṑ","ŏ":"ŏ","ǒ":"ǒ","ô":"ô","ố":"ố","ồ":"ồ","ỗ":"ỗ","ȯ":"ȯ","ȱ":"ȱ","ő":"ő","ṕ":"ṕ","ṗ":"ṗ","ŕ":"ŕ","ř":"ř","ṙ":"ṙ","ś":"ś","ṥ":"ṥ","š":"š","ṧ":"ṧ","ŝ":"ŝ","ṡ":"ṡ","ẗ":"ẗ","ť":"ť","ṫ":"ṫ","ú":"ú","ù":"ù","ü":"ü","ǘ":"ǘ","ǜ":"ǜ","ǖ":"ǖ","ǚ":"ǚ","ũ":"ũ","ṹ":"ṹ","ū":"ū","ṻ":"ṻ","ŭ":"ŭ","ǔ":"ǔ","û":"û","ů":"ů","ű":"ű","ṽ":"ṽ","ẃ":"ẃ","ẁ":"ẁ","ẅ":"ẅ","ŵ":"ŵ","ẇ":"ẇ","ẘ":"ẘ","ẍ":"ẍ","ẋ":"ẋ","ý":"ý","ỳ":"ỳ","ÿ":"ÿ","ỹ":"ỹ","ȳ":"ȳ","ŷ":"ŷ","ẏ":"ẏ","ẙ":"ẙ","ź":"ź","ž":"ž","ẑ":"ẑ","ż":"ż","Á":"Á","À":"À","Ä":"Ä","Ǟ":"Ǟ","Ã":"Ã","Ā":"Ā","Ă":"Ă","Ắ":"Ắ","Ằ":"Ằ","Ẵ":"Ẵ","Ǎ":"Ǎ","Â":"Â","Ấ":"Ấ","Ầ":"Ầ","Ẫ":"Ẫ","Ȧ":"Ȧ","Ǡ":"Ǡ","Å":"Å","Ǻ":"Ǻ","Ḃ":"Ḃ","Ć":"Ć","Č":"Č","Ĉ":"Ĉ","Ċ":"Ċ","Ď":"Ď","Ḋ":"Ḋ","É":"É","È":"È","Ë":"Ë","Ẽ":"Ẽ","Ē":"Ē","Ḗ":"Ḗ","Ḕ":"Ḕ","Ĕ":"Ĕ","Ě":"Ě","Ê":"Ê","Ế":"Ế","Ề":"Ề","Ễ":"Ễ","Ė":"Ė","Ḟ":"Ḟ","Ǵ":"Ǵ","Ḡ":"Ḡ","Ğ":"Ğ","Ǧ":"Ǧ","Ĝ":"Ĝ","Ġ":"Ġ","Ḧ":"Ḧ","Ȟ":"Ȟ","Ĥ":"Ĥ","Ḣ":"Ḣ","Í":"Í","Ì":"Ì","Ï":"Ï","Ḯ":"Ḯ","Ĩ":"Ĩ","Ī":"Ī","Ĭ":"Ĭ","Ǐ":"Ǐ","Î":"Î","İ":"İ","Ĵ":"Ĵ","Ḱ":"Ḱ","Ǩ":"Ǩ","Ĺ":"Ĺ","Ľ":"Ľ","Ḿ":"Ḿ","Ṁ":"Ṁ","Ń":"Ń","Ǹ":"Ǹ","Ñ":"Ñ","Ň":"Ň","Ṅ":"Ṅ","Ó":"Ó","Ò":"Ò","Ö":"Ö","Ȫ":"Ȫ","Õ":"Õ","Ṍ":"Ṍ","Ṏ":"Ṏ","Ȭ":"Ȭ","Ō":"Ō","Ṓ":"Ṓ","Ṑ":"Ṑ","Ŏ":"Ŏ","Ǒ":"Ǒ","Ô":"Ô","Ố":"Ố","Ồ":"Ồ","Ỗ":"Ỗ","Ȯ":"Ȯ","Ȱ":"Ȱ","Ő":"Ő","Ṕ":"Ṕ","Ṗ":"Ṗ","Ŕ":"Ŕ","Ř":"Ř","Ṙ":"Ṙ","Ś":"Ś","Ṥ":"Ṥ","Š":"Š","Ṧ":"Ṧ","Ŝ":"Ŝ","Ṡ":"Ṡ","Ť":"Ť","Ṫ":"Ṫ","Ú":"Ú","Ù":"Ù","Ü":"Ü","Ǘ":"Ǘ","Ǜ":"Ǜ","Ǖ":"Ǖ","Ǚ":"Ǚ","Ũ":"Ũ","Ṹ":"Ṹ","Ū":"Ū","Ṻ":"Ṻ","Ŭ":"Ŭ","Ǔ":"Ǔ","Û":"Û","Ů":"Ů","Ű":"Ű","Ṽ":"Ṽ","Ẃ":"Ẃ","Ẁ":"Ẁ","Ẅ":"Ẅ","Ŵ":"Ŵ","Ẇ":"Ẇ","Ẍ":"Ẍ","Ẋ":"Ẋ","Ý":"Ý","Ỳ":"Ỳ","Ÿ":"Ÿ","Ỹ":"Ỹ","Ȳ":"Ȳ","Ŷ":"Ŷ","Ẏ":"Ẏ","Ź":"Ź","Ž":"Ž","Ẑ":"Ẑ","Ż":"Ż","ά":"ά","ὰ":"ὰ","ᾱ":"ᾱ","ᾰ":"ᾰ","έ":"έ","ὲ":"ὲ","ή":"ή","ὴ":"ὴ","ί":"ί","ὶ":"ὶ","ϊ":"ϊ","ΐ":"ΐ","ῒ":"ῒ","ῑ":"ῑ","ῐ":"ῐ","ό":"ό","ὸ":"ὸ","ύ":"ύ","ὺ":"ὺ","ϋ":"ϋ","ΰ":"ΰ","ῢ":"ῢ","ῡ":"ῡ","ῠ":"ῠ","ώ":"ώ","ὼ":"ὼ","Ύ":"Ύ","Ὺ":"Ὺ","Ϋ":"Ϋ","Ῡ":"Ῡ","Ῠ":"Ῠ","Ώ":"Ώ","Ὼ":"Ὼ"},ka=function(){function t(t,e){this.mode=void 0,this.gullet=void 0,this.settings=void 0,this.leftrightDepth=void 0,this.nextToken=void 0,this.mode="math",this.gullet=new ba(t,e,this.mode),this.settings=e,this.leftrightDepth=0}var e=t.prototype;return e.expect=function(t,e){if(void 0===e&&(e=!0),this.fetch().text!==t)throw new o("Expected '"+t+"', got '"+this.fetch().text+"'",this.fetch());e&&this.consume()},e.consume=function(){this.nextToken=null},e.fetch=function(){return null==this.nextToken&&(this.nextToken=this.gullet.expandNextToken()),this.nextToken},e.switchMode=function(t){this.mode=t,this.gullet.switchMode(t)},e.parse=function(){this.gullet.beginGroup(),this.settings.colorIsTextColor&&this.gullet.macros.set("\\color","\\textcolor");var t=this.parseExpression(!1);return this.expect("EOF"),this.gullet.endGroup(),t},e.parseExpression=function(e,r){for(var a=[];;){"math"===this.mode&&this.consumeSpaces();var n=this.fetch();if(-1!==t.endOfExpression.indexOf(n.text))break;if(r&&n.text===r)break;if(e&&na[n.text]&&na[n.text].infix)break;var i=this.parseAtom(r);if(!i)break;a.push(i)}return"text"===this.mode&&this.formLigatures(a),this.handleInfixNodes(a)},e.handleInfixNodes=function(t){for(var e,r=-1,a=0;a0&&!l||0===s&&!l&&"math"===this.mode,c=this.parseGroupOfType("argument to '"+t+"'",h,l,a,m);if(!c){if(l){i.push(null);continue}throw new o("Expected group after '"+t+"'",this.fetch())}(l?i:n).push(c)}return{args:n,optArgs:i}},e.parseGroupOfType=function(t,e,r,a,n){switch(e){case"color":return n&&this.consumeSpaces(),this.parseColorGroup(r);case"size":return n&&this.consumeSpaces(),this.parseSizeGroup(r);case"url":return this.parseUrlGroup(r,n);case"math":case"text":return this.parseGroup(t,r,a,void 0,e,n);case"hbox":var i=this.parseGroup(t,r,a,void 0,"text",n);return i?{type:"styling",mode:i.mode,body:[i],style:"text"}:i;case"raw":if(n&&this.consumeSpaces(),r&&"{"===this.fetch().text)return null;var s=this.parseStringGroup("raw",r,!0);if(s)return{type:"raw",mode:"text",string:s.text};throw new o("Expected raw group",this.fetch());case"original":case null:case void 0:return this.parseGroup(t,r,a,void 0,void 0,n);default:throw new o("Unknown group type as "+t,this.fetch())}},e.consumeSpaces=function(){for(;" "===this.fetch().text;)this.consume()},e.parseStringGroup=function(t,e,r){var a=e?"[":"{",n=e?"]":"}",i=this.fetch();if(i.text!==a){if(e)return null;if(r&&"EOF"!==i.text&&/[^{}[\]]/.test(i.text))return this.consume(),i}var s=this.mode;this.mode="text",this.expect(a);for(var h,l="",m=this.fetch(),c=0,u=m;(h=this.fetch()).text!==n||r&&c>0;){switch(h.text){case"EOF":throw new o("Unexpected end of input in "+t,m.range(u,l));case a:c++;break;case n:c--}l+=(u=h).text,this.consume()}return this.expect(n),this.mode=s,m.range(u,l)},e.parseRegexGroup=function(t,e){var r=this.mode;this.mode="text";for(var a,n=this.fetch(),i=n,s="";"EOF"!==(a=this.fetch()).text&&t.test(s+a.text);)s+=(i=a).text,this.consume();if(""===s)throw new o("Invalid "+e+": '"+n.text+"'",n);return this.mode=r,n.range(i,s)},e.parseColorGroup=function(t){var e=this.parseStringGroup("color",t);if(!e)return null;var r=/^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i.exec(e.text);if(!r)throw new o("Invalid color: '"+e.text+"'",e);var a=r[0];return/^[0-9a-f]{6}$/i.test(a)&&(a="#"+a),{type:"color-token",mode:this.mode,color:a}},e.parseSizeGroup=function(t){var e,r=!1;if(!(e=t||"{"===this.fetch().text?this.parseStringGroup("size",t):this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/,"size")))return null;t||0!==e.text.length||(e.text="0pt",r=!0);var a=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(e.text);if(!a)throw new o("Invalid size: '"+e.text+"'",e);var n={number:+(a[1]+a[2]),unit:a[3]};if(!At(n))throw new o("Invalid unit: '"+n.unit+"'",e);return{type:"size",mode:this.mode,value:n,isBlank:r}},e.parseUrlGroup=function(t,e){this.gullet.lexer.setCatcode("%",13);var r=this.parseStringGroup("url",t,!0);if(this.gullet.lexer.setCatcode("%",14),!r)return null;var a=r.text.replace(/\\([#$%&~_^{}])/g,"$1");return{type:"url",mode:this.mode,url:a}},e.parseGroup=function(e,r,n,i,s,h){var l=this.mode;s&&this.switchMode(s),h&&this.consumeSpaces();var m,c=this.fetch(),u=c.text;if(r?"["===u:"{"===u||"\\begingroup"===u){this.consume();var p=t.endOfGroup[u];this.gullet.beginGroup();var d=this.parseExpression(!1,p),f=this.fetch();this.expect(p),this.gullet.endGroup(),m={type:"ordgroup",mode:this.mode,loc:a.range(c,f),body:d,semisimple:"\\begingroup"===u||void 0}}else if(r)m=null;else if(null==(m=this.parseFunction(i,e,n)||this.parseSymbol())&&"\\"===u[0]&&!va.hasOwnProperty(u)){if(this.settings.throwOnError)throw new o("Undefined control sequence: "+u,c);m=this.formatUnsupportedCmd(u),this.consume()}return s&&this.switchMode(l),m},e.formLigatures=function(t){for(var e=t.length-1,r=0;r=0&&this.settings.reportNonstrict("unicodeTextInMathMode",'Latin-1/Unicode text character "'+e[0]+'" used in math mode',t);var h,l=$[this.mode][e].group,m=a.range(t);if(_.hasOwnProperty(l)){var c=l;h={type:"atom",mode:this.mode,family:c,loc:m,text:e}}else h={type:l,mode:this.mode,loc:m,text:e};i=h}else{if(!(e.charCodeAt(0)>=128))return null;this.settings.strict&&(M(e.charCodeAt(0))?"math"===this.mode&&this.settings.reportNonstrict("unicodeTextInMathMode",'Unicode text character "'+e[0]+'" used in math mode',t):this.settings.reportNonstrict("unknownSymbol",'Unrecognized Unicode character "'+e[0]+'" ('+e.charCodeAt(0)+")",t)),i={type:"textord",mode:"text",loc:a.range(t),text:e}}if(this.consume(),s)for(var u=0;u/g,p=//g;$docsify.plugins=[].concat((function(t){t.beforeEach(t=>{let e=t.replace(/(.*)<\/code>/g,(function(t,e){return`${e.replace(/`/g,"c194a9ec")}`})).replace(/\$`\$/g,"c194a9ed").replace(/\\`\{/g,"c194a9ee").replace(/\\\$/g,"c194a9eb").replace(/`[^`]*`/g,(function(t){return t.replace(/\$/g,"c194a9ef")})).replace(h,"`");return e=e.replace(l,"$ `$").replace(m,"\\`{"),e=e.replace(/(\$\$)([\s\S]*?)(\$\$)/g,(function(t,e,r){return"\x3c!-- begin-block-katex"+r+"end-block-katex--\x3e"})).replace(/(\$)([\s\S]*?)(\$)/g,(function(t,e,r){return"c194a9eg\x3c!-- begin-inline-katex"+r.replace(s,"\\$")+"end-inline-katex--\x3e"})).replace(s,"\\$"),e}),t.afterEach((function(t,e){let r=t.replace(u,(function(t,e){return n.a.renderToString(e,i)}));r=r.replace(p,(function(t,e){return n.a.renderToString(e,o)})),e(r.replace(c,"$"))}))}),$docsify.plugins)}]); \ No newline at end of file diff --git a/asset/docsify-quick-page.css b/asset/docsify-quick-page.css deleted file mode 100644 index 2cbba5b7..00000000 --- a/asset/docsify-quick-page.css +++ /dev/null @@ -1,37 +0,0 @@ -#prev-page-button { - position:fixed; - top:140px; - width: 35px; - height: 35px; - right: 15px; - background-color: transparent; - background-image: url(left.svg); - background-repeat: no-repeat; - background-size: cover; - border:0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - outline:none; - cursor: pointer; -} - -#next-page-button { - position:fixed; - top:180px; - width:35px; - height:35px; - right:15px; - background-color: transparent; - background-image: url(right.svg); - background-repeat: no-repeat; - background-size: cover; - border:0; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - outline:none; - cursor: pointer; -} \ No newline at end of file diff --git a/asset/docsify-quick-page.js b/asset/docsify-quick-page.js deleted file mode 100644 index d472eeb6..00000000 --- a/asset/docsify-quick-page.js +++ /dev/null @@ -1,42 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - var prevBtn = document.createElement("div") - prevBtn.id = "prev-page-button" - document.body.appendChild(prevBtn) - var nextBtn = document.createElement("div"); - nextBtn.id = "next-page-button" - document.body.appendChild(nextBtn) - - var links = null - var linkMap = null - var getCurIdx = function() { - if (!links) { - links = Array - .from(document.querySelectorAll(".sidebar-nav a")) - .map(x => x.href) - linkMap = {} - links.forEach((x, i) => linkMap[x] = i) - } - - var elem = document.querySelector(".active a") - var curIdx = elem? linkMap[elem.href]: -1 - return curIdx - } - - prevBtn.addEventListener('click', function () { - if (!document.body.classList.contains('ready')) - return - var curIdx = getCurIdx() - location.href = curIdx == -1? - links[0]: - links[(curIdx - 1 + links.length) % links.length] - document.body.scrollIntoView() - }, false) - - nextBtn.addEventListener('click', function () { - if (!document.body.classList.contains('ready')) - return - var curIdx = getCurIdx() - location.href = links[(curIdx + 1) % links.length] - document.body.scrollIntoView() - }, false) -}) \ No newline at end of file diff --git a/asset/docsify-sidebar-collapse.min.js b/asset/docsify-sidebar-collapse.min.js deleted file mode 100644 index 2b067c7e..00000000 --- a/asset/docsify-sidebar-collapse.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){("object"!=typeof exports||"undefined"==typeof module)&&"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";function e(e,n){var t,a=(n=void 0===n?{}:n).insertAt;e&&"undefined"!=typeof document&&(t=document.head||document.getElementsByTagName("head")[0],(n=document.createElement("style")).type="text/css","top"===a&&t.firstChild?t.insertBefore(n,t.firstChild):t.appendChild(n),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e)))}var t;function a(e){e&&null!=t&&(e=e.getBoundingClientRect().top,document.querySelector(".sidebar").scrollBy(0,e-t))}function n(){requestAnimationFrame(function(){var e=document.querySelector(".app-sub-sidebar > .active");if(e)for(e.parentNode.parentNode.querySelectorAll(".app-sub-sidebar").forEach(function(e){return e.classList.remove("open")});e.parentNode.classList.contains("app-sub-sidebar")&&!e.parentNode.classList.contains("open");)e.parentNode.classList.add("open"),e=e.parentNode})}function o(e){t=e.target.getBoundingClientRect().top;var n=d(e.target,"LI",2);n&&(n.classList.contains("open")?(n.classList.remove("open"),setTimeout(function(){n.classList.add("collapse")},0)):(function(e){if(e)for(e.classList.remove("open","active");e&&"sidebar-nav"!==e.className&&e.parentNode;)"LI"!==e.parentNode.tagName&&"app-sub-sidebar"!==e.parentNode.className||e.parentNode.classList.remove("open"),e=e.parentNode}(s()),i(n),setTimeout(function(){n.classList.remove("collapse")},0)),a(n))}function s(){var e=document.querySelector(".sidebar-nav .active");return e||(e=d(document.querySelector('.sidebar-nav a[href="'.concat(decodeURIComponent(location.hash).replace(/ /gi,"%20"),'"]')),"LI",2))&&e.classList.add("active"),e}function i(e){if(e)for(e.classList.add("open","active");e&&"sidebar-nav"!==e.className&&e.parentNode;)"LI"!==e.parentNode.tagName&&"app-sub-sidebar"!==e.parentNode.className||e.parentNode.classList.add("open"),e=e.parentNode}function d(e,n,t){if(e&&e.tagName===n)return e;for(var a=0;e;){if(t<++a)return;if(e.parentNode.tagName===n)return e.parentNode;e=e.parentNode}}e(".sidebar-nav > ul > li ul {\n display: none;\n}\n\n.app-sub-sidebar {\n display: none;\n}\n\n.app-sub-sidebar.open {\n display: block;\n}\n\n.sidebar-nav .open > ul:not(.app-sub-sidebar),\n.sidebar-nav .active:not(.collapse) > ul {\n display: block;\n}\n\n/* 抖动 */\n.sidebar-nav li.open:not(.collapse) > ul {\n display: block;\n}\n\n.active + ul.app-sub-sidebar {\n display: block;\n}\n"),document.addEventListener("scroll",n);e("@media screen and (max-width: 768px) {\n /* 移动端适配 */\n .markdown-section {\n max-width: none;\n padding: 16px;\n }\n /* 改变原来按钮热区大小 */\n .sidebar-toggle {\n padding: 0 0 10px 10px;\n }\n /* my pin */\n .sidebar-pin {\n appearance: none;\n outline: none;\n position: fixed;\n bottom: 0;\n border: none;\n width: 40px;\n height: 40px;\n background: transparent;\n }\n}\n");var r,c="DOCSIFY_SIDEBAR_PIN_FLAG";function l(){var e="true"===(e=localStorage.getItem(c));localStorage.setItem(c,!e),e?(document.querySelector(".sidebar").style.transform="translateX(0)",document.querySelector(".content").style.transform="translateX(0)"):(document.querySelector(".sidebar").style.transform="translateX(300px)",document.querySelector(".content").style.transform="translateX(300px)")}768 ul"),1),a(t),n(e)}),e.ready(function(){document.querySelector(".sidebar-nav").addEventListener("click",o)})})}); \ No newline at end of file diff --git a/asset/docsify.min.js b/asset/docsify.min.js deleted file mode 100644 index 13ee7221..00000000 --- a/asset/docsify.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){function s(n){var r=Object.create(null);return function(e){var t=c(e)?e:JSON.stringify(e);return r[t]||(r[t]=n(e))}}var a=s(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),l=Object.prototype.hasOwnProperty,f=Object.assign||function(e){for(var t=arguments,n=1;n/gm),Ve=$(/^data-[\-\w.\u00B7-\uFFFF]/),Xe=$(/^aria-[\-\w]+$/),Ke=$(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Qe=$(/^(?:\w+script|data):/i),Je=$(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g),et="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function tt(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t

').querySelector("svg img")&&(o=!0)}catch(e){}}(),function(){try{var e=$("</title><img>");ze(/<\/title/,e.querySelector("title").innerHTML)&&(s=!0)}catch(e){}}());function fe(e){return _.call(e.ownerDocument||e,e,r.SHOW_ELEMENT|r.SHOW_COMMENT|r.SHOW_TEXT,function(){return r.FILTER_ACCEPT},!1)}function he(e){return"object"===(void 0===f?"undefined":et(f))?e instanceof f:e&&"object"===(void 0===e?"undefined":et(e))&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName}function ge(e,t,n){E[e]&&we(E[e],function(e){e.call(d,t,n,pe)})}function me(e){var t=void 0;if(ge("beforeSanitizeElements",e,null),function(e){return!(e instanceof h||e instanceof g||"string"==typeof e.nodeName&&"string"==typeof e.textContent&&"function"==typeof e.removeChild&&e.attributes instanceof a&&"function"==typeof e.removeAttribute&&"function"==typeof e.setAttribute&&"string"==typeof e.namespaceURI)}(e))return R(e),!0;var n=Le(e.nodeName);if(ge("uponSanitizeElement",e,{tagName:n,allowedTags:j}),("svg"===n||"math"===n)&&0!==e.querySelectorAll("p, br").length)return R(e),!0;if(j[n]&&!U[n])return"noscript"===n&&ze(/<\/noscript/i,e.innerHTML)?(R(e),!0):"noembed"===n&&ze(/<\/noembed/i,e.innerHTML)?(R(e),!0):(!G||e.firstElementChild||e.content&&e.content.firstElementChild||!ze(/</g,e.textContent)||(Te(d.removed,{element:e.cloneNode()}),e.innerHTML?e.innerHTML=Ce(e.innerHTML,/</g,"<"):e.innerHTML=Ce(e.textContent,/</g,"<")),V&&3===e.nodeType&&(t=e.textContent,t=Ce(t,F," "),t=Ce(t,z," "),e.textContent!==t&&(Te(d.removed,{element:e.cloneNode()}),e.textContent=t)),ge("afterSanitizeElements",e,null),!1);if(ie&&!se[n]&&"function"==typeof e.insertAdjacentHTML)try{var r=e.innerHTML;e.insertAdjacentHTML("AfterEnd",y?y.createHTML(r):r)}catch(e){}return R(e),!0}function ve(e,t,n){if(re&&("id"===t||"name"===t)&&(n in l||n in de))return!1;if(W&&ze(O,t));else if(Z&&ze(M,t));else{if(!I[t]||B[t])return!1;if(ce[t]);else if(ze(D,Ce(n,P,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==$e(n,"data:")||!le[e])if(Y&&!ze(N,Ce(n,P,"")));else if(n)return!1}return!0}function be(e){var t=void 0,n=void 0,r=void 0,i=void 0,a=void 0;ge("beforeSanitizeAttributes",e,null);var o=e.attributes;if(o){var s={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:I};for(a=o.length;a--;){var l=t=o[a],c=l.name,u=l.namespaceURI;if(n=Fe(t.value),r=Le(c),s.attrName=r,s.attrValue=n,s.keepAttr=!0,s.forceKeepAttr=void 0,ge("uponSanitizeAttribute",e,s),n=s.attrValue,!s.forceKeepAttr){if("name"===r&&"IMG"===e.nodeName&&o.id)i=o.id,o=Ee(o,[]),C("id",e),C(c,e),_e(o,i)>a&&e.setAttribute("id",i.value);else{if("INPUT"===e.nodeName&&"type"===r&&"file"===n&&s.keepAttr&&(I[r]||!B[r]))continue;"id"===c&&e.setAttribute(c,""),C(c,e)}if(s.keepAttr)if(G&&ze(/\/>/i,n))C(c,e);else if(ze(/svg|math/i,e.namespaceURI)&&ze(Oe("</("+Se(ke(se),"|")+")","i"),n))C(c,e);else{V&&(n=Ce(n,F," "),n=Ce(n,z," "));var p=e.nodeName.toLowerCase();if(ve(p,r,n))try{u?e.setAttributeNS(u,c,n):e.setAttribute(c,n),Ae(d.removed)}catch(e){}}}}ge("afterSanitizeAttributes",e,null)}}function ye(e){var t=void 0,n=fe(e);for(ge("beforeSanitizeShadowDOM",e,null);t=n.nextNode();)ge("uponSanitizeShadowNode",t,null),me(t)||(t.content instanceof p&&ye(t.content),be(t));ge("afterSanitizeShadowDOM",e,null)}return d.sanitize=function(e,t){var n=void 0,r=void 0,i=void 0,a=void 0,o=void 0;if("string"!=typeof(e=e||"\x3c!--\x3e")&&!he(e)){if("function"!=typeof e.toString)throw Me("toString is not a function");if("string"!=typeof(e=e.toString()))throw Me("dirty is not a string, aborting")}if(!d.isSupported){if("object"===et(c.toStaticHTML)||"function"==typeof c.toStaticHTML){if("string"==typeof e)return c.toStaticHTML(e);if(he(e))return c.toStaticHTML(e.outerHTML)}return e}if(K||L(t),d.removed=[],"string"==typeof e&&(ae=!1),ae);else if(e instanceof f)1===(r=(n=$("\x3c!--\x3e")).ownerDocument.importNode(e,!0)).nodeType&&"BODY"===r.nodeName?n=r:"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!J&&!V&&!X&&ne&&-1===e.indexOf("<"))return y?y.createHTML(e):e;if(!(n=$(e)))return J?null:k}n&&Q&&R(n.firstChild);for(var s=fe(ae?e:n);i=s.nextNode();)3===i.nodeType&&i===a||me(i)||(i.content instanceof p&&ye(i.content),be(i),a=i);if(a=null,ae)return e;if(J){if(ee)for(o=A.call(n.ownerDocument);n.firstChild;)o.appendChild(n.firstChild);else o=n;return te&&(o=T.call(u,o,!0)),o}var l=X?n.outerHTML:n.innerHTML;return V&&(l=Ce(l,F," "),l=Ce(l,z," ")),y&&ne?y.createHTML(l):l},d.setConfig=function(e){L(e),K=!0},d.clearConfig=function(){pe=null,K=!1},d.isValidAttribute=function(e,t,n){pe||L({});var r=Le(e),i=Le(t);return ve(r,i,n)},d.addHook=function(e,t){"function"==typeof t&&(E[e]=E[e]||[],Te(E[e],t))},d.removeHook=function(e){E[e]&&Ae(E[e])},d.removeHooks=function(e){E[e]&&(E[e]=[])},d.removeAllHooks=function(){E={}},d}();function H(e){var t,n=e.loaded,r=e.total,i=e.step;P||function(){var e=g("div");e.classList.add("progress"),o(v,e),P=e}(),t=i?80<(t=parseInt(P.style.width||0,10)+i)?80:t:Math.floor(n/r*100),P.style.opacity=1,P.style.width=95<=t?"100%":t+"%",95<=t&&(clearTimeout(D),D=setTimeout(function(e){P.style.opacity=0,P.style.width="0%"},200))}var I={};function q(a,e,t){void 0===e&&(e=!1),void 0===t&&(t={});function n(){o.addEventListener.apply(o,arguments)}var o=new XMLHttpRequest,r=I[a];if(r)return{then:function(e){return e(r.content,r.opt)},abort:p};for(var i in o.open("GET",a),t)l.call(t,i)&&o.setRequestHeader(i,t[i]);return o.send(),{then:function(r,i){if(void 0===i&&(i=p),e){var t=setInterval(function(e){return H({step:Math.floor(5*Math.random()+1)})},500);n("progress",H),n("loadend",function(e){H(e),clearInterval(t)})}n("error",i),n("load",function(e){var t=e.target;if(400<=t.status)i(t);else{var n=I[a]={content:t.response,opt:{updatedAt:o.getResponseHeader("last-modified")}};r(n.content,n.opt)}})},abort:function(e){return 4!==o.readyState&&o.abort()}}}function U(e,t){e.innerHTML=e.innerHTML.replace(/var\(\s*--theme-color.*?\)/g,t)}function B(e,t,r,i){void 0===i&&(i=p);var a=e._hooks[t],o=function(t){var e=a[t];if(t>=a.length)i(r);else if("function"==typeof e)if(2===e.length)e(r,function(e){r=e,o(t+1)});else{var n=e(r);r=void 0===n?r:n,o(t+1)}else o(t+1)};o(0)}var Z=u.title;function W(){var e=m("section.cover");if(e){var t=e.getBoundingClientRect().height;window.pageYOffset>=t||e.classList.contains("hidden")?_(v,"add","sticky"):_(v,"remove","sticky")}}function Y(e,t,r,n){var i=[];null!=(t=m(t))&&(i=y(t,"a"));var a,o=decodeURI(e.toURL(e.getCurrentPath()));return i.sort(function(e,t){return t.href.length-e.href.length}).forEach(function(e){var t=e.getAttribute("href"),n=r?e.parentNode:e;e.title=e.innerText,0!==o.indexOf(t)||a?_(n,"remove","active"):(a=e,_(n,"add","active"))}),n&&(u.title=a?a.title||a.innerText+" - "+Z:Z),a}var G=decodeURIComponent,V=encodeURIComponent;function X(e){var n={};return(e=e.trim().replace(/^(\?|#|&)/,""))&&e.split("&").forEach(function(e){var t=e.replace(/\+/g," ").split("=");n[t[0]]=t[1]&&G(t[1])}),n}function K(e,t){void 0===t&&(t=[]);var n=[];for(var r in e)-1<t.indexOf(r)||n.push(e[r]?(V(r)+"="+V(e[r])).toLowerCase():V(r));return n.length?"?"+n.join("&"):""}var Q=s(function(e){return/(:|(\/{2}))/g.test(e)}),J=s(function(e){return e.split(/[?#]/)[0]}),ee=s(function(e){if(/\/$/g.test(e))return e;var t=e.match(/(\S*\/)[^/]+$/);return t?t[1]:""}),te=s(function(e){return e.replace(/^\/+/,"/").replace(/([^:])\/{2,}/g,"$1/")}),ne=s(function(e){for(var t=e.replace(/^\//,"").split("/"),n=[],r=0,i=t.length;r<i;r++){var a=t[r];".."===a?n.pop():"."!==a&&n.push(a)}return"/"+n.join("/")});function re(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];return te(e.join("/"))}var ie=s(function(e){return e.replace("#","?id=")});function ae(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}var oe=(function(e,t,n){return t&&ae(e.prototype,t),n&&ae(e,n),e}(se,[{key:"getIntermediateValue",value:function(e){return this.decimal?e:Math.round(e)}},{key:"getFinalValue",value:function(){return this.end}}]),se);function se(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,se),this.start=e.start,this.end=e.end,this.decimal=e.decimal}function le(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}var ce=(function(e,t,n){return t&&le(e.prototype,t),n&&le(e,n),e}(ue,[{key:"begin",value:function(){return this.isRunning||this.next===this.end||(this.frame=window.requestAnimationFrame(this._tick.bind(this))),this}},{key:"stop",value:function(){return window.cancelAnimationFrame(this.frame),this.isRunning=!1,this.frame=null,this.timeStart=null,this.next=null,this}},{key:"on",value:function(e,t){return this.events[e]=this.events[e]||[],this.events[e].push(t),this}},{key:"_emit",value:function(e,t){var n=this,r=this.events[e];r&&r.forEach(function(e){return e.call(n,t)})}},{key:"_tick",value:function(e){this.isRunning=!0;var t=this.next||this.start;this.timeStart||(this.timeStart=e),this.timeElapsed=e-this.timeStart,this.next=this.ease(this.timeElapsed,this.start,this.end-this.start,this.duration),this._shouldTick(t)?(this._emit("tick",this.tweener.getIntermediateValue(this.next)),this.frame=window.requestAnimationFrame(this._tick.bind(this))):(this._emit("tick",this.tweener.getFinalValue()),this._emit("done",null))}},{key:"_shouldTick",value:function(e){return{up:this.next<this.end&&e<=this.next,down:this.next>this.end&&e>=this.next}[this.direction]}},{key:"_defaultEase",value:function(e,t,n,r){return(e/=r/2)<1?n/2*e*e+t:-n/2*(--e*(e-2)-1)+t}}]),ue);function ue(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,ue),this.duration=e.duration||1e3,this.ease=e.easing||this._defaultEase,this.tweener=e.tweener||new oe(e),this.start=this.tweener.start,this.end=this.tweener.end,this.frame=null,this.next=null,this.isRunning=!1,this.events={},this.direction=this.start<this.end?"up":"down"}var pe={},de=!1,fe=null,he=!0,ge=0;function me(e){if(he){for(var t,n=m(".sidebar"),r=y(".anchor"),i=b(n,".sidebar-nav"),a=b(n,"li.active"),o=document.documentElement,s=(o&&o.scrollTop||document.body.scrollTop)-ge,l=0,c=r.length;l<c;l+=1){var u=r[l];if(u.offsetTop>s){t=t||u;break}t=u}if(t){var p=pe[ve(e,t.getAttribute("data-id"))];if(p&&p!==a&&(a&&a.classList.remove("active"),p.classList.add("active"),a=p,!de&&v.classList.contains("sticky"))){var d=n.clientHeight,f=a.offsetTop+a.clientHeight+40,h=a.offsetTop>=i.scrollTop&&f<=i.scrollTop+d,g=f-0<d;n.scrollTop=h?i.scrollTop:g?0:f-d}}}}function ve(e,t){return decodeURIComponent(e)+"?id="+decodeURIComponent(t)}function be(e,t){if(t){var n=A().topMargin,r=b("#"+t);r&&function(e,t){void 0===t&&(t=0),fe&&fe.stop(),he=!1,fe=new ce({start:window.pageYOffset,end:e.getBoundingClientRect().top+window.pageYOffset-t,duration:500}).on("tick",function(e){return window.scrollTo(0,e)}).on("done",function(){he=!0,fe=null}).begin()}(r,n);var i=pe[ve(e,t)],a=b(m(".sidebar"),"li.active");a&&a.classList.remove("active"),i&&i.classList.add("active")}}var ye=u.scrollingElement||u.documentElement;var it="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function at(e,t){return e(t={exports:{}},t.exports),t.exports}function ot(e){return dt[e]}var st=at(function(t){function e(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}t.exports={defaults:{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1},getDefaults:e,changeDefaults:function(e){t.exports.defaults=e}}}),lt=(st.defaults,st.getDefaults,st.changeDefaults,/[&<>"']/),ct=/[&<>"']/g,ut=/[<>"']|&(?!#?\w+;)/,pt=/[<>"']|&(?!#?\w+;)/g,dt={"&":"&","<":"<",">":">",'"':""","'":"'"};var ft=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function ht(e){return e.replace(ft,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var gt=/(^|[^\[])\^/g;var mt=/[^\w:]/g,vt=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var bt={},yt=/^[^:]+:\/*[^/]*$/,kt=/^([^:]+:)[\s\S]*$/,xt=/^([^:]+:\/*[^/]*)[\s\S]*$/;function wt(e,t){bt[" "+e]||(yt.test(e)?bt[" "+e]=e+"/":bt[" "+e]=_t(e,"/",!0));var n=-1===(e=bt[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(kt,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(xt,"$1")+t:e+t}function _t(e,t,n){var r=e.length;if(0===r)return"";for(var i=0;i<r;){var a=e.charAt(r-i-1);if(a!==t||n){if(a===t||!n)break;i++}else i++}return e.substr(0,r-i)}var St=function(e,t){if(t){if(lt.test(e))return e.replace(ct,ot)}else if(ut.test(e))return e.replace(pt,ot);return e},At=ht,Tt=function(n,e){n=n.source||n,e=e||"";var r={replace:function(e,t){return t=(t=t.source||t).replace(gt,"$1"),n=n.replace(e,t),r},getRegex:function(){return new RegExp(n,e)}};return r},Et=function(e,t,n){if(e){var r;try{r=decodeURIComponent(ht(n)).replace(mt,"").toLowerCase()}catch(e){return null}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:")||0===r.indexOf("data:"))return null}t&&!vt.test(n)&&(n=wt(t,n));try{n=encodeURI(n).replace(/%25/g,"%")}catch(e){return null}return n},Lt={exec:function(){}},Rt=function(e){for(var t,n,r=arguments,i=1;i<arguments.length;i++)for(n in t=r[i])Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e},Ct=function(e,t){var n=e.replace(/\|/g,function(e,t,n){for(var r=!1,i=t;0<=--i&&"\\"===n[i];)r=!r;return r?"|":" |"}).split(/ \|/),r=0;if(n.length>t)n.splice(t);else for(;n.length<t;)n.push("");for(;r<n.length;r++)n[r]=n[r].trim().replace(/\\\|/g,"|");return n},$t=_t,Ft=function(e,t){if(-1===e.indexOf(t[1]))return-1;for(var n=e.length,r=0,i=0;i<n;i++)if("\\"===e[i])i++;else if(e[i]===t[0])r++;else if(e[i]===t[1]&&--r<0)return i;return-1},zt=function(e){e&&e.sanitize&&!e.silent&&console.warn("marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options")},Ot=st.defaults,Mt=$t,Nt=Ct,Pt=St,Dt=Ft;function jt(e,t,n){var r=t.href,i=t.title?Pt(t.title):null,a=e[1].replace(/\\([\[\]])/g,"$1");return"!"!==e[0].charAt(0)?{type:"link",raw:n,href:r,title:i,text:a}:{type:"image",raw:n,href:r,title:i,text:Pt(a)}}var Ht=function(){function e(e){this.options=e||Ot}return e.prototype.space=function(e){var t=this.rules.block.newline.exec(e);if(t)return 1<t[0].length?{type:"space",raw:t[0]}:{raw:"\n"}},e.prototype.code=function(e,t){var n=this.rules.block.code.exec(e);if(n){var r=t[t.length-1];if(r&&"paragraph"===r.type)return{raw:n[0],text:n[0].trimRight()};var i=n[0].replace(/^ {4}/gm,"");return{type:"code",raw:n[0],codeBlockStyle:"indented",text:this.options.pedantic?i:Mt(i,"\n")}}},e.prototype.fences=function(e){var t=this.rules.block.fences.exec(e);if(t){var n=t[0],r=function(e,t){var n=e.match(/^(\s+)(?:```)/);if(null===n)return t;var r=n[1];return t.split("\n").map(function(e){var t=e.match(/^\s+/);return null===t?e:t[0].length>=r.length?e.slice(r.length):e}).join("\n")}(n,t[3]||"");return{type:"code",raw:n,lang:t[2]?t[2].trim():t[2],text:r}}},e.prototype.heading=function(e){var t=this.rules.block.heading.exec(e);if(t)return{type:"heading",raw:t[0],depth:t[1].length,text:t[2]}},e.prototype.nptable=function(e){var t=this.rules.block.nptable.exec(e);if(t){var n={type:"table",header:Nt(t[1].replace(/^ *| *\| *$/g,"")),align:t[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:t[3]?t[3].replace(/\n$/,"").split("\n"):[],raw:t[0]};if(n.header.length===n.align.length){var r,i=n.align.length;for(r=0;r<i;r++)/^ *-+: *$/.test(n.align[r])?n.align[r]="right":/^ *:-+: *$/.test(n.align[r])?n.align[r]="center":/^ *:-+ *$/.test(n.align[r])?n.align[r]="left":n.align[r]=null;for(i=n.cells.length,r=0;r<i;r++)n.cells[r]=Nt(n.cells[r],n.header.length);return n}}},e.prototype.hr=function(e){var t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}},e.prototype.blockquote=function(e){var t=this.rules.block.blockquote.exec(e);if(t){var n=t[0].replace(/^ *> ?/gm,"");return{type:"blockquote",raw:t[0],text:n}}},e.prototype.list=function(e){var t=this.rules.block.list.exec(e);if(t){for(var n,r,i,a,o,s,l,c=t[0],u=t[2],p=1<u.length,d=")"===u[u.length-1],f={type:"list",raw:c,ordered:p,start:p?+u.slice(0,-1):"",loose:!1,items:[]},h=t[0].match(this.rules.block.item),g=!1,m=h.length,v=0;v<m;v++)r=(c=n=h[v]).length,~(n=n.replace(/^ *([*+-]|\d+[.)]) */,"")).indexOf("\n ")&&(r-=n.length,n=this.options.pedantic?n.replace(/^ {1,4}/gm,""):n.replace(new RegExp("^ {1,"+r+"}","gm"),"")),v!==m-1&&(i=this.rules.block.bullet.exec(h[v+1])[0],(p?1===i.length||!d&&")"===i[i.length-1]:1<i.length||this.options.smartLists&&i!==u)&&(a=h.slice(v+1).join("\n"),f.raw=f.raw.substring(0,f.raw.length-a.length),v=m-1)),o=g||/\n\n(?!\s*$)/.test(n),v!==m-1&&(g="\n"===n.charAt(n.length-1),o=o||g),o&&(f.loose=!0),l=void 0,(s=/^\[[ xX]\] /.test(n))&&(l=" "!==n[1],n=n.replace(/^\[[ xX]\] +/,"")),f.items.push({type:"list_item",raw:c,task:s,checked:l,loose:o,text:n});return f}},e.prototype.html=function(e){var t=this.rules.block.html.exec(e);if(t)return{type:this.options.sanitize?"paragraph":"html",raw:t[0],pre:!this.options.sanitizer&&("pre"===t[1]||"script"===t[1]||"style"===t[1]),text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(t[0]):Pt(t[0]):t[0]}},e.prototype.def=function(e){var t=this.rules.block.def.exec(e);if(t)return t[3]&&(t[3]=t[3].substring(1,t[3].length-1)),{tag:t[1].toLowerCase().replace(/\s+/g," "),raw:t[0],href:t[2],title:t[3]}},e.prototype.table=function(e){var t=this.rules.block.table.exec(e);if(t){var n={type:"table",header:Nt(t[1].replace(/^ *| *\| *$/g,"")),align:t[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:t[3]?t[3].replace(/\n$/,"").split("\n"):[]};if(n.header.length===n.align.length){n.raw=t[0];var r,i=n.align.length;for(r=0;r<i;r++)/^ *-+: *$/.test(n.align[r])?n.align[r]="right":/^ *:-+: *$/.test(n.align[r])?n.align[r]="center":/^ *:-+ *$/.test(n.align[r])?n.align[r]="left":n.align[r]=null;for(i=n.cells.length,r=0;r<i;r++)n.cells[r]=Nt(n.cells[r].replace(/^ *\| *| *\| *$/g,""),n.header.length);return n}}},e.prototype.lheading=function(e){var t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1]}},e.prototype.paragraph=function(e){var t=this.rules.block.paragraph.exec(e);if(t)return{type:"paragraph",raw:t[0],text:"\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1]}},e.prototype.text=function(e,t){var n=this.rules.block.text.exec(e);if(n){var r=t[t.length-1];return r&&"text"===r.type?{raw:n[0],text:n[0]}:{type:"text",raw:n[0],text:n[0]}}},e.prototype.escape=function(e){var t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:Pt(t[1])}},e.prototype.tag=function(e,t,n){var r=this.rules.inline.tag.exec(e);if(r)return!t&&/^<a /i.test(r[0])?t=!0:t&&/^<\/a>/i.test(r[0])&&(t=!1),!n&&/^<(pre|code|kbd|script)(\s|>)/i.test(r[0])?n=!0:n&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(r[0])&&(n=!1),{type:this.options.sanitize?"text":"html",raw:r[0],inLink:t,inRawBlock:n,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):Pt(r[0]):r[0]}},e.prototype.link=function(e){var t=this.rules.inline.link.exec(e);if(t){var n=Dt(t[2],"()");if(-1<n){var r=(0===t[0].indexOf("!")?5:4)+t[1].length+n;t[2]=t[2].substring(0,n),t[0]=t[0].substring(0,r).trim(),t[3]=""}var i=t[2],a="";if(this.options.pedantic){var o=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(i);a=o?(i=o[1],o[3]):""}else a=t[3]?t[3].slice(1,-1):"";return jt(t,{href:(i=i.trim().replace(/^<([\s\S]*)>$/,"$1"))?i.replace(this.rules.inline._escapes,"$1"):i,title:a?a.replace(this.rules.inline._escapes,"$1"):a},t[0])}},e.prototype.reflink=function(e,t){var n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){var r=(n[2]||n[1]).replace(/\s+/g," ");if((r=t[r.toLowerCase()])&&r.href)return jt(n,r,n[0]);var i=n[0].charAt(0);return{type:"text",raw:i,text:i}}},e.prototype.strong=function(e,t,n){void 0===n&&(n="");var r=this.rules.inline.strong.start.exec(e);if(r&&(!r[1]||r[1]&&(""===n||this.rules.inline.punctuation.exec(n)))){t=t.slice(-1*e.length);var i,a="**"===r[0]?this.rules.inline.strong.endAst:this.rules.inline.strong.endUnd;for(a.lastIndex=0;null!=(r=a.exec(t));)if(i=this.rules.inline.strong.middle.exec(t.slice(0,r.index+3)))return{type:"strong",raw:e.slice(0,i[0].length),text:e.slice(2,i[0].length-2)}}},e.prototype.em=function(e,t,n){void 0===n&&(n="");var r=this.rules.inline.em.start.exec(e);if(r&&(!r[1]||r[1]&&(""===n||this.rules.inline.punctuation.exec(n)))){t=t.slice(-1*e.length);var i,a="*"===r[0]?this.rules.inline.em.endAst:this.rules.inline.em.endUnd;for(a.lastIndex=0;null!=(r=a.exec(t));)if(i=this.rules.inline.em.middle.exec(t.slice(0,r.index+2)))return{type:"em",raw:e.slice(0,i[0].length),text:e.slice(1,i[0].length-1)}}},e.prototype.codespan=function(e){var t=this.rules.inline.code.exec(e);if(t){var n=t[2].replace(/\n/g," "),r=/[^ ]/.test(n),i=n.startsWith(" ")&&n.endsWith(" ");return r&&i&&(n=n.substring(1,n.length-1)),n=Pt(n,!0),{type:"codespan",raw:t[0],text:n}}},e.prototype.br=function(e){var t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}},e.prototype.del=function(e){var t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[1]}},e.prototype.autolink=function(e,t){var n,r,i=this.rules.inline.autolink.exec(e);if(i)return r="@"===i[2]?"mailto:"+(n=Pt(this.options.mangle?t(i[1]):i[1])):n=Pt(i[1]),{type:"link",raw:i[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}},e.prototype.url=function(e,t){var n;if(n=this.rules.inline.url.exec(e)){var r,i;if("@"===n[2])i="mailto:"+(r=Pt(this.options.mangle?t(n[0]):n[0]));else{for(var a;a=n[0],n[0]=this.rules.inline._backpedal.exec(n[0])[0],a!==n[0];);r=Pt(n[0]),i="www."===n[1]?"http://"+r:r}return{type:"link",raw:n[0],text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}}},e.prototype.inlineText=function(e,t,n){var r,i=this.rules.inline.text.exec(e);if(i)return r=t?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):Pt(i[0]):i[0]:Pt(this.options.smartypants?n(i[0]):i[0]),{type:"text",raw:i[0],text:r}},e}(),It=Lt,qt=Tt,Ut=Rt,Bt={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|<![A-Z][\\s\\S]*?>\\n*|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:It,table:It,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Bt.def=qt(Bt.def).replace("label",Bt._label).replace("title",Bt._title).getRegex(),Bt.bullet=/(?:[*+-]|\d{1,9}[.)])/,Bt.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,Bt.item=qt(Bt.item,"gm").replace(/bull/g,Bt.bullet).getRegex(),Bt.list=qt(Bt.list).replace(/bull/g,Bt.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Bt.def.source+")").getRegex(),Bt._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Bt._comment=/<!--(?!-?>)[\s\S]*?-->/,Bt.html=qt(Bt.html,"i").replace("comment",Bt._comment).replace("tag",Bt._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Bt.paragraph=qt(Bt._paragraph).replace("hr",Bt.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Bt._tag).getRegex(),Bt.blockquote=qt(Bt.blockquote).replace("paragraph",Bt.paragraph).getRegex(),Bt.normal=Ut({},Bt),Bt.gfm=Ut({},Bt.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Bt.gfm.nptable=qt(Bt.gfm.nptable).replace("hr",Bt.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Bt._tag).getRegex(),Bt.gfm.table=qt(Bt.gfm.table).replace("hr",Bt.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Bt._tag).getRegex(),Bt.pedantic=Ut({},Bt.normal,{html:qt("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Bt._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:It,paragraph:qt(Bt.normal._paragraph).replace("hr",Bt.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Bt.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var Zt={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:It,tag:"^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",strong:{start:/^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,middle:/^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,endAst:/[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation\s]|$))/,endUnd:/[^\s]__(?!_)(?:(?=[punctuation\s])|$)/},em:{start:/^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,middle:/^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,endAst:/[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation\s]|$))/,endUnd:/[^\s]_(?!_)(?:(?=[punctuation\s])|$)/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:It,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n))|(?= {2,}\n))/,punctuation:/^([\s*punctuation])/,_punctuation:"!\"#$%&'()+\\-.,/:;<=>?@\\[\\]`^{|}~"};Zt.punctuation=qt(Zt.punctuation).replace(/punctuation/g,Zt._punctuation).getRegex(),Zt._blockSkip="\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>",Zt._overlapSkip="__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*",Zt.em.start=qt(Zt.em.start).replace(/punctuation/g,Zt._punctuation).getRegex(),Zt.em.middle=qt(Zt.em.middle).replace(/punctuation/g,Zt._punctuation).replace(/overlapSkip/g,Zt._overlapSkip).getRegex(),Zt.em.endAst=qt(Zt.em.endAst,"g").replace(/punctuation/g,Zt._punctuation).getRegex(),Zt.em.endUnd=qt(Zt.em.endUnd,"g").replace(/punctuation/g,Zt._punctuation).getRegex(),Zt.strong.start=qt(Zt.strong.start).replace(/punctuation/g,Zt._punctuation).getRegex(),Zt.strong.middle=qt(Zt.strong.middle).replace(/punctuation/g,Zt._punctuation).replace(/blockSkip/g,Zt._blockSkip).getRegex(),Zt.strong.endAst=qt(Zt.strong.endAst,"g").replace(/punctuation/g,Zt._punctuation).getRegex(),Zt.strong.endUnd=qt(Zt.strong.endUnd,"g").replace(/punctuation/g,Zt._punctuation).getRegex(),Zt.blockSkip=qt(Zt._blockSkip,"g").getRegex(),Zt.overlapSkip=qt(Zt._overlapSkip,"g").getRegex(),Zt._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,Zt._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,Zt._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,Zt.autolink=qt(Zt.autolink).replace("scheme",Zt._scheme).replace("email",Zt._email).getRegex(),Zt._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,Zt.tag=qt(Zt.tag).replace("comment",Bt._comment).replace("attribute",Zt._attribute).getRegex(),Zt._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Zt._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,Zt._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,Zt.link=qt(Zt.link).replace("label",Zt._label).replace("href",Zt._href).replace("title",Zt._title).getRegex(),Zt.reflink=qt(Zt.reflink).replace("label",Zt._label).getRegex(),Zt.reflinkSearch=qt(Zt.reflinkSearch,"g").replace("reflink",Zt.reflink).replace("nolink",Zt.nolink).getRegex(),Zt.normal=Ut({},Zt),Zt.pedantic=Ut({},Zt.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:qt(/^!?\[(label)\]\((.*?)\)/).replace("label",Zt._label).getRegex(),reflink:qt(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",Zt._label).getRegex()}),Zt.gfm=Ut({},Zt.normal,{escape:qt(Zt.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?= {2,}\n|[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/}),Zt.gfm.url=qt(Zt.gfm.url,"i").replace("email",Zt.gfm._extended_email).getRegex(),Zt.breaks=Ut({},Zt.gfm,{br:qt(Zt.br).replace("{2,}","*").getRegex(),text:qt(Zt.gfm.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()});var Wt={block:Bt,inline:Zt},Yt=st.defaults,Gt=Wt.block,Vt=Wt.inline;function Xt(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")}function Kt(e){var t,n,r="",i=e.length;for(t=0;t<i;t++)n=e.charCodeAt(t),.5<Math.random()&&(n="x"+n.toString(16)),r+="&#"+n+";";return r}var Qt=function(){function n(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||Yt,this.options.tokenizer=this.options.tokenizer||new Ht,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options;var t={block:Gt.normal,inline:Vt.normal};this.options.pedantic?(t.block=Gt.pedantic,t.inline=Vt.pedantic):this.options.gfm&&(t.block=Gt.gfm,this.options.breaks?t.inline=Vt.breaks:t.inline=Vt.gfm),this.tokenizer.rules=t}var e={rules:{configurable:!0}};return e.rules.get=function(){return{block:Gt,inline:Vt}},n.lex=function(e,t){return new n(t).lex(e)},n.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," "),this.blockTokens(e,this.tokens,!0),this.inline(this.tokens),this.tokens},n.prototype.blockTokens=function(e,t,n){var r,i,a,o;for(void 0===t&&(t=[]),void 0===n&&(n=!0),e=e.replace(/^ +$/gm,"");e;)if(r=this.tokenizer.space(e))e=e.substring(r.raw.length),r.type&&t.push(r);else if(r=this.tokenizer.code(e,t))e=e.substring(r.raw.length),r.type?t.push(r):((o=t[t.length-1]).raw+="\n"+r.raw,o.text+="\n"+r.text);else if(r=this.tokenizer.fences(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.heading(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.nptable(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.hr(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.blockquote(e))e=e.substring(r.raw.length),r.tokens=this.blockTokens(r.text,[],n),t.push(r);else if(r=this.tokenizer.list(e)){for(e=e.substring(r.raw.length),a=r.items.length,i=0;i<a;i++)r.items[i].tokens=this.blockTokens(r.items[i].text,[],!1);t.push(r)}else if(r=this.tokenizer.html(e))e=e.substring(r.raw.length),t.push(r);else if(n&&(r=this.tokenizer.def(e)))e=e.substring(r.raw.length),this.tokens.links[r.tag]||(this.tokens.links[r.tag]={href:r.href,title:r.title});else if(r=this.tokenizer.table(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.lheading(e))e=e.substring(r.raw.length),t.push(r);else if(n&&(r=this.tokenizer.paragraph(e)))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.text(e,t))e=e.substring(r.raw.length),r.type?t.push(r):((o=t[t.length-1]).raw+="\n"+r.raw,o.text+="\n"+r.text);else if(e){var s="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(s);break}throw new Error(s)}return t},n.prototype.inline=function(e){var t,n,r,i,a,o,s=e.length;for(t=0;t<s;t++)switch((o=e[t]).type){case"paragraph":case"text":case"heading":o.tokens=[],this.inlineTokens(o.text,o.tokens);break;case"table":for(o.tokens={header:[],cells:[]},i=o.header.length,n=0;n<i;n++)o.tokens.header[n]=[],this.inlineTokens(o.header[n],o.tokens.header[n]);for(i=o.cells.length,n=0;n<i;n++)for(a=o.cells[n],o.tokens.cells[n]=[],r=0;r<a.length;r++)o.tokens.cells[n][r]=[],this.inlineTokens(a[r],o.tokens.cells[n][r]);break;case"blockquote":this.inline(o.tokens);break;case"list":for(i=o.items.length,n=0;n<i;n++)this.inline(o.items[n].tokens)}return e},n.prototype.inlineTokens=function(e,t,n,r,i){var a;void 0===t&&(t=[]),void 0===n&&(n=!1),void 0===r&&(r=!1),void 0===i&&(i="");var o,s=e;if(this.tokens.links){var l=Object.keys(this.tokens.links);if(0<l.length)for(;null!=(o=this.tokenizer.rules.inline.reflinkSearch.exec(s));)l.includes(o[0].slice(o[0].lastIndexOf("[")+1,-1))&&(s=s.slice(0,o.index)+"["+"a".repeat(o[0].length-2)+"]"+s.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(o=this.tokenizer.rules.inline.blockSkip.exec(s));)s=s.slice(0,o.index)+"["+"a".repeat(o[0].length-2)+"]"+s.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;e;)if(a=this.tokenizer.escape(e))e=e.substring(a.raw.length),t.push(a);else if(a=this.tokenizer.tag(e,n,r))e=e.substring(a.raw.length),n=a.inLink,r=a.inRawBlock,t.push(a);else if(a=this.tokenizer.link(e))e=e.substring(a.raw.length),"link"===a.type&&(a.tokens=this.inlineTokens(a.text,[],!0,r)),t.push(a);else if(a=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(a.raw.length),"link"===a.type&&(a.tokens=this.inlineTokens(a.text,[],!0,r)),t.push(a);else if(a=this.tokenizer.strong(e,s,i))e=e.substring(a.raw.length),a.tokens=this.inlineTokens(a.text,[],n,r),t.push(a);else if(a=this.tokenizer.em(e,s,i))e=e.substring(a.raw.length),a.tokens=this.inlineTokens(a.text,[],n,r),t.push(a);else if(a=this.tokenizer.codespan(e))e=e.substring(a.raw.length),t.push(a);else if(a=this.tokenizer.br(e))e=e.substring(a.raw.length),t.push(a);else if(a=this.tokenizer.del(e))e=e.substring(a.raw.length),a.tokens=this.inlineTokens(a.text,[],n,r),t.push(a);else if(a=this.tokenizer.autolink(e,Kt))e=e.substring(a.raw.length),t.push(a);else if(n||!(a=this.tokenizer.url(e,Kt))){if(a=this.tokenizer.inlineText(e,r,Xt))e=e.substring(a.raw.length),i=a.raw.slice(-1),t.push(a);else if(e){var c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}throw new Error(c)}}else e=e.substring(a.raw.length),t.push(a);return t},Object.defineProperties(n,e),n}(),Jt=st.defaults,en=Et,tn=St,nn=function(){function e(e){this.options=e||Jt}return e.prototype.code=function(e,t,n){var r=(t||"").match(/\S*/)[0];if(this.options.highlight){var i=this.options.highlight(e,r);null!=i&&i!==e&&(n=!0,e=i)}return r?'<pre><code class="'+this.options.langPrefix+tn(r,!0)+'">'+(n?e:tn(e,!0))+"</code></pre>\n":"<pre><code>"+(n?e:tn(e,!0))+"</code></pre>\n"},e.prototype.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},e.prototype.html=function(e){return e},e.prototype.heading=function(e,t,n,r){return this.options.headerIds?"<h"+t+' id="'+this.options.headerPrefix+r.slug(n)+'">'+e+"</h"+t+">\n":"<h"+t+">"+e+"</h"+t+">\n"},e.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},e.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"</"+r+">\n"},e.prototype.listitem=function(e){return"<li>"+e+"</li>\n"},e.prototype.checkbox=function(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox"'+(this.options.xhtml?" /":"")+"> "},e.prototype.paragraph=function(e){return"<p>"+e+"</p>\n"},e.prototype.table=function(e,t){return"<table>\n<thead>\n"+e+"</thead>\n"+(t=t&&"<tbody>"+t+"</tbody>")+"</table>\n"},e.prototype.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},e.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"</"+n+">\n"},e.prototype.strong=function(e){return"<strong>"+e+"</strong>"},e.prototype.em=function(e){return"<em>"+e+"</em>"},e.prototype.codespan=function(e){return"<code>"+e+"</code>"},e.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"},e.prototype.del=function(e){return"<del>"+e+"</del>"},e.prototype.link=function(e,t,n){if(null===(e=en(this.options.sanitize,this.options.baseUrl,e)))return n;var r='<a href="'+tn(e)+'"';return t&&(r+=' title="'+t+'"'),r+=">"+n+"</a>"},e.prototype.image=function(e,t,n){if(null===(e=en(this.options.sanitize,this.options.baseUrl,e)))return n;var r='<img src="'+e+'" alt="'+n+'"';return t&&(r+=' title="'+t+'"'),r+=this.options.xhtml?"/>":">"},e.prototype.text=function(e){return e},e}(),rn=function(){function e(){}return e.prototype.strong=function(e){return e},e.prototype.em=function(e){return e},e.prototype.codespan=function(e){return e},e.prototype.del=function(e){return e},e.prototype.html=function(e){return e},e.prototype.text=function(e){return e},e.prototype.link=function(e,t,n){return""+n},e.prototype.image=function(e,t,n){return""+n},e.prototype.br=function(){return""},e}(),an=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),on=st.defaults,sn=At,ln=function(){function n(e){this.options=e||on,this.options.renderer=this.options.renderer||new nn,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new rn,this.slugger=new an}return n.parse=function(e,t){return new n(t).parse(e)},n.prototype.parse=function(e,t){void 0===t&&(t=!0);var n,r,i,a,o,s,l,c,u,p,d,f,h,g,m,v,b,y,k="",x=e.length;for(n=0;n<x;n++)switch((p=e[n]).type){case"space":continue;case"hr":k+=this.renderer.hr();continue;case"heading":k+=this.renderer.heading(this.parseInline(p.tokens),p.depth,sn(this.parseInline(p.tokens,this.textRenderer)),this.slugger);continue;case"code":k+=this.renderer.code(p.text,p.lang,p.escaped);continue;case"table":for(l=c="",a=p.header.length,r=0;r<a;r++)l+=this.renderer.tablecell(this.parseInline(p.tokens.header[r]),{header:!0,align:p.align[r]});for(c+=this.renderer.tablerow(l),u="",a=p.cells.length,r=0;r<a;r++){for(l="",o=(s=p.tokens.cells[r]).length,i=0;i<o;i++)l+=this.renderer.tablecell(this.parseInline(s[i]),{header:!1,align:p.align[i]});u+=this.renderer.tablerow(l)}k+=this.renderer.table(c,u);continue;case"blockquote":u=this.parse(p.tokens),k+=this.renderer.blockquote(u);continue;case"list":for(d=p.ordered,f=p.start,h=p.loose,a=p.items.length,u="",r=0;r<a;r++)v=(m=p.items[r]).checked,b=m.task,g="",m.task&&(y=this.renderer.checkbox(v),h?0<m.tokens.length&&"text"===m.tokens[0].type?(m.tokens[0].text=y+" "+m.tokens[0].text,m.tokens[0].tokens&&0<m.tokens[0].tokens.length&&"text"===m.tokens[0].tokens[0].type&&(m.tokens[0].tokens[0].text=y+" "+m.tokens[0].tokens[0].text)):m.tokens.unshift({type:"text",text:y}):g+=y),g+=this.parse(m.tokens,h),u+=this.renderer.listitem(g,b,v);k+=this.renderer.list(u,d,f);continue;case"html":k+=this.renderer.html(p.text);continue;case"paragraph":k+=this.renderer.paragraph(this.parseInline(p.tokens));continue;case"text":for(u=p.tokens?this.parseInline(p.tokens):p.text;n+1<x&&"text"===e[n+1].type;)u+="\n"+((p=e[++n]).tokens?this.parseInline(p.tokens):p.text);k+=t?this.renderer.paragraph(u):u;continue;default:var w='Token with "'+p.type+'" type was not found.';if(this.options.silent)return void console.error(w);throw new Error(w)}return k},n.prototype.parseInline=function(e,t){t=t||this.renderer;var n,r,i="",a=e.length;for(n=0;n<a;n++)switch((r=e[n]).type){case"escape":i+=t.text(r.text);break;case"html":i+=t.html(r.text);break;case"link":i+=t.link(r.href,r.title,this.parseInline(r.tokens,t));break;case"image":i+=t.image(r.href,r.title,r.text);break;case"strong":i+=t.strong(this.parseInline(r.tokens,t));break;case"em":i+=t.em(this.parseInline(r.tokens,t));break;case"codespan":i+=t.codespan(r.text);break;case"br":i+=t.br();break;case"del":i+=t.del(this.parseInline(r.tokens,t));break;case"text":i+=t.text(r.text);break;default:var o='Token with "'+r.type+'" type was not found.';if(this.options.silent)return void console.error(o);throw new Error(o)}return i},n}(),cn=Rt,un=zt,pn=St,dn=st.getDefaults,fn=st.changeDefaults,hn=st.defaults;function gn(e,n,r){if(null==e)throw new Error("marked(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");if("function"==typeof n&&(r=n,n=null),n=cn({},gn.defaults,n||{}),un(n),r){var i,a=n.highlight;try{i=Qt.lex(e,n)}catch(e){return r(e)}function o(t){var e;if(!t)try{e=ln.parse(i,n)}catch(e){t=e}return n.highlight=a,t?r(t):r(null,e)}if(!a||a.length<3)return o();if(delete n.highlight,!i.length)return o();var s=0;return gn.walkTokens(i,function(n){"code"===n.type&&(s++,setTimeout(function(){a(n.text,n.lang,function(e,t){if(e)return o(e);null!=t&&t!==n.text&&(n.text=t,n.escaped=!0),0===--s&&o()})},0))}),void(0===s&&o())}try{var t=Qt.lex(e,n);return n.walkTokens&&gn.walkTokens(t,n.walkTokens),ln.parse(t,n)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",n.silent)return"<p>An error occurred:</p><pre>"+pn(e.message+"",!0)+"</pre>";throw e}}gn.options=gn.setOptions=function(e){return cn(gn.defaults,e),fn(gn.defaults),gn},gn.getDefaults=dn,gn.defaults=hn,gn.use=function(a){var e=cn({},a);if(a.renderer){function t(r){var i=o[r];o[r]=function(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];var n=a.renderer[r].apply(o,e);return!1===n&&(n=i.apply(o,e)),n}}var o=gn.defaults.renderer||new nn;for(var n in a.renderer)t(n);e.renderer=o}if(a.tokenizer){function r(e){var r=i[s];i[s]=function(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];var n=a.tokenizer[s].apply(i,e);return!1===n&&(n=r.apply(i,e)),n}}var i=gn.defaults.tokenizer||new Ht;for(var s in a.tokenizer)r();e.tokenizer=i}if(a.walkTokens){var l=gn.defaults.walkTokens;e.walkTokens=function(e){a.walkTokens(e),l&&l(e)}}gn.setOptions(e)},gn.walkTokens=function(e,t){for(var n=0,r=e;n<r.length;n+=1){var i=r[n];switch(t(i),i.type){case"table":for(var a=0,o=i.tokens.header;a<o.length;a+=1){var s=o[a];gn.walkTokens(s,t)}for(var l=0,c=i.tokens.cells;l<c.length;l+=1)for(var u=0,p=c[l];u<p.length;u+=1){var d=p[u];gn.walkTokens(d,t)}break;case"list":gn.walkTokens(i.items,t);break;default:i.tokens&&gn.walkTokens(i.tokens,t)}}},gn.Parser=ln,gn.parser=ln.parse,gn.Renderer=nn,gn.TextRenderer=rn,gn.Lexer=Qt,gn.lexer=Qt.lex,gn.Tokenizer=Ht,gn.Slugger=an;var mn=gn.parse=gn;function vn(e,t){if(void 0===t&&(t='<ul class="app-sub-sidebar">{inner}</ul>'),!e||!e.length)return"";var n="";return e.forEach(function(e){n+='<li><a class="section-link" href="'+e.slug+'" title="'+e.title+'">'+e.title+"</a></li>",e.children&&(n+=vn(e.children,t))}),t.replace("{inner}",n)}function bn(e,t){return'<p class="'+e+'">'+t.slice(5).trim()+"</p>"}function yn(e,r){var i=[],a={};return e.forEach(function(e){var t=e.level||1,n=t-1;r<t||(a[n]?a[n].children=(a[n].children||[]).concat(e):i.push(e),a[t]=e)}),i}var kn={},xn=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g;function wn(e){return e.toLowerCase()}function _n(e){if("string"!=typeof e)return"";var t=e.trim().replace(/[A-Z]+/g,wn).replace(/<[^>\d]+>/g,"").replace(xn,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),n=kn[t];return n=l.call(kn,t)?n+1:0,(kn[t]=n)&&(t=t+"-"+n),t}function Sn(e,t){return'<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/'+t+'.png" alt="'+t+'" />'}function An(e){void 0===e&&(e="");var r={};return{str:e=e&&e.replace(/^'/,"").replace(/'$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,t,n){return-1===t.indexOf(":")?(r[t]=n&&n.replace(/"/g,"")||!0,""):e}).trim(),config:r}}_n.clear=function(){kn={}};var Tn,En=at(function(e){var a=function(c){var u=/\blang(?:uage)?-([\w-]+)\b/i,t=0,z={manual:c.Prism&&c.Prism.manual,disableWorkerMessageHandler:c.Prism&&c.Prism.disableWorkerMessageHandler,util:{encode:function e(t){return t instanceof O?new O(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function n(e,r){var i,t;switch(r=r||{},z.util.type(e)){case"Object":if(t=z.util.objId(e),r[t])return r[t];for(var a in i={},r[t]=i,e)e.hasOwnProperty(a)&&(i[a]=n(e[a],r));return i;case"Array":return t=z.util.objId(e),r[t]?r[t]:(i=[],r[t]=i,e.forEach(function(e,t){i[t]=n(e,r)}),i);default:return e}},getLanguage:function(e){for(;e&&!u.test(e.className);)e=e.parentElement;return e?(e.className.match(u)||[,"none"])[1].toLowerCase():"none"},currentScript:function(){if("undefined"==typeof document)return null;if("currentScript"in document)return document.currentScript;try{throw new Error}catch(e){var t=(/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(e.stack)||[])[1];if(t){var n=document.getElementsByTagName("script");for(var r in n)if(n[r].src==t)return n[r]}return null}},isActive:function(e,t,n){for(var r="no-"+t;e;){var i=e.classList;if(i.contains(t))return!0;if(i.contains(r))return!1;e=e.parentElement}return!!n}},languages:{extend:function(e,t){var n=z.util.clone(z.languages[e]);for(var r in t)n[r]=t[r];return n},insertBefore:function(n,e,t,r){var i=(r=r||z.languages)[n],a={};for(var o in i)if(i.hasOwnProperty(o)){if(o==e)for(var s in t)t.hasOwnProperty(s)&&(a[s]=t[s]);t.hasOwnProperty(o)||(a[o]=i[o])}var l=r[n];return r[n]=a,z.languages.DFS(z.languages,function(e,t){t===l&&e!=n&&(this[e]=a)}),a},DFS:function e(t,n,r,i){i=i||{};var a=z.util.objId;for(var o in t)if(t.hasOwnProperty(o)){n.call(t,o,t[o],r||o);var s=t[o],l=z.util.type(s);"Object"!==l||i[a(s)]?"Array"!==l||i[a(s)]||(i[a(s)]=!0,e(s,n,o,i)):(i[a(s)]=!0,e(s,n,null,i))}}},plugins:{},highlightAll:function(e,t){z.highlightAllUnder(document,e,t)},highlightAllUnder:function(e,t,n){var r={callback:n,container:e,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};z.hooks.run("before-highlightall",r),r.elements=Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)),z.hooks.run("before-all-elements-highlight",r);for(var i,a=0;i=r.elements[a++];)z.highlightElement(i,!0===t,r.callback)},highlightElement:function(e,t,n){var r=z.util.getLanguage(e),i=z.languages[r];e.className=e.className.replace(u,"").replace(/\s+/g," ")+" language-"+r;var a=e.parentElement;a&&"pre"===a.nodeName.toLowerCase()&&(a.className=a.className.replace(u,"").replace(/\s+/g," ")+" language-"+r);var o={element:e,language:r,grammar:i,code:e.textContent};function s(e){o.highlightedCode=e,z.hooks.run("before-insert",o),o.element.innerHTML=o.highlightedCode,z.hooks.run("after-highlight",o),z.hooks.run("complete",o),n&&n.call(o.element)}if(z.hooks.run("before-sanity-check",o),!o.code)return z.hooks.run("complete",o),void(n&&n.call(o.element));if(z.hooks.run("before-highlight",o),o.grammar)if(t&&c.Worker){var l=new Worker(z.filename);l.onmessage=function(e){s(e.data)},l.postMessage(JSON.stringify({language:o.language,code:o.code,immediateClose:!0}))}else s(z.highlight(o.code,o.grammar,o.language));else s(z.util.encode(o.code))},highlight:function(e,t,n){var r={code:e,grammar:t,language:n};return z.hooks.run("before-tokenize",r),r.tokens=z.tokenize(r.code,r.grammar),z.hooks.run("after-tokenize",r),O.stringify(z.util.encode(r.tokens),r.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var i=new a;return M(i,i.head,e),function e(t,n,r,i,a,o){for(var s in r)if(r.hasOwnProperty(s)&&r[s]){var l=r[s];l=Array.isArray(l)?l:[l];for(var c=0;c<l.length;++c){if(o&&o.cause==s+","+c)return;var u=l[c],p=u.inside,d=!!u.lookbehind,f=!!u.greedy,h=0,g=u.alias;if(f&&!u.pattern.global){var m=u.pattern.toString().match(/[imsuy]*$/)[0];u.pattern=RegExp(u.pattern.source,m+"g")}for(var v=u.pattern||u,b=i.next,y=a;b!==n.tail&&!(o&&y>=o.reach);y+=b.value.length,b=b.next){var k=b.value;if(n.length>t.length)return;if(!(k instanceof O)){var x=1;if(f&&b!=n.tail.prev){v.lastIndex=y;var w=v.exec(t);if(!w)break;var _=w.index+(d&&w[1]?w[1].length:0),S=w.index+w[0].length,A=y;for(A+=b.value.length;A<=_;)b=b.next,A+=b.value.length;if(A-=b.value.length,y=A,b.value instanceof O)continue;for(var T=b;T!==n.tail&&(A<S||"string"==typeof T.value);T=T.next)x++,A+=T.value.length;x--,k=t.slice(y,A),w.index-=y}else{v.lastIndex=0;var w=v.exec(k)}if(w){d&&(h=w[1]?w[1].length:0);var _=w.index+h,E=w[0].slice(h),S=_+E.length,L=k.slice(0,_),R=k.slice(S),C=y+k.length;o&&C>o.reach&&(o.reach=C);var $=b.prev;L&&($=M(n,$,L),y+=L.length),N(n,$,x);var F=new O(s,p?z.tokenize(E,p):E,g,E);b=M(n,$,F),R&&M(n,b,R),1<x&&e(t,n,r,b.prev,y,{cause:s+","+c,reach:C})}}}}}}(e,i,t,i.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(i)},hooks:{all:{},add:function(e,t){var n=z.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=z.hooks.all[e];if(n&&n.length)for(var r,i=0;r=n[i++];)r(t)}},Token:O};function O(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function a(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function M(e,t,n){var r=t.next,i={value:n,prev:t,next:r};return t.next=i,r.prev=i,e.length++,i}function N(e,t,n){for(var r=t.next,i=0;i<n&&r!==e.tail;i++)r=r.next;(t.next=r).prev=t,e.length-=i}if(c.Prism=z,O.stringify=function t(e,n){if("string"==typeof e)return e;if(Array.isArray(e)){var r="";return e.forEach(function(e){r+=t(e,n)}),r}var i={type:e.type,content:t(e.content,n),tag:"span",classes:["token",e.type],attributes:{},language:n},a=e.alias;a&&(Array.isArray(a)?Array.prototype.push.apply(i.classes,a):i.classes.push(a)),z.hooks.run("wrap",i);var o="";for(var s in i.attributes)o+=" "+s+'="'+(i.attributes[s]||"").replace(/"/g,""")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+o+">"+i.content+"</"+i.tag+">"},!c.document)return c.addEventListener&&(z.disableWorkerMessageHandler||c.addEventListener("message",function(e){var t=JSON.parse(e.data),n=t.language,r=t.code,i=t.immediateClose;c.postMessage(z.highlight(r,z.languages[n],n)),i&&c.close()},!1)),z;var e=z.util.currentScript();function n(){z.manual||z.highlightAll()}if(e&&(z.filename=e.src,e.hasAttribute("data-manual")&&(z.manual=!0)),!z.manual){var r=document.readyState;"loading"===r||"interactive"===r&&e&&e.defer?document.addEventListener("DOMContentLoaded",n):window.requestAnimationFrame?window.requestAnimationFrame(n):window.setTimeout(n,16)}return z}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});e.exports&&(e.exports=a),void 0!==it&&(it.Prism=a),a.languages.markup={comment:/<!--[\s\S]*?-->/,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/,name:/[^\s<>'"]+/}},cdata:/<!\[CDATA\[[\s\S]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var r={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var i={};i[e]={pattern:RegExp(/(<__[\s\S]*?>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,function(){return e}),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",i)}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.languages.xml,function(e){var t=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\((?!\s*\))\s*)(?:[^()]|\((?:[^()]|\([^()]*\))*\))+?(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:RegExp("[^{}\\s](?:[^{};\"']|"+t.source+")*?(?=\\s*\\{)"),string:{pattern:t,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),e.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:n.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:e.languages.css}},alias:"language-css"}},n.tag))}(a),a.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|(?:get|set)(?=\s*[\[$\w\xA0-\uFFFF])|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}}}),a.languages.markup&&a.languages.markup.tag.addInlined("script","javascript"),a.languages.js=a.languages.javascript,function(){if("undefined"!=typeof self&&self.Prism&&self.document){var l=window.Prism,c={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},u="data-src-status",p="loading",d="pre[data-src]:not(["+u+'="loaded"]):not(['+u+'="'+p+'"])',r=/\blang(?:uage)?-([\w-]+)\b/i;l.hooks.add("before-highlightall",function(e){e.selector+=", "+d}),l.hooks.add("before-sanity-check",function(e){var t=e.element;if(t.matches(d)){e.code="",t.setAttribute(u,p);var n=t.appendChild(document.createElement("CODE"));n.textContent="Loading…";var r=t.getAttribute("data-src"),i=e.language;if("none"===i){var a=(/\.(\w+)$/.exec(r)||[,"none"])[1];i=c[a]||a}f(n,i),f(t,i);var o=l.plugins.autoloader;o&&o.loadLanguages(i);var s=new XMLHttpRequest;s.open("GET",r,!0),s.onreadystatechange=function(){4==s.readyState&&(s.status<400&&s.responseText?(t.setAttribute(u,"loaded"),n.textContent=s.responseText,l.highlightElement(n)):(t.setAttribute(u,"failed"),400<=s.status?n.textContent=function(e,t){return"✖ Error "+e+" while fetching file: "+t}(s.status,s.statusText):n.textContent="✖ Error: File does not exist or is empty"))},s.send(null)}});var e=!(l.plugins.fileHighlight={highlight:function(e){for(var t,n=(e||document).querySelectorAll(d),r=0;t=n[r++];)l.highlightElement(t)}});l.fileHighlight=function(){e||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),e=!0),l.plugins.fileHighlight.highlight.apply(this,arguments)}}function f(e,t){var n=e.className;n=n.replace(r," ")+" language-"+t,e.className=n.replace(/\s+/g," ").trim()}}()});function Ln(e,t){return"___"+e.toUpperCase()+t+"___"}Tn=Prism,Object.defineProperties(Tn.languages["markup-templating"]={},{buildPlaceholders:{value:function(r,i,e,a){if(r.language===i){var o=r.tokenStack=[];r.code=r.code.replace(e,function(e){if("function"==typeof a&&!a(e))return e;for(var t,n=o.length;-1!==r.code.indexOf(t=Ln(i,n));)++n;return o[n]=e,t}),r.grammar=Tn.languages.markup}}},tokenizePlaceholders:{value:function(f,h){if(f.language===h&&f.tokenStack){f.grammar=Tn.languages[h];var g=0,m=Object.keys(f.tokenStack);!function e(t){for(var n=0;n<t.length&&!(g>=m.length);n++){var r=t[n];if("string"==typeof r||r.content&&"string"==typeof r.content){var i=m[g],a=f.tokenStack[i],o="string"==typeof r?r:r.content,s=Ln(h,i),l=o.indexOf(s);if(-1<l){++g;var c=o.substring(0,l),u=new Tn.Token(h,Tn.tokenize(a,f.grammar),"language-"+h,a),p=o.substring(l+s.length),d=[];c&&d.push.apply(d,e([c])),d.push(u),p&&d.push.apply(d,e([p])),"string"==typeof r?t.splice.apply(t,[n,1].concat(d)):r.content=d}}else r.content&&e(r.content)}return t}(f.tokens)}}}});var Rn={},Cn={markdown:function(e){return{url:e}},mermaid:function(e){return{url:e}},iframe:function(e,t){return{html:'<iframe src="'+e+'" '+(t||"width=100% height=400")+"></iframe>"}},video:function(e,t){return{html:'<video src="'+e+'" '+(t||"controls")+">Not Support</video>"}},audio:function(e,t){return{html:'<audio src="'+e+'" '+(t||"controls")+">Not Support</audio>"}},code:function(e,t){var n=e.match(/\.(\w+)$/);return"md"===(n=t||n&&n[1])&&(n="markdown"),{url:e,lang:n}}},$n=function(i,e){var a=this;this.config=i,this.router=e,this.cacheTree={},this.toc=[],this.cacheTOC={},this.linkTarget=i.externalLinkTarget||"_blank",this.linkRel="_blank"===this.linkTarget?i.externalLinkRel||"noopener":"",this.contentBase=e.getBasePath();var o,t=this._initRenderer();this.heading=t.heading;var n=i.markdown||{};o=r(n)?n(mn,t):(mn.setOptions(f(n,{renderer:f(t,n.renderer)})),mn),this._marked=o,this.compile=function(n){var r=!0,e=s(function(e){r=!1;var t="";return n?(t=c(n)?o(n):o.parser(n),t=i.noEmoji?t:function(e){return e.replace(/:\+1:/g,":thumbsup:").replace(/:-1:/g,":thumbsdown:").replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/:(\w+?):/gi,window.emojify||Sn).replace(/__colon__/g,":")}(t),_n.clear(),t):n})(n),t=a.router.parse().file;return r?a.toc=a.cacheTOC[t]:a.cacheTOC[t]=[].concat(a.toc),e}};$n.prototype.compileEmbed=function(e,t){var n,r=An(t),i=r.str,a=r.config;if(t=i,a.include){var o;if(Q(e)||(e=re(this.contentBase,ee(this.router.getCurrentPath()),e)),a.type&&(o=Cn[a.type]))(n=o.call(this,e,t)).type=a.type;else{var s="code";/\.(md|markdown)/.test(e)?s="markdown":/\.mmd/.test(e)?s="mermaid":/\.html?/.test(e)?s="iframe":/\.(mp4|ogg)/.test(e)?s="video":/\.mp3/.test(e)&&(s="audio"),(n=Cn[s].call(this,e,t)).type=s}return n.fragment=a.fragment,n}},$n.prototype._matchNotCompileLink=function(e){for(var t=this.config.noCompileLinks||[],n=0;n<t.length;n++){var r=t[n];if((Rn[r]||(Rn[r]=new RegExp("^"+r+"$"))).test(e))return e}},$n.prototype._initRenderer=function(){var e=new mn.Renderer,t=this.linkTarget,n=this.linkRel,l=this.router,r=this.contentBase,c=this,i={};return i.heading=e.heading=function(e,t){var n=An(e),r=n.str,i=n.config,a={level:t,title:r};/<!-- {docsify-ignore} -->/g.test(r)&&(r=r.replace("\x3c!-- {docsify-ignore} --\x3e",""),a.title=r,a.ignoreSubHeading=!0),/{docsify-ignore}/g.test(r)&&(r=r.replace("{docsify-ignore}",""),a.title=r,a.ignoreSubHeading=!0),/<!-- {docsify-ignore-all} -->/g.test(r)&&(r=r.replace("\x3c!-- {docsify-ignore-all} --\x3e",""),a.title=r,a.ignoreAllSubs=!0),/{docsify-ignore-all}/g.test(r)&&(r=r.replace("{docsify-ignore-all}",""),a.title=r,a.ignoreAllSubs=!0);var o=_n(i.id||r),s=l.toURL(l.getCurrentPath(),{id:o});return a.slug=s,c.toc.push(a),"<h"+t+' id="'+o+'"><a href="'+s+'" data-id="'+o+'" class="anchor"><span>'+r+"</span></a></h"+t+">"},i.code=function(e){return e.renderer.code=function(e,t){void 0===t&&(t="");var n=En.languages[t]||En.languages.markup;return'<pre v-pre data-lang="'+t+'"><code class="lang-'+t+'">'+En.highlight(e.replace(/@DOCSIFY_QM@/g,"`"),n)+"</code></pre>"}}({renderer:e}),i.link=function(e){var t=e.renderer,s=e.router,l=e.linkTarget,c=e.linkRel,u=e.compilerClass;return t.link=function(e,t,n){void 0===t&&(t="");var r=[],i=An(t),a=i.str,o=i.config;return l=o.target||l,c="_blank"===l?u.config.externalLinkRel||"noopener":"",t=a,Q(e)||u._matchNotCompileLink(e)||o.ignore?(!Q(e)&&e.startsWith("./")&&(e=document.URL.replace(/\/(?!.*\/).*/,"/").replace("#/./","")+e),r.push(0===e.indexOf("mailto:")?"":'target="'+l+'"'),r.push(0===e.indexOf("mailto:")?"":""!==c?' rel="'+c+'"':"")):(e===u.config.homepage&&(e="README"),e=s.toURL(e,null,s.getCurrentPath())),o.crossorgin&&"_self"===l&&"history"===u.config.routerMode&&-1===u.config.crossOriginLinks.indexOf(e)&&u.config.crossOriginLinks.push(e),o.disabled&&(r.push("disabled"),e="javascript:void(0)"),o.class&&r.push('class="'+o.class+'"'),o.id&&r.push('id="'+o.id+'"'),t&&r.push('title="'+t+'"'),'<a href="'+e+'" '+r.join(" ")+">"+n+"</a>"}}({renderer:e,router:l,linkTarget:t,linkRel:n,compilerClass:c}),i.paragraph=function(e){return e.renderer.paragraph=function(e){return/^!>/.test(e)?bn("tip",e):/^\?>/.test(e)?bn("warn",e):"<p>"+e+"</p>"}}({renderer:e}),i.image=function(e){var t=e.renderer,p=e.contentBase,d=e.router;return t.image=function(e,t,n){var r=e,i=[],a=An(t),o=a.str,s=a.config;if(t=o,s["no-zoom"]&&i.push("data-no-zoom"),t&&i.push('title="'+t+'"'),s.size){var l=s.size.split("x"),c=l[0],u=l[1];u?i.push('width="'+c+'" height="'+u+'"'):i.push('width="'+c+'"')}return s.class&&i.push('class="'+s.class+'"'),s.id&&i.push('id="'+s.id+'"'),Q(e)||(r=re(p,ee(d.getCurrentPath()),e)),0<i.length?'<img src="'+r+'" data-origin="'+e+'" alt="'+n+'" '+i.join(" ")+" />":'<img src="'+r+'" data-origin="'+e+'" alt="'+n+'"'+i+">"}}({renderer:e,contentBase:r,router:l}),i.list=function(e){return e.renderer.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+" "+[/<li class="task-list-item">/.test(e.split('class="task-list"')[0])?'class="task-list"':"",n&&1<n?'start="'+n+'"':""].join(" ").trim()+">"+e+"</"+r+">"}}({renderer:e}),i.listitem=function(e){return e.renderer.listitem=function(e){return/^(<input.*type="checkbox"[^>]*>)/.test(e)?'<li class="task-list-item"><label>'+e+"</label></li>":"<li>"+e+"</li>"}}({renderer:e}),e.origin=i,e},$n.prototype.sidebar=function(e,t){var n=this.toc,r=this.router.getCurrentPath(),i="";if(e)i=this.compile(e);else{for(var a=0;a<n.length;a++)if(n[a].ignoreSubHeading){var o=n[a].level;n.splice(a,1);for(var s=a;o<n[s].level&&s<n.length;s++)n.splice(s,1)&&s--&&a++;a--}var l=this.cacheTree[r]||yn(n,t);i=vn(l,"<ul>{inner}</ul>"),this.cacheTree[r]=l}return i},$n.prototype.subSidebar=function(e){if(e){var t=this.router.getCurrentPath(),n=this.cacheTree,r=this.toc;r[0]&&r[0].ignoreAllSubs&&r.splice(0),r[0]&&1===r[0].level&&r.shift();for(var i=0;i<r.length;i++)r[i].ignoreSubHeading&&r.splice(i,1)&&i--;var a=n[t]||yn(r,e);return n[t]=a,this.toc=[],vn(a)}this.toc=[]},$n.prototype.header=function(e,t){return this.heading(e,t)},$n.prototype.article=function(e){return this.compile(e)},$n.prototype.cover=function(e){var t=this.toc.slice(),n=this.compile(e);return this.toc=t.slice(),n};var Fn=function(e){var t=function(e){var t=e.match(/^[ \t]*(?=\S)/gm);return t?Math.min.apply(Math,t.map(function(e){return e.length})):0}(e);if(0===t)return e;var n=new RegExp("^[ \\t]{"+t+"}","gm");return e.replace(n,"")},zn={};function On(e,i){var o=e.compiler,a=e.raw;void 0===a&&(a="");var t=e.fetch,n=zn[a];if(n){var r=n.slice();return r.links=n.links,i(r)}var s=o._marked,l=s.lexer(a),c=[],u=s.Lexer.rules.inline.link,p=l.links;l.forEach(function(e,a){"paragraph"===e.type&&(e.text=e.text.replace(new RegExp(u.source,"g"),function(e,t,n,r){var i=o.compileEmbed(n,r);return i&&c.push({index:a,embed:i}),e}))});var d=[];!function(e,o){var t,n=e.embedTokens,s=e.compile,l=(e.fetch,0),c=1;if(!n.length)return o({});for(;t=n[l++];){var r=function(a){return function(e){var t;if(e)if("markdown"===a.embed.type){var n=a.embed.url.split("/");n.pop(),n=n.join("/"),e=e.replace(/\[([^[\]]+)\]\(([^)]+)\)/g,function(e){var t=e.indexOf("(");return e.substring(t).startsWith("(.")?e.substring(0,t)+"("+window.location.protocol+"//"+window.location.host+n+"/"+e.substring(t+1,e.length-1)+")":e}),!0===(($docsify.frontMatter||{}).installed||!1)&&(e=$docsify.frontMatter.parseMarkdown(e)),t=s.lexer(e)}else if("code"===a.embed.type){if(a.embed.fragment){var r=a.embed.fragment,i=new RegExp("(?:###|\\/\\/\\/)\\s*\\["+r+"\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\["+r+"\\]");e=Fn((e.match(i)||[])[1]||"").trim()}t=s.lexer("```"+a.embed.lang+"\n"+e.replace(/`/g,"@DOCSIFY_QM@")+"\n```\n")}else"mermaid"===a.embed.type?(t=[{type:"html",text:'<div class="mermaid">\n'+e+"\n</div>"}]).links={}:(t=[{type:"html",text:e}]).links={};o({token:a,embedToken:t}),++c>=l&&o({})}}(t);t.embed.url?q(t.embed.url).then(r):r(t.embed.html)}}({compile:s,embedTokens:c,fetch:t},function(e){var t=e.embedToken,n=e.token;if(n){var r=n.index;d.forEach(function(e){r>e.start&&(r+=e.length)}),f(p,t.links),l=l.slice(0,r).concat(t,l.slice(r+1)),d.push({start:r,length:t.length-1})}else zn[a]=l.concat(),l.links=zn[a].links=p,i(l)})}function Mn(){var e=y(".markdown-section>script").filter(function(e){return!/template/.test(e.type)})[0];if(!e)return!1;var t=e.innerText.trim();if(!t)return!1;setTimeout(function(e){window.__EXECUTE_RESULT__=new Function(t)()},0)}function Nn(e,t,n){return t="function"==typeof n?n(t):"string"==typeof n?function(r,i){var a=[],o=0;return r.replace(T,function(t,e,n){a.push(r.substring(o,n-1)),o=n+=t.length+1,a.push(i&&i[t]||function(e){return("00"+("string"==typeof E[t]?e[E[t]]():E[t](e))).slice(-t.length)})}),o!==r.length&&a.push(r.substring(o)),function(e){for(var t="",n=0,r=e||new Date;n<a.length;n++)t+="string"==typeof a[n]?a[n]:a[n](r);return t}}(n)(new Date(t)):t,e.replace(/{docsify-updated}/g,t)}function Pn(e){e=e||"<h1>404 - Not found</h1>",this._renderTo(".markdown-section",e),this.config.loadSidebar||this._renderSidebar(),!1===this.config.executeScript||void 0===window.Vue||Mn()?this.config.executeScript&&Mn():setTimeout(function(e){var t=window.__EXECUTE_RESULT__;t&&t.$destroy&&t.$destroy(),window.__EXECUTE_RESULT__=(new window.Vue).$mount("#main")},0)}function Dn(e){var t=e.config;e.compiler=new $n(t,e.router),window.__current_docsify_compiler__=e.compiler;var n=t.el||"#app",r=b("nav")||g("nav"),i=b(n),a="",o=v;if(i){if(t.repo&&(a+=function(e,t){return e?(/\/\//.test(e)||(e="https://github.com/"+e),'<a href="'+(e=e.replace(/^git\+/,""))+'" target="'+(t=t||"_blank")+'" class="github-corner" aria-label="View source on Github"><svg viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>'):""}(t.repo,t.cornerExternalLinkTarge)),t.coverpage&&(a+=function(){var e=", 100%, 85%";return'<section class="cover show" style="background: '+("linear-gradient(to left bottom, hsl("+Math.floor(255*Math.random())+e+") 0%,hsl("+Math.floor(255*Math.random())+e+") 100%)")+'"><div class="mask"></div><div class="cover-main">\x3c!--cover--\x3e</div></section>'}()),t.logo){var s=/^data:image/.test(t.logo),l=/(?:http[s]?:)?\/\//.test(t.logo),c=/^\./.test(t.logo);s||l||c||(t.logo=re(e.router.getBasePath(),t.logo))}a+=function(e){var t=e.name?e.name:"";return"<main>"+('<button class="sidebar-toggle" aria-label="Menu"><div class="sidebar-toggle-button"><span></span><span></span><span></span></div></button><aside class="sidebar">'+(e.name?'<h1 class="app-name"><a class="app-name-link" data-nosearch>'+(e.logo?'<img alt="'+t+'" src='+e.logo+">":t)+"</a></h1>":"")+'<div class="sidebar-nav">\x3c!--sidebar--\x3e</div></aside>')+'<section class="content"><article class="markdown-section" id="main">\x3c!--main--\x3e</article></section></main>'}(t),e._renderTo(i,a,!0)}else e.rendered=!0;t.mergeNavbar&&h?o=b(".sidebar"):(r.classList.add("app-nav"),t.repo||r.classList.add("no-badge")),t.loadNavbar&&k(o,r),t.themeColor&&(u.head.appendChild(g("div",function(e){return"<style>:root{--theme-color: "+e+";}</style>"}(t.themeColor)).firstElementChild),function(n){if(!(window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)"))){var e=y("style:not(.inserted),link");[].forEach.call(e,function(e){if("STYLE"===e.nodeName)U(e,n);else if("LINK"===e.nodeName){var t=e.getAttribute("href");if(!/\.css$/.test(t))return;q(t).then(function(e){var t=g("style",e);d.appendChild(t),U(t,n)})}})}}(t.themeColor)),e._updateRender(),_(v,"ready")}var jn={};function Hn(e){this.config=e}function In(e){var t=location.href.indexOf("#");location.replace(location.href.slice(0,0<=t?t:0)+"#"+e)}Hn.prototype.getBasePath=function(){return this.config.basePath},Hn.prototype.getFile=function(e,t){void 0===e&&(e=this.getCurrentPath());var n=this.config,r=this.getBasePath(),i="string"==typeof n.ext?n.ext:".md";return e=(e=function(e,t){return new RegExp("\\.("+t.replace(/^\./,"")+"|html)$","g").test(e)?e:/\/$/g.test(e)?e+"README"+t:""+e+t}(e=n.alias?function e(t,n,r){var i=Object.keys(n).filter(function(e){return(jn[e]||(jn[e]=new RegExp("^"+e+"$"))).test(t)&&t!==r})[0];return i?e(t.replace(jn[i],n[i]),n,t):t}(e,n.alias):e,i))==="/README"+i&&n.homepage||e,e=Q(e)?e:re(r,e),t&&(e=e.replace(new RegExp("^"+r),"")),e},Hn.prototype.onchange=function(e){void 0===e&&(e=p),e()},Hn.prototype.getCurrentPath=function(){},Hn.prototype.normalize=function(){},Hn.prototype.parse=function(){},Hn.prototype.toURL=function(e,t,n){var r=n&&"#"===e[0],i=this.parse(ie(e));if(i.query=f({},i.query,t),e=(e=i.path+K(i.query)).replace(/\.md(\?)|\.md$/,"$1"),r){var a=n.indexOf("?");e=(0<a?n.substring(0,a):n)+e}if(this.config.relativePath&&0!==e.indexOf("/")){var o=n.substring(0,n.lastIndexOf("/")+1);return te(ne(o+e))}return te("/"+e)};var qn=function(r){function e(e){r.call(this,e),this.mode="hash"}return r&&(e.__proto__=r),((e.prototype=Object.create(r&&r.prototype)).constructor=e).prototype.getBasePath=function(){var e=window.location.pathname||"",t=this.config.basePath;return/^(\/|https?:)/g.test(t)?t:te(e+"/"+t)},e.prototype.getCurrentPath=function(){var e=location.href,t=e.indexOf("#");return-1===t?"":e.slice(t+1)},e.prototype.onchange=function(n){void 0===n&&(n=p);var r=!1;x("click",function(e){var t="A"===e.target.tagName?e.target:e.target.parentNode;t&&"A"===t.tagName&&!/_blank/.test(t.target)&&(r=!0)}),x("hashchange",function(e){var t=r?"navigate":"history";r=!1,n({event:e,source:t})})},e.prototype.normalize=function(){var e=this.getCurrentPath();if("/"===(e=ie(e)).charAt(0))return In(e);In("/"+e)},e.prototype.parse=function(e){void 0===e&&(e=location.href);var t="",n=e.indexOf("#");0<=n&&(e=e.slice(n+1));var r=e.indexOf("?");return 0<=r&&(t=e.slice(r+1),e=e.slice(0,r)),{path:e,file:this.getFile(e,!0),query:X(t)}},e.prototype.toURL=function(e,t,n){return"#"+r.prototype.toURL.call(this,e,t,n)},e}(Hn),Un=function(t){function e(e){t.call(this,e),this.mode="history"}return t&&(e.__proto__=t),((e.prototype=Object.create(t&&t.prototype)).constructor=e).prototype.getCurrentPath=function(){var e=this.getBasePath(),t=window.location.pathname;return e&&0===t.indexOf(e)&&(t=t.slice(e.length)),(t||"/")+window.location.search+window.location.hash},e.prototype.onchange=function(r){var i=this;void 0===r&&(r=p),x("click",function(e){var t="A"===e.target.tagName?e.target:e.target.parentNode;if("A"===t.tagName&&!/_blank/.test(t.target)){e.preventDefault();var n=t.href;-1!==i.config.crossOriginLinks.indexOf(n)?window.open(n,"_self"):window.history.pushState({key:n},"",n),r({event:e,source:"navigate"})}}),x("popstate",function(e){r({event:e,source:"history"})})},e.prototype.parse=function(e){void 0===e&&(e=location.href);var t="",n=e.indexOf("?");0<=n&&(t=e.slice(n+1),e=e.slice(0,n));var r=re(location.origin),i=e.indexOf(r);return-1<i&&(e=e.slice(i+r.length)),{path:e,file:this.getFile(e),query:X(t)}},e}(Hn);var Bn={};function Zn(e){e.router.normalize(),e.route=e.router.parse(),v.setAttribute("data-page",e.route.file)}function Wn(e){!function(e){function t(e){return v.classList.toggle("close")}null!=(e=m(e))&&(x(e,"click",function(e){e.stopPropagation(),t()}),h&&x(v,"click",function(e){return v.classList.contains("close")&&t()}))}("button.sidebar-toggle",e.router),function(e){null!=(e=m(e))&&x(e,"click",function(e){var t=e.target;"A"===t.nodeName&&t.nextSibling&&t.nextSibling.classList&&t.nextSibling.classList.contains("app-sub-sidebar")&&_(t.parentNode,"collapse")})}(".sidebar",e.router),e.config.coverpage?h||x("scroll",W):v.classList.add("sticky")}function Yn(t,n,r,i,a,e){t=e?t:t.replace(/\/$/,""),(t=ee(t))&&q(a.router.getFile(t+r)+n,!1,a.config.requestHeaders).then(i,function(e){return Yn(t,n,r,i,a)})}var Gn=Object.freeze({__proto__:null,cached:s,hyphenate:a,hasOwn:l,merge:f,isPrimitive:c,noop:p,isFn:r,inBrowser:!0,isMobile:h,supportsPushState:i,parseQuery:X,stringifyQuery:K,isAbsolutePath:Q,removeParams:J,getParentPath:ee,cleanPath:te,resolvePath:ne,getPath:re,replaceSlug:ie});function Vn(){this._init()}var Xn,Kn,Qn,Jn=Vn.prototype;function er(e,t,n){return Qn&&Qn.abort&&Qn.abort(),Qn=q(e,!0,n)}Jn._init=function(){var e=this;e.config=A(e),function(n){n._hooks={},n._lifecycle={},["init","mounted","beforeEach","afterEach","doneEach","ready"].forEach(function(e){var t=n._hooks[e]=[];n._lifecycle[e]=function(e){return t.push(e)}})}(e),function(t){[].concat(t.config.plugins).forEach(function(e){return r(e)&&e(t._lifecycle,t)})}(e),B(e,"init"),function(t){var e,n=t.config;e="history"===(n.routerMode||"hash")&&i?new Un(n):new qn(n),t.router=e,Zn(t),Bn=t.route,e.onchange(function(e){Zn(t),t._updateRender(),Bn.path!==t.route.path?(t.$fetch(p,t.$resetEvents.bind(t,e.source)),Bn=t.route):t.$resetEvents(e.source)})}(e),Dn(e),Wn(e),function(t){var e=t.config.loadSidebar;if(t.rendered){var n=Y(t.router,".sidebar-nav",!0,!0);e&&n&&(n.parentNode.innerHTML+=window.__SUB_SIDEBAR__),t._bindEventOnRendered(n),t.$resetEvents(),B(t,"doneEach"),B(t,"ready")}else t.$fetch(function(e){return B(t,"ready")})}(e),B(e,"mounted")},Jn.route={},(Xn=Jn)._renderTo=function(e,t,n){var r=m(e);r&&(r[n?"outerHTML":"innerHTML"]=t)},Xn._renderSidebar=function(e){var t=this.config,n=t.maxLevel,r=t.subMaxLevel,i=t.loadSidebar;if(t.hideSidebar)return document.querySelector("aside.sidebar").remove(),document.querySelector("button.sidebar-toggle").remove(),document.querySelector("section.content").style.right="unset",document.querySelector("section.content").style.left="unset",document.querySelector("section.content").style.position="relative",document.querySelector("section.content").style.width="100%",null;this._renderTo(".sidebar-nav",this.compiler.sidebar(e,n));var a=Y(this.router,".sidebar-nav",!0,!0);i&&a?a.parentNode.innerHTML+=this.compiler.subSidebar(r)||"":this.compiler.subSidebar(),this._bindEventOnRendered(a)},Xn._bindEventOnRendered=function(e){var t=this.config.autoHeader;if(function(e){var t=b(".cover.show");ge=t?t.offsetHeight:0;var n=m(".sidebar"),r=[];null!=n&&(r=y(n,"li"));for(var i=0,a=r.length;i<a;i+=1){var o=r[i],s=o.querySelector("a");if(s){var l=s.getAttribute("href");if("/"!==l){var c=e.parse(l),u=c.query.id,p=c.path;u&&(l=ve(p,u))}l&&(pe[decodeURIComponent(l)]=o)}}if(!h){var d=J(e.getCurrentPath());w("scroll",function(){return me(d)}),x("scroll",function(){return me(d)}),x(n,"mouseover",function(){de=!0}),x(n,"mouseleave",function(){de=!1})}}(this.router),t&&e){var n=m("#main"),r=n.children[0];r&&"H1"!==r.tagName&&k(n,g("div",this.compiler.header(e.innerText,1)).children[0])}},Xn._renderNav=function(e){e&&this._renderTo("nav",this.compiler.compile(e)),this.config.loadNavbar&&Y(this.router,"nav")},Xn._renderMain=function(r,i,a){var o=this;if(void 0===i&&(i={}),!r)return Pn.call(this,r);B(this,"beforeEach",r,function(e){function t(){i.updatedAt&&(n=Nn(n,i.updatedAt,o.config.formatUpdated)),B(o,"afterEach",n,function(e){return Pn.call(o,e)})}var n;o.isHTML?(n=o.result=r,t(),a()):On({compiler:o.compiler,raw:e},function(e){n=o.compiler.compile(e),n=o.isRemoteUrl?j.sanitize(n):n,t(),a()})})},Xn._renderCover=function(e,t){var n=m(".cover");if(_(m("main"),t?"add":"remove","hidden"),e){_(n,"add","show");var r=this.coverIsHTML?e:this.compiler.cover(e),i=r.trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$');if(i){if("color"===i[2])n.style.background=i[1]+(i[3]||"");else{var a=i[1];_(n,"add","has-mask"),Q(i[1])||(a=re(this.router.getBasePath(),i[1])),n.style.backgroundImage="url("+a+")",n.style.backgroundSize="cover",n.style.backgroundPosition="center center"}r=r.replace(i[0],"")}this._renderTo(".cover-main",r),W()}else _(n,"remove","show")},Xn._updateRender=function(){!function(e){var t=m(".app-name-link"),n=e.config.nameLink,r=e.route.path;if(t)if(c(e.config.nameLink))t.setAttribute("href",n);else if("object"==typeof n){var i=Object.keys(n).filter(function(e){return-1<r.indexOf(e)})[0];t.setAttribute("href",n[i])}}(this)},(Kn=Jn)._loadSideAndNav=function(e,t,n,r){var i=this;return function(){if(!n)return r();Yn(e,t,n,function(e){i._renderSidebar(e),r()},i,!0)}},Kn._fetch=function(n){var r=this;void 0===n&&(n=p);var e=this.route,i=e.path,a=K(e.query,["id"]),t=this.config,o=t.loadNavbar,s=t.requestHeaders,l=t.loadSidebar,c=this.router.getFile(i),u=er(c+a,0,s);this.isRemoteUrl=function(e){var t=e.match(/^([^:\/?#]+:)?(?:\/\/([^\/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/);return"string"==typeof t[1]&&0<t[1].length&&t[1].toLowerCase()!==location.protocol||"string"==typeof t[2]&&0<t[2].length&&t[2].replace(new RegExp(":("+{"http:":80,"https:":443}[location.protocol]+")?$"),"")!==location.host}(c),this.isHTML=/\.html$/g.test(c),u.then(function(e,t){return r._renderMain(e,t,r._loadSideAndNav(i,a,l,n))},function(e){r._fetchFallbackPage(i,a,n)||r._fetch404(c,a,n)}),o&&Yn(i,a,o,function(e){return r._renderNav(e)},this,!0)},Kn._fetchCover=function(){var t=this,e=this.config,n=e.coverpage,r=e.requestHeaders,i=this.route.query,a=ee(this.route.path);if(n){var o=null,s=this.route.path;if("string"==typeof n)"/"===s&&(o=n);else if(Array.isArray(n))o=-1<n.indexOf(s)&&"_coverpage";else{var l=n[s];o=!0===l?"_coverpage":l}var c=Boolean(o)&&this.config.onlyCover;return o?(o=this.router.getFile(a+o),this.coverIsHTML=/\.html$/g.test(o),q(o+K(i,["id"]),!1,r).then(function(e){return t._renderCover(e,c)})):this._renderCover(null,c),c}},Kn.$fetch=function(e,t){var n=this;function r(){B(n,"doneEach"),e()}void 0===e&&(e=p),void 0===t&&(t=this.$resetEvents.bind(this)),this._fetchCover()?r():this._fetch(function(){t(),r()})},Kn._fetchFallbackPage=function(n,r,i){var a=this;void 0===i&&(i=p);var e=this.config,t=e.requestHeaders,o=e.fallbackLanguages,s=e.loadSidebar;if(!o)return!1;var l=n.split("/")[1];if(-1===o.indexOf(l))return!1;var c=this.router.getFile(n.replace(new RegExp("^/"+l),""));return er(c+r,0,t).then(function(e,t){return a._renderMain(e,t,a._loadSideAndNav(n,r,s,i))},function(){return a._fetch404(n,r,i)}),!0},Kn._fetch404=function(e,t,n){var r=this;void 0===n&&(n=p);var i=this.config,a=i.loadSidebar,o=i.requestHeaders,s=i.notFoundPage,l=this._loadSideAndNav(e,t,a,n);if(s){var c=function(t,e){var n,r,i=e.notFoundPage,a="_404"+(e.ext||".md");switch(typeof i){case"boolean":r=a;break;case"string":r=i;break;case"object":r=(n=Object.keys(i).sort(function(e,t){return t.length-e.length}).find(function(e){return t.match(new RegExp("^"+e))}))&&i[n]||a}return r}(e,this.config);return er(this.router.getFile(c),0,o).then(function(e,t){return r._renderMain(e,t,l)},function(){return r._renderMain(null,{},l)}),!0}return this._renderMain(null,{},l),!1},Jn.$resetEvents=function(e){var t=this,n=this.config.auto2top;"history"!==e&&(t.route.query.id&&be(t.route.path,t.route.query.id),"navigate"===e&&n&&function(e){void 0===e&&(e=0),ye.scrollTop=!0===e?0:Number(e)}(n)),this.config.loadNavbar&&Y(this.router,"nav")},window.Docsify={util:Gn,dom:t,get:q,slugify:_n,version:"4.11.6"},window.DocsifyCompiler=$n,window.marked=mn,window.Prism=En,e(function(e){return new Vn})}(); diff --git a/asset/edit.css b/asset/edit.css deleted file mode 100644 index 960bc6ef..00000000 --- a/asset/edit.css +++ /dev/null @@ -1,15 +0,0 @@ -#edit-btn { - position: fixed; - right: 15px; - top: 260px; - width: 35px; - height: 35px; - background-repeat: no-repeat; - background-size: cover; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-image: url(edit.svg); -} \ No newline at end of file diff --git a/asset/edit.js b/asset/edit.js deleted file mode 100644 index 753f3eda..00000000 --- a/asset/edit.js +++ /dev/null @@ -1,15 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - var editBtn = document.createElement('div') - editBtn.id = 'edit-btn' - document.body.append(editBtn) - - var repo = window.$docsify.repo - editBtn.addEventListener('click', function() { - if (!repo) return - if (!/https?:\/\//.exec(repo)) - repo = 'https://github.com/' + repo - var url = repo + '/tree/master' + - location.hash.slice(1) + '.md' - window.open(url) - }) -}) \ No newline at end of file diff --git a/asset/edit.svg b/asset/edit.svg deleted file mode 100644 index e941dd34..00000000 --- a/asset/edit.svg +++ /dev/null @@ -1,13 +0,0 @@ -<!--?xml version="1.0" encoding="UTF-8" standalone="no"?--> -<svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="si-glyph si-glyph-edit"> - <!-- Generator: Sketch 3.0.3 (7891) - http://www.bohemiancoding.com/sketch --> - <title>Edit - - - - - - - - - \ No newline at end of file diff --git a/asset/fonts/KaTeX_AMS-Regular.ttf b/asset/fonts/KaTeX_AMS-Regular.ttf deleted file mode 100644 index afcd2eb4..00000000 Binary files a/asset/fonts/KaTeX_AMS-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_AMS-Regular.woff b/asset/fonts/KaTeX_AMS-Regular.woff deleted file mode 100644 index 4f575152..00000000 Binary files a/asset/fonts/KaTeX_AMS-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_AMS-Regular.woff2 b/asset/fonts/KaTeX_AMS-Regular.woff2 deleted file mode 100644 index b982d6ea..00000000 Binary files a/asset/fonts/KaTeX_AMS-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Caligraphic-Bold.ttf b/asset/fonts/KaTeX_Caligraphic-Bold.ttf deleted file mode 100644 index f84148db..00000000 Binary files a/asset/fonts/KaTeX_Caligraphic-Bold.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Caligraphic-Bold.woff b/asset/fonts/KaTeX_Caligraphic-Bold.woff deleted file mode 100644 index ab56ab7f..00000000 Binary files a/asset/fonts/KaTeX_Caligraphic-Bold.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Caligraphic-Bold.woff2 b/asset/fonts/KaTeX_Caligraphic-Bold.woff2 deleted file mode 100644 index 710c2617..00000000 Binary files a/asset/fonts/KaTeX_Caligraphic-Bold.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Caligraphic-Regular.ttf b/asset/fonts/KaTeX_Caligraphic-Regular.ttf deleted file mode 100644 index 97814db7..00000000 Binary files a/asset/fonts/KaTeX_Caligraphic-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Caligraphic-Regular.woff b/asset/fonts/KaTeX_Caligraphic-Regular.woff deleted file mode 100644 index aec8a333..00000000 Binary files a/asset/fonts/KaTeX_Caligraphic-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Caligraphic-Regular.woff2 b/asset/fonts/KaTeX_Caligraphic-Regular.woff2 deleted file mode 100644 index ee5193d7..00000000 Binary files a/asset/fonts/KaTeX_Caligraphic-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Fraktur-Bold.ttf b/asset/fonts/KaTeX_Fraktur-Bold.ttf deleted file mode 100644 index 483a7cdd..00000000 Binary files a/asset/fonts/KaTeX_Fraktur-Bold.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Fraktur-Bold.woff b/asset/fonts/KaTeX_Fraktur-Bold.woff deleted file mode 100644 index 189fea5e..00000000 Binary files a/asset/fonts/KaTeX_Fraktur-Bold.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Fraktur-Bold.woff2 b/asset/fonts/KaTeX_Fraktur-Bold.woff2 deleted file mode 100644 index dc3bd4c0..00000000 Binary files a/asset/fonts/KaTeX_Fraktur-Bold.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Fraktur-Regular.ttf b/asset/fonts/KaTeX_Fraktur-Regular.ttf deleted file mode 100644 index 9aa5f674..00000000 Binary files a/asset/fonts/KaTeX_Fraktur-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Fraktur-Regular.woff b/asset/fonts/KaTeX_Fraktur-Regular.woff deleted file mode 100644 index d01450e9..00000000 Binary files a/asset/fonts/KaTeX_Fraktur-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Fraktur-Regular.woff2 b/asset/fonts/KaTeX_Fraktur-Regular.woff2 deleted file mode 100644 index 7eeba377..00000000 Binary files a/asset/fonts/KaTeX_Fraktur-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Bold.ttf b/asset/fonts/KaTeX_Main-Bold.ttf deleted file mode 100644 index dc0185a1..00000000 Binary files a/asset/fonts/KaTeX_Main-Bold.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Bold.woff b/asset/fonts/KaTeX_Main-Bold.woff deleted file mode 100644 index acf48e66..00000000 Binary files a/asset/fonts/KaTeX_Main-Bold.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Bold.woff2 b/asset/fonts/KaTeX_Main-Bold.woff2 deleted file mode 100644 index cf5ababf..00000000 Binary files a/asset/fonts/KaTeX_Main-Bold.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-BoldItalic.ttf b/asset/fonts/KaTeX_Main-BoldItalic.ttf deleted file mode 100644 index 4346f173..00000000 Binary files a/asset/fonts/KaTeX_Main-BoldItalic.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-BoldItalic.woff b/asset/fonts/KaTeX_Main-BoldItalic.woff deleted file mode 100644 index d2cfe4e3..00000000 Binary files a/asset/fonts/KaTeX_Main-BoldItalic.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-BoldItalic.woff2 b/asset/fonts/KaTeX_Main-BoldItalic.woff2 deleted file mode 100644 index d0178f42..00000000 Binary files a/asset/fonts/KaTeX_Main-BoldItalic.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Italic.ttf b/asset/fonts/KaTeX_Main-Italic.ttf deleted file mode 100644 index f2c3ebae..00000000 Binary files a/asset/fonts/KaTeX_Main-Italic.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Italic.woff b/asset/fonts/KaTeX_Main-Italic.woff deleted file mode 100644 index 1184295d..00000000 Binary files a/asset/fonts/KaTeX_Main-Italic.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Italic.woff2 b/asset/fonts/KaTeX_Main-Italic.woff2 deleted file mode 100644 index aa05e142..00000000 Binary files a/asset/fonts/KaTeX_Main-Italic.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Regular.ttf b/asset/fonts/KaTeX_Main-Regular.ttf deleted file mode 100644 index 8acb3654..00000000 Binary files a/asset/fonts/KaTeX_Main-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Regular.woff b/asset/fonts/KaTeX_Main-Regular.woff deleted file mode 100644 index 9f8228fc..00000000 Binary files a/asset/fonts/KaTeX_Main-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Main-Regular.woff2 b/asset/fonts/KaTeX_Main-Regular.woff2 deleted file mode 100644 index e3f71eb7..00000000 Binary files a/asset/fonts/KaTeX_Main-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Math-BoldItalic.ttf b/asset/fonts/KaTeX_Math-BoldItalic.ttf deleted file mode 100644 index a645df64..00000000 Binary files a/asset/fonts/KaTeX_Math-BoldItalic.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Math-BoldItalic.woff b/asset/fonts/KaTeX_Math-BoldItalic.woff deleted file mode 100644 index 87d4f223..00000000 Binary files a/asset/fonts/KaTeX_Math-BoldItalic.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Math-BoldItalic.woff2 b/asset/fonts/KaTeX_Math-BoldItalic.woff2 deleted file mode 100644 index 83b49962..00000000 Binary files a/asset/fonts/KaTeX_Math-BoldItalic.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Math-Italic.ttf b/asset/fonts/KaTeX_Math-Italic.ttf deleted file mode 100644 index 9c38359c..00000000 Binary files a/asset/fonts/KaTeX_Math-Italic.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Math-Italic.woff b/asset/fonts/KaTeX_Math-Italic.woff deleted file mode 100644 index 959746ef..00000000 Binary files a/asset/fonts/KaTeX_Math-Italic.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Math-Italic.woff2 b/asset/fonts/KaTeX_Math-Italic.woff2 deleted file mode 100644 index e3ea522a..00000000 Binary files a/asset/fonts/KaTeX_Math-Italic.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Bold.ttf b/asset/fonts/KaTeX_SansSerif-Bold.ttf deleted file mode 100644 index ff108512..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Bold.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Bold.woff b/asset/fonts/KaTeX_SansSerif-Bold.woff deleted file mode 100644 index f0d6ea73..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Bold.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Bold.woff2 b/asset/fonts/KaTeX_SansSerif-Bold.woff2 deleted file mode 100644 index 4cf8f146..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Bold.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Italic.ttf b/asset/fonts/KaTeX_SansSerif-Italic.ttf deleted file mode 100644 index 3dd76713..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Italic.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Italic.woff b/asset/fonts/KaTeX_SansSerif-Italic.woff deleted file mode 100644 index 9da0dfe3..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Italic.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Italic.woff2 b/asset/fonts/KaTeX_SansSerif-Italic.woff2 deleted file mode 100644 index ce19ae03..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Italic.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Regular.ttf b/asset/fonts/KaTeX_SansSerif-Regular.ttf deleted file mode 100644 index f117cd61..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Regular.woff b/asset/fonts/KaTeX_SansSerif-Regular.woff deleted file mode 100644 index 6ed98780..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_SansSerif-Regular.woff2 b/asset/fonts/KaTeX_SansSerif-Regular.woff2 deleted file mode 100644 index 27611491..00000000 Binary files a/asset/fonts/KaTeX_SansSerif-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Script-Regular.ttf b/asset/fonts/KaTeX_Script-Regular.ttf deleted file mode 100644 index e6f34542..00000000 Binary files a/asset/fonts/KaTeX_Script-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Script-Regular.woff b/asset/fonts/KaTeX_Script-Regular.woff deleted file mode 100644 index 4a48e65f..00000000 Binary files a/asset/fonts/KaTeX_Script-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Script-Regular.woff2 b/asset/fonts/KaTeX_Script-Regular.woff2 deleted file mode 100644 index b0aed195..00000000 Binary files a/asset/fonts/KaTeX_Script-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Size1-Regular.ttf b/asset/fonts/KaTeX_Size1-Regular.ttf deleted file mode 100644 index 37faa0f9..00000000 Binary files a/asset/fonts/KaTeX_Size1-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Size1-Regular.woff b/asset/fonts/KaTeX_Size1-Regular.woff deleted file mode 100644 index 0832f7a4..00000000 Binary files a/asset/fonts/KaTeX_Size1-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Size1-Regular.woff2 b/asset/fonts/KaTeX_Size1-Regular.woff2 deleted file mode 100644 index 483e7b66..00000000 Binary files a/asset/fonts/KaTeX_Size1-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Size2-Regular.ttf b/asset/fonts/KaTeX_Size2-Regular.ttf deleted file mode 100644 index cf326236..00000000 Binary files a/asset/fonts/KaTeX_Size2-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Size2-Regular.woff b/asset/fonts/KaTeX_Size2-Regular.woff deleted file mode 100644 index 14f6485a..00000000 Binary files a/asset/fonts/KaTeX_Size2-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Size2-Regular.woff2 b/asset/fonts/KaTeX_Size2-Regular.woff2 deleted file mode 100644 index 5ff70606..00000000 Binary files a/asset/fonts/KaTeX_Size2-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Size3-Regular.ttf b/asset/fonts/KaTeX_Size3-Regular.ttf deleted file mode 100644 index ff7e2b90..00000000 Binary files a/asset/fonts/KaTeX_Size3-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Size3-Regular.woff b/asset/fonts/KaTeX_Size3-Regular.woff deleted file mode 100644 index d3626cef..00000000 Binary files a/asset/fonts/KaTeX_Size3-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Size3-Regular.woff2 b/asset/fonts/KaTeX_Size3-Regular.woff2 deleted file mode 100644 index e45ca49d..00000000 Binary files a/asset/fonts/KaTeX_Size3-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Size4-Regular.ttf b/asset/fonts/KaTeX_Size4-Regular.ttf deleted file mode 100644 index 3034091c..00000000 Binary files a/asset/fonts/KaTeX_Size4-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Size4-Regular.woff b/asset/fonts/KaTeX_Size4-Regular.woff deleted file mode 100644 index 93c57a6f..00000000 Binary files a/asset/fonts/KaTeX_Size4-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Size4-Regular.woff2 b/asset/fonts/KaTeX_Size4-Regular.woff2 deleted file mode 100644 index 53b65afc..00000000 Binary files a/asset/fonts/KaTeX_Size4-Regular.woff2 and /dev/null differ diff --git a/asset/fonts/KaTeX_Typewriter-Regular.ttf b/asset/fonts/KaTeX_Typewriter-Regular.ttf deleted file mode 100644 index 2fd85294..00000000 Binary files a/asset/fonts/KaTeX_Typewriter-Regular.ttf and /dev/null differ diff --git a/asset/fonts/KaTeX_Typewriter-Regular.woff b/asset/fonts/KaTeX_Typewriter-Regular.woff deleted file mode 100644 index e90fa2bc..00000000 Binary files a/asset/fonts/KaTeX_Typewriter-Regular.woff and /dev/null differ diff --git a/asset/fonts/KaTeX_Typewriter-Regular.woff2 b/asset/fonts/KaTeX_Typewriter-Regular.woff2 deleted file mode 100644 index e40ab151..00000000 Binary files a/asset/fonts/KaTeX_Typewriter-Regular.woff2 and /dev/null differ diff --git a/asset/katex.min.css b/asset/katex.min.css deleted file mode 100644 index 98b7c7bd..00000000 --- a/asset/katex.min.css +++ /dev/null @@ -1 +0,0 @@ -@font-face{font-family:KaTeX_AMS;src:url(fonts/KaTeX_AMS-Regular.woff2) format("woff2"),url(fonts/KaTeX_AMS-Regular.woff) format("woff"),url(fonts/KaTeX_AMS-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Bold.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Regular.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Bold.woff) format("woff"),url(fonts/KaTeX_Fraktur-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Regular.woff) format("woff"),url(fonts/KaTeX_Fraktur-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Bold.woff2) format("woff2"),url(fonts/KaTeX_Main-Bold.woff) format("woff"),url(fonts/KaTeX_Main-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Main-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Main-BoldItalic.ttf) format("truetype");font-weight:700;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Italic.woff2) format("woff2"),url(fonts/KaTeX_Main-Italic.woff) format("woff"),url(fonts/KaTeX_Main-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Regular.woff2) format("woff2"),url(fonts/KaTeX_Main-Regular.woff) format("woff"),url(fonts/KaTeX_Main-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Math-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Math-BoldItalic.ttf) format("truetype");font-weight:700;font-style:italic}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-Italic.woff2) format("woff2"),url(fonts/KaTeX_Math-Italic.woff) format("woff"),url(fonts/KaTeX_Math-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Bold.woff) format("woff"),url(fonts/KaTeX_SansSerif-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Italic.woff) format("woff"),url(fonts/KaTeX_SansSerif-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Regular.woff) format("woff"),url(fonts/KaTeX_SansSerif-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Script;src:url(fonts/KaTeX_Script-Regular.woff2) format("woff2"),url(fonts/KaTeX_Script-Regular.woff) format("woff"),url(fonts/KaTeX_Script-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size1;src:url(fonts/KaTeX_Size1-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size1-Regular.woff) format("woff"),url(fonts/KaTeX_Size1-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size2;src:url(fonts/KaTeX_Size2-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size2-Regular.woff) format("woff"),url(fonts/KaTeX_Size2-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size3;src:url(fonts/KaTeX_Size3-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size3-Regular.woff) format("woff"),url(fonts/KaTeX_Size3-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size4;src:url(fonts/KaTeX_Size4-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size4-Regular.woff) format("woff"),url(fonts/KaTeX_Size4-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Typewriter;src:url(fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"),url(fonts/KaTeX_Typewriter-Regular.woff) format("woff"),url(fonts/KaTeX_Typewriter-Regular.ttf) format("truetype");font-weight:400;font-style:normal}.katex{font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0;text-rendering:auto;border-color:currentColor}.katex *{-ms-high-contrast-adjust:none!important}.katex .katex-version:after{content:"0.12.0"}.katex .katex-mathml{position:absolute;clip:rect(1px,1px,1px,1px);padding:0;border:0;height:1px;width:1px;overflow:hidden}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-weight:700;font-style:italic}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{display:inline-table;table-layout:fixed;border-collapse:collapse}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;vertical-align:bottom;position:relative}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;vertical-align:bottom;font-size:1px;width:2px;min-width:2px}.katex .vbox{-ms-flex-direction:column;flex-direction:column;align-items:baseline}.katex .hbox,.katex .vbox{display:-ms-inline-flexbox;display:inline-flex}.katex .hbox{-ms-flex-direction:row;flex-direction:row;width:100%}.katex .thinbox{display:inline-flex;flex-direction:row;width:0;max-width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{display:inline-block;width:100%;border-bottom-style:solid}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{width:0;position:relative}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{display:inline-block;border:0 solid;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{display:inline-block;width:100%;border-bottom-style:solid}.katex .hdashline{display:inline-block;width:100%;border-bottom-style:dashed}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.83333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.16666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.66666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.45666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.14666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.85714286em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.46857143em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.96285714em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.55428571em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.66666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.77777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.88888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.30444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.76444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.58333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.66666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72833333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.07333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.41666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.48611111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.55555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.44027778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.72777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.28935185em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.34722222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.40509259em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.46296296em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.52083333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20023148em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.43981481em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.24108004em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.28929605em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.33751205em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.38572806em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.43394407em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48216008em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57859209em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69431051em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.83317261em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.19961427em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.20096463em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.24115756em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.28135048em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.32154341em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.36173633em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.40192926em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.48231511em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.57877814em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.69453376em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.83360129em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .op-limits>.vlist-t{text-align:center}.katex .accent>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{display:block;position:absolute;width:100%;height:inherit;fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1}.katex svg path{stroke:none}.katex img{border-style:none;min-width:0;min-height:0;max-width:none;max-height:none}.katex .stretchy{width:100%;display:block;position:relative;overflow:hidden}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{width:100%;position:relative;overflow:hidden}.katex .halfarrow-left{position:absolute;left:0;width:50.2%;overflow:hidden}.katex .halfarrow-right{position:absolute;right:0;width:50.2%;overflow:hidden}.katex .brace-left{position:absolute;left:0;width:25.1%;overflow:hidden}.katex .brace-center{position:absolute;left:25%;width:50%;overflow:hidden}.katex .brace-right{position:absolute;right:0;width:25.1%;overflow:hidden}.katex .x-arrow-pad{padding:0 .5em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{box-sizing:border-box;border:.04em solid}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{text-align:left;padding-left:2em} diff --git a/asset/left.svg b/asset/left.svg deleted file mode 100644 index 5f3e9a07..00000000 --- a/asset/left.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - 1210 - - - - - - \ No newline at end of file diff --git a/asset/moon.svg b/asset/moon.svg deleted file mode 100644 index bc0bf105..00000000 --- a/asset/moon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/asset/prism-c.min.js b/asset/prism-c.min.js deleted file mode 100644 index 6a4fff5e..00000000 --- a/asset/prism-c.min.js +++ /dev/null @@ -1 +0,0 @@ -Prism.languages.c=Prism.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+/,lookbehind:!0},keyword:/\b(?:__attribute__|_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,function:/[a-z_]\w*(?=\s*\()/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/,number:/(?:\b0x(?:[\da-f]+\.?[\da-f]*|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+(?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},Prism.languages.c.string],comment:Prism.languages.c.comment,directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:Prism.languages.c}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete Prism.languages.c.boolean; \ No newline at end of file diff --git a/asset/prism-cpp.min.js b/asset/prism-cpp.min.js deleted file mode 100644 index 129cbbb8..00000000 --- a/asset/prism-cpp.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/;e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp("(\\b(?:class|concept|enum|struct|typename)\\s+)(?!)\\w+".replace(//g,function(){return t.source})),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+\.?[\da-f']*|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+\.?[\d']*|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]*/i,greedy:!0},operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:true|false)\b/}),e.languages.insertBefore("cpp","string",{"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)(?:[^;{}"'])+?(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","operator",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(Prism); \ No newline at end of file diff --git a/asset/prism-csharp.min.js b/asset/prism-csharp.min.js deleted file mode 100644 index 4b3dc42e..00000000 --- a/asset/prism-csharp.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(s){function a(e,s){return e.replace(/<<(\d+)>>/g,function(e,n){return"(?:"+s[+n]+")"})}function t(e,n,s){return RegExp(a(e,n),s||"")}function e(e,n){for(var s=0;s>/g,function(){return"(?:"+e+")"});return e.replace(/<>/g,"[^\\s\\S]")}var n="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",r="class enum interface struct",i="add alias and ascending async await by descending from get global group into join let nameof not notnull on or orderby partial remove select set unmanaged value when where where",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var d=l(r),p=RegExp(l(n+" "+r+" "+i+" "+o)),c=l(r+" "+i+" "+o),u=l(n+" "+r+" "+o),g=e("<(?:[^<>;=+\\-*/%&|^]|<>)*>",2),b=e("\\((?:[^()]|<>)*\\)",2),h="@?\\b[A-Za-z_]\\w*\\b",f=a("<<0>>(?:\\s*<<1>>)?",[h,g]),m=a("(?!<<0>>)<<1>>(?:\\s*\\.\\s*<<1>>)*",[c,f]),k="\\[\\s*(?:,\\s*)*\\]",y=a("<<0>>(?:\\s*(?:\\?\\s*)?<<1>>)*(?:\\s*\\?)?",[m,k]),w=a("(?:<<0>>|<<1>>)(?:\\s*(?:\\?\\s*)?<<2>>)*(?:\\s*\\?)?",[a("\\(<<0>>+(?:,<<0>>+)+\\)",[a("[^,()<>[\\];=+\\-*/%&|^]|<<0>>|<<1>>|<<2>>",[g,b,k])]),m,k]),v={keyword:p,punctuation:/[<>()?,.:[\]]/},x="'(?:[^\r\n'\\\\]|\\\\.|\\\\[Uux][\\da-fA-F]{1,8})'",$='"(?:\\\\.|[^\\\\"\r\n])*"';s.languages.csharp=s.languages.extend("clike",{string:[{pattern:t("(^|[^$\\\\])<<0>>",['@"(?:""|\\\\[^]|[^\\\\"])*"(?!")']),lookbehind:!0,greedy:!0},{pattern:t("(^|[^@$\\\\])<<0>>",[$]),lookbehind:!0,greedy:!0},{pattern:RegExp(x),greedy:!0,alias:"character"}],"class-name":[{pattern:t("(\\busing\\s+static\\s+)<<0>>(?=\\s*;)",[m]),lookbehind:!0,inside:v},{pattern:t("(\\busing\\s+<<0>>\\s*=\\s*)<<1>>(?=\\s*;)",[h,w]),lookbehind:!0,inside:v},{pattern:t("(\\busing\\s+)<<0>>(?=\\s*=)",[h]),lookbehind:!0},{pattern:t("(\\b<<0>>\\s+)<<1>>",[d,f]),lookbehind:!0,inside:v},{pattern:t("(\\bcatch\\s*\\(\\s*)<<0>>",[m]),lookbehind:!0,inside:v},{pattern:t("(\\bwhere\\s+)<<0>>",[h]),lookbehind:!0},{pattern:t("(\\b(?:is(?:\\s+not)?|as)\\s+)<<0>>",[y]),lookbehind:!0,inside:v},{pattern:t("\\b<<0>>(?=\\s+(?!<<1>>)<<2>>(?:\\s*[=,;:{)\\]]|\\s+(?:in|when)\\b))",[w,u,h]),inside:v}],keyword:p,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:ul|lu|[dflmu])?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),s.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),s.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:t("([(,]\\s*)<<0>>(?=\\s*:)",[h]),lookbehind:!0,alias:"punctuation"}}),s.languages.insertBefore("csharp","class-name",{namespace:{pattern:t("(\\b(?:namespace|using)\\s+)<<0>>(?:\\s*\\.\\s*<<0>>)*(?=\\s*[;{])",[h]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:t("(\\b(?:default|typeof|sizeof)\\s*\\(\\s*)(?:[^()\\s]|\\s(?!\\s*\\))|<<0>>)*(?=\\s*\\))",[b]),lookbehind:!0,alias:"class-name",inside:v},"return-type":{pattern:t("<<0>>(?=\\s+(?:<<1>>\\s*(?:=>|[({]|\\.\\s*this\\s*\\[)|this\\s*\\[))",[w,m]),inside:v,alias:"class-name"},"constructor-invocation":{pattern:t("(\\bnew\\s+)<<0>>(?=\\s*[[({])",[w]),lookbehind:!0,inside:v,alias:"class-name"},"generic-method":{pattern:t("<<0>>\\s*<<1>>(?=\\s*\\()",[h,g]),inside:{function:t("^<<0>>",[h]),generic:{pattern:RegExp(g),alias:"class-name",inside:v}}},"type-list":{pattern:t("\\b((?:<<0>>\\s+<<1>>|where\\s+<<2>>)\\s*:\\s*)(?:<<3>>|<<4>>)(?:\\s*,\\s*(?:<<3>>|<<4>>))*(?=\\s*(?:where|[{;]|=>|$))",[d,f,h,w,p.source]),lookbehind:!0,inside:{keyword:p,"class-name":{pattern:RegExp(w),greedy:!0,inside:v},punctuation:/,/}},preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(\s*#)\b(?:define|elif|else|endif|endregion|error|if|line|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var _=$+"|"+x,B=a("/(?![*/])|//[^\r\n]*[\r\n]|/\\*(?:[^*]|\\*(?!/))*\\*/|<<0>>",[_]),E=e(a("[^\"'/()]|<<0>>|\\(<>*\\)",[B]),2),R="\\b(?:assembly|event|field|method|module|param|property|return|type)\\b",P=a("<<0>>(?:\\s*\\(<<1>>*\\))?",[m,E]);s.languages.insertBefore("csharp","class-name",{attribute:{pattern:t("((?:^|[^\\s\\w>)?])\\s*\\[\\s*)(?:<<0>>\\s*:\\s*)?<<1>>(?:\\s*,\\s*<<1>>)*(?=\\s*\\])",[R,P]),lookbehind:!0,greedy:!0,inside:{target:{pattern:t("^<<0>>(?=\\s*:)",[R]),alias:"keyword"},"attribute-arguments":{pattern:t("\\(<<0>>*\\)",[E]),inside:s.languages.csharp},"class-name":{pattern:RegExp(m),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var z=":[^}\r\n]+",S=e(a("[^\"'/()]|<<0>>|\\(<>*\\)",[B]),2),j=a("\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}",[S,z]),A=e(a("[^\"'/()]|/(?!\\*)|/\\*(?:[^*]|\\*(?!/))*\\*/|<<0>>|\\(<>*\\)",[_]),2),F=a("\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}",[A,z]);function U(e,n){return{interpolation:{pattern:t("((?:^|[^{])(?:\\{\\{)*)<<0>>",[e]),lookbehind:!0,inside:{"format-string":{pattern:t("(^\\{(?:(?![}:])<<0>>)*)<<1>>(?=\\}$)",[n,z]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:s.languages.csharp}}},string:/[\s\S]+/}}s.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:t('(^|[^\\\\])(?:\\$@|@\\$)"(?:""|\\\\[^]|\\{\\{|<<0>>|[^\\\\{"])*"',[j]),lookbehind:!0,greedy:!0,inside:U(j,S)},{pattern:t('(^|[^@\\\\])\\$"(?:\\\\.|\\{\\{|<<0>>|[^\\\\"{])*"',[F]),lookbehind:!0,greedy:!0,inside:U(F,A)}]})}(Prism),Prism.languages.dotnet=Prism.languages.cs=Prism.languages.csharp; \ No newline at end of file diff --git a/asset/prism-darcula.css b/asset/prism-darcula.css deleted file mode 100644 index 11a8f3ed..00000000 --- a/asset/prism-darcula.css +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Darcula theme - * - * Adapted from a theme based on: - * IntelliJ Darcula Theme (https://github.com/bulenkov/Darcula) - * - * @author Alexandre Paradis - * @version 1.0 - */ - -code[class*="lang-"], -pre[data-lang] { - color: #a9b7c6 !important; - background-color: #2b2b2b !important; - font-family: Consolas, Monaco, 'Andale Mono', monospace; - direction: ltr; - text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; - line-height: 1.5; - - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -pre[data-lang]::-moz-selection, pre[data-lang] ::-moz-selection, -code[class*="lang-"]::-moz-selection, code[class*="lang-"] ::-moz-selection { - color: inherit; - background: rgba(33, 66, 131, .85); -} - -pre[data-lang]::selection, pre[data-lang] ::selection, -code[class*="lang-"]::selection, code[class*="lang-"] ::selection { - color: inherit; - background: rgba(33, 66, 131, .85); -} - -/* Code blocks */ -pre[data-lang] { - padding: 1em; - margin: .5em 0; - overflow: auto; -} - -:not(pre) > code[class*="lang-"], -pre[data-lang] { - background: #2b2b2b; -} - -/* Inline code */ -:not(pre) > code[class*="lang-"] { - padding: .1em; - border-radius: .3em; -} - -.token.comment, -.token.prolog, -.token.cdata { - color: #808080; -} - -.token.delimiter, -.token.boolean, -.token.keyword, -.token.selector, -.token.important, -.token.atrule { - color: #cc7832; -} - -.token.operator, -.token.punctuation, -.token.attr-name { - color: #a9b7c6; -} - -.token.tag, -.token.tag .punctuation, -.token.doctype, -.token.builtin { - color: #e8bf6a; -} - -.token.entity, -.token.number, -.token.symbol { - color: #6897bb; -} - -.token.property, -.token.constant, -.token.variable { - color: #9876aa; -} - -.token.string, -.token.char { - color: #6a8759; -} - -.token.attr-value, -.token.attr-value .punctuation { - color: #a5c261; -} - -.token.attr-value .punctuation:first-child { - color: #a9b7c6; -} - -.token.url { - color: #287bde; - text-decoration: underline; -} - -.token.function { - color: #ffc66d; -} - -.token.regex { - background: #364135; -} - -.token.bold { - font-weight: bold; -} - -.token.italic { - font-style: italic; -} - -.token.inserted { - background: #294436; -} - -.token.deleted { - background: #484a4a; -} - -code.lang-css .token.property, -code.lang-css .token.property + .token.punctuation { - color: #a9b7c6; -} - -code.lang-css .token.id { - color: #ffc66d; -} - -code.lang-css .token.selector > .token.class, -code.lang-css .token.selector > .token.attribute, -code.lang-css .token.selector > .token.pseudo-class, -code.lang-css .token.selector > .token.pseudo-element { - color: #ffc66d; -} \ No newline at end of file diff --git a/asset/prism-java.min.js b/asset/prism-java.min.js deleted file mode 100644 index 818fd8ec..00000000 --- a/asset/prism-java.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|null|open|opens|package|private|protected|provides|public|record|requires|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,a=/\b[A-Z](?:\w*[a-z]\w*)?\b/;e.languages.java=e.languages.extend("clike",{"class-name":[a,/\b[A-Z]\w*(?=\s+\w+\s*[;,=())])/],keyword:t,function:[e.languages.clike.function,{pattern:/(\:\:)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x[\da-f_]*\.?[\da-f_p+-]+\b|(?:\b\d[\d_]*\.?[\d_]*|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"}}),e.languages.insertBefore("java","class-name",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0},namespace:{pattern:RegExp("(\\b(?:exports|import(?:\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\s+)(?!)[a-z]\\w*(?:\\.[a-z]\\w*)*\\.?".replace(//g,function(){return t.source})),lookbehind:!0,inside:{punctuation:/\./}},generics:{pattern:/<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}}})}(Prism); \ No newline at end of file diff --git a/asset/prism-javascript.min.js b/asset/prism-javascript.min.js deleted file mode 100644 index 0faf69af..00000000 --- a/asset/prism-javascript.min.js +++ /dev/null @@ -1 +0,0 @@ -Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|(?:get|set)(?=\s*[\[$\w\xA0-\uFFFF])|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript; \ No newline at end of file diff --git a/asset/prism-php.min.js b/asset/prism-php.min.js deleted file mode 100644 index 1c4ef765..00000000 --- a/asset/prism-php.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(n){n.languages.php=n.languages.extend("clike",{keyword:/\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|class|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|final|finally|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|new|or|parent|print|private|protected|public|require|require_once|return|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,boolean:{pattern:/\b(?:false|true)\b/i,alias:"constant"},constant:[/\b[A-Z_][A-Z0-9_]*\b/,/\b(?:null)\b/i],comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0}}),n.languages.insertBefore("php","string",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),n.languages.insertBefore("php","comment",{delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"}}),n.languages.insertBefore("php","keyword",{variable:/\$+(?:\w+\b|(?={))/i,package:{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),n.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}});var e={pattern:/{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)*)/,lookbehind:!0,inside:n.languages.php};n.languages.insertBefore("php","string",{"nowdoc-string":{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,greedy:!0,alias:"string",inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},"heredoc-string":{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,greedy:!0,alias:"string",inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:e}},"single-quoted-string":{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0,alias:"string"},"double-quoted-string":{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,alias:"string",inside:{interpolation:e}}}),delete n.languages.php.string,n.hooks.add("before-tokenize",function(e){if(/<\?/.test(e.code)){n.languages["markup-templating"].buildPlaceholders(e,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#)(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|\/\*[\s\S]*?(?:\*\/|$))*?(?:\?>|$)/gi)}}),n.hooks.add("after-tokenize",function(e){n.languages["markup-templating"].tokenizePlaceholders(e,"php")})}(Prism); \ No newline at end of file diff --git a/asset/prism-python.min.js b/asset/prism-python.min.js deleted file mode 100644 index 3045bfb1..00000000 --- a/asset/prism-python.min.js +++ /dev/null @@ -1 +0,0 @@ -Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},"string-interpolation":{pattern:/(?:f|rf|fr)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:{{)*){(?!{)(?:[^{}]|{(?!{)(?:[^{}]|{(?!{)(?:[^{}])+})+})+}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|rb|br)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|rb|br)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^\s*)@\w+(?:\.\w+)*/im,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:True|False|None)\b/,number:/(?:\b(?=\d)|\B(?=\.))(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python; \ No newline at end of file diff --git a/asset/right.svg b/asset/right.svg deleted file mode 100644 index 7e4d26e3..00000000 --- a/asset/right.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - 1209 - - - - - - \ No newline at end of file diff --git a/asset/search.min.js b/asset/search.min.js deleted file mode 100644 index f7447441..00000000 --- a/asset/search.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){var h={},f={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function l(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(e).replace(/[&<>"']/g,function(e){return n[e]})}function p(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function u(r,e,i,o){void 0===e&&(e="");var s,n=window.marked.lexer(e),c=window.Docsify.slugify,d={};return n.forEach(function(e){if("heading"===e.type&&e.depth<=o){var n=function(e){void 0===e&&(e="");var a={};return{str:e=e&&e.replace(/^'/,"").replace(/'$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(a[n]=t&&t.replace(/"/g,"")||!0,""):e}).trim(),config:a}}(e.text),t=n.str,a=n.config;s=a.id?i.toURL(r,{id:c(a.id)}):i.toURL(r,{id:c(l(e.text))}),d[s]={slug:s,title:t,body:""}}else{if(!s)return;d[s]?d[s].body?(e.text=p(e),d[s].body+="\n"+(e.text||"")):(e.text=p(e),d[s].body=d[s].body?d[s].body+e.text:e.text):d[s]={slug:s,title:"",body:""}}}),c.clear(),d}function c(e){var r=[],i=[];Object.keys(h).forEach(function(n){i=i.concat(Object.keys(h[n]).map(function(e){return h[n][e]}))});var o=(e=e.trim()).split(/[\s\-,\\/]+/);1!==o.length&&(o=[].concat(e,o));function n(e){var n=i[e],s=0,c="",d=n.title&&n.title.trim(),p=n.body&&n.body.trim(),t=n.slug||"";if(d&&(o.forEach(function(e){var n,t=new RegExp(e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&"),"gi"),a=-1;if(n=d?d.search(t):-1,a=p?p.search(t):-1,0<=n||0<=a){s+=0<=n?3:0<=a?2:0,a<0&&(a=0);var r,i=0;i=0==(r=a<11?0:a-10)?70:a+e.length+60,p&&i>p.length&&(i=p.length);var o="..."+l(p).substring(r,i).replace(t,function(e){return''+e+""})+"...";c+=o}}),0\n\n

'+e.title+"

\n

"+e.content+"

\n
\n"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=s||'

'+m+"

",d.hideOtherSidebarContent&&(r.classList.add("hide"),i.classList.add("hide"))}function a(e){d=e}function o(e,n){var t=n.router.parse().query.s;a(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n='
\n \n
\n \n \n \n \n \n
\n
\n
\n ',t=Docsify.dom.create("div",n),a=Docsify.dom.find("aside");Docsify.dom.toggleClass(t,"search"),Docsify.dom.before(a,t)}(t),function(){var e,n=Docsify.dom.find("div.search"),t=Docsify.dom.find(n,"input"),a=Docsify.dom.find(n,".input-wrap");Docsify.dom.on(n,"click",function(e){return-1===["A","H2","P","EM"].indexOf(e.target.tagName)&&e.stopPropagation()}),Docsify.dom.on(t,"input",function(n){clearTimeout(e),e=setTimeout(function(e){return r(n.target.value.trim())},100)}),Docsify.dom.on(a,"click",function(e){"INPUT"!==e.target.tagName&&(t.value="",r())})}(),t&&setTimeout(function(e){return r(t)},500)}function s(e,n){a(e),function(e,n){var t=Docsify.dom.getNode('.search input[type="search"]');if(t)if("string"==typeof e)t.placeholder=e;else{var a=Object.keys(e).filter(function(e){return-11?(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=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;s0?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()}); diff --git a/asset/share.svg b/asset/share.svg deleted file mode 100644 index 79da99c4..00000000 --- a/asset/share.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - Share-1 - - - - - - \ No newline at end of file diff --git a/asset/sidebar.min.css b/asset/sidebar.min.css deleted file mode 100644 index 94996d37..00000000 --- a/asset/sidebar.min.css +++ /dev/null @@ -1 +0,0 @@ -.sidebar-nav li{position:relative;margin:0;cursor:pointer}.sidebar-nav ul:not(.app-sub-sidebar)>li:not(.file)::before{content:'';display:block;position:absolute;top:11px;left:-12px;height:6px;width:6px;border-right:1px solid #505d6b;border-bottom:1px solid #505d6b;transform:rotate(-45deg);transition:transform .1s}.sidebar-nav ul:not(.app-sub-sidebar)>li.open::before{transform:rotate(45deg)}.sidebar-nav ul:not(.app-sub-sidebar)>li.collapse::before{transform:rotate(-45deg)} \ No newline at end of file diff --git a/asset/style.css b/asset/style.css deleted file mode 100644 index cccc9b95..00000000 --- a/asset/style.css +++ /dev/null @@ -1,100 +0,0 @@ - /*隐藏头部的目录*/ - #main>ul:nth-child(1) { - display: none; - } - - #main>ul:nth-child(2) { - display: none; - } - - .markdown-section h1 { - margin: 3rem 0 2rem 0; - } - - .markdown-section h2 { - margin: 2rem 0 1rem; - } - - img, - pre { - border-radius: 8px; - } - - .content, - .sidebar, - .markdown-section, - body, - .search input { - background-color: rgba(243, 242, 238, 1) !important; - } - - @media (min-width:600px) { - .sidebar-toggle { - background-color: #f3f2ee; - } - } - - .docsify-copy-code-button { - background: #f8f8f8 !important; - color: #7a7a7a !important; - } - - body { - /*font-family: Microsoft YaHei, Source Sans Pro, Helvetica Neue, Arial, sans-serif !important;*/ - } - - .markdown-section>p { - font-size: 16px !important; - } - - .markdown-section pre>code { - font-family: Consolas, Roboto Mono, Monaco, courier, monospace !important; - font-size: .9rem !important; - - } - - /*.anchor span { - color: rgb(66, 185, 131); -}*/ - - section.cover h1 { - margin: 0; - } - - body>section>div.cover-main>ul>li>a { - color: #42b983; - } - - .markdown-section img { - box-shadow: 7px 9px 10px #aaa !important; - } - - - pre { - background-color: #f3f2ee !important; - } - - @media (min-width:600px) { - pre code { - /*box-shadow: 2px 1px 20px 2px #aaa;*/ - /*border-radius: 10px !important;*/ - padding-left: 20px !important; - } - } - - @media (max-width:600px) { - pre { - padding-left: 0px !important; - padding-right: 0px !important; - } - } - - .markdown-section pre { - padding-left: 0 !important; - padding-right: 0px !important; - box-shadow: 2px 1px 20px 2px #aaa; - } - - iframe { - display: inline; - } \ No newline at end of file diff --git a/asset/sun.svg b/asset/sun.svg deleted file mode 100644 index 8fb9960c..00000000 --- a/asset/sun.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/asset/up.svg b/asset/up.svg deleted file mode 100644 index ee90b8fe..00000000 --- a/asset/up.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - 1211 - - - - - - \ No newline at end of file diff --git a/asset/vue.css b/asset/vue.css deleted file mode 100644 index d9b71bb1..00000000 --- a/asset/vue.css +++ /dev/null @@ -1,829 +0,0 @@ -@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600"); -* { - -webkit-font-smoothing: antialiased; - -webkit-overflow-scrolling: touch; - -webkit-tap-highlight-color: rgba(0,0,0,0); - -webkit-text-size-adjust: none; - -webkit-touch-callout: none; - box-sizing: border-box; -} -body:not(.ready) { - overflow: hidden; -} -body:not(.ready) [data-cloak], -body:not(.ready) .app-nav, -body:not(.ready) > nav { - display: none; -} -div#app { - font-size: 30px; - font-weight: lighter; - margin: 40vh auto; - text-align: center; -} -div#app:empty::before { - content: 'Loading...'; -} -.emoji { - height: 1.2rem; - vertical-align: middle; -} -.progress { - background-color: var(--theme-color, #42b983); - height: 2px; - left: 0px; - position: fixed; - right: 0px; - top: 0px; - transition: width 0.2s, opacity 0.4s; - width: 0%; - z-index: 999999; -} -.search a:hover { - color: var(--theme-color, #42b983); -} -.search .search-keyword { - color: var(--theme-color, #42b983); - font-style: normal; - font-weight: bold; -} -html, -body { - height: 100%; -} -body { - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - color: #34495e; - font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif; - font-size: 15px; - letter-spacing: 0; - margin: 0; - overflow-x: hidden; -} -img { - max-width: 100%; -} -a[disabled] { - cursor: not-allowed; - opacity: 0.6; -} -kbd { - border: solid 1px #ccc; - border-radius: 3px; - display: inline-block; - font-size: 12px !important; - line-height: 12px; - margin-bottom: 3px; - padding: 3px 5px; - vertical-align: middle; -} -li input[type='checkbox'] { - margin: 0 0.2em 0.25em 0; - vertical-align: middle; -} -.app-nav { - margin: 25px 60px 0 0; - position: absolute; - right: 0; - text-align: right; - z-index: 10; -/* navbar dropdown */ -} -.app-nav.no-badge { - margin-right: 25px; -} -.app-nav p { - margin: 0; -} -.app-nav > a { - margin: 0 1rem; - padding: 5px 0; -} -.app-nav ul, -.app-nav li { - display: inline-block; - list-style: none; - margin: 0; -} -.app-nav a { - color: inherit; - font-size: 16px; - text-decoration: none; - transition: color 0.3s; -} -.app-nav a:hover { - color: var(--theme-color, #42b983); -} -.app-nav a.active { - border-bottom: 2px solid var(--theme-color, #42b983); - color: var(--theme-color, #42b983); -} -.app-nav li { - display: inline-block; - margin: 0 1rem; - padding: 5px 0; - position: relative; - cursor: pointer; -} -.app-nav li ul { - background-color: #fff; - border: 1px solid #ddd; - border-bottom-color: #ccc; - border-radius: 4px; - box-sizing: border-box; - display: none; - max-height: calc(100vh - 61px); - overflow-y: auto; - padding: 10px 0; - position: absolute; - right: -15px; - text-align: left; - top: 100%; - white-space: nowrap; -} -.app-nav li ul li { - display: block; - font-size: 14px; - line-height: 1rem; - margin: 0; - margin: 8px 14px; - white-space: nowrap; -} -.app-nav li ul a { - display: block; - font-size: inherit; - margin: 0; - padding: 0; -} -.app-nav li ul a.active { - border-bottom: 0; -} -.app-nav li:hover ul { - display: block; -} -.github-corner { - border-bottom: 0; - position: fixed; - right: 0; - text-decoration: none; - top: 0; - z-index: 1; -} -.github-corner:hover .octo-arm { - -webkit-animation: octocat-wave 560ms ease-in-out; - animation: octocat-wave 560ms ease-in-out; -} -.github-corner svg { - color: #fff; - fill: var(--theme-color, #42b983); - height: 80px; - width: 80px; -} -main { - display: block; - position: relative; - width: 100vw; - height: 100%; - z-index: 0; -} -main.hidden { - display: none; -} -.anchor { - display: inline-block; - text-decoration: none; - transition: all 0.3s; -} -.anchor span { - color: #34495e; -} -.anchor:hover { - text-decoration: underline; -} -.sidebar { - border-right: 1px solid rgba(0,0,0,0.07); - overflow-y: auto; - padding: 40px 0 0; - position: absolute; - top: 0; - bottom: 0; - left: 0; - transition: transform 250ms ease-out; - width: 300px; - z-index: 20; -} -.sidebar > h1 { - margin: 0 auto 1rem; - font-size: 1.5rem; - font-weight: 300; - text-align: center; -} -.sidebar > h1 a { - color: inherit; - text-decoration: none; -} -.sidebar > h1 .app-nav { - display: block; - position: static; -} -.sidebar .sidebar-nav { - line-height: 2em; - padding-bottom: 40px; -} -.sidebar li.collapse .app-sub-sidebar { - display: none; -} -.sidebar ul { - margin: 0 0 0 15px; - padding: 0; -} -.sidebar li > p { - font-weight: 700; - margin: 0; -} -.sidebar ul, -.sidebar ul li { - list-style: none; -} -.sidebar ul li a { - border-bottom: none; - display: block; -} -.sidebar ul li ul { - padding-left: 20px; -} -.sidebar::-webkit-scrollbar { - width: 4px; -} -.sidebar::-webkit-scrollbar-thumb { - background: transparent; - border-radius: 4px; -} -.sidebar:hover::-webkit-scrollbar-thumb { - background: rgba(136,136,136,0.4); -} -.sidebar:hover::-webkit-scrollbar-track { - background: rgba(136,136,136,0.1); -} -.sidebar-toggle { - background-color: transparent; - background-color: rgba(255,255,255,0.8); - border: 0; - outline: none; - padding: 10px; - position: absolute; - bottom: 0; - left: 0; - text-align: center; - transition: opacity 0.3s; - width: 284px; - z-index: 30; - cursor: pointer; -} -.sidebar-toggle:hover .sidebar-toggle-button { - opacity: 0.4; -} -.sidebar-toggle span { - background-color: var(--theme-color, #42b983); - display: block; - margin-bottom: 4px; - width: 16px; - height: 2px; -} -body.sticky .sidebar, -body.sticky .sidebar-toggle { - position: fixed; -} -.content { - padding-top: 60px; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 300px; - transition: left 250ms ease; -} -.markdown-section { - margin: 0 auto; - max-width: 80%; - padding: 30px 15px 40px 15px; - position: relative; -} -.markdown-section > * { - box-sizing: border-box; - font-size: inherit; -} -.markdown-section > :first-child { - margin-top: 0 !important; -} -.markdown-section hr { - border: none; - border-bottom: 1px solid #eee; - margin: 2em 0; -} -.markdown-section iframe { - border: 1px solid #eee; -/* fix horizontal overflow on iOS Safari */ - width: 1px; - min-width: 100%; -} -.markdown-section table { - border-collapse: collapse; - border-spacing: 0; - display: block; - margin-bottom: 1rem; - overflow: auto; - width: 100%; -} -.markdown-section th { - border: 1px solid #ddd; - font-weight: bold; - padding: 6px 13px; -} -.markdown-section td { - border: 1px solid #ddd; - padding: 6px 13px; -} -.markdown-section tr { - border-top: 1px solid #ccc; -} -.markdown-section tr:nth-child(2n) { - background-color: #f8f8f8; -} -.markdown-section p.tip { - background-color: #f8f8f8; - border-bottom-right-radius: 2px; - border-left: 4px solid #f66; - border-top-right-radius: 2px; - margin: 2em 0; - padding: 12px 24px 12px 30px; - position: relative; -} -.markdown-section p.tip:before { - background-color: #f66; - border-radius: 100%; - color: #fff; - content: '!'; - font-family: 'Dosis', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif; - font-size: 14px; - font-weight: bold; - left: -12px; - line-height: 20px; - position: absolute; - height: 20px; - width: 20px; - text-align: center; - top: 14px; -} -.markdown-section p.tip code { - background-color: #efefef; -} -.markdown-section p.tip em { - color: #34495e; -} -.markdown-section p.warn { - background: rgba(66,185,131,0.1); - border-radius: 2px; - padding: 1rem; -} -.markdown-section ul.task-list > li { - list-style-type: none; -} -body.close .sidebar { - transform: translateX(-300px); -} -body.close .sidebar-toggle { - width: auto; -} -body.close .content { - left: 0; -} -@media print { - .github-corner, - .sidebar-toggle, - .sidebar, - .app-nav { - display: none; - } -} -@media screen and (max-width: 768px) { - .github-corner, - .sidebar-toggle, - .sidebar { - position: fixed; - } - .app-nav { - margin-top: 16px; - } - .app-nav li ul { - top: 30px; - } - main { - height: auto; - overflow-x: hidden; - } - .sidebar { - left: -300px; - transition: transform 250ms ease-out; - } - .content { - left: 0; - max-width: 100vw; - position: static; - padding-top: 20px; - transition: transform 250ms ease; - } - .app-nav, - .github-corner { - transition: transform 250ms ease-out; - } - .sidebar-toggle { - background-color: transparent; - width: auto; - padding: 30px 30px 10px 10px; - } - body.close .sidebar { - transform: translateX(300px); - } - body.close .sidebar-toggle { - background-color: rgba(255,255,255,0.8); - transition: 1s background-color; - width: 284px; - padding: 10px; - } - body.close .content { - transform: translateX(300px); - } - body.close .app-nav, - body.close .github-corner { - display: none; - } - .github-corner:hover .octo-arm { - -webkit-animation: none; - animation: none; - } - .github-corner .octo-arm { - -webkit-animation: octocat-wave 560ms ease-in-out; - animation: octocat-wave 560ms ease-in-out; - } -} -@-webkit-keyframes octocat-wave { - 0%, 100% { - transform: rotate(0); - } - 20%, 60% { - transform: rotate(-25deg); - } - 40%, 80% { - transform: rotate(10deg); - } -} -@keyframes octocat-wave { - 0%, 100% { - transform: rotate(0); - } - 20%, 60% { - transform: rotate(-25deg); - } - 40%, 80% { - transform: rotate(10deg); - } -} -section.cover { - align-items: center; - background-position: center center; - background-repeat: no-repeat; - background-size: cover; - height: 100vh; - width: 100vw; - display: none; -} -section.cover.show { - display: flex; -} -section.cover.has-mask .mask { - background-color: #fff; - opacity: 0.8; - position: absolute; - top: 0; - height: 100%; - width: 100%; -} -section.cover .cover-main { - flex: 1; - margin: -20px 16px 0; - text-align: center; - position: relative; -} -section.cover a { - color: inherit; - text-decoration: none; -} -section.cover a:hover { - text-decoration: none; -} -section.cover p { - line-height: 1.5rem; - margin: 1em 0; -} -section.cover h1 { - color: inherit; - font-size: 2.5rem; - font-weight: 300; - margin: 0.625rem 0 2.5rem; - position: relative; - text-align: center; -} -section.cover h1 a { - display: block; -} -section.cover h1 small { - bottom: -0.4375rem; - font-size: 1rem; - position: absolute; -} -section.cover blockquote { - font-size: 1.5rem; - text-align: center; -} -section.cover ul { - line-height: 1.8; - list-style-type: none; - margin: 1em auto; - max-width: 500px; - padding: 0; -} -section.cover .cover-main > p:last-child a { - border-color: var(--theme-color, #42b983); - border-radius: 2rem; - border-style: solid; - border-width: 1px; - box-sizing: border-box; - color: var(--theme-color, #42b983); - display: inline-block; - font-size: 1.05rem; - letter-spacing: 0.1rem; - margin: 0.5rem 1rem; - padding: 0.75em 2rem; - text-decoration: none; - transition: all 0.15s ease; -} -section.cover .cover-main > p:last-child a:last-child { - background-color: var(--theme-color, #42b983); - color: #fff; -} -section.cover .cover-main > p:last-child a:last-child:hover { - color: inherit; - opacity: 0.8; -} -section.cover .cover-main > p:last-child a:hover { - color: inherit; -} -section.cover blockquote > p > a { - border-bottom: 2px solid var(--theme-color, #42b983); - transition: color 0.3s; -} -section.cover blockquote > p > a:hover { - color: var(--theme-color, #42b983); -} -body { - background-color: #fff; -} -/* sidebar */ -.sidebar { - background-color: #fff; - color: #364149; -} -.sidebar li { - margin: 6px 0 6px 0; -} -.sidebar ul li a { - color: #505d6b; - font-size: 14px; - font-weight: normal; - overflow: hidden; - text-decoration: none; - text-overflow: ellipsis; - white-space: nowrap; -} -.sidebar ul li a:hover { - text-decoration: underline; -} -.sidebar ul li ul { - padding: 0; -} -.sidebar ul li.active > a { - border-right: 2px solid; - color: var(--theme-color, #42b983); - font-weight: 600; -} -.app-sub-sidebar li::before { - content: '-'; - padding-right: 4px; - float: left; -} -/* markdown content found on pages */ -.markdown-section h1, -.markdown-section h2, -.markdown-section h3, -.markdown-section h4, -.markdown-section strong { - color: #2c3e50; - font-weight: 600; -} -.markdown-section a { - color: var(--theme-color, #42b983); - font-weight: 600; -} -.markdown-section h1 { - font-size: 2rem; - margin: 0 0 1rem; -} -.markdown-section h2 { - font-size: 1.75rem; - margin: 45px 0 0.8rem; -} -.markdown-section h3 { - font-size: 1.5rem; - margin: 40px 0 0.6rem; -} -.markdown-section h4 { - font-size: 1.25rem; -} -.markdown-section h5 { - font-size: 1rem; -} -.markdown-section h6 { - color: #777; - font-size: 1rem; -} -.markdown-section figure, -.markdown-section p { - margin: 1.2em 0; -} -.markdown-section p, -.markdown-section ul, -.markdown-section ol { - line-height: 1.6rem; - word-spacing: 0.05rem; -} -.markdown-section ul, -.markdown-section ol { - padding-left: 1.5rem; -} -.markdown-section blockquote { - border-left: 4px solid var(--theme-color, #42b983); - color: #858585; - margin: 2em 0; - padding-left: 20px; -} -.markdown-section blockquote p { - font-weight: 600; - margin-left: 0; -} -.markdown-section iframe { - margin: 1em 0; -} -.markdown-section em { - color: #7f8c8d; -} -.markdown-section code { - background-color: #f8f8f8; - border-radius: 2px; - color: #e96900; - font-family: 'Roboto Mono', Monaco, courier, monospace; - font-size: 0.8rem; - margin: 0 2px; - padding: 3px 5px; - white-space: pre-wrap; -} -.markdown-section pre { - -moz-osx-font-smoothing: initial; - -webkit-font-smoothing: initial; - background-color: #f8f8f8; - font-family: 'Roboto Mono', Monaco, courier, monospace; - line-height: 1.5rem; - margin: 1.2em 0; - overflow: auto; - padding: 0 1.4rem; - position: relative; - word-wrap: normal; -} -/* code highlight */ -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: #8e908c; -} -.token.namespace { - opacity: 0.7; -} -.token.boolean, -.token.number { - color: #c76b29; -} -.token.punctuation { - color: #525252; -} -.token.property { - color: #c08b30; -} -.token.tag { - color: #2973b7; -} -.token.string { - color: var(--theme-color, #42b983); -} -.token.selector { - color: #6679cc; -} -.token.attr-name { - color: #2973b7; -} -.token.entity, -.token.url, -.language-css .token.string, -.style .token.string { - color: #22a2c9; -} -.token.attr-value, -.token.control, -.token.directive, -.token.unit { - color: var(--theme-color, #42b983); -} -.token.keyword, -.token.function { - color: #e96900; -} -.token.statement, -.token.regex, -.token.atrule { - color: #22a2c9; -} -.token.placeholder, -.token.variable { - color: #3d8fd1; -} -.token.deleted { - text-decoration: line-through; -} -.token.inserted { - border-bottom: 1px dotted #202746; - text-decoration: none; -} -.token.italic { - font-style: italic; -} -.token.important, -.token.bold { - font-weight: bold; -} -.token.important { - color: #c94922; -} -.token.entity { - cursor: help; -} -.markdown-section pre > code { - -moz-osx-font-smoothing: initial; - -webkit-font-smoothing: initial; - background-color: #f8f8f8; - border-radius: 2px; - color: #525252; - display: block; - font-family: 'Roboto Mono', Monaco, courier, monospace; - font-size: 0.8rem; - line-height: inherit; - margin: 0 2px; - max-width: inherit; - overflow: inherit; - padding: 2.2em 5px; - white-space: inherit; -} -.markdown-section code::after, -.markdown-section code::before { - letter-spacing: 0.05rem; -} -code .token { - -moz-osx-font-smoothing: initial; - -webkit-font-smoothing: initial; - min-height: 1.5rem; - position: relative; - left: auto; -} -pre::after { - color: #ccc; - content: attr(data-lang); - font-size: 0.6rem; - font-weight: 600; - height: 15px; - line-height: 15px; - padding: 5px 10px 0; - position: absolute; - right: 0; - text-align: right; - top: 0; -} diff --git a/old/config b/config similarity index 100% rename from old/config rename to config diff --git a/docs/Algorithm/DataStructure/C++/README.md b/docs/Algorithm/DataStructure/C++/README.md new file mode 100755 index 00000000..6889eed1 --- /dev/null +++ b/docs/Algorithm/DataStructure/C++/README.md @@ -0,0 +1,5 @@ +# Some algorithm templates for better understanding! + +> [八大排序算法 集合](/docs/Algorithm/Sort) + +![](/images/SortingAlgorithm/八大排序算法性能.png) diff --git a/.nojekyll b/docs/Algorithm/DataStructure/Java/Cipher/README.md old mode 100644 new mode 100755 similarity index 100% rename from .nojekyll rename to docs/Algorithm/DataStructure/Java/Cipher/README.md diff --git a/img/Algorithm/LeetCode/005/1.md b/docs/Algorithm/DataStructure/Java/Compression/README.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/005/1.md rename to docs/Algorithm/DataStructure/Java/Compression/README.md diff --git a/docs/Algorithm/DataStructure/Java/Conversion/README.md b/docs/Algorithm/DataStructure/Java/Conversion/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/Graph/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/Graph/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/Graph/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/HashMap/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/HashMap/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/HashMap/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/HashTable/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/HashTable/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/HashTable/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/Heqp/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/Heqp/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/Heqp/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/LinkedList/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/LinkedList/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/LinkedList/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/Matrix/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/Matrix/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/Matrix/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/Queue/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/Queue/README.md new file mode 100755 index 00000000..2259b95a --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/Queue/README.md @@ -0,0 +1,2 @@ +## Queue Implementation + diff --git a/img/Algorithm/LeetCode/011/1.md b/docs/Algorithm/DataStructure/Java/Data_Structure/README.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/011/1.md rename to docs/Algorithm/DataStructure/Java/Data_Structure/README.md diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/Stack/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/Stack/README.md new file mode 100755 index 00000000..a381eb91 --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/Stack/README.md @@ -0,0 +1,65 @@ +## Stack Implementation + +### Stack using Array + +```java +public class Stack { + + private int[] nums; + private int size; + private int top; # 栈顶位置 + + private Stack(int size) { + this.size = size; + this.nums = new int[size]; + this.top = -1; + } + + private boolean isFull() { + return this.top == this.size - 1; + } + + public boolean push(int num) { + if(isFull()) { + System.out.println("the stack is full!"); + return false; + } else { + this.top++; + this.nums[this.top] = num; + return true; + } + } + + public int peek() { + return this.nums[this.top]; + } + + public int pop() throws Exception { + if(empty()) { + throw new Exception("the stack is empty!"); + } else { + return this.nums[this.top--]; + } + } + + public boolean empty() { + return this.top == -1; + } + + public static void main(String[] args) { + Stack stack = new Stack(20); + for (int i = 0; i < 10; i++) { + stack.push(i); + } + System.out.println("Now the peek num is:" + stack.peek()); + + while(!stack.empty()) { + try { + System.out.println(stack.pop()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} +``` diff --git a/docs/Algorithm/DataStructure/Java/Data_Structure/Tree/README.md b/docs/Algorithm/DataStructure/Java/Data_Structure/Tree/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Data_Structure/Tree/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Java/Dynamic_Programming/README.md b/docs/Algorithm/DataStructure/Java/Dynamic_Programming/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/Java/Hash/README.md b/docs/Algorithm/DataStructure/Java/Hash/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/Others/NextNodeInOrderTree.md b/docs/Algorithm/DataStructure/Java/Others/NextNodeInOrderTree.md old mode 100644 new mode 100755 similarity index 100% rename from docs/Algorithm/DataStructure/Others/NextNodeInOrderTree.md rename to docs/Algorithm/DataStructure/Java/Others/NextNodeInOrderTree.md diff --git a/docs/Algorithm/DataStructure/Others/TopKWords.java b/docs/Algorithm/DataStructure/Java/Others/TopKWords.java old mode 100644 new mode 100755 similarity index 100% rename from docs/Algorithm/DataStructure/Others/TopKWords.java rename to docs/Algorithm/DataStructure/Java/Others/TopKWords.java diff --git a/docs/Algorithm/DataStructure/Others/words.txt b/docs/Algorithm/DataStructure/Java/Others/words.txt old mode 100644 new mode 100755 similarity index 100% rename from docs/Algorithm/DataStructure/Others/words.txt rename to docs/Algorithm/DataStructure/Java/Others/words.txt diff --git a/docs/Algorithm/DataStructure/Java/README.md b/docs/Algorithm/DataStructure/Java/README.md new file mode 100755 index 00000000..ed14f53a --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/README.md @@ -0,0 +1,2 @@ +# Some algorithm templates for better understanding! + diff --git a/docs/Algorithm/DataStructure/Java/Search/README.md b/docs/Algorithm/DataStructure/Java/Search/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/Java/Sort/README.md b/docs/Algorithm/DataStructure/Java/Sort/README.md new file mode 100755 index 00000000..7f01a8d7 --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Sort/README.md @@ -0,0 +1,13 @@ +# 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/src/py3.x/sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/src/py3.x/sort/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/src/py3.x/sort/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/src/py3.x/sort/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/src/py3.x/sort/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/src/py3.x/sort/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | [RadixSort.py](/src/py3.x/sort/RadixSort.py) | diff --git a/docs/Algorithm/DataStructure/Java/Sort/Sort.ipynb b/docs/Algorithm/DataStructure/Java/Sort/Sort.ipynb new file mode 100755 index 00000000..a38ab891 --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Sort/Sort.ipynb @@ -0,0 +1,772 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 排序算法\n", + "\n", + "## 1、冒泡排序(Bubble Sort)\n", + "\n", + "### 1.1、简介\n", + "\n", + "冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们两个的顺序错误就把它们两个交换。走访数列的工作是重复的,直到最后没有再需要交换,也就是说该数列已经排序完成了。这个算法的名字由来是因为越小的元素会经由交换慢慢 \"浮\" 到数列的顶端。\n", + "\n", + "### 1.2、算法描述\n", + "\n", + " - 比较相邻的元素。如果第一个比第二个大,就交换它们两个;\n", + " - 对每一组相邻元素做相同的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;\n", + " - 针对所有的元素重复以上的步骤,除了最后一个;\n", + " - 重复步骤 1~3 ,直到排序完成。\n", + " \n", + "### 1.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/BubbleSort_1.gif)\n", + "\n", + "### 1.4、代码实现" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "def bubble_sort(nums):\n", + " # 外层循环负责设置冒泡排序进行的次数\n", + " for i in range(len(nums)-1):\n", + " # 内层循环负责前后两两比较,求最大值放到最后\n", + " # j 为列表下标\n", + " for j in range(len(nums)-1-i):\n", + " # 如果相互比较的两个数,前一个数比后一个数大\n", + " if nums[j] > nums[j+1]:\n", + " nums[j], nums[j+1] = nums[j+1], nums[j]\n", + " return nums\n", + "\n", + "if __name__ == \"__main__\":\n", + " nums = [5, 1, 9, 3, 2, 7]\n", + " bubble_sort(nums)\n", + " print(nums)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.5、代码优化\n", + "\n", + "#### 1.5.1、优化 1\n", + "\n", + "如果上面代码中,里面一层循环在某次扫描中没有执行交换,则说明此时数组已经全部有序了,无需再进行扫描。因此,我们增加一个标记,每次发生交换,用来标记,如果某次循环完没有标记,则说明已经完成排序。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "# 改进版的冒泡排序_1\n", + "def bubble_sort_2(nums):\n", + " # 外层循环负责设置冒泡排序进行的次数\n", + " for i in range(len(nums)-1):\n", + " # 标记是否已经完成排序\n", + " swaped = False\n", + " # 内层循环负责前后两两比较,求最大值放到最后,j 为列表下标\n", + " for j in range(len(nums)-1-i):\n", + " # 如果相互比较的两个数,前一个数比后一个数大\n", + " if nums[j] > nums[j+1]:\n", + " nums[j], nums[j+1] = nums[j+1], nums[j]\n", + " swaped = True\n", + " # 如果上一次扫描没有发生交换,说明数组已经全部都排好序了,那我们就退出循环\n", + " if not swaped:\n", + " break\n", + " return nums\n", + "\n", + "if __name__ == \"__main__\":\n", + " nums = [5, 1, 9, 3, 2, 7]\n", + " bubble_sort_2(nums)\n", + " print(nums)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "#### 1.5.2、优化 2\n", + "\n", + "在我们第一步优化的基础上,我们可以进一步思考:如果 R[0 ~ i] 已是有序区间,上次扫描的区间是 R[i ~ n],记上次扫描时最后一次执行交换的位置为 lastSwapPos,则 lastSwapPos 在 i 与 n 之间,不难发现 R[i ~ lastSwapPos] 区间也是有序的,否则这个区间也会发生变换;所以下次扫描区间就可以由 R[i ~ n] 缩减到 R[lastSwapPos ~ n] 。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "# 改进版的冒泡排序_2\n", + "def bubble_sort_3(nums):\n", + " lastSwapPos = 0\n", + " lastSwapPosTemp = 0\n", + " # 外层循环负责设置冒泡排序进行的次数\n", + " for i in range(len(nums)-1):\n", + " lastSwapPos = lastSwapPosTemp\n", + " # 内层循环负责前后两两比较,求最大值放到最后,j 为列表下标\n", + " for j in range(len(nums)-1-i):\n", + " # 如果相互比较的两个数,前一个数比后一个数大\n", + " if nums[j] > nums[j+1]:\n", + " nums[j], nums[j+1] = nums[j+1], nums[j]\n", + " # 记录最后一次发生交换的位置\n", + " lastSwapPosTemp = j\n", + " # 如果上一次扫描没有发生交换,说明数组已经全部都排好序了,那我们就退出循环\n", + " if lastSwapPos == lastSwapPosTemp:\n", + " break\n", + " return nums\n", + "\n", + "if __name__ == \"__main__\":\n", + " nums = [5, 1, 9, 3, 2, 7]\n", + " bubble_sort_3(nums)\n", + " print(nums)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2、插入排序(Insert Sort)\n", + "\n", + "### 2.1、简介\n", + "\n", + "插入排序(insert sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。\n", + "\n", + "### 2.2、算法描述\n", + "\n", + "一般来说,插入排序都采用 in-place 在数组上实现。具体算法描述如下:\n", + "\n", + " - 从第一个元素开始,该元素可以认为已经被排序;\n", + " - 取出下一个元素,在已经排序的元素序列中从后向前扫描;\n", + " - 如果该元素(已排序)大于新元素,将该元素移到下一个位置;\n", + " - 重复步骤 3 ,直到找到已排序的元素小于或者等于新元素的位置;\n", + " - 将新元素插入到该位置后;\n", + " - 重复步骤 2 ~ 5\n", + " \n", + "### 2.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/InsertSort_1.gif)\n", + "\n", + "### 2.4、代码实现\n", + "\n", + "插入排序和冒泡排序的区别在于:\n", + "\n", + " - 插入排序的前提是:左边是有序的数列\n", + " - 冒泡排序:相邻的值进行交换,一共进行 n 次" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 1, 9, 3, 2, 7]\n", + "[5]\n", + "[1, 5]\n", + "[1, 5, 9]\n", + "[1, 3, 5, 9]\n", + "[1, 2, 3, 5, 9]\n", + "result: [1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "def insert_sort(nums):\n", + " # 循环 除第一个数字组成的有序数组 以外的数字\n", + " for i in range(1, len(nums)):\n", + " # 每一个数字,依次和有序数组进行比较\n", + " print(nums[:i])\n", + " for j in range(len(nums[:i])):\n", + " if nums[i] < nums[j]:\n", + " nums[i], nums[j] = nums[j], nums[i]\n", + " \n", + "if __name__ == \"__main__\":\n", + " l = [5, 1, 9, 3, 2, 7]\n", + " print(l)\n", + " insert_sort(l)\n", + " print(\"result: \" + str(l))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3、选择排序(SelectionSort)\n", + "\n", + "### 3.1、简介\n", + "\n", + "选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 \n", + "\n", + "### 3.2、算法描述\n", + "\n", + "n 个记录的直接选择排序可经过 n-1 趟直接选择排序得到有序结果。具体算法描述如下:\n", + "\n", + " - 初始状态:无序区为 R[1 ... n],有序区为空;\n", + " - 第 i 趟排序 (i = 1, 2, 3, ... n-1) 开始时,当前有序区和无序区分别为 R[1 ... i-1] 和 R[i ... n]。该趟排序从当前无序区中 —— 选出关键字最小的记录 R[k],将它与无序区的第 1 个记录 R 交换,使 R[1 ... i] 和 R[i+1 ... n] 分别变为记录个数增加 1 个的新有序区和记录个数减少 1 个的新无序区;\n", + " - n-1 趟结束,数组有序化了。\n", + " \n", + "### 3.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/SelectionSort_1.gif)\n", + "\n", + "### 3.4、代码实现\n", + "\n", + "选择排序和冒泡排序的区别在于:\n", + "\n", + "选择排序的前提是:找到最大值的位置,最后才进行 1 次交换;\n", + "而冒泡排序是:相邻的值进行交换,一共进行 n 次交换" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 1, 9, 3, 2, 7]\n", + "1 [5, 1, 7, 3, 2, 9]\n", + "2 [5, 1, 2, 3, 7, 9]\n", + "3 [3, 1, 2, 5, 7, 9]\n", + "4 [2, 1, 3, 5, 7, 9]\n", + "5 [1, 2, 3, 5, 7, 9]\n", + "result: [1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "def selection_sort(nums):\n", + " length = len(nums) - 1\n", + "\n", + " while length:\n", + " index = length\n", + " # 第一个数字,和后面每一个数字进行对比,找出最大值,放到最后!!\n", + " for j in range(length):\n", + " if nums[j] > nums[index]:\n", + " index = j\n", + " nums[length], nums[index] = nums[index], nums[length]\n", + " print(len(nums) - length, nums)\n", + " length -= 1\n", + " \n", + "if __name__ == \"__main__\":\n", + " nums = [5, 1, 9, 3, 2, 7]\n", + " print(nums)\n", + " selection_sort(nums)\n", + " print(\"result: \" + str(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4、快速排序(Quick Sort)\n", + "\n", + "### 4.1、简介\n", + "\n", + "快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。\n", + "\n", + "### 4.2、算法描述\n", + "\n", + "快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:\n", + "\n", + " - 从数列中挑出一个元素,称为 \"基准\"(pivot)\n", + " - 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出后,该基准就处于数列的中间位置。这个称为分区(partition)操作;\n", + " - 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。\n", + " \n", + "### 4.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/QuickSort_1.gif)\n", + "\n", + "### 4.4、代码实现" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 7 ******************************\n", + "5 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "5 1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "5 9 ******************************\n", + "5 3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "2 3 ******************************\n", + "2 1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "9 7 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "def quick_sort(nums, start, end):\n", + " i = start\n", + " j = end\n", + " # 结束排序\n", + " if i >= j:\n", + " return\n", + " # 保存首个数值\n", + " key = nums[i]\n", + " # 一次排序,i和j的值不断的靠拢,然后最终停止,结束一次排序\n", + " while i < j:\n", + " # 和最右边的比较,如果值 >=key,然后j-1,慢慢的和前一个值比较;如果值key,那么就交换位置\n", + " while i < j and key >= nums[i]:\n", + " print(key, nums[i], '%' * 30)\n", + " i += 1\n", + " nums[j] = nums[i]\n", + " nums[i] = key\n", + " # 左边排序\n", + " quick_sort(nums, start, j-1)\n", + " # 右边排序\n", + " quick_sort(nums, i+1, end)\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " l = [5, 1, 9, 3, 2, 7]\n", + " quick_sort(l, 0, len(l) - 1)\n", + " print(l)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5、希尔排序(ShellSort)\n", + "\n", + "### 5.1、简介\n", + "\n", + "希尔排序(Shell Sort)也是插入排序的一种。也称为缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。\n", + "\n", + "1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会 **优先比较距离较远的元素。希尔排序又叫缩小增量排序。**\n", + "\n", + "### 5.2、算法描述\n", + "\n", + "先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:\n", + "\n", + " - 选择一个增量序列 $t_1, t_2, …, t_k$ ,其中 $t_i>t_j, t_k=1$ ;\n", + " - 按增量序列个数 k,对序列进行 k 趟排序;\n", + " - 每趟排序,根据对应的增量 $t_i$,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。\n", + " \n", + "**补充描述:**\n", + " \n", + "是不是有些不明白呢?那我们用通俗一些的语句来说。\n", + "\n", + "直接插入排序在在本身数量比较少的时候情况下效率很高,如果待排数的数量很多,其效率不是很理想。\n", + "\n", + "  回想一下直接插入排序过程,排序过程中,我们可以设置一条线,左边是排好序的,右边则是一个一个等待排序,\n", + "\n", + "如果最小的那个值在最右边,那么排这个最小值的时候,需要将所有元素向右边移动一位。\n", + "\n", + "  是否能够减少这样的移位呢?\n", + "\n", + "  我们不希望它是一步一步的移动,而是大步大步的移动。希尔排序就被发明出来了,它也是当时打破效率\n", + "\n", + "O(n2)的算法之一。希尔排序算法通过设置一个间隔,对同样间隔的数的集合进行插入排序,此数集合中的元素\n", + "\n", + "移位的长度是以间隔的长度为准,这样就实现了大步位移。但是最后需要对元素集合进行一次直接插入排序,所以\n", + "\n", + "最后的间隔一定是1。\n", + "\n", + "下面举一个例子:\n", + "\n", + "第一趟希尔排序,间隔为4\n", + "\n", + "![](/images/SortingAlgorithm/ShellSort_2.png)\n", + "\n", + "第二趟排序:间隔为 2\n", + "\n", + "![](/images/SortingAlgorithm/ShellSort_3.png)\n", + "\n", + "第三趟排序,间隔为 1,即 直接插入排序法(InsertSort):\n", + "\n", + "具体的插入排序过程,这里我们就不再详细说了。\n", + "\n", + "```\n", + "减小间隔:\n", + "\n", + "上面已经演示了以4为初始间隔对包含10个数据项的数组进行排序的情况。对于更大的数组开始的间隔也应该更大。然后间隔不断减小,直到间隔变成1。\n", + "\n", + "举例来说,含有1000个数据项的数组可能先以364为增量,然后以121为增量,以40为增量,以13为增量,以4为增量,最后以 1为增量进行希尔排序。用来形成间隔的数列被称为间隔序列。这里所表示的间隔序列由Knuth提出,此序列是很常用的。数列以逆向形式从1开始,通过递归表达式\n", + "\n", + "h = 3 * b + 1\n", + "\n", + "来产生,初始值为 1 。\n", + "\n", + "在排序算法中,首先在一个短小的循环中使用序列的生成公式来计算出最初的间隔。h值最初被赋为1,然后应用公式h=3*h+1生成序列1,4,13,40,121,364,等等。当间隔大于数组大小的时候,这个过程停止。对于一个含有1000个数据项的数组,序列的第七个数字,1093就太大了。因此,使用序列的第六个数字作为最大的数字来开始这个排序过程,作364-增量排序。然后,每完成一次排序全程的外部循环,用前面提供的此公式倒推式来减小间隔:\n", + "\n", + "h=(h-1)/3\n", + "\n", + "这个倒推的公式生成逆置的序列364,121,40,13,4,1。从364开始,以每一个数字作为增量进行排序。当数组用1-增量排序后,算法结束。\n", + "\n", + "希尔排序比插入排序快很多,它是基于什么原因呢?当h值大的时候,数据项每一趟排序需要移动元素的个数很少,但数据项移动的距离很长。这是非常有效率的。当h减小时,每一趟排序需要移动的元素的个数增多,但是此时数据项已经接近于它们排序后最终的位置,这对于插入排序可以更有效率。正是这两种情况的结合才使希尔排序效率那么高。\n", + "\n", + "注意后期的排序过程不撤销前期排序所做的工作。例如,已经完成了以40-增量的排序的数组,在经过以13-增量的排序后仍然保持了以40-增量的排序的结果。如果不是这样的话,希尔排序就无法实现排序的目的。\n", + "```\n", + " \n", + "### 5.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/ShellSort_1.gif)\n", + "\n", + "再附加一个静态图:\n", + "\n", + "![](/images/SortingAlgorithm/ShellSort_4.png)\n", + "\n", + "### 5.4、代码实现" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "开始 [5, 2, 9, 8, 1, 10, 3, 4, 7]\n", + "3 -- [3, 2, 9, 5, 1, 10, 8, 4, 7]\n", + "3 -- [3, 1, 9, 5, 2, 10, 8, 4, 7]\n", + "3 -- [3, 1, 7, 5, 2, 9, 8, 4, 10]\n", + "2 -- [2, 1, 3, 5, 7, 9, 8, 4, 10]\n", + "2 -- [2, 1, 3, 4, 7, 5, 8, 9, 10]\n", + "1 -- [1, 2, 3, 4, 5, 7, 8, 9, 10]\n", + "结束 [1, 2, 3, 4, 5, 7, 8, 9, 10]\n" + ] + } + ], + "source": [ + "# 直接插入排序\n", + "def insert_sort(nums, start, increment):\n", + " for i in range(start+increment, len(nums), increment):\n", + " for j in range(start, len(nums[:i]), increment):\n", + " if nums[i] < nums[j]:\n", + " nums[i], nums[j] = nums[j], nums[i]\n", + " print(increment, '--', nums)\n", + " return nums\n", + "\n", + "# 希尔排序\n", + "def shell_sort(nums, increment):\n", + " # 依次进行分层\n", + " while increment:\n", + " # 每一层,都进行n次插入排序\n", + " for i in range(0, increment):\n", + " insert_sort(nums, i, increment)\n", + " increment -= 1\n", + " return nums\n", + "\n", + "if __name__ == \"__main__\":\n", + " l = [5, 2, 9, 8, 1, 10, 3, 4, 7]\n", + " increment = int(len(l)/3)+1 if len(l)%3 else int(len(l)/3)\n", + " print(\"开始\", l)\n", + " l = shell_sort(l, increment)\n", + " print(\"结束\", l)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6、归并排序(MergeSort)\n", + "\n", + "### 6.1、简介\n", + "\n", + "归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。\n", + "\n", + "### 6.2、算法描述\n", + "\n", + " - 把长度为 n 的输入序列分成两个长度为 n/2 的子序列;\n", + " - 对这两个子序列分别采用归并排序;\n", + " - 将两个排序好的子序列合并成一个最终的排序序列。\n", + " \n", + "### 6.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/MergeSort_1.gif)\n", + "\n", + "### 6.4、代码实现\n", + "\n", + "归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1]\n", + "********************\n", + "[2]\n", + "____________________\n", + "result: [1, 2]\n", + "[4]\n", + "********************\n", + "[5]\n", + "____________________\n", + "result: [4, 5]\n", + "[3]\n", + "********************\n", + "[4, 5]\n", + "____________________\n", + "result: [3, 4, 5]\n", + "[1, 2]\n", + "********************\n", + "[3, 4, 5]\n", + "____________________\n", + "result: [1, 2, 3, 4, 5]\n", + "[7]\n", + "********************\n", + "[90]\n", + "____________________\n", + "result: [7, 90]\n", + "[6]\n", + "********************\n", + "[7, 90]\n", + "____________________\n", + "result: [6, 7, 90]\n", + "[23]\n", + "********************\n", + "[45]\n", + "____________________\n", + "result: [23, 45]\n", + "[21]\n", + "********************\n", + "[23, 45]\n", + "____________________\n", + "result: [21, 23, 45]\n", + "[6, 7, 90]\n", + "********************\n", + "[21, 23, 45]\n", + "____________________\n", + "result: [6, 7, 21, 23, 45, 90]\n", + "[1, 2, 3, 4, 5]\n", + "********************\n", + "[6, 7, 21, 23, 45, 90]\n", + "____________________\n", + "result: [1, 2, 3, 4, 5, 6, 7, 21, 23, 45, 90]\n", + "[1, 2, 3, 4, 5, 6, 7, 21, 23, 45, 90]\n" + ] + } + ], + "source": [ + "def MergeSort(lists):\n", + " if len(lists) <= 1:\n", + " return lists\n", + " num = int(len(lists) / 2)\n", + " # 从中间,进行数据的拆分, 递归的返回数据进行迭代排序\n", + " left = MergeSort(lists[:num])\n", + " right = MergeSort(lists[num:])\n", + " print(left)\n", + " print(\"*\" * 20)\n", + " print(right)\n", + " print(\"_\" * 20)\n", + " return Merge(left, right)\n", + "\n", + "# 将 2 个已经排好序的子序列合并成一个序列,也就是 2-路归并\n", + "def Merge(left, right):\n", + " r, l = 0, 0\n", + " result = []\n", + " # 这里将两个序列中的每个值都比较一下,最小的放到最左边\n", + " while l < len(left) and r < len(right):\n", + " if left[l] < right[r]:\n", + " result.append(left[l])\n", + " l += 1\n", + " else:\n", + " result.append(right[r])\n", + " r += 1\n", + " result += right[r:]\n", + " result += left[l:]\n", + " print('result:', result)\n", + " # 最终将合并好的完整序列返回\n", + " return result\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " print(MergeSort([1, 2, 3, 4, 5, 6, 7, 90, 21, 23, 45]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7、基数排序\n", + "\n", + "### 7.1、简介\n", + "\n", + "以十进制为例,基数指的是数的位,如个位,十位百位等。而以十六进制为例,0xB2,就有两个radices(radix的复数)。\n", + "\n", + "基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。\n", + "\n", + "### 7.2、算法描述\n", + "\n", + " - 取得数组中的最大数,并取得位数;\n", + " - arr 为原始数组,从最低位开始取每个位组成 radix 数组;\n", + " - 对 radix 进行计数排序(利用计数排序适用于小范围数的特点)\n", + " \n", + "**补充描述:**\n", + "\n", + "基数排序不同于其他的排序算法,它不是基于比较的算法。基数排序是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法。它是一种稳定的排序算法。多关键字排序中有两种方法:最高位优先法(MSD)和最低位优先法(LSD)。通常用于对数的排序选择的是最低位优先法,即先对最次位关键字进行排序,再对高一位的关键字进行排序,以此类推。\n", + "\n", + "算法的思想:类似于桶式排序,我们需要给待排序记录准备10个桶,为什么是10个??因为一个数的任何一位上,其数字大小都位于0~9之间,因此采用10个桶,桶的编号分别为0,1,2,3,4...9,对应待排序记录中每个数相应位的数值,基数排序也是因此而得名。我们先根据待排序记录的每个数的个位来决定让其加入哪个桶中。例如:待排序数组为\n", + "\n", + "278 109 63 930 589 184 505 269 8 83\n", + "\n", + "求取每个数的个位数,依次为:8 9 3 0 9 4 5 9 8 3\n", + "\n", + "依照其个位数决定将其加入哪个桶中\n", + "\n", + "![](/images/SortingAlgorithm/RadixSort_2.png)\n", + " \n", + "### 7.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/RadixSort_1.gif)\n", + "\n", + "### 7.4、代码实现\n", + "\n", + "基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要 $O(n)$ 的时间复杂度,而且分配之后得到新的关键字序列又需要 $O(n)$ 的时间复杂度。假如待排数据可以分为 $d$ 个关键字,则基数排序的时间复杂度将是 $O(d*2n)$ ,当然 $d$ 要远远小于 $n$ ,因此基本上还是线性级别的。\n", + "\n", + "基数排序的空间复杂度为 $O(n+k)$ ,其中 $k$ 为桶的数量。一般来说 $n>>k$ ,因此额外空间需要大概 $n$ 个左右。" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "# ************************基数排序****************************\n", + "# 确定排序的次数\n", + "# 排序的顺序跟序列中最大数的位数相关\n", + "def radix_sort_nums(L):\n", + " maxNum = L[0]\n", + " #寻找序列中的最大数\n", + " for x in L:\n", + " if maxNum < x:\n", + " maxNum = x\n", + " # 确定序列中的最大元素的位数\n", + " times = 0\n", + " while (maxNum > 0):\n", + " maxNum = int((maxNum/10))\n", + " times += 1\n", + " return times\n", + "\n", + "# 找到num从低到高第pos位的数据\n", + "def get_num_pos(num, pos):\n", + " return (int((num/(10**(pos-1))))) % 10\n", + "\n", + "# 基数排序\n", + "def radix_sort(L):\n", + " count = 10 * [None] # 存放各个桶的数据统计个数\n", + " bucket = len(L) * [None] # 暂时存放排序结果\n", + " # 从低位到高位依次执行循环\n", + " for pos in range(1, radix_sort_nums(L)+1):\n", + " # 置空各个桶的数据统计\n", + " for x in range(0, 10):\n", + " count[x] = 0\n", + " # 统计当前该位(个位,十位,百位....)的元素数目\n", + " for x in range(0, len(L)):\n", + " # 统计各个桶将要装进去的元素个数\n", + " j = get_num_pos(int(L[x]), pos)\n", + " count[j] += 1\n", + " # count[i]表示第i个桶的右边界索引\n", + " for x in range(1,10):\n", + " count[x] += count[x-1]\n", + " # 将数据依次装入桶中\n", + " for x in range(len(L)-1, -1, -1):\n", + " # 求出元素第K位的数字\n", + " j = get_num_pos(L[x], pos)\n", + " # 放入对应的桶中,count[j]-1是第j个桶的右边界索引\n", + " bucket[count[j]-1] = L[x]\n", + " # 对应桶的装入数据索引-1\n", + " count[j] -= 1\n", + " # 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表\n", + " for x in range(0, len(L)):\n", + " L[x] = bucket[x]\n", + " \n", + "if __name__ == \"__main__\":\n", + " l = [5, 1, 9, 3, 2, 7]\n", + " radix_sort(l)\n", + " print(l)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/DataStructure/Java/Sort/insertionSort.py b/docs/Algorithm/DataStructure/Java/Sort/insertionSort.py new file mode 100755 index 00000000..29f975d7 --- /dev/null +++ b/docs/Algorithm/DataStructure/Java/Sort/insertionSort.py @@ -0,0 +1,16 @@ +def insertionSort(nums): + if not nums or len(nums) < 2: + return nums + + for i in range(1, len(nums)): + for j in range(i): + if nums[i] < nums[j]: + nums[i], nums[j] = nums[j], nums[i] + return nums + + +if __name__ == "__main__": + nums = [5, 1, 9, 3, 2, 7] + print('input: ', nums) + nums = insertionSort(nums) + print("result: ", nums) diff --git "a/docs/Algorithm/DataStructure/Java/Sort/\346\216\222\345\272\217\347\250\263\345\256\232\346\200\247.md" "b/docs/Algorithm/DataStructure/Java/Sort/\346\216\222\345\272\217\347\250\263\345\256\232\346\200\247.md" new file mode 100755 index 00000000..08b1c964 --- /dev/null +++ "b/docs/Algorithm/DataStructure/Java/Sort/\346\216\222\345\272\217\347\250\263\345\256\232\346\200\247.md" @@ -0,0 +1 @@ +https://baike.baidu.com/item/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%E7%A8%B3%E5%AE%9A%E6%80%A7 diff --git a/docs/Algorithm/DataStructure/Java/Traversals/README.md b/docs/Algorithm/DataStructure/Java/Traversals/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/JavaScript.md b/docs/Algorithm/DataStructure/JavaScript/README.md old mode 100644 new mode 100755 similarity index 100% rename from docs/Algorithm/DataStructure/JavaScript.md rename to docs/Algorithm/DataStructure/JavaScript/README.md diff --git a/docs/Algorithm/DataStructure/Python/Cipher/README.md b/docs/Algorithm/DataStructure/Python/Cipher/README.md new file mode 100755 index 00000000..e69de29b diff --git a/img/Algorithm/LeetCode/033/1.md b/docs/Algorithm/DataStructure/Python/Compression/README.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/033/1.md rename to docs/Algorithm/DataStructure/Python/Compression/README.md diff --git a/docs/Algorithm/DataStructure/Python/Conversion/README.md b/docs/Algorithm/DataStructure/Python/Conversion/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/Python/Data_Structure/Graph/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/Graph/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Data_Structure/Graph/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Python/Data_Structure/HashMap/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/HashMap/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Data_Structure/HashMap/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Python/Data_Structure/HashTable/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/HashTable/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Data_Structure/HashTable/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Python/Data_Structure/Heqp/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/Heqp/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Data_Structure/Heqp/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Python/Data_Structure/LinkedList/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/LinkedList/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Data_Structure/LinkedList/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Python/Data_Structure/Matrix/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/Matrix/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Data_Structure/Matrix/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Queue/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/Queue/README.md old mode 100644 new mode 100755 similarity index 100% rename from docs/Algorithm/DataStructure/Queue/README.md rename to docs/Algorithm/DataStructure/Python/Data_Structure/Queue/README.md diff --git a/img/Algorithm/LeetCode/042/1.md b/docs/Algorithm/DataStructure/Python/Data_Structure/README.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/042/1.md rename to docs/Algorithm/DataStructure/Python/Data_Structure/README.md diff --git a/docs/Algorithm/DataStructure/Stack/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/Stack/README.md old mode 100644 new mode 100755 similarity index 100% rename from docs/Algorithm/DataStructure/Stack/README.md rename to docs/Algorithm/DataStructure/Python/Data_Structure/Stack/README.md diff --git a/docs/Algorithm/DataStructure/Python/Data_Structure/Tree/README.md b/docs/Algorithm/DataStructure/Python/Data_Structure/Tree/README.md new file mode 100755 index 00000000..fe9c7bbf --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Data_Structure/Tree/README.md @@ -0,0 +1,15 @@ +# Some algorithm templates for better understanding! + +## 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/opt/git/LeetCode/docs/Algorithm\ Templates/Sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/opt/git/LeetCode/docs/src/py2.x/SortingAlgorithm/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | | diff --git a/docs/Algorithm/DataStructure/Python/Dynamic_Programming/README.md b/docs/Algorithm/DataStructure/Python/Dynamic_Programming/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/Python/Hash/README.md b/docs/Algorithm/DataStructure/Python/Hash/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/Python/Others/NextNodeInOrderTree.md b/docs/Algorithm/DataStructure/Python/Others/NextNodeInOrderTree.md new file mode 100755 index 00000000..28a10248 --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Others/NextNodeInOrderTree.md @@ -0,0 +1,45 @@ +``` python + 8 + / + 5 + / \ + 3 6 + / \ \ + 1 4 7 + + +class Node { + Node parent, lc, rc; + int val; +} +``` + +1. 首先判断其自有无右孩子,若有,则取其右子树的最左节点; 若无,则开始2 + + +2. 它是其父亲节点的左孩子,则其父亲节点 + + +2. 它是其父亲节点的右孩子,则从其父亲开始往上追溯到第一个向右的节点,如果没有这个节点或者说没有父亲节点,则无下一个节点,若有则取之 + + +```python +def nextNode(node): + def leftest(node): + while node.lc: + node = node.lc + return node + if node.rc: + return leftest(node.rc) + if not node.parent: + return None + if node == node.parent.lc: + return node.parent + elif node == node.parent.rc: + while node.parent.parent: + if node.parent != node.parent.parent.lc: + node = node.parent + else: + return node.parent.parent + return None +``` diff --git a/docs/Algorithm/DataStructure/Python/Others/TopKWords.java b/docs/Algorithm/DataStructure/Python/Others/TopKWords.java new file mode 100755 index 00000000..c9f13800 --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Others/TopKWords.java @@ -0,0 +1,86 @@ +import java.io.*; +import java.util.*; + +/* display the most frequent K words in the file and the times it appear + in the file – shown in order (ignore case and periods) */ + +public class TopKWords { + static class CountWords { + private String fileName; + + public CountWords(String fileName) { + this.fileName = fileName; + } + + public Map getDictionary() { + Map dictionary = new HashMap<>(); + FileInputStream fis = null; + + try { + + fis = new FileInputStream(fileName); // open the file + int in = 0; + String s = ""; // init a empty word + in = fis.read(); // read one character + + while (-1 != in) { + if (Character.isLetter((char)in)) { + s += (char)in; //if get a letter, append to s + } else { + // this branch means an entire word has just been read + if (s.length() > 0) { + // see whether word exists or not + if (dictionary.containsKey(s)) { + // if exist, count++ + dictionary.put(s, dictionary.get(s) + 1); + } else { + // if not exist, initiate count of this word with 1 + dictionary.put(s, 1); + } + } + s = ""; // reInit a empty word + } + in = fis.read(); + } + return dictionary; + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + // you always have to close the I/O streams + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + } + public static void main(String[] args) { + // you can replace the filePath with yours, e.g. + // CountWords cw = new CountWords("/Users/lisanaaa/Desktop/words.txt"); + CountWords cw = new CountWords("/words.txt"); + Map dictionary = cw.getDictionary(); // get the words dictionary: {word: frequency} + + // we change the map to list for convenient sort + List> list = new ArrayList<>(dictionary.entrySet()); + + // sort by lambda valueComparator + list.sort(Comparator.comparing( + m -> m.getValue()) + ); + + Scanner input = new Scanner(System.in); + int k = input.nextInt(); + while (k > list.size()) { + System.out.println("Retype a number, your number is too large"); + input = new Scanner(System.in); + k = input.nextInt(); + } + for (int i = 0; i < k; i++) { + System.out.println(list.get(list.size() - i - 1)); + } + } +} + + diff --git a/docs/Algorithm/DataStructure/Python/Others/words.txt b/docs/Algorithm/DataStructure/Python/Others/words.txt new file mode 100755 index 00000000..b3c4b567 --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Others/words.txt @@ -0,0 +1,11 @@ + + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam non pharetra purus. Quisque non tristique risus. Nulla ultricies eget nunc a volutpat. Aliquam semper, eros sit amet semper pellentesque, elit magna auctor ligula, sit amet vulputate nunc arcu sit amet ipsum. Aenean efficitur, felis ut tincidunt semper, sem sapien facilisis felis, et elementum ipsum risus sit amet metus. Pellentesque et orci at odio hendrerit lobortis vitae non felis. Phasellus nunc eros, ultricies sed dolor vel, ultricies mattis neque. Mauris placerat fringilla libero id efficitur. Donec nec imperdiet augue. Sed sit amet risus in turpis scelerisque rutrum. Ut sed pretium dolor. Donec metus nisl, blandit quis augue et, interdum suscipit metus. Morbi rutrum eros vel lacus aliquet, et maximus erat dapibus. Vivamus est justo, sagittis a augue id, vulputate vehicula nunc. Praesent mattis eros sapien, ac sagittis urna accumsan sit amet. Proin non dui tincidunt, tristique nisi in, vestibulum lorem. + +Quisque fermentum justo lacus, sit amet tempus lectus congue eu. Nulla sed quam nec nulla consequat tincidunt. Sed sed nunc diam. Integer ex ante, accumsan id fermentum a, interdum eu sapien. Aliquam justo dui, luctus vel ligula in, lacinia ornare turpis. Praesent leo purus, fringilla ut lobortis et, porta ac urna. Mauris id velit porta, iaculis felis non, sagittis nunc. Quisque non condimentum nisl, vitae venenatis urna. Nam commodo euismod felis, ac efficitur turpis scelerisque nec. Phasellus sagittis nec lacus eu bibendum. Suspendisse finibus vestibulum quam, quis volutpat ante. Duis nibh ligula, dapibus at est sed, tincidunt convallis augue. Pellentesque non consequat mi. Curabitur consequat imperdiet efficitur. + +Mauris ipsum arcu, fermentum in urna ultricies, venenatis vehicula nisl. Donec viverra non tellus sit amet porta. Phasellus ornare magna eget condimentum mollis. In hac habitasse platea dictumst. Proin in nibh venenatis, fermentum neque nec, commodo urna. In eget condimentum risus, ac interdum dolor. Sed ut neque sapien. Proin nulla diam, lobortis sed ultrices eget, blandit ut libero. + +Fusce at varius dui. Quisque viverra vulputate consectetur. Quisque sagittis id ante a vestibulum. Phasellus vel lobortis lectus. Duis vestibulum, quam vel congue elementum, lacus nibh efficitur odio, consectetur dapibus ipsum velit at diam. Duis eu nunc id diam tempor vestibulum sed luctus arcu. Nunc eu luctus ex. Morbi et commodo eros, non suscipit enim. Ut fringilla odio nec tincidunt scelerisque. Nam quis elit cursus, ullamcorper lorem id, convallis dui. Mauris elementum tortor odio, nec imperdiet nisl bibendum eget. Suspendisse potenti. + +Cras ut efficitur enim. Sed consequat non ante id euismod. Ut at magna viverra, aliquam purus a, lobortis mi. Donec hendrerit odio eu nunc imperdiet, quis pharetra sapien volutpat. Morbi leo libero, egestas vitae tortor eget, dictum volutpat augue. Donec arcu lacus, tristique eu posuere ac, pharetra vel ante. Nunc efficitur arcu elit, quis semper risus vestibulum eu. diff --git a/docs/Algorithm/DataStructure/Python/README.md b/docs/Algorithm/DataStructure/Python/README.md new file mode 100755 index 00000000..6889eed1 --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/README.md @@ -0,0 +1,5 @@ +# Some algorithm templates for better understanding! + +> [八大排序算法 集合](/docs/Algorithm/Sort) + +![](/images/SortingAlgorithm/八大排序算法性能.png) diff --git a/docs/Algorithm/DataStructure/Python/Search/README.md b/docs/Algorithm/DataStructure/Python/Search/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/Python/Sort/README.md b/docs/Algorithm/DataStructure/Python/Sort/README.md new file mode 100755 index 00000000..7f01a8d7 --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Sort/README.md @@ -0,0 +1,13 @@ +# 八大排序算法 + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +| 名称 | 动图 | 代码 | +| --- | --- | --- | +| 冒泡排序 | ![](/images/SortingAlgorithm/冒泡排序.gif) | [BubbleSort.py](/src/py3.x/sort/BubbleSort.py) | +| 插入排序 | ![](/images/SortingAlgorithm/直接插入排序.gif) | [InsertSort.py](/src/py3.x/sort/InsertSort.py) | +| 选择排序 | ![](/images/SortingAlgorithm/简单选择排序.gif) | [SelectionSort.py](/src/py3.x/sort/SelectionSort.py) | +| 快速排序 | ![](/images/SortingAlgorithm/快速排序.gif) | [QuickSort.py](/src/py3.x/sort/QuickSort.py) | +| 希尔排序 | ![](/images/SortingAlgorithm/希尔排序.png) | [ShellSort.py](/src/py3.x/sort/ShellSort.py) | +| 归并排序 | ![](/images/SortingAlgorithm/归并排序.gif) | [MergeSort.py](/src/py3.x/sort/MergeSort.py) | +| 基数排序 | ![](/images/SortingAlgorithm/基数排序.gif) | [RadixSort.py](/src/py3.x/sort/RadixSort.py) | diff --git a/docs/Algorithm/DataStructure/Python/Sort/Sort.ipynb b/docs/Algorithm/DataStructure/Python/Sort/Sort.ipynb new file mode 100755 index 00000000..a38ab891 --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Sort/Sort.ipynb @@ -0,0 +1,772 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 排序算法\n", + "\n", + "## 1、冒泡排序(Bubble Sort)\n", + "\n", + "### 1.1、简介\n", + "\n", + "冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们两个的顺序错误就把它们两个交换。走访数列的工作是重复的,直到最后没有再需要交换,也就是说该数列已经排序完成了。这个算法的名字由来是因为越小的元素会经由交换慢慢 \"浮\" 到数列的顶端。\n", + "\n", + "### 1.2、算法描述\n", + "\n", + " - 比较相邻的元素。如果第一个比第二个大,就交换它们两个;\n", + " - 对每一组相邻元素做相同的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;\n", + " - 针对所有的元素重复以上的步骤,除了最后一个;\n", + " - 重复步骤 1~3 ,直到排序完成。\n", + " \n", + "### 1.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/BubbleSort_1.gif)\n", + "\n", + "### 1.4、代码实现" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "def bubble_sort(nums):\n", + " # 外层循环负责设置冒泡排序进行的次数\n", + " for i in range(len(nums)-1):\n", + " # 内层循环负责前后两两比较,求最大值放到最后\n", + " # j 为列表下标\n", + " for j in range(len(nums)-1-i):\n", + " # 如果相互比较的两个数,前一个数比后一个数大\n", + " if nums[j] > nums[j+1]:\n", + " nums[j], nums[j+1] = nums[j+1], nums[j]\n", + " return nums\n", + "\n", + "if __name__ == \"__main__\":\n", + " nums = [5, 1, 9, 3, 2, 7]\n", + " bubble_sort(nums)\n", + " print(nums)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.5、代码优化\n", + "\n", + "#### 1.5.1、优化 1\n", + "\n", + "如果上面代码中,里面一层循环在某次扫描中没有执行交换,则说明此时数组已经全部有序了,无需再进行扫描。因此,我们增加一个标记,每次发生交换,用来标记,如果某次循环完没有标记,则说明已经完成排序。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "# 改进版的冒泡排序_1\n", + "def bubble_sort_2(nums):\n", + " # 外层循环负责设置冒泡排序进行的次数\n", + " for i in range(len(nums)-1):\n", + " # 标记是否已经完成排序\n", + " swaped = False\n", + " # 内层循环负责前后两两比较,求最大值放到最后,j 为列表下标\n", + " for j in range(len(nums)-1-i):\n", + " # 如果相互比较的两个数,前一个数比后一个数大\n", + " if nums[j] > nums[j+1]:\n", + " nums[j], nums[j+1] = nums[j+1], nums[j]\n", + " swaped = True\n", + " # 如果上一次扫描没有发生交换,说明数组已经全部都排好序了,那我们就退出循环\n", + " if not swaped:\n", + " break\n", + " return nums\n", + "\n", + "if __name__ == \"__main__\":\n", + " nums = [5, 1, 9, 3, 2, 7]\n", + " bubble_sort_2(nums)\n", + " print(nums)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "#### 1.5.2、优化 2\n", + "\n", + "在我们第一步优化的基础上,我们可以进一步思考:如果 R[0 ~ i] 已是有序区间,上次扫描的区间是 R[i ~ n],记上次扫描时最后一次执行交换的位置为 lastSwapPos,则 lastSwapPos 在 i 与 n 之间,不难发现 R[i ~ lastSwapPos] 区间也是有序的,否则这个区间也会发生变换;所以下次扫描区间就可以由 R[i ~ n] 缩减到 R[lastSwapPos ~ n] 。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "# 改进版的冒泡排序_2\n", + "def bubble_sort_3(nums):\n", + " lastSwapPos = 0\n", + " lastSwapPosTemp = 0\n", + " # 外层循环负责设置冒泡排序进行的次数\n", + " for i in range(len(nums)-1):\n", + " lastSwapPos = lastSwapPosTemp\n", + " # 内层循环负责前后两两比较,求最大值放到最后,j 为列表下标\n", + " for j in range(len(nums)-1-i):\n", + " # 如果相互比较的两个数,前一个数比后一个数大\n", + " if nums[j] > nums[j+1]:\n", + " nums[j], nums[j+1] = nums[j+1], nums[j]\n", + " # 记录最后一次发生交换的位置\n", + " lastSwapPosTemp = j\n", + " # 如果上一次扫描没有发生交换,说明数组已经全部都排好序了,那我们就退出循环\n", + " if lastSwapPos == lastSwapPosTemp:\n", + " break\n", + " return nums\n", + "\n", + "if __name__ == \"__main__\":\n", + " nums = [5, 1, 9, 3, 2, 7]\n", + " bubble_sort_3(nums)\n", + " print(nums)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2、插入排序(Insert Sort)\n", + "\n", + "### 2.1、简介\n", + "\n", + "插入排序(insert sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。\n", + "\n", + "### 2.2、算法描述\n", + "\n", + "一般来说,插入排序都采用 in-place 在数组上实现。具体算法描述如下:\n", + "\n", + " - 从第一个元素开始,该元素可以认为已经被排序;\n", + " - 取出下一个元素,在已经排序的元素序列中从后向前扫描;\n", + " - 如果该元素(已排序)大于新元素,将该元素移到下一个位置;\n", + " - 重复步骤 3 ,直到找到已排序的元素小于或者等于新元素的位置;\n", + " - 将新元素插入到该位置后;\n", + " - 重复步骤 2 ~ 5\n", + " \n", + "### 2.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/InsertSort_1.gif)\n", + "\n", + "### 2.4、代码实现\n", + "\n", + "插入排序和冒泡排序的区别在于:\n", + "\n", + " - 插入排序的前提是:左边是有序的数列\n", + " - 冒泡排序:相邻的值进行交换,一共进行 n 次" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 1, 9, 3, 2, 7]\n", + "[5]\n", + "[1, 5]\n", + "[1, 5, 9]\n", + "[1, 3, 5, 9]\n", + "[1, 2, 3, 5, 9]\n", + "result: [1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "def insert_sort(nums):\n", + " # 循环 除第一个数字组成的有序数组 以外的数字\n", + " for i in range(1, len(nums)):\n", + " # 每一个数字,依次和有序数组进行比较\n", + " print(nums[:i])\n", + " for j in range(len(nums[:i])):\n", + " if nums[i] < nums[j]:\n", + " nums[i], nums[j] = nums[j], nums[i]\n", + " \n", + "if __name__ == \"__main__\":\n", + " l = [5, 1, 9, 3, 2, 7]\n", + " print(l)\n", + " insert_sort(l)\n", + " print(\"result: \" + str(l))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3、选择排序(SelectionSort)\n", + "\n", + "### 3.1、简介\n", + "\n", + "选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 \n", + "\n", + "### 3.2、算法描述\n", + "\n", + "n 个记录的直接选择排序可经过 n-1 趟直接选择排序得到有序结果。具体算法描述如下:\n", + "\n", + " - 初始状态:无序区为 R[1 ... n],有序区为空;\n", + " - 第 i 趟排序 (i = 1, 2, 3, ... n-1) 开始时,当前有序区和无序区分别为 R[1 ... i-1] 和 R[i ... n]。该趟排序从当前无序区中 —— 选出关键字最小的记录 R[k],将它与无序区的第 1 个记录 R 交换,使 R[1 ... i] 和 R[i+1 ... n] 分别变为记录个数增加 1 个的新有序区和记录个数减少 1 个的新无序区;\n", + " - n-1 趟结束,数组有序化了。\n", + " \n", + "### 3.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/SelectionSort_1.gif)\n", + "\n", + "### 3.4、代码实现\n", + "\n", + "选择排序和冒泡排序的区别在于:\n", + "\n", + "选择排序的前提是:找到最大值的位置,最后才进行 1 次交换;\n", + "而冒泡排序是:相邻的值进行交换,一共进行 n 次交换" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 1, 9, 3, 2, 7]\n", + "1 [5, 1, 7, 3, 2, 9]\n", + "2 [5, 1, 2, 3, 7, 9]\n", + "3 [3, 1, 2, 5, 7, 9]\n", + "4 [2, 1, 3, 5, 7, 9]\n", + "5 [1, 2, 3, 5, 7, 9]\n", + "result: [1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "def selection_sort(nums):\n", + " length = len(nums) - 1\n", + "\n", + " while length:\n", + " index = length\n", + " # 第一个数字,和后面每一个数字进行对比,找出最大值,放到最后!!\n", + " for j in range(length):\n", + " if nums[j] > nums[index]:\n", + " index = j\n", + " nums[length], nums[index] = nums[index], nums[length]\n", + " print(len(nums) - length, nums)\n", + " length -= 1\n", + " \n", + "if __name__ == \"__main__\":\n", + " nums = [5, 1, 9, 3, 2, 7]\n", + " print(nums)\n", + " selection_sort(nums)\n", + " print(\"result: \" + str(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4、快速排序(Quick Sort)\n", + "\n", + "### 4.1、简介\n", + "\n", + "快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。\n", + "\n", + "### 4.2、算法描述\n", + "\n", + "快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:\n", + "\n", + " - 从数列中挑出一个元素,称为 \"基准\"(pivot)\n", + " - 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出后,该基准就处于数列的中间位置。这个称为分区(partition)操作;\n", + " - 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。\n", + " \n", + "### 4.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/QuickSort_1.gif)\n", + "\n", + "### 4.4、代码实现" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 7 ******************************\n", + "5 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "5 1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "5 9 ******************************\n", + "5 3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "2 3 ******************************\n", + "2 1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "9 7 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "def quick_sort(nums, start, end):\n", + " i = start\n", + " j = end\n", + " # 结束排序\n", + " if i >= j:\n", + " return\n", + " # 保存首个数值\n", + " key = nums[i]\n", + " # 一次排序,i和j的值不断的靠拢,然后最终停止,结束一次排序\n", + " while i < j:\n", + " # 和最右边的比较,如果值 >=key,然后j-1,慢慢的和前一个值比较;如果值key,那么就交换位置\n", + " while i < j and key >= nums[i]:\n", + " print(key, nums[i], '%' * 30)\n", + " i += 1\n", + " nums[j] = nums[i]\n", + " nums[i] = key\n", + " # 左边排序\n", + " quick_sort(nums, start, j-1)\n", + " # 右边排序\n", + " quick_sort(nums, i+1, end)\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " l = [5, 1, 9, 3, 2, 7]\n", + " quick_sort(l, 0, len(l) - 1)\n", + " print(l)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5、希尔排序(ShellSort)\n", + "\n", + "### 5.1、简介\n", + "\n", + "希尔排序(Shell Sort)也是插入排序的一种。也称为缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。\n", + "\n", + "1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会 **优先比较距离较远的元素。希尔排序又叫缩小增量排序。**\n", + "\n", + "### 5.2、算法描述\n", + "\n", + "先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:\n", + "\n", + " - 选择一个增量序列 $t_1, t_2, …, t_k$ ,其中 $t_i>t_j, t_k=1$ ;\n", + " - 按增量序列个数 k,对序列进行 k 趟排序;\n", + " - 每趟排序,根据对应的增量 $t_i$,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。\n", + " \n", + "**补充描述:**\n", + " \n", + "是不是有些不明白呢?那我们用通俗一些的语句来说。\n", + "\n", + "直接插入排序在在本身数量比较少的时候情况下效率很高,如果待排数的数量很多,其效率不是很理想。\n", + "\n", + "  回想一下直接插入排序过程,排序过程中,我们可以设置一条线,左边是排好序的,右边则是一个一个等待排序,\n", + "\n", + "如果最小的那个值在最右边,那么排这个最小值的时候,需要将所有元素向右边移动一位。\n", + "\n", + "  是否能够减少这样的移位呢?\n", + "\n", + "  我们不希望它是一步一步的移动,而是大步大步的移动。希尔排序就被发明出来了,它也是当时打破效率\n", + "\n", + "O(n2)的算法之一。希尔排序算法通过设置一个间隔,对同样间隔的数的集合进行插入排序,此数集合中的元素\n", + "\n", + "移位的长度是以间隔的长度为准,这样就实现了大步位移。但是最后需要对元素集合进行一次直接插入排序,所以\n", + "\n", + "最后的间隔一定是1。\n", + "\n", + "下面举一个例子:\n", + "\n", + "第一趟希尔排序,间隔为4\n", + "\n", + "![](/images/SortingAlgorithm/ShellSort_2.png)\n", + "\n", + "第二趟排序:间隔为 2\n", + "\n", + "![](/images/SortingAlgorithm/ShellSort_3.png)\n", + "\n", + "第三趟排序,间隔为 1,即 直接插入排序法(InsertSort):\n", + "\n", + "具体的插入排序过程,这里我们就不再详细说了。\n", + "\n", + "```\n", + "减小间隔:\n", + "\n", + "上面已经演示了以4为初始间隔对包含10个数据项的数组进行排序的情况。对于更大的数组开始的间隔也应该更大。然后间隔不断减小,直到间隔变成1。\n", + "\n", + "举例来说,含有1000个数据项的数组可能先以364为增量,然后以121为增量,以40为增量,以13为增量,以4为增量,最后以 1为增量进行希尔排序。用来形成间隔的数列被称为间隔序列。这里所表示的间隔序列由Knuth提出,此序列是很常用的。数列以逆向形式从1开始,通过递归表达式\n", + "\n", + "h = 3 * b + 1\n", + "\n", + "来产生,初始值为 1 。\n", + "\n", + "在排序算法中,首先在一个短小的循环中使用序列的生成公式来计算出最初的间隔。h值最初被赋为1,然后应用公式h=3*h+1生成序列1,4,13,40,121,364,等等。当间隔大于数组大小的时候,这个过程停止。对于一个含有1000个数据项的数组,序列的第七个数字,1093就太大了。因此,使用序列的第六个数字作为最大的数字来开始这个排序过程,作364-增量排序。然后,每完成一次排序全程的外部循环,用前面提供的此公式倒推式来减小间隔:\n", + "\n", + "h=(h-1)/3\n", + "\n", + "这个倒推的公式生成逆置的序列364,121,40,13,4,1。从364开始,以每一个数字作为增量进行排序。当数组用1-增量排序后,算法结束。\n", + "\n", + "希尔排序比插入排序快很多,它是基于什么原因呢?当h值大的时候,数据项每一趟排序需要移动元素的个数很少,但数据项移动的距离很长。这是非常有效率的。当h减小时,每一趟排序需要移动的元素的个数增多,但是此时数据项已经接近于它们排序后最终的位置,这对于插入排序可以更有效率。正是这两种情况的结合才使希尔排序效率那么高。\n", + "\n", + "注意后期的排序过程不撤销前期排序所做的工作。例如,已经完成了以40-增量的排序的数组,在经过以13-增量的排序后仍然保持了以40-增量的排序的结果。如果不是这样的话,希尔排序就无法实现排序的目的。\n", + "```\n", + " \n", + "### 5.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/ShellSort_1.gif)\n", + "\n", + "再附加一个静态图:\n", + "\n", + "![](/images/SortingAlgorithm/ShellSort_4.png)\n", + "\n", + "### 5.4、代码实现" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "开始 [5, 2, 9, 8, 1, 10, 3, 4, 7]\n", + "3 -- [3, 2, 9, 5, 1, 10, 8, 4, 7]\n", + "3 -- [3, 1, 9, 5, 2, 10, 8, 4, 7]\n", + "3 -- [3, 1, 7, 5, 2, 9, 8, 4, 10]\n", + "2 -- [2, 1, 3, 5, 7, 9, 8, 4, 10]\n", + "2 -- [2, 1, 3, 4, 7, 5, 8, 9, 10]\n", + "1 -- [1, 2, 3, 4, 5, 7, 8, 9, 10]\n", + "结束 [1, 2, 3, 4, 5, 7, 8, 9, 10]\n" + ] + } + ], + "source": [ + "# 直接插入排序\n", + "def insert_sort(nums, start, increment):\n", + " for i in range(start+increment, len(nums), increment):\n", + " for j in range(start, len(nums[:i]), increment):\n", + " if nums[i] < nums[j]:\n", + " nums[i], nums[j] = nums[j], nums[i]\n", + " print(increment, '--', nums)\n", + " return nums\n", + "\n", + "# 希尔排序\n", + "def shell_sort(nums, increment):\n", + " # 依次进行分层\n", + " while increment:\n", + " # 每一层,都进行n次插入排序\n", + " for i in range(0, increment):\n", + " insert_sort(nums, i, increment)\n", + " increment -= 1\n", + " return nums\n", + "\n", + "if __name__ == \"__main__\":\n", + " l = [5, 2, 9, 8, 1, 10, 3, 4, 7]\n", + " increment = int(len(l)/3)+1 if len(l)%3 else int(len(l)/3)\n", + " print(\"开始\", l)\n", + " l = shell_sort(l, increment)\n", + " print(\"结束\", l)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6、归并排序(MergeSort)\n", + "\n", + "### 6.1、简介\n", + "\n", + "归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。\n", + "\n", + "### 6.2、算法描述\n", + "\n", + " - 把长度为 n 的输入序列分成两个长度为 n/2 的子序列;\n", + " - 对这两个子序列分别采用归并排序;\n", + " - 将两个排序好的子序列合并成一个最终的排序序列。\n", + " \n", + "### 6.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/MergeSort_1.gif)\n", + "\n", + "### 6.4、代码实现\n", + "\n", + "归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1]\n", + "********************\n", + "[2]\n", + "____________________\n", + "result: [1, 2]\n", + "[4]\n", + "********************\n", + "[5]\n", + "____________________\n", + "result: [4, 5]\n", + "[3]\n", + "********************\n", + "[4, 5]\n", + "____________________\n", + "result: [3, 4, 5]\n", + "[1, 2]\n", + "********************\n", + "[3, 4, 5]\n", + "____________________\n", + "result: [1, 2, 3, 4, 5]\n", + "[7]\n", + "********************\n", + "[90]\n", + "____________________\n", + "result: [7, 90]\n", + "[6]\n", + "********************\n", + "[7, 90]\n", + "____________________\n", + "result: [6, 7, 90]\n", + "[23]\n", + "********************\n", + "[45]\n", + "____________________\n", + "result: [23, 45]\n", + "[21]\n", + "********************\n", + "[23, 45]\n", + "____________________\n", + "result: [21, 23, 45]\n", + "[6, 7, 90]\n", + "********************\n", + "[21, 23, 45]\n", + "____________________\n", + "result: [6, 7, 21, 23, 45, 90]\n", + "[1, 2, 3, 4, 5]\n", + "********************\n", + "[6, 7, 21, 23, 45, 90]\n", + "____________________\n", + "result: [1, 2, 3, 4, 5, 6, 7, 21, 23, 45, 90]\n", + "[1, 2, 3, 4, 5, 6, 7, 21, 23, 45, 90]\n" + ] + } + ], + "source": [ + "def MergeSort(lists):\n", + " if len(lists) <= 1:\n", + " return lists\n", + " num = int(len(lists) / 2)\n", + " # 从中间,进行数据的拆分, 递归的返回数据进行迭代排序\n", + " left = MergeSort(lists[:num])\n", + " right = MergeSort(lists[num:])\n", + " print(left)\n", + " print(\"*\" * 20)\n", + " print(right)\n", + " print(\"_\" * 20)\n", + " return Merge(left, right)\n", + "\n", + "# 将 2 个已经排好序的子序列合并成一个序列,也就是 2-路归并\n", + "def Merge(left, right):\n", + " r, l = 0, 0\n", + " result = []\n", + " # 这里将两个序列中的每个值都比较一下,最小的放到最左边\n", + " while l < len(left) and r < len(right):\n", + " if left[l] < right[r]:\n", + " result.append(left[l])\n", + " l += 1\n", + " else:\n", + " result.append(right[r])\n", + " r += 1\n", + " result += right[r:]\n", + " result += left[l:]\n", + " print('result:', result)\n", + " # 最终将合并好的完整序列返回\n", + " return result\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " print(MergeSort([1, 2, 3, 4, 5, 6, 7, 90, 21, 23, 45]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7、基数排序\n", + "\n", + "### 7.1、简介\n", + "\n", + "以十进制为例,基数指的是数的位,如个位,十位百位等。而以十六进制为例,0xB2,就有两个radices(radix的复数)。\n", + "\n", + "基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。\n", + "\n", + "### 7.2、算法描述\n", + "\n", + " - 取得数组中的最大数,并取得位数;\n", + " - arr 为原始数组,从最低位开始取每个位组成 radix 数组;\n", + " - 对 radix 进行计数排序(利用计数排序适用于小范围数的特点)\n", + " \n", + "**补充描述:**\n", + "\n", + "基数排序不同于其他的排序算法,它不是基于比较的算法。基数排序是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法。它是一种稳定的排序算法。多关键字排序中有两种方法:最高位优先法(MSD)和最低位优先法(LSD)。通常用于对数的排序选择的是最低位优先法,即先对最次位关键字进行排序,再对高一位的关键字进行排序,以此类推。\n", + "\n", + "算法的思想:类似于桶式排序,我们需要给待排序记录准备10个桶,为什么是10个??因为一个数的任何一位上,其数字大小都位于0~9之间,因此采用10个桶,桶的编号分别为0,1,2,3,4...9,对应待排序记录中每个数相应位的数值,基数排序也是因此而得名。我们先根据待排序记录的每个数的个位来决定让其加入哪个桶中。例如:待排序数组为\n", + "\n", + "278 109 63 930 589 184 505 269 8 83\n", + "\n", + "求取每个数的个位数,依次为:8 9 3 0 9 4 5 9 8 3\n", + "\n", + "依照其个位数决定将其加入哪个桶中\n", + "\n", + "![](/images/SortingAlgorithm/RadixSort_2.png)\n", + " \n", + "### 7.3、动图演示\n", + "\n", + "![](/images/SortingAlgorithm/RadixSort_1.gif)\n", + "\n", + "### 7.4、代码实现\n", + "\n", + "基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要 $O(n)$ 的时间复杂度,而且分配之后得到新的关键字序列又需要 $O(n)$ 的时间复杂度。假如待排数据可以分为 $d$ 个关键字,则基数排序的时间复杂度将是 $O(d*2n)$ ,当然 $d$ 要远远小于 $n$ ,因此基本上还是线性级别的。\n", + "\n", + "基数排序的空间复杂度为 $O(n+k)$ ,其中 $k$ 为桶的数量。一般来说 $n>>k$ ,因此额外空间需要大概 $n$ 个左右。" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 5, 7, 9]\n" + ] + } + ], + "source": [ + "# ************************基数排序****************************\n", + "# 确定排序的次数\n", + "# 排序的顺序跟序列中最大数的位数相关\n", + "def radix_sort_nums(L):\n", + " maxNum = L[0]\n", + " #寻找序列中的最大数\n", + " for x in L:\n", + " if maxNum < x:\n", + " maxNum = x\n", + " # 确定序列中的最大元素的位数\n", + " times = 0\n", + " while (maxNum > 0):\n", + " maxNum = int((maxNum/10))\n", + " times += 1\n", + " return times\n", + "\n", + "# 找到num从低到高第pos位的数据\n", + "def get_num_pos(num, pos):\n", + " return (int((num/(10**(pos-1))))) % 10\n", + "\n", + "# 基数排序\n", + "def radix_sort(L):\n", + " count = 10 * [None] # 存放各个桶的数据统计个数\n", + " bucket = len(L) * [None] # 暂时存放排序结果\n", + " # 从低位到高位依次执行循环\n", + " for pos in range(1, radix_sort_nums(L)+1):\n", + " # 置空各个桶的数据统计\n", + " for x in range(0, 10):\n", + " count[x] = 0\n", + " # 统计当前该位(个位,十位,百位....)的元素数目\n", + " for x in range(0, len(L)):\n", + " # 统计各个桶将要装进去的元素个数\n", + " j = get_num_pos(int(L[x]), pos)\n", + " count[j] += 1\n", + " # count[i]表示第i个桶的右边界索引\n", + " for x in range(1,10):\n", + " count[x] += count[x-1]\n", + " # 将数据依次装入桶中\n", + " for x in range(len(L)-1, -1, -1):\n", + " # 求出元素第K位的数字\n", + " j = get_num_pos(L[x], pos)\n", + " # 放入对应的桶中,count[j]-1是第j个桶的右边界索引\n", + " bucket[count[j]-1] = L[x]\n", + " # 对应桶的装入数据索引-1\n", + " count[j] -= 1\n", + " # 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表\n", + " for x in range(0, len(L)):\n", + " L[x] = bucket[x]\n", + " \n", + "if __name__ == \"__main__\":\n", + " l = [5, 1, 9, 3, 2, 7]\n", + " radix_sort(l)\n", + " print(l)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/DataStructure/Python/Sort/insertionSort.py b/docs/Algorithm/DataStructure/Python/Sort/insertionSort.py new file mode 100755 index 00000000..29f975d7 --- /dev/null +++ b/docs/Algorithm/DataStructure/Python/Sort/insertionSort.py @@ -0,0 +1,16 @@ +def insertionSort(nums): + if not nums or len(nums) < 2: + return nums + + for i in range(1, len(nums)): + for j in range(i): + if nums[i] < nums[j]: + nums[i], nums[j] = nums[j], nums[i] + return nums + + +if __name__ == "__main__": + nums = [5, 1, 9, 3, 2, 7] + print('input: ', nums) + nums = insertionSort(nums) + print("result: ", nums) diff --git "a/docs/Algorithm/DataStructure/Python/Sort/\346\216\222\345\272\217\347\250\263\345\256\232\346\200\247.md" "b/docs/Algorithm/DataStructure/Python/Sort/\346\216\222\345\272\217\347\250\263\345\256\232\346\200\247.md" new file mode 100755 index 00000000..08b1c964 --- /dev/null +++ "b/docs/Algorithm/DataStructure/Python/Sort/\346\216\222\345\272\217\347\250\263\345\256\232\346\200\247.md" @@ -0,0 +1 @@ +https://baike.baidu.com/item/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%E7%A8%B3%E5%AE%9A%E6%80%A7 diff --git a/docs/Algorithm/DataStructure/Python/Traversals/README.md b/docs/Algorithm/DataStructure/Python/Traversals/README.md new file mode 100755 index 00000000..e69de29b diff --git a/docs/Algorithm/DataStructure/README.md b/docs/Algorithm/DataStructure/README.md deleted file mode 100644 index b4dade6a..00000000 --- a/docs/Algorithm/DataStructure/README.md +++ /dev/null @@ -1,23 +0,0 @@ -## 二分查找 - -![](/img/Algorithm/DataStructure/二分查找.gif) - -* 二分查找: [BinarySearch.py](/src/py3.x/DataStructure/BinarySearch.py) - -## 八大排序算法 - -> Python 模版 - -![](/img/Algorithm/DataStructure/Python/八大排序算法性能.png) - -| 名称 | 动图 | 代码 | -| --- | --- | --- | -| 冒泡排序 | ![](/img/Algorithm/DataStructure/冒泡排序.gif) | [BubbleSort.py](/src/py3.x/DataStructure/BubbleSort.py) | -| 插入排序 | ![](/img/Algorithm/DataStructure/直接插入排序.gif) | [InsertSort.py](/src/py3.x/DataStructure/InsertionSort.py) | -| 选择排序 | ![](/img/Algorithm/DataStructure/简单选择排序.gif) | [SelectionSort.py](/src/py3.x/DataStructure/SelectionSort.py) | -| 快速排序 | ![](/img/Algorithm/DataStructure/快速排序.gif) | [QuickSort.py](/src/py3.x/DataStructure/QuickSort.py) | -| 希尔排序 | ![](/img/Algorithm/DataStructure/希尔排序.png) | [ShellSort.py](/src/py3.x/DataStructure/ShellSort.py) | -| 归并排序 | ![](/img/Algorithm/DataStructure/归并排序.gif) | [MergeSort.py](/src/py3.x/DataStructure/MergeSort.py) | -| 基数排序 | ![](/img/Algorithm/DataStructure/基数排序.gif) | [RadixSort.py](/src/py3.x/DataStructure/RadixSort.py) | - -补充: [JavaScript 模块](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure/JavaScript.md) diff --git a/docs/Algorithm/Leetcode/C++/0001._Two_Sum.md b/docs/Algorithm/Leetcode/C++/0001._Two_Sum.md new file mode 100755 index 00000000..b693d4ad --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0001._Two_Sum.md @@ -0,0 +1,74 @@ +# 1. Two Sum + **难度: Easy** + ## 刷题内容 + > 原题连接 + * https://leetcode.com/problems/two-sum +* https://leetcode-cn.com/problems/two-sum/description + > 内容描述 + ``` +给定 nums = [2, 7, 11, 15], target = 9 + 因为 nums[0] + nums[1] = 2 + 7 = 9 +所以返回 [0, 1] +``` + ## 解题方案 + > 思路 1 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)****** + 采用双指针法,先将数组排序形成了一个有序的区间,指针i,j分别指向头尾, +``` +当 nums1[i] + nums[j] > traget 时,j--, +nums[i] + nums[j] < target 时,i++, +直到 nums[i] + nums[j] == target +``` +```cpp +class Solution +{ +public: + vector twoSum(vector& nums, int target) + { + vector > nums1; + for(int i = 0;i < nums.size();++i) + nums1.push_back(make_pair(nums[i],i)); + sort(nums1.begin(),nums1.end()); + int i = 0,j = nums1.size() - 1; + vector ret; + while(i < j) + { + if(nums1[i].first + nums1[j].first == target) + { + ret.push_back(nums1[i].second); + ret.push_back(nums1[j].second); + return ret; + } + nums1[i].first +nums1[j].first < target ? ++i : --j; + } + } +}; +``` +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + c++中提供了 unordered_map 的容器,unordered_map 中的元素没有按照它们的键值或映射值的任何顺序排序, +而是根据它们的散列值组织成桶以允许通过它们的键值直接快速访问单个元素(具有常数平均时间复杂度) +将先出现的元素储存在 unorder_map 中,遍历数组,每次查找 target - nums[i] 是否存在即可。 + ```cpp +class Solution +{ +public: + vector twoSum(vector& nums, int target) + { + unordered_map m; + vector res; + for (int i = 0; i < nums.size(); ++i) { + m[nums[i]] = i; + } + for (int i = 0; i < nums.size(); ++i) { + int t = target - nums[i]; + if (m.count(t) && m[t] != i) { + res.push_back(i); + res.push_back(m[t]); + break; + } + } + return res; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0002._Add_Two_Numbers.md b/docs/Algorithm/Leetcode/C++/0002._Add_Two_Numbers.md new file mode 100755 index 00000000..5e39962c --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0002._Add_Two_Numbers.md @@ -0,0 +1,70 @@ +# 2. Add Two Numbers + +**难度:Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/add-two-numbers/description/ + +> 内容描述 + +``` +给定两个链表代表两个非负数,求这两个数的和 +(2 -> 4 -> 3) + (5 -> 6 -> 4) +因为 342 + 465 = 807 +所以返回 7 -> 0 -> 8 +``` + +## 解题方案 + +> 思路 + + +这题的的关键在于链表的数储存是倒序的,因此只要从链表头相加,再将所得数挨个储存即可,但是要注意两数相加有可能大于10要进一位。 +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { + ListNode* current; + ListNode* ret = nullptr; + int num = 0; + while(l1 && l2) + { + int sum = l1 ->val + l2 ->val + num; + ListNode* node = new ListNode(sum % 10); + num = sum / 10; + ret ? current ->next = node : ret = node; + current = node; + l1 = l1 ->next; + l2 = l2 ->next; + } + if(l2) + l1 = l2; + while(l1) + { + int sum = num + l1 ->val; + ListNode* node = new ListNode(sum % 10); + num = sum / 10; + current ->next = node; + current = node; + l1 = l1 ->next; + } + if(num) + { + ListNode* node = new ListNode(num); + current ->next = node; + } + return ret; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0003._Longest_Substring_Without_Repeating_Characters.md b/docs/Algorithm/Leetcode/C++/0003._Longest_Substring_Without_Repeating_Characters.md new file mode 100755 index 00000000..130d4cab --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0003._Longest_Substring_Without_Repeating_Characters.md @@ -0,0 +1,97 @@ +# 3. Longest Substring Without Repeating Characters + +**难度:Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ + +> 内容描述 + +``` + +Given a string, find the length of the longest substring without repeating characters. + +Example 1: + +Input: "abcabcbb" +Output: 3 +Explanation: The answer is "abc", with the length of 3. +Example 2: + +Input: "bbbbb" +Output: 1 +Explanation: The answer is "b", with the length of 1. +Example 3: + +Input: "pwwkew" +Output: 3 +Explanation: The answer is "wke", with the length of 3. + Note that the answer must be a substring, "pwke" is a subsequence and not a substring. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)****** + + +用 map储存 key为字符,value 为这个字符的位置,我们可以维护一个子字符串(无重复字符),记录它的起始位置,遍历 string s 当无法在map中找到字符或者小于子字符串的起始位置,就是没有在这个字符串中出现,反之则字符重复,不过 map查找为 O(lgn),因此总的时间复杂度为O(NlgN) +```cpp +class Solution { +public: + int lengthOfLongestSubstring(string s) { + map m; + int beg = 0,length = s.length(),ll = 0,ans = 0; + for(int i = 0;i < length;++i) + { + if(m.find(s[i]) == m.end() || m[s[i]] < beg) + ll++; + else + { + int pos = m[s[i]]; + ans = max(ll,ans); + ll = ll - (pos - beg); + beg = pos + 1; + } + m[s[i]] = i; + } + ans = max(ans,ll); + return ans; + } +}; +``` + +> 思路 2 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(1)****** + +这个思路和上面差不多,用到了一个小窍门,因为储存的是字符,char为8位,因此能储存的最大数为256,这样空间复杂度就为O(1) + +```cpp +class Solution { +public: + int lengthOfLongestSubstring(string s) { + int m[256]; + for(int i = 0;i < 256;++i) + m[i] = -1; + int beg = 0,length = s.length(),ll = 0,ans = 0; + for(int i = 0;i < length;++i) + { + if(m[s[i]] < beg) + ll++; + else + { + int pos = m[s[i]]; + ans = max(ll,ans); + ll = ll - (pos - beg); + beg = pos + 1; + } + m[s[i]] = i; + } + ans = max(ans,ll); + return ans; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0004._Median_of_Two_Sorted_Arrays.md b/docs/Algorithm/Leetcode/C++/0004._Median_of_Two_Sorted_Arrays.md new file mode 100755 index 00000000..9e8c456b --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0004._Median_of_Two_Sorted_Arrays.md @@ -0,0 +1,159 @@ +# 004. Median of Two Sorted Arrays + +**难度Hard** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/median-of-two-sorted-arrays/submissions/ + +> 内容描述 + +``` +There are two sorted arrays nums1 and nums2 of size m and n respectively. + +Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)). + +You may assume nums1 and nums2 cannot be both empty. + +Example 1: + +nums1 = [1, 3] +nums2 = [2] + +The median is 2.0 +Example 2: + +nums1 = [1, 2] +nums2 = [3, 4] + +The median is (2 + 3)/2 = 2.5 +``` + +> 思路1 +******- 时间复杂度: O(n + m)******- 空间复杂度: O(1)****** + +直接用暴利搜索,类似与归并两个有序的数组。遍历两个数组,当总长度等于(m+n)/ 2,注意区分总长度奇数和偶数 +```cpp +class Solution { +public: + double findMedianSortedArrays(vector& nums1, vector& nums2) { + int temp = (nums1.size() + nums2.size()) / 2,count1 = 0,i = 0,j = 0,current,pre; + while(i < nums1.size() && j < nums2.size() && count1 <= temp) + { + pre = current; + if(nums1[i] > nums2[j]) + current = nums2[j++]; + else + current = nums1[i++]; + ++count1; + } + if(count1 <= temp) + { + if(i < nums1.size()) + while(count1 <= temp) + { + pre = current; + current = nums1[i++]; + ++count1; + } + else + while(count1 <= temp) + { + pre = current; + current = nums2[j++]; + ++count1; + } + } + if((nums1.size() + nums2.size()) % 2) + return current; + double ans = (current + pre) / 2.0; + return ans; + } +}; +``` +> 思路2 +******- 时间复杂度: O(lg(min(n.m)))******- 空间复杂度: O(1)****** + +我们可以通过二分查找优化算法,利用中位数的定义,将两个数组划分为左右两个部分,nums1左半部分加nums2左半部分等于nums1右半部分加nums2的右半部分,如果总长度为偶数,那么nums1左半部分加nums2左半部分等于nums1右半部分加nums2的右半部分加1。并且```max(nums1[i],nums2[j]) <= max(nums1[i + 1],nums2[j + 1])```,接下来我们只要二分查找找i,并且要注意边界情况 + +```cpp +class Solution { +public: + double findMedianSortedArrays(vector& nums1, vector& nums2) { + int m = nums1.size(),n = nums2.size(),sum = m + n; + if(!nums1.size()) + return sum % 2 ? nums2[sum / 2] : (nums2[sum /2] + nums2[sum / 2 - 1]) / 2.0; + if(!nums2.size()) + return sum % 2 ? nums1[sum / 2] : (nums1[sum /2] + nums1[sum / 2 - 1]) / 2.0; + if(m > n) + return findMedianSortedArrays(nums2,nums1); + int l = 0,r = m - 1; + while(l < r) + { + int mid = (l + r) / 2; + int j = (sum + 1) / 2 - mid - 2; + int min1 = max(nums1[mid],nums2[j]),max1 = min(nums1[mid + 1],nums2[j + 1]); + if(min1 <= max1) + return sum % 2 ? min1 : (min1 + max1) / 2.0; + else if(nums1[mid] > nums2[j]) + r = mid - 1; + else + l = mid + 1; + } + int j = (sum + 1) / 2 - l - 2; + int min1,max1; + if(j < 0) + min1 = nums1[l]; + else + min1 = max(nums1[l],nums2[j]); + if(l == nums1.size() - 1) + max1 = nums2[j + 1]; + else + max1 = min(nums1[l + 1],nums2[j + 1]); + if(min1 <= max1) + return sum % 2 ? min1 : (min1 + max1) / 2.0; + j++; + if(j < nums2.size() - 1) + max1 = min(nums1[l],nums2[j + 1]); + else + max1 = nums1[l]; + min1 = nums2[j]; + return sum % 2 ? min1 : (min1 + max1) / 2.0; + } +}; +``` +> 思路3 +******- 时间复杂度: O(lg(n+m))******- 空间复杂度: O(1)****** + +由于题目中建议我们在时间复杂度O(lg(m+n))中完成,我们可以把这题看成寻找第k大的值,这样我们可以递归的去做,每次查找k/2,知道k等于1,注意边界值的处理 +```cpp +class Solution { +public: +int getKth(vector nums1, int start1, int end1, vector nums2, int start2, int end2, int k) { + int len1 = end1 - start1 + 1; + int len2 = end2 - start2 + 1; + if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k); + if (len1 == 0) return nums2[start2 + k - 1]; + + if (k == 1) return min(nums1[start1], nums2[start2]); + + int i = start1 + min(len1, k / 2) - 1; + int j = start2 + min(len2, k / 2) - 1; + + if (nums1[i] > nums2[j]) { + return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1)); + } + else { + return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1)); + } + } +double findMedianSortedArrays(vector nums1, vector nums2) { + int n = nums1.size(); + int m = nums2.size(); + int left = (n + m + 1) / 2; + int right = (n + m + 2) / 2; + return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5; +} +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0005._Longest_Palindromic_Substring.md b/docs/Algorithm/Leetcode/C++/0005._Longest_Palindromic_Substring.md new file mode 100755 index 00000000..dff587dc --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0005._Longest_Palindromic_Substring.md @@ -0,0 +1,64 @@ +# 5. Longest Palindromic Substring + +**难度:Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-palindromic-substring/description/ + +> 内容描述 + +``` +Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. + +Example 1: + +Input: "babad" +Output: "bab" +Note: "aba" is also a valid answer. +Example 2: + +Input: "cbbd" +Output: "bb" +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)****** + + +这题如果用单纯暴力的解法,时间复杂度为 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]) + +```cpp +class Solution { +public: + int dp[1000][1000] = {0}; + string longestPalindrome(string s) { + int beg = 0,en = 1,ans = 0; + int length = s.length(); + for(int i = 0;i < length;++i) + { + dp[i][i] = 1; + if(i + 1 < length && s[i] == s[i + 1]) + dp[i][i + 1] = 1; + } + for(int i = 0;i < length;++i) + for(int j = 0;j <= i;++j) + { + if(i > j + 1) + dp[j][i] = (dp[j + 1][i - 1] && s[i] == s[j]); + if(dp[j][i] && i - j + 1 > ans) + { + ans = i - j + 1; + beg = j; + en = i + 1; + } + } + string ret(s.begin() + beg,s.begin() + en); + return ret; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0006._ZigZag _Conversion.md b/docs/Algorithm/Leetcode/C++/0006._ZigZag _Conversion.md new file mode 100755 index 00000000..2338fc3d --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0006._ZigZag _Conversion.md @@ -0,0 +1,96 @@ +# 6. ZigZag Conversion + +**难度:Medium** + +## 刷题内容 + +> 原题连接 + +*https://leetcode.com/problems/zigzag-conversion/description/ +* +> 内容描述 + +``` +The 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) + +P A H N +A P L S I I G +Y I R +And then read line by line: "PAHNAPLSIIGYIR" + +Write the code that will take a string and make this conversion given a number of rows: + +string convert(string s, int numRows); +Example 1: + +Input: s = "PAYPALISHIRING", numRows = 3 +Output: "PAHNAPLSIIGYIR" +Example 2: + +Input: s = "PAYPALISHIRING", numRows = 4 +Output: "PINALSIGYAHRPI" +Explanation: + +P I N +A L S I G +Y A H R +P I +``` + +## 解题方案 + +> 思路1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N + numRows)****** + + +这道题理解了题目意思其实不难,一般人可能会开一个二维数组,然后就按题目意思储存,这样做的话时间复杂度和空间复杂度都比较大,这里我用的方法先用一个 string 类型变量 str ,resize 和输入的 s 长度相等,接着只要遍历找到 s[i] 在 str 中的位置即可 + + +```cpp +class Solution { +public: + string convert(string s, int numRows) { + string newStr; + if(!s.length() || numRows == 1) + return s; + newStr.resize(s.length()); + int num = numRows * 2 - 2,col = s.length() / num,rem = (s.length() - 1) % num; + vector rowNum; + for(int i = 0;i < numRows;++i) + if(!i) + s.length() % num ? rowNum.push_back(col + 1) : rowNum.push_back(col); + else + { + if(i == numRows - 1) + rem >= i ? rowNum.push_back(rowNum[i - 1] + (s.length() - 1) / num + 1) : rowNum.push_back(rowNum[i - 1] + (s.length() - 1) / num); + else + { + int temp = 2 * numRows - i - 2,col1 = (s.length() - 1) / num; + if(rem >= temp) + rowNum.push_back(rowNum[i - 1] + (col1 + 1) * 2); + else if(rem >= i) + rowNum.push_back(rowNum[i - 1] + col1 * 2 + 1); + else + rowNum.push_back(rowNum[i - 1] + col1 * 2); + } + } + for(int i = 0;i < s.length();++i) + { + int index1 = i % num; + int index2 = i / num; + if(!index1) + newStr[index2] = s[i]; + else if(index1 == numRows - 1) + newStr[index2 + rowNum[index1 - 1]] = s[i]; + else if(index1 < numRows) + newStr[index2 * 2 + rowNum[index1 - 1]] = s[i]; + else + { + int index3 = 2 * numRows - index1 - 2; + newStr[index2 * 2 + 1 + rowNum[index3 - 1]] = s[i]; + } + } + return newStr; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0007._Reverse_Integer.md b/docs/Algorithm/Leetcode/C++/0007._Reverse_Integer.md new file mode 100755 index 00000000..c11dccfb --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0007._Reverse_Integer.md @@ -0,0 +1,50 @@ +# 7. Reverse Integer + +**Ѷ:Easy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/reverse-integer/ + +> + +``` +Given a 32-bit signed integer, reverse digits of an integer. + +Example 1: + +Input: 123 +Output: 321 +Example 2: + +Input: -123 +Output: -321 +Example 3: + +Input: 120 +Output: 21 +Note: +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. +``` + +> ˼·1 +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +һeasyĿμλҪעⳬintķΧ + +```cpp +class Solution { +public: + int reverse(int x) { + long long val = 0; + do + { + val = val * 10 + x % 10; + x /= 10; + } while (x); + + return (val > INT_MAX || val < INT_MIN) ? 0 : val; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0008._String_to_Integer_(atoi).md b/docs/Algorithm/Leetcode/C++/0008._String_to_Integer_(atoi).md new file mode 100755 index 00000000..006e4cb5 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0008._String_to_Integer_(atoi).md @@ -0,0 +1,104 @@ +# 8. String to Integer (atoi) + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/string-to-integer-atoi/ + +> + +``` +Implement atoi which converts a string to an integer. + +The 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. + +The 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. + +If 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. + +If no valid conversion could be performed, a zero value is returned. + +Note: + +Only the space character ' ' is considered as whitespace character. +Assume 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. +Example 1: + +Input: "42" +Output: 42 +Example 2: + +Input: " -42" +Output: -42 +Explanation: The first non-whitespace character is '-', which is the minus sign. + Then take as many numerical digits as possible, which gets 42. +Example 3: + +Input: "4193 with words" +Output: 4193 +Explanation: Conversion stops at digit '3' as the next character is not a numerical digit. +Example 4: + +Input: "words and 987" +Output: 0 +Explanation: The first non-whitespace character is 'w', which is not a numerical + digit or a +/- sign. Therefore no valid conversion could be performed. +Example 5: + +Input: "-91283472332" +Output: -2147483648 +Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer. + Thefore INT_MIN (?231) is returned. +``` + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)****** + +һַתַֻֻ֣Ҫַתint͵ּɣģҪעֵ߽жֵΪЧʡȼ1032η10nηֵ + +```cpp +class Solution { +public: + int myAtoi(string str) { + int i = 0,count1 = 0; + long long arr[34]; + arr[0] = 1; + for(int i = 1;i < 34;++i) + arr[i] = arr[i - 1] * 10; + while(str[i] == ' ') + i++; + if(str[i] == '-' || str[i] == '+') + { + if(str[i] == '-') + count1 = 1; + i++; + } + if(!isdigit(str[i])) + return 0; + while(str[i] == '0') + i++; + long long num = 0; + int j = i; + while(j < str.length() && isdigit(str[j])) + j++; + if(j - i > 33) + return count1 ? INT_MIN : INT_MAX; + j--; + int t = 0; + while(j >= i) + { + num += (str[j] - '0') * arr[t++]; + if(!count1 && num > INT_MAX) + return INT_MAX; + if(count1 && num * -1 < INT_MIN) + return INT_MIN; + j--; + } + if(count1) + num *= -1; + return num; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0009._Palindrome_Number.md b/docs/Algorithm/Leetcode/C++/0009._Palindrome_Number.md new file mode 100755 index 00000000..2547c8c6 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0009._Palindrome_Number.md @@ -0,0 +1,102 @@ +# 9. Palindrome Number + +**难度:Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/palindrome-number/description/ +* +> 内容描述 + +``` +Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward. + +Example 1: + +Input: 121 +Output: true +Example 2: + +Input: -121 +Output: false +Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome. +Example 3: + +Input: 10 +Output: false +Explanation: Reads 01 from right to left. Therefore it is not a palindrome. +Follow up: + +Coud you solve it without converting the integer to a string? +``` + +## 解题方案 + +> 思路1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +这题的难度不大,由于是数字,判断回文只需要求出倒过来的数字,判断两者是否相等,不过要注意负数一定不是回文 + + +```cpp +class Solution { +public: + bool isPalindrome(int x) { + long long ret = 0; + int num = x; + if(x < 0) + return false; + while(num) + { + ret = 10 * ret + num % 10; + num /= 10; + } + if(ret == x) + return true; + return false; + } +}; +``` +> 思路2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +计算出数字的长度,用双指针法,一个指针指向头,另一个指向尾,相等就前一个指针加一,后一个指针减一,若不相等则返回 false + + +```cpp +class Solution { +public: + bool isPalindrome(int x) { + if (x < 0) + return false; + + int cnt = 0; + long fac = 1; + int div = INT_MAX; + while (div != 0) { + cnt++; + fac *= 10; + div = x/fac; + } + + fac /= 10; + for (int i=0; i难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/regular-expression-matching/description/ + +> 内容描述 + +``` +Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'. + +'.' Matches any single character. +'*' Matches zero or more of the preceding element. +The matching should cover the entire input string (not partial). + +Note: + +s could be empty and contains only lowercase letters a-z. +p could be empty and contains only lowercase letters a-z, and characters like . or *. + +Example 1: + +Input: +s = "aa" +p = "a" +Output: false +Explanation: "a" does not match the entire string "aa". + +Example 2: + +Input: +s = "aa" +p = "a*" +Output: true +Explanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa". + +Example 3: + +Input: +s = "ab" +p = ".*" +Output: true +Explanation: ".*" means "zero or more (*) of any character (.)". + +Example 4: + +Input: +s = "aab" +p = "c*a*b" +Output: true +Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab". + +Example 5: + +Input: +s = "mississippi" +p = "mis*is*p*." +Output: false +``` + +## 解题方案 + +> 思路1 +******- 时间复杂度: O(n^2)******- 空间复杂度: O(n^2)****** + +用动态规划的思路去解,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]``` + +```cpp +class Solution { +public: + bool isMatch(string s, string p) { + s.push_back(' '); + p.push_back(' '); + int len1 = s.length(),len2 = p.length(); + int dp[len1 + 1][len2 + 1]; + memset(dp,0,sizeof(dp)); + dp[0][0] = 1; + for(int i = 1;i < len2;++i) + if(p[i] == '*') + dp[0][i + 1] = dp[0][i - 1]; + for(int i = 0;i < len1;++i) + for(int j = 0;j < len2;++j) + if(j && p[j] == '*') + { + dp[i + 1][j + 1] = (p[j - 1] == s[i] || p[j - 1] == '.') && (dp[i][j] || dp[i][j + 1]); + dp[i + 1][j + 1] = dp[i + 1][j + 1] || dp[i + 1][j - 1]; + } + else if(s[i] == p[j] || p[j] == '.') + dp[i + 1][j + 1] = dp[i][j]; + return dp[len1][len2]; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0011._Container_With_Most_Water.md b/docs/Algorithm/Leetcode/C++/0011._Container_With_Most_Water.md new file mode 100755 index 00000000..31679e93 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0011._Container_With_Most_Water.md @@ -0,0 +1,41 @@ +# 11. container with most water + +**难度:Medium** + +## 刷题内容 + +> 原题连接 + +*https://leetcode.com/problems/container-with-most-water/ +* +> 内容描述 + +``` +Given 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. + +Note: You may not slant the container and n is at least 2. +``` + +## 解题方案 + +> 思路 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +这道题刚开始很容易想到用暴力的方法去解,但是时间复杂度为 O(n^2) 测试之后发现是 TLE,那么我们就要对算法进行优化,这里我们用双指针法,定义两个指针,一个指向头,另一个指向尾部,比较两个指针指向的数的大小,若头部的大,则指向头部的指针向后移动一位,反之,则指向尾部的指针向前移动一位。 + + +```cpp +class Solution { +public: + int maxArea(vector& height) { + int i = 0,j = height.size() - 1,ans = INT_MIN; + while(i < j) + { + int t = min(height[i],height[j]); + ans = max(ans,t * (j - i)); + height[i] < height[j] ? i++ : j--; + } + return ans; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0012._Integer_to_Roman.md b/docs/Algorithm/Leetcode/C++/0012._Integer_to_Roman.md new file mode 100755 index 00000000..11ef18ee --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0012._Integer_to_Roman.md @@ -0,0 +1,164 @@ +# 12. Integer to Roman + +**Ѷ:Medium** + +## ˢ + +> ԭ + +* https://leetcode.com/problems/rotate-list/ + +> + +``` +Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. + +Symbol Value +I 1 +V 5 +X 10 +L 50 +C 100 +D 500 +M 1000 +For 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. + +Roman 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: + +I can be placed before V (5) and X (10) to make 4 and 9. +X can be placed before L (50) and C (100) to make 40 and 90. +C can be placed before D (500) and M (1000) to make 400 and 900. +Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999. + +Example 1: + +Input: 3 +Output: "III" +Example 2: + +Input: 4 +Output: "IV" +Example 3: + +Input: 9 +Output: "IX" +Example 4: + +Input: 58 +Output: "LVIII" +Explanation: L = 50, V = 5, III = 3. +Example 5: + +Input: 1994 +Output: "MCMXCIV" +Explanation: M = 1000, CM = 900, XC = 90 and IV = 4. + +``` + + + +> ˼·1 + +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)****** + +Ŀѣֱһֱд + +```cpp +class Solution { +public: + string intToRoman(int num) { + string ans; + vector table; + int a = 0; + int count = 0; + while(num){ + a = num%10; + num /= 10; + ++count; + if(count==1){ + if(a==1) table.push_back("I"); + else if(a==2) table.push_back("II"); + else if(a==3) table.push_back("III"); + else if(a==4) table.push_back("IV"); + else if(a==5) table.push_back("V"); + else if(a==6) table.push_back("VI"); + else if(a==7) table.push_back("VII"); + else if(a==8) table.push_back("VIII"); + else if(a==9) table.push_back("IX"); + } + else if(count==2){ + if(a==1) table.push_back("X"); + else if(a==2) table.push_back("XX"); + else if(a==3) table.push_back("XXX"); + else if(a==4) table.push_back("XL"); + else if(a==5) table.push_back("L"); + else if(a==6) table.push_back("LX"); + else if(a==7) table.push_back("LXX"); + else if(a==8) table.push_back("LXXX"); + else if(a==9) table.push_back("XC"); + } + else if(count==3){ + if(a==1) table.push_back("C"); + else if(a==2) table.push_back("CC"); + else if(a==3) table.push_back("CCC"); + else if(a==4) table.push_back("CD"); + else if(a==5) table.push_back("D"); + else if(a==6) table.push_back("DC"); + else if(a==7) table.push_back("DCC"); + else if(a==8) table.push_back("DCCC"); + else if(a==9) table.push_back("CM"); + } + else if(count==4){ + if(a==1) table.push_back("M"); + else if(a==2) table.push_back("MM"); + else if(a==3) table.push_back("MMM"); + } + } + for(int i = table.size()-1; i >= 0; --i){ + ans += table[i]; + } + return ans; + } +}; +``` + +> ˼·2 + +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +̫if elseIJÿǿԻһָŵдôÿ + +```cpp +class Solution { +public: + int arr[7] = {'I','V','X','L','C','D','M'}; + int arr1[13] = {1,4,5,9,10,40,50,90,100,400,500,900,1000}; + void f(int& num,int i,string& ans) + { + if(i % 2) + { + ans.push_back(arr[i / 4 * 2]); + ans.push_back(arr[i / 2 + 1]); + } + else + ans.push_back(arr[i / 2]); + num -= arr1[i]; + } + string intToRoman(int num) { + string ans; + while(num) + { + int i; + for(i = 0;i < 13;++i) + if(num < arr1[i]) + { + f(num,i - 1,ans); + break; + } + if(i == 13) + f(num,i - 1,ans); + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0014._Longest_Common_Prefix.md b/docs/Algorithm/Leetcode/C++/0014._Longest_Common_Prefix.md new file mode 100755 index 00000000..7f4e57db --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0014._Longest_Common_Prefix.md @@ -0,0 +1,58 @@ +# 14. Longest Common Prefix + +**Ѷ:Easy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/longest-common-prefix/ + +> + +``` +Write a function to find the longest common prefix string amongst an array of strings. + +If there is no common prefix, return an empty string "". + +Example 1: + +Input: ["flower","flow","flight"] +Output: "fl" +Example 2: + +Input: ["dog","racecar","car"] +Output: "" +Explanation: There is no common prefix among the input strings. +Note: + +All given inputs are in lowercase letters a-z. +``` + +> ˼·1 +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(1)****** + +ǰ׺ӴֻбӴӴɣҪעܴڿַ + +```cpp +class Solution { +public: + string longestCommonPrefix(vector& strs) { + string temp; + if(!strs.size() || !strs[0].length()) + return temp; + int j = 0; + while(1) + { + int i = 0; + int ch = strs[0][j]; + for(;i < strs.size();++i) + if(j >= strs[i].length() || strs[i][j] != ch) + break; + if(i != strs.size()) + break; + temp.push_back(strs[0][j++]); + } + return temp; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0015._3sum.md b/docs/Algorithm/Leetcode/C++/0015._3sum.md new file mode 100755 index 00000000..e77e5ff4 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0015._3sum.md @@ -0,0 +1,61 @@ +# 15. 3sum + +**难度:Medium** + +## 刷题内容 + +> 原题连接 + +*https://leetcode.com/problems/3sum/description/ +* +> 内容描述 + +``` +Given 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. + +Note: + +The solution set must not contain duplicate triplets. +``` + +## 解题方案 + +> 思路 +******- 时间复杂度: O(N ^ 2)******- 空间复杂度: O(N)****** + +之前做过两个数之和等于某个数的题目,其实这题也差不多,三数之和等于0,那么我们只要让另外两个数之和等于第三个数的相反数即可,不过这里要注意会存在重复,所以要去重 + + +```cpp +class Solution { +public: + vector> threeSum(vector& nums) { + vector > ret; + sort(nums.begin(),nums.end()); + for(int i = 0;i < nums.size();++i) + { + int t1 = i + 1,t2 = nums.size() - 1; + if(i && nums[i] == nums[i - 1]) + continue; + while(t1 < t2) + if(nums[t1] + nums[t2] == -nums[i]) + { + vector v; + v.push_back(nums[i]); + v.push_back(nums[t1]); + v.push_back(nums[t2]); + ret.push_back(v); + ++t1; + --t2; + } + else if(nums[t1] + nums[t2] < -nums[i]) + ++t1; + else + --t2; + } + auto pos = unique(ret.begin(),ret.end()); + ret.erase(pos,ret.end()); + return ret; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0016._3Sum_Closest.md b/docs/Algorithm/Leetcode/C++/0016._3Sum_Closest.md new file mode 100755 index 00000000..7cc1f3a0 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0016._3Sum_Closest.md @@ -0,0 +1,45 @@ +## 16. 3Sum Closest + +难度:Medium + +## 内容 + +> 原题链接:https://leetcode.com/problems/3sum-closest/description/ + +Given 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. + +Example: + +``` +Given array nums = [-1, 2, 1, -4], and target = 1. + +The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). +``` + +## 思路 + +先排序,遍历第一个数,第二和第三个数通过双指针查找,转化为2sum closest的问题。如果遇到和等于target的三个数,直接返回target。 + +## 代码 + +``` +class Solution { +public: + int threeSumClosest(vector& nums, int target) { + std::sort(nums.begin(), nums.end()); + int min_distance{INT_MAX}, sum{0}, cur_sum{0}; + for (auto it = nums.cbegin(); it != nums.cend(); ++it) + for (auto left_idx = std::next(it), right_idx = std::prev(nums.cend()); left_idx < right_idx; cur_sum > target ? --right_idx : ++left_idx) { + cur_sum = *it + *left_idx + *right_idx; + auto cur_distance = std::abs(cur_sum - target); + if (cur_sum == target) + return target; + else if (cur_distance < min_distance) { + min_distance = cur_distance; + sum = cur_sum; + } + } + return sum; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0017._Letter_Combinations_of_a_Phone_Number.md b/docs/Algorithm/Leetcode/C++/0017._Letter_Combinations_of_a_Phone_Number.md new file mode 100755 index 00000000..3b5763f2 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0017._Letter_Combinations_of_a_Phone_Number.md @@ -0,0 +1,68 @@ +# 17. Letter Combinations of a Phone Number + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/letter-combinations-of-a-phone-number/ + +> + +``` +Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. + +A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters. + + + +Example: + +Input: "23" +Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. +Note: + +Although the above answer is in lexicographical order, your answer could be in any order you want. +``` + +> ˼·1 +******- ʱ临Ӷ: O(2^n)******- ռ临Ӷ: O(1)****** + +ûݷȥ⣬Ƚַת֡79ֶ֮3ĸÿִĸûݷ + +```cpp +class Solution { +public: + void DFS(string& s,int i,vector& ans,string& temp) + { + if(i == s.length()) + { + ans.push_back(temp); + return; + } + int t = s[i] - '2'; + int ch_beg; + if(t < 6) + ch_beg = 'a' + t * 3; + else + ch_beg = 'a' + (t - 1) * 3 + 4; + int en = 3; + if(t == 5 || t == 7) + en = 4; + for(int j = 0;j < en;++j) + { + temp.push_back(ch_beg + j); + DFS(s,i + 1,ans,temp); + temp.pop_back(); + } + } + vector letterCombinations(string digits) { + vector ans; + if(!digits.size()) + return ans; + string temp; + DFS(digits,0,ans,temp); + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0018._4Sum.md b/docs/Algorithm/Leetcode/C++/0018._4Sum.md new file mode 100755 index 00000000..0f30d24a --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0018._4Sum.md @@ -0,0 +1,57 @@ +## 18. 4Sum + +难度:Medium + +## 内容 + +题目链接:https://leetcode.com/problems/4sum/description/ + +Given 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. + +Note: + +The solution set must not contain duplicate quadruplets. + +Example: + +``` +Given array nums = [1, 0, -1, 0, -2, 2], and target = 0. + +A solution set is: +[ + [-1, 0, 0, 1], + [-2, -1, 1, 2], + [-2, 0, 0, 2] +] +``` + +## 思路 + +思路和 3Sum 类似,多了一层for循环。为了避免重复,在存储结果的时候使用STL的set。 + +## 代码 + +``` +class Solution { +public: + vector> fourSum(vector& nums, int target) { + if (nums.size() < 4) return vector>{}; + std::set> res; + std::sort(nums.begin(), nums.end()); + for (size_t i = 0; i < nums.size() - 3; ++i) + for (size_t j = i + 1; j < nums.size() - 2; ++j) { + auto left_idx = j + 1; auto right_idx = nums.size() - 1; + int sum = 0; + for (left_idx = j + 1, right_idx = nums.size() - 1; left_idx < right_idx; sum > target ? --right_idx : ++left_idx) { + sum = nums[i] + nums[j] + nums[left_idx] + nums[right_idx]; + if (sum == target) { + vector res_single{nums[i], nums[j], nums[left_idx], nums[right_idx]}; + res.insert(res_single); + } + + } + } + return vector>(res.begin(), res.end()); + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0019._Remove_Nth_Node_From_End_of_List.md b/docs/Algorithm/Leetcode/C++/0019._Remove_Nth_Node_From_End_of_List.md new file mode 100755 index 00000000..3d45103f --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0019._Remove_Nth_Node_From_End_of_List.md @@ -0,0 +1,60 @@ +# 19. Remove Nth Node From End of List + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/remove-nth-node-from-end-of-list/ + +> + +``` +Given a linked list, remove the n-th node from the end of list and return its head. + +Example: + +Given linked list: 1->2->3->4->5, and n = 2. + +After removing the second node from the end, the linked list becomes 1->2->3->5. +``` + +> ˼· +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +ɾnΪ˷ֹΪ1ʱĿָ쳣ȲһͷֻҪȱܳȣܳȼȥ n ҪɾǰһͷijȣֻҪøѭҵɾҪɾĽڵ㼴ɡ + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* removeNthFromEnd(ListNode* head, int n) { + ListNode* current = head; + int num = 0; + while(current) + { + num++; + current = current ->next; + } + ListNode* n1 = new ListNode(0); + n1 ->next = head; + current = n1; + num -= n; + while(num) + { + num--; + current = current ->next; + } + ListNode* temp = current ->next; + current ->next = temp ->next; + return n1 ->next; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0020._Valid_Parentheses.md b/docs/Algorithm/Leetcode/C++/0020._Valid_Parentheses.md new file mode 100755 index 00000000..102c66ca --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0020._Valid_Parentheses.md @@ -0,0 +1,55 @@ +## 20. Valid Parentheses + **难度: Easy** +## 刷题内容 +> 原题连接 +* https://leetcode-cn.com/problems/valid-parentheses/ +> 内容描述 +``` +Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. + +An input string is valid if: + +Open brackets must be closed by the same type of brackets. +Open brackets must be closed in the correct order. +Note that an empty string is also considered valid. + +### Example +1. Input: "()" -> Output: true + +2. Input: "()[]{}" -> Output: true + +3. Input: "(]" -> Output: false + +4. Input: "([)]" -> Output: false + +5. Input: "{[]}" -> Output: true +``` +## 解题方案 +> 思路: +``` +利用栈先进后出的先天优势,解决匹配问题。 +``` +```cpp +bool isValid(string s) { + stack stacks; + for(int i=0;i难度:Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/merge-two-sorted-lists/description/ +* +> 内容描述 + +``` +Merge 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. + +Example: + +Input: 1->2->4, 1->3->4 +Output: 1->1->2->3->4->4 +``` + +## 解题方案 + +> 思路 +******- 时间复杂度: O(N + M)******- 空间复杂度: O(1)****** + +首先这两个链表是排序好的,那么我们先定义一个空链表,再定义两个指针 i,j,按照顺序比较两个链表,如果 i 指向的数字小于 j指向的数字,i 指向的节点插入新链表中,i = i -> next,反之则操作 j。不过要注意其中一个链表可能会先结束,所以另一个未结束的链表直接插入新链表即可 + + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + ListNode* h1 = l1; + ListNode* h2 = l2; + ListNode* t = new ListNode(0); + ListNode* curr = t; + while (h1 && h2) + { + if (h1->val <= h2->val) { + curr->next = h1; + h1 = h1->next; + } + else{ + curr->next = h2; + h2 = h2->next; + } + curr = curr->next; + } + while (h1) + { + curr->next = h1; + h1 = h1->next; + curr = curr->next; + } + while(h2) + { + curr->next = h2; + h2 = h2->next; + curr = curr->next; + } + ListNode* res = t->next; + delete t; + return res; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0022._Generate_Parentheses.md b/docs/Algorithm/Leetcode/C++/0022._Generate_Parentheses.md new file mode 100755 index 00000000..469322c3 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0022._Generate_Parentheses.md @@ -0,0 +1,50 @@ +# 22. Generate Parentheses + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/generate-parentheses/ + + > 内容描述 + + ``` +给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + +例如,给出 n = 3,生成结果为: + +[ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()" +] + ``` + +## 解题方案 +> 思路 1 +``` +回溯法 +``` + +```cpp +void dfs(int left, int total, string path, vector& ans){ + if(total==0&&left==0){ + ans.push_back(path); + return ; + } + if(left>0) + dfs(left-1, total-1, path+"(", ans); + if(left generateParenthesis(int n) { + vector ans; + string path=""; + dfs(n, n*2, path, ans); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0023._Merge_K_Sorted_Lists.md b/docs/Algorithm/Leetcode/C++/0023._Merge_K_Sorted_Lists.md new file mode 100755 index 00000000..93dca868 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0023._Merge_K_Sorted_Lists.md @@ -0,0 +1,125 @@ +# 23. merge k sorted lists + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/merge-k-sorted-lists/ + +> 内容描述 + +``` +Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. + +Example: + +Input: +[ + 1->4->5, + 1->3->4, + 2->6 +] +Output: 1->1->2->3->4->4->5->6 +``` + +## 解题方案 + +> 思路1 +******- 时间复杂度: O(Nlg(K))******- 空间复杂度: O(K)****** + +这里运用最小堆,先去每个链表的第一个元素构建最小堆,由于链表都是已排序的,因此,每次堆的顶部都是最小的元素,这里用优先队列实现最小堆。 + + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + struct cmp + { + bool operator()(ListNode* a, ListNode* b) const + { + return a ->val > b ->val; + } + }; + ListNode* mergeKLists(vector& lists) { + priority_queue,cmp> pq; + ListNode* ret = nullptr; + ListNode* current = nullptr; + for(int i = 0;i < lists.size();++i) + if(lists[i]) + pq.push(lists[i]); + while(pq.size()) + { + ListNode* temp = pq.top(); + pq.pop(); + if(!ret) + ret = temp; + else + current ->next = temp; + current = temp; + if(temp ->next) + pq.push(temp ->next); + } + return ret; + } +}; +``` +> 思路2 +******- 时间复杂度: O(Nlg(K))******- 空间复杂度: O(1)****** + +这个思路用分治思想,我们可以通过归并排序解决,首先前面已经做过了两个有序链表的排序,我们可以把链表看做元素,只要对数组 Lists进行归并排序即可。 + +```cpp +class Solution { +public: + ListNode* merge(ListNode* list1, ListNode* list2) { + ListNode head(0); + ListNode* tail = &head; + auto cur1 = list1; + auto cur2 = list2; + while (cur1 != nullptr && cur2 != nullptr) { + if (cur1->val < cur2->val) { + tail->next = cur1; + tail = tail->next; + cur1 = cur1->next; + } else { + tail->next = cur2; + tail = tail->next; + cur2 = cur2->next; + } + } + auto cur = cur1 == nullptr ? cur2 : cur1; + while (cur != nullptr) { + tail->next = cur; + tail = tail->next; + cur = cur->next; + } + return head.next; + } + ListNode* mergeSort(vector& lists, int start, int end) { + if (start > end) { + return nullptr; + } + if (start == end) { + return lists[start]; + } + int mid = start + (end - start) / 2; + auto list1 = mergeSort(lists, start, mid); + auto list2 = mergeSort(lists, mid + 1, end); + return merge(list1, list2); + } + ListNode* mergeKLists(vector& lists) { + int n = lists.size(); + return mergeSort(lists, 0, n - 1); + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0024._Swap_Nodes_in_Pairs.md b/docs/Algorithm/Leetcode/C++/0024._Swap_Nodes_in_Pairs.md new file mode 100755 index 00000000..4e812ada --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0024._Swap_Nodes_in_Pairs.md @@ -0,0 +1,53 @@ +# 24. Swap Nodes in Pairs + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/swap-nodes-in-pairs/ + + > 内容描述 + + ``` +给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 + +示例: + +给定 1->2->3->4, 你应该返回 2->1->4->3. +说明: + +你的算法只能使用常数的额外空间。 +你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 + ``` + +## 解题方案 +> 思路 1 +``` +链表反转 +``` + +```cpp +ListNode* swapPairs(ListNode* head) { + if(head==NULL||head->next==NULL) + return head; + + ListNode* slow=head; + ListNode* fast=head->next; + ListNode* pre=new ListNode(0); + ListNode* ans = pre; + while(slow&&fast){ + slow->next = fast->next; + fast->next = slow; + pre->next = fast; + if(slow->next==NULL||slow->next->next==NULL){ + break; + } + fast = slow->next->next; + pre = slow; + slow = slow->next; + } + return ans->next; +} +``` diff --git a/docs/Algorithm/Leetcode/C++/0025._Reverse_Nodes_In_K_Group.md b/docs/Algorithm/Leetcode/C++/0025._Reverse_Nodes_In_K_Group.md new file mode 100755 index 00000000..905c67aa --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0025._Reverse_Nodes_In_K_Group.md @@ -0,0 +1,76 @@ +# 25.reverse nodes in k group + +**ѶHard** + +## ˢ + +> ԭ + +* https://leetcode.com/problems/reverse-nodes-in-k-group/ + +> + +``` +Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. + +k 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. + +Example: + +Given this linked list: 1->2->3->4->5 + +For k = 2, you should return: 2->1->4->3->5 + +For k = 3, you should return: 3->2->1->4->5 + +Note: + +Only constant extra memory is allowed. +You may not alter the values in the list's nodes, only nodes itself may be changed. +``` +> ˼·1 +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +Ŀѣ˵ݹķȥ⣬Ŀеnote˵жĴռ䣬ݹɸĿռ䣬԰ѵݹijѭ»ǵݹİ汾 + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* reverseKGroup(ListNode* head, int k) { + if(!head) + return head; + ListNode* current = head,*next1,*pre = nullptr; + int m = 1; + while(m <= k && current) + { + next1 = current ->next; + current ->next = pre; + pre = current; + current = next1; + ++m; + } + if(m <= k) + { + while(current != head) + { + ListNode* temp = pre ->next; + pre ->next = current; + current = pre; + pre = temp; + } + pre = head; + } + else + head ->next = reverseKGroup(current,k); + return pre; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0026._Remove_Duplicates_From_Sorted_Array.md b/docs/Algorithm/Leetcode/C++/0026._Remove_Duplicates_From_Sorted_Array.md new file mode 100755 index 00000000..f03c9368 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0026._Remove_Duplicates_From_Sorted_Array.md @@ -0,0 +1,71 @@ +# 26.Remove Duplicates From Sorted Array + +**ѶEasy** + +## ˢ + +> ԭ + +* https://leetcode.com/problems/remove-duplicates-from-sorted-array/ +> + +``` +Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length. + +Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. + +Example 1: + +Given nums = [1,1,2], + +Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. + +It doesn't matter what you leave beyond the returned length. +Example 2: + +Given nums = [0,0,1,1,1,2,2,3,3,4], + +Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively. + +It doesn't matter what values are set beyond the returned length. +Clarification: + +Confused why the returned value is an integer but your answer is an array? + +Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well. + +Internally you can think of this: + +// nums is passed in by reference. (i.e., without making a copy) +int len = removeDuplicates(nums); + +// any modification to nums in your function would be known by the caller. +// using the length returned by your function, it prints the first len elements. +for (int i = 0; i < len; i++) { + print(nums[i]); +} +``` +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +Ѿõģֱӱ飬һָ i ָʼһ j ָڶ j ָ i ָ```++i,++j```ֻ```++j``` + +```cpp +class Solution { +public: + int removeDuplicates(vector& nums) { + int j = 0; + if(!nums.size()) + return 0; + for(int i = 1;i < nums.size();) + { + while(nums[j] == nums[i] && i < nums.size()) + ++i; + if(i == nums.size()) + break; + swap(nums[++j],nums[i++]); + } + return j + 1; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0027._Remove_Element.md b/docs/Algorithm/Leetcode/C++/0027._Remove_Element.md new file mode 100755 index 00000000..50ec5f20 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0027._Remove_Element.md @@ -0,0 +1,73 @@ +# 27.Remove Element + +**ѶEasy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/remove-element/ + +> + +``` +Given an array nums and a value val, remove all instances of that value in-place and return the new length. + +Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. + +The order of elements can be changed. It doesn't matter what you leave beyond the new length. + +Example 1: + +Given nums = [3,2,2,3], val = 3, + +Your function should return length = 2, with the first two elements of nums being 2. + +It doesn't matter what you leave beyond the returned length. +Example 2: + +Given nums = [0,1,2,2,3,0,4,2], val = 2, + +Your function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4. + +Note that the order of those five elements can be arbitrary. + +It doesn't matter what values are set beyond the returned length. +Clarification: + +Confused why the returned value is an integer but your answer is an array? + +Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well. + +Internally you can think of this: + +// nums is passed in by reference. (i.e., without making a copy) +int len = removeElement(nums, val); + +// any modification to nums in your function would be known by the caller. +// using the length returned by your function, it prints the first len elements. +for (int i = 0; i < len; i++) { + print(nums[i]); +} +``` +> ˼· +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +ǿԱ飬ѵ val ŵĺ벿־Сǿ˫ָʵ֡ nums[i] != val ʱnums[j++] = nums[i] +```cpp +class Solution { +public: + int removeElement(vector& nums, int val) { + int i ,count = 0,j = 0,numsSize = nums.size(); + for(i = 0;i < numsSize;i++) + { + if(nums[i] == val) + { + count++; + } + else + nums[j++] = nums[i]; + } + return numsSize - count; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0028._Implement_Strstr.md b/docs/Algorithm/Leetcode/C++/0028._Implement_Strstr.md new file mode 100755 index 00000000..2714a3a3 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0028._Implement_Strstr.md @@ -0,0 +1,61 @@ +# 28.implement strstr + +**ѶEasy** + +## ˢ + +> ԭ + +* https://leetcode.com/problems/implement-strstr/ +> + +``` +Implement strStr(). + +Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. + +Example 1: + +Input: haystack = "hello", needle = "ll" +Output: 2 +Example 2: + +Input: haystack = "aaaaa", needle = "bba" +Output: -1 +Clarification: + +What should we return when needle is an empty string? This is a great question to ask during an interview. + +For 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(). +``` +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +ֱӱ haystack ƥ䵽 needle һַʱͱ needleȽַ + +```cpp +class Solution { +public: + int strStr(string haystack, string needle) { + int j = 0,i = 0,index= 0; + while(i < haystack.size() && j < needle.size()) + { + if(haystack[i] == needle[j]) + { + if(!j) + index = i; + j++; + i++; + } + else + { + i = ++index; + j = 0; + } + } + if(j == needle.size()) + return index; + return -1; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0029._Divide_Two_Integers.md b/docs/Algorithm/Leetcode/C++/0029._Divide_Two_Integers.md new file mode 100755 index 00000000..c1b82a47 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0029._Divide_Two_Integers.md @@ -0,0 +1,80 @@ +# 29.divide two integers + +**ѶMedium** + +## ˢ + +> ԭ + +* https://leetcode.com/problems/divide-two-integers/ +> + +``` +Given two integers dividend and divisor, divide two integers without using multiplication, division and mod operator. + +Return the quotient after dividing dividend by divisor. + +The integer division should truncate toward zero. + +Example 1: + +Input: dividend = 10, divisor = 3 +Output: 3 +Example 2: + +Input: dividend = 7, divisor = -3 +Output: -2 +Note: + +Both dividend and divisor will be 32-bit signed integers. +The divisor will never be 0. +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 231 ? 1 when the division result overflows. + +``` +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +ֱñķ϶ʱ˿ռ任ʱ䣬 int Ϊ2^31 - 1 ĴСҲǹ̶ġñȶһres = 0ÿζ res += divisor * 2^n ֱdividend ٴ res = divisor * 2^(n-1)ʼֱijres + divisor > dividend + + +```cpp +class Solution { +public: + int divide(int dividend, int divisor) { + if(!dividend) + return 0; + long long arr[33]; + arr[0] = 1; + for(int i = 1;i < 33;++i) + arr[i] = arr[i - 1] * 2; + long long temp1 = dividend,temp2 = divisor; + if(temp1 < 0) + temp1 *= -1; + if(temp2 < 0) + temp2 *= -1; + long long res,pre = 0,ret = 0; + int count1 = 0; + while(1) + { + res = pre + arr[count1] * temp2; + if(res > temp1) + { + if(!count1) + break; + pre = pre + arr[count1 - 1] * temp2; + ret += arr[count1 - 1]; + count1 = 0; + } + else + count1++; + } + if(dividend < 0) + ret *= -1; + if(divisor < 0) + ret *= -1; + if(ret == 2147483648) + return ret - 1; + return ret; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0030._Substring_With_Concatenation_Of_All_Words.md b/docs/Algorithm/Leetcode/C++/0030._Substring_With_Concatenation_Of_All_Words.md new file mode 100755 index 00000000..9bc3b6cf --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0030._Substring_With_Concatenation_Of_All_Words.md @@ -0,0 +1,64 @@ +# 30.substring with concatenation of all words + +**难度Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/substring-with-concatenation-of-all-words/ + +> 内容描述 + +``` +You 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. + +Example 1: + +Input: + s = "barfoothefoobarman", + words = ["foo","bar"] +Output: [0,9] +Explanation: Substrings starting at index 0 and 9 are "barfoor" and "foobar" respectively. +The output order does not matter, returning [9,0] is fine too. +Example 2: + +Input: + s = "wordgoodstudentgoodword", + words = ["word","student"] +Output: [] + +``` +> 思路 +******- 时间复杂度: O(mlgn)******- 空间复杂度: O(m+n)****** + +这题可以两个 map 来解决,第一个 map 中存放了 words 中的所有单词和出现的次数,接下来遍历字符串,固定区间的大小为 words 的长度,存入另一个map,两个 map 相等就放入返回数组中 + +```cpp +class Solution { +public: + vector findSubstring(string s, vector& words) { + vector ans; + if(!s.length() || !words.size()) + return ans; + unordered_map m1; + int len = words.size(),wl = words[0].length(),sl = s.length(); + for(int i = 0;i < words.size();++i) + m1[words[i]]++; + int count1 = 0,reLen = wl * len,left = 0; + for(int i = 0;i < sl - wl * len + 1;++i) + { + unordered_map m2; + for(int j = 0,left = i;j < len;j ++) + { + string temp = s.substr(left,wl); + left += wl; + m2[temp]++; + } + if(m2 == m1) + ans.push_back(i); + } + return ans; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0031._Next_Permutatio.md b/docs/Algorithm/Leetcode/C++/0031._Next_Permutatio.md new file mode 100755 index 00000000..1c5bf396 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0031._Next_Permutatio.md @@ -0,0 +1,64 @@ +# 31.Next Permutatio + +**难度Medium** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/next-permutation/ + +> 内容描述 + +``` +Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers. + +If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order). + +The replacement must be in-place and use only constant extra memory. + +Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column. + +1,2,3 → 1,3,2 +3,2,1 → 1,2,3 +1,1,5 → 1,5,1 +``` +> 思路 +******- 时间复杂度: O(n)******- 空间复杂度: O(1)****** + +我们可以用两个指针表示需要交换的两个数,遍历数组。这题的最坏的情况下,数组降序排列,排序算法的复杂度也是O(n)。 + +```cpp +class Solution { +public: + void nextPermutation(vector& nums) { + int n1 = 0,n2 = 0; + for(int i = 1;i < nums.size();++i) + if(nums[i] > nums[n2]) + { + n1 = n2; + n2 = i; + } + else if((nums[i] < nums[n2] && nums[i] > nums[n1]) || nums[i] == nums[n2]) + n2 = i; + else if(nums[i] <= nums[n1]) + { + int j = i; + for(;j < nums.size() - 1;++j) + if(nums[j + 1] > nums[j]) + { + n1 = j; + n2 = j + 1; + break; + } + i = j + 1; + } + if(n1 == n2) + sort(nums.begin(),nums.end()); + else + { + swap(nums[n1],nums[n2]); + sort(nums.begin() + n1 + 1,nums.end()); + } + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0032._Longest_Valid_Parentheses.md b/docs/Algorithm/Leetcode/C++/0032._Longest_Valid_Parentheses.md new file mode 100755 index 00000000..fe49d253 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0032._Longest_Valid_Parentheses.md @@ -0,0 +1,57 @@ +# 32. Longest Valid Parentheses + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/longest-valid-parentheses/ + +> + +``` +Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring. + +Example 1: + +Input: "(()" +Output: 2 +Explanation: The longest valid parentheses substring is "()" +Example 2: + +Input: ")()())" +Output: 4 +Explanation: The longest valid parentheses substring is "()()" +``` + +> ˼·1 +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)****** + +DPķ⡣һջȥߵIJ֣'('λãֱһ')'ʱͼ¼ջ'('λãǾͿд״̬תƷ̡dp[i]ַеiԶλáһ')'ʱdp[i] = ջ'('λáڿԴţdp[dp[i] - 1]ڣdp[i] = dp[dp[i] - 1]Ҫע߽缴ɡ + +```cpp +class Solution { +public: + int longestValidParentheses(string s) { + int len = s.length(); + if(!len) + return 0; + int dp[len]; + memset(dp,-1,sizeof(dp)); + int ans = 0; + vector v; + for(int i = 0;i < len;++i) + if(s[i] == '(') + v.push_back(i); + else if(s[i] == ')' && v.size()) + { + dp[i] = v[v.size() - 1]; + if(dp[i] && dp[dp[i] - 1] >= 0) + dp[i] = dp[dp[i] - 1]; + ans = max(ans,i - dp[i] + 1); + v.pop_back(); + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0033._Search_in_Rotated_Sorted_Array.md b/docs/Algorithm/Leetcode/C++/0033._Search_in_Rotated_Sorted_Array.md new file mode 100755 index 00000000..e2cd5310 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0033._Search_in_Rotated_Sorted_Array.md @@ -0,0 +1,80 @@ +# 033. Search in Rotated Sorted Array + +**难度Medium** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/search-in-rotated-sorted-array/ + +> 内容描述 + +``` +Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. + +(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). + +You are given a target value to search. If found in the array return its index, otherwise return -1. + +You may assume no duplicate exists in the array. + +Your algorithm's runtime complexity must be in the order of O(log n). + +Example 1: + +Input: nums = [4,5,6,7,0,1,2], target = 0 +Output: 4 +Example 2: + +Input: nums = [4,5,6,7,0,1,2], target = 3 +Output: -1 +``` +> 思路1 +******- 时间复杂度: O(n)******- 空间复杂度: O(1)****** + +第一个方法是直接遍历数组,找到返回数组下标,找不到就返回-1 + +```cpp +class Solution { +public: + int search(vector& nums, int target) { + for(int i = 0;i < nums.size();++i) + if(nums[i] == target) + return i; + return -1; + } +}; +``` +> 思路2 +******- 时间复杂度: O(lgn)*****- 空间复杂度: O(1)****** + +第二个方法是用二分法找到旋转轴,再用二分法找到目标数 +```cpp +class Solution { +public: + int search(vector& nums, int target) { + int i = 0,j = nums.size() - 1; + if(!nums.size()) + return -1; + while(i < j - 1) + { + int mid = (i + j) / 2; + if(nums[i] < nums[mid]) + i = mid; + else + j = mid; + //cout << i << j << endl; + } + if(nums[i] <= nums[j]) + j = i; + //cout << j; + auto pos = lower_bound(nums.begin(),nums.begin() + j,target); + if(pos != nums.end() && (*pos) == target) + return pos - nums.begin(); + pos = lower_bound(nums.begin() + j,nums.end(),target); + if(pos != nums.end() && (*pos) == target) + return pos - nums.begin(); + return -1; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md b/docs/Algorithm/Leetcode/C++/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md new file mode 100755 index 00000000..122f32c4 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md @@ -0,0 +1,105 @@ +# 34. Find First and Last Position of Element in Sorted Array + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/ + +> + +``` +Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value. + +Your algorithm's runtime complexity must be in the order of O(log n). + +If the target is not found in the array, return [-1, -1]. + +Example 1: + +Input: nums = [5,7,7,8,8,10], target = 8 +Output: [3,4] +Example 2: + +Input: nums = [5,7,7,8,8,10], target = 6 +Output: [-1,-1] +``` + +> ˼·1 +******- ʱ临Ӷ: O(lgn)******- ռ临Ӷ: O(1)****** + +͵ĶȲĿǷtargetڷֱҵһֵtargetһtarget + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + int l = 0,r = nums.size(); + vector ans = {-1,-1}; + int mid = -1; + while(l < r) + { + mid = (r + l) / 2; + if(nums[mid] < target) + l = mid + 1; + else if(nums[mid] > target) + r = mid; + else + break; + } + if(mid == -1 || nums[mid] != target) + return ans; + int mid1 = l = mid; + r = nums.size(); + while(l < r) + { + mid = (r + l) / 2; + if(mid == nums.size()) + break; + if(nums[mid] > target) + r = mid; + else + l = mid + 1; + } + if(nums[mid] > target) + mid--; + ans[1] = mid; + l = 0; + r = mid1 + 1; + while(l < r) + { + mid = (r + l) / 2; + if(nums[mid] < target) + l = mid + 1; + else + r = mid; + } + if(nums[mid] < target) + mid++; + ans[0] = mid; + return ans; + } +}; +``` + +> ˼·2 +******- ʱ临Ӷ: O(lgn)******- ռ临Ӷ: O(1)****** + +õc++lower_boundupper_bound + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + auto pos1 = lower_bound(nums.begin(),nums.end(),target); + vector ans = {-1,-1}; + if(pos1 == nums.end() || (*pos1) != target) + return ans; + ans[0] = pos1 - nums.begin(); + auto pos2 = upper_bound(nums.begin(),nums.end(),target); + ans[1] = pos2 - nums.begin() - 1; + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0035._Search_Insert_Position.md b/docs/Algorithm/Leetcode/C++/0035._Search_Insert_Position.md new file mode 100755 index 00000000..396e361d --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0035._Search_Insert_Position.md @@ -0,0 +1,60 @@ +#35.search insert position + +**Ѷ:Easy** + +## ˢ + +> ԭ + +*https://leetcode.com/problems/search-insert-position/ +* +> + +``` +Given 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. + +You may assume no duplicates in the array. +``` +> ˼·1 +******- ʱ临Ӷ: O(lgN)******- ռ临Ӷ: O(1)****** + +Ѿõģһܵ͵Ķַ + +```cpp +class Solution { +public: + int searchInsert(vector& nums, int target) { + int first = 0,last = nums.size() - 1; + while(last > (first + 1)) + { + int medium = (last + first) / 2; + if(nums[medium] == target) + return medium; + else if(nums[medium] < target) + first = medium; + else + last = medium; + } + if(target > nums[last]) + return last + 1; + else if((target < nums[first]) || (target == nums[first])) + return first; + else + return last; + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(lgN)******- ռ临Ӷ: O(1)****** + +ʵ˼·ҲǶַֻc++ѾǷװlower_boundֱӵü +뿴ȥҲܶ +```cpp +class Solution { +public: + int searchInsert(vector& nums, int target) { + auto pos = lower_bound(nums.begin(),nums.end(),target); + return pos - nums.begin(); + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0036._Valid_Sudoku.md b/docs/Algorithm/Leetcode/C++/0036._Valid_Sudoku.md new file mode 100755 index 00000000..9dec0351 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0036._Valid_Sudoku.md @@ -0,0 +1,90 @@ +# 36. Valid Sudoku + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/valid-sudoku/ + +> + +``` +Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules: + +Each row must contain the digits 1-9 without repetition. +Each column must contain the digits 1-9 without repetition. +Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition. +A partially filled sudoku which is valid. + +The Sudoku board could be partially filled, where empty cells are filled with the character '.'. +Example 1: + +Input: +[ + ["5","3",".",".","7",".",".",".","."], + ["6",".",".","1","9","5",".",".","."], + [".","9","8",".",".",".",".","6","."], + ["8",".",".",".","6",".",".",".","3"], + ["4",".",".","8",".","3",".",".","1"], + ["7",".",".",".","2",".",".",".","6"], + [".","6",".",".",".",".","2","8","."], + [".",".",".","4","1","9",".",".","5"], + [".",".",".",".","8",".",".","7","9"] +] +Output: true +Example 2: + +Input: +[ + ["8","3",".",".","7",".",".",".","."], + ["6",".",".","1","9","5",".",".","."], + [".","9","8",".",".",".",".","6","."], + ["8",".",".",".","6",".",".",".","3"], + ["4",".",".","8",".","3",".",".","1"], + ["7",".",".",".","2",".",".",".","6"], + [".","6",".",".",".",".","2","8","."], + [".",".",".","4","1","9",".",".","5"], + [".",".",".",".","8",".",".","7","9"] +] +Output: false +Explanation: Same as Example 1, except with the 5 in the top left corner being + modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid. +Note: + +A Sudoku board (partially filled) could be valid but is not necessarily solvable. +Only the filled cells need to be validated according to the mentioned rules. +The given board contain only digits 1-9 and the character '.'. +The given board size is always 9x9. +``` + +> ˼·1 +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(1)****** + +board9x9ģʵʵʱ临ӶҲ9x9ġֻҪֱжÿÿкÿ9СǷظɡѶȲ + + +```cpp +class Solution { +public: + bool isValidSudoku(vector>& board) { + int arr[9][9]; + int arr1[9][9]; + int arr2[9][9]; + memset(arr,0,sizeof(arr)); + memset(arr2,0,sizeof(arr1)); + memset(arr1,0,sizeof(arr1)); + for(int i = 0;i < 9;++i) + for(int j = 0;j < 9;++j) + if(board[i][j] != '.') + { + if(arr[i][board[i][j] - '1'] || arr1[j][board[i][j] -'1'] || arr2[3 * (i / 3) + (j / 3)][board[i][j] -'1']) + return 0; + arr[i][board[i][j] - '1'] = 1; + arr1[j][board[i][j] -'1'] = 1; + arr2[3 * (i / 3) + (j / 3)][board[i][j] -'1'] = 1; + } + return 1; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0038._Count_and_Say.md b/docs/Algorithm/Leetcode/C++/0038._Count_and_Say.md new file mode 100755 index 00000000..064f7fbb --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0038._Count_and_Say.md @@ -0,0 +1,69 @@ +# 38. Count and Say + +**Ѷ:Easy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/count-and-say/ + +> + +``` +The count-and-say sequence is the sequence of integers with the first five terms as following: + +1. 1 +2. 11 +3. 21 +4. 1211 +5. 111221 +1 is read off as "one 1" or 11. +11 is read off as "two 1s" or 21. +21 is read off as "one 2, then one 1" or 1211. + +Given an integer n where 1 n 30, generate the nth term of the count-and-say sequence. + +Note: Each term of the sequence of integers will be represented as a string. + + +Example 1: + +Input: 1 +Output: "1" +Example 2: + +Input: 4 +Output: "1211" +``` + +> ˼· +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +ҪŪĿ˼n == 1ʱ1һ1 one 1n == 2ʱǡ1121 two 1n == 3ʱǡ211211 one 2 one 1n == 4ʱǡ1211ƣдѭģIJɡ + +```cpp +class Solution { +public: + string countAndSay(int n) { + string str; + str.push_back('0' + 1); + n--; + while(n) + { + string temp; + for(int i = 0;i < str.length();) + { + int j = 0; + while(i + j < str.length() && str[i] == str[j + i]) + ++j; + temp.push_back('0' + j); + temp.push_back(str[i]); + i += j; + } + --n; + str = temp; + } + return str; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0039._Combination_Sum.md b/docs/Algorithm/Leetcode/C++/0039._Combination_Sum.md new file mode 100755 index 00000000..37226b70 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0039._Combination_Sum.md @@ -0,0 +1,69 @@ +# 39. Combination Sum + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/combination-sum/ + + > 内容描述 + + ``` +给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 + +candidates 中的数字可以无限制重复被选取。 + +说明: + +所有数字(包括 target)都是正整数。 +解集不能包含重复的组合。 +示例 1: + +输入: candidates = [2,3,6,7], target = 7, +所求解集为: +[ + [7], + [2,2,3] +] +示例 2: + +输入: candidates = [2,3,5], target = 8, +所求解集为: +[ + [2,2,2,2], + [2,3,3], + [3,5] +] + ``` + +## 解题方案 +> 思路 1 +``` +回溯 +``` + +```cpp +void dfs(vector& candidates, int target, int index, vector& path, vector>& ans){ + if(target<0) + return ; + if(target == 0){ + ans.push_back(path); + return ; + } + for(int i=index;i> combinationSum(vector& candidates, int target) { + sort(candidates.begin(), candidates.end()); + vector> ans; + vector path; + dfs(candidates, target, 0, path, ans); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0040._Combination_Sum_II.md b/docs/Algorithm/Leetcode/C++/0040._Combination_Sum_II.md new file mode 100755 index 00000000..f837be35 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0040._Combination_Sum_II.md @@ -0,0 +1,70 @@ +# 40. Combination Sum II + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/combination-sum-ii/ + + > 内容描述 + + ``` +给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 + +candidates 中的每个数字在每个组合中只能使用一次。 + +说明: + +所有数字(包括目标数)都是正整数。 +解集不能包含重复的组合。 +示例 1: + +输入: candidates = [10,1,2,7,6,1,5], target = 8, +所求解集为: +[ + [1, 7], + [1, 2, 5], + [2, 6], + [1, 1, 6] +] +示例 2: + +输入: candidates = [2,5,2,1,2], target = 5, +所求解集为: +[ + [1,2,2], + [5] +] + ``` + +## 解题方案 +> 思路 1 +``` +回溯 +``` + +```cpp +void dfs(vector& candidates, int target, int index, vector& path, vector>& ans){ + if(target<0) + return ; + if(target == 0){ + ans.push_back(path); + return ; + } + for(int i=index;i index && candidates[i] == candidates[i - 1]) continue; + path.push_back(candidates[i]); + dfs(candidates, target-candidates[i], i+1, path, ans); + path.pop_back(); + } +} +vector> combinationSum2(vector& candidates, int target) { + vector> ans; + vector path; + sort(candidates.begin(), candidates.end()); + dfs(candidates, target, 0, path, ans); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0041._First_Missing_Positive.md b/docs/Algorithm/Leetcode/C++/0041._First_Missing_Positive.md new file mode 100755 index 00000000..9daeed7e --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0041._First_Missing_Positive.md @@ -0,0 +1,52 @@ +# 041.First Missing Positive + +**ѶHard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/first-missing-positive/ + +> + +``` +Given an unsorted integer array, find the smallest missing positive integer. + +Example 1: + +Input: [1,2,0] +Output: 3 +Example 2: + +Input: [3,4,-1,1] +Output: 2 +Example 3: + +Input: [7,8,9,11,12] +Output: 1 +``` +> ˼· +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +տʼĿ˼ˣ֮ACˡʵĴռ䣬Ӧû뵽ֱ hash УǿԱ飬1ĵһ12ڣĵڶλӣ + +```cpp +class Solution { +public: + int firstMissingPositive(vector& nums) { + if(!nums.size()) + return 1; + for(int i = 0;i < nums.size();) + { + if(nums[i] < nums.size() && nums[i] != nums[nums[i] - 1]) + swap(nums[i],nums[nums[i] - 1]); + else + ++i; + } + for(int i = 0;i < nums.size();++i) + if(nums[i] != i + 1) + return i + 1; + return nums.size() + 1; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0042._Trapping_Rain_Water.md b/docs/Algorithm/Leetcode/C++/0042._Trapping_Rain_Water.md new file mode 100755 index 00000000..fe712f71 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0042._Trapping_Rain_Water.md @@ -0,0 +1,56 @@ +# 42. Trapping Rain Water + +**ѶHard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/trapping-rain-water/ + +> + +``` +Given 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. + +Example: + +Input: [0,1,0,2,1,0,1,3,2,1,2,1] +Output: 6 +``` + +¼ l = 0飬 height[i] < height[l],˵λ޷ˮ¼޷ˮ height[i] >= height[l]˵[i,l]ڿԻˮȻȥ޷ˮǻˮ֮ l != height.size() - 1飬衣 +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +```cpp +class Solution { +public: + int trap(vector& height) { + int l = 0,sum1 = 0,water = 0,i; + for(i = 1;i < height.size();++i) + if(height[i] >= height[l]) + { + water = water + height[l] * (i - l - 1) - sum1; + l = i; + sum1 = 0; + } + else + sum1 += height[i]; + if(l != (height.size() - 1)) + { + int temp = l; + sum1 = 0; + for(i = height.size() - 2,l = height.size() - 1;i >= temp;--i) + if(height[i] >= height[l]) + { + water = water + height[l] * (l- i - 1) - sum1; + l = i; + sum1 = 0; + } + else + sum1 += height[i]; + } + return water; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0043._Multiply_Strings.md b/docs/Algorithm/Leetcode/C++/0043._Multiply_Strings.md new file mode 100755 index 00000000..50aee87d --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0043._Multiply_Strings.md @@ -0,0 +1,74 @@ +# 43. Multiply Strings + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/multiply-strings/ + +> + +``` +Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string. + +Example 1: + +Input: num1 = "2", num2 = "3" +Output: "6" +Example 2: + +Input: num1 = "123", num2 = "456" +Output: "56088" +Note: + +The length of both num1 and num2 is < 110. +Both num1 and num2 contain only digits 0-9. +Both num1 and num2 do not contain any leading zero, except the number 0 itself. +You must not use any built-in BigInteger library or convert the inputs to integer directly. +``` + +> ˼·1 +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(1)****** + +ֱȽϴ󳬹long longֵ˲ת֣ģֵij˷ÿһλ¼һַС + +```cpp +class Solution { +public: + string multiply(string num1, string num2) { + string ans; + int d[120][120]; + memset(d,0,sizeof(d)); + for(int i = num2.size() - 1;i >= 0;--i) + { + int count1 = 0; + for(int j = num1.size()- 1;j >= 0;--j) + { + int pro_ans = (num1[j] - '0') * (num2[i] - '0'); + d[num2.size() - 1 - i][num1.size() - j - 1] = pro_ans % 10 + count1; + count1 = pro_ans / 10; + if(d[num2.size() - 1 - i][num1.size() - j - 1] >= 10) + { + count1++; + d[num2.size() - 1 - i][num1.size() - j - 1] %= 10; + } + } + d[num2.size() - 1 - i][num1.size()] = count1; + } + int count1 = 0; + for(int j = 0;j < num1.size() + num2.size();++j) + { + for(int i = 0;i <= num2.size();++i) + if(j - i >= 0 && j - i <= num1.size()) + count1 += d[i][j - i]; + ans.push_back(count1 % 10 + '0'); + count1 /= 10; + } + while(ans.length() > 1 && ans[ans.length() - 1] == '0') + ans.pop_back(); + reverse(ans.begin(),ans.end()); + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0044._Wildcard_Matching.md b/docs/Algorithm/Leetcode/C++/0044._Wildcard_Matching.md new file mode 100755 index 00000000..86a0eecb --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0044._Wildcard_Matching.md @@ -0,0 +1,98 @@ +# 44. Wildcard Matching + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/wildcard-matching/ + +> + +``` +Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*'. + +'?' Matches any single character. +'*' Matches any sequence of characters (including the empty sequence). +The matching should cover the entire input string (not partial). + +Note: + +s could be empty and contains only lowercase letters a-z. +p could be empty and contains only lowercase letters a-z, and characters like ? or *. +Example 1: + +Input: +s = "aa" +p = "a" +Output: false +Explanation: "a" does not match the entire string "aa". +Example 2: + +Input: +s = "aa" +p = "*" +Output: true +Explanation: '*' matches any sequence. +Example 3: + +Input: +s = "cb" +p = "?a" +Output: false +Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'. +Example 4: + +Input: +s = "adceb" +p = "*a*b" +Output: true +Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce". +Example 5: + +Input: +s = "acdcb" +p = "a*c?b" +Output: false +``` + +> ˼· +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n^2)****** + +տʼʱΪһģ⣬ʱŷֿ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] + +```cpp +class Solution { +public: + bool isMatch(string s, string p) { + if(!p.length()) + return !s.length(); + s.push_back(' '); + int dp[p.length() + 1][s.length() + 1]; + for(int i =0;i <= p.length();++i) + for(int j = 0;j <= s.length();++j) + dp[i][j] = 0; + + int count1 = 1; + dp[0][0] = 1; + for(int i = 0;i < p.length();++i) + { + for(int j = 0;j < s.length();++j) + if(p[i] == '?' || p[i] == s[j]) + dp[i + 1][j + 1] = dp[i][j]; + else if(p[i] == '*' && dp[i][j]) + { + dp[i + 1][j + 1] = 1; + dp[i + 1][j] = 1; + ++j; + while(j < s.length()) + { + dp[i + 1][j + 1] = 1; + ++j; + } + } + } + return dp[p.length()][s.length() - 1]; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0045._Jump_Game_II.md b/docs/Algorithm/Leetcode/C++/0045._Jump_Game_II.md new file mode 100755 index 00000000..04807a4b --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0045._Jump_Game_II.md @@ -0,0 +1,54 @@ +# 045. Jump Game II + +**ѶHard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/jump-game-ii/ + +> + +``` +Given an array of non-negative integers, you are initially positioned at the first index of the array. + +Each element in the array represents your maximum jump length at that position. + +Your goal is to reach the last index in the minimum number of jumps. + +Example: + +Input: [2,3,1,1,4] +Output: 2 +Explanation: The minimum number of jumps to reach the last index is 2. + Jump 1 step from index 0 to 1, then 3 steps to the last index. +``` + +> ˼· +******- ʱ临Ӷ: O(n)*****- ռ临Ӷ: O(1)****** + +տʼ뵽ʹö̬滮ʱ临ӶΪO(n)TLEˣʵO(n)ʱ临Ӷɵġ飬ÿζߵnums[i]ķΧߵԶľ롣¼ans +```cpp +class Solution { +public: + int jump(vector& nums) { + int i = 0,length = nums.size(),next = nums[0],ans = 0; + if(length < 2) + return 0; + while(i < length) + { + ++ans; + if(next >= length - 1) + return ans; + int current = i; + for(int j = current+1;j <= min(next,length - 1);++j) + { + i = max(i,nums[j] + j); + cout << i << " "; + } + swap(i,next); + cout << i << " "<< next << endl; + } + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0046._Permutations.md b/docs/Algorithm/Leetcode/C++/0046._Permutations.md new file mode 100755 index 00000000..b9b9c225 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0046._Permutations.md @@ -0,0 +1,99 @@ +# 46. Permutations + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/permutations/ + +> + +``` +Given a collection of distinct integers, return all possible permutations. + +Example: + +Input: [1,2,3] +Output: +[ + [1,2,3], + [1,3,2], + [2,1,3], + [2,3,1], + [3,1,2], + [3,2,1] +] +``` + +> ˼·1 +******- ʱ临Ӷ: O(n!*n)******- ռ临Ӷ: O(n)****** + +ܲĿݹһ⣬ÿζһ֮ɡ + +```cpp +class Solution { +public: + vector> permute(vector& nums) { + vector > ans; + if(!nums.size()) + return ans; + if(nums.size() == 1) + ans.push_back(nums); + for(int i = 0;i < nums.size();++i) + { + swap(nums[0],nums[i]); + vector v(nums.begin() + 1,nums.end()); + vector > ret = permute(v); + for(int i = 0;i < ret.size();++i) + { + ret[i].push_back(nums[0]); + ans.push_back(ret[i]); + } + swap(nums[0],nums[i]); + } + return ans; + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(n!)******- ռ临Ӷ: O(n)****** + +ǿԶ㷨ŻDFSķÿμ¼Ѿֽеݹ鼴 + +```cpp +class Solution { +public: +void DFS(int* visited,vector& nums,vector >& ans,vector temp) +{ + int count1 = 0; + for(int i = 0;i < nums.size();++i) + if(!visited[i]) + { + temp.push_back(nums[i]); + visited[i] = 1; + DFS(visited,nums,ans,temp); + temp.pop_back(); + visited[i] = 0; + count1 = 1; + } + if(!count1) + ans.push_back(temp); +} +vector> permute(vector& nums) { + vector > ans; + int visited[nums.size()]; + memset(visited,0,sizeof(visited)); + vector temp; + for(int i = 0; i < nums.size();++i) + { + visited[i] = 1; + temp.push_back(nums[i]); + DFS(visited,nums,ans,temp); + temp.pop_back(); + visited[i] = 0; + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0047._Permutations_II.md b/docs/Algorithm/Leetcode/C++/0047._Permutations_II.md new file mode 100755 index 00000000..a01e19a4 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0047._Permutations_II.md @@ -0,0 +1,102 @@ +# 47. Permutations II + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/permutations-ii/ + +> + +``` +Given a collection of numbers that might contain duplicates, return all possible unique permutations. + +Example: + +Input: [1,1,2] +Output: +[ + [1,1,2], + [1,2,1], + [2,1,1] +] +``` + +> ˼·1 +******- ʱ临Ӷ: O(n!*nlgn)******- ռ临Ӷ: O(n)****** + +ǰǵеƣԲο֮ǰĽ֮ⷨǰĿֱӾsetȥˣȻͨˣʱ临ӶȱȽϸߣҪŻ + +```cpp +class Solution { +public: + void DFS(int* visited,vector& nums,set >& ans,vector temp) + { + int count1 = 0; + for(int i = 0;i < nums.size();++i) + if(!visited[i]) + { + temp.push_back(nums[i]); + visited[i] = 1; + DFS(visited,nums,ans,temp); + temp.pop_back(); + visited[i] = 0; + count1 = 1; + } + if(!count1) + ans.insert(temp); + } + vector> permuteUnique(vector& nums) { + vector > ans; + int visited[nums.size()]; + memset(visited,0,sizeof(visited)); + set > s; + vector temp; + for(int i = 0; i < nums.size();++i) + { + visited[i] = 1; + temp.push_back(nums[i]); + DFS(visited,nums,s,temp); + temp.pop_back(); + visited[i] = 0; + } + for(auto pos = s.begin();pos != s.end();++pos) + ans.push_back(*pos); + return ans; + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(n!)******- ռ临Ӷ: O(n)****** + +֮ǰǵľ顣ҲͨDFSķȥ⣬и⣬ͬ־ͻظȶͬ־ͻһȻDFSʱǴҽеģ˵һ֮ǰȲ֮ǰѾˣôǾͲ + +```cpp +class Solution { +public: + vector> permuteUnique(vector& nums) { + const int n = nums.size(); + sort(nums.begin(), nums.end()); + vector> ret; + vector visited(n, 0), arr; + dfs(nums, ret, arr, visited); + return ret; + } + void dfs(vector& nums, vector>& ret, vector& arr, vector& visited) { + if (arr.size() == nums.size()) { + ret.push_back(arr); + return; + } + for (int i = 0; i < nums.size(); ++i) { + if (visited[i]) {continue;} + if (i -1 >= 0 && nums[i] == nums[i-1] && !visited[i-1]) {continue;} + arr.push_back(nums[i]); + visited[i] = 1; + dfs(nums, ret, arr, visited); + arr.pop_back(); + visited[i] = 0; + } + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0048._Rotate_Image.md b/docs/Algorithm/Leetcode/C++/0048._Rotate_Image.md new file mode 100755 index 00000000..30feef74 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0048._Rotate_Image.md @@ -0,0 +1,71 @@ +# 49. Group Anagrams + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode.com/problems/rotate-image/submissions/ + + > 内容描述 + + ``` +给你一个矩阵,让你顺时针旋转90° 思路: 不讨论复制一个数组然后在旋转的方法,因为太简单了。 下面的方法都是in-place的:。 + +示例: + +输入: +[ + [1,2,3], + [4,5,6], + [7,8,9] +], + +输出: +[ + [7,4,1], + [8,5,2], + [9,6,3] +] +说明: + +必须直接修改输入的2D矩阵。 +不要分配另一个2D矩阵并进行旋转。 + ``` + +## 解题方案 +> 思路 1 +``` +直接设置top, bottom, left, right四个变量,表示圈定当前要旋转的正方形范围, +然后按偏移计算位置,比如左上角的先和右上角交换,然后继续左上角和右下角交换这样即可. +``` + +```cpp +class Solution { +public: + void rotate(vector>& matrix) { + if(matrix.empty()) + return; + int top = 0, bottom = matrix.size() - 1; + int left = 0, right = matrix[0].size() - 1; + for(;top < bottom && left < right; ++top, ++left, --bottom, --right){ + for(int i = left; i < right; ++i){ + int dis = i - left; + + int row = top + dis; + int col = right; + swap(matrix[top][i], matrix[row][col]); + + row = bottom; + col = right - dis; + swap(matrix[top][i], matrix[row][col]); + + row = bottom - dis; + col = left; + swap(matrix[top][i], matrix[row][col]); + } + } + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0049._Group_Anagrams.md b/docs/Algorithm/Leetcode/C++/0049._Group_Anagrams.md new file mode 100755 index 00000000..e7cb3c46 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0049._Group_Anagrams.md @@ -0,0 +1,53 @@ +# 49. Group Anagrams + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/group-anagrams/submissions/ + + > 内容描述 + + ``` +给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + +示例: + +输入: ["eat", "tea", "tan", "ate", "nat", "bat"], +输出: +[ + ["ate","eat","tea"], + ["nat","tan"], + ["bat"] +] +说明: + +所有输入均为小写字母。 +不考虑答案输出的顺序。 + ``` + +## 解题方案 +> 思路 1 +``` +不同的组别字符串元素相同,顺序不同,所以排序后相同 +把排序后相同的元素映射到同一个vector +所有vector的组合就是结果 +``` + +```cpp +vector> groupAnagrams(vector& strs) { + vector> ans; + map> maps; + for(int i=0;i难度:Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/powx-n/ + +> 内容描述 + +``` +mplement pow(x, n), which calculates x raised to the power n (xn). + +Example 1: + +Input: 2.00000, 10 +Output: 1024.00000 +Example 2: + +Input: 2.10000, 3 +Output: 9.26100 +Example 3: + +Input: 2.00000, -2 +Output: 0.25000 +Explanation: 2-2 = 1/22 = 1/4 = 0.25 +Note: + +-100.0 < x < 100.0 +n is a 32-bit signed integer, within the range [?2^31, 2^31 ? 1] +``` + +> 思路1 +******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)****** + +求一个数的n次方是我们经常用的函数,一般刚开始可能会用暴力的方法去求,做了n次循环,但由于这里的n非常大,单纯的暴力会TLE,这里可以用分治的思想,比如``2*2*2*2``,我们前面已经计算过``2*2``了,那么后面就不用再计算依次,就相当于``2*2*(2*2)``,这样时间复杂度就变成了lgN,接下来只要主要幂次是负数的情况即可 + +```cpp +class Solution { +public: + double Pow(double x, long long n) + { + if(!n) + return 1; + if(n == 1) + return x; + double temp = Pow(x,(n)/ 2); + double ret; + if(n&1) + ret = temp * temp * x; + else + ret = temp * temp; + return ret; + } + double myPow(double x, int n) { + long long k = n; + if(n < 0) + x = 1 / x; + return Pow(x,n); + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0051._ N-Queens.md b/docs/Algorithm/Leetcode/C++/0051._ N-Queens.md new file mode 100755 index 00000000..cc76bf93 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0051._ N-Queens.md @@ -0,0 +1,91 @@ +# 51. N-Queens + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/n-queens/ + +> + +``` +The n-queens puzzle is the problem of placing n queens on an nn chessboard such that no two queens attack each other. + + + +Given an integer n, return all distinct solutions to the n-queens puzzle. + +Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively. + +Example: + +Input: 4 +Output: [ + [".Q..", // Solution 1 + "...Q", + "Q...", + "..Q."], + + ["..Q.", // Solution 2 + "Q...", + "...Q", + ".Q.."] +] +Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above. +``` + +> ˼·1 +******- ʱ临Ӷ: O(2^n)******- ռ临Ӷ: O(n)****** + +ûݷȥ⡣ʵľͼʵľͻˣֱ¼ֱбϷбϷǷлʺ + +```cpp +class Solution { +public: + void travel(int* d,vector& ret,int level,int n,vector >& ans,int* l,int* r) + { + if(level >= n) + ans.push_back(ret); + for(int i = 0;i < n;++i) + if(!d[i] && !r[level + i] && !l[i - level + n]) + { + d[i] = 1; + r[level + i] = 1; + l[i- level + n] = 1; + ret[level][i] = 'Q'; + travel(d,ret,level + 1,n,ans,l,r); + d[i] = 0; + r[level + i] = 0; + l[i- level + n] = 0; + ret[level][i] = '.'; + } + } + vector> solveNQueens(int n) { + int d[n]; + int l[2 * n]; + int r[2 * n]; + memset(d,0,sizeof(d)); + memset(l,0,sizeof(l)); + memset(r,0,sizeof(r)); + vector temp; + vector > ans; + string s(n,'.'); + for(int i = 0;i < n;++i) + temp.push_back(s); + for(int i = 0;i < n;++i) + { + temp[0][i] ='Q'; + d[i] = 1; + r[i] = 1; + l[i + n] = 1; + travel(d,temp,1,n,ans,l,r); + temp[0][i] = '.'; + d[i] = 0; + r[i] = 0; + l[i + n] = 0; + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0052._N-Queens_II.md b/docs/Algorithm/Leetcode/C++/0052._N-Queens_II.md new file mode 100755 index 00000000..2946e7e4 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0052._N-Queens_II.md @@ -0,0 +1,84 @@ +# 52. N-Queens II + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/n-queens-ii/ + +> + +``` +The n-queens puzzle is the problem of placing n queens on an nn chessboard such that no two queens attack each other. + + + +Given an integer n, return the number of distinct solutions to the n-queens puzzle. + +Example: + +Input: 4 +Output: 2 +Explanation: There are two distinct solutions to the 4-queens puzzle as shown below. +[ + [".Q..", // Solution 1 + "...Q", + "Q...", + "..Q."], + + ["..Q.", // Solution 2 + "Q...", + "...Q", + ".Q.."] +] +``` + +> ˼·1 +******- ʱ临Ӷ: O(2^n)******- ռ临Ӷ: O(n)****** + +һһֻ΢Ķһ¾ͺãIJ˵ + +```cpp +class Solution { +public: + int travel(int* d,int level,int n,int* l,int* r) + { + if(level >= n) + return 1; + int ans = 0; + for(int i = 0;i < n;++i) + if(!d[i] && !r[level + i] && !l[i - level + n]) + { + d[i] = 1; + r[level + i] = 1; + l[i- level + n] = 1; + ans += travel(d,level + 1,n,l,r); + d[i] = 0; + r[level + i] = 0; + l[i- level + n] = 0; + } + return ans; + } + int totalNQueens(int n) { + int d[n]; + int l[2 * n]; + int r[2 * n]; + memset(d,0,sizeof(d)); + memset(l,0,sizeof(l)); + memset(r,0,sizeof(r)); + int ans = 0; + for(int i = 0;i < n;++i) + { + d[i] = 1; + r[i] = 1; + l[i + n] = 1; + ans += travel(d,1,n,l,r); + d[i] = 0; + r[i] = 0; + l[i + n] = 0; + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0053._Maximum_Subarray.md b/docs/Algorithm/Leetcode/C++/0053._Maximum_Subarray.md new file mode 100755 index 00000000..d614e2d7 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0053._Maximum_Subarray.md @@ -0,0 +1,79 @@ +# 053. Maximum Subarray + +**ѶEasy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/maximum-subarray/ + +> + +``` +Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum. + +Example: + +Input: [-2,1,-3,4,-1,2,1,-5,4], +Output: 6 +Explanation: [4,-1,2,1] has the largest sum = 6. +Follow up: + +If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle. +``` + +> ˼·1 +******- ʱ临Ӷ: O(lgn)*****- ռ临Ӷ: O(1)****** + +ñķȥ⣬󲿷˶뵽ǿԶ㷨Ż÷η˼룬԰Ϊ飬ֵ[left,mid]䣬[mid + 1,right]ںmidڣֻҪȡֵɡ +```cpp +class Solution { +public: + int findArray(vector& nums,int beg,int en) + { + if(beg == en) + return nums[en]; + int mid = (beg + en) / 2; + int temp = max(findArray(nums,beg,mid),findArray(nums,mid + 1,en)); + int sum = 0,max1 = INT_MIN,max2 = INT_MIN; + for(int i = mid;i >= beg;--i) + { + sum += nums[i]; + max1 = max(max1,sum); + } + sum = 0; + for(int i = mid + 1;i <= en;++i) + { + sum += nums[i]; + max2 = max(max2,sum); + } + return max(temp,max1 + max2); + } + int maxSubArray(vector& nums) { + return findArray(nums,0,nums.size() - 1); + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(n)*****- ռ临Ӷ: O(1)****** + +ﻹO(n)ʱ临Ӷ⣬飬ret > 0,ret =nums[i] +ret += nums[i] + +```cpp +class Solution { +public: + int maxSubArray(vector& nums) { + int length = nums.size(),ret = nums[0],ans = nums[0]; + for(int i = 1;i < length;++i) + { + if(ret <= 0) + ret = nums[i]; + else + ret += nums[i]; + ans = max(ans,ret); + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0054._Spiral_Matrix.md b/docs/Algorithm/Leetcode/C++/0054._Spiral_Matrix.md new file mode 100755 index 00000000..c955cf57 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0054._Spiral_Matrix.md @@ -0,0 +1,70 @@ +# 54. Spiral Matrix + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/spiral-matrix/submissions/ + +> + +``` +Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. + +Example 1: + +Input: +[ + [ 1, 2, 3 ], + [ 4, 5, 6 ], + [ 7, 8, 9 ] +] +Output: [1,2,3,6,9,8,7,4,5] +Example 2: + +Input: +[ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9,10,11,12] +] +Output: [1,2,3,4,8,12,11,10,9,5,6,7] +``` + +> ˼·1 +******- ʱ临Ӷ: O(n*m)******- ռ临Ӷ: O(1)****** + +飬ҵɾУûʲôѶ + +```cpp +class Solution { +public: + vector spiralOrder(vector>& matrix) { + vector ans; + if(!matrix.size()) + return ans; + int row = matrix[0].size(),colunm = matrix.size(); + for(int i = 0;i < (matrix.size() + 1) / 2;++i) + { + if(row < 1 || colunm < 1) + break; + for(int j = 0;j < row;++j) + ans.push_back(matrix[i][i + j]); + if(colunm <= 1) + break; + for(int j = 1;j < colunm;++j) + ans.push_back(matrix[i + j][row + i - 1]); + if(row <= 1) + break; + for(int j = 1;j < row;++j) + ans.push_back(matrix[i + colunm - 1][row + i - 1 - j]); + for(int j = 1;j < colunm - 1;++j) + ans.push_back(matrix[i + colunm - 1 - j][i]); + row -= 2; + colunm -= 2; + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0055._Jump_Game.md b/docs/Algorithm/Leetcode/C++/0055._Jump_Game.md new file mode 100755 index 00000000..5d2d9ae4 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0055._Jump_Game.md @@ -0,0 +1,60 @@ +# 55. Jump Game + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/jump-game/submissions/ + +> + +``` +Given an array of non-negative integers, you are initially positioned at the first index of the array. + +Each element in the array represents your maximum jump length at that position. + +Determine if you are able to reach the last index. + +Example 1: + +Input: [2,3,1,1,4] +Output: true +Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index. +Example 2: + +Input: [3,2,1,0,4] +Output: false +Explanation: You will always arrive at index 3 no matter what. Its maximum + jump length is 0, which makes it impossible to reach the last index. +``` + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +տʼ뵽ľDPķDPĻʱ临ӶΪO(n^2)ȻǿԶ㷨Ż,ʱ临ӶO(n)ɡֻҪжÿһߵԶľ뼴ɣ[2,3,1,1,4]һֻߵ0ڶ[12]ԶľΪ4 + +```cpp +class Solution { +public: + bool canJump(vector& nums) { + if(nums.size() <= 1) + return 1; + for(int i = 0,r = 0;i < nums.size() - 1;) + { + int max1 = 0; + while(i <= r) + { + max1 = max(max1,i + nums[i]); + ++i; + } + //cout << max1 << endl; + if(max1 >= nums.size() - 1) + return 1; + if(max1 <= r) + return 0; + r = max1; + } + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0056._Merge_Intervals.md b/docs/Algorithm/Leetcode/C++/0056._Merge_Intervals.md new file mode 100755 index 00000000..493bddba --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0056._Merge_Intervals.md @@ -0,0 +1,62 @@ +# 56. Merge Intervals + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/merge-intervals/ + +> + +``` +Given a collection of intervals, merge all overlapping intervals. + +Example 1: + +Input: [[1,3],[2,6],[8,10],[15,18]] +Output: [[1,6],[8,10],[15,18]] +Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6]. +Example 2: + +Input: [[1,4],[4,5]] +Output: [[1,5]] +Explanation: Intervals [1,4] and [4,5] are considered overlapping. +``` + +> ˼·1 +******- ʱ临Ӷ: O(nlgn)******- ռ临Ӷ: O(1)****** + +Ҫȶ򣬰start򡣽ͱõ飬ཻͽ䶼ansཻͽϲIJans + +```cpp +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +class Solution { +public: + vector merge(vector& intervals) { + vector ans; + if(!intervals.size()) + return ans; + sort(intervals.begin(),intervals.end(),[](Interval a, Interval b){return a.start < b.start;}); + for(int i = 0;i < intervals.size() - 1;++i) + if(intervals[i + 1].start <= intervals[i].end) + { + intervals[i + 1].start = intervals[i].start; + intervals[i].end = max(intervals[i].end,intervals[i + 1].end); + intervals[i + 1].end = intervals[i].end; + } + else + ans.push_back(intervals[i]); + ans.push_back(intervals[intervals.size() - 1]); + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0057._Insert_Interval.md b/docs/Algorithm/Leetcode/C++/0057._Insert_Interval.md new file mode 100755 index 00000000..24b58bb5 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0057._Insert_Interval.md @@ -0,0 +1,93 @@ +# 57. Insert Interval + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/insert-interval/ + +> + +``` +Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). + +You may assume that the intervals were initially sorted according to their start times. + +Example 1: + +Input: intervals = [[1,3],[6,9]], newInterval = [2,5] +Output: [[1,5],[6,9]] +Example 2: + +Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] +Output: [[1,2],[3,10],[12,16]] +Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10]. +``` + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)****** + +ȼԭеλá飬αȽ䡣¼ l rֱҪӵյ㡣õλ֮ҵ intervals[i].end < l,ӽ飬[l,r] intervals[i].start > r䡣 + +```cpp +/** + * Definition for an interval. + * struct Interval { + * int start; + * int end; + * Interval() : start(0), end(0) {} + * Interval(int s, int e) : start(s), end(e) {} + * }; + */ +class Solution { +public: + vector insert(vector& intervals, Interval newInterval) { + int beg = newInterval.start,en = newInterval.end,l = beg,r = en; + int comp = beg; + for(int i = 0;i < intervals.size();++i) + { + if(comp < intervals[i].start) + { + comp == beg ? l = beg : r = en; + comp = comp == beg ? en : beg; + if(comp == en && en < intervals[i].start) + { + r = en; + break; + } + if(comp == beg) + break; + } + if(comp <= intervals[i].end) + { + + comp == beg ? l = intervals[i].start : r = intervals[i].end; + comp = comp == beg ? en : beg; + if(comp == en && en <= intervals[i].end) + { + r = intervals[i].end; + break; + } + if(comp == beg) + break; + } + } + int i = 0; + vector ans; + for(;i < intervals.size();++i) + if(intervals[i].end < l) + ans.push_back(intervals[i]); + else + break; + Interval i1(l,r); + ans.push_back(i1); + for(;i < intervals.size();++i) + if(intervals[i].start > r) + break; + for(;i < intervals.size();++i) + ans.push_back(intervals[i]); + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0058._Length_of_Last_Word.md b/docs/Algorithm/Leetcode/C++/0058._Length_of_Last_Word.md new file mode 100755 index 00000000..64093a4a --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0058._Length_of_Last_Word.md @@ -0,0 +1,37 @@ +# 058. Length of Last Word + +**难度Easy** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/length-of-last-word/ + +> 内容描述 + +``` +Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string. + +If the last word does not exist, return 0. +``` + +> 思路 +******- 时间复杂度: O(n)*****- 空间复杂度: O(1)****** + +这题我们只要从字符串的末尾开始向前找到第一个单词即可 +```cpp +class Solution { +public: + int lengthOfLastWord(string s) { + int i = s.length() - 1,length = s.length() - 1; + while((s[i] == ' ') &&(i >= 0)) + { + --i; + --length; + } + while((s[i] != ' ') && (i >= 0)) + --i; + return length- i; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0059._Spiral_Matrix_II.md b/docs/Algorithm/Leetcode/C++/0059._Spiral_Matrix_II.md new file mode 100755 index 00000000..a2cf72fb --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0059._Spiral_Matrix_II.md @@ -0,0 +1,60 @@ +# 59. Spiral Matrix II + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/spiral-matrix-ii/ + +> + +``` +Given a positive integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. + +Example: + +Input: 3 +Output: +[ + [ 1, 2, 3 ], + [ 8, 9, 4 ], + [ 7, 6, 5 ] +] +``` + +> ˼·1 +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n^2)****** + +֮ǰתһķֻҪȷһ󴢴棬Ϊvector鲻ò + +```cpp +class Solution { +public: + vector> generateMatrix(int n) { + int temp[n][n]; + int range = n,cur = 1; + for(int i = 0;i < (n + 1) / 2 ;++i) + { + for(int j = 0;j < range;++j) + temp[i][j + i] = cur++; + for(int j = 1;j < range;++j) + temp[i + j][i + range - 1] = cur++; + for(int j = 1;j < range;++j) + temp[i + range - 1][range + i - 1 -j] = cur++; + for(int j = 1;j < range - 1;++j) + temp[range + i - 1 - j][i] = cur++; + range -= 2; + } + vector > ans; + for(int i = 0;i < n;++i) + { + vector v; + for(int j = 0;j < n;++j) + v.push_back(temp[i][j]); + ans.push_back(v); + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0060._Permutation_Sequence.md b/docs/Algorithm/Leetcode/C++/0060._Permutation_Sequence.md new file mode 100755 index 00000000..083f9b76 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0060._Permutation_Sequence.md @@ -0,0 +1,73 @@ +# 60. Permutation Sequence + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/permutation-sequence/ + +> + +``` +The set [1,2,3,...,n] contains a total of n! unique permutations. + +By listing and labeling all of the permutations in order, we get the following sequence for n = 3: + +"123" +"132" +"213" +"231" +"312" +"321" +Given n and k, return the kth permutation sequence. + +Note: + +Given n will be between 1 and 9 inclusive. +Given k will be between 1 and n! inclusive. +Example 1: + +Input: n = 3, k = 3 +Output: "213" +Example 2: + +Input: n = 4, k = 9 +Output: "2314" +``` + +> ˼·1 +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n)****** + +Ƚ˳иַУȻѭnΣÿҵȷearseʱ临ӶΪnܵʱ临ӶΪn^2 + +```cpp +class Solution { +public: + string getPermutation(int n, int k){ + int arr[n + 1]; + string ans,org; + for(int i = 1;i <= n;++i) + { + org.push_back(i + '0'); + i == 1 ? arr[i] = 1 : arr[i] = arr[i - 1] * i; + } + for(int i = n - 1;i > 0;--i) + { + int t = k / arr[i]; + cout<< t<< endl; + k = (k) % arr[i]; + if(!k) + { + k = arr[i]; + t--; + } + ans.push_back(org[t]); + org.erase(org.begin() + t); + arr[i] = 0; + } + ans.push_back(org[0]); + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0061._Rotate_List.md b/docs/Algorithm/Leetcode/C++/0061._Rotate_List.md new file mode 100755 index 00000000..4174df16 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0061._Rotate_List.md @@ -0,0 +1,113 @@ +# 61. Rotate List + + + +**Ѷ:Medium** + + + +## ˢ + +> ԭ + + +* https://leetcode.com/problems/rotate-list/ + + + +> + + + +``` + +Given a linked list, rotate the list to the right by k places, where k is non-negative. + + + +Example 1: + + + +Input: 1->2->3->4->5->NULL, k = 2 + +Output: 4->5->1->2->3->NULL + +Explanation: + +rotate 1 steps to the right: 5->1->2->3->4->NULL + +rotate 2 steps to the right: 4->5->1->2->3->NULL + + +Example 2: + + +Input: 0->1->2->NULL, k = 4 + +Output: 2->0->1->NULL + +Explanation: + +rotate 1 steps to the right: 2->0->1->NULL + +rotate 2 steps to the right: 1->2->0->NULL + +rotate 3 steps to the right: 0->1->2->NULL + +rotate 4 steps to the right: 2->0->1->NULL + +``` + + + +> ˼·1 + +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)****** + + + +nָijȣknijȡ࣬Ϊkij֮һѭҪظ + + + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + int len = 0; + ListNode* h = head; + ListNode* pre; + while(h) + { + ++len; + pre = h; + h = h ->next; + } + if(!len) + return head; + int count1 = len - k % len; + if(count1 == len) + return head; + h = head; + ListNode* tail; + while(count1) + { + tail = h; + h = h ->next; + --count1; + } + pre ->next = head; + tail ->next = nullptr; + return h; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0062._Unique_Paths.md b/docs/Algorithm/Leetcode/C++/0062._Unique_Paths.md new file mode 100755 index 00000000..d45c7294 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0062._Unique_Paths.md @@ -0,0 +1,63 @@ +# 62. Unique Paths + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/unique-paths/ + + > 内容描述 + + ``` +一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 + +机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 + +问总共有多少条不同的路径? + + + +例如,上图是一个7 x 3 的网格。有多少可能的路径? + +说明:m 和 n 的值均不超过 100。 + +示例 1: + +输入: m = 3, n = 2 +输出: 3 +解释: +从左上角开始,总共有 3 条路径可以到达右下角。 +1. 向右 -> 向右 -> 向下 +2. 向右 -> 向下 -> 向右 +3. 向下 -> 向右 -> 向右 +示例 2: + +输入: m = 7, n = 3 +输出: 28 + ``` + +## 解题方案 +> 思路 1 +``` +动态规划,走到(i,j)可以从(i-1,j),(i, j-1)两个方向 +最优子结构: + dp[i, j] = dp[i-1, j]+dp[i, j-1] +``` + +```cpp +int uniquePaths(int m, int n) { + vector> dp(m, vector(n, 0)); + for(int i=0;i难度:Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/unique-paths-ii/ + +> 内容描述 + +``` +A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). + +The 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). + +Now consider if some obstacles are added to the grids. How many unique paths would there be? + + + +An obstacle and empty space is marked as 1 and 0 respectively in the grid. + +Note: m and n will be at most 100. + +Example 1: + +Input: +[ + [0,0,0], + [0,1,0], + [0,0,0] +] +Output: 2 +Explanation: +There is one obstacle in the middle of the 3x3 grid above. +There are two ways to reach the bottom-right corner: +1. Right -> Right -> Down -> Down +2. Down -> Down -> Right -> Right + +``` + + +> 思路1 + +******- 时间复杂度: O(n^2)******- 空间复杂度: O(n^2)****** + +运用动态规划的思想,写出状态转移方程,d(i,j) = d(i + 1,j) + d(i,j + 1),不过要注意边界值 + +```cpp +class Solution { +public: + int uniquePathsWithObstacles(vector>& obstacleGrid) { + int length1 = obstacleGrid.size(),length2 = obstacleGrid[0].size(); + long long dp[length1][length2]; + memset(dp,0,sizeof(dp)); + for(int i = length1 - 1;i >= 0;--i) + for(int j = length2 - 1;j >= 0;--j) + { + if(!obstacleGrid[i][j]) + { + if(i == length1 - 1 && j == length2 - 1) + dp[i][j] = 1; + else + { + if(i == length1 - 1) + dp[i][j] = dp[i][j + 1]; + else if(j == length2 - 1) + dp[i][j] = dp[i + 1][j]; + else + dp[i][j] = dp[i][j + 1] + dp[i + 1][j]; + } + } + } + return dp[0][0]; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0064._Minimum_Path_Sum.md b/docs/Algorithm/Leetcode/C++/0064._Minimum_Path_Sum.md new file mode 100755 index 00000000..c3cda766 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0064._Minimum_Path_Sum.md @@ -0,0 +1,52 @@ +# 64. Minimum Path Sum + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/minimum-path-sum/ + + > 内容描述 + + ``` +给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + +说明:每次只能向下或者向右移动一步。 + +示例: + +输入: +[ + [1,3,1], + [1,5,1], + [4,2,1] +] +输出: 7 +解释: 因为路径 1→3→1→1→1 的总和最小。 + ``` + +## 解题方案 +> 思路 1 +``` +dp: +1. 首行首列的路径只有一种,累加 +2. 其他都有两种方法,走到i,j的最小路径等于min(sum[i][j-1], sum[i-1][j])+grid[i][j] +``` + +```cpp +int minPathSum(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + int dp[m][n]; + dp[0][0] = grid[0][0]; + for (int i = 1; i < m; ++i) dp[i][0] = grid[i][0] + dp[i - 1][0]; + for (int i = 1; i < n; ++i) dp[0][i] = grid[0][i] + dp[0][i - 1]; + for (int i = 1; i < m; ++i) { + for (int j = 1; j < n; ++j) { + dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]); + } + } + return dp[m - 1][n - 1]; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0065._Valid_Number.md b/docs/Algorithm/Leetcode/C++/0065._Valid_Number.md new file mode 100755 index 00000000..17108087 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0065._Valid_Number.md @@ -0,0 +1,115 @@ +# 65. Valid Number + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/valid-number/ + +> + +``` +Validate if a given string can be interpreted as a decimal number. + +Some examples: +"0" => true +" 0.1 " => true +"abc" => false +"1 a" => false +"2e10" => true +" -90e3 " => true +" 1e" => false +"e3" => false +" 6e-1" => true +" 99e2.5 " => false +"53.5e93" => true +" --6 " => false +"-+3" => false +"95a54e53" => false +Note: 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: + +Numbers 0-9 +Exponent - "e" +Positive/negative sign - "+"/"-" +Decimal point - "." +Of course, the context of these characters also matters in the input. +``` + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +õģĿʵҪַҪ󼴿ɣҪеǽȥnumberǰɸո񣬡.1"1.ںϷ֡ + +```cpp +class Solution { +public: + void blank(int& i,string& s) + { + while(i < s.length() && s[i] == ' ') + i++; + } + bool firstHalf(int& i,string& s) + { + int num = 0; + for(;i < s.length();++i) + if(isdigit(s[i])) + continue; + else if(s[i] == '.') + { + if(num) + return 0; + num++; + } + else if(s[i] == 'e' || s[i] == ' ') + return 1; + else + return 0; + return 1; + } + bool secondHalf(int& i,string& s) + { + if(i == s.length()) + return 0; + if(s[i] =='-' || s[i] == '+') + ++i; + if(!isdigit(s[i])) + return 0; + for(;i < s.length();++i) + if(!isdigit(s[i])) + { + if(s[i] == ' ') + return 1; + return 0; + } + return 1; + } + bool isNumber(string s) { + int i = 0; + if(!s.length()) + return 0; + blank(i,s); + if(i == s.length()) + return 0; + if(s[i] == '-' || s[i] == '+') + ++i; + int temp = i; + if(!firstHalf(i,s)) + return 0; + if(i == temp) + return 0; + if(i - 1 == temp && s[i - 1] == '.') + return 0; + if(i == s.length()) + return 1; + if(s[i] == 'e') + { + i++; + if(!secondHalf(i,s)) + return 0; + } + blank(i,s); + return i == s.length(); + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0066._Plus_One.md b/docs/Algorithm/Leetcode/C++/0066._Plus_One.md new file mode 100755 index 00000000..3ed9779a --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0066._Plus_One.md @@ -0,0 +1,57 @@ +# 66. Plus One + +**Ѷ:Easy** + +## ˢ + +> ԭ + +* https://leetcode.com/problems/plus-one/ + +> + +``` +Given a non-empty array of digits representing a non-negative integer, plus one to the integer. + +The 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. + +You may assume the integer does not contain any leading zero, except the number 0 itself. + +Example 1: + +Input: [1,2,3] +Output: [1,2,4] +Explanation: The array represents the integer 123. +Example 2: + +Input: [4,3,2,1] +Output: [4,3,2,2] +Explanation: The array represents the integer 4321. + +``` + + +> ˼·1 + +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +ַתּɣҪעпܻһ + +```cpp +class Solution { +public: + vector plusOne(vector& digits) { + int i = digits.size() - 1; + while((i >= 0) && (digits[i] == 9)) + { + digits[i] = 0; + --i; + } + if(i < 0) + digits.insert(digits.begin(),1); + else + ++digits[i]; + return digits; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0068._Text_Justification.md b/docs/Algorithm/Leetcode/C++/0068._Text_Justification.md new file mode 100755 index 00000000..df005384 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0068._Text_Justification.md @@ -0,0 +1,140 @@ +# 68. Text Justification + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/text-justification/ + +> + +``` +Given 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. + +You 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. + +Extra 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. + +For the last line of text, it should be left justified and no extra space is inserted between words. + +Note: + +A word is defined as a character sequence consisting of non-space characters only. +Each word's length is guaranteed to be greater than 0 and not exceed maxWidth. +The input array words contains at least one word. +Example 1: + +Input: +words = ["This", "is", "an", "example", "of", "text", "justification."] +maxWidth = 16 +Output: +[ + "This is an", + "example of text", + "justification. " +] +Example 2: + +Input: +words = ["What","must","be","acknowledgment","shall","be"] +maxWidth = 16 +Output: +[ + "What must be", + "acknowledgment ", + "shall be " +] +Explanation: Note that the last line is "shall be " instead of "shall be", + because the last line must be left-justified instead of fully-justified. + Note that the second line is also left-justified becase it contains only one word. +Example 3: + +Input: +words = ["Science","is","what","we","understand","well","enough","to","explain", + "to","a","computer.","Art","is","everything","else","we","do"] +maxWidth = 20 +Output: +[ + "Science is what we", + "understand well", + "enough to explain to", + "a computer. Art is", + "everything else we", + "do " +] +``` + +> ˼· +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)****** + +ĿѣĿ˼ȼһɶٵʣÿ֮һոָͿԼÿɶٵʡÿеȷʽܹĿոԼܿոԼΪ0Ϊ֮Ŀո r Ϊ0ͷʼ r ո1ʣµIJ䡣һҪעÿ֮ĿոΪ1ַmaxWidthʣµÿո񲹳䡣 + +```cpp +class Solution { +public: + vector fullJustify(vector& words, int maxWidth) { + int l = 0,r = 0,sum = 0; + vector ans; + for(int i = 0;i < words.size();++i) + { + sum += words[i].length(); + if(sum <= maxWidth) + { + sum += 1; + r++; + } + else + { + string temp; + sum -= (r - l + words[i].length()); + int residue = 0, divide = (maxWidth - words[l].length()); + if(l + 1 != r) + { + residue = (maxWidth - sum) % (r - l - 1); + divide = (maxWidth - sum - residue) / (r - l - 1); + } + temp.append(words[l].begin(),words[l].end()); + for(int j = l + 1;j < r - 1;++j) + { + int k = residue > 0 ? divide + 1 : divide; + while(k) + { + temp.push_back(' '); + --k; + } + temp.append(words[j].begin(),words[j].end()); + residue--; + } + int k = residue > 0 ? divide +1 : divide; + while(k) + { + temp.push_back(' '); + --k; + } + if(l + 1 != r) + temp.append(words[r - 1].begin(),words[r - 1].end()); + ans.push_back(temp); + l = r++; + sum = words[i].length() + 1; + } + } + sum -= 1; + string temp; + temp.append(words[l].begin(),words[l].end()); + for(int i = l + 1;i < r;++i) + { + temp.push_back(' '); + temp.append(words[i].begin(),words[i].end()); + } + int k = maxWidth - sum; + while(k) + { + temp.push_back(' '); + --k; + } + ans.push_back(temp); + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0069._Sqr(x).md b/docs/Algorithm/Leetcode/C++/0069._Sqr(x).md new file mode 100755 index 00000000..47946457 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0069._Sqr(x).md @@ -0,0 +1,73 @@ +# 69. Sqrt(x) + +**Ѷ:Easy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/sqrtx/ + +> + +``` +Implement int sqrt(int x). + +Compute and return the square root of x, where x is guaranteed to be a non-negative integer. + +Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned. + +Example 1: + +Input: 4 +Output: 2 +Example 2: + +Input: 8 +Output: 2 +Explanation: The square root of 8 is 2.82842..., and since + the decimal part is truncated, 2 is returned. +``` + +> ˼·1 +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +0xЩƽֱx + +```cpp +class Solution { +public: + int mySqrt(int x) { + int i = 0; + if(!x || x == 1) + return x; + for(;i < x;++i) + if((long long)i * i > x) + break; + return i - 1; + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(lgn)******- ռ临Ӷ: O(1)****** + +ԣҿԽһŻöַ0Ϊ½磬xΪϽ磬ͿԽж + +```cpp +class Solution { +public: + int mySqrt(int x) { + int l = 0, r= x; + while(l < r) + { + long long mid = (l + r) / 2,temp = mid * mid; + if(temp == x) + return mid; + if(temp < x) + l = mid + 1; + else + r = mid - 1; + } + return l * l <= x ? l : l - 1; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0072._Edit_Distance.md b/docs/Algorithm/Leetcode/C++/0072._Edit_Distance.md new file mode 100755 index 00000000..1cca984f --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0072._Edit_Distance.md @@ -0,0 +1,70 @@ +# 72. Edit Distance + +**难度Hard** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/edit-distance/ + +> 内容描述 + +``` +You 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. + +Example 1: + +Input: + s = "barfoothefoobarman", + words = ["foo","bar"] +Output: [0,9] +Explanation: Substrings starting at index 0 and 9 are "barfoor" and "foobar" respectively. +The output order does not matter, returning [9,0] is fine too. +Example 2: + +Input: + s = "wordgoodstudentgoodword", + words = ["word","student"] +Output: [] + +``` +> 思路 +******- 时间复杂度: O(n^2)******- 空间复杂度: O(n^2)****** + +这题可以动态规划的思想去解决,首先定义两个指针 i 和 j,分别指向字符串的末尾。从两个字符串的末尾开始比较,相等,则```--i,--j```。若不相等,有三种情况,删除 i 指向的字符,在 i 指向的字符之后增加一个字符,替换 i 指向的字符, 接着比较这三次的操作的次数,取最小值即可,不过这里要注意递归操作时会重复计算,所以我们用一个数组 dp[i][j],表示 i 在words1中的位置,j 在 words2 的位置。由于c++对动态数组的支持不是很好,这里我用 vector 代替,在效率上可能较欠缺。 + +```cpp +class Solution { +public: + vector > dp; + int minLen(string& w1,string& w2,int i,int j) + { + if(i < 0) + return j + 1; + if(j < 0) + return i + 1; + if(dp[i][j]) + return dp[i][j]; + if(w1[i] == w2[j]) + { + dp[i][j] = minLen(w1,w2,i - 1,j - 1); + return dp[i][j]; + } + int temp1 = min(minLen(w1,w2,i - 1,j) + 1,minLen(w1,w2,i - 1,j - 1) + 1); + dp[i][j] = min(minLen(w1,w2,i,j - 1) + 1,temp1); + return dp[i][j]; + } + int minDistance(string word1, string word2) { + int i = word1.length() - 1,j = word2.length() - 1; + for(int t1 = 0;t1 <= i;++t1) + { + vector v1; + for(int t2 = 0;t2 <= j;++t2) + v1.push_back(0); + dp.push_back(v1); + } + int m = minLen(word1,word2,i,j); + return m; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0075._Sort_Colors.md b/docs/Algorithm/Leetcode/C++/0075._Sort_Colors.md new file mode 100755 index 00000000..9b72ecc9 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0075._Sort_Colors.md @@ -0,0 +1,61 @@ +# 75. Sort Colors + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/sort-colors/submissions/ + + > 内容描述 + + ``` +给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 + +此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 + +注意: +不能使用代码库中的排序函数来解决这道题。 + +示例: + +输入: [2,0,2,1,1,0] +输出: [0,0,1,1,2,2] +进阶: + +一个直观的解决方案是使用计数排序的两趟扫描算法。 +首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 +你能想出一个仅使用常数空间的一趟扫描算法吗? + ``` + +## 解题方案 +> 思路 1 +``` +记录两个指针,一个是0部分的后一位,另一个是2开头的前一个位置。 +遍历数组,遇到2,就和后一个指针交换(交换回来的有可能还是2,所以这个位置要再次判断) +遇到0则和最后一个数的下一个位置交换。 + +``` + +```cpp +void sortColors(vector& nums) { + int left = 0; + int right = nums.size()-1; + for(int i=0;i<=right;i++){ + if(nums[i]==0){ + int tmp = nums[left]; + nums[left] = nums[i]; + nums[i] = tmp; + left++; + } + else if(nums[i]==2){ + int tmp = nums[i]; + nums[i] = nums[right]; + nums[right] = tmp; + right--; + i--; + } + } +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0076._Minimum_Window_Substring.md b/docs/Algorithm/Leetcode/C++/0076._Minimum_Window_Substring.md new file mode 100755 index 00000000..3db7417f --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0076._Minimum_Window_Substring.md @@ -0,0 +1,74 @@ +# 76. Minimum Window Substring + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/minimum-window-substring/ + +> + +``` +Given 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). + +Example: + +Input: S = "ADOBECODEBANC", T = "ABC" +Output: "BANC" +Note: + +If there is no such window in S that covers all characters in T, return the empty string "". +If there is such window, you are guaranteed that there will always be only one unique minimum window in S. +``` + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)****** + +տʼ뵽 map ȥļֵַ˿ȥʱ临ӶΪO(n)һÿֵַĴű s̶һ䣬ʹڵַַ tͬҲһ鴢䡣ƶ伴ɡҵ̵䡣 + +```cpp +class Solution { +public: + string minWindow(string s, string t) { + int arr[128],alNum = t.length(); + memset(arr,0,sizeof(arr)); + for(int i = 0;i < t.length();++i) + arr[t[i]]++; + vector v; + for(int i = 0;i < s.length();++i) + if(arr[s[i]]) + v.push_back(i); + int s_map[128],beg = -1,en,ans = INT_MAX,count1 = 0,l,r; + memset(s_map,0,sizeof(s_map)); + for(int i = 0;i < v.size();++i) + { + if(count1 != alNum) + { + if(beg == -1) + beg = i; + s_map[s[v[i]]]++; + if(s_map[s[v[i]]] <= arr[s[v[i]]]) + count1++; + } + for(int j = beg;count1 == alNum;) + { + en = v[i]; + s_map[s[v[j]]]--; + if(ans > en - v[beg]) + { + l = v[beg]; + r = en; + ans = en - v[beg]; + } + if(s_map[s[v[j]]] < arr[s[v[j]]]) + count1--; + beg = ++j; + } + } + if(ans == INT_MAX) + return ""; + return s.substr(l,r - l + 1); + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0077._combinations.md b/docs/Algorithm/Leetcode/C++/0077._combinations.md new file mode 100755 index 00000000..43420918 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0077._combinations.md @@ -0,0 +1,53 @@ +# 77. Combinations + +**难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/combinations/ + + > 内容描述 + ``` +给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 + +示例: + +输入: n = 4, k = 2 +输出: +[ + [2,4], + [3,4], + [2,3], + [1,2], + [1,3], + [1,4], +] + ``` + +## 解题方案 +> 思路 1 +``` +回溯寻找所有组合。 +``` + +```cpp + void dfs(int k, int index, int n, vector& path, vector>& ans){ + if(k==0){ + ans.push_back(path); + return ; + } + for(int i=index;i<=n;i++){ + path.push_back(i); + dfs(k-1, i+1, n, path, ans); + path.pop_back(); + } +} +vector> combine(int n, int k) { + vector> ans; + vector path; + dfs(k, 1, n, path, ans); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0078._subsets.md b/docs/Algorithm/Leetcode/C++/0078._subsets.md new file mode 100755 index 00000000..fc22be46 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0078._subsets.md @@ -0,0 +1,56 @@ +# 78. Subsets + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/subsets/ + + > 内容描述 + ``` +给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + +说明:解集不能包含重复的子集。 + +示例: + +输入: nums = [1,2,3] +输出: +[ + [3], + [1], + [2], + [1,2,3], + [1,3], + [2,3], + [1,2], + [] +] + ``` + +## 解题方案 +> 思路 1 +``` +每个元素有两种选择,选与不选,可以使用K位二进制数组表示K个元素的选与不选。 +``` + +```cpp +vector> subsets(vector& nums) { + vector> ans; + for(int i=0;i tmp; + int index = 0; + int j=i; + while(j){ + if(j%2==1) + tmp.push_back(nums[index]); + index++; + j/=2; + } + ans.push_back(tmp); + } + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0081._Search_in_Rotated_Sorted_Array_II.md b/docs/Algorithm/Leetcode/C++/0081._Search_in_Rotated_Sorted_Array_II.md new file mode 100755 index 00000000..ab201271 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0081._Search_in_Rotated_Sorted_Array_II.md @@ -0,0 +1,82 @@ +# 81. Search in Rotated Sorted Array II + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/search-in-rotated-sorted-array-ii/submissions/ + +> + +``` +Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. + +(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]). + +You are given a target value to search. If found in the array return true, otherwise return false. + +Example 1: + +Input: nums = [2,5,6,0,0,1,2], target = 0 +Output: true +Example 2: + +Input: nums = [2,5,6,0,0,1,2], target = 3 +Output: false +``` + +> ˼· +******- ʱ临Ӷ: O(lgN)******- ռ临Ӷ: O(1)****** + +תһʼ뵽ľöַʵҲѣؼж l = mid j = mid⻹Ҫһµnums[mid] == nums[l] nums[l] == nums[mid]ʱֱ[l,mid][mid,r]Ƿtarget + +```cpp +class Solution { +public: + bool searchInternal( const vector& Nums, const int Target, int Left, int Right ) + { + if ( Right <= Left ) + return false; + while ( Left < Right - 1 ) + { + int Middle = (Left + Right) / 2; + if ( Nums[Left] == Nums[Middle] ) + { + return searchInternal( Nums, Target, Left, Middle ) + || searchInternal( Nums, Target, Middle, Right ); + } + if ( Target < Nums[Middle] ) + { + if ( Nums[Left] < Nums[Middle] && Nums[Left] > Target ) + { + Left = Middle; + } + else + { + Right = Middle; + } + } + else if ( Target > Nums[Middle] ) + { + if ( Nums[Left] > Nums[Middle] && Nums[Left] <= Target ) + { + Right = Middle; + } + else + { + Left = Middle; + } + } + else + { + return true; + } + } + return Nums[Left] == Target; + } + bool search(vector& nums, int target) { + return searchInternal(nums,target,0,nums.size()); + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0083._Remove_Duplicates_From_Sorted_Lists.md b/docs/Algorithm/Leetcode/C++/0083._Remove_Duplicates_From_Sorted_Lists.md new file mode 100755 index 00000000..ae6a7922 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0083._Remove_Duplicates_From_Sorted_Lists.md @@ -0,0 +1,62 @@ +#83. remove-duplicates-from-sorted-list + +**Ѷ:Easy** + +## ˢ + +> ԭ + +*https://leetcode.com/problems/remove-duplicates-from-sorted-list/ +* +> + +``` +Given a sorted linked list, delete all duplicates such that each element appear only once. + +Example 1: + +Input: 1->1->2 +Output: 1->2 +Example 2: + +Input: 1->1->2->3->3 +Output: 1->2->3 +``` + +## ⷽ + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + + +ĿиѾõģôֻҪһڵڵǰڵģɾȥ + + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* deleteDuplicates(ListNode* head) { + ListNode* l = head; + ListNode* l1 = head; + if(l != nullptr) + { + while(l ->next != nullptr) + { + if(l ->val == (l ->next ->val)) + l ->next = l ->next ->next; + else + l = l ->next; + } + } + return l1; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0084._Largest_Rectangle_in_Histogram.md b/docs/Algorithm/Leetcode/C++/0084._Largest_Rectangle_in_Histogram.md new file mode 100755 index 00000000..b7c7ec48 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0084._Largest_Rectangle_in_Histogram.md @@ -0,0 +1,97 @@ +# 84. Largest Rectangle in Histogram + +**难度:Hard** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/largest-rectangle-in-histogram/ + +> 内容描述 + +``` +Given 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. + +Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]. + +The largest rectangle is shown in the shaded area, which has area = 10 unit. + +Example: + +Input: [2,1,5,6,2,3] +Output: 10 +``` + +> 思路1 +******- 时间复杂度: O(n^2)******- 空间复杂度: O(n)****** + +这题第一种思路就是用暴力的方法去解。时间复杂度为O(n^2)。遍历数组,对数组中每个元素分别向右向左找到最远,计算最大值得到结果 + +```cpp +class Solution { +public: + int largestRectangleArea(vector& heights) { + long long ans = 0; + for(int i = 0;i < heights.size();++i) + { + int j = i + 1; + long long l,r; + for(;j < heights.size();++j) + if(heights[j] < heights[i]) + { + r = (long long)heights[i] * (j - i); + break; + } + if(j == heights.size()) + r = (long long)heights[i] * (heights.size() - i); + for(j = i - 1;j >= 0;--j) + if(heights[j] < heights[i]) + { + l = (long long)heights[i] * (i - j - 1); + break; + } + if(j < 0) + l = (long long)heights[i] * i; + ans = max(ans,l + r); + } + return ans; + } +}; +``` +> 思路2 +******- 时间复杂度: O(n)******- 空间复杂度: O(n)****** + +上面第一种方法的实现中有重复计算的过程,我们用栈去解决这个问题就很好的剔除了重复计算的过程,时间复杂度降到了O(n)。先定义一个栈,我们要保证栈中的数是递增的,遍历数组,若这个数小于栈顶的数,则将栈顶的数弹出,并计算栈顶元素的最大距离,直到栈为空或者比这个数小 + +```cpp +class Solution { +public: + int largestRectangleArea(vector& heights) { + long long ans = 0; + heights.push_back(0); + vector > v; + for(int i = 0;i < heights.size();++i) + { + if(!v.size() || heights[i] > v[v.size() - 1].first) + v.push_back(make_pair(heights[i],i)); + else + { + int j = v.size() - 1; + while(j > 0 && v[j].first > heights[i]) + { + ans = max(ans,v[j].first * (i - v[j - 1].second - 1)); + v.pop_back(); + --j; + } + if(!j && v[j].first > heights[i]) + { + ans = max(ans,v[j].first * (i)); + v.pop_back(); + } + v.push_back(make_pair(heights[i],i)); + } + } + return ans; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0085._Maximal_Rectangle.md b/docs/Algorithm/Leetcode/C++/0085._Maximal_Rectangle.md new file mode 100755 index 00000000..2d098713 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0085._Maximal_Rectangle.md @@ -0,0 +1,118 @@ +# 85. Maximal Rectangle + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/maximal-rectangle/ + +> + +``` +Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area. + +Example: + +Input: +[ + ["1","0","1","0","0"], + ["1","0","1","1","1"], + ["1","1","1","1","1"], + ["1","0","0","1","0"] +] +Output: 6 +``` + +> ˼·1 +******- ʱ临Ӷ: O(n^3)******- ռ临Ӷ: O(1)****** + +һֱķȥ⣬ÿһжٸ1¼³count1λѰңijСcount1count1ȡСֵΪ0ͼĴСֱе + +```cpp +class Solution { +public: + int maximalRectangle(vector>& matrix) { + int len1 = matrix.size(); + if(!len1) + return 0; + int len2 = matrix[0].size(); + int ans = 0; + for(int t = 0;t < len1;++t) + for(int i = 0;i < len2;++i) + { + int count1 = 0; + while(i + count1 < len2 && matrix[t][i + count1] - '0') + ++count1; + if(count1) + { + int row = 1; + ans = max(ans,row * count1); + for(int j = t + 1;j < len1;++j) + { + int count2 = 0; + while(count2 <= count1 && matrix[j][i + count2] - '0') + ++count2; + if(!count2) + break; + if(count1 > count2) + count1 = count2; + ++row; + ans = max(ans,row * count1); + } + } + } + return ans; + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n)****** + +㷨Żÿĸ߶Ⱥ߶λúҵλãֻҪO(n^2)ʱ临ھ + +```cpp +class Solution { +public: + int maximalRectangle(vector>& matrix) { + int len1 = matrix.size(); + if(!len1) + return 0; + int len2 = matrix[0].size(); + int height[len2],l[len2],r[len2]; + memset(height,0,sizeof(height)); + memset(l,0,sizeof(l)); + for(int i = 0;i < len2;++i) + r[i] = len2; + int ans = 0; + for(int i = 0;i < len1;++i) + { + int t_l = 0,t_r = len2; + for(int j = 0;j < len2;++j) + if(matrix[i][j]-'0') + height[j] = height[j] + 1; + else + height[j] = 0; + for(int j = 0;j < len2;++j) + if(matrix[i][j]-'0') + l[j] = max(l[j],t_l); + else + { + t_l = j + 1; + l[j] = 0; + } + for(int j = len2 - 1;j >= 0;--j) + if(matrix[i][j]-'0') + r[j] = min(r[j],t_r); + else + { + t_r = j; + r[j] = len2; + } + for(int j = 0;j < len2;++j) + ans = max(ans,(r[j] - l[j]) * height[j]); + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0087._Scramble_String.md b/docs/Algorithm/Leetcode/C++/0087._Scramble_String.md new file mode 100755 index 00000000..a77736f3 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0087._Scramble_String.md @@ -0,0 +1,123 @@ +# 87. Scramble String + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/scramble-string/ + +> + +``` +Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively. + +Below is one possible representation of s1 = "great": + + great + / \ + gr eat + / \ / \ +g r e at + / \ + a t +To scramble the string, we may choose any non-leaf node and swap its two children. + +For example, if we choose the node "gr" and swap its two children, it produces a scrambled string "rgeat". + + rgeat + / \ + rg eat + / \ / \ +r g e at + / \ + a t +We say that "rgeat" is a scrambled string of "great". + +Similarly, if we continue to swap the children of nodes "eat" and "at", it produces a scrambled string "rgtae". + + rgtae + / \ + rg tae + / \ / \ +r g ta e + / \ + t a +We say that "rgtae" is a scrambled string of "great". + +Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1. + +Example 1: + +Input: s1 = "great", s2 = "rgeat" +Output: true +Example 2: + +Input: s1 = "abcde", s2 = "caebd" +Output: false +``` + +> ˼·1 +******- ʱ临Ӷ: O(2^n)******- ռ临Ӷ: O(1)****** + +տʼʱĿ˼ûΪǰַ԰룬ʵַкܶĶʾһַǵݹķÿεݹʱȽilen֮ӴǷs2еӴֱͬȽϷʽs2ʼͽβֱȽϷʽһ㼴ɣֻҪжӴĸǷͬͬͽһεݹ顣 + +```cpp +class Solution { +public: + bool isScramble(string s1, string s2) { + if(s1==s2) + return true; + int len = s1.length(); + int count[26] = {0}; + for(int i=0; i ˼·2 +******- ʱ临Ӷ: O(n^4)******- ռ临Ӷ: O(n^3 + +ڶֵķʹDPdp[i][j][t],ʾs1[i]s2[j]ʼijΪtַǷΪscramble string + +```cpp +class Solution { +public: + bool isScramble(string s1, string s2) { + int len = s1.length(); + int dp[len][len][len + 1] = {0}; + for(int i = len - 1;i >= 0;--i) + for(int j = len - 1;j >= 0;--j) + for(int t = 1;t <= min(len - i,len - j);++t) + if(t == 1) + dp[i][j][t] = (s1[i] == s2[j]); + else + { + int k = 1; + for(;k < t;++k) + if((dp[i][j][k] && dp[i + k][j + k][t - k]) || (dp[i][j + t - k][k] && dp[i + k][j][t - k])) + break; + dp[i][j][t] = k == t ? 0 : 1; + } + return dp[0][0][len]; + +} +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0088._Merge_Sorted_Array.md b/docs/Algorithm/Leetcode/C++/0088._Merge_Sorted_Array.md new file mode 100755 index 00000000..ecd81752 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0088._Merge_Sorted_Array.md @@ -0,0 +1,57 @@ +# 88.Merge Sorted Array + +**ѶEasy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/merge-sorted-array/ + +> + +``` +Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. + +Note: + +The number of elements initialized in nums1 and nums2 are m and n respectively. +You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. +Example: + +Input: +nums1 = [1,2,3,0,0,0], m = 3 +nums2 = [2,5,6], n = 3 + +Output: [1,2,2,3,5,6] +``` +> ˼· +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +Ѿõģǿָ ij ָĵһԪأnums[i] < nums[j],++i ++j,jָԪزnums1Ҫעijȡ + +```cpp +class Solution { +public: + void merge(vector& nums1, int m, vector& nums2, int n) { + int i = 0,j = 0; + while((i < m) && (j < n)) + { + if(nums1[i] < nums2[j]) + i++; + else + { + nums1.insert(nums1.begin() + i,nums2[j++]); + i++; + m++; + } + } + if(j < n) + { + nums1.erase(nums1.begin() + m,nums1.end()); + nums1.insert(nums1.end(),nums2.begin() + j,nums2.begin() + n); + } + else + nums1.erase(nums1.begin() + m,nums1.end()); + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0090._Subsets_II.md b/docs/Algorithm/Leetcode/C++/0090._Subsets_II.md new file mode 100755 index 00000000..eb6eb503 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0090._Subsets_II.md @@ -0,0 +1,59 @@ +# 90. Subsets II + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/subsets-ii/submissions/ + + > 内容描述 + + ``` +给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + +说明:解集不能包含重复的子集。 + +示例: + +输入: [1,2,2] +输出: +[ + [2], + [1], + [1,2,2], + [2,2], + [1,2], + [] +] + ``` + +## 解题方案 +> 思路 1 +``` +回溯搜索 +``` + +```cpp +void dfs(vector nums, int index, vector subset, vector>& ans){ + ans.push_back(subset); + if(index == nums.size()){ + return ; + } + for(int i=index;iindex) + continue; + subset.push_back(nums[i]); + dfs(nums, i+1, subset, ans); + subset.pop_back(); + } +} +vector> subsetsWithDup(vector& nums) { + vector> ans; + vector subset; + sort(nums.begin(), nums.end()); + dfs(nums, 0, subset, ans); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0094._binary_tree_inorder_traversal.md b/docs/Algorithm/Leetcode/C++/0094._binary_tree_inorder_traversal.md new file mode 100755 index 00000000..c1710aa9 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0094._binary_tree_inorder_traversal.md @@ -0,0 +1,46 @@ +# 94. Binary Tree Inorder Traversal + **难度: Medium** + + ## 刷题内容 + > 原题连接 + +* https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + + > 内容描述 + ``` +给定一个二叉树,返回它的中序 遍历。 + +示例: + +输入: [1,null,2,3] + 1 + \ + 2 + / + 3 + +输出: [1,3,2] + +进阶: 递归算法很简单,你可以通过迭代算法完成吗? + ``` + +## 解题方案 +> 思路 1 +``` +递归。 +``` + +```cpp +void dfs(TreeNode* root, vector& ans){ + if(root==NULL) + return ; + dfs(root->left, ans); + ans.push_back(root->val); + dfs(root->right, ans); +} +vector inorderTraversal(TreeNode* root) { + vector ans; + dfs(root, ans); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0096._Unique_Binary_Search_Trees.md b/docs/Algorithm/Leetcode/C++/0096._Unique_Binary_Search_Trees.md new file mode 100755 index 00000000..52a7190c --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0096._Unique_Binary_Search_Trees.md @@ -0,0 +1,50 @@ +# 96. Unique Binary Search Trees + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/unique-binary-search-trees/ + + > 内容描述 + + ``` +给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? + +示例: + +输入: 3 +输出: 5 +解释: +给定 n = 3, 一共有 5 种不同结构的二叉搜索树: + + 1 3 3 2 1 + \ / / / \ \ + 3 2 1 1 3 2 + / / \ \ + 2 1 2 3 + ``` + +## 解题方案 +> 思路 1 +``` +假设有n个节点,左右子树有(0,n-1)(1,n-2)...(n-1, 0)等情况 +子结构: +dp[i] = dp[0]*dp[i-1]+...+dp[i-1]*dp[0] +``` + +```cpp +int numTrees(int n) { + vector dp(n+1, 0); + dp[0]=1; + dp[1]=1; + for(int i=2;i<=n;i++){ + for(int j=0;jѶ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/interleaving-string/ + +> + +``` +Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. + +Example 1: + +Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac" +Output: true +Example 2: + +Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc" +Output: false +``` + +> ˼· +******- ʱ临Ӷ: O(N^2)******- ռ临Ӷ: O(N^2)****** + +һñķȥ⣬ʱ临ӶΪ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])``` + +```cpp +class Solution { +public: + bool isInterleave(string s1, string s2, string s3) { + int l1 = s1.length(),l2 = s2.length(),l3 = s3.length(); + if(l1 + l2 != s3.length()) + return 0; + int dp[l1 + 2][l2 + 2]; + memset(dp,0,sizeof(dp)); + dp[l1][l2] = 1; + for(int i = l1;i >= 0;--i) + for(int j = l2;j >= 0;--j) + { + if(i < l1 && s1[i] == s3[i + j] && dp[i + 1][j]) + dp[i][j] = 1; + if(j < l2 && s2[j] == s3[i + j] && dp[i][j + 1]) + dp[i][j] = 1; + } + return dp[0][0]; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0099._Recover_Binary_Search_Tree.md b/docs/Algorithm/Leetcode/C++/0099._Recover_Binary_Search_Tree.md new file mode 100755 index 00000000..ffecc8e2 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0099._Recover_Binary_Search_Tree.md @@ -0,0 +1,89 @@ +# 99. Recover Binary Search Tree + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/recover-binary-search-tree/ + +> + +``` +Two elements of a binary search tree (BST) are swapped by mistake. + +Recover the tree without changing its structure. + +Example 1: + +Input: [1,3,null,null,2] + + 1 + / + 3 + \ + 2 + +Output: [3,1,null,null,2] + + 3 + / + 1 + \ + 2 +Example 2: + +Input: [3,1,4,null,null,2] + + 3 + / \ +1 4 + / + 2 + +Output: [2,1,4,null,null,3] + + 2 + / \ +1 4 + / + 3 +``` + +> ˼· +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +Ҫ㶮ƽʱġʺֻҪԶҵĸɣһ֮Ϊ 32131ڶ֮Ϊ 132432 + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: +TreeNode* n1; +TreeNode* n2; +TreeNode* pre = new TreeNode(INT_MIN); +void travel(TreeNode* root){ + if(!root) + return; + travel(root ->left); + if(!n1 && root ->val <= pre ->val) + n1 = pre; + if(pre && n1 && root ->val <= pre ->val) + n2 = root; + pre = root; + travel(root ->right); +} +void recoverTree(TreeNode* root) { + travel(root); + swap(n1 ->val,n2 ->val); +} +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0100._same_tree.md b/docs/Algorithm/Leetcode/C++/0100._same_tree.md new file mode 100755 index 00000000..dfd92677 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0100._same_tree.md @@ -0,0 +1,73 @@ +# 100. same tree + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/same-tree/ +* +> 内容描述 + +``` +Given two binary trees, write a function to check if they are the same or not. + +Two binary trees are considered the same if they are structurally identical and the nodes have the same value. + +Example 1: + +Input: 1 1 + / \ / \ + 2 3 2 3 + + [1,2,3], [1,2,3] + +Output: true +Example 2: + +Input: 1 1 + / \ + 2 2 + + [1,2], [1,null,2] + +Output: false +Example 3: + +Input: 1 1 + / \ / \ + 2 1 1 2 + + [1,2,1], [1,1,2] + +Output: false +``` +> 思路1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +这道题直接从两颗树的根节点开始递归比较,如果不同就返回false,反之则true + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + bool isSameTree(TreeNode* p, TreeNode* q) { + if(p != nullptr && q != nullptr) + { + if(p ->val != q ->val) + return false; + return isSameTree(p ->left,q ->left) && isSameTree(p ->right,q ->right); + } + return p == q ? true : false; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0101._Symmetric_Tree.md b/docs/Algorithm/Leetcode/C++/0101._Symmetric_Tree.md new file mode 100755 index 00000000..ea3efbbc --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0101._Symmetric_Tree.md @@ -0,0 +1,63 @@ +# 101. Symmetric Tree + +**ѶEasy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/symmetric-tree/ + +> + +``` +Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). + +For example, this binary tree [1,2,2,3,4,4,3] is symmetric: + + 1 + / \ + 2 2 + / \ / \ +3 4 4 3 +But the following [1,2,2,null,3,null,3] is not: + 1 + / \ + 2 2 + \ \ + 3 3 +``` + +ֱDFSȽǷȣȷtrueȣfalse +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + bool judge(TreeNode* oTree,TreeNode* mTree){ + if((oTree != nullptr) && (mTree != nullptr)) + { + if((oTree ->val == mTree ->val) && (oTree ->val == mTree ->val)) + return judge(oTree ->left,mTree ->right) && judge(oTree ->right,mTree ->left); + return false; + } + if(oTree == mTree) + return true; + return false; + } + bool isSymmetric(TreeNode* root) { + if(root != nullptr) + return judge(root ->left,root ->right); + return true; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0102._Binary_Tree_Level_Order_Traversal.md b/docs/Algorithm/Leetcode/C++/0102._Binary_Tree_Level_Order_Traversal.md new file mode 100755 index 00000000..f59fa949 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0102._Binary_Tree_Level_Order_Traversal.md @@ -0,0 +1,62 @@ +# 102. Binary Tree Level Order Traversal + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ + + > 内容描述 + + ``` +给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 + +例如: +给定二叉树: [3,9,20,null,null,15,7], + + 3 + / \ + 9 20 + / \ + 15 7 +返回其层次遍历结果: + +[ + [3], + [9,20], + [15,7] +] + ``` + +## 解题方案 +> 思路 1 +``` +层次遍历 +``` + +```cpp +vector> levelOrder(TreeNode* root) { + vector> ans; + if(root==NULL) + return ans; + vector level; + level.push_back(root); + while(!level.empty()){ + vector tmp; + vector level_val; + for(int i=0;ileft) + tmp.push_back(level[i]->left); + if(level[i]->right) + tmp.push_back(level[i]->right); + level_val.push_back(level[i]->val); + } + ans.push_back(level_val); + level = tmp; + } + return ans; +} + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0104._Maximum_Depth_of_Binary_Tree.md b/docs/Algorithm/Leetcode/C++/0104._Maximum_Depth_of_Binary_Tree.md new file mode 100755 index 00000000..8e90f26f --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0104._Maximum_Depth_of_Binary_Tree.md @@ -0,0 +1,64 @@ +# 104. Maximum Depth of Binary Tree + +**Ѷ:Easy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/maximum-depth-of-binary-tree/ + +> + +``` +Given a binary tree, find its maximum depth. + +The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. + +Note: A leaf is a node with no children. + +Example: + +Given binary tree [3,9,20,null,null,15,7], + + 3 + / \ + 9 20 + / \ + 15 7 +return its depth = 3. +``` + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)****** + +DFSݹֱҵ depthȽ depthĴС + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int maxDepth(TreeNode* root) { + return max(root,0); + } + int max(TreeNode* ptr,int deep) + { + if(ptr != nullptr) + { + int ldeep = max(ptr ->left,deep + 1); + int rdeep = max(ptr ->right,deep + 1); + if(ldeep > rdeep) + deep = ldeep; + else + deep = rdeep; + } + return deep; + } +}; \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md b/docs/Algorithm/Leetcode/C++/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md new file mode 100755 index 00000000..8a33c3dd --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md @@ -0,0 +1,59 @@ +# 105. Construct Binary Tree from Preorder and Inorder Traversal + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + + > 内容描述 + + ``` +根据一棵树的前序遍历与中序遍历构造二叉树。 + +注意: +你可以假设树中没有重复的元素。 + +例如,给出 + +前序遍历 preorder = [3,9,20,15,7] +中序遍历 inorder = [9,3,15,20,7] +返回如下的二叉树: + + 3 + / \ + 9 20 + / \ + 15 7 + ``` + +## 解题方案 +> 思路 1 +``` +和106思路一致 +``` + +```cpp +TreeNode* dfs(vector& preorder, vector& inorder, int start, int end, int& index){ + int post = preorder[index]; + int i=start; + for(;istart) + node->left = dfs(preorder, inorder, start, i-1, ++index); + if(iright = dfs(preorder, inorder, i+1, end, ++index); + return node; +} +TreeNode* buildTree(vector& preorder, vector& inorder) { + if(preorder.empty()||inorder.empty()) + return NULL; + int index =0; + return dfs(preorder, inorder, 0, preorder.size()-1, index); +} + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md b/docs/Algorithm/Leetcode/C++/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md new file mode 100755 index 00000000..1b529666 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md @@ -0,0 +1,61 @@ +# 106. Construct Binary Tree from Inorder and Postorder Traversal + + **难度: Medium** + + ## 原题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/ + + > 内容描述 + + ``` +根据一棵树的中序遍历与后序遍历构造二叉树。 + +注意: +你可以假设树中没有重复的元素。 + +例如,给出 + +中序遍历 inorder = [9,3,15,20,7] +后序遍历 postorder = [9,15,7,20,3] +返回如下的二叉树: + + 3 + / \ + 9 20 + / \ + 15 7 + ``` + +## 解题方案 +> 思路 1 +``` +后序二叉树最后访问根节点 +中序二叉树的节点在中间,左边是左子树,反之是右子树。 +通过后序二叉树找到子树根节点,然后到中序二叉树中区分左右子树,递归求解。 +``` + +```cpp + TreeNode* dfs(int start, int end, vector& inorder, vector& postorder, int& val){ + int post = postorder[val]; + int i=start; + for(; i=i+1) + root->right=dfs(i+1, end, inorder, postorder, --val); + if(i-1>=start) + root->left = dfs(start, i-1, inorder, postorder, --val); + return root; +} +TreeNode* buildTree(vector& inorder, vector& postorder) { + if(inorder.empty()||postorder.empty()) + return NULL; + int index = inorder.size()-1; + return dfs(0, index, inorder, postorder, index); +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0107._Binary_Tree Level_Order_Traversal_II.md b/docs/Algorithm/Leetcode/C++/0107._Binary_Tree Level_Order_Traversal_II.md new file mode 100755 index 00000000..1185fe96 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0107._Binary_Tree Level_Order_Traversal_II.md @@ -0,0 +1,117 @@ +# 107.Binary Tree Level Order Traversal II + +**ѶEasy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/binary-tree-level-order-traversal-ii/ + +> + +``` +Given 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). + +For example: +Given binary tree [3,9,20,null,null,15,7], + 3 + / \ + 9 20 + / \ + 15 7 +return its bottom-up level order traversal as: +[ + [15,7], + [9,20], + [3] +] +``` +> ˼·1 +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)****** + +һ͵BFSĿһַõǵݹķȽ + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector > levelOrderBottom(TreeNode* root) { + if(!root) + { + vector > ret; + return ret; + } + vector v; + v.push_back(root ->val); + vector > temp1 = levelOrderBottom(root ->left); + vector > temp2 = levelOrderBottom(root ->right); + int pos1 = temp1.size() - 1; + int pos2 = temp2.size() - 1; + while(pos1 >= 0 && pos2 >= 0) + { + temp1[pos1].insert(temp1[pos1].end(),temp2[pos2].begin(),temp2[pos2].end()); + --pos1; + --pos2; + } + if(pos2 >= 0) + { + auto pos = temp2.begin() + pos2 + 1; + temp1.insert(temp1.begin(),temp2.begin(),pos); + } + temp1.push_back(v); + return temp1; + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)****** + +ڶָĽķõջĴ淽ʽ +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector> levelOrderBottom(TreeNode* root) { + vector > ret; + if(root != nullptr) + { + vector v; + v.push_back(*root); + judge(v,ret); + } + return ret; + } + void judge(vector& v,vector >& ret) + { + vector v1; + vector v2; + for(int i = 0;i < v.size();i++) + { + v2.push_back(v[i].val); + if(v[i].left != nullptr) + v1.push_back(*(v[i].left)); + if(v[i].right != nullptr) + v1.push_back(*(v[i].right)); + } + if(v1.size()) + judge(v1,ret); + ret.push_back(v2); + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md b/docs/Algorithm/Leetcode/C++/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md new file mode 100755 index 00000000..31c0e5a1 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md @@ -0,0 +1,61 @@ +# 108. Convert Sorted Array to Binary Search Tree + +**Ѷ:Easy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/ + +> + +``` +Given an array where elements are sorted in ascending order, convert it to a height balanced BST. + +For 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. + +Example: + +Given the sorted array: [-10,-3,0,5,9], + +One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST: + + 0 + / \ + -3 9 + / / + -10 5 +``` + +> ˼·1 +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +Ǹõ飬ƽҪIJľֵܴ1ֻÿν԰룬һΪһΪɡassignvecrtorֵ + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* sortedArrayToBST(vector& nums) { + if(!nums.size()) + return nullptr; + TreeNode* root = new TreeNode(nums[nums.size() / 2]); + vector v1,v2; + if(nums.size() / 2 >= 0) + v1.assign(nums.begin(),nums.begin() + nums.size() / 2); + root ->left = sortedArrayToBST(v1); + if(nums.size() / 2 + 1 < nums.size()) + v2.assign(nums.begin() + nums.size() / 2 + 1,nums.end()); + root ->right = sortedArrayToBST(v2); + return root; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0109._Convert_Sorted_List_to_Binary_Search_Tree.md b/docs/Algorithm/Leetcode/C++/0109._Convert_Sorted_List_to_Binary_Search_Tree.md new file mode 100755 index 00000000..03844b11 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0109._Convert_Sorted_List_to_Binary_Search_Tree.md @@ -0,0 +1,64 @@ +# 109. Convert Sorted List to Binary Search Tree + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/ + + > 内容描述 + + ``` +给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。 + +本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 + +示例: + +给定的有序链表: [-10, -3, 0, 5, 9], + +一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树: + + 0 + / \ + -3 9 + / / + -10 5 + ``` + +## 解题方案 +> 思路 1 +``` +1. 用快慢指针找链表中点 +2. 断开前半部分和后半部分 +3. 迭代构造左右子树 +``` + +```cpp +TreeNode* dfs(ListNode* node){ + if(node == NULL) + return NULL; + if(node->next==NULL) + return new TreeNode(node->val); + ListNode* fast=node; + ListNode* slow=node; + ListNode* last = slow; + while(fast&&fast->next){ + last = slow; + fast = fast->next->next; + slow = slow->next; + } + fast = slow->next; + last->next = NULL; + TreeNode* root = new TreeNode(slow->val); + if (node != slow) + root->left=dfs(node); + root->right=dfs(fast); + return root; +} +TreeNode* sortedListToBST(ListNode* head) { + return dfs(head); +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0110._Balanced_Binary_Tree.md b/docs/Algorithm/Leetcode/C++/0110._Balanced_Binary_Tree.md new file mode 100755 index 00000000..67432740 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0110._Balanced_Binary_Tree.md @@ -0,0 +1,71 @@ +# 110.Balanced Binary Tree + +**ѶEasy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/balanced-binary-tree/ + +> + +``` +Given a binary tree, determine if it is height-balanced. + +For 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. + +Example 1: + +Given the following tree [3,9,20,null,null,15,7]: + + 3 + / \ + 9 20 + / \ + 15 7 +Return true. + +Example 2: + +Given the following tree [1,2,2,3,3,null,null,4,4]: + + 1 + / \ + 2 2 + / \ + 3 3 + / \ + 4 4 +Return false. +``` +> ˼· +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +жиƽֻҪĸ߶ȲжǷ1ٷֱжǷΪƽ + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + bool isBalanced(TreeNode* root) { + if(root == nullptr) + return true; + return abs(height(root ->left) - height(root ->right)) <= 1 && isBalanced(root ->left) && isBalanced(root ->right); + } + int height(TreeNode* root){ + if(root == nullptr) + return 0; + return max(height(root ->left),height(root ->right)) + 1; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0111._Minimum_Depth_Of_Binary_Tree.md b/docs/Algorithm/Leetcode/C++/0111._Minimum_Depth_Of_Binary_Tree.md new file mode 100755 index 00000000..d36eb1f7 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0111._Minimum_Depth_Of_Binary_Tree.md @@ -0,0 +1,39 @@ +# 111. Minimum Depth of Binary Tree + **难度: Easy** +## 刷题内容 +> 原题连接 +* https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/ +> 内容描述 +``` +Given a binary tree, find its minimum depth. + +The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. + +Note: A leaf is a node with no children. +``` +## 解题方案 +> 思路 1 +``` +遍历树,找出最小深度的分支 +``` +```cpp +void dfs(TreeNode* root, int depth, int& ans){ + if(root == NULL) + return ; + if(root->left==NULL && root->right==NULL){ + if(depthleft, depth+1, ans); + dfs(root->right, depth+1, ans); +} +int minDepth(TreeNode* root) { + int ans = 10000; + if(root==NULL) + return 0; + dfs(root, 1, ans); + return ans; +} + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0112._Path_Sum.md b/docs/Algorithm/Leetcode/C++/0112._Path_Sum.md new file mode 100755 index 00000000..cd2382bc --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0112._Path_Sum.md @@ -0,0 +1,54 @@ +# 112. Path Sum + +**Ѷ:Easy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/path-sum/ + +> + +``` +Given 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. + +Note: A leaf is a node with no children. + +Example: + +Given the below binary tree and sum = 22, + + 5 + / \ + 4 8 + / / \ + 11 13 4 + / \ \ +7 2 1 +return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22. + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** +DFSֱǷ sum - val · + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + bool hasPathSum(TreeNode* root, int sum) { + if(root == nullptr) + return false; + if(root ->right == nullptr && root ->left == nullptr) + return sum - root ->val ? false : true; + return hasPathSum(root ->left,sum - root ->val) || hasPathSum(root ->right,sum - root ->val); + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0114._Flatten_Binary_Tree_to_Linked_List.md b/docs/Algorithm/Leetcode/C++/0114._Flatten_Binary_Tree_to_Linked_List.md new file mode 100755 index 00000000..19f6a6d3 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0114._Flatten_Binary_Tree_to_Linked_List.md @@ -0,0 +1,60 @@ +# 114. Flatten Binary Tree to Linked List + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/ + + > 内容描述 + + ``` +给定一个二叉树,原地将它展开为链表。 + +例如,给定二叉树 + + 1 + / \ + 2 5 + / \ \ +3 4 6 +将其展开为: + +1 + \ + 2 + \ + 3 + \ + 4 + \ + 5 + \ + 6 + ``` + +## 解题方案 +> 思路 1 +``` +后续遍历二叉树 +``` + +```cpp +void dfs(TreeNode* root){ + if(root==NULL) + return ; + dfs(root->left); + dfs(root->right); + TreeNode* tmp=root->right; + root->right=root->left; + root->left=NULL; + while(root->right) + root=root->right; + root->right = tmp; +} +void flatten(TreeNode* root) { + dfs(root); +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0115._Distinct_Subsequences.md b/docs/Algorithm/Leetcode/C++/0115._Distinct_Subsequences.md new file mode 100755 index 00000000..dad884bd --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0115._Distinct_Subsequences.md @@ -0,0 +1,80 @@ +# 115.Distinct Subsequences + +**ѶHard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/distinct-subsequences/ + +> + +``` +Given a string S and a string T, count the number of distinct subsequences of S which equals T. + +A 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). + +Example 1: + +Input: S = "rabbbit", T = "rabbit" +Output: 3 +Explanation: + +As shown below, there are 3 ways you can generate "rabbit" from S. +(The caret symbol ^ means the chosen letters) + +rabbbit +^^^^ ^^ +rabbbit +^^ ^^^^ +rabbbit +^^^ ^^^ +Example 2: + +Input: S = "babgbag", T = "bag" +Output: 5 +Explanation: + +As shown below, there are 5 ways you can generate "bag" from S. +(The caret symbol ^ means the chosen letters) + +babgbag +^^ ^ +babgbag +^^ ^ +babgbag +^ ^^ +babgbag + ^ ^^ +babgbag + ^^^ +``` +> ˼· +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n^2)****** + +һ̬滮⣬̬Ĺؼľд״̬תƷ̡Ƕһ dp[m][n],ʾ s[m] t[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]) + +```cpp +class Solution { +public: + int numDistinct(string s, string t) { + int l1 = s.length(),l2 = t.length(); + int dp[l1 + 1][l2 + 1]; + memset(dp,0,sizeof(dp)); + for(int i = 1;i <= l1;++i) + if(s[i - 1] == t[0]) + dp[i][1] = 1; + for(int i = 1;i <= l1;++i) + for(int j = 1;j <= l2;++j) + { + if(s[i - 1] != t[j - 1]) + dp[i][j] = dp[i - 1][j]; + else + dp[i][j] += (dp[i - 1][j - 1] + dp[i - 1][j]); + //cout << dp[i][j] << " "; + } + return dp[l1][l2]; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0118._Pascals_Triangle.md b/docs/Algorithm/Leetcode/C++/0118._Pascals_Triangle.md new file mode 100755 index 00000000..e98936b3 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0118._Pascals_Triangle.md @@ -0,0 +1,58 @@ +## 118. Pascal's Triangle + +难度:Easy + +## 内容 + +题目链接:https://leetcode.com/problems/pascals-triangle/description/ + +Given a non-negative integer *numRows*, generate the first *numRows* of Pascal's triangle. + +![img](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif) +In Pascal's triangle, each number is the sum of the two numbers directly above it. + +**Example:** + +``` +Input: 5 +Output: +[ + [1], + [1,1], + [1,2,1], + [1,3,3,1], + [1,4,6,4,1] +] +``` + +## 思路 + +该题比较简单,杨辉三角形,从第三行开始,除了首尾,中间元素的值可通过如下公式计算:`cur[i] = prev[i] + prev[i-1]` + +计算当前行实现要点如下: + +* 拷贝上一行,并在末尾添加元素1 +* 倒着开始计算,除了首尾,`cur[i] += cur[i-1]` + +## 代码 + +``` +class Solution { +public: + vector> generate(int numRows) { + vector> res; + for (auto i = 0; i < numRows; ++i) { + vector row; + if (!res.empty()) + row.assign(res.at(i-1).begin(), res.at(i-1).end()); + row.emplace_back(1); + for (auto j = i - 1; j > 0; --j) + row[j] += row[j-1]; + res.emplace_back(row); + } + return res; + } +}; +``` + +来源:https://github.com/xiaqunfeng/leetcode \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0119._Pascals_Triangle-II.md b/docs/Algorithm/Leetcode/C++/0119._Pascals_Triangle-II.md new file mode 100755 index 00000000..8f7d1c9c --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0119._Pascals_Triangle-II.md @@ -0,0 +1,49 @@ +## 119. Pascal's Triangle II + +难度:Easy + +## 内容 + +题目链接:https://leetcode.com/problems/pascals-triangle-ii/description/ + +Given a non-negative index *k* where *k* ≤ 33, return the *k*th index row of the Pascal's triangle. + +Note that the row index starts from 0. + +![img](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif) +In Pascal's triangle, each number is the sum of the two numbers directly above it. + +**Example:** + +``` +Input: 3 +Output: [1,3,3,1] +``` + +**Follow up:** + +Could you optimize your algorithm to use only *O*(*k*) extra space? + +## 思路 + +思路和[上一题](118._Pascals_Triangle.md)一样,只不过这里不需要存每一行的数据。 + +注意:和上一题相比,这里的 `rowIndex + 1 = numRows` + +## 代码 + +``` +class Solution { +public: + vector getRow(int rowIndex) { + vector res(rowIndex+1, 0); + res[0] = 1; + for (auto i = 0; i <= rowIndex; ++i) + for (auto j = i; j > 0; --j) + res[j] += res[j-1]; + return res; + } +}; +``` + +来源:https://github.com/xiaqunfeng/leetcode \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0120._Triangle.md b/docs/Algorithm/Leetcode/C++/0120._Triangle.md new file mode 100755 index 00000000..b5c7712e --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0120._Triangle.md @@ -0,0 +1,42 @@ +# 120. Triangle + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/triangle/ + + > 内容描述 + + ``` +给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 + +例如,给定三角形: + +[ + [2], + [3,4], + [6,5,7], + [4,1,8,3] +] +自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 + ``` + +## 解题方案 +> 思路 1 +``` +dfs超时 +采用dp,自底向上更新每个数,每个数加上向下路径的最小和,更新到第一层既为第一层向下路径的最小和。 +``` + +```cpp + +int minimumTotal(vector>& triangle) { + for (int i = triangle.size() - 2; i >= 0; i--) + for (int j = 0; j < triangle[i].size(); j++) + triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1]); + return triangle[0][0]; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0121._Best_Tim_ to_Buy_and_Sell_Stock.md b/docs/Algorithm/Leetcode/C++/0121._Best_Tim_ to_Buy_and_Sell_Stock.md new file mode 100755 index 00000000..e2864006 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0121._Best_Tim_ to_Buy_and_Sell_Stock.md @@ -0,0 +1,40 @@ +# 121. Best Time to Buy and Sell Stock + +**ѶEasy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/best-time-to-buy-and-sell-stock/submissions/ + +> + +``` + + +Say you have an array for which the ith element is the price of a given stock on day i. + +If 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. + +Note that you cannot sell a stock before you buy one. +``` + +> ˼· +******- ʱ临Ӷ: O(n)*****- ռ临Ӷ: O(1)****** +ֱӱ飬ÿμ¼СֵʱpriceСֵͱȽ```min(ans,prices[i] - min)``` +```cpp +class Solution { +public: + int maxProfit(vector& prices) { + int min1 = INT_MAX; + int ans = 0; + for(int i = 0;i < prices.size();++i) + if(prices[i] > min1) + ans = max(ans,prices[i] - min1); + else + min1 = prices[i]; + return ans; + } + +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0122._Best_Time_to_Buy_and_Sell_Stock_II.md b/docs/Algorithm/Leetcode/C++/0122._Best_Time_to_Buy_and_Sell_Stock_II.md new file mode 100755 index 00000000..4cc1bf51 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0122._Best_Time_to_Buy_and_Sell_Stock_II.md @@ -0,0 +1,55 @@ +# 122. Best Time to Buy and Sell Stock II + +**Ѷ:Easy** + +## ˢ +> ԭ + +* https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ + +> + +``` +Say you have an array for which the ith element is the price of a given stock on day i. + +Design 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). + +Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again). + +Example 1: + +Input: [7,1,5,3,6,4] +Output: 7 +Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. + Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3. +Example 2: + +Input: [1,2,3,4,5] +Output: 4 +Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. + Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are + engaging multiple transactions at the same time. You must sell before buying again. +Example 3: + +Input: [7,6,4,3,1] +Output: 0 +Explanation: In this case, no transaction is done, i.e. max profit = 0. +``` + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +ñĽⷨܿͿ⣬ǿøõķO(N)ʱ临ӶȽ⡣i = 1顣 prices[i] > prices[i - 1]ans += prices[i] - prices[i - 1] + +```cpp +class Solution { +public: + int maxProfit(vector& prices) { + int maxRet = 0; + for(int i = 1;i < prices.size();++i) + if(prices[i] > prices[i - 1]) + maxRet += (prices[i] - prices[i - 1]); + return maxRet; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0123._Best_Time_to_Buy _and_Sell_Stock_III.md b/docs/Algorithm/Leetcode/C++/0123._Best_Time_to_Buy _and_Sell_Stock_III.md new file mode 100755 index 00000000..07ae9fc6 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0123._Best_Time_to_Buy _and_Sell_Stock_III.md @@ -0,0 +1,100 @@ +# 123. Best Time to Buy and Sell Stock III + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ + +> + +``` +Say you have an array for which the ith element is the price of a given stock on day i. + +Design an algorithm to find the maximum profit. You may complete at most two transactions. + +Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again). + +Example 1: + +Input: [3,3,5,0,0,3,1,4] +Output: 6 +Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3. + Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3. +Example 2: + +Input: [1,2,3,4,5] +Output: 4 +Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. + Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are + engaging multiple transactions at the same time. You must sell before buying again. +Example 3: + +Input: [7,6,4,3,1] +Output: 0 +Explanation: In this case, no transaction is done, i.e. max profit = 0. +``` + +> ˼·1 +******- ʱ临Ӷ: O(n^2)******- ռ临Ӷ: O(n)****** + +֮ǰIJͬҪΣü仯ķ¼µi֮׵ֵǵڶÿ콻ֵֻ֮Ҫ飬һ콻ֵһöÿνףֵ + +```cpp +class Solution { +public: + int maxProfit(vector& prices) { + int len = prices.size(); + if(!len) + return 0; + int arr[len + 1]; + memset(arr,0,sizeof(arr)); + int max1 = prices[len - 1],price = 0; + for(int j = len - 2;j >= 0;--j) + { + if(prices[j] > max1) + max1 = prices[j]; + arr[j] = max(arr[j + 1],max1 - prices[j]); + } + int ret = 0; + for(int i = 0;i < len;++i) + for(int j = i + 1;j < len;++j) + if(prices[j] > prices[i]) + ret = max(ret,prices[j] - prices[i] + arr[j + 1]); + return ret; + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(n)****** + +ڶַǶ˼·1ŻһνʱһСֵmin1˵i֮ǰСֵ֮飬ÿθmin1prices[i] - min1ֵ + +```cpp +class Solution { +public: + int maxProfit(vector& prices) { + int len = prices.size(); + if(!len) + return 0; + int arr[len + 1]; + memset(arr,0,sizeof(arr)); + int max1 = prices[len - 1],price = 0; + for(int j = len - 2;j >= 0;--j) + { + if(prices[j] > max1) + max1 = prices[j]; + arr[j] = max(arr[j + 1],max1 - prices[j]); + } + int ret = 0; + int min1 = prices[0]; + for(int i = 0;i < len;++i) + { + if(prices[i] < min1) + min1 = prices[i]; + ret = max(ret,prices[i] - min1 + arr[i + 1]); + } + return ret; + } +}; \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0124._Binary_Tree_Maximum_Path_Sum.md b/docs/Algorithm/Leetcode/C++/0124._Binary_Tree_Maximum_Path_Sum.md new file mode 100755 index 00000000..08a7041f --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0124._Binary_Tree_Maximum_Path_Sum.md @@ -0,0 +1,78 @@ +# 124. Binary Tree Maximum Path Sum + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/binary-tree-maximum-path-sum/ + +> + +``` +Given a non-empty binary tree, find the maximum path sum. + +For 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. + +Example 1: + +Input: [1,2,3] + + 1 + / \ + 2 3 + +Output: 6 +Example 2: + +Input: [-10,9,20,null,null,15,7] + + -10 + / \ + 9 20 + / \ + 15 7 + +Output: 42 +``` + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +뵽DPʱ临ӶΪO(n^2)ǶֻˣǿøŻ㷨úȻ¼ڵ· ansȽϡ max(l,r) ڵֵ + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + int ans = INT_MIN; + int travel(TreeNode* root) + { + if(!root) + return 0; + int l = travel(root ->left); + int r = travel(root ->right); + if(l < 0) + l = 0; + if(r < 0) + r = 0; + int temp = r + l + root ->val; + ans = max(ans,temp); + return max(l,r) + root ->val; + } + int maxPathSum(TreeNode* root) { + travel(root); + if(ans == INT_MIN) + return 0; + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0127._Word_Ladde.md b/docs/Algorithm/Leetcode/C++/0127._Word_Ladde.md new file mode 100755 index 00000000..70fbd4c3 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0127._Word_Ladde.md @@ -0,0 +1,158 @@ +# 127. Word Ladder + +**Ѷ:Medium** + +## ˢ + +> ԭ + +* https://leetcode.com/problems/word-ladder/ + +> + +``` +Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that: + +Only one letter can be changed at a time. +Each transformed word must exist in the word list. Note that beginWord is not a transformed word. +Note: + +Return 0 if there is no such transformation sequence. +All words have the same length. +All words contain only lowercase alphabetic characters. +You may assume no duplicates in the word list. +You may assume beginWord and endWord are non-empty and are not the same. +Example 1: + +Input: +beginWord = "hit", +endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] + +Output: 5 + +Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", +return its length 5. +Example 2: + +Input: +beginWord = "hit" +endWord = "cog" +wordList = ["hot","dot","dog","lot","log"] + +Output: 0 + +Explanation: The endWord "cog" is not in wordList, therefore no possible transformation. + +``` +> ˼·1 + +******- ʱ临Ӷ: O(EV+V^3)******- ռ临Ӷ: O(n^2)****** + +һ⣬һBFS⣬ǹһͼöά鴢棬ȻBFSһһEDZߵvǽڵ + +```cpp +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + wordList.push_back(beginWord); + int len = wordList[0].length(),length = wordList.size(); + queue q; + vector d[length]; + int min_l[length]; + for(int i = 0;i < length;++i) + min_l[i] = INT_MAX; + for(int i = 0;i < length;++i) + for(int j = i + 1;j min_l[t] + 1) + { + q.push(d[t][i]); + min_l[d[t][i]] = min_l[t] + 1; + if(d[t][i] == length - 1) + return min_l[length - 1] + 1; + } + q.pop(); + } + return 0; + } +}; +``` + + +> ˼·2 + +******- ʱ临Ӷ: O(EV*len)******- ռ临Ӷ: O(V)****** + +ķЧʲߣ˿Ըunordered_setеַȻÿֻĶһַsetвǷڼɡlenÿʵijȡ + +```cpp +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + wordList.push_back(beginWord); + int len = wordList[0].length(),length = wordList.size(); + queue q; + unordered_set s(wordList.begin(),wordList.end()); + int min_l[length]; + auto pos = s.find(endWord); + if(pos == s.end()) + return 0; + q.push(*pos); + int level = 1; + string count1 = endWord; + while(q.size()) + { + string temp1 = q.front(); + for(int j = 0;j < temp1.size();++j) + { + string temp = temp1; + for(int i = 'a';i <= 'z';++i) + { + temp[j] = i; + if(temp != temp1 && s.find(temp) != s.end()) + { + q.push(temp); + if(temp == beginWord) + return level + 1; + s.erase(temp); + } + temp = temp1; + } + } + if(count1 == temp1) + { + count1 = q.back(); + level++; + } + s.erase(temp1); + q.pop(); + } + return 0; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0128._Longest_Consecutive_Sequence.md b/docs/Algorithm/Leetcode/C++/0128._Longest_Consecutive_Sequence.md new file mode 100755 index 00000000..b847e9c5 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0128._Longest_Consecutive_Sequence.md @@ -0,0 +1,83 @@ +# 128. Longest Consecutive Sequence + +**难度:Hard** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/longest-consecutive-sequence/ + +> 内容描述 + +``` +Given an unsorted array of integers, find the length of the longest consecutive elements sequence. + +Your algorithm should run in O(n) complexity. + +Example: + +Input: [100, 4, 200, 1, 3, 2] +Output: 4 +Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4. +``` + +> 思路1 +******- 时间复杂度: O(n)******- 空间复杂度: O(1)****** + +先对数组进行排序。在用unique()函数去除重复的数字。在遍历数组,找到最长的连续数字。时间复杂度为O(nlgn)。 + +```cpp +class Solution { +public: + int longestConsecutive(vector& nums) { + if(!nums.size()) + return 0; + sort(nums.begin(),nums.end()); + auto end_pos = unique(nums.begin(),nums.end()); + int j = end_pos - nums.begin(); + int ans = 1,sum = 1; + for(int i = 1;i < j;++i) + { + if(nums[i] == nums[i - 1] + 1) + sum++; + else + sum = 1; + ans = max(ans,sum); + } + return ans; + } +}; +``` +> 思路2 +******- 时间复杂度: O(nlgn)******- 空间复杂度: O(1)****** +c++中的unordered_map是用hash桶实现的,所以可以在线性时间内完成。县遍历数组,用nums[i]作为unordered_map的键值。0作为 value。0表示此时的nums[i]还没被遍历过。接着遍历数组,用DFS搜索每个nums[i]的最长连续数字。被遍历过的nums[i]的unordered_map值设为1 +```cpp +class Solution { +public: + int longestConsecutive(vector& nums) { + if(!nums.size()) + return 0; + unordered_map m; + for(int i = 0;i < nums.size();++i) + m[nums[i]] = 0; + int ans = 0; + for(int i = 0;i < nums.size();++i) + { + if(m[nums[i]]) + continue; + m[nums[i]] = 1; + int temp = nums[i] + 1,sum = 0; + while(m.find(temp) != m.end()) + m[temp++] = 1; + sum = temp - nums[i]; + temp = nums[i] - 1; + //cout << temp << endl; + while(m.find(temp) != m.end()) + m[temp--] = 1; + sum += (nums[i] - temp - 1); + ans = max(ans,sum); + } + return ans; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0129._Sum_Root_to_Leaf_Numbers.md b/docs/Algorithm/Leetcode/C++/0129._Sum_Root_to_Leaf_Numbers.md new file mode 100755 index 00000000..fe7ab4ae --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0129._Sum_Root_to_Leaf_Numbers.md @@ -0,0 +1,75 @@ +# 129. Sum Root to Leaf Numbers + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/ + + > 内容描述 + + ``` +给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。 + +例如,从根到叶子节点路径 1->2->3 代表数字 123。 + +计算从根到叶子节点生成的所有数字之和。 + +说明: 叶子节点是指没有子节点的节点。 + +示例 1: + +输入: [1,2,3] + 1 + / \ + 2 3 +输出: 25 +解释: +从根到叶子节点路径 1->2 代表数字 12. +从根到叶子节点路径 1->3 代表数字 13. +因此,数字总和 = 12 + 13 = 25. +示例 2: + +输入: [4,9,0,5,1] + 4 + / \ + 9 0 + / \ +5 1 +输出: 1026 +解释: +从根到叶子节点路径 4->9->5 代表数字 495. +从根到叶子节点路径 4->9->1 代表数字 491. +从根到叶子节点路径 4->0 代表数字 40. +因此,数字总和 = 495 + 491 + 40 = 1026. + ``` + +## 解题方案 +> 思路 1 +``` +深搜,记录路径,到叶子节点相加 +``` + +```cpp +void dfs(TreeNode* root, string path, int& sum){ + if(root==NULL){ + return; + } + if(root->left==NULL && root->right==NULL){ + path = path+std::to_string(root->val); + int tmp = std::stoi(path); + sum+=tmp; + return ; + } + dfs(root->left, path+std::to_string(root->val), sum); + dfs(root->right, path+std::to_string(root->val), sum); +} +int sumNumbers(TreeNode* root) { + int sum=0; + dfs(root, "", sum); + return sum; +} + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0131._Palindrome_Partitioning.md b/docs/Algorithm/Leetcode/C++/0131._Palindrome_Partitioning.md new file mode 100755 index 00000000..d4e60396 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0131._Palindrome_Partitioning.md @@ -0,0 +1,64 @@ +# 131. Palindrome Paritionaing + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/palindrome-partitioning/ + + > 内容描述 + + ``` +给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。 + +返回 s 所有可能的分割方案。 + +示例: + +输入: "aab" +输出: +[ + ["aa","b"], + ["a","a","b"] +] + ``` + +## 解题方案 +> 思路 1 +``` +回溯,判断是否回文。 +``` + +```cpp +bool isValid(string str){ + for(int i=0;i& path, vector>& ans, string s){ + if(start == s.length()){ + ans.push_back(path); + return ; + } + for(int i=start;i> partition(string s) { + vector> ans; + if(s.length()==0) + return ans; + vector path; + dfs(0, path, ans, s); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0136._Single_Numbe.md b/docs/Algorithm/Leetcode/C++/0136._Single_Numbe.md new file mode 100755 index 00000000..47cf9a94 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0136._Single_Numbe.md @@ -0,0 +1,79 @@ +# 136. Single Numbe + +**难度:Easy** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/single-number/ + +> 内容描述 + +``` +Given a non-empty array of integers, every element appears twice except for one. Find that single one. + +Note: + +Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? + +Example 1: + +Input: [2,2,1] +Output: 1 +Example 2: + +Input: [4,1,2,1,2] +Output: 4 +``` + +> 思路1 +******- 时间复杂度: O(n)******- 空间复杂度: O(1)****** + +用异或运算解决这道题,这里用了异或运算的几个性质,异或的交换和结合律,还有两个相同的数异或的值为0,任何数异或0为它本身。有了这些基本只是之后,我们只要对数组进行异或运算得到的数就是答案。因为只有一个数是 single number,其余的数都成双,那么最后就相当于single number异或0 + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + int ans = nums[0]; + for(int i = 1;i < nums.size();++i) + ans ^= nums[i]; + return ans; + } +}; +``` +> 思路2 +******- 时间复杂度: O(n)******- 空间复杂度: O(1)****** + +第二种思路将所有数转成二进制,记录下每一位不为2的倍数,这些位为1,其余为0,求出最后的数就是答案。 + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + int arr[32][2],t = 1; + memset(arr,0,sizeof(arr)); + for(int i = 0;i < nums.size();++i) + { + int count1 = 0; + if(nums[i] < 0) + { + t *= -1; + nums[i] *= -1; + } + while(nums[i]) + { + arr[count1++][nums[i] % 2]++; + nums[i] /= 2; + } + } + int ans = 0; + for(int i = 0;i < 32;++i) + if(arr[i][1] % 2) + ans += pow(2,i); + if(t < 0) + ans *= -1; + return ans; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0137._Single_Number_II.md b/docs/Algorithm/Leetcode/C++/0137._Single_Number_II.md new file mode 100755 index 00000000..e449b0d3 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0137._Single_Number_II.md @@ -0,0 +1,64 @@ +# 137.Single Number II + +**难度: Medium** + + ## 刷题内容 + > 原题连接 +* https://leetcode.com/problems/single-number-ii/ + > 内容描述 + ``` +Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one. + +Note: + +Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? + +Example 1: + +Input: [2,2,3,2] +Output: 3 +Example 2: + +Input: [0,1,0,1,0,1,99] +Output: 99 + ``` + +## 解题方案 +> 思路 +``` +相同的数有相同的二进制,相同位置有相同的1,0;所以如果都出现3次,那么相同位上出现的1和0都是3的倍数 +所以,统计不同位上1、0的个数,如果不是3的倍数,说明出现次数不是3的倍数。 +所有不为3倍数的位加起来就是结果。 +``` + +```cpp +class Solution { +public: + int singleNumber(vector& nums) { + int arr[32][2],t = 0; + memset(arr,0,sizeof(arr)); + for(int i = 0;i < nums.size();++i) + { + int count1 = 0; + long long temp = nums[i]; + if(nums[i] < 0) + { + t++; + temp *= -1; + } + while(temp) + { + arr[count1++][temp % 2]++; + temp /= 2; + } + } + int ans = 0; + for(int i = 0;i < 32;++i) + if(arr[i][1] % 3) + ans += pow(2,i); + if(t % 3) + ans *= -1; + return ans; + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0141._Linked_List_Cycle.md b/docs/Algorithm/Leetcode/C++/0141._Linked_List_Cycle.md new file mode 100755 index 00000000..dace3235 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0141._Linked_List_Cycle.md @@ -0,0 +1,54 @@ +#141. linked list cycle + +**Ѷ:Easy** + +## ˢ + +> ԭ + +*https://leetcode.com/problems/linked-list-cycle/ +* +> + +``` +Given a linked list, determine if it has a cycle in it. + +Follow up: +Can you solve it without using extra space? +``` + +## ⷽ + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +͵Ŀָеãָ룬ÿѭһ1һ2ָл + + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + bool hasCycle(ListNode *head) { + if(head == nullptr) + return false; + ListNode* l1 = head,*l2 = head ->next; + while(true) + { + if(l2 == nullptr || l2 ->next == nullptr) + return false; + if(l1 == l2) + return true; + l1 = l1 ->next; + l2 = l2 ->next ->next; + } + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0142._Linked_List_Cycle_II.md b/docs/Algorithm/Leetcode/C++/0142._Linked_List_Cycle_II.md new file mode 100755 index 00000000..8491a839 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0142._Linked_List_Cycle_II.md @@ -0,0 +1,78 @@ +# 142. linked list cycle II + +***难度:Medium*** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/linked-list-cycle-ii/ + +> 内容描述 + +``` +Given a linked list, return the node where the cycle begins. If there is no cycle, return null. + +Note: Do not modify the linked list. + +Follow up: +Can you solve it without using extra space? +``` + +## 解题方案 + +> 思路 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +上一道题已经解决了链表是否有环的问题,那么如何判断环的入口在哪里,我们先设入口链表的头的距离为m,两个人指针相遇的节点距离入口为x,l2比l1多走 n 圈,环部分的链表长度为p。这样,我们就得到了如下公式。 +``` +2(m + x) = m + n * p + x + +``` +化简得到 +``` +m = n * p - x + +``` +接着我们再定义一个指针 ret,当 ret 移动 m 个,l1刚好移动 n * p - x,就是二者相遇的地方即为入口 + + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *detectCycle(ListNode *head) { + if(head == nullptr) + return nullptr; + ListNode* l1 = head,*l2 = head; + int count1 = 0,count2 = 0; + while(1) + { + if(l2 == nullptr || l2 ->next == nullptr) + return nullptr; + l1 = l1 ->next; + ++count1; + l2 = l2 ->next ->next; + + ++count2; + if(l1 == l2) + break; + } + ListNode* ret = head; + while(1) + { + if(l1 == ret) + return ret; + ret = ret ->next; + l1 = l1 ->next; + } + } +}; +``` diff --git a/docs/Algorithm/Leetcode/C++/0144._Binary_Tree_Preorder_Traversal.md b/docs/Algorithm/Leetcode/C++/0144._Binary_Tree_Preorder_Traversal.md new file mode 100755 index 00000000..47e4b109 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0144._Binary_Tree_Preorder_Traversal.md @@ -0,0 +1,48 @@ +# 144. Binary Tree Preorder Traversal + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + + > 内容描述 + + ``` + 给定一个二叉树,返回它的 前序 遍历。 + + 示例: + +输入: [1,null,2,3] + 1 + \ + 2 + / + 3 + +输出: [1,2,3] + + ``` + +## 解题方案 +> 思路 1 +``` +递归 +``` + +```cpp +void dfs(TreeNode* root, vector &ans){ + if(root==NULL) + return ; + ans.push_back(root->val); + dfs(root->left, ans); + dfs(root->right, ans); +} +vector preorderTraversal(TreeNode* root) { + vector ans; + dfs(root, ans); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0145._Binary_Tree_Postorder_Traversal.md b/docs/Algorithm/Leetcode/C++/0145._Binary_Tree_Postorder_Traversal.md new file mode 100755 index 00000000..085f47fb --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0145._Binary_Tree_Postorder_Traversal.md @@ -0,0 +1,113 @@ +# 145. Binary Tree Postorder Traversal + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/binary-tree-postorder-traversal/ + +> + +``` +Given a binary tree, return the postorder traversal of its nodes' values. + +Example: + +Input: [1,null,2,3] + 1 + \ + 2 + / + 3 + +Output: [3,2,1] +Follow up: Recursive solution is trivial, could you do it iteratively? +``` + +> ˼·1 +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(1)****** + +ж治ڣж治ڣroot->valɡ + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + void travel(TreeNode* root,vector& v) + { + if(!root) + return; + if(root ->left) + travel(root ->left,v); + if(root ->right) + travel(root ->right,v); + v.push_back(root ->val); + } + vector postorderTraversal(TreeNode* root) { + vector v; + travel(root,v); + return v; + } +}; +``` +> ˼·2 +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)****** + +Ŀᵽ˲õݹñķʽȥ⡣ôǾҪջȥԪأʱǻҪһջԪǷӦ pop + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector postorderTraversal(TreeNode* root) { + vector v; + vector ans; + vector count1; + if(root) + { + v.push_back(root); + count1.push_back(0); + } + while(v.size()) + { + int index = v.size(); + if(!count1[index - 1] && v[index -1] ->left) + { + count1[index - 1] = 1; + v.push_back(v[index - 1] ->left); + count1.push_back(0); + } + else if(count1[index - 1] != 2 && v[index - 1] ->right) + { + count1[index - 1] = 2; + v.push_back(v[index - 1] ->right); + count1.push_back(0); + } + else + { + ans.push_back(v[index - 1] ->val); + count1.pop_back(); + v.pop_back(); + } + } + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0147._Insert_on_Sort_List.md b/docs/Algorithm/Leetcode/C++/0147._Insert_on_Sort_List.md new file mode 100755 index 00000000..5fad7387 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0147._Insert_on_Sort_List.md @@ -0,0 +1,85 @@ +# 147. Insertion Sort List + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/insertion-sort-list/ + +> + +``` +Sort a linked list using insertion sort. + + +A graphical example of insertion sort. The partial sorted list (black) initially contains only the first element in the list. +With each iteration one element (red) is removed from the input data and inserted in-place into the sorted list + + +Algorithm of Insertion Sort: + +Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. +At each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there. +It repeats until no input elements remain. + +Example 1: + +Input: 4->2->1->3 +Output: 1->2->3->4 +Example 2: + +Input: -1->5->3->4->0 +Output: -1->0->3->4->5 +``` + +> ˼· +******- ʱ临Ӷ: O(N^2)******- ռ临Ӷ: O(1)****** + +в򡣺ͨIJһҪעҪIJϤijֵеλʱҪڵ뵽ʵλãִIJɾ + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* insertionSortList(ListNode* head) { + if(!head) + return head; + ListNode* current = head ->next; + ListNode* pre = head; + while(current) + { + ListNode* temp2 = head; + ListNode* temp1 = head; + while(temp2 ->val < current ->val) + { + temp1 = temp2; + temp2 = temp2 ->next; + } + if(temp1 != temp2) + temp1 ->next = current; + else + head = current; + if(temp2 != current) + { + pre ->next = current ->next; + current ->next = temp2; + current = pre ->next; + } + else + { + pre = current; + current = current ->next; + } + } + return head; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0148._Sort _list.md b/docs/Algorithm/Leetcode/C++/0148._Sort _list.md new file mode 100755 index 00000000..7e21ce43 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0148._Sort _list.md @@ -0,0 +1,59 @@ +# 148.Sort list + +**ѶMedium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/sort-list/ + +> + +``` +Sort a linked list in O(n log n) time using constant space complexity. + +Example 1: + +Input: 4->2->1->3 +Output: 1->2->3->4 +Example 2: + +Input: -1->5->3->4->0 +Output: -1->0->3->4->5 +``` +> ˼· +******- ʱ临Ӷ: O(nlgn)******- ռ临Ӷ: O(n)****** + +˼·ͷ͵˸c++е sort() 㷨ֽе val δУ򡣽ٰемɡ + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* sortList(ListNode* head) { + vector v; + ListNode* current = head; + while(current) + { + v.push_back(current ->val); + current = current ->next; + } + sort(v.begin(),v.end()); + current = head; + int i = 0; + while(current) + { + current ->val = v[i++]; + current = current ->next; + } + return head; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0151._Reverse_Words_in_a_String.md b/docs/Algorithm/Leetcode/C++/0151._Reverse_Words_in_a_String.md new file mode 100755 index 00000000..d993b523 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0151._Reverse_Words_in_a_String.md @@ -0,0 +1,63 @@ +# 151. Reverse Words in a String + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/reverse-words-in-a-string/ + +> + +``` +Given an input string, reverse the string word by word. + +Example: + +Input: "the sky is blue", +Output: "blue is sky the". +Note: + +A word is defined as a sequence of non-space characters. +Input string may contain leading or trailing spaces. However, your reversed string should not contain leading or trailing spaces. +You need to reduce multiple spaces between two words to a single space in the reversed string. +``` + + +> ˼· +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)****** + +űȱ飬ոΪһʣעڱ߽жϣڿһµ string ոյĵʣֵ sܵ˵ѡǻһСģ֮ĿոǶģַĿͷĩβҲжոҪдѭո + +```cpp +class Solution { +public: + void reverseWords(string &s) { + int i = 0,j = s.length(); + while(i < j && s[i] == ' ') + i++; + j--; + while(j >= i && s[j] == ' ') + j--; + j++; + string s1; + while(j >= i) + { + int temp = j - 1; + while(temp >= 0 && s[temp] != ' ') + temp--; + int t = temp; + temp++; + while(j > temp) + s1.push_back(s[temp++]); + j = t - 1; + while(j >= i && s[j] == ' ') + j--; + j++; + if(j >= i) + s1.push_back(' '); + } + s = s1; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0153._Find_Minimum_in_Rotated_Sorted_Array.md b/docs/Algorithm/Leetcode/C++/0153._Find_Minimum_in_Rotated_Sorted_Array.md new file mode 100755 index 00000000..490fead5 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0153._Find_Minimum_in_Rotated_Sorted_Array.md @@ -0,0 +1,91 @@ +## 153. Find Minimum in Rotated Sorted Array + +难度:Medium + +## 内容 + +题目链接:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/ + +Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. + +(i.e., `[0,1,2,4,5,6,7]` might become `[4,5,6,7,0,1,2]`). + +Find the minimum element. + +You may assume no duplicate exists in the array. + +**Example 1:** + +``` +Input: [3,4,5,1,2] +Output: 1 +``` + +**Example 2:** + +``` +Input: [4,5,6,7,0,1,2] +Output: 0 +``` + +## 思路 + +最简单的方法,挨个遍历,如果当前值小于前一个值,那么输出当前值即可,时间复杂度为O(n)。 +二分查找法,时间复杂度为O(log(n))。 + +## 代码 + +快速简单的写了一个,提交,过了。 + +``` +class Solution { +public: + int findMin(vector& nums) { + int res_idx = 0; + for (int i = 1; i < nums.size(); ++i) + if (nums[i] < nums[i-1]) { + res_idx = i; + break; + } + return nums[res_idx]; + } +}; +``` + +二分查找的简单实现 + +``` +class Solution { +public: + int findMin(vector& nums) { + int left = 0, right = nums.size() - 1; + while (nums[left] > nums[right]) { + int mid = (right + left) >> 1; + if (nums[mid] >= nums[left]) + left = mid + 1; + else + right = mid; + } + return nums[left]; + } +}; +``` + +用迭代器来实现 + +``` +class Solution { +public: + int findMin(vector& nums) { + auto begin = nums.begin(); + auto end = std::prev(nums.end()); + while (*begin > *end) { + auto gap = (end - begin) >> 1; + *next(begin, gap) >= *begin ? advance(begin, gap + 1) : advance(end, -gap); + } + return *begin; + } +}; +``` + +来源:https://github.com/xiaqunfeng/leetcode \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md b/docs/Algorithm/Leetcode/C++/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md new file mode 100755 index 00000000..5c5207d9 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md @@ -0,0 +1,105 @@ +## 154. Find Minimum in Rotated Sorted Array II + +难度:Hard + +## 内容 + +题目链接:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/description/ + +Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. + +(i.e., `[0,1,2,4,5,6,7]` might become `[4,5,6,7,0,1,2]`). + +Find the minimum element. + +The array may contain duplicates. + +**Example 1:** + +``` +Input: [1,3,5] +Output: 1 +``` + +**Example 2:** + +``` +Input: [2,2,2,0,1] +Output: 0 +``` + +**Note:** + +- This is a follow up problem to [Find Minimum in Rotated Sorted Array](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/). +- Would allow duplicates affect the run-time complexity? How and why? + +## 思路 + +这题竟然是hard,好尴尬。最简单时间复杂度为O(n)的方法,我把前一题的代码一行不动的挪过来,Accepted。 +二分查找法,时间复杂度为O(log(n))。 + +## 代码 + +O(n),和前一题代码一样 + +``` +class Solution { +public: + int findMin(vector& nums) { + int res_idx = 0; + for (int i = 1; i < nums.size(); ++i) + if (nums[i] < nums[i-1]) { + res_idx = i; + break; + } + return nums[res_idx]; + } +}; +``` + +二分法实现 + +``` +class Solution { +public: + int findMin(vector& nums) { + int left = 0, right = nums.size() - 1; + + while (left < right && nums[left] >= nums[right]) { + int mid = left + (right - left) / 2; + if (nums[mid] == nums[left]) { + ++left; + } else if (nums[mid] < nums[left]) { + right = mid; + } else { + left = mid + 1; + } + } + + return nums[left]; + } +}; +``` + +迭代器二分查找的实现 + +``` +class Solution { +public: + int findMin(vector& nums) { + auto left = nums.begin(); + auto right = std::prev(nums.end()); + while (*left >= *right && left < right) { + auto gap = (right - left) >> 1; + if (*next(left, gap) == *left) + advance(left, 1); + else if (*next(left, gap) < *left) + advance(right, -gap); + else + advance(left, gap + 1); + } + return *left; +}; +``` + +来源:https://github.com/xiaqunfeng/leetcode \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0160._Intersection_Of_Two_Linked_Lists.md b/docs/Algorithm/Leetcode/C++/0160._Intersection_Of_Two_Linked_Lists.md new file mode 100755 index 00000000..73f5102a --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0160._Intersection_Of_Two_Linked_Lists.md @@ -0,0 +1,48 @@ +# 160 intersection_of_Two_Linked_Lists + **难度: Easy** +## 刷题内容 +>原题连接 +* https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ +>内容描述 +``` +Write a program to find the node at which the intersection of two singly linked lists begins. +``` + +## 解题方案 +> 思路 1 +``` +1. 求长度差 +2. 长的链表先走掉长的部分 +3. 一起走,相遇即为交点 +``` +```cpp + ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { + int lena=0; + int lenb=0; + ListNode *a = headA; + ListNode *b = headB; + while(a){ + lena++; + a=a->next; + } + while(b){ + lenb++; + b=b->next; + } + if(a!=b) + return NULL; + int sub=abs(lena-lenb); + if(lena>lenb){ + while(sub--) + headA=headA->next; + }else + while(sub--) + headB=headB->next; + while(headA!=headB){ + headA = headA->next; + headB = headB->next; + } + return headA; + } +``` + diff --git a/docs/Algorithm/Leetcode/C++/0164._Maximum_Gap.md b/docs/Algorithm/Leetcode/C++/0164._Maximum_Gap.md new file mode 100755 index 00000000..c026935e --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0164._Maximum_Gap.md @@ -0,0 +1,97 @@ +# 164. Maximum Gap + +**Ѷ:Hard** + +## ˢ +> ԭ + +* https://leetcode.com/problems/maximum-gap/ + +> + +``` +Given an unsorted array, find the maximum difference between the successive elements in its sorted form. + +Return 0 if the array contains less than 2 elements. + +Example 1: + +Input: [3,6,9,1] +Output: 3 +Explanation: The sorted form of the array is [1,3,6,9], either + (3,6) or (6,9) has the maximum difference 3. +Example 2: + +Input: [10] +Output: 0 +Explanation: The array contains less than 2 elements, therefore return 0. +Note: + +You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range. +Try to solve it in linear time/space. +``` + +> ˼·1 +******- ʱ临Ӷ: O(NlgN)******- ռ临Ӷ: O(1)****** + +ͨķȥʵѣȶٱ飬μ nums[i] - nums[i - 1] ֵ + +```cpp +class Solution { +public: + int maximumGap(vector& nums) { + if(nums.size() < 2) + return 0; + sort(nums.begin(),nums.end()); + int ans = INT_MIN; + for(int i = 1;i < nums.size();++i) + ans = max(ans,nums[i] - nums[i - 1]); + return ans; + } +}; +``` + +> ˼·2 +******- ʱ临Ӷ: O(N)******- ռ临Ӷ: O(N)****** + +ĿеnoteѾʾԵʱͿռ临ӶɡڵֵĴС32bitsڵģôǿͰ߻򣬾㷨͸ӶȵƵԲο㷨ۡDz˻ +```cpp +class Solution { +public: + int maximumGap(vector& nums) { + if(nums.size() < 2) + return 0; + int res[nums.size()]; + int t[nums.size()][10]; + for(int i = 0;i < nums.size();++i) + { + res[i] = i; + for(int j = 0;j < 10;++j) + t[i][j] = 0; + int temp = nums[i],j = 9; + while(temp) + { + t[i][j--] = temp % 10; + temp /= 10; + } + } + for(int i = 9;i >= 0;--i) + { + int bucket[nums.size()],count1[10]; + memset(count1,0,sizeof(count1)); + for(int j = 0;j < nums.size();++j) + count1[t[res[j]][i]]++; + for(int j = 1;j < 10;++j) + count1[j] += count1[j - 1]; + for(int j = nums.size() - 1;j >= 0;--j) + bucket[--count1[t[res[j]][i]]] = res[j]; + for(int j = 0;j < nums.size();++j) + res[j] = bucket[j]; + } + int ans INT_MIN; + for(int i = 1;i < nums.size();++i) + ans = max(ans,nums[res[i]] - nums[res[i - 1]]); + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0166._Fraction_to_Recurring_Decimal.md b/docs/Algorithm/Leetcode/C++/0166._Fraction_to_Recurring_Decimal.md new file mode 100755 index 00000000..a4ba70ff --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0166._Fraction_to_Recurring_Decimal.md @@ -0,0 +1,105 @@ +# 166. Fraction to Recurring Decimal + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/fraction-to-recurring-decimal/ + +> + +``` +Given two integers representing the numerator and denominator of a fraction, return the fraction in string format. + +If the fractional part is repeating, enclose the repeating part in parentheses. + +Example 1: + +Input: numerator = 1, denominator = 2 +Output: "0.5" +Example 2: + +Input: numerator = 2, denominator = 1 +Output: "2" +Example 3: + +Input: numerator = 2, denominator = 3 +Output: "0.(6)" +``` + +> ˼· +******- ʱ临Ӷ: O(nlgn)******- ռ临Ӷ: O(n)****** + +⿼ǵĵȽ϶࣬mapÿεԼõĴַеλãֻҪmapгֹˣʾʼѭҪעõĴпǸҪעӸšӦΪintСֵ-1intֵlong longͱ + +```cpp +class Solution { +public: + void join_str(string& str,long long num,int t) + { + if(!num) + { + if(t < 0) + str.push_back('-'); + str.push_back('0'); + return; + } + while(num) + { + str.push_back(num % 10 + '0'); + num /= 10; + } + if(t < 0) + str.push_back('-'); + reverse(str.begin(),str.end()); + } + string fractionToDecimal(int numerator, int denominator) { + map m; + if(!numerator) + return "0"; + int t = 1; + long long n1 = numerator,d1 = denominator; + if(numerator < 0) + { + t *= -1; + n1 *= -1; + } + if(denominator < 0) + { + t *= -1; + d1 *= -1; + } + long long num = n1 / d1; + string ans; + join_str(ans,num,t); + long long quotient = n1 % d1; + if(quotient) + ans.push_back('.'); + string temp; + int count1 = 0; + while(quotient) + { + long long new_num = quotient * 10; + if(m[new_num]) + { + temp.push_back(')'); + count1 = m[new_num]; + break; + } + m[new_num] = temp.length() + 1; + temp.push_back(new_num / d1 + '0'); + quotient = new_num % d1; + } + if(count1) + { + ans.append(temp.begin(),temp.begin() + count1 - 1); + ans.push_back('('); + ans.append(temp.begin() + count1 - 1,temp.end()); + } + else + ans.append(temp.begin(),temp.end()); + return ans; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0167._Two_Sum_II-Input_array_is_sorted.md b/docs/Algorithm/Leetcode/C++/0167._Two_Sum_II-Input_array_is_sorted.md new file mode 100755 index 00000000..63db7cda --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0167._Two_Sum_II-Input_array_is_sorted.md @@ -0,0 +1,53 @@ +## 167. Two Sum II - Input array is sorted + +难度:Easy + +## 内容 + +原题链接:https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/ + +Given an array of integers that is already **sorted in ascending order**, find two numbers such that they add up to a specific target number. + +The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. + +**Note:** + +- Your returned answers (both index1 and index2) are not zero-based. +- You may assume that each input would have *exactly* one solution and you may not use the *same* element twice. + +**Example:** + +``` +Input: numbers = [2,7,11,15], target = 9 +Output: [1,2] +Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2. +``` + +## 思路 + +关键点: + +- 升序排列 +- 一定有解 + +## 代码 + +``` +class Solution { +public: + vector twoSum(vector& numbers, int target) { + int left = 0, right = numbers.size() - 1; + while (left < right) { + int sum = numbers[left] + numbers[right]; + if (sum < target) + left++; + else if (sum > target) + right--; + else + return {left + 1, right + 1}; + } + return {0, 0}; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0199._Binary_Tree_Right_Side_View.md b/docs/Algorithm/Leetcode/C++/0199._Binary_Tree_Right_Side_View.md new file mode 100755 index 00000000..c0389e97 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0199._Binary_Tree_Right_Side_View.md @@ -0,0 +1,58 @@ +# 199. Binary Tree Right Side View + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/binary-tree-right-side-view/ + + > 内容描述 + + ``` +给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 + +示例: + +输入: [1,2,3,null,5,null,4] +输出: [1, 3, 4] +解释: + + 1 <--- + / \ +2 3 <--- + \ \ + 5 4 <--- + ``` + +## 解题方案 +> 思路 1 +``` +二叉树层次遍历 +``` + +```cpp +vector rightSideView(TreeNode* root) { + vector ans; + if(root==NULL) + return ans; + vector stack; + stack.push_back(root); + + while(!stack.empty()){ + vector tmp; + TreeNode* node; + for(int i=0;ileft) + tmp.push_back(node->left); + if(node->right) + tmp.push_back(node->right); + } + ans.push_back(node->val); + stack = tmp; + } + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0216._Combination_Sum_III.md b/docs/Algorithm/Leetcode/C++/0216._Combination_Sum_III.md new file mode 100755 index 00000000..16b76007 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0216._Combination_Sum_III.md @@ -0,0 +1,56 @@ +# 216. Combination Sum III + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/combination-sum-iii/ + + > 内容描述 + + ``` +找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。 + +说明: + +所有数字都是正整数。 +解集不能包含重复的组合。 +示例 1: + +输入: k = 3, n = 7 +输出: [[1,2,4]] +示例 2: + +输入: k = 3, n = 9 +输出: [[1,2,6], [1,3,5], [2,3,4]] + ``` + +## 解题方案 +> 思路 1 +``` +回溯 +``` + +```cpp + void dfs(int n, int k, int index, vector& path, vector>& ans){ + if(n<0||k<0) + return; + if(n==0&&k==0){ + ans.push_back(path); + return ; + } + for(int i=index;i<=9;i++){ + path.push_back(i); + dfs(n-i, k-1, i+1, path, ans); + path.pop_back(); + } +} +vector> combinationSum3(int k, int n) { + vector> ans; + vector path; + dfs(n, k, 1, path, ans); + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0230._Kth_Smallest_Element_in_a_BST.md b/docs/Algorithm/Leetcode/C++/0230._Kth_Smallest_Element_in_a_BST.md new file mode 100755 index 00000000..94e4978a --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0230._Kth_Smallest_Element_in_a_BST.md @@ -0,0 +1,63 @@ +# 230. Kth Smallest Element in a BST + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/ + + > 内容描述 + + ``` +给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。 + +说明: +你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。 + +示例 1: + +输入: root = [3,1,4,null,2], k = 1 + 3 + / \ + 1 4 + \ + 2 +输出: 1 +示例 2: + +输入: root = [5,3,6,2,4,null,null,1], k = 3 + 5 + / \ + 3 6 + / \ + 2 4 + / + 1 +输出: 3 +进阶: +如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数? + ``` + +## 解题方案 +> 思路 1 +``` +遍历树后排序 +``` +``` +```cpp +void dfs(TreeNode* root, vector& nums){ + if(root==NULL) + return ; + nums.push_back(root->val); + dfs(root->left, nums); + dfs(root->right, nums); +} +int kthSmallest(TreeNode* root, int k) { + vector nums; + dfs(root, nums); + sort(nums.begin(), nums.end()); + return nums[k-1]; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0260._Single_Number_III.md b/docs/Algorithm/Leetcode/C++/0260._Single_Number_III.md new file mode 100755 index 00000000..0d8397f0 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0260._Single_Number_III.md @@ -0,0 +1,54 @@ +# 260. Single Number III + +**Ѷ:Medium** + +## ˢ +> ԭ + +* https://leetcode.com/problems/single-number-iii/ + +> + +``` +Given 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. + +Example: + +Input: [1,2,1,3,2,5] +Output: [3,5] +Note: + +The order of the result is not important. So in the above example, [5, 3] is also correct. +Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity? +``` + +> ˼·1 +******- ʱ临Ӷ: O(n)******- ռ临Ӷ: O(1)****** + +֮ǰвͬ single number֮ǰ˼άȥĻڶ֮õӦ single number ֵaXorbaXorbתɶƣӵ0λ𣬵һΪ1λ˵λa bȣеֳ֣λΪ0һ֣Ϊ1һ֣Ͱֵ˲ͬСŷֱܵõ + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + int aXorB = 0; + for (int num : nums) { + aXorB ^= num; + } + int differingBit = 1; + while ((differingBit & aXorB) == 0) { + differingBit <<= 1; + } + int a = 0; + int b = 0; + for (int num : nums) { + if ((num & differingBit) == 0) { + a ^= num; + } else { + b ^= num; + } + } + return {a, b}; + } +}; +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0287._Find_the_Duplicate_Number.md b/docs/Algorithm/Leetcode/C++/0287._Find_the_Duplicate_Number.md new file mode 100755 index 00000000..644959f0 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0287._Find_the_Duplicate_Number.md @@ -0,0 +1,48 @@ +# 287. Find the Duplicate Number + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/find-the-duplicate-number/ + + > 内容描述 + + ``` +给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 + +示例 1: + +输入: [1,3,4,2,2] +输出: 2 +示例 2: + +输入: [3,1,3,4,2] +输出: 3 +说明: + +不能更改原数组(假设数组是只读的)。 +只能使用额外的 O(1) 的空间。 +时间复杂度小于 O(n2) 。 +数组中只有一个重复的数字,但它可能不止重复出现一次。 + ``` + +## 解题方案 +> 思路 1 +``` +采用下标取反标记,假设下标数字为负,则为ans +``` + +```cpp +int findDuplicate(vector& nums) { + for(int i=0;i难度: Easy** +## 刷题内容 +> 原题连接 +* https://leetcode-cn.com/problems/power-of-three/ +> 内容描述 +``` +Given an integer, write a function to determine if it is a power of three. + +###example +1. Input: 27 -> Output: true + +2. Input: 0 -> Output: false + +3. Input: 9 -> Output: true + +4. Input: 45 -> Output: false +``` +### 题解方案 +``` +只要是3的幂次,一定能够被3的最大次方整除 +``` +### coding +```cpp + bool isPowerOfThree(int n) { + return n > 0 and 1162261467 % n ==0; + } +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0328._Odd_Even_Linked_List.md b/docs/Algorithm/Leetcode/C++/0328._Odd_Even_Linked_List.md new file mode 100755 index 00000000..85ae7826 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0328._Odd_Even_Linked_List.md @@ -0,0 +1,51 @@ +# 328. Odd Even Linked List + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/odd-even-linked-list/ + + > 内容描述 + + ``` +给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。 + +请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。 + +示例 1: + +输入: 1->2->3->4->5->NULL +输出: 1->3->5->2->4->NULL +示例 2: + +输入: 2->1->3->5->6->4->7->NULL +输出: 2->3->6->7->1->5->4->NULL + ``` + +## 解题方案 +> 思路 1 +``` +如题 +``` + +```cpp +ListNode* oddEvenList(ListNode* head) { + if(head==NULL || head->next==NULL) + return head; + ListNode* link = head->next; + ListNode* slow=head; + ListNode* fast=head->next; + while(fast&&fast->next){ + slow->next = fast->next; + fast->next = fast->next->next; + slow=slow->next; + fast=fast->next; + } + cout<val<next = link; + return head; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0329._Longest_Increasing_Path_in_a_Matrix.md b/docs/Algorithm/Leetcode/C++/0329._Longest_Increasing_Path_in_a_Matrix.md new file mode 100755 index 00000000..15855f86 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0329._Longest_Increasing_Path_in_a_Matrix.md @@ -0,0 +1,100 @@ +# 329. Longest Increasing Path in a Matrix + +**难度Hard** + +## 刷题内容 +> 原题连接 + +* https://leetcode.com/problems/longest-increasing-path-in-a-matrix/ + +> 内容描述 + +``` +Given an integer matrix, find the length of the longest increasing path. + +From 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). + +Example 1: + +Input: nums = +[ + [9,9,4], + [6,6,8], + [2,1,1] +] +Output: 4 +Explanation: The longest increasing path is [1, 2, 6, 9]. +Example 2: + +Input: nums = +[ + [3,4,5], + [3,2,6], + [2,2,1] +] +Output: 4 +Explanation: The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed. +``` + +> 思路 +******- 时间复杂度: O(n * m)******-空间复杂度: O(n * m)****** + +如果直接用DFS去做,时间复杂度为O(n^4),我们就需要对算法进行优化,定义一个二维数组用记忆化的方法去记录进行剪枝 +```cpp +class Solution { +public: + int** dp; + int len1,len2,ans; + int dfs(vector >&matrix,int i,int j) + { + if(dp[i][j] != -1) + return dp[i][j]; + //cout << i << j << endl; + if(i && matrix[i][j] < matrix[i - 1][j]) + dp[i][j] = max(dp[i][j],dfs(matrix,i - 1,j) + 1); + if(j < len2 - 1 && matrix[i][j] < matrix[i][j + 1]) + dp[i][j] = max(dp[i][j],dfs(matrix,i,j + 1) + 1); + if(i < len1 - 1 && matrix[i][j] < matrix[i + 1][j]) + dp[i][j] = max(dp[i][j],dfs(matrix,i + 1,j) + 1); + if(j && matrix[i][j] < matrix[i][j - 1]) + dp[i][j] = max(dp[i][j],dfs(matrix,i,j - 1) + 1); + //cout << dp[i][j]; + if(dp[i][j] == -1) + dp[i][j] = 1; + ans = max(ans,dp[i][j]); + return dp[i][j]; + } + int longestIncreasingPath(vector>& matrix) { + len1 = matrix.size(); + if(!len1) + return 0; + len2 = matrix[0].size(); + ans = 0; + dp = new int*[len1]; + for(int i = 0; i < len1; ++i){ + dp[i] = new int[len2]; + for(int j=0;j难度: Medium** + + ## 刷题内容 + > 原题连接 + +* https://leetcode-cn.com/problems/counting-bits/ + > 内容描述 + ``` +给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 + +示例 1: + +输入: 2 +输出: [0,1,1] +示例 2: + +输入: 5 +输出: [0,1,1,2,1,2] +进阶: + +给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗? +要求算法的空间复杂度为O(n)。 +你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。 + ``` + +## 解题方案 +> 思路 1 +``` +第i个数的二进制中数含1的个数等于等于第(i&i-1)个数中二进制数中1的个数加1 +``` + +```cpp +vector countBits(int num) { + vector res(num+1,0); + for(int i=1;i<=num;i++){ + res[i]=res[i&(i-1)]+1; + } + return res; +} + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0413._Arithmetic_Slices.md b/docs/Algorithm/Leetcode/C++/0413._Arithmetic_Slices.md new file mode 100755 index 00000000..9366220b --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0413._Arithmetic_Slices.md @@ -0,0 +1,65 @@ +# 413. Arithmetic Slices + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/arithmetic-slices/ + + > 内容描述 + + ``` +如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列。 + +例如,以下数列为等差数列: + +1, 3, 5, 7, 9 +7, 7, 7, 7 +3, -1, -5, -9 +以下数列不是等差数列。 + +1, 1, 2, 5, 7 + + +数组 A 包含 N 个数,且索引从0开始。数组 A 的一个子数组划分为数组 (P, Q),P 与 Q 是整数且满足 0<=P 思路 1 +``` +dp[i]记录以i开头任意结尾的等差数列的个数 +如果A[i+1]-A[i]==A[i]-A[i-1],那么A[i+1],则dp[i+1]=dp[i]+1 +最后所有位置开头的等差数列的和为结果。 +``` + +```cpp +int numberOfArithmeticSlices(vector& A) { + vector dp(A.size(), 0); + for(int i=2;i难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/find-all-duplicates-in-an-array/ + + > 内容描述 + + ``` +给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次。 + +找到所有出现两次的元素。 + +你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗? + +示例: + +输入: +[4,3,2,7,8,2,3,1] + +输出: +[2,3] + ``` + +## 解题方案 +> 思路 1 +``` +数值在1-n之间,可以对相应数值-1的下标位置取反,如果出现两次,就为正值,否则为负。 +``` + +```cpp +vector findDuplicates(vector& nums) { + vector ans; + for(int i=0;i难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/find-bottom-left-tree-value/ + + > 内容描述 + + ``` +给定一个二叉树,在树的最后一行找到最左边的值。 + +示例 1: + +输入: + + 2 + / \ + 1 3 + +输出: +1 + + +示例 2: + +输入: + + 1 + / \ + 2 3 + / / \ + 4 5 6 + / + 7 + +输出: +7 + + +注意: 您可以假设树(即给定的根节点)不为 NULL。 + ``` + +## 解题方案 +> 思路 1 +``` +从左到右层次遍历二叉树 +``` + +```cpp + int findBottomLeftValue(TreeNode* root) { + vector que; + que.push_back(root); + while(que.size()>0){ + vector tmp; + int len = que.size(); + for(int i=0;ileft) + tmp.push_back(que[i]->left); + if(que[i]->right) + tmp.push_back(que[i]->right); + } + if(tmp.size()==0) + break; + que = tmp; + } + return que[0]->val; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0515._Find_Largest_Value_in_Each_Tree_Row.md b/docs/Algorithm/Leetcode/C++/0515._Find_Largest_Value_in_Each_Tree_Row.md new file mode 100755 index 00000000..88a8454f --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0515._Find_Largest_Value_in_Each_Tree_Row.md @@ -0,0 +1,60 @@ +# 515. Find Largest Value in Each Tree Row + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/ + + > 内容描述 + + ``` +您需要在二叉树的每一行中找到最大的值。 + +示例: + +输入: + + 1 + / \ + 3 2 + / \ \ + 5 3 9 + +输出: [1, 3, 9] + ``` + +## 解题方案 +> 思路 1 +``` +层次遍历二叉树 +``` + +```cpp +vector largestValues(TreeNode* root) { + vector ans; + if(root==NULL) + return ans; + vector level; + level.push_back(root); + while(level.size()>0){ + vector tmp; + int n = level.size(); + int maxnum = INT_MIN; + for(int i=0;ival) + maxnum=level[i]->val; + if(level[i]->left) + tmp.push_back(level[i]->left); + if(level[i]->right) + tmp.push_back(level[i]->right); + } + ans.push_back(maxnum); + level=tmp; + } + return ans; +} + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0540._Single_Element_in_a_Sorted_Array.md b/docs/Algorithm/Leetcode/C++/0540._Single_Element_in_a_Sorted_Array.md new file mode 100755 index 00000000..fc6f361f --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0540._Single_Element_in_a_Sorted_Array.md @@ -0,0 +1,46 @@ +# 540. Single Element in a Sorted Array + + **难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/single-element-in-a-sorted-array/ + + > 内容描述 + + ``` +给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。 + +示例 1: + +输入: [1,1,2,3,3,4,4,8,8] +输出: 2 +示例 2: + +输入: [3,3,7,7,10,11,11] +输出: 10 +注意: 您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。 + ``` + +## 解题方案 +> 思路 1 +``` +时间复杂度选择二分 + +``` + +```cpp +int singleNonDuplicate(vector& nums) { + int start=0, end=nums.size()/2; + while(start难度: Easy** + + ## 刷题内容 + > 原题连接 +* https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/ + > 内容描述 + ``` + 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。 + +你找到的子数组应是最短的,请输出它的长度。 + +示例 1: + +输入: [2, 6, 4, 8, 10, 9, 15] +输出: 5 +解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。 + ``` + +## 解题方案 +> 思路 1 +``` +1. 拷贝数组,排序 +2. 计算两个数组不同的起始位置和末端位置 +3. 计算差值 +``` + +```cpp +int findUnsortedSubarray(vector& nums) { + vector tmp(nums.begin(), nums.end()); + sort(tmp.begin(), tmp.end()); + int start=-1, end=-1; + for(int i=0;i=0;i--){ + if(tmp[i]!=nums[i]){ + end = i; + break; + } + } + if(start==-1&&end==-1) + return 0; + return end-start+1; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0629._K_Inverse_Pairs_Array.md b/docs/Algorithm/Leetcode/C++/0629._K_Inverse_Pairs_Array.md new file mode 100755 index 00000000..a8a9045a --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0629._K_Inverse_Pairs_Array.md @@ -0,0 +1,58 @@ +### 793. K Inverse Pairs Array + + + +题目: +https://leetcode.com/problems/k-inverse-pairs-array + +难度: +Hard + +题意: + +1. 给定一个数n和一个数k +2. 求n个元素,逆序对数等于k的序列数 + +思路: + +- 最容易想到的是动态规划 +- 我们一个数一个数丢进去,假设已经存在n-1个元素的序列,我们要放一个比他们都小的数,这时候根据插入的位置不同就会产生0到(n-1)的逆序对数 +- 设`dp[n][k]`表示n个元素,逆序对数等于k的序列数,有状态转移方程`dp[n][k]=sum{dp[n-1][k - (0..(n-1))]}` +- 如果直接求的话,复杂度是o(n^3) +- 注意观察算`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]`的时候只需要加一个数减一个数就可以维护这个和 +- 复杂度是o(n^2) + +解法: + +```c++ +#include +#include + +class Solution { +public: + int a[1001][1001]; + int MOD = 1000000007; + int kInversePairs(int n, int k) { + memset(a, 0, sizeof(a)); + a[0][0] = 1; + for (int i = 1;i <= n;i++) { + int s = 0; + for (int j = 0;j <= k;j++) { + s += a[i - 1][j]; + if (s >= MOD) { + s -= MOD; + } + if (j - i >= 0) { + s -= a[i - 1][j - i]; + if (s < 0) { + s += MOD; + } + } + a[i][j] = s; + } + } + return a[n][k]; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0632._Smallest_Range.md b/docs/Algorithm/Leetcode/C++/0632._Smallest_Range.md new file mode 100755 index 00000000..23656d93 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0632._Smallest_Range.md @@ -0,0 +1,59 @@ +### 632. Smallest Range + + + +题目: +https://leetcode.com/problems/smallest-range/ + +难度: +Hard + +题意: + +1. 给定n个序列,求一个最小区间,使得每个序列至少一个数在这个区间里面 + +思路: + +- 采用移动区间的做法。如果区间左端点为l,那么我们需要在所有的序列中寻找比l大的最小数,构成一个区间[l, r] +- 首先,将所有序列的第一个数字入堆,我们记录一个最大值。这时候堆里面的数形成一个区间,判断和记录下来。接着区间开始移动,将堆里面的最小数弹出丢掉,再从这个最小数所在的序列取出下一个数放进堆,又形成一个区间,判断和记录下来。如此循环,直到其中一个序列没有数可以进堆 + +解法: + +```c++ +class Solution { +public: + struct myData { + int x, y, value; + myData(int _x = 0, int _y = 0, int _value = 0): x(_x), y(_y), value(_value) {} + bool operator<(const myData &b) const { + return value > b.value; + } + }; + vector smallestRange(vector>& nums) { + int l = -10000000, r = -10000000; + priority_queue q; + int res = -10000000; + for (int i = 0;i < nums.size();i++) { + q.push(myData(i, 0, nums[i][0])); + res = res > nums[i][0] ? res : nums[i][0]; + } + while (q.size() == nums.size()) { + myData t = q.top(); + q.pop(); + if (l == -10000000 || (res - t.value) < (r - l)) { + l = t.value; + r = res; + } + if (t.y + 1 < nums[t.x].size()) { + q.push(myData(t.x, t.y + 1, nums[t.x][t.y + 1])); + res = res > nums[t.x][t.y + 1] ? res : nums[t.x][t.y + 1]; + } + } + vector ret; + ret.push_back(l); + ret.push_back(r); + return ret; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0654._maximum_binary_tree.md b/docs/Algorithm/Leetcode/C++/0654._maximum_binary_tree.md new file mode 100755 index 00000000..67cbd034 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0654._maximum_binary_tree.md @@ -0,0 +1,57 @@ +# 654. Maximum Binary Tree + + **难度: Medium** + + ## 刷题内容 + > 原题连接 +* https://leetcode-cn.com/problems/maximum-binary-tree/ + > 内容描述 + ``` +给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下: + +二叉树的根是数组中的最大元素。 +左子树是通过数组中最大值左边部分构造出的最大二叉树。 +右子树是通过数组中最大值右边部分构造出的最大二叉树。 +通过给定的数组构建最大二叉树,并且输出这个树的根节点。 + +Example 1: + +输入: [3,2,1,6,0,5] +输入: 返回下面这棵树的根节点: + + 6 + / \ + 3 5 + \ / + 2 0 + \ + 1 + ``` + +## 解题方案 +> 思路 1 +``` +深搜构建二叉树 +``` + +```cpp +TreeNode* dfs(vector& nums, int start, int end){ + int root_val = 0, max=INT_MIN; + if(start==end) + return NULL; + for(int i=start;ileft = dfs(nums, start, root_val); + root->right = dfs(nums, root_val+1, end); + return root; +} +TreeNode* constructMaximumBinaryTree(vector& nums) { + return dfs(nums, 0, nums.size()); +} + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0668._Kth_Smallest_Number_in_Multiplication_Table.md b/docs/Algorithm/Leetcode/C++/0668._Kth_Smallest_Number_in_Multiplication_Table.md new file mode 100755 index 00000000..db8c2122 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0668._Kth_Smallest_Number_in_Multiplication_Table.md @@ -0,0 +1,55 @@ +### 668. Kth Smallest Number in Multiplication Table + + + +题目: +https://leetcode.com/problems/kth-smallest-number-in-multiplication-table/ + +难度: +Hard + +题意: + +1. 给定一个m和n,表示生成m*n的矩阵,矩阵里面的值为a(i,j) = i * j +2. 求这个矩阵所有数中第k小是哪个数 + +思路: + +- 由于m,n,k都很大,因此不能用排序或者堆排序的方式进行解答 +- 我们可以二分结果,因为结果肯定是在0到n*m之间的某个数 +- 假设二分值是p,我们需要判断整个矩阵中小于p有多少个,只需要遍历一遍,根据p/i来判断第i行小于p有多少个,累加 + +解法: + +```c++ +#include +#include + +class Solution { +public: + int a[1001][1001]; + int MOD = 1000000007; + int kInversePairs(int n, int k) { + memset(a, 0, sizeof(a)); + a[0][0] = 1; + for (int i = 1;i <= n;i++) { + int s = 0; + for (int j = 0;j <= k;j++) { + s += a[i - 1][j]; + if (s >= MOD) { + s -= MOD; + } + if (j - i >= 0) { + s -= a[i - 1][j - i]; + if (s < 0) { + s += MOD; + } + } + a[i][j] = s; + } + } + return a[n][k]; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0701._Insert_into_a_Binary_Search_Tree.md b/docs/Algorithm/Leetcode/C++/0701._Insert_into_a_Binary_Search_Tree.md new file mode 100755 index 00000000..6cb6ecfe --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0701._Insert_into_a_Binary_Search_Tree.md @@ -0,0 +1,76 @@ +# 701. Insert into a Binary Search Tree + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/ + + > 内容描述 + + ``` +给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 保证原始二叉搜索树中不存在新值。 + +注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。 + +例如, + +给定二叉搜索树: + + 4 + / \ + 2 7 + / \ + 1 3 + +和 插入的值: 5 +你可以返回这个二叉搜索树: + + 4 + / \ + 2 7 + / \ / + 1 3 5 +或者这个树也是有效的: + + 5 + / \ + 2 7 + / \ + 1 3 + \ + 4 + ``` + +## 解题方案 +> 思路 1 +``` +二分查找,记录父节点和大小关系 +``` + +```cpp +TreeNode* insertIntoBST(TreeNode* root, int val) { + TreeNode* pre; + TreeNode* head = root; + int side = 0; + while(root){ + pre = root; + if(root->val>val){ + root = root->left; + side = 1; + } + else if(root->valright; + } + } + TreeNode* node = new TreeNode(val); + if(side==1) + pre->left = node; + else + pre->right = node; + return head; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0715._Range_Module.md b/docs/Algorithm/Leetcode/C++/0715._Range_Module.md new file mode 100755 index 00000000..11f58f10 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0715._Range_Module.md @@ -0,0 +1,126 @@ +### 715. Range Module + + + +题目: +https://leetcode.com/problems/range-module/ + +难度: +Hard + +题意: + +1. 设计一种数据结构 +2. 操作1:向该数据结构插入一个线段(的所有实数) +3. 操作2:向该数据结构删除一个线段(的所有实数) +4. 操作3:查询一个线段包含的所有实数是否都在这个数据结构中 + +思路: + +- 线段与线段之间有三种关系,包含,相交,相离。插入一个线段,我们需要寻找可能包含和相交的线段来合并 +- 假设插入的线段为[a,b),我们需要在已有的线段中寻找包含和相交的线段。假设已有线段为[i,j),当j b +- 我们需要一种数据结构,可以遍历,可以快速定位到比某个数小的最大值。平衡树满足我们的需求。 +- 平衡树的key是线段的左端点,value是线段的右端点 +- 剩下的操作就是线段合并和线段删除了,用笔模拟一下就可以得到结果 + +解法: + +```c++ +class RangeModule { +public: + map range; + RangeModule() { + + } + + struct Range { + int x, y; + Range(int _x = 0, int _y = 0) : x(_x), y(_y) {} + }; + + int min(int a, int b) { + return a < b ? a : b; + } + + int max(int a, int b) { + return a < b ? b : a; + } + + void addRange(int left, int right) { + if (range.size() == 0) { + range[left] = right; + return; + } + map::iterator it; + vector forDelete; + it = range.upper_bound(left); + if (it != range.begin()) { + it--; + } + while (it != range.end() && it->first <= right) { + if ((it -> second >= right && it -> first <= right) || (right >= it -> second && left <= it -> second)) { + forDelete.push_back(it -> first); + left = min(left, it -> first); + right = max(right, it -> second); + } + it++; + } + for (int i = 0;i < forDelete.size();i++) { + range.erase(forDelete[i]); + } + range[left] = right; + } + + bool queryRange(int left, int right) { + if (range.size() == 0) { + return false; + } + map::iterator it; + it = range.upper_bound(left); + if (it != range.begin()) { + it--; + } + if (it -> first <= left && it -> second >= right) { + return true; + } else { + return false; + } + } + + void removeRange(int left, int right) { + if (range.size() == 0) { + return; + } + map::iterator it; + vector forDelete; + vector forInsert; + it = range.upper_bound(left); + if (it != range.begin()) { + it--; + } + while (it != range.end() && it->first <= right) { + if (it -> first >= left && it -> second <= right) { + forDelete.push_back(it->first); + } else if (it -> first < left && it -> second > right) { + forDelete.push_back(it->first); + forInsert.push_back(Range(it -> first, left)); + forInsert.push_back(Range(right, it -> second)); + } else if(it -> first < left && it -> second >= left) { + forDelete.push_back(it->first); + forInsert.push_back(Range(it -> first, left)); + } else if (it -> first <= right && it -> second > right) { + forDelete.push_back(it->first); + forInsert.push_back(Range(right, it -> second)); + } + it++; + } + for (int i = 0;i < forDelete.size();i++) { + range.erase(forDelete[i]); + } + for (int i = 0;i < forInsert.size();i++) { + range[forInsert[i].x] = forInsert[i].y; + } + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0719._Find_K-th_Smallest_Pair_Distance.md b/docs/Algorithm/Leetcode/C++/0719._Find_K-th_Smallest_Pair_Distance.md new file mode 100755 index 00000000..c992e29c --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0719._Find_K-th_Smallest_Pair_Distance.md @@ -0,0 +1,66 @@ +### 793. Find K-th Smallest Pair Distance + + + +题目: +https://leetcode.com/problems/find-k-th-smallest-pair-distance/ + +难度: +Hard + +题意: + +1. 给定一个数组 +2. 计算数组总所有点对的差 +3. 求第k大是多少 + +思路: + +- 暴力枚举肯定不行 +- 换种思路,我们可以二分结果,数组所有点对的差的取值范围是1到最大值-最小值 +- 二分结果,计算点对的差小于或等于这个结果有多少个,跟k比是大还是小 +- 计算点对的差小于或等于某个值p有多少个,需要遍历数组,对于每个数a,判断数组中有多少个数小于或等于a+p,累加即可 +- 复杂度是o(nlogn*logn) + +解法: + +```java +class Solution { +public: + int findIndex(vector& nums, int left, int right, int k) { + while (right - left > 1) { + int mid = (left + right) / 2; + if (nums[mid] <= k) { + left = mid; + } else { + right = mid; + } + } + return left; + } + int judge(vector& nums, int p) { + int ret = 0; + for (int i = 0;i < nums.size();i++) { + ret += findIndex(nums, i, nums.size(), p + nums[i]) - i; + } + return ret; + } + int bsearch(vector& nums, int left, int right, int k) { + left--; + while (right - left > 1) { + int mid = (left + right) / 2; + if (judge(nums, mid) >= k) { + right = mid; + } else { + left = mid; + } + } + return right; + } + int smallestDistancePair(vector& nums, int k) { + sort(nums.begin(), nums.end()); + return bsearch(nums, 0, nums[nums.size() - 1] - nums[0], k); + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0739._Daily_Temperatures.md b/docs/Algorithm/Leetcode/C++/0739._Daily_Temperatures.md new file mode 100755 index 00000000..5d414204 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0739._Daily_Temperatures.md @@ -0,0 +1,47 @@ +# 739. Daily Temperatures + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/daily-temperatures/ + + > 内容描述 + + ``` +根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高的天数。如果之后都不会升高,请输入 0 来代替。 + +例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。 + +提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的都是 [30, 100] 范围内的整数。 + ``` + +## 解题方案 +> 思路 1 +``` +暴力超时。 +采用递减栈思维,用栈存下表 +当前值小于栈顶值,入栈 +否则出站,出栈index的结果为当前处理下表和出栈下标的差值。 +``` + +```cpp +vector dailyTemperatures(vector& temperatures) { + if(temperatures.size()==0) + return temperatures; + vector ans(temperatures.size(), 0); + stack index; + for(int i=0;itemperatures[index.top()]){ + int tmp = index.top(); + index.pop(); + ans[tmp]=i-tmp; + } + index.push(i); + } + return ans; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0797._All_Paths_From_Source_To_Target.md b/docs/Algorithm/Leetcode/C++/0797._All_Paths_From_Source_To_Target.md new file mode 100755 index 00000000..c9d1deb3 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0797._All_Paths_From_Source_To_Target.md @@ -0,0 +1,55 @@ +# 797. All Paths From Source to Target + + **难度: Medium** + + ## 刷题内容 + > 原题连接 +* https://leetcode-cn.com/problems/all-paths-from-source-to-target/ + > 内容描述 + ``` +给一个有 n 个结点的有向无环图,找到所有从 0 到 n-1 的路径并输出(不要求按顺序) + +二维数组的第 i 个数组中的单元都表示有向图中 i 号结点所能到达的下一些结点(译者注:有向图是有方向的,即规定了a→b你就不能从b→a)空就是没有下一个结点了。 + +示例: +输入: [[1,2], [3], [3], []] +输出: [[0,1,3],[0,2,3]] +解释: 图是这样的: +0--->1 +| | +v v +2--->3 +这有两条路: 0 -> 1 -> 3 和 0 -> 2 -> 3. +提示: + +结点的数字会在范围 [2, 15] 内。 +你可以把路径以任意顺序输出,但在路径内的结点的顺序必须保证。 + ``` + +## 解题方案 +> 思路 1 +``` +深搜二叉树,记录路径,当i==graph.size()-1,停止。 +``` + +```cpp +void dfs(int i, vector& path, int target, vector>& ans, vector>& graph){ + if(i==target){ + ans.push_back(path); + return ; + } + for(int j=0;j> allPathsSourceTarget(vector>& graph) { + vector> ans; + vector path; + path.push_back(0); + dfs(0, path, graph.size()-1, ans, graph); + return ans; +} + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0814._Binary_Tree_Pruning.md b/docs/Algorithm/Leetcode/C++/0814._Binary_Tree_Pruning.md new file mode 100755 index 00000000..2925ff9e --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0814._Binary_Tree_Pruning.md @@ -0,0 +1,43 @@ +# 814. Binary Tree Pruning + + **难度: Medium** + + ## 刷题内容 + > 原题连接 +* https://leetcode-cn.com/problems/binary-tree-pruning/ + > 内容描述 + ``` +给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1。 + +返回移除了所有不包含 1 的子树的原二叉树。 + +( 节点 X 的子树为 X 本身,以及所有 X 的后代。) + +示例1: +输入: [1,null,0,0,1] +输出: [1,null,0,null,1] + ``` + +## 解题方案 +> 思路 1 +``` +遍历二叉树,切除左右子树中无1的子树。 +``` + +```cpp +bool dfs(TreeNode* root){ + if(root==NULL) + return false; + bool left = dfs(root->left); + bool right = dfs(root->right); + if(left==false) + root->left=NULL; + if(right==false) + root->right=NULL; + return root->val==1||left||right; +} +TreeNode* pruneTree(TreeNode* root) { + dfs(root); + return root; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0841._Keys_and_Rooms.md b/docs/Algorithm/Leetcode/C++/0841._Keys_and_Rooms.md new file mode 100755 index 00000000..739a2729 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0841._Keys_and_Rooms.md @@ -0,0 +1,76 @@ +# 841. Keys and Rooms + + **难度: Medium** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/keys-and-rooms/submissions/ + + > 内容描述 + + ``` +有 N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,...,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。 + +在形式上,对于每个房间 i 都有一个钥匙列表 rooms[i],每个钥匙 rooms[i][j] 由 [0,1,...,N-1] 中的一个整数表示,其中 N = rooms.length。 钥匙 rooms[i][j] = v 可以打开编号为 v 的房间。 + +最初,除 0 号房间外的其余所有房间都被锁住。 + +你可以自由地在房间之间来回走动。 + +如果能进入每个房间返回 true,否则返回 false。 + +示例 1: + +输入: [[1],[2],[3],[]] +输出: true +解释: +我们从 0 号房间开始,拿到钥匙 1。 +之后我们去 1 号房间,拿到钥匙 2。 +然后我们去 2 号房间,拿到钥匙 3。 +最后我们去了 3 号房间。 +由于我们能够进入每个房间,我们返回 true。 +示例 2: + +输入:[[1,3],[3,0,1],[2],[0]] +输出:false +解释:我们不能进入 2 号房间。 +提示: + +1 <= rooms.length <= 1000 +0 <= rooms[i].length <= 1000 +所有房间中的钥匙数量总计不超过 3000。 + ``` + +## 解题方案 +> 思路 1 +``` +广搜遍历可以到达房间, 记录开启房间个数。 +``` + +```cpp +bool canVisitAllRooms(vector>& rooms) { + queue keys; + vector unlocked(rooms.size(), false); + keys.push(0); + unlocked[0]=true; + int locked=rooms.size()-1; + while(!keys.empty()){ + int key = keys.front(); + keys.pop(); + for(int i=0;i难度: Middle** + + ## 刷题内容 + + > 原题连接 + +* https://leetcode-cn.com/problems/stone-game/ + + > 内容描述 + + ``` +亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。 + +游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。 + +亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。 + +假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 true ,当李赢得比赛时返回 false 。 + + + +示例: + +输入:[5,3,4,5] +输出:true +解释: +亚历克斯先开始,只能拿前 5 颗或后 5 颗石子 。 +假设他取了前 5 颗,这一行就变成了 [3,4,5] 。 +如果李拿走前 3 颗,那么剩下的是 [4,5],亚历克斯拿走后 5 颗赢得 10 分。 +如果李拿走后 5 颗,那么剩下的是 [3,4],亚历克斯拿走后 4 颗赢得 9 分。 +这表明,取前 5 颗石子对亚历克斯来说是一个胜利的举动,所以我们返回 true 。 + + ``` + +## 解题方案 +> 思路 1 +``` +dp: +dp[i][j]表示从i-j之间alex和lee拿的总数差 +dp[i][j]>0: alex赢,否则lee赢 +从i==j时:dp[i][i]为piles[i] +i!=j时:dp[i][j] = max(piles[i]-dp[i+1][j], piles[j]-dp[i][j-1]) +两个人交错拿石子,所以上一步的赢为下一步的输,所以本次取减去上一次的差,为本次过后总的比分,取较大。 + +``` + +```cpp +bool stoneGame(vector& piles) { + int len = piles.size(); + vector> dp(len, vector(len, 0)); + for(int i=0;i0; +} +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/C++/0945._Minimum_Increment_to_Make_Array_Unique.md b/docs/Algorithm/Leetcode/C++/0945._Minimum_Increment_to_Make_Array_Unique.md new file mode 100755 index 00000000..f9cf5f24 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0945._Minimum_Increment_to_Make_Array_Unique.md @@ -0,0 +1,38 @@ +### 945. Minimum Increment to Make Array Unique + +题目: +https://leetcode.com/problems/minimum-increment-to-make-array-unique/ + +难度: +Medium + +题意: + +1. 给定一个数组 +2. 每次操作,数组中的元素只能+1 +3. 求最少多少次操作,数组中所有元素都不相同 + +思路: + +- 注意看题意,数组中的元素只能+1,所以数组需要先排序,从小到大,因为小的数处理好,大的数不管怎么+1都不会冲突 +- 从小到大循环,需要操作的只可能是跟前一个相同的,或者比前一个小(因为前一个也有可能跟前前一个相同),因此我们跟前面一个比较,如果比前面一个大,那么啥事都没,如果跟前一个相同,或者比前一个小,那么我们就把他加到比前面一个数大1即可 + +解法: + +```c++ +class Solution { +public: + int minIncrementForUnique(vector& A) { + sort(A.begin(), A.end()); + int ret = 0; + for (int i= 1;i < A.size();i++) { + if (A[i] <= A[i - 1]) { + ret += A[i - 1] - A[i] + 1; + A[i] = A[i - 1] + 1; + } + } + return ret; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0946._Validate_Stack_Sequences.md b/docs/Algorithm/Leetcode/C++/0946._Validate_Stack_Sequences.md new file mode 100755 index 00000000..33aa174b --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0946._Validate_Stack_Sequences.md @@ -0,0 +1,41 @@ +### 946. Validate Stack Sequences + +题目: +https://leetcode.com/problems/validate-stack-sequences/ + +难度: +Medium + +题意: + +1. 两个数组 +2. 问入栈顺序为pushed数组,是否可能出栈顺序为popped数组 + +思路: + +- 模拟即可。我们把新建一个栈,按照pushed数组的顺序一个一个丢进去,并且,检查popped数组前面的数组,如果可以弹出就弹出。到最后判断栈是否为空即可 + +解法: + +```c++ +class Solution { +public: + int stack[1010]; + bool validateStackSequences(vector& pushed, vector& popped) { + int n = 0, j = 0; + for (int i = 0;i < pushed.size();i++) { + stack[n++] = pushed[i]; + while (n > 0 && stack[n - 1] == popped[j]) { + n--; + j++; + } + } + if (n == 0) { + return true; + } else { + return false; + } + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0947._Most_Stones_Removed_with_Same_Row_or_Column.md b/docs/Algorithm/Leetcode/C++/0947._Most_Stones_Removed_with_Same_Row_or_Column.md new file mode 100755 index 00000000..c4f3d7d0 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0947._Most_Stones_Removed_with_Same_Row_or_Column.md @@ -0,0 +1,52 @@ +### 947. Most Stones Removed with Same Row or Column + +题目: +https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/ + +难度: +Medium + +题意: + +1. 给平面上n个点 +2. 每次操作都可以挑选其中x坐标相等或者y坐标相等的两个点,划掉一个 +3. 求最多能划掉多少个 + +思路: + +- 我们平面上的点想象成图论上的一个几点,如果两个点之间,x坐标相等或者y坐标相等,那么连边 +- 题目就可以转为,求这个图的联通分量,因为只要两个团不联通,是无论如何无法进行操作的,所以剩下的个数必是联通分量的个数 +- 剩下就是dfs即可 + +解法: + +```c++ +class Solution { +public: + bool flag[1010]; + void dfs(vector>& stones, int idx) { + for (int i = 0;i < stones.size();i++) { + if (flag[i]) { + continue; + } + if (stones[idx][0] != stones[i][0] && stones[idx][1] != stones[i][1]) { + continue; + } + flag[i] = true; + dfs(stones, i); + } + } + int removeStones(vector>& stones) { + memset(flag, false, sizeof(flag)); + int ret = 0; + for (int i = 0;i < stones.size();i++) { + if (!flag[i]) { + ret++; + dfs(stones, i); + } + } + return stones.size() - ret; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0948._Bag_of_Tokens.md b/docs/Algorithm/Leetcode/C++/0948._Bag_of_Tokens.md new file mode 100755 index 00000000..7ea0f686 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0948._Bag_of_Tokens.md @@ -0,0 +1,72 @@ +### 948. Bag of Tokens + +题目: +https://leetcode.com/problems/bag-of-tokens/ + +难度: +Medium + +题意: + +1. 玩个游戏,有n个游戏币,游戏币有权值,初始能量为P +2. 每个游戏币只能被选择一次,每次只能在两种操作中选择其中一个操作 + 1. 如果当前能量大于或等于该游戏币的权值,那么可以将能量减掉该游戏币的权值,分数+1 + 2. 如果当前分数大于或等于1,那么可以将分数-1,将能量加上该游戏币的权值 +3. 问最多能得到多少分 + +思路: + +- 假设只有第一种操作,那么这个题就是个贪心题,排序,从小到大选择游戏币,直到能量用完 +- 第二种操作,相当于找一个权重小于或等于P的游戏币(命名为游戏币B),跟另一个游戏币(命名为游戏币A)同时去掉,然后能量加上游戏币A的能量 +- 游戏币A很容易想,肯定选择权重最大的那个,那游戏币B要挑哪个呢? +- 答案是任意挑,因为对结果无影响。大家可以想一想,贪心算法相当于要求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)是被消去的 +- 所以解法就是,枚举所有的操作,每次操作把最小的置换最大的,剩下的就是求解贪心问题A[0]+A[1]+...A[k]<=P + +解法: + +```c++ +class Solution { +public: + int sum[10010]; + int getSum(int idx) { + if (idx < 0) { + return 0; + } else { + return sum[idx]; + } + } + int bagOfTokensScore(vector& tokens, int P) { + if (tokens.size() == 0) { + return 0; + } + + sort(tokens.begin(), tokens.end()); + sum[0] = tokens[0]; + for (int i = 1;i < tokens.size();i++) { + sum[i] = sum[i - 1] + tokens[i]; + } + + int left = 0, right = tokens.size() - 1; + + int ret = 0; + int res = 0; + while (left <= right) { + while (res <= right && getSum(res) - getSum(left - 1) <= P) { + res++; + } + ret = ret > res - left ? ret : res - left; + + if (left == right) { + break; + } + if (P >= tokens[left]) { + P += tokens[right--] - tokens[left++]; + } else { + break; + } + } + return ret; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0949._Largest_Time_for_Given_Digits.md b/docs/Algorithm/Leetcode/C++/0949._Largest_Time_for_Given_Digits.md new file mode 100755 index 00000000..3c856994 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0949._Largest_Time_for_Given_Digits.md @@ -0,0 +1,49 @@ +### 949. Largest Time for Given Digits + + 题目: +https://leetcode.com/problems/largest-time-for-given-digits/ + +难度: +Easy + +题意: + +1. 给4个0-9的数字 +2. 求能组成最大的时间,时间格式是hh:mm + +思路: + +- 枚举所有的hh:mm的格式 +- 判断是否符合时间的要求,hh<24,mm<60 +- 寻找最大的时间 + +解法: + +```c++ +class Solution { +public: + string largestTimeFromDigits(vector& A) { + string ret = ""; + for (int i = 0;i < 4;i++) { + for (int j = 0;j < 4;j++) { + if (i == j) continue; + if (A[i] * 10 + A[j] >= 24) continue; + for (int k = 0;k < 4;k++) { + if (i == k || j == k) continue; + for (int l = 0;l < 4;l++) { + if (i == l || j == l || k == l) continue; + string s = ""; + if (A[k] * 10 + A[l] >= 60) continue; + s = string("") + char(A[i] + '0') + char(A[j] + '0') + ":" + char(A[k] + '0') + char(A[l] + '0'); + if (ret < s) { + ret = s; + } + } + } + } + } + return ret; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0950._Reveal_Cards_In_Increasing_Order.md b/docs/Algorithm/Leetcode/C++/0950._Reveal_Cards_In_Increasing_Order.md new file mode 100755 index 00000000..894a6623 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0950._Reveal_Cards_In_Increasing_Order.md @@ -0,0 +1,72 @@ +### 950. Reveal Cards In Increasing Order + +题目: +https://leetcode.com/problems/reveal-cards-in-increasing-order/ + +难度: +Medium + +题意: + +1. 有这么个操作 +2. 将牌的第一张拿出来,把下一张放到底部 +3. 重复这种操作 +4. 到最后拿出来的是一个严格递增数列 +5. 求牌开始的顺序 + +思路: + +- 反过来操作即可 +- 对牌排个序,备选 +- 把底部的牌放到第一张,从备选的牌中选择最大的一张放在顶部 +- 重复这种操作 + +解法: + +```c++ +class Solution { +public: + int list[10000]; + int front, back; + + void add(int val) { + list[front++] = val; + if (front == 10000) { + front = 0; + } + } + + int remove() { + int ret = list[back]; + back++; + if (back == 10000) { + back = 0; + } + return ret; + } + + vector deckRevealedIncreasing(vector& deck) { + front = back = 0; + sort(deck.begin(), deck.end()); + add(deck[deck.size() - 1]); + for (int i = deck.size() - 2;i >= 0;i--) { + int x = remove(); + add(x); + x = deck[i]; + add(x); + } + vector ret; + int i = back; + while (i != front) { + ret.push_back(list[i]); + i++; + if (i == 10000) { + i = 0; + } + } + reverse(ret.begin(), ret.end()); + return ret; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0951._Flip_Equivalent_Binary_Trees.md b/docs/Algorithm/Leetcode/C++/0951._Flip_Equivalent_Binary_Trees.md new file mode 100755 index 00000000..1b1a8600 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0951._Flip_Equivalent_Binary_Trees.md @@ -0,0 +1,58 @@ +### 951. Flip Equivalent Binary Trees + +题目: +https://leetcode.com/problems/flip-equivalent-binary-trees/ + +难度: +Medium + +题意: + +1. 给两棵树 +2. 两棵树可以做交换左右子树的操作 +3. 求两棵树是否能通过某些操作,使得两棵树一模一样 + +思路: + +- 递归判断 + - 两个都为空,返回true + - 一个为空,返回false + - 根的值不同,返回false + - 递归判断左子树和右子树,判断左右两棵对应的子树是否为true,或者交换下子树,判断是否为true,返回true + - 其他情况返回false + +解法: + +```c++ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + bool flipEquiv(TreeNode* root1, TreeNode* root2) { + if (!root1 && !root2) { + return true; + } + if (!root1 || !root2) { + return false; + } + if (root1->val != root2->val) { + return false; + } + if (flipEquiv(root1->left, root2->left) && flipEquiv(root1->right, root2->right)) { + return true; + } + if (flipEquiv(root1->left, root2->right) && flipEquiv(root1->right, root2->left)) { + return true; + } + return false; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/0952._Largest_Component_Size_by_Common_Factor.md b/docs/Algorithm/Leetcode/C++/0952._Largest_Component_Size_by_Common_Factor.md new file mode 100755 index 00000000..97aafcf0 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/0952._Largest_Component_Size_by_Common_Factor.md @@ -0,0 +1,125 @@ +### 952. Largest Component Size by Common Factor + +题目: +https://leetcode.com/problems/largest-component-size-by-common-factor/ + +难度: +Hard + +题意: + +1. 给n个数 +2. 将n个数设定为n个节点,如果两个数之间的最大公约数大于1,则连边 +3. 求图的最大联通分量的大小 + +思路: + +- n的数据量高达2w,如果两两节点计算最大公约数,复杂度是o(n^2logn) +- 我们可以使用素数筛法来取出需要两两画线的数列,比如:取出被2整除的数,被3整除的数。。。 +- 求图的最大联通分量可以用并查集来做 +- 过程是这样的 + - 枚举所有的素数 + - 假设当前枚举的素数是i + - 从n个数中取出所有能被i整除的数 + - 假设有m个数,那么第1个数跟第m-1个数都跟第0个数做下合并 + - 枚举结束后,求最大的集合的大小 +- 素数筛法的复杂度是o(nlogn),这里需要做下优化,如果枚举每个素数都得从n个数寻找能被它整除的数,复杂度还是o(nk),k是素数的个数,但如果我们把n个数映射到1-100000的数组中,就可以套用素数筛法了 + +解法: + +```c++ +bool isPrime[100100]; +bool hasValue[100100]; +int p[100100]; +int size[100100]; +class Solution { +public: + bool inited = false; + + void init() { + memset(isPrime, true, sizeof(isPrime)); + for (int i = 2;i <= 100000;i++) { + if (!isPrime[i]) { + continue; + } + for (int j = i + i;j <= 100000;j += i) { + isPrime[j] = false; + } + } + } + + int find_set(int x) { + vector temp; + while (p[x] != x) { + temp.push_back(x); + x = p[x]; + } + for (int i = 0;i < temp.size();i++) { + p[temp[i]] = x; + } + return x; + } + + void union_set(int x, int y) { + x = find_set(x); + y = find_set(y); + if (x == y) { + return; + } + p[x] = y; + size[y] += size[x]; + } + + vector find(int prime) { + vector ret; + for (int i = prime;i <= 100000;i += prime) { + if (hasValue[i]) { + ret.push_back(i); + } + } + return ret; + } + + int largestComponentSize(vector& A) { + if (!inited) { + init(); + inited = true; + } + + memset(hasValue, false, sizeof(hasValue)); + for (int i = 0;i < A.size();i++) { + hasValue[A[i]] = true; + } + for (int i = 0;i <= 100000;i++) { + p[i] = i; + size[i] = 1; + } + for (int i = 2;i <= 100000;i++) { + if(isPrime[i]) { + vector temp = find(i); + + if (temp.size() == 0){ + continue; + } + + for (int j = 1;j < temp.size();j++) { + union_set(temp[0], temp[j]); + } + } + } + + int ret = 0; + for (int i = 0;i <= 100000;i++) { + if (!hasValue[i]) { + continue; + } + int x = find_set(i); + if (size[x] > ret) { + ret = size[x]; + } + } + return ret; + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/C++/README.md b/docs/Algorithm/Leetcode/C++/README.md new file mode 100755 index 00000000..fb996b73 --- /dev/null +++ b/docs/Algorithm/Leetcode/C++/README.md @@ -0,0 +1 @@ +# Leetcode solutions and summary! diff --git a/docs/Algorithm/Leetcode/Java/0001._Two_Sum.md b/docs/Algorithm/Leetcode/Java/0001._Two_Sum.md new file mode 100755 index 00000000..9292a32f --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0001._Two_Sum.md @@ -0,0 +1,48 @@ +# 1. Two Sum + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum + +> 内容描述 + +``` +Given an array of integers, return indices of the two numbers such that they add up to a specific target. + +You may assume that each input would have exactly one solution, and you may not use the same element twice. + +Example: + +Given nums = [2, 7, 11, 15], target = 9, + +Because nums[0] + nums[1] = 2 + 7 = 9, +return [0, 1]. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +```java +class Solution { + public int[] twoSum(int[] nums, int target) { + Map lookup = new HashMap<>(); + int[] res = new int[2]; + for (int i = 0; i < nums.length; i++) { + if (lookup.containsKey(target - nums[i])) { + res = new int[] { lookup.get(target - nums[i]), i }; + break; + } else { + lookup.put(nums[i], i); + } + } + return res; + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0002._add_two_numbers.md b/docs/Algorithm/Leetcode/Java/0002._add_two_numbers.md new file mode 100755 index 00000000..92fbd35e --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0002._add_two_numbers.md @@ -0,0 +1,90 @@ +# 2. Add Two Numbers + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/add-two-numbers/description/ + +> 内容描述 + +``` +You 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. + +You may assume the two numbers do not contain any leading zero, except the number 0 itself. + +Example: + +Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) +Output: 7 -> 0 -> 8 +Explanation: 342 + 465 = 807. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +迭代,每次只算个位数的相加 + +```java +class Solution { + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + + ListNode head = new ListNode(0); + ListNode p = head; + + int tmp = 0; + while(l1 != null || l2 != null || tmp != 0) { + if(l1 != null) { + tmp += l1.val; + l1 = l1.next; + } + if(l2 != null) { + tmp += l2.val; + l2 = l2.next; + } + + p.next = new ListNode(tmp % 10); + p = p.next; + tmp = tmp / 10; + } + return head.next; + } +} +``` +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +可以使用递归,每次算一位的相加, beats 70.66% + + +```java +class Solution { + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + if (l1 == null && l2 == null) { + return null; + } else if (l1 == null || l2 == null) { + return l1 != null ? l1: l2; + } else { + ListNode l3; + if (l1.val + l2.val < 10) { + l3 = new ListNode(l1.val + l2.val); + l3.next = addTwoNumbers(l1.next, l2.next); + } else { + l3 = new ListNode(l1.val + l2.val - 10); + l3.next = addTwoNumbers(l1.next, addTwoNumbers(l2.next, new ListNode(1))); + } + return l3; + } + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0003._Longest_Substring_Without_Repeating_Characters.md b/docs/Algorithm/Leetcode/Java/0003._Longest_Substring_Without_Repeating_Characters.md new file mode 100755 index 00000000..b57a0d28 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0003._Longest_Substring_Without_Repeating_Characters.md @@ -0,0 +1,52 @@ +# 3. Longest Substring Without Repeating Characters + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ + +> 内容描述 + +``` +Given a string, find the length of the longest substring without repeating characters. + +Example 1: + +Input: "abcabcbb" +Output: 3 +Explanation: The answer is "abc", with the length of 3. +Example 2: + +Input: "bbbbb" +Output: 1 +Explanation: The answer is "b", with the length of 1. +Example 3: + +Input: "pwwkew" +Output: 3 +Explanation: The answer is "wke", with the length of 3. + Note that the answer must be a substring, "pwke" is a subsequence and not a substring. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +```java +class Solution { + public int lengthOfLongestSubstring(String s) { + int stIdx = 0, maxLen = 0; + int arr[] = new int[128]; + for(int i=0;i难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description + +> 内容描述 + +``` +There are two sorted arrays nums1 and nums2 of size m and n respectively. + +Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)). + +You may assume nums1 and nums2 cannot be both empty. + + +Example 1: + +nums1 = [1, 3] +nums2 = [2] + +The median is 2.0 + +Example 2: + +nums1 = [1, 2] +nums2 = [3, 4] + +The median is (2 + 3)/2 = 2.5 + +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(log(m + n))******- 空间复杂度: O(1)****** + +将问题转化为两个有序数组,找出其中的第K大的数, beats 99.80% + +```java +class Solution { +// 寻找两个有序数组的中位数 + // 问题转换为求第K大的数 + public double findMedianSortedArrays(int[] nums1, int[] nums2) { + if(nums1 == null || nums1.length == 0){ + // 求nums2的中位数 + return nums2.length % 2 == 0 ? (nums2[nums2.length / 2] + nums2[nums2.length / 2 - 1]) / 2.0 : nums2[nums2.length / 2]; + } + if(nums2 == null || nums2.length == 0){ + return nums1.length % 2 == 0 ? (nums1[nums1.length / 2] + nums1[nums1.length / 2 - 1]) / 2.0 : nums1[nums1.length / 2]; + } + int len = nums1.length + nums2.length; + 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); + } + // 找两个有序数组的topk小的数 + public int topK(int[] nums1,int[] nums2,int start1,int start2,int k){ + if(start1 >= nums1.length){ + return nums2[start2 + k - 1]; + } + if(start2 >= nums2.length){ + return nums1[start1 + k - 1]; + } + + if(k == 1){ + return Math.min(nums1[start1] , nums2[start2]); + } + + if(start1 + k / 2 > nums1.length){ // 肯定不会在nums2的前 k / 2 + return topK(nums1,nums2,start1,start2 + k / 2,k - k / 2); + }else if(start2 + k / 2 > nums2.length){ + return topK(nums1,nums2,start1 + k / 2,start2,k - k / 2); + } + + int mid1 = nums1[start1 + k / 2 - 1]; + int mid2 = nums2[start2 + k / 2 - 1]; + if(mid1 > mid2){ // 移除nums2的前k/2 + return topK(nums1,nums2,start1,start2 + k / 2,k - k / 2); + }else { + return topK(nums1,nums2,start1 + k / 2,start2,k - k/2); + } + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0005._Longest_Palindromic_Substring.md b/docs/Algorithm/Leetcode/Java/0005._Longest_Palindromic_Substring.md new file mode 100755 index 00000000..6ff2a688 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0005._Longest_Palindromic_Substring.md @@ -0,0 +1,78 @@ +# 5. Longest Palindromic Substring + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode-cn.com/problems/longest-palindromic-substring/description + +> 内容描述 + +``` +Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. + + +Example 1: + +Input: "babad" +Output: "bab" +Note: "aba" is also a valid answer. + + +Example 2: + +Input: "cbbd" +Output: "bb" + +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(n^2)******- 空间复杂度: O(n^2)****** + +使用动态规划的思路,用一个二维数组cache[i][j]记录i到j是否为回文串, beats 54.36% + +```java +class Solution { + // 采用动态规划 + // 如果 i == j ,则只有一个字母 肯定是回文串 + // 如果 char[i] == char[j] && j == i + 1 , 两个字母相等 肯定是回文串 + // 如果 char[i] == char[j] && j > i + 1 && cache[i+1][j-1]为true,则肯定是回文串 + public String longestPalindrome(String s) { + if(s == null || s.length() <2){ + return s; + } + boolean[][] cache = new boolean[s.length()][s.length()]; // 记录 i ~ j 是否是回文串 + char[] chars = s.toCharArray(); + int len = s.length(); + int start = 0; + int end = 0; + // 采用至底向上的动态规划,也可以采用递归方式 + for(int i = len - 1; i >= 0; i --){ + for(int j = i; j < len; j ++){ + if(i == j){ + cache[i][j] = true; + }else if(j == i + 1 && chars[i] == chars[j]){ + cache[i][j] = true; + if(end - start + 1 < 2){ + end = j; + start = i; + } + }else if(chars[i] == chars[j] && cache[i + 1][j-1]){ + cache[i][j] = true; + if(end - start < j-i){ + start = i; + end = j; + } + }else{ + cache[i][j] = false; + } + } + } + return s.substring(start,end+1); + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0006._ ZigZag_Conversion.md b/docs/Algorithm/Leetcode/Java/0006._ ZigZag_Conversion.md new file mode 100755 index 00000000..2de5e264 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0006._ ZigZag_Conversion.md @@ -0,0 +1,93 @@ +# 5. ZigZag Conversion + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode-cn.com/problems/zigzag-conversion/description + +> 内容描述 + +``` +The 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) + +P A H N +A P L S I I G +Y I R + +And then read line by line: "PAHNAPLSIIGYIR" + +Write the code that will take a string and make this conversion given a number of rows: + +string convert(string s, int numRows); + +Example 1: + +Input: s = "PAYPALISHIRING", numRows = 3 +Output: "PAHNAPLSIIGYIR" + + + +Example 2: + +Input: s = "PAYPALISHIRING", numRows = 4 +Output: "PINALSIGYAHRPI" +Explanation: + +P I N +A L S I G +Y A H R +P I + + +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(len(s))******- 空间复杂度: O(len(s))****** + +需要将字符串s转换为按N排列,总共有numRows行,直接将字符串转换为N字形,然后输出, beats 74.18% + +```java +class Solution { + // 将字符串进行z子排列,行数为numRows + public String convert(String s, int numRows) { + // 思路:先转换为z字 + List[] arr = new List[numRows]; // 保存每一行元素 + for(int i = 0; i < numRows; i ++){ + arr[i] = new ArrayList(); + } + char[] chars = s.toCharArray(); + for(int i = 0; i < chars.length;){ + // 每次打印两列 + for(int j = 0; j < numRows && i < chars.length; j++,i++){ + List list = arr[j]; + list.add(chars[i]); + } + for(int j = numRows - 1; j >= 0 && i < chars.length; j --){ + if(j == numRows - 1 || j == 0){ + arr[j].add(' '); + }else{ + arr[j].add(chars[i]); + i++; + } + } + } + // 输出最终字符串 + char[] result = new char[chars.length]; + int index = 0; + for(int i = 0; i < numRows; i ++){ + List list = arr[i]; + for(int j = 0; j < list.size(); j ++){ + if(' ' != (char)list.get(j)){ + result[index++] = (char) list.get(j); + } + } + } + return new String(result); + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0007._Reverse_Integer.md b/docs/Algorithm/Leetcode/Java/0007._Reverse_Integer.md new file mode 100755 index 00000000..c5b9235f --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0007._Reverse_Integer.md @@ -0,0 +1,57 @@ +# 5. Reverse Integer + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode-cn.com/problems/reverse-integer/description + +> 内容描述 + +``` +Given a 32-bit signed integer, reverse digits of an integer. + +Example 1: + +Input: 123 +Output: 321 + +Example 2: + +Input: -123 +Output: -321 + +Example 3: + +Input: 120 +Output: 21 + + +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(n)******- 空间复杂度: O(1)****** + +将整数翻转,翻转后是否溢出了, beats 95.35% + +```java +class Solution { + public int reverse(int x) { + // 使用一个long型变量来保存 + long index = 0; + while (x != 0){ + index = index * 10 + x %10; + x = x / 10; + } + int result = (int) index; + if(result != index){ + return 0; + } + return (int)index; + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0023._Merge_K_Sorted_Lists.md b/docs/Algorithm/Leetcode/Java/0023._Merge_K_Sorted_Lists.md new file mode 100755 index 00000000..ee69f1b9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0023._Merge_K_Sorted_Lists.md @@ -0,0 +1,69 @@ +# 23. Merge K Sorted Lists + +**难度: Hard** + +## 刷题内容 + +> 原题链接 + +* https://leetcode.com/problems/merge-k-sorted-lists/description/ + +> 内容描述 + +``` +Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. + +Example: + + +Input: +[ +  1->4->5, +  1->3->4, +  2->6 +] +``` + +## 解题方案 + +> 思路 1 +*****- 时间复杂度:O(NlogK) *****- 空间复杂度:O(N)***** + +K为链表的数量,N为所有链表的节点的总个数 + +此题在于一分一合,将K个有序链表通过二分,拆成两两一组的链表,就变成了leetcode 21题中的合并两个有序链表了,随后将所有链表逐层合并,就像从二叉树的叶子节点开始,不断向上合并,此题就求解完毕了。 + +此题需要用到的技巧就是二分,以及递归合并两个有序链表(当然迭代合并两个有序列表也是可以的) + +Beats 100% + +```java +public ListNode mergeKLists(ListNode[] lists) { + if (lists == null || lists.length == 0) return null; + return sort(lists, 0, lists.length - 1); +} + +// 二分K个链表 +ListNode sort(ListNode[] lists, int lo, int hi) { + if (lo >= hi) return lists[lo]; + int mid = (hi -lo) / 2 + lo; + ListNode l1 = sort(lists, lo, mid); + ListNode l2 = sort(lists, mid + 1, hi); + return merge(l1, l2); +} + +// 合并两个有序链表的递归写法 +ListNode merge(ListNode l1, ListNode l2) { + if (l1 == null) return l2; + if (l2 == null) return l1; + + if (l1.val < l2.val) { + l1.next = merge(l1.next, l2); + return l1; + } + + l2.next = merge(l2.next, l1); + return l2; +} + +``` diff --git a/docs/Algorithm/Leetcode/Java/0141._linked_list_cycle.md b/docs/Algorithm/Leetcode/Java/0141._linked_list_cycle.md new file mode 100755 index 00000000..6762cf21 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0141._linked_list_cycle.md @@ -0,0 +1,51 @@ +# 141. Linked List Cycle + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/linked-list-cycle/description/ + +> 内容描述 + +``` +Given a linked list, determine if it has a cycle in it. + +Follow up: +Can you solve it without using extra space? +``` + +## 解题方案 + + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +快慢指针 + + + +```java +java +public class Solution { + public boolean hasCycle(ListNode head) { + if (head == null){ + return false; + } + ListNode fast = head; + ListNode slow = head; + while (fast != null && slow != null && fast.next != null){ + fast = fast.next.next; + slow = slow.next; + if (slow == fast){ + return true; + } + } + return false; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0218._The_Skyline_Problem.md b/docs/Algorithm/Leetcode/Java/0218._The_Skyline_Problem.md new file mode 100755 index 00000000..e3a07e06 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0218._The_Skyline_Problem.md @@ -0,0 +1,107 @@ +# 218. The Skyline Problem + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/the-skyline-problem/description/ + +> 内容描述 + +``` +A 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). +``` + +
+ + +
+ +``` +Buildings Skyline Contour +The 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. + +For 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] ] . + +The 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. + +For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]. + +Notes: + +The number of buildings in any input list is guaranteed to be in the range [0, 10000]. +The input list is already sorted in ascending order by the left x position Li. +The output list must be sorted by the x position. +There 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], ...] +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + +观察发现,skyline的points的横坐标一定是某个building的左边界或者右边界。 + +开始,假设只有2个建筑物,拿出第一个buiding B1,我们先把它的左上顶点加进我们的output结果skyline中,然后继续拿下一个building B2,我们现在需要将B2的左上顶点对应的x coordinate与B1的右上顶点所对应的x coordinate做比较: + +- 如果前者小且B2的高度大于B1的高度,则我们将B2的左上顶点也加入skyline中去。 +- 如果前者小且B2的高度小于等于B1的高度,则忽略B2的左上顶点 + +接下来考虑更多建筑物的情况,从左到右扫描,当我们遇到第一个楼的左边界时,把它push到一个heap中。如果后面扫描的楼的高度比heap中最高的楼还高,那么它的左上顶点一定会被加入到skyline中。当我们遇到一个building的右边界时,我们需要将其从heap中pop掉,如果heap中max height有变化,则push到结果中。 + +参考[Brian Gordon的blog](https://briangordon.github.io/2014/08/the-skyline-problem.html) +和 [Stefan大神的题解](https://leetcode.com/problems/the-skyline-problem/discuss/61194) + + + +```Java +public class Solution { + public List getSkyline(int[][] buildings) { + List result = new ArrayList(); + if (buildings == null || buildings.length == 0 || buildings[0].length == 0) { + return result; + } + + List heights = new ArrayList(); + for (int[] building : buildings) { + heights.add(new Height(building[0], -building[2])); + heights.add(new Height(building[1], building[2])); + } + Collections.sort(heights, new Comparator() { + @Override + public int compare(Height h1, Height h2) { + return h1.index != h2.index ? h1.index - h2.index : h1.height - h2.height; + } + }); + + PriorityQueue pq = new PriorityQueue(1000, Collections.reverseOrder()); + pq.offer(0); + int prev = 0; + for (Height h : heights) { + if (h.height < 0) { + pq.offer(-h.height); + } else { + pq.remove(h.height); + } + int cur = pq.peek(); + if (cur != prev) { + result.add(new int[]{h.index, cur}); + prev = cur; + } + } + + return result; + } + + class Height { + int index; + int height; + Height(int index, int height) { + this.index = index; + this.height = height; + } + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0238._product_of_array_except_self.md b/docs/Algorithm/Leetcode/Java/0238._product_of_array_except_self.md new file mode 100755 index 00000000..6b3ec01b --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0238._product_of_array_except_self.md @@ -0,0 +1,69 @@ +# 238. Product of Array Except Self + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum + +> 内容描述 + +``` +Given 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]. + +Example: + +Input: [1,2,3,4] +Output: [24,12,8,6] +Note: Please solve it without division and in O(n). + +Follow up: +Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.) +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +前缀积和后缀积, 懒得实现了 + + +# Follow up: +Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.) + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +还是一样的思想,只不过不记录下来,而是采用边循环边更新的方式 + +beats 100.00% + + +```java +class Solution { + public int[] productExceptSelf(int[] nums) { + int[] res = new int[nums.length]; + + for (int i = 0; i < nums.length; i++) { + res[i] = 1; + } + + int left = 1; + for (int i = 0; i < nums.length - 1; i++) { + left *= nums[i]; + res[i+1] *= left; + } + + int right = 1; + for (int i = nums.length - 1; i > 0; i--) { + right *= nums[i]; + res[i-1] *= right; + } + + return res; + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0342._Power_of_Four.md b/docs/Algorithm/Leetcode/Java/0342._Power_of_Four.md new file mode 100755 index 00000000..d7e073db --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0342._Power_of_Four.md @@ -0,0 +1,46 @@ +# 342. Power of Four + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/power-of-four/description/ + +> 内容描述 + +``` +Given an integer (signed 32 bits), write a function to check whether it is a power of 4. + +Example 1: + +Input: 16 +Output: true +Example 2: + +Input: 5 +Output: false +Follow up: Could you solve it without loops/recursion? +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(1)******- 空间复杂度: O(1)****** + +recursive + +```java +class Solution { + public boolean isPowerOfFour(int num) { + if (num <= 0) + return false; + if (num == 1) + return true; + if (num % 4 == 0) + return isPowerOfFour(num/4); + return false; + } +} +``` diff --git a/docs/Algorithm/Leetcode/Java/0403._Frog_Jump.md b/docs/Algorithm/Leetcode/Java/0403._Frog_Jump.md new file mode 100755 index 00000000..f4cc732b --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0403._Frog_Jump.md @@ -0,0 +1,119 @@ +# 403. Frog Jump + +**难度: hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/frog-jump/description/ + +> 内容描述 + +``` +A 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. + +Given 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. + +If 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. + +Note: + +The number of stones is ≥ 2 and is < 1,100. +Each stone's position will be a non-negative integer < 231. +The first stone's position is always 0. +Example 1: + +[0,1,3,5,6,8,12,17] + +There are a total of 8 stones. +The first stone at the 0th unit, second stone at the 1st unit, +third stone at the 3rd unit, and so on... +The last stone at the 17th unit. + +Return true. The frog can jump to the last stone by jumping +1 unit to the 2nd stone, then 2 units to the 3rd stone, then +2 units to the 4th stone, then 3 units to the 6th stone, +4 units to the 7th stone, and 5 units to the 8th stone. +Example 2: + +[0,1,2,3,4,8,9,11] + +Return false. There is no way to jump to the last stone as +the gap between the 5th and 6th stone is too large. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +* 关注点放在数据范围。 + +* 判断是否能够到达y点(因为问题就是到达最后一个点),需要两个条件: + + * 能够到达x点(xy,如果`|(z-y) - (y-x)|<=1`,那么`flag[y][z]=true` + +* 这里有个需要注意的优化点,可以固定y,枚举xy,这样对于每个y,只需要扫一遍点数组就可以成功执行转移 + +* 复杂度是o(n^2) + +代码: + +```java +class Solution { + public boolean canCross(int[] stones) { + int n = stones.length; + + if (stones[1] != 1) { + return false; + } + + boolean[][] flag = new boolean[n][n]; + for (int i = 0;i < n;i++) { + for (int j = 0;j < n;j++) { + flag[i][j] = false; + } + } + + flag[1][0] = true; + + for (int i = 1;i < n;i++) { + int left = i - 1; + int right = i + 1; + + while (left >= 0 && right < n) { + while (left >= 0 && !flag[i][left]) left--; + if (left >= 0) { + while (right < n && stones[right] - stones[i] <= stones[i] - stones[left] + 1) { + if (stones[right] - stones[i] == stones[i] - stones[left] - 1 + || stones[right] - stones[i] == stones[i] - stones[left] + || stones[right] - stones[i] == stones[i] - stones[left] + 1) { + flag[right][i] = true; + } + right++; + } + left--; + } + } + } + + for (int i = 0;i < n;i++) { + if (flag[n - 1][i]) { + return true; + } + } + return false; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0757._Set_Intersection_Size_At_Least_Two.md b/docs/Algorithm/Leetcode/Java/0757._Set_Intersection_Size_At_Least_Two.md new file mode 100755 index 00000000..b49ef161 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0757._Set_Intersection_Size_At_Least_Two.md @@ -0,0 +1,75 @@ +### 757. Set Intersection Size At Least Two + + + +题目: +https://leetcode.com/problems/set-intersection-size-at-least-two/ + +难度: +Hard + +题意: + +1. 给定n个区间 +2. 求一个最小集合,使得每个区间,集合中至少有两个数在区间里面 + +思路: + +- 这题是贪心题 +- 先对区间右端点排序。再从右端点小的开始贪心。每次先判断当前集合中是否有两个数在这个区间中,如果有,直接跳过,没有,从右端点开始往集合丢数,直到有两个数在这个区间中 +- 直观的解释就是,为了满足前面的区间的条件,而丢进集合的数一定是越大越好,这样跟后面的区间共用一个数的几率会更大 + +解法: + +```java +class Solution { + public int intersectionSizeTwo(int[][] intervals) { + Integer[] array = new Integer[intervals.length]; + for (int i = 0;i < array.length;i++) { + array[i] = i; + } + Arrays.sort(array, new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return Integer.compare(intervals[o1][1], intervals[o2][1]); + } + }); + List result = new ArrayList(); + int[] t = new int[2]; + for (int i = 0;i < array.length;i++) { + int n = 0; + if (result.size() > 0 && result.get(result.size() - 1) >= intervals[array[i]][0]) { + t[n++] = result.get(result.size() - 1); + } + if (result.size() > 1 && result.get(result.size() - 2) >= intervals[array[i]][0]) { + t[n++] = result.get(result.size() - 2); + } + int res = n; + int j = intervals[array[i]][1]; + while (n != 2) { + boolean found = false; + for (int k = 0;k < n;k++) { + if (t[k] == j) { + found = true; + break; + } + } + if (found) { + j--; + } else { + t[n++] = j--; + } + } + if (res == 0) { + result.add(t[1]); + result.add(t[0]); + } + if (res == 1) { + result.add(t[1]); + } + } + return result.size(); + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0768._Max_Chunks_To_Make_Sorted_II.md b/docs/Algorithm/Leetcode/Java/0768._Max_Chunks_To_Make_Sorted_II.md new file mode 100755 index 00000000..1e2be6df --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0768._Max_Chunks_To_Make_Sorted_II.md @@ -0,0 +1,45 @@ +### 768. Max Chunks To Make Sorted II + + + +题目: +https://leetcode.com/problems/max-chunks-to-make-sorted-ii/ + +难度: +Hard + +题意: + +1. 给定一个数组,求最多能够将数组分成多少段,使得每段排序之后连接起来,是一个有序数组 + +思路: + +- 显而易见,数据能否分的条件是,分出来的左边数组的最大值不大于比右边数组的最小值 +- 只需要扫描一下,先把最大值和最小值数组预处理出来,然后遍历就可以得出结果 + +解法: + +```java +class Solution { + public int maxChunksToSorted(int[] arr) { + int[] min = new int[arr.length]; + int[] max = new int[arr.length]; + max[0] = arr[0]; + for (int i = 1;i < arr.length;i++) { + max[i] = Math.max(arr[i], max[i - 1]); + } + min[arr.length - 1] = arr[arr.length - 1]; + for (int i = arr.length - 2;i >= 0;i--) { + min[i] = Math.min(arr[i], min[i + 1]); + } + int ret = 1; + for (int i = 0;i + 1 < arr.length;i++) { + if (max[i] <= min[i + 1]) { + ret++; + } + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0780._Reaching_Points.md b/docs/Algorithm/Leetcode/Java/0780._Reaching_Points.md new file mode 100755 index 00000000..91dc0a20 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0780._Reaching_Points.md @@ -0,0 +1,59 @@ +### 780. Reaching Points + +题目: +https://leetcode.com/problems/reaching-points/ + +难度: +Hard + +题意: + +1. 给定一个点对(x,y),每次操作可以变换成(x,x+y)或者(x+y,y) +2. 给定两个点对(sx, sy),和(tx, ty),问能否通过任意次操作,使前一个点对可以变换成后一个点对 + +思路: + +- 我们反正来,如果得到一个点对(x,y),最有可能是从哪些点对来的 +- 假设txtx,直接返回false,因为sx不管怎么变换,都不能比sx小 +- 如果sx=tx,判断(ty-sy)是否不小于0,并且可以被sx整除 +- 如果sx= sy && (ty - sy) % sx == 0) { + return true; + } else { + return false; + } + } + return solve(sx, sy, tx, ty % tx); + } else { + if (ty < sy) { + return false; + } + if (ty == sy) { + if (tx >= sx && (tx - sx) % sy == 0) { + return true; + } else { + return false; + } + } + return solve(sx, sy, tx % ty, ty); + } + } + + public boolean reachingPoints(int sx, int sy, int tx, int ty) { + return solve(sx, sy, tx, ty); + } + } \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md b/docs/Algorithm/Leetcode/Java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md new file mode 100755 index 00000000..b3b42dfd --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md @@ -0,0 +1,78 @@ +### 793. Preimage Size of Factorial Zeroes Function + + + +题目: +https://leetcode.com/problems/preimage-size-of-factorial-zeroes-function/ + +难度: +Hard + +题意: + +1. 求n!末尾有k个0的n有多少个 + +思路: + +- 因式分解,末尾有0肯定是2*5,不管n是多大,n!分解因式后,2的个数肯定比5的个数多 +- 假设给定n,如何求n!分解因式后有多少个5?每隔5个数贡献一个5因子,每隔25个数有多贡献一个5因子。。。统计能得到结果 +- 这个题的做法是二分一个范围区间,求出n!分解因式后因子5的个数等于k的上下界,相减所得 +- 这个题有个可优化的点,答案要么是0,要么是5,因为每隔5个数肯定会贡献一个5因子。那么我们只需要一个二分,找出是否有一个n,分解因式后有k个5因子,就可以返回5,否则返回0 + +解法: + +```java +class Solution { + private long cal5(long n) { + long ret = 0; + while (n != 0) { + ret += n / 5; + n /= 5; + } + return ret; + } + + private long upper(long left, long right, int k) { + while (right - left > 1) { + long mid = (left + right) / 2; + if (cal5(mid) <= k) { + left = mid; + } else { + right = mid; + } + } + if (cal5(left) == k) { + return left; + } else { + return -1; + } + } + + private long lower(long left, long right, int k) { + while (right - left > 1) { + long mid = (left + right) / 2; + if (cal5(mid) >= k) { + right = mid; + } else { + left = mid; + } + } + if (cal5(right) == k) { + return right; + } else { + return -1; + } + } + + public int preimageSizeFZF(int K) { + long n = upper(1, 6000000000L, K); + if (n == -1) { + return 0; + } else { + long m = lower(-1, n, K); + return (int) (n - m + 1); + } + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0827._Making_A_Large_Island.md b/docs/Algorithm/Leetcode/Java/0827._Making_A_Large_Island.md new file mode 100755 index 00000000..e9b07268 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0827._Making_A_Large_Island.md @@ -0,0 +1,128 @@ +### 827. Making A Large Island + + + +题目: +https://leetcode.com/problems/making-a-large-island/ + +难度: +Hard + +题意: + +1. 给定一张矩阵图 +2. 如果两个点相邻且都为1,这两个点连通 +3. 至多把一个0改为1,问最大的连通岛的面积是多大 + +思路: + +- 看数据结构,横竖最大是50,整个图最多才2500个点,直接枚举所有的0,改成1之后做dfs判断连通图,都可以解决 +- 两个连通岛其实是两个集合,如果将一个0改成1,意味着把上下左右所在的岛都合并在一个集合中,我们需要一个数据结构,既可以将集合合并,又可以判断某两个元素是否在同一个集合中,这种数据结构就是并查集 + +解法: + +```java +class Solution { + private class Set { + + int[] s; + int[] num; + int r; + int c; + + private Set(int r, int c) { + this.r = r; + this.c = c; + this.s = new int[r * c]; + this.num = new int[r * c]; + for (int i = 0;i < this.s.length;i++) { + this.s[i] = i; + this.num[i] = 1; + } + } + + private int calIdx(int x, int y) { + return x * c + y; + } + + private int find(int idx) { + if (this.s[idx] == idx) { + return idx; + } else { + return this.s[idx] = find(this.s[idx]); + } + } + + private void merge(int x1, int y1, int x2, int y2) { + int p1 = find(calIdx(x1, y1)); + int p2 = find(calIdx(x2, y2)); + if (p1 != p2) { + this.s[p1] = p2; + this.num[p2] += this.num[p1]; + } + } + + } + + public int largestIsland(int[][] grid) { + int[] dx = new int[]{0,0,1,-1}; + int[] dy = new int[]{1,-1,0,0}; + Set set = new Set(grid.length, grid[0].length); + for (int i = 0;i < grid.length;i++) { + for (int j = 0;j < grid[0].length;j++) { + if (grid[i][j] == 0) { + continue; + } + for (int k = 0;k < 4;k++) { + if (i + dx[k] < 0 || i + dx[k] >= grid.length) { + continue; + } + if (j + dy[k] < 0 || j + dy[k] >= grid[0].length) { + continue; + } + if (grid[i + dx[k]][j + dy[k]] == 0) { + continue; + } + set.merge(i, j, i + dx[k], j + dy[k]); + } + } + } + + int max = 0; + for (int i = 0;i < grid.length;i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1) { + continue; + } + + HashSet t = new HashSet<>(); + for (int k = 0;k < 4;k++) { + if (i + dx[k] < 0 || i + dx[k] >= grid.length) { + continue; + } + if (j + dy[k] < 0 || j + dy[k] >= grid[0].length) { + continue; + } + if (grid[i + dx[k]][j + dy[k]] == 0) { + continue; + } + + t.add(set.find(set.calIdx(i + dx[k], j + dy[k]))); + } + + int ret = 0; + for (Integer p: t) { + ret += set.num[p]; + } + ret ++; + max = Math.max(ret, max); + } + } + if (max == 0) { + max = grid.length * grid[0].length; + } + return max; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0828._Unique_Letter_String.md b/docs/Algorithm/Leetcode/Java/0828._Unique_Letter_String.md new file mode 100755 index 00000000..046cedb0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0828._Unique_Letter_String.md @@ -0,0 +1,169 @@ +### 828. Unique Letter String + + + +题目: +https://leetcode.com/problems/unique-letter-string + +难度: +Hard + +题意: + +1. 求一个字符串中的所有非空子字符串,这些字符串当中的唯一字符数的总和 +2. 唯一字符数就是在字符串中出现只有一次的字符的个数 + +思路: + +- 枚举左右端点,暴力统计子字符串的唯一字符数,复杂度是o(n^3) +- 枚举左端点,然后遍历右端点,每次保存上一次的字符统计个数,和唯一字符数,并更新为当前的数值,复杂度是o(n^2) +- 注意到,当某个字符出现次数大于1个后,后面不管怎么遍历,该字符都不会是唯一字符,因此,有个剪枝动作,如果此时某个字符出现次数大于1个后,后面直接跳过该字符 +- 因此我们需要实现把每个字符出现的位置记录下来,以便可以跳过某些字符 +- 枚举左端点,然后遍历右端点,加上剪枝之后,每个字符至多被扫描2次。把字符串拆成26个字符后,从左边遍历到右边,就需要一个堆来维持,类似于归并排序的merge操作,这个堆最多26个元素,时间复杂度是o(52nlog26) +- 我们可以另外想一种解决方案。假设我们把26个字母全部拆开,当某个字符第一次出现到第二次出现中间,它就能贡献一个唯一字符。假设A这个字符,第一次出现是位置1,第二次出现是位置10,于是1-10中间就可以增加一个唯一字符,同理,其他字符也是这样的。假设左端点移动,所需要改变的,也只有一个字符而已,这个字符的第一次出现的位置,到第二次出现的位置,改变了位置。我们不要想着每个字符串有多少唯一字符,而是从总体来看,每个字符贡献了多少次唯一字符。还是上面那个例子,A这个字符,第一次出现是位置1,第二次出现是位置10,那么贡献了10-1=9次唯一字符。扫描左端点时,只需要不断用上一个左端点字符移动来更新总唯一字符数即可。复杂度是o(n) + +解法一: + +```java +class Solution { + private class Item implements Comparable { + int alph; + int idx; + int pos; + + public Item(int alph, int idx, int pos) { + this.alph = alph; + this.idx = idx; + this.pos = pos; + } + + @Override + public int compareTo(Item o) { + return Integer.compare(pos, o.pos); + } + } + + private int solve(List[] idxList, int start, int len, int[] init) { + PriorityQueue queue = new PriorityQueue(); + boolean[] flag = new boolean[26]; + for (int i = 0;i < 26;i++) { + flag[i] = false; + } + int ret = 0; + int res = 0; + int pre = start - 1; + + for (int i = 0;i < 26;i++) { + int idx = init[i]; + if (idx != idxList[i].size()) { + queue.add(new Item(i, idx, (Integer) idxList[i].get(idx))); + } + } + + while (!queue.isEmpty()) { + Item top = queue.poll(); + ret += (long) res * (top.pos - pre) % MOD; + if (ret >= MOD) { + ret -= MOD; + } + if (flag[top.alph]) { + res--; + } else { + flag[top.alph] = true; + if (top.idx + 1 != idxList[top.alph].size()) { + queue.add(new Item(top.alph, top.idx + 1, (Integer) idxList[top.alph].get(top.idx + 1))); + } + res++; + } + pre = top.pos; + } + + ret += (long) res * (len - pre) % MOD; + if (ret >= MOD) { + ret -= MOD; + } + return ret; + } + + private static int MOD = 1000000007; + + public int uniqueLetterString(String S) { + List[] idxList = new List[26]; + int[] init = new int[26]; + for (int i = 0;i < 26;i++) { + idxList[i] = new ArrayList(); + init[i] = 0; + } + for (int i = 0;i < S.length();i++) { + idxList[S.charAt(i) - 'A'].add(i); + } + + int ret = 0; + for (int i = 0;i < S.length();i++) { + ret += solve(idxList, i, S.length(), init); + if (ret >= MOD) { + ret -= MOD; + } + init[S.charAt(i) - 'A']++; + } + + return ret; + } +} +``` + +解法二: + +```java +class Solution { + private static int MOD = 1000000007; + + public int uniqueLetterString(String S) { + List[] idxList = new List[26]; + int[] pos = new int[26]; + for (int i = 0;i < 26;i++) { + idxList[i] = new ArrayList(); + pos[i] = 0; + } + for (int i = 0;i < S.length();i++) { + idxList[S.charAt(i) - 'A'].add(i); + } + + int ret = 0; + int res = 0; + for (int i = 0;i < 26;i++) { + if (pos[i] < idxList[i].size()) { + if (pos[i] + 1 < idxList[i].size()) { + res += idxList[i].get(pos[i] + 1) - idxList[i].get(pos[i]); + } else { + res += S.length() - idxList[i].get(pos[i]); + } + } + } + + for (int i = 0;i < S.length();i++) { + ret += res; + if (ret >= MOD) { + ret -= MOD; + } + int j = S.charAt(i) - 'A'; + if (pos[j] + 1 < idxList[j].size()) { + res -= idxList[j].get(pos[j] + 1) - idxList[j].get(pos[j]); + } else { + res -= S.length() - idxList[j].get(pos[j]); + } + pos[j]++; + if (pos[j] < idxList[j].size()) { + if (pos[j] + 1 < idxList[j].size()) { + res += idxList[j].get(pos[j] + 1) - idxList[j].get(pos[j]); + } else { + res += S.length() - idxList[j].get(pos[j]); + } + } + } + + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0834._Sum_of_Distances_in_Tree.md b/docs/Algorithm/Leetcode/Java/0834._Sum_of_Distances_in_Tree.md new file mode 100755 index 00000000..0e4f499f --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0834._Sum_of_Distances_in_Tree.md @@ -0,0 +1,144 @@ +### 834. Sum of Distances in Tree + + + +题目: +https://leetcode.com/problems/sum-of-distances-in-tree/ + +难度: +Hard + +题意: + +1. 给定一棵树 +2. 问每个节点到其他节点的距离之和是多少 +3. N <= 10000 + +思路: + +- 最简单的方法,假设我们要求节点0与其他节点的距离之和,只需要一遍dfs即可,其他节点同理。复杂度是o(n^2) + +- 注意到,树中每个边都是一个桥(就是去掉这个边图就变成非连通了),树中的任意两个节点都是一个固定的路径。当我们计算不同节点的dfs,其实是有一部分路径是重复计算的(自己拿笔画一下) + +- 来看看分析的思路。从问题出发,要问每个节点到其他节点的距离和,想象这个点A是树根(每个点都可以是树根),那么我们遍历一下所有连接这个节点的边。想象一下某个边e连接的是一个子树,点A跟这个子树所有的点都得经过边e,因此我们把问题下推,计算这个子树的树根与其他节点的距离之和,然后加上这个子树的数量就等于点A跟这个子树所有的点的距离和 + +- 有个点需要注意的,由于边是无向的,我们动态规划的方向也需要两个方向,怎么理解呢。比如说,假设A和B连着。以A为树根计算子问题的时候,顺序是A->B,以B为树根计算子问题的时候,顺序是B->A,相当于对边进行动态规划,规划两个方向 + +- 解法知道了,就需要编码。注意到,N <= 10000,如果递归的话,小心stack over flow。需要自己模拟栈 + + +代码: + +```java +class Solution { + private class Edge { + private int x; + private int y; + private int num; + private int dist; + + public Edge(int x, int y, int num, int dist) { + this.x = x; + this.y = y; + this.num = num; + this.dist = dist; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } + + public int getNum() { + return num; + } + + public void setNum(int num) { + this.num = num; + } + + public int getDist() { + return dist; + } + + public void setDist(int dist) { + this.dist = dist; + } + } + + private void solve(Edge edge, List[] edgeList) { + if (edge.num != -1) { + return; + } + + LinkedList queue = new LinkedList(); + Stack stack = new Stack(); + + queue.addLast(edge); + stack.add(edge); + + while (!queue.isEmpty()) { + Edge e = queue.pollFirst(); + for (Edge next: (List) edgeList[e.y]) { + if (next.y == e.x) { + continue; + } + if (next.num != -1) { + continue; + } + queue.addLast(next); + stack.add(next); + } + } + + while (!stack.empty()) { + Edge e = stack.pop(); + e.num = e.dist = 0; + for (Edge next: (List) edgeList[e.y]) { + if (next.y == e.x) { + continue; + } + e.num += next.num; + e.dist += next.num + next.dist; + } + e.num ++; + } + } + + public int[] sumOfDistancesInTree(int N, int[][] edges) { + List[] edgeList = new List[N]; + for (int i = 0;i < edgeList.length;i++) { + edgeList[i] = new ArrayList(); + } + + for (int i = 0;i < edges.length;i++) { + edgeList[edges[i][0]].add(new Edge(edges[i][0], edges[i][1], -1, -1)); + edgeList[edges[i][1]].add(new Edge(edges[i][1], edges[i][0], -1, -1)); + } + + int[] result = new int[N]; + for (int i = 0;i < N;i++) { + result[i] = 0; + for (Edge next: (List) edgeList[i]) { + if (next.dist == -1) { + solve(next, edgeList); + } + result[i] += next.dist + next.num; + } + } + return result; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0843._Guess_the_Word.md b/docs/Algorithm/Leetcode/Java/0843._Guess_the_Word.md new file mode 100755 index 00000000..8833e181 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0843._Guess_the_Word.md @@ -0,0 +1,94 @@ +### 843. Guess the Word + + + +题目: +https://leetcode.com/problems/guess-the-word/ + +难度: +Hard + +题意: + +1. 给定最多100个长度为6的字符串 +2. 有一个字符串为秘密字符串,需要从这些字符串中猜出秘密字符串是哪个 +3. 每一轮猜会给出你猜的跟秘密字符串的不同字符数 +4. 最多猜10轮 + +思路: + +- 这个题就纯模拟,挑一个字符串,然后根据返回的数,来决定下一轮的备选字符串 +- 加快速度的话,可以枚举所有的字符串,判断这个字符串跟其他字符串的字符差的统计值,取统计值差异最大的字符串来作为这一轮的猜测 +- 类似决策树 + +代码: + +```java +class Solution { + private int calDiff(String word1, String word2) { + int ret = 0; + for (int i = 0;i < word1.length();i++) { + if (word1.charAt(i) == word2.charAt(i)) { + ret++; + } + } + return ret; + } + + private int select(int idx, List pre, int[][] cache) { + int[] dist = new int[7]; + Arrays.fill(dist, 0); + for (int x: pre) { + dist[cache[idx][x]] ++; + } + int ret = 0; + for (int i = 0;i < 6;i++) { + ret = Math.max(ret, dist[i]); + } + return ret; + } + + private int select(List pre, int[][] cache) { + int value = 1000000; + int ret = -1; + for (int idx: pre) { + int tmp = select(idx, pre, cache); + if (tmp < value) { + value = tmp; + ret = idx; + } + } + return ret; + } + + public void findSecretWord(String[] wordlist, Master master) { + int[][] cache = new int[wordlist.length][wordlist.length]; + for (int i = 0;i < wordlist.length;i++) { + for (int j = 0;j < wordlist.length;j++) { + cache[i][j] = calDiff(wordlist[i], wordlist[j]); + } + } + + List pre = new ArrayList(); + for (int i = 0;i < wordlist.length;i++) { + pre.add(i); + } + while (pre.size() != 0) { + int first = select(pre, cache); + + int diff = master.guess(wordlist[first]); + if (diff == 6) { + return; + } + List post = new ArrayList(); + for (int x: pre) { + if (cache[first][x] == diff) { + post.add(x); + } + } + pre = post; + } + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0847._Shortest_Path_Visiting_All_Nodes.md b/docs/Algorithm/Leetcode/Java/0847._Shortest_Path_Visiting_All_Nodes.md new file mode 100755 index 00000000..181c5508 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0847._Shortest_Path_Visiting_All_Nodes.md @@ -0,0 +1,85 @@ +### 847. Shortest Path Visiting All Nodes + + + +题目: +https://leetcode.com/problems/shortest-path-visiting-all-nodes/ + +难度: +Hard + +题意: + +1. 给定一个图,问走遍所有的点的最短距离是多少 + +思路: + +- 这个题首先考虑一下dfs的做法。假设我们已经到达了m个点,下个点,我们需要枚举所有下个点没有被访问的点,进行访问遍历,直到所有的点都被访问到 +- 我们注意到,枚举的过程中,需要枚举所有下个点没有被访问的点,而这个跟先前访问的顺序无关,也就是状态是一个访问集合,和当前到达的点共同组合而成的 +- 我们注意到,枚举的过程中,状态是需要重复访问,因此我们利用记忆化搜索,保存中间结果,进行动态规划 +- 这里需要注意的,我们可以预先把图形中两两最短距离先求出来缓存起来,这一部分只需要o(n^3)的复杂度 +- 子问题是:f(set, last),set是访问集合,last是当前到达的点,函数值是达到当前状态最短距离 +- 这里有个代码的实现方式,集合如何用实现?当然如果想实现一个具备集合特性的数据结构也是可以的,最简单的方式就是用bitset,也就是把集合的信息压缩在一个二进制串中,这个题的数据范围是n<=12,因此一个int就可以表达状态,状态总量是`2^n*n`,因此这个动态规划的时间复杂度是`o(2^n*n^2)` + +代码: + +```java +class Solution { + private int solve(int set, int last, int[][] dist, int[][] cache) { + if (cache[set][last] != -1) { + return cache[set][last]; + } + + if (set == (1 << dist.length) - 1) { + return cache[set][last] = 0; + } + + int ret = 0x3fffffff; + for (int i = 0;i < dist.length;i++) { + if ((set & (1 << i)) == 0) { + ret = Math.min(ret, dist[last][i] + solve(set + (1 << i), i, dist, cache)); + } + } + return cache[set][last] = ret; + } + + private int[][] calDist(int[][] graph) { + int[][] dist = new int[graph.length][graph.length]; + for (int i = 0;i < graph.length;i++) { + for (int j = 0;j < graph.length;j++) { + dist[i][j] = 0x3fffffff; + } + } + for (int i = 0;i < graph.length;i++) { + dist[i][i] = 0; + for (int j = 0;j < graph[i].length;j++) { + dist[i][graph[i][j]] = 1; + } + } + for (int k = 0;k < graph.length;k++) { + for (int i = 0;i < graph.length;i++) { + for (int j = 0;j < graph.length;j++) { + dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]); + } + } + } + return dist; + } + + public int shortestPathLength(int[][] graph) { + int[][] cache = new int[1 << graph.length][graph.length]; + for (int i = 0;i < (1 << graph.length);i++) { + for (int j = 0;j < graph.length;j++) { + cache[i][j] = -1; + } + } + int[][] dist = calDist(graph); + int ret = 0x3fffffff; + for (int i = 0;i < graph.length;i++) { + ret = Math.min(ret, solve((1 << i), i, dist, cache)); + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0850._Rectangle_Area_II.md b/docs/Algorithm/Leetcode/Java/0850._Rectangle_Area_II.md new file mode 100755 index 00000000..3ded6874 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0850._Rectangle_Area_II.md @@ -0,0 +1,87 @@ +### 850. Rectangle Area II + + + +题目: +https://leetcode.com/problems/rectangle-area-ii/ + +难度: +Hard + +题意: + +1. 给n个矩阵,求这n个矩阵覆盖的区域面积有多大 + +思路: + +- 把x坐标和y坐标id化,将n个矩阵覆盖的区域分成r*c个小矩阵,这些小矩阵的距离都可以不相等 +- 遍历所有的矩阵,把这些小矩阵填充满 +- 遍历小矩阵,统计面积 +- 复杂度是o(n^3) +- 这个题目可以将x坐标id化后,构建线段树来查询和更新面积区域,复杂度可以降为o(n^2logn),当n>=1000使用 + +代码: + +```java +class Solution { + private int[] setToArray(TreeSet set) { + int[] ret = new int[set.size()]; + int idx = 0; + for (Integer e: set) { + ret[idx++] = e; + } + return ret; + } + + private static int MOD = 1000000007; + + public int rectangleArea(int[][] rectangles) { + TreeSet set = new TreeSet(); + for (int i = 0;i < rectangles.length;i++) { + set.add(rectangles[i][0]); + set.add(rectangles[i][2]); + } + int[] x = setToArray(set); + + set.clear(); + for (int i = 0;i < rectangles.length;i++) { + set.add(rectangles[i][1]); + set.add(rectangles[i][3]); + } + int[] y = setToArray(set); + + boolean[][] area = new boolean[x.length][y.length]; + for (int i = 0;i < x.length;i++) { + for (int j = 0;j < y.length;j++) { + area[i][j] = false; + } + } + for (int i = 0;i < rectangles.length;i++) { + int lx = Arrays.binarySearch(x, rectangles[i][0]); + int rx = Arrays.binarySearch(x, rectangles[i][2]); + + int ly = Arrays.binarySearch(y, rectangles[i][1]); + int ry = Arrays.binarySearch(y, rectangles[i][3]); + + for (int j = lx;j < rx;j++) { + for (int k = ly;k < ry;k++) { + area[j][k] = true; + } + } + } + int ret = 0; + for (int i = 0;i < x.length;i++) { + for (int j = 0;j < y.length;j++) { + if (area[i][j]) { + ret += (long)(x[i + 1] - x[i]) * (y[j + 1] - y[j]) % MOD; + if (ret >= MOD) { + ret -= MOD; + } + } + } + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0854._K-Similar_Strings.md b/docs/Algorithm/Leetcode/Java/0854._K-Similar_Strings.md new file mode 100755 index 00000000..c30626ca --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0854._K-Similar_Strings.md @@ -0,0 +1,141 @@ +### 854. K-Similar Strings + + + +题目: +https://leetcode.com/problems/k-similar-strings + +难度: +Hard + +题意: + +1. 给定两个字符串,问最少要交换多少次,使得A变成了B,A和B里面的字母都是a-f + +思路: + +- 将字符串A到字符串B的变换看成图,那么这张图就是一个一个环构成的。环上,交换的次数等于环的长度-1,所以这个题目变成了,将图拆成环,使环的个数最大 +- 后面就是纯搜索,注意状态合并。状态定义为,当前图的状态(6*6的矩阵),然后在图上寻找所有的可行环,分别去掉,转成下一个状态 + +代码: + +```java +class Solution { + private class State implements Comparable { + int[] a; + int total; + + State() { + a = new int[6]; + Arrays.fill(a, 0); + total = 0; + } + + State(int[] a, int total) { + this.a = Arrays.copyOf(a, a.length); + this.total = total; + } + + private int get(int x, int y) { + return (a[x] >> (y * 4)) & 15; + } + + private void minus(int x, int y) { + a[x] -= 1 << (y * 4); + total--; + } + + private void add(int x, int y) { + a[x] += 1 << (y * 4); + total++; + } + + @Override + public int compareTo(State o) { + if (Integer.compare(total, o.total) == 0) { + for (int i = 0;i < 6;i++) { + if (Integer.compare(a[i], o.a[i]) != 0) { + return Integer.compare(a[i], o.a[i]); + } + } + return 0; + } else { + return -Integer.compare(total, o.total); + } + } + } + + private void extand(boolean[] flag, int[] pos, TreeMap stateMap, State current, int idx) { + if (current.get(pos[idx - 1], pos[0]) != 0) { + State next = new State(current.a, current.total); + for (int i = 0;i < idx - 1;i++) { + next.minus(pos[i], pos[i + 1]); + } + next.minus(pos[idx - 1], pos[0]); + int value = stateMap.get(current); + value += idx - 1; + if (stateMap.containsKey(next)) { + value = value < stateMap.get(next) ? value : stateMap.get(next); + stateMap.put(next, value); + } else { + stateMap.put(next, value); + } + } + + if (idx == 6) { + return; + } + for (int i = 0;i < 6;i++) { + if (!flag[i] && current.get(pos[idx - 1], i) != 0) { + flag[i] = true; + pos[idx] = i; + extand(flag, pos, stateMap, current, idx + 1); + flag[i] = false; + } + } + } + + private void solve(TreeMap stateMap, State current) { + boolean[] flag = new boolean[6]; + Arrays.fill(flag, false); + int[] pos = new int[6]; + int min = -1; + for (int i = 0;i < 6;i++) { + if (current.a[i] != 0) { + min = i; + break; + } + } + if (min == -1) { + return; + } + flag[min] = true; + pos[0] = min; + extand(flag, pos, stateMap, current, 1); + } + + public int kSimilarity(String A, String B) { + TreeMap stateMap = new TreeMap(); + State start = new State(); + for (int i = 0;i < A.length();i++) { + if (A.charAt(i) != B.charAt(i)) { + start.add(A.charAt(i) - 'a', B.charAt(i) - 'a'); + } + } + int ret = 0x3fffffff; + stateMap.put(start, 0); + + while (!stateMap.isEmpty()) { + State current = stateMap.firstKey(); + if (current.total == 0) { + ret = ret < stateMap.get(current) ? ret : stateMap.get(current); + } else { + solve(stateMap, current); + } + stateMap.remove(current); + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0857._Minimum_Cost_to_Hire_K_Workers.md b/docs/Algorithm/Leetcode/Java/0857._Minimum_Cost_to_Hire_K_Workers.md new file mode 100755 index 00000000..1b2dc913 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0857._Minimum_Cost_to_Hire_K_Workers.md @@ -0,0 +1,63 @@ +### 857. Minimum Cost to Hire K Workers + + + +题目: +https://leetcode.com/problems/minimum-cost-to-hire-k-workers/ + +难度: +Hard + +题意: + +1. n个工人,有一个工作量数组quality,有个最低工资数组wage +2. 要聘用K个工人,工资最低。要求,这n个工人的工资必须不低于他们的最低工资要求,并且他们的工资跟工作量成正比 + +思路: + +- 由于工资跟工作量成正比,假设这个比率是r。第i工人愿意被聘用的条件是r>=wage[i]/quality[i] +- 令ratio[i]=wage[i]/quality[i],对ratio[i]排序,遍历数组ratio,i每递曾一个,就有一个工人愿意被聘用 +- 假设现在有p个工人愿意被聘用(p>=K),现在轮到我们来挑选K个人,由于工资总和要最低,且工资=工作量*p,所以在这p个人中挑选工作量最低的K个人 +- 子问题是,求数列中前K小的数,需要最小堆 +- 复杂度是o(nlogn) + +代码: + +```java +class Solution { + public double mincostToHireWorkers(int[] quality, int[] wage, int K) { + double[] ratio = new double[quality.length]; + Integer[] pos = new Integer[quality.length]; + for (int i = 0;i < quality.length;i++) { + ratio[i] = (double) wage[i] / quality[i]; + pos[i] = i; + } + Arrays.sort(pos, new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return Double.compare(ratio[o1], ratio[o2]); + } + }); + double ret = 1e40; + int maxK = 0; + PriorityQueue queue = new PriorityQueue(new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return -Integer.compare(o1, o2); + } + }); + for (int i = 0;i < pos.length;i++) { + maxK += quality[pos[i]]; + queue.add(quality[pos[i]]); + if (queue.size() > K) { + maxK -= queue.poll(); + } + if (queue.size() == K) { + ret = ret > maxK * ratio[pos[i]] ? maxK * ratio[pos[i]] : ret; + } + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0862._Shortest_Subarray_with_Sum_at_Least_K.md b/docs/Algorithm/Leetcode/Java/0862._Shortest_Subarray_with_Sum_at_Least_K.md new file mode 100755 index 00000000..a931ffea --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0862._Shortest_Subarray_with_Sum_at_Least_K.md @@ -0,0 +1,77 @@ +### 862. Shortest Subarray with Sum at Least K + + + +题目: +https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k + +难度: +Hard + +题意: + +1. 给定一个数组A +2. 求A的所有连续子数组中,和大于K,最短的一个,长度是多少 + +思路: + +- 如果A里面都是正整数,那就是一个妥妥的移动区间,可惜有负数 +- 换种思路,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),是不可接受的 +- 注意到,当我们累加到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 < ... +- 有了单调递增队列,当遍历到j,我们只需要二分这个队列,就可以找到一个最大的i,使的sum[1..j]-sum[1..i] >= K,插入一个数到单调队列,只需要从队列尾开始比较,把比要插入的数大的都出列,维持单调递增特性 +- 复杂度是o(nlogn) + +代码: + +```java +class Solution { + private class Node { + int sum; + int pos; + + public Node(int sum, int pos) { + this.sum = sum; + this.pos = pos; + } + } + + private int find(Node[] incrQueue, int n, int value) { + int left = -1; + int right = n; + while (right - left > 1) { + int mid = (left + right) / 2; + if (incrQueue[mid].sum <= value) { + left = mid; + } else { + right = mid; + } + } + return left; + } + + public int shortestSubarray(int[] A, int K) { + Node[] incrQueue = new Node[A.length + 1]; + int n = 0; + int ret = 0x3fffffff; + incrQueue[n++] = new Node(0, -1); + int sum = 0; + for (int i = 0;i < A.length;i++) { + sum += A[i]; + int pos = find(incrQueue, n, sum - K); + if (pos != -1) { + ret = ret < (i - incrQueue[pos].pos) ? ret : (i - incrQueue[pos].pos); + } + while (n != 0 && incrQueue[n - 1].sum > sum) { + n--; + } + incrQueue[n++] = new Node(sum, i); + } + if (ret == 0x3fffffff) { + return -1; + } else { + return ret; + } + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0864._Shortest_Path_to_Get_All_Keys.md b/docs/Algorithm/Leetcode/Java/0864._Shortest_Path_to_Get_All_Keys.md new file mode 100755 index 00000000..9125cc32 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0864._Shortest_Path_to_Get_All_Keys.md @@ -0,0 +1,180 @@ +### 864. Shortest Path to Get All Keys + + + +题目: +https://leetcode.com/problems/shortest-path-to-get-all-keys/ + +难度: +Hard + +题意: + +1. 给一个最大30*30的地图 +2. 其中有6个钥匙6个锁,锁要拿到相应的钥匙才能开 +3. 上下左右四个方向走,问最少要走多少步,才能拿到所有的钥匙 + +思路: + +- 这个题比较暴力,就是广度优先搜索 +- 注意搜索空间,总共最多才6个钥匙6个锁,定义状态为:去过的钥匙集合(二进制压缩),去过的锁集合(二进制压缩),当前位置。我们需要从这个状态转移到另一个状态,从这个状态开始广度优先搜索。转移到另一个状态,合并下一轮的搜索空间 +- 复杂度是o(k * 2 ^ 6 * 2 ^ 6 *30 * 30),k是搜索空间所用数据结构的复杂度 +- 这个题我写的比较差,主要是用了哈希表来保存搜索空间,引入了不必要的复杂度,超时了。大家写的时候直接用数组来保存搜索空间即可 +- 这道题优化空间很大,可以剪枝,大家可以当做练习 + +代码: + +```java +class Solution { + private int[] dx = new int[]{1, -1, 0, 0}; + private int[] dy = new int[]{0, 0, 1, -1}; + + private class State { + int setKey; + int setLock; + int posX; + int posY; + + public State() { + } + + public State(int setKey, int setLock, int posX, int posY) { + this.setKey = setKey; + this.setLock = setLock; + this.posX = posX; + this.posY = posY; + } + + @Override + public int hashCode() { + int hashCode = 0; + hashCode = hashCode * 31 + Integer.hashCode(setKey); + hashCode = hashCode * 31 + Integer.hashCode(setLock); + hashCode = hashCode * 31 + Integer.hashCode(posX); + hashCode = hashCode * 31 + Integer.hashCode(posY); + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof State)) { + return false; + } + State state = (State) obj; + return setKey == state.setKey && setLock == state.setLock && + posX == state.posX && posY == state.posY; + } + } + + private class Point { + int x; + int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + } + + public int shortestPathAllKeys(String[] grid) { + Map currentMap = new HashMap(); + State start = new State(); + int numKey = 0; + for (int i = 0;i < grid.length;i++) { + for (int j = 0;j < grid[i].length();j++) { + if (grid[i].charAt(j) == '@') { + start.posX = i; + start.posY = j; + } + if (grid[i].charAt(j) <= 'f' && grid[i].charAt(j) >= 'a') { + numKey ++; + } + } + } + start.setKey = start.setLock = ((1 << numKey) - 1); + currentMap.put(start, 0); + if (numKey == 0) { + return 0; + } + + int ret = 0x3fffffff; + while (!currentMap.isEmpty()) { + Map nextMap = new HashMap(); + + for (State state: currentMap.keySet()) { + + int curValue = currentMap.get(state); + if (state.setKey == 0) { + ret = ret < curValue ? ret : curValue; + continue; + } + + int[][] dis = new int[grid.length][grid[0].length()]; + for (int i = 0;i < grid.length;i++) { + for (int j = 0;j < grid[0].length();j++) { + dis[i][j] = 0x3fffffff; + } + } + dis[state.posX][state.posY] = 0; + LinkedList queue = new LinkedList(); + queue.addLast(new Point(state.posX, state.posY)); + while (!queue.isEmpty()) { + Point point = queue.pollFirst(); + for (int i = 0;i < 4;i++) { + Point next = new Point(point.x + dx[i], point.y + dy[i]); + if (next.x < 0 || next.y < 0 || next.x >= grid.length || next.y >= grid[0].length()) { + continue; + } + char c = grid[next.x].charAt(next.y); + if (c == '#') { + continue; + } + if (c <= 'F' && c >= 'A' && (state.setKey & (1 << (c - 'A'))) != 0) { + continue; + } + + if (dis[next.x][next.y] == 0x3fffffff) { + dis[next.x][next.y] = dis[point.x][point.y] + 1; + queue.addLast(next); + + if (c <= 'f' && c >= 'a' && (state.setKey & (1 << (c - 'a'))) != 0) { + State nextState = new State( + state.setKey - (1 << (c - 'a')), + state.setLock, + next.x, + next.y + ); + int value = currentMap.get(state) + dis[next.x][next.y]; + if (!nextMap.containsKey(nextState) || value < nextMap.get(nextState)) { + nextMap.put(nextState, value); + } + } + + if (c <= 'F' && c >= 'A' && (state.setLock & (1 << (c - 'A'))) != 0) { + State nextState = new State( + state.setKey, + state.setLock - (1 << (c - 'A')), + next.x, + next.y + ); + int value = curValue + dis[next.x][next.y]; + if (!nextMap.containsKey(nextState) || value < nextMap.get(nextState)) { + nextMap.put(nextState, value); + } + } + } + } + } + } + + currentMap = nextMap; + } + if (ret == 0x3fffffff) { + return -1; + } else { + return ret; + } + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0871._Minimum_Number_of_Refueling_Stops.md b/docs/Algorithm/Leetcode/Java/0871._Minimum_Number_of_Refueling_Stops.md new file mode 100755 index 00000000..5c57101f --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0871._Minimum_Number_of_Refueling_Stops.md @@ -0,0 +1,69 @@ +### 871. Minimum Number of Refueling Stops + + + +题目: +https://leetcode.com/problems/minimum-number-of-refueling-stops/ + +难度: +Hard + +题意: + +1. 一辆车要从start跑到target,带着fuel单位的油 +2. 中间有很多个加油站,给定加油站的坐标和油量。到了加油站你可以选择到站加油和直接过站 +3. 求最少需要停几个加油站 + +思路: + +- 看起来是不是跟403的Frog jump很像啊,看数据范围,确实也是个动态规划的题目,动态规划的解法留给大家做,这里说一个更简单的方法 +- 我们可以换种思路。每次到站之后,把所有加油站的油都带上。先不加,等到有需要的时候再加。如果发现不够油到下个加油站,那么我们就优先选择油多的加油站的油来加,相当于我们在那个加油站停了。这里为什么优先选择油多的加油站呢?因为油多也是一站,油少也是一站。 +- 如果把所有的油加满都达不到下个加油站,那么,输出-1 +- 如果可以到target之后,我们就输出加了多少个加油站的油即可 +- 中间那部分,优先选择油多,我们需要维护一个优先队列(即最大堆),复杂度o(nlogn),当然按照数据范围,就算是用一个链表啊,数组啊,o(n^2)照样能过,这道题的数据范围出错了,应该是stations.length<=100000 +- 这种算法叫贪心 + +代码: + +```java +class Solution { + private int runTo(int start, int fuel, int target, PriorityQueue queue) { + fuel -= target - start; + while (fuel < 0) { + Integer top = queue.poll(); + if (top == null) { + return -1; + } + fuel += top; + } + return fuel; + } + + public int minRefuelStops(int target, int startFuel, int[][] stations) { + PriorityQueue queue = new PriorityQueue<>(new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return -Integer.compare(o1, o2); + } + }); + int start = 0; + int fuel = startFuel; + + for (int i = 0;i < stations.length;i++) { + fuel = runTo(start, fuel, stations[i][0], queue); + if (fuel == -1) { + return fuel; + } + queue.add(stations[i][1]); + start = stations[i][0]; + } + + if (runTo(start, fuel, target, queue) != -1) { + return stations.length - queue.size(); + } else { + return -1; + } + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0878._Nth_Magical_Number.md b/docs/Algorithm/Leetcode/Java/0878._Nth_Magical_Number.md new file mode 100755 index 00000000..be2d4a31 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0878._Nth_Magical_Number.md @@ -0,0 +1,103 @@ +# 878. Nth Magical Number + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/nth-magical-number/description/ + +> 内容描述 + +``` +A positive integer is magical if it is divisible by either A or B. + +Return the N-th magical number. Since the answer may be very large, return it modulo 10^9 + 7. + + + +Example 1: + +Input: N = 1, A = 2, B = 3 +Output: 2 +Example 2: + +Input: N = 4, A = 2, B = 3 +Output: 6 +Example 3: + +Input: N = 5, A = 2, B = 4 +Output: 10 +Example 4: + +Input: N = 3, A = 6, B = 4 +Output: 8 + + +Note: + +1 <= N <= 10^9 +2 <= A <= 40000 +2 <= B <= 40000 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(log(A*B))******- 空间复杂度: O(N)****** + +* 从数据范围看来,N高达10^9,直接遍历不现实 +* 注意到魔法数是有循环的,我们令P=A和B的最小公倍数,那么在每P个数中,魔法数的数量和位置都是相同的,因此我们只需要计算1-P中间的魔法数 +* 1~P的魔法数数量是 P/A+P/B-1,注意到,P是A和B的最小公倍数,因此1~P中,既能被A整除,也能被B整除,只有一个数,就是P +* 现在问题变成,在1~P中,求第n个魔法数 +* 解法一:A和B的数据范围只有40000,因此,1~P中魔法数,不超过80000个,只需要把所有的魔法数求出来,排个序,就能求出第n个魔法数,复杂度是O(A+B) +* 解法二:注意到,我们在1~p中任取一个数x(x 1) { + int mid = (left + right) / 2; + if (mid / a + mid / b >= n) { + right = mid; + } else { + left = mid; + } + } + + return right; + } + + public int nthMagicalNumber(int N, int A, int B) { + int repeat = lcm(A, B); + int num = repeat / A + repeat / B - 1; + + int ret = find(A, B, (N - 1) % num + 1); + ret += (long)((N - 1) / num) * repeat % MOD; + if (ret > MOD) { + ret -= MOD; + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0879._Profitable_Schemes.md b/docs/Algorithm/Leetcode/Java/0879._Profitable_Schemes.md new file mode 100755 index 00000000..8d615678 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0879._Profitable_Schemes.md @@ -0,0 +1,66 @@ +### 879. Profitable Schemes + + + +题目: +https://leetcode.com/problems/profitable-schemes/ + +难度: +Hard + +题意: + +1. 给定一个集合,每个集合都有一个group和profile,给定两个数G和P +2. 求在集合所有的子集合中,group和不大于G,并且profile和不小于P的子集合个数 + +思路: + +- 这是一个01背包模型的变种 +- 大家思考一下,01背包是说,给定一个集合,每个集合有一个成本和一个收益,求成本和不大于总成本的最大收益 +- 这个题有两个条件,因此有两个规划方向。这两个方向还不一样,group是约束条件,规划长度是1-G,而profile是下限,规划长度也是1-P(因为超过P再记录P的具体的值已经没有意义了,所以一切>=P都可用P代替) +- 最后的结果就是总group在1-G中,并且总profile>=p的子集合个数 +- 复杂度是o(NGP),看数据范围,是不是正好在10^6的量级里面? + +代码: + +```java +class Solution { + private static int MOD = 1000000007; + + public int profitableSchemes(int G, int P, int[] group, int[] profit) { + int[][] dp = new int[G + 1][P + 1]; + for(int i = 0;i <= G;i++) { + for (int j = 0;j <= P;j++) { + dp[i][j] = 0; + } + } + dp[0][0] = 1; + for (int k = 0;k < group.length;k++) { + for (int i = G;i >= 0;i--) { + if (i + group[k] > G) { + continue; + } + for (int j = 0;j <= P;j++) { + int p = j + profit[k]; + if (p > P) { + p = P; + } + dp[i + group[k]][p] += dp[i][j]; + if (dp[i + group[k]][p] >= MOD) { + dp[i + group[k]][p] -= MOD; + } + } + } + } + int ret = 0; + for (int i = 1;i <= G;i++) { + ret += dp[i][P]; + if (ret >= MOD) { + ret -= MOD; + } + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0882._Reachable_Nodes_In_Subdivided_Graph.md b/docs/Algorithm/Leetcode/Java/0882._Reachable_Nodes_In_Subdivided_Graph.md new file mode 100755 index 00000000..b1be4d82 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0882._Reachable_Nodes_In_Subdivided_Graph.md @@ -0,0 +1,116 @@ +### 899. Reachable Nodes In Subdivided Graph + + + +题目: +https://leetcode.com/problems/reachable-nodes-in-subdivided-graph/ + +难度: +Hard + +题意: + +1. 给定一张图,图上有无向边,边上有等距的点 +2. 从0出发,最长路径能够访问M个点,问总共能访问多少个点 + +思路: + +- 这个题是最短路的变种 +- 边上面点的个数就是边的权值,先做一遍最短路 +- 扫描每个边,判断左右两个端点的值,进行累加 + - 左/右 端点大于M的,不累加 + - 左/右 端点分别向边里面访问点,假设左端点能访问a个点,右端点能访问b个点,那么能访问的点数就是min(a + b, 该边点数) +- 统计完边,再统计点,只需要扫描所有点,根据最短路的端点值,判断是否不大于M,累加 +- 最短路复杂度是o(n^2),最短路中间有一个步骤,每一轮寻找当前最小的点开扩展,这一步骤是可以用一个堆来优化,复杂度是o(n log e),e是边的个数。这个做法留给大家做练习 + +代码: + +```java +class Solution { + private static int MAX = 2000000000; + + private class Edge { + int src; + int dest; + int value; + + public Edge(int src, int dest, int value) { + this.src = src; + this.dest = dest; + this.value = value; + } + } + + public int reachableNodes(int[][] edges, int M, int N) { + List[] edgeList = new List[N]; + for (int i = 0;i < edgeList.length;i++) { + edgeList[i] = new ArrayList(); + } + + for (int i = 0;i < edges.length;i++) { + edgeList[edges[i][0]].add(new Edge(edges[i][0], edges[i][1], edges[i][2] + 1)); + edgeList[edges[i][1]].add(new Edge(edges[i][1], edges[i][0], edges[i][2] + 1)); + } + + int ret = 0; + + boolean[] flag = new boolean[N]; + int[] min = new int[N]; + for (int i = 0;i < N;i++) { + flag[i] = false; + min[i] = MAX; + } + + min[0] = 0; + while (true) { + int idx = -1; + for (int i = 0;i < N;i++) { + if (!flag[i] && min[i] != MAX) { + if (idx == -1 || min[i] < min[idx]) { + idx = i; + } + } + } + if (idx == -1) { + break; + } + + flag[idx] = true; + for (int i = 0;i < edgeList[idx].size();i++) { + Edge edge = edgeList[idx].get(i); + if (!flag[edge.dest]) { + min[edge.dest] = Math.min(min[edge.dest], min[edge.src] + edge.value); + } + } + } + + for (int i = 0;i < edges.length;i++) { + if (min[edges[i][0]] + edges[i][2] <= M || min[edges[i][1]] + edges[i][2] <= M) { + ret += edges[i][2]; + continue; + } + int left = 0, right = 0; + if (min[edges[i][0]] <= M) { + left = M - min[edges[i][0]]; + } + if (min[edges[i][1]] <= M) { + right = M - min[edges[i][1]]; + } + if (left + right >= edges[i][2]) { + ret += edges[i][2]; + } else { + ret += left + right; + } + } + + for (int i = 0;i < N;i++) { + if (min[i] <= M) { + ret++; + } + } + + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0887._Super_Egg_Drop.md b/docs/Algorithm/Leetcode/Java/0887._Super_Egg_Drop.md new file mode 100755 index 00000000..9f7870d0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0887._Super_Egg_Drop.md @@ -0,0 +1,66 @@ +### 887. Super Egg Drop + + + +题目: +https://leetcode.com/problems/super-egg-drop + +难度: +Hard + +题意: + +1. 已知蛋从F楼丢下会坏 +2. 现在给你K个蛋,在N层楼中,请问最坏情况最少要试验几次才能知道F的精确值 +3. 如果蛋丢下来不会坏,那么可以捡起来继续丢 + +思路: + +- 又是一个脑筋急转弯的题目,我们来看看K=1的情况。由于只有一个蛋,坏了就没了,所以只能一层一层往下丢。一层丢下,蛋坏了,说明F=1,反之,继续去二层丢,所以K=1时,最坏情况要试验N次 +- 当K>=2时,由于蛋有多余,可以大胆的去中间丢,这样就可以少丢几次 +- 因此,令`cache[K][N]`表示K个蛋在N层试验最少要试验的次数,假设第一次要在i层丢蛋,那么分成了两个子问题,如果蛋没碎了,那么最少次数等于`cache[k][N-i]+1`,如果蛋碎了,那么最少次数等于`cache[k-1][i-1]+1` +- 那么这个题就变成了`cache[k][N] = min[1<=i<=N]{max{cache[k][N-i], cache[k - 1][i - 1] + 1} + 1}`,时间复杂度是o(kNN) +- 但是看数据范围,k<=100,N<=10000,o(kNN)肯定是过不了的 +- 注意到,`cache[k][N]`是非严格递增输了,且递增值不会超过1,即`0<=cache[k][i+1]-cache[k][i]<=1` +- 计算过程中令`cache[k][N]`最优解的i,跟`cache[k][N+1]`最优解的j,关系是`0<=j-i<=1` +- 因此在处理的过程,固定k,递推N,保存上一个最优解i,继续推出下一个最优解 + +代码: + +```java +class Solution { + private static int[][] cache; + + private static void init() { + if (cache == null) { + cache = new int[101][10001]; + + for (int i = 1;i <= 10000;i++) { + cache[1][i] = i; + } + + for (int i = 2;i <= 100;i++) { + cache[i][1] = 0; + cache[i][1] = 1; + cache[i][2] = 2; + + int idx = 1; + for (int j = 3;j <= 10000;j++) { + + while (cache[i - 1][idx + 1] <= cache[i][j - idx - 2]) { + idx++; + } + + cache[i][j] = Math.max(cache[i - 1][idx], cache[i][j - idx - 1]) + 1; + } + } + } + } + + public int superEggDrop(int K, int N) { + init(); + return cache[K][N]; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0891._Sum_of_Subsequence_Widths.md b/docs/Algorithm/Leetcode/Java/0891._Sum_of_Subsequence_Widths.md new file mode 100755 index 00000000..69ab46ed --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0891._Sum_of_Subsequence_Widths.md @@ -0,0 +1,90 @@ +# 891. Sum of Subsequence Widths + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/sum-of-subsequence-widths/description/ + +> 内容描述 + +``` + +Given an array of integers A, consider all non-empty subsequences of A. + +For any sequence S, let the width of S be the difference between the maximum and minimum element of S. + +Return the sum of the widths of all subsequences of A. + +As the answer may be very large, return the answer modulo 10^9 + 7. + + + +Example 1: + +Input: [2,1,3] +Output: 6 +Explanation: +Subsequences are [1], [2], [3], [2,1], [2,3], [1,3], [2,1,3]. +The corresponding widths are 0, 0, 0, 1, 1, 2, 2. +The sum of these widths is 6. + + +Note: + +1 <= A.length <= 20000 +1 <= A[i] <= 20000 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)****** + +* 我们逆向思路解决这个问题。结果要求最大数减去最小数的差之和,我们可以认为是,把所有的子序列的最大值累加,减去所有的子序列的最小值的累加值 +* 数组中最大数,在子数组中也是最大数的,有2^(n-1)个子数组,同理,第二大数,在子数组是最大数的,有2^(n-2)个子数组,以此类推 +* 同理,最小数也是这样计算 +* 复杂度是O(nlgn) + +代码: + +```java +class Solution { + private static int MOD = 1000000007; + + private static int[] pow2; + + private void init() { + if (pow2 == null) { + pow2 = new int[20000]; + pow2[0] = 1; + for (int i = 1;i < pow2.length;i++) { + pow2[i] = pow2[i - 1] * 2; + if (pow2[i] >= MOD) { + pow2[i] -= MOD; + } + } + } + } + + public int sumSubseqWidths(int[] A) { + init(); + Arrays.sort(A); + int ret = 0; + for (int i = 0;i < A.length;i++) { + ret += (long)A[i] * pow2[i] % MOD; + if (ret >= MOD) { + ret -= MOD; + } + ret -= (long)A[i] * pow2[A.length - i - 1] % MOD; + if (ret < 0) { + ret += MOD; + } + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0895._Maximum_Frequency_Stack.md b/docs/Algorithm/Leetcode/Java/0895._Maximum_Frequency_Stack.md new file mode 100755 index 00000000..7f002afc --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0895._Maximum_Frequency_Stack.md @@ -0,0 +1,96 @@ +### 895. Maximum Frequency Stack + + + +题目: +https://leetcode.com/problems/maximum-frequency-stack/ + +难度: +Hard + +题意: + +1. 一个特殊的类栈数据结构,具有两种操作 +2. push x:表示将x入栈 +3. pop:表示将栈中最多的数弹出,相同数量的数弹出最近入栈的一个数 + +思路: + +- 这个题的数据结构中,x是key,既需要根据x来操作,又需要根据x的数量和入栈时间来出栈,典型的双向查找表 + +- 维护一个x到x的入栈时间的映射关系,入栈时间我们定义为第几次push操作,即x->[t1,t2,t3] + +- 维护一个**有序**的x的入栈时间到x的对应表,比较函数定义为:栈中元素个数,和栈顶时间 + +代码: + +```java +class FreqStack { + + int _count; + private class Item implements Comparable { + LinkedList time; + + public Item(LinkedList time) { + this.time = time; + } + + public LinkedList getTime() { + return time; + } + + @Override + public int compareTo(Item o) { + if (time.size() == o.time.size()) { + return Integer.compare(o.time.getLast(), time.getLast()); + } else { + return Integer.compare(o.time.size(), time.size()); + } + } + } + + TreeMap freqToId; + Map idToFreq; + + public FreqStack() { + _count = 0; + freqToId = new TreeMap(); + idToFreq = new HashMap(); + } + + public void push(int x) { + if (!idToFreq.containsKey(x)) { + LinkedList time = new LinkedList(); + time.addLast(_count++); + Item item = new Item(time); + freqToId.put(item, x); + idToFreq.put(x, item); + } else { + Item origin = idToFreq.get(x); + freqToId.remove(origin); + LinkedList time = origin.time; + time.addLast(_count++); + Item item = new Item(time); + idToFreq.put(x, item); + freqToId.put(item, x); + } + } + + public int pop() { + Map.Entry first = freqToId.firstEntry(); + freqToId.remove(first.getKey()); + idToFreq.remove(first.getValue()); + + LinkedList time = first.getKey().time; + time.removeLast(); + if (time.size() != 0) { + Item item = new Item(time); + idToFreq.put(first.getValue(), item); + freqToId.put(item, first.getValue()); + } + + return first.getValue(); + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0899._Orderly_Queue.md b/docs/Algorithm/Leetcode/Java/0899._Orderly_Queue.md new file mode 100755 index 00000000..711480fa --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0899._Orderly_Queue.md @@ -0,0 +1,54 @@ +### 899. Orderly Queue + + + +题目: +https://leetcode.com/problems/orderly-queue/ + +难度: +Hard + +题意: + +1. 给定一个字符串S和一个数K +2. 每一轮可以选择字符串的前K个数的其中一个,把它移到放在最后面 +3. 无限次数后,问生成的最小字符串是什么 + +思路: + +- 不要考虑暴力了,由于是无限次数,连暴力搜索都无从下手,除非出动启发式搜索 +- 这是个脑筋急转弯的题目,分为两种情况 +- 当K=1时,由于每次只能取第一个放在最后面,这种情况是暴力搜索,时间复杂度是o(nk),k是字符串的长度 +- 当K>=2时,我们拿K=2出来考虑,证明当K=2时,可以生成任一字符串。 + - 固定第一个数,不断的把第二个数放在最后面,这种做法可以使第一个数插入到队列的任一位置 + - 假设队列A1-Ak有序,我们要把第A(k+1)插入到Ak的后面,只需要把A(k+1)固定在第一个数,重复第一个做法即可 + - 根据数据归纳法,当K=2时,可以生成任一字符串 +- 因此当K>=2时,只需要排序字符串里面的字符即可 + +拓展: + +- 这道题有o(nlogn)的解法,当k=1时,可以用o(nlogn)的排序算法,找到最小的字符串。有兴趣的同学可以百度一下“后缀数组”,一百行代码左右,这里就不展示了 + +代码: + +```java +class Solution { + public String orderlyQueue(String S, int K) { + if (K == 1) { + String min = S; + for (int i = 0;i < S.length();i++) { + S = S.substring(1, S.length()) + S.charAt(0); + if (min.compareTo(S) > 0) { + min = S; + } + } + return min; + } else { + char[] c = S.toCharArray(); + Arrays.sort(c); + return new String(c); + } + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0902._Numbers_At_Most_N_Given_Digit_Set.md b/docs/Algorithm/Leetcode/Java/0902._Numbers_At_Most_N_Given_Digit_Set.md new file mode 100755 index 00000000..4bc5617a --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0902._Numbers_At_Most_N_Given_Digit_Set.md @@ -0,0 +1,78 @@ +### 902. Numbers At Most N Given Digit Set + + + +题目: +https://leetcode.com/problems/numbers-at-most-n-given-digit-set/ + +难度: +Hard + +题意: + +1. 给定一个1-9的集合S,和一个上限k +2. 求这个集合中能构成多少个数,并且不大于k + +思路: + +- 分情况计算 + - 当构成的数的位数小于k的位数,那么能构成的数数量为|S|^位数 + - 当构成的数的位数等于k的位数,遍历集合S的数a,判断a + - 如果小于k的最高位,那么能够成的数数量为|S|^(k的位数-1) + - 如果等于k的最高位,继续判断下一位 + - 如果不存在等于k的最高位的数,不判断下一位,直接跳出循环 + +代码: + +```java +class Solution { + private int[] split(int a) { + int[] ret = new int[10]; + int idx = 0; + while (a != 0) { + ret[idx++] = a % 10; + a /= 10; + } + return Arrays.copyOf(ret, idx); + } + + public int atMostNGivenDigitSet(String[] D, int N) { + int[] d = new int[D.length]; + for (int i = 0;i < D.length;i++) { + d[i] = Integer.parseInt(D[i]); + } + + int[] length = new int[10]; + length[0] = 1; + for (int i = 1;i < 10;i++) { + length[i] = length[i - 1] * D.length; + } + + int[] a = split(N); + int ret = 0; + for (int i = 1;i < a.length;i++) { + ret += length[i]; + } + int i; + for (i = a.length - 1;i >= 0;i--) { + boolean find = false; + for (int j = 0;j < d.length;j++) { + if (a[i] == d[j]) { + find = true; + } + if (d[j] < a[i]) { + ret += length[i]; + } + } + if (!find) { + break; + } + } + if (i < 0) { + ret++; + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0903._Valid_Permutations_for_DI_Sequence.md b/docs/Algorithm/Leetcode/Java/0903._Valid_Permutations_for_DI_Sequence.md new file mode 100755 index 00000000..dacfafdc --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0903._Valid_Permutations_for_DI_Sequence.md @@ -0,0 +1,95 @@ +### 903. Valid Permutations for DI Sequence + + + +题目: +https://leetcode.com/problems/valid-permutations-for-di-sequence + +难度: +Hard + +题意: + +1. 给定一个字符串,长度为n,D代表前一个数比下一个数大而I代表前一个数比下一个数小 +2. 求出在所有0-n的排列中,满足上面字符串所代表的排列两两之间大小比较的排列的个数 + +思路: + +- 最大的那个数,可能出现在下面三种情况: + - 出现在位置0,a[0]>a[1] + - 出现在位置i,a[i]>a[i+1]且a[i]a[n-1] +- 枚举最大的数出现的位置,假设为i,当i选定为最大的数后,剩下的数要分配给左右两边,有c(n, i)种情况,并且左右两边的队列互相独立 +- 这时候左右两边分别成了一个命题相同的子问题,求出即可 +- 注意:需要注意的是,不是所有的动态规划都需要用递推的方式求解。这道题可以选择另一种写法,就是递归+缓存,代码量会少不少 + +代码: + +```java +class Solution { + private static int[][] c; + private static int MOD = 1000000007; + private static int[][] cache = new int[202][202]; + + private void init() { + c = new int[202][202]; + c[0][0] = 1; + for (int i = 1;i <= 201;i++) { + c[i][0] = 1; + for (int j = 1;j < i;j++) { + c[i][j] = c[i - 1][j - 1] + c[i - 1][j]; + if (c[i][j] >= MOD) { + c[i][j] -= MOD; + } + } + c[i][i] = 1; + } + } + + public int find(String S, int left, int right) { + int ret = 0; + if (right - left == 0) { + return 1; + } + if (cache[left][right] != -1) { + return cache[left][right]; + } + if (S.charAt(left) == 'D') { + ret += find(S, left + 1, right); + if (ret >= MOD) { + ret -= MOD; + } + } + if (S.charAt(right - 1) == 'I') { + ret += find(S, left, right - 1); + if (ret >= MOD) { + ret -= MOD; + } + } + for (int i = left + 1;i < right;i++) { + if (S.charAt(i) == 'D' && S.charAt(i - 1) == 'I') { + ret += ((long) find(S, left, i - 1) * find(S, i + 1, right) % MOD) * c[right - left][i - left] % MOD; + if (ret >= MOD) { + ret -= MOD; + } + } + } + if (ret == 0) { + return cache[left][right] = 1; + } + return cache[left][right] = ret; + } + + public int numPermsDISequence(String S) { + init(); + for (int i = 0;i < 202;i++) { + for (int j = 0;j < 202;j++) { + cache[i][j] = -1; + } + } + int ret = find(S, 0, S.length()); + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0906._Super_Palindromes.md b/docs/Algorithm/Leetcode/Java/0906._Super_Palindromes.md new file mode 100755 index 00000000..5c5970d2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0906._Super_Palindromes.md @@ -0,0 +1,151 @@ +### 906. Super Palindromes + + + +题目: +https://leetcode.com/problems/super-palindromes/ + +难度: +Hard + +题意: + +1. 定义超级回文数为,是回文数,并且是回文数的平方 +2. 给定范围[L,R],求出超级回文数的个数 + +思路: + +- 看数据范围,L和R都在10^18内 +- 令a为其中一个超级回文数,那么a=b*b,b也是一个回文数,由于超级回文数在10^18以内,b的取值范围是10^9以内 +- 由于b是回文数,只有两种情况,如果长度为奇数的话,那么b就是(abcd)x(dcba),如果长度为偶数的话,那么b就是(abcd)(dcba),那么小于10^9的回文数个数,不超过11w个 +- 那么这个题的解题方案就是把所有的超级回文数枚举出来 +- 当然要挑战速度的话,注意到超级回文数才70个,写死在代码里面绝对秒杀各种预处理代码 + +代码: + +```java +class Solution { + private static List allSuper; + + private int[] split(int a) { + int[] ret = new int[10]; + int idx = 0; + while (a != 0) { + ret[idx++] = a % 10; + a /= 10; + } + return Arrays.copyOf(ret, idx); + } + + private int[] split(long a) { + int[] ret = new int[20]; + int idx = 0; + while (a != 0) { + ret[idx++] = (int) (a % 10); + a /= 10; + } + return Arrays.copyOf(ret, idx); + } + + private int joinToInt(int[] a) { + int ret = 0; + for (int i = a.length - 1;i >= 0;i--) { + ret = ret * 10 + a[i]; + } + return ret; + } + + private long joinToLong(int[] a) { + long ret = 0; + for (int i = a.length - 1;i >= 0;i--) { + ret = ret * 10 + a[i]; + } + return ret; + } + + private int[] reverse(int[] a) { + int[] ret = new int[a.length]; + for (int i = 0;i < ret.length;i++) { + ret[i] = a[ret.length - i - 1]; + } + return ret; + } + + private int join(int[] a, int e) { + int[] ret = new int[a.length * 2 + 1]; + for (int i = 0;i < a.length;i++) { + ret[i] = a[i]; + } + ret[a.length] = e; + a = reverse(a); + for (int i = 0;i < a.length;i++) { + ret[a.length + i + 1] = a[i]; + } + return joinToInt(ret); + } + + private int join(int[] a) { + int[] ret = new int[a.length * 2]; + for (int i = 0;i < a.length;i++) { + ret[i] = a[i]; + } + a = reverse(a); + for (int i = 0;i < a.length;i++) { + ret[a.length + i] = a[i]; + } + return joinToInt(ret); + } + + private boolean isPalindrome(int[] a) { + int left = 0; + int right = a.length - 1; + while (right > left) { + if (a[right] != a[left]) { + return false; + } + right--; + left++; + } + return true; + } + + private void judgeAndAdd(int x) { + long t = (long)x * x; + if (isPalindrome(split(t))) { + allSuper.add(t); + } + } + + private void init() { + allSuper = new ArrayList(); + allSuper.add(1L); + allSuper.add(4L); + allSuper.add(9L); + for (int i = 1;i <= 9999;i++) { + int[] a = split(i); + a = reverse(a); + judgeAndAdd(join(a)); + + for (int j = 0;j <= 9;j++) { + judgeAndAdd(join(a, j)); + } + } + } + + public int superpalindromesInRange(String L, String R) { + init(); + + long l = Long.valueOf(L); + long r = Long.valueOf(R); + + int count = 0; + for (int i = 0;i < allSuper.size();i++) { + if (allSuper.get(i) >= l && allSuper.get(i) <= r) { + count++; + } + } + return count; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0913._Cat_and_Mouse.md b/docs/Algorithm/Leetcode/Java/0913._Cat_and_Mouse.md new file mode 100755 index 00000000..1872b5f9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0913._Cat_and_Mouse.md @@ -0,0 +1,178 @@ +### 913. Cat and Mouse + + + +题目: +https://leetcode.com/problems/cat-and-mouse/ + +难度: +Hard + +题意: + +1. 给定一张图,猫和鼠轮流走动,每一次可以走到当前点的下一个节点 +2. 猫胜利的条件是猫和老鼠在同一个位置 +3. 老鼠胜利的条件是到达0号节点 +4. 如果猫和老鼠所到达的状态是先前他们走过的状态,则平局 +5. 猫和鼠都是选择对它们最优的策略走 + +思路: + +- 零和博弈 +- 轮到猫走的时候,猫会选择一个状态,使得这个状态下猫必胜利 +- 如果找不到一个子状态必胜,那么猫会找一个平局的状态进行游戏 +- 如果找不到一个必胜和一个平局的状态,那么这个状态下只能鼠胜出 +- 轮到鼠走时也是如此 +- 令状态表达式是`f[first][cat][mouse]`表示猫或者鼠先走时,猫在cat的位置,鼠在mouse的位置的状态,状态值是猫(2)或鼠(1)胜利,或者平局(0) +- 根据博弈的条件,可以得出状态转移公式和初始状态 +- 这个题最难的地方不在公式,而是无子问题。无法用递推或者递归的方式解决问题。借助一下最短路松弛算法,我们可以从初始状态出发,然后影响周边状态,假设某个状态值改变了,需要对这个状态的周边状态进行重新计算,直到收敛 + +代码: + +```java +class Solution { + private class Node { + int first; + int mouse; + int cat; + + public Node(int first, int cat, int mouse) { + this.first = first; + this.mouse = mouse; + this.cat = cat; + } + + public int getFirst() { + return first; + } + + public void setFirst(int first) { + this.first = first; + } + + public int getMouse() { + return mouse; + } + + public void setMouse(int mouse) { + this.mouse = mouse; + } + + public int getCat() { + return cat; + } + + public void setCat(int cat) { + this.cat = cat; + } + } + + private int solve(int[][] graph) { + int[][][] cache = new int[2][graph.length][graph.length]; + for (int first = 0;first < 2;first++) { + for (int cat = 0;cat < graph.length;cat++) { + for (int mouse = 0;mouse < graph.length;mouse++) { + cache[first][cat][mouse] = 0; + } + } + } + + Queue nodes = new LinkedList<>(); + + for (int first = 0;first < 2;first++) { + for (int cat = 1; cat < graph.length; cat++) { + for (int mouse = 0; mouse < graph.length; mouse++) { + if (mouse == 0) { + cache[first][cat][mouse] = 1; + nodes.add(new Node(first, cat, mouse)); + } + if (cat == mouse) { + cache[first][cat][mouse] = 2; + nodes.add(new Node(first, cat, mouse)); + } + } + } + } + + while (!nodes.isEmpty()) { + Node node = nodes.poll(); + + if (node.first == 0) { + for (int i = 0;i < graph[node.mouse].length;i++) { + int x = graph[node.mouse][i]; + + int pre = cache[1][node.cat][x]; + if (x == 0 || node.cat == x) { + continue; + } + + boolean findWin = false; + boolean findDraw = false; + for (int j = 0;j < graph[x].length;j++) { + int y = graph[x][j]; + if (cache[0][node.cat][y] == 1) { + findWin = true; + } else if (cache[0][node.cat][y] == 0) { + findDraw = true; + } + } + if (findWin) { + cache[1][node.cat][x] = 1; + } else if (!findDraw) { + cache[1][node.cat][x] = 2; + } else { + cache[1][node.cat][x] = 0; + } + + if (cache[1][node.cat][x] != pre) { + nodes.add(new Node(1, node.cat, x)); + } + } + } else { + for (int i = 0;i < graph[node.cat].length;i++) { + int x = graph[node.cat][i]; + + int pre = cache[0][x][node.mouse]; + + if (x == 0 || node.mouse == x) { + continue; + } + + boolean findWin = false; + boolean findDraw = false; + for (int j = 0;j < graph[x].length;j++) { + int y = graph[x][j]; + if (y == 0) { + continue; + } + if (cache[1][y][node.mouse] == 2) { + findWin = true; + } else if (cache[1][y][node.mouse] == 0) { + findDraw = true; + } + } + if (findWin) { + cache[0][x][node.mouse] = 2; + } else if (!findDraw) { + cache[0][x][node.mouse] = 1; + } else { + cache[0][x][node.mouse] = 0; + } + + if (pre != cache[0][x][node.mouse]) { + nodes.add(new Node(0, x, node.mouse)); + } + } + } + } + + return cache[1][2][1]; + } + + public int catMouseGame(int[][] graph) { + int ret = solve(graph); + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Java/0920._Number_of_Music_Playlists.md b/docs/Algorithm/Leetcode/Java/0920._Number_of_Music_Playlists.md new file mode 100755 index 00000000..cf7685b2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Java/0920._Number_of_Music_Playlists.md @@ -0,0 +1,64 @@ +### 920. Number of Music Playlists + + + +题目: +https://leetcode.com/problems/number-of-music-playlists + +难度: +Hard + +题意: + +1. 排一张长度为L首的有顺序的歌单,有N首歌可以选择 +2. 每N首歌必须出现一次 +3. 两个相同的歌必须隔K首歌才能再次出现 +4. 问有多少种排列方式 + +思路: + +- 排列组合的题目,最重要的是找准排列方向,避免计算重复 +- 先解决第一个条件,每首歌必须出现一次,那么我们先把N首歌放进歌单中,不管顺序先 +- 我们假定已经把N首歌放进歌单,那么其他的位置就随意放,只要满足相同的歌必须隔K个位置 +- 为了避免计算重复,我们规定,这N首歌不管是放在什么位置,都是这首歌在歌单的第一次出现 +- 剩下的就是动态规划了。定义`dp[l][n]`为歌单的前l个位置中,填入了n首唯一的歌 +- 状态转移有两种情况, + - 这个位置已经有歌放进来了(因为我们事先填入了N首歌),排序方式为`dp[l-1][n-1]` + - 这个位置没有歌放进来。由于我们的设定,这个位置只能有n首歌选择(因为其他歌还没有第一次出现在歌单)。注意有隔K首歌的问题,前面有K首歌不能选,这K首歌还不一样,为什么呢,因为这K首歌里面,两两之间肯定相隔小于K。所以只有n-k首歌选择,排序方式为`dp[l-1][n-1]*(n-K)` +- 由于我们事先把N首歌放进去,这N首歌肯定会有顺序排列。于是最后的结果就等于`dp[L][N]*n!` + +代码: + +```java +class Solution { + private static int MOD = 1000000007; + + public int numMusicPlaylists(int N, int L, int K) { + int[][] dp = new int[L + 1][N + 1]; + dp[0][0] = 1; + for (int i = 1;i <= N;i++) { + dp[0][i] = 0; + } + for (int i = 1;i <= L;i++) { + dp[i][0] = 0; + for (int j = 1;j <= N;j++) { + int p = j - Math.min(i - 1, K); + if (p < 0) { + p = 0; + } + dp[i][j] = (int) ((long)dp[i - 1][j] * p % MOD); + dp[i][j] += dp[i - 1][j - 1]; + if (dp[i][j] >= MOD) { + dp[i][j] -= MOD; + } + } + } + int ret = dp[L][N]; + for (int i = 1;i <= N;i++) { + ret = (int) ((long) ret * i % MOD); + } + return ret; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0001._Two_Sum.md b/docs/Algorithm/Leetcode/JavaScript/0001._Two_Sum.md new file mode 100755 index 00000000..db181811 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0001._Two_Sum.md @@ -0,0 +1,56 @@ +# 001. Two Sum + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum/description/ + +> 内容描述 + +``` +Given an array of integers, return indices of the two numbers such that they add up to a specific target. + +You may assume that each input would have exactly one solution, and you may not use the same element twice. + +Example: + +Given nums = [2, 7, 11, 15], target = 9, + +Because nums[0] + nums[1] = 2 + 7 = 9, +return [0, 1]. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +算法来源于知乎文章——[趣味算法思想](https://zhuanlan.zhihu.com/p/46223775) + +先定义一个Object类型的数据结构obj,它的key为target - numbers[i](比如数组第一项为2),value为索引。然后每次都看看obj[numbers[i]] 是否存在,如果存在,那我们就找到了这样的一组数据,返回当前索引以及obj[numbers[i]]。 + +代码: + +```javascript +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + var obj = {}; + + for(var i=0; i< nums.length;i++) { + const item = nums[i]; + if(obj[item] >= 0) { + return [obj[item], i] + } else { + obj[target - item] = i; + } + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0002._Add_Two_Numbers.md b/docs/Algorithm/Leetcode/JavaScript/0002._Add_Two_Numbers.md new file mode 100755 index 00000000..a37fc4c6 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0002._Add_Two_Numbers.md @@ -0,0 +1,74 @@ +# 002. Add Two Numbers + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/add-two-numbers/description/ + +> 内容描述 + +You 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. + +You may assume the two numbers do not contain any leading zero, except the number 0 itself. + + +#### Example: + + Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) + Output: 7 -> 0 -> 8 + Explanation: 342 + 465 = 807. + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(max(m,n))******- 空间复杂度: O(max(m,n))****** + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +let addTwoNumbers = function (l1,l2) { + let result = new ListNode(0), + node = result; + while(l1 || l2){ + let r = node.val, + i = (l1 && l1.val) || 0, + j = (l2 && l2.val) || 0, + sum = r + i + j, + m,n; + if(sum >= 10){ + m = 1; + n = sum - 10; + }else{ + m = 0; + n = sum; + } + l1 = l1 && l1.next; + l2 = l2 && l2.next; + node.val = n; + if(m || l1 || l2){ + node.next = new ListNode(m); + node = node.next + } + } + return result; +}; + +function ListNode(val) { + this.val = val; + this.next = null; +} +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0003._Longest_Substring_without_Repeating_Characters.md b/docs/Algorithm/Leetcode/JavaScript/0003._Longest_Substring_without_Repeating_Characters.md new file mode 100755 index 00000000..f1b2250c --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0003._Longest_Substring_without_Repeating_Characters.md @@ -0,0 +1,63 @@ +# 003. Longest Substring Without Repeating Characters + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-substring-without-repeating-characters/ + +> 内容描述 + +``` +Given a string, find the length of the longest substring without repeating characters. + +Example 1: + +Input: "abcabcbb" +Output: 3 +Explanation: The answer is "abc", with the length of 3. +Example 2: + +Input: "bbbbb" +Output: 1 +Explanation: The answer is "b", with the length of 1. +Example 3: + +Input: "pwwkew" +Output: 3 +Explanation: The answer is "wke", with the length of 3. + Note that the answer must be a substring, "pwke" is a subsequence and not a substring. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + +#### 暴力解法 + +代码: + +```javascript +/** + * @param {string} s + * @return {number} + */ +let lengthOfLongestSubstring = function (s) { + let result = 0; + for (let i = 0, len = s.length; i < len; i++) { + let set = new Set(); + set.add(s.charAt(i)); + for (let j = i + 1; j < len; j++) { + if (set.has(s.charAt(j))) { + break; + } + set.add(s.charAt(j)); + } + result = Math.max(result,set.size); + } + return result; +}; +``` diff --git a/docs/Algorithm/Leetcode/JavaScript/0007._Reverse_Integer.md b/docs/Algorithm/Leetcode/JavaScript/0007._Reverse_Integer.md new file mode 100755 index 00000000..772fb766 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0007._Reverse_Integer.md @@ -0,0 +1,59 @@ +# 007. Reverse Integer + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/reverse-integer/description/ + +> 内容描述 + +Given a 32-bit signed integer, reverse digits of an integer. + +#### Example 1: + + Input: 123 + Output: 321 + +#### Example 2: + + Input: -123 + Output: -321 + +#### Example 3: + + Input: 120 + Output: 21 + +#### Note: + 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. + +## 解题方案 + +> 思路 +******- 时间复杂度: O(1)******- 空间复杂度: O(N)****** + +#### 思路:通过将数字转成数组,然后翻转再转回数字 + +代码: + +```javascript +/** + * @param {number} x + * @return {number} + */ +var reverse = function(x) { + var num = parseInt(x.toString().split('').reverse().join('')) + if(num > Math.pow(2, 31)) { + return 0 + } + if(x < 0){ + return num*(-1) + } else { + return num + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0008._String_to_Integer.md b/docs/Algorithm/Leetcode/JavaScript/0008._String_to_Integer.md new file mode 100755 index 00000000..d618aa1c --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0008._String_to_Integer.md @@ -0,0 +1,94 @@ +# 008. String to Integer (atoi) + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/string-to-integer-atoi/description/ + +> 内容描述 + +``` +Implement atoi which converts a string to an integer. + +The 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. + +The 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. + +If 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. + +If no valid conversion could be performed, a zero value is returned. + +Note: + +Only the space character ' ' is considered as whitespace character. +Assume 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. + +``` +#### Example 1: +``` +Input: "42" +Output: 42 +``` + +#### Example 2: +``` +Input: " -42" +Output: -42 +Explanation: The first non-whitespace character is '-', which is the minus sign. + Then take as many numerical digits as possible, which gets 42. + +``` +#### Example 3: +``` +Input: "4193 with words" +Output: 4193 +Explanation: Conversion stops at digit '3' as the next character is not a numerical digit. +``` + +#### Example 4: +``` +Input: "words and 987" +Output: 0 +Explanation: The first non-whitespace character is 'w', which is not a numerical + digit or a +/- sign. Therefore no valid conversion could be performed. + +``` + +#### Example 5: +``` +Input: "-91283472332" +Output: -2147483648 +Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer. + Thefore INT_MIN (−231) is returned. + +``` +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(1)******- 空间复杂度: O(N)****** + +代码: + +```javascript +/** + * @param {string} str + * @return {number} + */ +var myAtoi = function(str) { + const INT_MAX = 2 ** 31 - 1; + const INT_MIN = -(2 ** 31); + str = str.match(/^\s*([-+]?\d+)/); + let strNum = str ? Number(str[0]) : 0; + if(strNum < INT_MIN ){ + return INT_MIN + }else if(strNum > INT_MAX){ + return INT_MAX + }else{ + return strNum + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0009._Palindrome_Number.md b/docs/Algorithm/Leetcode/JavaScript/0009._Palindrome_Number.md new file mode 100755 index 00000000..b0905df7 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0009._Palindrome_Number.md @@ -0,0 +1,72 @@ +# 9. Palindrome Number + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/palindrome-number/description/ + +> 内容描述 + +``` +Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward. + +Example 1: + +Input: 121 +Output: true +Example 2: + +Input: -121 +Output: false +Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome. +Example 3: + +Input: 10 +Output: false +Explanation: Reads 01 from right to left. Therefore it is not a palindrome. +Follow up: + +Coud you solve it without converting the integer to a string? +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(log2 N)******- 空间复杂度: O(1)****** + +* 不使用字符串,使用除法分别从首尾获得数字,最后对比是否相同 + +代码: + +```javascript +/** + * @param {number} x + * @return {boolean} + */ +var isPalindrome = function(x) { + if(x<0||x!==0&&x%10===0) + return false; + var reverse = 0; + while (x>reverse){ + reverse = reverse*10 +x%10; + x = Math.floor(x/10); + } + return reverse === x||Math.floor(reverse/10) === x; +}; +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +* 转化为字符串,reverse字符串 + +代码: + +```javascript +var isPalindrome = function(x) { + return x.toString().split('').reverse().join('')==x.toString()?true:false; +}; +``` diff --git a/docs/Algorithm/Leetcode/JavaScript/0011._Container_With_Most_Water.md b/docs/Algorithm/Leetcode/JavaScript/0011._Container_With_Most_Water.md new file mode 100755 index 00000000..8ae19c40 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0011._Container_With_Most_Water.md @@ -0,0 +1,71 @@ +# 11. Container With Most Water + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/container-with-most-water/description/ + +> 内容描述 + +``` +Given 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. + +Note: You may not slant the container and n is at least 2. +``` +![img](https://s3-lc-upload.s3.amazonaws.com/uploads/2018/07/17/question_11.jpg) +``` +The 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. +``` + +``` +Example: + +Input: [1,8,6,2,5,4,8,3,7] +Output: 49 +``` + +## 解题方案 + +> 对撞指针 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +* 从数组两层对向查找,直到找到最大乘积 + +代码: + +```javascript +var maxArea = function (list) { + let i = 0,j = list.length -1,result = 0; + while(i < j){ + result = Math.max(result ,(j - i ) * Math.min(list[i],list[j])) + if(list[i] < list[j]){ + i++; + }else{ + j--; + } + } + return result; +}; +``` + +> 暴力解法 +******- 时间复杂度: O(N²)******- 空间复杂度: O(1)****** + +代码 + +```javascript +var maxArea = function (list) { + let result = 0; + for(let i = 0,len = list.length; i难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/integer-to-roman/description/ + +> 内容描述 + +Roman numerals are represented by seven different symbols: `I`, `V`, `X`, `L`, `C`, `D` and `M`. +``` +Symbol Value +I 1 +V 5 +X 10 +L 50 +C 100 +D 500 +M 1000 +``` + +For 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`. + +Roman 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: + * `I` can be placed before `V` (5) and `X` (10) to make 4 and 9. + * `X` can be placed before `L` (50) and `C` (100) to make 40 and 90. + * `C` can be placed before `D` (500) and `M` (1000) to make 400 and 900. + +Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999. + +##### Example 1: +``` +Input: 3 +Output: "III" +``` + +##### Example 2: +``` +Input: 4 +Output: "IV" +``` + +##### Example 3: +``` +Input: 9 +Output: "IX" +``` + +##### Example 4: +``` +Input: 58 +Output: "LVIII" +Explanation: L = 50, V = 5, III = 3. +``` + +##### Example 5: +``` +Input: 1994 +Output: "MCMXCIV" +Explanation: M = 1000, CM = 900, XC = 90 and IV = 4. +``` + + +## 解题方案 + +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +代码: + +```javascript +let getMap = function () { + return { + 1:'I', + 4:'IV', + 5:'V', + 9:'IX', + 10:'X', + 40:'XL', + 50:'L', + 90:'XC', + 100:'C', + 400:'CD', + 500:'D', + 900:'CM', + 1000:'M' + }; +}; + +let match = function (result,num) { + let obj = getMap(); + while (result.num >= num){ + let n = parseInt(result.num /num); + result.num = result.num % num; + result.str = result.str + obj[num].repeat(n); + } +}; + +/** + * @param {number} num + * @return {string} + */ +var intToRoman = function (num) { + if(num < 1 || num > 3999) throw Error('error'); + let obj = getMap(); + if(num in obj) return obj[num]; + let result = { + str:'', + num + }; + match(result,1000); + match(result,900); + match(result,500); + match(result,400); + match(result,100); + match(result,90); + match(result,50); + match(result,40); + match(result,10); + match(result,9); + match(result,5); + match(result,4); + match(result,1); + + return result.str; +}; +``` diff --git a/docs/Algorithm/Leetcode/JavaScript/0013._Roman_To_Integer.md b/docs/Algorithm/Leetcode/JavaScript/0013._Roman_To_Integer.md new file mode 100755 index 00000000..ac257f90 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0013._Roman_To_Integer.md @@ -0,0 +1,106 @@ +# 13. Roman to Integer + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/roman-to-integer/description/ + +> 内容描述 + +Roman numerals are represented by seven different symbols: `I`, `V`, `X`, `L`, `C`, `D` and `M`. +``` +Symbol Value +I 1 +V 5 +X 10 +L 50 +C 100 +D 500 +M 1000 +``` + +For 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`. + +Roman 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: + * `I` can be placed before `V` (5) and `X` (10) to make 4 and 9. + * `X` can be placed before `L` (50) and `C` (100) to make 40 and 90. + * `C` can be placed before `D` (500) and `M` (1000) to make 400 and 900. + +Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from `1` to `3999`. + +##### Example 1: +``` +Input: "III" +Output: 3 +``` + +##### Example 2: +``` +Input: "IV" +Output: 4 +``` + +##### Example 3: +``` +Input: "IX" +Output: 9 +``` + +##### Example 4: +``` +Input: "LVIII" +Output: 58 +Explanation: L = 50, V= 5, III = 3. +``` + +##### Example 5: +``` +Input: "MCMXCIV" +Output: 1994 +Explanation: M = 1000, CM = 900, XC = 90 and IV = 4. +``` + + +## 解题方案 + +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +代码: + +```javascript +/** + * @param {string} roman + * @return {number} + */ +let romanToInt = function (roman) { + let result = 0; + let obj = { + 'I':1, + 'IV':4, + 'V':5, + 'IX':9, + 'X':10, + 'XL':40, + 'L':50, + 'XC':90, + 'C':100, + 'CD':400, + 'D':500, + 'CM':900, + 'M':1000 + }; + for(let len = roman.length,i = len -1;i>=0; i--){ + if(i - 1 >= 0 && `${roman.charAt(i - 1)}${roman.charAt(i)}` in obj){ + result = result + obj[`${roman.charAt(i - 1)}${roman.charAt(i)}`]; + i--; + }else{ + result = result + obj[roman.charAt(i)]; + } + } + return result; +}; +``` diff --git a/docs/Algorithm/Leetcode/JavaScript/0014._Longest_Common_Prefix.md b/docs/Algorithm/Leetcode/JavaScript/0014._Longest_Common_Prefix.md new file mode 100755 index 00000000..f90fb205 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0014._Longest_Common_Prefix.md @@ -0,0 +1,64 @@ +# 014. Longest Common Prefix + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum/description/ + +> 内容描述 + +Write a function to find the longest common prefix string amongst an array of strings. + +If there is no common prefix, return an empty string `""`. + +#### Example 1: +```markdown +Input: ["flower","flow","flight"] +Output: "fl" +``` + +#### Example 2: +```markdown +Input: ["dog","racecar","car"] +Output: "" +Explanation: There is no common prefix among the input strings. +``` + +##### Note: +All given inputs are in lowercase letters `a-z`. + +## 解题方案 + +> 思路 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +代码: + +```javascript +/** + * @param {string[]} strs + * @return {string} + */ +let longestCommonPrefix = function(strs) { + let firstStr = strs[0]; + let result =''; + if(!strs.length){ + return result; + } + for (let i = 0; i < firstStr.length; i++) { + for (let j = 1; j < strs.length; j++) { + if(firstStr.charAt(i) !== strs[j].charAt(i)){ + return result; + } + } + result = result + firstStr.charAt(i); + } + return result; + +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0015._Three_Sum.md b/docs/Algorithm/Leetcode/JavaScript/0015._Three_Sum.md new file mode 100755 index 00000000..cda51cca --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0015._Three_Sum.md @@ -0,0 +1,74 @@ +# 015. 3Sum + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/3sum/description/ + +> 内容描述 + +Given 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. + +#### Note: + + The solution set must not contain duplicate triplets. + +#### Example: + + Given array nums = [-1, 0, 1, 2, -1, -4], + + A solution set is: + [ + [-1, 0, 1], + [-1, -1, 2] + ] + + +## 解题方案 + +> 思路 +******- 时间复杂度: O(N²)******- 空间复杂度: O(N)****** + + +代码: + +```javascript +/** + * @param {number[]} nums + * @return {number[][]} + */ +let threeSum = function(nums, n = 0) { + let result = []; + let len = nums.length; + if(!len) return result; + // 对数组进行排序 + nums.sort((a,b)=>a-b); + for(let k = 0; k0 && nums[k-1] === nums[k]){ + continue; + } + let target = n - nums[k]; + let i = k + 1; + let j = len -1; + while(i target){ + j--; + }else{ + i++ + } + } + } + return result; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0016._3_Sum_Closest.md b/docs/Algorithm/Leetcode/JavaScript/0016._3_Sum_Closest.md new file mode 100755 index 00000000..a65c18e4 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0016._3_Sum_Closest.md @@ -0,0 +1,66 @@ +# 016. 3Sum Closest + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/3sum-closest/description/ + +> 内容描述 + +Given 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. + +#### Example: + + Given array nums = [-1, 2, 1, -4], and target = 1. + + The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). + +## 解题方案 + +> 思路 +******- 时间复杂度: O(N²)******- 空间复杂度: O(N)****** + + +代码: + +```javascript +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var threeSumClosest = function(nums, target) { + let result = Infinity; + let len = nums.length; + if(len <= 3){ + return nums.reduce((a,b)=>a+b,0); + } + nums.sort((a,b)=>a-b); + for(let k = 0; k0 && nums[k-1] === nums[k]){ + continue; + } + let i = k + 1; + let j = len -1; + while(i Math.abs(count - target)){ + result = count; + } + if(count > target){ + j-- + }else{ + i ++ + } + } + } + return result; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0017._Letter_Combinations_Of_A_Phone_Number.md b/docs/Algorithm/Leetcode/JavaScript/0017._Letter_Combinations_Of_A_Phone_Number.md new file mode 100755 index 00000000..6f9d9142 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0017._Letter_Combinations_Of_A_Phone_Number.md @@ -0,0 +1,110 @@ +# 017. Letter Combinations of a Phone Number + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/letter-combinations-of-a-phone-number/ + +> 内容描述 + +Given a string containing digits from `2-9` inclusive, return all possible letter combinations that the number could represent. + +A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters. + +![img](http://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Telephone-keypad2.svg/200px-Telephone-keypad2.svg.png) + +#### Example: + + Input: "23" + Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. + +#### Note: +Although the above answer is in lexicographical order, your answer could be in any order you want. + + +## 解题方案 + +> 递归版本 +******- 时间复杂度: O(N²)******- 空间复杂度: O(N)****** + +代码: + +```javascript +/** + * 递归函数 + * @param digits 传入的数字 + * @param index 当前是第几个数字 + * @param str 当前已拼装的字符串 + * @param list 结果集 + */ +let helper = function (digits, index, str, list) { + let map = { + 2: 'abc', + 3: 'def', + 4: 'ghi', + 5: 'jkl', + 6: 'mno', + 7: 'pqrs', + 8: 'tuv', + 9: 'wxyz' + }; + if (str.length === digits.length) { + list.push(str); + return false; + } + let strs = map[digits[index]]; + for (let i = 0; i < strs.length; i++) { + helper(digits, index + 1, str + strs.charAt(i), list) + } +}; +let letterCombinations = function (digits) { + let list = []; + if (digits) { + helper(digits, 0, '', list); + } + return list; +}; +``` + +> 非递归版本 +******- 时间复杂度: O(N²)******- 空间复杂度: O(N)****** + +```javascript +/** + * @param {string} digits + * @return {string[]} + */ +let letterCombinations = function (digits) { + let map = { + 2: 'abc', + 3: 'def', + 4: 'ghi', + 5: 'jkl', + 6: 'mno', + 7: 'pqrs', + 8: 'tuv', + 9: 'wxyz' + }; + let res = []; + for(let i = 0,len = digits.length; i难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum/description/ + +> 内容描述 + +``` +Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. + +An input string is valid if: + +Open brackets must be closed by the same type of brackets. +Open brackets must be closed in the correct order. +Note that an empty string is also considered valid. +``` + +#### Example 1: +```bash +Input: "()" +Output: true +``` + +#### Example 2: +```bash +Input: "()[]{}" +Output: true +``` + +#### Example 3: +```bash +Input: "(]" +Output: false +``` + +#### Example 4: +```bash +Input: "([)]" +Output: false +``` + +#### Example 5: +```bash +Input: "{[]}" +Output: true +``` + + + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +代码: + +```javascript +/** + * @param {string} s + * @return {boolean} + */ +var isValid = function(s) { + if(!s){ + return true; + } + let array = []; + for(let i = 0,len = s.length; i难度: Easy** + +> 原题连接 + +* https://leetcode.com/problems/merge-two-sorted-lists/ + +> 内容描述 + +``` +Merge 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. + +Example: + +Input: 1->2->4, 1->3->4 +Output: 1->1->2->3->4->4 + +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +代码: + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +var mergeTwoLists = function(l1, l2) { + if(l2 == null) return l1; + if(l1 == null) return l2; + if(l1.val 思路 2: 暴力解法 +> ******- 时间复杂度: O(2N)******- 空间复杂度: O(2N)****** + +由于是有序的链表,所以可以用数组中转的方式。把两个数组全部转成数组,再将两个数组合并再排序,最后再将两个数组转化为链表。 + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +var mergeTwoLists = function(l1, l2) { + if (!l1 && !l2) { + return null + } + let array1 = listNodeToArray(l1) + let array2 = listNodeToArray(l2) + let array = array1.concat(array2) + array.sort((a, b) => (a - b)) + + return arrayToListNode(array) +}; + + +function listNodeToArray (head) { + let array = [] + while (head) { + array.push(head.val) + head = head.next + } + return array +} + +function arrayToListNode(array) { + if(!array || !array.length) { + return null + } + + let node + let head = new ListNode(array[0]) + let pnode = head + + for(let i = 1; i < array.length; i++) { + node = new ListNode(array[i]) + pnode.next = node + pnode = node + } + + return head +} +``` + + + +> 思路 3: 单次循环遍历 +> ******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +let mergeTwoLists = function(l1, l2) { + if(!l1 || !l2){ + return (l1 || l2) + } + let result = new ListNode; + let preNode = result; + while (l1 || l2){ + let currentNode = new ListNode; + if(!l2){ + currentNode.val = l1.val; + l1 = l1.next; + }else if(!l1){ + currentNode.val = l2.val; + l2 = l2.next; + }else{ + if(l1.val < l2.val){ + currentNode.val = l1.val; + l1 = l1.next; + }else{ + currentNode.val = l2.val; + l2 = l2.next; + } + } + preNode.next = currentNode; + preNode = currentNode; + } + return result.next; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0022._Generate_Parentheses.md b/docs/Algorithm/Leetcode/JavaScript/0022._Generate_Parentheses.md new file mode 100755 index 00000000..0ac68ce2 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0022._Generate_Parentheses.md @@ -0,0 +1,70 @@ +# 022. generate-parentheses + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode-cn.com/problems/generate-parentheses/ + +> 内容描述 + +Given `n` pairs of parentheses, write a function to generate all combinations of well-formed parentheses. + +For example, given n = 3, a solution set is: + +```javascript + +[ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()" +] +``` + +## 解题方案 + +******- 时间复杂度: O(2N)******- 空间复杂度: O(N)****** + +代码: + +```javascript +/** + * 递归函数 + * @param left 剩余的左括号 + * @param right 剩余的又括号 + * @param str 当前已拼装括号的字符串 + * @param list 最终结果集 + */ +let helper = function (left,right,str,list) { + //当前右括号大于左括号 + if (left > right){ + return ; + } + //左括号,右括号均无剩余,作为终值填充 + if(left === 0 && right === 0){ + list.push(str); + return ; + } + //左括号有剩余 + if(left > 0){ + helper(left - 1,right,str + '(',list); + } + //右括号有剩余 + if(right > 0){ + helper(left,right - 1,str + ')',list); + } +}; +/** + * @param {number} n + * @return {string[]} + */ +let generateParenthesis = function(n) { + let list = []; + helper(n,n,'',list); + return list; +}; +``` diff --git a/docs/Algorithm/Leetcode/JavaScript/0027._Remove_Element.md b/docs/Algorithm/Leetcode/JavaScript/0027._Remove_Element.md new file mode 100755 index 00000000..b0dcfcff --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0027._Remove_Element.md @@ -0,0 +1,81 @@ +# 027. Remove Element + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/remove-element + +> 内容描述 + +Given an array nums and a value val, remove all instances of that value in-place and return the new length. + +Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. + +The order of elements can be changed. It doesn't matter what you leave beyond the new length. + +#### Example 1: + + Given nums = [3,2,2,3], val = 3, + + Your function should return length = 2, with the first two elements of nums being 2. + + It doesn't matter what you leave beyond the returned length. + +#### Example 2: + + Given nums = [0,1,2,2,3,0,4,2], val = 2, + + Your function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4. + + Note that the order of those five elements can be arbitrary. + + It doesn't matter what values are set beyond the returned length. + +#### Clarification: + +Confused why the returned value is an integer but your answer is an array? + +Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well. + +Internally you can think of this: + + // nums is passed in by reference. (i.e., without making a copy) + int len = removeElement(nums, val); + + // any modification to nums in your function would be known by the caller. + // using the length returned by your function, it prints the first len elements. + for (int i = 0; i < len; i++) { + print(nums[i]); + } + + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +保留两个指针 i 和 j,其中 i 是慢指针,j 是快指针。当 nums[j] 与给定的值相等时,递增 j 以跳过该元素。只要 nums[j] !== val,我们就复制 nums[j] 到 nums[i] 并同时递增两个索引。重复这一过程,直到 j 到达数组的末尾,该数组的新长度为 i。 + +代码: + +```javascript +/** + * @param {number[]} nums + * @param {number} val + * @return {number} + */ +var removeElement = function (nums,val) { + let j = 0; + for(let i = 0,len = nums.length; i难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/search-insert-position/ + +> 内容描述 + +``` +Given 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. + +You may assume no duplicates in the array. + +Example 1: + +Input: [1,3,5,6], 5 +Output: 2 +Example 2: + +Input: [1,3,5,6], 2 +Output: 1 +Example 3: + +Input: [1,3,5,6], 7 +Output: 4 +Example 4: + +Input: [1,3,5,6], 0 +Output: 0 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(logN)******- 空间复杂度: O(N)****** + +代码: + +```javascript +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +let searchInsert = function(nums, target) { + let lo = 0,high = nums.length-1; + while(lo<=high){ + let mid = Math.floor((high-lo)/2)+lo; + if(nums[mid]===target) + return mid; + if(nums[mid]>target) + high = mid-1; + else lo = mid+1; + } + return lo; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0058._Length_of_Last_Word.md b/docs/Algorithm/Leetcode/JavaScript/0058._Length_of_Last_Word.md new file mode 100755 index 00000000..4d10c40a --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0058._Length_of_Last_Word.md @@ -0,0 +1,49 @@ +# 58. Length of Last Word + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/length-of-last-word/description/ + +> 内容描述 + +``` +Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string. + +If the last word does not exist, return 0. + +Note: A word is defined as a character sequence consists of non-space characters only. + +Example: + +Input: "Hello World" + +Output: 5 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +* 将数组以空格分割,找到最后一个字符串输出长度 +* 注意以空格结尾以及输入空字符串 + +代码: + +```javascript +/** + * @param {string} s + * @return {number} + */ +var lengthOfLastWord = function(s) { + var temp = s.split(' ').filter(function (value) { + return value!=''; + }); + return temp.length>0?temp.pop().length:0; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0066._Plus_One.md b/docs/Algorithm/Leetcode/JavaScript/0066._Plus_One.md new file mode 100755 index 00000000..1f3c4375 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0066._Plus_One.md @@ -0,0 +1,60 @@ +# 66. Plus One + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/plus-one/description/ + +> 内容描述 + +``` +Given a non-empty array of digits representing a non-negative integer, plus one to the integer. + +The 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. + +You may assume the integer does not contain any leading zero, except the number 0 itself. + +Example 1: + +Input: [1,2,3] +Output: [1,2,4] +Explanation: The array represents the integer 123. +Example 2: + +Input: [4,3,2,1] +Output: [4,3,2,2] +Explanation: The array represents the integer 4321. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +* 如果数字小于9则不会发生进位,仅当前位置++即可 +* 因进位和plus one 都是数字加一 +* 数字大于9则进位与初始加一的处理方式一样 + +代码: + +```javascript +/** + * @param {number[]} digits + * @return {number[]} + */ +var plusOne = function(digits) { + for(var i=digits.length-1;i>=0;i--){ + if(digits[i]<9){ + digits[i]++; + return digits; + } + digits[i]=0; + } + digits.unshift(1); + return digits; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0067._Add_Binary.md b/docs/Algorithm/Leetcode/JavaScript/0067._Add_Binary.md new file mode 100755 index 00000000..fe9448a9 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0067._Add_Binary.md @@ -0,0 +1,65 @@ +# 67. Add Binary + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/add-binary/description/ + +> 内容描述 + +``` +Given two binary strings, return their sum (also a binary string). + +The input strings are both non-empty and contains only characters 1 or 0. + +Example 1: + +Input: a = "11", b = "1" +Output: "100" +Example 2: + +Input: a = "1010", b = "1011" +Output: "10101" +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +* 对于每一位数进行加法,如有进位单独计算 +* 注意需使用字符串进行存储,整型无法计算大型数据 + +代码: + +```javascript +/** + * @param {string} a + * @param {string} b + * @return {string} + */ +var addBinary = function(a, b) { + var tempA = a.split(''); + var tempB = b.split(''); + var result =[]; + var aLen=tempA.length,bLen=tempB.length; + var carry = 0; + while(aLen>0||bLen>0){ + var charA=0,charB=0; + if(aLen>0) + charA = tempA[--aLen]-0; + if(bLen>0) + charB = tempB[--bLen]-0; + var temp = charA + charB + carry; + carry = temp>1?1:0; + result.unshift(temp%2); + } + if(carry===1) + result.unshift(1); + return result.toString().replace(/,/g,''); +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0074._Search_a_2D_Matrix.md b/docs/Algorithm/Leetcode/JavaScript/0074._Search_a_2D_Matrix.md new file mode 100755 index 00000000..dc32ab31 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0074._Search_a_2D_Matrix.md @@ -0,0 +1,71 @@ +# 074. Search a 2D Matrix + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/search-a-2d-matrix/ + +> 内容描述 + +``` +Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: + +Integers in each row are sorted from left to right. +The first integer of each row is greater than the last integer of the previous row. +Example 1: + +Input: +matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] +] +target = 3 +Output: true +Example 2: + +Input: +matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] +] +target = 13 +Output: false +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +* 可以将这个二维数组看做一个数组,以二分法查找为最优算法 + +代码: + +```javascript +/** + * @param {number[][]} matrix + * @param {number} target + * @return {boolean} + */ +var searchMatrix = function(matrix, target) { + if(matrix.length===0) + return false; + var row=0,col=matrix[0].length-1; + while(row=0){ + if(matrix[row][col]===target) + return true; + else if(matrix[row][col]>target) + col--; + else + row++; + } + return false; +}; + +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0083._Remove_Duplicates_From_Sorted_List.md b/docs/Algorithm/Leetcode/JavaScript/0083._Remove_Duplicates_From_Sorted_List.md new file mode 100644 index 00000000..fe894d81 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0083._Remove_Duplicates_From_Sorted_List.md @@ -0,0 +1,148 @@ +# 083. Remove Duplicates From Sorted List + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* [https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/) + +> 内容描述 + + + +给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 + +**示例 1:** + +``` +输入: 1->1->2 +输出: 1->2 +``` + +**示例 2:** + +``` +输入: 1->1->2->3->3 +输出: 1->2->3 +``` + + + +## 解题方案 + +> 思路 1 +> **- 时间复杂度: O(N)** +> +> **- 空间复杂度: O(2N)** + +**暴力解法**:将链表转化为数组,对数组去重,然后数组转换为链表 + +> 执行用时 :**100 ms**, 在所有 JavaScript 提交中击败了**75.87%**的用户 +> +> 内存消耗 :**36.7 MB**, 在所有 JavaScript 提交中击败了**7.05%**的用户 + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var deleteDuplicates = function(head) { + if (!head) { + return null + } + let array = listNodeToArray(head) + return arrayToListNode([...new Set(array)]) +}; + + +function listNodeToArray (head) { + let array = [] + while (head) { + array.push(head.val) + head = head.next + } + return array +} + +function arrayToListNode(array) { + if(!array || !array.length) { + return null + } + + let node + let head = new ListNode(array[0]) + let pnode = head //pnode变量用来保存前一个节点 + + for(let i = 1; i < array.length; i++) { + node = new ListNode(array[i]) + pnode.next = node //将前一个节点的next指向当前节点 + pnode = node //将node赋值给pnode + } + + return head +} +``` + + +> 思路 2 +> **- 时间复杂度: O(N)** +> +> **- 空间复杂度: O(1)** + +**快慢指针**:每次循环,判断当前的值与下一个是否相等,如果**相等**,快指针(`head`)向前移动,慢指针(`slow`)原地不动;如果**不等**则把下一个节点连接到慢指针后,再将快慢指针都向前移动。 + +> 执行用时 :**92 ms**, 在所有 JavaScript 提交中击败了**91.01%**的用户 +> +> 内存消耗 :**35.7 MB**, 在所有 JavaScript 提交中击败了**69.46%**的用户 + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var deleteDuplicates = function(head) { + if (!head) { + return null + } + let slow = head + let result = slow + while (head) { + if (head.next && (head.val === head.next.val)) { + head = head.next + } else { + slow.next = head.next + slow = slow.next + head = head.next + } + } + return result +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0104._Maximum_Depth_of_Binary_Tree.md b/docs/Algorithm/Leetcode/JavaScript/0104._Maximum_Depth_of_Binary_Tree.md new file mode 100755 index 00000000..ee3e9d7a --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0104._Maximum_Depth_of_Binary_Tree.md @@ -0,0 +1,49 @@ +# 104. Maximum Depth of Binary Tree + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/maximum-depth-of-binary-tree/description/ + +> 内容描述 + +``` +Given a binary tree, find its maximum depth. + +The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. + +Note: A leaf is a node with no children. + +Example: + +Given binary tree [3,9,20,null,null,15,7], + + 3 + / \ + 9 20 + / \ + 15 7 +return its depth = 3. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(log2 N)******- 空间复杂度: O(N)****** + +* 这道题使用递归进行解决,因为对于树的每一个儿子的处理方法是一致的。 +* 将左儿子和右儿子中最大的数进行返回再加上当前的深度1即可解决。 + +代码: + +```javascript +var maxDepth = function(root) { + if(root===null||root === undefined) + return 0; + return Math.max(maxDepth(root.left),maxDepth(root.right))+1; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0141._Linked_List_Cycle.md b/docs/Algorithm/Leetcode/JavaScript/0141._Linked_List_Cycle.md new file mode 100755 index 00000000..d68add33 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0141._Linked_List_Cycle.md @@ -0,0 +1,109 @@ +# 0141. Linked List Cycle + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/linked-list-cycle/ + +> 内容描述 + +``` +Given a linked list, determine if it has a cycle in it. + +To 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. +``` + +**Example 1:** + +``` +Input: head = [3,2,0,-4], pos = 1 +Output: true +Explanation: There is a cycle in the linked list, where tail connects to the second node. +``` + +![img](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png) + +**Example 2:** + +``` +Input: head = [1,2], pos = 0 +Output: true +Explanation: There is a cycle in the linked list, where tail connects to the first node. +``` + +![img](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test2.png) + +**Example 3:** + +``` +Input: head = [1], pos = -1 +Output: false +Explanation: There is no cycle in the linked list. +``` + +![img](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test3.png) + + + +**Follow up:** + +Can you solve it using *O(1)* (i.e. constant) memory? + + + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +使用`快慢指针`的思路进行解题。就像两个运动员在同一个环形赛道上赛跑,如果一个运动员跑的快,一个跑得慢,最后两个运动员一定会相遇。 + +下面代码中的`fast`每次会走两步,而`slow`每次会走一步,如果`fast`没有`next`节点,自然没有环;如果`fast`等于`slow`说明二者相遇,最终为表明存在环。 + + + +#### 执行结果 + +执行用时 :**92 ms**, 在所有 JavaScript 提交中击败了94.16%的用户 + +内存消耗 :**36.6 MB**, 在所有 JavaScript 提交中击败了51.93% + + + +代码: + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ + +/** + * @param {ListNode} head + * @return {boolean} + */ +var hasCycle = function(head) { + if (head === null || head.next === null) { + return false + } + + let slow = head + let fast = head.next + + while (slow !== fast) { + if (fast === null || fast.next === null) { + return false + } + slow = slow.next + fast = fast.next.next + } + return true +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0146._LRU_Cache.md b/docs/Algorithm/Leetcode/JavaScript/0146._LRU_Cache.md new file mode 100644 index 00000000..87d87dc7 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0146._LRU_Cache.md @@ -0,0 +1,122 @@ +# 0146. LRU Cache + +**难度: Medium** + +## 刷题内容 + +> 原题链接 + +* https://leetcode.com/problems/lru-cache/ + +> 内容描述 + +Design 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`. + +`get(key)` - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. +`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. + +The cache is initialized with a **positive** capacity. + +**Follow up:** +Could you do both operations in **O(1)** time complexity? + +**Example:** + +``` +LRUCache cache = new LRUCache( 2 /* capacity */ ); + +cache.put(1, 1); +cache.put(2, 2); +cache.get(1); // returns 1 +cache.put(3, 3); // evicts key 2 +cache.get(2); // returns -1 (not found) +cache.put(4, 4); // evicts key 1 +cache.get(1); // returns -1 (not found) +cache.get(3); // returns 3 +cache.get(4); // returns 4 +``` + + + +## 解题方案 + +> 思路1 + +******- 时间复杂度: O(1)******- 空间复杂度: O(N)****** + +这是一道数据结构的考题。 + +简单的获取和插入,顺序不做考虑,所以数据结构用Object即可。 + +但是重要的考点——[LRU](https://baike.baidu.com/item/LRU/1269842?fr=aladdin),也就是删除最近没有使用的数据。所以想到用`队列`存在key列表: + +* 未超过存储上限时,每次`put`一个新数据时,向队列末尾插入当前`key` +* 每次`get`时,如果key存在,则将对应的key从的队列中,移到对末尾 +* 在超过存储上限时,如进行`put`操作,则将队列首位删除掉 + +> 执行用时 :492 ms, 在所有 JavaScript 提交中击败了35.29%的用户 +> +> 内存消耗 :59.7 MB, 在所有 JavaScript 提交中击败了16.36%的用户 + +```javascript +/** + * @param {number} capacity + */ +var LRUCache = function(capacity) { + this.limit = capacity || 2 + this.storage = {} + this.keyList = [] +}; + +/** + * @param {number} key + * @return {number} + */ +LRUCache.prototype.get = function(key) { + if (this.storage.hasOwnProperty(key)) { + let index = this.keyList.findIndex(k => k === key) + this.keyList.splice(index, 1) + this.keyList.push(key) + return this.storage[key] + } else { + return -1 + } +}; + +/** + * @param {number} key + * @param {number} value + * @return {void} + */ +LRUCache.prototype.put = function(key, value) { + // 判断容量 + if (this.keyList.length >= this.limit && !this.storage.hasOwnProperty(key)) { + this.deleteLRU() + } + + // 存储数据 + this.updateKeyList(key) + this.storage[key] = value +}; + +LRUCache.prototype.deleteLRU = function () { + delete this.storage[this.keyList.shift()] +} + +LRUCache.prototype.updateKeyList = function (key) { + if (this.storage.hasOwnProperty(key)) { + var index = this.keyList.findIndex(k => key === k) + this.keyList.splice(index, 1) + } + this.keyList.push(key) +} + +/** + * Your LRUCache object will be instantiated and called as such: + * var obj = new LRUCache(capacity) + * var param_1 = obj.get(key) + * obj.put(key,value) + */ + + +``` diff --git a/docs/Algorithm/Leetcode/JavaScript/0167._Two_Sum_II_-_Input_array_is_sorted.md b/docs/Algorithm/Leetcode/JavaScript/0167._Two_Sum_II_-_Input_array_is_sorted.md new file mode 100755 index 00000000..c5a722ff --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0167._Two_Sum_II_-_Input_array_is_sorted.md @@ -0,0 +1,58 @@ +# 167. Two Sum II - Input array is sorted + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/ + +> 内容描述 + +``` +Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number. + +The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. + +Note: + +Your returned answers (both index1 and index2) are not zero-based. +You may assume that each input would have exactly one solution and you may not use the same element twice. +Example: + +Input: numbers = [2,7,11,15], target = 9 +Output: [1,2] +Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(log2 N)******- 空间复杂度: O(n)****** + +* 使用贪心算法,用左右的数字开始加,如果数字大于目标right--,反之left++ + +代码: + +```javascript +/** + * @param {number[]} numbers + * @param {number} target + * @return {number[]} + */ +var twoSum = function(numbers, target) { + if(numbers.length===0) + return []; + var left = 0,right = numbers.length-1; + while(right>left){ + if(numbers[right]+numbers[left]>target) + right--; + else if(numbers[right]+numbers[left]难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/ + +> 内容描述 + +``` +Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number. + +The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. + +Note: + +Your returned answers (both index1 and index2) are not zero-based. +You may assume that each input would have exactly one solution and you may not use the same element twice. +Example: + +Input: numbers = [2,7,11,15], target = 9 +Output: [1,2] +Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +算法来源于知乎文章——[趣味算法思想](https://zhuanlan.zhihu.com/p/46223775) +* 由于数组是有序的,所以可以从两边向中间逐渐收敛地进行查找,好处在于避免了双重循环 +* 如果最两端的和小于目标数,则可以让左侧下标+1,然后重新进行运算比较 +* 如果最两端的和大于目标数,则可以让右侧下标-1,然后重新进行运算比较 + +代码: + +```javascript +/** + * @param {number[]} numbers + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + var number=[]; + var left = 0; + var right = nums.length - 1 ; + while(left < right ) { + if(nums[left] + nums[right] === target) { + return [left+1, right+1] + } else if(nums[left] + nums[right] > target ) { + right--; + } else { + left++; + } + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0203._Remove_Linked_List_Elements.md b/docs/Algorithm/Leetcode/JavaScript/0203._Remove_Linked_List_Elements.md new file mode 100644 index 00000000..ffce1f28 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0203._Remove_Linked_List_Elements.md @@ -0,0 +1,139 @@ +# 203. Remove Linked List Elements + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* [https://leetcode-cn.com/problems/remove-linked-list-elements/](https://leetcode-cn.com/problems/remove-linked-list-elements/) + +> 内容描述 + +删除链表中等于给定值 **val** 的所有节点。 + +**示例:** + +``` +输入: 1->2->6->3->4->5->6, val = 6 +输出: 1->2->3->4->5 +``` + + +## 解题方案 + +> 思路 1 +> **- 时间复杂度: O(3N)** +> +> **- 空间复杂度: O(2N)** + +**暴力解法**: + +1. 将链表转化为数组 +2. 对数组进行过滤 +3. 将过滤后的数组重新转化为数组 + +> 执行用时 :**160 ms**, 在所有 JavaScript 提交中击败了**10.71%**的用户 +> +> 内存消耗 :**38.4 MB**, 在所有 JavaScript 提交中击败了**5.13%**的用户 + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @param {number} val + * @return {ListNode} + */ +var removeElements = function(head, val) { + if (!head) { + return head + } + let array = listNodeToArray(head) + array = array.filter(i => (i !== val)) + return arrayToListNode(array) +}; + + +function listNodeToArray (head) { + let array = [] + while (head) { + array.push(head.val) + head = head.next + } + return array +} + +function arrayToListNode(array) { + if(!array || !array.length) { + return null + } + + let node + let head = new ListNode(array[0]) + let pnode = head //pnode变量用来保存前一个节点 + + for(let i = 1; i < array.length; i++) { + node = new ListNode(array[i]) + pnode.next = node //将前一个节点的next指向当前节点 + pnode = node //将node赋值给pnode + } + + return head +} +``` + + +> 思路 2 +> **- 时间复杂度: O(N)** +> +> **- 空间复杂度: O(1)** + +**快慢指针**: + +1. 快指针(`head`)每次循环都向前移动一个 +2. 慢指针(`slow`)只有在快指针当前节点的值不等于给定值时,才会向前移动,并在此之前将快指针当前节点指向慢指针的`next` + +> 执行用时 :**108 ms**, 在所有 JavaScript 提交中击败了**77.37%**的用户 +> +> 内存消耗 :**37.9 MB**, 在所有 JavaScript 提交中击败了**11.11%**的用户 + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @param {number} val + * @return {ListNode} + */ +var removeElements = function(head, val) { + if (!head) { + return head + } + let slow = new ListNode() + let result = slow + while (head) { + if (head.val !== val) { + slow.next = head + slow = slow.next + } else if (!head.next) { + slow.next = null + } + head = head.next + } + return result.next +}; + + +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0206._Reverse-Linked-List.md b/docs/Algorithm/Leetcode/JavaScript/0206._Reverse-Linked-List.md new file mode 100644 index 00000000..e4e4a7db --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0206._Reverse-Linked-List.md @@ -0,0 +1,120 @@ +# 206. Reverse Linked List(反转链表) + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* [https://leetcode-cn.com/problems/reverse-linked-list/](https://leetcode-cn.com/problems/reverse-linked-list/) + +> 内容描述 + +反转一个单链表。 + +**示例:** + +``` +输入: 1->2->3->4->5->NULL +输出: 5->4->3->2->1->NULL +``` + + +## 解题方案 + * 思路1 :暴力解法 + +将链表转化为数组,再利用数组重建数组。 + +> 思路 +> **- 时间复杂度: O(N²)** +> +> **- 空间复杂度: O(N)** + +> 执行用时 :**96 ms**, 在所有 JavaScript 提交中击败了**54.77%**的用户 +> +> 内存消耗 :**35.2 MB**, 在所有 JavaScript 提交中击败了**30.19%**的用户 + +```javascript + +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var reverseList = function(head) { + var nodeList = [] + if (!head) { + return head + } + while (head.next) { + nodeList.push(head) + head = head.next + } + nodeList.push(head) + nodeList.forEach((node, index) => { + if (nodeList[index - 1]) { + node.next = nodeList[index - 1] + } else { + node.next = null + } + }) + return nodeList[nodeList.length - 1] +}; + +``` + + + +* 思路2: 迭代法 + +使用`parentNode`缓存上次循环的结果,每次循环都生成两个新的`ListNode`用来翻转链表各个元素,一次迭代即可完成链表反转。 + +> 思路 +> **- 时间复杂度: O(N)** +> +> **- 空间复杂度: O(1)** + +> 执行用时 :**116 ms**, 在所有 JavaScript 提交中击败了**20.19%**的用户 +> +> 内存消耗 :**35.5 MB**, 在所有 JavaScript 提交中击败了**14.78%**的用户 + +```javascript +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var reverseList = function(head) { + if (!head) { + return head + } + let parentNode = null + while (head) { + let current = new ListNode(head.val) + current.next = parentNode + if (head.next) { + let next = new ListNode(head.next.val) + next.next = current + } else { + let next = null + return current + } + parentNode = current + head = head.next + } + return head +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0209._Minimum_Size_Subarray_Sum.md b/docs/Algorithm/Leetcode/JavaScript/0209._Minimum_Size_Subarray_Sum.md new file mode 100755 index 00000000..210419da --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0209._Minimum_Size_Subarray_Sum.md @@ -0,0 +1,80 @@ +# 209. Minimum Size Subarray Sum + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/minimum-size-subarray-sum/description/ + +> 内容描述 + +``` +Given 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. + +Example: + +Input: s = 7, nums = [2,3,1,2,4,3] +Output: 2 +Explanation: the subarray [4,3] has the minimal length under the problem constraint. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +算法来源于知乎文章——[趣味算法思想](https://zhuanlan.zhihu.com/p/46223775) + * 这里可以看到由于需要找连续的子数组,所以依旧可以设置两个指针,往同一方向移动。 + * 如果两个指针中间的值加起来>sum的时候,记录此时数组的长度,接着左指针移动,减小sum的值 ; + * 如果< sum的话,右指针移动扩大范围。 + * 最后返回最短的长度值。 + + + +代码: + +```javascript +/** + * @param {number} s + * @param {number[]} nums + * @return {number} + */ +var minSubArrayLen = function(s, nums) { + var left = 0; + var right = -1; // right 的起始位置很重要,这里选择-1 [left, right]这个区间刚开始是没有值的 + var tmpSum = 0; + var minLength; + + // 循环停止的条件是左指针小于长度 + while (left < nums.length - 1) { + if(tmpSum < s) { + // 这里要注意边界的处理,当右指针移动到最后一个元素的时候结束 + if(right >= nums.length -1) { + return minLength || 0; + } + right ++; + // 这里tmpSum的计算也很巧妙,直接用累加的方式,节省计算量 + tmpSum = tmpSum + nums[right] + } else { + var tmp = right - left + 1; + if(minLength) { + if(tmp < minLength) { + minLength = tmp; + } + } else { + minLength = tmp; + } + // 左边指针移动减少sum的值 + tmpSum = tmpSum - nums[left]; + left ++; + } + } + if(!minLength) { + return 0; + } + return minLength; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0258._Add_Digits.md b/docs/Algorithm/Leetcode/JavaScript/0258._Add_Digits.md new file mode 100755 index 00000000..785ee7ff --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0258._Add_Digits.md @@ -0,0 +1,56 @@ +# 258. Add Digits + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/add-digits/description/ + +> 内容描述 + +``` +Given a non-negative integer num, repeatedly add all its digits until the result has only one digit. + +Example: + +Input: 38 +Output: 2 +Explanation: The process is like: 3 + 8 = 11, 1 + 1 = 2. + Since 2 has only one digit, return it. + +Follow up: +Could you do it without any loop/recursion in O(1) runtime? +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(1)******- 空间复杂度: O(1)****** + +* 原理: +* 假设输入的数字是一个5位数字num,则num的各位分别为a、b、c、d、e +* 有如下关系:num = a * 10000 + b * 1000 + c * 100 + d * 10 + e +* 即:num = (a + b + c + d + e) + (a * 9999 + b * 999 + c * 99 + d * 9) +* 因为 a * 9999 + b * 999 + c * 99 + d * 9 一定可以被9整除,因此num模除9的结果与 a + b + c + d + e 模除9的结果是一样的。 +* 对数字 a + b + c + d + e 反复执行同类操作,最后的结果就是一个 1-9 的数字加上一串数字,最左边的数字是 1-9 之间的,右侧的数字永远都是可以被9整除的。 +* 这道题最后的目标,就是不断将各位相加,相加到最后,当结果小于10时返回。因为最后结果在1-9之间,得到9之后将不会再对各位进行相加,因此不会出现结果为0的情况。 +* 因为 (x + y) % z = (x % z + y % z) % z,又因为 x % z % z = x % z,因此结果为 (num - 1) % 9 + 1,只模除9一次,并将模除后的结果加一返回。 + +代码: + +```javascript +/** + * @param {number} num + * @return {number} + */ +var addDigits = function(num) { + if(num==0) + return num; + if(num%9==0) + return 9; + else return num%9; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0402._Remove_K_Digits.md b/docs/Algorithm/Leetcode/JavaScript/0402._Remove_K_Digits.md new file mode 100755 index 00000000..3dbff985 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0402._Remove_K_Digits.md @@ -0,0 +1,67 @@ +# 402. Remove K Digits + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/remove-k-digits/description/ + +> 内容描述 + +``` +Given a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible. + +Note: +The length of num is less than 10002 and will be ≥ k. +The given num does not contain any leading zero. +Example 1: + +Input: num = "1432219", k = 3 +Output: "1219" +Explanation: Remove the three digits 4, 3, and 2 to form the new number 1219 which is the smallest. +Example 2: + +Input: num = "10200", k = 1 +Output: "200" +Explanation: Remove the leading 1 and the number is 200. Note that the output must not contain leading zeroes. +Example 3: + +Input: num = "10", k = 2 +Output: "0" +Explanation: Remove all the digits from the number and it is left with nothing which is 0. + +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +* 使用栈的思路 +* 如果n是num的长度,我们要去除k个,那么需要剩下n-k个数,定义一个result数组用于保存剩下的字符,与result中最后一个字符相比,比它小, +* 栈中最后一个字符出栈,该字符进栈,否则该字符直接进栈。值得注意的是在删除k个数之后,若剩下的数前面有0,应该去掉。 + +代码: + +```javascript +/** + * @param {string} num + * @param {number} k + * @return {string} + */ +var removeKdigits = function(num, k) { + let stack = [], numDigits = num.length; + for (let i = 0; i < numDigits; i++) { + while(k > 0 && stack.length && stack[stack.length - 1] > num[i]) { + stack.pop(); + k--; + } + stack.push(num[i]); + } + stack = k > 0 ? stack.slice(0, -k) : stack; + return stack.join('').replace(/^0+/, '') || '0'; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0485._Max_Consecutive_Ones.md b/docs/Algorithm/Leetcode/JavaScript/0485._Max_Consecutive_Ones.md new file mode 100755 index 00000000..535fd666 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0485._Max_Consecutive_Ones.md @@ -0,0 +1,53 @@ +# 485. Max Consecutive Ones + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/max-consecutive-ones/description/ + +> 内容描述 + +``` +Given a binary array, find the maximum number of consecutive 1s in this array. + +Example 1: +Input: [1,1,0,1,1,1] +Output: 3 +Explanation: The first two digits or the last three digits are consecutive 1s. + The maximum number of consecutive 1s is 3. +Note: + +The input array will only contain 0 and 1. +The length of input array is a positive integer and will not exceed 10,000 + +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +* 使用temp保存每个0之间的差值 +* 找出最大的差值即可 + +代码: + +```javascript +/** + * @param {number[]} nums + * @return {number} + */ +var findMaxConsecutiveOnes = function(nums) { + var max = 0,temp = 0; + for(var i =0;i难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/minimum-time-difference/description/ + +> 内容描述 + +``` +Given 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. + +Example 1: +Input: ["23:59","00:00"] +Output: 1 + +Note: +The number of time points in the given list is at least 2 and won't exceed 20000. +The input time is legal and ranges from 00:00 to 23:59. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +* 将所有时间转换成分钟数,然后进行sort排序 +* 计算两个数之间的差值,找出最小差值即可 +* 不要忘记第一个时间与最后一个时间相比较 + +代码: + +```javascript +/** + * @param {string[]} timePoints + * @return {number} + */ +var findMinDifference = function(timePoints) { + var dayTime = 24*60; + var minTime = 24*60; + var temp = timePoints.map(function (value) { + var t = value.split(':'); + return parseInt(t[0])*60+parseInt(t[1]); + }); + temp.sort(function (a,b) { + return a-b; + }); + for(var i =0;i(dayTime/2)){ + diff = Math.abs(temp[f]-(temp[b]+dayTime)); + minTime = diff难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/boats-to-save-people/description/ + +> 内容描述 + +``` +The i-th person has weight people[i], and each boat can carry a maximum weight of limit. + +Each boat carries at most 2 people at the same time, provided the sum of the weight of those people is at most limit. + +Return the minimum number of boats to carry every given person. (It is guaranteed each person can be carried by a boat.) + + + +Example 1: + +Input: people = [1,2], limit = 3 +Output: 1 +Explanation: 1 boat (1, 2) +Example 2: + +Input: people = [3,2,2,1], limit = 3 +Output: 3 +Explanation: 3 boats (1, 2), (2) and (3) +Example 3: + +Input: people = [3,5,3,4], limit = 5 +Output: 4 +Explanation: 4 boats (3), (3), (4), (5) +Note: + +1 <= people.length <= 50000 +1 <= people[i] <= limit <= 30000 + +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N logN)******- 空间复杂度: O(N)****** + +* 使用贪心算法,将数组进行排序之后进行处理 + +代码: + +```javascript +/** + * @param {number[]} people + * @param {number} limit + * @return {number} + */ +var numRescueBoats = function(people, limit) { + people.sort(function (a,b) { return a-b }); + var num=0; + for(var left = 0,right = people.length-1;right-left>=0;right--){ + if(people[left]+people[right]<=limit) + left++; + num++; + } + return num; +}; +``` + diff --git a/docs/Algorithm/Leetcode/JavaScript/0997._Find_The_Town_Judge.md b/docs/Algorithm/Leetcode/JavaScript/0997._Find_The_Town_Judge.md new file mode 100644 index 00000000..36d41cf7 --- /dev/null +++ b/docs/Algorithm/Leetcode/JavaScript/0997._Find_The_Town_Judge.md @@ -0,0 +1,121 @@ +# 997. Find The Town Judge + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode-cn.com/problems/find-the-town-judge/ + +> 内容描述 + +在一个小镇里,按从 1 到 N 标记了 N 个人。传言称,这些人中有一个是小镇上的秘密法官。 + +如果小镇的法官真的存在,那么: + +1. 小镇的法官不相信任何人。 +2. 每个人(除了小镇法官外)都信任小镇的法官。 +3. 只有一个人同时满足属性 1 和属性 2 。 + +给定数组 trust,该数组由信任对 trust[i] = [a, b] 组成,表示标记为 a 的人信任标记为 b 的人。 + +如果小镇存在秘密法官并且可以确定他的身份,请返回该法官的标记。否则,返回 -1。 + +**示例 1:** + +``` +输入:N = 2, trust = [[1,2]] +输出:2 +``` + +**示例 2:** + +``` +输入:N = 3, trust = [[1,3],[2,3]] +输出:3 +``` + +**示例 3:** + +``` +输入:N = 3, trust = [[1,3],[2,3],[3,1]] +输出:-1 +``` + +**示例 4:** + +``` +输入:N = 3, trust = [[1,2],[2,3]] +输出:-1 +``` + +**示例 5:** + +``` +输入:N = 4, trust = [[1,3],[1,4],[2,3],[2,4],[4,3]] +输出:3 +``` + + **提示:** + +1. `1 <= N <= 1000` +2. `trust.length <= 10000` +3. `trust[i]` 是完全不同的 +4. `trust[i][0] != trust[i][1]` +5. `1 <= trust[i][0], trust[i][1] <= N` + + + +## 解题方案 + +> 思路 +> **- 时间复杂度: O(N)** +> +> **- 空间复杂度: O(N)** + +利用`trustedMap`来存储“被信任者”的列表,数组下标代表村民的“标记”,数组元素的值代表“被多少人信任”。 + +利用`trustOtherMap`来存储“村民信任列表”,数组下标代表村民的“标记”,数组元素的值代表该村民“信任几个人”。 + +根据题目,`每个人(除了小镇法官外)都信任小镇的法官。`所以`trustedMap`中值为`N-1`的那个元素下标即是法官;但是`小镇的法官不相信任何人。`所以上一步得到的标记所在`trustOtherMap`的值一定是空。 + +> 执行用时 :**136 ms**, 在所有 JavaScript 提交中击败了**95.77%**的用户 +> +> 内存消耗 :**43.4 MB**, 在所有 JavaScript 提交中击败了**68.00%**的用户 + +代码: + +```javascript +/** + * @param {number} N + * @param {number[][]} trust + * @return {number} + */ +var findJudge = function(N, trust) { + let trustedMap = [] + let trustOtherMap = [] + if (N === 1 && trust.length === 0) { + return 1 + } + trust.forEach(([person, trustedPerson]) => { + if (trustedMap[trustedPerson]) { + trustedMap[trustedPerson]++ + } else { + trustedMap[trustedPerson] = 1 + } + if (trustOtherMap[person]) { + trustOtherMap[person]++ + } else { + trustOtherMap[person] = 1 + } + }) + const trustedPerson = trustedMap.findIndex(i => i === (N - 1)) + if (trustedPerson !== -1 && !trustOtherMap[trustedPerson]) { + return trustedPerson + } else { + return -1 + } +}; +``` + diff --git a/docs/Algorithm/Leetcode/Python/001._two_sum.ipynb b/docs/Algorithm/Leetcode/Python/001._two_sum.ipynb new file mode 100644 index 00000000..c1fc51bf --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/001._two_sum.ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 1. Two Sum 两数之和\n", + "\n", + "## 题目:\n", + "\n", + " - https://leetcode.com/problems/two-sum/\n", + " - https://leetcode-cn.com/problems/two-sum/description/\n", + "\n", + "```\n", + "给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。\n", + "\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", + "## 难度:Easy\n", + "\n", + "这个题目略微有点简单,我们只要注意的是,同样的元素不能被重复利用两次。\n", + "\n", + "还有就是思考,是不是我们可以使用一次循环就能够找到这两个数呢?\n", + "\n", + "接下来我们看一下如何解决这个问题。\n", + "\n", + "> 思路 1\n", + "\n", + " - 简单判断一下,是否两个数都在 list 中,以及判断两个数不是重复利用一个元素即可。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2]\n" + ] + } + ], + "source": [ + "class Solution(object):\n", + " def twoSum(self, nums, target):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :type target: int\n", + " :rtype: List[int]\n", + " \"\"\"\n", + " # 循环名为 nums 的 list\n", + " for num_one in nums:\n", + " # 判断 target 减去 num_one 是否仍在我们的 nums list 中,另一个条件是这两个数不是同一个元素\n", + " if target - num_one in nums and num_one is not target-num_one:\n", + " # 返回两个数对应的 index\n", + " return [nums.index(num_one), nums.index(target - num_one)]\n", + " \n", + "nums = [4, 3, 5, 15]\n", + "target = 8\n", + "s = Solution()\n", + "print(s.twoSum(nums, target))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 其实我们上一个解决方案已经是弄的一个 for 循环了,这次我们换一个思路。\n", + " - 可以用 $O(n^2)$ 的循环(lookup)\n", + " - 其实也可以牺牲空间换取时间,异常聪明的 AC 解法\n", + " \n", + "```\n", + " 2 7 11 15\n", + " 不存在 存在之中 \n", + "lookup {2:0} [0, 1]\n", + "```\n", + "大体思路如下:\n", + "\n", + " - 建立字典 lookup 存放第一个数字,并存放该数字的 index\n", + " - 判断 lookup 中是否存在: target - 当前数字, 则表面 当前值和 lookup中的值加和为 target\n", + " - 如果存在,则返回: target - 当前数字 的 index 和 当前值的 index" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2]\n" + ] + } + ], + "source": [ + "class 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", + " lookup = {}\n", + " # 使用 enumerate 语法,返回的是每一个元素及其对应的 index\n", + " for i, num in enumerate(nums):\n", + " if target - num in lookup:\n", + " return [lookup[target - num],i]\n", + " lookup[num] = i\n", + " return []\n", + " \n", + "nums = [4, 3, 5, 15]\n", + "target = 8\n", + "s = Solution()\n", + "print(s.twoSum(nums, target))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3\n", + "\n", + " - 对于 dict ,也就是其他语言的 map,判断一个元素在不在容器中,list 要遍历,而 set 和 dict 直接根据哈希算出,不需要遍历\n", + " - 我们可以仿照上面的代码,但是换个简单的写法。\n", + " - 对于字典的这种方式,如果我们只是判断 i 以及 target - i 是不是相等,这样是错误的,如果两个元素相同,但是不是同一个元素,那就会出错了。\n", + " \n", + "比如,我们先看一下错误的版本:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def twoSum(self, nums, target):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :type target: int\n", + " :rtype: List[int]\n", + " \"\"\"\n", + " dict1 = {}\n", + " for k, i in enumerate(nums):\n", + " dict1[i] = k\n", + " if target - i in dict1 and i is not target - i:\n", + " return [dict1[target - i], dict1[i]]\n", + "\n", + "nums = [3, 3]\n", + "target = 6\n", + "s = Solution()\n", + "print(s.twoSum(nums, target))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "上面的代码是存在问题的,对于相同的元素 [3, 3], target =6, 就得到了 None ,按理说,应该得到 [0, 1] 的。所以,这地方的判断是错误的。\n", + "\n", + " - 对于字典的那种方式,就只能索引为 key,数据为value,只是这样一来,判断在或者不在,还是多了一层循环\n", + " \n", + "下面的版本是正确的版本:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1]\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def twoSum(self, nums, target):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :type target: int\n", + " :rtype: List[int]\n", + " \"\"\"\n", + " for k, i in enumerate(nums):\n", + " if target - i in nums[k + 1:]:\n", + " return [k, nums[k + 1:].index(target - i) + k + 1]\n", + "\n", + "nums = [3, 3]\n", + "target = 6\n", + "s = Solution()\n", + "print(s.twoSum(nums, target)) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 小结\n", + "\n", + "应该还有更加好的解法,大佬们积极贡献自己的解法哈。一起为好的工作,好的未来,加油。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/001._two_sum.md b/docs/Algorithm/Leetcode/Python/001._two_sum.md new file mode 100644 index 00000000..d9368ff3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/001._two_sum.md @@ -0,0 +1,53 @@ +# 1. Two Sum 两数之和 + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum +* https://leetcode-cn.com/problems/two-sum/description + +> 内容描述 + +``` +给定 nums = [2, 7, 11, 15], target = 9 + +因为 nums[0] + nums[1] = 2 + 7 = 9 +所以返回 [0, 1] +``` + +## 解题方案 + +> 思路 1 + +可以用O(n^2) loop + +但是也可以牺牲空间换取时间,异常聪明的AC解法 + +``` + 2 7 11 15 + 不存在 存在之中 +lookup {2:0} [0,1] +``` + +* 建立字典 lookup 存放第一个数字,并存放该数字的 index +* 判断 lookup 种是否存在: `target - 当前数字`, 则表面 当前值和 lookup中的值加和为 target. +* 如果存在,则返回: `target - 当前数字` 的 index 和 当前值的 index + +```python +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + lookup = {} + for i, num in enumerate(nums): + if target - num in lookup: + return [lookup[target - num],i] + lookup[num] = i + return [] +``` diff --git a/docs/Algorithm/Leetcode/Python/002._add_two_numbers.ipynb b/docs/Algorithm/Leetcode/Python/002._add_two_numbers.ipynb new file mode 100644 index 00000000..7971d420 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/002._add_two_numbers.ipynb @@ -0,0 +1,245 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2.Add Two Numbers\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容:\n", + "\n", + "> 原题链接:\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/add-two-numbers/description/\n", + " - 英文:https://leetcode.com/problems/add-two-numbers/\n", + "\n", + "> 内容描述:\n", + "\n", + "给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。\n", + "\n", + "你可以假设除了数字 0 之外,这两个数字都不会以零开头。\n", + "\n", + "示例:\n", + "```\n", + "输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)\n", + "输出:7 -> 0 -> 8\n", + "原因:342 + 465 = 807\n", + "```\n", + "\n", + "## 解法方案\n", + "\n", + "由于两数相加可能会出现进位,所以加法我们谁都会算,但是要着重注意的一点是,要考虑上一位的进位,并且传递给下一位计算时的进位。\n", + "\n", + "> 思路 1\n", + "\n", + "我们先构建一个空的头结点不动,然后尾结点从头结点开始向后不断生成新的结点。遍历两个链表的公共部分,每次相加相应位数字和进位,分配到结果的链表中。公共部分遍历完后再确定长的链表剩余的部分,同样的方式遍历完。\n", + "\n", + " - 需要注意的是遍历时每次都要更新进位,不断计算和时有没有发生进位,以防止之前数据的污染。\n", + " - 对于 python 来说,需要新的变量做游标来遍历两个链表,不能直接用形参,否则我们会修改原链表。\n", + " - 注意最后可能的进位。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "0\n", + "8\n", + "None\n" + ] + } + ], + "source": [ + "# Definition for singly-linked list.\n", + "class ListNode:\n", + " def __init__(self, x):\n", + " self.val = x\n", + " self.next = None\n", + "\n", + "class Solution: \n", + " def addTwoNumbers(self, l1, l2):\n", + " \"\"\"\n", + " :type l1: ListNode\n", + " :type l2: ListNode\n", + " :rtype: ListNode\n", + " \"\"\"\n", + " # 用 p1, p2 赋值为 l1 和 l2 ,以防止我们的操作改变原链表\n", + " p1, p2 = l1, l2\n", + " # 创建一个空链表用来返回结果,分别有头结点和尾结点\n", + " head = ListNode(0)\n", + " tail = head\n", + " # carry 表示进位值\n", + " carry = 0\n", + " # 处理两个链表的公共部分,也就是两个链表都不为空的部分\n", + " while p1 and p2:\n", + " # 计算当前位相加的和\n", + " num = p1.val + p2.val + carry\n", + " # 大于 9 ,应该向前进一位\n", + " if num > 9:\n", + " num -= 10\n", + " carry = 1\n", + " else:\n", + " carry = 0\n", + " # 添加结点\n", + " tail.next = ListNode(num)\n", + " # 尾结点向后移动\n", + " tail = tail.next\n", + " # 移动两条链表的公共部分\n", + " p1 = p1.next\n", + " p2 = p2.next\n", + " # 取长链表剩余的部分,也就是未参与上面计算的部分\n", + " if p2:\n", + " # 如果 p2 较长,将 p2 剩余的部分赋值给 p1 ,我们只需要处理 p1 就行了\n", + " p1 = p2\n", + " # 接下来,处理长链表剩余分部分\n", + " while p1:\n", + " # 最近的一位,我们要考虑一下,是否有进位\n", + " num = p1.val + carry\n", + " if num > 9:\n", + " num -= 10\n", + " carry = 1\n", + " else:\n", + " carry = 0\n", + " # 添加结点\n", + " tail.next = ListNode(num)\n", + " tail = tail.next\n", + " \n", + " # 移动我们处理的链表\n", + " p1 = p1.next\n", + " # 如果最后仍然有进位,我们需要再分配一个结点\n", + " if carry:\n", + " # 创建一个 val 为 1 的 ListNode 结点,然后将 tail 向后移动一位\n", + " tail.next = ListNode(1)\n", + " tail = tail.next\n", + " # 将所有的加和及进位都处理完成了,现在我们将链表收尾\n", + " tail.next = None\n", + " # 将 链表的头结点返回\n", + " return head.next # 去除掉我们初始化为 0 的头结点\n", + "\n", + "la = ListNode(2)\n", + "la.next = ListNode(4)\n", + "la.next.next = ListNode(3)\n", + "\n", + "lb = ListNode(5)\n", + "lb.next = ListNode(6)\n", + "lb.next.next = ListNode(4)\n", + "\n", + "s = Solution()\n", + "ss = s.addTwoNumbers(la, lb)\n", + "print(ss.val)\n", + "print(ss.next.val)\n", + "print(ss.next.next.val)\n", + "print(ss.next.next.next) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "因此,这个地方我们可以考虑使用递归来求解,具体可以分为以下情况:\n", + "\n", + " - 当两个链表均不为空时,计算两个节点值与上一位进位的和 sum,取 sum 的个位数构建新的节点,更新进位为 sum 的十位数,令本节点的 next 指针指向下一位求和返回的节点。\n", + " - 当两个链表其中一个为空时,计算不为空的节点值与上一位进位的和 sum,更新进位为 sum 的十位数。若进位不为 0 ,取 sum 的个位数构建新节点,令本节点的 next 指针指向下一位求和返回的节点,注意只传递不为空的链表;若进位为 0,则直接更新不为空节点的值为 sum,此时此链表之后的所有高位值都不会更新,因此返回此节点。\n", + " - 若两个链表都为空,判断进位是否为 0。若进位为 0,直接返回 NULL;否则构建值为进位值的新节点,并返回此节点。\n", + " \n", + "> 思路 2\n", + "\n", + " - 跟 plus One ,add Binary 玩的同一个花样,但是相对上个思路来说,更加简单和简洁。\n", + " - 使用递归调用简化算法" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "0\n", + "8\n", + "None\n" + ] + } + ], + "source": [ + "# Definition for singly-linked list.\n", + "class ListNode:\n", + " def __init__(self, x):\n", + " self.val = x\n", + " self.next = None\n", + "\n", + "class Solution(object):\n", + " def addTwoNumbers(self, l1, l2):\n", + " \"\"\"\n", + " :type l1: ListNode\n", + " :type l2: ListNode\n", + " :rtype: ListNode\n", + " \"\"\"\n", + " # 特殊情况\n", + " if l1 == None:\n", + " return l2\n", + " if l2 == None:\n", + " return l1\n", + " # 如果 相加 小于 10 ,不需要进位\n", + " if l1.val + l2.val < 10:\n", + " l3 = ListNode(l1.val + l2.val)\n", + " l3.next = self.addTwoNumbers(l1.next, l2.next)\n", + " # 相加大于等于 10,需要进位\n", + " elif l1.val + l2.val >= 10:\n", + " l3 = ListNode(l1.val + l2.val - 10)\n", + " tmp = ListNode(1)\n", + " tmp.next = None\n", + " # 递归调用\n", + " l3.next = self.addTwoNumbers(l1.next, self.addTwoNumbers(l2.next ,tmp))\n", + " return l3\n", + " \n", + "la = ListNode(2)\n", + "la.next = ListNode(4)\n", + "la.next.next = ListNode(3)\n", + "\n", + "lb = ListNode(5)\n", + "lb.next = ListNode(6)\n", + "lb.next.next = ListNode(4)\n", + "\n", + "s = Solution()\n", + "ss = s.addTwoNumbers(la, lb)\n", + "print(ss.val)\n", + "print(ss.next.val)\n", + "print(ss.next.next.val)\n", + "print(ss.next.next.next)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/002._add_two_numbers.md b/docs/Algorithm/Leetcode/Python/002._add_two_numbers.md new file mode 100644 index 00000000..a225a341 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/002._add_two_numbers.md @@ -0,0 +1,90 @@ +# 2. Add Two Numbers +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/add-two-numbers/description/ + +> 内容描述 + +``` +You 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. + +You may assume the two numbers do not contain any leading zero, except the number 0 itself. + +Example: + +Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) +Output: 7 -> 0 -> 8 +Explanation: 342 + 465 = 807. +``` + +## 解题方案 + +> 思路 1 + +全部变成数字做加法再换回去呗,这多暴力,爽! + +```python +class Solution(object): + def addTwoNumbers(self, l1, l2): + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ + if not l1: + return l2 + if not l2: + return l1 + + val1, val2 = [l1.val], [l2.val] + while l1.next: + val1.append(l1.next.val) + l1 = l1.next + while l2.next: + val2.append(l2.next.val) + l2 = l2.next + + num1 = ''.join([str(i) for i in val1[::-1]]) + num2 = ''.join([str(i) for i in val2[::-1]]) + + tmp = str(int(num1) + int(num2))[::-1] + res = ListNode(tmp[0]) + run_res = res + for i in range(1, len(tmp)): + run_res.next = ListNode(tmp[i]) + run_res = run_res.next + return res +``` +> 思路 2 + +可以使用递归,每次算一位的相加 + + +```python +class Solution(object): + def addTwoNumbers(self, l1, l2): + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ + if not l1: + return l2 + if not l2: + return l1 + + if l1.val + l2.val < 10: + l3 = ListNode(l1.val + l2.val) + l3.next = self.addTwoNumbers(l1.next, l2.next) + + else: + l3 = ListNode(l1.val + l2.val - 10) + tmp = ListNode(1) + tmp.next = None + l3.next = self.addTwoNumbers(l1.next, self.addTwoNumbers(l2.next ,tmp)) + return l3 +``` diff --git a/docs/Algorithm/Leetcode/Python/003._longest_substring_without_repeating_characters.md b/docs/Algorithm/Leetcode/Python/003._longest_substring_without_repeating_characters.md new file mode 100644 index 00000000..8b8ef18e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/003._longest_substring_without_repeating_characters.md @@ -0,0 +1,84 @@ +### 3. Longest Substring Without Repeating Characters + + +题目: + + + +难度: + +Medium + + + +思路 + +粗一看是dp,细一看是greedy + +我们先从第一个字符开始,只要碰到已经出现过的字符我们就必须从之前出现该字符的index开始重新往后看。 + +例如‘xyzxlkjh’,当看到第二个‘x’时我们就应该从y开始重新往后看了。 + +那么怎么判断字符已经出现过了呢?我们使用一个hashmap,将每一个已经阅读过的字符作为键,而它的值就是它在原字符串中的index,如果我们现在的字符不在hashmap里面我们就把它加进hashmap中去,因此,只要目前的这个字符在该hashmap中的值大于等于了这一轮字符串的首字符,就说明它已经出现过了,我们就将首字符的index加1,即从后一位又重新开始读,然后比较目前的子串长度与之前的最大长度,取大者。 + +### 程序变量解释 + +- l(字母L) 代表目前最大子串的长度 +- start 是这一轮未重复子串首字母的index +- maps 放置每一个字符的index,如果maps.get(s[i], -1)大于等于start的话,就说明字符重复了,此时就要重置 l(字母L) 和start的值了, + + + +```python +class Solution(object): + def lengthOfLongestSubstring(self, s): + """ + :type s: str + :rtype: int + + """ + l, start, n = 0, 0, len(s) + maps = {} + for i in range(n): + start = max(start, maps.get(s[i], -1)+1) + l = max(l, i - start+1) + maps[s[i]] = i + return l +``` + +```python +class Solution(object): + def lengthOfLongestSubstring(self, s): + """ + :type s: str + :rtype: int + """ + maps = {} + begin, end, counter, d = 0, 0, 0, 0 + while end < len(s): + if s[end] in maps: + maps[s[end]] += 1 + else: + maps[s[end]] = 1 + if maps[s[end]] > 1: + counter += 1 + end += 1 + while counter > 0: + if maps[s[begin]] > 1: + counter -= 1 + maps[s[begin]] -= 1 + begin += 1 + d = max(d, end - begin) + return d +``` + + + + + + +Author: Keqi Huang + +If you like it, please spread your support + +![Support](https://github.com/Lisanaaa/myTODOs/blob/master/WechatIMG17.jpeg) diff --git a/docs/Algorithm/Leetcode/Python/004._median_of_two_sorted_arrays.md b/docs/Algorithm/Leetcode/Python/004._median_of_two_sorted_arrays.md new file mode 100644 index 00000000..8ad14bbb --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/004._median_of_two_sorted_arrays.md @@ -0,0 +1,260 @@ +### 4. Median of Two Sorted Arrays + +题目: + + + +难度: + +Hard + + +一看到的时候,觉得跟CLRS书上的一道习题类似 +求X[1....n] Y[1....n] 的 median + +习题 9.3-8 + + +Let 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 . + + +> 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. + +- 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 + +- 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. + + +In 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). + + +divide and conquer + +- 如果X[n/2] == Y[n/2],则找到,return +- 如果X[n/2] < Y[n/2],找X[n/2+1….n]和Y[1,2…n/2]之间 +- 否则找X[1..n/2]和Y[n/2…n] + + + + +但是实际上不同,这里需要考虑的问题更多: + +- 两个数组长度不一样 +- 并不是只找一个median,如果median有两个,需要算平均 + +思路 + +把它转化成经典的findKth问题 + +参考: + + +首先转成求A和B数组中第k小的数的问题, 然后用k/2在A和B中分别找。 + + +比如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 开始来找。 + + + +B3至少大于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空, 这两种情况都是终止条件。 + + +发问,为什么要从k/2开始寻找,依旧k = 6, 我可以比较A1 和 B5的关系么,可以这样做,但是明显的问题出现在如果A1 > B5,那么这个第6小的数应该存在于B6和A1中。 + +如果A1 < B5,这个时间可能性就很多了,比如A1 < A2 < A3 < A4 < B1 < B2,各种可能,无法排除元素,所以还是要从k/2开始寻找。 + +这个跟习题算法的区别是每次扔的东西明显少一些,但是k也在不断变小。下面的代码的时间复杂度是O(lg(m+n)) + + +```python +class Solution(object): + def findMedianSortedArrays(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: float + """ + n = len(nums1) + len(nums2) + if n % 2 == 1: + return self.findKth(nums1, nums2, n / 2 + 1) + else: + smaller = self.findKth(nums1, nums2, n / 2) + bigger = self.findKth(nums1, nums2, n / 2 + 1) + return (smaller + bigger) / 2.0 + + + def findKth(self, A, B, k): + if len(A) == 0: + return B[k-1] + if len(B) == 0: + return A[k-1] + if k == 1 : + return min(A[0],B[0]) + + + a = A[ k / 2 - 1 ] if len(A) >= k / 2 else None + b = B[ k / 2 - 1 ] if len(B) >= k / 2 else None + + if b is None or (a is not None and a < b): + return self.findKth(A[k/2:], B, k - k/2) +   return self.findKth(A, B[k/2:],k - k/2) #这里要注意:因为 k/2 不一定 等于 (k - k/2), + + +``` +```python +#python3里面要用向下取整函数才可以AC,否则报错,TypeError: list indices must be integers or slices, not float + +from math import floor +class Solution: + def findMedianSortedArrays(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: float + """ + n = len(nums1) + len(nums2) + if n % 2 == 1: + return self.findKth(nums1, nums2, floor(n/2)+1) + else: + smaller = self.findKth(nums1, nums2, floor(n/2)) + bigger = self.findKth(nums1, nums2, floor(n/2)+1) + return (smaller + bigger) / 2.0 + def findKth(self, A, B, k): + + if len(A) == 0: + return B[k-1] + if len(B) == 0: + return A[k-1] + if k == 1: + return min(A[0], B[0]) + a = A[floor(k/2)-1] if len(A) >= k/2 else None + b = B[floor(k/2)-1] if len(B) >= k/2 else None + if b is None or (a is not None and a < b): + return self.findKth(A[floor(k/2):], B, k - floor(k/2)) + else: + return self.findKth(A, B[floor(k/2):], k - floor(k/2)) +``` + +这个findKth的算法单独抽出来也是题目。 +### 寻找最小的k个数 + +题目描述 + +输入n个整数,输出其中最小的k个。 +分析与解法 + +## 解法一 + +要求一个序列中最小的k个数,按照惯有的思维方式,则是先对这个序列从小到大排序,然后输出前面的最小的k个数。 +至于选取什么的排序方法,我想你可能会第一时间想到快速排序(我们知道,快速排序平均所费时间为n*logn),然后再遍历序列中前k个元素输出即可。因此,总的时间复杂度:```O(n * log n)+O(k)=O(n * log n)```。 +## 解法二 + +咱们再进一步想想,题目没有要求最小的```k```个数有序,也没要求最后```n-k```个数有序。既然如此,就没有必要对所有元素进行排序。这时,咱们想到了用选择或交换排序,即: +1. 遍历```n```个数,把最先遍历到的k个数存入到大小为```k```的数组中,假设它们即是最小的```k```个数; +2. 对这```k```个数,利用选择或交换排序找到这k个元素中的最大值```kmax```(找最大值需要遍历这```k```个数,时间复杂度为```O(k))```; +3. 继续遍历剩余```n-k```个数。假设每一次遍历到的新的元素的值为```x```,把```x```与```kmax```比较:如果```x``` < ```kmax``` ,用```x```替换```kmax```,并回到第二步重新找出k个元素的数组中最大元素kmax‘;如果```x >= kmax```,则继续遍历不更新数组。 +每次遍历,更新或不更新数组的所用的时间为```O(k)```或```O(0)```。故整趟下来,时间复杂度为```n*O(k)=O(n*k)```。 +## 解法三 + +更好的办法是维护容量为k的最大堆,原理跟解法二的方法相似: +1. 用容量为```k```的最大堆存储最先遍历到的```k```个数,同样假设它们即是最小的```k```个数; +2. 堆中元素是有序的,令```k1 pivot ){ } + if( i < j ) + swap( &a[ i ], &a[ j ] ); + else + break; + } + //重置枢纽元 + swap( &a[ i ], &a[ right - 1 ] ); + + if( k <= i ) + QuickSelect( a, k, left, i - 1 ); + else if( k > i + 1 ) + QuickSelect( a, k, i + 1, right ); + } + else + InsertSort( a + left, right - left + 1 ); +} +``` +这个快速选择SELECT算法,类似快速排序的划分方法。N个数存储在数组S中,再从数组中选取“中位数的中位数”作为枢纽元X,把数组划分为Sa和Sb俩部分,Sa<=X<=Sb,如果要查找的k个元素小于Sa的元素个数,则返回Sa中较小的k个元素,否则返回Sa中所有元素+Sb中小的k-|Sa|个元素,这种解法在平均情况下能做到O(n)的复杂度。 +更进一步,《算法导论》第9章第9.3节介绍了一个最坏情况下亦为O(n)时间的SELECT算法,有兴趣的读者可以参看。 + +给定两个已经排序好的数组,求第k大的,算法有O(m+n).类似merge sort的原理。否则利用的就是之上提到的,利用已经有序的原理,然后每次丢。 + +之所以这里还有一个丢弃条件是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大,所以可以放心丢弃。 + + +这里是两个sorted list/array findKth,想到了类似的题目,如果给一个n个linked list,findKth,能想到的办法也只能是用heap吧,类似merge k sorted lists. + + +再写一个O(m+n)类似merge sort的也可以AC的代码 + +```python +class Solution(object): + def findMedianSortedArrays(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: float + """ + def findKth(A, pa, B, pb, k): + res = 0 + m = 0 + while pa < len(A) and pb < len(B) and m < k: + if A[pa] < B[pb]: + res = A[pa] + m += 1 + pa += 1 + else: + res = B[pb] + m += 1 + pb += 1 + + while pa < len(A) and m < k: + res = A[pa] + pa += 1 + m += 1 + + + while pb < len(B) and m < k: + res = B[pb] + pb += 1 + m += 1 + return res + + n = len(nums1) + len(nums2) + if n % 2 == 1: + return findKth(nums1,0, nums2,0, n / 2 + 1) + else: + smaller = findKth(nums1,0, nums2,0, n / 2) + bigger = findKth(nums1,0, nums2,0, n / 2 + 1) + return (smaller + bigger) / 2.0 + +``` diff --git a/docs/Algorithm/Leetcode/Python/005._longest_palindromic_substring.ipynb b/docs/Algorithm/Leetcode/Python/005._longest_palindromic_substring.ipynb new file mode 100644 index 00000000..f0a71c9d --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/005._longest_palindromic_substring.ipynb @@ -0,0 +1,388 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 005. Longest Palindromic Substring 最长回文子串\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/longest-palindromic-substring/description/\n", + " - 英文:https://leetcode.com/problems/longest-palindromic-substring/\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。\n", + "\n", + "示例 1:\n", + "输入: \"babad\"\n", + "输出: \"bab\"\n", + "注意: \"aba\"也是一个有效答案。\n", + "\n", + "示例 2:\n", + "输入: \"cbbd\"\n", + "输出: \"bb\"\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + "如果一个字符串从左向右写和从右向左写是一样的,这样我们就把它叫做回文字符串。如 aba 或者 abba。\n", + "\n", + "首先想到的是一个最笨的方法,就是依次把每一个字符当做回文字符串的中间的那个字符,向两边扩展,找到以该字符为中间字符的回文串的最大长度。但是这需要将回文串长度是奇偶的情况分开来讨论。然后接下来要注意的关键是对边界的把握,确保下标不要越界。当子串已经包含首字符或最后一个字符且此时还是回文串的时候,下标分别会向两边多移一位,需要补回来。\n", + "\n", + "以 abba 这样一个字符串为例来看,abba 中,一共有偶数个字,第 1 位=倒数第 1 位,第 2 位=倒数第 2 位......第 N 位=倒数第 N 位\n", + "\n", + "以 aba 这样一个字符串为例来看,aba 中,一共有奇数个字符,排除掉正中间的那个字符后,第 1 位=倒数第 1 位......第 N 位=倒数第 N 位\n", + "\n", + "所以,假设找到一个长度为 len1 的子串后,我们接下去测试它是否满足,第 1 位=倒数第 1 位,第 2 位=倒数第 2 位......第 N 位=倒数第 N 位,也就是说,去测试从头尾到中点,字符是否逐一对应相等。如果一直进行了 [length/2] 次后,对应字符都相等,即满足第 i 位=倒数第 i 位。那么这个子串必然是palindromic string。并且,很容易知道,无论这个字符串长度为奇数还是偶数,都是 palindromic string,因为奇数位数的字符串相当于满足,第中间位=第中间位。\n", + "\n", + "于是,现在问题转化为能不能找到一个子串,满足,第 1 位=倒数第 1 位(下文叫做候选子串)。如果有,就对剩下的字符做进一步的检查。\n", + "\n", + "我们看一下下面的代码:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cbc\n" + ] + } + ], + "source": [ + "class Solution(object):\n", + " def longestPalindrome(self, s):\n", + " \"\"\"\n", + " :type s: str\n", + " :rtype: str\n", + " \"\"\"\n", + " if not s:\n", + " return\n", + " n = len(s)\n", + " if n == 1:\n", + " return s\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", + " # Whether the substring contains the first character or last character\n", + " # and is palindromic\n", + " b = True\n", + " # i 设置的是字符串的一个字符\n", + " for i in range(0, n):\n", + " # 奇数情况\n", + " # j 设置的是字符串的 i 字符的左右两边的 j 个字符是不是属于回文串,n-i 限制的是不能超出字符串末尾,i+1 限制的是不能越过字符串的开头\n", + " for j in range(0, min(n - i, i + 1)):\n", + " # 如果 以 i 字符为中央字符的情况,向两边扩展,不相等的话,代表不是回文串,停止继续比较\n", + " if (s[i - j] != s[i + j]):\n", + " b = False\n", + " break\n", + " else:\n", + " # 如果以 i 字符为中心字符向左右扩展 j 个字符是回文串,那么现在回文串的长度设置为 c\n", + " c = 2 * j + 1\n", + " # 判断 c 与 m 的大小,m 记录的是我们目前为止最长的回文串的长度,如果 c > m,那我们最长回文子串设置为 c ,否则仍然是原来的 m\n", + " if (c > m):\n", + " # 设置新的回文子串的左 index,b 是 True 就是等于 1,b 是 False 等于 0\n", + " l = i - j + 1 - b\n", + " # 设置新的回文子串的右 index\n", + " r = i + j + b\n", + " # 将新的最长回文子串赋值给 m\n", + " m = c\n", + " b = True\n", + " # 偶数情况\n", + " # i+1 限制的是不超越字符串的开头,n-i-1 限制的是不超过字符串末尾\n", + " for j in range(0, min(n - i - 1, i + 1)):\n", + " # 偶数情况下,对应位置上是够相等,相等则是回文串,不相等就不是回文串\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", + " # 将最终的回文串返回\n", + " return s[l:r]\n", + " \n", + "s = Solution()\n", + "nums = \"acbcd\"\n", + "print(s.longestPalindrome(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "上面是我们的一个参考版本,算是思路很清晰的。下面这个是 Lisanaaa 大佬根据上面版本进行修改的完成版本,总体思路是相同的,大家可以参考下。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cbc\n" + ] + } + ], + "source": [ + "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", + "s = Solution()\n", + "nums = \"acbcd\"\n", + "print(s.longestPalindrome(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + "很明显的一个动态规划思路。\n", + "\n", + " - 这个问题可以联想我们之前做的动态规划的问题,也就是 72 题,思想是一样的,但是相对于我们的 72 题来说,已经是相当简单了。\n", + " - 一个比较好的想法是 s 和 reverse(s) 共有的最长的 substring 就是 longest palindromic substring,这样我们就把问题转化为求 Longest common substring 问题了。\n", + " - 我们来看一下下面的代码,你就懂得了。\n", + " - 如果还是看不懂,那就去看看我们 72 题的讲解,已经很清楚了。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cbc\n" + ] + } + ], + "source": [ + "class Solution2(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 range(1 + len(s1))]\n", + " longest, x_longest = 0, 0\n", + " for x in range(1, 1 + len(s1)):\n", + " for y in range(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_2 = Solution2()\n", + "nums = \"acbcd\"\n", + "print(s_2.longestPalindrome(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "典型的动态规划问题。\n", + "\n", + "伪码如下:\n", + "\n", + "LCSuff(S1...p, T1...q) = LCS(S1...p1, T1...q-1) if S[p] = T[q] else 0\n", + "\n", + "代码可以参考:\n", + "\n", + "https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring#Python_2\n", + "\n", + "**但是我们上面的动态规划问题,仍然出现了超时的情况。**\n", + "\n", + "因为我们以为这样s[::-1]已经很快了.\n", + "\n", + "**特别注意:**\n", + "\n", + "这个方法是buggy的,看字符串 abcxgcba ,它 reverse 之后是 abcgxcba ,它们有公共字符串,但是这里面没有回文,修复方式是:\n", + "\n", + "we 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", + "原本 翻转\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", + "> 思路 3\n", + "\n", + "[Manacher算法,我私下叫马拉车算法,哈哈](https://www.felix021.com/blog/read.php?2040)\n", + "\n", + "Manacher 算法增加两个辅助变量 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", + "\n", + " - 当 P[j] >= mx - i 的时候,以 S[j] 为中心的回文子串不一定完全包含于以 S[id] 为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以 S[i] 为中心的回文子串,其向右至少会扩张到 mx 的位置,也就是说 P[i] >= mx - i。至于 mx 之后的部分是否对称,再具体匹配。 所以 P[i] >= Min(P[2 * id - i], mx - i),因为以 j 为中心的绘回文子串的左边界可能会比 mx 关于 id 的对称点要大,此时只能证明 P[i]=P[2 * id - i]\n", + "\n", + " - 此外,对于 mx <= i 的情况,因为无法对 P[i] 做更多的假设,只能让 P[i] = 1,然后再去匹配。\n", + "\n", + "在下面的程序中我的 P 数组保存的是,以当前字符为回文子串中心时,该回文子串的长度(不包含当前字符自身)\n", + "\n", + "简单地用一个小例子来解释:原字符串为 'qacbcaw' ,一眼就可以看出来最大回文子串是 'acbca' , 下面是我做的图,累 shi 了!\n", + "\n", + "\n", + "\n", + "所以最终代码中的 max_i 就是字符 'b' 所对应的 index8 ,start 的值就是 (max_i - P[max_i] - 1) / 2 = 1 ,最终输出结果为 s[1:6] ,即‘acbca’" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cbc\n" + ] + } + ], + "source": [ + "class Solution3(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 = int((max_i - P[max_i] - 1) / 2)\n", + " res = s[start: start + P[max_i]]\n", + " return res\n", + " \n", + "s_3 = Solution3()\n", + "nums = \"acbcd\"\n", + "print(s_3.longestPalindrome(nums)) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "run code的时候结果会跟expected不一样,但是该input确实2个结果都可以,所以放心地submit吧 还可以转到647题去看一看,也可以用这个算法解" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/005._longest_palindromic_substring.md b/docs/Algorithm/Leetcode/Python/005._longest_palindromic_substring.md new file mode 100644 index 00000000..14fd335f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/005._longest_palindromic_substring.md @@ -0,0 +1,241 @@ +### 5. Longest Palindromic Substring + +题目: + +https://leetcode.com/problems/longest-palindromic-substring/ + +难度: + +Medium + + + +思路0: + +暴力解法绝对不行 + +思路1: + +所以一个好的想法是 s 和 reverse(s) 共有的最长的 substring就是longest palindromic substring -> 问题转成求Longest common substring problem + +参见wikipedia + +,典型动归 + +LCSuff(S1...p, T1...q) = LCS(S1...p1, T1...q-1) if S[p] = T[q] else 0 + + + +伪码也有了,代码也有: + +https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring#Python_2 + +这样也超时? +```python + class Solution(object): + def longestPalindrome(self, s): + """ + :type s: str + :rtype: str + """ + def lcs(s1, s2): + m = [[0] * (1 + len(s2)) for i in xrange(1 + len(s1))] + longest, x_longest = 0, 0 + for x in xrange(1, 1 + len(s1)): + for y in xrange(1, 1 + len(s2)): + if s1[x - 1] == s2[y - 1]: + m[x][y] = m[x - 1][y - 1] + 1 + if m[x][y] > longest: + longest = m[x][y] + x_longest = x + else: + m[x][y] = 0 + return s1[x_longest - longest: x_longest] + + return lcs(s, s[::-1]) +``` +因为以为这样s[::-1]已经很快了. + +这个方法是buggy的,看字符串abcxgcba,它reverse之后是abcgxcba,它们有公共字符串,但是这里面没有回文,修复方式是: + +we 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. + +我觉得的修复方式这样么: + + 原本 翻转 + ABXYBA ABYXBA + + 求出来的substring indices是 0:2 但是这个s1[0:2] 和 s2[0:2]一样,所以不行 + 同理common substring indices还是s[4:6] 和s2[4:6]一样,不行 + + 而比如ABAD和 DABA + + substring indice 一个是0:3, 一个是1:4,这样就没问题 + + + + +思路2: + + + +依次把每一个字符当做回文字符串的中间字符,找到以该字符为中间字符的回文串的最大长度。分别对奇偶的情况进行讨论,接下来的关键就是对边界的把握,确保下标不要越界。当子串已经包含首字符或最后一个字符且此时还是回文串的时候,下标分别会向两边多移一位,需要补回来。 + +参考https://shenjie1993.gitbooks.io/leetcode-python/content/005%20Longest%20Palindromic%20Substring.html +```python + class Solution(object): + def longestPalindrome(self, s): + """ + :type s: str + :rtype: str + """ + n = len(s) + + # empty or one char + if n < 2: + return s + + # left index of the target substring + l = 0 + # right index of the target substring + r = 0 + # length of the longest palindromic substring for now + m = 0 + # length of the current substring + c = 0 + + # Whether the substring contains the first character or last character and is palindromic + b = True + for i in range(n): + # Odd situation + for j in range(min(n-i,i+1)): + if s[i-j] != s [i+j]: + b = False + break + else: + c = 2 * j + 1 + + if c > m : + l = i - j + 1 - b + r = i + j + b + m = c + b = True + + # Even situation + for j in range(min(n - i - 1, i + 1)): + if (s[i - j] != s[i + j + 1]): + b = False + break + else: + c = 2 * j + 2 + if (c > m): + l = i - j + 1 - b + r = i + j + 1 + b + m = c + b = True + return s[l:r] +``` +以上是参考版本,自己写的版本: +```python + class Solution(object): + def longestPalindrome(self, s): + """ + :type s: str + :rtype: str + """ + n = len(s) + + m,l,r = 0,0,0 + + for i in range(n): + # odd case + for j in range(min(i+1,n-i)): + if s[i-j] != s[i+j]: + break + if 2*j + 1 > m : + m = 2 * j + 1 + l = i-j + r = i+j + + + if i+1 < n and s[i] == s[i+1]: + for j in range(min(i+1,n-i-1)): + if s[i-j] != s[i+j+1]: + break + if 2 * j + 2 > m : + m = 2*j +2 + l = i-j + r = i+j+1 + + + return s[l:r+1] +``` + + +思路3: + +[Manacher算法](https://www.felix021.com/blog/read.php?2040) + +Manacher算法增加两个辅助变量id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。得到一个很重要的结论: + +- 如果mx > i,那么P[i] >= Min(P[2 * id - i], mx - i) . 为什么这样说呢,下面解释 + +下面,令j = 2*id - i,也就是说j是i关于id的对称点。 + +- 当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于i和j对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有P[i] = P[j]; +![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher1.png) + +- 当 P[j] >= mx - i 的时候,以S[j]为中心的回文子串不一定完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,再具体匹配。 +![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher2.png) +所以P[i] >= Min(P[2 * id - i], mx - i),因为以j为中心的绘回文子串的左边界可能会比mx关于id的对称点要大,此时只能证明P[i]=P[2 * id - i] +- 此外,对于 mx <= i 的情况,因为无法对 P[i]做更多的假设,只能让P[i] = 1,然后再去匹配。 + +在下面的程序中我的P数组保存的是,以当前字符为回文子串中心时,该回文子串的长度(不包含当前字符自身) + + +简单地用一个小例子来解释:原字符串为'qacbcaw',一眼就可以看出来最大回文子串是'acbca', +下面是我做的图,累shi了! + +![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher3.jpg) + + + +所以最终代码中的max_i就是字符'b'所对应的index8,start的值就是(max_i - P[max_i] - 1) / 2 = 1,最终输出结果为s[1:6],即‘acbca’ + +```python +class Solution(object): + def longestPalindrome(self, s): + """ + :type s: str + :rtype: str + """ + def preProcess(s): + if not s: + return ['^', '&'] + T = ['^'] + for i in s: + T += ['#', i] + T += ['#', '$'] + return T + T = preProcess(s) + P = [0] * len(T) + id, mx = 0, 0 + for i in range(1, len(T)-1): + j = 2 * id - i + if mx > i: + P[i] = min(P[j], mx-i) + else: + P[i]= 0 + while T[i+P[i]+1] == T[i-P[i]-1]: + P[i] += 1 + if i + P[i] > mx: + id, mx = i, i + P[i] + max_i = P.index(max(P)) #保存的是当前最大回文子串中心位置的index + start = (max_i - P[max_i] - 1) / 2 + res = s[start:start+P[max_i]] + return res +``` +run code的时候结果会跟expected不一样,但是该input确实2个结果都可以,所以放心地submit吧 +还可以转到[647题](https://github.com/Lisanaaa/thinking_in_lc/blob/master/647._Palindromic_Substrings.md)去看一看,也可以用这个算法解 + + diff --git a/docs/Algorithm/Leetcode/Python/006._ZigZag_Conversion.md b/docs/Algorithm/Leetcode/Python/006._ZigZag_Conversion.md new file mode 100644 index 00000000..6f1f9139 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/006._ZigZag_Conversion.md @@ -0,0 +1,94 @@ +# 6. ZigZag Conversion +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/zigzag-conversion/ + +> 内容描述 + +``` +The 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) + +P A H N +A P L S I I G +Y I R +And then read line by line: "PAHNAPLSIIGYIR" + +Write the code that will take a string and make this conversion given a number of rows: + +string convert(string s, int numRows); +Example 1: + +Input: s = "PAYPALISHIRING", numRows = 3 +Output: "PAHNAPLSIIGYIR" +Example 2: + +Input: s = "PAYPALISHIRING", numRows = 4 +Output: "PINALSIGYAHRPI" +Explanation: + +P I N +A L S I G +Y A H R +P I +``` + +## 解题方案 + +> 思路 1 + +参考大神[pharrellyhy](https://leetcode.com/problems/zigzag-conversion/discuss/3404/Python-O(n)-Solution-in-96ms-(99.43)?page=2)的思路, +纵向思维考虑,```index```从```0```开始,我们要一直***自增***直到```numRows-1```,此后又一直***自减***到```0```,重复执行。 +给个例子容易懂一些:```s = “abcdefghijklmn”```, ```numRows = 4``` +``` +a g m +b f h l n +c e i k +d j +``` +看明白了吗,下来上去,下来上去,zigzag + + +```python +class Solution(object): + def convert(self, s, numRows): + """ + :type s: str + :type numRows: int + :rtype: str + """ + if numRows == 1 or numRows >= len(s): + return s + res = [''] * numRows + idx, step = 0, 1 + + for x in s: + res[idx] += x + if idx == 0: ## 第一行,一直向下走 + step = 1 + elif idx == numRows - 1: ## 最后一行了,向上走 + step = -1 + idx += step + return ''.join(res) +``` +假设用我上面给的例子,并且在```L[index] += x```这一行后面打印出index, step, L的值, 输出结果如下: +``` +(0, 1, ['a', '', '', '']) +(1, 1, ['a', 'b', '', '']) +(2, 1, ['a', 'b', 'c', '']) +(3, 1, ['a', 'b', 'c', 'd']) +(2, -1, ['a', 'b', 'ce', 'd']) +(1, -1, ['a', 'bf', 'ce', 'd']) +(0, -1, ['ag', 'bf', 'ce', 'd']) +(1, 1, ['ag', 'bfh', 'ce', 'd']) +(2, 1, ['ag', 'bfh', 'cei', 'd']) +(3, 1, ['ag', 'bfh', 'cei', 'dj']) +(2, -1, ['ag', 'bfh', 'ceik', 'dj']) +(1, -1, ['ag', 'bfhl', 'ceik', 'dj']) +(0, -1, ['agm', 'bfhl', 'ceik', 'dj']) +(1, 1, ['agm', 'bfhln', 'ceik', 'dj']) +``` + diff --git a/docs/Algorithm/Leetcode/Python/007._Reverse_Integer.ipynb b/docs/Algorithm/Leetcode/Python/007._Reverse_Integer.ipynb new file mode 100644 index 00000000..d471473d --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/007._Reverse_Integer.ipynb @@ -0,0 +1,168 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 7. Reverse Integer 反转整数\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/reverse-integer/description/\n", + " - 英文:https://leetcode.com/problems/Reverse-Integer\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个 32 位有符号整数,将整数中的数字进行反转。\n", + "\n", + "示例 1:\n", + "输入: 123\n", + "输出: 321\n", + "\n", + "示例 2:\n", + "输入: -123\n", + "输出: -321\n", + "\n", + "示例 3:\n", + "输入: 120\n", + "输出: 21\n", + "\n", + "注意:\n", + "假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0。\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - x > 0, flag = 1; x < 0, flag = -1\n", + " - 将 x 转成字符串 s = str(abs(x)),然后再反转字符串 s1 = s[::-1]\n", + " - 字符串再转为整数:x1 = int(s1) * flag\n", + " - 判断是否溢出,将数据返回" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "21\n", + "-654\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def reverse(self, x):\n", + " \"\"\"\n", + " :type x: int\n", + " :rtype: int\n", + " \"\"\"\n", + " # 如果是负数,我们需要注意转化为绝对值\n", + " flag = 1\n", + " x_1 = 0\n", + " if x < 0:\n", + " flag = -1\n", + " x = int(str(abs(x))[::-1])\n", + " x_1 = x * flag\n", + " else:\n", + " flag = 1\n", + " x = int(str(x)[::-1])\n", + " x_1 = x * flag\n", + " if x_1 > 2**31-1 or x_1 < -2**31:\n", + " return 0\n", + " else:\n", + " return x_1\n", + "\n", + "s = Solution()\n", + "x = 120\n", + "y = -456\n", + "print(s.reverse(x))\n", + "print(s.reverse(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 按照低位摘除,在按高位加上去其实就可以了\n", + " - 利用循环,每次将最后一位取出来(求余),然后将原来的数据除以 10 ,取整,这样就可以每次都得到个位数\n", + " - 按照取第二步,反向操作,取出来一个最后的个位数,然后乘以 10 ,再加上每一次得到的个位数,就实现了反转\n", + " - 注意一个点,python 中对一个数求余时,结果与 求余 的符号相同,比如 5 % 2 = 1, 5 % (-2) = -1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "21\n", + "-654\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def reverse(self, x):\n", + " \"\"\"\n", + " :type x: int\n", + " :rtype: int\n", + " \"\"\"\n", + " num = 0\n", + " flag = 1\n", + " if x > 0:\n", + " flag = 1\n", + " else:\n", + " flag = -1\n", + " while x != 0:\n", + " num = num * 10 + x % (10 * flag)\n", + " x = int(x / 10)\n", + " if num > 2**31-1 or num < -2**31:\n", + " return 0\n", + " else:\n", + " return num\n", + "s = Solution()\n", + "x = 120\n", + "y = -456\n", + "print(s.reverse(x))\n", + "print(s.reverse(y))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/007._Reverse_Integer.md b/docs/Algorithm/Leetcode/Python/007._Reverse_Integer.md new file mode 100644 index 00000000..b3a00f61 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/007._Reverse_Integer.md @@ -0,0 +1,107 @@ +# 7. Reverse Integer 反转整数 + +## 题目 + +* https://leetcode.com/problems/Reverse-Integer +* https://leetcode-cn.com/problems/reverse-integer/description/ + +``` +给定一个 32 位有符号整数,将整数中的数字进行反转。 + +> 示例 1: + +输入: 123 +输出: 321 + + +> 示例 2: + +输入: -123 +输出: -321 + + +> 示例 3: + +输入: 120 +输出: 21 + +注意: +假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。 +根据这个假设,如果反转后的整数溢出,则返回 0。 +``` + +## 难度: Easy + +翻转数字问题需要注意的就是溢出问题,为什么会存在溢出问题呢,我们知道int型的数值范围是 -2147483648~2147483647(负的2的31次方~2的31次方-1), 那么如果我们要翻转 1000000009 这个在范围内的数得到 9000000001,而翻转后的数就超过了范围。 + +> 思路1 + +如果输入的是负数,就递归调用原函数,参数变成-x即可 + +```python +class Solution(object): + def reverse(self, x): + """ + :type x: int + :rtype: int + """ + if x < 0: + return -self.reverse(-x) + res = 0 + while x: + res = res * 10 + x % 10 + x /= 10 + return res if res <= 0x7fffffff else 0 +``` + +> 思路2 + +按照参数正负号先将其转成字符串,然后再反转,根据是否溢出决定输出0还是反转结果 + +```python +class Solution(object): + def reverse(self, x): + """ + :type x: int + :rtype: int + """ +        x = -int(str(x)[::-1][:-1]) if x < 0 else int(str(x)[::-1]) # [:-1]相当于把负号去掉 +        x = 0 if abs(x) > 0x7FFFFFFF else x + return x +``` + +> 思路3(StefanPochmann大神): + +看这个解法前先看[backticks](https://docs.python.org/2.7/reference/expressions.html#string-conversions) + +cmp函数在python3.x中用不了了,import operator用gt或者lt吧,或者回归if/else condition爸爸的怀抱吧! +```python +class Solution(object): + def reverse(self, x): + """ + :type x: int + :rtype: int + """ + s = cmp(x, 0) + r = int(`s * x`[::-1]) + return s * r * (r < 2 ** 31) +``` + +> 思路4 + +* 1.记录符号 +* 2.将数字当字符串处理 +* 3.判断是否阈值区间,进行比较就行 + +```python +class Solution: + def reverse(self, x): + """ + :type x: int + :rtype: int + """ + mark = 1 if x>=0 else -1 + x_abs = abs(x) + result = mark * int(str(x_abs)[::-1]) + return result if -2**31 <= result <= 2**31-1 else 0 +``` diff --git a/docs/Algorithm/Leetcode/Python/008._string_to_integer_(atoi).md b/docs/Algorithm/Leetcode/Python/008._string_to_integer_(atoi).md new file mode 100644 index 00000000..4ff1cddc --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/008._string_to_integer_(atoi).md @@ -0,0 +1,53 @@ +### 8. String to Integer (atoi) + +题目: + + + +难度: +Medium + + +需要考虑比较多的边界条件&特殊情况 +1. 首先输入可能会有空格,所以先去掉空格 +2. 去掉空格后要考虑空字符串情况 +3. 字符串首位可能会有正负号,要考虑 +4. 开始转换成数字,题目说只要遇到非数字就可以break了 +5. 结果太大或者太小超过```int```限制就要返回特定数字 ```2147483647``` 或者 ```-2147483648``` +6. 根据之前的正负号结果返回对应数值 + + +```python +class Solution(object): + def myAtoi(self, str): + """ + :type str: str + :rtype: int + """ + str = str.strip() + strNum = 0 + if len(str) == 0: + return strNum + + positive = True + if str[0] == '+' or str[0] == '-': + if str[0] == '-': + positive = False + str = str[1:] + + for char in str: + if char >='0' and char <='9': + strNum = strNum * 10 + ord(char) - ord('0') + if char < '0' or char > '9': + break + + if strNum > 2147483647: + if positive == False: + return -2147483648 + else: + return 2147483647 + if not positive: + strNum = 0 - strNum + return strNum + +``` diff --git a/docs/Algorithm/Leetcode/Python/009._Palindrome_Number.ipynb b/docs/Algorithm/Leetcode/Python/009._Palindrome_Number.ipynb new file mode 100644 index 00000000..4a643d0f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/009._Palindrome_Number.ipynb @@ -0,0 +1,165 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 9.Palindrome Number 回文数\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/palindrome-number/description\n", + " - 英文:https://leetcode.com/problems/palindrome-number\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。\n", + "\n", + "示例 1:\n", + "\n", + "输入: 121\n", + "输出: true\n", + "\n", + "示例 2:\n", + "\n", + "输入: -121\n", + "输出: false\n", + "解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。\n", + "\n", + "示例 3:\n", + "\n", + "输入: 10\n", + "输出: false\n", + "解释: 从右向左读, 为 01 。因此它不是一个回文数。\n", + "\n", + "进阶:\n", + "\n", + "你能不将整数转为字符串来解决这个问题吗?\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 首先负数肯定不是回文数\n", + " - 通过字符串进行反转,再转化为数字,对比数字是否相等就行" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def isPalindrome(self, x):\n", + " \"\"\"\n", + " :type x: int\n", + " :rtype: bool\n", + " \"\"\"\n", + " # 如果是负数,肯定不是回文数,排除掉\n", + " if x < 0:\n", + " return False\n", + " # 我们将 数字转为 str ,然后反转,再转化为 int,比较,相等的话,就是回文数,不相等的话,就不是回文数\n", + " elif x != int(str(x)[::-1]):\n", + " return False\n", + " else:\n", + " return True\n", + " \n", + "s = Solution()\n", + "x = 2345\n", + "y = 121\n", + "print(s.isPalindrome(x))\n", + "print(s.isPalindrome(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 负数一定不是回文数\n", + " - 如果一个数字是正数,并且能被我 0 整除那它肯定也不是 palidrome\n", + " - 这样我们就降低了复杂度" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def isPalindrome(self, x):\n", + " \"\"\"\n", + " :type x: int\n", + " :rtype: bool\n", + " \"\"\"\n", + " # 处理特殊情况:\n", + " # 1、负数一定不是回文数\n", + " # 2、如果数字的最后一位是 0, 为了让数字是回文数字,则第一位数字也应该是 0,只有 0 满足这种情况\n", + " if x < 0 or (x % 10 == 0 and x is not 0):\n", + " return False\n", + " revertNumber = 0\n", + " while x > revertNumber:\n", + " revertNumber = revertNumber * 10 + x % 10\n", + " x /= 10\n", + " # 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。\n", + " # 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,\n", + " # 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。\n", + " return x == revertNumber or x == revertNumber/10\n", + "\n", + "s = Solution()\n", + "x = 2345\n", + "y = 121\n", + "print(s.isPalindrome(x))\n", + "print(s.isPalindrome(y))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/009._Palindrome_Number.md b/docs/Algorithm/Leetcode/Python/009._Palindrome_Number.md new file mode 100644 index 00000000..96714ac8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/009._Palindrome_Number.md @@ -0,0 +1,74 @@ +# 9. Palindrome Number 回文数 + +## 题目 + +* https://leetcode.com/problems/palindrome-number +* https://leetcode-cn.com/problems/palindrome-number/description + +``` +判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 + +示例 1: + +输入: 121 +输出: true +示例 2: + +输入: -121 +输出: false +解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 +示例 3: + +输入: 10 +输出: false +解释: 从右向左读, 为 01 。因此它不是一个回文数。 +进阶: + +你能不将整数转为字符串来解决这个问题吗? +``` + +## 难度:Medium + +> 思路1 (满足Follow up) + +- 首先负数肯定不是palindrome +- 其次如果一个数字是一个正数,并且能被我0整除那它肯定也不是palindrome + +这样降低了复杂度 + +```python +class Solution(object): + def isPalindrome(self, x): + """ + :type x: int + :rtype: bool + """ + if x < 0 or (x != 0 and x % 10 == 0): + return False + rev, y = 0, x + while x > 0: + rev = rev * 10 + x % 10 + x /= 10 + return y == rev + +``` + +> 思路2 + +* 排除小于0的数 +* 通过字符串进行反转,对比数字是否相等就行 + +```python +class Solution: + def isPalindrome(self, x): + """ + :type x: int + :rtype: bool + """ + if x < 0: + return False + elif x != int(str(x)[::-1]): + return False + else: + return True +``` diff --git a/docs/Algorithm/Leetcode/Python/010._regular_expression_matching.ipynb b/docs/Algorithm/Leetcode/Python/010._regular_expression_matching.ipynb new file mode 100644 index 00000000..8a6af2b6 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/010._regular_expression_matching.ipynb @@ -0,0 +1,311 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 010. Regular Expression Matching 正则表达式匹配\n", + "\n", + "### 难度:Hard\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/two-sum/description\n", + " - 英文:https://leetcode.com/problems/two-sum\n", + "\n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个字符串 (s) 和一个字符模式 (p)。实现支持 '.' 和 '*' 的正则表达式匹配。\n", + "\n", + "'.' 匹配任意单个字符。\n", + "'*' 匹配零个或多个前面的元素。\n", + "匹配应该覆盖整个字符串 (s) ,而不是部分字符串。\n", + "\n", + "说明:\n", + " - s 可能为空,且只包含从 a-z 的小写字母。\n", + " - p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。\n", + "\n", + "示例 1:\n", + "输入:\n", + "s = \"aa\"\n", + "p = \"a\"\n", + "输出: false\n", + "解释: \"a\" 无法匹配 \"aa\" 整个字符串。\n", + "\n", + "示例 2:\n", + "输入:\n", + "s = \"aa\"\n", + "p = \"a*\"\n", + "输出: true\n", + "解释: '*' 代表可匹配零个或多个前面的元素, 即可以匹配 'a' 。因此, 重复 'a' 一次, 字符串可变为 \"aa\"。\n", + "\n", + "示例 3:\n", + "输入:\n", + "s = \"ab\"\n", + "p = \".*\"\n", + "输出: true\n", + "解释: \".*\" 表示可匹配零个或多个('*')任意字符('.')。\n", + "\n", + "示例 4:\n", + "输入:\n", + "s = \"aab\"\n", + "p = \"c*a*b\"\n", + "输出: true\n", + "解释: 'c' 可以不被重复, 'a' 可以被重复一次。因此可以匹配字符串 \"aab\"。\n", + "\n", + "示例 5:\n", + "输入:\n", + "s = \"mississippi\"\n", + "p = \"mis*is*p*.\"\n", + "输出: false\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + "暴力法。Lisanaaa 大佬想出来的,不得不赞一个,哈哈哈。之前想暴力法,把脑袋想爆掉了都没想全各种情况。那么,看看他是怎么解的吧。\n", + "\n", + "\".\" 很容易处理。难点就在 \"*\" 身上, \"*\" 是不会单独的,它一定是和前面的 一个字母或者 \".\" 配成一对 出现的。看成一对后是这样子的 \"X*\" ,它的性质是:要么匹配 0 个,要么匹配连续的 \"X\" 。所以尝试暴力法的时候一个 trick 是从后往前匹配。\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", + " - s 已经匹配完了, 如果此时 p 还有,那么如果剩下的是 X* 这种可以过,所以需要检查一下\n", + " - p 匹配完毕,如果 s 还有没有匹配的话,那么就 return False" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = 'abc'\n", + "p = 'a*abc'\n", + "ss = Solution()\n", + "print(ss.isMatch(s, p))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + "动态规划 解法。\n", + "\n", + "dp 优化,感觉和 edit distance 很像。DP优化待代码化,感觉学DP的一个重点除了递归学好以外,另一点是一定要会画表格。\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\n", + "a\t1\t0\t0\t0\t1\t1\t0\t\t\t\t\t\n", + "a\t2\t0\t0\t0\t0\t1\t0\t\t\t\t\t\n", + "b\t3\t0\t0\t0\t0\t0\t1\t\t\t\n", + "```\n", + "\n", + "这里有几个取巧/容易出问题的敌方,这里画的表用的是1-based string。一上来,做的事包括:\n", + "\n", + " - 初始化,空字符匹配:dp[0][0] =1\n", + " - 第一行, c * 可以匹配空字符, c * a * 可以匹配空字符, p[j-1] != s[i] ,匹配空字符\n", + " - 然后进入第二行再来看,实际上我们可以看到,如果没有碰到 * 匹配还是很朴素的,但是碰到 * :\n", + " - 1 这个匹配可以从左侧传来,dp[i][j] = dp[i][j-1] ,that is 匹配 1 个\n", + " - 1 也可以有上方传来,这种情况是 p[j-1] = s[i] ,匹配多个 dp[i][j] = dp[i-1][j]\n", + " - 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", + " - p[j-1] != s[i] : dp[i][j] = dp[i][j-2] 匹配 0 个的状况\n", + " - p[j-1] == s[i] or p[i-1] == '.':\n", + " - dp[i][j] = dp[i-1][j] 匹配多个 s[i]\n", + " - dp[i][j] = dp[i][j-2] 匹配 0 个\n", + "\n", + "AC 代码,注意一下,因为上表为了表达方便,用的是 1-based string 系统,实际写代码的时候我们心里还是清楚这个 string 还是从 0 开始的,不过也可以尝试往前面添东西来方便。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = 'abc'\n", + "p = 'a*abc'\n", + "ss = Solution()\n", + "print(ss.isMatch(s, p))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "我做的动态规划和上面大体思路是类似的。\n", + "\n", + "直接说动态转移方程组了,我们首先定义一些变量方便解释,被匹配串为s,模式串为p。状态转移数组 dp[i][j]表示利用 p 的前 j 个字符匹配 s 的前 i 个字符的匹配结果(成功为 true,失败为 false)。\n", + "\n", + " - **s[i] == p[j] || p[j] == '.'** ,那么 dp[i][j] = dp[i-1][j-1] ,也就是既然 s 串的第 i 个字符能和 p 串的第 j 个字符匹配,那么如果 s 串的前 i-1 个字符和 p 串的前 j-1 个字符能匹配则 s 串的前 i 个和 p 串的前 j 个则能匹配,反之不能。\n", + " - **p[j] == '*'** :分情况讨论。\n", + " - **s[i] != p[j-1] && p[j-1] != '.'** ,那么 dp[i][j] = dp[i][j-2] ,也就是 * 号前面的那个字符在匹配的过程当中一个都不使用。\n", + " - **else,那么dp[i][j] = dp[i-1][j] || dp[i][j-1] || dp[i][j-2]**,也就是说要么使用 '*' 号进行匹配( dp[i-1][j] ),要么只使用 '*' 号前面的那个字符匹配,不使用 '*' 匹配( dp[i][j-1] ),要么 '*' 号前面的那个字符在匹配的过程当中一个都不使用( dp[i][j-2] ),只要有一个是 true 则能够匹配。\n", + " \n", + "最后考虑一下边界条件。一开始 i 是从 1 到 len(s) ,j 是 1 到 len(p) 。首先一来就能想到 dp[0][0] 是true,其他都是 false。但是这个边界条件是不够的。比如 isMatch(\"aab\", \"c * a * b\") ,dp[1][3] 应该是从 dp[0][2] 转移过来的,所以需要更多的边界条件,也就是一开始的 * 是能匹配空字符串的。所以我把 i 改到了从 0 开始,并且第二条也添加了 i=0,dp[i][j] = dp[i][j-2] 。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def isMatch(self, s, p):\n", + " \"\"\"\n", + " :type s: str\n", + " :type p: str\n", + " :rtype: bool\n", + " \"\"\"\n", + " dp = []\n", + " dp = [[False for i in range(len(p)+1)] for j in range(len(s)+1)]\n", + " dp[0][0] = True\n", + "# print(dp)\n", + " for i in range(len(s)+1):\n", + " for j in range(1, len(p)+1):\n", + " if i > 0 and (s[i-1] == p[j-1] or p[j-1] == '.'):\n", + "# print(\"1111111\",i)\n", + "# print(\"2222222\",j)\n", + " dp[i][j] = dp[i-1][j-1]\n", + "# print(\"3333333\",dp[i-1][j-1])\n", + " if p[j-1] == '*':\n", + " if i == 0 or (s[i-1] != p[j-2] and p[j-2] != '.'):\n", + "# print(\"4444444\",i)\n", + "# print(\"5555555\",j)\n", + " dp[i][j] = dp[i][j-2]\n", + "# print(\"6666666\",dp[i][j-2])\n", + " else:\n", + " dp[i][j] = dp[i-1][j] or dp[i][j-1] or dp[i][j-2]\n", + "# print(\"7777777\",i)\n", + "# print(\"8888888\",j)\n", + "# print(dp) \n", + " return dp[len(s)][len(p)]\n", + " \n", + "s = 'aa'\n", + "p = 'a*'\n", + "ss = Solution()\n", + "print(ss.isMatch(s, p))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/010._regular_expression_matching.md b/docs/Algorithm/Leetcode/Python/010._regular_expression_matching.md new file mode 100644 index 00000000..f3d51b10 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/010._regular_expression_matching.md @@ -0,0 +1,229 @@ +### 010. Regular Expression Matching + +题目: + + + +难度: + +Hard + + + + +先尝试暴力解法,难点就在 * 身上, * 不会单独出现,它一定是和前面一个字母或"."配成一对。看成一对后"X*",它的性质就是:要不匹配0个,要不匹配连续的“X”.所以尝试暴力解法的时候一个trick是从后往前匹配. + + + +暴力解法居然也能AC? + +是这样来分情况看得: + +- 如果s[i] = p[j] 或者 p[j]= . : 往前匹配一位 +- 如果p[j] = ' * ', 检查一下,如果这个时候p[j-1] = . 或者p[j-1] = s[i] ,那么就往前匹配,如果这样能匹配过,就return True, 否者我们忽略 ' X* ',这里注意里面的递推关系 +- 再处理一下边界状况: + - s已经匹配完了, 如果此时p还有,那么如果剩下的是 X* 这种可以过,所以检查 + - p匹配完毕,如果s还有那么报错 + +```python +class Solution(object): + def isMatch(self, s, p): + """ + :type s: str + :type p: str + :rtype: bool + """ + def helper(s, i, p, j): + if j == -1: + return i == -1 + if i == -1: + if p[j] != '*': + return False + return helper(s, i, p, j-2) + if p[j] == '*': + if p[j-1] == '.' or p[j-1] == s[i]: + if helper(s, i-1, p, j): + return True + return helper(s, i, p, j-2) + if p[j] == '.' or p[j] == s[i]: + return helper(s, i-1, p, j-1) + return False + + return helper(s, len(s)-1, p, len(p)-1) +``` + + + +---------- + +dp优化,感觉和edit distance很像。 DP优化待代码化,感觉学DP的一个重点除了递归学好以外,另一点是一定要会画表格。 + + +画一个表格来看一下状况 + +``` + c * a * b + 0 1 2 3 4 5 + 0 1 0 1 0 1 0 +a 1 0 0 0 1 1 0 +a 2 0 0 0 0 1 0 +b 3 0 0 0 0 0 1 + +``` + +这里有几个取巧/容易出问题的敌方,这里画的表用的是1-based string。一上来,做的事包括: + +- 初始化,空字符匹配:dp[0][0] =1 +- 第一行,c* 可以匹配空字符,c* a* 可以匹配空字符,p[j-1] != s[i],匹配空字符 +- 然后进入第二行再来看,实际上我们可以看到,如果没有碰到 * 匹配还是很朴素的,但是碰到 * : + - 1这个匹配可以从左侧传来,dp[i][j] = dp[i][j-1],that is 匹配 1个 + - 1 也可以有上方传来,这种情况是p[j-1] = s[i],匹配多个 dp[i][j] = dp[i-1][j] + - 1 这个匹配也可以从间隔一个的左侧传来,that is也可以有个性的匹配0个,如同匹配空字符一样dp[i][j] = dp[i][j-2],但是注意匹配0个实际上有两种状况,如果p[j-1]!=s[i],强制匹配0个,即使p[j-1] == s[i],我们也可以傲娇的用它来匹配0个。 + +再代码化一点: + +- s[i] == p[j] 或者 p[j] == '.' : dp[i][j] = dp[i-1][j-1] +- p[j] == '*': 然后分几种情况 + - p[j-1] != s[i] : dp[i][j] = dp[i][j-2] 匹配0个的状况 + - p[j-1] == s[i] or p[i-1] == '.': + - dp[i][j] = dp[i-1][j] 匹配多个s[i] + - dp[i][j] = dp[i][j-2] 匹配0个 + +AC代码,注意一下,因为上表为了表达方便,用的是1-based string系统,实际写代码的时候我们心里还是清楚这个string还是从0开始的,不过也可以尝试往前面添东西来方便。 + + +AC代码 + +```python +class Solution(object): + def isMatch(self, s, p): + """ + :type s: str + :type p: str + :rtype: bool + """ + m, n = len(s), len(p) + dp = [ [0 for i in range(n+1)] for j in range(m+1)] + + dp[0][0] = 1 + + # init the first line + for i in range(2,n+1): + if p[i-1] == '*': + dp[0][i] = dp[0][i-2] + + for i in range(1,m+1): + for j in range(1,n+1): + if p[j-1] == '*': + if p[j-2] != s[i-1] and p[j-2] != '.': + dp[i][j] = dp[i][j-2] + elif p[j-2] == s[i-1] or p[j-2] == '.': + dp[i][j] = dp[i-1][j] or dp[i][j-2] + + elif s[i-1] == p[j-1] or p[j-1] == '.': + dp[i][j] = dp[i-1][j-1] + + return dp[m][n] == 1 +``` + +写个测试案例 +```python +import unittest +class Solution(object): + def isMatch(self, s, p): + """ + :type s: str + :type p: str + :rtype: bool + """ + m, n = len(s), len(p) + dp = [ [0 for i in range(n+1)] for j in range(m+1)] + + dp[0][0] = 1 + + # init the first line + for i in range(2,n+1): + if p[i-1] == '*': + dp[0][i] = dp[0][i-2] + + for i in range(1,m+1): + for j in range(1,n+1): + if p[j-1] == '*': + if p[j-2] != s[i-1] and p[j-2] != '.': + dp[i][j] = dp[i][j-2] + elif p[j-2] == s[i-1] or p[j-2] == '.': + dp[i][j] = dp[i-1][j] or dp[i][j-2] + + elif s[i-1] == p[j-1] or p[j-1] == '.': + dp[i][j] = dp[i-1][j-1] + + return dp[m][n] == 1 + + +class TestSolution(unittest.TestCase): + def test_none_0(self): + s = "" + p = "" + self.assertTrue(Solution().isMatch(s, p)) + + def test_none_1(self): + s = "" + p = "a" + self.assertFalse(Solution().isMatch(s, p)) + + def test_no_symbol_equal(self): + s = "abcd" + p = "abcd" + self.assertTrue(Solution().isMatch(s, p)) + + def test_no_symbol_not_equal_0(self): + s = "abcd" + p = "efgh" + self.assertFalse(Solution().isMatch(s, p)) + + def test_no_symbol_not_equal_1(self): + s = "ab" + p = "abb" + self.assertFalse(Solution().isMatch(s, p)) + + def test_symbol_0(self): + s = "" + p = "a*" + self.assertTrue(Solution().isMatch(s, p)) + + def test_symbol_1(self): + s = "a" + p = "ab*" + self.assertTrue(Solution().isMatch(s, p)) + + def test_symbol_2(self): + # E.g. + # s a b b + # p 1 0 0 0 + # a 0 1 0 0 + # b 0 0 1 0 + # * 0 1 1 1 + s = "abb" + p = "ab*" + self.assertTrue(Solution().isMatch(s, p)) + + +if __name__ == "__main__": + unittest.main() + + + +输出: +........ + +Ran 8 tests in 0.001s + +OK +``` + +参考: + + +[动态规划](https://hk029.gitbooks.io/leetbook/content/动态规划/010.%20Regular%20Expression%20Matching/010.%20Regular%20Expression%20Matching.html) + + diff --git a/docs/Algorithm/Leetcode/Python/011._container_with_most_water.md b/docs/Algorithm/Leetcode/Python/011._container_with_most_water.md new file mode 100644 index 00000000..4fac0f11 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/011._container_with_most_water.md @@ -0,0 +1,112 @@ +### 11. Container With Most Water + + + +题目: + + + +难度: +Medium + +思路: + + +首先理解花了我一点时间,因为一开始写出来,给了一个例子: + +``` + +height = [3,2,1,3] +解是 9 + + +| | +| | | +| | | | +1 2 3 4 + + 一开始我的理解走偏的地方是这个9是如何得到的,因为根据最短板原理,明显不可能得到9啊,后来发现是·Find two lines, which together with x-axis forms a container, such that the container contains the most water. +``` + +所以代码写起来就简单了,AC无能,超时,时间复杂度O(N^2) + + +``` +class Solution(object): # 此法超时 + def maxArea(self, height): + """ + :type height: List[int] + :rtype: int + """ + n = len(height) + most_water = 0 + for i in range(n-1): + for j in range(i, n): + water = (j-i) * min(height[i], height[j]) + most_water = max(water, most_water) + return most_water + +``` + +题目给的tag是 two pointer,所以上边的策略肯定可以改进,改进的地方就不能是这个一次走一边,而可能是两边都要走。 + + + +参考 + + +思路: + +由于ai和aj (i=i, j'<=j) >= S(i,j)```,由于```j'-i' <= j-i```,必然要有```min(ai',aj')>=min(ai,aj)```才行。同样可以采用头尾双指针向中间移动: + +当```a(left) < a(right)```时,对任何```j S(left, j a(right)时,需要左移right`。 + +`而当a(left) = a(right)时,需要同时移动left和right。` + +思路整理: +left = 0, right = n-1 +1. a[left] < a[right], left++ +2. a[left] > a[right], right-- +3. a[left] = a[right], left++, right-- +终止条件:left >= right + +这个证明大快人心 + + +这样写也能过: + + +```python +class Solution(object): + def maxArea(self, height): + """ + :type height: List[int] + :rtype: int + """ + n = len(height) + left, right = 0, n-1 + most_water = 0 + while left <= right: + water = (right - left) * min(height[left], height[right]) + most_water = max(water, most_water) + if height[left] < height[right]: + left += 1 + elif height[left] > height[right]: + right -= 1 + else: + left += 1 + right -= 1 + return most_water + +``` diff --git a/docs/Algorithm/Leetcode/Python/012._Integer_to_Roman.md b/docs/Algorithm/Leetcode/Python/012._Integer_to_Roman.md new file mode 100644 index 00000000..6177e332 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/012._Integer_to_Roman.md @@ -0,0 +1,71 @@ +### 12. Integer to Roman + + +题目: + + + +难度: +Medium + +思路: + +首先我学习了一下罗马字母是如何表示的。然后感慨,这个阿拉伯数字是多么好的发明 + + + +上图 + + + +基于的是这些个Symbol: + +``` +1 5 10 50 100 500 1000 +I V X L C D M +``` + + + +罗马数字表示法见[Leetcode 013](https://github.com/Lisanaaa/thinking_in_lc/blob/master/013._Roman_to_Integer.md) + +这里有一个很棒的[算法](https://gist.github.com/imilu/00f32c61e50b7ca296f91e9d96d8e976) + +AC代码 + +```python +class Solution(object): + def intToRoman(self, num): + """ + :type num: int + :rtype: str + """ + lookup = { + 'M': 1000, + 'CM': 900, + 'D': 500, + 'CD': 400, + 'C': 100, + 'XC': 90, + 'L': 50, + 'XL': 40, + 'X': 10, + 'IX': 9, + 'V': 5, + 'IV': 4, + 'I': 1 + } + romanStr = '' + + for symbol, val in sorted(lookup.items(), key = lambda t: t[1], reverse = True): + while num >= val: + romanStr += symbol + num -= val + return romanStr +``` + + + + + +因为dict本身是无序的,这里做了一个排序的操作,否则可能会出现IIII这种状况。 diff --git a/docs/Algorithm/Leetcode/Python/013._Roman_to_Integer.ipynb b/docs/Algorithm/Leetcode/Python/013._Roman_to_Integer.ipynb new file mode 100644 index 00000000..8ac444f2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/013._Roman_to_Integer.ipynb @@ -0,0 +1,197 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 013.Roman to Integer\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 英文:https://leetcode.com/problems/roman-to-integer/\n", + " - 中文:https://leetcode-cn.com/problems/roman-to-integer/description/\n", + "\n", + "> 内容描述\n", + "\n", + "```\n", + "罗马数字包含以下七种字符:I, V, X, L,C,D 和 M。\n", + "\n", + "字符 数值\n", + "I 1\n", + "V 5\n", + "X 10\n", + "L 50\n", + "C 100\n", + "D 500\n", + "M 1000\n", + "\n", + "例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。\n", + "\n", + "通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:\n", + "\n", + "I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。\n", + "X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 \n", + "C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。\n", + "\n", + "给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。\n", + "\n", + "示例 1:\n", + "输入: \"III\"\n", + "输出: 3\n", + "\n", + "示例 2:\n", + "输入: \"IV\"\n", + "输出: 4\n", + "\n", + "示例 3:\n", + "输入: \"IX\"\n", + "输出: 9\n", + "\n", + "示例 4:\n", + "输入: \"LVIII\"\n", + "输出: 58\n", + "解释: C = 100, L = 50, XXX = 30, III = 3.\n", + "\n", + "示例 5:\n", + "输入: \"MCMXCIV\"\n", + "输出: 1994\n", + "解释: M = 1000, CM = 900, XC = 90, IV = 4.\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 从前向后依次扫描,用一个临时变量记录当前数字。\n", + " - 如果没有出现题目中出现的特殊情况,那我们就可以一直一个一个加下去,这样就能得到正确结果。\n", + " - 特殊情况出现的时候,后一位数字比前一位数字大,而正常情况正好是相反的(后一位数字一定比前一位小),后一位减去前一位即可得到这两位得到的数值,但是要注意一点,我们在这之前已经将前一位进行加和了一次,所以这时候,我们要减去 2 次前一位数字。\n", + " - 其他地方没有太难的部分,以下是 AC 代码。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1994\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "string = \"MCMXCIV\"\n", + "print(s.romanToInt(string))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "可以修改一下的地方,我们可以将从字典中取数的逻辑封装到一个函数中,这样也比较优雅。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1994\n" + ] + } + ], + "source": [ + "def getNum(x):\n", + " return {\"I\":1,\n", + " \"V\":5,\n", + " \"X\":10,\n", + " \"L\":50,\n", + " \"C\":100,\n", + " \"D\":500,\n", + " \"M\":1000}.get(x)\n", + "\n", + "class Solution: \n", + " def romanToInt(self, s):\n", + " \"\"\"\n", + " :type s: str\n", + " :rtype: int\n", + " \"\"\"\n", + " Num = {\n", + " 'M': 1000,\n", + " 'D': 500,\n", + " 'C': 100,\n", + " 'L': 50,\n", + " 'X': 10,\n", + " 'V': 5,\n", + " 'I': 1\n", + " }\n", + " result = 0\n", + " for i in range(len(s)):\n", + " if i > 0 and Num[s[i]] > Num[s[i-1]]:\n", + " result = result + Num[s[i]] - 2 * Num[s[i-1]]\n", + " else:\n", + " result += Num[s[i]]\n", + " return result\n", + " \n", + "s = Solution()\n", + "string = \"MCMXCIV\"\n", + "print(s.romanToInt(string))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/013._Roman_to_Integer.md b/docs/Algorithm/Leetcode/Python/013._Roman_to_Integer.md new file mode 100644 index 00000000..4f1184b8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/013._Roman_to_Integer.md @@ -0,0 +1,82 @@ +### 13.Roman to Integer + + + +题目: + + +难度: +Easy + +思路: + + +``` +罗马数字是最古老的数字表示方式,比阿拉伯数组早2000多年,起源于罗马 + +罗马数字有如下符号: + +基本字符 I V X L C D M +对应阿拉伯数字 1 5 10 50 100 500 1000 + +计数规则: +- 相同的数字连写,所表示的数等于这些数字相加得到的数,例如:III = 3 +- 小的数字在大的数字右边,所表示的数等于这些数字相加得到的数,例如:VIII = 8 +- 小的数字,限于(I、X和C)在大的数字左边,所表示的数等于大数减去小数所得的数,例如:IV = 4,这条规则好像这题不管 +- 正常使用时,连续的数字重复不得超过三次 +- 在一个数的上面画横线,表示这个数扩大1000倍(本题只考虑3999以内的数,所以用不到这条规则) +- 从前向后遍历罗马数字,如果某个数比前一个数小,则加上该数。反之,减去前一个数的两倍然后加上该数 +``` + + + +integer to Roman 是 Medium,这个roman to integer是easy + + +- 从前往后扫描,用一个临时变量记录分段数字。 +- 如果当前比前一个大,说明这一段的值应当是这个值减去上一个值。比如IV = 5-1 =4; 否则,将当前值加入到结果中,然后开始下一段记录,比如VI = 5 + 1, II = 1 +1 + + +所以这也就是罗马数字的基础,感觉?这样才不会读串? + + + +AC代码 + +```python +class Solution(object): + def romanToInt(self, s): + """ + :type s: str + :rtype: int + """ + lookup = { + 'M': 1000, + 'D': 500, + 'C': 100, + 'L': 50, + 'X': 10, + 'V': 5, + 'I': 1 + } + res = 0 + for i in range(len(s)): + if i > 0 and lookup[s[i]] > lookup[s[i-1]]: + res = res + lookup[s[i]] - 2 * lookup[s[i-1]] + else: + res += lookup[s[i]] + return res +``` +或者甚至可以建立一个新函数用于取对应数值: +``` + def table(x): + return { + 'I':1, + 'V':5, + 'X':10, + 'L':50, + 'C':100, + 'D':500, + 'M':1000 + }.get(x) +``` diff --git a/docs/Algorithm/Leetcode/Python/014._longest_common_prefix.md b/docs/Algorithm/Leetcode/Python/014._longest_common_prefix.md new file mode 100644 index 00000000..a64997ef --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/014._longest_common_prefix.md @@ -0,0 +1,77 @@ +### 14. Longest Common Prefix + + +题目: + + + +难度: + +Easy + + +思路: + +#### 解法1: +以一个小例子来解释,strs=['laa', 'lab', 'lac'], 如果存在LCP的话它肯定就在第一个字符串strs[0]中,并且LCP的长度肯定不会大于strs[0]的长度 +- 依次假设LCP长度为0到len(strs[0]),在每一轮循环中: +   +- 1. 只要strs中存在比当前长度i更短的string,立刻返回上一轮LCP,即strs[0][:i] + 2. 只要strs中存在当前index字符与LCP该index不相同的字符串,立刻返回上一轮LCP,即strs[0][:i] +- 如果一直没返回,说明strs[0]本身就是LCP,返回它 + + +``` +class Solution(object): + def longestCommonPrefix(self, strs): + """ + :type strs: List[str] + :rtype: str + """ + if not strs: + return "" + for i in range(len(strs[0])): + for str in strs: + if len(str) <= i or strs[0][i] != str[i]: + return strs[0][:i] + return strs[0] + +``` + +#### 解法2: +- dp[i]代表前i+1个字符串的最大前缀串, +- 如果第i+2个字符串不以dp[i]为前缀,就去掉dp[i]的最后一个字符再试一次 +- 都去完了那么dp[i+1]肯定就是空串了,也就等于这时候的dp[i],因为dp[i]的每个字符已经被去完了 +```python +class Solution(object): + def longestCommonPrefix(self, strs): + """ + :type strs: List[str] + :rtype: str + """ + if not strs: + return '' + dp = [strs[0]]*len(strs) + for i in range(1,len(strs)): + while not strs[i].startswith(dp[i-1]): + dp[i-1] = dp[i-1][:-1] + dp[i] = dp[i-1] + return dp[-1] +``` + + + + + + + +python无敌啊!!!有没有天理啊,手动滑稽😏😏😏😏!一行解法: +```python +class Solution(object): + def longestCommonPrefix(self, strs): + """ + :type strs: List[str] + :rtype: str + """ + return os.path.commonprefix(strs) +``` diff --git a/docs/Algorithm/Leetcode/Python/015._3sum.md b/docs/Algorithm/Leetcode/Python/015._3sum.md new file mode 100644 index 00000000..9f962f9e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/015._3sum.md @@ -0,0 +1,106 @@ +### 15. 3Sum + +题目: + + + +难度: + +Medium + + +第一想法,先把nums排序,用三个loop,无法AC + +``` +class Solution(object): + def threeSum(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + n = len(nums) + res = [] + nums.sort() + for i in range(n): + for j in range(i,n): + for k in range(j,n): + if nums[i] + nums[j] + nums[k] == 0 and j != i and k != j and k != i: + curRes = [nums[i],nums[j],nums[k]] + if curRes not in res: + res.append(curRes) + + return res +``` + + +然后查了一下2sum,用2sum的花样,因为要排除重复以及输出是按照从小到大的输出:但是还是超时 + + +``` +class Solution(object): # 此法也超时 +    def threeSum(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + def twoSum(nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + lookup = {} + for num in nums: + if target - num in lookup: + if (-target ,target - num, num) not in res: + res.append((-target ,target - num, num)) + lookup[num] = target - num + + n = len(nums) + nums.sort() + res = [] + for i in range(n): + twoSum(nums[i+1:], 0-nums[i]) + return [list(i) for i in res] +``` + + +谷歌看别人的代码,思路非常清晰的,运行起来比直接调用 Two Sum快. + +清晰的思路: + +- 排序 +- 固定左边,如果左边重复,继续 +- 左右弄边界,去重,针对不同的左右边界情况处理 + + +```python +class Solution(object): + def threeSum(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + n, res = len(nums), [] + nums.sort() + for i in range(n): + if i > 0 and nums[i] == nums[i-1]: # 因为i=0这个元素会直接往下执行 + continue + l, r = i+1, n-1 + while l < r: + tmp = nums[i] + nums[l] + nums[r] + if tmp == 0: + res.append([nums[i], nums[l], nums[r]]) + l += 1 + r -= 1 + while l < r and nums[l] == nums[l-1]: + l += 1 + while l < r and nums[r] == nums[r+1]: + r -= 1 + elif tmp > 0: + r -= 1 + else: + l += 1 + return res +``` + diff --git a/docs/Algorithm/Leetcode/Python/016._3sum_closest.md b/docs/Algorithm/Leetcode/Python/016._3sum_closest.md new file mode 100644 index 00000000..96b012ad --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/016._3sum_closest.md @@ -0,0 +1,51 @@ +### 16. 3Sum Closest + +题目: + + + +难度: + +Medium + + +思路: +跟3 Sum一样,固定一个元素 + +用两个指针来循环 + + +```python +class Solution(object): + def threeSumClosest(self, nums, target): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + n, res, diff = len(nums), None, float('inf') + nums.sort() + for i in range(n): + if i > 0 and nums[i] == nums[i-1]: + continue + l, r = i+1, n-1 + while l < r: + tmp = nums[i] + nums[l] + nums[r] + if tmp == target: + return target + elif tmp > target: + r -= 1 + if abs(tmp-target) < diff: + diff = abs(tmp-target) + res = tmp + while l < r and nums[r] == nums[r+1]: + r -= 1 + else: + l += 1 + if abs(tmp-target) < diff: + diff = abs(tmp-target) + res = tmp + while l < r and nums[l] == nums[l-1]: + l += 1 + return res + +``` diff --git a/docs/Algorithm/Leetcode/Python/017._letter_combinations_of_a_phone_number.md b/docs/Algorithm/Leetcode/Python/017._letter_combinations_of_a_phone_number.md new file mode 100644 index 00000000..e951ad85 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/017._letter_combinations_of_a_phone_number.md @@ -0,0 +1,51 @@ +### 17. Letter Combinations of a Phone Number + +题目: + + + + +难度: + +Medium + + +思路: + + - hash table一个,用来对应digit -> letter + - s用来记录结果,每次从digits里面去一个,然后寻找其可能的char,加到s中,digits长度减小 + - digits长度为0时候,把它加入结果 + + + +```python +class Solution(object): + def letterCombinations(self, digits): + """ + :type digits: str + :rtype: List[str] + """ + if digits == '': + return [] + self.res = [] + self.singleResult('', digits) + return self.res + + def singleResult(self, s, digits): + if len(digits) == 0: + self.res.append(s) + else: + mapx = {'2':['a','b','c'], + '3':['d','e','f'], + '4':['g','h','i'], + '5':['j','k','l'], + '6':['m','n','o'], + '7':['p','q','r','s'], + '8':['t','u','v'], + '9':['w','x','y','z']} + cur_digit = digits[0] + for c in mapx[cur_digit]: + self.singleResult(s+c, digits[1:]) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/018._4sum.md b/docs/Algorithm/Leetcode/Python/018._4sum.md new file mode 100644 index 00000000..ba686205 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/018._4sum.md @@ -0,0 +1,136 @@ +### 18. 4Sum + +题目: + + + +难度: + +Medium + + +思路: + +用3sum改 + +固定两个数,活动别的 + + +```python +class Solution(object): + def fourSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[List[int]] + """ + n = len(nums) + nums.sort() + res = [] + for i in range(n): + for j in range(i+1,n): + l, r = j+1, n-1 + while l < r: + temp = nums[i] + nums[j] + nums[l] + nums[r] + if temp == target: + if [nums[i],nums[j],nums[l],nums[r]] not in ans: + ans.append([nums[i],nums[j],nums[l],nums[r]]) + l += 1 + r -= 1 + elif temp > target: + r -= 1 + else: + l+=1 + return ans +``` + +可以通过加判断条件,前后数字相等可以直接跳过,使得算法更快 + + +```python +class Solution(object): + def fourSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[List[int]] + """ + n, res = len(nums), [] + nums.sort() + for i in range(n): + if i > 0 and nums[i] == nums[i-1]: # 因为i=0这个元素会直接往下执行 + continue + for j in range(i+1, n): + if j > i+1 and nums[j] == nums[j-1]: # 因为j=i+1这个元素会直接往下执行 + continue + l, r = j+1, n-1 + while l < r: + tmp = nums[i] + nums[j] + nums[l] + nums[r] + if tmp == target: + res.append([nums[i], nums[j], nums[l], nums[r]]) + l += 1 + r -= 1 + while l < r and nums[l] == nums[l-1]: + l += 1 + while l < r and nums[r] == nums[r+1]: + r -= 1 + elif tmp > target: + r -= 1 + else: + l += 1 + return res + +``` + +还可以再用一些判断来加速,比如枚举第一个数的时候 + +- nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target: break +这是当前能凑齐的最小的4个数,比target后面都不用做了 +- nums[i] + nums[n – 3] + nums[n – 2] + nums[n – 1] < target: continue +这是当前凑齐的最大的4个数,比target小,说明第一个数不够大 + +参考 + + + + +```python +class Solution(object): + def fourSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[List[int]] + """ + n, res = len(nums), [] + nums.sort() + for i in range(n): + if i > 0 and nums[i] == nums[i-1]: # 因为i=0这个元素会直接往下执行 + continue + if i+3 <= n-1: + if nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target: + break + if i < n-3: + if nums[i] + nums[n-3] + nums[n-2] + nums[n-1] < target: + continue + for j in range(i+1, n): + if j > i+1 and nums[j] == nums[j-1]: # 因为j=i+1这个元素会直接往下执行 + continue + l, r = j+1, n-1 + while l < r: + tmp = nums[i] + nums[j] + nums[l] + nums[r] + if tmp == target: + res.append([nums[i], nums[j], nums[l], nums[r]]) + l += 1 + r -= 1 + while l < r and nums[l] == nums[l-1]: + l += 1 + while l < r and nums[r] == nums[r+1]: + r -= 1 + elif tmp > target: + r -= 1 + else: + l += 1 + return res + +``` diff --git a/docs/Algorithm/Leetcode/Python/019._remove_nth_node_from_end_of_list.md b/docs/Algorithm/Leetcode/Python/019._remove_nth_node_from_end_of_list.md new file mode 100644 index 00000000..5bdefb7a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/019._remove_nth_node_from_end_of_list.md @@ -0,0 +1,42 @@ +### 19. Remove Nth Node From End of List + +题目: + + + + +难度: Medium + + +AC击败了95.80%的Python用户,技巧 dummy head 和双指针。 + +切记最后要返回```dummy.next```而不是```head```,因为有这样一种情况,删掉节点后```linked list```空了,那返回```head```的话结果显然不同。如: +输入链表为```[1]```, ```n = 1```, 应该返回```None```而不是```[1]``` + +```python +class Solution(object): + def removeNthFromEnd(self, head, n): + """ + :type head: ListNode + :type n: int + :rtype: ListNode + """ + dummy = ListNode(-1) + dummy.next = head + p, q = dummy, dummy + + for i in range(n): + q = q.next + + while q.next: + p = p.next + q = q.next + + p.next = p.next.next + return dummy.next + +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/020._valid_parentheses.ipynb b/docs/Algorithm/Leetcode/Python/020._valid_parentheses.ipynb new file mode 100644 index 00000000..f665733d --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/020._valid_parentheses.ipynb @@ -0,0 +1,302 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 20. Valid Parentheses 有效的括号\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/valid-parentheses/description\n", + " - 英文:https://leetcode.com/problems/valid-parentheses\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。\n", + "\n", + "有效字符串需满足:\n", + "\n", + "1、左括号必须用相同类型的右括号闭合。\n", + "2、左括号必须以正确的顺序闭合。\n", + "\n", + "注意空字符串可被认为是有效字符串。\n", + "\n", + "示例1:\n", + "输入: \"()\"\n", + "输出: true\n", + "\n", + "示例2:\n", + "输入: \"()[]{}\"\n", + "输出: true\n", + "\n", + "示例3:\n", + "输入: \"(]\"\n", + "输出: false\n", + "\n", + "示例4:\n", + "输入: \"([)]\"\n", + "输出: false\n", + "\n", + "示例5:\n", + "输入: \"{[]}\"\n", + "输出: true\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + "我们只需要匹配三种情况: \"(\" -> \")\", \"[\" -> \"]\", \"{\" -> \"}\".\n", + "\n", + "但是这里最重要的思想是 栈 。一遇到左括号就入栈,右括号出栈,这样来寻找对应。\n", + "\n", + "需要检查几件事:\n", + "\n", + " - 出现右括号时 stack 里是否还有符号(无论左右)\n", + " - 出 stack 时是否对应\n", + " - 最终 stack 是否为空" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def isValid(self, s):\n", + " \"\"\"\n", + " :type s: str\n", + " :rtype: bool\n", + " \"\"\"\n", + " LEFT = {'(', '[', '{'} # 左括号\n", + " RIGHT = {')', ']', '}'} # 右括号\n", + " stack = [] # 创建一个栈\n", + " for brackets in s: # 迭代传过来的所有字符串\n", + " if brackets in LEFT: # 如果当前字符在左括号内\n", + " stack.append(brackets) # 把当前左括号入栈\n", + " elif brackets in RIGHT: # 如果是右括号\n", + " if not stack or not 1 <= ord(brackets) - ord(stack[-1]) <= 2:\n", + " # 如果当前栈为空,()]\n", + " # 如果右括号减去左括号的值不是小于等于2大于等于1\n", + " return False # 返回False\n", + " stack.pop() # 删除左括号\n", + " return not stack # 如果栈内没有值则返回True,否则返回False\n", + " \n", + "s = Solution()\n", + "print(s.isValid(\"([[])[]{}\"))\n", + "print(s.isValid(\"([])[]{}\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "与 思路 1 相同,但是更加容易理解的版本:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.isValid(\"([[])[]{}\"))\n", + "print(s.isValid(\"([])[]{}\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 扩展性和可理解性更强\n", + " - 使用字典类型来存储对应关系" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.isValid(\"([[])[]{}\"))\n", + "print(s.isValid(\"([])[]{}\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3\n", + "\n", + " - 括号匹配,我们可以换用另一种方式\n", + " - 首先,不管它是否符合第一个符号是左括号的要求,我们先把它放到list 中,作为栈,然后一个一个遍历,符合配对顺序就弹出,最终只需要判断是否栈为空就可以了" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "l_d = {\n", + " '{': -3,\n", + " '(': -2,\n", + " '[': -1,\n", + " ']': 1,\n", + " ')': 2,\n", + " '}': 3,\n", + "}\n", + " \n", + "class Solution:\n", + " def isValid(self, s):\n", + " l_s = []\n", + " for c_r in s:\n", + " if len(l_s) == 0:\n", + " l_s.append(c_r)\n", + " continue\n", + "\n", + " c_l = l_s[-1]\n", + "\n", + " if l_d[c_l] + l_d[c_r] == 0 and l_d[c_l] < 0:\n", + " l_s.pop()\n", + " else:\n", + " l_s.append(c_r)\n", + "\n", + " if len(l_s) == 0:\n", + " return True\n", + " else:\n", + " return False\n", + " \n", + "s = Solution()\n", + "print(s.isValid(\"([[])[]{}\"))\n", + "print(s.isValid(\"([])[]{}\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/020._valid_parentheses.md b/docs/Algorithm/Leetcode/Python/020._valid_parentheses.md new file mode 100644 index 00000000..85442a22 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/020._valid_parentheses.md @@ -0,0 +1,123 @@ +# 20. Valid Parentheses 有效的括号 + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/valid-parentheses +* https://leetcode-cn.com/problems/valid-parentheses/description + +> 内容描述 + +``` +给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 + +有效字符串需满足: + +左括号必须用相同类型的右括号闭合。 +左括号必须以正确的顺序闭合。 +注意空字符串可被认为是有效字符串。 + +示例 1: + +输入: "()" +输出: true +示例 2: + +输入: "()[]{}" +输出: true +示例 3: + +输入: "(]" +输出: false +示例 4: + +输入: "([)]" +输出: false +示例 5: + +输入: "{[]}" +输出: true +``` + +## 解题方案 + +> 思路 1 + +因为一共只有三种状况"(" -> ")", "[" -> "]", "{" -> "}". + +一遇到左括号就入栈,右括号出栈,这样来寻找对应 + +需要检查几件事: + +- 出现右括号时stack里还有没有东西 +- 出stack时是否对应 +- 最终stack是否为空 + +```python +class Solution(object): + def isValid(self, s): + """ + :type s: str + :rtype: bool + """ + leftP = '([{' + rightP = ')]}' + stack = [] + for char in s: + if char in leftP: + stack.append(char) + if char in rightP: + if not stack: + return False + tmp = stack.pop() + if char == ')' and tmp != '(': + return False + if char == ']' and tmp != '[': + return False + if char == '}' and tmp != '{': + return False + return stack == [] +``` + +> 思路 2 + +* 扩展性和可理解性强 + +```python +class Solution: + def isValid(self, s): + """ + :type s: str + :rtype: bool + """ + if len(s) % 2 == 1: + return False + + index = 0 + stack = [i for i in s] + map1 = {"(": ")", "[": "]", "{": "}"} + + while len(stack) > 0: + # 判断索引是否超过边界 + if index >= len(stack)-1: + return False + + b = stack[index] + e = stack[index+1] + + if b not in map1.keys(): + return False + elif e in map1.keys(): + index += 1 + elif map1[b] == e: + stack.pop(index+1) + stack.pop(index) + index = 0 if index-1<0 else index-1 + else: + return False + + return stack == [] +``` diff --git a/docs/Algorithm/Leetcode/Python/021._merge_two_sorted_lists.md b/docs/Algorithm/Leetcode/Python/021._merge_two_sorted_lists.md new file mode 100644 index 00000000..40517726 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/021._merge_two_sorted_lists.md @@ -0,0 +1,48 @@ +### 21. Merge Two Sorted Lists + +题目: + + + + +难度: Easy + + +同样适用dummy head + +```python +class Solution(object): + def mergeTwoLists(self, l1, l2): + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ + if l1 == None: + return l2 + if l2 == None: + return l1 + + dummy = ListNode(-1) + cur = dummy + + while l1 and l2: + if l1.val < l2.val: + cur.next = l1 + l1 = l1.next + else: + cur.next = l2 + l2 = l2.next + cur = cur.next + + if l1: + cur.next = l1 + else: + cur.next = l2 + return dummy.next + +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/022._generate_parentheses.md b/docs/Algorithm/Leetcode/Python/022._generate_parentheses.md new file mode 100644 index 00000000..ae14c908 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/022._generate_parentheses.md @@ -0,0 +1,88 @@ +### 22. Generate Parentheses + +题目: + + + +难度: + +Medium + + + + + +```python +class Solution(object): + def generateParenthesis(self,n): + """ + :type n: int + :rtype: List[str] + """ + self.res = [] + self.singleStr('', 0, 0, n) + return self.res + + def singleStr(self, s, left, right, n): + if left == n and right == n: + self.res.append(s) + if left < n: + self.singleStr(s + '(',left + 1, right,n) + if right < left: + self.singleStr(s + ')',left, right + 1, n) + +``` + + +非常牛逼的讲解,需要这样的人来给我们讲算法 + +####以Generate Parentheses为例,backtrack的题到底该怎么去思考? + + +所谓Backtracking都是这样的思路:在当前局面下,你有若干种选择。那么尝试每一种选择。如果已经发现某种选择肯定不行(因为违反了某些限定条件),就返回;如果某种选择试到最后发现是正确解,就将其加入解集 + +所以你思考递归题时,只要明确三点就行:选择 (Options),限制 (Restraints),结束条件 (Termination)。即“ORT原则”(这个是我自己编的) + + + + +对于这道题,在任何时刻,你都有两种选择: +1. 加左括号。 +2. 加右括号。 + +同时有以下限制: +1. 如果左括号已经用完了,则不能再加左括号了。 +2. 如果已经出现的右括号和左括号一样多,则不能再加右括号了。因为那样的话新加入的右括号一定无法匹配。 + +结束条件是: +左右括号都已经用完。 + +结束后的正确性: +左右括号用完以后,一定是正确解。因为1. 左右括号一样多,2. 每个右括号都一定有与之配对的左括号。因此一旦结束就可以加入解集(有时也可能出现结束以后不一定是正确解的情况,这时要多一步判断)。 + +递归函数传入参数: +限制和结束条件中有“用完”和“一样多”字样,因此你需要知道左右括号的数目。 +当然你还需要知道当前局面sublist和解集res。 + +因此,把上面的思路拼起来就是代码: + + if (左右括号都已用完) { + 加入解集,返回 + } + //否则开始试各种选择 + if (还有左括号可以用) { + 加一个左括号,继续递归 + } + if (右括号小于左括号) { + 加一个右括号,继续递归 + } + + + +你帖的那段代码逻辑中加了一条限制:“3. 是否还有右括号剩余。如有才加右括号”。这是合理的。不过对于这道题,如果满足限制1、2时,3一定自动满足,所以可以不判断3。 + +这题其实是最好的backtracking初学练习之一,因为ORT三者都非常简单明显。你不妨按上述思路再梳理一遍,还有问题的话再说。 + + + +以上文字来自 1point3arces的牛人解答 diff --git a/docs/Algorithm/Leetcode/Python/023._merge_k_sorted_lists.md b/docs/Algorithm/Leetcode/Python/023._merge_k_sorted_lists.md new file mode 100644 index 00000000..9cd97355 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/023._merge_k_sorted_lists.md @@ -0,0 +1,46 @@ +### 23. Merge k Sorted Lists + + + +题目: + + + +难度: +Hard + +思路: + +看到思路有heap,similar question有ugly number|| -> 这个是用heapq来解决的 + +那么就用heap吧? heapsort + +最简单的做法是只要每个list里面还有node,就把他们扔到minheap里面去,然后再把minheap pop,一个一个node连起来,听起来时间复杂度和空间复杂度都蛮高的。 +直接merge必然是不好的,因为没有利用有序这个点,应该做的是每次取来一个,然后再把应该的下一个放入 + +写到这里瞬间明白和ugly number ii像的点了,甚至感觉跟find in sorted matrix ii也像 + +```python +class Solution(object): + def mergeKLists(self, lists): + """ + :type lists: List[ListNode] + :rtype: ListNode + """ + import heapq + h = [] + for lst_head in lists: + if lst_head: + heapq.heappush(h, (lst_head.val, lst_head)) + cur = ListNode(-1) + dummy = cur + while h: + smallest_node = heapq.heappop(h)[1] + cur.next = smallest_node + cur = cur.next + if smallest_node.next: + heapq.heappush(h, (smallest_node.next.val, smallest_node.next)) + return dummy.next +``` + +当然还像merge two sorted list diff --git a/docs/Algorithm/Leetcode/Python/024._swap_nodes_in_pairs.md b/docs/Algorithm/Leetcode/Python/024._swap_nodes_in_pairs.md new file mode 100644 index 00000000..fc08296f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/024._swap_nodes_in_pairs.md @@ -0,0 +1,52 @@ +### 24. Swap Nodes in Pairs + +题目: + + + +难度 : Medium + +一眼就知道这个用递归做,```beats 96.06%``` +```python +class Solution(object): + def swapPairs(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if not head: + return None + if not head.next: + return head + tmp = head.next + head.next = self.swapPairs(head.next.next) + tmp.next = head + return tmp +``` + +或者用```loop```做,每个```node```关系要弄清楚, 又是巧用```dummy```,```dummy```大法对于```nodeList```的题目简直无敌!!!🐂批, 但是只```beats```了```69.40%``` + + +```python +class Solution(object): + def swapPairs(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if head == None or head.next == None: + return head + + dummy = ListNode(-1) + dummy.next = head + + cur = dummy + + while cur.next and cur.next.next: + next_one, next_two, next_three = cur.next, cur.next.next, cur.next.next.next + cur.next = next_two + next_two.next = next_one + next_one.next = next_three + cur = next_one + return dummy.next +``` diff --git a/docs/Algorithm/Leetcode/Python/026._Remove_Duplicates_from_Sorted_Array.md b/docs/Algorithm/Leetcode/Python/026._Remove_Duplicates_from_Sorted_Array.md new file mode 100644 index 00000000..23b43561 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/026._Remove_Duplicates_from_Sorted_Array.md @@ -0,0 +1,73 @@ +### 26. Remove Duplicates from Sorted Array + + + +题目: + + + +难度: +Easy + +思路: +因为题目说了是```sorted array```,所以只需要不停判断当前位置值和下一位置是否相等,若相等则```pop掉当前值```,否则```move```到下一位置做重复判断 + + +```python +class Solution(object): + def removeDuplicates(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + i = 0 + while i < (len(nums) - 1): + if nums[i] == nums[i+1]: + nums.remove(nums[i]) + else: + i += 1 + return len(nums) +``` + + +这里代码用```while loop```而不用```for loop```是因为```pop```操作之后```nums```的长度会变化 + +如:```for i in range(len(nums)-1)```实际上固定了```range```里面的值了,不会二次判断 + +``` +n = 10 +for i in range(n): + n = n - 1 # 尽管n在变化 + print(i) + +上面这段代码的输出结果为: + +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +``` + + + + + + + + + + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/027._Remove_Element.md b/docs/Algorithm/Leetcode/Python/027._Remove_Element.md new file mode 100644 index 00000000..3603a5b3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/027._Remove_Element.md @@ -0,0 +1,25 @@ +### 27. Remove Element + + + +题目: + + + +难度: +Easy + +瞬秒 + +```python +class Solution(object): + def removeElement(self, nums, val): + """ + :type nums: List[int] + :type val: int + :rtype: int + """ + while val in nums: + nums.remove(val) + return len(nums) +``` diff --git a/docs/Algorithm/Leetcode/Python/028._implement_strstr().md b/docs/Algorithm/Leetcode/Python/028._implement_strstr().md new file mode 100644 index 00000000..cecd6a5e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/028._implement_strstr().md @@ -0,0 +1,47 @@ +### 28. Implement strStr() + +题目: + + + + +难度: + +Easy + + +一行解法如何? +```python +class Solution(object): + def strStr(self, haystack, needle): + """ + :type haystack: str + :type needle: str + :rtype: int + """ + return haystack.find(needle) +``` + + +这个题目其实可以引来一大类,那就是关于string的算法,但是此处先用暴力算法来AC,然后再来细读/品味别的string相关算法吧。 + +虽然是暴力算法,但是也不容易写对啊 +```python +class Solution(object): + def strStr(self, haystack, needle): + """ + :type haystack: str + :type needle: str + :rtype: int + """ + if not needle: + return 0 + for i in xrange(len(haystack) - len(needle) + 1): + if haystack[i] == needle[0]: + j = 1 + while j < len(needle) and haystack[i+j] == needle[j]: + j += 1 + if j == len(needle): + return i + return -1 +``` diff --git a/docs/Algorithm/Leetcode/Python/030._Substring_with_Concatenation_of_All_Words.md b/docs/Algorithm/Leetcode/Python/030._Substring_with_Concatenation_of_All_Words.md new file mode 100644 index 00000000..0dd9eea2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/030._Substring_with_Concatenation_of_All_Words.md @@ -0,0 +1,54 @@ +### 30. Substring with Concatenation of All Words + +题目: + + + +难度 : Hard + + + +```python +class Solution(object): + def findSubstring(self, s, words): + """ + :type s: str + :type words: List[str] + :rtype: List[int] + """ + res = [] + if len(words) == 0 or len(s) < len(words) * len(words[0]): + return res + n, m, wl = len(s), len(words), len(words[0]) + maps, cur_map = {}, {} + maps = collections.Counter(words) + for i in range(wl): + count, start, r = 0, i, i + while r + wl <= n: + string = s[r:r+wl] + if string in maps: + cur_map[string] = cur_map.get(string, 0) + 1 + if cur_map[string] <= maps[string]: + count += 1 + while cur_map[string] > maps[string]: + tmp = s[start:start+wl] + cur_map[tmp] -= 1 + start += wl + if cur_map[tmp] < maps[tmp]: + count -= 1 + if count == m: + res.append(start) + tmp = s[start:start+wl] + cur_map[tmp] -= 1 + start += wl + count -= 1 + else: + cur_map = {} + count = 0 + start = r + wl + r += wl + cur_map = {} + return res + + +``` diff --git a/docs/Algorithm/Leetcode/Python/031._next_permutation.md b/docs/Algorithm/Leetcode/Python/031._next_permutation.md new file mode 100644 index 00000000..69d810cb --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/031._next_permutation.md @@ -0,0 +1,103 @@ + +### 31. Next Permutation + + +题目: + + + +难度: + +Medium + +参照wikipedia: + + + +首先,关于什么是全排列不做解释。如果一个排列为A,下一个排列为A_NEXT,那么A_NEXT一定与A有尽可能长的公共前缀。 + +看具体例子,一个排列为124653,如何找到它的下一个排列,因为下一个排列一定与124653有尽可能长的前缀,所以,脑洞大开一下,从后面往前看这个序列,如果后面的若干个数字有下一个排列,问题就得到了解决。 + +第一步:找最后面1个数字的下一个全排列。 + +124653,显然最后1个数字3不具有下一个全排列。 + +第二步:找最后面2个数字的下一个全排列。 + +124653,显然最后2个数字53不具有下一个全排列。 + +第三步:找最后面3个数字的下一个全排列。 + +124653,显然最后3个数字653不具有下一个全排列。 + + +------插曲:到这里相信大家已经看出来,如果一个序列是递减的,那么它不具有下一个排列。 + + +第四步:找最后面4个数字的下一个全排列。 + +124653,我们发现显然最后4个数字4653具有下一个全排列。因为它不是递减的,例如6453,5643这些排列都在4653的后面。 + + +我们总结上面的操作,并总结出重复上面操作的两种终止情况: + +1:从后向前比较相邻的两个元素,直到前一个元素小于后一个元素,停止 + +2:如果已经没有了前一个元素,则说明这个排列是递减的,所以这个排列是没有下一个排列的。 + + +124653这个排列终止情况是上面介绍的第一种,从后向前比较相邻的2个元素,遇到4<6的情况停止。 + +并且我们可以知道: + +1:124653和它的下一个排列的公共前缀为12(因为4653存在下一个排列,所以前面的数字12保持不变) + +2:4后面的元素是递减的(上面介绍的终止条件是前一个元素小于后一个元素,这里是4<6) + + +现在,我们开始考虑如何找到4653的下个排列,首先明确4后面的几个数字中至少有一个大于4. + +4肯定要和653这3个数字中大于4的数字中(6,5)的某一个进行交换。这里就是4要和6,5中的某一个交换,很明显要和5交换,如果找到这样的元素呢,因为我们知道4后面的元素是递减的,所以在653中从后面往前查找,找到第一个大于4的数字,这就是需要和4进行交换的数字。这里我们找到了5,交换之后得到的临时序列为5643.,交换后得到的643也是一个递减序列。 + + +所以得到的4653的下一个临时序列为5643,但是既然前面数字变大了(4653--->5643),后面的自然要变为升序才行,变换5643得到5346. + +所以124653的下一个序列为125346. + +看一个permutation,比如 + +125430 + + +- 从末尾开始,找到decreasing subsequence,5430,因为来调5330无论怎么调,都不可能有比它更小的,数也被自然的分成两部分(1,2) 和 (5,4,3,0) +- 下一步是找这个sequence里面第一个比前面部分,比2大的,3,也很容易理解,因为下一个必定是(1,3)打头 +- 交换 3和2 ,变成 (1,3,5,4,2,0),再把后面的部分reverse,得到后面部分可得到的最小的 + +这个时候,得到下一个sequence 130245 + +AC 代码 + +```python +class Solution(object): + def nextPermutation(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + if len(nums) <= 1: + return + idx = 0 + for i in range(len(nums)-1, 0, -1): + if nums[i] > nums[i-1]: # find first number which is smaller than it's after number + idx = i + break + if idx != 0: # if the number exist,which means that the nums not like{5,4,3,2,1} + for i in range(len(nums)-1, idx-1, -1): + if nums[i] > nums[idx-1]: + nums[i], nums[idx-1] = nums[idx-1], nums[i] + break + + nums[idx:] = nums[idx:][::-1] +``` + + diff --git a/docs/Algorithm/Leetcode/Python/032._longest_valid_parentheses.ipynb b/docs/Algorithm/Leetcode/Python/032._longest_valid_parentheses.ipynb new file mode 100644 index 00000000..56e88640 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/032._longest_valid_parentheses.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# 032.longest-valid-parentheses 最长有效括号\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/longest-valid-parentheses/description\n", + " - 英文:https://leetcode.com/problems/longest-valid-parentheses\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。\n", + "\n", + "示例 1:\n", + "输入: \"(()\"\n", + "输出: 2\n", + "解释: 最长有效括号子串为 \"()\"\n", + "\n", + "示例 2:\n", + "输入: \")()())\"\n", + "输出: 4\n", + "解释: 最长有效括号子串为 \"()()\"\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + "**注:** 千万注意,这个题上来就坑了一下,题目没有说清楚一种情况,比如 (()) ,这种情况,有效括号子串是 4 ,而不是错误的。\n", + "\n", + "实际上,在看到这个最长有效括号的题目的时候,我就想到了之前我们做的一个题目。LeetCode 20 题,它的解法是如何使用堆栈判断括号序列是否可以成功配对。我们仍然可以将堆栈的思想延续到这里。\n", + "\n", + "每当遇到一个左括号或者是无法成对的右括号,就将它压入栈中,可以成对的括号则从栈中 pop 出。这样栈中剩下的就是无法成对的括号的下标。这时我们可以判断这些下标间的距离来获得最大的成对括号长度。 **在这里,我们需要先遍历一遍字符串,再遍历一下非空的堆栈。一定要注意,这里我们遍历的非空的栈存储的是没有匹配上的括号下标,匹配上的我们都已经做了pop 处理。**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "4\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def longestValidParentheses(self, s):\n", + " \"\"\"\n", + " :type s: str\n", + " :rtype: int\n", + " \"\"\"\n", + " # 创建一个 stack ,用来做 栈 的操作\n", + " stack = []\n", + " # 第一次遍历 s 字符串\n", + " for i in range(len(s)):\n", + " # 如果当前循环到的 字符 是 右括号,那就要 检查一下栈内是否有与之匹配的 左括号\n", + " if s[i] == ')':\n", + " # stack 如果不为空,并且 stack 的栈顶元素存储的下标在 s 字符串中是 左括号\n", + " if stack and s[stack[-1]] == '(':\n", + " # 将栈顶元素 pop 出来,与当前的 右括号 配对\n", + " stack.pop()\n", + " # 直接 continue\n", + " continue\n", + " stack.append(i)\n", + " # 设置 最大长度\n", + " max_length = 0\n", + " # 设置为当前字符串 s 的长度\n", + " next_index = len(s)\n", + " # 遍历 非空的栈\n", + " while stack:\n", + " # 当前的栈顶存储的 s 的下标\n", + " cur_index = stack.pop()\n", + " # 计算下一个有效的最长括号长度\n", + " cur_length = next_index - cur_index - 1\n", + " # 将之与 之前存储的 max_length 比较,留下较大值\n", + " max_length = max(cur_length, max_length)\n", + " # 下一个的有效括号的右索引赋值,接着进入下一次循环,一直到 stack 为空\n", + " next_index = cur_index\n", + " # 遍历到最后的时候,肯定 next_index 即是有效符号的长度,与 max_length 做比较,取较大值\n", + " return max(next_index, max_length)\n", + " \n", + " \n", + "s = Solution()\n", + "print(s.longestValidParentheses(\"()(())\"))\n", + "print(s.longestValidParentheses(\"()()(()\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + "使用动态规划(dynamic programming)思想来做这个问题。\n", + "\n", + "下面是 片刻 大佬想出来的,我感觉思想真的超棒。参考链接:http://www.cnblogs.com/George1994/p/7531574.html\n", + "\n", + "1. 用一个 dp 数组来存放以每个 index 为结尾的最长有效括号子串长度,例如:dp[3] = 2 代表以 index 为 3 结尾的最长有效括号子串长度为 2\n", + "2. 很明显,dp[i] 和 dp[i-1] 之间是有关系的。\n", + " - 当 dp[i] 所在的索引 i 在字符串 s 中代表的字符是 \"(\" 时,也就是 s[i] == '(' ,很显然,此时的 dp[i] 与之前的一个关系是 dp[i] = dp[i-1] + 0,也就是不用处理。\n", + " - 当 dp[i] 所在的索引 i 在字符串 s 中代表的字符是 \")\" 时,也就是 s[i] == ')' 时,如果在 dp[i-1] 的所表示的最长有效括号子串之前还有一个 '(' 与 s[i] 对应,那么 dp[i] = dp[i-1] + 2,并且还可以继续往前追溯(如果前面还能连接起来的话)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "4\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.longestValidParentheses(\"()(())\"))\n", + "print(s.longestValidParentheses(\"()()(()\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/032._longest_valid_parentheses.md b/docs/Algorithm/Leetcode/Python/032._longest_valid_parentheses.md new file mode 100644 index 00000000..7042c176 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/032._longest_valid_parentheses.md @@ -0,0 +1,87 @@ +# 32. longest-valid-parentheses 最长有效括号 + +**难度: 困难** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-valid-parentheses +* https://leetcode-cn.com/problems/longest-valid-parentheses/description + +> 内容描述 + +``` +给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 + +示例 1: + +输入: "(()" +输出: 2 +解释: 最长有效括号子串为 "()" +示例 2: + +输入: ")()())" +输出: 4 +解释: 最长有效括号子串为 "()()" +``` + +## 解题方案 + +> 思路 1 + +* 动态规划,参考[banananana](http://www.cnblogs.com/George1994/p/7531574.html) +1. 用一个```dp```数组来存放以每个```index```为结尾的最长有效括号子串长度,例如:```dp[3] = 2```代表以```index为3```结尾的最长有效括号子串长度为```2``` +2. 很明显```dp[i]```和```dp[i-1]```之间是有关系的 +- 当```s[i] == ‘(’```时,```dp[i]```显然为```0```, 由于我们初始化dp的时候就全部设为0了,所以这种情况压根不用写 +- 当```s[i] == ')'```时, 如果在```dp[i-1]```的所表示的最长有效括号子串之前还有一个```'('```与```s[i]```对应,那么```dp[i] = dp[i-1] + 2```, 并且还可以继续往前追溯(如果前面还能连起来的话) + +```python +class Solution(object): + def longestValidParentheses(self, s): + """ + :type s: str + :rtype: int + """ + if len(s) == 0: + return 0 + dp = [0 for i in range(len(s))] + for i in range(1, len(s)): + if s[i] == ')': + left = i - 1 - dp[i-1] + if left >= 0 and s[left] == '(': + dp[i] = dp[i-1] + 2 + if left > 0: # 这个是判断 left 前面是否能与后面继续连起来 + dp[i] += dp[left-1] + return max(dp) +``` + +> 思路 2 + +每当遇到一个左括号或者是无法成对的右括号,就将它压入栈中,可以成对的括号则从栈中 pop 出。这样栈中剩下的就是无法成对的括号的下标。这时我们可以判断这些下标间的距离来获得最大的成对括号长度。 在这里,我们需要先遍历一遍字符串,再遍历一下非空的堆栈。一定要注意,这里我们遍历的非空的栈存储的是没有匹配上的括号下标,匹配上的我们都已经做了pop 处理。 + + +```python +class Solution(object): + def longestValidParentheses(self, s): + """ + :type s: str + :rtype: int + """ + stack = [] + for i in range(len(s)): + if s[i] == ')': + if stack and s[stack[-1]] == '(': ## 这里要注意,不能想当然地用s[i-1],因为我们有些下标直接continue了没有存到栈中去 + stack.pop() + continue + stack.append(i) + max_length = 0 + next_index = len(s) + while stack: + cur_index = stack.pop() + cur_length = next_index - cur_index - 1 + max_length = max(cur_length, max_length) + next_index = cur_index + return max(next_index, max_length) +``` + diff --git a/docs/Algorithm/Leetcode/Python/033._search_in_rotated_sorted_array.md b/docs/Algorithm/Leetcode/Python/033._search_in_rotated_sorted_array.md new file mode 100644 index 00000000..c2e6eb74 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/033._search_in_rotated_sorted_array.md @@ -0,0 +1,53 @@ +### 33. Search in Rotated Sorted Array + +题目: + + + +难度: +Medium + + +思路: + + + +下面是rotated-array图解, + +![rotated-array图解](https://github.com/Lisanaaa/myTODOs/blob/master/rotated-array12:09:2017.jpg) + + +所以直接用二分,O(lg(n)) +- 如果是mid,return mid +- 如果mid在绿色线上,就对绿色线进行二分 +- 如果mid在红色线上,就对红色线进行二分 +- 都没找到,return -1 + + +```python +class Solution(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + l, r = 0, len(nums) - 1 + while l <= r: + mid = l + ((r - l) >> 2) + if nums[mid] == target: + return mid + if nums[mid] < nums[r]: + if nums[mid] < target <= nums[r]: + l = mid + 1 + else: + r = mid - 1 + else: + if nums[l] <= target < nums[mid]: + r = mid - 1 + else: + l = mid + 1 + return -1 +``` + + diff --git a/docs/Algorithm/Leetcode/Python/034._Search for a Range.md b/docs/Algorithm/Leetcode/Python/034._Search for a Range.md new file mode 100644 index 00000000..e5a7048b --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/034._Search for a Range.md @@ -0,0 +1,77 @@ +### 34. Search for a Range + + + +题目: + + https://leetcode.com/problems/search-for-a-range/ + + + +难度 : Medium + + + +思路: + +二分法,先找```target```出现的左边界,判断是否有```target```后再判断右边界 + +- 找左边界:二分,找到一个```index``` + - 该```index```对应的值为```target``` + - 并且它左边```index-1```对应的值不是```target```(如果```index```为```0```则不需要判断此条件) + - 如果存在```index```就将其```append```到```res```中 +- 判断此时```res```是否为空,如果为空,说明压根不存在```target```,返回```[-1, -1]``` +- 找右边界:二分,找到一个```index```(但是此时用于二分循环的```l```可以保持不变,```r```重置为```len(nums)-1```,这样程序可以更快一些) + - 该```index```对应的值为```target``` + - 并且它右边```index+1```对应的值不是```target```(如果```index```为```len(nums)-1```则不需要判断此条件) + - 如果存在```index```就将其```append```到```res```中 + + + +AC 代码 + + + + +```python +class Solution(object): + def searchRange(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + if not nums : return [-1, -1] + + res = [] + l, r = 0, len(nums)-1 + # search for left bound + while l <= r: + mid = l + ((r - l) >> 2) + if nums[mid] == target and (mid == 0 or nums[mid-1] != target): + res.append(mid) + break + if nums[mid] < target: + l = mid + 1 + else: + r = mid - 1 + if not res: + return [-1, -1] + # search for right bound + r = len(nums)-1 + while l <= r: + mid = l + ((r - l) >> 2) + if nums[mid] == target and (mid == len(nums)-1 or nums[mid+1] != target): + res.append(mid) + break + if nums[mid] > target: + r = mid - 1 + else: + l = mid + 1 + return res +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/035._search_insert_position.md b/docs/Algorithm/Leetcode/Python/035._search_insert_position.md new file mode 100644 index 00000000..1b14c88c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/035._search_insert_position.md @@ -0,0 +1,48 @@ +### 35. Search Insert Position + +题目: + + + +难度: + +Medium + +找到第一个比```target```大的值的```index```,如果没找到则返回```len(nums)```,但是代码中直接返回```i```值就行了 + +### 思路一:暴力 + +```python +class Solution(object): + def searchInsert(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + i = 0 + while nums[i] < target: + i += 1 + if i == len(nums): + return i + return i +``` +### 思路二:二分 + +```python +class Solution(object): + def searchInsert(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + left, right = 0, len(nums) - 1 + while left <= right: + mid = left + ((right - left) >> 2) + if nums[mid] < target: + left = mid + 1 + else: + right = mid - 1 + return left +``` diff --git a/docs/Algorithm/Leetcode/Python/038._Count_and_Say.md b/docs/Algorithm/Leetcode/Python/038._Count_and_Say.md new file mode 100644 index 00000000..c735ca18 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/038._Count_and_Say.md @@ -0,0 +1,98 @@ +### 38. Count and Say + +题目: + + + +难度: + +Easy + + +思路 + + +1. i代表字符下标,从0开始取值,也就是从第一个字符开始,因为要让i取到最后一个字符,并且后面还要进行i+1的操作,所以将原字符串随意加上一个‘*’字符防止溢出 +2. count代表此时已经连续相同的字符个数 +3. res代表最终输出的字符串 + +- 只要i下标对应的字符等于下一个字符,则sum和i都加1,无限循环 +- 如果i下标对应的字符不等于下一个字符了,则res应该加上str(sum)和i下标对应的那个字符,并且i加1,sum复原回0 + +``` +Examples of nth sequence + + 1. 1 + 2. 11 + 3. 21 + 4. 1211 + 5. 111221 + 6. 312211 + 7. 13112221 + 8. 1113213211 + 9. 31131211131221 + 10. 13211311123113112211 + +``` +```python +解法1 +class Solution(object): + def countAndSay(self, n): + """ + :type n: int + :rtype: str + """ + if n == 1: + return '1' + s = self.countAndSay(n-1) + '*' + res, count = '', 1 + for i in range(len(s)-1): + if s[i] == s[i+1]: + count += 1 + else: + res += str(count) + str(s[i]) + count = 1 + return res +``` +```python +解法2 +class Solution(object): + def countAndSay(self, n): + """ + :type n: int + :rtype: str + """ + res = '1' + for i in range(n-1): + res = ''.join([str(len(list(group))) + digit for digit, group in itertools.groupby(res)]) + return res +``` +详见[python进阶-ITERTOOLS模块小结](http://www.wklken.me/posts/2013/08/20/python-extra-itertools.html#itertoolsgroupbyiterable-key) + +```java +解法3 +class Solution { + public String countAndSay(int n) { + if(n == 1){ + return "1"; + } + //递归调用,然后对字符串处理 + String str = countAndSay(n-1) + "*";//为了str末尾的标记,方便循环读数 + char[] c = str.toCharArray(); + int count = 1; + String s = ""; + for(int i = 0; i < c.length - 1;i++){ + if(c[i] == c[i+1]){ + count++;//计数增加 + }else{ + s = s + count + c[i];//上面的*标记这里方便统一处理 + count = 1;//初始化 + } + } + return s; + + } +} +``` + + diff --git a/docs/Algorithm/Leetcode/Python/039._combination_sum.md b/docs/Algorithm/Leetcode/Python/039._combination_sum.md new file mode 100644 index 00000000..b5579c25 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/039._combination_sum.md @@ -0,0 +1,64 @@ +### 39. Combination Sum + +题目: + + + + +难度: + +Medium + + +最初的思路: + + +``` +res = [] +def combSum(candidates, target, valueList): + if target == 0: + res.append(valueList) + for candidate in candidates: + if candidate > target: + return + combSum(candidates, target - candidate, valueList + [candidate] ) + +``` + + +问题在于,有重复: + +``` +combSum([2,3,6,7],7,[]) + +res +Out[9]: [[2, 2, 3], [2, 3, 2], [3, 2, 2], [7]] +``` + +然后看了hint,除[2, 2, 3] 和 [2, 3, 2]这种重复的方式是, 把candidates先sort,然后用index的方式来处理。 + + +所以最终的除重大法如下,根据hint做出: + +```python +class Solution(object): + def combinationSum(self, candidates, target): + """ + :type candidates: List[int] + :type target: int + :rtype: List[List[int]] + """ + def dfs(remain, combo, index): + if remain == 0: + res.append(combo) + return + for i in range(index, len(candidates)): + if candidates[i] > remain: + break + dfs(remain - candidates[i], combo + [candidates[i]], i) + candidates = list(set(candidates)) + candidates.sort() + res = [] + dfs(target, [], 0) + return res +``` diff --git a/docs/Algorithm/Leetcode/Python/040._combination_sum_ii.md b/docs/Algorithm/Leetcode/Python/040._combination_sum_ii.md new file mode 100644 index 00000000..7abb448f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/040._combination_sum_ii.md @@ -0,0 +1,39 @@ +### 40. Combination Sum II + +题目: + + + + +难度: + +Medium + + +Combination Sum 已经AC,做了minor change. +- 现在不需要```set```化```candidates```了 +- 但是递归的时候```index```要从```i+1```开始了 +- 要判断```combo not in res```才```append```到```res```中去 + +```python +class Solution(object): + def combinationSum2(self, candidates, target): + """ + :type candidates: List[int] + :type target: int + :rtype: List[List[int]] + """ + def dfs(remain, combo, index): + if remain == 0 and combo not in res: + res.append(combo) + return + for i in range(index, len(candidates)): + if candidates[i] > remain: + break + dfs(remain - candidates[i], combo + [candidates[i]], i+1) + candidates.sort() + res = [] + dfs(target, [], 0) + return res + +``` diff --git a/docs/Algorithm/Leetcode/Python/041._First_Missing_Positive.md b/docs/Algorithm/Leetcode/Python/041._First_Missing_Positive.md new file mode 100644 index 00000000..e3439355 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/041._First_Missing_Positive.md @@ -0,0 +1,90 @@ +# 41. First Missing Positive +**难度: 困难** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/first-missing-positive/description/ + +> 内容描述 + +``` +Given an unsorted integer array, find the smallest missing positive integer. + +Example 1: + +Input: [1,2,0] +Output: 3 +Example 2: + +Input: [3,4,-1,1] +Output: 2 +Example 3: + +Input: [7,8,9,11,12] +Output: 1 +Note: + +Your algorithm should run in O(n) time and uses constant extra space. +``` + +## 解题方案 + +> 思路 1 + +题目要求O(n)时间和O(1)空间,所以我们知道先排序再循环找是不行的 + +因此我们可以这样,第一轮循环,找1(因为1是最小的正整数),如果1在,立马原地开始继续找2,以此类推,一轮循环结束后,我们记录下当前正在找的值i, +并开始第二轮循环,但是这次从i开始找了,然后以此类推,直到有一次循环我们要找的值没有变过,则代表它没出现过,返回它即可 + +可以看一个例子 +``` +[3,4,-1,1] + +第一轮循环:[1,1,1,2] +第二轮循环:[2,2,2,2] + +然后我们发现第二轮循环2没有变过了,所以2就是我们要的结果 +``` + +```python +class Solution(object): + def firstMissingPositive(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + old_missing, missing = 0, 1 + while old_missing != missing: + old_missing = missing + for i in range(len(nums)): + if nums[i] == missing: + missing += 1 + return missing +``` + +> 思路 2 + +如果不限制空间的话,我们用一个dict就可以解决, 时间是O(N) + + +```python +class Solution(object): + def firstMissingPositive(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums: + return 1 + lookup = {} + for i in nums: + lookup[i] = 1 + for i in range(1, max(nums)+2): + if i not in lookup: + return i +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/042._trapping_rain_water.md b/docs/Algorithm/Leetcode/Python/042._trapping_rain_water.md new file mode 100644 index 00000000..17e03b9e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/042._trapping_rain_water.md @@ -0,0 +1,39 @@ +### 42. Trapping Rain Water + + + +题目: + + + +难度: +Hard + +思路: + +题目有几个特性可用,bar width = 1,然后第一个和最后一个是不能trap water,其次中间的部分能trap多少水是看`左右高度差较低的那个 - 本身的高度` + +The 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. + +AC代码: + + +```python +class Solution(object): + def trap(self, height): + """ + :type height: List[int] + :rtype: int + """ + l, r, water, min_height = 0, len(height) - 1, 0, 0 + while l < r: + min_height = min(height[l], height[r]) + while l < r and height[l] <= min_height: + water += min_height - height[l] + l += 1 + while l < r and height[r] <= min_height: + water += min_height - height[r] + r -= 1 + return water + +``` diff --git a/docs/Algorithm/Leetcode/Python/043._multiply_strings.md b/docs/Algorithm/Leetcode/Python/043._multiply_strings.md new file mode 100644 index 00000000..6dd1e053 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/043._multiply_strings.md @@ -0,0 +1,54 @@ +# 43. Multiply Strings 字符串相乘 + +## 题目: + +* https://leetcode.com/problems/multiply-strings/> +* https://leetcode-cn.com/problems/multiply-strings/description/ + +## 难度: Medium + + +参考了别人的思路: + +1. m位的数字乘以n位的数字的结果最大为m+n位: + * 999*99 < 1000*100 = 100000,最多为3+2 = 5位数。 +2. 先将字符串逆序便于从最低位开始计算。 + + + +```python +class Solution(object): + def multiply(self, num1, num2): + """ + :type num1: str + :type num2: str + :rtype: str + """ + lookup = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9} # 节省查找时间,避免无休止使用ord函数来得到数字 + if num1 == '0' or num2 == '0': + return '0' + num1, num2 = num1[::-1], num2[::-1] + + tmp_res = [0 for i in range(len(num1)+len(num2))] + for i in range(len(num1)): + for j in range(len(num2)): + tmp_res[i+j] += lookup[num1[i]] * lookup[num2[j]] + + res = [0 for i in range(len(num1)+len(num2))] + for i in range(len(num1)+len(num2)): + res[i] = tmp_res[i] % 10 + if i < len(num1)+len(num2)-1: + tmp_res[i+1] += tmp_res[i]/10 + return ''.join(str(i) for i in res[::-1]).lstrip('0') # 去掉最终结果头部可能存在的‘0’ +``` + +觉得这样写才是最容易理解的,看一个具体的🌰: +``` +input: num1, num2 = '91', '91' +tmp_res = [1,18,81,0] +res = [1,8,2,8] + +最终返回 "8281" + +要注意最终返回头部可能会有‘0’,所以我们用lstrip去除一下 +``` diff --git a/docs/Algorithm/Leetcode/Python/044._wildcard_matching.md b/docs/Algorithm/Leetcode/Python/044._wildcard_matching.md new file mode 100644 index 00000000..e7d2755a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/044._wildcard_matching.md @@ -0,0 +1,44 @@ +###44. Wildcard Matching + +题目: + + + +难度: + +Hard + + + +做完Regular Expression Matching来做的这道题,按照DP思路run一下是超时,感觉是开心的,至少暂时没有报错了,有待优化,应该在dp的同时在贪心一下么。 + + + +超时代码 +``` +class Solution(object): + def isMatch(self, s, p): + """ + :type s: str + :type p: str + :rtype: bool + """ + m, n = len(s), len(p) + dp = [ [0 for i in xrange(n+1)] for j in xrange(m+1)] + + dp[0][0] = 1 + + # init the first line + for i in xrange(1,n+1): + if p[i-1] == '*': + dp[0][i] = dp[0][i-1] + + for i in xrange(1,m+1): + for j in xrange(1,n+1): + if p[j-1] == s[i-1] or p[j-1] == '?': + dp[i][j] = dp[i-1][j-1] + elif p[j-1] == '*': + dp[i][j] = dp[i][j-1] or dp[i-1][j] + + return dp[m][n] == 1 +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/045._Jump_Game_II.md b/docs/Algorithm/Leetcode/Python/045._Jump_Game_II.md new file mode 100644 index 00000000..ae8caf9a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/045._Jump_Game_II.md @@ -0,0 +1,43 @@ +### 45. Jump Game II + +题目: + + + +难度: + +Easy + + +思路 + +greedy solution, the current jump is ```[i, cur_end]```, and the ```cur_farthest``` is the farthest point +that all of point in ```[i, cur_end]``` can reach, whenever ```cur_farthest``` is larger than the last point' index, +return current ```jump+1```; whenever ```i``` reaches ```cur_end```, update ```cur_end``` to ```current cur_farthest```. +- Time: O(log(n)) +- Space: O(1) + +```python +class Solution(object): + def jump(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + # Note You can assume that you can always reach the last index. + cur_end, cur_farthest, step, n = 0, 0, 0, len(nums) + for i in range(n-1): + cur_farthest = max(cur_farthest, i + nums[i]) + if cur_farthest >= n - 1: + step += 1 + break + if i == cur_end: + cur_end = cur_farthest + step += 1 + return step + + + +``` + + diff --git a/docs/Algorithm/Leetcode/Python/046._permutations.md b/docs/Algorithm/Leetcode/Python/046._permutations.md new file mode 100644 index 00000000..07e337ec --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/046._permutations.md @@ -0,0 +1,56 @@ +### 46. Permutations + +题目: + + + +难度: + +Medium + + +每次取一个作为prefix, 剩下的继续做permutation,然后连接起来加入res中 + +```python +class Solution(object): + def permute(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + if len(nums) == 0: + return [] + if len(nums) == 1: + return [nums] + res = [] + for i in range(len(nums)): + prefix = nums[i] + rest = nums[:i] + nums[i+1:] + for j in self.permute(rest): + res.append([prefix]+j) + return res +``` + +还有介绍的基本无memory使用的算法: + + +``` +class Solution: + def permute(self, num): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + if len(num) == 0: yield [] + if len(num) == 1: yield [num] + res = [] + for i in range(len(num)): + x = num[i] + xs = num[:i] + num[i+1:] + for j in self.permute(xs): + res.append([x] + j) + yield res + +``` + +但是这个yield只是生产generator,要看结果还是要用for in 来查看res的。 diff --git a/docs/Algorithm/Leetcode/Python/047._permutations_ii.md b/docs/Algorithm/Leetcode/Python/047._permutations_ii.md new file mode 100644 index 00000000..37524812 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/047._permutations_ii.md @@ -0,0 +1,35 @@ +### 47. Permutations II + +题目: + + + +难度: + +Medium + +跟第46题一样,就是最后append的时候不一样,只有没有结果里面没有的才加入 + + +```python +class Solution(object): + def permuteUnique(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + if len(nums) == 0: + return [] + if len(nums) == 1: + return [nums] + res = [] + for i in range(len(nums)): + prefix = nums[i] + rest = nums[:i] + nums[i+1:] + for j in self.permuteUnique(rest): + if [prefix]+j not in res: + res.append([prefix]+j) + return res +``` + + diff --git a/docs/Algorithm/Leetcode/Python/048._rotate_image.md b/docs/Algorithm/Leetcode/Python/048._rotate_image.md new file mode 100644 index 00000000..5c727dd7 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/048._rotate_image.md @@ -0,0 +1,105 @@ +### 48. Rotate Image + + +题目: + + + +难度: + +Medium + + + + +思路一: + + +先将矩阵上下翻转,然后将矩阵中心对称翻转,即可实现顺时针90度旋转。 + + +- 上下翻转规律 [i][:] --> [n-1-i][:] +- 对角线变换的规律是 [i][j] --> [j][i] + + +例如: +``` +1 1 1 3 3 3 3 2 1 +2 2 2 -> 2 2 2 -> 3 2 1 +3 3 3 1 1 1 3 2 1 +``` + + +```python +class Solution(object): + def rotate(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: void Do not return anything, modify matrix in-place instead. + """ + n = len(matrix) + # 上下翻转 + for i in range(n/2): + matrix[i], matrix[n-1-i] = matrix[n-1-i], matrix[i] + # 主对角线翻转 + for i in range(n): + for j in range(i+1,n): + matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] +``` + + +思路二: + +参考这里 + + + +找规律,一次完成四个数的该有的变换 + +``` + +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 + +``` + +在思路一的解法下观察得出,每个元素的变换是 [x][y] -> [n-1-x][y] -> [y][n-1-x] -> [n-1-y][x] + + +```python +class Solution(object): + def rotate(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: void Do not return anything, modify matrix in-place instead. + """ + n = len(matrix) + for i in range(n/2): + for j in range(n-n/2): + matrix[i][j], matrix[~j][i], matrix[~i][~j], matrix[j][~i] = \ + matrix[~j][i], matrix[~i][~j], matrix[j][~i], matrix[i][j] +``` +这里的```[~i]``` 意思就是 ```[n-1-i]``` + +思路三: + +直接用zip函数,一行, 😂 + +```python +class Solution: + def rotate(self, A): + A[:] = zip(*A[::-1]) + # A[:] = map(list, zip(*A[::-1])) +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/049._group_anagrams_python.md b/docs/Algorithm/Leetcode/Python/049._group_anagrams_python.md new file mode 100644 index 00000000..1371afdb --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/049._group_anagrams_python.md @@ -0,0 +1,28 @@ +### 49. Group Anagrams python + +题目: + + + +难度 : Medium + +python大法好 + + +```python +class Solution(object): + def groupAnagrams(self, strs): + """ + :type strs: List[str] + :rtype: List[List[str]] + """ + mapx = {} + for i in strs: + x = ''.join(sorted(list(i))) + if x in mapx: + mapx[x].append(i) + else: + mapx[x] = [i] + return mapx.values() + +``` diff --git a/docs/Algorithm/Leetcode/Python/050._pow(x,_n).md b/docs/Algorithm/Leetcode/Python/050._pow(x,_n).md new file mode 100644 index 00000000..697863e2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/050._pow(x,_n).md @@ -0,0 +1,48 @@ +### 50. Pow(x, n) + +题目: + + + +难度: + +Medium + + +Recursive + +```python +class Solution(object): + def myPow(self, x, n): + """ + :type x: float + :type n: int + :rtype: float + """ + if n == 0: + return 1 + if n < 0: + return 1 / self.myPow(x, -n) + if n % 2 == 0: + return self.myPow(x*x, n/2) + else: + return x * self.myPow(x*x, n/2) + +``` +iterative + + +```python +class Solution: + def myPow(self, x, n): + if n < 0: + x = 1 / x + n = -n + pow = 1 + while n: + if n & 1: + pow *= x + x *= x + n >>= 1 + return pow +``` diff --git a/docs/Algorithm/Leetcode/Python/051._n-queens.md b/docs/Algorithm/Leetcode/Python/051._n-queens.md new file mode 100644 index 00000000..3e7c197c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/051._n-queens.md @@ -0,0 +1,38 @@ +### 51. N-Queens + +题目: + + + +难度: +Hard + +八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解[1]。 + +对于任意(x,y),如果要让新的点和它不能处于同一条横行、纵行或斜线上,则新点(p,q)必须要满足p+q != x+y 和p-q!= x-y, 前者针对左下右上斜线,后者针对左上右下斜线,两者同时都保证了不在同一条横行和纵行上。 + +代码中变量的含义: +- col_per_row: 每一行皇后的column位置组成的列表 +- cur_row:目前正在判断的row的index +- xy_diff:所有x-y组成的列表 +- xy_sum:所有x+y组成的列表 + +```python +class Solution(object): + def solveNQueens(self, n): + """ + :type n: int + :rtype: List[List[str]] + """ + def dfs(col_per_row, xy_diff, xy_sum): + cur_row = len(col_per_row) + if cur_row == n: + ress.append(col_per_row) + for col in range(n): + if col not in col_per_row and cur_row-col not in xy_diff and cur_row+col not in xy_sum: + dfs(col_per_row+[col], xy_diff+[cur_row-col], xy_sum+[cur_row+col]) + ress = [] + dfs([], [], []) + return [['.'*i + 'Q' + '.'*(n-i-1) for i in res] for res in ress] + +``` diff --git a/docs/Algorithm/Leetcode/Python/052._n-queens_ii.md b/docs/Algorithm/Leetcode/Python/052._n-queens_ii.md new file mode 100644 index 00000000..1d65adc1 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/052._n-queens_ii.md @@ -0,0 +1,46 @@ +### 52. N-Queens II + +题目: + + + +难度: +Hard + +思路参见recursion & backtracking + +n queens还是属于比较难的,需要花时间吃透的问题 + +八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解[1]。 + +对于任意(x,y),如果要让新的点和它不能处于同一条横行、纵行或斜线上,则新点(p,q)必须要满足p+q != x+y 和p-q!= x-y, 前者针对左下右上斜线,后者针对左上右下斜线,两者同时都保证了不在同一条横行和纵行上。 + +代码中变量的含义: +- col_per_row: 每一行皇后的column位置组成的列表 +- cur_row:目前正在判断的row的index +- xy_diff:所有x-y组成的列表 +- xy_sum:所有x+y组成的列表 + +```python +class Solution(object): + def totalNQueens(self, n): + """ + :type n: int + :rtype: int + """ + def dfs(col_per_row, xy_diff, xy_sum): + cur_row = len(col_per_row) + if cur_row == n: + ress.append(col_per_row) + for col in range(n): + if col not in col_per_row and cur_row-col not in xy_diff and cur_row+col not in xy_sum: + dfs(col_per_row+[col], xy_diff+[cur_row-col], xy_sum+[cur_row+col]) + ress = [] + dfs([], [], []) + return len(ress) + +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/053._maximum_subarray.ipynb b/docs/Algorithm/Leetcode/Python/053._maximum_subarray.ipynb new file mode 100644 index 00000000..1bbb8ab2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/053._maximum_subarray.ipynb @@ -0,0 +1,275 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 53. Maximum Subarray 最大子序和\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/maximum-subarray/description/\n", + " - 英文:https://leetcode.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", + "如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 可以用 O(N^2) 循环\n", + " - 从i开始,计算i到n,存比较大的sum\n", + " - 会超时,不会 AC" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "1\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def maxSubArray(self, nums):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :rtype: int\n", + " \"\"\"\n", + " # 设置为无穷小\n", + " ans = float('-inf')\n", + " # 这个循环控制子串的元素个数\n", + " for i in range(1, len(nums)):\n", + " # 这个循环控制子串从原始串的哪个位置开始计算\n", + " for j in range(len(nums)-i):\n", + " big = 0\n", + " big = sum(nums[j : j+i])\n", + " if big > ans:\n", + " ans = big\n", + " return ans\n", + "\n", + "s = Solution()\n", + "nums_1 = [-2,1,-3,4,-1,2,1,-5,4]\n", + "nums_2 = [1, -1]\n", + "print(s.maxSubArray(nums_1))\n", + "print(s.maxSubArray(nums_2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 使用动态规划\n", + " - ms(i) = max(ms[i-1] + a[i], a[i])\n", + " - 我们只需要知道,计算到 i 处的最大值的两种可能,一个是加上 a[i],另一个是从 a[i] 开始重新计算子串。\n", + " - 比较 ms[i-1]+a[i] 与 a[i] 的值的大小关系,如果前者小于后者,就说明,前面的子串的最大的和是负数,我们可以抛弃掉,而从 a[i] 处开始起头重新计算子串;如果前者大于后者,说明,前面的子串的最大的和是正数,我们可以加上 a[i] 继续计算。\n", + " - 可以 AC" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "1\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "nums_1 = [-2,1,-3,4,-1,2,1,-5,4]\n", + "nums_2 = [1, -1]\n", + "print(s.maxSubArray(nums_1))\n", + "print(s.maxSubArray(nums_2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3\n", + "\n", + "Kadane’s Algorithm wikipedia可以查到,然后一般的是负的可以还回0,这里需要稍作修改,参考:\n", + "http://algorithms.tutorialhorizon.com/kadanes-algorithm-maximum-subarray-problem/\n", + "\n", + "```\n", + "start:\n", + " max_so_far = a[0]\n", + " max_ending_here = a[0]\n", + "\n", + "loop 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", + "\n", + "return max_so_far\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "AC 代码如下:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "1\n" + ] + } + ], + "source": [ + "class 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", + " maxEnd = max(nums[i],maxEnd + nums[i])\n", + " maxSum = max(maxEnd,maxSum)\n", + " return maxSum\n", + " \n", + "s = Solution()\n", + "nums_1 = [-2,1,-3,4,-1,2,1,-5,4]\n", + "nums_2 = [1, -1]\n", + "print(s.maxSubArray(nums_1))\n", + "print(s.maxSubArray(nums_2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 4\n", + "\n", + "参见clrs 第71页,用divide and conquer,有伪码\n", + "\n", + "最大的 subarray sum 有三个可能,左半段或者右半段,或者跨越左右半段,\n", + "\n", + "速度比较慢,AC代码,复杂度O(NlogN)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Solution(object):\n", + " def maxSubArray(self, nums):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :rtype: int\n", + " \"\"\"\n", + " def find_max_crossing_subarray(nums, low, mid, high):\n", + " left_sum = float('-inf')\n", + " sum = 0\n", + " for i in xrange(mid,low-1,-1):\n", + " sum = sum + nums[i]\n", + " if sum > left_sum:\n", + " left_sum = sum\n", + "\n", + " right_sum = float('-inf')\n", + " sum = 0\n", + " for j in range(mid+1,high+1):\n", + " sum = sum + nums[j]\n", + " if sum > right_sum:\n", + " right_sum = sum\n", + "\n", + " return left_sum + right_sum\n", + "\n", + " def find_max_subarray(nums,low,high):\n", + " if low == high: \n", + " return nums[low]\n", + " else:\n", + " mid = (low + high) / 2\n", + " left_sum = find_max_subarray(nums, low, mid)\n", + " right_sum = find_max_subarray(nums,mid+1,high)\n", + " cross_sum = find_max_crossing_subarray(nums,low,mid,high)\n", + " # print left_sum, right_sum, cross_sum\n", + " # print mid, low, high\n", + " return max(left_sum, right_sum, cross_sum)\n", + "\n", + " return find_max_subarray(nums, 0, len(nums)-1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/053._maximum_subarray.md b/docs/Algorithm/Leetcode/Python/053._maximum_subarray.md new file mode 100644 index 00000000..ac95e00f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/053._maximum_subarray.md @@ -0,0 +1,156 @@ +# 53. Maximum Subarray 最大子序和 + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/maximum-subarray +* https://leetcode-cn.com/problems/maximum-subarray/description + +> 内容描述 + +``` +给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 + +示例: + +输入: [-2,1,-3,4,-1,2,1,-5,4], +输出: 6 +解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 + +进阶: + +如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 +``` + +## 解题方案 + +> 思路 1 + +O(N^2) + +从i开始,计算i到n,存比较大的sum,会超时 + +``` +class Solution(object): + def maxSubArray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = len(nums) + m = float('-inf') + for i in range(n): + s = 0 + for j in range(i,n): + s = s + nums[j] + m = max(m,s) + return m +``` + +> 思路 2 + +* 动态规划(只关注:当然值 和 当前值+过去的状态,是变好还是变坏,一定是回看容易理解) +* ms(i) = max(ms[i-1]+ a[i],a[i]) +* 到i处的最大值两个可能,一个是加上a[i], 另一个从a[i]起头,重新开始。可以AC + +```python +class Solution(object): + def maxSubArray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = len(nums) + maxSum = [nums[0] for i in range(n)] + for i in range(1,n): + maxSum[i] = max(maxSum[i-1] + nums[i], nums[i]) + return max(maxSum) +``` + +> 思路 3 + +Kadane’s Algorithm wikipedia可以查到,然后一般的是负的可以还回0,这里需要稍作修改,参考 + + + + +``` +start: + max_so_far = a[0] + max_ending_here = a[0] + +loop i= 1 to n + (i) max_end_here = Max(arrA[i], max_end_here+a[i]); + (ii) max_so_far = Max(max_so_far,max_end_here); + +return max_so_far + +``` + +AC代码: + +```python +class Solution(object): + def maxSubArray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = len(nums) + maxSum , maxEnd = nums[0], nums[0] + + for i in range(1,n): + maxEnd = max(nums[i],maxEnd + nums[i]) + maxSum = max(maxEnd,maxSum) + return maxSum +``` + +> 思路 4 + +参见clrs 第71页,用divide and conquer,有伪码 + +最大的subarray sum有三个可能,左半段或者右半段,或者跨越左右半段, + +速度比较慢,AC代码,复杂度O(NlogN) + +``` +class Solution(object): + def maxSubArray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + def find_max_crossing_subarray(nums, low, mid, high): + left_sum = float('-inf') + sum = 0 + for i in xrange(mid,low-1,-1): + sum = sum + nums[i] + if sum > left_sum: + left_sum = sum + + right_sum = float('-inf') + sum = 0 + for j in range(mid+1,high+1): + sum = sum + nums[j] + if sum > right_sum: + right_sum = sum + + return left_sum + right_sum + + def find_max_subarray(nums,low,high): + if low == high: + return nums[low] + else: + mid = (low + high) / 2 + left_sum = find_max_subarray(nums, low, mid) + right_sum = find_max_subarray(nums,mid+1,high) + cross_sum = find_max_crossing_subarray(nums,low,mid,high) + # print left_sum, right_sum, cross_sum + # print mid, low, high + return max(left_sum, right_sum, cross_sum) + + return find_max_subarray(nums, 0, len(nums)-1) +``` diff --git a/docs/Algorithm/Leetcode/Python/054._spiral_matrix.md b/docs/Algorithm/Leetcode/Python/054._spiral_matrix.md new file mode 100644 index 00000000..ca2219ec --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/054._spiral_matrix.md @@ -0,0 +1,139 @@ +### 54. Spiral Matrix + +题目: + + + +难度: +Medium + + +参考别人的代码,一开始觉得很有递归性,根据奇偶不同来写,递归太难写。 + +然后想到了loop,再想,可能有更优trick,事实证明并没有。 + +用四个变量来控制边界,然后因为方向总是:→↓←↑ 左右下上 + + + + +```python +class Solution(object): + def spiralOrder(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: List[int] + """ + if matrix == [] : return [] + res = [] + maxUp = maxLeft = 0 + maxDown = len(matrix) - 1 + maxRight = len(matrix[0]) - 1 + direction = 0 # 0 go right, 1 go down, 2 go left, 3 up + while True: + if direction == 0: #go right + for i in range(maxLeft, maxRight+1): + res.append(matrix[maxUp][i]) + maxUp += 1 + elif direction == 1: # go down + for i in range(maxUp, maxDown+1): + res.append(matrix[i][maxRight]) + maxRight -= 1 + elif direction == 2: # go left + for i in reversed(range(maxLeft, maxRight+1)): + res.append(matrix[maxDown][i]) + maxDown -= 1 + else: #go up + for i in reversed(range(maxUp, maxDown+1)): + res.append(matrix[i][maxLeft]) + maxLeft +=1 + if maxUp > maxDown or maxLeft > maxRight: + return res + direction = (direction + 1 ) % 4 +``` + +以上的写法非常精妙,看看我自己用同样的思路写的|||| + +```python +class Solution(object): + def spiralOrder(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: List[int] + """ + if len(matrix) == 0 : return [] + + left = 0 + up = 0 + down = len(matrix) - 1 + right = len(matrix[0]) -1 + + # 0 -> right, 1 -> down, 2-> left, 3 -> up + direction = 0 + + # start location + x, y = 0,0 + res = [] + + while True: + if left > right or up > down: + return res + + if direction == 0 : + while y <= right: + res.append(matrix[up][y]) + y += 1 + up += 1 + x = up + direction = 1 + continue + + if direction == 1: + while x <= down: + res.append(matrix[x][right]) + x += 1 + right -= 1 + y = right + direction = 2 + continue + + if direction == 2: + while y >= left: + res.append(matrix[down][y]) + y -= 1 + down -= 1 + x = down + direction = 3 + continue + + if direction == 3: + while x >= up: + res.append(matrix[x][left]) + x -= 1 + left += 1 + y = left + direction = 0 + continue + +``` + +明显别人的代码写的更精妙,因为这里两个boundary都很明确,所以用for in range就能很好的解决问题了. + + + + + +----------- + +最后放一个无敌一行,怕你看完不想看上面的代码了 +```python +class Solution(object): + def spiralOrder(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: List[int] + """ + return matrix and list(matrix.pop(0)) + self.spiralOrder(zip(*matrix)[::-1]) +``` + +oh, my god! diff --git a/docs/Algorithm/Leetcode/Python/055._jump_game.md b/docs/Algorithm/Leetcode/Python/055._jump_game.md new file mode 100644 index 00000000..1de4f1d0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/055._jump_game.md @@ -0,0 +1,39 @@ +### 55. Jump Game + +题目: + + + +难度: + +Medium + + +问题出现在一旦有0,而且这个0是不可跨过的那么无解,无法达到 + + +看了hint,根本不用这个数组,直接用一个数来记录可达最远距离,非常巧妙 + + +```python +class Solution(object): + def canJump(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + if not nums: + return True + if len(nums) == 1: + return True + n = len(nums) + idx, reach = 0, 0 + while idx < n-1 and idx <= reach: # idx <= reach是为了处理nums[idx] == 0的情况,若idx>reach说明已经失败了 + reach = max(reach, idx+nums[idx]) + idx += 1 + return reach >= n-1 +``` + +idx记录当前loop位置,reach记录当前可到位置 + +注意这里的while循环的条件是 `idx < n-1 and idx <= reach`,之所以加上 `idx <= reach` 是因为如果```idx > reach```说明```idx```层不可达,其实也可以直接terminate. diff --git a/docs/Algorithm/Leetcode/Python/056._Merge_Intervals.md b/docs/Algorithm/Leetcode/Python/056._Merge_Intervals.md new file mode 100644 index 00000000..1f5ab7aa --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/056._Merge_Intervals.md @@ -0,0 +1,31 @@ +### 56. Merge Intervals + +题目: + + + +难度: + +Medium + + +Just go through the intervals sorted by start coordinate and +either combine the current interval with the previous one if they overlap, or add it to the output by itself if they don’t. + +```python +class Solution(object): + def merge(self, intervals): + """ + :type intervals: List[Interval] + :rtype: List[Interval] + """ + res = [] + for i in sorted(intervals, key = lambda i: i.start): + if res and i.start <= res[-1].end: + res[-1].end = max(i.end, res[-1].end) + else: + res.append(i) + return res +``` + + diff --git a/docs/Algorithm/Leetcode/Python/058._length_of_last_word.md b/docs/Algorithm/Leetcode/Python/058._length_of_last_word.md new file mode 100644 index 00000000..b9ec0160 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/058._length_of_last_word.md @@ -0,0 +1,45 @@ +### 58. Length of Last Word + +题目: + + + +难度 : Easy + +我的解法: + +```python +class Solution(object): + def lengthOfLastWord(self, s): + """ + :type s: str + :rtype: int + """ + s = s[::-1].strip() + return s.find(' ') if s.find(' ') != -1 else len(s) +``` +作弊式做法 + +```python +class Solution(object): + def lengthOfLastWord(self, s): + """ + :type s: str + :rtype: int + """ + lst = s.split() + if len(lst) >= 1: + return len(lst[-1]) + return 0 +``` +split()方法最低可以分0组,split(' ')最低可以分1组 +```python +一行解法: +class Solution(object): + def lengthOfLastWord(self, s): + """ + :type s: str + :rtype: int + """ + return len(s.strip().split(" ")[-1]) +``` diff --git a/docs/Algorithm/Leetcode/Python/059._spiral_matrix_ii.md b/docs/Algorithm/Leetcode/Python/059._spiral_matrix_ii.md new file mode 100644 index 00000000..42ae5266 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/059._spiral_matrix_ii.md @@ -0,0 +1,67 @@ +### 59. Spiral Matrix II + +题目: + + + +难度: +Medium + +和Spiral Matrix的思路基本一致 + +也许还有待挖掘trick + + +```python +class Solution(object): + def generateMatrix(self,n): + """ + :type n: int + :rtype: List[List[int]] + """ + curNum = 0 + matrix = [[0 for i in range(n)] for j in range(n)] + maxUp = maxLeft = 0 + maxDown = maxRight = n - 1 + direction = 0 + while True: + if direction == 0: #go right + for i in range(maxLeft, maxRight+1): + curNum += 1 + matrix[maxUp][i] = curNum + maxUp += 1 + elif direction == 1: # go down + for i in range(maxUp, maxDown+1): + curNum += 1 + matrix[i][maxRight] = curNum + maxRight -= 1 + elif direction == 2: # go left + for i in reversed(range(maxLeft, maxRight+1)): + curNum += 1 + matrix[maxDown][i] = curNum + maxDown -= 1 + else: #go up + for i in reversed(range(maxUp, maxDown+1)): + curNum += 1 + matrix[i][maxLeft] = curNum + maxLeft +=1 + if curNum >= n*n: + return matrix + direction = (direction + 1 ) % 4 +``` + +Same idea with [spiral matrix I](https://github.com/Lisanaaa/thinking_in_lc/blob/master/054._spiral_matrix.md) +```python +class Solution(object): + def generateMatrix(self, n): + """ + :type n: int + :rtype: List[List[int]] + """ + res = [] + l = n * n + 1 + while l > 1: + l, r = l - len(res), l + res = [range(l, r)] + zip(*res[::-1]) + return res +``` diff --git a/docs/Algorithm/Leetcode/Python/060._permutation_sequence.md b/docs/Algorithm/Leetcode/Python/060._permutation_sequence.md new file mode 100644 index 00000000..81935e25 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/060._permutation_sequence.md @@ -0,0 +1,93 @@ +###60. Permutation Sequence + +题目: + + + +难度: + +Medium + + + +偷懒,用46的方法,会超时 + +``` + +class Solution(object): + def getPermutation(self, n, k): + """ + :type n: int + :type k: int + :rtype: str + """ + self.result = [] + s = "" + for i in range(1, n+1): + s += str(i) + self.recPermute("",s,k) + return self.result[-1] + + + def recPermute(self, sofar, rest, k): + if rest == "": + if len(self.result) == k: + return + self.result.append(sofar) + else: + for i in xrange(len(rest)): + nnext = sofar + rest[i] + remaining = rest[:i] + rest[i+1:] + self.recPermute(nnext, remaining, k) +``` + + +然后其实有规律的,比如 + +``` +1 "123" +2 "132" +3 "213" +4 "231" +5 "312" +6 "321" +``` + +是第n个数 + 余下的n-1个数的permutation + + +k = 1 就是所有的顺序排列 +k = n! 是所有的逆序排列 + +对于余下的也是递归,比如 + + +k < (n-1)! 1 + (n-1)个数的全排列的第k个 +k < 2*(n-1)! 2 + (n-1)个数的顺序全排列的第k个 + + +发现思路对了,但是implement还有点困难. + +看了一个最为精妙的解法 + +``` +class Solution(object): + def getPermutation(self, n, k): + """ + :type n: int + :type k: int + :rtype: str + """ + seq, k, fact = '', k-1, math.factorial(n-1) + perm = [i for i in range(1, n+1)] + for i in reversed(xrange(n)): + curr = perm[k/fact] + seq += str(curr) + perm.remove(curr) + if i > 0: + k %= fact + fact /= i + return seq +``` + + diff --git a/docs/Algorithm/Leetcode/Python/061._rotate_list.md b/docs/Algorithm/Leetcode/Python/061._rotate_list.md new file mode 100644 index 00000000..a26319d1 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/061._rotate_list.md @@ -0,0 +1,58 @@ + +###61. Rotate List + + +题目: + + + +难度: + +Medium + +- k可能比list的size大,需要做一个取余准备 +- 计算list size的同时把tail也记录下来,方便之后把tail的next指向原本的head +- 利用之前的到末端的kth node + + +AC 代码 + +``` +class Solution(object): + def rotateRight(self, head, k): + if head == None or k == 0 : + return head + + cur = head + size = 1 + while cur.next: + size += 1 + cur = cur.next + + tail = cur + + k = k % size + + p = self.findKth(head,k) + + tail.next = head + head = p.next + p.next = None + return head + + def findKth(self,head, k): + dummy = ListNode(-1) + dummy.next = head + p = dummy + q = dummy + + for i in range(k): + q = q.next + + while q.next: + p = p.next + q = q.next + return p +``` + + diff --git a/docs/Algorithm/Leetcode/Python/062._unique_paths.ipynb b/docs/Algorithm/Leetcode/Python/062._unique_paths.ipynb new file mode 100644 index 00000000..372560e0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/062._unique_paths.ipynb @@ -0,0 +1,167 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 062.unique_paths 不同路径\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/unique-paths/description\n", + " - 英文:https://leetcode.com/problems/unique-paths\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。\n", + "\n", + "机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。\n", + "\n", + "问总共有多少条不同的路径?\n", + "\n", + "说明:m 和 n 的值均不超过 100。\n", + "\n", + "示例 1:\n", + "输入: m = 3, n = 2\n", + "输出: 3\n", + "解释:\n", + "从左上角开始,总共有 3 条路径可以到达右下角。\n", + "1. 向右 -> 向右 -> 向下\n", + "2. 向右 -> 向下 -> 向右\n", + "3. 向下 -> 向右 -> 向右\n", + "\n", + "示例 2:\n", + "输入: m = 7, n = 3\n", + "输出: 28\n", + "\n", + "例如,下图是一个3 x 7 的网格。有多少可能的路径?\n", + "```\n", + "\n", + "![](img/robot_maze.png)\n", + "\n", + "## 解决方案\n", + "\n", + "> 思路 1\n", + "\n", + "数学思路。\n", + "\n", + "本质上,这道题就是排列组合,一共走 m + n - 步,其中 m - 1 步是向右边走,所以不就是从 m + n - 2 中选择 m-1 个的问题,阶乘问题,so easy !妈妈再也不用担心我的学习!!!这个方法 beats 99.97% 。\n", + "\n", + "补充一下,math 模块中自带 factorial 函数,只要 import math 之后调用即可。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "28.0\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.uniquePaths(7,3))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "> 思路 2\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 |" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "28\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.uniquePaths(7,3))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/062._unique_paths.md b/docs/Algorithm/Leetcode/Python/062._unique_paths.md new file mode 100644 index 00000000..eb7f96d5 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/062._unique_paths.md @@ -0,0 +1,109 @@ +# 62. unique paths 不同路径 + +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/unique-paths +* https://leetcode-cn.com/problems/unique-paths/description + +> 内容描述 + +``` +一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 + +机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 + +问总共有多少条不同的路径? +``` + +![](https://leetcode-cn.com/img/problemset/robot_maze.png) + +``` +例如,上图是一个7 x 3 的网格。有多少可能的路径? + +说明:m 和 n 的值均不超过 100。 + +> 示例 1: + +输入: m = 3, n = 2 +输出: 3 +解释: +从左上角开始,总共有 3 条路径可以到达右下角。 +1. 向右 -> 向右 -> 向下 +2. 向右 -> 向下 -> 向右 +3. 向下 -> 向右 -> 向右 + +> 示例 2: + +输入: m = 7, n = 3 +输出: 28 +``` + +## 解题方案 + +> 思路 1 + +| | | | +| - | - | - | +| 1 | 1 | 1 | +| 1 | 2 | 3 | +| 1 | 3 | 6 | +| 1 | 4 | 10 | +| 1 | 5 | 15 | +| 1 | 6 | 21 | +| 1 | 7 | 28 | + +```python +class Solution: + def uniquePaths(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + if m < 1 or n < 1: + return 0 + dp = [0] *n + dp[0] = 1 + for i in range(0,m): + for j in range(1,n): + dp[j] += dp[j-1] + return dp[n-1] +``` + +> 思路 2 + +这道题我一看到就觉得这不就是排列组合吗,一共走m+n-2步, 其中m-1步是向右边走,所以不就是从m+n-2中选m-1个的问题吗,阶乘问题,so easy! 妈妈 +再也不用担心我的学习!!这个方法```beats 99.97%``` + +```python +class Solution(object): + def uniquePaths(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + def factorial(num): + res = 1 + for i in range(1, num+1): + res *= i + return res + return factorial(m+n-2)/factorial(n-1)/factorial(m-1) +``` +另外补充一句,我发现math模块里面自带factorial函数,只要import math之后调用即可, + + + + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/064._minimum_path_sum.ipynb b/docs/Algorithm/Leetcode/Python/064._minimum_path_sum.ipynb new file mode 100644 index 00000000..2844c495 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/064._minimum_path_sum.ipynb @@ -0,0 +1,160 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 064. Minimum Path Sum 最小路径和\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/minimum-path-sum/description\n", + " - 英文:https://leetcode.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", + "使用 动态规划 ,我们考虑到,一个位于 [i][j] 位置的格子,到达它的路径只有 2 条:1 条是从上到下到达这个格子([i-1][j] -> [i][j]),另一条是从左到右到达这个格子([i][j-1] -> [i][j])。我们只需要关注这两条路径中,哪条路径的路径和最小就好了。 另外可以参考 072.编辑距离 。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def minPathSum(self, grid):\n", + " \"\"\"\n", + " :type grid: List[List[int]]\n", + " :rtype: int\n", + " \"\"\"\n", + " m = len(grid)\n", + " n = len(grid[0])\n", + " dp = grid.copy()\n", + " for i in range(1, n):\n", + " dp[0][i] = dp[0][i-1] + grid[0][i]\n", + " for i in range(1, m):\n", + " dp[i][0] = dp[i-1][0] + grid[i][0]\n", + " for i in range(1, m):\n", + " for j in range(1, n):\n", + " dp[i][j] = min(dp[i][j-1] + grid[i][j], dp[i-1][j] + grid[i][j])\n", + " return dp[m-1][n-1]\n", + " \n", + "s = Solution()\n", + "grid = [\n", + " [1,3,1],\n", + " [1,5,1],\n", + " [4,2,1]\n", + "]\n", + "print(s.minPathSum(grid))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "上面的版本是我最初写成的,后来听大佬们说,尽量减少 for 循环的个数。改成下面的最终版本,已经 AC 。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "grid = [\n", + " [1,3,1],\n", + " [1,5,1],\n", + " [4,2,1]\n", + "]\n", + "print(s.minPathSum(grid))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/064._minimum_path_sum.md b/docs/Algorithm/Leetcode/Python/064._minimum_path_sum.md new file mode 100644 index 00000000..fe89255e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/064._minimum_path_sum.md @@ -0,0 +1,60 @@ +# 64. Minimum Path Sum 最小路径和 + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/minimum-path-sum +* https://leetcode-cn.com/problems/minimum-path-sum/description + +> 内容描述 + +``` +给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + +说明:每次只能向下或者向右移动一步。 + +示例: + +输入: +[ + [1,3,1], + [1,5,1], + [4,2,1] +] +输出: 7 +解释: 因为路径 1→3→1→1→1 的总和最小。 +``` + +## 解题方案 + +> 思路 1 + +* 经典的动态规划问题,和:72. 编辑距离 类似 + +```python +class Solution(object): + def minPathSum(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + if not grid or len(grid) == 0: + return 0 + row = len(grid) + col = len(grid[0]) if row else 0 + dp = [[0 for j in range(col)] for i in range(row)] + for i in range(row): + for j in range(col): + if i > 0 and j > 0: + dp[i][j] = min(dp[i-1][j]+grid[i][j], dp[i][j-1]+grid[i][j]) + elif i > 0 and j == 0: + dp[i][j] = sum([grid[k][0] for k in range(i+1)]) + elif i == 0 and j > 0: + dp[i][j] = sum([grid[0][k] for k in range(j+1)]) + else: + dp[i][j] = grid[0][0] + return dp[-1][-1] +``` diff --git a/docs/Algorithm/Leetcode/Python/065.unique_paths_ii.md b/docs/Algorithm/Leetcode/Python/065.unique_paths_ii.md new file mode 100644 index 00000000..16e8e940 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/065.unique_paths_ii.md @@ -0,0 +1,84 @@ + ###65.Unique Paths II + +题目: + + + + +tag : DP + +难度 : Medium + + + + + +``` +BASE CASE( i = 0 , j = 0): +//第一排和第一列,如果没有obstacle, 则走法为1, 一旦有了obstacle,则之后的格子走法都为0 + +非BASE CASE : +//一旦有obstacle,则dp为0 +dp(i, j) = dp(i,j-1) + dp(i-1,j) + +``` + +Python代码 + +``` +class Solution(object): + def uniquePathsWithObstacles(self, obstacleGrid): + """ + :type obstacleGrid: List[List[int]] + :rtype: int + """ + row = len(obstacleGrid) + col = len(obstacleGrid[0]) + dp = [[0 for i in range(col)] for j in range(row)] + + dp[0][0] = int(obstacleGrid[0][0] == 0) + + #first row + for j in range(1,col): + if obstacleGrid[0][j] == 1: + dp[0][j] = 0 + else: + dp[0][j] = dp[0][j-1] + #first col + for i in range(1,row): + if obstacleGrid[i][0] == 1: + dp[i][0] = 0 + else: + dp[i][0] = dp[i-1][0] + + for i in range(1,row): + for j in range(1,col): + if obstacleGrid[i][j] == 1: + dp[i][j] = 0 + else: + dp[i][j] = dp[i-1][j] + dp[i][j-1] + return dp[row-1][col-1] + +``` + +犯了一个错,简直觉得不可思议。一开始初始化dp用的代码是 + +``` +dp = [[0] * col] * row +``` + +问题在此: + + +``` +>>> x = [[]] * 3 +>>> x[1].append(0) +>>> x +[[0], [0], [0]] +``` + +这样初始化是做了三个一样的object. + +The 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. + +参见stackoverflow : diff --git a/docs/Algorithm/Leetcode/Python/066._plus_one.md b/docs/Algorithm/Leetcode/Python/066._plus_one.md new file mode 100644 index 00000000..8897d391 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/066._plus_one.md @@ -0,0 +1,60 @@ +### 66. Plus One + +题目: + + + +难度 : Easy + + + + +这里是用的递归,很容易理解,如果空列表直接加1,最后一位小于9,那么直接就最后一位加1,否则添加一个0,然后再把余下的递归加1 + + +```python + +class Solution(object): + def plusOne(self, digits): + """ + :type digits: List[int] + :rtype: List[int] + """ + if digits == []: + return [1] + if digits[-1] < 9: + return digits[:-1] + [digits[-1] + 1] + else: + return self.plusOne(digits[:-1]) + [0] +``` + + +其实可以考虑循环,效率更高,参考[此处](https://shenjie1993.gitbooks.io/leetcode-python/content/066%20Plus%20One.html) + + + +> 从低位到高位,如果后一位有进位的话,那么该位要加上一,否则退出循环。如果最高位也进位,那么在列表前要插入一个一。 + + + +``` +class Solution(object): + def plusOne(self, digits): + """ + :type digits: List[int] + :rtype: List[int] + """ + carry = 1 + + for i in range(len(digits)-1,-1,-1): + digits[i] += carry + if digits[i] < 10: + carry = 0 + break + else: + digits[i] -= 10 + if carry == 1: + digits.insert(0,1) + return digits +``` + diff --git a/docs/Algorithm/Leetcode/Python/067._add_binary.md b/docs/Algorithm/Leetcode/Python/067._add_binary.md new file mode 100644 index 00000000..875dc9e6 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/067._add_binary.md @@ -0,0 +1,31 @@ +###67. Add Binary + +题目: + + + +难度 : Easy + + +几种case: + +- a or b 为空,最简单 +- 唯一的问题是如果有进位的处理,进位的处理就是先让其中的一个数和```‘1’```做```addBinary```处理 ,然后再用```addBinary``` + +```python +class Solution(object): + def addBinary(self, a, b): + """ + :type a: str + :type b: str + :rtype: str + """ + if (a == '' or b == ''): + return a + b + elif a[-1] == '0' and b[-1] == '0': + return self.addBinary(a[:-1], b[:-1]) + '0' + elif a[-1] == '1' and b[-1] == '1': + return self.addBinary(a[:-1], self.addBinary(b[:-1],'1')) + '0' + else: + return self.addBinary(a[:-1], b[:-1]) + '1' +``` diff --git a/docs/Algorithm/Leetcode/Python/069._sqrt(x).md b/docs/Algorithm/Leetcode/Python/069._sqrt(x).md new file mode 100644 index 00000000..70c28f6e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/069._sqrt(x).md @@ -0,0 +1,101 @@ +### 69. Sqrt(x) + + +题目: + + + +难度: + +Medium + + +思路: + +一看,觉得很容易,一写,超时: + +``` +class Solution(object): + def mySqrt(self, x): + """ + :type x: int + :rtype: int + """ + i = 0 + while i * i <= x : + if i * i == x: + return i + elif i * i < x and (i+1) * (i+1) > x: + return i + i += 1 +``` + +看一眼tag, binary search,难道从x/2之类的开始搜起来?话说还想到求sqrt有个🐂的牛顿法? + +莫名其妙过了的代码: + +```python +class Solution(object): + def mySqrt(self, x): + """ + :type x: int + :rtype: int + """ + if x == 1 : return 1 + if x == 0 : return 0 + l, r = 0, x - 1 + while l <= r: + mid = l + ((r - l) >> 2) + if mid * mid <= x and (mid+1)*(mid+1) > x: + return mid + elif mid * mid > x: + r = mid - 1 + else: + l = mid + 1 +``` + +或者 +```python +class Solution(object): + def mySqrt(self, x): + """ + :type x: int + :rtype: int + """ + if x == 1: + return 1 + if x == 0: + return 0 + l, r = 0, x-1 + while l <= r: + mid = l + ((r - l) >> 2) + if (mid * mid - x == 0): + return mid + elif (mid * mid - x > 0): + r = mid - 1 + else: + l = mid + 1 + return r +``` + + + +牛顿法 + +参见wikipedia,to be done:自己推导一遍 + + + +```python +class Solution(object): + def mySqrt(self, x): + """ + :type x: int + :rtype: int + """ + res = 1.0 + while abs(res * res - x) > 0.1: + res = (res + x / res) / 2 + return int(res) + +``` diff --git a/docs/Algorithm/Leetcode/Python/070. Climbing Stairs.md b/docs/Algorithm/Leetcode/Python/070. Climbing Stairs.md new file mode 100644 index 00000000..890b2f33 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/070. Climbing Stairs.md @@ -0,0 +1,99 @@ +### 70. Climbing Stairs + + +题目: + + + +难度: +Easy + +思路: + +Fibonacci 的DP版本 + +对于DP的不同理解造成不同的写法 +Memoization 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). +详看 + +[Dynamic programming and memoization: bottom-up vs top-down approaches](https://awjin.me/algos-js/dp/tab-memo.html) + +[Tabulation vs Memoizatation](http://www.geeksforgeeks.org/tabulation-vs-memoizatation/) +- top-down(memorize) + +``` +def memorize_fib(n): # n为第几个Fibonacci数 + memo = {1:1, 2:1} + if n in memo: + return memo[n] + else: + memo[n] = memorize_fib(n-1) + memorize_fib(n-2) + return memo[n] + +print(memorize_fib(4)) +``` +输出```3``` + + +- bottom up(tabulation) + +``` +def tabulation_fib(n): # n为第几个Fibonacci数 + fib = [1, 1, 2] + if n < 4: + return fib[n-1] + for k in range(3, n+1): + fib[2] = fib[0] + fib[1] + fib[0], fib[1] = fib[1], fib[2] + return fib[2] + +print(tabulation_fib(4)) +``` +输出```3``` + +这里memo用dict,用array也一样。当然用bottom up还有一点,可以只存每次最后两个数,可以save space.,这样就只用到constant space. + +AC 代码(这里采用bottom up思想) + +```python +class Solution(object): + def climbStairs(self, n): + """ + :type n: int + :rtype: int + """ + fib = [1, 2, 3] + if n < 4: + return fib[n-1] + for k in range(3, n+1): +            fib[2] = fib[0] + fib[1]             # 永远只存3个元素,save space +            fib[0], fib[1] = fib[1], fib[2] + return fib[2] +``` +- Complexity Analysis + + - Time complexity : O(n) + + - Space complexity : O(1). Constant space is used. +另外还有一个公式法: + +![](https://github.com/Lisanaaa/myTODOs/blob/master/41512784914_.pic.jpg) + +由于这里面相当于```standard Fibonacci```函数向前进了一步,排列为1,2,3,5而非原本的1,1,2,3,所以代码中使用```n+1``` +```python +class Solution(object): + def climbStairs(self, n): + """ + :type n: int + :rtype: int + """ + import math + sqrt5 = math.sqrt(5) + fibn = pow((1 + sqrt5) / 2, n+1) - pow((1 - sqrt5) / 2, n+1) + return int(float(fibn/sqrt5)) +``` +- Complexity Analysis + + - Time complexity : O(lg(n)). pow method takes log(n) time. + + - Space complexity : O(1). Constant space is used. diff --git a/docs/Algorithm/Leetcode/Python/072._edit_distance.ipynb b/docs/Algorithm/Leetcode/Python/072._edit_distance.ipynb new file mode 100644 index 00000000..9c8a9d1c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/072._edit_distance.ipynb @@ -0,0 +1,211 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 072. Edit Distance 编辑距离\n", + "\n", + "### 难度:Hard\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/edit-distance/description/\n", + " - 英文:https://leetcode.com/problems/edit-distance/\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。\n", + "\n", + "你可以对一个单词进行如下三种操作:\n", + "\n", + "插入一个字符\n", + "删除一个字符\n", + "替换一个字符\n", + "\n", + "示例 1:\n", + "输入: word1 = \"horse\", word2 = \"ros\"\n", + "输出: 3\n", + "解释: \n", + "horse -> rorse (将 'h' 替换为 'r')\n", + "rorse -> rose (删除 'r')\n", + "rose -> ros (删除 'e')\n", + "\n", + "示例 2:\n", + "输入: word1 = \"intention\", word2 = \"execution\"\n", + "输出: 5\n", + "解释: \n", + "intention -> inention (删除 't')\n", + "inention -> enention (将 'i' 替换为 'e')\n", + "enention -> exention (将 'n' 替换为 'x')\n", + "exention -> exection (将 'n' 替换为 'c')\n", + "exection -> execution (插入 'u')\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "这个题目是动态规划的典型例题,在 wikipedia 中是有相应页面介绍的。\n", + "\n", + " - https://en.wikipedia.org/wiki/Edit_distance#Common_algorithm\n", + " - https://en.wikipedia.org/wiki/Levenshtein_distance\n", + "\n", + "> 思路 1\n", + "\n", + " - 使用动态规划\n", + "\n", + "下面我们说说,这个题的思路。具体来描述一下。\n", + "\n", + "要始终明确一点, dp[i][j] 的含义是使得 word1 的前 i 字符子串与 word2 的前 j 字符子串相等所需要的操作数,这也是为什么我们需要在初始化 dp 矩阵时需要行列数均加上 1 。\n", + "\n", + "我们创建一个 dp[][] 二维数组,表示从 word1 的前 i 个字符(下标为:0~ i-1)到 word2 的前 j 个字符(下标为:0~j-1)的编辑过程中,需要的最少步数,那么:\n", + "\n", + "如果 $word1[i] = word2[j]$ 则 $dp[i][j] = dp[i-1][j-1]$\n", + "\n", + "如果 $word1[i] != word2[j]$ 则 $dp[i][j] = min ( dp[i-1][j] , dp[i][j-1], dp[i-1][j-1] ) + 1$\n", + "\n", + "下面就是我们对上述动态规划过程的解释:\n", + "\n", + "第一个条件比较容易理解,就是说 word1 的下标为 i 的字符 和 word2 的下标为 j 的字符相同,那么这个位置的字符我们不需要进行操作,所以我们只需要关注 word1 和 word2 去除掉相应位置的字符之后的子串的结果即可。\n", + "\n", + "我们下面对第二个条件的三种情况进行重点讲解:\n", + "\n", + "假设 word1 的前 i+1 (下标为 0~i)的子串为 \"abcde\"\n", + "假设 word2 的前 j+1 (下标为 0~j)的子串为 \"abcddgf\"\n", + "现在 word1[i] != word2[j],也就是 'e' != 'f'\n", + "\n", + "那么我们接下来应该怎么做呢?\n", + "\n", + "我们会发现,我们做的三种解释实际上就是把我们题中写到的三种操作模拟在最后一步实现。每种操作都是额外加一的操作。\n", + "\n", + "简单说,就是这样:\n", + " - 1.delete:dp[i-1][j] + 1 —— 保留了从 word1[0~i-1] 转变到 word2[0~j] 的最优操作次数,因为我们的 word1 的 0~i-1 已经能够转变到 word2 了,所以我们就直接把 word1 中的最后一个字符删除掉就行了。所以就需要额外进行一个 删除 操作。\n", + " - 2.insert:dp[i][j-1] + 1 —— 保留了从 word1[0~i] 转变到 word2[0~j-1] 的最优操作次数,因为我们的 word1 的 0~i 只能转变到 word2 的倒数第二位,所以我们就直接在 word1 的末尾添加一个与 word2 的最后一个字符相同的字符就可以了。所以就需要额外进行一个 插入 操作。\n", + " - 3.replace:dp[i-1][j-1] + 1 —— 保留了从 word1[0~i-1] 转变到 word2[0~j-1] 的最优操作次数,因为我们的 word1 的 0~i-1 只能转变到 word2 的倒数第二位,而 word1 的最后一位与 word2 的最后一位是不同的,所以现在的情况只需要额外的一个 替换 操作即可。\n", + "\n", + "\n", + "无论我们选取上面 3 中操作的哪种操作,我们选其中最小的值就可以了。\n", + "\n", + "参考链接:http://www.cnblogs.com/pandora/archive/2009/12/20/levenshtein_distance.html\n", + "\n", + "下面我们看一下代码:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def minDistance(self, word1, word2):\n", + " \"\"\"\n", + " :type word1: str\n", + " :type word2: str\n", + " :rtype: int\n", + " \"\"\"\n", + " # 初始化一个 len(word1)+1 * len(word2)+1 的矩阵\n", + " matrix = [[i+j for j in range(len(word2) + 1)] for i in range(len(word1) + 1)]\n", + " # 辅助理解,matrix 矩阵的样子\n", + " # print(matrix)\n", + " for i in range(1, len(word1)+1):\n", + " for j in range(1,len(word2)+1):\n", + " if word1[i-1] == word2[j-1]:\n", + " d = 0\n", + " else:\n", + " d = 1\n", + " matrix[i][j] = min(matrix[i-1][j]+1, matrix[i][j-1]+1, matrix[i-1][j-1]+d)\n", + "\n", + " return matrix[len(word1)][len(word2)]\n", + " \n", + "s = Solution()\n", + "word1 = 'horse'\n", + "word2 = 'ros'\n", + "print(s.minDistance(word1, word2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "上面代码的 matrix 矩阵生成,可能会让大家产生理解误差,我在这个地方的理解也是通过大佬问,我才知道具体是怎么回事的。\n", + "\n", + "下面我们把它打印一下。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "matrix([[0, 1, 2, 3],\n", + " [1, 2, 3, 4],\n", + " [2, 3, 4, 5],\n", + " [3, 4, 5, 6],\n", + " [4, 5, 6, 7],\n", + " [5, 6, 7, 8]])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "juzhen = [[i+j for j in range(len(word2) + 1)] for i in range(len(word1) + 1)]\n", + "juzhen = np.mat(juzhen)\n", + "juzhen" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "以 numpy 的样子打印出来,看这样子比较清晰。各行各列对应比较整齐。\n", + "\n", + "我要说明的是:\n", + "\n", + " - 这个 matrix 的 第 1 行(下标为0的行)的 [0, 1, 2, 3] 这个维度的意思,对应的是 dp[i][j] 。也就是说,word1 取前 i 个字符,然后编辑成 word2 时所需要转换的最少步数。因为这里 i = 0,也就是 word1 取 0 个字符,而 j 我们取 0 - 3 个字符的时候,我们从 word1 变换到 word2 的时候所需要经过的最小步数。本质上,就是在 **空的** word1 上进行对应插入 word2 对应的字符就可以变换到 word2 。word2 取几个字符,我们的最小变换次数就是几。也就对应这个维度上的数字。\n", + "\n", + " - 另一个维度上,matrix 的第 1 列(下标为 0 的列),对应的是 [0, 1, 2, 3, 4, 5] 也是对应的 dp[i][j]。只不过我们这里调换了顺序,i 现在不为 0 了,而是 j 为 0 。也就是 word1 取 0~ i 个字符的时候,变换到 word2 的最小步骤数。实际上 word2 是空的,也就是说,我们 word1 有几个字符,我们对应删除几个字符就可以得到 word2 。这就对应着我们的这个列维度上的数字。\n", + " \n", + " - 其他维度,i 和 j 都不为 0 的部分,我们的初始化的数字是没有意义的。我们在迭代过程中会全部都更改一遍。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/072._edit_distance.md b/docs/Algorithm/Leetcode/Python/072._edit_distance.md new file mode 100644 index 00000000..3a502d08 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/072._edit_distance.md @@ -0,0 +1,118 @@ +### 72. Edit Distance + +题目: + + + +难度: + +Hard + +可以做的操作: + +- insert +- delete +- replace + +动归典型,原来也是有wikipedia page的算法 + + + + + + +看wikipedia 这解释 + +``` + / max(i,j) if min(i,j) = 0 + + / dp[i-1][j] + 1 word1[i]不在word2[0...j]中,所以删除 + dp[i][j] - min -- dp[i][j-1] + 1 insertion + \ dp[i-1][j-1] + 1/0 word[i]与word[j]是否相等 +``` + +上面的就不用解释了,min分别对应:删除、插入、以及替代(1/0取决 word1[i] == word2[j] ),反正也是tabular类型,画表来解决问题。 + +简单说,就是这样: + +1.delete:dp[i-1][j] + 1 —— 保留了从 word1[0:i-1] 转变到 word2[0:j] 的最优操作次数,因为我们的 word1 的 0~i-1 已经能够转变到 word2 了, +所以我们就直接把 word1 中的最后一个字符删除掉就行了。所以就需要额外进行一个 删除 操作。 + +2.insert:dp[i][j-1] + 1 —— 保留了从 word1[0:i] 转变到 word2[0:j-1] 的最优操作次数,因为我们的 word1 的 0~i 只能转变到 word2 的倒数第二位,所以我们就直接在 word1 的末尾添加一个与 word2 的最后一个字符相同的字符就可以了。所以就需要额外进行一个 插入 操作。 + +3.replace:dp[i-1][j-1] + 1 —— 保留了从 word1[0:i-1] 转变到 word2[0:j-1] 的最优操作次数,因为我们的 word1 的 0~i-1 只能转变到 word2 的倒数第二位,而 word1 的最后一位与 word2 的最后一位是不同的,所以现在的情况只需要额外的一个 替换 操作即可。 + +无论我们选取上面 3 中操作的哪种操作,我们选其中最小的值就可以了。 + +参考链接:http://www.cnblogs.com/pandora/archive/2009/12/20/levenshtein_distance.html + +***要始终明确一点,```dp[i][j]```的含义是使得```word1的前i字符子串```与```word2的前j字符子串```相等所需要的操作数,这也是为什么我们需要在初始化```dp矩阵```时需要行列数均加上```1```*** + +用wikipedia上的伪码改造 + +``` +function LevenshteinDistance(char s[1..m], char t[1..n]): + // for all i and j, d[i,j] will hold the Levenshtein distance between + // the first i characters of s and the first j characters of t + // note that d has (m+1)*(n+1) values + declare int d[0..m, 0..n] + + set each element in d to zero + + // source prefixes can be transformed into empty string by + // dropping all characters + for i from 1 to m: + d[i, 0] := i + + // target prefixes can be reached from empty source prefix + // by inserting every character + for j from 1 to n: + d[0, j] := j + + for j from 1 to n: + for i from 1 to m: + if s[i] = t[j]: + substitutionCost := 0 + else: + substitutionCost := 1 + d[i, j] := minimum(d[i-1, j] + 1, // deletion + d[i, j-1] + 1, // insertion + d[i-1, j-1] + substitutionCost) // substitution + + return d[m, n] +``` + +对应的例子表格图 + +``` + k i t t e n + 0 1 2 3 4 5 6 +s 1 1 2 3 4 5 6 +i 2 2 1 2 3 4 5 +t 3 3 2 1 2 3 4 +t 4 4 3 2 1 2 3 +i 5 5 4 3 2 2 3 +n 6 6 5 4 3 3 2 +g 7 7 6 5 4 4 3 +``` + + +AC代码 + +```python +class Solution(object): + def minDistance(self, word1, word2): + """ + :type word1: str + :type word2: str + :rtype: int + """ + if len(word1) == 0 or len(word2) == 0: # corner cases + return max(len(word1), len(word2)) + dp = [[i+j for j in range(len(word2)+1)] for i in range(len(word1)+1)] + for i in range(1, len(word1)+1): + for j in range(1, len(word2)+1): + tmp_dist = 0 if word1[i-1] == word2[j-1] else 1 + dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+tmp_dist) + return dp[-1][-1] +``` diff --git a/docs/Algorithm/Leetcode/Python/073. Set Matrix Zeroes.md b/docs/Algorithm/Leetcode/Python/073. Set Matrix Zeroes.md new file mode 100644 index 00000000..b8d12ccd --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/073. Set Matrix Zeroes.md @@ -0,0 +1,50 @@ +### 73. Set Matrix Zeroes + + + +题目: + + + + +难度 : Medium + + + +思路: + +Naive AC代码,一看类似那个 game of life,不用extra space,不用O(mn),应该就是用状态转移机了(?),所以还是先naive AC把: + +```python +class Solution(object): + def setZeroes(self, matrix): + """ + :type matrix: List[List[int]] + :rtype: void Do not return anything, modify matrix in-place instead. + """ + def setZero(i,j): + for m in range(col): + matrix[i][m] = 0 + for n in range(row): + matrix[n][j] = 0 + + row = len(matrix) + col = len(matrix[0]) if row else 0 + new_matrix = [matrix[i][:] for i in range(row)] + + for i in range(row): + for j in range(col): + if new_matrix[i][j] == 0: + setZero(i,j) +``` + + + +`正确思路`: + +一边遍历,一边将相应的行和列置为0是行不通的,会影响后面元素的遍历判断,所以要记录下哪些行和哪些列是要置为0的。为了节约空间,在原矩阵中借两条边,如果该行或者列要置为0,则把左边或者上边的相应位置置为0。如果左边和上边本来就有0,那么需要额外标记一下,最后把左边或者右边也全部置为0. + + + + + diff --git a/docs/Algorithm/Leetcode/Python/074._search_a_2d_matrix.md b/docs/Algorithm/Leetcode/Python/074._search_a_2d_matrix.md new file mode 100644 index 00000000..026a5d34 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/074._search_a_2d_matrix.md @@ -0,0 +1,81 @@ +### 74. Search a 2D Matrix + +题目: + + + +难度: +Medium + + +思路: +想过将```2D matrix```看成一个大```sorted list```,代码如下: +```python +class Solution(object): + def searchMatrix(self, matrix, target): + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + row = len(matrix) + col = len(matrix[0]) if row else 0 + l, r = 0, row * col - 1 + while l <= r: + mid = l + ((r - l) >> 2) + if target > matrix[mid/col][mid%col]: + l = mid + 1 + elif target < matrix[mid/col][mid%col]: + r = mid - 1 + else: + return True + return False +``` + + +但是后面觉得不行, +原因如下: +1. m * n may overflow for large m and n; +2. it will use multiple expensive operations such as / and % + + + + + + +因此二分Search,``` binary search by row first, then binary search by column.``` + + +```python +class Solution(object): + def searchMatrix(self, matrix, target): + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + if not matrix or not matrix[0]: + return False + row = len(matrix) + col = len(matrix[0]) if row else 0 + l, r = 0, row - 1 + while l <= r: + mid_row = l + ((r - l) >> 2) + if matrix[mid_row][0] <= target <= matrix[mid_row][-1]: + m, n = 0, col - 1 + while m <= n: + mid_col = m + ((n - m) >> 2) + if matrix[mid_row][mid_col] > target: + n = mid_col - 1 + elif matrix[mid_row][mid_col] < target: + m = mid_col + 1 + else: + return True + return False + elif target < matrix[mid_row][0]: + r = mid_row - 1 + else: + l = mid_row + 1 + return False + +``` diff --git a/docs/Algorithm/Leetcode/Python/075._sort_colors.md b/docs/Algorithm/Leetcode/Python/075._sort_colors.md new file mode 100644 index 00000000..8e6a628c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/075._sort_colors.md @@ -0,0 +1,149 @@ +# 75. Sort Colors +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/sort-colors/description/ + +> 内容描述 + +``` +Given 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. + +Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. + +Note: You are not suppose to use the library's sort function for this problem. + +Example: + +Input: [2,0,2,1,1,0] +Output: [0,0,1,1,2,2] +Follow up: + +A rather straight forward solution is a two-pass algorithm using counting sort. +First, 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. +Could you come up with a one-pass algorithm using only constant space? +``` + +## 解题方案 + +> 思路 1 + +先算一下0, 1, 2分别有多少个,然后in-place改呗,简单, beats 100% + +```python +class Solution(object): + def sortColors(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + red, white, blue = 0, 0, 0 + for i in nums: + if i == 0: + red += 1 + elif i == 1: + white += 1 + for i in range(red): + nums[i] = 0 + for i in range(red, red+white): + nums[i] = 1 + for i in range(red+white, len(nums)): + nums[i] = 2 +``` + + +> 思路 2 + +这个问题是 Dutch National Flag Problem, 荷兰旗问题 + + + +思路其实是类似partition的,比x小的放左边,比x大的放右边。 + +这里是用三个指针,begin, cur, end,cur需要遍历整个数组 + +- cur 指向0,交换begin与cur, begin++,cur++ +- cur 指向1,不做任何交换,cur++ +- cur 指向2,交换end与cur,end-- + +之所以cur指向2,交换之后不前进是因为我们end交换过来的是0或者1,如果是0那么明显我们需要做进一步的处理,所以最终判断条件是end < cur应该就结束了 + +这样的three-way-partition也只是3-way好用吧?如果有4个数,那么这样则是无效的,或者如果是4-way,那么可以转换成3-way+2-way + + +```python +class Solution(object): + def sortColors(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + begin, cur, end = 0, 0, len(nums) - 1 + + while cur <= end: + if nums[cur] == 0: + nums[begin], nums[cur] = nums[cur], nums[begin] + cur += 1 + begin += 1 + elif nums[cur] == 1: + cur += 1 + else: # nums[cur] == 2 + nums[cur], nums[end] = nums[end], nums[cur] + end -= 1 +``` + +> 思路 3 + +两个指针也可以 + +```python +class Solution(object): + def sortColors(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + i, l, r = 0, 0, len(nums) - 1 + while i < len(nums): + if nums[i] == 2 and i < r: + nums[i], nums[r] = nums[r], 2 + r -= 1 + elif nums[i] == 0 and i > l: + nums[i], nums[l] = nums[l], 0 + l += 1 + else: + i += 1 +``` + +> 思路 4 + +这个方法就很巧妙了,我们遍历整个数组,只要碰到了什么数字我们就把这个数字往右边推一下 + +大家可以用例子[2,0,2,1,1,0]自己推导一下过程,看看是不是有一种向右推的感觉 + + +```python +class Solution(object): + def sortColors(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + n0, n1, n2 = -1, -1, -1 + for i in range(len(nums)): + if nums[i] == 0: + n0, n1, n2 = n0+1, n1+1, n2+1 + nums[n2] = 2 + nums[n1] = 1 + nums[n0] = 0 + elif nums[i] == 1: + n1, n2 = n1+1, n2+1 + nums[n2] = 2 + nums[n1] = 1 + else: + n2 += 1 + nums[n2] = 2 +``` diff --git a/docs/Algorithm/Leetcode/Python/076._Minimum_Window_Substring.md b/docs/Algorithm/Leetcode/Python/076._Minimum_Window_Substring.md new file mode 100644 index 00000000..1407d82d --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/076._Minimum_Window_Substring.md @@ -0,0 +1,44 @@ +### 76. Minimum Window Substring +题目: + + + +难度 : Hard + + +模板大法 + + +```python +class Solution(object): + def minWindow(self, s, t): + """ + :type s: str + :type t: str + :rtype: str + """ + if len(t) > len(s): + return '' + maps = collections.Counter(t) + counter = len(maps.keys()) + begin, end, head, length = 0, 0, 0, float('inf') + while end < len(s): + if s[end] in maps: + maps[s[end]] -= 1 + if maps[s[end]] == 0: + counter -= 1 + end += 1 + while counter == 0: + if s[begin] in maps: + maps[s[begin]] += 1 + if maps[s[begin]] > 0: + counter += 1 + if end - begin < length: + length = end - begin + head = begin + begin += 1 + if length == float('inf'): + return '' + return s[head:head+length] +``` + diff --git a/docs/Algorithm/Leetcode/Python/077._combinations.md b/docs/Algorithm/Leetcode/Python/077._combinations.md new file mode 100644 index 00000000..1672b9df --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/077._combinations.md @@ -0,0 +1,123 @@ +###77. Combinations + + +题目: + + + +难度 : Medium + + +思路一: +python作弊法 + +``` +import itertools +p = [4, 8, 15, 16, 23, 42] +c = itertools.combinations(p, 4) +for i in c: + print i + +结果: + +(4, 8, 15, 16) +(4, 8, 15, 23) +(4, 8, 15, 42) +(4, 8, 16, 23) +(4, 8, 16, 42) +(4, 8, 23, 42) +(4, 15, 16, 23) +(4, 15, 16, 42) +(4, 15, 23, 42) +(4, 16, 23, 42) +(8, 15, 16, 23) +(8, 15, 16, 42) +(8, 15, 23, 42) +(8, 16, 23, 42) +(15, 16, 23, 42) +``` + +作弊AC代码: + +``` +class Solution(object): + def combine(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[List[int]] + """ + import itertools + return [list(i) for i in itertools.combinations(range(1,n+1), k)] +``` + + +思路二: + +标准的recursion + +但是会超时 + + +``` +class Solution(object): + def combine(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[List[int]] + """ + ans = [] + self.dfs(n, k, 1, [], ans) + return ans + + def dfs(self, n, k ,start, lst, ans): + if k == 0 : + ans.append(lst) + return + for i in range(start, n+1): + self.dfs(n, k - 1, i + 1,lst +[i], ans) +``` + +理解方式 + +``` + + 1 2 3 + 12 13 14 23 24 34 +``` + +可以参照这里 + + + + + +解法三: + + +采用递归的方式,在n个数中选k个,如果n大于k,那么可以分类讨论,如果选了n,那么就是在1到(n-1)中选(k-1)个,否则就是在1到(n-1)中选k个。递归终止的条件是k为1,这时候1到n都符合要求。 + +注意一开始这里的else part花了我一点时间来理解,因为n必定大于k,所以这样递归当 n == k的时候选法就是code原作者的写法,也就是直接[range(1,k+1)] + +参考这里: + + +``` +class Solution(object): + def combine(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[List[int]] + """ + if k == 1: + return [[i + 1] for i in range(n)] + result = [] + if n > k: + result = [r + [n] for r in self.combine(n - 1, k - 1)] + self.combine(n - 1, k) + else: #n == k + # result = [r + [n] for r in self.combine(n - 1, k - 1)] + result = [range(1,k+1)] + return result +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/078._Subsets.md b/docs/Algorithm/Leetcode/Python/078._Subsets.md new file mode 100644 index 00000000..62d32e24 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/078._Subsets.md @@ -0,0 +1,106 @@ +# 78. Subsets + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/subsets/description/ + +> 内容描述 + +``` + +Given a set of distinct integers, nums, return all possible subsets (the power set). + +Note: The solution set must not contain duplicate subsets. + +Example: + +Input: nums = [1,2,3] +Output: +[ + [3], + [1], + [2], + [1,2,3], + [1,3], + [2,3], + [1,2], + [] +] +``` + +## 解题方案 + +> 思路 1 + +每次拿一个,跟res里面的每一个已有列表取并集再次插入res中 + +```python +class Solution(object): + def subsets(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + res = [[]] + for num in nums: + res.extend([tmp+[num] for tmp in res]) + return res +``` + +> 思路 2 + +BackTrack 标准解法版 + +对每个元素,有两种可能,加入 cur_lst 和不加入 cur_lst,写起来思路还是很清爽的 + + +```python +class Solution(object): + def subsets(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + res = [] + + def search(cur_lst, idx): + if idx == len(nums): + res.append(cur_lst) + return + search(cur_lst + [nums[idx]], idx + 1) + search(cur_lst, idx + 1) + + search([], 0) + return res +``` + + +> 思路 3 + +DFS + +```python +class Solution(object): + def subsets(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + res = [] + def dfs(depth, start, lst): + res.append(lst) + if depth == len(nums): + return + for i in range(start, len(nums)): + dfs(depth+1, i+1, lst+[nums[i]]) + dfs(0, 0, []) + return res +``` + + diff --git a/docs/Algorithm/Leetcode/Python/079._word_search.md b/docs/Algorithm/Leetcode/Python/079._word_search.md new file mode 100644 index 00000000..e097a425 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/079._word_search.md @@ -0,0 +1,63 @@ +###79. Word Search + + + +题目: + + + +难度: +Medium + + +思路: + +其实这个题和number of islands类似,是backtracking基本功的考查,但是基本功非常有待提高||| + +比较核心的是dfs函数,然后这个函数有取巧的写法:如果outside of boundary就return False + +loop, 如果碰到跟word开头的字母一样,把这个扔进去loop,可以考查这个char在这个board的上下左右是否可以选择,补课使用则重置used, 然后return + +也还是之前摘录的,backtrack写法关键: 选择 (Options),限制 (Restraints),结束条件 (Termination)。 + + + + +``` +class Solution(object): + def exist(self, board, word): + """ + :type board: List[List[str]] + :type word: str + :rtype: bool + """ + + def dfs(board, used, row, col, x, y, word, idx): + if idx == len(word) : + return True + + if x < 0 or x > row -1 or y < 0 or y > col -1 : + return False + + if board[x][y] == word[idx] and not used[x][y]: + used[x][y] = 1 + left = dfs(board,used,row,col,x-1,y,word,idx+1) + right = dfs(board,used,row,col,x+1,y,word,idx+1) + up = dfs(board,used,row,col,x,y-1,word,idx+1) + down = dfs(board,used,row,col,x,y+1,word,idx+1) + + used[x][y] = left or right or up or down + return left or right or up or down + return False + + + row = len(board) + col = len(board[0]) if row else 0 + used = [ [0 for i in range(col)] for j in range(row)] + + for i in range(row): + for j in range(col): + if dfs(board,used,row,col,i,j,word,0): + return True + return False +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/082._remove_duplicates_from_sorted_list_ii.md b/docs/Algorithm/Leetcode/Python/082._remove_duplicates_from_sorted_list_ii.md new file mode 100644 index 00000000..277b3870 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/082._remove_duplicates_from_sorted_list_ii.md @@ -0,0 +1,49 @@ +###82. Remove Duplicates from Sorted List II + + +题目: + + + + +难度: + +Medium + + +木有space 和 time的限制,第一想法,用dictionary存一下每个nodes的个数,这样只要看到它是大于1的,就删删删。 + +虽然是笨办法。但是也可以AC + +``` +class Solution(object): + def deleteDuplicates(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + dummy = ListNode(-1) + dummy.next = head + + cur = dummy.next + nodeNumber = {} + while cur: + if cur.val in nodeNumber: + nodeNumber[cur.val] += 1 + else: + nodeNumber[cur.val] = 1 + cur = cur.next + + cur = dummy + while cur.next: + if nodeNumber[cur.next.val] > 1: + cur.next = cur.next.next + else: + cur = cur.next + return dummy.next +``` + + +谷歌一下,更省时间的方法是用一个prev 和 cur 指针,然后用一个bool来记录是否duplicate,这样loop一次即可解决问题。 + +to be 写出来 \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/083._remove_duplicates_from_sorted_list.md b/docs/Algorithm/Leetcode/Python/083._remove_duplicates_from_sorted_list.md new file mode 100644 index 00000000..a9081a68 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/083._remove_duplicates_from_sorted_list.md @@ -0,0 +1,28 @@ +### 83. Remove Duplicates from Sorted List + +题目: + + + +难度: + +Easy + + +dummy 大法 + +```python +class Solution(object): + def deleteDuplicates(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + dummy = head + while head: + while head.next and head.next.val == head.val: + head.next = head.next.next # skip duplicated node + head = head.next # not duplicate of current node, move to next node + return dummy + +``` diff --git a/docs/Algorithm/Leetcode/Python/086._partition_list.md b/docs/Algorithm/Leetcode/Python/086._partition_list.md new file mode 100644 index 00000000..c1fd2dca --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/086._partition_list.md @@ -0,0 +1,56 @@ +###86. Partition List + + +题目: + + + +难度 : Medium + + +思路一: + + +最简单的思路就是两个dummy head,然后一个指向 小于的node,一个指向大于的node + + +思路二: + +不走寻常路了,使用两个指针,一个指向小于的尾巴,一个一直往后走,指向大于,然后交换node + +完成比完美更重要啊,其实可以先试试用简单方法,因为我用我的不走寻常路画了比较久的图,写起来也稍显没那么美观,还在交换node的部分卡了一会 + + + +``` +class Solution(object): + def partition(self, head, x): + """ + :type head: ListNode + :type x: int + :rtype: ListNode + """ + dummy = ListNode(-1) + dummy.next = head + + p1 = p2 = dummy + + while p1.next and p1.next.val < x: + p1 = p1.next + + p2 = p1.next + + while p2: + while p2.next and p2.next.val >= x: + p2 = p2.next + + if p2.next == None: + break + node = p2.next + p2.next = node.next + node.next = p1.next + p1.next = node + p1 = p1.next + + return dummy.next +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/088._merge_sorted_array.md b/docs/Algorithm/Leetcode/Python/088._merge_sorted_array.md new file mode 100644 index 00000000..d24fb9b3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/088._merge_sorted_array.md @@ -0,0 +1,67 @@ +# 88. Merge Sorted Array + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/merge-sorted-array/description/ + +> 内容描述 + +``` +Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. + +Note: + +The number of elements initialized in nums1 and nums2 are m and n respectively. +You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. +Example: + +Input: +nums1 = [1,2,3,0,0,0], m = 3 +nums2 = [2,5,6], n = 3 + +Output: [1,2,2,3,5,6] +``` + +## 解题方案 + +> 思路 1 + +给的数组可能是这样的 + +- nums1 : [0] +- m : 0 +- nums2 : [1] +- n : 1 + + +所以要判断m和n是不是仍然大于0, 但是m不需要了,因为我们本来就是要在nums1的基础上改,m如果还大于0的话我们不需要改nums1了,保留不变即可 + + +AC代码 + + +```python +class Solution: + def merge(self, nums1, m, nums2, n): + """ + :type nums1: List[int] + :type m: int + :type nums2: List[int] + :type n: int + :rtype: void Do not return anything, modify nums1 in-place instead. + """ + while m > 0 and n > 0: + if nums1[m-1] > nums2[n-1]: + nums1[m+n-1] = nums1[m-1] + m -= 1 + else: + nums1[m+n-1] = nums2[n-1] + n -= 1 + if n > 0: + nums1[:n] = nums2[:n] +``` + diff --git a/docs/Algorithm/Leetcode/Python/089._gray_code.md b/docs/Algorithm/Leetcode/Python/089._gray_code.md new file mode 100644 index 00000000..c0a9f193 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/089._gray_code.md @@ -0,0 +1,101 @@ +###89. Gray Code + + + +题目: + + + +难度: +Medium + +思路: + +首先不是从任何一个数开始都是有效的,所以naive的想法是从任何一个开始,然后如果能到2^n位,那么说明是有效的,问题解决. + +A gray code sequence must begin with 0. ->简化了一点 + +先写了一段代码: + +``` +def nextCode(curCode, res, n): + if curCode not in res: + res.append(curCode) + else: + return + if len(res) == pow(2,n): + return res + for i in range(n): + nCode = curCode[:] + nCode[i] = 1 if curCode[i] == 0 else 0 + nextCode(nCode,res,n) + +res = [] +nextCode([0,0,0],res,3) +print res +#[[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 0, 1], [0, 0, 1]] +``` +实际上问题是这段代码的时间复杂度感觉很高,但是试试 + + +不失所望,到11就超时 + +``` + +class Solution(object): + def grayCode(self, n): + """ + :type n: int + :rtype: List[int] + """ + def nextCode(curCode, res, n): + if curCode not in res: + res.append(curCode) + else: + return + if len(res) == pow(2,n): + return res + for i in xrange(n): + nCode = curCode[:] + nCode[i] = 1 if curCode[i] == 0 else 0 + nextCode(nCode, res, n) + + def listoVal(curCode,n): + val = 0 + for i in range(n-1,-1,-1): + val += pow(2,i) * curCode[i] + return val + + + res = [] + nextCode([0]*n, res, n) + # print res + + val = [] + for i in res: + val.append(listoVal(i,n)) + return val +``` + +然后居然有这个东西: +Gray code,要用位运算!瞑目 + + + + +服气,这个待研究 +``` +class Solution(object): + def grayCode(self, n): + """ + :type n: int + :rtype: List[int] + """ + result = [(i>>1)^i for i in range(pow(2,n))] + return results +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/090._subsets_ii.md b/docs/Algorithm/Leetcode/Python/090._subsets_ii.md new file mode 100644 index 00000000..b896628d --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/090._subsets_ii.md @@ -0,0 +1,158 @@ +# 90. Subsets II + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/subsets-ii/description/ + +> 内容描述 + +``` +Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set). + +Note: The solution set must not contain duplicate subsets. + +Example: + +Input: [1,2,2] +Output: +[ + [2], + [1], + [1,2,2], + [2,2], + [1,2], + [] +] +``` + +## 解题方案 + +> 思路 1 + + +``` +[[],[1]] 是 [1] 的子集合 +[[],[1],[2],[1,2]] 是 [1,2] 的子集合,实际上就是1的子集合们加了一个2 +新来的2不能再从头开始加了,它需要从[ .., [2],[1,2] ]加 才是合理的 + +****当出现多个重复数字时,应该从 已经拥有了新数字所出现全部次数的list开始加才是合理的**** +[[],[1]] 是 [1] 的子集合 +[[],[1],[2],[1,2]] 是 [1,2] 的子集合,实际上就是1的子集合们加了一个2 +[ + [2], + [1], + [1,2,2], + [2,2], + [1,2], + [] +] 是 [1,2,2] 的子集和,实际上也就是[1,2]的子集合加了一个2 +新来的2不能再从头开始加了,它需要从[ .., [2,2],[1,2,2] ]加 才是合理的 +例如: +``` + +自己的解法,这里最关键的就是先对nums进行了排序,保证了我们插入相同的数字时都是相邻的 +```python +class Solution(object): + def subsetsWithDup(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + res = [[]] + for i in range(len(nums)): + if any(nums[i] in tmp for tmp in res): + res.extend([tmp+[nums[i]] for tmp in res if tmp.count(nums[i]) == i - nums.index(nums[i])]) + else: + res.extend([tmp+[nums[i]] for tmp in res]) + return res +``` + +> 思路 2 + +参考别人的 + +现在来观察规律,与之前有不同之处是我们需要一个位置来mark,因为不再需要往之前出现过的地方再加了,看这个: +这里这个start是来记录了之前一次数组的长度,temp_size记住目前数组的长度,然后用这个来达到去重的目的,非常聪明 + +别人的解法,但是一个思路 + +```python +class Solution(object): + def subsetsWithDup(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + res = [[]] + tmp_size = 0 + for i in range(len(nums)): + start = tmp_size if i >= 1 and nums[i] == nums[i-1] else 0 + tmp_size = len(res) + for j in range(start, tmp_size): + res.append([nums[i]]+res[j]) + return res +``` + +> 思路 3 + +跟[leetcode第78题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/078._Subsets.md)一样,DFS, 只不过需要在dfs函数里加一个剪枝的条件,排除掉同样的子集。 + + +```python +class Solution(object): + def subsetsWithDup(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + res = [] + def dfs(depth, start, lst): + if lst not in res: + res.append(lst) + if depth == len(nums): + return + for i in range(start, len(nums)): + dfs(depth+1, i+1, lst+[nums[i]]) + dfs(0, 0, []) + return res +``` + + + +> 思路 4 + +跟[leetcode第78题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/078._Subsets.md)一样,backtrack + + +```python +class Solution(object): + def subsetsWithDup(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + res = [] + + def search(cur_lst, idx): + if idx == len(nums): + if cur_lst not in res: + res.append(cur_lst) + return + search(cur_lst + [nums[idx]], idx + 1) + search(cur_lst, idx + 1) + + search([], 0) + return res + +``` + +## References +[南郭子綦](https://www.cnblogs.com/zuoyuan/p/3758346.html) diff --git a/docs/Algorithm/Leetcode/Python/091._decode_ways.md b/docs/Algorithm/Leetcode/Python/091._decode_ways.md new file mode 100644 index 00000000..3abd24a8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/091._decode_ways.md @@ -0,0 +1,71 @@ +###91. Decode Ways + +题目: + + + + +tag : DP + +难度 : Medium + + + + + +``` +BASE CASE(len(s) = 1 和 len(s) = 2 ): +直接check + +非BASE CASE : +先令 dp[i] = 0 +如果s[i]是可以map的话 -> dp[i] += dp[i-1] 原本的s[0..i]decode方式加上s[i] +如果s[i-1,i]可以map的话 -> dp[i] += dp[i-2] 原本的s[0...i-1]decode方式加上s[i-1,i] +``` + + +Python代码(可美化) + +``` +class Solution(object): + def numDecodings(self, s): + """ + :type s: str + :rtype: int + """ + 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'] + 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'] + numbersToLetters = dict(zip(keys, values)) + + ways = {} + n = len(s) + for i in range(n): + ways[i] = 0 + if n == 0: + return 0 + elif n == 1 : + ways[0] = int(s in numbersToLetters) + elif n == 2: + if (s[0] in numbersToLetters) and (s[1] in numbersToLetters): + ways[1] += 1 + if (s in numbersToLetters): + ways[1] += 1 + else: + #s[0] + ways[0] = int(s[0] in numbersToLetters) + #s[01] + if (s[0] in numbersToLetters) and (s[1] in numbersToLetters): + ways[1] += 1 + if (s[:2] in numbersToLetters): + ways[1] += 1 + for i in range(2,n): + if s[i] in numbersToLetters: + ways[i] += ways[i-1] + if (s[i-1:i+1] in numbersToLetters): + ways[i] += ways[i-2] + + #print(ways[n-1]) + return ways[n-1] + +``` + diff --git a/docs/Algorithm/Leetcode/Python/092._reverse_linked_list_ii.md b/docs/Algorithm/Leetcode/Python/092._reverse_linked_list_ii.md new file mode 100644 index 00000000..f2b29da1 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/092._reverse_linked_list_ii.md @@ -0,0 +1,66 @@ +###92. Reverse Linked List II + +题目: + + + +难度: +Medium + + +跟 reverse linked list一样 + +思路: 找到 第 m 个node,然后开始reverse到第n个node,然后再把它们和原本的list连接起来 + +AC 代码 + +``` +class Solution(object): + def reverseBetween(self, head, m, n): + """ + :type head: ListNode + :type m: int + :type n: int + :rtype: ListNode + """ + # m == n, not reverse + if m == n : return head + + dummy = ListNode(-1) + dummy.next = head + + mbefore = dummy + cnt = 1 + + while mbefore and cnt < m: + mbefore = mbefore.next + cnt += 1 + + prev = None + cur = mbefore.next + tail1 = mbefore.next + + + while cnt <= n : + nxt = cur.next + cur.next = prev + prev = cur + cur = nxt + cnt += 1 + + + + mbefore.next = prev + tail1.next = cur + + return dummy.next +``` + +看了一下别人的代码,又比我写的好嘛,因为是保证m和n有效,用的是for循环先找到 m node: + + + for _ in range(m-1): + .... + + for _ in range(n-m): + reverse 操作 \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/093._restore_ip_addresses.md b/docs/Algorithm/Leetcode/Python/093._restore_ip_addresses.md new file mode 100644 index 00000000..55e31916 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/093._restore_ip_addresses.md @@ -0,0 +1,66 @@ +###93. Restore IP Addresses + +题目: + + + + +难度: + +Medium + + +基本思路已达到,等待AC之路 + +结果AC之路还是比较漫长的,因为不允许前缀为0困扰了一下 + +``` +class Solution(object): + def restoreIpAddresses(self, s): + """ + :type s: str + :rtype: List[str] + """ + self.res = [] + self.singgleAddresses([],s,4) + for i in range(len(self.res)): + self.res[i] = '.'.join(str(j) for j in self.res[i]) + return self.res + + + + def singgleAddresses(self, curRes, s, k): + """ + :type s: str + :rtype: List[str] + """ + if len(s) == 0 and k == 0: + if curRes not in self.res: + self.res.append(curRes) + if len(s) == 0 or k < 0: + return + else: + if self.between0And255(s[:1]): + self.singgleAddresses(curRes + [int(s[:1])], s[1:], k-1) + if self.between0And255(s[:2]): + self.singgleAddresses(curRes + [int(s[:2])], s[2:], k-1) + if self.between0And255(s[:3]): + self.singgleAddresses(curRes + [int(s[:3])], s[3:], k-1) + + def between0And255(self,s): + #前缀不允许为0 + if int(s) == 0 : + if len(s) == 1 : + return True + else: + return False + + if int(s) > 0 and s[0] == '0': + return False + if int(s) > 0 and int(s) <= 255: + return True + return False + +``` + + diff --git a/docs/Algorithm/Leetcode/Python/094._binary_tree_inorder_traversal.md b/docs/Algorithm/Leetcode/Python/094._binary_tree_inorder_traversal.md new file mode 100644 index 00000000..2b91f1ab --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/094._binary_tree_inorder_traversal.md @@ -0,0 +1,108 @@ +# 94. Binary Tree Inorder Traversal +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/binary-tree-inorder-traversal/description/ + +> 内容描述 + +``` + +Given a binary tree, return the inorder traversal of its nodes' values. + +Example: + +Input: [1,null,2,3] + 1 + \ + 2 + / + 3 + +Output: [1,3,2] +Follow up: Recursive solution is trivial, could you do it iteratively? +``` + +## 解题方案 + +> 思路 1 + + +递归,瞬秒 + + +```python +class Solution(object): + def inorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if not root: + return res + if root.left: + res.extend(self.inorderTraversal(root.left)) + res.append(root.val) + if root.right: + res.extend(self.inorderTraversal(root.right)) + return res +``` +> 思路 2 + +或者我们可以先写一下中序遍历的函数,然后一个一个贴上去 + +```python +class Solution(object): + def inorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + if root == None: + return [] + res = [] + self.inorder(root,res) + return res + + + def inorder(self,root,res): + if root == None: + return + self.inorder(root.left,res) + res.append(root.val) + self.inorder(root.right,res) +``` +> 思路 3 + +迭代 + +先一股脑把左边一条线全部push到底(即走到最左边),然后node最终为None了就开始pop stack了,然后因为pop出来的每一个node都是自己这棵树的root,所以看看它有没有右孩子,没有那肯定继续pop,有的话自然而然右孩子是下一个要被访问的节点。 + + +```python +class Solution(object): + def inorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if not root: + return res + + stack = [] + node = root + while node or (len(stack) > 0): + if node: + stack.append(node) + node = node.left + else: + node = stack.pop() + res.append(node.val) + node = node.right + return res +``` diff --git a/docs/Algorithm/Leetcode/Python/096._unique_binary_search_trees.md b/docs/Algorithm/Leetcode/Python/096._unique_binary_search_trees.md new file mode 100644 index 00000000..cf9d8c9a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/096._unique_binary_search_trees.md @@ -0,0 +1,56 @@ +# 96. Unique Binary Search Trees +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/unique-binary-search-trees/description/ + +> 内容描述 + +``` +Given n, how many structurally unique BST's (binary search trees) that store values 1 ... n? + +Example: + +Input: 3 +Output: 5 +Explanation: +Given n = 3, there are a total of 5 unique BST's: + + 1 3 3 2 1 + \ / / / \ \ + 3 2 1 1 3 2 + / / \ \ + 2 1 2 3 +``` + +## 解题方案 + +> 思路 1 + + +参照此处hint: + +https://shenjie1993.gitbooks.io/leetcode-python/096%20Unique%20Binary%20Search%20Trees.html + + +首先明确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)的值即可。此外这其实就是一个卡特兰数,可以直接用数学公式计算,不过上面的方法更加直观一些。 + + +```python +class Solution(object): + def numTrees(self, n): + """ + :type n: int + :rtype: int + """ + dp = [1 for i in range(n+1)] + for i in range(2, n+1): + s = 0 + for k in range(i): + s += dp[k]*dp[i-k-1] + dp[i] = s + return dp[-1] +``` diff --git a/docs/Algorithm/Leetcode/Python/098._validate_binary_search_tree.md b/docs/Algorithm/Leetcode/Python/098._validate_binary_search_tree.md new file mode 100644 index 00000000..c4b5dcfb --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/098._validate_binary_search_tree.md @@ -0,0 +1,74 @@ +###98. Validate Binary Search Tree + +题目: + + + + +难度: + +Easy + + +以前做过这道题,valid binary tree,需要check两件事: + + +``` + 10 + / \ + 7 20 + / \ + 5 40 +``` + + +- node.left.val < node.val + - right subtree of left child, value < node.val +- node.right.val > node.val + - left subtree of the right child, value > node.val + + +wikipedia上有伪码: + +``` +truct TreeNode { + int key; + int value; + struct TreeNode *left; + struct TreeNode *right; +}; + +bool isBST(struct TreeNode *node, int minKey, int maxKey) { + if(node == NULL) return true; + if(node->key < minKey || node->key > maxKey) return false; + + return isBST(node->left, minKey, node->key) && isBST(node->right, node->key, maxKey); +} + + +if(isBST(root, INT_MIN, INT_MAX)) { + puts("This is a BST."); +} else { + puts("This is NOT a BST!"); +} +``` + +实际上就是每次往下看,node都确保被夹在一个范围。 + +翻译了一下伪码,AC + + +``` +class Solution(object): + def isValidBST(self, root): + """ + :type root: TreeNode + :rtype: bool + """ + return self.isBST(root, float('-inf'),float('inf')) + + def isBST(self, root, minKey, maxKey): + if root == None: return True + if root.val <= minKey or root.val >= maxKey : return False + return self.isBST(root.left,minKey,root.val) and self.isBST(root.right, root.val, maxKey) +``` diff --git a/docs/Algorithm/Leetcode/Python/100._same_tree.md b/docs/Algorithm/Leetcode/Python/100._same_tree.md new file mode 100644 index 00000000..f12c86c3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/100._same_tree.md @@ -0,0 +1,49 @@ +### 100. Same Tree + +题目: + + + + +难度: + +Easy + + +太简单了,递归一行! + + +```python +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def isSameTree(self, p, q): + """ + :type p: TreeNode + :type q: TreeNode + :rtype: bool + """ + 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 +``` + +```python +class Solution(object): + def isSameTree(self, p, q): + """ + :type p: TreeNode + :type q: TreeNode + :rtype: bool + """ + if (not p and q) or (p and not q): + return False + if not p and not q: + return True + if p.val == q.val: + return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) + return False +``` diff --git a/docs/Algorithm/Leetcode/Python/101._symmetric_tree.md b/docs/Algorithm/Leetcode/Python/101._symmetric_tree.md new file mode 100644 index 00000000..cb6f5219 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/101._symmetric_tree.md @@ -0,0 +1,45 @@ +### 101. Symmetric Tree + +题目: + + + + +难度: + +Easy + + +两棵树symmetric, 有几种可能: + +- 均为none ,symmetric +- 左孩子,右孩子都不存在,并且值相等, symmetric +- 右子树 和 另一棵树的左子树相等,左子树 和另一颗树的右子树相等 🌲 + + +```python +class Solution(object): + def isSymmetric(self, root): + """ + :type root: TreeNode + :rtype: bool + """ + if not root: + return True + return self.symmetric(root.left, root.right) + + def symmetric(self, l1, l2): + if not l1 or not l2: + if not l1 and not l2: + return True + else: + return False + if l1.val == l2.val: + return self.symmetric(l1.left, l2.right) and self.symmetric(l1.right, l2.left) + else: + return False +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/102._binary_tree_level_order_traversal.md b/docs/Algorithm/Leetcode/Python/102._binary_tree_level_order_traversal.md new file mode 100644 index 00000000..a16135d6 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/102._binary_tree_level_order_traversal.md @@ -0,0 +1,85 @@ +# 102. Binary Tree Level Order Traversal +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/binary-tree-level-order-traversal/description/ + +> 内容描述 + +``` +Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). + +For example: +Given binary tree [3,9,20,null,null,15,7], + 3 + / \ + 9 20 + / \ + 15 7 +return its level order traversal as: +[ + [3], + [9,20], + [15,7] +] +``` + +## 解题方案 + +> 思路 1 + +递归 + +```python +class Solution(object): + def levelOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + res = [] + self.recurHelper(root, 0, res) + return res + + def recurHelper(self, root, level, res): + if not root: return + if len(res) < level + 1: + res.append([]) + res[level].append(root.val) + self.recurHelper(root.left, level+1, res) + self.recurHelper(root.right, level+1, res) +``` + +> 思路 2 + +迭代,利用curLevel和nextLevel来记录,然后按层append. + + +```python +class Solution(object): + def levelOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + if not root: + return [] + res, cur_level = [], [root] + while cur_level: + next_level, tmp_res = [], [] + for node in cur_level: + tmp_res.append(node.val) + if node.left: + next_level.append(node.left) + if node.right: + next_level.append(node.right) + res.append(tmp_res) + cur_level = next_level + return res +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/103._binary_tree_zigzag_level_order_traversal.md b/docs/Algorithm/Leetcode/Python/103._binary_tree_zigzag_level_order_traversal.md new file mode 100644 index 00000000..edc9b398 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/103._binary_tree_zigzag_level_order_traversal.md @@ -0,0 +1,43 @@ +### 103. Binary Tree Zigzag Level Order Traversal + +题目: + + + + +难度: + +Medium + + + +```python +class Solution(object): + def zigzagLevelOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + if not root: + return [] + res, cur_level, level_count = [], [root], 0 + while cur_level: + next_level, tmp_res = [], [] + for node in cur_level: + tmp_res.append(node.val) + if node.left: + next_level.append(node.left) + if node.right: + next_level.append(node.right) + if level_count % 2 == 0: + res.append(tmp_res) + else: + tmp_res.reverse() + res.append(tmp_res) + level_count += 1 + cur_level = next_level + + return res +``` + + diff --git a/docs/Algorithm/Leetcode/Python/104._maximum_depth_of_binary_tree.md b/docs/Algorithm/Leetcode/Python/104._maximum_depth_of_binary_tree.md new file mode 100644 index 00000000..451160d3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/104._maximum_depth_of_binary_tree.md @@ -0,0 +1,23 @@ +### 104. Maximum Depth of Binary Tree + +题目: + + + +难度: + +Easy + + +简单题,但是这道题跟[leetcode111](https://github.com/Lisanaaa/thinking_in_lc/blob/master/111._minimum_depth_of_binary_tree.md)不一样,这道题没有特殊情况,所以一行就够了 + + +```python +class Solution(object): + def maxDepth(self, root): + """ + :type root: TreeNode + :rtype: int + """ + return 1 + max(map(self.maxDepth, (root.left, root.right))) if root else 0 +``` diff --git a/docs/Algorithm/Leetcode/Python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md b/docs/Algorithm/Leetcode/Python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md new file mode 100644 index 00000000..44167943 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md @@ -0,0 +1,60 @@ +# 105. Construct Binary Tree from Preorder and Inorder Traversal 从前序与中序遍历序列构造二叉树 + +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/ +* https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/ + +> 内容描述 + +``` +根据一棵树的前序遍历与中序遍历构造二叉树。 + +注意: +你可以假设树中没有重复的元素。 + +例如,给出 + +前序遍历 preorder = [3,9,20,15,7] +中序遍历 inorder = [9,3,15,20,7] +返回如下的二叉树: + + 3 + / \ + 9 20 + / \ + 15 7 +``` + +## 解题方案 + +> 思路 1 + +一句话,看到树🌲就要想到递归 + +- preorder 是 根 -> 左 -> 右 +- inorder 是 左 -> 根 -> 右 + +首先pre的第一个就是整个树的root, 假设 preorder[0] = inorder[k],那么inorder的前k-1个就是树的左子树,后面部分就是树的右子树 + +```python +class Solution(object): + def buildTree(self, preorder, inorder): + """ + :type preorder: List[int] + :type inorder: List[int] + :rtype: TreeNode + """ + if not preorder or len(preorder) == 0: + return None + root = TreeNode(preorder[0]) + k = inorder.index(preorder[0]) + root.left = self.buildTree(preorder[1:k+1], inorder[0:k]) + root.right = self.buildTree(preorder[k+1:], inorder[k+1:]) + return root +``` + diff --git a/docs/Algorithm/Leetcode/Python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md b/docs/Algorithm/Leetcode/Python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md new file mode 100644 index 00000000..61331c52 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md @@ -0,0 +1,68 @@ +###106. Construct Binary Tree from Inorder and Postorder Traversal + +题目: + + + +难度 : Medium + + +inorder 是 左 -> 根 -> 右 +postorder 是 左 -> 右 -> 根 + + +跟105基本一样 + +还是先弄了一个递归可用版本 + + +``` +def buildTree(inorder, postorder): + """ + :type preorder: List[int] + :type inorder: List[int] + :rtype: TreeNode + """ + if postorder == inorder == []: + return None + else: + rootVal = postorder[-1] + root = TreeNode(rootVal) + k = inorder.index(rootVal) + root.left = buildTree(inorder[:k],postorder[:k]) + root.right = buildTree(inorder[k+1:],postorder[k:-1]) + return root + +``` +照抄105 + + +``` +class Solution(object): + def buildTree(self, inorder, postorder): + """ + :type inorder: List[int] + :type postorder: List[int] + :rtype: TreeNode + """ + def buildTree(inorder, postorder, li, ri ,lp, rp ): + if lp > rp or li > ri: + return None + + root = TreeNode(postorder[rp]) + k = inorder.index(postorder[rp]) + + # left node + left = buildTree(inorder, postorder, li, k-1, lp, lp + k - li - 1) + right = buildTree(inorder, postorder, k+1, ri, lp+k-li, rp-1) + + root.left = left + root.right = right + + return root + + return buildTree(inorder, postorder, 0, len(inorder) - 1, 0, len(postorder) - 1) + +``` + + diff --git a/docs/Algorithm/Leetcode/Python/107._binary_tree_level_order_traversal_ii.md b/docs/Algorithm/Leetcode/Python/107._binary_tree_level_order_traversal_ii.md new file mode 100644 index 00000000..a7fd3d73 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/107._binary_tree_level_order_traversal_ii.md @@ -0,0 +1,48 @@ +###107. Binary Tree Level Order Traversal II + +题目: + + + + +难度: + +Easy + + +用102 的算法作弊 + + +``` +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def levelOrderBottom(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + res = [] + + if root == None: return [] + + curLevel = [root] + while curLevel: + nextLevel = [] + tmpRes = [] + for node in curLevel: + tmpRes.append(node.val) + if node.left: nextLevel.append(node.left) + if node.right: nextLevel.append(node.right) + res.append(tmpRes) + curLevel = nextLevel + res.reverse() + return res +``` + + diff --git a/docs/Algorithm/Leetcode/Python/108._convert_sorted_array_to_binary_search_tree.md b/docs/Algorithm/Leetcode/Python/108._convert_sorted_array_to_binary_search_tree.md new file mode 100644 index 00000000..66b21ee1 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/108._convert_sorted_array_to_binary_search_tree.md @@ -0,0 +1,34 @@ +### 108. Convert Sorted Array to Binary Search Tree + +题目: + + + +难度: +Medium + + +思路: + +递归 + +- nums为空,return None +- nums非空,nums[n/2]为中间元素,根结点,nums[:mid]为左子树, nums[mid+1:]为右子树 + + +```python +class Solution(object): + def sortedArrayToBST(self, nums): + """ + :type nums: List[int] + :rtype: TreeNode + """ + if not nums: + return None + if nums: + mid = len(nums) / 2 + root = TreeNode(nums[mid]) + root.left = self.sortedArrayToBST(nums[:mid]) + root.right = self.sortedArrayToBST(nums[mid+1:]) + return root +``` diff --git a/docs/Algorithm/Leetcode/Python/109._convert_sorted_list_to_binary_search_tree.md b/docs/Algorithm/Leetcode/Python/109._convert_sorted_list_to_binary_search_tree.md new file mode 100644 index 00000000..6858fb52 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/109._convert_sorted_list_to_binary_search_tree.md @@ -0,0 +1,41 @@ +### 109. Convert Sorted List to Binary Search Tree + + + +题目: + + + +难度: + +Medium + +思路: + +跟第 108 题一样 + +```python +class Solution(object): + def sortedListToBST(self, head): + """ + :type head: ListNode + :rtype: TreeNode + """ + def sortedArrayToBST(nums): + if not nums: + return None + if nums: + mid = len(nums) / 2 + root = TreeNode(nums[mid]) + root.left = sortedArrayToBST(nums[:mid]) + root.right = sortedArrayToBST(nums[mid+1:]) + return root + if not head: + return None + else: + lst = [] + while head: + lst.append(head.val) + head = head.next + return sortedArrayToBST(lst) +``` diff --git a/docs/Algorithm/Leetcode/Python/110._balanced_binary_tree.md b/docs/Algorithm/Leetcode/Python/110._balanced_binary_tree.md new file mode 100644 index 00000000..5dc519d6 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/110._balanced_binary_tree.md @@ -0,0 +1,68 @@ +# 110. Balanced Binary Tree +**难度: 简单** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/balanced-binary-tree/description/ + +> 内容描述 + +``` +Given a binary tree, determine if it is height-balanced. + +For 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. + +Example 1: + +Given the following tree [3,9,20,null,null,15,7]: + + 3 + / \ + 9 20 + / \ + 15 7 +Return true. + +Example 2: + +Given the following tree [1,2,2,3,3,null,null,4,4]: + + 1 + / \ + 2 2 + / \ + 3 3 + / \ + 4 4 +Return false. +``` + +## 解题方案 + +> 思路 1 + +递归,判断左右子树最大高度差不超过1且左右子树均为平衡树 + +```python +class Solution(object): + def isBalanced(self, root): + """ + :type root: TreeNode + :rtype: bool + """ + def height(node): + if not node: + return 0 + return 1 + max(height(node.left), height(node.right)) + if not root: + return True + return abs(height(root.left) - height(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right) +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/111._minimum_depth_of_binary_tree.md b/docs/Algorithm/Leetcode/Python/111._minimum_depth_of_binary_tree.md new file mode 100644 index 00000000..d84421b0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/111._minimum_depth_of_binary_tree.md @@ -0,0 +1,94 @@ +### 111. Minimum Depth of Binary Tree + +题目: + + + +难度: + +Easy + + +思路,看完题目我想当然的认为就是直接递归取最小的值,代码如下: +``` +class Solution(object): + def minDepth(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if not root: + return 0 + return 1 + min(map(self.minDepth, (root.left, root.right))) +``` + + +但是没过,有一种特殊情况就是 + +注意```leaf node```反正就是没有```left```和```right```的 + +比如下图 + + +``` +1 + \ + 2 +``` + +```2```是一个孩子节点 + +这种情况应该输出```2```而不是```1``` + + + +唯一的特殊情况就是上面这种了,因为```root```下只有一个左节点或者是右节点,这样另外一边的空节点并不算是```leaf node``` + +```leaf node: itself is not null but it has both children null``` + +因此要避免这种情况,代码改成下面: + + +```python +# Definition for a binary tree node. +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def minDepth(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if not root: + return 0 + depth_under_root = map(self.minDepth, (root.left, root.right)) + return 1 + (min(depth_under_root) or max(depth_under_root)) +``` + + +所以还是要养成多写edge case的好习惯,也许就帮你避免了general写法的特例,代码如下 +```python +class Solution(object): + def minDepth(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if root == None: + return 0 + elif root.left == None and root.right == None: + return 1 + else : + if root.left == None: + return 1 + self.minDepth(root.right) + elif root.right == None: + return 1 + self.minDepth(root.left) + else: + return min(1+ self.minDepth(root.left), 1+ self.minDepth(root.right)) + +``` diff --git a/docs/Algorithm/Leetcode/Python/112._path_sum.md b/docs/Algorithm/Leetcode/Python/112._path_sum.md new file mode 100644 index 00000000..1f6b07a5 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/112._path_sum.md @@ -0,0 +1,28 @@ +### 112. Path Sum + +题目: + + + +难度: + +Easy + + +递归 + +```python +class Solution(object): + def hasPathSum(self, root, sum): + """ + :type root: TreeNode + :type sum: int + :rtype: bool + """ + if not root: + return False + if root.left or root.right: + return self.hasPathSum(root.left, sum-root.val) or self.hasPathSum(root.right, sum-root.val) + else: + return root.val == sum +``` diff --git a/docs/Algorithm/Leetcode/Python/113._path_sum_ii.md b/docs/Algorithm/Leetcode/Python/113._path_sum_ii.md new file mode 100644 index 00000000..d1f2ea9c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/113._path_sum_ii.md @@ -0,0 +1,40 @@ +### 113. Path Sum II + +题目: + + + + + +tag : DFS + + +难度 : Medium + + +注意宁愿写几次curList + [root.val] 也不要直接传一个list进去,因为list pass by reference的亏已经吃过了 + +```python +class Solution(object): + def pathSum(self, root, sum): + """ + :type root: TreeNode + :type sum: int + :rtype: List[List[int]] + """ + res = [] + self.auxPathSum(root, sum, [], res) + return res + def auxPathSum(self, root, sum, cur_list, cur_lists): + if not root: + return + sum -= root.val + if sum == 0 and not root.left and not root.right: + cur_lists.append(cur_list + [root.val]) + return + if root.left: + self.auxPathSum(root.left, sum, cur_list + [root.val], cur_lists) + if root.right: + self.auxPathSum(root.right, sum, cur_list + [root.val], cur_lists) +``` + diff --git a/docs/Algorithm/Leetcode/Python/114._flatten_binary_tree_to_linked_list.md b/docs/Algorithm/Leetcode/Python/114._flatten_binary_tree_to_linked_list.md new file mode 100644 index 00000000..81ad647c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/114._flatten_binary_tree_to_linked_list.md @@ -0,0 +1,71 @@ +### 114. Flatten Binary Tree to Linked List + +题目: + + + +难度: + +Medium + +这道题看了hint,说每个node的右节点都是相应先序遍历中它的下一个节点。 +所以我的思路是先把先序遍历的node顺序搞出来,然后对于这里面的每一个节点,只需要做两个操作: +1. node.left = None +2. node.right = 相应先序遍历中node的下一个节点 + +```python +class Solution(object): + def flatten(self, root): + """ + :type root: TreeNode + :rtype: void Do not return anything, modify root in-place instead. + """ + def preorder(root): + res = [] + if not root: + return res + res.append(root) + if root.left: + res.extend(preorder(root.left)) + if root.right: + res.extend(preorder(root.right)) + return res + if not root: + return + node_order = preorder(root) + for i in range(len(node_order)-1): + node_order[i].left = None + node_order[i].right = node_order[i+1] + node_order[-1].left = None + node_order[-1].right = None +``` +beat 40.67% + +另外一种解法: +1. copy the left and right subtree +2. then cut root’s left subtree +3. do DFS +4. left and right has been flattened and connect them left and right back to the root + +```python +class Solution(object): + def flatten(self, root): + """ + :type root: TreeNode + :rtype: void Do not return anything, modify root in-place instead. + """ + if not root: + return + left_node = root.left + right_node = root.right + root.left = None + self.flatten(left_node) + self.flatten(right_node) + if left_node: + root.right = left_node + while left_node.right: + left_node = left_node.right + left_node.right = right_node +``` +beat 32.18% + diff --git a/docs/Algorithm/Leetcode/Python/116._populating_next_right_pointers_in_each_node.md b/docs/Algorithm/Leetcode/Python/116._populating_next_right_pointers_in_each_node.md new file mode 100644 index 00000000..f0548445 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/116._populating_next_right_pointers_in_each_node.md @@ -0,0 +1,104 @@ +# 116. Populating Next Right Pointers in Each Node +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/populating-next-right-pointers-in-each-node/description/ + +> 内容描述 + +``` +Given a binary tree + +struct TreeLinkNode { + TreeLinkNode *left; + TreeLinkNode *right; + TreeLinkNode *next; +} +Populate 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. + +Initially, all next pointers are set to NULL. + +Note: + +You may only use constant extra space. +Recursive approach is fine, implicit stack space does not count as extra space for this problem. +You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children). +Example: + +Given the following perfect binary tree, + + 1 + / \ + 2 3 + / \ / \ +4 5 6 7 +After calling your function, the tree should look like: + + 1 -> NULL + / \ + 2 -> 3 -> NULL + / \ / \ +4->5->6->7 -> NULL +``` + +## 解题方案 + +> 思路 1 + +递归 + +```python +class Solution: + # @param root, a tree link node + # @return nothing + def connect(self, root): + res = [] + self.recurHelper(root, 0, res) + for level in res: + for i in range(len(level)-1): + level[i].next = level[i+1] + + + def recurHelper(self, root, level, res): + if not root: + return + if len(res) < level + 1: + res.append([]) + res[level].append(root) + self.recurHelper(root.left, level+1, res) + self.recurHelper(root.right, level+1, res) +``` + +> 思路 2 + +迭代,利用curLevel和nextLevel来记录,然后按层append. + + +```python +class Solution: + # @param root, a tree link node + # @return nothing + def connect(self, root): + if not root: + return + res, cur_level = [], [root] + while cur_level: + next_level = [] + for node in cur_level: + if node.left: + next_level.append(node.left) + if node.right: + next_level.append(node.right) + res.append(cur_level) + cur_level = next_level + + for cur_level in res: + for i in range(len(cur_level)-1): + cur_level[i].next = cur_level[i+1] +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md b/docs/Algorithm/Leetcode/Python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md new file mode 100644 index 00000000..72b10dfb --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md @@ -0,0 +1,99 @@ +# 117. Populating Next Right Pointers in Each Node II +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/description/ + +> 内容描述 + +``` +Given a binary tree + +struct TreeLinkNode { + TreeLinkNode *left; + TreeLinkNode *right; + TreeLinkNode *next; +} +Populate 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. + +Initially, all next pointers are set to NULL. + +Note: + +You may only use constant extra space. +Recursive approach is fine, implicit stack space does not count as extra space for this problem. +Example: + +Given the following binary tree, + + 1 + / \ + 2 3 + / \ \ +4 5 7 +After calling your function, the tree should look like: + + 1 -> NULL + / \ + 2 -> 3 -> NULL + / \ \ +4-> 5 -> 7 -> NULL +``` + +## 解题方案 + +> 思路 1 + +递归 + +```python +class Solution: + # @param root, a tree link node + # @return nothing + def connect(self, root): + res = [] + self.recurHelper(root, 0, res) + for cur_level in res: + for i in range(len(cur_level)-1): + cur_level[i].next = cur_level[i+1] + + def recurHelper(self, root, level, res): + if not root: return + if len(res) < level + 1: + res.append([]) + res[level].append(root) + self.recurHelper(root.left, level+1, res) + self.recurHelper(root.right, level+1, res) +``` + +> 思路 2 + +迭代版本, beats 100% + +```python +class Solution: + # @param root, a tree link node + # @return nothing + def connect(self, root): + if not root: + return + res, cur_level = [], [root] + while cur_level: + next_level = [] + for node in cur_level: + if node.left: + next_level.append(node.left) + if node.right: + next_level.append(node.right) + res.append(next_level) + cur_level = next_level + + for cur_level in res: + for i in range(len(cur_level)-1): + cur_level[i].next = cur_level[i+1] +``` + + diff --git a/docs/Algorithm/Leetcode/Python/118._pascal's_triangle.md b/docs/Algorithm/Leetcode/Python/118._pascal's_triangle.md new file mode 100644 index 00000000..2b7c01a3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/118._pascal's_triangle.md @@ -0,0 +1,73 @@ +# 118. Pascal's Triangle +**难度: 简单** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/pascals-triangle/description/ + +> 内容描述 + +``` +Given a non-negative integer numRows, generate the first numRows of Pascal's triangle. +``` +![](https://github.com/apachecn/LeetCode/blob/master/images/118/PascalTriangleAnimated2.gif) + +``` +In Pascal's triangle, each number is the sum of the two numbers directly above it. + +Example: + +Input: 5 +Output: +[ + [1], + [1,1], + [1,2,1], + [1,3,3,1], + [1,4,6,4,1] +] +``` + +## 解题方案 + +> 思路 1 + + +高中数学知识,把行数理理清楚就ok + + +```python +class Solution(object): + def generate(self, numRows): + """ + :type numRows: int + :rtype: List[List[int]] + """ + if numRows == 0: + return [] + res = [[1]] + for i in range(1, numRows): + tmp = [1] + for j in range(1, i): + tmp.append(res[-1][j-1]+res[-1][j]) + tmp.append(1) + res.append(tmp) + return res +``` +或者可以写得更简单一些,这里谢谢荼靡大佬的想法,棒! + +```python +class Solution(object): + def generate(self, numRows): + """ + :type numRows: int + :rtype: List[List[int]] + """ + res = [[1]] + for i in range(1, numRows): + res.append(map(lambda x,y:x+y, [0]+res[-1], res[-1]+[0])) + return res[:numRows] +``` + diff --git a/docs/Algorithm/Leetcode/Python/119. _Pascal's_Triangle_II.md b/docs/Algorithm/Leetcode/Python/119. _Pascal's_Triangle_II.md new file mode 100644 index 00000000..5aec2a5b --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/119. _Pascal's_Triangle_II.md @@ -0,0 +1,32 @@ +### 119. Pascal's Triangle II + +题目: + + +难度 : Easy + + + +思路: + +太简单了,注意一点算数就好 + + +```python +class Solution(object): + def getRow(self, rowIndex): + """ + :type rowIndex: int + :rtype: List[int] + """ + if rowIndex == 0: + return [1] + res = [1] + for i in range(1, rowIndex+1): + tmp = [1] + for j in range(1, i): + tmp.append(res[j-1]+res[j]) + tmp.append(1) + res = tmp + return res +``` diff --git a/docs/Algorithm/Leetcode/Python/120. Triangle.md b/docs/Algorithm/Leetcode/Python/120. Triangle.md new file mode 100644 index 00000000..954a28cb --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/120. Triangle.md @@ -0,0 +1,72 @@ +### 120. Triangle + +题目: + + + +难度: +Medium + +思路: + +先是要注意下这句话:**Each step you may move to adjacent numbers on the row below** + +在考虑adjacent number的定义,并不是角标的adjacent,而是真的形态上的adjacent + +比如 + +``` + -1 -1 + 2 1 最小 1 0 +-2 2 0 -1 2 0 +``` + +最小是-1, 而并不能从第二排的0跳到第三排的第一个造成-2. + + so AC代码 + +感觉关于dp,我可能还需要补一些东西,因为我不能做到O(n) space + +``` +class Solution(object): + def minimumTotal(self, triangle): + """ + :type triangle: List[List[int]] + :rtype: int + """ + # n total rows of triangle + n = len(triangle) + if n == 1: return triangle[0][0] + elif n == 2 : return min(triangle[0][0] + triangle[1][0], triangle[0][0] + triangle[1][1]) + else: + res = [] + for i in range(n): + res.append(triangle[i]) + + res[0] = [triangle[0][0]] + res[1] = [triangle[0][0] + triangle[1][0], triangle[0][0] + triangle[1][1]] + + for i in range(2,n): + for j in range(i+1): + if j == 0: + res[i][j] = res[i-1][j] + triangle[i][j] + elif j == i: + res[i][j] = res[i-1][-1] + triangle[i][j] + else: + res[i][j] = min(res[i-1][j-1],res[i-1][j]) + triangle[i][j] + + return min(res[-1]) +``` + + + + + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/121._Best_Time_to_Buy_and_Sell_Stock.md b/docs/Algorithm/Leetcode/Python/121._Best_Time_to_Buy_and_Sell_Stock.md new file mode 100644 index 00000000..1e33b35f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/121._Best_Time_to_Buy_and_Sell_Stock.md @@ -0,0 +1,84 @@ +# 121. Best Time to Buy and Sell Stock +**难度: 简单** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ + +> 内容描述 + +``` +Say you have an array for which the ith element is the price of a given stock on day i. + +If 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. + +Note that you cannot sell a stock before you buy one. + +Example 1: + +Input: [7,1,5,3,6,4] +Output: 5 +Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. + Not 7-1 = 6, as selling price needs to be larger than buying price. +Example 2: + +Input: [7,6,4,3,1] +Output: 0 +Explanation: In this case, no transaction is done, i.e. max profit = 0. +``` + +## 解题方案 + + +> 思路1 + +对于从第一天后的每一天,我们都假设昨天就已经卖掉了,那么现在我们可以看看**如果昨天卖可以赚的钱加上今天与昨天股票的价格差价**是否大于0,如果大于0就说明今天卖赚的更多,那么我们就还是先存下今天卖可以多赚的max_cur,继续往后看,如果小于0就还是坚持昨天可以赚的钱(即之前的max_cur) + +All the straight forward solution should work, but if the interviewer twists the question slightly +by giving the difference array of prices, Ex: for ```{1, 7, 4, 11}```, if he gives ```{0, 6, -3, 7}```, +you might end up being confused. + +Here, the logic is to calculate the difference ```(maxCur += prices[i] - prices[i-1])``` +of the original array, and find a contiguous subarray giving maximum profit. +If the difference falls below ```0```, reset it to zero. + +参考[Maximum subarray problem](https://en.wikipedia.org/wiki/Maximum_subarray_problem), +[Kadane's Algorithm](https://discuss.leetcode.com/topic/19853/kadane-s-algorithm-since-no-one-has-mentioned-about-this-so-far-in-case-if-interviewer-twists-the-input) + + +``` +Why maxCur = Math.max(0, maxCur += prices[i] - prices[i-1]); ? + +Well, we can assume opt(i) as the max Profit you will get if you sell the stock at day i; + +We now face two situations: + +We hold a stock at day i, which means opt(i) = opt(i - 1) - prices[i - 1] + prices[i] (max Profit you can get if you sell stock at day(i-1) - money you lose if you buy the stock at day (i-1) + money you gain if you sell the stock at day i. + +We do not hold a stock at day i, which means we cannot sell any stock at day i. In this case, money we can get at day i is 0; + +opt(i) is the best case of 1 and 2. + +So, opt(i) = Max{opt(i - 1) - prices[i - 1] + prices[i], 0} +``` + +```python +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + if not prices or len(prices) == 0: + return 0 + res, max_cur = 0, 0 + for i in range(1, len(prices)): + max_cur = max(0, max_cur+prices[i]-prices[i-1]) # 如果今天卖相比于昨天卖能多赚,则今天卖,否则之前就卖了 + res = max(res, max_cur) + return res +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/124._Binary_Tree_Maximum_Path_Sum.md b/docs/Algorithm/Leetcode/Python/124._Binary_Tree_Maximum_Path_Sum.md new file mode 100644 index 00000000..459901c2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/124._Binary_Tree_Maximum_Path_Sum.md @@ -0,0 +1,65 @@ +### 124. Binary Tree Maximum Path Sum + +题目: + + + +难度: + +Hard + + +思路 + + + +```python +class Solution(object): + + def maxPathSum(self, root): + """ + :type root: TreeNode + :rtype: int + """ + self.global_max = root.val if root else 0 + self.findmax(root) + return self.global_max + + def findmax(self, node): + if not node: + return 0 + + left = self.findmax(node.left) + left = left if left > 0 else 0 + + right = self.findmax(node.right) + right = right if right > 0 else 0 + # 这句是精髓,只要判断出当前这个点作为root的path更长,就更新一下 + self.global_max = max(left + right + node.val, self.global_max) + # 这里是因为sub_path只能为一条边,不然跟上面的root组合起来就不是path了 + return max(left, right) + node.val +``` + +其实开始的时候我想当然的用了很傻的方法,并且是错误的,因为这样当[-10,9,20,null,null,15,7]的时候我们会取所有的点,返回41,然而我们可以取到42的, +即15+7+20 + +``` +class Solution(object): + def maxPathSum(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if not root: + return 0 + if not root.left and not root.right: + return root.val + if not root.left: + return max(root.val, root.val+self.maxPathSum(root.right)) + if not root.right: + return max(root.val, root.val+self.maxPathSum(root.left)) + return max(root.val, + root.val+self.maxPathSum(root.right), + root.val+self.maxPathSum(root.left), + root.val+self.maxPathSum(root.left)+self.maxPathSum(root.right)) +``` diff --git a/docs/Algorithm/Leetcode/Python/125._valid_palindrome.md b/docs/Algorithm/Leetcode/Python/125._valid_palindrome.md new file mode 100644 index 00000000..d3e09f6c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/125._valid_palindrome.md @@ -0,0 +1,46 @@ +### 125. Valid Palindrome + +题目: + + + +难度: + +Easy + + + +就是比较reversed string 和原本的是否相等. + + +```python +class Solution(object): + def isPalindrome(self,s): + """ + :type s: str + :rtype: bool + """ + + new=[] + s = s.lower() + + for i in s: + if '0'<=i<='9' or 'a'<=i<='z': + new.append(i) + + return new == new[::-1] +``` + +或者用正则,详见[re.sub()用法](http://blog.csdn.net/geekleee/article/details/75309433) +瞬间```beats 97.71%``` +```python +class Solution(object): + def isPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + newString = re.sub("[^0-9a-zA-Z]+", "", s) + return newString.lower() == newString.lower()[::-1] +``` + diff --git a/docs/Algorithm/Leetcode/Python/126. Word Ladder II.md b/docs/Algorithm/Leetcode/Python/126. Word Ladder II.md new file mode 100644 index 00000000..99e75f49 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/126. Word Ladder II.md @@ -0,0 +1,99 @@ +### 126. Word Ladder II + +题目: + + + +难度: + +Hard + +其实关键在于怎么优化和表示图 + + + +思路来自1p3a: + +这题目实在是太适合python了  如此简洁 + +就是基本的bfs,典型的level order traverse +有两个坑: + +1. 不要判断字典里的某两个word是否只相差一个字母,而是要判断某个word的邻居(和他只相差一个字母的所有word)是否在字典里,这样的改进会使这一步的复杂度下降很多,否则超时妥妥 +2. 每一轮访问过的word一定要从字典中删除掉,否则一定会超时 + +最后见到end word就收 +完成 + + + +拿题目的例子来看: + +```\ + hit + | + hot + / \ + dot lot + | | + dog log + \ / + cog +``` + +routine 字典,然后再根据这个来寻找路径 + +`{'cog': ['log', 'dog'], 'hit': [], 'log': ['lot'], 'dog': ['dot'], 'hot': ['hit'], 'lot': ['hot'], 'dot': ['hot']}` + +```'cog': ['log', 'dog']```这里的意思就是说在走到```'cog'```之前尝试过了```'log'```和```'dog'```,即previous tried node + +而生成字典的过程就是BFS的,此处保证寻找的路径就是最短的。 + +AC代码: + +```python +class Solution(object): + def findLadders(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: List[List[str]] + """ + + def backtrack(result, trace, path, word): + if len(trace[word]) == 0: + result.append([word] + path) + else: + for prev in trace[word]: + backtrack(result, trace, [word] + path, prev) + + lookup = set(wordList) | set([beginWord]) + res, cur, routine = [], set([beginWord]), {word: [] for word in lookup} + while cur and endWord not in cur: + next_queue = set() + for word in cur: + lookup.remove(word) + for word in cur: + for i in range(len(word)): + for j in 'abcdefghijklmnopqrstuvwxyz': + candidate = word[:i] + j + word[i + 1:] + if candidate in lookup: + next_queue.add(candidate) + routine[candidate].append(word) + cur = next_queue + + if cur: + backtrack(res, routine, [], endWord) + return res +``` + + + +这样可以beat 69.09% + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/127._word_ladder.md b/docs/Algorithm/Leetcode/Python/127._word_ladder.md new file mode 100644 index 00000000..42a14a7a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/127._word_ladder.md @@ -0,0 +1,43 @@ +### 127. Word Ladder + +题目: + + + + +难度: + +Medium + +tag可以算BFS,其实就是求shortest path的变体 + +Reference from [kamyu104](https://github.com/kamyu104/LeetCode/blob/71e0ba555ee49befa01fcd9fc78c3528e2ab63a9/Python/word-ladder.py) + +```python +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + distance, cur, visited, lookup = 0, [beginWord], set([beginWord]), set(wordList) + + while cur: + next_queue = [] + + for word in cur: + if word == endWord: + return distance + 1 + for i in xrange(len(word)): + for j in 'abcdefghijklmnopqrstuvwxyz': + candidate = word[:i] + j + word[i + 1:] + if candidate not in visited and candidate in lookup: + next_queue.append(candidate) + visited.add(candidate) + distance += 1 + cur = next_queue + + return 0 +``` diff --git a/docs/Algorithm/Leetcode/Python/128._Longest_Consecutive_Sequence.md b/docs/Algorithm/Leetcode/Python/128._Longest_Consecutive_Sequence.md new file mode 100644 index 00000000..53e57505 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/128._Longest_Consecutive_Sequence.md @@ -0,0 +1,70 @@ +### 128. Longest Consecutive Sequence + +题目: + + + +难度: + +Hard + + +### 思路 +首先去重复,时间```O(N)```,然后将所有元素都放到一个字典中,这样判断一个数字的后续在不在这个字典中,如果存在就一直判断下去,每次判断只要```O(1)```。 + +对于每个数,如果他的前续已经判断过了,他就没有必要判断了,继续判断下一个数,即: +``` +if num - 1 in nums: + continue +``` + + +AC代码: + +```python +class Solution(object): + def longestConsecutive(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + nums = set(nums) + tmp = {} + for num in nums: + tmp[num] = 1 + res = 0 + for num in nums: + if num - 1 not in nums: + y = num + 1 + while y in nums: + y += 1 + res = max(res, y - num) + return res +``` + +但其实```set```和字典的```in```判断都是```O(1)``` + +```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) + +  其中,我们把实现set的方式叫做Hash Set,实现dict的方式叫做Hash Map/Table(注:map指的就是通过key来寻找value的过程) + +```set```和```dict```的唯一区别仅在于没有存储对应的```value```,但是,```set```的原理和```dict```一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证```set```内部“不会有重复元素”。 + +因此,代码也可以写成这样 +```python +class Solution(object): + def longestConsecutive(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + nums = set(nums) + res = 0 + for num in nums: + if num - 1 not in nums: + y = num + 1 + while y in nums: + y += 1 + res = max(res, y - num) + return res +``` diff --git a/docs/Algorithm/Leetcode/Python/129._sum_root_to_leaf_numbers.md b/docs/Algorithm/Leetcode/Python/129._sum_root_to_leaf_numbers.md new file mode 100644 index 00000000..cedbdcd7 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/129._sum_root_to_leaf_numbers.md @@ -0,0 +1,37 @@ +###129. Sum Root to Leaf Numbers + +题目: + + + +难度: + +Medium + +其实递归不难想到,不过我自己做错在细节方面 + +如果只有单支,每朝下走一层,代表的数字都增加10, 10* 原本的 + 新节点的数字,最终也是用这个来解 + +``` +class Solution(object): + def sumNumbers(self, root): + """ + :type root: TreeNode + :rtype: int + """ + return self.calSum(root,0) + + + def calSum(self,root,curSum): + if root == None: + return 0 + else: + curSum = curSum * 10 + root.val + if root.left == None and root.right == None: + return curSum + else: + return self.calSum(root.left, curSum) + self.calSum(root.right, curSum) + + + +``` diff --git a/docs/Algorithm/Leetcode/Python/130._surrounded_regions.md b/docs/Algorithm/Leetcode/Python/130._surrounded_regions.md new file mode 100644 index 00000000..a0f76e26 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/130._surrounded_regions.md @@ -0,0 +1,147 @@ +###130. Surrounded Regions + + +题目: + + + + +难度: + +Medium + + +思路: + +loop,然后碰到O做DFS/BFS找出O所在区域: + +- 貌似只要O没有碰壁,O就总是被X包围着? +- 所以找出O的范围,然后看它是否碰壁,没有碰壁则mark不需要修改 + +但是这道题折磨我了很久,因为它有毛病。。。。 +它给的input例子是 +["XXX","XOX","XXX"] +也怪我 input写着List[List[str]] + +但实际上的输入是: +[[u'X', u'X', u'X'], [u'X', u'X', u'X'], [u'X', u'X', u'X']] + + +还要mark unicode + +还有就是学会了新的可以函数之下定义函数,这样就不用什么self了,用起来真方便,但是这样的思路做起来会超时。 + + + +``` +class Solution(object): + def solve(self, board): + """ + :type board: List[List[str]] + :rtype: void Do not return anything, modify board in-place instead. + """ + + + def shouldOChange(i, j): + """ + return x,y area and whether they shouldChange + """ + shouldChange = True + Oarea = [] + s = [] + s.append((i,j)) + while s: + (x,y) = s.pop() + if x == 0 or x == row - 1 or y == 0 or y == col -1 : + shouldChange = False + visited[x][y] = 1 + Oarea.append((x,y)) + if legal(x-1,y): + s.append((x-1,y)) + if legal(x+1,y): + s.append((x+1,y)) + if legal(x,y-1): + s.append((x,y-1)) + if legal(x,y-1): + s.append((x,y+1)) + return Oarea,shouldChange + + def legal(x,y): + return x>=0 and x < row and y>=0 and y < col and board[x][y] == 'O' and visited[x][y] == 0 + + + row = len(board) + col = len(board[0]) if row else 0 + + visited = [[0 for i in range(col)] for j in range(row)] + + for i in range(row): + for j in range(col): + if board[i][j] == 'O' and visited[i][j] == 0: + Oarea, shouldChange = shouldOChange(i,j) + print Oarea,shouldChange + if shouldChange: + for (x,y) in Oarea: + board[x][y] = u'X' + + print board +``` + + +另一个思路就是对周围碰壁的O做BFS/DFS,碰壁的和碰壁相连的是不需要修改的。这样就时间复杂度降低很多了。 + +原本是O(n^2)可能做DFS/BFS。现在是O(4n)做DFS/BFS,但是发现依旧超时,最后查看了别人的解法,因为我的解法里面多了一个存储工具,相当于,把需要更换location的位置存储起来,最后做loop的时候去查,然后这样还是很耗时。 + +而一个简便的变法是把这些特别的碰壁的'O' mark出来,这样最后loop的时候不改变这些'O',只改变不碰壁的'O',又可以减少工作量。同时依旧可以使用collection里面的queue + + + +AC代码 + +``` +class Solution(object): + def solve(self, board): + """ + :type board: List[List[str]] + :rtype: void Do not return anything, modify board in-place instead. + """ + def legal(x,y): + return x>=0 and x < row and y>=0 and y < col and board[x][y] == 'O' and visited[x][y] == 0 + + + row = len(board) + col = len(board[0]) if row else 0 + + visited = [[0 for i in range(col)] for j in range(row)] + + notChangeOArea = [] + queue = collections.deque() + + for j in range(col): + if board[0][j] == 'O': queue.append((0,j)) + if board[row-1][j] == 'O': queue.append((row-1,j)) + for i in range(row): + if board[i][0] == 'O': queue.append((i,0)) + if board[i][col-1] == 'O': queue.append((i,col-1)) + + while queue: + (x,y) = queue.popleft() + board[x][y] = '$' + visited[x][y] = 1 + if legal(x-1,y): + queue.append((x-1,y)) + if legal(x+1,y): + queue.append((x+1,y)) + if legal(x,y-1): + queue.append((x,y-1)) + if legal(x,y+1): + queue.append((x,y+1)) + + for i in range(row): + for j in range(col): + if board[i][j] == '$' : board[i][j] = 'O' + elif board[i][j] == 'O' : board[i][j] = 'X' +``` + + +同时发现,用这种方式,无论是否使用collection里面的queue,都能AC \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/131._palindrome_partitioning.md b/docs/Algorithm/Leetcode/Python/131._palindrome_partitioning.md new file mode 100644 index 00000000..45d404c8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/131._palindrome_partitioning.md @@ -0,0 +1,48 @@ +###131. Palindrome Partitioning + +题目: + + + +难度: +Medium + +知道一定是用递归做,但是在怎么拆的部分疑惑了,然后看了hint + +key部分长这样,拆法是类似于combination,然后这个len(s) == 0是确保能被拆为palindrome,因为这样剩下的string才是空的 + + +这个recursion tree是这样的,感觉时间复杂度是O(n!),因为每次树都branch n个分支 + +``` + +class Solution(object): + def partition(self, s): + """ + :type s: str + :rtype: List[List[str]] + """ + self.res = [] + self.dfs(s,[]) + return self.res + + + def dfs(self, s, stringList): + if len(s) == 0: + self.res.append(stringList) + for i in range(1,len(s)+1): + if self.isPalindrome(s[:i]): + self.dfs(s[i:],stringList + [s[:i]]) + + def isPalindrome(self, s): + if len(s) <= 1: + return True + return s[0] == s[-1] and self.isPalindrome(s[1:-1]) + +a = Solution() +print a.partition("aab") + +# [['a', 'a', 'b'], ['aa', 'b']] +``` + +输出是每次必定从单个char的list开始,然后单个char 配 palindrome word,然后palindrome word再来配char... \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/133._clone_graph.md b/docs/Algorithm/Leetcode/Python/133._clone_graph.md new file mode 100644 index 00000000..39921e28 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/133._clone_graph.md @@ -0,0 +1,66 @@ +###133. Clone Graph + + +题目: + + + +难度: +Medium + + + +思路: + +DFS或者BFS把graph traverse一遍,边traverse边复制。因为nodes are labeled uniquely,这就是方便的地方,但是注意node可能重复和有self-loop. + +所以先建立新的root node,然后有一个dict把node label和node一一对应。 + +用stack来存储原本的graph root node,对原本的graph做DFS,这个时候,如果这个node的neighbor是已经出现过,那么我们就是去修改原本的existNode,让它指向存在的neighbor,否则创建新的,再把它们联系起来,谷歌了一下,别人写的比我更简单。anyway,先AC。 + + + +`if cur.label in createdNodes:`多余。 + + + + +``` +class Solution(object): + def cloneGraph(self, node): + """ + :type node: UndirectedGraphNode + :rtype: UndirectedGraphNode + """ + if node == None: return None + + root = UndirectedGraphNode(node.label) + # must 1 to 1 + createdNodes = {} + createdNodes[root.label] = root + + stack = [] + stack.append(node) + + while stack: + cur = stack.pop() + if cur.label in createdNodes: + existNode = createdNodes[cur.label] + for neighbor in cur.neighbors: + if neighbor.label in createdNodes: + existNeighbor = createdNodes[neighbor.label] + existNode.neighbors.append(existNeighbor) + else: + newNode = UndirectedGraphNode(neighbor.label) + existNode.neighbors.append(newNode) + createdNodes[neighbor.label] = newNode + stack.append(neighbor) + return root +``` + + + +看了别人的代码,貌似比我又写的简洁。 + + + diff --git a/docs/Algorithm/Leetcode/Python/136._single_number.md b/docs/Algorithm/Leetcode/Python/136._single_number.md new file mode 100644 index 00000000..18540da0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/136._single_number.md @@ -0,0 +1,42 @@ +### 136. Single Number + + + +题目: + + + +难度: + +Easy + + +思路: + +位运算,终于要take it了 + +非常常见的一道算法题,将所有数字进行异或操作即可。对于异或操作明确以下三点: + +- 一个整数与自己异或的结果是0 +- 一个整数与0异或的结果是自己 +- 异或操作满足交换律,即a^b=b^a + +Python的位操作: + + +神奇的解法: + + +```python +class Solution(object): + def singleNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + res = nums[0] + for i in nums[1:]: + res ^= i + return res +``` + diff --git a/docs/Algorithm/Leetcode/Python/139._word_break.ipynb b/docs/Algorithm/Leetcode/Python/139._word_break.ipynb new file mode 100644 index 00000000..ffbac6d1 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/139._word_break.ipynb @@ -0,0 +1,222 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Word Break 单词拆分\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/word-break/description/\n", + " - 英文:https://leetcode.com/problems/word-break/\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。\n", + "\n", + "说明:\n", + "\n", + "1、拆分时可以重复使用字典中的单词。\n", + "2、你可以假设字典中没有重复的单词。\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", + "> 思路 1\n", + "\n", + " - 字符串 S ,它的长度为 N ,如果 S 能够被 字典集合(dict)中的单词拼接而成,那么所要满足的条件为:\n", + " - F(0, N) = F(0, i) && F(i, j) && F(j, N)\n", + " - 这样,如果我们想知道某个子串是否可由 Dict 中的几个单词拼接而成就可以用这样的方式得到结果(满足条件为True,不满足条件为 False)存入到一个 boolean 数组的对应位置上,这样,最后 boolean 数组的最后一位就是 F(0, N) 的值,为 True 表示这个字符串 S 可以由 Dict 中的单词拼接,否则是不行的。\n", + " - AC 代码如下" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def wordBreak(self, s, wordDict):\n", + " \"\"\"\n", + " :type s: str\n", + " :type wordDict: List[str]\n", + " :rtype: bool\n", + " \"\"\"\n", + " # 参数校验\n", + " if s is None or len(s) < 1 or wordDict is None or len(wordDict) < 1:\n", + " return False\n", + " # 标记是否匹配,match[i] 表示 [0, i-1] 都匹配\n", + " length = len(s)\n", + " match = [False for i in range(length + 1)]\n", + " match[0] = True\n", + " \n", + " for i in range(1, length +1):\n", + " for j in range(i):\n", + " if match[j] and s[j:i] in wordDict:\n", + " match[i] = True\n", + " break\n", + " return match[length]\n", + "\n", + "\n", + "sss = Solution()\n", + "s = \"leetcode\"\n", + "wordDict = [\"leet\", \"code\"]\n", + "print(sss.wordBreak(s, wordDict))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "> 思路 2\n", + "\n", + " - **ok[i] 表示 s[:i] 是不是存在于我们的字典中。**\n", + " - 原理类似于我们上面的 思路 1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "sss = Solution()\n", + "s = \"leetcode\"\n", + "wordDict = [\"leet\", \"code\"]\n", + "print(sss.wordBreak(s, wordDict))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "但是往list里面加数据的方法有快有慢,下面是对比:\n", + "\n", + "```python\n", + ">>> from timeit import timeit\n", + ">>> timeit('x.append(1)', 'x = []', number=10000000)\n", + "1.9880003412529277\n", + ">>> timeit('x += 1,', 'x = []', number=10000000)\n", + "1.2676891852971721\n", + ">>> timeit('x += [1]', 'x = []', number=10000000)\n", + "3.361207239950204\n", + "```\n", + "\n", + "因此我们可以将代码直接换成下面的格式:\n", + "\n", + "```python\n", + "ok += any(ok[j] and s[j:i] in wordDict for j in range(i)) # 会报错\n", + "```\n", + "\n", + "但是这样会报错,TypeError: 'bool' object is not iterable,因此bool类型数据不能这样加,别的可以(list类型本身当然要注意哈)\n", + "\n", + "因此在这个例子中我们这样:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "sss = Solution()\n", + "s = \"leetcode\"\n", + "wordDict = [\"leet\", \"code\"]\n", + "print(sss.wordBreak(s, wordDict))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/139._word_break.md b/docs/Algorithm/Leetcode/Python/139._word_break.md new file mode 100644 index 00000000..815737de --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/139._word_break.md @@ -0,0 +1,59 @@ +### 139. Word Break + +题目: + + + +难度: + +Medium + + + +```ok[i]``` tells whether ```s[:i]``` can be built. + +```python +class Solution(object): + def wordBreak(self, s, wordDict): + """ + :type s: str + :type wordDict: List[str] + :rtype: bool + """ + ok = [True] + for i in range(1, len(s)+1): + ok += [any(ok[j] and s[j:i] in wordDict for j in range(i))] + return ok[-1] +``` + +但是往list里面加数据的方法有快有慢,下面是对比: +``` +>>> from timeit import timeit +>>> timeit('x.append(1)', 'x = []', number=10000000) +1.9880003412529277 +>>> timeit('x += 1,', 'x = []', number=10000000) +1.2676891852971721 +>>> timeit('x += [1]', 'x = []', number=10000000) +3.361207239950204 +``` +因此我们可以将代码直接换成下面的格式 +```python +ok += any(ok[j] and s[j:i] in wordDict for j in range(i)) # 会报错 +``` +但是这样会报错,TypeError: 'bool' object is not iterable,因此bool类型数据不能这样加,别的可以(list类型本身当然要注意哈) + +因此在这个例子中我们这样: +```python +class Solution(object): + def wordBreak(self, s, wordDict): + """ + :type s: str + :type wordDict: List[str] + :rtype: bool + """ + ok = [True] + for i in range(1, len(s)+1): + ok += any(ok[j] and s[j:i] in wordDict for j in range(i)), + return ok[-1] +``` +代码里面的那个逗号构建了一个tuple,也会快一点 diff --git a/docs/Algorithm/Leetcode/Python/140._word_break_ii.md b/docs/Algorithm/Leetcode/Python/140._word_break_ii.md new file mode 100644 index 00000000..6333bf8f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/140._word_break_ii.md @@ -0,0 +1,113 @@ + +### 140. Word Break II + +题目: + + + +难度: + +Medium + + + +还是backtracking,会超时 + +``` +class Solution(object): # 此法超时 +    def wordBreak(self, s, wordDict): + """ + :type s: str + :type wordDict: Set[str] + :rtype: bool + """ + self.res = [] + self.wordBreakLst("",s,wordDict) + return self.res + + + def wordBreakLst(self, lst, rest, wordDict): + if rest == '': + self.res.append(lst.rstrip()) + # print lst + for i in range(1+len(rest)): + if rest[:i] in wordDict: + self.wordBreakLst(lst + rest[:i] + " ",rest[i:],wordDict) + +``` + + + + +然后看到有把word break i 结合起来减少时间复杂度的作法。 + + +做法如下,聪明: + +就是对于每一个s,我们来check它是否可以break,如果不可以,就不用做相应的操作了 + + +```python +class Solution(object): + def wordBreak(self, s, wordDict): + """ + :type s: str + :type wordDict: List[str] + :rtype: List[str] + """ + self.res = [] + self.wordBreakLst(s, wordDict, '') + return self.res + + def check(self, s, wordDict): + ok = [True] + for i in range(1, len(s) + 1): + ok += any(ok[j] and s[j:i] in wordDict for j in range(i)), + return ok[-1] + + + def wordBreakLst(self, s, wordDict, stringLst): + if self.check(s, wordDict): + if len(s) == 0 : self.res.append(stringLst[1:]) # 因为最开始也加了一个空格 + for i in range(1,len(s)+1): + if s[:i] in wordDict: + self.wordBreakLst(s[i:], wordDict, stringLst + ' ' + s[:i]) +``` + + +但是其实 + +``` +s = "aaaaaa" +wordDict = ["a","aa","aaa"] +print a.wordBreak(s,wordDict)还是会loop很多次 + +不过像 +s = "aabbb" +wordDict = ["a","abbb"] +就会极其的减少loop次数 +``` + + +看看stefan大神的做法: + +```sentences(i)``` returns a list of all sentences that can be built from the suffix ```s[i:]```. + +```python +class Solution(object): + def wordBreak(self, s, wordDict): + """ + :type s: str + :type wordDict: List[str] + :rtype: List[str] + """ + memo = {len(s): ['']} + def sentences(i): + if i not in memo: + memo[i] = [s[i:j] + (tail and ' ' + tail) + for j in range(i+1, len(s)+1) + if s[i:j] in wordDict + for tail in sentences(j)] + return memo[i] + return sentences(0) +``` diff --git a/docs/Algorithm/Leetcode/Python/141._linked_list_cycle.md b/docs/Algorithm/Leetcode/Python/141._linked_list_cycle.md new file mode 100644 index 00000000..2d50901e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/141._linked_list_cycle.md @@ -0,0 +1,105 @@ +### 141. Linked List Cycle + +题目: + + + + +难度: + +Easy + + +想法一: + +直接超时 + +``` +class Solution(object): + def hasCycle(self, head): + """ + :type head: ListNode + :rtype: bool + """ + if head == None: return False + lst = [] + cur = head + while cur: + if cur in lst: + return True + lst.append(cur) + cur = cur.next + return False +``` + + + +想法二:相当用boolean array记录某个点是否被访问过,时间,空间复杂度都是O(n) + +``` +class Solution(object): + def hasCycle(self, head): + """ + :type head: ListNode + :rtype: bool + """ + if head == None: return False + dictx = {} + cur = head + while cur: + if cur in dictx: + return True + dictx[cur] = 1 + cur = cur.next + return False +``` + +结果这种方法的run time还比较快 + +查了一下,有解答说可以有空间复杂度O(1),时间复杂度O(n)。两个指针,一个快一个慢,快的每次走两步,慢的每次走一步,如果有环,最终会在某处相遇。这也是一个算法。这种快慢指针配合已经不是第一次遇到了,比如找linklist中间的node。 + + + +但是并没有觉得这样的算法是O(n), worst case time complexity is O(N+K), which is O(n). + + +```python +python +class Solution(object): + def hasCycle(self, head): + """ + :type head: ListNode + :rtype: bool + """ + slow = head + fast = head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + if slow == fast: + return True + return False +``` + + +```java +java +public class Solution { + public boolean hasCycle(ListNode head) { + if (head == null){ + return false; + } + ListNode fast = head; + ListNode slow = head; + while (fast != null && slow != null && fast.next != null){ + fast = fast.next.next; + slow = slow.next; + if (slow == fast){ + return true; + } + } + return false; + } +} +``` + diff --git a/docs/Algorithm/Leetcode/Python/142_Linked_List_Cycle_II.md b/docs/Algorithm/Leetcode/Python/142_Linked_List_Cycle_II.md new file mode 100644 index 00000000..cd887592 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/142_Linked_List_Cycle_II.md @@ -0,0 +1,56 @@ +### 142. Linked List Cycle II + +题目: + + + + +难度: + +Medium + +思路: +稍微改了一下[141](https://github.com/Lisanaaa/thinking_in_lc/blob/master/141._linked_list_cycle.md),这里稍微注意一下```while-else clause```就行 + +Let’s say, the first node is node ```0```, the cycle starts at node ```L```, and the length of the cycle is ```C```; +Moreover, after ```t``` steps, ```fast``` catches ```slow```. + +Now we know that fast totally traveled ```2t``` nodes, and slow traveled ```t``` nodes + +Then we have: +```2t - t = nC``` (where ```n``` is an positive integer.) +i.e. ```t=nC``` + +Now, think about that, at step ```t```, if we travels ```L``` more steps, where are we? +i.e. if we travel ```L+t = L + nC``` steps in total, where are we? + +Absolutely, at the start of the cycle, because we have covered the first ```L``` nodes once and the entire cycle ```n``` times. + +So, if we travel ```L``` more steps at time ```t```, then we get the start of the cycle. + +However, how can we travel exactly ```L``` step? +The 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. + +参考[LostSummer233的解答](https://leetcode.com/problems/linked-list-cycle-ii/discuss/44833) +```python +class Solution(object): + def detectCycle(self, head): + """ + :type head: ListNode + :rtype: bool + """ + slow = fast = head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + if slow == fast: + break + else: + return None + while head != slow: + slow = slow.next + head = head.next + return head +``` + + diff --git a/docs/Algorithm/Leetcode/Python/143._reorder_list.md b/docs/Algorithm/Leetcode/Python/143._reorder_list.md new file mode 100644 index 00000000..59c9fb9f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/143._reorder_list.md @@ -0,0 +1,112 @@ +###143. Reorder List + +题目: + + + + +难度: + +Medium + +超时 + + +``` + +class Solution(object): + def reorderList(self, head): + """ + :type head: ListNode + :rtype: void Do not return anything, modify head in-place instead. + """ + head = self.reorder(head) + + + def reorder(self, head): + if head == None or head.next == None or head.next.next == None: + return head + + l0 = head + l1 = head.next + ln_1 = self.oneNodeTail(head) + ln =ln_1.next + + l0.next = ln + ln_1.next = None + ln.next = self.reorder(l1) + return l0 + + + def oneNodeTail(self, head): + if head == None or head.next == None or head.next.next == None: + return head + cur = head + while cur.next: + if cur.next.next: + cur = cur.next + else: + break + return cur + +``` + + +取巧的办法是: + +找到中间节点,断开,把后半截linked list reverse,然后合并 √ + +看了AC指南 + +``` +class Solution(object): + def reorderList(self, head): + """ + :type head: ListNode + :rtype: void Do not return anything, modify head in-place instead. + """ + if head == None or head.next == None or head.next.next == None: + return + + slow = head + fast = head + prev = None + + while fast and fast.next: + prev = slow + slow = slow.next + fast = fast.next.next + + prev.next = None + + + slow = self.reverseList(slow) + + cur = head + while cur.next: + tmp = cur.next + cur.next = slow + slow = slow.next + cur.next.next = tmp + cur = tmp + cur.next = slow + + + + def reverseList(self,head): + """ + :type head: ListNode + :rtype: ListNode + """ + prev = None + cur = head + while(cur): + nxt = cur.next + cur.next = prev + prev = cur + cur = nxt + return prev + + +``` + diff --git a/docs/Algorithm/Leetcode/Python/144._binary_tree_preorder_traversal.md b/docs/Algorithm/Leetcode/Python/144._binary_tree_preorder_traversal.md new file mode 100644 index 00000000..b8189068 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/144._binary_tree_preorder_traversal.md @@ -0,0 +1,104 @@ +# 144. Binary Tree Preorder Traversal +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/binary-tree-preorder-traversal/description/ + +> 内容描述 + +``` +Given a binary tree, return the preorder traversal of its nodes' values. + +Example: + +Input: [1,null,2,3] + 1 + \ + 2 + / + 3 + +Output: [1,2,3] +Follow up: Recursive solution is trivial, could you do it iteratively? +``` + +## 解题方案 + +> 思路 1 + +Recursive递归,瞬秒 + + +```python +class Solution(object): + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if not root: + return res + res.append(root.val) + if root.left: + res.extend(self.preorderTraversal(root.left)) + if root.right: + res.extend(self.preorderTraversal(root.right)) + return res +``` + +> 思路 2 + +或者我们可以先写一下先序遍历的函数,然后一个一个贴上去 + +```python +class Solution(object): + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + if root == None: + return [] + res = [] + self.preorder(root,res) + return res + + + def preorder(self,root,res): + if root == None: + return + res.append(root.val) + self.preorder(root.left,res) + self.preorder(root.right,res) +``` + + +Iterative, 迭代 + + +```python +class Solution(object): + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if not root: + return res + stack = [] + stack.append(root) + + while(len(stack) > 0): + node = stack.pop() + res.append(node.val) + if node.right: + stack.append(node.right) + if node.left: + stack.append(node.left) + return res +``` diff --git a/docs/Algorithm/Leetcode/Python/145._binary_tree_postorder_traversal.md b/docs/Algorithm/Leetcode/Python/145._binary_tree_postorder_traversal.md new file mode 100644 index 00000000..2729d497 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/145._binary_tree_postorder_traversal.md @@ -0,0 +1,110 @@ +# 145. Binary Tree Postorder Traversal 二叉树的后序遍历 +**难度: 困难** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/binary-tree-postorder-traversal/description/ + +> 内容描述 + +``` +给定一个二叉树,返回它的 后序 遍历。 + +示例: + +输入: [1,null,2,3] + 1 + \ + 2 + / + 3 + +输出: [3,2,1] +进阶: 递归算法很简单,你可以通过迭代算法完成吗? +``` + +## 解题方案 + +> 思路 1 + +递归,so easy + +```python +class Solution(object): + def postorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if not root: + return res + + left = self.postorderTraversal(root.left) + right = self.postorderTraversal(root.right) + + if left: + res.extend(left) + if right: + res.extend(right) + + res.append(root.val) + return res +``` + +> 思路 2 + +也可以先写一下后序遍历的函数,然后一个一个贴上去 + + +```python +class Solution(object): + def postorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + def postOrder(root): + if not root : return + postOrder(root.left) + postOrder(root.right) + res.append(root.val) + + res = [] + postOrder(root) + return res +``` + +> 思路 3 + +迭代, 其实思路就一句话,后序遍历是左右中,因为我们第一个放进去的肯定是中(即root),所以我们逆向思维考虑一下,我们按照中右左的顺序放进去,然后返回res[::-1]就行了。这其实跟[leetcode第144题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/144._binary_tree_preorder_traversal.md)是一样的思路 + + +```python +class Solution(object): + def postorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if not root: + return res + + stack1 = [] + stack1.append(root) + + while len(stack1) > 0: + node = stack1.pop() + res.append(node.val) + if node.left: + stack1.append(node.left) + if node.right: + stack1.append(node.right) + + return res[::-1] +``` + + diff --git a/docs/Algorithm/Leetcode/Python/147._insertion_sort_list.md b/docs/Algorithm/Leetcode/Python/147._insertion_sort_list.md new file mode 100644 index 00000000..b385d14f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/147._insertion_sort_list.md @@ -0,0 +1,59 @@ +###147. Insertion Sort List + +题目: + + + +难度: +Medium + +insertion sort 也是入门必备,一个元素本身被认为是sort的,一个简单的理解是打牌,然后进入第二个元素的时候,看它是比第一个元素大还是小,做排序,进入下一个元素的时候再看再移。 + +伪码 + +``` +for i ← 1 to length(A)-1 + j ← i + while j > 0 and A[j-1] > A[j] + swap A[j] and A[j-1] + j ← j - 1 + end while +end for +``` + +这个伪码对于list可能适用性没有那么强,则考虑,从第二个node开始,那么从开始开始看,找到这个node应该插入的位置,插入。 + + + +就是这样,就是会超时|||| + +``` +class Solution(object): + def insertionSortList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if head == None or head.next == None: + return head + + dummy = ListNode(-1) + dummy.next = head + + prev = head + cur = head.next + + while cur: + p = dummy + while p.next.val <= cur.val and p != prev: + p = p.next + if p != prev: + prev.next = cur.next + cur.next = p.next + p.next = cur + prev = cur + cur = cur.next + + return dummy.next +``` + diff --git a/docs/Algorithm/Leetcode/Python/148._sort_list.md b/docs/Algorithm/Leetcode/Python/148._sort_list.md new file mode 100644 index 00000000..7bb4e80b --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/148._sort_list.md @@ -0,0 +1,138 @@ +###148. Sort List + +题目: + + + +难度: +Medium + +MergeSort + +merge sort是必备,divide & conquer的入门之物。 + +merge sort做两件事, sort 和 merge。 + +看一看标准伪码: + +``` +function mergesort(m) + var list left, right, result + if length(m) ≤ 1 + return m + else + var middle = length(m) / 2 + for each x in m up to middle - 1 + add x to left + for each x in m at and after middle + add x to right + left = mergesort(left) + right = mergesort(right) + if last(left) ≤ first(right) + append right to left + return left + result = merge(left, right) + return result + +function merge(left,right) + var list result + while length(left) > 0 and length(right) > 0 + if first(left) ≤ first(right) + append first(left) to result + left = rest(left) + else + append first(right) to result + right = rest(right) + if length(left) > 0 + append rest(left) to result + if length(right) > 0 + append rest(right) to result + return result +``` + +另一处获得伪码 + +``` +MergeSort(arr[], l, r) +If r > l + 1. Find the middle point to divide the array into two halves: + middle m = (l+r)/2 + 2. Call mergeSort for first half: + Call mergeSort(arr, l, m) + 3. Call mergeSort for second half: + Call mergeSort(arr, m+1, r) + 4. Merge the two halves sorted in step 2 and 3: + Call merge(arr, l, m, r) +``` + + +merge sort用在linked list上的好处是不用开辟空间,然后就处理node + +用旧的代码拼装出来的结果 + +然后需要注意的一点是拆分链表,所以有设置left node 的tail为None的操作. + +``` +class Solution(object): + def sortList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if head == None or head.next == None: + return head + + mid = self.findMid(head) + # split the + l1 = head + l2 = mid.next + mid.next = None + + l1 = self.sortList(l1) + l2 = self.sortList(l2) + + return self.mergeTwoLists(l1, l2) + + def mergeTwoLists(self, l1, l2): + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ + if l1 == None: + return l2 + if l2 == None: + return l1 + + dummy = ListNode(-1) + cur = dummy + + while l1 and l2: + if l1.val < l2.val: + cur.next = l1 + l1 = l1.next + else: + cur.next = l2 + l2 = l2.next + cur = cur.next + + if l1: + cur.next = l1 + else: + cur.next = l2 + return dummy.next + + def findMid(self,head): + if head == None or head.next == None: + return head + + slow = head + fast = head + + while fast.next and fast.next.next: + slow = slow.next + fast = fast.next.next + + return slow + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/150._evaluate_reverse_polish_notation.md b/docs/Algorithm/Leetcode/Python/150._evaluate_reverse_polish_notation.md new file mode 100644 index 00000000..4e2b48aa --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/150._evaluate_reverse_polish_notation.md @@ -0,0 +1,83 @@ +###150. Evaluate Reverse Polish Notation + + + +题目: + + + +难度: +Medium + + + +AC代码 + +``` +class Solution(object): + def evalRPN(self, tokens): + """ + :type tokens: List[str] + :rtype: int + """ + def cal(op, op1, op2): + if op == '*': + return op1 * op2 + elif op == '/': + return op1 / float(op2) + elif op == '+': + return op1 + op2 + else: + return op1 - op2 + + operandStack = [] + + for token in tokens: + if token in '+-*/': + op2 = operandStack.pop() + op1 = operandStack.pop() + res = cal(token, op1, op2) + operandStack.append(int(res)) + else: + operandStack.append(int(token)) + + return operandStack.pop() +``` + + +实际上这里有一个很奇(sha)怪(bi)的地方,看到了么,除法➗处,如果我不这么做,就是错的,这是python 2 和 python 3 的除法不一致导致的,所以最终我这样做了才能得到正确答案。 + +思路: + +已经给了我们wikipedia的链接了 + +- While there are input tokens left + - Read the next token from input. + - If the token is a value + - Push it onto the stack. + -Otherwise, the token is an operator (operator here includes both operators and functions). + - It is already known that the operator takes n arguments. + - If there are fewer than n values on the stack + - (Error) The user has not input sufficient values in the expression. + - Else, Pop the top n values from the stack. + - Evaluate the operator, with the values as arguments. + - Push the returned results, if any, back onto the stack. +- If there is only one value in the stack + - That value is the result of the calculation. +- Otherwise, there are more values in the stack + - (Error) The user input has too many values. + + + +再参考这里 + + + + +1. Create an empty stack called operandStack. +2. Convert the string to a list by using the string method split. +3. Scan the token list from left to right. + - If the token is an operand, convert it from a string to an integer and push the value onto the operandStack. + - 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. +4. When the input expression has been completely processed, the result is on the stack. Pop the operandStack and return the value. + diff --git a/docs/Algorithm/Leetcode/Python/151._reverse_words_in_a_string.md b/docs/Algorithm/Leetcode/Python/151._reverse_words_in_a_string.md new file mode 100644 index 00000000..10414801 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/151._reverse_words_in_a_string.md @@ -0,0 +1,37 @@ +### 151. Reverse Words in a String + +题目: + + + +难度: +Medium + +太简单了 + +```python +class Solution(object): + def reverseWords(self, s): + """ + :type s: str + :rtype: str + """ + tmp = s.split() + res = " ".join(tmp[::-1]) + return res + +``` + +```python +class Solution(object): + def reverseWords(self, s): + """ + :type s: str + :rtype: str + """ + tmp = s.split() + tmp.reverse() + res = " ".join(tmp) + return res + +``` diff --git a/docs/Algorithm/Leetcode/Python/152._maximum_product_subarray.md b/docs/Algorithm/Leetcode/Python/152._maximum_product_subarray.md new file mode 100644 index 00000000..7570876f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/152._maximum_product_subarray.md @@ -0,0 +1,44 @@ +###152. Maximum Product Subarray + + + +题目: + + + +难度: +Medium + +思路: + +粗一看, 一股浓烈的DP气息飘来,想要套用53题的思路和方程。但是这个跟sum是不一样的,因为乘积可以正负正负的跳,这样的动归方程肯定是不对的 + +dp[i] = max(dp[i-1] * a[i],a[i]) + +举个例子 : [-2,3,-4] + + +用O(N^2)超时,厉害啊! + +想,可不可以记录+的和-的,记录两个dp数组,我哭了,真的是这样做的 + +最大值可能来源于最小值 -> 哲学般的句子 + +``` +class Solution(object): + def maxProduct(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = len(nums) + maxdp = [ nums[0] for i in range(n)] + mindp = [ nums[0] for i in range(n)] + + + for i in range(1,n): + maxdp[i] = max(mindp[i-1]*nums[i], maxdp[i-1]*nums[i],nums[i]) + mindp[i] = min(maxdp[i-1]*nums[i], mindp[i-1]*nums[i],nums[i]) + + return max(maxdp) +``` diff --git a/docs/Algorithm/Leetcode/Python/153._find_minimum_in_rotated_sorted_array.md b/docs/Algorithm/Leetcode/Python/153._find_minimum_in_rotated_sorted_array.md new file mode 100644 index 00000000..b46e1950 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/153._find_minimum_in_rotated_sorted_array.md @@ -0,0 +1,85 @@ +###153. Find Minimum in Rotated Sorted Array + + +题目: + + + +难度: + +Medium + + + +思路一: + +O(N) 就不说了 + +思路二: + +想的是分治,两段分别找出最小值,然后取最小值,但是依旧没有利用题目特性,并且也是O(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. + + +上面提到了一个特性,就是minimum element唯一一个它之前的element比它大的,如果不存在这个element,那么就没有rotation. + + + +思路其实是判断前半部分或者后半部分是否有序,然后来剔除,这里需要注意有比较多的边界case,因为如果就两个,那么会有特殊case 0 ,1 mid = 0,所以可以看一下,它这个处理,最后一个elif 是来比较mid 和 end + + + + + +``` +class Solution(object): + def findMin(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + def findRotatedMin(nums, start, end): + if end < start: + return nums[0] + if start == end: + return nums[start] + mid = (start + end) / 2 + if mid > start and nums[mid] < nums[mid-1]: + return nums[mid] + elif mid < end and nums[mid+1] < nums[mid]: + return nums[mid+1] + elif nums[mid] < nums[end]: + return findRotatedMin(nums,start, mid -1) + return findRotatedMin(nums, mid+1, end) + + + return findRotatedMin(nums,0,len(nums)-1) + +``` + +非递归 + +``` +class Solution(object): + def findMin(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + l,r = 0, len(nums) - 1 + while l < r: + mid = (l+r) / 2 + if mid > l and nums[mid] < nums[mid-1]: + return nums[mid] + elif mid < r and nums[mid] > nums[mid+1]: + return nums[mid+1] + elif nums[mid] < nums[r]: + r = mid -1 + else: + l = mid +1 + return nums[0] + +``` + + diff --git a/docs/Algorithm/Leetcode/Python/155._min_stack.md b/docs/Algorithm/Leetcode/Python/155._min_stack.md new file mode 100644 index 00000000..fac02c17 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/155._min_stack.md @@ -0,0 +1,169 @@ +### 155. Min Stack + +题目: + + + +难度: + +Easy + +思路一: + +懒,直接用系统的数据结构 +用lst和系统的heapq,提升一下,用deque和heapq,这样也没太大提升 + + +```python +from heapq import * + +class MinStack(object): + + def __init__(self): + """ + initialize your data structure here. + """ + self.lst = [] + self.h = [] + + + def push(self, x): + """ + :type x: int + :rtype: void + """ + self.lst.append(x) + heappush(self.h,x) + + + def pop(self): + """ + :rtype: void + """ + val = self.lst.pop() + self.h.remove(val) + heapify(self.h) + + def top(self): + """ + :rtype: int + """ + return self.lst[-1] + + + def getMin(self): + """ + :rtype: int + """ + return self.h[0] + +``` + +思路二: + + +参考 + +用两个stack,其中一个始终来记录到当前位置的最小值 + + +``` +When we insert 18, both stacks change to following. +Actual Stack +18 <--- top +Auxiliary Stack +18 <---- top + +When 19 is inserted, both stacks change to following. +Actual Stack +19 <--- top +18 +Auxiliary Stack +18 <---- top +18 + +When 29 is inserted, both stacks change to following. +Actual Stack +29 <--- top +19 +18 +Auxiliary Stack +18 <---- top +18 +18 + +When 15 is inserted, both stacks change to following. +Actual Stack +15 <--- top +29 +19 +18 +Auxiliary Stack +15 <---- top +18 +18 +18 + +When 16 is inserted, both stacks change to following. +Actual Stack +16 <--- top +15 +29 +19 +18 +Auxiliary Stack +15 <---- top +15 +18 +18 +18 +``` + +这样无论是用deque还是本身的lst都有一些提升 + + +```python +from collections import deque +class MinStack(object): + + def __init__(self): + """ + initialize your data structure here. + """ + self.lst = deque() + self.aux = deque() + + + def push(self, x): + """ + :type x: int + :rtype: void + """ + self.lst.append(x) + if not self.aux or self.aux[-1] > x: + self.aux.append(x) + else: + self.aux.append(self.aux[-1]) + + + + def pop(self): + """ + :rtype: void + """ + self.lst.pop() + self.aux.pop() + + def top(self): + """ + :rtype: int + """ + return self.lst[-1] + + + def getMin(self): + """ + :rtype: int + """ + return self.aux[-1] +``` diff --git a/docs/Algorithm/Leetcode/Python/157._Read_N_Characters_Given_Read4.md b/docs/Algorithm/Leetcode/Python/157._Read_N_Characters_Given_Read4.md new file mode 100644 index 00000000..447051ff --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/157._Read_N_Characters_Given_Read4.md @@ -0,0 +1,95 @@ +# 157. Read N Characters Given Read4 最长有效括号 + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/read-n-characters-given-read4/description/ + +> 内容描述 + +``` +The API: int read4(char *buf) reads 4 characters at a time from a file. + +The return value is the actual number of characters read. For example, it returns 3 if there is only 3 characters left in the file. + +By using the read4 API, implement the function int read(char *buf, int n) that reads n characters from the file. + +Example 1: + +Input: buf = "abc", n = 4 +Output: "abc" +Explanation: The actual number of characters read is 3, which is "abc". +Example 2: + +Input: buf = "abcde", n = 5 +Output: "abcde" +Note: +The read function will only be called once for each test case. +``` + +## 解题方案 + +> 思路 1 + +讨论区有很多人说这道题很sb,给的例子和代码里面的input数据类型不一样,其实我也很懵逼 +然后我看到了这个解释,顿悟 +``` +It took me several hours to understand what the problem is talking about. + +Let'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. + +Similarly, 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. + +Also the examples are very misleading. Let's say example 1, +Input: buf = "abc", n = 4 +Output: "abc" +Explanation: The actual number of characters read is 3, which is "abc". +The 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. + +Hope this clarification helps :) +``` + + +总结一下,就是```read4(*read4_buf)```这个函数的意思就是从文件当中读4个字符并将其写入到read4_buf中去,返回值是实际读取到的字符个数,即如果文件中只剩3个(不到4个字符了) +,那么就只写3个字符到read4_buf中去,返回值是3 + +所以我们要实现的read(*buf)函数也是这样,我们要读取n个字符并写入到buf中去并且返回实际读取到的字符个数,如果不够我们就有多少写多少,然后返回实际写入的个数 + + +那么现在我们有两种情况: + +- n大于文件中的字符数,我们检测文件结束并停止读取并返回文件中的字符数。 +- n小于或等于文件中的字符数,当读取足够的字符时返回(即n) + +代码中用eof代表'end of file' + + +```python +class Solution(object): + def read(self, buf, n): + """ + :type buf: Destination buffer (List[str]) + :type n: Maximum number of characters to read (int) + :rtype: The number of characters read (int) + """ + if n == 0 : + return 0 + total_read, eof = 0, False + while not eof: + read4_buf = [''] * 4 + cur_read = read4(read4_buf) + if (cur_read < 4): + eof = True + for i in range(cur_read): + buf[total_read] = read4_buf[i] + total_read += 1 + if total_read == n: + return total_read + return total_read +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md b/docs/Algorithm/Leetcode/Python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md new file mode 100644 index 00000000..ec2c8cce --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md @@ -0,0 +1,75 @@ +# 158. Read N Characters Given Read4 II - Call multiple times + +**难度: 困难** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times/description/ + +> 内容描述 + +``` +The API: int read4(char *buf) reads 4 characters at a time from a file. + +The return value is the actual number of characters read. For example, it returns 3 if there is only 3 characters left in the file. + +By using the read4 API, implement the function int read(char *buf, int n) that reads n characters from the file. + +Note: +The read function may be called multiple times. + +Example 1: + +Given buf = "abc" +read("abc", 1) // returns "a" +read("abc", 2); // returns "bc" +read("abc", 1); // returns "" +Example 2: + +Given buf = "abc" +read("abc", 4) // returns "abc" +read("abc", 1); // returns "" +``` + +## 解题方案 + +> 思路 1 + +这个题目的描述就是一坨屎💩,真的,sb。 + +我来总结一下,跟第157题不一样的地方就是,157是就读一次,158是可以读好几次 +例如: +文件是‘abcdefg’ +- 157题就读一次,给一个n就行了。n给1那buf就是‘a’, n给2那buf就是‘ab’ +- 但是158不一样,可以多次read,比如第一次n给1,那buf是‘a’,再read一次,n给2,那'a'已经读过了,所以现在buf是'bc'了, +如果再来个n=3的话,buf就是‘def’, + +总之就是一个test case 中read函数可以调用一次和调用多次的区别 + +```python +class Solution(object): + head, tail, buffer = 0, 0, [''] * 4 ## 定义全局变量 + + def read(self, buf, n): + """ + :type buf: Destination buffer (List[str]) + :type n: Maximum number of characters to read (int) + :rtype: The number of characters read (int) + """ + i = 0 + while i < n: + if self.head == self.tail: ## read4 的缓存区为空的时候 + self.head = 0 + self.tail = read4(self.buffer) ## 开始进缓存区 + if self.tail == 0: + break + while i < n and self.head < self.tail: + buf[i] = self.buffer[self.head] ## 读出缓存区的变量 + i += 1 + self.head += 1 + return i +``` + + diff --git a/docs/Algorithm/Leetcode/Python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md b/docs/Algorithm/Leetcode/Python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md new file mode 100644 index 00000000..7d65fb60 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md @@ -0,0 +1,32 @@ +### 159. Longest Substring with At Most Two Distinct Characters + +题目: + + + +难度 : Hard + + + +```python +class Solution(object): + def lengthOfLongestSubstringTwoDistinct(self, s): + """ + :type s: str + :rtype: int + """ + maps = {} + begin, end, counter, length = 0, 0, 0, 0 + while end < len(s): + maps[s[end]] = maps.get(s[end], 0) + 1 + if maps[s[end]] == 1: + counter += 1 +            end += 1   # end 永远指向下一个待处理的字符 +            while counter > 2: + maps[s[begin]] -= 1 + if maps[s[begin]] == 0: + counter -= 1 + begin += 1 +            length = max(length, end - begin) # 因此这里是```end - begin```而不是```end - begin + 1``` +        return length +``` diff --git a/docs/Algorithm/Leetcode/Python/160._intersection_of_two_linked_lists.md b/docs/Algorithm/Leetcode/Python/160._intersection_of_two_linked_lists.md new file mode 100644 index 00000000..b403f01f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/160._intersection_of_two_linked_lists.md @@ -0,0 +1,59 @@ +### 160. Intersection of Two Linked Lists + +题目: + + + +难度: + +Easy + + +如果两个linkedlist有intersection的话,可以看到,其实如果一开始我们就走到b2的话,那么我们就可以两个pointer一个一个的对比,到哪一个地址一样,接下来就是intersection部分。 + + + +``` +A: a1 → a2 + ↘ + c1 → c2 → c3 + ↗ +B: b1 → b2 → b3 +``` +比较巧妙的数学解法,看下面的解释和代码 + + + +AC代码如下: + +```python +class Solution(object): + def getIntersectionNode(self, headA, headB): + """ + :type head1, head1: ListNode + :rtype: ListNode + """ + pA, pB = headA, headB + while pA is not pB: + pA = pA.next if pA else headB + pB = pB.next if pB else headA + return pA +``` +Just 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. +详见[zzg_zzm的评论](https://leetcode.com/problems/intersection-of-two-linked-lists/discuss/49799) + +This algorithm is sooooo perfect! + +I was wonder if the running time is O(n+m), but later I figured out that the actually running time is just: + +- m+n for non-intersection case + +With intersection: + +- Suppose for LL-A, it’s a+b=n, a is the # of nodes before intersection + +- Suppose for LL-B, it’s c+b=m, c is the # of nodes before intersection + +Thus the actual running time is a+b+c = n+c = m+a. + +Actually, when b=0, this just stands for the case with no intersection with a+b+c=n+m diff --git a/docs/Algorithm/Leetcode/Python/162._find_peak_element.md b/docs/Algorithm/Leetcode/Python/162._find_peak_element.md new file mode 100644 index 00000000..2aad9b1c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/162._find_peak_element.md @@ -0,0 +1,61 @@ +### 162. Find Peak Element + +题目: + + + +难度: +Medium + + +思路: + + +最直观的是O(N)解法 + +```python +class Solution(object): + def findPeakElement(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + for i in range(1, len(nums)): + if nums[i] < nums[i-1]: + return i-1 + return len(nums) - 1 +``` + +O(lgN) 解法 + +这是一个经典题目 + +- a[mid] < a[mid] only look at the left side +- a[mid] < a[mid] only look at the right side +- else peak found + + +证明就是用反证法,或者看peak,因为这里已经限制了num[i] ≠ num[i+1],所以peak element 一定存在。然后a[mid] < a[mid-1],那么说明这里一定是下降的,说明之前一定有一个peak存在,否则我们可以用反证法证明. + +写到这里,我非常相信就是binary search能写对其实不容易。 + + +AC代码 + +```python +class Solution(object): + def findPeakElement(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + l, r = 0, len(nums) - 1 + while l <= r: + if l == r : return l + mid = l + ((r - l) >> 2) + if nums[mid] < nums[mid+1]: + l = mid + 1 + else: + r = mid +``` + diff --git a/docs/Algorithm/Leetcode/Python/165._compare_version_numbers.md b/docs/Algorithm/Leetcode/Python/165._compare_version_numbers.md new file mode 100644 index 00000000..ab976ce9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/165._compare_version_numbers.md @@ -0,0 +1,47 @@ +###165. Compare Version Numbers + +题目: + + + +难度: + +Easy + + +其实我并不觉得这个很简单 + +因为可能两个的位数不一样,首端或者尾端需要补0,同时我还考虑过可能有出现多个'.'的状况 + + + +``` +class Solution(object): + def compareVersion(self, version1, version2): + """ + :type version1: str + :type version2: str + :rtype: int + """ + v1 = version1.split('.') + v2 = version2.split('.') + v1 = [int(x) for x in v1] + v2 = [int(x) for x in v2] + + len1 = len(v1) + len2 = len(v2) + lenMax = max(len1, len2) + for x in range(lenMax): + v1Token = 0 + if x < len1: + v1Token = v1[x] + v2Token = 0 + if x < len2: + v2Token = v2[x] + if v1Token > v2Token: + return 1 + elif v1Token < v2Token: + return -1 + return 0 + +``` diff --git a/docs/Algorithm/Leetcode/Python/166._Fraction_to_Recurring_Decimal.md b/docs/Algorithm/Leetcode/Python/166._Fraction_to_Recurring_Decimal.md new file mode 100644 index 00000000..d4285fe4 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/166._Fraction_to_Recurring_Decimal.md @@ -0,0 +1,42 @@ +### 166. Fraction to Recurring Decimal + +题目: + + + +难度: + +Medium + + + + +```python +class Solution: + # @return a string + def fractionToDecimal(self, n, d): + res = '' + if n == 0: # zero numerator + return str(n) + if (n < 0) ^ (d < 0): # determine the sign + res += '-' + n = abs(n) # remove sign of operands + d = abs(d) + res += str(n / d) # append integral part + if (n % d == 0): # in case no fractional part + return res + res += '.' + r = n % d + m = {} + while r: # simulate the division process + if r in m: # meet a known remainder + res = res[:m[r]] + '(' + res[m[r]:] + ')' # so we reach the end of the repeating part + break + m[r] = len(res) # if the remainder is first seen, remember the current position for it + r *= 10 + res += str(r / d) # append the quotient digit + r %= d + return res +``` + + diff --git a/docs/Algorithm/Leetcode/Python/167._two_sum_ii_-_input_array_is_sorted.md b/docs/Algorithm/Leetcode/Python/167._two_sum_ii_-_input_array_is_sorted.md new file mode 100644 index 00000000..8fcd5170 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/167._two_sum_ii_-_input_array_is_sorted.md @@ -0,0 +1,35 @@ +### 167. Two Sum II - Input array is sorted + + + +题目: + + + +难度: +Medium + + +思路: + + +双指针 + +```python +class Solution(object): + def twoSum(self, numbers, target): + """ + :type numbers: List[int] + :type target: int + :rtype: List[int] + """ + l, r = 0, len(numbers) - 1 + while l < r: + if numbers[l] + numbers[r] == target: + return [l+1, r+1] + elif numbers[l] + numbers[r] > target: + r -= 1 + else: + l += 1 + +``` diff --git a/docs/Algorithm/Leetcode/Python/168._excel_sheet_column_title.md b/docs/Algorithm/Leetcode/Python/168._excel_sheet_column_title.md new file mode 100644 index 00000000..547f083e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/168._excel_sheet_column_title.md @@ -0,0 +1,28 @@ +###168. Excel Sheet Column Title + +题目: + + + + +难度: + +Easy + +依旧26进制的反击,不过这个反击我做的没之前那个好,看了hint + +``` +class Solution(object): + def convertToTitle(self, n): + """ + :type n: int + :rtype: str + """ + ans = '' + while n : + ans = chr(ord('A') + (n - 1) % 26) + ans + n = (n - 1) // 26 + return ans + +``` + diff --git a/docs/Algorithm/Leetcode/Python/169._majority_element.md b/docs/Algorithm/Leetcode/Python/169._majority_element.md new file mode 100644 index 00000000..6701ba75 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/169._majority_element.md @@ -0,0 +1,74 @@ +###169. Majority Element + + + +题目: + + + +难度: +Easy + +思路: + +其实这个我有点有想到过 + + +给定一个长度为 n的数组,其中有一个数,它出现的次数大于⎣n/2⎦,称为主要元素,找到它. + +这个很像之前做过的一道CLRS的题目,想法可以用divide & conquer. + + +- 如果数组长度 <= 2,那么return第一个即解决问题 +- 如果长度 > 2,那么可以两两配对,对于配对一样的结果,删去 + - 如果最后余一个,这一个留下 + - shuffle之后再尝试两两配对,直到最后结果不再改变 + + 这样肯定是能解决问题的,因为为了满足次数大于⎣n/2⎦这个条件。 + + + + + + +``` + + 1 2 1 2 1 2 1 2 + 2 3 2 3 2 3 2 3 + 2 4 2 2 2 2 3 + 2 4 2 3 3 + 3 2 + 2 2 + 2 2 +``` + +思路容易implement非常难啊. + + + +这个问题有一个很出名的算法 + + +Boyer-Moore众数(majority number) 问题 + +在数组中找到两个不相同的元素并删除它们,不断重复此过程,直到数组中元素都相同,那么剩下的元素就是主要元素。 + + +这个算法的妙处在于不直接删除数组中的元素,而是利用一个计数变量. + +伪码 + + def majorityElement(self, nums): + count,major=0,0 + for n in nums: + if count==0: + major=n + if major==n: + count+=1 + else: + count-=1 + return major + + + + \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/171._excel_sheet_column_number.md b/docs/Algorithm/Leetcode/Python/171._excel_sheet_column_number.md new file mode 100644 index 00000000..4521f737 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/171._excel_sheet_column_number.md @@ -0,0 +1,34 @@ +###171. Excel Sheet Column Number + +题目: + + + + +难度: + +Easy + + +26进制的反击 + +``` +class Solution(object): + def titleToNumber(self, s): + """ + :type s: str + :rtype: int + """ + maps = {} + for i in range(65,91): + maps[chr(i)] = i - 64 + + lst = list(s) + lst.reverse() + num = 0 + for idx,item in enumerate(lst): + num += maps[item] * (26 ** idx) + return num + +``` + diff --git a/docs/Algorithm/Leetcode/Python/173._binary_search_tree_iterator.md b/docs/Algorithm/Leetcode/Python/173._binary_search_tree_iterator.md new file mode 100644 index 00000000..a8b6fd9c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/173._binary_search_tree_iterator.md @@ -0,0 +1,95 @@ +### 173. Binary Search Tree Iterator + +题目: + + + +难度: +Medium + + +同样没有听题目要求,一开始就取巧,用InOrder,这样得到BSF有序排列,然后使用 + + +```python + +class BSTIterator(object): + def __init__(self, root): + """ + :type root: TreeNode + """ + self.root = root + self.lst = [] + self.inOrder(root) + self.lst.reverse() + + + + def hasNext(self): + """ + :rtype: bool + """ + return self.lst != [] + + + def next(self): + """ + :rtype: int + """ + return self.lst.pop() + + def inOrder(self, root): + if root == None: + return + self.inOrder(root.left) + self.lst.append(root.val) + self.inOrder(root.right) + +``` + +谷歌了一下,得到如何满足题目要求的hint,从root开始,往左走,把左孩子压入stack,直到左边为空。 + +然后开始取node,如果node有右孩子,则同样要把node的右孩子的所有左孩子全部append入stack,画了一个图,可行。 + + + + + +```python + +class BSTIterator(object): + def __init__(self, root): + """ + :type root: TreeNode + """ + self.root = root + self.stack = [] + self.pushAllLeft(root) + + + def hasNext(self): + """ + :rtype: bool + """ + return self.stack != [] + + + def next(self): + """ + :rtype: int + """ + if self.hasNext(): + cur = self.stack.pop() + if cur.right: + self.pushAllLeft(cur.right) + return cur.val + + def pushAllLeft(self, node): + """ + :type node: TreeNode + """ + cur = node + while cur: + self.stack.append(cur) + cur = cur.left +``` diff --git a/docs/Algorithm/Leetcode/Python/179._Largest_Number.ipynb b/docs/Algorithm/Leetcode/Python/179._Largest_Number.ipynb new file mode 100644 index 00000000..9ce76348 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/179._Largest_Number.ipynb @@ -0,0 +1,186 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 179.Largest Number 最大数\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/largest-number/description/\n", + " - 英文:https://leetcode.com/problems/largest-number/\n", + "\n", + "> 内容描述\n", + "\n", + "```\n", + "给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。\n", + "\n", + "示例 1:\n", + "输入: [10,2]\n", + "输出: 210\n", + "\n", + "示例 2:\n", + "输入: [3,30,34,5,9]\n", + "输出: 9534330\n", + "说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 先排序,后合并,若最后为空字符串,则返回 '0'\n", + "\n", + "其中的排序思想是字符串的经典比较:\n", + "\n", + "【注】:在 Python3 中没有了 cmp,只有 key,我们可以使用 functools.cmp_to_key 去修饰一下。\n", + "\n", + "cmp 函数比较两个对象,如 (x, y),若 x > y,则返回 1,if x == y,return 0,如果 x < y,则返回 -1 。\n", + "\n", + "下面这个是 python2 的解决方案,可以 AC ,但是在我们的 Python3 中就会报如下错误" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'cmp' is an invalid keyword argument for this function", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[0ms\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSolution\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[0mnums\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlargestNumber\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnums\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36mlargestNumber\u001b[1;34m(self, nums)\u001b[0m\n\u001b[0;32m 6\u001b[0m \"\"\"\n\u001b[0;32m 7\u001b[0m \u001b[0mnums\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mnum\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mnums\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m \u001b[0mnums\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msort\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcmp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mcmp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 9\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlstrip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'0'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlstrip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'0'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32melse\u001b[0m \u001b[1;34m'0'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mTypeError\u001b[0m: 'cmp' is an invalid keyword argument for this function" + ] + } + ], + "source": [ + "class 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(num).lstrip('0') if ''.join(num).lstrip('0') else '0'\n", + " \n", + "s = Solution()\n", + "nums = [10, 2]\n", + "print(s.largestNumber(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "或者更简单的写法,可以写成下面这样(Python2适用,python3 会报错):" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'cmp' is an invalid keyword argument for this function", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[0ms\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSolution\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[0mnums\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlargestNumber\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnums\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36mlargestNumber\u001b[1;34m(self, nums)\u001b[0m\n\u001b[0;32m 6\u001b[0m \"\"\"\n\u001b[0;32m 7\u001b[0m \u001b[0mnums\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mnum\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mnums\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m \u001b[0mnums\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msort\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcmp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mcmp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 9\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlstrip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'0'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mor\u001b[0m \u001b[1;34m'0'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mTypeError\u001b[0m: 'cmp' is an invalid keyword argument for this function" + ] + } + ], + "source": [ + "class 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(num).lstrip('0') or '0'\n", + " \n", + "s = Solution()\n", + "nums = [10, 2]\n", + "print(s.largestNumber(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "下面这个解法就是我们在 Python3 中的解法" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "210\n" + ] + } + ], + "source": [ + "from functools import cmp_to_key\n", + "\n", + "# 比较函数\n", + "def compare(a, b):\n", + " return int(b + a) - int(a + b)\n", + "\n", + "class Solution(object):\n", + " def largestNumber(self, nums):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :rtype: str\n", + " \"\"\"\n", + " nums = sorted([str(x) for x in nums], key=cmp_to_key(compare))\n", + " return str(int(''.join(nums)))\n", + " \n", + "s = Solution()\n", + "nums = [10, 2]\n", + "print(s.largestNumber(nums))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/179._Largest_Number.md b/docs/Algorithm/Leetcode/Python/179._Largest_Number.md new file mode 100644 index 00000000..b225dd83 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/179._Largest_Number.md @@ -0,0 +1,51 @@ +### 179. Largest Number + +题目: + + + +难度: + +Medium + + +思路 + +先排序,再合并,若最后为空字符串,则返回'0' + +其中排序思想为字符串的经典比较: +``` + """ + Replacement for built-in funciton cmp that was removed in Python 3 + + Compare the two objects x and y and return an integer according to + the outcome. The return value is negative if x < y, zero if x == y + and strictly positive if x > y. + """ +``` + +```python +class Solution(object): + def largestNumber(self, nums): + """ + :type nums: List[int] + :rtype: str + """ + nums = [str(num) for num in nums] + nums.sort(cmp=lambda x, y: cmp(y+x, x+y)) + return ''.join(nums).lstrip('0') if ''.join(num).lstrip('0') else '0' +``` +或者更简单一点 + +```python +class Solution(object): + def largestNumber(self, nums): + """ + :type nums: List[int] + :rtype: str + """ + nums = [str(num) for num in nums] + nums.sort(cmp=lambda x, y: cmp(y+x, x+y)) + return ''.join(nums).lstrip('0') or '0' +``` + diff --git a/docs/Algorithm/Leetcode/Python/182._duplicate_emails.md b/docs/Algorithm/Leetcode/Python/182._duplicate_emails.md new file mode 100644 index 00000000..f000e80c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/182._duplicate_emails.md @@ -0,0 +1,49 @@ +# 182. duplicate-emails 查找重复的电子邮箱 + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/duplicate-emails +* https://leetcode-cn.com/problems/duplicate-emails/description + +> 内容描述 + +``` +编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。 + +示例: ++----+---------+ +| Id | Email | ++----+---------+ +| 1 | a@b.com | +| 2 | c@d.com | +| 3 | a@b.com | ++----+---------+ + +根据以上输入,你的查询应返回以下结果: ++---------+ +| Email | ++---------+ +| a@b.com | ++---------+ + +说明:所有电子邮箱都是小写字母。 +``` + +## 解题方案 + +> 思路 1 + +```sql +select Email +from Person +group by Email +having count(1)>1 +``` +或者 +```sql +select Email from Person group by Email having count(Email) > 1 +``` diff --git a/docs/Algorithm/Leetcode/Python/189._rotate_array.md b/docs/Algorithm/Leetcode/Python/189._rotate_array.md new file mode 100644 index 00000000..b00de875 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/189._rotate_array.md @@ -0,0 +1,42 @@ +###189. Rotate Array + +题目: + + + +难度 : Easy + +首先,要知道一点,```k```如果大于```nums```的长度了,那么其实进行 ```k % len(nums)``` 次就行了 + +其次,要注意```k 为0```的情况 + +```python +class Solution(object): + def rotate(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: void Do not return anything, modify nums in-place instead. + """ + k = k % len(nums) + if k != 0: + tmp = nums[-k:] + for j in range(len(nums)-1, k-1, -1): + nums[j] = nums[j-k] + nums[:k] = tmp +``` + + +还有作弊大法,贼🐂批 + +```python +class Solution(object): + def rotate(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: void Do not return anything, modify nums in-place instead. + """ + k %= len(nums) + nums[:] = nums[-k:] + nums[:-k] +``` diff --git a/docs/Algorithm/Leetcode/Python/191._number_of_1_bits.md b/docs/Algorithm/Leetcode/Python/191._number_of_1_bits.md new file mode 100644 index 00000000..dcba66c7 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/191._number_of_1_bits.md @@ -0,0 +1,66 @@ +### 191. Number of 1 Bits + +题目: + + + + +难度: + +Easy + + +转成二进制,数1的个数 + +```python +class Solution(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + return bin(n).count('1') +``` + + + +有wikipedia的题目 [Hamming Weight]((https://zh.wikipedia.org/wiki/汉明重量)) + + + +用wikipedia的解法: + +原理是在于每次使用x & x-1 总会把低位的数字给置0 + +比如 3 = 011 2 = 010 3 & 2 = 010 cnt =1 + +​ 2 = 010 1 = 001 2 & 1 = 000 cnt = 2 + +比如 9 = 1001 8 = 1000 9&8 = 1000 cnt =1 + +​ 8 = 1000 7 = 0111 8&7 = 0000 cnt = 2 + +> 减1操作将最右边的符号从0变到1,从1变到0,与操作将会移除最右端的1。如果最初X有N个1,那么经过N次这样的迭代运算,X将减到0。下面的算法就是根据这个原理实现的。 + +所以关键点是每次都会把最右边的1变成0. + + + +AC代码 + + + +```python +class Solution(object): + def hammingWeight(self, n): + """ + :type n: int + :rtype: int + """ + cnt = 0 + while n != 0: + n &= n - 1 + cnt += 1 + return cnt +``` + diff --git a/docs/Algorithm/Leetcode/Python/198._house_robber.md b/docs/Algorithm/Leetcode/Python/198._house_robber.md new file mode 100644 index 00000000..2b2deedd --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/198._house_robber.md @@ -0,0 +1,53 @@ + +### 198. House Robber + + +题目: + + + +难度: + +Easy + + +状态转移方程: + +dp[i] = max(dp[i-1], dp[i-2] + nums[i]) + + +AC 代码 + +```python +class Solution(object): + def rob(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = len(nums) + if n == 0 : return 0 + elif n == 1 : return nums[0] + elif n == 2 : return max(nums[0], nums[1]) + else: + dp = [0 for i in range(n)] + dp[0] = nums[0] + dp[1] = max(nums[0],nums[1]) + for i in range(2,n): + dp[i] = max( dp[i-1], dp[i-2] + nums[i]) + return dp[n-1] +``` + +```python +class Solution(object): + def rob(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + last, now = 0, 0 + for i in nums: last, now = now, max(last + i, now) + return now +``` + + diff --git a/docs/Algorithm/Leetcode/Python/199._binary_tree_right_side_view.md b/docs/Algorithm/Leetcode/Python/199._binary_tree_right_side_view.md new file mode 100644 index 00000000..6f7b3b6d --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/199._binary_tree_right_side_view.md @@ -0,0 +1,37 @@ +###199. Binary Tree Right Side View + +题目: + + + + +难度: + +Medium + + +还是在玩第102题,level order traversal. + +``` +class Solution(object): + def rightSideView(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + if root == None: return [] + + res = [] + curLevel = [root] + while curLevel: + nextLevel = [] + tmpRes = [] + for node in curLevel: + tmpRes.append(node.val) + if node.left: nextLevel.append(node.left) + if node.right: nextLevel.append(node.right) + res.append(tmpRes[-1]) + curLevel = nextLevel + return res +``` + diff --git a/docs/Algorithm/Leetcode/Python/200._number_of_islands.md b/docs/Algorithm/Leetcode/Python/200._number_of_islands.md new file mode 100644 index 00000000..73c5aecf --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/200._number_of_islands.md @@ -0,0 +1,130 @@ +### 200. Number of Islands + + +题目: + + + +难度: +Medium + + +思路: + + +一开始: +numberOfIslands = 0 +islandArea = [] + + +然后遇到(x,y) = 1的状况,更新numberOfIslands,并且把(x,y)放入islandArea,然后用BFS或者DFS查找岛屿范围,全部更如islandArea,做loop + +以上就是基本思路 + + +然后超时|||, 小改之后AC + + +``` + +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + self.grid = grid[:] + + self.row = len(self.grid) + self.col = len(self.grid[0]) if self.row else 0 + self.visited = [[0 for i in range(self.col)]for j in range(self.row)] + + + self.numberOfIslands = 0 + + for i in range(self.row): + for j in range(self.col): + if self.grid[i][j] == '1' and self.visited[i][j] == 0: + self.findArea(i,j) + self.numberOfIslands += 1 + + return self.numberOfIslands + + def findArea(self, i, j): + s = [] + s.append((i,j)) + while s: + (x,y) = s.pop() + self.visited[x][y] = 1 + if self.legal(x-1,y): + s.append((x-1,y)) + if self.legal(x+1,y): + s.append((x+1,y)) + if self.legal(x,y-1): + s.append((x,y-1)) + if self.legal(x,y+1): + s.append((x,y+1)) + + def legal(self,x,y): + return 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 +a = Solution() +print a.numIslands(["11000","11000","00100","00011"]) + +``` + + +看了别人的代码,写的真美 ╮(╯_╰)╭ 啊 + +``` +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + def dfs(gird, used, row, col, x, y): + if gird[x][y] == '0' or used[x][y]: + return + used[x][y] = True + + if x!= 0: + dfs(grid, used, row,col, x-1,y) + if x!= row -1 : + dfs(grid, used, row,col, x+1, y) + if y!= 0: + dfs(grid, used, row,col, x, y-1) + if y!= col - 1: + dfs(grid, used, row,col, x, y+1) + + + row = len(grid) + col = len(grid[0]) if row else 0 + + used = [[0 for i in xrange(col)] for i in xrange(row)] + + count = 0 + for i in xrange(row): + for j in xrange(col): + if grid[i][j] == '1' and not used[i][j]: + dfs(grid,used,row,col,i,j) + count += 1 + return count +``` + +厉害的解法:Sink and count the islands. +```python +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + def sink(i, j): + if 0 <= i < len(grid) and 0 <= j < len(grid[0]) and grid[i][j] == '1': + grid[i][j] = '0' + map(sink, (i+1, i-1, i, i), (j, j, j+1, j-1)) + return 1 + return 0 + return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[0]))) +``` + diff --git a/docs/Algorithm/Leetcode/Python/203._remove_linked_list_elements.md b/docs/Algorithm/Leetcode/Python/203._remove_linked_list_elements.md new file mode 100644 index 00000000..15aa10ef --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/203._remove_linked_list_elements.md @@ -0,0 +1,38 @@ +###203. Remove Linked List Elements + +题目: + + + +难度: + +Easy + + +AC代码如下: + + + +``` +class Solution(object): + def removeElements(self, head, val): + """ + :type head: ListNode + :type val: int + :rtype: ListNode + """ + dummy = ListNode(-1) + dummy.next = head + + cur = dummy + + while cur.next: + if cur.next.val == val: + cur.next = cur.next.next + else: + cur = cur.next + + return dummy.next + + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/204._count_primes.md b/docs/Algorithm/Leetcode/Python/204._count_primes.md new file mode 100644 index 00000000..b69290b7 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/204._count_primes.md @@ -0,0 +1,57 @@ +###204. Count Primes + + +题目: + + + +难度: + +Easy + + + +这个题的hint是已经把算法喂到嘴边了 + + + + +``` +Input: an integer n > 1 + +Let A be an array of Boolean values, indexed by integers 2 to n, +initially all set to true. + +for i = 2, 3, 4, ..., not exceeding √n: + if A[i] is true: + for j = i^2, i^2+i, i^2+2*i, i^2+3i, ..., not exceeding n : + A[j] := false + +Output: all i such that A[i] is true. +``` + + + +python算法 + + +``` +class Solution(object): + def countPrimes(self, n): + """ + :type n: int + :rtype: int + """ + isPrime = [1 for i in range(n)] + + i = 2 + while i * i < n: + if isPrime[i]: + j = i * i + while j < n : + isPrime[j] = 0 + j += i + i += 1 + + return sum(isPrime[2:]) +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/205._isomorphic_strings.md b/docs/Algorithm/Leetcode/Python/205._isomorphic_strings.md new file mode 100644 index 00000000..47b0ab77 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/205._isomorphic_strings.md @@ -0,0 +1,39 @@ +###205. Isomorphic Strings + +题目: + + + +难度 : Easy + + +AC之法,用dictionary,因为限制,所以确保s 和 t 是isomorphic 同时 t 和 s 是 + + +``` +class Solution(object): + def isIsomorphic(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + return self.iso(s,t) and self.iso(t,s) + + def iso(self,s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + mapx = {} + for i in range(len(s)): + if s[i] not in mapx: + mapx[s[i]] = t[i] + elif s[i] in mapx: + if t[i] != mapx[s[i]]: + return False + return True + + +``` diff --git a/docs/Algorithm/Leetcode/Python/206._reverse_linked_list.md b/docs/Algorithm/Leetcode/Python/206._reverse_linked_list.md new file mode 100644 index 00000000..97c10db2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/206._reverse_linked_list.md @@ -0,0 +1,69 @@ +### 206. Reverse Linked List + +题目: + + + +难度: +Easy + +用三个指针,分别指向prev,cur 和 nxt,然后loop一圈还算比较简单. + + + + +```python +class Solution(object): + def reverseList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + prev = None + cur = head + while(cur): + nxt = cur.next + cur.next = prev + prev = cur + cur = nxt + return prev +``` +其实一个指针就够了 +```python +class Solution(object): + def reverseList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if not head: + return head + prev = None + while head.next: + tmp = head.next + head.next = prev + prev = head + head = tmp + head.next = prev + return head +``` + +递归版本,可以再消化一下. + + +```python +class Solution(object): + def reverseList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + return self.reverseHelper(head, None) + + def reverseHelper(self, head, new_head): + if not head: + return new_head + nxt = head.next + head.next = new_head + return self.reverseHelper(nxt, head) +``` diff --git a/docs/Algorithm/Leetcode/Python/207._course_schedule.md b/docs/Algorithm/Leetcode/Python/207._course_schedule.md new file mode 100644 index 00000000..6e990f09 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/207._course_schedule.md @@ -0,0 +1,93 @@ +###207. Course Schedule + + + +题目: + + + +难度: +Medium + +思路: + +就是考topological sort,用来判断directed graph是否有cycle + +DFS 和 BFS都可以用来拓扑排序。 + +最简单的想法是每次取出indegree是0的node,然后把它和与之相关的edge都删了。一开始觉得这样的时间复杂度会很高,然后看到了这样写,参照: + + + +很聪明的写法 + +这里做了转成set以及添加removeList这样的操作是因为边list边做iterator这样的操作很危险 + + + + +``` +class Solution(object): + def canFinish(self, numCourses, prerequisites): + """ + :type numCourses: int + :type prerequisites: List[List[int]] + :rtype: bool + """ + degrees = [ 0 for i in range(numCourses)] + childs = [[] for i in range(numCourses)] + for front, tail in prerequisites: + degrees[front] += 1 + childs[tail].append(front) + + courses = set(range(numCourses)) + flag = True + + while flag and len(courses): + flag = False + removeList = [] + for x in courses: + if degrees[x] == 0: + for child in childs[x]: + degrees[child] -= 1 + removeList.append(x) + flag = True + for x in removeList: + courses.remove(x) + return len(courses) == 0 + +``` + +因为CLRS里面明确提到涂色法来处理DFS + +搞了半天,写了一个涂色法,在超时的边缘。之所以超时边缘是因为每次都要去prerequisites里看,没有删减,不高效. + +``` +class Solution(object): + def canFinish(self, numCourses, prerequisites): + """ + :type numCourses: int + :type prerequisites: List[List[int]] + :rtype: bool + """ + def dfs(i, colors, prerequisites): + colors[i] = 'G' + #print i, colors + for front, tail in prerequisites: + if tail == i: + if colors[front] == 'G': + return False + elif colors[front] == 'B': + continue + elif dfs(front, colors, prerequisites) == False: + return False + colors[i] = 'B' + return True + + colors = ['W' for i in range(numCourses)] + for i in range(numCourses): + if colors[i] == 'W': + if dfs(i, colors, prerequisites) == False: + return False + return True +``` diff --git a/docs/Algorithm/Leetcode/Python/208._implement_trie_(prefix_tree).md b/docs/Algorithm/Leetcode/Python/208._implement_trie_(prefix_tree).md new file mode 100644 index 00000000..8ee06db5 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/208._implement_trie_(prefix_tree).md @@ -0,0 +1,89 @@ +### 208. Implement Trie (Prefix Tree) + +题目: + + + + +难度: + +Medium + +这个Python实现也太精美了吧,谷歌复写之 + +然后还unlock了一个solution,to read + +Trie整个都需要 to read,精美,可爱😊 + + + + +```python +class TrieNode(object): + def __init__(self): + """ + Initialize your data structure here. + """ + self.childs = dict() + self.isWord = False + + + +class Trie(object): + + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + """ + Inserts a word into the trie. + :type word: str + :rtype: void + """ + node = self.root + for letter in word: + child = node.childs.get(letter) + if child is None: + child = TrieNode() + node.childs[letter] = child + node = child + node.isWord = True + + def search(self, word): + """ + Returns if the word is in the trie. + :type word: str + :rtype: bool + """ + node = self.root + for i in word: + child = node.childs.get(i) + if child is None: + return False + node = child + return node.isWord + + + def startsWith(self, prefix): + """ + Returns if there is any word in the trie + that starts with the given prefix. + :type prefix: str + :rtype: bool + """ + node = self.root + for letter in prefix: + child = node.childs.get(letter) + if child is None: + return False + node = child + return True + + +# Your Trie object will be instantiated and called as such: +# trie = Trie() +# trie.insert("somestring") +# trie.search("key") + +``` + diff --git a/docs/Algorithm/Leetcode/Python/210._course_schedule_ii.md b/docs/Algorithm/Leetcode/Python/210._course_schedule_ii.md new file mode 100644 index 00000000..852b1163 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/210._course_schedule_ii.md @@ -0,0 +1,55 @@ +###210. Course Schedule II + + + +题目: + + + +难度: +Medium + +思路: + +在207的基础上加了order,进击 + + +``` +class Solution(object): + def findOrder(self, numCourses, prerequisites): + """ + :type numCourses: int + :type prerequisites: List[List[int]] + :rtype: List[int] + """ + degrees = [ 0 for i in range(numCourses)] + childs = [[] for i in range(numCourses)] + for front, tail in prerequisites: + degrees[front] += 1 + childs[tail].append(front) + + + courses = set(range(numCourses)) + flag = True + order = [] + + while flag and len(courses): + flag = False + removeList = [] + for x in courses: + if degrees[x] == 0: + print x + for child in childs[x]: + degrees[child] -= 1 + removeList.append(x) + order.append(x) + flag = True + for x in removeList: + courses.remove(x) + + if len(courses) == 0: + return order + else: + return [] + +``` diff --git a/docs/Algorithm/Leetcode/Python/211. Add and Search Word - Data structure design.md b/docs/Algorithm/Leetcode/Python/211. Add and Search Word - Data structure design.md new file mode 100644 index 00000000..7dd0ea27 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/211. Add and Search Word - Data structure design.md @@ -0,0 +1,77 @@ +### 211. Add and Search Word - Data structure design + +题目: + + + +难度: Medium + +思路: + +trie也是树,那么dfs/bfs同样适用。 + +实际上是照抄208trie的题目再加上dfs + + + +AC代码 + + + +``` +class TrieNode(object): + """docstring for TrieNode""" + def __init__(self): + self.childs = dict() + self.isWord = False + +class WordDictionary(object): + def __init__(self): + """ + initialize your data structure here. + """ + self.root = TrieNode() + + + def addWord(self, word): + """ + Adds a word into the data structure. + :type word: str + :rtype: void + """ + node = self.root + for letter in word: + child = node.childs.get(letter) + if child is None: + child = TrieNode() + node.childs[letter] = child + node = child + node.isWord = True + + + def search(self, word): + """ + Returns if the word is in the data structure. A word could + contain the dot character '.' to represent any one letter. + :type word: str + :rtype: bool + """ + def dfs(root, word): + if len(word) == 0: + return root.isWord + elif word[0] == '.': + for node in root.childs: + if dfs(root.childs[node], word[1:]): + return True + return False + else: + node = root.childs.get(word[0]) + if node is None: + return False + return dfs(node, word[1:]) + + return dfs(self.root, word) +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/213._house_robber_ii.md b/docs/Algorithm/Leetcode/Python/213._house_robber_ii.md new file mode 100644 index 00000000..9caec3df --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/213._house_robber_ii.md @@ -0,0 +1,61 @@ +###213. House Robber II + + +题目: + + + +难度: +Medium + +思路: + +跟house robber 1 类似,但是加了一些限制,抢到第 n-1 家最大两种可能,抢第 n-1 家和不抢第 n-1 家。 + + 0, 1, 2, 3, 4, 5, 6 ... n-1 + + +所以状态转移方程写成二维的更好来求,从第i家抢到第j家的状态转移方程 + + + nums[j] ,j = i + dp[i][j] = max(nums[i], nums[i+1]) , j = i +1 + max(dp[i][j-2] + nums[j], dp[i][j-1]), j > i+1 + + + +Show me the code + + +AC代码 + +``` +class Solution(object): + def rob(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = len(nums) + if n == 0 : return 0 + if n == 1 : return nums[0] + if n == 2 : return max(nums[0],nums[1]) + + dp = [[0 for i in range(n)] for j in range(n)] + + for i in range(n): + for j in range(i,n): + if j == i: + dp[i][j] = nums[j] + elif j == i + 1: + dp[i][j] = max(nums[i],nums[i+1]) + else: + dp[i][j] = max(dp[i][j-2] + nums[j], dp[i][j-1]) + + # print dp + # rob without n-1, or rob with n-1 + val = max(dp[0][n-2], dp[1][n-3] + nums[n-1]) + + return val + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/216._combination_sum_iii.md b/docs/Algorithm/Leetcode/Python/216._combination_sum_iii.md new file mode 100644 index 00000000..9e1b6371 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/216._combination_sum_iii.md @@ -0,0 +1,40 @@ +###216. Combination Sum III + +题目: + + + + +难度: + +Medium + +继续Combination Sum 系列 + + +``` +class Solution(object): + def combinationSum3(self, k, n): + """ + :type k: int + :type n: int + :rtype: List[List[int]] + """ + candidates = [1,2,3,4,5,6,7,8,9] + self.res = [] + self.combSum(candidates, n, [], k) + return self.res + + + def combSum(self,candidates, target, valueList, k): + if target == 0 and k == 0: + self.res.append(valueList) + length = len(candidates) + if length == 0 or k < 0 : + return + for i in range(length): + if candidates[i] > target: + return + self.combSum(candidates[i+1:], target - candidates[i], valueList + [candidates[i]], k-1) + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/217._contains_duplicate.md b/docs/Algorithm/Leetcode/Python/217._contains_duplicate.md new file mode 100644 index 00000000..8737f923 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/217._contains_duplicate.md @@ -0,0 +1,66 @@ +# 217. Contains Duplicate +**难度: 简单** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/contains-duplicate/ + +> 内容描述 + +``` + +Given an array of integers, find if the array contains any duplicates. + +Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct. + +Example 1: + +Input: [1,2,3,1] +Output: true +Example 2: + +Input: [1,2,3,4] +Output: false +Example 3: + +Input: [1,1,1,3,3,4,3,2,4,2] +Output: true +``` + +## 解题方案 + +> 思路 1 + +利用set怎么可以这么简单。。。。 + + +```python +class Solution(object): + def containsDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + return len(nums) != len(set(nums)) +``` + + +> 思路 2 + +或者先 sort 也可以 + +```python +class Solution(object): + def containsDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + nums.sort() + for i in range(len(nums)-1): + if nums[i] == nums[i+1]: + return True + return False +``` diff --git a/docs/Algorithm/Leetcode/Python/218._The _Skyline_Problem .md b/docs/Algorithm/Leetcode/Python/218._The _Skyline_Problem .md new file mode 100644 index 00000000..34d9c917 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/218._The _Skyline_Problem .md @@ -0,0 +1,134 @@ +### 218. The Skyline Problem + +题目: + + + +难度: + +Hard + +思路 + +观察发现,skyline的points的横坐标一定是某个building的左边界或者右边界。 + +开始,假设只有2个建筑物,拿出第一个buiding B1,我们先把它的左上顶点加进我们的output结果skyline中,然后继续拿下一个building B2,我们现在需要将B2的左上顶点对应的x coordinate与B1的右上顶点所对应的x coordinate做比较: + +- 如果前者小且B2的高度大于B1的高度,则我们将B2的左上顶点也加入skyline中去。 +- 如果前者小且B2的高度小于等于B1的高度,则忽略B2的左上顶点 + +接下来考虑更多建筑物的情况,从左到右扫描,当我们遇到第一个楼的左边界时,把它push到一个heap中。如果后面扫描的楼的高度比heap中最高的楼还高,那么它的左上顶点一定会被加入到skyline中。当我们遇到一个building的右边界时,我们需要将其从heap中pop掉,如果heap中max height有变化,则push到结果中。 + +参考[Brian Gordon的blog](https://briangordon.github.io/2014/08/the-skyline-problem.html) + 和 [Stefan大神的题解](https://leetcode.com/problems/the-skyline-problem/discuss/61194) + +#### 程序代码解释 + +- liveBuildings代表(左上顶点已经被加入output中但右上顶点还没有做判断的building)的右上顶点的集合,形式为[(height, x-coordinate)…..] +- skyline是output +- 程序里面的这句代码```while idx < n and buildings[idx][0] == start:```是为了防止有左右坐标完全相同但是height不同的building的存在,it's not useless!!! +- python里面的heapq模块如果有不懂的同学可以看看这个文章:[heapq](http://blog.csdn.net/calling_wisdom/article/details/41676133) + + +```python +class Solution(object): + def getSkyline(self, buildings): + """ + :type buildings: List[List[int]] + :rtype: List[List[int]] + """ + idx, n = 0, len(buildings) + liveBuildings, skyline = [], [] +        while idx < n or len(liveBuildings) > 0: # 只要所有的点没处理完就一直循环 +            if len(liveBuildings) == 0 or (idx < n and buildings[idx][0] <= -liveBuildings[0][1]): + start = buildings[idx][0] + while idx < n and buildings[idx][0] == start: + heapq.heappush(liveBuildings, [-buildings[idx][2], -buildings[idx][1]]) + idx += 1 + else: + start = -liveBuildings[0][1] + while len(liveBuildings) > 0 and -liveBuildings[0][1] <= start: + heapq.heappop(liveBuildings) + height = len(liveBuildings) and -liveBuildings[0][0] + if len(skyline) == 0 or skyline[-1][1] != height: + skyline.append([start, height]) + return skyline +``` +#####另外还有一个超级6的大神的代码,但是今天我要赶报告,就只先贴代码了 + +```python +class Solution(object): + def getSkyline(self, buildings): + """ + :type buildings: List[List[int]] + :rtype: List[List[int]] + """ + events = sorted([(L, -H, R) for L, R, H in buildings] + list(set((R, 0, None) for L, R, H in buildings))) + #events = sorted(event for L, R, H in buildings for event in ((L, -H, R), (R, 0, None))) + res, hp = [[0, 0]], [(0, float("inf"))] + for x, negH, R in events: + while x >= hp[0][1]: + heapq.heappop(hp) + if negH: heapq.heappush(hp, (negH, R)) + if res[-1][1] + hp[0][0]: + res += [x, -hp[0][0]], + return res[1:] +``` + +```Java +public class Solution { + public List getSkyline(int[][] buildings) { + List result = new ArrayList(); + if (buildings == null || buildings.length == 0 || buildings[0].length == 0) { + return result; + } + + List heights = new ArrayList(); + for (int[] building : buildings) { + heights.add(new Height(building[0], -building[2])); + heights.add(new Height(building[1], building[2])); + } + Collections.sort(heights, new Comparator() { + @Override + public int compare(Height h1, Height h2) { + return h1.index != h2.index ? h1.index - h2.index : h1.height - h2.height; + } + }); + + PriorityQueue pq = new PriorityQueue(1000, Collections.reverseOrder()); + pq.offer(0); + int prev = 0; + for (Height h : heights) { + if (h.height < 0) { + pq.offer(-h.height); + } else { + pq.remove(h.height); + } + int cur = pq.peek(); + if (cur != prev) { + result.add(new int[]{h.index, cur}); + prev = cur; + } + } + + return result; + } + + class Height { + int index; + int height; + Height(int index, int height) { + this.index = index; + this.height = height; + } + } +} +``` + + + +Author: Keqi Huang + +If you like it, please spread your support + +![Support](https://github.com/Lisanaaa/myTODOs/blob/master/WechatIMG17.jpeg) diff --git a/docs/Algorithm/Leetcode/Python/219._contains_duplicate_ii.md b/docs/Algorithm/Leetcode/Python/219._contains_duplicate_ii.md new file mode 100644 index 00000000..050dd932 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/219._contains_duplicate_ii.md @@ -0,0 +1,99 @@ +# 219. Contains Duplicate II +**难度: 简单** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/contains-duplicate-ii/ + +> 内容描述 + +``` +Given 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. + +Example 1: + +Input: nums = [1,2,3,1], k = 3 +Output: true +Example 2: + +Input: nums = [1,0,1,1], k = 1 +Output: true +Example 3: + +Input: nums = [1,2,3,1,2,3], k = 2 +Output: false +``` + +## 解题方案 + +> 思路 1 + + +这道题虽然看似简单,但是我还是经历几次失败 + +第一次我打算用最粗暴的方法来做,直接 Time Limit Exceeded,代码如下: +``` +class Solution(object): + def containsNearbyDuplicate(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: bool + """ + if k == 0: + return False + if k >= len(nums): + return len(nums) != len(set(nums)) + for i in range(len(nums)-k): + for j in range(1, k+1): + if nums[i] == nums[i+j]: + return True + for i in range(len(nums)-k, len(nums)): + for j in range(i+1, len(nums)): + if nums[i] == nums[j]: + return True + return False +``` +然后我打算用第 217 题的方法来一遍,还是报 Time Limit Exceeded 这个错,代码如下L: +``` +class Solution(object): + def containsNearbyDuplicate(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: bool + """ + if k == 0: + return False + if k >= len(nums): + return len(nums) != len(set(nums)) + for i in range(len(nums)-k): + if len(nums[i:i+k+1]) != len(set(nums[i:i+k+1])): + return True + return len(nums[-k:]) != len(set(nums[-k:])) +``` + +终于我想到了用字典来存,这个元素还没出现过,就以 的形式存进字典里,如果 num 再次出现了,计算相邻距离,小于等于 k 则 return true,否则更新字典中元素的位置, + + +```python +class Solution(object): + def containsNearbyDuplicate(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: bool + """ + lookup = {} + for i in range(len(nums)): + if nums[i] not in lookup: + lookup[nums[i]] = i + else: + if i - lookup[nums[i]] <= k: + return True + else: + lookup[nums[i]] = i + return False +``` diff --git a/docs/Algorithm/Leetcode/Python/221._maximal_square.md b/docs/Algorithm/Leetcode/Python/221._maximal_square.md new file mode 100644 index 00000000..3dd7b9a8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/221._maximal_square.md @@ -0,0 +1,78 @@ +###221. Maximal Square + + +题目: + + + +难度: +Medium + +tag: DP + + +递推公式,一开始想的很简单: + +dp[i][j] = dp[i-1][j-1] + 1 #如果dp[i-1][j-1]为1,dp[i-1][j]为1,dp[i][j-1]为1 + +很明显的错误,一旦遇到更大的方块就会有问题 + +然后看了hint,其实递推方程式是很有技巧的,左上角,左边,上面,相邻的三个部分最小的+1,当然,前提也是要这里dp[i][j] 为1,然后我们再会去看其他的部分。 + +看个例子 + +``` +原本的matrix DP + +1 0 1 0 0 1 0 1 0 0 +1 0 1 1 1 → 1 0 1 1 1 +1 1 1 1 1 1 1 1 2 2 +1 0 0 1 0 1 0 0 1 0 + +``` + +是非常make sense的,因为最小的必定包括了周边的1,然后再加1,否则如果是0的话那么就为0. + +而naïve的错误的递推公式是因为一个square考虑的部分是k * k的部分, k * k 部分都必定为1. + +而正确的递推公式 + + + dp[i][j] = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) + 1 + +则完美的考虑了这一情况 + + +``` +class Solution(object): + def maximalSquare(self, matrix): + """ + :type matrix: List[List[str]] + :rtype: int + """ + dp = [] + for i in matrix: + tmp = [] + for j in i: + tmp.append(int(j)) + dp.append(tmp) + + row = len(dp) + col = len(dp[0]) if row else 0 + + + for i in range(1,row): + for j in range(1,col): + if dp[i][j] == 1: + dp[i][j] = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) + 1 + + + maxv = 0 + for i in range(row): + for j in range(col): + if dp[i][j] > maxv: + maxv = dp[i][j] + return maxv * maxv +``` + + diff --git a/docs/Algorithm/Leetcode/Python/222._count_complete_tree_nodes.md b/docs/Algorithm/Leetcode/Python/222._count_complete_tree_nodes.md new file mode 100644 index 00000000..e1b6bede --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/222._count_complete_tree_nodes.md @@ -0,0 +1,67 @@ +###222. Count Complete Tree Nodes + +题目: + + + +难度: +Medium + + +思路: + + +思路一: 超时,跟一般的树一样,递归的来数nodes数 + + + +``` +class Solution(object): + def countNodes(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if root == None: + return 0 + if root.left == None and root.right == None: + return 1 + return 1 + self.countNodes(root.left) + self.countNodes(root.right) +``` + + +思路二:既然说了是 complete binary tree,那么必然有特性可用,complete binary tree的特性是除了最后一层,之前的就是perfect tree. + + +所以寻找左子树的最左边的高度和右子树的最右边的node高度,如果相同就是perfect tree,高度2^h - 1, 否则递归的来看左子树和右子树 + + +``` + +class Solution(object): + def countNodes(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if root == None: + return 0 + + p, q = root,root + + leftHeight = 0 + rightHeight = 0 + + while p: + p = p.left + leftHeight += 1 + + while q: + q = q.right + rightHeight += 1 + + if leftHeight == rightHeight: + return (int)(math.pow(2,leftHeight) - 1) + else: + return 1 + self.countNodes(root.left) + self.countNodes(root.right) +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/223._rectangle_area.md b/docs/Algorithm/Leetcode/Python/223._rectangle_area.md new file mode 100644 index 00000000..90a69fa3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/223._rectangle_area.md @@ -0,0 +1,51 @@ +# 223. Rectangle Area +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/rectangle-area/description/ + +> 内容描述 + +``` +Find the total area covered by two rectilinear rectangles in a 2D plane. + +Each rectangle is defined by its bottom left corner and top right corner as shown in the figure. + +Rectangle Area + +Example: + +Input: A = -3, B = 0, C = 3, D = 4, E = 0, F = -1, G = 9, H = 2 +Output: 45 +Note: + +Assume that the total area is never beyond the maximum possible value of int. +``` + +## 解题方案 + +> 思路 1 + +sb题没什么好说的 + +```python +class Solution(object): + def computeArea(self, A, B, C, D, E, F, G, H): + """ + :type A: int + :type B: int + :type C: int + :type D: int + :type E: int + :type F: int + :type G: int + :type H: int + :rtype: int + """ + 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) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/224. Basic Calculator .md b/docs/Algorithm/Leetcode/Python/224. Basic Calculator .md new file mode 100644 index 00000000..53683dc7 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/224. Basic Calculator .md @@ -0,0 +1,108 @@ +### 224. Basic Calculator + + + +题目: + + +难度: +Medium + +思路: + +基本跟227一样,只是这里加了括号 + +瞄了一眼,基本上infix(中缀表达式)都是表达成postfix(后缀表达式)再来求值的。 +比如 A + B * C 写成 A B C * + + +| Infix Expression | Prefix Expression | Postfix Expression | +| ---------------- | ----------------- | ------------------ | +| A + B | + A B | A B + | +| A + B * C | + A * B C | A B C * + | + + + +infix 中缀转postfix 后缀还有专门的算法: + + + +1. Create an empty stack called opstack for keeping operators. Create an empty list for output. + +2. Convert the input infix string to a list by using the string method split. + +3. Scan the token list from left to right. + +4. - If the token is an operand, append it to the end of the output list. + - If the token is a left parenthesis, push it on the opstack. + - 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. + - 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. + +5. 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. + + + +可以看到中缀转后缀一个重要的点是: 当我们把operator +-*/ 放到opstack上时候,我们需要考虑/看是否有之前的operator有更高或者相等的precedence,这个时候我们需要优先(计算)把它放到output list. + + + +参考 + + + + + +AC代码 + +``` +class Solution(object): + def calculate(self, s): + """ + :type s: str + :rtype: int + """ + def precedence(op): + if op == '*' or op == '/': + return 2 + else: + return 1 + + def cal(op, op1, op2): + if op == '*': + return op1 * op2 + elif op == '/': + return op1 / float(op2) + elif op == '+': + return op1 + op2 + else: + return op1 - op2 + + + opstack = [] + operands = [] + + # remove empty space and put operands and + idx = 0 + for i in range(idx, len(s)): + if s[i] in '+-*/': + operands.append(s[idx:i]) + while len(opstack) > 0 and precedence(s[i]) <= precedence(opstack[-1]) and len(operands) >= 2: + op = opstack.pop() + op2 = int(operands.pop()) + op1 = int(operands.pop()) + res = cal(op, op1, op2) + operands.append(res) + opstack.append(s[i]) + idx = i + 1 + operands.append(s[idx:]) + + while opstack: + op = opstack.pop() + op2 = int(operands.pop()) + op1 = int(operands.pop()) + res = cal(op, op1, op2) + operands.append(res) + + return int(operands[0]) + +``` + diff --git a/docs/Algorithm/Leetcode/Python/225._implement_stack_using_queues.md b/docs/Algorithm/Leetcode/Python/225._implement_stack_using_queues.md new file mode 100644 index 00000000..10a1ac20 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/225._implement_stack_using_queues.md @@ -0,0 +1,53 @@ +###225. Implement Stack using Queues + +题目: + + + + +难度: + +Easy + + +又到了作弊神预言Python的强项 + + +``` +class Stack(object): + def __init__(self): + """ + initialize your data structure here. + """ + self.lst = [] + + + def push(self, x): + """ + :type x: int + :rtype: nothing + """ + self.lst.append(x) + + + def pop(self): + """ + :rtype: nothing + """ + self.lst.remove(self.lst[-1]) + + + def top(self): + """ + :rtype: int + """ + return self.lst[-1] + + def empty(self): + """ + :rtype: bool + """ + return self.lst == [] + +``` + diff --git a/docs/Algorithm/Leetcode/Python/226._invert_binary_tree.md b/docs/Algorithm/Leetcode/Python/226._invert_binary_tree.md new file mode 100644 index 00000000..cb908696 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/226._invert_binary_tree.md @@ -0,0 +1,28 @@ +### 226. Invert Binary Tree + +题目: + + + +难度: + +Easy + +典型的递归题 + + +```python +class Solution(object): + def invertTree(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + if not root: + return None + self.invertTree(root.left) + self.invertTree(root.right) + root.left, root.right = root.right, root.left + return root +``` + diff --git a/docs/Algorithm/Leetcode/Python/227._basic_calculator_ii.md b/docs/Algorithm/Leetcode/Python/227._basic_calculator_ii.md new file mode 100644 index 00000000..ac5ea4ee --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/227._basic_calculator_ii.md @@ -0,0 +1,108 @@ +###227. Basic Calculator II + + + +题目: + + + +难度: +Medium + +思路: + +瞄了一眼,基本上infix(中缀表达式)都是表达成postfix(后缀表达式)再来求值的。 +比如 A + B * C 写成 A B C * + + + +| Infix Expression | Prefix Expression | Postfix Expression | +| ---------------- | ----------------- | ------------------ | +| A + B | + A B | A B + | +| A + B * C | + A * B C | A B C * + | + + +infix 中缀转postfix 后缀还有专门的算法: + + + +1. Create an empty stack called opstack for keeping operators. Create an empty list for output. + +2. Convert the input infix string to a list by using the string method split. + +3. Scan the token list from left to right. + +4. - If the token is an operand, append it to the end of the output list. + - If the token is a left parenthesis, push it on the opstack. + - 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. + - 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. + +5. 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. + + + +可以看到中缀转后缀一个重要的点是: 当我们把operator +-*/ 放到opstack上时候,我们需要考虑/看是否有之前的operator有更高或者相等的precedence,这个时候我们需要优先(计算)把它放到output list. + + + + +参考 + + + + + +AC代码 + +``` +class Solution(object): + def calculate(self, s): + """ + :type s: str + :rtype: int + """ + def precedence(op): + if op == '*' or op == '/': + return 2 + else: + return 1 + + def cal(op, op1, op2): + if op == '*': + return op1 * op2 + elif op == '/': + return op1 / float(op2) + elif op == '+': + return op1 + op2 + else: + return op1 - op2 + + + opstack = [] + operands = [] + + # remove empty space and put operands and + idx = 0 + for i in range(idx, len(s)): + if s[i] in '+-*/': + operands.append(s[idx:i]) + while len(opstack) > 0 and precedence(s[i]) <= precedence(opstack[-1]) and len(operands) >= 2: + op = opstack.pop() + op2 = int(operands.pop()) + op1 = int(operands.pop()) + res = cal(op, op1, op2) + operands.append(res) + opstack.append(s[i]) + idx = i + 1 + operands.append(s[idx:]) + + while opstack: + op = opstack.pop() + op2 = int(operands.pop()) + op1 = int(operands.pop()) + res = cal(op, op1, op2) + operands.append(res) + + return int(operands[0]) + +``` + diff --git a/docs/Algorithm/Leetcode/Python/228._summary_ranges.md b/docs/Algorithm/Leetcode/Python/228._summary_ranges.md new file mode 100644 index 00000000..ce9dce0f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/228._summary_ranges.md @@ -0,0 +1,58 @@ +### 228. Summary Ranges + +题目: + + + +难度: + +Medium + + +Just collect the ranges, then format and return them. + +```python +class Solution(object): + def summaryRanges(self, nums): + """ + :type nums: List[int] + :rtype: List[str] + """ + ranges = [] + for i in nums: + if not ranges or i > ranges[-1][-1] + 1: + ranges += [], + ranges[-1][1:] = i, + return ['->'.join(map(str, r)) for r in ranges] +``` +About the commas :-) + +``` +ranges += [], +r[1:] = n, +``` +Why the trailing commas? Because it turns the right hand side into a tuple and I get the same effects as these more common alternatives: +``` +ranges += [[]] +or +ranges.append([]) + +r[1:] = [n] +``` +Without the comma, … + +- ranges += [] wouldn’t add [] itself but only its elements, i.e., nothing. +- r[1:] = n wouldn’t work, because my n is not an iterable. + +Why 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). + +写到这里可能又有疑问了🤔️,为什么不可以直接写```ranges[-1][1] = i```呢,当然是会报```IndexError: list assignment index out of range```错误啦,那为什么```ranges[-1][1:] = i,```可以呢? + +简单来说 + +L1=L 与 L1=L[:] +- L1和L 都是对同一个对象的引用(所谓绑定的意思)。 +- L[:] 是生成了一个和L不同的新的对象,L1 变为了L[:] 这个对象的引用。 + + +参考[stefan](https://leetcode.com/problems/summary-ranges/discuss/63193) diff --git a/docs/Algorithm/Leetcode/Python/229._majority_element_ii.md b/docs/Algorithm/Leetcode/Python/229._majority_element_ii.md new file mode 100644 index 00000000..061c0344 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/229._majority_element_ii.md @@ -0,0 +1,62 @@ +###229. Majority Element II + + + +题目: + + + +难度: +Medium + +思路: + +majority element是两两比较扔掉不同的元素,然后最后会留下一个。 + +这里变成三三比较来扔东西, find all elements that appear more than ⌊ n/3 ⌋ times,所以最多可以有两个majority element ii. + + +最后再加一个比较来确认这些函数是majority element + +``` +class Solution(object): + def majorityElement(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + cnt1 = 0 + cnt2 = 0 + maj1 = 0 + maj2 = 0 + for num in nums: + if maj1 == num: + cnt1 += 1 + elif maj2 == num: + cnt2 += 1 + elif cnt1 == 0: + maj1 = num + cnt1 += 1 + elif cnt2 == 0: + maj2 = num + cnt2 += 1 + else: + cnt1 -= 1 + cnt2 -= 1 + + cnt1 = 0 + cnt2 = 0 + + n = len(nums) + res = [] + for num in nums: + if maj1 == num: + cnt1 += 1 + elif maj2 == num: + cnt2 += 1 + if cnt1 > n/3: + res.append(maj1) + if cnt2 > n/3: + res.append(maj2) + return res +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/230._kth_smallest_element_in_a_bst.md b/docs/Algorithm/Leetcode/Python/230._kth_smallest_element_in_a_bst.md new file mode 100644 index 00000000..b51fc7a0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/230._kth_smallest_element_in_a_bst.md @@ -0,0 +1,48 @@ +### 230. Kth Smallest Element in a BST + +题目: + + + +难度: +Medium + + +跟昨天做的一道题类似,一上来就走取巧之路。 + +InOrder排序,输出,当然也完全可以用昨天的binary tree iterator,入stack,出stack,直到输出第k位 + + +```python +class Solution(object): + def kthSmallest(self, root, k): + """ + :type root: TreeNode + :type k: int + :rtype: int + """ + self.root = root + self.lst = [] + self.inOrder(root) + return self.lst[k-1] + + def inOrder(self, root): + if root == None: + return + self.inOrder(root.left) + self.lst.append(root.val) + self.inOrder(root.right) +``` + + +现在看到kth 就条件反射的想用divide & conquer, 扫root的左子树看nodes量,如果nodes数量是k-1,那么node就刚好是第k个,如果大于k > 左子树数量,扫右子树,同时更新root为root.right。 + +看到的言论: + +> 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. + +when the node is not null. + +- if k == node.leftNum + 1, return node +- if k > node.leftNum + 1, make k -= node.leftNum + 1, and then node = node.right +- otherwise, node = node.left diff --git a/docs/Algorithm/Leetcode/Python/231. _Power_of_Two.md b/docs/Algorithm/Leetcode/Python/231. _Power_of_Two.md new file mode 100644 index 00000000..c90024d2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/231. _Power_of_Two.md @@ -0,0 +1,89 @@ +### 231. Power of Two + + + +题目: + + + +难度: + +Easy + + + +思路: + + + +power of two 那是这个数字的binary 表示一定只有一个1 + +套用以前的代码[leetcode191](https://github.com/Lisanaaa/thinking_in_lc/blob/master/191._number_of_1_bits.md) + +这样会超时 + +``` +class Solution(object): +    def isPowerOfTwo(self, n): # 此法超时 +        """ + :type n: int + :rtype: bool + """ + cnt = 0 + while n != 0: + n &= n - 1 + cnt += 1 + return cnt == 1 +``` + + + +跟power of three一样递归,可以AC + + + +```python +class Solution(object): + def isPowerOfTwo(self, n): + """ + :type n: int + :rtype: bool + """ + if n <= 0: + return False + if n == 1: + return True + if n % 2 == 0: + return self.isPowerOfTwo(n/2) + return False + +``` + + + + + + + +也是有[算法的wikipedia page](https://en.wikipedia.org/wiki/Power_of_two#Fast_algorithm_to_check_if_a_positive_number_is_a_power_of_two) + +> 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: +> +> positive *x* is a power of two ⇔ (*x* & (*x* − 1)) is equal to zero. + + + +注意特殊case 0的处理 + +```python +class Solution(object): + def isPowerOfTwo(self, n): + """ + :type n: int + :rtype: bool + """ + return n & (n-1) == 0 if n != 0 else False +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/232._implement_queue_using_stacks.md b/docs/Algorithm/Leetcode/Python/232._implement_queue_using_stacks.md new file mode 100644 index 00000000..53647fc0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/232._implement_queue_using_stacks.md @@ -0,0 +1,51 @@ +###232. Implement Queue using Stacks + +题目: + + + +难度: +Easy + +这个题没有乖乖听话,不过因为当年做过用两个stack来模拟queue + +然后不得不说,我Python大法实在太厉害了 + +这功能强大的,我简直要啧啧啧 + +``` +class Queue(object): + def __init__(self): + """ + initialize your data structure here. + """ + self.lst = [] + + + def push(self, x): + """ + :type x: int + :rtype: nothing + """ + self.lst.append(x) + + + def pop(self): + """ + :rtype: nothing + """ + del self.lst[0] + + def peek(self): + """ + :rtype: int + """ + return self.lst[0] + + + def empty(self): + """ + :rtype: bool + """ + return self.lst == [] +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/234._palindrome_linked_list.md b/docs/Algorithm/Leetcode/Python/234._palindrome_linked_list.md new file mode 100644 index 00000000..0d92492b --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/234._palindrome_linked_list.md @@ -0,0 +1,94 @@ +### 234. Palindrome Linked List + +题目: + + + +难度: +Easy + +蠢了一下, + +思路是:“先翻转整个链表(in-place),然后和之前的链表比较”,但是这样原链表都变了,肯定错。 + +如果新建一个链表,然后改造成原来链表的翻转链表,还是可行的,但是空间复杂度就是O(n)了。那还不如直接把List中元素拷贝到数组中直接比较,ac代码如下: + + +```python +class Solution(object): + def isPalindrome(self, head): + """ + :type head: ListNode + :rtype: bool + """ + vals = [] + while head: + vals += head.val, + head = head.next + return vals == vals[::-1] +``` + +这道题并不能算Easy吧: + +思路二: +要想实现O(1)的空间复杂度,可以找到中间的节点,把linked list拆成两个部分,后半部分linkedlist reverse,然后比较两个linked list值是否相同,看例子: + + +``` +1 -> 3 -> 1 拆成 1 和 1 + +1 -> 3 -> 5 ->5 -> 3 -> 1 拆成 1-> 3 -> 5 和 5 -> 3 -> 1 + +``` + +可以使用快慢指针来找到中间的节点。 + + +```python +class Solution(object): + def isPalindrome(self, head): + """ + :type head: ListNode + :rtype: bool + """ + fast = slow = head + # 找到中间节点 + while fast and fast.next: + fast = fast.next.next + slow = slow.next + # 翻转后半部分 + prev = None + while slow: + tmp = slow.next + slow.next = prev + prev = slow + slow = tmp + # 比较前后两部分 + while prev: # while prev and head: + if prev.val != head.val: + return False + prev = prev.next + head = head.next + return True +``` + +给个最终状态的例子: +``` + + fast tmp + None prev slow + ^ ^ ^ + | | | +1 --> 2 --> 3 <-- 2 <-- 1 None + +``` +但是注意最后的while prev不能换成while fast, 因为这是总节点数为奇数的情况,如果是偶数情况就不一样了,如下: +``` +                         tmp +                          slow    + None prev fast + ^ ^ ^ + | | | +1 --> 2 --> 2 <-- 1 None + +``` diff --git a/docs/Algorithm/Leetcode/Python/235._lowest_common_ancestor_of_a_binary_search_tree.md b/docs/Algorithm/Leetcode/Python/235._lowest_common_ancestor_of_a_binary_search_tree.md new file mode 100644 index 00000000..62c1e09a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/235._lowest_common_ancestor_of_a_binary_search_tree.md @@ -0,0 +1,33 @@ +###235. Lowest Common Ancestor of a Binary Search Tree + +题目: + + + +难度 : Easy + +- 两个node,一个大于root,一个小于root,那么必定root两边,共同的ancestor是root,同时再考虑同为空的状况 +- 两个node,都比node小,到左边去寻找,那么先找到那个必定是common ancestor +- 两个node,都比node大,类似.... + + +AC解法 + +``` +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + if root == None or root == p or root == q: + return root + elif p.val < root.val < q.val or q.val < root.val < p.val : + return root + elif p.val < root.val and q.val < root.val: + return self.lowestCommonAncestor(root.left,p,q) + else: + return self.lowestCommonAncestor(root.right,p,q) +``` diff --git a/docs/Algorithm/Leetcode/Python/236._lowest_common_ancestor_of_a_binary_tree.md b/docs/Algorithm/Leetcode/Python/236._lowest_common_ancestor_of_a_binary_tree.md new file mode 100644 index 00000000..271c462a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/236._lowest_common_ancestor_of_a_binary_tree.md @@ -0,0 +1,104 @@ + +###236. Lowest Common Ancestor of a Binary Tree + + +题目: + + + +难度: + +Medium + + + +思路 + +求root到node的path,然后对比path,最后一个想同的点就是lowest common ancestor + + + +好开心,AC了 + + +但是我根本不能在Runtime Distribution 上找到我,因为太慢了|||| + + + + +``` + +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + pathP = self.pathTo(root,p) + pathQ = self.pathTo(root,q) + n = min(len(pathP), len(pathQ)) + + ans = root + for i in range(n): + if pathP[i] == pathQ[i]: + ans = pathP[i] + else: + break + return ans + + + def pathTo(self, root, goal): + # goal node ,path + if root == None: return root + stack = [(root, [root])] + while stack: + node, path = stack.pop() + if node == goal: + return path + if node.left: stack.append((node.left, path + [node.left])) + if node.right: stack.append((node.right, path + [node.right])) + +``` + +递归解法,之所以我没有用递归因为有疑惑, BASE CASE 很容易想到,root 是none,或者p == root 或者q == root,那么LCA就是root,如果两个node一个在左边,一个在右边,那么LCA也是root,但是如果一个是6,另一个是4则有一点疑惑,但其实是没有问题的,因为这个时候给的总是他们的共同root,所以这个递归解法是没错的,总是想到递归是在那个状况下递归 + + +``` + _______3______ + / \ + ___5__ ___1__ + / \ / \ + 6 _2 0 8 + / \ + 7 4 +``` + +AC代码 + + + +``` +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + if root == None: + return None + + if p == root or q == root: + return root + + left = self.lowestCommonAncestor(self.left,p,q) + right = self.lowestCommonAncestor(self.right,p,q) + + if left and right: + return root + + return left if left is None else right +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/237._delete_node_in_a_linked_list.md b/docs/Algorithm/Leetcode/Python/237._delete_node_in_a_linked_list.md new file mode 100644 index 00000000..d401e090 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/237._delete_node_in_a_linked_list.md @@ -0,0 +1,52 @@ +### 237. Delete Node in a Linked List + +题目: + + + +难度: +Easy + + + +这道题,第一感觉,像删链表一样来删,把所有的node val前移一个,但是有个问题,为什么tail那个node还是存在?哼(ˉ(∞)ˉ)唧.. + +已经被解答: + + + + + +另外一个O(1)的办法更好,把后一个node的val移到待删这个节点,并且把node.next = node.next.next + +题目说了不会删最后一个点,所以node.next.next一定存在,所以直接让node的val等于它next的val,然后让node的next指向它的next的next,举个例子: + 1->2->3->4->5->None,要删除第四个节点,就让4变成5,然后让第四个节点指向第五个节点的next, +这样原来的第四个节点就不存在了,虽然原来的第五个节点仍然存在且指向None,变成了1->2->3->5->None-<5 + + + +```python +O(1)时间 +class Solution(object): + def deleteNode(self, node): + """ + :type node: ListNode + :rtype: void Do not return anything, modify node in-place instead. + """ + node.val = node.next.val + node.next = node.next.next +``` +```python +O(n)时间 +class Solution(object): + def deleteNode(self, node): + """ + :type node: ListNode + :rtype: void Do not return anything, modify node in-place instead. + """ + while node.next: + node.val = node.next.val + prev, node = node, node.next + # clear reference to tail + prev.next = None +``` diff --git a/docs/Algorithm/Leetcode/Python/238._product_of_array_except_self.md b/docs/Algorithm/Leetcode/Python/238._product_of_array_except_self.md new file mode 100644 index 00000000..00a883f6 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/238._product_of_array_except_self.md @@ -0,0 +1,100 @@ +###238. Product of Array Except Self + +题目: + + + +难度: + +Medium + + +不使用division 并且O(n) + + +想到的算法 O(n^2) + +会超时 + + +``` +class Solution(object): + def productExceptSelf(self,nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + lst = [] + for i in range(len(nums)): + lst.append(self.productWithoutI(nums,i)) + return lst + + + def productWithoutI(self,nums,i): + product = 1 + for j in range(len(nums)): + if j != i: + product *= nums[j] + return product +``` + +如果用除法,也会有问题,如果有0出现也会变繁琐。 + +谷歌一下: + + +解法还是很棒的 + + output[i] = { i 前面的数的乘积} X { i 后面的数的乘积} + + +``` +class Solution(object): + def productExceptSelf(self,nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + if nums == [] : return [] + lft = [1] + rgt = [1] + product = 1 + for i in range(1,len(nums)): + product *= nums[i-1] + lft.append(product) + product = 1 + for i in reversed(range(1,len(nums))): + product *= nums[i] + rgt.append(product) + rgt.reverse() + result = [] + for i in range(len(nums)): + result.append(lft[i]*rgt[i]) + return result + +``` + + +空间O(n),再看到满足要求的“标准解法” + + +``` +class Solution(object): + def productExceptSelf(self,nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + if nums == [] : return [] + size = len(nums) + output = [1] * size + left = 1 + for x in range(size-1): + left *= nums[x] + output[x+1] *= left + right = 1 + for x in range(size - 1, 0, -1): + right *= nums[x] + output[x-1] *= right + return output +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/240._search_a_2d_matrix_ii.md b/docs/Algorithm/Leetcode/Python/240._search_a_2d_matrix_ii.md new file mode 100644 index 00000000..545732eb --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/240._search_a_2d_matrix_ii.md @@ -0,0 +1,63 @@ +### 240. Search a 2D Matrix II + + + +题目: + + + +难度: +Medium + +思路: + +每行,每列都是sorted + +但是比较好的策略是从右上角开始搜索,比如这样: + +``` +matrix = [ + [1, 4, 7, 11, 15], + [2, 5, 8, 12, 19], + [3, 6, 9, 16, 22], + [10, 13, 14, 17, 24], + [18, 21, 23, 26, 30] +] + +m, n = 0, col - 1 +更新策略: + matrix[m][n] < target: 那么这一行到从左走到此都会小于target,row+1 ,往下走 + matrix[m][n] > target: 那么这一列往下走都会大于target,col - 1,往左走 + 否则找到 +``` + +时间复杂度O(max(M,N)),因为每次都会往下或者往左走 + + +用的算法是Saddleback + + + +```python +class Solution(object): + def searchMatrix(self, matrix, target): + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + if not matrix: + return False + row = len(matrix) + col = len(matrix[0]) if row else 0 + m, n = 0, col - 1 + while m < row and n >= 0: + if matrix[m][n] < target: + m += 1 + elif matrix[m][n] > target: + n -= 1 + else: + return True + return False + +``` diff --git a/docs/Algorithm/Leetcode/Python/242._valid_anagram.ipynb b/docs/Algorithm/Leetcode/Python/242._valid_anagram.ipynb new file mode 100644 index 00000000..26218f62 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/242._valid_anagram.ipynb @@ -0,0 +1,189 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 242. Valid Anagram 有效的字母异位词\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/valid-anagram/description/\n", + " - 英文:https://leetcode.com/problems/valid-anagram/\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。\n", + "\n", + "示例 1:\n", + "输入: s = \"anagram\", t = \"nagaram\"\n", + "输出: true\n", + "\n", + "示例 2:\n", + "输入: s = \"rat\", t = \"car\"\n", + "输出: false\n", + "\n", + "说明:\n", + "你可以假设字符串只包含小写字母。\n", + "\n", + "进阶:\n", + "如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 一行瞬秒!\n", + " - 适用 collections.Counter() 方法" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "import collections\n", + "\n", + "class 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", + "s = \"anagram\"\n", + "t = \"nagaram\"\n", + "ss = Solution()\n", + "print(ss.isAnagram(s, t))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "> 思路 2\n", + "\n", + " - 同样是一行瞬秒!\n", + " - 适用 sorted() 函数" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = \"anagram\"\n", + "t = \"nagaram\"\n", + "ss = Solution()\n", + "print(ss.isAnagram(s, t))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3\n", + "\n", + " - 用字数统计,因为只可能是 26 个字母" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + " if cnt != 0:\n", + " return False\n", + " return True\n", + " \n", + "s = \"anagram\"\n", + "t = \"nagaram\"\n", + "ss = Solution()\n", + "print(ss.isAnagram(s, t))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/242._valid_anagram.md b/docs/Algorithm/Leetcode/Python/242._valid_anagram.md new file mode 100644 index 00000000..46d8cd26 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/242._valid_anagram.md @@ -0,0 +1,61 @@ +### 242. Valid Anagram + +题目: + + + +难度 : Easy + + +一行瞬秒: + +```python +class Solution(object): + def isAnagram(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + return collections.Counter(s) == collections.Counter(t) +``` + +```python +class Solution(object): + def isAnagram(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + return sorted(s) == sorted(t) + +``` + + +用字数统计,因为只可能是26个字母 + + +``` + +class Solution(object): + def isAnagram(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + if len(s) != len(t): + return False + + charCnt = [0] * 26 + + for i in range(len(s)): + charCnt[ord(s[i]) - 97] += 1 + charCnt[ord(t[i]) - 97] -= 1 + + for cnt in charCnt: + if cnt != 0: + return False + return True +``` diff --git a/docs/Algorithm/Leetcode/Python/249._Group_Shifted_Strings.md b/docs/Algorithm/Leetcode/Python/249._Group_Shifted_Strings.md new file mode 100644 index 00000000..1ad1c478 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/249._Group_Shifted_Strings.md @@ -0,0 +1,61 @@ +# 249. Group Shifted Strings +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/group-shifted-strings/description/ + +> 内容描述 + +``` +Given 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: + +"abc" -> "bcd" -> ... -> "xyz" +Given a list of strings which contains only lowercase alphabets, group all strings that belong to the same shifting sequence. + +Example: + +Input: ["abc", "bcd", "acef", "xyz", "az", "ba", "a", "z"], +Output: +[ + ["abc","bcd","xyz"], + ["az","ba"], + ["acef"], + ["a","z"] +] +``` + +## 解题方案 + +> 思路 1 + +hash table存储pattern + +```python +class Solution(object): + def groupStrings(self, strings): + """ + :type strings: List[str] + :rtype: List[List[str]] + """ + table = {} + for w in strings: + pattern = '' + for i in range(1, len(w)): + if ord(w[i]) - ord(w[i - 1]) >= 0: + pattern += str(ord(w[i]) - ord(w[i - 1])) + else: + pattern += str(ord(w[i]) - ord(w[i - 1]) + 26) ## 这是为了处理'az'和'ba'的情况 + + if pattern in table: + table[pattern].append(w) + else: + table[pattern] = [w] + return [table[pattern] for pattern in table] +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/252. Meeting Rooms.md b/docs/Algorithm/Leetcode/Python/252. Meeting Rooms.md new file mode 100644 index 00000000..c84dee95 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/252. Meeting Rooms.md @@ -0,0 +1,47 @@ +### 252. Meeting Rooms + + + +题目: + + + + +难度 : Easy + + + +思路: + +学了一下如何根据attribute 来sort object `intervals.sort(key = lambda interval : interval.start)` + + + +AC 代码 + +``` +# Definition for an interval. +# class Interval(object): +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class Solution(object): + def canAttendMeetings(self, intervals): + """ + :type intervals: List[Interval] + :rtype: bool + """ + n = len(intervals) + if n < 2 : return True + intervals.sort(key = lambda interval : interval.start) + for i in range(1,n): + if intervals[i].start < intervals[i-1].end: + return False + return True +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md b/docs/Algorithm/Leetcode/Python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md new file mode 100644 index 00000000..dfe1f703 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md @@ -0,0 +1,72 @@ +### 255. Verify Preorder Sequence in Binary Search Tree + +题目: + + + +难度: + +Medium + + +思路: + +这道题让给了我们一个一维数组,让我们验证其是否为一个二叉搜索树的先序遍历出的顺序,我们都知道二叉搜索树的性质是左<根<右,如果用中序遍历得到的结果就是有序数组,而先序遍历的结果就不是有序数组了,但是难道一点规律都没有了吗,其实规律还是有的,根据二叉搜索树的性质,当前节点的值一定大于其左子树中任何一个节点值,而且其右子树中的任何一个节点值都不能小于当前节点值,那么我们可以用这个性质来验证,举个例子,比如下面这棵二叉搜索树: +``` + 10 + / \ + 5 12 + / \ + 2 6 + + preorder:[10, 5, 2, 6, 12] +``` + +如这个例子,我们先设一个最小值min_num,然后遍历数组,如果当前值小于这个最小值min_num,返回false,对于根节点,我们将其压入栈中,然后往后遍历,如果遇到的数字比栈顶元素小,说明是其左子树的点,继续压入栈中,直到遇到的数字比栈顶元素大,那么就是右边的值了,我们需要找到是哪个节点的右子树,所以我们更新low值并删掉栈顶元素,然后继续和下一个栈顶元素比较,如果还是大于,则继续更新low值和删掉栈顶,直到栈为空或者当前栈顶元素大于当前值停止,压入当前值,这样如果遍历完整个数组之前都没有返回false的话,最后返回true即可 + + +参考[Ethan Li 的技术专栏](https://segmentfault.com/a/1190000003874375) + +O(n) time, O(n) space +```python +class Solution(object): + def verifyPreorder(self, preorder): + """ + :type preorder: List[int] + :rtype: bool + """ + stack = [] + min_num = -1 << 31 # 初始化最小值为最小整数 + for x in preorder: + if x < min_num: # 违反最小值限定则是无效的 + return False + while stack and x > stack[-1]: # 将路径中所有小于当前的数pop出来并更新最小值 + min_num = stack.pop() + stack.append(x) # 将当前值push进去 + return True +``` + +### Follow up: +O(n) time, O(1) space + +we 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. +```python +class Solution(object): + def verifyPreorder(self, preorder): + """ + :type preorder: List[int] + :rtype: bool + """ + # stack = preorder[:i], reuse preorder as stack + min_num = -1 << 31 + i = 0 + for x in preorder: + if x < min_num: + return False + while i > 0 and x > preorder[i - 1]: + min_num = preorder[i - 1] + i -= 1 + preorder[i] = x + i += 1 + return True +``` diff --git a/docs/Algorithm/Leetcode/Python/256. Paint House.md b/docs/Algorithm/Leetcode/Python/256. Paint House.md new file mode 100644 index 00000000..21576f90 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/256. Paint House.md @@ -0,0 +1,57 @@ +### 256. Paint House + +题目: + + +难度: +Medium + + + +其实这个题目有实际意义诶,至少我的故乡?在要申请啥东西的时候就把街上的房子全刷了。 + +然后这个是相邻的房子不同色。 + + + +其实我觉得paint fense更难一点 + + + +思路: + +数组 dp\[x][3] 代表第x个房子paint r/g/b的值 + + + +AC代码 + +``` +class Solution(object): + def minCost(self, costs): + """ + :type costs: List[List[int]] + :rtype: int + """ + m = len(costs) + if m == 0 : return 0 + elif m == 1 : return min(costs[0][0], costs[0][1],costs[0][2]) + else: + n = 3 if m else 0 + dp = [[0 for i in range(3)] for j in range(m)] + + dp[0] = costs[0] + + + for i in range(1,m): + dp[i][0] = min(dp[i-1][1],dp[i-1][2]) + costs[i][0] + dp[i][1] = min(dp[i-1][0],dp[i-1][2]) + costs[i][1] + dp[i][2] = min(dp[i-1][0],dp[i-1][1]) + costs[i][2] + return min(dp[m-1][0], dp[m-1][1], dp[m-1][2]) + +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/257._binary_tree_paths.md b/docs/Algorithm/Leetcode/Python/257._binary_tree_paths.md new file mode 100644 index 00000000..c1191e27 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/257._binary_tree_paths.md @@ -0,0 +1,83 @@ +# 257. Binary Tree Paths +**难度: 简单** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/binary-tree-paths/description/ + +> 内容描述 + +``` +Given a binary tree, return all root-to-leaf paths. + +Note: A leaf is a node with no children. + +Example: + +Input: + + 1 + / \ +2 3 + \ + 5 + +Output: ["1->2->5", "1->3"] + +Explanation: All root-to-leaf paths are: 1->2->5, 1->3 +``` + +## 解题方案 + +> 思路 1 + +递归+DFS + +```python +class Solution(object): + def binaryTreePaths(self, root): + """ + :type root: TreeNode + :rtype: List[str] + """ + def helper(node, cur_path): + if not node.left and not node.right: ## 到leaf了 + res.append(cur_path+[node.val]) + return + if node.left: + helper(node.left, cur_path+[node.val]) + if node.right: + helper(node.right, cur_path+[node.val]) + + res = [] + if not root: + return res + helper(root, []) + + return ['->'.join([str(val) for val in path]) for path in res] +``` +注意一点,很多人可能看到这里有好几次cur_path+[node.val],觉得干嘛不直接写在最开头了,事实是这样做的话cur_path就已经变化了,因为要执行完if node.left才去执行if node.right,此时cur_path就不是原来的cur_path了。 + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/258_ Add_Digits.md b/docs/Algorithm/Leetcode/Python/258_ Add_Digits.md new file mode 100644 index 00000000..2fa72406 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/258_ Add_Digits.md @@ -0,0 +1,34 @@ +### 258. Add Digits + +题目: + + + +难度: + +Easy + + +思路 + +这就简单的一p了。。 + + +```python +class Solution(object): + def addDigits(self, num): + """ + :type num: int + :rtype: int + """ + while num / 10 >= 1: + tmp = 0 + while num / 10 >= 1: + tmp += num % 10 + num /= 10 + tmp += num % 10 + num = tmp + return num +``` + + diff --git a/docs/Algorithm/Leetcode/Python/261. Graph Valid Tree.md b/docs/Algorithm/Leetcode/Python/261. Graph Valid Tree.md new file mode 100644 index 00000000..1e309007 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/261. Graph Valid Tree.md @@ -0,0 +1,69 @@ +### 261. Graph Valid Tree + + + +题目: + + + + +难度 : Medium + + + +思路: + +graph 为 tree 两个条件: + +- 这个图是connected +- 没有cycle + + + +偷懒AC代码,直接在323题,Number of Connected Components in an Undirected Graph上改的AC代码: + + + +``` +class Solution(object): + def validTree(self, n, edges): + """ + :type n: int + :type edges: List[List[int]] + :rtype: bool + """ + def find(x): + if uf[x] != x: + uf[x] = find(uf[x]) + return uf[x] + + def union(x,y): + xRoot = find(x) + yRoot = find(y) + uf[xRoot] = yRoot + + uf = [i for i in range(n)] + + for node1, node2 in edges: + # cycle exists + if find(node1) == find(node2): + print 'ha ' + return False + else: + union(node1, node2) + + res = set() + for i in range(n): + res.add(find(i)) + + return len(res) == 1 +``` + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/263._ugly_number.md b/docs/Algorithm/Leetcode/Python/263._ugly_number.md new file mode 100644 index 00000000..730b0bdd --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/263._ugly_number.md @@ -0,0 +1,38 @@ +###263. Ugly Number + + + +题目: + + + +难度: +Easy + + +思路: + +因为其prime factors 只包括 2, 3, 5,所以比如如果能被2 整除, n = n / 2, 直到不能被2整除,然后同样对3,5检验,如果最终结果为1,那么就是ugly number,否则不过关 + + +注意一下边界条件,当num为0的时候,return一下False + +``` +class Solution(object): + def isUgly(self, num): + """ + :type num: int + :rtype: bool + """ + if num == 0 : return False + while num % 2 == 0: + num = num / 2 + while num % 3 == 0: + num = num / 3 + while num % 5 == 0: + num = num / 5 + if num == 1: + return True + return False +``` + diff --git a/docs/Algorithm/Leetcode/Python/264._ugly_number_ii.md b/docs/Algorithm/Leetcode/Python/264._ugly_number_ii.md new file mode 100644 index 00000000..ba1546b9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/264._ugly_number_ii.md @@ -0,0 +1,140 @@ +###264. Ugly Number II + + + +题目: + + + +难度: +Medium + + +思路: + +暴力算法一定会超时 + + + + +先看一个非常🐂的帖子,当我知道python 除了有list之外还有collections就已经被刷新了一次了,然后数据结构 x 数据结构,就展示了数据结构的魅力 + + + + +看一下deque + rotate: + + +``` +import collections +a = collections.deque() +a.append(2) +a.append(5) +a.append(7) +a.append(9) #a deque([2, 5, 7, 9]) + +import bisect +idx = bisect.bisect_left(a,3) #1 +a.rotate(-idx) #deque([5, 7, 9, 2]) + +a.appendleft(3) #deque([3, 5, 7, 9, 2]) + +a.rotate(idx) # deque([2, 3, 5, 7, 9]) +``` + +这个rotate -是往左边rotate,看官网的介绍. + +>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()). + +所以这样造成可以🐂的数据结构 + +用这个微调之后的fasttable来解决问题 + + +``` +import collections +import bisect + +class FastTable: + + def __init__(self): + self.__deque = collections.deque() + + def __len__(self): + return len(self.__deque) + + def head(self): + return self.__deque.popleft() + + def tail(self): + return self.__deque.pop() + + def peek(self): + return self.__deque[-1] + + def insert(self, obj): + if obj in self.__deque: + return + index = bisect.bisect_left(self.__deque, obj) + self.__deque.rotate(-index) + self.__deque.appendleft(obj) + self.__deque.rotate(index) + +class Solution(object): + + def nthUglyNumber(self, n): + """ + :type n: int + :rtype: int + """ + q = FastTable() + q.insert(1) + while n > 0: + x = q.head() + q.insert(2*x) + q.insert(3*x) + q.insert(5*x) + n -= 1 + return x +``` + + +还可以优化: +根据页面hint 来做的 + + +``` +class Solution(object): + def nthUglyNumber(self, n): + """ + :type n: int + :rtype: int + """ + if n == 1: + return 1 + else: + import collections + q2 = collections.deque() + q3 = collections.deque() + q5 = collections.deque() + q2.append(2) + q3.append(3) + q5.append(5) + while n > 1: + x = min(q2[0],q3[0],q5[0]) + if x == q2[0]: + x = q2.popleft() + q2.append(2*x) + q3.append(3*x) + q5.append(5*x) + elif x == q3[0]: + x = q3.popleft() + q3.append(3*x) + q5.append(5*x) + else: + x = q5.popleft() + q5.append(5*x) + n -= 1 + return x +``` + diff --git a/docs/Algorithm/Leetcode/Python/265. Paint House II.md b/docs/Algorithm/Leetcode/Python/265. Paint House II.md new file mode 100644 index 00000000..c9dfbc20 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/265. Paint House II.md @@ -0,0 +1,60 @@ +### 265. Paint House II + + + +题目: + + +难度: + +Hard + + + +思路: + +感觉不像hard 题,知道为啥hard了,因为can you solve it in O(nk) runtime + +数组 dp\[x][k] 代表第x个房子paint 0..k的值 + + + +用paint house 1 改的AC代码: + +不过这个时间复杂度是O(nkk)吧 + + + +``` +class Solution(object): + def minCostII(self, costs): + """ + :type costs: List[List[int]] + :rtype: int + """ + n = len(costs) + if n == 0 : return 0 + elif n == 1 : return min (costs[0]) + else: + k = len(costs[0]) if n else 0 + dp = [[0 for i in range(k)] for j in range(n)] + + dp[0] = costs[0] + + for i in range(1,n): + for j in range(0,k): + minVal = float('inf') + for m in range(0,k): + if m != j and dp[i-1][m] < minVal: + minVal = dp[i-1][m] + dp[i][j] = minVal + costs[i][j] + + return min(dp[-1]) +``` + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/266. Palindrome Permutation.md b/docs/Algorithm/Leetcode/Python/266. Palindrome Permutation.md new file mode 100644 index 00000000..49f78bd0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/266. Palindrome Permutation.md @@ -0,0 +1,46 @@ +### 266. Palindrome Permutation + + + +题目: + + +难度 : Easy + + + +思路: + +hint 已经提示的很明显。数单字个数来处理 + + + +AC代码 + + + +``` +class Solution(object): + def canPermutePalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + lookup = {} + + for char in s: + lookup[char] = lookup.get(char,0) + 1 + + res = 0 + + for char, cnt in lookup.items(): + if cnt % 2 == 0 : + continue + else: + res += 1 + + return res < 2 +``` + +​ + diff --git a/docs/Algorithm/Leetcode/Python/267. Palindrome Permutation II.md b/docs/Algorithm/Leetcode/Python/267. Palindrome Permutation II.md new file mode 100644 index 00000000..5243954e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/267. Palindrome Permutation II.md @@ -0,0 +1,77 @@ +### 267. Palindrome Permutation II + + + + + +题目: + + + + +难度 : Medium + + + +思路: + +首先这个题目有个简单版本,那就是判断是否可以permutate 为 palindrome. 问题的关键是最多只能一个odd character. + + + +写的这么不elegant,我也是服气! + +AC代码: + + + +``` +class Solution(object): + def generatePalindromes(self, s): + """ + :type s: str + :rtype: List[str] + """ + def permuteUnique(firstS): + if len(firstS) == 0 : return [] + if len(firstS) == 1 : return [firstS] + res = [] + for i in range(len(firstS)): + if i > 0 and firstS[i] == firstS[i-1]: continue + for j in permuteUnique(firstS[:i] + firstS[i+1:]): + res.append([firstS[i]] + j) + return res + + lookup = {} + for char in s: + lookup[char] = lookup.get(char, 0) + 1 + + res, firstS, oddChar = 0, [], '' + for char, cnt in lookup.items(): + if cnt % 2 == 0: + for i in range(cnt/2): + firstS.append(char) + continue + else: + for i in range(cnt / 2): + firstS.append(char) + oddChar = char + res += 1 + if res >= 2: + return [] + else: + res = permuteUnique(firstS) + if len(res) == 0 and oddChar: + return [oddChar] + return map(lambda x: ''.join(x) + oddChar + ''.join(x[::-1]),res) + +``` + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/268._missing_number.md b/docs/Algorithm/Leetcode/Python/268._missing_number.md new file mode 100644 index 00000000..fbd54da5 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/268._missing_number.md @@ -0,0 +1,49 @@ +### 268. Missing Number + +题目: + + + +难度: + +Medium + + + +等差数列前n项和减去数组之和,一行瞬秒 +```(注意题目input从0开始取值)``` + + +```python +class Solution(object): + def missingNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return len(nums) * (len(nums) + 1) / 2 - sum(nums) +``` + + + +第二种解法是位运算:位运算(异或运算) + + + +```python +class Solution(object): + def missingNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + res = n = len(nums) + for i in range(n): + res ^= i + res ^= nums[i] + return res +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/270._Closest_Binary_Search_Tree_Value.md b/docs/Algorithm/Leetcode/Python/270._Closest_Binary_Search_Tree_Value.md new file mode 100644 index 00000000..c7f7bff8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/270._Closest_Binary_Search_Tree_Value.md @@ -0,0 +1,113 @@ +# 270. Closest Binary Search Tree Value +**难度: 简单** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/closest-binary-search-tree-value/description/ + +> 内容描述 + +``` +Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target. + +Note: + +Given target value is a floating point. +You are guaranteed to have only one unique value in the BST that is closest to the target. +Example: + +Input: root = [4,2,5,1,3], target = 3.714286 + + 4 + / \ + 2 5 + / \ +1 3 + +Output: 4 +``` + +## 解题方案 + +> 思路 1 + +来个中序遍历,再判断哪个最close + +```python +class Solution(object): + def closestValue(self, root, target): + """ + :type root: TreeNode + :type target: float + :rtype: int + """ + res, diff = [], [] + self.inorder(root, res) + + for i in res: + diff.append(abs(i-target)) + return res[diff.index(min(diff))] + + def inorder(self, root, res): + if not root: + return + self.inorder(root.left, res) + res.append(root.val) + self.inorder(root.right, res) +``` + +> 思路 2 + +或者可以用更节省空间的方式,只保留一个closet,不断比较 + +```python +class Solution(object): + def closestValue(self, root, target): + """ + :type root: TreeNode + :type target: float + :rtype: int + """ + lst = [] + + def inorder(root): + if root: + inorder(root.left) + lst.append(root.val) + inorder(root.right) + + inorder(root) + + close = lst[0] + diff = abs(target - lst[0]) + + for i in lst: + if abs(target - i) < diff: + close = i + diff = abs(target - i ) + + return close +``` + +> 思路 3 + +AC代码,跟binary search tree 寻值一样, loop 一遍树来寻找 + +```python +class Solution(object): + def closestValue(self, root, target): + """ + :type root: TreeNode + :type target: float + :rtype: int + """ + close = root.val + + while root: + close = root.val if abs(target - root.val) < abs(target - close) else close + root = root.right if root.val < target else root.left + return close +``` + diff --git a/docs/Algorithm/Leetcode/Python/276. Paint Fence.md b/docs/Algorithm/Leetcode/Python/276. Paint Fence.md new file mode 100644 index 00000000..3b7373ed --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/276. Paint Fence.md @@ -0,0 +1,65 @@ +### 276. Paint Fence + +题目: + + +难度: +Easy + +思路: + +先解释一下题目意思: fence 栅栏, post 柱子 , no more than two adjacent fence posts have the same color.(一开始看漏,没有看到more than,以为相邻就不能同色)。 + +本来想画格子找规律,结果走偏了,所以老老实实写递推关系式,貌似是这样的 + +- n = 0 : 全为0 +- n = 1 : 有 k种方式 +- n = 2 :有 k * k 种 +- 否则,第n个有两种可能, 跟 n-1 颜色不一样, 跟 n-1 颜色一样, fn = (k-1)fn-1 + (k-1) fn-2 + + + +画一下表:对一下递推关系式,正确✅ + + + +``` + n + 0 1 2 3 4 + 0 0 0 0 0 0 +t 1 0 1 1 0 0 + 2 0 2 4 6 10 + 3 0 3 9 24 . + 4 0 4 16 60 . +``` + + + +AC 代码 + +``` +class Solution(object): + def numWays(self, n, k): + """ + :type n: int + :type k: int + :rtype: int + """ + if n == 0: + return 0 + else: + if k == 0: return 0 + elif n == 1: return k + elif n == 2 : return k * k + else: + dp = [0 for i in range(n+1)] + dp[0] = 0 + dp[1] = k + dp[2] = k * k + + for i in range(3,n+1): + dp[i] = (k-1) * dp [i-1] + (k-1) * dp [i-2] + return dp[-1] + +``` + diff --git a/docs/Algorithm/Leetcode/Python/277. Find the Celebrity.md b/docs/Algorithm/Leetcode/Python/277. Find the Celebrity.md new file mode 100644 index 00000000..e6bc0312 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/277. Find the Celebrity.md @@ -0,0 +1,65 @@ +### 277. Find the Celebrity + + + +题目: + + + + +难度 : Medium + + + +思路: + +算法考试考过 + +celebrity 是 每个人都知道他,而他不认识任何别的人。 + + + +如果用图来看,那就每个别的人都有箭头指向c,而c没有任何出去的箭头。 + +O(N^2)的代码还是还是很容易想到的 + +但是我们可以有提升,那么就是可以check `knows(a,b)`,如果 a knows b,那么可以排除a是celebrity,否则可以排除b是celebrity. + +最后还要确认一遍是否这个是真的celebrity + + + +AC代码 + +``` +# The knows API is already defined for you. +# @param a, person a +# @param b, person b +# @return a boolean, whether a knows b +# def knows(a, b): + +class Solution(object): + def findCelebrity(self, n): + """ + :type n: int + :rtype: int + """ + if n == 0: + return -1 + c = 0 + for i in xrange(1,n): + if not knows(i, c): + c = i + for i in range(n): + if c != i: + if not knows(i,c) or knows(c,i): + return -1 + return c + + +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/278._First_Bad _Version.md b/docs/Algorithm/Leetcode/Python/278._First_Bad _Version.md new file mode 100644 index 00000000..7c6d9424 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/278._First_Bad _Version.md @@ -0,0 +1,40 @@ +### 278. First Bad Version + + + + + +题目: + + + + +难度 : Easy + + + +思路: + +根据 search for a range 改的 + + + +```python +class Solution(object): + def firstBadVersion(self, n): + """ + :type n: int + :rtype: int + """ + l, r = 0, n - 1 + while l <= r: + mid = l + ((r - l) >> 2) + if not isBadVersion(mid): + l = mid + 1 + else: + r = mid - 1 + return l +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/279._perfect_squares.md b/docs/Algorithm/Leetcode/Python/279._perfect_squares.md new file mode 100644 index 00000000..f4d8bd50 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/279._perfect_squares.md @@ -0,0 +1,116 @@ + +### 279. Perfect Squares + + +题目: + + + +难度: + +Medium + +### 思路一: +DP, 状态转移方程: + +```dp[i] = min(dp[i], dp[i - j * j] + 1)``` + + + + +```python +class Solution(object): + def numSquares(self, n): + """ + :type n: int + :rtype: int + """ + dp = [0] * (n+1) + for i in range(n+1): + dp[i] = i + j = 1 + while j * j <= i: + dp[i] = min(dp[i], dp[i-j*j] + 1) + j += 1 + return dp[-1] +``` +但是这个方法贼慢,beats 12%, 有时候提交甚至会超时,有时候又不会。。。。因此想别的办法 + +### 思路二: + +Static DP, beats 90.39% + +```python +class Solution(object): + dp = [0] + def numSquares(self, n): + """ + :type n: int + :rtype: int + """ + while len(self.dp) <= n: + m = len(self.dp) + inf = float('inf') + i = 1 + while i * i <= m: + inf = min(inf, self.dp[m-i*i] + 1) + i += 1 + self.dp.append(inf) + return self.dp[n] +``` + +进一步简化可以写成: +```python +class Solution(object): + dp = [0] + def numSquares(self, n): + """ + :type n: int + :rtype: int + """ + while len(self.dp) <= n: + self.dp += min(self.dp[-j*j] + 1 for j in range(1, int(len(self.dp)**0.5+1))), + return self.dp[n] +``` +这里有个问题现在还没搞明白,以后再好好想一下,写成```return self.dp[-1]```提交就失败, +``` +Submission Result: Wrong Answer +Input: 1024 +Output: 4 +Expected: 1 +``` + +### 思路三: + +还是慢,有个数学方法, runtime beats 98.48% +```python +import math +class Solution(object): + def numSquares(self, n): + """ + :type n: int + :rtype: int + """ + def isSquare(num): + tmp = int(math.sqrt(num)) + return tmp * tmp == num + while n & 3 == 0: # n % 4 == 0 + n >>= 2 + if n & 7 == 7: # n % 8 == 7 + return 4 + if isSquare(n): + return 1 + sqrt_n = int(math.sqrt(n)) + for i in range(1, sqrt_n + 1): + if isSquare(n-i*i): + return 2 + return 3 +``` +in order to understand, I suggest u read: + +here is the [Lagrange's Four Square theorem](https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem +) - Limit the result to <= 4: + +And 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: + + diff --git a/docs/Algorithm/Leetcode/Python/280._Wiggle_Sort.md b/docs/Algorithm/Leetcode/Python/280._Wiggle_Sort.md new file mode 100644 index 00000000..3188ca40 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/280._Wiggle_Sort.md @@ -0,0 +1,78 @@ +### 280. Wiggle Sort + + + + + +题目: + + + + +难度 : Medium + + + +思路: + + + +想的是比如bubble sort或者任何简单的比较sort,只是放数字的时候是按这样的大小顺序放: + +1, n, 2, n-1,3, n-2…. + +或者每个pass其实做两个sort,找出最大的和最小的。然后分别放在头尾。 + + + +这样的写法TLE: + +``` +class Solution(object): +    def wiggleSort(self, nums): # 此法超时 +        """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + n = len(nums) + for i in range(n): + # small bubble sort + if i % 2 == 0: + for j in range(n-1, i-1, -1): + if nums[j] > nums[j-1]: + nums[j], nums[j-1] = nums[j-1],nums[j] + else: + for j in range(n-1, i-1, -1): + if nums[j] < nums[j-1]: + nums[j], nums[j-1] = nums[j-1],nums[j] +``` + + + + + +但是貌似想复杂了,其实对于这个简单化,要求只有一个: + +1. 如果i是奇数,nums[i] >= nums[i - 1] +2. 如果i是偶数,nums[i] <= nums[i - 1] + +所以我们只要遍历一遍数组,把不符合的情况交换一下就行了。具体来说,如果nums[i] > nums[i - 1], 则交换以后肯定有nums[i] <= nums[i - 1]。 + + + +AC 代码 + +```python +class Solution(object): + def wiggleSort(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + for i in xrange(1, len(nums)): + if ((i % 2) and nums[i] < nums[i-1]) or ((not i % 2) and nums[i] > nums[i-1]): + nums[i], nums[i-1] = nums[i-1], nums[i] +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/283._move_zeroes.md b/docs/Algorithm/Leetcode/Python/283._move_zeroes.md new file mode 100644 index 00000000..a5e887c0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/283._move_zeroes.md @@ -0,0 +1,128 @@ +### 283. Move Zeroes + + +题目: + + + +难度: +Easy + + +思路: + +### 思路一:暴力 + +```python +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + i = 0 + while 0 in nums: + nums.remove(0) + i += 1 + nums.extend([0]*i) +``` + +### 思路二: + +一旦遇到不是0的就把它往前移动,移动非0完成,剩下的全部填0,看例子 + + + +``` +0 1 0 3 12 + +``` + +也算双指针吧, +首先cur = 0, idx = 0,为0,不变,然后idx = 1,不为0,前移,数组变成 + +``` +1 1 0 3 12 +``` + +继续idx 这个时候是2,不变,继续处理,碰到3可以变成 + +``` +1 3 0 3 12 +``` +这样知道变换完成,简直逆天啊,因为cur 总是小于idx,所以总可以保持这样的稳定性 + + +```python +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + cur,idx = 0,0 + while idx < len(nums): + # cur is not 0 + if nums[idx] != 0 : + nums[cur] = nums[idx] + cur += 1 + idx += 1 + + while cur < len(nums): + nums[cur] = 0 + cur += 1 + +``` + + +### 思路三: + +传统的双指针,参考这里 + + + +```此法最快,beats 90.50%``` + +```python +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ +        p0, p1 = 0, 0 # P1指向非0,p0指向0 +        while p0 < len(nums) and p1 < len(nums): + if nums[p0] != 0: + p0 += 1 + p1 = p0 + continue + if nums[p1] == 0: + p1 += 1 + continue + nums[p0],nums[p1] = nums[p1],nums[p0] + p0 += 1 + p1 += 1 +``` + +相反,我觉得这样双指针反而没有上面的代码容易理解 + +### 思路四: + +一个比较巧妙的方法: +```python +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + nums.sort(key= lambda x: 1 if x == 0 else 0) +``` +原理就是原先为0的数优先级在此次sort中更高了,所以全部升序排列排到后面去了 + +但是这个解法被人说是没有满足题目```no extra space```的条件,详见[Sayo](https://leetcode.com/problems/move-zeroes/discuss/72074/) +``` +timsort 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. +``` + + diff --git a/docs/Algorithm/Leetcode/Python/285._inorder_successor_in_bst.md b/docs/Algorithm/Leetcode/Python/285._inorder_successor_in_bst.md new file mode 100644 index 00000000..aafca56c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/285._inorder_successor_in_bst.md @@ -0,0 +1,115 @@ +# 285. Inorder Successor in BST + +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/inorder-successor-in-bst/description/ + +> 内容描述 + +``` + +Given a binary search tree and a node in it, find the in-order successor of that node in the BST. + +Note: If the given node has no in-order successor in the tree, return null. + +Example 1: + +Input: root = [2,1,3], p = 1 + + 2 + / \ +1 3 + +Output: 2 +Example 2: + +Input: root = [5,3,6,2,4,null,null,1], p = 6 + + 5 + / \ + 3 6 + / \ + 2 4 + / +1 + +Output: null +``` + +## 解题方案 + +> 思路 1 + +首先可以去看一下[二叉树的一些操作](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) + +BST的特性,对于一个node,它的所有左侧node都比它小,它的所有右侧node都比它大。最小的元素在最左边,最大的元素在最右边。 + +一个node x它的successor y 是满足y > x的最小值。两种情况,如果node x有right child,那么这个right child 中的最小值就是它的successor,否则就要往上走,如果走上去的parent使得这个node是其左边的孩子的话,那么successor我们也找到了。 + + +因为状况可能是这样的: + +``` + 3 + / + 1 + / \ + 0 2 +``` + +如果是寻找0的successor,那么我们往上一走,发现0的祖先是1,并且0是1的左孩子,找到,否则如果寻找2的successor,那么我们要往上走到3的部分,2是3的左subtree,这样才能解决问题。 + +伪码 + +``` +function Succ(x) + if Right(x) ̸= NIL then + return Min(Right(x)) + else + p ← Parent(x) + while p ̸= NIL and x = Right(p) do + x←p + p ← Parent(p) + return p +``` + +这里伪码有点不适用是因为我们并没有这个parent指针,当然我们还是有trick方式的,就是我们从root开始走,直到找到这个node p,同时我们记录一路上看到的比p.val大的值,这样最后一个就是它的successor.其中最低的那一个就是他的successor. + + + +```python +class Solution(object): + def inorderSuccessor(self, root, p): + """ + :type root: TreeNode + :type p: TreeNode + :rtype: TreeNode + """ + def minNode(node): + while node.left: + node = node.left + return node + + def searchP(root, p): + if not root or root.val == p.val: + return None + else: + succ = None + while root != None and p.val != root.val: + if p.val < root.val: + succ = root + root = root.left + else: + root = root.right + return succ + + if p.right: + return minNode(p.right) + else: + return searchP(root, p) +``` + diff --git a/docs/Algorithm/Leetcode/Python/286. Walls and Gates.md b/docs/Algorithm/Leetcode/Python/286. Walls and Gates.md new file mode 100644 index 00000000..8a23c268 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/286. Walls and Gates.md @@ -0,0 +1,90 @@ +### 286. Walls and Gates + + + +题目: +https://leetcode.com/problems/walls-and-gates/ + + + +难度 : Medium + + + +思路: + +乍一看feel like all pairs shortest path. + +naive的想法是针对所有为0的点做all pairs shortest path,然后最终得到的就是把INF替换保留最小的。时间复杂度是0的个数* BFS + + + +naive的想法AC + +``` +class Solution(object): + def wallsAndGates(self, rooms): + """ + :type rooms: List[List[int]] + :rtype: void Do not return anything, modify rooms in-place instead. + """ + def legal(x,y): + return x >= 0 and x < row and y >= 0 and y < col and rooms[x][y] != -1 + + def bfs(rooms, i, j): + queue = [] + queue.append((i,j)) + + while queue: + (x,y) = queue.pop() + + if legal(x-1,y) and rooms[x-1][y] > rooms[x][y] + 1: + rooms[x-1][y] = rooms[x][y] + 1 + queue.append((x-1,y)) + if legal(x+1,y) and rooms[x+1][y] > rooms[x][y] + 1 : + rooms[x+1][y] = rooms[x][y] + 1 + queue.append((x+1,y)) + if legal(x,y-1) and rooms[x][y-1] > rooms[x][y] + 1: + rooms[x][y-1] = rooms[x][y] + 1 + queue.append((x,y-1)) + if legal(x,y+1) and rooms[x][y+1] > rooms[x][y] + 1 : + rooms[x][y+1] = rooms[x][y] + 1 + queue.append((x,y+1)) + + + row = len(rooms) + col = len(rooms[0]) if row else 0 + + for i in range(row): + for j in range(col): + if rooms[i][j] == 0: + bfs(rooms,i,j) +``` + + + +复习一下BFS的伪码 + +from wikipedia, 一开始有点小迷茫,那就是为什么没有keep一个visited的数据结构,但是随即反应过来,其实`n.distance == INFINITY` 已经是check它是否被visited 过了,我以上的代码并没有做这个操作,但是因为是格子状以及我仅在检查是否更小,所以也能AC. + +``` +Breadth-First-Search(Graph, root): + + for each node n in Graph: + n.distance = INFINITY + n.parent = NIL + + create empty queue Q + + root.distance = 0 + Q.enqueue(root) + + while Q is not empty: + current = Q.dequeue() + for each node n that is adjacent to current: + if n.distance == INFINITY: + n.distance = current.distance + 1 + n.parent = current + Q.enqueue(n) +``` + diff --git a/docs/Algorithm/Leetcode/Python/287._Find_the_Duplicate_Number.ipynb b/docs/Algorithm/Leetcode/Python/287._Find_the_Duplicate_Number.ipynb new file mode 100644 index 00000000..62e7895d --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/287._Find_the_Duplicate_Number.ipynb @@ -0,0 +1,244 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 287.Find the Duplicate Number 找到重复的数\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/find-the-duplicate-number/description/\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", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "class 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", + " \n", + "s = Solution()\n", + "nums = [1,2,3,3]\n", + "print(s.findDuplicate(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "思路 1 的解法是时间复杂度为 $O(nlogn)$ 的解法,思路 2 则是时间复杂度为 $O(n)$ ,但是相对来说,是投机取巧了些。\n", + "> 思路 2\n", + "\n", + "一次遍历统计,另一次遍历输出即可。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "class 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", + "\n", + "s = Solution()\n", + "nums = [1,2,3,3]\n", + "print(s.findDuplicate(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3 \n", + "\n", + "思路 3 则是更加完整的 $O(n)$ 的解法,现在我还没有完全搞懂,我先写在下面吧,大佬们可以提前学习了解。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "class 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", + " \n", + "s = Solution()\n", + "nums = [1,2,3,3]\n", + "print(s.findDuplicate(nums))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/Python/289._game_of_life.md b/docs/Algorithm/Leetcode/Python/289._game_of_life.md new file mode 100644 index 00000000..097ffc3e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/289._game_of_life.md @@ -0,0 +1,111 @@ +### 289. Game of Life + +题目: + + + +难度 : Medium + + +直接一上来就没有考虑solve it in-place,考虑的是便利,简直是born for 便利 + +首先我把board拓宽了,宽,高各增加了两排。 + +因为这样求neighbor方便,针对原来的borad,现在新的big 对于 1 -> n-1 的部分 + +全都有八个neighbor,用了一个2d array来记录nbrs,再根据当下的nbr来判断更新,因为不能一边在board上loop一边更新. + +AC的效率还ok: + +```python +class Solution(object): + def gameOfLife(self, board): + """ + :type board: List[List[int]] + :rtype: void Do not return anything, modify board in-place instead. + """ + def liveNeighbors(i,j): + 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] + + if board == [[]] : return + row = len(board) + col = len(board[0]) + + nbrs = [[0 for j in range(col)] for i in range(row)] + big = [[ 0 for j in range(col+2) ] for i in range(row+2)] + for i in range(1,row+1): + for j in range(1,col+1): + big[i][j] = board[i-1][j-1] + + for i in range(1,row+1): + for j in range(1,col+1): + nbrs[i-1][j-1] = liveNeighbors(i,j) + + for i in range(row): + for j in range(col): + if board[i][j] == 1: + if nbrs[i][j] < 2: + board[i][j] = 0 + elif nbrs[i][j] == 2 or nbrs[i][j] == 3: + board[i][j] = 1 + else: + board[i][j] = 0 + else: + if nbrs[i][j] == 3: + board[i][j] = 1 + +``` + +谷歌了一下,大家都用到了temp 2d array嘛,哼(ˉ(∞)ˉ)唧。好吧,空间复杂度比我小。 + + + +很多的解法都是一样开了一个二维数组,即使没有像我一样扩展board.因为问题在于不能一边更新board 一边来做。 + +看了一下这边的思路: + + + + + + + +不开数组 + +我们可以使用状态机转换 o(╯□╰)o 感觉不知道在听什么 还是很迷茫的感觉, in-place AC代码 + +```python +class Solution(object): + def gameOfLife(self, board): + """ + :type board: List[List[int]] + :rtype: void Do not return anything, modify board in-place instead. + """ + row = len(board) + col = len(board[0]) if row else 0 + + dx = [-1,-1,-1,0,1,1,1,0] + dy = [-1,0,1,1,1,0,-1,-1] + + for i in range(row): + for j in range(col): + cnt = 0 + for k in range(8): + x, y = i + dx[k], j + dy[k] + if x >=0 and x < row and y >=0 and y < col and (board[x][y] == 1 or board[x][y] == 2): + cnt += 1 + + if board[i][j] and (cnt < 2 or cnt > 3): + board[i][j] = 2 + elif board[i][j] == 0 and cnt == 3: + board[i][j] = 3 + + for i in range(row): + for j in range(col): + board[i][j] %= 2 + + +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/290._word_pattern.md b/docs/Algorithm/Leetcode/Python/290._word_pattern.md new file mode 100644 index 00000000..e6122ec8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/290._word_pattern.md @@ -0,0 +1,42 @@ +###290. Word Pattern + +题目: + + + +难度 : Easy + +4.pattern = "abba", str = "dog dog dog dog" should return false. + +因为这个的限制,所以中间加了一个loop用来查询是否这个a对应的已经出现过了。 + +不过其实也可以用两个dictionary来处理,可以O(n^3) -> O(n^2) + + +``` +class Solution(object): + def wordPattern(self, pattern, str): + """ + :type pattern: str + :type str: str + :rtype: bool + """ + strList = str.split(' ') + if len(pattern) != len(strList): + return False + lookup = {} + for i in range(len(strList)): + if pattern[i] not in lookup: + for key in lookup: + if lookup[key] == strList[i]: + return False + lookup[pattern[i]] = strList[i] + elif lookup[pattern[i]] != strList[i]: + return False + + return True + +``` + + +另外看到一段非常简短代码,使用了map函数,有待学习 diff --git a/docs/Algorithm/Leetcode/Python/292._nim_game.md b/docs/Algorithm/Leetcode/Python/292._nim_game.md new file mode 100644 index 00000000..9f78914f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/292._nim_game.md @@ -0,0 +1,55 @@ +### 292. Nim Game + +题目: + + + + +难度: + +Easy + + +对于总是优先开始的那方 + + +- 有一到三块,总是赢 +- 有四块,总是输 +- 有五块,总是赢 + +所以如果自己想赢,总是要迫使对方拿之后,给自己遗留5块,或者三块以及以下。 + +- 如果是六块: + - 拿一块,对方五块,对方赢 + - 拿两块,对方余下四块,我方赢 + - 拿三块,余三块,对方赢 + +- 七块: + - 拿三块,余四块,迫使对方输,总是赢 + +本打算用递归来看,因为对方也可以重复使用这个函数,但是会超时,所以就看了一下hint + + +- n <= 3 能赢 √ +- n == 4 总输 +- n = 5,6,7 总赢 +- n == 8, 先手如何选,总可以转成5,6,7 对方总会赢 + + +所以 n % 4 == 0 时候,先手必输 + +简直是啊,有些游戏就是这样来必赢的啊,没想到你是这样的题目 + + + +``` +class Solution(object): + def canWinNim(self, n): + """ + :type n: int + :rtype: bool + """ + return n % 4 != 0 +``` + + diff --git a/docs/Algorithm/Leetcode/Python/293._Flip_Game.md b/docs/Algorithm/Leetcode/Python/293._Flip_Game.md new file mode 100644 index 00000000..14f5226a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/293._Flip_Game.md @@ -0,0 +1,34 @@ +### 293. Flip Game + +题目: + + + +难度: + +Easy + + +思路 + + + + +```python +class Solution(object): + def generatePossibleNextMoves(self, s): + """ + :type s: str + :rtype: List[str] + """ + res = [] + if not s or len(s) <= 1: + return res + for i in range(len(s)-1): + if s[i] == '+' and s[i+1] == '+': + res.append(s[:i]+'--'+s[i+2:]) + return res +``` + +这里要注意一个点:s[i+2:] 虽然i+2取不到,但是s[i+2:]就是一个空字符串。 + diff --git a/docs/Algorithm/Leetcode/Python/296. Best Meeting Point.md b/docs/Algorithm/Leetcode/Python/296. Best Meeting Point.md new file mode 100644 index 00000000..5f141f6a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/296. Best Meeting Point.md @@ -0,0 +1,67 @@ +### 296. Best Meeting Point + +题目: + + + + +难度 : Hard + + + +思路: + +提示是先从一维开始,其实一开始是略迷茫的,因为如果两个点,那么只要在这两个之间,一定就是最小值,线段长度。 + +不过倘若点增加到三个,那么就是第三个点处。 + + + +然后发现了一个很棒的stackoverflow page + + + + + +因为一开始理解错误二维数组的输入,以为是给的locs这样的数组,所以直接这样写了,然后发现给的是格子,所以但是还是偷懒这样写了。 + + + +AC 代码 + +``` +class Solution(object): + def minTotalDistance(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + res = 0 + locs = [] + + m = len(grid) + n = len(grid[0]) if m else 0 + + for i in range(m): + for j in range(n): + if grid[i][j] == 1: + locs.append([i,j]) + + + locs.sort(key = lambda point: point[0]) + x = locs[len(locs)/2][0] + for point in locs: + res += abs(point[0] - x) + + locs.sort(key = lambda point: point[1]) + y = locs[len(locs)/2][1] + for point in locs: + res += abs(point[1] - y) + + return res +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/298. Binary Tree Longest Consecutive Sequence.md b/docs/Algorithm/Leetcode/Python/298. Binary Tree Longest Consecutive Sequence.md new file mode 100644 index 00000000..4c6bc841 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/298. Binary Tree Longest Consecutive Sequence.md @@ -0,0 +1,123 @@ +### 298. Binary Tree Longest Consecutive Sequence + + + + + +题目: +https://leetcode.com/problems/binary-tree-longest-consecutive-sequence/ + + + +难度 : Medium + + + +思路: + + + +TLE代码,每个node求,然后求最大值 + +``` +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def longestConsecutive(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def consecutive(root): + if root == None: + return 0 + else: + left, right = 0,0 + if root.left: + if root.left.val == root.val + 1: + left = 1 + consecutive(root.left) + if root.right: + if root.right.val == root.val + 1: + right = 1 + consecutive(root.right) + return max(left, right, 1) + + def dfs(root): + s = [] + s.append(root) + while s: + root = s.pop() + res.append(consecutive(root)) + if root.left: + s.append(root.left) + if root.right: + s.append(root.right) + if not root: + return 0 + + res = [] + dfs(root) + return max(res) + +``` + + + + + +其实第二次递归,也就是dfs其实是有点多余的?因为可以边走边保存最大值? + +因为可以 + +> - recursion,在参数中包含当前的连续seq长度 +> - 如果left, right child的value是连续的,那么就将长度+1传入下一个call + + + + + +AC代码 + +``` +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def longestConsecutive(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def dfs(root, curLen): + self.result = max(curLen, self.result) + if root.left: + if root.left.val == root.val + 1: + dfs(root.left, curLen + 1) + else: + dfs(root.left, 1) + if root.right: + if root.right.val == root.val + 1: + dfs(root.right, curLen + 1) + else: + dfs(root.right,1) + + if not root: return 0 + + self.result = 0 + dfs(root, 1) + return self.result + +``` + + + +这里值得注意的是这里的self.result其实相当于dfs的全局变量,也是利用了这个才做到边递归边记录边重置。 + diff --git a/docs/Algorithm/Leetcode/Python/299._bulls_and_cows.md b/docs/Algorithm/Leetcode/Python/299._bulls_and_cows.md new file mode 100644 index 00000000..8b6cbe46 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/299._bulls_and_cows.md @@ -0,0 +1,119 @@ +###299. Bulls and Cows + +题目: + + + + +难度: + +Easy + + +我花了很久时间来AC,因为想了边界条件 + + +``` +class Solution(object): + def getHint(self, secret, guess): + """ + :type secret: str + :type guess: str + :rtype: str + """ + maps = {} + for i in range(len(secret)): + if secret[i] not in maps: + maps[secret[i]] = [i] + else: + maps[secret[i]].append(i) + mapg = {} + for i in range(len(guess)): + if guess[i] not in mapg: + mapg[guess[i]] = [i] + else: + mapg[guess[i]].append(i) + + print maps, mapg + + a,b = 0,0 + for key in maps.keys(): + if key in mapg.keys(): + common = list(set(mapg[key]) & set(maps[key])) + #check for bull + a += len(common) + mapg[key] = [item for item in mapg[key] if item not in common] + maps[key] = [item for item in maps[key] if item not in common] + b += min(len(maps[key]), len(mapg[key])) + return str(a) + 'A' + str(b) + 'B' +``` + + + + + + + +两种解法都....... + +都这么短。。。。。 +我Python还是用的不行啊 + + +``` +class Solution(object): + def getHint(self, secret, guess): + """ + :type secret: str + :type guess: str + :rtype: str + """ + bull = sum(map(operator.eq, secret, guess)) + sa = collections.Counter(secret) + sb = collections.Counter(guess) + cow = sum((sa & sb).values()) - bull + return str(bull) + 'A' + str(cow) + 'B' +``` + + +bull = secret与guess下标与数值均相同的数字个数 + +cow = secret与guess中出现数字的公共部分 - bull + + + + +来分析一下这个解法 + +``` +def getHint(self, secret, guess): + bulls = sum(map(operator.eq, secret, guess)) + both = sum(min(secret.count(x), guess.count(x)) for x in '0123456789') + return '%dA%dB' % (bulls, both - bulls) +``` + +首先map的用法是,对于iterable中的每个元素应用function方法,将结果作为list返回 + +``` +>>> def add100(x): +... return x+100 +... +>>> hh = [11,22,33] +>>> map(add100,hh) +[111, 122, 133] +``` + + + + +用'1123','0111' 来测试: + + +``` +map(operator.eq, secret, guess) +[False, True, False, False] +``` +就是将equal函数并行应用在两个string上,然后后面的解法也是粗暴简约和厉害 + + +参考 diff --git a/docs/Algorithm/Leetcode/Python/300._longest_increasing_subsequence.md b/docs/Algorithm/Leetcode/Python/300._longest_increasing_subsequence.md new file mode 100644 index 00000000..9c59ae19 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/300._longest_increasing_subsequence.md @@ -0,0 +1,41 @@ +### 300. Longest Increasing Subsequence + +题目: + + + +难度: +Medium + + +思路: + +典型DP + +递推关系式: + +对于以num[i]结束的longest increasing subsequence的长度 + +dp[i] = dp[j] + 1 if num[i] > num[j] else 1 + +最后loop一圈,求出最长的 + +AC 代码 + +```python +class Solution(object): + def lengthOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums: + return 0 + dp = [1 for i in range(len(nums))] + for i in range(1, len(nums)): + for j in range(i): + if nums[i] > nums[j]: + dp[i] = max(dp[j]+1, dp[i]) + return max(dp) +``` + diff --git a/docs/Algorithm/Leetcode/Python/303._range_sum_query_-_immutable.md b/docs/Algorithm/Leetcode/Python/303._range_sum_query_-_immutable.md new file mode 100644 index 00000000..32c459ae --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/303._range_sum_query_-_immutable.md @@ -0,0 +1,47 @@ +###303. Range Sum Query - Immutable + +题目: + + + +tag : DP +难度 : Easy + + + +``` +sum(i, j) = nums[i] j = i +sum(i,j) = sum[i,j-1] + nums[j] j > i + +``` + +Python代码 + +``` + +class NumArray(object): + def __init__(self, nums): + """ + initialize your data structure here. + :type nums: List[int] + """ + self.sums = nums + for i in range(1, len(self.sums)): + self.sums[i] = self.sums[i-1] + self.sums[i] + + + + + def sumRange(self, i, j): + """ + sum of elements nums[i..j], inclusive. + :type i: int + :type j: int + :rtype: int + """ + if i == 0 : + return self.sums[j] + else : + return self.sums[j] - self.sums[i-1] + +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/316._Remove_Duplicate_Letters.md b/docs/Algorithm/Leetcode/Python/316._Remove_Duplicate_Letters.md new file mode 100644 index 00000000..cce1a8b4 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/316._Remove_Duplicate_Letters.md @@ -0,0 +1,108 @@ +### 316. Remove Duplicate Letters + +题目: + + + +难度: + +Hard + + +思路 + +这道题让我们移除重复字母,使得每个字符只能出现一次,而且结果要按最优的字母顺序排列,前提是不能打乱其原本的相对位置。 +- 先用remaining统计所有出现字母出现过的次数; +- res就是输出结果的字母顺序(list),最后用join连接起来作为返回值(str); +- 在stack(set)中的元素意味着其已经出现在最终结果中; + +对s中每个字母c,首先看它在stack中有没有出现过: +1. 如果没有那么只要res最后一个字母的ASCII值大于c,且其剩余次数大于0,就将其在res和stack中删去,不停做此操作 +2. 如果有了那么说明已经出现在最终结果中,只需要将其统计次数减去1以防后面挪动位置要做判断 + +做完这些后必须要把c加入到stack和res中去,代表c已经加入到最终结果中的目前应该处于的位置 + +参考[python的colloections之defaultdict模块](https://docs.python.org/2/library/collections.html) + +```python +class Solution(object): + def removeDuplicateLetters(self, s): + """ + :type s: str + :rtype: str + """ + remaining = collections.defaultdict(int) + for c in s: + remaining[c] += 1 + res, stack = [], set() + for c in s: + if c not in stack: + while res and res[-1] > c and remaining[res[-1]] > 0: + stack.remove(res.pop()) + res.append(c) + stack.add(c) + remaining[c] -= 1 + return ''.join(res) +``` +还有别的一些优美的解法,参考[stefan的回答](https://leetcode.com/problems/remove-duplicate-letters/discuss/76787) + + + +```python +递归贪心版本 +class Solution(object): + def removeDuplicateLetters(self, s): + """ + :type s: str + :rtype: str + """ + for c in sorted(set(s)): + suffix = s[s.index(c):] + if set(suffix) == set(s): + return c + self.removeDuplicateLetters(suffix.replace(c, '')) + return '' +``` +```python +class Solution(object): + def removeDuplicateLetters(self, s): + """ + :type s: str + :rtype: str + """ + result = '' + while s: + i = min(map(s.rindex, set(s))) + c = min(s[:i+1]) + result += c + s = s[s.index(c):].replace(c, '') + return result +``` + +```python +class Solution(object): + def removeDuplicateLetters(self, s): + """ + :type s: str + :rtype: str + """ + rindex = {c: i for i, c in enumerate(s)} + result = '' + for i, c in enumerate(s): + if c not in result: + while c < result[-1:] and i < rindex[result[-1]]: + result = result[:-1] + result += c + return result +``` + + + + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/319._Bulb_Switcher.md b/docs/Algorithm/Leetcode/Python/319._Bulb_Switcher.md new file mode 100644 index 00000000..840cce51 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/319._Bulb_Switcher.md @@ -0,0 +1,69 @@ +### 319. Bulb Switcher + +题目: + + + +难度: + +Medium + + +思路 + +bulb代表第一轮结束后的所有灯亮灭的情况,从第二轮开始 +- 如果是最后一轮,则bulb的最后一个灯要switch +- 对于其他轮,相应的第i-1+C(i)个灯要siwitch,且C为常数,i-1+C(i)必须<=n-1 + +但是发现这样提交会超时 +Last executed input: +999999 + + +``` +class Solution(object): + def bulbSwitch(self, n): + """ + :type n: int + :rtype: int + """ + bulb = [1] * n + for i in range(2,n+1): + for x in range(i-1, n, i): + bulb[x] = 1 if bulb[x] == 0 else 0 + return bulb.count(1) +``` + +原来,这是一道智商碾压题: + +> A bulb ends up on iff it is switched an odd number of times. +Bulb i is switched in round d iff d divides i. +So bulb i ends up on iff it has an odd number of >divisors. +Divisors come in pairs, like i=12 has divisors 1 and 12, 2 and 6, and 3 and 4. +Except if i is a >square, like 36 has divisors 1 and 36, 2 and 18, 3 and 12, 4 and 9, +and double divisor 6. So bulb >i ends up on iff and only if i is a square. So just count the square numbers. + +大概解释一下,当一个灯泡被执行偶数次switch操作时它是灭着的,当被执行奇数次switch操作时它是亮着的,那么这题就是要找出哪些编号的灯泡会被执行奇数次操作。 + +现在假如我们执行第i次操作,即从编号i开始对编号每次+i进行switch操作,对于这些灯来说, +如果其编号j(j=1,2,3,⋯,n)能够整除i,则编号j的灯需要执行switch操作。 +具备这样性质的i是成对出现的,比如: +- 12 = 1 * 12, +- 12 = 2 * 6 +- 12 = 3 * 4 + +所以编号为12的灯,在第1次,第12次;第2次,第6次;第3次,第4次一定会被执行Switch操作,这样的话,编号为12的灯执行偶数次switch,肯定为灭。 +这样推出,完全平方数一定是亮着的,因为它有两个相同的因子,总因子数为奇数,如36 = 6 * 6,所以本题的关键在于找完全平方数的个数。 + +```python +class Solution(object): + def bulbSwitch(self, n): + """ + type n: int + rtype: int + """ + # The number of full squares. + return int(math.sqrt(n)) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/322. Coin Change.md b/docs/Algorithm/Leetcode/Python/322. Coin Change.md new file mode 100644 index 00000000..1246fa16 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/322. Coin Change.md @@ -0,0 +1,52 @@ +### 322. Coin Change + + + +题目: + + +难度: + +Medium + +DP入门 + +递推方程式: dp[i] = min(dp[i-vj]+1), vj 是硬币的面额 + +伪码: + +``` +Set Min[i] equal to Infinity for all of i +Min[0]=0 + +For i = 1 to S + For j = 0 to N - 1 + If (Vj<=i AND Min[i-Vj]+1难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/description/ + +> 内容描述 + +``` +Given 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. + +Example 1: + +Input: n = 5 and edges = [[0, 1], [1, 2], [3, 4]] + + 0 3 + | | + 1 --- 2 4 + +Output: 2 +Example 2: + +Input: n = 5 and edges = [[0, 1], [1, 2], [2, 3], [3, 4]] + + 0 4 + | | + 1 --- 2 --- 3 + +Output: 1 +Note: +You 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. +``` + +## 解题方案 + +> 思路 1 + +经典并查集题目,可以去总结部分先看看并查集的概念已经优化 + + +```python +class Solution(object): + def countComponents(self, n, edges): + """ + :type n: int + :type edges: List[List[int]] + :rtype: int + """ + def find(x): + # if uf[x] != x: + # uf[x] = find(uf[x]) + while x != uf[x]: + uf[x] = uf[uf[x]] + x = uf[x] + return uf[x] + + def union(x, y): + x_root = find(x) + y_root = find(y) + uf[x_root] = y_root + + uf = [i for i in range(n)] + + for (node1, node2) in edges: + union(node1, node2) + + res = set([find(i) for i in range(n)]) + return len(res) +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/324._Wiggle_Sort_II.md b/docs/Algorithm/Leetcode/Python/324._Wiggle_Sort_II.md new file mode 100644 index 00000000..5ebc2594 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/324._Wiggle_Sort_II.md @@ -0,0 +1,42 @@ +### 324. Wiggle Sort II + + + +题目: + + + +难度: +Medium + +思路: + +首先这道题和[Wiggle Sort](https://github.com/Lisanaaa/thinking_in_lc/blob/master/280._Wiggle_Sort.md)要求不一样,不能有等于, +所以如果碰到一串```‘1,1,1,1,1,1’```,当调换顺序时候还是不会满足。 + +因此我们用新方法,首先将原数组排序,然后大的那一半数字降序插在奇数```index```上,小的那一半数字降序插在偶数```index```上 + + +```python +class Solution(object): + def wiggleSort(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + nums.sort() + half = len(nums[::2]) + nums[::2], nums[1::2] = nums[:half][::-1], nums[half:][::-1] +``` + + +### Follow up +O(n) time, O(1) space + +思路: +首先想到的是将我们上面的排序方法用堆排序实现即可,建堆O(n),调整堆O(lgN) + + +```python + +``` diff --git a/docs/Algorithm/Leetcode/Python/326._power_of_three.md b/docs/Algorithm/Leetcode/Python/326._power_of_three.md new file mode 100644 index 00000000..9cd035d9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/326._power_of_three.md @@ -0,0 +1,48 @@ +### 326. Power of Three + +题目: + + + + + +难度 : Easy + + +直接就上的递归 + +```python +class Solution(object): + def isPowerOfThree(self,n): + """ + :type n: int + :rtype: bool + """ + if n <= 0: + return False + if n == 1: + return True + if n % 3 == 0: + return self.isPowerOfThree(n/3) + return False + +``` + +有一个follow up,可否不用 loop/recusion + +看到了取巧的办法,因为是Given an integer,是有范围的(<2147483648),存在能输入的最大的3的幂次,即 3^19=1162261467。 + +只用检查是否能被这个数整除 + + +```python +class Solution(object): + def isPowerOfThree(self, n): + """ + :type n: int + :rtype: bool + """ + return n > 0 and pow(3, 19) % n == 0 + +``` + diff --git a/docs/Algorithm/Leetcode/Python/328._odd_even_linked_list.md b/docs/Algorithm/Leetcode/Python/328._odd_even_linked_list.md new file mode 100644 index 00000000..b628ab24 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/328._odd_even_linked_list.md @@ -0,0 +1,112 @@ +###328. Odd Even Linked List + +题目: + + + +难度: + +Medium + + +想法:因为相对顺序保持不变,所以可以拆list,然后再组合在一起?这样是满足题目要求的,因为linked list不像array,我们操作的时候只是用指向,没有分配新的空间。 + +``` + +class Solution(object): + def oddEvenList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if head == None or head.next == None or head.next.next == None: + return head + + oddDummy = ListNode(-1) + oddDummy.next = head + + evenDummy = ListNode(-1) + evenDummy.next = head.next + + oddCur = oddDummy.next + evenCur = evenDummy.next + + cur = head.next.next + while cur: + oddCur.next = cur + oddCur = oddCur.next + evenCur.next = cur.next + evenCur = evenCur.next + if cur.next: + cur = cur.next.next + else: + cur = cur.next + oddCur.next = evenDummy.next + # print oddDummy.next.val + return oddDummy.next + +``` + + + + +看别人的优雅代码 + +``` +class Solution(object): + def oddEvenList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if head == None: + return head + + # odd used to keep track of the tail of odd nodes + odd = oddHead = head + # record how many swaps happend + even = evenHead = head.next + while even and even.next: + odd.next = even.next + odd = odd.next + even.next = odd.next + even = even.next + odd.next = evenHead + return head +``` + +intuitive and concise + + +``` +1 → 2 → 3 → 4 → 5 → NULL + +一开始 + + 1 → 2 → 3 → 4 → 5 → NULL +odd even even.next + + +1 → 3 → 4 → 5 → NULL + odd ↑ + 2 - + + +1 → 3 → 4 → 5 → NULL + odd + 2 - even + + +再loop一次: + + | ----------- + | --------- ↓ ↓ +1 → 3 4 5 → NULL + odd ↑ + 2 - ↑ even + + +最后一步,再将两个odd的最后一个和evenHead连接起来,完工 +``` + + diff --git a/docs/Algorithm/Leetcode/Python/334._increasing_triplet_subsequence.md b/docs/Algorithm/Leetcode/Python/334._increasing_triplet_subsequence.md new file mode 100644 index 00000000..e5e4c645 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/334._increasing_triplet_subsequence.md @@ -0,0 +1,71 @@ +###334. Increasing Triplet Subsequence + +题目: + + + +难度: +Medium + + +思路: + +用longest increasing subsequence来求,超时 + +``` +class Solution(object): + def increasingTriplet(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + if not nums: return False + n = len(nums) + dp = [1 for i in range(n)] + for i in range(1,n): + for j in range(i): + if nums[i] > nums[j] : + dp[i] = max(dp[i],dp[j] + 1) + if dp[i] >= 3: + return True + + return False +``` + +于是转而用Third Maximum Number的方法,维护一个当前最小和当前第二小,当碰到当前比较大,返回True,否则一圈走下来依旧不能满足,返回false. + +想一下,如果不是求三个增长,如果是求两个的话,那么一定想到的是保存当前最小值,那么一旦后方遇到一个比较大的,就这样处理掉了。 + +所以对于任何一个num来说,有三种可能: + +- 小于当前的最小值,那么更新当前最小值 +- 小于当前第二小值,更新当前第二小值 +- 如果以上两种都不是,那么是大于当前第二小值和最小值,于是这样就true + +所以是求四个增长也是类似的么 + +AC代码 + +``` +class Solution(object): + def increasingTriplet(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + # m - min, sm - second min + m, sm = float('inf'), float('inf') + + for num in nums: + print m, sm + if m >= num: + m = num + elif sm >= num: + sm = num + else: + return True + return False +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/337._house_robber_iii.md b/docs/Algorithm/Leetcode/Python/337._house_robber_iii.md new file mode 100644 index 00000000..a081ba01 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/337._house_robber_iii.md @@ -0,0 +1,47 @@ +###337. House Robber III + + +题目: + + + +难度: +Medium + +思路: + +参考 + + +这个解法好像有点厉害 + +从root开始抢起来,最大能抢到的两个可能: 抢root和不抢root + +- rob_root = max(rob_L + rob_R , no_rob_L + no_nob_R + root.val) +- no_rob_root = rob_L + rob_R + + +这个递归写起来就很厉害了 + + +``` +class Solution(object): + def rob(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def dfs(root): + if not root: return 0, 0 + rob_L, no_rob_L = dfs(root.left) + rob_R, no_rob_R = dfs(root.right) + return max(no_rob_R + no_rob_L + root.val , rob_L + rob_R), rob_L + rob_R + + return dfs(root)[0] + +``` + +对于每个node,我们return的是从这个node能抢到的最大值,以及不抢它能获得的最大值,这个递归简直我服 + + + diff --git a/docs/Algorithm/Leetcode/Python/338. Counting Bits.md b/docs/Algorithm/Leetcode/Python/338. Counting Bits.md new file mode 100644 index 00000000..e74a1325 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/338. Counting Bits.md @@ -0,0 +1,46 @@ +### 338. Counting Bits + +题目: + + + +难度: +Medium + + + +**O(n\*sizeof(integer))** 算法,其实就是把count of 1 bit拿来用: + +``` +class Solution(object): + def countBits(self, num): + """ + :type num: int + :rtype: List[int] + """ + def hammingWeight(n): + cnt = 0 + while n != 0: + n &= n -1 + cnt += 1 + return cnt + + res = [] + for i in range(num+1): + res.append(hammingWeight(i)) + return res + +``` + + + +DP算法 - to be done + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/339. Nested List Weight Sum.md b/docs/Algorithm/Leetcode/Python/339. Nested List Weight Sum.md new file mode 100644 index 00000000..a39800a5 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/339. Nested List Weight Sum.md @@ -0,0 +1,58 @@ +### 339. Nested List Weight Sum + + + +题目: + + +难度: +Easy + +思路: + +一开始没认真读题,直接上手开写: + +``` +class Solution(object): + def depthSum(self, nestedList): + """ + :type nestedList: List[NestedInteger] + :rtype: int + """ + def dfs(nestedList): + for item in nestedList: + if item.isInteger(): + self.res += item.getInteger() + else: + dfs(item.getList()) + self.res = 0 + dfs(nestedList) + return self.res +``` + + + +然后注意到要weight by its depth. + + + +AC + +``` +class Solution(object): + def depthSum(self, nestedList): + """ + :type nestedList: List[NestedInteger] + :rtype: int + """ + def dfs(nestedList,depth): + for item in nestedList: + if item.isInteger(): + self.res += item.getInteger() * depth + else: + dfs(item.getList(), depth+1) + self.res = 0 + dfs(nestedList,1) + return self.res +``` + diff --git a/docs/Algorithm/Leetcode/Python/341._Flatten_Nested_List_Iterator.md b/docs/Algorithm/Leetcode/Python/341._Flatten_Nested_List_Iterator.md new file mode 100644 index 00000000..2acc186f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/341._Flatten_Nested_List_Iterator.md @@ -0,0 +1,47 @@ +### 341. Flatten Nested List Iterator + + + +题目: + + + + +难度: +Medium + + + +```python +class NestedIterator(object): + + def __init__(self, nestedList): + """ + Initialize your data structure here. + :type nestedList: List[NestedInteger] + """ + def dfs(nestedList): + for item in nestedList: + if item.isInteger(): + self.stack.append(item.getInteger()) + else: + dfs(item.getList()) + self.stack = [] + dfs(nestedList) + + + def next(self): + """ + :rtype: int + """ + if self.hasNext(): + return self.stack.pop(0) + + + def hasNext(self): + """ + :rtype: bool + """ + return self.stack != [] +``` + diff --git a/docs/Algorithm/Leetcode/Python/342._Power_of_Four.md b/docs/Algorithm/Leetcode/Python/342._Power_of_Four.md new file mode 100644 index 00000000..c895a7c2 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/342._Power_of_Four.md @@ -0,0 +1,32 @@ +### 342. Power of Four + + + +题目: + + + + +难度 : Easy + +继续照抄power of three + +```python +class Solution(object): + def isPowerOfFour(self, num): + """ + :type num: int + :rtype: bool + """ + if num <= 0 : + return False + if num == 1: + return True + if num % 4 == 0: + return self.isPowerOfFour(num/4) + return False + +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/344._reverse_string.md b/docs/Algorithm/Leetcode/Python/344._reverse_string.md new file mode 100644 index 00000000..0e4c0f4f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/344._reverse_string.md @@ -0,0 +1,47 @@ +### 344. Reverse String + + + +题目: + + + +难度: +Easy + +思路: + +不要脸的python AC code: + + +```python +class Solution(object): + def reverseString(self, s): + """ + :type s: str + :rtype: str + """ + return s[::-1] +``` + +因为python不支持item assignment + +所以如果非要用two pointer来做的话,那么会是这样 + +```python +class Solution(object): + def reverseString(self, s): + """ + :type s: str + :rtype: str + """ + lst = list(s) + n = len(lst) + start, end = 0, n - 1 + + while start < end: + lst[end], lst[start] = lst[start],lst[end] + start += 1 + end -= 1 + return ''.join(lst) +``` diff --git a/docs/Algorithm/Leetcode/Python/345._Reverse_Vowels_of_a_String.md b/docs/Algorithm/Leetcode/Python/345._Reverse_Vowels_of_a_String.md new file mode 100644 index 00000000..380c1b51 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/345._Reverse_Vowels_of_a_String.md @@ -0,0 +1,61 @@ +### 345. Reverse Vowels of a String + + +题目: + + + +难度: + +Easy + + + +思路 + +字符串不可变,所以用list代替,最后join + + + +```python +class Solution(object): + def reverseVowels(self, s): + """ + :type s: str + :rtype: str + """ + vowels = 'aeiou' + string = list(s) + i, j = 0, len(s) -1 + while i <= j: + if string[i].lower() not in vowels: + i += 1 + elif string[j].lower() not in vowels: + j -= 1 + else: + string[i], string[j] = string[j], string[i] + i += 1 + j -= 1 + return ''.join(string) +``` + +正则版本 + +```python +class Solution(object): + def reverseVowels(self, s): + """ + :type s: str + :rtype: str + """ + vowels = re.findall('(?i)[aeiou]', s) + return re.sub('(?i)[aeiou]', lambda m: vowels.pop(), s) +``` + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/349._intersection_of_two_arrays.md b/docs/Algorithm/Leetcode/Python/349._intersection_of_two_arrays.md new file mode 100644 index 00000000..2f79b8dd --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/349._intersection_of_two_arrays.md @@ -0,0 +1,25 @@ +### 349. Intersection of Two Arrays + +题目: + + + +难度: + +Easy + + + +Python一句话作弊 + +```python +class Solution(object): + def intersection(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + return list(set(nums1).intersection(nums2)) +``` + diff --git a/docs/Algorithm/Leetcode/Python/350._intersection_of_two_arrays_ii.md b/docs/Algorithm/Leetcode/Python/350._intersection_of_two_arrays_ii.md new file mode 100644 index 00000000..d2a44477 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/350._intersection_of_two_arrays_ii.md @@ -0,0 +1,65 @@ +### 350. Intersection of Two Arrays II + +题目: + + + + +难度: + +Easy + + +sort之后用了双指针来走和看 + + +```python +class Solution(object): + def intersect(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + nums1.sort() + nums2.sort() + + l1 = len(nums1) + l2 = len(nums2) + + p1 = 0 + p2 = 0 + + res = [] + + while p1 < l1 and p2 < l2: + if nums1[p1] < nums2[p2]: + p1 += 1 + elif nums1[p1] > nums2[p2]: + p2 += 1 + else: + res.append(nums1[p1]) + p1 += 1 + p2 += 1 + return res +``` + +两行版本 +```python +class Solution(object): + def intersect(self, nums1, nums2): + """ + :type nums1: List[int] + :type nums2: List[int] + :rtype: List[int] + """ + a, b = map(collections.Counter, (nums1, nums2)) + return list((a & b).elements()) +``` + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/353. Design Snake Game.md b/docs/Algorithm/Leetcode/Python/353. Design Snake Game.md new file mode 100644 index 00000000..b9b95757 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/353. Design Snake Game.md @@ -0,0 +1,89 @@ +### 353. Design Snake Game + + + +题目: + + + +难度: Medium + +思路: + +纯正单纯方式 + +在TLE边缘AC + +AC代码 + + + +``` +class SnakeGame(object): + + def __init__(self, width,height,food): + """ + Initialize your data structure here. + @param width - screen width + @param height - screen height + @param food - A list of food positions + E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. + :type width: int + :type height: int + :type food: List[List[int]] + """ + self.width = width + self.height = height + self.food = food + self.snake = [[0,0]] + self.score = 0 + + + def move(self, direction): + """ + Moves the snake. + @param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down + @return The game's score after the move. Return -1 if game over. + Game over when snake crosses the screen boundary or bites its body. + :type direction: str + :rtype: int + """ + + nextx, nexty = self.snake[0] + + if direction == 'U': + nextx -= 1 + if direction == 'L': + nexty -=1 + if direction == 'R': + nexty +=1 + if direction == 'D': + nextx +=1 + + # nextx, nexty has food + if self.food and [nextx,nexty] == self.food[0]: + self.snake.insert(0,[nextx,nexty]) + self.food = self.food[1:] + self.score += 1 + # netx, nety outside boundary + else: + self.snake = self.snake[:-1] + self.snake.insert(0,[nextx,nexty]) + if nextx < 0 or nextx > self.height - 1 or nexty < 0 or nexty > self.width - 1: + return -1 + noDupes = [] + + for snakePt in self.snake: + # print snakePt, + if snakePt not in noDupes: + noDupes.append(snakePt) + # print 'snake', self.snake + # print 'noDpues', noDupes + if len(noDupes) < len(self.snake): + return -1 + return self.score + +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/361._Bomb_Enemy.md b/docs/Algorithm/Leetcode/Python/361._Bomb_Enemy.md new file mode 100644 index 00000000..8eedf436 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/361._Bomb_Enemy.md @@ -0,0 +1,74 @@ +### 361. Bomb Enemy + +题目: + + + +难度: + +Medium + + +思路 + +1. 首先,从每一行开始,从左到右,计算E的个数,然后一碰到W就将row_hits重置为0,一碰到0就将row_hits赋值给他 +2. 然后,从每一行开始,从右到左,原操作不变,唯一是碰到0的时候加上row_hits而不是直接等于row_hits +3. 接下来,就是跟第二步一样的操作,只不过是变成了从每一列开始,从上到下 +4. 最后也是跟第二步一样的操作,只不过是变成了从每一列开始,并且是从下到上,然后就是每一次碰到0不但要加上col_hits的值还要决出max_hits +5. 返回max_hits + +时间复杂度是 ```O(m*n) * (m+n)``` + + +```python + if not grid or len(grid) == 0: + return 0 + max_hits = 0 + nums = [[0 for i in range(len(grid[0]))] for j in range(len(grid))] + + for i in range(len(grid)): + row_hits = 0 + for j in range(len(grid[0])): + if grid[i][j] == 'E': + row_hits += 1 + elif grid[i][j] == 'W': + row_hits = 0 + else: + nums[i][j] = row_hits + + for i in range(len(grid)): + row_hits = 0 + for j in range(len(grid[0])-1, -1, -1): + if grid[i][j] == 'E': + row_hits += 1 + elif grid[i][j] == 'W': + row_hits = 0 + else: + nums[i][j] += row_hits + + for i in range(len(grid[0])): + col_hits = 0 + for j in range(len(grid)): + if grid[j][i] == 'E': + col_hits += 1 + elif grid[j][i] == 'W': + col_hits = 0 + else: + nums[j][i] += col_hits + + for i in range(len(grid[0])): + col_hits = 0 + for j in range(len(grid)-1, -1, -1): + if grid[j][i] == 'E': + col_hits +=1 + elif grid[j][i] == 'W': + col_hits = 0 + else: + nums[j][i] += col_hits + max_hits = max(max_hits, nums[j][i]) + + + return max_hits +``` + + diff --git a/docs/Algorithm/Leetcode/Python/364. Nested List Weight Sum II.md b/docs/Algorithm/Leetcode/Python/364. Nested List Weight Sum II.md new file mode 100644 index 00000000..d72cb164 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/364. Nested List Weight Sum II.md @@ -0,0 +1,47 @@ +### 364. Nested List Weight Sum II + + + +题目: + + +难度: +Medium + +思路: + + + +跟 Nested List Weight Sum I 的区别是这个是从不是数depth,是数层的高度: + + + +比较naive的AC代码: + +``` +class Solution(object): + def depthSumInverse(self, nestedList): + """ + :type nestedList: List[NestedInteger] + :rtype: int + """ + def level(nestedList,height): + self.level = max(height, self.level) + for item in nestedList: + if not item.isInteger(): + level(item.getList(), height + 1) + + def dfs(nestedList, height): + for item in nestedList: + if item.isInteger(): + self.res += item.getInteger() * height + else: + dfs(item.getList(),height - 1) + + self.level = 1 + self.res = 0 + level(nestedList,1) + dfs(nestedList, self.level) + return self.res +``` + diff --git a/docs/Algorithm/Leetcode/Python/366. Find Leaves of Binary Tree.md b/docs/Algorithm/Leetcode/Python/366. Find Leaves of Binary Tree.md new file mode 100644 index 00000000..e82d592c --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/366. Find Leaves of Binary Tree.md @@ -0,0 +1,52 @@ +### 366. Find Leaves of Binary Tree + + + +题目: + + + + + +难度 :Medium + + + +按照它的要求,老老实实写了两个递归 findleaf 和 deleteleaf, 再组合起来 + + + +AC代码 + +```python +class Solution(object): + def findLeaves(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + def findLeaf(root): + if not root: + return [] + elif not root.left and not root.right: + return [root.val] + else: + return findLeaf(root.left) + findLeaf(root.right) + def removeLeaf(root): + if not root: + return None + elif not root.left and not root.right: + return None + else: + if root.left: + root.left = removeLeaf(root.left) + if root.right: + root.right = removeLeaf(root.right) + return root + res = [] + while root: + res.append(findLeaf(root)) + root = removeLeaf(root) + return res +``` + diff --git a/docs/Algorithm/Leetcode/Python/367._valid_perfect_square.md b/docs/Algorithm/Leetcode/Python/367._valid_perfect_square.md new file mode 100644 index 00000000..7bb7285d --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/367._valid_perfect_square.md @@ -0,0 +1,42 @@ +###367. Valid Perfect Square + +题目: + + + + +难度: + +Medium + + +直接用循环做也可以AC + + +``` +class Solution(object): + def isPerfectSquare(self, num): + """ + :type num: int + :rtype: bool + """ + if num == 1 or num == 4 : return True + for i in xrange(num//2): + if i*i == num: + return True + elif i*i > num: + return False + return False + +``` + +然后发现有传说中的牛顿法 + +有待阅读,然后还有二分法 + +``` + r = x + while r*r > x: + r = (r + x/r) / 2 + return r*r == x +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/369.Plus One Linked List.md b/docs/Algorithm/Leetcode/Python/369.Plus One Linked List.md new file mode 100644 index 00000000..92c64e78 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/369.Plus One Linked List.md @@ -0,0 +1,46 @@ +### 369.Plus One Linked List + +题目: + + +难度 : Medium + + + +类似题目: plus one,plus one 用递归和循环写了,对于linked list,因为most significant digit在首位,递归写起来不方便,用循环尝试,然后代码并没有实质上的区别。 + + + +``` +class Solution(object): + def plusOne(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + lst = [] + cur = head + + while cur: + lst.append(cur) + cur = cur.next + + carry = 1 + for i in range(len(lst)-1,-1,-1): + lst[i].val += carry + if lst[i].val < 10: + carry = 0 + break + else: + lst[i].val -= 10 + + if carry == 1: + node = ListNode(1) + node.next = head + return node + else: + return head +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/371._sum_of_two_integers.md b/docs/Algorithm/Leetcode/Python/371._sum_of_two_integers.md new file mode 100644 index 00000000..675aa972 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/371._sum_of_two_integers.md @@ -0,0 +1,95 @@ +###371. Sum of Two Integers + +题目: + + + +难度: + +Easy + + +思路 + + +谷歌答案 + + +位运算 + +``` +XOR +x y output +0 0 0 +1 0 1 +0 1 1 +1 1 0 + + +AND +x y output +0 0 0 +1 0 1 +0 1 1 +1 1 1 + +``` + +如果对x和y来做加法(x和y都是一位的),那么末位会是x xor y,进位会是x and y + + + + + +python没有左移,用c++来看 + +``` +class Solution { +public: + int getSum(int a, int b) { + while (b != 0 ){ + int c = a & b; + a = a ^ b; + b = c << 1; + } + return a; + } +}; +``` + +实际上看到答案还是没有那么明白的,还是动手算算 + + + +``` +a = 6 (0110) +b = 15 (1111) + + +1st +--------- +carry = a & b = 0110 +a = a ^ b = 1001 +b = 1100 + + +2nd +--------- +carry = a & b = 1000 +a = a ^ b = 0101 +b = 10000 + + +3rd +---------- + +carry = a & b = 0 +a = a ^ b = 10101 +b = 0 + +这个时候a 的值是2^4 + 2^2 + 2^0 = 16+4+1 = 21 +``` + +虽然convence了我自己,但是表示依旧迷茫ing + +也知道位运算需要待补啊 \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/374._Guess_Number_Higher_or_Lower.md b/docs/Algorithm/Leetcode/Python/374._Guess_Number_Higher_or_Lower.md new file mode 100644 index 00000000..d7d3072f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/374._Guess_Number_Higher_or_Lower.md @@ -0,0 +1,34 @@ +### 374. Guess Number Higher or Lower + +题目: + + + +难度: + +Easy + + +思路 + +二分 + +```python +class Solution(object): + def guessNumber(self, n): + """ + :type n: int + :rtype: int + """ + l, r = 1, n + while l <= r: + mid = l + ((r - l) >> 2) + if guess(mid) == 1: + l = mid + 1 + elif guess(mid) == -1: + r = mid - 1 + else: + return mid +``` + + diff --git a/docs/Algorithm/Leetcode/Python/377._combination_sum_iv.md b/docs/Algorithm/Leetcode/Python/377._combination_sum_iv.md new file mode 100644 index 00000000..88548d17 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/377._combination_sum_iv.md @@ -0,0 +1,77 @@ +###377. Combination Sum IV + +题目: + + + + +难度: + +Medium + + +直接用combination sum的思路: 超时 + +``` +class Solution(object): + def combinationSum4(self, candidates, target): + """ + :type candidates: List[int] + :type target: int + :rtype: List[List[int]] + """ + def combSum(candidates, target, start, valueList): + length = len(candidates) + if target == 0 : + res.append(valueList) + for i in range(start, length): + if target < candidates[i]: + return + combSum(candidates, target - candidates[i], 0, valueList + [candidates[i]]) + + candidates = list(set(candidates)) + candidates.sort() + res = [] + combSum(candidates, target, 0, []) + return len(res) +``` + + + + + +说起来标签是dp,也知道是dp啊,状态转移方程: + + + +参考: + + + +> +> +> 我们需要一个一维数组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的所有情况了 + + + +AC代码 + +``` +class Solution(object): + def combinationSum4(self, candidates, target): + """ + :type candidates: List[int] + :type target: int + :rtype: List[List[int]] + """ + dp = [0 for i in range(target+1)] + + dp[0] = 1 + + for i in range(target+1): + for candidate in candidates: + if i >= candidate: + dp[i] += dp[i - candidate] + return dp[-1] +``` + diff --git a/docs/Algorithm/Leetcode/Python/378._kth_smallest_element_in_a_sorted_matrix.md b/docs/Algorithm/Leetcode/Python/378._kth_smallest_element_in_a_sorted_matrix.md new file mode 100644 index 00000000..34c267b4 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/378._kth_smallest_element_in_a_sorted_matrix.md @@ -0,0 +1,107 @@ +### 378. Kth Smallest Element in a Sorted Matrix + + + +题目: + + + +难度: +Medium + + + +### 思路一:暴力法 + +```python +class Solution(object): + def kthSmallest(self, matrix, k): + """ + :type matrix: List[List[int]] + :type k: int + :rtype: int + """ + tmp = [] + for row in matrix: + for column in row: + tmp.append(column) + tmp.sort() + return tmp[k-1] if tmp and len(tmp)>0 else None +``` +### 思路二: +两个tag : binary search, heap + +######先来heap + +1. 利用heap,先对第一行所有元素加入heap,每个元素下面同一列的元素必然比他们大 +2. 重复K-1次下面的过程 + - 取现在的root + - 将root下面的元素加入heap + +可以手写一个例子来看 + +参考: + + +```python +class Solution(object): + def kthSmallest(self, matrix, k): + """ + :type matrix: List[List[int]] + :type k: int + :rtype: int + """ + if not matrix: + return 0 + + heap = [] + row = len(matrix) + col = len(matrix[0]) + + for i in range(col): + # heap store its value and location + heapq.heappush(heap, (matrix[0][i], 0, i)) + + print heap + + for j in range(k-1): + cur = heappop(heap) + x = cur[1] + y = cur[2] + if x+1 < row: + heapq.heappush(heap, (matrix[x+1][y],x+1,y)) + + return heap[0][0] +``` + +### 思路三: heapq一行 + +```python +class Solution(object): + def kthSmallest(self, matrix, k): + """ + :type matrix: List[List[int]] + :type k: int + :rtype: int + """ + return list(heapq.merge(*matrix))[k-1] +``` + +### 思路四; binary search +```python +class Solution(object): + def kthSmallest(self, matrix, k): + """ + :type matrix: List[List[int]] + :type k: int + :rtype: int + """ + l, r = matrix[0][0], matrix[-1][-1] + while l <= r: + mid = l + ((r - l) >> 2) + if sum(bisect.bisect_right(row, mid) for row in matrix) < k: + l = mid + 1 + else: + r = mid - 1 + return l +``` diff --git a/docs/Algorithm/Leetcode/Python/380. Insert Delete GetRandom O(1).md b/docs/Algorithm/Leetcode/Python/380. Insert Delete GetRandom O(1).md new file mode 100644 index 00000000..401f3ee7 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/380. Insert Delete GetRandom O(1).md @@ -0,0 +1,159 @@ +### 380. Insert Delete GetRandom O(1) + + + +题目: + + + + +难度 : Hard + + + +我的naive TLE代码,关键还是在想这个getRandom,这就不是O(1)的: + + + +``` +class RandomizedSet(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.container = {} + + + def insert(self, val): + """ + Inserts a value to the set. Returns true if the set did not already contain the specified element. + :type val: int + :rtype: bool + """ + # 1 stands for present + if val in self.container and self.container[val] == 1: + return False + else: + self.container[val] = 1 + return True + + + def remove(self, val): + """ + Removes a value from the set. Returns true if the set contained the specified element. + :type val: int + :rtype: bool + """ + if self.container.get(val,0) == 1: + self.container[val] = 0 + return True + else: + return False + + + + def getRandom(self): + """ + Get a random element from the set. + :rtype: int + """ + import random + keys = self.container.keys() + rd = random.randint(0, len(keys) - 1) + if self.container[keys[rd]] == 1: + return keys[rd] + elif self.container.get(keys[rd],0) == 0: + return self.getRandom() +``` + + + +也是有[stackoverflow问题界面的题目](http://stackoverflow.com/questions/5682218/data-structure-insert-remove-contains-get-random-element-all-at-o1#comment18171331_5684892): + +> 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. +> +> 1.insert(value): append the value to array and let i be its index in A. Set H[value]=i. +> +> 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. +> +> 3.contains(value): return H.contains(value) +> +> 4.getRandomElement(): let r=random(current size of A). return A[r]. +> +> +> +> 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. + + + + + +按照以答案AC代码 + +``` +class RandomizedSet(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.hashtable = {} + self.array = [] + self.arraySize = 0 + + def insert(self, val): + """ + Inserts a value to the set. Returns true if the set did not already contain the specified element. + :type val: int + :rtype: bool + """ + # already in the set + if val in self.hashtable: + return False + else: + self.hashtable[val] = self.arraySize + self.array.append(val) + self.arraySize += 1 + return True + + + def remove(self, val): + """ + Removes a value from the set. Returns true if the set contained the specified element. + :type val: int + :rtype: bool + """ + if val not in self.hashtable: + return False + else: + removeIdx = self.hashtable[val] + if self.arraySize == 1: + self.__init__() + else: + self.array[removeIdx] = self.array[-1] + self.hashtable[self.array[-1]] = removeIdx + self.arraySize -= 1 + del self.hashtable[val] + del self.array[-1] + return True + + + + def getRandom(self): + """ + Get a random element from the set. + :rtype: int + """ + import random + rd = random.randint(0, self.arraySize-1) + return self.array[rd] +``` + + + + + +最后getRandom也可以写成: + +`return random.choice(self.array)` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/381. Insert Delete GetRandom O(1) - Duplicates allowed.md b/docs/Algorithm/Leetcode/Python/381. Insert Delete GetRandom O(1) - Duplicates allowed.md new file mode 100644 index 00000000..9adb6cd3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/381. Insert Delete GetRandom O(1) - Duplicates allowed.md @@ -0,0 +1,83 @@ +### 381. Insert Delete GetRandom O(1) - Duplicates allowed + + + +题目: + + + + +难度 : Hard + + + +一开始的想法是在380上面做简单的修改,比如用一个list来存每个数对应的location,但是这样remove会退化为O(N),然后看到: + +- 用 set 这个数据结构就可以贴近O(1) +- 学了一个新的东西`defaultdict`, 相当于 D.get('key',defaultvalue) + + + +这个defaultdict的好处就是添加的时候默认的值就是set,但是并不默认这个就存在 + + + +AC代码 + +``` +class RandomizedCollection(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + import collections + self.hashtable = collections.defaultdict(set) + self.array = [] + + def insert(self, val): + """ + Inserts a value to the collection. Returns true if the collection did not already contain the specified element. + :type val: int + :rtype: bool + """ + valin = val not in self.hashtable + self.hashtable[val].add(len(self.array)) + self.array.append(val) + return valin + + def remove(self, val): + """ + Removes a value from the collection. Returns true if the collection contained the specified element. + :type val: int + :rtype: bool + """ + if val not in self.hashtable: + return False + else: + if self.array[-1] == val: + removeIdx = len(self.array) - 1 + self.hashtable[val].remove(removeIdx) + else: + # set pop remove arbitrary element + removeIdx = self.hashtable[val].pop() + self.array[removeIdx] = self.array[-1] + self.hashtable[self.array[-1]].remove(len(self.array) - 1) + self.hashtable[self.array[-1]].add(removeIdx) + if len(self.hashtable[val]) == 0: + del self.hashtable[val] + del self.array[-1] + return True + + + def getRandom(self): + """ + Get a random element from the collection. + :rtype: int + """ + import random + return random.choice(self.array) + +``` + +` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/382._linked_list_random_node.md b/docs/Algorithm/Leetcode/Python/382._linked_list_random_node.md new file mode 100644 index 00000000..775a0b32 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/382._linked_list_random_node.md @@ -0,0 +1,79 @@ + +###382. Linked List Random Node + + +题目: + + + +难度: + +Medium + + + +tag:reservoir sampling 水塘抽样 + + +思路: + +n选k + + +这样来看,有k个元素,那么这个时候全部选中,当第k+1个元素进来的时候,生成一个随机数r,如果 r <= k,那么用它来替换第r个元素 + +那么r被替换掉的概率是 1 / k + 1, 不被替换掉的概率是 k / k + 1 (不生成r) + +k+2来继续: 被替换掉的概率 1 / k + 2, 不被替换掉的概率 (k + 1) / (k+2) + +所以最终被选中的(不被替换掉的概率是) k / n + +随机 √ + + +针对这道题目来看 + +- 一开始选head为choice +- 出现第二个,生成[1,2]之间的随机数,如果r = 2,则用新的来替换choice +- 出现第三个,生成[1,2,3]之间的随机数,如果r = 3,则替换 + +再写简单一点就是 + + +每次以 1/i 来决定是否用新的元素来替换选中元素,那么就是 i - 1 / i 不替换,它之前被选中的概率就是 1 / i-1 ,所以最终被选中的概率是 1/i + +这个对于linked list更优之处在于它不用reverse + +时间复杂度 O(N), 空间复杂度O(K) + + +然后AC + + +``` +class Solution(object): + + def __init__(self, head): + """ + @param head The linked list's head. + Note that the head is guaranteed to be not null, so it contains at least one node. + :type head: ListNode + """ + self.head = head + + def getRandom(self): + """ + Returns a random node's value. + :rtype: int + """ + choice = self.head + cur = self.head + i = 1 + while cur.next: + cur = cur.next + i += 1 + rd = random.randint(1,i) + if rd == i: + choice = cur + return choice.val +``` diff --git a/docs/Algorithm/Leetcode/Python/383._ransom_note.md b/docs/Algorithm/Leetcode/Python/383._ransom_note.md new file mode 100644 index 00000000..6a6ee16e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/383._ransom_note.md @@ -0,0 +1,53 @@ +### 383. Ransom Note + +题目: + + + +难度 : Easy + + + +略微想了一下,用了一个dictionary来存magazine里面的单字出现的个数,然后来对应check是否可以用来组成ransomNote + + +```python +class Solution(object): + def canConstruct(self, ransomNote, magazine): + """ + :type ransomNote: str + :type magazine: str + :rtype: bool + """ + maps = {} + for i in magazine: + if i in maps: + maps[i] += 1 + else: + maps[i] = 1 + for i in ransomNote: + if i not in maps: + return False + else: + maps[i] -= 1 + if maps[i] < 0: + return False + return True +``` +解法2: + +```python +class Solution(object): + def canConstruct(self, ransomNote, magazine): + """ + :type ransomNote: str + :type magazine: str + :rtype: bool + """ + magCounter = collections.Counter(magazine) + ranCounter = collections.Counter(ransomNote) + for k in ranCounter: + if ranCounter.get(k) > magCounter.get(k): + return False + return True +``` diff --git a/docs/Algorithm/Leetcode/Python/384. Shuffle an Array.md b/docs/Algorithm/Leetcode/Python/384. Shuffle an Array.md new file mode 100644 index 00000000..bd3d126a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/384. Shuffle an Array.md @@ -0,0 +1,105 @@ +### 384. Shuffle an Array + + + +题目: + + + + +难度 : Medium + + + +思路: + + + +这就是洗牌算法吧,洗牌算法几种常见的: + + + +http://www.matrix67.com/blog/archives/879 + + + +也是有wikipedia page的: + +最简单的算法是很容易想到的, O(N^2) + +然后就是modern 算法: + + + +``` +-- To shuffle an array a of n elements (indices 0..n-1): +for i from n−1 downto 1 do + j ← random integer such that 0 ≤ j ≤ i + exchange a[j] and a[i] +``` + + + +这个感觉还是比较容易证明的,一开始生成的数字 1/n 概率 + +没选中,下一个 n-1 /n * 1/ n-1 = 1/n, 所以每个位置都是等概率的? + + + +这个有很妙的点: + +比如五个人顺序抽签,只要不uncover 结果,那么就是等概率的。 + + + +但是第一个人抽奖之后uncover结果,比如他没有抽中 → 那么概率就会变。 + + + + + + + +AC代码: + +``` +class Solution(object): + + def __init__(self, nums): + """ + + :type nums: List[int] + :type size: int + """ + self.lst = nums + + + def reset(self): + """ + Resets the array to its original configuration and return it. + :rtype: List[int] + """ + return self.lst + + + def shuffle(self): + """ + Returns a random shuffling of the array. + :rtype: List[int] + """ + import random + res = self.lst[:] + n = len(res) + for i in range(n-1,0,-1): + j = random.randint(0,i) + res[i], res[j] = res[j], res[i] + return res + +``` + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/386._Lexicographical_Numbers.md b/docs/Algorithm/Leetcode/Python/386._Lexicographical_Numbers.md new file mode 100644 index 00000000..beceeab5 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/386._Lexicographical_Numbers.md @@ -0,0 +1,90 @@ +# 386. Lexicographical Numbers 字典序排数 + +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/lexicographical-numbers/description/ +* https://leetcode-cn.com/problems/lexicographical-numbers/description/ + +> 内容描述 + +``` + +给定一个整数 n, 返回从 1 到 n 的字典顺序。 + +例如, + +给定 n =1 3,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。 + +请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 n 小于等于 5,000,000。 +``` + +## 解题方案 + +> 思路 1 + +那当然是直接转换成string比较排序啊,多么暴力,简单明了, ```beats 66.87%``` + +- 时间复杂度:O(NlogN) +- 空间复杂度:O(N) +```python +class Solution(object): + def lexicalOrder(self, n): + """ + :type n: int + :rtype: List[int] + """ + return sorted(range(1, n+1), key=lambda x: str(x)) +``` + +> 思路 2 + +其实我们每次只要知道下一个数是啥就行了 +例如对于67这个数, +- 它的下一个数要么是670(如果670 <= n )的话 +- 要么是68(如果68 <= n )的话, 同时还要注意,如果我们例子中n换成200的话,如果当前数字为199,那其实它的下一个数字应该是2而不是200, +所以这里我们要多加一个判断```(cur + 1) % 10 != 0```, 然后对于尾数是9的数字我们要一直除以10让它尾数不是9之后再加1,即```199 --> 2```的过程 +- 要么是7(当然7肯定小于n了,因为67都出现了) + +- 时间复杂度:O(N) +- 空间复杂度:O(1) + +这个方法```beats 94.59%``` + +```python +class Solution(object): + def lexicalOrder(self, n): + """ + :type n: int + :rtype: List[int] + """ + res = [] + cur = 1 + for i in range(n): + res.append(cur) + if (cur * 10 <= n): + cur *= 10 + elif cur + 1 <= n and (cur + 1) % 10 != 0: + cur += 1 + else: + while (cur/10) % 10 == 9: + cur /= 10 + cur = cur / 10 + 1 + return res +``` + + + + + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/387._first_unique_character_in_a_string.md b/docs/Algorithm/Leetcode/Python/387._first_unique_character_in_a_string.md new file mode 100644 index 00000000..dfbb89ae --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/387._first_unique_character_in_a_string.md @@ -0,0 +1,58 @@ +### 387. First Unique Character in a String + +题目: + + + +难度: +Easy + + + +思路一: + +Python作弊法 + +用Python的Counter模块 + +可以参考 + + + + +```python +class Solution(object): + def firstUniqChar(self, s): + """ + :type s: str + :rtype: int + """ + d = collections.Counter(s) + for x,c in enumerate(s): + if d[c] == 1: + return x + return -1 +``` + + +思路二: + +利用问题的特性,因为只有可能是小写字母,所以可以用一个长度为26的array, 先数一遍char的数量,然后enumerate从左往右又来 + +```python +class Solution(object): + def firstUniqChar(self, s): + """ + :type s: str + :rtype: int + """ + cnt = [0 for i in range(26)] + for char in s: + cnt[ord(char) - ord('a')] += 1 + + for idx, char in enumerate(s): + if cnt[ord(char) - ord('a')] == 1: + return idx + return -1 + +``` diff --git a/docs/Algorithm/Leetcode/Python/388._Longest_Absolute_File_Path.md b/docs/Algorithm/Leetcode/Python/388._Longest_Absolute_File_Path.md new file mode 100644 index 00000000..7d92da63 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/388._Longest_Absolute_File_Path.md @@ -0,0 +1,93 @@ +### 388. Longest Absolute File Path + + +题目: + + + +难度: + +Medium + + + +思路 + +我们首先观察到每个```文件夹```或者是```文件```前面都会有一个```'\n'```, 还有对应其层数个数的```'\t'```. +- 所以首先根据```'\n'```分行,然后算出该```文件/文件夹```的层数```depth``` +- 如果是```文件```,我们需要更新```maxlen``` +- 如果是```文件夹```,我们需要更新该```depth```下的```pathlen``` + +### 程序变量解释 + +- ```maxlen``` 代表目前最大子串的长度 +- ```pathlen``` 每一个```depth```下对应的```path```长度 + +#### 特别需要注意的是,```'\t'```的长度是1 +有的人仍然会有疑问,每次碰到文件夹都直接更新```pathlen```会不会导致本来长的反而变得短了,但是我们可以看到字符串的排版格式,每层```path```都是严格有自己的分级的, +因此不会出现这样的问题。 +例如: +- The string ```"dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"``` represents: +``` +dir + subdir1 + file1.ext + subsubdir1 + subdir2 + subsubdir2 + file2.ext +``` +其最大长度是```32```, ```"dir/subdir2/subsubdir2/file2.ext"``` + +- 如果变成```"dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir20\n\t\tsubsubdir2\n\t\t\tfile2.ext"```, + +``` +dir + subdir1 + file1.ext + subsubdir1 + subdir20 + subsubdir2 + file2.ext +``` + +最大长度就是```33```, +```"dir/subdir2/subsubdir20/file2.ext"``` + + +- 如果变成 +```"dir\n\tsubdir1000000000000\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"``` + +``` +dir + subdir10000000000000 + file1.ext + subsubdir1 + subdir20 + subsubdir2 + file2.ext +``` + +最大长度就是```34```,```"dir/subdir10000000000000/file1.ext"``` + + +```python +class Solution(object): + def lengthLongestPath(self, input): + """ + :type input: str + :rtype: int + """ + maxlen = 0 + pathlen = {0 : 0} + for line in input.splitlines(): + name = line.lstrip('\t') + depth = len(line) - len(name) # 前面有几个'\t', depth就是几 + if '.' in name: + maxlen = max(maxlen, pathlen[depth] + len(name)) + else: +                pathlen[depth+1] = pathlen[depth] + len(name) + 1   #加1是为了加上一个path分隔符'/'的长度 + return maxlen +``` + + diff --git a/docs/Algorithm/Leetcode/Python/389._find_the_difference.md b/docs/Algorithm/Leetcode/Python/389._find_the_difference.md new file mode 100644 index 00000000..9ebaced6 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/389._find_the_difference.md @@ -0,0 +1,47 @@ + +### 389. Find the Difference + + +题目: + + + +难度: + +Easy + +用个字典来记录,把s加进去,把t减掉,最后剩下那个要么个数为1,要么个数为-1 + +```python +class Solution(object): + def findTheDifference(self, s, t): + """ + :type s: str + :type t: str + :rtype: str + """ + res = {} + for i in s: + res[i] = res.get(i, 0) + 1 + for j in t: + res[j] = res.get(j, 0) - 1 + for key in res: + if abs(res[key]) == 1: # 这里用 abs 是因为新增加的那个字母在 s 中可能未出现过 + return key +``` +还有一个简单的方法 +```python +class Solution(object): + def findTheDifference(self, s, t): + """ + :type s: str + :type t: str + :rtype: str + """ + from collections import Counter + return list((Counter(t) - Counter(s)).keys()).pop() +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/392._is_subsequence.md b/docs/Algorithm/Leetcode/Python/392._is_subsequence.md new file mode 100644 index 00000000..44c5b812 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/392._is_subsequence.md @@ -0,0 +1,86 @@ +# 392. Is Subsequence +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/is-subsequence/description/ + +> 内容描述 + +``` + +Given a string s and a string t, check if s is subsequence of t. + +You 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). + +A 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). + +Example 1: +s = "abc", t = "ahbgdc" + +Return true. + +Example 2: +s = "axc", t = "ahbgdc" + +Return false. + +Follow up: +If 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? +``` + +## 解题方案 + +> 思路 1 + + +follow up question很有意思 + + +最naive的思路表现形式如下: + +beats 53.74% + +```python +class Solution(object): + def isSubsequence(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + if s == '': return True + for i in xrange(len(t)): + if t[i] == s[0]: + return self.isSubsequence(s[1:],t[i+1:]) + + return False +``` + +> 思路 2 + +递归操作以及对字符串的操作太过于昂贵,所以用index来处理,节省了时间和空间 + + +```python +class Solution(object): + def isSubsequence(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + if s == '': return True + ps, pt = 0, 0 + while ps < len(s) and pt < len(t): + if s[ps] == t[pt]: + ps += 1 + pt += 1 + return ps >= len(s) +``` + +精妙绝伦!! + + diff --git a/docs/Algorithm/Leetcode/Python/394._decode_string.md b/docs/Algorithm/Leetcode/Python/394._decode_string.md new file mode 100644 index 00000000..a9eabe7f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/394._decode_string.md @@ -0,0 +1,70 @@ +###394. Decode String + + +题目: + + + + +难度: + +Medium + + +思路: + +感觉像用栈做运算。 + +s = "3[a2[c]]" + +⬇️ + +s = 3 *( a + 2 * ( c ) ) + + +遇到非右括号全部入栈,碰到右括号出栈直到左括号,这个就算运算符2 → op2 +然后检查,直到stack空掉或者碰到下一个非数字,这个就算运算符1 → op1 + +算出op1 和 op2 之后把这个res继续入栈。然后接着处理 + + +代码不是很优美 + + + + +``` +class Solution(object): + def decodeString(self, s): + """ + :type s: str + :rtype: str + """ + + s = list(s) + stack = [] + + while s: + char = s.pop(0) + if char != ']': + stack.append(char) + else: + op1, op2 = '','' + popChar = stack.pop() + while popChar != '[': + op2 = popChar + op2 + popChar = stack.pop() + + while stack and stack[-1] in ['0','1','2','3','4','5','6','7','8','9']: + popChar = stack.pop() + op1 = popChar + op1 + + res = int(op1) * op2 + + for char in res: + stack.append(char) + + return ''.join(stack) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/400. Nth Digit.md b/docs/Algorithm/Leetcode/Python/400. Nth Digit.md new file mode 100644 index 00000000..6cc93ab3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/400. Nth Digit.md @@ -0,0 +1,46 @@ +### 400. Nth Digit + + + +题目: + + +难度: + +Easy + +思路: + +这道简单题我服, tag是math,找规律 + +``` +1- 9 : 9 → 只占1位 9 +10 - 99: 90 → 两位 90 * 2 +100 - 999: 900 → 三位 900 * 3 +1000 - 9999: 9000 → 四位 9000 * 4 +``` + + + +AC代码来之不易,是参考别人的,这里的`for i in range(9)`, 其实无论`range`多少都可以吧 + + + +``` +class Solution(object): + def findNthDigit(self, n): + """ + :type n: int + :rtype: int + """ + for i in range(9): + d = 9 * 10 ** i + if n <= d * (i+1): break + n -= d *(i+1) + n -= 1 + + return int(str(10**i + n / (i+1))[n % (i+1)]) +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/401._binary_watch.md b/docs/Algorithm/Leetcode/Python/401._binary_watch.md new file mode 100644 index 00000000..00f217e7 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/401._binary_watch.md @@ -0,0 +1,60 @@ +###401. Binary Watch + + + +题目: + + + +难度: +Easy + + +思路: + + +一看到位操作,我的内心是拒绝的。 + +我也有想这样的想法,因为其实可以的组合并没有那么多,干脆枚举算了,然而也没有动手来写,直到被发了题解的截屏。 + + +``` +class Solution(object): + def readBinaryWatch(self, num): + """ + :type num: int + :rtype: List[str] + """ + hour = { 0 : ['0'], + 1:['1','2','4','8'], + 2:['3','5','6','9','10'], + 3:['7','11'] + } + + minute = { 0:['00'], + 1: ['01','02','04','08','16','32'], + 2: ['03','05','06','09','10','12','17','18','20','24','33','34','36','40','48'], + 3: ['07','11','13','14','19','21','22','25','26','28','35','37','38','41','42','44','49','50','52','56'], + 4: ['15','23','27','29','30','39','43','45','46','51','53','54','57','58'], + 5: ['31','47','55','59'] + } + + res = [] + + #num = num for hour + num for minute + i = 0 + + while i <= 3 and i <= num: + if num - i <= 5: + for str1 in hour[i]: + for str2 in minute[num-i]: + res.append(str1 + ':' + str2) + i += 1 + return res +``` + + +关于循环那处,因为hour的led最多只有4个,所以这样写循环 + + + diff --git a/docs/Algorithm/Leetcode/Python/404._sum_of_left_leaves.md b/docs/Algorithm/Leetcode/Python/404._sum_of_left_leaves.md new file mode 100644 index 00000000..b6cda537 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/404._sum_of_left_leaves.md @@ -0,0 +1,45 @@ +###404. Sum of Left Leaves + + + +题目: + + + +难度: +Easy + + +思路: + + +典型递归,检查root的左孩子是不是node,是的话加上它的值,不是的话递归去求它的孩子们的,对于右边,递归的求sum of left leaves + + + +``` +class Solution(object): + def sumOfLeftLeaves(self, root): + """ + :type root: TreeNode + :rtype: int + """ + def isLeaf(node): + if node == None: + return False + if node.left == None and node.right == None: + return True + return False + + res = 0 + + if root: + if isLeaf(root.left): + res += root.left.val + else: + res += self.sumOfLeftLeaves(root.left) + if root.right: + res += self.sumOfLeftLeaves(root.right) + + return res +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/405. Convert a Number to Hexadecimal.md b/docs/Algorithm/Leetcode/Python/405. Convert a Number to Hexadecimal.md new file mode 100644 index 00000000..5bcb3ec3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/405. Convert a Number to Hexadecimal.md @@ -0,0 +1,114 @@ +### 405. Convert a Number to Hexadecimal + +题目: + + + +难度: + +Easy + + + +wikipedia两个page: + + + +[十六进制](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) + +例子: + +4877÷16=304....13(D) + +304÷16=19....0 + +19÷16=1....3 + +1÷16=0....1 + +這樣就計到4877(10)=130D(16) + + + +[补码](https://zh.wikipedia.org/wiki/二補數) + +> 一個數字的二補數就是將該數字作[位元](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。在二補數系統中,一個負數就是用其對應正數的二補數來表示 + + + +看给的这个-1的例子 + + + +0000 0000 0000 0000 0000 0000 0000 0001 + +1111 1111 1111 1111 1111 1111 1111 1110 +1 + +1111 1111 1111 1111 1111 1111 1111 1111 + +f f f f f f f f + + + + + +也可以参考这里: + +[基础03:原码、反码、补码](https://higoge.github.io/2015/07/02/basic03/) + + + +这里我一开始迷茫和晕了一下,但是随后反应过来,这些数字在电脑里使用二进制存的,而负数也是用二进制的补码存的。所以其实AC代码应当很简单。 + +参考: + + + + + +AC代码: + +``` +class Solution(object): + def toHex(self, num): + """ + :type num: int + :rtype: str + """ + if not num : + return "0" + + result = [] + hexStr ="0123456789abcdef" + while num and len(result) != 8: + h = num & 15 + result.append(hexStr[h]) + num >>= 4 + + return ''.join(result[::-1]) +``` + + + +每次看后四位的结果,把它存起来,比如还是是看4877 + +它在计算机内部的表示是: + +``` +0b1001100001101 +num & 15 1101 & 15 = 13(d) +num >>=4 0b100110000 +num & 15 0000 & 15 = 0 +num >>=4 0b10011 +num & 15 10011 & 15 = 9 +num >>=4 0001 +num & 15 0001 & 15 = 1 + +``` + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/406._Queue_Reconstruction_by_Height.md b/docs/Algorithm/Leetcode/Python/406._Queue_Reconstruction_by_Height.md new file mode 100644 index 00000000..87e55196 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/406._Queue_Reconstruction_by_Height.md @@ -0,0 +1,43 @@ +### 406. Queue Reconstruction by Height + +题目: + + + +难度: + +Medium + + +思路: +People are only counting (in their k-value) taller or equal-height others standing in front of them. +So a smallest person is completely irrelevant for all taller ones. And of all smallest people, +the one standing most in the back is even completely irrelevant for everybody else. Nobody is counting that person. +So we can first arrange everybody else, ignoring that one person. And then just insert that person appropriately. +Now note that while this person is irrelevant for everybody else, everybody else is relevant for this person - +this person counts exactly everybody in front of them. So their count-value tells you exactly the index they must be standing. + +So you can first solve the sub-problem with all but that one person and then just insert that person appropriately. +And you can solve that sub-problem the same way, first solving the sub-sub-problem with all +but the last-smallest person of the subproblem. And so on. The base case is when you have the sub-…-sub-problem of zero people. +You’re then inserting the people in the reverse order, i.e., that overall last-smallest person in the very end +and thus the first-tallest person in the very beginning. That’s what the above solution does, +Sorting the people from the first-tallest to the last-smallest, and inserting them one by one as appropriate. + +参考[stefan](https://leetcode.com/problems/queue-reconstruction-by-height/discuss/89359) + +```python +class Solution(object): + def reconstructQueue(self, people): + """ + :type people: List[List[int]] + :rtype: List[List[int]] + """ + people.sort(key=lambda (h, k): (-h, k)) + queue = [] + for p in people: + queue.insert(p[1], p) + return queue +``` + + diff --git a/docs/Algorithm/Leetcode/Python/412._fizz_buzz.md b/docs/Algorithm/Leetcode/Python/412._fizz_buzz.md new file mode 100644 index 00000000..76551be9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/412._fizz_buzz.md @@ -0,0 +1,68 @@ +### 412. Fizz Buzz + +题目: + + + +难度: +Easy + +一行 +```python +class Solution(object): + def fizzBuzz(self, n): + """ + :type n: int + :rtype: List[str] + """ + return [(not i%3)*"Fizz" + (not i%5)*"Buzz" or str(i) for i in range(1, n+1)] + +``` +```python +class Solution(object): + def fizzBuzz(self, n): + """ + :type n: int + :rtype: List[str] + """ + 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)] + +``` + + +就是easy,不过可以参见这里,有一些讨论 + + + +我觉得这里一个用yield的想法还蛮不错 +``` +# the fizbuz logic, returns an iterator object that +# calculates one value at a time, not all ot them at once +def fiz(numbers): + for i in numbers: + if i % 15 == 0: + yield 'fizbuz' + elif i % 5 == 0: + yield 'buz' + elif i % 3 == 0: + yield 'fiz' + else: + yield str(i) + +# xrange evaluates lazily, good for big numbers +# matches well with the lazy-eval generator function +numbers = xrange(1,2**20) + +# this gets one number, turns that one number into fuz, repeat +print ' '.join(fiz(numbers)) + +# returns: 1 2 fiz 4 buz fiz [...] fiz 1048573 1048574 fizbuz +``` +- clearly separates fizbuz logic from concatenation +- is as plain and readeable as possible +- generator iterator does not keep all the array in memory +- so that you can do it on arbitrary numbers (see Euler problem #10) + +What I do not like in this solution is the three ifs, whereas the problem can be solved with two. + +Answer: 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. diff --git a/docs/Algorithm/Leetcode/Python/413. Arithmetic Slices.md b/docs/Algorithm/Leetcode/Python/413. Arithmetic Slices.md new file mode 100644 index 00000000..6aff8c82 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/413. Arithmetic Slices.md @@ -0,0 +1,84 @@ +### 413. Arithmetic Slices + + + +题目: + + + + +难度 : Medium + + + +思路: + +tag 是DP + +数从 i 到 j 之间的这个arithmetic 数 + +我的方法时间复杂度比较高O(N^2),从 i 开始数它的arithmetic slice,每个i数一遍,到 j + +AC代码 + +``` +class Solution(object): + def numberOfArithmeticSlices(self, A): + """ + :type A: List[int] + :rtype: int + """ + n = len(A) + if n < 3: + return 0 + else: + res = 0 + for i in range(n-2): + for j in range(i+2,n): + if A[j] - A[j-1] == A[i+1] - A[i]: + res += 1 + else: + break + return res +``` + + + +应该可以优化到O(N) + +不需要每个每个开始数,可以边数边移动 + +可以参考 + + + +O(N) 代码 + +``` +class Solution(object): + def numberOfArithmeticSlices(self, A): + """ + :type A: List[int] + :rtype: int + """ + n = len(A) + if n < 3: + return 0 + else: + res, cnt = 0, 2 + for i in range(2, n): + if A[i] - A[i-1] == A[i-1] - A[i-2]: + print i, i-1, i-2 + cnt += 1 + else: + if cnt > 2: + res += (cnt-1) * (cnt-2) / 2 + cnt = 2 + if cnt > 2: res += (cnt-1) * (cnt-2) / 2 + return res + + +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/414._third_maximum_number.md b/docs/Algorithm/Leetcode/Python/414._third_maximum_number.md new file mode 100644 index 00000000..fc3652b9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/414._third_maximum_number.md @@ -0,0 +1,46 @@ +###414. Third Maximum Number + +题目: + + + +难度: + +Easy + + +思路: + +用三个变量来记录,max, secondmax, thirdmax, + +- 遇到比max还大的就更新,当前max降级为secondmax,当前secondmax降级为thirdmax +- 遇到比max小但是比secondmax大的也这样做降级处理 +- 更thirdmax + + +AC代码 + + +``` +class Solution(object): + def thirdMax(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + m, sm, tm = float('-inf'), float('-inf'), float('-inf') + + for num in nums: + if num > m: + tm = sm + sm = m + m = num + elif num < m and num > sm: + tm = sm + sm = num + elif num < m and num < sm and num > tm: + tm = num + + return tm if tm != float('-inf') else m +``` + diff --git a/docs/Algorithm/Leetcode/Python/415._add_strings.md b/docs/Algorithm/Leetcode/Python/415._add_strings.md new file mode 100644 index 00000000..95663f8e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/415._add_strings.md @@ -0,0 +1,45 @@ +# 415. Add Strings + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/add-strings/description/ + +> 内容描述 + +``` + +Given two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2. + +Note: + +The length of both num1 and num2 is < 5100. +Both num1 and num2 contains only digits 0-9. +Both num1 and num2 does not contain any leading zero. +You must not use any built-in BigInteger library or convert the inputs to integer directly. +``` + +## 解题方案 + +> 思路 1 + +题目说不能直接将input转换为int,那我就一次只转换一位,真tm简单! + +```python +class Solution(object): + def addStrings(self, num1, num2): + """ + :type num1: str + :type num2: str + :rtype: str + """ + def str2int(num): + res = 0 + for i in range(len(num)-1, -1, -1): + res += int(num[i]) * pow(10, len(num)-1-i) + return res + return str(str2int(num1) + str2int(num2)) +``` diff --git a/docs/Algorithm/Leetcode/Python/416._Partition_Equal_Subset_Sum.md b/docs/Algorithm/Leetcode/Python/416._Partition_Equal_Subset_Sum.md new file mode 100644 index 00000000..1dd92f5f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/416._Partition_Equal_Subset_Sum.md @@ -0,0 +1,65 @@ +# 416. Partition Equal Subset Sum +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/partition-equal-subset-sum/description/ + +> 内容描述 + +``` +Given 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. + +Note: +Each of the array element will not exceed 100. +The array size will not exceed 200. +Example 1: + +Input: [1, 5, 11, 5] + +Output: true + +Explanation: The array can be partitioned as [1, 5, 5] and [11]. +Example 2: + +Input: [1, 2, 3, 5] + +Output: false + +Explanation: The array cannot be partitioned into equal sum subsets. +``` + +## 解题方案 + +> 思路 1 + +动态规划 + +dp[i]代表nums中能否找出一个subset的sum等于i,例如dp[0] = True是必然的,因为我们只要取空子集,那么其sum一定为0 + +```python +class Solution(object): + def canPartition(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + if not nums or len(nums) == 0: + return True + if sum(nums) % 2 != 0: ## 总和必须为偶数,否则肯定无法取两个集合的sum相等 + return False + half_sum = sum(nums)/2 + dp = [False] * (half_sum+1) + dp[0] = True + for i in range(len(nums)): + for j in range(half_sum, nums[i]-1, -1): + dp[j] = dp[j] or dp[j-nums[i]] + print(dp) + return dp[half_sum] +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md b/docs/Algorithm/Leetcode/Python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md new file mode 100644 index 00000000..b0697b2a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md @@ -0,0 +1,74 @@ +### 421. Maximum XOR of Two Numbers in an Array + +题目: + + + +难度: + +Medium + +题目要求O(N)时间 + +看了半天的解法居然超时, +```python +class Solution(object): # 此法超时 +    def findMaximumXOR(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + '''The maxResult is a record of the largest XOR we got so far. if it's 11100 at i = 2, it means + before we reach the last two bits, 11100 is the biggest XOR we have, and we're going to explore + whether we can get another two '1's and put them into maxResult''' + max_res, mask = 0, 0 + + '''This is a greedy part, since we're looking for the largest XOR, we start + from the very begining, aka, the 31st postition of bits.''' + for i in range(32)[::-1]: + + '''The mask will grow like 100..000 , 110..000, 111..000, then 1111...111 + for each iteration, we only care about the left parts''' + mask |= (1 << i) + tmp = [] + for num in nums: + '''we only care about the left parts, for example, if i = 2, then we have + {1100, 1000, 0100, 0000} from {1110, 1011, 0111, 0010}''' + tmp.append(num & mask) + + '''if i = 1 and before this iteration, the maxResult we have now is 1100, + my wish is the maxResult will grow to 1110, so I will try to find a candidate + which can give me the greedyTry;''' + greedy_try = max_res | (1 << i) + + for i in tmp: + '''This is the most tricky part, coming from a fact that if a ^ b = c, then a ^ c = b; + now we have the 'c', which is greedyTry, and we have the 'a', which is leftPartOfNum + If we hope the formula a ^ b = c to be valid, then we need the b, + and to get b, we need a ^ c, if a ^ c exisited in our set, then we're good to go''' + if i ^ greedy_try in tmp: + max_res = greedy_try + '''If unfortunately, we didn't get the greedyTry, we still have our max, + So after this iteration, the max will stay at 1100.''' + return max_res +``` + + +只好想别的办法 + + +参考[stefan](https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/discuss/91050?page=3) +```python +class Solution(object): + def findMaximumXOR(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + answer = 0 + for i in range(32)[::-1]: + answer <<= 1 + prefixes = {num >> i for num in nums} + answer += any(answer^1 ^ p in prefixes for p in prefixes) + return answer +``` diff --git a/docs/Algorithm/Leetcode/Python/422. Valid Word Square.md b/docs/Algorithm/Leetcode/Python/422. Valid Word Square.md new file mode 100644 index 00000000..17cb1144 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/422. Valid Word Square.md @@ -0,0 +1,48 @@ +### 422. Valid Word Square + + + + + +题目: + + + + +难度 : Easy + + + +思路: + +就是对比一个矩阵内 xy == yx? + +try /except 真是好用 + +AC代码 + + + +``` +class Solution(object): + def validWordSquare(self, words): + """ + :type words: List[str] + :rtype: bool + """ + n = len(words) + for i in xrange(n): + m = len(words[i]) + for j in xrange(m): + try: + if words[i][j] != words[j][i]: + return False + except: + return False + return True +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/434._number_of_segments_in_a_string.md b/docs/Algorithm/Leetcode/Python/434._number_of_segments_in_a_string.md new file mode 100644 index 00000000..424472a5 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/434._number_of_segments_in_a_string.md @@ -0,0 +1,27 @@ +### 434. Number of Segments in a String + +题目: + + + +难度: + +Easy + + +作弊神器Python + + +```python +class Solution(object): + def countSegments(self, s): + """ + :type s: str + :rtype: int + """ + return len(s.split()) +``` + +不过对于比如C++这种语言来说,应该是O(N),扫一圈应该也能得到正确答案 + +总之拿Python做string的题目就是作弊啊 diff --git a/docs/Algorithm/Leetcode/Python/435._Non-overlapping_Intervals.md b/docs/Algorithm/Leetcode/Python/435._Non-overlapping_Intervals.md new file mode 100644 index 00000000..b9f6f1df --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/435._Non-overlapping_Intervals.md @@ -0,0 +1,95 @@ +# 435. Non-overlapping Intervals +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/non-overlapping-intervals/description/ + +> 内容描述 + +``` +Given a collection of intervals, find the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping. + +Note: +You may assume the interval's end point is always bigger than its start point. +Intervals like [1,2] and [2,3] have borders "touching" but they don't overlap each other. +Example 1: +Input: [ [1,2], [2,3], [3,4], [1,3] ] + +Output: 1 + +Explanation: [1,3] can be removed and the rest of intervals are non-overlapping. +Example 2: +Input: [ [1,2], [1,2], [1,2] ] + +Output: 2 + +Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping. +Example 3: +Input: [ [1,2], [2,3] ] + +Output: 0 + +Explanation: You don't need to remove any of the intervals since they're already non-overlapping. +``` + +## 解题方案 + +> 思路 1 + +先按照start排序,然后每次如果下一个的start小于前一个的end的时候意味着我们需要删掉一个了,但是我们尽量留下end比较小的那个Interval,具体看代码会比较清晰 + +```python +# Definition for an interval. +# class Interval(object): +# def __init__(self, s=0, e=0): +# self.start = s +# self.end = e + +class Solution(object): + def eraseOverlapIntervals(self, intervals): + """ + :type intervals: List[Interval] + :rtype: int + """ + if not intervals or len(intervals) == 0: + return 0 + res = 0 + intervals = sorted(intervals, key=lambda x:x.start) + cur_end = intervals[0].end + for i in range(1, len(intervals)): + if intervals[i].start < cur_end: #overlap + res += 1 + cur_end = min(intervals[i].end, cur_end) ## 尽量留下end小的Interval + else: + cur_end = intervals[i].end + return res +``` + +> 思路 2 + +又发现有大佬比我牛p多了,代码更nice,跟646题比较像 + +首先按照end排序,我们可以知道的,一旦后面一个Interval的start比前一个的end小的话,这个时候我们就需要删除掉当前的这个Interval, +反之则前面的那些Interval已经成立了,我们只需要更新cur_end为当前Interval的end + + +```python +class Solution(object): + def eraseOverlapIntervals(self, intervals): + """ + :type intervals: List[Interval] + :rtype: int + """ + intervals.sort(key = lambda x: x.end) + res, cur_end = 0, -float("inf") + for i in intervals: + if cur_end > i.start: res += 1 + else: cur_end = i.end + return res +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/437._path_sum_iii.md b/docs/Algorithm/Leetcode/Python/437._path_sum_iii.md new file mode 100644 index 00000000..ac5c314a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/437._path_sum_iii.md @@ -0,0 +1,39 @@ +### 437. Path Sum III + + + +题目: + + + +难度: +Easy + +思路: + + + + +```python +class Solution(object): + def pathSum(self, root, sum): + """ + :type root: TreeNode + :type sum: int + :rtype: int + """ + if not root: + return 0 + res = self.auxPathSum(root, sum) + res += self.pathSum(root.left, sum) + res += self.pathSum(root.right, sum) + return res + def auxPathSum(self, root, sum): + if not root: + return 0 + if sum == root.val: +            # 因为可能有负值, 所以sum为0也会有解, 必须加上 +            return 1 + self.auxPathSum(root.left, 0) + self.auxPathSum(root.right, 0) + else: + return self.auxPathSum(root.left, sum - root.val) + self.auxPathSum(root.right, sum - root.val) +``` diff --git a/docs/Algorithm/Leetcode/Python/438._Find_All_Anagrams_in_a_String.md b/docs/Algorithm/Leetcode/Python/438._Find_All_Anagrams_in_a_String.md new file mode 100644 index 00000000..2b851985 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/438._Find_All_Anagrams_in_a_String.md @@ -0,0 +1,92 @@ +### 438. Find All Anagrams in a String + + +题目: + + + +难度: + +Easy + + + +思路 + +刚开始打算直接遍历整个s,时间复杂度为O(m*n),m和n分别为字符串p和s的长度,但是超时了 + + + +``` + +class Solution(object): # 此法超时 +    def findAnagrams(self, s, p): + """ + :type s: str + :type p: str + :rtype: List[int] + """ + l, res = len(p), [] + for i in range(len(s)): + if collections.Counter(s[i:i+l]) == collections.Counter(p): + res.append(i) + return res +``` + +于是用双指针,left和right都从0开始往后遍历 +``` +class Solution(object): + def findAnagrams(self, s, p): + """ + :type s: str + :type p: str + :rtype: List[int] + """ + res, cnts = [], [0] * 26 + for c in p: + cnts[ord(c) - ord('a')] += 1 + left, right = 0, 0 + while right < len(s): + cnts[ord(s[right]) - ord('a')] -= 1 + while left <= right and cnts[ord(s[right]) - ord('a')] < 0: + cnts[ord(s[left]) - ord('a')] += 1 + left += 1 + if right - left + 1 == len(p): + res.append(left) + right += 1 + return res +``` +模板大法好 +```python +class Solution(object): + def findAnagrams(self, s, p): + """ + :type s: str + :type p: str + :rtype: List[int] + """ + res = [] + if len(p) > len(s): + return res + maps = collections.Counter(p) + counter = len(maps.keys()) + begin, end, head, length = 0, 0, 0, sys.maxint + while end < len(s): + if s[end] in maps: + maps[s[end]] -= 1 + if maps[s[end]] == 0: + counter -= 1 + end += 1 + while counter == 0: + if s[begin] in maps: + maps[s[begin]] += 1 + if maps[s[begin]] > 0: + counter += 1 + if end - begin == len(p): + res.append(begin) + begin += 1 + return res +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/439. Ternary Expression Parser.md b/docs/Algorithm/Leetcode/Python/439. Ternary Expression Parser.md new file mode 100644 index 00000000..065f56cd --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/439. Ternary Expression Parser.md @@ -0,0 +1,58 @@ +### 439. Ternary Expression Parser + + + + + +题目: + + + + +难度: +Medium + +思路: + +其实这个和算术运算蛮像,但是不同于运算,有operator precedence差别,这个是三目运算,并且需要检查是否符合运算规则。 + + + +运用stack 然后每次查看是否形成运算式再来做处理 + +AC代码: + +``` +class Solution(object): + def parseTernary(self, expression): + """ + :type expression: str + :rtype: str + """ + n = len(expression) + + stack = [] + + for i in range(n-1, -1, -1): + char = expression[i] + stack.append(char) + + if len(stack) >= 5: + op0 = stack.pop() + op1 = stack.pop() + op2 = stack.pop() + op3 = stack.pop() + op4 = stack.pop() + + if op1 == '?' and op3 == ':': + res = op2 if op0 == 'T' else op4 + stack.append(res) + else: + stack.append(op4) + stack.append(op3) + stack.append(op2) + stack.append(op1) + stack.append(op0) + return stack[0] +``` + diff --git a/docs/Algorithm/Leetcode/Python/441._arranging_coins.md b/docs/Algorithm/Leetcode/Python/441._arranging_coins.md new file mode 100644 index 00000000..5ef0dae9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/441._arranging_coins.md @@ -0,0 +1,29 @@ +###441. Arranging Coins + +题目: + + + +难度: +Easy + + +可以直接O(1),公式: + +i(i+1)/2 = n + +解i + +i = ( sqrt(8*n+1) -1 )/ 2 + + +``` +import math +class Solution(object): + def arrangeCoins(self, n): + """ + :type n: int + :rtype: int + """ + return int((math.sqrt( 8 * n + 1) - 1 )/ 2 ) +``` \ No newline at end of file diff --git a/docs/Algorithm/Leetcode/Python/448._Find_All_Numbers_Disappeared_in_an_Array.md b/docs/Algorithm/Leetcode/Python/448._Find_All_Numbers_Disappeared_in_an_Array.md new file mode 100644 index 00000000..b03105e6 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/448._Find_All_Numbers_Disappeared_in_an_Array.md @@ -0,0 +1,25 @@ +### 448. Find All Numbers Disappeared in an Array + +题目: + + + +难度: + +Easy + + + + + +```python +class Solution(object): + def findDisappearedNumbers(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + return list(set(range(1, len(nums)+1)) - set(nums)) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/450. Delete Node in a BST.md b/docs/Algorithm/Leetcode/Python/450. Delete Node in a BST.md new file mode 100644 index 00000000..3f622c90 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/450. Delete Node in a BST.md @@ -0,0 +1,62 @@ +### 450. Delete Node in a BST + + + +题目: + + +难度 : Medium + + + +思路: + +从二叉搜索树中删除节点x的方法如下: + +• 如果x没有子节点,或者只有一个孩子,直接将x“切下”; + +• 否则,x有两个孩子,我们用其右子树中的最小值替换掉x,然后将右子树中的这一最小值递归的“切掉”。 +​ + + + +AC代码 + + + +```python +class Solution(object): + def deleteNode(self, root, key): + """ + :type root: TreeNode + :type key: int + :rtype: TreeNode + """ + def findmin(root): + while root.left: + root = root.left + return root + + + if not root : return None + elif key < root.val: root.left = self.deleteNode(root.left, key) + elif key > root.val : root.right = self.deleteNode(root.right, key) + else: + if root.left and root.right: + tmp = findmin(root.right) + root.val = tmp.val + root.right = self.deleteNode(root.right, tmp.val) + else: + if not root.left: + root = root.right + elif not root.right: + root = root.left + return root +``` + +​ + + + +其实这个代码还是需要花点时间来理解,需要画个图,理解这个root是每个stack return回去然后被接在原来的树上的,if 这个node并不是在node左右。 + diff --git a/docs/Algorithm/Leetcode/Python/453._Minimum_Moves_to_Equal_Array_Elements.md b/docs/Algorithm/Leetcode/Python/453._Minimum_Moves_to_Equal_Array_Elements.md new file mode 100644 index 00000000..2e966808 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/453._Minimum_Moves_to_Equal_Array_Elements.md @@ -0,0 +1,72 @@ +### 453. Minimum Moves to Equal Array Elements + + + + + +题目: + + + + +难度 : Easy + + + +思路: + +naive TLE 代码: + +每次都是给并不是最大的元素加1直到全部相等。 + +``` +class Solution(object): + def minMoves(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + res = 0 + while(not all(x == nums[0] for x in nums)): + nums.sort() + for i in range(len(nums) - 1): + nums[i] += 1 + res += 1 + + return res +``` + + + +给的测试例子是 `[1,2147483647]`能不TLE么?tag 是Math,所以要用观察到的结果来做吧? + +所以就是每个和最小值来比,看到底要增加多少,这是观察,但不是证明 + + + + + +AC代码 + +```python +class Solution(object): + def minMoves(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + res = 0 + minVal = min(nums) + for num in nums: + res += num -minVal + return res +``` + + + +类证明: + + + +> 其实给n-1个数字加1,效果等同于给那个未被选中的数字减1,比如数组[1,2,3], 给除去最大值的其他数字加1,变为[2,3,3],我们全体减1,并不影响数字间相对差异,变为[1,2,2],这个结果其实就是原始数组的最大值3自减1,那么问题也可能转化为,将所有数字都减小到最小值,这样难度就大大降低了,我们只要先找到最小值,然后累加每个数跟最小值之间的差值即可 + diff --git a/docs/Algorithm/Leetcode/Python/459._Repeated_Substring_Pattern.md b/docs/Algorithm/Leetcode/Python/459._Repeated_Substring_Pattern.md new file mode 100644 index 00000000..f32b6eb4 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/459._Repeated_Substring_Pattern.md @@ -0,0 +1,31 @@ +### 459. Repeated Substring Pattern + + +题目: + + + +难度: + +Easy + + +思路 + +- 如果存在这样的子串,那么子串的第一个字符和最后一个字符肯定跟父字符串```s```的相同。 +- 因此构建一个新字符串```s*2```(两个父字符串相加),去掉首尾字符 +- 如果此时能在其中找到```s```,说明存在这样的子串 + + + + +```python +class Solution(object): + def repeatedSubstringPattern(self, s): + """ + :type s: str + :rtype: bool + """ + return (s*2)[1:-1].find(s) != -1 +``` + diff --git a/docs/Algorithm/Leetcode/Python/461._Hamming Distance.md b/docs/Algorithm/Leetcode/Python/461._Hamming Distance.md new file mode 100644 index 00000000..4a8d63d8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/461._Hamming Distance.md @@ -0,0 +1,66 @@ +### 461. Hamming Distance + + + +题目: + 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*. +> +> + + + +一行无敌 +```python +class Solution(object): + def hammingDistance(self, x, y): + """ + :type x: int + :type y: int + :rtype: int + """ + return bin(x^y).count('1') +``` +AC代码 + +```python +class Solution(object): + def hammingDistance(self, x, y): + """ + :type x: int + :type y: int + :rtype: int + """ + dist = 0 + val = x ^ y + + while val: + dist += 1 + val &= val - 1 + + return dist +``` + + + + + diff --git a/docs/Algorithm/Leetcode/Python/463._Island_Perimeter.md b/docs/Algorithm/Leetcode/Python/463._Island_Perimeter.md new file mode 100644 index 00000000..bedc5f8a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/463._Island_Perimeter.md @@ -0,0 +1,38 @@ +### 463. Island Perimeter + + + +题目: + + + +难度: +Easy + +思路: + + + + +```python +class Solution(object): + def islandPerimeter(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + # 每一个陆地单元格的周长为4,当两单元格上下或者左右相邻时,令周长减2 + h = len(grid) + w = len(grid[0]) if h else 0 + ans = 0 + for x in range(h): + for y in range(w): + if grid[x][y] == 1: + ans += 4 + # 因为x+1还在后面,所以不需要考虑,即只需要考虑左边和上边,因为循环已经出现过该点了 + if x > 0 and grid[x - 1][y]: + ans -= 2 + if y > 0 and grid[x][y - 1]: + ans -= 2 + return ans +``` diff --git a/docs/Algorithm/Leetcode/Python/467._Unique_Substrings_in_Wraparound_String.md b/docs/Algorithm/Leetcode/Python/467._Unique_Substrings_in_Wraparound_String.md new file mode 100644 index 00000000..85c7a9d9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/467._Unique_Substrings_in_Wraparound_String.md @@ -0,0 +1,42 @@ +### 467. Unique Substrings in Wraparound String + +题目: + + + +难度: + +Medium + + +思路: + +有个无限长的字符串s,是由无数个「abcdefghijklmnopqrstuvwxyz」组成的。现在给你一个字符串p,求多少个p的非空子串在s中出现了? +   + +先考虑s的特性,满足条件(在s中)的p的子串只可能是abcd……z的连续序列(z后面是a), 我们只需要处理p中连续的部分就可以了。但是 举个例子,h-k的序列出现了,a-z的序列也出现了,那么只需要计算a-z的子串个数就可以了,因为h-k已经包含在a-z里了。考虑所有包含的情况,似乎就变得复杂了,a-z还可能被包含在x-za-z中,甚至更长的序列中。 + +  但是如果考虑以某个字母结尾的子串个数,那么p中以该字母结尾的连续序列长度,就是满足条件的子串个数。如果以字母x结尾的连续序列有多个, 我们只需要最长的一个即可,因为其他短的序列都已经被长的包含进去了,例如'bcd'和'abcd',有了'abcd'就知道以d结尾的子串有4个,分别是‘d’,'cd','bcd','abcd',‘bcd’已经被包含进去了。最后求和,问题就解决了。 这样思考就非常简单了,代码也可以很容易写出来。 + + + +```python +class Solution(object): + def findSubstringInWraproundString(self, p): + """ + :type p: str + :rtype: int + """ +        letters = [0] * 26         #开始默认每个都是0 +        length = 0 + for i in range(len(p)): + curr = ord(p[i]) - ord('a') +            if i > 0 and ord(p[i-1]) != (curr-1)%26 + ord('a'):   #一旦开始不相等了就要将length重置为0 +                length = 0 +            length += 1     #否则就说明继续与前面一个字符是连续的,length要加1才行 +            if length > letters[curr]:     #length一直加,如果到i这个字符length比它的目前的最大连续子串长度还要长,那么肯定要更新letters +                letters[curr] = length + return sum(letters) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/469. Convex Polygon.md b/docs/Algorithm/Leetcode/Python/469. Convex Polygon.md new file mode 100644 index 00000000..2afb7d07 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/469. Convex Polygon.md @@ -0,0 +1,88 @@ +### 469. Convex Polygon + + + +题目: + 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. +> +> 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): +> +> +> +> 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: +> +> The polygon is convex if the z-components of the cross products are either all positive or all negative. Otherwise the polygon is nonconvex. +> +> given p[k], p[k+1], p[k+2] each with coordinates x, y: +> +>  dx1 = x[k+1]-x[k] +> +>  dy1 = y[k+1]-y[k] +> +>  dx2 = x[k+2]-x[k+1] +> +>  dy2 = y[k+2]-y[k+1] +> +>  zcrossproduct = dx1 * dy2 - dy1 * dx2 +> +> 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]). + + + +所以根据这个答案AC代码 + +``` +class Solution(object): + def isConvex(self, points): + """ + :type points: List[List[int]] + :rtype: bool + """ + n = len(points) + zcrossproduct = None + + for i in range(-2, n-2): + x = [ points[i][0], points[i+1][0], points[i+2][0] ] + y = [ points[i][1], points[i+1][1], points[i+2][1] ] + + dx1 = x[1] - x[0] + dy1 = y[1] - y[0] + + dx2 = x[2] - x[1] + dy2 = y[2] - y[1] + + if not zcrossproduct: + zcrossproduct = dx1 * dy2 - dy1 * dx2 + elif ( dx1 * dy2 - dy1 * dx2 ) * zcrossproduct < 0: + return False + return True +``` + diff --git a/docs/Algorithm/Leetcode/Python/476._Number_Complement.md b/docs/Algorithm/Leetcode/Python/476._Number_Complement.md new file mode 100644 index 00000000..91b25397 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/476._Number_Complement.md @@ -0,0 +1,28 @@ +### 476. Number Complement + + + +题目: + + + +难度: +Easy + + + + + +```python +class Solution(object): + def findComplement(self, num): + """ + :type num: int + :rtype: int + """ + i = 1 << (len(bin(num)) -2) # 因为bin函数转化成的格式是‘0bXXXX’,头两个‘0b’要减掉去 + return (i - 1) ^ num + # return (i - 1) - num # 这样也可以 +``` + + diff --git a/docs/Algorithm/Leetcode/Python/477._Total_Hamming_Distance.md b/docs/Algorithm/Leetcode/Python/477._Total_Hamming_Distance.md new file mode 100644 index 00000000..cf5bc54a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/477._Total_Hamming_Distance.md @@ -0,0 +1,82 @@ +### 477. Total Hamming Distance + + + +题目: + + + +难度: +Medium + +思路: + + +第一想法就是暴力,直接超时 + +``` +class Solution(object): # 此法超时 + def totalHammingDistance(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + res = 0 + for i in range(len(nums)): + for j in range(i+1, len(nums)): + res += bin(nums[i]^nums[j]).count('1') + return res +``` + + +前面的解法是```O(n^2)```所以超时,所以我们想想有没有```O(n)```的解法 +对于所有的数字,我们先从右数第一位开始算,如果一共有```n```个数字,其中```k```个数字的右数第一位是```‘1’```,其他```n-k```个数字的右数第一位是```‘0’```, +所以这一位对最终```res```的贡献就是```k*(n-k)```,这样我们的时间复杂度就是```O(32n)```,也就是```O(N)```了 + +``` +for each “column” or bit position, once you count the number of set bits you can figure out the number of pairs +that will contribute to the count using combination logic. + +Consider you have 10 numbers and only one of them is a 1 the rest are zeros. How many (1, 0) pairs can you make? +Clearly you can make 9, pair the 1 with each of the other 9 zeros. If you have 2 ones, +you can pair each of those with the other 8 zeros giving 2*8 = 16. +Keep 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. + +This would be an O(32 * n) solution which is an O(n) solution, no space used. +``` + +AC代码 + +```python +class Solution(object): + def totalHammingDistance(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + # iterate thru "column" or bit position + # Note: you could stop at 10^9 as stated in the problem if you want to optimize + res = 0 + for i in range(32): + mask = 1 << i + count_ones, count_zeros = 0, 0 + for num in nums: + if num & mask != 0: + count_ones += 1 + else: + count_zeros += 1 + res += count_ones * count_zeros + return res +``` + +上面的代码简化一下就是[stefan大神(老流氓罒ω罒)](https://leetcode.com/problems/total-hamming-distance/discuss/96229)的无敌一行了 + +```python +class Solution(object): # 此法超时 + def totalHammingDistance(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return sum(b.count('0') * b.count('1') for b in zip(*map('{:032b}'.format, nums))) +``` diff --git a/docs/Algorithm/Leetcode/Python/485._Max_Consecutive_Ones.md b/docs/Algorithm/Leetcode/Python/485._Max_Consecutive_Ones.md new file mode 100644 index 00000000..422a70c9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/485._Max_Consecutive_Ones.md @@ -0,0 +1,40 @@ +### 485. Max Consecutive Ones + + + +题目: + + + +难度: +Easy + +思路: + + +一行无敌 +```python +class Solution(object): + def findMaxConsecutiveOnes(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return len(max(''.join(map(str, nums)).split('0'))) +``` + +```python +class Solution(object): + def findMaxConsecutiveOnes(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + res, count = [], 0 + for x in nums: + count = 0 if x == 0 else count + 1 + res.append(count) + return max(res) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/494._Target_Sum.md b/docs/Algorithm/Leetcode/Python/494._Target_Sum.md new file mode 100644 index 00000000..e9f1a959 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/494._Target_Sum.md @@ -0,0 +1,112 @@ +# 494. Target Sum +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/target-sum/description/ + +> 内容描述 + +``` +You 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. + +Find out how many ways to assign symbols to make sum of integers equal to target S. + +Example 1: +Input: nums is [1, 1, 1, 1, 1], S is 3. +Output: 5 +Explanation: + +-1+1+1+1+1 = 3 ++1-1+1+1+1 = 3 ++1+1-1+1+1 = 3 ++1+1+1-1+1 = 3 ++1+1+1+1-1 = 3 + +There are 5 ways to assign symbols to make the sum of nums be target 3. +Note: +The length of the given array is positive and will not exceed 20. +The sum of elements in the given array will not exceed 1000. +Your output answer is guaranteed to be fitted in a 32-bit integer. +``` + +## 解题方案 + +> 思路 1 + +递归,findSum(s, start_idx) 函数的意思是从start_index开始向后的子集合能有几种得到s的方法 + +``` +class Solution(object): + def findTargetSumWays(self, nums, S): + """ + :type nums: List[int] + :type S: int + :rtype: int + """ + def findSum(s, start_idx): + if start_idx == len(nums): + return 1 if s == 0 else 0 + return findSum(s+nums[start_idx], start_idx+1) + findSum(s-nums[start_idx], start_idx+1) + return findSum(S, 0) +``` + +但是这样会超时,所以用cache 记一下 + +```python +class Solution(object): + def findTargetSumWays(self, nums, S): + """ + :type nums: List[int] + :type S: int + :rtype: int + """ + def findSum(s, start_idx): + if start_idx == len(nums): + return 1 if s == 0 else 0 + if (s, start_idx) not in cache: + cache[(s, start_idx)] = findSum(s+nums[start_idx], start_idx+1) + findSum(s-nums[start_idx], start_idx+1) + return cache[(s, start_idx)] + + cache = {} + return findSum(S, 0) +``` + +> 思路 2 + +首先我们要找到一个集合 X 的正sum和其补集 Y 的负sum之和为target. +- 则有 sum(X) - sum(Y) = target +- 又有 sum(X) + sum(Y) = sum(nums) +- ---> 因此由 1 式和 2 式证得:sum(X) = (sum(nums) + target) / 2 + +因此题目就变成了找到了一个subset的正sum为(sum(nums) + target) / 2 + +于是动态规划,利用[leetcode416题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/416._Partition_Equal_Subset_Sum.md)的思想 + +但是这次dp[i]代表的是能够找出几个subset的sum等于i, 例如dp[0] = 1是必然的,因为我们只能取空子集,才能得到sum为0 + +```python +class Solution(object): + def findTargetSumWays(self, nums, S): + """ + :type nums: List[int] + :type S: int + :rtype: int + """ + def subsetSum(s): + dp = [0] * (s+1) + dp[0] = 1 + for i in range(len(nums)): + for j in range(s, nums[i]-1, -1): + dp[j] += dp[j-nums[i]] + return dp[-1] + + if sum(nums) < S or (S+sum(nums)) % 2 > 0: + return 0 + return subsetSum((S+sum(nums))/2) +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/536._Construct_Binary_Tree_from_String.md b/docs/Algorithm/Leetcode/Python/536._Construct_Binary_Tree_from_String.md new file mode 100644 index 00000000..3f000278 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/536._Construct_Binary_Tree_from_String.md @@ -0,0 +1,73 @@ +# 536. Construct Binary Tree from String +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/construct-binary-tree-from-string/description/ + +> 内容描述 + +``` +You need to construct a binary tree from a string consisting of parenthesis and integers. + +The 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. + +You always start to construct the left child node of the parent first if it exists. + +Example: +Input: "4(2(3)(1))(6(5))" +Output: return the tree root node representing the following tree: + + 4 + / \ + 2 6 + / \ / + 3 1 5 +Note: +There will only be '(', ')', '-' and '0' ~ '9' in the input string. +An empty tree is represented by "" instead of "()". +``` + +## 解题方案 + +> 思路 1 + +递归,每次先找到左子树,然后判断有无右子树,继续下去 + +```python +class Solution(object): + def str2tree(self, s): + """ + :type s: str + :rtype: TreeNode + """ + if not s or len(s) == 0: + return None + if '(' not in s: + return TreeNode(int(s)) + + def paren_pair_idx(s): + paren_count = 0 + for i in range(len(s)): + if s[i] == '(': + paren_count += 1 + elif s[i] == ')': + paren_count -= 1 + if paren_count == 0 and i > s.find('('): + return (s.find('('), i) + + root = TreeNode(int(s[:s.find('(')])) + (paren_left, paren_right) = paren_pair_idx(s) + root.left = self.str2tree(s[paren_left+1: paren_right]) + if paren_right < len(s) - 1: + root.right = self.str2tree(s[paren_right+2:-1]) + else: + root.right = None + return root +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/587._Erect_the_Fence .md b/docs/Algorithm/Leetcode/Python/587._Erect_the_Fence .md new file mode 100644 index 00000000..f61d75b3 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/587._Erect_the_Fence .md @@ -0,0 +1,133 @@ + + +### 587. Erect the Fence + + +题目: + + + +难度: + +Hard + + + +思路 + +题目要求用一个围栏把所有的点(🌲)围起来,然后求处于围栏上点(🌲)的集合。 + +我们可以发现,从最左边的那个点一直往右走,只要一直都是走的逆时针方向,那么我们一定可以找到这条围栏。那么接下来就考虑最简单的情况, + +- 只有两个点```p```和```q```,我们从```p```走到```q```,当```p```到原点这条直线的斜率小于```q```到原点这条直线的斜率时,```p->q```就是沿逆时针方向走的; +- 接下来考虑3个点:```p,q,r```,以```p```为参照点(即前面的原点),那么从```q```走到```r```的时候,只要```q```到```q```这条直线的斜率小于```r```到```p```这条直线的斜率,```q->r```就是沿逆时针方向走的。 + +因此,我们只要构建一个```orientation```函数,就可以判断出目前我们的围栏是不是沿着逆时针在走下去了。 + +我们用一个```stack```来存放目前认为在围栏上的点的集合,然后把所有的点按照指定规则排好序:```先按照点的x坐标升序排列,如果x相等则按照点的y坐标升序排列```。这样我们依次取点,只要```stack```里面的点大于等于```2```个我们就要无限进行判断是否走的是逆时针,如果不是就把```stack```里面最后那个点```pop```出去(可能一直```pop```到只剩一个点),否则就把目前的这个点加入到```stack```中去,因为目前它还是在逆时针方向上的。 + +从左往右走完一遍```points```之后,我们围栏的下部分```lower hull```就构建好了,此时我们还要构建围栏的```upper hull```,因此我们将```points```逆序一下,从右往左再来一次遍历,仍然看是否走的是逆时针。但是这次遍历我们需要进行一个判断,就是之前放进```stack```的点,此时我们还是会经过它,如果它已经在```stack```里面了,我们就不需要再加进去了,同时这样也避免了我们把最左边的点重复加进去。 + + + +```python +python +# import functools +class Solution: + def outerTrees(self, points): + """ + :type points: List[Point] + :rtype: List[Point] + """ + def orientation(p, q, r): + return (q.y - p.y)*(r.x - p.x) - (r.y - p.y)*(q.x - p.x) + # def myComparator(p,q): + # return p.x - q.x if p.x != q.x else p.y - q.y + stack= [] + # points.sort(key = functools.cmp_to_key(myComparator)) + points.sort(key = lambda p: (p.x, p.y)) + for i in range(len(points)): + while (len(stack) >= 2 and orientation(stack[-2],stack[-1],points[i]) > 0): + stack.pop() + stack.append(points[i]) + points.reverse(); + for i in range(len(points)): + while (len(stack) >= 2 and orientation(stack[-2],stack[-1],points[i]) > 0): + stack.pop() + if points[i] not in stack: + stack.append(points[i]) + return stack +``` +简化python版本 +```python +class Solution(object): + def outerTrees(self, points): + """ + :type points: List[Point] + :rtype: List[Point] + """ + def orientation(p, q, r): + return (q.y - p.y) * (r.x - q.x) - \ + (q.x - p.x) * (r.y - q.y) + + hull = [] + points.sort(key=lambda p: (p.x, p.y)) + + for i in itertools.chain(xrange(len(points)), \ + reversed(xrange(len(points)))): + while len(hull) >= 2 and \ + orientation(hull[-2], hull[-1], points[i]) > 0: + hull.pop() + hull.append(points[i]) + + return list(set(hull)) +``` + +下面是小傅大神的代码,本来想叫‘’傅神‘’的,结果这名字🤦‍♂️(手动捂脸)[小傅每日一题587](https://www.bilibili.com/video/av15446980/) + +另外其中的```stack.pop()```这行代码注释掉也是可以的 + +```java +java +class Solution { + public List outerTrees(Point[] points) { + List res = new ArrayList(); + Arrays.sort(points, new Comparator(){ + @Override + public int compare(Point p, Point q){ + return p.x == q.x ? p.y - q.y : p.x - q.x; + } + }); + Stack stack = new Stack<>(); + for (int i = 0; i < points.length; i++){ + while(stack.size() >= 2 && orientation(stack.get(stack.size() - 2), stack.peek(), points[i]) > 0){ + stack.pop(); + } + stack.push(points[i]); + } + //stack.pop(); + for (int i = points.length - 1; i >= 0; i--){ + while(stack.size() >= 2 && orientation(stack.get(stack.size() - 2), stack.peek(), points[i]) > 0){ + stack.pop(); + } + stack.push(points[i]); + } + res.addAll(new HashSet<>(stack)); + return res; + } + + public int orientation(Point p, Point q, Point r){ + return (q.y - p.y)*(r.x - p.x) - (r.y - p.y)*(q.x - p.x); + } +} +``` + + + + + +Author: Keqi Huang + +If you like it, please spread your support + +![Support](https://github.com/Lisanaaa/myTODOs/blob/master/WechatIMG17.jpeg) diff --git a/docs/Algorithm/Leetcode/Python/599._Minimum_Index_Sum_of_Two_Lists.md b/docs/Algorithm/Leetcode/Python/599._Minimum_Index_Sum_of_Two_Lists.md new file mode 100644 index 00000000..1682fab6 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/599._Minimum_Index_Sum_of_Two_Lists.md @@ -0,0 +1,58 @@ +### 599. Minimum Index Sum of Two Lists + + +题目: + + + +难度: + +Easy + + + +思路 + +两个list,我们首先要取得它们相同的部分,并且之后我们还要知道哪个相同的字符串在两个list中的index之和是最小的。 +- 所以我们首先遍历list1,只要目前这个字符串在list2中,我们就以[字符串,index之和]的形式将其存放到ress中,同时维护一个index保持为最小index之和的值 +- 对于ress,我们遍历,只要某一项的index之和等于最小index之和我们就将他的字符串以i[0]的形式append到res中去, +- return res + +### 程序变量解释 + +- ress format: [[string1, sumOfIndex1], [string2, sumOfIndex2]... ] +- index 最小sunOfIndex值 +- res 最终结果,foramt: [string1, string2,. ...] + + + + +```python +python +class Solution: + def findRestaurant(self, list1, list2): + """ + :type list1: List[str] + :type list2: List[str] + :rtype: List[str] + """ + ress = [] + index = 2000 + for i in list1: + if i in list2: + ress.append([i, list1.index(i)+list2.index(i)]) + index = min(index, list1.index(i)+list2.index(i)) + res = [] + for i in ress: + if i[1] == index: + res.append(i[0]) + return res +``` + + + +Author: Keqi Huang + +If you like it, please spread your support + +![Support](https://github.com/Lisanaaa/myTODOs/blob/master/WechatIMG17.jpeg) diff --git a/docs/Algorithm/Leetcode/Python/606._Construct_String_from_Binary_Tree.md b/docs/Algorithm/Leetcode/Python/606._Construct_String_from_Binary_Tree.md new file mode 100644 index 00000000..df0b8af4 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/606._Construct_String_from_Binary_Tree.md @@ -0,0 +1,71 @@ +# 606. Construct String from Binary Tree +**难度: 简单** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/construct-string-from-binary-tree/description/ + +> 内容描述 + +``` +You need to construct a string consists of parenthesis and integers from a binary tree with the preorder traversing way. + +The 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. + +Example 1: +Input: Binary tree: [1,2,3,4] + 1 + / \ + 2 3 + / + 4 + +Output: "1(2(4))(3)" + +Explanation: Originallay it needs to be "1(2(4)())(3()())", +but you need to omit all the unnecessary empty parenthesis pairs. +And it will be "1(2(4))(3)". +Example 2: +Input: Binary tree: [1,2,3,null,4] + 1 + / \ + 2 3 + \ + 4 + +Output: "1(2()(4))(3)" + +Explanation: Almost the same as the first example, +except we can't omit the first parenthesis pair to break the one-to-one mapping relationship between the input and the output. +``` + +## 解题方案 + +> 思路 1 + +递归 + +```python +class Solution(object): + def tree2str(self, t): + """ + :type t: TreeNode + :rtype: str + """ + if not t: + return '' + res = str(t.val) + if t.left and t.right: + res += '(' + self.tree2str(t.left) + ')' + '(' + self.tree2str(t.right) + ')' + elif not t.left and t.right: + res += '()(' + self.tree2str(t.right) + ')' + elif t.left and not t.right: + res += '(' + self.tree2str(t.left) + ')' + return res +``` + + + + diff --git a/docs/Algorithm/Leetcode/Python/611._Valid_Triangle_Number.md b/docs/Algorithm/Leetcode/Python/611._Valid_Triangle_Number.md new file mode 100644 index 00000000..f17d298e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/611._Valid_Triangle_Number.md @@ -0,0 +1,102 @@ +# 611. Valid Triangle Number 有效三角形的个数 + +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/valid-triangle-number/description/ +* https://leetcode-cn.com/problems/valid-triangle-number/description/ + +> 内容描述 + +``` +给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。 + +示例 1: + +输入: [2,2,3,4] +输出: 3 +解释: +有效的组合是: +2,3,4 (使用第一个 2) +2,3,4 (使用第二个 2) +2,2,3 +注意: + +数组长度不超过1000。 +数组里整数的范围为 [0, 1000]。 +``` + +## 解题方案 + +> 思路 1 + +明确一点,三角形三边为a, b, c,那么何时满足可以组成一个三角形呢? +要同时满足以下3点: +1. a + b > c +2. a + c > b +3. b + c > a + +首先对数组逆向排序,固定第一个数字,我们发现```nums[i] >= nums[j] >= nums[k]```, +所以我们现在只需要保证```nums[j] + nums[k] > nums[i]```即可, +因为```nums[i] + nums[j] > nums[k]```和```nums[i] + nums[k] > nums[j]```是肯定的 + +后面开始二分,分两种情况: +- 如果```nums[j] + nums[k] > nums[i]```,那么我们只需要将```j += 1```使得比较式前面变小继续判断, +并且```res += k - j```,因为组合```i, j, [j+1...k]```都可以满足比较式,我们需要全部加起来,后面不会再次判断了 +- 如果```nums[j] + nums[k] <= nums[i]```,那么我们只需要将```k -= 1```使得比较式前面变大继续判断是否满足比较式 + + +```python +class Solution(object): + def triangleNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + nums = sorted(nums)[::-1] + res = 0 + for i in range(len(nums)-2): + j, k = i + 1, len(nums) - 1 + while j < k: + if nums[k] + nums[j] > nums[i]: + res += k - j + j += 1 + else: + k -= 1 + return res +``` +这里真的我遇到了两次坑,首先如果我们排序用的是正向排序的话,那么我们需要做的是固定最后一个数,否则会出现(假如固定第一个数): +- 等式满足,我们将```j -= 1``,那么就有可能漏掉了一种情况,就是原本组合```i, j, [j+1...k-1]```可以满足,但是我们这里没有加上 +- 等式满足,我们将```k += 1``,那么就有可能漏掉了一种情况,就是原本组合```i, [j+1...k-1], k```可以满足,但是我们这里没有加上 + +所以二分法真的没有那么简单,我们需要充分根据实际场景去改变我们的固定位置和前后更新方向 + +这里也给出正向排序的代码: + + +```python +class Solution(object): + def triangleNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + nums.sort() + res = 0 + for k in range(len(nums)-1, 1, -1): + i, j = 0, k - 1 + while i < j: + if nums[i] + nums[j] > nums[k]: + res += j - i + j -= 1 + + else: + i += 1 + return res +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/646._Maximum_Length_of_Pair_Chain.md b/docs/Algorithm/Leetcode/Python/646._Maximum_Length_of_Pair_Chain.md new file mode 100644 index 00000000..a294701e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/646._Maximum_Length_of_Pair_Chain.md @@ -0,0 +1,124 @@ +# 646. Maximum Length of Pair Chain +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/maximum-length-of-pair-chain/description/ + +> 内容描述 + +``` +You are given n pairs of numbers. In every pair, the first number is always smaller than the second number. + +Now, 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. + +Given 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. + +Example 1: +Input: [[1,2], [2,3], [3,4]] +Output: 2 +Explanation: The longest chain is [1,2] -> [3,4] +Note: +The number of given pairs will be in the range [1, 1000]. +``` + +## 解题方案 + +> 思路 1 + +先按照start --> end中的end排序,即```pairs = sorted(pairs, key=lambda x:x[1])``` + +原因在于,你想想看,如果我们已经取得了最长的那一条序列,end最小的那个pair肯定在里面对不对? +如果你说不对,那假设它不在里面,现在max_chain的第一个pair是不是至少可以被end最小的那个pair替代,因为我的end比你更小,你都可以我为什么不可以,甚至如果我的 +end比你的start小的话,我还可以加在你前面呢,这样max_chain岂不是就不是最长的chain了? + +综上所述,我们只要先按照start --> end中的end排序,然后从第一个慢慢向下判断就行,如果不符合就跳过,符合我们就把长度加1,这样最后肯定是对的。 + +AC代码如下: + + +```python +class Solution(object): + def findLongestChain(self, pairs): + """ + :type pairs: List[List[int]] + :rtype: int + """ + if not pairs or len(pairs) == 0: + return 0 + pairs = sorted(pairs, key=lambda x:x[1]) + res, i = 0, -1 + while i + 1 < len(pairs): + res += 1 + i += 1 + cur_end = pairs[i][1] + while i + 1 < len(pairs) and pairs[i+1][0] <= cur_end: + i += 1 + return res +``` + +发现有大佬比我牛p多了,代码更nice + +```python +class Solution(object): + def findLongestChain(self, pairs): + """ + :type pairs: List[List[int]] + :rtype: int + """ + if not pairs or len(pairs) == 0: + return 0 + cur, res = float('-inf'), 0 + for p in sorted(pairs, key=lambda x: x[1]): + if cur < p[0]: cur, res = p[1], res + 1 + return res +``` + + + + +> 思路 2 + +动态规划 + +思路看代码就理解了,不宜多说 + + + +``` +class Solution(object): + def findLongestChain(self, pairs): + """ + :type pairs: List[List[int]] + :rtype: int + """ + if not pairs or len(pairs) == 0: + return 0 + pairs = sorted(pairs, key=lambda x:x[0]) + dp = [1] * len(pairs) + for i in range(1, len(pairs)): + for j in range(i): + dp[i] = max(dp[i], dp[j] + 1 if pairs[i][0] > pairs[j][1] else dp[j]) + return dp[-1] +``` +这样会超时,不知道为啥,然后改了下代码的写法就过了,beats 2.21% 哈哈哈哈哈, 管它呢,过了就行,代码如下: + +```python +class Solution(object): + def findLongestChain(self, pairs): + """ + :type pairs: List[List[int]] + :rtype: int + """ + if not pairs or len(pairs) == 0: + return 0 + pairs = sorted(pairs, key=lambda x:x[0]) + dp = [1] * len(pairs) + for i in range(1, len(pairs)): + dp[i] = max([dp[j] + 1 if pairs[i][0] > pairs[j][1] else dp[j] for j in range(i)]) + return dp[-1] +``` + + diff --git a/docs/Algorithm/Leetcode/Python/647._Palindromic_Substrings.md b/docs/Algorithm/Leetcode/Python/647._Palindromic_Substrings.md new file mode 100644 index 00000000..8ee312ad --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/647._Palindromic_Substrings.md @@ -0,0 +1,89 @@ +### 647. Palindromic Substrings + +题目: + + + +难度: + +Medium + + +思路 + +这道题要求给定一个字符串中的所有回文子串的个数,所以我想到了Manacher算法, +[Manacher算法](https://www.felix021.com/blog/read.php?2040) + +Manacher算法增加两个辅助变量id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。得到一个很重要的结论: + +- 如果mx > i,那么P[i] >= Min(P[2 * id - i], mx - i) . 为什么这样说呢,下面解释 + +下面,令j = 2*id - i,也就是说j是i关于id的对称点。 + +- 当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于i和j对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有P[i] = P[j]; +![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher1.png) + +- 当 P[j] >= mx - i 的时候,以S[j]为中心的回文子串不一定完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,再具体匹配。 +![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher2.png) +所以P[i] >= Min(P[2 * id - i], mx - i),因为以j为中心的绘回文子串的左边界可能会比mx关于id的对称点要大,此时只能证明P[i]=P[2 * id - i] +- 此外,对于 mx <= i 的情况,因为无法对 P[i]做更多的假设,只能让P[i] = 1,然后再去匹配。 +此题还可以借鉴我leetcode第5题的解析, +[thining-in-lc-5](https://github.com/Lisanaaa/thinking_in_lc/blob/master/005._longest_palindromic_substring.md) + +这道题的基本思想是将以每一个字符为中心的回文子串个数相加,还是用一个小例子来解释 +![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher3.jpg) +其实,以‘#’为中心的回文子串就代表这个子串的长度是偶数,类似于'abba'这种 +但是其实这个字符本身也是一个回文子串,所以叠加的形式是count += (P[i]+1)/2,为什么呢,以下是解释: +- 对于每一个以字符‘#’为中心的回文子串,其P值绝对是偶数,所以```(P[i]+1)/2 = P[i]/2```,并不影响 +- 对于每一个以非字符‘#’为中心的回文子串,其P值绝对是奇数,这就保证了单个字母的回文子串(```例如'a'也算一个回文子串```)也被加起来了,因为```(P[i]+1)/2 = P[i]/2+1``` + + +```python +class Solution(object): + def countSubstrings(self, s): + """ + :type s: str + :rtype: str + """ + def preProcess(s): + if not s: + return ['^', '$'] + T = ['^'] + for c in s: + T += ['#', c] + T += ['#', '$'] + return T + T = preProcess(s) + P = [0] * len(T) + id, mx, count = 0, 0, 0 + for i in range(1,len(T) - 1): + j = 2*id - i + if mx > i: + P[i] = min(mx - i, P[j]) + else: + P[i] = 0 + while T[i+P[i]+1] == T[i-P[i]-1]: + P[i] += 1 + if (i + P[i]) > mx: + id, mx = i, i + P[i] + for i in range(len(P)): + count += (P[i]+1)/2 + return count +``` +python无敌啊!!!有没有天理啊,手动滑稽😏😏😏😏!一行解法: +```python +class Solution(object): + def countSubstrings(self, s): + """ + :type s: str + :rtype: int + """ + return sum(len(os.path.commonprefix((s[:i][::-1], s[i:]))) + + len(os.path.commonprefix((s[:i][::-1], s[i + 1:]))) + 1 + for i in range(len(s))) +``` +解释下为啥要加两次,因为回文串有以下两种形式: +- ‘abcba’ +- 'abba' + +那为啥要加那个1呢,上面解释过了,单个字符也算是一个回文子串呀,嘻嘻😁 diff --git a/docs/Algorithm/Leetcode/Python/657._Judge_Route_Circle.md b/docs/Algorithm/Leetcode/Python/657._Judge_Route_Circle.md new file mode 100644 index 00000000..12827f57 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/657._Judge_Route_Circle.md @@ -0,0 +1,23 @@ +### 657. Judge Route Circle +题目: + + + +难度: + +Easy + + + + +```python +class Solution(object): + def judgeCircle(self, moves): + """ + :type moves: str + :rtype: bool + """ + return moves.count('D') == moves.count('U') and moves.count('R') == moves.count('L') +``` + + diff --git a/docs/Algorithm/Leetcode/Python/665._Non-decreasing_Array.md b/docs/Algorithm/Leetcode/Python/665._Non-decreasing_Array.md new file mode 100644 index 00000000..cf05d3c9 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/665._Non-decreasing_Array.md @@ -0,0 +1,48 @@ +### 665. Non-decreasing Array + +题目: + + + +难度: + +Easy + + +思路 + +从index=1的元素依次检查,只要不符合规则则让count+1,如果count>1则肯定不符合返回False +但是我们在发现nums[i]小于nums[i-1]的时候,我们就必须要对原数组作出改变了,来让它的后面index部分尽可能满足条件 +下面就是两种情况: +- 2,4,2,6 + +如果是这种情况,当index=2时,不满足条件,但是i=0的元素是小于i=2处元素的,我们需要改变的是i-1处的元素,也就是将4改变成i=2处元素即2,最终变成2,2,2,6 + +- 3,4,2,6 + +这种情况如果我们将4变成2那么仍然是不满足条件的,此时我们需要将2变成4,即将i处元素变为i-1处元素 + +在每一次不符合条件的时候我们都检查一下count,如果count大于1的话我们就返回False,否则最终就返回True + +```python +class Solution(object): + def checkPossibility(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + count = 0 + for i in range(1,len(nums)): + if nums[i] < nums[i-1]: + count += 1 + if count > 1: + return False + if i - 2 < 0 or nums[i-2] <= nums[i]: + nums[i-1] = nums[i] + else: + nums[i] = nums[i-1] + return True +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/672._Bulb_Switcher_II.md b/docs/Algorithm/Leetcode/Python/672._Bulb_Switcher_II.md new file mode 100644 index 00000000..2441178f --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/672._Bulb_Switcher_II.md @@ -0,0 +1,74 @@ +### 672. Bulb Switcher II + +题目: + + + +难度: + +Medium + + +思路 + +这道题又是一个数学题。找规律呀找规律。 +我们只需要考虑当 n<=2 and m < 3 的特殊情形。因为当 n >2 and m >=3, 结果肯定是 8. +The four buttons: + +- Flip all the lights. +- Flip lights with even numbers. +- Flip lights with odd numbers. +- Flip lights with (3k + 1) numbers, k = 0, 1, 2, ... + +如果我们使用了 button 1 和 2, 其效果等同于使用 button 3 。 +类似的.. + +- 1 + 2 --> 3 +- 1 + 3 --> 2 +- 2 + 3 --> 1 + +所以,只有 8 种情形。 + +***灯全亮, 操作1, 操作2, 操作3, 操作4, 操作1+4, 操作2+4, 操作3+4*** + +并且当 n>2 and m>=3 时,我们就能够获得所有的情形。 + +| m\n | 0 | 1 | 2 | 3 | 4 | + --- |----|--- |----|---|---| +| 0 | 1 | 1 | 1 | 1 | 1 | +| 1 | 1 | 2 | 3 | 4 | 4 | +| 2 | 1 | 2 | 4 | 7 | 7 | +| 3 | 1 | 2 | 3 | 8 | 8 | + +```python +class Solution(object): + def flipLights(self, n, m): + """ + :type n: int + :type m: int + :rtype: int + """ + if m * n == 0: return 1 + if n == 1: return 2 + if n == 2: return 4 - (m % 2) + if m == 1: return 4 + if m == 2: return 7 + return 8 +``` + +还有两位大佬的两行解法: +```python +class Solution(object): + def flipLights(self, n, m): + m, n = min(3, m), min(3, n) + return 1 if n * m == 0 else self.flipLights(n - 1, m) + self.flipLights( n - 1, m - 1) +``` +```python +class Solution(object): + def flipLights(self, n, m): + n = min(n, 3) + return min(1< + + +难度: + +Medium + + + +思路 + +题目说输入一个时间,format是HH:MM, 然后输出接下来最近的一个时间,且这个时间的数字必须要在输入的时间中可以找到,所以我们用```h```, ```m``` +分别代表输入时间的小时数和分钟数,然后可以计算出输入时间的总分钟数```curr```,在未来的一天之内,我们一分钟一分钟往下面试,第一个满足的就直接 +作为结果就行了. + + + + +```python +class Solution(object): + def nextClosestTime(self, time): + """ + :type time: str + :rtype: str + """ + h, m = time.split(":") +        curr = int(h) * 60 + int(m) # 这里要注意h可能会是0开头的,如输入的时间为01:22,所以需要int(h)和int(m) +        result = None + for i in xrange(curr+1, curr+1441): + t = i % 1440 + h, m = t // 60, t % 60 + result = "%02d:%02d" % (h, m) + if set(result) <= set(time): + break + return result +``` + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/682._Baseball_Game.md b/docs/Algorithm/Leetcode/Python/682._Baseball_Game.md new file mode 100644 index 00000000..e775cbf8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/682._Baseball_Game.md @@ -0,0 +1,37 @@ +### 682. Baseball Game + +题目: + + + +难度: + +Easy + + +思路 + +points用来存放每一次的分数,最后求和。 + + +```python +class Solution(object): + def calPoints(self, ops): + """ + :type ops: List[str] + :rtype: int + """ + points = [] + for i in ops: + if i == 'C': + points.pop() + elif i == 'D': + points.append(2 * points[-1]) + elif i == '+': + points.append(points[-1] + points[-2]) + else: + points.append(int(i)) + return sum(points) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/685._Redundant_Connection_II.md b/docs/Algorithm/Leetcode/Python/685._Redundant_Connection_II.md new file mode 100644 index 00000000..0db1338e --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/685._Redundant_Connection_II.md @@ -0,0 +1,66 @@ +### 685. Redundant Connection II + +题目: + + + +难度 : Hard + + + +我们先定义一下,每条边的第一个点是parent,第二个点是child,例如 2 -> 1 中 node 2 就是 parent,而 node 1 就是 child + +明确这个之后,我们要知道图中有一条边是 invalid 的,去除它之后整个图就变成了一棵树,那么什么情况下一个边会导致树变成图呢: + +1. 如果一个child 在此之前已经有过一个parent了,那么意味着它有两个parent,这在树中肯定是不合法的。 +在代码中体现为```node_parent[child] != child```,这说明在碰到此时的parent之前我们就已经更新过node_parent[child]了,即child之前已经有一个parent了 +2. 如果一个child 的 parent 的 parent(或者一直往上找) 就是 child 本身,那么这意味着有环,这在树中也肯定是不合法的。 +在代码中体现为```find(node_parents, parent) == child```, 这说明child的parent的parent或以上就是child本身,即有环。 +例如 ```1 --> 2 --> 1```或者```1 --> 2 --> 3 --> 1``` + +因此我们可以定义一个列表 node_parent,在最开始的时候,此列表的 index 和 value 一一相等。 + +然后我们对edges进行第一轮遍历(正序遍历),并且用count来计数不合法的边: +- 如果只找到一条不合法的边,那么直接返回它即可 +- 如果有超过一条不合法的边,那么我们就进行第二轮遍历(逆序遍历),返回碰到的第一条不合法的边, +这里是为了节约时间,因为如题意我们要返回的是最后一条出现的边,那么我们逆序就更省时间嘛 + + +```python +class Solution(object): + def findRedundantDirectedConnection(self, edges): + """ + :type edges: List[List[int]] + :rtype: List[int] + """ + + def find(node_parent, parent): + return parent if node_parent[parent] == parent else find(node_parent, node_parent[parent]) + + n, count = len(edges), 0 # 用 count 来计数不合法的边 + node_parent = [i for i in range(n+1)] + res = [0, 0] + + # 第一轮查找不合法的边 (正序) + for i in range(n): + parent, child = edges[i][0], edges[i][1] + if node_parent[child] != child or find(node_parent, parent) == child: + res = edges[i] + count += 1 + else: + node_parent[child] = parent + if count == 1: # 如果只有一条不合法的边,直接返回 + return res + + # 重置 node_parent 并开始第二轮查找 (逆序) + node_parent = [i for i in range(n+1)] + for i in range(n-1, -1, -1): + parent, child = edges[i][0], edges[i][1] + if node_parent[child] != child or find(node_parent, parent) == child: + return edges[i] + else: + node_parent[child] = parent + return res +``` +这道题感谢[xyzxuyizhen](https://leetcode.com/problems/redundant-connection-ii/discuss/128596/Easy-to-understand-Java-Solution-Union-Find)大佬, +看到他的思路才逃离了我之前的很复杂的想法。 diff --git a/docs/Algorithm/Leetcode/Python/687._Longest_Univalue_Path.md b/docs/Algorithm/Leetcode/Python/687._Longest_Univalue_Path.md new file mode 100644 index 00000000..0b7a2eef --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/687._Longest_Univalue_Path.md @@ -0,0 +1,58 @@ +### 687. Longest Univalue Path + + +题目: + + + +难度: + +Easy + + + +思路 + +这道题也只能算个```easy```题目,根据传进来的```root```,我们只要从它的左右节点不停的递归下去,只要其```value```值与```root```一样, +该方向上的```length```就加```1```,最后我们将左右方向上的```length```相加, 递归取最大值 +##### 很重要的一点就是,Note: The length of path between two nodes is represented by the number of edges between them. +- 因此是```self.res = max(self.res, left_arrow + right_arrow)```, ```return max(left_arrow, right_arrow)``` +- 而不是```self.res = max(self.res, left_arrow + right_arrow + 1)```, ```return max(left_arrow + 1, right_arrow + 1)``` + + + + + +```python +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def longestUnivaluePath(self, root): + """ + :type root: TreeNode + :rtype: int + """ + self.res = 0 + def dir_length(node): + if not node: + return 0 + left_len = dir_length(node.left) # 左节点的length + right_len = dir_length(node.right) # 右节点的length + left_dir, right_dir = 0, 0 + if node.left and node.left.val == node.val: + left_dir = left_len + 1 # 当前节点的左节点方向的length + if node.right and node.right.val == node.val: + right_dir = right_len + 1 # 当前节点的右边节点方向的length + self.res = max(self.res, left_dir + right_dir) + return max(left_dir, right_dir) + dir_length(root) + return self.res +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/693._Binary_Number_with_Alternating_Bits.md b/docs/Algorithm/Leetcode/Python/693._Binary_Number_with_Alternating_Bits.md new file mode 100644 index 00000000..f95ae536 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/693._Binary_Number_with_Alternating_Bits.md @@ -0,0 +1,73 @@ +# 693. Binary Number with Alternating Bits 交替位二进制数 + +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/binary-number-with-alternating-bits/description/ +* https://leetcode-cn.com/problems/binary-number-with-alternating-bits/description/ + +> 内容描述 + +``` +给定一个正整数,检查他是否为交替位二进制数:换句话说,就是他的二进制数相邻的两个位数永不相等。 + +示例 1: + +输入: 5 +输出: True +解释: +5的二进制数是: 101 +示例 2: + +输入: 7 +输出: False +解释: +7的二进制数是: 111 +示例 3: + +输入: 11 +输出: False +解释: +11的二进制数是: 1011 + 示例 4: + +输入: 10 +输出: True +解释: +10的二进制数是: 1010 +``` + +## 解题方案 + +> 思路 1 + +太简单了,可以一行秒,但是太难看了,还是多写几行吧 + +调用bin函数转换成二进制以后再转换成字符串,注意二进制前面2为是‘0b’,要记得去掉 + +```python +class Solution(object): + def hasAlternatingBits(self, n): + """ + :type n: int + :rtype: bool + """ + tmp = str(bin(n))[2:] + res = [tmp[i] != tmp[i-1] for i in range(1, len(tmp))] + return all(res) +``` + + + + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/701._Insert_into_a_Binary_Search_Tree.md b/docs/Algorithm/Leetcode/Python/701._Insert_into_a_Binary_Search_Tree.md new file mode 100644 index 00000000..f2ecc394 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/701._Insert_into_a_Binary_Search_Tree.md @@ -0,0 +1,67 @@ +# 701. Insert into a Binary Search Tree + +**难度: 困难** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-valid-parentheses + +> 内容描述 + +``` +Given 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. + +Note 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. + +For example, + +Given the tree: + 4 + / \ + 2 7 + / \ + 1 3 +And the value to insert: 5 +You can return this binary search tree: + + 4 + / \ + 2 7 + / \ / + 1 3 5 +This tree is also valid: + + 5 + / \ + 2 7 + / \ + 1 3 + \ + 4 +``` + +## 解题方案 + +> 思路 1 + +就一句话,看到树🌲就想到递归,太简单了,30秒敲完答案 + +```python +class Solution(object): + def insertIntoBST(self, root, val): + """ + :type root: TreeNode + :type val: int + :rtype: TreeNode + """ + if not root: + return TreeNode(val) + if val < root.val: + root.left = self.insertIntoBST(root.left, val) + if val > root.val: + root.right = self.insertIntoBST(root.right, val) + return root +``` + diff --git a/docs/Algorithm/Leetcode/Python/707._Design_Linked_List.md b/docs/Algorithm/Leetcode/Python/707._Design_Linked_List.md new file mode 100644 index 00000000..7623a50a --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/707._Design_Linked_List.md @@ -0,0 +1,111 @@ +# 707. Design Linked List + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/design-linked-list/description/ + +> 内容描述 + +``` +Design 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. + +Implement these functions in your linked list class: + +get(index) : Get the value of the index-th node in the linked list. If the index is invalid, return -1. +addAtHead(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. +addAtTail(val) : Append a node of value val to the last element of the linked list. +addAtIndex(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. +deleteAtIndex(index) : Delete the index-th node in the linked list, if the index is valid. +Example: + +MyLinkedList linkedList = new MyLinkedList(); +linkedList.addAtHead(1); +linkedList.addAtTail(3); +linkedList.addAtIndex(1, 2); // linked list becomes 1->2->3 +linkedList.get(1); // returns 2 +linkedList.deleteAtIndex(1); // now the linked list is 1->3 +linkedList.get(1); // returns 3 +Note: + +All values will be in the range of [1, 1000]. +The number of operations will be in the range of [1, 1000]. +Please do not use the built-in LinkedList library. +``` + +## 解题方案 + +> 思路 1 + +用list模拟,太简单了,🙄️🙄️🙄️ + +```python +class MyLinkedList(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.lst = [] + + + def get(self, index): + """ + Get the value of the index-th node in the linked list. If the index is invalid, return -1. + :type index: int + :rtype: int + """ + if index > len(self.lst) - 1 or index < 0: + return -1 + return self.lst[index] + + + def addAtHead(self, 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. + :type val: int + :rtype: void + """ + self.lst.insert(0, val) + + + def addAtTail(self, val): + """ + Append a node of value val to the last element of the linked list. + :type val: int + :rtype: void + """ + self.lst.append(val) + + + def addAtIndex(self, 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. + :type index: int + :type val: int + :rtype: void + """ + if index > len(self.lst): + return + elif index == len(self.lst): + self.lst.append(val) + else: + self.lst.insert(index, val) + + + def deleteAtIndex(self, index): + """ + Delete the index-th node in the linked list, if the index is valid. + :type index: int + :rtype: void + """ + if index > len(self.lst) - 1 or index < 0: + return + self.lst.pop(index) +``` + + + diff --git a/docs/Algorithm/Leetcode/Python/740._delete_and_earn.md b/docs/Algorithm/Leetcode/Python/740._delete_and_earn.md new file mode 100644 index 00000000..3810c4b0 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/740._delete_and_earn.md @@ -0,0 +1,29 @@ +### 740. Delete and Earn + +题目: + + + +难度: + +Medium + + + + +```python +class Solution(object): + def deleteAndEarn(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + dp = [0] * 10001 + for num in nums: + dp[num] += num + for i in range(2, 10001): + dp[i] = max(dp[i]+dp[i-2], dp[i-1]) + return dp[-1] +``` + + diff --git a/docs/Algorithm/Leetcode/Python/760._Find_Anagram_Mappings.md b/docs/Algorithm/Leetcode/Python/760._Find_Anagram_Mappings.md new file mode 100644 index 00000000..fe69ce14 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/760._Find_Anagram_Mappings.md @@ -0,0 +1,31 @@ +### 760. Find Anagram Mappings + +题目: + + + +难度: + +Easy + + + + + +```python +class Solution(object): + def anagramMappings(self, A, B): + """ + :type A: List[int] + :type B: List[int] + :rtype: List[int] + """ + if not A: + return [] + res = [] + for i in A: + res.append(B.index(i)) + return res +``` + + diff --git a/docs/Algorithm/Leetcode/Python/774._Minimize_Max_Distance_to_Gas_Station.md b/docs/Algorithm/Leetcode/Python/774._Minimize_Max_Distance_to_Gas_Station.md new file mode 100644 index 00000000..e9c4c06b --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/774._Minimize_Max_Distance_to_Gas_Station.md @@ -0,0 +1,62 @@ +# 774. Minimize Max Distance to Gas Station +**难度: 困难** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/minimize-max-distance-to-gas-station/description/ + +> 内容描述 + +``` +On a horizontal number line, we have gas stations at positions stations[0], stations[1], ..., stations[N-1], where N = stations.length. + +Now, we add K more gas stations so that D, the maximum distance between adjacent gas stations, is minimized. + +Return the smallest possible value of D. + +Example: + +Input: stations = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], K = 9 +Output: 0.500000 +Note: + +stations.length will be an integer in range [10, 2000]. +stations[i] will be an integer in range [0, 10^8]. +K will be an integer in range [1, 10^6]. +Answers within 10^-6 of the true value will be accepted as correct. +``` + +## 解题方案 + +> 思路 1 + +首先明确一下题意,如果目前最大的一个距离是D的话,只要现在我们能够让最大的距离全都变小就行了,也就是说通过在最大距离的station之间再加一些station即可, +加了之后现在原来的最大距离就变小了,就可以了。明确一点,我们需要返回的是我们用最多k个station所能构造出的最小的最大距离。 + +于是我们判断一下需要我们额外加的stations数目是否小于等于k: +- 若是,且当前最大距离小于10^-6则返回当前最大距离 +- 若不是,则继续追加stations数目,继续让最大距离变小 + +```python +class Solution(object): + def minmaxGasDist(self, stations, K): + """ + :type stations: List[int] + :type K: int + :rtype: float + """ + def possible(D): + return sum(int((stations[i+1] - stations[i]) / D) + for i in xrange(len(stations) - 1)) <= K + + l, r = 0, 10**8 + while r - l > 1e-6: + mid = (l + r) / 2.0 + if possible(mid): + r = mid + else: + l = mid + return l +``` diff --git a/docs/Algorithm/Leetcode/Python/777. Swap_Adjacent_in_LR_String.md b/docs/Algorithm/Leetcode/Python/777. Swap_Adjacent_in_LR_String.md new file mode 100644 index 00000000..af0a3001 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/777. Swap_Adjacent_in_LR_String.md @@ -0,0 +1,133 @@ +# 777. Swap Adjacent in LR String 在LR字符串中交换相邻字符 + +**难度: 中等** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/swap-adjacent-in-lr-string/description/ +* https://leetcode-cn.com/problems/swap-adjacent-in-lr-string/description/ + +> 内容描述 + +``` + +在一个由 'L' , 'R' 和 'X' 三个字符组成的字符串(例如"RXXLRXRXL")中进行移动操作。一次移动操作指用一个"LX"替换一个"XL",或者用一个"XR"替换一个"RX"。现给定起始字符串start和结束字符串end,请编写代码,当且仅当存在一系列移动操作使得start可以转换成end时, 返回True。 + +示例 : + +输入: start = "RXXLRXRXL", end = "XRLXXRRLX" +输出: True +解释: +我们可以通过以下几步将start转换成end: +RXXLRXRXL -> +XRXLRXRXL -> +XRLXRXRXL -> +XRLXXRRXL -> +XRLXXRRLX +注意: + +1 <= len(start) = len(end) <= 10000。 +start和end中的字符串仅限于'L', 'R'和'X'。 +``` + +## 解题方案 + +> 思路 1 + +这道题就是一道坑比题,为什么我这么说,题目都说了是 **Adjacent**,然后XL换成LX的情况居然包括"XXXXXLXXXX"到"LXXXXXXXXX", +你说这是 **Adjacent**吗,XL不相邻也可以换,我去nm的,不好意思爆粗口了。 + +先说一下XL必须相邻的解法吧,不能白费我功夫啊。 + +动态规划:dp[i]代表以```index i```结尾的字串是否能够被替换成功,首先dp[0]必须等于False吧,所以我们初始化全部设为False,然后把dp[1]也先判断好 + +那么很显然,对于dp[i]有下面的情况: +1. dp[i-1] == True +- 如果start[i] == end[i],那么dp[i] = True +- 如果start[i] != end[i],那么这里我们不做操作,因为初始化就是False + +2. dp[i-1] == False +- 如果start[i] == end[i],那么dp[i] = False +- 如果start[i] != end[i],那么只有当最后两个字符可以转换且dp[i-2] == True的情况下dp[i]才为True + +最后返回dp[-1] + + +``` +class Solution(object): + def canTransform(self, start, end): + """ + :type start: str + :type end: str + :rtype: bool + """ + if not start or len(start) == 0: + return True + if len(start) == 1: + return False + + dp = [False for i in range(len(start))] + if start[:2] == 'XL' and end[:2] == 'LX' or start[:2] == 'RX' and end[:2] == 'XR' or start[:2] == end[:2]: + dp[1] = True + for i in range(2, len(dp)): + if dp[i-1]: + if start[i] == end[i]: + dp[i] = True + else: + if start[i] == 'L' and start[i-1] == 'X' and end[i] == 'X' and end[i-1] == 'L' and dp[i-2]: + dp[i] = True + if start[i] == 'X' and start[i-1] == 'R' and end[i] == 'R' and end[i-1] == 'X' and dp[i-2]: + dp[i] = True + return dp[-1] +``` +接下来说一下XL可以不相邻的情况吧。 +用```rx``` 和 ```xl```来存储出现了可以替换的可能性,即当start出现X或者R的时候,如果后面又开始出现结尾情况了, +我们就要pop一下对应的```rx``` 和 ```xl```中的一个 + +```python +class Solution(object): + def canTransform(self, start, end): + """ + :type start: str + :type end: str + :rtype: bool + """ + if not start or len(start) == 0 or start == end: + return True + if len(start) == 1: + return False + + xl, rx = [], [] + for i in range(len(start)): + if start[i] == end[i]: + continue + elif start[i] == 'X' and end[i] == 'L': + xl.append('L') + elif start[i] == 'L' and end[i] == 'X': + if not xl: + return False + xl.pop() + elif start[i] == 'R' and end[i] == 'X': + rx.append('R') + elif start[i] == 'X' and end[i] == 'R': + if not rx: + return False + rx.pop() + else: + return False + return not rx and not xl +``` + + + + + + + + + + + + diff --git a/docs/Algorithm/Leetcode/Python/844._Backspace_String_Compare.md b/docs/Algorithm/Leetcode/Python/844._Backspace_String_Compare.md new file mode 100644 index 00000000..4ddbd8ca --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/844._Backspace_String_Compare.md @@ -0,0 +1,38 @@ +### 844. Backspace String Compare + +题目: + + + +难度: + +Easy + + +思路 + +就看一下两个字符串变化完之后是不是相等就行了, +- 时间复杂度:O(n) +- 空间复杂度:O(n) + + +```python +class Solution(object): + def backspaceCompare(self, S, T): + """ + :type S: str + :type T: str + :rtype: bool + """ + def afterChange(s): + res = '' + for i in s: + if i == '#': + res = '' if len(res) == 0 else res[:-1] + else: + res += i + return res + return afterChange(S) == afterChange(T) +``` + + diff --git a/docs/Algorithm/Leetcode/Python/README.md b/docs/Algorithm/Leetcode/Python/README.md new file mode 100644 index 00000000..c477b8c8 --- /dev/null +++ b/docs/Algorithm/Leetcode/Python/README.md @@ -0,0 +1 @@ +# Leetcode solutions and summarizations! diff --git a/docs/Algorithm/DataStructure/Summarization/Binary Search.md b/docs/Algorithm/Leetcode/Python/Summarization/Binary Search.md similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/Binary Search.md rename to docs/Algorithm/Leetcode/Python/Summarization/Binary Search.md diff --git "a/docs/Algorithm/DataStructure/Summarization/DFS\345\222\214BFS.md" "b/docs/Algorithm/Leetcode/Python/Summarization/DFS\345\222\214BFS.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/DFS\345\222\214BFS.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/DFS\345\222\214BFS.md" diff --git a/docs/Algorithm/DataStructure/Summarization/Data Structure and Algorthim Review.md b/docs/Algorithm/Leetcode/Python/Summarization/Data Structure and Algorthim Review.md similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/Data Structure and Algorthim Review.md rename to docs/Algorithm/Leetcode/Python/Summarization/Data Structure and Algorthim Review.md diff --git a/docs/Algorithm/DataStructure/Summarization/Dynamic Programming.md b/docs/Algorithm/Leetcode/Python/Summarization/Dynamic Programming.md similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/Dynamic Programming.md rename to docs/Algorithm/Leetcode/Python/Summarization/Dynamic Programming.md diff --git "a/docs/Algorithm/DataStructure/Summarization/Introduction to String Searching Algorithms \342\200\223 topcoder.pdf" "b/docs/Algorithm/Leetcode/Python/Summarization/Introduction to String Searching Algorithms \342\200\223 topcoder.pdf" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/Introduction to String Searching Algorithms \342\200\223 topcoder.pdf" rename to "docs/Algorithm/Leetcode/Python/Summarization/Introduction to String Searching Algorithms \342\200\223 topcoder.pdf" diff --git "a/docs/Algorithm/DataStructure/Summarization/Java\345\220\204\347\247\215\347\261\273\345\236\213\347\232\204\350\275\254\346\215\242.md" "b/docs/Algorithm/Leetcode/Python/Summarization/Java\345\220\204\347\247\215\347\261\273\345\236\213\347\232\204\350\275\254\346\215\242.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/Java\345\220\204\347\247\215\347\261\273\345\236\213\347\232\204\350\275\254\346\215\242.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/Java\345\220\204\347\247\215\347\261\273\345\236\213\347\232\204\350\275\254\346\215\242.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/LinkedList\346\212\200\345\267\247.md" "b/docs/Algorithm/Leetcode/Python/Summarization/LinkedList\346\212\200\345\267\247.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/LinkedList\346\212\200\345\267\247.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/LinkedList\346\212\200\345\267\247.md" diff --git a/docs/Algorithm/DataStructure/Summarization/Maximal Square.pdf b/docs/Algorithm/Leetcode/Python/Summarization/Maximal Square.pdf similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/Maximal Square.pdf rename to docs/Algorithm/Leetcode/Python/Summarization/Maximal Square.pdf diff --git "a/docs/Algorithm/DataStructure/Summarization/Python\345\210\267\351\242\230\346\212\200\345\267\247\347\254\224\350\256\260.py" "b/docs/Algorithm/Leetcode/Python/Summarization/Python\345\210\267\351\242\230\346\212\200\345\267\247\347\254\224\350\256\260.py" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/Python\345\210\267\351\242\230\346\212\200\345\267\247\347\254\224\350\256\260.py" rename to "docs/Algorithm/Leetcode/Python/Summarization/Python\345\210\267\351\242\230\346\212\200\345\267\247\347\254\224\350\256\260.py" diff --git a/docs/Algorithm/DataStructure/Summarization/Range Sum Query 2D - Immutable.pdf b/docs/Algorithm/Leetcode/Python/Summarization/Range Sum Query 2D - Immutable.pdf similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/Range Sum Query 2D - Immutable.pdf rename to docs/Algorithm/Leetcode/Python/Summarization/Range Sum Query 2D - Immutable.pdf diff --git a/docs/Algorithm/DataStructure/Summarization/Recusrion & BackTracking.md b/docs/Algorithm/Leetcode/Python/Summarization/Recusrion & BackTracking.md similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/Recusrion & BackTracking.md rename to docs/Algorithm/Leetcode/Python/Summarization/Recusrion & BackTracking.md diff --git "a/docs/Algorithm/DataStructure/Summarization/backtracking\346\200\235\350\267\257.md" "b/docs/Algorithm/Leetcode/Python/Summarization/backtracking\346\200\235\350\267\257.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/backtracking\346\200\235\350\267\257.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/backtracking\346\200\235\350\267\257.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/delete_node_in_a_linked_list\351\227\256\351\242\230.md" "b/docs/Algorithm/Leetcode/Python/Summarization/delete_node_in_a_linked_list\351\227\256\351\242\230.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/delete_node_in_a_linked_list\351\227\256\351\242\230.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/delete_node_in_a_linked_list\351\227\256\351\242\230.md" diff --git a/docs/Algorithm/DataStructure/Summarization/python_base.py b/docs/Algorithm/Leetcode/Python/Summarization/python_base.py similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/python_base.py rename to docs/Algorithm/Leetcode/Python/Summarization/python_base.py diff --git "a/docs/Algorithm/DataStructure/Summarization/python\347\232\204\345\220\204\347\247\215pass.md" "b/docs/Algorithm/Leetcode/Python/Summarization/python\347\232\204\345\220\204\347\247\215pass.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/python\347\232\204\345\220\204\347\247\215pass.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/python\347\232\204\345\220\204\347\247\215pass.md" diff --git a/docs/Algorithm/DataStructure/Summarization/slide_windows_template.md b/docs/Algorithm/Leetcode/Python/Summarization/slide_windows_template.md similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/slide_windows_template.md rename to docs/Algorithm/Leetcode/Python/Summarization/slide_windows_template.md diff --git a/docs/Algorithm/DataStructure/Summarization/union_find.md b/docs/Algorithm/Leetcode/Python/Summarization/union_find.md similarity index 100% rename from docs/Algorithm/DataStructure/Summarization/union_find.md rename to docs/Algorithm/Leetcode/Python/Summarization/union_find.md diff --git "a/docs/Algorithm/DataStructure/Summarization/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\200\344\272\233\346\223\215\344\275\234.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\200\344\272\233\346\223\215\344\275\234.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\200\344\272\233\346\223\215\344\275\234.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\200\344\272\233\346\223\215\344\275\234.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/\344\275\215\350\277\220\347\256\227.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\344\275\215\350\277\220\347\256\227.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\344\275\215\350\277\220\347\256\227.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\344\275\215\350\277\220\347\256\227.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/\345\205\250\346\216\222\345\210\227\347\256\227\346\263\225.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\345\205\250\346\216\222\345\210\227\347\256\227\346\263\225.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\345\205\250\346\216\222\345\210\227\347\256\227\346\263\225.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\345\205\250\346\216\222\345\210\227\347\256\227\346\263\225.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/\345\205\253\346\216\222\345\272\217.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\345\205\253\346\216\222\345\272\217.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\345\205\253\346\216\222\345\272\217.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\345\205\253\346\216\222\345\272\217.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/\345\255\220\351\233\206\345\220\210\351\227\256\351\242\230.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\345\255\220\351\233\206\345\220\210\351\227\256\351\242\230.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\345\255\220\351\233\206\345\220\210\351\227\256\351\242\230.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\345\255\220\351\233\206\345\220\210\351\227\256\351\242\230.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/\346\200\273\347\273\223.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\346\200\273\347\273\223.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\346\200\273\347\273\223.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\346\200\273\347\273\223.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/\347\273\204\345\220\210\351\227\256\351\242\230.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\347\273\204\345\220\210\351\227\256\351\242\230.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\347\273\204\345\220\210\351\227\256\351\242\230.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\347\273\204\345\220\210\351\227\256\351\242\230.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/\351\200\222\345\275\222_recursion.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\351\200\222\345\275\222_recursion.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\351\200\222\345\275\222_recursion.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\351\200\222\345\275\222_recursion.md" diff --git "a/docs/Algorithm/DataStructure/Summarization/\351\235\242\350\257\225\347\241\256\350\256\244\351\242\230\347\233\256\347\273\206\350\212\202\351\227\256\351\242\230.md" "b/docs/Algorithm/Leetcode/Python/Summarization/\351\235\242\350\257\225\347\241\256\350\256\244\351\242\230\347\233\256\347\273\206\350\212\202\351\227\256\351\242\230.md" similarity index 100% rename from "docs/Algorithm/DataStructure/Summarization/\351\235\242\350\257\225\347\241\256\350\256\244\351\242\230\347\233\256\347\273\206\350\212\202\351\227\256\351\242\230.md" rename to "docs/Algorithm/Leetcode/Python/Summarization/\351\235\242\350\257\225\347\241\256\350\256\244\351\242\230\347\233\256\347\273\206\350\212\202\351\227\256\351\242\230.md" diff --git a/docs/Algorithm/Leetcode/ipynb/0001._two_sum.ipynb b/docs/Algorithm/Leetcode/ipynb/0001._two_sum.ipynb new file mode 100755 index 00000000..c1fc51bf --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0001._two_sum.ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 1. Two Sum 两数之和\n", + "\n", + "## 题目:\n", + "\n", + " - https://leetcode.com/problems/two-sum/\n", + " - https://leetcode-cn.com/problems/two-sum/description/\n", + "\n", + "```\n", + "给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。\n", + "\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", + "## 难度:Easy\n", + "\n", + "这个题目略微有点简单,我们只要注意的是,同样的元素不能被重复利用两次。\n", + "\n", + "还有就是思考,是不是我们可以使用一次循环就能够找到这两个数呢?\n", + "\n", + "接下来我们看一下如何解决这个问题。\n", + "\n", + "> 思路 1\n", + "\n", + " - 简单判断一下,是否两个数都在 list 中,以及判断两个数不是重复利用一个元素即可。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2]\n" + ] + } + ], + "source": [ + "class Solution(object):\n", + " def twoSum(self, nums, target):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :type target: int\n", + " :rtype: List[int]\n", + " \"\"\"\n", + " # 循环名为 nums 的 list\n", + " for num_one in nums:\n", + " # 判断 target 减去 num_one 是否仍在我们的 nums list 中,另一个条件是这两个数不是同一个元素\n", + " if target - num_one in nums and num_one is not target-num_one:\n", + " # 返回两个数对应的 index\n", + " return [nums.index(num_one), nums.index(target - num_one)]\n", + " \n", + "nums = [4, 3, 5, 15]\n", + "target = 8\n", + "s = Solution()\n", + "print(s.twoSum(nums, target))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 其实我们上一个解决方案已经是弄的一个 for 循环了,这次我们换一个思路。\n", + " - 可以用 $O(n^2)$ 的循环(lookup)\n", + " - 其实也可以牺牲空间换取时间,异常聪明的 AC 解法\n", + " \n", + "```\n", + " 2 7 11 15\n", + " 不存在 存在之中 \n", + "lookup {2:0} [0, 1]\n", + "```\n", + "大体思路如下:\n", + "\n", + " - 建立字典 lookup 存放第一个数字,并存放该数字的 index\n", + " - 判断 lookup 中是否存在: target - 当前数字, 则表面 当前值和 lookup中的值加和为 target\n", + " - 如果存在,则返回: target - 当前数字 的 index 和 当前值的 index" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2]\n" + ] + } + ], + "source": [ + "class 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", + " lookup = {}\n", + " # 使用 enumerate 语法,返回的是每一个元素及其对应的 index\n", + " for i, num in enumerate(nums):\n", + " if target - num in lookup:\n", + " return [lookup[target - num],i]\n", + " lookup[num] = i\n", + " return []\n", + " \n", + "nums = [4, 3, 5, 15]\n", + "target = 8\n", + "s = Solution()\n", + "print(s.twoSum(nums, target))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3\n", + "\n", + " - 对于 dict ,也就是其他语言的 map,判断一个元素在不在容器中,list 要遍历,而 set 和 dict 直接根据哈希算出,不需要遍历\n", + " - 我们可以仿照上面的代码,但是换个简单的写法。\n", + " - 对于字典的这种方式,如果我们只是判断 i 以及 target - i 是不是相等,这样是错误的,如果两个元素相同,但是不是同一个元素,那就会出错了。\n", + " \n", + "比如,我们先看一下错误的版本:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def twoSum(self, nums, target):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :type target: int\n", + " :rtype: List[int]\n", + " \"\"\"\n", + " dict1 = {}\n", + " for k, i in enumerate(nums):\n", + " dict1[i] = k\n", + " if target - i in dict1 and i is not target - i:\n", + " return [dict1[target - i], dict1[i]]\n", + "\n", + "nums = [3, 3]\n", + "target = 6\n", + "s = Solution()\n", + "print(s.twoSum(nums, target))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "上面的代码是存在问题的,对于相同的元素 [3, 3], target =6, 就得到了 None ,按理说,应该得到 [0, 1] 的。所以,这地方的判断是错误的。\n", + "\n", + " - 对于字典的那种方式,就只能索引为 key,数据为value,只是这样一来,判断在或者不在,还是多了一层循环\n", + " \n", + "下面的版本是正确的版本:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1]\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def twoSum(self, nums, target):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :type target: int\n", + " :rtype: List[int]\n", + " \"\"\"\n", + " for k, i in enumerate(nums):\n", + " if target - i in nums[k + 1:]:\n", + " return [k, nums[k + 1:].index(target - i) + k + 1]\n", + "\n", + "nums = [3, 3]\n", + "target = 6\n", + "s = Solution()\n", + "print(s.twoSum(nums, target)) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 小结\n", + "\n", + "应该还有更加好的解法,大佬们积极贡献自己的解法哈。一起为好的工作,好的未来,加油。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0002._add_two_numbers.ipynb b/docs/Algorithm/Leetcode/ipynb/0002._add_two_numbers.ipynb new file mode 100755 index 00000000..7971d420 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0002._add_two_numbers.ipynb @@ -0,0 +1,245 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2.Add Two Numbers\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容:\n", + "\n", + "> 原题链接:\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/add-two-numbers/description/\n", + " - 英文:https://leetcode.com/problems/add-two-numbers/\n", + "\n", + "> 内容描述:\n", + "\n", + "给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。\n", + "\n", + "你可以假设除了数字 0 之外,这两个数字都不会以零开头。\n", + "\n", + "示例:\n", + "```\n", + "输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)\n", + "输出:7 -> 0 -> 8\n", + "原因:342 + 465 = 807\n", + "```\n", + "\n", + "## 解法方案\n", + "\n", + "由于两数相加可能会出现进位,所以加法我们谁都会算,但是要着重注意的一点是,要考虑上一位的进位,并且传递给下一位计算时的进位。\n", + "\n", + "> 思路 1\n", + "\n", + "我们先构建一个空的头结点不动,然后尾结点从头结点开始向后不断生成新的结点。遍历两个链表的公共部分,每次相加相应位数字和进位,分配到结果的链表中。公共部分遍历完后再确定长的链表剩余的部分,同样的方式遍历完。\n", + "\n", + " - 需要注意的是遍历时每次都要更新进位,不断计算和时有没有发生进位,以防止之前数据的污染。\n", + " - 对于 python 来说,需要新的变量做游标来遍历两个链表,不能直接用形参,否则我们会修改原链表。\n", + " - 注意最后可能的进位。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "0\n", + "8\n", + "None\n" + ] + } + ], + "source": [ + "# Definition for singly-linked list.\n", + "class ListNode:\n", + " def __init__(self, x):\n", + " self.val = x\n", + " self.next = None\n", + "\n", + "class Solution: \n", + " def addTwoNumbers(self, l1, l2):\n", + " \"\"\"\n", + " :type l1: ListNode\n", + " :type l2: ListNode\n", + " :rtype: ListNode\n", + " \"\"\"\n", + " # 用 p1, p2 赋值为 l1 和 l2 ,以防止我们的操作改变原链表\n", + " p1, p2 = l1, l2\n", + " # 创建一个空链表用来返回结果,分别有头结点和尾结点\n", + " head = ListNode(0)\n", + " tail = head\n", + " # carry 表示进位值\n", + " carry = 0\n", + " # 处理两个链表的公共部分,也就是两个链表都不为空的部分\n", + " while p1 and p2:\n", + " # 计算当前位相加的和\n", + " num = p1.val + p2.val + carry\n", + " # 大于 9 ,应该向前进一位\n", + " if num > 9:\n", + " num -= 10\n", + " carry = 1\n", + " else:\n", + " carry = 0\n", + " # 添加结点\n", + " tail.next = ListNode(num)\n", + " # 尾结点向后移动\n", + " tail = tail.next\n", + " # 移动两条链表的公共部分\n", + " p1 = p1.next\n", + " p2 = p2.next\n", + " # 取长链表剩余的部分,也就是未参与上面计算的部分\n", + " if p2:\n", + " # 如果 p2 较长,将 p2 剩余的部分赋值给 p1 ,我们只需要处理 p1 就行了\n", + " p1 = p2\n", + " # 接下来,处理长链表剩余分部分\n", + " while p1:\n", + " # 最近的一位,我们要考虑一下,是否有进位\n", + " num = p1.val + carry\n", + " if num > 9:\n", + " num -= 10\n", + " carry = 1\n", + " else:\n", + " carry = 0\n", + " # 添加结点\n", + " tail.next = ListNode(num)\n", + " tail = tail.next\n", + " \n", + " # 移动我们处理的链表\n", + " p1 = p1.next\n", + " # 如果最后仍然有进位,我们需要再分配一个结点\n", + " if carry:\n", + " # 创建一个 val 为 1 的 ListNode 结点,然后将 tail 向后移动一位\n", + " tail.next = ListNode(1)\n", + " tail = tail.next\n", + " # 将所有的加和及进位都处理完成了,现在我们将链表收尾\n", + " tail.next = None\n", + " # 将 链表的头结点返回\n", + " return head.next # 去除掉我们初始化为 0 的头结点\n", + "\n", + "la = ListNode(2)\n", + "la.next = ListNode(4)\n", + "la.next.next = ListNode(3)\n", + "\n", + "lb = ListNode(5)\n", + "lb.next = ListNode(6)\n", + "lb.next.next = ListNode(4)\n", + "\n", + "s = Solution()\n", + "ss = s.addTwoNumbers(la, lb)\n", + "print(ss.val)\n", + "print(ss.next.val)\n", + "print(ss.next.next.val)\n", + "print(ss.next.next.next) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "因此,这个地方我们可以考虑使用递归来求解,具体可以分为以下情况:\n", + "\n", + " - 当两个链表均不为空时,计算两个节点值与上一位进位的和 sum,取 sum 的个位数构建新的节点,更新进位为 sum 的十位数,令本节点的 next 指针指向下一位求和返回的节点。\n", + " - 当两个链表其中一个为空时,计算不为空的节点值与上一位进位的和 sum,更新进位为 sum 的十位数。若进位不为 0 ,取 sum 的个位数构建新节点,令本节点的 next 指针指向下一位求和返回的节点,注意只传递不为空的链表;若进位为 0,则直接更新不为空节点的值为 sum,此时此链表之后的所有高位值都不会更新,因此返回此节点。\n", + " - 若两个链表都为空,判断进位是否为 0。若进位为 0,直接返回 NULL;否则构建值为进位值的新节点,并返回此节点。\n", + " \n", + "> 思路 2\n", + "\n", + " - 跟 plus One ,add Binary 玩的同一个花样,但是相对上个思路来说,更加简单和简洁。\n", + " - 使用递归调用简化算法" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "0\n", + "8\n", + "None\n" + ] + } + ], + "source": [ + "# Definition for singly-linked list.\n", + "class ListNode:\n", + " def __init__(self, x):\n", + " self.val = x\n", + " self.next = None\n", + "\n", + "class Solution(object):\n", + " def addTwoNumbers(self, l1, l2):\n", + " \"\"\"\n", + " :type l1: ListNode\n", + " :type l2: ListNode\n", + " :rtype: ListNode\n", + " \"\"\"\n", + " # 特殊情况\n", + " if l1 == None:\n", + " return l2\n", + " if l2 == None:\n", + " return l1\n", + " # 如果 相加 小于 10 ,不需要进位\n", + " if l1.val + l2.val < 10:\n", + " l3 = ListNode(l1.val + l2.val)\n", + " l3.next = self.addTwoNumbers(l1.next, l2.next)\n", + " # 相加大于等于 10,需要进位\n", + " elif l1.val + l2.val >= 10:\n", + " l3 = ListNode(l1.val + l2.val - 10)\n", + " tmp = ListNode(1)\n", + " tmp.next = None\n", + " # 递归调用\n", + " l3.next = self.addTwoNumbers(l1.next, self.addTwoNumbers(l2.next ,tmp))\n", + " return l3\n", + " \n", + "la = ListNode(2)\n", + "la.next = ListNode(4)\n", + "la.next.next = ListNode(3)\n", + "\n", + "lb = ListNode(5)\n", + "lb.next = ListNode(6)\n", + "lb.next.next = ListNode(4)\n", + "\n", + "s = Solution()\n", + "ss = s.addTwoNumbers(la, lb)\n", + "print(ss.val)\n", + "print(ss.next.val)\n", + "print(ss.next.next.val)\n", + "print(ss.next.next.next)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0005._longest_palindromic_substring.ipynb b/docs/Algorithm/Leetcode/ipynb/0005._longest_palindromic_substring.ipynb new file mode 100755 index 00000000..f0a71c9d --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0005._longest_palindromic_substring.ipynb @@ -0,0 +1,388 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 005. Longest Palindromic Substring 最长回文子串\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/longest-palindromic-substring/description/\n", + " - 英文:https://leetcode.com/problems/longest-palindromic-substring/\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。\n", + "\n", + "示例 1:\n", + "输入: \"babad\"\n", + "输出: \"bab\"\n", + "注意: \"aba\"也是一个有效答案。\n", + "\n", + "示例 2:\n", + "输入: \"cbbd\"\n", + "输出: \"bb\"\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + "如果一个字符串从左向右写和从右向左写是一样的,这样我们就把它叫做回文字符串。如 aba 或者 abba。\n", + "\n", + "首先想到的是一个最笨的方法,就是依次把每一个字符当做回文字符串的中间的那个字符,向两边扩展,找到以该字符为中间字符的回文串的最大长度。但是这需要将回文串长度是奇偶的情况分开来讨论。然后接下来要注意的关键是对边界的把握,确保下标不要越界。当子串已经包含首字符或最后一个字符且此时还是回文串的时候,下标分别会向两边多移一位,需要补回来。\n", + "\n", + "以 abba 这样一个字符串为例来看,abba 中,一共有偶数个字,第 1 位=倒数第 1 位,第 2 位=倒数第 2 位......第 N 位=倒数第 N 位\n", + "\n", + "以 aba 这样一个字符串为例来看,aba 中,一共有奇数个字符,排除掉正中间的那个字符后,第 1 位=倒数第 1 位......第 N 位=倒数第 N 位\n", + "\n", + "所以,假设找到一个长度为 len1 的子串后,我们接下去测试它是否满足,第 1 位=倒数第 1 位,第 2 位=倒数第 2 位......第 N 位=倒数第 N 位,也就是说,去测试从头尾到中点,字符是否逐一对应相等。如果一直进行了 [length/2] 次后,对应字符都相等,即满足第 i 位=倒数第 i 位。那么这个子串必然是palindromic string。并且,很容易知道,无论这个字符串长度为奇数还是偶数,都是 palindromic string,因为奇数位数的字符串相当于满足,第中间位=第中间位。\n", + "\n", + "于是,现在问题转化为能不能找到一个子串,满足,第 1 位=倒数第 1 位(下文叫做候选子串)。如果有,就对剩下的字符做进一步的检查。\n", + "\n", + "我们看一下下面的代码:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cbc\n" + ] + } + ], + "source": [ + "class Solution(object):\n", + " def longestPalindrome(self, s):\n", + " \"\"\"\n", + " :type s: str\n", + " :rtype: str\n", + " \"\"\"\n", + " if not s:\n", + " return\n", + " n = len(s)\n", + " if n == 1:\n", + " return s\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", + " # Whether the substring contains the first character or last character\n", + " # and is palindromic\n", + " b = True\n", + " # i 设置的是字符串的一个字符\n", + " for i in range(0, n):\n", + " # 奇数情况\n", + " # j 设置的是字符串的 i 字符的左右两边的 j 个字符是不是属于回文串,n-i 限制的是不能超出字符串末尾,i+1 限制的是不能越过字符串的开头\n", + " for j in range(0, min(n - i, i + 1)):\n", + " # 如果 以 i 字符为中央字符的情况,向两边扩展,不相等的话,代表不是回文串,停止继续比较\n", + " if (s[i - j] != s[i + j]):\n", + " b = False\n", + " break\n", + " else:\n", + " # 如果以 i 字符为中心字符向左右扩展 j 个字符是回文串,那么现在回文串的长度设置为 c\n", + " c = 2 * j + 1\n", + " # 判断 c 与 m 的大小,m 记录的是我们目前为止最长的回文串的长度,如果 c > m,那我们最长回文子串设置为 c ,否则仍然是原来的 m\n", + " if (c > m):\n", + " # 设置新的回文子串的左 index,b 是 True 就是等于 1,b 是 False 等于 0\n", + " l = i - j + 1 - b\n", + " # 设置新的回文子串的右 index\n", + " r = i + j + b\n", + " # 将新的最长回文子串赋值给 m\n", + " m = c\n", + " b = True\n", + " # 偶数情况\n", + " # i+1 限制的是不超越字符串的开头,n-i-1 限制的是不超过字符串末尾\n", + " for j in range(0, min(n - i - 1, i + 1)):\n", + " # 偶数情况下,对应位置上是够相等,相等则是回文串,不相等就不是回文串\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", + " # 将最终的回文串返回\n", + " return s[l:r]\n", + " \n", + "s = Solution()\n", + "nums = \"acbcd\"\n", + "print(s.longestPalindrome(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "上面是我们的一个参考版本,算是思路很清晰的。下面这个是 Lisanaaa 大佬根据上面版本进行修改的完成版本,总体思路是相同的,大家可以参考下。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cbc\n" + ] + } + ], + "source": [ + "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", + "s = Solution()\n", + "nums = \"acbcd\"\n", + "print(s.longestPalindrome(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + "很明显的一个动态规划思路。\n", + "\n", + " - 这个问题可以联想我们之前做的动态规划的问题,也就是 72 题,思想是一样的,但是相对于我们的 72 题来说,已经是相当简单了。\n", + " - 一个比较好的想法是 s 和 reverse(s) 共有的最长的 substring 就是 longest palindromic substring,这样我们就把问题转化为求 Longest common substring 问题了。\n", + " - 我们来看一下下面的代码,你就懂得了。\n", + " - 如果还是看不懂,那就去看看我们 72 题的讲解,已经很清楚了。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cbc\n" + ] + } + ], + "source": [ + "class Solution2(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 range(1 + len(s1))]\n", + " longest, x_longest = 0, 0\n", + " for x in range(1, 1 + len(s1)):\n", + " for y in range(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_2 = Solution2()\n", + "nums = \"acbcd\"\n", + "print(s_2.longestPalindrome(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "典型的动态规划问题。\n", + "\n", + "伪码如下:\n", + "\n", + "LCSuff(S1...p, T1...q) = LCS(S1...p1, T1...q-1) if S[p] = T[q] else 0\n", + "\n", + "代码可以参考:\n", + "\n", + "https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring#Python_2\n", + "\n", + "**但是我们上面的动态规划问题,仍然出现了超时的情况。**\n", + "\n", + "因为我们以为这样s[::-1]已经很快了.\n", + "\n", + "**特别注意:**\n", + "\n", + "这个方法是buggy的,看字符串 abcxgcba ,它 reverse 之后是 abcgxcba ,它们有公共字符串,但是这里面没有回文,修复方式是:\n", + "\n", + "we 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", + "原本 翻转\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", + "> 思路 3\n", + "\n", + "[Manacher算法,我私下叫马拉车算法,哈哈](https://www.felix021.com/blog/read.php?2040)\n", + "\n", + "Manacher 算法增加两个辅助变量 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", + "\n", + " - 当 P[j] >= mx - i 的时候,以 S[j] 为中心的回文子串不一定完全包含于以 S[id] 为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以 S[i] 为中心的回文子串,其向右至少会扩张到 mx 的位置,也就是说 P[i] >= mx - i。至于 mx 之后的部分是否对称,再具体匹配。 所以 P[i] >= Min(P[2 * id - i], mx - i),因为以 j 为中心的绘回文子串的左边界可能会比 mx 关于 id 的对称点要大,此时只能证明 P[i]=P[2 * id - i]\n", + "\n", + " - 此外,对于 mx <= i 的情况,因为无法对 P[i] 做更多的假设,只能让 P[i] = 1,然后再去匹配。\n", + "\n", + "在下面的程序中我的 P 数组保存的是,以当前字符为回文子串中心时,该回文子串的长度(不包含当前字符自身)\n", + "\n", + "简单地用一个小例子来解释:原字符串为 'qacbcaw' ,一眼就可以看出来最大回文子串是 'acbca' , 下面是我做的图,累 shi 了!\n", + "\n", + "\n", + "\n", + "所以最终代码中的 max_i 就是字符 'b' 所对应的 index8 ,start 的值就是 (max_i - P[max_i] - 1) / 2 = 1 ,最终输出结果为 s[1:6] ,即‘acbca’" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cbc\n" + ] + } + ], + "source": [ + "class Solution3(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 = int((max_i - P[max_i] - 1) / 2)\n", + " res = s[start: start + P[max_i]]\n", + " return res\n", + " \n", + "s_3 = Solution3()\n", + "nums = \"acbcd\"\n", + "print(s_3.longestPalindrome(nums)) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "run code的时候结果会跟expected不一样,但是该input确实2个结果都可以,所以放心地submit吧 还可以转到647题去看一看,也可以用这个算法解" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0007._Reverse_Integer.ipynb b/docs/Algorithm/Leetcode/ipynb/0007._Reverse_Integer.ipynb new file mode 100755 index 00000000..d471473d --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0007._Reverse_Integer.ipynb @@ -0,0 +1,168 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 7. Reverse Integer 反转整数\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/reverse-integer/description/\n", + " - 英文:https://leetcode.com/problems/Reverse-Integer\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个 32 位有符号整数,将整数中的数字进行反转。\n", + "\n", + "示例 1:\n", + "输入: 123\n", + "输出: 321\n", + "\n", + "示例 2:\n", + "输入: -123\n", + "输出: -321\n", + "\n", + "示例 3:\n", + "输入: 120\n", + "输出: 21\n", + "\n", + "注意:\n", + "假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0。\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - x > 0, flag = 1; x < 0, flag = -1\n", + " - 将 x 转成字符串 s = str(abs(x)),然后再反转字符串 s1 = s[::-1]\n", + " - 字符串再转为整数:x1 = int(s1) * flag\n", + " - 判断是否溢出,将数据返回" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "21\n", + "-654\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def reverse(self, x):\n", + " \"\"\"\n", + " :type x: int\n", + " :rtype: int\n", + " \"\"\"\n", + " # 如果是负数,我们需要注意转化为绝对值\n", + " flag = 1\n", + " x_1 = 0\n", + " if x < 0:\n", + " flag = -1\n", + " x = int(str(abs(x))[::-1])\n", + " x_1 = x * flag\n", + " else:\n", + " flag = 1\n", + " x = int(str(x)[::-1])\n", + " x_1 = x * flag\n", + " if x_1 > 2**31-1 or x_1 < -2**31:\n", + " return 0\n", + " else:\n", + " return x_1\n", + "\n", + "s = Solution()\n", + "x = 120\n", + "y = -456\n", + "print(s.reverse(x))\n", + "print(s.reverse(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 按照低位摘除,在按高位加上去其实就可以了\n", + " - 利用循环,每次将最后一位取出来(求余),然后将原来的数据除以 10 ,取整,这样就可以每次都得到个位数\n", + " - 按照取第二步,反向操作,取出来一个最后的个位数,然后乘以 10 ,再加上每一次得到的个位数,就实现了反转\n", + " - 注意一个点,python 中对一个数求余时,结果与 求余 的符号相同,比如 5 % 2 = 1, 5 % (-2) = -1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "21\n", + "-654\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def reverse(self, x):\n", + " \"\"\"\n", + " :type x: int\n", + " :rtype: int\n", + " \"\"\"\n", + " num = 0\n", + " flag = 1\n", + " if x > 0:\n", + " flag = 1\n", + " else:\n", + " flag = -1\n", + " while x != 0:\n", + " num = num * 10 + x % (10 * flag)\n", + " x = int(x / 10)\n", + " if num > 2**31-1 or num < -2**31:\n", + " return 0\n", + " else:\n", + " return num\n", + "s = Solution()\n", + "x = 120\n", + "y = -456\n", + "print(s.reverse(x))\n", + "print(s.reverse(y))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0009._Palindrome_Number.ipynb b/docs/Algorithm/Leetcode/ipynb/0009._Palindrome_Number.ipynb new file mode 100755 index 00000000..4a643d0f --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0009._Palindrome_Number.ipynb @@ -0,0 +1,165 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 9.Palindrome Number 回文数\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/palindrome-number/description\n", + " - 英文:https://leetcode.com/problems/palindrome-number\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。\n", + "\n", + "示例 1:\n", + "\n", + "输入: 121\n", + "输出: true\n", + "\n", + "示例 2:\n", + "\n", + "输入: -121\n", + "输出: false\n", + "解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。\n", + "\n", + "示例 3:\n", + "\n", + "输入: 10\n", + "输出: false\n", + "解释: 从右向左读, 为 01 。因此它不是一个回文数。\n", + "\n", + "进阶:\n", + "\n", + "你能不将整数转为字符串来解决这个问题吗?\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 首先负数肯定不是回文数\n", + " - 通过字符串进行反转,再转化为数字,对比数字是否相等就行" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def isPalindrome(self, x):\n", + " \"\"\"\n", + " :type x: int\n", + " :rtype: bool\n", + " \"\"\"\n", + " # 如果是负数,肯定不是回文数,排除掉\n", + " if x < 0:\n", + " return False\n", + " # 我们将 数字转为 str ,然后反转,再转化为 int,比较,相等的话,就是回文数,不相等的话,就不是回文数\n", + " elif x != int(str(x)[::-1]):\n", + " return False\n", + " else:\n", + " return True\n", + " \n", + "s = Solution()\n", + "x = 2345\n", + "y = 121\n", + "print(s.isPalindrome(x))\n", + "print(s.isPalindrome(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 负数一定不是回文数\n", + " - 如果一个数字是正数,并且能被我 0 整除那它肯定也不是 palidrome\n", + " - 这样我们就降低了复杂度" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def isPalindrome(self, x):\n", + " \"\"\"\n", + " :type x: int\n", + " :rtype: bool\n", + " \"\"\"\n", + " # 处理特殊情况:\n", + " # 1、负数一定不是回文数\n", + " # 2、如果数字的最后一位是 0, 为了让数字是回文数字,则第一位数字也应该是 0,只有 0 满足这种情况\n", + " if x < 0 or (x % 10 == 0 and x is not 0):\n", + " return False\n", + " revertNumber = 0\n", + " while x > revertNumber:\n", + " revertNumber = revertNumber * 10 + x % 10\n", + " x /= 10\n", + " # 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。\n", + " # 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,\n", + " # 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。\n", + " return x == revertNumber or x == revertNumber/10\n", + "\n", + "s = Solution()\n", + "x = 2345\n", + "y = 121\n", + "print(s.isPalindrome(x))\n", + "print(s.isPalindrome(y))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0010._regular_expression_matching.ipynb b/docs/Algorithm/Leetcode/ipynb/0010._regular_expression_matching.ipynb new file mode 100755 index 00000000..8a6af2b6 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0010._regular_expression_matching.ipynb @@ -0,0 +1,311 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 010. Regular Expression Matching 正则表达式匹配\n", + "\n", + "### 难度:Hard\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/two-sum/description\n", + " - 英文:https://leetcode.com/problems/two-sum\n", + "\n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个字符串 (s) 和一个字符模式 (p)。实现支持 '.' 和 '*' 的正则表达式匹配。\n", + "\n", + "'.' 匹配任意单个字符。\n", + "'*' 匹配零个或多个前面的元素。\n", + "匹配应该覆盖整个字符串 (s) ,而不是部分字符串。\n", + "\n", + "说明:\n", + " - s 可能为空,且只包含从 a-z 的小写字母。\n", + " - p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。\n", + "\n", + "示例 1:\n", + "输入:\n", + "s = \"aa\"\n", + "p = \"a\"\n", + "输出: false\n", + "解释: \"a\" 无法匹配 \"aa\" 整个字符串。\n", + "\n", + "示例 2:\n", + "输入:\n", + "s = \"aa\"\n", + "p = \"a*\"\n", + "输出: true\n", + "解释: '*' 代表可匹配零个或多个前面的元素, 即可以匹配 'a' 。因此, 重复 'a' 一次, 字符串可变为 \"aa\"。\n", + "\n", + "示例 3:\n", + "输入:\n", + "s = \"ab\"\n", + "p = \".*\"\n", + "输出: true\n", + "解释: \".*\" 表示可匹配零个或多个('*')任意字符('.')。\n", + "\n", + "示例 4:\n", + "输入:\n", + "s = \"aab\"\n", + "p = \"c*a*b\"\n", + "输出: true\n", + "解释: 'c' 可以不被重复, 'a' 可以被重复一次。因此可以匹配字符串 \"aab\"。\n", + "\n", + "示例 5:\n", + "输入:\n", + "s = \"mississippi\"\n", + "p = \"mis*is*p*.\"\n", + "输出: false\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + "暴力法。Lisanaaa 大佬想出来的,不得不赞一个,哈哈哈。之前想暴力法,把脑袋想爆掉了都没想全各种情况。那么,看看他是怎么解的吧。\n", + "\n", + "\".\" 很容易处理。难点就在 \"*\" 身上, \"*\" 是不会单独的,它一定是和前面的 一个字母或者 \".\" 配成一对 出现的。看成一对后是这样子的 \"X*\" ,它的性质是:要么匹配 0 个,要么匹配连续的 \"X\" 。所以尝试暴力法的时候一个 trick 是从后往前匹配。\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", + " - s 已经匹配完了, 如果此时 p 还有,那么如果剩下的是 X* 这种可以过,所以需要检查一下\n", + " - p 匹配完毕,如果 s 还有没有匹配的话,那么就 return False" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = 'abc'\n", + "p = 'a*abc'\n", + "ss = Solution()\n", + "print(ss.isMatch(s, p))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + "动态规划 解法。\n", + "\n", + "dp 优化,感觉和 edit distance 很像。DP优化待代码化,感觉学DP的一个重点除了递归学好以外,另一点是一定要会画表格。\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\n", + "a\t1\t0\t0\t0\t1\t1\t0\t\t\t\t\t\n", + "a\t2\t0\t0\t0\t0\t1\t0\t\t\t\t\t\n", + "b\t3\t0\t0\t0\t0\t0\t1\t\t\t\n", + "```\n", + "\n", + "这里有几个取巧/容易出问题的敌方,这里画的表用的是1-based string。一上来,做的事包括:\n", + "\n", + " - 初始化,空字符匹配:dp[0][0] =1\n", + " - 第一行, c * 可以匹配空字符, c * a * 可以匹配空字符, p[j-1] != s[i] ,匹配空字符\n", + " - 然后进入第二行再来看,实际上我们可以看到,如果没有碰到 * 匹配还是很朴素的,但是碰到 * :\n", + " - 1 这个匹配可以从左侧传来,dp[i][j] = dp[i][j-1] ,that is 匹配 1 个\n", + " - 1 也可以有上方传来,这种情况是 p[j-1] = s[i] ,匹配多个 dp[i][j] = dp[i-1][j]\n", + " - 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", + " - p[j-1] != s[i] : dp[i][j] = dp[i][j-2] 匹配 0 个的状况\n", + " - p[j-1] == s[i] or p[i-1] == '.':\n", + " - dp[i][j] = dp[i-1][j] 匹配多个 s[i]\n", + " - dp[i][j] = dp[i][j-2] 匹配 0 个\n", + "\n", + "AC 代码,注意一下,因为上表为了表达方便,用的是 1-based string 系统,实际写代码的时候我们心里还是清楚这个 string 还是从 0 开始的,不过也可以尝试往前面添东西来方便。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = 'abc'\n", + "p = 'a*abc'\n", + "ss = Solution()\n", + "print(ss.isMatch(s, p))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "我做的动态规划和上面大体思路是类似的。\n", + "\n", + "直接说动态转移方程组了,我们首先定义一些变量方便解释,被匹配串为s,模式串为p。状态转移数组 dp[i][j]表示利用 p 的前 j 个字符匹配 s 的前 i 个字符的匹配结果(成功为 true,失败为 false)。\n", + "\n", + " - **s[i] == p[j] || p[j] == '.'** ,那么 dp[i][j] = dp[i-1][j-1] ,也就是既然 s 串的第 i 个字符能和 p 串的第 j 个字符匹配,那么如果 s 串的前 i-1 个字符和 p 串的前 j-1 个字符能匹配则 s 串的前 i 个和 p 串的前 j 个则能匹配,反之不能。\n", + " - **p[j] == '*'** :分情况讨论。\n", + " - **s[i] != p[j-1] && p[j-1] != '.'** ,那么 dp[i][j] = dp[i][j-2] ,也就是 * 号前面的那个字符在匹配的过程当中一个都不使用。\n", + " - **else,那么dp[i][j] = dp[i-1][j] || dp[i][j-1] || dp[i][j-2]**,也就是说要么使用 '*' 号进行匹配( dp[i-1][j] ),要么只使用 '*' 号前面的那个字符匹配,不使用 '*' 匹配( dp[i][j-1] ),要么 '*' 号前面的那个字符在匹配的过程当中一个都不使用( dp[i][j-2] ),只要有一个是 true 则能够匹配。\n", + " \n", + "最后考虑一下边界条件。一开始 i 是从 1 到 len(s) ,j 是 1 到 len(p) 。首先一来就能想到 dp[0][0] 是true,其他都是 false。但是这个边界条件是不够的。比如 isMatch(\"aab\", \"c * a * b\") ,dp[1][3] 应该是从 dp[0][2] 转移过来的,所以需要更多的边界条件,也就是一开始的 * 是能匹配空字符串的。所以我把 i 改到了从 0 开始,并且第二条也添加了 i=0,dp[i][j] = dp[i][j-2] 。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def isMatch(self, s, p):\n", + " \"\"\"\n", + " :type s: str\n", + " :type p: str\n", + " :rtype: bool\n", + " \"\"\"\n", + " dp = []\n", + " dp = [[False for i in range(len(p)+1)] for j in range(len(s)+1)]\n", + " dp[0][0] = True\n", + "# print(dp)\n", + " for i in range(len(s)+1):\n", + " for j in range(1, len(p)+1):\n", + " if i > 0 and (s[i-1] == p[j-1] or p[j-1] == '.'):\n", + "# print(\"1111111\",i)\n", + "# print(\"2222222\",j)\n", + " dp[i][j] = dp[i-1][j-1]\n", + "# print(\"3333333\",dp[i-1][j-1])\n", + " if p[j-1] == '*':\n", + " if i == 0 or (s[i-1] != p[j-2] and p[j-2] != '.'):\n", + "# print(\"4444444\",i)\n", + "# print(\"5555555\",j)\n", + " dp[i][j] = dp[i][j-2]\n", + "# print(\"6666666\",dp[i][j-2])\n", + " else:\n", + " dp[i][j] = dp[i-1][j] or dp[i][j-1] or dp[i][j-2]\n", + "# print(\"7777777\",i)\n", + "# print(\"8888888\",j)\n", + "# print(dp) \n", + " return dp[len(s)][len(p)]\n", + " \n", + "s = 'aa'\n", + "p = 'a*'\n", + "ss = Solution()\n", + "print(ss.isMatch(s, p))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0013._Roman_to_Integer.ipynb b/docs/Algorithm/Leetcode/ipynb/0013._Roman_to_Integer.ipynb new file mode 100755 index 00000000..8ac444f2 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0013._Roman_to_Integer.ipynb @@ -0,0 +1,197 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 013.Roman to Integer\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 英文:https://leetcode.com/problems/roman-to-integer/\n", + " - 中文:https://leetcode-cn.com/problems/roman-to-integer/description/\n", + "\n", + "> 内容描述\n", + "\n", + "```\n", + "罗马数字包含以下七种字符:I, V, X, L,C,D 和 M。\n", + "\n", + "字符 数值\n", + "I 1\n", + "V 5\n", + "X 10\n", + "L 50\n", + "C 100\n", + "D 500\n", + "M 1000\n", + "\n", + "例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。\n", + "\n", + "通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:\n", + "\n", + "I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。\n", + "X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 \n", + "C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。\n", + "\n", + "给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。\n", + "\n", + "示例 1:\n", + "输入: \"III\"\n", + "输出: 3\n", + "\n", + "示例 2:\n", + "输入: \"IV\"\n", + "输出: 4\n", + "\n", + "示例 3:\n", + "输入: \"IX\"\n", + "输出: 9\n", + "\n", + "示例 4:\n", + "输入: \"LVIII\"\n", + "输出: 58\n", + "解释: C = 100, L = 50, XXX = 30, III = 3.\n", + "\n", + "示例 5:\n", + "输入: \"MCMXCIV\"\n", + "输出: 1994\n", + "解释: M = 1000, CM = 900, XC = 90, IV = 4.\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 从前向后依次扫描,用一个临时变量记录当前数字。\n", + " - 如果没有出现题目中出现的特殊情况,那我们就可以一直一个一个加下去,这样就能得到正确结果。\n", + " - 特殊情况出现的时候,后一位数字比前一位数字大,而正常情况正好是相反的(后一位数字一定比前一位小),后一位减去前一位即可得到这两位得到的数值,但是要注意一点,我们在这之前已经将前一位进行加和了一次,所以这时候,我们要减去 2 次前一位数字。\n", + " - 其他地方没有太难的部分,以下是 AC 代码。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1994\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "string = \"MCMXCIV\"\n", + "print(s.romanToInt(string))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "可以修改一下的地方,我们可以将从字典中取数的逻辑封装到一个函数中,这样也比较优雅。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1994\n" + ] + } + ], + "source": [ + "def getNum(x):\n", + " return {\"I\":1,\n", + " \"V\":5,\n", + " \"X\":10,\n", + " \"L\":50,\n", + " \"C\":100,\n", + " \"D\":500,\n", + " \"M\":1000}.get(x)\n", + "\n", + "class Solution: \n", + " def romanToInt(self, s):\n", + " \"\"\"\n", + " :type s: str\n", + " :rtype: int\n", + " \"\"\"\n", + " Num = {\n", + " 'M': 1000,\n", + " 'D': 500,\n", + " 'C': 100,\n", + " 'L': 50,\n", + " 'X': 10,\n", + " 'V': 5,\n", + " 'I': 1\n", + " }\n", + " result = 0\n", + " for i in range(len(s)):\n", + " if i > 0 and Num[s[i]] > Num[s[i-1]]:\n", + " result = result + Num[s[i]] - 2 * Num[s[i-1]]\n", + " else:\n", + " result += Num[s[i]]\n", + " return result\n", + " \n", + "s = Solution()\n", + "string = \"MCMXCIV\"\n", + "print(s.romanToInt(string))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0020._valid_parentheses.ipynb b/docs/Algorithm/Leetcode/ipynb/0020._valid_parentheses.ipynb new file mode 100755 index 00000000..f665733d --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0020._valid_parentheses.ipynb @@ -0,0 +1,302 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 20. Valid Parentheses 有效的括号\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/valid-parentheses/description\n", + " - 英文:https://leetcode.com/problems/valid-parentheses\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。\n", + "\n", + "有效字符串需满足:\n", + "\n", + "1、左括号必须用相同类型的右括号闭合。\n", + "2、左括号必须以正确的顺序闭合。\n", + "\n", + "注意空字符串可被认为是有效字符串。\n", + "\n", + "示例1:\n", + "输入: \"()\"\n", + "输出: true\n", + "\n", + "示例2:\n", + "输入: \"()[]{}\"\n", + "输出: true\n", + "\n", + "示例3:\n", + "输入: \"(]\"\n", + "输出: false\n", + "\n", + "示例4:\n", + "输入: \"([)]\"\n", + "输出: false\n", + "\n", + "示例5:\n", + "输入: \"{[]}\"\n", + "输出: true\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + "我们只需要匹配三种情况: \"(\" -> \")\", \"[\" -> \"]\", \"{\" -> \"}\".\n", + "\n", + "但是这里最重要的思想是 栈 。一遇到左括号就入栈,右括号出栈,这样来寻找对应。\n", + "\n", + "需要检查几件事:\n", + "\n", + " - 出现右括号时 stack 里是否还有符号(无论左右)\n", + " - 出 stack 时是否对应\n", + " - 最终 stack 是否为空" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def isValid(self, s):\n", + " \"\"\"\n", + " :type s: str\n", + " :rtype: bool\n", + " \"\"\"\n", + " LEFT = {'(', '[', '{'} # 左括号\n", + " RIGHT = {')', ']', '}'} # 右括号\n", + " stack = [] # 创建一个栈\n", + " for brackets in s: # 迭代传过来的所有字符串\n", + " if brackets in LEFT: # 如果当前字符在左括号内\n", + " stack.append(brackets) # 把当前左括号入栈\n", + " elif brackets in RIGHT: # 如果是右括号\n", + " if not stack or not 1 <= ord(brackets) - ord(stack[-1]) <= 2:\n", + " # 如果当前栈为空,()]\n", + " # 如果右括号减去左括号的值不是小于等于2大于等于1\n", + " return False # 返回False\n", + " stack.pop() # 删除左括号\n", + " return not stack # 如果栈内没有值则返回True,否则返回False\n", + " \n", + "s = Solution()\n", + "print(s.isValid(\"([[])[]{}\"))\n", + "print(s.isValid(\"([])[]{}\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "与 思路 1 相同,但是更加容易理解的版本:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.isValid(\"([[])[]{}\"))\n", + "print(s.isValid(\"([])[]{}\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 扩展性和可理解性更强\n", + " - 使用字典类型来存储对应关系" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.isValid(\"([[])[]{}\"))\n", + "print(s.isValid(\"([])[]{}\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3\n", + "\n", + " - 括号匹配,我们可以换用另一种方式\n", + " - 首先,不管它是否符合第一个符号是左括号的要求,我们先把它放到list 中,作为栈,然后一个一个遍历,符合配对顺序就弹出,最终只需要判断是否栈为空就可以了" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n" + ] + } + ], + "source": [ + "l_d = {\n", + " '{': -3,\n", + " '(': -2,\n", + " '[': -1,\n", + " ']': 1,\n", + " ')': 2,\n", + " '}': 3,\n", + "}\n", + " \n", + "class Solution:\n", + " def isValid(self, s):\n", + " l_s = []\n", + " for c_r in s:\n", + " if len(l_s) == 0:\n", + " l_s.append(c_r)\n", + " continue\n", + "\n", + " c_l = l_s[-1]\n", + "\n", + " if l_d[c_l] + l_d[c_r] == 0 and l_d[c_l] < 0:\n", + " l_s.pop()\n", + " else:\n", + " l_s.append(c_r)\n", + "\n", + " if len(l_s) == 0:\n", + " return True\n", + " else:\n", + " return False\n", + " \n", + "s = Solution()\n", + "print(s.isValid(\"([[])[]{}\"))\n", + "print(s.isValid(\"([])[]{}\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0032._longest_valid_parentheses.ipynb b/docs/Algorithm/Leetcode/ipynb/0032._longest_valid_parentheses.ipynb new file mode 100755 index 00000000..56e88640 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0032._longest_valid_parentheses.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# 032.longest-valid-parentheses 最长有效括号\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/longest-valid-parentheses/description\n", + " - 英文:https://leetcode.com/problems/longest-valid-parentheses\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。\n", + "\n", + "示例 1:\n", + "输入: \"(()\"\n", + "输出: 2\n", + "解释: 最长有效括号子串为 \"()\"\n", + "\n", + "示例 2:\n", + "输入: \")()())\"\n", + "输出: 4\n", + "解释: 最长有效括号子串为 \"()()\"\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + "**注:** 千万注意,这个题上来就坑了一下,题目没有说清楚一种情况,比如 (()) ,这种情况,有效括号子串是 4 ,而不是错误的。\n", + "\n", + "实际上,在看到这个最长有效括号的题目的时候,我就想到了之前我们做的一个题目。LeetCode 20 题,它的解法是如何使用堆栈判断括号序列是否可以成功配对。我们仍然可以将堆栈的思想延续到这里。\n", + "\n", + "每当遇到一个左括号或者是无法成对的右括号,就将它压入栈中,可以成对的括号则从栈中 pop 出。这样栈中剩下的就是无法成对的括号的下标。这时我们可以判断这些下标间的距离来获得最大的成对括号长度。 **在这里,我们需要先遍历一遍字符串,再遍历一下非空的堆栈。一定要注意,这里我们遍历的非空的栈存储的是没有匹配上的括号下标,匹配上的我们都已经做了pop 处理。**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "4\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def longestValidParentheses(self, s):\n", + " \"\"\"\n", + " :type s: str\n", + " :rtype: int\n", + " \"\"\"\n", + " # 创建一个 stack ,用来做 栈 的操作\n", + " stack = []\n", + " # 第一次遍历 s 字符串\n", + " for i in range(len(s)):\n", + " # 如果当前循环到的 字符 是 右括号,那就要 检查一下栈内是否有与之匹配的 左括号\n", + " if s[i] == ')':\n", + " # stack 如果不为空,并且 stack 的栈顶元素存储的下标在 s 字符串中是 左括号\n", + " if stack and s[stack[-1]] == '(':\n", + " # 将栈顶元素 pop 出来,与当前的 右括号 配对\n", + " stack.pop()\n", + " # 直接 continue\n", + " continue\n", + " stack.append(i)\n", + " # 设置 最大长度\n", + " max_length = 0\n", + " # 设置为当前字符串 s 的长度\n", + " next_index = len(s)\n", + " # 遍历 非空的栈\n", + " while stack:\n", + " # 当前的栈顶存储的 s 的下标\n", + " cur_index = stack.pop()\n", + " # 计算下一个有效的最长括号长度\n", + " cur_length = next_index - cur_index - 1\n", + " # 将之与 之前存储的 max_length 比较,留下较大值\n", + " max_length = max(cur_length, max_length)\n", + " # 下一个的有效括号的右索引赋值,接着进入下一次循环,一直到 stack 为空\n", + " next_index = cur_index\n", + " # 遍历到最后的时候,肯定 next_index 即是有效符号的长度,与 max_length 做比较,取较大值\n", + " return max(next_index, max_length)\n", + " \n", + " \n", + "s = Solution()\n", + "print(s.longestValidParentheses(\"()(())\"))\n", + "print(s.longestValidParentheses(\"()()(()\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + "使用动态规划(dynamic programming)思想来做这个问题。\n", + "\n", + "下面是 片刻 大佬想出来的,我感觉思想真的超棒。参考链接:http://www.cnblogs.com/George1994/p/7531574.html\n", + "\n", + "1. 用一个 dp 数组来存放以每个 index 为结尾的最长有效括号子串长度,例如:dp[3] = 2 代表以 index 为 3 结尾的最长有效括号子串长度为 2\n", + "2. 很明显,dp[i] 和 dp[i-1] 之间是有关系的。\n", + " - 当 dp[i] 所在的索引 i 在字符串 s 中代表的字符是 \"(\" 时,也就是 s[i] == '(' ,很显然,此时的 dp[i] 与之前的一个关系是 dp[i] = dp[i-1] + 0,也就是不用处理。\n", + " - 当 dp[i] 所在的索引 i 在字符串 s 中代表的字符是 \")\" 时,也就是 s[i] == ')' 时,如果在 dp[i-1] 的所表示的最长有效括号子串之前还有一个 '(' 与 s[i] 对应,那么 dp[i] = dp[i-1] + 2,并且还可以继续往前追溯(如果前面还能连接起来的话)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "4\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.longestValidParentheses(\"()(())\"))\n", + "print(s.longestValidParentheses(\"()()(()\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0053._maximum_subarray.ipynb b/docs/Algorithm/Leetcode/ipynb/0053._maximum_subarray.ipynb new file mode 100755 index 00000000..1bbb8ab2 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0053._maximum_subarray.ipynb @@ -0,0 +1,275 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 53. Maximum Subarray 最大子序和\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/maximum-subarray/description/\n", + " - 英文:https://leetcode.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", + "如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 可以用 O(N^2) 循环\n", + " - 从i开始,计算i到n,存比较大的sum\n", + " - 会超时,不会 AC" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "1\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def maxSubArray(self, nums):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :rtype: int\n", + " \"\"\"\n", + " # 设置为无穷小\n", + " ans = float('-inf')\n", + " # 这个循环控制子串的元素个数\n", + " for i in range(1, len(nums)):\n", + " # 这个循环控制子串从原始串的哪个位置开始计算\n", + " for j in range(len(nums)-i):\n", + " big = 0\n", + " big = sum(nums[j : j+i])\n", + " if big > ans:\n", + " ans = big\n", + " return ans\n", + "\n", + "s = Solution()\n", + "nums_1 = [-2,1,-3,4,-1,2,1,-5,4]\n", + "nums_2 = [1, -1]\n", + "print(s.maxSubArray(nums_1))\n", + "print(s.maxSubArray(nums_2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 2\n", + "\n", + " - 使用动态规划\n", + " - ms(i) = max(ms[i-1] + a[i], a[i])\n", + " - 我们只需要知道,计算到 i 处的最大值的两种可能,一个是加上 a[i],另一个是从 a[i] 开始重新计算子串。\n", + " - 比较 ms[i-1]+a[i] 与 a[i] 的值的大小关系,如果前者小于后者,就说明,前面的子串的最大的和是负数,我们可以抛弃掉,而从 a[i] 处开始起头重新计算子串;如果前者大于后者,说明,前面的子串的最大的和是正数,我们可以加上 a[i] 继续计算。\n", + " - 可以 AC" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "1\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "nums_1 = [-2,1,-3,4,-1,2,1,-5,4]\n", + "nums_2 = [1, -1]\n", + "print(s.maxSubArray(nums_1))\n", + "print(s.maxSubArray(nums_2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3\n", + "\n", + "Kadane’s Algorithm wikipedia可以查到,然后一般的是负的可以还回0,这里需要稍作修改,参考:\n", + "http://algorithms.tutorialhorizon.com/kadanes-algorithm-maximum-subarray-problem/\n", + "\n", + "```\n", + "start:\n", + " max_so_far = a[0]\n", + " max_ending_here = a[0]\n", + "\n", + "loop 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", + "\n", + "return max_so_far\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "AC 代码如下:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "1\n" + ] + } + ], + "source": [ + "class 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", + " maxEnd = max(nums[i],maxEnd + nums[i])\n", + " maxSum = max(maxEnd,maxSum)\n", + " return maxSum\n", + " \n", + "s = Solution()\n", + "nums_1 = [-2,1,-3,4,-1,2,1,-5,4]\n", + "nums_2 = [1, -1]\n", + "print(s.maxSubArray(nums_1))\n", + "print(s.maxSubArray(nums_2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 4\n", + "\n", + "参见clrs 第71页,用divide and conquer,有伪码\n", + "\n", + "最大的 subarray sum 有三个可能,左半段或者右半段,或者跨越左右半段,\n", + "\n", + "速度比较慢,AC代码,复杂度O(NlogN)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Solution(object):\n", + " def maxSubArray(self, nums):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :rtype: int\n", + " \"\"\"\n", + " def find_max_crossing_subarray(nums, low, mid, high):\n", + " left_sum = float('-inf')\n", + " sum = 0\n", + " for i in xrange(mid,low-1,-1):\n", + " sum = sum + nums[i]\n", + " if sum > left_sum:\n", + " left_sum = sum\n", + "\n", + " right_sum = float('-inf')\n", + " sum = 0\n", + " for j in range(mid+1,high+1):\n", + " sum = sum + nums[j]\n", + " if sum > right_sum:\n", + " right_sum = sum\n", + "\n", + " return left_sum + right_sum\n", + "\n", + " def find_max_subarray(nums,low,high):\n", + " if low == high: \n", + " return nums[low]\n", + " else:\n", + " mid = (low + high) / 2\n", + " left_sum = find_max_subarray(nums, low, mid)\n", + " right_sum = find_max_subarray(nums,mid+1,high)\n", + " cross_sum = find_max_crossing_subarray(nums,low,mid,high)\n", + " # print left_sum, right_sum, cross_sum\n", + " # print mid, low, high\n", + " return max(left_sum, right_sum, cross_sum)\n", + "\n", + " return find_max_subarray(nums, 0, len(nums)-1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0062._unique_paths.ipynb b/docs/Algorithm/Leetcode/ipynb/0062._unique_paths.ipynb new file mode 100755 index 00000000..372560e0 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0062._unique_paths.ipynb @@ -0,0 +1,167 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 062.unique_paths 不同路径\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/unique-paths/description\n", + " - 英文:https://leetcode.com/problems/unique-paths\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。\n", + "\n", + "机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。\n", + "\n", + "问总共有多少条不同的路径?\n", + "\n", + "说明:m 和 n 的值均不超过 100。\n", + "\n", + "示例 1:\n", + "输入: m = 3, n = 2\n", + "输出: 3\n", + "解释:\n", + "从左上角开始,总共有 3 条路径可以到达右下角。\n", + "1. 向右 -> 向右 -> 向下\n", + "2. 向右 -> 向下 -> 向右\n", + "3. 向下 -> 向右 -> 向右\n", + "\n", + "示例 2:\n", + "输入: m = 7, n = 3\n", + "输出: 28\n", + "\n", + "例如,下图是一个3 x 7 的网格。有多少可能的路径?\n", + "```\n", + "\n", + "![](img/robot_maze.png)\n", + "\n", + "## 解决方案\n", + "\n", + "> 思路 1\n", + "\n", + "数学思路。\n", + "\n", + "本质上,这道题就是排列组合,一共走 m + n - 步,其中 m - 1 步是向右边走,所以不就是从 m + n - 2 中选择 m-1 个的问题,阶乘问题,so easy !妈妈再也不用担心我的学习!!!这个方法 beats 99.97% 。\n", + "\n", + "补充一下,math 模块中自带 factorial 函数,只要 import math 之后调用即可。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "28.0\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.uniquePaths(7,3))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "> 思路 2\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 |" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "28\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "print(s.uniquePaths(7,3))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0064._minimum_path_sum.ipynb b/docs/Algorithm/Leetcode/ipynb/0064._minimum_path_sum.ipynb new file mode 100755 index 00000000..2844c495 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0064._minimum_path_sum.ipynb @@ -0,0 +1,160 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 064. Minimum Path Sum 最小路径和\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/minimum-path-sum/description\n", + " - 英文:https://leetcode.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", + "使用 动态规划 ,我们考虑到,一个位于 [i][j] 位置的格子,到达它的路径只有 2 条:1 条是从上到下到达这个格子([i-1][j] -> [i][j]),另一条是从左到右到达这个格子([i][j-1] -> [i][j])。我们只需要关注这两条路径中,哪条路径的路径和最小就好了。 另外可以参考 072.编辑距离 。" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def minPathSum(self, grid):\n", + " \"\"\"\n", + " :type grid: List[List[int]]\n", + " :rtype: int\n", + " \"\"\"\n", + " m = len(grid)\n", + " n = len(grid[0])\n", + " dp = grid.copy()\n", + " for i in range(1, n):\n", + " dp[0][i] = dp[0][i-1] + grid[0][i]\n", + " for i in range(1, m):\n", + " dp[i][0] = dp[i-1][0] + grid[i][0]\n", + " for i in range(1, m):\n", + " for j in range(1, n):\n", + " dp[i][j] = min(dp[i][j-1] + grid[i][j], dp[i-1][j] + grid[i][j])\n", + " return dp[m-1][n-1]\n", + " \n", + "s = Solution()\n", + "grid = [\n", + " [1,3,1],\n", + " [1,5,1],\n", + " [4,2,1]\n", + "]\n", + "print(s.minPathSum(grid))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "上面的版本是我最初写成的,后来听大佬们说,尽量减少 for 循环的个数。改成下面的最终版本,已经 AC 。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "class 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", + "s = Solution()\n", + "grid = [\n", + " [1,3,1],\n", + " [1,5,1],\n", + " [4,2,1]\n", + "]\n", + "print(s.minPathSum(grid))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0072._edit_distance.ipynb b/docs/Algorithm/Leetcode/ipynb/0072._edit_distance.ipynb new file mode 100755 index 00000000..9c8a9d1c --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0072._edit_distance.ipynb @@ -0,0 +1,211 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 072. Edit Distance 编辑距离\n", + "\n", + "### 难度:Hard\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/edit-distance/description/\n", + " - 英文:https://leetcode.com/problems/edit-distance/\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。\n", + "\n", + "你可以对一个单词进行如下三种操作:\n", + "\n", + "插入一个字符\n", + "删除一个字符\n", + "替换一个字符\n", + "\n", + "示例 1:\n", + "输入: word1 = \"horse\", word2 = \"ros\"\n", + "输出: 3\n", + "解释: \n", + "horse -> rorse (将 'h' 替换为 'r')\n", + "rorse -> rose (删除 'r')\n", + "rose -> ros (删除 'e')\n", + "\n", + "示例 2:\n", + "输入: word1 = \"intention\", word2 = \"execution\"\n", + "输出: 5\n", + "解释: \n", + "intention -> inention (删除 't')\n", + "inention -> enention (将 'i' 替换为 'e')\n", + "enention -> exention (将 'n' 替换为 'x')\n", + "exention -> exection (将 'n' 替换为 'c')\n", + "exection -> execution (插入 'u')\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "这个题目是动态规划的典型例题,在 wikipedia 中是有相应页面介绍的。\n", + "\n", + " - https://en.wikipedia.org/wiki/Edit_distance#Common_algorithm\n", + " - https://en.wikipedia.org/wiki/Levenshtein_distance\n", + "\n", + "> 思路 1\n", + "\n", + " - 使用动态规划\n", + "\n", + "下面我们说说,这个题的思路。具体来描述一下。\n", + "\n", + "要始终明确一点, dp[i][j] 的含义是使得 word1 的前 i 字符子串与 word2 的前 j 字符子串相等所需要的操作数,这也是为什么我们需要在初始化 dp 矩阵时需要行列数均加上 1 。\n", + "\n", + "我们创建一个 dp[][] 二维数组,表示从 word1 的前 i 个字符(下标为:0~ i-1)到 word2 的前 j 个字符(下标为:0~j-1)的编辑过程中,需要的最少步数,那么:\n", + "\n", + "如果 $word1[i] = word2[j]$ 则 $dp[i][j] = dp[i-1][j-1]$\n", + "\n", + "如果 $word1[i] != word2[j]$ 则 $dp[i][j] = min ( dp[i-1][j] , dp[i][j-1], dp[i-1][j-1] ) + 1$\n", + "\n", + "下面就是我们对上述动态规划过程的解释:\n", + "\n", + "第一个条件比较容易理解,就是说 word1 的下标为 i 的字符 和 word2 的下标为 j 的字符相同,那么这个位置的字符我们不需要进行操作,所以我们只需要关注 word1 和 word2 去除掉相应位置的字符之后的子串的结果即可。\n", + "\n", + "我们下面对第二个条件的三种情况进行重点讲解:\n", + "\n", + "假设 word1 的前 i+1 (下标为 0~i)的子串为 \"abcde\"\n", + "假设 word2 的前 j+1 (下标为 0~j)的子串为 \"abcddgf\"\n", + "现在 word1[i] != word2[j],也就是 'e' != 'f'\n", + "\n", + "那么我们接下来应该怎么做呢?\n", + "\n", + "我们会发现,我们做的三种解释实际上就是把我们题中写到的三种操作模拟在最后一步实现。每种操作都是额外加一的操作。\n", + "\n", + "简单说,就是这样:\n", + " - 1.delete:dp[i-1][j] + 1 —— 保留了从 word1[0~i-1] 转变到 word2[0~j] 的最优操作次数,因为我们的 word1 的 0~i-1 已经能够转变到 word2 了,所以我们就直接把 word1 中的最后一个字符删除掉就行了。所以就需要额外进行一个 删除 操作。\n", + " - 2.insert:dp[i][j-1] + 1 —— 保留了从 word1[0~i] 转变到 word2[0~j-1] 的最优操作次数,因为我们的 word1 的 0~i 只能转变到 word2 的倒数第二位,所以我们就直接在 word1 的末尾添加一个与 word2 的最后一个字符相同的字符就可以了。所以就需要额外进行一个 插入 操作。\n", + " - 3.replace:dp[i-1][j-1] + 1 —— 保留了从 word1[0~i-1] 转变到 word2[0~j-1] 的最优操作次数,因为我们的 word1 的 0~i-1 只能转变到 word2 的倒数第二位,而 word1 的最后一位与 word2 的最后一位是不同的,所以现在的情况只需要额外的一个 替换 操作即可。\n", + "\n", + "\n", + "无论我们选取上面 3 中操作的哪种操作,我们选其中最小的值就可以了。\n", + "\n", + "参考链接:http://www.cnblogs.com/pandora/archive/2009/12/20/levenshtein_distance.html\n", + "\n", + "下面我们看一下代码:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def minDistance(self, word1, word2):\n", + " \"\"\"\n", + " :type word1: str\n", + " :type word2: str\n", + " :rtype: int\n", + " \"\"\"\n", + " # 初始化一个 len(word1)+1 * len(word2)+1 的矩阵\n", + " matrix = [[i+j for j in range(len(word2) + 1)] for i in range(len(word1) + 1)]\n", + " # 辅助理解,matrix 矩阵的样子\n", + " # print(matrix)\n", + " for i in range(1, len(word1)+1):\n", + " for j in range(1,len(word2)+1):\n", + " if word1[i-1] == word2[j-1]:\n", + " d = 0\n", + " else:\n", + " d = 1\n", + " matrix[i][j] = min(matrix[i-1][j]+1, matrix[i][j-1]+1, matrix[i-1][j-1]+d)\n", + "\n", + " return matrix[len(word1)][len(word2)]\n", + " \n", + "s = Solution()\n", + "word1 = 'horse'\n", + "word2 = 'ros'\n", + "print(s.minDistance(word1, word2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "上面代码的 matrix 矩阵生成,可能会让大家产生理解误差,我在这个地方的理解也是通过大佬问,我才知道具体是怎么回事的。\n", + "\n", + "下面我们把它打印一下。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "matrix([[0, 1, 2, 3],\n", + " [1, 2, 3, 4],\n", + " [2, 3, 4, 5],\n", + " [3, 4, 5, 6],\n", + " [4, 5, 6, 7],\n", + " [5, 6, 7, 8]])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "juzhen = [[i+j for j in range(len(word2) + 1)] for i in range(len(word1) + 1)]\n", + "juzhen = np.mat(juzhen)\n", + "juzhen" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "以 numpy 的样子打印出来,看这样子比较清晰。各行各列对应比较整齐。\n", + "\n", + "我要说明的是:\n", + "\n", + " - 这个 matrix 的 第 1 行(下标为0的行)的 [0, 1, 2, 3] 这个维度的意思,对应的是 dp[i][j] 。也就是说,word1 取前 i 个字符,然后编辑成 word2 时所需要转换的最少步数。因为这里 i = 0,也就是 word1 取 0 个字符,而 j 我们取 0 - 3 个字符的时候,我们从 word1 变换到 word2 的时候所需要经过的最小步数。本质上,就是在 **空的** word1 上进行对应插入 word2 对应的字符就可以变换到 word2 。word2 取几个字符,我们的最小变换次数就是几。也就对应这个维度上的数字。\n", + "\n", + " - 另一个维度上,matrix 的第 1 列(下标为 0 的列),对应的是 [0, 1, 2, 3, 4, 5] 也是对应的 dp[i][j]。只不过我们这里调换了顺序,i 现在不为 0 了,而是 j 为 0 。也就是 word1 取 0~ i 个字符的时候,变换到 word2 的最小步骤数。实际上 word2 是空的,也就是说,我们 word1 有几个字符,我们对应删除几个字符就可以得到 word2 。这就对应着我们的这个列维度上的数字。\n", + " \n", + " - 其他维度,i 和 j 都不为 0 的部分,我们的初始化的数字是没有意义的。我们在迭代过程中会全部都更改一遍。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0139._word_break.ipynb b/docs/Algorithm/Leetcode/ipynb/0139._word_break.ipynb new file mode 100755 index 00000000..ffbac6d1 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0139._word_break.ipynb @@ -0,0 +1,222 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Word Break 单词拆分\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/word-break/description/\n", + " - 英文:https://leetcode.com/problems/word-break/\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。\n", + "\n", + "说明:\n", + "\n", + "1、拆分时可以重复使用字典中的单词。\n", + "2、你可以假设字典中没有重复的单词。\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", + "> 思路 1\n", + "\n", + " - 字符串 S ,它的长度为 N ,如果 S 能够被 字典集合(dict)中的单词拼接而成,那么所要满足的条件为:\n", + " - F(0, N) = F(0, i) && F(i, j) && F(j, N)\n", + " - 这样,如果我们想知道某个子串是否可由 Dict 中的几个单词拼接而成就可以用这样的方式得到结果(满足条件为True,不满足条件为 False)存入到一个 boolean 数组的对应位置上,这样,最后 boolean 数组的最后一位就是 F(0, N) 的值,为 True 表示这个字符串 S 可以由 Dict 中的单词拼接,否则是不行的。\n", + " - AC 代码如下" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class Solution:\n", + " def wordBreak(self, s, wordDict):\n", + " \"\"\"\n", + " :type s: str\n", + " :type wordDict: List[str]\n", + " :rtype: bool\n", + " \"\"\"\n", + " # 参数校验\n", + " if s is None or len(s) < 1 or wordDict is None or len(wordDict) < 1:\n", + " return False\n", + " # 标记是否匹配,match[i] 表示 [0, i-1] 都匹配\n", + " length = len(s)\n", + " match = [False for i in range(length + 1)]\n", + " match[0] = True\n", + " \n", + " for i in range(1, length +1):\n", + " for j in range(i):\n", + " if match[j] and s[j:i] in wordDict:\n", + " match[i] = True\n", + " break\n", + " return match[length]\n", + "\n", + "\n", + "sss = Solution()\n", + "s = \"leetcode\"\n", + "wordDict = [\"leet\", \"code\"]\n", + "print(sss.wordBreak(s, wordDict))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "> 思路 2\n", + "\n", + " - **ok[i] 表示 s[:i] 是不是存在于我们的字典中。**\n", + " - 原理类似于我们上面的 思路 1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "sss = Solution()\n", + "s = \"leetcode\"\n", + "wordDict = [\"leet\", \"code\"]\n", + "print(sss.wordBreak(s, wordDict))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "但是往list里面加数据的方法有快有慢,下面是对比:\n", + "\n", + "```python\n", + ">>> from timeit import timeit\n", + ">>> timeit('x.append(1)', 'x = []', number=10000000)\n", + "1.9880003412529277\n", + ">>> timeit('x += 1,', 'x = []', number=10000000)\n", + "1.2676891852971721\n", + ">>> timeit('x += [1]', 'x = []', number=10000000)\n", + "3.361207239950204\n", + "```\n", + "\n", + "因此我们可以将代码直接换成下面的格式:\n", + "\n", + "```python\n", + "ok += any(ok[j] and s[j:i] in wordDict for j in range(i)) # 会报错\n", + "```\n", + "\n", + "但是这样会报错,TypeError: 'bool' object is not iterable,因此bool类型数据不能这样加,别的可以(list类型本身当然要注意哈)\n", + "\n", + "因此在这个例子中我们这样:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "sss = Solution()\n", + "s = \"leetcode\"\n", + "wordDict = [\"leet\", \"code\"]\n", + "print(sss.wordBreak(s, wordDict))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0179._Largest_Number.ipynb b/docs/Algorithm/Leetcode/ipynb/0179._Largest_Number.ipynb new file mode 100755 index 00000000..9ce76348 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0179._Largest_Number.ipynb @@ -0,0 +1,186 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 179.Largest Number 最大数\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/largest-number/description/\n", + " - 英文:https://leetcode.com/problems/largest-number/\n", + "\n", + "> 内容描述\n", + "\n", + "```\n", + "给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。\n", + "\n", + "示例 1:\n", + "输入: [10,2]\n", + "输出: 210\n", + "\n", + "示例 2:\n", + "输入: [3,30,34,5,9]\n", + "输出: 9534330\n", + "说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 先排序,后合并,若最后为空字符串,则返回 '0'\n", + "\n", + "其中的排序思想是字符串的经典比较:\n", + "\n", + "【注】:在 Python3 中没有了 cmp,只有 key,我们可以使用 functools.cmp_to_key 去修饰一下。\n", + "\n", + "cmp 函数比较两个对象,如 (x, y),若 x > y,则返回 1,if x == y,return 0,如果 x < y,则返回 -1 。\n", + "\n", + "下面这个是 python2 的解决方案,可以 AC ,但是在我们的 Python3 中就会报如下错误" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'cmp' is an invalid keyword argument for this function", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[0ms\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSolution\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[0mnums\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlargestNumber\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnums\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36mlargestNumber\u001b[1;34m(self, nums)\u001b[0m\n\u001b[0;32m 6\u001b[0m \"\"\"\n\u001b[0;32m 7\u001b[0m \u001b[0mnums\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mnum\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mnums\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m \u001b[0mnums\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msort\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcmp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mcmp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 9\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlstrip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'0'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlstrip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'0'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32melse\u001b[0m \u001b[1;34m'0'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mTypeError\u001b[0m: 'cmp' is an invalid keyword argument for this function" + ] + } + ], + "source": [ + "class 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(num).lstrip('0') if ''.join(num).lstrip('0') else '0'\n", + " \n", + "s = Solution()\n", + "nums = [10, 2]\n", + "print(s.largestNumber(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "或者更简单的写法,可以写成下面这样(Python2适用,python3 会报错):" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'cmp' is an invalid keyword argument for this function", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[0ms\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSolution\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[0mnums\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlargestNumber\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnums\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36mlargestNumber\u001b[1;34m(self, nums)\u001b[0m\n\u001b[0;32m 6\u001b[0m \"\"\"\n\u001b[0;32m 7\u001b[0m \u001b[0mnums\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mnum\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mnums\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 8\u001b[1;33m \u001b[0mnums\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msort\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcmp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mcmp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 9\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlstrip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'0'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mor\u001b[0m \u001b[1;34m'0'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mTypeError\u001b[0m: 'cmp' is an invalid keyword argument for this function" + ] + } + ], + "source": [ + "class 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(num).lstrip('0') or '0'\n", + " \n", + "s = Solution()\n", + "nums = [10, 2]\n", + "print(s.largestNumber(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "下面这个解法就是我们在 Python3 中的解法" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "210\n" + ] + } + ], + "source": [ + "from functools import cmp_to_key\n", + "\n", + "# 比较函数\n", + "def compare(a, b):\n", + " return int(b + a) - int(a + b)\n", + "\n", + "class Solution(object):\n", + " def largestNumber(self, nums):\n", + " \"\"\"\n", + " :type nums: List[int]\n", + " :rtype: str\n", + " \"\"\"\n", + " nums = sorted([str(x) for x in nums], key=cmp_to_key(compare))\n", + " return str(int(''.join(nums)))\n", + " \n", + "s = Solution()\n", + "nums = [10, 2]\n", + "print(s.largestNumber(nums))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0242._valid_anagram.ipynb b/docs/Algorithm/Leetcode/ipynb/0242._valid_anagram.ipynb new file mode 100755 index 00000000..26218f62 --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0242._valid_anagram.ipynb @@ -0,0 +1,189 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 242. Valid Anagram 有效的字母异位词\n", + "\n", + "### 难度:Easy\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/valid-anagram/description/\n", + " - 英文:https://leetcode.com/problems/valid-anagram/\n", + " \n", + "> 内容描述\n", + "\n", + "```\n", + "给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。\n", + "\n", + "示例 1:\n", + "输入: s = \"anagram\", t = \"nagaram\"\n", + "输出: true\n", + "\n", + "示例 2:\n", + "输入: s = \"rat\", t = \"car\"\n", + "输出: false\n", + "\n", + "说明:\n", + "你可以假设字符串只包含小写字母。\n", + "\n", + "进阶:\n", + "如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?\n", + "```\n", + "\n", + "## 解题方案\n", + "\n", + "> 思路 1\n", + "\n", + " - 一行瞬秒!\n", + " - 适用 collections.Counter() 方法" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "import collections\n", + "\n", + "class 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", + "s = \"anagram\"\n", + "t = \"nagaram\"\n", + "ss = Solution()\n", + "print(ss.isAnagram(s, t))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "> 思路 2\n", + "\n", + " - 同样是一行瞬秒!\n", + " - 适用 sorted() 函数" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + "s = \"anagram\"\n", + "t = \"nagaram\"\n", + "ss = Solution()\n", + "print(ss.isAnagram(s, t))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3\n", + "\n", + " - 用字数统计,因为只可能是 26 个字母" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "class 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", + " if cnt != 0:\n", + " return False\n", + " return True\n", + " \n", + "s = \"anagram\"\n", + "t = \"nagaram\"\n", + "ss = Solution()\n", + "print(ss.isAnagram(s, t))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/Leetcode/ipynb/0287._Find_the_Duplicate_Number.ipynb b/docs/Algorithm/Leetcode/ipynb/0287._Find_the_Duplicate_Number.ipynb new file mode 100755 index 00000000..62e7895d --- /dev/null +++ b/docs/Algorithm/Leetcode/ipynb/0287._Find_the_Duplicate_Number.ipynb @@ -0,0 +1,244 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 287.Find the Duplicate Number 找到重复的数\n", + "\n", + "### 难度:Medium\n", + "\n", + "## 刷题内容\n", + "\n", + "> 原题链接\n", + "\n", + " - 中文:https://leetcode-cn.com/problems/find-the-duplicate-number/description/\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", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "class 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", + " \n", + "s = Solution()\n", + "nums = [1,2,3,3]\n", + "print(s.findDuplicate(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "思路 1 的解法是时间复杂度为 $O(nlogn)$ 的解法,思路 2 则是时间复杂度为 $O(n)$ ,但是相对来说,是投机取巧了些。\n", + "> 思路 2\n", + "\n", + "一次遍历统计,另一次遍历输出即可。" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "class 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", + "\n", + "s = Solution()\n", + "nums = [1,2,3,3]\n", + "print(s.findDuplicate(nums))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> 思路 3 \n", + "\n", + "思路 3 则是更加完整的 $O(n)$ 的解法,现在我还没有完全搞懂,我先写在下面吧,大佬们可以提前学习了解。" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "class 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", + " \n", + "s = Solution()\n", + "nums = [1,2,3,3]\n", + "print(s.findDuplicate(nums))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/Algorithm/PULL_REQUEST_TEMPLATE.md b/docs/Algorithm/PULL_REQUEST_TEMPLATE.md new file mode 100755 index 00000000..253ab873 --- /dev/null +++ b/docs/Algorithm/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,79 @@ +# 1. Two Sum + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/two-sum + +> 内容描述 + +``` +Given an array of integers, return indices of the two numbers such that they add up to a specific target. + +You may assume that each input would have exactly one solution, and you may not use the same element twice. + +Example: + +Given nums = [2, 7, 11, 15], target = 9, + +Because nums[0] + nums[1] = 2 + 7 = 9, +return [0, 1]. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(1)****** + +暴力解法,两轮遍历 + +beats 27.6% +```python +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + for i in range(len(nums)): + for j in range(i+1, len(nums)): + if nums[i] + nums[j] == target: + return [i, j] + return [] +``` + + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +上面的思路1太慢了,我们可以牺牲空间换取时间 + +``` + 2 7 11 15 + 不存在 存在之中 +lookup {2:0} [0,1] +``` + +* 建立字典 lookup 存放第一个数字,并存放该数字的 index +* 判断 lookup 种是否存在: `target - 当前数字`, 则表面 当前值和 lookup中的值加和为 target. +* 如果存在,则返回: `target - 当前数字` 的 index 和 当前值的 index + +```python +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + look_up = {} + for i, num in enumerate(nums): + if target-num in look_up: + return [look_up[target-num], i] + look_up[num] = i + return [] +``` diff --git a/docs/Algorithm/ProjectCornerstone/3221532952133_.pic_hd.jpg b/docs/Algorithm/ProjectCornerstone/3221532952133_.pic_hd.jpg old mode 100644 new mode 100755 diff --git a/docs/Algorithm/ProjectCornerstone/3231532952152_.pic_hd.jpg b/docs/Algorithm/ProjectCornerstone/3231532952152_.pic_hd.jpg old mode 100644 new mode 100755 diff --git a/docs/Algorithm/ProjectCornerstone/ApproveLetter.md b/docs/Algorithm/ProjectCornerstone/ApproveLetter.md old mode 100644 new mode 100755 diff --git a/docs/Algorithm/README.md b/docs/Algorithm/README.md index d16eb97d..2fb765d0 100644 --- a/docs/Algorithm/README.md +++ b/docs/Algorithm/README.md @@ -4,75 +4,30 @@ * 英文官网: https://leetcode.com * 中文官网: https://leetcode-cn.com -* [ApacheCN 组织资源](https://docs.apachecn.org/): +* [ApacheCN 组织资源](https://www.ibooker.org.cn/docs): * **ApacheCN - 面试求职群【724187166】ApacheCN - 面试求职群[724187166]** -## 关于刷题 - -``` -刷题可能是目前来说:最有用,也是最没用的东西 - -有用只是指:面试最快捷的一种方式 -最没用是指:基本上在工作中用不上 - -简单来说;形式主义为主,技术提升为辅,目的就是为了驯服和奴役思维 - -会刷题和当年会考试没有本质区别 -我并没有觉得这个是一件值得骄傲的事情 -相反,这恰恰是普通人没用选择的事情 - -我吐槽一下: -工作5年,面试还要刷题,写排序,聊一些优化细节和技巧,感觉比较惭愧 -你能写出一个高性能的代码吗?(例如:处理10G,做排序) -你反问:为什么不用GPU和Spark. -他说:。。(他无语) -我觉得大家可能都很无语吧,最无语的应该是前沿的技术吧 - - -很多时候,基本上你遇到问题百度一下答案就出来了 -工作中你可能没遇到,但是面试你必须背下来,不管会不会 - -一个人的好坏,我觉得是在人的性格和搜索能力。 -但是在各大公司的HR和不入流的面试官面前:高学历和强刷题 -技术高低和花的时间有关系,而工作是否录取和高学历和强刷题有关 - -``` - ---- - -当然我们得先战胜市场,才能改变市场! -下面正式开始我们刷题教程入门 -- 你准备好了吗? - -## 数据结构 - 排序 - -* 二分查找 -* 冒泡排序 -* 插入排序 -* 选择排序 -* 快速排序 -* 希尔排序 -* 归并排序 -* 基数排序 - -实战入口: - ## [算法刷题](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/README.md) -1. [Leetcode](/docs/Algorithm/Leetcode) - - [Python](/docs/Algorithm/Leetcode/Python) - - [Java](/docs/Algorithm/Leetcode/Java) - - [JavaScript](/docs/Algorithm/Leetcode/JavaScript) - - [C++](/docs/Algorithm/Leetcode/C++) - - [ipynb](/docs/Algorithm/Leetcode/ipynb) +1. [Leetcode](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode) + - [Python](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/Python) + - [Java](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/Java) + - [JavaScript](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/JavaScript) + - [C++](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/C++) + - [ipynb](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/Leetcode/ipynb) - [GO](https://github.com/aQuaYi/LeetCode-in-Go) - - [Golang](https://github.com/kylesliu/awesome-golang-leetcode) -2. [剑指 Offer](/docs/Algorithm/剑指offer) - - [Python](/docs/Algorithm/剑指offer/Python) - - [Scala](/docs/Algorithm/剑指offer/Scala) - - [Java](/docs/Algorithm/剑指offer/Java) - - [JavaScript](/docs/Algorithm/剑指offer/JavaScript) - - [C++](/docs/Algorithm/剑指offer/C++) -3. [数据结构](/docs/Algorithm/DataStructure) +2. [剑指 Offer](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer) + - [Python](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/Python) + - [Scala](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/Scala) + - [Java](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/Java) + - [JavaScript](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/JavaScript) + - [C++](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/剑指offer/C++) +3. [数据结构](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure) + - [Python](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure/Python) + - [八大排序算法 集合](DataStructure/Python/Sort) + - [Java](https://github.com/apachecn/Interview/tree/master/docs/DataStructure/Java) + - [JavaScript](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure/JavaScript) + - [C++](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/DataStructure/C++) - [Wikipedia: List of Algorithms](https://en.wikipedia.org/wiki/List_of_algorithms) ## 参与方式 @@ -86,8 +41,7 @@ > **案例模版** -[模版 md: 001. Two Sum 两数之和](docs/Algorithm/Leetcode/Python/001._two_sum.md) -[模版页面效果: 001. Two Sum 两数之和](https://interview.apachecn.org/docs/Algorithm/Leetcode/Python/001._two_sum.html) +[模版:001. Two Sum 两数之和](https://github.com/apachecn/Interview/blob/master/docs/Algorithm/Leetcode/Python/001._two_sum.md) ## 推荐 LeetCode 网站 @@ -111,3 +65,74 @@ - [shejie1993](https://shenjie1993.gitbooks.io/leetcode-python/content/096%20Unique%20Binary%20Search%20Trees.html) - [编程之法:面试和算法心得](https://legacy.gitbook.com/book/wizardforcel/the-art-of-programming-by-july/details) - [算法/NLP/深度学习/机器学习面试笔记](https://github.com/imhuay/Interview_Notes-Chinese) + +## 项目负责人 + +格式: GitHub + QQ + +> 第一期 (2016-01-01) + +* [KrisYu的Github](https://github.com/KrisYu/LeetCode-CLRS-Python) +* 授权信息: + +> 第二期 (2018-06-01) + +* [@Lisanaaa](https://github.com/Lisanaaa) -- 由于个人商业化原因,退出 +* [@片刻](https://github.com/jiangzhonglian) +* [@小瑶](https://github.com/chenyyx) +* [cclauss](https://github.com/cclauss) +* [yudaer](https://github.com/yudaer) +* [yuzhoujr](https://github.com/yuzhoujr) +* [wizardforcel](https://github.com/wizardforcel) +* [Stuming](https://github.com/Stuming) +* [GaofanHu](https://github.com/GaofanHu) +* [er3456qi](https://github.com/er3456qi) +* [xshahq](https://github.com/xshahq) +* [xiaqunfeng](https://github.com/xiaqunfeng) +* [CaviarChen](https://github.com/CaviarChen) +* [royIdoodle](https://github.com/royIdoodle) +* [MarsXue](https://github.com/MarsXue) +* [nature1995](https://github.com/nature1995) + +> 第三期 (2019-07-17) + +* [@yudaer](https://github.com/yudaer) +* [@xixici](https://github.com/xixici) +* 空缺量很大,欢迎 + +-- 负责人要求: (欢迎一起为 求职面试 中文版本 做贡献) + +* 热爱开源,喜欢装逼 +* 擅长:刷题、面试、或职场套路 +* 能够有时间及时优化页面bug和用户issues +* 试用期: 2个月 +* 欢迎联系: 片刻 529815144 + +## 免责声明 - 【只供学习参考】 + +* ApacheCN 纯粹出于学习目的与个人兴趣整理 +* ApacheCN 保留对此版本译文的署名权及其它相关权利 + +## **协议** + +* 以各项目协议为准。 +* ApacheCN 账号下没有协议的项目,一律视为 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)。 + +## 赞助我们 + +微信&支付宝 + +--- + +> 特别赞助商(欢迎“私聊”赞助) + + + + + + +
+ + + +
diff --git a/img/Algorithm/LeetCode/065/1.md b/docs/Algorithm/img/005/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/065/1.md rename to docs/Algorithm/img/005/1.md diff --git a/img/Algorithm/LeetCode/005/manacher1.png b/docs/Algorithm/img/005/manacher1.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/005/manacher1.png rename to docs/Algorithm/img/005/manacher1.png diff --git a/img/Algorithm/LeetCode/005/manacher2.png b/docs/Algorithm/img/005/manacher2.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/005/manacher2.png rename to docs/Algorithm/img/005/manacher2.png diff --git a/img/Algorithm/LeetCode/005/manacher3.jpg b/docs/Algorithm/img/005/manacher3.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/005/manacher3.jpg rename to docs/Algorithm/img/005/manacher3.jpg diff --git a/img/Algorithm/LeetCode/218/1.md b/docs/Algorithm/img/011/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/218/1.md rename to docs/Algorithm/img/011/1.md diff --git a/img/Algorithm/LeetCode/011/question_11.jpg b/docs/Algorithm/img/011/question_11.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/011/question_11.jpg rename to docs/Algorithm/img/011/question_11.jpg diff --git a/img/Algorithm/LeetCode/343/1.md b/docs/Algorithm/img/033/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/343/1.md rename to docs/Algorithm/img/033/1.md diff --git a/img/Algorithm/LeetCode/033/rotated-array12_09_2017.jpg b/docs/Algorithm/img/033/rotated-array12_09_2017.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/033/rotated-array12_09_2017.jpg rename to docs/Algorithm/img/033/rotated-array12_09_2017.jpg diff --git a/img/Algorithm/LeetCode/367/1.md b/docs/Algorithm/img/042/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/367/1.md rename to docs/Algorithm/img/042/1.md diff --git a/img/Algorithm/LeetCode/042/rainwatertrap.png b/docs/Algorithm/img/042/rainwatertrap.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/042/rainwatertrap.png rename to docs/Algorithm/img/042/rainwatertrap.png diff --git a/img/Algorithm/LeetCode/371/1.md b/docs/Algorithm/img/065/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/371/1.md rename to docs/Algorithm/img/065/1.md diff --git a/img/Algorithm/LeetCode/065/image.png b/docs/Algorithm/img/065/image.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/065/image.png rename to docs/Algorithm/img/065/image.png diff --git a/img/Algorithm/LeetCode/118/PascalTriangleAnimated2.gif b/docs/Algorithm/img/118/PascalTriangleAnimated2.gif old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/118/PascalTriangleAnimated2.gif rename to docs/Algorithm/img/118/PascalTriangleAnimated2.gif diff --git a/img/Algorithm/LeetCode/463/1.md b/docs/Algorithm/img/218/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/463/1.md rename to docs/Algorithm/img/218/1.md diff --git a/img/Algorithm/LeetCode/218/skyline1.jpg b/docs/Algorithm/img/218/skyline1.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/218/skyline1.jpg rename to docs/Algorithm/img/218/skyline1.jpg diff --git a/img/Algorithm/LeetCode/218/skyline2.jpg b/docs/Algorithm/img/218/skyline2.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/218/skyline2.jpg rename to docs/Algorithm/img/218/skyline2.jpg diff --git a/img/Algorithm/LeetCode/470/1.md b/docs/Algorithm/img/343/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/470/1.md rename to docs/Algorithm/img/343/1.md diff --git a/img/Algorithm/LeetCode/343/WechatIMG509.jpeg b/docs/Algorithm/img/343/WechatIMG509.jpeg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/343/WechatIMG509.jpeg rename to docs/Algorithm/img/343/WechatIMG509.jpeg diff --git a/img/Algorithm/LeetCode/815/1.md b/docs/Algorithm/img/367/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/815/1.md rename to docs/Algorithm/img/367/1.md diff --git a/img/Algorithm/LeetCode/367/WechatIMG505.jpeg b/docs/Algorithm/img/367/WechatIMG505.jpeg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/367/WechatIMG505.jpeg rename to docs/Algorithm/img/367/WechatIMG505.jpeg diff --git a/img/Algorithm/LeetCode/84/1.md b/docs/Algorithm/img/371/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/84/1.md rename to docs/Algorithm/img/371/1.md diff --git a/img/Algorithm/LeetCode/371/18C549E8937CF66D42060DCB802661C8.jpg b/docs/Algorithm/img/371/18C549E8937CF66D42060DCB802661C8.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/371/18C549E8937CF66D42060DCB802661C8.jpg rename to docs/Algorithm/img/371/18C549E8937CF66D42060DCB802661C8.jpg diff --git a/img/Algorithm/LeetCode/371/A4CF94C4A380101180708CF0CF35265B.jpg b/docs/Algorithm/img/371/A4CF94C4A380101180708CF0CF35265B.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/371/A4CF94C4A380101180708CF0CF35265B.jpg rename to docs/Algorithm/img/371/A4CF94C4A380101180708CF0CF35265B.jpg diff --git a/img/Algorithm/LeetCode/935/1.md b/docs/Algorithm/img/463/1.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/935/1.md rename to docs/Algorithm/img/463/1.md diff --git a/img/Algorithm/LeetCode/463/island.png b/docs/Algorithm/img/463/island.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/463/island.png rename to docs/Algorithm/img/463/island.png diff --git a/docs/Algorithm/img/470/1.md b/docs/Algorithm/img/470/1.md new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/docs/Algorithm/img/470/1.md @@ -0,0 +1 @@ + diff --git a/img/Algorithm/LeetCode/470/image.png b/docs/Algorithm/img/470/image.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/470/image.png rename to docs/Algorithm/img/470/image.png diff --git a/docs/Algorithm/img/815/1.md b/docs/Algorithm/img/815/1.md new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/docs/Algorithm/img/815/1.md @@ -0,0 +1 @@ + diff --git a/img/Algorithm/LeetCode/815/WechatIMG6057.png b/docs/Algorithm/img/815/WechatIMG6057.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/815/WechatIMG6057.png rename to docs/Algorithm/img/815/WechatIMG6057.png diff --git a/docs/Algorithm/img/84/1.md b/docs/Algorithm/img/84/1.md new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/docs/Algorithm/img/84/1.md @@ -0,0 +1 @@ + diff --git a/img/Algorithm/LeetCode/84/histogram1.png b/docs/Algorithm/img/84/histogram1.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/84/histogram1.png rename to docs/Algorithm/img/84/histogram1.png diff --git a/img/Algorithm/LeetCode/84/histogram_area1.png b/docs/Algorithm/img/84/histogram_area1.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/84/histogram_area1.png rename to docs/Algorithm/img/84/histogram_area1.png diff --git a/docs/Algorithm/img/935/1.md b/docs/Algorithm/img/935/1.md new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/docs/Algorithm/img/935/1.md @@ -0,0 +1 @@ + diff --git a/img/Algorithm/LeetCode/935/keypad.png b/docs/Algorithm/img/935/keypad.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/935/keypad.png rename to docs/Algorithm/img/935/keypad.png diff --git a/img/Algorithm/LeetCode/935/knight.png b/docs/Algorithm/img/935/knight.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/935/knight.png rename to docs/Algorithm/img/935/knight.png diff --git a/img/Algorithm/LeetCode/N-Queens.png b/docs/Algorithm/img/N-Queens.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/N-Queens.png rename to docs/Algorithm/img/N-Queens.png diff --git a/img/Algorithm/LeetCode/README.md b/docs/Algorithm/img/README.md old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/README.md rename to docs/Algorithm/img/README.md diff --git a/img/Algorithm/DataStructure/BubbleSort_1.gif b/docs/Algorithm/img/SortingAlgorithm/BubbleSort_1.gif old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/BubbleSort_1.gif rename to docs/Algorithm/img/SortingAlgorithm/BubbleSort_1.gif diff --git a/img/Algorithm/DataStructure/InsertSort_1.gif b/docs/Algorithm/img/SortingAlgorithm/InsertSort_1.gif old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/InsertSort_1.gif rename to docs/Algorithm/img/SortingAlgorithm/InsertSort_1.gif diff --git a/img/Algorithm/DataStructure/MergeSort_1.gif b/docs/Algorithm/img/SortingAlgorithm/MergeSort_1.gif old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/MergeSort_1.gif rename to docs/Algorithm/img/SortingAlgorithm/MergeSort_1.gif diff --git a/img/Algorithm/DataStructure/QuickSort_1.gif b/docs/Algorithm/img/SortingAlgorithm/QuickSort_1.gif old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/QuickSort_1.gif rename to docs/Algorithm/img/SortingAlgorithm/QuickSort_1.gif diff --git a/img/Algorithm/DataStructure/RadixSort_1.gif b/docs/Algorithm/img/SortingAlgorithm/RadixSort_1.gif old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/RadixSort_1.gif rename to docs/Algorithm/img/SortingAlgorithm/RadixSort_1.gif diff --git a/img/Algorithm/DataStructure/RadixSort_2.png b/docs/Algorithm/img/SortingAlgorithm/RadixSort_2.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/RadixSort_2.png rename to docs/Algorithm/img/SortingAlgorithm/RadixSort_2.png diff --git a/img/Algorithm/DataStructure/SelectionSort_1.gif b/docs/Algorithm/img/SortingAlgorithm/SelectionSort_1.gif old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/SelectionSort_1.gif rename to docs/Algorithm/img/SortingAlgorithm/SelectionSort_1.gif diff --git a/img/Algorithm/DataStructure/ShellSort_1.gif b/docs/Algorithm/img/SortingAlgorithm/ShellSort_1.gif old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/ShellSort_1.gif rename to docs/Algorithm/img/SortingAlgorithm/ShellSort_1.gif diff --git a/img/Algorithm/DataStructure/ShellSort_2.png b/docs/Algorithm/img/SortingAlgorithm/ShellSort_2.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/ShellSort_2.png rename to docs/Algorithm/img/SortingAlgorithm/ShellSort_2.png diff --git a/img/Algorithm/DataStructure/ShellSort_3.png b/docs/Algorithm/img/SortingAlgorithm/ShellSort_3.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/ShellSort_3.png rename to docs/Algorithm/img/SortingAlgorithm/ShellSort_3.png diff --git a/img/Algorithm/DataStructure/ShellSort_4.png b/docs/Algorithm/img/SortingAlgorithm/ShellSort_4.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/DataStructure/ShellSort_4.png rename to docs/Algorithm/img/SortingAlgorithm/ShellSort_4.png diff --git "a/img/Algorithm/DataStructure/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\247\350\203\275.png" "b/docs/Algorithm/img/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\247\350\203\275.png" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\247\350\203\275.png" rename to "docs/Algorithm/img/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\247\350\203\275.png" diff --git "a/img/Algorithm/DataStructure/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.png" "b/docs/Algorithm/img/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.png" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.png" rename to "docs/Algorithm/img/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.png" diff --git "a/img/Algorithm/DataStructure/\345\206\222\346\263\241\346\216\222\345\272\217.gif" "b/docs/Algorithm/img/SortingAlgorithm/\345\206\222\346\263\241\346\216\222\345\272\217.gif" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\345\206\222\346\263\241\346\216\222\345\272\217.gif" rename to "docs/Algorithm/img/SortingAlgorithm/\345\206\222\346\263\241\346\216\222\345\272\217.gif" diff --git "a/img/Algorithm/DataStructure/\345\237\272\346\225\260\346\216\222\345\272\217.gif" "b/docs/Algorithm/img/SortingAlgorithm/\345\237\272\346\225\260\346\216\222\345\272\217.gif" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\345\237\272\346\225\260\346\216\222\345\272\217.gif" rename to "docs/Algorithm/img/SortingAlgorithm/\345\237\272\346\225\260\346\216\222\345\272\217.gif" diff --git "a/img/Algorithm/DataStructure/\345\270\214\345\260\224\346\216\222\345\272\217.png" "b/docs/Algorithm/img/SortingAlgorithm/\345\270\214\345\260\224\346\216\222\345\272\217.png" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\345\270\214\345\260\224\346\216\222\345\272\217.png" rename to "docs/Algorithm/img/SortingAlgorithm/\345\270\214\345\260\224\346\216\222\345\272\217.png" diff --git "a/img/Algorithm/DataStructure/\345\275\222\345\271\266\346\216\222\345\272\217.gif" "b/docs/Algorithm/img/SortingAlgorithm/\345\275\222\345\271\266\346\216\222\345\272\217.gif" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\345\275\222\345\271\266\346\216\222\345\272\217.gif" rename to "docs/Algorithm/img/SortingAlgorithm/\345\275\222\345\271\266\346\216\222\345\272\217.gif" diff --git "a/img/Algorithm/DataStructure/\345\277\253\351\200\237\346\216\222\345\272\217.gif" "b/docs/Algorithm/img/SortingAlgorithm/\345\277\253\351\200\237\346\216\222\345\272\217.gif" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\345\277\253\351\200\237\346\216\222\345\272\217.gif" rename to "docs/Algorithm/img/SortingAlgorithm/\345\277\253\351\200\237\346\216\222\345\272\217.gif" diff --git "a/img/Algorithm/DataStructure/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" "b/docs/Algorithm/img/SortingAlgorithm/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" rename to "docs/Algorithm/img/SortingAlgorithm/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" diff --git "a/img/Algorithm/DataStructure/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" "b/docs/Algorithm/img/SortingAlgorithm/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" rename to "docs/Algorithm/img/SortingAlgorithm/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" diff --git "a/img/Algorithm/DataStructure/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" "b/docs/Algorithm/img/SortingAlgorithm/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" rename to "docs/Algorithm/img/SortingAlgorithm/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" diff --git "a/img/Algorithm/DataStructure/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" "b/docs/Algorithm/img/SortingAlgorithm/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/DataStructure/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" rename to "docs/Algorithm/img/SortingAlgorithm/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" diff --git a/img/Algorithm/LeetCode/logo.png b/docs/Algorithm/img/logo.png similarity index 100% rename from img/Algorithm/LeetCode/logo.png rename to docs/Algorithm/img/logo.png diff --git a/img/Algorithm/LeetCode/logo/71EC577ABCDF4D4AE8082BED5D204919.jpg b/docs/Algorithm/img/logo/71EC577ABCDF4D4AE8082BED5D204919.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/logo/71EC577ABCDF4D4AE8082BED5D204919.jpg rename to docs/Algorithm/img/logo/71EC577ABCDF4D4AE8082BED5D204919.jpg diff --git a/img/Algorithm/LeetCode/sketch1.png b/docs/Algorithm/img/sketch1.png old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/sketch1.png rename to docs/Algorithm/img/sketch1.png diff --git a/img/Algorithm/LeetCode/union_find8D76B4AFCB73CED67BE37B92B385A55C.jpg b/docs/Algorithm/img/union_find8D76B4AFCB73CED67BE37B92B385A55C.jpg old mode 100644 new mode 100755 similarity index 100% rename from img/Algorithm/LeetCode/union_find8D76B4AFCB73CED67BE37B92B385A55C.jpg rename to docs/Algorithm/img/union_find8D76B4AFCB73CED67BE37B92B385A55C.jpg diff --git "a/img/Algorithm/LeetCode/\347\272\277\347\250\213\350\275\254\346\215\242.jpg" "b/docs/Algorithm/img/\347\272\277\347\250\213\350\275\254\346\215\242.jpg" old mode 100644 new mode 100755 similarity index 100% rename from "img/Algorithm/LeetCode/\347\272\277\347\250\213\350\275\254\346\215\242.jpg" rename to "docs/Algorithm/img/\347\272\277\347\250\213\350\275\254\346\215\242.jpg" diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/C++/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/C++/README.md" new file mode 100755 index 00000000..d02bbf3a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/C++/README.md" @@ -0,0 +1,2 @@ +# Jianzhi-offer + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_01_DuplicationInArray/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_01_DuplicationInArray/README.md" new file mode 100755 index 00000000..e8094f1d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_01_DuplicationInArray/README.md" @@ -0,0 +1,72 @@ +## 找出数组中重复的数字 + +### 题目描述 +在一个长度为 `n` 的数组里的所有数字都在 `0` 到 `n-1` 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 `7` 的数组 `{2, 3, 1, 0, 2, 5, 3}`,那么对应的输出是重复的数字 `2` 或者 `3`。 + + +### 解法 +#### 解法一 +排序后,顺序扫描,判断是否有重复,时间复杂度为 `O(n²)`。 + +#### 解法二 +利用哈希表,遍历数组,如果哈希表中没有该元素,则存入哈希表中,否则返回重复的元素。时间复杂度为 `O(n)`,空间复杂度为 `O(n)`。 + +#### 解法三 +长度为 `n`,元素的数值范围也为 `n`,如果没有重复元素,那么数组每个下标对应的值与下标相等。 + +从头到尾遍历数组,当扫描到下标 `i` 的数字 `nums[i]`: +- 如果等于 `i`,继续向下扫描; +- 如果不等于 `i`,拿它与第 `nums[i]` 个数进行比较,如果相等,说明有重复值,返回 `nums[i]`。如果不相等,就把第 `i` 个数 和第 `nums[i]` 个数交换。重复这个比较交换的过程。 + +此算法时间复杂度为 `O(n)`,因为每个元素最多只要两次交换,就能确定位置。空间复杂度为 `O(1)`。 + +```java + +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 查找数组中的重复元素 + * @param numbers 数组 + * @param length 数组长度 + * @param duplication duplication[0]存储重复元素 + * @return boolean + */ + public boolean duplicate(int[] numbers, int length, int[] duplication) { + if (numbers == null || length < 1) { + return false; + } + for (int e : numbers) { + if (e >= length) { + return false; + } + } + + for (int i = 0; i < length; ++i) { + while (numbers[i] != i) { + if (numbers[i] == numbers[numbers[i]]) { + duplication[0] = numbers[i]; + return true; + } + swap(numbers, i, numbers[i]); + } + } + + return false; + } + + private void swap(int[] numbers, int i, int j) { + int t = numbers[i]; + numbers[i] = numbers[j]; + numbers[j] = t; + } +} +``` + +### 测试用例 +1. 长度为 n 的数组中包含一个或多个重复的数字; +2. 数组中不包含重复的数字; +3. 无效测试输入用例(输入空指针;长度为 n 的数组中包含 0~n-1 之外的数字)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_01_DuplicationInArray/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_01_DuplicationInArray/Solution.java" new file mode 100755 index 00000000..c6aefd33 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_01_DuplicationInArray/Solution.java" @@ -0,0 +1,43 @@ + +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 查找数组中的重复元素 + * @param numbers 数组 + * @param length 数组长度 + * @param duplication duplication[0]存储重复元素 + * @return boolean + */ + public boolean duplicate(int[] numbers, int length, int[] duplication) { + if (numbers == null || length < 1) { + return false; + } + for (int e : numbers) { + if (e >= length) { + return false; + } + } + + for (int i = 0; i < length; ++i) { + while (numbers[i] != i) { + if (numbers[i] == numbers[numbers[i]]) { + duplication[0] = numbers[i]; + return true; + } + swap(numbers, i, numbers[i]); + } + } + + return false; + } + + private void swap(int[] numbers, int i, int j) { + int t = numbers[i]; + numbers[i] = numbers[j]; + numbers[j] = t; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_02_DuplicationInArrayNoEdit/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_02_DuplicationInArrayNoEdit/README.md" new file mode 100755 index 00000000..5fdac9cd --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_02_DuplicationInArrayNoEdit/README.md" @@ -0,0 +1,86 @@ +## 不修改数组找出重复的数字 + +### 题目描述 +在一个长度为 `n+1` 的数组里的所有数字都在 `1` 到 `n` 的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为 `8` 的数组 `{2, 3, 5, 4, 3, 2, 6, 7}`,那么对应的输出是重复的数字 `2` 或者 `3`。 + + +### 解法 +#### 解法一 +创建长度为 `n+1` 的辅助数组,把原数组的元素复制到辅助数组中。如果原数组被复制的数是 `m`,则放到辅助数组第 `m` 个位置。这样很容易找出重复元素。空间复杂度为 `O(n)`。 + +#### 解法二 +数组元素的取值范围是 `[1, n]`,对该范围对半划分,分成 `[1, middle]`, `[middle+1, n]`。计算数组中有多少个(count)元素落在 `[1, middle]` 区间内,如果 count 大于 middle-1+1,那么说明这个范围内有重复元素,否则在另一个范围内。继续对这个范围对半划分,继续统计区间内元素数量。 + +时间复杂度 `O(n * log n)`,空间复杂度 `O(1)`。 + +注意,此方法无法找出所有重复的元素。 + +```java +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 不修改数组查找重复的元素,没有则返回-1 + * @param numbers 数组 + * @return 重复的元素 + */ + public int getDuplication(int[] numbers) { + if (numbers == null || numbers.length < 1) { + return -1; + } + + int start = 1; + int end = numbers.length - 1; + while (end >= start) { + int middle = start + ((end - start) >> 1); + + // 调用 log n 次 + int count = countRange(numbers, start, middle); + if (start == end) { + if (count > 1) { + return start; + } + break; + } else { + // 无法找出所有重复的数 + if (count > (middle - start) + 1) { + end = middle; + } else { + start = middle + 1; + } + } + } + return -1; + } + + + /** + * 计算整个数组中有多少个数的取值在[start, end] 之间 + * 时间复杂度 O(n) + * @param numbers 数组 + * @param start 左边界 + * @param end 右边界 + * @return 数量 + */ + private int countRange(int[] numbers, int start, int end) { + if (numbers == null) { + return 0; + } + int count = 0; + for(int e : numbers) { + if (e >= start && e <= end) { + ++count; + } + } + return count; + } +} +``` + +### 测试用例 +1. 长度为 n 的数组中包含一个或多个重复的数字; +2. 数组中不包含重复的数字; +3. 无效测试输入用例(输入空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_02_DuplicationInArrayNoEdit/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_02_DuplicationInArrayNoEdit/Solution.java" new file mode 100755 index 00000000..bc479796 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/03_02_DuplicationInArrayNoEdit/Solution.java" @@ -0,0 +1,62 @@ +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 不修改数组查找重复的元素,没有则返回-1 + * @param numbers 数组 + * @return 重复的元素 + */ + public int getDuplication(int[] numbers) { + if (numbers == null || numbers.length < 1) { + return -1; + } + + int start = 1; + int end = numbers.length - 1; + while (end >= start) { + int middle = start + ((end - start) >> 1); + + // 调用 log n 次 + int count = countRange(numbers, start, middle); + if (start == end) { + if (count > 1) { + return start; + } + break; + } else { + // 无法找出所有重复的数 + if (count > (middle - start) + 1) { + end = middle; + } else { + start = middle + 1; + } + } + } + return -1; + } + + + /** + * 计算整个数组中有多少个数的取值在[start, end] 之间 + * 时间复杂度 O(n) + * @param numbers 数组 + * @param start 左边界 + * @param end 右边界 + * @return 数量 + */ + private int countRange(int[] numbers, int start, int end) { + if (numbers == null) { + return 0; + } + int count = 0; + for(int e : numbers) { + if (e >= start && e <= end) { + ++count; + } + } + return count; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/04_FindInPartiallySortedMatrix/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/04_FindInPartiallySortedMatrix/README.md" new file mode 100755 index 00000000..70ab58be --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/04_FindInPartiallySortedMatrix/README.md" @@ -0,0 +1,57 @@ +## 二维数组中的查找 + +### 题目描述 +在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 + + +### 解法 +从二维数组的右上方开始查找: +- 若元素值等于 `target`,返回 `true`; +- 若元素值大于 `target`,砍掉这一列,即 `--j`; +- 若元素值小于 `target`,砍掉这一行,即 `++i`。 + +也可以从二维数组的左下方开始查找,以下代码使用左下方作为查找的起点。 + +注意,不能选择左上方或者右下方的数字,因为这样无法缩小查找的范围。 + +```java +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 二维数组中的查找 + * @param target 目标值 + * @param array 二维数组 + * @return boolean + */ + public boolean find(int target, int[][] array) { + if (array == null) { + return false; + } + int rows = array.length; + int columns = array[0].length; + + int i = rows - 1; + int j = 0; + while (i >= 0 && j < columns) { + if (array[i][j] == target) { + return true; + } + if (array[i][j] < target) { + ++j; + } else { + --i; + } + } + return false; + } +} +``` + +### 测试用例 +1. 二维数组中包含查找的数字(查找的数字是数组中的最大值和最小值;查找的数字介于数组中的最大值和最小值之间); +2. 二维数组中没有查找的数字(查找的数字大于/小于数组中的最大值;查找的数字在数组的最大值和最小值之间但数组中没有这个数字); +3. 特殊输入测试(输入空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/04_FindInPartiallySortedMatrix/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/04_FindInPartiallySortedMatrix/Solution.java" new file mode 100755 index 00000000..27df4521 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/04_FindInPartiallySortedMatrix/Solution.java" @@ -0,0 +1,34 @@ +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 二维数组中的查找 + * @param target 目标值 + * @param array 二维数组 + * @return boolean + */ + public boolean find(int target, int[][] array) { + if (array == null) { + return false; + } + int rows = array.length; + int columns = array[0].length; + + int i = rows - 1; + int j = 0; + while (i >= 0 && j < columns) { + if (array[i][j] == target) { + return true; + } + if (array[i][j] < target) { + ++j; + } else { + --i; + } + } + return false; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/05_ReplaceSpaces/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/05_ReplaceSpaces/README.md" new file mode 100755 index 00000000..eb3e00d3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/05_ReplaceSpaces/README.md" @@ -0,0 +1,98 @@ +## 替换空格 + +### 题目描述 +请实现一个函数,将一个字符串中的每个空格替换成 `%20`。例如,当字符串为 `We Are Happy`,则经过替换之后的字符串为 `We%20Are%20Happy`。 + + +### 解法 +#### 解法一 +创建 `StringBuilder`,遍历原字符串,遇到非空格,直接 append 到 `StringBuilder` 中,遇到空格则将 `%20` append 到 `StringBuilder` 中。 +```java +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 将字符串中的所有空格替换为%20 + * @param str 字符串 + * @return 替换后的字符串 + */ + public String replaceSpace(StringBuffer str) { + if (str == null || str.length() == 0) { + return str.toString(); + } + StringBuilder sb = new StringBuilder(); + int len = str.length(); + for (int i = 0; i < len; ++i) { + char ch = str.charAt(i); + sb.append(ch == ' ' ? "%20" : ch); + } + + return sb.toString(); + } +} +``` + +#### 解法二【推荐】 +先遍历原字符串,遇到空格,则在原字符串末尾 `append` 任意两个字符,如两个空格。 + +用指针 `p` 指向原字符串末尾,`q` 指向现字符串末尾,`p`, `q` 从后往前遍历,当 `p` 遇到空格,`q` 位置依次要 `append` '02%',若不是空格,直接 `append` `p` 指向的字符。 + +> 🤔思路扩展: +在合并两个数组(包括字符串)时,如果从前往后复制每个数字(或字符)需要重复移动数字(或字符)多次,那么我们可以考虑从后往前复制,这样就能减少移动的次数,从而提高效率。 + +```java +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 将字符串中的所有空格替换为%20 + * @param str 字符串 + * @return 替换后的字符串 + */ + public String replaceSpace(StringBuffer str) { + if (str == null || str.length() == 0) { + return str.toString(); + } + + int len = str.length(); + for (int i = 0; i < len; ++i) { + if (str.charAt(i) == ' ') { + // append 两个空格 + str.append(" "); + } + } + + // p 指向原字符串末尾 + int p = len - 1; + + // q 指向现字符串末尾 + int q = str.length() - 1; + + while (p >= 0) { + char ch = str.charAt(p--); + if (ch == ' ') { + str.setCharAt(q--, '0'); + str.setCharAt(q--, '2'); + str.setCharAt(q--, '%'); + } else { + str.setCharAt(q--, ch); + } + } + + return str.toString(); + + } +} +``` + + +### 测试用例 +1. 输入的字符串包含空格(空格位于字符串的最前面/最后面/中间;字符串有多个连续的空格); +2. 输入的字符串中没有空格; +3. 特殊输入测试(字符串是一个空指针;字符串是一个空字符串;字符串只有一个空格字符;字符串中有多个连续空格)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/05_ReplaceSpaces/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/05_ReplaceSpaces/Solution.java" new file mode 100755 index 00000000..f71a416d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/05_ReplaceSpaces/Solution.java" @@ -0,0 +1,45 @@ +/** + * @author bingo + * @since 2018/10/27 + */ + +public class Solution { + /** + * 将字符串中的所有空格替换为%20 + * @param str 字符串 + * @return 替换后的字符串 + */ + public String replaceSpace(StringBuffer str) { + if (str == null || str.length() == 0) { + return str.toString(); + } + + int len = str.length(); + for (int i = 0; i < len; ++i) { + if (str.charAt(i) == ' ') { + // append 两个空格 + str.append(" "); + } + } + + // p 指向原字符串末尾 + int p = len - 1; + + // q 指向现字符串末尾 + int q = str.length() - 1; + + while (p >= 0) { + char ch = str.charAt(p--); + if (ch == ' ') { + str.setCharAt(q--, '0'); + str.setCharAt(q--, '2'); + str.setCharAt(q--, '%'); + } else { + str.setCharAt(q--, ch); + } + } + + return str.toString(); + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/06_PrintListInReversedOrder/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/06_PrintListInReversedOrder/README.md" new file mode 100755 index 00000000..60e99a53 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/06_PrintListInReversedOrder/README.md" @@ -0,0 +1,110 @@ +## 从尾到头打印链表 + +### 题目描述 +输入一个链表,按链表值从尾到头的顺序返回一个 `ArrayList`。 + + +### 解法 +#### 解法一【推荐】 +遍历链表,每个链表结点值 `push` 进栈,最后将栈中元素依次 `pop` 到 `list` 中。 +```java +/** +* public class ListNode { +* int val; +* ListNode next = null; +* +* ListNode(int val) { +* this.val = val; +* } +* } +* +*/ +import java.util.ArrayList; +import java.util.Stack; + +/** + * @author bingo + * @since 2018/10/28 + */ +public class Solution { + /** + * 从尾到头打印链表 + * @param listNode 链表头节点 + * @return list + */ + public ArrayList printListFromTailToHead(ListNode listNode) { + ArrayList res = new ArrayList<>(); + if (listNode == null) { + return res; + } + Stack stack = new Stack<>(); + while (listNode != null) { + stack.push(listNode.val); + listNode = listNode.next; + } + while (!stack.isEmpty()) { + res.add(stack.pop()); + } + + return res; + } +} +``` + +#### 解法二【不推荐】 +利用递归方式: +- 若不是链表尾结点,继续递归; +- 若是,添加到 `list` 中。 + +这种方式不推荐,当递归层数过多时,容易发生 `Stack Overflow`。 + +```java +/** +* public class ListNode { +* int val; +* ListNode next = null; +* +* ListNode(int val) { +* this.val = val; +* } +* } +* +*/ +import java.util.ArrayList; +import java.util.Stack; + +/** + * @author bingo + * @since 2018/10/28 + */ +public class Solution { + /** + * 从尾到头打印链表 + * @param listNode 链表头结点 + * @return list + */ + public ArrayList printListFromTailToHead(ListNode listNode) { + ArrayList res = new ArrayList<>(); + if (listNode == null) { + return res; + } + + addElement(listNode, res); + return res; + + } + + private void addElement(ListNode listNode, ArrayList res) { + if (listNode.next != null) { + // 递归调用 + addElement(listNode.next, res); + } + res.add(listNode.val); + } +} +``` + + +### 测试用例 +1. 功能测试(输入的链表有多个结点;输入的链表只有一个结点); +2. 特殊输入测试(输入的链表结点指针为空)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/06_PrintListInReversedOrder/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/06_PrintListInReversedOrder/Solution.java" new file mode 100755 index 00000000..018e9ec2 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/06_PrintListInReversedOrder/Solution.java" @@ -0,0 +1,42 @@ + +/** +* public class ListNode { +* int val; +* ListNode next = null; +* +* ListNode(int val) { +* this.val = val; +* } +* } +* +*/ +import java.util.ArrayList; +import java.util.Stack; + +/** + * @author bingo + * @since 2018/10/28 + */ +public class Solution { + /** + * 从尾到头打印链表 + * @param listNode 链表头节点 + * @return list + */ + public ArrayList printListFromTailToHead(ListNode listNode) { + ArrayList res = new ArrayList<>(); + if (listNode == null) { + return res; + } + Stack stack = new Stack<>(); + while (listNode != null) { + stack.push(listNode.val); + listNode = listNode.next; + } + while (!stack.isEmpty()) { + res.add(stack.pop()); + } + + return res; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/07_ConstructBinaryTree/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/07_ConstructBinaryTree/README.md" new file mode 100755 index 00000000..f8c824a2 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/07_ConstructBinaryTree/README.md" @@ -0,0 +1,82 @@ +## 重建二叉树 + +### 题目描述 +输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 `{1,2,4,7,3,5,6,8}` 和中序遍历序列 `{4,7,2,1,5,3,8,6}`,则重建二叉树并返回。 + + +### 解法 +在二叉树的前序遍历序列中,第一个数字总是根结点的值。在中序遍历序列中,根结点的值在序列的中间,左子树的结点位于根结点左侧,而右子树的结点位于根结点值的右侧。 + +遍历中序序列,找到根结点,递归构建左子树与右子树。 + +注意添加特殊情况的 `if` 判断。 + +```java +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + +/** + * @author bingo + * @since 2018/10/28 + */ + +public class Solution { + /** + * 重建二叉树 + * + * @param pre 先序序列 + * @param in 中序序列 + * @return 二叉树根结点 + */ + public TreeNode reConstructBinaryTree(int[] pre, int[] in) { + if (pre == null || in == null || pre.length != in.length) { + return null; + } + int n = pre.length; + return constructBinaryTree(pre, 0, n - 1, in, 0, n - 1); + } + + private TreeNode constructBinaryTree(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) { + TreeNode node = new TreeNode(pre[startPre]); + if (startPre == endPre) { + if (startIn == endIn) { + return node; + } + throw new IllegalArgumentException("Invalid input!"); + } + + int inOrder = startIn; + while (in[inOrder] != pre[startPre]) { + ++inOrder; + if (inOrder > endIn) { + new IllegalArgumentException("Invalid input!"); + } + } + int len = inOrder - startIn; + if (len > 0) { + // 递归构建左子树 + node.left = constructBinaryTree(pre, startPre + 1, startPre + len, in, startIn, inOrder - 1); + } + + if (inOrder < endIn) { + // 递归构建右子树 + node.right = constructBinaryTree(pre, startPre + len + 1, endPre, in, inOrder + 1, endIn); + } + return node; + + } +} +``` + + +### 测试用例 +1. 普通二叉树(完全二叉树;不完全二叉树); +2. 特殊二叉树(所有结点都没有左/右子结点;只有一个结点的二叉树); +3. 特殊输入测试(二叉树根结点为空;输入的前序序列和中序序列不匹配)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/07_ConstructBinaryTree/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/07_ConstructBinaryTree/Solution.java" new file mode 100755 index 00000000..897c51ac --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/07_ConstructBinaryTree/Solution.java" @@ -0,0 +1,61 @@ +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + +/** + * @author bingo + * @since 2018/10/28 + */ + +public class Solution { + /** + * 重建二叉树 + * + * @param pre 先序序列 + * @param in 中序序列 + * @return 二叉树根结点 + */ + public TreeNode reConstructBinaryTree(int[] pre, int[] in) { + if (pre == null || in == null || pre.length != in.length) { + return null; + } + int n = pre.length; + return constructBinaryTree(pre, 0, n - 1, in, 0, n - 1); + } + + private TreeNode constructBinaryTree(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) { + TreeNode node = new TreeNode(pre[startPre]); + if (startPre == endPre) { + if (startIn == endIn) { + return node; + } + throw new IllegalArgumentException("Invalid input!"); + } + + int inOrder = startIn; + while (in[inOrder] != pre[startPre]) { + ++inOrder; + if (inOrder > endIn) { + new IllegalArgumentException("Invalid input!"); + } + } + int len = inOrder - startIn; + if (len > 0) { + // 递归构建左子树 + node.left = constructBinaryTree(pre, startPre + 1, startPre + len, in, startIn, inOrder - 1); + } + + if (inOrder < endIn) { + // 递归构建右子树 + node.right = constructBinaryTree(pre, startPre + len + 1, endPre, in, inOrder + 1, endIn); + } + return node; + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/08_NextNodeInBinaryTrees/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/08_NextNodeInBinaryTrees/README.md" new file mode 100755 index 00000000..e16037ce --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/08_NextNodeInBinaryTrees/README.md" @@ -0,0 +1,74 @@ +## 二叉树的下一个结点 + +### 题目描述 +给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 + + +### 解法 +对于结点 `pNode`: +- 如果它有右子树,则**右子树的最左结点**就是它的下一个结点; +- 如果它没有右子树,判断它与父结点 `pNode.next` 的位置情况: + - 如果它是父结点的左孩子,那么父结点 `pNode.next` 就是它的下一个结点; + - 如果它是父结点的右孩子,一直向上寻找,直到找到某个结点,它是它父结点的左孩子,那么该父结点就是 `pNode` 的下一个结点。 + +```java +/* +public class TreeLinkNode { + int val; + TreeLinkNode left = null; + TreeLinkNode right = null; + TreeLinkNode next = null; + + TreeLinkNode(int val) { + this.val = val; + } +} +*/ + +/** + * @author bingo + * @since 2018/10/28 + */ + +public class Solution { + /** + * 获取中序遍历结点的下一个结点 + * @param pNode 某个结点 + * @return pNode的下一个结点 + */ + public TreeLinkNode GetNext(TreeLinkNode pNode) { + if (pNode == null) { + return null; + } + + if (pNode.right != null) { + TreeLinkNode t = pNode.right; + while (t.left != null) { + t = t.left; + } + return t; + } + + // 须保证 pNode.next 不为空,否则会出现 NPE + if (pNode.next != null && pNode.next.left == pNode) { + return pNode.next; + } + + while (pNode.next != null) { + if (pNode.next.left == pNode) { + return pNode.next; + } + pNode = pNode.next; + } + + return null; + + } +} +``` + + +### 测试用例 +1. 普通二叉树(完全二叉树;不完全二叉树); +2. 特殊二叉树(所有结点都没有左/右子结点;只有一个结点的二叉树;二叉树的根结点为空); +3. 不同位置的结点的下一个结点(下一个结点为当前结点的右子结点、右子树的最左子结点、父结点、跨层的父结点等;当前结点没有下一个结点)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/08_NextNodeInBinaryTrees/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/08_NextNodeInBinaryTrees/Solution.java" new file mode 100755 index 00000000..c6165f32 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/08_NextNodeInBinaryTrees/Solution.java" @@ -0,0 +1,54 @@ +/* +public class TreeLinkNode { + int val; + TreeLinkNode left = null; + TreeLinkNode right = null; + TreeLinkNode next = null; + + TreeLinkNode(int val) { + this.val = val; + } +} +*/ + +/** + * @author bingo + * @since 2018/10/28 + */ + +public class Solution { + /** + * 获取中序遍历结点的下一个结点 + * + * @param pNode 某个结点 + * @return pNode的下一个结点 + */ + public TreeLinkNode GetNext(TreeLinkNode pNode) { + if (pNode == null) { + return null; + } + + if (pNode.right != null) { + TreeLinkNode t = pNode.right; + while (t.left != null) { + t = t.left; + } + return t; + } + + // 须保证 pNode.next 不为空,否则会出现 NPE + if (pNode.next != null && pNode.next.left == pNode) { + return pNode.next; + } + + while (pNode.next != null) { + if (pNode.next.left == pNode) { + return pNode.next; + } + pNode = pNode.next; + } + + return null; + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_01_QueueWithTwoStacks/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_01_QueueWithTwoStacks/README.md" new file mode 100755 index 00000000..9dc32d0d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_01_QueueWithTwoStacks/README.md" @@ -0,0 +1,47 @@ +## 用两个栈实现队列 + +### 题目描述 +用两个栈来实现一个队列,完成队列的 `Push` 和 `Pop` 操作。 队列中的元素为 `int` 类型。 + + +### 解法 +`Push` 操作,每次都存入 `stack1`; +`Pop` 操作,每次从 `stack2` 取: +- `stack2` 栈不为空时,不能将 `stack1` 元素倒入; +- `stack2` 栈为空时,需要一次将 `stack1` 元素全部倒入。 + +```java +import java.util.Stack; + +/** + * @author bingo + * @since 2018/10/28 + */ + +public class Solution { + Stack stack1 = new Stack(); + Stack stack2 = new Stack(); + + public void push(int node) { + stack1.push(node); + } + + public int pop() { + if (stack2.isEmpty()) { + if (stack1.isEmpty()) { + return -1; + } + while (!stack1.isEmpty()) { + stack2.push(stack1.pop()); + } + } + return stack2.pop(); + } +} +``` + + +### 测试用例 +1. 往空的队列里添加、删除元素; +2. 往非空的队列添加、删除元素; +3. 连续删除元素直至队列为空。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_01_QueueWithTwoStacks/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_01_QueueWithTwoStacks/Solution.java" new file mode 100755 index 00000000..ab77e4af --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_01_QueueWithTwoStacks/Solution.java" @@ -0,0 +1,27 @@ +import java.util.Stack; + +/** + * @author bingo + * @since 2018/10/28 + */ + +public class Solution { + Stack stack1 = new Stack(); + Stack stack2 = new Stack(); + + public void push(int node) { + stack1.push(node); + } + + public int pop() { + if (stack2.isEmpty()) { + if (stack1.isEmpty()) { + return -1; + } + while (!stack1.isEmpty()) { + stack2.push(stack1.pop()); + } + } + return stack2.pop(); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_02_StackWithTwoQueues/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_02_StackWithTwoQueues/README.md" new file mode 100755 index 00000000..823b8fa2 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_02_StackWithTwoQueues/README.md" @@ -0,0 +1,55 @@ +## 用两个队列实现栈 + +### 题目描述 +用两个队列来实现一个栈,完成栈的 `Push` 和 `Pop` 操作。 栈中的元素为 `int` 类型。 + + +### 解法 +`Push` 操作,每次都存入 `queue1`; +`Pop` 操作,每次从 `queue1` 取: +- 将 `queue1` 中的元素依次倒入 `queue2`,直到 `queue1` 剩下一个元素,这个元素就是要 `pop` 出去的; +- 将 `queue1` 与 `queue2` 进行交换,这样保证每次都从 `queue1` 中存取元素,`queue2` 只起到辅助暂存的作用。 + +```java +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author bingo + * @since 2018/10/29 + */ + +public class Solution { + + private Queue queue1 = new LinkedList<>(); + private Queue queue2 = new LinkedList<>(); + + public void push(int node) { + queue1.offer(node); + } + + public int pop() { + if (queue1.isEmpty()) { + throw new RuntimeException("Empty stack!"); + } + + while (queue1.size() > 1) { + queue2.offer(queue1.poll()); + } + + int val = queue1.poll(); + + Queue t = queue1; + queue1 = queue2; + queue2 = t; + return val; + + } +} +``` + + +### 测试用例 +1. 往空的栈里添加、删除元素; +2. 往非空的栈添加、删除元素; +3. 连续删除元素直至栈为空。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_02_StackWithTwoQueues/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_02_StackWithTwoQueues/Solution.java" new file mode 100755 index 00000000..5704c26b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/09_02_StackWithTwoQueues/Solution.java" @@ -0,0 +1,35 @@ +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author bingo + * @since 2018/10/29 + */ + +public class Solution { + + private Queue queue1 = new LinkedList<>(); + private Queue queue2 = new LinkedList<>(); + + public void push(int node) { + queue1.offer(node); + } + + public int pop() { + if (queue1.isEmpty()) { + throw new RuntimeException("Empty stack!"); + } + + while (queue1.size() > 1) { + queue2.offer(queue1.poll()); + } + + int val = queue1.poll(); + + Queue t = queue1; + queue1 = queue2; + queue2 = t; + return val; + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_01_Fibonacci/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_01_Fibonacci/README.md" new file mode 100755 index 00000000..31ac8b0e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_01_Fibonacci/README.md" @@ -0,0 +1,79 @@ +## 斐波那契数列 + +### 题目描述 +大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第 `n` 项(从 `0` 开始,第 `0` 项为 `0`)。`n<=39` + + +### 解法 +#### 解法一 +采用递归方式,简洁明了,但效率很低,存在大量的重复计算。 +``` + f(10) + / \ + f(9) f(8) + / \ / \ + f(8) f(7) f(7) f(6) + / \ / \ + f(7) f(6) f(6) f(5) +``` + +```java + +/** + * @author bingo + * @since 2018/10/29 + */ + +public class Solution { + /** + * 求斐波那契数列的第n项,n从0开始 + * @param n 第n项 + * @return 第n项的值 + */ + public int Fibonacci(int n) { + if (n < 2) { + return n; + } + // 递归调用 + return Fibonacci(n - 1) + Fibonacci(n - 2); + } +} +``` + +#### 解法二 +从下往上计算,递推,时间复杂度 `O(n)`。 + +```java + +/** + * @author bingo + * @since 2018/10/29 + */ + +public class Solution { + /** + * 求斐波那契数列的第n项,n从0开始 + * @param n 第n项 + * @return 第n项的值 + */ + public int Fibonacci(int n) { + if (n < 2) { + return n; + } + int[] res = new int[n + 1]; + res[0] = 0; + res[1] = 1; + for (int i = 2; i <= n; ++i) { + res[i] = res[i - 1] + res[i - 2]; + } + return res[n]; + + } +} +``` + + +### 测试用例 +1. 功能测试(如输入 3、5、10 等); +2. 边界值测试(如输入 0、1、2); +3. 性能测试(输入较大的数字,如 40、50、100 等)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_01_Fibonacci/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_01_Fibonacci/Solution.java" new file mode 100755 index 00000000..5117af6f --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_01_Fibonacci/Solution.java" @@ -0,0 +1,26 @@ + +/** + * @author bingo + * @since 2018/10/29 + */ + +public class Solution { + /** + * 求斐波那契数列的第n项,n从0开始 + * @param n 第n项 + * @return 第n项的值 + */ + public int Fibonacci(int n) { + if (n < 2) { + return n; + } + int[] res = new int[n + 1]; + res[0] = 0; + res[1] = 1; + for (int i = 2; i <= n; ++i) { + res[i] = res[i - 1] + res[i - 2]; + } + return res[n]; + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_02_JumpFloor/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_02_JumpFloor/README.md" new file mode 100755 index 00000000..268b7c8a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_02_JumpFloor/README.md" @@ -0,0 +1,42 @@ +## 跳台阶 + +### 题目描述 +一只青蛙一次可以跳上`1`级台阶,也可以跳上`2`级。求该青蛙跳上一个`n`级的台阶总共有多少种跳法(先后次序不同算不同的结果)。 + +### 解法 +跳上 `n` 级台阶,可以从 `n-1` 级跳 `1` 级上去,也可以从 `n-2` 级跳 `2` 级上去。所以 +``` +f(n) = f(n-1) + f(n-2) +``` + +```java +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 青蛙跳台阶 + * @param target 跳上的那一级台阶 + * @return 多少种跳法 + */ + public int JumpFloor(int target) { + if (target < 3) { + return target; + } + int[] res = new int[target + 1]; + res[1] = 1; + res[2] = 2; + for (int i = 3; i <= target; ++i) { + res[i] = res[i - 1] + res[i - 2]; + } + return res[target]; + } +} +``` + +### 测试用例 +1. 功能测试(如输入 3、5、10 等); +2. 边界值测试(如输入 0、1、2); +3. 性能测试(输入较大的数字,如 40、50、100 等)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_02_JumpFloor/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_02_JumpFloor/Solution.java" new file mode 100755 index 00000000..fbd96e02 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_02_JumpFloor/Solution.java" @@ -0,0 +1,25 @@ +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 青蛙跳台阶 + * + * @param target 跳上的那一级台阶 + * @return 多少种跳法 + */ + public int JumpFloor(int target) { + if (target < 3) { + return target; + } + int[] res = new int[target + 1]; + res[1] = 1; + res[2] = 2; + for (int i = 3; i <= target; ++i) { + res[i] = res[i - 1] + res[i - 2]; + } + return res[target]; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_03_JumpFloorII/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_03_JumpFloorII/README.md" new file mode 100755 index 00000000..91f3ac3e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_03_JumpFloorII/README.md" @@ -0,0 +1,48 @@ +## 变态跳台阶 + +### 题目描述 +一只青蛙一次可以跳上`1`级台阶,也可以跳上`2`级……它也可以跳上`n`级。求该青蛙跳上一个`n`级的台阶总共有多少种跳法。 + +### 解法 +跳上 `n-1` 级台阶,可以从 `n-2` 级跳 `1` 级上去,也可以从 `n-3` 级跳 `2` 级上去...也可以从 `0` 级跳上去。那么 +``` +f(n-1) = f(0) + f(1) + ... + f(n-2) ① +``` + +跳上 `n` 级台阶,可以从 `n-1` 级跳 `1` 级上去,也可以从 `n-2` 级跳 `2` 级上去...也可以从 `0` 级跳上去。那么 +``` +f(n) = f(0) + f(1) + ... + f(n-2) + f(n-1) ② + +②-①: +f(n) - f(n-1) = f(n-1) +f(n) = 2f(n-1) +``` + +所以 f(n) 是一个等比数列: +``` +f(n) = 2^(n-1) +``` + + +```java +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 青蛙跳台阶II + * @param target 跳上的那一级台阶 + * @return 多少种跳法 + */ + public int JumpFloorII(int target) { + return (int) Math.pow(2, target - 1); + } +} +``` + +### 测试用例 +1. 功能测试(如输入 3、5、10 等); +2. 边界值测试(如输入 0、1、2); +3. 性能测试(输入较大的数字,如 40、50、100 等)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_03_JumpFloorII/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_03_JumpFloorII/Solution.java" new file mode 100755 index 00000000..ebf516a1 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_03_JumpFloorII/Solution.java" @@ -0,0 +1,16 @@ +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 青蛙跳台阶II + * + * @param target 跳上的那一级台阶 + * @return 多少种跳法 + */ + public int JumpFloorII(int target) { + return (int) Math.pow(2, target - 1); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_04_RectCover/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_04_RectCover/README.md" new file mode 100755 index 00000000..07ddc850 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_04_RectCover/README.md" @@ -0,0 +1,73 @@ +## 矩形覆盖 + +### 题目描述 +我们可以用`2*1`的小矩形横着或者竖着去覆盖更大的矩形。请问用`n`个`2*1`的小矩形无重叠地覆盖一个`2*n`的大矩形,总共有多少种方法? + +### 解法 +覆盖 `2*n` 的矩形: +- 可以先覆盖 `2*n-1` 的矩形,再覆盖一个 `2*1` 的矩形; +- 也可以先覆盖 `2*(n-2)` 的矩形,再覆盖两个 `1*2` 的矩形。 + +#### 解法一:利用数组存放结果 +```java +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 矩形覆盖 + * @param target 2*target大小的矩形 + * @return 多少种覆盖方法 + */ + public int RectCover(int target) { + if (target < 3) { + return target; + } + int[] res = new int[target + 1]; + res[1] = 1; + res[2] = 2; + for (int i = 3; i <= target; ++i) { + res[i] = res[i - 1] + res[i - 2]; + } + return res[target]; + } +} +``` + +#### 解法二:直接用变量存储结果 +```java +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 矩形覆盖 + * @param target 2*target大小的矩形 + * @return 多少种覆盖方法 + */ + public int RectCover(int target) { + if (target < 3) { + return target; + } + int res1 = 1; + int res2 = 2; + int res = 0; + for (int i = 3; i <= target; ++i) { + res = res1 + res2; + res1 = res2; + res2 = res; + } + return res; + } +} +``` + + +### 测试用例 +1. 功能测试(如输入 3、5、10 等); +2. 边界值测试(如输入 0、1、2); +3. 性能测试(输入较大的数字,如 40、50、100 等)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_04_RectCover/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_04_RectCover/Solution.java" new file mode 100755 index 00000000..26215a2e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/10_04_RectCover/Solution.java" @@ -0,0 +1,25 @@ +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 矩形覆盖 + * + * @param target 2*target大小的矩形 + * @return 多少种覆盖方法 + */ + public int RectCover(int target) { + if (target < 3) { + return target; + } + int[] res = new int[target + 1]; + res[1] = 1; + res[2] = 2; + for (int i = 3; i <= target; ++i) { + res[i] = res[i - 1] + res[i - 2]; + } + return res[target]; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/11_MinNumberInRotatedArray/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/11_MinNumberInRotatedArray/README.md" new file mode 100755 index 00000000..e8fcdad0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/11_MinNumberInRotatedArray/README.md" @@ -0,0 +1,119 @@ +## 旋转数组的最小数字 + +### 题目描述 +把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组 `{3,4,5,1,2}` 为 `{1,2,3,4,5}` 的一个旋转,该数组的最小值为 `1`。 + +**NOTE:**给出的所有元素都大于 `0`,若数组大小为 `0`,请返回 `0`。 + + +### 解法 +#### 解法一 +直接遍历数组找最小值,时间复杂度 `O(n)`,不推荐。 + +```java + +/** + * @author bingo + * @since 2018/10/30 + */ + +public class Solution { + /** + * 获取旋转数组的最小元素 + * @param array 旋转数组 + * @return 数组中的最小值 + */ + public int minNumberInRotateArray(int[] array) { + if (array == null || array.length == 0) { + return 0; + } + + int n = array.length; + if (n == 1 || array[0] < array[n - 1]) { + return array[0]; + } + + int min = array[0]; + for (int i = 1; i < n; ++i) { + min = array[i] < min ? array[i] : min; + } + + return min; + } + +} +``` + +#### 解法二 +利用指针 `p`,`q` 指向数组的首尾,如果 `array[p] < array[q]`,说明数组是递增数组,直接返回 `array[p]`。否则进行如下讨论。 + +计算中间指针 `mid`: +- 如果此时 `array[p]`, `array[q]`, `array[mid]` 两两相等,此时无法采用二分方式,只能通过遍历区间 `[p,q]` 获取最小值; +- 如果此时 `p`,`q` 相邻,说明此时 `q` 指向的元素是最小值,返回 `array[q]`; +- 如果此时 `array[mid] >= array[p]`,说明 `mid` 位于左边的递增数组中,最小值在右边,因此,把 `p` 指向 `mid`,此时保持了 `p` 指向左边递增子数组; +- 如果此时 `array[mid] <= array[q]`,说明 `mid` 位于右边的递增数组中,最小值在左边,因此,把 `q` 指向 `mid`,此时保持了 `q` 指向右边递增子数组。 + +```java + + +/** + * @author bingo + * @since 2018/10/30 + */ + +public class Solution { + /** + * 获取旋转数组的最小元素 + * @param array 旋转数组 + * @return 数组中的最小值 + */ + public int minNumberInRotateArray(int[] array) { + if (array == null || array.length == 0) { + return 0; + } + + int p = 0; + // mid初始为p,为了兼容当数组是递增数组(即不满足 array[p] >= array[q])时,返回 array[p] + int mid = p; + int q = array.length - 1; + while (array[p] >= array[q]) { + if (q - p == 1) { + // 当p,q相邻时(距离为1),那么q指向的元素就是最小值 + mid = q; + break; + } + mid = p + ((q - p) >> 1); + + // 当p,q,mid指向的值相等时,此时只能通过遍历查找最小值 + if (array[p] == array[q] && array[mid] == array[p]) { + mid = getMinIndex(array, p, q); + break; + } + + if (array[mid] >= array[p]) { + p = mid; + } else if (array[mid] <= array[q]) { + q = mid; + } + } + + return array[mid]; + + + } + + private int getMinIndex(int[] array, int p, int q) { + int minIndex = p; + for (int i = p + 1; i <= q; ++i) { + minIndex = array[i] < array[minIndex] ? i : minIndex; + } + return minIndex; + } +} +``` + + +### 测试用例 +1. 功能测试(输入的数组是升序排序数组的一个旋转,数组中有重复数字或者没有重复数字); +2. 边界值测试(输入的数组是一个升序排序的数组,只包含一个数字的数组); +3. 特殊输入测试(输入空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/11_MinNumberInRotatedArray/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/11_MinNumberInRotatedArray/Solution.java" new file mode 100755 index 00000000..b9d94d32 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/11_MinNumberInRotatedArray/Solution.java" @@ -0,0 +1,55 @@ + +/** + * @author bingo + * @since 2018/10/30 + */ + +public class Solution { + /** + * 获取旋转数组的最小元素 + * @param array 旋转数组 + * @return 数组中的最小值 + */ + public int minNumberInRotateArray(int[] array) { + if (array == null || array.length == 0) { + return 0; + } + + int p = 0; + // mid初始为p,为了兼容当数组是递增数组(即不满足 array[p] >= array[q])时,返回 array[p] + int mid = p; + int q = array.length - 1; + while (array[p] >= array[q]) { + if (q - p == 1) { + // 当p,q相邻时(距离为1),那么q指向的元素就是最小值 + mid = q; + break; + } + mid = p + ((q - p) >> 1); + + // 当p,q,mid指向的值相等时,此时只能通过遍历查找最小值 + if (array[p] == array[q] && array[mid] == array[p]) { + mid = getMinIndex(array, p, q); + break; + } + + if (array[mid] >= array[p]) { + p = mid; + } else if (array[mid] <= array[q]) { + q = mid; + } + } + + return array[mid]; + + + } + + private int getMinIndex(int[] array, int p, int q) { + int minIndex = p; + for (int i = p + 1; i <= q; ++i) { + minIndex = array[i] < array[minIndex] ? i : minIndex; + } + return minIndex; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/12_StringPathInMatrix/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/12_StringPathInMatrix/README.md" new file mode 100755 index 00000000..9a87e9e3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/12_StringPathInMatrix/README.md" @@ -0,0 +1,66 @@ +## 矩阵中的路径 + +### 题目描述 +请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 `a b c e s f c s a d e e` 这样的 `3 X 4` 矩阵中包含一条字符串`"bcced"`的路径,但是矩阵中不包含`"abcb"`路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。 + +### 解法 +回溯法。首先,任选一个格子作为路径起点。假设格子对应的字符为 ch,并且对应路径上的第 i 个字符。若相等,到相邻格子寻找路径上的第 i+1 个字符。重复这一过程。 + +```java +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + /** + * 判断矩阵中是否包含某条路径 + * @param matrix 矩阵 + * @param rows 行数 + * @param cols 列数 + * @param str 路径 + * @return bool + */ + public boolean hasPath(char[] matrix, int rows, int cols, char[] str) { + if (matrix == null || rows < 1 || cols < 1 || str == null) { + return false; + } + boolean[] visited = new boolean[matrix.length]; + int pathLength = 0; + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + if (hasPath(matrix, rows, cols, str, i, j, pathLength, visited)) { + return true; + } + } + } + return false; + } + + private boolean hasPath(char[] matrix, int rows, int cols, char[] str, int i, int j, int pathLength, boolean[] visited) { + if (pathLength == str.length) { + return true; + } + boolean hasPath = false; + if (i >= 0 && i < rows && j >= 0 && j < cols && matrix[i * cols + j] == str[pathLength] && !visited[i * cols + j]) { + ++pathLength; + visited[i * cols + j] = true; + hasPath = hasPath(matrix, rows, cols, str, i - 1, j, pathLength, visited) + || hasPath(matrix, rows, cols, str, i + 1, j, pathLength, visited) + || hasPath(matrix, rows, cols, str, i, j - 1, pathLength, visited) + || hasPath(matrix, rows, cols, str, i, j + 1, pathLength, visited); + if (!hasPath) { + --pathLength; + visited[i * cols + j] = false; + } + } + return hasPath; + } +} + +``` + +### 测试用例 +1. 功能测试(在多行多列的矩阵中存在或者不存在路径); +2. 边界值测试(矩阵只有一行或者一列;矩阵和路径中的所有字母都是相同的); +3. 特殊输入测试(输入空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/12_StringPathInMatrix/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/12_StringPathInMatrix/Solution.java" new file mode 100755 index 00000000..f24549aa --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/12_StringPathInMatrix/Solution.java" @@ -0,0 +1,52 @@ +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + /** + * 判断矩阵中是否包含某条路径 + * @param matrix 矩阵 + * @param rows 行数 + * @param cols 列数 + * @param str 路径 + * @return bool + */ + public boolean hasPath(char[] matrix, int rows, int cols, char[] str) { + if (matrix == null || rows < 1 || cols < 1 || str == null) { + return false; + } + boolean[] visited = new boolean[matrix.length]; + int pathLength = 0; + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + if (hasPath(matrix, rows, cols, str, i, j, pathLength, visited)) { + return true; + } + } + } + return false; + } + + private boolean hasPath(char[] matrix, int rows, int cols, char[] str, int i, int j, int pathLength, boolean[] visited) { + if (pathLength == str.length) { + return true; + } + boolean hasPath = false; + if (i >= 0 && i < rows && j >= 0 && j < cols && matrix[i * cols + j] == str[pathLength] && !visited[i * cols + j]) { + ++pathLength; + visited[i * cols + j] = true; + hasPath = hasPath(matrix, rows, cols, str, i - 1, j, pathLength, visited) + || hasPath(matrix, rows, cols, str, i + 1, j, pathLength, visited) + || hasPath(matrix, rows, cols, str, i, j - 1, pathLength, visited) + || hasPath(matrix, rows, cols, str, i, j + 1, pathLength, visited); + if (!hasPath) { + --pathLength; + visited[i * cols + j] = false; + } + } + return hasPath; + } + + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/13_RobotMove/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/13_RobotMove/README.md" new file mode 100755 index 00000000..7a4e8d5e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/13_RobotMove/README.md" @@ -0,0 +1,66 @@ +## 机器人的移动范围 + +### 题目描述 +地上有一个`m`行和`n`列的方格。一个机器人从坐标`0,0`的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于`k`的格子。 例如,当`k`为`18`时,机器人能够进入方格`(35,37)`,因为`3+5+3+7 = 18`。但是,它不能进入方格`(35,38)`,因为`3+5+3+8 = 19`。请问该机器人能够达到多少个格子? + +### 解法 +从坐标(0, 0) 开始移动,当它准备进入坐标(i, j),判断是否能进入,如果能,再判断它能否进入 4 个相邻的格子 (i-1, j), (i+1, j), (i, j-1), (i, j+1)。 + +```java +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + /** + * 计算能到达的格子数 + * @param threshold 限定的数字 + * @param rows 行数 + * @param cols 列数 + * @return 格子数 + */ + public int movingCount(int threshold, int rows, int cols) { + if (threshold < 0 || rows < 1 || cols < 1) { + return 0; + } + boolean[] visited = new boolean[rows * cols]; + return getCount(threshold, 0, 0, rows, cols, visited); + } + + private int getCount(int threshold, int i, int j, int rows, int cols, boolean[] visited) { + if (check(threshold, i, j, rows, cols, visited)) { + visited[i * cols + j] = true; + return 1 + + getCount(threshold, i - 1, j, rows, cols, visited) + + getCount(threshold, i + 1, j, rows, cols, visited) + + getCount(threshold, i, j - 1, rows, cols, visited) + + getCount(threshold, i, j + 1, rows, cols, visited); + } + return 0; + } + + private boolean check(int threshold, int i, int j, int rows, int cols, boolean[] visited) { + return i >= 0 + && i < rows + && j >= 0 + && j < cols + && !visited[i * cols + j] + && getDigitSum(i) + getDigitSum(j) <= threshold; + } + + private int getDigitSum(int i) { + int res = 0; + while (i > 0) { + res += i % 10; + i /= 10; + } + return res; + } +} +``` + +### 测试用例 +1. 功能测试(方格为多行多列;k 为正数); +2. 边界值测试(方格只有一行或者一列;k = 0); +3. 特殊输入测试(k < 0)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/13_RobotMove/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/13_RobotMove/Solution.java" new file mode 100755 index 00000000..f29180b5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/13_RobotMove/Solution.java" @@ -0,0 +1,47 @@ +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + /** + * 计算能到达的格子数 + * + * @param threshold 限定的数字 + * @param rows 行数 + * @param cols 列数 + * @return 格子数 + */ + public int movingCount(int threshold, int rows, int cols) { + if (threshold < 0 || rows < 1 || cols < 1) { + return 0; + } + boolean[] visited = new boolean[rows * cols]; + return getCount(threshold, 0, 0, rows, cols, visited); + } + + private int getCount(int threshold, int i, int j, int rows, int cols, boolean[] visited) { + if (check(threshold, i, j, rows, cols, visited)) { + visited[i * cols + j] = true; + return 1 + getCount(threshold, i - 1, j, rows, cols, visited) + + getCount(threshold, i + 1, j, rows, cols, visited) + + getCount(threshold, i, j - 1, rows, cols, visited) + + getCount(threshold, i, j + 1, rows, cols, visited); + } + return 0; + } + + private boolean check(int threshold, int i, int j, int rows, int cols, boolean[] visited) { + return i >= 0 && i < rows && j >= 0 && j < cols && !visited[i * cols + j] + && getDigitSum(i) + getDigitSum(j) <= threshold; + } + + private int getDigitSum(int i) { + int res = 0; + while (i > 0) { + res += i % 10; + i /= 10; + } + return res; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/14_CuttingRope/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/14_CuttingRope/README.md" new file mode 100755 index 00000000..c120a5b7 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/14_CuttingRope/README.md" @@ -0,0 +1,102 @@ +## 剪绳子 + +### 题目描述 +给你一根长度为`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`。 + +### 解法 +#### 解法一:动态规划法 +时间复杂度`O(n²)`,空间复杂度`O(n)`。 + +- 长度为 2,只可能剪成长度为 1 的两段,因此 f(2)=1 +- 长度为 3,剪成长度分别为 1 和 2 的两段,乘积比较大,因此 f(3) = 2 +- 长度为 n,在剪第一刀的时候,有 n-1 种可能的选择,剪出来的绳子又可以继续剪,可以看出,原问题可以划分为子问题,子问题又有重复子问题。 + +```java +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + + /** + * 剪绳子求最大乘积 + * @param length 绳子长度 + * @return 乘积最大值 + */ + public int maxProductAfterCutting(int length) { + if (length < 2) { + return 0; + } + if (length < 4) { + return length - 1; + } + + // res[i] 表示当长度为i时的最大乘积 + int[] res = new int[length + 1]; + res[1] = 1; + res[2] = 2; + res[3] = 3; + // 从长度为4开始计算 + for (int i = 4; i <= length; ++i) { + int max = 0; + for (int j = 1; j <= i / 2; ++j) { + max = Math.max(max, res[j] * res[i - j]); + } + res[i] = max; + } + + return res[length]; + + } +} + +``` + +#### 贪心算法 +时间复杂度`O(1)`,空间复杂度`O(1)`。 + +贪心策略: +- 当 n>=5 时,尽可能多地剪长度为 3 的绳子 +- 当剩下的绳子长度为 4 时,就把绳子剪成两段长度为 2 的绳子。 + +**证明:** +- 当 n>=5 时,可以证明 2(n-2)>n,并且 3(n-3)>n。也就是说,当绳子剩下长度大于或者等于 5 的时候,可以把它剪成长度为 3 或者 2 的绳子段。 +- 当 n>=5 时,3(n-3)>=2(n-2),因此,应该尽可能多地剪长度为 3 的绳子段。 +- 当 n=4 时,剪成两根长度为 2 的绳子,其实没必要剪,只是题目的要求是至少要剪一刀。 + +```java +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + + /** + * 剪绳子求最大乘积 + * @param length 绳子长度 + * @return 乘积最大值 + */ + public int maxProductAfterCutting(int length) { + if (length < 2) { + return 0; + } + if (length < 4) { + return length - 1; + } + + int timesOf3 = length / 3; + if (length % 3 == 1) { + --timesOf3; + } + int timesOf2 = (length - timesOf3 * 3) >> 1; + return (int) (Math.pow(3, timesOf3) * Math.pow(2, timesOf2)); + } +} + +``` + +### 测试用例 +1. 功能测试(绳子的初始长度大于 5); +2. 边界值测试(绳子的初始长度分别为 0、1、2、3、4)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/14_CuttingRope/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/14_CuttingRope/Solution.java" new file mode 100755 index 00000000..e22d7748 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/14_CuttingRope/Solution.java" @@ -0,0 +1,57 @@ +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + + /** + * 剪绳子求最大乘积(动态规划) + * + * @param length 绳子长度 + * @return 乘积最大值 + */ + public int maxProductAfterCutting1(int length) { + if (length < 2) { + return 0; + } + if (length < 4) { + return length - 1; + } + + int[] res = new int[length + 1]; + res[1] = 1; + res[2] = 2; + res[3] = 3; + for (int i = 4; i <= length; ++i) { + int max = 0; + for (int j = 1; j <= i / 2; ++j) { + max = Math.max(max, res[j] * res[i - j]); + } + res[i] = max; + } + return res[length]; + } + + /** + * 剪绳子求最大乘积(贪心算法) + * + * @param length 绳子长度 + * @return 乘积最大值 + */ + public int maxProductAfterCutting2(int length) { + if (length < 2) { + return 0; + } + if (length < 4) { + return length - 1; + } + + int timesOf3 = length / 3; + if (length % 3 == 1) { + --timesOf3; + } + int timesOf2 = (length - timesOf3 * 3) >> 1; + return (int) (Math.pow(3, timesOf3) * Math.pow(2, timesOf2)); + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/15_NumberOf1InBinary/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/15_NumberOf1InBinary/README.md" new file mode 100755 index 00000000..23bf9351 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/15_NumberOf1InBinary/README.md" @@ -0,0 +1,73 @@ +## 二进制中 1 的个数 + +### 题目描述 +输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 + +### 解法 +#### 解法一 +利用整数 1,依次左移每次与 n 进行与运算,若结果不为0,说明这一位上数字为 1,++cnt。 + +此解法 i 需要左移 32 次。 + +不要用 n 去右移并与 1 进行与运算,因为n 可能为负数,右移时会陷入死循环。 + +```java +public class Solution { + public int NumberOf1(int n) { + int cnt = 0; + int i = 1; + while (i != 0) { + if ((n & i) != 0) { + ++cnt; + } + i <<= 1; + } + return cnt; + } +} +``` + +#### 解法二(推荐) +- 运算 (n - 1) & n,直至 n 为 0。运算的次数即为 n 的二进制中 1 的个数。 + +因为 n-1 会将 n 的最右边一位 1 改为 0,如果右边还有 0,则所有 0 都会变成 1。结果与 n 进行与运算,会去除掉最右边的一个1。 + +举个栗子: +``` +若 n = 1100, +n - 1 = 1011 +n & (n - 1) = 1000 + +即:把最右边的 1 变成了 0。 +``` + +> 把一个整数减去 1 之后再和原来的整数做位与运算,得到的结果相当于把整数的二进制表示中最右边的 1 变成 0。很多二进制的问题都可以用这种思路解决。 + +```java +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + /** + * 计算整数的二进制表示里1的个数 + * @param n 整数 + * @return 1的个数 + */ + public int NumberOf1(int n) { + int cnt = 0; + while (n != 0) { + n = (n - 1 ) & n; + ++cnt; + } + return cnt; + } +} + +``` + +### 测试用例 +1. 正数(包括边界值 1、0x7FFFFFFF); +2. 负数(包括边界值 0x80000000、0xFFFFFFFF); +3. 0。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/15_NumberOf1InBinary/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/15_NumberOf1InBinary/Solution.java" new file mode 100755 index 00000000..724d78b0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/15_NumberOf1InBinary/Solution.java" @@ -0,0 +1,21 @@ +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + /** + * 计算整数的二进制表示里1的个数 + * + * @param n 整数 + * @return 1的个数 + */ + public int NumberOf1(int n) { + int cnt = 0; + while (n != 0) { + n = (n - 1) & n; + ++cnt; + } + return cnt; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/16_Power/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/16_Power/README.md" new file mode 100755 index 00000000..f1bbc09c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/16_Power/README.md" @@ -0,0 +1,36 @@ +## 数值的整数次方 + +### 题目描述 +给定一个 `double` 类型的浮点数 `base` 和 `int` 类型的整数 `exponent`。求 `base`的 `exponent` 次方。 + +### 解法 +注意判断值数是否小于 0。另外 0 的 0 次方没有意义,也需要考虑一下,看具体题目要求。 + +```java +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + /** + * 计算数值的整数次方 + * @param base 底数 + * @param exponent 指数 + * @return 数值的整数次方 + */ + public double Power(double base, int exponent) { + double result = 1.0; + int n = Math.abs(exponent); + for (int i = 0; i < n; ++i) { + result *= base; + } + + return exponent < 0 ? 1.0 / result : result; + } +} + +``` + +### 测试用例 +1. 把底数和指数分别设为正数、负数和零。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/16_Power/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/16_Power/Solution.java" new file mode 100755 index 00000000..29ac585a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/16_Power/Solution.java" @@ -0,0 +1,23 @@ +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + /** + * 计算数值的整数次方 + * + * @param base 底数 + * @param exponent 指数 + * @return 数值的整数次方 + */ + public double Power(double base, int exponent) { + double result = 1.0; + int n = Math.abs(exponent); + for (int i = 0; i < n; ++i) { + result *= base; + } + + return exponent < 0 ? 1.0 / result : result; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/17_Print1ToMaxOfNDigits/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/17_Print1ToMaxOfNDigits/README.md" new file mode 100755 index 00000000..86b8e8fa --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/17_Print1ToMaxOfNDigits/README.md" @@ -0,0 +1,90 @@ +## 打印从 1 到最大的 n 位数 + +### 题目描述 +输入数字 `n`,按顺序打印出从 `1` 最大的 `n` 位十进制数。比如输入 `3`,则打印出 `1、2、3` 一直到最大的 3 位数即 999。 + +### 解法 +此题需要注意 n 位数构成的数字可能超出最大的 int 或者 long long 能表示的范围。因此,采用字符数组来存储数字。 + +关键是: +- 对字符数组表示的数进行递增操作 +- 输出数字(0开头的需要把0去除) + +```java +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + + /** + * 打印从1到最大的n位数 + * @param n n位 + */ + public void print1ToMaxOfNDigits(int n) { + if (n < 1) { + return; + } + + char[] chars = new char[n]; + for (int i = 0; i < n; ++i) { + chars[i] = '0'; + } + + while (!increment(chars)) { + printNumber(chars); + } + } + + /** + * 打印数字(去除前面的0) + * @param chars 数字数组 + */ + private void printNumber(char[] chars) { + int index = 0; + int n = chars.length; + for (char ch : chars) { + if (ch != '0') { + break; + } + ++index; + } + StringBuilder sb = new StringBuilder(); + for (int i = index; i < n; ++i) { + sb.append(chars[i]); + } + System.out.println(sb.toString()); + } + + /** + * 数字加1 + * @param chars 数字数组 + * @return 是否溢出 + */ + private boolean increment(char[] chars) { + boolean flag = false; + int n = chars.length; + int carry = 1; + for (int i = n - 1; i >= 0; --i) { + + int num = chars[i] - '0' + carry; + if (num > 9) { + if (i == 0) { + flag = true; + break; + } + chars[i] = '0'; + } else { + ++chars[i]; + break; + } + } + return flag; + } +} +``` + +### 测试用例 +1. 功能测试(输入 1、2、3......); +2. 特殊输入测试(输入 -1、0)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/17_Print1ToMaxOfNDigits/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/17_Print1ToMaxOfNDigits/Solution.java" new file mode 100755 index 00000000..be21ea35 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/17_Print1ToMaxOfNDigits/Solution.java" @@ -0,0 +1,75 @@ +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + + /** + * 打印从1到最大的n位数 + * + * @param n n位 + */ + public void print1ToMaxOfNDigits(int n) { + if (n < 1) { + return; + } + + char[] chars = new char[n]; + for (int i = 0; i < n; ++i) { + chars[i] = '0'; + } + + while (!increment(chars)) { + printNumber(chars); + } + } + + /** + * 打印数字(去除前面的0) + * + * @param chars 数字数组 + */ + private void printNumber(char[] chars) { + int index = 0; + int n = chars.length; + for (char ch : chars) { + if (ch != '0') { + break; + } + ++index; + } + StringBuilder sb = new StringBuilder(); + for (int i = index; i < n; ++i) { + sb.append(chars[i]); + } + System.out.println(sb.toString()); + } + + /** + * 数字加1 + * + * @param chars 数字数组 + * @return 是否溢出 + */ + private boolean increment(char[] chars) { + boolean flag = false; + int n = chars.length; + int carry = 1; + for (int i = n - 1; i >= 0; --i) { + + int num = chars[i] - '0' + carry; + if (num > 9) { + if (i == 0) { + flag = true; + break; + } + chars[i] = '0'; + } else { + ++chars[i]; + break; + } + } + return flag; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_01_DeleteNodeInList/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_01_DeleteNodeInList/README.md" new file mode 100755 index 00000000..fdebe01d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_01_DeleteNodeInList/README.md" @@ -0,0 +1,59 @@ +## 在O(1)时间内删除链表节点 + +### 题目描述 +给定单向链表的头指针和一个节点指针,定义一个函数在 O(1) 时间内删除该节点。 + +### 解法 +判断要删除的节点是否是尾节点,若是,直接删除;若不是,把要删除节点的下一个节点赋给要删除的节点即可。 + +### ```进行n次操作,平均时间复杂度为:( (n-1) * O(1) + O(n) ) / n = O(1),所以符合题目上说的O(1)``` + +```java +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + + class ListNode { + int val; + ListNode next; + } + + /** + * 删除链表的节点 + * @param head 链表头节点 + * @param tobeDelete 要删除的节点 + */ + public ListNode deleteNode(ListNode head, ListNode tobeDelete) { + if (head == null || tobeDelete == null) { + return head; + } + + // 删除的不是尾节点 + if (tobeDelete.next != null) { + tobeDelete.val = tobeDelete.next.val; + tobeDelete.next = tobeDelete.next.next; + } + // 链表中仅有一个节点 + else if (head == tobeDelete) { + head = null; + } + // 删除的是尾节点 + else { + ListNode ptr = head; + while (ptr.next != tobeDelete) { + ptr = ptr.next; + } + ptr.next = null; + } + + return head; + } +} +``` + +### 测试用例 +1. 功能测试(从有多个节点的链表的中间/头部/尾部删除一个节点;从只有一个节点的链表中删除唯一的节点); +2. 特殊输入测试(指向链表头节点的为空指针;指向要删除节点的为空指针)。 diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_01_DeleteNodeInList/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_01_DeleteNodeInList/Solution.java" new file mode 100755 index 00000000..987f5519 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_01_DeleteNodeInList/Solution.java" @@ -0,0 +1,44 @@ +/** + * @author bingo + * @since 2018/11/20 + */ + +public class Solution { + + class ListNode { + int val; + ListNode next; + } + + /** + * 删除链表的节点 + * + * @param head 链表头节点 + * @param tobeDelete 要删除的节点 + */ + public ListNode deleteNode(ListNode head, ListNode tobeDelete) { + if (head == null || tobeDelete == null) { + return head; + } + + // 删除的不是尾节点 + if (tobeDelete.next != null) { + tobeDelete.val = tobeDelete.next.val; + tobeDelete.next = tobeDelete.next.next; + } + // 链表中仅有一个节点 + else if (head == tobeDelete) { + head = null; + } + // 删除的是尾节点 + else { + ListNode ptr = head; + while (ptr.next != tobeDelete) { + ptr = ptr.next; + } + ptr.next = null; + } + + return head; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_02_DeleteDuplicatedNode/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_02_DeleteDuplicatedNode/README.md" new file mode 100755 index 00000000..054e6e34 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_02_DeleteDuplicatedNode/README.md" @@ -0,0 +1,94 @@ +## 删除链表中重复的节点 + +### 题目描述 +在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表`1->2->3->3->4->4->5` 处理后为 `1->2->5`。 + +### 解法 +#### 解法一:递归 + +```java +/** + * @author bingo + * @since 2018/11/21 + */ + +/* + public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +} +*/ +public class Solution { + /** + * 删除链表重复的节点 + * @param pHead 链表头节点 + * @return 删除节点后的链表 + */ + public ListNode deleteDuplication(ListNode pHead) { + if (pHead == null || pHead.next == null) { + return pHead; + } + + if (pHead.val == pHead.next.val) { + if (pHead.next.next == null) { + return null; + } + if (pHead.next.next.val == pHead.val) { + return deleteDuplication(pHead.next); + } + return deleteDuplication(pHead.next.next); + } + pHead.next = deleteDuplication(pHead.next); + return pHead; + } +} +``` + +#### 解法二 +```java +/* + public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +} +*/ +public class Solution { + public ListNode deleteDuplication(ListNode pHead) { + if (pHead == null || pHead.next == null) { + return pHead; + } + + ListNode pre = null; + ListNode cur = pHead; + while (cur != null) { + if (cur.next != null && cur.next.val == cur.val) { + int val = cur.val; + while (cur.next != null && cur.next.val == val) { + cur = cur.next; + } + if (pre == null) { + pHead = cur.next; + } else { + pre.next = cur.next; + } + } else { + pre = cur; + } + cur = cur.next; + } + return pHead; + } +} +``` + +### 测试用例 +1. 功能测试(重复的节点位于链表的头部/中间/尾部;链表中没有重复的节点); +2. 特殊输入测试(指向链表头节点的为空指针;链表中所有节点都是重复的)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_02_DeleteDuplicatedNode/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_02_DeleteDuplicatedNode/Solution.java" new file mode 100755 index 00000000..0c48b1f1 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/18_02_DeleteDuplicatedNode/Solution.java" @@ -0,0 +1,39 @@ +/** + * @author bingo + * @since 2018/11/21 + */ + +/* + public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +} +*/ +public class Solution { + /** + * 删除链表重复的节点 + * @param pHead 链表头节点 + * @return 删除节点后的链表 + */ + public ListNode deleteDuplication(ListNode pHead) { + if (pHead == null || pHead.next == null) { + return pHead; + } + + if (pHead.val == pHead.next.val) { + if (pHead.next.next == null) { + return null; + } + if (pHead.next.next.val == pHead.val) { + return deleteDuplication(pHead.next); + } + return deleteDuplication(pHead.next.next); + } + pHead.next = deleteDuplication(pHead.next); + return pHead; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/19_RegularExpressionsMatching/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/19_RegularExpressionsMatching/README.md" new file mode 100755 index 00000000..5cd4833b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/19_RegularExpressionsMatching/README.md" @@ -0,0 +1,68 @@ +## 正则表达式匹配 + +### 题目描述 +请实现一个函数用来匹配包括`.`和`*`的正则表达式。模式中的字符`.`表示任意一个字符,而`*`表示它前面的字符可以出现任意次(包含`0`次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串`aaa`与模式`a.a`和`ab*ac*a`匹配,但是与`aa.a`和`ab*a`均不匹配。 + +### 解法 +判断模式中第二个字符是否是 `*`: +- 若是,看如果模式串第一个字符与字符串第一个字符是否匹配: + - 1. 若不匹配,在模式串上向右移动两个字符`j+2`,相当于 a* 被忽略 + - 2. 若匹配,字符串后移`i+1`。此时模式串可以移动两个字符`j+2`,也可以不移动`j`。 +- 若不是,看当前字符与模式串的当前字符是否匹配,即 str[i] == pattern[j] || pattern[j] == '.': + - 1. 若匹配,则字符串与模式串都向右移动一位,`i+1`,`j+1`。 + - 2. 若不匹配,返回 fasle。 + +```java +/** + * @author bingo + * @since 2018/11/21 + */ + +public class Solution { + /** + * 判断字符串是否与模式串匹配 + * @param str 字符串 + * @param pattern 模式串 + * @return 是否匹配 + */ + public boolean match(char[] str, char[] pattern) { + if (str == null || pattern == null) { + return false; + } + return match(str, 0, str.length, pattern, 0, pattern.length); + } + + private boolean match(char[] str, int i, int len1, + char[] pattern, int j, int len2) { + if (i == len1 && j == len2) { + return true; + } + + // "",".*" + if (i != len1 && j == len2) { + return false; + } + + if (j + 1 < len2 && pattern[j + 1] == '*') { + if (i < len1 && (str[i] == pattern[j] || pattern[j] == '.')) { + return match(str, i, len1, pattern, j + 2, len2) + || match(str, i + 1, len1, pattern, j, len2) + || match(str, i + 1, len1, pattern,j + 2, len2); + } + + // "",".*" + return match(str, i, len1, pattern, j + 2, len2); + + } + if (i < len1 && (str[i] == pattern[j] || pattern[j] == '.')) { + return match(str, i + 1, len1, pattern, j + 1, len2); + } + return false; + + } +} +``` + +### 测试用例 +1. 功能测试(模式字符串里包含普通字符、`.`、`*`;模式字符串和输入字符串匹配/不匹配); +2. 特殊输入测试(输入字符串和模式字符串是空指针、空字符串)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/19_RegularExpressionsMatching/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/19_RegularExpressionsMatching/Solution.java" new file mode 100755 index 00000000..dde2eb01 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/19_RegularExpressionsMatching/Solution.java" @@ -0,0 +1,47 @@ +/** + * @author bingo + * @since 2018/11/21 + */ + +public class Solution { + /** + * 判断字符串是否与模式串匹配 + * + * @param str 字符串 + * @param pattern 模式串 + * @return 是否匹配 + */ + public boolean match(char[] str, char[] pattern) { + if (str == null || pattern == null) { + return false; + } + return match(str, 0, str.length, pattern, 0, pattern.length); + } + + private boolean match(char[] str, int i, int len1, char[] pattern, int j, int len2) { + if (i == len1 && j == len2) { + return true; + } + + // "",".*" + if (i != len1 && j == len2) { + return false; + } + + if (j + 1 < len2 && pattern[j + 1] == '*') { + if (i < len1 && (str[i] == pattern[j] || pattern[j] == '.')) { + return match(str, i, len1, pattern, j + 2, len2) || match(str, i + 1, len1, pattern, j, len2) + || match(str, i + 1, len1, pattern, j + 2, len2); + } + + // "",".*" + return match(str, i, len1, pattern, j + 2, len2); + + } + if (i < len1 && (str[i] == pattern[j] || pattern[j] == '.')) { + return match(str, i + 1, len1, pattern, j + 1, len2); + } + return false; + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/README.md" new file mode 100755 index 00000000..55fa620c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/README.md" @@ -0,0 +1,115 @@ +## 表示数值的字符串 + +### 题目描述 +请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。 + +### 解法 + +#### 解法一 + +利用正则表达式匹配即可。 +``` +[] : 字符集合 +() : 分组 +? : 重复 0 ~ 1 ++ : 重复 1 ~ n +* : 重复 0 ~ n +. : 任意字符 +\\. : 转义后的 . +\\d : 数字 +``` + +```java +/** + * @author bingo + * @since 2018/11/21 + */ + +public class Solution { + /** + * 判断是否是数字 + * @param str + * @return + */ + public boolean isNumeric(char[] str) { + return str != null + && str.length != 0 + && new String(str).matches("[+-]?\\d*(\\.\\d+)?([eE][+-]?\\d+)?"); + } +} +``` + +#### 解法二【剑指offer解法】 + +表示数值的字符串遵循模式`A[.[B]][e|EC]`或者`.B[e|EC]`,其中A为数值的整数部分,B紧跟小数点为数值的小数部分,C紧跟着e或者E为数值的指数部分。上述A和C都有可能以 `+` 或者 `-` 开头的0~9的数位串,B也是0~9的数位串,但前面不能有正负号。 + +```java +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2018/12/29 + * @description + */ +public class Solution { + + private int index = 0; + + /** + * 判断是否是数值 + * @param str + * @return + */ + public boolean isNumeric(char[] str) { + if (str == null || str.length < 1) { + return false; + } + + // 判断是否存在整数 + boolean flag = scanInteger(str); + + // 小数部分 + if (index < str.length && str[index] == '.') { + index++; + // 小数部分可以有整数或者没有整数 + // 所以使用 || + flag = scanUnsignedInteger(str) || flag; + } + + if (index < str.length && (str[index] == 'e' || str[index] == 'E')) { + index++; + // e或E前面必须有数字 + // e或者E后面必须有整数 + // 所以使用 && + flag = scanInteger(str) && flag; + } + + return flag && index == str.length; + + } + + private boolean scanInteger(char[] str) { + // 去除符号 + while (index < str.length && (str[index] == '+' || str[index] == '-')) { + index++; + } + + return scanUnsignedInteger(str); + } + + private boolean scanUnsignedInteger(char[] str) { + int start = index; + while (index < str.length && str[index] >= '0' && str[index] <= '9') { + index++; + } + // 判断是否存在整数 + return index > start; + } +} +``` + + + +### 测试用例 + +1. 功能测试(正数或者负数;包含或者不包含整数部分的数值;包含或者不包含效数部分的值;包含或者不包含指数部分的值;各种不能表达有效数值的字符串); +2. 特殊输入测试(输入字符串和模式字符串是空指针、空字符串)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/Solution.java" new file mode 100755 index 00000000..5e81c67c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/Solution.java" @@ -0,0 +1,16 @@ +/** + * @author bingo + * @since 2018/11/21 + */ + +public class Solution { + /** + * 判断是否是数字 + * + * @param str + * @return + */ + public boolean isNumeric(char[] str) { + return str != null && str.length != 0 && new String(str).matches("[+-]?\\d*(\\.\\d+)?([eE][+-]?\\d+)?"); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/Solution1.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/Solution1.java" new file mode 100755 index 00000000..8c1c5a5b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/20_NumericStrings/Solution1.java" @@ -0,0 +1,61 @@ +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2018/12/29 + * @description + */ +public class Solution1 { + + private int index = 0; + + /** + * 判断是否是数值 + * @param str + * @return + */ + public boolean isNumeric(char[] str) { + if (str == null || str.length < 1) { + return false; + } + + // 判断是否存在整数 + boolean flag = scanInteger(str); + + // 小数部分 + if (index < str.length && str[index] == '.') { + index++; + // 小数部分可以有整数或者没有整数 + // 所以使用 || + flag = scanUnsignedInteger(str) || flag; + } + + if (index < str.length && (str[index] == 'e' || str[index] == 'E')) { + index++; + // e或E前面必须有数字 + // e或者E后面必须有整数 + // 所以使用 && + flag = scanInteger(str) && flag; + } + + return flag && index == str.length; + + } + + private boolean scanInteger(char[] str) { + // 去除符号 + if (index < str.length && (str[index] == '+' || str[index] == '-')) { + index++; + } + + return scanUnsignedInteger(str); + } + + private boolean scanUnsignedInteger(char[] str) { + int start = index; + while (index < str.length && str[index] >= '0' && str[index] <= '9') { + index++; + } + // 判断是否存在整数 + return index > start; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/21_ReorderArray/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/21_ReorderArray/README.md" new file mode 100755 index 00000000..a4730a32 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/21_ReorderArray/README.md" @@ -0,0 +1,68 @@ +## 调整数组顺序使奇数位于偶数前面 + +### 题目描述 +输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 + +### 解法 +#### 解法一 +计算出奇数的个数,就很容易写出来了。 + +```java +import java.util.Arrays; + +/** + * @author bingo + * @since 2018/11/21 + */ + +public class Solution { + /** + * 调整数组元素顺序,使得奇数元素位于偶数元素前面,且保证奇数和奇数,偶数和偶数之间的相对位置不变。 + * @param array 数组 + */ + public void reOrderArray(int [] array) { + if (array == null || array.length < 2) { + return; + } + + int numsOfOdd = 0; + for (int val : array) { + if (val % 2 == 1) { + ++numsOfOdd; + } + } + int[] bak = Arrays.copyOf(array, array.length); + int i = 0, j = numsOfOdd; + for (int val : bak) { + if (val % 2 == 1) { + array[i++] = val; + } else { + array[j++] = val; + } + } + } + +} +``` + +#### 解法二 +```java +import java.util.Arrays; + +public class Solution { + public void reOrderArray(int [] array) { + if (array == null || array.length < 2) { + return; + } + Integer[] bak = new Integer[array.length]; + Arrays.setAll(bak, i -> array[i]); + Arrays.sort(bak, (x, y) -> (y & 1) - (x & 1)); + Arrays.setAll(array, i -> bak[i]); + } + +} +``` + +### 测试用例 +1. 功能测试(输入数组中的奇数、偶数交替出现;输入的数组中所有偶数都出现在奇数的前面;输入的数组中所有偶数都出现在奇数的前面;输入的数组中所有奇数都出现在偶数的前面); +2. 特殊输入测试(输入空指针;输入的数组只包含一个数字)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/21_ReorderArray/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/21_ReorderArray/Solution.java" new file mode 100755 index 00000000..5dbdd264 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/21_ReorderArray/Solution.java" @@ -0,0 +1,36 @@ +import java.util.Arrays; + +/** + * @author bingo + * @since 2018/11/21 + */ + +public class Solution { + /** + * 调整数组元素顺序,使得奇数元素位于偶数元素前面,且保证奇数和奇数,偶数和偶数之间的相对位置不变。 + * + * @param array 数组 + */ + public void reOrderArray(int[] array) { + if (array == null || array.length < 2) { + return; + } + + int numsOfOdd = 0; + for (int val : array) { + if (val % 2 == 1) { + ++numsOfOdd; + } + } + int[] bak = Arrays.copyOf(array, array.length); + int i = 0, j = numsOfOdd; + for (int val : bak) { + if (val % 2 == 1) { + array[i++] = val; + } else { + array[j++] = val; + } + } + } + +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/22_KthNodeFromEnd/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/22_KthNodeFromEnd/README.md" new file mode 100755 index 00000000..2e54c99e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/22_KthNodeFromEnd/README.md" @@ -0,0 +1,61 @@ +## 链表中倒数第k个结点 + +### 题目描述 +输入一个链表,输出该链表中倒数第k个结点。 + +### 解法 +pre 指针走 `k-1` 步。之后 cur 指针指向 phead,然后两个指针同时走,直至 pre 指针到达尾结点。 + +> 当用一个指针遍历链表不能解决问题的时候,可以尝试用两个指针来遍历链表。可以让其中一个指针遍历的速度快一些。 + +此题需要考虑一些特殊情况。比如 k 的值小于 0 或者大于链表长度。 + +```java +/** + * @author bingo + * @since 2018/11/21 + */ + +/* +public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +}*/ +public class Solution { + /** + * 找出链表倒数第k个节点,k从1开始 + * @param head 链表头部 + * @param k 第k个节点 + * @return 倒数第k个节点 + */ + public ListNode FindKthToTail(ListNode head,int k) { + if (head == null || k < 1) { + return null; + } + + ListNode pre = head; + for (int i = 0; i < k - 1; ++i) { + if (pre.next != null) { + pre = pre.next; + } else { + return null; + } + } + + ListNode cur = head; + while (pre.next != null) { + pre = pre.next; + cur = cur.next; + } + return cur; + } +} +``` + +### 测试用例 +1. 功能测试(第 k 个节点在链表的中间/头部/尾部); +2. 特殊输入测试(输入空指针;链表的节点总数小于 k;k=0)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/22_KthNodeFromEnd/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/22_KthNodeFromEnd/Solution.java" new file mode 100755 index 00000000..5652dffd --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/22_KthNodeFromEnd/Solution.java" @@ -0,0 +1,43 @@ +/** + * @author bingo + * @since 2018/11/21 + */ + +/* +public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +}*/ +public class Solution { + /** + * 找出链表倒数第k个节点,k从1开始 + * @param head 链表头部 + * @param k 第k个节点 + * @return 倒数第k个节点 + */ + public ListNode FindKthToTail(ListNode head,int k) { + if (head == null || k < 1) { + return null; + } + + ListNode pre = head; + for (int i = 0; i < k - 1; ++i) { + if (pre.next != null) { + pre = pre.next; + } else { + return null; + } + } + + ListNode cur = head; + while (pre.next != null) { + pre = pre.next; + cur = cur.next; + } + return cur; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/23_EntryNodeInListLoop/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/23_EntryNodeInListLoop/README.md" new file mode 100755 index 00000000..262cd9f5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/23_EntryNodeInListLoop/README.md" @@ -0,0 +1,83 @@ +## 链表中环的入口结点 + +### 题目描述 +给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出`null`。 + +### 解法 +- 先利用快慢指针。若能相遇,说明存在环,且相遇点一定是在环上;若没有相遇,说明不存在环,返回 `null`。 +- 固定当前相遇点,用一个指针继续走,同时累积结点数。计算出环的结点个数 `cnt`。 +- 指针 p1 先走 `cnt` 步,p2 指向链表头部,之后 `p1`,`p2` 同时走,相遇时,相遇点一定是在环的入口处。因为 `p1` 比 `p2` 多走了环的一圈。 + +```java + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* + public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +} +*/ +public class Solution { + + /** + * 求链表环的入口,若没有环,返回null + * @param pHead 链表头 + * @return 环的入口点 + */ + public ListNode EntryNodeOfLoop(ListNode pHead) { + if (pHead == null || pHead.next == null) { + return null; + } + ListNode fast = pHead; + ListNode slow = pHead; + boolean flag = false; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (fast == slow) { + flag = true; + break; + } + } + + // 快指针与慢指针没有相遇,说明无环,返回 null + if (!flag) { + return null; + } + + ListNode cur = slow.next; + // 求出环中结点个数 + int cnt = 1; + while (cur != slow) { + cur = cur.next; + ++cnt; + } + + // 指针p1先走cnt步 + ListNode p1 = pHead; + for (int i = 0; i < cnt; ++i) { + p1 = p1.next; + } + + // p2指向链表头,然后p1/p2同时走,首次相遇的地方就是环的入口 + ListNode p2 = pHead; + while (p1 != p2) { + p1 = p1.next; + p2 = p2.next; + } + return p1; + } +} +``` + +### 测试用例 +1. 功能测试(链表中包含/不包含环;链表中有多个或者只有一个节点); +2. 特殊输入测试(链表头节点为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/23_EntryNodeInListLoop/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/23_EntryNodeInListLoop/Solution.java" new file mode 100755 index 00000000..9411e67e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/23_EntryNodeInListLoop/Solution.java" @@ -0,0 +1,63 @@ + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* + * public class ListNode { int val; ListNode next = null; + * + * ListNode(int val) { this.val = val; } } + */ +public class Solution { + + /** + * 求链表环的入口,若没有环,返回null + * + * @param pHead 链表头 + * @return 环的入口点 + */ + public ListNode EntryNodeOfLoop(ListNode pHead) { + if (pHead == null || pHead.next == null) { + return null; + } + ListNode fast = pHead; + ListNode slow = pHead; + boolean flag = false; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (fast == slow) { + flag = true; + break; + } + } + + // 快指针与慢指针没有相遇,说明无环,返回 null + if (!flag) { + return null; + } + + ListNode cur = slow.next; + // 求出环中结点个数 + int cnt = 1; + while (cur != slow) { + cur = cur.next; + ++cnt; + } + + // 指针p1先走cnt步 + ListNode p1 = pHead; + for (int i = 0; i < cnt; ++i) { + p1 = p1.next; + } + + // p2指向链表头,然后p1/p2同时走,首次相遇的地方就是环的入口 + ListNode p2 = pHead; + while (p1 != p2) { + p1 = p1.next; + p2 = p2.next; + } + return p1; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/24_ReverseList/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/24_ReverseList/README.md" new file mode 100755 index 00000000..118d6587 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/24_ReverseList/README.md" @@ -0,0 +1,94 @@ +## 反转链表 + +### 题目描述 +输入一个链表,反转链表后,输出新链表的表头。 + +### 解法 +#### 解法一 +利用头插法解决。 + +```java + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* +public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +}*/ +public class Solution { + /** + * 反转链表 + * @param head 链表头部 + * @return 反转后的链表 + */ + public ListNode ReverseList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode dummy = new ListNode(-1); + dummy.next = null; + ListNode p1 = head; + ListNode p2 = p1.next; + while (p1 != null) { + p1.next = dummy.next; + dummy.next = p1; + p1 = p2; + if (p1 == null) { + break; + } + p2 = p1.next; + } + + return dummy.next; + } +} +``` + +#### 解法二:递归 + +```java +/** + * @author bingo + * @since 2018/11/22 + */ + + +/* +public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +}*/ +public class Solution { + public ListNode ReverseList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode next = ReverseList(head.next); + ListNode cur = next; + while (cur.next != null) { + cur = cur.next; + } + cur.next = head; + head.next = null; + return next; + } +} +``` + +### 测试用例 +1. 功能测试(链表中有多个结点/只有一个节点); +2. 特殊输入测试(链表头节点为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/24_ReverseList/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/24_ReverseList/Solution.java" new file mode 100755 index 00000000..d9a443b5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/24_ReverseList/Solution.java" @@ -0,0 +1,40 @@ + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* + * public class ListNode { int val; ListNode next = null; + * + * ListNode(int val) { this.val = val; } } + */ +public class Solution { + /** + * 反转链表 + * + * @param head 链表头部 + * @return 反转后的链表 + */ + public ListNode ReverseList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode dummy = new ListNode(-1); + dummy.next = null; + ListNode p1 = head; + ListNode p2 = p1.next; + while (p1 != null) { + p1.next = dummy.next; + dummy.next = p1; + p1 = p2; + if (p1 == null) { + break; + } + p2 = p1.next; + } + + return dummy.next; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/25_MergeSortedLists/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/25_MergeSortedLists/README.md" new file mode 100755 index 00000000..9bcc3c7b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/25_MergeSortedLists/README.md" @@ -0,0 +1,112 @@ +## 合并两个排序的链表 + +### 题目描述 +输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 + +### 解法 +#### 解法一 +同时遍历两链表进行 `merge`。 + +```java + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* +public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +}*/ +public class Solution { + /** + * 合并两个排序链表 + * @param list1 链表1 + * @param list2 链表2 + * @return 合并后的单调不递减链表 + */ + public ListNode Merge(ListNode list1, ListNode list2) { + if (list1 == null) { + return list2; + } + if (list2 == null) { + return list1; + } + + ListNode dummy = new ListNode(-1); + ListNode cur = dummy; + ListNode p1 = list1; + ListNode p2 = list2; + while (p1 != null && p2 != null) { + if (p1.val < p2.val) { + ListNode t = p1.next; + cur.next = p1; + p1.next = null; + p1 = t; + } else { + ListNode t = p2.next; + cur.next = p2; + p2.next = null; + p2 = t; + } + cur = cur.next; + } + + cur.next = p1 == null ? p2 : p1; + return dummy.next; + + } +} +``` + +#### 解法二:递归 +```java + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* +public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } +}*/ +public class Solution { + /** + * 合并两个排序链表 + * @param list1 链表1 + * @param list2 链表2 + * @return 合并后的单调不递减链表 + */ + public ListNode Merge(ListNode list1, ListNode list2) { + if (list1 == null) { + return list2; + } + if (list2 == null) { + return list1; + } + + if (list1.val < list2.val) { + list1.next = Merge(list1.next, list2); + return list1; + } + + list2.next = Merge(list1, list2.next); + return list2; + } +} +``` + +### 测试用例 +1. 功能测试(输入的两个链表有多个节点;节点的值互不相同或者存在值相等的多个节点); +2. 特殊输入测试(两个链表的一个或者两个头节点为空指针;两个链表中只有一个节点)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/25_MergeSortedLists/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/25_MergeSortedLists/Solution.java" new file mode 100755 index 00000000..368104d8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/25_MergeSortedLists/Solution.java" @@ -0,0 +1,51 @@ + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* + * public class ListNode { int val; ListNode next = null; + * + * ListNode(int val) { this.val = val; } } + */ +public class Solution { + /** + * 合并两个排序链表 + * + * @param list1 链表1 + * @param list2 链表2 + * @return 合并后的单调不递减链表 + */ + public ListNode Merge(ListNode list1, ListNode list2) { + if (list1 == null) { + return list2; + } + if (list2 == null) { + return list1; + } + + ListNode dummy = new ListNode(-1); + ListNode cur = dummy; + ListNode p1 = list1; + ListNode p2 = list2; + while (p1 != null && p2 != null) { + if (p1.val < p2.val) { + ListNode t = p1.next; + cur.next = p1; + p1.next = null; + p1 = t; + } else { + ListNode t = p2.next; + cur.next = p2; + p2.next = null; + p2 = t; + } + cur = cur.next; + } + + cur.next = p1 == null ? p2 : p1; + return dummy.next; + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/26_SubstructureInTree/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/26_SubstructureInTree/README.md" new file mode 100755 index 00000000..24b852e9 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/26_SubstructureInTree/README.md" @@ -0,0 +1,69 @@ +## 树的子结构 + +### 题目描述 +输入两棵二叉树`A`,`B`,判断`B`是不是`A`的子结构。(ps:我们约定空树不是任意一个树的子结构) + +### 解法 +递归方式遍历: + +- 在树A中找到和树B的根结点值一样的结点R +- 判断树A以R为根结点的子树是否包含与树B一样的结构 + +这道题的time complexity应该为O(n * m),其中n为root1的节点数,m为root2的节点数。 + +```java +/** +public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } +} +*/ + +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/01 + * @description + */ +public class Solution { + + public boolean HasSubtree(TreeNode root1, TreeNode root2) { + + if (root1 == null || root2 == null) { + return false; + } + + return isSame(root1, root2) || + HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); + } + + private boolean isSame(TreeNode root1, TreeNode root2) { + + if (root2 == null) { + return true; + } + + // 在root2,root1遍历完成后,仍未找到符合的结构,返回false + if (root1 == null) { + return false; + } + + if (root1.val != root2.val) { + return false; + } + + return isSame(root1.left, root2.left) && isSame(root1.right, root2.right); + } + +} +``` + +### 测试用例 +1. 功能测试(树A和树B都是普通的二叉树;树B是/不是树A的子结构); +2. 特殊输入测试(两棵二叉树的一个或者两个根结点为空指针,二叉树的所有结点都没有左/右子树)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/26_SubstructureInTree/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/26_SubstructureInTree/Solution.java" new file mode 100755 index 00000000..aa2015ff --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/26_SubstructureInTree/Solution.java" @@ -0,0 +1,51 @@ + +/** +public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } +} +*/ + +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/01 + * @description + */ +public class Solution { + + public boolean HasSubtree(TreeNode root1, TreeNode root2) { + + if (root1 == null || root2 == null) { + return false; + } + + return isSame(root1, root2) || + HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); + } + + private boolean isSame(TreeNode root1, TreeNode root2) { + + if (root2 == null) { + return true; + } + + // 在root2,root1遍历完成后,仍未找到符合的结构,返回false + if (root1 == null) { + return false; + } + + if (root1.val != root2.val) { + return false; + } + + return isSame(root1.left, root2.left) && isSame(root1.right, root2.right); + } + +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/27_MirrorOfBinaryTree/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/27_MirrorOfBinaryTree/README.md" new file mode 100755 index 00000000..8e036d5c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/27_MirrorOfBinaryTree/README.md" @@ -0,0 +1,70 @@ +## 二叉树的镜像 + +### 题目描述 +操作给定的二叉树,将其变换为源二叉树的镜像。 + +``` +源二叉树 + 8 + / \ + 6 10 + / \ / \ + 5 7 9 11 + +镜像二叉树 + 8 + / \ + 10 6 + / \ / \ + 11 9 7 5 +``` + +### 解法 +将根结点的左右孩子互换,之后递归左右孩子。 + +```java + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* + public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + + } + */ +public class Solution { + /** + * 将二叉树转换为它的镜像 + * @param root 二叉树的根结点 + */ + public void Mirror(TreeNode root) { + if (root == null || !hasChild(root)) { + return; + } + + TreeNode t = root.left; + root.left = root.right; + root.right = t; + Mirror(root.left); + Mirror(root.right); + } + + private boolean hasChild(TreeNode root) { + return root.left != null || root.right != null; + } +} +``` + +### 测试用例 +1. 功能测试(普通的二叉树;二叉树的所有结点都没有左/右子树;只有一个结点的二叉树); +2. 特殊输入测试(二叉树的根结点为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/27_MirrorOfBinaryTree/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/27_MirrorOfBinaryTree/Solution.java" new file mode 100755 index 00000000..4d9ae2fe --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/27_MirrorOfBinaryTree/Solution.java" @@ -0,0 +1,38 @@ + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* + * public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = + * null; + * + * public TreeNode(int val) { this.val = val; + * + * } + * + * } + */ +public class Solution { + /** + * 将二叉树转换为它的镜像 + * + * @param root 二叉树的根结点 + */ + public void Mirror(TreeNode root) { + if (root == null || !hasChild(root)) { + return; + } + + TreeNode t = root.left; + root.left = root.right; + root.right = t; + Mirror(root.left); + Mirror(root.right); + } + + private boolean hasChild(TreeNode root) { + return root.left != null || root.right != null; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/28_SymmetricalBinaryTree/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/28_SymmetricalBinaryTree/README.md" new file mode 100755 index 00000000..6b13edef --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/28_SymmetricalBinaryTree/README.md" @@ -0,0 +1,58 @@ +## 对称的二叉树 + +### 题目描述 +请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。 + +### 解法 +比较二叉树的前序遍历序列和对称前序遍历序列是否一样,若是,说明是对称的。 + +```java + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* +public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + +} +*/ +public class Solution { + /** + * 判断是否是对称二叉树 + * @param pRoot 二叉树的根结点 + * @return 是否为对称二叉树 + */ + boolean isSymmetrical(TreeNode pRoot) { + return isSymmetrical(pRoot, pRoot); + } + + private boolean isSymmetrical(TreeNode pRoot1, TreeNode pRoot2) { + if (pRoot1 == null && pRoot2 == null) { + return true; + } + if (pRoot1 == null || pRoot2 == null) { + return false; + } + if (pRoot1.val != pRoot2.val) { + return false; + } + + return isSymmetrical(pRoot1.left, pRoot2.right) && isSymmetrical(pRoot1.right, pRoot2.left); + + } +} +``` + +### 测试用例 +1. 功能测试(对称的二叉树;因结构而不对称的二叉树;结构对称但节点的值不对称的二叉树); +2. 特殊输入测试(二叉树的根结点为空指针;只有一个节点的二叉树;所有节点的值都相同的二叉树)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/28_SymmetricalBinaryTree/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/28_SymmetricalBinaryTree/Solution.java" new file mode 100755 index 00000000..af731b18 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/28_SymmetricalBinaryTree/Solution.java" @@ -0,0 +1,42 @@ + +/** + * @author bingo + * @since 2018/11/22 + */ + +/* + * public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = + * null; + * + * public TreeNode(int val) { this.val = val; + * + * } + * + * } + */ +public class Solution { + /** + * 判断是否是对称二叉树 + * + * @param pRoot 二叉树的根结点 + * @return 是否为对称二叉树 + */ + boolean isSymmetrical(TreeNode pRoot) { + return isSymmetrical(pRoot, pRoot); + } + + private boolean isSymmetrical(TreeNode pRoot1, TreeNode pRoot2) { + if (pRoot1 == null && pRoot2 == null) { + return true; + } + if (pRoot1 == null || pRoot2 == null) { + return false; + } + if (pRoot1.val != pRoot2.val) { + return false; + } + + return isSymmetrical(pRoot1.left, pRoot2.right) && isSymmetrical(pRoot1.right, pRoot2.left); + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/29_PrintMatrix/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/29_PrintMatrix/README.md" new file mode 100755 index 00000000..e47e18c8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/29_PrintMatrix/README.md" @@ -0,0 +1,103 @@ +## 顺时针打印矩阵 + +### 题目描述 +输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下 `4 X 4` 矩阵: +``` +1 2 3 4 +5 6 7 8 +9 10 11 12 +13 14 15 16 +``` + +则依次打印出数字: +``` +1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10. +``` +### 解法 +剑指offer上的思路有点复杂,需要考虑坐标变换太多,考虑用另一种思路来解决。 + +在矩阵中,使用左上角坐标(tR,tC)和右下角的坐标(dR,dC)就可以表示一个矩阵。比如题目中的矩阵,当(tR,tC) = (0,0)和(dR,dC) = (3,3)时,表示的子矩阵就是整个矩阵: + +```java +1 2 3 4 +5 8 +9 12 +13 14 15 16 +``` + +当外层循环遍历后,可以令tR和tC加1,dR和dC减1,执行内层循环。当左上角的坐标跑到右下角坐标的右方或者下方,则整个过程就终止。 + +```java +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/2 + */ +public class Solution { + /** + * 转圈打印矩阵 + * @param matrix 矩阵 + * @return 存放结果的list + */ + public ArrayList printMatrix(int[][] matrix) { + ArrayList reList = new ArrayList<>(); + if (matrix == null) { + return reList; + } + + int tR = 0; + int tC = 0; + int dR = matrix.length - 1; + int dC = matrix[0].length - 1; + + while (tR <= dR && tC <= dC) { + printMatrix(matrix, tR++, tC++, dR--, dC--, reList); + } + + return reList; + } + + public void printMatrix(int[][] matrix, int tR, int tC, int dR, int dC, ArrayList reList) { + // 只有一行 + if (tR == dR) { + for (int i = tC; i <= dC; i++) { + reList.add(matrix[tR][i]); + } + } + // 只有一列 + else if (tC == dC) { + for (int i = tR; i <= dR; i++) { + reList.add(matrix[i][tC]); + } + } else { + int curR = tR; + int curC = tC; + // 从左到右 + while (curC != dC) { + reList.add(matrix[tR][curC]); + curC++; + } + // 从上到下 + while (curR != dR) { + reList.add(matrix[curR][dC]); + curR++; + } + // 从右到左 + while (curC != tC) { + reList.add(matrix[dR][curC]); + curC--; + } + // 从下到上 + while (curR != tR) { + reList.add(matrix[curR][tC]); + curR--; + } + } + + } +} +``` + +### 测试用例 +1. 数组中有多行多列;数组中只有一行;数组中只有一列;数组中只有一行一列。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/29_PrintMatrix/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/29_PrintMatrix/Solution.java" new file mode 100755 index 00000000..07d58d49 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/29_PrintMatrix/Solution.java" @@ -0,0 +1,69 @@ +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/2 + */ +public class Solution { + /** + * 转圈打印矩阵 + * @param matrix 矩阵 + * @return 存放结果的list + */ + public ArrayList printMatrix(int[][] matrix) { + ArrayList reList = new ArrayList<>(); + if (matrix == null) { + return reList; + } + + int tR = 0; + int tC = 0; + int dR = matrix.length - 1; + int dC = matrix[0].length - 1; + + while (tR <= dR && tC <= dC) { + printMatrix(matrix, tR++, tC++, dR--, dC--, reList); + } + + return reList; + } + + public void printMatrix(int[][] matrix, int tR, int tC, int dR, int dC, ArrayList reList) { + // 只有一行 + if (tR == dR) { + for (int i = tC; i <= dC; i++) { + reList.add(matrix[tR][i]); + } + } + // 只有一列 + else if (tC == dC) { + for (int i = tR; i <= dR; i++) { + reList.add(matrix[i][tC]); + } + } else { + int curR = tR; + int curC = tC; + // 从左到右 + while (curC != dC) { + reList.add(matrix[tR][curC]); + curC++; + } + // 从上到下 + while (curR != dR) { + reList.add(matrix[curR][dC]); + curR++; + } + // 从右到左 + while (curC != tC) { + reList.add(matrix[dR][curC]); + curC--; + } + // 从下到上 + while (curR != tR) { + reList.add(matrix[curR][tC]); + curR--; + } + } + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/30_MinInStack/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/30_MinInStack/README.md" new file mode 100755 index 00000000..38353b27 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/30_MinInStack/README.md" @@ -0,0 +1,63 @@ +## 包含min函数的栈 + +### 题目描述 +定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为`O(1)`)。 + +### 解法 +定义两个`stack`。 + +压栈时,先将元素`node`压入`stack1`。然后判断`stack2`的情况: +- `stack2`栈为空或者栈顶元素大于`node`,则将`node`压入`stack2`中。 +- `stack2`栈不为空且栈定元素小于`node`,则重复压入栈顶元素。 + +获取最小元素时,从`stack2`中获取栈顶元素即可。 + +```java +import java.util.Stack; + +/** + * @author bingo + * @since 2018/11/22 + */ + + +public class Solution { + + private Stack stack1 = new Stack<>(); + private Stack stack2 = new Stack<>(); + + /** + * 压栈 + * @param node 待压入的元素 + */ + public void push(int node) { + stack1.push(node); + if (stack2.isEmpty() || stack2.peek() >= node) { + stack2.push(node); + } else { + stack2.push(stack2.peek()); + } + } + + public void pop() { + stack1.pop(); + stack2.pop(); + } + + public int top() { + return stack2.peek(); + } + + /** + * O(1)获取栈中最小值 + * @return 最小值 + */ + public int min() { + return stack2.peek(); + } +} +``` + +### 测试用例 +1. 新压入栈的数字比之前的最小值大/小。 +2. 弹出栈的数字是/不是最小元素。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/30_MinInStack/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/30_MinInStack/Solution.java" new file mode 100755 index 00000000..a1bde5c4 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/30_MinInStack/Solution.java" @@ -0,0 +1,44 @@ +import java.util.Stack; + +/** + * @author bingo + * @since 2018/11/22 + */ + +public class Solution { + + private Stack stack1 = new Stack<>(); + private Stack stack2 = new Stack<>(); + + /** + * 压栈 + * + * @param node 待压入的元素 + */ + public void push(int node) { + stack1.push(node); + if (stack2.isEmpty() || stack2.peek() >= node) { + stack2.push(node); + } else { + stack2.push(stack2.peek()); + } + } + + public void pop() { + stack1.pop(); + stack2.pop(); + } + + public int top() { + return stack2.peek(); + } + + /** + * O(1)获取栈中最小值 + * + * @return 最小值 + */ + public int min() { + return stack2.peek(); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/31_StackPushPopOrder/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/31_StackPushPopOrder/README.md" new file mode 100755 index 00000000..3b2a5e59 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/31_StackPushPopOrder/README.md" @@ -0,0 +1,58 @@ +## 栈的压入、弹出序列 + +### 题目描述 +输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列`1,2,3,4,5`是某栈的压入顺序,序列`4,5,3,2,1`是该压栈序列对应的一个弹出序列,但`4,3,5,1,2`就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) + +### 解法 +判断下一个要弹出的元素: +- 如果刚好是栈顶元素,直接弹出。 +- 如果不在栈顶,则把压栈序列中还没有入栈的数字压入栈,直到待弹出的数字压入栈顶。 +- 如果所有数字都压入栈顶后依然没有后找到下一个弹出的数字,则不可能是弹出序列。 + +```java +import java.util.Stack; + +/** + * @author bingo + * @since 2018/11/22 + */ + + +public class Solution { + /** + * 判断是否是弹出序列 + * @param pushA 压栈序列 + * @param popA 弹栈序列 + * @return 是否是弹出序列 + */ + public boolean IsPopOrder(int[] pushA,int[] popA) { + if (pushA == null || popA == null || pushA.length != popA.length) { + return false; + } + + Stack stack = new Stack<>(); + int i = 0; + int n = pushA.length; + boolean flag = false; + for (int val : popA) { + while (stack.isEmpty() || stack.peek() != val) { + if (i >= n) { + flag = true; + break; + } + stack.push(pushA[i++]); + } + if (flag) { + break; + } + stack.pop(); + } + + return stack.isEmpty(); + } +} +``` + +### 测试用例 +1. 功能测试(输入的两个数组含有多个数字或者只有一个数字:第二个数组是/不是第一个数组表示的压入序列对应的栈的弹出序列); +2. 特殊输入测试(输入两个空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/31_StackPushPopOrder/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/31_StackPushPopOrder/Solution.java" new file mode 100755 index 00000000..07e99a63 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/31_StackPushPopOrder/Solution.java" @@ -0,0 +1,42 @@ +import java.util.Stack; + +/** + * @author bingo + * @since 2018/11/22 + */ + + +public class Solution { + /** + * 判断是否是弹出序列 + * + * @param pushA 压栈序列 + * @param popA 弹栈序列 + * @return 是否是弹出序列 + */ + public boolean IsPopOrder(int[] pushA,int[] popA) { + if (pushA == null || popA == null || pushA.length != popA.length) { + return false; + } + + Stack stack = new Stack<>(); + int i = 0; + int n = pushA.length; + boolean flag = false; + for (int val : popA) { + while (stack.isEmpty() || stack.peek() != val) { + if (i >= n) { + flag = true; + break; + } + stack.push(pushA[i++]); + } + if (flag) { + break; + } + stack.pop(); + } + + return stack.isEmpty(); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_01_PrintTreeFromTopToBottom/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_01_PrintTreeFromTopToBottom/README.md" new file mode 100755 index 00000000..c93a997e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_01_PrintTreeFromTopToBottom/README.md" @@ -0,0 +1,64 @@ +## 不分行从上到下打印二叉树 + +### 题目描述 +从上往下打印出二叉树的每个节点,同层节点从左至右打印。 + +### 解法 +先将根节点进入队列。 + +队头元素出队,将值存入 list,判断该元素是否有左/右子树,有的话依次进入队列中。队列为空时结束。 + +```java +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author bingo + * @since 2018/11/23 + */ + +/** + public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + + } + */ +public class Solution { + /** + * 从上到下打印二叉树 + * @param root 二叉树根节点 + * @return 结果list + */ + public ArrayList PrintFromTopToBottom(TreeNode root) { + ArrayList list = new ArrayList<>(); + if (root == null) { + return list; + } + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + list.add(node.val); + } + return list; + } +} +``` + +### 测试用例 +1. 功能测试(完全二叉树;所有节点只有左/右子树); +2. 特殊输入测试(二叉树根节点为空指针;只有一个节点的二叉树)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_01_PrintTreeFromTopToBottom/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_01_PrintTreeFromTopToBottom/Solution.java" new file mode 100755 index 00000000..7489a0f8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_01_PrintTreeFromTopToBottom/Solution.java" @@ -0,0 +1,46 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author bingo + * @since 2018/11/23 + */ + +/** + * public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = + * null; + * + * public TreeNode(int val) { this.val = val; + * + * } + * + * } + */ +public class Solution { + /** + * 从上到下打印二叉树 + * + * @param root 二叉树根节点 + * @return 结果list + */ + public ArrayList PrintFromTopToBottom(TreeNode root) { + ArrayList list = new ArrayList<>(); + if (root == null) { + return list; + } + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + list.add(node.val); + } + return list; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_02_PrintTreesInLines/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_02_PrintTreesInLines/README.md" new file mode 100755 index 00000000..4904948f --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_02_PrintTreesInLines/README.md" @@ -0,0 +1,73 @@ +## 把二叉树打印成多行 + +### 题目描述 +从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。 + +### 解法 +与上一题类似,只不过需要用变量记录每一层要打印多少个节点。 + +```java +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author bingo + * @since 2018/11/23 + */ + +/* +public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + +} +*/ +public class Solution { + /** + * 把二叉树打印成多行 + * @param pRoot 二叉树根节点 + * @return 结果list + */ + ArrayList > Print(TreeNode pRoot) { + ArrayList> list = new ArrayList<>(); + if (pRoot == null) { + return list; + } + + Queue queue = new LinkedList<>(); + queue.offer(pRoot); + int cnt = 1; + while (cnt > 0) { + int num = cnt; + cnt = 0; + ArrayList res = new ArrayList<>(); + for (int i = 0; i < num; ++i) { + TreeNode node = queue.poll(); + if (node.left != null) { + queue.offer(node.left); + ++cnt; + } + if (node.right != null) { + queue.offer(node.right); + ++cnt; + } + res.add(node.val); + } + list.add(res); + } + return list; + } + +} +``` + +### 测试用例 +1. 功能测试(完全二叉树;所有节点只有左/右子树); +2. 特殊输入测试(二叉树根节点为空指针;只有一个节点的二叉树)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_02_PrintTreesInLines/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_02_PrintTreesInLines/Solution.java" new file mode 100755 index 00000000..359fc888 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_02_PrintTreesInLines/Solution.java" @@ -0,0 +1,57 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author bingo + * @since 2018/11/23 + */ + +/* + * public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = + * null; + * + * public TreeNode(int val) { this.val = val; + * + * } + * + * } + */ +public class Solution { + /** + * 把二叉树打印成多行 + * + * @param pRoot 二叉树根节点 + * @return 结果list + */ + ArrayList> Print(TreeNode pRoot) { + ArrayList> list = new ArrayList<>(); + if (pRoot == null) { + return list; + } + + Queue queue = new LinkedList<>(); + queue.offer(pRoot); + int cnt = 1; + while (cnt > 0) { + int num = cnt; + cnt = 0; + ArrayList res = new ArrayList<>(); + for (int i = 0; i < num; ++i) { + TreeNode node = queue.poll(); + if (node.left != null) { + queue.offer(node.left); + ++cnt; + } + if (node.right != null) { + queue.offer(node.right); + ++cnt; + } + res.add(node.val); + } + list.add(res); + } + return list; + } + +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_03_PrintTreesInZigzag/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_03_PrintTreesInZigzag/README.md" new file mode 100755 index 00000000..538f10c0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_03_PrintTreesInZigzag/README.md" @@ -0,0 +1,104 @@ +## 按之字形打印二叉树 + +### 题目描述 +请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。 + +如二叉树: +``` + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 +``` + +打印结果为: +``` +1 +3 2 +4 5 6 7 +``` + +### 解法 +对于上述二叉树: + +首先访问根结点,之后把2、3存入某结构。打印的时候,先打印3、2。这不就是栈? + +依次弹出栈元素,分别是3、2。弹出时需要把3、2的子结点存入结构。由于访问时顺序是`4 5 6 7`。所以也需要用栈来存放。而且,此时需要先存放右孩子,再存放左孩子。(奇数层/偶数层存放左右孩子的顺序不同) + +这里需要用两个栈来实现。如果只用一个栈,那么当弹出3、2 时,先将 3 的孩子节点压入栈。之后弹栈的时候不是先弹出 2,而是弹出了 3 的 孩子节点,就错了。 + + +```java +import java.util.ArrayList; +import java.util.Stack; + +/** + * @author bingo + * @since 2018/11/23 + */ + +/* +public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + +} +*/ +public class Solution { + /** + * 按之字形打印二叉树 + * @param pRoot 二叉树的根节点 + * @return 结果list + */ + public ArrayList> Print(TreeNode pRoot) { + ArrayList> res = new ArrayList<>(); + if (pRoot == null) { + return res; + } + Stack stack1 = new Stack<>(); + Stack stack2 = new Stack<>(); + stack1.push(pRoot); + int i = 1; + Stack stack = stack1; + while (!stack.isEmpty()) { + ArrayList list = new ArrayList<>(); + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + list.add(node.val); + if (i % 2 == 1) { + if (node.left != null) { + stack2.push(node.left); + } + if (node.right != null) { + stack2.push(node.right); + } + } else { + if (node.right != null) { + stack1.push(node.right); + } + if (node.left != null) { + stack1.push(node.left); + } + } + } + res.add(list); + ++i; + stack = stack1.isEmpty() ? stack2 : stack1; + } + + return res; + } + +} +``` + +### 测试用例 +1. 功能测试(完全二叉树;所有节点只有左/右子树); +2. 特殊输入测试(二叉树根节点为空指针;只有一个节点的二叉树)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_03_PrintTreesInZigzag/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_03_PrintTreesInZigzag/Solution.java" new file mode 100755 index 00000000..5585b4bf --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/32_03_PrintTreesInZigzag/Solution.java" @@ -0,0 +1,65 @@ +import java.util.ArrayList; +import java.util.Stack; + +/** + * @author bingo + * @since 2018/11/23 + */ + +/* + * public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = + * null; + * + * public TreeNode(int val) { this.val = val; + * + * } + * + * } + */ +public class Solution { + /** + * 按之字形打印二叉树 + * + * @param pRoot 二叉树的根节点 + * @return 结果list + */ + public ArrayList> Print(TreeNode pRoot) { + ArrayList> res = new ArrayList<>(); + if (pRoot == null) { + return res; + } + Stack stack1 = new Stack<>(); + Stack stack2 = new Stack<>(); + stack1.push(pRoot); + int i = 1; + Stack stack = stack1; + while (!stack.isEmpty()) { + ArrayList list = new ArrayList<>(); + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + list.add(node.val); + if (i % 2 == 1) { + if (node.left != null) { + stack2.push(node.left); + } + if (node.right != null) { + stack2.push(node.right); + } + } else { + if (node.right != null) { + stack1.push(node.right); + } + if (node.left != null) { + stack1.push(node.left); + } + } + } + res.add(list); + ++i; + stack = stack1.isEmpty() ? stack2 : stack1; + } + + return res; + } + +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/33_SquenceOfBST/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/33_SquenceOfBST/README.md" new file mode 100755 index 00000000..4d99624f --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/33_SquenceOfBST/README.md" @@ -0,0 +1,60 @@ +## 二叉搜索树的后序遍历序列 + +### 题目描述 +输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出`Yes`,否则输出`No`。假设输入的数组的任意两个数字都互不相同。 + +### 解法 +序列的最后一个元素是二叉搜索树的根节点。 + +在序列中从左到右找到根节点的左子树(比根节点小)、右子树(比根节点大)。 +- 如果右子树中出现比根节点小的元素,那么为 false。 +- 否则递归左右子树。 + + +```java +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 判断数组是否是某个二叉搜索树的后序遍历序列 + * + * @param sequence 数组 + * @return 是否属于某二叉搜索树的后序遍历序列 + */ + public boolean VerifySquenceOfBST(int[] sequence) { + if (sequence == null || sequence.length < 1) { + return false; + } + return verify(sequence, 0, sequence.length - 1); + } + + private boolean verify(int[] sequence, int start, int end) { + if (start >= end) { + return true; + } + int val = sequence[end]; + int i = start; + for (; i <= end; ++i) { + if (sequence[i] >= val) { + break; + } + } + + for (int j = i; j < end; ++j) { + if (sequence[j] < val) { + return false; + } + } + + return verify(sequence, start, i - 1) && verify(sequence, i, end - 1); + + } +} +``` + +### 测试用例 +1. 功能测试(输入的后序遍历序列对应一棵二叉树,包括完全二叉树、所有节点都没有左/右子树的二叉树、只有一个节点的二叉树;输入的后续遍历序列没有对应一棵二叉树); +2. 特殊输入测试(后序遍历序列为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/33_SquenceOfBST/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/33_SquenceOfBST/Solution.java" new file mode 100755 index 00000000..ef5610ba --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/33_SquenceOfBST/Solution.java" @@ -0,0 +1,41 @@ +/** + * @author bingo + * @since 2018/11/23 + */ + +public class Solution { + /** + * 判断数组是否是某个二叉搜索树的后序遍历序列 + * + * @param sequence 数组 + * @return 是否属于某二叉搜索树的后序遍历序列 + */ + public boolean VerifySquenceOfBST(int[] sequence) { + if (sequence == null || sequence.length < 1) { + return false; + } + return verify(sequence, 0, sequence.length - 1); + } + + private boolean verify(int[] sequence, int start, int end) { + if (start >= end) { + return true; + } + int val = sequence[end]; + int i = start; + for (; i <= end; ++i) { + if (sequence[i] >= val) { + break; + } + } + + for (int j = i; j < end; ++j) { + if (sequence[j] < val) { + return false; + } + } + + return verify(sequence, start, i - 1) && verify(sequence, i, end - 1); + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/34_PathInTree/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/34_PathInTree/README.md" new file mode 100755 index 00000000..d4dfc62a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/34_PathInTree/README.md" @@ -0,0 +1,64 @@ +## 二叉树中和为某一值的路径 + +### 题目描述 +输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的`list`中,数组长度大的数组靠前) + +### 解法 + +```java +import java.util.ArrayList; + +/** + * @author bingo + * @since 2018/11/23 + */ + +/** + public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + + } + */ +public class Solution { + + private ArrayList> res = new ArrayList<>(); + + /** + * 找出二叉树中和为某一值的路径(必须从根节点到叶节点) + * + * @param root 二叉树的根结点 + * @param target 目标值 + * @return 结果list + */ + public ArrayList> FindPath(TreeNode root, int target) { + findPath(root, target, new ArrayList<>()); + return res; + } + + private void findPath(TreeNode root, int target, ArrayList list) { + if (root == null) { + return; + } + list.add(root.val); + target -= root.val; + if (target == 0 && root.left == null && root.right == null) { + res.add(new ArrayList<>(list)); + } else { + findPath(root.left, target, list); + findPath(root.right, target, list); + } + list.remove(list.size() - 1); + } +} +``` + +### 测试用例 +1. 功能测试(二叉树中有一条、多条符合要求的路径;二叉树中没有符合要求的路径); +2. 特殊输入测试(指向二叉树根节点的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/34_PathInTree/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/34_PathInTree/Solution.java" new file mode 100755 index 00000000..65b209a1 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/34_PathInTree/Solution.java" @@ -0,0 +1,48 @@ +import java.util.ArrayList; + +/** + * @author bingo + * @since 2018/11/23 + */ + +/** + * public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = + * null; + * + * public TreeNode(int val) { this.val = val; + * + * } + * + * } + */ +public class Solution { + + private ArrayList> res = new ArrayList<>(); + + /** + * 找出二叉树中和为某一值的路径(必须从根节点到叶节点) + * + * @param root 二叉树的根结点 + * @param target 目标值 + * @return 结果list + */ + public ArrayList> FindPath(TreeNode root, int target) { + findPath(root, target, new ArrayList<>()); + return res; + } + + private void findPath(TreeNode root, int target, ArrayList list) { + if (root == null) { + return; + } + list.add(root.val); + target -= root.val; + if (target == 0 && root.left == null && root.right == null) { + res.add(new ArrayList<>(list)); + } else { + findPath(root.left, target, list); + findPath(root.right, target, list); + } + list.remove(list.size() - 1); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/35_CopyComplexList/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/35_CopyComplexList/README.md" new file mode 100755 index 00000000..762e595c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/35_CopyComplexList/README.md" @@ -0,0 +1,73 @@ +## 复杂链表的复制 + +### 题目描述 +输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的 `head`。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) + +### 解法 +可以分为3步: + +1. 复制每个节点,并插入到被复制节点的后面。比如1->2->3 clone 1->1->2->2->3->3 +2. 复制随机节点。当遍历到的当前节点存在随机节点时,则其复制节点也应该存在随机节点。比如当前节点`cur.random != null`,则`RandomListNode clone = cur.next;clone.random = cur.random.next;` +3. 分离两个链表。其中奇数链表为原链表,偶数链表为复制的链表 + +这道题的time complexity为O(n)。 + +```java +/** + * @author bingo + * @since 2018/11/24 + */ + +/* +public class RandomListNode { + int label; + RandomListNode next = null; + RandomListNode random = null; + + RandomListNode(int label) { + this.label = label; + } +} +*/ +public class Solution { + /** + * 复杂链表的复制 + * @param pHead 链表头结点 + * @return 复制的链表 + */ + public RandomListNode Clone(RandomListNode pHead) { + if (pHead == null) { + return null; + } + RandomListNode cur = pHead; + while (cur != null) { + RandomListNode node = new RandomListNode(cur.label); + node.next = cur.next; + cur.next = node; + cur = node.next; + } + + cur = pHead; + while (cur != null) { + RandomListNode clone = cur.next; + if (cur.random != null) { + clone.random = cur.random.next; + } + cur = clone.next; + } + + cur = pHead; + RandomListNode cloneHead = pHead.next; + while (cur.next != null) { + RandomListNode clone = cur.next; + cur.next = clone.next; + cur = clone; + } + return cloneHead; + } +} +``` + +### 测试用例 +1. 功能测试(结点中的 random 指针指向结点自身;两个结点的 random 形成环状结构;链表中只有一个结点); +2. 特殊输入测试(指向链表头结点的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/35_CopyComplexList/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/35_CopyComplexList/Solution.java" new file mode 100755 index 00000000..7f83a2e5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/35_CopyComplexList/Solution.java" @@ -0,0 +1,54 @@ +/** + * @author bingo + * @since 2018/11/24 + */ + +/* +public class RandomListNode { + int label; + RandomListNode next = null; + RandomListNode random = null; + + RandomListNode(int label) { + this.label = label; + } +} +*/ +public class Solution { + /** + * 复杂链表的复制 + * + * @param pHead 链表头结点 + * @return 复制的链表 + */ + public RandomListNode Clone(RandomListNode pHead) { + if (pHead == null) { + return null; + } + RandomListNode cur = pHead; + while (cur != null) { + RandomListNode node = new RandomListNode(cur.label); + node.next = cur.next; + cur.next = node; + cur = node.next; + } + + cur = pHead; + while (cur != null) { + RandomListNode clone = cur.next; + if (cur.random != null) { + clone.random = cur.random.next; + } + cur = clone.next; + } + + cur = pHead; + RandomListNode cloneHead = pHead.next; + while (cur.next != null) { + RandomListNode clone = cur.next; + cur.next = clone.next; + cur = clone; + } + return cloneHead; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/36_ConvertBinarySearchTree/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/36_ConvertBinarySearchTree/README.md" new file mode 100755 index 00000000..d80076e2 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/36_ConvertBinarySearchTree/README.md" @@ -0,0 +1,76 @@ +## 二叉搜索树与双向链表 + +### 题目描述 +输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 + +### 解法 +由于是二叉搜索树,因此中序遍历的结果就是排序的。 + +中序遍历利用栈来实现。遍历时,前一个结点的 right 指向后一个结点,后一个结点的 left 指向前一个结点。 +```java +pre.right = cur +cur.left = pre +``` + +```java +import java.util.Stack; + +/** + * @author bingo + * @since 2018/11/24 + */ + +/** + public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + + } + */ +public class Solution { + /** + * 将二叉搜索树转换为双向链表 + * + * @param pRootOfTree + * @return + */ + public TreeNode Convert(TreeNode pRootOfTree) { + if (pRootOfTree == null) { + return null; + } + Stack stack = new Stack<>(); + TreeNode cur = pRootOfTree; + TreeNode res = null; + TreeNode pre = null; + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + stack.push(cur); + cur = cur.left; + } else { + cur = stack.pop(); + if (pre == null) { + pre = cur; + res = pre; + } else { + pre.right = cur; + cur.left = pre; + pre = cur; + } + cur = cur.right; + + } + } + return res; + } +} +``` + +### 测试用例 +1. 功能测试(输入的二叉树是完全二叉树;所有结点都没有左/右子树;只有一个结点的二叉树); +2. 特殊输入测试(指向二叉树根结点的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/36_ConvertBinarySearchTree/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/36_ConvertBinarySearchTree/Solution.java" new file mode 100755 index 00000000..805756a3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/36_ConvertBinarySearchTree/Solution.java" @@ -0,0 +1,56 @@ +import java.util.Stack; + +/** + * @author bingo + * @since 2018/11/24 + */ + +/** + public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + + } + */ +public class Solution { + /** + * 将二叉搜索树转换为双向链表 + * + * @param pRootOfTree + * @return + */ + public TreeNode Convert(TreeNode pRootOfTree) { + if (pRootOfTree == null) { + return null; + } + Stack stack = new Stack<>(); + TreeNode cur = pRootOfTree; + TreeNode res = null; + TreeNode pre = null; + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + stack.push(cur); + cur = cur.left; + } else { + cur = stack.pop(); + if (pre == null) { + pre = cur; + res = pre; + } else { + pre.right = cur; + cur.left = pre; + pre = cur; + } + cur = cur.right; + + } + } + return res; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/37_SerializeBinaryTrees/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/37_SerializeBinaryTrees/README.md" new file mode 100755 index 00000000..e9795c2f --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/37_SerializeBinaryTrees/README.md" @@ -0,0 +1,89 @@ +## 序列化二叉树 + +### 题目描述 +请实现两个函数,分别用来序列化和反序列化二叉树。使用前序遍历实现,空节点使用字符`#` 表示。 + +比如有如下二叉树: + +```java + 1 + 2 3 + 4 # 5 6 + # # # # # # +``` + +序列化的结果为 `1,2,4,#,#,#,3,5,#,#,6,#,#` + +反序列化的结果为上述二叉树 + +### 解法 +使用前序遍历进行序列化和反序列化。对格式没有要求,只要序列化得到的结果,再反序列化后能与原树相同即可。 +```java +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/12 + */ +public class Solution { + + + public String Serialize(TreeNode root) { + + StringBuilder res = new StringBuilder(); + if (root == null) { + return res.toString(); + } + + serializeHelper(root, res); + // 移除最后一个的符号"," + res.deleteCharAt(res.lastIndexOf(",")); + return res.toString(); + } + + private void serializeHelper(TreeNode root, StringBuilder res) { + + if (root == null) { + res.append("#"); + res.append(","); + return; + } + + res.append(root.val); + res.append(","); + serializeHelper(root.left, res); + serializeHelper(root.right, res); + } + + private int index = -1; + + public TreeNode Deserialize(String str) { + + if (str == null || str.length() == 0) { + return null; + } + + String[] treeNodeStr = str.split(","); + return deserializeHelper(treeNodeStr); + } + + private TreeNode deserializeHelper(String[] treeNodeStr) { + + index++; + TreeNode node = null; + + // index不越界并且当前节点不为# + if (index < treeNodeStr.length && !"#".equals(treeNodeStr[index])) { + node = new TreeNode(Integer.valueOf(treeNodeStr[index])); + node.left = deserializeHelper(treeNodeStr); + node.right = deserializeHelper(treeNodeStr); + } + + return node; + } +} +``` + +### 测试用例 +1. 功能测试(输入的二叉树是完全二叉树;所有节点都没有左/右子树的二叉树;只有一个节点的二叉树;所有节点的值都相同的二叉树); +2. 特殊输入测试(指向二叉树根结点的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/37_SerializeBinaryTrees/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/37_SerializeBinaryTrees/Solution.java" new file mode 100755 index 00000000..b0a0f1db --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/37_SerializeBinaryTrees/Solution.java" @@ -0,0 +1,64 @@ + +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/12 + */ +public class Solution { + + + public String Serialize(TreeNode root) { + + StringBuilder res = new StringBuilder(); + if (root == null) { + return res.toString(); + } + + serializeHelper(root, res); + // 移除最后一个的符号"," + res.deleteCharAt(res.lastIndexOf(",")); + return res.toString(); + } + + private void serializeHelper(TreeNode root, StringBuilder res) { + + if (root == null) { + res.append("#"); + res.append(","); + return; + } + + res.append(root.val); + res.append(","); + serializeHelper(root.left, res); + serializeHelper(root.right, res); + } + + private int index = -1; + + public TreeNode Deserialize(String str) { + + if (str == null || str.length() == 0) { + return null; + } + + String[] treeNodeStr = str.split(","); + return deserializeHelper(treeNodeStr); + } + + private TreeNode deserializeHelper(String[] treeNodeStr) { + + index++; + TreeNode node = null; + + // index不越界并且当前节点不为# + if (index < treeNodeStr.length && !"#".equals(treeNodeStr[index])) { + node = new TreeNode(Integer.valueOf(treeNodeStr[index])); + node.left = deserializeHelper(treeNodeStr); + node.right = deserializeHelper(treeNodeStr); + } + + return node; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/38_StringPermutation/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/38_StringPermutation/README.md" new file mode 100755 index 00000000..b603cb51 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/38_StringPermutation/README.md" @@ -0,0 +1,74 @@ +## 字符串的排列 + +### 题目描述 +输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。(输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母)。ps:牛客上的测试用例对返回的list要排序。 + +### 解法 +对整个字符串的排列可以看成两部分。第一步求所有可能出现在第一个位置的字符,即把第一个字符与后面所有非重复的字符进行交换。第二步固定第一个字符,求后面所有字符的排列;第二步中后面的所有字符又可以看成一个完整的字符,继续执行这两个步骤。 + +注意存在重复值得情况,比如输入字符串bab,将首字符b作为固定字符串,对于将第2个下标的b换到首位仍然是bab,所有这种情况无需输出。 + +**这道题的时间复杂度应该为O(n!)** + +```java +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/14 + */ +public class Solution { + + public ArrayList Permutation(String str) { + + ArrayList reList = new ArrayList<>(); + + if (str == null || str.length() == 0) { + return reList; + } + + char[] chars = str.toCharArray(); + + // 递归输出字符串排列 + permutationHelper(chars, 0, reList); + Collections.sort(reList); + return reList; + } + + private void permutationHelper(char[] chars, int index, ArrayList list) { + + if (index == chars.length - 1) { + list.add(new String(chars)); + return; + } + + Set set = new HashSet<>(); + // 确定交换的字符,包括自己[index,length-1] + for (int i = index; i < chars.length; i++) { + + // 排除出现重复字符 + // hash表,查询花费O(1) + if (!set.contains(chars[i])) { + set.add(chars[i]); + // 固定字符index + swap(chars, i, index); + // 递归固定剩余字符[index+1,length-1] + permutationHelper(chars, index + 1, list); + // 恢复原数组 + swap(chars, index, i); + } + } + } + + private void swap(char[] chars, int x, int y) { + + char temp = chars[x]; + chars[x] = chars[y]; + chars[y] = temp; + } +} +``` + +### 测试用例 +1. 功能测试(输入的字符串有一个或多个字符); +2. 特殊输入测试(输入的字符串为nullptr指针或者内容为空)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/38_StringPermutation/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/38_StringPermutation/Solution.java" new file mode 100755 index 00000000..e28cf054 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/38_StringPermutation/Solution.java" @@ -0,0 +1,56 @@ +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/14 + */ +public class Solution { + + public ArrayList Permutation(String str) { + + ArrayList reList = new ArrayList<>(); + + if (str == null || str.length() == 0) { + return reList; + } + + char[] chars = str.toCharArray(); + + // 递归输出字符串排列 + permutationHelper(chars, 0, reList); + Collections.sort(reList); + return reList; + } + + private void permutationHelper(char[] chars, int index, ArrayList list) { + + if (index == chars.length - 1) { + list.add(new String(chars)); + return; + } + + Set set = new HashSet<>(); + // 确定交换的字符,包括自己[index,length-1] + for (int i = index; i < chars.length; i++) { + + // 排除出现重复字符 + // hash表,查询花费O(1) + if (!set.contains(chars[i])) { + set.add(chars[i]); + // 固定字符index + swap(chars, i, index); + // 递归固定剩余字符[index+1,length-1] + permutationHelper(chars, index + 1, list); + // 恢复原数组 + swap(chars, index, i); + } + } + } + + private void swap(char[] chars, int x, int y) { + + char temp = chars[x]; + chars[x] = chars[y]; + chars[y] = temp; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/39_MoreThanHalfNumber/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/39_MoreThanHalfNumber/README.md" new file mode 100755 index 00000000..a256e5ab --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/39_MoreThanHalfNumber/README.md" @@ -0,0 +1,162 @@ +## 数组中出现次数超过一半的数字 + +### 题目描述 +数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为 9 的数组 `{1,2,3,2,2,2,5,4,2}`。由于数字 2 在数组中出现了 5 次,超过数组长度的一半,因此输出 2。如果不存在则输出 0。 + +### 解法 +#### 解法一 +利用快排中的 partition 思想。 + +数组中有一个数字出现次数超过了数组长度的一半,那么排序后,数组中间的数字一定就是我们要找的数字。我们随机选一个数字,利用 partition() 函数,使得比选中数字小的数字都排在它左边,比选中数字大的数字都排在它的右边。 + +判断选中数字的下标 `index`: + +- 如果 `index = n/2`,那么这个数字就是中位数。 +- 如果 `index > n/2`,那么接着在 index 的左边进行 partition。 +- 如果 `index < n/2`,则在 index 的右边继续进行 partition。 + +**注意:**这种方法会修改输入的数组。时间复杂度为 `O(n)`。 + +```java +/** + * @author bingo + * @since 2018/12/6 + */ + +public class Solution { + /** + * 查找数组中出现次数超过一次的数字 + * + * @param array 数组 + * @return 返回该数,不存在则返回0 + */ + public int MoreThanHalfNum_Solution(int[] array) { + if (array == null || array.length == 0) { + return 0; + } + int n = array.length; + int start = 0, end = n - 1; + int mid = n >> 1; + int index = partition(array, start, end); + while (index != mid) { + if (index > mid) { + end = index - 1; + } else { + start = index + 1; + } + index = partition(array, start, end); + } + + return isMoreThanHalf(array, array[index]) ? array[index] : 0; + } + + /** + * 快排中的 partition 方法 + * + * @param array 数组 + * @param start 开始位置 + * @param end 结束位置 + * @return + */ + private int partition(int[] array, int start, int end) { + int small = start - 1; + for (int i = start; i < end; ++i) { + if (array[i] < array[end]) { + swap(array, i, ++small); + } + } + ++small; + swap(array, small, end); + return small; + + } + + private void swap(int[] array, int i, int j) { + int t = array[i]; + array[i] = array[j]; + array[j] = t; + } + + /** + * 判断val元素是否真的超过数组元素个数的一半 + * + * @param array 数组 + * @param val 某元素 + * @return boolean + */ + private boolean isMoreThanHalf(int[] array, int val) { + int cnt = 0; + for (int e : array) { + if (e == val) { + ++cnt; + } + } + + return cnt * 2 > array.length; + } +} +``` + +#### 解法二 +利用多数投票算法,从头到尾遍历数组,遇到两个不一样的数就把这两个数同时除去。除去的两个数可能都不是 majority,也可能一个是 majority 另一个不是,但是因为 majority 总数大于一半,所以这么删完最后剩下的肯定是 majority。 + +此方法时间复杂度为 `O(n)`,且不会改变数组。 + +```java +/** + * @author bingo + * @since 2018/12/6 + */ + +public class Solution { + /** + * 查找数组中出现次数超过一次的数字 + * + * @param array 数组 + * @return 返回该数,不存在则返回0 + */ + public int MoreThanHalfNum_Solution(int[] array) { + if (array == null || array.length == 0) { + return 0; + } + + int res = array[0]; + int times = 1; + for (int i = 1; i < array.length; ++i) { + if (times == 0) { + res = array[i]; + times = 1; + } else if (array[i] == res) { + ++times; + } else { + --times; + } + } + + return isMoreThanHalf(array, res) ? res : 0; + } + + + /** + * 判断val元素是否真的超过数组元素个数的一半 + * + * @param array 数组 + * @param val 某元素 + * @return boolean + */ + private boolean isMoreThanHalf(int[] array, int val) { + int cnt = 0; + for (int e : array) { + if (e == val) { + ++cnt; + } + } + + return cnt * 2 > array.length; + } +} +``` + +### 测试用例 +1. 功能测试(输入的数组中存在/不存在一个出现次数超过数组长度一半的数字); +2. 特殊输入测试(输入的数组只有一个数字;输入空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/39_MoreThanHalfNumber/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/39_MoreThanHalfNumber/Solution.java" new file mode 100755 index 00000000..fb2950bc --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/39_MoreThanHalfNumber/Solution.java" @@ -0,0 +1,51 @@ +/** + * @author bingo + * @since 2018/12/6 + */ + +public class Solution { + /** + * 查找数组中出现次数超过一次的数字 + * + * @param array 数组 + * @return 返回该数,不存在则返回0 + */ + public int MoreThanHalfNum_Solution(int[] array) { + if (array == null || array.length == 0) { + return 0; + } + + int res = array[0]; + int times = 1; + for (int i = 1; i < array.length; ++i) { + if (times == 0) { + res = array[i]; + times = 1; + } else if (array[i] == res) { + ++times; + } else { + --times; + } + } + + return isMoreThanHalf(array, res) ? res : 0; + } + + /** + * 判断val元素是否真的超过数组元素个数的一半 + * + * @param array 数组 + * @param val 某元素 + * @return boolean + */ + private boolean isMoreThanHalf(int[] array, int val) { + int cnt = 0; + for (int e : array) { + if (e == val) { + ++cnt; + } + } + + return cnt * 2 > array.length; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/40_KLeastNumbers/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/40_KLeastNumbers/README.md" new file mode 100755 index 00000000..645478a0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/40_KLeastNumbers/README.md" @@ -0,0 +1,132 @@ +## 获取数组中最小的k个数 + +### 题目描述 +输入 n 个整数,找出其中最小的 K 个数。例如输入 `4,5,1,6,2,7,3,8` 这 8 个数字,则最小的 4 个数字是 `1,2,3,4`。 + +### 解法 +#### 解法一 +利用快排中的 partition 思想。 + +数组中有一个数字出现次数超过了数组长度的一半,那么排序后,数组中间的数字一定就是我们要找的数字。我们随机选一个数字,利用 partition() 函数,使得比选中数字小的数字都排在它左边,比选中数字大的数字都排在它的右边。 + +判断选中数字的下标 `index`: + +- 如果 `index = k-1`,结束循环,返回前 k 个数。 +- 如果 `index > k-1`,那么接着在 index 的左边进行 partition。 +- 如果 `index < k-1`,则在 index 的右边继续进行 partition。 + +**注意**,这种方法会修改输入的数组。时间复杂度为 `O(n)`。 + +```java +import java.util.ArrayList; + +/** + * @author bingo + * @since 2018/12/6 + */ + +public class Solution { + + /** + * 获取数组中最小的k个数 + * + * @param input 输入的数组 + * @param k 元素个数 + * @return 最小的k的数列表 + */ + public ArrayList GetLeastNumbers_Solution(int[] input, int k) { + ArrayList res = new ArrayList<>(); + if (input == null || input.length == 0 || input.length < k || k < 1) { + return res; + } + int n = input.length; + int start = 0, end = n - 1; + int index = partition(input, start, end); + while (index != k - 1) { + if (index > k - 1) { + end = index - 1; + } else { + start = index + 1; + } + index = partition(input, start, end); + } + for (int i = 0; i < k; ++i) { + res.add(input[i]); + } + return res; + } + + private int partition(int[] input, int start, int end) { + int index = start - 1; + for (int i = start; i < end; ++i) { + if (input[i] < input[end]) { + swap(input, i, ++index); + } + } + ++index; + swap(input, index, end); + return index; + } + + private void swap(int[] array, int i, int j) { + int t = array[i]; + array[i] = array[j]; + array[j] = t; + } +} +``` + +#### 解法二 +利用大根堆,存储最小的 k 个数,最后返回即可。 + +此方法时间复杂度为 `O(nlogk)`。虽然慢一点,但是它不会改变输入的数组,并且它**适合海量数据的输入**。 + +假设题目要求从海量的数据中找出最小的 k 个数,由于内存的大小是有限的,有可能不能把这些海量的数据一次性全部载入内存。这个时候,用这种方法是最合适的。就是说它适合 n 很大并且 k 较小的问题。 + +```java +import java.util.ArrayList; +import java.util.Comparator; +import java.util.PriorityQueue; + +/** + * @author bingo + * @since 2018/12/6 + */ + +public class Solution { + + /** + * 获取数组中最小的k个数 + * + * @param input 输入的数组 + * @param k 元素个数 + * @return 最小的k的数列表 + */ + public ArrayList GetLeastNumbers_Solution(int[] input, int k) { + ArrayList res = new ArrayList<>(); + if (input == null || input.length == 0 || input.length < k || k < 1) { + return res; + } + + PriorityQueue maxHeap = new PriorityQueue<>(k, Comparator.reverseOrder()); + System.out.println(maxHeap.size()); + for (int e : input) { + if (maxHeap.size() < k) { + maxHeap.add(e); + } else { + if (maxHeap.peek() > e) { + maxHeap.poll(); + maxHeap.add(e); + } + + } + } + res.addAll(maxHeap); + return res; + } +} +``` + +### 测试用例 +1. 功能测试(输入的数组中存在/不存在一个出现次数超过数组长度一半的数字); +2. 特殊输入测试(输入的数组只有一个数字;输入空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/40_KLeastNumbers/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/40_KLeastNumbers/Solution.java" new file mode 100755 index 00000000..c24b0eb0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/40_KLeastNumbers/Solution.java" @@ -0,0 +1,56 @@ +import java.util.ArrayList; + +/** + * @author bingo + * @since 2018/12/6 + */ + +public class Solution { + + /** + * 获取数组中最小的k个数 + * + * @param input 输入的数组 + * @param k 元素个数 + * @return 最小的k的数列表 + */ + public ArrayList GetLeastNumbers_Solution(int[] input, int k) { + ArrayList res = new ArrayList<>(); + if (input == null || input.length == 0 || input.length < k || k < 1) { + return res; + } + int n = input.length; + int start = 0, end = n - 1; + int index = partition(input, start, end); + while (index != k - 1) { + if (index > k - 1) { + end = index - 1; + } else { + start = index + 1; + } + index = partition(input, start, end); + } + for (int i = 0; i < k; ++i) { + res.add(input[i]); + } + return res; + } + + private int partition(int[] input, int start, int end) { + int index = start - 1; + for (int i = start; i < end; ++i) { + if (input[i] < input[end]) { + swap(input, i, ++index); + } + } + ++index; + swap(input, index, end); + return index; + } + + private void swap(int[] array, int i, int j) { + int t = array[i]; + array[i] = array[j]; + array[j] = t; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/41_StreamMedian/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/41_StreamMedian/README.md" new file mode 100755 index 00000000..f3e3ce8e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/41_StreamMedian/README.md" @@ -0,0 +1,67 @@ +## 数据流中的中位数 + +### 题目描述 +如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用`Insert()`方法读取数据流,使用`GetMedian()`方法获取当前读取数据的中位数。 + +### 解法 +利用大根堆存放较小的一半元素,小根堆存放较大的一半元素。维持大小堆的元素个数差不超过 1。 + + +```java +import java.util.Comparator; +import java.util.PriorityQueue; + +/** + * @author bingo + * @since 2018/12/7 + */ + +public class Solution { + + private PriorityQueue minHeap = new PriorityQueue<>(); + private PriorityQueue maxHeap = new PriorityQueue<>(Comparator.reverseOrder()); + + /** + * 插入一个数 + * + * @param num 数 + */ + public void Insert(Integer num) { + + if (maxHeap.isEmpty() || num < maxHeap.peek()) { + maxHeap.offer(num); + if (maxHeap.size() - minHeap.size() > 1) { + minHeap.offer(maxHeap.poll()); + } + + } else { + minHeap.offer(num); + if (minHeap.size() - maxHeap.size() > 1) { + maxHeap.offer(minHeap.poll()); + } + } + } + + /** + * 获取中位数 + * + * @return 中位数 + */ + public Double GetMedian() { + int size1 = maxHeap.size(); + int size2 = minHeap.size(); + if (size1 > size2) { + return (double) maxHeap.peek(); + } + if (size1 < size2) { + return (double) minHeap.peek(); + } + + return (maxHeap.peek() + minHeap.peek()) / 2.0; + } +} +``` + +### 测试用例 +1. 功能测试(从数据流中读出奇数/偶数个数字); +2. 边界值测试(从数据流中读出 0/1/2 个数字)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/41_StreamMedian/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/41_StreamMedian/Solution.java" new file mode 100755 index 00000000..daa70230 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/41_StreamMedian/Solution.java" @@ -0,0 +1,54 @@ +import java.util.Comparator; +import java.util.PriorityQueue; + +/** + * @author bingo + * @since 2018/12/7 + */ + +public class Solution { + + private PriorityQueue minHeap = new PriorityQueue<>(); + private PriorityQueue maxHeap = new PriorityQueue<>(Comparator.reverseOrder()); + + /** + * 插入一个数 + * + * @param num 数 + */ + public void Insert(Integer num) { + + if (maxHeap.isEmpty() || num < maxHeap.peek()) { + maxHeap.offer(num); + if (maxHeap.size() - minHeap.size() > 1) { + minHeap.offer(maxHeap.poll()); + } + + } else { + minHeap.offer(num); + if (minHeap.size() - maxHeap.size() > 1) { + maxHeap.offer(minHeap.poll()); + } + } + } + + /** + * 获取中位数 + * + * @return 中位数 + */ + public Double GetMedian() { + int size1 = maxHeap.size(); + int size2 = minHeap.size(); + if (size1 > size2) { + return (double) maxHeap.peek(); + } + if (size1 < size2) { + return (double) minHeap.peek(); + } + + return (maxHeap.peek() + minHeap.peek()) / 2.0; + } + + +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/42_GreatestSumOfSubarrays/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/42_GreatestSumOfSubarrays/README.md" new file mode 100755 index 00000000..e5a2d99c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/42_GreatestSumOfSubarrays/README.md" @@ -0,0 +1,49 @@ +## 连续子数组的最大和 + +### 题目描述 +输入一个**非空**整型数组,数组里的数可能为正,也可能为负。 +数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。 + +要求时间复杂度为`O(n)`。 + +### 解法 +动态规划法。 + +res[i] 表示以第 i 个数字结尾的子数组的最大和,那么求出 `max(res[i])` 即可。 + +- `res[i] = array[i]`, if `res[i - 1] < 0` +- `res[i] = res[i - 1] + array[i]`, if `res[i - 1] >= 0` + +```java + +/** + * @author bingo + * @since 2018/12/7 + */ + +public class Solution { + /** + * 求连续子数组的最大和 + * + * @param array 数组 + * @return 最大和 + */ + public int FindGreatestSumOfSubArray(int[] array) { + int n = array.length; + int[] res = new int[n]; + res[0] = array[0]; + int max = res[0]; + for (int i = 1; i < n; ++i) { + res[i] = res[i - 1] > 0 ? res[i - 1] + array[i] : array[i]; + max = Math.max(max, res[i]); + } + return max; + } +} + + +``` + +### 测试用例 +1. 功能测试(输入的数组中有正数也有负数;输入的数组中全是正数;输入的数组中全是负数); +2. 特殊输入测试(表示数组的指针位为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/42_GreatestSumOfSubarrays/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/42_GreatestSumOfSubarrays/Solution.java" new file mode 100755 index 00000000..f1bdbe88 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/42_GreatestSumOfSubarrays/Solution.java" @@ -0,0 +1,25 @@ + +/** + * @author bingo + * @since 2018/12/7 + */ + +public class Solution { + /** + * 求连续子数组的最大和 + * + * @param array 数组 + * @return 最大和 + */ + public int FindGreatestSumOfSubArray(int[] array) { + int n = array.length; + int[] res = new int[n]; + res[0] = array[0]; + int max = res[0]; + for (int i = 1; i < n; ++i) { + res[i] = res[i - 1] > 0 ? res[i - 1] + array[i] : array[i]; + max = Math.max(max, res[i]); + } + return max; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/43_NumberOf1/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/43_NumberOf1/README.md" new file mode 100755 index 00000000..27352aaf --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/43_NumberOf1/README.md" @@ -0,0 +1,66 @@ +## 整数中1出现的次数 + +### 题目描述 +求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。 + +### 解法 +- 编程之美上给出的规律: + + 1. 如果第i位(自右至左,从1开始标号)上的数字为0,则第i位可能出现1的次数由更高位决定(若没有高位,视高位为0),等于更高位数字X当前位数的权重10^(i-1)。 + 2. 如果第i位上的数字为1,则第i位上可能出现1的次数不仅受更高位影响,还受低位影响(若没有低位,视低位为0),等于更高位数字X当前位数的权重10^(i-1)+(低位数字+1)。 + 3. 如果第i位上的数字大于1,则第i位上可能出现1的次数仅由更高位决定(若没有高位,视高位为0),等于(更高位数字+1)X当前位数的权重10^(i-1)。 + + 总结一下以上的算法,可以看到,当计算右数第 i 位包含的 X 的个数时: + + 1. 取第 i 位左边(高位)的数字,乘以 10i−1,得到**基础值** a。 + 2. 取第 i 位数字,计算**修正值**: + 1. 如果大于 X,则结果为 a+10i−1。 + 2. 如果小于 X,则结果为 a。 + 3. 如果等 X,则取第 i 位右边(低位)数字,设为 b,最后结果为 a+b+1。 + + 相应的代码非常简单,效率也非常高,时间复杂度只有 O(logn)。 + +```java + +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/17 + */ +public class Solution { + + public int NumberOf1Between1AndN_Solution(int n) { + + if (n < 1) { + return 0; + } + + int high, low, curr, tmp, i = 1; + high = n; + int number = 0; + while (high != 0) { + // 获取第i位的高位 + high = n / (int) Math.pow(10, i); + tmp = n % (int) Math.pow(10, i); + // 获取第i位 + curr = tmp / (int) Math.pow(10, i - 1); + // 获取第i位的低位 + low = tmp % (int) Math.pow(10, i - 1); + if (curr == 1) { + number += high * (int) Math.pow(10, i - 1) + low + 1; + } else if (curr < 1) { + number += high * (int) Math.pow(10, i - 1); + } else { + number += (high + 1) * (int) Math.pow(10, i - 1); + } + i++; + } + return number; + } +} +``` + +### 测试用例 +1. 功能测试(输入1~n的数字); +2. 特殊输入测试(输入的数字小于0)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/43_NumberOf1/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/43_NumberOf1/Solution.java" new file mode 100755 index 00000000..6cb2ec63 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/43_NumberOf1/Solution.java" @@ -0,0 +1,37 @@ +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/17 + */ +public class Solution { + + public int NumberOf1Between1AndN_Solution(int n) { + + if (n < 1) { + return 0; + } + + int high, low, curr, tmp, i = 1; + high = n; + int number = 0; + while (high != 0) { + // 获取第i位的高位 + high = n / (int) Math.pow(10, i); + tmp = n % (int) Math.pow(10, i); + // 获取第i位 + curr = tmp / (int) Math.pow(10, i - 1); + // 获取第i位的低位 + low = tmp % (int) Math.pow(10, i - 1); + if (curr == 1) { + number += high * (int) Math.pow(10, i - 1) + low + 1; + } else if (curr < 1) { + number += high * (int) Math.pow(10, i - 1); + } else { + number += (high + 1) * (int) Math.pow(10, i - 1); + } + i++; + } + return number; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/44_DigitsInSequence/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/44_DigitsInSequence/README.md" new file mode 100755 index 00000000..427f3744 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/44_DigitsInSequence/README.md" @@ -0,0 +1,71 @@ +## 数字序列中某一位的数字 + +### 题目描述 +数字以 `0123456789101112131415…` 的格式序列化到一个字符序列中。 + +在这个序列中,第 5 位(从 0 开始计数)是 5,第 13 位是 1,第 19 位是 4,等等。 + +请写一个函数求任意位对应的数字。 + +### 解法 +举个栗子,求序列第 1001 位。 + +序列的前 10 位是 `0~9`, 这 10 个只有一位的数字。显然第 1001 位在这 10 个数字之后,因此这 10 个数字可以直接跳过。再从后面序列中找第 991(991=1001-10) 位的数字。接下来有 90 个两位数,共 180 位,由于 991>180,所以继续跳过。从 881 找...最后可以找到对应的数字以及数字的某一位。 + +```java +/** + * @author bingo + * @since 2018/12/7 + */ + +public class Solution { + /** + * 求数字序列中某一位的数字 + * + * @param n 第n位 + * @return 第n位的数字 + */ + public int digitAtIndex(int n) { + if (n < 0) { + return -1; + } + int digits = 1; + while (true) { + long numbers = countOfIntegers(digits); + if (n < digits * numbers) { + break; + } + n -= numbers * digits; + ++digits; + } + return digitAtIndex(digits, n); + + } + + private long countOfIntegers(int digits) { + return digits == 1 + ? 10 + : (int) (9 * Math.pow(10, digits - 1)); + } + + private int digitAtIndex(int digits, int n) { + int beginNumber = getBeginNumber(digits); + int val = beginNumber + n / digits; + int indexFromRight = digits - n % digits; + for (int i = 1; i < indexFromRight; ++i) { + val /= 10; + } + return val % 10; + } + + private int getBeginNumber(int digits) { + return digits == 1 + ? 0 + : (int) Math.pow(10, digits - 1); + } +} +``` + +### 测试用例 +1. 功能测试(输入 10、190、1000); +2. 边界值测试(输入 0、1)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/44_DigitsInSequence/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/44_DigitsInSequence/Solution.java" new file mode 100755 index 00000000..aad6f04b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/44_DigitsInSequence/Solution.java" @@ -0,0 +1,47 @@ +/** + * @author bingo + * @since 2018/12/7 + */ + +public class Solution { + /** + * 求数字序列中某一位的数字 + * + * @param n 第n位 + * @return 第n位的数字 + */ + public int digitAtIndex(int n) { + if (n < 0) { + return -1; + } + int digits = 1; + while (true) { + long numbers = countOfIntegers(digits); + if (n < digits * numbers) { + break; + } + n -= numbers * digits; + ++digits; + } + return digitAtIndex(digits, n); + + } + + private long countOfIntegers(int digits) { + return digits == 1 ? 10 : (int) (9 * Math.pow(10, digits - 1)); + } + + private int digitAtIndex(int digits, int n) { + int beginNumber = getBeginNumber(digits); + int val = beginNumber + n / digits; + int indexFromRight = digits - n % digits; + for (int i = 1; i < indexFromRight; ++i) { + val /= 10; + } + return val % 10; + } + + private int getBeginNumber(int digits) { + return digits == 1 ? 0 : (int) Math.pow(10, digits - 1); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/45_SortArrayForMinNumber/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/45_SortArrayForMinNumber/README.md" new file mode 100755 index 00000000..b563cb46 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/45_SortArrayForMinNumber/README.md" @@ -0,0 +1,50 @@ +## 把数组排成最小的数 + +### 题目描述 +输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。 + +例如输入数组 `[3, 32, 321]`,则打印出这3个数字能排成的最小数字`321323`。 + +### 解法 + + +```java +import java.util.Arrays; + +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + + /** + * 打印数组元素组成的最小的数字 + * + * @param nums 数组 + * @return 最小的数字 + */ + public String printMinNumber(int[] nums) { + if (nums == null || nums.length == 0) { + return ""; + } + int n = nums.length; + String[] strNums = new String[n]; + for (int i = 0; i < n; ++i) { + strNums[i] = String.valueOf(nums[i]); + } + + Arrays.sort(strNums, (o1, o2) -> (o1 + o2).compareTo(o2 + o1)); + + StringBuilder sb = new StringBuilder(); + for (String str : strNums) { + sb.append(str); + } + return sb.toString(); + } +} +``` + +### 测试用例 +1. 功能测试(输入的数组中有多个数字;输入的数组中的数字有重复的数位;输入的数组中只有一个数字); +2. 特殊输入测试(表示数组的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/45_SortArrayForMinNumber/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/45_SortArrayForMinNumber/Solution.java" new file mode 100755 index 00000000..cf01a95e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/45_SortArrayForMinNumber/Solution.java" @@ -0,0 +1,34 @@ +import java.util.Arrays; + +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + + /** + * 打印数组元素组成的最小的数字 + * + * @param nums 数组 + * @return 最小的数字 + */ + public String printMinNumber(int[] nums) { + if (nums == null || nums.length == 0) { + return ""; + } + int n = nums.length; + String[] strNums = new String[n]; + for (int i = 0; i < n; ++i) { + strNums[i] = String.valueOf(nums[i]); + } + + Arrays.sort(strNums, (o1, o2) -> (o1 + o2).compareTo(o2 + o1)); + + StringBuilder sb = new StringBuilder(); + for (String str : strNums) { + sb.append(str); + } + return sb.toString(); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/46_TranslateNumbersToStrings/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/46_TranslateNumbersToStrings/README.md" new file mode 100755 index 00000000..759b1f9c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/46_TranslateNumbersToStrings/README.md" @@ -0,0 +1,56 @@ +## 把数字翻译成字符串 + +### 题目描述 +给定一个数字,我们按照如下规则把它翻译为字符串: + +0 翻译成 ”a”,1 翻译成 ”b”,……,11 翻译成 ”l”,……,25 翻译成 ”z”。 + +一个数字可能有多个翻译。例如 12258 有 5 种不同的翻译,它们分别是 ”bccfi”、”bwfi”、”bczi”、”mcfi”和”mzi”。 + +请编程实现一个函数用来计算一个数字有多少种不同的翻译方法。 + +### 解法 +先写入递推式,res 表示共有多少种翻译方法。看最后一个字符,判断它与前一个字符能否构成有效翻译,计算 res[i]: + +- 能,那么 `res[i] = res[i - 1] + res[i - 2]`; +- 不能,那么 `res[i] = res[i - 1]`。 + + +```java +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 获取翻译字符串的方法个数 + * + * @param s 字符串 + * @return 个数 + */ + public int getTranslationCount(String s) { + if (s == null || s.length() < 2) { + return 1; + } + char[] chars = s.toCharArray(); + int n = chars.length; + int[] res = new int[n]; + res[0] = 1; + res[1] = isInRange(chars[0], chars[1]) ? 2 : 1; + for (int i = 2; i < n; ++i) { + res[i] = res[i - 1] + (isInRange(chars[i - 1], chars[i]) ? res[i - 2] : 0); + } + return res[n - 1]; + } + + private boolean isInRange(char a, char b) { + int s = (a - '0') * 10 + (b -'0'); + return s >= 10 && s <= 25; + } +} +``` + +### 测试用例 +1. 功能测试(只有一位数字;包含多位数字); +2. 特殊输入测试(负数;0;包含 25、26 的数字)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/46_TranslateNumbersToStrings/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/46_TranslateNumbersToStrings/Solution.java" new file mode 100755 index 00000000..197711b9 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/46_TranslateNumbersToStrings/Solution.java" @@ -0,0 +1,32 @@ +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 获取翻译字符串的方法个数 + * + * @param s 字符串 + * @return 个数 + */ + public int getTranslationCount(String s) { + if (s == null || s.length() < 2) { + return 1; + } + char[] chars = s.toCharArray(); + int n = chars.length; + int[] res = new int[n]; + res[0] = 1; + res[1] = isInRange(chars[0], chars[1]) ? 2 : 1; + for (int i = 2; i < n; ++i) { + res[i] = res[i - 1] + (isInRange(chars[i - 1], chars[i]) ? res[i - 2] : 0); + } + return res[n - 1]; + } + + private boolean isInRange(char a, char b) { + int s = (a - '0') * 10 + (b - '0'); + return s >= 10 && s <= 25; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/47_MaxValueOfGifts/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/47_MaxValueOfGifts/README.md" new file mode 100755 index 00000000..8af6ff5b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/47_MaxValueOfGifts/README.md" @@ -0,0 +1,57 @@ +## 礼物的最大价值 + +### 题目描述 +在一个 `m×n` 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。 + +你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或者向下移动一格直到到达棋盘的右下角。 + +给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物? + +### 解法 +写出递推式,res 表示获得的最大礼物。 + +```java +res[i][j] = Math.max(res[i - 1][j], res[i][j - 1]) + grid[i][j]; +``` + + +```java +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 获取礼物的最大价值 + * + * @param grid 数组 + * @return 最大价值 + */ + public int getMaxValue(int[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + int m = grid.length; + int n = grid[0].length; + int[][] res = new int[m][n]; + res[0][0] = grid[0][0]; + for (int j = 1; j < n; ++j) { + res[0][j] = res[0][j - 1] + grid[0][j]; + } + for (int i = 1; i < m; ++i) { + res[i][0] = res[i - 1][0] + grid[i][0]; + } + for (int i = 1; i < m; ++i) { + for (int j = 1; j < n; ++j) { + res[i][j] = Math.max(res[i - 1][j], res[i][j - 1]) + grid[i][j]; + } + } + return res[m - 1][n - 1]; + } +} +``` + +### 测试用例 +1. 功能测试(多行多列的矩阵;一行或者一列的矩阵;只有一个数字的矩阵); +2. 特殊输入测试(指向矩阵数组的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/47_MaxValueOfGifts/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/47_MaxValueOfGifts/Solution.java" new file mode 100755 index 00000000..059fba01 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/47_MaxValueOfGifts/Solution.java" @@ -0,0 +1,34 @@ +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 获取礼物的最大价值 + * + * @param grid 数组 + * @return 最大价值 + */ + public int getMaxValue(int[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + int m = grid.length; + int n = grid[0].length; + int[][] res = new int[m][n]; + res[0][0] = grid[0][0]; + for (int j = 1; j < n; ++j) { + res[0][j] = res[0][j - 1] + grid[0][j]; + } + for (int i = 1; i < m; ++i) { + res[i][0] = res[i - 1][0] + grid[i][0]; + } + for (int i = 1; i < m; ++i) { + for (int j = 1; j < n; ++j) { + res[i][j] = Math.max(res[i - 1][j], res[i][j - 1]) + grid[i][j]; + } + } + return res[m - 1][n - 1]; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/48_LongestSubstringWithoutDup/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/48_LongestSubstringWithoutDup/README.md" new file mode 100755 index 00000000..0012f287 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/48_LongestSubstringWithoutDup/README.md" @@ -0,0 +1,63 @@ +## 最长不含重复字符的子字符串 + +### 题目描述 +请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 + +假设字符串中只包含从 `a` 到 `z`的字符。 + +### 解法 +动态规划。 + +`res[i]` 表示以 `s[i]` 字符结尾的最长不重复字符串的长度。判断 `s[i]`: +- 若 `s[i]` 在前面没出现过,那么 `res[i] = res[i - 1] + 1`; +- 若 `s[i]` 在前面有出现过,判断它上一次出现的位置 `index` 到 `i` 的距离 `d` 与 `res[i - 1]` 的大小关系: + - 若 `d <= res[i - 1]`,说明它被包含在 `res[i - 1]` 构成的子串中,那么 `res[i] = d`; + - 若 `d > res[i - 1]`,说明它在 `res[i - 1]` 构成的子串的左侧,那么 `res[i] = res[i - 1] + 1`。 + +需要用一个数组 t 记录一下当前出现的字符在哪个位置。 + +```java +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 最长不含重复字符的子字符串 + * + * @param s 字符串 + * @return 最长不重复字符子串 + */ + public int longestSubstringWithoutDuplication(String s) { + if (s == null || s.length() == 0) { + return 0; + } + char[] chars = s.toCharArray(); + int[] t = new int[26]; + for (int i = 0; i < 26; ++i) { + t[i] = -1; + } + t[chars[0] - 'a'] = 0; + int n = chars.length; + int[] res = new int[n]; + res[0] = 1; + int max = res[0]; + for (int i = 1; i < n; ++i) { + int index = t[chars[i] - 'a']; + int d = i - index; + res[i] = (index == -1 || d > res[i - 1]) + ? res[i - 1] + 1 + : d; + + t[chars[i] - 'a'] = i; + max = Math.max(max, res[i]); + } + return max; + } +} +``` + +### 测试用例 +1. 功能测试(包含多个字符的字符串;只有一个字符的字符串;所有字符都唯一的字符串;所有字符都相同的字符串); +2. 特殊输入测试(空字符串)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/48_LongestSubstringWithoutDup/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/48_LongestSubstringWithoutDup/Solution.java" new file mode 100755 index 00000000..d8bd693b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/48_LongestSubstringWithoutDup/Solution.java" @@ -0,0 +1,37 @@ +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 最长不含重复字符的子字符串 + * + * @param s 字符串 + * @return 最长不重复字符子串 + */ + public int longestSubstringWithoutDuplication(String s) { + if (s == null || s.length() == 0) { + return 0; + } + char[] chars = s.toCharArray(); + int[] t = new int[26]; + for (int i = 0; i < 26; ++i) { + t[i] = -1; + } + t[chars[0] - 'a'] = 0; + int n = chars.length; + int[] res = new int[n]; + res[0] = 1; + int max = res[0]; + for (int i = 1; i < n; ++i) { + int index = t[chars[i] - 'a']; + int d = i - index; + res[i] = (index == -1 || d > res[i - 1]) ? res[i - 1] + 1 : d; + + t[chars[i] - 'a'] = i; + max = Math.max(max, res[i]); + } + return max; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/49_UglyNumber/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/49_UglyNumber/README.md" new file mode 100755 index 00000000..bec37fd3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/49_UglyNumber/README.md" @@ -0,0 +1,106 @@ +## 丑数 + +### 题目描述 +把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 + +### 解法1 +由题目可以得知,丑数必定可以整除2、3或者5(除了丑数1之外),也就是说,如果一个数能够被2整除,就连续除以2;能够被3整除,就连续除以3;能够被5整除,就连续除以5;如果最后得到1,那么这个数便是丑数。因此我们可以使用暴力的方式遍历到第N个丑数。 + +该解法的time complexity为O(count),比如第1500个丑数为859963392,那么就需要枚举1到859963392 + +```java +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/23 + * @description + */ +public class Solution { + + private boolean isUgly(int number){ + if(number % 2 == 0) + number /= 2; + if(number % 3 == 0) + number /= 3; + if(number % 5 == 0) + number /= 5; + return number == 1; + } + + public int GetUglyNumber_Solution(int index){ + if(index <= 0) + return 0; + + int number = 0; + int count = 0; + while(count < index){ + number++; + if(isUgly(number)){ + count++; + } + } + + return number; + } +} +``` + +### 解法2 + +把15以内的丑数列出来:`1、2、3、4、5、6、8、9、10、12、15` ,你会发现新丑数必定是旧丑数乘以因子2、3或者5得来的。所以可以使用一个list来存储已经出现的丑数以此来计算出新的丑数,从而避免对非丑数的计算。 + +通过维护3个下标i2,i3,i5和它们对应的值m2,m3,m5,每次向list中添加的为m2,m3,m5中的最小值,以此来维护list的有序性。 + +该解法的time complexity为O(n),space complexity为O(n),属于典型的用空间换时间的解决方法。 + +```java +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/23 + * @description + */ +public class Solution { + + public int GetUglyNumber_Solution(int index) { + + if (index <= 0) + return 0; + + List reList = new ArrayList<>(); + // 第一个丑数为1 + reList.add(1); + int i2 = 0, i3 = 0, i5 = 0; + while (reList.size() < index) { + + int m2 = reList.get(i2) * 2; + int m3 = reList.get(i3) * 3; + int m5 = reList.get(i5) * 5; + + // 求出m2、m3、m5中的最小值,该值为加入list的丑数 + int min = Math.min(m2, Math.min(m3, m5)); + + if (m2 == min) { + i2++; + } + if (m3 == min) { + i3++; + } + if (m5 == min) { + i5++; + } + + reList.add(min); + } + + // O(1) + return reList.get(reList.size() - 1); + } +} +``` + +### 测试用例 + +1. 功能测试(输入2、3、4、5、6等)。 +2. 特殊输入测试(边界值1;无效输入0)。 +3. 性能测试(输入较大的数字,比如1500)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/49_UglyNumber/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/49_UglyNumber/Solution.java" new file mode 100755 index 00000000..cb3140c5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/49_UglyNumber/Solution.java" @@ -0,0 +1,43 @@ +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/23 + * @description + */ +public class Solution { + + public int GetUglyNumber_Solution(int index) { + + if (index <= 0) + return 0; + + List reList = new ArrayList<>(); + // 第一个丑数为1 + reList.add(1); + int i2 = 0, i3 = 0, i5 = 0; + while (reList.size() < index) { + + int m2 = reList.get(i2) * 2; + int m3 = reList.get(i3) * 3; + int m5 = reList.get(i5) * 5; + + // 求出m2、m3、m5中的最小值,该值为加入list的丑数 + int min = Math.min(m2, Math.min(m3, m5)); + + if (m2 == min) { + i2++; + } + if (m3 == min) { + i3++; + } + if (m5 == min) { + i5++; + } + + reList.add(min); + } + + // O(1) + return reList.get(reList.size() - 1); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_01_FirstNotRepeatingChar/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_01_FirstNotRepeatingChar/README.md" new file mode 100755 index 00000000..ebf2baeb --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_01_FirstNotRepeatingChar/README.md" @@ -0,0 +1,43 @@ +## 第一个只出现一次的字符 + +### 题目描述 +在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写). + +### 解法1 +使用HashMap来统计字符出现的次数,因为字符的多少是固定的(大小写字母一共52个),所以可以认为使用HashMap的空间复杂度为O(1)。该解法时间复杂度为O(n)。 + +```java +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/24 + * @description + */ +public class Solution { + + public int FirstNotRepeatingChar(String str) { + + if (str == null || str.length() == 0) { + return -1; + } + + Map characterMap = new HashMap<>(); + // hashMap is HashTable,search cost O(1) + for (int i = 0; i < str.length(); i++) { + characterMap.put(str.charAt(i), characterMap.getOrDefault(str.charAt(i), 0) + 1); + } + + for (int i = 0; i < str.length(); i++) { + if (characterMap.get(str.charAt(i)) == 1) { + return i; + } + } + + return -1; + } +} +``` +### 测试用例 + +1. 功能测试(字符串中仅存在只出现一次的字符;字符串中不存在只出现一次的字符;字符串中所有字符都只出现一次)。 +2. 特殊输入测试(字符串为null)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_01_FirstNotRepeatingChar/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_01_FirstNotRepeatingChar/Solution.java" new file mode 100755 index 00000000..881c4bba --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_01_FirstNotRepeatingChar/Solution.java" @@ -0,0 +1,29 @@ +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/24 + * @description + */ +public class Solution { + + public int FirstNotRepeatingChar(String str) { + + if (str == null || str.length() == 0) { + return -1; + } + + Map characterMap = new HashMap<>(); + // hashMap is HashTable,search cost O(1) + for (int i = 0; i < str.length(); i++) { + characterMap.put(str.charAt(i), characterMap.getOrDefault(str.charAt(i), 0) + 1); + } + + for (int i = 0; i < str.length(); i++) { + if (characterMap.get(str.charAt(i)) == 1) { + return i; + } + } + + return -1; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_02_FristCharacterInStream/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_02_FristCharacterInStream/README.md" new file mode 100755 index 00000000..2d67dbcc --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_02_FristCharacterInStream/README.md" @@ -0,0 +1,45 @@ +## 字符流中第一个不重复的字符 + +### 题目描述 + +请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。如果当前字符流没有存在出现一次的字符,返回#字符。 + + +### 解法1 +与上一道题的思路是一致的。 + +```java +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/25 + * @description + */ +public class Solution { + + private StringBuilder res = new StringBuilder(); + private Map characterMap = new HashMap<>(); + + // Insert one char from stringstream + public void Insert(char ch) { + res.append(ch); + characterMap.put(ch, characterMap.getOrDefault(ch, 0) + 1); + } + + // return the first appearence once char in current stringstream + public char FirstAppearingOnce() { + + for (char c : res.toString().toCharArray()) { + if (characterMap.get(c) == 1) { + return c; + } + } + + return '#'; + } +} +``` +### 测试用例 + +1. 功能测试(读入一个字符;读入多个字符;读入的所有字符都是唯一的;读入的所有字符都是重复出现的)。 +2. 特殊输入测试(读入0个字符)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_02_FristCharacterInStream/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_02_FristCharacterInStream/Solution.java" new file mode 100755 index 00000000..7e0c7ebf --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/50_02_FristCharacterInStream/Solution.java" @@ -0,0 +1,29 @@ +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/01/25 + * @description + */ +public class Solution { + + private StringBuilder res = new StringBuilder(); + private Map characterMap = new HashMap<>(); + + // Insert one char from stringstream + public void Insert(char ch) { + res.append(ch); + characterMap.put(ch, characterMap.getOrDefault(ch, 0) + 1); + } + + // return the first appearence once char in current stringstream + public char FirstAppearingOnce() { + + for (char c : res.toString().toCharArray()) { + if (characterMap.get(c) == 1) { + return c; + } + } + + return '#'; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/52_FirstCommonNodesInLists/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/52_FirstCommonNodesInLists/README.md" new file mode 100755 index 00000000..78fe0068 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/52_FirstCommonNodesInLists/README.md" @@ -0,0 +1,86 @@ +## 两个链表的第一个公共结点 + +### 题目描述 +输入两个链表,找出它们的第一个公共结点。 + +**样例** +``` +给出两个链表如下所示: +A: a1 → a2 + ↘ + c1 → c2 → c3 + ↗ +B: b1 → b2 → b3 + +输出第一个公共节点c1 +``` + +### 解法 +先遍历两链表,求出两链表的长度,再求长度差 `|n1 - n2|`。 + +较长的链表先走 `|n1 - n2|` 步,之后两链表再同时走,首次相遇时的节点即为两链表的第一个公共节点。 + + +```java +/** + * @author bingo + * @since 2018/12/8 + */ + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +class Solution { + + /** + * 求两链表第一个公共节点 + * + * @param headA 链表A + * @param headB 链表B + * @return 第一个公共节点 + */ + public ListNode findFirstCommonNode(ListNode headA, ListNode headB) { + if (headA == null || headB == null) { + return null; + } + int n1 = len(headA), n2 = len(headB); + ListNode p1 = headA, p2 = headB; + if (n1 > n2) { + for (int i = 0; i < n1 - n2; ++i) { + p1 = p1.next; + } + } else if (n1 < n2) { + for (int i = 0; i < n2 - n1; ++i) { + p2 = p2.next; + } + } + while (p1 != p2 && p1 != null && p2 != null) { + p1 = p1.next; + p2 = p2.next; + } + return (p1 == null || p2 == null) ? null : p1; + } + + private int len(ListNode head) { + int n = 0; + ListNode cur = head; + while (cur != null) { + ++n; + cur = cur.next; + } + return n; + } +} +``` + +### 测试用例 +1. 功能测试(输入的两个链表有公共节点;第一个公共节点在链表的中间,第一个公共节点在链表的末尾,第一个公共节点是链表的头节点;输入的两个链表没有公共节点); +2. 特殊输入测试(输入的链表头节点是空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/52_FirstCommonNodesInLists/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/52_FirstCommonNodesInLists/Solution.java" new file mode 100755 index 00000000..b904da34 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/52_FirstCommonNodesInLists/Solution.java" @@ -0,0 +1,57 @@ +/** + * @author bingo + * @since 2018/12/8 + */ + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +class Solution { + + /** + * 求两链表第一个公共节点 + * + * @param headA 链表A + * @param headB 链表B + * @return 第一个公共节点 + */ + public ListNode findFirstCommonNode(ListNode headA, ListNode headB) { + if (headA == null || headB == null) { + return null; + } + int n1 = len(headA), n2 = len(headB); + ListNode p1 = headA, p2 = headB; + if (n1 > n2) { + for (int i = 0; i < n1 - n2; ++i) { + p1 = p1.next; + } + } else if (n1 < n2) { + for (int i = 0; i < n2 - n1; ++i) { + p2 = p2.next; + } + } + while (p1 != p2 && p1 != null && p2 != null) { + p1 = p1.next; + p2 = p2.next; + } + return (p1 == null || p2 == null) ? null : p1; + } + + private int len(ListNode head) { + int n = 0; + ListNode cur = head; + while (cur != null) { + ++n; + cur = cur.next; + } + return n; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_01_NumberOfK/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_01_NumberOfK/README.md" new file mode 100755 index 00000000..76cb7d22 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_01_NumberOfK/README.md" @@ -0,0 +1,99 @@ +## 数字在排序数组中出现的次数 + +### 题目描述 +统计一个数字在排序数组中出现的次数。 + +例如输入排序数组 `[1, 2, 3, 3, 3, 3, 4, 5]` 和数字 3,由于 3 在这个数组中出现了 4 次,因此输出 4。 + +**样例** + +``` +输入:[1, 2, 3, 3, 3, 3, 4, 5] , 3 + +输出:4 +``` + +### 解法 +找出第一个 k 和最后一个 k 出现的位置。 + +找第一个 k 时,利用二分法,如果 `nums[m] == k`,判断它的前一个位置是不是也是 k,如果不是,说明这是第一个 k,直接返回。如果是,那么递归在左边查找第一个 k。 + +找最后一个 k 也同理。 + + +```java +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 求数字k在排序数组中出现的次数 + * + * @param nums 数组 + * @param k 数字k + * @return k在数组中出现的次数 + */ + public int getNumberOfK(int[] nums, int k) { + if (nums == null || nums.length == 0) { + return 0; + } + int start = 0, end = nums.length - 1; + int first = getFirstK(nums, start, end, k); + int last = getLastK(nums, start, end, k); + if (first > -1 && last > -1) { + return last - first + 1; + } + return 0; + } + + private int getFirstK(int[] nums, int start, int end, int k) { + if (start > end) { + return -1; + } + int m = start + ((end - start) >> 1); + if (nums[m] == k) { + if (m == 0 || (m > 0 && nums[m - 1] != k)) { + return m; + } else { + end = m - 1; + } + } else { + if (nums[m] > k) { + end = m - 1; + } else { + start = m + 1; + } + } + return getFirstK(nums, start, end, k); + } + + private int getLastK(int[] nums, int start, int end, int k) { + if (start > end) { + return -1; + } + int m = start + ((end - start) >> 1); + if (nums[m] == k) { + if (m == nums.length - 1 || (m < nums.length - 1 && nums[m + 1] != k)) { + return m; + } else { + start = m + 1; + } + } else { + if (nums[m] > k) { + end = m - 1; + } else { + start = m + 1; + } + } + return getLastK(nums, start, end, k); + + } +} +``` + +### 测试用例 +1. 功能测试(数组中包含要查找的数字;数组中没有要查找的数字;要查找的数字在数组中出现一次/多次); +2. 边界值测试(查找数组中的最大值、最小值;数组中只有一个数字); +3. 特殊输入测试(表示数组的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_01_NumberOfK/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_01_NumberOfK/Solution.java" new file mode 100755 index 00000000..eed896d0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_01_NumberOfK/Solution.java" @@ -0,0 +1,69 @@ +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 求数字k在排序数组中出现的次数 + * + * @param nums 数组 + * @param k 数字k + * @return k在数组中出现的次数 + */ + public int getNumberOfK(int[] nums, int k) { + if (nums == null || nums.length == 0) { + return 0; + } + int start = 0, end = nums.length - 1; + int first = getFirstK(nums, start, end, k); + int last = getLastK(nums, start, end, k); + if (first > -1 && last > -1) { + return last - first + 1; + } + return 0; + } + + private int getFirstK(int[] nums, int start, int end, int k) { + if (start > end) { + return -1; + } + int m = start + ((end - start) >> 1); + if (nums[m] == k) { + if (m == 0 || (m > 0 && nums[m - 1] != k)) { + return m; + } else { + end = m - 1; + } + } else { + if (nums[m] > k) { + end = m - 1; + } else { + start = m + 1; + } + } + return getFirstK(nums, start, end, k); + } + + private int getLastK(int[] nums, int start, int end, int k) { + if (start > end) { + return -1; + } + int m = start + ((end - start) >> 1); + if (nums[m] == k) { + if (m == nums.length - 1 || (m < nums.length - 1 && nums[m + 1] != k)) { + return m; + } else { + start = m + 1; + } + } else { + if (nums[m] > k) { + end = m - 1; + } else { + start = m + 1; + } + } + return getLastK(nums, start, end, k); + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_02_MissingNumber/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_02_MissingNumber/README.md" new file mode 100755 index 00000000..ba4f46ae --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_02_MissingNumber/README.md" @@ -0,0 +1,62 @@ +## [0到n-1中缺失的数字](https://www.acwing.com/problem/content/64/) + +### 题目描述 +一个长度为 `n-1` 的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围 `0` 到 `n-1` 之内。 + +在范围 `0` 到 `n-1` 的 `n` 个数字中有且只有一个数字不在该数组中,请找出这个数字。 + +**样例** +``` +输入:[0,1,2,4] + +输出:3 +``` + +### 解法 +找出第一个与下标不对应的数字即可。 + +特殊情况: +- 下标都对应,那么应该返回 `最后一个数+1`; +- 缺失的数字是第一个,那么返回 0。 + + +```java +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 获取0~n-1缺失的数字 + * + * @param nums 数组 + * @return 缺失的数字 + */ + public int getMissingNumber(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int n = nums.length; + int start = 0, end = n - 1; + while (start <= end) { + int mid = start + ((end - start) >> 1); + if (nums[mid] != mid) { + if (mid == 0 || nums[mid - 1] == mid - 1) { + return mid; + } + end = mid - 1; + } else { + start = mid + 1; + } + } + return start == n ? n : -1; + + } +} +``` + +### 测试用例 +1. 功能测试(缺失的数字位于数组的开始、中间或者末尾); +2. 边界值测试(数组中只有一个数字 0); +3. 特殊输入测试(表示数组的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_02_MissingNumber/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_02_MissingNumber/Solution.java" new file mode 100755 index 00000000..bb1851ec --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_02_MissingNumber/Solution.java" @@ -0,0 +1,33 @@ +/** + * @author bingo + * @since 2018/12/8 + */ + +class Solution { + /** + * 获取0~n-1缺失的数字 + * + * @param nums 数组 + * @return 缺失的数字 + */ + public int getMissingNumber(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int n = nums.length; + int start = 0, end = n - 1; + while (start <= end) { + int mid = start + ((end - start) >> 1); + if (nums[mid] != mid) { + if (mid == 0 || nums[mid - 1] == mid - 1) { + return mid; + } + end = mid - 1; + } else { + start = mid + 1; + } + } + return start == n ? n : -1; + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_03_IntegerIdenticalToIndex/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_03_IntegerIdenticalToIndex/README.md" new file mode 100755 index 00000000..086e3629 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_03_IntegerIdenticalToIndex/README.md" @@ -0,0 +1,63 @@ +## [数组中数值和下标相等的元素](https://www.acwing.com/problem/content/65/) + +### 题目描述 +假设一个单调递增的数组里的每个元素都是整数并且是唯一的。 + +请编程实现一个函数找出数组中任意一个数值等于其下标的元素。 + +例如,在数组 `[-3, -1, 1, 3, 5]` 中,数字 3 和它的下标相等。 + +**样例** +``` +输入:[-3, -1, 1, 3, 5] + +输出:3 +``` + +**注意**:如果不存在,则返回 -1。 + +### 解法 +二分法查找。 +- 当前元素等于对应的下标,直接返回该下标; +- 当前元素大于该下标,在左边查找; +- 当前元素小于该下标,在右边查找。 + + +```java +/** + * @author bingo + * @since 2018/12/10 + */ + +class Solution { + /** + * 找出单调递增数组中数值和下标相等的元素 + * + * @param nums 数组 + * @return 数值与下标相等的元素 + */ + public int getNumberSameAsIndex(int[] nums) { + if (nums == null || nums.length == 0) { + return -1; + } + int start = 0, end = nums.length - 1; + while (start <= end) { + int mid = start + ((end - start) >> 1); + if (nums[mid] == mid) { + return mid; + } + if (nums[mid] < mid) { + start = mid + 1; + } else { + end = mid - 1; + } + } + return -1; + } +} +``` + +### 测试用例 +1. 功能测试(数组中包含或者不包含数值和下标相等的元素); +2. 边界值测试(数组中只有一个数字;数值和下标相等的元素位于数组的开头或者结尾); +3. 特殊输入测试(表示数组的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_03_IntegerIdenticalToIndex/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_03_IntegerIdenticalToIndex/Solution.java" new file mode 100755 index 00000000..c2da5adc --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/53_03_IntegerIdenticalToIndex/Solution.java" @@ -0,0 +1,31 @@ +/** + * @author bingo + * @since 2018/12/10 + */ + +class Solution { + /** + * 找出单调递增数组中数值和下标相等的元素 + * + * @param nums 数组 + * @return 数值与下标相等的元素 + */ + public int getNumberSameAsIndex(int[] nums) { + if (nums == null || nums.length == 0) { + return -1; + } + int start = 0, end = nums.length - 1; + while (start <= end) { + int mid = start + ((end - start) >> 1); + if (nums[mid] == mid) { + return mid; + } + if (nums[mid] < mid) { + start = mid + 1; + } else { + end = mid - 1; + } + } + return -1; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/54_KthNodeInBST/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/54_KthNodeInBST/README.md" new file mode 100755 index 00000000..be0bc799 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/54_KthNodeInBST/README.md" @@ -0,0 +1,54 @@ +## 二叉搜索树的第k个结点 + +### 题目描述 +给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4 + +### 解法 +因为BST的中序遍历得到的是一个升序的列表,所以在进行中序遍历行进行判断即可。所以该算法的时间复杂度为O(logn) + + +```java +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/28 + */ +class Solution { + + private int count = 0; + + public TreeNode KthNode(TreeNode pRoot, int k) { + + if (pRoot == null || k == 0) { + return null; + } + + // 左递归 + TreeNode retNode = KthNode(pRoot.left, k); + + if (retNode != null) { + return retNode; + } + + // 符合条件则返回 + count++; + if (count == k) { + return pRoot; + } + + // 右递归 + retNode = KthNode(pRoot.right, k); + if (retNode != null) { + return retNode; + } + + return null; + } +} +``` + +### 测试用例 +1. 功能测试(各种形态不同的二叉搜索树); +2. 边界值测试(输入k为0、1、二叉搜索树的结点数、二叉搜索树的结点数+1); +3. 特殊输入测试(指向二叉搜索树的节点的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/54_KthNodeInBST/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/54_KthNodeInBST/Solution.java" new file mode 100755 index 00000000..d0716a55 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/54_KthNodeInBST/Solution.java" @@ -0,0 +1,38 @@ +/** + * @author mcrwayfun + * @version 1.0 + * @description + * @date Created in 2019/1/28 + */ +class Solution { + + private int count = 0; + + public TreeNode KthNode(TreeNode pRoot, int k) { + + if (pRoot == null || k == 0) { + return null; + } + + // 左递归 + TreeNode retNode = KthNode(pRoot.left, k); + + if (retNode != null) { + return retNode; + } + + // 符合条件则返回 + count++; + if (count == k) { + return pRoot; + } + + // 右递归 + retNode = KthNode(pRoot.right, k); + if (retNode != null) { + return retNode; + } + + return null; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_01_TreeDepth/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_01_TreeDepth/README.md" new file mode 100755 index 00000000..e9282675 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_01_TreeDepth/README.md" @@ -0,0 +1,59 @@ +## [二叉树的深度](https://www.acwing.com/problem/content/67/) + +### 题目描述 +输入一棵二叉树的根结点,求该树的深度。 + +从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 + +**样例** +``` +输入:二叉树[8, 12, 2, null, null, 6, 4, null, null, null, null]如下图所示: + 8 + / \ + 12 2 + / \ + 6 4 + +输出:3 +``` + +### 解法 +递归即可。 + + +```java +/** + * @author bingo + * @since 2018/12/10 + */ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + /** + * 求二叉树的深度 + * + * @param root 二叉树根结点 + * @return 深度 + */ + public int treeDepth(TreeNode root) { + if (root == null) { + return 0; + } + int lDepth = treeDepth(root.left); + int rDepth = treeDepth(root.right); + return 1 + Math.max(lDepth, rDepth); + } +} +``` + +### 测试用例 +1. 功能测试(输入普通的二叉树;二叉树中所有节点都没有左/右子树); +2. 特殊输入测试(二叉树只有一个节点;二叉树的头节点为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_01_TreeDepth/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_01_TreeDepth/Solution.java" new file mode 100755 index 00000000..1dda52fd --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_01_TreeDepth/Solution.java" @@ -0,0 +1,30 @@ +/** + * @author bingo + * @since 2018/12/10 + */ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + /** + * 求二叉树的深度 + * + * @param root 二叉树根结点 + * @return 深度 + */ + public int treeDepth(TreeNode root) { + if (root == null) { + return 0; + } + int lDepth = treeDepth(root.left); + int rDepth = treeDepth(root.right); + return 1 + Math.max(lDepth, rDepth); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_02_BalancedBinaryTree/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_02_BalancedBinaryTree/README.md" new file mode 100755 index 00000000..6e1d6ee9 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_02_BalancedBinaryTree/README.md" @@ -0,0 +1,127 @@ +## [平衡二叉树](https://www.acwing.com/problem/content/68/) + +### 题目描述 +输入一棵二叉树的根结点,判断该树是不是平衡二叉树。 + +如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。 + +**注意:** + +- 规定空树也是一棵平衡二叉树。 + +**样例** +``` +输入:二叉树[5,7,11,null,null,12,9,null,null,null,null]如下所示, + 5 + / \ + 7 11 + / \ + 12 9 + +输出:true +``` + +### 解法 +#### 解法一 +求每个节点左右孩子的深度,判断该节点是否平衡。 + +这种方法需要重复遍历节点多次,不推荐。 + + +```java +/** + * @author bingo + * @since 2018/12/10 + */ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + /** + * 判断是否是平衡二叉树 + * + * @param root 二叉树根结点 + * @return 是否是平衡二叉树 + */ + public boolean isBalanced(TreeNode root) { + if (root == null) { + return true; + } + if (Math.abs(treeDepth(root.left) - treeDepth(root.right)) > 1) { + return false; + } + return isBalanced(root.left) && isBalanced(root.right); + } + + private int treeDepth(TreeNode root) { + if (root == null) { + return 0; + } + int lDepth = treeDepth(root.left); + int rDepth = treeDepth(root.right); + return 1 + Math.max(lDepth, rDepth); + } +} +``` + +#### 解法二 + +```java +/** + * @author bingo + * @since 2018/12/10 + */ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + private boolean isBalanced; + + /** + * 判断是否是平衡二叉树 + * + * @param root 二叉树根结点 + * @return 是否是平衡二叉树 + */ + public boolean isBalanced(TreeNode root) { + if (root == null) { + return true; + } + isBalanced = true; + treeDepth(root); + return isBalanced; + } + + private int treeDepth(TreeNode root) { + if (root == null || !isBalanced) { + return 0; + } + int lDepth = treeDepth(root.left); + int rDepth = treeDepth(root.right); + if (Math.abs(lDepth - rDepth) > 1) { + isBalanced = false; + } + return 1 + Math.max(lDepth, rDepth); + + } +} +``` + + +### 测试用例 +1. 功能测试(平衡的二叉树;不是平衡的二叉树;二叉树中所有节点都没有左/右子树); +2. 特殊输入测试(二叉树只有一个节点;二叉树的头节点为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_02_BalancedBinaryTree/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_02_BalancedBinaryTree/Solution.java" new file mode 100755 index 00000000..f2248b40 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/55_02_BalancedBinaryTree/Solution.java" @@ -0,0 +1,45 @@ +/** + * @author bingo + * @since 2018/12/10 + */ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + private boolean isBalanced; + + /** + * 判断是否是平衡二叉树 + * + * @param root 二叉树根结点 + * @return 是否是平衡二叉树 + */ + public boolean isBalanced(TreeNode root) { + if (root == null) { + return true; + } + isBalanced = true; + treeDepth(root); + return isBalanced; + } + + private int treeDepth(TreeNode root) { + if (root == null || !isBalanced) { + return 0; + } + int lDepth = treeDepth(root.left); + int rDepth = treeDepth(root.right); + if (Math.abs(lDepth - rDepth) > 1) { + isBalanced = false; + } + return 1 + Math.max(lDepth, rDepth); + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_01_NumbersAppearOnce/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_01_NumbersAppearOnce/README.md" new file mode 100755 index 00000000..46d4d280 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_01_NumbersAppearOnce/README.md" @@ -0,0 +1,77 @@ +## [数组中只出现一次的两个数字](https://www.acwing.com/problem/content/69/) + +### 题目描述 +一个整型数组里除了两个数字之外,其他的数字都出现了两次。 + +请写程序找出这两个只出现一次的数字。 + +你可以假设这两个数字一定存在。 + +**样例** +``` +输入:[1,2,3,3,4,4] + +输出:[1,2] +``` + +### 解法 +如果数组有一个数字出现一次,其它数字都出现两次。那么我们很容易通过异或 `^` 运算求出来。 + +而现在是有两个数字出现一次,那么我们考虑一下怎么将这两个数字隔开,之后我们对隔开的数组分别进行异或,不就求出来了? + +我们先异或,求得的结果是两个不相同的数字异或的结果,结果一定不为 0。那么它的二进制表示中一定有 1。我们根据这个 1 在二进制中出现的位置。将数组划分,这样,两个只出现一次的数字就会被隔开,之后求异或即可。 + +```java +/** + * @author bingo + * @since 2018/12/10 + */ + +class Solution { + /** + * 求数组中只出现一次的两个数字 + * + * @param nums 数字 + * @return 两个数字组成的数组 + */ + public int[] findNumsAppearOnce(int[] nums) { + if (nums == null || nums.length < 2) { + return null; + } + int xorRes = 0; + for (int e : nums) { + xorRes ^= e; + } + int[] res = new int[2]; + int index = indexOf1(xorRes); + for (int e : nums) { + if (isBit1(e, index)) { + res[0] ^= e; + } else { + res[1] ^= e; + } + } + return res; + + + } + + private int indexOf1(int val) { + int index = 0; + while ((val & 1) == 0) { + val = val >> 1; + ++index; + } + return index; + } + + private boolean isBit1(int val, int index) { + val = val >> index; + return (val & 1) == 1; + } +} +``` + + +### 测试用例 +1. 功能测试(数组中有多对重复的数字;数组中没有重复的数字)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_01_NumbersAppearOnce/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_01_NumbersAppearOnce/Solution.java" new file mode 100755 index 00000000..9e70e920 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_01_NumbersAppearOnce/Solution.java" @@ -0,0 +1,47 @@ +/** + * @author bingo + * @since 2018/12/10 + */ + +class Solution { + /** + * 求数组中只出现一次的两个数字 + * + * @param nums 数字 + * @return 两个数字组成的数组 + */ + public int[] findNumsAppearOnce(int[] nums) { + if (nums == null || nums.length < 2) { + return null; + } + int xorRes = 0; + for (int e : nums) { + xorRes ^= e; + } + int[] res = new int[2]; + int index = indexOf1(xorRes); + for (int e : nums) { + if (isBit1(e, index)) { + res[0] ^= e; + } else { + res[1] ^= e; + } + } + return res; + + } + + private int indexOf1(int val) { + int index = 0; + while ((val & 1) == 0) { + val = val >> 1; + ++index; + } + return index; + } + + private boolean isBit1(int val, int index) { + val = val >> index; + return (val & 1) == 1; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_02_NumberAppearingOnce/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_02_NumberAppearingOnce/README.md" new file mode 100755 index 00000000..77d1b4e3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_02_NumberAppearingOnce/README.md" @@ -0,0 +1,55 @@ +## [数组中唯一只出现一次的数字](https://www.acwing.com/problem/content/70/) + +### 题目描述 +在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。 + +请找出那个只出现一次的数字。 + +你可以假设满足条件的数字一定存在。 + +**思考题:** + +- 如果要求只使用 `O(n)` 的时间和额外 `O(1)` 的空间,该怎么做呢? + +### 解法 +分别累加数组中每个元素的二进制中出现的数字,那么出现三次的数字,二进制位上最后累加的结果一定能被 3 整除。不能被 3 整除的位,就属于只出现一次的数字。 + +```java +/** + * @author bingo + * @since 2018/12/10 + */ + +class Solution { + /** + * 找出数组中只出现一次的数字,其它数字都出现三次 + * + * @param nums 数字 + * @return 只出现一次的数字 + */ + public int findNumberAppearingOnce(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int[] bits = new int[32]; + int n = nums.length; + for (int i = 0; i < n; ++i) { + int val = nums[i]; + for (int j = 0; j < 32; ++j) { + bits[j] += (val & 1); + val = val >> 1; + } + } + int res = 0; + for (int i = 0; i < 32; ++i) { + if (bits[i] % 3 != 0) { + res += Math.pow(2, i); + } + } + return res; + } +} +``` + +### 测试用例 +1. 功能测试(唯一只出现一次的数字分别是 0、正数、负数;重复出现三次的数字分别是 0、正数、负数)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_02_NumberAppearingOnce/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_02_NumberAppearingOnce/Solution.java" new file mode 100755 index 00000000..f275f2df --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/56_02_NumberAppearingOnce/Solution.java" @@ -0,0 +1,34 @@ +/** + * @author bingo + * @since 2018/12/10 + */ + +class Solution { + /** + * 找出数组中只出现一次的数字,其它数字都出现三次 + * + * @param nums 数字 + * @return 只出现一次的数字 + */ + public int findNumberAppearingOnce(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int[] bits = new int[32]; + int n = nums.length; + for (int i = 0; i < n; ++i) { + int val = nums[i]; + for (int j = 0; j < 32; ++j) { + bits[j] += (val & 1); + val = val >> 1; + } + } + int res = 0; + for (int i = 0; i < 32; ++i) { + if (bits[i] % 3 != 0) { + res += Math.pow(2, i); + } + } + return res; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_01_TwoNumbersWithSum/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_01_TwoNumbersWithSum/README.md" new file mode 100755 index 00000000..0b477017 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_01_TwoNumbersWithSum/README.md" @@ -0,0 +1,55 @@ +## 和为S的两个数字 + +### 题目描述 +输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。ps:对应每个测试案例,输出两个数,小的先输出。 + +### 解法 +定义两个指针,start指向数组头,end指向数组末尾。如果: + +- `sum == array[start] + array[end]`,则返回结果 +- `sum > array[start] + array[end]`,则start++,因为数组是递增的,所以从小数右边找一个大数与 `array[end]` 求和再次判断 +- 否则 end-- + +```java +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/02/02 + * @description + */ +public class Solution { + + public ArrayList FindNumbersWithSum(int[] array, int sum) { + + ArrayList reList = new ArrayList<>(); + + if (array == null || array.length < 2 || sum <= array[0]) { + return reList; + } + + int start = 0; + int end = array.length - 1; + + while (start < end) { + + int curSum = array[start] + array[end]; + if (curSum == sum) { + reList.add(array[start]); + reList.add(array[end]); + return reList; + } else if (curSum < sum) { + start++; + } else { + end--; + } + } + + // 查无 + return reList; + } +} +``` + +### 测试用例 +1. 功能测试(数组中存在和为 s 的两个数;数组中不存在和为 s 的两个数); +2. 特殊输入测试(表示数组的指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_01_TwoNumbersWithSum/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_01_TwoNumbersWithSum/Solution.java" new file mode 100755 index 00000000..71dec19e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_01_TwoNumbersWithSum/Solution.java" @@ -0,0 +1,37 @@ +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/02/02 + * @description + */ +public class Solution { + + public ArrayList FindNumbersWithSum(int[] array, int sum) { + + ArrayList reList = new ArrayList<>(); + + if (array == null || array.length < 2 || sum <= array[0]) { + return reList; + } + + int start = 0; + int end = array.length - 1; + + while (start < end) { + + int curSum = array[start] + array[end]; + if (curSum == sum) { + reList.add(array[start]); + reList.add(array[end]); + return reList; + } else if (curSum < sum) { + start++; + } else { + end--; + } + } + + // 查无 + return reList; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_02_ContinuousSquenceWithSum/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_02_ContinuousSquenceWithSum/README.md" new file mode 100755 index 00000000..c837b587 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_02_ContinuousSquenceWithSum/README.md" @@ -0,0 +1,77 @@ +## 和为S的连续正数序列 + +### 题目描述 +输入一个正数 s,打印出所有和为 s 的连续正数序列(至少含有两个数)。 + +例如输入 15,由于 `1+2+3+4+5=4+5+6=7+8=15`,所以结果打印出 3 个连续序列 1~5、4~6 和 7~8。 + +**样例** +``` +输入:15 + +输出:[[1,2,3,4,5],[4,5,6],[7,8]] +``` + +### 解法 +这道题同样利用两个指针left和right,将(1,2)作为初始序列。当序列和大于所求值,则left向前走,把最小的数排除了;当序列和小于所求值,则right向前走,把一个更大的数包进序列中;如果序列和等于所求值,则求值区间[left,right]中的所有数并加入到列表中,并且right向前走,把一个更大的值包入序列中。循环直到 `left < (sum + 1)/2` 。 + +这道题的time complexity为O(n^2),space complexity为O(1) + +```java +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/02/03 + * @description + */ +public class Solution { + + public List> findContinuousSequence(int sum) { + + List> reList = new ArrayList<>(); + + if (sum < 3) { + return reList; + } + + int left = 1; + int right = 2; + int mid = (sum + 1) / 2; + int curSum = left + right; + + // left小于sum一半即可(1/2n) + while (left < mid) { + + // 等与sum则加入列表中(2~1/2n) + if (curSum == sum) { + reList.add(getListFromleftToright(left, right)); + // right增加并重新寻找序列 + right++; + curSum += right; + } else if (curSum > sum) { + curSum -= left; + left++; + } else { + right++; + curSum += right; + } + } + + return reList; + } + + private List getListFromleftToright(int left, int right) { + + List tempList = new ArrayList<>(); + for (int i = left; i <= right; i++) { + tempList.add(i); + } + + return tempList; + } +} +``` + +### 测试用例 +1. 功能测试(存在和为 s 的连续序列,如 9、100 等;不存在和为 s 的连续序列,如 4、0 等); +2. 边界值测试(连续序列的最小和 3)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_02_ContinuousSquenceWithSum/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_02_ContinuousSquenceWithSum/Solution.java" new file mode 100755 index 00000000..c6203bcb --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/57_02_ContinuousSquenceWithSum/Solution.java" @@ -0,0 +1,52 @@ +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/02/03 + * @description + */ +public class Solution { + + public List> findContinuousSequence(int sum) { + + List> reList = new ArrayList<>(); + + if (sum < 3) { + return reList; + } + + int left = 1; + int right = 2; + int mid = (sum + 1) / 2; + int curSum = left + right; + + // left小于sum一半即可(1/2n) + while (left < mid) { + + // 等与sum则加入列表中(2~1/2n) + if (curSum == sum) { + reList.add(getListFromleftToright(left, right)); + // right增加并重新寻找序列 + right++; + curSum += right; + } else if (curSum > sum) { + curSum -= left; + left++; + } else { + right++; + curSum += right; + } + } + + return reList; + } + + private List getListFromleftToright(int left, int right) { + + List tempList = new ArrayList<>(); + for (int i = left; i <= right; i++) { + tempList.add(i); + } + + return tempList; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_01_ReverseWordsInSentence/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_01_ReverseWordsInSentence/README.md" new file mode 100755 index 00000000..5360b9cf --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_01_ReverseWordsInSentence/README.md" @@ -0,0 +1,55 @@ +## [ 翻转单词顺序](https://www.acwing.com/problem/content/73/) + +### 题目描述 +输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。 + +为简单起见,标点符号和普通字母一样处理。 + +例如输入字符串 `"I am a student."`,则输出 `"student. a am I"`。 + +**样例** +``` +输入:"I am a student." + +输出:"student. a am I" +``` + +### 解法 +先对字符串按空格切割成数组,再逆序数组后,最后将元素拼接并返回。 + +```java +/** + * @author bingo + * @since 2018/12/12 + */ + +class Solution { + /** + * 翻转单词 + * + * @param s 字符串 + * @return 翻转后的字符串 + */ + public String reverseWords(String s) { + if (s == null || s.length() == 0 || s.trim().equals("")) { + return s; + } + + String[] arr = s.split(" "); + int p = 0, q = arr.length - 1; + while (p < q) { + swap(arr, p++, q--); + } + return String.join(" ", arr); + } + private void swap(String[] arr, int p, int q) { + String t = arr[p]; + arr[p] = arr[q]; + arr[q] = t; + } +} +``` + +### 测试用例 +1. 功能测试(句子中有多个单词;句子中只有一个单词); +2. 特殊输入测试(字符串指针为空指针;字符串的内容为空;字符串中只有空格)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_01_ReverseWordsInSentence/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_01_ReverseWordsInSentence/Solution.java" new file mode 100755 index 00000000..50ed9a1d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_01_ReverseWordsInSentence/Solution.java" @@ -0,0 +1,31 @@ +/** + * @author bingo + * @since 2018/12/12 + */ + +class Solution { + /** + * 翻转单词 + * + * @param s 字符串 + * @return 翻转后的字符串 + */ + public String reverseWords(String s) { + if (s == null || s.length() == 0 || s.trim().equals("")) { + return s; + } + + String[] arr = s.split(" "); + int p = 0, q = arr.length - 1; + while (p < q) { + swap(arr, p++, q--); + } + return String.join(" ", arr); + } + + private void swap(String[] arr, int p, int q) { + String t = arr[p]; + arr[p] = arr[q]; + arr[q] = t; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_02_LeftRotateString/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_02_LeftRotateString/README.md" new file mode 100755 index 00000000..40363cf4 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_02_LeftRotateString/README.md" @@ -0,0 +1,67 @@ +## [左旋转字符串](https://www.acwing.com/problem/content/74/) + +### 题目描述 +字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。 + +请定义一个函数实现字符串左旋转操作的功能。 + +比如输入字符串 `"abcdefg"` 和数字 2,该函数将返回左旋转 2 位得到的结果 `"cdefgab"`。 + +**注意:** + +- 数据保证 n 小于等于输入字符串的长度。 + +**样例** +``` +输入:"abcdefg" , n=2 + +输出:"cdefgab" +``` + +### 解法 +先翻转前 n 个字符,再翻转后面的字符,最后整体翻转。 + +```java +/** + * @author bingo + * @since 2018/12/12 + */ + +class Solution { + + /** + * 左旋转字符串 + * + * @param str 字符串 + * @param n 左旋的位数 + * @return 旋转后的字符串 + */ + public String leftRotateString(String str, int n) { + if (str == null || n < 1 || n > str.length()) { + return str; + } + char[] chars = str.toCharArray(); + int len = chars.length; + reverse(chars, 0, n - 1); + reverse(chars, n, len - 1); + reverse(chars, 0, len - 1); + return new String(chars); + } + + private void reverse(char[] chars, int p, int q) { + while (p < q) { + swap(chars, p++, q--); + } + } + + private void swap(char[] chars, int p, int q) { + char t = chars[p]; + chars[p] = chars[q]; + chars[q] = t; + } +} +``` + +### 测试用例 +1. 功能测试(把长度为 n 的字符串左旋转 0/1/2/n-1/n/n+1 个字符); +2. 特殊输入测试(字符串指针为空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_02_LeftRotateString/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_02_LeftRotateString/Solution.java" new file mode 100755 index 00000000..e61d8ae8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/58_02_LeftRotateString/Solution.java" @@ -0,0 +1,38 @@ +/** + * @author bingo + * @since 2018/12/12 + */ + +class Solution { + + /** + * 左旋转字符串 + * + * @param str 字符串 + * @param n 左旋的位数 + * @return 旋转后的字符串 + */ + public String leftRotateString(String str, int n) { + if (str == null || n < 1 || n > str.length()) { + return str; + } + char[] chars = str.toCharArray(); + int len = chars.length; + reverse(chars, 0, n - 1); + reverse(chars, n, len - 1); + reverse(chars, 0, len - 1); + return new String(chars); + } + + private void reverse(char[] chars, int p, int q) { + while (p < q) { + swap(chars, p++, q--); + } + } + + private void swap(char[] chars, int p, int q) { + char t = chars[p]; + chars[p] = chars[q]; + chars[q] = t; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/59_01_MaxInSlidingWindow/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/59_01_MaxInSlidingWindow/README.md" new file mode 100755 index 00000000..f568e9b3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/59_01_MaxInSlidingWindow/README.md" @@ -0,0 +1,75 @@ +## 滑动窗口的最大值 + +### 题目描述 +给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。 + +例如,如果输入数组 `[2, 3, 4, 2, 6, 2, 5, 1]` 及滑动窗口的大小 3,那么一共存在 6 个滑动窗口,它们的最大值分别为 `[4, 4, 6, 6, 6, 5]`。 + +**注意:** + +- 数据保证 k 大于 0,且 k 小于等于数组长度。 + +**样例** + +``` +输入:[2, 3, 4, 2, 6, 2, 5, 1] , k=3 + +输出: [4, 4, 6, 6, 6, 5] +``` + +### 解法 +使用一个双端队列,保证队首存放的是窗口最大值的下标。遍历数组, + +1. 队尾元素比要入队的元素小,则把其移除(因为不可能成为窗口最大值)。 +2. 队首下标对应的元素不在窗口内(即窗口最大值),将其从队列中移除。 +3. 把每次滑动值的下标加入队列中(经过步骤1、2,此时加入队列的下标要么是当前窗口最大值的下标,要么是小于窗口最大值的下标)。 +4. 滑动窗口的首地址i大于size就写入窗口最大值。 + +time complexity:O(n) + +space complexity:O(k) , k is the size + +```java +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/02/05 + * @description + */ +class Solution { + + public ArrayList maxInWindows(int[] num, int size) { + + ArrayList reList = new ArrayList<>(); + if (num == null || num.length < size || size < 1) { + return reList; + } + + Deque deque = new LinkedList<>(); + for (int i = 0; i < num.length; i++) { + + // 队尾元素比要入队的元素小,则把其移除(因为不可能成为窗口最大值) + while (!deque.isEmpty() && num[deque.getLast()] <= num[i]) { + deque.pollLast(); + } + // 队首下标对应的元素不在窗口内(即窗口最大值),将其从队列中移除 + while (!deque.isEmpty() && (i - deque.getFirst() + 1 > size)) { + deque.pollFirst(); + } + // 把每次滑动的值加入到队列中 + deque.add(i); + // 滑动窗口的首地址i大于size就写入窗口最大值 + if (!deque.isEmpty() && i + 1 >= size) { + reList.add(num[deque.getFirst()]); + } + } + + return reList; + } +} +``` + +### 测试用例 +1. 功能测试(输入数组的数字大小无序;输入数组的数字单调递增;输入数组的数字单调递减); +2. 边界值测试(滑动窗口的大小为 0、1、等于输入数组的长度、大于输入数组的长度); +3. 特殊输入测试(输入数组为空)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/59_01_MaxInSlidingWindow/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/59_01_MaxInSlidingWindow/Solution.java" new file mode 100755 index 00000000..a46be4eb --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/59_01_MaxInSlidingWindow/Solution.java" @@ -0,0 +1,37 @@ +/** + * @author mcrwayfun + * @version v1.0 + * @date Created in 2019/02/05 + * @description + */ +class Solution { + + public ArrayList maxInWindows(int[] num, int size) { + + ArrayList reList = new ArrayList<>(); + if (num == null || num.length < size || size < 1) { + return reList; + } + + Deque deque = new LinkedList<>(); + for (int i = 0; i < num.length; i++) { + + // 队尾元素比要入队的元素小,则把其移除(因为不可能成为窗口最大值) + while (!deque.isEmpty() && num[deque.getLast()] <= num[i]) { + deque.pollLast(); + } + // 队首下标对应的元素不在窗口内(即窗口最大值),将其从队列中移除 + while (!deque.isEmpty() && (i - deque.getFirst() + 1 > size)) { + deque.pollFirst(); + } + // 把每次滑动的值加入到队列中 + deque.add(i); + // 滑动窗口的首地址i大于size就写入窗口最大值 + if (!deque.isEmpty() && i + 1 >= size) { + reList.add(num[deque.getFirst()]); + } + } + + return reList; + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/61_ContinousCards/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/61_ContinousCards/README.md" new file mode 100755 index 00000000..d5c7d0e5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/61_ContinousCards/README.md" @@ -0,0 +1,78 @@ +## [扑克牌的顺子](https://www.acwing.com/problem/content/77/) + +### 题目描述 +从扑克牌中随机抽 `5` 张牌,判断是不是一个顺子,即这5张牌是不是连续的。 + +`2~10` 为数字本身,`A` 为`1`,`J` 为 `11`,`Q` 为 `12`,`K` 为 `13`,大小王可以看做任意数字。 + +为了方便,大小王均以 `0` 来表示,并且假设这副牌中大小王均有两张。 + +**样例1** +``` +输入:[8,9,10,11,12] + +输出:true +``` + +**样例2** +``` +输入:[0,8,9,11,12] + +输出:true +``` + +### 解法 +- 对数组排序; +- 计算出 0 的个数 `zeroCount`; +- 从第一个不是 0 的数字开始遍历,与后一个数字比较,如果相等,直接返回 `false`;否则累计 `gap`; +- 判断 `zeroCount` 是否大于等于 `gap`。 + + +```java +import java.util.Arrays; + +/** + * @author bingo + * @since 2018/12/12 + */ + +class Solution { + + /** + * 判断是否是连续的数字 + * + * @param numbers 数组 + * @return 是否是顺子 + */ + public boolean isContinuous(int [] numbers) { + if (numbers == null || numbers.length == 0) { + return false; + } + int zeroCount = 0; + Arrays.sort(numbers); + for (int e : numbers) { + if (e > 0) { + break; + } + ++zeroCount; + } + + int p = zeroCount, q = p + 1, n = numbers.length; + int gap = 0; + while (q < n) { + if (numbers[p] == numbers[q]) { + return false; + } + gap += (numbers[q] - numbers[p] - 1); + p = q; + ++q; + } + return gap <= zeroCount; + + } +} +``` + +### 测试用例 +1. 功能测试(抽出的牌中有一个或者多个大、小王;抽出的牌中没有大、小王;抽出的牌中有对子); +2. 特殊输入测试(输入空指针)。 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/61_ContinousCards/Solution.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/61_ContinousCards/Solution.java" new file mode 100755 index 00000000..158b495e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/61_ContinousCards/Solution.java" @@ -0,0 +1,42 @@ +import java.util.Arrays; + +/** + * @author bingo + * @since 2018/12/12 + */ + +class Solution { + + /** + * 判断是否是连续的数字 + * + * @param numbers 数组 + * @return 是否是顺子 + */ + public boolean isContinuous(int[] numbers) { + if (numbers == null || numbers.length == 0) { + return false; + } + int zeroCount = 0; + Arrays.sort(numbers); + for (int e : numbers) { + if (e > 0) { + break; + } + ++zeroCount; + } + + int p = zeroCount, q = p + 1, n = numbers.length; + int gap = 0; + while (q < n) { + if (numbers[p] == numbers[q]) { + return false; + } + gap += (numbers[q] - numbers[p] - 1); + p = q; + ++q; + } + return gap <= zeroCount; + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Java/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/README.md" new file mode 100755 index 00000000..4709905e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Java/README.md" @@ -0,0 +1,69 @@ +# [《剑指 Offer》 Java 版实现](https://github.com/doocs/coding-interview) + +| # | Title | +|---|---| +| 03_01 | [Find Duplication In Array](/docs/剑指offer/Java/03_01_DuplicationInArray) | +| 03_02 | [Find Duplication In Array II](/docs/剑指offer/Java/03_02_DuplicationInArrayNoEdit) | +| 04 | [Find In Partially Sorted Matrix](/docs/剑指offer/Java/04_FindInPartiallySortedMatrix) | +| 05 | [Replace Spaces](/docs/剑指offer/Java/05_ReplaceSpaces) | +| 06 | [Print List In Reversed Order](/docs/剑指offer/Java/06_PrintListInReversedOrder) | +| 07 | [Construct Binary Tree](/docs/剑指offer/Java/07_ConstructBinaryTree) | +| 08 | [Next Node In Binary Trees](/docs/剑指offer/Java/08_NextNodeInBinaryTrees) | +| 09_01 | [Queue With Two Stacks](/docs/剑指offer/Java/09_01_QueueWithTwoStacks) | +| 09_02 | [Stack With Two Queues](/docs/剑指offer/Java/09_02_StackWithTwoQueues) | +| 10_01 | [Fibonacci](/docs/剑指offer/Java/10_01_Fibonacci) | +| 10_02 | [Jump Floor](/docs/剑指offer/Java/10_02_JumpFloor) | +| 10_03 | [Jump Floor II](/docs/剑指offer/Java/10_03_JumpFloorII) | +| 10_04 | [Rect Cover](/docs/剑指offer/Java/10_04_RectCover) | +| 11 | [Min Number In Rotated Array](/docs/剑指offer/Java/11_MinNumberInRotatedArray) | +| 12 | [String Path In Matrix](/docs/剑指offer/Java/12_StringPathInMatrix) | +| 13 | [Robot Move](/docs/剑指offer/Java/13_RobotMove) | +| 14 | [Cutting Rope](/docs/剑指offer/Java/14_CuttingRope) | +| 15 | [Number Of 1 In Binary](/docs/剑指offer/Java/15_NumberOf1InBinary) | +| 16 | [Power](/docs/剑指offer/Java/16_Power) | +| 17 | [Print 1 To Max Of N Digits](/docs/剑指offer/Java/17_Print1ToMaxOfNDigits) | +| 18_01 | [Delete Node In List](/docs/剑指offer/Java/18_01_DeleteNodeInList) | +| 18_02 | [Delete Duplicated Node](/docs/剑指offer/Java/18_02_DeleteDuplicatedNode) | +| 19 | [Regular Expressions Matching](/docs/剑指offer/Java/19_RegularExpressionsMatching) | +| 20 | [Numeric Strings](/docs/剑指offer/Java/20_NumericStrings) | +| 21 | [Reorder Array](/docs/剑指offer/Java/21_ReorderArray) | +| 22 | [Kth Node From End](/docs/剑指offer/Java/22_KthNodeFromEnd) | +| 23 | [Entry Node In List Loop](/docs/剑指offer/Java/23_EntryNodeInListLoop) | +| 24 | [Reverse List](/docs/剑指offer/Java/24_ReverseList) | +| 25 | [Merge Sorted Lists](/docs/剑指offer/Java/25_MergeSortedLists) | +| 26 | [Substructure In Tree](/docs/剑指offer/Java/26_SubstructureInTree) | +| 27 | [Mirror Of Binary Tree](/docs/剑指offer/Java/27_MirrorOfBinaryTree) | +| 28 | [Symmetrical Binary Tree](/docs/剑指offer/Java/28_SymmetricalBinaryTree) | +| 29 | [Print Matrix](/docs/剑指offer/Java/29_PrintMatrix) | +| 30 | [Min In Stack](/docs/剑指offer/Java/30_MinInStack) | +| 31 | [Stack Push Pop Order](/docs/剑指offer/Java/31_StackPushPopOrder) | +| 32_01 | [Print Tree From Top To Bottom](/docs/剑指offer/Java/32_01_PrintTreeFromTopToBottom) | +| 32_02 | [Print Trees In Lines](/docs/剑指offer/Java/32_02_PrintTreesInLines) | +| 32_03 | [Print Trees In Zigzag](/docs/剑指offer/Java/32_03_PrintTreesInZigzag) | +| 33 | [Squence Of BST](/docs/剑指offer/Java/33_SquenceOfBST) | +| 34 | [Path In Tree](/docs/剑指offer/Java/34_PathInTree) | +| 35 | [Copy Complex List](/docs/剑指offer/Java/35_CopyComplexList) | +| 36 | [Convert Binary Search Tree](/docs/剑指offer/Java/36_ConvertBinarySearchTree) | +| 39 | [More Than Half Number](/docs/剑指offer/Java/39_MoreThanHalfNumber) | +| 40 | [K Least Numbers](/docs/剑指offer/Java/40_KLeastNumbers) | +| 41 | [Stream Median](/docs/剑指offer/Java/41_StreamMedian) | +| 42 | [Greatest Sum Of Subarrays](/docs/剑指offer/Java/42_GreatestSumOfSubarrays) | +| 44 | [Digits In Sequence](/docs/剑指offer/Java/44_DigitsInSequence) | +| 45 | [Sort Array For Min Number](/docs/剑指offer/Java/45_SortArrayForMinNumber) | +| 46 | [Translate Numbers To Strings](/docs/剑指offer/Java/46_TranslateNumbersToStrings) | +| 47 | [Max Value Of Gifts](/docs/剑指offer/Java/47_MaxValueOfGifts) | +| 48 | [Longest Substring Without Dup](/docs/剑指offer/Java/48_LongestSubstringWithoutDup) | +| 52 | [First Common Nodes In Lists](/docs/剑指offer/Java/52_FirstCommonNodesInLists) | +| 53_01 | [Number Of K](/docs/剑指offer/Java/53_01_NumberOfK) | +| 53_02 | [Missing Number](/docs/剑指offer/Java/53_02_MissingNumber) | +| 53_03 | [Integer Identical To Index](/docs/剑指offer/Java/53_03_IntegerIdenticalToIndex) | +| 55_01 | [Tree Depth](/docs/剑指offer/Java/55_01_TreeDepth) | +| 55_02 | [Balanced Binary Tree](/docs/剑指offer/Java/55_02_BalancedBinaryTree) | +| 56_01 | [Numbers Appear Once](/docs/剑指offer/Java/56_01_NumbersAppearOnce) | +| 56_02 | [Number Appearing Once](/docs/剑指offer/Java/56_02_NumberAppearingOnce) | +| 57_01 | [Two Numbers With Sum](/docs/剑指offer/Java/57_01_TwoNumbersWithSum) | +| 57_02 | [Continuous Squence With Sum](/docs/剑指offer/Java/57_02_ContinuousSquenceWithSum) | +| 58_01 | [Reverse Words In Sentence](/docs/剑指offer/Java/58_01_ReverseWordsInSentence) | +| 58_02 | [Left Rotate String](/docs/剑指offer/Java/58_02_LeftRotateString) | +| 59_01 | [Max In Sliding Window](/docs/剑指offer/Java/59_01_MaxInSlidingWindow) | +| 61 | [Continous Cards](/docs/剑指offer/Java/61_ContinousCards) | diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/01-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.js" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/01-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.js" new file mode 100755 index 00000000..cccb4664 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/01-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.js" @@ -0,0 +1,13 @@ +function Find(target, array) +{ + // write code here + const num_row = array.length; + for(let i=0; i -1) { + return true + } + } +} +module.exports = { + Find : Find +}; diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/02-\346\233\277\346\215\242\347\251\272\346\240\274.js" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/02-\346\233\277\346\215\242\347\251\272\346\240\274.js" new file mode 100755 index 00000000..c695f8af --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/02-\346\233\277\346\215\242\347\251\272\346\240\274.js" @@ -0,0 +1,11 @@ +function replaceSpace(str) +{ + // write code here + let strArr = str.split(''); + return strArr.reduce((pre, next) => { + return pre + (next === ' ' ? '%20' : next) + }, ''); +} +module.exports = { + replaceSpace : replaceSpace +}; diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/03-\344\273\216\345\244\264\345\210\260\345\260\276\346\211\223\345\215\260\351\223\276\350\241\250.js" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/03-\344\273\216\345\244\264\345\210\260\345\260\276\346\211\223\345\215\260\351\223\276\350\241\250.js" new file mode 100755 index 00000000..0d233732 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/03-\344\273\216\345\244\264\345\210\260\345\260\276\346\211\223\345\215\260\351\223\276\350\241\250.js" @@ -0,0 +1,20 @@ +/*function ListNode(x){ + this.val = x; + this.next = null; +}*/ +function printListFromTailToHead(head) +{ + // write code here + let arr = []; + if (!head) { + return arr; + } + while(head) { + arr.unshift(head.val) + head=head.next + } + return arr; +} +module.exports = { + printListFromTailToHead : printListFromTailToHead +}; diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/05-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.js" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/05-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.js" new file mode 100755 index 00000000..b391be9e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/05-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.js" @@ -0,0 +1,21 @@ +let stack1 = []; +let stack2 = []; +function push(node) +{ + // write code here + stack1.push(node) +} +function pop() +{ + // write code here + if(stack2.length === 0) { + while (stack1.length!==0) { + stack2.push(stack1.pop()) + } + } + return stack2.pop() +} +module.exports = { + push : push, + pop : pop +}; diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/06-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.js" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/06-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.js" new file mode 100755 index 00000000..670da1b8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/06-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.js" @@ -0,0 +1,12 @@ +function minNumberInRotateArray(rotateArray) +{ + // write code here + if (rotateArray.length === 0) { + return 0; + } else { + return Math.min.apply(null, rotateArray) + } +} +module.exports = { + minNumberInRotateArray : minNumberInRotateArray +}; diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/07-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.js" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/07-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.js" new file mode 100755 index 00000000..f93eb1b9 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/07-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.js" @@ -0,0 +1,17 @@ +function Fibonacci(n) +{ + // write code here + if (n===0 || n===1) { + return n; + } + let n1 = 0, n2=1, sum=1; + for(let i=2;i<=n;i++) { + sum = n1+n2; + n1=n2; + n2=sum; + } + return sum; +} +module.exports = { + Fibonacci : Fibonacci +}; diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/08-\350\267\263\345\217\260\351\230\266.js" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/08-\350\267\263\345\217\260\351\230\266.js" new file mode 100755 index 00000000..c339dee3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/08-\350\267\263\345\217\260\351\230\266.js" @@ -0,0 +1,23 @@ +/** + * + * @param {number} number + * 思路: n级台阶只能由第n-1和第n-2级台阶跳上来,得到动态规划方程 + */ + +function jumpFloor(number) +{ + // write code here + if(number===0) return 0; + if(number==1)return 1; + if(number===2) return 2; + let a=1, b=2, sum=0; + for(let i=3; i<= number; i++) { + sum=a+b; + a=b; + b=sum; + } + return sum; +} +module.exports = { + jumpFloor : jumpFloor +}; diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/09-\345\217\230\346\200\201\350\267\263\345\217\260\351\230\266.js" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/09-\345\217\230\346\200\201\350\267\263\345\217\260\351\230\266.js" new file mode 100755 index 00000000..a88df29e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/09-\345\217\230\346\200\201\350\267\263\345\217\260\351\230\266.js" @@ -0,0 +1,20 @@ +function sumArr(arr) { + return arr.reduce((pre, next) => pre+next) +} + +function jumpFloorII(number) +{ + // write code here + if(number===0) return 0; + if(number==1)return 1; + if(number===2) return 2; + let ans = [1,2]; + for(let i=3;i<=number;i++) { + // 额外加一是可以直接跳到第n级台阶 + ans.push(sumArr(ans)+1); + } + return ans[ans.length -1]; +} +module.exports = { + jumpFloorII : jumpFloorII +}; diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/README.md" new file mode 100755 index 00000000..d02bbf3a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/JavaScript/README.md" @@ -0,0 +1,2 @@ +# Jianzhi-offer + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/01-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/01-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.py" new file mode 100755 index 00000000..7656a30f --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/01-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.py" @@ -0,0 +1,20 @@ +# -*- coding:utf-8 -*- +class Solution: + # array 二维列表 + def Find(self, target, array): + # write code here + if array == []: + return False + num_row = len(array) + num_col = len(array[0]) + + i = num_col - 1 + j = 0 + + while i >= 0 and j < num_row: + if array[j][i] > target: + i -= 1 + elif array[j][i] < target: + j += 1 + else: + return True \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/02-\346\233\277\346\215\242\347\251\272\346\240\274.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/02-\346\233\277\346\215\242\347\251\272\346\240\274.py" new file mode 100755 index 00000000..416e4a1e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/02-\346\233\277\346\215\242\347\251\272\346\240\274.py" @@ -0,0 +1,24 @@ +class Solution: + # s 源字符串 + def replaceSpace(self, s): + # write code here + if not isinstance(s, str) or len(s) <= 0 or s == None: + return '' + spaceNum = 0 + for i in s: + if i == " ": + spaceNum += 1 + + newStrLen = len(s) + spaceNum * 2 + newStr = newStrLen * [None] + indexOfOriginal, indexOfNew = len(s) - 1, newStrLen - 1 + while indexOfNew >= 0 and indexOfOriginal <= indexOfNew: + if s[indexOfOriginal] == ' ': + newStr[indexOfNew - 2: indexOfNew + 1] = ['%', '2', '0'] + indexOfNew -= 3 + indexOfOriginal -= 1 + else: + newStr[indexOfNew] = s[indexOfOriginal] + indexOfNew -= 1 + indexOfOriginal -= 1 + return ''.join(newStr) \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/03-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/03-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.py" new file mode 100755 index 00000000..d24761ab --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/03-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.py" @@ -0,0 +1,19 @@ +# -*- coding:utf-8 -*- +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + +class Solution: + # 返回从尾部到头部的列表值序列,例如[1,2,3] + def printListFromTailToHead(self, listNode): + # write code here + if not listNode: + return [] + + result =[] + + while listNode: + result.insert(0, listNode.val) + listNode = listNode.next + return result \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/04-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/04-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.py" new file mode 100755 index 00000000..a99dc80f --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/04-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1,19 @@ +# -*- coding:utf-8 -*- +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None +class Solution: + # 返回构造的TreeNode根节点 + def reConstructBinaryTree(self, pre, tin): + # write code here + if not pre and not tin: + return None + root = TreeNode(pre[0]) + if set(pre) != set(tin): + return None + i = tin.index(pre[0]) + root.left = self.reConstructBinaryTree(pre[1:i+1],tin[:i]) + root.right = self.reConstructBinaryTree(pre[i+1:], tin[i+1:]) + return root \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/05-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/05-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" new file mode 100755 index 00000000..93d0d7f7 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/05-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" @@ -0,0 +1,19 @@ +# -*- coding:utf-8 -*- +class Solution: + def __init__(self): + self.stack1 = [] + self.stack2 = [] + + def push(self, node): + # write code here + self.stack1.append(node) + + def pop(self): + # return xx + if len(self.stack1) == 0 and len(self.stack2) == 0: + return + elif len(self.stack2) == 0: + while len(self.stack1) > 0: + self.stack2.append(self.stack1.pop()) + + return self.stack2.pop() \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/06-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/06-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.py" new file mode 100755 index 00000000..b6ea7192 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/06-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +class Solution: + def minNumberInRotateArray(self, rotateArray): + # write code here + if len(rotateArray) == 0: + return 0 + front = 0 + rear = len(rotateArray) - 1 + minVal = rotateArray[0] + + if rotateArray[front] < rotateArray[rear]: + return rotateArray[front] + else: + while (rear - front) > 1: + mid = (front + rear) // 2 + if rotateArray[front] == rotateArray[rear] == rotateArray[mid]: + for i in range(1, len(rotateArray)): + if rotateArray[i] < minVal: + minVal = rotateArray[i] + rear = i + elif rotateArray[mid] >= rotateArray[front]: + front = mid + elif rotateArray[mid] <= rotateArray[rear]: + rear = mid + minVal = rotateArray[rear] + return minVal diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/07-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/07-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.py" new file mode 100755 index 00000000..49463d32 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/07-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.py" @@ -0,0 +1,9 @@ +# -*- coding:utf-8 -*- +class Solution: + def Fibonacci(self, n): + # write code here + tempArray = [0,1] + if n >= 2: + for i in range(2, n+1): + tempArray[i%2] = tempArray[0] + tempArray[1] + return tempArray[n%2] \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/08-\350\267\263\345\217\260\351\230\266.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/08-\350\267\263\345\217\260\351\230\266.py" new file mode 100755 index 00000000..a66d6d60 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/08-\350\267\263\345\217\260\351\230\266.py" @@ -0,0 +1,9 @@ +# -*- coding:utf-8 -*- +class Solution: + def jumpFloor(self, number): + # write code here + tempArray = [1, 2] + if number >= 3: + for i in range(3, number+1): + tempArray[(i+1)%2] = tempArray[0] + tempArray[1] + return tempArray[(number + 1)%2] \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/09-\345\217\230\346\200\201\350\267\263\345\217\260\351\230\266.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/09-\345\217\230\346\200\201\350\267\263\345\217\260\351\230\266.py" new file mode 100755 index 00000000..75ea747b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/09-\345\217\230\346\200\201\350\267\263\345\217\260\351\230\266.py" @@ -0,0 +1,9 @@ +# -*- coding:utf-8 -*- +class Solution: + def jumpFloorII(self, number): + # write code here + ans = 1 + if number >= 2: + for i in range(number-1): + ans = ans * 2 + return ans \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/10-\347\237\251\345\275\242\350\246\206\347\233\226.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/10-\347\237\251\345\275\242\350\246\206\347\233\226.py" new file mode 100755 index 00000000..6a460834 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/10-\347\237\251\345\275\242\350\246\206\347\233\226.py" @@ -0,0 +1,11 @@ +# -*- coding:utf-8 -*- +class Solution: + def rectCover(self, number): + # write code here + if number == 0: + return 0 + tempArray = [1,2] + if number >= 3: + for i in range(3,number+1): + tempArray[(i+1)%2] = tempArray[0] + tempArray[1] + return tempArray[(number+1)%2] \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/11-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/11-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.py" new file mode 100755 index 00000000..8eff8b6c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/11-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.py" @@ -0,0 +1,10 @@ +class Solution: + def NumberOf1(self, n): + # write code here + count = 0 + if n < 0: + n = n & 0xffffffff + while n != 0: + count += 1 + n = (n - 1) & n + return count \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/12-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/12-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.py" new file mode 100755 index 00000000..db81f069 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/12-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.py" @@ -0,0 +1,23 @@ +class Solution: + def Power(self, base, exponent): + # write code here + try: + ret = self.power_value(base, abs(exponent)) + if exponent < 0: + return 1.0 / ret + + except ZeroDivisionError: + print('Error: base is zero') + else: + return ret + + def power_value(self,base, exponent): + if exponent == 0: + return 1 + if exponent == 1: + return base + ret = self.power_value(base, exponent >> 1) + ret *= ret + if exponent & 1 == 1: + ret *= base + return ret \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/13-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/13-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.py" new file mode 100755 index 00000000..9c5486ca --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/13-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.py" @@ -0,0 +1,4 @@ +class Solution: + def reOrderArray(self, array): + # write code here + return sorted(array,key=lambda c:c%2,reverse=True) \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/14-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/14-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271.py" new file mode 100755 index 00000000..fa5aa591 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/14-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271.py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def FindKthToTail(self, head, k): + # write code here + if head == None or k <= 0: + return None + + pAhead = head + pBhead = None + + for i in range(k-1): + if pAhead.next != None: + pAhead = pAhead.next + else: + return None + + pBhead = head + while pAhead.next != None: + pAhead = pAhead.next + pBhead = pBhead.next + return pBhead \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/15-\345\217\215\350\275\254\351\223\276\350\241\250.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/15-\345\217\215\350\275\254\351\223\276\350\241\250.py" new file mode 100755 index 00000000..8997caa8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/15-\345\217\215\350\275\254\351\223\276\350\241\250.py" @@ -0,0 +1,21 @@ +# -*- coding:utf-8 -*- +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +class Solution: + # 返回ListNode + def ReverseList(self, pHead): + # write code here + pReversedHead = None + pNode = pHead + pPrev = None + while pNode != None: + pNext = pNode.next + if pNext == None: + pReversedHead = pNode + + pNode.next = pPrev + pPrev = pNode + pNode = pNext + return pReversedHead \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/16-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/16-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.py" new file mode 100755 index 00000000..768421a2 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/16-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.py" @@ -0,0 +1,22 @@ +# -*- coding:utf-8 -*- +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +class Solution: + # 返回合并后列表 + def Merge(self, pHead1, pHead2): + # write code here + if pHead1 == None: + return pHead2 + if pHead2 == None: + return pHead1 + + pMergeHead = None + if pHead1.val < pHead2.val: + pMergeHead = pHead1 + pMergeHead.next = self.Merge(pHead1.next,pHead2) + else: + pMergeHead = pHead2 + pMergeHead.next = self.Merge(pHead1,pHead2.next) + return pMergeHead \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/17-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/17-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.py" new file mode 100755 index 00000000..f7e41b50 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/17-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.py" @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + def HasSubtree(self, pRoot1, pRoot2): + # write code here + result = False + if pRoot1 != None and pRoot2 != None: + if pRoot1.val == pRoot2.val: + result = self.DoesTree1haveTree2(pRoot1,pRoot2) + if not result: + result = self.HasSubtree(pRoot1.left,pRoot2) + if not result: + result = self.HasSubtree(pRoot1.right,pRoot2) + + return result + + def DoesTree1haveTree2(self,pRoot1,pRoot2): + if pRoot2 == None: + return True + if pRoot1 == None: + return False + if pRoot1.val != pRoot2.val: + return False + + return self.DoesTree1haveTree2(pRoot1.left, pRoot2.left) and self.DoesTree1haveTree2(pRoot1.right, pRoot2.right) \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/18-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/18-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.py" new file mode 100755 index 00000000..6d9fb0f4 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/18-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.py" @@ -0,0 +1,21 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + # 返回镜像树的根节点 + def Mirror(self, root): + # write code here + if root == None: + return + if root.left == None and root.right == None: + return root + + ptemp = root.left + root.left = root.right + root.right = ptemp + + self.Mirror(root.left) + self.Mirror(root.right) \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/19-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/19-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.py" new file mode 100755 index 00000000..1c2c50df --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/19-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.py" @@ -0,0 +1,41 @@ +class Solution: + # matrix类型为二维列表,需要返回列表 + def printMatrix(self, matrix): + if not matrix: + return [] + + rows = len(matrix) + columns = len(matrix[0]) + start = 0 + result = [] + while rows > start * 2 and columns > start * 2: + self.PrintMatrixInCircle(matrix, columns, rows, start,result) + start += 1 + return result + + def PrintMatrixInCircle(self, matrix, columns, rows,start,result): + endX = columns - 1 - start + endY = rows - 1 - start + + # 从左到右打印一行 + for i in range(start, endX+1): + #number = matrix[start][i] + result.append(matrix[start][i]) + + # 从上到下打印一行 + if start < endY: + for i in range(start+1, endY+1): + #number = matrix[i][endX] + result.append(matrix[i][endX]) + + # 从右到左打印一行 + if start < endX and start < endY: + for i in range(endX-1, start-1, -1): + #number = matrix[endY][i] + result.append(matrix[endY][i]) + + # 从下到上打印一行 + if start < endX and start < endY-1: + for i in range(endY-1, start, -1): + #number = matrix[i][start] + result.append(matrix[i][start]) \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/20-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/20-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.py" new file mode 100755 index 00000000..6d55025a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/20-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.py" @@ -0,0 +1,29 @@ +# -*- coding:utf-8 -*- +class Solution: + def __init__(self): + self.stack = [] + self.minStack = [] + + def push(self, node): + # write code here + self.stack.append(node) + if self.minStack == [] or node < self.min(): + self.minStack.append(node) + else: + temp = self.min() + self.minStack.append(temp) + + def pop(self): + # write code here + if self.stack == None or self.minStack == None: + return None + self.minStack.pop() + self.stack.pop() + + def top(self): + # write code here + return self.stack[-1] + + def min(self): + # write code here + return self.minStack[-1] \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/21-\346\240\210\347\232\204\345\216\213\345\205\245\343\200\201\345\274\271\345\207\272\345\272\217\345\210\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/21-\346\240\210\347\232\204\345\216\213\345\205\245\343\200\201\345\274\271\345\207\272\345\272\217\345\210\227.py" new file mode 100755 index 00000000..513b7971 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/21-\346\240\210\347\232\204\345\216\213\345\205\245\343\200\201\345\274\271\345\207\272\345\272\217\345\210\227.py" @@ -0,0 +1,18 @@ +# -*- coding:utf-8 -*- +class Solution: + def IsPopOrder(self, pushV, popV): + # write code here + if pushV == [] or popV == []: + return False + + stack = [] + for i in pushV: + stack.append(i) + while len(stack) and stack[-1] == popV[0]: + stack.pop() + popV.pop(0) + + if len(stack): + return False + else: + return True \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/22-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/22-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" new file mode 100755 index 00000000..d90b7678 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/22-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + # 返回从上到下每个节点值列表,例:[1,2,3] + def PrintFromTopToBottom(self, root): + # write code here + if root is None: + return [] + queue = [] + result = [] + + queue.append(root) + while len(queue) > 0: + currentRoot = queue.pop(0) + result.append(currentRoot.val) + if currentRoot.left: + queue.append(currentRoot.left) + if currentRoot.right: + queue.append(currentRoot.right) + + return result \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/23-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/23-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227.py" new file mode 100755 index 00000000..f479113b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/23-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227.py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +class Solution: + def VerifySquenceOfBST(self, sequence): + # write code here + if sequence == []: + return False + + length = len(sequence) + root = sequence[-1] + + for i in range(length): + if sequence[i] > root: + break + + for j in range(i, length): + if sequence[j] < root: + return False + + left = True + if i > 0: + left = self.VerifySquenceOfBST(sequence[:i]) + right = True + if j < length - 1: + right = self.VerifySquenceOfBST(sequence[i:length-1]) + + return left and right \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/24-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/24-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.py" new file mode 100755 index 00000000..0836e623 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/24-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.py" @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + # 返回二维列表,内部每个列表表示找到的路径 + def FindPath(self, root, expectNumber): + # write code here + if not root or root.val > expectNumber: + return [] + + if not root.left and not root.right and root.val == expectNumber: + return [[root.val]] + else: + expectNumber -= root.val + left = self.FindPath(root.left,expectNumber) + right = self.FindPath(root.right,expectNumber) + + result = [[root.val]+i for i in left] + for i in right: + result.append([root.val]+i) + + return sorted(result, key=lambda x:-len(x)) \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/25-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/25-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.py" new file mode 100755 index 00000000..2295013e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/25-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.py" @@ -0,0 +1,40 @@ +# -*- coding:utf-8 -*- +# class RandomListNode: +# def __init__(self, x): +# self.label = x +# self.next = None +# self.random = None +class Solution: + # 返回 RandomListNode + def Clone(self, pHead): + # write code here + if not pHead: + return None + pNode = pHead + + while pNode: + pClone = RandomListNode(pNode.label) + pClone.next = pNode.next + pNode.next = pClone + pNode = pClone.next + + pNode = pHead + + while pNode: + pClone = pNode.next + if pNode.random != None: + pClone.random = pNode.random.next + pNode = pClone.next + + pNode = pHead + pCloneHead = pCloneNode = pNode.next + pNode.next = pCloneHead.next + pNode = pNode.next + + while pNode: + pCloneNode.next = pNode.next + pCloneNode = pCloneNode.next + pNode.next = pCloneNode.next + pNode = pNode.next + + return pCloneHead \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/26-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/26-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.py" new file mode 100755 index 00000000..88a4c656 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/26-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.py" @@ -0,0 +1,38 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + def Convert(self, pRootOfTree): + # write code here + if not pRootOfTree: + return None + + if not pRootOfTree.left and not pRootOfTree.right: + return pRootOfTree + + self.Convert(pRootOfTree.left) + left = pRootOfTree.left + + if left: + while left.right: + left = left.right + + pRootOfTree.left = left + left.right = pRootOfTree + + self.Convert(pRootOfTree.right) + right = pRootOfTree.right + + if right: + while right.left: + right = right.left + pRootOfTree.right = right + right.left = pRootOfTree + + while pRootOfTree.left: + pRootOfTree = pRootOfTree.left + + return pRootOfTree \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/27-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/27-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.py" new file mode 100755 index 00000000..6e20de1c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/27-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.py" @@ -0,0 +1,20 @@ +# -*- coding:utf-8 -*- +class Solution: + def Permutation(self, ss): + # write code here + if not ss: + return [] + if len(ss) == 1: + return list(ss) + + charList = list(ss) + charList.sort() + pStr = [] + for i in range(0,len(charList)): + if i > 0 and charList[i] == charList[i-1]: + continue + temp = self.Permutation(''.join(charList[:i])+''.join(charList[i+1:])) + for j in temp: + pStr.append(charList[i] + j) + + return pStr \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/28-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/28-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.py" new file mode 100755 index 00000000..1280dffe --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/28-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.py" @@ -0,0 +1,31 @@ +class Solution: + def MoreThanHalfNum_Solution(self, numbers): + # write code here + length = len(numbers) + if not numbers: + return 0 + result = numbers[0] + times = 1 + + for i in range(1,length): + if times == 0: + result = numbers[i] + times = 1 + elif numbers[i] == result: + times += 1 + else: + times -= 1 + + if not self.CheckNoreThanHalf(numbers,length,result): + return 0 + return result + + def CheckNoreThanHalf(self, numbers,length,number): + times = 0 + for i in range(length): + if numbers[i] == number: + times += 1 + + if times*2 <= length: + return False + return True \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/29-\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/29-\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260.py" new file mode 100755 index 00000000..97c0226a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/29-\346\234\200\345\260\217\347\232\204k\344\270\252\346\225\260.py" @@ -0,0 +1,17 @@ +# -*- coding:utf-8 -*- +class Solution: + def GetLeastNumbers_Solution(self, tinput, k): + # write code here + if not tinput or k > len(tinput): + return [] + tinput = self.quick_sort(tinput) + return tinput[:k] + + def quick_sort(self,lst): + if not lst: + return [] + pivot = lst[0] + left = self.quick_sort([x for x in lst[1: ] if x < pivot]) + right = self.quick_sort([x for x in lst[1: ] if x >= pivot]) + + return left + [pivot] + right \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/30-\350\277\236\347\273\255\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/30-\350\277\236\347\273\255\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.py" new file mode 100755 index 00000000..2a6df066 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/30-\350\277\236\347\273\255\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.py" @@ -0,0 +1,20 @@ +# -*- coding:utf-8 -*- +class Solution: + def FindGreatestSumOfSubArray(self, array): + # write code here + if not array: + return 0 + + cur_sum = 0 + max_sum = array[0] + + for i in range(len(array)): + if cur_sum <= 0: + cur_sum = array[i] + else: + cur_sum += array[i] + + if cur_sum > max_sum: + max_sum = cur_sum + + return max_sum \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/31-\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/31-\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" new file mode 100755 index 00000000..cefbade7 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/31-\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" @@ -0,0 +1,21 @@ +class Solution: + def NumberOf1Between1AndN_Solution(self, n): + # write code here + count=0 + for i in range(1,n+1): + while i: + if i%10==1: + count+=1 + i=i/10 + return count + +# 数学规律 +# -*- coding:utf-8 -*- +class Solution: + def NumberOf1Between1AndN_Solution(self, n): + # write code here + count, m =0, 1 + while m <= n: + count += (n // m + 8) // 10 * m + (n // m % 10 == 1) * (n % m + 1) + m*=10 + return count \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/32-\346\212\212\346\225\260\347\273\204\346\216\222\346\210\220\346\234\200\345\260\217\347\232\204\346\225\260.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/32-\346\212\212\346\225\260\347\273\204\346\216\222\346\210\220\346\234\200\345\260\217\347\232\204\346\225\260.py" new file mode 100755 index 00000000..6b4b8ca5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/32-\346\212\212\346\225\260\347\273\204\346\216\222\346\210\220\346\234\200\345\260\217\347\232\204\346\225\260.py" @@ -0,0 +1,14 @@ +# -*- coding:utf-8 -*- +class Solution: + def PrintMinNumber(self, numbers): + # write code here + if not numbers: + return '' + + str_num = [str(m) for m in numbers] + for i in range(len(numbers)-1): + for j in range(i+1,len(numbers)): + if str_num[i] + str_num[j] > str_num[j] + str_num[i]: + str_num[i],str_num[j] = str_num[j] ,str_num[i] + + return ''.join(str_num) \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/33-\344\270\221\346\225\260.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/33-\344\270\221\346\225\260.py" new file mode 100755 index 00000000..6c8b1775 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/33-\344\270\221\346\225\260.py" @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +class Solution: + def GetUglyNumber_Solution(self, index): + # write code here + if not index: + return 0 + + ugly_number = [1]*index + next_index = 1 + + index2 = 0 + index3 = 0 + index5 = 0 + + while next_index < index: + minValue = min(ugly_number[index2]*2, ugly_number[index3]*3,ugly_number[index5]*5) + ugly_number[next_index] = minValue + + while ugly_number[index2]*2 <= ugly_number[next_index]: + index2 += 1 + + while ugly_number[index3]*3 <= ugly_number[next_index]: + index3 += 1 + + while ugly_number[index5]*5 <= ugly_number[next_index]: + index5 += 1 + + next_index += 1 + + return ugly_number[-1] \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/34-\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/34-\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.py" new file mode 100755 index 00000000..d6481820 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/34-\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.py" @@ -0,0 +1,20 @@ +# -*- coding:utf-8 -*- +class Solution: + def FirstNotRepeatingChar(self, s): + # write code here + if not s: + return -1 + + store = {} + lis = list(s) + + for i in lis: + if i not in store.keys(): + store[i] = 0 + store[i] += 1 + + for i in lis: + if store[i] == 1: + return s.index(i) + + return -1 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/35-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/35-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" new file mode 100755 index 00000000..ff12d1a9 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/35-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" @@ -0,0 +1,43 @@ +from __future__ import print_function + + +class Solution: + def InversePairs(self, data): + # write code here + count = 0 + + for item in sorted(data): + count += data.index(item) + data.remove(item) + + return count%1000000007 + + +count = 0 +class Solution: + def InversePairs(self, data): + global count + def MergeSort(lists): + global count + if len(lists) <= 1: + return lists + num = int( len(lists)/2 ) + left = MergeSort(lists[:num]) + right = MergeSort(lists[num:]) + r, l=0, 0 + result=[] + while l len2: + while len1 - len2: + pHead1 = pHead1.next + len1 -= 1 + else: + while len2 - len1: + pHead2 = pHead2.next + len2 -= 1 + + while pHead1 and pHead2: + if pHead1 is pHead2: + return pHead1 + pHead1 = pHead1.next + pHead2 = pHead2.next + + return None \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/37-\346\225\260\345\255\227\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/37-\346\225\260\345\255\227\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" new file mode 100755 index 00000000..49beb73d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/37-\346\225\260\345\255\227\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" @@ -0,0 +1,43 @@ +# -*- coding:utf-8 -*- +class Solution: + def GetNumberOfK(self, data, k): + # write code here + if not data: + return 0 + if self.GetLastK(data, k) == -1 and self.GetFirstK(data, k) == -1: + return 0 + return self.GetLastK(data, k) - self.GetFirstK(data, k) + 1 + + + + def GetFirstK(self, data, k): + low = 0 + high = len(data) - 1 + while low <= high: + mid = (low + high) // 2 + if data[mid] < k: + low = mid + 1 + elif data[mid] > k: + high = mid - 1 + else: + if mid == low or data[mid - 1] != k: #当到list[0]或不为k的时候跳出函数 + return mid + else: + high = mid - 1 + return -1 + + def GetLastK(self, data, k): + low = 0 + high = len(data) - 1 + while low <= high: + mid = (low + high) // 2 + if data[mid] > k: + high = mid - 1 + elif data[mid] < k: + low = mid + 1 + else: + if mid == high or data[mid + 1] != k: + return mid + else: + low = mid + 1 + return -1 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/38-\344\272\214\345\217\211\346\240\221\347\232\204\346\267\261\345\272\246.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/38-\344\272\214\345\217\211\346\240\221\347\232\204\346\267\261\345\272\246.py" new file mode 100755 index 00000000..4453051b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/38-\344\272\214\345\217\211\346\240\221\347\232\204\346\267\261\345\272\246.py" @@ -0,0 +1,12 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + def TreeDepth(self, pRoot): + # write code here + if not pRoot: + return 0 + return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right)) + 1 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/39-\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/39-\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.py" new file mode 100755 index 00000000..7b36f513 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/39-\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + def __init__(self): + self.flag = True + + def IsBalanced_Solution(self, pRoot): + # write code here + self.getDepth(pRoot) + return self.flag + + def getDepth(self, root): + if not root: + return 0 + left = self.getDepth(root.left) + 1 + right = self.getDepth(root.right) + 1 + + if abs(left - right) > 1: + self.flag = False + + return left if left > right else right \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/40-\346\225\260\347\273\204\344\270\255\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/40-\346\225\260\347\273\204\344\270\255\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.py" new file mode 100755 index 00000000..e6559f91 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/40-\346\225\260\347\273\204\344\270\255\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\346\225\260\345\255\227.py" @@ -0,0 +1,46 @@ +# -*- coding:utf-8 -*- +class Solution: + # 返回[a,b] 其中ab是出现一次的两个数字 + def FindNumsAppearOnce(self, array): + # write code here + hashmap = {} + for i in array: + if str(i) in hashmap: + hashmap[str(i)] += 1 + else: + hashmap[str(i)] = 1 + result = [] + for k in hashmap.keys(): + if hashmap[k] == 1: + result.append(int(k)) + return result + +# -*- coding:utf-8 -*- +class Solution: + # 返回[a,b] 其中ab是出现一次的两个数字 + def FindNumsAppearOnce(self, array): + if array == None: + return [] + xor = 0 + for i in array: + xor ^= i + + idxOf1 = self.getFirstIdx(xor) + num1 = num2 = 0 + for j in range(len(array)): + if self.IsBit(array[j], idxOf1): + num1 ^= array[j] + else: + num2 ^= array[j] + return [num1, num2] + + def getFirstIdx(self, num): + idx = 0 + while num & 1 == 0 and idx <= 32: + idx += 1 + num = num >> 1 + return idx + + def IsBit(self, num, indexBit): + num = num >> indexBit + return num & 1 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/41-\345\222\214\344\270\272s\347\232\204\350\277\236\347\273\255\346\225\264\346\225\260\345\272\217\345\210\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/41-\345\222\214\344\270\272s\347\232\204\350\277\236\347\273\255\346\225\264\346\225\260\345\272\217\345\210\227.py" new file mode 100755 index 00000000..7e8d7b58 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/41-\345\222\214\344\270\272s\347\232\204\350\277\236\347\273\255\346\225\264\346\225\260\345\272\217\345\210\227.py" @@ -0,0 +1,16 @@ +# -*- coding:utf-8 -*- +class Solution: + def FindContinuousSequence(self, tsum): + # write code here + small, big,res = 1, 2, [] + csum = small + big + while small < big: + if csum > tsum: + csum -= small + small += 1 + else: + if csum == tsum: + res.append([i for i in range(small,big+1)]) + big += 1 + csum += big + return res \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/42-\345\222\214\344\270\272s\347\232\204\344\270\244\344\270\252\346\225\260\345\255\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/42-\345\222\214\344\270\272s\347\232\204\344\270\244\344\270\252\346\225\260\345\255\227.py" new file mode 100755 index 00000000..8897ebb6 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/42-\345\222\214\344\270\272s\347\232\204\344\270\244\344\270\252\346\225\260\345\255\227.py" @@ -0,0 +1,19 @@ +# -*- coding:utf-8 -*- +class Solution: + def FindNumbersWithSum(self, array, tsum): + # write code here + if not array or not tsum: + return [] + start = 0 + end = len(array) - 1 + while start < end: + csum = array[start] + array[end] + + if csum < tsum: + start += 1 + elif csum > tsum: + end -= 1 + else: + return [array[start],array[end]] + + return [] \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/43-\345\267\246\346\227\213\345\255\227\347\254\246\344\270\262.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/43-\345\267\246\346\227\213\345\255\227\347\254\246\344\270\262.py" new file mode 100755 index 00000000..cb01d77b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/43-\345\267\246\346\227\213\345\255\227\347\254\246\344\270\262.py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +class Solution: + def LeftRotateString(self, s, n): + # write code here + if len(s) <= 0 or n < 0 or len(s) < n: + return '' + lis = list(s) + self.Reverse(lis) + length = len(s) + pivot = length - n + frontlist = self.Reverse(lis[:pivot]) + behindlist = self.Reverse(lis[pivot:]) + res = ''.join(frontlist) + ''.join(behindlist) + return res + + def Reverse(self,lis): + if not lis or len(lis) <= 0: + return '' + start = 0 + end = len(lis) - 1 + while start < end: + lis[start], lis[end] = lis[end], lis[start] + start += 1 + end -= 1 + + return lis \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/44-\347\277\273\350\275\254\345\215\225\350\257\215\351\241\272\345\272\217\345\210\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/44-\347\277\273\350\275\254\345\215\225\350\257\215\351\241\272\345\272\217\345\210\227.py" new file mode 100755 index 00000000..6c6194da --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/44-\347\277\273\350\275\254\345\215\225\350\257\215\351\241\272\345\272\217\345\210\227.py" @@ -0,0 +1,42 @@ +# -*- coding:utf-8 -*- +class Solution: + def ReverseSentence(self, s): + # write code here + if not s or len(s) <= 0: + return '' + lis = list(s) + lis = self.Reverse(lis) + start = 0 + end = 0 + res = '' + lisTmp = [] + + while end < len(s): + if end == len(s) - 1: + lisTmp.append(self.Reverse(lis[start:])) + break + if lis[start] == ' ': + start += 1 + end += 1 + lisTmp.append(' ') + elif lis[end] == ' ': + lisTmp.append(self.Reverse(lis[start:end])) + start = end + else: + end += 1 + for i in lisTmp: + res += ''.join(i) + return res + + + def Reverse(self,lis): + if not lis or len(lis) <= 0: + return '' + start = 0 + end = len(lis) - 1 + while start < end: + lis[start], lis[end] = lis[end], lis[start] + start += 1 + end -= 1 + + return lis \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/45-\346\211\221\345\205\213\347\211\214\351\241\272\345\255\220.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/45-\346\211\221\345\205\213\347\211\214\351\241\272\345\255\220.py" new file mode 100755 index 00000000..d161a2a3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/45-\346\211\221\345\205\213\347\211\214\351\241\272\345\255\220.py" @@ -0,0 +1,30 @@ +# -*- coding:utf-8 -*- +class Solution: + def IsContinuous(self, numbers): + # write code here + if not numbers or len(numbers) == 0: + return False + + transdict = {'A':1,'J':11,'Q':12,'K':13} + for i in range(len(numbers)): + if numbers[i] in transdict.keys(): + numbers[i] = transdict[numbers[i]] + + numbers = sorted(numbers) + number_0 = 0 + number_gap = 0 + + i = 0 + while i < len(numbers) and numbers[i] == 0: + number_0 += 1 + i += 1 + + front = number_0 + behind = front + 1 + while behind < len(numbers): + if numbers[front] == numbers[behind]: + return False + number_gap += numbers[behind] - numbers[front] - 1 + front = behind + behind += 1 + return False if number_gap > number_0 else True \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/46-\345\255\251\345\255\220\344\273\254\347\232\204\346\270\270\346\210\217(\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260).py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/46-\345\255\251\345\255\220\344\273\254\347\232\204\346\270\270\346\210\217(\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260).py" new file mode 100755 index 00000000..141935c0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/46-\345\255\251\345\255\220\344\273\254\347\232\204\346\270\270\346\210\217(\345\234\206\345\234\210\344\270\255\346\234\200\345\220\216\345\211\251\344\270\213\347\232\204\346\225\260).py" @@ -0,0 +1,26 @@ +# -*- coding:utf-8 -*- +class Solution: + def LastRemaining_Solution(self, n, m): + # write code here + if n < 1 or m < 1: + return -1 + con = range(n) + start = 0 + end = -1 + while con: + k = (start + m - 1) % n + end = con.pop(k) + n -= 1 + start = k + return end + +# -*- coding:utf-8 -*- +class Solution: + def LastRemaining_Solution(self, n, m): + # write code here + if n < 1 or m < 1: + return -1 + idx = 0 + for i in range(1,n+1): + idx = (idx + m ) % i + return idx \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/47-\346\261\2021+2+3+...+n.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/47-\346\261\2021+2+3+...+n.py" new file mode 100755 index 00000000..f270c929 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/47-\346\261\2021+2+3+...+n.py" @@ -0,0 +1,18 @@ +# -*- coding:utf-8 -*- +class Solution: + def Sum_Solution(self, n): + # write code here + return self.sumN(n) + + def sum0(self, n): + return 0 + + def sumN(self,n): + fun = {False:self.sum0,True: self.sumN} + return n + fun[not not n](n - 1) + +# -*- coding:utf-8 -*- +class Solution: + def Sum_Solution(self, n): + # write code here + return n and self.Sum_Solution(n - 1) + n \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/48-\344\270\215\347\224\250\345\212\240\345\207\217\344\271\230\351\231\244\345\201\232\345\212\240\346\263\225.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/48-\344\270\215\347\224\250\345\212\240\345\207\217\344\271\230\351\231\244\345\201\232\345\212\240\346\263\225.py" new file mode 100755 index 00000000..ee33a260 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/48-\344\270\215\347\224\250\345\212\240\345\207\217\344\271\230\351\231\244\345\201\232\345\212\240\346\263\225.py" @@ -0,0 +1,9 @@ +# -*- coding:utf-8 -*- +class Solution: + def Add(self, num1, num2): + # write code here + while num2 != 0: + temp = num1 ^ num2 + num2 = (num1 & num2) << 1 + num1 = temp & 0xFFFFFFFF + return num1 if num1 >> 31 == 0 else num1 - 4294967296 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/49-\346\212\212\345\255\227\347\254\246\344\270\262\350\275\254\345\214\226\346\210\220\346\225\264\346\225\260.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/49-\346\212\212\345\255\227\347\254\246\344\270\262\350\275\254\345\214\226\346\210\220\346\225\264\346\225\260.py" new file mode 100755 index 00000000..6451890e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/49-\346\212\212\345\255\227\347\254\246\344\270\262\350\275\254\345\214\226\346\210\220\346\225\264\346\225\260.py" @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +class Solution: + def StrToInt(self, s): + # write code here + flag = False + if not s or len(s) < 1: + return 0 + num = [] + numdict = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} + for i in s: + if i in numdict.keys(): + num.append(numdict[i]) + elif i == '+' or i == '-': + continue + else: + return 0 + ans = 0 + if len(num) == 1 and num[0] == 0: + flag = True + return 0 + for i in num: + ans = ans*10 + i + if s[0] == '-': + ans = 0 - ans + return ans \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/50-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/50-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.py" new file mode 100755 index 00000000..849ca3ca --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/50-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.py" @@ -0,0 +1,20 @@ +# -*- coding:utf-8 -*- +class Solution: + # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0] + # 函数返回True/False + def duplicate(self, numbers, duplication): + # write code here + if not numbers or len(numbers) < 0: + return False + for i in numbers: + if i < 0 or i > len(numbers) - 1: + return False + for i in range(len(numbers)): + while numbers[i] != i: + if numbers[i] == numbers[numbers[i]]: + duplication[0] = numbers[i] + return True + else: + idx = numbers[i] + numbers[i],numbers[idx] = numbers[idx],numbers[i] + return False \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/51-\346\236\204\345\273\272\344\271\230\347\247\257\346\225\260\347\273\204.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/51-\346\236\204\345\273\272\344\271\230\347\247\257\346\225\260\347\273\204.py" new file mode 100755 index 00000000..bfa39ab5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/51-\346\236\204\345\273\272\344\271\230\347\247\257\346\225\260\347\273\204.py" @@ -0,0 +1,15 @@ +# -*- coding:utf-8 -*- +class Solution: + def multiply(self, A): + # write code here + if not A or len(A) <= 0: + return + length = len(A) + lis = [1] * length + for i in range(1,length): + lis[i] = lis[i-1] * A[i-1] + temp = 1 + for i in range(length-2,-1,-1): + temp = temp * A[i+1] + lis[i] *= temp + return lis \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/52-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/52-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" new file mode 100755 index 00000000..a427e80d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/52-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" @@ -0,0 +1,36 @@ +# -*- coding:utf-8 -*- +class Solution: + # s, pattern都是字符串 + def match(self, s, pattern): + # 如果s与pattern都为空,则True + if len(s) == 0 and len(pattern) == 0: + return True + # 如果s不为空,而pattern为空,则False + elif len(s) != 0 and len(pattern) == 0: + return False + # 如果s为空,而pattern不为空,则需要判断 + elif len(s) == 0 and len(pattern) != 0: + # pattern中的第二个字符为*,则pattern后移两位继续比较 + if len(pattern) > 1 and pattern[1] == '*': + return self.match(s, pattern[2:]) + else: + return False + # s与pattern都不为空的情况 + else: + # pattern的第二个字符为*的情况 + if len(pattern) > 1 and pattern[1] == '*': + # s与pattern的第一个元素不同,则s不变,pattern后移两位,相当于pattern前两位当成空 + if s[0] != pattern[0] and pattern[0] != '.': + return self.match(s, pattern[2:]) + else: + # 如果s[0]与pattern[0]相同,且pattern[1]为*,这个时候有三种情况 + # pattern后移2个,s不变;相当于把pattern前两位当成空,匹配后面的 + # pattern后移2个,s后移1个;相当于pattern前两位与s[0]匹配 + # pattern不变,s后移1个;相当于pattern前两位,与s中的多位进行匹配,因为*可以匹配多位 + return self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern) + # pattern第二个字符不为*的情况 + else: + if s[0] == pattern[0] or pattern[0] == '.': + return self.match(s[1:], pattern[1:]) + else: + return False \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/53-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/53-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.py" new file mode 100755 index 00000000..a1897b77 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/53-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.py" @@ -0,0 +1,48 @@ +# -*- coding:utf-8 -*- +class Solution: + # s字符串 + def isNumeric(self, s): + # write code here + if len(s) <= 0: + return False + # 分别标记是否出现过正负号、小数点、e,因为这几个需要特殊考虑 + has_sign = False + has_point = False + has_e = False + for i in range(len(s)): + # 对于e的情况 + if s[i] == 'E' or s[i] == 'e': + # 不同出现两个e + if has_e: + return False + # e不能出现在最后面,因为e后面要接数字 + else: + has_e = True + if i == len(s) -1: + return False + # 对于符号位的情况 + elif s[i] == '+' or s[i] == '-': + # 如果前面已经出现过了符号位,那么这个符号位,必须是跟在e后面的 + if has_sign: + if s[i-1] != 'e' and s[i-1] != 'E': + return False + # 如果这是第一次出现符号位,而且出现的位置不是字符串第一个位置,那么就只能出现在e后面 + else: + has_sign = True + if i > 0 and s[i-1] != 'e' and s[i-1] != 'E': + return False + # 对于小数点的情况 + elif s[i] == '.': + # 小数点不能出现两次;而且如果已经出现过e了,那么就不能再出现小数点,因为e后面只能是整数 + if has_point or has_e: + return False + # 如果是第一次出现小数点,如果前面出现过e,那么还是不能出现小数点 + else: + has_point = True + if i > 0 and (s[i-1] == 'e' or s[i-1] == 'E'): + return False + else: + # 其他字符必须是‘0’到‘9’之间的 + if s[i] < '0' or s[i] > '9': + return False + return True \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/54-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\344\270\215\351\207\215\345\244\215\347\232\204\345\255\227\347\254\246.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/54-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\344\270\215\351\207\215\345\244\215\347\232\204\345\255\227\347\254\246.py" new file mode 100755 index 00000000..f3de7981 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/54-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\344\270\215\351\207\215\345\244\215\347\232\204\345\255\227\347\254\246.py" @@ -0,0 +1,23 @@ +# -*- coding:utf-8 -*- +class Solution: + # init + def __init__(self): + self.dic = {} + self.lis = [] + # 返回对应char + def FirstAppearingOnce(self): + # write code here + while len(self.lis) > 0 and self.dic[self.lis[0]] == 2: + self.lis.pop(0) + if len(self.lis) == 0: + return '#' + else: + return self.lis[0] + + def Insert(self, char): + # write code here + if char not in self.dic.keys(): + self.dic[char] = 1 + self.lis.append(char) + elif self.dic[char]: + self.dic[char] = 2 \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/55-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/55-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243.py" new file mode 100755 index 00000000..6cc9df8e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/55-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243.py" @@ -0,0 +1,41 @@ +# -*- coding:utf-8 -*- +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +class Solution: + def EntryNodeOfLoop(self, pHead): + # write code here + meetNode = self.MeetNode(pHead) + if not meetNode: + return None + loop = 1 + flag = meetNode + while flag.next != meetNode: + loop += 1 + flag = flag.next + + fast = pHead + for i in range(loop): + fast = fast.next + slow = pHead + while fast != slow: + fast = fast.next + slow = slow.next + return fast + + def MeetNode(self, head): + if not head: + return None + slow = head.next + if slow == None: + return None + fast = slow.next + while fast: + if slow == fast: + return slow + slow = slow.next + fast = fast.next.next + + + \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/56-\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\351\207\215\345\244\215\347\232\204\347\273\223\347\202\271.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/56-\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\351\207\215\345\244\215\347\232\204\347\273\223\347\202\271.py" new file mode 100755 index 00000000..36892be0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/56-\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\351\207\215\345\244\215\347\232\204\347\273\223\347\202\271.py" @@ -0,0 +1,24 @@ +# -*- coding:utf-8 -*- +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None +class Solution: + def deleteDuplication(self, pHead): + # write code here + if pHead is None or pHead.next is None: + return pHead + first = ListNode(-1) + first.next = pHead + last = first + while pHead and pHead.next: + if pHead.val == pHead.next.val: + val = pHead.val + while pHead and val == pHead.val: + pHead = pHead.next + last.next = pHead + + else: + last = pHead + pHead = pHead.next + return first.next \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/57-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/57-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.py" new file mode 100755 index 00000000..0025e267 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/57-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.py" @@ -0,0 +1,32 @@ +# -*- coding:utf-8 -*- +# class TreeLinkNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +# self.next = None +class Solution: + def GetNext(self, pNode): + # write code here + if pNode is None: + return + pNext = None + if pNode.right: + pNode = pNode.right + while pNode.left: + pNode = pNode.left + pNext = pNode + + else: + if pNode.next and pNode.next.left == pNode: + pNext = pNode.next + elif pNode.next and pNode.next.right == pNode: + pNode = pNode.next + while pNode.next and pNode.next.right == pNode: + pNode = pNode.next + # 遍历终止时当前节点有父节点, 说明当前节点是父节点的左子节点, 输入节点的下一个结点为当前节点的父节点 + # 反之终止时当前节点没有父节点, 说明当前节点在位于根节点的右子树, 没有下一个结点 + if pNode.next: + pNext = pNode.next + + return pNext \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/58-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/58-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.py" new file mode 100755 index 00000000..bdbbf8da --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/58-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1,19 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + def isSymmetrical(self, pRoot): + # write code here + return self.selfIsSym(pRoot,pRoot) + + def selfIsSym(self,root1,root2): + if root1 == root2 and root2 == None: + return True + if root1 == None or root2 == None: + return False + if root1.val != root2.val: + return False + return self.selfIsSym(root1.left, root2.right) and self.selfIsSym(root1.right,root2.left) \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/59-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/59-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" new file mode 100755 index 00000000..cc0ac1d0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/59-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1,34 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + def Print(self, pRoot): + # write code here + if not pRoot: + return [] + result,nodes = [],[pRoot] + right = True + while nodes: + curStack, nextStack = [],[] + if right: + for node in nodes: + curStack.append(node.val) + if node.left: + nextStack.append(node.left) + if node.right: + nextStack.append(node.right) + else: + for node in nodes: + curStack.append(node.val) + if node.right: + nextStack.append(node.right) + if node.left: + nextStack.append(node.left) + nextStack.reverse() + right = not right + result.append(curStack) + nodes = nextStack + return result \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/60-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/60-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.py" new file mode 100755 index 00000000..638d80b1 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/60-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.py" @@ -0,0 +1,24 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + + def Print(self, pRoot): + # write code here + if pRoot is None: + return [] + nodes,res = [pRoot],[] + while nodes: + curStack, nextStack = [],[] + for node in nodes: + curStack.append(node.val) + if node.left: + nextStack.append(node.left) + if node.right: + nextStack.append(node.right) + res.append(curStack) + nodes = nextStack + return res \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/61-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/61-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.py" new file mode 100755 index 00000000..f1ceb3a5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/61-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1,31 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + def __init__(self): + self.flag = -1 + + def Serialize(self, root): + # write code here + if not root: + return '#,' + return str(root.val)+','+self.Serialize(root.left)+self.Serialize(root.right) + + def Deserialize(self, s): + # write code here + self.flag += 1 + l = s.split(',') + + if self.flag >= len(s): + return None + root = None + + if l[self.flag] != '#': + root = TreeNode(int(l[self.flag])) + root.left = self.Deserialize(s) + root.right = self.Deserialize(s) + return root + \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/62-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\347\254\254k\344\270\252\347\273\223\347\202\271.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/62-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\347\254\254k\344\270\252\347\273\223\347\202\271.py" new file mode 100755 index 00000000..8144247c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/62-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\347\254\254k\344\270\252\347\273\223\347\202\271.py" @@ -0,0 +1,24 @@ +# -*- coding:utf-8 -*- +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +class Solution: + # 返回对应节点TreeNode + def KthNode(self, pRoot, k): + # write code here + if not pRoot or not k: + return + res = [] + def traverse(node): + if len(res) >= k or not node: + return + traverse(node.left) + res.append(node) + traverse(node.right) + traverse(pRoot) + if len(res) < k: + return + return res[k-1] + \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/63-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/63-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.py" new file mode 100755 index 00000000..9b51f34d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/63-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.py" @@ -0,0 +1,63 @@ +# -*- coding:utf-8 -*- +class Solution: + def __init__(self): + self.left = [] + self.right = [] + self.count = 0 + def Insert(self, num): + if self.count & 1 == 0: + self.left.append(num) + else: + self.right.append(num) + self.count += 1 + + def GetMedian(self, x): + if self.count == 1: + return self.left[0] + self.MaxHeap(self.left) + self.MinHeap(self.right) + if self.left[0] > self.right[0]: + self.left[0], self.right[0] = self.right[0], self.left[0] + self.MaxHeap(self.left) + self.MinHeap(self.right) + if self.count & 1 == 0: + return (self.left[0] + self.right[0])/2.0 + else: + return self.left[0] + + def MaxHeap(self, alist): + length = len(alist) + if alist == None or length <= 0: + return + if length == 1: + return alist + for i in range(length//2-1, -1, -1): + k = i; temp = alist[k]; heap = False + while not heap and 2*k < length-1: + index = 2*k+1 + if index < length - 1: + if alist[index] < alist[index + 1]: index += 1 + if temp >= alist[index]: heap = True + else: + alist[k] = alist[index] + k = index + alist[k] = temp + + def MinHeap(self, alist): + length = len(alist) + if alist == None or length <= 0: + return + if length == 1: + return alist + for i in range(length//2-1, -1, -1): + k = i; temp = alist[k]; heap = False + while not heap and 2 * k < length - 1: + index = 2 * k+1 + if index < length - 1: + if alist[index] > alist[index + 1]: index += 1 + if temp <= alist[index]: + heap = True + else: + alist[k] = alist[index] + k = index + alist[k] = temp \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/64-\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/64-\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274.py" new file mode 100755 index 00000000..a2e50036 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/64-\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274.py" @@ -0,0 +1,24 @@ +# -*- coding:utf-8 -*- +class Solution: + def maxInWindows(self, num, size): + # write code here + if not num or size <= 0: + return [] + deque = [] + if len(num) >= size: + index = [] + for i in range(size): + while len(index) > 0 and num[i] > num[index[-1]]: + index.pop() + index.append(i) + + for i in range(size, len(num)): + deque.append(num[index[0]]) + while len(index) > 0 and num[i] >= num[index[-1]]: + index.pop() + if len(index) > 0 and index[0] <= i - size: + index.pop(0) + index.append(i) + + deque.append(num[index[0]]) + return deque \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/65-\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/65-\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204.py" new file mode 100755 index 00000000..0bd9f87e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/65-\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204.py" @@ -0,0 +1,34 @@ +class Solution: + def hasPath(self, matrix, rows, cols, path): + if matrix == None or rows < 1 or cols < 1 or path == None: + return False + visited = [0] * (rows * cols) + + pathLength = 0 + for row in range(rows): + for col in range(cols): + if self.hasPathCore(matrix, rows, cols, row, col, path, pathLength, visited): + return True + return False + + def hasPathCore(self, matrix, rows, cols, row, col, path, pathLength, visited): + if len(path) == pathLength: + return True + + hasPath = False + if row >= 0 and row < rows and col >= 0 and col < cols and matrix[row * cols + col] == path[pathLength] and not \ + visited[row * cols + col]: + + pathLength += 1 + visited[row * cols + col] = True + + hasPath = self.hasPathCore(matrix, rows, cols, row, col - 1, path, pathLength, visited) or \ + self.hasPathCore(matrix, rows, cols, row - 1, col, path, pathLength, visited) or \ + self.hasPathCore(matrix, rows, cols, row, col + 1, path, pathLength, visited) or \ + self.hasPathCore(matrix, rows, cols, row + 1, col, path, pathLength, visited) + + if not hasPath: + pathLength -= 1 + visited[row * cols + col] = False + + return hasPath \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/66-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.py" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/66-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.py" new file mode 100755 index 00000000..44182ab0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/66-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.py" @@ -0,0 +1,28 @@ +# -*- coding:utf-8 -*- +class Solution: + def movingCount(self, threshold, rows, cols): + visited = [False] * (rows * cols) + count = self.movingCountCore(threshold, rows, cols, 0, 0, visited) + return count + + def movingCountCore(self, threshold, rows, cols, row, col, visited): + count = 0 + if self.check(threshold, rows, cols, row, col, visited): + visited[row * cols + col] = True + count = 1 + self.movingCountCore(threshold, rows, cols, row-1, col, visited) + \ + self.movingCountCore(threshold, rows, cols, row+1, col, visited) + \ + self.movingCountCore(threshold, rows, cols, row, col-1, visited) + \ + self.movingCountCore(threshold, rows, cols, row, col+1, visited) + return count + + def check(self, threshold, rows, cols, row, col, visited): + if row >= 0 and row < rows and col >= 0 and col < cols and self.getDigitSum(row) + self.getDigitSum(col) <= threshold and not visited[row * cols + col]: + return True + return False + + def getDigitSum(self, number): + sum = 0 + while number > 0: + sum += (number % 10) + number = number // 10 + return sum diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Python/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/README.md" new file mode 100755 index 00000000..a2bf3728 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Python/README.md" @@ -0,0 +1 @@ +[此处](https://kaiyuanyokii2n.com/offer-python.html)为作者博客网站, 感兴趣的去可以看看 diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/README.en.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/README.en.md" new file mode 100644 index 00000000..59495721 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/README.en.md" @@ -0,0 +1,850 @@ +

Sword Offer with Scala

+ +
语言: 中文
+ + +# Details + +- Sword Offer with Java + - [x] Problem 01-20 + +- Sword Offer with Scala + + - [x] Problem 01-20 Done at `2019-03-14` + - [x] Problem 20-24 Done at `2019-03-16` + - [x] Problem 47-51 Done at `2019-03-18` + - [x] Problem 25-28 Done at `2019-03-20` + - [x] Problem 29-32 Done at `2019-03-21` + - [x] Problem 33-36 Done at `2019-03-24` + - [x] Problem 37-40 Done at `2019-03-26` + - [x] Problem 41-43 Done at `2019-04-25` + - [x] Problem 45-46 Done at `2019-04-26` + - [x] Problem 52-54 Done at `2019-04-29` + - [x] Problem 55-57 Done at `2019-05-07` + - [x] Problem 58-62 Done at `2019-05-16` + - [x] Problem 63-66 Done at `2019-06-26` + + +# Features + +- Scala data types all use `Scala` native components to avoid using `java` + +- Contains a simple `ScalaTest` unit test module + +- Project Construction Based on `SBT` + +- [Link in Nowcoder.com](https://www.nowcoder.com/ta/coding-interviews) + +# Problem solved with Scala-[Link in Nowcoder.com](https://www.nowcoder.com/ta/coding-interviews) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号考点题目Scala解答热度指数通过率
+1 +数组 + + +二维数组中的查找 + +P0112482423.43%
+2 +字符串 + + +替换空格 + +P0211549924.18%
+3 +链表 + + +从尾到头打印链表 + +P0310000623.99%
+4 +树 + + +重建二叉树 + +P046975322.46%
+5 +栈和队列 + + +用两个栈实现队列 + +P057885735.71%
+6 +查找和排序 + + +旋转数组的最小数字 + +P067467631.58%
+7 +递归和循环 + + +斐波那契数列 + +P078307528.82%
+8 +递归和循环 + + +跳台阶 + +P088282434.02%
+9 +递归和循环 + + +变态跳台阶 + +P097501139.87%
+10 +递归和循环 + + +矩形覆盖 + +P106682734.45%
+11 +位运算 + + +二进制中1的个数 + +P117149134.08%
+12 +代码的完整性 + + +数值的整数次方 + +P126554731.02%
+13 +代码的完整性 + + +调整数组顺序使奇数位于偶数前面 + +P136595725.44%
+14 +代码的鲁棒性 + + +链表中倒数第k个结点 + +P146759020.41%
+15 +代码的鲁棒性 + + +反转链表 + +P156592628.53%
+16 +代码的鲁棒性 + + +合并两个排序的链表 + +P166098526.81%
+17 +代码的鲁棒性 + + +树的子结构 + +P175239622.83%
+18 +面试思路 + + +二叉树的镜像 + +P185753642.40%
+19 +画图让抽象形象化 + + +顺时针打印矩阵 + +P194713917.32%
+20 +举例让抽象具体化 + + +包含min函数的栈 + +P204847330.95%
+21 +举例让抽象具体化 + + +栈的压入、弹出序列 + +P214898528.47%
+22 +举例让抽象具体化 + + +从上往下打印二叉树 + +P225033226.34%
+23 +举例让抽象具体化 + + +二叉搜索树的后序遍历序列 + +P234391723.39%
+24 +举例让抽象具体化 + + +二叉树中和为某一值的路径 + +P244097525.86%
+25 +分解让复杂问题简单 + + +复杂链表的复制 + +P253469120.55%
+26 +分解让复杂问题简单 + + +二叉搜索树与双向链表 + +P263245627.42%
+27 +分解让复杂问题简单 + + +字符串的排列 + +P273607719.68%
+28 +时间效率 + + +数组中出现次数超过一半的数字 + +P284394426.71%
+29 +时间效率 + + +最小的K个数 + +P294327721.09%
+30 +时间效率 + + +连续子数组的最大和 + +P304164535.02%
+31 +时间效率 + + +整数中1出现的次数(从1到n整数中1出现的次数) + +P313320932.49%
+32 +时间效率 + + +把数组排成最小的数 + +P323385426.36%
+33 +时间空间效率的平衡 + + +丑数 + +P333424321.25%
+34 +时间空间效率的平衡 + + +第一个只出现一次的字符位置 + +P343699825.55%
+35 +时间空间效率的平衡 + + +数组中的逆序对 + +P352826614.94%
+36 +时间空间效率的平衡 + + +两个链表的第一个公共结点 + +P363508632.12%
+37 +知识迁移能力 + + +数字在排序数组中出现的次数 + +P373472129.33%
+38 +知识迁移能力 + + +二叉树的深度 + +P383997146.65%
+39 +知识迁移能力 + + +平衡二叉树 + +P393286233.69%
+40 +知识迁移能力 + + +数组中只出现一次的数字 + +P403447028.69%
+41 +知识迁移能力 + + +和为S的连续正数序列 + +P413037926.19%
+42 +知识迁移能力 + + +和为S的两个数字 + +P423367428.50%
+43 +知识迁移能力 + + +左旋转字符串 + +P433313530.41%
+44 +知识迁移能力 + + +翻转单词顺序列 + +P443260718.87%
+45 +抽象建模能力 + + +扑克牌顺子 + +P452615424.90%
+46 +抽象建模能力 + + +孩子们的游戏(圆圈中最后剩下的数) + +P462613629.42%
+47 +发散思维能力 + + +求1+2+3+...+n + +P473624137.01%
+48 +发散思维能力 + + +不用加减乘除做加法 + +P483055444.63%
+49 +综合 + + +把字符串转换成整数 + +P492811926.13%
+50 +数组 + + +数组中重复的数字 + +P503397128.14%
+51 +数组 + + +构建乘积数组 + +P512598338.10%
+52 +字符串 + + +正则表达式匹配 + +P521990119.45%
+53 +字符串 + + +表示数值的字符串 + +P532045726.28%
+54 +字符串 + + +字符流中第一个不重复的字符 + +P542242030.66%
+55 +链表 + + +链表中环的入口结点 + +P552834930.52%
+56 +链表 + + +删除链表中重复的结点 + +P563014919.18%
+57 +树 + + +二叉树的下一个结点 + +P572588929.02%
+58 +树 + + +对称的二叉树 + +P582720230.09%
+59 +树 + + +按之字形顺序打印二叉树 + +P592252423.33%
+60 +树 + + +把二叉树打印成多行 + +P602433729.65%
+61 +树 + + +序列化二叉树 + +P611843721.31%
+62 +树 + + +二叉搜索树的第k个结点 + +P622354323.66%
+63 +树 + + +数据流中的中位数 + +P631829625.77%
+64 +栈和队列 + + +滑动窗口的最大值 + +P642186323.59%
+65 +回溯法 + + +矩阵中的路径 + +P651913222.03%
+66 +回溯法 + + +机器人的运动范围 + +P661992522.45%
+ + +# Contributing + +Contribution is welcome, feel free to open an issue and fork. Waiting for your pull request. \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/README.md" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/README.md" new file mode 100644 index 00000000..c20708a0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/README.md" @@ -0,0 +1,842 @@ +

Scala版本剑指Offer

Language: English
+ +# 仓库详情 + +- Java版剑指OFFER + - [x] 01-20题 + +- Scala 版本剑指Offer + - [x] 01-20题 `2019-03-14`完成 + - [x] 20-24题 `2019-03-16`完成 + - [x] 47-51题 `2019-03-18`完成 + - [x] 25-28题 `2019-03-20`完成 + - [x] 29-32题 `2019-03-21`完成 + - [x] 33-36题 `2019-03-24`完成 + - [x] 37-40题 `2019-03-26`完成 + - [x] 41-43题 `2019-04-25`完成 + - [x] 44-46题 `2019-04-26`完成 + - [x] 52-54题 `2019-04-29`完成 + - [x] 55-57题 `2019-05-07`完成 + - [x] 58-62题 `2019-05-16`完成 + - [x] 58-62题 `2019-05-16`完成 + - [x] 63-66题 `2019-06-26`完成 + - [ ] 04-18-36 测试用例失败 + + +# 特性 + - 数据类型均采用`scala`原生组件, 避免使用`java`类型 + - 每题均包含简易的`ScalaTest` 单元测试模块 + - 项目基于`SBT`构建 + + # Scala 题目 - [牛客网题目](https://www.nowcoder.com/ta/coding-interviews) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号考点题目Scala解答热度指数通过率
+1 +数组 + + +二维数组中的查找 + +P0112482423.43%
+2 +字符串 + + +替换空格 + +P0211549924.18%
+3 +链表 + + +从尾到头打印链表 + +P0310000623.99%
+4 +树 + + +重建二叉树 + +P046975322.46%
+5 +栈和队列 + + +用两个栈实现队列 + +P057885735.71%
+6 +查找和排序 + + +旋转数组的最小数字 + +P067467631.58%
+7 +递归和循环 + + +斐波那契数列 + +P078307528.82%
+8 +递归和循环 + + +跳台阶 + +P088282434.02%
+9 +递归和循环 + + +变态跳台阶 + +P097501139.87%
+10 +递归和循环 + + +矩形覆盖 + +P106682734.45%
+11 +位运算 + + +二进制中1的个数 + +P117149134.08%
+12 +代码的完整性 + + +数值的整数次方 + +P126554731.02%
+13 +代码的完整性 + + +调整数组顺序使奇数位于偶数前面 + +P136595725.44%
+14 +代码的鲁棒性 + + +链表中倒数第k个结点 + +P146759020.41%
+15 +代码的鲁棒性 + + +反转链表 + +P156592628.53%
+16 +代码的鲁棒性 + + +合并两个排序的链表 + +P166098526.81%
+17 +代码的鲁棒性 + + +树的子结构 + +P175239622.83%
+18 +面试思路 + + +二叉树的镜像 + +P185753642.40%
+19 +画图让抽象形象化 + + +顺时针打印矩阵 + +P194713917.32%
+20 +举例让抽象具体化 + + +包含min函数的栈 + +P204847330.95%
+21 +举例让抽象具体化 + + +栈的压入、弹出序列 + +P214898528.47%
+22 +举例让抽象具体化 + + +从上往下打印二叉树 + +P225033226.34%
+23 +举例让抽象具体化 + + +二叉搜索树的后序遍历序列 + +P234391723.39%
+24 +举例让抽象具体化 + + +二叉树中和为某一值的路径 + +P244097525.86%
+25 +分解让复杂问题简单 + + +复杂链表的复制 + +P253469120.55%
+26 +分解让复杂问题简单 + + +二叉搜索树与双向链表 + +P263245627.42%
+27 +分解让复杂问题简单 + + +字符串的排列 + +P273607719.68%
+28 +时间效率 + + +数组中出现次数超过一半的数字 + +P284394426.71%
+29 +时间效率 + + +最小的K个数 + +P294327721.09%
+30 +时间效率 + + +连续子数组的最大和 + +P304164535.02%
+31 +时间效率 + + +整数中1出现的次数(从1到n整数中1出现的次数) + +P313320932.49%
+32 +时间效率 + + +把数组排成最小的数 + +P323385426.36%
+33 +时间空间效率的平衡 + + +丑数 + +P333424321.25%
+34 +时间空间效率的平衡 + + +第一个只出现一次的字符位置 + +P343699825.55%
+35 +时间空间效率的平衡 + + +数组中的逆序对 + +P352826614.94%
+36 +时间空间效率的平衡 + + +两个链表的第一个公共结点 + +P363508632.12%
+37 +知识迁移能力 + + +数字在排序数组中出现的次数 + +P373472129.33%
+38 +知识迁移能力 + + +二叉树的深度 + +P383997146.65%
+39 +知识迁移能力 + + +平衡二叉树 + +P393286233.69%
+40 +知识迁移能力 + + +数组中只出现一次的数字 + +P403447028.69%
+41 +知识迁移能力 + + +和为S的连续正数序列 + +P413037926.19%
+42 +知识迁移能力 + + +和为S的两个数字 + +P423367428.50%
+43 +知识迁移能力 + + +左旋转字符串 + +P433313530.41%
+44 +知识迁移能力 + + +翻转单词顺序列 + +P443260718.87%
+45 +抽象建模能力 + + +扑克牌顺子 + +P452615424.90%
+46 +抽象建模能力 + + +孩子们的游戏(圆圈中最后剩下的数) + +P462613629.42%
+47 +发散思维能力 + + +求1+2+3+...+n + +P473624137.01%
+48 +发散思维能力 + + +不用加减乘除做加法 + +P483055444.63%
+49 +综合 + + +把字符串转换成整数 + +P492811926.13%
+50 +数组 + + +数组中重复的数字 + +P503397128.14%
+51 +数组 + + +构建乘积数组 + +P512598338.10%
+52 +字符串 + + +正则表达式匹配 + +P521990119.45%
+53 +字符串 + + +表示数值的字符串 + +P532045726.28%
+54 +字符串 + + +字符流中第一个不重复的字符 + +P542242030.66%
+55 +链表 + + +链表中环的入口结点 + +P552834930.52%
+56 +链表 + + +删除链表中重复的结点 + +P563014919.18%
+57 +树 + + +二叉树的下一个结点 + +P572588929.02%
+58 +树 + + +对称的二叉树 + +P582720230.09%
+59 +树 + + +按之字形顺序打印二叉树 + +P592252423.33%
+60 +树 + + +把二叉树打印成多行 + +P602433729.65%
+61 +树 + + +序列化二叉树 + +P611843721.31%
+62 +树 + + +二叉搜索树的第k个结点 + +P622354323.66%
+63 +树 + + +数据流中的中位数 + +P631829625.77%
+64 +栈和队列 + + +滑动窗口的最大值 + +P642186323.59%
+65 +回溯法 + + +矩阵中的路径 + +P651913222.03%
+66 +回溯法 + + +机器人的运动范围 + +P661992522.45%
+---------------------- + +## 贡献你的代码 + +欢迎你贡献出你的一份力量,你可以随时提交 issue 或 fork 本仓库。静候你的 pull request。 diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/build.sbt" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/build.sbt" new file mode 100644 index 00000000..69ba003a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/build.sbt" @@ -0,0 +1,8 @@ +name := "sword-offer-scala-sbt" + +version := "0.1" + +scalaVersion := "2.12.8" + +// https://mvnrepository.com/artifact/org.scalatest/scalatest +libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.6" % Test \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P01.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P01.scala" new file mode 100644 index 00000000..d7b8ad17 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P01.scala" @@ -0,0 +1,22 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P01 { + def find(target: Int, array: Array[Array[Int]]) = { + val arrayLen = array.length + var res = false + for (i: Int <- 0 until arrayLen) { + for (j: Int <- 0 until array(i).length) { + if (target == array(i)(j)) { + res = true + } + } + } + res + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P02.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P02.scala" new file mode 100644 index 00000000..6314bf9a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P02.scala" @@ -0,0 +1,13 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P02 { + def replaceSpace(str: String) = { + str.replace(" ", "%20") + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P03.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P03.scala" new file mode 100644 index 00000000..218a16e0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P03.scala" @@ -0,0 +1,29 @@ +package com.xixici + + +import com.xixici.util.ListNode + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P03 { + def printListFromTailToHead(head: ListNode): collection.immutable.List[ListNode] = { + if (head == null) { + + } + val list = new collection.mutable.ListBuffer[ListNode]() + val stack = collection.mutable.ArrayStack[ListNode]() + var _head = head + while (_head != null) { + stack.push(_head) + _head = _head.next + } + while (!stack.isEmpty) { + list.append(stack.pop()) + } + list.toList + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P04.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P04.scala" new file mode 100644 index 00000000..39d7ef25 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P04.scala" @@ -0,0 +1,39 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P04 { + def reConstructBinaryTree(pre: Array[Int], in: Array[Int]): TreeNode = { + if (pre == null || in == null || pre.length <= 0 || in.length <= 0) { + + } + if (pre.length != in.length) { + throw new Exception("error, array length is not equal.") + } + + val root: TreeNode = new TreeNode(-1) + var flag: Boolean = false + for (i <- 0 until pre.length) { + if (pre(0) == in(i)) { + flag = true + root.data = pre(0) + root.left = reConstructBinaryTree(java.util.Arrays.copyOfRange(pre, 1, i + 1), + java.util.Arrays.copyOfRange(in, 0, i)) + root.right = reConstructBinaryTree(java.util.Arrays.copyOfRange(pre, i + 1, pre.length), + java.util.Arrays.copyOfRange(in, i + 1, in.length)) + } + } + + if (!flag) { + throw new Exception("error, no root node.") + } + + root + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P05.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P05.scala" new file mode 100644 index 00000000..f8d6df3a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P05.scala" @@ -0,0 +1,30 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/10 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P05 { + + val stack1 = new scala.collection.mutable.Stack[Int] + val stack2 = new scala.collection.mutable.Stack[Int] + + def push(a: Int) = { + stack1.push(a) + } + + def pop() = { + if (stack2.isEmpty) { + while (!stack1.isEmpty) { + stack2.push(stack1.pop()) + } + } + if (stack2.isEmpty) { + throw new Exception("delete error, queue is empty.") + } + stack2.pop() + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P06.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P06.scala" new file mode 100644 index 00000000..4fcffe3d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P06.scala" @@ -0,0 +1,38 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P06 { + + def minNumberInRotateArray(array: Array[Int]) = { + var res = 0 + if (array.length < 1) { + + } + else { + var left = 0 + var right = array.length - 1 + var middle = -1 + while (array(left) >= array(right) && middle != right) { + if ((right - left) == 1) { + middle = right + } else { + middle = left + (right - left) / 2 + if (array(middle) >= array(left)) { + left = middle + } + if (array(middle) <= array(right)) { + right = middle + } + } + } + res = array(middle) + } + res + //array.min + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P07.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P07.scala" new file mode 100644 index 00000000..5bdb4af0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P07.scala" @@ -0,0 +1,21 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/11 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P07 { + def Fibonacci(n: Int): Int = { + var res = 0 + if (n == 1) { + return 1 + } + if (n == 0) { + return 0 + } + + Fibonacci(n - 1) + Fibonacci(n - 2) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P08.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P08.scala" new file mode 100644 index 00000000..56e78bef --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P08.scala" @@ -0,0 +1,20 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P08 { + def Jump(n: Int): Int = { + if (n == 1) { + return 1 + } + if (n == 2) { + return 2 + } + + Jump(n - 1) + Jump(n - 2) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P09.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P09.scala" new file mode 100644 index 00000000..403a4e57 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P09.scala" @@ -0,0 +1,19 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P09 { + def Jump2(n: Int): Int = { + if (n == 1) { + return 1 + } + if (n == 2) { + return 2 + } + 2 * Jump2(n - 1) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P10.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P10.scala" new file mode 100644 index 00000000..04beb21e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P10.scala" @@ -0,0 +1,19 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P10 { + def RectCover(n: Int): Int = { + if (n == 1) { + return 1 + } + if (n == 2) { + return 2 + } + RectCover(n - 2) + RectCover(n - 1) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P11.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P11.scala" new file mode 100644 index 00000000..a3b1110b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P11.scala" @@ -0,0 +1,19 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P11 { + def NumberOf1(n: Int) = { + var count = 0 + var nNew = n + while (nNew != 0) { + count += 1 + nNew = nNew & (nNew - 1) + } + count + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P12.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P12.scala" new file mode 100644 index 00000000..9bd0c226 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P12.scala" @@ -0,0 +1,29 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P12 { + def Power(base: Double, exponent: Int): Double = { + var res = base + var exponentNew = exponent + if (exponent == 0) { + res = 0 + } + if (exponent < 0) { + for (i <- 1 until exponent) { + res *= base + } + res = 1 / res + } + if (exponent > 0) { + for (i <- 1 until exponent) { + res *= base + } + } + res + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P13.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P13.scala" new file mode 100644 index 00000000..d5e20fb3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P13.scala" @@ -0,0 +1,24 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P13 { + def reOrderArray(array: Array[Int]) = { + for (i <- 0 until array.length) { + if (array(i) % 2 == 1) { + val tmp = array(i) + var j = i - 1 + while (j >= 0 && array(j) % 2 == 0) { + array(j + 1) = array(j) + j -= 1 + } + array(j + 1) = tmp + } + } + array + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P14.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P14.scala" new file mode 100644 index 00000000..a4c81c11 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P14.scala" @@ -0,0 +1,26 @@ +package com.xixici + +import com.xixici.util.ListNode + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P14 { + def FindKthToTail(listNode: ListNode, k: Int): ListNode = { + if (listNode == null || k <= 0) + return null + var p = listNode + for (i <- 0 until k - 1) { + if (p.next != null) p = p.next else return null + } + var q = listNode + while (p.next != null) { + p = p.next + q = q.next + } + q + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P15.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P15.scala" new file mode 100644 index 00000000..1a97f5a3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P15.scala" @@ -0,0 +1,27 @@ +package com.xixici + +import com.xixici.util.ListNode + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P15 { + def ReverseList(listNode: ListNode): ListNode = { + if (listNode == null) + return null + var head: ListNode = listNode + var pre: ListNode = null + //前一结点 + var next: ListNode = null //后一结点 + while (head != null) { + next = head.next + head.next = pre + pre = head + head = next + } + pre + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P16.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P16.scala" new file mode 100644 index 00000000..0efa4109 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P16.scala" @@ -0,0 +1,28 @@ +package com.xixici + +import com.xixici.util.ListNode + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P16 { + def Merge(list1: ListNode, list2: ListNode): ListNode = { + if (list1 == null) { + return list2 + } + if (list2 == null) { + return list1 + } + if (list1.data <= list2.data) { + list1.next = Merge(list1.next, list2) + return list1 + } else { + list2.next = Merge(list1, list2.next) + return list2 + } + + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P17.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P17.scala" new file mode 100644 index 00000000..d2652f3b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P17.scala" @@ -0,0 +1,31 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P17 { + def HasSubtree(tree1: TreeNode, tree2: TreeNode): Boolean = { + var flag: Boolean = false + if (tree1 != null && tree2 != null) { + flag = DoesTree1HaveTree2(tree1, tree2) + if (!flag) { + flag = HasSubtree(tree1.left, tree2) || HasSubtree(tree1.right, tree2) + } + } + flag + } + + def DoesTree1HaveTree2(tree1: TreeNode, tree2: TreeNode): Boolean = { + if (tree1 == null && tree2 != null) return false + if (tree2 == null) return true + if (tree1.data != tree2.data) return false + else { + return DoesTree1HaveTree2(tree1.left, tree2.left) && DoesTree1HaveTree2(tree1.right, tree2.right) + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P18.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P18.scala" new file mode 100644 index 00000000..43e6d8d8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P18.scala" @@ -0,0 +1,21 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P18 { + def Mirror(tree: TreeNode): TreeNode = { + if (tree == null) return null + val tmp = tree.left + tree.left = tree.right + tree.right = tmp + Mirror(tree.left) + Mirror(tree.right) + tree + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P19.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P19.scala" new file mode 100644 index 00000000..d39bc6a6 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P19.scala" @@ -0,0 +1,43 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P19 { + def printMatrix(matrix: Array[Array[Int]]): Array[Int] = { + val rows = matrix.length + val cols = matrix(0).length + val res = new collection.mutable.ArrayBuffer[Int]() + if (rows == 0 || cols == 0) return null + var left = 0 + var top = 0 + var bottom = rows - 1 + var right = cols - 1 + while (left <= right && top <= bottom) { + for (i <- left until right) { + res.append(matrix(top)(i)) + } + for (i <- top until bottom) { + res.append(matrix(i)(right)) + } + if (top != bottom) { + for (i <- right until left by -1) { + res.append(matrix(bottom)(i)) + } + } + if (left != right) { + for (i <- bottom until top by -1) { + res.append(matrix(i)(left)) + } + } + left += 1 + top += 1 + bottom -= 1 + right -= 1 + } + res.toArray + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P20.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P20.scala" new file mode 100644 index 00000000..5e60cc5d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P20.scala" @@ -0,0 +1,30 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P20 { + private val dataStack = new collection.mutable.ArrayStack[Int] + private val minStack = new collection.mutable.ArrayStack[Int] + + def push(e: Int): Unit = { + dataStack.push(e) + if (minStack.isEmpty || e < minStack.top) { + minStack.push(e) + } else { + minStack.push(minStack.top) + } + } + + def pop(): Int = { + minStack.pop + dataStack.pop + } + + def min(): Int = { + minStack.top + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P21.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P21.scala" new file mode 100644 index 00000000..7856e53d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P21.scala" @@ -0,0 +1,24 @@ +package com.xixici + +import scala.collection.mutable + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P21 { + def IsPopOrder(pushA: Array[Int], popA: Array[Int]): Boolean = { + val stackA = mutable.ArrayStack[Int]() + var j = 0 + for (i <- 0 until pushA.length) { + stackA.push(pushA(i)) + while (!stackA.isEmpty && stackA.top == popA(j)) { + stackA.pop() + j += 1 + } + } + stackA.isEmpty + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P22.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P22.scala" new file mode 100644 index 00000000..c3ec9a72 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P22.scala" @@ -0,0 +1,37 @@ +package com.xixici + +import com.xixici.util.TreeNode + +import scala.collection.mutable + +/** + * Created by xixici + * Date: 2019/3/15 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P22 { + def PrintFromTopToBottom(root: TreeNode): List[Int] = { + // val list = collection.mutable.ListBuffer[Int]() + // val stack = new mutable.ArrayStack[TreeNode]() + // stack.push(root) + // list += stack.pop().data + // while(!stack.isEmpty){ + // if (stack.top.left != null) stack.push(stack.top.left) + // if (stack.top.right != null) stack.push(stack.top.right) + // } + + if (root == null) return null + val resultList = mutable.ListBuffer[Int]() + val treeStack = mutable.ListBuffer[TreeNode]() + treeStack.append(root) + while (!treeStack.isEmpty) { + val tempNode = treeStack.remove(0) + resultList += tempNode.data + if (tempNode.left != null) treeStack.append(tempNode.left) + if (tempNode.right != null) treeStack.append(tempNode.right) + + } + resultList.toList + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P23.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P23.scala" new file mode 100644 index 00000000..ce9a85af --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P23.scala" @@ -0,0 +1,36 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/15 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P23 { + def VerifySquenceOfBST(sequence: Array[Int]): Boolean = { + + if (sequence.length == 0) { + return false; + } + if (sequence.length == 1) { + return true; + } + return judge(sequence, 0, sequence.length - 1); + } + + def judge(a: Array[Int], start: Int, end: Int): Boolean = { + if (start >= end) { + return true; + } + var i = start; + while (a(i) < a(end)) { + i += 1 + } + for (j <- i until end) { + if (a(j) < a(end)) { + return false; + } + } + return judge(a, start, i - 1) && judge(a, i, end - 1) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P24.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P24.scala" new file mode 100644 index 00000000..a5ee6053 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P24.scala" @@ -0,0 +1,27 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/3/16 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P24 { + val listAll = new collection.mutable.ListBuffer[collection.immutable.List[Int]]() + val list = new collection.mutable.ListBuffer[Int]() + + def findPath(root: TreeNode, targetO: Int): List[List[Int]] = { + var target = targetO + if (root == null) return listAll.toList + list.append(root.data) + target -= root.data + if (target == 0 && root.left == null & root.right == null) + listAll.append(list.toList) + findPath(root.left, target) + findPath(root.right, target) + list.remove(list.size - 1) + listAll.toList + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P25.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P25.scala" new file mode 100644 index 00000000..61eb6a20 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P25.scala" @@ -0,0 +1,24 @@ +package com.xixici + +import com.xixici.util.RandomListNode + +/** + * Created by xixici + * Date: 2019/3/19 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P25 { + def Clone(pHead: RandomListNode): RandomListNode = { + + if (pHead == null) return null + + val newNode = new RandomListNode(pHead.data) + + newNode.random = pHead.random + newNode.next = Clone(pHead.next) + + newNode + + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P26.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P26.scala" new file mode 100644 index 00000000..028e0e65 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P26.scala" @@ -0,0 +1,38 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/3/19 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P26 { + var preNode: TreeNode = _ + + def Convert(root: TreeNode): TreeNode = { + if (root == null) return null + convertNode(root) + if (preNode == null) return null + while (preNode.left != null) { + preNode = preNode.left + } + preNode + } + + def convertNode(current: TreeNode): Unit = { + if (current == null) return + if (current.left != null) { + convertNode(current.left) + } + current.left = preNode + if (preNode != null) { + preNode.right = current + } + preNode = current + if (current.right != null) { + convertNode(current.right) + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P27.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P27.scala" new file mode 100644 index 00000000..1f7a059f --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P27.scala" @@ -0,0 +1,47 @@ +package com.xixici + +import scala.collection.mutable +import scala.collection.mutable.ListBuffer + +/** + * Created by xixici + * Date: 2019/3/20 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P27 { + val list = new collection.mutable.ListBuffer[String]() + + def Permutation(str: String): List[String] = { + if (str != null && str.length() > 0) { + PermutationHelper(str.toCharArray, 0, list) + list.sorted + } + list.toList + + } + + + def PermutationHelper(chars: Array[Char], i: Int, list: ListBuffer[String]): Unit = { + if (i == chars.length - 1) { + list.append(chars.mkString("")) + } else { + val charSet = new mutable.HashSet[Char]() + for (j <- i until chars.length) { + if (j == i || !charSet.contains(chars(j))) { + charSet.add(chars(j)) + SwapTwo(chars, i, j) + PermutationHelper(chars, i + 1, list) + SwapTwo(chars, j, i) + } + } + } + } + + def SwapTwo(chars: Array[Char], i: Int, j: + Int) = { + val tmp = chars(i) + chars(i) = chars(j) + chars(j) = tmp + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P28.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P28.scala" new file mode 100644 index 00000000..72d4acd8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P28.scala" @@ -0,0 +1,27 @@ +package com.xixici + +import scala.collection.mutable + +/** + * Created by xixici + * Date: 2019/3/18 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P28 { + def MoreThanHalfNum_Solution(arr: Array[Int]): Int = { + val hashMap = new mutable.HashMap[Int, Int]() + val len = arr.length + for (i <- 0 until len) { + val tmp = hashMap.getOrElseUpdate(arr(i), 0) + if (tmp == 0) { + hashMap.put(arr(i), 1) + } else { + hashMap.put(arr(i), tmp + 1) + } + if (tmp + 1 > len / 2) return arr(i) + + } + 0 + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P29.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P29.scala" new file mode 100644 index 00000000..60e8db7d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P29.scala" @@ -0,0 +1,28 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/20 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P29 { + def GetLeastNumbers_Solution(input: Array[Int], k: Int): List[Int] = { + val list = new collection.mutable.ListBuffer[Int]() + if (input == null || input.length <= 0 || input.length < k) { + return list.toList + } + // normal sort + for (i <- 0 until k) { + for (j <- 0 until input.length - i - 1) { + if (input(j) < input(j + 1)) { + val temp = input(j) + input(j) = input(j + 1) + input(j + 1) = temp + } + } + list.append(input(input.length - i - 1)) + } + list.toList + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P30.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P30.scala" new file mode 100644 index 00000000..f7a48c09 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P30.scala" @@ -0,0 +1,28 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/21 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P30 { + def FindGreatestSumOfSubarr(arr: Array[Int]): Int = { + if (arr.length == 0 || arr == null) { + return 0 + } + var curSum = 0 + var greatestSum = 0 + for (i <- 0 until arr.length) { + if (curSum <= 0) { + curSum = arr(i) + } else { + curSum += arr(i) + } + if (curSum > greatestSum) { + greatestSum = curSum + } + } + greatestSum + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P31.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P31.scala" new file mode 100644 index 00000000..07d844e0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P31.scala" @@ -0,0 +1,20 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/22 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P31 { + + def NumberOf1Between1AndN_Solution(n: Int) = { + var count = 0 + var i = 1 + while (i < n) { + count += (n / (i * 10)) * i + Math.min(Math.max(n % (i * 10) - i + 1, 0), i) + i *= 10 + } + count + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P32.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P32.scala" new file mode 100644 index 00000000..bf80bbb4 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P32.scala" @@ -0,0 +1,29 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/21 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P32 { + def PrintMinNumber(numbers: Array[Int]): String = { + var str: String = "" + for (i <- numbers.indices) { + for (j <- i + 1 until numbers.length) { + val a = (numbers(i) + "" + numbers(j)).toInt + val b = (numbers(j) + "" + numbers(i)).toInt + if (a > b) { + val t = numbers(i) + numbers(i) = numbers(j) + numbers(j) = t + } + } + } + for (i <- numbers.indices) { + str += numbers(i).toString + } + str + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P33.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P33.scala" new file mode 100644 index 00000000..2a59cb47 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P33.scala" @@ -0,0 +1,22 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/21 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P33 { + def GetUglyNumber_Solution(index: Int) = { + val list = new collection.mutable.ListBuffer[Int]() + list.append(1) + var t2, t3, t5 = 0 + for (i <- 0 until index) { + list.append(math.min(math.min(list(t2) * 2, list(t3) * 3), list(t5) * 5)) + if (list(i + 1) == list(t2) * 2) t2 += 1 + if (list(i + 1) == list(t3) * 3) t3 += 1 + if (list(i + 1) == list(t5) * 5) t5 += 1 + } + list(index - 1) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P34.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P34.scala" new file mode 100644 index 00000000..f9277d56 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P34.scala" @@ -0,0 +1,21 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/22 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P34 { + def FirstNotRepeatingChar(str: String): Int = { + val chars = str.toCharArray + val map = new Array[Int](256) + for (i <- 0 until str.length) { + map(chars(i)) += 1 + } + for (i <- 0 until chars.length) { + if (map(chars(i)) == 1) return i + } + -1 + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P35.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P35.scala" new file mode 100644 index 00000000..29955f3b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P35.scala" @@ -0,0 +1,67 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/22 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P35 { + def InversePairs(arr: Array[Int]): Int = { + if (arr == null || arr.length == 0) { + return 0 + } + val copy = new Array[Int](arr.length) + for (i <- arr.indices) { + copy(i) = arr(i) + } + val count = InversePairsCore(arr, copy, 0, arr.length - 1) + return count + 0 + } + + def InversePairsCore(arr: Array[Int], copy: Array[Int], low: Int, high: Int): Int = { + if (low == high) { + return 0 + } + val mid = (low + high) >> 1 + val leftCount = InversePairsCore(arr, copy, low, mid) % 1000000007 + val rightCount = InversePairsCore(arr, copy, mid + 1, high) % 1000000007 + var count = 0 + var i = mid + var j = high + var locCopy = high + while (i >= low && j > mid) { + if (arr(i) > arr(j)) { + count += (j - mid) + copy(locCopy) = arr(i) + locCopy -= 1 + i -= 1 + if (count >= 1000000007) { + count %= 1000000007 + } + } + else { + copy(locCopy) = arr(j) + locCopy -= 1 + j -= 1 + } + } + for (i <- i until low by -1) { + copy(locCopy) = arr(i) + locCopy -= 1 + + } + for (j <- j until mid by -1) { + copy(locCopy) = arr(j) + locCopy -= 1 + + } + for (s <- low to high) { + arr(s) = copy(s) + } + (leftCount + rightCount + count) % 1000000007 + + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P36.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P36.scala" new file mode 100644 index 00000000..ed5a58a2 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P36.scala" @@ -0,0 +1,25 @@ +package com.xixici + +import com.xixici.util.ListNode + +/** + * Created by xixici + * Date: 2019/3/22 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P36 { + def FindFirstCommonNode(pHead1: ListNode, pHead2: ListNode): ListNode = { + var p1 = pHead1 + var p2 = pHead2 + while (p1 != p2) { + p1 = p1.next + p2 = p2.next + if (p1 != p2) { + if (p1 == null) p1 = pHead1 + if (p2 == null) p2 = pHead2 + } + } + p1 + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P37.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P37.scala" new file mode 100644 index 00000000..64389b79 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P37.scala" @@ -0,0 +1,50 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P37 { + def GetNumberOfK(array: Array[Int], k: Int): Int = { + val length = array.length + if (length <= 0) return 0 + val firstK = getFirstK(array, k, 0, length - 1) + val lastK = getLastK(array, k, 0, length - 1) + if (firstK != -1 && lastK != -1) { + return lastK - firstK + 1 + } + 0 + } + + def getFirstK(arr: Array[Int], k: Int, start: Int, end: Int): Int = { + val mid = (start + end) >> 1 + if (arr(mid) > k) { + getFirstK(arr, k, start, mid - 1) + } + else if (arr(mid) < k) { + getFirstK(arr, k, mid + 1, end) + } + else if (mid - 1 >= 0 && arr(mid - 1) == k) { + getFirstK(arr, k, start, mid - 1) + } else { + mid + } + } + + def getLastK(arr: Array[Int], k: Int, start: Int, end: Int): Int = { + val mid = (start + end) >> 1 + if (arr(mid) > k) { + getLastK(arr, k, start, mid - 1) + } + else if (arr(mid) < k) { + getLastK(arr, k, mid + 1, end) + } + else if (mid + 1 <= end && arr(mid + 1) == k) { + getLastK(arr, k, mid + 1, end) + } else { + mid + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P38.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P38.scala" new file mode 100644 index 00000000..faa7789e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P38.scala" @@ -0,0 +1,20 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/3/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P38 { + def TreeDepth(root: TreeNode): Int = { + if (root == null) { + return 0 + } + val left: Int = TreeDepth(root.left) + val right: Int = TreeDepth(root.right) + math.max(left, right) + 1 + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P39.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P39.scala" new file mode 100644 index 00000000..a8cf4832 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P39.scala" @@ -0,0 +1,39 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/3/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P39 { + var isBalanced = true + + def IsBalanced_Solution(root: TreeNode): Boolean = { + + getDepth(root) + isBalanced + + } + + def getDepth(root: TreeNode): Int = { + + if (root == null) + return 0 + val left = getDepth(root.left) + val right = getDepth(root.right) + + if (Math.abs(left - right) > 1) { + isBalanced = false + } + if (right > left) { + right + 1 + } else { + left + 1 + } + + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P40.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P40.scala" new file mode 100644 index 00000000..52022e1b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P40.scala" @@ -0,0 +1,79 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P40 { + + def findNumsAppearOnce(array: Array[Int]): Array[Int] = { + // get(array) + + var num1 = 0 + var num2 = 0 + if (array == null || array.length <= 1) { + num1 = 0 + num2 = 0 + } + val len = array.length + var sum = 0 + var index = 0 + for (i <- 0 until len) { + sum ^= array(i) + } + var flag = true + for (index2 <- 0 until 32 if flag) { + if ((sum & (1 << index2)) != 0) { + flag = false + index = index2 + } + } + for (i <- 0 until len) { + if ((array(i) & (1 << index)) != 0) { + num2 ^= array(i) + } else { + num1 ^= array(i) + } + } + Array(num1, num2) + } + + + def get(a: Array[Int]): Array[Int] = { + if (a == null || a.length < 2) return null + + var number = 0 + for (i <- 0 until a.length) { + number ^= a(i) + } + val index = firstBitis1(number) + var num1 = 0 + var num2 = 0 + for (i <- 0 until a.length) { + if (isBit1(a(i), index)) { + num1 ^= a(i) + } else num2 ^= a(i) + } + Array(num1, num2) + } + + def firstBitis1(num: Int): Int = { + var index = 0 + var _num = num + while ((_num & 1) == 0) { + _num >>= 1 + index += 1 + } + index + } + + def isBit1(num: Int, index: Int): Boolean = { + var _num = num + for (i <- 0 until index) { + _num >>= index + } + (_num & 1) == 1 + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P41.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P41.scala" new file mode 100644 index 00000000..2954bfc9 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P41.scala" @@ -0,0 +1,34 @@ +package com.xixici + +import scala.collection.mutable + +/** + * Created by xixici + * Date: 2019/3/30 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P41 { + def FindContinuousSequence(sum: Int) = { + var result = mutable.Buffer[Int]() + var plow = 1 + var phigh = 2 + while (phigh > plow) { + val cur = (phigh + plow) * (phigh - plow + 1) / 2 + if (cur == sum) { + val list = mutable.Buffer[Int]() + for (i <- plow to phigh) { + list += i + } + result = result ++ list + plow += 1 + } else if (cur < sum) { + phigh += 1 + } else { + plow += 1 + } + + } + result.toList + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P42.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P42.scala" new file mode 100644 index 00000000..1588f23a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P42.scala" @@ -0,0 +1,29 @@ +package com.xixici + +import scala.collection.mutable + +/** + * Created by xixici + * Date: 2019/3/30 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P42 { + def FindNumbersWithSum(array: Array[Int], sum: Int): List[Int] = { + var i = 0 + var j = array.length - 1 + val list = mutable.Buffer[Int]() + while (i < j) { + if (array(i) + array(j) == sum) { + list.append(array(i)) + list.append(array(j)) + return list.toList + } else if (array(i) + array(j) > sum) { + j -= 1 + } else { + i += 1 + } + } + list.toList + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P43.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P43.scala" new file mode 100644 index 00000000..2367886d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P43.scala" @@ -0,0 +1,30 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/30 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P43 { + def LeftRotateString(str: String, n: Int) = { + val chars: Array[Char] = str.toCharArray + reverse(chars, 0, n - 1) + reverse(chars, n, chars.length - 1) + reverse(chars, 0, chars.length - 1) + chars.mkString("") + } + + def reverse(chars: Array[Char], start: Int, end: Int): Unit = { + var i = start + var j = end + while (i < j) { + val tmp = chars(i) + chars(i) = chars(j) + chars(j) = tmp + i += 1 + j -= 1 + } + + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P44.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P44.scala" new file mode 100644 index 00000000..ccf2f96d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P44.scala" @@ -0,0 +1,39 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/4/26 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P44 { + def ReverseSentence(str: String) = { + val chars = str.toCharArray + val charsLen = chars.length + reverse(chars, 0, charsLen - 1) + var blank = -1 + for (i <- 0 until charsLen) { + if (chars(i) == ' ') { + val blankNext = i + reverse(chars, blank + 1, blankNext - 1) + blank = blankNext + + } + } + reverse(chars, blank + 1, charsLen - 1) + chars.mkString("") + } + + + def reverse(chars: Array[Char], start: Int, end: Int): Unit = { + var i = start + var j = end + while (i < j) { + val tmp = chars(i) + chars(i) = chars(j) + chars(j) = tmp + i += 1 + j -= 1 + } + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P45.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P45.scala" new file mode 100644 index 00000000..79432d5d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P45.scala" @@ -0,0 +1,29 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/4/26 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P45 { + def isContinuous(numbers: Array[Int]): Boolean = { + val numLen = numbers.length + if (numLen != 5) return false + var min = 14 + var max = -1 + var flag = 0 + for (i <- 0 until numLen if numbers(i) != 0) { + val number = numbers(i) + if (number < 0 || number > 13) return false + // if (number == 0) return + if (((flag >> number) & 1) == 1) return false + flag |= (1 << number) + if (number > max) max = number + if (number < min) min = number + if (max - min >= 5) return false + } + true + + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P46.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P46.scala" new file mode 100644 index 00000000..143a0823 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P46.scala" @@ -0,0 +1,30 @@ +package com.xixici + +import scala.collection.mutable.ListBuffer + +/** + * Created by xixici + * Date: 2019/4/26 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P46 { + def LastRemaining_Solution(n: Int, m: Int) = { + val list = ListBuffer[Int]() + for (i <- 0 until n) { + list.append(i) + } + + var bt = 0 + while (list.size > 1) { + bt = (bt + m - 1) % list.size + list.remove(bt) + } + + if (list.size == 1) + list(0) + else { + -1 + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P47.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P47.scala" new file mode 100644 index 00000000..cdd22965 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P47.scala" @@ -0,0 +1,19 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/16 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P47 { + def Sum_Solution(n: Int): Int = { + // (1 + n) * n / 2 + var sum = n + (sum > 0) && { + sum += Sum_Solution(n - 1) + sum > 0 + } + sum + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P48.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P48.scala" new file mode 100644 index 00000000..f8d03c0a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P48.scala" @@ -0,0 +1,21 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/16 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P48 { + def Add(num1: Int, num2: Int) = { + var numA = num1 + var numB = num2 + while (numB != 0) { + val sum = numA ^ numB + val carray = (numA & numB) << 1 + numA = sum + numB = carray + } + numA + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P49.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P49.scala" new file mode 100644 index 00000000..877ebb60 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P49.scala" @@ -0,0 +1,29 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/16 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P49 { + def StrToInt(str: String): Int = { + if (str.length == 0) { + return 0 + } + var sum = 0 + var label = 1 + if (str.charAt(0) == '+') label = 1 + if (str.charAt(0) == '-') label = -1 + + for (s <- str) { + if (s > '9' || s < '0') { + sum = 0 + } + else { + sum = sum * 10 + s - '0' + } + } + label * sum + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P50.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P50.scala" new file mode 100644 index 00000000..a2ed0e84 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P50.scala" @@ -0,0 +1,23 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/18 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P50 { + def duplicate(numbers: Array[Int], length: Int, duplication: Array[Int]): Boolean = { + + val k = new Array[Boolean](length) + for (i <- 0 until length) { + if (k(numbers(i))) { + duplication(0) = numbers(i) + println(duplication(0)) + return true + } + k(numbers(i)) = true + } + false + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P51.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P51.scala" new file mode 100644 index 00000000..b49aec7d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P51.scala" @@ -0,0 +1,25 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/18 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P51 { + def multiply(A: Array[Int]): Array[Int] = { + val len = A.length + val B = new Array[Int](len) + B(0) = 1 + for (i <- 1 until len) { + B(i) = B(i - 1) * A(i - 1) + } + var tmp = 1 + for (j <- (len - 2) to 0 by -1) { + tmp *= A(j + 1) + B(j) *= tmp + } + B + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P52.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P52.scala" new file mode 100644 index 00000000..3a288608 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P52.scala" @@ -0,0 +1,45 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/3/18 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P52 { + def matchPattern(str: Array[Char], pattern: Array[Char]): Boolean = { + if (str == null || pattern == null) { + return false + } + val strIndex = 0 + val patternIndex = 0 + matchCore(str, strIndex, pattern, patternIndex) + } + + def matchCore(str: Array[Char], strIndex: Int, pattern: Array[Char], patternIndex: Int): Boolean = { + //有效性检验:str到尾,pattern到尾,匹配成功 + if (strIndex == str.length && patternIndex == pattern.length) { + return true + } + //pattern先到尾,匹配失败 + if (strIndex != str.length && patternIndex == pattern.length) { + return false + } + //模式第2个是*,且字符串第1个跟模式第1个匹配,分3种匹配模式;如不匹配,模式后移2位 + if (patternIndex + 1 < pattern.length && pattern(patternIndex + 1) == '*') { + if ((strIndex != str.length && pattern(patternIndex) == str(strIndex)) || (pattern(patternIndex) == '.' && strIndex != str.length)) { + //模式后移2,视为x*匹配0个字符 + //视为模式匹配1个字符 + //*匹配1个,再匹配str中的下一个 + return matchCore(str, strIndex, pattern, patternIndex + 2) || matchCore(str, strIndex + 1, pattern, patternIndex + 2) || matchCore(str, strIndex + 1, pattern, patternIndex) + } else { + return matchCore(str, strIndex, pattern, patternIndex + 2) + } + } + //模式第2个不是*,且字符串第1个跟模式第1个匹配,则都后移1位,否则直接返回false + if ((strIndex != str.length && pattern(patternIndex) == str(strIndex)) || (pattern(patternIndex) == '.' && strIndex != str.length)) { + return matchCore(str, strIndex + 1, pattern, patternIndex + 1) + } + false + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P53.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P53.scala" new file mode 100644 index 00000000..ed893bdc --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P53.scala" @@ -0,0 +1,17 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/4/27 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P53 { + def isNumeric(str: Array[Char]): Boolean = { + val strOri = str.mkString("") + strOri.matches("[\\+-]?[0-9]*(\\.[0-9]*)?([eE][\\+-]?[0-9]+)?") + + + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P54.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P54.scala" new file mode 100644 index 00000000..f73e87d5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P54.scala" @@ -0,0 +1,31 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/4/29 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P54 { + + val hashtable = new Array[Int](256) + val s = new StringBuffer() + + //Insert one char from stringstream + def Insert(ch: Char): Unit = { + s.append(ch) + if (hashtable(ch) == 0) + hashtable(ch) = 1 + else hashtable(ch) += 1 + } + + //return the first appearence once char in current stringstream + def FirstAppearingOnce(): Char = { + val str = s.toString.toCharArray + for (c <- str) { + if (hashtable(c) == 1) + return c + } + '#' + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P55.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P55.scala" new file mode 100644 index 00000000..864c35a0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P55.scala" @@ -0,0 +1,33 @@ +package com.xixici + +import com.xixici.util.ListNode + +/** + * Created by xixici + * Date: 2019/4/29 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P55 { + def EntryNodeOfLoop(pHead: ListNode): ListNode = { + if (pHead == null || pHead.next == null || pHead.next.next == null) return null + var fast = pHead.next.next + var slow = pHead.next + /////先判断有没有环 + while (fast != slow) { + if (fast.next != null && fast.next.next != null) { + fast = fast.next.next + slow = slow.next + } else { //没有环,返回 + return null + } + } + //循环出来的话就是有环,且此时 fast == slow. + fast = pHead + while (fast != slow) { + fast = fast.next + slow = slow.next + } + slow + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P56.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P56.scala" new file mode 100644 index 00000000..168f3449 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P56.scala" @@ -0,0 +1,30 @@ +package com.xixici + +import com.xixici.util.ListNode + +/** + * Created by xixici + * Date: 2019/4/29 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P56 { + def deleteDuplication(pHead: ListNode): ListNode = { + if (pHead == null || pHead.next == null) { // 只有0个或1个结点,则返回 + return pHead + } + if (pHead.data == pHead.next.data) { + // 当前结点是重复结点 + var pNode = pHead.next + while (pNode != null && pNode.data == pHead.data) { + // 跳过值与当前结点相同的全部结点,找到第一个与当前结点不同的结点 + pNode = pNode.next + } + deleteDuplication(pNode) // 从第一个与当前结点不同的结点开始递归 + } else { + // 当前结点不是重复结点 + pHead.next = deleteDuplication(pHead.next) // 保留当前结点,从下一个结点开始递归 + pHead + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P57.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P57.scala" new file mode 100644 index 00000000..f5d3bc54 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P57.scala" @@ -0,0 +1,30 @@ +package com.xixici + +import com.xixici.util.TreeLinkNode + +/** + * Created by xixici + * Date: 2019/5/7 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P57 { + def TreeLinkNode(pNodeO: TreeLinkNode): TreeLinkNode = { + var pNode = pNodeO + if (pNode == null) + return pNode + if (pNode.right != null) { // 节点有右子树 + pNode = pNode.right + while (pNode.left != null) { + pNode = pNode.left + } + return pNode + } + while (pNode.next != null) { //没右子树,则找第一个当前节点是父节点左孩子的节点 + if (pNode.next.left == pNode) + return pNode.next + pNode = pNode.next + } + null //退到了根节点仍没找到,则返回null + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P58.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P58.scala" new file mode 100644 index 00000000..25b1ee75 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P58.scala" @@ -0,0 +1,25 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/5/8 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P58 { + def comRoot(left: TreeNode, right: TreeNode): Boolean = { + if (left == null) return right == null + if (right == null) return false + if (left.data != right.data) return false + comRoot(left.right, right.left) && comRoot(left.left, right.right) + } + + def isSymmetrical(pRoot: TreeNode): Boolean = { + if (pRoot == null) { + return true + } + comRoot(pRoot.left, pRoot.right) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P59.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P59.scala" new file mode 100644 index 00000000..91792c19 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P59.scala" @@ -0,0 +1,55 @@ +package com.xixici + +import com.xixici.util.TreeNode + +import scala.collection.mutable + +/** + * Created by xixici + * Date: 2019/5/8 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P59 { + def Print(pNode: TreeNode) = { + var layer = 1 + val list = mutable.ArrayBuffer[mutable.ArrayBuffer[Int]]() + val s1 = mutable.ArrayStack[TreeNode]() + val s2 = mutable.ArrayStack[TreeNode]() + s1.push(pNode) + while (s1.nonEmpty || s2.nonEmpty) { + if (layer % 2 != 0) { + val temp = mutable.ArrayBuffer[Int]() + while (s1.nonEmpty) { + val node = s1.pop() + if (node != null) { + temp.append(node.data) + s2.push(node.left) + s2.push(node.right) + } + } + layer += 1 + if (temp.nonEmpty) { + list.append(temp) + } + } else { + val temp = mutable.ArrayBuffer[Int]() + while (s2.nonEmpty) { + val node = s2.pop() + if (node != null) { + temp.append(node.data) + s1.push(node.right) + s1.push(node.left) + } + } + layer += 1 + if (temp.nonEmpty) { + list.append(temp) + } + + + } + } + list + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P60.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P60.scala" new file mode 100644 index 00000000..bdab9ecc --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P60.scala" @@ -0,0 +1,56 @@ +package com.xixici + +import com.xixici.util.TreeNode + +import scala.collection.mutable + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P60 { + def Print(pNode: TreeNode) = { + var layer = 1 + val list = mutable.ArrayBuffer[mutable.ArrayBuffer[Int]]() + val s1 = mutable.ArrayStack[TreeNode]() + val s2 = mutable.ArrayStack[TreeNode]() + s1.push(pNode) + while (s1.nonEmpty || s2.nonEmpty) { + if (layer % 2 != 0) { + val temp = mutable.ArrayBuffer[Int]() + while (s1.nonEmpty) { + val node = s1.pop() + if (node != null) { + temp.append(node.data) + s2.push(node.right) + s2.push(node.left) + } + } + layer += 1 + if (temp.nonEmpty) { + list.append(temp) + } + } else { + val temp = mutable.ArrayBuffer[Int]() + while (s2.nonEmpty) { + val node = s2.pop() + if (node != null) { + temp.append(node.data) + s1.push(node.left) + s1.push(node.right) + } + } + layer += 1 + if (temp.nonEmpty) { + list.append(temp) + } + + + } + } + list + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P61.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P61.scala" new file mode 100644 index 00000000..b1e3b196 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P61.scala" @@ -0,0 +1,49 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P61 { + + var index = -1 + + def serialize(root: TreeNode): String = { + if (root == null) return "" + val sb = new StringBuilder + serialize(root, sb) + sb.substring(0, sb.length - 1) + } + + def deserialize(str: String): TreeNode = { + if (str == null || str.length <= 0) return null + val strs = str.split(",") + deserialize(strs) + } + + private def serialize(root: TreeNode, sb: StringBuilder): Unit = { + if (root == null) { + sb.append("$,") + return + } + sb.append(root.data).append(",") + serialize(root.left, sb) + serialize(root.right, sb) + + } + + private def deserialize(strs: Array[String]): TreeNode = { + index += 1 + if (!(strs(index) == "$")) { + val root = new TreeNode(strs(index).toInt) + root.left = deserialize(strs) + root.right = deserialize(strs) + return root + } + null + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P62.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P62.scala" new file mode 100644 index 00000000..b73ab22e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P62.scala" @@ -0,0 +1,28 @@ +package com.xixici + +import com.xixici.util.TreeNode + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P62 { + var index = 0 + + def KthNode(root: TreeNode, k: Int): TreeNode = { + if (root != null) { + var node = KthNode(root.left, k) + if (node != null) + return node + index += 1 + if (index == k) + return root + node = KthNode(root.right, k) + if (node != null) + return node + } + null + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P64.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P64.scala" new file mode 100644 index 00000000..428454b8 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P64.scala" @@ -0,0 +1,43 @@ +package com.xixici + +import java.{util => ju} + +import scala.collection.mutable.ListBuffer + +/** + * Created by xixici + * Date: 2019/6/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P64 { + + def maxInWindows(nums: Array[Int], size: Int): List[Int] = { + if (nums == null || nums.length <= 0 || size <= 0) return null + + val list = new ListBuffer[Int] + // deque中保存索引 以支持滑动 + val deque = new ju.LinkedList[Int]() + // 第一个窗口前 + for (i <- 0 until size - 1) { + while (!deque.isEmpty && nums(i) > nums(deque.getLast)) { + deque.removeLast() + } + deque.addLast(i) + } + // 窗口计算和滑动 + for (i <- size - 1 until nums.length) { + while (!deque.isEmpty && nums(i) > nums(deque.getLast)) { + deque.removeLast() + } + deque.addLast(i) + // 滑动 + if (i - deque.getFirst + 1 > size) { + deque.removeFirst() + } + list.append(nums(deque.getFirst)) + } + + list.toList + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P65.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P65.scala" new file mode 100644 index 00000000..c4440b4d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P65.scala" @@ -0,0 +1,45 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/6/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P65 { + + def hasPath(matrix: Array[Char], rows: Int, cols: Int, str: Array[Char]): Boolean = { + if (matrix == null || rows <= 0 || cols <= 0 || str == null) return false + val visited = new Array[Boolean](rows * cols) + val pathLen = Array(0) + for (row <- 0 until rows) { + for (col <- 0 until cols) { + if (hasPathCore(matrix, str, rows, cols, row, col, visited, pathLen)) { + return true + } + } + } + false + } + + private def hasPathCore(matrix: Array[Char], str: Array[Char], rows: Int, cols: Int, row: Int, col: Int, + visited: Array[Boolean], pathLen: Array[Int]): Boolean = { + if (pathLen(0) == str.length) return true + + var hasPath = false + if (row >= 0 && row < rows && col >= 0 && col < cols && matrix(row * cols + col) == str(pathLen(0)) + && !visited(row * cols + col)) { + pathLen(0) += 1 + visited(row * cols + col) = true + hasPath = hasPathCore(matrix, str, rows, cols, row - 1, col, visited, pathLen) || + hasPathCore(matrix, str, rows, cols, row + 1, col, visited, pathLen) || + hasPathCore(matrix, str, rows, cols, row, col - 1, visited, pathLen) || + hasPathCore(matrix, str, rows, cols, row, col + 1, visited, pathLen) + if (!hasPath) { + pathLen(0) -= 1 + visited(row * cols + col) = false + } + } + hasPath + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P66.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P66.scala" new file mode 100644 index 00000000..5b3bf2e0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/P66.scala" @@ -0,0 +1,49 @@ +package com.xixici + +/** + * Created by xixici + * Date: 2019/6/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P66 { + + def movingCount(rows: Int, cols: Int, k: Int): Int = { + if (rows < 0 || cols < 0 || k < 0) return 0 + + val visited = new Array[Boolean](rows * cols) + val count = movingCountCore(rows, cols, k, 0, 0, visited) + count + } + + private def movingCountCore(rows: Int, cols: Int, k: Int, row: Int, col: Int, visited: Array[Boolean]): Int = { + var count = 0 + if (check(rows, cols, k, row, col, visited)) { + visited(row * cols + col) = true + count = 1 + + movingCountCore(rows, cols, k, row + 1, col, visited) + + movingCountCore(rows, cols, k, row - 1, col, visited) + + movingCountCore(rows, cols, k, row, col + 1, visited) + + movingCountCore(rows, cols, k, row, col - 1, visited) + } + count + } + + private def check(rows: Int, cols: Int, k: Int, row: Int, col: Int, visited: Array[Boolean]): Boolean = { + if (row >= 0 && row < rows && col >= 0 && col < cols && getDigitSum(row) + getDigitSum(col) <= k && + !visited(row * cols + col)) { + return true + } + false + } + + private def getDigitSum(num: Int): Int = { + var sum = 0 + var _num = num + while (_num > 0) { + sum += _num % 10 + _num /= 10 + } + sum + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/p63.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/p63.scala" new file mode 100644 index 00000000..e51fbecd --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/p63.scala" @@ -0,0 +1,42 @@ +package com.xixici + +import java.util.Comparator +import java.{util => ju} + +/** + * Created by xixici + * Date: 2019/5/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +object P63 { + + val minHeap = new ju.PriorityQueue[Int](15) + val maxHeap = new ju.PriorityQueue[Int](15, new Comparator[Int] { + override def compare(o1: Int, o2: Int): Int = o2 - o1 + }) + var count = 0 + + def insert(num: Int) = { + if (count % 2 == 0) { + maxHeap.offer(num) + val filterNum = maxHeap.poll() + minHeap.offer(filterNum) + } else { + minHeap.offer(num) + val filterNum = minHeap.poll() + maxHeap.offer(filterNum) + } + count += 1 + } + + // 最大堆最小堆法 + def getMedian(): Double = { + if (count % 2 == 0) { + (maxHeap.peek() + minHeap.peek()) / 2.0 + } else { + minHeap.peek().toDouble + } + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/ListNode.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/ListNode.scala" new file mode 100644 index 00000000..3addea3e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/ListNode.scala" @@ -0,0 +1,12 @@ +package com.xixici.util + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class ListNode(var data: Int) { + var next: ListNode = null +} + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/RandomListNode.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/RandomListNode.scala" new file mode 100644 index 00000000..ade080db --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/RandomListNode.scala" @@ -0,0 +1,13 @@ +package com.xixici.util + +/** + * Created by xixici + * Date: 2019/3/19 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class RandomListNode(var data: Int) { + var next: RandomListNode = null + var random: RandomListNode = null + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/TreeLinkNode.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/TreeLinkNode.scala" new file mode 100644 index 00000000..569b6b3e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/TreeLinkNode.scala" @@ -0,0 +1,13 @@ +package com.xixici.util + +/** + * Created by xixici + * Date: 2019/5/7 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class TreeLinkNode(var data: Int) { + var left: TreeLinkNode = _ + var right: TreeLinkNode = _ + var next: TreeLinkNode = _ +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/TreeNode.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/TreeNode.scala" new file mode 100644 index 00000000..a3508927 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/main/scala/com/xixici/util/TreeNode.scala" @@ -0,0 +1,12 @@ +package com.xixici.util + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class TreeNode(var data: Int) { + var left: TreeNode = _ + var right: TreeNode = _ +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q02.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q02.java" new file mode 100644 index 00000000..1507df17 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q02.java" @@ -0,0 +1,15 @@ +package com.xixici; + +public class Q02 { + public String replaceSpace(StringBuffer str) { + StringBuffer newStr = new StringBuffer(); + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == ' ') { + newStr.append("%20"); + } else { + newStr.append(str.charAt(i)); + } + } + return newStr.toString(); + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q03.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q03.java" new file mode 100644 index 00000000..341ac287 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q03.java" @@ -0,0 +1,28 @@ +package com.xixici; + +import java.util.ArrayList; +import java.util.Stack; + +public class Q03 { + public ArrayList printListFromTailToHead2(ListNode listNode) { + ArrayList res = new ArrayList<>(); + Stack stack = new Stack<>(); + while (listNode != null) { + stack.push(listNode.val); + listNode = listNode.next; + } + while (!stack.isEmpty()) { + res.add(stack.pop()); + } + return res; + } + + public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q04.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q04.java" new file mode 100644 index 00000000..e20d93d1 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q04.java" @@ -0,0 +1,34 @@ +package com.xixici; + +public class Q04 { + public TreeNode reConstructBinaryTree(int[] pre, int[] in) { + return reConBTree(pre, 0, pre.length - 1, in, 0, in.length - 1); + } + + public TreeNode reConBTree(int[] pre, int preleft, int preright, int[] in, int inleft, int inright) { + if (preleft > preright || inleft > inright)// ????????????????null + return null; + // ??????TreeNode + TreeNode root = new TreeNode(pre[preleft]); + // ??????????????????????? + for (int i = inleft; i <= inright; i++) { + if (pre[preleft] == in[i]) { + // ???????????????????? + root.left = reConBTree(pre, preleft + 1, preleft + i - inleft, in, inleft, i - 1); + // ???????????????????? + root.right = reConBTree(pre, preleft + i + 1 - inleft, preright, in, i + 1, inright); + } + } + return root; + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q05.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q05.java" new file mode 100644 index 00000000..9fe3c206 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q05.java" @@ -0,0 +1,25 @@ +package com.xixici; + +import java.util.Stack; + +public class Q05 { + + Stack stack1 = new Stack(); + Stack stack2 = new Stack(); + + public void push(int node) { + stack1.push(node); + } + + public int pop() { + if (stack1.empty() && stack2.empty()) { + throw new RuntimeException("Queue is empty!"); + } + if (stack2.empty()) { + while (!stack1.empty()) { + stack2.push(stack1.pop()); + } + } + return stack2.pop(); + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q06.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q06.java" new file mode 100644 index 00000000..7d995833 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q06.java" @@ -0,0 +1,25 @@ +package com.xixici; + +public class Q06 { + public static int minNumberInRotateArray(int[] array) { + if (array.length == 0) + return 0; + int left = 0; + int right = array.length - 1; + int middle = -1; + while (array[left] >= array[right]) { + if (right - left == 1) { + middle = right; + break; + } + middle = left + (right - left) / 2; + if (array[middle] >= array[left]) { + left = middle; + } + if (array[middle] <= array[right]) { + right = middle; + } + } + return array[middle]; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q07.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q07.java" new file mode 100644 index 00000000..81cefabb --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q07.java" @@ -0,0 +1,18 @@ +package com.xixici; + +public class Q07 { + public int Fibonacci(int n) { + int a = 1, b = 1, v = 0; + if (n == 1 || n == 2) { + v = 1; + } + if (n >= 3) { + for (int i = 3; i <= n; i++) { + v = a + b; + a = b; + b = v; + } + } + return v; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q08.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q08.java" new file mode 100644 index 00000000..e4d6cfbb --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q08.java" @@ -0,0 +1,22 @@ +package com.xixici; + +public class Q08 { + public int JumpFloor(int target) { + int a = 1, b = 1, v = 0; + if (target == 1) { + v = 1; + } + if (target == 2) { + v = 2; + } + if (target >= 3) { + for (int i = 3; i <= target; i++) { + v = a + b; + a = b; + b = v; + } + } + return v; + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q09.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q09.java" new file mode 100644 index 00000000..f9f7b47c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q09.java" @@ -0,0 +1,14 @@ +package com.xixici; + +public class Q09 { + //2^(n-1) + public int JumpFloorII(int target) { + if (target <= 0) { + return -1; + } else if (target == 1) { + return 1; + } else { + return 2 * JumpFloorII(target - 1); + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q10.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q10.java" new file mode 100644 index 00000000..8588a5bc --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q10.java" @@ -0,0 +1,19 @@ +package com.xixici; + +public class Q10 { + public int RectCover(int target) { + int a = 1, b = 2, v = 0; + if (target == 1) { + v = 1; + } + if (target == 2) { + v = 2; + } + for (int i = 0; i < target - 2; i++) { + v = a + b; + a = b; + b = v; + } + return v; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q11.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q11.java" new file mode 100644 index 00000000..59ce6513 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q11.java" @@ -0,0 +1,12 @@ +package com.xixici; + +public class Q11 { + public int NumberOf1(int n) { + int count = 0; + while (n != 0) { + count++; + n = n & (n - 1); + } + return count; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q12.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q12.java" new file mode 100644 index 00000000..2a2dbaeb --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q12.java" @@ -0,0 +1,18 @@ +package com.xixici; + +public class Q12 { + public double Power(double base, int exponent) { + int n = exponent; + double result = base; + if (exponent < 0) { + n = -exponent; + } + if (n == 0) { + result = 1; + } + for (int i = 1; i < n; i++) { + result *= base; + } + return exponent < 0 ? 1 / result : result; + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q13.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q13.java" new file mode 100644 index 00000000..7b7bf5fe --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q13.java" @@ -0,0 +1,15 @@ +package com.xixici; + +public class Q13 { + public void reOrderArray(int[] array) { + for (int i = 0; i < array.length - 1; i++) { + for (int j = array.length - 1; j > i; j--) { + if (array[j] % 2 == 1 && array[j - 1] % 2 == 0) { + int temp = array[j]; + array[j] = array[j - 1]; + array[j - 1] = temp; + } + } + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q14.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q14.java" new file mode 100644 index 00000000..15b632cf --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q14.java" @@ -0,0 +1,33 @@ +package com.xixici; + +public class Q14 { + public ListNode FindKthToTail(ListNode head, int k) { + ListNode pre = null, p = null; + p = head; + pre = head; + int a = k; + int count = 0; + + while (p != null) { + p = p.next; + count++; + if (k < 1) { + pre = pre.next; + } + k--; + } + if (count < a) + return null; + return pre; + + } + + public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q15.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q15.java" new file mode 100644 index 00000000..6cf5637a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q15.java" @@ -0,0 +1,28 @@ +package com.xixici; + +public class Q15 { + public ListNode ReverseList(ListNode head) { + if (head == null) { + return null; + } + ListNode pre = null; + ListNode next = null; + while (head != null) { + next = head.next; + head.next = pre; + pre = head; + head = next; + } + return pre; + + } + + public class ListNode { + int val; + ListNode next = null; + + ListNode(int val) { + this.val = val; + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q16.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q16.java" new file mode 100644 index 00000000..a98733a3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q16.java" @@ -0,0 +1,5 @@ +package com.xixici; + +public class Q16 { + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q17.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q17.java" new file mode 100644 index 00000000..6b33b1fa --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q17.java" @@ -0,0 +1,39 @@ +package com.xixici; + + +public class Q17 { + public boolean HasSubtree(TreeNode root1, TreeNode root2) { + boolean result = false; + if (root1 != null && root2 != null) { + if (root1.val == root2.val) { + result = DoesTree1HaveTree2(root1, root2); + } + if (!result) { + result = HasSubtree(root1.left, root2); + } + if (!result) { + result = HasSubtree(root1.right, root2); + } + } + return result; + } + + public boolean DoesTree1HaveTree2(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 != null) return false; + if (root2 == null) return true; + if (root1.val != root2.val) return false; + return DoesTree1HaveTree2(root1.left, root2.left) && DoesTree1HaveTree2(root1.right, root2.right); + } + + public class TreeNode { + int val = 0; + TreeNode left = null; + TreeNode right = null; + + public TreeNode(int val) { + this.val = val; + + } + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q18.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q18.java" new file mode 100644 index 00000000..3412fb80 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q18.java" @@ -0,0 +1,5 @@ +package com.xixici; + +public class Q18 { + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q19.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q19.java" new file mode 100644 index 00000000..50c49171 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q19.java" @@ -0,0 +1,57 @@ +package com.xixici; + +import java.util.ArrayList; + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + */ + +public class Q19 { + + public ArrayList printMatrix(int[][] matrix) { + int row = matrix.length; + int col = matrix[0].length; + if (row != 0 && col != 0) { + ArrayList list = new ArrayList(); + int left = 0; + int top = 0; + int bottom = row - 1; + + for (int right = col - 1; left <= right && top <= bottom; --bottom) { + int k; + for (k = left; k <= right; ++k) { + list.add(matrix[top][k]); + } + + for (k = top + 1; k <= bottom; ++k) { + list.add(matrix[k][right]); + } + + if (top != bottom) { + for (k = right - 1; k >= left; --k) { + list.add(matrix[bottom][k]); + } + } + + if (left != right) { + for (k = bottom - 1; k > top; --k) { + list.add(matrix[k][left]); + } + } + + ++top; + ++left; + --right; + } + + return list; + } else { + return null; + } + } +} + + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q20.java" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q20.java" new file mode 100644 index 00000000..162e4862 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/other/java/com/xixici/Q20.java" @@ -0,0 +1,32 @@ +package com.xixici; + +import java.util.Stack; + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + */ +public class Q20 { + + public boolean IsPopOrder(int[] pushA, int[] popA) { + if (pushA.length != 0 && popA.length != 0) { + Stack stack = new Stack(); + int j = 0; + + for (int i = 0; i < popA.length; ++i) { + stack.push(pushA[i]); + + while (j < popA.length && (Integer) stack.peek() == popA[j]) { + stack.pop(); + ++j; + } + } + + return stack.empty(); + } else { + return false; + } + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P01Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P01Test.scala" new file mode 100644 index 00000000..3f05791c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P01Test.scala" @@ -0,0 +1,21 @@ +package com.xixiciTest + +import com.xixici.P01 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ + +class P01Test extends FunSuite { + + var a: Array[Array[Int]] = Array(Array(1, 2, 8, 9), Array(2, 4, 9, 12), Array(4, 7, 10, 13), Array(6, 8, 11, 15)) + + test("P1") { + assert(P01.find(-1, a) === false) + assert(P01.find(7, a) === true) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P02Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P02Test.scala" new file mode 100644 index 00000000..8ae432e6 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P02Test.scala" @@ -0,0 +1,20 @@ +package com.xixiciTest + +import com.xixici.P02.replaceSpace +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P02Test extends FunSuite { + var strOld = "We Are Happy" + var strNew = "We%20Are%20Happy" + val strNew20 = replaceSpace(strOld) + + test("P2Test") { + assert(replaceSpace(strOld) === strNew) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P03Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P03Test.scala" new file mode 100644 index 00000000..9ea3b8d0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P03Test.scala" @@ -0,0 +1,26 @@ +package com.xixiciTest + +import com.xixici.P03 +import com.xixici.util.ListNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P03Test extends FunSuite { + val a = new ListNode(2) + val b = new ListNode(3) + val c = new ListNode(4) + var head = new ListNode(1) + head.next = a + a.next = b + b.next = c + c.next = null + test("P3Test") { + val nodes = P03.printListFromTailToHead(head) + assert(nodes === List(c, b, a, head)) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P04Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P04Test.scala" new file mode 100644 index 00000000..9083a652 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P04Test.scala" @@ -0,0 +1,23 @@ +package com.xixiciTest + +import com.xixici.P04 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/5 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P04Test extends FunSuite { + + + var pre = Array(1, 2, 4, 7, 3, 5, 6, 8) + var in = Array(4, 7, 2, 1, 5, 3, 8, 6) + + test("P04Test") { +// assert(P04.reConstructBinaryTree(pre, in).data === 1) + assert(P04.reConstructBinaryTree(pre, in).left.data === 2) + // assert(P04.reConstructBinaryTree(pre, in).right.data === 3) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P05Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P05Test.scala" new file mode 100644 index 00000000..73dbb671 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P05Test.scala" @@ -0,0 +1,24 @@ +package com.xixiciTest + +import com.xixici.P05 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/11 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P05Test extends FunSuite { + + test("testPush") { + P05.push(1) + P05.push(2) + P05.push(3) + assert(List(P05.pop(), P05.pop(), P05.pop()) === List(1, 2, 3)) + } + + test("testPop") { + assertThrows[Exception](P05.pop()) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P06Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P06Test.scala" new file mode 100644 index 00000000..a8948e1d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P06Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P06 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/11 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P06Test extends FunSuite { + + test("P5Test") { + val dd = Array(3, 4, 5, 1, 2) + val res = P06.minNumberInRotateArray(dd) + assert(res === 1) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P07Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P07Test.scala" new file mode 100644 index 00000000..901dc997 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P07Test.scala" @@ -0,0 +1,20 @@ +package com.xixiciTest + +import com.xixici.P07 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/11 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P07Test extends FunSuite { + test("P7Test") { + val dd = 2 + val res = P07.Fibonacci(3) + assert(res === dd) + } +} + + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P08Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P08Test.scala" new file mode 100644 index 00000000..30c87d88 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P08Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P08 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/11 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P08Test extends FunSuite { + test("P8Test") { + val Expected = 5 + val Actual = P08.Jump(4) + assert(Expected === Actual) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P09Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P09Test.scala" new file mode 100644 index 00000000..40d0ba6a --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P09Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P09 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/11 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P09Test extends FunSuite { + test("P9Test") { + val Expected = 8 + val Actual = P09.Jump2(4) + assert(Expected === Actual) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P10Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P10Test.scala" new file mode 100644 index 00000000..ffba5860 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P10Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P10 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P10Test extends FunSuite { + test("P10Test") { + val Expected = 5 + val Actual = P10.RectCover(4) + assert(Expected === Actual) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P11Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P11Test.scala" new file mode 100644 index 00000000..7525ea79 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P11Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P11 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P11Test extends FunSuite { + test("P11Test") { + val Expected = 1 + val Actual = P11.NumberOf1(4) + assert(Expected === Actual) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P12Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P12Test.scala" new file mode 100644 index 00000000..057d2502 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P12Test.scala" @@ -0,0 +1,20 @@ +package com.xixiciTest + +import com.xixici.P12 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P12Test extends FunSuite { + test("P12Test") { + val Expected = 4 + val Actual = P12.Power(2, 2) + val predict1 = 1 / 4 + val real1 = P12.Power(2, -2) + assert(Actual === Expected, predict1 === real1) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P13Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P13Test.scala" new file mode 100644 index 00000000..278e5dd7 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P13Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P13 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P13Test extends FunSuite { + test("P13Test") { + val Expected = Array(1, 3, 5, 2, 4, 8) + val Actual = P13.reOrderArray(Array(1, 2, 3, 4, 5, 8)) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P14Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P14Test.scala" new file mode 100644 index 00000000..afb66017 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P14Test.scala" @@ -0,0 +1,27 @@ +package com.xixiciTest + +import com.xixici.P14 +import com.xixici.util.ListNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P14Test extends FunSuite { + val list1 = new ListNode(1) + val a = new ListNode(2) + val b = new ListNode(3) + val c = new ListNode(4) + list1.next = a + a.next = b + b.next = c + c.next = null + test("P14Test") { + val Expected = a.data + val Actual = P14.FindKthToTail(list1, 3).data + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P15Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P15Test.scala" new file mode 100644 index 00000000..a3194550 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P15Test.scala" @@ -0,0 +1,27 @@ +package com.xixiciTest + +import com.xixici.P15 +import com.xixici.util.ListNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/13 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P15Test extends FunSuite { + val list1 = new ListNode(1) + val a = new ListNode(2) + val b = new ListNode(3) + val c = new ListNode(4) + list1.next = a + a.next = b + b.next = c + c.next = null + test("P15Test") { + val Expected = c.data + val Actual = P15.ReverseList(list1).data + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P16Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P16Test.scala" new file mode 100644 index 00000000..92445a3d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P16Test.scala" @@ -0,0 +1,58 @@ +package com.xixiciTest + +import com.xixici.P16 +import com.xixici.util.ListNode +import org.scalatest.FunSuite + +import scala.collection.mutable.ArrayBuffer + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P16Test extends FunSuite { + val list1 = new ListNode(1) + val a = new ListNode(2) + val b = new ListNode(5) + val c = new ListNode(7) + val d = new ListNode(8) + list1.next = a + a.next = b + b.next = c + c.next = d + d.next = null + val list2 = new ListNode(2) + val a2 = new ListNode(4) + val b2 = new ListNode(6) + val c2 = new ListNode(8) + val d2 = new ListNode(9) + val e2 = new ListNode(10) + list2.next = a2 + a2.next = b2 + b2.next = c2 + c2.next = d2 + d2.next = e2 + e2.next = null + val list3 = new ListNode(1) + val a3 = new ListNode(1) + list3.next = a3 + a3.next = null + val list4 = new ListNode(2) + val a4 = new ListNode(3) + list4.next = a4 + a4.next = null + test("P16Test") { + val Expected1 = Array(1, 1, 2, 4) + var Actual1 = P16.Merge(list3, list4) + val Expected = Array(1, 2, 2, 4, 5, 6, 7, 8, 8, 9, 10) + var Actual = P16.Merge(list1, list2) + val res = new ArrayBuffer[Int] + while (Actual != null) { + res.append(Actual.data) + Actual = Actual.next + } + assert(res.toArray === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P17Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P17Test.scala" new file mode 100644 index 00000000..0c403d64 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P17Test.scala" @@ -0,0 +1,44 @@ +package com.xixiciTest + +import com.xixici.P17 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P17Test extends FunSuite { + + val node1 = new TreeNode(7) + val node2 = new TreeNode(2) + + root1 = new TreeNode(8) + val node3 = new TreeNode(9) + val node4 = new TreeNode(2) + val node5 = new TreeNode(4) + val node6 = new TreeNode(7) + val a = new TreeNode(9) + val b = new TreeNode(2) + var root1: TreeNode = _ + var root2: TreeNode = _ + root1.left = node1 + root1.right = node2 + node1.left = node3 + node1.right = node4 + node4.left = node5 + node4.right = node6 + + root2 = new TreeNode(7) + root2.left = a + root2.right = b + + test("P17Test") { + val Expected = true + val Actual = P17.HasSubtree(root1, root2) + assert(Actual === Expected) + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P18Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P18Test.scala" new file mode 100644 index 00000000..b5d270d7 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P18Test.scala" @@ -0,0 +1,68 @@ +package com.xixiciTest + +import com.xixici.P18 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +import scala.collection.mutable + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P18Test extends FunSuite { + val node1 = new TreeNode(7) + val node2 = new TreeNode(2) + val node3 = new TreeNode(9) + val node4 = new TreeNode(2) + val node5 = new TreeNode(4) + val node6 = new TreeNode(7) + var root1: TreeNode = _ + root1 = new TreeNode(8) + root1.left = node1 + root1.right = node2 + node1.left = node3 + node1.right = node4 + node4.left = node5 + node4.right = node6 + var root2: TreeNode = _ + root2 = root1 + root2.left = node2 + root2.right = node1 + node1.left = node4 + node1.right = node3 + node4.left = node6 + node4.right = node5 + + + test("P18Test") { + val Expected = P18Test.preOrder(root1) + val Actual = P18Test.preOrder(P18.Mirror(root2)) + assert(Actual === Expected) + } + +} + + +object P18Test { + // PreOrder Visit Btree + private def preOrder(root: TreeNode): List[Int] = { + if (root == null) return null + val resultList = mutable.ListBuffer[Int]() + val treeStack = mutable.ArrayStack[TreeNode]() + treeStack.push(root) + while (!treeStack.isEmpty) { + val tempNode = treeStack.pop(); + if (tempNode != null) { + resultList += tempNode.data + treeStack.push(tempNode.right) + treeStack.push(tempNode.left) + } + } + resultList.toList + } +} + + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P19Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P19Test.scala" new file mode 100644 index 00000000..52a1f70e --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P19Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P19 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P19Test extends FunSuite { + val matrix = Array(Array(1, 2, 3, 4), Array(5, 6, 7, 8), Array(9, 10, 11, 12), Array(13, 14, 15, 16)) + test("P19Test") { + val Expected = Array(1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10) + val Actual = P19.printMatrix(matrix) + assert(Actual === Expected) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P20Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P20Test.scala" new file mode 100644 index 00000000..89b28509 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P20Test.scala" @@ -0,0 +1,22 @@ +package com.xixiciTest + +import com.xixici.P20 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/14 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P20Test extends FunSuite { + val stack = new P20 + stack.push(2) + stack.push(3) + stack.push(5) + test("P20Test") { + val Expected = 2 + val Actual = stack.min() + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P21Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P21Test.scala" new file mode 100644 index 00000000..a2f93db0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P21Test.scala" @@ -0,0 +1,20 @@ +package com.xixiciTest + +import com.xixici.P21 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/15 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P21Test extends FunSuite { + val pushA = Array(1, 2, 3, 4, 5) + val popA = Array(4, 5, 3, 2, 1) + test("P21Test") { + val Expected = true + val Actual = P21.IsPopOrder(pushA, popA) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P22Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P22Test.scala" new file mode 100644 index 00000000..28115fcb --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P22Test.scala" @@ -0,0 +1,32 @@ +package com.xixiciTest + +import com.xixici.P22 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/15 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P22Test extends FunSuite { + val root1 = new TreeNode(8) + val node1 = new TreeNode(7) + val node2 = new TreeNode(2) + val node3 = new TreeNode(9) + val node4 = new TreeNode(2) + val node5 = new TreeNode(4) + val node6 = new TreeNode(7) + root1.left = node1 + root1.right = node2 + node1.left = node3 + node1.right = node4 + node4.left = node5 + node4.right = node6 + test("P22Test") { + val Expected = List(root1.data, node1.data, node2.data, node3.data, node4.data, node5.data, node6.data) + val Actual = P22.PrintFromTopToBottom(root1) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P23Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P23Test.scala" new file mode 100644 index 00000000..5dc08087 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P23Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P23 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/15 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P23Test extends FunSuite { + val seq = Array(5, 7, 6, 9, 11, 10, 8) + test("P23Test") { + val Expected = true + val Actual = P23.VerifySquenceOfBST(seq) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P24Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P24Test.scala" new file mode 100644 index 00000000..e0fce857 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P24Test.scala" @@ -0,0 +1,34 @@ +package com.xixiciTest + +import com.xixici.P24 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/16 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P24Test extends FunSuite { + val node1 = new TreeNode(7) + root1 = new TreeNode(8) + val node2 = new TreeNode(2) + val node3 = new TreeNode(9) + val node4 = new TreeNode(2) + val node5 = new TreeNode(4) + val node6 = new TreeNode(7) + var root1: TreeNode = _ + + root1.left = node1 + root1.right = node2 + node1.left = node3 + node1.right = node4 + node4.left = node5 + node4.right = node6 + test("P24Test") { + val Expected = List(List(8, 7, 9), List(8, 7, 2, 7)) + val Actual = P24.findPath(root1, 24) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P25Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P25Test.scala" new file mode 100644 index 00000000..f64e76a0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P25Test.scala" @@ -0,0 +1,33 @@ +package com.xixiciTest + +import com.xixici.P25 +import com.xixici.util.RandomListNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/19 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P25Test extends FunSuite { + val rln = new RandomListNode(1) + val a = new RandomListNode(2) + val b = new RandomListNode(3) + val c = new RandomListNode(4) + val d = new RandomListNode(5) + rln.next = a + rln.random = d + a.next = b + a.random = c + b.next = c + b.random = a + c.next = null + c.random = null + test("P25Test") { + val Expected = rln + val Actual = P25.Clone(rln) + assert(Actual.data === Expected.data) + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P26Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P26Test.scala" new file mode 100644 index 00000000..1d0ea795 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P26Test.scala" @@ -0,0 +1,40 @@ +package com.xixiciTest + +import com.xixici.P26 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/19 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P26Test extends FunSuite { + val node1 = new TreeNode(6) + root = new TreeNode(10) + val node2 = new TreeNode(14) + val node3 = new TreeNode(4) + val node4 = new TreeNode(8) + val node5 = new TreeNode(12) + val node6 = new TreeNode(16) + var root: TreeNode = _ + root.left = node1 + root.right = node2 + node1.left = node3 + node1.right = node4 + node2.left = node5 + node2.right = node6 + test("P26Test") { + + val Expected = List(4, 6, 8, 10, 12, 14, 16) + var res = P26.Convert(root) + val Actual = collection.mutable.ListBuffer[Int]() + while (res != null) { + Actual.append(res.data) + res = res.right + } + assert(Actual.toList === Expected) + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P27Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P27Test.scala" new file mode 100644 index 00000000..c22a132d --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P27Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P27 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/20 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P27Test extends FunSuite { + val A = "123" + test("P28Test") { + val Expected = List("123", "132", "213", "231", "321", "312") + val Actual = P27.Permutation(A) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P28Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P28Test.scala" new file mode 100644 index 00000000..be567503 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P28Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P28 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/18 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P28Test extends FunSuite { + val A = Array(2, 2, 2, 0, 2, 5, 3) + test("P28Test") { + val Expected = 2 + val Actual = P28.MoreThanHalfNum_Solution(A) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P29Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P29Test.scala" new file mode 100644 index 00000000..2b8661ba --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P29Test.scala" @@ -0,0 +1,20 @@ +package com.xixiciTest + +import com.xixici.P29 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/20 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P29Test extends FunSuite { + val A = Array(2, 2, 2, 0, 2, 5, 3) + test("P29Test") { + val Expected = List(0, 2, 2, 2) + val Actual = P29.GetLeastNumbers_Solution(A, 4) + assert(Actual === Expected) + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P30Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P30Test.scala" new file mode 100644 index 00000000..77e264e9 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P30Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P30 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/21 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P30Test extends FunSuite { + val A = Array(2, 2, 2, -9, 2, 5, 3) + test("P30Test") { + val Expected = 10 + val Actual = P30.FindGreatestSumOfSubarr(A) + assert(Actual === Expected) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P31Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P31Test.scala" new file mode 100644 index 00000000..5cb4ae14 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P31Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P31 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/22 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P31Test extends FunSuite { + test("P33Test") { + val Expected = 8 + val Actual = P31.NumberOf1Between1AndN_Solution(15) + assert(Actual === Expected) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P32Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P32Test.scala" new file mode 100644 index 00000000..1b4d1183 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P32Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P32 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/21 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P32Test extends FunSuite { + val A = Array(3, 32, 321) + test("P32Test") { + val Expected = 321323.toString + val Actual = P32.PrintMinNumber(A) + assert(Actual === Expected) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P33Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P33Test.scala" new file mode 100644 index 00000000..8be31cd1 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P33Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P33 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/21 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P33Test extends FunSuite { + test("P33Test") { + val Expected = 12 + val Actual = P33.GetUglyNumber_Solution(10) + assert(Actual === Expected) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P34Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P34Test.scala" new file mode 100644 index 00000000..f26b1976 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P34Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P34 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/22 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P34Test extends FunSuite { + test("P34Test") { + val Expected = 4 + val Actual = P34.FirstNotRepeatingChar("AABBeCCDD") + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P35Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P35Test.scala" new file mode 100644 index 00000000..15056587 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P35Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P35 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/22 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P35Test extends FunSuite { + test("P35Test") { + val Expected = 7 + val Actual = P35.InversePairs(Array(1, 2, 3, 4, 5, 6, 7, 0)) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P36Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P36Test.scala" new file mode 100644 index 00000000..8bad3c50 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P36Test.scala" @@ -0,0 +1,32 @@ +package com.xixiciTest + +import com.xixici.P36 +import com.xixici.util.ListNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/22 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P36Test extends FunSuite { + val list1 = new ListNode(1) + val a = new ListNode(2) + val b = new ListNode(3) + val c = new ListNode(4) + list1.next = a + a.next = b + b.next = c + c.next = null + val list2 = new ListNode(1) + list2.next = b + b.next = c + c.next = a + a.next = null + test("P36Test") { + val Expected = b + val Actual = P36.FindFirstCommonNode(list1, list2) + assert(Actual.data === Expected.data) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P37Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P37Test.scala" new file mode 100644 index 00000000..9ea768f2 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P37Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P37 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P37Test extends FunSuite { + test("P37Test") { + val Expected = 4 + val Actual = P37.GetNumberOfK(Array(1, 2, 3, 3, 3, 3, 4, 5, 6, 7), 3) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P38Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P38Test.scala" new file mode 100644 index 00000000..a65b6e08 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P38Test.scala" @@ -0,0 +1,37 @@ +package com.xixiciTest + +import com.xixici.P38 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P38Test extends FunSuite { + + val node1 = new TreeNode(7) + + root1 = new TreeNode(8) + val node2 = new TreeNode(2) + val node3 = new TreeNode(9) + val node4 = new TreeNode(2) + val node5 = new TreeNode(4) + val node6 = new TreeNode(7) + val a = new TreeNode(9) + val b = new TreeNode(2) + var root1: TreeNode = _ + root1.left = node1 + root1.right = node2 + node1.left = node3 + node1.right = node4 + node4.left = node5 + node4.right = node6 + test("P38Test") { + val Expected = 4 + val Actual = P38.TreeDepth(root1) + assert(Actual === Expected) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P39Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P39Test.scala" new file mode 100644 index 00000000..f556bb19 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P39Test.scala" @@ -0,0 +1,38 @@ +package com.xixiciTest + +import com.xixici.P39 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P39Test extends FunSuite { + + val node1 = new TreeNode(7) + val node2 = new TreeNode(2) + + root1 = new TreeNode(8) + val node3 = new TreeNode(9) + val node4 = new TreeNode(2) + val node5 = new TreeNode(4) + val node6 = new TreeNode(7) + val a = new TreeNode(9) + val b = new TreeNode(2) + var root1: TreeNode = _ + var root2: TreeNode = _ + root1.left = node1 + root1.right = node2 + node1.left = node3 + node1.right = node4 + node4.left = node5 + node4.right = node6 + test("P39Test") { + val Expected = false + val Actual = P39.IsBalanced_Solution(root1) + assert(Actual === Expected) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P40Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P40Test.scala" new file mode 100644 index 00000000..7f573193 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P40Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P40 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P40Test extends FunSuite { + test("P40Test") { + val ttt = Array(2, 2, 3, 3, 4, 7, 5, 5, 9, 9) + val Expected = Array(4, 7) + val Actual = P40.findNumsAppearOnce(ttt) + assert(Actual.sorted === Expected.sorted) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P41Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P41Test.scala" new file mode 100644 index 00000000..c9344594 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P41Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P41 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P41Test extends FunSuite { + test("P41Test") { + val Expected = List(9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22) + val Actual = P41.FindContinuousSequence(100) + assert(Actual.sorted === Expected.sorted) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P42Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P42Test.scala" new file mode 100644 index 00000000..8ab05faa --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P42Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P42 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P42Test extends FunSuite { + test("P42Test") { + val Expected = List(1, 3) + val Actual = P42.FindNumbersWithSum(Array(1, 2, 2, 3), 4) + assert(Actual.sorted === Expected.sorted) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P43Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P43Test.scala" new file mode 100644 index 00000000..cbd0559b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P43Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P43 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/25 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P43Test extends FunSuite { + test("P43Test") { + val Expected = "XYZdefabc" + val Actual = P43.LeftRotateString("abcXYZdef", 3) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P44Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P44Test.scala" new file mode 100644 index 00000000..f3ef8f4c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P44Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P44 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/26 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P44Test extends FunSuite { + test("P44Test") { + val Expected = "student a am I" + val Actual = P44.ReverseSentence("I am a student") + assert(Actual === Expected) + } +} + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P45Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P45Test.scala" new file mode 100644 index 00000000..0d335b82 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P45Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P45 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/26 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P45Test extends FunSuite { + test("P45Test") { + val Expected = true + val Actual = P45.isContinuous(Array(4, 5, 6, 0, 0)) + assert(Actual === Expected) + } +} + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P46Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P46Test.scala" new file mode 100644 index 00000000..50e86b81 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P46Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P46 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/26 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P46Test extends FunSuite { + test("P46Test") { + val Expected = 2 + val Actual = P46.LastRemaining_Solution(5, 2) + assert(Actual === Expected) + } +} + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P47Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P47Test.scala" new file mode 100644 index 00000000..58022ed3 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P47Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P47 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/16 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P47Test extends FunSuite { + + test("P47Test") { + val Expected = 15 + val Actual = P47.Sum_Solution(5) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P48Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P48Test.scala" new file mode 100644 index 00000000..747eab9b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P48Test.scala" @@ -0,0 +1,20 @@ +package com.xixiciTest + +import com.xixici.P48 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/16 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P48Test extends FunSuite { + + test("P47Test") { + val Expected = 15 + val Actual = P48.Add(7, 8) + assert(Actual === Expected) + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P49Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P49Test.scala" new file mode 100644 index 00000000..4f8788da --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P49Test.scala" @@ -0,0 +1,21 @@ +package com.xixiciTest + +import com.xixici.P49 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/17 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P49Test extends FunSuite { + + + test("P47Test") { + val Expected = 0 + val Actual = P49.StrToInt("abc") + assert(Actual === Expected) + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P50Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P50Test.scala" new file mode 100644 index 00000000..beaeeab0 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P50Test.scala" @@ -0,0 +1,18 @@ +package com.xixiciTest + +import com.xixici.P50 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/18 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P50Test extends FunSuite { + test("P50Test") { + val Expected = true + val Actual = P50.duplicate(Array(2, 3, 1, 0, 2, 5, 3), 7, Array(2)) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P51Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P51Test.scala" new file mode 100644 index 00000000..80f448ed --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P51Test.scala" @@ -0,0 +1,20 @@ +package com.xixiciTest + +import com.xixici.P51 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/3/18 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P51Test extends FunSuite { + val A = Array(2, 3, 1, 0, 2, 5, 3) + test("P51Test") { + val Expected = Array(0, 0, 0, 180, 0, 0, 0) + val Actual = P51.multiply(A) + assert(Actual === Expected) + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P52Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P52Test.scala" new file mode 100644 index 00000000..4a611c95 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P52Test.scala" @@ -0,0 +1,24 @@ +package com.xixiciTest + +import com.xixici.P52 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/29 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P52Test extends FunSuite { + test("P52Test") { + val Expected = true + val Actual = P52.matchPattern("aaa".toCharArray, "a.a".toCharArray) + assert(Actual === Expected) + } + test("P52Test-2") { + val Expected = false + val Actual = P52.matchPattern("aaa".toCharArray, "a.b".toCharArray) + assert(Actual === Expected) + } + +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P53Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P53Test.scala" new file mode 100644 index 00000000..476eb669 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P53Test.scala" @@ -0,0 +1,24 @@ +package com.xixiciTest + +import com.xixici.P53 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/29 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P53Test extends FunSuite { + test("P53Test") { + val Expected = true + val Actual = P53.isNumeric("+100".toCharArray) + assert(Actual === Expected) + } + test("P53Test-2") { + val Expected = false + val Actual = P53.isNumeric("12e".toCharArray) + assert(Actual === Expected) + } + +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P54Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P54Test.scala" new file mode 100644 index 00000000..64945364 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P54Test.scala" @@ -0,0 +1,25 @@ +package com.xixiciTest + +import com.xixici.P54 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/29 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P54Test extends FunSuite { + test("P54Test") { + val google = "google".toCharArray + val s = new StringBuffer() + for (c: Char <- google) { + P54.Insert(c) + s.append(P54.FirstAppearingOnce()) + } + val Expected = "ggg#ll" + val Actual = s.toString + assert(Actual === Expected) + + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P55Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P55Test.scala" new file mode 100644 index 00000000..3e1b3078 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P55Test.scala" @@ -0,0 +1,28 @@ +package com.xixiciTest + +import com.xixici.P55 +import com.xixici.util.ListNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/4/29 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P55Test extends FunSuite { + val a = new ListNode(2) + val b = new ListNode(3) + val c = new ListNode(4) + var head = new ListNode(1) + head.next = a + a.next = b + b.next = c + c.next = b + test("P55Test") { + val Expected = b + val Actual = P55.EntryNodeOfLoop(head) + assert(Actual === Expected) + } + +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P56Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P56Test.scala" new file mode 100644 index 00000000..0c0fa239 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P56Test.scala" @@ -0,0 +1,38 @@ +package com.xixiciTest + +import com.xixici.P56 +import com.xixici.util.ListNode +import org.scalatest.FunSuite + +import scala.collection.mutable.ArrayBuffer + +/** + * Created by xixici + * Date: 2019/4/29 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P56Test extends FunSuite { + val a = new ListNode(2) + val b = new ListNode(3) + val c = new ListNode(4) + val d = new ListNode(4) + val e = new ListNode(5) + var head = new ListNode(1) + head.next = a + a.next = b + b.next = c + c.next = d + d.next = e + test("P56Test") { + var Expected = Array(1, 2, 3, 5) + var Actual = P56.deleteDuplication(head) + val res = new ArrayBuffer[Int] + while (Actual != null) { + res.append(Actual.data) + Actual = Actual.next + } + assert(res.toArray === Expected) + } + +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P57Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P57Test.scala" new file mode 100644 index 00000000..f9528f22 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P57Test.scala" @@ -0,0 +1,63 @@ +package com.xixiciTest + +import com.xixici.P57 +import com.xixici.util.TreeLinkNode +import org.scalatest.FunSuite + + +/** + * Created by xixici + * Date: 2019/5/7 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +/* d - b - h - e - i - a - f - c - g +* a +* / \ +* b c +* / \ / \ +* d e f g +* / \ +* h i +* */ +class P57Test extends FunSuite { + val a = new TreeLinkNode(1) + val b = new TreeLinkNode(2) + val c = new TreeLinkNode(3) + val d = new TreeLinkNode(4) + val e = new TreeLinkNode(5) + val f = new TreeLinkNode(6) + val g = new TreeLinkNode(7) + val h = new TreeLinkNode(8) + val i = new TreeLinkNode(9) + a.left = b + a.right = c + b.left = d + b.right = e + b.next = a + e.left = h + e.right = i + e.next = b + c.left = f + c.right = g + c.next = a + d.next = b + h.next = e + i.next = e + f.next = c + g.next = c + test("P57Test") { + val Expected = f.data + val Actual = P57.TreeLinkNode(a).data + + val Expected2 = b.data + val Actual2 = P57.TreeLinkNode(d).data + + val Expected3 = h.data + val Actual3 = P57.TreeLinkNode(b).data + assert(Actual === Expected) + assert(Actual2 === Expected2) + assert(Actual3 === Expected3) + } +} + diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P58Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P58Test.scala" new file mode 100644 index 00000000..4fe85f42 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P58Test.scala" @@ -0,0 +1,32 @@ +package com.xixiciTest + +import com.xixici.P58 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/5/8 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P58Test extends FunSuite { + val a = new TreeNode(1) + val b = new TreeNode(2) + val bb = new TreeNode(2) + val c = new TreeNode(3) + val d = new TreeNode(4) + a.left = b + b.left = c + b.right = d + a.right = bb + bb.left = d + bb.right = c + + + test("P58Test") { + val Expected = true + val Actual = P58.isSymmetrical(a) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P59Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P59Test.scala" new file mode 100644 index 00000000..40f2f4cf --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P59Test.scala" @@ -0,0 +1,34 @@ +package com.xixiciTest + +import com.xixici.P59 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +import scala.collection.mutable.ArrayBuffer + +/** + * Created by xixici + * Date: 2019/5/8 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P59Test extends FunSuite { + val a = new TreeNode(1) + val b = new TreeNode(2) + val bb = new TreeNode(3) + val c = new TreeNode(4) + val d = new TreeNode(5) + a.left = b + b.left = c + b.right = d + a.right = bb + bb.left = d + bb.right = c + + + test("P59Test") { + val Expected = ArrayBuffer(ArrayBuffer(1), ArrayBuffer(3, 2), ArrayBuffer(4, 5, 5, 4)) + val Actual = P59.Print(a) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P60Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P60Test.scala" new file mode 100644 index 00000000..8d6b3b5c --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P60Test.scala" @@ -0,0 +1,34 @@ +package com.xixiciTest + +import com.xixici.P60 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +import scala.collection.mutable.ArrayBuffer + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P60Test extends FunSuite { + val a = new TreeNode(1) + val b = new TreeNode(2) + val bb = new TreeNode(3) + val c = new TreeNode(4) + val d = new TreeNode(5) + a.left = b + b.left = c + b.right = d + a.right = bb + bb.left = d + bb.right = c + + + test("P60Test") { + val Expected = ArrayBuffer(ArrayBuffer(1), ArrayBuffer(2, 3), ArrayBuffer(4, 5, 5, 4)) + val Actual = P60.Print(a) + assert(Actual === Expected) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P61Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P61Test.scala" new file mode 100644 index 00000000..4e8a18cf --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P61Test.scala" @@ -0,0 +1,31 @@ +package com.xixiciTest + +import com.xixici.P61 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P61Test extends FunSuite { + val a = new TreeNode(1) + val b = new TreeNode(2) + val bb = new TreeNode(3) + val c = new TreeNode(4) + val d = new TreeNode(5) + a.left = b + b.left = c + b.right = d + a.right = bb + bb.left = d + bb.right = c + test("P61Test") { + val Expected1 = "1,2,4,$,$,5,$,$,3,5,$,$,4,$,$" + val Actual1 = P61.deserialize("1,2,4,$,$,5,$,$,3,5,$,$,4,$,$") + val Actual0 = P61.serialize(Actual1) + assert(Actual0 === Expected1) + } +} \ No newline at end of file diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P62Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P62Test.scala" new file mode 100644 index 00000000..ae8ff208 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P62Test.scala" @@ -0,0 +1,32 @@ +package com.xixiciTest + +import com.xixici.P62 +import com.xixici.util.TreeNode +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P62Test extends FunSuite { + val a = new TreeNode(2) + val b = new TreeNode(3) + val c = new TreeNode(4) + val d = new TreeNode(5) + val e = new TreeNode(6) + val f = new TreeNode(7) + val g = new TreeNode(8) + d.left = b + d.right = f + b.left = a + b.right = c + f.left = e + f.right = g + test("P62Test") { + val Expected = 3 + val Actual = P62.KthNode(d, 2) + assert(Actual.data === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P63Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P63Test.scala" new file mode 100644 index 00000000..e9be71e5 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P63Test.scala" @@ -0,0 +1,28 @@ +package com.xixiciTest + +import com.xixici.P63 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P63Test extends FunSuite { + + test("P63Test") { + P63.insert(2) + P63.insert(3) + P63.insert(4) + P63.insert(2) + P63.insert(6) + P63.insert(2) + P63.insert(5) + P63.insert(1) + println(P63.getMedian()) + val Expected = 2.5 + val Actual = P63.getMedian() + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P64Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P64Test.scala" new file mode 100644 index 00000000..7d696f4b --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P64Test.scala" @@ -0,0 +1,19 @@ +package com.xixiciTest + +import com.xixici.P64 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P64Test extends FunSuite { + val A = Array[Int](2, 3, 4, 2, 6, 2, 5, 1) + test("P64Test") { + val Expected = Array[Int](4, 4, 6, 6, 6, 5) + val Actual = P64.maxInWindows(A, 3) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P65Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P65Test.scala" new file mode 100644 index 00000000..3ac92d20 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P65Test.scala" @@ -0,0 +1,23 @@ +package com.xixiciTest + +import com.xixici.P65 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P65Test extends FunSuite { + val matrix = Array('a', 'b', 'c', 'e', 's', 'f', 'c', 's', 'a', 'd', 'e', 'e') + val str1 = Array('b', 'c', 'c', 'e', 'd') + val str2 = Array('a', 'b', 'c', 'b') + println(P65.hasPath(matrix, 3, 4, str1)) + println(P65.hasPath(matrix, 3, 4, str2)) + test("P65Test") { + val Expected = true + val Actual = P65.hasPath(matrix, 3, 4, str1) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P66Test.scala" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P66Test.scala" new file mode 100644 index 00000000..7b6c8107 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/src/test/scala/com/xixiciTest/P66Test.scala" @@ -0,0 +1,20 @@ +package com.xixiciTest + +import com.xixici.P66 +import org.scalatest.FunSuite + +/** + * Created by xixici + * Date: 2019/5/9 + * Project Name: sword-offer-scala-sbt + * Project URL: https://github.com/xixici/sword-offer-scala + **/ +class P66Test extends FunSuite { + test("P66Test") { + println(P66.movingCount(10, 10, 5)) + println(P66.movingCount(20, 20, 15)) + val Expected = 21 + val Actual = P66.movingCount(10, 10, 5) + assert(Actual === Expected) + } +} diff --git "a/docs/Algorithm/\345\211\221\346\214\207offer/Scala/update.sh" "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/update.sh" new file mode 100644 index 00000000..7a268e00 --- /dev/null +++ "b/docs/Algorithm/\345\211\221\346\214\207offer/Scala/update.sh" @@ -0,0 +1,11 @@ +emoji=(♈ ♉ ♊ ♋ ♌ ♎ ♏ ♐ ♑ ♒ ♓ ⛎ 🔯) +git add -A +echo "###Add Finish" +git commit -am "${emoji[$(($RANDOM % ${#emoji[@]} + 1 ))]} xixici push at $(date "+%Y-%m-%d %H:%M:%S")" +echo "###Commit Finish" +git pull +echo "###Pull Finish" +git status +echo "###Status Finish" +git push +echo "###push Finish" diff --git a/docs/GitHub/README.md b/docs/GitHub/README.md index df4b559f..12ba8bc4 100644 --- a/docs/GitHub/README.md +++ b/docs/GitHub/README.md @@ -80,11 +80,11 @@ jiangzl@jiangzhongliandeMacBook-Pro:~$ > 2.点击 Settings, 添加ssh key -![](/img/docs/GitHub/GitHub-Setting.png) +![](/static/images/docs/GitHub/GitHub-Setting.png) > 3.点击 New SSH key -![](/img/docs/GitHub/SSH-Key.jpg) +![](/static/images/docs/GitHub/SSH-Key.jpg) > 4.链接验证 @@ -106,18 +106,18 @@ jiangzl@jiangzhongliandeMacBook-Pro:~$ ## 基本命令 此图片链接为 bilibili 视频地址: (视频图片下面为文本操作指南) - + 全局概况图(看不懂就多看几遍) -![](/img/docs/GitHub/github_origin_online_remote.jpg) +![](/static/images/docs/GitHub/github_origin_online_remote.jpg) > 一) fork apachecn/kaggle 项目 -![](/img/docs/GitHub/github-step-1-fork.jpg) +![](/static/images/docs/GitHub/github-step-1-fork.jpg) -![](/img/docs/GitHub/github-step-2-clone.jpg) +![](/static/images/docs/GitHub/github-step-2-clone.jpg) > 二) jiangzhonglian/kaggle 第一次初始化 @@ -150,9 +150,9 @@ $ git push origin master > 四) pull requests 到 apachecn/kaggle -![](/img/docs/GitHub/github-step-3-PullRequests.jpg) +![](/static/images/docs/GitHub/github-step-3-PullRequests.jpg) -![](/img/docs/GitHub/github-step-4-PullRequests.jpg) +![](/static/images/docs/GitHub/github-step-4-PullRequests.jpg) -![](/img/docs/GitHub/github-step-5-PullRequests.jpg) +![](/static/images/docs/GitHub/github-step-5-PullRequests.jpg) diff --git a/docs/Kaggle/README.md b/docs/Kaggle/README.md index 846d5ef0..af81d68b 100644 --- a/docs/Kaggle/README.md +++ b/docs/Kaggle/README.md @@ -4,7 +4,7 @@ > **你已经抓住了石头,现在是挥舞它的时候了!** -* [ApacheCN 组织资源](https://docs.apachecn.org/): +* [ApacheCN 组织资源](https://www.ibooker.org.cn/docs): * **ApacheCN - 比赛学习群【724187166】ApacheCN - 比赛学习群[724187166]** * [Kaggle](https://www.kaggle.com) 是一个流行的数据科学竞赛平台。 * [GitHub 入门操作指南](/docs/GitHub/README.md) 和 [Kaggle 入门操作指南](/docs/kaggle-quickstart.md),适合于学习过 [MachineLearning(机器学习实战)](https://github.com/apachecn/MachineLearning) 的小盆友 @@ -22,8 +22,7 @@ > kaggle入门系列 -* [Kaggle系列-数字识别](https://www.bilibili.com/video/av53119200) -* [Kaggle系列-泰坦尼克号](https://www.bilibili.com/video/av65679428) +* [【Kaggle 入门篇】B站视频讲解,跟我们一起来学习吧!](https://www.bilibili.com/video/av53119200) > 比赛直播系列 @@ -32,23 +31,6 @@ * [昊神GitHub地址: https://github.com/Smilexuhc](https://github.com/Smilexuhc) * [昊神整理比赛系列: https://github.com/Smilexuhc/Data-Competition-TopSolution](https://github.com/Smilexuhc/Data-Competition-TopSolution) -## Kaggle 官方教程 - -> 机器学习入门 - -* [**1. 模型是怎样工作的**](learn/intro-to-machine-learning/1.md) -* [**2. 数据探索**](learn/intro-to-machine-learning/2.md) -* [**3. 你的第一个机器学习模型**](learn/intro-to-machine-learning/3.md) -* [**4. 模型验证**](learn/intro-to-machine-learning/4.md) -* [**5. 欠拟合与过拟合**](learn/intro-to-machine-learning/5.md) -* [**6. 随机森林**](learn/intro-to-machine-learning/6.md) -* [**7. 继续你的征程**](learn/intro-to-machine-learning/7.md) - -> 补充 - -* [**Embedding**](learn/embeddings) - - ## [竞赛](https://www.kaggle.com/competitions) * 【推荐】特征工程全过程: https://www.cnblogs.com/jasonfreak/p/5448385.html @@ -182,3 +164,49 @@ WriteUp 需要带有预处理过程,从你能下载到的原始数据开始, 请放在`/competitions/{分类}/{名称}`目录下。 其中分类一共有六个,请见上面,名称是 URL 中`/c/`后面的部分。 + +## 联系方式 + +> 项目负责人 + +* [@jiangzhonglian](https://github.com/jiangzhonglian)(片刻) + +> 项目发起人 + +* [@jiangzhonglian](https://github.com/jiangzhonglian)(片刻) +* [@wangyangting](https://github.com/wangyangting)(那伊抹微笑) +* [@chenyyx](https://github.com/chenyyx)(瑶妹) + +> 项目贡献者(请手动添加) + +* [@jiangzhonglian](https://github.com/jiangzhonglian)(片刻) +* [@wangyangting](https://github.com/wangyangting)(那伊抹微笑) +* [@chenyyx](https://github.com/chenyyx)(瑶妹) +* [@zehuichen](https://github.com/zehuichen123)(loveSnowBest) +* [@谈笑风生](https://github.com/zhu1040028623)(谈笑风生) +* [@诺木人](https://github.com/1mrliu)(诺木人) +* [@飞龙](https://github.com/wizardforcel) + +> 加入方式 + +有任何建议反馈, 或想参与文档翻译, 麻烦联系下面的企鹅 +* 企鹅: 529815144(片刻) 1042658081(那伊抹微笑) 190442212(瑶妹) +* **ApacheCN - 比赛学习群【724187166】ApacheCN - 比赛学习群[724187166]** +* **Kaggle (数据科学竞赛平台) | [ApacheCN(apache中文网)](http://www.apachecn.org/)** + +微信&支付宝 + +--- + +> 特别赞助商(欢迎“私聊”赞助) + + + + + + +
+ + + +
diff --git a/docs/Kaggle/competitions/getting-started/digit-recognizer/README.md b/docs/Kaggle/competitions/getting-started/digit-recognizer/README.md index d5cec412..cf9ea71d 100644 --- a/docs/Kaggle/competitions/getting-started/digit-recognizer/README.md +++ b/docs/Kaggle/competitions/getting-started/digit-recognizer/README.md @@ -13,11 +13,11 @@ | 角色 | 用户 | 内容 | 代码 | | -- | -- | -- | -- | -| 负责: knn | [诺木人](https://github.com/1mrliu) | [knn项目文档](/competitions/getting-started/digit-recognizer/knn算法描述.md) | [knn项目代码](/src/py3.x/kaggle/getting-started/digit-recognizer/knn-python3.6.py) | -| 负责: svm | [马小穆](https://github.com/maxiaomu) | [svm项目文档](/competitions/getting-started/digit-recognizer/svm算法描述.md) | [svm项目代码](/src/py3.x/kaggle/getting-started/digit-recognizer/svm-python3.6.py) | -| 负责: 随机森林 | [平淡的天](https://github.com/friedhelm739) | [随机森林项目文档](/competitions/getting-started/digit-recognizer/随机森林算法描述.md) | [随机森林项目代码](/src/py3.x/kaggle/getting-started/digit-recognizer/rf-python3.6.py) | -| 负责: 神经网络 | [平淡的天](https://github.com/friedhelm739) | [神经网络项目文档](/competitions/getting-started/digit-recognizer/神经网络算法描述.md) | [神经网络项目代码](/src/py3.x/kaggle/getting-started/digit-recognizer/nn-python3.6.py) | -| 负责: cnn | [==](https://github.com/xiaomingnio) | [cnn项目文档](/competitions/getting-started/digit-recognizer/cnn算法描述.md) | [cnn项目代码](/src/py3.x/kaggle/getting-started/digit-recognizer/keras_cnn-python3.6.py) | +| 负责: knn | [诺木人](https://github.com/1mrliu) | [knn项目文档](/competitions/getting-started/digit-recognizer/knn算法描述.md) | [knn项目代码](/src/python/getting-started/digit-recognizer/knn-python3.6.py) | +| 负责: svm | [马小穆](https://github.com/maxiaomu) | [svm项目文档](/competitions/getting-started/digit-recognizer/svm算法描述.md) | [svm项目代码](/src/python/getting-started/digit-recognizer/svm-python3.6.py) | +| 负责: 随机森林 | [平淡的天](https://github.com/friedhelm739) | [随机森林项目文档](/competitions/getting-started/digit-recognizer/随机森林算法描述.md) | [随机森林项目代码](/src/python/getting-started/digit-recognizer/rf-python3.6.py) | +| 负责: 神经网络 | [平淡的天](https://github.com/friedhelm739) | [神经网络项目文档](/competitions/getting-started/digit-recognizer/神经网络算法描述.md) | [神经网络项目代码](/src/python/getting-started/digit-recognizer/nn-python3.6.py) | +| 负责: cnn | [==](https://github.com/xiaomingnio) | [cnn项目文档](/competitions/getting-started/digit-recognizer/cnn算法描述.md) | [cnn项目代码](/src/python/getting-started/digit-recognizer/keras_cnn-python3.6.py) | > 数字识别 第一期(2018-04-18) diff --git a/docs/Kaggle/competitions/getting-started/house-price/README.md b/docs/Kaggle/competitions/getting-started/house-price/README.md index 331b91b0..cbf5ed84 100644 --- a/docs/Kaggle/competitions/getting-started/house-price/README.md +++ b/docs/Kaggle/competitions/getting-started/house-price/README.md @@ -1,1995 +1,1995 @@ -# **房价预测** - -![](/img/competitions/getting-started/house-price/housesbanner.png) - -## 比赛说明 - -* [**房价预测**](https://www.kaggle.com/c/house-prices-advanced-regression-techniques) -* 要求购房者描述他们的梦想之家,他们可能不会从地下室天花板的高度或与东西方铁路的接近度开始。但是这个游乐场比赛的数据集证明,对价格谈判的影响远远超过卧室或白色栅栏的数量。 -* 有79个解释变量描述(几乎)爱荷华州埃姆斯的住宅房屋的每个方面,这个竞赛挑战你预测每个房屋的最终价格。 - -## 参赛成员 - -* 开源组织: [ApacheCN ~ apachecn.org](http://www.apachecn.org/) - -## 比赛分析 - -* 回归问题:价格的问题 -* 常用算法: `回归`、`树回归`、`GBDT`、`xgboost`、`lightGBM` - -``` -步骤: -一. 数据分析 -1. 下载并加载数据 -2. 总体预览:了解每列数据的含义,数据的格式等 -3. 数据初步分析,使用统计学与绘图:初步了解数据之间的相关性,为构造特征工程以及模型建立做准备 - -二. 特征工程 -1.根据业务,常识,以及第二步的数据分析构造特征工程. -2.将特征转换为模型可以辨别的类型(如处理缺失值,处理文本进行等) - -三. 模型选择 -1.根据目标函数确定学习类型,是无监督学习还是监督学习,是分类问题还是回归问题等. -2.比较各个模型的分数,然后取效果较好的模型作为基础模型. - -四. 模型融合 -1. 可以参考泰坦尼克号的简单模型融合方式,通过对模型的对比打分方式选择合适的模型 -2. 在房价预测里我们使用模型融合的方法来输出结果,最终的效果很好。 - -五. 修改特征和模型参数 -1.可以通过添加或者修改特征,提高模型的上限. -2.通过修改模型的参数,是模型逼近上限 -``` - -## 一. 数据分析 - -### 数据下载和加载 - -* 数据集下载地址: - -```python -# 导入相关数据包 -import numpy as np -import pandas as pd -import seaborn as sns -import matplotlib.pyplot as plt -%matplotlib inline - -from scipy import stats -from scipy.stats import norm -``` - - -```python -root_path = '/opt/data/kaggle/getting-started/house-prices' - -train = pd.read_csv('%s/%s' % (root_path, 'train.csv')) -test = pd.read_csv('%s/%s' % (root_path, 'test.csv')) -``` - -### 特征说明 - - -```python -train.columns -``` - - Index(['Id', 'MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea', 'Street', - 'Alley', 'LotShape', 'LandContour', 'Utilities', 'LotConfig', - 'LandSlope', 'Neighborhood', 'Condition1', 'Condition2', 'BldgType', - 'HouseStyle', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd', - 'RoofStyle', 'RoofMatl', 'Exterior1st', 'Exterior2nd', 'MasVnrType', - 'MasVnrArea', 'ExterQual', 'ExterCond', 'Foundation', 'BsmtQual', - 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinSF1', - 'BsmtFinType2', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', 'Heating', - 'HeatingQC', 'CentralAir', 'Electrical', '1stFlrSF', '2ndFlrSF', - 'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath', - 'HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'KitchenQual', - 'TotRmsAbvGrd', 'Functional', 'Fireplaces', 'FireplaceQu', 'GarageType', - 'GarageYrBlt', 'GarageFinish', 'GarageCars', 'GarageArea', 'GarageQual', - 'GarageCond', 'PavedDrive', 'WoodDeckSF', 'OpenPorchSF', - 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'PoolQC', - 'Fence', 'MiscFeature', 'MiscVal', 'MoSold', 'YrSold', 'SaleType', - 'SaleCondition', 'SalePrice'], - dtype='object') - - -![](/img/competitions/getting-started/house-price/房价预测-字段说明.png) - - -```python -train.info() -``` - - - RangeIndex: 1460 entries, 0 to 1459 - Data columns (total 81 columns): - Id 1460 non-null int64 - MSSubClass 1460 non-null int64 - MSZoning 1460 non-null object - LotFrontage 1201 non-null float64 - LotArea 1460 non-null int64 - Street 1460 non-null object - Alley 91 non-null object - LotShape 1460 non-null object - LandContour 1460 non-null object - Utilities 1460 non-null object - LotConfig 1460 non-null object - LandSlope 1460 non-null object - Neighborhood 1460 non-null object - Condition1 1460 non-null object - Condition2 1460 non-null object - BldgType 1460 non-null object - HouseStyle 1460 non-null object - OverallQual 1460 non-null int64 - OverallCond 1460 non-null int64 - YearBuilt 1460 non-null int64 - YearRemodAdd 1460 non-null int64 - RoofStyle 1460 non-null object - RoofMatl 1460 non-null object - Exterior1st 1460 non-null object - Exterior2nd 1460 non-null object - MasVnrType 1452 non-null object - MasVnrArea 1452 non-null float64 - ExterQual 1460 non-null object - ExterCond 1460 non-null object - Foundation 1460 non-null object - BsmtQual 1423 non-null object - BsmtCond 1423 non-null object - BsmtExposure 1422 non-null object - BsmtFinType1 1423 non-null object - BsmtFinSF1 1460 non-null int64 - BsmtFinType2 1422 non-null object - BsmtFinSF2 1460 non-null int64 - BsmtUnfSF 1460 non-null int64 - TotalBsmtSF 1460 non-null int64 - Heating 1460 non-null object - HeatingQC 1460 non-null object - CentralAir 1460 non-null object - Electrical 1459 non-null object - 1stFlrSF 1460 non-null int64 - 2ndFlrSF 1460 non-null int64 - LowQualFinSF 1460 non-null int64 - GrLivArea 1460 non-null int64 - BsmtFullBath 1460 non-null int64 - BsmtHalfBath 1460 non-null int64 - FullBath 1460 non-null int64 - HalfBath 1460 non-null int64 - BedroomAbvGr 1460 non-null int64 - KitchenAbvGr 1460 non-null int64 - KitchenQual 1460 non-null object - TotRmsAbvGrd 1460 non-null int64 - Functional 1460 non-null object - Fireplaces 1460 non-null int64 - FireplaceQu 770 non-null object - GarageType 1379 non-null object - GarageYrBlt 1379 non-null float64 - GarageFinish 1379 non-null object - GarageCars 1460 non-null int64 - GarageArea 1460 non-null int64 - GarageQual 1379 non-null object - GarageCond 1379 non-null object - PavedDrive 1460 non-null object - WoodDeckSF 1460 non-null int64 - OpenPorchSF 1460 non-null int64 - EnclosedPorch 1460 non-null int64 - 3SsnPorch 1460 non-null int64 - ScreenPorch 1460 non-null int64 - PoolArea 1460 non-null int64 - PoolQC 7 non-null object - Fence 281 non-null object - MiscFeature 54 non-null object - MiscVal 1460 non-null int64 - MoSold 1460 non-null int64 - YrSold 1460 non-null int64 - SaleType 1460 non-null object - SaleCondition 1460 non-null object - SalePrice 1460 non-null int64 - dtypes: float64(3), int64(35), object(43) - memory usage: 924.0+ KB - - -### 特征详情 - - -```python -train.head(5) -``` - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IdMSSubClassMSZoningLotFrontageLotAreaStreetAlleyLotShapeLandContourUtilities...PoolAreaPoolQCFenceMiscFeatureMiscValMoSoldYrSoldSaleTypeSaleConditionSalePrice
0160RL65.08450PaveNaNRegLvlAllPub...0NaNNaNNaN022008WDNormal208500
1220RL80.09600PaveNaNRegLvlAllPub...0NaNNaNNaN052007WDNormal181500
2360RL68.011250PaveNaNIR1LvlAllPub...0NaNNaNNaN092008WDNormal223500
3470RL60.09550PaveNaNIR1LvlAllPub...0NaNNaNNaN022006WDAbnorml140000
4560RL84.014260PaveNaNIR1LvlAllPub...0NaNNaNNaN0122008WDNormal250000
-

5 rows × 81 columns

-
- - - -### 特征分析(统计学与绘图) - -每一行是一条房子出售的记录,原始特征有80列,具体的意思可以根据data_description来查询,我们要预测的是房子的售价,即“SalePrice”。训练集有1459条记录,测试集有1460条记录,数据量还是很小的。 - - -```python -# 相关性协方差表,corr()函数,返回结果接近0说明无相关性,大于0说明是正相关,小于0是负相关. -train_corr = train.drop('Id',axis=1).corr() -train_corr -``` - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MSSubClassLotFrontageLotAreaOverallQualOverallCondYearBuiltYearRemodAddMasVnrAreaBsmtFinSF1BsmtFinSF2...WoodDeckSFOpenPorchSFEnclosedPorch3SsnPorchScreenPorchPoolAreaMiscValMoSoldYrSoldSalePrice
MSSubClass1.000000-0.386347-0.1397810.032628-0.0593160.0278500.0405810.022936-0.069836-0.065649...-0.012579-0.006100-0.012037-0.043825-0.0260300.008283-0.007683-0.013585-0.021407-0.084284
LotFrontage-0.3863471.0000000.4260950.251646-0.0592130.1233490.0888660.1934580.2336330.049900...0.0885210.1519720.0107000.0700290.0413830.2061670.0033680.0112000.0074500.351799
LotArea-0.1397810.4260951.0000000.105806-0.0056360.0142280.0137880.1041600.2141030.111170...0.1716980.084774-0.0183400.0204230.0431600.0776720.0380680.001205-0.0142610.263843
OverallQual0.0326280.2516460.1058061.000000-0.0919320.5723230.5506840.4118760.239666-0.059119...0.2389230.308819-0.1139370.0303710.0648860.065166-0.0314060.070815-0.0273470.790982
OverallCond-0.059316-0.059213-0.005636-0.0919321.000000-0.3759830.073741-0.128101-0.0462310.040229...-0.003334-0.0325890.0703560.0255040.054811-0.0019850.068777-0.0035110.043950-0.077856
YearBuilt0.0278500.1233490.0142280.572323-0.3759831.0000000.5928550.3157070.249503-0.049107...0.2248800.188686-0.3872680.031355-0.0503640.004950-0.0343830.012398-0.0136180.522897
YearRemodAdd0.0405810.0888660.0137880.5506840.0737410.5928551.0000000.1796180.128451-0.067759...0.2057260.226298-0.1939190.045286-0.0387400.005829-0.0102860.0214900.0357430.507101
MasVnrArea0.0229360.1934580.1041600.411876-0.1281010.3157070.1796181.0000000.264736-0.072319...0.1597180.125703-0.1102040.0187960.0614660.011723-0.029815-0.005965-0.0082010.477493
BsmtFinSF1-0.0698360.2336330.2141030.239666-0.0462310.2495030.1284510.2647361.000000-0.050117...0.2043060.111761-0.1023030.0264510.0620210.1404910.003571-0.0157270.0143590.386420
BsmtFinSF2-0.0656490.0499000.111170-0.0591190.040229-0.049107-0.067759-0.072319-0.0501171.000000...0.0678980.0030930.036543-0.0299930.0888710.0417090.004940-0.0152110.031706-0.011378
BsmtUnfSF-0.1407590.132644-0.0026180.308159-0.1368410.1490400.1811330.114442-0.495251-0.209294...-0.0053160.129005-0.0025380.020764-0.012579-0.035092-0.0238370.034888-0.0412580.214479
TotalBsmtSF-0.2385180.3920750.2608330.537808-0.1710980.3914520.2910660.3639360.5223960.104810...0.2320190.247264-0.0954780.0373840.0844890.126053-0.0184790.013196-0.0149690.613581
1stFlrSF-0.2517580.4571810.2994750.476224-0.1442030.2819860.2403790.3445010.4458630.097117...0.2354590.211671-0.0652920.0561040.0887580.131525-0.0210960.031372-0.0136040.605852
2ndFlrSF0.3078860.0801770.0509860.2954930.0289420.0103080.1400240.174561-0.137079-0.099260...0.0921650.2080260.061989-0.0243580.0406060.0814870.0161970.035164-0.0287000.319334
LowQualFinSF0.0464740.0384690.004779-0.0304290.025494-0.183784-0.062419-0.069071-0.0645030.014807...-0.0254440.0182510.061081-0.0042960.0267990.062157-0.003793-0.022174-0.028921-0.025606
GrLivArea0.0748530.4027970.2631160.593007-0.0796860.1990100.2873890.3908570.208171-0.009640...0.2474330.3302240.0091130.0206430.1015100.170205-0.0024160.050240-0.0365260.708624
BsmtFullBath0.0034910.1009490.1581550.111098-0.0549420.1875990.1194700.0853100.6492120.158678...0.1753150.067341-0.049911-0.0001060.0231480.067616-0.023047-0.0253610.0670490.227122
BsmtHalfBath-0.002333-0.0072340.048046-0.0401500.117821-0.038162-0.0123370.0266730.0674180.070948...0.040161-0.025324-0.0085550.0351140.0321210.020025-0.0073670.032873-0.046524-0.016844
FullBath0.1316080.1987690.1260310.550600-0.1941490.4682710.4390460.2768330.058543-0.076444...0.1877030.259977-0.1150930.035353-0.0081060.049604-0.0142900.055872-0.0196690.560664
HalfBath0.1773540.0535320.0142590.273458-0.0607690.2426560.1833310.2014440.004262-0.032148...0.1080800.199740-0.095317-0.0049720.0724260.0223810.001290-0.009050-0.0102690.284108
BedroomAbvGr-0.0234380.2631700.1196900.1016760.012980-0.070651-0.0405810.102821-0.107355-0.015728...0.0468540.0938100.041570-0.0244780.0443000.0707030.0077670.046544-0.0360140.168213
KitchenAbvGr0.281721-0.006069-0.017784-0.183882-0.087001-0.174800-0.149598-0.037610-0.081007-0.040751...-0.090130-0.0700910.037312-0.024600-0.051613-0.0145250.0623410.0265890.031687-0.135907
TotRmsAbvGrd0.0403800.3520960.1900150.427452-0.0575830.0955890.1917400.2806820.044316-0.035227...0.1659840.2341920.004151-0.0066830.0593830.0837570.0247630.036907-0.0345160.533723
Fireplaces-0.0455690.2666390.2713640.396765-0.0238200.1477160.1125810.2490700.2600110.046921...0.2000190.169405-0.0248220.0112570.1845300.0950740.0014090.046357-0.0240960.466929
GarageYrBlt0.0850720.070250-0.0249470.547766-0.3242970.8256670.6422770.2526910.153484-0.088011...0.2245770.228425-0.2970030.023544-0.075418-0.014501-0.0324170.005337-0.0010140.486362
GarageCars-0.0401100.2856910.1548710.600671-0.1857580.5378500.4206220.3642040.224054-0.038264...0.2263420.213569-0.1514340.0357650.0504940.020934-0.0430800.040522-0.0391170.640409
GarageArea-0.0986720.3449970.1804030.562022-0.1515210.4789540.3716000.3730660.296970-0.018227...0.2246660.241435-0.1217770.0350870.0514120.061047-0.0274000.027974-0.0273780.623431
WoodDeckSF-0.0125790.0885210.1716980.238923-0.0033340.2248800.2057260.1597180.2043060.067898...1.0000000.058661-0.125989-0.032771-0.0741810.073378-0.0095510.0210110.0222700.324413
OpenPorchSF-0.0061000.1519720.0847740.308819-0.0325890.1886860.2262980.1257030.1117610.003093...0.0586611.000000-0.093079-0.0058420.0743040.060762-0.0185840.071255-0.0576190.315856
EnclosedPorch-0.0120370.010700-0.018340-0.1139370.070356-0.387268-0.193919-0.110204-0.1023030.036543...-0.125989-0.0930791.000000-0.037305-0.0828640.0542030.018361-0.028887-0.009916-0.128578
3SsnPorch-0.0438250.0700290.0204230.0303710.0255040.0313550.0452860.0187960.026451-0.029993...-0.032771-0.005842-0.0373051.000000-0.031436-0.0079920.0003540.0294740.0186450.044584
ScreenPorch-0.0260300.0413830.0431600.0648860.054811-0.050364-0.0387400.0614660.0620210.088871...-0.0741810.074304-0.082864-0.0314361.0000000.0513070.0319460.0232170.0106940.111447
PoolArea0.0082830.2061670.0776720.065166-0.0019850.0049500.0058290.0117230.1404910.041709...0.0733780.0607620.054203-0.0079920.0513071.0000000.029669-0.033737-0.0596890.092404
MiscVal-0.0076830.0033680.038068-0.0314060.068777-0.034383-0.010286-0.0298150.0035710.004940...-0.009551-0.0185840.0183610.0003540.0319460.0296691.000000-0.0064950.004906-0.021190
MoSold-0.0135850.0112000.0012050.070815-0.0035110.0123980.021490-0.005965-0.015727-0.015211...0.0210110.071255-0.0288870.0294740.023217-0.033737-0.0064951.000000-0.1457210.046432
YrSold-0.0214070.007450-0.014261-0.0273470.043950-0.0136180.035743-0.0082010.0143590.031706...0.022270-0.057619-0.0099160.0186450.010694-0.0596890.004906-0.1457211.000000-0.028923
SalePrice-0.0842840.3517990.2638430.790982-0.0778560.5228970.5071010.4774930.386420-0.011378...0.3244130.315856-0.1285780.0445840.1114470.092404-0.0211900.046432-0.0289231.000000
-

37 rows × 37 columns

-
- - -> 所有特征相关度分析 - - -```python -# 画出相关性热力图 -a = plt.subplots(figsize=(20, 12))#调整画布大小 -a = sns.heatmap(train_corr, vmax=.8, square=True)#画热力图 annot=True 显示系数 -``` - - -![png](/img/competitions/getting-started/house-price/output_14_0.png) - - -> SalePrice 相关度特征排序 - - -```python -# 寻找K个最相关的特征信息 -k = 10 # number of variables for heatmap -cols = train_corr.nlargest(k, 'SalePrice')['SalePrice'].index -cm = np.corrcoef(train[cols].values.T) -sns.set(font_scale=1.5) -hm = plt.subplots(figsize=(20, 12))#调整画布大小 -hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values) -plt.show() - -''' -1. GarageCars 和 GarageAre 相关性很高、就像双胞胎一样,所以我们只需要其中的一个变量,例如:GarageCars。 -2. TotalBsmtSF 和 1stFloor 与上述情况相同,我们选择 TotalBsmtS -3. GarageAre 和 TotRmsAbvGrd 与上述情况相同,我们选择 GarageAre -''' -``` - - -![png](/img/competitions/getting-started/house-price/output_16_0.png) - - - '\n1. GarageCars 和 GarageAre 相关性很高、就像双胞胎一样,所以我们只需要其中的一个变量,例如:GarageCars。\n2. TotalBsmtSF 和 1stFloor 与上述情况相同,我们选择 TotalBsmtS\n3. GarageAre 和 TotRmsAbvGrd 与上述情况相同,我们选择 GarageAre\n' - - - -> SalePrice 和相关变量之间的散点图 - - -```python -sns.set() -cols = ['SalePrice', 'OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt'] -sns.pairplot(train[cols], size = 2.5) -plt.show(); -``` - - -![png](/img/competitions/getting-started/house-price/output_18_0.png) - - -```python -train[['SalePrice', 'OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']].info() -``` - - - RangeIndex: 1460 entries, 0 to 1459 - Data columns (total 7 columns): - SalePrice 1460 non-null int64 - OverallQual 1460 non-null int64 - GrLivArea 1460 non-null int64 - GarageCars 1460 non-null int64 - TotalBsmtSF 1460 non-null int64 - FullBath 1460 non-null int64 - YearBuilt 1460 non-null int64 - dtypes: int64(7) - memory usage: 79.9 KB - -## 二. 特征工程 - -``` -test['SalePrice'] = None -train_test = pd.concat((train, test)).reset_index(drop=True) -``` - -### 1. 缺失值分析 - -2. 根据业务,常识,以及第二步的数据分析构造特征工程. -2. 将特征转换为模型可以辨别的类型(如处理缺失值,处理文本进行等) - - -```python -total= train_test.isnull().sum().sort_values(ascending=False) -percent = (train_test.isnull().sum()/train_test.isnull().count()).sort_values(ascending=False) -missing_data = pd.concat([total, percent], axis=1, keys=['Total','Lost Percent']) - -print(missing_data[missing_data.isnull().values==False].sort_values('Total', axis=0, ascending=False).head(20)) - - -''' -1. 对于缺失率过高的特征,例如 超过15% 我们应该删掉相关变量且假设该变量并不存在 -2. GarageX 变量群的缺失数据量和概率都相同,可以选择一个就行,例如:GarageCars -3. 对于缺失数据在5%左右(缺失率低),可以直接删除/回归预测 -''' -``` - - - '\n1. 对于缺失率过高的特征,例如 超过15% 我们应该删掉相关变量且假设该变量并不存在\n2. GarageX 变量群的缺失数据量和概率都相同,可以选择一个就行,例如:GarageCars\n3. 对于缺失数据在5%左右(缺失率低),可以直接删除/回归预测\n' - - -```python -train_test = train_test.drop((missing_data[missing_data['Total'] > 1]).index.drop('SalePrice') , axis=1) -# train_test = train_test.drop(train.loc[train['Electrical'].isnull()].index) - -tmp = train_test[train_test['SalePrice'].isnull().values==False] -print(tmp.isnull().sum().max()) # justchecking that there's no missing data missing -``` - - - 1 - - - -### 2. 异常值处理 - -#### 单因素分析 - -这里的关键在于如何建立阈值,定义一个观察值为异常值。我们对数据进行正态化,意味着把数据值转换成均值为 0,方差为 1 的数据 - - -```python -fig = plt.figure(figsize=(12, 6)) -ax1 = fig.add_subplot(1, 2, 1) -ax2 = fig.add_subplot(1, 2, 2) -ax1.hist(train.SalePrice) -ax2.hist(np.log1p(train.SalePrice)) - -''' -从直方图中可以看出: - -* 偏离正态分布 -* 数据正偏 -* 有峰值 -''' -# 数据偏度和峰度度量: - -print("Skewness: %f" % train['SalePrice'].skew()) -print("Kurtosis: %f" % train['SalePrice'].kurt()) - -''' -低范围的值都比较相似并且在 0 附近分布。 -高范围的值离 0 很远,并且七点几的值远在正常范围之外。 -''' -``` - - - '\n低范围的值都比较相似并且在 0 附近分布。\n高范围的值离 0 很远,并且七点几的值远在正常范围之外。\n' - - -![png](/img/competitions/getting-started/house-price/output_25_1.png) - - -#### 双变量分析 - -> 1.GrLivArea 和 SalePrice 双变量分析 - - -```python -var = 'GrLivArea' -data = pd.concat([train['SalePrice'], train[var]], axis=1) -data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000)); - -''' -从图中可以看出: - -1. 有两个离群的 GrLivArea 值很高的数据,我们可以推测出现这种情况的原因。 - 或许他们代表了农业地区,也就解释了低价。 这两个点很明显不能代表典型样例,所以我们将它们定义为异常值并删除。 -2. 图中顶部的两个点是七点几的观测值,他们虽然看起来像特殊情况,但是他们依然符合整体趋势,所以我们将其保留下来。 -''' -``` - - - '\n从图中可以看出:\n\n1. 有两个离群的 GrLivArea 值很高的数据,我们可以推测出现这种情况的原因。\n 或许他们代表了农业地区,也就解释了低价。 这两个点很明显不能代表典型样例,所以我们将它们定义为异常值并删除。\n2. 图中顶部的两个点是七点几的观测值,他们虽然看起来像特殊情况,但是他们依然符合整体趋势,所以我们将其保留下来。\n' - - - - -![png](/img/competitions/getting-started/house-price/output_27_1.png) - - - -```python -# 删除点 -print(train.sort_values(by='GrLivArea', ascending = False)[:2]) -tmp = train_test[train_test['SalePrice'].isnull().values==False] - -train_test = train_test.drop(tmp[tmp['Id'] == 1299].index) -train_test = train_test.drop(tmp[tmp['Id'] == 524].index) -``` - -> 2.TotalBsmtSF 和 SalePrice 双变量分析 - - -```python -var = 'TotalBsmtSF' -data = pd.concat([train['SalePrice'],train[var]], axis=1) -data.plot.scatter(x=var, y='SalePrice',ylim=(0,800000)) -``` - - -![png](/img/competitions/getting-started/house-price/output_30_0.png) - - -### 核心部分 - -“房价” 到底是谁? - -这个问题的答案,需要我们验证根据数据基础进行多元分析的假设。 - -我们已经进行了数据清洗,并且发现了 SalePrice 的很多信息,现在我们要更进一步理解 SalePrice 如何遵循统计假设,可以让我们应用多元技术。 - -应该测量 4 个假设量: - -* 正态性 -* 同方差性 -* 线性 -* 相关错误缺失 - -#### 正态性: - -应主要关注以下两点:直方图 – 峰度和偏度。 - - -正态概率图 – 数据分布应紧密跟随代表正态分布的对角线。 - -1. SalePrice 绘制直方图和正态概率图: - - -```python -sns.distplot(train['SalePrice'], fit=norm) -fig = plt.figure() -res = stats.probplot(train['SalePrice'], plot=plt) - -''' -可以看出,房价分布不是正态的,显示了峰值,正偏度,但是并不跟随对角线。 -可以用对数变换来解决这个问题 -''' -``` - - - '\n可以看出,房价分布不是正态的,显示了峰值,正偏度,但是并不跟随对角线。\n可以用对数变换来解决这个问题\n' - - -![png](/img/competitions/getting-started/house-price/output_33_1.png) - - -![png](/img/competitions/getting-started/house-price/output_33_2.png) - - - -```python -# 进行对数变换: -# 进行对数变换: -train_test['SalePrice'] = [i if i is None else np.log1p(i) for i in train_test['SalePrice']] -``` - - -```python -# 绘制变换后的直方图和正态概率图: -tmp = train_test[train_test['SalePrice'].isnull().values==False] - -sns.distplot(tmp[tmp['SalePrice'] !=0]['SalePrice'], fit=norm); -fig = plt.figure() -res = stats.probplot(tmp['SalePrice'], plot=plt) -``` - - -![png](/img/competitions/getting-started/house-price/output_35_0.png) - - -![png](/img/competitions/getting-started/house-price/output_35_1.png) - - -#### 2. GrLivArea -绘制直方图和正态概率曲线图: - - -```python -sns.distplot(train['GrLivArea'], fit=norm); -fig = plt.figure() -res = stats.probplot(train['GrLivArea'], plot=plt) -``` - - -![png](/img/competitions/getting-started/house-price/output_37_0.png) - - -![png](/img/competitions/getting-started/house-price/output_37_1.png) - - - -```python -# 进行对数变换: -train_test['GrLivArea'] = [i if i is None else np.log1p(i) for i in train_test['GrLivArea']] - -# 绘制变换后的直方图和正态概率图: -tmp = train_test[train_test['SalePrice'].isnull().values==False] -sns.distplot(tmp['GrLivArea'], fit=norm) -fig = plt.figure() -res = stats.probplot(tmp['GrLivArea'], plot=plt) -``` - - -![png](/img/competitions/getting-started/house-price/output_38_0.png) - - -![png](/img/competitions/getting-started/house-price/output_38_1.png) - - -#### 3.TotalBsmtSF - -绘制直方图和正态概率曲线图: - - -```python -sns.distplot(train['TotalBsmtSF'],fit=norm); -fig = plt.figure() -res = stats.probplot(train['TotalBsmtSF'],plot=plt) - -''' -从图中可以看出: -* 显示出了偏度 -* 大量为 0(Y值) 的观察值(没有地下室的房屋) -* 含 0(Y值) 的数据无法进行对数变换 -''' -``` - - '\n从图中可以看出:\n* 显示出了偏度\n* 大量为 0(Y值) 的观察值(没有地下室的房屋)\n* 含 0(Y值) 的数据无法进行对数变换\n' - - -![png](/img/competitions/getting-started/house-price/output_40_1.png) - - -![png](/img/competitions/getting-started/house-price/output_40_2.png) - - - -```python -# 去掉为0的分布情况 -tmp = train_test[train_test['SalePrice'].isnull().values==False] - -tmp = np.array(tmp.loc[tmp['TotalBsmtSF']>0, ['TotalBsmtSF']])[:, 0] -sns.distplot(tmp, fit=norm) -fig = plt.figure() -res = stats.probplot(tmp, plot=plt) -``` - - -![png](/img/competitions/getting-started/house-price/output_41_0.png) - - - -![png](/img/competitions/getting-started/house-price/output_41_1.png) - - - -```python -# 我们建立了一个变量,可以得到有没有地下室的影响值(二值变量),我们选择忽略零值,只对非零值进行对数变换。 -# 这样我们既可以变换数据,也不会损失有没有地下室的影响。 - -print(train.loc[train['TotalBsmtSF']==0, ['TotalBsmtSF']].count()) -train.loc[train['TotalBsmtSF']==0,'TotalBsmtSF'] = 1 -print(train.loc[train['TotalBsmtSF']==1, ['TotalBsmtSF']].count()) -``` - - TotalBsmtSF 37 - dtype: int64 - TotalBsmtSF 37 - dtype: int64 - - - -```python -# 进行对数变换: -tmp = train_test[train_test['SalePrice'].isnull().values==False] - -print(tmp['TotalBsmtSF'].head(10)) -train_test['TotalBsmtSF']= np.log1p(train_test['TotalBsmtSF']) - -tmp = train_test[train_test['SalePrice'].isnull().values==False] -print(tmp['TotalBsmtSF'].head(10)) -``` - - 0 856.0 - 1 1262.0 - 2 920.0 - 3 756.0 - 4 1145.0 - 5 796.0 - 6 1686.0 - 7 1107.0 - 8 952.0 - 9 991.0 - Name: TotalBsmtSF, dtype: float64 - 0 6.753438 - 1 7.141245 - 2 6.825460 - 3 6.629363 - 4 7.044033 - 5 6.680855 - 6 7.430707 - 7 7.010312 - 8 6.859615 - 9 6.899723 - Name: TotalBsmtSF, dtype: float64 - - - -```python -# 绘制变换后的直方图和正态概率图: -tmp = train_test[train_test['SalePrice'].isnull().values==False] - -tmp = np.array(tmp.loc[tmp['TotalBsmtSF']>0, ['TotalBsmtSF']])[:, 0] -sns.distplot(tmp, fit=norm) -fig = plt.figure() -res = stats.probplot(tmp, plot=plt) -``` - - -![png](/img/competitions/getting-started/house-price/output_44_0.png) - - - -![png](/img/competitions/getting-started/house-price/output_44_1.png) - - -#### 同方差性: - -最好的测量两个变量的同方差性的方法就是图像。 - -1. SalePrice 和 GrLivArea 同方差性 - -绘制散点图: - - - -```python -tmp = train_test[train_test['SalePrice'].isnull().values==False] - -plt.scatter(tmp['GrLivArea'], tmp['SalePrice']) -``` - - - - - -![png](/img/competitions/getting-started/house-price/output_46_1.png) - - -2. SalePrice with TotalBsmtSF 同方差性 - -绘制散点图: - - -```python -tmp = train_test[train_test['SalePrice'].isnull().values==False] - -plt.scatter(tmp[tmp['TotalBsmtSF']>0]['TotalBsmtSF'], tmp[tmp['TotalBsmtSF']>0]['SalePrice']) - -# 可以看出 SalePrice 在整个 TotalBsmtSF 变量范围内显示出了同等级别的变化。 -``` - - - - - - - -![png](/img/competitions/getting-started/house-price/output_48_1.png) - - -## 三. 模型选择 - -### 1.数据标准化 - - -```python -tmp = train_test[train_test['SalePrice'].isnull().values==False] -tmp_1 = train_test[train_test['SalePrice'].isnull().values==True] - -x_train = tmp[['OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']] -y_train = tmp[["SalePrice"]].values.ravel() -x_test = tmp_1[['OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']] - -# 简单测试,用中位数来替代 -# print(x_test.GarageCars.mean(), x_test.GarageCars.median(), x_test.TotalBsmtSF.mean(), x_test.TotalBsmtSF.median()) - -x_test["GarageCars"].fillna(x_test.GarageCars.median(), inplace=True) -x_test["TotalBsmtSF"].fillna(x_test.TotalBsmtSF.median(), inplace=True) -``` - -### 2.开始建模 - -1. 可选单个模型模型有 线性回归(Ridge、Lasso)、树回归、GBDT、XGBoost、LightGBM 等. -2. 也可以将多个模型组合起来,进行模型融合,比如voting,stacking等方法 -3. 好的特征决定模型上限,好的模型和参数可以无线逼近上限. -4. 我测试了多种模型,模型结果最高的随机森林,最高有0.8. - -#### bagging: - -单个分类器的效果真的是很有限。 -我们会倾向于把N多的分类器合在一起,做一个“综合分类器”以达到最好的效果。 -我们从刚刚的试验中得知,Ridge(alpha=15)给了我们最好的结果。 - - -```python -from sklearn.linear_model import Ridge -from sklearn.model_selection import cross_val_score -from sklearn.ensemble import BaggingRegressor, RandomForestRegressor - -ridge = Ridge(alpha=0.1) - -# bagging 把很多小的分类器放在一起,每个train随机的一部分数据,然后把它们的最终结果综合起来(多数投票) -# bagging 算是一种算法框架 -params = [1, 10, 20, 40, 60] -test_scores = [] -for param in params: - clf = BaggingRegressor(base_estimator=ridge, n_estimators=param) - # cv=5表示cross_val_score采用的是k-fold cross validation的方法,重复5次交叉验证 - # scoring='precision'、scoring='recall'、scoring='f1', scoring='neg_mean_squared_error' 方差值 - test_score = np.sqrt(-cross_val_score(clf, x_train, y_train, cv=10, scoring='neg_mean_squared_error')) - test_scores.append(np.mean(test_score)) - -print(test_score.mean()) -plt.plot(params, test_scores) -plt.title('n_estimators vs CV Error') -plt.show() -``` - - -![png](/img/competitions/getting-started/house-price/output_53_0.png) -```python -# 模型选择 -## LASSO Regression : -lasso = make_pipeline(RobustScaler(), Lasso(alpha=0.0005, random_state=1)) -* Elastic Net Regression -ENet = make_pipeline( - RobustScaler(), ElasticNet( - alpha=0.0005, l1_ratio=.9, random_state=3)) -Kernel Ridge Regression -KRR = KernelRidge(alpha=0.6, kernel='polynomial', degree=2, coef0=2.5) -## Gradient Boosting Regression -GBoost = GradientBoostingRegressor( - n_estimators=3000, - learning_rate=0.05, - max_depth=4, - max_features='sqrt', - min_samples_leaf=15, - min_samples_split=10, - loss='huber', - random_state=5) -## XGboost -model_xgb = xgb.XGBRegressor( - colsample_bytree=0.4603, - gamma=0.0468, - learning_rate=0.05, - max_depth=3, - min_child_weight=1.7817, - n_estimators=2200, - reg_alpha=0.4640, - reg_lambda=0.8571, - subsample=0.5213, - silent=1, - random_state=7, - nthread=-1) -## lightGBM -model_lgb = lgb.LGBMRegressor( - objective='regression', - num_leaves=5, - learning_rate=0.05, - n_estimators=720, - max_bin=55, - bagging_fraction=0.8, - bagging_freq=5, - feature_fraction=0.2319, - feature_fraction_seed=9, - bagging_seed=9, - min_data_in_leaf=6, - min_sum_hessian_in_leaf=11) -## 对这些基本模型进行打分 -score = rmsle_cv(lasso) -print("\nLasso score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) -score = rmsle_cv(ENet) -print("ElasticNet score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) -score = rmsle_cv(KRR) -print( - "Kernel Ridge score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) -score = rmsle_cv(GBoost) -print("Gradient Boosting score: {:.4f} ({:.4f})\n".format(score.mean(), - score.std())) -score = rmsle_cv(model_xgb) -print("Xgboost score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) -score = rmsle_cv(model_lgb) -print("LGBM score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) -``` - - -```python -from sklearn.linear_model import Ridge -from sklearn.model_selection import learning_curve - -ridge = Ridge(alpha=0.1) - -train_sizes, train_loss, test_loss = learning_curve(ridge, x_train, y_train, cv=10, - scoring='neg_mean_squared_error', - train_sizes = [0.1, 0.3, 0.5, 0.7, 0.9 , 0.95, 1]) - -# 训练误差均值 -train_loss_mean = -np.mean(train_loss, axis = 1) -# 测试误差均值 -test_loss_mean = -np.mean(test_loss, axis = 1) - -# 绘制误差曲线 -plt.plot(train_sizes/len(x_train), train_loss_mean, 'o-', color = 'r', label = 'Training') -plt.plot(train_sizes/len(x_train), test_loss_mean, 'o-', color = 'g', label = 'Cross-Validation') - -plt.xlabel('Training data size') -plt.ylabel('Loss') -plt.legend(loc = 'best') -plt.show() -``` - - -![png](/img/competitions/getting-started/house-price/output_54_0.png) - - - -```python -mode_br = BaggingRegressor(base_estimator=ridge, n_estimators=10) -mode_br.fit(x_train, y_train) -y_test = np.expm1(mode_br.predict(x_test)) -``` - -## 四 建立模型 - -> 模型融合 voting - -```python -# 模型融合 -class AveragingModels(BaseEstimator, RegressorMixin, TransformerMixin): - def __init__(self, models): - self.models = models - - # we define clones of the original models to fit the data in - def fit(self, X, y): - self.models_ = [clone(x) for x in self.models] - - # Train cloned base models - for model in self.models_: - model.fit(X, y) - - return self - - # Now we do the predictions for cloned models and average them - def predict(self, X): - predictions = np.column_stack( - [model.predict(X) for model in self.models_]) - return np.mean(predictions, axis=1) - - -# 评价这四个模型的好坏 -averaged_models = AveragingModels(models=(ENet, GBoost, KRR, lasso)) -score = rmsle_cv(averaged_models) -print(" Averaged base models score: {:.4f} ({:.4f})\n".format(score.mean(), - score.std())) - -# 最终对模型的训练和预测 -# StackedRegressor -stacked_averaged_models.fit(train.values, y_train) -stacked_train_pred = stacked_averaged_models.predict(train.values) -stacked_pred = np.expm1(stacked_averaged_models.predict(test.values)) -print(rmsle(y_train, stacked_train_pred)) - -# XGBoost -model_xgb.fit(train, y_train) -xgb_train_pred = model_xgb.predict(train) -xgb_pred = np.expm1(model_xgb.predict(test)) -print(rmsle(y_train, xgb_train_pred)) -# lightGBM -model_lgb.fit(train, y_train) -lgb_train_pred = model_lgb.predict(train) -lgb_pred = np.expm1(model_lgb.predict(test.values)) -print(rmsle(y_train, lgb_train_pred)) -'''RMSE on the entire Train data when averaging''' - -print('RMSLE score on train data:') -print(rmsle(y_train, stacked_train_pred * 0.70 + xgb_train_pred * 0.15 + - lgb_train_pred * 0.15)) -# 模型融合的预测效果 -ensemble = stacked_pred * 0.70 + xgb_pred * 0.15 + lgb_pred * 0.15 -# 保存结果 -result = pd.DataFrame() -result['Id'] = test_ID -result['SalePrice'] = ensemble -# index=False 是用来除去行编号 -result.to_csv('/Users/liudong/Desktop/house_price/result.csv', index=False) -``` +# **房价预测** + +![](/img/competitions/getting-started/house-price/housesbanner.png) + +## 比赛说明 + +* [**房价预测**](https://www.kaggle.com/c/house-prices-advanced-regression-techniques) +* 要求购房者描述他们的梦想之家,他们可能不会从地下室天花板的高度或与东西方铁路的接近度开始。但是这个游乐场比赛的数据集证明,对价格谈判的影响远远超过卧室或白色栅栏的数量。 +* 有79个解释变量描述(几乎)爱荷华州埃姆斯的住宅房屋的每个方面,这个竞赛挑战你预测每个房屋的最终价格。 + +## 参赛成员 + +* 开源组织: [ApacheCN ~ apachecn.org](http://www.apachecn.org/) + +## 比赛分析 + +* 回归问题:价格的问题 +* 常用算法: `回归`、`树回归`、`GBDT`、`xgboost`、`lightGBM` + +``` +步骤: +一. 数据分析 +1. 下载并加载数据 +2. 总体预览:了解每列数据的含义,数据的格式等 +3. 数据初步分析,使用统计学与绘图:初步了解数据之间的相关性,为构造特征工程以及模型建立做准备 + +二. 特征工程 +1.根据业务,常识,以及第二步的数据分析构造特征工程. +2.将特征转换为模型可以辨别的类型(如处理缺失值,处理文本进行等) + +三. 模型选择 +1.根据目标函数确定学习类型,是无监督学习还是监督学习,是分类问题还是回归问题等. +2.比较各个模型的分数,然后取效果较好的模型作为基础模型. + +四. 模型融合 +1. 可以参考泰坦尼克号的简单模型融合方式,通过对模型的对比打分方式选择合适的模型 +2. 在房价预测里我们使用模型融合的方法来输出结果,最终的效果很好。 + +五. 修改特征和模型参数 +1.可以通过添加或者修改特征,提高模型的上限. +2.通过修改模型的参数,是模型逼近上限 +``` + +## 一. 数据分析 + +### 数据下载和加载 + +* 数据集下载地址: + +```python +# 导入相关数据包 +import numpy as np +import pandas as pd +import seaborn as sns +import matplotlib.pyplot as plt +%matplotlib inline + +from scipy import stats +from scipy.stats import norm +``` + + +```python +root_path = '/opt/data/kaggle/getting-started/house-prices' + +train = pd.read_csv('%s/%s' % (root_path, 'train.csv')) +test = pd.read_csv('%s/%s' % (root_path, 'test.csv')) +``` + +### 特征说明 + + +```python +train.columns +``` + + Index(['Id', 'MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea', 'Street', + 'Alley', 'LotShape', 'LandContour', 'Utilities', 'LotConfig', + 'LandSlope', 'Neighborhood', 'Condition1', 'Condition2', 'BldgType', + 'HouseStyle', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd', + 'RoofStyle', 'RoofMatl', 'Exterior1st', 'Exterior2nd', 'MasVnrType', + 'MasVnrArea', 'ExterQual', 'ExterCond', 'Foundation', 'BsmtQual', + 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinSF1', + 'BsmtFinType2', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', 'Heating', + 'HeatingQC', 'CentralAir', 'Electrical', '1stFlrSF', '2ndFlrSF', + 'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath', + 'HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'KitchenQual', + 'TotRmsAbvGrd', 'Functional', 'Fireplaces', 'FireplaceQu', 'GarageType', + 'GarageYrBlt', 'GarageFinish', 'GarageCars', 'GarageArea', 'GarageQual', + 'GarageCond', 'PavedDrive', 'WoodDeckSF', 'OpenPorchSF', + 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'PoolQC', + 'Fence', 'MiscFeature', 'MiscVal', 'MoSold', 'YrSold', 'SaleType', + 'SaleCondition', 'SalePrice'], + dtype='object') + + +![](/img/competitions/getting-started/house-price/房价预测-字段说明.png) + + +```python +train.info() +``` + + + RangeIndex: 1460 entries, 0 to 1459 + Data columns (total 81 columns): + Id 1460 non-null int64 + MSSubClass 1460 non-null int64 + MSZoning 1460 non-null object + LotFrontage 1201 non-null float64 + LotArea 1460 non-null int64 + Street 1460 non-null object + Alley 91 non-null object + LotShape 1460 non-null object + LandContour 1460 non-null object + Utilities 1460 non-null object + LotConfig 1460 non-null object + LandSlope 1460 non-null object + Neighborhood 1460 non-null object + Condition1 1460 non-null object + Condition2 1460 non-null object + BldgType 1460 non-null object + HouseStyle 1460 non-null object + OverallQual 1460 non-null int64 + OverallCond 1460 non-null int64 + YearBuilt 1460 non-null int64 + YearRemodAdd 1460 non-null int64 + RoofStyle 1460 non-null object + RoofMatl 1460 non-null object + Exterior1st 1460 non-null object + Exterior2nd 1460 non-null object + MasVnrType 1452 non-null object + MasVnrArea 1452 non-null float64 + ExterQual 1460 non-null object + ExterCond 1460 non-null object + Foundation 1460 non-null object + BsmtQual 1423 non-null object + BsmtCond 1423 non-null object + BsmtExposure 1422 non-null object + BsmtFinType1 1423 non-null object + BsmtFinSF1 1460 non-null int64 + BsmtFinType2 1422 non-null object + BsmtFinSF2 1460 non-null int64 + BsmtUnfSF 1460 non-null int64 + TotalBsmtSF 1460 non-null int64 + Heating 1460 non-null object + HeatingQC 1460 non-null object + CentralAir 1460 non-null object + Electrical 1459 non-null object + 1stFlrSF 1460 non-null int64 + 2ndFlrSF 1460 non-null int64 + LowQualFinSF 1460 non-null int64 + GrLivArea 1460 non-null int64 + BsmtFullBath 1460 non-null int64 + BsmtHalfBath 1460 non-null int64 + FullBath 1460 non-null int64 + HalfBath 1460 non-null int64 + BedroomAbvGr 1460 non-null int64 + KitchenAbvGr 1460 non-null int64 + KitchenQual 1460 non-null object + TotRmsAbvGrd 1460 non-null int64 + Functional 1460 non-null object + Fireplaces 1460 non-null int64 + FireplaceQu 770 non-null object + GarageType 1379 non-null object + GarageYrBlt 1379 non-null float64 + GarageFinish 1379 non-null object + GarageCars 1460 non-null int64 + GarageArea 1460 non-null int64 + GarageQual 1379 non-null object + GarageCond 1379 non-null object + PavedDrive 1460 non-null object + WoodDeckSF 1460 non-null int64 + OpenPorchSF 1460 non-null int64 + EnclosedPorch 1460 non-null int64 + 3SsnPorch 1460 non-null int64 + ScreenPorch 1460 non-null int64 + PoolArea 1460 non-null int64 + PoolQC 7 non-null object + Fence 281 non-null object + MiscFeature 54 non-null object + MiscVal 1460 non-null int64 + MoSold 1460 non-null int64 + YrSold 1460 non-null int64 + SaleType 1460 non-null object + SaleCondition 1460 non-null object + SalePrice 1460 non-null int64 + dtypes: float64(3), int64(35), object(43) + memory usage: 924.0+ KB + + +### 特征详情 + + +```python +train.head(5) +``` + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdMSSubClassMSZoningLotFrontageLotAreaStreetAlleyLotShapeLandContourUtilities...PoolAreaPoolQCFenceMiscFeatureMiscValMoSoldYrSoldSaleTypeSaleConditionSalePrice
0160RL65.08450PaveNaNRegLvlAllPub...0NaNNaNNaN022008WDNormal208500
1220RL80.09600PaveNaNRegLvlAllPub...0NaNNaNNaN052007WDNormal181500
2360RL68.011250PaveNaNIR1LvlAllPub...0NaNNaNNaN092008WDNormal223500
3470RL60.09550PaveNaNIR1LvlAllPub...0NaNNaNNaN022006WDAbnorml140000
4560RL84.014260PaveNaNIR1LvlAllPub...0NaNNaNNaN0122008WDNormal250000
+

5 rows × 81 columns

+
+ + + +### 特征分析(统计学与绘图) + +每一行是一条房子出售的记录,原始特征有80列,具体的意思可以根据data_description来查询,我们要预测的是房子的售价,即“SalePrice”。训练集有1459条记录,测试集有1460条记录,数据量还是很小的。 + + +```python +# 相关性协方差表,corr()函数,返回结果接近0说明无相关性,大于0说明是正相关,小于0是负相关. +train_corr = train.drop('Id',axis=1).corr() +train_corr +``` + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MSSubClassLotFrontageLotAreaOverallQualOverallCondYearBuiltYearRemodAddMasVnrAreaBsmtFinSF1BsmtFinSF2...WoodDeckSFOpenPorchSFEnclosedPorch3SsnPorchScreenPorchPoolAreaMiscValMoSoldYrSoldSalePrice
MSSubClass1.000000-0.386347-0.1397810.032628-0.0593160.0278500.0405810.022936-0.069836-0.065649...-0.012579-0.006100-0.012037-0.043825-0.0260300.008283-0.007683-0.013585-0.021407-0.084284
LotFrontage-0.3863471.0000000.4260950.251646-0.0592130.1233490.0888660.1934580.2336330.049900...0.0885210.1519720.0107000.0700290.0413830.2061670.0033680.0112000.0074500.351799
LotArea-0.1397810.4260951.0000000.105806-0.0056360.0142280.0137880.1041600.2141030.111170...0.1716980.084774-0.0183400.0204230.0431600.0776720.0380680.001205-0.0142610.263843
OverallQual0.0326280.2516460.1058061.000000-0.0919320.5723230.5506840.4118760.239666-0.059119...0.2389230.308819-0.1139370.0303710.0648860.065166-0.0314060.070815-0.0273470.790982
OverallCond-0.059316-0.059213-0.005636-0.0919321.000000-0.3759830.073741-0.128101-0.0462310.040229...-0.003334-0.0325890.0703560.0255040.054811-0.0019850.068777-0.0035110.043950-0.077856
YearBuilt0.0278500.1233490.0142280.572323-0.3759831.0000000.5928550.3157070.249503-0.049107...0.2248800.188686-0.3872680.031355-0.0503640.004950-0.0343830.012398-0.0136180.522897
YearRemodAdd0.0405810.0888660.0137880.5506840.0737410.5928551.0000000.1796180.128451-0.067759...0.2057260.226298-0.1939190.045286-0.0387400.005829-0.0102860.0214900.0357430.507101
MasVnrArea0.0229360.1934580.1041600.411876-0.1281010.3157070.1796181.0000000.264736-0.072319...0.1597180.125703-0.1102040.0187960.0614660.011723-0.029815-0.005965-0.0082010.477493
BsmtFinSF1-0.0698360.2336330.2141030.239666-0.0462310.2495030.1284510.2647361.000000-0.050117...0.2043060.111761-0.1023030.0264510.0620210.1404910.003571-0.0157270.0143590.386420
BsmtFinSF2-0.0656490.0499000.111170-0.0591190.040229-0.049107-0.067759-0.072319-0.0501171.000000...0.0678980.0030930.036543-0.0299930.0888710.0417090.004940-0.0152110.031706-0.011378
BsmtUnfSF-0.1407590.132644-0.0026180.308159-0.1368410.1490400.1811330.114442-0.495251-0.209294...-0.0053160.129005-0.0025380.020764-0.012579-0.035092-0.0238370.034888-0.0412580.214479
TotalBsmtSF-0.2385180.3920750.2608330.537808-0.1710980.3914520.2910660.3639360.5223960.104810...0.2320190.247264-0.0954780.0373840.0844890.126053-0.0184790.013196-0.0149690.613581
1stFlrSF-0.2517580.4571810.2994750.476224-0.1442030.2819860.2403790.3445010.4458630.097117...0.2354590.211671-0.0652920.0561040.0887580.131525-0.0210960.031372-0.0136040.605852
2ndFlrSF0.3078860.0801770.0509860.2954930.0289420.0103080.1400240.174561-0.137079-0.099260...0.0921650.2080260.061989-0.0243580.0406060.0814870.0161970.035164-0.0287000.319334
LowQualFinSF0.0464740.0384690.004779-0.0304290.025494-0.183784-0.062419-0.069071-0.0645030.014807...-0.0254440.0182510.061081-0.0042960.0267990.062157-0.003793-0.022174-0.028921-0.025606
GrLivArea0.0748530.4027970.2631160.593007-0.0796860.1990100.2873890.3908570.208171-0.009640...0.2474330.3302240.0091130.0206430.1015100.170205-0.0024160.050240-0.0365260.708624
BsmtFullBath0.0034910.1009490.1581550.111098-0.0549420.1875990.1194700.0853100.6492120.158678...0.1753150.067341-0.049911-0.0001060.0231480.067616-0.023047-0.0253610.0670490.227122
BsmtHalfBath-0.002333-0.0072340.048046-0.0401500.117821-0.038162-0.0123370.0266730.0674180.070948...0.040161-0.025324-0.0085550.0351140.0321210.020025-0.0073670.032873-0.046524-0.016844
FullBath0.1316080.1987690.1260310.550600-0.1941490.4682710.4390460.2768330.058543-0.076444...0.1877030.259977-0.1150930.035353-0.0081060.049604-0.0142900.055872-0.0196690.560664
HalfBath0.1773540.0535320.0142590.273458-0.0607690.2426560.1833310.2014440.004262-0.032148...0.1080800.199740-0.095317-0.0049720.0724260.0223810.001290-0.009050-0.0102690.284108
BedroomAbvGr-0.0234380.2631700.1196900.1016760.012980-0.070651-0.0405810.102821-0.107355-0.015728...0.0468540.0938100.041570-0.0244780.0443000.0707030.0077670.046544-0.0360140.168213
KitchenAbvGr0.281721-0.006069-0.017784-0.183882-0.087001-0.174800-0.149598-0.037610-0.081007-0.040751...-0.090130-0.0700910.037312-0.024600-0.051613-0.0145250.0623410.0265890.031687-0.135907
TotRmsAbvGrd0.0403800.3520960.1900150.427452-0.0575830.0955890.1917400.2806820.044316-0.035227...0.1659840.2341920.004151-0.0066830.0593830.0837570.0247630.036907-0.0345160.533723
Fireplaces-0.0455690.2666390.2713640.396765-0.0238200.1477160.1125810.2490700.2600110.046921...0.2000190.169405-0.0248220.0112570.1845300.0950740.0014090.046357-0.0240960.466929
GarageYrBlt0.0850720.070250-0.0249470.547766-0.3242970.8256670.6422770.2526910.153484-0.088011...0.2245770.228425-0.2970030.023544-0.075418-0.014501-0.0324170.005337-0.0010140.486362
GarageCars-0.0401100.2856910.1548710.600671-0.1857580.5378500.4206220.3642040.224054-0.038264...0.2263420.213569-0.1514340.0357650.0504940.020934-0.0430800.040522-0.0391170.640409
GarageArea-0.0986720.3449970.1804030.562022-0.1515210.4789540.3716000.3730660.296970-0.018227...0.2246660.241435-0.1217770.0350870.0514120.061047-0.0274000.027974-0.0273780.623431
WoodDeckSF-0.0125790.0885210.1716980.238923-0.0033340.2248800.2057260.1597180.2043060.067898...1.0000000.058661-0.125989-0.032771-0.0741810.073378-0.0095510.0210110.0222700.324413
OpenPorchSF-0.0061000.1519720.0847740.308819-0.0325890.1886860.2262980.1257030.1117610.003093...0.0586611.000000-0.093079-0.0058420.0743040.060762-0.0185840.071255-0.0576190.315856
EnclosedPorch-0.0120370.010700-0.018340-0.1139370.070356-0.387268-0.193919-0.110204-0.1023030.036543...-0.125989-0.0930791.000000-0.037305-0.0828640.0542030.018361-0.028887-0.009916-0.128578
3SsnPorch-0.0438250.0700290.0204230.0303710.0255040.0313550.0452860.0187960.026451-0.029993...-0.032771-0.005842-0.0373051.000000-0.031436-0.0079920.0003540.0294740.0186450.044584
ScreenPorch-0.0260300.0413830.0431600.0648860.054811-0.050364-0.0387400.0614660.0620210.088871...-0.0741810.074304-0.082864-0.0314361.0000000.0513070.0319460.0232170.0106940.111447
PoolArea0.0082830.2061670.0776720.065166-0.0019850.0049500.0058290.0117230.1404910.041709...0.0733780.0607620.054203-0.0079920.0513071.0000000.029669-0.033737-0.0596890.092404
MiscVal-0.0076830.0033680.038068-0.0314060.068777-0.034383-0.010286-0.0298150.0035710.004940...-0.009551-0.0185840.0183610.0003540.0319460.0296691.000000-0.0064950.004906-0.021190
MoSold-0.0135850.0112000.0012050.070815-0.0035110.0123980.021490-0.005965-0.015727-0.015211...0.0210110.071255-0.0288870.0294740.023217-0.033737-0.0064951.000000-0.1457210.046432
YrSold-0.0214070.007450-0.014261-0.0273470.043950-0.0136180.035743-0.0082010.0143590.031706...0.022270-0.057619-0.0099160.0186450.010694-0.0596890.004906-0.1457211.000000-0.028923
SalePrice-0.0842840.3517990.2638430.790982-0.0778560.5228970.5071010.4774930.386420-0.011378...0.3244130.315856-0.1285780.0445840.1114470.092404-0.0211900.046432-0.0289231.000000
+

37 rows × 37 columns

+
+ + +> 所有特征相关度分析 + + +```python +# 画出相关性热力图 +a = plt.subplots(figsize=(20, 12))#调整画布大小 +a = sns.heatmap(train_corr, vmax=.8, square=True)#画热力图 annot=True 显示系数 +``` + + +![png](/img/competitions/getting-started/house-price/output_14_0.png) + + +> SalePrice 相关度特征排序 + + +```python +# 寻找K个最相关的特征信息 +k = 10 # number of variables for heatmap +cols = train_corr.nlargest(k, 'SalePrice')['SalePrice'].index +cm = np.corrcoef(train[cols].values.T) +sns.set(font_scale=1.5) +hm = plt.subplots(figsize=(20, 12))#调整画布大小 +hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values) +plt.show() + +''' +1. GarageCars 和 GarageAre 相关性很高、就像双胞胎一样,所以我们只需要其中的一个变量,例如:GarageCars。 +2. TotalBsmtSF 和 1stFloor 与上述情况相同,我们选择 TotalBsmtS +3. GarageAre 和 TotRmsAbvGrd 与上述情况相同,我们选择 GarageAre +''' +``` + + +![png](/img/competitions/getting-started/house-price/output_16_0.png) + + + '\n1. GarageCars 和 GarageAre 相关性很高、就像双胞胎一样,所以我们只需要其中的一个变量,例如:GarageCars。\n2. TotalBsmtSF 和 1stFloor 与上述情况相同,我们选择 TotalBsmtS\n3. GarageAre 和 TotRmsAbvGrd 与上述情况相同,我们选择 GarageAre\n' + + + +> SalePrice 和相关变量之间的散点图 + + +```python +sns.set() +cols = ['SalePrice', 'OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt'] +sns.pairplot(train[cols], size = 2.5) +plt.show(); +``` + + +![png](/img/competitions/getting-started/house-price/output_18_0.png) + + +```python +train[['SalePrice', 'OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']].info() +``` + + + RangeIndex: 1460 entries, 0 to 1459 + Data columns (total 7 columns): + SalePrice 1460 non-null int64 + OverallQual 1460 non-null int64 + GrLivArea 1460 non-null int64 + GarageCars 1460 non-null int64 + TotalBsmtSF 1460 non-null int64 + FullBath 1460 non-null int64 + YearBuilt 1460 non-null int64 + dtypes: int64(7) + memory usage: 79.9 KB + +## 二. 特征工程 + +``` +test['SalePrice'] = None +train_test = pd.concat((train, test)).reset_index(drop=True) +``` + +### 1. 缺失值分析 + +2. 根据业务,常识,以及第二步的数据分析构造特征工程. +2. 将特征转换为模型可以辨别的类型(如处理缺失值,处理文本进行等) + + +```python +total= train_test.isnull().sum().sort_values(ascending=False) +percent = (train_test.isnull().sum()/train_test.isnull().count()).sort_values(ascending=False) +missing_data = pd.concat([total, percent], axis=1, keys=['Total','Lost Percent']) + +print(missing_data[missing_data.isnull().values==False].sort_values('Total', axis=0, ascending=False).head(20)) + + +''' +1. 对于缺失率过高的特征,例如 超过15% 我们应该删掉相关变量且假设该变量并不存在 +2. GarageX 变量群的缺失数据量和概率都相同,可以选择一个就行,例如:GarageCars +3. 对于缺失数据在5%左右(缺失率低),可以直接删除/回归预测 +''' +``` + + + '\n1. 对于缺失率过高的特征,例如 超过15% 我们应该删掉相关变量且假设该变量并不存在\n2. GarageX 变量群的缺失数据量和概率都相同,可以选择一个就行,例如:GarageCars\n3. 对于缺失数据在5%左右(缺失率低),可以直接删除/回归预测\n' + + +```python +train_test = train_test.drop((missing_data[missing_data['Total'] > 1]).index.drop('SalePrice') , axis=1) +# train_test = train_test.drop(train.loc[train['Electrical'].isnull()].index) + +tmp = train_test[train_test['SalePrice'].isnull().values==False] +print(tmp.isnull().sum().max()) # justchecking that there's no missing data missing +``` + + + 1 + + + +### 2. 异常值处理 + +#### 单因素分析 + +这里的关键在于如何建立阈值,定义一个观察值为异常值。我们对数据进行正态化,意味着把数据值转换成均值为 0,方差为 1 的数据 + + +```python +fig = plt.figure(figsize=(12, 6)) +ax1 = fig.add_subplot(1, 2, 1) +ax2 = fig.add_subplot(1, 2, 2) +ax1.hist(train.SalePrice) +ax2.hist(np.log1p(train.SalePrice)) + +''' +从直方图中可以看出: + +* 偏离正态分布 +* 数据正偏 +* 有峰值 +''' +# 数据偏度和峰度度量: + +print("Skewness: %f" % train['SalePrice'].skew()) +print("Kurtosis: %f" % train['SalePrice'].kurt()) + +''' +低范围的值都比较相似并且在 0 附近分布。 +高范围的值离 0 很远,并且七点几的值远在正常范围之外。 +''' +``` + + + '\n低范围的值都比较相似并且在 0 附近分布。\n高范围的值离 0 很远,并且七点几的值远在正常范围之外。\n' + + +![png](/img/competitions/getting-started/house-price/output_25_1.png) + + +#### 双变量分析 + +> 1.GrLivArea 和 SalePrice 双变量分析 + + +```python +var = 'GrLivArea' +data = pd.concat([train['SalePrice'], train[var]], axis=1) +data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000)); + +''' +从图中可以看出: + +1. 有两个离群的 GrLivArea 值很高的数据,我们可以推测出现这种情况的原因。 + 或许他们代表了农业地区,也就解释了低价。 这两个点很明显不能代表典型样例,所以我们将它们定义为异常值并删除。 +2. 图中顶部的两个点是七点几的观测值,他们虽然看起来像特殊情况,但是他们依然符合整体趋势,所以我们将其保留下来。 +''' +``` + + + '\n从图中可以看出:\n\n1. 有两个离群的 GrLivArea 值很高的数据,我们可以推测出现这种情况的原因。\n 或许他们代表了农业地区,也就解释了低价。 这两个点很明显不能代表典型样例,所以我们将它们定义为异常值并删除。\n2. 图中顶部的两个点是七点几的观测值,他们虽然看起来像特殊情况,但是他们依然符合整体趋势,所以我们将其保留下来。\n' + + + + +![png](/img/competitions/getting-started/house-price/output_27_1.png) + + + +```python +# 删除点 +print(train.sort_values(by='GrLivArea', ascending = False)[:2]) +tmp = train_test[train_test['SalePrice'].isnull().values==False] + +train_test = train_test.drop(tmp[tmp['Id'] == 1299].index) +train_test = train_test.drop(tmp[tmp['Id'] == 524].index) +``` + +> 2.TotalBsmtSF 和 SalePrice 双变量分析 + + +```python +var = 'TotalBsmtSF' +data = pd.concat([train['SalePrice'],train[var]], axis=1) +data.plot.scatter(x=var, y='SalePrice',ylim=(0,800000)) +``` + + +![png](/img/competitions/getting-started/house-price/output_30_0.png) + + +### 核心部分 + +“房价” 到底是谁? + +这个问题的答案,需要我们验证根据数据基础进行多元分析的假设。 + +我们已经进行了数据清洗,并且发现了 SalePrice 的很多信息,现在我们要更进一步理解 SalePrice 如何遵循统计假设,可以让我们应用多元技术。 + +应该测量 4 个假设量: + +* 正态性 +* 同方差性 +* 线性 +* 相关错误缺失 + +#### 正态性: + +应主要关注以下两点:直方图 – 峰度和偏度。 + + +正态概率图 – 数据分布应紧密跟随代表正态分布的对角线。 + +1. SalePrice 绘制直方图和正态概率图: + + +```python +sns.distplot(train['SalePrice'], fit=norm) +fig = plt.figure() +res = stats.probplot(train['SalePrice'], plot=plt) + +''' +可以看出,房价分布不是正态的,显示了峰值,正偏度,但是并不跟随对角线。 +可以用对数变换来解决这个问题 +''' +``` + + + '\n可以看出,房价分布不是正态的,显示了峰值,正偏度,但是并不跟随对角线。\n可以用对数变换来解决这个问题\n' + + +![png](/img/competitions/getting-started/house-price/output_33_1.png) + + +![png](/img/competitions/getting-started/house-price/output_33_2.png) + + + +```python +# 进行对数变换: +# 进行对数变换: +train_test['SalePrice'] = [i if i is None else np.log1p(i) for i in train_test['SalePrice']] +``` + + +```python +# 绘制变换后的直方图和正态概率图: +tmp = train_test[train_test['SalePrice'].isnull().values==False] + +sns.distplot(tmp[tmp['SalePrice'] !=0]['SalePrice'], fit=norm); +fig = plt.figure() +res = stats.probplot(tmp['SalePrice'], plot=plt) +``` + + +![png](/img/competitions/getting-started/house-price/output_35_0.png) + + +![png](/img/competitions/getting-started/house-price/output_35_1.png) + + +#### 2. GrLivArea +绘制直方图和正态概率曲线图: + + +```python +sns.distplot(train['GrLivArea'], fit=norm); +fig = plt.figure() +res = stats.probplot(train['GrLivArea'], plot=plt) +``` + + +![png](/img/competitions/getting-started/house-price/output_37_0.png) + + +![png](/img/competitions/getting-started/house-price/output_37_1.png) + + + +```python +# 进行对数变换: +train_test['GrLivArea'] = [i if i is None else np.log1p(i) for i in train_test['GrLivArea']] + +# 绘制变换后的直方图和正态概率图: +tmp = train_test[train_test['SalePrice'].isnull().values==False] +sns.distplot(tmp['GrLivArea'], fit=norm) +fig = plt.figure() +res = stats.probplot(tmp['GrLivArea'], plot=plt) +``` + + +![png](/img/competitions/getting-started/house-price/output_38_0.png) + + +![png](/img/competitions/getting-started/house-price/output_38_1.png) + + +#### 3.TotalBsmtSF + +绘制直方图和正态概率曲线图: + + +```python +sns.distplot(train['TotalBsmtSF'],fit=norm); +fig = plt.figure() +res = stats.probplot(train['TotalBsmtSF'],plot=plt) + +''' +从图中可以看出: +* 显示出了偏度 +* 大量为 0(Y值) 的观察值(没有地下室的房屋) +* 含 0(Y值) 的数据无法进行对数变换 +''' +``` + + '\n从图中可以看出:\n* 显示出了偏度\n* 大量为 0(Y值) 的观察值(没有地下室的房屋)\n* 含 0(Y值) 的数据无法进行对数变换\n' + + +![png](/img/competitions/getting-started/house-price/output_40_1.png) + + +![png](/img/competitions/getting-started/house-price/output_40_2.png) + + + +```python +# 去掉为0的分布情况 +tmp = train_test[train_test['SalePrice'].isnull().values==False] + +tmp = np.array(tmp.loc[tmp['TotalBsmtSF']>0, ['TotalBsmtSF']])[:, 0] +sns.distplot(tmp, fit=norm) +fig = plt.figure() +res = stats.probplot(tmp, plot=plt) +``` + + +![png](/img/competitions/getting-started/house-price/output_41_0.png) + + + +![png](/img/competitions/getting-started/house-price/output_41_1.png) + + + +```python +# 我们建立了一个变量,可以得到有没有地下室的影响值(二值变量),我们选择忽略零值,只对非零值进行对数变换。 +# 这样我们既可以变换数据,也不会损失有没有地下室的影响。 + +print(train.loc[train['TotalBsmtSF']==0, ['TotalBsmtSF']].count()) +train.loc[train['TotalBsmtSF']==0,'TotalBsmtSF'] = 1 +print(train.loc[train['TotalBsmtSF']==1, ['TotalBsmtSF']].count()) +``` + + TotalBsmtSF 37 + dtype: int64 + TotalBsmtSF 37 + dtype: int64 + + + +```python +# 进行对数变换: +tmp = train_test[train_test['SalePrice'].isnull().values==False] + +print(tmp['TotalBsmtSF'].head(10)) +train_test['TotalBsmtSF']= np.log1p(train_test['TotalBsmtSF']) + +tmp = train_test[train_test['SalePrice'].isnull().values==False] +print(tmp['TotalBsmtSF'].head(10)) +``` + + 0 856.0 + 1 1262.0 + 2 920.0 + 3 756.0 + 4 1145.0 + 5 796.0 + 6 1686.0 + 7 1107.0 + 8 952.0 + 9 991.0 + Name: TotalBsmtSF, dtype: float64 + 0 6.753438 + 1 7.141245 + 2 6.825460 + 3 6.629363 + 4 7.044033 + 5 6.680855 + 6 7.430707 + 7 7.010312 + 8 6.859615 + 9 6.899723 + Name: TotalBsmtSF, dtype: float64 + + + +```python +# 绘制变换后的直方图和正态概率图: +tmp = train_test[train_test['SalePrice'].isnull().values==False] + +tmp = np.array(tmp.loc[tmp['TotalBsmtSF']>0, ['TotalBsmtSF']])[:, 0] +sns.distplot(tmp, fit=norm) +fig = plt.figure() +res = stats.probplot(tmp, plot=plt) +``` + + +![png](/img/competitions/getting-started/house-price/output_44_0.png) + + + +![png](/img/competitions/getting-started/house-price/output_44_1.png) + + +#### 同方差性: + +最好的测量两个变量的同方差性的方法就是图像。 + +1. SalePrice 和 GrLivArea 同方差性 + +绘制散点图: + + + +```python +tmp = train_test[train_test['SalePrice'].isnull().values==False] + +plt.scatter(tmp['GrLivArea'], tmp['SalePrice']) +``` + + + + + +![png](/img/competitions/getting-started/house-price/output_46_1.png) + + +2. SalePrice with TotalBsmtSF 同方差性 + +绘制散点图: + + +```python +tmp = train_test[train_test['SalePrice'].isnull().values==False] + +plt.scatter(tmp[tmp['TotalBsmtSF']>0]['TotalBsmtSF'], tmp[tmp['TotalBsmtSF']>0]['SalePrice']) + +# 可以看出 SalePrice 在整个 TotalBsmtSF 变量范围内显示出了同等级别的变化。 +``` + + + + + + + +![png](/img/competitions/getting-started/house-price/output_48_1.png) + + +## 三. 模型选择 + +### 1.数据标准化 + + +```python +tmp = train_test[train_test['SalePrice'].isnull().values==False] +tmp_1 = train_test[train_test['SalePrice'].isnull().values==True] + +x_train = tmp[['OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']] +y_train = tmp[["SalePrice"]].values.ravel() +x_test = tmp_1[['OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']] + +# 简单测试,用中位数来替代 +# print(x_test.GarageCars.mean(), x_test.GarageCars.median(), x_test.TotalBsmtSF.mean(), x_test.TotalBsmtSF.median()) + +x_test["GarageCars"].fillna(x_test.GarageCars.median(), inplace=True) +x_test["TotalBsmtSF"].fillna(x_test.TotalBsmtSF.median(), inplace=True) +``` + +### 2.开始建模 + +1. 可选单个模型模型有 线性回归(Ridge、Lasso)、树回归、GBDT、XGBoost、LightGBM 等. +2. 也可以将多个模型组合起来,进行模型融合,比如voting,stacking等方法 +3. 好的特征决定模型上限,好的模型和参数可以无线逼近上限. +4. 我测试了多种模型,模型结果最高的随机森林,最高有0.8. + +#### bagging: + +单个分类器的效果真的是很有限。 +我们会倾向于把N多的分类器合在一起,做一个“综合分类器”以达到最好的效果。 +我们从刚刚的试验中得知,Ridge(alpha=15)给了我们最好的结果。 + + +```python +from sklearn.linear_model import Ridge +from sklearn.model_selection import cross_val_score +from sklearn.ensemble import BaggingRegressor, RandomForestRegressor + +ridge = Ridge(alpha=0.1) + +# bagging 把很多小的分类器放在一起,每个train随机的一部分数据,然后把它们的最终结果综合起来(多数投票) +# bagging 算是一种算法框架 +params = [1, 10, 20, 40, 60] +test_scores = [] +for param in params: + clf = BaggingRegressor(base_estimator=ridge, n_estimators=param) + # cv=5表示cross_val_score采用的是k-fold cross validation的方法,重复5次交叉验证 + # scoring='precision'、scoring='recall'、scoring='f1', scoring='neg_mean_squared_error' 方差值 + test_score = np.sqrt(-cross_val_score(clf, x_train, y_train, cv=10, scoring='neg_mean_squared_error')) + test_scores.append(np.mean(test_score)) + +print(test_score.mean()) +plt.plot(params, test_scores) +plt.title('n_estimators vs CV Error') +plt.show() +``` + + +![png](/img/competitions/getting-started/house-price/output_53_0.png) +```python +# 模型选择 +## LASSO Regression : +lasso = make_pipeline(RobustScaler(), Lasso(alpha=0.0005, random_state=1)) +* Elastic Net Regression +ENet = make_pipeline( + RobustScaler(), ElasticNet( + alpha=0.0005, l1_ratio=.9, random_state=3)) +Kernel Ridge Regression +KRR = KernelRidge(alpha=0.6, kernel='polynomial', degree=2, coef0=2.5) +## Gradient Boosting Regression +GBoost = GradientBoostingRegressor( + n_estimators=3000, + learning_rate=0.05, + max_depth=4, + max_features='sqrt', + min_samples_leaf=15, + min_samples_split=10, + loss='huber', + random_state=5) +## XGboost +model_xgb = xgb.XGBRegressor( + colsample_bytree=0.4603, + gamma=0.0468, + learning_rate=0.05, + max_depth=3, + min_child_weight=1.7817, + n_estimators=2200, + reg_alpha=0.4640, + reg_lambda=0.8571, + subsample=0.5213, + silent=1, + random_state=7, + nthread=-1) +## lightGBM +model_lgb = lgb.LGBMRegressor( + objective='regression', + num_leaves=5, + learning_rate=0.05, + n_estimators=720, + max_bin=55, + bagging_fraction=0.8, + bagging_freq=5, + feature_fraction=0.2319, + feature_fraction_seed=9, + bagging_seed=9, + min_data_in_leaf=6, + min_sum_hessian_in_leaf=11) +## 对这些基本模型进行打分 +score = rmsle_cv(lasso) +print("\nLasso score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) +score = rmsle_cv(ENet) +print("ElasticNet score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) +score = rmsle_cv(KRR) +print( + "Kernel Ridge score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) +score = rmsle_cv(GBoost) +print("Gradient Boosting score: {:.4f} ({:.4f})\n".format(score.mean(), + score.std())) +score = rmsle_cv(model_xgb) +print("Xgboost score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) +score = rmsle_cv(model_lgb) +print("LGBM score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) +``` + + +```python +from sklearn.linear_model import Ridge +from sklearn.model_selection import learning_curve + +ridge = Ridge(alpha=0.1) + +train_sizes, train_loss, test_loss = learning_curve(ridge, x_train, y_train, cv=10, + scoring='neg_mean_squared_error', + train_sizes = [0.1, 0.3, 0.5, 0.7, 0.9 , 0.95, 1]) + +# 训练误差均值 +train_loss_mean = -np.mean(train_loss, axis = 1) +# 测试误差均值 +test_loss_mean = -np.mean(test_loss, axis = 1) + +# 绘制误差曲线 +plt.plot(train_sizes/len(x_train), train_loss_mean, 'o-', color = 'r', label = 'Training') +plt.plot(train_sizes/len(x_train), test_loss_mean, 'o-', color = 'g', label = 'Cross-Validation') + +plt.xlabel('Training data size') +plt.ylabel('Loss') +plt.legend(loc = 'best') +plt.show() +``` + + +![png](/img/competitions/getting-started/house-price/output_54_0.png) + + + +```python +mode_br = BaggingRegressor(base_estimator=ridge, n_estimators=10) +mode_br.fit(x_train, y_train) +y_test = np.expm1(mode_br.predict(x_test)) +``` + +## 四 建立模型 + +> 模型融合 voting + +```python +# 模型融合 +class AveragingModels(BaseEstimator, RegressorMixin, TransformerMixin): + def __init__(self, models): + self.models = models + + # we define clones of the original models to fit the data in + def fit(self, X, y): + self.models_ = [clone(x) for x in self.models] + + # Train cloned base models + for model in self.models_: + model.fit(X, y) + + return self + + # Now we do the predictions for cloned models and average them + def predict(self, X): + predictions = np.column_stack( + [model.predict(X) for model in self.models_]) + return np.mean(predictions, axis=1) + + +# 评价这四个模型的好坏 +averaged_models = AveragingModels(models=(ENet, GBoost, KRR, lasso)) +score = rmsle_cv(averaged_models) +print(" Averaged base models score: {:.4f} ({:.4f})\n".format(score.mean(), + score.std())) + +# 最终对模型的训练和预测 +# StackedRegressor +stacked_averaged_models.fit(train.values, y_train) +stacked_train_pred = stacked_averaged_models.predict(train.values) +stacked_pred = np.expm1(stacked_averaged_models.predict(test.values)) +print(rmsle(y_train, stacked_train_pred)) + +# XGBoost +model_xgb.fit(train, y_train) +xgb_train_pred = model_xgb.predict(train) +xgb_pred = np.expm1(model_xgb.predict(test)) +print(rmsle(y_train, xgb_train_pred)) +# lightGBM +model_lgb.fit(train, y_train) +lgb_train_pred = model_lgb.predict(train) +lgb_pred = np.expm1(model_lgb.predict(test.values)) +print(rmsle(y_train, lgb_train_pred)) +'''RMSE on the entire Train data when averaging''' + +print('RMSLE score on train data:') +print(rmsle(y_train, stacked_train_pred * 0.70 + xgb_train_pred * 0.15 + + lgb_train_pred * 0.15)) +# 模型融合的预测效果 +ensemble = stacked_pred * 0.70 + xgb_pred * 0.15 + lgb_pred * 0.15 +# 保存结果 +result = pd.DataFrame() +result['Id'] = test_ID +result['SalePrice'] = ensemble +# index=False 是用来除去行编号 +result.to_csv('/Users/liudong/Desktop/house_price/result.csv', index=False) +``` diff --git a/docs/Kaggle/competitions/getting-started/titanic/README.md b/docs/Kaggle/competitions/getting-started/titanic/README.md index 80ef2980..2e5167fd 100644 --- a/docs/Kaggle/competitions/getting-started/titanic/README.md +++ b/docs/Kaggle/competitions/getting-started/titanic/README.md @@ -33,42 +33,18 @@ 2.比较各个模型的分数,然后取效果较好的模型作为基础模型. 四. 模型融合 -1. Bagging: 同一模型的投票选举 -2. Boosting: 同一模型的再学习 -3. Voting: 不同模型的投票选举 -4. Stacking: 分层预测 – K-1份数据预测1份模型拼接,得到 预测结果*算法数(作为特征) => 从而预测最终结果 -5. Blending: 分层预测 – 将数据分成2部分(A部分训练B部分得到预测结果),得到 预测结果*算法数(作为特征) => 从而预测最终结果 -五. 参数优化 +五. 修改特征和模型参数 1.可以通过添加或者修改特征,提高模型的上限. 2.通过修改模型的参数,是模型逼近上限 ``` ## 一. 数据分析 -### 数据下载和观察 +### 数据下载和加载 * 数据集下载地址: -> 特征说明 - -| 特征 | 描述 | 值| -| - | - | - | -| PassengerId | 乘客ID | | -| Survived | 生存 | 0 = No, 1 = Yes | -| Pclass | 票类别-社会地位 | 1 = 1st, 2 = 2nd, 3 = 3rd | -| Name | 姓名 | | -| Sex | 性别 | | -| Age | 年龄 | | -| SibSp | 兄弟姐妹/配偶 | | -| Parch | 父母/孩子的数量 | | -| Ticket | 票号 | | -| Fare | 乘客票价 | | -| Cabin | 客舱号码 | | -| Embarked | 登船港口 | C=Cherbourg, Q=Queenstown, S=Southampton | - -### 特征详情 - ```python # 导入相关数据包 import numpy as np @@ -85,16 +61,32 @@ train = pd.read_csv('%s/%s' % (root_path, 'train.csv')) test = pd.read_csv('%s/%s' % (root_path, 'test.csv')) ``` +### 特征说明 + +| 特征 | 描述 | 值| +| - | - | - | +| survival | 生存 | 0 = No, 1 = Yes | +| pclass | 票类别-社会地位 | 1 = 1st, 2 = 2nd, 3 = 3rd | +| sex | 性别 | | +| Age | 年龄 | | +| sibsp | 兄弟姐妹/配偶 | | +| parch | 父母/孩子的数量 | | +| ticket | 票号 | | +| fare | 乘客票价 | | +| cabin | 客舱号码 | | +| embarked | 登船港口 | C=Cherbourg, Q=Queenstown, S=Southampton | + +### 特征详情 + ```python train.head(5) ``` ![](/img/competitions/getting-started/titanic/titanic_top_5.jpg) -```py ->>> # 返回每列列名,该列非nan值个数,以及该列类型 ->>> train.info() ->>> # test.info() +```python +# 返回每列列名,该列非nan值个数,以及该列类型 +train.info() RangeIndex: 891 entries, 0 to 890 @@ -115,27 +107,39 @@ dtypes: float64(2), int64(5), object(5) memory usage: 83.6+ KB ``` -```py ->>> # 返回数值型变量的统计量 ->>> # train.describe(percentiles=[0.00, 0.25, 0.5, 0.75, 1.00]) ->>> print(titanic.describe()) - PassengerId Survived Pclass Age SibSp Parch Fare -count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000 -mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208 -std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429 -min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000 -25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400 -50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200 -75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000 -max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200 +```python +test.info() + + +RangeIndex: 418 entries, 0 to 417 +Data columns (total 11 columns): +PassengerId 418 non-null int64 +Pclass 418 non-null int64 +Name 418 non-null object +Sex 418 non-null object +Age 332 non-null float64 +SibSp 418 non-null int64 +Parch 418 non-null int64 +Ticket 418 non-null object +Fare 417 non-null float64 +Cabin 91 non-null object +Embarked 418 non-null object +dtypes: float64(2), int64(4), object(5) +memory usage: 36.0+ KB ``` -## 二. 特征工程 +```python +# 返回数值型变量的统计量 +# train.describe(percentiles=[0.00, 0.25, 0.5, 0.75, 1.00]) +train.describe() +``` -### 特征处理 +![](/img/competitions/getting-started/titanic/titanic_train_desc.jpg) +### 特征分析(统计学与绘图) 目的:初步了解数据之间的相关性,为构造特征工程以及模型建立做准备 + ```python # 存活人数 train['Survived'].value_counts() @@ -143,134 +147,623 @@ train['Survived'].value_counts() 0 549 1 342 Name: Survived, dtype: int64 +``` +> 1)数值型数据协方差,corr()函数 -# 对缺失值处理(Age 中位数不错) -titanic["Age"] = titanic["Age"].fillna(titanic["Age"].median()) -titanic["Fare"] = titanic["Fare"].fillna(titanic["Fare"].median()) +来个总览,快速了解个数据的相关性 +```python +# 相关性协方差表,corr()函数,返回结果接近0说明无相关性,大于0说明是正相关,小于0是负相关. +train_corr = train.drop('PassengerId',axis=1).corr() +train_corr +``` -# 对文本特征进行处理(性别, 登船港口) -print(titanic["Sex"].unique()) -titanic.loc[titanic["Sex"]=="male", "Sex"] = 0 -titanic.loc[titanic["Sex"]=="female", "Sex"] = 1 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SurvivedPclassAgeSibSpParchFare
Survived1.000000-0.338481-0.077221-0.0353220.0816290.257307
Pclass-0.3384811.000000-0.3692260.0830810.018443-0.549500
Age-0.077221-0.3692261.000000-0.308247-0.1891190.096067
SibSp-0.0353220.083081-0.3082471.0000000.4148380.159651
Parch0.0816290.018443-0.1891190.4148381.0000000.216225
Fare0.257307-0.5495000.0960670.1596510.2162251.000000
+
-# 组合特征(特征组合相关性变差了) -# titanic["FamilySize"] = titanic["SibSp"] + titanic["Parch"] +```python +# 画出相关性热力图 +a = plt.subplots(figsize=(15,9))#调整画布大小 +a = sns.heatmap(train_corr, vmin=-1, vmax=1 , annot=True , square=True)#画热力图 +``` + +![png](/img/competitions/getting-started/titanic/titanic_corr_analysis.png) + +> 2)各个数据与结果的关系 -# S的概率最大,当然我们也可以按照概率随机算,都可以 -print(titanic["Embarked"].unique()) -""" -titanic[["Embarked"]].groupby("Embarked").agg({"Embarked": "count"}) - Embarked -Embarked -C 168 -Q 77 -S 644 -""" -titanic["Embarked"] = titanic["Embarked"].fillna('S') -titanic.loc[titanic["Embarked"] == "S", "Embarked"] = 0 -titanic.loc[titanic["Embarked"] == "C", "Embarked"] = 1 -titanic.loc[titanic["Embarked"] == "Q", "Embarked"] = 2 +进一步探索分析各个数据与结果的关系 +* ① Pclass,乘客等级,1是最高级 -def get_title(name): - # 名字的尊称 - title_search = re.search(' ([A-Za-z]+)\.', name) - if title_search: - return title_search.group(1) - return "" -titles = titanic["Name"].apply(get_title) -# print(pandas.value_counts(titles)) -# 对尊称建立mapping字典 -# 在数据的Name项中包含了对该乘客的称呼,如Mr、Miss等,这些信息包含了乘客的年龄、性别、也有可能包含社会地位,如Dr、Lady、Major、Master等称呼。这一项不方便用图表展示,但是在特征工程中,我们会将其提取出来,然后放到模型中。 -# 剩余因素还有船票价格、船舱号和船票号,这三个因素都可能会影响乘客在船中的位置从而影响逃生顺序,但是因为这三个因素与生存之间看不出明显规律,所以在后期模型融合时,将这些因素交给模型来决定其重要性。 -title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Dr": 5, "Rev": 6, "Major": 7, "Col": 7, "Mlle": 8, "Mme": 8, "Don": 9, "Dona": 9, "Lady": 10, "Countess": 10, "Jonkheer": 10, "Sir": 9, "Capt": 7, "Ms": 2} -for k, v in title_mapping.items(): - titles[titles == k] = v -# print(pd.value_counts(titles)) +结果分析:可以看出Survived和Pclass在Pclass=1的时候有较强的相关性(>0.5),所以最终模型中包含该特征。 +```python +train.groupby(['Pclass'])['Pclass','Survived'].mean() +``` -# 添加一个新特征表示拥护尊称 -titanic["Title"] = [int(i) for i in titles.values.tolist()] -# 添加一个新特征表示名字长度 -titanic["NameLength"] = titanic["Name"].apply(lambda x: len(x)) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PclassSurvived
Pclass
11.00.629630
22.00.472826
33.00.242363
+
-# 相关性太差,删除 -# titanic.drop(['PassengerId'], axis=1,inplace=True) -titanic.drop(['Cabin'], axis=1,inplace=True) -titanic.drop(['SibSp'], axis=1,inplace=True) -# titanic.drop(['Parch'],axis=1,inplace=True) -titanic.drop(['Ticket'], axis=1,inplace=True) -titanic.drop(['Name'], axis=1,inplace=True) +```python +train[['Pclass','Survived']].groupby(['Pclass']).mean().plot.bar() + + ``` -### 特征相关性 +![png](/img/competitions/getting-started/titanic/titanic_pclass_bar.png) -> 1)数值型数据协方差 corr()函数 +* ② Sex,性别 -来个总览,快速了解个数据的相关性 +结果分析:女性有更高的活下来的概率(74%),保留该特征 ```python -# 相关性协方差表,corr()函数,返回结果接近0说明无相关性,大于0说明是正相关,小于0是负相关. -train_corr = train.corr() -train_corr +train.groupby(['Sex'])['Sex','Survived'].mean() ``` -| 相关性 | Survived | Pclass | Sex | Age | Parch | Fare | Embarked | Title | NameLength | -| ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | -| Survived | 1.000000 | -0.338481 | 0.543351 | -0.064910 | 0.081629 | 0.257307 | 0.106811 | 0.354072 | 0.332350 | -| Pclass | -0.338481 | 1.000000 | -0.131900 | -0.339898 | 0.018443 | -0.549500 | 0.045702 | -0.211552 | -0.220001 | -| Sex | 0.543351 | -0.131900 | 1.000000 | -0.081163 | 0.245489 | 0.182333 | 0.116569 | 0.419760 | 0.448759 | -| Age | -0.064910 | -0.339898 | -0.081163 | 1.000000 | -0.172482 | 0.096688 | -0.009165 | -0.037174 | 0.039702 | -| Parch | 0.081629 | 0.018443 | 0.245489 | -0.172482 | 1.000000 | 0.216225 | -0.078665 | 0.235164 | 0.252282 | -| Fare | 0.257307 | -0.549500 | 0.182333 | 0.096688 | 0.216225 | 1.000000 | 0.062142 | 0.122872 | 0.155832 | -| Embarked | 0.106811 | 0.045702 | 0.116569 | -0.009165 | -0.078665 | 0.062142 | 1.000000 | 0.055788 | -0.107749 | -| Title | 0.354072 | -0.211552 | 0.419760 | -0.037174 | 0.235164 | 0.122872 | 0.055788 | 1.000000 | 0.436099 | -| NameLength | 0.332350 | -0.220001 | 0.448759 | 0.039702 | 0.252282 | 0.155832 | -0.107749 | 0.436099 | 1.000000 | +
+ + + + + + + + + + + + + + + + + + + + + +
Survived
Sex
female0.742038
male0.188908
+
```python -# 画出相关性热力图 -a = plt.subplots(figsize=(15,9))#调整画布大小 -a = sns.heatmap(train_corr, vmin=-1, vmax=1 , annot=True , square=True)#画热力图 +train[['Sex','Survived']].groupby(['Sex']).mean().plot.bar() + + ``` -![png](/img/competitions/getting-started/titanic/titanic_corr_analysis.png) +![png](/img/competitions/getting-started/titanic/titanic_sex_bar.png) +* ③ SibSp and Parch 兄妹配偶数/父母子女数 -### 特征标准化和降维 +结果分析:这些特征与特定的值没有相关性不明显,最好是由这些独立的特征派生出一个新特征或者一组新特征 -* 数据标准化 +```python +train[['SibSp','Survived']].groupby(['SibSp']).mean() +``` -1. 线性模型需要用标准化的数据建模, 而树类模型不需要标准化的数据 -2. 处理标准化的时候,注意将测试集的数据transform到test集上 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Survived
SibSp
00.345395
10.535885
20.464286
30.250000
40.166667
50.000000
80.000000
+
+ +```python +train[['Parch','Survived']].groupby(['Parch']).mean().plot.bar() + + +``` + +![png](/img/competitions/getting-started/titanic/titanic_parch_bar.png) + +* ④ Age年龄与生存情况的分析. + +结果分析:由图,可以看到年龄是影响生存情况的. + +但是年龄是有大部分缺失值的,缺失值需要进行处理,可以使用填充或者模型预测. + +```python +g = sns.FacetGrid(train, col='Survived',size=5) +g.map(plt.hist, 'Age', bins=40) + + +``` + +![png](/img/competitions/getting-started/titanic/titanic_age_map.png) -```py -def do_FeatureEngineering(data, COMPONENT_NUM=0.9): - # scale values 对一化 - scaler = preprocessing.StandardScaler() - s_data = scaler.fit_transform(data) - return s_data +```python +train.groupby(['Age'])['Survived'].mean().plot() + + +``` + +![png](/img/competitions/getting-started/titanic/titanic_age_axes.png) + +* ⑤ Embarked登港港口与生存情况的分析 + +结果分析:C地的生存率更高,这个也应该保留为模型特征. + +```python +sns.countplot('Embarked',hue='Survived',data=train) + + +``` - # # 降维(不降维,准确率还上升了) - # ''' - # 使用说明:https://www.cnblogs.com/pinard/p/6243025.html - # n_components>=1 - # n_components=NUM 设置占特征数量比 - # 0 < n_components < 1 - # n_components=0.99 设置阈值总方差占比 - # ''' - # pca = PCA(n_components=COMPONENT_NUM, whiten=False) - # pca.fit(s_data) # Fit the model with X - # pca_data = pca.transform(s_data) # Fit the model with X and 在X上完成降维. +![png](/img/competitions/getting-started/titanic/titanic_embarked_count.png) + +* ⑥ 其他因素 + +在数据的Name项中包含了对该乘客的称呼,如Mr、Miss等,这些信息包含了乘客的年龄、性别、也有可能包含社会地位,如Dr、Lady、Major、Master等称呼。这一项不方便用图表展示,但是在特征工程中,我们会将其提取出来,然后放到模型中。 + +剩余因素还有船票价格、船舱号和船票号,这三个因素都可能会影响乘客在船中的位置从而影响逃生顺序,但是因为这三个因素与生存之间看不出明显规律,所以在后期模型融合时,将这些因素交给模型来决定其重要性。 + +## 二. 特征工程 + +```python +#先将数据集合并,一起做特征工程(注意,标准化的时候需要分开处理) +#先将test补齐,然后通过pd.apped()合并 +test['Survived'] = 0 +train_test = train.append(test) +``` - # # pca 方差大小、方差占比、特征数量 - # # print("方差大小:\n", pca.explained_variance_, "方差占比:\n", pca.explained_variance_ratio_) - # print("特征数量: %s" % pca.n_components_) - # print("总方差占比: %s" % sum(pca.explained_variance_ratio_)) +### 特征处理 + +* ① Pclass,乘客等级,1是最高级 + +两种方式:一是该特征不做处理,可以直接保留.二是再处理:也进行分列处理(比较那种方式模型效果更好,就选那种) + +```python +train_test = pd.get_dummies(train_test,columns=['Pclass']) +``` + +* ② Sex,性别¶ +无缺失值,直接分列 + +```python +train_test = pd.get_dummies(train_test,columns=["Sex"]) +``` + +* ③ SibSp and Parch 兄妹配偶数/父母子女数 + +第一次直接保留:这两个都影响生存率,且都是数值型,先直接保存. + +第二次进行两项求和,并进行分列处理.(兄妹配偶数和父母子女数都是认识人的数量,所以总数可能也会更好)(模型结果提高到了) + +```python +#这是剑豪模型后回来添加的新特征,模型的分数最终有所提高了. +train_test['SibSp_Parch'] = train_test['SibSp'] + train_test['Parch'] +``` - # return pca_data +```python +train_test = pd.get_dummies(train_test,columns = ['SibSp','Parch','SibSp_Parch']) +``` + +* ④ Embarked +数据有极少量(3个)缺失值,但是在分列的时候,缺失值的所有列可以均为0,所以可以考虑不填充. + +另外,也可以考虑用测试集众数来填充.先找出众数,再采用df.fillna()方法 + +```python +train_test = pd.get_dummies(train_test,columns=["Embarked"]) +``` + +* ⑤ Name + +1.在数据的Name项中包含了对该乘客的称呼,将这些关键词提取出来,然后做分列处理.(参考别人的) + +```python +#从名字中提取出称呼: df['Name].str.extract()是提取函数,配合正则一起使用 +train_test['Name1'] = train_test['Name'].str.extract('.+,(.+)', expand=False).str.extract('^(.+?)\.', expand=False).str.strip() +``` + +```python +#将姓名分类处理() +train_test['Name1'].replace(['Capt', 'Col', 'Major', 'Dr', 'Rev'], 'Officer' , inplace = True) +train_test['Name1'].replace(['Jonkheer', 'Don', 'Sir', 'the Countess', 'Dona', 'Lady'], 'Royalty' , inplace = True) +train_test['Name1'].replace(['Mme', 'Ms', 'Mrs'], 'Mrs') +train_test['Name1'].replace(['Mlle', 'Miss'], 'Miss') +train_test['Name1'].replace(['Mr'], 'Mr' , inplace = True) +train_test['Name1'].replace(['Master'], 'Master' , inplace = True) +``` + +```python +#分列处理 +train_test = pd.get_dummies(train_test,columns=['Name1']) +``` + +2. 从姓名中提取出姓做特征 + +```python +#从姓名中提取出姓 +train_test['Name2'] = train_test['Name'].apply(lambda x: x.split('.')[1]) + +#计算数量,然后合并数据集 +Name2_sum = train_test['Name2'].value_counts().reset_index() +Name2_sum.columns=['Name2','Name2_sum'] +train_test = pd.merge(train_test,Name2_sum,how='left',on='Name2') + +#由于出现一次时该特征时无效特征,用one来代替出现一次的姓 +train_test.loc[train_test['Name2_sum'] == 1 , 'Name2_new'] = 'one' +train_test.loc[train_test['Name2_sum'] > 1 , 'Name2_new'] = train_test['Name2'] +del train_test['Name2'] + +#分列处理 +train_test = pd.get_dummies(train_test,columns=['Name2_new']) +``` + +```python +#删掉姓名这个特征 +del train_test['Name'] +``` + +* ⑥ Fare + +该特征有缺失值,先找出缺失值的那调数据,然后用平均数填充 + +```python +#从上面的分析,发现该特征train集无miss值,test有一个缺失值,先查看 +train_test.loc[train_test["Fare"].isnull()] +``` + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AgeCabinFarePassengerIdSurvivedTicketPclass_1Pclass_2Pclass_3Sex_female...Name2_new_ Thomas HenryName2_new_ VictorName2_new_ WashingtonName2_new_ WilliamName2_new_ William EdwardName2_new_ William HenryName2_new_ William JamesName2_new_ William JohnName2_new_ William ThomasName2_new_one
104360.5NaNNaN1044037010010...0000000000
+

1 rows × 137 columns

+
+ +```python +#票价与pclass和Embarked有关,所以用train分组后的平均数填充 +train.groupby(by=["Pclass","Embarked"]).Fare.mean() + +Pclass Embarked +1 C 104.718529 + Q 90.000000 + S 70.364862 +2 C 25.358335 + Q 12.350000 + S 20.327439 +3 C 11.214083 + Q 11.183393 + S 14.644083 +Name: Fare, dtype: float64 +``` + +```python +#用pclass=3和Embarked=S的平均数14.644083来填充 +train_test["Fare"].fillna(14.435422,inplace=True) +``` + +* ⑦ Ticket + +该列和名字做类似的处理,先提取,然后分列 + +```python +#将Ticket提取字符列 +#str.isnumeric() 如果S中只有数字字符,则返回True,否则返回False +train_test['Ticket_Letter'] = train_test['Ticket'].str.split().str[0] +train_test['Ticket_Letter'] = train_test['Ticket_Letter'].apply(lambda x:np.nan if x.isnumeric() else x) +train_test.drop('Ticket',inplace=True,axis=1) +``` + +```python +#分列,此时nan值可以不做处理 +train_test = pd.get_dummies(train_test,columns=['Ticket_Letter'],drop_first=True) +``` + +* ⑧ Age + +1. 该列有大量缺失值,考虑用一个回归模型进行填充. +2. 在模型修改的时候,考虑到年龄缺失值可能影响死亡情况,用年龄是否缺失值来构造新特征 + +```python +"""这是模型就好后回来增加的新特征 +考虑年龄缺失值可能影响死亡情况,数据表明,年龄缺失的死亡率为0.19.""" +train_test.loc[train_test["Age"].isnull()]['Survived'].mean() + +0.19771863117870722 +``` + +```python +# 所以用年龄是否缺失值来构造新特征 +train_test.loc[train_test["Age"].isnull() ,"age_nan"] = 1 +train_test.loc[train_test["Age"].notnull() ,"age_nan"] = 0 +train_test = pd.get_dummies(train_test,columns=['age_nan']) +``` + +利用其他组特征量,采用机器学习算法来预测Age + +```python +train_test.info() + + +Int64Index: 1309 entries, 0 to 1308 +Columns: 187 entries, Age to age_nan_1.0 +dtypes: float64(2), int64(3), object(1), uint8(181) +memory usage: 343.0+ KB +``` + +```python +#创建没有['Age','Survived']的数据集 +missing_age = train_test.drop(['Survived','Cabin'],axis=1) +#将Age完整的项作为训练集、将Age缺失的项作为测试集。 +missing_age_train = missing_age[missing_age['Age'].notnull()] +missing_age_test = missing_age[missing_age['Age'].isnull()] +``` + +```python +#构建训练集合预测集的X和Y值 +missing_age_X_train = missing_age_train.drop(['Age'], axis=1) +missing_age_Y_train = missing_age_train['Age'] +missing_age_X_test = missing_age_test.drop(['Age'], axis=1) +``` + +```python +# 先将数据标准化 +from sklearn.preprocessing import StandardScaler +ss = StandardScaler() +#用测试集训练并标准化 +ss.fit(missing_age_X_train) +missing_age_X_train = ss.transform(missing_age_X_train) +missing_age_X_test = ss.transform(missing_age_X_test) +``` + +```python +#使用贝叶斯预测年龄 +from sklearn import linear_model +lin = linear_model.BayesianRidge() +``` + +```python +lin.fit(missing_age_X_train,missing_age_Y_train) + +BayesianRidge(alpha_1=1e-06, alpha_2=1e-06, compute_score=False, copy_X=True, + fit_intercept=True, lambda_1=1e-06, lambda_2=1e-06, n_iter=300, + normalize=False, tol=0.001, verbose=False) +``` + +```python +#利用loc将预测值填入数据集 +train_test.loc[(train_test['Age'].isnull()), 'Age'] = lin.predict(missing_age_X_test) +``` + +```python +#将年龄划分是个阶段10以下,10-18,18-30,30-50,50以上 +train_test['Age'] = pd.cut(train_test['Age'], bins=[0,10,18,30,50,100],labels=[1,2,3,4,5]) + +train_test = pd.get_dummies(train_test,columns=['Age']) +``` + +* ⑨ Cabin + +cabin项缺失太多,只能将有无Cain首字母进行分类,缺失值为一类,作为特征值进行建模,也可以考虑直接舍去该特征 + +```python +#cabin项缺失太多,只能将有无Cain首字母进行分类,缺失值为一类,作为特征值进行建模 +train_test['Cabin_nan'] = train_test['Cabin'].apply(lambda x:str(x)[0] if pd.notnull(x) else x) +train_test = pd.get_dummies(train_test,columns=['Cabin_nan']) +``` + +```python +#cabin项缺失太多,只能将有无Cain首字母进行分类, +train_test.loc[train_test["Cabin"].isnull() ,"Cabin_nan"] = 1 +train_test.loc[train_test["Cabin"].notnull() ,"Cabin_nan"] = 0 +train_test = pd.get_dummies(train_test,columns=['Cabin_nan']) +train_test.drop('Cabin',axis=1,inplace=True) +``` + +* ⑩ 特征工程处理完了,划分数据集 + +```python +train_data = train_test[:891] +test_data = train_test[891:] +train_data_X = train_data.drop(['Survived'],axis=1) +train_data_Y = train_data['Survived'] +test_data_X = test_data.drop(['Survived'],axis=1) +``` + +### 数据规约 + +1. 线性模型需要用标准化的数据建模,而树类模型不需要标准化的数据 +2. 处理标准化的时候,注意将测试集的数据transform到test集上 + +```python +from sklearn.preprocessing import StandardScaler +ss2 = StandardScaler() +ss2.fit(train_data_X) +train_data_X_sd = ss2.transform(train_data_X) +test_data_X_sd = ss2.transform(test_data_X) ``` @@ -278,152 +771,185 @@ def do_FeatureEngineering(data, COMPONENT_NUM=0.9): ### 模型发现 -1. 可选单个模型模型有逻辑回归, 随机森林, svm, xgboost, gbdt等. +1. 可选单个模型模型有随机森林,逻辑回归,svm,xgboost,gbdt等. 2. 也可以将多个模型组合起来,进行模型融合,比如voting,stacking等方法 3. 好的特征决定模型上限,好的模型和参数可以无线逼近上限. 4. 我测试了多种模型,模型结果最高的随机森林,最高有0.8. ### 构建模型 -```py -# 0.8069524400247253 [0.79329609 0.81564246 0.8258427 0.80337079 0.79661017] -model = LogisticRegression(random_state=1) - -# 0.8272091118939124 [0.82122905 0.80446927 0.84831461 0.82022472 0.84180791] -model = RandomForestClassifier(random_state=1, n_estimators=100, min_samples_split=4, min_samples_leaf=2) - -# 0.822670577600365 [0.82681564 0.82122905 0.83146067 0.80898876 0.82485876] -model = RandomForestClassifier(random_state=1, n_estimators=50, min_samples_split=8, min_samples_leaf=4) - -# 0.8294499549079417 [0.82122905 0.80446927 0.86516854 0.82022472 0.83615819] -model = XGBClassifier(n_estimators=196, max_depth=4, learning_rate=0.03) -``` - -## 四. 模型融合 - -```py -print("模型融合") -""" -Bagging: 同一模型的投票选举 -Boosting: 同一模型的再学习 -Voting: 不同模型的投票选举 -Stacking: 分层预测 – K-1份数据预测1份模型拼接,得到 预测结果*算法数(作为特征) => 从而预测最终结果 -Blending: 分层预测 – 将数据分成2部分(A部分训练B部分得到预测结果),得到 预测结果*算法数(作为特征) => 从而预测最终结果 -""" -# 1. Bagging 算法实现 -# 0.8691726623564537 [0.86179183 0.82700922 0.8855615 0.87700535 0.89449541] -model = RandomForestClassifier(random_state=1, n_estimators=100, min_samples_split=4, min_samples_leaf=2) - -# 2. Boosting 算法实现 -# 0.8488710896477386 [0.8198946 0.82285903 0.87780749 0.84906417 0.87473017] -model = AdaBoostClassifier(random_state=1, n_estimators=100, learning_rate=1) - -# 3. Voting -# 0.8695399796790022 [0.87259552 0.8370224 0.87433155 0.86885027 0.89490016] -model = VotingClassifier( - estimators=[ - ('log_clf', LogisticRegression()), - ('ab_clf', AdaBoostClassifier()), - ('svm_clf', SVC(probability=True)), - ('rf_clf', RandomForestClassifier()), - ('gbdt_clf', GradientBoostingClassifier()), - ('rb_clf', AdaBoostClassifier()) - ], voting='soft') # , voting='hard') -scores = cross_val_score(model, trainData, trainLabel, cv=5, scoring='roc_auc') -print(scores.mean(), "\n", scores) - -# 4. Stacking -# 0.8713813265814722 [0.87747036 0.83886693 0.86590909 0.87085561 0.90380464] -clfs = [ - AdaBoostClassifier(), - SVC(probability=True), - AdaBoostClassifier(), - LogisticRegression(C=0.1,max_iter=100), - XGBClassifier(max_depth=6,n_estimators=100,num_round = 5), - RandomForestClassifier(n_estimators=100,max_depth=6,oob_score=True), - GradientBoostingClassifier(learning_rate=0.3,max_depth=6,n_estimators=100) -] - -kf = KFold(n_splits=5, shuffle=True, random_state=1) +> 随机森林 -# 创建零矩阵 -dataset_stacking_train = np.zeros((trainData.shape[0], len(clfs))) -# dataset_stacking_label = np.zeros((trainLabel.shape[0], len(clfs))) +```python +from sklearn.ensemble import RandomForestClassifier -for j, clf in enumerate(clfs): - '''依次训练各个单模型''' - for i,(train, test) in enumerate(kf.split(trainLabel)): - '''使用第i个部分作为预测,剩余的部分来训练模型,获得其预测的输出作为第i部分的新特征。''' - # print("Fold", i) - X_train, y_train, X_test, y_test = trainData[train], trainLabel[train], trainData[test], trainLabel[test] - clf.fit(X_train, y_train) - y_submission = clf.predict_proba(X_test)[:, 1] +rf = RandomForestClassifier(n_estimators=150,min_samples_leaf=3,max_depth=6,oob_score=True) +rf.fit(train_data_X,train_data_Y) - # j 表示每一次的算法,而 test是交叉验证得到的每一行(也就是每一个算法把测试机和都预测了一遍) - dataset_stacking_train[test, j] = y_submission - -# 用建立第二层模型 -model = LogisticRegression(C=0.1, max_iter=100) -model.fit(dataset_stacking_train, trainLabel) - -scores = cross_val_score(model, dataset_stacking_train, trainLabel, cv=5, scoring='roc_auc') -print(scores.mean(), "\n", scores) - -# 5. Blending -# 0.8838950287185581 [0.87584416 0.91064935 0.89714286 0.85294118 0.8828976 ] -clfs = [ - AdaBoostClassifier(), - SVC(probability=True), - AdaBoostClassifier(), - LogisticRegression(C=0.1,max_iter=100), - XGBClassifier(max_depth=6,n_estimators=100,num_round = 5), - RandomForestClassifier(n_estimators=100,max_depth=6,oob_score=True), - GradientBoostingClassifier(learning_rate=0.3,max_depth=6,n_estimators=100) -] -X_d1, X_d2, y_d1, y_d2 = train_test_split(trainData, trainLabel, test_size=0.5, random_state=2017) -dataset_d1 = np.zeros((X_d2.shape[0], len(clfs))) -dataset_d2 = np.zeros((trainLabel.shape[0], len(clfs))) +test["Survived"] = rf.predict(test_data_X) +RF = test[['PassengerId','Survived']].set_index('PassengerId') +RF.to_csv('RF.csv') +``` -for j, clf in enumerate(clfs): - #依次训练各个单模型 - # 对于测试集,直接用这k个模型的预测值作为新的特征。 - clf.fit(X_d1, y_d1) - dataset_d1[:, j] = clf.predict_proba(X_d2)[:, 1] +```python +# 随机森林是随机选取特征进行建模的,所以每次的结果可能都有点小差异 +# 如果分数足够好,可以将该模型保存起来,下次直接调出来使用0.81339 'rf10.pkl' +from sklearn.externals import joblib +joblib.dump(rf, 'rf10.pkl') +``` -# 用建立第二层模型 -model = LogisticRegression(C=0.1, max_iter=100) -model.fit(dataset_d1, y_d2) +> LogisticRegression + +```python +from sklearn.linear_model import LogisticRegression +from sklearn.grid_search import GridSearchCV + +lr = LogisticRegression() +param = {'C':[0.001,0.01,0.1,1,10], "max_iter":[100,250]} +clf = GridSearchCV(lr, param,cv=5, n_jobs=-1, verbose=1, scoring="roc_auc") +clf.fit(train_data_X_sd, train_data_Y) + +# 打印参数的得分情况 +clf.grid_scores_ +# 打印最佳参数 +clf.best_params_ + +# 将最佳参数传入训练模型 +lr = LogisticRegression(clf.best_params_) +lr.fit(train_data_X_sd, train_data_Y) + +# 输出结果 +test["Survived"] = lr.predict(test_data_X_sd) +test[['PassengerId', 'Survived']].set_index('PassengerId').to_csv('LS5.csv') +``` + +> SVM + +```python +from sklearn import svm +svc = svm.SVC() + +clf = GridSearchCV(svc,param,cv=5,n_jobs=-1,verbose=1,scoring="roc_auc") +clf.fit(train_data_X_sd,train_data_Y) + +clf.best_params_ + +svc = svm.SVC(C=1,max_iter=250) + +# 训练模型并预测结果 +svc.fit(train_data_X_sd,train_data_Y) +svc.predict(test_data_X_sd) + +# 打印结果 +test["Survived"] = svc.predict(test_data_X_sd) +SVM = test[['PassengerId','Survived']].set_index('PassengerId') +SVM.to_csv('svm1.csv') +``` -scores = cross_val_score(model, dataset_d1, y_d2, cv=5, scoring='roc_auc') -print(scores.mean(), "\n", scores) +> GBDT + +```python +from sklearn.ensemble import GradientBoostingClassifier + +gbdt = GradientBoostingClassifier(learning_rate=0.7,max_depth=6,n_estimators=100,min_samples_leaf=2) + +gbdt.fit(train_data_X,train_data_Y) + +test["Survived"] = gbdt.predict(test_data_X) +test[['PassengerId','Survived']].set_index('PassengerId').to_csv('gbdt3.csv') +``` + +> xgboost + +```python +import xgboost as xgb + +xgb_model = xgb.XGBClassifier(n_estimators=150,min_samples_leaf=3,max_depth=6) +xgb_model.fit(train_data_X,train_data_Y) + +test["Survived"] = xgb_model.predict(test_data_X) +XGB = test[['PassengerId','Survived']].set_index('PassengerId') +XGB.to_csv('XGB5.csv') +``` + +## 四 建立模型 + +> 模型融合 voting + +```python +from sklearn.ensemble import VotingClassifier + +from sklearn.linear_model import LogisticRegression +lr = LogisticRegression(C=0.1,max_iter=100) + +import xgboost as xgb +xgb_model = xgb.XGBClassifier(max_depth=6,min_samples_leaf=2,n_estimators=100,num_round = 5) + +from sklearn.ensemble import RandomForestClassifier +rf = RandomForestClassifier(n_estimators=200,min_samples_leaf=2,max_depth=6,oob_score=True) + +from sklearn.ensemble import GradientBoostingClassifier +gbdt = GradientBoostingClassifier(learning_rate=0.1,min_samples_leaf=2,max_depth=6,n_estimators=100) + +vot = VotingClassifier(estimators=[('lr', lr), ('rf', rf),('gbdt',gbdt),('xgb',xgb_model)], voting='hard') +vot.fit(train_data_X_sd,train_data_Y) + +test["Survived"] = vot.predict(test_data_X_sd) +test[['PassengerId','Survived']].set_index('PassengerId').to_csv('vot5.csv') ``` -## 五. 参数优化 +> 模型融合 stacking -```py -from sklearn.model_selection import GridSearchCV -param_test = { - # 'n_estimators': np.arange(190, 240, 2), - # 'max_depth': np.arange(4, 7, 1), - # 'learning_rate': np.array([0.01, 0.03, 0.05, 0.08, 0.1, 0.15, 0.2]), - 'n_estimators': np.array([196]), - 'max_depth': np.array([4]), - 'learning_rate': np.array([0.01, 0.02, 0.03, 0.04, 0.05]), - # 'min_child_weight': np.arange(1, 6, 2), - # 'C': (1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9) -} +```python +# 划分train数据集,调用代码,把数据集名字转成和代码一样 +X = train_data_X_sd +X_predict = test_data_X_sd +y = train_data_Y + +'''模型融合中使用到的各个单模型''' +from sklearn.linear_model import LogisticRegression +from sklearn import svm +import xgboost as xgb +from sklearn.ensemble import RandomForestClassifier +from sklearn.ensemble import GradientBoostingClassifier + +clfs = [LogisticRegression(C=0.1,max_iter=100), + xgb.XGBClassifier(max_depth=6,n_estimators=100,num_round = 5), + RandomForestClassifier(n_estimators=100,max_depth=6,oob_score=True), + GradientBoostingClassifier(learning_rate=0.3,max_depth=6,n_estimators=100)] + +# 创建n_folds +from sklearn.cross_validation import StratifiedKFold +n_folds = 5 +skf = list(StratifiedKFold(y, n_folds)) + +# 创建零矩阵 +dataset_blend_train = np.zeros((X.shape[0], len(clfs))) +dataset_blend_test = np.zeros((X_predict.shape[0], len(clfs))) -# 0.8294499549079417 [0.82122905 0.80446927 0.86516854 0.82022472 0.83615819] -model = XGBClassifier() -grid_search = GridSearchCV(estimator=model, param_grid=param_test, scoring='roc_auc', cv=5) -grid_search.fit(trainData, trainLabel) -print("最优得分 >>>", grid_search.best_score_) -print("最优参数 >>>", grid_search.best_params_) +# 建立模型 +for j, clf in enumerate(clfs): + '''依次训练各个单模型''' + # print(j, clf) + dataset_blend_test_j = np.zeros((X_predict.shape[0], len(skf))) + for i, (train, test) in enumerate(skf): + '''使用第i个部分作为预测,剩余的部分来训练模型,获得其预测的输出作为第i部分的新特征。''' + # print("Fold", i) + X_train, y_train, X_test, y_test = X[train], y[train], X[test], y[test] + clf.fit(X_train, y_train) + y_submission = clf.predict_proba(X_test)[:, 1] + dataset_blend_train[test, j] = y_submission + dataset_blend_test_j[:, i] = clf.predict_proba(X_predict)[:, 1] + '''对于测试集,直接用这k个模型的预测值均值作为新的特征。''' + dataset_blend_test[:, j] = dataset_blend_test_j.mean(1) -# 0.8685305085155506 [0.85770751 0.82002635 0.89632353 0.87018717 0.89840799] -model = XGBClassifier(n_estimators=196, max_depth=4, learning_rate=0.03) +# 用建立第二层模型 +clf2 = LogisticRegression(C=0.1,max_iter=100) +clf2.fit(dataset_blend_train, y) +y_submission = clf2.predict_proba(dataset_blend_test)[:, 1] -scores = cross_val_score(model, trainData, trainLabel, cv=5, scoring='roc_auc') -print(scores.mean(), "\n", scores) +test = pd.read_csv("test.csv") +test["Survived"] = clf2.predict(dataset_blend_test) +test[['PassengerId','Survived']].set_index('PassengerId').to_csv('stack3.csv') ``` diff --git a/docs/Kaggle/competitions/getting-started/titanic/titanic-data-science-solutions.md b/docs/Kaggle/competitions/getting-started/titanic/titanic-data-science-solutions.md index e3e13bed..324437f2 100644 --- a/docs/Kaggle/competitions/getting-started/titanic/titanic-data-science-solutions.md +++ b/docs/Kaggle/competitions/getting-started/titanic/titanic-data-science-solutions.md @@ -1033,7 +1033,7 @@ g.map(plt.hist, 'Age', bins=20) -![png](/img/competitions/getting-started/titanic/titanic_output_24_1.png) +![png](../../../img/competitions/getting-started/titanic/titanic_output_24_1.png) ### 关联数字和顺序的特征 @@ -1061,7 +1061,7 @@ grid.add_legend(); ``` -![png](/img/competitions/getting-started/titanic/titanic_output_26_0.png) +![png](../../../img/competitions/getting-started/titanic/titanic_output_26_0.png) ### 关联分类特征 @@ -1096,7 +1096,7 @@ grid.add_legend() -![png](/img/competitions/getting-started/titanic/titanic_output_28_1.png) +![png](../../../img/competitions/getting-started/titanic/titanic_output_28_1.png) ### 关联分类和数值的特征 @@ -1132,7 +1132,7 @@ grid.add_legend() -![png](/img/competitions/getting-started/titanic/titanic_output_30_1.png) +![png](../../../img/competitions/getting-started/titanic/titanic_output_30_1.png) ## 整理数据 @@ -1677,7 +1677,7 @@ grid.add_legend() -![png](/img/competitions/getting-started/titanic/titanic_output_44_1.png) +![png](../../../img/competitions/getting-started/titanic/titanic_output_44_1.png) 让我们开始准备一个空数组, 以包含基于 Pclass x Gender 组合以猜测 Age 值. diff --git a/docs/Kaggle/competitions/getting-started/titanic/titanic_yy.md b/docs/Kaggle/competitions/getting-started/titanic/titanic_yy.md index d84b8d3b..45cbe7cc 100644 --- a/docs/Kaggle/competitions/getting-started/titanic/titanic_yy.md +++ b/docs/Kaggle/competitions/getting-started/titanic/titanic_yy.md @@ -64,7 +64,7 @@ train.head(3) 是下面这样(NaN 不是咱们想要的结果): -![train前3行](/img/competitions/getting-started/titanic/titanic_yy_1.png) +![train前3行](../../../img/competitions/getting-started/titanic/titanic_yy_1.png) ### 2.2、加入一些特征,删除一些特征,映射一些特征 @@ -217,7 +217,7 @@ saveTmpFile(test,'D:/titanic/titanic_dataset/test_later.csv') 我们处理完成之后的 train 数据集为: -![train前3行](/img/competitions/getting-started/titanic/titanic_yy_2.png) +![train前3行](../../../img/competitions/getting-started/titanic/titanic_yy_2.png) 让我们生成一些特征的关联图,以查看一个特征与下一个特征之间的相关性。 为此,我们将利用 Seaborn 绘图软件包,使我们能够非常方便地绘制热图,如下所示: @@ -225,7 +225,7 @@ saveTmpFile(test,'D:/titanic/titanic_dataset/test_later.csv') ``` -![train前3行](/img/competitions/getting-started/titanic/titanic_yy_3.png) +![train前3行](../../../img/competitions/getting-started/titanic/titanic_yy_3.png) 皮尔逊相关图可以告诉我们的一件事是,没有太多的特征与彼此强相关。 从将这些特征提供给您的学习模型的角度来看,这是很好的,因为这意味着我们的训练集中没有太多冗余或多余的数据,我们很高兴每个特征都带有一些独特的信息。 这里有两个最相关的功能是 FamilySize 和 Parch(家长和儿童)。但是这儿没有删除,依然留着。 diff --git a/docs/Kaggle/competitions/playground/dogs-vs-cats/kernel.md b/docs/Kaggle/competitions/playground/dogs-vs-cats/kernel.md index 24b87b2a..74c9df84 100644 --- a/docs/Kaggle/competitions/playground/dogs-vs-cats/kernel.md +++ b/docs/Kaggle/competitions/playground/dogs-vs-cats/kernel.md @@ -21,13 +21,13 @@ Create an algorithm to distinguish dogs from cats. - 训练数据 -![trainDataset](/img/competitions/playground/train.png) +![trainDataset](../../../img/competitions/playground/train.png) - 训练数据集 - 说明:训练数据集中的数据,是经过人工标记的数据,类别和数字之间使用的 "." (点)做的分隔。 - 测试数据 -![testDataset](/img/competitions/playground/test.png) +![testDataset](../../../img/competitions/playground/test.png) - 测试数据集 - 说明:测试数据集中的数据,是没有经过人工标记的数据,没有对应的类别,只有一些相应的数字号码。 diff --git a/img/logos/ApacheCN-group.png b/docs/Kaggle/img/MainPage/ApacheCN-group.png old mode 100644 new mode 100755 similarity index 100% rename from img/logos/ApacheCN-group.png rename to docs/Kaggle/img/MainPage/ApacheCN-group.png diff --git a/img/competitions/featured/home-credit-default-risk/about-us-home-credit.jpg b/docs/Kaggle/img/competitions/featured/home-credit-default-risk/about-us-home-credit.jpg similarity index 100% rename from img/competitions/featured/home-credit-default-risk/about-us-home-credit.jpg rename to docs/Kaggle/img/competitions/featured/home-credit-default-risk/about-us-home-credit.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975410546.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975410546.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975410546.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975410546.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975616578.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975616578.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975616578.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975616578.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975799651.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975799651.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975799651.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160975799651.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160977834397.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160977834397.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160977834397.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160977834397.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160979383193.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160979383193.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160979383193.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160979383193.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160982666965.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160982666965.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160982666965.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160982666965.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160988495710.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160988495710.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160988495710.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160988495710.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989546724.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989546724.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989546724.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989546724.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989672539.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989672539.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989672539.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989672539.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989939052.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989939052.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989939052.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160989939052.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160990207804.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160990207804.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160990207804.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/EvaluationCriteria/15160990207804.jpg diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/mercari_comparison.png b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/mercari_comparison.png similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/mercari_comparison.png rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/mercari_comparison.png diff --git a/img/competitions/featured/mercari-price-suggestion-challenge/project_process.jpg b/docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/project_process.jpg similarity index 100% rename from img/competitions/featured/mercari-price-suggestion-challenge/project_process.jpg rename to docs/Kaggle/img/competitions/featured/mercari-price-suggestion-challenge/project_process.jpg diff --git a/img/competitions/getting-started/digit-recognizer/front_page.png b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/front_page.png similarity index 100% rename from img/competitions/getting-started/digit-recognizer/front_page.png rename to docs/Kaggle/img/competitions/getting-started/digit-recognizer/front_page.png diff --git a/img/competitions/getting-started/digit-recognizer/knn/knn-1-movie.png b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/knn/knn-1-movie.png similarity index 100% rename from img/competitions/getting-started/digit-recognizer/knn/knn-1-movie.png rename to docs/Kaggle/img/competitions/getting-started/digit-recognizer/knn/knn-1-movie.png diff --git "a/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2171.jpg" "b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2171.jpg" similarity index 100% rename from "img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2171.jpg" rename to "docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2171.jpg" diff --git "a/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2172.jpg" "b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2172.jpg" similarity index 100% rename from "img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2172.jpg" rename to "docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2172.jpg" diff --git "a/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2173.jpg" "b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2173.jpg" similarity index 100% rename from "img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2173.jpg" rename to "docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/SVM\345\205\254\345\274\2173.jpg" diff --git a/img/competitions/getting-started/digit-recognizer/svm/explain1.jpg b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/explain1.jpg similarity index 100% rename from img/competitions/getting-started/digit-recognizer/svm/explain1.jpg rename to docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/explain1.jpg diff --git a/img/competitions/getting-started/digit-recognizer/svm/explain2.jpg b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/explain2.jpg similarity index 100% rename from img/competitions/getting-started/digit-recognizer/svm/explain2.jpg rename to docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/explain2.jpg diff --git a/img/competitions/getting-started/digit-recognizer/svm/explainsvm1.png b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/explainsvm1.png similarity index 100% rename from img/competitions/getting-started/digit-recognizer/svm/explainsvm1.png rename to docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/explainsvm1.png diff --git a/img/competitions/getting-started/digit-recognizer/svm/svm-simple.jpg b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/svm-simple.jpg similarity index 100% rename from img/competitions/getting-started/digit-recognizer/svm/svm-simple.jpg rename to docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/svm-simple.jpg diff --git "a/img/competitions/getting-started/digit-recognizer/svm/\346\225\260\346\215\256\347\211\271\345\276\201\345\210\206\346\236\220.jpg" "b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/\346\225\260\346\215\256\347\211\271\345\276\201\345\210\206\346\236\220.jpg" similarity index 100% rename from "img/competitions/getting-started/digit-recognizer/svm/\346\225\260\346\215\256\347\211\271\345\276\201\345\210\206\346\236\220.jpg" rename to "docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/\346\225\260\346\215\256\347\211\271\345\276\201\345\210\206\346\236\220.jpg" diff --git "a/img/competitions/getting-started/digit-recognizer/svm/\346\234\200\344\274\230\347\211\271\345\276\201\346\225\260\347\233\256\345\222\214roc\345\210\206\346\236\220.jpg" "b/docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/\346\234\200\344\274\230\347\211\271\345\276\201\346\225\260\347\233\256\345\222\214roc\345\210\206\346\236\220.jpg" similarity index 100% rename from "img/competitions/getting-started/digit-recognizer/svm/\346\234\200\344\274\230\347\211\271\345\276\201\346\225\260\347\233\256\345\222\214roc\345\210\206\346\236\220.jpg" rename to "docs/Kaggle/img/competitions/getting-started/digit-recognizer/svm/\346\234\200\344\274\230\347\211\271\345\276\201\346\225\260\347\233\256\345\222\214roc\345\210\206\346\236\220.jpg" diff --git a/img/competitions/getting-started/house-price/housesbanner.png b/docs/Kaggle/img/competitions/getting-started/house-price/housesbanner.png similarity index 100% rename from img/competitions/getting-started/house-price/housesbanner.png rename to docs/Kaggle/img/competitions/getting-started/house-price/housesbanner.png diff --git a/img/competitions/getting-started/house-price/output_14_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_14_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_14_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_14_0.png diff --git a/img/competitions/getting-started/house-price/output_16_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_16_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_16_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_16_0.png diff --git a/img/competitions/getting-started/house-price/output_18_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_18_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_18_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_18_0.png diff --git a/img/competitions/getting-started/house-price/output_25_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_25_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_25_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_25_1.png diff --git a/img/competitions/getting-started/house-price/output_27_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_27_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_27_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_27_1.png diff --git a/img/competitions/getting-started/house-price/output_30_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_30_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_30_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_30_0.png diff --git a/img/competitions/getting-started/house-price/output_33_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_33_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_33_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_33_1.png diff --git a/img/competitions/getting-started/house-price/output_33_2.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_33_2.png similarity index 100% rename from img/competitions/getting-started/house-price/output_33_2.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_33_2.png diff --git a/img/competitions/getting-started/house-price/output_35_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_35_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_35_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_35_0.png diff --git a/img/competitions/getting-started/house-price/output_35_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_35_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_35_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_35_1.png diff --git a/img/competitions/getting-started/house-price/output_37_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_37_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_37_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_37_0.png diff --git a/img/competitions/getting-started/house-price/output_37_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_37_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_37_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_37_1.png diff --git a/img/competitions/getting-started/house-price/output_38_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_38_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_38_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_38_0.png diff --git a/img/competitions/getting-started/house-price/output_38_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_38_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_38_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_38_1.png diff --git a/img/competitions/getting-started/house-price/output_40_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_40_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_40_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_40_1.png diff --git a/img/competitions/getting-started/house-price/output_40_2.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_40_2.png similarity index 100% rename from img/competitions/getting-started/house-price/output_40_2.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_40_2.png diff --git a/img/competitions/getting-started/house-price/output_41_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_41_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_41_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_41_0.png diff --git a/img/competitions/getting-started/house-price/output_41_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_41_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_41_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_41_1.png diff --git a/img/competitions/getting-started/house-price/output_44_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_44_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_44_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_44_0.png diff --git a/img/competitions/getting-started/house-price/output_44_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_44_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_44_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_44_1.png diff --git a/img/competitions/getting-started/house-price/output_46_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_46_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_46_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_46_1.png diff --git a/img/competitions/getting-started/house-price/output_48_1.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_48_1.png similarity index 100% rename from img/competitions/getting-started/house-price/output_48_1.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_48_1.png diff --git a/img/competitions/getting-started/house-price/output_53_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_53_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_53_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_53_0.png diff --git a/img/competitions/getting-started/house-price/output_54_0.png b/docs/Kaggle/img/competitions/getting-started/house-price/output_54_0.png similarity index 100% rename from img/competitions/getting-started/house-price/output_54_0.png rename to docs/Kaggle/img/competitions/getting-started/house-price/output_54_0.png diff --git "a/img/competitions/getting-started/house-price/\346\210\277\344\273\267\351\242\204\346\265\213-\345\255\227\346\256\265\350\257\264\346\230\216.png" "b/docs/Kaggle/img/competitions/getting-started/house-price/\346\210\277\344\273\267\351\242\204\346\265\213-\345\255\227\346\256\265\350\257\264\346\230\216.png" similarity index 100% rename from "img/competitions/getting-started/house-price/\346\210\277\344\273\267\351\242\204\346\265\213-\345\255\227\346\256\265\350\257\264\346\230\216.png" rename to "docs/Kaggle/img/competitions/getting-started/house-price/\346\210\277\344\273\267\351\242\204\346\265\213-\345\255\227\346\256\265\350\257\264\346\230\216.png" diff --git a/img/competitions/getting-started/titanic/titanic_age_axes.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_age_axes.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_age_axes.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_age_axes.png diff --git a/img/competitions/getting-started/titanic/titanic_age_map.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_age_map.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_age_map.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_age_map.png diff --git a/docs/Kaggle/img/competitions/getting-started/titanic/titanic_corr_analysis.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_corr_analysis.png new file mode 100644 index 00000000..b3ed9196 Binary files /dev/null and b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_corr_analysis.png differ diff --git a/img/competitions/getting-started/titanic/titanic_embarked_count.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_embarked_count.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_embarked_count.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_embarked_count.png diff --git a/img/competitions/getting-started/titanic/titanic_output_24_1.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_24_1.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_output_24_1.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_24_1.png diff --git a/img/competitions/getting-started/titanic/titanic_output_26_0.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_26_0.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_output_26_0.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_26_0.png diff --git a/img/competitions/getting-started/titanic/titanic_output_28_1.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_28_1.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_output_28_1.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_28_1.png diff --git a/img/competitions/getting-started/titanic/titanic_output_30_1.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_30_1.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_output_30_1.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_30_1.png diff --git a/img/competitions/getting-started/titanic/titanic_output_44_1.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_44_1.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_output_44_1.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_output_44_1.png diff --git a/img/competitions/getting-started/titanic/titanic_parch_bar.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_parch_bar.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_parch_bar.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_parch_bar.png diff --git a/img/competitions/getting-started/titanic/titanic_pclass_bar.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_pclass_bar.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_pclass_bar.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_pclass_bar.png diff --git a/img/competitions/getting-started/titanic/titanic_sex_bar.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_sex_bar.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_sex_bar.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_sex_bar.png diff --git a/img/competitions/getting-started/titanic/titanic_top_5.jpg b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_top_5.jpg similarity index 100% rename from img/competitions/getting-started/titanic/titanic_top_5.jpg rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_top_5.jpg diff --git a/img/competitions/getting-started/titanic/titanic_train_desc.jpg b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_train_desc.jpg similarity index 100% rename from img/competitions/getting-started/titanic/titanic_train_desc.jpg rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_train_desc.jpg diff --git a/img/competitions/getting-started/titanic/titanic_yy_1.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_yy_1.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_yy_1.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_yy_1.png diff --git a/img/competitions/getting-started/titanic/titanic_yy_2.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_yy_2.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_yy_2.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_yy_2.png diff --git a/img/competitions/getting-started/titanic/titanic_yy_3.png b/docs/Kaggle/img/competitions/getting-started/titanic/titanic_yy_3.png similarity index 100% rename from img/competitions/getting-started/titanic/titanic_yy_3.png rename to docs/Kaggle/img/competitions/getting-started/titanic/titanic_yy_3.png diff --git a/img/competitions/playground/dogs-vs-cats.jpg b/docs/Kaggle/img/competitions/playground/dogs-vs-cats.jpg similarity index 100% rename from img/competitions/playground/dogs-vs-cats.jpg rename to docs/Kaggle/img/competitions/playground/dogs-vs-cats.jpg diff --git a/img/competitions/playground/test.png b/docs/Kaggle/img/competitions/playground/test.png similarity index 100% rename from img/competitions/playground/test.png rename to docs/Kaggle/img/competitions/playground/test.png diff --git a/img/competitions/playground/train.png b/docs/Kaggle/img/competitions/playground/train.png similarity index 100% rename from img/competitions/playground/train.png rename to docs/Kaggle/img/competitions/playground/train.png diff --git a/img/docs/All-GettingStarted.jpg b/docs/Kaggle/img/docs/All-GettingStarted.jpg similarity index 100% rename from img/docs/All-GettingStarted.jpg rename to docs/Kaggle/img/docs/All-GettingStarted.jpg diff --git "a/img/docs/GitHub/ApacheCN-GitHub\345\205\245\351\227\250\346\223\215\344\275\234-Fork\345\210\260PullRequests.png" "b/docs/Kaggle/img/docs/GitHub/ApacheCN-GitHub\345\205\245\351\227\250\346\223\215\344\275\234-Fork\345\210\260PullRequests.png" similarity index 100% rename from "img/docs/GitHub/ApacheCN-GitHub\345\205\245\351\227\250\346\223\215\344\275\234-Fork\345\210\260PullRequests.png" rename to "docs/Kaggle/img/docs/GitHub/ApacheCN-GitHub\345\205\245\351\227\250\346\223\215\344\275\234-Fork\345\210\260PullRequests.png" diff --git a/img/docs/GitHub/GitHub-Setting.png b/docs/Kaggle/img/docs/GitHub/GitHub-Setting.png similarity index 100% rename from img/docs/GitHub/GitHub-Setting.png rename to docs/Kaggle/img/docs/GitHub/GitHub-Setting.png diff --git a/img/docs/GitHub/SSH-Key.jpg b/docs/Kaggle/img/docs/GitHub/SSH-Key.jpg similarity index 100% rename from img/docs/GitHub/SSH-Key.jpg rename to docs/Kaggle/img/docs/GitHub/SSH-Key.jpg diff --git a/img/docs/GitHub/github-step-1-fork.jpg b/docs/Kaggle/img/docs/GitHub/github-step-1-fork.jpg similarity index 100% rename from img/docs/GitHub/github-step-1-fork.jpg rename to docs/Kaggle/img/docs/GitHub/github-step-1-fork.jpg diff --git a/img/docs/GitHub/github-step-2-clone.jpg b/docs/Kaggle/img/docs/GitHub/github-step-2-clone.jpg similarity index 100% rename from img/docs/GitHub/github-step-2-clone.jpg rename to docs/Kaggle/img/docs/GitHub/github-step-2-clone.jpg diff --git a/img/docs/GitHub/github-step-3-PullRequests.jpg b/docs/Kaggle/img/docs/GitHub/github-step-3-PullRequests.jpg similarity index 100% rename from img/docs/GitHub/github-step-3-PullRequests.jpg rename to docs/Kaggle/img/docs/GitHub/github-step-3-PullRequests.jpg diff --git a/img/docs/GitHub/github-step-4-PullRequests.jpg b/docs/Kaggle/img/docs/GitHub/github-step-4-PullRequests.jpg similarity index 100% rename from img/docs/GitHub/github-step-4-PullRequests.jpg rename to docs/Kaggle/img/docs/GitHub/github-step-4-PullRequests.jpg diff --git a/img/docs/GitHub/github-step-5-PullRequests.jpg b/docs/Kaggle/img/docs/GitHub/github-step-5-PullRequests.jpg similarity index 100% rename from img/docs/GitHub/github-step-5-PullRequests.jpg rename to docs/Kaggle/img/docs/GitHub/github-step-5-PullRequests.jpg diff --git a/img/docs/GitHub/github_origin_online_remote.jpg b/docs/Kaggle/img/docs/GitHub/github_origin_online_remote.jpg similarity index 100% rename from img/docs/GitHub/github_origin_online_remote.jpg rename to docs/Kaggle/img/docs/GitHub/github_origin_online_remote.jpg diff --git a/img/docs/choose-digit-recognizer.jpg b/docs/Kaggle/img/docs/choose-digit-recognizer.jpg similarity index 100% rename from img/docs/choose-digit-recognizer.jpg rename to docs/Kaggle/img/docs/choose-digit-recognizer.jpg diff --git a/img/docs/kaggle-submit.jpg b/docs/Kaggle/img/docs/kaggle-submit.jpg similarity index 100% rename from img/docs/kaggle-submit.jpg rename to docs/Kaggle/img/docs/kaggle-submit.jpg diff --git "a/img/docs/kaggle-\345\270\270\347\224\250\345\267\245\345\205\267\351\200\211\346\213\251.png" "b/docs/Kaggle/img/docs/kaggle-\345\270\270\347\224\250\345\267\245\345\205\267\351\200\211\346\213\251.png" similarity index 100% rename from "img/docs/kaggle-\345\270\270\347\224\250\345\267\245\345\205\267\351\200\211\346\213\251.png" rename to "docs/Kaggle/img/docs/kaggle-\345\270\270\347\224\250\345\267\245\345\205\267\351\200\211\346\213\251.png" diff --git "a/img/docs/kaggle-\345\270\270\347\224\250\347\256\227\346\263\225\351\200\211\346\213\251.png" "b/docs/Kaggle/img/docs/kaggle-\345\270\270\347\224\250\347\256\227\346\263\225\351\200\211\346\213\251.png" similarity index 100% rename from "img/docs/kaggle-\345\270\270\347\224\250\347\256\227\346\263\225\351\200\211\346\213\251.png" rename to "docs/Kaggle/img/docs/kaggle-\345\270\270\347\224\250\347\256\227\346\263\225\351\200\211\346\213\251.png" diff --git "a/img/docs/kaggle-\347\211\271\345\276\201\345\267\245\347\250\213.png" "b/docs/Kaggle/img/docs/kaggle-\347\211\271\345\276\201\345\267\245\347\250\213.png" similarity index 100% rename from "img/docs/kaggle-\347\211\271\345\276\201\345\267\245\347\250\213.png" rename to "docs/Kaggle/img/docs/kaggle-\347\211\271\345\276\201\345\267\245\347\250\213.png" diff --git a/img/docs/login.jpg b/docs/Kaggle/img/docs/login.jpg similarity index 100% rename from img/docs/login.jpg rename to docs/Kaggle/img/docs/login.jpg diff --git a/img/docs/read-digit-recognizer.jpg b/docs/Kaggle/img/docs/read-digit-recognizer.jpg similarity index 100% rename from img/docs/read-digit-recognizer.jpg rename to docs/Kaggle/img/docs/read-digit-recognizer.jpg diff --git a/docs/Kaggle/img/logos/ApacheCN-group.png b/docs/Kaggle/img/logos/ApacheCN-group.png new file mode 100644 index 00000000..ea93fc51 Binary files /dev/null and b/docs/Kaggle/img/logos/ApacheCN-group.png differ diff --git a/img/logos/kaggle-logo-gray-bigger.jpeg b/docs/Kaggle/img/logos/kaggle-logo-gray-bigger.jpeg similarity index 100% rename from img/logos/kaggle-logo-gray-bigger.jpeg rename to docs/Kaggle/img/logos/kaggle-logo-gray-bigger.jpeg diff --git a/img/logos/kaggle-logo-gray.png b/docs/Kaggle/img/logos/kaggle-logo-gray.png similarity index 100% rename from img/logos/kaggle-logo-gray.png rename to docs/Kaggle/img/logos/kaggle-logo-gray.png diff --git a/img/logos/kaggle-logo-transparent.png b/docs/Kaggle/img/logos/kaggle-logo-transparent.png similarity index 100% rename from img/logos/kaggle-logo-transparent.png rename to docs/Kaggle/img/logos/kaggle-logo-transparent.png diff --git a/img/logos/kaggle-logo.png b/docs/Kaggle/img/logos/kaggle-logo.png similarity index 100% rename from img/logos/kaggle-logo.png rename to docs/Kaggle/img/logos/kaggle-logo.png diff --git "a/img/math/\347\237\251\351\230\2651.jpg" "b/docs/Kaggle/img/math/\347\237\251\351\230\2651.jpg" similarity index 100% rename from "img/math/\347\237\251\351\230\2651.jpg" rename to "docs/Kaggle/img/math/\347\237\251\351\230\2651.jpg" diff --git a/docs/Kaggle/kernel.md b/docs/Kaggle/kernel.md deleted file mode 100644 index 1dfe1cfa..00000000 --- a/docs/Kaggle/kernel.md +++ /dev/null @@ -1,6 +0,0 @@ -# Kaggle Kernel 备份 - -+ [第一部分](https://github.com/apachecn/kaggle-kernel-pt1) -+ [第二部分](https://github.com/apachecn/kaggle-kernel-pt2) -+ [第三部分](https://github.com/apachecn/kaggle-kernel-pt3) -+ [第四部分](https://github.com/apachecn/kaggle-kernel-pt4) \ No newline at end of file diff --git a/docs/Kaggle/learn/embeddings/README.md b/docs/Kaggle/learn/embeddings/README.md deleted file mode 100644 index 76a5e941..00000000 --- a/docs/Kaggle/learn/embeddings/README.md +++ /dev/null @@ -1,964 +0,0 @@ -# Kaggle 官方教程:嵌入 - -> 原文:[Embeddings](https://www.kaggle.com/learn/embeddings) -> -> 译者:[飞龙](https://github.com/wizardforcel) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -P.S... - -本课程仍处于测试阶段,因此我很乐意收到你的反馈意见。 如果你有时间填写[本课程的超短期调查](https://form.jotform.com/82826168584267),我将非常感激。 你也可以在下面的评论中或在[学习论坛](https://www.kaggle.com/learn-forum)上留下公开反馈。 - -## 一、嵌入层 - -欢迎阅读嵌入主题的第一课。 在本课程中,我将展示如何使用`tf.keras` API 实现带嵌入层的模型。 嵌入是一种技术,使深度神经网络能够处理稀疏的类别变量。 - -### 稀疏类别变量 - -我的意思是一个具有许多可能值(高基数)的类别变量,其中少数(通常只有 1)存在于任何给定的观察中。 一个很好的例子是词汇。 英语中的词汇是成千上万的,但一条推文可能只有十几个词。 词嵌入是将深度学习应用于自然语言的关键技术。 但其他例子还有很多。 - -例如,[洛杉矶餐馆检查](https://www.kaggle.com/meganrisdal/la-county-restaurant-inspections-and-violations)的这个数据集有几个稀疏的分类变量,包括: - -+ `employee_id`:卫生部门的哪些员工进行了这次检查? (约 250 个不同的值) -+ `facility_zip`:餐厅的邮政编码是什么? (约 3,000 个不同的值) -+ `owner_name`:谁拥有餐厅? (约 35,000 个不同的值) - -对于将任何这些变量用作网络的输入,嵌入层是个好主意。 - -在本课程中,我将使用 [MovieLens 数据集](https://www.kaggle.com/grouplens/movielens-20m-dataset)作为示例。 - -### MovieLens - -MovieLens 数据集由用户给电影的评分组成。这是一个示例: - - -| | userId | movieId | rating | y | title | year | -| --- | --- | --- | --- | --- | --- | --- | -| 12904240 | 85731 | 1883 | 4.5 | 0.974498 | Labyrinth | 1986 | -| 6089380 | 45008 | 1221 | 4.5 | 0.974498 | Femme Nikita, La (Nikita) | 1990 | -| 17901393 | 125144 | 3948 | 4.0 | 0.474498 | The Alamo | 1960 | -| 9024816 | 122230 | 3027 | 3.5 | -0.025502 | Toy Story 2 | 1999 | -| 11655659 | 21156 | 5202 | 3.0 | -0.525502 | My Big Fat Greek Wedding | - -评分范围是 0.5 到 5。我们的目标是预测由给定用户`ui`给出的,特定电影`mj`的评分。 (列`y`只是评分列的副本,减去了平均值 - 这在以后会有用。) - -`userId`和`movieId`都是稀疏分类变量。 它们有许多可能的值: - -``` -138,493 个独立用户评分了 26,744 个不同的电影(总评分是 20,000,263 个) -``` - -### 在 Keras 中创建评分预测模型 - -我们想要构建一个模型,它接受用户`ui`和电影`mj`,并输出 0.5-5 的数字,表示我们认为该用户将为该电影评分多少星。 - -> 注:你可能已经注意到`MovieLens`数据集包含每部电影的信息,例如标题,发行年份,一组流派和用户指定的标签。 但就目前而言,我们不会试图利用任何额外的信息。 - -我说我们需要一个嵌入层来处理这些输入。 为什么? 让我们回顾一些替代方案,看看为什么它们不起作用。 - -### 坏主意 #1:使用用户和电影 ID 作为数值输入 - -为什么不将用户 ID 和电影 ID 作为数值来输入,然后添加一些密集层?即: - -```py -model = keras.Sequential([ - # 2 个输入值:用户 ID 和电影 ID - keras.layers.Dense(256, input_dim=2, activation='relu'), - keras.layers.Dense(32, activation='relu'), - # 单个输出节点,包含预测的评分 - keras.layers.Dense(1) -]) -``` - -用最简单的术语来说,神经网络的原理是对输入进行数学运算。 但分配给用户和电影的 ID 的实际数值是没有意义的。《辛德勒的名单》的 id 为 527,而《非常嫌疑犯》的 id 为 50,但这并不意味着《辛德勒的名单》比《非常嫌疑犯》大十倍。 - -### 坏主意 #2:独热编码的用户和电影输入 - -如果你不熟悉单热编码,可能需要查看我们的课程[“使用独热编码处理类别数据”](https://www.kaggle.com/dansbecker/using-categorical-data-with-one-hot-encoding)。 - -在该课程中,我们说独热编码是“类别数据的标准方法”。 那么为什么这是一个坏主意呢? 让我们看看模型是什么样子,它接受独热编码的用户和电影。 - -```py -input_size = n_movies + n_users -print("Input size = {:,} ({:,} movies + {:,} users)".format( - input_size, n_movies, n_users, -)) -model = keras.Sequential([ - # 一个带有 128 个单元的隐藏层 - keras.layers.Dense(128, input_dim=input_size, activation='relu'), - # 单个输出节点,包含预测的评分 - keras.layers.Dense(1) -]) -model.summary() -''' -Input size = 165,237 (26,744 movies + 138,493 users) -_________________________________________________________________ -Layer (type) Output Shape Param # -================================================================= -dense_3 (Dense) (None, 128) 21150464 -_________________________________________________________________ -dense_4 (Dense) (None, 1) 129 -================================================================= -Total params: 21,150,593 -Trainable params: 21,150,593 -Non-trainable params: 0 -_________________________________________________________________ -''' -``` - -这里的一个基本问题是扩展和效率。 我们模型的单个输入是包含 165,237 个数字的向量(其中我们知道 165,235 是零)。 我们整个 2000 万个评分实例数据集的特征数据,将需要一个大小为 20,000,000 x 165,237 或大约 3 万亿个数字的二维数组。 但愿你能把这一切都放进内存中! - -此外,在我们的模型上进行训练和推断将是低效的。 为了计算我们的第一个隐藏层的激活,我们需要将我们的 165k 输入乘以大约 2100 万个权重 - 但是这些乘积的绝大多数都将为零。 - -对于具有少量可能值的分类变量,例如`{Red, Yellow, Green}`或`{Monday, Tuesday, Wednesday, Friday, Saturday, Sunday}`,独热编码是合适的。 但在像我们的电影推荐问题的情况下,它并不是那么好,其中变量有数十或数十万个可能的值。 - -### 好主意:嵌入层 - -简而言之,嵌入层将一组离散对象(如单词,用户或电影)中的每个元素映射到实数的密集(嵌入)向量。 - -> 注:一个关键的实现细节是嵌入层接受被嵌入实体的索引作为输入(即我们可以将`userId`和`movieId`作为输入)。 你可以将其视为一种“查找表”。 这比采用独热向量并进行巨大的矩阵乘法要有效得多! - -例如,如果我们为电影学习大小为 8 的嵌入,则《律政俏佳人》(`index = 4352`)的嵌入可能如下所示: - -``` -[1.624,−0.612,−0.528,−1.073,0.865,−2.302,1.745,−0.761] -``` - -它们来自哪里? 我们使用随机噪声为每个用户和电影初始化嵌入,然后我们将它们训练,作为整体评分预测模型训练过程的一部分。 - -他们的意思是什么? 如果对象的嵌入有任何好处,它应该捕获该对象的一些有用的潜在属性。 但这里的关键词是潜在,也就是隐藏的。 由模型来发现实体的任何属性,并在嵌入空间中对它们编码,对预测任务有用。 听起来很神秘? 在后面的课程中,我将展示一些解释习得的嵌入的技术,例如使用 t-SNE 算法将它们可视化。 - -### 实现它 - -我希望我的模型是这样: - -![](/img/learn/embeddings/emb-1.png) - -需要注意的一个关键点是,这个网络不仅仅是从输入到输出的一堆层级。 我们将用户和电影视为单独的输入,只有在每个输入经过自己的嵌入层之后才会聚集在一起。 - -这意味着[`keras.Sequential`](https://www.tensorflow.org/api_docs/python/tf/keras/Sequential)类(你可能从我们的[图像数据深度学习课程](https://www.kaggle.com/learn/deep-learning)中熟悉它)将无法工作。 我们需要使用[`keras.Model`](https://www.tensorflow.org/api_docs/python/tf/keras/Model)类转向更强大的“函数式 API”。 函数式 API 的更多详细信息,请查看 [Keras 的指南](https://keras.io/getting-started/functional-api-guide/)。 - -这是代码: - -```py -hidden_units = (32,4) -movie_embedding_size = 8 -user_embedding_size = 8 - -# 每个实例将包含两个输入:单个用户 ID 和单个电影 ID -user_id_input = keras.Input(shape=(1,), name='user_id') -movie_id_input = keras.Input(shape=(1,), name='movie_id') -user_embedded = keras.layers.Embedding(df.userId.max()+1, user_embedding_size, - input_length=1, name='user_embedding')(user_id_input) -movie_embedded = keras.layers.Embedding(df.movieId.max()+1, movie_embedding_size, - input_length=1, name='movie_embedding')(movie_id_input) -# 连接嵌入(并删除无用的额外维度) -concatenated = keras.layers.Concatenate()([user_embedded, movie_embedded]) -out = keras.layers.Flatten()(concatenated) - -# 添加一个或多个隐层 -for n_hidden in hidden_units: - out = keras.layers.Dense(n_hidden, activation='relu')(out) - -# 单一输出:我们的预测评分 -out = keras.layers.Dense(1, activation='linear', name='prediction')(out) - -model = keras.Model( - inputs = [user_id_input, movie_id_input], - outputs = out, -) -model.summary(line_length=88) -''' -________________________________________________________________________________________ -Layer (type) Output Shape Param # Connected to -======================================================================================== -user_id (InputLayer) (None, 1) 0 -________________________________________________________________________________________ -movie_id (InputLayer) (None, 1) 0 -________________________________________________________________________________________ -user_embedding (Embedding) (None, 1, 8) 1107952 user_id[0][0] -________________________________________________________________________________________ -movie_embedding (Embedding) (None, 1, 8) 213952 movie_id[0][0] -________________________________________________________________________________________ -concatenate (Concatenate) (None, 1, 16) 0 user_embedding[0][0] - movie_embedding[0][0] -________________________________________________________________________________________ -flatten (Flatten) (None, 16) 0 concatenate[0][0] -________________________________________________________________________________________ -dense_5 (Dense) (None, 32) 544 flatten[0][0] -________________________________________________________________________________________ -dense_6 (Dense) (None, 4) 132 dense_5[0][0] -________________________________________________________________________________________ -prediction (Dense) (None, 1) 5 dense_6[0][0] -======================================================================================== -Total params: 1,322,585 -Trainable params: 1,322,585 -Non-trainable params: 0 -________________________________________________________________________________________ -''' -``` - -### 训练 - -我们将编译我们的模型,来最小化平方误差('MSE')。 我们还将绝对值误差('MAE')作为在训练期间报告的度量标准,因为它更容易解释。 - -> 需要考虑的事情:我们知道评分只能取值`{0.5,1,1.5,2,2.5,3,3.5,4,4.5,5}` - 所以为什么不将其视为 10 类的多类分类问题 ,每个可能的星级评分一个? - -```py -model.compile( - # 技术说明:使用嵌入层时,我强烈建议使用 - # tf.train 中发现的优化器之一: - # https://www.tensorflow.org/api_guides/python/train#Optimizers - # 传入像 'adam' 或 'SGD' 这样的字符串,会加载一个 keras 优化器 - # (在 tf.keras.optimizers 下寻找)。 对于像这样的问题,它们似乎要慢得多, - # 因为它们无法有效处理稀疏梯度更新。 - tf.train.AdamOptimizer(0.005), - loss='MSE', - metrics=['MAE'], -) -``` - -让我们训练模型: - -> 注:我传入`df.y`而不是`df.rating`,作为我的目标变量。`y`列只是评分的“中心”版本 - 即评分列减去其在训练集上的平均值。 例如,如果训练集中的总体平均评分是 3 星,那么我们将 3 星评分翻译为 0, 5星评分为 2.0 等等,来获得`y`。 这是深度学习中的常见做法,并且往往有助于在更少的时期内获得更好的结果。 对于更多详细信息,请随意使用我在 MovieLens 数据集上执行的所有预处理来检查[这个内核](https://www.kaggle.com/colinmorris/movielens-preprocessing)。 - -```py -history = model.fit( - [df.userId, df.movieId], - df.y, - batch_size=5000, - epochs=20, - verbose=0, - validation_split=.05, -); -``` - -为了判断我们的模型是否良好,有一个基线是有帮助的。 在下面的单元格中,我们计算了几个虚拟基线的误差:始终预测全局平均评分,以及预测每部电影的平均评分: - -+ 训练集的平均评分:3.53 星 -+ 总是预测全局平均评分,结果为 MAE=0.84,MSE=1.10 -+ 预测每部电影的平均评分,结果为 MAE=0.73,MSE=0.88 - - -这是我们的嵌入模型的绝对误差随时间的绘图。 为了进行比较,我们的最佳基线(预测每部电影的平均评分)用虚线标出: - -![](/img/learn/embeddings/emb-2.png) - -与基线相比,我们能够将平均误差降低超过 0.1 星(或约 15%)。不错! - -### 示例预测 - -让我们尝试一些示例预测作为健全性检查。 我们首先从数据集中随机挑选一个特定用户。 - -``` -用户 #26556 评分了 21 个电影(平均评分为 3.7) -``` - -| | userId | movieId | rating | title | year | -| --- | --- | --- | --- | --- | --- | -| 4421455 | 26556 | 2705 | 5.0 | Airplane! | 1980 | -| 14722970 | 26556 | 2706 | 5.0 | Airplane II: The Sequel | 1982 | -| 7435440 | 26556 | 2286 | 4.5 | Fletch | 1985 | -| 16621016 | 26556 | 2216 | 4.5 | History of the World: Part I | 1981 | -| 11648630 | 26556 | 534 | 4.5 | Six Degrees of Separation | 1993 | -| 14805184 | 26556 | 937 | 4.5 | Mr. Smith Goes to Washington | 1939 | -| 14313285 | 26556 | 2102 | 4.5 | Strangers on a Train | 1951 | -| 13671173 | 26556 | 2863 | 4.5 | Dr. No | 1962 | -| 13661434 | 26556 | 913 | 4.0 | Notorious | 1946 | -| 11938282 | 26556 | 916 | 4.0 | To Catch a Thief | 1955 | -| 2354167 | 26556 | 3890 | 4.0 | Diamonds Are Forever | 1971 | -| 16095891 | 26556 | 730 | 4.0 | Spy Hard | 1996 | -| 16265128 | 26556 | 3414 | 3.5 | Network | 1976 | -| 13050537 | 26556 | 1414 | 3.5 | Waiting for Guffman | 1996 | -| 9891416 | 26556 | 2907 | 3.5 | Thunderball | 1965 | -| 3496223 | 26556 | 4917 | 3.5 | Gosford Park | 2001 | -| 1996728 | 26556 | 1861 | 3.0 | On the Waterfront | 1954 | -| 15893218 | 26556 | 1082 | 2.5 | A Streetcar Named Desire | 1951 | -| 13875921 | 26556 | 3445 | 2.5 | Keeping the Faith | 2000 | -| 13163853 | 26556 | 1225 | 2.0 | The Day the Earth Stood Still | 1951 | -| 7262983 | 26556 | 2348 | 0.5 | A Civil Action | 1998 | - -用户 26556 给电影《空前绝后满天飞》和《空前绝后满天飞 II》打了两个完美的评分。很棒的选择! 也许他们也会喜欢《白头神探》系列 - 另一系列由 Leslie Nielsen 主演的恶搞电影。 - -我们没有那么多关于这个用户讨厌什么的证据。 我们不根据他们的少数低评分做推断,用户不喜欢什么的更好推断是,他们甚至没有评价的电影类型。 让我们再举几个电影的例子,根据用户的评分历史记录,他们似乎不太可能看过。 - -```py -candidate_movies = movies[ - movies.title.str.contains('Naked Gun') - | (movies.title == 'The Sisterhood of the Traveling Pants') - | (movies.title == 'Lilo & Stitch') -].copy() - -preds = model.predict([ - [uid] * len(candidate_movies), # 用户 ID - candidate_movies.index, # 电影 ID -]) -# 注意:记住我们在 'y' 上训练,这是评分列的中心为 0 的版本。 -# 要将我们模型的输出值转换为 [0.5, 5] 原始的星级评分范围, -# 我们需要通过添加均值来对值“去中心化” -row = df.iloc[0] # rating 和 y 之间的差对于所有行都是相同的,所以我们可以使用第一行 -y_delta = row.rating - row.y -candidate_movies['predicted_rating'] = preds + y_delta -# 添加一列,带有我们的预测评分(对于此用户) -# 和电影对于数据集中所有用户的总体平均评分之间的差 -candidate_movies['delta'] = candidate_movies['predicted_rating'] - candidate_movies['mean_rating'] -candidate_movies.sort_values(by='delta', ascending=False) -``` - -| | title | year | mean_rating | n_ratings | predicted_rating | delta | -| --- | --- | --- | --- | --- | --- | --- | -| movieId | | | | | | | -| 366 | Naked Gun 33 1/3: The Final Insult | 1994 | 2.954226 | 13534.0 | 3.816926 | 0.862699 | -| 3776 | The Naked Gun 2 1/2: The Smell of Fear | 1991 | 3.132616 | 4415.0 | 3.946124 | 0.813508 | -| 3775 | The Naked Gun: From the Files of Police Squad! | 1988 | 3.580381 | 6973.0 | 4.236419 | 0.656037 | -| 5347 | Lilo & Stitch | 2002 | 3.489323 | 4402.0 | 3.971318 | 0.481995 | -| 10138 | The Sisterhood of the Traveling Pants | 2005 | 3.369987 | 773.0 | 2.041227 | -1.328760 | - -看起来很合理! 对于《白头神探》系列中的每部电影,我们对此用户的预测评分,大约比数据集中平均评分高一星,而我们的“out of left field”使它们的预测评分低于平均值。 - -### 你的回合 - -前往[练习笔记本](https://www.kaggle.com/kernels/fork/1598432),进行嵌入层的实践练习。 - -## 二、用于推荐问题的矩阵分解 - -在上一课中,我们训练了一个模型来预测在 MovieLens 数据集中,用户给电影的评分。 提醒一下,模型看起来像这样: - -![](/img/learn/embeddings/emb-1.png) - -我们为电影和用户查找嵌入向量,将它们连接在一起。 然后我们添加一些隐层。 最后,这些在一个输出节点汇集在一起来预测评分。 - -在本节课中,我将展示一个更简单的架构,来解决同样的问题:矩阵分解。 更简单可以是一件非常好的事情! 有时,简单的模型会快速收敛到适当的解决方案,一个更复杂的模型可能会过拟合或无法收敛。 - -这是我们的矩阵分解模型的样子: - -![](/img/learn/embeddings/emb-3.png) - -### 点积 - -让我们回顾一下数学。 如果你是线性代数专家,请跳过本节。 - -两个长度为`n`的向量`a`和`b`的点积定义为: - -![](/img/learn/embeddings/emb-4.png) - -结果是单个标量(不是向量)。 - -点积仅为相同长度的矢量而定义。 这意味着我们需要为电影嵌入和用户嵌入使用相同的大小。 - -例如,假设我们已经训练了大小为 4 的嵌入,并且电影 Twister 由向量表示: - -``` -m_Twister=[ 1.0 −0.5 0.3 −0.1 ] -``` - -用户 Stanley 表示为: - -``` -u_Stanley=[ −0.2 1.5 −0.1 0.9 ] -``` - -我们认为 Stanley 会给 Twister 什么评分? 我们可以将模型的输出计算为: - -``` -m_Twister · u_Stanley -= (1.0·−0.2)+(−0.5·1.5)+(0.3·−0.1)+(−0.1·0.9) -= −1.07 -``` - -因为我们正在在评分列的中心版本上训练,所以我们的模型输出的比例为 0 等于训练集中的总体平均评分(约 3.5)。 因此我们预测 Stanley 将给 Twister `3.5+(−1.07)=2.43`星。 - -### 为什么 - -有一个直观的解释,支持了以这种方式组合我们的嵌入向量的决定。 假设我们的电影嵌入空间的维度对应于以下变化的轴: - -维度 1:多么令人激动? -维度 2:多么浪漫? -维度 3:目标受众有多成熟? -维度 4:多么好笑? - -因此,Twister 是一部令人激动的灾难电影,`m1`的正值为 1.0。 - -简单来说,`u1`告诉我们“这个用户对动作片的看法如何?”。 他们喜欢它吗?讨厌它?还是不喜欢也不讨厌? - -Stanley 的向量告诉,我们他是浪漫和喜剧的忠实粉丝,并且略微不喜欢动作和成熟的内容。 如果我们给他一部类似于最后一部的电影,除了它有很多浪漫元素,会怎么样? - -``` -m_Titanic=[ 1.0 1.1 0.3 −0.1 ] -``` - -不难预测这会如何影响我们的评分输出。 我们给 Stanley 更多他喜欢的东西,所以他的预测评分会增加。 - -``` -predicted_rating(Stanley,Titanic) -= m_Titanic·u_Stanley+3.5 -=(1.0·−0.2)+(1.1·1.5)+(0.3·−0.1)+(−0.1·0.9)+3.5 -=4.83 stars -``` - -> 注:在实践中,我们的电影嵌入的维度的含义不会那么明确,但我们的电影嵌入空间和用户嵌入空间的含义从根本上联系在一起,这仍然是正确的:`ui`总是代表“这个用户多么喜欢某个电影,其质量由`mi`代表?“ (希望这也提供了一些直觉,为什么电影嵌入空间和用户嵌入空间在这个技巧中必须大小相同。) - -### 实现它 - -创建此模型的代码,类似于我们在上一课中编写的代码,除了我使用点积层来组合用户和电影嵌入层的输出(而不是连接它们,并输入到密集层)。 - -```py -movie_embedding_size = user_embedding_size = 8 - -# 每个实例由两个输入组成:单个用户 ID 和单个电影 ID -user_id_input = keras.Input(shape=(1,), name='user_id') -movie_id_input = keras.Input(shape=(1,), name='movie_id') -user_embedded = keras.layers.Embedding(df.userId.max()+1, user_embedding_size, - input_length=1, name='user_embedding')(user_id_input) -movie_embedded = keras.layers.Embedding(df.movieId.max()+1, movie_embedding_size, - input_length=1, name='movie_embedding')(movie_id_input) - -dotted = keras.layers.Dot(2)([user_embedded, movie_embedded]) -out = keras.layers.Flatten()(dotted) - -model = keras.Model( - inputs = [user_id_input, movie_id_input], - outputs = out, -) -model.compile( - tf.train.AdamOptimizer(0.001), - loss='MSE', - metrics=['MAE'], -) -model.summary(line_length=88) -''' -________________________________________________________________________________________ -Layer (type) Output Shape Param # Connected to -======================================================================================== -user_id (InputLayer) (None, 1) 0 -________________________________________________________________________________________ -movie_id (InputLayer) (None, 1) 0 -________________________________________________________________________________________ -user_embedding (Embedding) (None, 1, 8) 1107952 user_id[0][0] -________________________________________________________________________________________ -movie_embedding (Embedding) (None, 1, 8) 213952 movie_id[0][0] -________________________________________________________________________________________ -dot (Dot) (None, 1, 1) 0 user_embedding[0][0] - movie_embedding[0][0] -________________________________________________________________________________________ -flatten (Flatten) (None, 1) 0 dot[0][0] -======================================================================================== -Total params: 1,321,904 -Trainable params: 1,321,904 -Non-trainable params: 0 -________________________________________________________________________________________ -''' -``` - -让我们训练它。 - -```py -history = model.fit( - [df.userId, df.movieId], - df.y, - batch_size=5000, - epochs=20, - verbose=0, - validation_split=.05, -); -``` - -让我们将这个模型随时间的误差,与我们在上一课中训练的深度神经网络进行比较: - -![](/img/learn/embeddings/emb-5.png) - -我们新的,更简单的模型(蓝色)看起来非常好。 - -然而,即使我们的嵌入相当小,两种模型都会产生一些明显的过拟合。 也就是说,训练集上的误差 - 实线 - 明显好于看不见的数据。 我们将在练习中尽快解决这个问题。 - -### 你的回合 - -前往[练习笔记本](https://www.kaggle.com/kernels/fork/1598589),进行矩阵分解的实践练习。 - -## 三、使用 Gensim 探索嵌入 - -早些时候,我们训练了一个模型,使用一个网络,它带有为每个电影和用户学习的嵌入,来预测用户为电影提供的评分。 嵌入是强大的!但他们实际如何工作? - -以前,我说嵌入捕获了它们所代表的对象的“含义”,并发现了有用的潜在结构。 让我们来测试吧! - -### 查询嵌入 - -让我们加载我们之前训练过的模型,这样我们就可以研究它学到的嵌入权重。 - -```py -import os - -import numpy as np -import pandas as pd -from matplotlib import pyplot as plt -import tensorflow as tf -from tensorflow import keras - -input_dir = '../input/movielens-preprocessing' -model_dir = '../input/movielens-spiffy-model' -model_path = os.path.join(model_dir, 'movie_svd_model_32.h5') -model = keras.models.load_model(model_path) -``` - -嵌入权重是模型内部的一部分,因此我们必须进行一些挖掘才能访问它们。 我们将获取负责嵌入电影的层,并使用`get_weights()`方法获取其学习的权重。 - -```py -emb_layer = model.get_layer('movie_embedding') -(w,) = emb_layer.get_weights() -w.shape -# (26744, 32) -``` - -对于那么多电影,我们的权重矩阵有 26,744 行。 每行是 32 个数字 - 我们的电影嵌入的大小。 - -我们来看一个示例电影向量: - -```py -w[0] -''' -array([-0.08716497, -0.25286013, -0.52679837, -0.2602235 , -0.4349191 , - -0.48805636, -0.30346015, -0.1416321 , 0.08305884, -0.17578898, - -0.36220485, 0.14578693, 0.37118354, -0.02961254, -0.063666 , - -0.5223456 , 0.0526049 , 0.47991064, -0.19034313, -0.3271599 , - 0.32792446, -0.3794548 , -0.55778086, -0.42602876, 0.14532137, - 0.21002969, -0.32203963, -0.46950188, -0.22500233, -0.08298543, - -0.00373308, -0.3885791 ], dtype=float32) -''' -``` - -这是什么电影的嵌入? 让我们加载我们的电影元数据的数据帧。 - -```py -movies_path = os.path.join(input_dir, 'movie.csv') -movies_df = pd.read_csv(movies_path, index_col=0) -movies_df.head() -``` - - -| | movieId | title | genres | key | year | n_ratings | mean_rating | -| --- | --- | --- | --- | --- | --- | --- | --- | -| 0 | 0 | Toy Story | Adventure|Animation|Children|Comedy|Fantasy | Toy Story | 1995 | 49695 | 3.921240 | -| 1 | 1 | Jumanji | Adventure|Children|Fantasy | Jumanji | 1995 | 22243 | 3.211977 | -| 2 | 2 | Grumpier Old Men | Comedy|Romance | Grumpier Old Men | 1995 | 12735 | 3.151040 | -| 3 | 3 | Waiting to Exhale | Comedy|Drama|Romance | Waiting to Exhale | 1995 | 2756 | 2.861393 | -| 4 | 4 | Father of the Bride Part II | Comedy | Father of the Bride Part II | 1995 | 12161 | 3.064592 | - -当然,这是《玩具总动员》! 我应该在任何地方认出这个向量。 - -好吧,我很滑稽。此时很难利用这些向量。 我们从未告诉模型如何使用任何特定嵌入维度。 我们只让它学习它认为有用的任何表示。 - -那么我们如何检查这些表示是否合理且连贯? - -### 向量相似度 - -测试它的一种简单方法是,查看嵌入空间中电影对有多么接近或远离。 嵌入可以被认为是智能的距离度量。 如果我们的嵌入矩阵是良好的,它应该将类似的电影(如《玩具总动员》和《怪物史莱克》)映射到类似的向量。 - -```py -i_toy_story = 0 -i_shrek = movies_df.loc[ - movies_df.title == 'Shrek', - 'movieId' -].iloc[0] - -toy_story_vec = w[i_toy_story] -shrek_vec = w[i_shrek] - -print( - toy_story_vec, - shrek_vec, - sep='\n', -) -''' -[-0.08716497 -0.25286013 -0.52679837 -0.2602235 -0.4349191 -0.48805636 - -0.30346015 -0.1416321 0.08305884 -0.17578898 -0.36220485 0.14578693 - 0.37118354 -0.02961254 -0.063666 -0.5223456 0.0526049 0.47991064 - -0.19034313 -0.3271599 0.32792446 -0.3794548 -0.55778086 -0.42602876 - 0.14532137 0.21002969 -0.32203963 -0.46950188 -0.22500233 -0.08298543 - -0.00373308 -0.3885791 ] -[ 0.0570179 0.5991162 -0.71662885 0.22245468 -0.40536046 -0.33602375 - -0.24281627 0.08997302 0.03362623 -0.12569055 -0.2764452 -0.12710975 - 0.48197436 0.2724923 0.01551001 -0.20889504 -0.04863157 0.39106563 - -0.24811408 -0.05642252 0.24475795 -0.53363544 -0.2281187 -0.17529544 - 0.21050802 -0.37807122 0.03861505 -0.27024794 -0.24332719 -0.17732081 - 0.07961234 -0.39079434] -''' -``` - -逐个维度地比较,这些看起来大致相似。 如果我们想为它们的相似度分配一个数字,我们可以计算这两个向量之间的欧氏距离。 (这是我们传统的“乌鸦飞过的”两点之间的距离的概念。容易在 1,2 或 3 维上进行研究。在数学上,我们也可以将它扩展到 32 维,虽然需要好运来可视化它。) - -```py -from scipy.spatial import distance - -distance.euclidean(toy_story_vec, shrek_vec) -# 1.4916094541549683 -``` - -这与我们认为非常不同的一对电影相比如何? - -```py -i_exorcist = movies_df.loc[ - movies_df.title == 'The Exorcist', - 'movieId' -].iloc[0] - -exorcist_vec = w[i_exorcist] - -distance.euclidean(toy_story_vec, exorcist_vec) -# 2.356588363647461 -``` - -更远了,和我们期待的一样。 - -### 余弦距离 - -如果你看看[`scipy.spatial`模块的文档](https://docs.scipy.org/doc/scipy-0.14.0/reference/spatial.distance.html),你会发现人们用于不同任务的距离,实际上有很多不同的衡量标准。 - -在判断嵌入的相似性时,使用[余弦相似性](https://en.wikipedia.org/wiki/Cosine_similarity)更为常见。 - -简而言之,两个向量的余弦相似度范围从 -1 到 1,并且是向量之间的角度的函数。 如果两个向量指向同一方向,则它们的余弦相似度为 1。如果它们指向相反的方向,它为 -1。 如果它们是正交的(即成直角),则它们的余弦相似度为 0。 - -余弦距离定义为 1 减去余弦相似度(因此范围从 0 到 2)。 - -让我们计算电影向量之间的几个余弦距离: - -```py -print( - distance.cosine(toy_story_vec, shrek_vec), - distance.cosine(toy_story_vec, exorcist_vec), - sep='\n' -) -''' -0.3593705892562866 -0.811933159828186 -''' -``` - -> 注:为什么在使用嵌入时常用余弦距离? 与许多深度学习技巧一样,简短的答案是“凭经验,它能用”。 在即将进行的练习中,你将进行一些实践调查,更深入地探讨这个问题。 - -哪部电影与《玩具总动员》最相似? 在嵌入空间中哪些电影落在 Psycho 和 Scream 之间? 我们可以编写一堆代码来解决这样的问题,但这样做非常繁琐。 幸运的是,已经有一个库可以完成这类工作:Gensim。 - -## 使用 Gensim 探索嵌入 - -我将使用我们的模型的电影嵌入和相应电影的标题,来实例化`WordEmbeddingsKeyedVectors`。 - -> 注:你可能会注意到,Gensim 的文档及其许多类和方法名称都指的是词嵌入。 虽然库最常用于文本领域,但我们可以使用它来探索任何类型的嵌入。 - -```py -from gensim.models.keyedvectors import WordEmbeddingsKeyedVectors - -# 将数据集中的电影限制为至少具有这么多评分 -threshold = 100 -mainstream_movies = movies_df[movies_df.n_ratings >= threshold].reset_index(drop=True) - -movie_embedding_size = w.shape[1] -kv = WordEmbeddingsKeyedVectors(movie_embedding_size) -kv.add( - mainstream_movies['key'].values, - w[mainstream_movies.movieId] -) -``` - -好的,哪个电影与《玩具总动员》最相似? - -```py -kv.most_similar('Toy Story') -''' -/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`. - if np.issubdtype(vec.dtype, np.int): -[('Toy Story 2', 0.9583659172058105), - ('Toy Story 3', 0.9159570932388306), - ('Finding Nemo', 0.882755696773529), - ('Monsters, Inc.', 0.8684015870094299), - ("A Bug's Life", 0.8322919607162476), - ('The Incredibles', 0.8271597623825073), - ('Ratatouille', 0.8149864673614502), - ('Up', 0.802034318447113), - ('WALL·E', 0.7794805765151978), - ('The Iron Giant', 0.7664535641670227)] -''' -``` - -哇,这些都很棒! 《玩具总动员 2》是与玩具总动员最相似的电影,这是完全合理的。 其余大多数都是具有类似计算机动画风格的动画儿童电影。 - -所以它学到了关于三维动画儿童电影的一些东西,但也许这只是一个侥幸。 让我们来看看几个不同类型的电影的最近邻居: - -``` -/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`. - if np.issubdtype(vec.dtype, np.int): -``` - -![](/img/learn/embeddings/emb-6.png) - -小众的性爱剧,风骚的半吊子喜剧,老派音乐剧,超级英雄电影......我们的嵌入能够支持各种各样的电影类型! - -### 语义向量数学 - -`most_similar`方法接受可选的第二个参数`negative`。 如果我们调用`kv.most_similar(a, b)`,那么它将找到最接近`a-b`的向量,而不是找到最接近`a`的向量。 - -你为什么想这么做? 事实证明,对嵌入向量进行加法和减法通常会产生令人惊讶的有意义的结果。 例如,你将如何填写以下等式? - -``` -Scream = Psycho + ________ -``` - -Scream 和 Psycho 的相似之处在于它们是恐怖片和惊悚片之间的某个地方的暴力恐怖电影。 最大的区别是 Scream 有喜剧元素。 因此,如果你将 Psycho 与喜剧结合起来,我会说 Scream 就是你所得到的。 - -但我们实际上可以通过向量数学(在重新排列之后)让 Gensim 为我们填补空白: - -``` -________ = Scream - Psycho -``` - -```py -kv.most_similar( - positive = ['Scream'], - negative = ['Psycho (1960)'] -) -''' -/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`. - if np.issubdtype(vec.dtype, np.int): -[('Scream 3', 0.6535503268241882), - ('Scream 2', 0.6417772769927979), - ('Piranha (Piranha 3D)', 0.6411199569702148), - ('Freddy vs. Jason', 0.6275623440742493), - ('Final Destination 5', 0.6264907121658325), - ('Booty Call', 0.6207411289215088), - ("Charlie's Angels", 0.6146069765090942), - ('Mortal Kombat', 0.6145076155662537), - ('Deuce Bigalow: Male Gigolo', 0.6140967607498169), - ('Final Destination 2', 0.612423300743103)] -''' -``` - -如果你熟悉这些电影,你会发现,从 Psycho 到 Scream 的缺失成分是喜剧(也是 90 年代后期的青少年电影)。 - -### 类比解决 - -用于进入美国大学和学院的 SAT 考试提出了类似的问题: - -``` -shower : deluge :: _____ : stare -``` - -(意思是“shower”(淋浴)对于“deluge”(洪水),相当于“_____”对于“stare”(凝视)) - -为了解决这个问题,我们找到了“deluge”和“shower”之间的关系,并将其应用于“stare”。 “shower”是一种温和的“deluge”形式。 什么是温和的“stare”的形式? 这里一个好的答案是“glance”(一瞥)或“look”(看)。 - -令人惊讶的是,这种方法很有效,但人们发现这些通常可以通过单词嵌入的简单向量数学来有效地解决。 我们可以通过嵌入来解决电影类比问题吗? 我们试试吧。这样如何: - -``` -Brave : Cars 2 :: Pocahontas : _____ -``` - -答案不明确。 一种解释是,《勇敢传说》(Brave)就像《赛车总动员 2》(Cars 2),除了后者主要针对男孩,而前者可能对女孩更具吸引力,因为它是女性主角。 所以也许答案应该像《风中奇缘》(Pocahontas)一样,90 年代中期的传统动画儿童电影,但更像是一部“男孩电影”。《大力士》?《狮子王》? - -让我们问一下他们的想法。 - -在向量数学方面,我们可以将其构建为...... - -``` -Cars 2 = Brave + X -_____ = Pocahontas + X -``` - -重新排列之后,我们得到: - -``` -____ = Pocahontas + (Cars 2 - Brave) -``` - -我们可以通过将两部电影(《风中奇缘》和《赛车总动员 2》)传递给`most_similar`的`positive`,将《勇敢传说》作为`negative`参数,来解决这个问题: - -```py -kv.most_similar( - ['Pocahontas', 'Cars 2'], - negative = ['Brave'] -) -''' -/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`. - if np.issubdtype(vec.dtype, np.int): -[("A Kid in King Arthur's Court", 0.8660464882850647), - ('Land Before Time III: The Time of the Great Giving', 0.8655920624732971), - ('Free Willy 2: The Adventure Home', 0.8606677651405334), - ('3 Ninjas Knuckle Up', 0.8496973514556885), - ('3 Ninjas Kick Back', 0.8479241132736206), - ('The Return of Jafar', 0.8474882245063782), - ("Beethoven's 2nd", 0.8443870544433594), - ('Air Bud: Golden Receiver', 0.84358811378479), - ('Meet the Deedles', 0.8370730876922607), - ('All Dogs Go to Heaven 2', 0.8368842601776123)] -''' -``` - -这与我们的预测无关:4 部最接近的电影确实是 90 年代的儿童动画电影。 在那之后,结果有点令人困惑。 - -我们的模型是错的,还是我们是错的? 在《赛车总动员 2》和《勇敢传说》之间,我们未能解释的另一个区别是前者是续集,而后者则不是。 我们的结果中有 7/10 也是续集。 这告诉我们关于我们学习的嵌入的一些有趣内容(最终,关于预测电影偏好的问题)。 “Sequelness”是我们模型的一个重要特性 - 这表明我们数据中的一些变化,是因为有些人倾向于比其他人更喜欢续集。 - -### 你的回合 - -前往[练习笔记本](https://www.kaggle.com/kernels/fork/1598893),进行一些动手实践,使用 gensim 探索嵌入。 - -## 四、将 t-SNE 用于可视化 - -在上一课中,我们查看了我们学习的电影嵌入的一些示例,测量了电影对之间的距离,查找了与某些电影最相似的电影,并且通过向量数学组合了电影语义。 这些是调试嵌入模型或理解嵌入模型的好方法。 但它也非常耗时。 - -在本课程中,你将学习如何使用 t-SNE 算法可视化嵌入。 这是一种很好的廉价技术,用于理解嵌入的本质。 - -### t-SNE - -可视化 1 维或 2 维的数据很容易 - 但目前尚不清楚如何可视化 8 维或 32 维的嵌入。 t-SNE 是一种降维算法,通常用于可视化。 它学习从一组高维向量到较小维数(通常为 2)的空间映射,这有望很好地表示高维空间。 - -是什么让映射成为“良好的表示”? 简而言之,t-SNE 试图确保如果高维向量`u`和`v`靠近在一起,则`map(u)`和`map(v)`在 2d 映射空间中靠近在一起。 - -### 代码 - -首先,我们将加载我们的预训练嵌入,就像之前一样。 - -```py -%matplotlib inline -import random -import os - -import numpy as np -import pandas as pd -from matplotlib import pyplot as plt -import tensorflow as tf -from tensorflow import keras - -input_dir = '../input/movielens-preprocessing' -model_dir = '../input/movielens-spiffy-model' -model_path = os.path.join(model_dir, 'movie_svd_model_32.h5') - -model = keras.models.load_model(model_path) -emb_layer = model.get_layer('movie_embedding') -(w,) = emb_layer.get_weights() - -movies_path = os.path.join(input_dir, 'movie.csv') -movies_df = pd.read_csv(movies_path, index_col=0) -``` - -正如我们在前面的课程中看到的那样,我们的数据集中有很多不起眼的电影,评分很少(有时只有一个)。 我们对这些电影知之甚少,因为它们的嵌入效果和随机一样。 我们可以通过仅仅选择满足一定流行度阈值的电影,来弄清楚我们的可视化。 - -```py -threshold = 100 -mainstream_movies = movies_df[movies_df.n_ratings >= threshold].reset_index(drop=True) -print("Went from {} to {} movies after applying threshold".format( - len(movies_df), len(mainstream_movies), -)) -w_full = w -w = w[mainstream_movies.movieId] -df = mainstream_movies -# 在应用阈值后,电影从 26744 变为 8546 部 -``` - -我们将使用 scikit-learn 的 t-SNE 实现。 - -我提到 t-SNE 在特征空间中试图保持实体之间的“接近度”。 我们在之前的课程中看到,有许多竞争性的距离概念。 默认情况下,t-SNE 使用欧氏距离。 但是因为已知余弦距离适用于嵌入,我们将在创建模型时传递`metric ="cosine"`。 - -```py -from sklearn.manifold import TSNE - -# 1,000 次迭代的默认值可以得到很好的结果, -# 但是我的训练时间更长,只是为了一些微小的改进。 -# 注意:这需要近一个小时! -tsne = TSNE(random_state=1, n_iter=15000, metric="cosine") - -embs = tsne.fit_transform(w) -# 为方便起见,添加到数据帧 -df['x'] = embs[:, 0] -df['y'] = embs[:, 1] -``` - -这是我们将电影映射到的二维向量样本: - -```py -embs[:5] -''' -array([[ -93.78184 , 74.296936 ], - [ -78.09159 , -107.294334 ], - [ 27.506392 , -73.33844 ], - [ -7.8512335, -82.217896 ], - [ -10.345706 , -71.288704 ]], dtype=float32) -''' -``` - -这种降维的全部意义在于可视化,所以让我们使用 matplotlib 绘制我们电影的散点图,使用我们新的二维映射。 - -```py -FS = (10, 8) -fig, ax = plt.subplots(figsize=FS) -# 使点变得半透明,以便我们可以直观地识别具有高密度重叠点的区域 -ax.scatter(df.x, df.y, alpha=.1); -``` - -![](/img/learn/embeddings/emb-7.png) - -### 它有效嘛 - -单凭形状很难判断。 良好的理智检查是识别,我们强烈认为应该靠近的一些电影分组,看看它们是否在二维空间中接近。 - -例如,所有的哈利波特电影都应该互相接近,对吧? - -```py -# 这个和其他几个辅助函数在上面的代码单元中定义。 -# 如果你对它们的实现方式感到好奇,请点击上面的“代码”按钮。 -plot_by_title_pattern('Harry Potter', figsize=(15, 9), bg_alpha=.05, text=False); -``` - -![](/img/learn/embeddings/emb-8.png) - -上面的绘图中,8 个哈利波特电影中的每一个都有一个绿点 - 但它们是如此接近,它们无法在这个刻度上区分。 是个好的标志! - -让我们放大一下,仔细看看。 - -```py -plot_region_around('Harry Potter and the Order of the Phoenix', 4); -``` - -![](/img/learn/embeddings/emb-9.png) - -哈利波特的电影不仅紧密聚集在一起,而且大致按发布顺序排列! - -### 局部和全局结构 - -t-SNE 的一个关键特性使它非常适合可视化,它擅长在多个尺度上捕获簇。 我们已经看到,我们的映射成功捕获了小而紧凑的局部结构。 那些包含更多松散的相关电影的大型结构呢? - -我们在上面已经看到了这方面的一个小例子:与哈利波特电影最接近的邻居是饥饿游戏系列的电影 - 另一组基于一系列青年幻想小说的电影。这说得通! - -小众流派如何? 纪录片落在哪里? - -```py -docs = df[ (df.genres == 'Documentary') ] -plot_with_annotations(docs.index, text=False, alpha=.4, figsize=(15, 8)); -``` - -![](/img/learn/embeddings/emb-10.png) - -太好了! 它不是一个紧密的簇,但这里肯定有较强的规律。 - -并且重申一下:我们从未真正将类型展示给模型作为特征。 它无法读取标题,并看到《哈利波特和魔法石》和《哈利波特和密室》属于同一系列。 它设法获取这些潜在的模式并将它们合并到嵌入空间中,只需看到数据点,例如“用户 5299 给电影 806 评分为 4.5”。 非常好! - -这是另一个稍微复杂的类型实验:可视化所有电影,其类型是`{喜剧,戏剧,浪漫}`的一部分(即喜剧,戏剧,浪漫,戏剧,浪漫剧,romcoms 和......我猜是“dromcoms”?) - -![](/img/learn/embeddings/emb-11.png) - -这是最大规模的结构的一个很棒的例子。 戏剧主要在上半部分,而喜剧主要在另一半(浪漫片的分布更加分散)。 - -### 你的回合 - -前往[练习笔记本](https://www.kaggle.com/kernels/fork/1599029)进行一些实践练习,使用 t-SNE 可视化嵌入。 - -## 扩展阅读 - -我们使用 t-SNE 模型的开箱即用的默认参数取得了良好的效果,但根据你的数据特征,你可能不会那么幸运。 - -t-SNE 不是简单的闭式数学运算。 你正在训练模型,使用随机梯度下降来最小化一些非凸损失函数。 可能需要一段时间,需要一点折腾。 你甚至可以在使用相同参数训练的两个 t-SNE 模型之间看到非常不同的结果(如果你想要可重复性,则设置固定的`random_state`)。 - -如果你在尝试训练 t-SNE 模型时得到的结果不令人满意,或者你只是想了解更多数学基础和实现,那么下面的链接会提供一些你可能会觉得有用的信息。 - -+ 如果你对 t-SNE 的更深入的数学细节感兴趣,我强烈建议你查看 [Laurens van der Maaten 和 Geoff Hinton 向世界介绍 t-SNE 的原始论文](http://www.jmlr.org/papers/volume9/vandermaaten08a/vandermaaten08a.pdf)。 -+ [如何使用 t-SNE](https://distill.pub/2016/misread-tsne/) 有效地展示了一些令人难以置信的实时交互式示例,允许你将 t-SNE 应用于各种合成数据集并实时观察训练,并看到改变参数的效果,例如 perplexity。 -+ [sklearn TSNE 文档](http://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html)提供了每个参数含义的详细信息,以及一些设置它们的提示。 - + 另请参阅:[scikit-learn 的 t-SNE 用户指南](http://scikit-learn.org/stable/modules/manifold.html#t-sne) -+ [t-SNE FAQ](https://lvdmaaten.github.io/tsne/#faq) 由 Laurens van der Maaten 撰写 diff --git a/docs/Kaggle/learn/intermediate-machine-learning/1.md b/docs/Kaggle/learn/intermediate-machine-learning/1.md deleted file mode 100644 index 1299db9f..00000000 --- a/docs/Kaggle/learn/intermediate-machine-learning/1.md +++ /dev/null @@ -1,31 +0,0 @@ -# Kaggle 官方教程:机器学习中级1 课程介绍 -> 原文:[Intermediate Machine Learning](https://www.kaggle.com/learn/intermediate-machine-learning) > [Introduction](https://www.kaggle.com/alexisbcook/introduction) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -## 1、课程介绍 -欢迎来到Kaggle Learning《机器学习中级》微课程! - -如果你有一些机器学习的基础,并且你想学习如何快速提高模型的质量,那么你就来对地方了!在这个微型课程中,你将学习如何: - - - 处理现实数据集中常见的数据类型(`缺失的值、分类变量`), - - 设计`pipelines`来提高机器学习代码的质量, - - 使用先进的技术进行模型验证(`交叉验证`), - - 建立最先进的模型,广泛用于赢得Kaggle比赛(`XGBoost`),和 - - 避免常见和重要的数据科学错误(`泄漏`)。 - -在此过程中,你将通过使用各个新主题的真实数据完成实际操作来巩固你的知识。实际操作数据来自于赛题 [Housing Prices Competition for Kaggle Learn Users](https://www.kaggle.com/c/home-data-for-ml-course), 你将使用79个不同的统计变量(如屋顶类型、卧室数量和浴室数量)来预测房价。通过提交预测结果,观察你在排行榜上的名次上升! - -![在这里插入图片描述](/img/learn/intermediate-machine-learning/1.1.png) - -## 2、先决条件 -如果你以前构建过机器学习模型,并且熟悉模型验证、欠拟合和过拟合以及随机森林等主题,那么你已经为这门微型课程做好了准备。 - -如果你对机器学习完全陌生,请学习我们的微课程[《机器学习入门》](https://leytton.blog.csdn.net/article/details/101154693),它涵盖了机器学习的基础知识。 - -## 3、去吧,皮卡丘 -继续[第一个练习](https://www.kaggle.com/kernels/fork/3370272),学习如何向Kaggle竞赛提交预测结果,并确定在开始之前可能需要检查的内容。 \ No newline at end of file diff --git a/docs/Kaggle/learn/intermediate-machine-learning/2.md b/docs/Kaggle/learn/intermediate-machine-learning/2.md deleted file mode 100644 index 2b887ecb..00000000 --- a/docs/Kaggle/learn/intermediate-machine-learning/2.md +++ /dev/null @@ -1,166 +0,0 @@ -# Kaggle 官方教程:机器学习中级2 缺失值处理 -> 原文:[Intermediate Machine Learning](https://www.kaggle.com/learn/intermediate-machine-learning) > [Missing Values](https://www.kaggle.com/alexisbcook/missing-values) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -在本课程中,你将学习三种处理缺失值的方法。然后使用实际数据集比较这些方法的效果。 - -## 1、介绍 - -造成数据丢失的原因有很多。例如, - -- 两间卧室的房子不包括第三间卧室的价值。 -- 调查对象可能选择不分享其收入。 - -大多数机器学习库(包括`scikit-learn`)在试图使用缺失值的数据构建模型时都会出现错误。因此,你需要选择下面的策略之一。 - -## 2、三种方法 -**1) 一个简单的选择:删除缺少值的列** - -最简单的选择是删除缺少值的列。 - -![tut2_approach1](/img/learn/intermediate-machine-learning/2.1.png) - -除非删除列中的大多数值都丢失了,否则使用这种方法将丢失许多潜在价值的信息。举个极端的例子,假如有一个10,000行的数据集,其中一个重要的列缺少一条数据。这种方法将完全删除该列! - -**2) 一个更好的选择:填充** - -用一些数字填充缺失的值。例如,我们可以用平均值填充。 - -![在这里插入图片描述](/img/learn/intermediate-machine-learning/2.2.png) - -在大多数情况下,填充的值不一定正确,但它通常会比完全删除该列数据要好。 - -**3) 填充扩展** - -`填充`是标准的方法,通常效果很好。然而,填充的值可能高于或低于实际值(数据集中没有收集这些值)。或者缺少值的行在某些方面可能是唯一的。在这种情况下,你的模型将考虑哪些值是最初丢失的,从而做出更好的预测。 - -![在这里插入图片描述](/img/learn/intermediate-machine-learning/2.3.png) - -在这种方法中,我们像以前一样输入缺失的值。此外,新增一列用于记录哪条数据是缺失填充的。 - -在某些情况下,这将非常有效。但某些情况,这没有一点用。 - -## 3、案例 - -在本例中,我们将使用 [Melbourne Housing](https://www.kaggle.com/dansbecker/melbourne-housing-snapshot/home) 数据集。我们的模型将使用房间数量和土地面积等信息来预测房价。 - -我们不会关注数据加载步骤。相反,你可以想象你已经拥有了`X_train`、`X_valid`、`y_train`和`y_valid`中的训练和验证数据。 - -**定义函数来评估每种方法的效果** - -我们定义了一个函数`score_dataset()`来比较处理缺失值的不同方法。该函数计算`随机森林模型`的`平均绝对误差(MAE)`。 - -**方法1的得分(删除缺少值的列)** - -由于我们同时处理训练集和验证集,所以要注意在两个数据框中删除相同的列。 - -```python -# 获取缺少值的列名称 -cols_with_missing = [col for col in X_train.columns - if X_train[col].isnull().any()] - -# 删除训练和验证数据中的列 -reduced_X_train = X_train.drop(cols_with_missing, axis=1) -reduced_X_valid = X_valid.drop(cols_with_missing, axis=1) - -print("MAE from Approach 1 (Drop columns with missing values):") -print(score_dataset(reduced_X_train, reduced_X_valid, y_train, y_valid)) -``` -输出结果: -``` -MAE from Approach 1 (Drop columns with missing values): -183550.22137772635 -``` -**方法2得分(填充)** - -接下来,我们使用`SimpleImputer`用每一列的平均值填充缺失的值。 - -虽然它很简单,但是填充平均值的方法通常很好用(不同数据集有所差异)。尽管统计学家已经尝试了更复杂的方法来确定填充值(例如回归填充),但一旦将结果插入复杂的机器学习模型,这些复杂的策略通常不会带来额外的好处。 - -```python -from sklearn.impute import SimpleImputer - -# 填充 -my_imputer = SimpleImputer() -imputed_X_train = pd.DataFrame(my_imputer.fit_transform(X_train)) -imputed_X_valid = pd.DataFrame(my_imputer.transform(X_valid)) - -# 填充移除了列名;补回来 -imputed_X_train.columns = X_train.columns -imputed_X_valid.columns = X_valid.columns - -print("MAE from Approach 2 (Imputation):") -print(score_dataset(imputed_X_train, imputed_X_valid, y_train, y_valid)) -``` -输出结果: -``` -MAE from Approach 2 (Imputation): -178166.46269899711 -``` -我们看到方法2的`MAE`比方法1低,所以方法2在这个数据集中表现得更好。 - - -**方法3得分(填充扩展)** - -接下来,我们填充缺失的值,同时记录哪些值是填充的。 -```python -# Make copy to avoid changing original data (when imputing) -X_train_plus = X_train.copy() -X_valid_plus = X_valid.copy() - -# Make new columns indicating what will be imputed -for col in cols_with_missing: - X_train_plus[col + '_was_missing'] = X_train_plus[col].isnull() - X_valid_plus[col + '_was_missing'] = X_valid_plus[col].isnull() - -# Imputation -my_imputer = SimpleImputer() -imputed_X_train_plus = pd.DataFrame(my_imputer.fit_transform(X_train_plus)) -imputed_X_valid_plus = pd.DataFrame(my_imputer.transform(X_valid_plus)) - -# Imputation removed column names; put them back -imputed_X_train_plus.columns = X_train_plus.columns -imputed_X_valid_plus.columns = X_valid_plus.columns - -print("MAE from Approach 3 (An Extension to Imputation):") -print(score_dataset(imputed_X_train_plus, imputed_X_valid_plus, y_train, y_valid)) -``` -输出结果: -``` -MAE from Approach 3 (An Extension to Imputation): -178927.503183954 -``` - -正如我们所看到的,方法3的效果略差于方法2。 - -**那么,为什么填充比删除列更好呢?** - -训练数据有10864行和12列,其中3列包含丢失的数据。对于每一列,缺少的条目不到一半。因此,删除列会删除很多有用的信息,因此填充方法效果会更好。 - -```python -# Shape of training data (num_rows, num_columns) -print(X_train.shape) - -# Number of missing values in each column of training data -missing_val_count_by_column = (X_train.isnull().sum()) -print(missing_val_count_by_column[missing_val_count_by_column > 0]) -``` -输出结果: -``` -(10864, 12) -Car 49 -BuildingArea 5156 -YearBuilt 4307 -dtype: int64 -``` -## 4、结论 -一般来说,比起简单地删除具有缺失值的列(在方法1中),填充缺失值(在方法2和方法3中)会得到更好的效果。 - -## 5、去吧,皮卡丘 -在[练习中](https://www.kaggle.com/kernels/fork/3370280)比较处理缺失值的方法。 - diff --git a/docs/Kaggle/learn/intermediate-machine-learning/3.md b/docs/Kaggle/learn/intermediate-machine-learning/3.md deleted file mode 100644 index 6575ba24..00000000 --- a/docs/Kaggle/learn/intermediate-machine-learning/3.md +++ /dev/null @@ -1,200 +0,0 @@ -# Kaggle 官方教程:机器学习中级3 分类变量 -> 原文:[Intermediate Machine Learning](https://www.kaggle.com/learn/intermediate-machine-learning) > [Categorical Variables](https://www.kaggle.com/alexisbcook/categorical-variables) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -在本教程中,你将了解什么是分类变量,以及处理这类数据的三种方法。 -## 1、介绍 -分类变量类似于枚举,拥有特定数量的值类型。 - - - 比如一项调查,询问你多久吃一次早餐,并提供四个选项:“从不”、“很少”、“大多数日子”或“每天”。在本例中,数据是分类的,因为答案属于一组固定的类别。 - - - 如果对人们所拥有的汽车品牌进行调查,回答可以分为“本田”、“丰田”和“福特”。在本例中,数据也是分类的。 - -如果您没有预处理这些分类变量,就将这些变量应用于机器学习模型中,大多数情况您将得到一个错误结果。在本教程中,我们将比较三种预处理分类数据的方法。 - -## 2、三种方法 -**1) 删除分类变量** -处理分类变量最简单的方法是从数据集中删除它们。这种方法适用于该列中不包含有用信息的情况。 - -**2) 标签编码** -标签编码将每个变量类型标记为不同的整数。 - -![在这里插入图片描述](/img/learn/intermediate-machine-learning/3.1.png) - -这种方法假设类别的顺序为:“Never”(0)<“rare”(1)<“Most days”(2)<“Every day”(3)。 - -在本例中,这个假设是有意义的,因为对类别有个唯一的排名。 并不是所有的分类变量在值中都有一个明确的顺序,但是我们将那些有顺序的变量称为`有序变量`。对于基于树的模型(如决策树和随机森林),有序变量的标签编码可能效果不错。 - -**3) One-Hot 编码** - -“One-hot”编码创建新列,表明原始数据中每个可能值的存在(或不存在)。为了说明这点,我们举个例子: - -![在这里插入图片描述]((/img/learn/intermediate-machine-learning/3.2.png)) - -在原始数据集中,“Color”是一个分类变量,包含“Red”、“Yellow”和“Green”三个类别。对应的`one-hot编码`是每个可能的值各自作为一列,原始数据集中的每一行作为一行。当原始值为“Red”时,我们在“Red”列中放入1;如果原始值是“Yellow”,则在“Yellow”列中放入1,以此类推。 - -与`标签编码`不同,`one-hot编码`不假定类别的顺序。因此,如果在分类数据中没有明确的顺序(例如,“红色”既不比“黄色”多也不比“黄色”少),这种方法可能会特别有效。我们把没有内在排序的分类变量称为`名义变量`。 - -如果分类变量具有大量不同的值(超过15个),效果将不会很好。 - -## 3、案例 -像前一篇教程一样,我们将使用 [Melbourne Housing数据集](https://www.kaggle.com/dansbecker/melbourne-housing-snapshot/home)。 - -我们不会关注数据加载步骤。假设您已经拥有了`X_train`、`X_valid`、`y_train`和`y_valid`中的训练和验证数据。 - -```python -import pandas as pd -from sklearn.model_selection import train_test_split - -# Read the data -data = pd.read_csv('../input/melbourne-housing-snapshot/melb_data.csv') - -# Separate target from predictors -y = data.Price -X = data.drop(['Price'], axis=1) - -# Divide data into training and validation subsets -X_train_full, X_valid_full, y_train, y_valid = train_test_split(X, y, train_size=0.8, test_size=0.2, - random_state=0) - -# Drop columns with missing values (simplest approach) -cols_with_missing = [col for col in X_train_full.columns if X_train_full[col].isnull().any()] -X_train_full.drop(cols_with_missing, axis=1, inplace=True) -X_valid_full.drop(cols_with_missing, axis=1, inplace=True) - -# "Cardinality" means the number of unique values in a column -# Select categorical columns with relatively low cardinality (convenient but arbitrary) -low_cardinality_cols = [cname for cname in X_train_full.columns if X_train_full[cname].nunique() < 10 and - X_train_full[cname].dtype == "object"] - -# Select numerical columns -numerical_cols = [cname for cname in X_train_full.columns if X_train_full[cname].dtype in ['int64', 'float64']] - -# Keep selected columns only -my_cols = low_cardinality_cols + numerical_cols -X_train = X_train_full[my_cols].copy() -X_valid = X_valid_full[my_cols].copy() -``` -我们使用下面的`head()`方法查看训练数据。 -```python -X_train.head() -``` -输出结果: -``` - Type Method Regionname Rooms Distance Postcode Bedroom2 Bathroom Landsize Lattitude Longtitude Propertycount -12167 u S Southern Metropolitan 1 5.0 3182.0 1.0 1.0 0.0 -37.85984 144.9867 13240.0 -6524 h SA Western Metropolitan 2 8.0 3016.0 2.0 2.0 193.0 -37.85800 144.9005 6380.0 -8413 h S Western Metropolitan 3 12.6 3020.0 3.0 1.0 555.0 -37.79880 144.8220 3755.0 -2919 u SP Northern Metropolitan 3 13.0 3046.0 3.0 1.0 265.0 -37.70830 144.9158 8870.0 -6043 h S Western Metropolitan 3 13.3 3020.0 3.0 1.0 673.0 -37.76230 144.8272 4217.0 -``` -接下来,我们获得训练数据中所有分类变量的列。 - -我们通过检查每个列的数据类型(或`dtype`)来做到这一点。`object` 类型表示改列存在文本(理论上它还可以是其他东西,但对于我们的目的来说并不重要)。对于这个数据集,带有文本的列表示分类变量。 -```python -# Get list of categorical variables -s = (X_train.dtypes == 'object') -object_cols = list(s[s].index) - -print("Categorical variables:") -print(object_cols) -``` -输出结果: -``` -Categorical variables: -['Type', 'Method', 'Regionname'] -``` - -**定义函数来评估每种方法的效果** - -我们定义了一个函数`score_dataset()`来比较处理分类变量的不同方法。该函数计算`随机森林模型`的`平均绝对误差(MAE)`。一般来说,我们希望`MAE`越低越好! - -**方法1的得分(删除分类变量)** - -我们使用`select_dtypes()`方法删除对象列。 -```python -drop_X_train = X_train.select_dtypes(exclude=['object']) -drop_X_valid = X_valid.select_dtypes(exclude=['object']) - -print("MAE from Approach 1 (Drop categorical variables):") -print(score_dataset(drop_X_train, drop_X_valid, y_train, y_valid)) -``` -``` -MAE from Approach 1 (Drop categorical variables): -175703.48185157913 -``` -**方法2的得分(标签编码)** - -`Scikit-learn`有一个`LabelEncoder`类,可以用来获取标签编码。我们循环遍历分类变量,并将标签编码器分别应用于每一列。 -```python -from sklearn.preprocessing import LabelEncoder - -# 复制一份数据防止改变源数据 -label_X_train = X_train.copy() -label_X_valid = X_valid.copy() - -# 将标签编码器分别应用于每一列 -label_encoder = LabelEncoder() -for col in object_cols: - label_X_train[col] = label_encoder.fit_transform(X_train[col]) - label_X_valid[col] = label_encoder.transform(X_valid[col]) - -print("MAE from Approach 2 (Label Encoding):") -print(score_dataset(label_X_train, label_X_valid, y_train, y_valid)) -``` -``` -MAE from Approach 2 (Label Encoding): -165936.40548390493 -``` -在上面的代码中,对于每个列,我们随机分配一个唯一整数。这是一种比提供自定义标签更简单的常见方法;然而,如果我们为所有有序变量提供更好的信息标签,效果会更好。 - -**方法3的得分((One-Hot编码)** - -我们使用`scikit-learn`的`OneHotEncoder`类来获得`one-hot编码`。有许多参数可定义。 -- 设置`handle_unknown='ignore'`,以避免在验证数据包含训练数据中没有包括的值时发生错误 -- 设置`sparse=False`可以确保将已编码的列作为`numpy数组`(而不是稀疏矩阵)返回。 - -为了使用这个编码器,我们提供了只有分类变量的数据列。举例来说,为了对训练数据进行编码,我们提供了`X_train[object_cols]`(代码中的`object_cols`表示分类变量名称,`X_train[object_cols]`包含了训练数据的所有分类变量)。 -```python -from sklearn.preprocessing import OneHotEncoder - -# 将one-hot编码器分别应用于每一列分类变量 -OH_encoder = OneHotEncoder(handle_unknown='ignore', sparse=False) -OH_cols_train = pd.DataFrame(OH_encoder.fit_transform(X_train[object_cols])) -OH_cols_valid = pd.DataFrame(OH_encoder.transform(X_valid[object_cols])) - -# One-hot编码时移除了index;补回来 -OH_cols_train.index = X_train.index -OH_cols_valid.index = X_valid.index - -# 删除分类列(将替换为One-hot编码),留下编码列 -num_X_train = X_train.drop(object_cols, axis=1) -num_X_valid = X_valid.drop(object_cols, axis=1) - -# 向数值特征添加One-hot编码列 -OH_X_train = pd.concat([num_X_train, OH_cols_train], axis=1) -OH_X_valid = pd.concat([num_X_valid, OH_cols_valid], axis=1) - -print("MAE from Approach 3 (One-Hot Encoding):") -print(score_dataset(OH_X_train, OH_X_valid, y_train, y_valid)) -``` -输出结果: -``` -MAE from Approach 3 (One-Hot Encoding): -166089.4893009678 -``` -## 4、哪种方法最好? -在本案例中,`删除分类变量`(方法1)的性能最差,因为它有最高的`MAE`分数。至于另外两种方法,由于返回的`MAE`分数值非常接近,没有太大差异。 - -通常,`one-hot编码`(方法3)的效果最好,`删除分类变量`(方法1)的效果最差,但还得视情况而定。 - -## 5、结论 -这个世界充满了分类数据。如果您知道如何使用这种常见的数据类型,您将成为一个更高效的数据科学家! - -## 6、去吧,皮卡丘 -把你的新技能运用到下面的[练习中](https://www.kaggle.com/kernels/fork/3370279)! \ No newline at end of file diff --git a/docs/Kaggle/learn/intermediate-machine-learning/4.md b/docs/Kaggle/learn/intermediate-machine-learning/4.md deleted file mode 100644 index 0d804bb1..00000000 --- a/docs/Kaggle/learn/intermediate-machine-learning/4.md +++ /dev/null @@ -1,115 +0,0 @@ -# Kaggle 官方教程:机器学习中级4 Pipeline -> 原文:[Intermediate Machine Learning](https://www.kaggle.com/learn/intermediate-machine-learning) > [Pipelines](https://www.kaggle.com/alexisbcook/pipelines) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -在本教程中,你将学习如何使用`pipeline`来清理你的建模代码。 - -## 1、介绍 -`Pipeline`是一种简单的方法,能让你的数据预处理和建模步骤一步到位。 - -很多数据科学家没有使用`pipeline`来建模,但`pipeline`有很多重要好处。包含: - - 1. 更精简的代码:考虑到数据处理时会造成混乱,使用`pipeline`不需要在每个步骤都特别注意训练和验证数据。 - 2. 更少的Bug:错误应用和忘记处理步骤的概率更小。 - 3. 更易产品化:把模型转化成规模化发布原型是比较难的,再此我们不做过多讨论,但`pipeline`对这个有帮助。 - 4. 模型验证更加多样化:你将会在下一个课程中看到`交叉验证`的案例。 - -## 2、案例 -跟前面教程一样,我们将会使用 [Melbourne Housing 数据集](https://www.kaggle.com/dansbecker/melbourne-housing-snapshot/home) - -我们不会关注数据加载步骤。假设你已经拥有了`X_train`、`X_valid`、`y_train`和`y_valid`中的训练和验证数据。 - -我们先使用`head()`方法瞄一眼训练数据。注意这些数据保护分类数据和缺失数据。使用pipelines将会很方便处理这两者。 -```python -X_train.head() -``` -输出结果: -``` - Type Method Regionname Rooms Distance Postcode Bedroom2 Bathroom Car Landsize BuildingArea YearBuilt Lattitude Longtitude Propertycount -12167 u S Southern Metropolitan 1 5.0 3182.0 1.0 1.0 1.0 0.0 NaN 1940.0 -37.85984 144.9867 13240.0 -6524 h SA Western Metropolitan 2 8.0 3016.0 2.0 2.0 1.0 193.0 NaN NaN -37.85800 144.9005 6380.0 -8413 h S Western Metropolitan 3 12.6 3020.0 3.0 1.0 1.0 555.0 NaN NaN -37.79880 144.8220 3755.0 -2919 u SP Northern Metropolitan 3 13.0 3046.0 3.0 1.0 1.0 265.0 NaN 1995.0 -37.70830 144.9158 8870.0 -6043 h S Western Metropolitan 3 13.3 3020.0 3.0 1.0 2.0 673.0 673.0 1970.0 -37.76230 144.8272 4217.0 -``` -我们通过三个步骤来使用pipelines: - -**步骤1:定义处理步骤** - -与`pipeline`将预处理与建模步骤打包一样,我们使用`ColumnTransformer`类来将不同的步骤打包在一起。下面的代码做了两件事情: - - - 填充缺失数据为`数值`类型(用均值等方法填充数值类型数据) - - 用`one-hot`编码来填充`分类`缺失数据 - -```python -from sklearn.compose import ColumnTransformer -from sklearn.pipeline import Pipeline -from sklearn.impute import SimpleImputer -from sklearn.preprocessing import OneHotEncoder - -# 预处理数值类型数据 -numerical_transformer = SimpleImputer(strategy='constant') - -# 预处理分类数据 -categorical_transformer = Pipeline(steps=[ - ('imputer', SimpleImputer(strategy='most_frequent')), - ('onehot', OneHotEncoder(handle_unknown='ignore')) -]) - -# 将处理步骤打包 -preprocessor = ColumnTransformer( - transformers=[ - ('num', numerical_transformer, numerical_cols), - ('cat', categorical_transformer, categorical_cols) - ]) -``` - -**步骤2:定义模型** - -接下来我们使用熟悉的`RandomForestRegressor`类定义一个`随机森林`模型。 - -```python -from sklearn.ensemble import RandomForestRegressor - -model = RandomForestRegressor(n_estimators=100, random_state=0) -``` -**步骤3:创建和评估Pipeline** - -最后,我们使用`Pipeline`类来定义一个打包预处理和建模步骤的pipeline。这里有些重点需要注意: - - - 使用pipeline,我们预处理训练数据以及拟合模型只有了一行代码。(相反,如果不使用pipeline,我们需要做填充、编码、和模型训练的步骤。如果我们需要同时处理数值和分类变量,这将非常繁琐!) - - 我们在调用`predict()`指令时使用的`X_valid`中包含未经处理的特征值,pipeline会在预测前自动进行预处理。(然而,如果不使用pipeline,在预测前,我们需要记住对验证数据进行预处理)。 - -```python -from sklearn.metrics import mean_absolute_error - -# 在pipeline中打包预处理和建模代码 -my_pipeline = Pipeline(steps=[('preprocessor', preprocessor), - ('model', model) - ]) - -# 预处理训练数据,拟合模型 -my_pipeline.fit(X_train, y_train) - -# 预处理验证数据, 获取预测值 -preds = my_pipeline.predict(X_valid) - -# 评估模型 -score = mean_absolute_error(y_valid, preds) -print('MAE:', score) -``` -输出结果: -``` -MAE: 160679.18917034855 -``` -## 3、结论 -`Pipeline`在机器学习代码清理和规避错误中,尤其是复杂数据预处理的工作流,非常实用。 - -## 4、去吧,皮卡丘 -在接下来的[练习](https://www.kaggle.com/kernels/fork/3370278)中,使用`pipeline`来体验高级数据预处理技术并改善你的预测! - diff --git a/docs/Kaggle/learn/intermediate-machine-learning/5.md b/docs/Kaggle/learn/intermediate-machine-learning/5.md deleted file mode 100644 index a939da82..00000000 --- a/docs/Kaggle/learn/intermediate-machine-learning/5.md +++ /dev/null @@ -1,101 +0,0 @@ -# Kaggle 官方教程:机器学习中级5 交叉验证 -> 原文:[Intermediate Machine Learning](https://www.kaggle.com/learn/intermediate-machine-learning) > [Cross-Validation](https://www.kaggle.com/alexisbcook/cross-validation) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -在本节课程中,你将会学习如何使用交叉验证来评估模型性能。 - -## 1、介绍 -机器学习是一个迭代的过程。 - -您将面临以下选择:使用什么预测变量、使用什么类型的模型、向这些模型提供什么参数等等。目前为止,你使用验证数据(或保留数据)评估模型质量来做出这些选择。 - -但这种方法也有一些缺点。假设你有一个5000行的数据集,通常你会保留大约20%(1000行)的数据作为验证数据。但这再模型评分中会带来随机变化,有时在一组1000行校验数据中表现良好,但在另一个1000行数据集中却不准确。 - -在极端情况下,你可以想象在验证数据集中只有一行数据。如果你比较不同的模型,那么哪一个模型预测效果最好主要取决于运气! - -一般来说,验证数据集越大,评估模型质量中带来的随机性(即“噪音”)越小,越可靠。不幸的是,我们只能从训练数据中取出部分来获取更大的验证数据集,更小的训练数据集意味着更糟糕的模型! - -## 2、什么是交叉验证? -在`交叉验证中`,我们使用不同的数据子集来执行建模过程,以获得模型质量的多个度量。 - -例如,我们可以将数据分成5个部分,每个部分占整个数据集的20%。.在这种情况下,我们将数据分成5个“**folds**”。 - -![tut5_crossval](/img/learn/intermediate-machine-learning/5.1.png) - -然后,我们对每个fold进行一次实验: - - - 在**实验1**中,我们使用第一个fold作为验证(保留)数据集,其他fold为训练数据。这给我们一个基于20%保留数据集的模型质量度量。 - - 在**实验2**中,我们保留第二个fold的数据(其他fold为训练数据)。这将得到第二个模型质量评估结果。 - - 以此类推,使用每个fold作为验证数据集,我们最终得到的模型质量,是基于所有的行数据集(即使我们不同时使用所有行)。 - -## 3、什么时候使用交叉验证? -交叉验证为模型质量提供了更精确的度量,这在您进行大量建模决策时尤为重要。然而,它可能需要更长的时间来运行,因为它评估了多个模型(每个fold一个)。 - -所以,在此权衡之下,什么时候使用每种方法呢? - - - 对于小数据集,额外的计算并不是什么大事,你应该进行交叉验证。 - - 对于较大的数据集,一个验证数据集就够了。你的代码将会执行得更快,有足够的数据就没必要复用数据。 - -并没有一个明确的界限来区数据集是大还是小,但如果你的模型几分钟或更短时间就能跑完,那么久值得使用交叉验证。 - -或者,你可以运行交叉验证,看看每个实验的分数是否接近。如果每个实验都产生相同的结果,一个验证集可能就足够了。 - -## 4、案例 - -我们将会使用前面课程中相同的数据,加载输入数据`X`并输出数据到`y`。 - -然后我们定义一个`pipeline`,使用`填充器`来填充缺失数据,以及`随机森林模型`来做预测。 - -如果不使用 `pipeline`,来交叉验证是非常困难的!使用`pipeline`将会使代码非常简单。 -```python -from sklearn.ensemble import RandomForestRegressor -from sklearn.pipeline import Pipeline -from sklearn.impute import SimpleImputer - -my_pipeline = Pipeline(steps=[('preprocessor', SimpleImputer()), - ('model', RandomForestRegressor(n_estimators=50, - random_state=0)) - ]) -``` -我们使用`cross_val_score() `函数来获取交叉验证评分,通过`cv`参数来设置fold数量。 -```python -from sklearn.model_selection import cross_val_score - -# 乘以-1,因为sklearn计算得到的是负MAE值(neg_mean_absolute_error) -scores = -1 * cross_val_score(my_pipeline, X, y, - cv=5, - scoring='neg_mean_absolute_error') - -print("MAE scores:\n", scores) -``` -输出结果: -``` -MAE scores: - [301628.7893587 303164.4782723 287298.331666 236061.84754543 - 260383.45111427] -``` -`scoring`参数指定了模型质量的度量方法,我们选择`负的平均绝对误差值`,`scikit-learn`文档列出了[可选值](http://scikit-learn.org/stable/modules/model_evaluation.html)。 - -指定负MAE有点奇怪。Scikit-learn有一个约定,大的数字意味着更好的效果。在这里使用负号可以使它们与约定保持一致,尽管在其他地方几乎没有听说过。 - -我们通常需要模型质量的单一度量来比较不同的模型,所以取全部实验的平均值。 -```python -print("Average MAE score (across experiments):") -print(scores.mean()) -``` -输出结果: -``` -Average MAE score (across experiments): -277707.3795913405 -``` -## 5、结论 -使用交叉验证能使模型质量更好,同时代码也更加简洁:注意我们不再需要跟踪每个的训练和验证集。尤其是对于小数据集,这是个很大的提升! - -## 6、去吧,皮卡丘 - -把你的新技能运用到[下一个练习](https://www.kaggle.com/kernels/fork/3370281)中~ diff --git a/docs/Kaggle/learn/intro-to-machine-learning/1.md b/docs/Kaggle/learn/intro-to-machine-learning/1.md deleted file mode 100644 index 4cb2c2cd..00000000 --- a/docs/Kaggle/learn/intro-to-machine-learning/1.md +++ /dev/null @@ -1,50 +0,0 @@ -# Kaggle 官方教程:机器学习入门1 模型是怎样工作的 -> 原文:[Intro to Machine Learning](https://www.kaggle.com/learn/intro-to-machine-learning) > [How Models Work](https://www.kaggle.com/dansbecker/how-models-work) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -## 1、简介 - -我们将首先概述机器学习模型如何工作以及如何使用它们。如果您以前做过统计建模或机器学习,这可能会让您觉得很基础。别担心,我们很快就会建立强大的模型。 - -这门微课程将用以下场景为例来构建模型: - -你的表哥在房地产投机上赚了几百万美元。由于你对数据科学的兴趣,他愿意成为你的商业伙伴。他会提供资金,你负责提供模型来预测各种房子的价值。 - -你问表哥他过去是如何预测房产价值的,他说只是凭直觉。但更多的问题表明,他从过去看到的房子中总结出价格模式,并利用这些模式对他当前考虑的新房做出预测。 - -机器学习也是如此。 我们将从一个叫做决策树的模型开始说起。当然还有更神奇的模型可以提供更准确的预测,但是决策树很容易理解,它们是数据科学中一些最佳模型的基本构件。 - -为了简单起见,我们将从最简单的决策树开始。 - -![First Decision Trees](/img/learn/intro-to-machine-learning/1.1.png) - -如上图所示,它将房子只分为两类。房子的预测价格是同类房子的历史平均价格。 - -我们使用数据来决定如何把房子分成两组,然后再确定每组的预测价格。从数据中捕获模式的这一步骤称为`拟合`或`训练模型`。用于`拟合模型`的数据称为`训练数据`。 - -模型拟合的过程(例如,如何分割数据)比较复杂,我们以后再提。在模型被拟合之后,您可以将其应用于预测新房的价格。 - -## 2、改进决策树 - -以下两种决策树中,哪一种更有可能来自于房子训练数据的拟合? - -![在这里插入图片描述](/img/learn/intro-to-machine-learning/1.2.png) - -左边的决策树可能更有意义,因为它考虑一个事实:卧室多的房子往往比卧室少的房子售价更高。但这个模型没有考虑到影响房价的其他因素,比如卫生间的数量,地段大小,位置等。 - -你可以使用更多`“分叉”`的决策树来考虑其他影响因素,即`“更深”`的树。一个决策树也考虑了每栋房子的总占地面积,看起来可能是这样的: - -![在这里插入图片描述](/img/learn/intro-to-machine-learning/1.3.png) - -只要沿着满足条件的分支进行选择,您可以通过跟踪决策树来预测任何房子的价格。房价将在决策树的底部点得出,我们将这个点叫做`叶节点`。 - -叶子处的分支和值将由数据决定,接下来将检查您用到的数据。 - -## 3、后续 - -接下来我们将详细讲解怎么检查您的数据。 diff --git a/docs/Kaggle/learn/intro-to-machine-learning/2.md b/docs/Kaggle/learn/intro-to-machine-learning/2.md deleted file mode 100644 index b9118c50..00000000 --- a/docs/Kaggle/learn/intro-to-machine-learning/2.md +++ /dev/null @@ -1,44 +0,0 @@ -# Kaggle 官方教程:机器学习入门2 数据探索 -> 原文:[Intro to Machine Learning](https://www.kaggle.com/learn/intro-to-machine-learning) > [Basic Data Exploration](https://www.kaggle.com/dansbecker/basic-data-exploration) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -## 1、使用Pandas熟悉数据 -任何机器学习项目的第一步都是熟悉数据。你可以使用`Pandas`来实现。`Pandas`是数据科学家用来探索和操作数据的主要工具。大多数人在代码中将`panda`简写为`pd`,使用以下代码将其引用: -```python -import pandas as pd -``` -`Pandas`最重要的部分就是`DataFrame`了。`DataFrame`保存了类似表的数据类型,就像Excel中的工作表或SQL数据库中的表。 - -`Pandas`具有强大的函数来实现大部分你想要的数据操作。 - -举个例子,我们来看看澳大利亚墨尔本的房价数据。 -数据文件路径在`../input/melbourne-housing-snapshot/melb_data.csv`。 - -我们使用以下命令来加载和查看数据: -```python -# 文件路径 -melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv' -# 读取并保存数据到DataFrame类型变量melbourne_data -melbourne_data = pd.read_csv(melbourne_file_path) -# 打印数据概览 -melbourne_data.describe() -``` - -![在这里插入图片描述](/img/learn/intro-to-machine-learning/2.1.png) - -## 2、数据描述详解 -如上图所示,结果打印了8个数据。第一个`count`显示有多少个未缺失的数据。缺失值的产生有很多原因。例如,本身只有一间卧室的房子,就不会存在第二间卧室的数据。我们重回数据缺失的主题。 - -第二个值是`mean`,也就是平均值。`std`是标准偏差,它体现了数据分布情况。 - -`min`和 `max` 比较好理解,分别是指`最小值`和`最大值`; - `25%, 50%, 75% `是指,我们将数据从小到大排列,返回25%,50%,75%数据量时的数字。 - -## 3、去吧,皮卡丘 -从[这里](https://www.kaggle.com/kernels/fork/1258954)开启你的编程实战吧~ - diff --git a/docs/Kaggle/learn/intro-to-machine-learning/3.md b/docs/Kaggle/learn/intro-to-machine-learning/3.md deleted file mode 100644 index cc9c03fb..00000000 --- a/docs/Kaggle/learn/intro-to-machine-learning/3.md +++ /dev/null @@ -1,144 +0,0 @@ -# Kaggle 官方教程:机器学习入门3 你的第一个机器学习模型 -> 原文:[Intro to Machine Learning](https://www.kaggle.com/learn/intro-to-machine-learning) > [Your First Machine Learning Model](https://www.kaggle.com/dansbecker/your-first-machine-learning-model) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -## 1、选择建模数据 -原始数据集有太多的干扰变量,难以理解,甚至无法很好地打印出来。如何将这些数据处理为比较精简易懂呢? - -我们先凭直觉选择几个变量。后面的课程将向你展示使用统计技术来自动优选变量。 - -选择变量/列前,我们先来看看数据集中有哪些列,使用`DataFrame`的`columns`属性来实现,代码如下: -```python -import pandas as pd - -melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv' -melbourne_data = pd.read_csv(melbourne_file_path) -melbourne_data.columns -``` -输出结果: -``` -Index(['Suburb', 'Address', 'Rooms', 'Type', 'Price', 'Method', 'SellerG', - 'Date', 'Distance', 'Postcode', 'Bedroom2', 'Bathroom', 'Car', - 'Landsize', 'BuildingArea', 'YearBuilt', 'CouncilArea', 'Lattitude', - 'Longtitude', 'Regionname', 'Propertycount'], - dtype='object') -``` - - - Melbourne 数据集有部分缺失(有些房子没有记录变量。) - - 我们将在后面的教程中学习如何处理缺失值。 - - Iowa 数据没有缺失值。 - - 现在我们将采用最简单的方法,从数据中删除掉数据缺失的房屋。 - - 现在不要太担心这个,代码如下: -```python -# dropna 删除有缺失的数据 (na可以看作是"not available") -melbourne_data = melbourne_data.dropna(axis=0) -``` - -有许多选择数据子集的方法,[《Pandas微课程》](https://www.kaggle.com/learn/pandas)将更深入地介绍这些内容,但目前我们将重点介绍两种方法。 -There are many ways to select a subset of your data. The Pandas Micro-Course covers these in more depth, but we will focus on two approaches for now. - - 1. `点符号`,用来选择`"预测目标"`; - 2. `列数组`, 用来选择`“特性”`。 - - -## 2、选择预测目标 -你可以用`点符号`来获取一个变量。这个单列存储在一个系列中,与只有单列数据的`DataFrame`非常类似。 - -我们将使用点符号来选择要预测的列,这称为预测目标。按照惯例,预测目标我们记为`y`,将房价保存到`y`变量的代码为: -```python -y = melbourne_data.Price -``` - -## 3、选择特征值 -输入到模型中的数据列(稍后用于进行预测)称为“特性”。在我们的例子中,这些数据列是用来确定房价。有时,你将使用除预测目标之外的所有数据列作为特性。但有时候,剔除无效的特征,预测效果会更好。 - -现在,我们将构建一个只包含几个特性的模型。稍后你将看到如何迭代和比较这些使用不同特性构建的模型。 -我们通过在括号内提供列名列表来选择多个特性。列表中的每一项都应该是一个字符串(带引号)。 - -在数据集中提取多个特征列的代码如下(列名称应该是字符串类型): - -```python -melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'Lattitude', 'Longtitude'] -``` -按照惯例,这个数据称为X。 -```python -X = melbourne_data[melbourne_features] -``` -我们快速地用`describe`方法与`head `方法,来查看数据概览: -```python -X.describe() -``` -输出结果: - -![在这里插入图片描述](/img/learn/intro-to-machine-learning/3.1.png) - -```python -X.head() -``` -输出结果: - -![在这里插入图片描述](/img/learn/intro-to-machine-learning/3.2.png) - -使用这些命令可视化地检查数据是数据科学家工作的一个重要部分,你会经常在其中发现值得进一步研究的惊喜。 - ---- -## 4、构建模型 - -你将使用`scikit-learn`库创建模型。编写代码时,这个库被编写为`sklearn`,你将在示例代码中看到。`Scikit-learn` 很容易将处理存储在`DataFrames`中的数据进行建模,是最流行的库。 - -建立和使用模型的步骤如下: - -`定义`: 它将是什么类型的模型?一个决策树吗?还是其他类型的模型?也指定了模型类型的一些参数。 -`拟合: `从提供的数据中捕获模式,这是建模的核心。 -`预测: `表面意思,这个就不说了 -`评估: `确定模型的预测有多准确。 - -下面是一个用`scikit-learn`定义一个`决策树模型`,并用`特性`和`目标`变量进行拟合的例子: -```python -from sklearn.tree import DecisionTreeRegressor - -# 定义模型. 指定一个参数random_state确保每次运行结果一致 -melbourne_model = DecisionTreeRegressor(random_state=1) - -# 拟合模型 -melbourne_model.fit(X, y) -``` -输出结果: -``` -DecisionTreeRegressor(criterion='mse', max_depth=None, max_features=None, - max_leaf_nodes=None, min_impurity_decrease=0.0, - min_impurity_split=None, min_samples_leaf=1, - min_samples_split=2, min_weight_fraction_leaf=0.0, - presort=False, random_state=1, splitter='best') -``` -许多机器学习模型在模型训练中允许一定的随机性。为`random_state`指定一个数字可以确保每次运行得到相同的结果。这被认为是一种很好的做法。你使用任何数字,而模型的质量并不完全取决于你所选择的值。 - -我们现在有了一个拟合的模型,可以用来进行预测。 - -在实践中,你会想要预测即将上市的新房子,而不是我们已经有价格的房子。但我们将对训练数据的前几行进行预测,以了解`predict`函数是如何工作的。 -```python -print("Making predictions for the following 5 houses:") -print(X.head()) -print("The predictions are") -print(melbourne_model.predict(X.head())) -``` -输出结果: -``` -Making predictions for the following 5 houses: - Rooms Bathroom Landsize Lattitude Longtitude -1 2 1.0 156.0 -37.8079 144.9934 -2 3 2.0 134.0 -37.8093 144.9944 -4 4 1.0 120.0 -37.8072 144.9941 -6 3 2.0 245.0 -37.8024 144.9993 -7 2 1.0 256.0 -37.8060 144.9954 -The predictions are -[1035000. 1465000. 1600000. 1876000. 1636000.] -``` -## 5、去吧,皮卡丘 -在[模型构建练习](https://www.kaggle.com/kernels/fork/400771)中自己尝试一下~ - diff --git a/docs/Kaggle/learn/intro-to-machine-learning/4.md b/docs/Kaggle/learn/intro-to-machine-learning/4.md deleted file mode 100644 index ac927c86..00000000 --- a/docs/Kaggle/learn/intro-to-machine-learning/4.md +++ /dev/null @@ -1,114 +0,0 @@ -# Kaggle 官方教程:机器学习入门4 模型验证 -> 原文:[Intro to Machine Learning](https://www.kaggle.com/learn/intro-to-machine-learning) > [Model Validation](https://www.kaggle.com/dansbecker/model-validation) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -你已经建立了一个模型。但是它好不好呢? -在本节课中,你将学习使用模型验证来度量模型的质量。度量模型质量是迭代改进模型的关键。 - -## 1、什么是模型验证 -你将需要评估几乎所有构建的模型。在大多数应用程序中,模型质量的相关度量是预测精度。换言之,模型预测结果是否接近实际发生情况。 - -`许多人在测量预测精度时犯了一个巨大的错误。他们用训练数据进行预测,并将预测结果与训练数据中的目标值进行比较。`你很快就会发现这个弊端并且学习如何解决它,先让我们想一下该怎么做吧。 - -你首先需要以一种可理解的方式总结模型质量。如果你比较10000套房子的预测和实际房价,你可能会发现好坏参半。浏览10000个预测值和实际值的数据是没有意义的。我们需要将其总结为一个单一的度量。 - -总结模型质量有许多度量标准,但我们将从一个称为`平均绝对误差(Mean Absolute Error,也称为MAE)`的度量标准开始。让我们从最后一个单词`error`开始分析这个度量。 - -每栋房子的预测误差为: -``` -error = actual − predicted -``` -所以,如果一栋房子实际售价15万美元,而你预测它的售价是10万美元,则误差是5万美元。 - -利用MAE度量,我们取每个误差的绝对值,这将把每个误差转换为一个正数。然后取绝对误差的平均值。这就是我们对模型质量的评估。也可以这么说: ->我们的预测平均偏离了X。 - -为了计算MAE,我们首先需要一个模型: - -```python -import pandas as pd - -# 加载数据 -melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv' -melbourne_data = pd.read_csv(melbourne_file_path) -# 过滤缺失数据 -filtered_melbourne_data = melbourne_data.dropna(axis=0) -# 选择预测目标和特征 -y = filtered_melbourne_data.Price -melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'BuildingArea', - 'YearBuilt', 'Lattitude', 'Longtitude'] -X = filtered_melbourne_data[melbourne_features] - -from sklearn.tree import DecisionTreeRegressor -# 定义模型 -melbourne_model = DecisionTreeRegressor() -# 拟合模型 -melbourne_model.fit(X, y) -``` -我们有了一个模型,下面来计算平均绝对误差: -```python -from sklearn.metrics import mean_absolute_error - -predicted_home_prices = melbourne_model.predict(X) -mean_absolute_error(y, predicted_home_prices) -``` -输出数据: -``` -434.71594577146544 -``` -## 2、“样本内”分数问题 -刚刚计算的测量值可以称为“样本内”分数。我们使用了单个的房屋“样本”来构建模型并对其进行评估。这就是弊端产生原因。 - -想象一下,在大型房地产市场中,门的颜色与房价无关。 - -然而,在你用于构建模型的数据样本中,所有带有绿色门的住宅都非常昂贵。该模型的工作是找到预测房价的模式,所以它会看到这种模式,而且总是会将带有绿色门的房子预测为高价。 - -由于这种模式是从训练数据中推导出来的,所以模型在训练数据中会显得比较准确。 -但是,如果模型使用新数据进行预测,这种模式是不成立的,在实际使用中,模型将非常不准确。 - -由于模型的实用价值体现在对新数据的预测,所以我们需要使用没有参与模型构建的数据,来度量模型性能。 -最直接的方法是从模型构建过程中`排除一些数据`,然后使用这些数据来测试模型的准确性。这些数据称为`验证数据`。 - -## 3、编程实现 -`scikit-learn`库有一个函数`train_test_split`,用于将数据分成两部分。我们将使用一部分数据作为训练数据来适应模型,并将使用另一部分数据作为验证数据来计算`mean_absolute_error`。 - -代码如下: -```python -from sklearn.model_selection import train_test_split - -# 将数据分割为训练和验证数据,都有特征和预测目标值 -# 分割基于随机数生成器。为random_state参数提供一个数值可以保证每次得到相同的分割 -# 执行下面代码 -train_X, val_X, train_y, val_y = train_test_split(X, y, random_state = 0) -# 定义模型 -melbourne_model = DecisionTreeRegressor() -# 拟合模型 -melbourne_model.fit(train_X, train_y) - -# 根据验证数据获得预测价格 -val_predictions = melbourne_model.predict(val_X) -print(mean_absolute_error(val_y, val_predictions)) -``` -输出数据: -``` -260585.51323434475 -``` - -## 3、哇! - -样本内数据的平均绝对误差是500美元。样本外价格超过25万美元。 - -这就是一个几乎完全正确的模型和一个不实用模型之间的区别。实际上,验证数据中的平均房屋价值为110万美元。因此,预测误差约为实际平均房价的四分之一。 - -有很多方法可以改进这个模型,比如尝试找到更好的特征或使用不同类型的模型。 - -## 4、去吧,皮卡丘 -在我们考虑改进这个模型之前,请自己尝试[模型验证](https://www.kaggle.com/kernels/fork/1259097)。 - -原文: -https://www.kaggle.com/dansbecker/model-validation \ No newline at end of file diff --git a/docs/Kaggle/learn/intro-to-machine-learning/5.md b/docs/Kaggle/learn/intro-to-machine-learning/5.md deleted file mode 100644 index 7bfde004..00000000 --- a/docs/Kaggle/learn/intro-to-machine-learning/5.md +++ /dev/null @@ -1,95 +0,0 @@ -# Kaggle 官方教程:机器学习入门5 欠拟合与过拟合 -> 原文:[Intro to Machine Learning](https://www.kaggle.com/learn/intro-to-machine-learning) > [Underfitting and Overfitting](https://www.kaggle.com/dansbecker/underfitting-and-overfitting) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -在这一步的最后,你将了解欠拟合和过拟合的概念,并将能够应用这些概念使你的模型更加准确。 - -## 1、尝试不同的模型 - -现在你已经有了一种可靠的方法来度量模型的准确性,你可以使用其他模型进行试验,看看哪个模型的预测效果最好。那么有哪些模型可选择呢? - -你可以在`scikit-learn`的文档中看到,决策树模型有许多选项。最重要的选项决定了树的深度。回想一下这门微课程的第一节课,一棵树的深度是它在做出预测之前进行分裂次数的度量。这是一棵相对较浅的树: - -![在这里插入图片描述](/img/learn/intro-to-machine-learning/5.1.png) - -在实践中,一棵树的顶层(所有的房子)和一片叶子之间有10个分叉是很常见的。随着树越来越深,数据集被分割成具有更少房子的叶子。 - -如果一棵树只有一个分叉,它将数据分成两组。如果每组再分裂一次,我们会得到4组房子。再把它们分成8组。如果我们在每一层增加更多的分叉,使群组数量翻倍,到第10层时,我们将有2^10组房子。即1024片叶子。 - -当我们把房子分成许多片叶子时,每片叶子上的房子也就更少了。叶子上的房子越少,则预测值更接近房子的实际价值。但它们对新数据的预测可能非常不可靠(因为每个预测都只基于少数房子)。 - -这种现象叫做`过拟合`,模型与训练数据几乎完全匹配,但在验证其他新数据方面效果很差。另一方面,如果我们设计的树很浅,它不会把房子分成很明显的组。 - -在极端情况下,如果一棵树只有2或4个分支,则各个叶子仍然有各种各样的房子。这就导致预测房价相差甚远,即使是在训练数据中(由于这个原因,验证结果也会很糟糕)。当一个模型不能捕捉到数据中的重要特征和模式时,它在训练数据时就表现得很差,这称为`欠拟合`。 - -由于我们关心新数据的准确性,根据验证数据估算,我们希望在`欠拟合`和`过拟合`之间找到一个最佳点。在视觉上,我们想要(红色)验证曲线的最低点。 - -![在这里插入图片描述](/img/learn/intro-to-machine-learning/5.2.png) - -## 2、案例 -有几种方法可以控制树的深度,树的一些路径可以比其他路径有更大的深度。但是`max_leaf_nodes`参数提供了一种非常合适的方法来控制`过拟合`和`欠拟合`。我们允许模型生成的叶子越多,在上图中就越接近`过拟合区域`。 - -我们可以使用一个实用函数来比较不同`max_leaf_nodes`值模型的`MAE分数`: -```python -from sklearn.metrics import mean_absolute_error -from sklearn.tree import DecisionTreeRegressor - -def get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y): - model = DecisionTreeRegressor(max_leaf_nodes=max_leaf_nodes, random_state=0) - model.fit(train_X, train_y) - preds_val = model.predict(val_X) - mae = mean_absolute_error(val_y, preds_val) - return(mae) -``` -数据被加载进`train_X`, `val_X`, `train_y` 和 `val_y` 变量: -```python -import pandas as pd - -# 加载数据 -melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv' -melbourne_data = pd.read_csv(melbourne_file_path) -# 过滤缺失数据 -filtered_melbourne_data = melbourne_data.dropna(axis=0) -# 选择特征和目标值 -y = filtered_melbourne_data.Price -melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'BuildingArea', - 'YearBuilt', 'Lattitude', 'Longtitude'] -X = filtered_melbourne_data[melbourne_features] - -from sklearn.model_selection import train_test_split - -# 将数据分割为训练和验证数据,都有特征和预测目标值 -train_X, val_X, train_y, val_y = train_test_split(X, y,random_state = 0) -``` - -我们可以使用`for循环`来比较使用不同`max_leaf_nodes`值构建模型的准确性。 -```python -# 比较不同max_leaf_nodes值的MAE -for max_leaf_nodes in [5, 50, 500, 5000]: - my_mae = get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y) - print("Max leaf nodes: %d \t\t Mean Absolute Error: %d" %(max_leaf_nodes, my_mae)) -``` -输出数据: -``` -Max leaf nodes: 5 Mean Absolute Error: 347380 -Max leaf nodes: 50 Mean Absolute Error: 258171 -Max leaf nodes: 500 Mean Absolute Error: 243495 -Max leaf nodes: 5000 Mean Absolute Error: 254983 -``` -在列出的选项中,500个是最佳的叶子数。 - -## 3、结论 - -结论是,构建模型可能遇到这两种情况: -- `过拟合`: 捕捉那些在未来不会重现的虚假模式,导致预测不那么准确。 -- `欠拟合`: 未能捕捉到相关的模式,导致预测不那么准确。 - -我们使用不参与模型训练的验证数据来度量候选模型的准确性。这让我们可以尝试多种候选模型后,保留最佳模型。 - -## 4、去吧,皮卡丘 -尝试[优化你之前构建的模型](https://www.kaggle.com/kernels/fork/1259126) diff --git a/docs/Kaggle/learn/intro-to-machine-learning/6.md b/docs/Kaggle/learn/intro-to-machine-learning/6.md deleted file mode 100644 index 7644e771..00000000 --- a/docs/Kaggle/learn/intro-to-machine-learning/6.md +++ /dev/null @@ -1,70 +0,0 @@ -# Kaggle 官方教程:机器学习入门6 随机森林 -> 原文:[Intro to Machine Learning](https://www.kaggle.com/learn/intro-to-machine-learning) > [Random Forests](https://www.kaggle.com/dansbecker/random-forests) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -## 1、介绍 -`决策树`给你留下一个难题。一颗较深、叶子多的树将会`过拟合`,因为每一个预测都来自叶子上仅有的几个历史训练数据。一颗较浅、叶子少的树将会`欠拟合`,因为它不能在原始数据中捕捉到那么多的差异。 - -即使是当今最精良的建模技术,也面临着拟合不足和拟合过度之间问题。但是,许多模型通过一些不错的点子来提升效果。我们将以`随机森林`为例。 - -`随机森林`使用了许多树,它通过对每棵成分树的预测进行平均来进行预测。它通常比单个决策树具有更好的预测精度,并且使用默认参数效果也不错。如果继续建模,你可以学习更多具有更好性能的模型,但是其中许多模型效果受调参影响特别大。 - -## 2、案例 -你已经多次看到加载数据的代码。数据加载后,我们将得到以下变量: - - train_X - - val_X - - train_y - - val_y - -```python -import pandas as pd -# 加载数据 -melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv' -melbourne_data = pd.read_csv(melbourne_file_path) -# 过滤缺失数据 -melbourne_data = melbourne_data.dropna(axis=0) -# Choose target and features -y = melbourne_data.Price -melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'BuildingArea', - 'YearBuilt', 'Lattitude', 'Longtitude'] -X = melbourne_data[melbourne_features] - -from sklearn.model_selection import train_test_split - -# 将数据分割为训练和验证数据,都有特征和预测目标值 -# 分割基于随机数生成器。为random_state参数提供一个数值可以保证每次得到相同的分割 -# 执行下面代码 -train_X, val_X, train_y, val_y = train_test_split(X, y,random_state = 0) -``` - -我们构建了一个随机森林模型,类似于我们在scikit-learn中构建决策树的方法——这次使用的是`RandomForestRegressor`类,而不是`DecisionTreeRegressor`。 - -```python -from sklearn.ensemble import RandomForestRegressor -from sklearn.metrics import mean_absolute_error - -forest_model = RandomForestRegressor(random_state=1) -forest_model.fit(train_X, train_y) -melb_preds = forest_model.predict(val_X) -print(mean_absolute_error(val_y, melb_preds)) -``` -输出结果: -``` -202888.18157951365 - -/opt/conda/lib/python3.6/site-packages/sklearn/ensemble/forest.py:245: FutureWarning: The default value of n_estimators will change from 10 in version 0.20 to 100 in 0.22. - "10 in version 0.20 to 100 in 0.22.", FutureWarning) -``` -## 3、结论 -可能还有进一步改进的空间,但是这比最佳决策树250,000的误差有很大的改进。你可以修改一些参数来提升随机森林的性能,就像我们改变单个决策树的最大深度一样。但是,随机森林模型的最佳特性之一是,即使没有这种调优,它们通常也可以正常工作。 - -你很快就会了解`XGBoost`模型,它在使用正确的参数进行调优时提供了更好的性能(但是需要一些技巧才能获得正确的模型参数)。 - -## 4、去吧,皮卡丘 -尝试自己[使用一个随机森林模型](https://www.kaggle.com/kernels/fork/1259186),看看它对你的模型有多大的改进。 - diff --git a/docs/Kaggle/learn/intro-to-machine-learning/7.md b/docs/Kaggle/learn/intro-to-machine-learning/7.md deleted file mode 100644 index 5e4777bc..00000000 --- a/docs/Kaggle/learn/intro-to-machine-learning/7.md +++ /dev/null @@ -1,28 +0,0 @@ -# Kaggle 官方教程:机器学习入门7 继续你的征程 -> 原文:[Intro to Machine Learning](https://www.kaggle.com/learn/intro-to-machine-learning) > [Exercise: Machine Learning Competitions](https://www.kaggle.com/kernels/fork/1259198) -> -> 译者:[Leytton](https://github.com/Leytton) -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -PS:水平有限,欢迎交流指正(Leytton@126.com) - -《Kaggle教程 机器学习入门》系列课程翻译完毕,撒花 ✿✿ヽ(°▽°)ノ✿ - -## 1、机器学习竞赛 -进入机器学习竞赛的世界,不断提高,看看你的进步。 -[https://www.kaggle.com/kernels/fork/1259198](https://www.kaggle.com/kernels/fork/1259198) - -## 2、继续你的征程 - -有很多方法可以改进你的模型,此时,`尝试是一个很好的学习方法`。. - -改进模型的最佳方法是添加特征。看看这些数据列表,想想什么可能影响房价。缺失值或非数字数据类型将导致错误。 - -[《中级机器学习》](https://www.kaggle.com/learn/intermediate-machine-learning)微课程将教你如何处理这些类型的特征。你还将学习使用`xgboost`,这是一种比`Random Forest`更精确的技术。 - -## 3、其他微课程 - -[《Pandas》](https://kaggle.com/Learn/Pandas) 微课程将为你讲解数据操作技巧,使你能够快速地实现从概念到数据科学项目的实现。 - -[《深度学习》](https://kaggle.com/Learn/Deep-Learning)微课程中,建立模型在计算机视觉任务中表现得比人类更好。 \ No newline at end of file diff --git a/docs/kaggle-quickstart.md b/docs/kaggle-quickstart.md index 041ed366..53ef276a 100644 --- a/docs/kaggle-quickstart.md +++ b/docs/kaggle-quickstart.md @@ -5,23 +5,23 @@ 1. 首先注册账号 2. 关联 GitHub 账号 -![](/img/docs/login.jpg) +![](../static/images/docs/login.jpg) ## [竞赛 - competitions](https://www.kaggle.com/competitions) * [选择 - All 和 Getting Started](https://www.kaggle.com/competitions?sortBy=deadline&group=all&page=1&pageSize=20&segment=gettingStarted) -![](/img/docs/All-GettingStarted.jpg) +![](..//static/images/docs/All-GettingStarted.jpg) * [选择 - Digit Recognizer(数字识别器)](https://www.kaggle.com/c/digit-recognizer) -![](/img/docs/choose-digit-recognizer.jpg) +![](../static/images/docs/choose-digit-recognizer.jpg) * [阅读资料 - Digit Recognizer(数字识别器)](https://www.kaggle.com/c/digit-recognizer) **选择 版本框架 和 star 最高的 Kernels 编辑就行,然后模仿 [**数字识别**](/competitions/getting-started/digit-recognizer) 案例更新** -![](/img/docs/read-digit-recognizer.jpg) +![](/static/images/docs/read-digit-recognizer.jpg) ## 项目规范(以:DigitRecognizer 为例) @@ -38,7 +38,7 @@ > 代码:结尾文件名可自由定义.py -* 案例:`src/py3.x/kaggle/getting-started/digit-recognizer/dr_knn_pandas.py` +* 案例:`src/python/getting-started/digit-recognizer/dr_knn_pandas.py` * 例如:数字识别,代码只有 `竞赛` 有,所以直接创建 `getting-started/digit-recognizer` 存放代码就行 * 要求(方法:完全解耦) 1. 加载数据 @@ -76,7 +76,7 @@ Github: https://github.com/apachecn/kaggle 将数据的输出结果提交到项目的页面中 - + ## docs目录(可忽略) diff --git "a/docs/\347\237\251\351\230\265\346\261\202\345\257\274.md" "b/docs/\347\237\251\351\230\265\346\261\202\345\257\274.md" index cd9eb978..4cf68d09 100644 --- "a/docs/\347\237\251\351\230\265\346\261\202\345\257\274.md" +++ "b/docs/\347\237\251\351\230\265\346\261\202\345\257\274.md" @@ -1,3 +1,3 @@ # 矩阵求导公式 -![矩阵1](/img/math/矩阵1.jpg) \ No newline at end of file +![矩阵1](../static/images/math/矩阵1.jpg) \ No newline at end of file diff --git "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\346\212\200\350\203\275\346\250\241\345\235\227\350\214\203\346\226\207.png" "b/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\346\212\200\350\203\275\346\250\241\345\235\227\350\214\203\346\226\207.png" deleted file mode 100644 index 9a3a5e23..00000000 Binary files "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\346\212\200\350\203\275\346\250\241\345\235\227\350\214\203\346\226\207.png" and /dev/null differ diff --git "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\350\207\252\346\210\221\350\257\204\344\273\267\350\214\203\346\226\207.png" "b/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\350\207\252\346\210\221\350\257\204\344\273\267\350\214\203\346\226\207.png" deleted file mode 100644 index 47cc9c6d..00000000 Binary files "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\350\207\252\346\210\221\350\257\204\344\273\267\350\214\203\346\226\207.png" and /dev/null differ diff --git "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\351\241\271\347\233\256\346\250\241\345\235\227\350\214\203\346\226\2071.png" "b/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\351\241\271\347\233\256\346\250\241\345\235\227\350\214\203\346\226\2071.png" deleted file mode 100644 index d4a3fc12..00000000 Binary files "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\351\241\271\347\233\256\346\250\241\345\235\227\350\214\203\346\226\2071.png" and /dev/null differ diff --git "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\351\241\271\347\233\256\346\250\241\345\235\227\350\214\203\346\226\2072.png" "b/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\351\241\271\347\233\256\346\250\241\345\235\227\350\214\203\346\226\2072.png" deleted file mode 100644 index 26dc9060..00000000 Binary files "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/img/\351\241\271\347\233\256\346\250\241\345\235\227\350\214\203\346\226\2072.png" and /dev/null differ diff --git "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206.md" "b/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206.md" deleted file mode 100644 index eaba4730..00000000 --- "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206.md" +++ /dev/null @@ -1,141 +0,0 @@ -# 【求职系列】人工智能学历真的重要吗? - -## 学历:奇怪现象? - -* 如果你是跨专业的学习?进入AI行业,别人会觉得你很励志很牛逼! -* 但是如果你是低学历的人,企业一般认为你就是个垃圾(普遍而已) - -表现形式: - -1. 学历门槛(当然大家都有自己的理由,说降低面试成本 - 就是懒嘛!) -2. 风险转嫁(如果你是高学历,即使被裁也就是看走眼;而学历低,就是眼界有问题) - -除非你做的最前沿的技术! - -* 因为最前沿,学历高的也没几个会。。你还得去教别人 -* 最后高学历的学会了,差不多也是该辞退你的时候,因为公司说你是没门面的事情。 - -当然你还会问,那极个别的牛人成功了为什么社会没变化呢? - -* 因为人家当老板了,可能忘记了自己当初那么苦。 -* 毕竟他有那么多事情要做,干嘛非要帮助当初的自己呢??? - -## 面试: 奇异现象? - -* 毕业季拼命的 刷题(leetcode、剑指 Offer) -* 更有甚者,工作n年以后,面试还是刷题,刷题 - -我不理解,持续刷题的意义是什么? - -``` -请问你工作用让你写这些东西吗?【没有,性能问题:数据库、分布式、GPU帮你解决】 -刷题为了获取精神上的愉悦? 【考察你的逻辑思维?狗屁】 - 其实不然,这东西基本上不用都会忘记,这就是为什么每一次都要复习,背写! - 我在5年的工作中,从大数据、算法策略、NLP,我都没有涉及到leetcode的题目 - 当然除非你重构一些框架,底层需要使用到一些复杂的数据结构【极少人】 -很多人从大学毕业就是这样过来的,所以他以为面试就这样,所以这样面试别人【沃日】 -``` - -现在算法面试不管你什么谁,都要上来做个题目,我真想草你们这些人,真尼玛闲的蛋疼! - -* 你说一个应届生没啥社会经验,你考考,我理解 -* 但是人家有项目,有比赛经验,你还考数据结构,为什么这么闲呢?? -* 我就想问你们,你们招聘人不就是使用开源框架做事情,难道还手写自己框架【沃日】 - -## 公司:奇异现象? - -* 悲哀的是: -* 不管毕业多久,很多人炫耀的资本还是学校 -* 而更悲哀的是: -* 这些人也都习惯性的默认了这一点并继续炫耀 -…… 社会现实到有些过时呢 - -## 至少是个本科,是什么意思? - -* 首先,学历真的很重要。。。(至少是个本科) -* 但是这个至少是个神马意思呢??? - -就是说: - -* 如果一直没招到合适的研究生和博士,就勉为其难的试试本科,然后压低工资。。 - -什么意思呢? - -* 就是说:你能力要强,工资还要低!(甚至可能还要给某些研究生or博士汇报工作) - -## 那么如果是专科呢,能学吗? - -专科当然也是有机会的,不过基本上即使技术过了也不会招聘你的! - -为什么? - -* 因为正常情况下大公司不需要学历低的人,无所谓你的能力。【即使叫你去面试】 -* 但是大公司的创业部门和中小型公司创业公司是需要有能力的人,所以机会还是有的。。 - -那么我们该怎么办呢? - - -调整好自己的心态,别总是觉得要去大公司什么的。 - -很多从大公司出来的boss 创业都是直接带一个团队出来,要么就是从社招招聘。 - -基本上也都是普通的大学生,只是公司大了就开始矫情,所以摆正好心态,开心学习就行 - -记住一点: -* 工资高 -* 圈子:例如 ApacheCN -* 自学能力强、有自己的想法(知道自己喜欢什么、为什么学他就行) - ---- - -## 最近有趣的新闻 - -> 最近关于学历的残酷事实 - -[AI泡沫崩了?抖音员工爆料:校招内推985本硕简历过不了!](https://mp.weixin.qq.com/s?__biz=MzUzODMxMTI5MA==&mid=2247485175&idx=1&sn=d5f2359685b02cf33594eceae1cf52ba&chksm=fad8e9e2cdaf60f4382b1dff40ab570f68d7b64f63f86a7d92701aaf2f26a9d6f50ce9d22916) - -本事件只是反映了一个问题,就是人已经过饱和。【饱和只是入门,高手依然很少】 - -> 在国内,为什么我们看到的大佬都是高学历的? - -![](/img/面试求职/学历/学历1.jpg) - -话说:低学历别人也不会给你机会进入这个圈子? - -例如: - -* 求职这一块,求职各种刁难【高压力、低薪资】 -* 在社交圈这一块,基本上是无法进入他们的圈子【为什么大佬都要花钱进MBA什么圈】 -* 在融资这一块,你没学历背景基本上也融不到资 -* 学历这一块,是一个相互交流的点,【例如:你也是某某某学校的?我是你学弟!】 -* 国内人口流量过大,导致对人要求过于严格,甚至高于全球水平,甚至排名最高几名 - -> 今日头条张一鸣炮轰公司HR: 按你们写的JD招聘,我自己都进不来公司 - -现实和理想的差距 VS 老板的要求和HR行动 - -![](/img/面试求职/学历/学历2.jpg) - -> 互联网-大公司人员的传播路径 - -现在我们看到的现象是:看学历、看背景 - -其实才是:个人能力、个人品质(其中还有各种小套路) - -头条CEO张一鸣虽然说了那些话,但其实改变是非常难的,因为公司已经被某些人腐蚀了! - -要改变就要大动干戈,掉血掉肉;要么就新建一个创业公司,重新找人,定义好文化规范。 - -![](/img/面试求职/学历/学历3.jpg) - -解决方案: - -1. 其他的国家(相比而言:国外急缺这方面的人才) -2. 提升自己的能力,但是短期是不可能实现的(所以这个建议是个废话,但是我想告诉有些人这是个现实问题) -3. 选择换个方向,从算法转开发,说实话开发薪资并不低,并且你可以调用算法的接口,只是你叫开发工程师(别人叫算法工程师而已)【就好比找对象一样,1000个人(厉害不厉害都有)追一个妹子,所以作为一个男孩子而言,完全可以找一个其他的女孩,没必要在这个树上吊死。也不见得没有比她更好的,所以人得灵活一点】 - -算法只是一种思想,我们学它,可以从事它的研究,也可以从事它的应用。 - -一定别把自己搞死在这个地方就行。 - -所以?你准备好了入坑吗? diff --git "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\347\256\200\345\216\206.md" "b/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\347\256\200\345\216\206.md" deleted file mode 100644 index 76ce7f9a..00000000 --- "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\347\256\200\345\216\206.md" +++ /dev/null @@ -1,49 +0,0 @@ -# 简历如何写? - -> 个人信息 - -姓名、性别、学历、工龄、籍贯、现居地、电话、电子邮箱 - -> 求职意向 - -* 工作情况: 北京-全职 -* 期望职业: 数据/算法负责人 -* 期望月薪: 面议 - -> 教育经历 - -* 20xx.09-20xx.06 xxxxx大学 xxx - -> 技能描述 - -* 使用Python 6年、熟练使用 SQL -* 熟悉主流算法: 分类、回归 - -> 自我评价 - -1. 工作踏实认真,负责过Kaggle比赛项目、企业反作弊、推荐和大数据项目 -2. 学习能力很强,热衷研究技术、经常分享交流技术、喜欢看Kaggle全球优秀kernels -3. 人脉资源广泛,在GitHub和知乎有点小名气,坚持做了2年的机器学习的开源社区 - -> 个人经历 - -``` -xx 2018.09~现在 算法负责人 负责:负责AI算法实现和落地应用 -xx 2016.06~2018-08 社区负责人 负责: 负责整个AI社区的内容梳理 -xx 2014.08~2016.03 算法策略 负责:广告联盟反作弊算法策略 -xx 2013.11~2014.07 数据仓库 负责:数据仓库优化和可视化展现 -``` - -> 项目经验 - -* 工作时间:2018/09~现在 -* 所处职位:数据算法负责人 -* 日常工作 - * 1/2/3/4 [聊工作相关的重点] - -> 自学经验 - -* Pytorch + TensorFlow (2017/06 ~ 现在) -* 搜索:TensorFlow 2.0 - 教程: https://github.com/apachecn/AiLearning -* Pytorch 没有是因为翻译了教程: https://github.com/apachecn/pytorch-doc-zh -* 各种做过的开源项目 diff --git "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\347\256\200\345\216\206\350\214\203\346\226\207.md" "b/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\347\256\200\345\216\206\350\214\203\346\226\207.md" deleted file mode 100644 index 261f68b6..00000000 --- "a/docs/\351\235\242\350\257\225\346\261\202\350\201\214/\347\256\200\345\216\206\350\214\203\346\226\207.md" +++ /dev/null @@ -1,15 +0,0 @@ -# 简历范文 - -## 自我评价模块 - -![](img/自我评价范文.png) - -## 技能模块 - -![](img/技能模块范文.png) - -## 项目模块 - -![](img/项目模块范文1.png) - -![](img/项目模块范文2.png) diff --git "a/img/Algorithm/DataStructure/\344\272\214\345\210\206\346\237\245\346\211\276.gif" "b/img/Algorithm/DataStructure/\344\272\214\345\210\206\346\237\245\346\211\276.gif" deleted file mode 100644 index 9a1edaa8..00000000 Binary files "a/img/Algorithm/DataStructure/\344\272\214\345\210\206\346\237\245\346\211\276.gif" and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/BubbleSort_1.gif b/img/Algorithm/LeetCode/SortingAlgorithm/BubbleSort_1.gif deleted file mode 100644 index 9dd0ed47..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/BubbleSort_1.gif and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/InsertSort_1.gif b/img/Algorithm/LeetCode/SortingAlgorithm/InsertSort_1.gif deleted file mode 100644 index 2702b14d..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/InsertSort_1.gif and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/MergeSort_1.gif b/img/Algorithm/LeetCode/SortingAlgorithm/MergeSort_1.gif deleted file mode 100644 index a29ca19d..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/MergeSort_1.gif and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/QuickSort_1.gif b/img/Algorithm/LeetCode/SortingAlgorithm/QuickSort_1.gif deleted file mode 100644 index ad88d357..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/QuickSort_1.gif and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/RadixSort_1.gif b/img/Algorithm/LeetCode/SortingAlgorithm/RadixSort_1.gif deleted file mode 100644 index 2a556955..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/RadixSort_1.gif and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/RadixSort_2.png b/img/Algorithm/LeetCode/SortingAlgorithm/RadixSort_2.png deleted file mode 100644 index 922e878f..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/RadixSort_2.png and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/SelectionSort_1.gif b/img/Algorithm/LeetCode/SortingAlgorithm/SelectionSort_1.gif deleted file mode 100644 index 353459bc..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/SelectionSort_1.gif and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_1.gif b/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_1.gif deleted file mode 100644 index bbb3beac..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_1.gif and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_2.png b/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_2.png deleted file mode 100644 index 891d3ba9..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_2.png and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_3.png b/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_3.png deleted file mode 100644 index 0cf9303f..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_3.png and /dev/null differ diff --git a/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_4.png b/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_4.png deleted file mode 100644 index fa474c3d..00000000 Binary files a/img/Algorithm/LeetCode/SortingAlgorithm/ShellSort_4.png and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\247\350\203\275.png" "b/img/Algorithm/LeetCode/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\247\350\203\275.png" deleted file mode 100644 index 77b48e41..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\247\350\203\275.png" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.png" "b/img/Algorithm/LeetCode/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.png" deleted file mode 100644 index dbc5b0ef..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\205\253\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.png" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\206\222\346\263\241\346\216\222\345\272\217.gif" "b/img/Algorithm/LeetCode/SortingAlgorithm/\345\206\222\346\263\241\346\216\222\345\272\217.gif" deleted file mode 100644 index f190e62d..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\206\222\346\263\241\346\216\222\345\272\217.gif" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\237\272\346\225\260\346\216\222\345\272\217.gif" "b/img/Algorithm/LeetCode/SortingAlgorithm/\345\237\272\346\225\260\346\216\222\345\272\217.gif" deleted file mode 100644 index bfec4065..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\237\272\346\225\260\346\216\222\345\272\217.gif" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\270\214\345\260\224\346\216\222\345\272\217.png" "b/img/Algorithm/LeetCode/SortingAlgorithm/\345\270\214\345\260\224\346\216\222\345\272\217.png" deleted file mode 100644 index fa474c3d..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\270\214\345\260\224\346\216\222\345\272\217.png" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\275\222\345\271\266\346\216\222\345\272\217.gif" "b/img/Algorithm/LeetCode/SortingAlgorithm/\345\275\222\345\271\266\346\216\222\345\272\217.gif" deleted file mode 100644 index d6fa725b..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\275\222\345\271\266\346\216\222\345\272\217.gif" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\277\253\351\200\237\346\216\222\345\272\217.gif" "b/img/Algorithm/LeetCode/SortingAlgorithm/\345\277\253\351\200\237\346\216\222\345\272\217.gif" deleted file mode 100644 index 6f04ec97..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\345\277\253\351\200\237\346\216\222\345\272\217.gif" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" "b/img/Algorithm/LeetCode/SortingAlgorithm/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" deleted file mode 100644 index f08422cd..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" "b/img/Algorithm/LeetCode/SortingAlgorithm/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" deleted file mode 100644 index 52e209b5..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" "b/img/Algorithm/LeetCode/SortingAlgorithm/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" deleted file mode 100644 index d5975d0c..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" and /dev/null differ diff --git "a/img/Algorithm/LeetCode/SortingAlgorithm/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" "b/img/Algorithm/LeetCode/SortingAlgorithm/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" deleted file mode 100644 index 735cff28..00000000 Binary files "a/img/Algorithm/LeetCode/SortingAlgorithm/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" and /dev/null differ diff --git a/img/competitions/getting-started/titanic/titanic_corr_analysis.png b/img/competitions/getting-started/titanic/titanic_corr_analysis.png deleted file mode 100644 index 01639ea7..00000000 Binary files a/img/competitions/getting-started/titanic/titanic_corr_analysis.png and /dev/null differ diff --git a/img/learn/intermediate-machine-learning/1.1.png b/img/learn/intermediate-machine-learning/1.1.png deleted file mode 100644 index 1009d293..00000000 Binary files a/img/learn/intermediate-machine-learning/1.1.png and /dev/null differ diff --git a/img/learn/intermediate-machine-learning/2.1.png b/img/learn/intermediate-machine-learning/2.1.png deleted file mode 100644 index 58d1e4e0..00000000 Binary files a/img/learn/intermediate-machine-learning/2.1.png and /dev/null differ diff --git a/img/learn/intermediate-machine-learning/2.2.png b/img/learn/intermediate-machine-learning/2.2.png deleted file mode 100644 index 06a3a200..00000000 Binary files a/img/learn/intermediate-machine-learning/2.2.png and /dev/null differ diff --git a/img/learn/intermediate-machine-learning/2.3.png b/img/learn/intermediate-machine-learning/2.3.png deleted file mode 100644 index 5c3940d1..00000000 Binary files a/img/learn/intermediate-machine-learning/2.3.png and /dev/null differ diff --git a/img/learn/intermediate-machine-learning/3.1.png b/img/learn/intermediate-machine-learning/3.1.png deleted file mode 100644 index 7ac717c0..00000000 Binary files a/img/learn/intermediate-machine-learning/3.1.png and /dev/null differ diff --git a/img/learn/intermediate-machine-learning/3.2.png b/img/learn/intermediate-machine-learning/3.2.png deleted file mode 100644 index 13fc871b..00000000 Binary files a/img/learn/intermediate-machine-learning/3.2.png and /dev/null differ diff --git a/img/learn/intermediate-machine-learning/5.1.png b/img/learn/intermediate-machine-learning/5.1.png deleted file mode 100644 index 4770fbca..00000000 Binary files a/img/learn/intermediate-machine-learning/5.1.png and /dev/null differ diff --git a/img/learn/intro-to-machine-learning/1.1.png b/img/learn/intro-to-machine-learning/1.1.png deleted file mode 100644 index ce276725..00000000 Binary files a/img/learn/intro-to-machine-learning/1.1.png and /dev/null differ diff --git a/img/learn/intro-to-machine-learning/1.2.png b/img/learn/intro-to-machine-learning/1.2.png deleted file mode 100644 index ec1a930d..00000000 Binary files a/img/learn/intro-to-machine-learning/1.2.png and /dev/null differ diff --git a/img/learn/intro-to-machine-learning/1.3.png b/img/learn/intro-to-machine-learning/1.3.png deleted file mode 100644 index 836c8cfa..00000000 Binary files a/img/learn/intro-to-machine-learning/1.3.png and /dev/null differ diff --git a/img/learn/intro-to-machine-learning/2.1.png b/img/learn/intro-to-machine-learning/2.1.png deleted file mode 100644 index 8efd8b7c..00000000 Binary files a/img/learn/intro-to-machine-learning/2.1.png and /dev/null differ diff --git a/img/learn/intro-to-machine-learning/3.1.png b/img/learn/intro-to-machine-learning/3.1.png deleted file mode 100644 index 02d4d751..00000000 Binary files a/img/learn/intro-to-machine-learning/3.1.png and /dev/null differ diff --git a/img/learn/intro-to-machine-learning/3.2.png b/img/learn/intro-to-machine-learning/3.2.png deleted file mode 100644 index 75841a82..00000000 Binary files a/img/learn/intro-to-machine-learning/3.2.png and /dev/null differ diff --git a/img/learn/intro-to-machine-learning/5.1.png b/img/learn/intro-to-machine-learning/5.1.png deleted file mode 100644 index 836c8cfa..00000000 Binary files a/img/learn/intro-to-machine-learning/5.1.png and /dev/null differ diff --git a/img/learn/intro-to-machine-learning/5.2.png b/img/learn/intro-to-machine-learning/5.2.png deleted file mode 100644 index 3d518fac..00000000 Binary files a/img/learn/intro-to-machine-learning/5.2.png and /dev/null differ diff --git "a/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2061.jpg" "b/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2061.jpg" deleted file mode 100644 index cf916cfa..00000000 Binary files "a/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2061.jpg" and /dev/null differ diff --git "a/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2062.jpg" "b/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2062.jpg" deleted file mode 100644 index 4f95f2f3..00000000 Binary files "a/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2062.jpg" and /dev/null differ diff --git "a/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2063.jpg" "b/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2063.jpg" deleted file mode 100644 index b8e9101c..00000000 Binary files "a/img/\351\235\242\350\257\225\346\261\202\350\201\214/\345\255\246\345\216\206/\345\255\246\345\216\2063.jpg" and /dev/null differ diff --git a/index.html b/index.html deleted file mode 100644 index ba76d30d..00000000 --- a/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
now loading...
- - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/learn/embeddings.md b/learn/embeddings.md new file mode 100644 index 00000000..31539532 --- /dev/null +++ b/learn/embeddings.md @@ -0,0 +1,964 @@ +# Kaggle 官方教程:嵌入 + +> 原文:[Embeddings](https://www.kaggle.com/learn/embeddings) +> +> 译者:[飞龙](https://github.com/wizardforcel) +> +> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) + +P.S... + +本课程仍处于测试阶段,因此我很乐意收到你的反馈意见。 如果你有时间填写[本课程的超短期调查](https://form.jotform.com/82826168584267),我将非常感激。 你也可以在下面的评论中或在[学习论坛](https://www.kaggle.com/learn-forum)上留下公开反馈。 + +## 一、嵌入层 + +欢迎阅读嵌入主题的第一课。 在本课程中,我将展示如何使用`tf.keras` API 实现带嵌入层的模型。 嵌入是一种技术,使深度神经网络能够处理稀疏的类别变量。 + +### 稀疏类别变量 + +我的意思是一个具有许多可能值(高基数)的类别变量,其中少数(通常只有 1)存在于任何给定的观察中。 一个很好的例子是词汇。 英语中的词汇是成千上万的,但一条推文可能只有十几个词。 词嵌入是将深度学习应用于自然语言的关键技术。 但其他例子还有很多。 + +例如,[洛杉矶餐馆检查](https://www.kaggle.com/meganrisdal/la-county-restaurant-inspections-and-violations)的这个数据集有几个稀疏的分类变量,包括: + ++ `employee_id`:卫生部门的哪些员工进行了这次检查? (约 250 个不同的值) ++ `facility_zip`:餐厅的邮政编码是什么? (约 3,000 个不同的值) ++ `owner_name`:谁拥有餐厅? (约 35,000 个不同的值) + +对于将任何这些变量用作网络的输入,嵌入层是个好主意。 + +在本课程中,我将使用 [MovieLens 数据集](https://www.kaggle.com/grouplens/movielens-20m-dataset)作为示例。 + +### MovieLens + +MovieLens 数据集由用户给电影的评分组成。这是一个示例: + + +| | userId | movieId | rating | y | title | year | +| --- | --- | --- | --- | --- | --- | --- | +| 12904240 | 85731 | 1883 | 4.5 | 0.974498 | Labyrinth | 1986 | +| 6089380 | 45008 | 1221 | 4.5 | 0.974498 | Femme Nikita, La (Nikita) | 1990 | +| 17901393 | 125144 | 3948 | 4.0 | 0.474498 | The Alamo | 1960 | +| 9024816 | 122230 | 3027 | 3.5 | -0.025502 | Toy Story 2 | 1999 | +| 11655659 | 21156 | 5202 | 3.0 | -0.525502 | My Big Fat Greek Wedding | + +评分范围是 0.5 到 5。我们的目标是预测由给定用户`ui`给出的,特定电影`mj`的评分。 (列`y`只是评分列的副本,减去了平均值 - 这在以后会有用。) + +`userId`和`movieId`都是稀疏分类变量。 它们有许多可能的值: + +``` +138,493 个独立用户评分了 26,744 个不同的电影(总评分是 20,000,263 个) +``` + +### 在 Keras 中创建评分预测模型 + +我们想要构建一个模型,它接受用户`ui`和电影`mj`,并输出 0.5-5 的数字,表示我们认为该用户将为该电影评分多少星。 + +> 注:你可能已经注意到`MovieLens`数据集包含每部电影的信息,例如标题,发行年份,一组流派和用户指定的标签。 但就目前而言,我们不会试图利用任何额外的信息。 + +我说我们需要一个嵌入层来处理这些输入。 为什么? 让我们回顾一些替代方案,看看为什么它们不起作用。 + +### 坏主意 #1:使用用户和电影 ID 作为数值输入 + +为什么不将用户 ID 和电影 ID 作为数值来输入,然后添加一些密集层?即: + +```py +model = keras.Sequential([ + # 2 个输入值:用户 ID 和电影 ID + keras.layers.Dense(256, input_dim=2, activation='relu'), + keras.layers.Dense(32, activation='relu'), + # 单个输出节点,包含预测的评分 + keras.layers.Dense(1) +]) +``` + +用最简单的术语来说,神经网络的原理是对输入进行数学运算。 但分配给用户和电影的 ID 的实际数值是没有意义的。《辛德勒的名单》的 id 为 527,而《非常嫌疑犯》的 id 为 50,但这并不意味着《辛德勒的名单》比《非常嫌疑犯》大十倍。 + +### 坏主意 #2:独热编码的用户和电影输入 + +如果你不熟悉单热编码,可能需要查看我们的课程[“使用独热编码处理类别数据”](https://www.kaggle.com/dansbecker/using-categorical-data-with-one-hot-encoding)。 + +在该课程中,我们说独热编码是“类别数据的标准方法”。 那么为什么这是一个坏主意呢? 让我们看看模型是什么样子,它接受独热编码的用户和电影。 + +```py +input_size = n_movies + n_users +print("Input size = {:,} ({:,} movies + {:,} users)".format( + input_size, n_movies, n_users, +)) +model = keras.Sequential([ + # 一个带有 128 个单元的隐藏层 + keras.layers.Dense(128, input_dim=input_size, activation='relu'), + # 单个输出节点,包含预测的评分 + keras.layers.Dense(1) +]) +model.summary() +''' +Input size = 165,237 (26,744 movies + 138,493 users) +_________________________________________________________________ +Layer (type) Output Shape Param # +================================================================= +dense_3 (Dense) (None, 128) 21150464 +_________________________________________________________________ +dense_4 (Dense) (None, 1) 129 +================================================================= +Total params: 21,150,593 +Trainable params: 21,150,593 +Non-trainable params: 0 +_________________________________________________________________ +''' +``` + +这里的一个基本问题是扩展和效率。 我们模型的单个输入是包含 165,237 个数字的向量(其中我们知道 165,235 是零)。 我们整个 2000 万个评分实例数据集的特征数据,将需要一个大小为 20,000,000 x 165,237 或大约 3 万亿个数字的二维数组。 但愿你能把这一切都放进内存中! + +此外,在我们的模型上进行训练和推断将是低效的。 为了计算我们的第一个隐藏层的激活,我们需要将我们的 165k 输入乘以大约 2100 万个权重 - 但是这些乘积的绝大多数都将为零。 + +对于具有少量可能值的分类变量,例如`{Red, Yellow, Green}`或`{Monday, Tuesday, Wednesday, Friday, Saturday, Sunday}`,独热编码是合适的。 但在像我们的电影推荐问题的情况下,它并不是那么好,其中变量有数十或数十万个可能的值。 + +### 好主意:嵌入层 + +简而言之,嵌入层将一组离散对象(如单词,用户或电影)中的每个元素映射到实数的密集(嵌入)向量。 + +> 注:一个关键的实现细节是嵌入层接受被嵌入实体的索引作为输入(即我们可以将`userId`和`movieId`作为输入)。 你可以将其视为一种“查找表”。 这比采用独热向量并进行巨大的矩阵乘法要有效得多! + +例如,如果我们为电影学习大小为 8 的嵌入,则《律政俏佳人》(`index = 4352`)的嵌入可能如下所示: + +``` +[1.624,−0.612,−0.528,−1.073,0.865,−2.302,1.745,−0.761] +``` + +它们来自哪里? 我们使用随机噪声为每个用户和电影初始化嵌入,然后我们将它们训练,作为整体评分预测模型训练过程的一部分。 + +他们的意思是什么? 如果对象的嵌入有任何好处,它应该捕获该对象的一些有用的潜在属性。 但这里的关键词是潜在,也就是隐藏的。 由模型来发现实体的任何属性,并在嵌入空间中对它们编码,对预测任务有用。 听起来很神秘? 在后面的课程中,我将展示一些解释习得的嵌入的技术,例如使用 t-SNE 算法将它们可视化。 + +### 实现它 + +我希望我的模型是这样: + +![](img/emb-1.png) + +需要注意的一个关键点是,这个网络不仅仅是从输入到输出的一堆层级。 我们将用户和电影视为单独的输入,只有在每个输入经过自己的嵌入层之后才会聚集在一起。 + +这意味着[`keras.Sequential`](https://www.tensorflow.org/api_docs/python/tf/keras/Sequential)类(你可能从我们的[图像数据深度学习课程](https://www.kaggle.com/learn/deep-learning)中熟悉它)将无法工作。 我们需要使用[`keras.Model`](https://www.tensorflow.org/api_docs/python/tf/keras/Model)类转向更强大的“函数式 API”。 函数式 API 的更多详细信息,请查看 [Keras 的指南](https://keras.io/getting-started/functional-api-guide/)。 + +这是代码: + +```py +hidden_units = (32,4) +movie_embedding_size = 8 +user_embedding_size = 8 + +# 每个实例将包含两个输入:单个用户 ID 和单个电影 ID +user_id_input = keras.Input(shape=(1,), name='user_id') +movie_id_input = keras.Input(shape=(1,), name='movie_id') +user_embedded = keras.layers.Embedding(df.userId.max()+1, user_embedding_size, + input_length=1, name='user_embedding')(user_id_input) +movie_embedded = keras.layers.Embedding(df.movieId.max()+1, movie_embedding_size, + input_length=1, name='movie_embedding')(movie_id_input) +# 连接嵌入(并删除无用的额外维度) +concatenated = keras.layers.Concatenate()([user_embedded, movie_embedded]) +out = keras.layers.Flatten()(concatenated) + +# 添加一个或多个隐层 +for n_hidden in hidden_units: + out = keras.layers.Dense(n_hidden, activation='relu')(out) + +# 单一输出:我们的预测评分 +out = keras.layers.Dense(1, activation='linear', name='prediction')(out) + +model = keras.Model( + inputs = [user_id_input, movie_id_input], + outputs = out, +) +model.summary(line_length=88) +''' +________________________________________________________________________________________ +Layer (type) Output Shape Param # Connected to +======================================================================================== +user_id (InputLayer) (None, 1) 0 +________________________________________________________________________________________ +movie_id (InputLayer) (None, 1) 0 +________________________________________________________________________________________ +user_embedding (Embedding) (None, 1, 8) 1107952 user_id[0][0] +________________________________________________________________________________________ +movie_embedding (Embedding) (None, 1, 8) 213952 movie_id[0][0] +________________________________________________________________________________________ +concatenate (Concatenate) (None, 1, 16) 0 user_embedding[0][0] + movie_embedding[0][0] +________________________________________________________________________________________ +flatten (Flatten) (None, 16) 0 concatenate[0][0] +________________________________________________________________________________________ +dense_5 (Dense) (None, 32) 544 flatten[0][0] +________________________________________________________________________________________ +dense_6 (Dense) (None, 4) 132 dense_5[0][0] +________________________________________________________________________________________ +prediction (Dense) (None, 1) 5 dense_6[0][0] +======================================================================================== +Total params: 1,322,585 +Trainable params: 1,322,585 +Non-trainable params: 0 +________________________________________________________________________________________ +''' +``` + +### 训练 + +我们将编译我们的模型,来最小化平方误差('MSE')。 我们还将绝对值误差('MAE')作为在训练期间报告的度量标准,因为它更容易解释。 + +> 需要考虑的事情:我们知道评分只能取值`{0.5,1,1.5,2,2.5,3,3.5,4,4.5,5}` - 所以为什么不将其视为 10 类的多类分类问题 ,每个可能的星级评分一个? + +```py +model.compile( + # 技术说明:使用嵌入层时,我强烈建议使用 + # tf.train 中发现的优化器之一: + # https://www.tensorflow.org/api_guides/python/train#Optimizers + # 传入像 'adam' 或 'SGD' 这样的字符串,会加载一个 keras 优化器 + # (在 tf.keras.optimizers 下寻找)。 对于像这样的问题,它们似乎要慢得多, + # 因为它们无法有效处理稀疏梯度更新。 + tf.train.AdamOptimizer(0.005), + loss='MSE', + metrics=['MAE'], +) +``` + +让我们训练模型: + +> 注:我传入`df.y`而不是`df.rating`,作为我的目标变量。`y`列只是评分的“中心”版本 - 即评分列减去其在训练集上的平均值。 例如,如果训练集中的总体平均评分是 3 星,那么我们将 3 星评分翻译为 0, 5星评分为 2.0 等等,来获得`y`。 这是深度学习中的常见做法,并且往往有助于在更少的时期内获得更好的结果。 对于更多详细信息,请随意使用我在 MovieLens 数据集上执行的所有预处理来检查[这个内核](https://www.kaggle.com/colinmorris/movielens-preprocessing)。 + +```py +history = model.fit( + [df.userId, df.movieId], + df.y, + batch_size=5000, + epochs=20, + verbose=0, + validation_split=.05, +); +``` + +为了判断我们的模型是否良好,有一个基线是有帮助的。 在下面的单元格中,我们计算了几个虚拟基线的误差:始终预测全局平均评分,以及预测每部电影的平均评分: + ++ 训练集的平均评分:3.53 星 ++ 总是预测全局平均评分,结果为 MAE=0.84,MSE=1.10 ++ 预测每部电影的平均评分,结果为 MAE=0.73,MSE=0.88 + + +这是我们的嵌入模型的绝对误差随时间的绘图。 为了进行比较,我们的最佳基线(预测每部电影的平均评分)用虚线标出: + +![](img/emb-2.png) + +与基线相比,我们能够将平均误差降低超过 0.1 星(或约 15%)。不错! + +### 示例预测 + +让我们尝试一些示例预测作为健全性检查。 我们首先从数据集中随机挑选一个特定用户。 + +``` +用户 #26556 评分了 21 个电影(平均评分为 3.7) +``` + +| | userId | movieId | rating | title | year | +| --- | --- | --- | --- | --- | --- | +| 4421455 | 26556 | 2705 | 5.0 | Airplane! | 1980 | +| 14722970 | 26556 | 2706 | 5.0 | Airplane II: The Sequel | 1982 | +| 7435440 | 26556 | 2286 | 4.5 | Fletch | 1985 | +| 16621016 | 26556 | 2216 | 4.5 | History of the World: Part I | 1981 | +| 11648630 | 26556 | 534 | 4.5 | Six Degrees of Separation | 1993 | +| 14805184 | 26556 | 937 | 4.5 | Mr. Smith Goes to Washington | 1939 | +| 14313285 | 26556 | 2102 | 4.5 | Strangers on a Train | 1951 | +| 13671173 | 26556 | 2863 | 4.5 | Dr. No | 1962 | +| 13661434 | 26556 | 913 | 4.0 | Notorious | 1946 | +| 11938282 | 26556 | 916 | 4.0 | To Catch a Thief | 1955 | +| 2354167 | 26556 | 3890 | 4.0 | Diamonds Are Forever | 1971 | +| 16095891 | 26556 | 730 | 4.0 | Spy Hard | 1996 | +| 16265128 | 26556 | 3414 | 3.5 | Network | 1976 | +| 13050537 | 26556 | 1414 | 3.5 | Waiting for Guffman | 1996 | +| 9891416 | 26556 | 2907 | 3.5 | Thunderball | 1965 | +| 3496223 | 26556 | 4917 | 3.5 | Gosford Park | 2001 | +| 1996728 | 26556 | 1861 | 3.0 | On the Waterfront | 1954 | +| 15893218 | 26556 | 1082 | 2.5 | A Streetcar Named Desire | 1951 | +| 13875921 | 26556 | 3445 | 2.5 | Keeping the Faith | 2000 | +| 13163853 | 26556 | 1225 | 2.0 | The Day the Earth Stood Still | 1951 | +| 7262983 | 26556 | 2348 | 0.5 | A Civil Action | 1998 | + +用户 26556 给电影《空前绝后满天飞》和《空前绝后满天飞 II》打了两个完美的评分。很棒的选择! 也许他们也会喜欢《白头神探》系列 - 另一系列由 Leslie Nielsen 主演的恶搞电影。 + +我们没有那么多关于这个用户讨厌什么的证据。 我们不根据他们的少数低评分做推断,用户不喜欢什么的更好推断是,他们甚至没有评价的电影类型。 让我们再举几个电影的例子,根据用户的评分历史记录,他们似乎不太可能看过。 + +```py +candidate_movies = movies[ + movies.title.str.contains('Naked Gun') + | (movies.title == 'The Sisterhood of the Traveling Pants') + | (movies.title == 'Lilo & Stitch') +].copy() + +preds = model.predict([ + [uid] * len(candidate_movies), # 用户 ID + candidate_movies.index, # 电影 ID +]) +# 注意:记住我们在 'y' 上训练,这是评分列的中心为 0 的版本。 +# 要将我们模型的输出值转换为 [0.5, 5] 原始的星级评分范围, +# 我们需要通过添加均值来对值“去中心化” +row = df.iloc[0] # rating 和 y 之间的差对于所有行都是相同的,所以我们可以使用第一行 +y_delta = row.rating - row.y +candidate_movies['predicted_rating'] = preds + y_delta +# 添加一列,带有我们的预测评分(对于此用户) +# 和电影对于数据集中所有用户的总体平均评分之间的差 +candidate_movies['delta'] = candidate_movies['predicted_rating'] - candidate_movies['mean_rating'] +candidate_movies.sort_values(by='delta', ascending=False) +``` + +| | title | year | mean_rating | n_ratings | predicted_rating | delta | +| --- | --- | --- | --- | --- | --- | --- | +| movieId | | | | | | | +| 366 | Naked Gun 33 1/3: The Final Insult | 1994 | 2.954226 | 13534.0 | 3.816926 | 0.862699 | +| 3776 | The Naked Gun 2 1/2: The Smell of Fear | 1991 | 3.132616 | 4415.0 | 3.946124 | 0.813508 | +| 3775 | The Naked Gun: From the Files of Police Squad! | 1988 | 3.580381 | 6973.0 | 4.236419 | 0.656037 | +| 5347 | Lilo & Stitch | 2002 | 3.489323 | 4402.0 | 3.971318 | 0.481995 | +| 10138 | The Sisterhood of the Traveling Pants | 2005 | 3.369987 | 773.0 | 2.041227 | -1.328760 | + +看起来很合理! 对于《白头神探》系列中的每部电影,我们对此用户的预测评分,大约比数据集中平均评分高一星,而我们的“out of left field”使它们的预测评分低于平均值。 + +### 你的回合 + +前往[练习笔记本](https://www.kaggle.com/kernels/fork/1598432),进行嵌入层的实践练习。 + +## 二、用于推荐问题的矩阵分解 + +在上一课中,我们训练了一个模型来预测在 MovieLens 数据集中,用户给电影的评分。 提醒一下,模型看起来像这样: + +![](img/emb-1.png) + +我们为电影和用户查找嵌入向量,将它们连接在一起。 然后我们添加一些隐层。 最后,这些在一个输出节点汇集在一起来预测评分。 + +在本节课中,我将展示一个更简单的架构,来解决同样的问题:矩阵分解。 更简单可以是一件非常好的事情! 有时,简单的模型会快速收敛到适当的解决方案,一个更复杂的模型可能会过拟合或无法收敛。 + +这是我们的矩阵分解模型的样子: + +![](img/emb-3.png) + +### 点积 + +让我们回顾一下数学。 如果你是线性代数专家,请跳过本节。 + +两个长度为`n`的向量`a`和`b`的点积定义为: + +![](img/emb-4.png) + +结果是单个标量(不是向量)。 + +点积仅为相同长度的矢量而定义。 这意味着我们需要为电影嵌入和用户嵌入使用相同的大小。 + +例如,假设我们已经训练了大小为 4 的嵌入,并且电影 Twister 由向量表示: + +``` +m_Twister=[ 1.0 −0.5 0.3 −0.1 ] +``` + +用户 Stanley 表示为: + +``` +u_Stanley=[ −0.2 1.5 −0.1 0.9 ] +``` + +我们认为 Stanley 会给 Twister 什么评分? 我们可以将模型的输出计算为: + +``` +m_Twister · u_Stanley += (1.0·−0.2)+(−0.5·1.5)+(0.3·−0.1)+(−0.1·0.9) += −1.07 +``` + +因为我们正在在评分列的中心版本上训练,所以我们的模型输出的比例为 0 等于训练集中的总体平均评分(约 3.5)。 因此我们预测 Stanley 将给 Twister `3.5+(−1.07)=2.43`星。 + +### 为什么 + +有一个直观的解释,支持了以这种方式组合我们的嵌入向量的决定。 假设我们的电影嵌入空间的维度对应于以下变化的轴: + +维度 1:多么令人激动? +维度 2:多么浪漫? +维度 3:目标受众有多成熟? +维度 4:多么好笑? + +因此,Twister 是一部令人激动的灾难电影,`m1`的正值为 1.0。 + +简单来说,`u1`告诉我们“这个用户对动作片的看法如何?”。 他们喜欢它吗?讨厌它?还是不喜欢也不讨厌? + +Stanley 的向量告诉,我们他是浪漫和喜剧的忠实粉丝,并且略微不喜欢动作和成熟的内容。 如果我们给他一部类似于最后一部的电影,除了它有很多浪漫元素,会怎么样? + +``` +m_Titanic=[ 1.0 1.1 0.3 −0.1 ] +``` + +不难预测这会如何影响我们的评分输出。 我们给 Stanley 更多他喜欢的东西,所以他的预测评分会增加。 + +``` +predicted_rating(Stanley,Titanic) += m_Titanic·u_Stanley+3.5 +=(1.0·−0.2)+(1.1·1.5)+(0.3·−0.1)+(−0.1·0.9)+3.5 +=4.83 stars +``` + +> 注:在实践中,我们的电影嵌入的维度的含义不会那么明确,但我们的电影嵌入空间和用户嵌入空间的含义从根本上联系在一起,这仍然是正确的:`ui`总是代表“这个用户多么喜欢某个电影,其质量由`mi`代表?“ (希望这也提供了一些直觉,为什么电影嵌入空间和用户嵌入空间在这个技巧中必须大小相同。) + +### 实现它 + +创建此模型的代码,类似于我们在上一课中编写的代码,除了我使用点积层来组合用户和电影嵌入层的输出(而不是连接它们,并输入到密集层)。 + +```py +movie_embedding_size = user_embedding_size = 8 + +# 每个实例由两个输入组成:单个用户 ID 和单个电影 ID +user_id_input = keras.Input(shape=(1,), name='user_id') +movie_id_input = keras.Input(shape=(1,), name='movie_id') +user_embedded = keras.layers.Embedding(df.userId.max()+1, user_embedding_size, + input_length=1, name='user_embedding')(user_id_input) +movie_embedded = keras.layers.Embedding(df.movieId.max()+1, movie_embedding_size, + input_length=1, name='movie_embedding')(movie_id_input) + +dotted = keras.layers.Dot(2)([user_embedded, movie_embedded]) +out = keras.layers.Flatten()(dotted) + +model = keras.Model( + inputs = [user_id_input, movie_id_input], + outputs = out, +) +model.compile( + tf.train.AdamOptimizer(0.001), + loss='MSE', + metrics=['MAE'], +) +model.summary(line_length=88) +''' +________________________________________________________________________________________ +Layer (type) Output Shape Param # Connected to +======================================================================================== +user_id (InputLayer) (None, 1) 0 +________________________________________________________________________________________ +movie_id (InputLayer) (None, 1) 0 +________________________________________________________________________________________ +user_embedding (Embedding) (None, 1, 8) 1107952 user_id[0][0] +________________________________________________________________________________________ +movie_embedding (Embedding) (None, 1, 8) 213952 movie_id[0][0] +________________________________________________________________________________________ +dot (Dot) (None, 1, 1) 0 user_embedding[0][0] + movie_embedding[0][0] +________________________________________________________________________________________ +flatten (Flatten) (None, 1) 0 dot[0][0] +======================================================================================== +Total params: 1,321,904 +Trainable params: 1,321,904 +Non-trainable params: 0 +________________________________________________________________________________________ +''' +``` + +让我们训练它。 + +```py +history = model.fit( + [df.userId, df.movieId], + df.y, + batch_size=5000, + epochs=20, + verbose=0, + validation_split=.05, +); +``` + +让我们将这个模型随时间的误差,与我们在上一课中训练的深度神经网络进行比较: + +![](img/emb-5.png) + +我们新的,更简单的模型(蓝色)看起来非常好。 + +然而,即使我们的嵌入相当小,两种模型都会产生一些明显的过拟合。 也就是说,训练集上的误差 - 实线 - 明显好于看不见的数据。 我们将在练习中尽快解决这个问题。 + +### 你的回合 + +前往[练习笔记本](https://www.kaggle.com/kernels/fork/1598589),进行矩阵分解的实践练习。 + +## 三、使用 Gensim 探索嵌入 + +早些时候,我们训练了一个模型,使用一个网络,它带有为每个电影和用户学习的嵌入,来预测用户为电影提供的评分。 嵌入是强大的!但他们实际如何工作? + +以前,我说嵌入捕获了它们所代表的对象的“含义”,并发现了有用的潜在结构。 让我们来测试吧! + +### 查询嵌入 + +让我们加载我们之前训练过的模型,这样我们就可以研究它学到的嵌入权重。 + +```py +import os + +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +import tensorflow as tf +from tensorflow import keras + +input_dir = '../input/movielens-preprocessing' +model_dir = '../input/movielens-spiffy-model' +model_path = os.path.join(model_dir, 'movie_svd_model_32.h5') +model = keras.models.load_model(model_path) +``` + +嵌入权重是模型内部的一部分,因此我们必须进行一些挖掘才能访问它们。 我们将获取负责嵌入电影的层,并使用`get_weights()`方法获取其学习的权重。 + +```py +emb_layer = model.get_layer('movie_embedding') +(w,) = emb_layer.get_weights() +w.shape +# (26744, 32) +``` + +对于那么多电影,我们的权重矩阵有 26,744 行。 每行是 32 个数字 - 我们的电影嵌入的大小。 + +我们来看一个示例电影向量: + +```py +w[0] +''' +array([-0.08716497, -0.25286013, -0.52679837, -0.2602235 , -0.4349191 , + -0.48805636, -0.30346015, -0.1416321 , 0.08305884, -0.17578898, + -0.36220485, 0.14578693, 0.37118354, -0.02961254, -0.063666 , + -0.5223456 , 0.0526049 , 0.47991064, -0.19034313, -0.3271599 , + 0.32792446, -0.3794548 , -0.55778086, -0.42602876, 0.14532137, + 0.21002969, -0.32203963, -0.46950188, -0.22500233, -0.08298543, + -0.00373308, -0.3885791 ], dtype=float32) +''' +``` + +这是什么电影的嵌入? 让我们加载我们的电影元数据的数据帧。 + +```py +movies_path = os.path.join(input_dir, 'movie.csv') +movies_df = pd.read_csv(movies_path, index_col=0) +movies_df.head() +``` + + +| | movieId | title | genres | key | year | n_ratings | mean_rating | +| --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 0 | Toy Story | Adventure|Animation|Children|Comedy|Fantasy | Toy Story | 1995 | 49695 | 3.921240 | +| 1 | 1 | Jumanji | Adventure|Children|Fantasy | Jumanji | 1995 | 22243 | 3.211977 | +| 2 | 2 | Grumpier Old Men | Comedy|Romance | Grumpier Old Men | 1995 | 12735 | 3.151040 | +| 3 | 3 | Waiting to Exhale | Comedy|Drama|Romance | Waiting to Exhale | 1995 | 2756 | 2.861393 | +| 4 | 4 | Father of the Bride Part II | Comedy | Father of the Bride Part II | 1995 | 12161 | 3.064592 | + +当然,这是《玩具总动员》! 我应该在任何地方认出这个向量。 + +好吧,我很滑稽。此时很难利用这些向量。 我们从未告诉模型如何使用任何特定嵌入维度。 我们只让它学习它认为有用的任何表示。 + +那么我们如何检查这些表示是否合理且连贯? + +### 向量相似度 + +测试它的一种简单方法是,查看嵌入空间中电影对有多么接近或远离。 嵌入可以被认为是智能的距离度量。 如果我们的嵌入矩阵是良好的,它应该将类似的电影(如《玩具总动员》和《怪物史莱克》)映射到类似的向量。 + +```py +i_toy_story = 0 +i_shrek = movies_df.loc[ + movies_df.title == 'Shrek', + 'movieId' +].iloc[0] + +toy_story_vec = w[i_toy_story] +shrek_vec = w[i_shrek] + +print( + toy_story_vec, + shrek_vec, + sep='\n', +) +''' +[-0.08716497 -0.25286013 -0.52679837 -0.2602235 -0.4349191 -0.48805636 + -0.30346015 -0.1416321 0.08305884 -0.17578898 -0.36220485 0.14578693 + 0.37118354 -0.02961254 -0.063666 -0.5223456 0.0526049 0.47991064 + -0.19034313 -0.3271599 0.32792446 -0.3794548 -0.55778086 -0.42602876 + 0.14532137 0.21002969 -0.32203963 -0.46950188 -0.22500233 -0.08298543 + -0.00373308 -0.3885791 ] +[ 0.0570179 0.5991162 -0.71662885 0.22245468 -0.40536046 -0.33602375 + -0.24281627 0.08997302 0.03362623 -0.12569055 -0.2764452 -0.12710975 + 0.48197436 0.2724923 0.01551001 -0.20889504 -0.04863157 0.39106563 + -0.24811408 -0.05642252 0.24475795 -0.53363544 -0.2281187 -0.17529544 + 0.21050802 -0.37807122 0.03861505 -0.27024794 -0.24332719 -0.17732081 + 0.07961234 -0.39079434] +''' +``` + +逐个维度地比较,这些看起来大致相似。 如果我们想为它们的相似度分配一个数字,我们可以计算这两个向量之间的欧氏距离。 (这是我们传统的“乌鸦飞过的”两点之间的距离的概念。容易在 1,2 或 3 维上进行研究。在数学上,我们也可以将它扩展到 32 维,虽然需要好运来可视化它。) + +```py +from scipy.spatial import distance + +distance.euclidean(toy_story_vec, shrek_vec) +# 1.4916094541549683 +``` + +这与我们认为非常不同的一对电影相比如何? + +```py +i_exorcist = movies_df.loc[ + movies_df.title == 'The Exorcist', + 'movieId' +].iloc[0] + +exorcist_vec = w[i_exorcist] + +distance.euclidean(toy_story_vec, exorcist_vec) +# 2.356588363647461 +``` + +更远了,和我们期待的一样。 + +### 余弦距离 + +如果你看看[`scipy.spatial`模块的文档](https://docs.scipy.org/doc/scipy-0.14.0/reference/spatial.distance.html),你会发现人们用于不同任务的距离,实际上有很多不同的衡量标准。 + +在判断嵌入的相似性时,使用[余弦相似性](https://en.wikipedia.org/wiki/Cosine_similarity)更为常见。 + +简而言之,两个向量的余弦相似度范围从 -1 到 1,并且是向量之间的角度的函数。 如果两个向量指向同一方向,则它们的余弦相似度为 1。如果它们指向相反的方向,它为 -1。 如果它们是正交的(即成直角),则它们的余弦相似度为 0。 + +余弦距离定义为 1 减去余弦相似度(因此范围从 0 到 2)。 + +让我们计算电影向量之间的几个余弦距离: + +```py +print( + distance.cosine(toy_story_vec, shrek_vec), + distance.cosine(toy_story_vec, exorcist_vec), + sep='\n' +) +''' +0.3593705892562866 +0.811933159828186 +''' +``` + +> 注:为什么在使用嵌入时常用余弦距离? 与许多深度学习技巧一样,简短的答案是“凭经验,它能用”。 在即将进行的练习中,你将进行一些实践调查,更深入地探讨这个问题。 + +哪部电影与《玩具总动员》最相似? 在嵌入空间中哪些电影落在 Psycho 和 Scream 之间? 我们可以编写一堆代码来解决这样的问题,但这样做非常繁琐。 幸运的是,已经有一个库可以完成这类工作:Gensim。 + +## 使用 Gensim 探索嵌入 + +我将使用我们的模型的电影嵌入和相应电影的标题,来实例化`WordEmbeddingsKeyedVectors`。 + +> 注:你可能会注意到,Gensim 的文档及其许多类和方法名称都指的是词嵌入。 虽然库最常用于文本领域,但我们可以使用它来探索任何类型的嵌入。 + +```py +from gensim.models.keyedvectors import WordEmbeddingsKeyedVectors + +# 将数据集中的电影限制为至少具有这么多评分 +threshold = 100 +mainstream_movies = movies_df[movies_df.n_ratings >= threshold].reset_index(drop=True) + +movie_embedding_size = w.shape[1] +kv = WordEmbeddingsKeyedVectors(movie_embedding_size) +kv.add( + mainstream_movies['key'].values, + w[mainstream_movies.movieId] +) +``` + +好的,哪个电影与《玩具总动员》最相似? + +```py +kv.most_similar('Toy Story') +''' +/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`. + if np.issubdtype(vec.dtype, np.int): +[('Toy Story 2', 0.9583659172058105), + ('Toy Story 3', 0.9159570932388306), + ('Finding Nemo', 0.882755696773529), + ('Monsters, Inc.', 0.8684015870094299), + ("A Bug's Life", 0.8322919607162476), + ('The Incredibles', 0.8271597623825073), + ('Ratatouille', 0.8149864673614502), + ('Up', 0.802034318447113), + ('WALL·E', 0.7794805765151978), + ('The Iron Giant', 0.7664535641670227)] +''' +``` + +哇,这些都很棒! 《玩具总动员 2》是与玩具总动员最相似的电影,这是完全合理的。 其余大多数都是具有类似计算机动画风格的动画儿童电影。 + +所以它学到了关于三维动画儿童电影的一些东西,但也许这只是一个侥幸。 让我们来看看几个不同类型的电影的最近邻居: + +``` +/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`. + if np.issubdtype(vec.dtype, np.int): +``` + +![](img/emb-6.png) + +小众的性爱剧,风骚的半吊子喜剧,老派音乐剧,超级英雄电影......我们的嵌入能够支持各种各样的电影类型! + +### 语义向量数学 + +`most_similar`方法接受可选的第二个参数`negative`。 如果我们调用`kv.most_similar(a, b)`,那么它将找到最接近`a-b`的向量,而不是找到最接近`a`的向量。 + +你为什么想这么做? 事实证明,对嵌入向量进行加法和减法通常会产生令人惊讶的有意义的结果。 例如,你将如何填写以下等式? + +``` +Scream = Psycho + ________ +``` + +Scream 和 Psycho 的相似之处在于它们是恐怖片和惊悚片之间的某个地方的暴力恐怖电影。 最大的区别是 Scream 有喜剧元素。 因此,如果你将 Psycho 与喜剧结合起来,我会说 Scream 就是你所得到的。 + +但我们实际上可以通过向量数学(在重新排列之后)让 Gensim 为我们填补空白: + +``` +________ = Scream - Psycho +``` + +```py +kv.most_similar( + positive = ['Scream'], + negative = ['Psycho (1960)'] +) +''' +/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`. + if np.issubdtype(vec.dtype, np.int): +[('Scream 3', 0.6535503268241882), + ('Scream 2', 0.6417772769927979), + ('Piranha (Piranha 3D)', 0.6411199569702148), + ('Freddy vs. Jason', 0.6275623440742493), + ('Final Destination 5', 0.6264907121658325), + ('Booty Call', 0.6207411289215088), + ("Charlie's Angels", 0.6146069765090942), + ('Mortal Kombat', 0.6145076155662537), + ('Deuce Bigalow: Male Gigolo', 0.6140967607498169), + ('Final Destination 2', 0.612423300743103)] +''' +``` + +如果你熟悉这些电影,你会发现,从 Psycho 到 Scream 的缺失成分是喜剧(也是 90 年代后期的青少年电影)。 + +### 类比解决 + +用于进入美国大学和学院的 SAT 考试提出了类似的问题: + +``` +shower : deluge :: _____ : stare +``` + +(意思是“shower”(淋浴)对于“deluge”(洪水),相当于“_____”对于“stare”(凝视)) + +为了解决这个问题,我们找到了“deluge”和“shower”之间的关系,并将其应用于“stare”。 “shower”是一种温和的“deluge”形式。 什么是温和的“stare”的形式? 这里一个好的答案是“glance”(一瞥)或“look”(看)。 + +令人惊讶的是,这种方法很有效,但人们发现这些通常可以通过单词嵌入的简单向量数学来有效地解决。 我们可以通过嵌入来解决电影类比问题吗? 我们试试吧。这样如何: + +``` +Brave : Cars 2 :: Pocahontas : _____ +``` + +答案不明确。 一种解释是,《勇敢传说》(Brave)就像《赛车总动员 2》(Cars 2),除了后者主要针对男孩,而前者可能对女孩更具吸引力,因为它是女性主角。 所以也许答案应该像《风中奇缘》(Pocahontas)一样,90 年代中期的传统动画儿童电影,但更像是一部“男孩电影”。《大力士》?《狮子王》? + +让我们问一下他们的想法。 + +在向量数学方面,我们可以将其构建为...... + +``` +Cars 2 = Brave + X +_____ = Pocahontas + X +``` + +重新排列之后,我们得到: + +``` +____ = Pocahontas + (Cars 2 - Brave) +``` + +我们可以通过将两部电影(《风中奇缘》和《赛车总动员 2》)传递给`most_similar`的`positive`,将《勇敢传说》作为`negative`参数,来解决这个问题: + +```py +kv.most_similar( + ['Pocahontas', 'Cars 2'], + negative = ['Brave'] +) +''' +/opt/conda/lib/python3.6/site-packages/gensim/matutils.py:737: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`. + if np.issubdtype(vec.dtype, np.int): +[("A Kid in King Arthur's Court", 0.8660464882850647), + ('Land Before Time III: The Time of the Great Giving', 0.8655920624732971), + ('Free Willy 2: The Adventure Home', 0.8606677651405334), + ('3 Ninjas Knuckle Up', 0.8496973514556885), + ('3 Ninjas Kick Back', 0.8479241132736206), + ('The Return of Jafar', 0.8474882245063782), + ("Beethoven's 2nd", 0.8443870544433594), + ('Air Bud: Golden Receiver', 0.84358811378479), + ('Meet the Deedles', 0.8370730876922607), + ('All Dogs Go to Heaven 2', 0.8368842601776123)] +''' +``` + +这与我们的预测无关:4 部最接近的电影确实是 90 年代的儿童动画电影。 在那之后,结果有点令人困惑。 + +我们的模型是错的,还是我们是错的? 在《赛车总动员 2》和《勇敢传说》之间,我们未能解释的另一个区别是前者是续集,而后者则不是。 我们的结果中有 7/10 也是续集。 这告诉我们关于我们学习的嵌入的一些有趣内容(最终,关于预测电影偏好的问题)。 “Sequelness”是我们模型的一个重要特性 - 这表明我们数据中的一些变化,是因为有些人倾向于比其他人更喜欢续集。 + +### 你的回合 + +前往[练习笔记本](https://www.kaggle.com/kernels/fork/1598893),进行一些动手实践,使用 gensim 探索嵌入。 + +## 四、将 t-SNE 用于可视化 + +在上一课中,我们查看了我们学习的电影嵌入的一些示例,测量了电影对之间的距离,查找了与某些电影最相似的电影,并且通过向量数学组合了电影语义。 这些是调试嵌入模型或理解嵌入模型的好方法。 但它也非常耗时。 + +在本课程中,你将学习如何使用 t-SNE 算法可视化嵌入。 这是一种很好的廉价技术,用于理解嵌入的本质。 + +### t-SNE + +可视化 1 维或 2 维的数据很容易 - 但目前尚不清楚如何可视化 8 维或 32 维的嵌入。 t-SNE 是一种降维算法,通常用于可视化。 它学习从一组高维向量到较小维数(通常为 2)的空间映射,这有望很好地表示高维空间。 + +是什么让映射成为“良好的表示”? 简而言之,t-SNE 试图确保如果高维向量`u`和`v`靠近在一起,则`map(u)`和`map(v)`在 2d 映射空间中靠近在一起。 + +### 代码 + +首先,我们将加载我们的预训练嵌入,就像之前一样。 + +```py +%matplotlib inline +import random +import os + +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +import tensorflow as tf +from tensorflow import keras + +input_dir = '../input/movielens-preprocessing' +model_dir = '../input/movielens-spiffy-model' +model_path = os.path.join(model_dir, 'movie_svd_model_32.h5') + +model = keras.models.load_model(model_path) +emb_layer = model.get_layer('movie_embedding') +(w,) = emb_layer.get_weights() + +movies_path = os.path.join(input_dir, 'movie.csv') +movies_df = pd.read_csv(movies_path, index_col=0) +``` + +正如我们在前面的课程中看到的那样,我们的数据集中有很多不起眼的电影,评分很少(有时只有一个)。 我们对这些电影知之甚少,因为它们的嵌入效果和随机一样。 我们可以通过仅仅选择满足一定流行度阈值的电影,来弄清楚我们的可视化。 + +```py +threshold = 100 +mainstream_movies = movies_df[movies_df.n_ratings >= threshold].reset_index(drop=True) +print("Went from {} to {} movies after applying threshold".format( + len(movies_df), len(mainstream_movies), +)) +w_full = w +w = w[mainstream_movies.movieId] +df = mainstream_movies +# 在应用阈值后,电影从 26744 变为 8546 部 +``` + +我们将使用 scikit-learn 的 t-SNE 实现。 + +我提到 t-SNE 在特征空间中试图保持实体之间的“接近度”。 我们在之前的课程中看到,有许多竞争性的距离概念。 默认情况下,t-SNE 使用欧氏距离。 但是因为已知余弦距离适用于嵌入,我们将在创建模型时传递`metric ="cosine"`。 + +```py +from sklearn.manifold import TSNE + +# 1,000 次迭代的默认值可以得到很好的结果, +# 但是我的训练时间更长,只是为了一些微小的改进。 +# 注意:这需要近一个小时! +tsne = TSNE(random_state=1, n_iter=15000, metric="cosine") + +embs = tsne.fit_transform(w) +# 为方便起见,添加到数据帧 +df['x'] = embs[:, 0] +df['y'] = embs[:, 1] +``` + +这是我们将电影映射到的二维向量样本: + +```py +embs[:5] +''' +array([[ -93.78184 , 74.296936 ], + [ -78.09159 , -107.294334 ], + [ 27.506392 , -73.33844 ], + [ -7.8512335, -82.217896 ], + [ -10.345706 , -71.288704 ]], dtype=float32) +''' +``` + +这种降维的全部意义在于可视化,所以让我们使用 matplotlib 绘制我们电影的散点图,使用我们新的二维映射。 + +```py +FS = (10, 8) +fig, ax = plt.subplots(figsize=FS) +# 使点变得半透明,以便我们可以直观地识别具有高密度重叠点的区域 +ax.scatter(df.x, df.y, alpha=.1); +``` + +![](img/emb-7.png) + +### 它有效嘛 + +单凭形状很难判断。 良好的理智检查是识别,我们强烈认为应该靠近的一些电影分组,看看它们是否在二维空间中接近。 + +例如,所有的哈利波特电影都应该互相接近,对吧? + +```py +# 这个和其他几个辅助函数在上面的代码单元中定义。 +# 如果你对它们的实现方式感到好奇,请点击上面的“代码”按钮。 +plot_by_title_pattern('Harry Potter', figsize=(15, 9), bg_alpha=.05, text=False); +``` + +![](img/emb-8.png) + +上面的绘图中,8 个哈利波特电影中的每一个都有一个绿点 - 但它们是如此接近,它们无法在这个刻度上区分。 是个好的标志! + +让我们放大一下,仔细看看。 + +```py +plot_region_around('Harry Potter and the Order of the Phoenix', 4); +``` + +![](img/emb-9.png) + +哈利波特的电影不仅紧密聚集在一起,而且大致按发布顺序排列! + +### 局部和全局结构 + +t-SNE 的一个关键特性使它非常适合可视化,它擅长在多个尺度上捕获簇。 我们已经看到,我们的映射成功捕获了小而紧凑的局部结构。 那些包含更多松散的相关电影的大型结构呢? + +我们在上面已经看到了这方面的一个小例子:与哈利波特电影最接近的邻居是饥饿游戏系列的电影 - 另一组基于一系列青年幻想小说的电影。这说得通! + +小众流派如何? 纪录片落在哪里? + +```py +docs = df[ (df.genres == 'Documentary') ] +plot_with_annotations(docs.index, text=False, alpha=.4, figsize=(15, 8)); +``` + +![](img/emb-10.png) + +太好了! 它不是一个紧密的簇,但这里肯定有较强的规律。 + +并且重申一下:我们从未真正将类型展示给模型作为特征。 它无法读取标题,并看到《哈利波特和魔法石》和《哈利波特和密室》属于同一系列。 它设法获取这些潜在的模式并将它们合并到嵌入空间中,只需看到数据点,例如“用户 5299 给电影 806 评分为 4.5”。 非常好! + +这是另一个稍微复杂的类型实验:可视化所有电影,其类型是`{喜剧,戏剧,浪漫}`的一部分(即喜剧,戏剧,浪漫,戏剧,浪漫剧,romcoms 和......我猜是“dromcoms”?) + +![](img/emb-11.png) + +这是最大规模的结构的一个很棒的例子。 戏剧主要在上半部分,而喜剧主要在另一半(浪漫片的分布更加分散)。 + +### 你的回合 + +前往[练习笔记本](https://www.kaggle.com/kernels/fork/1599029)进行一些实践练习,使用 t-SNE 可视化嵌入。 + +## 扩展阅读 + +我们使用 t-SNE 模型的开箱即用的默认参数取得了良好的效果,但根据你的数据特征,你可能不会那么幸运。 + +t-SNE 不是简单的闭式数学运算。 你正在训练模型,使用随机梯度下降来最小化一些非凸损失函数。 可能需要一段时间,需要一点折腾。 你甚至可以在使用相同参数训练的两个 t-SNE 模型之间看到非常不同的结果(如果你想要可重复性,则设置固定的`random_state`)。 + +如果你在尝试训练 t-SNE 模型时得到的结果不令人满意,或者你只是想了解更多数学基础和实现,那么下面的链接会提供一些你可能会觉得有用的信息。 + ++ 如果你对 t-SNE 的更深入的数学细节感兴趣,我强烈建议你查看 [Laurens van der Maaten 和 Geoff Hinton 向世界介绍 t-SNE 的原始论文](http://www.jmlr.org/papers/volume9/vandermaaten08a/vandermaaten08a.pdf)。 ++ [如何使用 t-SNE](https://distill.pub/2016/misread-tsne/) 有效地展示了一些令人难以置信的实时交互式示例,允许你将 t-SNE 应用于各种合成数据集并实时观察训练,并看到改变参数的效果,例如 perplexity。 ++ [sklearn TSNE 文档](http://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html)提供了每个参数含义的详细信息,以及一些设置它们的提示。 + + 另请参阅:[scikit-learn 的 t-SNE 用户指南](http://scikit-learn.org/stable/modules/manifold.html#t-sne) ++ [t-SNE FAQ](https://lvdmaaten.github.io/tsne/#faq) 由 Laurens van der Maaten 撰写 diff --git a/img/learn/embeddings/emb-1.png b/learn/img/emb-1.png similarity index 100% rename from img/learn/embeddings/emb-1.png rename to learn/img/emb-1.png diff --git a/img/learn/embeddings/emb-10.png b/learn/img/emb-10.png similarity index 100% rename from img/learn/embeddings/emb-10.png rename to learn/img/emb-10.png diff --git a/img/learn/embeddings/emb-11.png b/learn/img/emb-11.png similarity index 100% rename from img/learn/embeddings/emb-11.png rename to learn/img/emb-11.png diff --git a/img/learn/embeddings/emb-2.png b/learn/img/emb-2.png similarity index 100% rename from img/learn/embeddings/emb-2.png rename to learn/img/emb-2.png diff --git a/img/learn/embeddings/emb-3.png b/learn/img/emb-3.png similarity index 100% rename from img/learn/embeddings/emb-3.png rename to learn/img/emb-3.png diff --git a/img/learn/embeddings/emb-4.png b/learn/img/emb-4.png similarity index 100% rename from img/learn/embeddings/emb-4.png rename to learn/img/emb-4.png diff --git a/img/learn/embeddings/emb-5.png b/learn/img/emb-5.png similarity index 100% rename from img/learn/embeddings/emb-5.png rename to learn/img/emb-5.png diff --git a/img/learn/embeddings/emb-6.png b/learn/img/emb-6.png similarity index 100% rename from img/learn/embeddings/emb-6.png rename to learn/img/emb-6.png diff --git a/img/learn/embeddings/emb-7.png b/learn/img/emb-7.png similarity index 100% rename from img/learn/embeddings/emb-7.png rename to learn/img/emb-7.png diff --git a/img/learn/embeddings/emb-8.png b/learn/img/emb-8.png similarity index 100% rename from img/learn/embeddings/emb-8.png rename to learn/img/emb-8.png diff --git a/img/learn/embeddings/emb-9.png b/learn/img/emb-9.png similarity index 100% rename from img/learn/embeddings/emb-9.png rename to learn/img/emb-9.png diff --git a/old/.travis.yml b/old/.travis.yml deleted file mode 100644 index d02d93ae..00000000 --- a/old/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -language: node_js # 构建所需的语言环境 -node_js: - - "v10.16.0" # 对应的版本 - -branches: - only: - - master # 构建的分支 - -cache: - directories: - - node_modules # 依赖缓存的目录 - -install: - - npm install -g gitbook-cli # 安装编译工具 - - gitbook fetch 3.2.3 # 安装 Gitbook 子版本 - -script: - - sh run_website.sh - -after_script: - - cd _book - - git init - - git config user.name ${GH_UN} - - git config user.email ${GH_EMAIL} - - git add -A - - git commit -am "$(date "+%Y-%m-%d %H:%M:%S")" - - git push "https://${GH_TOKEN}@github.com/${GH_USER}/${GH_REPO}.git" master:${GH_BRANCH} -f - -env: - global: - - GH_UN=jiangzhonglian - - GH_EMAIL=jiang-s@163.com - - GH_USER=apachecn - - GH_REPO=Interview - - GH_BRANCH=gh-pages diff --git a/old/book.json b/old/book.json deleted file mode 100644 index 0508e203..00000000 --- a/old/book.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "title" : "Interview 求职指南", - "author" : "ApacheCN", - "description" : "Interview 求职指南", - "language" : "zh-hans", - "plugins": [ - "github", - "github-buttons", - "-sharing", - "insert-logo", - "sharing-plus", - "back-to-top-button", - "code", - "copy-code-button", - "pageview-count", - "edit-link", - "emphasize", - "alerts", - "auto-scroll-table", - "popup", - "hide-element", - "page-toc-button", - "tbfed-pagefooter", - "sitemap", - "advanced-emoji", - "expandable-chapters", - "splitter", - "search-pro" - ], - "pluginsConfig": { - "github": { - "url": "https://github.com/apachecn/Interview" - }, - "github-buttons": { - "buttons": [ - { - "user": "apachecn", - "repo": "Interview", - "type": "star", - "count": true, - "size": "small" - } - ] - }, - "insert-logo": { - "url": "http://data.apachecn.org/img/logo.jpg", - "style": "background: none; max-height: 150px; min-height: 150px" - }, - "hide-element": { - "elements": [".gitbook-link"] - }, - "edit-link": { - "base": "https://github.com/apachecn/Interview/blob/master", - "label": "编辑本页" - }, - "sharing": { - "qzone": true, - "weibo": true, - "twitter": false, - "facebook": false, - "google": false, - "qq": false, - "line": false, - "whatsapp": false, - "douban": false, - "all": [ - "qq", "douban", "facebook", "google", "linkedin", "twitter", "weibo", "whatsapp" - ] - }, - "page-toc-button": { - "maxTocDepth": 4, - "minTocSize": 4 - }, - "tbfed-pagefooter": { - "copyright":"Copyright © ibooker.org.cn 2019", - "modify_label": "该文件修订时间: ", - "modify_format": "YYYY-MM-DD HH:mm:ss" - }, - "sitemap": { - "hostname": "http://pytorch.apachecn.org" - } - }, - "my_links" : { - "sidebar" : { - "Home" : "https://www.baidu.com" - } - }, - "my_plugins": [ - "donate", - "todo", - "-lunr", - "-search", - "expandable-chapters-small", - "chapter-fold", - "expandable-chapters", - "expandable-chapters-small", - "back-to-top-button", - "ga", - "baidu", - "sitemap", - "tbfed-pagefooter", - "advanced-emoji", - "sectionx", - "page-treeview", - "simple-page-toc", - "ancre-navigation", - "theme-apachecn@git+https://github.com/apachecn/theme-apachecn#HEAD", - "pagefooter-apachecn@git+https://github.com/apachecn/gitbook-plugin-pagefooter-apachecn#HEAD" - ], - "my_pluginsConfig": { - "github-buttons": { - "buttons": [ - { - "user": "apachecn", - "repo": "Interview", - "type": "star", - "count": true, - "size": "small" - }, - { - "user": "apachecn", - "width": "160", - "type": "follow", - "count": true, - "size": "small" - } - ] - }, - "ignores": ["node_modules"], - "simple-page-toc": { - "maxDepth": 3, - "skipFirstH1": true - }, - "page-toc-button": { - "maxTocDepth": 2, - "minTocSize": 2 - }, - "page-treeview": { - "copyright": "Copyright © aleen42", - "minHeaderCount": "2", - "minHeaderDeep": "2" - }, - "donate": { - "wechat": "微信收款的二维码URL", - "alipay": "支付宝收款的二维码URL", - "title": "", - "button": "赏", - "alipayText": "支付宝打赏", - "wechatText": "微信打赏" - }, - "page-copyright": { - "description": "modified at", - "signature": "你的签名", - "wisdom": "Designer, Frontend Developer & overall web enthusiast", - "format": "YYYY-MM-dd hh:mm:ss", - "copyright": "Copyright © 你的名字", - "timeColor": "#666", - "copyrightColor": "#666", - "utcOffset": "8", - "style": "normal", - "noPowered": false - }, - "ga": { - "token": "UA-127082511-1" - }, - "baidu": { - "token": "84fca651656bc67b4b2d56605b6d0852" - }, - "pagefooter-apachecn": { - "copyright":"Copyright © ibooker.org.cn 2019", - "modify_label": "该文件修订时间: ", - "modify_format": "YYYY-MM-DD HH:mm:ss" - } - } -} diff --git a/old/run_website.sh b/old/run_website.sh deleted file mode 100644 index b4f5ad78..00000000 --- a/old/run_website.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -loginfo() { echo "[INFO] $@"; } -logerror() { echo "[ERROR] $@" 1>&2; } - -python3 src/script.py "home" "book" -rm -rf node_modules/gitbook-plugin-tbfed-pagefooter -gitbook install -python3 src/script.py "home" "powered" -python3 src/script.py "home" "gitalk" -gitbook build ./ _book -# python3 src/script.py "home" "index" - -versions="Algorithm/Leetcode/Python Algorithm/Leetcode/JavaScript" -for version in $versions;do - loginfo "===========================================================" - loginfo "开始", ${version}, "版本编译" - - echo "cp book.json docs/${version}" - cp book.json docs/${version} - - # 替换 book.json 的编辑地址 - echo "python3 src/script.py ${version} book" - python3 src/script.py ${version} "book" - - echo "cp -r node_modules docs/${version}" - rm -rf docs/${version}/node_modules - cp -r node_modules docs/${version} - - echo "gitbook install docs/${version}" - gitbook install docs/${version} - - echo "python3 src/script.py ${version} powered" - python3 src/script.py ${version} "powered" - - echo "python3 src/script.py ${version} gitalk" - python3 src/script.py ${version} "gitalk" - - echo "gitbook build docs/${version} _book/docs/${version}" - gitbook build docs/${version} _book/docs/${version} - - # 注释多余的内容 - # echo "python3 src/script.py ${version} index" - # python3 src/script.py ${version} "index" -done - -# rm -rf /opt/apache-tomcat-9.0.17/webapps/test_book -# cp -r _book /opt/apache-tomcat-9.0.17/webapps/test_book diff --git a/old/requirements.txt b/requirements.txt similarity index 100% rename from old/requirements.txt rename to requirements.txt diff --git "a/src/\345\205\266\344\273\226/51CFCB8475F4ED5B1CAD5F23CF96887A.jpg" b/src/51CFCB8475F4ED5B1CAD5F23CF96887A.jpg old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/51CFCB8475F4ED5B1CAD5F23CF96887A.jpg" rename to src/51CFCB8475F4ED5B1CAD5F23CF96887A.jpg diff --git "a/src/\345\205\266\344\273\226/58.md" b/src/58.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/58.md" rename to src/58.md diff --git "a/src/\345\205\266\344\273\226/5C3A0153C03FD214FE68B002903E2135.jpg" b/src/5C3A0153C03FD214FE68B002903E2135.jpg old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/5C3A0153C03FD214FE68B002903E2135.jpg" rename to src/5C3A0153C03FD214FE68B002903E2135.jpg diff --git "a/src/\345\205\266\344\273\226/B9A582497F833DDE4E93FA5BAA0BA4EB.jpg" b/src/B9A582497F833DDE4E93FA5BAA0BA4EB.jpg old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/B9A582497F833DDE4E93FA5BAA0BA4EB.jpg" rename to src/B9A582497F833DDE4E93FA5BAA0BA4EB.jpg diff --git "a/src/\345\205\266\344\273\226/WechatIMG437.jpeg" b/src/WechatIMG437.jpeg old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/WechatIMG437.jpeg" rename to src/WechatIMG437.jpeg diff --git "a/src/\345\205\266\344\273\226/WechatIMG438.jpeg" b/src/WechatIMG438.jpeg old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/WechatIMG438.jpeg" rename to src/WechatIMG438.jpeg diff --git "a/src/\345\205\266\344\273\226/aiqiyi.md" b/src/aiqiyi.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/aiqiyi.md" rename to src/aiqiyi.md diff --git "a/src/\345\205\266\344\273\226/baicizhanxiaomi.md" b/src/baicizhanxiaomi.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/baicizhanxiaomi.md" rename to src/baicizhanxiaomi.md diff --git a/src/config_nowcoder.json b/src/config_nowcoder.json deleted file mode 100644 index 60c60a75..00000000 --- a/src/config_nowcoder.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "牛客前端岗面试求职真题解析 2021~2022", - "url": "https://www.nowcoder.com/tutorial/10091/fdde7d829d5c451d9b38a2ff042a6a28", - "link": ".sub-menu-tit>h3, .sub-menu-items dd a", - "title": ".study-tit>h2", - "content": "article", - "remove": "", - "credit": true, - "optiMode": "quant", - "headers": { - "Cookie": "" - } -} \ No newline at end of file diff --git "a/src/\345\205\266\344\273\226/data_structure.md" b/src/data_structure.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/data_structure.md" rename to src/data_structure.md diff --git "a/src/\345\205\266\344\273\226/didi.md" b/src/didi.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/didi.md" rename to src/didi.md diff --git a/src/do_dir_structure.py b/src/do_dir_structure.py deleted file mode 100644 index 6a294371..00000000 --- a/src/do_dir_structure.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python3 -# coding: utf8 -import os -import sys -# 自定义包(添加:中间件) -sys.path.append(os.getcwd()) -from Middleware.tool import get_dir_files - -catalog = "docs/Algorithm/Leetcode/JavaScript" -files_path = get_dir_files(catalog, [], status=-1, str1=".DS_Store") -# print(files_path) - -for line in files_path: - if "ipynb" not in line: - l_file = line.split("/")[-2:] - filename = "%s %s" % (l_file[-1].split(".")[0], l_file[-1].split(".")[1].replace("_", " ").strip()) - filepath = " * [%s](%s)" % (filename, "/".join(l_file[-1:])) - # print(">>> ", filepath) - print(filepath) \ No newline at end of file diff --git "a/src/\345\205\266\344\273\226/glodon.md" b/src/glodon.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/glodon.md" rename to src/glodon.md diff --git "a/src/\345\205\266\344\273\226/huaweiliuxuesheng.md" b/src/huaweiliuxuesheng.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/huaweiliuxuesheng.md" rename to src/huaweiliuxuesheng.md diff --git "a/src/\345\205\266\344\273\226/indeed_tokyo.md" b/src/indeed_tokyo.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/indeed_tokyo.md" rename to src/indeed_tokyo.md diff --git "a/src/\345\205\266\344\273\226/kuaishou.md" b/src/kuaishou.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/kuaishou.md" rename to src/kuaishou.md diff --git "a/src/\345\205\266\344\273\226/liulishuo.md" b/src/liulishuo.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/liulishuo.md" rename to src/liulishuo.md diff --git "a/src/\345\205\266\344\273\226/pdd.md" b/src/pdd.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/pdd.md" rename to src/pdd.md diff --git a/src/py2.x/TreeRecursionIterator.py b/src/py2.x/TreeRecursionIterator.py old mode 100644 new mode 100755 diff --git a/src/py2.x/list2iteration.py b/src/py2.x/list2iteration.py old mode 100644 new mode 100755 diff --git a/src/py3.x/DataStructure/BinarySearch.py b/src/py3.x/DataStructure/BinarySearch.py deleted file mode 100644 index e9533cfc..00000000 --- a/src/py3.x/DataStructure/BinarySearch.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -1. 二分查找是有条件的,首先是有序,其次因为二分查找操作的是下标,所以要求是顺序表 -2. 最优时间复杂度:O(1) -3. 最坏时间复杂度:O(logn) -""" -# def binary_search(nums, data): -# """ -# 非递归解决二分查找 -# :param nums: -# :return: -# """ -# n = len(nums) -# first = 0 -# last = n - 1 -# while first <= last: -# mid = (last + first) // 2 -# if nums[mid] > data: -# last = mid - 1 -# elif nums[mid] < data: -# first = mid + 1 -# else: -# return True -# return False - - -def binary_search(nums, data): - """ - 递归解决二分查找: nums 是一个有序数组 - :param nums: - :return: - """ - n = len(nums) - if n < 1: - return False - mid = n // 2 - if nums[mid] > data: - return binary_search(nums[:mid], data) - elif nums[mid] < data: - return binary_search(nums[mid+1:], data) - else: - return True - -if __name__ == '__main__': - nums = [1, 4, 6, 8, 10, 20, 25, 30] - if binary_search(nums, 8): - print('ok') diff --git a/src/py3.x/DataStructure/BubbleSort.py b/src/py3.x/DataStructure/BubbleSort.py deleted file mode 100644 index 5aecf6b2..00000000 --- a/src/py3.x/DataStructure/BubbleSort.py +++ /dev/null @@ -1,29 +0,0 @@ -# coding:utf-8 -""" -# 冒泡排序 -# 1. 外层循环负责循环的次数,依次递减到1就停止(1个数不存在下一个值) -# 2. 内层循环负责前后两两比较, 判断是否需要交换位置,然后移动判断 - -5个数 -5 0,1,2,3,4 -4 0,1,2,3 -3 0,1,2 -2 0,1 -""" - -def bubble_sort(nums): - # 判断外出循环的次数 - index = len(nums) - 1 - while index: - print(index) - # 第一个数字,和后面每一个数字进行对比,找出最大值,放到最后!! - for i in range(index): - if nums[i] > nums[i+1]: - nums[i], nums[i+1] = nums[i+1], nums[i] - index -= 1 - - -if __name__ == "__main__": - nums = [3, 6, 8, 5, 2, 4, 9, 1, 7] - bubble_sort(nums) - print('result:', nums) diff --git a/src/py3.x/DataStructure/InsertionSort.py b/src/py3.x/DataStructure/InsertionSort.py deleted file mode 100644 index 400243c8..00000000 --- a/src/py3.x/DataStructure/InsertionSort.py +++ /dev/null @@ -1,20 +0,0 @@ -# coding:utf8 -""" -插入排序和冒泡排序的区别在于: - -插入排序的前提是:左边是有序的数列 -而冒泡排序:相邻的值进行交换,一共进行n次交换 -""" -def insertion_sort(nums): - for i in range(1, len(nums)): - while i: - if nums[i] < nums[i-1]: - nums[i], nums[i-1] = nums[i-1], nums[i] - i -= 1 - return nums - - -if __name__ == "__main__": - nums = [3, 6, 8, 5, 2, 4, 9, 1, 7] - insertion_sort(nums) - print('result:', nums) diff --git a/src/py3.x/DataStructure/SelectionSort.py b/src/py3.x/DataStructure/SelectionSort.py deleted file mode 100644 index 6be69a2f..00000000 --- a/src/py3.x/DataStructure/SelectionSort.py +++ /dev/null @@ -1,21 +0,0 @@ -# coding:utf8 -""" -选择排序和冒泡排序的区别在于: - -选择排序的前提是:找到最小值的位置,最后才进行1次交换 -而冒泡排序:相邻的值进行交换,一共进行n次交换 -""" -def selection_sort(nums): - for i in range(len(nums)-1): - index = i - # 考虑到数组会遇到多个最小值,所以比较的时候直接用index表示当前比较最小 - for j in range(i+1, len(nums)): - if nums[index] > nums[j]: - index = j - nums[i], nums[index] = nums[index], nums[i] - - -if __name__ == "__main__": - nums = [3, 6, 8, 5, 2, 4, 9, 1, 7] - selection_sort(nums) - print('result:', nums) diff --git a/src/py3.x/TreeRecursionIterator.py b/src/py3.x/TreeRecursionIterator.py old mode 100644 new mode 100755 diff --git a/src/py3.x/kaggle/getting-started/titanic/titanic-python3.6.py b/src/py3.x/kaggle/getting-started/titanic/titanic-python3.6.py deleted file mode 100644 index 141a4003..00000000 --- a/src/py3.x/kaggle/getting-started/titanic/titanic-python3.6.py +++ /dev/null @@ -1,358 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -''' -Created on 2019-08-14 -Update on 2019-08-31 -Author: 片刻 -Github: https://github.com/apachecn/Interview -''' -import re -import datetime -import numpy as np -import pandas as pd -import seaborn as sns -import matplotlib.pyplot as plt -from sklearn import preprocessing -from sklearn.decomposition import PCA -from sklearn.metrics import roc_auc_score -from sklearn.model_selection import KFold, cross_val_score, train_test_split -from xgboost import XGBClassifier -from sklearn.linear_model import LogisticRegression -from sklearn.svm import SVC -from sklearn.tree import DecisionTreeClassifier -from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier, VotingClassifier - - -# 加载数据 -def opencsv(): - root_path = '/opt/data/kaggle/getting-started/titanic' - - tr_data = pd.read_csv('%s/%s' % (root_path, 'input/train.csv'), header=0) - te_data = pd.read_csv('%s/%s' % (root_path, 'input/test.csv'), header=0) - - # print(tr_data.head(5)) - # print(tr_data.info()) - # # 返回数值型变量的统计量 - # print(tr_data.describe()) - - # 数据预处理(清洗、缺失值) - do_DataPreprocessing(tr_data) - # print(tr_data.head(5)) - # print(tr_data.dtypes) - # print(te_data.describe()) - - do_DataPreprocessing(te_data) - # print(te_data.head(5)) - # print(te_data.dtypes) - # print(te_data.describe()) - - # # 相关性分析 - # # 相关性协方差表, corr()函数,返回结果接近0说明无相关性,大于0说明是正相关,小于0是负相关. - # train_corr = tr_data.corr() - # print(train_corr) - # # 画出相关性热力图 - # a = plt.subplots(figsize=(15,9))#调整画布大小 - # a = sns.heatmap(train_corr, vmin=-1, vmax=1 , annot=True , square=True) #画热力图 - # plt.show() - # """ - # Survived Pclass Sex Age Parch Fare Embarked Title NameLength - # Survived 1.000000 -0.338481 0.543351 -0.064910 0.081629 0.257307 0.106811 0.354072 0.332350 - # Pclass -0.338481 1.000000 -0.131900 -0.339898 0.018443 -0.549500 0.045702 -0.211552 -0.220001 - # Sex 0.543351 -0.131900 1.000000 -0.081163 0.245489 0.182333 0.116569 0.419760 0.448759 - # Age -0.064910 -0.339898 -0.081163 1.000000 -0.172482 0.096688 -0.009165 -0.037174 0.039702 - # Parch 0.081629 0.018443 0.245489 -0.172482 1.000000 0.216225 -0.078665 0.235164 0.252282 - # Fare 0.257307 -0.549500 0.182333 0.096688 0.216225 1.000000 0.062142 0.122872 0.155832 - # Embarked 0.106811 0.045702 0.116569 -0.009165 -0.078665 0.062142 1.000000 0.055788 -0.107749 - # Title 0.354072 -0.211552 0.419760 -0.037174 0.235164 0.122872 0.055788 1.000000 0.436099 - # NameLength 0.332350 -0.220001 0.448759 0.039702 0.252282 0.155832 -0.107749 0.436099 1.000000 - # """ - - # 对于PessengerId 忽略,这个是自增长没意义 - pids = te_data['PassengerId'].tolist() - tr_data.drop(['PassengerId'], axis=1,inplace=True) - te_data.drop(['PassengerId'], axis=1,inplace=True) - train_data = tr_data.values[:, 1:] # 读入全部训练数据, [行,列] - train_label = tr_data.values[:, 0] # 读取列表的第一列 - test_data = te_data.values[:, :] # 测试全部测试个数据 - return train_data, train_label, test_data, pids - - -def do_DataPreprocessing(titanic): - """ - | Survival | 生存 | 0 = No, 1 = Yes | - | Pclass | 票类别-社会地位 | 1 = 1st, 2 = 2nd, 3 = 3rd | - | Name | 姓名 | | - | Sex | 性别 | | - | Age | 年龄 | | - | SibSp | 船上的兄弟姐妹/配偶 | | - | Parch | 船上的父母/孩子的数量 | | - | Ticket | 票号 | | - | Fare | 乘客票价 | | - | Cabin | 客舱号码 | | - | Embarked | 登船港口 | C=Cherbourg, Q=Queenstown, S=Southampton | - - >>> print(titanic.describe()) - PassengerId Survived Pclass Age SibSp Parch Fare - count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000 - mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208 - std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429 - min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000 - 25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400 - 50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200 - 75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000 - max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200 - - Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked - 3 Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.25 S - 1 Cumings, Mrs. John Bradley female 38 1 0 PC 17599 71.2833 C85 C - """ - # 组合特征(特征组合相关性变差了) - # titanic["FamilySize"] = titanic["SibSp"] + titanic["Parch"] - - # 对缺失值处理(Age 中位数不错) - titanic["Age"] = titanic["Age"].fillna(titanic["Age"].median()) - titanic["Fare"] = titanic["Fare"].fillna(titanic["Fare"].median()) - - # 对文本特征进行处理(性别, 登船港口) - # print(titanic["Sex"].unique()) - titanic.loc[titanic["Sex"]=="male", "Sex"] = 0 - titanic.loc[titanic["Sex"]=="female", "Sex"] = 1 - - # S的概率最大,当然我们也可以按照概率随机算,都可以 - # print(titanic["Embarked"].unique()) - """ - titanic[["Embarked"]].groupby("Embarked").agg({"Embarked": "count"}) - Embarked - Embarked - C 168 - Q 77 - S 644 - """ - titanic["Embarked"] = titanic["Embarked"].fillna('S') - titanic.loc[titanic["Embarked"] == "S", "Embarked"] = 0 - titanic.loc[titanic["Embarked"] == "C", "Embarked"] = 1 - titanic.loc[titanic["Embarked"] == "Q", "Embarked"] = 2 - - def get_title(name): - # 名字的尊称 - title_search = re.search(' ([A-Za-z]+)\.', name) - if title_search: - return title_search.group(1) - return "" - titles = titanic["Name"].apply(get_title) - # print(pd.value_counts(titles)) - # 对尊称建立mapping字典 - title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Dr": 5, "Rev": 6, "Major": 7, "Col": 7, "Mlle": 8, "Mme": 8, "Don": 9, "Dona": 9, "Lady": 10, "Countess": 10, "Jonkheer": 10, "Sir": 9, "Capt": 7, "Ms": 2} - for k, v in title_mapping.items(): - titles[titles == k] = v - # print(pd.value_counts(titles)) - - # 添加一个新特征表示拥护尊称 - titanic["Title"] = [int(i) for i in titles.values.tolist()] - # 添加一个新特征表示名字长度 - titanic["NameLength"] = titanic["Name"].apply(lambda x: len(x)) - - # 相关性太差,删除 - # titanic.drop(['PassengerId'], axis=1,inplace=True) - titanic.drop(['Cabin'], axis=1,inplace=True) - titanic.drop(['SibSp'], axis=1,inplace=True) - # titanic.drop(['Parch'],axis=1,inplace=True) - titanic.drop(['Ticket'], axis=1,inplace=True) - titanic.drop(['Name'], axis=1,inplace=True) - - -def do_FeatureEngineering(data, COMPONENT_NUM=0.9): - # scale values 归一化 - scaler = preprocessing.StandardScaler() - s_data = scaler.fit_transform(data) - return s_data - - # # 降维(不降维,准确率还上升了) - # ''' - # 使用说明:https://www.cnblogs.com/pinard/p/6243025.html - # n_components>=1 - # n_components=NUM 设置占特征数量比 - # 0 < n_components < 1 - # n_components=0.99 设置阈值总方差占比 - # ''' - # pca = PCA(n_components=COMPONENT_NUM, whiten=False) - # # 只训练 训练集数据 - # pca.fit(s_data) # Fit the model with X - # # 训练集 和 测试集 保持一直,进行 transform - # pca_data = pca.transform(s_data) # Fit the model with X and 在X上完成降维. - - # # pca 方差大小、方差占比、特征数量 - # # print("方差大小:\n", pca.explained_variance_, "方差占比:\n", pca.explained_variance_ratio_) - # print("特征数量: %s" % pca.n_components_) - # print("总方差占比: %s" % sum(pca.explained_variance_ratio_)) - - # return pca_data - - -def trainModel(trainData, trainLabel): - - # 模拟测试 - # 0.881994680700563 [0.87480519 0.91168831 0.89090909 0.85294118 0.87962963] - # model = LogisticRegression(random_state=1) - # 0.8819594261947202 [0.87532468 0.91272727 0.89298701 0.84912854 0.87962963] - # model = RandomForestClassifier(random_state=1, n_estimators=100, min_samples_split=4, min_samples_leaf=2) - # 0.8812371898254252 [0.87428571 0.90857143 0.89402597 0.84803922 0.88126362] - # model = RandomForestClassifier(random_state=1, n_estimators=50, min_samples_split=8, min_samples_leaf=4) - - # # 网格搜索 ##### - # from sklearn.model_selection import GridSearchCV - # param_test = { - # # 'n_estimators': np.arange(190, 240, 2), - # 'max_depth': np.arange(4, 7, 1), - # 'learning_rate': np.array([0.01, 0.03, 0.05, 0.08, 0.1, 0.15, 0.2]), - - # 'n_estimators': np.array([222]), - # # 'max_depth': np.array([4]), - # # 'learning_rate': np.array([0.01, 0.02, 0.03, 0.04, 0.05]), - # # 'min_child_weight': np.arange(1, 6, 2), - # # 'C': (1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9) - # } - - # 0.8294499549079417 [0.82122905 0.80446927 0.86516854 0.82022472 0.83615819] - # model = XGBClassifier() - # grid_search = GridSearchCV(estimator=model, param_grid=param_test, scoring='roc_auc', cv=5) - # grid_search.fit(trainData, trainLabel) - # print("最优得分 >>>", grid_search.best_score_) - # print("最优参数 >>>", grid_search.best_params_) - - # model = XGBClassifier(learning_rate = 0.1, n_estimators= 202, max_depth= 4, - # min_child_weight= 5, gamma=0, subsample=0.8, colsample_bytree=0.8, - # objective= 'binary:logistic', scale_pos_weight=1 - # ) - # 0.8825292702939761 [0.87272727 0.91376623 0.89194805 0.84912854 0.88507625] - # 0.8812472625413802 [0.87480519 0.91012987 0.89090909 0.85239651 0.87799564] - # model = XGBClassifier(n_estimators=222, max_depth=4, learning_rate=0.03) - - # scores = cross_val_score(model, trainData, trainLabel, cv=5, scoring='roc_auc') - # print(scores.mean(), "\n", scores) - print("模型融合") - """ - Bagging: 同一模型的投票选举 - Boosting: 同一模型的再学习 - Voting: 不同模型的投票选举 - Stacking: 分层预测 – K-1份数据预测1份模型拼接,得到 预测结果*算法数(作为特征) => 从而预测最终结果 - Blending: 分层预测 – 将数据分成2部分(A部分训练B部分得到预测结果),得到 预测结果*算法数(作为特征) => 从而预测最终结果 - """ - # 1. Bagging 算法实现 - # 0.8818756755227344 [0.87324675 0.91428571 0.89090909 0.85076253 0.88017429] - # model = RandomForestClassifier(random_state=1, n_estimators=100, min_samples_split=4, min_samples_leaf=2) - - # 2. Boosting 算法实现 - # 0.8488710896477386 [0.8198946 0.82285903 0.87780749 0.84906417 0.87473017] - # model = AdaBoostClassifier(random_state=1, n_estimators=100, learning_rate=1) - - # 3. Voting - # 0.8815388054211584 [0.87480519 0.91272727 0.89194805 0.84912854 0.87908497] - # model = VotingClassifier( - # estimators=[ - # ('log_clf', LogisticRegression()), - # ('ab_clf', AdaBoostClassifier()), - # ('svm_clf', SVC(probability=True)), - # ('rf_clf', RandomForestClassifier()), - # ('gbdt_clf', GradientBoostingClassifier()), - # ('rb_clf', AdaBoostClassifier()) - # ], voting='soft') # , voting='hard') - # scores = cross_val_score(model, trainData, trainLabel, cv=5, scoring='roc_auc') - # print(scores.mean(), "\n", scores) - - # # 4. Stacking - # # 0.8813662677192088 [0.87532468 0.90805195 0.89142857 0.85348584 0.87854031] - # clfs = [ - # AdaBoostClassifier(), - # SVC(probability=True), - # AdaBoostClassifier(), - # LogisticRegression(C=0.1,max_iter=100), - # XGBClassifier(max_depth=6,n_estimators=100,num_round = 5), - # RandomForestClassifier(n_estimators=100,max_depth=6,oob_score=True), - # GradientBoostingClassifier(learning_rate=0.3,max_depth=6,n_estimators=100) - # ] - # kf = KFold(n_splits=5, shuffle=True, random_state=1) - - # # 创建零矩阵 - # dataset_stacking_train = np.zeros((trainData.shape[0], len(clfs))) - # # dataset_stacking_label = np.zeros((trainLabel.shape[0], len(clfs))) - - # for j, clf in enumerate(clfs): - # '''依次训练各个单模型''' - # for i,(train, test) in enumerate(kf.split(trainLabel)): - # '''使用第i个部分作为预测,剩余的部分来训练模型,获得其预测的输出作为第i部分的新特征。''' - # # print("Fold", i) - # X_train, y_train, X_test, y_test = trainData[train], trainLabel[train], trainData[test], trainLabel[test] - # clf.fit(X_train, y_train) - # y_submission = clf.predict_proba(X_test)[:, 1] - - # # j 表示每一次的算法,而 test是交叉验证得到的每一行(也就是每一个算法把测试机和都预测了一遍) - # dataset_stacking_train[test, j] = y_submission - - # # 用建立第二层模型 - # model = LogisticRegression(C=0.1, max_iter=100) - # model.fit(dataset_stacking_train, trainLabel) - # scores = cross_val_score(model, dataset_stacking_train, trainLabel, cv=5, scoring='roc_auc') - # print(scores.mean(), "\n", scores) - - # 5. Blending - # 0.8838950287185581 [0.87584416 0.91064935 0.89714286 0.85294118 0.8828976 ] - clfs = [ - AdaBoostClassifier(), - SVC(probability=True), - AdaBoostClassifier(), - LogisticRegression(C=0.1,max_iter=100), - XGBClassifier(max_depth=6,n_estimators=100,num_round = 5), - RandomForestClassifier(n_estimators=100,max_depth=6,oob_score=True), - GradientBoostingClassifier(learning_rate=0.3,max_depth=6,n_estimators=100) - ] - X_d1, X_d2, y_d1, y_d2 = train_test_split(trainData, trainLabel, test_size=0.5, random_state=2017) - dataset_d1 = np.zeros((X_d2.shape[0], len(clfs))) - dataset_d2 = np.zeros((trainLabel.shape[0], len(clfs))) - - for j, clf in enumerate(clfs): - #依次训练各个单模型 - # 对于测试集,直接用这k个模型的预测值作为新的特征。 - clf.fit(X_d1, y_d1) - dataset_d1[:, j] = clf.predict_proba(X_d2)[:, 1] - # 用建立第二层模型 - model = LogisticRegression(C=0.1, max_iter=100) - model.fit(dataset_d1, y_d2) - - scores = cross_val_score(model, dataset_d1, y_d2, cv=5, scoring='roc_auc') - print(scores.mean(), "\n", scores) - return model - - -def main(): - # 开始时间 - sta_time = datetime.datetime.now() - - # 1.加载数据和预处理 - train_data, train_label, test_data, pids = opencsv() - - # 2. 特征工程 - pca_tr_data = do_FeatureEngineering(train_data) - pca_te_data = do_FeatureEngineering(test_data) - - # 3. 模型训练/模型融合(分类问题: lr、rf、adboost、xgboost、lightgbm) - model = trainModel(pca_tr_data, train_label) - model.fit(pca_tr_data, train_label) - labels = model.predict(pca_te_data) - - # 4. 数据导出 - print(type(pids), type(labels.tolist())) - result = pd.DataFrame({ - 'PassengerId': pids, - 'Survived': [int(i) for i in labels.tolist()] - }) - result.to_csv('Result_titanic.csv', index=False) - - # 结束时间 - end_time = datetime.datetime.now() - times = (end_time - sta_time).seconds - print("\n运行时间: %ss == %sm == %sh\n\n" % (times, times/60, times/60/60)) - - -if __name__ == "__main__": - main() diff --git a/src/py3.x/list2iteration.py b/src/py3.x/list2iteration.py old mode 100644 new mode 100755 diff --git a/src/py3.x/sort/BubbleSort.py b/src/py3.x/sort/BubbleSort.py new file mode 100755 index 00000000..aa518bb4 --- /dev/null +++ b/src/py3.x/sort/BubbleSort.py @@ -0,0 +1,20 @@ +# coding:utf-8 + + +# 冒泡排序 +# 1. 外层循环负责帮忙递减内存循环的次数【1, len-1】 +# 2. 内层循环负责前后两两比较, index 的取值范围【0, len-2】 len-1-i 次,求最大值放到最后 +def bubble_sort(nums): + # [1, len-1] + for i in range(1, len(nums)-1): + # [0, len-1-i] + for j in range(len(nums)-i): # j为列表下标 + if nums[j] > nums[j+1]: + nums[j], nums[j+1] = nums[j+1], nums[j] + return nums + + +if __name__ == "__main__": + nums = [2, 6, 8, 5, 1, 4, 9, 3, 7] + bubble_sort(nums) + print('result:', nums) diff --git a/src/py3.x/sort/InsertionSort.py b/src/py3.x/sort/InsertionSort.py new file mode 100755 index 00000000..2c49a75b --- /dev/null +++ b/src/py3.x/sort/InsertionSort.py @@ -0,0 +1,26 @@ +# coding:utf8 +""" +插入排序和冒泡排序的区别在于: + +插入排序的前提是:左边是有序的数列 +而冒泡排序:相邻的值进行交换,一共进行n次交换 +""" +from __future__ import print_function + + +def insertionSort(nums): + if not nums or len(nums) < 2: + return nums + + for i in range(1, len(nums)): + for j in range(i): + if nums[i] < nums[j]: + nums[i], nums[j] = nums[j], nums[i] + return nums + + +if __name__ == "__main__": + nums = [5, 1, 9, 3, 2, 7] + print('input: ', nums) + nums = insertionSort(nums) + print("result: ", nums) diff --git a/src/py3.x/DataStructure/MergeSort.py b/src/py3.x/sort/MergeSort.py old mode 100644 new mode 100755 similarity index 100% rename from src/py3.x/DataStructure/MergeSort.py rename to src/py3.x/sort/MergeSort.py diff --git a/src/py3.x/DataStructure/QuickSort.py b/src/py3.x/sort/QuickSort.py old mode 100644 new mode 100755 similarity index 96% rename from src/py3.x/DataStructure/QuickSort.py rename to src/py3.x/sort/QuickSort.py index db4187bb..f8753b44 --- a/src/py3.x/DataStructure/QuickSort.py +++ b/src/py3.x/sort/QuickSort.py @@ -1,5 +1,7 @@ #!/usr/bin/python # coding:utf8 + + def quick_sort(nums, start, end): i = start j = end @@ -28,6 +30,6 @@ def quick_sort(nums, start, end): if __name__ == "__main__": - nums = [3, 6, 8, 5, 2, 4, 9, 1, 7] + nums = [2, 6, 8, 5, 1, 4, 9, 3, 7] quick_sort(nums, 0, len(nums) - 1) print('result:', nums) diff --git a/src/py3.x/DataStructure/RadixSort.py b/src/py3.x/sort/RadixSort.py old mode 100644 new mode 100755 similarity index 100% rename from src/py3.x/DataStructure/RadixSort.py rename to src/py3.x/sort/RadixSort.py diff --git a/src/py3.x/sort/SelectionSort.py b/src/py3.x/sort/SelectionSort.py new file mode 100755 index 00000000..a52a8ef4 --- /dev/null +++ b/src/py3.x/sort/SelectionSort.py @@ -0,0 +1,29 @@ +# coding:utf8 +""" +选择排序和冒泡排序的区别在于: + +选择排序的前提是:找到最大值的位置,最后才进行1次交换 +而冒泡排序:相邻的值进行交换,一共进行n次交换 +""" +from __future__ import print_function + + +def selection_sort(l): + length = len(l) - 1 + + while length: + index = length + # 第一个数字,和后面每一个数字进行对比,找出最大值,放到最后!! + for j in range(length): + if l[j] > l[index]: + index = j + l[length], l[index] = l[index], l[length] + print(len(l) - length, l) + length -= 1 + + +if __name__ == "__main__": + l = [5, 1, 9, 3, 2, 7] + print(l) + selection_sort(l) + print("result: " + str(l)) \ No newline at end of file diff --git a/src/py3.x/DataStructure/ShellSort.py b/src/py3.x/sort/ShellSort.py old mode 100644 new mode 100755 similarity index 100% rename from src/py3.x/DataStructure/ShellSort.py rename to src/py3.x/sort/ShellSort.py diff --git a/src/py3.x/kaggle/featured/mercari-price-suggestion-challenge/script.py b/src/python/featured/mercari-price-suggestion-challenge/script.py similarity index 100% rename from src/py3.x/kaggle/featured/mercari-price-suggestion-challenge/script.py rename to src/python/featured/mercari-price-suggestion-challenge/script.py diff --git a/src/py3.x/kaggle/getting-started/digit-recognizer/cnn_keras-python3.6.py b/src/python/getting-started/digit-recognizer/cnn_keras-python3.6.py similarity index 100% rename from src/py3.x/kaggle/getting-started/digit-recognizer/cnn_keras-python3.6.py rename to src/python/getting-started/digit-recognizer/cnn_keras-python3.6.py diff --git a/src/py3.x/kaggle/getting-started/digit-recognizer/cnn_pytorch-python3.6.py b/src/python/getting-started/digit-recognizer/cnn_pytorch-python3.6.py similarity index 100% rename from src/py3.x/kaggle/getting-started/digit-recognizer/cnn_pytorch-python3.6.py rename to src/python/getting-started/digit-recognizer/cnn_pytorch-python3.6.py diff --git a/src/py3.x/kaggle/getting-started/digit-recognizer/knn-python3.6.py b/src/python/getting-started/digit-recognizer/knn-python3.6.py similarity index 100% rename from src/py3.x/kaggle/getting-started/digit-recognizer/knn-python3.6.py rename to src/python/getting-started/digit-recognizer/knn-python3.6.py diff --git a/src/py3.x/kaggle/getting-started/digit-recognizer/nn-python3.6.py b/src/python/getting-started/digit-recognizer/nn-python3.6.py similarity index 100% rename from src/py3.x/kaggle/getting-started/digit-recognizer/nn-python3.6.py rename to src/python/getting-started/digit-recognizer/nn-python3.6.py diff --git a/src/py3.x/kaggle/getting-started/digit-recognizer/rf-python3.6.py b/src/python/getting-started/digit-recognizer/rf-python3.6.py similarity index 100% rename from src/py3.x/kaggle/getting-started/digit-recognizer/rf-python3.6.py rename to src/python/getting-started/digit-recognizer/rf-python3.6.py diff --git a/src/py3.x/kaggle/getting-started/digit-recognizer/svm-python3.6.py b/src/python/getting-started/digit-recognizer/svm-python3.6.py similarity index 100% rename from src/py3.x/kaggle/getting-started/digit-recognizer/svm-python3.6.py rename to src/python/getting-started/digit-recognizer/svm-python3.6.py diff --git a/src/py3.x/kaggle/getting-started/house-prices/base-model_lasso_python3.6.py b/src/python/getting-started/house-prices/base-model_lasso_python3.6.py similarity index 100% rename from src/py3.x/kaggle/getting-started/house-prices/base-model_lasso_python3.6.py rename to src/python/getting-started/house-prices/base-model_lasso_python3.6.py diff --git a/src/py3.x/kaggle/getting-started/house-prices/deeplearning_method.py b/src/python/getting-started/house-prices/deeplearning_method.py similarity index 100% rename from src/py3.x/kaggle/getting-started/house-prices/deeplearning_method.py rename to src/python/getting-started/house-prices/deeplearning_method.py diff --git a/src/py3.x/kaggle/getting-started/house-prices/housePredice_335.py b/src/python/getting-started/house-prices/housePredice_335.py similarity index 100% rename from src/py3.x/kaggle/getting-started/house-prices/housePredice_335.py rename to src/python/getting-started/house-prices/housePredice_335.py diff --git a/src/py3.x/kaggle/getting-started/house-prices/jiangheng_houseprice.py b/src/python/getting-started/house-prices/jiangheng_houseprice.py similarity index 100% rename from src/py3.x/kaggle/getting-started/house-prices/jiangheng_houseprice.py rename to src/python/getting-started/house-prices/jiangheng_houseprice.py diff --git a/src/py3.x/kaggle/getting-started/titanic/introduction-to-ensemblingStacking-in-python.py b/src/python/getting-started/titanic/introduction-to-ensemblingStacking-in-python.py similarity index 100% rename from src/py3.x/kaggle/getting-started/titanic/introduction-to-ensemblingStacking-in-python.py rename to src/python/getting-started/titanic/introduction-to-ensemblingStacking-in-python.py diff --git a/src/python/getting-started/titanic/titanic-python3.6.py b/src/python/getting-started/titanic/titanic-python3.6.py new file mode 100644 index 00000000..7af1826d --- /dev/null +++ b/src/python/getting-started/titanic/titanic-python3.6.py @@ -0,0 +1,25 @@ +#!/usr/bin/python +# coding: utf-8 +''' +Created on 2017-10-26 +Update on 2017-10-26 +Author: 片刻 +Github: https://github.com/apachecn/kaggle +''' + +# 导入相关数据包 +import numpy as np +import pandas as pd +# import seaborn as sns +import matplotlib.pyplot as plt + +root_path = '/opt/git/kaggle/datasets/getting-started/titanic/input' + +train_data = pd.read_csv('%s/%s' % (root_path, 'train.csv')) +test_data = pd.read_csv('%s/%s' % (root_path, 'test.csv')) + + +print(train_data.head(5)) +print(train_data.info()) +# # 返回数值型变量的统计量 +print(train_data.describe()) diff --git a/src/py3.x/kaggle/getting-started/titanic/titanic.py b/src/python/getting-started/titanic/titanic.py similarity index 97% rename from src/py3.x/kaggle/getting-started/titanic/titanic.py rename to src/python/getting-started/titanic/titanic.py index 8d0127f8..272788e5 100644 --- a/src/py3.x/kaggle/getting-started/titanic/titanic.py +++ b/src/python/getting-started/titanic/titanic.py @@ -1,191 +1,191 @@ -# -*- coding: utf-8 -*- -""" -Created on 2017-12-07 -Update on 2017-12-24 -Team: 一把梭 -Github: https://github.com/apachecn/kaggle -""" - -import numpy as np -import pandas as pd -from sklearn.preprocessing import StandardScaler -from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier -from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier -from sklearn.ensemble import VotingClassifier -from sklearn.linear_model import LogisticRegression -from sklearn.svm import SVC -from sklearn.model_selection import cross_val_score - -# 0. 数据读入及预处理 -root_path = 'datasets/getting-started/titanic/input' -data_train = pd.read_csv('%s/%s' % (root_path, 'train.csv')) -# data_train.info() -# print(data_train.describe()) - -# 1. 去除唯一属性特 -data_train.drop(['PassengerId', 'Ticket'], axis=1, inplace=True) - -# 2. 类别特征One-Hot编码 -data_train['Sex'] = data_train['Sex'].map({'female': 0, 'male': 1}).astype(np.int64) -data_train.loc[data_train.Embarked.isnull(), 'Embarked'] = 'S' # 2个Embarked缺失值直接填充为S -data_train = pd.concat([data_train, pd.get_dummies(data_train.Embarked)], axis=1) -data_train = data_train.rename(columns={'C': 'Cherbourg','Q': 'Queenstown','S': 'Southampton'}) - -# 将名字转换 -def replace_name(x): - if 'Mrs' in x: return 'Mrs' - elif 'Mr' in x: return 'Mr' - elif 'Miss' in x: return 'Miss' - else: return 'Other' - -data_train['Name'] = data_train['Name'].map(lambda x:replace_name(x)) -data_train = pd.concat([data_train, pd.get_dummies(data_train.Name)], axis=1) -data_train = data_train.rename(columns={'Miss': 'Name_Miss','Mr': 'Name_Mr', - 'Mrs': 'Name_Mrs','Other': 'Name_Other'}) - -# 3. 数值特征标准化 -def fun_scale(df_feature): - np_feature = df_feature.values.reshape(-1,1).astype(np.float64) - feature_scale = StandardScaler().fit(np_feature) - feature_scaled = StandardScaler().fit_transform(np_feature, feature_scale) - return feature_scale, feature_scaled - -Pclass_scale, data_train['Pclass_scaled'] = fun_scale(data_train['Pclass']) -Fare_scale, data_train['Fare_scaled'] = fun_scale(data_train['Fare']) -SibSp_scale, data_train['SibSp_scaled'] = fun_scale(data_train['SibSp']) -Parch_scale, data_train['Parch_scaled'] = fun_scale(data_train['Parch']) - -# 4. 缺失值补全及相应处理 -# 处理Age缺失值并标准化 -# 缺失值处理函数 -def set_missing_feature(train_for_missingkey, data, info): - known_feature = train_for_missingkey[train_for_missingkey.Age.notnull()].as_matrix() - unknown_feature = train_for_missingkey[train_for_missingkey.Age.isnull()].as_matrix() - y = known_feature[:, 0] # 第1列作为待补全属性 - x = known_feature[:, 1:] # 第2列及之后的属性作为预测属性 - rf = RandomForestRegressor(random_state=0, n_estimators=100) - rf.fit(x, y) - print(info, "缺失值预测得分", rf.score(x, y)) - predictage = rf.predict(unknown_feature[:, 1:]) - data.loc[data.Age.isnull(), 'Age'] = predictage - return data - -train_for_missingkey_train = data_train[['Age','Survived','Sex','Name_Miss','Name_Mr','Name_Mrs', - 'Name_Other','Fare_scaled','SibSp_scaled','Parch_scaled']] -data_train = set_missing_feature(train_for_missingkey_train, data_train,'Train_Age') -Age_scale, data_train['Age_scaled'] = fun_scale(data_train['Age']) - -# 处理Cabin特征 -def set_Cabin_type(df): - df.loc[ (df.Cabin.notnull()), 'Cabin' ] = 1. - df.loc[ (df.Cabin.isnull()), 'Cabin' ] = 0. - return df - -data_train = set_Cabin_type(data_train) - -# 5. 整合数据 -train_X = data_train[['Sex','Cabin','Cherbourg','Queenstown','Southampton','Name_Miss','Name_Mr','Name_Mrs','Name_Other', - 'Pclass_scaled','Fare_scaled','SibSp_scaled','Parch_scaled','Age_scaled']].as_matrix() -train_y = data_train['Survived'].as_matrix() - -# 6. 模型搭建及交叉验证 -lr = LogisticRegression(C=1.0, tol=1e-6) -svc = SVC(C=1.1, kernel='rbf', decision_function_shape='ovo') -adaboost = AdaBoostClassifier(n_estimators=490, random_state=0) -randomf = RandomForestClassifier(n_estimators=185, max_depth=5, random_state=0) -gbdt = GradientBoostingClassifier(n_estimators=436, max_depth=2, random_state=0) -VotingC = VotingClassifier(estimators=[('LR',lr),('SVC',svc),('AdaBoost',adaboost), - ('RandomF',randomf),('GBDT',gbdt)]) - -''' -# 交叉验证部分 ##### -param_test = { - 'n_estimators': np.arange(200, 240, 1), - 'max_depth': np.arange(4, 7, 1), - #'min_child_weight': np.arange(1, 6, 2), - #'C': (1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9) - } - -from sklearn.grid_search import GridSearchCV - -grid_search = GridSearchCV(estimator=xgbClassifier, param_grid=param_test, scoring='roc_auc', cv=5) -grid_search.fit(train_X,train_y) -grid_search.grid_scores_, grid_search.best_params_, grid_search.best_score_ -# 交叉验证部分 ##### -''' - -# 模型训练及交叉验证 -classifierlist = [('LR',lr),('SVC',svc),('AdaBoost',adaboost),('RandomF',randomf), - ('GBDT',gbdt),('VotingC',VotingC)] -for name, classifier in classifierlist: - # 分类器训练与下一步交叉验证无关,训练是为下面测试集预测使用 - classifier.fit(train_X, train_y) - print(name, "Mean_Cross_Val_Score is:", - cross_val_score(classifier, train_X, train_y, cv=5, scoring='accuracy').mean(), "\n") - -# 7. 测试集处理 -data_test = pd.read_csv('test.csv') -data_test.drop(['Ticket'], axis=1, inplace=True) - -data_test['Sex'] = data_test['Sex'].map({'female': 0, 'male': 1}).astype(np.int64) -data_test = pd.concat([data_test, pd.get_dummies(data_test.Embarked)], axis=1) -data_test = data_test.rename(columns={'C': 'Cherbourg','Q': 'Queenstown','S': 'Southampton'}) - -data_test['Name'] = data_test['Name'].map(lambda x:replace_name(x)) -data_test = pd.concat([data_test, pd.get_dummies(data_test.Name)], axis=1) -data_test = data_test.rename(columns={'Miss': 'Name_Miss','Mr': 'Name_Mr', - 'Mrs': 'Name_Mrs','Other': 'Name_Other'}) - -# 测试集标准化函数 -def fun_test_scale(feature_scale, df_feature): - np_feature = df_feature.values.reshape(-1,1).astype(np.float64) - feature_scaled = StandardScaler().fit_transform(np_feature, feature_scale) - return feature_scaled - -data_test['Pclass_scaled'] = fun_test_scale(Pclass_scale, data_test['Pclass']) -data_test.loc[data_test.Fare.isnull(),'Fare'] = 0 # 缺失值置为0 -data_test['Fare_scaled'] = fun_test_scale(Fare_scale, data_test['Fare']) -data_test['SibSp_scaled'] = fun_test_scale(SibSp_scale, data_test['SibSp']) -data_test['Parch_scaled'] = fun_test_scale(Parch_scale, data_test['Parch']) - -# 处理测试集Age缺失值并归一化 -train_for_missingkey_test = data_test[['Age','Sex','Name_Miss','Name_Mr','Name_Mrs','Name_Other', - 'Fare_scaled','SibSp_scaled','Parch_scaled']] -data_test = set_missing_feature(train_for_missingkey_test, data_test, 'Test_Age') -data_test['Age_scaled'] = fun_test_scale(Age_scale, data_test['Age']) - -data_test = set_Cabin_type(data_test) - -test_X = data_test[['Sex','Cabin','Cherbourg','Queenstown','Southampton','Name_Miss','Name_Mr','Name_Mrs','Name_Other', - 'Pclass_scaled','Fare_scaled','SibSp_scaled','Parch_scaled','Age_scaled']].as_matrix() - -# 8. 模型预测 -model = classifierlist[4] # 选择分类器 -print("Test in %s!" % model[0]) -predictions = model[1].predict(test_X).astype(np.int32) -result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions}) -result.to_csv('Result_with_%s.csv' % model[0], index=False) -print('...\nAll Finish!') - - -# 9. XGBoost -import xgboost as xgb - -from sklearn.model_selection import train_test_split -x_train, x_valid, y_train, y_valid = train_test_split(train_X, train_y, test_size=0.1, random_state=0) -print(x_train.shape, x_valid.shape) - -xgbClassifier = xgb.XGBClassifier(learning_rate = 0.1, - n_estimators= 234, - max_depth= 6, - min_child_weight= 5, - gamma=0, - subsample=0.8, - colsample_bytree=0.8, - objective= 'binary:logistic', - scale_pos_weight=1) - -xgbClassifier.fit(train_X, train_y) -xgbpred_test = xgbClassifier.predict(test_X).astype(np.int32) -result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':xgbpred_test}) -result.to_csv('Result_with_%s.csv' % 'XGBoost', index=False) +# -*- coding: utf-8 -*- +""" +Created on 2017-12-07 +Update on 2017-12-24 +Team: 一把梭 +Github: https://github.com/apachecn/kaggle +""" + +import numpy as np +import pandas as pd +from sklearn.preprocessing import StandardScaler +from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier +from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier +from sklearn.ensemble import VotingClassifier +from sklearn.linear_model import LogisticRegression +from sklearn.svm import SVC +from sklearn.model_selection import cross_val_score + +# 0. 数据读入及预处理 +root_path = 'datasets/getting-started/titanic/input' +data_train = pd.read_csv('%s/%s' % (root_path, 'train.csv')) +# data_train.info() +# print(data_train.describe()) + +# 1. 去除唯一属性特 +data_train.drop(['PassengerId', 'Ticket'], axis=1, inplace=True) + +# 2. 类别特征One-Hot编码 +data_train['Sex'] = data_train['Sex'].map({'female': 0, 'male': 1}).astype(np.int64) +data_train.loc[data_train.Embarked.isnull(), 'Embarked'] = 'S' # 2个Embarked缺失值直接填充为S +data_train = pd.concat([data_train, pd.get_dummies(data_train.Embarked)], axis=1) +data_train = data_train.rename(columns={'C': 'Cherbourg','Q': 'Queenstown','S': 'Southampton'}) + +# 将名字转换 +def replace_name(x): + if 'Mrs' in x: return 'Mrs' + elif 'Mr' in x: return 'Mr' + elif 'Miss' in x: return 'Miss' + else: return 'Other' + +data_train['Name'] = data_train['Name'].map(lambda x:replace_name(x)) +data_train = pd.concat([data_train, pd.get_dummies(data_train.Name)], axis=1) +data_train = data_train.rename(columns={'Miss': 'Name_Miss','Mr': 'Name_Mr', + 'Mrs': 'Name_Mrs','Other': 'Name_Other'}) + +# 3. 数值特征标准化 +def fun_scale(df_feature): + np_feature = df_feature.values.reshape(-1,1).astype(np.float64) + feature_scale = StandardScaler().fit(np_feature) + feature_scaled = StandardScaler().fit_transform(np_feature, feature_scale) + return feature_scale, feature_scaled + +Pclass_scale, data_train['Pclass_scaled'] = fun_scale(data_train['Pclass']) +Fare_scale, data_train['Fare_scaled'] = fun_scale(data_train['Fare']) +SibSp_scale, data_train['SibSp_scaled'] = fun_scale(data_train['SibSp']) +Parch_scale, data_train['Parch_scaled'] = fun_scale(data_train['Parch']) + +# 4. 缺失值补全及相应处理 +# 处理Age缺失值并标准化 +# 缺失值处理函数 +def set_missing_feature(train_for_missingkey, data, info): + known_feature = train_for_missingkey[train_for_missingkey.Age.notnull()].as_matrix() + unknown_feature = train_for_missingkey[train_for_missingkey.Age.isnull()].as_matrix() + y = known_feature[:, 0] # 第1列作为待补全属性 + x = known_feature[:, 1:] # 第2列及之后的属性作为预测属性 + rf = RandomForestRegressor(random_state=0, n_estimators=100) + rf.fit(x, y) + print(info, "缺失值预测得分", rf.score(x, y)) + predictage = rf.predict(unknown_feature[:, 1:]) + data.loc[data.Age.isnull(), 'Age'] = predictage + return data + +train_for_missingkey_train = data_train[['Age','Survived','Sex','Name_Miss','Name_Mr','Name_Mrs', + 'Name_Other','Fare_scaled','SibSp_scaled','Parch_scaled']] +data_train = set_missing_feature(train_for_missingkey_train, data_train,'Train_Age') +Age_scale, data_train['Age_scaled'] = fun_scale(data_train['Age']) + +# 处理Cabin特征 +def set_Cabin_type(df): + df.loc[ (df.Cabin.notnull()), 'Cabin' ] = 1. + df.loc[ (df.Cabin.isnull()), 'Cabin' ] = 0. + return df + +data_train = set_Cabin_type(data_train) + +# 5. 整合数据 +train_X = data_train[['Sex','Cabin','Cherbourg','Queenstown','Southampton','Name_Miss','Name_Mr','Name_Mrs','Name_Other', + 'Pclass_scaled','Fare_scaled','SibSp_scaled','Parch_scaled','Age_scaled']].as_matrix() +train_y = data_train['Survived'].as_matrix() + +# 6. 模型搭建及交叉验证 +lr = LogisticRegression(C=1.0, tol=1e-6) +svc = SVC(C=1.1, kernel='rbf', decision_function_shape='ovo') +adaboost = AdaBoostClassifier(n_estimators=490, random_state=0) +randomf = RandomForestClassifier(n_estimators=185, max_depth=5, random_state=0) +gbdt = GradientBoostingClassifier(n_estimators=436, max_depth=2, random_state=0) +VotingC = VotingClassifier(estimators=[('LR',lr),('SVC',svc),('AdaBoost',adaboost), + ('RandomF',randomf),('GBDT',gbdt)]) + +''' +# 交叉验证部分 ##### +param_test = { + 'n_estimators': np.arange(200, 240, 1), + 'max_depth': np.arange(4, 7, 1), + #'min_child_weight': np.arange(1, 6, 2), + #'C': (1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9) + } + +from sklearn.grid_search import GridSearchCV + +grid_search = GridSearchCV(estimator=xgbClassifier, param_grid=param_test, scoring='roc_auc', cv=5) +grid_search.fit(train_X,train_y) +grid_search.grid_scores_, grid_search.best_params_, grid_search.best_score_ +# 交叉验证部分 ##### +''' + +# 模型训练及交叉验证 +classifierlist = [('LR',lr),('SVC',svc),('AdaBoost',adaboost),('RandomF',randomf), + ('GBDT',gbdt),('VotingC',VotingC)] +for name, classifier in classifierlist: + # 分类器训练与下一步交叉验证无关,训练是为下面测试集预测使用 + classifier.fit(train_X, train_y) + print(name, "Mean_Cross_Val_Score is:", + cross_val_score(classifier, train_X, train_y, cv=5, scoring='accuracy').mean(), "\n") + +# 7. 测试集处理 +data_test = pd.read_csv('test.csv') +data_test.drop(['Ticket'], axis=1, inplace=True) + +data_test['Sex'] = data_test['Sex'].map({'female': 0, 'male': 1}).astype(np.int64) +data_test = pd.concat([data_test, pd.get_dummies(data_test.Embarked)], axis=1) +data_test = data_test.rename(columns={'C': 'Cherbourg','Q': 'Queenstown','S': 'Southampton'}) + +data_test['Name'] = data_test['Name'].map(lambda x:replace_name(x)) +data_test = pd.concat([data_test, pd.get_dummies(data_test.Name)], axis=1) +data_test = data_test.rename(columns={'Miss': 'Name_Miss','Mr': 'Name_Mr', + 'Mrs': 'Name_Mrs','Other': 'Name_Other'}) + +# 测试集标准化函数 +def fun_test_scale(feature_scale, df_feature): + np_feature = df_feature.values.reshape(-1,1).astype(np.float64) + feature_scaled = StandardScaler().fit_transform(np_feature, feature_scale) + return feature_scaled + +data_test['Pclass_scaled'] = fun_test_scale(Pclass_scale, data_test['Pclass']) +data_test.loc[data_test.Fare.isnull(),'Fare'] = 0 # 缺失值置为0 +data_test['Fare_scaled'] = fun_test_scale(Fare_scale, data_test['Fare']) +data_test['SibSp_scaled'] = fun_test_scale(SibSp_scale, data_test['SibSp']) +data_test['Parch_scaled'] = fun_test_scale(Parch_scale, data_test['Parch']) + +# 处理测试集Age缺失值并归一化 +train_for_missingkey_test = data_test[['Age','Sex','Name_Miss','Name_Mr','Name_Mrs','Name_Other', + 'Fare_scaled','SibSp_scaled','Parch_scaled']] +data_test = set_missing_feature(train_for_missingkey_test, data_test, 'Test_Age') +data_test['Age_scaled'] = fun_test_scale(Age_scale, data_test['Age']) + +data_test = set_Cabin_type(data_test) + +test_X = data_test[['Sex','Cabin','Cherbourg','Queenstown','Southampton','Name_Miss','Name_Mr','Name_Mrs','Name_Other', + 'Pclass_scaled','Fare_scaled','SibSp_scaled','Parch_scaled','Age_scaled']].as_matrix() + +# 8. 模型预测 +model = classifierlist[4] # 选择分类器 +print("Test in %s!" % model[0]) +predictions = model[1].predict(test_X).astype(np.int32) +result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions}) +result.to_csv('Result_with_%s.csv' % model[0], index=False) +print('...\nAll Finish!') + + +# 9. XGBoost +import xgboost as xgb + +from sklearn.model_selection import train_test_split +x_train, x_valid, y_train, y_valid = train_test_split(train_X, train_y, test_size=0.1, random_state=0) +print(x_train.shape, x_valid.shape) + +xgbClassifier = xgb.XGBClassifier(learning_rate = 0.1, + n_estimators= 234, + max_depth= 6, + min_child_weight= 5, + gamma=0, + subsample=0.8, + colsample_bytree=0.8, + objective= 'binary:logistic', + scale_pos_weight=1) + +xgbClassifier.fit(train_X, train_y) +xgbpred_test = xgbClassifier.predict(test_X).astype(np.int32) +result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':xgbpred_test}) +result.to_csv('Result_with_%s.csv' % 'XGBoost', index=False) diff --git a/src/py3.x/kaggle/getting-started/word2vec-nlp-tutorial/delete-tmp.py b/src/python/getting-started/word2vec-nlp-tutorial/delete-tmp.py similarity index 100% rename from src/py3.x/kaggle/getting-started/word2vec-nlp-tutorial/delete-tmp.py rename to src/python/getting-started/word2vec-nlp-tutorial/delete-tmp.py diff --git a/src/py3.x/kaggle/getting-started/word2vec-nlp-tutorial/test.py b/src/python/getting-started/word2vec-nlp-tutorial/test.py similarity index 100% rename from src/py3.x/kaggle/getting-started/word2vec-nlp-tutorial/test.py rename to src/python/getting-started/word2vec-nlp-tutorial/test.py diff --git a/src/py3.x/kaggle/playground/dogs-vs-cats/Pytorch-CNN.py b/src/python/playground/dogs-vs-cats/Pytorch-CNN.py similarity index 100% rename from src/py3.x/kaggle/playground/dogs-vs-cats/Pytorch-CNN.py rename to src/python/playground/dogs-vs-cats/Pytorch-CNN.py diff --git "a/src/py3.x/kaggle/playground/dogs-vs-cats/main\347\232\204\345\211\257\346\234\254.py" "b/src/python/playground/dogs-vs-cats/main\347\232\204\345\211\257\346\234\254.py" similarity index 100% rename from "src/py3.x/kaggle/playground/dogs-vs-cats/main\347\232\204\345\211\257\346\234\254.py" rename to "src/python/playground/dogs-vs-cats/main\347\232\204\345\211\257\346\234\254.py" diff --git a/src/py3.x/kaggle/playground/dogs-vs-cats/models/AlexNet.py b/src/python/playground/dogs-vs-cats/models/AlexNet.py similarity index 100% rename from src/py3.x/kaggle/playground/dogs-vs-cats/models/AlexNet.py rename to src/python/playground/dogs-vs-cats/models/AlexNet.py diff --git a/src/py3.x/kaggle/playground/dogs-vs-cats/models/BasicModule.py b/src/python/playground/dogs-vs-cats/models/BasicModule.py similarity index 100% rename from src/py3.x/kaggle/playground/dogs-vs-cats/models/BasicModule.py rename to src/python/playground/dogs-vs-cats/models/BasicModule.py diff --git a/src/py3.x/kaggle/playground/dogs-vs-cats/models/ResNet34.py b/src/python/playground/dogs-vs-cats/models/ResNet34.py similarity index 100% rename from src/py3.x/kaggle/playground/dogs-vs-cats/models/ResNet34.py rename to src/python/playground/dogs-vs-cats/models/ResNet34.py diff --git a/src/py3.x/kaggle/playground/dogs-vs-cats/models/__init__.py b/src/python/playground/dogs-vs-cats/models/__init__.py similarity index 100% rename from src/py3.x/kaggle/playground/dogs-vs-cats/models/__init__.py rename to src/python/playground/dogs-vs-cats/models/__init__.py diff --git "a/src/py3.x/kaggle/playground/dogs-vs-cats/\344\275\277\347\224\250\350\277\201\347\247\273\345\255\246\344\271\240\350\277\233\350\241\214\347\214\253\347\213\227\350\257\206\345\210\25398%.ipynb" "b/src/python/playground/dogs-vs-cats/\344\275\277\347\224\250\350\277\201\347\247\273\345\255\246\344\271\240\350\277\233\350\241\214\347\214\253\347\213\227\350\257\206\345\210\25398%.ipynb" similarity index 100% rename from "src/py3.x/kaggle/playground/dogs-vs-cats/\344\275\277\347\224\250\350\277\201\347\247\273\345\255\246\344\271\240\350\277\233\350\241\214\347\214\253\347\213\227\350\257\206\345\210\25398%.ipynb" rename to "src/python/playground/dogs-vs-cats/\344\275\277\347\224\250\350\277\201\347\247\273\345\255\246\344\271\240\350\277\233\350\241\214\347\214\253\347\213\227\350\257\206\345\210\25398%.ipynb" diff --git "a/src/\345\205\266\344\273\226/qqchangE_problem.md" b/src/qqchangE_problem.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/qqchangE_problem.md" rename to src/qqchangE_problem.md diff --git a/src/script.py b/src/script.py deleted file mode 100644 index 73dbbec5..00000000 --- a/src/script.py +++ /dev/null @@ -1,146 +0,0 @@ -# coding: utf-8 -import os -import sys - - -def format_file(filename, str1, str2): - """ - 文件内容的替换功能 - :return: - """ - with open(filename, 'r') as f: - var_object = f.read() - if "gitalk" not in var_object: - var_object = var_object.replace(str1, str2) - # print(var_object) - - f = open(filename, "w") - f.write(var_object) - - -if __name__ == "__main__": - if len(sys.argv) == 3: - version, u_type = sys.argv[1], sys.argv[2] - else: - print("Usage: 参数个数为%s - 错误,应该改为3" % len(sys.argv)) - sys.exit(-1) - - tag = True - if u_type == "index": - tag = False - # if version == "home": - # filename = "_book/index.html" - # else: - # filename = "_book/docs/%s/index.html" % version - # str1 = """ - # - # - # """ - - # str2 = """ - # - # - # - # """ - elif u_type == "book": - if version == "home": - filename = "book.json" - tag = False - else: - filename = "docs/%s/book.json" % version - str1 = "https://github.com/apachecn/Interview/blob/master" - str2 = "https://github.com/apachecn/Interview/blob/master/docs/%s" % version - - elif u_type == "powered": - if version == "home": - filename = "node_modules/gitbook-plugin-tbfed-pagefooter/index.js" - else: - filename = "docs/%s/node_modules/gitbook-plugin-tbfed-pagefooter/index.js" % version - str1 = "powered by Gitbook" - str2 = "由 ApacheCN 团队提供支持" - - elif u_type == "gitalk": - if version == "home": - filename = "node_modules/gitbook-plugin-tbfed-pagefooter/index.js" - else: - filename = "docs/%s/node_modules/gitbook-plugin-tbfed-pagefooter/index.js" % version - str1 = """ var str = ' \\n\\n
' + _copy + - '' + - _label + - '\\n{{file.mtime | date("' + _format + - '")}}\\n
'""" - - str2 = """ - var str = '\\n\\n'+ - '\\n
'+ - '\\n
'+ - '\\n

我们一直在努力

'+ - '\\n

apachecn/Interview

'+ - '\\n

'+ - '\\n '+ - '\\n '+ - '\\n ML | ApacheCN

'+ - '\\n
'+ - '\\n
'+ - '\\n '+ - '\\n '+ - '\\n '+ - '\\n '+ - '\\n'+ - '\\n '+ - '\\n'+ - '\\n '+ - '\\n '+ - '\\n
'+ - '\\n'+ - '\\n'+ - '\\n'+ - '\\n' - - str += '\\n\\n'+ - '\\n
'+ - '\\n '+ - '\\n '+ - '\\n '+ - '\\n
'+ - '\\n '+ - '\\n
' - - str += '\\n\\n' - """ - - # 状态为 True 就进行替换 - if tag: format_file(filename, str1, str2) diff --git "a/src/\345\205\266\344\273\226/shopee.md" b/src/shopee.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/shopee.md" rename to src/shopee.md diff --git "a/src/\345\205\266\344\273\226/sohuchangyouweipinhui.md" b/src/sohuchangyouweipinhui.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/sohuchangyouweipinhui.md" rename to src/sohuchangyouweipinhui.md diff --git "a/src/\345\205\266\344\273\226/tecent.md" b/src/tecent.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/tecent.md" rename to src/tecent.md diff --git a/src/test.py b/src/test.py deleted file mode 100644 index 34499b09..00000000 --- a/src/test.py +++ /dev/null @@ -1,30 +0,0 @@ - -class Solution(object): - def searchInsert(self, nums, target): - """ - :type nums: List[int] - :type target: int - :rtype: int - """ - left = 0 - right = len(nums) - 1 - while left <= right: - mid = (left + right) // 2 - print(">>> %s: %s[%s], %s[%s], %s[%s]" % (target, nums[left], left, nums[right], right, nums[mid], mid)) - if nums[mid] > target: - right = mid - 1 - elif nums[mid] < target: - left = mid + 1 - else: - break - - mid = mid+1 if left > mid else mid - print("结果: ", mid, left) - - -if __name__ == "__main__": - - nums = [1, 2, 4, 5, 6, 7, 8, 9, 11, 15] - target = -2 - s = Solution() - s.searchInsert(nums, target) diff --git "a/src/\345\205\266\344\273\226/times.md" b/src/times.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/times.md" rename to src/times.md diff --git "a/src/\345\205\266\344\273\226/vmware.md" b/src/vmware.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/vmware.md" rename to src/vmware.md diff --git "a/src/\345\205\266\344\273\226/wangyihuyudierti.java" b/src/wangyihuyudierti.java old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/wangyihuyudierti.java" rename to src/wangyihuyudierti.java diff --git "a/src/\345\205\266\344\273\226/xunlei.md" b/src/xunlei.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/xunlei.md" rename to src/xunlei.md diff --git "a/src/\345\205\266\344\273\226/zhaoyincreditcard.md" b/src/zhaoyincreditcard.md old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/zhaoyincreditcard.md" rename to src/zhaoyincreditcard.md diff --git "a/src/\345\205\266\344\273\226/zhaoyinwangluokeji.java" b/src/zhaoyinwangluokeji.java old mode 100644 new mode 100755 similarity index 100% rename from "src/\345\205\266\344\273\226/zhaoyinwangluokeji.java" rename to src/zhaoyinwangluokeji.java