diff --git a/.gitignore b/.gitignore index a387c72b8..cd1fbccc7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,115 +1,7 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg - -# 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/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# dotenv -.env - -# virtualenv -.venv -venv/ -ENV/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ .DS_Store - -# gitbook -_book - -# node.js -node_modules - -# windows Thumbs.db - -# word -~$*.docx -~$*.doc +db.json +*.log +node_modules/ +public/ +.deploy*/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..9e5a6ab0e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,28 @@ +group: travis_latest +language: python +cache: pip +python: + - 2.7 + - 3.6 + #- nightly + #- pypy + #- pypy3 +matrix: + allow_failures: + - python: 2.7 + - python: nightly + - python: pypy + - python: pypy3 +install: + #- pip install -r requirements.txt + - pip install flake8 # pytest # add another testing frameworks later +before_script: + # stop the build if there are Python syntax errors or undefined names + - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics +script: + - true # pytest --capture=sys # add other tests here +notifications: + on_success: change + on_failure: change # `always` will be the setting once code changes slow down diff --git a/404.html b/404.html deleted file mode 100644 index 5705bebe5..000000000 --- a/404.html +++ /dev/null @@ -1,4 +0,0 @@ ---- -permalink: /404.html ---- - diff --git a/CNAME b/CNAME deleted file mode 100644 index ad71e6f3f..000000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -algo.apachecn.org \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 65e2ef590..000000000 --- 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 new file mode 100644 index 000000000..9cecc1d46 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + 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/NAV.md b/NAV.md deleted file mode 100644 index a91cdb26a..000000000 --- a/NAV.md +++ /dev/null @@ -1,196 +0,0 @@ -+ 编程 - + [JavaTPoint 编程语言中文教程📚](https://apachecn.github.io/javatpoint-prog-zh) - + [JavaTPoint .NET 中文教程📚](https://apachecn.github.io/javatpoint-dotnet-zh) - + [JavaTPoint Java 中文教程📚](https://apachecn.github.io/javatpoint-java-zh) - + [JavaTPoint Python 中文教程📚](https://apachecn.github.io/javatpoint-python-zh) - + [GeeksForGeeks 编程语言杂项中文教程📚](https://apachecn.github.io/geeksforgeeks-lang-misc-zh) - + [GeeksForGeeks C# 中文教程📚](https://apachecn.github.io/geeksforgeeks-csharp-zh) - + [GeeksForGeeks Scala 中文教程📚](https://apachecn.github.io/geeksforgeeks-scala-zh) - + [GeeksForGeeks Python 中文教程📚](https://apachecn.github.io/geeksforgeeks-python-zh) - + [GeeksForGeeks C/C++ 中文教程📚](https://apachecn.github.io/geeksforgeeks-c-cpp-zh) - + [GeeksForGeeks Java 中文教程📚](https://apachecn.github.io/geeksforgeeks-java-zh) - + [GeeksForGeeks JavaScript 中文教程📚](https://apachecn.github.io/geeksforgeeks-js-zh) - + [ApacheCN C# 译文集📚](https://apachecn.github.io/apachecn-csharp-zh) - + [ApacheCN C# 译文集(二)📚](https://apachecn.github.io/apachecn-csharp-zh-pt2) - + [ApacheCN C# 译文集(三)📚](https://apachecn.github.io/apachecn-csharp-zh-pt3) - + [ApacheCN C# 译文集(四)📚](https://apachecn.github.io/apachecn-csharp-zh-pt4) - + [ApacheCN Golang 译文集📚](https://apachecn.github.io/apachecn-golang-zh) - + [ApacheCN Golang 译文集(二)📚](https://apachecn.github.io/apachecn-golang-zh-pt2) - + [ApacheCN C/C++ 译文集📚](https://apachecn.github.io/apachecn-c-cpp-zh) - + [ApacheCN C/C++ 译文集(二)📚](https://apachecn.github.io/apachecn-c-cpp-zh-pt2) - + [ApacheCN C/C++ 译文集(三)📚](https://apachecn.github.io/apachecn-c-cpp-zh-pt3) - + [ApacheCN Java 译文集📚](https://apachecn.github.io/apachecn-java-zh) - + [ApacheCN Java 译文集(二)📚](https://apachecn.github.io/apachecn-java-zh-pt2) - + [ApacheCN Java 译文集(三)📚](https://apachecn.github.io/apachecn-java-zh-pt3) - + [ApacheCN JavaScript 译文集📚](https://apachecn.github.io/apachecn-js-zh) - + [ApacheCN JavaScript 译文集(二)📚](https://apachecn.github.io/apachecn-js-zh-pt2) - + [ApacheCN JavaScript 译文集(三)📚](https://apachecn.github.io/apachecn-js-zh-pt3) - + [ApacheCN JavaScript 译文集(四)📚](https://apachecn.github.io/apachecn-js-zh-pt4) - + [ApacheCN Python 译文集📚](https://apachecn.github.io/apachecn-python-zh) - + [ApacheCN Python 译文集(二)📚](https://apachecn.github.io/apachecn-python-zh-pt2) - + [ApacheCN Python 译文集(三)📚](https://apachecn.github.io/apachecn-python-zh-pt3) - + [ApacheCN Python 译文集(四)📚](https://apachecn.github.io/apachecn-python-zh-pt4) - + [ApacheCN Ruby 译文集📚](https://apachecn.github.io/apachecn-ruby-zh) - + [BeginnersBook 中文系列教程📚](https://apachecn.github.io/beginnersbook-zh) - + [JavaScript 编程精解 中文第三版](https://apachecn.github.io/eloquent-js-3e-zh) - + [Guru99 中文系列教程📚🚧](https://apachecn.github.io/guru99-zh) - + [HowToDoInJava 中文系列教程📚](https://apachecn.github.io/howtodoinjava-zh) - + [OverIQ 中文系列教程📚](https://apachecn.github.io/overiq-zh) - + [LearnETutroials 中文系列教程📚](https://apachecn.github.io/learnetutorials-zh) - + [StudyTonight 中文系列教程📚](https://apachecn.github.io/studytonight-zh) - + [TutorialGateway 中文系列教程📚](https://apachecn.github.io/tutorialgateway-zh) - + [TutorialGateway BI 中文系列教程📚](https://apachecn.github.io/tutorialgateway-bi-zh) - + [TutorialsTeacher 中文系列教程📚](https://apachecn.github.io/tutorialsteacher-zh) - + [通过示例学 Golang 2020 中文版](https://apachecn.github.io/golang-by-example-2020-zh) - + [写给不耐烦程序员的 JavaScript🚧](https://apachecn.github.io/impatient-js-zh) - + [JavaBeginnersTutorial 中文系列教程📚](https://apachecn.github.io/jbt-zh) - + [JavaTutorialNetwork 中文系列教程📚](https://apachecn.github.io/jtn-zh) - + [笨办法学C 中文版](https://apachecn.github.io/lcthw-zh) - + [笨办法学 Python · 续 中文版](https://apachecn.github.io/lmpythw-zh) - + [Programiz 中文系列教程📚](https://apachecn.github.io/programiz-zh) - + [PythonBasics 中文系列教程📚](https://apachecn.github.io/pythonbasics-zh) - + [PythonGuru 中文系列教程📚](https://apachecn.github.io/pythonguru-zh) - + [PythonSpot 中文系列教程📚](https://apachecn.github.io/pythonspot-zh) - + [Think Python](https://apachecn.github.io/think-py-2e-zh) - + [ZetCode 中文系列教程📚](https://apachecn.github.io/zetcode-zh) -+ 前端 - + [JavaTPoint 移动开发中文教程📚](https://apachecn.github.io/javatpoint-mobi-zh) - + [GeeksForGeeks Web 杂项中文教程📚](https://apachecn.github.io/geeksforgeeks-web-misc-zh) - + [GeeksForGeeks Angular/Vue/React 中文教程📚](https://apachecn.github.io/geeksforgeeks-ng-vue-react-zh) - + [GeeksForGeeks jQuery 中文教程📚](https://apachecn.github.io/geeksforgeeks-jquery-zh) - + [GeeksForGeeks CSS 中文教程📚](https://apachecn.github.io/geeksforgeeks-css-zh) - + [GeeksForGeeks HTML 中文教程📚](https://apachecn.github.io/geeksforgeeks-html-zh) - + [ApacheCN Vue 译文集📚](https://apachecn.github.io/apachecn-vue-zh) - + [ApacheCN Angular 译文集📚](https://apachecn.github.io/apachecn-angular-zh) - + [ApacheCN React 译文集📚](https://apachecn.github.io/apachecn-react-zh) - + [ApacheCN jQuery 译文集📚](https://apachecn.github.io/apachecn-jquery-zh) - + [ApacheCN jQuery 译文集(二)📚](https://apachecn.github.io/apachecn-jquery-zh-pt2) -+ 后端/大数据 - + [JavaTPoint 大数据中文教程📚](https://apachecn.github.io/javatpoint-bigdata-zh) - + [JavaTPoint Web 开发中文教程📚](https://apachecn.github.io/javatpoint-web-zh) - + [JavaTPoint 数据库中文教程📚](https://apachecn.github.io/javatpoint-db-zh) - + [JavaTPoint PHP 中文教程📚](https://apachecn.github.io/javatpoint-php-zh) - + [GeeksForGeeks ASP 中文教程📚](https://apachecn.github.io/geeksforgeeks-asp-zh) - + [GeeksForGeeks SQL 中文教程📚](https://apachecn.github.io/geeksforgeeks-sql-zh) - + [GeeksForGeeks NodeJS 中文教程📚](https://apachecn.github.io/geeksforgeeks-nodejs-zh) - + [GeeksForGeeks PHP 中文教程📚](https://apachecn.github.io/geeksforgeeks-php-zh) - + [ApacheCN 数据库译文集📚](https://apachecn.github.io/apachecn-db-zh) - + [ApacheCN 数据库译文集(二)📚](https://apachecn.github.io/apachecn-db-zh-pt2) - + [ApacheCN Python Web 译文集📚](https://apachecn.github.io/apachecn-pythonweb-zh) - + [ApacheCN Python Web 译文集(二)📚](https://apachecn.github.io/apachecn-pythonweb-zh-pt2) - + [ApacheCN Asp.NET 译文集📚](https://apachecn.github.io/apachecn-asp-dotnet-zh) - + [ApacheCN Asp.NET 译文集(二)📚](https://apachecn.github.io/apachecn-asp-dotnet-zh-pt2) - + [ApacheCN Asp.NET 译文集(三)📚](https://apachecn.github.io/apachecn-asp-dotnet-zh-pt3) - + [ApacheCN Asp.NET 译文集(四)📚](https://apachecn.github.io/apachecn-asp-dotnet-zh-pt4) - + [ApacheCN NodeJS 译文集📚](https://apachecn.github.io/apachecn-node-zh) - + [ApacheCN NodeJS 译文集(二)📚](https://apachecn.github.io/apachecn-node-zh-pt2) - + [ApacheCN PHP 译文集📚](https://apachecn.github.io/apachecn-php-zh) - + [ApacheCN PHP 译文集(二)📚](https://apachecn.github.io/apachecn-php-zh-pt2) - + [ApacheCN 大数据译文集(二)📚](https://apachecn.github.io/apachecn-bigdata-zh-pt2) - + [ApacheCN 大数据译文集(三)📚](https://apachecn.github.io/apachecn-bigdata-zh-pt3) - + [ApacheCN 大数据译文集📚](https://apachecn.github.io/apachecn-bigdata-zh) - + [ApacheCN Java Web 译文集📚](https://apachecn.github.io/apachecn-javaweb-zh) - + [ApacheCN Java Web 译文集(二)📚](https://apachecn.github.io/apachecn-javaweb-zh-pt2) - + [Airflow 中文文档](https://apachecn.github.io/airflow-doc-zh) - + [Elasticsearch 5.4 中文文档](https://apachecn.github.io/elasticsearch-doc-zh) - + [Flink 中文文档](https://apachecn.github.io/flink-doc-zh) - + [HBase™ 中文参考指南 3.0🚧](https://apachecn.github.io/hbase-doc-zh) - + [HighScalability 中文示例📚🚧](https://apachecn.github.io/highscalability-examples-zh) - + [Kibana 5.2 中文文档](https://apachecn.github.io/kibana-doc-zh) - + [Kudu 1.4.0 中文文档](https://apachecn.github.io/kudu-doc-zh) - + [Apache Spark 官方文档中文版](https://apachecn.github.io/spark-doc-zh) - + [Apache Kafka 官方文档中文版](https://apachecn.github.io/kafka-site-zh) - + [Spring Boot 1.5.2 中文文档](https://apachecn.github.io/spring-boot-doc-zh) - + [Storm 1.1.0 中文文档](https://apachecn.github.io/storm-doc-zh) - + [Zeppelin 0.7.2 中文文档](https://apachecn.github.io/zeppelin-doc-zh) -+ 工具 - + [JavaTPoint 实用工具中文教程📚](https://apachecn.github.io/javatpoint-util-zh) - + [ApacheCN DevOps 译文集📚](https://apachecn.github.io/apachecn-devops-zh) - + [ApacheCN DevOps 译文集(二)📚](https://apachecn.github.io/apachecn-devops-zh-pt2) - + [ApacheCN DevOps 译文集(三)📚](https://apachecn.github.io/apachecn-devops-zh-pt3) - + [ApacheCN DevOps 译文集(四)📚](https://apachecn.github.io/apachecn-devops-zh-pt4) - + [ApacheCN DevOps 译文集(五)📚](https://apachecn.github.io/apachecn-devops-zh-pt5) - + [ApacheCN Linux 译文集📚](https://apachecn.github.io/apachecn-linux-zh) - + [ApacheCN Linux 译文集(二)📚](https://apachecn.github.io/apachecn-linux-zh-pt2) - + [ApacheCN Linux 译文集(三)📚](https://apachecn.github.io/apachecn-linux-zh-pt3) - + [Cython 3.0 中文文档🚧](https://apachecn.github.io/cython-doc-zh) - + [Git 中文参考🚧](https://apachecn.github.io/git-doc-zh) - + [Gitlab 中文文档🚧](https://apachecn.github.io/gitlab-doc-zh) - + [笨办法学 Linux 中文版](https://apachecn.github.io/llthw-zh) - + [Numba 0.44 中文文档🚧](https://apachecn.github.io/numba-doc-zh) - + [PyQt4 中文文档🚧](https://apachecn.github.io/pyqt4-doc-zh) - + [Scrapy 1.6 中文文档](https://apachecn.github.io/scrapy-doc-zh) -+ 数据科学 - + [ApacheCN 数据科学译文集📚](https://apachecn.github.io/apachecn-ds-zh) - + [ApacheCN 数据科学译文集(二)📚](https://apachecn.github.io/apachecn-ds-zh-pt2) - + [ApacheCN 数据科学译文集(三)📚](https://apachecn.github.io/apachecn-ds-zh-pt3) - + [ApacheCN 数据科学译文集📚](https://apachecn.github.io/apachecn-ds-zh) - + [MIT 18.03 面向初学者的微积分🚧](https://apachecn.github.io/calc4b-zh) - + [UCB Data8 计算与推断思维](https://apachecn.github.io/data8-textbook-zh) - + [数据可视化的基础知识](https://apachecn.github.io/dataviz-zh) - + [数据科学和人工智能技术笔记](https://apachecn.github.io/ds-ai-tech-notes) - + [数据科学 IPython 笔记本📚](https://apachecn.github.io/ds-ipynb-zh) - + [UCB DS100 数据科学的原理与技巧🚧](https://apachecn.github.io/ds100-textbook-zh) - + [ApacheCN 数据科学和人工智能知识库](https://apachecn.github.io/dsai-wiki) - + [Matplotlib 用户指南](https://apachecn.github.io/matplotlib-doc-zh) - + [MIT 18.06 线性代数笔记](https://apachecn.github.io/mit-18.06-linalg-notes) - + [利用 Python 进行数据分析 · 第 2 版](https://apachecn.github.io/pyda-2e-zh) - + [QuantLearning](https://apachecn.github.io/quant-learning) - + [seaborn 0.9 中文文档](https://apachecn.github.io/seaborn-doc-zh) - + [社交媒体挖掘 - 翻译版](https://apachecn.github.io/socialmediamining-zh) - + [斯坦福 Stats60 21 世纪的统计思维🚧](https://apachecn.github.io/stats-thinking-21-zh) - + [复杂性思维 中文第二版](https://apachecn.github.io/think-comp-2e-zh) - + [PyMiner 开发者指南](https://apachecn.github.io/pyminer-dev-guide) -+ 人工智能 - + [JavaTPoint 数据科学与人工智能中文教程📚](https://apachecn.github.io/javatpoint-dsai-zh) - + [GeeksForGeeks 人工智能中文教程📚](https://apachecn.github.io/geeksforgeeks-ai-zh) - + [AILearning📚](https://apachecn.github.io/ailearning) - + [ApacheCN 计算机视觉译文集📚](https://apachecn.github.io/apachecn-cv-zh) - + [ApacheCN 计算机视觉译文集(二)📚](https://apachecn.github.io/apachecn-cv-zh-pt2) - + [ApacheCN 深度学习译文集📚](https://apachecn.github.io/apachecn-dl-zh) - + [ApacheCN 深度学习译文集(二)📚](https://apachecn.github.io/apachecn-dl-zh-pt2) - + [ApacheCN 深度学习译文集(三)📚](https://apachecn.github.io/apachecn-dl-zh-pt3) - + [ApacheCN 机器学习译文集📚](https://apachecn.github.io/apachecn-ml-zh) - + [ApacheCN 机器学习译文集(二)📚](https://apachecn.github.io/apachecn-ml-zh-pt2) - + [ApacheCN 机器学习译文集(三)📚](https://apachecn.github.io/apachecn-ml-zh-pt3) - + [FastText 中文文档](https://apachecn.github.io/fasttext-doc-zh) - + [面向机器学习的特征工程](https://apachecn.github.io/fe4ml-zh) - + [Gensim 中文文档](https://apachecn.github.io/gensim-doc-zh) - + [Sklearn 与 TensorFlow 机器学习实用指南第二版](https://apachecn.github.io/hands-on-ml-2e-zh) - + [LightGBM 中文文档](https://apachecn.github.io/lightgbm-doc-zh) - + [Machine Learning Mastery 博客文章翻译📚🚧](https://apachecn.github.io/ml-mastery-zh) - + [Machine Learning Mastery 博客文章翻译(二)📚🚧](https://apachecn.github.io/ml-mastery-zh-pt2) - + [Python 自然语言处理 第二版](https://apachecn.github.io/nlp-py-2e-zh) - + [PyTorch 自然语言处理](https://apachecn.github.io/nlp-pytorch-zh) - + [台湾大学林轩田机器学习笔记](https://apachecn.github.io/ntu-hsuantienlin-ml) - + [OpenCV 中文文档 4.0.0](https://apachecn.github.io/opencv-doc-zh) - + [PythonProgramming.net 系列教程📚](https://apachecn.github.io/python-programming-net-zh) - + [PyTorch 中文教程](https://apachecn.github.io/pytorch-doc-zh) - + [scikit-learn (sklearn) 官方文档中文版](https://apachecn.github.io/sklearn-doc-zh) - + [XGBoost 中文文档](https://apachecn.github.io/xgboost-doc-zh) -+ 计算机科学 - + [JavaTPoint 计算机科学中文教程📚](https://apachecn.github.io/javatpoint-cs-zh) - + [ApacheCN 数据结构与算法译文集📚](https://apachecn.github.io/apachecn-algo-zh) - + [ApacheCN 计算机系统译文集📚](https://apachecn.github.io/apachecn-sys-zh) - + [NUS CS1101s SICP JavaScript 描述🚧](https://apachecn.github.io/sicp-js-zh) - + [UCB CS61a SICP Python 描述](https://apachecn.github.io/sicp-py-zh) - + [数据结构思维中文版](https://apachecn.github.io/think-dast-zh) - + [UIUC CS241 系统编程中文讲义🚧](https://apachecn.github.io/uiuc-cs241-notes-zh) -+ 安全 - + [ApacheCN Kali Linux 译文集📚](https://apachecn.github.io/apachecn-kali-zh) - + [ApacheCN 网络安全译文集📚](https://apachecn.github.io/apachecn-sec-zh) - + [ApacheCN 网络安全译文集(二)📚](https://apachecn.github.io/apachecn-sec-zh-pt2) - + [SecLearning——零组文库备份📚](https://apachecn.github.io/sec-learning) - + [ApacheCN 安全知识库📚](https://apachecn.github.io/sec-wiki) - + [Web Hacking 101 中文版](https://apachecn.github.io/web-hacking-101-zh) -+ 其它 - + [生化环材劝退文集](https://apachecn.github.io/bio-chem-env-mat-discourage) - + [5 分钟商学院精细笔记](https://apachecn.github.io/business-5min-notes) - + [iBooker 布客](https://apachecn.github.io/home) - + [iBooker 布客老实人报](https://apachecn.github.io/ibooker-plain-dealer) - + [使用 Qiskit 学习量子计算 - 翻译版](https://apachecn.github.io/lqcuq-zh) - + [原则 · 中文版](https://apachecn.github.io/principles-zh) - + [斯坦福 CS183 & YC 创业课系列中文笔记📚](https://apachecn.github.io/stanford-cs183-notes) - + [iBooker 团队知识库📚](https://apachecn.github.io/team-wiki) - + [ApacheCN 技术评论](https://apachecn.github.io/tech-review) - + [通往财富自由之路精细笔记](https://apachecn.github.io/the-way-to-wealth-freedom-notes) diff --git a/README.md b/README.md index 3bb1958c7..3cb04b2c1 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,100 @@ -# ApacheCN 数据结构与算法译文集 - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) -> -> 程序员的双手是魔术师的双手,他们把枯燥无味的代码变成了丰富多彩的软件。——《疯狂的程序员》 - -* [在线阅读](https://algo.apachecn.org) -* [在线阅读(Gitee)](https://apachecn.gitee.io/apachecn-algo-zh/) -* [ApacheCN 学习资源](http://docs.apachecn.org/) - -## 目录 - -+ [数据结构思维中文版](docs/think-dast-zh/SUMMARY.md) -+ [Leetcode C++ 题解](docs/leetcode/cpp/SUMMARY.md) -+ [Leetcode Java 题解](docs/leetcode/java/SUMMARY.md) -+ [Leetcode JavaScript 题解](docs/leetcode/javascript/SUMMARY.md) -+ [Leetcode Python 题解](docs/leetcode/python/SUMMARY.md) -+ [剑指 Offer Java 题解](docs/jianzhioffer/java/SUMMARY.md) - -## 贡献指南 - -为了不断改进翻译质量,我们特此启动了【翻译、校对、笔记整理活动】,开设了多个校对项目。贡献者校对一章之后可以领取千字2\~4元的奖励。进行中的校对活动请见[活动列表](https://home.apachecn.org/#/docs/activity/docs-activity)。更多详情请联系飞龙(Q562826179,V:wizardforcel)。 - -## 联系方式 - -### 负责人 - -* [飞龙](https://github.com/wizardforcel): 562826179 - -### 其他 - -* 在我们的 [apachecn/apachecn-algo-zh](https://github.com/apachecn/apachecn-algo-zh) github 上提 issue. -* 发邮件到 Email: `apachecn@163.com`. -* 在我们的 [组织学习交流群](http://www.apachecn.org/organization/348.html) 中联系群主/管理员即可. - -## 下载 - -### Docker - -``` -docker pull apachecn0/apachecn-algo-zh -docker run -tid -p :80 apachecn0/apachecn-algo-zh -# 访问 http://localhost:{port} 查看文档 -``` - -### PYPI - -``` -pip install apachecn-algo-zh -apachecn-algo-zh -# 访问 http://localhost:{port} 查看文档 -``` - -### NPM - -``` -npm install -g apachecn-algo-zh -apachecn-algo-zh -# 访问 http://localhost:{port} 查看文档 -``` - -## 赞助我们 - -![](http://data.apachecn.org/img/about/donate.jpg) +
+ +
+ +
+ +
+ +
+ +## Contents +1. [Leetcode Solutions](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Leetcode_Solutions) + - [Python](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Leetcode_Solutions/Python) + - [Java](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Leetcode_Solutions/Java) + - [C++](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Leetcode_Solutions/C++) + - [ipynb](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Leetcode_Solutions/ipynb) +2. [Algorithm Implementation](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Algorithm_Implementation) + - [Python](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Algorithm_Implementation/Python) + - [Java](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Algorithm_Implementation/Java) + - [C++](https://github.com/apachecn/awesome-leetcode/tree/master/docs/Algorithm_Implementation/C++) + +## Useful Links +- [kamyu104的Github](https://github.com/kamyu104/LeetCode) +- [数据结构与算法/leetcode/lintcode题解](https://algorithm.yuanbin.me/zh-hans/) +- [visualgo算法可视化网站](https://visualgo.net/en) +- [Data Structure Visualization](https://www.cs.usfca.edu/~galles/visualization/Algorithms.html) +- [HiredInTech](https://www.hiredintech.com/) System Design 的总结特别适合入门 +- [mitcc的Github](https://github.com/mitcc/AlgoSolutions) +- [小土刀的面试刷题笔记](http://wdxtub.com/interview/14520594642530.html) +- [nonstriater/Learn-Algorithms](https://github.com/nonstriater/Learn-Algorithms) +- [剑指 Offer 题解](https://github.com/gatieme/CodingInterviews) +- https://github.com/liuchuo/LeetCode +- [公瑾的Github](https://github.com/yuzhoujr/leetcode) +- [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) +- [CS-Notes](https://github.com/CyC2018/CS-Notes) +- [OI Wiki](https://oi-wiki.org) + +## Sponsor +1. [Lisanaaa](https://github.com/Lisanaaa) +2. [jiangzhonglian](https://github.com/jiangzhonglian) + +## Contributors +1. [Lisanaaa](https://github.com/Lisanaaa) +2. [jiangzhonglian](https://github.com/jiangzhonglian) +3. [chenyyx](https://github.com/chenyyx) +4. [cclauss](https://github.com/cclauss) +5. [yudaer](https://github.com/yudaer) +6. [yuzhoujr](https://github.com/yuzhoujr) +7. [wizardforcel](https://github.com/wizardforcel) +8. [Stuming](https://github.com/Stuming) +9. [GaofanHu](https://github.com/GaofanHu) +10. [er3456qi](https://github.com/er3456qi) +11. [xshahq](https://github.com/xshahq) + +you can make a pull request if you are not in the list above +## Pull Request + +If you feel your PR is satisfied with one of the conditions below, we are glad to merge it. Welcome to contributions, open to suggestions! + +- Different thinking +- Time & Space complexity optimization +- Follow up solutions +- Unsubmitted questions + +Feel free to get our [PR template](https://github.com/apachecn/awesome-leetcode/blob/master/docs/Leetcode_Solutions/Python/001._two_sum.md) + +If you are a newbie of Git, please check this [tutorial](https://github.com/apachecn/kaggle/tree/dev/docs/GitHub) we have made. + +## Support +- [GitHub issues](https://github.com/apachecn/awesome-leetcode/issues) for bug reports and new feature requests. +- Our ```[QQ Group: 812791932]``` to ask questions, discuss features, and for general discussion. + +## Acknowledgement + +> Please note, this repository is inspired from [KrisYu](https://github.com/KrisYu/LeetCode-CLRS-Python), and here is the [approve letter](https://github.com/apachecn/LeetCode/blob/master/images/Project%20cornerstone/approve%20letter.md). However, it has been modified, added and improved to reflect our knowledge, wisdom and efforts. + +## Log + +- Aug 2017, I started to brush leetcode questions using Python . +- Oct 2017, I saw Kris Yu's algorithm project on Github, but he has not updated it. I decided to build new one on my own and got his permission successfully. +- Dec 2017, this project was only considered as my record of question solutions. +- Mar 2018, the project continued to have dozens of stars. I felt that my thinking and funny words were helpful to others, determined to persist, and never stop. +- May 2018, I had to start my internship, less update, but the number of stars reached 200. +- Sep 2018, since I was also looking for a domestic job, I would send my own code link on the nowcoder.com every time I finished the online tech test. The strategy for attracting traffic was very successful, the number of stars reached 1.7k in a rush way. At this moment, I found that my thinking and description styles are very popular, but the power of one person is limited, so I would like to recruit some like-minded people to contribute to the project like myself. + +The current positioning of this project is to implement the basic algorithm in different programming languages, refining the boilerplate, and summarize the ideas. + +### ***Two words: boilerplate + ideas*** + +## License + +GPL-3.0 © [ApacheCN](https://github.com/apachecn) + +## Organization + +* [ApacheCN 组织资源](https://github.com/apachecn/home): https://github.com/apachecn/home + +> **欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远** diff --git a/SUMMARY.md b/SUMMARY.md deleted file mode 100644 index 24fbf429f..000000000 --- a/SUMMARY.md +++ /dev/null @@ -1,651 +0,0 @@ -+ [数据结构思维中文版](docs/think-dast-zh/README.md) - + [前言](docs/think-dast-zh/0.md) - + [第一章 接口](docs/think-dast-zh/1.md) - + [第二章 算法分析](docs/think-dast-zh/2.md) - + [第三章 `ArrayList`](docs/think-dast-zh/3.md) - + [第四章 `LinkedList`](docs/think-dast-zh/4.md) - + [第五章 双链表](docs/think-dast-zh/5.md) - + [第六章 树的遍历](docs/think-dast-zh/6.md) - + [第七章 到达哲学](docs/think-dast-zh/7.md) - + [第八章 索引器](docs/think-dast-zh/8.md) - + [第九章 `Map`接口](docs/think-dast-zh/9.md) - + [第十章 哈希](docs/think-dast-zh/10.md) - + [第十一章 `HashMap`](docs/think-dast-zh/11.md) - + [第十二章 `TreeMap`](docs/think-dast-zh/12.md) - + [第十三章 二叉搜索树](docs/think-dast-zh/13.md) - + [第十四章 持久化](docs/think-dast-zh/14.md) - + [第十五章 爬取维基百科](docs/think-dast-zh/15.md) - + [第十六章 布尔搜索](docs/think-dast-zh/16.md) - + [第十七章 排序](docs/think-dast-zh/17.md) -+ [Leetcode C++ 题解](docs/leetcode/cpp/README.md) - + [1. Two Sum](docs/leetcode/cpp/0001._Two_Sum.md) - + [2. Add Two Numbers](docs/leetcode/cpp/0002._Add_Two_Numbers.md) - + [3. Longest Substring Without Repeating Characters](docs/leetcode/cpp/0003._Longest_Substring_Without_Repeating_Characters.md) - + [004. Median of Two Sorted Arrays](docs/leetcode/cpp/0004._Median_of_Two_Sorted_Arrays.md) - + [5. Longest Palindromic Substring](docs/leetcode/cpp/0005._Longest_Palindromic_Substring.md) - + [6. ZigZag Conversion](docs/leetcode/cpp/0006._ZigZag_Conversion.md) - + [7. Reverse Integer](docs/leetcode/cpp/0007._Reverse_Integer.md) - + [8. String to Integer (atoi)](docs/leetcode/cpp/0008._String_to_Integer_(atoi).md) - + [9. Palindrome Number](docs/leetcode/cpp/0009._Palindrome_Number.md) - + [10. Regular Expression Matching](docs/leetcode/cpp/0010._Regular_Expression_Matching.md) - + [11. container with most water](docs/leetcode/cpp/0011._Container_With_Most_Water.md) - + [12. Integer to Roman](docs/leetcode/cpp/0012._Integer_to_Roman.md) - + [14. Longest Common Prefix](docs/leetcode/cpp/0014._Longest_Common_Prefix.md) - + [15. 3sum](docs/leetcode/cpp/0015._3sum.md) - + [16. 3Sum Closest](docs/leetcode/cpp/0016._3Sum_Closest.md) - + [17. Letter Combinations of a Phone Number](docs/leetcode/cpp/0017._Letter_Combinations_of_a_Phone_Number.md) - + [18. 4Sum](docs/leetcode/cpp/0018._4Sum.md) - + [19. Remove Nth Node From End of List](docs/leetcode/cpp/0019._Remove_Nth_Node_From_End_of_List.md) - + [20. Valid Parentheses](docs/leetcode/cpp/0020._Valid_Parentheses.md) - + [21. Merge Two Sorted Lists](docs/leetcode/cpp/0021._Merge_Two_Sorted_Lists.md) - + [22. Generate Parentheses](docs/leetcode/cpp/0022._Generate_Parentheses.md) - + [23. merge k sorted lists](docs/leetcode/cpp/0023._Merge_K_Sorted_Lists.md) - + [24. Swap Nodes in Pairs](docs/leetcode/cpp/0024._Swap_Nodes_in_Pairs.md) - + [25.reverse nodes in k group](docs/leetcode/cpp/0025._Reverse_Nodes_In_K_Group.md) - + [26.Remove Duplicates From Sorted Array](docs/leetcode/cpp/0026._Remove_Duplicates_From_Sorted_Array.md) - + [27.Remove Element](docs/leetcode/cpp/0027._Remove_Element.md) - + [28.implement strstr](docs/leetcode/cpp/0028._Implement_Strstr.md) - + [29.divide two integers](docs/leetcode/cpp/0029._Divide_Two_Integers.md) - + [30.substring with concatenation of all words](docs/leetcode/cpp/0030._Substring_With_Concatenation_Of_All_Words.md) - + [31.Next Permutatio](docs/leetcode/cpp/0031._Next_Permutatio.md) - + [32. Longest Valid Parentheses](docs/leetcode/cpp/0032._Longest_Valid_Parentheses.md) - + [033. Search in Rotated Sorted Array](docs/leetcode/cpp/0033._Search_in_Rotated_Sorted_Array.md) - + [34. Find First and Last Position of Element in Sorted Array](docs/leetcode/cpp/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md) - + [???????](docs/leetcode/cpp/0035._Search_Insert_Position.md) - + [36. Valid Sudoku](docs/leetcode/cpp/0036._Valid_Sudoku.md) - + [38. Count and Say](docs/leetcode/cpp/0038._Count_and_Say.md) - + [39. Combination Sum](docs/leetcode/cpp/0039._Combination_Sum.md) - + [40. Combination Sum II](docs/leetcode/cpp/0040._Combination_Sum_II.md) - + [041.First Missing Positive](docs/leetcode/cpp/0041._First_Missing_Positive.md) - + [42. Trapping Rain Water](docs/leetcode/cpp/0042._Trapping_Rain_Water.md) - + [43. Multiply Strings](docs/leetcode/cpp/0043._Multiply_Strings.md) - + [44. Wildcard Matching](docs/leetcode/cpp/0044._Wildcard_Matching.md) - + [045. Jump Game II](docs/leetcode/cpp/0045._Jump_Game_II.md) - + [46. Permutations](docs/leetcode/cpp/0046._Permutations.md) - + [47. Permutations II](docs/leetcode/cpp/0047._Permutations_II.md) - + [49. Group Anagrams](docs/leetcode/cpp/0048._Rotate_Image.md) - + [49. Group Anagrams](docs/leetcode/cpp/0049._Group_Anagrams.md) - + [50. powx n](docs/leetcode/cpp/0050._powx_n.md) - + [51. N-Queens](docs/leetcode/cpp/0051._N-Queens.md) - + [52. N-Queens II](docs/leetcode/cpp/0052._N-Queens_II.md) - + [053. Maximum Subarray](docs/leetcode/cpp/0053._Maximum_Subarray.md) - + [54. Spiral Matrix](docs/leetcode/cpp/0054._Spiral_Matrix.md) - + [55. Jump Game](docs/leetcode/cpp/0055._Jump_Game.md) - + [56. Merge Intervals](docs/leetcode/cpp/0056._Merge_Intervals.md) - + [57. Insert Interval](docs/leetcode/cpp/0057._Insert_Interval.md) - + [058. Length of Last Word](docs/leetcode/cpp/0058._Length_of_Last_Word.md) - + [59. Spiral Matrix II](docs/leetcode/cpp/0059._Spiral_Matrix_II.md) - + [60. Permutation Sequence](docs/leetcode/cpp/0060._Permutation_Sequence.md) - + [61. Rotate List](docs/leetcode/cpp/0061._Rotate_List.md) - + [62. Unique Paths](docs/leetcode/cpp/0062._Unique_Paths.md) - + [63. Unique Paths II](docs/leetcode/cpp/0063._Unique_Paths_II.md) - + [64. Minimum Path Sum](docs/leetcode/cpp/0064._Minimum_Path_Sum.md) - + [65. Valid Number](docs/leetcode/cpp/0065._Valid_Number.md) - + [66. Plus One](docs/leetcode/cpp/0066._Plus_One.md) - + [68. Text Justification](docs/leetcode/cpp/0068._Text_Justification.md) - + [69. Sqrt(x)](docs/leetcode/cpp/0069._Sqr(x).md) - + [72. Edit Distance](docs/leetcode/cpp/0072._Edit_Distance.md) - + [75. Sort Colors](docs/leetcode/cpp/0075._Sort_Colors.md) - + [76. Minimum Window Substring](docs/leetcode/cpp/0076._Minimum_Window_Substring.md) - + [77. Combinations](docs/leetcode/cpp/0077._combinations.md) - + [78. Subsets](docs/leetcode/cpp/0078._subsets.md) - + [81. Search in Rotated Sorted Array II](docs/leetcode/cpp/0081._Search_in_Rotated_Sorted_Array_II.md) - + [???????](docs/leetcode/cpp/0083._Remove_Duplicates_From_Sorted_Lists.md) - + [84. Largest Rectangle in Histogram](docs/leetcode/cpp/0084._Largest_Rectangle_in_Histogram.md) - + [85. Maximal Rectangle](docs/leetcode/cpp/0085._Maximal_Rectangle.md) - + [87. Scramble String](docs/leetcode/cpp/0087._Scramble_String.md) - + [88.Merge Sorted Array](docs/leetcode/cpp/0088._Merge_Sorted_Array.md) - + [90. Subsets II](docs/leetcode/cpp/0090._Subsets_II.md) - + [94. Binary Tree Inorder Traversal](docs/leetcode/cpp/0094._binary_tree_inorder_traversal.md) - + [96. Unique Binary Search Trees](docs/leetcode/cpp/0096._Unique_Binary_Search_Trees.md) - + [97. Interleaving String](docs/leetcode/cpp/0097._Interleaving_String.md) - + [99. Recover Binary Search Tree](docs/leetcode/cpp/0099._Recover_Binary_Search_Tree.md) - + [100. same tree](docs/leetcode/cpp/0100._same_tree.md) - + [101. Symmetric Tree](docs/leetcode/cpp/0101._Symmetric_Tree.md) - + [102. Binary Tree Level Order Traversal](docs/leetcode/cpp/0102._Binary_Tree_Level_Order_Traversal.md) - + [104. Maximum Depth of Binary Tree](docs/leetcode/cpp/0104._Maximum_Depth_of_Binary_Tree.md) - + [105. Construct Binary Tree from Preorder and Inorder Traversal](docs/leetcode/cpp/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md) - + [106. Construct Binary Tree from Inorder and Postorder Traversal](docs/leetcode/cpp/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md) - + [107.Binary Tree Level Order Traversal II](docs/leetcode/cpp/0107._Binary_Tree_Level_Order_Traversal_II.md) - + [108. Convert Sorted Array to Binary Search Tree](docs/leetcode/cpp/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md) - + [109. Convert Sorted List to Binary Search Tree](docs/leetcode/cpp/0109._Convert_Sorted_List_to_Binary_Search_Tree.md) - + [110.Balanced Binary Tree](docs/leetcode/cpp/0110._Balanced_Binary_Tree.md) - + [111. Minimum Depth of Binary Tree](docs/leetcode/cpp/0111._Minimum_Depth_Of_Binary_Tree.md) - + [112. Path Sum](docs/leetcode/cpp/0112._Path_Sum.md) - + [114. Flatten Binary Tree to Linked List](docs/leetcode/cpp/0114._Flatten_Binary_Tree_to_Linked_List.md) - + [115.Distinct Subsequences](docs/leetcode/cpp/0115._Distinct_Subsequences.md) - + [118. Pascal's Triangle](docs/leetcode/cpp/0118._Pascals_Triangle.md) - + [119. Pascal's Triangle II](docs/leetcode/cpp/0119._Pascals_Triangle-II.md) - + [120. Triangle](docs/leetcode/cpp/0120._Triangle.md) - + [121. Best Time to Buy and Sell Stock](docs/leetcode/cpp/0121._Best_Tim_to_Buy_and_Sell_Stock.md) - + [122. Best Time to Buy and Sell Stock II](docs/leetcode/cpp/0122._Best_Time_to_Buy_and_Sell_Stock_II.md) - + [123. Best Time to Buy and Sell Stock III](docs/leetcode/cpp/0123._Best_Time_to_Buy_and_Sell_Stock_III.md) - + [124. Binary Tree Maximum Path Sum](docs/leetcode/cpp/0124._Binary_Tree_Maximum_Path_Sum.md) - + [127. Word Ladder](docs/leetcode/cpp/0127._Word_Ladde.md) - + [128. Longest Consecutive Sequence](docs/leetcode/cpp/0128._Longest_Consecutive_Sequence.md) - + [129. Sum Root to Leaf Numbers](docs/leetcode/cpp/0129._Sum_Root_to_Leaf_Numbers.md) - + [131. Palindrome Paritionaing](docs/leetcode/cpp/0131._Palindrome_Partitioning.md) - + [136. Single Numbe](docs/leetcode/cpp/0136._Single_Numbe.md) - + [137.Single Number II](docs/leetcode/cpp/0137._Single_Number_II.md) - + [???????](docs/leetcode/cpp/0141._Linked_List_Cycle.md) - + [142. linked list cycle II](docs/leetcode/cpp/0142._Linked_List_Cycle_II.md) - + [144. Binary Tree Preorder Traversal](docs/leetcode/cpp/0144._Binary_Tree_Preorder_Traversal.md) - + [145. Binary Tree Postorder Traversal](docs/leetcode/cpp/0145._Binary_Tree_Postorder_Traversal.md) - + [147. Insertion Sort List](docs/leetcode/cpp/0147._Insert_on_Sort_List.md) - + [148.Sort list](docs/leetcode/cpp/0148._Sort_list.md) - + [151. Reverse Words in a String](docs/leetcode/cpp/0151._Reverse_Words_in_a_String.md) - + [153. Find Minimum in Rotated Sorted Array](docs/leetcode/cpp/0153._Find_Minimum_in_Rotated_Sorted_Array.md) - + [154. Find Minimum in Rotated Sorted Array II](docs/leetcode/cpp/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md) - + [160 intersection_of_Two_Linked_Lists](docs/leetcode/cpp/0160._Intersection_Of_Two_Linked_Lists.md) - + [164. Maximum Gap](docs/leetcode/cpp/0164._Maximum_Gap.md) - + [166. Fraction to Recurring Decimal](docs/leetcode/cpp/0166._Fraction_to_Recurring_Decimal.md) - + [167. Two Sum II - Input array is sorted](docs/leetcode/cpp/0167._Two_Sum_II-Input_array_is_sorted.md) - + [199. Binary Tree Right Side View](docs/leetcode/cpp/0199._Binary_Tree_Right_Side_View.md) - + [216. Combination Sum III](docs/leetcode/cpp/0216._Combination_Sum_III.md) - + [230. Kth Smallest Element in a BST](docs/leetcode/cpp/0230._Kth_Smallest_Element_in_a_BST.md) - + [260. Single Number III](docs/leetcode/cpp/0260._Single_Number_III.md) - + [287. Find the Duplicate Number](docs/leetcode/cpp/0287._Find_the_Duplicate_Number.md) - + [326. Power_of_Three](docs/leetcode/cpp/0326._Power_Of_Three.md) - + [328. Odd Even Linked List](docs/leetcode/cpp/0328._Odd_Even_Linked_List.md) - + [329. Longest Increasing Path in a Matrix](docs/leetcode/cpp/0329._Longest_Increasing_Path_in_a_Matrix.md) - + [338. Counting Bits ](docs/leetcode/cpp/0338._Counting_Bits.md) - + [413. Arithmetic Slices](docs/leetcode/cpp/0413._Arithmetic_Slices.md) - + [442. Find All Duplicates in an Array](docs/leetcode/cpp/0442._Find_All_Duplicates_in_an_Array.md) - + [513. Find Bottom Left Tree Value](docs/leetcode/cpp/0513._Find_Bottom_Left_Tree_Value.md) - + [515. Find Largest Value in Each Tree Row](docs/leetcode/cpp/0515._Find_Largest_Value_in_Each_Tree_Row.md) - + [540. Single Element in a Sorted Array](docs/leetcode/cpp/0540._Single_Element_in_a_Sorted_Array.md) - + [581. Shortest Unsorted Continuous Subarray](docs/leetcode/cpp/0581._Shortest_Unsorted_Continuous_Subarray.md) - + [793. K Inverse Pairs Array](docs/leetcode/cpp/0629._K_Inverse_Pairs_Array.md) - + [632. Smallest Range](docs/leetcode/cpp/0632._Smallest_Range.md) - + [654. Maximum Binary Tree ](docs/leetcode/cpp/0654._maximum_binary_tree.md) - + [668. Kth Smallest Number in Multiplication Table](docs/leetcode/cpp/0668._Kth_Smallest_Number_in_Multiplication_Table.md) - + [701. Insert into a Binary Search Tree](docs/leetcode/cpp/0701._Insert_into_a_Binary_Search_Tree.md) - + [715. Range Module](docs/leetcode/cpp/0715._Range_Module.md) - + [793. Find K-th Smallest Pair Distance](docs/leetcode/cpp/0719._Find_K-th_Smallest_Pair_Distance.md) - + [739. Daily Temperatures](docs/leetcode/cpp/0739._Daily_Temperatures.md) - + [797. All Paths From Source to Target](docs/leetcode/cpp/0797._All_Paths_From_Source_To_Target.md) - + [814. Binary Tree Pruning](docs/leetcode/cpp/0814._Binary_Tree_Pruning.md) - + [841. Keys and Rooms](docs/leetcode/cpp/0841._Keys_and_Rooms.md) - + [877. Stone Game](docs/leetcode/cpp/0877._Stone_Game.md) - + [945. Minimum Increment to Make Array Unique](docs/leetcode/cpp/0945._Minimum_Increment_to_Make_Array_Unique.md) - + [946. Validate Stack Sequences](docs/leetcode/cpp/0946._Validate_Stack_Sequences.md) - + [947. Most Stones Removed with Same Row or Column](docs/leetcode/cpp/0947._Most_Stones_Removed_with_Same_Row_or_Column.md) - + [948. Bag of Tokens](docs/leetcode/cpp/0948._Bag_of_Tokens.md) - + [949. Largest Time for Given Digits](docs/leetcode/cpp/0949._Largest_Time_for_Given_Digits.md) - + [950. Reveal Cards In Increasing Order](docs/leetcode/cpp/0950._Reveal_Cards_In_Increasing_Order.md) - + [951. Flip Equivalent Binary Trees](docs/leetcode/cpp/0951._Flip_Equivalent_Binary_Trees.md) - + [952. Largest Component Size by Common Factor](docs/leetcode/cpp/0952._Largest_Component_Size_by_Common_Factor.md) -+ [Leetcode Java 题解](docs/leetcode/java/README.md) - + [1. Two Sum](docs/leetcode/java/0001._Two_Sum.md) - + [2. Add Two Numbers](docs/leetcode/java/0002._add_two_numbers.md) - + [3. Longest Substring Without Repeating Characters](docs/leetcode/java/0003._Longest_Substring_Without_Repeating_Characters.md) - + [4. Median of Two Sorted Arrays](docs/leetcode/java/0004._Median_of_Two_Sorted_Arrays.md) - + [5. Longest Palindromic Substring](docs/leetcode/java/0005._Longest_Palindromic_Substring.md) - + [6. ZigZag Conversion](docs/leetcode/java/0006._ZigZag_Conversion.md) - + [7. Reverse Integer](docs/leetcode/java/0007._Reverse_Integer.md) - + [23. Merge K Sorted Lists](docs/leetcode/java/0023._Merge_K_Sorted_Lists.md) - + [141. Linked List Cycle](docs/leetcode/java/0141._linked_list_cycle.md) - + [218. The Skyline Problem](docs/leetcode/java/0218._The_Skyline_Problem.md) - + [238. Product of Array Except Self](docs/leetcode/java/0238._product_of_array_except_self.md) - + [342. Power of Four](docs/leetcode/java/0342._Power_of_Four.md) - + [403. Frog Jump](docs/leetcode/java/0403._Frog_Jump.md) - + [757. Set Intersection Size At Least Two](docs/leetcode/java/0757._Set_Intersection_Size_At_Least_Two.md) - + [768. Max Chunks To Make Sorted II](docs/leetcode/java/0768._Max_Chunks_To_Make_Sorted_II.md) - + [780. Reaching Points](docs/leetcode/java/0780._Reaching_Points.md) - + [793. Preimage Size of Factorial Zeroes Function](docs/leetcode/java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md) - + [827. Making A Large Island](docs/leetcode/java/0827._Making_A_Large_Island.md) - + [828. Unique Letter String](docs/leetcode/java/0828._Unique_Letter_String.md) - + [834. Sum of Distances in Tree](docs/leetcode/java/0834._Sum_of_Distances_in_Tree.md) - + [843. Guess the Word](docs/leetcode/java/0843._Guess_the_Word.md) - + [847. Shortest Path Visiting All Nodes](docs/leetcode/java/0847._Shortest_Path_Visiting_All_Nodes.md) - + [850. Rectangle Area II](docs/leetcode/java/0850._Rectangle_Area_II.md) - + [854. K-Similar Strings](docs/leetcode/java/0854._K-Similar_Strings.md) - + [857. Minimum Cost to Hire K Workers](docs/leetcode/java/0857._Minimum_Cost_to_Hire_K_Workers.md) - + [862. Shortest Subarray with Sum at Least K](docs/leetcode/java/0862._Shortest_Subarray_with_Sum_at_Least_K.md) - + [864. Shortest Path to Get All Keys](docs/leetcode/java/0864._Shortest_Path_to_Get_All_Keys.md) - + [871. Minimum Number of Refueling Stops](docs/leetcode/java/0871._Minimum_Number_of_Refueling_Stops.md) - + [878. Nth Magical Number](docs/leetcode/java/0878._Nth_Magical_Number.md) - + [879. Profitable Schemes](docs/leetcode/java/0879._Profitable_Schemes.md) - + [899. Reachable Nodes In Subdivided Graph](docs/leetcode/java/0882._Reachable_Nodes_In_Subdivided_Graph.md) - + [887. Super Egg Drop](docs/leetcode/java/0887._Super_Egg_Drop.md) - + [891. Sum of Subsequence Widths](docs/leetcode/java/0891._Sum_of_Subsequence_Widths.md) - + [895. Maximum Frequency Stack](docs/leetcode/java/0895._Maximum_Frequency_Stack.md) - + [899. Orderly Queue](docs/leetcode/java/0899._Orderly_Queue.md) - + [902. Numbers At Most N Given Digit Set](docs/leetcode/java/0902._Numbers_At_Most_N_Given_Digit_Set.md) - + [903. Valid Permutations for DI Sequence](docs/leetcode/java/0903._Valid_Permutations_for_DI_Sequence.md) - + [906. Super Palindromes](docs/leetcode/java/0906._Super_Palindromes.md) - + [913. Cat and Mouse](docs/leetcode/java/0913._Cat_and_Mouse.md) - + [920. Number of Music Playlists](docs/leetcode/java/0920._Number_of_Music_Playlists.md) -+ [Leetcode JavaScript 题解](docs/leetcode/javascript/README.md) - + [0001 Two Sum](docs/leetcode/javascript/0001._Two_Sum.md) - + [0002 Add Two Numbers](docs/leetcode/javascript/0002._Add_Two_Numbers.md) - + [0003 Longest Substring without Repeating Characters](docs/leetcode/javascript/0003._Longest_Substring_without_Repeating_Characters.md) - + [0007 Reverse Integer](docs/leetcode/javascript/0007._Reverse_Integer.md) - + [0008 String to Integer](docs/leetcode/javascript/0008._String_to_Integer.md) - + [0009 Palindrome Number](docs/leetcode/javascript/0009._Palindrome_Number.md) - + [0011 Container With Most Water](docs/leetcode/javascript/0011._Container_With_Most_Water.md) - + [0012 Integer To Roman](docs/leetcode/javascript/0012._Integer_To_Roman.md) - + [0013 Roman To Integer](docs/leetcode/javascript/0013._Roman_To_Integer.md) - + [0014 Longest Common Prefix](docs/leetcode/javascript/0014._Longest_Common_Prefix.md) - + [0015 Three Sum](docs/leetcode/javascript/0015._Three_Sum.md) - + [0016 3 Sum Closest](docs/leetcode/javascript/0016._3_Sum_Closest.md) - + [0017 Letter Combinations Of A Phone Number](docs/leetcode/javascript/0017._Letter_Combinations_Of_A_Phone_Number.md) - + [0019 Remove Nth Node From End Of List](docs/leetcode/javascript/0019._Remove_Nth_Node_From_End_Of_List.md) - + [0020 Valid Parentheses](docs/leetcode/javascript/0020._Valid_Parentheses.md) - + [0021 Merge Two Sorted Lists](docs/leetcode/javascript/0021._Merge_Two_Sorted_Lists.md) - + [0022 Generate Parentheses](docs/leetcode/javascript/0022._Generate_Parentheses.md) - + [0024 Swap Nodes In Pairs](docs/leetcode/javascript/0024._Swap_Nodes_In_Pairs.md) - + [0027 Remove Element](docs/leetcode/javascript/0027._Remove_Element.md) - + [0031 Next Permutation](docs/leetcode/javascript/0031._Next_Permutation.md) - + [0035 Search Insert Position](docs/leetcode/javascript/0035._Search_Insert_Position.md) - + [0054 Spiral Matrix](docs/leetcode/javascript/0054._Spiral_Matrix.md) - + [0055 Jump Game](docs/leetcode/javascript/0055._Jump_Game.md) - + [0056 Merge Intervals](docs/leetcode/javascript/0056._Merge_Intervals.md) - + [0058 Length of Last Word](docs/leetcode/javascript/0058._Length_of_Last_Word.md) - + [0061 Rotate List](docs/leetcode/javascript/0061._Rotate_List.md) - + [0062 Unique Paths](docs/leetcode/javascript/0062._Unique_Paths.md) - + [0066 Plus One](docs/leetcode/javascript/0066._Plus_One.md) - + [0067 Add Binary](docs/leetcode/javascript/0067._Add_Binary.md) - + [0074 Search a 2D Matrix](docs/leetcode/javascript/0074._Search_a_2D_Matrix.md) - + [0079 Search Word](docs/leetcode/javascript/0079._Search_Word.md) - + [0083 Remove Duplicates From Sorted List](docs/leetcode/javascript/0083._Remove_Duplicates_From_Sorted_List.md) - + [0094 Binary Tree Inorder Traversal](docs/leetcode/javascript/0094._Binary_Tree_Inorder_Traversal.md) - + [0098 Validate Binary Search Tree](docs/leetcode/javascript/0098._Validate_Binary_Search_Tree.md) - + [0100 Same Tree](docs/leetcode/javascript/0100._Same_Tree.md) - + [0101 Symmetric Tree](docs/leetcode/javascript/0101._Symmetric_Tree.md) - + [0104 Maximum Depth of Binary Tree](docs/leetcode/javascript/0104._Maximum_Depth_of_Binary_Tree.md) - + [0106 Construct Binary Tree From Inorder And Postorder Traversal](docs/leetcode/javascript/0106._Construct_Binary_Tree_From_Inorder_And_Postorder_Traversal.md) - + [0141 Linked List Cycle](docs/leetcode/javascript/0141._Linked_List_Cycle.md) - + [0146 LRU Cache](docs/leetcode/javascript/0146._LRU_Cache.md) - + [0167 Two Sum II - Input array is sorted](docs/leetcode/javascript/0167._Two_Sum_II_-_Input_array_is_sorted.md) - + [0167 Two Sum II Input Array is Sorted](docs/leetcode/javascript/0167._Two_Sum_II_Input_Array_is_Sorted.md) - + [0171 Excel Sheet Column Number](docs/leetcode/javascript/0171._Excel_Sheet_Column_Number.md) - + [0179 Largest Number](docs/leetcode/javascript/0179._Largest_Number.md) - + [0203 Remove Linked List Elements](docs/leetcode/javascript/0203._Remove_Linked_List_Elements.md) - + [0206 Reverse-Linked-List](docs/leetcode/javascript/0206._Reverse-Linked-List.md) - + [0209 Minimum Size Subarray Sum](docs/leetcode/javascript/0209._Minimum_Size_Subarray_Sum.md) - + [0258 Add Digits](docs/leetcode/javascript/0258._Add_Digits.md) - + [0347 Top K Frequent Elements](docs/leetcode/javascript/0347._Top_K_Frequent_Elements.md) - + [0402 Remove K Digits](docs/leetcode/javascript/0402._Remove_K_Digits.md) - + [0406 Queue Reconstruction By Height](docs/leetcode/javascript/0406._Queue_Reconstruction_By_Height.md) - + [0485 Max Consecutive Ones](docs/leetcode/javascript/0485._Max_Consecutive_Ones.md) - + [0539 Minimum Time Difference](docs/leetcode/javascript/0539._Minimum_Time_Difference.md) - + [0581 Shortest Unsorted Continuous Subarray](docs/leetcode/javascript/0581._Shortest_Unsorted_Continuous_Subarray.md) - + [0881 Boats to Save People](docs/leetcode/javascript/0881._Boats_to_Save_People.md) - + [0997 Find The Town Judge](docs/leetcode/javascript/0997._Find_The_Town_Judge.md) - + [1130 Minimum Cost Tree From Leaf Values](docs/leetcode/javascript/1130._Minimum_Cost_Tree_From_Leaf_Values.md) -+ [Leetcode Python 题解](docs/leetcode/python/README.md) - + [001 two sum](docs/leetcode/python/001._two_sum.md) - + [002 add two numbers](docs/leetcode/python/002._add_two_numbers.md) - + [003 longest substring without repeating characters](docs/leetcode/python/003._longest_substring_without_repeating_characters.md) - + [004 median of two sorted arrays](docs/leetcode/python/004._median_of_two_sorted_arrays.md) - + [005 longest palindromic substring](docs/leetcode/python/005._longest_palindromic_substring.md) - + [006 ZigZag Conversion](docs/leetcode/python/006._ZigZag_Conversion.md) - + [007 Reverse Integer](docs/leetcode/python/007._Reverse_Integer.md) - + [008 string to integer (atoi)](docs/leetcode/python/008._string_to_integer_(atoi).md) - + [009 Palindrome Number](docs/leetcode/python/009._Palindrome_Number.md) - + [010 regular expression matching](docs/leetcode/python/010._regular_expression_matching.md) - + [011 container with most water](docs/leetcode/python/011._container_with_most_water.md) - + [012 Integer to Roman](docs/leetcode/python/012._Integer_to_Roman.md) - + [013 Roman to Integer](docs/leetcode/python/013._Roman_to_Integer.md) - + [014 longest common prefix](docs/leetcode/python/014._longest_common_prefix.md) - + [015 3sum](docs/leetcode/python/015._3sum.md) - + [016 3sum closest](docs/leetcode/python/016._3sum_closest.md) - + [017 letter combinations of a phone number](docs/leetcode/python/017._letter_combinations_of_a_phone_number.md) - + [018 4sum](docs/leetcode/python/018._4sum.md) - + [019 remove nth node from end of list](docs/leetcode/python/019._remove_nth_node_from_end_of_list.md) - + [020 valid parentheses](docs/leetcode/python/020._valid_parentheses.md) - + [021 merge two sorted lists](docs/leetcode/python/021._merge_two_sorted_lists.md) - + [022 generate parentheses](docs/leetcode/python/022._generate_parentheses.md) - + [023 merge k sorted lists](docs/leetcode/python/023._merge_k_sorted_lists.md) - + [024 swap nodes in pairs](docs/leetcode/python/024._swap_nodes_in_pairs.md) - + [026 Remove Duplicates from Sorted Array](docs/leetcode/python/026._Remove_Duplicates_from_Sorted_Array.md) - + [027 Remove Element](docs/leetcode/python/027._Remove_Element.md) - + [028 implement strstr()](docs/leetcode/python/028._implement_strstr.md) - + [030 Substring with Concatenation of All Words](docs/leetcode/python/030._Substring_with_Concatenation_of_All_Words.md) - + [031 next permutation](docs/leetcode/python/031._next_permutation.md) - + [032 longest valid parentheses](docs/leetcode/python/032._longest_valid_parentheses.md) - + [033 search in rotated sorted array](docs/leetcode/python/033._search_in_rotated_sorted_array.md) - + [034 Search for a Range](docs/leetcode/python/034._Search_for_a_Range.md) - + [035 search insert position](docs/leetcode/python/035._search_insert_position.md) - + [038 Count and Say](docs/leetcode/python/038._Count_and_Say.md) - + [039 combination sum](docs/leetcode/python/039._combination_sum.md) - + [040 combination sum ii](docs/leetcode/python/040._combination_sum_ii.md) - + [041 First Missing Positive](docs/leetcode/python/041._First_Missing_Positive.md) - + [042 trapping rain water](docs/leetcode/python/042._trapping_rain_water.md) - + [043 multiply strings](docs/leetcode/python/043._multiply_strings.md) - + [044 wildcard matching](docs/leetcode/python/044._wildcard_matching.md) - + [045 Jump Game II](docs/leetcode/python/045._Jump_Game_II.md) - + [046 permutations](docs/leetcode/python/046._permutations.md) - + [047 permutations ii](docs/leetcode/python/047._permutations_ii.md) - + [048 rotate image](docs/leetcode/python/048._rotate_image.md) - + [049 group anagrams python](docs/leetcode/python/049._group_anagrams_python.md) - + [050 pow(x, n)](docs/leetcode/python/050._pow(x,_n).md) - + [051 n-queens](docs/leetcode/python/051._n-queens.md) - + [052 n-queens ii](docs/leetcode/python/052._n-queens_ii.md) - + [053 maximum subarray](docs/leetcode/python/053._maximum_subarray.md) - + [054 spiral matrix](docs/leetcode/python/054._spiral_matrix.md) - + [055 jump game](docs/leetcode/python/055._jump_game.md) - + [056 Merge Intervals](docs/leetcode/python/056._Merge_Intervals.md) - + [058 length of last word](docs/leetcode/python/058._length_of_last_word.md) - + [059 spiral matrix ii](docs/leetcode/python/059._spiral_matrix_ii.md) - + [060 permutation sequence](docs/leetcode/python/060._permutation_sequence.md) - + [061 rotate list](docs/leetcode/python/061._rotate_list.md) - + [062 unique paths](docs/leetcode/python/062._unique_paths.md) - + [064 minimum path sum](docs/leetcode/python/064._minimum_path_sum.md) - + [065 unique paths ii](docs/leetcode/python/065.unique_paths_ii.md) - + [066 plus one](docs/leetcode/python/066._plus_one.md) - + [067 add binary](docs/leetcode/python/067._add_binary.md) - + [069 sqrt(x)](docs/leetcode/python/069._sqrt(x).md) - + [070 Climbing Stairs](docs/leetcode/python/070._Climbing_Stairs.md) - + [072 edit distance](docs/leetcode/python/072._edit_distance.md) - + [073 Set Matrix Zeroes](docs/leetcode/python/073._Set_Matrix_Zeroes.md) - + [074 search a 2d matrix](docs/leetcode/python/074._search_a_2d_matrix.md) - + [075 sort colors](docs/leetcode/python/075._sort_colors.md) - + [076 Minimum Window Substring](docs/leetcode/python/076._Minimum_Window_Substring.md) - + [077 combinations](docs/leetcode/python/077._combinations.md) - + [078 Subsets](docs/leetcode/python/078._Subsets.md) - + [079 word search](docs/leetcode/python/079._word_search.md) - + [082 remove duplicates from sorted list ii](docs/leetcode/python/082._remove_duplicates_from_sorted_list_ii.md) - + [083 remove duplicates from sorted list](docs/leetcode/python/083._remove_duplicates_from_sorted_list.md) - + [086 partition list](docs/leetcode/python/086._partition_list.md) - + [088 merge sorted array](docs/leetcode/python/088._merge_sorted_array.md) - + [089 gray code](docs/leetcode/python/089._gray_code.md) - + [090 subsets ii](docs/leetcode/python/090._subsets_ii.md) - + [091 decode ways](docs/leetcode/python/091._decode_ways.md) - + [092 reverse linked list ii](docs/leetcode/python/092._reverse_linked_list_ii.md) - + [093 restore ip addresses](docs/leetcode/python/093._restore_ip_addresses.md) - + [094 binary tree inorder traversal](docs/leetcode/python/094._binary_tree_inorder_traversal.md) - + [096 unique binary search trees](docs/leetcode/python/096._unique_binary_search_trees.md) - + [098 validate binary search tree](docs/leetcode/python/098._validate_binary_search_tree.md) - + [100 same tree](docs/leetcode/python/100._same_tree.md) - + [101 symmetric tree](docs/leetcode/python/101._symmetric_tree.md) - + [102 binary tree level order traversal](docs/leetcode/python/102._binary_tree_level_order_traversal.md) - + [103 binary tree zigzag level order traversal](docs/leetcode/python/103._binary_tree_zigzag_level_order_traversal.md) - + [104 maximum depth of binary tree](docs/leetcode/python/104._maximum_depth_of_binary_tree.md) - + [105 construct binary tree from preorder and inorder traversal](docs/leetcode/python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md) - + [106 construct binary tree from inorder and postorder traversal](docs/leetcode/python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md) - + [107 binary tree level order traversal ii](docs/leetcode/python/107._binary_tree_level_order_traversal_ii.md) - + [108 convert sorted array to binary search tree](docs/leetcode/python/108._convert_sorted_array_to_binary_search_tree.md) - + [109 convert sorted list to binary search tree](docs/leetcode/python/109._convert_sorted_list_to_binary_search_tree.md) - + [110 balanced binary tree](docs/leetcode/python/110._balanced_binary_tree.md) - + [111 minimum depth of binary tree](docs/leetcode/python/111._minimum_depth_of_binary_tree.md) - + [112 path sum](docs/leetcode/python/112._path_sum.md) - + [113 path sum ii](docs/leetcode/python/113._path_sum_ii.md) - + [114 flatten binary tree to linked list](docs/leetcode/python/114._flatten_binary_tree_to_linked_list.md) - + [116 populating next right pointers in each node](docs/leetcode/python/116._populating_next_right_pointers_in_each_node.md) - + [117 Populating Next Right Pointers in Each Node II](docs/leetcode/python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md) - + [118 pascal's triangle](docs/leetcode/python/118._pascal's_triangle.md) - + [119 Pascal's Triangle II](docs/leetcode/python/119._Pascal's_Triangle_II.md) - + [120 Triangle](docs/leetcode/python/120._Triangle.md) - + [121 Best Time to Buy and Sell Stock](docs/leetcode/python/121._Best_Time_to_Buy_and_Sell_Stock.md) - + [124 Binary Tree Maximum Path Sum](docs/leetcode/python/124._Binary_Tree_Maximum_Path_Sum.md) - + [125 valid palindrome](docs/leetcode/python/125._valid_palindrome.md) - + [126 Word Ladder II](docs/leetcode/python/126._Word_Ladder_II.md) - + [127 word ladder](docs/leetcode/python/127._word_ladder.md) - + [128 Longest Consecutive Sequence](docs/leetcode/python/128._Longest_Consecutive_Sequence.md) - + [129 sum root to leaf numbers](docs/leetcode/python/129._sum_root_to_leaf_numbers.md) - + [130 surrounded regions](docs/leetcode/python/130._surrounded_regions.md) - + [131 palindrome partitioning](docs/leetcode/python/131._palindrome_partitioning.md) - + [133 clone graph](docs/leetcode/python/133._clone_graph.md) - + [136 single number](docs/leetcode/python/136._single_number.md) - + [139 word break](docs/leetcode/python/139._word_break.md) - + [140 word break ii](docs/leetcode/python/140._word_break_ii.md) - + [141 linked list cycle](docs/leetcode/python/141._linked_list_cycle.md) - + [142_Linked_List_Cycle_II md](docs/leetcode/python/142_Linked_List_Cycle_II.md) - + [143 reorder list](docs/leetcode/python/143._reorder_list.md) - + [144 binary tree preorder traversal](docs/leetcode/python/144._binary_tree_preorder_traversal.md) - + [145 binary tree postorder traversal](docs/leetcode/python/145._binary_tree_postorder_traversal.md) - + [147 insertion sort list](docs/leetcode/python/147._insertion_sort_list.md) - + [148 sort list](docs/leetcode/python/148._sort_list.md) - + [150 evaluate reverse polish notation](docs/leetcode/python/150._evaluate_reverse_polish_notation.md) - + [151 reverse words in a string](docs/leetcode/python/151._reverse_words_in_a_string.md) - + [152 maximum product subarray](docs/leetcode/python/152._maximum_product_subarray.md) - + [153 find minimum in rotated sorted array](docs/leetcode/python/153._find_minimum_in_rotated_sorted_array.md) - + [155 min stack](docs/leetcode/python/155._min_stack.md) - + [157 Read N Characters Given Read4](docs/leetcode/python/157._Read_N_Characters_Given_Read4.md) - + [158 Read N Characters Given Read4 II - Call multiple times](docs/leetcode/python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md) - + [159 Longest Substring with At Most Two Distinct Characters](docs/leetcode/python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md) - + [160 intersection of two linked lists](docs/leetcode/python/160._intersection_of_two_linked_lists.md) - + [162 find peak element](docs/leetcode/python/162._find_peak_element.md) - + [165 compare version numbers](docs/leetcode/python/165._compare_version_numbers.md) - + [166 Fraction to Recurring Decimal](docs/leetcode/python/166._Fraction_to_Recurring_Decimal.md) - + [167 two sum ii - input array is sorted](docs/leetcode/python/167._two_sum_ii_-_input_array_is_sorted.md) - + [168 excel sheet column title](docs/leetcode/python/168._excel_sheet_column_title.md) - + [169 majority element](docs/leetcode/python/169._majority_element.md) - + [171 excel sheet column number](docs/leetcode/python/171._excel_sheet_column_number.md) - + [173 binary search tree iterator](docs/leetcode/python/173._binary_search_tree_iterator.md) - + [179 Largest Number](docs/leetcode/python/179._Largest_Number.md) - + [182 duplicate emails](docs/leetcode/python/182._duplicate_emails.md) - + [189 rotate array](docs/leetcode/python/189._rotate_array.md) - + [191 number of 1 bits](docs/leetcode/python/191._number_of_1_bits.md) - + [198 house robber](docs/leetcode/python/198._house_robber.md) - + [199 binary tree right side view](docs/leetcode/python/199._binary_tree_right_side_view.md) - + [200 number of islands](docs/leetcode/python/200._number_of_islands.md) - + [203 remove linked list elements](docs/leetcode/python/203._remove_linked_list_elements.md) - + [204 count primes](docs/leetcode/python/204._count_primes.md) - + [205 isomorphic strings](docs/leetcode/python/205._isomorphic_strings.md) - + [206 reverse linked list](docs/leetcode/python/206._reverse_linked_list.md) - + [207 course schedule](docs/leetcode/python/207._course_schedule.md) - + [208 implement trie (prefix tree)](docs/leetcode/python/208._implement_trie_(prefix_tree).md) - + [210 course schedule ii](docs/leetcode/python/210._course_schedule_ii.md) - + [211 Add and Search Word - Data structure design](docs/leetcode/python/211._Add_and_Search_Word_-_Data_structure_design.md) - + [213 house robber ii](docs/leetcode/python/213._house_robber_ii.md) - + [216 combination sum iii](docs/leetcode/python/216._combination_sum_iii.md) - + [217 contains duplicate](docs/leetcode/python/217._contains_duplicate.md) - + [218 The Skyline Problem](docs/leetcode/python/218._The_Skyline_Problem.md) - + [219 contains duplicate ii](docs/leetcode/python/219._contains_duplicate_ii.md) - + [221 maximal square](docs/leetcode/python/221._maximal_square.md) - + [222 count complete tree nodes](docs/leetcode/python/222._count_complete_tree_nodes.md) - + [223 rectangle area](docs/leetcode/python/223._rectangle_area.md) - + [224 Basic Calculator](docs/leetcode/python/224._Basic_Calculator.md) - + [225 implement stack using queues](docs/leetcode/python/225._implement_stack_using_queues.md) - + [226 invert binary tree](docs/leetcode/python/226._invert_binary_tree.md) - + [227 basic calculator ii](docs/leetcode/python/227._basic_calculator_ii.md) - + [228 summary ranges](docs/leetcode/python/228._summary_ranges.md) - + [229 majority element ii](docs/leetcode/python/229._majority_element_ii.md) - + [230 kth smallest element in a bst](docs/leetcode/python/230._kth_smallest_element_in_a_bst.md) - + [231 Power of Two](docs/leetcode/python/231._Power_of_Two.md) - + [232 implement queue using stacks](docs/leetcode/python/232._implement_queue_using_stacks.md) - + [234 palindrome linked list](docs/leetcode/python/234._palindrome_linked_list.md) - + [235 lowest common ancestor of a binary search tree](docs/leetcode/python/235._lowest_common_ancestor_of_a_binary_search_tree.md) - + [236 lowest common ancestor of a binary tree](docs/leetcode/python/236._lowest_common_ancestor_of_a_binary_tree.md) - + [237 delete node in a linked list](docs/leetcode/python/237._delete_node_in_a_linked_list.md) - + [238 product of array except self](docs/leetcode/python/238._product_of_array_except_self.md) - + [240 search a 2d matrix ii](docs/leetcode/python/240._search_a_2d_matrix_ii.md) - + [242 valid anagram](docs/leetcode/python/242._valid_anagram.md) - + [249 Group Shifted Strings](docs/leetcode/python/249._Group_Shifted_Strings.md) - + [252 Meeting Rooms](docs/leetcode/python/252._Meeting_Rooms.md) - + [255 Verify Preorder Sequence in Binary Search Tree](docs/leetcode/python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md) - + [256 Paint House](docs/leetcode/python/256._Paint_House.md) - + [257 binary tree paths](docs/leetcode/python/257._binary_tree_paths.md) - + [258_Add_Digits md](docs/leetcode/python/258._Add_Digits.md) - + [261 Graph Valid Tree](docs/leetcode/python/261._Graph_Valid_Tree.md) - + [263 ugly number](docs/leetcode/python/263._ugly_number.md) - + [264 ugly number ii](docs/leetcode/python/264._ugly_number_ii.md) - + [265 Paint House II](docs/leetcode/python/265._Paint_House_II.md) - + [266 Palindrome Permutation](docs/leetcode/python/266._Palindrome_Permutation.md) - + [267 Palindrome Permutation II](docs/leetcode/python/267._Palindrome_Permutation_II.md) - + [268 missing number](docs/leetcode/python/268._missing_number.md) - + [270 Closest Binary Search Tree Value](docs/leetcode/python/270._Closest_Binary_Search_Tree_Value.md) - + [276 Paint Fence](docs/leetcode/python/276._Paint_Fence.md) - + [277 Find the Celebrity](docs/leetcode/python/277._Find_the_Celebrity.md) - + [278 First Bad Version](docs/leetcode/python/278._First_Bad_Version.md) - + [279 perfect squares](docs/leetcode/python/279._perfect_squares.md) - + [280 Wiggle Sort](docs/leetcode/python/280._Wiggle_Sort.md) - + [283 move zeroes](docs/leetcode/python/283._move_zeroes.md) - + [285 inorder successor in bst](docs/leetcode/python/285._inorder_successor_in_bst.md) - + [286 Walls and Gates](docs/leetcode/python/286._Walls_and_Gates.md) - + [287 Find the Duplicate Number](docs/leetcode/python/287._Find_the_Duplicate_Number.md) - + [289 game of life](docs/leetcode/python/289._game_of_life.md) - + [290 word pattern](docs/leetcode/python/290._word_pattern.md) - + [292 nim game](docs/leetcode/python/292._nim_game.md) - + [293 Flip Game](docs/leetcode/python/293._Flip_Game.md) - + [296 Best Meeting Point](docs/leetcode/python/296._Best_Meeting_Point.md) - + [298 Binary Tree Longest Consecutive Sequence](docs/leetcode/python/298._Binary_Tree_Longest_Consecutive_Sequence.md) - + [299 bulls and cows](docs/leetcode/python/299._bulls_and_cows.md) - + [300 longest increasing subsequence](docs/leetcode/python/300._longest_increasing_subsequence.md) - + [303 range sum query - immutable](docs/leetcode/python/303._range_sum_query_-_immutable.md) - + [316 Remove Duplicate Letters](docs/leetcode/python/316._Remove_Duplicate_Letters.md) - + [319 Bulb Switcher](docs/leetcode/python/319._Bulb_Switcher.md) - + [322 Coin Change](docs/leetcode/python/322._Coin_Change.md) - + [323 number of connected components in an undirected graph](docs/leetcode/python/323._number_of_connected_components_in_an_undirected_graph.md) - + [324 Wiggle Sort II](docs/leetcode/python/324._Wiggle_Sort_II.md) - + [326 power of three](docs/leetcode/python/326._power_of_three.md) - + [328 odd even linked list](docs/leetcode/python/328._odd_even_linked_list.md) - + [334 increasing triplet subsequence](docs/leetcode/python/334._increasing_triplet_subsequence.md) - + [337 house robber iii](docs/leetcode/python/337._house_robber_iii.md) - + [338 Counting Bits](docs/leetcode/python/338._Counting_Bits.md) - + [339 Nested List Weight Sum](docs/leetcode/python/339._Nested_List_Weight_Sum.md) - + [341 Flatten Nested List Iterator](docs/leetcode/python/341._Flatten_Nested_List_Iterator.md) - + [342 Power of Four](docs/leetcode/python/342._Power_of_Four.md) - + [344 reverse string](docs/leetcode/python/344._reverse_string.md) - + [345 Reverse Vowels of a String](docs/leetcode/python/345._Reverse_Vowels_of_a_String.md) - + [349 intersection of two arrays](docs/leetcode/python/349._intersection_of_two_arrays.md) - + [350 intersection of two arrays ii](docs/leetcode/python/350._intersection_of_two_arrays_ii.md) - + [353 Design Snake Game](docs/leetcode/python/353._Design_Snake_Game.md) - + [361 Bomb Enemy](docs/leetcode/python/361._Bomb_Enemy.md) - + [364 Nested List Weight Sum II](docs/leetcode/python/364._Nested_List_Weight_Sum_II.md) - + [366 Find Leaves of Binary Tree](docs/leetcode/python/366._Find_Leaves_of_Binary_Tree.md) - + [367 valid perfect square](docs/leetcode/python/367._valid_perfect_square.md) - + [369 Plus One Linked List](docs/leetcode/python/369._Plus_One_Linked_List.md) - + [371 sum of two integers](docs/leetcode/python/371._sum_of_two_integers.md) - + [374 Guess Number Higher or Lower](docs/leetcode/python/374._Guess_Number_Higher_or_Lower.md) - + [377 combination sum iv](docs/leetcode/python/377._combination_sum_iv.md) - + [378 kth smallest element in a sorted matrix](docs/leetcode/python/378._kth_smallest_element_in_a_sorted_matrix.md) - + [380 Insert Delete GetRandom O(1)](docs/leetcode/python/380._Insert_Delete_GetRandom_O(1).md) - + [381 Insert Delete GetRandom O(1) - Duplicates allowed](docs/leetcode/python/381._Insert_Delete_GetRandom_O(1)_-_Duplicates_allowed.md) - + [382 linked list random node](docs/leetcode/python/382._linked_list_random_node.md) - + [383 ransom note](docs/leetcode/python/383._ransom_note.md) - + [384 Shuffle an Array](docs/leetcode/python/384._Shuffle_an_Array.md) - + [386 Lexicographical Numbers](docs/leetcode/python/386._Lexicographical_Numbers.md) - + [387 first unique character in a string](docs/leetcode/python/387._first_unique_character_in_a_string.md) - + [388 Longest Absolute File Path](docs/leetcode/python/388._Longest_Absolute_File_Path.md) - + [389 find the difference](docs/leetcode/python/389._find_the_difference.md) - + [392 is subsequence](docs/leetcode/python/392._is_subsequence.md) - + [394 decode string](docs/leetcode/python/394._decode_string.md) - + [400 Nth Digit](docs/leetcode/python/400._Nth_Digit.md) - + [401 binary watch](docs/leetcode/python/401._binary_watch.md) - + [404 sum of left leaves](docs/leetcode/python/404._sum_of_left_leaves.md) - + [405 Convert a Number to Hexadecimal](docs/leetcode/python/405._Convert_a_Number_to_Hexadecimal.md) - + [406 Queue Reconstruction by Height](docs/leetcode/python/406._Queue_Reconstruction_by_Height.md) - + [412 fizz buzz](docs/leetcode/python/412._fizz_buzz.md) - + [413 Arithmetic Slices](docs/leetcode/python/413._Arithmetic_Slices.md) - + [414 third maximum number](docs/leetcode/python/414._third_maximum_number.md) - + [415 add strings](docs/leetcode/python/415._add_strings.md) - + [416 Partition Equal Subset Sum](docs/leetcode/python/416._Partition_Equal_Subset_Sum.md) - + [421 Maximum XOR of Two Numbers in an Array](docs/leetcode/python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md) - + [422 Valid Word Square](docs/leetcode/python/422._Valid_Word_Square.md) - + [434 number of segments in a string](docs/leetcode/python/434._number_of_segments_in_a_string.md) - + [435 Non-overlapping Intervals](docs/leetcode/python/435._Non-overlapping_Intervals.md) - + [437 path sum iii](docs/leetcode/python/437._path_sum_iii.md) - + [438 Find All Anagrams in a String](docs/leetcode/python/438._Find_All_Anagrams_in_a_String.md) - + [439 Ternary Expression Parser](docs/leetcode/python/439._Ternary_Expression_Parser.md) - + [441 arranging coins](docs/leetcode/python/441._arranging_coins.md) - + [448 Find All Numbers Disappeared in an Array](docs/leetcode/python/448._Find_All_Numbers_Disappeared_in_an_Array.md) - + [450 Delete Node in a BST](docs/leetcode/python/450._Delete_Node_in_a_BST.md) - + [453 Minimum Moves to Equal Array Elements](docs/leetcode/python/453._Minimum_Moves_to_Equal_Array_Elements.md) - + [459 Repeated Substring Pattern](docs/leetcode/python/459._Repeated_Substring_Pattern.md) - + [461 Hamming Distance](docs/leetcode/python/461._Hamming_Distance.md) - + [463 Island Perimeter](docs/leetcode/python/463._Island_Perimeter.md) - + [467 Unique Substrings in Wraparound String](docs/leetcode/python/467._Unique_Substrings_in_Wraparound_String.md) - + [469 Convex Polygon](docs/leetcode/python/469._Convex_Polygon.md) - + [476 Number Complement](docs/leetcode/python/476._Number_Complement.md) - + [477 Total Hamming Distance](docs/leetcode/python/477._Total_Hamming_Distance.md) - + [485 Max Consecutive Ones](docs/leetcode/python/485._Max_Consecutive_Ones.md) - + [494 Target Sum](docs/leetcode/python/494._Target_Sum.md) - + [536 Construct Binary Tree from String](docs/leetcode/python/536._Construct_Binary_Tree_from_String.md) - + [587 Erect the Fence](docs/leetcode/python/587._Erect_the_Fence.md) - + [599 Minimum Index Sum of Two Lists](docs/leetcode/python/599._Minimum_Index_Sum_of_Two_Lists.md) - + [606 Construct String from Binary Tree](docs/leetcode/python/606._Construct_String_from_Binary_Tree.md) - + [611 Valid Triangle Number](docs/leetcode/python/611._Valid_Triangle_Number.md) - + [646 Maximum Length of Pair Chain](docs/leetcode/python/646._Maximum_Length_of_Pair_Chain.md) - + [647 Palindromic Substrings](docs/leetcode/python/647._Palindromic_Substrings.md) - + [657 Judge Route Circle](docs/leetcode/python/657._Judge_Route_Circle.md) - + [665 Non-decreasing Array](docs/leetcode/python/665._Non-decreasing_Array.md) - + [672 Bulb Switcher II](docs/leetcode/python/672._Bulb_Switcher_II.md) - + [681 Next Closest Time](docs/leetcode/python/681._Next_Closest_Time.md) - + [682 Baseball Game](docs/leetcode/python/682._Baseball_Game.md) - + [685 Redundant Connection II](docs/leetcode/python/685._Redundant_Connection_II.md) - + [687 Longest Univalue Path](docs/leetcode/python/687._Longest_Univalue_Path.md) - + [693 Binary Number with Alternating Bits](docs/leetcode/python/693._Binary_Number_with_Alternating_Bits.md) - + [701 Insert into a Binary Search Tree](docs/leetcode/python/701._Insert_into_a_Binary_Search_Tree.md) - + [707 Design Linked List](docs/leetcode/python/707._Design_Linked_List.md) - + [740 delete and earn](docs/leetcode/python/740._delete_and_earn.md) - + [760 Find Anagram Mappings](docs/leetcode/python/760._Find_Anagram_Mappings.md) - + [774 Minimize Max Distance to Gas Station](docs/leetcode/python/774._Minimize_Max_Distance_to_Gas_Station.md) - + [777 Swap Adjacent in LR String](docs/leetcode/python/777._Swap_Adjacent_in_LR_String.md) - + [844 Backspace String Compare](docs/leetcode/python/844._Backspace_String_Compare.md) -+ [剑指 Offer Java 题解](docs/jianzhioffer/java/README.md) - + [找出数组中重复的数字](docs/jianzhioffer/java/03_01_DuplicationInArray.md) - + [不修改数组找出重复的数字](docs/jianzhioffer/java/03_02_DuplicationInArrayNoEdit.md) - + [二维数组中的查找](docs/jianzhioffer/java/04_FindInPartiallySortedMatrix.md) - + [替换空格](docs/jianzhioffer/java/05_ReplaceSpaces.md) - + [从尾到头打印链表](docs/jianzhioffer/java/06_PrintListInReversedOrder.md) - + [重建二叉树](docs/jianzhioffer/java/07_ConstructBinaryTree.md) - + [二叉树的下一个结点](docs/jianzhioffer/java/08_NextNodeInBinaryTrees.md) - + [用两个栈实现队列](docs/jianzhioffer/java/09_01_QueueWithTwoStacks.md) - + [用两个队列实现栈](docs/jianzhioffer/java/09_02_StackWithTwoQueues.md) - + [斐波那契数列](docs/jianzhioffer/java/10_01_Fibonacci.md) - + [跳台阶](docs/jianzhioffer/java/10_02_JumpFloor.md) - + [变态跳台阶](docs/jianzhioffer/java/10_03_JumpFloorII.md) - + [矩形覆盖](docs/jianzhioffer/java/10_04_RectCover.md) - + [旋转数组的最小数字](docs/jianzhioffer/java/11_MinNumberInRotatedArray.md) - + [矩阵中的路径](docs/jianzhioffer/java/12_StringPathInMatrix.md) - + [机器人的移动范围](docs/jianzhioffer/java/13_RobotMove.md) - + [剪绳子](docs/jianzhioffer/java/14_CuttingRope.md) - + [二进制中 1 的个数](docs/jianzhioffer/java/15_NumberOf1InBinary.md) - + [数值的整数次方](docs/jianzhioffer/java/16_Power.md) - + [打印从 1 到最大的 n 位数](docs/jianzhioffer/java/17_Print1ToMaxOfNDigits.md) - + [在O(1)时间内删除链表节点](docs/jianzhioffer/java/18_01_DeleteNodeInList.md) - + [删除链表中重复的节点](docs/jianzhioffer/java/18_02_DeleteDuplicatedNode.md) - + [正则表达式匹配](docs/jianzhioffer/java/19_RegularExpressionsMatching.md) - + [表示数值的字符串](docs/jianzhioffer/java/20_NumericStrings.md) - + [调整数组顺序使奇数位于偶数前面](docs/jianzhioffer/java/21_ReorderArray.md) - + [链表中倒数第k个结点](docs/jianzhioffer/java/22_KthNodeFromEnd.md) - + [链表中环的入口结点](docs/jianzhioffer/java/23_EntryNodeInListLoop.md) - + [反转链表](docs/jianzhioffer/java/24_ReverseList.md) - + [合并两个排序的链表](docs/jianzhioffer/java/25_MergeSortedLists.md) - + [树的子结构](docs/jianzhioffer/java/26_SubstructureInTree.md) - + [二叉树的镜像](docs/jianzhioffer/java/27_MirrorOfBinaryTree.md) - + [对称的二叉树](docs/jianzhioffer/java/28_SymmetricalBinaryTree.md) - + [顺时针打印矩阵](docs/jianzhioffer/java/29_PrintMatrix.md) - + [包含min函数的栈](docs/jianzhioffer/java/30_MinInStack.md) - + [栈的压入、弹出序列](docs/jianzhioffer/java/31_StackPushPopOrder.md) - + [不分行从上到下打印二叉树](docs/jianzhioffer/java/32_01_PrintTreeFromTopToBottom.md) - + [把二叉树打印成多行](docs/jianzhioffer/java/32_02_PrintTreesInLines.md) - + [按之字形打印二叉树](docs/jianzhioffer/java/32_03_PrintTreesInZigzag.md) - + [二叉搜索树的后序遍历序列](docs/jianzhioffer/java/33_SquenceOfBST.md) - + [二叉树中和为某一值的路径](docs/jianzhioffer/java/34_PathInTree.md) - + [复杂链表的复制](docs/jianzhioffer/java/35_CopyComplexList.md) - + [二叉搜索树与双向链表](docs/jianzhioffer/java/36_ConvertBinarySearchTree.md) - + [序列化二叉树](docs/jianzhioffer/java/37_SerializeBinaryTrees.md) - + [字符串的排列](docs/jianzhioffer/java/38_StringPermutation.md) - + [数组中出现次数超过一半的数字](docs/jianzhioffer/java/39_MoreThanHalfNumber.md) - + [获取数组中最小的k个数](docs/jianzhioffer/java/40_KLeastNumbers.md) - + [数据流中的中位数](docs/jianzhioffer/java/41_StreamMedian.md) - + [连续子数组的最大和](docs/jianzhioffer/java/42_GreatestSumOfSubarrays.md) - + [整数中1出现的次数](docs/jianzhioffer/java/43_NumberOf1.md) - + [数字序列中某一位的数字](docs/jianzhioffer/java/44_DigitsInSequence.md) - + [把数组排成最小的数](docs/jianzhioffer/java/45_SortArrayForMinNumber.md) - + [把数字翻译成字符串](docs/jianzhioffer/java/46_TranslateNumbersToStrings.md) - + [礼物的最大价值](docs/jianzhioffer/java/47_MaxValueOfGifts.md) - + [最长不含重复字符的子字符串](docs/jianzhioffer/java/48_LongestSubstringWithoutDup.md) - + [丑数](docs/jianzhioffer/java/49_UglyNumber.md) - + [第一个只出现一次的字符](docs/jianzhioffer/java/50_01_FirstNotRepeatingChar.md) - + [字符流中第一个不重复的字符](docs/jianzhioffer/java/50_02_FristCharacterInStream.md) - + [两个链表的第一个公共结点](docs/jianzhioffer/java/52_FirstCommonNodesInLists.md) - + [数字在排序数组中出现的次数](docs/jianzhioffer/java/53_01_NumberOfK.md) - + [0到n-1中缺失的数字](docs/jianzhioffer/java/53_02_MissingNumber.md) - + [数组中数值和下标相等的元素](docs/jianzhioffer/java/53_03_IntegerIdenticalToIndex.md) - + [二叉搜索树的第k个结点](docs/jianzhioffer/java/54_KthNodeInBST.md) - + [二叉树的深度](docs/jianzhioffer/java/55_01_TreeDepth.md) - + [平衡二叉树](docs/jianzhioffer/java/55_02_BalancedBinaryTree.md) - + [数组中只出现一次的两个数字](docs/jianzhioffer/java/56_01_NumbersAppearOnce.md) - + [数组中唯一只出现一次的数字](docs/jianzhioffer/java/56_02_NumberAppearingOnce.md) - + [和为S的两个数字](docs/jianzhioffer/java/57_01_TwoNumbersWithSum.md) - + [和为S的连续正数序列](docs/jianzhioffer/java/57_02_ContinuousSquenceWithSum.md) - + [翻转单词顺序](docs/jianzhioffer/java/58_01_ReverseWordsInSentence.md) - + [左旋转字符串](docs/jianzhioffer/java/58_02_LeftRotateString.md) - + [滑动窗口的最大值](docs/jianzhioffer/java/59_01_MaxInSlidingWindow.md) - + [扑克牌的顺子](docs/jianzhioffer/java/61_ContinousCards.md) diff --git a/asset/back-to-top.css b/asset/back-to-top.css deleted file mode 100644 index bcb3d5a75..000000000 --- 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 3efad9be0..000000000 --- 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 4aa47afcb..000000000 --- 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 471dcf800..000000000 --- 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 0723a6b41..000000000 --- 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 27b1f7423..000000000 --- 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 811aa35fb..000000000 --- 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 1b2a5729e..000000000 --- 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 cbfda89e9..000000000 --- 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 dee84c795..000000000 --- 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-quick-page.css b/asset/docsify-quick-page.css deleted file mode 100644 index 2cbba5b7e..000000000 --- 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 d472eeb64..000000000 --- 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 2b067c7e2..000000000 --- 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 13ee7221c..000000000 --- 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 960bc6efe..000000000 --- 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 753f3eda8..000000000 --- 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 e941dd343..000000000 --- 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/left.svg b/asset/left.svg deleted file mode 100644 index 5f3e9a079..000000000 --- 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 bc0bf105f..000000000 --- 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 6a4fff5e7..000000000 --- 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 129cbbb82..000000000 --- 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-darcula.css b/asset/prism-darcula.css deleted file mode 100644 index 11a8f3ed8..000000000 --- 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 818fd8ec7..000000000 --- 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 0faf69afc..000000000 --- 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-kotlin.min.js b/asset/prism-kotlin.min.js deleted file mode 100644 index 45b197e7a..000000000 --- a/asset/prism-kotlin.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(n){n.languages.kotlin=n.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[/\w+(?=\s*\()/,{pattern:/(\.)\w+(?=\s*\{)/,lookbehind:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete n.languages.kotlin["class-name"],n.languages.insertBefore("kotlin","string",{"raw-string":{pattern:/("""|''')[\s\S]*?\1/,alias:"string"}}),n.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),n.languages.insertBefore("kotlin","function",{label:{pattern:/\w+@|@\w+/,alias:"symbol"}});var e=[{pattern:/\$\{[^}]+\}/,inside:{delimiter:{pattern:/^\$\{|\}$/,alias:"variable"},rest:n.languages.kotlin}},{pattern:/\$\w+/,alias:"variable"}];n.languages.kotlin.string.inside=n.languages.kotlin["raw-string"].inside={interpolation:e},n.languages.kt=n.languages.kotlin,n.languages.kts=n.languages.kotlin}(Prism); \ No newline at end of file diff --git a/asset/prism-perl.min.js b/asset/prism-perl.min.js deleted file mode 100644 index 570934047..000000000 --- a/asset/prism-perl.min.js +++ /dev/null @@ -1 +0,0 @@ -Prism.languages.perl={comment:[{pattern:/(^\s*)=\w+[\s\S]*?=cut.*/m,lookbehind:!0},{pattern:/(^|[^\\$])#.*/,lookbehind:!0}],string:[{pattern:/\b(?:q|qq|qx|qw)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s+([a-zA-Z0-9])(?:(?!\1)[^\\]|\\[\s\S])*\1/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s*\((?:[^()\\]|\\[\s\S])*\)/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s*\{(?:[^{}\\]|\\[\s\S])*\}/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s*\[(?:[^[\]\\]|\\[\s\S])*\]/,greedy:!0},{pattern:/\b(?:q|qq|qx|qw)\s*<(?:[^<>\\]|\\[\s\S])*>/,greedy:!0},{pattern:/("|`)(?:(?!\1)[^\\]|\\[\s\S])*\1/,greedy:!0},{pattern:/'(?:[^'\\\r\n]|\\.)*'/,greedy:!0}],regex:[{pattern:/\b(?:m|qr)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1[msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s+([a-zA-Z0-9])(?:(?!\1)[^\\]|\\[\s\S])*\1[msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s*\((?:[^()\\]|\\[\s\S])*\)[msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s*\{(?:[^{}\\]|\\[\s\S])*\}[msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s*\[(?:[^[\]\\]|\\[\s\S])*\][msixpodualngc]*/,greedy:!0},{pattern:/\b(?:m|qr)\s*<(?:[^<>\\]|\\[\s\S])*>[msixpodualngc]*/,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\2)[^\\]|\\[\s\S])*\2(?:(?!\2)[^\\]|\\[\s\S])*\2[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s+([a-zA-Z0-9])(?:(?!\2)[^\\]|\\[\s\S])*\2(?:(?!\2)[^\\]|\\[\s\S])*\2[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\((?:[^()\\]|\\[\s\S])*\)\s*\((?:[^()\\]|\\[\s\S])*\)[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\{(?:[^{}\\]|\\[\s\S])*\}\s*\{(?:[^{}\\]|\\[\s\S])*\}[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\[(?:[^[\]\\]|\\[\s\S])*\]\s*\[(?:[^[\]\\]|\\[\s\S])*\][msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*<(?:[^<>\\]|\\[\s\S])*>\s*<(?:[^<>\\]|\\[\s\S])*>[msixpodualngcer]*/,lookbehind:!0,greedy:!0},{pattern:/\/(?:[^\/\\\r\n]|\\.)*\/[msixpodualngc]*(?=\s*(?:$|[\r\n,.;})&|\-+*~<>!?^]|(?:lt|gt|le|ge|eq|ne|cmp|not|and|or|xor|x)\b))/,greedy:!0}],variable:[/[&*$@%]\{\^[A-Z]+\}/,/[&*$@%]\^[A-Z_]/,/[&*$@%]#?(?=\{)/,/[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+)+(?:::)*/i,/[&*$@%]\d+/,/(?!%=)[$@%][!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/],filehandle:{pattern:/<(?![<=])\S*>|\b_\b/,alias:"symbol"},vstring:{pattern:/v\d+(?:\.\d+)*|\d+(?:\.\d+){2,}/,alias:"string"},function:{pattern:/sub [a-z0-9_]+/i,inside:{keyword:/sub/}},keyword:/\b(?:any|break|continue|default|delete|die|do|else|elsif|eval|for|foreach|given|goto|if|last|local|my|next|our|package|print|redo|require|return|say|state|sub|switch|undef|unless|until|use|when|while)\b/,number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0b[01](?:_?[01])*|(?:\d(?:_?\d)*)?\.?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)\b/,operator:/-[rwxoRWXOezsfdlpSbctugkTBMAC]\b|\+[+=]?|-[-=>]?|\*\*?=?|\/\/?=?|=[=~>]?|~[~=]?|\|\|?=?|&&?=?|<(?:=>?|<=?)?|>>?=?|![~=]?|[%^]=?|\.(?:=|\.\.?)?|[\\?]|\bx(?:=|\b)|\b(?:lt|gt|le|ge|eq|ne|cmp|not|and|or|xor)\b/,punctuation:/[{}[\];(),:]/}; \ 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 3045bfb17..000000000 --- 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/prism-sql.min.js b/asset/prism-sql.min.js deleted file mode 100644 index 72e0c85d8..000000000 --- a/asset/prism-sql.min.js +++ /dev/null @@ -1 +0,0 @@ -Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:S|ING)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b0x[\da-f]+\b|\b\d+\.?\d*|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|IN|LIKE|NOT|OR|IS|DIV|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/}; \ No newline at end of file diff --git a/asset/right.svg b/asset/right.svg deleted file mode 100644 index 7e4d26e32..000000000 --- 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 f74474415..000000000 --- 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 79da99c44..000000000 --- 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 94996d37c..000000000 --- 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 4587d3194..000000000 --- a/asset/style.css +++ /dev/null @@ -1,96 +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; - } \ No newline at end of file diff --git a/asset/sun.svg b/asset/sun.svg deleted file mode 100644 index 8fb9960c7..000000000 --- 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 ee90b8fec..000000000 --- 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 d9b71bb18..000000000 --- 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/docs/Algorithm_Implementation/C++/README \344\270\213\345\215\21010.41.57.md" "b/docs/Algorithm_Implementation/C++/README \344\270\213\345\215\21010.41.57.md" new file mode 100644 index 000000000..6889eed16 --- /dev/null +++ "b/docs/Algorithm_Implementation/C++/README \344\270\213\345\215\21010.41.57.md" @@ -0,0 +1,5 @@ +# Some algorithm templates for better understanding! + +> [八大排序算法 集合](/docs/Algorithm/Sort) + +![](/images/SortingAlgorithm/八大排序算法性能.png) diff --git "a/docs/Algorithm_Implementation/Java/README \344\270\213\345\215\21010.41.57.md" "b/docs/Algorithm_Implementation/Java/README \344\270\213\345\215\21010.41.57.md" new file mode 100644 index 000000000..6889eed16 --- /dev/null +++ "b/docs/Algorithm_Implementation/Java/README \344\270\213\345\215\21010.41.57.md" @@ -0,0 +1,5 @@ +# Some algorithm templates for better understanding! + +> [八大排序算法 集合](/docs/Algorithm/Sort) + +![](/images/SortingAlgorithm/八大排序算法性能.png) diff --git a/.nojekyll b/docs/Algorithm_Implementation/Python/Cipher/README.md similarity index 100% rename from .nojekyll rename to docs/Algorithm_Implementation/Python/Cipher/README.md diff --git a/docs/Algorithm_Implementation/Python/Compression/README.md b/docs/Algorithm_Implementation/Python/Compression/README.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/docs/Algorithm_Implementation/Python/Compression/README.md @@ -0,0 +1 @@ + diff --git a/docs/Algorithm_Implementation/Python/Conversion/README.md b/docs/Algorithm_Implementation/Python/Conversion/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/Algorithm_Implementation/Python/Data_Structure/Graph/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/Graph/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Data_Structure/HashMap/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/HashMap/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Data_Structure/HashTable/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/HashTable/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Data_Structure/Heqp/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/Heqp/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Data_Structure/LinkedList/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/LinkedList/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Data_Structure/Matrix/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/Matrix/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Data_Structure/Queue/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/Queue/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/Python/Data_Structure/Queue/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_Implementation/Python/Data_Structure/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/README.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/docs/Algorithm_Implementation/Python/Data_Structure/README.md @@ -0,0 +1 @@ + diff --git a/docs/Algorithm_Implementation/Python/Data_Structure/Stack/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/Stack/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/Python/Data_Structure/Stack/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_Implementation/Python/Data_Structure/Tree/README.md b/docs/Algorithm_Implementation/Python/Data_Structure/Tree/README.md new file mode 100644 index 000000000..fe9c7bbf3 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Dynamic_Programming/README.md b/docs/Algorithm_Implementation/Python/Dynamic_Programming/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/Algorithm_Implementation/Python/Hash/README.md b/docs/Algorithm_Implementation/Python/Hash/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/Algorithm_Implementation/Python/Others/NextNodeInOrderTree.md b/docs/Algorithm_Implementation/Python/Others/NextNodeInOrderTree.md new file mode 100644 index 000000000..28a102486 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Others/TopKWords.java b/docs/Algorithm_Implementation/Python/Others/TopKWords.java new file mode 100644 index 000000000..c9f138000 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Others/words.txt b/docs/Algorithm_Implementation/Python/Others/words.txt new file mode 100644 index 000000000..b3c4b5679 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/README.md b/docs/Algorithm_Implementation/Python/README.md new file mode 100644 index 000000000..6889eed16 --- /dev/null +++ b/docs/Algorithm_Implementation/Python/README.md @@ -0,0 +1,5 @@ +# Some algorithm templates for better understanding! + +> [八大排序算法 集合](/docs/Algorithm/Sort) + +![](/images/SortingAlgorithm/八大排序算法性能.png) diff --git a/docs/Algorithm_Implementation/Python/Search/README.md b/docs/Algorithm_Implementation/Python/Search/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/Algorithm_Implementation/Python/Sort/README.md b/docs/Algorithm_Implementation/Python/Sort/README.md new file mode 100644 index 000000000..7f01a8d78 --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Sort/Sort.ipynb b/docs/Algorithm_Implementation/Python/Sort/Sort.ipynb new file mode 100644 index 000000000..a38ab891f --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Sort/insertionSort.py b/docs/Algorithm_Implementation/Python/Sort/insertionSort.py new file mode 100644 index 000000000..29f975d7c --- /dev/null +++ b/docs/Algorithm_Implementation/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_Implementation/Python/Sort/\346\216\222\345\272\217\347\250\263\345\256\232\346\200\247.md" "b/docs/Algorithm_Implementation/Python/Sort/\346\216\222\345\272\217\347\250\263\345\256\232\346\200\247.md" new file mode 100644 index 000000000..08b1c964e --- /dev/null +++ "b/docs/Algorithm_Implementation/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_Implementation/Python/Traversals/README.md b/docs/Algorithm_Implementation/Python/Traversals/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/leetcode/cpp/0001._Two_Sum.md b/docs/Leetcode_Solutions/C++/001._two_sum.md similarity index 90% rename from docs/leetcode/cpp/0001._Two_Sum.md rename to docs/Leetcode_Solutions/C++/001._two_sum.md index 917f83e6f..43558e034 100644 --- a/docs/leetcode/cpp/0001._Two_Sum.md +++ b/docs/Leetcode_Solutions/C++/001._two_sum.md @@ -1,74 +1,74 @@ -# 1. Two Sum - **难度: Easy** - ## 刷题内容 - > 原题连接 - * https://leetcode.com/problems/two-sum -* https://leetcode-cn.com/problems/two-sum - > 内容描述 - ``` -给定 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; - } -}; -``` +# 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 时,i++, +nums[i] + nums[j] < target 时,j--, +直到 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/Leetcode_Solutions/C++/README.md b/docs/Leetcode_Solutions/C++/README.md new file mode 100644 index 000000000..c477b8c84 --- /dev/null +++ b/docs/Leetcode_Solutions/C++/README.md @@ -0,0 +1 @@ +# Leetcode solutions and summarizations! diff --git a/docs/leetcode/java/0403._Frog_Jump.md b/docs/Leetcode_Solutions/Java/403._Frog_Jump.md similarity index 98% rename from docs/leetcode/java/0403._Frog_Jump.md rename to docs/Leetcode_Solutions/Java/403._Frog_Jump.md index 2b8dbd594..f4cc732ba 100644 --- a/docs/leetcode/java/0403._Frog_Jump.md +++ b/docs/Leetcode_Solutions/Java/403._Frog_Jump.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/frog-jump +* https://leetcode.com/problems/frog-jump/description/ > 内容描述 diff --git a/docs/leetcode/java/0878._Nth_Magical_Number.md b/docs/Leetcode_Solutions/Java/878._Nth_Magical_Number.md similarity index 97% rename from docs/leetcode/java/0878._Nth_Magical_Number.md rename to docs/Leetcode_Solutions/Java/878._Nth_Magical_Number.md index 7f71e0c45..be2d4a31e 100644 --- a/docs/leetcode/java/0878._Nth_Magical_Number.md +++ b/docs/Leetcode_Solutions/Java/878._Nth_Magical_Number.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/nth-magical-number +* https://leetcode.com/problems/nth-magical-number/description/ > 内容描述 diff --git a/docs/leetcode/java/0882._Reachable_Nodes_In_Subdivided_Graph.md b/docs/Leetcode_Solutions/Java/882._Reachable_Nodes_In_Subdivided_Graph.md similarity index 100% rename from docs/leetcode/java/0882._Reachable_Nodes_In_Subdivided_Graph.md rename to docs/Leetcode_Solutions/Java/882._Reachable_Nodes_In_Subdivided_Graph.md diff --git a/docs/leetcode/java/0887._Super_Egg_Drop.md b/docs/Leetcode_Solutions/Java/887._Super_Egg_Drop.md similarity index 100% rename from docs/leetcode/java/0887._Super_Egg_Drop.md rename to docs/Leetcode_Solutions/Java/887._Super_Egg_Drop.md diff --git a/docs/leetcode/java/0891._Sum_of_Subsequence_Widths.md b/docs/Leetcode_Solutions/Java/891._Sum_of_Subsequence_Widths.md similarity index 96% rename from docs/leetcode/java/0891._Sum_of_Subsequence_Widths.md rename to docs/Leetcode_Solutions/Java/891._Sum_of_Subsequence_Widths.md index 8f140d35f..69ab46ed5 100644 --- a/docs/leetcode/java/0891._Sum_of_Subsequence_Widths.md +++ b/docs/Leetcode_Solutions/Java/891._Sum_of_Subsequence_Widths.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/sum-of-subsequence-widths +* https://leetcode.com/problems/sum-of-subsequence-widths/description/ > 内容描述 diff --git a/docs/leetcode/java/0895._Maximum_Frequency_Stack.md b/docs/Leetcode_Solutions/Java/895._Maximum_Frequency_Stack.md similarity index 100% rename from docs/leetcode/java/0895._Maximum_Frequency_Stack.md rename to docs/Leetcode_Solutions/Java/895._Maximum_Frequency_Stack.md diff --git a/docs/leetcode/java/0899._Orderly_Queue.md b/docs/Leetcode_Solutions/Java/899._Orderly_Queue.md similarity index 100% rename from docs/leetcode/java/0899._Orderly_Queue.md rename to docs/Leetcode_Solutions/Java/899._Orderly_Queue.md diff --git a/docs/leetcode/java/0902._Numbers_At_Most_N_Given_Digit_Set.md b/docs/Leetcode_Solutions/Java/902._Numbers_At_Most_N_Given_Digit_Set.md similarity index 100% rename from docs/leetcode/java/0902._Numbers_At_Most_N_Given_Digit_Set.md rename to docs/Leetcode_Solutions/Java/902._Numbers_At_Most_N_Given_Digit_Set.md diff --git a/docs/leetcode/java/0903._Valid_Permutations_for_DI_Sequence.md b/docs/Leetcode_Solutions/Java/903._Valid_Permutations_for_DI_Sequence.md similarity index 100% rename from docs/leetcode/java/0903._Valid_Permutations_for_DI_Sequence.md rename to docs/Leetcode_Solutions/Java/903._Valid_Permutations_for_DI_Sequence.md diff --git a/docs/leetcode/java/0906._Super_Palindromes.md b/docs/Leetcode_Solutions/Java/906._Super_Palindromes.md similarity index 100% rename from docs/leetcode/java/0906._Super_Palindromes.md rename to docs/Leetcode_Solutions/Java/906._Super_Palindromes.md diff --git a/docs/Leetcode_Solutions/Python/001._two_sum.md b/docs/Leetcode_Solutions/Python/001._two_sum.md new file mode 100644 index 000000000..8d22f6a95 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/001._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(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/leetcode/python/002._add_two_numbers.md b/docs/Leetcode_Solutions/Python/002._add_two_numbers.md similarity index 84% rename from docs/leetcode/python/002._add_two_numbers.md rename to docs/Leetcode_Solutions/Python/002._add_two_numbers.md index 177706bbd..597384c2e 100644 --- a/docs/leetcode/python/002._add_two_numbers.md +++ b/docs/Leetcode_Solutions/Python/002._add_two_numbers.md @@ -1,90 +1,90 @@ -# 2. Add Two Numbers -**难度: 中等** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/add-two-numbers - -> 内容描述 - -``` -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 -``` +# 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(int(tmp[0])) + run_res = res + for i in range(1, len(tmp)): + run_res.next = ListNode(int(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/leetcode/python/003._longest_substring_without_repeating_characters.md b/docs/Leetcode_Solutions/Python/003._longest_substring_without_repeating_characters.md similarity index 56% rename from docs/leetcode/python/003._longest_substring_without_repeating_characters.md rename to docs/Leetcode_Solutions/Python/003._longest_substring_without_repeating_characters.md index ea5d372f5..728538d01 100644 --- a/docs/leetcode/python/003._longest_substring_without_repeating_characters.md +++ b/docs/Leetcode_Solutions/Python/003._longest_substring_without_repeating_characters.md @@ -1,13 +1,41 @@ -### 3. Longest Substring Without Repeating Characters +# 3. Longest Substring Without Repeating Characters +**难度: Medium** -题目: - +## 刷题内容 +> 原题连接 -难度: +* https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ -Medium +> 内容描述 + +``` + +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(N)****** @@ -46,6 +74,12 @@ class Solution(object): return l ``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +slide window全家桶,第159题和第340题几乎一摸一样,改几个数字就AC了 + ```python class Solution(object): def lengthOfLongestSubstring(self, s): @@ -53,32 +87,18 @@ class Solution(object): :type s: str :rtype: int """ - maps = {} - begin, end, counter, d = 0, 0, 0, 0 + lookup = {} + start, end, counter, length = 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: + lookup[s[end]] = lookup.get(s[end], 0) + 1 + if lookup[s[end]] == 1: counter += 1 end += 1 - while counter > 0: - if maps[s[begin]] > 1: + while start < end and counter < end - start: + lookup[s[start]] -= 1 + if lookup[s[start]] == 0: counter -= 1 - maps[s[begin]] -= 1 - begin += 1 - d = max(d, end - begin) - return d + start += 1 + length = max(length, end - start) + return length ``` - - - - - - -Author: Keqi Huang - -If you like it, please spread your support - -![Support](/img/Algorithm/LeetCode/WechatIMG17.jpeg) diff --git a/docs/leetcode/python/004._median_of_two_sorted_arrays.md b/docs/Leetcode_Solutions/Python/004._median_of_two_sorted_arrays.md similarity index 97% rename from docs/leetcode/python/004._median_of_two_sorted_arrays.md rename to docs/Leetcode_Solutions/Python/004._median_of_two_sorted_arrays.md index 655bc4f9c..8ad14bbb6 100644 --- a/docs/leetcode/python/004._median_of_two_sorted_arrays.md +++ b/docs/Leetcode_Solutions/Python/004._median_of_two_sorted_arrays.md @@ -1,260 +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 - -``` +### 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/leetcode/python/005._longest_palindromic_substring.md b/docs/Leetcode_Solutions/Python/005._longest_palindromic_substring.md similarity index 97% rename from docs/leetcode/python/005._longest_palindromic_substring.md rename to docs/Leetcode_Solutions/Python/005._longest_palindromic_substring.md index f6eb8ef16..14fd335f3 100644 --- a/docs/leetcode/python/005._longest_palindromic_substring.md +++ b/docs/Leetcode_Solutions/Python/005._longest_palindromic_substring.md @@ -183,10 +183,10 @@ Manacher算法增加两个辅助变量id和mx,其中id表示最大回文子串 下面,令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]; -![](/img/Algorithm/LeetCode/manacher1.png) +![](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之后的部分是否对称,再具体匹配。 -![](/img/Algorithm/LeetCode/manacher2.png) +![](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,然后再去匹配。 @@ -196,7 +196,7 @@ Manacher算法增加两个辅助变量id和mx,其中id表示最大回文子串 简单地用一个小例子来解释:原字符串为'qacbcaw',一眼就可以看出来最大回文子串是'acbca', 下面是我做的图,累shi了! -![](/img/Algorithm/LeetCode/manacher3.jpg) +![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher3.jpg) diff --git a/docs/leetcode/python/006._ZigZag_Conversion.md b/docs/Leetcode_Solutions/Python/006._ZigZag_Conversion.md similarity index 100% rename from docs/leetcode/python/006._ZigZag_Conversion.md rename to docs/Leetcode_Solutions/Python/006._ZigZag_Conversion.md diff --git a/docs/leetcode/python/007._Reverse_Integer.md b/docs/Leetcode_Solutions/Python/007._Reverse_Integer.md similarity index 67% rename from docs/leetcode/python/007._Reverse_Integer.md rename to docs/Leetcode_Solutions/Python/007._Reverse_Integer.md index 29edf8596..b3a00f61b 100644 --- a/docs/leetcode/python/007._Reverse_Integer.md +++ b/docs/Leetcode_Solutions/Python/007._Reverse_Integer.md @@ -1,73 +1,41 @@ -# 7. Reverse Integer 整数反转 +# 7. Reverse Integer 反转整数 -**难度: Easy** - -## 刷题内容 - -> 原题连接 +## 题目 * https://leetcode.com/problems/Reverse-Integer -* https://leetcode-cn.com/problems/reverse-integer - -> 内容描述 +* https://leetcode-cn.com/problems/reverse-integer/description/ -```python -给定一个 32 位有符号整数,将整数中的数字进行反转 +``` +给定一个 32 位有符号整数,将整数中的数字进行反转。 > 示例 1: 输入: 123 输出: 321 + > 示例 2: 输入: -123 输出: -321 + > 示例 3: 输入: 120 输出: 21 注意: -假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1] -根据这个假设,如果反转后的整数溢出,则返回 0 +假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。 +根据这个假设,如果反转后的整数溢出,则返回 0。 ``` -## 解题方案 +## 难度: Easy -* 翻转数字问题需要注意的就是溢出问题,为什么会存在溢出问题呢 -* 我们知道int型的数值范围是: -2147483648~2147483647(-2^31 ~ 2^31-1) -* 那么如果我们要翻转 1000000009 这个在范围内的数得到 9000000001,而翻转后的数就超过了范围 +翻转数字问题需要注意的就是溢出问题,为什么会存在溢出问题呢,我们知道int型的数值范围是 -2147483648~2147483647(负的2的31次方~2的31次方-1), 那么如果我们要翻转 1000000009 这个在范围内的数得到 9000000001,而翻转后的数就超过了范围。 > 思路1 -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 - - -if __name__ == "__main__": - num = -12395 - so = Solution() - n = so.reverse(num) - print("结果: ", n) -``` - -> 思路2 - 如果输入的是负数,就递归调用原函数,参数变成-x即可 ```python @@ -86,7 +54,7 @@ class Solution(object): return res if res <= 0x7fffffff else 0 ``` -> 思路3 +> 思路2 按照参数正负号先将其转成字符串,然后再反转,根据是否溢出决定输出0还是反转结果 @@ -102,12 +70,11 @@ class Solution(object): return x ``` -> 思路4(StefanPochmann大神): +> 思路3(StefanPochmann大神): -看这个解法前先看 [backticks](https://docs.python.org/2.7/reference/expressions.html#string-conversions) +看这个解法前先看[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): @@ -119,3 +86,22 @@ class Solution(object): 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/leetcode/python/008._string_to_integer_(atoi).md b/docs/Leetcode_Solutions/Python/008._string_to_integer_(atoi).md similarity index 100% rename from docs/leetcode/python/008._string_to_integer_(atoi).md rename to docs/Leetcode_Solutions/Python/008._string_to_integer_(atoi).md diff --git a/docs/Leetcode_Solutions/Python/009._Palindrome_Number.md b/docs/Leetcode_Solutions/Python/009._Palindrome_Number.md new file mode 100644 index 000000000..96714ac87 --- /dev/null +++ b/docs/Leetcode_Solutions/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/leetcode/python/010._regular_expression_matching.md b/docs/Leetcode_Solutions/Python/010._regular_expression_matching.md similarity index 80% rename from docs/leetcode/python/010._regular_expression_matching.md rename to docs/Leetcode_Solutions/Python/010._regular_expression_matching.md index f3d51b109..a0a7ec103 100644 --- a/docs/leetcode/python/010._regular_expression_matching.md +++ b/docs/Leetcode_Solutions/Python/010._regular_expression_matching.md @@ -1,26 +1,74 @@ -### 010. Regular Expression Matching +# 10. Regular Expression Matching -题目: - +**难度: Easy** +## 刷题内容 -难度: +> 原题连接 -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 +``` +## 解题方案 -先尝试暴力解法,难点就在 * 身上, * 不会单独出现,它一定是和前面一个字母或"."配成一对。看成一对后"X*",它的性质就是:要不匹配0个,要不匹配连续的“X”.所以尝试暴力解法的时候一个trick是从后往前匹配. - +> 思路 1 +先尝试暴力解法,难点就在 * 身上, * 不会单独出现,它一定是和前面一个字母或"."配成一对。看成一对后"X*",它的性质就是:要不匹配0个,要不匹配连续的“X”.所以尝试暴力解法的时候一个trick是从后往前匹配. 暴力解法居然也能AC? 是这样来分情况看得: - 如果s[i] = p[j] 或者 p[j]= . : 往前匹配一位 -- 如果p[j] = ' * ', 检查一下,如果这个时候p[j-1] = . 或者p[j-1] = s[i] ,那么就往前匹配,如果这样能匹配过,就return True, 否者我们忽略 ' X* ',这里注意里面的递推关系 +- 如果p[j] = ' * ', 检查一下,如果这个时候p[j-1] = . 或者p[j-1] = s[i] ,那么就往前匹配,如果这样能匹配过,就return True(注意如果这样不能最终匹配成功的话我们不能直接返回False,因为还可以直接忽略' X* '进行一下匹配试试是否可行), 否则我们忽略 ' X* ',这里注意里面的递推关系 - 再处理一下边界状况: - s已经匹配完了, 如果此时p还有,那么如果剩下的是 X* 这种可以过,所以检查 - p匹配完毕,如果s还有那么报错 @@ -53,8 +101,8 @@ class Solution(object): ``` +> 思路 2 ----------- dp优化,感觉和edit distance很像。 DP优化待代码化,感觉学DP的一个重点除了递归学好以外,另一点是一定要会画表格。 diff --git a/docs/leetcode/python/011._container_with_most_water.md b/docs/Leetcode_Solutions/Python/011._container_with_most_water.md similarity index 100% rename from docs/leetcode/python/011._container_with_most_water.md rename to docs/Leetcode_Solutions/Python/011._container_with_most_water.md diff --git a/docs/leetcode/python/012._Integer_to_Roman.md b/docs/Leetcode_Solutions/Python/012._Integer_to_Roman.md similarity index 100% rename from docs/leetcode/python/012._Integer_to_Roman.md rename to docs/Leetcode_Solutions/Python/012._Integer_to_Roman.md diff --git a/docs/leetcode/python/013._Roman_to_Integer.md b/docs/Leetcode_Solutions/Python/013._Roman_to_Integer.md similarity index 56% rename from docs/leetcode/python/013._Roman_to_Integer.md rename to docs/Leetcode_Solutions/Python/013._Roman_to_Integer.md index 4f1184b8a..b7bbb7a74 100644 --- a/docs/leetcode/python/013._Roman_to_Integer.md +++ b/docs/Leetcode_Solutions/Python/013._Roman_to_Integer.md @@ -1,14 +1,62 @@ -### 13.Roman to Integer +# 13.Roman to Integer +**难度: Easy** +## 刷题内容 -题目: - +> 原题连接 -难度: -Easy +* https://leetcode.com/problems/roman-to-integer/ -思路: +> 内容描述 + +``` +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: C = 100, L = 50, XXX = 30 and III = 3. +Example 5: + +Input: "MCMXCIV" +Output: 1994 +Explanation: M = 1000, CM = 900, XC = 90 and IV = 4. +``` + +## 解题方案 + +> 思路 1 ``` @@ -37,8 +85,6 @@ integer to Roman 是 Medium,这个roman to integer是easy - 如果当前比前一个大,说明这一段的值应当是这个值减去上一个值。比如IV = 5-1 =4; 否则,将当前值加入到结果中,然后开始下一段记录,比如VI = 5 + 1, II = 1 +1 -所以这也就是罗马数字的基础,感觉?这样才不会读串? - AC代码 @@ -51,18 +97,18 @@ class Solution(object): :rtype: int """ lookup = { - 'M': 1000, - 'D': 500, - 'C': 100, - 'L': 50, - 'X': 10, + 'I': 1, 'V': 5, - 'I': 1 + 'X': 10, + 'L': 50, + 'C': 100, + 'D': 500, + 'M': 1000 } 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]] + res += lookup[s[i]] - 2 * lookup[s[i-1]] else: res += lookup[s[i]] return res diff --git a/docs/leetcode/python/014._longest_common_prefix.md b/docs/Leetcode_Solutions/Python/014._longest_common_prefix.md similarity index 100% rename from docs/leetcode/python/014._longest_common_prefix.md rename to docs/Leetcode_Solutions/Python/014._longest_common_prefix.md diff --git a/docs/leetcode/python/015._3sum.md b/docs/Leetcode_Solutions/Python/015._3sum.md similarity index 75% rename from docs/leetcode/python/015._3sum.md rename to docs/Leetcode_Solutions/Python/015._3sum.md index 26a95fe2f..cdea768cd 100644 --- a/docs/leetcode/python/015._3sum.md +++ b/docs/Leetcode_Solutions/Python/015._3sum.md @@ -1,106 +1,134 @@ -### 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 -``` - +# 15. 3Sum + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/3sum/ + +> 内容描述 + +``` +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] +] +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^3)******- 空间复杂度: O(N)****** + +第一想法,先把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 +``` + +> 思路 2 +******- 时间复杂度: O(N^3)******- 空间复杂度: O(N)****** + +然后查了一下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] +``` + +> 思路 3 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + +谷歌看别人的代码,思路非常清晰的,运行起来比直接调用 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/leetcode/python/016._3sum_closest.md b/docs/Leetcode_Solutions/Python/016._3sum_closest.md similarity index 65% rename from docs/leetcode/python/016._3sum_closest.md rename to docs/Leetcode_Solutions/Python/016._3sum_closest.md index 96b012ad2..8c2525cd1 100644 --- a/docs/leetcode/python/016._3sum_closest.md +++ b/docs/Leetcode_Solutions/Python/016._3sum_closest.md @@ -1,12 +1,30 @@ -### 16. 3Sum Closest +# 16. 3Sum Closest -题目: - +**难度: Medium** +## 刷题内容 -难度: +> 原题连接 -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). +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(1)****** 思路: diff --git a/docs/Leetcode_Solutions/Python/017._letter_combinations_of_a_phone_number.md b/docs/Leetcode_Solutions/Python/017._letter_combinations_of_a_phone_number.md new file mode 100644 index 000000000..0bee9cea5 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/017._letter_combinations_of_a_phone_number.md @@ -0,0 +1,72 @@ +# 17. Letter Combinations of a Phone Number + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/ + +> 内容描述 + +``` +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 + + + - 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] + """ + lookup = { + '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'] + } + res = [] + + def helper(s, digits): + if len(digits) == 0: + res.append(s) + else: + cur_digit = digits[0] + for char in lookup[cur_digit]: + helper(s+char, digits[1:]) + + if not digits or len(digits) == 0: + return res + helper('', digits) + return res +``` + + diff --git a/docs/leetcode/python/018._4sum.md b/docs/Leetcode_Solutions/Python/018._4sum.md similarity index 100% rename from docs/leetcode/python/018._4sum.md rename to docs/Leetcode_Solutions/Python/018._4sum.md diff --git a/docs/leetcode/python/019._remove_nth_node_from_end_of_list.md b/docs/Leetcode_Solutions/Python/019._remove_nth_node_from_end_of_list.md similarity index 95% rename from docs/leetcode/python/019._remove_nth_node_from_end_of_list.md rename to docs/Leetcode_Solutions/Python/019._remove_nth_node_from_end_of_list.md index 5de9f6673..5bdefb7a0 100644 --- a/docs/leetcode/python/019._remove_nth_node_from_end_of_list.md +++ b/docs/Leetcode_Solutions/Python/019._remove_nth_node_from_end_of_list.md @@ -1,42 +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 - -``` - - - - +### 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/leetcode/python/020._valid_parentheses.md b/docs/Leetcode_Solutions/Python/020._valid_parentheses.md similarity index 93% rename from docs/leetcode/python/020._valid_parentheses.md rename to docs/Leetcode_Solutions/Python/020._valid_parentheses.md index fee842370..85442a225 100644 --- a/docs/leetcode/python/020._valid_parentheses.md +++ b/docs/Leetcode_Solutions/Python/020._valid_parentheses.md @@ -1,123 +1,123 @@ -# 20. Valid Parentheses 有效的括号 - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/valid-parentheses -* https://leetcode-cn.com/problems/valid-parentheses - -> 内容描述 - -``` -给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 - -有效字符串需满足: - -左括号必须用相同类型的右括号闭合。 -左括号必须以正确的顺序闭合。 -注意空字符串可被认为是有效字符串。 - -示例 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 == [] -``` +# 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/leetcode/python/021._merge_two_sorted_lists.md b/docs/Leetcode_Solutions/Python/021._merge_two_sorted_lists.md similarity index 59% rename from docs/leetcode/python/021._merge_two_sorted_lists.md rename to docs/Leetcode_Solutions/Python/021._merge_two_sorted_lists.md index 1122f7df9..40d474308 100644 --- a/docs/leetcode/python/021._merge_two_sorted_lists.md +++ b/docs/Leetcode_Solutions/Python/021._merge_two_sorted_lists.md @@ -1,48 +1,63 @@ -### 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 - -``` - - - - +# 21. Merge Two Sorted Lists + +**难度: 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 +``` + +## 解题方案 + +> 思路 1 + +同样适用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/leetcode/python/022._generate_parentheses.md b/docs/Leetcode_Solutions/Python/022._generate_parentheses.md similarity index 97% rename from docs/leetcode/python/022._generate_parentheses.md rename to docs/Leetcode_Solutions/Python/022._generate_parentheses.md index 06282a26e..ae14c9089 100644 --- a/docs/leetcode/python/022._generate_parentheses.md +++ b/docs/Leetcode_Solutions/Python/022._generate_parentheses.md @@ -1,88 +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的牛人解答 +### 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/Leetcode_Solutions/Python/023._merge_k_sorted_lists.md b/docs/Leetcode_Solutions/Python/023._merge_k_sorted_lists.md new file mode 100644 index 000000000..8f150514f --- /dev/null +++ b/docs/Leetcode_Solutions/Python/023._merge_k_sorted_lists.md @@ -0,0 +1,136 @@ +# 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 +] +Output: 1->1->2->3->4->4->5->6 +``` + +## 解题方案 + +> 思路 1 + + +看到思路有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 + """ + from heapq import heappush, heappop + nodes_pool = [] + dummy = cur = ListNode(-1) + for head in lists: + if head: + heappush(nodes_pool, [head.val, head]) + while nodes_pool: + smallest_node = heappop(nodes_pool)[1] + cur.next = smallest_node + cur = cur.next + if smallest_node.next: + heappush(nodes_pool, [smallest_node.next.val, smallest_node.next]) + return dummy.next +``` + +当然还像merge two sorted list + + + + +## Follow up + +> 问题描述 + +``` +一个double array length为n,有k个区间,n >> k,每个区间是单调递增的 +比如 [2.3, 5, 8.4, 3, 5, 1, 3, 9],这里k是3,三个区间是[2.3, 5, 8.4],[3, 5], [1,3,9] +要求输出sort好的array +比如 [1,2.3,3,3,5,5,8.4,9] +``` + +## 解题方案 + +> 思路 1 + +跟上面一样的思路,维护一个当前num pool就行了 + +```python +class Solution(object): + def sortKSortedArray(self, nums, k): + """ + :type list: int + :rtype: list + """ + num_pool = [] # current nums we are comparing + interval_idx = [] # current k interval + start, end = 0, 0 + for i in range(len(nums)-1): + if nums[i] > nums[i+1]: + end = i + interval_idx.append([start, end]) + start = i+1 + interval_idx.append([start, len(nums)-1]) + # record which start is invalid in arr_idx + invalid_interval_idx = set() + res = [] + while len(invalid_interval_idx) != k: + for i in range(len(interval_idx)): + # we have to make sure start <= end + if interval_idx[i][0] <= interval_idx[i][1]: + num_pool.append(nums[interval_idx[i][0]]) + interval_idx[i][0] += 1 + else: + invalid_interval_idx.add(i) + num_pool.sort() + # begin to handle current k (maybe) nums + for i in range(len(num_pool)): + res.append(num_pool[i]) + num_pool = [] + return res +``` + + +写一下测试用例 + +```python +import unittest + + +class TestSolution(unittest.TestCase): + def test_none_0(self): + nums = [2.3, 5, 8.4, 3, 5, 1, 3, 9] + res = [1, 2.3, 3, 3, 5, 5, 8.4, 9] + self.assertTrue(Solution().sortKSortedArray(nums, 3) == res) + + +if __name__ == "__main__": + unittest.main() +``` diff --git a/docs/leetcode/python/024._swap_nodes_in_pairs.md b/docs/Leetcode_Solutions/Python/024._swap_nodes_in_pairs.md similarity index 100% rename from docs/leetcode/python/024._swap_nodes_in_pairs.md rename to docs/Leetcode_Solutions/Python/024._swap_nodes_in_pairs.md diff --git a/docs/leetcode/cpp/0026._Remove_Duplicates_From_Sorted_Array.md b/docs/Leetcode_Solutions/Python/026._Remove_Duplicates_from_Sorted_Array.md similarity index 55% rename from docs/leetcode/cpp/0026._Remove_Duplicates_From_Sorted_Array.md rename to docs/Leetcode_Solutions/Python/026._Remove_Duplicates_from_Sorted_Array.md index 9dfffb6a3..1f2600177 100644 --- a/docs/leetcode/cpp/0026._Remove_Duplicates_From_Sorted_Array.md +++ b/docs/Leetcode_Solutions/Python/026._Remove_Duplicates_from_Sorted_Array.md @@ -1,13 +1,14 @@ -# 26.Remove Duplicates From Sorted Array +# 26. Remove Duplicates from Sorted Array -**�Ѷ�Easy** +**难度: Easy** -## ˢ������ +## 刷题内容 -> ԭ������ +> 原题连接 -* https://leetcode.com/problems/remove-duplicates-from-sorted-array/ -> �������� +* https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/ + +> 内容描述 ``` Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length. @@ -45,27 +46,69 @@ 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 + +## 解题方案 + +> 思路 1 + +因为题目说了是```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.pop(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/Leetcode_Solutions/Python/027._Remove_Element.md b/docs/Leetcode_Solutions/Python/027._Remove_Element.md new file mode 100644 index 000000000..3603a5b3d --- /dev/null +++ b/docs/Leetcode_Solutions/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/leetcode/python/028._implement_strstr.md b/docs/Leetcode_Solutions/Python/028._implement_strstr().md similarity index 52% rename from docs/leetcode/python/028._implement_strstr.md rename to docs/Leetcode_Solutions/Python/028._implement_strstr().md index cecd6a5e5..4428a8c55 100644 --- a/docs/leetcode/python/028._implement_strstr.md +++ b/docs/Leetcode_Solutions/Python/028._implement_strstr().md @@ -1,14 +1,39 @@ -### 28. Implement strStr() +# 28. Implement strStr() -题目: +**难度: Easy** - +## 刷题内容 +> 原题连接 -难度: +* https://leetcode.com/problems/implement-strstr/description/ -Easy +> 内容描述 +``` + +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(). +``` + +## 解题方案 + +> 思路 1 一行解法如何? ```python @@ -22,10 +47,12 @@ class Solution(object): return haystack.find(needle) ``` +> 思路 2 这个题目其实可以引来一大类,那就是关于string的算法,但是此处先用暴力算法来AC,然后再来细读/品味别的string相关算法吧。 虽然是暴力算法,但是也不容易写对啊 + ```python class Solution(object): def strStr(self, haystack, needle): @@ -34,9 +61,9 @@ class Solution(object): :type needle: str :rtype: int """ - if not needle: + if not needle or len(needle) == 0: return 0 - for i in xrange(len(haystack) - len(needle) + 1): + for i in range(len(haystack)-len(needle)+1): if haystack[i] == needle[0]: j = 1 while j < len(needle) and haystack[i+j] == needle[j]: diff --git a/docs/leetcode/python/030._Substring_with_Concatenation_of_All_Words.md b/docs/Leetcode_Solutions/Python/030._Substring_with_Concatenation_of_All_Words.md similarity index 98% rename from docs/leetcode/python/030._Substring_with_Concatenation_of_All_Words.md rename to docs/Leetcode_Solutions/Python/030._Substring_with_Concatenation_of_All_Words.md index 24d5c0849..0dd9eea26 100644 --- a/docs/leetcode/python/030._Substring_with_Concatenation_of_All_Words.md +++ b/docs/Leetcode_Solutions/Python/030._Substring_with_Concatenation_of_All_Words.md @@ -1,7 +1,7 @@ ### 30. Substring with Concatenation of All Words 题目: - + 难度 : Hard diff --git a/docs/leetcode/python/031._next_permutation.md b/docs/Leetcode_Solutions/Python/031._next_permutation.md similarity index 100% rename from docs/leetcode/python/031._next_permutation.md rename to docs/Leetcode_Solutions/Python/031._next_permutation.md diff --git a/docs/leetcode/python/032._longest_valid_parentheses.md b/docs/Leetcode_Solutions/Python/032._longest_valid_parentheses.md similarity index 97% rename from docs/leetcode/python/032._longest_valid_parentheses.md rename to docs/Leetcode_Solutions/Python/032._longest_valid_parentheses.md index 68c6e238f..7042c1767 100644 --- a/docs/leetcode/python/032._longest_valid_parentheses.md +++ b/docs/Leetcode_Solutions/Python/032._longest_valid_parentheses.md @@ -7,7 +7,7 @@ > 原题连接 * https://leetcode.com/problems/longest-valid-parentheses -* https://leetcode-cn.com/problems/longest-valid-parentheses +* https://leetcode-cn.com/problems/longest-valid-parentheses/description > 内容描述 diff --git a/docs/leetcode/python/033._search_in_rotated_sorted_array.md b/docs/Leetcode_Solutions/Python/033._search_in_rotated_sorted_array.md similarity index 52% rename from docs/leetcode/python/033._search_in_rotated_sorted_array.md rename to docs/Leetcode_Solutions/Python/033._search_in_rotated_sorted_array.md index 0da34a59f..5ae75a6ba 100644 --- a/docs/leetcode/python/033._search_in_rotated_sorted_array.md +++ b/docs/Leetcode_Solutions/Python/033._search_in_rotated_sorted_array.md @@ -1,20 +1,45 @@ -### 33. Search in Rotated Sorted Array +# 33. Search in Rotated Sorted Array -题目: - +**难度: Medium** +## 刷题内容 -难度: -Medium +> 原题连接 +* https://leetcode.com/problems/search-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]). + +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 下面是rotated-array图解, -![rotated-array图解](/img/Algorithm/LeetCode/rotated-array12:09:2017.jpg) +![rotated-array图解](https://github.com/Lisanaaa/myTODOs/blob/master/rotated-array12:09:2017.jpg) 所以直接用二分,O(lg(n)) diff --git a/docs/Leetcode_Solutions/Python/034._Search for a Range.md b/docs/Leetcode_Solutions/Python/034._Search for a Range.md new file mode 100644 index 000000000..dc54844fd --- /dev/null +++ b/docs/Leetcode_Solutions/Python/034._Search for a Range.md @@ -0,0 +1,162 @@ +# 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/description/ + +> 内容描述 + +``` +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```后再判断右边界 + +- 找左边界:二分,找到一个```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 or len(nums) == 0: + 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 + # 这里直接返回res是因为前面如果判断左边界没返回的话就说明我们判断右边界的时候一定会append元素 + return res +``` + + + +> 思路 2 +******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)****** + +跟第35题一样的思路,先找到第一个大于等于target的值的index,再找到最后一个小于等于target的值的index,然后做一些边界判断,就可以了。 + +```python +class Solution(object): + def searchRange(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + if not nums or len(nums) == 0: + return [-1, -1] + res = [] + l, r = 0, len(nums) - 1 + while l <= r: + mid = l + ((r-l) >> 1) + if nums[mid] < target: + l = mid + 1 + else: + r = mid - 1 + if l <= len(nums) - 1: + if nums[l] != target: + return [-1, -1] + else: + res.append(l) + else: + if nums[l-1] != target: + return [-1, -1] + else: + res.append(l-1) + + r = len(nums) - 1 + while l <= r: + mid = l + ((r-l) >> 1) + if nums[mid] > target: + r = mid - 1 + else: + l = mid + 1 + if r >= 0: + if nums[r] != target: + res.append(-1) + else: + res.append(r) + else: + if nums[r+1] != target: + res.append(-1) + else: + res.append(r+1) + return res +``` + + + + + + + + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/035._search_insert_position.md b/docs/Leetcode_Solutions/Python/035._search_insert_position.md new file mode 100644 index 000000000..ef3ab0a02 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/035._search_insert_position.md @@ -0,0 +1,82 @@ +# 35. Search Insert Position + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/search-insert-position/description/ + +> 内容描述 + +``` +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(N)******- 空间复杂度: O(1)****** + +找到第一个比```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 +``` + +> 思路 2 +******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)****** + +```python +class Solution(object): + def searchInsert(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) >> 1) + if nums[mid] < target: + l = mid + 1 + else: + r = mid - 1 + return l +``` + + +这题值得一提的随时将上面的移位变成一次移动2位,瞬间beats 100%,可能跟测试用例有关系吧,结果对应索引比较靠前 diff --git a/docs/leetcode/python/038._Count_and_Say.md b/docs/Leetcode_Solutions/Python/038._Count_and_Say.md similarity index 67% rename from docs/leetcode/python/038._Count_and_Say.md rename to docs/Leetcode_Solutions/Python/038._Count_and_Say.md index c735ca188..3076d72e3 100644 --- a/docs/leetcode/python/038._Count_and_Say.md +++ b/docs/Leetcode_Solutions/Python/038._Count_and_Say.md @@ -1,15 +1,44 @@ -### 38. Count and Say +# 38. Count and Say -题目: - +**难度: Easy** +## 刷题内容 -难度: +> 原题连接 -Easy +* https://leetcode.com/problems/count-and-say/description/ +> 内容描述 -思路 +``` + +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, 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" +``` + +## 解题方案 + +> 思路 1 1. i代表字符下标,从0开始取值,也就是从第一个字符开始,因为要让i取到最后一个字符,并且后面还要进行i+1的操作,所以将原字符串随意加上一个‘*’字符防止溢出 @@ -34,8 +63,8 @@ Examples of nth sequence 10. 13211311123113112211 ``` + ```python -解法1 class Solution(object): def countAndSay(self, n): """ @@ -54,8 +83,10 @@ class Solution(object): count = 1 return res ``` + +> 思路 2 + ```python -解法2 class Solution(object): def countAndSay(self, n): """ @@ -67,32 +98,10 @@ class Solution(object): 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/leetcode/python/039._combination_sum.md b/docs/Leetcode_Solutions/Python/039._combination_sum.md similarity index 100% rename from docs/leetcode/python/039._combination_sum.md rename to docs/Leetcode_Solutions/Python/039._combination_sum.md diff --git a/docs/leetcode/python/040._combination_sum_ii.md b/docs/Leetcode_Solutions/Python/040._combination_sum_ii.md similarity index 100% rename from docs/leetcode/python/040._combination_sum_ii.md rename to docs/Leetcode_Solutions/Python/040._combination_sum_ii.md diff --git a/docs/leetcode/python/041._First_Missing_Positive.md b/docs/Leetcode_Solutions/Python/041._First_Missing_Positive.md similarity index 52% rename from docs/leetcode/python/041._First_Missing_Positive.md rename to docs/Leetcode_Solutions/Python/041._First_Missing_Positive.md index 5d1a3a05c..70c764a31 100644 --- a/docs/leetcode/python/041._First_Missing_Positive.md +++ b/docs/Leetcode_Solutions/Python/041._First_Missing_Positive.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/first-missing-positive +* https://leetcode.com/problems/first-missing-positive/description/ > 内容描述 @@ -32,6 +32,7 @@ Your algorithm should run in O(n) time and uses constant extra space. ## 解题方案 > 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(1)****** 题目要求O(n)时间和O(1)空间,所以我们知道先排序再循环找是不行的 @@ -65,6 +66,7 @@ class Solution(object): ``` > 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** 如果不限制空间的话,我们用一个dict就可以解决, 时间是O(N) @@ -81,10 +83,43 @@ class Solution(object): lookup = {} for i in nums: lookup[i] = 1 - for i in range(1, max(nums)+2): + for i in range(1, len(nums)+2): if i not in lookup: return i ``` +> 思路 3 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +参考[eeetcoders@gmail.com](https://leetcode.com/problems/first-missing-positive/discuss/158842/Python-O(1)-Space-O(N)-Time) +先把所有的数字都放到该放的地方去,最后来一个for循环看哪个位置上没有对应的数字,就返回那个数字 + +- 1st sweep through the array and swap the number to its appropriate index (i.e 3 should go to index 3 - 1 = 2) + - Ignore the useless numbers such as duplicates, negatives or 0 and place them at the end of the array + - How to do this is similar to https://leetcode.com/problems/move-zeroes/description/ +- 2nd sweep check if the number is at the appropriate index (i.e at index 2 nums[i] should be 3) + - if not return i + 1 +- Edge case when all the numbers are in the appropriate indices then return n + 1 + +```python +class Solution(object): + def firstMissingPositive(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums or len(nums) == 0: + return 1 + + for i in range(len(nums)): + # swap nums[i] to i - 1 then use nums[i - 1] as new target to swap + while nums[i] > 0 and nums[i] <= len(nums) and nums[nums[i]-1] != nums[i]: + nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1] + for i in range(len(nums)): + if nums[i] != i + 1: + return i + 1 + return len(nums) + 1 +``` + diff --git a/docs/leetcode/python/042._trapping_rain_water.md b/docs/Leetcode_Solutions/Python/042._trapping_rain_water.md similarity index 100% rename from docs/leetcode/python/042._trapping_rain_water.md rename to docs/Leetcode_Solutions/Python/042._trapping_rain_water.md diff --git a/docs/leetcode/python/043._multiply_strings.md b/docs/Leetcode_Solutions/Python/043._multiply_strings.md similarity index 52% rename from docs/leetcode/python/043._multiply_strings.md rename to docs/Leetcode_Solutions/Python/043._multiply_strings.md index bd2c6a2e0..cede77572 100644 --- a/docs/leetcode/python/043._multiply_strings.md +++ b/docs/Leetcode_Solutions/Python/043._multiply_strings.md @@ -1,11 +1,60 @@ # 43. Multiply Strings 字符串相乘 +**难度: Medium** + ## 刷题内容 -* https://leetcode.com/problems/multiply-strings -* https://leetcode-cn.com/problems/multiply-strings +> 原题连接 + +* https://leetcode.com/problems/multiply-strings/> +* https://leetcode-cn.com/problems/multiply-strings/description/ + +> 内容描述 + +``` +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: -## 难度: Medium +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 + + +直接一位一位的搞,最后转string, 但是考虑到这样kennel最后str2int(num1) * str2int(num2)是一个极大的数字可能会导致溢出,所以有了后面的思路2 + +```python +class Solution(object): + def multiply(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)) +``` + +> 思路 2 参考了别人的思路: @@ -15,7 +64,6 @@ 2. 先将字符串逆序便于从最低位开始计算。 - ```python class Solution(object): def multiply(self, num1, num2): @@ -52,3 +100,4 @@ res = [1,8,2,8] 要注意最终返回头部可能会有‘0’,所以我们用lstrip去除一下 ``` + diff --git a/docs/leetcode/python/044._wildcard_matching.md b/docs/Leetcode_Solutions/Python/044._wildcard_matching.md similarity index 100% rename from docs/leetcode/python/044._wildcard_matching.md rename to docs/Leetcode_Solutions/Python/044._wildcard_matching.md diff --git a/docs/leetcode/python/045._Jump_Game_II.md b/docs/Leetcode_Solutions/Python/045._Jump_Game_II.md similarity index 100% rename from docs/leetcode/python/045._Jump_Game_II.md rename to docs/Leetcode_Solutions/Python/045._Jump_Game_II.md diff --git a/docs/Leetcode_Solutions/Python/046._permutations.md b/docs/Leetcode_Solutions/Python/046._permutations.md new file mode 100644 index 000000000..083376946 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/046._permutations.md @@ -0,0 +1,60 @@ +# 46. Permutations + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/permutations/description/ + +> 内容描述 + +``` +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!)******- 空间复杂度: O(N)****** + + +每次取一个作为prefix, 剩下的继续做permutation,然后连接起来加入res中 + +beats 87.18% + +```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 +``` + + diff --git a/docs/leetcode/python/047._permutations_ii.md b/docs/Leetcode_Solutions/Python/047._permutations_ii.md similarity index 100% rename from docs/leetcode/python/047._permutations_ii.md rename to docs/Leetcode_Solutions/Python/047._permutations_ii.md diff --git a/docs/leetcode/python/048._rotate_image.md b/docs/Leetcode_Solutions/Python/048._rotate_image.md similarity index 100% rename from docs/leetcode/python/048._rotate_image.md rename to docs/Leetcode_Solutions/Python/048._rotate_image.md diff --git a/docs/Leetcode_Solutions/Python/049._group_anagrams.md b/docs/Leetcode_Solutions/Python/049._group_anagrams.md new file mode 100644 index 000000000..02fd269c1 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/049._group_anagrams.md @@ -0,0 +1,52 @@ +# 49. Group Anagrams + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/group-anagrams/description/ + +> 内容描述 + +``` +Given an array of strings, group anagrams together. + +Example: + +Input: ["eat", "tea", "tan", "ate", "nat", "bat"], +Output: +[ + ["ate","eat","tea"], + ["nat","tan"], + ["bat"] +] +Note: + +All inputs will be in lowercase. +The order of your output does not matter. +``` + +## 解题方案 + +> 思路 1 + +每一个字符串都先排个序看看是不是一样,这样更好判断 + +```python +class Solution(object): + def groupAnagrams(self, strs): + """ + :type strs: List[str] + :rtype: List[List[str]] + """ + mapx = {} + for i in strs: + tmp = ''.join(sorted(list(i))) + if tmp in mapx: + mapx[tmp].append(i) + else: + mapx[tmp] = [i] + return mapx.values() +``` diff --git a/docs/Leetcode_Solutions/Python/050._pow(x,_n).md b/docs/Leetcode_Solutions/Python/050._pow(x,_n).md new file mode 100644 index 000000000..4854a5942 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/050._pow(x,_n).md @@ -0,0 +1,82 @@ +# 50. Pow(x, n) + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/powx-n/description/ + +> 内容描述 + +``` +Implement 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 [−231, 231 − 1] +``` + +## 解题方案 + +> 思路 1 + +Recursive, beats 100% + +```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 & 1: # n 为 奇数 + return x * self.myPow(x*x, n>>1) + else: + return self.myPow(x*x, n>>1) +``` + +> 思路 2 + +iterative + + +```python +class Solution(object): + def myPow(self, x, n): + """ + :type x: float + :type n: int + :rtype: float + """ + if n < 0: + x = 1 / x + n = -n + res = 1 + while n: + if n & 1: + res *= x + x *= x + n >>= 1 + return res +``` diff --git a/docs/Leetcode_Solutions/Python/051._n-queens.md b/docs/Leetcode_Solutions/Python/051._n-queens.md new file mode 100644 index 000000000..d4c8325ba --- /dev/null +++ b/docs/Leetcode_Solutions/Python/051._n-queens.md @@ -0,0 +1,74 @@ +# 51. N-Queens + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/n-queens/description/ + +> 内容描述 + +``` +The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other. +``` +![](https://github.com/apachecn/awesome-leetcode/blob/master/images/N-Queens.png) + + +``` +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(N^2)******- 空间复杂度: O(N)****** + +八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解[1]。 + +对于任意(x,y),如果要让新的点和它不能处于同一条横行、纵行或斜线上,则新点(p,q)必须要满足p+q != x+y 和p-q!= x-y, 前者针对左下右上斜线,后者针对左上右下斜线,两者同时都保证了不在同一条横行和纵行上。 + +代码中变量的含义: +- cols_lst: 每一行皇后的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(cols_lst, xy_diff, xy_sum): + cur_row = len(cols_lst) + if cur_row == n: + ress.append(cols_lst) + for col in range(n): + if col not in cols_lst and cur_row - col not in xy_diff and cur_row + col not in xy_sum: + dfs(cols_lst+[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/leetcode/python/052._n-queens_ii.md b/docs/Leetcode_Solutions/Python/052._n-queens_ii.md similarity index 100% rename from docs/leetcode/python/052._n-queens_ii.md rename to docs/Leetcode_Solutions/Python/052._n-queens_ii.md diff --git a/docs/leetcode/python/053._maximum_subarray.md b/docs/Leetcode_Solutions/Python/053._maximum_subarray.md similarity index 92% rename from docs/leetcode/python/053._maximum_subarray.md rename to docs/Leetcode_Solutions/Python/053._maximum_subarray.md index 5cfbacf7f..c2cb4ca0d 100644 --- a/docs/leetcode/python/053._maximum_subarray.md +++ b/docs/Leetcode_Solutions/Python/053._maximum_subarray.md @@ -7,7 +7,7 @@ > 原题连接 * https://leetcode.com/problems/maximum-subarray -* https://leetcode-cn.com/problems/maximum-subarray +* https://leetcode-cn.com/problems/maximum-subarray/description > 内容描述 @@ -99,15 +99,14 @@ class Solution(object): :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 + max_sum, max_end = nums[0], nums[0] + for i in range(1, len(nums)): + max_end = max(max_end + nums[i], nums[i]) + max_sum = max(max_sum, max_end) + return max_sum ``` + > 思路 4 参见clrs 第71页,用divide and conquer,有伪码 diff --git a/docs/leetcode/python/054._spiral_matrix.md b/docs/Leetcode_Solutions/Python/054._spiral_matrix.md similarity index 100% rename from docs/leetcode/python/054._spiral_matrix.md rename to docs/Leetcode_Solutions/Python/054._spiral_matrix.md diff --git a/docs/leetcode/python/055._jump_game.md b/docs/Leetcode_Solutions/Python/055._jump_game.md similarity index 100% rename from docs/leetcode/python/055._jump_game.md rename to docs/Leetcode_Solutions/Python/055._jump_game.md diff --git a/docs/Leetcode_Solutions/Python/056._Merge_Intervals.md b/docs/Leetcode_Solutions/Python/056._Merge_Intervals.md new file mode 100644 index 000000000..8a0ab4d90 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/056._Merge_Intervals.md @@ -0,0 +1,51 @@ +# 56. Merge Intervals + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/merge-intervals/description/ + +> 内容描述 + +``` +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 considerred overlapping. +``` + +## 解题方案 + +> 思路 1 + +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 x: x.start): + if res and i.start <= res[-1].end: + res[-1].end = max(res[-1].end, i.end) + else: + res.append(i) + return res +``` + + diff --git a/docs/leetcode/python/058._length_of_last_word.md b/docs/Leetcode_Solutions/Python/058._length_of_last_word.md similarity index 100% rename from docs/leetcode/python/058._length_of_last_word.md rename to docs/Leetcode_Solutions/Python/058._length_of_last_word.md diff --git a/docs/leetcode/python/059._spiral_matrix_ii.md b/docs/Leetcode_Solutions/Python/059._spiral_matrix_ii.md similarity index 100% rename from docs/leetcode/python/059._spiral_matrix_ii.md rename to docs/Leetcode_Solutions/Python/059._spiral_matrix_ii.md diff --git a/docs/Leetcode_Solutions/Python/060._permutation_sequence.md b/docs/Leetcode_Solutions/Python/060._permutation_sequence.md new file mode 100644 index 000000000..d67e9dfcf --- /dev/null +++ b/docs/Leetcode_Solutions/Python/060._permutation_sequence.md @@ -0,0 +1,193 @@ +# 60. Permutation Sequence + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/permutation-sequence/description/ + +> 内容描述 + +``` +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 + + +当然是暴力直接算出所有的排列然后取第k个,但是会超时 + +``` +class Solution(object): + def getPermutation(self, n, k): + """ + :type n: int + :type k: int + :rtype: str + """ + s = ''.join([str(i) for i in range(1, n+1)]) + print(s) + def permunation(s): + if len(s) == 0: + return + if len(s) == 1: + return [s] + res = [] + for i in range(len(s)): + x = s[i] + xs = s[:i] + s[i+1:] + for j in permunation(xs): + res.append(x+j) + return res + return permunation(s)[k-1] +``` + +> 思路 2 + +参考大神[tso](https://leetcode.com/problems/permutation-sequence/discuss/22507/%22Explain-like-I'm-five%22-Java-Solution-in-O(n))的思路 + +``` +I'm sure somewhere can be simplified so it'd be nice if anyone can let me know. The pattern was that: + +say n = 4, you have {1, 2, 3, 4} + +If you were to list out all the permutations you have + +1 + (permutations of 2, 3, 4) + +2 + (permutations of 1, 3, 4) + +3 + (permutations of 1, 2, 4) + +4 + (permutations of 1, 2, 3) + + +We know how to calculate the number of permutations of n numbers... n! So each of those with permutations of 3 numbers means there are 6 possible permutations. Meaning there would be a total of 24 permutations in this particular one. So if you were to look for the (k = 14) 14th permutation, it would be in the + +3 + (permutations of 1, 2, 4) subset. + +To programmatically get that, you take k = 13 (subtract 1 because of things always starting at 0) and divide that by the 6 we got from the factorial, which would give you the index of the number you want. In the array {1, 2, 3, 4}, k/(n-1)! = 13/(4-1)! = 13/3! = 13/6 = 2. The array {1, 2, 3, 4} has a value of 3 at index 2. So the first number is a 3. + +Then the problem repeats with less numbers. + +The permutations of {1, 2, 4} would be: + +1 + (permutations of 2, 4) + +2 + (permutations of 1, 4) + +4 + (permutations of 1, 2) + +But our k is no longer the 14th, because in the previous step, we've already eliminated the 12 4-number permutations starting with 1 and 2. So you subtract 12 from k.. which gives you 1. Programmatically that would be... + +k = k - (index from previous) * (n-1)! = k - 2*(n-1)! = 13 - 2*(3)! = 1 + +In this second step, permutations of 2 numbers has only 2 possibilities, meaning each of the three permutations listed above a has two possibilities, giving a total of 6. We're looking for the first one, so that would be in the 1 + (permutations of 2, 4) subset. + +Meaning: index to get number from is k / (n - 2)! = 1 / (4-2)! = 1 / 2! = 0.. from {1, 2, 4}, index 0 is 1 + + +so the numbers we have so far is 3, 1... and then repeating without explanations. + + +{2, 4} + +k = k - (index from pervious) * (n-2)! = k - 0 * (n - 2)! = 1 - 0 = 1; + +third number's index = k / (n - 3)! = 1 / (4-3)! = 1/ 1! = 1... from {2, 4}, index 1 has 4 + +Third number is 4 + + +{2} + +k = k - (index from pervious) * (n - 3)! = k - 1 * (4 - 3)! = 1 - 1 = 0; + +third number's index = k / (n - 4)! = 0 / (4-4)! = 0/ 1 = 0... from {2}, index 0 has 2 + +Fourth number is 2 + + +Giving us 3142. If you manually list out the permutations using DFS method, it would be 3142. Done! It really was all about pattern finding. +``` + +```python +class Solution(object): + def getPermutation(self, n, k): + """ + :type n: int + :type k: int + :rtype: str + """ + res = '' + + factorial = [1] * (n+1) + # factorial[] = [1, 1, 2, 6, 24, ... n!] + for i in range(1, n+1): + factorial[i] = factorial[i-1] * i + + # create a list of numbers to get indices + nums = [i for i in range(1, n+1)] + # because we start from index 0 + k -= 1 + + for i in range(1, n+1): + # this is the idx of first num each time we will get + idx = k / factorial[n-i] + res += str(nums[idx]) + # delete this num, since we have got it + nums.pop(idx) + # update k + k -= idx * factorial[n-i] + return res +``` +或者空间复杂度更低一点 + +```python +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 range(n)[::-1]: + curr = perm[k/fact] + seq += str(curr) + perm.remove(curr) + if i > 0: + k %= fact + fact /= i + return seq +``` + + diff --git a/docs/leetcode/python/061._rotate_list.md b/docs/Leetcode_Solutions/Python/061._rotate_list.md similarity index 100% rename from docs/leetcode/python/061._rotate_list.md rename to docs/Leetcode_Solutions/Python/061._rotate_list.md diff --git a/docs/leetcode/python/062._unique_paths.md b/docs/Leetcode_Solutions/Python/062._unique_paths.md similarity index 94% rename from docs/leetcode/python/062._unique_paths.md rename to docs/Leetcode_Solutions/Python/062._unique_paths.md index 75a7edc52..759ada816 100644 --- a/docs/leetcode/python/062._unique_paths.md +++ b/docs/Leetcode_Solutions/Python/062._unique_paths.md @@ -7,7 +7,7 @@ > 原题连接 * https://leetcode.com/problems/unique-paths -* https://leetcode-cn.com/problems/unique-paths +* https://leetcode-cn.com/problems/unique-paths/description > 内容描述 @@ -19,7 +19,7 @@ 问总共有多少条不同的路径? ``` -![](https://leetcode-cn.com/img/problemset/robot_maze.png) +![](https://leetcode-cn.com/static/images/problemset/robot_maze.png) ``` 例如,上图是一个7 x 3 的网格。有多少可能的路径? diff --git a/docs/leetcode/python/065.unique_paths_ii.md b/docs/Leetcode_Solutions/Python/063.unique_paths_ii.md similarity index 98% rename from docs/leetcode/python/065.unique_paths_ii.md rename to docs/Leetcode_Solutions/Python/063.unique_paths_ii.md index 16e8e940c..6c16b47bd 100644 --- a/docs/leetcode/python/065.unique_paths_ii.md +++ b/docs/Leetcode_Solutions/Python/063.unique_paths_ii.md @@ -1,4 +1,4 @@ - ###65.Unique Paths II + ###63.Unique Paths II 题目: diff --git a/docs/leetcode/python/064._minimum_path_sum.md b/docs/Leetcode_Solutions/Python/064._minimum_path_sum.md similarity index 95% rename from docs/leetcode/python/064._minimum_path_sum.md rename to docs/Leetcode_Solutions/Python/064._minimum_path_sum.md index 8e801f567..fe89255e5 100644 --- a/docs/leetcode/python/064._minimum_path_sum.md +++ b/docs/Leetcode_Solutions/Python/064._minimum_path_sum.md @@ -7,7 +7,7 @@ > 原题连接 * https://leetcode.com/problems/minimum-path-sum -* https://leetcode-cn.com/problems/minimum-path-sum +* https://leetcode-cn.com/problems/minimum-path-sum/description > 内容描述 diff --git a/docs/leetcode/python/066._plus_one.md b/docs/Leetcode_Solutions/Python/066._plus_one.md similarity index 100% rename from docs/leetcode/python/066._plus_one.md rename to docs/Leetcode_Solutions/Python/066._plus_one.md diff --git a/docs/Leetcode_Solutions/Python/067._add_binary.md b/docs/Leetcode_Solutions/Python/067._add_binary.md new file mode 100644 index 000000000..811c04d17 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/067._add_binary.md @@ -0,0 +1,53 @@ +# 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 + +几种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 + if 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/leetcode/python/069._sqrt(x).md b/docs/Leetcode_Solutions/Python/069._sqrt(x).md similarity index 53% rename from docs/leetcode/python/069._sqrt(x).md rename to docs/Leetcode_Solutions/Python/069._sqrt(x).md index 70c28f6e2..f01be5105 100644 --- a/docs/leetcode/python/069._sqrt(x).md +++ b/docs/Leetcode_Solutions/Python/069._sqrt(x).md @@ -1,16 +1,37 @@ -### 69. Sqrt(x) +# 69. Sqrt(x) +**难度: Easy** -题目: - +## 刷题内容 +> 原题连接 -难度: +* https://leetcode.com/problems/sqrtx/description/ -Medium +> 内容描述 +``` +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 一看,觉得很容易,一写,超时: @@ -30,7 +51,9 @@ class Solution(object): i += 1 ``` -看一眼tag, binary search,难道从x/2之类的开始搜起来?话说还想到求sqrt有个🐂的牛顿法? +> 思路 2 + +看一眼tag, binary search,难道从x/2之类的开始搜起来? 莫名其妙过了的代码: @@ -41,20 +64,24 @@ class Solution(object): :type x: int :rtype: int """ - if x == 1 : return 1 - if x == 0 : return 0 - l, r = 0, x - 1 + if x == 0: + return 0 + if x == 1: + return 1 + 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 + mid = l + ((r-l) >> 1) + if mid * mid <= x and (mid+1) * (mid+1) > x: + return mid + elif mid * mid > x: + r = mid - 1 # 这里也可以 r = mid + else: + l = mid + 1 ``` +> 思路 3 + +跟思路 2 一样,就是return时机不一样 -或者 ```python class Solution(object): def mySqrt(self, x): @@ -77,13 +104,12 @@ class Solution(object): l = mid + 1 return r ``` +> 思路 4 +话说还想到求sqrt有个🐂的牛顿法? +[牛顿法 wiki](https://zh.wikipedia.org/wiki/牛顿法) -牛顿法 - -参见wikipedia,to be done:自己推导一遍 - ```python @@ -97,5 +123,4 @@ class Solution(object): while abs(res * res - x) > 0.1: res = (res + x / res) / 2 return int(res) - ``` diff --git a/docs/leetcode/python/070._Climbing_Stairs.md b/docs/Leetcode_Solutions/Python/070._Climbing_Stairs.md similarity index 73% rename from docs/leetcode/python/070._Climbing_Stairs.md rename to docs/Leetcode_Solutions/Python/070._Climbing_Stairs.md index 5c7ce3077..872a1dd77 100644 --- a/docs/leetcode/python/070._Climbing_Stairs.md +++ b/docs/Leetcode_Solutions/Python/070._Climbing_Stairs.md @@ -1,14 +1,43 @@ -### 70. Climbing Stairs +# 70. Climbing Stairs +**难度: Easy** -题目: - +## 刷题内容 +> 原题连接 -难度: -Easy +* https://leetcode.com/problems/climbing-stairs/description/ -思路: +> 内容描述 + +``` + +You are climbing a stair case. It takes n steps to reach to the top. + +Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? + +Note: Given n will be a positive integer. + +Example 1: + +Input: 2 +Output: 2 +Explanation: There are two ways to climb to the top. +1. 1 step + 1 step +2. 2 steps +Example 2: + +Input: 3 +Output: 3 +Explanation: There are three ways to climb to the top. +1. 1 step + 1 step + 1 step +2. 1 step + 2 steps +3. 2 steps + 1 step +``` + +## 解题方案 + +> 思路 1 Fibonacci 的DP版本 @@ -30,9 +59,9 @@ def memorize_fib(n): # n为第几个Fibonacci数 memo[n] = memorize_fib(n-1) + memorize_fib(n-2) return memo[n] -print(memorize_fib(4)) +print(memorize_fib(4)) # 输出3 ``` -输出```3``` + - bottom up(tabulation) @@ -47,9 +76,9 @@ def tabulation_fib(n): # n为第几个Fibonacci数 fib[0], fib[1] = fib[1], fib[2] return fib[2] -print(tabulation_fib(4)) +print(tabulation_fib(4)) # 输出3 ``` -输出```3``` + 这里memo用dict,用array也一样。当然用bottom up还有一点,可以只存每次最后两个数,可以save space.,这样就只用到constant space. @@ -75,9 +104,12 @@ class Solution(object): - Time complexity : O(n) - Space complexity : O(1). Constant space is used. + +> 思路 2 + 另外还有一个公式法: -![](/img/Algorithm/LeetCode/41512784914_.pic.jpg) +![](https://github.com/Lisanaaa/myTODOs/blob/master/41512784914_.pic.jpg) 由于这里面相当于```standard Fibonacci```函数向前进了一步,排列为1,2,3,5而非原本的1,1,2,3,所以代码中使用```n+1``` ```python diff --git a/docs/leetcode/python/072._edit_distance.md b/docs/Leetcode_Solutions/Python/072._edit_distance.md similarity index 68% rename from docs/leetcode/python/072._edit_distance.md rename to docs/Leetcode_Solutions/Python/072._edit_distance.md index 3a502d081..75291042c 100644 --- a/docs/leetcode/python/072._edit_distance.md +++ b/docs/Leetcode_Solutions/Python/072._edit_distance.md @@ -1,12 +1,47 @@ -### 72. Edit Distance +# 72. Edit Distance -题目: - +**难度: Hard** +## 刷题内容 -难度: +> 原题连接 -Hard +* https://leetcode.com/problems/edit-distance/description/ + +> 内容描述 + +``` +Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2. + +You have the following 3 operations permitted on a word: + +Insert a character +Delete a character +Replace a character +Example 1: + +Input: word1 = "horse", word2 = "ros" +Output: 3 +Explanation: +horse -> rorse (replace 'h' with 'r') +rorse -> rose (remove 'r') +rose -> ros (remove 'e') +Example 2: + +Input: word1 = "intention", word2 = "execution" +Output: 5 +Explanation: +intention -> inention (remove 't') +inention -> enention (replace 'i' with 'e') +enention -> exention (replace 'n' with 'x') +exention -> exection (replace 'n' with 'c') +exection -> execution (insert 'u') +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(len(word1)*len(word2))******- 空间复杂度: O(len(word1)*len(word2))****** 可以做的操作: @@ -48,39 +83,7 @@ Hard ***要始终明确一点,```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] -``` 对应的例子表格图 @@ -109,10 +112,20 @@ class Solution(object): """ 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)] + # 这里第一行第一列初始值一定要为i+j,因为当另一个单词为空的时候很明显至少需要i或者j次edit + 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] ``` + +或者你愿意麻烦,可以这样初始化dp矩阵 + +``` +dp = [[0 for j in range(len(word2)+1)] for i in range(len(word1)+1)] +dp[0] = [i for i in range(len(word2)+1)] +for i in range(len(word1)+1): + dp[i][0] = i +``` diff --git a/docs/leetcode/python/073._Set_Matrix_Zeroes.md b/docs/Leetcode_Solutions/Python/073. Set Matrix Zeroes.md similarity index 100% rename from docs/leetcode/python/073._Set_Matrix_Zeroes.md rename to docs/Leetcode_Solutions/Python/073. Set Matrix Zeroes.md diff --git a/docs/leetcode/python/074._search_a_2d_matrix.md b/docs/Leetcode_Solutions/Python/074._search_a_2d_matrix.md similarity index 100% rename from docs/leetcode/python/074._search_a_2d_matrix.md rename to docs/Leetcode_Solutions/Python/074._search_a_2d_matrix.md diff --git a/docs/leetcode/python/075._sort_colors.md b/docs/Leetcode_Solutions/Python/075._sort_colors.md similarity index 98% rename from docs/leetcode/python/075._sort_colors.md rename to docs/Leetcode_Solutions/Python/075._sort_colors.md index 7605e298d..8e6a628c6 100644 --- a/docs/leetcode/python/075._sort_colors.md +++ b/docs/Leetcode_Solutions/Python/075._sort_colors.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/sort-colors +* https://leetcode.com/problems/sort-colors/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/076._Minimum_Window_Substring.md b/docs/Leetcode_Solutions/Python/076._Minimum_Window_Substring.md new file mode 100644 index 000000000..a31e09202 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/076._Minimum_Window_Substring.md @@ -0,0 +1,77 @@ +# 76. Minimum Window Substring + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/minimum-window-substring/description/ + +> 内容描述 + +``` +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. +``` + +## 解题方案 + +> 思路 1 + + +[模板大法好](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/Summarization/slide_windows_template.md), + + +- 首先搞几个corner case +- 开始步入正题,我们脑子里面必须要有一个window的概念,只要这个window的end小于len(s),就一直搞下去 +- 记录一下t中字符和其频率,然后随着end的变大不停更新这个maps,即出现一个字符,如果该字符在maps里面,我们就对应的自减一下这个字符在maps中的频率 +- 用一个counter记录这个maps里面频率不为0的字符个数,即key个数,当counter为0的时候我们就知道t中所以的字符都在我们的window里面了 +- 这个时候,我们就可以开始自增begin了,然后只要仍然可以保持counter为0(即所有字符都还在window里面),我们就一直移动begin以减小window的size +- 当最后while end < len(s)循环出来的时候,我们判断一下我们的window的length是不是变化了(最开始设置了inf最大值),如果变化了说明我们找到了符合要求的window,否则没有 + + + +```python +class Solution(object): + def minWindow(self, s, t): + """ + :type s: str + :type t: str + :rtype: str + """ + if len(t) > len(s): + return '' + if s == '' or t == '': + 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/leetcode/python/077._combinations.md b/docs/Leetcode_Solutions/Python/077._combinations.md similarity index 100% rename from docs/leetcode/python/077._combinations.md rename to docs/Leetcode_Solutions/Python/077._combinations.md diff --git a/docs/leetcode/python/078._Subsets.md b/docs/Leetcode_Solutions/Python/078._Subsets.md similarity index 85% rename from docs/leetcode/python/078._Subsets.md rename to docs/Leetcode_Solutions/Python/078._Subsets.md index 307e6a8dc..6fc756dbe 100644 --- a/docs/leetcode/python/078._Subsets.md +++ b/docs/Leetcode_Solutions/Python/078._Subsets.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/subsets +* https://leetcode.com/problems/subsets/description/ > 内容描述 @@ -65,16 +65,15 @@ class Solution(object): :type nums: List[int] :rtype: List[List[int]] """ - nums.sort() res = [] - def search(cur_lst, idx): + def search(tmp_res, idx): if idx == len(nums): - res.append(cur_lst) - return - search(cur_lst + [nums[idx]], idx + 1) - search(cur_lst, idx + 1) - + res.append(tmp_res) + else: + search(tmp_res+[nums[idx]], idx+1) + search(tmp_res, idx+1) + search([], 0) return res ``` @@ -91,7 +90,6 @@ class Solution(object): :type nums: List[int] :rtype: List[List[int]] """ - nums.sort() res = [] def dfs(depth, start, lst): res.append(lst) diff --git a/docs/Leetcode_Solutions/Python/079._word_search.md b/docs/Leetcode_Solutions/Python/079._word_search.md new file mode 100644 index 000000000..1b88d3c7b --- /dev/null +++ b/docs/Leetcode_Solutions/Python/079._word_search.md @@ -0,0 +1,77 @@ +# 79. Word Search + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/word-search/description/ + +> 内容描述 + +``` +Given a 2D board and a word, find if the word exists in the grid. + +The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once. + +Example: + +board = +[ + ['A','B','C','E'], + ['S','F','C','S'], + ['A','D','E','E'] +] + +Given word = "ABCCED", return true. +Given word = "SEE", return true. +Given word = "ABCB", return false. +``` + +## 解题方案 + +> 思路 1 + +其实这个题和number of islands类似,是backtracking基本功的考查,但是基本功非常有待提高||| + +比较核心的是dfs函数,然后这个函数有取巧的写法:如果outside of boundary就return False + +loop, 如果碰到跟word开头的字母一样,把这个扔进去loop,可以考查这个char在这个board的上下左右是否可以选择,补课使用则重置used, 然后return + +也还是之前摘录的,backtrack写法关键: 选择 (Options),限制 (Restraints),结束条件 (Termination)。 + + +```python +class Solution(object): + def exist(self, board, word): + """ + :type board: List[List[str]] + :type word: str + :rtype: bool + """ + if not board: + return False + + row = len(board) + col = len(board[0]) if row else 0 + + if row == 0: + return False + if row != 0 and col == 0: + return False + if not word or word == '': + return True + + def dfs(i, j, idx): + if i < 0 or j < 0 or i > row-1 or j > col-1 or board[i][j] != word[idx]: + return False + if idx == len(word) - 1: + return True + board[i][j] = '*' # mark as visited + res = dfs(i+1, j, idx+1) or dfs(i, j+1, idx+1) or dfs(i-1, j, idx+1) or dfs(i, j-1, idx+1) + board[i][j] = word[idx] # backtrack + return res + + return any(dfs(i, j, 0) for i in range(row) for j in range(col)) +``` diff --git a/docs/leetcode/python/082._remove_duplicates_from_sorted_list_ii.md b/docs/Leetcode_Solutions/Python/082._remove_duplicates_from_sorted_list_ii.md similarity index 100% rename from docs/leetcode/python/082._remove_duplicates_from_sorted_list_ii.md rename to docs/Leetcode_Solutions/Python/082._remove_duplicates_from_sorted_list_ii.md diff --git a/docs/leetcode/python/083._remove_duplicates_from_sorted_list.md b/docs/Leetcode_Solutions/Python/083._remove_duplicates_from_sorted_list.md similarity index 100% rename from docs/leetcode/python/083._remove_duplicates_from_sorted_list.md rename to docs/Leetcode_Solutions/Python/083._remove_duplicates_from_sorted_list.md diff --git a/docs/Leetcode_Solutions/Python/084._Largest_Rectangle_in_Histogram.md b/docs/Leetcode_Solutions/Python/084._Largest_Rectangle_in_Histogram.md new file mode 100644 index 000000000..f1a9bd05d --- /dev/null +++ b/docs/Leetcode_Solutions/Python/084._Largest_Rectangle_in_Histogram.md @@ -0,0 +1,100 @@ +# 84. Largest Rectangle in Histogram + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/largest-rectangle-in-histogram/description/ + +> 内容描述 + +``` +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. +``` +![](https://github.com/apachecn/LeetCode/blob/master/images/84/histogram1.png) + +Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]. + + + +![](https://github.com/apachecn/LeetCode/blob/master/images/84/histogram_area1.png) + +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 + + +参考大神[learnjava](https://leetcode.com/problems/largest-rectangle-in-histogram/discuss/158050/same-pattern-for-problem-84-496-503-and-739)的解法 + +``` +All these problems share the same pattern: how to find the next greater/smaller element in an array. + +Problem 84: +For bar i in the heights array, if we can find the first smaller bar with index l on the left +and the first smaller bar with index r on the right, then the current max area with h(i) +as the height is h(i)*(r-l-1). So we just need to compare all these current max areas. +To find l for each bar, we can use one stack (see problem 496, 503 and 739); +similarly we can use another stack for r. +``` + + +```python +class Solution(object): + def largestRectangleArea(self, heights): + """ + :type heights: List[int] + :rtype: int + """ + left_stack, right_stack = [], [] + left_indexes, right_indexes = [-1] * len(heights), [len(heights)] * len(heights) + + for i in range(len(heights)): + while left_stack and heights[i] < heights[left_stack[-1]]: + right_indexes[left_stack.pop()] = i + left_stack.append(i) + + for i in range(len(heights)-1, -1, -1): + while right_stack and heights[i] < heights[right_stack[-1]]: + left_indexes[right_stack.pop()] = i + right_stack.append(i) + + res = 0 + for i in range(len(heights)): + area = heights[i] * (right_indexes[i] - left_indexes[i] - 1) + res = max(res, area) + return res +``` + +> 思路 2 + +```python +class Solution(object): + def largestRectangleArea(self, heights): + """ + :type heights: List[int] + :rtype: int + """ + heights.append(0) + area, stack = 0, [-1] + + for idx, height in enumerate(heights): + while height < heights[stack[-1]]: + h = heights[stack.pop()] + w = idx - stack[-1] - 1 + area = max(w*h, area) + stack.append(idx) + + return area +``` diff --git a/docs/Leetcode_Solutions/Python/085._Maximal_Rectangle.md b/docs/Leetcode_Solutions/Python/085._Maximal_Rectangle.md new file mode 100644 index 000000000..a1aaf9a1a --- /dev/null +++ b/docs/Leetcode_Solutions/Python/085._Maximal_Rectangle.md @@ -0,0 +1,107 @@ +# 85. Maximal Rectangle + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/maximal-rectangle/description/ + +> 内容描述 + +``` +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 + +参考大神[sikp](https://leetcode.com/problems/maximal-rectangle/discuss/122456/Easiest-solution-build-on-top-of-leetcode84)的解法 + +首先我们可以看看 leetcode 第84题,然后你就会发现,这道题可以直接使用84题的解法来做。 + +我们可以从matrix的第一行开始往下进行,然后每次都做出一个heights列表,找出当前的最大area,最终找到最后一行,可以得到最终的最大area。 + +伪代码可以这样写: + +``` +class Solution(object): + def maximalRectangle(self, matrix): + """ + :type matrix: List[List[str]] + :rtype: int + """ + if not matrix or not matrix[0]: + return 0 + # for each cell with value=1, we look upward (north), the number of continuous '1' is the height of cell + heights = [0] * len(matrix[0]) + res, cur_max_area = -1 + for i in range(len(matrix)): + for j in range(len(matrix[0])): + if matrix[i][j] == 0: + heights[j] = 0 + else: + heights[j] += 1 + cur_max_area = yourLeetCode84Funtion(heights) + res = max(cur_max_area, res) + return res +``` + + + + +最终代码就是: + +```python +class Solution(object): + def maximalRectangle(self, matrix): + """ + :type matrix: List[List[str]] + :rtype: int + """ + if not matrix or not matrix[0]: + return 0 + heights = [0] * len(matrix[0]) + area = 0 + for row in matrix: + for col_num, item in enumerate(row): + # for each cell with value=1, we look upward (north), the number of continuous '1' is the height of cell + heights[col_num] = heights[col_num] + 1 if item == '1' else 0 + area = max(area, self.largestRectangleArea(heights)) + print(heights) + return area + + + def largestRectangleArea(self, heights): + left_stack, right_stack = [], [] + left_indexes, right_indexes = [-1] * len(heights), [len(heights)] * len(heights) + + for i in range(len(heights)): + while left_stack and heights[i] < heights[left_stack[-1]]: + right_indexes[left_stack.pop()] = i + left_stack.append(i) + + for i in range(len(heights)-1, -1, -1): + while right_stack and heights[i] < heights[right_stack[-1]]: + left_indexes[right_stack.pop()] = i + right_stack.append(i) + + res = 0 + for i in range(len(heights)): + area = heights[i] * (right_indexes[i] - left_indexes[i] - 1) + res = max(res, area) + return res +``` diff --git a/docs/leetcode/python/086._partition_list.md b/docs/Leetcode_Solutions/Python/086._partition_list.md similarity index 100% rename from docs/leetcode/python/086._partition_list.md rename to docs/Leetcode_Solutions/Python/086._partition_list.md diff --git a/docs/leetcode/python/088._merge_sorted_array.md b/docs/Leetcode_Solutions/Python/088._merge_sorted_array.md similarity index 95% rename from docs/leetcode/python/088._merge_sorted_array.md rename to docs/Leetcode_Solutions/Python/088._merge_sorted_array.md index 2117ae223..d24fb9b32 100644 --- a/docs/leetcode/python/088._merge_sorted_array.md +++ b/docs/Leetcode_Solutions/Python/088._merge_sorted_array.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/merge-sorted-array +* https://leetcode.com/problems/merge-sorted-array/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/089._gray_code.md b/docs/Leetcode_Solutions/Python/089._gray_code.md new file mode 100644 index 000000000..c889837a4 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/089._gray_code.md @@ -0,0 +1,107 @@ +# 89. Gray Code + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/gray-code/description/ + +> 内容描述 + +``` +The gray code is a binary numeral system where two successive values differ in only one bit. + +Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0. + +Example 1: + +Input: 2 +Output: [0,1,3,2] +Explanation: +00 - 0 +01 - 1 +11 - 3 +10 - 2 + +For a given n, a gray code sequence may not be uniquely defined. +For example, [0,2,3,1] is also a valid gray code sequence. + +00 - 0 +10 - 2 +11 - 3 +01 - 1 +Example 2: + +Input: 0 +Output: [0] +Explanation: We define the gray code sequence to begin with 0. + A gray code sequence of n has size = 2n, which for n = 0 the size is 20 = 1. + Therefore, for n = 0 the gray code sequence is [0]. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(2^N)******- 空间复杂度: O(2^N)****** + +几分钟找到了规律,然后实现,AC了。 + +规律就是n从1开始,每次的结果都是三部分的叠加,part1就是n-1返回的值f(n-1),part2就是f(n-1)的前半部分每一个元素加上```3*pow(2, n-2)```, +part3就是f(n-1)的后半部分每一个元素加上```pow(2, n-2)``` + +``` + 3 1 6 6 2 2 12 12 12 12 4 4 4 4 (这一行就是要加上的数字) +0 1 3 2 6 7 5 4 12 13 15 14 10 11 9 8 +``` + +```python +class Solution(object): + def grayCode(self, n): + """ + :type n: int + :rtype: List[int] + """ + if n == 0: + return [0] + if n == 1: + return [0, 1] + part1 = self.grayCode(n-1) + part2 = [i + 3 * pow(2, n-2) for i in part1[:len(part1)//2]] + part3 = [i + pow(2, n-2) for i in part1[len(part1)//2:]] + return part1 + part2 + part3 +``` + +> 思路 2 +******- 时间复杂度: O(2^N)******- 空间复杂度: O(2^N)****** + +AC了以后好自豪哦,看了下 discuss,然后居然有这个东西,我一口老血,我宛若一个智障 + +``` +The main problem is we need to convert binary code B to Gray code G. +For the i th bit of binary code: +if i==0: G[i]=B[i] +else: G[i] = B[i] XOR B[i-1] + +The above part can be simply expressed by G = B^(B>>1). +``` + + + +服气,这个待研究 +``` +class Solution(object): + def grayCode(self, n): + """ + :type n: int + :rtype: List[int] + """ + res = [(i>>1)^i for i in range(pow(2,n))] + return res +``` + + + + + diff --git a/docs/leetcode/python/090._subsets_ii.md b/docs/Leetcode_Solutions/Python/090._subsets_ii.md similarity index 78% rename from docs/leetcode/python/090._subsets_ii.md rename to docs/Leetcode_Solutions/Python/090._subsets_ii.md index 5d7285397..584fe278f 100644 --- a/docs/leetcode/python/090._subsets_ii.md +++ b/docs/Leetcode_Solutions/Python/090._subsets_ii.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/subsets-ii +* https://leetcode.com/problems/subsets-ii/description/ > 内容描述 @@ -55,6 +55,8 @@ Output: ``` 自己的解法,这里最关键的就是先对nums进行了排序,保证了我们插入相同的数字时都是相邻的 + + ```python class Solution(object): def subsetsWithDup(self, nums): @@ -64,16 +66,35 @@ class Solution(object): """ 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]) + res.extend([tmp+[nums[i]] for tmp in res if tmp.count(nums[i]) == i - nums.index(nums[i])]) return res ``` > 思路 2 +其实我们也可以不sort,如果出现了重复数字,我们就只需要将其加到拥有最多的那个数字的列表中即可 +比如对于[2,1,2],在第二个2出现的时候,我们只需要对[[], [2], [1], [1,2]]中的[1,2]和[2]进行加个2的操作即可 + +其实换句话说就是之前出现了几次那个数字,现在只需要把这个数字加到拥有几个这个数字的列表中去,就像上面的[1,2]和[2]都出现了一次2,前面2也只出现了1次,所以对他们进行加个2操作就行了 + +```python +class Solution(object): + def subsetsWithDup(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + res = [[]] + + for i in range(len(nums)): + res.extend([tmp+[nums[i]] for tmp in res if tmp.count(nums[i]) == nums[:i].count(nums[i])]) + return res +``` + +> 思路 3 + 参考别人的 现在来观察规律,与之前有不同之处是我们需要一个位置来mark,因为不再需要往之前出现过的地方再加了,看这个: @@ -99,7 +120,7 @@ class Solution(object): return res ``` -> 思路 3 +> 思路 4 跟[leetcode第78题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/078._Subsets.md)一样,DFS, 只不过需要在dfs函数里加一个剪枝的条件,排除掉同样的子集。 @@ -126,7 +147,7 @@ class Solution(object): -> 思路 4 +> 思路 5 跟[leetcode第78题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/078._Subsets.md)一样,backtrack diff --git a/docs/leetcode/python/091._decode_ways.md b/docs/Leetcode_Solutions/Python/091._decode_ways.md similarity index 100% rename from docs/leetcode/python/091._decode_ways.md rename to docs/Leetcode_Solutions/Python/091._decode_ways.md diff --git a/docs/Leetcode_Solutions/Python/092._reverse_linked_list_ii.md b/docs/Leetcode_Solutions/Python/092._reverse_linked_list_ii.md new file mode 100644 index 000000000..35ffebe8d --- /dev/null +++ b/docs/Leetcode_Solutions/Python/092._reverse_linked_list_ii.md @@ -0,0 +1,111 @@ +# 92. Reverse Linked List II + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/reverse-linked-list-ii/description/ + +> 内容描述 + +``` +Reverse a linked list from position m to n. Do it in one-pass. + +Note: 1 ≤ m ≤ n ≤ length of list. + +Example: + +Input: 1->2->3->4->5->NULL, m = 2, n = 4 +Output: 1->4->3->2->5->NULL +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +难度: +Medium + + +跟 reverse linked list一样 + +思路: 找到 第 m 个node,然后开始reverse到第n个node,然后再把它们和原本的list连接起来 + +AC 代码 + +```python +class Solution(object): + def reverseBetween(self, head, m, n): + """ + :type head: ListNode + :type m: int + :type n: int + :rtype: ListNode + """ + if not head or m == n: + return head + node_m_before = dummy = ListNode(-1) + dummy.next = head + + for i in range(m-1): + node_m_before = node_m_before.next + + prev = None + cur = node_m_before.next + node_m = node_m_before.next + + for i in range(n-m+1): + nxt = cur.next + cur.next = prev + prev = cur + cur = nxt + + node_m_before.next = prev + node_m.next = cur + + return dummy.next +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +看了一下别人的代码,又比我写的好嘛,因为是保证m和n有效,用的是for循环先找到 m node: + +详细见[realisking](https://leetcode.com/problems/reverse-linked-list-ii/discuss/30709/Talk-is-cheap-show-me-the-code-(and-DRAWING)) +``` +for _ in range(m-1): + .... + +for _ in range(n-m): + reverse 操作 + +``` +```python +class Solution(object): + def reverseBetween(self, head, m, n): + """ + :type head: ListNode + :type m: int + :type n: int + :rtype: ListNode + """ + if not head or m == n: + return head + p = dummy = ListNode(None) + dummy.next = head + for i in range(m-1): + p = p.next + tail = p.next + + for i in range(n-m): + tmp = p.next + p.next = tail.next + tail.next = tail.next.next + p.next.next = tmp + return dummy.next +``` + diff --git a/docs/leetcode/python/093._restore_ip_addresses.md b/docs/Leetcode_Solutions/Python/093._restore_ip_addresses.md similarity index 100% rename from docs/leetcode/python/093._restore_ip_addresses.md rename to docs/Leetcode_Solutions/Python/093._restore_ip_addresses.md diff --git a/docs/leetcode/python/094._binary_tree_inorder_traversal.md b/docs/Leetcode_Solutions/Python/094._binary_tree_inorder_traversal.md similarity index 96% rename from docs/leetcode/python/094._binary_tree_inorder_traversal.md rename to docs/Leetcode_Solutions/Python/094._binary_tree_inorder_traversal.md index dc0f41f49..2b91f1ab8 100644 --- a/docs/leetcode/python/094._binary_tree_inorder_traversal.md +++ b/docs/Leetcode_Solutions/Python/094._binary_tree_inorder_traversal.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/binary-tree-inorder-traversal +* https://leetcode.com/problems/binary-tree-inorder-traversal/description/ > 内容描述 diff --git a/docs/leetcode/python/096._unique_binary_search_trees.md b/docs/Leetcode_Solutions/Python/096._unique_binary_search_trees.md similarity index 95% rename from docs/leetcode/python/096._unique_binary_search_trees.md rename to docs/Leetcode_Solutions/Python/096._unique_binary_search_trees.md index 6601516c5..cf9d8c9a7 100644 --- a/docs/leetcode/python/096._unique_binary_search_trees.md +++ b/docs/Leetcode_Solutions/Python/096._unique_binary_search_trees.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/unique-binary-search-trees +* https://leetcode.com/problems/unique-binary-search-trees/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/098._validate_binary_search_tree.md b/docs/Leetcode_Solutions/Python/098._validate_binary_search_tree.md new file mode 100644 index 000000000..db5a92028 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/098._validate_binary_search_tree.md @@ -0,0 +1,140 @@ +# 98. Validate Binary Search Tree + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/validate-binary-search-tree/description/ + +> 内容描述 + +``` +Given a binary tree, determine if it is a valid binary search tree (BST). + +Assume a BST is defined as follows: + +The left subtree of a node contains only nodes with keys less than the node's key. +The right subtree of a node contains only nodes with keys greater than the node's key. +Both the left and right subtrees must also be binary search trees. +Example 1: + +Input: + 2 + / \ + 1 3 +Output: true +Example 2: + + 5 + / \ + 1 4 + / \ + 3 6 +Output: false +Explanation: The input is: [5,1,4,null,null,3,6]. The root node's value + is 5 but its right child's value is 4. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +中序遍历一次,看看list是否严格满足递增 + +```python + def isValidBST(self, root): + """ + :type root: TreeNode + :rtype: bool + """ + def inorder(root): + if not root: + return + inorder(root.left) + res.append(root) + inorder(root.right) + + res = [] + if not root: + return True + inorder(root) + for i in range(1, len(res)): + if res[i].val <= res[i-1].val: + return False + return True +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +以前做过这道题,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都确保被夹在一个范围。 + + +```python +class Solution(object): + def isValidBST(self, root): + """ + :type root: TreeNode + :rtype: bool + """ + def valid(root, smallest, largest): + if not root: + return True + if smallest >= root.val or largest <= root.val: + return False + return valid(root.left, smallest, root.val) and valid(root.right, root.val, largest) + if not root: + return True + return valid(root, -sys.maxsize, sys.maxsize) +``` + + + diff --git a/docs/leetcode/python/100._same_tree.md b/docs/Leetcode_Solutions/Python/100._same_tree.md similarity index 95% rename from docs/leetcode/python/100._same_tree.md rename to docs/Leetcode_Solutions/Python/100._same_tree.md index f1e4a0b26..f12c86c3a 100644 --- a/docs/leetcode/python/100._same_tree.md +++ b/docs/Leetcode_Solutions/Python/100._same_tree.md @@ -1,49 +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 -``` +### 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/leetcode/python/101._symmetric_tree.md b/docs/Leetcode_Solutions/Python/101._symmetric_tree.md similarity index 95% rename from docs/leetcode/python/101._symmetric_tree.md rename to docs/Leetcode_Solutions/Python/101._symmetric_tree.md index ac5b08266..cb6f5219b 100644 --- a/docs/leetcode/python/101._symmetric_tree.md +++ b/docs/Leetcode_Solutions/Python/101._symmetric_tree.md @@ -1,45 +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 -``` - - - - +### 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/leetcode/python/102._binary_tree_level_order_traversal.md b/docs/Leetcode_Solutions/Python/102._binary_tree_level_order_traversal.md similarity index 77% rename from docs/leetcode/python/102._binary_tree_level_order_traversal.md rename to docs/Leetcode_Solutions/Python/102._binary_tree_level_order_traversal.md index d95eac61f..9c298ffda 100644 --- a/docs/leetcode/python/102._binary_tree_level_order_traversal.md +++ b/docs/Leetcode_Solutions/Python/102._binary_tree_level_order_traversal.md @@ -1,11 +1,11 @@ # 102. Binary Tree Level Order Traversal -**难度: 中等** +**难度: Medium** ## 刷题内容 > 原题连接 -* https://leetcode.com/problems/binary-tree-level-order-traversal +* https://leetcode.com/problems/binary-tree-level-order-traversal/description/ > 内容描述 @@ -34,23 +34,24 @@ return its level order traversal as: 递归 ```python -class Solution(object): +class Solution: def levelOrder(self, root): """ :type root: TreeNode :rtype: List[List[int]] """ + def dfs(node, level, res): + if not node: + return + if len(res) < level: + res.append([]) + res[level-1].append(node.val) + dfs(node.left, level+1, res) + dfs(node.right, level+1, res) + res = [] - self.recurHelper(root, 0, res) + dfs(root, 1, 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 diff --git a/docs/leetcode/python/103._binary_tree_zigzag_level_order_traversal.md b/docs/Leetcode_Solutions/Python/103._binary_tree_zigzag_level_order_traversal.md similarity index 95% rename from docs/leetcode/python/103._binary_tree_zigzag_level_order_traversal.md rename to docs/Leetcode_Solutions/Python/103._binary_tree_zigzag_level_order_traversal.md index 0f5f55fd1..edc9b3986 100644 --- a/docs/leetcode/python/103._binary_tree_zigzag_level_order_traversal.md +++ b/docs/Leetcode_Solutions/Python/103._binary_tree_zigzag_level_order_traversal.md @@ -1,43 +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 -``` - - +### 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/leetcode/python/104._maximum_depth_of_binary_tree.md b/docs/Leetcode_Solutions/Python/104._maximum_depth_of_binary_tree.md similarity index 95% rename from docs/leetcode/python/104._maximum_depth_of_binary_tree.md rename to docs/Leetcode_Solutions/Python/104._maximum_depth_of_binary_tree.md index ffd5898a8..451160d32 100644 --- a/docs/leetcode/python/104._maximum_depth_of_binary_tree.md +++ b/docs/Leetcode_Solutions/Python/104._maximum_depth_of_binary_tree.md @@ -1,23 +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 -``` +### 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/leetcode/python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md b/docs/Leetcode_Solutions/Python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md similarity index 94% rename from docs/leetcode/python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md rename to docs/Leetcode_Solutions/Python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md index 1fc2656c3..441679434 100644 --- a/docs/leetcode/python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md +++ b/docs/Leetcode_Solutions/Python/105._construct_binary_tree_from_preorder_and_inorder_traversal.md @@ -6,8 +6,8 @@ > 原题连接 -* https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal -* https://leetcode-cn.com/problems/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/ > 内容描述 diff --git a/docs/leetcode/python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md b/docs/Leetcode_Solutions/Python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md similarity index 100% rename from docs/leetcode/python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md rename to docs/Leetcode_Solutions/Python/106._construct_binary_tree_from_inorder_and_postorder_traversal.md diff --git a/docs/Leetcode_Solutions/Python/107._binary_tree_level_order_traversal_ii.md b/docs/Leetcode_Solutions/Python/107._binary_tree_level_order_traversal_ii.md new file mode 100644 index 000000000..a3d59a027 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/107._binary_tree_level_order_traversal_ii.md @@ -0,0 +1,61 @@ +# 107. Binary Tree Level Order Traversal II + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/binary-tree-level-order-traversal-ii/description/ + +> 内容描述 + +``` +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)****** + + +用102 的算法作弊 + + +```python +class Solution: + def levelOrderBottom(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + def dfs(node, level, res): + if not node: + return + if len(res) < level: + res.append([]) + res[level-1].append(node.val) + dfs(node.left, level+1, res) + dfs(node.right, level+1, res) + + res = [] + dfs(root, 1, res) + return res[::-1] +``` + + diff --git a/docs/leetcode/python/108._convert_sorted_array_to_binary_search_tree.md b/docs/Leetcode_Solutions/Python/108._convert_sorted_array_to_binary_search_tree.md similarity index 100% rename from docs/leetcode/python/108._convert_sorted_array_to_binary_search_tree.md rename to docs/Leetcode_Solutions/Python/108._convert_sorted_array_to_binary_search_tree.md diff --git a/docs/leetcode/python/109._convert_sorted_list_to_binary_search_tree.md b/docs/Leetcode_Solutions/Python/109._convert_sorted_list_to_binary_search_tree.md similarity index 100% rename from docs/leetcode/python/109._convert_sorted_list_to_binary_search_tree.md rename to docs/Leetcode_Solutions/Python/109._convert_sorted_list_to_binary_search_tree.md diff --git a/docs/leetcode/python/110._balanced_binary_tree.md b/docs/Leetcode_Solutions/Python/110._balanced_binary_tree.md similarity index 89% rename from docs/leetcode/python/110._balanced_binary_tree.md rename to docs/Leetcode_Solutions/Python/110._balanced_binary_tree.md index ac8f70104..5dc519d6a 100644 --- a/docs/leetcode/python/110._balanced_binary_tree.md +++ b/docs/Leetcode_Solutions/Python/110._balanced_binary_tree.md @@ -1,68 +1,68 @@ -# 110. Balanced Binary Tree -**难度: 简单** - -## 刷题内容 - -> 原题连接 - -* 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. -``` - -## 解题方案 - -> 思路 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) -``` - - - - +# 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/leetcode/python/111._minimum_depth_of_binary_tree.md b/docs/Leetcode_Solutions/Python/111._minimum_depth_of_binary_tree.md similarity index 100% rename from docs/leetcode/python/111._minimum_depth_of_binary_tree.md rename to docs/Leetcode_Solutions/Python/111._minimum_depth_of_binary_tree.md diff --git a/docs/leetcode/python/112._path_sum.md b/docs/Leetcode_Solutions/Python/112._path_sum.md similarity index 100% rename from docs/leetcode/python/112._path_sum.md rename to docs/Leetcode_Solutions/Python/112._path_sum.md diff --git a/docs/leetcode/python/113._path_sum_ii.md b/docs/Leetcode_Solutions/Python/113._path_sum_ii.md similarity index 100% rename from docs/leetcode/python/113._path_sum_ii.md rename to docs/Leetcode_Solutions/Python/113._path_sum_ii.md diff --git a/docs/leetcode/python/114._flatten_binary_tree_to_linked_list.md b/docs/Leetcode_Solutions/Python/114._flatten_binary_tree_to_linked_list.md similarity index 96% rename from docs/leetcode/python/114._flatten_binary_tree_to_linked_list.md rename to docs/Leetcode_Solutions/Python/114._flatten_binary_tree_to_linked_list.md index 7997d090a..81ad647ca 100644 --- a/docs/leetcode/python/114._flatten_binary_tree_to_linked_list.md +++ b/docs/Leetcode_Solutions/Python/114._flatten_binary_tree_to_linked_list.md @@ -1,71 +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% - +### 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/leetcode/python/116._populating_next_right_pointers_in_each_node.md b/docs/Leetcode_Solutions/Python/116._populating_next_right_pointers_in_each_node.md similarity index 98% rename from docs/leetcode/python/116._populating_next_right_pointers_in_each_node.md rename to docs/Leetcode_Solutions/Python/116._populating_next_right_pointers_in_each_node.md index fec99e947..f0548445c 100644 --- a/docs/leetcode/python/116._populating_next_right_pointers_in_each_node.md +++ b/docs/Leetcode_Solutions/Python/116._populating_next_right_pointers_in_each_node.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/populating-next-right-pointers-in-each-node +* https://leetcode.com/problems/populating-next-right-pointers-in-each-node/description/ > 内容描述 diff --git a/docs/leetcode/python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md b/docs/Leetcode_Solutions/Python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md similarity index 98% rename from docs/leetcode/python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md rename to docs/Leetcode_Solutions/Python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md index f42e157ab..72b10dfb3 100644 --- a/docs/leetcode/python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md +++ b/docs/Leetcode_Solutions/Python/117._Populating_Next_Right_Pointers_in_Each_Node_II.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii +* https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/description/ > 内容描述 diff --git a/docs/leetcode/python/118._pascal's_triangle.md b/docs/Leetcode_Solutions/Python/118._pascal's_triangle.md similarity index 91% rename from docs/leetcode/python/118._pascal's_triangle.md rename to docs/Leetcode_Solutions/Python/118._pascal's_triangle.md index 026ce65e4..2b7c01a33 100644 --- a/docs/leetcode/python/118._pascal's_triangle.md +++ b/docs/Leetcode_Solutions/Python/118._pascal's_triangle.md @@ -1,73 +1,73 @@ -# 118. Pascal's Triangle -**难度: 简单** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/pascals-triangle - -> 内容描述 - -``` -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] -``` - +# 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/leetcode/python/119._Pascal's_Triangle_II.md b/docs/Leetcode_Solutions/Python/119. _Pascal's_Triangle_II.md similarity index 100% rename from docs/leetcode/python/119._Pascal's_Triangle_II.md rename to docs/Leetcode_Solutions/Python/119. _Pascal's_Triangle_II.md diff --git a/docs/leetcode/python/120._Triangle.md b/docs/Leetcode_Solutions/Python/120. Triangle.md similarity index 100% rename from docs/leetcode/python/120._Triangle.md rename to docs/Leetcode_Solutions/Python/120. Triangle.md diff --git a/docs/Leetcode_Solutions/Python/121._Best_Time_to_Buy_and_Sell_Stock.md b/docs/Leetcode_Solutions/Python/121._Best_Time_to_Buy_and_Sell_Stock.md new file mode 100644 index 000000000..fb027fc9d --- /dev/null +++ b/docs/Leetcode_Solutions/Python/121._Best_Time_to_Buy_and_Sell_Stock.md @@ -0,0 +1,112 @@ +# 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 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + + +对于从第一天后的每一天i来说: +- 如果我们在第i天卖出,则能赚的钱是在第i-1卖能赚到的钱+(第i天的股价 - 第i-1的股价) +- 如果我们在第i天不卖出,则当前赚的钱为 0 + +所以对于第一天后的第i天来说,他能赚到的最多的钱就是上面两种情况中的较大值 + + +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 + opt = [0] * len(prices) + for i in range(1, len(prices)): + opt[i] = max(opt[i-1]+prices[i]-prices[i-1], 0) + return max(opt) +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +```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/leetcode/cpp/0122._Best_Time_to_Buy_and_Sell_Stock_II.md b/docs/Leetcode_Solutions/Python/122._Best_Time_to_Buy_and_Sell_Stock_II.md similarity index 59% rename from docs/leetcode/cpp/0122._Best_Time_to_Buy_and_Sell_Stock_II.md rename to docs/Leetcode_Solutions/Python/122._Best_Time_to_Buy_and_Sell_Stock_II.md index 58e81c278..24051f264 100644 --- a/docs/leetcode/cpp/0122._Best_Time_to_Buy_and_Sell_Stock_II.md +++ b/docs/Leetcode_Solutions/Python/122._Best_Time_to_Buy_and_Sell_Stock_II.md @@ -1,15 +1,17 @@ # 122. Best Time to Buy and Sell Stock II -**�Ѷ�:Easy** +**难度: Easy** -## ˢ������ -> ԭ������ +## 刷题内容 -* https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ +> 原题连接 -> �������� +* https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + +> 内容描述 ``` + 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). @@ -36,20 +38,21 @@ 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 +## 解题方案 + +> 思路 1 + +因为不限制买卖次数,所以对于除了最后一天的每一天,我们只需要看看它是否比明天价格低即可, +如果是的话那我们就今天买入明天卖出(注意:前后两天价格相等的话我们不做买卖操作,因为可能会减少后面可以赚钱的操作数),这样一直操作下去叠加即可 + +```python +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + if not prices or len(prices) == 0: + return 0 + return sum([max(prices[i+1]-prices[i], 0) for i in range(len(prices)-1)]) +``` diff --git a/docs/leetcode/python/124._Binary_Tree_Maximum_Path_Sum.md b/docs/Leetcode_Solutions/Python/124._Binary_Tree_Maximum_Path_Sum.md similarity index 100% rename from docs/leetcode/python/124._Binary_Tree_Maximum_Path_Sum.md rename to docs/Leetcode_Solutions/Python/124._Binary_Tree_Maximum_Path_Sum.md diff --git a/docs/Leetcode_Solutions/Python/125._valid_palindrome.md b/docs/Leetcode_Solutions/Python/125._valid_palindrome.md new file mode 100644 index 000000000..460a40df5 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/125._valid_palindrome.md @@ -0,0 +1,100 @@ +# 125. Valid Palindrome + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/valid-palindrome/description/ + +> 内容描述 + +``` +Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. + +Note: For the purpose of this problem, we define empty string as valid palindrome. + +Example 1: + +Input: "A man, a plan, a canal: Panama" +Output: true +Example 2: + +Input: "race a car" +Output: false +``` + +## 解题方案 + +> 思路 1 + +就是比较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 += i + return new == new[::-1] +``` +这样写更简单 + +```python +class Solution: + def isPalindrome(self, s): + s = ''.join(e for e in s if e.isalnum()).lower() + return s==s[::-1] +``` + +> 思路 2 + +或者用正则,详见[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 + """ + s = re.sub('[^0-9a-zA-Z]+', '', s ).lower() + return s == s[::-1] +``` + +> 思路 3 + + +双指针in-place + +时间复杂度还是O(n), 但是空间优化到了O(1) +```python +class Solution(object): + def isPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + l, r = 0, len(s)-1 + while l < r: + while l < r and not s[l].isalnum(): + l += 1 + while l < r and not s[r].isalnum(): + r -= 1 + if s[l].lower() != s[r].lower(): + return False + l +=1 + r -= 1 + return True +``` + diff --git a/docs/leetcode/python/126._Word_Ladder_II.md b/docs/Leetcode_Solutions/Python/126. Word Ladder II.md similarity index 100% rename from docs/leetcode/python/126._Word_Ladder_II.md rename to docs/Leetcode_Solutions/Python/126. Word Ladder II.md diff --git a/docs/Leetcode_Solutions/Python/127._word_ladder.md b/docs/Leetcode_Solutions/Python/127._word_ladder.md new file mode 100644 index 000000000..b852e9b11 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/127._word_ladder.md @@ -0,0 +1,81 @@ +# 127. Word Ladder + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/word-ladder/description/ + +> 内容描述 + +``` +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 + +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, stack, visited, lookup = 0, [beginWord], set([beginWord]), set(wordList) + while stack: + next_stack = [] + for word in stack: + if word == endWord: + return distance + 1 + for i in range(len(word)): + for char in 'abcdefghijklmnopqrstuvwxyz': + trans_word = word[:i] + char + word[i+1:] + if trans_word not in visited and trans_word in lookup: + next_stack.append(trans_word) + visited.add(trans_word) + distance += 1 + stack = next_stack + return 0 +``` diff --git a/docs/leetcode/python/128._Longest_Consecutive_Sequence.md b/docs/Leetcode_Solutions/Python/128._Longest_Consecutive_Sequence.md similarity index 100% rename from docs/leetcode/python/128._Longest_Consecutive_Sequence.md rename to docs/Leetcode_Solutions/Python/128._Longest_Consecutive_Sequence.md diff --git a/docs/leetcode/python/129._sum_root_to_leaf_numbers.md b/docs/Leetcode_Solutions/Python/129._sum_root_to_leaf_numbers.md similarity index 100% rename from docs/leetcode/python/129._sum_root_to_leaf_numbers.md rename to docs/Leetcode_Solutions/Python/129._sum_root_to_leaf_numbers.md diff --git a/docs/leetcode/python/130._surrounded_regions.md b/docs/Leetcode_Solutions/Python/130._surrounded_regions.md similarity index 100% rename from docs/leetcode/python/130._surrounded_regions.md rename to docs/Leetcode_Solutions/Python/130._surrounded_regions.md diff --git a/docs/leetcode/python/131._palindrome_partitioning.md b/docs/Leetcode_Solutions/Python/131._palindrome_partitioning.md similarity index 100% rename from docs/leetcode/python/131._palindrome_partitioning.md rename to docs/Leetcode_Solutions/Python/131._palindrome_partitioning.md diff --git a/docs/leetcode/python/133._clone_graph.md b/docs/Leetcode_Solutions/Python/133._clone_graph.md similarity index 100% rename from docs/leetcode/python/133._clone_graph.md rename to docs/Leetcode_Solutions/Python/133._clone_graph.md diff --git a/docs/leetcode/python/136._single_number.md b/docs/Leetcode_Solutions/Python/136._single_number.md similarity index 51% rename from docs/leetcode/python/136._single_number.md rename to docs/Leetcode_Solutions/Python/136._single_number.md index 18540da0f..97778eaa8 100644 --- a/docs/leetcode/python/136._single_number.md +++ b/docs/Leetcode_Solutions/Python/136._single_number.md @@ -1,17 +1,36 @@ -### 136. Single Number +# 136. Single Number +**难度: Easy** +## 刷题内容 -题目: - +> 原题连接 +* https://leetcode.com/problems/single-number/description/ -难度: +> 内容描述 -Easy +``` +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(N)****** 位运算,终于要take it了 @@ -24,7 +43,7 @@ Easy Python的位操作: -神奇的解法: + ```python diff --git a/docs/Leetcode_Solutions/Python/137._Single_Number_II.md b/docs/Leetcode_Solutions/Python/137._Single_Number_II.md new file mode 100644 index 000000000..9c26ff3a5 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/137._Single_Number_II.md @@ -0,0 +1,85 @@ +# 137. Single Number II + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/single-number-ii/description/ + +> 内容描述 + +``` +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 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +一行,算出set和的三倍,然后减去总的sum,就是所求数字的2倍 + +beats 100% +```python +class Solution(object): + def singleNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + return int((3 * sum(set(nums)) - sum(nums)) // 2) +``` + + + + + + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +参考文章: + +1. [[Leetcode]找到出现不同次数的数字(通用解法)](https://www.cnblogs.com/bjwu/p/9323808.html) +2. [bron 【中文】简短又通俗的理解](https://leetcode.com/problems/single-number-ii/discuss/167343/topic) +3. [leetcode-137-Single Number II-第二种解法](https://cloud.tencent.com/developer/article/1131945) + +```python +class Solution(object): + def singleNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + a = b = 0 + for num in nums: + b = b ^ num & ~a + a = a ^ num & ~b + return a | b +``` + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/139._word_break.md b/docs/Leetcode_Solutions/Python/139._word_break.md new file mode 100644 index 000000000..815737dec --- /dev/null +++ b/docs/Leetcode_Solutions/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/leetcode/python/140._word_break_ii.md b/docs/Leetcode_Solutions/Python/140._word_break_ii.md similarity index 100% rename from docs/leetcode/python/140._word_break_ii.md rename to docs/Leetcode_Solutions/Python/140._word_break_ii.md diff --git a/docs/leetcode/python/141._linked_list_cycle.md b/docs/Leetcode_Solutions/Python/141._linked_list_cycle.md similarity index 95% rename from docs/leetcode/python/141._linked_list_cycle.md rename to docs/Leetcode_Solutions/Python/141._linked_list_cycle.md index 49417387a..2d50901e9 100644 --- a/docs/leetcode/python/141._linked_list_cycle.md +++ b/docs/Leetcode_Solutions/Python/141._linked_list_cycle.md @@ -1,105 +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; - } -} -``` - +### 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/leetcode/python/142_Linked_List_Cycle_II.md b/docs/Leetcode_Solutions/Python/142_Linked_List_Cycle_II.md similarity index 100% rename from docs/leetcode/python/142_Linked_List_Cycle_II.md rename to docs/Leetcode_Solutions/Python/142_Linked_List_Cycle_II.md diff --git a/docs/Leetcode_Solutions/Python/143._reorder_list.md b/docs/Leetcode_Solutions/Python/143._reorder_list.md new file mode 100644 index 000000000..3bf56c53c --- /dev/null +++ b/docs/Leetcode_Solutions/Python/143._reorder_list.md @@ -0,0 +1,133 @@ +# 143. Reorder List + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/reorder-list/description/ + +> 内容描述 + +``` +Given a singly linked list L: L0→L1→…→Ln-1→Ln, +reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→… + +You may not modify the values in the list's nodes, only nodes itself may be changed. + +Example 1: + +Given 1->2->3->4, reorder it to 1->4->2->3. +Example 2: + +Given 1->2->3->4->5, reorder it to 1->5->2->4->3. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +找到后半段反转后,再merge + +```python +class Solution(object): + def reorderList(self, head): + """ + :type head: ListNode + :rtype: void Do not return anything, modify head in-place instead. + """ + if not head or not head.next or not head.next.next: + return + + # calculate the length + n = 0 + dummy1 = head + while dummy1: + n += 1 + dummy1 = dummy1.next + + # find the start point of the second half + m = n // 2 + 1 + dummy2 = head + for i in range(m-1): + dummy2 = dummy2.next + dummy3 = dummy2.next + dummy2.next = None + + # reverse second half + prev = None + while dummy3: + nxt = dummy3.next + dummy3.next = prev + prev = dummy3 + dummy3= nxt + + # merge two half + dummy4 = head + # print(head.next.next.val) + for i in range(n-m): + nxt_head = dummy4.next + nxt_prev = prev.next + dummy4.next = prev + prev.next = nxt_head + prev = nxt_prev + dummy4 = nxt_head +``` + + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +取巧的办法是,用快慢指针找到后半段,这样不用计算链表长度 + +找到中间节点,断开,把后半截linked list reverse,然后合并两段 + +```python +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: + nxt = cur.next + cur.next = slow + slow = slow.next + cur.next.next = nxt + cur = nxt + 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/leetcode/python/144._binary_tree_preorder_traversal.md b/docs/Leetcode_Solutions/Python/144._binary_tree_preorder_traversal.md similarity index 96% rename from docs/leetcode/python/144._binary_tree_preorder_traversal.md rename to docs/Leetcode_Solutions/Python/144._binary_tree_preorder_traversal.md index 8dd38e7fe..b81890681 100644 --- a/docs/leetcode/python/144._binary_tree_preorder_traversal.md +++ b/docs/Leetcode_Solutions/Python/144._binary_tree_preorder_traversal.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/binary-tree-preorder-traversal +* https://leetcode.com/problems/binary-tree-preorder-traversal/description/ > 内容描述 diff --git a/docs/leetcode/python/145._binary_tree_postorder_traversal.md b/docs/Leetcode_Solutions/Python/145._binary_tree_postorder_traversal.md similarity index 96% rename from docs/leetcode/python/145._binary_tree_postorder_traversal.md rename to docs/Leetcode_Solutions/Python/145._binary_tree_postorder_traversal.md index c62edbaf0..2729d4973 100644 --- a/docs/leetcode/python/145._binary_tree_postorder_traversal.md +++ b/docs/Leetcode_Solutions/Python/145._binary_tree_postorder_traversal.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/binary-tree-postorder-traversal +* https://leetcode.com/problems/binary-tree-postorder-traversal/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/146._LRU_Cache.md b/docs/Leetcode_Solutions/Python/146._LRU_Cache.md new file mode 100644 index 000000000..2bdea0395 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/146._LRU_Cache.md @@ -0,0 +1,158 @@ +# 146. LRU Cache + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/lru-cache/description/ + +> 内容描述 + +``` +Design and implement a data structure for Least Recently Used (LRU) cache. 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. + +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)****** + + +LRU cache 相当于要维护一个跟时间顺序相关的数据结构 + +那么能找到最早更新元素的数据结构有 queue,heap和LinkedList这几种 + +1. 首先,我们需要能够快速的访问到指点的元素,这一点LinkedList要用O(n)遍历,但是我们可以通过一个字典来对应key和node的信息,这样就是O(1)了 +2. 其次,由于要随时插入和删除找到的node,双向链表 doubly LinkedList 显然更好一些 + +然后我们可以开始想接下来的逻辑了 + +1. LRU Cache里面维护一个cache字典对应key和node的信息,一个cap表示最大容量,一个双向链表,其中head.next是most recently的node, +tail.prev是least recently的node(即容量满了被删除的那个node) +2. 对于get方法 + - 1. 如果key在cache字典中,说明node在链表中 + - 根据key从cache字典中拿到对应的node,删除这个node,再重新插入这个node(插入逻辑包含了更新到最新的位置) + - 2. 如果不在直接返回 -1 +3. 对于put方法 + - 1. 如果key在cache字典中,说明node在链表中 + - 根据key从cache字典中拿到对应的node,删除这个node,再重新插入这个node(插入逻辑包含了更新到最新的位置) + - 2. 如果key不在cache字典中,说明是一个新的node + - 如果此时容量还没满的话: + - 生成新node,插入链表中,放入cache中 + - 如果此时容量满了的话: + - 从链表中删除tail.prev,即least recently的node + - 从cache中删除这个node的信息 + - 生成新node,插入链表中,放入cache中 + + +下面是AC代码,其中逻辑3中如果key不在cache字典中的代码可以优化,生成新node,插入链表中,放入cache中这一步是重复的 + +beats 95.66% + +```python +class Node(object): + def __init__(self, key, val): + self.key = key + self.val = val + self.next = None + self.prev = None + + +class LRUCache(object): + def __init__(self, capacity): + """ + :type capacity: int + """ + self.cache = {} + self.cap = capacity + self.head = Node(None, None) + self.tail = Node(None, None) + self.head.next = self.tail + self.tail.prev = self.head + + + def remove(self, node): + n = node.next + p = node.prev + p.next = n + n.prev = p + node.next = None + node.prev = None + + + def insert(self, node): + n = self.head.next + self.head.next = node + node.next = n + n.prev = node + node.prev = self.head + + + def get(self, key): + """ + :type key: int + :rtype: int + """ + if key in self.cache: + node = self.cache[key] + self.remove(node) + self.insert(node) + return node.val + else: + return -1 + + + def put(self, key, value): + """ + :type key: int + :type value: int + :rtype: void + """ + if key in self.cache: + node = self.cache[key] + node.val = value + self.remove(node) + self.insert(node) + else: + if len(self.cache) == self.cap: + delete_node = self.tail.prev + del self.cache[delete_node.key] + self.remove(delete_node) + node = Node(key, value) + self.insert(node) + self.cache[key] = node + + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) +``` + + + + + + diff --git a/docs/leetcode/python/147._insertion_sort_list.md b/docs/Leetcode_Solutions/Python/147._insertion_sort_list.md similarity index 100% rename from docs/leetcode/python/147._insertion_sort_list.md rename to docs/Leetcode_Solutions/Python/147._insertion_sort_list.md diff --git a/docs/leetcode/python/148._sort_list.md b/docs/Leetcode_Solutions/Python/148._sort_list.md similarity index 100% rename from docs/leetcode/python/148._sort_list.md rename to docs/Leetcode_Solutions/Python/148._sort_list.md diff --git a/docs/leetcode/python/150._evaluate_reverse_polish_notation.md b/docs/Leetcode_Solutions/Python/150._evaluate_reverse_polish_notation.md similarity index 100% rename from docs/leetcode/python/150._evaluate_reverse_polish_notation.md rename to docs/Leetcode_Solutions/Python/150._evaluate_reverse_polish_notation.md diff --git a/docs/leetcode/python/151._reverse_words_in_a_string.md b/docs/Leetcode_Solutions/Python/151._reverse_words_in_a_string.md similarity index 100% rename from docs/leetcode/python/151._reverse_words_in_a_string.md rename to docs/Leetcode_Solutions/Python/151._reverse_words_in_a_string.md diff --git a/docs/leetcode/python/152._maximum_product_subarray.md b/docs/Leetcode_Solutions/Python/152._maximum_product_subarray.md similarity index 100% rename from docs/leetcode/python/152._maximum_product_subarray.md rename to docs/Leetcode_Solutions/Python/152._maximum_product_subarray.md diff --git a/docs/leetcode/python/153._find_minimum_in_rotated_sorted_array.md b/docs/Leetcode_Solutions/Python/153._find_minimum_in_rotated_sorted_array.md similarity index 100% rename from docs/leetcode/python/153._find_minimum_in_rotated_sorted_array.md rename to docs/Leetcode_Solutions/Python/153._find_minimum_in_rotated_sorted_array.md diff --git a/docs/leetcode/python/155._min_stack.md b/docs/Leetcode_Solutions/Python/155._min_stack.md similarity index 100% rename from docs/leetcode/python/155._min_stack.md rename to docs/Leetcode_Solutions/Python/155._min_stack.md diff --git a/docs/leetcode/python/157._Read_N_Characters_Given_Read4.md b/docs/Leetcode_Solutions/Python/157._Read_N_Characters_Given_Read4.md similarity index 97% rename from docs/leetcode/python/157._Read_N_Characters_Given_Read4.md rename to docs/Leetcode_Solutions/Python/157._Read_N_Characters_Given_Read4.md index e390ca0e3..447051ff7 100644 --- a/docs/leetcode/python/157._Read_N_Characters_Given_Read4.md +++ b/docs/Leetcode_Solutions/Python/157._Read_N_Characters_Given_Read4.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/read-n-characters-given-read4 +* https://leetcode.com/problems/read-n-characters-given-read4/description/ > 内容描述 diff --git a/docs/leetcode/python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md b/docs/Leetcode_Solutions/Python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md similarity index 98% rename from docs/leetcode/python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md rename to docs/Leetcode_Solutions/Python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md index a3826eafd..ec2c8cce8 100644 --- a/docs/leetcode/python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md +++ b/docs/Leetcode_Solutions/Python/158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times +* https://leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times/description/ > 内容描述 diff --git a/docs/leetcode/python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md b/docs/Leetcode_Solutions/Python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md similarity index 54% rename from docs/leetcode/python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md rename to docs/Leetcode_Solutions/Python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md index 7d65fb605..128abbe66 100644 --- a/docs/leetcode/python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md +++ b/docs/Leetcode_Solutions/Python/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md @@ -1,11 +1,34 @@ -### 159. Longest Substring with At Most Two Distinct Characters +# 159. Longest Substring with At Most Two Distinct Characters -题目: - +**难度: Hard** +## 刷题内容 -难度 : Hard +> 原题连接 +* https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/description/ + +> 内容描述 + +``` +Given a string s , find the length of the longest substring t that contains at most 2 distinct characters. + +Example 1: + +Input: "eceba" +Output: 3 +Explanation: t is "ece" which its length is 3. +Example 2: + +Input: "ccaabbb" +Output: 5 +Explanation: t is "aabbb" which its length is 5. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** ```python @@ -30,3 +53,5 @@ class Solution(object):            length = max(length, end - begin) # 因此这里是```end - begin```而不是```end - begin + 1```        return length ``` + + diff --git a/docs/leetcode/python/160._intersection_of_two_linked_lists.md b/docs/Leetcode_Solutions/Python/160._intersection_of_two_linked_lists.md similarity index 100% rename from docs/leetcode/python/160._intersection_of_two_linked_lists.md rename to docs/Leetcode_Solutions/Python/160._intersection_of_two_linked_lists.md diff --git a/docs/leetcode/python/162._find_peak_element.md b/docs/Leetcode_Solutions/Python/162._find_peak_element.md similarity index 100% rename from docs/leetcode/python/162._find_peak_element.md rename to docs/Leetcode_Solutions/Python/162._find_peak_element.md diff --git a/docs/leetcode/python/165._compare_version_numbers.md b/docs/Leetcode_Solutions/Python/165._compare_version_numbers.md similarity index 100% rename from docs/leetcode/python/165._compare_version_numbers.md rename to docs/Leetcode_Solutions/Python/165._compare_version_numbers.md diff --git a/docs/Leetcode_Solutions/Python/166._Fraction_to_Recurring_Decimal.md b/docs/Leetcode_Solutions/Python/166._Fraction_to_Recurring_Decimal.md new file mode 100644 index 000000000..2045b3362 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/166._Fraction_to_Recurring_Decimal.md @@ -0,0 +1,83 @@ +# 166. Fraction to Recurring Decimal + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/fraction-to-recurring-decimal/description/ + +> 内容描述 + +``` +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)" +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: hard to say****** - 空间复杂度: O(1)****** + + +- 先处理正负号 +- 再处理整数部分 +- 最后处理小数部分,利用字典来判断是否循环 + +***note:对于小数处理部分,必须先进行将没有处理过的r加入到m中去*** + +这是因为: +``` +例如输入为4, 333 +如果我们将已经处理过的r加入到m中去的话,重复数字当次就被加入m中了,下一次循环判断的时候r肯定已经在里面了 +``` + + +```python +class Solution(object): + def fractionToDecimal(self, numerator, denominator): + """ + :type numerator: int + :type denominator: int + :rtype: str + """ + if numerator == 0: # zero numerator + return '0' + res = '' + if numerator * denominator < 0: # determine the sign + res += '-' + numerator, denominator = abs(numerator), abs(denominator) # remove sign of operands + res += str(numerator / denominator) # append integer part + if numerator % denominator == 0: # in case no fractional part + return res + res += '.' + r = numerator % denominator + 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 next r/denominator index in res + r *= 10 + res += str(r/denominator) # append the quotient digit + r %= denominator + + return res +``` + + diff --git a/docs/leetcode/python/167._two_sum_ii_-_input_array_is_sorted.md b/docs/Leetcode_Solutions/Python/167._two_sum_ii_-_input_array_is_sorted.md similarity index 100% rename from docs/leetcode/python/167._two_sum_ii_-_input_array_is_sorted.md rename to docs/Leetcode_Solutions/Python/167._two_sum_ii_-_input_array_is_sorted.md diff --git a/docs/leetcode/python/168._excel_sheet_column_title.md b/docs/Leetcode_Solutions/Python/168._excel_sheet_column_title.md similarity index 97% rename from docs/leetcode/python/168._excel_sheet_column_title.md rename to docs/Leetcode_Solutions/Python/168._excel_sheet_column_title.md index 1746fa858..547f083ee 100644 --- a/docs/leetcode/python/168._excel_sheet_column_title.md +++ b/docs/Leetcode_Solutions/Python/168._excel_sheet_column_title.md @@ -12,17 +12,17 @@ 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 +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/leetcode/python/169._majority_element.md b/docs/Leetcode_Solutions/Python/169._majority_element.md similarity index 100% rename from docs/leetcode/python/169._majority_element.md rename to docs/Leetcode_Solutions/Python/169._majority_element.md diff --git a/docs/leetcode/python/171._excel_sheet_column_number.md b/docs/Leetcode_Solutions/Python/171._excel_sheet_column_number.md similarity index 97% rename from docs/leetcode/python/171._excel_sheet_column_number.md rename to docs/Leetcode_Solutions/Python/171._excel_sheet_column_number.md index 0a92b3808..4521f737c 100644 --- a/docs/leetcode/python/171._excel_sheet_column_number.md +++ b/docs/Leetcode_Solutions/Python/171._excel_sheet_column_number.md @@ -13,22 +13,22 @@ 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 +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/Leetcode_Solutions/Python/172._Factorial_Trailing_Zeroes.md b/docs/Leetcode_Solutions/Python/172._Factorial_Trailing_Zeroes.md new file mode 100644 index 000000000..c7e98eefa --- /dev/null +++ b/docs/Leetcode_Solutions/Python/172._Factorial_Trailing_Zeroes.md @@ -0,0 +1,58 @@ +# 172. Factorial Trailing Zeroes + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/factorial-trailing-zeroes/description/ + +> 内容描述 + +``` +Given an integer n, return the number of trailing zeroes in n!. + +Example 1: + +Input: 3 +Output: 0 +Explanation: 3! = 6, no trailing zero. +Example 2: + +Input: 5 +Output: 1 +Explanation: 5! = 120, one trailing zero. +Note: Your solution should be in logarithmic time complexity. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)****** + +思路就是开始看我们有多少个5,多少个25,多少个125,这些数字成为base,直到这个base比我们的n大了,我们就不继续加了。那这是为什么呢? + +因为我们知道想让后面多个0,那一定要是偶数乘以5的形式,我们知道偶数一定是比5多的,所以完全够用,所以直接一直加就行了。 + + +开始我还想复杂了,每次算出最前的base_val,即1有0个0,5有1个0,25有6个0,我是通过算出所在区间然后再叠加,这样显然可以, +但是不如上面的想法来得直接来得快。 + +前后想了一个小时,真蠢啊!!! + +```python +class Solution(object): + def trailingZeroes(self, n): + """ + :type n: int + :rtype: int + """ + base, res = 5, 0 + while n >= base: + res += n // base + base *= 5 + return res +``` + + diff --git a/docs/leetcode/python/173._binary_search_tree_iterator.md b/docs/Leetcode_Solutions/Python/173._binary_search_tree_iterator.md similarity index 100% rename from docs/leetcode/python/173._binary_search_tree_iterator.md rename to docs/Leetcode_Solutions/Python/173._binary_search_tree_iterator.md diff --git a/docs/Leetcode_Solutions/Python/176._Second_Highest_Salary.md b/docs/Leetcode_Solutions/Python/176._Second_Highest_Salary.md new file mode 100644 index 000000000..71cf29950 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/176._Second_Highest_Salary.md @@ -0,0 +1,50 @@ +# 176. Second Highest Salary + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/second-highest-salary/description/ + +> 内容描述 + +``` +Write a SQL query to get the second highest salary from the Employee table. + ++----+--------+ +| Id | Salary | ++----+--------+ +| 1 | 100 | +| 2 | 200 | +| 3 | 300 | ++----+--------+ +For example, given the above Employee table, the query should return 200 as the second highest salary. If there is no second highest salary, then the query should return null. + ++---------------------+ +| SecondHighestSalary | ++---------------------+ +| 200 | ++---------------------+ +``` + +## 解题方案 + +> 思路 1 + +```sql +select Salary SecondHighestSalary from Employee +union +select null +order by SecondHighestSalary desc limit 1, 1 +``` + + +> 思路 2 + +```sql +select ( + select distinct Salary from Employee order by Salary Desc limit 1, 1 +)as SecondHighestSalary +``` diff --git a/docs/leetcode/python/179._Largest_Number.md b/docs/Leetcode_Solutions/Python/179._Largest_Number.md similarity index 100% rename from docs/leetcode/python/179._Largest_Number.md rename to docs/Leetcode_Solutions/Python/179._Largest_Number.md diff --git a/docs/leetcode/python/182._duplicate_emails.md b/docs/Leetcode_Solutions/Python/182._duplicate_emails.md similarity index 92% rename from docs/leetcode/python/182._duplicate_emails.md rename to docs/Leetcode_Solutions/Python/182._duplicate_emails.md index 1e77debe3..f000e80cd 100644 --- a/docs/leetcode/python/182._duplicate_emails.md +++ b/docs/Leetcode_Solutions/Python/182._duplicate_emails.md @@ -7,7 +7,7 @@ > 原题连接 * https://leetcode.com/problems/duplicate-emails -* https://leetcode-cn.com/problems/duplicate-emails +* https://leetcode-cn.com/problems/duplicate-emails/description > 内容描述 diff --git a/docs/leetcode/python/189._rotate_array.md b/docs/Leetcode_Solutions/Python/189._rotate_array.md similarity index 95% rename from docs/leetcode/python/189._rotate_array.md rename to docs/Leetcode_Solutions/Python/189._rotate_array.md index ff9d5457f..b00de8752 100644 --- a/docs/leetcode/python/189._rotate_array.md +++ b/docs/Leetcode_Solutions/Python/189._rotate_array.md @@ -1,42 +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] -``` +###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/leetcode/python/191._number_of_1_bits.md b/docs/Leetcode_Solutions/Python/191._number_of_1_bits.md similarity index 100% rename from docs/leetcode/python/191._number_of_1_bits.md rename to docs/Leetcode_Solutions/Python/191._number_of_1_bits.md diff --git a/docs/Leetcode_Solutions/Python/198._house_robber.md b/docs/Leetcode_Solutions/Python/198._house_robber.md new file mode 100644 index 000000000..950868ea6 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/198._house_robber.md @@ -0,0 +1,81 @@ +# 198. House Robber + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/house-robber/description/ + +> 内容描述 + +``` +You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night. + +Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police. + +Example 1: + +Input: [1,2,3,1] +Output: 4 +Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). + Total amount you can rob = 1 + 3 = 4. +Example 2: + +Input: [2,7,9,3,1] +Output: 12 +Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1). + Total amount you can rob = 2 + 9 + 1 = 12. +``` + +## 解题方案 + +> 思路 1 + + +状态转移方程: + +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] +``` + +> 思路 2 + +迭代 + +```python +class Solution(object): + def rob(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + last, now = 0, 0 + for num in nums: + last, now = now, max(last+num, now) + return now +``` + + diff --git a/docs/leetcode/python/199._binary_tree_right_side_view.md b/docs/Leetcode_Solutions/Python/199._binary_tree_right_side_view.md similarity index 100% rename from docs/leetcode/python/199._binary_tree_right_side_view.md rename to docs/Leetcode_Solutions/Python/199._binary_tree_right_side_view.md diff --git a/docs/Leetcode_Solutions/Python/200._number_of_islands.md b/docs/Leetcode_Solutions/Python/200._number_of_islands.md new file mode 100644 index 000000000..fe0420dbd --- /dev/null +++ b/docs/Leetcode_Solutions/Python/200._number_of_islands.md @@ -0,0 +1,59 @@ +# 200. Number of Islands + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/number-of-islands/description/ + +> 内容描述 + +``` +Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. + +Example 1: + +Input: +11110 +11010 +11000 +00000 + +Output: 1 +Example 2: + +Input: +11000 +11000 +00100 +00011 + +Output: 3 +``` + +## 解题方案 + +> 思路 1 + +厉害的解法:Sink and count the islands. + +就是说从(0,0)这个点开始,只要一碰到1就将我们最终island数加1,并且同时将其周围临近的所有1全部都变成0,这样后面就不会重复计算了 + +```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/Leetcode_Solutions/Python/201._Bitwise_AND_of_Numbers_Range.md b/docs/Leetcode_Solutions/Python/201._Bitwise_AND_of_Numbers_Range.md new file mode 100644 index 000000000..a7c1d4bb7 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/201._Bitwise_AND_of_Numbers_Range.md @@ -0,0 +1,93 @@ +# 201. Bitwise AND of Numbers Range + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/bitwise-and-of-numbers-range/description/ + +> 内容描述 + +``` +Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive. + +Example 1: + +Input: [5,7] +Output: 4 +Example 2: + +Input: [0,1] +Output: 0 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(1)******- 空间复杂度: O(1)****** + +我们知道你从m一直&到n,那么m和n二进制位后面不一样的地方肯定都会变成0 +``` +譬如n = 101111,m = 101011,当中经过101100。 +m & n抹除common prefix右边第一位上的1,中间经过那个数抹除所有更低位的1。 +``` +所以我们找到m和n的最长相同前缀,然后补齐二进制的32位(即往右边贴'0') + +自己写的一行版本! + + +```python +import os +class Solution(object): + def rangeBitwiseAnd(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + return int(os.path.commonprefix([bin(m)[2:].zfill(32), bin(n)[2:].zfill(32)])[::-1].zfill(32)[::-1], 2) +``` + + +> 思路 2 +******- 时间复杂度: O(1)******- 空间复杂度: O(1)****** + + +别人的一行版本! + + +```python +class Solution(object): + def rangeBitwiseAnd(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + return self.rangeBitwiseAnd(m, n & n-1) if m < n else n +``` + + +> 思路 +******- 时间复杂度: O(1)******- 空间复杂度: O(1)****** + + +bit移位操作版本 + +```python +class Solution(object): + def rangeBitwiseAnd(self, m, n): + """ + :type m: int + :type n: int + :rtype: int + """ + diff = 0 + while m != n: + m >>= 1 + n >>= 1 + diff += 1 + return m << diff +``` diff --git a/docs/leetcode/python/203._remove_linked_list_elements.md b/docs/Leetcode_Solutions/Python/203._remove_linked_list_elements.md similarity index 96% rename from docs/leetcode/python/203._remove_linked_list_elements.md rename to docs/Leetcode_Solutions/Python/203._remove_linked_list_elements.md index 7dcb32ee2..15aa10efa 100644 --- a/docs/leetcode/python/203._remove_linked_list_elements.md +++ b/docs/Leetcode_Solutions/Python/203._remove_linked_list_elements.md @@ -13,26 +13,26 @@ 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 +``` +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/leetcode/python/204._count_primes.md b/docs/Leetcode_Solutions/Python/204._count_primes.md similarity index 100% rename from docs/leetcode/python/204._count_primes.md rename to docs/Leetcode_Solutions/Python/204._count_primes.md diff --git a/docs/leetcode/python/205._isomorphic_strings.md b/docs/Leetcode_Solutions/Python/205._isomorphic_strings.md similarity index 97% rename from docs/leetcode/python/205._isomorphic_strings.md rename to docs/Leetcode_Solutions/Python/205._isomorphic_strings.md index 9e4b6f178..47b0ab772 100644 --- a/docs/leetcode/python/205._isomorphic_strings.md +++ b/docs/Leetcode_Solutions/Python/205._isomorphic_strings.md @@ -10,29 +10,29 @@ AC之法,用dictionary,因为限制,所以确保s 和 t 是isomorphic 同时 t 和 s 是 -``` -class Solution(object): - def isIsomorphic(self, s, t): - """ - :type s: str - :type t: str - :rtype: bool - """ +``` +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 + + 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/Leetcode_Solutions/Python/206._reverse_linked_list.md b/docs/Leetcode_Solutions/Python/206._reverse_linked_list.md new file mode 100644 index 000000000..5c05edc02 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/206._reverse_linked_list.md @@ -0,0 +1,95 @@ +# 206. Reverse Linked List + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/reverse-linked-list/description/ + +> 内容描述 + +``` +Reverse a singly linked list. + +Example: + +Input: 1->2->3->4->5->NULL +Output: 5->4->3->2->1->NULL +Follow up: + +A linked list can be reversed either iteratively or recursively. Could you implement both? +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +用三个指针,分别指向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 +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +其实不用cur也可以 + +```python +class Solution(object): + def reverseList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + if not head: + return head + prev = None + while head.next: + nxt = head.next + head.next = prev + prev = head + head = nxt + head.next = prev + return head +``` + +递归版本,可以再消化一下. + +> 思路 3 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +```python +class Solution(object): + def reverseList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + def helper(head, new_head): + if head: + nxt = head.next + head.next = new_head + return helper(nxt, head) + else: + return new_head + + return helper(head, None) +``` diff --git a/docs/leetcode/python/207._course_schedule.md b/docs/Leetcode_Solutions/Python/207._course_schedule.md similarity index 100% rename from docs/leetcode/python/207._course_schedule.md rename to docs/Leetcode_Solutions/Python/207._course_schedule.md diff --git a/docs/leetcode/python/208._implement_trie_(prefix_tree).md b/docs/Leetcode_Solutions/Python/208._implement_trie_(prefix_tree).md similarity index 95% rename from docs/leetcode/python/208._implement_trie_(prefix_tree).md rename to docs/Leetcode_Solutions/Python/208._implement_trie_(prefix_tree).md index a828b2fd5..8ee06db58 100644 --- a/docs/leetcode/python/208._implement_trie_(prefix_tree).md +++ b/docs/Leetcode_Solutions/Python/208._implement_trie_(prefix_tree).md @@ -1,89 +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") - -``` - +### 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/leetcode/python/210._course_schedule_ii.md b/docs/Leetcode_Solutions/Python/210._course_schedule_ii.md similarity index 100% rename from docs/leetcode/python/210._course_schedule_ii.md rename to docs/Leetcode_Solutions/Python/210._course_schedule_ii.md diff --git a/docs/leetcode/python/211._Add_and_Search_Word_-_Data_structure_design.md b/docs/Leetcode_Solutions/Python/211. Add and Search Word - Data structure design.md similarity index 100% rename from docs/leetcode/python/211._Add_and_Search_Word_-_Data_structure_design.md rename to docs/Leetcode_Solutions/Python/211. Add and Search Word - Data structure design.md diff --git a/docs/leetcode/python/213._house_robber_ii.md b/docs/Leetcode_Solutions/Python/213._house_robber_ii.md similarity index 100% rename from docs/leetcode/python/213._house_robber_ii.md rename to docs/Leetcode_Solutions/Python/213._house_robber_ii.md diff --git a/docs/Leetcode_Solutions/Python/215._Kth_Largest_Element_in_an_Array.md b/docs/Leetcode_Solutions/Python/215._Kth_Largest_Element_in_an_Array.md new file mode 100644 index 000000000..cf3fbfc32 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/215._Kth_Largest_Element_in_an_Array.md @@ -0,0 +1,148 @@ +# 215. Kth Largest Element in an Array + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/kth-largest-element-in-an-array/description/ + +> 内容描述 + +``` +Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element. + +Example 1: + +Input: [3,2,1,5,6,4] and k = 2 +Output: 5 +Example 2: + +Input: [3,2,3,1,2,4,5,5,6] and k = 4 +Output: 4 +Note: +You may assume k is always valid, 1 ≤ k ≤ array's length. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)****** + +先全部放到一个最大堆中去,然后返回第k个就行了 + +因为python实现的heapq插入操作的时间复杂度是O(lgN),所以最终时间复杂度是O(NlgN) + +``` +1. bisect +根据insort_left 的文档: + +Keep in mind that the O(log n) search is dominated by the slow O(n) insertion step. + +也就是说,单次 insort_left 的时间复杂度是 O(n),自然 sort1 的复杂度就变成了 O(n^2),它最慢是应当的。 + +2. sort +文档说是 O(n log n) 的复杂度。从 listsort 详细文档来看,开发人员着实没少下了工夫。 + +3. heappush +根据维基百科,插入操作的时间复杂度是 O(log n),所以总的时间复杂度仍然是 O(n log n)。不过有一点值得注意,插入操作的平均时间是 O(1),所以有可能会稍微快一点。 + +Python vs. PyPy +CPython 2.7 + +sort1 : bisect 2.617674 +sort2 :lst.sort 0.295187 +sort3 : heapq 0.39279 +PyPy 2.4 + +sort1 : bisect 1.31 +sort2 :lst.sort 0.043 +sort3 : heapq 0.029 +注,我把你的调用部分复制了一遍,执行了两次,结果为第二次的输出。 + +可以看得出,O(n log n) 算法的耗时是在同一个数量级上的,但 CPython 中 sort 胜出,PyPy 中 heapq 胜出。 +``` + +详细可见: +1. [heapq数据结构](https://love.ranshy.com/heapq-%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/) +2. [序列的sort方法 与 bisect.insort, heapq.heappush 效率比较](https://segmentfault.com/q/1010000000664272) + + +```python +class Solution(object): + def findKthLargest(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + from heapq import heappush, heappop + topk = [] + heap = [] + for i in range(len(nums)): + heappush(heap, -nums[i]) + for i in range(k): + if i == k-1: + return -heappop(heap) + heappop(heap) +``` + + +> 思路 1 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(k)****** + +前面的思路是全部放进去以后再pop k次 + +现在打算只维护一个容量为k的最大堆,最终堆顶的值就是结果 + + +```python +class Solution(object): + def findKthLargest(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + if not nums: + return 0 + from heapq import * + heap = [] + for i in range(len(nums)): + heappush(heap,nums[i]) + if len(heap) > k: + heappop(heap) + return heap[0] +``` + + + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(n)****** + +二分+quick sort的思想,随机取一个pivot,大于小于等于它的分别放起来,然后看看大于它的有没有k个,没有就可能在等于或者小于里面 + +二分是O(lgN),但是找大于小于等于是O(N),所以最终时间复杂度是O(N) + +```python +class Solution(object): + def findKthLargest(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + pivot = nums[0] + smaller = [num for num in nums if num < pivot] + equal = [num for num in nums if num == pivot] + greater = [num for num in nums if num > pivot] + + if len(greater) >= k: + return self.findKthLargest(greater, k) #k may be there + elif len(equal) >= (k - len(greater)): # k may be in equal or smaller + return equal[0] # any number from equal + else: + return self.findKthLargest(smaller, k - len(greater) - len(equal)) +``` + diff --git a/docs/leetcode/python/216._combination_sum_iii.md b/docs/Leetcode_Solutions/Python/216._combination_sum_iii.md similarity index 100% rename from docs/leetcode/python/216._combination_sum_iii.md rename to docs/Leetcode_Solutions/Python/216._combination_sum_iii.md diff --git a/docs/leetcode/python/217._contains_duplicate.md b/docs/Leetcode_Solutions/Python/217._contains_duplicate.md similarity index 100% rename from docs/leetcode/python/217._contains_duplicate.md rename to docs/Leetcode_Solutions/Python/217._contains_duplicate.md diff --git a/docs/leetcode/python/218._The_Skyline_Problem.md b/docs/Leetcode_Solutions/Python/218._The _Skyline_Problem .md similarity index 98% rename from docs/leetcode/python/218._The_Skyline_Problem.md rename to docs/Leetcode_Solutions/Python/218._The _Skyline_Problem .md index e11d460f8..34d9c9176 100644 --- a/docs/leetcode/python/218._The_Skyline_Problem.md +++ b/docs/Leetcode_Solutions/Python/218._The _Skyline_Problem .md @@ -131,4 +131,4 @@ Author: Keqi Huang If you like it, please spread your support -![Support](/img/Algorithm/LeetCode/WechatIMG17.jpeg) +![Support](https://github.com/Lisanaaa/myTODOs/blob/master/WechatIMG17.jpeg) diff --git a/docs/leetcode/python/219._contains_duplicate_ii.md b/docs/Leetcode_Solutions/Python/219._contains_duplicate_ii.md similarity index 96% rename from docs/leetcode/python/219._contains_duplicate_ii.md rename to docs/Leetcode_Solutions/Python/219._contains_duplicate_ii.md index 7ffcf2427..050dd932e 100644 --- a/docs/leetcode/python/219._contains_duplicate_ii.md +++ b/docs/Leetcode_Solutions/Python/219._contains_duplicate_ii.md @@ -1,99 +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 -``` +# 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/leetcode/python/221._maximal_square.md b/docs/Leetcode_Solutions/Python/221._maximal_square.md similarity index 100% rename from docs/leetcode/python/221._maximal_square.md rename to docs/Leetcode_Solutions/Python/221._maximal_square.md diff --git a/docs/leetcode/python/222._count_complete_tree_nodes.md b/docs/Leetcode_Solutions/Python/222._count_complete_tree_nodes.md similarity index 100% rename from docs/leetcode/python/222._count_complete_tree_nodes.md rename to docs/Leetcode_Solutions/Python/222._count_complete_tree_nodes.md diff --git a/docs/leetcode/python/223._rectangle_area.md b/docs/Leetcode_Solutions/Python/223._rectangle_area.md similarity index 89% rename from docs/leetcode/python/223._rectangle_area.md rename to docs/Leetcode_Solutions/Python/223._rectangle_area.md index 1f5dd34c5..90a69fa37 100644 --- a/docs/leetcode/python/223._rectangle_area.md +++ b/docs/Leetcode_Solutions/Python/223._rectangle_area.md @@ -1,51 +1,51 @@ -# 223. Rectangle Area -**难度: 中等** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/rectangle-area - -> 内容描述 - -``` -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) -``` - - +# 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/leetcode/python/224._Basic_Calculator.md b/docs/Leetcode_Solutions/Python/224. Basic Calculator .md similarity index 100% rename from docs/leetcode/python/224._Basic_Calculator.md rename to docs/Leetcode_Solutions/Python/224. Basic Calculator .md diff --git a/docs/leetcode/python/225._implement_stack_using_queues.md b/docs/Leetcode_Solutions/Python/225._implement_stack_using_queues.md similarity index 99% rename from docs/leetcode/python/225._implement_stack_using_queues.md rename to docs/Leetcode_Solutions/Python/225._implement_stack_using_queues.md index 9f61d9722..10a1ac200 100644 --- a/docs/leetcode/python/225._implement_stack_using_queues.md +++ b/docs/Leetcode_Solutions/Python/225._implement_stack_using_queues.md @@ -13,7 +13,7 @@ Easy 又到了作弊神预言Python的强项 -``` +``` class Stack(object): def __init__(self): """ diff --git a/docs/Leetcode_Solutions/Python/226._invert_binary_tree.md b/docs/Leetcode_Solutions/Python/226._invert_binary_tree.md new file mode 100644 index 000000000..afcb20bea --- /dev/null +++ b/docs/Leetcode_Solutions/Python/226._invert_binary_tree.md @@ -0,0 +1,60 @@ +# 226. Invert Binary Tree + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/invert-binary-tree/description/ + +> 内容描述 + +``` +Invert a binary tree. + +Example: + +Input: + + 4 + / \ + 2 7 + / \ / \ +1 3 6 9 +Output: + + 4 + / \ + 7 2 + / \ / \ +9 6 3 1 +Trivia: +This problem was inspired by this original tweet by Max Howell: + +Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so f*** off. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +典型的递归题 + + +```python +class Solution(object): + def invertTree(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + if not root: + return root + root.left, root.right = root.right, root.left + self.invertTree(root.left) + self.invertTree(root.right) + return root +``` + diff --git a/docs/leetcode/python/227._basic_calculator_ii.md b/docs/Leetcode_Solutions/Python/227._basic_calculator_ii.md similarity index 100% rename from docs/leetcode/python/227._basic_calculator_ii.md rename to docs/Leetcode_Solutions/Python/227._basic_calculator_ii.md diff --git a/docs/leetcode/python/228._summary_ranges.md b/docs/Leetcode_Solutions/Python/228._summary_ranges.md similarity index 96% rename from docs/leetcode/python/228._summary_ranges.md rename to docs/Leetcode_Solutions/Python/228._summary_ranges.md index 27486605e..ce9dce0f9 100644 --- a/docs/leetcode/python/228._summary_ranges.md +++ b/docs/Leetcode_Solutions/Python/228._summary_ranges.md @@ -1,58 +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) +### 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/leetcode/python/229._majority_element_ii.md b/docs/Leetcode_Solutions/Python/229._majority_element_ii.md similarity index 100% rename from docs/leetcode/python/229._majority_element_ii.md rename to docs/Leetcode_Solutions/Python/229._majority_element_ii.md diff --git a/docs/Leetcode_Solutions/Python/230._kth_smallest_element_in_a_bst.md b/docs/Leetcode_Solutions/Python/230._kth_smallest_element_in_a_bst.md new file mode 100644 index 000000000..3a14adb30 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/230._kth_smallest_element_in_a_bst.md @@ -0,0 +1,113 @@ +# 230. Kth Smallest Element in a BST + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/kth-smallest-element-in-a-bst/description/ + +> 内容描述 + +``` +Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. + +Note: +You may assume k is always valid, 1 ≤ k ≤ BST's total elements. + +Example 1: + +Input: root = [3,1,4,null,2], k = 1 + 3 + / \ + 1 4 + \ + 2 +Output: 1 +Example 2: + +Input: root = [5,3,6,2,4,null,null,1], k = 3 + 5 + / \ + 3 6 + / \ + 2 4 + / + 1 +Output: 3 +Follow up: +What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine? +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +跟昨天做的一道题类似,一上来就走取巧之路。 + +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) +``` + +> 思路 2 +******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)****** + +现在看到kth 就条件反射的想用divide & conquer, 扫root的左子树看nodes量,如果nodes数量是k-1,那么root就刚好是第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 + + +```python +class Solution: + def kthSmallest(self, root, k): + """ + :type root: TreeNode + :type k: int + :rtype: int + """ + def count(node): + if not node: + return 0 + return count(node.left) + count(node.right) + 1 + + if not root: + return None + left = count(root.left) + if left == k - 1: + return root.val + elif left > k - 1: + return self.kthSmallest(root.left, k) + else: + return self.kthSmallest(root.right, k - left - 1) +``` diff --git a/docs/leetcode/python/231._Power_of_Two.md b/docs/Leetcode_Solutions/Python/231. _Power_of_Two.md similarity index 100% rename from docs/leetcode/python/231._Power_of_Two.md rename to docs/Leetcode_Solutions/Python/231. _Power_of_Two.md diff --git a/docs/leetcode/python/232._implement_queue_using_stacks.md b/docs/Leetcode_Solutions/Python/232._implement_queue_using_stacks.md similarity index 100% rename from docs/leetcode/python/232._implement_queue_using_stacks.md rename to docs/Leetcode_Solutions/Python/232._implement_queue_using_stacks.md diff --git a/docs/leetcode/python/234._palindrome_linked_list.md b/docs/Leetcode_Solutions/Python/234._palindrome_linked_list.md similarity index 100% rename from docs/leetcode/python/234._palindrome_linked_list.md rename to docs/Leetcode_Solutions/Python/234._palindrome_linked_list.md diff --git a/docs/Leetcode_Solutions/Python/235._lowest_common_ancestor_of_a_binary_search_tree.md b/docs/Leetcode_Solutions/Python/235._lowest_common_ancestor_of_a_binary_search_tree.md new file mode 100644 index 000000000..4e6a02622 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/235._lowest_common_ancestor_of_a_binary_search_tree.md @@ -0,0 +1,71 @@ +# 235. Lowest Common Ancestor of a Binary Search Tree + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/ + +> 内容描述 + +``` +Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST. + +According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).” + +Given binary search tree: root = [6,2,8,0,4,7,9,null,null,3,5] + + _______6______ + / \ + ___2__ ___8__ + / \ / \ + 0 _4 7 9 + / \ + 3 5 +Example 1: + +Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 +Output: 6 +Explanation: The LCA of nodes 2 and 8 is 6. +Example 2: + +Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 +Output: 2 +Explanation: The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself + according to the LCA definition. +Note: + +All of the nodes' values will be unique. +p and q are different and both values will exist in the BST. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +- 两个node,一个大于root,一个小于root,那么它们必定在root两边,共同的ancestor是root +- 两个node,都比node小,到左边去寻找,那么先找到那个必定是common ancestor +- 两个node,都比node大,类似.... + + + +```python +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + if not root: + return root + if root.val > p.val and root.val > q.val: + return self.lowestCommonAncestor(root.left, p, q) + if root.val < p.val and root.val < q.val: + return self.lowestCommonAncestor(root.right, p, q) + return root +``` diff --git a/docs/Leetcode_Solutions/Python/236._lowest_common_ancestor_of_a_binary_tree.md b/docs/Leetcode_Solutions/Python/236._lowest_common_ancestor_of_a_binary_tree.md new file mode 100644 index 000000000..244969559 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/236._lowest_common_ancestor_of_a_binary_tree.md @@ -0,0 +1,108 @@ +# 236. Lowest Common Ancestor of a Binary Tree + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/ + +> 内容描述 + +``` +Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. + +According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).” + +Given the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4] + + _______3______ + / \ + ___5__ ___1__ + / \ / \ + 6 _2 0 8 + / \ + 7 4 +Example 1: + +Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 +Output: 3 +Explanation: The LCA of of nodes 5 and 1 is 3. +Example 2: + +Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 +Output: 5 +Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself + according to the LCA definition. +Note: + +All of the nodes' values will be unique. +p and q are different and both values will exist in the binary tree. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +1. Find path from root to n1 and store it in a vector or array. +2. Find path from root to n2 and store it in another vector or array. +3. Traverse both paths till the values in arrays are same. Return the common element just before the mismatch. + +时间复杂度worst case 是O(N),空间is the same +```python +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + def findPath(root, path, node): + if not root: + return False + path.append(root) + if root == node: + return True + if (root.left and findPath(root.left, path, node)) or (root.right and findPath(root.right, path, node)): + return True + path.pop() + return False + path_p, path_q = [], [] + if not findPath(root, path_p, p) or not findPath(root, path_q, q): + return -1 + i = 0 + while i < len(path_p) and i < len(path_q): + if path_p[i] != path_q[i]: + break + i += 1 + return path_p[i-1] +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +看代码才是最容易懂的,直接看吧 + +```python +class Solution(object): + pathp, pathq = [], [] + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + if not root or root == p or root == q: + return root + left = self.lowestCommonAncestor(root.left, p, q) + right = self.lowestCommonAncestor(root.right, p, q) + if left and right: + return root + return left or right +``` diff --git a/docs/leetcode/python/237._delete_node_in_a_linked_list.md b/docs/Leetcode_Solutions/Python/237._delete_node_in_a_linked_list.md similarity index 96% rename from docs/leetcode/python/237._delete_node_in_a_linked_list.md rename to docs/Leetcode_Solutions/Python/237._delete_node_in_a_linked_list.md index cd8be88c9..d401e090d 100644 --- a/docs/leetcode/python/237._delete_node_in_a_linked_list.md +++ b/docs/Leetcode_Solutions/Python/237._delete_node_in_a_linked_list.md @@ -1,52 +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 -``` +### 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/leetcode/python/238._product_of_array_except_self.md b/docs/Leetcode_Solutions/Python/238._product_of_array_except_self.md similarity index 100% rename from docs/leetcode/python/238._product_of_array_except_self.md rename to docs/Leetcode_Solutions/Python/238._product_of_array_except_self.md diff --git a/docs/leetcode/python/240._search_a_2d_matrix_ii.md b/docs/Leetcode_Solutions/Python/240._search_a_2d_matrix_ii.md similarity index 100% rename from docs/leetcode/python/240._search_a_2d_matrix_ii.md rename to docs/Leetcode_Solutions/Python/240._search_a_2d_matrix_ii.md diff --git a/docs/leetcode/python/242._valid_anagram.md b/docs/Leetcode_Solutions/Python/242._valid_anagram.md similarity index 100% rename from docs/leetcode/python/242._valid_anagram.md rename to docs/Leetcode_Solutions/Python/242._valid_anagram.md diff --git a/docs/leetcode/python/249._Group_Shifted_Strings.md b/docs/Leetcode_Solutions/Python/249._Group_Shifted_Strings.md similarity index 95% rename from docs/leetcode/python/249._Group_Shifted_Strings.md rename to docs/Leetcode_Solutions/Python/249._Group_Shifted_Strings.md index 2c31ed30c..1ad1c478d 100644 --- a/docs/leetcode/python/249._Group_Shifted_Strings.md +++ b/docs/Leetcode_Solutions/Python/249._Group_Shifted_Strings.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/group-shifted-strings +* https://leetcode.com/problems/group-shifted-strings/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/251._Flatten_2D_Vector.md b/docs/Leetcode_Solutions/Python/251._Flatten_2D_Vector.md new file mode 100644 index 000000000..4032191c8 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/251._Flatten_2D_Vector.md @@ -0,0 +1,71 @@ +# 251. Flatten 2D Vector + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/flatten-2d-vector/discuss/67653/My-Python-Solution + +> 内容描述 + +``` +Implement an iterator to flatten a 2d vector. + +Example: + +Input: 2d vector = +[ + [1,2], + [3], + [4,5,6] +] +Output: [1,2,3,4,5,6] +Explanation: By calling next repeatedly until hasNext returns false, + the order of elements returned by next should be: [1,2,3,4,5,6]. +``` + +## 解题方案 + +> 思路 1 + + +```python +class Vector2D(object): + + def __init__(self, vec2d): + """ + Initialize your data structure here. + :type vec2d: List[List[int]] + """ + self.row = 0 + self.col = 0 + self.vec = vec2d + + + def next(self): + """ + :rtype: int + """ + res = self.vec[self.row][self.col] + self.col += 1 + return res + + + def hasNext(self): + """ + :rtype: bool + """ + while self.row < len(self.vec): + if self.col < len(self.vec[self.row]): + return True + self.col = 0 + self.row += 1 + return False + + +# Your Vector2D object will be instantiated and called as such: +# i, v = Vector2D(vec2d), [] +# while i.hasNext(): v.append(i.next()) +``` diff --git a/docs/Leetcode_Solutions/Python/252._Meeting_Rooms.md b/docs/Leetcode_Solutions/Python/252._Meeting_Rooms.md new file mode 100644 index 000000000..7f434db8d --- /dev/null +++ b/docs/Leetcode_Solutions/Python/252._Meeting_Rooms.md @@ -0,0 +1,50 @@ +# 252. Meeting Rooms + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/meeting-rooms/description/ + +> 内容描述 + +``` +Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), determine if a person could attend all meetings. + +Example 1: + +Input: [[0,30],[5,10],[15,20]] +Output: false +Example 2: + +Input: [[7,10],[2,4]] +Output: true +``` + +## 解题方案 + +> 思路 1 + + +排个序然后看看后面meeting的start会不会比前面meeting的end小,如果有立刻就返回False,全都没有那就返回True + + + + +```python +class Solution(object): + def canAttendMeetings(self, intervals): + """ + :type intervals: List[Interval] + :rtype: bool + """ + if not intervals or len(intervals) < 2: + return True + intervals = sorted(intervals, key=lambda x:(x.start, x.end)) + for i in range(1, len(intervals)): + if intervals[i].start < intervals[i-1].end: + return False + return True +``` diff --git a/docs/Leetcode_Solutions/Python/253._Meeting_Rooms_II.md b/docs/Leetcode_Solutions/Python/253._Meeting_Rooms_II.md new file mode 100644 index 000000000..890a2f6d2 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/253._Meeting_Rooms_II.md @@ -0,0 +1,69 @@ +# 253. Meeting Rooms II + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/meeting-rooms-ii/description/ + +> 内容描述 + +``` +Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), find the minimum number of conference rooms required. + +Example 1: + +Input: [[0, 30],[5, 10],[15, 20]] +Output: 2 +Example 2: + +Input: [[7,10],[2,4]] +Output: 1 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +想象一下,现实生活中,先开始的会议还没结束前我们就又要开始一个会议的话,此时我们需要一个新的会议室 + +如果前面一堆先开始的会议都先于我们的新会议开始之前结束了,我们不需要新会议室 + +换句话说,如果前面一堆新开始的会议中结束最早的那个会议如果在新开始的会议之前结束了的话,我们不需要会议室 + + +所以我们的思路是,先按照会议开始的时间排序,然后维护一个会议结束时间的最小堆,堆顶就是前面结束最早的那个会议的结束时间 + +那么对于一个新的会议出现时: +- 如果堆顶元素比新会议的开始时间更小的话,我们不需要新会议室。同时因为后面出现的新会议的开始时间更大了, +所以目前最先结束的会议永远不可能比后面新出现的会议的开始时间更大,因此我们可以pop目前最先结束的会议,即pop堆顶元素,并且将新会议的结束时间放进堆中 +- 如果堆顶元素比新会议的开始时间更大的话,我们知道我们需要一个新的会议室,此时直接将新会议的结束时间放进堆中 + +最终堆的size就是我们需要的会议室数量 + +```python +from heapq import heappush, heappop +class Solution(object): + def minMeetingRooms(self, intervals): + """ + :type intervals: List[Interval] + :rtype: int + """ + if not intervals: + return 0 + + intervals.sort(key = lambda x:x.start) + end = [] + for it in intervals: + # if the first finished meeting m1 ends before the next meeting + # we can directly pop m1, because there is no need to add a new room + if end and end[0] <= it.start: + heappop(end) + heappush(end, it.end) + + return len(end) +``` diff --git a/docs/Leetcode_Solutions/Python/254._Factor_Combinations.md b/docs/Leetcode_Solutions/Python/254._Factor_Combinations.md new file mode 100644 index 000000000..c3e0ff5ae --- /dev/null +++ b/docs/Leetcode_Solutions/Python/254._Factor_Combinations.md @@ -0,0 +1,144 @@ +# 254. Factor Combinations + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/factor-combinations/description/ + +> 内容描述 + +``` +Numbers can be regarded as product of its factors. For example, + +8 = 2 x 2 x 2; + = 2 x 4. +Write a function that takes an integer n and return all possible combinations of its factors. + +Note: + +You may assume that n is always positive. +Factors should be greater than 1 and less than n. +Example 1: + +Input: 1 +Output: [] +Example 2: + +Input: 37 +Output:[] +Example 3: + +Input: 12 +Output: +[ + [2, 6], + [2, 2, 3], + [3, 4] +] +Example 4: + +Input: 32 +Output: +[ + [2, 16], + [2, 2, 8], + [2, 2, 2, 4], + [2, 2, 2, 2, 2], + [2, 4, 4], + [4, 8] +] +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + + +就每次遍历到sqrt(n)就够了,再往后面过去其实重复了, beats 62.6% + +```python +class Solution(object): + def getFactors(self, n): + """ + :type n: int + :rtype: List[List[int]] + """ + from math import sqrt + if n < 4: + return [] + res = [] + for i in range(2, int(sqrt(n))+1): + if n % i == 0 and i <= n / i: + res.append([i]+[n/i]) + for j in self.getFactors(n/i): + if j and i <= j[0]: + res.append([i]+j) + return res +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +想着用一下memorization会更快一点,果然beats 100% + +```python +class Solution(object): + cache = {} + def getFactors(self, n): + """ + :type n: int + :rtype: List[List[int]] + """ + from math import sqrt + if n < 4: + return [] + if n in self.cache: + return self.cache[n] + else: + res = [] + for i in range(2, int(sqrt(n))+1): + if n % i == 0 and i <= n / i: + res.append([i]+[n/i]) + for j in self.getFactors(n/i): + if j and i <= j[0]: + res.append([i]+j) + self.cache[n] = res + return res +``` + + + +> 思路 3 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +换个思路,每次都先直接append一个最大到res中,然后递归部分只增加一个更大的factor,但其实这种也不是很快,只beats 62.61,跟思路1一样一样的。 + +一直觉得这种类似递归的算法看code最能理解了,我就不多说了,打球去了! + + +```python +class Solution(object): + def getFactors(self, n): + """ + :type n: int + :rtype: List[List[int]] + """ + def helper(n, prev): + # for each recursive part, at least append a larger factor + start = 2 if not prev else prev[-1] + for i in range(start, int(pow(n, 0.5))+1): + if n % i == 0: + helper(n/i, prev+[i]) + if prev: # drectly append the cur largest factor + self.res.append(prev+[n]) + + self.res = [] + helper(n, []) + return self.res +``` diff --git a/docs/leetcode/python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md b/docs/Leetcode_Solutions/Python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md similarity index 100% rename from docs/leetcode/python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md rename to docs/Leetcode_Solutions/Python/255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md diff --git a/docs/leetcode/python/256._Paint_House.md b/docs/Leetcode_Solutions/Python/256. Paint House.md similarity index 100% rename from docs/leetcode/python/256._Paint_House.md rename to docs/Leetcode_Solutions/Python/256. Paint House.md diff --git a/docs/leetcode/python/257._binary_tree_paths.md b/docs/Leetcode_Solutions/Python/257._binary_tree_paths.md similarity index 90% rename from docs/leetcode/python/257._binary_tree_paths.md rename to docs/Leetcode_Solutions/Python/257._binary_tree_paths.md index ff642ec54..c1191e275 100644 --- a/docs/leetcode/python/257._binary_tree_paths.md +++ b/docs/Leetcode_Solutions/Python/257._binary_tree_paths.md @@ -1,83 +1,83 @@ -# 257. Binary Tree Paths -**难度: 简单** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/binary-tree-paths - -> 内容描述 - -``` -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了。 - - - - - - - - - - - - - - - - - - - - - - +# 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/leetcode/python/258._Add_Digits.md b/docs/Leetcode_Solutions/Python/258_ Add_Digits.md similarity index 100% rename from docs/leetcode/python/258._Add_Digits.md rename to docs/Leetcode_Solutions/Python/258_ Add_Digits.md diff --git a/docs/leetcode/python/261._Graph_Valid_Tree.md b/docs/Leetcode_Solutions/Python/261. Graph Valid Tree.md similarity index 100% rename from docs/leetcode/python/261._Graph_Valid_Tree.md rename to docs/Leetcode_Solutions/Python/261. Graph Valid Tree.md diff --git a/docs/leetcode/python/263._ugly_number.md b/docs/Leetcode_Solutions/Python/263._ugly_number.md similarity index 100% rename from docs/leetcode/python/263._ugly_number.md rename to docs/Leetcode_Solutions/Python/263._ugly_number.md diff --git a/docs/leetcode/python/264._ugly_number_ii.md b/docs/Leetcode_Solutions/Python/264._ugly_number_ii.md similarity index 98% rename from docs/leetcode/python/264._ugly_number_ii.md rename to docs/Leetcode_Solutions/Python/264._ugly_number_ii.md index cece144eb..ba1546b9e 100644 --- a/docs/leetcode/python/264._ugly_number_ii.md +++ b/docs/Leetcode_Solutions/Python/264._ugly_number_ii.md @@ -102,39 +102,39 @@ class Solution(object): 还可以优化: 根据页面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 + +``` +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/leetcode/python/265._Paint_House_II.md b/docs/Leetcode_Solutions/Python/265. Paint House II.md similarity index 100% rename from docs/leetcode/python/265._Paint_House_II.md rename to docs/Leetcode_Solutions/Python/265. Paint House II.md diff --git a/docs/leetcode/python/266._Palindrome_Permutation.md b/docs/Leetcode_Solutions/Python/266. Palindrome Permutation.md similarity index 100% rename from docs/leetcode/python/266._Palindrome_Permutation.md rename to docs/Leetcode_Solutions/Python/266. Palindrome Permutation.md diff --git a/docs/leetcode/python/267._Palindrome_Permutation_II.md b/docs/Leetcode_Solutions/Python/267. Palindrome Permutation II.md similarity index 100% rename from docs/leetcode/python/267._Palindrome_Permutation_II.md rename to docs/Leetcode_Solutions/Python/267. Palindrome Permutation II.md diff --git a/docs/Leetcode_Solutions/Python/268._missing_number.md b/docs/Leetcode_Solutions/Python/268._missing_number.md new file mode 100644 index 000000000..3b41c9adb --- /dev/null +++ b/docs/Leetcode_Solutions/Python/268._missing_number.md @@ -0,0 +1,99 @@ +# 268. Missing Number + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/missing-number/description/ + +> 内容描述 + +``` +Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array. + +Example 1: + +Input: [3,0,1] +Output: 2 +Example 2: + +Input: [9,6,4,2,3,5,7,0,1] +Output: 8 +Note: +Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity? +``` + +## 解题方案 + +> 思路 1 + + + + +等差数列前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) +``` + +> 思路 2 + +位运算(异或运算) + + + +```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 +``` + +> 思路 3 + + +让每一个元素都放在正确的index上面,感谢微信上大神 Jay kay的思路,这样写只要给出的nums是非负的就行,应用性更强, +但是这个代码还是无法用于[leetcode 41题:First missing positive](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/041._First_Missing_Positive.md) + +最后元素不等于其index的就是返回值 +```python +class Solution(object): + def missingNumber(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums or len(nums) == 0: + return 0 + if len(nums) == 1: + return 1 if nums[0] == 0 else 0 + for i in range(len(nums)): + tmp = nums[i] + while tmp < len(nums) and nums[tmp] != tmp: + nums[tmp], tmp = tmp, nums[tmp] + for i in range(len(nums)): + if nums[i] != i: + return i + return len(nums) +``` + + + + diff --git a/docs/Leetcode_Solutions/Python/269._Alien_Dictionary.md b/docs/Leetcode_Solutions/Python/269._Alien_Dictionary.md new file mode 100644 index 000000000..a88f2f2ad --- /dev/null +++ b/docs/Leetcode_Solutions/Python/269._Alien_Dictionary.md @@ -0,0 +1,135 @@ +# 269. Alien Dictionary + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/alien-dictionary/description/ + +> 内容描述 + +``` +There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of non-empty words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language. + +Example 1: + +Input: +[ + "wrt", + "wrf", + "er", + "ett", + "rftt" +] + +Output: "wertf" +Example 2: + +Input: +[ + "z", + "x" +] + +Output: "zx" +Example 3: + +Input: +[ + "z", + "x", + "z" +] + +Output: "" + +Explanation: The order is invalid, so return "". +Note: + +You may assume all letters are in lowercase. +You may assume that if a is a prefix of b, then a must appear before b in the given dictionary. +If the order is invalid, return an empty string. +There may be multiple valid order of letters, return any one of them is fine. +``` + +## 解题方案 + +> 思路 1 + +参考大神[seanmsha](https://leetcode.com/problems/alien-dictionary/discuss/156130/Python-Solution-with-Detailed-Explanation-(91))的思路 + + +``` +We want to build a DAG graph so that we can get a possible order that doesn't have any invalid dependencies. First we initialize all of the words with degree 0 (which means that they're the first value in sorted order). We compare every letter by adjacent words (word i and word i+1) Once we find a different letter, we know that the letter in word i+1 is greater than word i so it comes later. We add a degree to the letter in i+1 and add an entry to the letter in word i's dictionary/hashmap signifying that theres an arrow from the letter in word i to the letter in word i+1. We break the loop on the adjacent words because we already found out the reason why word i is before word i+1 (we only get information about at most 1 letter per word). Once we have our degree counts, we traverse the graph (similar to a BFS) from the nodes with degree 0. When we visit a node, we append it to the result string. We subtract one from all of the words repeatedly until all of the words have had degree 0 and have been added to the result string. +In summary: + +1. Initialize all letters in words with degree 0 + +2. For each word i and word i+1 where i+1 原题连接 -* https://leetcode.com/problems/closest-binary-search-tree-value +* https://leetcode.com/problems/closest-binary-search-tree-value/description/ > 内容描述 diff --git a/docs/leetcode/python/276._Paint_Fence.md b/docs/Leetcode_Solutions/Python/276. Paint Fence.md similarity index 100% rename from docs/leetcode/python/276._Paint_Fence.md rename to docs/Leetcode_Solutions/Python/276. Paint Fence.md diff --git a/docs/Leetcode_Solutions/Python/277. Find the Celebrity.md b/docs/Leetcode_Solutions/Python/277. Find the Celebrity.md new file mode 100644 index 000000000..1eb3cf29b --- /dev/null +++ b/docs/Leetcode_Solutions/Python/277. Find the Celebrity.md @@ -0,0 +1,76 @@ +# 277. Find the Celebrity + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/find-the-celebrity/description/ + +> 内容描述 + +``` +Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them. + +Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do is to ask questions like: "Hi, A. Do you know B?" to get information of whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense). + +You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a function int findCelebrity(n), your function should minimize the number of calls to knows. + +Note: There will be exactly one celebrity if he/she is in the party. Return the celebrity's label if there is a celebrity in the party. If there is no celebrity, return -1. +``` + +## 解题方案 + +> 思路 1 + +celebrity 是 每个人都知道他,而他不认识任何别的人。 + +如果用图来看,那就每个别的人都有箭头指向c,而c没有任何出去的箭头。 + +O(N^2)的代码还是还是很容易想到的 + +但是我们可以有提升,那么就是可以check `knows(a,b)`,如果 a knows b,那么可以排除a是celebrity,否则可以排除b是celebrity. + +最后还要确认一遍是否这个是真的celebrity + + + +总的思路就是说先假设0就是celebrity,然后我们依次遍历下去,第一个不认识cele的人new成为新的cele,因为new不认识原来的cele,并且我们知道如果有的cele的话,那么有且只能有一个cele,所以既然new不认识cele,那cele肯定不是真正的cele,所以目前先假设new是新的cele,继续判断下去。最后我们需要遍历再判断一遍,如果任意cele认识某人或者某人不认识cele的情况出现,就说明没有cele了。 + + +AC代码 + +时间复杂度: O(n) +空间复杂度: O(1) + +```python +# 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 + cele = 0 + for i in range(1, n): + if not knows(i, cele): + cele = i + for i in range(n): + if cele != i: + if not knows(i, cele) or knows(cele, i): + return -1 + return cele +``` + + + + + diff --git a/docs/leetcode/python/278._First_Bad_Version.md b/docs/Leetcode_Solutions/Python/278._First_Bad _Version.md similarity index 100% rename from docs/leetcode/python/278._First_Bad_Version.md rename to docs/Leetcode_Solutions/Python/278._First_Bad _Version.md diff --git a/docs/Leetcode_Solutions/Python/279._perfect_squares.md b/docs/Leetcode_Solutions/Python/279._perfect_squares.md new file mode 100644 index 000000000..f4d8bd50f --- /dev/null +++ b/docs/Leetcode_Solutions/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/Leetcode_Solutions/Python/280._Wiggle_Sort.md b/docs/Leetcode_Solutions/Python/280._Wiggle_Sort.md new file mode 100644 index 000000000..13a97f476 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/280._Wiggle_Sort.md @@ -0,0 +1,88 @@ +# 280. Wiggle Sort + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/wiggle-sort/description/ + +> 内容描述 + +``` +Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= nums[2] <= nums[3].... + +Example: + +Input: nums = [3,5,2,1,6,4] +Output: One possible answer is [3,5,1,6,2,4] +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)****** + + + +想的是比如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] +``` + + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +但是貌似想复杂了,其实对于这个简单化,要求只有一个: + +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 range(1, len(nums)): + if (i & 1 == 0 and nums[i] > nums[i-1]) or (i & 1 != 0 and nums[i] < nums[i-1]): + nums[i], nums[i-1] = nums[i-1], nums[i] +``` + + + diff --git a/docs/leetcode/python/283._move_zeroes.md b/docs/Leetcode_Solutions/Python/283._move_zeroes.md similarity index 78% rename from docs/leetcode/python/283._move_zeroes.md rename to docs/Leetcode_Solutions/Python/283._move_zeroes.md index a5e887c05..26d868112 100644 --- a/docs/leetcode/python/283._move_zeroes.md +++ b/docs/Leetcode_Solutions/Python/283._move_zeroes.md @@ -1,19 +1,35 @@ -### 283. Move Zeroes +# 283. Move Zeroes +**难度: Easy** -题目: - +## 刷题内容 +> 原题连接 -难度: -Easy +* https://leetcode.com/problems/move-zeroes/description/ +> 内容描述 -思路: +``` +Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. -### 思路一:暴力 +Example: -```python +Input: [0,1,0,3,12] +Output: [1,3,12,0,0] +Note: + +You must do this in-place without making a copy of the array. +Minimize the total number of operations. +``` + +## 解题方案 + +> 思路 1 + +这个思路不符合题目意思,题目要求in-place + +``` class Solution(object): def moveZeroes(self, nums): """ @@ -26,13 +42,10 @@ class Solution(object): i += 1 nums.extend([0]*i) ``` - -### 思路二: +> 思路 2 一旦遇到不是0的就把它往前移动,移动非0完成,剩下的全部填0,看例子 - - ``` 0 1 0 3 12 @@ -50,6 +63,13 @@ class Solution(object): ``` 1 3 0 3 12 ``` +然后变成 +``` +1 3 12 3 12 + ^ ^ + cur idx +``` + 这样知道变换完成,简直逆天啊,因为cur 总是小于idx,所以总可以保持这样的稳定性 @@ -71,11 +91,10 @@ class Solution(object): while cur < len(nums): nums[cur] = 0 cur += 1 - ``` -### 思路三: +> 思路 3 传统的双指针,参考这里 @@ -106,9 +125,11 @@ class Solution(object): 相反,我觉得这样双指针反而没有上面的代码容易理解 -### 思路四: +> 思路 4 一个比较巧妙的方法: + +这个思路符合题目意思in-place,但是时间复杂度是O(nlgn) ```python class Solution(object): def moveZeroes(self, nums): diff --git a/docs/leetcode/python/285._inorder_successor_in_bst.md b/docs/Leetcode_Solutions/Python/285._inorder_successor_in_bst.md similarity index 97% rename from docs/leetcode/python/285._inorder_successor_in_bst.md rename to docs/Leetcode_Solutions/Python/285._inorder_successor_in_bst.md index b3a941587..aafca56c7 100644 --- a/docs/leetcode/python/285._inorder_successor_in_bst.md +++ b/docs/Leetcode_Solutions/Python/285._inorder_successor_in_bst.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/inorder-successor-in-bst +* https://leetcode.com/problems/inorder-successor-in-bst/description/ > 内容描述 diff --git a/docs/leetcode/python/286._Walls_and_Gates.md b/docs/Leetcode_Solutions/Python/286. Walls and Gates.md similarity index 100% rename from docs/leetcode/python/286._Walls_and_Gates.md rename to docs/Leetcode_Solutions/Python/286. Walls and Gates.md diff --git a/docs/Leetcode_Solutions/Python/287._Find_the_Duplicate_Number.md b/docs/Leetcode_Solutions/Python/287._Find_the_Duplicate_Number.md new file mode 100644 index 000000000..9b8d8b014 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/287._Find_the_Duplicate_Number.md @@ -0,0 +1,161 @@ +# 287. Find the Duplicate Number + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/find-the-duplicate-number/description/ + +> 内容描述 + +``` + +Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one. + +Example 1: + +Input: [1,3,4,2,2] +Output: 2 +Example 2: + +Input: [3,1,3,4,2] +Output: 3 +Note: + +You must not modify the array (assume the array is read only). +You must use only constant, O(1) extra space. +Your runtime complexity should be less than O(n2). +There is only one duplicate number in the array, but it could be repeated more than once. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(1)****** + +参考[小瑶大神](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/287._Find_the_Duplicate_Number.ipynb +)的思路 + +二分枚举答案范围,使用鸽笼原理进行检验 + +根据鸽笼原理,给定 n+1 个范围为 [1, n]的整数,其中一定存在数字出现至少两次。 +假设枚举的数字为 n / 2 : +遍历数组,若数组中不大于 n / 2 的数字个数超过 n / 2 ,则可以确定 [1, n/2] 范围内一定有解,否则可以确定解落在 (n/2, n]范围内。 +也可以这样分析一下: + + +如果n 是5,那么就会有1 2 3 4 5 一共5个数字的可能,而array size 是6,那么其中一个数字肯定会至少出现两次。 + +如果没有重复的数字,小于等于1的数字 出现的次数 等于 1; + +小于等于2的数字 出现的次数 等于 2; + +... 同理3;4;5。 + +如果有重复的数字,如果重复的是1,那么 小于等于1的数字 出现的次数 肯定大于1; + +基于这个理论,我们可以在1 2 3 4 5 选出一个 mid, 遍历array来count 小于等于mid 的数字个数 小于等于 它自己mid 还是 大于 mid? + +如果count 小于等于mid, 说明 1 到 mid 这些数字 没有重复项, 重复项在 右半边 mid 到n, 所以缩小到右半边继续搜索; + +如果count 大于mid, 说明 1 到 mid 这些数字中 有重复项,缩小到 左半边继续搜索。 + +```python +class Solution(object): + def findDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + l, r = 0, len(nums) - 1 + while l <= r: + mid = l +((r-l) >> 2) + count = sum(num <= mid for num in nums) + if count > mid: + r = mid - 1 + else: + l = mid + 1 + return l +``` + +> 思路 2 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(1)****** + +参考[haitao7](https://leetcode.com/haitao7/)大神的思路 + +我们可以用bit的思路来做,basic idea就是,重复出现的那个数字会使得我们在某一位上出现1的次数是异常的 + +比如说[1,3,4,2,2]跟[1, 2, 3, 4]对比: + +- [1, 3, 4, 2, 2] == [001, 011, 100, 010, 010] +- [1, 2, 3, 4] == [001, 010, 011, 100] + +从最小位开始看起,[1, 3, 4, 2, 2]有2个数,1和3,在最小位上是1,[1, 2, 3, 4]也一样。 + +但是在从右往左数第二位,[1, 3, 4, 2, 2]就有3个数[3, 2, 2] == [011, 010, 010],在那个bit上是1;而[1, 2, 3, 4]只有[2, 3]两个。 + +每当发现一个数位上,nums里在那个数位上为1的元素个数,超过了1到n在那个数位上为1的元素个数,我们就可以确定,重复的那个数,在那个数位上肯定是1。如果数位上的1个数相等,则本来那个重复的数字该数位上也是0,不管重复的那个数重复出现多少次,只要多了该数位就是1,没多该数位就是0。 + + +这个算法还是有点慢,可能大家用的都是接下来的这个思路,只beats 了 2% + +```python +class Solution(object): + def findDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + import math + + bits_count = int(math.log(len(nums), 2)) # this is the bits we have + base, duplicate = 1, 0 + for i in range(bits_count+1): # O(logn) for loop + normal, real = 0, 0 + for j in range(len(nums)): # O(n) for loop + normal += (j >> i) & 1 + real += (nums[j] >> i) & 1 + if real > normal: + duplicate += base + base <<= 1 + return duplicate +``` + + + + + +> 思路 3 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +快慢指针,先快慢轮询一遍,再慢慢轮询一遍,就找到了,beats 99.7% +```python +class Solution(object): + def findDuplicate(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + # The "tortoise and hare" step. We start at the end of the array and try + # to find an intersection point in the cycle. + slow, fast = 0, 0 + # Keep advancing 'slow' by one step and 'fast' by two steps until they + # meet inside the loop. + while True: + slow = nums[slow] + fast = nums[nums[fast]] + if slow == fast: + break + # Start up another pointer from the end of the array and march it forward + # until it hits the pointer inside the array. + finder = 0 + while True: + slow = nums[slow] + finder = nums[finder] + # If the two hit, the intersection index is the duplicate element. + if slow == finder: + return slow +``` diff --git a/docs/leetcode/python/289._game_of_life.md b/docs/Leetcode_Solutions/Python/289._game_of_life.md similarity index 100% rename from docs/leetcode/python/289._game_of_life.md rename to docs/Leetcode_Solutions/Python/289._game_of_life.md diff --git a/docs/leetcode/python/290._word_pattern.md b/docs/Leetcode_Solutions/Python/290._word_pattern.md similarity index 100% rename from docs/leetcode/python/290._word_pattern.md rename to docs/Leetcode_Solutions/Python/290._word_pattern.md diff --git a/docs/leetcode/python/292._nim_game.md b/docs/Leetcode_Solutions/Python/292._nim_game.md similarity index 100% rename from docs/leetcode/python/292._nim_game.md rename to docs/Leetcode_Solutions/Python/292._nim_game.md diff --git a/docs/leetcode/python/293._Flip_Game.md b/docs/Leetcode_Solutions/Python/293._Flip_Game.md similarity index 100% rename from docs/leetcode/python/293._Flip_Game.md rename to docs/Leetcode_Solutions/Python/293._Flip_Game.md diff --git a/docs/leetcode/python/296._Best_Meeting_Point.md b/docs/Leetcode_Solutions/Python/296. Best Meeting Point.md similarity index 100% rename from docs/leetcode/python/296._Best_Meeting_Point.md rename to docs/Leetcode_Solutions/Python/296. Best Meeting Point.md diff --git a/docs/leetcode/python/298._Binary_Tree_Longest_Consecutive_Sequence.md b/docs/Leetcode_Solutions/Python/298. Binary Tree Longest Consecutive Sequence.md similarity index 100% rename from docs/leetcode/python/298._Binary_Tree_Longest_Consecutive_Sequence.md rename to docs/Leetcode_Solutions/Python/298. Binary Tree Longest Consecutive Sequence.md diff --git a/docs/leetcode/python/299._bulls_and_cows.md b/docs/Leetcode_Solutions/Python/299._bulls_and_cows.md similarity index 98% rename from docs/leetcode/python/299._bulls_and_cows.md rename to docs/Leetcode_Solutions/Python/299._bulls_and_cows.md index 1d6818460..8b6cbe468 100644 --- a/docs/leetcode/python/299._bulls_and_cows.md +++ b/docs/Leetcode_Solutions/Python/299._bulls_and_cows.md @@ -13,38 +13,38 @@ 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])) +``` +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' ``` diff --git a/docs/Leetcode_Solutions/Python/300._longest_increasing_subsequence.md b/docs/Leetcode_Solutions/Python/300._longest_increasing_subsequence.md new file mode 100644 index 000000000..556041d7a --- /dev/null +++ b/docs/Leetcode_Solutions/Python/300._longest_increasing_subsequence.md @@ -0,0 +1,138 @@ +# 300. Longest Increasing Subsequence + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-increasing-subsequence/description/ + +> 内容描述 + +``` +Given an unsorted array of integers, find the length of longest increasing subsequence. + +Example: + +Input: [10,9,2,5,3,7,101,18] +Output: 4 +Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. +Note: + +There may be more than one LIS combination, it is only necessary for you to return the length. +Your algorithm should run in O(n2) complexity. +Follow up: Could you improve it to O(n log n) time complexity? +``` + +## 解题方案 + +> 思路 1 + +典型DP + +递推关系式: + +对于以num[i]结束的longest increasing subsequence的长度 + +dp[i] = dp[j] + 1 if num[i] > num[j] else dp[i], which 0 <= j < i + +loop一圈,求出最长的 + +AC 代码, 时间复杂度为O(n^2) + +```python +class Solution(object): + def lengthOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums or len(nums) == 0: + return 0 + dp = [1] * len(nums) + for i in range(len(nums)): + for j in range(i): + if nums[i] > nums[j]: + dp[i] = max(dp[j]+1, dp[i]) + return max(dp) +``` + + +## Follow up + +Could you improve it to O(n log n) time complexity? + +> 思路 1 + +参考这篇🐂p的[博客](https://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/): + +自己写二分 + +```python +class Solution(object): + def lengthOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + def binarySearch(nums, l, r, target): + while l <= r: + mid = l + ((r-l) >> 1) + if nums[mid] < target: + l = mid + 1 + else: + r = mid - 1 + return l + + if not nums or len(nums) == 0: + return 0 + + tails = [0 for i in range(len(nums)+1)] + tails[0] = nums[0] + # always points empty slot + length = 1 + for i in range(1, len(nums)): + if (nums[i] < tails[0]): + # new smallest value + tails[0] = nums[i] + elif (nums[i] > tails[length-1]): + # A[i] wants to extend + # largest subsequence + tails[length] = nums[i] + length+=1 + else: + # A[i] wants to be current + # end candidate of an existing + # subsequence. It will replace + # ceil value in tailTable + tails[binarySearch(tails, 0, length-1, nums[i])] = nums[i] + + return length +``` + + +> 思路 2 + +调用自带的二分,并且不维护整个tails,只是慢慢往上面append元素,这样二分查找时不需要手动输入left和right + +```python +class Solution(object): + def lengthOfLIS(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums or len(nums) == 0: + return 0 + + lis = [nums[0]] + for i in range(1, len(nums)): + if nums[i] > lis[-1]: + lis.append(nums[i]) + else: + # 要用bisect_left,因为如果插入到右边就相当于多append了一个,而不再是replace了 + lis[bisect.bisect_left(lis, nums[i])] = nums[i] + + return len(lis) +``` diff --git a/docs/leetcode/python/303._range_sum_query_-_immutable.md b/docs/Leetcode_Solutions/Python/303._range_sum_query_-_immutable.md similarity index 100% rename from docs/leetcode/python/303._range_sum_query_-_immutable.md rename to docs/Leetcode_Solutions/Python/303._range_sum_query_-_immutable.md diff --git a/docs/Leetcode_Solutions/Python/305._Number_of_Islands_II.md b/docs/Leetcode_Solutions/Python/305._Number_of_Islands_II.md new file mode 100644 index 000000000..d4e1c25a6 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/305._Number_of_Islands_II.md @@ -0,0 +1,95 @@ +# 305. Number of Islands II + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/number-of-islands-ii/description/ + +> 内容描述 + +``` +A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand operation which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of islands after each addLand operation. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. + +Example: + +Input: m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]] +Output: [1,1,2,3] +Explanation: + +Initially, the 2d grid grid is filled with water. (Assume 0 represents water and 1 represents land). + +0 0 0 +0 0 0 +0 0 0 +Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land. + +1 0 0 +0 0 0 Number of islands = 1 +0 0 0 +Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land. + +1 1 0 +0 0 0 Number of islands = 1 +0 0 0 +Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land. + +1 1 0 +0 0 1 Number of islands = 2 +0 0 0 +Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land. + +1 1 0 +0 0 1 Number of islands = 3 +0 1 0 +Follow up: + +Can you do it in time complexity O(k log mn), where k is the length of the positions? +``` + +## 解题方案 + +> 思路 1 + +对于positions中的每一个点,我们把他认为是一个单独的岛屿的root,然后我们看看他周围有没有value为1的点(即陆地),如果有,那么那一块陆地的root也是当前点 + +然后每次结束一个点,我们就可以算一下当前一共有几个岛屿,即有几个不同的root,在代码中为```island_groups```的长度 + +这个解法也称为并查集算法,可以去看看[union-find](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/Summarization/union_find.md) + + +```python +class Solution(object): + def numIslands2(self, m, n, positions): + """ + :type m: int + :type n: int + :type positions: List[List[int]] + :rtype: List[int] + """ + # find the root of a point + def find(x, uf): + while x != uf[x]: + uf[x] = uf[uf[x]] + x = uf[x] + return uf[x] + + island_groups, res, uf, idx = set(), [], {}, 1 + for i, j in positions: + uf[(i, j)] = uf[idx] = idx + for x, y in ((i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)): + # when neighbor == 1, we make cur_point as the root + if (x, y) in uf: + root = find(uf[(x, y)], uf) + island_groups.discard(root) + uf[root] = idx + island_groups.add(idx) + idx += 1 + res.append(len(island_groups)) + return res +``` + + +```因为并查集的查找时间复杂度是O(lgN),由于这里N就是m*n,所以我们总的时间复杂度就是O(k*lgmn)``` diff --git a/docs/Leetcode_Solutions/Python/311._Sparse_Matrix_Multiplication.md b/docs/Leetcode_Solutions/Python/311._Sparse_Matrix_Multiplication.md new file mode 100644 index 000000000..e8f33c212 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/311._Sparse_Matrix_Multiplication.md @@ -0,0 +1,78 @@ +# 311. Sparse Matrix Multiplication + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/sparse-matrix-multiplication/description/ + +> 内容描述 + +``` +Given two sparse matrices A and B, return the result of AB. + +You may assume that A's column number is equal to B's row number. + +Example: + +Input: + +A = [ + [ 1, 0, 0], + [-1, 0, 3] +] + +B = [ + [ 7, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 1 ] +] + +Output: + + | 1 0 0 | | 7 0 0 | | 7 0 0 | +AB = | -1 0 3 | x | 0 0 0 | = | -7 0 3 | + | 0 0 1 | +``` + +## 解题方案 + +> 思路 1 + + + +直接搞一个完全的稀疏矩阵然后一个一个地去看,这样万一内存不够怎么办,所以我们基于A建一个非0的新list,然后对应的求出结果,这样操作数会少一些, +并且对内存的要求也没有那么高,借用一句话```I think, in perspective of Big4, they would have a HUGE sparse dataset. +And would like to process them in a machine. +So memory does not fit without the Table representation of sparse matrix. +And this is efficient since can be loaded into a one machine``` + +```python +class Solution(object): + def multiply(self, A, B): + """ + :type A: List[List[int]] + :type B: List[List[int]] + :rtype: List[List[int]] + """ + m, n, nB = len(A), len(A[0]), len(B[0]) + res = [[0] * nB for i in range(m)] + + idxA = [] + for i in range(len(A)): + tmp = [] + for j in range(len(A[0])): + if A[i][j] != 0: + tmp.append(j) + idxA.append(tmp) + print(idxA) + + for i in range(len(idxA)): + for j in idxA[i]: + for k in range(nB): + res[i][k] += A[i][j] * B[j][k] + + return res +``` diff --git a/docs/leetcode/python/316._Remove_Duplicate_Letters.md b/docs/Leetcode_Solutions/Python/316._Remove_Duplicate_Letters.md similarity index 100% rename from docs/leetcode/python/316._Remove_Duplicate_Letters.md rename to docs/Leetcode_Solutions/Python/316._Remove_Duplicate_Letters.md diff --git a/docs/leetcode/python/319._Bulb_Switcher.md b/docs/Leetcode_Solutions/Python/319._Bulb_Switcher.md similarity index 60% rename from docs/leetcode/python/319._Bulb_Switcher.md rename to docs/Leetcode_Solutions/Python/319._Bulb_Switcher.md index 840cce518..c764bbd30 100644 --- a/docs/leetcode/python/319._Bulb_Switcher.md +++ b/docs/Leetcode_Solutions/Python/319._Bulb_Switcher.md @@ -1,15 +1,35 @@ -### 319. Bulb Switcher +# 319. Bulb Switcher -题目: - +**难度: Medium** +## 刷题内容 -难度: +> 原题连接 -Medium +* https://leetcode.com/problems/bulb-switcher/description/ +> 内容描述 -思路 +``` +There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it's off or turning off if it's on). For the i-th round, you toggle every i bulb. For the n-th round, you only toggle the last bulb. Find how many bulbs are on after n rounds. + +Example: + +Input: 3 +Output: 1 +Explanation: +At first, the three bulbs are [off, off, off]. +After first round, the three bulbs are [on, on, on]. +After second round, the three bulbs are [on, off, on]. +After third round, the three bulbs are [on, off, off]. + +So you should return 1, because there is only one bulb is on. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** bulb代表第一轮结束后的所有灯亮灭的情况,从第二轮开始 - 如果是最后一轮,则bulb的最后一个灯要switch @@ -34,6 +54,9 @@ class Solution(object): return bulb.count(1) ``` +> 思路 2 +******- 时间复杂度: O(1)******- 空间复杂度: O(1)****** + 原来,这是一道智商碾压题: > A bulb ends up on iff it is switched an odd number of times. @@ -55,6 +78,10 @@ and double divisor 6. So bulb >i ends up on iff and only if i is a square. So ju 所以编号为12的灯,在第1次,第12次;第2次,第6次;第3次,第4次一定会被执行Switch操作,这样的话,编号为12的灯执行偶数次switch,肯定为灭。 这样推出,完全平方数一定是亮着的,因为它有两个相同的因子,总因子数为奇数,如36 = 6 * 6,所以本题的关键在于找完全平方数的个数。 +为什么时间复杂度是O(1)呢,因为追溯到最底层,求开方就是O(1)的,详细见 +1. [求平方根sqrt()函数的底层算法效率问题](http://www.nowamagic.net/algorithm/algorithm_EfficacyOfFunctionSqrt.php) +2. [Time complexity of Math.Sqrt()?](https://stackoverflow.com/questions/34580158/time-complexity-of-math-sqrt) + ```python class Solution(object): def bulbSwitch(self, n): @@ -62,7 +89,7 @@ class Solution(object): type n: int rtype: int """ - # The number of full squares. + # The number of full/perfect squares. return int(math.sqrt(n)) ``` diff --git a/docs/Leetcode_Solutions/Python/322._Coin_Change.md b/docs/Leetcode_Solutions/Python/322._Coin_Change.md new file mode 100644 index 000000000..dc7d8fc58 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/322._Coin_Change.md @@ -0,0 +1,56 @@ +# 322. Coin Change + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/coin-change/description/ + +> 内容描述 + +``` +You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1. + +Example 1: + +Input: coins = [1, 2, 5], amount = 11 +Output: 3 +Explanation: 11 = 5 + 5 + 1 +Example 2: + +Input: coins = [2], amount = 3 +Output: -1 +Note: +You may assume that you have an infinite number of each kind of coin. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N*amount)******- 空间复杂度: O(amount)****** + +DP入门 + +递推方程式: dp[i] = min(dp[i], dp[i-coins[j]]+1), coins[j] 是硬币的面额 + + + +```python +class Solution(object): + def coinChange(self, coins, amount): + """ + :type coins: List[int] + :type amount: int + :rtype: int + """ + dp = [amount+1] * (amount+1) + dp[0] = 0 + for i in range(1, amount+1): + for j in range(len(coins)): + if coins[j] <= i: + dp[i] = min(dp[i], dp[i-coins[j]]+1) + return -1 if dp[-1] > amount else dp[-1] +``` + diff --git a/docs/leetcode/python/323._number_of_connected_components_in_an_undirected_graph.md b/docs/Leetcode_Solutions/Python/323._number_of_connected_components_in_an_undirected_graph.md similarity index 97% rename from docs/leetcode/python/323._number_of_connected_components_in_an_undirected_graph.md rename to docs/Leetcode_Solutions/Python/323._number_of_connected_components_in_an_undirected_graph.md index 9527b47df..c7d282ae4 100644 --- a/docs/leetcode/python/323._number_of_connected_components_in_an_undirected_graph.md +++ b/docs/Leetcode_Solutions/Python/323._number_of_connected_components_in_an_undirected_graph.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph +* https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/description/ > 内容描述 diff --git a/docs/leetcode/python/324._Wiggle_Sort_II.md b/docs/Leetcode_Solutions/Python/324._Wiggle_Sort_II.md similarity index 100% rename from docs/leetcode/python/324._Wiggle_Sort_II.md rename to docs/Leetcode_Solutions/Python/324._Wiggle_Sort_II.md diff --git a/docs/leetcode/python/326._power_of_three.md b/docs/Leetcode_Solutions/Python/326._power_of_three.md similarity index 94% rename from docs/leetcode/python/326._power_of_three.md rename to docs/Leetcode_Solutions/Python/326._power_of_three.md index 0059d10a4..9cd035d9c 100644 --- a/docs/leetcode/python/326._power_of_three.md +++ b/docs/Leetcode_Solutions/Python/326._power_of_three.md @@ -28,7 +28,7 @@ class Solution(object): ``` -有一个follow up,可否不用 loop/recursion +有一个follow up,可否不用 loop/recusion 看到了取巧的办法,因为是Given an integer,是有范围的(<2147483648),存在能输入的最大的3的幂次,即 3^19=1162261467。 diff --git a/docs/leetcode/python/328._odd_even_linked_list.md b/docs/Leetcode_Solutions/Python/328._odd_even_linked_list.md similarity index 99% rename from docs/leetcode/python/328._odd_even_linked_list.md rename to docs/Leetcode_Solutions/Python/328._odd_even_linked_list.md index 893314630..b628ab241 100644 --- a/docs/leetcode/python/328._odd_even_linked_list.md +++ b/docs/Leetcode_Solutions/Python/328._odd_even_linked_list.md @@ -52,26 +52,26 @@ class Solution(object): 看别人的优雅代码 -``` -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 +``` +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 ``` diff --git a/docs/leetcode/python/334._increasing_triplet_subsequence.md b/docs/Leetcode_Solutions/Python/334._increasing_triplet_subsequence.md similarity index 100% rename from docs/leetcode/python/334._increasing_triplet_subsequence.md rename to docs/Leetcode_Solutions/Python/334._increasing_triplet_subsequence.md diff --git a/docs/leetcode/python/337._house_robber_iii.md b/docs/Leetcode_Solutions/Python/337._house_robber_iii.md similarity index 100% rename from docs/leetcode/python/337._house_robber_iii.md rename to docs/Leetcode_Solutions/Python/337._house_robber_iii.md diff --git a/docs/Leetcode_Solutions/Python/338._Counting_Bits.md b/docs/Leetcode_Solutions/Python/338._Counting_Bits.md new file mode 100644 index 000000000..e96e70c79 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/338._Counting_Bits.md @@ -0,0 +1,132 @@ +# 338. Counting Bits + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/counting-bits/description/ + +> 内容描述 + +``` +Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array. + +Example 1: + +Input: 2 +Output: [0,1,1] +Example 2: + +Input: 5 +Output: [0,1,1,2,1,2] +Follow up: + +It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass? +Space complexity should be O(n). +Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N*k) k is number of bits in num******- 空间复杂度: O(N)****** + + + +**O(n\*sizeof(integer))** 算法,其实就是把count of 1 bit拿来用: + +```python +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 + +``` + + +## Follow up: + +```It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass? +Space complexity should be O(n). +Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language. +``` +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +DP 算法 + +DP 的思路其实不难,就是“把每天当成是末日来相待”,并且这一天发生的事能记下来就记下来。 +转换到实际问题上,就是把每一步都当时是最后一步来操作,然后沿途记下一些以后需要的数据即可。 + +本题是求二进制数中`1`的个数,首先,创建一个数组`dp`,数组的索引`i`就是数字`i`,索引`i`对应的值就是数字`i`二进制数的`1`的个数。 + +我们知道,任何一个十进制数字`num`都可以转换成二进制,并且,转换后的二进制长度是`x = floor(log(num, 2)) + 1`位,这`x`位数字除了第一位是`1`之外,其他位都是`0`或`1`。 + +所以,可以把`num`拆成两个数的和,其中第一个数是`p = 2**(x-1)`,第二个数就是`num - p`。如果`num == p`, 因为`p = 2**(x-1)`中数字`1`的个数是`1`,那么此时`num`的二进制数中的`1`的个数就是`1`,即`dp[num] = 1`,否则,`dp[num] = dp[p] + dp[num-p]`(`num-p`一定小于`p`)。 + +总结一下,关键点在于`c = a + b`,如何找到合适的`a`、`b`. + + + +首先只有一轮循环,在每一轮循环里面有log函数,但是基本上可以忽略不计,所以总时间复杂度为O(N),空间也为O(N) + +```python +class Solution(object): + def countBits(self, num): + """ + :type num: int + :rtype: List[int] + """ + from math import floor, log + dp = [0] * (num+1) + for i in range(1, num+1): + x = floor(log(i, 2)) + 1 + p = int(pow(2, x-1)) + if p == i: + dp[i] = 1 + else: + dp[i] = dp[p] + dp[i-p] + return dp +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +dp的另外一种方法,状态方程为 ```P(x) = P(x&(x-1)) + 1``` + +beats 95.17% + +```python +class Solution(object): + def countBits(self, num): + """ + :type num: int + :rtype: List[int] + """ + dp = [0] * (num+1) + for i in range(1, num+1): + dp[i] = dp[i&(i-1)] + 1 + return dp +``` + + + + + + diff --git a/docs/leetcode/python/339._Nested_List_Weight_Sum.md b/docs/Leetcode_Solutions/Python/339. Nested List Weight Sum.md similarity index 100% rename from docs/leetcode/python/339._Nested_List_Weight_Sum.md rename to docs/Leetcode_Solutions/Python/339. Nested List Weight Sum.md diff --git a/docs/Leetcode_Solutions/Python/340._Longest_Substring_with_At_Most_K_Distinct_Characters.md b/docs/Leetcode_Solutions/Python/340._Longest_Substring_with_At_Most_K_Distinct_Characters.md new file mode 100644 index 000000000..832857c02 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/340._Longest_Substring_with_At_Most_K_Distinct_Characters.md @@ -0,0 +1,59 @@ +# 340. Longest Substring with At Most K Distinct Characters + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/description/ + +> 内容描述 + +``` + +Given a string, find the length of the longest substring T that contains at most k distinct characters. + +Example 1: + +Input: s = "eceba", k = 2 +Output: 3 +Explanation: T is "ece" which its length is 3. +Example 2: + +Input: s = "aa", k = 1 +Output: 2 +Explanation: T is "aa" which its length is 2. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +思路见第159题 + +```python +class Solution(object): + def lengthOfLongestSubstringKDistinct(self, s, k): + """ + :type s: str + :type k: int + :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 > k: + 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/Leetcode_Solutions/Python/341._Flatten_Nested_List_Iterator.md b/docs/Leetcode_Solutions/Python/341._Flatten_Nested_List_Iterator.md new file mode 100644 index 000000000..4ac6ac6c7 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/341._Flatten_Nested_List_Iterator.md @@ -0,0 +1,115 @@ +# 341. Flatten Nested List Iterator + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/flatten-nested-list-iterator/description/ + +> 内容描述 + +``` +Given a nested list of integers, implement an iterator to flatten it. + +Each element is either an integer, or a list -- whose elements may also be integers or other lists. + +Example 1: + +Input: [[1,1],2,[1,1]] +Output: [1,1,2,1,1] +Explanation: By calling next repeatedly until hasNext returns false, + the order of elements returned by next should be: [1,1,2,1,1]. +Example 2: + +Input: [1,[4,[6]]] +Output: [1,4,6] +Explanation: By calling next repeatedly until hasNext returns false, + the order of elements returned by next should be: [1,4,6]. +``` + +## 解题方案 + +> 思路 1 + +这个思路就是先把nestedList里面所有的Integer全部拿出来放到一个stack里面,next()就是简单的拿出下一个,hasNext()就是简单的看看还有没有下一个,但是这样会有一个不好的地方就是如果在现实中,我们的nestedList很大很大,然后我们可能只调用一次next(),那岂不是很亏吗。后面的解法会解决这个问题 + + +```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 != [] +``` + +> 思路 2 + +参考大神[StefanPochmann](https://leetcode.com/problems/flatten-nested-list-iterator/discuss/80146/Real-iterator-in-Python-Java-C++) +其实还是有一个stack,但是每次只把当前非空的nestedList加进来,然后递归嵌套调用的思想,取出最后一个。 + + +```python +class NestedIterator(object): + + def __init__(self, nestedList): + """ + Initialize your data structure here. + :type nestedList: List[NestedInteger] + """ + self.stack = [[nestedList, 0]] + + + def next(self): + """ + :rtype: int + """ + cur_nestedList, i = self.stack[-1] + self.stack[-1][1] += 1 + return cur_nestedList[i] + + + def hasNext(self): + """ + :rtype: bool + """ + s = self.stack + while s: + cur_nestedList, i = s[-1] + if i == len(cur_nestedList): + s.pop() + else: + x = cur_nestedList[i] + if x.isInteger(): # x is a Integer + return True + else: # x is still a nestedList + s[-1][1] += 1 + s.append([x.getList(), 0]) + return False +``` diff --git a/docs/leetcode/python/342._Power_of_Four.md b/docs/Leetcode_Solutions/Python/342._Power_of_Four.md similarity index 100% rename from docs/leetcode/python/342._Power_of_Four.md rename to docs/Leetcode_Solutions/Python/342._Power_of_Four.md diff --git a/docs/leetcode/python/344._reverse_string.md b/docs/Leetcode_Solutions/Python/344._reverse_string.md similarity index 94% rename from docs/leetcode/python/344._reverse_string.md rename to docs/Leetcode_Solutions/Python/344._reverse_string.md index 2346c22e6..0e4c0f4fb 100644 --- a/docs/leetcode/python/344._reverse_string.md +++ b/docs/Leetcode_Solutions/Python/344._reverse_string.md @@ -1,47 +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) -``` +### 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/leetcode/python/345._Reverse_Vowels_of_a_String.md b/docs/Leetcode_Solutions/Python/345._Reverse_Vowels_of_a_String.md similarity index 100% rename from docs/leetcode/python/345._Reverse_Vowels_of_a_String.md rename to docs/Leetcode_Solutions/Python/345._Reverse_Vowels_of_a_String.md diff --git a/docs/Leetcode_Solutions/Python/347._Top_K_Frequent_Elements.md b/docs/Leetcode_Solutions/Python/347._Top_K_Frequent_Elements.md new file mode 100644 index 000000000..db073ec64 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/347._Top_K_Frequent_Elements.md @@ -0,0 +1,92 @@ +# 347. Top K Frequent Elements + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/top-k-frequent-elements/description/ + +> 内容描述 + +``` +Given a non-empty array of integers, return the k most frequent elements. + +Example 1: + +Input: nums = [1,1,1,2,2,3], k = 2 +Output: [1,2] +Example 2: + +Input: nums = [1], k = 1 +Output: [1] +Note: + +You may assume k is always valid, 1 ≤ k ≤ number of unique elements. +Your algorithm's time complexity must be better than O(n log n), where n is the array's size. +``` + +## 解题方案 + +> 思路 1 + +思路就是我们先把对应的数字和其出现频次放到一个map里面,然后对这个maps里面的value()集合做一个for loop,这样我们就可以得到一个list, +list里面的每一个元素代表的就是count为该对应index的key(即数字)的集合 + +例如: +``` +k = 2 +nums = [1,1,1,2,2,3,4,4]时, + +我们的maps就是{1: 3, 2: 2, 3: 1}, +然后我们新建一个buckets, +- count为3的数字有1,我们就令bucktes[3] = [1], +- count为2的数字有2和4,我们就令buckets[2] = [2,4] +- count为1的数字有3,我们就令buckets[1] = [3] + + +最后我们从bucktes的最后一个元素开始遍历,如果该元素不为初始化的'*'的话,我们就把当前元素(type list)的元素全部extend到res中去,最后返回res +``` + + +时间复杂度为O(n) + +```python +class Solution(object): + def topKFrequent(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: List[int] + """ + res, maps, buckets = [], collections.Counter(nums), ['*'] * (len(nums)+1) + + for key in maps.keys(): + count = maps.get(key) + if buckets[count] == '*': + buckets[count] = [] + buckets[count].append(key) + i = len(nums) + while len(res) < k and i >= 0: + if buckets[i] != '*': + res.extend(buckets[i]) + i -= 1 + return res +``` + +> 思路 2 + +如果题目没有要求时间复杂度必须要优于o(nlgn)的话,下面这个解法真的🐂p + + +```python +class Solution(object): + def topKFrequent(self, nums, K): + """ + :type nums: List[int] + :type k: int + :rtype: List[int] + """ + return [k for k,v in sorted(collections.Counter(nums).items(), key=lambda (k,v): -v)][:K] +``` diff --git a/docs/leetcode/python/349._intersection_of_two_arrays.md b/docs/Leetcode_Solutions/Python/349._intersection_of_two_arrays.md similarity index 94% rename from docs/leetcode/python/349._intersection_of_two_arrays.md rename to docs/Leetcode_Solutions/Python/349._intersection_of_two_arrays.md index eb4052736..2f79b8dd9 100644 --- a/docs/leetcode/python/349._intersection_of_two_arrays.md +++ b/docs/Leetcode_Solutions/Python/349._intersection_of_two_arrays.md @@ -1,25 +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)) -``` - +### 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/leetcode/python/350._intersection_of_two_arrays_ii.md b/docs/Leetcode_Solutions/Python/350._intersection_of_two_arrays_ii.md similarity index 94% rename from docs/leetcode/python/350._intersection_of_two_arrays_ii.md rename to docs/Leetcode_Solutions/Python/350._intersection_of_two_arrays_ii.md index b386d9179..d2a444772 100644 --- a/docs/leetcode/python/350._intersection_of_two_arrays_ii.md +++ b/docs/Leetcode_Solutions/Python/350._intersection_of_two_arrays_ii.md @@ -1,65 +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()) -``` - - - - - - - +### 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/leetcode/python/353._Design_Snake_Game.md b/docs/Leetcode_Solutions/Python/353. Design Snake Game.md similarity index 100% rename from docs/leetcode/python/353._Design_Snake_Game.md rename to docs/Leetcode_Solutions/Python/353. Design Snake Game.md diff --git a/docs/leetcode/python/361._Bomb_Enemy.md b/docs/Leetcode_Solutions/Python/361._Bomb_Enemy.md similarity index 100% rename from docs/leetcode/python/361._Bomb_Enemy.md rename to docs/Leetcode_Solutions/Python/361._Bomb_Enemy.md diff --git a/docs/leetcode/python/364._Nested_List_Weight_Sum_II.md b/docs/Leetcode_Solutions/Python/364. Nested List Weight Sum II.md similarity index 100% rename from docs/leetcode/python/364._Nested_List_Weight_Sum_II.md rename to docs/Leetcode_Solutions/Python/364. Nested List Weight Sum II.md diff --git a/docs/leetcode/python/366._Find_Leaves_of_Binary_Tree.md b/docs/Leetcode_Solutions/Python/366. Find Leaves of Binary Tree.md similarity index 100% rename from docs/leetcode/python/366._Find_Leaves_of_Binary_Tree.md rename to docs/Leetcode_Solutions/Python/366. Find Leaves of Binary Tree.md diff --git a/docs/leetcode/python/367._valid_perfect_square.md b/docs/Leetcode_Solutions/Python/367._valid_perfect_square.md similarity index 98% rename from docs/leetcode/python/367._valid_perfect_square.md rename to docs/Leetcode_Solutions/Python/367._valid_perfect_square.md index c51099284..7bb7285d4 100644 --- a/docs/leetcode/python/367._valid_perfect_square.md +++ b/docs/Leetcode_Solutions/Python/367._valid_perfect_square.md @@ -14,19 +14,19 @@ Medium ``` -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 +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 ``` diff --git a/docs/leetcode/python/369._Plus_One_Linked_List.md b/docs/Leetcode_Solutions/Python/369.Plus One Linked List.md similarity index 100% rename from docs/leetcode/python/369._Plus_One_Linked_List.md rename to docs/Leetcode_Solutions/Python/369.Plus One Linked List.md diff --git a/docs/leetcode/python/371._sum_of_two_integers.md b/docs/Leetcode_Solutions/Python/371._sum_of_two_integers.md similarity index 99% rename from docs/leetcode/python/371._sum_of_two_integers.md rename to docs/Leetcode_Solutions/Python/371._sum_of_two_integers.md index f7e949deb..675aa9724 100644 --- a/docs/leetcode/python/371._sum_of_two_integers.md +++ b/docs/Leetcode_Solutions/Python/371._sum_of_two_integers.md @@ -44,16 +44,16 @@ x y output 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; - } +class Solution { +public: + int getSum(int a, int b) { + while (b != 0 ){ + int c = a & b; + a = a ^ b; + b = c << 1; + } + return a; + } }; ``` diff --git a/docs/leetcode/python/374._Guess_Number_Higher_or_Lower.md b/docs/Leetcode_Solutions/Python/374._Guess_Number_Higher_or_Lower.md similarity index 100% rename from docs/leetcode/python/374._Guess_Number_Higher_or_Lower.md rename to docs/Leetcode_Solutions/Python/374._Guess_Number_Higher_or_Lower.md diff --git a/docs/leetcode/python/377._combination_sum_iv.md b/docs/Leetcode_Solutions/Python/377._combination_sum_iv.md similarity index 100% rename from docs/leetcode/python/377._combination_sum_iv.md rename to docs/Leetcode_Solutions/Python/377._combination_sum_iv.md diff --git a/docs/leetcode/python/378._kth_smallest_element_in_a_sorted_matrix.md b/docs/Leetcode_Solutions/Python/378._kth_smallest_element_in_a_sorted_matrix.md similarity index 100% rename from docs/leetcode/python/378._kth_smallest_element_in_a_sorted_matrix.md rename to docs/Leetcode_Solutions/Python/378._kth_smallest_element_in_a_sorted_matrix.md diff --git a/docs/Leetcode_Solutions/Python/380._Insert_Delete_GetRandom_O(1).md b/docs/Leetcode_Solutions/Python/380._Insert_Delete_GetRandom_O(1).md new file mode 100644 index 000000000..1b6113eaa --- /dev/null +++ b/docs/Leetcode_Solutions/Python/380._Insert_Delete_GetRandom_O(1).md @@ -0,0 +1,147 @@ +# 380. Insert Delete GetRandom O(1) + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/insert-delete-getrandom-o1/description/ + +> 内容描述 + +``` +Design a data structure that supports all following operations in average O(1) time. + +insert(val): Inserts an item val to the set if not already present. +remove(val): Removes an item val from the set if present. +getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned. +Example: + +// Init an empty set. +RandomizedSet randomSet = new RandomizedSet(); + +// Inserts 1 to the set. Returns true as 1 was inserted successfully. +randomSet.insert(1); + +// Returns false as 2 does not exist in the set. +randomSet.remove(2); + +// Inserts 2 to the set, returns true. Set now contains [1,2]. +randomSet.insert(2); + +// getRandom should return either 1 or 2 randomly. +randomSet.getRandom(); + +// Removes 1 from the set, returns true. Set now contains [2]. +randomSet.remove(1); + +// 2 was already in the set, so return false. +randomSet.insert(2); + +// Since 2 is the only number in the set, getRandom always return 2. +randomSet.getRandom(); +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(1)******- 空间复杂度: O(N)****** + + + +因为对于插入,删除还有同可能性返回数都要O(1),我们知道以下几种典型的数据结构 +``` +dictionary +list +set +LinkedList +``` +想要删除确定数字必须要知道数字的index,所以list肯定需要,然后怎么通过O(1)时间得到要删除元素的index呢? + +mock的时候我没有想出来,墨汁大佬给了hint才想出来的 + +然后我就想到用字典,key,value分别是element和其index + +然后想要O(1)时间同可能性返回数都要,必须要知道总共有多少个数字,那么就要维护一个self.length才行 + + + + + + +```python +import random +class RandomizedSet(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.cache = {} + self.lst = [] + self.length = 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 + """ + # if this element is not in our RandomizedSet + if val not in self.cache: + # just insert into both of our self.cache and self.lst + self.cache[val] = self.length + self.lst.append(val) + self.length += 1 + return True + else: + return False + + + 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 the elment is in our RandomizedSet + if val in self.cache: + # get the index of element in our self.lst + idx = self.cache[val] + # use the index to update our self.lst + self.lst[idx] = self.lst[-1] # swap the value in index and self.length-1 + # this should be done before pop() operation + # because we may only have one element is self.lst + self.cache[self.lst[idx]] = idx + self.lst.pop() + del self.cache[val] + self.length -= 1 + return True + else: + return False + + + def getRandom(self): + """ + Get a random element from the set. + :rtype: int + """ + # 这种是常规方法 + # idx = random.randint(0, self.length-1) + # return self.lst[idx] + # 神奇函数 + return random.choice(self.lst) + + + +# Your RandomizedSet object will be instantiated and called as such: +# obj = RandomizedSet() +# param_1 = obj.insert(val) +# param_2 = obj.remove(val) +# param_3 = obj.getRandom() +``` + + + diff --git a/docs/leetcode/python/381._Insert_Delete_GetRandom_O(1)_-_Duplicates_allowed.md b/docs/Leetcode_Solutions/Python/381. Insert Delete GetRandom O(1) - Duplicates allowed.md similarity index 100% rename from docs/leetcode/python/381._Insert_Delete_GetRandom_O(1)_-_Duplicates_allowed.md rename to docs/Leetcode_Solutions/Python/381. Insert Delete GetRandom O(1) - Duplicates allowed.md diff --git a/docs/leetcode/python/382._linked_list_random_node.md b/docs/Leetcode_Solutions/Python/382._linked_list_random_node.md similarity index 100% rename from docs/leetcode/python/382._linked_list_random_node.md rename to docs/Leetcode_Solutions/Python/382._linked_list_random_node.md diff --git a/docs/leetcode/python/383._ransom_note.md b/docs/Leetcode_Solutions/Python/383._ransom_note.md similarity index 95% rename from docs/leetcode/python/383._ransom_note.md rename to docs/Leetcode_Solutions/Python/383._ransom_note.md index 82fc223d6..6a6ee16e7 100644 --- a/docs/leetcode/python/383._ransom_note.md +++ b/docs/Leetcode_Solutions/Python/383._ransom_note.md @@ -1,53 +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 -``` +### 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/leetcode/python/384._Shuffle_an_Array.md b/docs/Leetcode_Solutions/Python/384. Shuffle an Array.md similarity index 100% rename from docs/leetcode/python/384._Shuffle_an_Array.md rename to docs/Leetcode_Solutions/Python/384. Shuffle an Array.md diff --git a/docs/leetcode/python/386._Lexicographical_Numbers.md b/docs/Leetcode_Solutions/Python/386._Lexicographical_Numbers.md similarity index 93% rename from docs/leetcode/python/386._Lexicographical_Numbers.md rename to docs/Leetcode_Solutions/Python/386._Lexicographical_Numbers.md index 95eff4ca0..beceeab5a 100644 --- a/docs/leetcode/python/386._Lexicographical_Numbers.md +++ b/docs/Leetcode_Solutions/Python/386._Lexicographical_Numbers.md @@ -6,8 +6,8 @@ > 原题连接 -* https://leetcode.com/problems/lexicographical-numbers -* https://leetcode-cn.com/problems/lexicographical-numbers +* https://leetcode.com/problems/lexicographical-numbers/description/ +* https://leetcode-cn.com/problems/lexicographical-numbers/description/ > 内容描述 diff --git a/docs/leetcode/python/387._first_unique_character_in_a_string.md b/docs/Leetcode_Solutions/Python/387._first_unique_character_in_a_string.md similarity index 100% rename from docs/leetcode/python/387._first_unique_character_in_a_string.md rename to docs/Leetcode_Solutions/Python/387._first_unique_character_in_a_string.md diff --git a/docs/Leetcode_Solutions/Python/388._Longest_Absolute_File_Path.md b/docs/Leetcode_Solutions/Python/388._Longest_Absolute_File_Path.md new file mode 100644 index 000000000..9e1d12614 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/388._Longest_Absolute_File_Path.md @@ -0,0 +1,132 @@ +# 388. Longest Absolute File Path + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-absolute-file-path/description/ + +> 内容描述 + +``` +Suppose we abstract our file system by a string in the following manner: + +The string "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext" represents: + +dir + subdir1 + subdir2 + file.ext +The directory dir contains an empty sub-directory subdir1 and a sub-directory subdir2 containing a file file.ext. + +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 +The directory dir contains two sub-directories subdir1 and subdir2. subdir1 contains a file file1.ext and an empty second-level sub-directory subsubdir1. subdir2 contains a second-level sub-directory subsubdir2 containing a file file2.ext. + +We are interested in finding the longest (number of characters) absolute path to a file within our file system. For example, in the second example above, the longest absolute path is "dir/subdir2/subsubdir2/file2.ext", and its length is 32 (not including the double quotes). + +Given a string representing the file system in the above format, return the length of the longest absolute path to file in the abstracted file system. If there is no file in the system, return 0. + +Note: +The name of a file contains at least a . and an extension. +The name of a directory or sub-directory will not contain a .. +Time complexity required: O(n) where n is the size of the input string. + +Notice that a/aa/aaa/file1.txt is not the longest file path, if there is another path aaaaaaaaaaaaaaaaaaaaa/sth.png. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +我们首先观察到每个```文件夹```或者是```文件```前面都会有一个```'\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"``` + +beats 99.66% + +```python +class Solution(object): + def lengthLongestPath(self, input): + """ + :type input: str + :rtype: int + """ + lap = 0 + depth_len = {0: 0} + for line in input.splitlines(): + name = line.lstrip('\t') + # 前面有几个'\t', depth就是几, 因为'\t'的长度为1 + depth = len(line) - len(name) + if '.' in name: + lap = max(lap, depth_len[depth]+len(name)) + else: + # 加1是为了加上一个path分隔符'/'的长度 + depth_len[depth+1] = depth_len[depth] + 1 + len(name) + return lap +``` + + diff --git a/docs/leetcode/python/389._find_the_difference.md b/docs/Leetcode_Solutions/Python/389._find_the_difference.md similarity index 100% rename from docs/leetcode/python/389._find_the_difference.md rename to docs/Leetcode_Solutions/Python/389._find_the_difference.md diff --git a/docs/Leetcode_Solutions/Python/392._is_subsequence.md b/docs/Leetcode_Solutions/Python/392._is_subsequence.md new file mode 100644 index 000000000..84297dd49 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/392._is_subsequence.md @@ -0,0 +1,185 @@ +# 392. Is Subsequence +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* 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 +******- 时间复杂度: O(len(s)+len(t))******- 空间复杂度: O(1)****** + + +最naive的思路是递归,原来可以beats 53.74% + + +但是今天上来发现多了case,超时过不了了 + +时间复杂度为O(len(s)+len(t)) + + + + +``` +class Solution(object): + def isSubsequence(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + if s == '': + return True + for i in range(len(t)): + if t[i] == s[0]: + return self.isSubsequence(s[1:],t[i+1:]) + + return False +``` + +> 思路 2 +******- 时间复杂度: O(max(len(s), len(t)))******- 空间复杂度: O(1)****** + +因为递归操作以及对字符串的操作太过于昂贵,所以用index来处理,节省了时间和空间 + +时间复杂度是O(max(len(s), len(t))) + +beats 40% + + +```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) +``` +> 思路 3 +******- 时间复杂度: O(len(t))******- 空间复杂度: O(1)****** + + +想到说对于每一个s中的字符,看看在不在,找到了就记录一下t的当前位置idx,下次从t的idx+1后面开始找 + + +```python +class Solution(object): + def isSubsequence(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + idx = 0 + for c in s: + idx = t.find(c, idx) + if idx == -1: + return False + idx += 1 + return True +``` + +## follow up question +``` +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 +******- 时间复杂度: O(lt+k*ms*O(lg(lt)))******- 空间复杂度: O(lt)****** + +我们可以先把t里面的所有字符和其出现的idx的list分别作为key和value放进一个字典里面 + +然后对于s中的每个字符,我们要做两步判断: +1. 如果这个字符不在字典里面,直接返回False +2. 如果这个字符在字典里面,那我们就看看我们在这个字符在t里面出现的idx的list里面是不是有比上一个字符的idx更大的idx, + +例如对于输入 +``` +"abc" +"ahbgdc" +``` + +``` +首先初始化idx为-1 +lookup = {'a': [0], 'c': [5], 'b': [2], 'd': [4], 'g': [3], 'h': [1]} +我们先找字符a,发现a在lookup里面的list为[0],并且里面存在比idx -1更大的元素,所以我们找到了字符a,更新 idx为1,意味着下一个字符要从t的idx 1开始找 +开始找字符b,发现b在lookup里面的list为[2],并且里面存在比idx 1更大的元素,所以我们找到了字符b,更新idx 为3,意味着下一个字符要从t的idx 3开始找 +开始找字符c,发现c在lookup里面的list为[5],并且里面存在比idx 3更大的元素,所以我们找到了字符c,更新idx 为6,意味着下一个字符要从t的idx 6开始找 + +但是此时所有字符都已经找到,直接返回True +``` + +假设t的长度为lt,s的长度为ls,一共有k个s(假设最长的一个s长度为ms) + +我们只需要最开始对整个t做一个遍历,时间复杂度为O(lt),同时用了一个字典,空间复杂度为O(lt), + +然后对于每一个s的每一个字符,我们都只需要进行一个二分查找,时间复杂度为O(lg(lt)),因为最坏有可能t只有一个字符,它在字典里面对应的list的长度就是lt + +因此最终的时间复杂度为O(lt+k*ms*O(lg(lt))),时间复杂度为O(lt) + + +```python +class Solution(object): + def isSubsequence(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + lookup = {} + for i in range(len(t)): + if t[i] in lookup: + lookup[t[i]].append(i) + else: + lookup[t[i]] = [i] + idx = -1 + for c in s: + if c not in lookup: + return False + else: + c_idx = bisect.bisect_left(lookup[c], idx) + if c_idx == len(lookup[c]): # this means we don't find next char of s in t + return False + idx = lookup[c][c_idx] + 1 # we have to find next char from the prev char's index + 1 + return True +``` + + + + diff --git a/docs/leetcode/python/394._decode_string.md b/docs/Leetcode_Solutions/Python/394._decode_string.md similarity index 100% rename from docs/leetcode/python/394._decode_string.md rename to docs/Leetcode_Solutions/Python/394._decode_string.md diff --git a/docs/Leetcode_Solutions/Python/400._Nth_Digit.md b/docs/Leetcode_Solutions/Python/400._Nth_Digit.md new file mode 100644 index 000000000..5dd5f3ccb --- /dev/null +++ b/docs/Leetcode_Solutions/Python/400._Nth_Digit.md @@ -0,0 +1,113 @@ +# 400. Nth Digit + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/nth-digit/description/ + +> 内容描述 + +``` +Find the nth digit of the infinite integer sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... + +Note: +n is positive and will fit within the range of a 32-bit signed integer (n < 231). + +Example 1: + +Input: +3 + +Output: +3 +Example 2: + +Input: +11 + +Output: +0 + +Explanation: +The 11th digit of the sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... is a 0, which is part of the number 10. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(lgn)******- 空间复杂度: O(1)****** + + + +这道简单题我服, tag是math,找规律 + +``` +1- 9 : 9 → 只占1位 9 +10 - 99: 90 → 两位 90 * 2 +100 - 999: 900 → 三位 900 * 3 +1000 - 9999: 9000 → 四位 9000 * 4 +``` +参考微信大佬[caitao7](https://leetcode.com/haitao7/)的代码,加了注释,修改了变量名 + +```python +class Solution(object): + def findNthDigit(self, n): + """ + :type n: int + :rtype: int + """ + digits_count = 1 # 当前区间数字的位数 + while n >= 9 * 10 ** (digits_count-1) * digits_count: + n -= 9 * 10 ** (digits_count-1) * digits_count + digits_count += 1 + target_num = 10 ** (digits_count-1) - 1 + n // digits_count # 我们要从这个数字上面取digit + target_digit = n % digits_count # 我们要从这个数字上面取第几位digit + if target_digit == 0: # 取第0位digit其实就是说这个数字的个数位刚好到达我们的第n位digit + return target_num % 10 + return ((target_num+1) / 10 ** (digits_count-target_digit)) % 10 +``` + + +> 思路 2 +******- 时间复杂度: O(lgn)******- 空间复杂度: O(1)****** + +改进[agave](https://leetcode.com/problems/nth-digit/discuss/88417/4-liner-in-Python-and-complexity-analysis)大神的解法 + +So we can "fast-skip" those numbers until we find the size of the number that will hold our digit. +At the end of the loop, we will have: + +- start: first number of size size (will be power of 10) +- n: will be the number of digits that we need to count after start + +How do we get the number that will hold the digit? It will be start + (n - 1) // size (we use n - 1 because we need zero-based index). Once we have that number, we can get the ```[(n - 1) % size]-th``` digit of that number, and that will be our result. + +```python +class Solution(object): + def findNthDigit(self, n): + """ + :type n: int + :rtype: int + """ + start, size, step = 1, 1, 9 + while n > size * step: + n -= size * step + start, size, step = start * 10, size + 1, step * 10 + num = start + (n - 1) // size # 所要取的数字,(n - 1) % size为取该数字的第几位 + mod = 0 + for i in range(size - (n - 1) % size): + mod = num % 10 + num /= 10 + return mod +``` + +The while loop takes O(log(n)) time because a number n will have at most O(log(n)) digits. Then the return statement takes O(log(n)) time to convert the number to string. So total time complexity is O(log(n)), with O(1) extra space for the string. + + + + + + + diff --git a/docs/leetcode/python/401._binary_watch.md b/docs/Leetcode_Solutions/Python/401._binary_watch.md similarity index 100% rename from docs/leetcode/python/401._binary_watch.md rename to docs/Leetcode_Solutions/Python/401._binary_watch.md diff --git a/docs/Leetcode_Solutions/Python/403._Frog_Jump.md b/docs/Leetcode_Solutions/Python/403._Frog_Jump.md new file mode 100644 index 000000000..df9f9038d --- /dev/null +++ b/docs/Leetcode_Solutions/Python/403._Frog_Jump.md @@ -0,0 +1,161 @@ +# 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^3)******- 空间复杂度: O(N^2)****** + +这个题目肯定要用dp来做的 + +然后我开始找了一个方法,就是让dp[x][y]代表我们可以到达stone x,我们是否可以到达z + +所以初始值就是dp[0][1] = 1 + +如果```dp[x][y] == 1```的话,并且对于一个```z```大于```y```,如果```abs((stones[z] - stones[y]) - (stones[y) - stones[x)) <= 1```, +那么```dp[y][z] = 1``` + +但是超时了 + +```python +class Solution(object): + def canCross(self, stones): + """ + :type stones: List[int] + :rtype: bool + """ + if stones[1] != 1: + return False + + dp = [[0] * len(stones) for i in range(len(stones))] + dp[0][1] = 1 + for y in range(1, len(stones)): + for x in range(y): + for z in range(y+1, len(stones)): + if not dp[x][y]: + continue + else: + if abs((stones[z]-stones[y])-(stones[y]-stones[x])) <= 1: + if z == len(stones)-1: + return True + dp[y][z] = 1 + for i in range(len(dp)): + if dp[i][-1]: + return True + return False +``` + + + + + +> 思路 2 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N^2)****** + +于是想到了另外一种dp,用一个字典,存的key和value分别是stone 的位置和从该位置能跳的步数的set + +初始值位置0的value只有1,那么初始位置1的value有(0,1,2) + +最后我们看看,如果有哪个位置和其value中的任意一个步数的和可以凑齐最后一个位置,那么最后一个位置可达 + +但是这样不是很好判断,其实如果最后一个位置对应的value set非空的话也说明最后一个位置可达,因为不可达我们对其误操作,其value set必为空 + +beats 66.77% +```python +class Solution(object): + def canCross(self, stones): + """ + :type stones: List[int] + :rtype: bool + """ + lookup = {} + for i in range(len(stones)): + lookup[stones[i]] = set() + lookup[0].add(1) + + for i in range(len(stones)): + for step in lookup[stones[i]]: + if step > 0 and stones[i] + step in lookup: + # lookup[stones[i]+step] = lookup[stones[i]+step].union(set([step-1,step,step+1])) + lookup[stones[i]+step].update([step-1,step,step+1]) + return len(lookup[stones[-1]]) > 0 +``` + +或者将value看作可以到达该key的步数,beats 47.71% + +```python +class Solution(object): + def canCross(self, stones): + """ + :type stones: List[int] + :rtype: bool + """ + lookup = {} + for i in range(len(stones)): + lookup[stones[i]] = set() + lookup[0].add(0) + + for i in range(len(stones)): + for k in lookup[stones[i]]: + for step in (k-1,k,k+1): + if step > 0 and stones[i] + step in lookup: + lookup[stones[i]+step].add(step) + return len(lookup[stones[-1]]) > 0 +``` + + + + + + + + + + + + + + + diff --git a/docs/leetcode/python/404._sum_of_left_leaves.md b/docs/Leetcode_Solutions/Python/404._sum_of_left_leaves.md similarity index 100% rename from docs/leetcode/python/404._sum_of_left_leaves.md rename to docs/Leetcode_Solutions/Python/404._sum_of_left_leaves.md diff --git a/docs/leetcode/python/405._Convert_a_Number_to_Hexadecimal.md b/docs/Leetcode_Solutions/Python/405. Convert a Number to Hexadecimal.md similarity index 100% rename from docs/leetcode/python/405._Convert_a_Number_to_Hexadecimal.md rename to docs/Leetcode_Solutions/Python/405. Convert a Number to Hexadecimal.md diff --git a/docs/leetcode/python/406._Queue_Reconstruction_by_Height.md b/docs/Leetcode_Solutions/Python/406._Queue_Reconstruction_by_Height.md similarity index 100% rename from docs/leetcode/python/406._Queue_Reconstruction_by_Height.md rename to docs/Leetcode_Solutions/Python/406._Queue_Reconstruction_by_Height.md diff --git a/docs/leetcode/python/412._fizz_buzz.md b/docs/Leetcode_Solutions/Python/412._fizz_buzz.md similarity index 100% rename from docs/leetcode/python/412._fizz_buzz.md rename to docs/Leetcode_Solutions/Python/412._fizz_buzz.md diff --git a/docs/leetcode/python/413._Arithmetic_Slices.md b/docs/Leetcode_Solutions/Python/413. Arithmetic Slices.md similarity index 100% rename from docs/leetcode/python/413._Arithmetic_Slices.md rename to docs/Leetcode_Solutions/Python/413. Arithmetic Slices.md diff --git a/docs/leetcode/python/414._third_maximum_number.md b/docs/Leetcode_Solutions/Python/414._third_maximum_number.md similarity index 100% rename from docs/leetcode/python/414._third_maximum_number.md rename to docs/Leetcode_Solutions/Python/414._third_maximum_number.md diff --git a/docs/leetcode/python/415._add_strings.md b/docs/Leetcode_Solutions/Python/415._add_strings.md similarity index 94% rename from docs/leetcode/python/415._add_strings.md rename to docs/Leetcode_Solutions/Python/415._add_strings.md index 4c7be7b0a..95663f8e2 100644 --- a/docs/leetcode/python/415._add_strings.md +++ b/docs/Leetcode_Solutions/Python/415._add_strings.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/add-strings +* https://leetcode.com/problems/add-strings/description/ > 内容描述 diff --git a/docs/leetcode/python/416._Partition_Equal_Subset_Sum.md b/docs/Leetcode_Solutions/Python/416._Partition_Equal_Subset_Sum.md similarity index 95% rename from docs/leetcode/python/416._Partition_Equal_Subset_Sum.md rename to docs/Leetcode_Solutions/Python/416._Partition_Equal_Subset_Sum.md index 045089748..1dd92f5fa 100644 --- a/docs/leetcode/python/416._Partition_Equal_Subset_Sum.md +++ b/docs/Leetcode_Solutions/Python/416._Partition_Equal_Subset_Sum.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/partition-equal-subset-sum +* https://leetcode.com/problems/partition-equal-subset-sum/description/ > 内容描述 diff --git a/docs/leetcode/python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md b/docs/Leetcode_Solutions/Python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md similarity index 100% rename from docs/leetcode/python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md rename to docs/Leetcode_Solutions/Python/421._Maximum_XOR_of_Two_Numbers_in_an_Array.md diff --git a/docs/leetcode/python/422._Valid_Word_Square.md b/docs/Leetcode_Solutions/Python/422. Valid Word Square.md similarity index 100% rename from docs/leetcode/python/422._Valid_Word_Square.md rename to docs/Leetcode_Solutions/Python/422. Valid Word Square.md diff --git a/docs/Leetcode_Solutions/Python/424._Longest_Repeating_Character_Replacement.md b/docs/Leetcode_Solutions/Python/424._Longest_Repeating_Character_Replacement.md new file mode 100644 index 000000000..5bebbafea --- /dev/null +++ b/docs/Leetcode_Solutions/Python/424._Longest_Repeating_Character_Replacement.md @@ -0,0 +1,159 @@ +# 424. Longest Repeating Character Replacement + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/longest-repeating-character-replacement/description/ + +> 内容描述 + +``` +Given a string that consists of only uppercase English letters, you can replace any letter in the string with another letter at most k times. Find the length of a longest substring containing all repeating letters you can get after performing the above operations. + +Note: +Both the string's length and k will not exceed 104. + +Example 1: + +Input: +s = "ABAB", k = 2 + +Output: +4 + +Explanation: +Replace the two 'A's with two 'B's or vice versa. +Example 2: + +Input: +s = "AABABBA", k = 1 + +Output: +4 + +Explanation: +Replace the one 'A' in the middle with 'B' and form "AABBBBA". +The substring "BBBB" has the longest repeating letters, which is 4. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +假设我们用来替换别的字符的那个字符是c,那么题目可以转变成这样一个问题,在一个window里面,最多有k个不为c的字符,这样才是满足条件的 + +那么这样的字符c有哪些呢?毫无疑问是set(s)里面的这些字符。 + +然后我们维护一个window,不断计算不为c的字符的个数counter,如果counter大于n了说明我们怎么替换也不行了,我们就要将start往前挪一格,否则一直挪end。 +每次挪完end之后都要记得更新这一轮的最大长度 + +每个字符c循环后都要更新最终res。 + +代码如下:只beats 15% + + +```python +class Solution(object): + def characterReplacement(self, s, k): + """ + :type s: str + :type k: int + :rtype: int + """ + res = 0 + for c in set(s): + start, end, counter, length = 0, 0, 0, 0 + while end < len(s): + if s[end] != c: + counter += 1 + end += 1 # end 永远指向下一个待处理的字符 + while counter > k: + if s[start] != c: + counter -= 1 + start += 1 + length = max(length, end - start) # 因此这里是```end - start```而不是```end - start + 1``` + res = max(res, length) + return res +``` + + + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + + +我们不按照可能的字符来遍历了,我们每次维护一个当前的最大字符频率,如果```end - start + 1 - max_freq > k```我们就知道此时怎么替换都不行了 + +这个时候我们就要将start往前挪一格,对应的东西全都更新一下 + + + +beats 93.46% + + + + +```python +class Solution(object): + def characterReplacement(self, s, k): + """ + :type s: str + :type k: int + :rtype: int + """ + lookup = {} + start, end, max_freq, res = 0, 0, 0, 0 + while end < len(s): + lookup[s[end]] = lookup.get(s[end], 0) + 1 + max_freq = max(max_freq, lookup[s[end]]) + if end - start + 1 - max_freq > k: # 这里为什么用if不用while呢?见下方解析 + lookup[s[start]] -= 1 + start += 1 + end += 1 + res = max(res, end - start) + return res +``` + +上面用if不用while是因为在接下来的变化当中,我们start肯定是要前进一位的,end和max_freq此时没有变化,那么也就是说 +```end - start + 1 - max_freq > k```在经过一次if后就一定不会再满足了,所以这个地方不用while直接用if即可。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/leetcode/python/434._number_of_segments_in_a_string.md b/docs/Leetcode_Solutions/Python/434._number_of_segments_in_a_string.md similarity index 94% rename from docs/leetcode/python/434._number_of_segments_in_a_string.md rename to docs/Leetcode_Solutions/Python/434._number_of_segments_in_a_string.md index a1aa617b2..424472a5a 100644 --- a/docs/leetcode/python/434._number_of_segments_in_a_string.md +++ b/docs/Leetcode_Solutions/Python/434._number_of_segments_in_a_string.md @@ -1,27 +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的题目就是作弊啊 +### 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/leetcode/python/435._Non-overlapping_Intervals.md b/docs/Leetcode_Solutions/Python/435._Non-overlapping_Intervals.md similarity index 97% rename from docs/leetcode/python/435._Non-overlapping_Intervals.md rename to docs/Leetcode_Solutions/Python/435._Non-overlapping_Intervals.md index 581fb1982..b9f6f1dfd 100644 --- a/docs/leetcode/python/435._Non-overlapping_Intervals.md +++ b/docs/Leetcode_Solutions/Python/435._Non-overlapping_Intervals.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/non-overlapping-intervals +* https://leetcode.com/problems/non-overlapping-intervals/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/436._Find_Right_Interval.md b/docs/Leetcode_Solutions/Python/436._Find_Right_Interval.md new file mode 100644 index 000000000..044cb3156 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/436._Find_Right_Interval.md @@ -0,0 +1,153 @@ +# 436. Find Right Interval + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/find-right-interval/description/ + +> 内容描述 + +``` +Given a set of intervals, for each of the interval i, check if there exists an interval j whose start point is bigger than or equal to the end point of the interval i, which can be called that j is on the "right" of i. + +For any interval i, you need to store the minimum interval j's index, which means that the interval j has the minimum start point to build the "right" relationship for interval i. If the interval j doesn't exist, store -1 for the interval i. Finally, you need output the stored value of each interval as an array. + +Note: +You may assume the interval's end point is always bigger than its start point. +You may assume none of these intervals have the same start point. +Example 1: +Input: [ [1,2] ] + +Output: [-1] + +Explanation: There is only one interval in the collection, so it outputs -1. +Example 2: +Input: [ [3,4], [2,3], [1,2] ] + +Output: [-1, 0, 1] + +Explanation: There is no satisfied "right" interval for [3,4]. +For [2,3], the interval [3,4] has minimum-"right" start point; +For [1,2], the interval [2,3] has minimum-"right" start point. +Example 3: +Input: [ [1,4], [2,3], [3,4] ] + +Output: [-1, 2, -1] + +Explanation: There is no satisfied "right" interval for [1,4] and [3,4]. +For [2,3], the interval [3,4] has minimum-"right" start point. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + + +打算先按照start,end排个序,然后只要往后面找就行,虽然是O(N^2),但是稍微小了点,但没想到结果超时。 + +``` +class Solution(object): + def findRightInterval(self, intervals): + """ + :type intervals: List[Interval] + :rtype: List[int] + """ + res = [-1] * len(intervals) + new_intervals = sorted(intervals, key = lambda x: (x.start, x.end)) + lookup = {} + for idx, interval in enumerate(intervals): + lookup[(interval.start, interval.end)] = idx + + for i in range(len(new_intervals)): + for j in range(i+1, len(new_intervals)): + if new_intervals[j].start >= new_intervals[i].end: + look_interval = (new_intervals[i].start, new_intervals[i].end) + look_idx = lookup[look_interval] + next_interval = (new_intervals[j].start, new_intervals[j].end) + next_idx = lookup[next_interval] + res[look_idx] = next_idx + break + return res +``` + +> 思路 2 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + +后面我想到既然所有的start都不一样,我不如搞一个list存排过序的start,然后这样就可以用二分查找来找到第一个大于某end的idx了, +同样的用一个字典来存start和idx的信息。 + +这个二分的思想就是找到第一个大于target的index,思路跟[leetcode第35题](https://github.com/apachecn/awesome-leetcode/blob/master/docs/Leetcode_Solutions/035._search_insert_position.md)一样 + +```python +class Solution(object): + def findRightInterval(self, intervals): + """ + :type intervals: List[Interval] + :rtype: List[int] + """ + res = [-1] * len(intervals) + starts = sorted([i.start for i in intervals]) + lookup = {} + for idx, interval in enumerate(intervals): + lookup[interval.start] = idx + for i in range(len(intervals)): + if starts[-1] < intervals[i].end: + continue + else: + l, r = 0, len(starts) - 1 + target = intervals[i].end + # print(i, l, r, target) + while l <= r: + mid = l + ((r-l) >> 1) + if starts[mid] < target: + l = mid + 1 + else: + r = mid - 1 + res[i] = lookup[starts[l]] + return res +``` + + + + + + +## Follow up + + +就是题目变成 +``` +Given a set of intervals, for each of the interval i, +check if there exists an interval j whose start point is bigger than or equal to the start point of the interval i, +which can be called that j is on the "right" of i. +``` + + +> 思路 1 +******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)****** + + +```python +class Solution(object): + def findRightInterval(self, intervals): + """ + :type intervals: List[Interval] + :rtype: List[int] + """ + res = [-1] * len(intervals) + new_intervals = sorted(intervals, key = lambda x: (x.start, x.end)) + lookup = {} + for idx, interval in enumerate(intervals): + lookup[(interval.start, interval.end)] = idx + for i in range(len(new_intervals)-1): + look_interval = (new_intervals[i].start, new_intervals[i].end) + look_idx = lookup[look_interval] + next_interval = (new_intervals[i+1].start, new_intervals[i+1].end) + next_idx = lookup[next_interval] + res[look_idx] = next_idx + return res +``` diff --git a/docs/leetcode/python/437._path_sum_iii.md b/docs/Leetcode_Solutions/Python/437._path_sum_iii.md similarity index 100% rename from docs/leetcode/python/437._path_sum_iii.md rename to docs/Leetcode_Solutions/Python/437._path_sum_iii.md diff --git a/docs/leetcode/python/438._Find_All_Anagrams_in_a_String.md b/docs/Leetcode_Solutions/Python/438._Find_All_Anagrams_in_a_String.md similarity index 100% rename from docs/leetcode/python/438._Find_All_Anagrams_in_a_String.md rename to docs/Leetcode_Solutions/Python/438._Find_All_Anagrams_in_a_String.md diff --git a/docs/leetcode/python/439._Ternary_Expression_Parser.md b/docs/Leetcode_Solutions/Python/439. Ternary Expression Parser.md similarity index 100% rename from docs/leetcode/python/439._Ternary_Expression_Parser.md rename to docs/Leetcode_Solutions/Python/439. Ternary Expression Parser.md diff --git a/docs/leetcode/python/441._arranging_coins.md b/docs/Leetcode_Solutions/Python/441._arranging_coins.md similarity index 100% rename from docs/leetcode/python/441._arranging_coins.md rename to docs/Leetcode_Solutions/Python/441._arranging_coins.md diff --git a/docs/Leetcode_Solutions/Python/442._Find_All_Duplicates_in_an_Array.md b/docs/Leetcode_Solutions/Python/442._Find_All_Duplicates_in_an_Array.md new file mode 100644 index 000000000..c89c19a27 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/442._Find_All_Duplicates_in_an_Array.md @@ -0,0 +1,89 @@ +# 442. Find All Duplicates in an Array + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/find-all-duplicates-in-an-array/description/ + +> 内容描述 + +``` +Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once. + +Find all the elements that appear twice in this array. + +Could you do it without extra space and in O(n) runtime? + +Example: +Input: +[4,3,2,7,8,2,3,1] + +Output: +[2,3] +``` + +## 解题方案 + +> 思路 1 + +直接用个字典存一下key和出现次数,然后loop一遍 + +- 时间复杂度O(n) +- 空间复杂度O(n) + +```python +class Solution(object): + def findDuplicates(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + res, lookup = [], {} + for num in nums: + lookup[num] = lookup.get(num, 0) + 1 + for key in lookup.keys(): + if lookup[key] == 2: + res.append(key) + return res +``` + + +> 思路 2 + +把每个数字都放到正确的位置上去,a[0] = 1, a[1] = 2, a[2] = 3 ... etc. (1<=a[i]<=n). + +参考[ZhassanB](https://leetcode.com/problems/find-all-duplicates-in-an-array/discuss/92411/Java-O(1)-space-O(n)-time-solution-with-swapping) + +- 时间复杂度O(n) +- 空间复杂度O(1) +```python +class Solution(object): + def findDuplicates(self, nums): + """ + :type nums: List[int] + :rtype: List[int] + """ + if not nums or len(nums) == 0: + return [] + res = [] + i, n = 0, len(nums) + while i < n: # traverse the array till the end + if nums[i] == i+1: # if number stays at it's supposed position, just continue + i += 1 + continue + cur = nums[i] + if cur == -1: # if the duplicate number in that position is already found continue + i += 1 + continue + if nums[cur-1] == cur: # if current num is equals to the number at supposed position, + res.append(cur) # then it is duplicate. + nums[i] = -1 # mark this position, in order to denote that duplicate has found + i += 1 + continue + # if current number's supposed position is occupied by another number swap and consider that number + nums[i], nums[cur-1] = nums[cur-1], nums[i] + return res +``` diff --git a/docs/leetcode/python/448._Find_All_Numbers_Disappeared_in_an_Array.md b/docs/Leetcode_Solutions/Python/448._Find_All_Numbers_Disappeared_in_an_Array.md similarity index 100% rename from docs/leetcode/python/448._Find_All_Numbers_Disappeared_in_an_Array.md rename to docs/Leetcode_Solutions/Python/448._Find_All_Numbers_Disappeared_in_an_Array.md diff --git a/docs/leetcode/python/450._Delete_Node_in_a_BST.md b/docs/Leetcode_Solutions/Python/450. Delete Node in a BST.md similarity index 100% rename from docs/leetcode/python/450._Delete_Node_in_a_BST.md rename to docs/Leetcode_Solutions/Python/450. Delete Node in a BST.md diff --git a/docs/leetcode/python/453._Minimum_Moves_to_Equal_Array_Elements.md b/docs/Leetcode_Solutions/Python/453._Minimum_Moves_to_Equal_Array_Elements.md similarity index 100% rename from docs/leetcode/python/453._Minimum_Moves_to_Equal_Array_Elements.md rename to docs/Leetcode_Solutions/Python/453._Minimum_Moves_to_Equal_Array_Elements.md diff --git a/docs/Leetcode_Solutions/Python/457._Circular_Array_Loop.md b/docs/Leetcode_Solutions/Python/457._Circular_Array_Loop.md new file mode 100644 index 000000000..22ef6f435 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/457._Circular_Array_Loop.md @@ -0,0 +1,104 @@ +# 457. Circular Array Loop + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/circular-array-loop/description/ + +> 内容描述 + +``` + +You are given an array of positive and negative integers. If a number n at an index is positive, then move forward n steps. Conversely, if it's negative (-n), move backward n steps. Assume the first element of the array is forward next to the last element, and the last element is backward next to the first element. Determine if there is a loop in this array. A loop starts and ends at a particular index with more than 1 element along the loop. The loop must be "forward" or "backward'. + +Example 1: Given the array [2, -1, 1, 2, 2], there is a loop, from index 0 -> 2 -> 3 -> 0. + +Example 2: Given the array [-1, 2], there is no loop. + +Note: The given array is guaranteed to contain no element "0". + +Can you do it in O(n) time complexity and O(1) space complexity? +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +快慢指针,然后要注意的是如果loop只有一个元素不算loop,每次找完一圈后发现没有找到的话要将这一路上经过的点全都设为0防止下次重复查找了 + + +```python +class Solution(object): + def circularArrayLoop(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + def get_next_idx(i): + n = len(nums) + return (i + nums[i] + n) % n + + for i, val in enumerate(nums): + if val == 0: + continue + + slow = i + fast = get_next_idx(i) + # make sure always forward or always backward + while nums[fast] * val > 0 and nums[get_next_idx(fast)] * val > 0: + if slow == fast: + # exclude for loop with only one element + if slow == get_next_idx(slow): + break + return True + + slow = get_next_idx(slow) + fast = get_next_idx(get_next_idx(fast)) + + slow = i + # set all the element along the path to 0, avoiding repeated lookup + while nums[slow] * val > 0: + nxt = get_next_idx(slow) + nums[slow] = 0 + slow = nxt + + return False +``` + +或者最后的循环也可以改一下 + +```python +class Solution(object): + def circularArrayLoop(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + def get_nxt_idx(i): + n = len(nums) + return (i+nums[i]+n) % n + + for i, val in enumerate(nums): + slow = i + fast = get_nxt_idx(i) + + while nums[fast] * val > 0 and nums[get_nxt_idx(fast)] * val > 0: + if slow == fast: + if slow == get_nxt_idx(slow): + break + return True + + slow = get_nxt_idx(slow) + fast = get_nxt_idx(get_nxt_idx(fast)) + + fast = get_nxt_idx(i) + while nums[fast] * val > 0: + nxt = get_nxt_idx(get_nxt_idx(fast)) + nums[fast] = 0 + fast = nxt + return False +``` diff --git a/docs/leetcode/python/459._Repeated_Substring_Pattern.md b/docs/Leetcode_Solutions/Python/459._Repeated_Substring_Pattern.md similarity index 100% rename from docs/leetcode/python/459._Repeated_Substring_Pattern.md rename to docs/Leetcode_Solutions/Python/459._Repeated_Substring_Pattern.md diff --git a/docs/leetcode/python/461._Hamming_Distance.md b/docs/Leetcode_Solutions/Python/461._Hamming Distance.md similarity index 51% rename from docs/leetcode/python/461._Hamming_Distance.md rename to docs/Leetcode_Solutions/Python/461._Hamming Distance.md index 4a8d63d81..32b2b3dd6 100644 --- a/docs/leetcode/python/461._Hamming_Distance.md +++ b/docs/Leetcode_Solutions/Python/461._Hamming Distance.md @@ -1,13 +1,41 @@ -### 461. Hamming Distance +# 461. Hamming Distance +**难度: Easy** +## 刷题内容 -题目: - 原题连接 +* https://leetcode.com/problems/hamming-distance/description/ +> 内容描述 -难度 : Easy +``` +The Hamming distance between two integers is the number of positions at which the corresponding bits are different. + +Given two integers x and y, calculate the Hamming distance. + +Note: +0 ≤ x, y < 231. + +Example: + +Input: x = 1, y = 4 + +Output: 2 + +Explanation: +1 (0 0 0 1) +4 (0 1 0 0) + ↑ ↑ + +The above arrows point to positions where the corresponding bits are different. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** @@ -27,7 +55,7 @@ https://en.wikipedia.org/wiki/Hamming_distance > > - +beats 100% 一行无敌 ```python @@ -40,6 +68,14 @@ class Solution(object): """ return bin(x^y).count('1') ``` + + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +不用count,用位运算更快,虽然在这里全部都是beats 100% + AC代码 ```python diff --git a/docs/Leetcode_Solutions/Python/463._Island_Perimeter.md b/docs/Leetcode_Solutions/Python/463._Island_Perimeter.md new file mode 100644 index 000000000..2897ca68e --- /dev/null +++ b/docs/Leetcode_Solutions/Python/463._Island_Perimeter.md @@ -0,0 +1,53 @@ +# 463. Island Perimeter + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/island-perimeter/description/ + +> 内容描述 + +``` +You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represents water. Grid cells are connected horizontally/vertically (not diagonally). The grid is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells). The island doesn't have "lakes" (water inside that isn't connected to the water around the island). One cell is a square with side length 1. The grid is rectangular, width and height don't exceed 100. Determine the perimeter of the island. + +Example: + +[[0,1,0,0], + [1,1,1,0], + [0,1,0,0], + [1,1,0,0]] + +Answer: 16 +Explanation: The perimeter is the 16 yellow stripes in the image below: +``` +![](https://github.com/apachecn/LeetCode/blob/master/images/463/island.png) +## 解题方案 + +> 思路 1 + + +```python +class Solution(object): + def islandPerimeter(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + h = len(grid) + w = len(grid[0]) if h else 0 + res = 0 + # 每一个陆地单元格的周长为4,当两单元格上下或者左右相邻时,令周长减2 + for i in range(h): + for j in range(w): + if grid[i][j] == 1: + res += 4 + # 因为x+1还在后面,所以不需要考虑,即只需要考虑左边和上边,因为循环已经出现过该点了 + if i > 0 and grid[i-1][j]: + res -= 2 + if j > 0 and grid[i][j-1]: + res -= 2 + return res +``` diff --git a/docs/leetcode/python/467._Unique_Substrings_in_Wraparound_String.md b/docs/Leetcode_Solutions/Python/467._Unique_Substrings_in_Wraparound_String.md similarity index 100% rename from docs/leetcode/python/467._Unique_Substrings_in_Wraparound_String.md rename to docs/Leetcode_Solutions/Python/467._Unique_Substrings_in_Wraparound_String.md diff --git a/docs/leetcode/python/469._Convex_Polygon.md b/docs/Leetcode_Solutions/Python/469. Convex Polygon.md similarity index 100% rename from docs/leetcode/python/469._Convex_Polygon.md rename to docs/Leetcode_Solutions/Python/469. Convex Polygon.md diff --git a/docs/leetcode/python/476._Number_Complement.md b/docs/Leetcode_Solutions/Python/476._Number_Complement.md similarity index 100% rename from docs/leetcode/python/476._Number_Complement.md rename to docs/Leetcode_Solutions/Python/476._Number_Complement.md diff --git a/docs/leetcode/python/477._Total_Hamming_Distance.md b/docs/Leetcode_Solutions/Python/477._Total_Hamming_Distance.md similarity index 100% rename from docs/leetcode/python/477._Total_Hamming_Distance.md rename to docs/Leetcode_Solutions/Python/477._Total_Hamming_Distance.md diff --git a/docs/leetcode/python/485._Max_Consecutive_Ones.md b/docs/Leetcode_Solutions/Python/485._Max_Consecutive_Ones.md similarity index 100% rename from docs/leetcode/python/485._Max_Consecutive_Ones.md rename to docs/Leetcode_Solutions/Python/485._Max_Consecutive_Ones.md diff --git a/docs/leetcode/python/494._Target_Sum.md b/docs/Leetcode_Solutions/Python/494._Target_Sum.md similarity index 98% rename from docs/leetcode/python/494._Target_Sum.md rename to docs/Leetcode_Solutions/Python/494._Target_Sum.md index e9ef2f4ce..e9f1a9598 100644 --- a/docs/leetcode/python/494._Target_Sum.md +++ b/docs/Leetcode_Solutions/Python/494._Target_Sum.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/target-sum +* https://leetcode.com/problems/target-sum/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/496._Next_Greater_Element_I.md b/docs/Leetcode_Solutions/Python/496._Next_Greater_Element_I.md new file mode 100644 index 000000000..74a6d8d79 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/496._Next_Greater_Element_I.md @@ -0,0 +1,113 @@ +# 496. Next Greater Element I + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/next-greater-element-i/description/ + +> 内容描述 + +``` +You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1's elements in the corresponding places of nums2. + +The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output -1 for this number. + +Example 1: +Input: nums1 = [4,1,2], nums2 = [1,3,4,2]. +Output: [-1,3,-1] +Explanation: + For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1. + For number 1 in the first array, the next greater number for it in the second array is 3. + For number 2 in the first array, there is no next greater number for it in the second array, so output -1. +Example 2: +Input: nums1 = [2,4], nums2 = [1,2,3,4]. +Output: [3,-1] +Explanation: + For number 2 in the first array, the next greater number for it in the second array is 3. + For number 4 in the first array, there is no next greater number for it in the second array, so output -1. +Note: +All elements in nums1 and nums2 are unique. +The length of both nums1 and nums2 would not exceed 1000. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(len(findNums) * len(nums))******- 空间复杂度: O(len(nums))****** + + + +用一个字典把nums里面的数字和其idx分别作为key和value存下来,然后对于findNums里面的每一个数字,我们只需要看看其在字典中的value, +然后从nums的idx = value+1开始往后找,如果找到了更大的数字就append,没找到出来之后根据flag定位知道要append一个-1 + +beats 57.92% + +```python +class Solution(object): + def nextGreaterElement(self, findNums, nums): + """ + :type findNums: List[int] + :type nums: List[int] + :rtype: List[int] + """ + lookup = {} + for i in range(len(nums)): + lookup[nums[i]] = i + + res = [] + for num in findNums: + idx = lookup[num] + flag = False + for i in range(idx+1, len(nums)): + if nums[i] > num: + res.append(nums[i]) + flag = True + break + if not flag: + res.append(-1) + return res +``` + + +> 思路 2 +******- 时间复杂度: O(len(nums))******- 空间复杂度: O(len(nums))****** + +遍历nums,用栈来存nums里面的数字 + +- while 碰到比栈顶元素更大的元素,我们知道栈顶元素的next greater num就是当前nums[i],pop栈顶,别忘了push nums[i] +- 如果当前栈顶元素比nums[i]更大,只需要push当前nums[i] + +beats 100% + +```python +class Solution(object): + def nextGreaterElement(self, findNums, nums): + """ + :type findNums: List[int] + :type nums: List[int] + :rtype: List[int] + """ + if not nums: + return [] # because findNums is subset of nums + stack = [nums[0]] + lookup = {} + for i in range(1, len(nums)): + # meet larger(than the last number in stack) number + # pop(all the smaller numbers than the current number) + # and set their next greater num to nums[i] + while stack and stack[-1] < nums[i]: + lookup[stack[-1]] = nums[i] + stack = stack[:-1] + stack.append(nums[i]) # don't forget to push nums[i] + # all the nums left in stack has no greater num behind it + for num in stack: + lookup[num] = -1 + res =[] + for num in findNums: + res.append(lookup[num]) + + return res +``` diff --git a/docs/Leetcode_Solutions/Python/507._Perfect_Number.md b/docs/Leetcode_Solutions/Python/507._Perfect_Number.md new file mode 100644 index 000000000..6fe9436fd --- /dev/null +++ b/docs/Leetcode_Solutions/Python/507._Perfect_Number.md @@ -0,0 +1,51 @@ +# 507. Perfect Number + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/perfect-number/description/ + +> 内容描述 + +``` +We define the Perfect Number is a positive integer that is equal to the sum of all its positive divisors except itself. + +Now, given an integer n, write a function that returns true when it is a perfect number and false when it is not. +Example: +Input: 28 +Output: True +Explanation: 28 = 1 + 2 + 4 + 7 + 14 +Note: The input number n will not exceed 100,000,000. (1e8) +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(lgN)******- 空间复杂度: O(1)****** + +用了一个比较巧妙的方法,首先排除一些 corner case,num 小于等于1的时候直接返回 False + +然后后面开始这个方法,就是我们其实不需要对所有小于 num 的数字做遍历,只需要从 2 遍历到 int(sqrt(num)) 即可, +然后每次可以整除的时候都加上当前数字 i 和 num//i,然后初始化的时候让 sums = 1 ,这样最后就是不包含自己的所有因子的和,最后 return sum == num + + +beats 95.73% +```python +from math import sqrt +class Solution(object): + def checkPerfectNumber(self, num): + """ + :type num: int + :rtype: bool + """ + if num <= 1: + return False + sums = 1 + for i in range(2, int(sqrt(num))+1): + if num % i == 0: + sums += i + num // i + return sums == num +``` diff --git a/docs/leetcode/python/536._Construct_Binary_Tree_from_String.md b/docs/Leetcode_Solutions/Python/536._Construct_Binary_Tree_from_String.md similarity index 99% rename from docs/leetcode/python/536._Construct_Binary_Tree_from_String.md rename to docs/Leetcode_Solutions/Python/536._Construct_Binary_Tree_from_String.md index d28194fab..3f000278e 100644 --- a/docs/leetcode/python/536._Construct_Binary_Tree_from_String.md +++ b/docs/Leetcode_Solutions/Python/536._Construct_Binary_Tree_from_String.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/construct-binary-tree-from-string +* https://leetcode.com/problems/construct-binary-tree-from-string/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/547._Friend_Circles.md b/docs/Leetcode_Solutions/Python/547._Friend_Circles.md new file mode 100644 index 000000000..31369032e --- /dev/null +++ b/docs/Leetcode_Solutions/Python/547._Friend_Circles.md @@ -0,0 +1,102 @@ +# 547. Friend Circles + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/friend-circles/description/ + +> 内容描述 + +``` +There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a direct friend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends. + +Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = 1, then the ith and jth students are direct friends with each other, otherwise not. And you have to output the total number of friend circles among all the students. + +Example 1: +Input: +[[1,1,0], + [1,1,0], + [0,0,1]] +Output: 2 +Explanation:The 0th and 1st students are direct friends, so they are in a friend circle. +The 2nd student himself is in a friend circle. So return 2. +Example 2: +Input: +[[1,1,0], + [1,1,1], + [0,1,1]] +Output: 1 +Explanation:The 0th and 1st students are direct friends, the 1st and 2nd students are direct friends, +so the 0th and 2nd students are indirect friends. All of them are in the same friend circle, so return 1. +Note: +N is in range [1,200]. +M[i][i] = 1 for all students. +If M[i][j] = 1, then M[j][i] = 1. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^3)******- 空间复杂度: O(N)****** + +发现一件事,只要是关于这种circle类的题目, +- 第一印象如果是关于链表的那么就想到快慢指针 +- 第二印象如果是关于图的立马想到union-find + +思路就没什么好说的,把这道题看成求图中有多少个联通分量就可以了。 + +时间复杂度是因为两个for loop,并且调用connected方法会调用find方法,find方法最差到O(n),所以最终是O(N^3) + +空间自然就是O(N) + + +```python +class UnionFind(object): + uf = [] # access to component id (site indexed) + count = 0 # number of components + + def uf(self, n): # 初始化uf数组和组数目 + self.count = n + self.uf = [i for i in range(n)] + + def find(self, x): # 判断节点所属于的组 + while x != self.uf[x]: + self.uf[x] = self.uf[self.uf[x]] + x = self.uf[x] + return self.uf[x] + + def union(self, x, y): # 连接两个节点 + x_root = self.find(x) + y_root = self.find(y) + self.uf[x_root] = y_root + self.count -= 1 + + def connected(self, x, y): # 判断两个节点是否联通 + return self.find(x) == self.find(y) + + def count(self): # 返回所有组的数目 + return self.count + + +class Solution(object): + def findCircleNum(self, grid): + """ + :type M: List[List[int]] + :rtype: int + """ + s = UnionFind() + s.uf(len(grid)) + for i in range(len(grid)): + for j in range(len(grid[i])): + # 如果i等于j说明是自己,没必要判断 + # 只有当该位置为1即互为朋友的时候才需要看是否联通 + # 不联通才union,联通也union一来浪费时间二来可能会无故减小count + if j != i and grid[i][j] == 1 and not s.connected(j, i): + s.union(j, i) + return s.count +``` + + diff --git a/docs/Leetcode_Solutions/Python/560._Subarray_Sum_Equals_K.md b/docs/Leetcode_Solutions/Python/560._Subarray_Sum_Equals_K.md new file mode 100644 index 000000000..6821d7b3b --- /dev/null +++ b/docs/Leetcode_Solutions/Python/560._Subarray_Sum_Equals_K.md @@ -0,0 +1,56 @@ +# 560. Subarray Sum Equals K + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/subarray-sum-equals-k/description/ + +> 内容描述 + +``` +Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k. + +Example 1: +Input:nums = [1,1,1], k = 2 +Output: 2 +Note: +The length of the array is in range [1, 20,000]. +The range of numbers in the array is [-1000, 1000] and the range of the integer k is [-1e7, 1e7]. +``` + +## 解题方案 + +> 思路 1 + + +跟two sum一样的题目 + +就不停维护一个当前和的变量,然后每次都check一下```当前和 - k```是否在字典里面,如果存在我们就知道了之前有一坨字符串和的值为```当前和 - k```,然后 +当前和的值就是当前和,所以最近接触的一坨字符串其和必为k + +例如在[1,2,3,4]里面找7,之前存过1+2在字典里面,然后循环到4的时候当前和为10,就看看3在不在字典里面,一看果然有,那么最近一坨的 3+4 = 7,找到了 + +但是这里要注意光找到没用,我们要知道存在多少个,所以字典里面的value对应的就是当前和出现的次数 + +AC 代码: + +```python +class Solution(object): + def subarraySum(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + # 这是为了保证如果当前和的值就等于k的话,我们其实也相当于找到一次 + lookup = {0:1} + res = cur_sum = 0 + for num in nums: + cur_sum += num + res += lookup.get(cur_sum-k, 0) + lookup[cur_sum] = lookup.get(cur_sum, 0) + 1 + return res +``` diff --git a/docs/Leetcode_Solutions/Python/564._Find_the_Closest_Palindrome.md b/docs/Leetcode_Solutions/Python/564._Find_the_Closest_Palindrome.md new file mode 100644 index 000000000..8d4312ddd --- /dev/null +++ b/docs/Leetcode_Solutions/Python/564._Find_the_Closest_Palindrome.md @@ -0,0 +1,118 @@ +# 564. Find the Closest Palindrome + +**难度: Hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/find-the-closest-palindrome/description/ + +> 内容描述 + +``` +Given an integer n, find the closest integer (not including itself), which is a palindrome. + +The 'closest' is defined as absolute difference minimized between two integers. + +Example 1: +Input: "123" +Output: "121" +Note: +The input n is a positive integer represented by string, whose length will not exceed 18. +If there is a tie, return the smaller one as answer. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +前前后后搞了2天,感谢今天下午女朋友和我一起讨论,最终搞出来了。 + +- 总共三种情况,算出后面的,前面的,还有当前的前半部分直接反转黏贴到后半部分。总结一下就是说[前半部分+1,前半部分-1,前半部分自身] + 前面得出结果的反转就是我们可能的结果之一。 +- 另外两种情况就是进位和减位,格式为1000..0001, 999...999 + +5个部分看看哪个更近,唯一需要注意的是输入为10和11的时候handle不了,要在最前面手动处理一下。 + +beats 100%,功夫不负有心人! + +``` +class Solution(object): + def nearestPalindromic(self, n): + """ + :type n: str + :rtype: str + """ + tmp = str(n) + if 9 < int(n) < 12: + return '9' + r_half_len = len(tmp) // 2 + if len(tmp) & 1 == 0: # 长度为偶数 + num_digits = len(str(int(tmp[:len(tmp)/2]))) + half = tmp[:len(tmp)/2] + else: # 长度为奇数 + num_digits = len(str(int(tmp[:(len(tmp)+1)/2]))) + half = tmp[:(len(tmp)+1)/2] + + if len(str(int(half)+1)) > num_digits: # 进位了 + behind = '1' + '0' * (len(tmp)-1) + '1' + else: + behind = str(int(half) + 1)+ str(int(half) + 1)[:r_half_len][::-1] + if len(str(int(half)-1)) < num_digits: # 减位了 + before = '9' * (len(tmp)-1) + else: + before = str(int(half) - 1)+ str(int(half) - 1)[:r_half_len][::-1] + # 当前的前半部分直接反转,如1002,变成了1001 + cur = str(int(half))+ str(int(half))[:r_half_len][::-1] + if cur == tmp[::-1]: + return behind if abs(int(tmp)-int(behind)) < abs(int(tmp)-int(before)) else before + abss = map(lambda x: abs(int(x)-int(tmp)), [before, cur, behind]) + selects = [before, cur, behind] + return selects[abss.index(min(abss))] +``` + +后面我觉得完全可以重构一下代码,behind和before不用非得算出来,我只要把所有的可能性全都放到一个list里面去,最后来判断就行了 + +```python +class Solution(object): + def nearestPalindromic(self, n): + """ + :type n: str + :rtype: str + """ + prefix = int(n[:(len(n)+1)//2]) + + candidates = set(['1' + '0' * (len(n)-1) + '1', '9' * (len(n)-1)]) # 进位减位可能性 + + for i in map(str, [prefix-1, prefix, prefix+1]): # 前半部分+1,-1,+0可能性 + candidates.add(i + [i, i[:-1]][len(n) & 1][::-1]) + + candidates.discard(n) # 除去自身可能就是Palindrome的可能性 + candidates.discard('') # 输入n为个位数的话,我们还会加入空字符串,必须要去掉 + + return min(candidates, key = lambda x: (abs(int(x) - int(n)), int(x))) +``` + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/581._Shortest_Unsorted_Continuous_Subarray.md b/docs/Leetcode_Solutions/Python/581._Shortest_Unsorted_Continuous_Subarray.md new file mode 100644 index 000000000..e53153d72 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/581._Shortest_Unsorted_Continuous_Subarray.md @@ -0,0 +1,176 @@ +# 581. Shortest Unsorted Continuous Subarray + +**难度: 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)****** + +直接sort,然后找出sort前与sort后不同的数组长度 + + +```python +class Solution(object): + def findUnsortedSubarray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + start, end = 0, 0 + sorted_nums = sorted(nums) + + for i in range(len(nums)): + if nums[i] != sorted_nums[i]: + start = i + break + for i in range(len(nums)-1, -1, -1): + if nums[i] != sorted_nums[i]: + end = i + break + + return end - start + 1 if start != end else 0 +``` + +> 思路 2 + ******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +要满足三个性质: + +1. nums[0, i - 1] and nums[j + 1, n - 1] are both sorted. +2. nums[i] != nums_sorted[i] and nums[j] != nums_sorted[j]. +3. nums[i - 1] <= min and max <= nums[j + 1], where min and max are the minimum and maximum values of subarray nums[i, j]. + +所以我们需要做的就是 find the two longest sorted subarrays starting at index 0 and ending at index n - 1 + +- 从左到右找到第一个不满足nums[l] <= nums[l+1]的index l +- 然后从右到左找到第一个不满足nums[r] >= nums[r-1]的 index r +- 然后开始保证第三条性质,只要min(nums[l:r+1]) < nums[l],l就自减1;只要max(nums[l:r+1]) > nums[r], r就自增1; +- 这两个index中间这一坨就是需要我们sort的最短subarray + +参考[fun4LeetCode](https://leetcode.com/problems/shortest-unsorted-continuous-subarray/discuss/103066/Ideas-behind-the-O(n)-two-pass-and-one-pass-solutions) + +two-pass,Finding the longest subarrays and the maximum and minimum values of the middle subarray takes one-pass. +Ensuring the third property requires a second pass. + +```python +class Solution(object): + def findUnsortedSubarray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + l, r = 0, len(nums) - 1 + while l < r and nums[l] <= nums[l+1]: + l += 1 + if l >= r: + return 0 + while nums[r] >= nums[r-1]: + r -= 1 + max_num, min_num = -sys.maxsize, sys.maxsize + + for k in range(l, r+1): + max_num = max(max_num, nums[k]) + min_num = min(min_num, nums[k]) + + while l >= 0 and min_num < nums[l]: + l -= 1 + while r < len(nums) and nums[r] < max_num: + r += 1 + + return r - l - 1 +``` + +> 思路 3 + ******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +这个方法我最推荐了,他其实和思路2一样,但是不用考虑那么多 + +1. 从左到右找到最后一个不符合递增规律的index end +2. 从右到左找到最后一个不符合递增规律的index start +3. 直接返回max(end-start+1, 0), 因为end可能比start小,比如对于输入[1,2,3,3,3],end等于0,start等于4 + +```python +class Solution(object): + def findUnsortedSubarray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + m = nums[0] + end = 0 + for i in range(1, len(nums)): + if nums[i] >= m: + m = nums[i] + else: + end = i + + m = nums[-1] + start = len(nums)-1 + for i in range(len(nums)-1, -1, -1): + if nums[i] <= m: + m = nums[i] + else: + start = i + + if start == end: + return 0 + + return max(end-start+1, 0) +``` + + + + +> 思路 4 + ******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + one-pass + + 这一次我们只需要找到 + +- i is the smallest index such that nums[i] != min[i:] +- j is the largest index such that nums[j] != max[:j+1] + + +```python +class Solution(object): + def findUnsortedSubarray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + i, j = 0, -1 + l, r = 0, len(nums) - 1 + max_num, min_num = -sys.maxsize, sys.maxsize + while r >= 0: + min_num = min(min_num, nums[r]) + # i is the smallest index such that nums[i] != min[i:] + if nums[r] != min_num: + i = r + max_num = max(max_num, nums[l]) + # j is the largest index such that nums[j] != max[:j+1] + if nums[l] != max_num: + j = l + l += 1 + r -= 1 + + return j-i+1 +``` + diff --git a/docs/leetcode/python/587._Erect_the_Fence.md b/docs/Leetcode_Solutions/Python/587._Erect_the_Fence .md similarity index 98% rename from docs/leetcode/python/587._Erect_the_Fence.md rename to docs/Leetcode_Solutions/Python/587._Erect_the_Fence .md index 301c1c1b1..f61d75b3c 100644 --- a/docs/leetcode/python/587._Erect_the_Fence.md +++ b/docs/Leetcode_Solutions/Python/587._Erect_the_Fence .md @@ -130,4 +130,4 @@ Author: Keqi Huang If you like it, please spread your support -![Support](/img/Algorithm/LeetCode/WechatIMG17.jpeg) +![Support](https://github.com/Lisanaaa/myTODOs/blob/master/WechatIMG17.jpeg) diff --git a/docs/Leetcode_Solutions/Python/592._Fraction_Addition_and_Subtraction.md b/docs/Leetcode_Solutions/Python/592._Fraction_Addition_and_Subtraction.md new file mode 100644 index 000000000..cef93a65d --- /dev/null +++ b/docs/Leetcode_Solutions/Python/592._Fraction_Addition_and_Subtraction.md @@ -0,0 +1,115 @@ +# 592. Fraction Addition and Subtraction + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/fraction-addition-and-subtraction/description/ + +> 内容描述 + +``` +Given a string representing an expression of fraction addition and subtraction, you need to return the calculation result in string format. The final result should be irreducible fraction. If your final result is an integer, say 2, you need to change it to the format of fraction that has denominator 1. So in this case, 2 should be converted to 2/1. + +Example 1: +Input:"-1/2+1/2" +Output: "0/1" +Example 2: +Input:"-1/2+1/2+1/3" +Output: "1/3" +Example 3: +Input:"1/3-1/2" +Output: "-1/6" +Example 4: +Input:"5/3+1/3" +Output: "2/1" +Note: +The input string only contains '0' to '9', '/', '+' and '-'. So does the output. +Each fraction (input and output) has format ±numerator/denominator. If the first input fraction or the output is positive, then '+' will be omitted. +The input only contains valid irreducible fractions, where the numerator and denominator of each fraction will always be in the range [1,10]. If the denominator is 1, it means this fraction is actually an integer in a fraction format defined above. +The number of given fractions will be in the range [1,10]. +The numerator and denominator of the final result are guaranteed to be valid and in the range of 32-bit int. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +这个思路真的没啥好说的,就是最小公倍数和最大公约数稍微注意下怎么写就行,然后剩下的就是搬砖活了, 20分钟 bug free,一遍AC,莫名小自豪。。。。 + +```python +class Solution(object): + def fractionAddition(self, expression): + """ + :type expression: str + :rtype: str + """ + def gcd(a, b): + if a == 0: + return b + return gcd(b % a, a) + + def gcm(num1, num2): + return num1 * num2 // gcd(num1, num2) + + def is_sign(expression, index): # 判断符号'-'是否是描述负数的符号 + if expression[i] == '-': + if i - 1 < 0 or expression[i - 1] in oprs: + return True + return False + + oprs = '+-' + units = [] # 保存包含操作符和操作数的列表 + start = 0 # 标记数字起点 + for i in range(len(expression)): + if expression[i] in oprs: + if not is_sign(expression, i): + units.append(expression[start:i]) + units.append(expression[i]) + start = i + 1 + units.append(expression[start:]) + while len(units) > 1: + left, right = 0, 0 + gcmm = gcm(int(units[0].split('/')[1]), int(units[2].split('/')[1])) + if units[0].split('/')[0][0] == '-': + left = int(units[0].split('/')[0].lstrip('-')) * gcmm // int(units[0].split('/')[1]) * (-1) + else: + left = int(units[0].split('/')[0].lstrip('-')) * gcmm // int(units[0].split('/')[1]) + right = int(units[2].split('/')[0]) * gcmm // int(units[2].split('/')[1]) + if units[1] == '+': + units = [str(left + right) + '/' + str(gcmm)] + units[3:] + else: + units = [str(left - right) + '/' + str(gcmm)] + units[3:] + if units[0].split('/')[0].lstrip('-') == '0': + res = units[0].split('/')[0] + '/1' + else: + gcdd = gcd(int(units[0].split('/')[0].lstrip('-')), int(units[0].split('/')[1])) + # print('gcdd',gcdd) + if units[0].split('/')[0][0] == '-': + res = '-' + str(int(units[0].split('/')[0].lstrip('-'))//gcdd) + '/' + str(int(units[0].split('/')[1])//gcdd) + else: + res = str(int(units[0].split('/')[0].lstrip('-'))//gcdd) + '/' + str(int(units[0].split('/')[1])//gcdd) + + return res +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +我怕不是个智障吧,还小自豪,。。。。看了discuss里面[lee215](https://leetcode.com/problems/fraction-addition-and-subtraction/discuss/103387/Python-easy-understood-2-line-solution)大神的答案,我tm。。。。 +```python +class Solution(object): + def fractionAddition(self, expression): + """ + :type expression: str + :rtype: str + """ + from fractions import Fraction + res = sum(map(Fraction, expression.replace('+', ' +').replace('-', ' -').split())) + return str(res.numerator) + '/' + str(res.denominator) +``` diff --git a/docs/Leetcode_Solutions/Python/593._Valid_Square.md b/docs/Leetcode_Solutions/Python/593._Valid_Square.md new file mode 100644 index 000000000..fb61b27fe --- /dev/null +++ b/docs/Leetcode_Solutions/Python/593._Valid_Square.md @@ -0,0 +1,201 @@ +# 593. Valid Square + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/valid-square/description/ + +> 内容描述 + +``` + +Given the coordinates of four points in 2D space, return whether the four points could construct a square. + +The coordinate (x,y) of a point is represented by an integer array with two integers. + +Example: +Input: p1 = [0,0], p2 = [1,1], p3 = [1,0], p4 = [0,1] +Output: True +Note: + +All the input integers are in the range [-10000, 10000]. +A valid square has four equal sides with positive length and four equal angles (90-degree angles). +Input points have no order. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + +只要满足3个条件就行, + +1. 每个点都不相等,处理掉比如4个点都是(0, 0)啥的case +2. 4条边相等 +3. 其中2条边夹角为90度 + + +或者, + +1. 每个点都不相等,处理掉比如4个点都是(0, 0)啥的case +2. 有其中一组相邻边相等 +3. 有一对对角均为90度 + + +第一种方式代码如下: + + +```python +class Solution(object): + def validSquare(self, p1, p2, p3, p4): + """ + :type p1: List[int] + :type p2: List[int] + :type p3: List[int] + :type p4: List[int] + :rtype: bool + """ + # corner cases + points = [p1, p2, p3, p4] + for i in range(len(points)): + for j in range(i + 1, len(points)): + if points[i][0] == points[j][0] and points[i][1] == points[j][1]: + return False + + points = sorted(points, key=lambda p: (p[0], p[1])) # [] + + import math + + # for this part , we calculate the four sides + tmp = pow(points[-1][0] - points[1][0], 2) + pow(points[-1][1] - points[1][1], 2) + len_bottom = math.sqrt((tmp)) + + tmp = pow(points[-2][0] - points[0][0], 2) + pow(points[-2][1] - points[0][1], 2) + len_top = math.sqrt((tmp)) + + tmp = pow(points[1][0] - points[0][0], 2) + pow(points[1][1] - points[0][1], 2) + len_left = math.sqrt((tmp)) + + tmp = pow(points[-1][0] - points[-2][0], 2) + pow(points[-1][1] - points[-2][1], 2) + len_right = math.sqrt((tmp)) + + # now this is our angle part + vector_bottom = [points[-1][0] - points[1][0], points[-1][1] - points[1][1]] + vector_left = [points[1][0] - points[0][0], points[1][1] - points[0][1]] + + dikall = vector_bottom[0] * vector_left[0] + vector_bottom[1] * vector_left[1] + + if len_bottom == len_top == len_left == len_right and dikall == 0: + return True + return False +``` + +第二种代码如下: + +```python +class Solution(object): + def validSquare(self, p1, p2, p3, p4): + """ + :type p1: List[int] + :type p2: List[int] + :type p3: List[int] + :type p4: List[int] + :rtype: bool + """ + # corner cases + points = [p1, p2, p3, p4] + for i in range(len(points)): + for j in range(i + 1, len(points)): + if points[i][0] == points[j][0] and points[i][1] == points[j][1]: + return False + + points = sorted(points, key=lambda p: (p[0], p[1])) # [] + + import math + + # for this part , we calculate the four sides + tmp = pow(points[-1][0] - points[1][0], 2) + pow(points[-1][1] - points[1][1], 2) + len_bottom = math.sqrt((tmp)) + + tmp = pow(points[1][0] - points[0][0], 2) + pow(points[1][1] - points[0][1], 2) + len_left = math.sqrt((tmp)) + + # now this is our angle part + vector_bottom = [points[-1][0] - points[1][0], points[-1][1] - points[1][1]] + vector_left = [points[1][0] - points[0][0], points[1][1] - points[0][1]] + + vector_top = [points[2][0] - points[0][0], points[2][1] - points[0][1]] + vector_right = [points[2][0] - points[-1][0], points[2][1] - points[-1][1]] + + vec_product1 = vector_bottom[0] * vector_left[0] + vector_bottom[1] * vector_left[1] + vec_product2 = vector_top[0] * vector_right[0] + vector_top[1] * vector_right[1] + + if len_bottom == len_left and vec_product1 == vec_product2 == 0: + return True + return False +``` + +> 思路 2 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + +这个思路是根据后面Follow up大佬告诉我的,根据三个点就可以算出正方形的第四个点了,然后我们需要考虑的就是下面的几个case + +1. 如果4个点中有两个点相等,那么肯定不行 +2. 如果是菱形,肯定不行,即夹角不为90度 +3. 如果相邻边长度不相等,那肯定不行 + +满足以上3个条件,就返回True,否则返回False + + +```python +class Solution(object): + def validSquare(self, p1, p2, p3, p4): + """ + :type p1: List[int] + :type p2: List[int] + :type p3: List[int] + :type p4: List[int] + :rtype: bool + """ + points = [p1, p2, p3, p4] + points = sorted(points, key=lambda p: (p[0], p[1])) + + for i in range(len(points)): # for same point case + for j in range(i + 1, len(points)): + if points[i][0] == points[j][0] and points[i][1] == points[j][1]: + return False + + x4, y4 = points[2][0] + points[1][0] - points[0][0], points[1][1] - points[0][1] + points[2][1] + + if x4 == points[-1][0] and y4 == points[-1][1]: # for point4 not exist case + + distance_bottom = pow((x4-points[1][0]), 2) + pow((y4-points[1][1]), 2) + distance_left = pow((points[0][1]-points[1][1]), 2) + pow((points[0][0]-points[1][0]), 2) + + if distance_bottom == distance_left: # for diamond case + + vec_product = (x4-points[1][0]) * (points[0][0]-points[1][0]) + (y4-points[1][1]) * (points[0][1]-points[1][1]) + + if vec_product == 0: # for angle != 90 degree case + return True + return False +``` + +## Follow up + +如果给一个列表的点,返回一共能组成多少个正方形。input里面可能有重复的点 + + +开始我很sb的想着4 个 for loop取得4个点,然后用上面的函数判断是否可以组成正方形,最后叠加结果并且返回 + +这里感谢微信墨汁大佬的指导, + +- 首先将input去重 +- 然后可以先将所有点放到一个字典里面去 +- 然后我们用2个for loop去确定好2个点,根据正方形的性质我们就可以自己算出正方形的另外两个点了 +- 随后我们判断这两个点是否在我们的字典里面 + +这样我们最终的时间复杂度是O(N^2),空间复杂度是O(N),完美!! diff --git a/docs/Leetcode_Solutions/Python/595._Big_Countries.md b/docs/Leetcode_Solutions/Python/595._Big_Countries.md new file mode 100644 index 000000000..cf8cace79 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/595._Big_Countries.md @@ -0,0 +1,45 @@ +# 595. Big Countries + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/big-countries/description/ + +> 内容描述 + +``` +There is a table World + ++-----------------+------------+------------+--------------+---------------+ +| name | continent | area | population | gdp | ++-----------------+------------+------------+--------------+---------------+ +| Afghanistan | Asia | 652230 | 25500100 | 20343000 | +| Albania | Europe | 28748 | 2831741 | 12960000 | +| Algeria | Africa | 2381741 | 37100000 | 188681000 | +| Andorra | Europe | 468 | 78115 | 3712000 | +| Angola | Africa | 1246700 | 20609294 | 100990000 | ++-----------------+------------+------------+--------------+---------------+ +A country is big if it has an area of bigger than 3 million square km or a population of more than 25 million. + +Write a SQL solution to output big countries' name, population and area. + +For example, according to the above table, we should output: + ++--------------+-------------+--------------+ +| name | population | area | ++--------------+-------------+--------------+ +| Afghanistan | 25500100 | 652230 | +| Algeria | 37100000 | 2381741 | ++--------------+-------------+--------------+ +``` + +## 解题方案 + +> 思路 1 + +```sql +select name, population, area from World where area > 3000000 or population > 25000000; +``` diff --git a/docs/leetcode/python/599._Minimum_Index_Sum_of_Two_Lists.md b/docs/Leetcode_Solutions/Python/599._Minimum_Index_Sum_of_Two_Lists.md similarity index 94% rename from docs/leetcode/python/599._Minimum_Index_Sum_of_Two_Lists.md rename to docs/Leetcode_Solutions/Python/599._Minimum_Index_Sum_of_Two_Lists.md index 819bcff9d..1682fab62 100644 --- a/docs/leetcode/python/599._Minimum_Index_Sum_of_Two_Lists.md +++ b/docs/Leetcode_Solutions/Python/599._Minimum_Index_Sum_of_Two_Lists.md @@ -55,4 +55,4 @@ Author: Keqi Huang If you like it, please spread your support -![Support](/img/Algorithm/LeetCode/WechatIMG17.jpeg) +![Support](https://github.com/Lisanaaa/myTODOs/blob/master/WechatIMG17.jpeg) diff --git a/docs/leetcode/python/606._Construct_String_from_Binary_Tree.md b/docs/Leetcode_Solutions/Python/606._Construct_String_from_Binary_Tree.md similarity index 99% rename from docs/leetcode/python/606._Construct_String_from_Binary_Tree.md rename to docs/Leetcode_Solutions/Python/606._Construct_String_from_Binary_Tree.md index cc67ceac0..df0b8af42 100644 --- a/docs/leetcode/python/606._Construct_String_from_Binary_Tree.md +++ b/docs/Leetcode_Solutions/Python/606._Construct_String_from_Binary_Tree.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/construct-string-from-binary-tree +* https://leetcode.com/problems/construct-string-from-binary-tree/description/ > 内容描述 diff --git a/docs/leetcode/python/611._Valid_Triangle_Number.md b/docs/Leetcode_Solutions/Python/611._Valid_Triangle_Number.md similarity index 95% rename from docs/leetcode/python/611._Valid_Triangle_Number.md rename to docs/Leetcode_Solutions/Python/611._Valid_Triangle_Number.md index 41c8831c7..f17d298e2 100644 --- a/docs/leetcode/python/611._Valid_Triangle_Number.md +++ b/docs/Leetcode_Solutions/Python/611._Valid_Triangle_Number.md @@ -6,8 +6,8 @@ > 原题连接 -* https://leetcode.com/problems/valid-triangle-number -* https://leetcode-cn.com/problems/valid-triangle-number +* https://leetcode.com/problems/valid-triangle-number/description/ +* https://leetcode-cn.com/problems/valid-triangle-number/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/613._Shortest_Distance_in_a_Line.md b/docs/Leetcode_Solutions/Python/613._Shortest_Distance_in_a_Line.md new file mode 100644 index 000000000..de97e3de3 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/613._Shortest_Distance_in_a_Line.md @@ -0,0 +1,41 @@ +# 613. Shortest Distance in a Line + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/shortest-distance-in-a-line/description/ + +> 内容描述 + +``` +Table point holds the x coordinate of some points on x-axis in a plane, which are all integers. +Write a query to find the shortest distance between two points in these points. +| x | +|-----| +| -1 | +| 0 | +| 2 | +The shortest distance is '1' obviously, which is from point '-1' to '0'. So the output is as below: +| shortest| +|---------| +| 1 | +Note: Every point is unique, which means there is no duplicates in table point. +Follow-up: What if all these points have an id and are arranged from the left most to the right most of x axis? +``` + +## 解题方案 + +> 思路 1 + +```sql +select min(abs(p1.x-p2.x)) as shortest from point p1, point p2 where p1.x != p2.x; +``` + +> 思路 2 + +```sql +select min(p2.x-p1.x) shortest from point p1 inner join point p2 where p2.x > p1.x; +``` diff --git a/docs/leetcode/python/646._Maximum_Length_of_Pair_Chain.md b/docs/Leetcode_Solutions/Python/646._Maximum_Length_of_Pair_Chain.md similarity index 97% rename from docs/leetcode/python/646._Maximum_Length_of_Pair_Chain.md rename to docs/Leetcode_Solutions/Python/646._Maximum_Length_of_Pair_Chain.md index 8cc8e6260..a294701e3 100644 --- a/docs/leetcode/python/646._Maximum_Length_of_Pair_Chain.md +++ b/docs/Leetcode_Solutions/Python/646._Maximum_Length_of_Pair_Chain.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/maximum-length-of-pair-chain +* https://leetcode.com/problems/maximum-length-of-pair-chain/description/ > 内容描述 diff --git a/docs/leetcode/python/647._Palindromic_Substrings.md b/docs/Leetcode_Solutions/Python/647._Palindromic_Substrings.md similarity index 79% rename from docs/leetcode/python/647._Palindromic_Substrings.md rename to docs/Leetcode_Solutions/Python/647._Palindromic_Substrings.md index 22791ab64..450acba5d 100644 --- a/docs/leetcode/python/647._Palindromic_Substrings.md +++ b/docs/Leetcode_Solutions/Python/647._Palindromic_Substrings.md @@ -1,12 +1,37 @@ -### 647. Palindromic Substrings +# 647. Palindromic Substrings -题目: - +**难度: Medium** +## 刷题内容 -难度: +> 原题连接 -Medium +* https://leetcode.com/problems/palindromic-substrings/description/ + +> 内容描述 + +``` + +Given a string, your task is to count how many palindromic substrings in this string. + +The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters. + +Example 1: +Input: "abc" +Output: 3 +Explanation: Three palindromic strings: "a", "b", "c". +Example 2: +Input: "aaa" +Output: 6 +Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa". +Note: +The input string length won't exceed 1000. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** 思路 @@ -21,17 +46,17 @@ Manacher算法增加两个辅助变量id和mx,其中id表示最大回文子串 下面,令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]; -![](/img/Algorithm/LeetCode/manacher1.png) +![](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之后的部分是否对称,再具体匹配。 -![](/img/Algorithm/LeetCode/manacher2.png) +![](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) 这道题的基本思想是将以每一个字符为中心的回文子串个数相加,还是用一个小例子来解释 -![](/img/Algorithm/LeetCode/manacher3.jpg) +![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher3.jpg) 其实,以‘#’为中心的回文子串就代表这个子串的长度是偶数,类似于'abba'这种 但是其实这个字符本身也是一个回文子串,所以叠加的形式是count += (P[i]+1)/2,为什么呢,以下是解释: - 对于每一个以字符‘#’为中心的回文子串,其P值绝对是偶数,所以```(P[i]+1)/2 = P[i]/2```,并不影响 @@ -70,6 +95,10 @@ class Solution(object): count += (P[i]+1)/2 return count ``` + +> 思路 2 + + python无敌啊!!!有没有天理啊,手动滑稽😏😏😏😏!一行解法: ```python class Solution(object): diff --git a/docs/leetcode/python/657._Judge_Route_Circle.md b/docs/Leetcode_Solutions/Python/657._Judge_Route_Circle.md similarity index 100% rename from docs/leetcode/python/657._Judge_Route_Circle.md rename to docs/Leetcode_Solutions/Python/657._Judge_Route_Circle.md diff --git a/docs/leetcode/python/665._Non-decreasing_Array.md b/docs/Leetcode_Solutions/Python/665._Non-decreasing_Array.md similarity index 58% rename from docs/leetcode/python/665._Non-decreasing_Array.md rename to docs/Leetcode_Solutions/Python/665._Non-decreasing_Array.md index cf05d3c9e..bd5deb204 100644 --- a/docs/leetcode/python/665._Non-decreasing_Array.md +++ b/docs/Leetcode_Solutions/Python/665._Non-decreasing_Array.md @@ -1,15 +1,34 @@ -### 665. Non-decreasing Array +# 665. Non-decreasing Array -题目: - +**难度: Easy** +## 刷题内容 -难度: +> 原题连接 -Easy +* https://leetcode.com/problems/non-decreasing-array/description/ +> 内容描述 -思路 +``` +Given an array with n integers, your task is to check if it could become non-decreasing by modifying at most 1 element. + +We define an array is non-decreasing if array[i] <= array[i + 1] holds for every i (1 <= i < n). + +Example 1: +Input: [4,2,3] +Output: True +Explanation: You could modify the first 4 to 1 to get a non-decreasing array. +Example 2: +Input: [4,2,1] +Output: False +Explanation: You can't get a non-decreasing array by modify at most one element. +Note: The n belongs to [1, 10,000]. +``` + +## 解题方案 + +> 思路 1 从index=1的元素依次检查,只要不符合规则则让count+1,如果count>1则肯定不符合返回False 但是我们在发现nums[i]小于nums[i-1]的时候,我们就必须要对原数组作出改变了,来让它的后面index部分尽可能满足条件 @@ -31,13 +50,15 @@ class Solution(object): :type nums: List[int] :rtype: bool """ + if not nums or len(nums) <= 1: + return True count = 0 - for i in range(1,len(nums)): + 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]: + if i-2 < 0 or nums[i-2] <= nums[i]: nums[i-1] = nums[i] else: nums[i] = nums[i-1] diff --git a/docs/leetcode/python/672._Bulb_Switcher_II.md b/docs/Leetcode_Solutions/Python/672._Bulb_Switcher_II.md similarity index 57% rename from docs/leetcode/python/672._Bulb_Switcher_II.md rename to docs/Leetcode_Solutions/Python/672._Bulb_Switcher_II.md index 2441178f4..3cad5b3ce 100644 --- a/docs/leetcode/python/672._Bulb_Switcher_II.md +++ b/docs/Leetcode_Solutions/Python/672._Bulb_Switcher_II.md @@ -1,15 +1,43 @@ -### 672. Bulb Switcher II +# 672. Bulb Switcher II -题目: - +**难度: Medium** +## 刷题内容 -难度: +> 原题连接 -Medium +* https://leetcode.com/problems/bulb-switcher-ii/description/ +> 内容描述 -思路 +``` +There is a room with n lights which are turned on initially and 4 buttons on the wall. After performing exactly m unknown operations towards buttons, you need to return how many different kinds of status of the n lights could be. + +Suppose n lights are labeled as number [1, 2, 3 ..., n], function of these 4 buttons are given below: + +Flip all the lights. +Flip lights with even numbers. +Flip lights with odd numbers. +Flip lights with (3k + 1) numbers, k = 0, 1, 2, ... +Example 1: +Input: n = 1, m = 1. +Output: 2 +Explanation: Status can be: [on], [off] +Example 2: +Input: n = 2, m = 1. +Output: 3 +Explanation: Status can be: [on, off], [off, on], [off, off] +Example 3: +Input: n = 3, m = 1. +Output: 4 +Explanation: Status can be: [off, on, off], [on, off, on], [off, off, off], [off, on, on]. +Note: n and m both fit in range [0, 1000]. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(1)******- 空间复杂度: O(1)****** 这道题又是一个数学题。找规律呀找规律。 我们只需要考虑当 n<=2 and m < 3 的特殊情形。因为当 n >2 and m >=3, 结果肯定是 8. @@ -56,7 +84,11 @@ class Solution(object): return 8 ``` +> 思路 2 + + 还有两位大佬的两行解法: + ```python class Solution(object): def flipLights(self, n, m): @@ -68,7 +100,6 @@ class Solution(object): def flipLights(self, n, m): n = min(n, 3) return min(1<难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/valid-parenthesis-string/description/ + +> 内容描述 + +``` + +Given a string containing only three types of characters: '(', ')' and '*', write a function to check whether this string is valid. We define the validity of a string by these rules: + +Any left parenthesis '(' must have a corresponding right parenthesis ')'. +Any right parenthesis ')' must have a corresponding left parenthesis '('. +Left parenthesis '(' must go before the corresponding right parenthesis ')'. +'*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string. +An empty string is also valid. +Example 1: +Input: "()" +Output: True +Example 2: +Input: "(*)" +Output: True +Example 3: +Input: "(*))" +Output: True +Note: +The string size will be in the range [1, 100]. +``` + +## 解题方案 + + +> 思路 1 +******- 时间复杂度: O(N^3)******- 空间复杂度: O(N^2)****** + +``` +Let dp[i][j] be true if and only if the interval s[i], s[i+1], ..., s[j] can be made valid. Then dp[i][j] is true only if: + +s[i] is '*', and the interval s[i+1], s[i+2], ..., s[j] can be made valid; + +or, s[i] can be made to be '(', and there is some k in [i+1, j] such that s[k] can be made to be ')', plus the two intervals cut by s[k] (s[i+1: k] and s[k+1: j+1]) can be made valid; +``` +因为文章要从垃圾算法写到好的算法,这不是我的第一解法 + +但是是真的垃圾,才beats 2.75% +```python +class Solution(object): + def checkValidString(self, s): + """ + :type s: str + :rtype: bool + """ + if not s or len(s) == 0: + return True + + LEFTY, RIGHTY = '(*', ')*' + + n = len(s) + dp = [[0] * n for _ in s] + for i in range(n): + if s[i] == '*': + dp[i][i] = 1 + if i < n-1 and s[i] in LEFTY and s[i+1] in RIGHTY: + dp[i][i+1] = 1 + for j in range(n): + for i in range(j-2, -1, -1): + if s[i] == '*' and dp[i+1][j]: + dp[i][j] = 1 + elif s[i] in LEFTY: + for k in range(i+1, j+1): + if s[k] in RIGHTY and \ + (k == i+1 or dp[i+1][k-1]) and \ + (k == j or dp[k+1][j]): + dp[i][j] = 1 + + return True if dp[0][-1] else False +``` + +或者后面的循环按照子串的长度size来遍历, + +```python +class Solution(object): + def checkValidString(self, s): + """ + :type s: str + :rtype: bool + """ + if not s or len(s) == 0: + return True + + LEFTY, RIGHTY = '(*', ')*' + + n = len(s) + dp = [[False] * n for _ in s] + for i in range(n): + if s[i] == '*': + dp[i][i] = True + if i < n-1 and s[i] in LEFTY and s[i+1] in RIGHTY: + dp[i][i+1] = True + + for size in range(2, n): + for i in range(n - size): + if s[i] == '*' and dp[i+1][i+size]: + dp[i][i+size] = True + elif s[i] in LEFTY: + for k in range(i+1, i+size+1): + if (s[k] in RIGHTY and \ + (k == i+1 or dp[i+1][k-1]) and \ + (k == i+size or dp[k+1][i+size])): + dp[i][i+size] = True + + return dp[0][-1] +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +这是我的最初方法 + +- Keep track of indices for unmatched '(' and available '*'. +- After the loop we can check whether the index of any remaining '*' can match the unmatched '('. +- If the index of star is greater than the index of '(' then they can match. + +beats 100% + + +```python +class Solution(object): + def checkValidString(self, s): + """ + :type s: str + :rtype: bool + """ + if not s or len(s) == 0: + return True + + stack, star = [], [] + for i in range(len(s)): + if s[i] == '(': + stack.append(i) + elif s[i] == ')': + if stack: + stack.pop() + elif star: + star.pop() + else: + return False + else: + star.append(i) + + while stack and star: + # 从后面开始比较,如果最后出现的'('的index比最后出现的'*'更大,那其实这个匹配不了,比如'*(' + if stack[-1] > star[-1]: + return False + else: + stack.pop() + star.pop() + + return not stack +``` + +> 思路 3 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +看到别人的解法,真的🐂p,贪心算法 + +``` +We know that at each point in the string, '( 'count should never be bigger than ')' count, and in the end the difference of two counts should be 0. +So we have two boundaries: lowerBond and higherBound, which respectively represents the minimun possible difference and maximum possbile difference, as long as + +higherBound is never below 0. +in the end 0 is between lowerBond and higherBound +in the string, when lowerbound is < 0, we make it back to 0. +We know that the string is valid. +``` + +beats 100% + +```python +class Solution(object): + def checkValidString(self, s): + """ + :type s: str + :rtype: bool + """ + lower_bound = higher_bound = 0 + for c in s: + lower_bound += 1 if c == '(' else -1 + higher_bound += 1 if c != ')' else -1 + if higher_bound < 0: + return False + lower_bound = max(lower_bound, 0) + + return lower_bound == 0 +``` + diff --git a/docs/Leetcode_Solutions/Python/680._Valid_Palindrome_II.md b/docs/Leetcode_Solutions/Python/680._Valid_Palindrome_II.md new file mode 100644 index 000000000..b33597376 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/680._Valid_Palindrome_II.md @@ -0,0 +1,111 @@ +# 680. Valid Palindrome II + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/valid-palindrome-ii/description/ + +> 内容描述 + +``` + +Given a non-empty string s, you may delete at most one character. Judge whether you can make it a palindrome. + +Example 1: +Input: "aba" +Output: True +Example 2: +Input: "abca" +Output: True +Explanation: You could delete the character 'c'. +Note: +The string will only contain lowercase characters a-z. The maximum length of the string is 50000. +``` + +## 解题方案 + +> 思路 1 + +想直接来个 for loop,看看对应除去该index元素之后的字符串是否为 palindrome 即可 + +但是直接 Time Limit Exceeded + +```python +class Solution(object): + def validPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + for i in range(len(s)): + if s[:i] + s[i+1:] == s[i+1:][::-1] + s[:i][::-1]: + return True + return False +``` + + +> 思路 2 + +我们先定义一个reverse变量作为字符串s的翻转版本,例如 + +``` +s = 'abbbbbca' +reverse = 'acbbbbba' +``` + +然后我们从第一个字符开始比较,直到两边的字符不相等的时候,比如上面的例子我们就是index为1的时候不相等,所以i = 1,此时我们就会面临两个选择: + +1. 我们可以舍弃s中index为i的这个元素看看是否可以使其成为palindrome,即让s变成'abbbbca',然后我们可以通过s[i+1:n-i] == reverse[i:n-i-1]来判断 +2. 我们可以舍弃reverse中index为i的这个元素(即s中index为n-1-i的这个元素),即让s变成'abbbbba',我们可以通过s[i:n-1-i] == reverse[i+1:n-i]来判断 + +```python +class Solution(object): + def validPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + n = len(s) + if n < 3: + return True + + reverse = s[::-1] + i = 0 + while i < len(s) and s[i] == reverse[i]: + i += 1 + return s[i:n-1-i] == reverse[i+1:n-i] or s[i+1:n-i] == reverse[i:n-i-1] +``` + + + +> 思路 3 + +或者我们不搞reverse,直接在s上面原地判断即可 + + +```python +class Solution(object): + def validPalindrome(self, s): + """ + :type s: str + :rtype: bool + """ + n = len(s) + if n < 3: + return True + + l, r = 0, n - 1 + while l < r and s[l] == s[r]: + l += 1 + r -= 1 + if l >= r: + return True + else: + return s[l+1:r+1] == s[l+1:r+1][::-1] or s[l:r] == s[l:r][::-1] +``` + + + diff --git a/docs/leetcode/python/681._Next_Closest_Time.md b/docs/Leetcode_Solutions/Python/681._Next_Closest_Time.md similarity index 100% rename from docs/leetcode/python/681._Next_Closest_Time.md rename to docs/Leetcode_Solutions/Python/681._Next_Closest_Time.md diff --git a/docs/leetcode/python/682._Baseball_Game.md b/docs/Leetcode_Solutions/Python/682._Baseball_Game.md similarity index 100% rename from docs/leetcode/python/682._Baseball_Game.md rename to docs/Leetcode_Solutions/Python/682._Baseball_Game.md diff --git a/docs/leetcode/python/685._Redundant_Connection_II.md b/docs/Leetcode_Solutions/Python/685._Redundant_Connection_II.md similarity index 100% rename from docs/leetcode/python/685._Redundant_Connection_II.md rename to docs/Leetcode_Solutions/Python/685._Redundant_Connection_II.md diff --git a/docs/leetcode/python/687._Longest_Univalue_Path.md b/docs/Leetcode_Solutions/Python/687._Longest_Univalue_Path.md similarity index 100% rename from docs/leetcode/python/687._Longest_Univalue_Path.md rename to docs/Leetcode_Solutions/Python/687._Longest_Univalue_Path.md diff --git a/docs/leetcode/python/693._Binary_Number_with_Alternating_Bits.md b/docs/Leetcode_Solutions/Python/693._Binary_Number_with_Alternating_Bits.md similarity index 97% rename from docs/leetcode/python/693._Binary_Number_with_Alternating_Bits.md rename to docs/Leetcode_Solutions/Python/693._Binary_Number_with_Alternating_Bits.md index 0fdbac4b1..f95ae536e 100644 --- a/docs/leetcode/python/693._Binary_Number_with_Alternating_Bits.md +++ b/docs/Leetcode_Solutions/Python/693._Binary_Number_with_Alternating_Bits.md @@ -6,8 +6,8 @@ > 原题连接 -* https://leetcode.com/problems/binary-number-with-alternating-bits -* https://leetcode-cn.com/problems/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/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/695._Max_Area_of_Island.md b/docs/Leetcode_Solutions/Python/695._Max_Area_of_Island.md new file mode 100644 index 000000000..f25827006 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/695._Max_Area_of_Island.md @@ -0,0 +1,164 @@ +# 695. Max Area of Island + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/max-area-of-island/description/ + +> 内容描述 + +``` +Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. + +Find the maximum area of an island in the given 2D array. (If there is no island, the maximum area is 0.) + +Example 1: +[[0,0,1,0,0,0,0,1,0,0,0,0,0], + [0,0,0,0,0,0,0,1,1,1,0,0,0], + [0,1,1,0,1,0,0,0,0,0,0,0,0], + [0,1,0,0,1,1,0,0,1,0,1,0,0], + [0,1,0,0,1,1,0,0,1,1,1,0,0], + [0,0,0,0,0,0,0,0,0,0,1,0,0], + [0,0,0,0,0,0,0,1,1,1,0,0,0], + [0,0,0,0,0,0,0,1,1,0,0,0,0]] +Given the above grid, return 6. Note the answer is not 11, because the island must be connected 4-directionally. +Example 2: +[[0,0,0,0,0,0,0,0]] +Given the above grid, return 0. +Note: The length of each dimension in the given grid does not exceed 50. +``` + +## 解题方案 + +> 思路 1 + + +对于每一个点我们不停的dfs,然后每次碰到一个点是1我们就将当前area加1,然后把这个点变成0,每一次都更新我们的res,最终返回res + +```python +class Solution(object): + def maxAreaOfIsland(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + if not grid or len(grid) == 0: + return 0 + m = len(grid) + n = len(grid[0]) if m else 0 + + def dfs(i, j, area): + if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] != 1: + return area + else: + grid[i][j] = 0 + area += 1 + for x, y in ([(i, j+1), (i, j-1), (i+1, j), (i-1, j)]): + area = dfs(x, y, area) + return area + + res = 0 + for i in range(len(grid)): + for j in range(len(grid[0])): + area = dfs(i, j, 0) + res = max(res, area) + return res +``` + + + +## Follow up: + +If we still want the max area of the island, but if one land is surrrounded all by land, +then it should not be part of our area, how can we solve it? + + + + +比如: +``` +1 0 0 1 1 1 +1 0 0 1 1 1 +0 0 0 0 1 1 +``` + +这个我们要返回的是7而不是8,因为坐标为(1,4)的点被陆地包围,所以我们不算他的面积 + +大概思路就是并查集,然后各大岛屿的坐标集合遍历一遍看看有没有没有点完全被包围,有的话就面积减1,然后最后算出来, +参考[leetcode 200](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/200._number_of_islands.md) +和 [leetcode 305](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/305._Number_of_Islands_II.md) + +```python +def find(x, uf): + while x != uf[x]: + uf[x] = uf[uf[x]] + x = uf[x] + return uf[x] + +class Solution(object): + uf, idx = {}, 1 + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + m = len(grid) + n = len(grid[0]) + + + + def sink(i, j): + if 0 <= i < len(grid) and 0 <= j < len(grid[0]) and grid[i][j] == '1': + self.uf[(i,j)] = self.uf[self.idx] = self.idx + grid[i][j] = '0' + for x, y in [(i, j+1), (i, j-1), (i+1, j), (i-1, j)]: + if (x,y) in self.uf: + root = find(self.uf[(x,y)], self.uf) + self.uf[root] = self.idx + self.idx += 1 + map(sink, (i+1, i-1, i, i), (j, j, j+1, j-1)) + + for i in range(len(grid)): + for j in range(len(grid[0])): + sink(i, j) + return self.uf + +grid = [["1","1","1","1","0"],["1","1","1","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]] +grid1 = [["1","1","1","1","0"],["1","1","1","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]] +# print(Solution().numIslands(grid)) + +uf = Solution().numIslands(grid) +print(uf) + +islands = {} +for key in uf.keys(): + if type(key).__name__ != 'int': + if find(key, uf) not in islands: + islands[find(key, uf)] = [key] + else: + islands[find(key, uf)].append(key) +print(islands) + +print(grid) +max_aera = -float('inf') +for key in islands.keys(): + aera = len(islands[key]) + for i, j in islands[key]: + tmp = 0 + for x, y in [(i, j + 1), (i, j - 1), (i + 1, j), (i - 1, j)]: + if 0 <= x < len(grid1) and 0 <= y < len(grid1[0]) and grid1[x][y] == '1': + tmp += 1 + if tmp == 4: + aera -= 1 + max_aera = max(max_aera, aera) +print(max_aera) +``` + + + + + + diff --git a/docs/Leetcode_Solutions/Python/698._Partition_to_K_Equal_Sum_Subsets.md b/docs/Leetcode_Solutions/Python/698._Partition_to_K_Equal_Sum_Subsets.md new file mode 100644 index 000000000..ebf2f58f6 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/698._Partition_to_K_Equal_Sum_Subsets.md @@ -0,0 +1,61 @@ +# 698. Partition to K Equal Sum Subsets + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/partition-to-k-equal-sum-subsets/description/ + +> 内容描述 + +``` +Given an array of integers nums and a positive integer k, find whether it's possible to divide this array into k non-empty subsets whose sums are all equal. + +Example 1: +Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4 +Output: True +Explanation: It's possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums. +Note: + +1 <= k <= len(nums) <= 16. +0 < nums[i] < 10000. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N!)******- 空间复杂度: O(N)****** + + + +将问题一步一步缩小到找一个subset的sum为target的问题,即剩下的整个数组的sum是否为target +```python +class Solution(object): + def canPartitionKSubsets(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: bool + """ + def dfs(nums, target, num, k): + if k == 0: + return True + for i in range(len(nums)): + new_nums = nums[:i] + nums[i+1:] + if num + nums[i] == target: + if dfs(new_nums, target, 0, k-1): + return True + elif num + nums[i] < target: + if dfs(new_nums, target, num+nums[i], k): + return True + elif num == 0: # 有一个数比target还大,直接返回False + return False + return False + if sum(nums) % k != 0: + return False + target = sum(nums) / k + nums.sort(reverse = True) # 逆序排序,先从大的开始判断,速度会更快 + return dfs(nums, target, 0, k) +``` diff --git a/docs/leetcode/python/701._Insert_into_a_Binary_Search_Tree.md b/docs/Leetcode_Solutions/Python/701._Insert_into_a_Binary_Search_Tree.md similarity index 100% rename from docs/leetcode/python/701._Insert_into_a_Binary_Search_Tree.md rename to docs/Leetcode_Solutions/Python/701._Insert_into_a_Binary_Search_Tree.md diff --git a/docs/leetcode/python/707._Design_Linked_List.md b/docs/Leetcode_Solutions/Python/707._Design_Linked_List.md similarity index 98% rename from docs/leetcode/python/707._Design_Linked_List.md rename to docs/Leetcode_Solutions/Python/707._Design_Linked_List.md index 6b84db798..7623a50ac 100644 --- a/docs/leetcode/python/707._Design_Linked_List.md +++ b/docs/Leetcode_Solutions/Python/707._Design_Linked_List.md @@ -6,7 +6,7 @@ > 原题连接 -* https://leetcode.com/problems/design-linked-list +* https://leetcode.com/problems/design-linked-list/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/713._Subarray_Product_Less_Than_K.md b/docs/Leetcode_Solutions/Python/713._Subarray_Product_Less_Than_K.md new file mode 100644 index 000000000..926a87203 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/713._Subarray_Product_Less_Than_K.md @@ -0,0 +1,95 @@ +# 713. Subarray Product Less Than K + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/subarray-product-less-than-k/description/ + +> 内容描述 + +``` +Your are given an array of positive integers nums. + +Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k. + +Example 1: +Input: nums = [10, 5, 2, 6], k = 100 +Output: 8 +Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]. +Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k. +Note: + +0 < nums.length <= 50000. +0 < nums[i] < 1000. +0 <= k < 10^6. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + +跟第560题思路一样,维护一个当前积的常量,每次只要看之前有多少个积大于 cur_product/nums[i]的,如果有就说明最近出现的这个subarray product可以小于k + +但是超时了 + +``` +class Solution(object): + def numSubarrayProductLessThanK(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + if k == 0: + n = nums.count(0) + return n*(n+1)/2 + # 这是为了保证如果当前product的值就等于k的话,我们其实也相当于找到一次 + lookup = {1:1} + res = 0 + cur_product = 1 + for num in nums: + cur_product *= num + res += sum(lookup[key] for key in lookup.keys() if key > cur_product/k) + # for key in lookup.keys(): + # if key > cur_product / k: + # res += lookup.get(key) + lookup[cur_product] = lookup.get(cur_product, 0) + 1 + return res +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +参考[gabbu](https://leetcode.com/problems/subarray-product-less-than-k/discuss/108846/Python-solution-with-detailed-explanation) +``` +Initialize start and end to index 0. Initialize prod to 1. Iterate end from 0 to len(nums)-1. +Now if prod * nums[end] is less than k, then all subarray between start and end contribute to the solution. +Since we are moving from left to right, we would have already counted all valid subarrays from start to end-1. +How many new subarrays with nums[end]? Answer: end-start. What will be the updated prod? Answer: prod * nums[end]. + +``` + +```python +class Solution(object): + def numSubarrayProductLessThanK(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + if k <= 1: + return 0 + res, l, r, cur_product = 0, 0, 0, 1 + while r < len(nums): + cur_product *= nums[r] + r += 1 + while cur_product >= k: + cur_product /= nums[l] + l += 1 + res += r - l + return res +``` diff --git a/docs/Leetcode_Solutions/Python/724._Find_Pivot_Index.md b/docs/Leetcode_Solutions/Python/724._Find_Pivot_Index.md new file mode 100644 index 000000000..04ab325d9 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/724._Find_Pivot_Index.md @@ -0,0 +1,112 @@ +# 724. Find Pivot Index + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/find-pivot-index/description/ + +> 内容描述 + +``` +Given an array of integers nums, write a method that returns the "pivot" index of this array. + +We define the pivot index as the index where the sum of the numbers to the left of the index is equal to the sum of the numbers to the right of the index. + +If no such index exists, we should return -1. If there are multiple pivot indexes, you should return the left-most pivot index. + +Example 1: +Input: +nums = [1, 7, 3, 6, 5, 6] +Output: 3 +Explanation: +The sum of the numbers to the left of index 3 (nums[3] = 6) is equal to the sum of numbers to the right of index 3. +Also, 3 is the first index where this occurs. +Example 2: +Input: +nums = [1, 2, 3] +Output: -1 +Explanation: +There is no index that satisfies the conditions in the problem statement. +Note: + +The length of nums will be in the range [0, 10000]. +Each element nums[i] will be an integer in the range [-1000, 1000]. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + + +前缀和数组+后缀和数组,实现时间复杂度O(n)和空间复杂度O(n),3分钟 bug free + + + +```python +class Solution(object): + def pivotIndex(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums or len(nums) == 0: + return -1 + + prefix_sums = [nums[0]] * len(nums) + for i in range(1, len(nums)): + prefix_sums[i] = nums[i] + prefix_sums[i-1] + + suffix_sums = [nums[-1]] * len(nums) + for i in range(len(nums)-2, -1, -1): + suffix_sums[i] = nums[i] + suffix_sums[i+1] + + sums = sum(nums) + if sum(nums[1:]) == 0: + return 0 + for i in range(1, len(nums)): + if prefix_sums[i] == suffix_sums[i]: + return i + return -1 +``` + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +后面发现其实空间只要O(1)就可以了,就是用left_sum, right_sum分别代表左右两边的和,初始化为0和sum(nums) + +```python +class Solution(object): + def pivotIndex(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left_sum, right_sum = 0, sum(nums) + for idx, num in enumerate(nums): + right_sum -= num + if left_sum == right_sum: + return idx + left_sum += num + return -1 +``` + + + + + + + + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/733._Flood_Fill.md b/docs/Leetcode_Solutions/Python/733._Flood_Fill.md new file mode 100644 index 000000000..d1c54dceb --- /dev/null +++ b/docs/Leetcode_Solutions/Python/733._Flood_Fill.md @@ -0,0 +1,80 @@ +# 733. Flood Fill + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/flood-fill/description/ + +> 内容描述 + +``` +An image is represented by a 2-D array of integers, each integer representing the pixel value of the image (from 0 to 65535). + +Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill, and a pixel value newColor, "flood fill" the image. + +To perform a "flood fill", consider the starting pixel, plus any pixels connected 4-directionally to the starting pixel of the same color as the starting pixel, plus any pixels connected 4-directionally to those pixels (also with the same color as the starting pixel), and so on. Replace the color of all of the aforementioned pixels with the newColor. + +At the end, return the modified image. + +Example 1: +Input: +image = [[1,1,1],[1,1,0],[1,0,1]] +sr = 1, sc = 1, newColor = 2 +Output: [[2,2,2],[2,2,0],[2,0,1]] +Explanation: +From the center of the image (with position (sr, sc) = (1, 1)), all pixels connected +by a path of the same color as the starting pixel are colored with the new color. +Note the bottom corner is not colored 2, because it is not 4-directionally connected +to the starting pixel. +Note: + +The length of image and image[0] will be in the range [1, 50]. +The given starting pixel will satisfy 0 <= sr < image.length and 0 <= sc < image[0].length. +The value of each color in image[i][j] and newColor will be an integer in [0, 65535]. + +``` + +## 解题方案 + +> 思路 1 + + +dfs, 多加了一层判断,只有周围color一样才放进stack里面 + +```python +class Solution(object): + def floodFill(self, image, sr, sc, newColor): + """ + :type image: List[List[int]] + :type sr: int + :type sc: int + :type newColor: int + :rtype: List[List[int]] + """ + row = len(image) + col = len(image[0]) if row else 0 + directions = [[1,0], [-1,0], [0,1], [0,-1]] + + def dfs(image, sr, sc, color): + stack, visited = [[sr, sc]], [] + flood = [] + while stack: + vertex = stack.pop() + if vertex not in visited: + flood.append(vertex) + visited.append(vertex) + x, y = vertex[0], vertex[1] + for dire in directions: + if 0 <= x+dire[0] < row and 0 <= y+dire[1] < col: + if [x+dire[0], y+dire[1]] not in visited: + if image[x+dire[0]][y+dire[1]] == color: + stack.append([x+dire[0], y+dire[1]]) + return flood + + for i in dfs(image, sr, sc, image[sr][sc]): + image[i[0]][i[1]] = newColor + return image +``` diff --git a/docs/Leetcode_Solutions/Python/740._delete_and_earn.md b/docs/Leetcode_Solutions/Python/740._delete_and_earn.md new file mode 100644 index 000000000..7d50fc5a8 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/740._delete_and_earn.md @@ -0,0 +1,85 @@ +# 740. Delete and Earn + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/delete-and-earn/description/ + +> 内容描述 + +``` +Given an array nums of integers, you can perform operations on the array. + +In each operation, you pick any nums[i] and delete it to earn nums[i] points. After, you must delete every element equal to nums[i] - 1 or nums[i] + 1. + +You start with 0 points. Return the maximum number of points you can earn by applying such operations. + +Example 1: +Input: nums = [3, 4, 2] +Output: 6 +Explanation: +Delete 4 to earn 4 points, consequently 3 is also deleted. +Then, delete 2 to earn 2 points. 6 total points are earned. +Example 2: +Input: nums = [2, 2, 3, 3, 3, 4] +Output: 9 +Explanation: +Delete 3 to earn 3 points, deleting both 2's and the 4. +Then, delete 3 again to earn 3 points, and 3 again to earn 3 points. +9 total points are earned. +Note: + +The length of nums is at most 20000. +Each element nums[i] is an integer in the range [1, 10000]. +``` + +## 解题方案 + +> 思路 1 + +典型dp,dp[i]代表的是数字i,然后我们将其变化为删除数字i我们可以得到的最大分数(已经处理过所有比i小的数字了)。 + +推导公式为dp[i] = max(dp[i]+dp[i-2], dp[i-1]), + +- 即要么删除dp[i]得到所有数字i的和 +- 要么删除dp[i-1]不要dp[i]的分数 + +又因为Each element nums[i] is an integer in the range [1, 10000],所以dp长度初始化为10001 + +```python +class Solution(object): + def deleteAndEarn(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + dp = [0] * 10001 + for num in nums: + # now dp[num] = sum of the 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] +``` + + +> 思路 2 + +迭代 + +```python +class Solution(object): + def deleteAndEarn(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + last, now = 0, 0 + for value in range(10001): + last, now = now, max(last + value * nums.count(value), now) + return now +``` + diff --git a/docs/leetcode/python/760._Find_Anagram_Mappings.md b/docs/Leetcode_Solutions/Python/760._Find_Anagram_Mappings.md similarity index 100% rename from docs/leetcode/python/760._Find_Anagram_Mappings.md rename to docs/Leetcode_Solutions/Python/760._Find_Anagram_Mappings.md diff --git a/docs/leetcode/python/774._Minimize_Max_Distance_to_Gas_Station.md b/docs/Leetcode_Solutions/Python/774._Minimize_Max_Distance_to_Gas_Station.md similarity index 99% rename from docs/leetcode/python/774._Minimize_Max_Distance_to_Gas_Station.md rename to docs/Leetcode_Solutions/Python/774._Minimize_Max_Distance_to_Gas_Station.md index 6dc7c9af6..e9c4c06b6 100644 --- a/docs/leetcode/python/774._Minimize_Max_Distance_to_Gas_Station.md +++ b/docs/Leetcode_Solutions/Python/774._Minimize_Max_Distance_to_Gas_Station.md @@ -5,7 +5,7 @@ > 原题连接 -* https://leetcode.com/problems/minimize-max-distance-to-gas-station +* https://leetcode.com/problems/minimize-max-distance-to-gas-station/description/ > 内容描述 diff --git a/docs/leetcode/python/777._Swap_Adjacent_in_LR_String.md b/docs/Leetcode_Solutions/Python/777. Swap_Adjacent_in_LR_String.md similarity index 96% rename from docs/leetcode/python/777._Swap_Adjacent_in_LR_String.md rename to docs/Leetcode_Solutions/Python/777. Swap_Adjacent_in_LR_String.md index 77ee48e29..af0a30019 100644 --- a/docs/leetcode/python/777._Swap_Adjacent_in_LR_String.md +++ b/docs/Leetcode_Solutions/Python/777. Swap_Adjacent_in_LR_String.md @@ -6,8 +6,8 @@ > 原题连接 -* https://leetcode.com/problems/swap-adjacent-in-lr-string -* https://leetcode-cn.com/problems/swap-adjacent-in-lr-string +* https://leetcode.com/problems/swap-adjacent-in-lr-string/description/ +* https://leetcode-cn.com/problems/swap-adjacent-in-lr-string/description/ > 内容描述 diff --git a/docs/Leetcode_Solutions/Python/785._Is_Graph_Bipartite?.md b/docs/Leetcode_Solutions/Python/785._Is_Graph_Bipartite?.md new file mode 100644 index 000000000..380db1feb --- /dev/null +++ b/docs/Leetcode_Solutions/Python/785._Is_Graph_Bipartite?.md @@ -0,0 +1,80 @@ +# 785. Is Graph Bipartite? + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/is-graph-bipartite/description/ + +> 内容描述 + +``` + +Given an undirected graph, return true if and only if it is bipartite. + +Recall that a graph is bipartite if we can split it's set of nodes into two independent subsets A and B such that every edge in the graph has one node in A and another node in B. + +The graph is given in the following form: graph[i] is a list of indexes j for which the edge between nodes i and j exists. Each node is an integer between 0 and graph.length - 1. There are no self edges or parallel edges: graph[i] does not contain i, and it doesn't contain any element twice. + +Example 1: +Input: [[1,3], [0,2], [1,3], [0,2]] +Output: true +Explanation: +The graph looks like this: +0----1 +| | +| | +3----2 +We can divide the vertices into two groups: {0, 2} and {1, 3}. +Example 2: +Input: [[1,2,3], [0,2], [0,1,3], [0,2]] +Output: false +Explanation: +The graph looks like this: +0----1 +| \ | +| \ | +3----2 +We cannot find a way to divide the set of nodes into two independent subsets. + + +Note: + +graph will have length in range [1, 100]. +graph[i] will contain integers in range [0, graph.length - 1]. +graph[i] will not contain i or duplicate values. +The graph is undirected: if any element j is in graph[i], then i will be in graph[j]. +``` + +## 解题方案 + +> 思路 1 + + + +```python +class Solution: + def isBipartite(self, graph): + """ + :type graph: List[List[int]] + :rtype: bool + """ + visited = set() + for i in range(len(graph)): + if i in visited or len(graph[i]) == 0: + continue + level = {i} + while level: + next_level = set() + for j in level: + visited.add(j) + for n in graph[j]: + if n in level: + return False + if n not in visited: + next_level.add(n) + level = next_level + return True +``` diff --git a/docs/Leetcode_Solutions/Python/792._Number_of_Matching_Subsequences.md b/docs/Leetcode_Solutions/Python/792._Number_of_Matching_Subsequences.md new file mode 100644 index 000000000..334ddf5af --- /dev/null +++ b/docs/Leetcode_Solutions/Python/792._Number_of_Matching_Subsequences.md @@ -0,0 +1,206 @@ +# 792. Number of Matching Subsequences + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/number-of-matching-subsequences/description/ + +> 内容描述 + +``` +Given string S and a dictionary of words words, find the number of words[i] that is a subsequence of S. + +Example : +Input: +S = "abcde" +words = ["a", "bb", "acd", "ace"] +Output: 3 +Explanation: There are three words in words that are a subsequence of S: "a", "acd", "ace". +Note: + +All words in words and S will only consists of lowercase letters. +The length of S will be in the range of [1, 50000]. +The length of words will be in the range of [1, 5000]. +The length of words[i] will be in the range of [1, 50]. +``` + +## 解题方案 + +假设words里面最长的word长度为m,words的长度为n,S的长度为s + +> 思路 1 +******- 时间复杂度: O(m*n*s)******- 空间复杂度: O(1)****** + +暴力,超时 +``` +class Solution(object): + def numMatchingSubseq(self, S, words): + """ + :type S: str + :type words: List[str] + :rtype: int + """ + def match(word, S): + i, j = 0, 0 + while i < len(word) and j < len(S): + if word[i] == S[j]: + i += 1 + j += 1 + else: + j += 1 + return i == len(word) + + res = 0 + for word in words: + if match(word, S): + res += 1 + return res +``` + +我觉得是不是多加一个判断,如果一个字符在S里面没有立马返回False这样会快一点,但是还是超时 + +``` +class Solution(object): + def numMatchingSubseq(self, S, words): + """ + :type S: str + :type words: List[str] + :rtype: int + """ + def match(word, S): + i = 0 + while S and i < len(word): + idx = S.find(word[i]) + if idx == -1: + return False + S = S[idx+1:] + i += 1 + return i == len(word) + + res = 0 + for word in words: + if match(word, S): + res += 1 + return res +``` + + +于是又觉得用自带的iter函数会不会快一点,结果还是超时 + + +``` +class Solution(object): + def numMatchingSubseq(self, S, words): + """ + :type S: str + :type words: List[str] + :rtype: int + """ + def match(word, S): + it = iter(S) + if all(c in it for c in word): + return True + return False + + res = 0 + for word in words: + if match(word, S): + res += 1 + return res +``` + + +> 思路 2 +******- 时间复杂度: O(m*n*s)******- 空间复杂度: O(N)****** + +终于,我想到了用memorization,AC了,beats 70.4% + +```python +class Solution(object): + def numMatchingSubseq(self, S, words): + """ + :type S: str + :type words: List[str] + :rtype: int + """ + def match(word, S): + it = iter(S) + if all(c in it for c in word): + return True + return False + + res = 0 + matched, unmatched = set(), set() + for word in words: + if word in matched: + res += 1 + continue + elif word in unmatched: + continue + else: + if match(word, S): + res += 1 + matched.add(word) + else: + unmatched.add(word) + return res +``` + + +然后换了之前我觉得写的最好最快的match函数,beats 100% + +```python +class Solution(object): + def numMatchingSubseq(self, S, words): + """ + :type S: str + :type words: List[str] + :rtype: int + """ + def match(sub, s): + idx = 0 + for c in sub: + idx = s.find(c, idx) + 1 + if idx == 0: + return False + return True + + res = 0 + matched, unmatched = set(), set() + for word in words: + if word in matched: + res += 1 + continue + elif word in unmatched: + continue + else: + if match(word, S): + res += 1 + matched.add(word) + else: + unmatched.add(word) + return res +``` + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/796._Rotate_String.md b/docs/Leetcode_Solutions/Python/796._Rotate_String.md new file mode 100644 index 000000000..1e08139be --- /dev/null +++ b/docs/Leetcode_Solutions/Python/796._Rotate_String.md @@ -0,0 +1,46 @@ +# 796. Rotate String + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/rotate-string/description/ + +> 内容描述 + +``` +We are given two strings, A and B. + +A shift on A consists of taking string A and moving the leftmost character to the rightmost position. For example, if A = 'abcde', then it will be 'bcdea' after one shift on A. Return True if and only if A can become B after some number of shifts on A. + +Example 1: +Input: A = 'abcde', B = 'cdeab' +Output: true + +Example 2: +Input: A = 'abcde', B = 'abced' +Output: false +Note: + +A and B will have length at most 100. +``` + +## 解题方案 + +> 思路 1 + + +一行就够了,太简单了 + +```python +class Solution(object): + def rotateString(self, A, B): + """ + :type A: str + :type B: str + :rtype: bool + """ + return len(A) == len(B) and B in A * 2 +``` diff --git a/docs/Leetcode_Solutions/Python/801._Minimum_Swaps_To_Make_Sequences_Increasing.md b/docs/Leetcode_Solutions/Python/801._Minimum_Swaps_To_Make_Sequences_Increasing.md new file mode 100644 index 000000000..df94d1a4d --- /dev/null +++ b/docs/Leetcode_Solutions/Python/801._Minimum_Swaps_To_Make_Sequences_Increasing.md @@ -0,0 +1,67 @@ +# 801. Minimum Swaps To Make Sequences Increasing + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/description/ + +> 内容描述 + +``` + +We have two integer sequences A and B of the same non-zero length. + +We are allowed to swap elements A[i] and B[i]. Note that both elements are in the same index position in their respective sequences. + +At the end of some number of swaps, A and B are both strictly increasing. (A sequence is strictly increasing if and only if A[0] < A[1] < A[2] < ... < A[A.length - 1].) + +Given A and B, return the minimum number of swaps to make both sequences strictly increasing. It is guaranteed that the given input always makes it possible. + +Example: +Input: A = [1,3,5,4], B = [1,2,3,7] +Output: 1 +Explanation: +Swap A[3] and B[3]. Then the sequences are: +A = [1, 3, 5, 7] and B = [1, 2, 3, 4] +which are both strictly increasing. +Note: + +A, B are arrays with the same length, and that length will be in the range [1, 1000]. +A[i], B[i] are integer values in the range [0, 2000]. +``` + +## 解题方案 + +> 思路 1 + + +参考大神[Luckypants](https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/discuss/119830/Python-14-line-O(1)-space-O(n)-time-DP-solution)的思路 + + +- dp[i][0] means the least swaps used to make A[:i+1] and B[:i+1] sorted having no swap at i-th position. +- dp[i][1] means the least swaps used to make A[:i+1] and B[:i+1] sorted having swap at i-th position. + +```python +class Solution(object): + def minSwap(self, A, B): + """ + :type A: List[int] + :type B: List[int] + :rtype: int + """ + n = len(A) + pre = [0, 1] + for i in range(1, n): + cur = [sys.maxsize, sys.maxsize] + if A[i]>A[i-1] and B[i]>B[i-1]: + cur[0] = min(cur[0], pre[0]) + cur[1] = min(cur[1], pre[1]+1) + if A[i]>B[i-1] and B[i]>A[i-1]: + cur[0] = min(cur[0], pre[1]) + cur[1] = min(cur[1], pre[0]+1) + pre = cur + return min(pre) +``` diff --git a/docs/Leetcode_Solutions/Python/824._Goat_Latin.md b/docs/Leetcode_Solutions/Python/824._Goat_Latin.md new file mode 100644 index 000000000..6d1ca175e --- /dev/null +++ b/docs/Leetcode_Solutions/Python/824._Goat_Latin.md @@ -0,0 +1,72 @@ +# 824. Goat Latin + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/goat-latin/description/ + +> 内容描述 + +``` +A sentence S is given, composed of words separated by spaces. Each word consists of lowercase and uppercase letters only. + +We would like to convert the sentence to "Goat Latin" (a made-up language similar to Pig Latin.) + +The rules of Goat Latin are as follows: + +If a word begins with a vowel (a, e, i, o, or u), append "ma" to the end of the word. +For example, the word 'apple' becomes 'applema'. + +If a word begins with a consonant (i.e. not a vowel), remove the first letter and append it to the end, then add "ma". +For example, the word "goat" becomes "oatgma". + +Add one letter 'a' to the end of each word per its word index in the sentence, starting with 1. +For example, the first word gets "a" added to the end, the second word gets "aa" added to the end and so on. +Return the final sentence representing the conversion from S to Goat Latin. + + + +Example 1: + +Input: "I speak Goat Latin" +Output: "Imaa peaksmaaa oatGmaaaa atinLmaaaaa" +Example 2: + +Input: "The quick brown fox jumped over the lazy dog" +Output: "heTmaa uickqmaaa rownbmaaaa oxfmaaaaa umpedjmaaaaaa overmaaaaaaa hetmaaaaaaaa azylmaaaaaaaaa ogdmaaaaaaaaaa" + + +Notes: + +S contains only uppercase, lowercase and spaces. Exactly one space between each word. +1 <= S.length <= 150. +``` + +## 解题方案 + +> 思路 1 + + +sb题没什么好说的 + +```python +class Solution(object): + def toGoatLatin(self, S): + """ + :type S: str + :rtype: str + """ + res = '' + for index, word in enumerate(S.split()): + if(word[0] in 'aeiouAEIOU'): + word = word + 'ma' + else: + tmp = word[0] + word = word[1:] + tmp + 'ma' + word = word + 'a' * (index + 1) + res = res + ' ' + word + return res[1:] +``` diff --git a/docs/Leetcode_Solutions/Python/844._Backspace_String_Compare.md b/docs/Leetcode_Solutions/Python/844._Backspace_String_Compare.md new file mode 100644 index 000000000..d62ebc325 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/844._Backspace_String_Compare.md @@ -0,0 +1,171 @@ +# 844. Backspace String Compare + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/backspace-string-compare/description/ + +> 内容描述 + +``` +Given two strings S and T, return if they are equal when both are typed into empty text editors. # means a backspace character. + +Example 1: + +Input: S = "ab#c", T = "ad#c" +Output: true +Explanation: Both S and T become "ac". +Example 2: + +Input: S = "ab##", T = "c#d#" +Output: true +Explanation: Both S and T become "". +Example 3: + +Input: S = "a##c", T = "#a#c" +Output: true +Explanation: Both S and T become "c". +Example 4: + +Input: S = "a#c", T = "b" +Output: false +Explanation: S becomes "c" while T becomes "b". +Note: + +1 <= S.length <= 200 +1 <= T.length <= 200 +S and T only contain lowercase letters and '#' characters. +Follow up: + +Can you solve it in O(N) time and O(1) space? +``` + +## 解题方案 + +> 思路 1 + +就看一下两个字符串变化完之后是不是相等就行了, + +- 时间复杂度: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) +``` + +> 思路 2 + +deque + +- 时间复杂度:O(n) +- 空间复杂度:O(n) + +```python +class Solution: + def backspaceCompare(self, S, T): + """ + :type S: str + :type T: str + :rtype: bool + """ + q1 = collections.deque() + q2 = collections.deque() + for i in S: + if i != "#": + q1.append(i) + elif q1: + q1.pop() + else: + continue + for i in T: + if i != "#": + q2.append(i) + elif q2: + q2.pop() + else: + continue + + return q1==q2 +``` +## Follow up + +Can you solve it in O(N) time and O(1) space? + +> 思路 2 + + +参考[angelina_not_jolie](https://leetcode.com/problems/backspace-string-compare/discuss/165435/Python-O(1)-space-solution-for-the-follow-up-beats-100-using-two-pointers) +``` +The idea is we first need to find the first char in each string that was not deleted and compare equality. +Corner case is that the number of '#' is larger than the number of chars in front, e.g. "ab#######c" ---> "c" +So in my codes, the outter loop condition is as long as we haven't gone through both strings, we need to keep going. e.g. "ab#########c" vs. "a#c" +The inner loops are to find the next char after deleting. + +There are only two cases we need to return False: +1. Both pointers are at a char and these two chars are different. +One pointer is pointing to a char but the other string has been deleted till index 0. i.e. +2. compare a char to an empty string + +``` +- 时间复杂度:O(n) +- 空间复杂度:O(1) + +```python +class Solution(object): + def backspaceCompare(self, S, T): + """ + :type S: str + :type T: str + :rtype: bool + """ + i, poundS = len(S) - 1, 0; j, poundT = len(T) - 1, 0 + while i >= 0 or j >= 0: + while i >= 0: + if S[i] == "#": + poundS += 1 + elif poundS: + poundS -= 1 + else: #found the first undeleted char + break + i -= 1 + + while j >= 0: + if T[j] == '#': + poundT += 1 + elif poundT: + poundT -= 1 + else: + break + j -= 1 + + #either both side are chars then we need to compare + if i >= 0 and j >= 0 and S[i] != T[j]: + return False + #compare a char with empty(have more # than actually char, we delete everything before #) + if (i >= 0) != (j >=0): + return False + + i -= 1 + j -= 1 + + return i == j +``` diff --git a/docs/Leetcode_Solutions/Python/865._Smallest_Subtree_with_all_the_Deepest_Nodes.md b/docs/Leetcode_Solutions/Python/865._Smallest_Subtree_with_all_the_Deepest_Nodes.md new file mode 100644 index 000000000..2c7b53625 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/865._Smallest_Subtree_with_all_the_Deepest_Nodes.md @@ -0,0 +1,331 @@ +# 865. Smallest Subtree with all the Deepest Nodes + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/description/ + +> 内容描述 + +``` +Given a binary tree rooted at root, the depth of each node is the shortest distance to the root. + +A node is deepest if it has the largest depth possible among any node in the entire tree. + +The subtree of a node is that node, plus the set of all descendants of that node. + +Return the node with the largest depth such that it contains all the deepest nodes in its subtree. + + + +Example 1: + +Input: [3,5,1,6,2,0,8,null,null,7,4] +Output: [2,7,4] +Explanation: +``` + +![](https://github.com/apachecn/LeetCode/blob/master/images/sketch1.png) + +``` +We return the node with value 2, colored in yellow in the diagram. +The nodes colored in blue are the deepest nodes of the tree. +The input "[3, 5, 1, 6, 2, 0, 8, null, null, 7, 4]" is a serialization of the given tree. +The output "[2, 7, 4]" is a serialization of the subtree rooted at the node with value 2. +Both the input and output have TreeNode type. + +Note: + +The number of nodes in the tree will be between 1 and 500. +The values of each node are unique. +``` + +## 解题方案 + +> 思路 1 + +直接参考的[leetcode solution](https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/solution/) +- 首先将所有的node与其对应的depth记录下来 +- 然后,从root开始往下走,如果一个node的depth是最大的depth的话,就直接返回这个node,递归进行 +- 如果这个node的depth不是最大的depth,但是它的左孩子和右孩子的depth都最大的话也是直接返回这个node,递归进行 + +```python +class Solution(object): + def subtreeWithAllDeepest(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + depth = { + None: -1 + } + def dfs(node, parent = None): + if node: + depth[node] = depth[parent] + 1 + dfs(node.left, node) + dfs(node.right, node) + + dfs(root) + max_depth = max(depth.values()) + + def decide(node): + if not node or depth[node] == max_depth: + return node + l, r = decide(node.left), decide(node.right) + return node if l and r else l or r + return decide(root) +``` + +> 思路 2 + +The Result (on some subtree) returned by our (depth-first search) recursion will have two parts: +- Result.node: the largest depth node that is equal to or an ancestor of all the deepest nodes of this subtree. +- Result.depth: the number of nodes in the path from the root of this subtree, to the deepest node in this subtree. + +We can calculate these answers disjointly for dfs(node): + +To calculate the Result.node of our answer: + +- If one childResult has deeper nodes, then childResult.node will be the answer. + +- If they both have the same depth nodes, then node will be the answer. + +- The Result.depth of our answer is always 1 more than the largest childResult.depth we have. + +```python +class Solution(object): + def subtreeWithAllDeepest(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + Result = collections.namedtuple('Result', ('node', 'depth')) + def dfs(node): + if not node: + return Result(None, 0) + l, r = dfs(node.left), dfs(node.right) + if l.depth > r.depth: + return Result(l.node, l.depth+1) + elif l.depth < r.depth: + return Result(r.node, r.depth+1) + else: + return Result(node, l.depth+1) + return dfs(root).node +``` + +> 思路 3 + +自己的解法: + +```python +class Solution(object): + def subtreeWithAllDeepest(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + def depth(node): + return 0 if not node else max(depth(node.left), depth(node.right)) + 1 + + tmp = depth(root.left) - depth(root.right) + if tmp == 0: + return root + elif tmp > 0: + return self.subtreeWithAllDeepest(root.left) + else: + return self.subtreeWithAllDeepest(root.right) +``` + + + +## Follow up + +如果每一个树节点可以拥有超过2个孩子怎么办: + +> 思路 1 + +自己的解法, +- 只要这个节点的孩子中有两个及以上的depth相等就直接返回这个node本身 +- 如果只有一个孩子的depth最大就返回那个孩子 + +```python +class TreeNode(object): + def __init__(self, x): + self.val = x + self.children = [] + + +class Solution(object): + def subtreeWithAllDeepestForMoreChildren(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + # calculate a node's depth + def depth(node): + if not node: + return 0 + tmp = [depth(child) for child in node.children] + if not tmp or len(tmp) == 0: + return 1 + return max(tmp) + 1 + + if not root: + return None + tmp = [depth(child) for child in root.children] + if not tmp or len(tmp) == 0: + return root + # if 2 or more children have same depth, then return the node itself + if tmp.count(max(tmp)) > 1: + return root + # else recalculate the child who has largest depth + else: + return self.subtreeWithAllDeepestForMoreChildren(root.children[tmp.index(max(tmp))]) +``` + +搞一下测试用例 + +```python +import unittest + + +class TestSolution(unittest.TestCase): + def test_1(self): + root = TreeNode(0) + + for i in range(1, 4): + root.children.append(TreeNode(i)) + + for i in range(4, 10): + root.children[1].children.append(TreeNode(i)) + self.assertTrue(Solution().subtreeWithAllDeepestForMoreChildren(root).val == 2) + + def test_2(self): + root = TreeNode(0) + self.assertTrue(Solution().subtreeWithAllDeepestForMoreChildren(root).val == 0) + + def test_3(self): + root = TreeNode(0) + + for i in range(1, 4): + root.children.append(TreeNode(i)) + + for i in range(4, 10): + root.children[1].children.append(TreeNode(i)) + + for i in range(10, 12): + root.children[2].children.append(TreeNode(i)) + self.assertTrue(Solution().subtreeWithAllDeepestForMoreChildren(root).val == 0) + + def test_4(self): + root = TreeNode(0) + + for i in range(1, 3): + root.children.append(TreeNode(i)) + + for i in range(3, 5): + root.children[0].children.append(TreeNode(i)) + + for i in range(5, 7): + root.children[1].children.append(TreeNode(i)) + + for i in range(7, 9): + root.children[0].children[1].children.append(TreeNode(i)) + self.assertTrue(Solution().subtreeWithAllDeepestForMoreChildren(root).val == 4) + + def test_5(self): + root = TreeNode(0) + + for i in range(1, 5): + root.children.append(TreeNode(i)) + root.children[1].children.append(TreeNode(5)) + root.children[2].children.append(TreeNode(6)) + root.children[3].children.append(TreeNode(7)) + self.assertTrue(Solution().subtreeWithAllDeepestForMoreChildren(root).val == 0) + + +if __name__ == "__main__": + unittest.main() + + + +..... +---------------------------------------------------------------------- +Ran 5 tests in 0.000s + +OK +``` + + +> 思路 2 + + + +```python +import collections +import sys + + +class TreeNode(object): + def __init__(self, x): + self.val = x + self.children = [] + + +# Find the tree with largest depth among all nodes +class Solution(object): + def subtreeWithAllDeepestForMoreChildren(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + if not root: + return None + Result = collections.namedtuple("Result", ("node", "depth")) + + # return the Result of the subtree at this node + def dfs(node): + if not node: + return Result(None, 0) + if len(node.children) == 0: + return Result(node, 1) + largest_depth = 0 + res = Result(None, 0) + for child in node.children: + cur = dfs(child) # cur is a Result type: store ('node','depth') + if cur.depth > abs(largest_depth): + largest_depth = cur.depth + res = cur + elif cur.depth == largest_depth: + # negative number means largestDepth occurs more than once + largest_depth = -largest_depth + if largest_depth > 0: + return Result(res.node, largest_depth + 1) + return Result(node, -largest_depth + 1) + + return dfs(root).node +``` + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/873._Length_of_Longest_Fibonacci_Subsequence.md b/docs/Leetcode_Solutions/Python/873._Length_of_Longest_Fibonacci_Subsequence.md new file mode 100644 index 000000000..ea6f71248 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/873._Length_of_Longest_Fibonacci_Subsequence.md @@ -0,0 +1,108 @@ +# 873. Length of Longest Fibonacci Subsequence + +**难度: Meidum** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/length-of-longest-fibonacci-subsequence/description/ + +> 内容描述 + +``` +A sequence X_1, X_2, ..., X_n is fibonacci-like if: + +n >= 3 +X_i + X_{i+1} = X_{i+2} for all i + 2 <= n +Given a strictly increasing array A of positive integers forming a sequence, find the length of the longest fibonacci-like subsequence of A. If one does not exist, return 0. + +(Recall that a subsequence is derived from another sequence A by deleting any number of elements (including none) from A, without changing the order of the remaining elements. For example, [3, 5, 8] is a subsequence of [3, 4, 5, 6, 7, 8].) + + + +Example 1: + +Input: [1,2,3,4,5,6,7,8] +Output: 5 +Explanation: +The longest subsequence that is fibonacci-like: [1,2,3,5,8]. +Example 2: + +Input: [1,3,7,11,12,14,18] +Output: 3 +Explanation: +The longest subsequence that is fibonacci-like: +[1,11,12], [3,11,14] or [7,11,18]. + + +Note: + +3 <= A.length <= 1000 +1 <= A[0] < A[1] < ... < A[A.length - 1] <= 10^9 +(The time limit has been reduced by 50% for submissions in Java, C, and C++.) +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N^2*LgN)******- 空间复杂度: O(N)****** + +思路见[lee215](https://leetcode.com/problems/length-of-longest-fibonacci-subsequence/discuss/152343/C++JavaPython-Check-Pair) +``` +Save array A to a hash set s. +Start from base (A[i], A[j]) as the first two element in the sequence, +we try to find the Fibonacci like subsequence as long as possible, + +Initial (a, b) = (A[i], A[j]) +While the set s contains a + b, we update (a, b) = (b, a + b). +In the end we update the longest length we find. + +Time Complexity: +O(N^2logM), where M is the max(A). +``` + +```python +class Solution(object): + def lenLongestFibSubseq(self, A): + """ + :type A: List[int] + :rtype: int + """ + s, res = set(A), 0 + for i in range(len(A)): + for j in range(i+1, len(A)): + a, b, l = A[i], A[j], 2 + while a + b in s: + a, b, l = b, a + b, l + 1 + res = max(res, l) + return res if res > 2 else 0 +``` + + + +> 思路 2 +******- 时间复杂度: O(N^2)******- 空间复杂度: O(N)****** + +``` +dp[a, b] represents the length of fibo sequence ends up with (a, b) +Then we have dp[a, b] = dp[b - a, a] or 2 +The complexity reduce to O(N^2). +``` + +```python +class Solution(object): + def lenLongestFibSubseq(self, A): + """ + :type A: List[int] + :rtype: int + """ + dp = {} + s, res = set(A), 0 + for i in range(len(A)): + for j in range(i): + if A[i] - A[j] < A[j] and A[i] - A[j] in s: + dp[(A[j], A[i])] = dp.get((A[i]-A[j], A[j]), 2) + 1 + res = max(res, dp[(A[j], A[i])]) + return res if res > 2 else 0 +``` diff --git a/docs/Leetcode_Solutions/Python/878._Nth_Magical_Number.md b/docs/Leetcode_Solutions/Python/878._Nth_Magical_Number.md new file mode 100644 index 000000000..c0be3ccd7 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/878._Nth_Magical_Number.md @@ -0,0 +1,140 @@ +# 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(A+B)******- 空间复杂度: O(1)****** + +数学题直接看的[solution](https://leetcode.com/problems/nth-magical-number/solution/): + +* 从数据范围看来,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个魔法数 + +注意到,我们在1~p中任取一个数x(x 思路 2 +******- 时间复杂度: O(log(N*max(A,B)))******- 空间复杂度: O(1)****** + + +从另外一个角度来看,如果我们知道了一个数字x,那么我们可以轻易算出有多少个magic number 是小于等于x的, +即```x // A + x // B - x // L```, 其中```L = lcm(A, B)```, 我们可以通过二分法算出一个最小的数字num,小于等于num的magic number 数量是刚好是N, +然后这个num就是我们要求的 Nth Magical Number + +时间复杂度为O(log(N∗max(A,B))), beats 100% + +```python +class Solution(object): + def nthMagicalNumber(self, N, A, B): + """ + :type N: int + :type A: int + :type B: int + :rtype: int + """ + def gcd(a, b): + if b == 0: + return a + return gcd(b, a % b) + + def lcm(a, b): + return a * b // gcd(a, b) + + MOD = 10**9 + 7 + L = lcm(A, B) + + def magic_below_x(x): + # How many magical numbers are <= x? + return x // A + x // B - x // L + + l, r = 0, N * max(A,B) + while l <= r: + mid = l + ((r-l) >> 1) + if magic_below_x(mid) < N: + l = mid + 1 + else: + r = mid - 1 + + return l % MOD +``` + diff --git a/docs/Leetcode_Solutions/Python/890._Find_and_Replace_Pattern.md b/docs/Leetcode_Solutions/Python/890._Find_and_Replace_Pattern.md new file mode 100644 index 000000000..edefe3380 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/890._Find_and_Replace_Pattern.md @@ -0,0 +1,83 @@ +# 890. Find and Replace Pattern + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/find-and-replace-pattern/description/ + +> 内容描述 + +``` +You have a list of words and a pattern, and you want to know which words in words matches the pattern. + +A word matches the pattern if there exists a permutation of letters p so that after replacing every letter x in the pattern with p(x), we get the desired word. + +(Recall that a permutation of letters is a bijection from letters to letters: every letter maps to another letter, and no two letters map to the same letter.) + +Return a list of the words in words that match the given pattern. + +You may return the answer in any order. + + + +Example 1: + +Input: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb" +Output: ["mee","aqq"] +Explanation: "mee" matches the pattern because there is a permutation {a -> m, b -> e, ...}. +"ccc" does not match the pattern because {a -> c, b -> c, ...} is not a permutation, +since a and b map to the same letter. + + +Note: + +1 <= words.length <= 50 +1 <= pattern.length = words[i].length <= 20 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N*k)******- 空间复杂度: O(k)****** 这里k为最长的那个字符串的长度 + +1. 定义一个convert函数 + - 首先对于传进来的word做一个for loop + - 只要字符没有出现过就用一个全新的num来对应它 + - 否则就用之前存在dict里面的它所对应num来对应它 +2. 比较每个word convert之后是否于pattern convert之后相等,相等就加入最终结果 +3. 返回最终结果 + + +```python +class Solution(object): + def findAndReplacePattern(self, words, pattern): + """ + :type words: List[str] + :type pattern: str + :rtype: List[str] + """ + def convert(word): + lookup = {} + num = 0 + word_convert = '' + for i in word: + if i not in lookup: # 第一次出现这个字符 + num += 1 # 用一个全新的num来对应它 + word_convert += str(num) + lookup[i] = num # 存进dict供给后面用 + else: + word_convert += str(lookup[i]) # 之前出现过了这个字符那么就加上它之前对应的数字 + return word_convert + pattern_convert = convert(pattern) + res = [] + for word in words: + if convert(word) == pattern_convert: + res.append(word) + return res +``` + + + diff --git a/docs/Leetcode_Solutions/Python/891._Sum_of_Subsequence_Widths.md b/docs/Leetcode_Solutions/Python/891._Sum_of_Subsequence_Widths.md new file mode 100644 index 000000000..1f5297320 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/891._Sum_of_Subsequence_Widths.md @@ -0,0 +1,104 @@ +# 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)****** + + +设n为A数组的长度 + +先给A排序,其中以A[0]为最小值的子序列的个数为2^(n-1),以A[0]为最大值的子序列的个数为2^(0),以此类推。 + +开始写的代码如下: + +``` +class Solution(object): + def sumSubseqWidths(self, A): + """ + :type A: List[int] + :rtype: int + """ + A.sort() + res, n = 0, len(A) + for i in range(len(A)): + res -= A[i] * pow(2, n-1-i) + res += A[i] * pow(2, i) + res %= pow(10, 9) + 7 + return res +``` + + +但是一直超时,于是我觉得是因为pow()函数太费时间了,所以用空间换时间,先把所有2的0到(n-1)次方全部存起来,然后后面直接取就行了,果然AC + +beats 84.15% +```python +class Solution(object): + def sumSubseqWidths(self, A): + """ + :type A: List[int] + :rtype: int + """ + MOD = 10**9 + 7 + res, n = 0, len(A) + A.sort() + + pow2 = [1] + for i in xrange(1, n): + pow2.append(pow2[-1] * 2 % MOD) + + for i, x in enumerate(A): + res -= x * pow2[n-1-i] % MOD + res += x * pow2[i] % MOD + return res % MOD +``` + + + + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/900._RLE_Iterator.md b/docs/Leetcode_Solutions/Python/900._RLE_Iterator.md new file mode 100644 index 000000000..3cc60284d --- /dev/null +++ b/docs/Leetcode_Solutions/Python/900._RLE_Iterator.md @@ -0,0 +1,173 @@ +# 900. RLE Iterator + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/rle-iterator/description/ + +> 内容描述 + +``` + +Write an iterator that iterates through a run-length encoded sequence. + +The iterator is initialized by RLEIterator(int[] A), where A is a run-length encoding of some sequence. More specifically, for all even i, A[i] tells us the number of times that the non-negative integer value A[i+1] is repeated in the sequence. + +The iterator supports one function: next(int n), which exhausts the next n elements (n >= 1) and returns the last element exhausted in this way. If there is no element left to exhaust, next returns -1 instead. + +For example, we start with A = [3,8,0,9,2,5], which is a run-length encoding of the sequence [8,8,8,5,5]. This is because the sequence can be read as "three eights, zero nines, two fives". + + + +Example 1: + +Input: ["RLEIterator","next","next","next","next"], [[[3,8,0,9,2,5]],[2],[1],[1],[2]] +Output: [null,8,8,5,-1] +Explanation: +RLEIterator is initialized with RLEIterator([3,8,0,9,2,5]). +This maps to the sequence [8,8,8,5,5]. +RLEIterator.next is then called 4 times: + +.next(2) exhausts 2 terms of the sequence, returning 8. The remaining sequence is now [8, 5, 5]. + +.next(1) exhausts 1 term of the sequence, returning 8. The remaining sequence is now [5, 5]. + +.next(1) exhausts 1 term of the sequence, returning 5. The remaining sequence is now [5]. + +.next(2) exhausts 2 terms, returning -1. This is because the first term exhausted was 5, +but the second term did not exist. Since the last term exhausted does not exist, we return -1. + +Note: + +0 <= A.length <= 1000 +A.length is an even integer. +0 <= A[i] <= 10^9 +There are at most 1000 calls to RLEIterator.next(int n) per test case. +Each call to RLEIterator.next(int n) will have 1 <= n <= 10^9. +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(len(A))****** + + + +周赛的时候做的这道题,刚开始很sb,抱着试试的想法直接全部装起来然后一个个返回,果然太 naive + + +``` +class RLEIterator(object): + + def __init__(self, A): + """ + :type A: List[int] + """ + self.lst = A + self.tmp = [] + for i in range(0, len(self.lst), 2): + self.tmp.extend([self.lst[i+1]]*self.lst[i]) + + + + def next(self, n): + """ + :type n: int + :rtype: int + """ + if len(self.tmp) < n: + return -1 + else: + for i in range(n): + if i == n-1: + return self.tmp.pop(0) + self.tmp.pop(0) +``` + + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(len(A))****** + + +然后写了半天,每次只取一个的逻辑,还是超时了。真的蠢。。。。 + +``` +class RLEIterator(object): + + def __init__(self, A): + """ + :type A: List[int] + """ + self.lst = A + self.tmp = [] + self.cnt, self.num = 0, 0 + + + + + def next(self, n): + """ + :type n: int + :rtype: int + """ + if self.tmp: + if n == 1: + return self.tmp.pop(0) + else: + self.tmp.pop(0) + return self.next(n-1) + else: + if self.cnt > 0: + self.tmp.append(self.num) + self.cnt -= 1 + return self.next(n) + else: + if self.lst: + self.cnt, self.num = self.lst.pop(0), self.lst.pop(0) + return self.next(n) + else: + return -1 +``` + +> 思路 3 +******- 时间复杂度: O(N)******- 空间复杂度: O(len(A))****** + + +利用python built-in数据结构deque的性质,直接AC, beats 100% + +```python +class RLEIterator(object): + + def __init__(self, A): + """ + :type A: List[int] + """ + self._deque = collections.deque(A) + + + def next(self, n): + """ + :type n: int + :rtype: int + """ + while self._deque and n: + count = self._deque.popleft() + val = self._deque[0] + if count >= n: + self._deque.appendleft(count-n) + return val + else: + n -= count + self._deque.popleft() + return -1 + + + + +# Your RLEIterator object will be instantiated and called as such: +# obj = RLEIterator(A) +# param_1 = obj.next(n) +``` diff --git a/docs/Leetcode_Solutions/Python/902._Numbers_At_Most_N_Given_Digit_Set.md b/docs/Leetcode_Solutions/Python/902._Numbers_At_Most_N_Given_Digit_Set.md new file mode 100644 index 000000000..c14134124 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/902._Numbers_At_Most_N_Given_Digit_Set.md @@ -0,0 +1,88 @@ +# 902. Numbers At Most N Given Digit Set + +**难度: hard** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/numbers-at-most-n-given-digit-set/description/ + +> 内容描述 + +``` +We have a sorted set of digits D, a non-empty subset of {'1','2','3','4','5','6','7','8','9'}. (Note that '0' is not included.) + +Now, we write numbers using these digits, using each digit as many times as we want. For example, if D = {'1','3','5'}, we may write numbers such as '13', '551', '1351315'. + +Return the number of positive integers that can be written (using the digits of D) that are less than or equal to N. + + + +Example 1: + +Input: D = ["1","3","5","7"], N = 100 +Output: 20 +Explanation: +The 20 numbers that can be written are: +1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77. +Example 2: + +Input: D = ["1","4","9"], N = 1000000000 +Output: 29523 +Explanation: +We can write 3 one digit numbers, 9 two digit numbers, 27 three digit numbers, +81 four digit numbers, 243 five digit numbers, 729 six digit numbers, +2187 seven digit numbers, 6561 eight digit numbers, and 19683 nine digit numbers. +In total, this is 29523 integers that can be written using the digits of D. + + +Note: + +D is a subset of digits '1'-'9' in sorted order. +1 <= N <= 10^9 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(lgN)******- 空间复杂度: O(N)****** + + +这里时间复杂度为 O(lgN) 是因为我们把N看作是input里面N的大小 + +并且pow(x, y)的时间复杂度为: + +1. For y < 2^63, there's a loop of size ceil(log_2(y)), +2. but for larger y, the result is calculated using Exp(y * Log(x)). + + +参见[lee215](https://leetcode.com/problems/numbers-at-most-n-given-digit-set/discuss/168279/Python-O(logN)) +``` +- N has n digits, so all numbers less than n digits are valid, which are: sum(len(D) ** i for i in range(1, n)) +- The loop is to deal with all numbers with n digits, considering from N[0], N[1] back to N[n-1]. +For example, N[0] is valid only for c in D if c <= N[0]. +If c < N[0], then N[1], ..., N[n-1] can take any number in D but if c == N[0], then we need consider N[1], +and the iteration repeats. That's why if N[i] not in D, then we don't need to repeat the loop anymore. +- Finally i==n is addressed at the end when there exists all c in D that matches N +``` + +```python +class Solution(object): + def atMostNGivenDigitSet(self, D, N): + """ + :type D: List[str] + :type N: int + :rtype: int + """ + N = str(N) + n = len(N) + res = sum(pow(len(D), i) for i in range(1, n)) # 考虑少于n位的答案 + i = 0 + while i < n: # 开始考虑刚好为n位的答案 + res += sum(c < N[i] for c in D) * pow(len(D), n-i-1) # 每次只考虑比N当前位置的数字小的数字 + if N[i] not in D: # 如果N当前位置的数字都不在D里面了,我们考虑不了下一个位置 + break + i += 1 + return res + (i==n) # 如果N判断到最后一个位置的数字了,这个数字都还在D里面,我们就知道有一个刚好等于N的组合 +``` diff --git a/docs/Leetcode_Solutions/Python/904._Fruit_Into_Baskets.md b/docs/Leetcode_Solutions/Python/904._Fruit_Into_Baskets.md new file mode 100644 index 000000000..7adabebb5 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/904._Fruit_Into_Baskets.md @@ -0,0 +1,89 @@ +# 904. Fruit Into Baskets + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/contest/weekly-contest-102/problems/fruit-into-baskets/ + +> 内容描述 + +``` +In a row of trees, the i-th tree produces fruit with type tree[i]. + +You start at any tree of your choice, then repeatedly perform the following steps: + +Add one piece of fruit from this tree to your baskets. If you cannot, stop. +Move to the next tree to the right of the current tree. If there is no tree to the right, stop. +Note that you do not have any choice after the initial choice of starting tree: you must perform step 1, then step 2, then back to step 1, then step 2, and so on until you stop. + +You have two baskets, and each basket can carry any quantity of fruit, but you want each basket to only carry one type of fruit each. + +What is the total amount of fruit you can collect with this procedure? + + + +Example 1: + +Input: [1,2,1] +Output: 3 +Explanation: We can collect [1,2,1]. +Example 2: + +Input: [0,1,2,2] +Output: 3 +Explanation: We can collect [1,2,2]. +If we started at the first tree, we would only collect [0, 1]. +Example 3: + +Input: [1,2,3,2,2] +Output: 4 +Explanation: We can collect [2,3,2,2]. +If we started at the first tree, we would only collect [1, 2]. +Example 4: + +Input: [3,3,3,1,2,1,1,2,3,3,4] +Output: 5 +Explanation: We can collect [1,2,1,1,2]. +If we started at the first tree or the eighth tree, we would only collect 4 fruits. + + +Note: + +1 <= tree.length <= 40000 +0 <= tree[i] < tree.length +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + + +和第159一样的思路,时间复杂度最差为O(N),因为有可能整个列表只有两种不同的数字 + +```python +class Solution(object): + def totalFruit(self, A): + """ + :type tree: List[int] + :rtype: int + """ + maps = {} + begin, end, counter, res = 0, 0, 0, 0 + while end < len(A): + maps[A[end]] = maps.get(A[end], 0) + 1 + if maps[A[end]] == 1: + counter += 1 + end += 1 # end points to the next fruit + while counter > 2: + maps[A[begin]] -= 1 + if maps[A[begin]] == 0: + counter -= 1 + begin += 1 + res = max(res, end - begin) + return res +``` diff --git a/docs/Leetcode_Solutions/Python/905._Sort_Array_By_Parity.md b/docs/Leetcode_Solutions/Python/905._Sort_Array_By_Parity.md new file mode 100644 index 000000000..53439ccda --- /dev/null +++ b/docs/Leetcode_Solutions/Python/905._Sort_Array_By_Parity.md @@ -0,0 +1,72 @@ +# 905. Sort Array By Parity + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/sort-array-by-parity/description/ + +> 内容描述 + +``` +Given an array A of non-negative integers, return an array consisting of all the even elements of A, followed by all the odd elements of A. + +You may return any answer array that satisfies this condition. + + + +Example 1: + +Input: [3,1,2,4] +Output: [2,4,3,1] +The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted. + + +Note: + +1 <= A.length <= 5000 +0 <= A[i] <= 5000 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + +贼暴力思路 + +```python +class Solution(object): + def sortArrayByParity(self, A): + """ + :type A: List[int] + :rtype: List[int] + """ + return [i for i in A if i & 1 == 0] + [i for i in A if i & 1 == 1] +``` + + + + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +优化空间,in-place AC! + +```python +class Solution(object): + def sortArrayByParity(self, A): + """ + :type A: List[int] + :rtype: List[int] + """ + idx = 0 # idx 指向的永远是奇数的 candidate + for i in range(len(A)): + if A[i] & 1 == 0: + A[i], A[idx] = A[idx], A[i] + idx += 1 + return A +``` diff --git a/docs/Leetcode_Solutions/Python/907._Sum_of_Subarray_Minimums.md b/docs/Leetcode_Solutions/Python/907._Sum_of_Subarray_Minimums.md new file mode 100644 index 000000000..190ec1a83 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/907._Sum_of_Subarray_Minimums.md @@ -0,0 +1,163 @@ +# 907. Sum of Subarray Minimums + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/sum-of-subarray-minimums/description/ + +> 内容描述 + +``` + +Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarray of A. + +Since the answer may be large, return the answer modulo 10^9 + 7. + + + +Example 1: + +Input: [3,1,2,4] +Output: 17 +Explanation: Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4]. +Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1. Sum is 17. + + +Note: + +1 <= A.length <= 30000 +1 <= A[i] <= 30000 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + + +对于A中的每一个元素,我们只需要计算出以它为最小值且以它为结束的子串的个数left[i],然后再计算出以它为最小值且以它为开始的子串的个数right[i], +注意这其中不允许有重复(即一个优先原则,例如1,2,3,1,其中先出现的那个1才是最小值,这样可以避免我们重复计算子串) + +``` +然后假设我们的A为[3,2,1,2,3] + +那么对于中间的1来说,它的left[i]为3,right[i]也为3 +那么它一共涉及到多少个字串呢,我们枚举一下 + +3,2,1 +2,1 +1 +3,2,1,2 +2,1,2 +1,2 +3,2,1,2,3 +2,1,2,3 +1,2,3 + + +一共涉及到9个,也就是说以A{i]为最小值的子串总数其实等于left[i] 和right[i]的乘积,这个也可以自己想出来,枚举只是为了看的更清晰 +``` + +所以现在我们的目标变成了求以A中每一个元素为最小值的子串个数的list,命名为sub_counts + +例如还是上面的例子,我们的sub_counts = [1*1, 2*1, 3*3, 1*2, 1*1], 这里的对称性不是普遍的,因为我们的输入是对称的。 + +所以我们的结果就是A中的每一个元素与其sub_count乘积的总和,即3*(1*1) + 2*(2*1) + 1*(3*3) + 2*(1*2) + 3*(1*1) = 23 + + +整个思路都是参考[寒神](https://leetcode.com/problems/sum-of-subarray-minimums/discuss/170750/C++JavaPython-Stack-Solution?page=2)的 + +AC 代码如下: +beats 53.98% + + +```python +class Solution(object): + def sumSubarrayMins(self, A): + """ + :type A: List[int] + :rtype: int + """ + stack_left, stack_right = [], [] + # 分别代表左边和右边所涉及的子串个数的list + sub_left, sub_right = [0] * len(A), [0] * len(A) + for i in range(len(A)): + count = 1 # 初始都是1,因为自己本身算一个 + while stack_left and stack_left[-1][0] > A[i]: + count += stack_left.pop()[1] + sub_left[i] = count # 其左边涉及子串个数为count + # stack—_left里面存的是A[i]这个元素前面有多少个严格比它小的数字 + stack_left.append((A[i], count)) + for i in range(len(A))[::-1]: + count = 1 + while stack_right and stack_right[-1][0] >= A[i]: + count += stack_right.pop()[1] + sub_right[i] = count # 其右边涉及子串个数为count + # stack—_right里面存的是A[i]这个元素前面有多少个大于等于它的数字 + stack_right.append((A[i], count)) + + return sum(a * l * r for a, l, r in zip(A, sub_left, sub_right)) % (10**9 + 7) +``` + +时间复杂度为O(N),因为对于A中的每一个元素我们都值进行了恰好两次push stack操作和最多2次pop stack的操作,因此是O(N) + +空间显然为O(N) + + +> 思路 2 +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** + + +看了下,别人说这两个stack可以one pass,一个stack就够了, beats 100% + + +不得不说,其中```left = stack[-1] if stack else -1```这句代码真的精妙绝伦,至少我想不到 +代码如下: + + +```python +class Solution(object): + def sumSubarrayMins(self, A): + """ + :type A: List[int] + :rtype: int + """ + count, stack = 0, [] + for i in range(len(A)): + while stack and A[stack[-1]] >= A[i]: + pos = stack.pop() + # 下面这句代码是整个代码中最精妙的一句了 + left = stack[-1] if stack else -1 + # 这里一次就把涉及A[i]的子串的和全部加上次 + count += (i - pos) * (pos - left) * A[pos] + stack.append(i) + + while stack: + pos = stack.pop() + left = stack[-1] if stack else -1 + count += (pos - left) * (len(A) - pos) * A[pos] + return count % (10**9 + 7) +``` + + + + + + + + + + + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/908._Smallest_Range.md b/docs/Leetcode_Solutions/Python/908._Smallest_Range.md new file mode 100644 index 000000000..de79b5db6 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/908._Smallest_Range.md @@ -0,0 +1,79 @@ +# 908. Smallest Range + +**难度: Easy** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/smallest-range-i/description/ + +> 内容描述 + +``` +Given an array A of integers, for each integer A[i] we may choose any x with -K <= x <= K, and add x to A[i]. + +After this process, we have some array B. + +Return the smallest possible difference between the maximum value of B and the minimum value of B. + + + +Example 1: + +Input: A = [1], K = 0 +Output: 0 +Explanation: B = [1] +Example 2: + +Input: A = [0,10], K = 2 +Output: 6 +Explanation: B = [2,8] +Example 3: + +Input: A = [1,3,6], K = 3 +Output: 0 +Explanation: B = [3,3,3] or B = [4,4,4] + + +Note: + +1 <= A.length <= 10000 +0 <= A[i] <= 10000 +0 <= K <= 10000 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + +比赛起晚了,9点25惊醒,看到题目后 3 分钟多一点 bug free 一遍 AC + +这个题目这么简单就没必要说什么了 + + +```python +class Solution(object): + def smallestRangeI(self, A, K): + """ + :type A: List[int] + :type K: int + :rtype: int + """ + max_num = max(A) + min_num = min(A) + if max_num - min_num > 2 * abs(K): + return max_num - min_num - 2 * abs(K) + elif max_num - min_num <= 2 * abs(K): + return 0 +``` + + + + + + + + + diff --git a/docs/Leetcode_Solutions/Python/910._Smallest_Range_II.md b/docs/Leetcode_Solutions/Python/910._Smallest_Range_II.md new file mode 100644 index 000000000..eb6f06c3e --- /dev/null +++ b/docs/Leetcode_Solutions/Python/910._Smallest_Range_II.md @@ -0,0 +1,83 @@ +# 910. Smallest Range II + +**难度: Medium** + +## 刷题内容 + +> 原题连接 + +* https://leetcode.com/problems/smallest-range-ii/description/ + +> 内容描述 + +``` +Given an array A of integers, for each integer A[i] we need to choose either x = -K or x = K, and add x to A[i] (only once). + +After this process, we have some array B. + +Return the smallest possible difference between the maximum value of B and the minimum value of B. + + + +Example 1: + +Input: A = [1], K = 0 +Output: 0 +Explanation: B = [1] +Example 2: + +Input: A = [0,10], K = 2 +Output: 6 +Explanation: B = [2,8] +Example 3: + +Input: A = [1,3,6], K = 3 +Output: 3 +Explanation: B = [4,6,3] + + +Note: + +1 <= A.length <= 10000 +0 <= A[i] <= 10000 +0 <= K <= 10000 +``` + +## 解题方案 + +> 思路 1 +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** + + +今天比赛睡晚了,总共只有35分钟,所以没什么时间,没有想出来,事后证明自己已经非常接近了 + +这道题的AC率12%左右,其实有点难想出来的 + +开始我想的是先算出max_num和min_num,再算出它们两的平均值avg_num,然后对于A中的所有数字,如果大于avg_num就减去K,如果小于等于avg_num就加上K。 +但是这样是不对的,毕竟这种东西跟我们的K也是有关的 + +最后想到我们先把A排序,然后A前面一部分比较小的数字全部加上K,后面那部分比较大的数字全部减去K,这样找到一个临界值,使得我们最终的极值最小 + +所以我们对排序后的A做一个遍历,然后每一轮的最大值会在```A[i]+K```和```A[-1]-K```之间取,最小值只会在```A[i+1]-K```和```A[0]+K```中取 + +```python +class Solution(object): + def smallestRangeII(self, A, K): + """ + :type A: List[int] + :type K: int + :rtype: int + """ + if not A or len(A) <= 1: + return 0 + if len(A) == 2: + return min(A[-1]-A[0], abs(A[-1]-A[0]-2*K)) + + K = abs(K) + A.sort() + res = sys.maxsize + for i in range(len(A)-1): + tmp = max(A[i]+K, A[-1]-K) - min(A[i+1]-K, A[0]+K) + res = min(res, tmp) + return min(res, A[-1]-A[0]) +``` diff --git a/docs/Leetcode_Solutions/Python/README.md b/docs/Leetcode_Solutions/Python/README.md new file mode 100644 index 000000000..c477b8c84 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/README.md @@ -0,0 +1 @@ +# Leetcode solutions and summarizations! diff --git a/docs/Leetcode_Solutions/Python/Summary/Binary Search.md b/docs/Leetcode_Solutions/Python/Summary/Binary Search.md new file mode 100644 index 000000000..e935c0c3f --- /dev/null +++ b/docs/Leetcode_Solutions/Python/Summary/Binary Search.md @@ -0,0 +1,42 @@ +### Binary Search + + +```python +def binarySearch(nums, target): + l, r = 0, len(nums) -1 + while l <= r: + mid = l + ((r-l) >> 1) + if nums[mid] > target: + r = mid - 1 + elif nums[mid] < target: + l = mid + 1 + else: + return mid + return -1 +``` + + +wisdompeak大佬说, + +标准模板就两套: +``` +while (left x的最小值 + + ​ • 如果x所在的节点有一个非空的右子树,则右子树中的最小值就是答案 + + ​ • 否则我们需要向上回溯,找到最近的一个祖先,使得该祖先的左侧孩子,也为x的祖 先。 + ​ + + - [x] 删除 + + • 如果x没有子节点,或者只有一个孩子,直接将x“切下”; + + • 否则,x有两个孩子,我们用其右子树中的最小值替换掉x,然后将右子树中的这一最小值“切掉”。 + + + + + + +- [x] 递归 + - [x] 入门 + + - 回文 + - 阶乘 factorial, 慕指数 + - 分形 + - Tower of Hanoi + + - [x] 排列 Permutation + + - [x] 子集 Subsets + + - [ ] backtracking + + +- [x] dynamic programming + + - coin change + + - longest common subsequence + + - edit distance + + ​ + + + + +-[ ] majority element + + + +- [ ] 随机 + - 水塘抽样 + - 洗牌 + + +-[ ] 荷兰旗问题 + + +-[ ] quick select + + +-[ ] median of two sorted array +-[ ] regular expression + diff --git a/docs/Leetcode_Solutions/Python/Summary/Dynamic Programming.md b/docs/Leetcode_Solutions/Python/Summary/Dynamic Programming.md new file mode 100644 index 000000000..102d032c3 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/Summary/Dynamic Programming.md @@ -0,0 +1,48 @@ +### Dynamic Programming + + + +- Fibonacci Numbers +- Shortest Path (no cycles) + + + + + + + +- subproblems + +- guessing + +- relate subproblems + +- recurse & memoize (bulid DP table) + +- solve original problem + + ​ + + + + + + +​ +​ +​ + +感觉DP有几类: + +- 容易写出递推公式的 + +- 画表更容易理解的 + + ​ + +* DP ≈ “controlled brute force” + +* DP ≈ recursion + re-use + + ​ + diff --git "a/docs/Leetcode_Solutions/Python/Summary/Introduction to String Searching Algorithms \342\200\223 topcoder.pdf" "b/docs/Leetcode_Solutions/Python/Summary/Introduction to String Searching Algorithms \342\200\223 topcoder.pdf" new file mode 100644 index 000000000..110950bf9 Binary files /dev/null and "b/docs/Leetcode_Solutions/Python/Summary/Introduction to String Searching Algorithms \342\200\223 topcoder.pdf" differ diff --git "a/docs/Leetcode_Solutions/Python/Summary/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/Leetcode_Solutions/Python/Summary/Java\345\220\204\347\247\215\347\261\273\345\236\213\347\232\204\350\275\254\346\215\242.md" new file mode 100644 index 000000000..c1d3e5522 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/Java\345\220\204\347\247\215\347\261\273\345\236\213\347\232\204\350\275\254\346\215\242.md" @@ -0,0 +1,239 @@ +之前在写java程序的时候,经常会遇到很多的需要需要转换基础数据类型的情况,然后我就一直去记录这些情况,今天做了一下总结,当然转换的方法肯定不止我写的这些,有的我可能只会写其中的一种,以后再遇到其他的情况的话,我会慢慢来补充,希望这篇文章会对大家能有所帮助。 + +------ + +# String的转换 + +首先介绍一下String类型的转换,一般遇到的情况可能会有以下几种:Strng转int,String转long,String转byte数组,String转float,下面主要介绍这四种情况。 + +## String转int + +把String类型转换为int类型,常用的有以下三种方法: + +``` +public class StringToInt { + public static void main(String[] args) { + String number = "123456"; + int num1 = Integer.parseInt(number);//使用Integer的parseInt方法 + int num2 = new Integer(number);//强制转换 + int num3 = Integer.valueOf(number).intValue();//先转Integer类型,再调用intValue()转为int + } +} +``` + +## String转long + +把String类型转换为long类型的方法跟上面的方法类似。 + +``` +public class StringToLong { + public static void main(String[] args) { + String number = "1234567890"; + long num1 = Long.parseLong(number);//调用Long类型的parseLong方法 + long num2 = new Long(number);//强制转换 + long num3 = Long.valueOf(number).longValue();//先转换Long类型,再使用longValue方法转为long + } +} +``` + +## String转float + +把String类型转换为float类型的方法也跟上面的类似。 + +``` +public class StringToFloat { + public static void main(String[] args) { + String number = "1234.202"; + float num1 = Float.parseFloat(number);//调用Float的parseFloat方法 + float num2 = new Float(number);//强制转换 + float num3 = Float.valueOf(number).floatValue();//先转为Float类型再使用floatValue转为float + } +} +``` + +## String转byte[] + +String类型转byte数组方法一般使用String类自带的`getBytes()`方法。 + +``` +public class StringToByte { + public static void main(String[] args) { + byte[] num = new byte[200]; + String number = "1234567890"; + num = number.getBytes(); + } +} +``` + +这里补充一个path类型转换为String类型的方法: + +``` +String fileName=path.getFileName().toString(); +``` + +------ + +# long类型转换 + +long类型的转换,这一部分用的情况也很多,下面介绍几种常见的情况。 + +## long转String + +long类型转String类型,这里主要介绍三种方法: + +``` +public class LongToString { + public static void main(String[] args) { + long number = 1234567890l; + String num1 = Long.toString(number);//Long的tostring方法 + String num2 = String.valueOf(number);//使用String的valueOf方法 + String num3 = "" + number;//这个应该属于强制转换吧 + } +} +``` + +## long转int + +long类型转换为int类型,这里也主要介绍三种方法: + +``` +public class LongToInt { + public static void main(String[] args) { + long number = 121121121l; + int num1 = (int) number;// 强制类型转换 + int num2 = new Long(number).intValue();// 调用intValue方法 + int num3 = Integer.parseInt(String.valueOf(number));// 先把long转换位字符串String,然后转换为Integer + } +} +``` + +## long与byte数组的相互转换 + +一直都感觉byte数组转换比较繁琐,这里也不再叙述,我就给出一篇别人的博客让大家作为参考吧,这里面byte数组与多种数据类型的转换——[ java Byte和各数据类型(short,int,long,float,double)之间的转换](http://blog.csdn.net/cshichao/article/details/9813973) + +------ + +# int类型的转换 + +int类型的转换也是我们经常使用的情况,下面也主要介绍几种常见的情况。 + +## int转String + +int类型转换为String类型与long转String的类似,一般也有以下三种方法。 + +``` +public class IntToString { + public static void main(String[] args) { + int number = 121121; + String num1 = Integer.toString(number);//使用Integer的toString方法 + String num2 = String.valueOf(number);//使用String的valueOf方法 + String num3 = "" + number;//也是强制转换吧 + } +} +``` + +## int与Byte的相互转换 + +关于int类型与byte[]数组的转换,一般情况下,我们使用条件都是在这里转换过来,在另外一个地方就要转换回来,这里介绍两种int与byte数组互相转换的方式。 + +``` +//int类型转换为byte[]数组 +public static byte[] intToByteArray(int i) { + byte[] result = new byte[4]; + // 由高位到低位 + result[0] = (byte) ((i >> 24) & 0xFF); + result[1] = (byte) ((i >> 16) & 0xFF); + result[2] = (byte) ((i >> 8) & 0xFF); + result[3] = (byte) (i & 0xFF); + return result; +} + +//byte数组转换为int类型 +public static int byteArrayToInt(byte[] bytes) { + int value = 0; + // 由高位到低位 + for (int i = 0; i < 4; i++) { + int shift = (4 - 1 - i) * 8; + value += (bytes[i] & 0x000000FF) << shift;// 往高位游 + } + return value; +} +``` + +还有一种为: + +``` +//int类型转换为byte[]数组 +public static byte[] intToByteArray(int x) { + byte[] bb = new byte[4]; + bb[3] = (byte) (x >> 24); + bb[2] = (byte) (x >> 16); + bb[1] = (byte) (x >> 8); + bb[0] = (byte) (x >> 0); + return bb; +} + +//byte数组转换为int类型 +public static int byteArrayToInt(byte[] bb) { + return (int) ((((bb[3] & 0xff) << 24) | ((bb[2] & 0xff) << 16) | ((bb[1] & 0xff) << 8) | ((bb[0] & 0xff) << 0))); +} +``` + +## int转long + +int类型转换为long类型的情况并不是大多,这里主要接收几种转换方法: + +``` +public class IntToLong { + public static void main(String[] args) { + int number = 123111; + long num1 = (long) number;//强制 + long num2 = Long.parseLong(new Integer(number).toString());//先转String再进行转换 + long num3 = Long.valueOf(number); + } +} +``` + +## int转Interger + +int类型转换为Interger类型的情况,我是基本上每怎么遇到过,在这里也上网查询一些资料找到了两种方法。 + +``` +public class IntToInterge { + public static void main(String[] args) { + int number = 123456; + Integer num1 = Integer.valueOf(number); + Integer num2 = new Integer(number); + } +} +``` + +------ + +# byte数组的转换 + +关于byte数组的转换,上面有几个都是它们只见相互转换的,所以这里就不再介绍那么多,只介绍一个byte数组转换String类型的方法,其他的类型可以通过String类型再进行转换。 + +byte数组转String类型的方法经常用的可能就是下面这种方法。 + +``` +public class ByteToString { + public static void main(String[] args) { + byte[] number = "121121".getBytes(); + String num1 = new String(number); + } +} +``` + +------ + +最后简单补充以下Java基本数据类型的一些知识: + +| 类型 | 字节数 | 类名称 | 范围 | +| ------ | ---- | -------- | ---------------------------------------- | +| int | 4字节 | Interger | -2147483648 ~ 2147483647 | +| short | 2字节 | Short | -32768 ~ 32767 | +| long | 8字节 | Long | -9223372036854775808 ~ 9223372036854775807 | +| byte | 1字节 | Byte | -128 ~ 127 | +| float | 4字节 | Float | | +| double | 8字节 | Double | | \ No newline at end of file diff --git "a/docs/Leetcode_Solutions/Python/Summary/LinkedList\346\212\200\345\267\247.md" "b/docs/Leetcode_Solutions/Python/Summary/LinkedList\346\212\200\345\267\247.md" new file mode 100644 index 000000000..677a083a2 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/LinkedList\346\212\200\345\267\247.md" @@ -0,0 +1,118 @@ +# LinkedList + +结点定义如下: + + class ListNode(object): + def __init__(self, x): + self.val = x + self.next = None + + +可以使用的技巧包括: + + +## Dummy head + +有的时候因为边界条件,需要判定是否是list的head,因为处理起来会有些不同,而创造一个dummy head则可以极大的解决一些问题。 + +``` + dummy = ListNode(-1) + dummy.next = head +``` + +## 双指针 + +- 19. Remove Nth Node From End of List + +两个指针p,q, q先走n步,然后p和q一起走,直到q走到结点,删除p.next解决。 + +理解: 先走了n步,q始终在p前方n个,这样q走到末尾,p的下一个则是距离尾端n个的,画个图还是容易理解。 + + +- 160. Intersection of Two Linked Lists + +如果两个linkedlist有intersection的话,可以看到,其实如果一开始我们就走到b2的话,那么我们就可以两个pointer一个一个的对比,到哪一个地址一样,接下来就是intersection部分。 + +就一开始把长的那条list走掉多余部分。 +还有这里保证了是无环的状况 + + + +``` +A: a1 → a2 + ↘ + c1 → c2 → c3 + ↗ +B: b1 → b2 → b3 +``` + + +## 快慢指针 + +- 141. Linked List Cycle + +用两个指针,一个每次走两步,一个每次走一步,如果慢的最终和快的相遇,那么说明有环,否则没有环,直观的理解是如果两个跑的速度不一的人进操场跑步,那么最终慢的会追上快的. + + + +## Reverse Linked List + +- 206. Reverse Linked List + +loop版本用prev, cur ,nxt 三个指针过一遍,recursion版本如下,可以再消化消化 + +``` +class Solution(object): + def reverseList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + return self.doReverse(head, None) + + + def doReverse(self, head, newHead): + if head == None: + return newHead + nxt = head.next + head.next = newHead + return self.doReverse(nxt, head) +``` + + +## 寻找LinkedList中间项 + +依旧使用双指针,快慢指针:快指针每次走两步,慢指针每次走一步,快指针如果到头了,那么慢指针也会在中间了,这个中间可以考量,如果是奇数的话必然是中间。 + +如果是偶数则是偏前面的中间一项 + +``` +1 -> 2 -> 3 -> 4: 2 +1 -> 2 -> 3 -> 4 -> 5 -> 6 : 3 +1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 : 4 + +``` + +算法: + +``` + +def findMid(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 +``` + + + + + + diff --git a/docs/Leetcode_Solutions/Python/Summary/Maximal Square.pdf b/docs/Leetcode_Solutions/Python/Summary/Maximal Square.pdf new file mode 100644 index 000000000..235cd3b86 Binary files /dev/null and b/docs/Leetcode_Solutions/Python/Summary/Maximal Square.pdf differ diff --git "a/docs/Leetcode_Solutions/Python/Summary/Python\345\210\267\351\242\230\346\212\200\345\267\247\347\254\224\350\256\260.md" "b/docs/Leetcode_Solutions/Python/Summary/Python\345\210\267\351\242\230\346\212\200\345\267\247\347\254\224\350\256\260.md" new file mode 100644 index 000000000..c781932a3 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/Python\345\210\267\351\242\230\346\212\200\345\267\247\347\254\224\350\256\260.md" @@ -0,0 +1,206 @@ + +### python有无数奇技淫巧和许多人不知道的秘密,这里用简洁的语言一条条表述出来,不断更新, 大家一起贡献! +```python +# 1. python 排序 +# 用lst.sort() 而不是nlst = sorted(lst), 区别在于lst.sort()是 in-place sort,改变lst, sorted会创建新list,成本比较高。 +``` +```python +# 2. xrange和range的区别 +# range会产生list存在memory中,xrange更像是生成器,generate on demand所以有的时候xrange会更快 +``` +```python +# 3. python处理矩阵 +row = len(matrix) +col = len(matrix[0]) if row else 0 +# 这样写通用的原因是, 当matrix = [], row = 0, col = 0 +``` +```python +# 4. python列表生成式 +lst = [0 for i in range(3)] # lst = [0,0,0] +lst = [[0 for i in range(3)] for j in range(2)] # lst =  [[0, 0, 0], [0, 0, 0]] +# 下面这种写法危险: +# lst1 = [ 0, 0, 0 ] +# lst2  = [lst1] * 2  # lst2 = [ [0,0,0] , [0,0,0] ] +# lst2[0][0] = 1  # lst2 = [ [1,0,0], [1,0,0]] +# 因为lst1是object,改一个相当于全改, 这样写会踩坑 +``` +```python +# 5. D.get(key, default) +# 如果这个key 没有在dict里面,给它一个默认值: +D = {} +if 1 in D: + val = D[1] +else : + val = 0 +# 等同于这样写: +val = D.get(1, 0) +``` +```python +# 6. 字典赋值 +if key in D: + D[key].append(1) +else : + D[key] = [] +``` +```python +# 7. 字符串反转和列表反转 +# python字符串没有reverse函数,只能str[::-1] +string[::-1] +# python的list可以直接reverse(),因此也可以借用这个特性 +"".join([string].reverse()) + +测试了一下3种列表反转的速度 +tmp = [i for i in range(100000)] + +import datetime +starttime = datetime.datetime.now() + +for i in range(100000): + tmp = tmp[::-1] +endtime = datetime.datetime.now() +print((endtime - starttime)) + +starttime = datetime.datetime.now() +for i in range(100000): + tmp = list(reversed(tmp)) +endtime = datetime.datetime.now() +print((endtime - starttime)) + +starttime = datetime.datetime.now() +for i in range(100000): + tmp.reverse() +endtime = datetime.datetime.now() +print((endtime - starttime)) + + + + +输出: +0:00:33.486971 +0:01:43.027222 +0:00:03.958400 + +说明in-place反转最快,但是这样改变了原list,因此在不能改动原list的情况下,我们用分片会更好 +``` +```python +# 8. 快速统计 +import collections +lst = [1, 1, 1, 2, 3, 4, 5, 5] +collections.Counter(lst) # Counter({1: 3, 5: 2, 2: 1, 3: 1, 4: 1}) +``` +```python +# 9. python自带小顶堆heapq +# Python有built-in heap, 默认min heap. +heapq.heappush(heap, item) # 把item添加到heap中(heap是一个列表) + +heapq.heappop(heap) # 把堆顶元素弹出,返回的就是堆顶 + +heapq.heappushpop(heap, item) # 先把item加入到堆中,然后再pop,比heappush()再heappop()要快得多 + +heapq.heapreplace(heap, item) # 先pop,然后再把item加入到堆中,比heappop()再heappush()要快得多 + +heapq.heapify(x) # 将列表x进行堆调整,默认的是小顶堆 + +heapq.merge(*iterables) # 将多个列表合并,并进行堆调整,返回的是合并后的列表的迭代器 + +heapq.nlargest(n, iterable, key=None) # 返回最大的n个元素(Top-K问题) + +heapq.nsmallest(n, iterable, key=None) # 返回最小的n个元素(Top-K问题) + +# 如何来用它实现max heap呢,看到过一个有意思的方法是把key取负,比如把100变成-100,5变成-5 + +import heapq +mylist = [1, 2, 3, 4, 5, 10, 9, 8, 7, 6] +largest = heapq.nlargest(3, mylist) # [10, 9, 8] +smallest = heapq.nsmallest(3, mylist) # [1, 2, 3] +``` +```python +# 10. 双端队列deque [http://stackoverflow.com/questions/4098179/anyone-know-this-python-data-structure] +# 可以很简单的.popleft(), .popright(), .appendleft(), .appendright(),最关键的是时间是O(1), 而用list来模拟队列是O(n)的时间复杂度 +# 还有很好用的rotate函数, +# 一个简单的跑马灯程序 +import sys +import time +from collections import deque + +fancy_loading = deque('>--------------------') + +while True: + print('\r%s' % ''.join(fancy_loading)) + fancy_loading.rotate(1) + sys.stdout.flush() + time.sleep(0.08) +``` +```python +# 11. 用yield 不用return,可以返回一个generator +``` +```python +# 12. 符号~的巧妙应用 +for i in range(n): + # 这里的```[~i]``` 意思就是 ```[n-1-i]``` + a[~i] = 1 +``` +```python +# 13. 位运算判断奇偶数 +一般判断奇偶数是用 num % 2 == 0 来判断,如果为true则为偶数,为false则为奇数。 +偶数在二进制里面,最后一位为0,奇数则为1。所以可以通过与1做位与运算判断奇偶数。 +if (num & 1) == 0: + print('偶数') +else: + print('奇数') +如果结果为true则为偶数,为false则为奇数。效率比取余运算高的多。 + +反正注意不要使用 +if num % 2 == 1 +来判断是否是奇数,因为如果是负奇数就不满足了 + +最起码也要用if num % 2 != 0 +``` + + +```python +# 14. pow(x, y)的时间复杂度为: + +For y < 2^63, there's a loop of size ceil(log_2(y)), +but for larger y, the result is calculated using Exp(y * Log(x)). + +sqrt()函数平常认为是O(lgn)的 +但是追溯到最底层,sqrt()就是O(1)的,详细见 +``` +1. [求平方根sqrt()函数的底层算法效率问题](http://www.nowamagic.net/algorithm/algorithm_EfficacyOfFunctionSqrt.php) +2. [Time complexity of Math.Sqrt()?](https://stackoverflow.com/questions/34580158/time-complexity-of-math-sqrt) + + +```python +# 15. python deque用法 + +Operations on deque : + +1. append() :- This function is used to insert the value in its argument to the right end of deque. +2. appendleft() :- This function is used to insert the value in its argument to the left end of deque. +3. pop() :- This function is used to delete an argument from the right end of deque. +4. popleft() :- This function is used to delete an argument from the left end of deque. +5. index(ele, beg, end) :- This function returns the first index of the value mentioned in arguments, starting searching from beg till end index. +6. insert(i, a) :- This function inserts the value mentioned in arguments(a) at index(i) specified in arguments. +7. remove() :- This function removes the first occurrence of value mentioned in arguments. +8. count() :- This function counts the number of occurrences of value mentioned in arguments. +9. extend(iterable) :- This function is used to add multiple values at the right end of deque. The argument passed is an iterable. +10. extendleft(iterable) :- This function is used to add multiple values at the left end of deque. The argument passed is an iterable. Order is reversed as a result of left appends. +11. reverse() :- This function is used to reverse order of deque elements. +12. rotate() :- This function rotates the deque by the number specified in arguments. If the number specified is negative, rotation occurs to left. Else rotation is to right. +``` +[Deque in Python](https://www.geeksforgeeks.org/deque-in-python/) + + +```python +# 16. getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned. + +# 这种是常规方法 +idx = random.randint(0, self.length-1) +return self.lst[idx] +# 神奇函数 +return random.choice(self.lst) +``` + + + diff --git a/docs/Leetcode_Solutions/Python/Summary/Range Sum Query 2D - Immutable.pdf b/docs/Leetcode_Solutions/Python/Summary/Range Sum Query 2D - Immutable.pdf new file mode 100644 index 000000000..09410e209 Binary files /dev/null and b/docs/Leetcode_Solutions/Python/Summary/Range Sum Query 2D - Immutable.pdf differ diff --git a/docs/Leetcode_Solutions/Python/Summary/Recusrion & BackTracking.md b/docs/Leetcode_Solutions/Python/Summary/Recusrion & BackTracking.md new file mode 100644 index 000000000..16e0f9279 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/Summary/Recusrion & BackTracking.md @@ -0,0 +1,237 @@ +#Recusrion & BackTracking + +##Recusrion + +### DrawFractal + +``` +void DrawFractal(double x, double y, double w, double h) +{ + DrawTriangel(x, y, w, h); + if(w < .2 || h < .2) return ; + double halfH = h/2; + double halfw = w/2; + DrawFractal(x, y, halfW, halfH); + DrawFractal(x + halfW/2, y + halfH, halfW, halfH); + DrawFractal(x + halfW, y, halfW, halfH); +} +``` + + +Sierpinski triangle更伪码的写法: + +``` +void DrawFractal (x, y, w, h){ + if (too small) return ; + DrawTriangle(x, y, w, h); + DrawFractal(.left); + DrawFractal(.top); + DrawFractal(.right); +} +``` + +实际上老师故意调了里面几句代码的顺序,让来看到虽然结果相同,但是画的过程是不一样的。 + +然后老师还在黑板上画了过程树,分枝是怎样的,实际上当学到DFS的preOrder, inOrder 和 postOrder的时候会更印象深刻。 + +一个分支走完之后再回去走另一些。 + + +### DrawMondrian + + + +``` +void DrawMondrian(double x, double y, double w, double h){ + + if(w < 1 || h < 1) return ;// base case + + FillRectangle(x,y,w,h,RandomColor()); // fill background + + switch(RandomInteger(0, 2)){ + case 0: // do nothing + break; + case 1: // bisect vertically + double midX = RandomReal(0,w); + DrawBlackLine( x + midX, y, h); + DrawMondrian(x, y, midX, h); + DrawMondrian(x + midx, y, w- midX, h); + break; + case 2: // bisect horizontally + double midY = RandomReal(0,h); + DrawBlackLine( x, y+ midY, h); + DrawMondrian(x, y, w, midY); + DrawMondrian(x, y+midY,w, midY); + break; + } +} +``` + + +### The tower of Hanoi + + +``` +void MoveTower(int n, char src, char dst, char tmp){ + if (n > 0){ + MoveTower(n - 1, src, tmp, dst ); + MoveSingleDisk(src, dst); + MoveTower(n -1, tmp, dst, src); + } +} + +``` + + +### Permutation + +老师说permutation 和 subset 是 mother problems of all recursion. + + +given a string, print out its all permutations + +思路如下: + +- 使用了的string sofar,以及还未使用的string rest +- 一开始rest就是给的string本身,然后sofar是空 +- 每次挑一个rest里面的char,然后递归的再把rest剩下的拿来permutation,这样每次都会有一个char从rest shuffle到sofar +- n 次之后 rest为空,制造了一个permutation + + +``` +void RecPermute(string sofar, string rest){ + if(rest = ""){ + cout << soFar << endl; + } else { + for(int i = 0 ; i < rest.length(); i++){ + string next = soFar + rest[i]; + string remaining = rest.substr(0,i) + rest.substr(i+1); + RecPermute(next, remaining); + } + } +} + + +// "wrapper" function +void ListPermutations(string s) +{ + RecPermute("",s); +} +``` + + +老师的黑板图真的是击中要害。 + +因为老师强调的是,也要用mind来trace它是如何操作的。 + + + +### Subsets + + +``` +void RecSubsets(string soFar, string rest) +{ + if(rest = "") + cout << soFar << endl; + else { + // add to subset, remove from rest, recur + RecSubsets(soFar + rest[0],rest.substr(1)); + //don't add to substr, remove from rest, recur + RecSubsets(soFar, rest.substr(1)); + } +} + + +void ListSubsets(string str) +{ + RecSubsets("",str); +} + +``` + +代码非常容易理解 + + +比较一下:两个都是有关选择,permutation是每次选哪一个char,而subsets是选择这个char 是否in. + +两个recursion tree都是有branching 和 depth的, depth都是n,每次选一个,知道n个选完. + +branching是how many recusive calls 每次made,subset每次都是两个,in/out,而permutation则是n,n-1.......grows very quickly. + +因为permutation是n!,subsets是2^n,跟树对应。这些都是比较intractable的问题,并不是因为recursion,而是问题本身的复杂度。 + + +这两个问题都是exhaustive的,然而,我们会更多碰到一些问题,有着 + +similar exhaustive structure,但是遇到'satisfactory' outcome就会stop的 -> 也就是backtracking了. + +##BackTracking + + + +### pseudocode + +把问题转成decision problem,然后开始make choice. + +``` +bool Solve(configuration conf) +{ + if (no more choices) // BASE CASE + return (conf is goal state); + + for (all available choices){ + try one choice c; + // sove from here, it works out. you're done. + if (Solve(conf with choice c made)) return true; + unmake choice c; + } + return false; //tried all choices, no soln found +} +``` + + +###IsAnagram + + +``` +bool IsAnagram(string soFar, string rest, Lexicon & lex) +{ + if(rest == ""){ + if(lex.contains(soFar)){ + cout << soFar << endl; + return true; + } + } else { + for(int i = 0; i < rest.length() ; i++ ){ + string next = soFar + rest[i]; + string remaining = rest.substr(0,i) + rest.substr(i+1); + if(IsAnagram(next, remaining, lex)) return true; + } + } + return false; +} +``` + + +### 8 Queens + + +``` + +bool Solve(Grid &board, int col) +{ + if(col > = board.numCols()) return true; + + for(int rowToTry = 0; rowToTry < board.numRows(); rowToTry++){ + if (IsSafe(board,rowToTry, col)){ + PlaceQueen(board,rowToTry,col); + if (Solve(board,col+1)) return true; + RemoveQueen(board,rowToTry, col); + } + } + return false; +} + +``` + diff --git "a/docs/Leetcode_Solutions/Python/Summary/backtracking\346\200\235\350\267\257.md" "b/docs/Leetcode_Solutions/Python/Summary/backtracking\346\200\235\350\267\257.md" new file mode 100644 index 000000000..dbb7e8cf1 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/backtracking\346\200\235\350\267\257.md" @@ -0,0 +1,295 @@ +## backtracking 全集 + +### 回溯是啥 +用爬山来比喻回溯,好比从山脚下找一条爬上山顶的路,起初有好几条道可走,当选择一条道走到某处时,又有几条岔道可供选择,只能选择其中一条道往前走,若能这样子顺利爬上山顶则罢了,否则走到一条绝路上时,只好返回到最近的一个路口,重新选择另一条没走过的道往前走。如果该路口的所有路都走不通,只得从该路口继续回返。照此规则走下去,要么找到一条到达山顶的路,要么最终试过所有可能的道,无法到达山顶。 +回溯是一种穷举,但与brute force有一些区别,回溯带了两点脑子的,并不多,brute force一点也没带。 +第一点脑子是回溯知道回头;相反如果是brute force,发现走不通立刻跳下山摔死,换第二条命从头换一条路走。 +第二点脑子是回溯知道剪枝;如果有一条岔路上放了一坨屎,那这条路我们不走,就可以少走很多不必要走的路。 + +还有一些爱混淆的概念:递归,回溯,DFS。 +回溯是一种找路方法,搜索的时候走不通就回头换路接着走,直到走通了或者发现此山根本不通。 +DFS是一种开路策略,就是一条道先走到头,再往回走一步换一条路走到头,这也是回溯用到的策略。在树和图上回溯时人们叫它DFS。 +递归是一种行为,回溯和递归如出一辙,都是一言不合就回到来时的路,所以一般回溯用递归实现;当然也可以不用,用栈。 +以下以回溯统称,因为这个词听上去很文雅。 + +### 识别回溯 +判断回溯很简单,拿到一个问题,你感觉如果不穷举一下就没法知道答案,那就可以开始回溯了。 +一般回溯的问题有三种: + +1. Find a path to success 有没有解 +2. Find all paths to success 求所有解 + - 2.1 求所有解的个数, + - 2.2 求所有解的具体信息 +3. Find the best path to success 求最优解 + +理解回溯:给一堆选择, 必须从里面选一个. 选完之后我又有了新的一组选择. ```This procedure is repeated over and over until you reach a final state. If you made a good sequence of choices, your final state is a goal state; if you didn't, it isn't.``` + +回溯可以抽象为一棵树,我们的目标可以是找这个树有没有good leaf,也可以是问有多少个good leaf,也可以是找这些good leaf都在哪,也可以问哪个good leaf最好,分别对应上面所说回溯的问题分类。 +good leaf都在leaf上。good leaf是我们的goal state,leaf node是final state,是解空间的边界。 + +对于第一类问题(问有没有解),基本都是长着个样子的,理解了它,其他类别迎刃而解: +```java +boolean solve(Node n) { + if n is a leaf node { + if the leaf is a goal node, return true + else return false + } else { + for each child c of n { + if solve(c) succeeds, return true + } + return false + } +} +``` +请读以下这段话以加深理解: +```Notice that the algorithm is expressed as a boolean function. This is essential to understanding the algorithm. If solve(n) is true, that means node n is part of a solution--that is, node n is one of the nodes on a path from the root to some goal node. We say that n is solvable. If solve(n) is false, then there is no path that includes n to any goal node.``` + +还不懂的话请通读全文吧:[Backtracking - David Matuszek](https://www.cis.upenn.edu/~matuszek/cit594-2012/Pages/backtracking.html) + +关于回溯的三种问题,模板略有不同, +第一种,返回值是true/false。 +第二种,求个数,设全局counter,返回值是void;求所有解信息,设result,返回值void。 +第三种,设个全局变量best,返回值是void。 + +第一种: +```java +boolean solve(Node n) { + if n is a leaf node { + if the leaf is a goal node, return true + else return false + } else { + for each child c of n { + if solve(c) succeeds, return true + } + return false + } +} +``` +第二种: +```java +void solve(Node n) { + if n is a leaf node { + if the leaf is a goal node, count++, return; + else return + } else { + for each child c of n { + solve(c) + } + } +} +``` +第三种: +```java +void solve(Node n) { + if n is a leaf node { + if the leaf is a goal node, update best result, return; + else return + } else { + for each child c of n { + solve(c) + } + } +} +``` +题目 + +八皇后 N-Queens + +问题 + +1. 给个n,问有没有解; +2. 给个n,有几种解;(Leetcode N-Queens II) +3. 给个n,给出所有解;(Leetcode N-Queens I) + +解答 + +1.有没有解 + +怎么做:一行一行的放queen,每行尝试n个可能,有一个可达,返回true;都不可达,返回false. + +边界条件leaf:放完第n行 或者 该放第n+1行(出界,返回) + +目标条件goal:n行放满且isValid,即目标一定在leaf上 + +helper函数: +boolean solve(int i, int[][] matrix) +在进来的一瞬间,满足property:第i行还没有被放置,前i-1行放置完毕且valid +solve要在给定的matrix上试图给第i行每个位置放queen。 +```java +public static boolean solve1(int i, List matrix, int n) { + if (i == n) { + if (isValid(matrix)) + return true; + return false; + } else { + for (int j = 0; j < n; j++) { + matrix.add(j); + if (isValid(matrix)) { //剪枝 + if (solve1(i + 1, matrix, n)) + return true; + } + matrix.remove(matrix.size() - 1); + } + return false; + } +} +``` +2.求解的个数 + +怎么做:一行一行的放queen,每行尝试n个可能。这回因为要找所有,返回值就没有了意义,用void即可。在搜索时,如果有一个可达,仍要继续尝试;每个子选项都试完了,返回. + +边界条件leaf:放完第n行 或者 该放第n+1行(出界,返回) + +目标条件goal:n行放满且isValid,即目标一定在leaf上 + +helper函数: +void solve(int i, int[][] matrix) +在进来的一瞬间,满足property:第i行还没有被放置,前i-1行放置完毕且valid +solve要在给定的matrix上试图给第i行每个位置放queen。 +这里为了记录解的个数,设置一个全局变量(static)int是比较efficient的做法。 +```java +public static void solve2(int i, List matrix, int n) { + if (i == n) { + if (isValid(matrix)) + count++; + return; + } else { + for (int j = 0; j < n; j++) { + matrix.add(j); + if (isValid(matrix)) { //剪枝 + solve2(i + 1, matrix, n); + } + matrix.remove(matrix.size() - 1); + } + } +} +``` +3.求所有解的具体信息 + +怎么做:一行一行的放queen,每行尝试n个可能。返回值同样用void即可。在搜索时,如果有一个可达,仍要继续尝试;每个子选项都试完了,返回. + +边界条件leaf:放完第n行 或者 该放第n+1行(出界,返回) + +目标条件goal:n行放满且isValid,即目标一定在leaf上 + +helper函数: +void solve(int i, int[][] matrix) +在进来的一瞬间,满足property:第i行还没有被放置,前i-1行放置完毕且valid +solve要在给定的matrix上试图给第i行每个位置放queen。 +这里为了记录解的具体情况,设置一个全局变量(static)集合是比较efficient的做法。 +当然也可以把结果集合作为参数传来传去。 +```java +public static void solve3(int i, List matrix, int n) { + if (i == n) { + if (isValid(matrix)) + result.add(new ArrayList(matrix)); + return; + } else { + for (int j = 0; j < n; j++) { + matrix.add(j); + if (isValid(matrix)) { //剪枝 + solve3(i + 1, matrix, n); + } + matrix.remove(matrix.size() - 1); + } + } +} +``` +优化 + +上面的例子用了省空间的方法。 +由于每行只能放一个,一共n行的话,用一个大小为n的数组,数组的第i个元素表示第i行放在了第几列上。 + +Utility(给一个list判断他的最后一行是否和前面冲突): +```java +public static boolean isValid(List list){ + int row = list.size() - 1; + int col = list.get(row); + for (int i = 0; i <= row - 1; i++) { + int row1 = i; + int col1 = list.get(i); + if (col == col1) + return false; + if (row1 - row == col1 - col) + return false; + if (row1 - row == col - col1) + return false; + } + return true; + +} +``` + +参考[Backtracking回溯法(又称DFS,递归)全解](https://segmentfault.com/a/1190000006121957) +以及 [Python Patterns - Implementing Graphs](https://www.python.org/doc/essays/graphs/) + + + +## 以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的牛人解答 + + + +Backtracking 伪码 + + +``` +Pick a starting point. +while(Problem is not solved) + For each path from the starting point. + check if selected path is safe, if yes select it + and make recursive call to rest of the problem + If recursive calls returns true, then return true. + else undo the current move and return false. + End For + If none of the move works out, return false, NO SOLUTON. + +``` diff --git "a/docs/Leetcode_Solutions/Python/Summary/delete_node_in_a_linked_list\351\227\256\351\242\230.md" "b/docs/Leetcode_Solutions/Python/Summary/delete_node_in_a_linked_list\351\227\256\351\242\230.md" new file mode 100644 index 000000000..e148bb218 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/delete_node_in_a_linked_list\351\227\256\351\242\230.md" @@ -0,0 +1,69 @@ +##Delete Node in a Linked List问题 + + +This is a LeetCode question, I knew its solution, but wondering about why my code not work. + + +>Write a function to delete a node (except the tail) in a singly linked list, given only access to that node. + +>Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node with value 3, the linked list should become 1 -> 2 -> 4 after calling your function + + +At first glance, my intution is delete like an array: + +shift all the node values one front, then delete the tail, here's my implementation and test case: + + + + class ListNode(object): + def __init__(self, x): + self.val = x + self.next = None + + node1 = ListNode(1) + node2 = ListNode(2) + node3 = ListNode(3) + node4 = ListNode(4) + node5 = ListNode(5) + + node1.next = node2 + node2.next = node3 + node3.next = node4 + node4.next = node5 + + + + def deleteNode(node): + """ + :type node: ListNode + :rtype: void Do not return anything, modify node in-place instead. + """ + while node.next: + node.val = node.next.val + node = node.next + node = None + + + deleteNode(node4) + +But After deletion, it has two 5 value nodes, the tail was still kept, can anyone please explain to me what's wrong here? + + deleteNode(node4) + + node1.val + Out[162]: 1 + + node1.next.val + Out[163]: 2 + + node1.next.next.val + Out[164]: 3 + + node1.next.next.next.val + Out[165]: 5 + + node1.next.next.next.next.val + Out[166]: 5 + + +Really appreciate any help. \ No newline at end of file diff --git a/docs/Leetcode_Solutions/Python/Summary/python_base.md b/docs/Leetcode_Solutions/Python/Summary/python_base.md new file mode 100644 index 000000000..718e2edbb --- /dev/null +++ b/docs/Leetcode_Solutions/Python/Summary/python_base.md @@ -0,0 +1,1338 @@ +```python +# _*_ coding: utf-8 _*_ + +"""类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算""" + +#-- 寻求帮助: + dir(obj) # 简单的列出对象obj所包含的方法名称,返回一个字符串列表 + help(obj.func) # 查询obj.func的具体介绍和用法 + +#-- 测试类型的三种方法,推荐第三种 + if type(L) == type([]): + print("L is list") + if type(L) == list: + print("L is list") + if isinstance(L, list): + print("L is list") + +#-- Python数据类型:哈希类型、不可哈希类型 + # 哈希类型,即在原地不能改变的变量类型,不可变类型。可利用hash函数查看其hash值,也可以作为字典的key + "数字类型:int, float, decimal.Decimal, fractions.Fraction, complex" + "字符串类型:str, bytes" + "元组:tuple" + "冻结集合:frozenset" + "布尔类型:True, False" + "None" + # 不可hash类型:原地可变类型:list、dict和set。它们不可以作为字典的key。 + +#-- 数字常量 + 1234, -1234, 0, 999999999 # 整数 + 1.23, 1., 3.14e-10, 4E210, 4.0e+210 # 浮点数 + 0o177, 0x9ff, 0X9FF, 0b101010 # 八进制、十六进制、二进制数字 + 3+4j, 3.0+4.0j, 3J # 复数常量,也可以用complex(real, image)来创建 + hex(I), oct(I), bin(I) # 将十进制数转化为十六进制、八进制、二进制表示的“字符串” + int(string, base) # 将字符串转化为整数,base为进制数 + # 2.x中,有两种整数类型:一般整数(32位)和长整数(无穷精度)。可以用l或L结尾,迫使一般整数成为长整数 + float('inf'), float('-inf'), float('nan') # 无穷大, 无穷小, 非数 + +#-- 数字的表达式操作符 + yield x # 生成器函数发送协议 + lambda args: expression # 生成匿名函数 + x if y else z # 三元选择表达式 + x and y, x or y, not x # 逻辑与、逻辑或、逻辑非 + x in y, x not in y # 成员对象测试 + x is y, x is not y # 对象实体测试 + xy, x>=y, x==y, x!=y # 大小比较,集合子集或超集值相等性操作符 + 1 < a < 3 # Python中允许连续比较 + x|y, x&y, x^y # 位或、位与、位异或 + x<>y # 位操作:x左移、右移y位 + +, -, *, /, //, %, ** # 真除法、floor除法:返回不大于真除法结果的整数值、取余、幂运算 + -x, +x, ~x # 一元减法、识别、按位求补(取反) + x[i], x[i:j:k] # 索引、分片、调用 + int(3.14), float(3) # 强制类型转换 + +#-- 整数可以利用bit_length函数测试所占的位数 + a = 1; a.bit_length() # 1 + a = 1024; a.bit_length() # 11 + +#-- repr和str显示格式的区别 + """ + repr格式:默认的交互模式回显,产生的结果看起来它们就像是代码。 + str格式:打印语句,转化成一种对用户更加友好的格式。 + """ + +#-- 数字相关的模块 + # math模块 + # Decimal模块:小数模块 + import decimal + from decimal import Decimal + Decimal("0.01") + Decimal("0.02") # 返回Decimal("0.03") + decimal.getcontext().prec = 4 # 设置全局精度为4 即小数点后边4位 + # Fraction模块:分数模块 + from fractions import Fraction + x = Fraction(4, 6) # 分数类型 4/6 + x = Fraction("0.25") # 分数类型 1/4 接收字符串类型的参数 + +#-- 集合set + """ + set是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素。 + set支持union(联合), intersection(交), difference(差)和symmetric difference(对称差集)等数学运算。 + set支持x in set, len(set), for x in set。 + set不记录元素位置或者插入点, 因此不支持indexing, slicing, 或其它类序列的操作 + """ + s = set([3,5,9,10]) # 创建一个数值集合,返回{3, 5, 9, 10} + t = set("Hello") # 创建一个唯一字符的集合返回{} + a = t | s; t.union(s) # t 和 s的并集 + b = t & s; t.intersection(s) # t 和 s的交集 + c = t – s; t.difference(s) # 求差集(项在t中, 但不在s中) + d = t ^ s; t.symmetric_difference(s) # 对称差集(项在t或s中, 但不会同时出现在二者中) + t.add('x'); t.remove('H') # 增加/删除一个item + s.update([10,37,42]) # 利用[......]更新s集合 + x in s, x not in s # 集合中是否存在某个值 + s.issubset(t); s <= t # 测试是否 s 中的每一个元素都在 t 中 + s.issuperset(t); s >= t # 测试是否 t 中的每一个元素都在 s 中 + s.copy(); + s.discard(x); # 删除s中x + s.clear() # 清空s + {x**2 for x in [1, 2, 3, 4]} # 集合解析,结果:{16, 1, 4, 9} + {x for x in 'spam'} # 集合解析,结果:{'a', 'p', 's', 'm'} + +#-- 集合frozenset,不可变对象 + """ + set是可变对象,即不存在hash值,不能作为字典的键值。同样的还有list等(tuple是可以作为字典key的) + frozenset是不可变对象,即存在hash值,可作为字典的键值 + frozenset对象没有add、remove等方法,但有union/intersection/difference等方法 + """ + a = set([1, 2, 3]) + b = set() + b.add(a) # error: set是不可哈希类型 + b.add(frozenset(a)) # ok,将set变为frozenset,可哈希 + +#-- 布尔类型bool + type(True) # 返回 + isinstance(False, int) # bool类型属于整型,所以返回True + True == 1; True is 1 # 输出(True, False) + +#-- 动态类型简介 + """ + 变量名通过引用,指向对象。 + Python中的“类型”属于对象,而不是变量,每个对象都包含有头部信息,比如"类型标示符" "引用计数器"等 + """ + #共享引用及在原处修改:对于可变对象,要注意尽量不要共享引用! + #共享引用和相等测试: + L = [1], M = [1], L is M # 返回False + L = M = [1, 2, 3], L is M # 返回True,共享引用 + #增强赋值和共享引用:普通+号会生成新的对象,而增强赋值+=会在原处修改 + L = M = [1, 2] + L = L + [3, 4] # L = [1, 2, 3, 4], M = [1, 2] + L += [3, 4] # L = [1, 2, 3, 4], M = [1, 2, 3, 4] + +#-- 常见字符串常量和表达式 + S = '' # 空字符串 + S = "spam’s" # 双引号和单引号相同 + S = "s\np\ta\x00m" # 转义字符 + S = """spam""" # 三重引号字符串,一般用于函数说明 + S = r'\temp' # Raw字符串,不会进行转义,抑制转义 + S = b'Spam' # Python3中的字节字符串 + S = u'spam' # Python2.6中的Unicode字符串 + s1+s2, s1*3, s[i], s[i:j], len(s) # 字符串操作 + 'a %s parrot' % 'kind' # 字符串格式化表达式 + 'a {1} {0} parrot'.format('kind', 'red')# 字符串格式化方法 + for x in s: print(x) # 字符串迭代,成员关系 + [x*2 for x in s] # 字符串列表解析 + ','.join(['a', 'b', 'c']) # 字符串输出,结果:a,b,c + +#-- 内置str处理函数: + str1 = "stringobject" + str1.upper(); str1.lower(); str1.swapcase(); str1.capitalize(); str1.title() # 全部大写,全部小写、大小写转换,首字母大写,每个单词的首字母都大写 + str1.ljust(width) # 获取固定长度,左对齐,右边不够用空格补齐 + str1.rjust(width) # 获取固定长度,右对齐,左边不够用空格补齐 + str1.center(width) # 获取固定长度,中间对齐,两边不够用空格补齐 + str1.zfill(width) # 获取固定长度,右对齐,左边不足用0补齐 + str1.find('t',start,end) # 查找字符串,可以指定起始及结束位置搜索 + str1.rfind('t') # 从右边开始查找字符串 + str1.count('t') # 查找字符串出现的次数 + #上面所有方法都可用index代替,不同的是使用index查找不到会抛异常,而find返回-1 + str1.replace('old','new') # 替换函数,替换old为new,参数中可以指定maxReplaceTimes,即替换指定次数的old为new + str1.strip(); # 默认删除空白符 + str1.strip('d'); # 删除str1字符串中开头、结尾处,位于 d 删除序列的字符 + str1.lstrip(); + str1.lstrip('d'); # 删除str1字符串中开头处,位于 d 删除序列的字符 + str1.rstrip(); + str1.rstrip('d') # 删除str1字符串中结尾处,位于 d 删除序列的字符 + str1.startswith('start') # 是否以start开头 + str1.endswith('end') # 是否以end结尾 + str1.isalnum(); str1.isalpha(); str1.isdigit(); str1.islower(); str1.isupper() # 判断字符串是否全为字符、数字、小写、大写 + +#-- 三重引号编写多行字符串块,并且在代码折行处嵌入换行字符\n + mantra = """hello world + hello python + hello my friend""" + # mantra为"""hello world \n hello python \n hello my friend""" + +#-- 索引和分片: + S[0], S[len(S)–1], S[-1] # 索引 + S[1:3], S[1:], S[:-1], S[1:10:2] # 分片,第三个参数指定步长,如`S[1:10:2]`是从1位到10位没隔2位获取一个字符。 + +#-- 字符串转换工具: + int('42'), str(42) # 返回(42, '42') + float('4.13'), str(4.13) # 返回(4.13, '4.13') + ord('s'), chr(115) # 返回(115, 's') + int('1001', 2) # 将字符串作为二进制数字,转化为数字,返回9 + bin(13), oct(13), hex(13) # 将整数转化为二进制/八进制/十六进制字符串,返回('0b1101', '015', '0xd') + +#-- 另类字符串连接 + name = "wang" "hong" # 单行,name = "wanghong" + name = "wang" \ + "hong" # 多行,name = "wanghong" + +#-- Python中的字符串格式化实现1--字符串格式化表达式 + """ + 基于C语言的'print'模型,并且在大多数的现有的语言中使用。 + 通用结构:%[(name)][flag][width].[precision]typecode + """ + "this is %d %s bird" % (1, 'dead') # 一般的格式化表达式 + "%s---%s---%s" % (42, 3.14, [1, 2, 3]) # 字符串输出:'42---3.14---[1, 2, 3]' + "%d...%6d...%-6d...%06d" % (1234, 1234, 1234, 1234) # 对齐方式及填充:"1234... 1234...1234 ...001234" + x = 1.23456789 + "%e | %f | %g" % (x, x, x) # 对齐方式:"1.234568e+00 | 1.234568 | 1.23457" + "%6.2f*%-6.2f*%06.2f*%+6.2f" % (x, x, x, x) # 对齐方式:' 1.23*1.23 *001.23* +1.23' + "%(name1)d---%(name2)s" % {"name1":23, "name2":"value2"} # 基于字典的格式化表达式 + "%(name)s is %(age)d" % vars() # vars()函数调用返回一个字典,包含了所有本函数调用时存在的变量 + +#-- Python中的字符串格式化实现2--字符串格式化调用方法 + # 普通调用 + "{0}, {1} and {2}".format('spam', 'ham', 'eggs') # 基于位置的调用 + "{motto} and {pork}".format(motto = 'spam', pork = 'ham') # 基于Key的调用 + "{motto} and {0}".format('ham', motto = 'spam') # 混合调用 + # 添加键 属性 偏移量 (import sys) + "my {1[spam]} runs {0.platform}".format(sys, {'spam':'laptop'}) # 基于位置的键和属性 + "{config[spam]} {sys.platform}".format(sys = sys, config = {'spam':'laptop'}) # 基于Key的键和属性 + "first = {0[0]}, second = {0[1]}".format(['A', 'B', 'C']) # 基于位置的偏移量 + # 具体格式化 + "{0:e}, {1:.3e}, {2:g}".format(3.14159, 3.14159, 3.14159) # 输出'3.141590e+00, 3.142e+00, 3.14159' + "{fieldname:format_spec}".format(......) + # 说明: + """ + fieldname是指定参数的一个数字或关键字, 后边可跟可选的".name"或"[index]"成分引用 + format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type] + fill ::= #填充字符 + align ::= "<" | ">" | "=" | "^" #对齐方式 + sign ::= "+" | "-" | " " #符号说明 + width ::= integer #字符串宽度 + precision ::= integer #浮点数精度 + type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" + """ + # 例子: + '={0:10} = {1:10}'.format('spam', 123.456) # 输出'=spam = 123.456' + '={0:>10}='.format('test') # 输出'= test=' + '={0:<10}='.format('test') # 输出'=test =' + '={0:^10}='.format('test') # 输出'= test =' + '{0:X}, {1:o}, {2:b}'.format(255, 255, 255) # 输出'FF, 377, 11111111' + 'My name is {0:{1}}.'.format('Fred', 8) # 输出'My name is Fred .' 动态指定参数 + +#-- 常用列表常量和操作 + L = [[1, 2], 'string', {}] # 嵌套列表 + L = list('spam') # 列表初始化 + L = list(range(0, 4)) # 列表初始化 + list(map(ord, 'spam')) # 列表解析 + len(L) # 求列表长度 + L.count(value) # 求列表中某个值的个数 + L.append(obj) # 向列表的尾部添加数据,比如append(2),添加元素2 + L.insert(index, obj) # 向列表的指定index位置添加数据,index及其之后的数据后移 + L.extend(interable) # 通过添加iterable中的元素来扩展列表,比如extend([2]),添加元素2,注意和append的区别 + L.index(value, [start, [stop]]) # 返回列表中值value的第一个索引 + L.pop([index]) # 删除并返回index处的元素,默认为删除并返回最后一个元素 + L.remove(value) # 删除列表中的value值,只删除第一次出现的value的值 + L.reverse() # 反转列表 + L.sort(cmp=None, key=None, reverse=False) # 排序列表 + a = [1, 2, 3], b = a[10:] # 注意,这里不会引发IndexError异常,只会返回一个空的列表[] + a = [], a += [1] # 这里实在原有列表的基础上进行操作,即列表的id没有改变 + a = [], a = a + [1] # 这里最后的a要构建一个新的列表,即a的id发生了变化 + +#-- 用切片来删除序列的某一段 + a = [1, 2, 3, 4, 5, 6, 7] + a[1:4] = [] # a = [1, 5, 6, 7] + a = [0, 1, 2, 3, 4, 5, 6, 7] + del a[::2] # 去除偶数项(偶数索引的),a = [1, 3, 5, 7] + +#-- 常用字典常量和操作 + D = {} + D = {'spam':2, 'tol':{'ham':1}} # 嵌套字典 + D = dict.fromkeys(['s', 'd'], 8) # {'s': 8, 'd': 8} + D = dict(name = 'tom', age = 12) # {'age': 12, 'name': 'tom'} + D = dict([('name', 'tom'), ('age', 12)]) # {'age': 12, 'name': 'tom'} + D = dict(zip(['name', 'age'], ['tom', 12])) # {'age': 12, 'name': 'tom'} + D.keys(); D.values(); D.items() # 字典键、值以及键值对 + D.get(key, default) # get函数 + D.update(D_other) # 合并字典,如果存在相同的键值,D_other的数据会覆盖掉D的数据 + D.pop(key, [D]) # 删除字典中键值为key的项,返回键值为key的值,如果不存在,返回默认值D,否则异常 + D.popitem() # pop字典中随机的一项(一个键值对) + D.setdefault(k[, d]) # 设置D中某一项的默认值。如果k存在,则返回D[k],否则设置D[k]=d,同时返回D[k]。 + del D # 删除字典 + del D['key'] # 删除字典的某一项 + if key in D: if key not in D: # 测试字典键是否存在 + # 字典注意事项:(1)对新索引赋值会添加一项(2)字典键不一定非得是字符串,也可以为任何的不可变对象 + # 不可变对象:调用对象自身的任意方法,也不会改变该对象自身的内容,这些方法会创建新的对象并返回。 + # 字符串、整数、tuple都是不可变对象,dict、set、list都是可变对象 + D[(1,2,3)] = 2 # tuple作为字典的key + +#-- 字典解析 + D = {k:8 for k in ['s', 'd']} # {'s': 8, 'd': 8} + D = {k:v for (k, v) in zip(['name', 'age'], ['tom', 12])} # {'age': 12, 'name': tom} + +#-- 字典的特殊方法__missing__:当查找找不到key时,会执行该方法 + class Dict(dict): + def __missing__(self, key): + self[key] = [] + return self[key] + dct = dict() + dct["foo"].append(1) # 这有点类似于collections.defalutdict + dct["foo"] # [1] + +#-- 元组和列表的唯一区别在于元组是不可变对象,列表是可变对象 + a = [1, 2, 3] # a[1] = 0, OK + a = (1, 2, 3) # a[1] = 0, Error + a = ([1, 2]) # a[0][1] = 0, OK + a = [(1, 2)] # a[0][1] = 0, Error + +#-- 元组的特殊语法: 逗号和圆括号 + D = (12) # 此时D为一个整数 即D = 12 + D = (12, ) # 此时D为一个元组 即D = (12, ) + +#-- 文件基本操作 + output = open(r'C:\spam', 'w') # 打开输出文件,用于写 + input = open('data', 'r') # 打开输入文件,用于读。打开的方式可以为'w', 'r', 'a', 'wb', 'rb', 'ab'等 + fp.read([size]) # size为读取的长度,以byte为单位 + fp.readline([size]) # 读一行,如果定义了size,有可能返回的只是一行的一部分 + fp.readlines([size]) # 把文件每一行作为一个list的一个成员,并返回这个list。其实它的内部是通过循环调用readline()来实现的。如果提供size参数,size是表示读取内容的总长。 + fp.readable() # 是否可读 + fp.write(str) # 把str写到文件中,write()并不会在str后加上一个换行符 + fp.writelines(seq) # 把seq的内容全部写到文件中(多行一次性写入) + fp.writeable() # 是否可写 + fp.close() # 关闭文件。 + fp.flush() # 把缓冲区的内容写入硬盘 + fp.fileno() # 返回一个长整型的”文件标签“ + fp.isatty() # 文件是否是一个终端设备文件(unix系统中的) + fp.tell() # 返回文件操作标记的当前位置,以文件的开头为原点 + fp.next() # 返回下一行,并将文件操作标记位移到下一行。把一个file用于for … in file这样的语句时,就是调用next()函数来实现遍历的。 + fp.seek(offset[,whence]) # 将文件打开操作标记移到offset的位置。whence为0表示从头开始计算,1表示以当前位置为原点计算。2表示以文件末尾为原点进行计算。 + fp.seekable() # 是否可以seek + fp.truncate([size]) # 把文件裁成规定的大小,默认的是裁到当前文件操作标记的位置。 + for line in open('data'): + print(line) # 使用for语句,比较适用于打开比较大的文件 + with open('data') as file: + print(file.readline()) # 使用with语句,可以保证文件关闭 + with open('data') as file: + lines = file.readlines() # 一次读入文件所有行,并关闭文件 + open('f.txt', encoding = 'latin-1') # Python3.x Unicode文本文件 + open('f.bin', 'rb') # Python3.x 二进制bytes文件 + # 文件对象还有相应的属性:buffer closed encoding errors line_buffering name newlines等 + +#-- 其他 + # Python中的真假值含义:1. 数字如果非零,则为真,0为假。 2. 其他对象如果非空,则为真 + # 通常意义下的类型分类:1. 数字、序列、映射。 2. 可变类型和不可变类型 + + +"""语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句""" + +#-- 赋值语句的形式 + spam = 'spam' # 基本形式 + spam, ham = 'spam', 'ham' # 元组赋值形式 + [spam, ham] = ['s', 'h'] # 列表赋值形式 + a, b, c, d = 'abcd' # 序列赋值形式 + a, *b, c = 'spam' # 序列解包形式(Python3.x中才有) + spam = ham = 'no' # 多目标赋值运算,涉及到共享引用 + spam += 42 # 增强赋值,涉及到共享引用 + +#-- 序列赋值 序列解包 + [a, b, c] = (1, 2, 3) # a = 1, b = 2, c = 3 + a, b, c, d = "spam" # a = 's', b = 'p', c = 'a', d = 'm' + a, b, c = range(3) # a = 0, b = 1, c = 2 + a, *b = [1, 2, 3, 4] # a = 1, b = [2, 3, 4] + *a, b = [1, 2, 3, 4] # a = [1, 2, 3], b = 4 + a, *b, c = [1, 2, 3, 4] # a = 1, b = [2, 3], c = 4 + # 带有*时 会优先匹配*之外的变量 如 + a, *b, c = [1, 2] # a = 1, c = 2, b = [] + +#-- print函数原型 + print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) + # 流的重定向 + print('hello world') # 等于sys.stdout.write('hello world') + temp = sys.stdout # 原有流的保存 + sys.stdout = open('log.log', 'a') # 流的重定向 + print('hello world') # 写入到文件log.log + sys.stdout.close() + sys.stdout = temp # 原有流的复原 + +#-- Python中and或or总是返回对象(左边的对象或右边的对象) 且具有短路求值的特性 + 1 or 2 or 3 # 返回 1 + 1 and 2 and 3 # 返回 3 + +#-- if/else三元表达符(if语句在行内) + A = 1 if X else 2 + A = 1 if X else (2 if Y else 3) + # 也可以使用and-or语句(一条语句实现多个if-else) + a = 6 + result = (a > 20 and "big than 20" or a > 10 and "big than 10" or a > 5 and "big than 5") # 返回"big than 5" + +#-- Python的while语句或者for语句可以带else语句 当然也可以带continue/break/pass语句 + while a > 1: + anything + else: + anything + # else语句会在循环结束后执行,除非在循环中执行了break,同样的还有for语句 + for i in range(5): + anything + else: + anything + +#-- for循环的元组赋值 + for (a, b) in [(1, 2), (3, 4)]: # 最简单的赋值 + for ((a, b), c) in [((1, 2), 3), ((4, 5), 6)]: # 自动解包赋值 + for ((a, b), c) in [((1, 2), 3), ("XY", 6)]: # 自动解包 a = X, b = Y, c = 6 + for (a, *b) in [(1, 2, 3), (4, 5, 6)]: # 自动解包赋值 + +#-- 列表解析语法 + M = [[1,2,3], [4,5,6], [7,8,9]] + res = [sum(row) for row in M] # G = [6, 15, 24] 一般的列表解析 生成一个列表 + res = [c * 2 for c in 'spam'] # ['ss', 'pp', 'aa', 'mm'] + res = [a * b for a in [1, 2] for b in [4, 5]] # 多解析过程 返回[4, 5, 8, 10] + res = [a for a in [1, 2, 3] if a < 2] # 带判断条件的解析过程 + res = [a if a > 0 else 0 for a in [-1, 0, 1]] # 带判断条件的高级解析过程 + # 两个列表同时解析:使用zip函数 + for teama, teamb in zip(["Packers", "49ers"], ["Ravens", "Patriots"]): + print(teama + " vs. " + teamb) + # 带索引的列表解析:使用enumerate函数 + for index, team in enumerate(["Packers", "49ers", "Ravens", "Patriots"]): + print(index, team) # 输出0, Packers \n 1, 49ers \n ...... + +#-- 生成器表达式 + G = (sum(row) for row in M) # 使用小括号可以创建所需结果的生成器generator object + next(G), next(G), next(G) # 输出(6, 15, 24) + G = {sum(row) for row in M} # G = {6, 15, 24} 解析语法还可以生成集合和字典 + G = {i:sum(M[i]) for i in range(3)} # G = {0: 6, 1: 15, 2: 24} + +#-- 文档字符串:出现在Module的开端以及其中函数或类的开端 使用三重引号字符串 + """ + module document + """ + def func(): + """ + function document + """ + print() + class Employee(object): + """ + class document + """ + print() + print(func.__doc__) # 输出函数文档字符串 + print(Employee.__doc__) # 输出类的文档字符串 + +#-- 命名惯例: + """ + 以单一下划线开头的变量名(_X)不会被from module import*等语句导入 + 前后有两个下划线的变量名(__X__)是系统定义的变量名,对解释器有特殊意义 + 以两个下划线开头但不以下划线结尾的变量名(__X)是类的本地(私有)变量 + """ + +#-- 列表解析 in成员关系测试 map sorted zip enumerate内置函数等都使用了迭代协议 + 'first line' in open('test.txt') # in测试 返回True或False + list(map(str.upper, open('t'))) # map内置函数 + sorted(iter([2, 5, 8, 3, 1])) # sorted内置函数 + list(zip([1, 2], [3, 4])) # zip内置函数 [(1, 3), (2, 4)] + +#-- del语句: 手动删除某个变量 + del X + +#-- 获取列表的子表的方法: + x = [1,2,3,4,5,6] + x[:3] # 前3个[1,2,3] + x[1:5] # 中间4个[2,3,4,5] + x[-3:] # 最后3个[4,5,6] + x[::2] # 奇数项[1,3,5] + x[1::2] # 偶数项[2,4,6] + +#-- 手动迭代:iter和next + L = [1, 2] + I = iter(L) # I为L的迭代器 + I.next() # 返回1 + I.next() # 返回2 + I.next() # Error:StopIteration + +#-- Python中的可迭代对象 + """ + 1.range迭代器 + 2.map、zip和filter迭代器 + 3.字典视图迭代器:D.keys()), D.items()等 + 4.文件类型 + """ + + +"""函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则""" + +#-- 函数相关的语句和表达式 + myfunc('spam') # 函数调用 + def myfunc(): # 函数定义 + return None # 函数返回值 + global a # 全局变量 + nonlocal x # 在函数或其他作用域中使用外层(非全局)变量 + yield x # 生成器函数返回 + lambda # 匿名函数 + +#-- Python函数变量名解析:LEGB原则,即: + """ + local(functin) --> encloseing function locals --> global(module) --> build-in(python) + 说明:以下边的函数maker为例 则相对于action而言 X为Local N为Encloseing + """ + +#-- 嵌套函数举例:工厂函数 + def maker(N): + def action(X): + return X ** N + return action + f = maker(2) # pass 2 to N + f(3) # 9, pass 3 to X + +#-- 嵌套函数举例:lambda实例 + def maker(N): + action = (lambda X: X**N) + return action + f = maker(2) # pass 2 to N + f(3) # 9, pass 3 to X + +#-- nonlocal和global语句的区别 + # nonlocal应用于一个嵌套的函数的作用域中的一个名称 例如: + start = 100 + def tester(start): + def nested(label): + nonlocal start # 指定start为tester函数内的local变量 而不是global变量start + print(label, start) + start += 3 + return nested + # global为全局的变量 即def之外的变量 + def tester(start): + def nested(label): + global start # 指定start为global变量start + print(label, start) + start += 3 + return nested + +#-- 函数参数,不可变参数通过“值”传递,可变参数通过“引用”传递 + def f(a, b, c): print(a, b, c) + f(1, 2, 3) # 参数位置匹配 + f(1, c = 3, b = 2) # 参数关键字匹配 + def f(a, b=1, c=2): print(a, b, c) + f(1) # 默认参数匹配 + f(1, 2) # 默认参数匹配 + f(a = 1, c = 3) # 关键字参数和默认参数的混合 + # Keyword-Only参数:出现在*args之后 必须用关键字进行匹配 + def keyOnly(a, *b, c): print('') # c就为keyword-only匹配 必须使用关键字c = value匹配 + def keyOnly(a, *, b, c): ...... # b c为keyword-only匹配 必须使用关键字匹配 + def keyOnly(a, *, b = 1): ...... # b有默认值 或者省略 或者使用关键字参数b = value + +#-- 可变参数匹配: * 和 ** + def f(*args): print(args) # 在元组中收集不匹配的位置参数 + f(1, 2, 3) # 输出(1, 2, 3) + def f(**args): print(args) # 在字典中收集不匹配的关键字参数 + f(a = 1, b = 2) # 输出{'a':1, 'b':2} + def f(a, *b, **c): print(a, b, c) # 两者混合使用 + f(1, 2, 3, x=4, y=5) # 输出1, (2, 3), {'x':4, 'y':5} + +#-- 函数调用时的参数解包: * 和 ** 分别解包元组和字典 + func(1, *(2, 3)) <==> func(1, 2, 3) + func(1, **{'c':3, 'b':2}) <==> func(1, b = 2, c = 3) + func(1, *(2, 3), **{'c':3, 'b':2}) <==> func(1, 2, 3, b = 2, c = 3) + +#-- 函数属性:(自己定义的)函数可以添加属性 + def func():..... + func.count = 1 # 自定义函数添加属性 + print.count = 1 # Error 内置函数不可以添加属性 + +#-- 函数注解: 编写在def头部行 主要用于说明参数范围、参数类型、返回值类型等 + def func(a:'spam', b:(1, 10), c:float) -> int : + print(a, b, c) + func.__annotations__ # {'c':, 'b':(1, 10), 'a':'spam', 'return':} + # 编写注解的同时 还是可以使用函数默认值 并且注解的位置位于=号的前边 + def func(a:'spam'='a', b:(1, 10)=2, c:float=3) -> int : + print(a, b, c) + +#-- 匿名函数:lambda + f = lambda x, y, z : x + y + z # 普通匿名函数,使用方法f(1, 2, 3) + f = lambda x = 1, y = 1: x + y # 带默认参数的lambda函数 + def action(x): # 嵌套lambda函数 + return (lambda y : x + y) + f = lambda: a if xxx() else b # 无参数的lambda函数,使用方法f() + +#-- lambda函数与map filter reduce函数的结合 + list(map((lambda x: x + 1), [1, 2, 3])) # [2, 3, 4] + list(filter((lambda x: x > 0), range(-4, 5))) # [1, 2, 3, 4] + functools.reduce((lambda x, y: x + y), [1, 2, 3]) # 6 + functools.reduce((lambda x, y: x * y), [2, 3, 4]) # 24 + +#-- 生成器函数:yield VS return + def gensquare(N): + for i in range(N): + yield i** 2 # 状态挂起 可以恢复到此时的状态 + for i in gensquare(5): # 使用方法 + print(i, end = ' ') # [0, 1, 4, 9, 16] + x = gensquare(2) # x是一个生成对象 + next(x) # 等同于x.__next__() 返回0 + next(x) # 等同于x.__next__() 返回1 + next(x) # 等同于x.__next__() 抛出异常StopIteration + +#-- 生成器表达式:小括号进行列表解析 + G = (x ** 2 for x in range(3)) # 使用小括号可以创建所需结果的生成器generator object + next(G), next(G), next(G) # 和上述中的生成器函数的返回值一致 + #(1)生成器(生成器函数/生成器表达式)是单个迭代对象 + G = (x ** 2 for x in range(4)) + I1 = iter(G) # 这里实际上iter(G) = G + next(I1) # 输出0 + next(G) # 输出1 + next(I1) # 输出4 + #(2)生成器不保留迭代后的结果 + gen = (i for i in range(4)) + 2 in gen # 返回True + 3 in gen # 返回True + 1 in gen # 返回False,其实检测2的时候,1已经就不在生成器中了,即1已经被迭代过了,同理2、3也不在了 + +#-- 本地变量是静态检测的 + X = 22 # 全局变量X的声明和定义 + def test(): + print(X) # 如果没有下一语句 则该句合法 打印全局变量X + X = 88 # 这一语句使得上一语句非法 因为它使得X变成了本地变量 上一句变成了打印一个未定义的本地变量(局部变量) + if False: # 即使这样的语句 也会把print语句视为非法语句 因为: + X = 88 # Python会无视if语句而仍然声明了局部变量X + def test(): # 改进 + global X # 声明变量X为全局变量 + print(X) # 打印全局变量X + X = 88 # 改变全局变量X + +#-- 函数的默认值是在函数定义的时候实例化的 而不是在调用的时候 例子: + def foo(numbers=[]): # 这里的[]是可变的 + numbers.append(9) + print(numbers) + foo() # first time, like before, [9] + foo() # second time, not like before, [9, 9] + foo() # third time, not like before too, [9, 9, 9] + # 改进: + def foo(numbers=None): + if numbers is None: numbers = [] + numbers.append(9) + print(numbers) + # 另外一个例子 参数的默认值为不可变的: + def foo(count=0): # 这里的0是数字, 是不可变的 + count += 1 + print(count) + foo() # 输出1 + foo() # 还是输出1 + foo(3) # 输出4 + foo() # 还是输出1 + + +"""函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子""" + + """数学运算类""" + abs(x) # 求绝对值,参数可以是整型,也可以是复数,若参数是复数,则返回复数的模 + complex([real[, imag]]) # 创建一个复数 + divmod(a, b) # 分别取商和余数,注意:整型、浮点型都可以 + float([x]) # 将一个字符串或数转换为浮点数。如果无参数将返回0.0 + int([x[, base]]) # 将一个字符串或浮点数转换为int类型,base表示进制 + long([x[, base]]) # 将一个字符串或浮点数转换为long类型 + pow(x, y) # 返回x的y次幂 + range([start], stop[, step]) # 产生一个序列,默认从0开始 + round(x[, n]) # 四舍五入 + sum(iterable[, start]) # 对集合求和 + oct(x) # 将一个数字转化为8进制字符串 + hex(x) # 将一个数字转换为16进制字符串 + chr(i) # 返回给定int类型对应的ASCII字符 + unichr(i) # 返回给定int类型的unicode + ord(c) # 返回ASCII字符对应的整数 + bin(x) # 将整数x转换为二进制字符串 + bool([x]) # 将x转换为Boolean类型 + + """集合类操作""" + basestring() # str和unicode的超类,不能直接调用,可以用作isinstance判断 + format(value [, format_spec]) # 格式化输出字符串,格式化的参数顺序从0开始,如“I am {0},I like {1}” + enumerate(sequence[, start=0]) # 返回一个可枚举的对象,注意它有第二个参数 + iter(obj[, sentinel]) # 生成一个对象的迭代器,第二个参数表示分隔符 + max(iterable[, args...][key]) # 返回集合中的最大值 + min(iterable[, args...][key]) # 返回集合中的最小值 + dict([arg]) # 创建数据字典 + list([iterable]) # 将一个集合类转换为另外一个集合类 + set() # set对象实例化 + frozenset([iterable]) # 产生一个不可变的set + tuple([iterable]) # 生成一个tuple类型 + str([object]) # 转换为string类型 + sorted(iterable[, cmp[, key[, reverse]]]) # 集合排序 + L = [('b',2),('a',1),('c',3),('d',4)] + sorted(L, key=lambda x: x[1]), reverse=True) # 使用Key参数和reverse参数 + sorted(L, key=lambda x: (x[0], x[1])) # 使用key参数进行多条件排序,即如果x[0]相同,则比较x[1] + + """逻辑判断""" + all(iterable) # 集合中的元素都为真的时候为真,特别的,若为空串返回为True + any(iterable) # 集合中的元素有一个为真的时候为真,特别的,若为空串返回为False + cmp(x, y) # 如果x < y ,返回负数;x == y, 返回0;x > y,返回正数 + + """IO操作""" + file(filename [, mode [, bufsize]]) # file类型的构造函数。 + input([prompt]) # 获取用户输入,推荐使用raw_input,因为该函数将不会捕获用户的错误输入,意思是自行判断类型 + # 在 Built-in Functions 里有一句话是这样写的:Consider using the raw_input() function for general input from users. + raw_input([prompt]) # 设置输入,输入都是作为字符串处理 + open(name[, mode[, buffering]]) # 打开文件,与file有什么不同?推荐使用open + + """其他""" + callable(object) # 检查对象object是否可调用 + classmethod(func) # 用来说明这个func是个类方法 + staticmethod(func) # 用来说明这个func为静态方法 + dir([object]) # 不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。 + help(obj) # 返回obj的帮助信息 + eval(expression) # 计算表达式expression的值,并返回 + exec(str) # 将str作为Python语句执行 + execfile(filename) # 用法类似exec(),不同的是execfile的参数filename为文件名,而exec的参数为字符串。 + filter(function, iterable) # 构造一个序列,等价于[item for item in iterable if function(item)],function返回值为True或False的函数 + list(filter(bool, range(-3, 4)))# 返回[-3, -2, -1, 1, 2, 3], 没有0 + hasattr(object, name) # 判断对象object是否包含名为name的特性 + getattr(object, name [, defalut]) # 获取一个类的属性 + setattr(object, name, value) # 设置属性值 + delattr(object, name) # 删除object对象名为name的属性 + globals() # 返回一个描述当前全局符号表的字典 + hash(object) # 如果对象object为哈希表类型,返回对象object的哈希值 + id(object) # 返回对象的唯一标识,一串数字 + isinstance(object, classinfo) # 判断object是否是class的实例 + isinstance(1, int) # 判断是不是int类型 + isinstance(1, (int, float)) # isinstance的第二个参数接受一个元组类型 + issubclass(class, classinfo) # 判断class是否为classinfo的子类 + locals() # 返回当前的变量列表 + map(function, iterable, ...) # 遍历每个元素,执行function操作 + list(map(abs, range(-3, 4))) # 返回[3, 2, 1, 0, 1, 2, 3] + next(iterator[, default]) # 类似于iterator.next() + property([fget[, fset[, fdel[, doc]]]]) # 属性访问的包装类,设置后可以通过c.x=value等来访问setter和getter + reduce(function, iterable[, initializer]) # 合并操作,从第一个开始是前两个参数,然后是前两个的结果与第三个合并进行处理,以此类推 + def add(x,y):return x + y + reduce(add, range(1, 11)) # 返回55 (注:1+2+3+4+5+6+7+8+9+10 = 55) + reduce(add, range(1, 11), 20) # 返回75 + reload(module) # 重新加载模块 + repr(object) # 将一个对象变幻为可打印的格式 + slice(start, stop[, step]) # 产生分片对象 + type(object) # 返回该object的类型 + vars([object]) # 返回对象的变量名、变量值的字典 + a = Class(); # Class为一个空类 + a.name = 'qi', a.age = 9 + vars(a) # {'name':'qi', 'age':9} + zip([iterable, ...]) # 返回对应数组 + list(zip([1, 2, 3], [4, 5, 6])) # [(1, 4), (2, 5), (3, 6)] + a = [1, 2, 3], b = ["a", "b", "c"] + z = zip(a, b) # 压缩:[(1, "a"), (2, "b"), (3, "c")] + zip(*z) # 解压缩:[(1, 2, 3), ("a", "b", "c")] + unicode(string, encoding, errors) # 将字符串string转化为unicode形式,string为encoded string。 + + +"""模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle""" + +#-- Python模块搜索路径: + """ + (1)程序的主目录 (2)PYTHONPATH目录 (3)标准链接库目录 (4)任何.pth文件的内容 + """ + +#-- 查看全部的模块搜索路径 + import sys + sys.path + sys.argv # 获得脚本的参数 + sys.builtin_module_names # 查找内建模块 + sys.platform # 返回当前平台 出现如: "win32" "linux" "darwin"等 + sys.modules # 查找已导入的模块 + sys.modules.keys() + sys.stdout # stdout 和 stderr 都是类文件对象,但是它们都是只写的。它们都没有 read 方法,只有 write 方法 + sys.stdout.write("hello") + sys.stderr + sys.stdin + +#-- 模块的使用代码 + import module1, module2 # 导入module1 使用module1.printer() + from module1 import printer # 导入module1中的printer变量 使用printer() + from module1 import * # 导入module1中的全部变量 使用不必添加module1前缀 + +#-- 重载模块reload: 这是一个内置函数 而不是一条语句 + from imp import reload + reload(module) + +#-- 模块的包导入:使用点号(.)而不是路径(dir1\dir2)进行导入 + import dir1.dir2.mod # d导入包(目录)dir1中的包dir2中的mod模块 此时dir1必须在Python可搜索路径中 + from dir1.dir2.mod import * # from语法的包导入 + +#-- __init__.py包文件:每个导入的包中都应该包含这么一个文件 + """ + 该文件可以为空 + 首次进行包导入时 该文件会自动执行 + 高级功能:在该文件中使用__all__列表来定义包(目录)以from*的形式导入时 需要导入什么 + """ + +#-- 包相对导入:使用点号(.) 只能使用from语句 + from . import spam # 导入当前目录下的spam模块(Python2: 当前目录下的模块, 直接导入即可) + from .spam import name # 导入当前目录下的spam模块的name属性(Python2: 当前目录下的模块, 直接导入即可,不用加.) + from .. import spam # 导入当前目录的父目录下的spam模块 + +#-- 包相对导入与普通导入的区别 + from string import * # 这里导入的string模块为sys.path路径上的 而不是本目录下的string模块(如果存在也不是) + from .string import * # 这里导入的string模块为本目录下的(不存在则导入失败) 而不是sys.path路径上的 + +#-- 模块数据隐藏:最小化from*的破坏 + _X # 变量名前加下划线可以防止from*导入时该变量名被复制出去 + __all__ = ['x', 'x1', 'x2'] # 使用__all__列表指定from*时复制出去的变量名(变量名在列表中为字符串形式) + +#-- 可以使用__name__进行模块的单元测试:当模块为顶层执行文件时值为'__main__' 当模块被导入时为模块名 + if __name__ == '__main__': + doSomething + # 模块属性中还有其他属性,例如: + __doc__ # 模块的说明文档 + __file__ # 模块文件的文件名,包括全路径 + __name__ # 主文件或者被导入文件 + __package__ # 模块所在的包 + +#-- import语句from语句的as扩展 + import modulename as name + from modulename import attrname as name + +#-- 得到模块属性的几种方法 假设为了得到name属性的值 + M.name + M.__dict__['name'] + sys.modules['M'].name + getattr(M, 'name') + + +"""类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象""" + +#-- 最普通的类 + class C1(C2, C3): + spam = 42 # 数据属性 + def __init__(self, name): # 函数属性:构造函数 + self.name = name + def __del__(self): # 函数属性:析构函数 + print("goodbey ", self.name) + I1 = C1('bob') + +#-- Python的类没有基于参数的函数重载 + class FirstClass(object): + def test(self, string): + print(string) + def test(self): # 此时类中只有一个test函数 即后者test(self) 它覆盖掉前者带参数的test函数 + print("hello world") + +#-- 子类扩展超类: 尽量调用超类的方法 + class Manager(Person): + def giveRaise(self, percent, bonus = .10): + self.pay = int(self.pay*(1 + percent + bonus)) # 不好的方式 复制粘贴超类代码 + Person.giveRaise(self, percent + bonus) # 好的方式 尽量调用超类方法 + +#-- 类内省工具 + bob = Person('bob') + bob.__class__ # + bob.__class__.__name__ # 'Person' + bob.__dict__ # {'pay':0, 'name':'bob', 'job':'Manager'} + +#-- 返回1中 数据属性spam是属于类 而不是对象 + I1 = C1('bob'); I2 = C2('tom') # 此时I1和I2的spam都为42 但是都是返回的C1的spam属性 + C1.spam = 24 # 此时I1和I2的spam都为24 + I1.spam = 3 # 此时I1新增自有属性spam 值为3 I2和C1的spam还都为24 + +#-- 类方法调用的两种方式 + instance.method(arg...) + class.method(instance, arg...) + +#-- 抽象超类的实现方法 + # (1)某个函数中调用未定义的函数 子类中定义该函数 + def delegate(self): + self.action() # 本类中不定义action函数 所以使用delegate函数时就会出错 + # (2)定义action函数 但是返回异常 + def action(self): + raise NotImplementedError("action must be defined") + # (3)上述的两种方法还都可以定义实例对象 实际上可以利用@装饰器语法生成不能定义的抽象超类 + from abc import ABCMeta, abstractmethod + class Super(metaclass = ABCMeta): + @abstractmethod + def action(self): pass + x = Super() # 返回 TypeError: Can't instantiate abstract class Super with abstract methods action + +#-- # OOP和继承: "is-a"的关系 + class A(B): + pass + a = A() + isinstance(a, B) # 返回True, A是B的子类 a也是B的一种 + # OOP和组合: "has-a"的关系 + pass + # OOP和委托: "包装"对象 在Python中委托通常是以"__getattr__"钩子方法实现的, 这个方法会拦截对不存在属性的读取 + # 包装类(或者称为代理类)可以使用__getattr__把任意读取转发给被包装的对象 + class wrapper(object): + def __init__(self, object): + self.wrapped = object + def __getattr(self, attrname): + print('Trace: ', attrname) + return getattr(self.wrapped, attrname) + # 注:这里使用getattr(X, N)内置函数以变量名字符串N从包装对象X中取出属性 类似于X.__dict__[N] + x = wrapper([1, 2, 3]) + x.append(4) # 返回 "Trace: append" [1, 2, 3, 4] + x = wrapper({'a':1, 'b':2}) + list(x.keys()) # 返回 "Trace: keys" ['a', 'b'] + +#-- 类的伪私有属性:使用__attr + class C1(object): + def __init__(self, name): + self.__name = name # 此时类的__name属性为伪私有属性 原理 它会自动变成self._C1__name = name + def __str__(self): + return 'self.name = %s' % self.__name + I = C1('tom') + print(I) # 返回 self.name = tom + I.__name = 'jeey' # 这里无法访问 __name为伪私有属性 + I._C1__name = 'jeey' # 这里可以修改成功 self.name = jeey + +#-- 类方法是对象:无绑定类方法对象 / 绑定实例方法对象 + class Spam(object): + def doit(self, message): + print(message) + def selfless(message) + print(message) + obj = Spam() + x = obj.doit # 类的绑定方法对象 实例 + 函数 + x('hello world') + x = Spam.doit # 类的无绑定方法对象 类名 + 函数 + x(obj, 'hello world') + x = Spam.selfless # 类的无绑定方法函数 在3.0之前无效 + x('hello world') + +#-- 获取对象信息: 属性和方法 + a = MyObject() + dir(a) # 使用dir函数 + hasattr(a, 'x') # 测试是否有x属性或方法 即a.x是否已经存在 + setattr(a, 'y', 19) # 设置属性或方法 等同于a.y = 19 + getattr(a, 'z', 0) # 获取属性或方法 如果属性不存在 则返回默认值0 + #这里有个小技巧,setattr可以设置一个不能访问到的属性,即只能用getattr获取 + setattr(a, "can't touch", 100) # 这里的属性名带有空格,不能直接访问 + getattr(a, "can't touch", 0) # 但是可以用getattr获取 + +#-- 为类动态绑定属性或方法: MethodType方法 + # 一般创建了一个class的实例后, 可以给该实例绑定任何属性和方法, 这就是动态语言的灵活性 + class Student(object): + pass + s = Student() + s.name = 'Michael' # 动态给实例绑定一个属性 + def set_age(self, age): # 定义一个函数作为实例方法 + self.age = age + from types import MethodType + s.set_age = MethodType(set_age, s) # 给实例绑定一个方法 类的其他实例不受此影响 + s.set_age(25) # 调用实例方法 + Student.set_age = MethodType(set_age, Student) # 为类绑定一个方法 类的所有实例都拥有该方法 + + +"""类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题""" + +#-- 多重继承: "混合类", 搜索方式"从下到上 从左到右 广度优先" + class A(B, C): + pass + +#-- 类的继承和子类的初始化 + # 1.子类定义了__init__方法时,若未显示调用基类__init__方法,python不会帮你调用。 + # 2.子类未定义__init__方法时,python会自动帮你调用首个基类的__init__方法,注意是首个。 + # 3.子类显示调用基类的初始化函数: + class FooParent(object): + def __init__(self, a): + self.parent = 'I\'m the Parent.' + print('Parent:a=' + str(a)) + def bar(self, message): + print(message + ' from Parent') + class FooChild(FooParent): + def __init__(self, a): + FooParent.__init__(self, a) + print('Child:a=' + str(a)) + def bar(self, message): + FooParent.bar(self, message) + print(message + ' from Child') + fooChild = FooChild(10) + fooChild.bar('HelloWorld') + +#-- #实例方法 / 静态方法 / 类方法 + class Methods(object): + def imeth(self, x): print(self, x) # 实例方法:传入的是实例和数据,操作的是实例的属性 + def smeth(x): print(x) # 静态方法:只传入数据 不传入实例,操作的是类的属性而不是实例的属性 + def cmeth(cls, x): print(cls, x) # 类方法:传入的是类对象和数据 + smeth = staticmethod(smeth) # 调用内置函数,也可以使用@staticmethod + cmeth = classmethod(cmeth) # 调用内置函数,也可以使用@classmethod + obj = Methods() + obj.imeth(1) # 实例方法调用 <__main__.Methods object...> 1 + Methods.imeth(obj, 2) # <__main__.Methods object...> 2 + Methods.smeth(3) # 静态方法调用 3 + obj.smeth(4) # 这里可以使用实例进行调用 + Methods.cmeth(5) # 类方法调用 5 + obj.cmeth(6) # 6 + +#-- 函数装饰器:是它后边的函数的运行时的声明 由@符号以及后边紧跟的"元函数"(metafunction)组成 + @staticmethod + def smeth(x): print(x) + # 等同于: + def smeth(x): print(x) + smeth = staticmethod(smeth) + # 同理 + @classmethod + def cmeth(cls, x): print(x) + # 等同于 + def cmeth(cls, x): print(x) + cmeth = classmethod(cmeth) + +#-- 类修饰器:是它后边的类的运行时的声明 由@符号以及后边紧跟的"元函数"(metafunction)组成 + def decorator(aClass):..... + @decorator + class C(object):.... + # 等同于: + class C(object):.... + C = decorator(C) + +#-- 限制class属性: __slots__属性 + class Student(object): + __slots__ = ('name', 'age') # 限制Student及其实例只能拥有name和age属性 + # __slots__属性只对当前类起作用, 对其子类不起作用 + # __slots__属性能够节省内存 + # __slots__属性可以为列表list,或者元组tuple + +#-- 类属性高级话题: @property + # 假设定义了一个类:C,该类必须继承自object类,有一私有变量_x + class C(object): + def __init__(self): + self.__x = None + # 第一种使用属性的方法 + def getx(self): + return self.__x + def setx(self, value): + self.__x = value + def delx(self): + del self.__x + x = property(getx, setx, delx, '') + # property函数原型为property(fget=None,fset=None,fdel=None,doc=None) + # 使用 + c = C() + c.x = 100 # 自动调用setx方法 + y = c.x # 自动调用getx方法 + del c.x # 自动调用delx方法 + # 第二种方法使用属性的方法 + @property + def x(self): + return self.__x + @x.setter + def x(self, value): + self.__x = value + @x.deleter + def x(self): + del self.__x + # 使用 + c = C() + c.x = 100 # 自动调用setter方法 + y = c.x # 自动调用x方法 + del c.x # 自动调用deleter方法 + +#-- 定制类: 重写类的方法 + # (1)__str__方法、__repr__方法: 定制类的输出字符串 + # (2)__iter__方法、next方法: 定制类的可迭代性 + class Fib(object): + def __init__(self): + self.a, self.b = 0, 1 # 初始化两个计数器a,b + def __iter__(self): + return self # 实例本身就是迭代对象,故返回自己 + def next(self): + self.a, self.b = self.b, self.a + self.b + if self.a > 100000: # 退出循环的条件 + raise StopIteration() + return self.a # 返回下一个值 + for n in Fib(): + print(n) # 使用 + # (3)__getitem__方法、__setitem__方法: 定制类的下标操作[] 或者切片操作slice + class Indexer(object): + def __init__(self): + self.data = {} + def __getitem__(self, n): # 定义getitem方法 + print('getitem:', n) + return self.data[n] + def __setitem__(self, key, value): # 定义setitem方法 + print('setitem:key = {0}, value = {1}'.format(key, value)) + self.data[key] = value + test = Indexer() + test[0] = 1; test[3] = '3' # 调用setitem方法 + print(test[0]) # 调用getitem方法 + # (4)__getattr__方法: 定制类的属性操作 + class Student(object): + def __getattr__(self, attr): # 定义当获取类的属性时的返回值 + if attr=='age': + return 25 # 当获取age属性时返回25 + raise AttributeError('object has no attribute: %s' % attr) + # 注意: 只有当属性不存在时 才会调用该方法 且该方法默认返回None 需要在函数最后引发异常 + s = Student() + s.age # s中age属性不存在 故调用__getattr__方法 返回25 + # (5)__call__方法: 定制类的'可调用'性 + class Student(object): + def __call__(self): # 也可以带参数 + print('Calling......') + s = Student() + s() # s变成了可调用的 也可以带参数 + callable(s) # 测试s的可调用性 返回True + # (6)__len__方法:求类的长度 + def __len__(self): + return len(self.data) + +#-- 动态创建类type() + # 一般创建类 需要在代码中提前定义 + class Hello(object): + def hello(self, name='world'): + print('Hello, %s.' % name) + h = Hello() + h.hello() # Hello, world + type(Hello) # Hello是一个type类型 返回 + type(h) # h是一个Hello类型 返回 + # 动态类型语言中 类可以动态创建 type函数可用于创建新类型 + def fn(self, name='world'): # 先定义函数 + print('Hello, %s.' % name) + Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello类 type原型: type(name, bases, dict) + h = Hello() # 此时的h和上边的h一致 + + +"""异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关""" + +#-- #捕获异常: + try: + except: # 捕获所有的异常 等同于except Exception: + except name: # 捕获指定的异常 + except name, value: # 捕获指定的异常和额外的数据(实例) + except (name1, name2): + except (name1, name2), value: + except name4 as X: + else: # 如果没有发生异常 + finally: # 总会执行的部分 + # 引发异常: raise子句(raise IndexError) + raise # raise instance of a class, raise IndexError() + raise # make and raise instance of a class, raise IndexError + raise # reraise the most recent exception + +#-- Python3.x中的异常链: raise exception from otherException + except Exception as X: + raise IndexError('Bad') from X + +#-- assert子句: assert , + assert x < 0, 'x must be negative' + +#-- with/as环境管理器:作为常见的try/finally用法模式的替代方案 + with expression [as variable], expression [as variable]: + # 例子: + with open('test.txt') as myfile: + for line in myfile: print(line) + # 等同于: + myfile = open('test.txt') + try: + for line in myfile: print(line) + finally: + myfile.close() + +#-- 用户自定义异常: class Bad(Exception):..... + """ + Exception超类 / except基类即可捕获到其所有子类 + Exception超类有默认的打印消息和状态 当然也可以定制打印显示: + """ + class MyBad(Exception): + def __str__(self): + return '定制的打印消息' + try: + MyBad() + except MyBad as x: + print(x) + +#-- 用户定制异常数据 + class FormatError(Exception): + def __init__(self, line ,file): + self.line = line + self.file = file + try: + raise FormatError(42, 'test.py') + except FormatError as X: + print('Error at ', X.file, X.line) + # 用户定制异常行为(方法):以记录日志为例 + class FormatError(Exception): + logfile = 'formaterror.txt' + def __init__(self, line ,file): + self.line = line + self.file = file + def logger(self): + open(self.logfile, 'a').write('Error at ', self.file, self.line) + try: + raise FormatError(42, 'test.py') + except FormatError as X: + X.logger() + +#-- 关于sys.exc_info:允许一个异常处理器获取对最近引发的异常的访问 + try: + ...... + except: + # 此时sys.exc_info()返回一个元组(type, value, traceback) + # type:正在处理的异常的异常类型 + # value:引发的异常的实例 + # traceback:堆栈信息 + +#-- 异常层次 + BaseException + +-- SystemExit + +-- KeyboardInterrupt + +-- GeneratorExit + +-- Exception + +-- StopIteration + +-- ArithmeticError + +-- AssertionError + +-- AttributeError + +-- BufferError + +-- EOFError + +-- ImportError + +-- LookupError + +-- MemoryError + +-- NameError + +-- OSError + +-- ReferenceError + +-- RuntimeError + +-- SyntaxError + +-- SystemError + +-- TypeError + +-- ValueError + +-- Warning + + +"""Unicode和字节字符串---Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串""" + +#-- Python的字符串类型 + """Python2.x""" + # 1.str表示8位文本和二进制数据 + # 2.unicode表示宽字符Unicode文本 + """Python3.x""" + # 1.str表示Unicode文本(8位或者更宽) + # 2.bytes表示不可变的二进制数据 + # 3.bytearray是一种可变的bytes类型 + +#-- 字符编码方法 + """ASCII""" # 一个字节,只包含英文字符,0到127,共128个字符,利用函数可以进行字符和数字的相互转换 + ord('a') # 字符a的ASCII码为97,所以这里返回97 + chr(97) # 和上边的过程相反,返回字符'a' + """Latin-1""" # 一个字节,包含特殊字符,0到255,共256个字符,相当于对ASCII码的扩展 + chr(196) # 返回一个特殊字符:Ä + """Unicode""" # 宽字符,一个字符包含多个字节,一般用于亚洲的字符集,比如中文有好几万字 + """UTF-8""" # 可变字节数,小于128的字符表示为单个字节,128到0X7FF之间的代码转换为两个字节,0X7FF以上的代码转换为3或4个字节 + # 注意:可以看出来,ASCII码是Latin-1和UTF-8的一个子集 + # 注意:utf-8是unicode的一种实现方式,unicode、gbk、gb2312是编码字符集 + +#-- 查看Python中的字符串编码名称,查看系统的编码 + import encodings + help(encoding) + import sys + sys.platform # 'win64' + sys.getdefaultencoding() # 'utf-8' + sys.getdefaultencoding() # 返回当前系统平台的编码类型 + sys.getsizeof(object) # 返回object占有的bytes的大小 + +#-- 源文件字符集编码声明: 添加注释来指定想要的编码形式 从而改变默认值 注释必须出现在脚本的第一行或者第二行 + """说明:其实这里只会检查#和coding:utf-8,其余的字符都是为了美观加上的""" + # _*_ coding: utf-8 _*_ + # coding = utf-8 + +#-- #编码: 字符串 --> 原始字节 #解码: 原始字节 --> 字符串 + +#-- Python3.x中的字符串应用 + s = '...' # 构建一个str对象,不可变对象 + b = b'...' # 构建一个bytes对象,不可变对象 + s[0], b[0] # 返回('.', 113) + s[1:], b[1:] # 返回('..', b'..') + B = B""" + xxxx + yyyy + """ + # B = b'\nxxxx\nyyyy\n' + # 编码,将str字符串转化为其raw bytes形式: + str.encode(encoding = 'utf-8', errors = 'strict') + bytes(str, encoding) + # 编码例子: + S = 'egg' + S.encode() # b'egg' + bytes(S, encoding = 'ascii') # b'egg' + # 解码,将raw bytes字符串转化为str形式: + bytes.decode(encoding = 'utf-8', errors = 'strict') + str(bytes_or_buffer[, encoding[, errors]]) + # 解码例子: + B = b'spam' + B.decode() # 'spam' + str(B) # "b'spam'",不带编码的str调用,结果为打印该bytes对象 + str(B, encoding = 'ascii')# 'spam',带编码的str调用,结果为转化该bytes对象 + +#-- Python2.x的编码问题 + u = u'汉' + print repr(u) # u'\xba\xba' + s = u.encode('UTF-8') + print repr(s) # '\xc2\xba\xc2\xba' + u2 = s.decode('UTF-8') + print repr(u2) # u'\xba\xba' + # 对unicode进行解码是错误的 + s2 = u.decode('UTF-8') # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) + # 同样,对str进行编码也是错误的 + u2 = s.encode('UTF-8') # UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128) + +#-- bytes对象 + B = b'abc' + B = bytes('abc', 'ascii') + B = bytes([97, 98, 99]) + B = 'abc'.encode() + # bytes对象的方法调用基本和str类型一致 但:B[0]返回的是ASCII码值97, 而不是b'a' + +#-- #文本文件: 根据Unicode编码来解释文件内容,要么是平台的默认编码,要么是指定的编码类型 + # 二进制文件:表示字节值的整数的一个序列 open('bin.txt', 'rb') + +#-- Unicode文件 + s = 'A\xc4B\xe8C' # s = 'A?BèC' len(s) = 5 + #手动编码 + l = s.encode('latin-1') # l = b'A\xc4B\xe8C' len(l) = 5 + u = s.encode('utf-8') # u = b'A\xc3\x84B\xc3\xa8C' len(u) = 7 + #文件输出编码 + open('latindata', 'w', encoding = 'latin-1').write(s) + l = open('latindata', 'rb').read() # l = b'A\xc4B\xe8C' len(l) = 5 + open('uft8data', 'w', encoding = 'utf-8').write(s) + u = open('uft8data', 'rb').read() # u = b'A\xc3\x84B\xc3\xa8C' len(u) = 7 + #文件输入编码 + s = open('latindata', 'r', encoding = 'latin-1').read() # s = 'A?BèC' len(s) = 5 + s = open('latindata', 'rb').read().decode('latin-1') # s = 'A?BèC' len(s) = 5 + s = open('utf8data', 'r', encoding = 'utf-8').read() # s = 'A?BèC' len(s) = 5 + s = open('utf8data', 'rb').read().decode('utf-8') # s = 'A?BèC' len(s) = 5 + + +"""其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他""" + +#-- Python实现任意深度的赋值 例如a[0] = 'value1'; a[1][2] = 'value2'; a[3][4][5] = 'value3' + class MyDict(dict): + def __setitem__(self, key, value): # 该函数不做任何改动 这里只是为了输出 + print('setitem:', key, value, self) + super().__setitem__(key, value) + def __getitem__(self, item): # 主要技巧在该函数 + print('getitem:', item, self) # 输出信息 + # 基本思路: a[1][2]赋值时 需要先取出a[1] 然后给a[1]的[2]赋值 + if item not in self: # 如果a[1]不存在 则需要新建一个dict 并使得a[1] = dict + temp = MyDict() # 新建的dict: temp + super().__setitem__(item, temp) # 赋值a[1] = temp + return temp # 返回temp 使得temp[2] = value有效 + return super().__getitem__(item) # 如果a[1]存在 则直接返回a[1] + # 例子: + test = MyDict() + test[0] = 'test' + print(test[0]) + test[1][2] = 'test1' + print(test[1][2]) + test[1][3] = 'test2' + print(test[1][3]) + +#-- Python中的多维数组 + lists = [0] * 3 # 扩展list,结果为[0, 0, 0] + lists = [[]] * 3 # 多维数组,结果为[[], [], []],但有问题,往下看 + lists[0].append(3) # 期望看到的结果[[3], [], []],实际结果[[3], [3], [3]],原因:list*n操作,是浅拷贝,如何避免?往下看 + lists = [[] for i in range(3)] # 多维数组,结果为[[], [], []] + lists[0].append(3) # 结果为[[3], [], []] + lists[1].append(6) # 结果为[[3], [6], []] + lists[2].append(9) # 结果为[[3], [6], [9]] + lists = [[[] for j in range(4)] for i in range(3)] # 3行4列,且每一个元素为[] +``` diff --git "a/docs/Leetcode_Solutions/Python/Summary/python\347\232\204\345\220\204\347\247\215pass.md" "b/docs/Leetcode_Solutions/Python/Summary/python\347\232\204\345\220\204\347\247\215pass.md" new file mode 100644 index 000000000..c1ac085a8 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/python\347\232\204\345\220\204\347\247\215pass.md" @@ -0,0 +1,123 @@ +#Python的各种Pass + +感觉最近对于pass by reference 和 pass by value又有了一点/一些认识 + + +1. python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值'来传递对象。 +2. 当人们复制列表或字典时,就复制了对象列表的引用同,如果改变引用的值,则修改了原始的参数。 +3. 为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。 + + +##### Linked List的例子 + + + +``` +class ListNode(object): + def __init__(self, x): + self.val = x + self.next = None + +node1 = ListNode(1) +node2 = ListNode(2) +node3 = ListNode(3) +node4 = ListNode(4) +node5 = ListNode(5) + +node1.next = node2 +node2.next = node3 +node3.next = node4 +node4.next = node5 + +``` + + + +来改变head + +``` +def testWithPointers1(head): + head.next = None +``` + + + +运行 testWithPointers1(node1) + +然后node1.next 为None了 + +// 可以理解,因为传进去的是head这个可变对象。 + + + +``` +def testWithPointers2(head): + cur = head + cur.next = None +``` + + + +运行 testWithPointers2(node1) +// node1.next 同样为None了 + +Python的object,list都是pass by reference,所以是改变的 + +看另外一个例子: + +``` +def printLinkedList(head): + while head: + print(head) + head = head.next +``` + + +输出 + +``` + printLinkedList(head) + +<__main__.ListNode object at 0x1044c0e10> + +1 + +<__main__.ListNode object at 0x1044c0fd0> + +2 + +<__main__.ListNode object at 0x1044c0c88> + +3 + +<__main__.ListNode object at 0x1044c0be0> + +4 + +<__main__.ListNode object at 0x1044c0780> + +5 + +head + +Out[39]: <__main__.ListNode at 0x1044c0e10> + +``` + +其实这里的head为什么没有改变有点疑惑 + + + +##### String看一下 + + + a = "abc" + + def changeA(s): + s = "" + changeA(a) + + +a 并不会改变,依旧为'abc' + + \ No newline at end of file diff --git a/docs/Leetcode_Solutions/Python/Summary/slide_windows_template.md b/docs/Leetcode_Solutions/Python/Summary/slide_windows_template.md new file mode 100644 index 000000000..919d1c0f9 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/Summary/slide_windows_template.md @@ -0,0 +1,185 @@ +能用此模板解决的题目目前有如下: +[leetcode 003](https://github.com/Lisanaaa/thinking_in_lc/blob/master/003._longest_substring_without_repeating_characters.md), +[leetcode 030](https://github.com/Lisanaaa/thinking_in_lc/edit/master/30._Substring_with_Concatenation_of_All_Words.md), +[leetcode 076](https://github.com/Lisanaaa/thinking_in_lc/blob/master/076._Minimum_Window_Substring.md), +[leetcode 159](https://github.com/Lisanaaa/thinking_in_lc/blob/master/159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md), +[leetcode 438](https://github.com/Lisanaaa/thinking_in_lc/blob/master/438._Find_All_Anagrams_in_a_String.md) + + + +带注释python版本 +```python +class Solution(object): + def slideWindowTemplateByLisanaaa(self, s, t): + """ + :type s: str + :type t: str + :rtype: 具体题目具体分析 + """ + # init a collection or int value to save the result according the question. + res = [] + if len(t) > len(s): + return res + + # create a hashmap to save the Characters of the target substring. + # (K, V) = (Character, Frequence of the Characters) + maps = collections.Counter(t) + + # maintain a counter to check whether match the target string. + # must be the map size, NOT the string size because the char may be duplicate. + counter = len(maps.keys()) + + # Two Pointers: begin - left pointer of the window; end - right pointer of the window + begin, end = 0, 0 + + # the length of the substring which match the target string. + length = sys.maxint + + # loop at the begining of the source string + while end < len(s): + if s[end] in maps: + maps[s[end]] -= 1 # plus or minus one + if maps[s[end]] == 0: + counter -= 1 # modify the counter according the requirement(different condition). + end += 1 + + # increase begin pointer to make it invalid/valid again + while counter == 0: # counter condition. different question may have different condition + if s[begin] in maps: + maps[s[begin]] += 1 # plus or minus one + if maps[s[begin]] > 0: + counter += 1 # modify the counter according the requirement(different condition). + begin += 1 + + ''' + type your code here according to the question + 1. save / update(min/max) the result if find a target + 2. result: collections or int value + ''' + return res +``` + +无注释python版本: +```python +class Solution(object): + def slideWindowTemplateByLisanaaa(self, s, t): + res = [] + if len(t) > len(s): + return res + maps = collections.Counter(t) + counter = len(maps.keys()) + begin, end = 0, 0 + length = 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 + begin += 1 + + ''' + 1. save / update(min/max) the result if find a target + 2. result: collections or int value + ''' + return res +``` +带注释java版本 +```java +public class Solution { + public List slidingWindowTemplateByHarryChaoyangHe(String s, String t) { + //init a collection or int value to save the result according the question. + List result = new LinkedList<>(); + if(t.length()> s.length()) return result; + + //create a hashmap to save the Characters of the target substring. + //(K, V) = (Character, Frequence of the Characters) + Map map = new HashMap<>(); + for(char c : t.toCharArray()){ + map.put(c, map.getOrDefault(c, 0) + 1); + } + //maintain a counter to check whether match the target string. + int counter = map.size();//must be the map size, NOT the string size because the char may be duplicate. + + //Two Pointers: begin - left pointer of the window; end - right pointer of the window + int begin = 0, end = 0; + + //the length of the substring which match the target string. + int len = Integer.MAX_VALUE; + + //loop at the begining of the source string + while(end < s.length()){ + + char c = s.charAt(end);//get a character + + if( map.containsKey(c) ){ + map.put(c, map.get(c)-1);// plus or minus one + if(map.get(c) == 0) counter--;//modify the counter according the requirement(different condition). + } + end++; + + //increase begin pointer to make it invalid/valid again + while(counter == 0 /* counter condition. different question may have different condition */){ + + char tempc = s.charAt(begin);//***be careful here: choose the char at begin pointer, NOT the end pointer + if(map.containsKey(tempc)){ + map.put(tempc, map.get(tempc) + 1);//plus or minus one + if(map.get(tempc) > 0) counter++;//modify the counter according the requirement(different condition). + } + + /* save / update(min/max) the result if find a target*/ + // result collections or result int value + + begin++; + } + } + return result; + } +} +``` + +无注释java版本: +```java +public class Solution { + public List slidingWindowTemplateByHarryChaoyangHe(String s, String t) { + List result = new LinkedList<>(); + if(t.length()> s.length()) return result; + Map map = new HashMap<>(); + for(char c : t.toCharArray()){ + map.put(c, map.getOrDefault(c, 0) + 1); + } + int counter = map.size(); + int begin = 0, end = 0; + int len = Integer.MAX_VALUE; + while(end < s.length()){ + char c = s.charAt(end); + if( map.containsKey(c) ){ + map.put(c, map.get(c)-1); + if(map.get(c) == 0) counter--; + } + end++; + while(counter == 0){ + char tempc = s.charAt(begin); + if(map.containsKey(tempc)){ + map.put(tempc, map.get(tempc) + 1); + if(map.get(tempc) > 0) counter++; + } + + /* + save / update(min/max) the result if find a target + result collections or result int value + */ + + begin++; + } + } + return result; + } +} +``` + diff --git a/docs/Leetcode_Solutions/Python/Summary/union_find.md b/docs/Leetcode_Solutions/Python/Summary/union_find.md new file mode 100644 index 000000000..5e32d3089 --- /dev/null +++ b/docs/Leetcode_Solutions/Python/Summary/union_find.md @@ -0,0 +1,281 @@ +## 并查集(参考leetcode323题) + +### 应用场景: + +动态联通性 + +- 网络连接判断: +如果每个pair中的两个整数用来表示这两个节点是需要连通的,那么为所有的pairs建立了动态连通图后,就能够尽可能少的减少布线的需要, +因为已经连通的两个节点会被直接忽略掉。例如[1,2]代表节点1和节点2是联通的,如果再次出现[2,1]我们就不需要再连接他们了,因为已经连接过一次了。 + +- 变量名等同性(类似于指针的概念): +在程序中,可以声明多个引用来指向同一对象,这个时候就可以通过为程序中声明的引用和实际对象建立动态连通图来判断哪些引用实际上是指向同一对象。 + +### 对问题建模: + +在对问题进行建模的时候,我们应该尽量想清楚需要解决的问题是什么。因为模型中选择的数据结构和算法显然会根据问题的不同而不同, +就动态连通性这个场景而言,我们需要解决的问题可能是: + +1. 给出两个节点,判断它们是否连通,如果连通,不需要给出具体的路径 +2. 给出两个节点,判断它们是否连通,如果连通,需要给出具体的路径 + +就上面两种问题而言,虽然只有是否能够给出具体路径的区别,但是这个区别导致了选择算法的不同 + +### 建模思路: + +最简单而直观的假设是,对于连通的所有节点,我们可以认为它们属于一个组,因此不连通的节点必然就属于不同的组。 +随着Pair的输入,我们需要首先判断输入的两个节点是否连通。如何判断呢?按照上面的假设,我们可以通过判断它们属于的组,然后看看这两个组是否相同。 +如果相同,那么这两个节点连通,反之不连通。为简单起见,我们将所有的节点以整数表示,即对N个节点使用0到N-1的整数表示。 +而在处理输入的Pair之前,每个节点必然都是孤立的,即他们分属于不同的组,可以使用数组来表示这一层关系。 +数组的index是节点的整数表示,而相应的值就是该节点的组号了。该数组可以初始化为:```uf = [i for i in range(n)]``` + +初始化完毕之后,对该动态连通图有几种可能的操作: + +1. 查询节点属于的组 + +数组对应位置的值即为组号 + +2. 判断两个节点是否属于同一个组 + +分别得到两个节点的组号,然后判断组号是否相等 + +3. 连接两个节点,使之属于同一个组 + +分别得到两个节点的组号,组号相同时操作结束,不同时,将其中的一个节点的组号换成另一个节点的组号 + +4. 获取组的数目 + +初始化为节点的数目,然后每次成功连接两个节点之后,递减1 + +### API: + +我们可以设置对应的API +```python +def uf(n) # 初始化uf数组和组数目 +def union(x, y) # 连接两个节点 +def find(x) # 判断节点所属于的组 +def connected(x, y) # 判断两个节点是否联通 +def count() # 返回所有组的数目 +``` + +注意其中使用整数来表示节点,如果需要使用其他的数据类型表示节点,比如使用字符串,那么可以用哈希表来进行映射,即将String映射成这里需要的Integer类型。 + +分析以上的API,方法connected和union都依赖于find,connected对两个参数调用两次find方法,而union在真正执行union之前也需要判断是否连通, +这又是两次调用find方法。因此我们需要把find方法的实现设计的尽可能的高效。所以就有了下面的Quick-Find实现。 + +### Quick-Find实现 + +``` +class Solution(object): + uf = [] # access to component id (site indexed) + count = 0 # number of components + + def uf(self, n): # 初始化uf数组和组数目 + self.count = n + self.uf = [i for i in range(n)] + + def find(self, x): # 判断节点所属于的组 + return uf[x] + + def union(self, x, y): # 连接两个节点 + x_root = find(x) + y_root = find(y) + if x_root == y_root: + return + for i in range(len(self.uf)): + if uf[i] == x_root: + uf[i] = y_root + count -= 1 + + def connected(self, x, y): # 判断两个节点是否联通 + return find(x) == find(y) + + def count(self): # 返回所有组的数目 + return count +``` + +上述代码的find方法十分高效,因为仅仅需要一次数组读取操作就能够找到该节点的组号。 +但是问题随之而来,对于需要添加新路径的情况,就涉及到对于组号的修改,因为并不能确定哪些节点的组号需要被修改, +因此就必须对整个数组进行遍历,找到需要修改的节点,逐一修改,这一下每次添加新路径带来的复杂度就是线性关系了, +如果要添加的新路径的数量是M,节点数量是N,那么最后的时间复杂度就是MN,显然是一个平方阶的复杂度,对于大规模的数据而言,平方阶的算法是存在问题的, +这种情况下,每次添加新路径就是“牵一发而动全身”,想要解决这个问题,关键就是要提高union方法的效率,让它不再需要遍历整个数组。 + + +### Quick-Union 算法: + +考虑一下,为什么以上的解法会造成“牵一发而动全身”?因为每个节点所属的组号都是单独记录,各自为政的,没有将它们以更好的方式组织起来, +当涉及到修改的时候,除了逐一通知、修改,别无他法。所以现在的问题就变成了,如何将节点以更好的方式组织起来,组织的方式有很多种, +但是最直观的还是将组号相同的节点组织在一起,想想所学的数据结构,什么样子的数据结构能够将一些节点给组织起来? +常见的就是链表,图,树,什么的了。但是哪种结构对于查找和修改的效率最高?毫无疑问是树,因此考虑如何将节点和组的关系以树的形式表现出来。 + +如果不改变底层数据结构,即不改变使用数组的表示方法的话。可以采用parent-link的方式将节点组织起来, +举例而言,uf[p]的值就是p节点的父节点的序号,如果p是树根的话,uf[p]的值就是p,因此最后经过若干次查找,一个节点总是能够找到它的根节点, +即满足uf[root] = root的节点也就是组的根节点了,然后就可以使用根节点的序号来表示组号。所以在处理一个pair的时候, +将首先找到pair中每一个节点的组号(即它们所在树的根节点的序号),如果属于不同的组的话,就将其中一个根节点的父节点设置为另外一个根节点, +相当于将一颗独立的树编程另一颗独立的树的子树。直观的过程如下图所示。但是这个时候又引入了问题。 + +树这种数据结构容易出现极端情况,因为在建树的过程中,树的最终形态严重依赖于输入数据本身的性质,比如数据是否排序,是否随机分布等等。 +比如在输入数据是有序的情况下,构造的BST会退化成一个链表。在我们这个问题中,也是会出现的极端情况的。 + +``` +class Solution(object): + uf = [] # access to component id (site indexed) + count = 0 # number of components + + def uf(self, n): # 初始化uf数组和组数目 + self.count = n + self.uf = [i for i in range(n)] + + def find(self, x): # 判断节点所属于的组 + # if uf[x] != x: ## 这种方式也可以,但是递归次数多了容易出问题 + # uf[x] = find(uf[x]) + while x != uf[x]: + x = uf[x] + return uf[x] + + def union(self, x, y): # 连接两个节点 + x_root = find(x) + y_root = find(y) + uf[x_root] = y_root + count -= 1 + + def connected(self, x, y): # 判断两个节点是否联通 + return find(x) == find(y) + + def count(self): # 返回所有组的数目 + return count +``` + +为了克服这个问题,BST可以演变成为红黑树或者AVL树等等。 + +然而,在我们考虑的这个应用场景中,每对节点之间是不具备可比性的。因此需要想其它的办法。在没有什么思路的时候,多看看相应的代码可能会有一些启发, +考虑一下Quick-Union算法中的union方法实现: + +``` +def union(self, x, y): # 连接两个节点 + x_root = find(x) + y_root = find(y) + uf[x_root] = y_root + count -= 1 +``` + +上面 id[pRoot] = qRoot 这行代码看上去似乎不太对劲。因为这也属于一种“硬编码”,这样实现是基于一个约定,即p所在的树总是会被作为q所在树的子树, +从而实现两颗独立的树的融合。那么这样的约定是不是总是合理的呢?显然不是,比如p所在的树的规模比q所在的树的规模大的多时, +p和q结合之后形成的树就是十分不和谐的一头轻一头重的”畸形树“了。 + +所以我们应该考虑树的大小,然后再来决定到底是调用 uf[x_root] = y_root 或者是 uf[y_root] = x_root + +即总是size小的树作为子树和size大的树进行合并。这样就能够尽量的保持整棵树的平衡。 + +所以现在的问题就变成了:树的大小该如何确定? + +我们回到最初的情形,即每个节点最一开始都是属于一个独立的组,通过下面的代码进行初始化: +``` +tree_size = [1 for i in range(n)] +``` + +然后: + +``` +def union(self, x, y): # 连接两个节点 + x_root = find(x) + y_root = find(y) + if tree_size[x_root] <= tree_size[y_root]: + uf[x_root] = y_root + tree_size[y_root] += tree_size[x_root] + else: + uf[y_root] = x_root + tree_size[x_root] += tree_size[y_root] + count -= 1 +``` + +可以发现,通过tree_size数组决定如何对两棵树进行合并之后,最后得到的树的高度大幅度减小了。这是十分有意义的。 +因为在Quick-Union算法中的任何操作,都不可避免的需要调用find方法,而该方法的执行效率依赖于树的高度。树的高度减小了, +find方法的效率就增加了,从而也就增加了整个Quick-Union算法的效率。 + +上面的论证其实还可以给我们一些启示,即对于Quick-Union算法而言,节点组织的理想情况应该是一颗十分扁平的树,所有的孩子节点应该都在height为1的地方, +即所有的孩子都直接连接到根节点。这样的组织结构能够保证find操作的最高效率。 + +那么如何构造这种理想结构呢? + +在find方法的执行过程中,不是需要进行一个while循环找到根节点嘛?如果保存所有路过的中间节点到一个数组中,然后在while循环结束之后, +将这些中间节点的父节点指向根节点,不就行了么?但是这个方法也有问题,因为find操作的频繁性,会造成频繁生成中间节点数组, +相应的分配销毁的时间自然就上升了。那么有没有更好的方法呢?还是有的,即将节点的父节点指向该节点的爷爷节点,这一点很巧妙, +十分方便且有效,相当于在寻找根节点的同时,对路径进行了压缩,使整个树结构扁平化。相应的实现如下,实际上只需要添加一行代码: + +``` +def find(self, x): # 判断节点所属于的组 + while x != uf[x]: + uf[x] = uf[uf[x]] + x = uf[x] + return uf[x] +``` +综上,我决定以后解决问题的时候用这个模版就行了: + +```python +class UnionFind(object): + uf = [] # access to component id (site indexed) + count = 0 # number of components + + def uf(self, n): # 初始化uf数组和组数目 + self.count = n + self.uf = [i for i in range(n)] + + def find(self, x): # 判断节点所属于的组 + while x != self.uf[x]: + self.uf[x] = self.uf[self.uf[x]] + x = self.uf[x] + return self.uf[x] + + def union(self, x, y): # 连接两个节点 + x_root = self.find(x) + y_root = self.find(y) + self.uf[x_root] = y_root + self.count -= 1 + + def connected(self, x, y): # 判断两个节点是否联通 + return self.find(x) == self.find(y) + + def count(self): # 返回所有组的数目 + return self.count +``` +### 时间复杂度分析 +- find()操作的时间复杂度最坏情况下为O(N) +- union()操作的时间复杂度最坏情况下为O(1) + +Quick union的表现将随着我们不断调用union()构建联通集而变差。因为代表这个联通集的树越来越高,调用find()的开销也就越来越大。 + +至此,动态连通性相关的Union-Find算法基本上就介绍完了,从容易想到的Quick-Find到相对复杂但是更加高效的Quick-Union,然后到对Quick-Union的几项改进, +让我们的算法的效率不断的提高。 + +这几种算法的时间复杂度如下所示: +![](https://github.com/apachecn/LeetCode/blob/master/images/union_find8D76B4AFCB73CED67BE37B92B385A55C.jpg) + +对大规模数据进行处理,使用平方阶的算法是不合适的,比如简单直观的Quick-Find算法,通过发现问题的更多特点,找到合适的数据结构,然后有针对性的进行改进, +得到了Quick-Union算法及其多种改进算法,最终使得算法的复杂度降低到了近乎线性复杂度。 + +如果需要的功能不仅仅是检测两个节点是否连通,还需要在连通时得到具体的路径,那么就需要用到别的算法了,比如DFS或者BFS。 + +并查集的应用,可以参考另外一篇文章[并查集应用举例](https://blog.csdn.net/dm_vincent/article/details/7769159) + +## References + +1. [并查集(Union-Find)算法介绍](https://blog.csdn.net/dm_vincent/article/details/7655764) + + + + + + + + + + + + + + + + + + diff --git "a/docs/Leetcode_Solutions/Python/Summary/\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/Leetcode_Solutions/Python/Summary/\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" new file mode 100644 index 000000000..54d08ab00 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\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" @@ -0,0 +1,245 @@ +### 1. 二叉搜索树(BSTree)的概念 + +二叉搜索树又被称为二叉排序树,那么它本身也是一棵二叉树,那么满足以下性质的二叉树就是二叉搜索树,如图: + +- 若左子树不为空,则左子树上所有节点的值都小于根节点的值; +- 若它的右子树不为空,则它的右子树上所有节点的值都大于根节点的值; +- 它的左右子树也要分别是二叉搜索树。 + +### 2. 二叉搜索树的插入 + +- 如果插入值已经存在,则不插,return False +- 如果not root,则返回TreeNode(val) +- 根据与root.val的比较,在左右子树中进行递归操作 + +代码中保证插入的值不存在,也是[leetcode第701题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/701._Insert_into_a_Binary_Search_Tree.md)中所gurantee的 +```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 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 +``` + +### 3. 二叉搜索树的搜索 + +* 搜索节点 +```java +public TreeNode search(int key) { + TreeNode pNode = root; + while (pNode != null) { + if (key == pNode.key) { + return pNode; + } else if (key > pNode.key) { + pNode = pNode.rchild; + } else if (key < pNode.key) { + pNode = pNode.lchild; + } + } + return null;// 如果没有搜索到结果那么就只能返回空值了 +} +``` + +* 获取最小节点 + +```java +public TreeNode minElemNode(TreeNode node) throws Exception { + if (node == null) { + throw new Exception("此树为空树!"); + } + TreeNode pNode = node; + while (pNode.lchild != null) { + pNode = pNode.lchild; + } + return pNode; +} +``` + +* 获取最大节点 + +```java +public TreeNode maxElemNode(TreeNode node) throws Exception { + if (node == null) { + throw new Exception("此树为空树!"); + } + TreeNode pNode = node; + while (pNode.rchild != null) { + pNode = pNode.rchild; + } + return pNode; +} +``` + +* 获取给定节点在中序遍历下的后续第一个节点(即找到该节点的右子树中的最左孩子) + +```java +public TreeNode successor(TreeNode node) throws Exception { + if (node == null) { + throw new Exception("此树为空树!"); + } + // 分两种情况考虑,此节点是否有右子树 + // 当这个节点有右子树的情况下,那么右子树的最小关键字节点就是这个节点的后续节点 + if (node.rchild != null) { + return minElemNode(node.rchild); + } + + // 当这个节点没有右子树的情况下,即 node.rchild == null + // 如果这个节点是它父节点的左子树的话,那么就说明这个父节点就是后续节点了 + TreeNode parentNode = node.parent; + while (parentNode != null && parentNode.rchild == node) { + node = parentNode; + parentNode = parentNode.parent; + } + return parentNode; +} +``` + + +* 获取给定节点在中序遍历下的前趋结点 + +```java +public TreeNode precessor(TreeNode node) throws Exception { + // 查找前趋节点也是分两种情况考虑 + // 如果这个节点存在左子树,那么这个左子树的最大关键字就是这个节点的前趋节点 + if (node.lchild != null) { + return maxElemNode(node.lchild); + } + // 如果这个节点不存在左子树,那么这个节点的父节点 + TreeNode parentNode = node.parent; + while (parentNode != null && parentNode.lchild == node) { + node = parentNode; + parentNode = parentNode.lchild; + } + return parentNode; +} +``` + + + +### 4. 二叉搜索树的删除 + +- 要删除的节点不存在,return False +- 要删除的节点没有子节点,直接删 +- 要删除的节点只有一个子节点(即只有一个左子节点或者一个右子节点),让被删除节点的父亲节点指向其子节点即可 +- 要删除的节点target有两个子节点(即左右均存在),则首先找到该节点的右子树中的最左孩子(也就是右子树中序遍历的第一个节点,分两种情况), +然后将两者互换,再删除target即可 + +```java + // 从二叉树当中删除指定的节点 + public void delete(int key) throws Exception { + TreeNode pNode = search(key); + if (pNode == null) { + throw new Exception("此树中不存在要删除的这个节点!"); + } + + delete(pNode); + } + + private void delete(TreeNode pNode) throws Exception { + // 第一种情况:删除没有子节点的节点 + if (pNode.lchild == null && pNode.rchild == null) { + if (pNode == root) {// 如果是根节点,那么就删除整棵树 + root = null; + } else if (pNode == pNode.parent.lchild) { + // 如果这个节点是父节点的左节点,则将父节点的左节点设为空 + pNode.parent.lchild = null; + } else if (pNode == pNode.parent.rchild) { + // 如果这个节点是父节点的右节点,则将父节点的右节点设为空 + pNode.parent.rchild = null; + } + } + + // 第二种情况: (删除有一个子节点的节点) + // 如果要删除的节点只有右节点 + if (pNode.lchild == null && pNode.rchild != null) { + if (pNode == root) { + root = pNode.rchild; + } else if (pNode == pNode.parent.lchild) { + pNode.parent.lchild = pNode.rchild; + pNode.rchild.parent = pNode.parent; + } else if (pNode == pNode.parent.rchild) { + pNode.parent.rchild = pNode.rchild; + pNode.rchild.parent = pNode.parent; + } + } + // 如果要删除的节点只有左节点 + if (pNode.lchild != null && pNode.rchild == null) { + if (pNode == root) { + root = pNode.lchild; + } else if (pNode == pNode.parent.lchild) { + pNode.parent.lchild = pNode.lchild; + pNode.lchild.parent = pNode.parent; + } else if (pNode == pNode.parent.rchild) { + pNode.parent.rchild = pNode.lchild; + pNode.lchild.parent = pNode.parent; + } + } + + // 第三种情况: (删除有两个子节点的节点,即左右子节点都非空) + + // 方法是用要删除的节点的后续节点代替要删除的节点,并且删除后续节点(删除后续节点的时候需要递归操作) + // 解析:这里要用到的最多也就会发生两次,即后续节点不会再继续递归的删除下一个后续节点了, + // 因为,要删除的节点的后续节点肯定是:要删除的那个节点的右子树的最小关键字,而这个最小关键字肯定不会有左节点; + // 所以,在删除后续节点的时候肯定不会用到(两个节点都非空的判断 ),如有有子节点,肯定就是有一个右节点。 + if (pNode.lchild != null && pNode.rchild != null) { + // 先找出后续节点 + TreeNode successorNode = successor(pNode); + if (pNode == root) { + root.key = successorNode.key; + } else { + pNode.key = successorNode.key;// 赋值,将后续节点的值赋给要删除的那个节点 + } + delete(successorNode);// 递归的删除后续节点 + } + } +``` + + +### 5. 二叉搜索树的遍历 + +前序遍历:[leetcode第144题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/144._binary_tree_preorder_traversal.md) + +中序遍历:[leetcode第94题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/094._binary_tree_inorder_traversal.md) + +后序遍历:[leetcode第145题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/145._binary_tree_postorder_traversal.md) + + +层次遍历:[leetcode第102题](https://github.com/apachecn/LeetCode/blob/master/docs/Leetcode_Solutions/102._binary_tree_level_order_traversal.md) + +## References + +[数据结构与算法之二叉搜索树插入、查询与删除](https://blog.csdn.net/chenliguan/article/details/52956546) + +[二叉搜索树的插入与删除图解](http://www.cnblogs.com/MrListening/p/5782752.html) + +[二叉树算法删除代码实现](https://blog.csdn.net/tayanxunhua/article/details/11100113) + +[二叉树的Java实现及特点总结](http://www.cnblogs.com/lzq198754/p/5857597.html) + + + + + + + + + + + + diff --git "a/docs/Leetcode_Solutions/Python/Summary/\344\275\215\350\277\220\347\256\227.md" "b/docs/Leetcode_Solutions/Python/Summary/\344\275\215\350\277\220\347\256\227.md" new file mode 100644 index 000000000..aeaa44c4d --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\344\275\215\350\277\220\347\256\227.md" @@ -0,0 +1,38 @@ +### 位运算 + +位运算包括: 加 减 乘 取反 and 异或 + +- 0110 + 0110 = 0110 * 2 ,也就是0110左移1位 + +- 0011 * 0100 0100 = 4, 一个数乘以 2^n 即是将这个数左移n + +- a ^(~a) = 0 + +- x & (~0 << n ) 这样来看,0取反全部为1,然后将其右移n位,后面的全是0,x & (~0 <>:右移 + + ​ + +Bit Facts and Tricks + +``` +x ^ 0s = x x & 0s = 0 x | 0s = x +x ^ 1s = ~x x & 1s = x x | 1s = 1s +x ^ x = 0 x & x = x x | x = x +``` + diff --git "a/docs/Leetcode_Solutions/Python/Summary/\345\205\250\346\216\222\345\210\227\347\256\227\346\263\225.md" "b/docs/Leetcode_Solutions/Python/Summary/\345\205\250\346\216\222\345\210\227\347\256\227\346\263\225.md" new file mode 100644 index 000000000..767617664 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\345\205\250\346\216\222\345\210\227\347\256\227\346\263\225.md" @@ -0,0 +1,194 @@ +### 全排列算法 + + +#### 46. Permutations + + +Given a collection of distinct numbers, return all possible permutations. + +For example, +[1,2,3] have the following permutations: + + [ + [1,2,3], + [1,3,2], + [2,1,3], + [2,3,1], + [3,1,2], + [3,2,1] + ] + + +#####从空开始加 + +先跳离开这道题,来看类似的'ABC',我们要求它的全排列 + + +``` +def recPermute(sofar, rest): + if rest == '': + print sofar + else: + for i in range(len(rest)): + nxt = sofar + rest[i] + remaining = rest[:i] + rest[i+1:] + recPermute(nxt, remaining) + +// "wrapper" function +def listPermute(s): + recPermute('',s) +``` + +会正确输出`ABC ACB BAC BCA CAB CBA`,题目依靠的是每次我们从余下的字母中选一个,如果画图则会是这样: + + +``` + A B C + B C A C A B + C B C A B A +``` + +时间复杂度应该是O(n!) + +- n choose 1 +- n-1 choose 1 +- ... + + + +#####另一种市面上常见思路是交换: + +思路是这样的,同样看上面的图: + +- n个元素的全排列 = (n-1)个元素的全排列 + 另一个元素作为前缀 +- 如果只有一个元素,那么这个元素本身就是它的全排列 +- 不断将每个元素放作第一个元素,然后将这个元素作为前缀,并将其余元素继续全排列,等到出口,出口出去后还需要还原数组 + + +这个用数组来测试更容易写代码和直观: + + +``` +def recPermute(nums,begin): + n = len(nums) + if begin == n: + print nums, + + for i in range(begin,n): + nums[begin], nums[i] = nums[i],nums[begin] + recPermute(nums,begin+1) + nums[begin],nums[i] = nums[i],nums[begin] + +recPermute(['A','B','C'],0) + +``` + +这样的写法更容易理解: + + +```python +class Solution: + # @param num, a list of integer + # @return a list of lists of integers + def permute(self, num): + if len(num) == 0: return [] + if len(num) == 1: return [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) + return res +``` + +每次用一个没有用过的头元素,然后加上全排列产生的结果. + +如果分析复杂度,应该也是O(n!) + + +#### 47. Permutations II + + +最简单的想法: + +- 排序 +- 如果碰到重复的就继续处理下一个 + +``` +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 = [] + nums.sort() + for i in range(len(nums)): + if i > 0 and nums[i] == nums[i-1]: continue + for j in self.permuteUnique(nums[:i] + nums[i+1:]): + res.append([nums[i]] + j) + return res + +``` + + + + +#### 31. Next Permutation + +实际上这个题目也就是Generation in lexicographic order, + +wikipedia 和 [这里](https://www.nayuki.io/page/next-lexicographical-permutation-algorithm) 有很好,很精妙的算法,也有点two pointer的意思 + + +``` +1. Find the highest index i such that s[i] < s[i+1]. If no such index exists, the permutation is the last permutation. +2. Find the highest index j > i such that s[j] > s[i]. Such a j must exist, since i+1 is such an index. +3. Swap s[i] with s[j]. +4. Reverse the order of all of the elements after index i till the last element. +``` + + +看例子: + +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 + + + +``` +class Solution(object): + def nextPermutation(self, nums): + """ + :type nums: List[int] + :rtype: void Do not return anything, modify nums in-place instead. + """ + m, n = 0, 0 + for i in range(len(nums) - 2, 0 , -1): + if nums[i] < nums[i+1]: + m = i + break + + for i in range(len(nums) - 1, 0 , -1): + if nums[i] > nums[m]: + n = i + break + + if m < n : + nums[m], nums[n] = nums[n], nums[m] + nums[m+1:] = nums[len(nums):m:-1] + else: + nums = nums.reverse() +``` + + +所以可以用这个next permutation来解46/47也可以,然后我兴奋了一下,这个算法很快的!然后我又冷静了,因为permutation的个数是O(n!)个啊|||,所以也不可能有啥大的提升吧 diff --git "a/docs/Leetcode_Solutions/Python/Summary/\345\205\253\346\216\222\345\272\217.md" "b/docs/Leetcode_Solutions/Python/Summary/\345\205\253\346\216\222\345\272\217.md" new file mode 100644 index 000000000..83b327202 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\345\205\253\346\216\222\345\272\217.md" @@ -0,0 +1,386 @@ +## 前言 +八大排序,三大查找是《数据结构》当中非常基础的知识点,在这里为了复习顺带总结了一下常见的八种排序算法。 +常见的八大排序算法,他们之间关系如下: + +![](/images/SortingAlgorithm/八大排序算法总结.png) + +他们的性能比较: + +![](/images/SortingAlgorithm/八大排序算法性能.png) + +### 直接插入排序 (Insertion sort) + +![](/images/SortingAlgorithm/直接插入排序.gif) + +直接插入排序的核心思想就是:将数组中的所有元素依次跟前面已经排好的元素相比较,如果选择的元素比已排序的元素小,则交换,直到全部元素都比较过。 +因此,从上面的描述中我们可以发现,直接插入排序可以用两个循环完成: + +1. 第一层循环:遍历待比较的所有数组元素 +2. 第二层循环:将本轮选择的元素(selected)与已经排好序的元素(ordered)相比较。 + - 如果```selected > ordered```,那么将二者交换 + +```python +#直接插入排序 +def insert_sort(L): + #遍历数组中的所有元素,其中0号索引元素默认已排序,因此从1开始 + for x in range(1,len(L)): + #将该元素与已排序好的前序数组依次比较,如果该元素小,则交换 + #range(x-1,-1,-1):从x-1倒序循环到0 + for i in range(x-1,-1,-1): + #判断:如果符合条件则交换 + if L[i] > L[i+1]: + L[i], L[i+1] = L[i+1], L[i] +``` +### 希尔排序 (Shell sort) + +![](/images/SortingAlgorithm/希尔排序.png) + +希尔排序的算法思想:将待排序数组按照步长gap进行分组,然后将每组的元素利用直接插入排序的方法进行排序;每次将gap折半减小,循环上述操作;当gap=1时,利用直接插入,完成排序。 +同样的:从上面的描述中我们可以发现:希尔排序的总体实现应该由三个循环完成: + +1. 第一层循环:将gap依次折半,对序列进行分组,直到gap=1 +2. 第二、三层循环:也即直接插入排序所需要的两次循环。具体描述见上。 + +```python +#希尔排序 +def insert_shell(L): + #初始化gap值,此处利用序列长度的一半为其赋值 + gap = int(len(L)/2) + #第一层循环:依次改变gap值对列表进行分组 + while (gap >= 1): + #下面:利用直接插入排序的思想对分组数据进行排序 + #range(gap,len(L)):从gap开始 + for x in range(gap,len(L)): + #range(x-gap,-1,-gap):从x-gap开始与选定元素开始倒序比较,每个比较元素之间间隔gap + for i in range(x-gap,-1,-gap): + #如果该组当中两个元素满足交换条件,则进行交换 + if L[i] > L[i+gap]: + L[i], L[i+gap] = L[i+gap], L[i] + #while循环条件折半 + gap = int((gap/2)) +``` + +### 简单选择排序 (Selection sort) + +![](/images/SortingAlgorithm/简单选择排序.gif) + +简单选择排序的基本思想:比较+交换。 + +1. 从待排序序列中,找到关键字最小的元素; +2. 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换; +3. 从余下的 N - 1 个元素中,找出关键字最小的元素,重复(1)、(2)步,直到排序结束。 +因此我们可以发现,简单选择排序也是通过两层循环实现。 + - 第一层循环:依次遍历序列当中的每一个元素 + - 第二层循环:将遍历得到的当前元素依次与余下的元素进行比较,符合最小元素的条件,则交换。 + +```python +# 简单选择排序 +def select_sort(L): +#依次遍历序列中的每一个元素 + for x in range(0,len(L)): +#将当前位置的元素定义此轮循环当中的最小值 + minimum = L[x] +#将该元素与剩下的元素依次比较寻找最小元素 + for i in range(x+1,len(L)): + if L[i] < minimum: + L[i], minimum = minimum, L[i] +#将比较后得到的真正的最小值赋值给当前位置 + L[x] = minimum +``` + +### 堆排序 (Heap sort) + +#### 堆的概念 + +堆:本质是一种数组对象。特别重要的一点性质:任意的叶子节点小于(或大于)它所有的父节点。对此,又分为大顶堆和小顶堆,大顶堆要求节点的元素都要大于其孩子,小顶堆要求节点元素都小于其左右孩子,两者对左右孩子的大小关系不做任何要求。 +利用堆排序,就是基于大顶堆或者小顶堆的一种排序方法。下面,我们通过大顶堆来实现。 + +基本思想: +堆排序可以按照以下步骤来完成: + +1. 首先将序列构建称为大顶堆; + +(这样满足了大顶堆那条性质:位于根节点的元素一定是当前序列的最大值) + +![](/images/SortingAlgorithm/构建大顶堆.png) + +2. 取出当前大顶堆的根节点,将其与序列末尾元素进行交换; + +(此时:序列末尾的元素为已排序的最大值;由于交换了元素,当前位于根节点的堆并不一定满足大顶堆的性质) + +3. 对交换后的n-1个序列元素进行调整,使其满足大顶堆的性质; + +![](/images/SortingAlgorithm/调整大顶堆.png) + +4. 重复2.3步骤,直至堆中只有1个元素为止 + +```python +#-------------------------堆排序-------------------------------- +#**********获取左右叶子节点********** +def LEFT(i): + return 2*i + 1 +def RIGHT(i): + return 2*i + 2 +#********** 调整大顶堆 ********** +#L:待调整序列 length: 序列长度 i:需要调整的结点 +def adjust_max_heap(L, length, i): +#定义一个int值保存当前序列最大值的下标 + largest = i +#获得序列左右叶子节点的下标 + left, right = LEFT(i), RIGHT(i) +#当左叶子节点的下标小于序列长度 并且 左叶子节点的值大于父节点时,将左叶子节点的下标赋值给largest + if (left < length) and (L[left] > L[i]): + largest = left +#当右叶子节点的下标小于序列长度 并且 右叶子节点的值大于父节点时,将右叶子节点的下标值赋值给largest + if (right < length) and (L[right] > L[largest]): + largest = right +#如果largest不等于i 说明当前的父节点不是最大值,需要交换值 + if (largest != i): + L[i], L[largest] = L[largest], L[i] + # 执行递归操作:两个任务:1 寻找最大值的下标;2.最大值与父节点交换 + adjust_max_heap(L, length, largest) +#********** 建立大顶堆 ********** +def build_max_heap(L): + length = len(L) + for x in range(int((length-1)/2), -1, -1): + adjust_max_heap(L, length, x) +#********** 堆排序 ********** +def heap_sort(L): +#先建立大顶堆,保证最大值位于根节点;并且父节点的值大于叶子结点 + build_max_heap(L) +#i:当前堆中序列的长度.初始化为序列的长度 + i = len(L) +#执行循环:1. 每次取出堆顶元素置于序列的最后(len-1,len-2,len-3...) +# 2. 调整堆,使其继续满足大顶堆的性质,注意实时修改堆中序列的长度 + while (i > 0): + L[i-1], L[0] = L[0], L[i-1] +#堆中序列长度减1 + i -= 1 +#调整大顶堆 + adjust_max_heap(L, i, 0) +``` +### 冒泡排序 (Bubble sort) + +![](/images/SortingAlgorithm/冒泡排序.gif) + +冒泡排序思路比较简单: + +1. 将序列当中的左右元素,依次比较,保证右边的元素始终大于左边的元素; +( 第一轮结束后,序列最后一个元素一定是当前序列的最大值;) +2. 对序列当中剩下的n-1个元素再次执行步骤1。 +3. 对于长度为n的序列,一共需要执行n-1轮比较 +(利用while循环可以减少执行次数) + +```python +#冒泡排序 +def bubble_sort(L): + length = len(L) +#序列长度为length,需要执行length-1轮交换 + for x in range(1, length): +#对于每一轮交换,都将序列当中的左右元素进行比较 +#每轮交换当中,由于序列最后的元素一定是最大的,因此每轮循环到序列未排序的位置即可 + for i in range(0, length-x): + if L[i] > L[i+1]: + L[i], L[i+1] = L[i+1], L[i] +``` + +### 快速排序 (Quick sort) + +![](/images/SortingAlgorithm/快速排序.gif) + +快速排序的基本思想:挖坑填数+分治法 + +1. 从序列当中选择一个基准数(pivot) +在这里我们选择序列当中第一个数作为基准数 +2. 将序列当中的所有数依次遍历,比基准数大的位于其右侧,比基准数小的位于其左侧 +3. 重复步骤1.2,直到所有子集当中只有一个元素为止。 + +用伪代码描述如下: +- i =L; j = R; 将基准数挖出形成第一个坑a[i]。 +- j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。 +- i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。 +- 再重复执行2,3二步,直到i==j,将基准数填入a[i]中 + +```python +#快速排序 +#L:待排序的序列;start排序的开始index,end序列末尾的index +#对于长度为length的序列:start = 0;end = length-1 +def quick_sort(L, start, end): + if start < end: + i, j, pivot = start, end, L[start] + while i < j: +#从右开始向左寻找第一个小于pivot的值 + while (i < j) and (L[j] >= pivot): + j -= 1 +#将小于pivot的值移到左边 + if (i < j): + L[i] = L[j] + i += 1 +#从左开始向右寻找第一个大于pivot的值 + while (i < j) and (L[i] <= pivot): + i += 1 +#将大于pivot的值移到右边 + if (i < j): + L[j] = L[i] + j -= 1 +#循环结束后,说明 i=j,此时左边的值全都小于pivot,右边的值全都大于pivot +#pivot的位置移动正确,那么此时只需对左右两侧的序列调用此函数进一步排序即可 +#递归调用函数:依次对左侧序列:从0 ~ i-1//右侧序列:从i+1 ~ end + L[i] = pivot +#左侧序列继续排序 + quick_sort(L, start, i-1) +#右侧序列继续排序 + quick_sort(L, i+1, end) +``` + +### 归并排序 (Merge sort) + +![](/images/SortingAlgorithm/归并排序.gif) + +1. 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个典型的应用。它的基本操作是:将已有的子序列合并,达到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。 +2. 归并排序其实要做两件事: + - 分解----将序列每次折半拆分 + - 合并----将划分后的序列段两两排序合并 +因此,归并排序实际上就是两个操作,拆分+合并 +3. 如何合并? + - L[first...mid]为第一段,L[mid+1...last]为第二段,并且两端已经有序,现在我们要将两端合成达到L[first...last]并且也有序。 + - 首先依次从第一段与第二段中取出元素比较,将较小的元素赋值给temp[] + - 重复执行上一步,当某一段赋值结束,则将另一段剩下的元素赋值给temp[] + - 此时将temp[]中的元素复制给L[],则得到的L[first...last]有序 +4. 如何分解? + - 在这里,我们采用递归的方法,首先将待排序列分成A,B两组; + - 然后重复对A、B序列分组; + - 直到分组后组内只有一个元素,此时我们认为组内所有元素有序,则分组结束。 + +```python +# 归并排序 +#这是合并的函数 +# 将序列L[first...mid]与序列L[mid+1...last]进行合并 +def mergearray(L, first, mid, last, temp): +#对i,j,k分别进行赋值 + i, j, k = first, mid+1, 0 +#当左右两边都有数时进行比较,取较小的数 + while (i <= mid) and (j <= last): + if L[i] <= L[j]: + temp[k] = L[i] + i += 1 + k += 1 + else: + temp[k] = L[j] + j += 1 + k += 1 +#如果左边序列还有数 + while (i <= mid): + temp[k] = L[i] + i += 1 + k += 1 +#如果右边序列还有数 + while (j <= last): + temp[k] = L[j] + j += 1 + k += 1 +#将temp当中该段有序元素赋值给L待排序列使之部分有序 + for x in range(0, k): + L[first+x] = temp[x] +# 这是分组的函数 +def merge_sort(L, first, last, temp): + if first < last: + mid = int(((first + last) / 2)) +#使左边序列有序 + merge_sort(L, first, mid, temp) +#使右边序列有序 + merge_sort(L, mid+1, last, temp) +#将两个有序序列合并 + mergearray(L, first, mid, last, temp) +# 归并排序的函数 +def merge_sort_array(L): +#声明一个长度为len(L)的空列表 + temp = len(L)*[None] +#调用归并排序 + merge_sort(L, 0, len(L)-1, temp) +``` + +### 基数排序 (Radix sort) + +![](/images/SortingAlgorithm/基数排序.gif) + +1. 基数排序:通过序列中各个元素的值,对排序的N个元素进行若干趟的“分配”与“收集”来实现排序。 + - 分配:我们将L[i]中的元素取出,首先确定其个位上的数字,根据该数字分配到与之序号相同的桶中 + - 收集:当序列中所有的元素都分配到对应的桶中,再按照顺序依次将桶中的元素收集形成新的一个待排序列L[ ] + - 对新形成的序列L[]重复执行分配和收集元素中的十位、百位...直到分配完该序列中的最高位,则排序结束 +2. 根据上述“基数排序”的展示,我们可以清楚的看到整个实现的过程 + +```python +#************************基数排序**************************** +#确定排序的次数 +#排序的顺序跟序列中最大数的位数相关 +def radix_sort_nums(L): + maxNum = L[0] +#寻找序列中的最大数 + for x in L: + if maxNum < x: + maxNum = x +#确定序列中的最大元素的位数 + times = 0 + while (maxNum > 0): + maxNum = int((maxNum/10)) + times += 1 + return times +#找到num从低到高第pos位的数据 +def get_num_pos(num, pos): + return (int((num/(10**(pos-1))))) % 10 +#基数排序 +def radix_sort(L): + count = 10 * [None] #存放各个桶的数据统计个数 + bucket = len(L) * [None] #暂时存放排序结果 +#从低位到高位依次执行循环 + for pos in range(1, radix_sort_nums(L)+1): + #置空各个桶的数据统计 + for x in range(0, 10): + count[x] = 0 + #统计当前该位(个位,十位,百位....)的元素数目 + for x in range(0, len(L)): + #统计各个桶将要装进去的元素个数 + j = get_num_pos(int(L[x]), pos) + count[j] += 1 + #count[i]表示第i个桶的右边界索引 + for x in range(1,10): + count[x] += count[x-1] + #将数据依次装入桶中 + for x in range(len(L)-1, -1, -1): + #求出元素第K位的数字 + j = get_num_pos(L[x], pos) + #放入对应的桶中,count[j]-1是第j个桶的右边界索引 + bucket[count[j]-1] = L[x] + #对应桶的装入数据索引-1 + count[j] -= 1 + # 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表 + for x in range(0, len(L)): + L[x] = bucket[x] +``` + +## 运行时间实测 + +10w数据 +``` +直接插入排序:1233.581131 +希尔排序:1409.8012320000003 +简单选择排序:466.66974500000015 +堆排序:1.2036720000000969 +冒泡排序:751.274449 +#**************************************************** +快速排序:1.0000003385357559e-06 +#快速排序有误:实际上并未执行 +#RecursionError: maximum recursion depth exceeded in comparison +#**************************************************** +归并排序:0.8262230000000272 +基数排序:1.1162899999999354 +``` +从运行结果上来看,堆排序、归并排序、基数排序真的快。 +对于快速排序迭代深度超过的问题,可以将考虑将快排通过非递归的方式进行实现。 + +## Resources + +1. [算法导论》笔记汇总](http://mindlee.com/2011/08/21/study-notes-directory/) +2. [八大排序算法的 Python 实现](http://python.jobbole.com/82270/) +3. [数据结构常见的八大排序算法(详细整理)](https://www.jianshu.com/p/7d037c332a9d) diff --git "a/docs/Leetcode_Solutions/Python/Summary/\345\255\220\351\233\206\345\220\210\351\227\256\351\242\230.md" "b/docs/Leetcode_Solutions/Python/Summary/\345\255\220\351\233\206\345\220\210\351\227\256\351\242\230.md" new file mode 100644 index 000000000..0d4afa96a --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\345\255\220\351\233\206\345\220\210\351\227\256\351\242\230.md" @@ -0,0 +1,114 @@ +###子集合问题 + +####78. Subsets + +子集合是全排列的好朋友,也是combination组合的好朋友,排列·组合·子集,他们三个都是好朋友. + + +#####从空开始加 + +同样先来看'ABC' + +``` +def recsubsets(sofar, rest): + if rest == '': + print sofar, + else: + recsubsets(sofar, rest[1:]) + recsubsets(sofar + rest[0], rest[1:]) + +def listsubsets(s): + recsubsets('',s) + + +listsubsets('ABC') +``` + +##### 市面流行思路 + +市面上流行的思路: + +- [[],[1]] 是 [1] 的子集合 +- [[],[1],[2],[1,2]] 是 [1,2] 的子集合,实际上就是1的子集合们加了一个2 + + +所以用python写起来也很简单/精美 + +``` +def subsets(nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + results = [[]] + for num in nums: + results.extend([result + [num] for result in results]) + return results +``` +我在这里犯过错,所以这一句 + +`results.extend([result + [num] for result in results])` 实际上等于: + + +``` +tmp = [] +for result in results: + tmp.append(result + [num]) +results.extend(tmp) +``` + + + + + +#### 90. Subsets II + + +要去重了,比如如果有 [1,2,2],那么解答为: + + + [ + [2], + [1], + [1,2,2], + [2,2], + [1,2], + [] + ] + + +现在来观察规律,与之前有不同之处是我们需要一个位置来mark,因为不再需要往之前出现过的地方再加了,看这个: + + +``` +[[],[1]] 是 [1] 的子集合 +[[],[1],[2],[1,2]] 是 [1,2] 的子集合,实际上就是1的子集合们加了一个2 +新来的2不能再从头开始加了,它需要从[ .., [2],[1,2] ]加 才是合理的 +``` + +所以看到非常精妙的代码 + + +``` +def subsets(nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + nums.sort() + result = [[]] + temp_size = 0 + + for i in range(len(nums)): + start = temp_size if i >= 1 and nums[i] == nums[i-1] else 0 + temp_size = len(result) + #print start,temp_size,result + for j in range(start, temp_size): + result.append(result[j] + [nums[i]]) + print result + +subsets([1,2,2]) +``` + +这里这个start是来记录了之前一次数组的长度,temp_size记住目前数组的长度,然后用这个来达到去重的目的,非常聪明 + diff --git "a/docs/Leetcode_Solutions/Python/Summary/\346\200\273\347\273\223.md" "b/docs/Leetcode_Solutions/Python/Summary/\346\200\273\347\273\223.md" new file mode 100644 index 000000000..99fcba752 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\346\200\273\347\273\223.md" @@ -0,0 +1,120 @@ +# 1 +```solution```下自定义函数```func(self, fargs, *args, **kwargs)```, 调用时使用```self.func()```的格式 + +# 2 +```not fargs``` 和 ```fargs == None```不一样,前者```fargs```可能为[], '', 0, etc + +# 3 +递归问题 +Any problem can be solved using dp. Solving using a greedy strategy is harder though, since you need to prove that greedy will work for that problem. There are some tell-tale signs of a problem where greedy may be applicable, but isn’t immediately apparent. Example: + +- Choice of an element depends only on its immediate neighbours (wiggle sort). +- Answer is monotonically non-decreasing or non-increasing (sorting). This is also applicable for LIS for example. +- Anything that requires lexicographically largest or smallest of something. +- Anything where processing the input in sorted order will help. +- Anything where processing the input in forward or reverse (as given) will help. +- Anything which requires you to track the minimum or maximum of something (think of sliding window problems). + +There’s matroid theory which deal with greedy algorithms, but I don’t really understand it. If someone does, I’ll be super grateful to them to explain it to me in simple language! + +In general, try to see if for a problem, the solution doesn’t depend on a lot of history about the solution itself, but the next part of the solution is somewhat independent from the rest of the solution. These are all indicative of the fact that a greedy strategy could be applicable. + +# 4 +[Counter.elements()](https://docs.python.org/2/library/collections.html) + +# 5 +测试案例写法 + +```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 +``` diff --git "a/docs/Leetcode_Solutions/Python/Summary/\346\226\220\346\263\242\351\202\243\345\245\221\347\232\204DP\346\200\235\350\200\203.md" "b/docs/Leetcode_Solutions/Python/Summary/\346\226\220\346\263\242\351\202\243\345\245\221\347\232\204DP\346\200\235\350\200\203.md" new file mode 100644 index 000000000..84ce8bbbf --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\346\226\220\346\263\242\351\202\243\345\245\221\347\232\204DP\346\200\235\350\200\203.md" @@ -0,0 +1,42 @@ +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. diff --git "a/docs/Leetcode_Solutions/Python/Summary/\347\203\231\345\215\260\344\277\256\347\202\274\345\244\247\346\263\225.md" "b/docs/Leetcode_Solutions/Python/Summary/\347\203\231\345\215\260\344\277\256\347\202\274\345\244\247\346\263\225.md" new file mode 100644 index 000000000..1765d341f --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\347\203\231\345\215\260\344\277\256\347\202\274\345\244\247\346\263\225.md" @@ -0,0 +1,12 @@ +## 战略思想 + +先要了解敌方的战略 + +``` +自我介绍5分钟,闲聊20分钟,再给你半道题目,要求你15分钟内想出最优解 +且代码实现 bug free并完成test cases,没完成超时,完成不符合题意 +``` + +## 应对方法 + +没辙,🤷‍♂️ diff --git "a/docs/Leetcode_Solutions/Python/Summary/\347\273\204\345\220\210\351\227\256\351\242\230.md" "b/docs/Leetcode_Solutions/Python/Summary/\347\273\204\345\220\210\351\227\256\351\242\230.md" new file mode 100644 index 000000000..33f295e82 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\347\273\204\345\220\210\351\227\256\351\242\230.md" @@ -0,0 +1,84 @@ +### 组合问题 + + +#### 77.Combinations + + +##### 会超时的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 + +- 如果 k==n ,则全选。 +- n > k 又可以分成两类: + - 选了n, 则在余下的n-1中选k-1 + - 没有选n, 则在余下的n-1中选k + +注意一下会有两个base case,因为k在不断减小和n在不断减小,所以写起来可以这样: + + +``` +def combine(n,k): + if k == 1: + return [[i+1] for i in range(n)] + if n == k: + return [range(1, k+1)] + # choose n , not choose n + return [r + [n] for r in combine(n-1,k-1)] + combine(n-1,k) + + +print combine(20,16) +``` + + +#### 39. Combination Sum + + +使用正常递归思路 + + +#### 40. Combination Sum II + +重复做跳过处理 + +#### 216. Combination Sum III + + +#### 377. Combination Sum IV diff --git "a/docs/Leetcode_Solutions/Python/Summary/\347\274\226\347\250\213\346\200\235\350\267\257\346\200\273\347\273\223.md" "b/docs/Leetcode_Solutions/Python/Summary/\347\274\226\347\250\213\346\200\235\350\267\257\346\200\273\347\273\223.md" new file mode 100644 index 000000000..53cde29b2 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\347\274\226\347\250\213\346\200\235\350\267\257\346\200\273\347\273\223.md" @@ -0,0 +1,20 @@ +## 1. OJ 基本条件 +达尔大佬对刷leetcode和刷笔试题有几个建议: + +1. 一般oj是有要求时间的,一般是1秒。后台判题系统都是单核单线程跑,机器性能不会太好。1秒能运行的基本操作个数的量级是10^6-10^7, +个别代码能跑到10^8,但很少见。这种情况下,看数据范围是可以大致了解到这个题目需要什么样子的时间复杂度。 +比如说,n<=1000的数据范围,o(n^3)的代码就不要写了,浪费时间而已。写代码之前得先计算自己代码的复杂度,预估自己代码跑的速度,再动手。 +2. 基本操作指的是逻辑和加减法,乘法比加减法慢得多,但在大复杂度的前提下,这种复杂度是可以忽略的。比如说,在一个算法o(n^3)中, +代码中一个两层嵌套循环o(n^2)就显得没什么优化意义了。优化代码主要优化算法复杂度,而那些,要不要用位运算代替除法啊, +或者两个一层循环要不要合并成一个一层循环啊,没有意义,不要纠结,同级复杂度,才有优化意义 +3. 高级编程语言每个api都有自己的复杂度,在没有了解复杂度之前不建议使用那些api,最好自己实现,比如哈希表啊,堆啊, +什么语言都有实现,熟悉之前还是乖乖自己实现的好 +4. 注意精度误差。。。比如开方,如果开方开的是一个整数,结果也是整数,最好写个二分,或者写个牛顿迭代求零点, +不要用内置函数sqrt,求出来是个浮点数,会有误差 + + +## 2. 判断环 +- 看到链表中的环就想到快慢指针 +- 看到图中的环就想到并查集,wisdompeak大佬说:用union find确实是判断图是否成环的一个很好的手段。但是它更常用在无向图。 +对于有向图,用并查集需要非常小心。这里的edge都是有向的,我觉得无脑用并查集会有风险。 +我的总结是:union find唯一能用在有向图的地方,就是只有我们试图保证这张图是树的时候。 diff --git "a/docs/Leetcode_Solutions/Python/Summary/\351\200\222\345\275\222_recursion.md" "b/docs/Leetcode_Solutions/Python/Summary/\351\200\222\345\275\222_recursion.md" new file mode 100644 index 000000000..413872965 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\351\200\222\345\275\222_recursion.md" @@ -0,0 +1,39 @@ +#递归 Recursion + +### 递归 + +递归绝对是一个非常重要的概念。比如安利? 不断的delegate,本来想要完成1000个人的销售,找10个人,每人完成100人的,这10个人每人再去找10个人,每人完成10人的销售,这样就完成了1000人的销售(不懂安利是否这样,拿来举例)。 + + +递归之所以重要,这里面存在的概念太多了,首先上面这个例子里面就有divide and conquer的意思,把task divide小,然后来解决它。 + + +同样有趣的例子 → 吃完一个bowl of chips: + +- for loop,知道多少薯片,然后从0开始吃到最后 +- while, while 碗里还有薯片,就吃 +- 递归,吃一片,然后继续吃剩下的 N - 1 片,直到碗里的薯片数量只剩下0片了 + + +典型的例子: + +- pow(x,n) +- isPalindrome +- TowerofHanoi +- binarySearch + + + +### 链表, 树, 图 + +链表(linked list) 是数据结构的基础,而链表本身就是具有递归特性的,看C++中对于linked list node的定义, next指向本身这样的结构,就是再这个node定义还未完成之时,我们已经指向自己。 + + +``` +struct node{ + int data; + node* next; +}; +``` + +binary tree定义就是靠递归来实现的。 diff --git "a/docs/Leetcode_Solutions/Python/Summary/\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/Leetcode_Solutions/Python/Summary/\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" new file mode 100644 index 000000000..90a8924a2 --- /dev/null +++ "b/docs/Leetcode_Solutions/Python/Summary/\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" @@ -0,0 +1,3 @@ +1. The length of the given array is positive and will not exceed 20? +2. The sum of elements in the given array will not exceed 1000? +3. The output answer is guaranteed to be fitted in a 32-bit integer? diff --git a/docs/Leetcode_Solutions/ipynb/001._two_sum.ipynb b/docs/Leetcode_Solutions/ipynb/001._two_sum.ipynb new file mode 100644 index 000000000..c1fc51bf0 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/002._add_two_numbers.ipynb b/docs/Leetcode_Solutions/ipynb/002._add_two_numbers.ipynb new file mode 100644 index 000000000..7971d4200 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/005._longest_palindromic_substring.ipynb b/docs/Leetcode_Solutions/ipynb/005._longest_palindromic_substring.ipynb new file mode 100644 index 000000000..f0a71c9d4 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/007._Reverse_Integer.ipynb b/docs/Leetcode_Solutions/ipynb/007._Reverse_Integer.ipynb new file mode 100644 index 000000000..d471473d6 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/009._Palindrome_Number.ipynb b/docs/Leetcode_Solutions/ipynb/009._Palindrome_Number.ipynb new file mode 100644 index 000000000..4a643d0f0 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/010._regular_expression_matching.ipynb b/docs/Leetcode_Solutions/ipynb/010._regular_expression_matching.ipynb new file mode 100644 index 000000000..8a6af2b6e --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/013._Roman_to_Integer.ipynb b/docs/Leetcode_Solutions/ipynb/013._Roman_to_Integer.ipynb new file mode 100644 index 000000000..8ac444f28 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/020._valid_parentheses.ipynb b/docs/Leetcode_Solutions/ipynb/020._valid_parentheses.ipynb new file mode 100644 index 000000000..f665733dc --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/032._longest_valid_parentheses.ipynb b/docs/Leetcode_Solutions/ipynb/032._longest_valid_parentheses.ipynb new file mode 100644 index 000000000..56e88640c --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/053._maximum_subarray.ipynb b/docs/Leetcode_Solutions/ipynb/053._maximum_subarray.ipynb new file mode 100644 index 000000000..1bbb8ab21 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/062._unique_paths.ipynb b/docs/Leetcode_Solutions/ipynb/062._unique_paths.ipynb new file mode 100644 index 000000000..372560e09 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/064._minimum_path_sum.ipynb b/docs/Leetcode_Solutions/ipynb/064._minimum_path_sum.ipynb new file mode 100644 index 000000000..2844c4953 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/072._edit_distance.ipynb b/docs/Leetcode_Solutions/ipynb/072._edit_distance.ipynb new file mode 100644 index 000000000..9c8a9d1c8 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/139._word_break.ipynb b/docs/Leetcode_Solutions/ipynb/139._word_break.ipynb new file mode 100644 index 000000000..ffbac6d1d --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/179._Largest_Number.ipynb b/docs/Leetcode_Solutions/ipynb/179._Largest_Number.ipynb new file mode 100644 index 000000000..9ce763484 --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/242._valid_anagram.ipynb b/docs/Leetcode_Solutions/ipynb/242._valid_anagram.ipynb new file mode 100644 index 000000000..26218f62d --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/Leetcode_Solutions/ipynb/287._Find_the_Duplicate_Number.ipynb b/docs/Leetcode_Solutions/ipynb/287._Find_the_Duplicate_Number.ipynb new file mode 100644 index 000000000..62e7895dc --- /dev/null +++ b/docs/Leetcode_Solutions/ipynb/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/jianzhioffer/java/03_01_DuplicationInArray.md b/docs/jianzhioffer/java/03_01_DuplicationInArray.md deleted file mode 100644 index e8094f1de..000000000 --- a/docs/jianzhioffer/java/03_01_DuplicationInArray.md +++ /dev/null @@ -1,72 +0,0 @@ -## 找出数组中重复的数字 - -### 题目描述 -在一个长度为 `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/jianzhioffer/java/03_02_DuplicationInArrayNoEdit.md b/docs/jianzhioffer/java/03_02_DuplicationInArrayNoEdit.md deleted file mode 100644 index 5fdac9cdc..000000000 --- a/docs/jianzhioffer/java/03_02_DuplicationInArrayNoEdit.md +++ /dev/null @@ -1,86 +0,0 @@ -## 不修改数组找出重复的数字 - -### 题目描述 -在一个长度为 `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/jianzhioffer/java/04_FindInPartiallySortedMatrix.md b/docs/jianzhioffer/java/04_FindInPartiallySortedMatrix.md deleted file mode 100644 index 70ab58be7..000000000 --- a/docs/jianzhioffer/java/04_FindInPartiallySortedMatrix.md +++ /dev/null @@ -1,57 +0,0 @@ -## 二维数组中的查找 - -### 题目描述 -在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 - - -### 解法 -从二维数组的右上方开始查找: -- 若元素值等于 `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/jianzhioffer/java/05_ReplaceSpaces.md b/docs/jianzhioffer/java/05_ReplaceSpaces.md deleted file mode 100644 index eb3e00d3b..000000000 --- a/docs/jianzhioffer/java/05_ReplaceSpaces.md +++ /dev/null @@ -1,98 +0,0 @@ -## 替换空格 - -### 题目描述 -请实现一个函数,将一个字符串中的每个空格替换成 `%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/jianzhioffer/java/06_PrintListInReversedOrder.md b/docs/jianzhioffer/java/06_PrintListInReversedOrder.md deleted file mode 100644 index 60e99a538..000000000 --- a/docs/jianzhioffer/java/06_PrintListInReversedOrder.md +++ /dev/null @@ -1,110 +0,0 @@ -## 从尾到头打印链表 - -### 题目描述 -输入一个链表,按链表值从尾到头的顺序返回一个 `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/jianzhioffer/java/07_ConstructBinaryTree.md b/docs/jianzhioffer/java/07_ConstructBinaryTree.md deleted file mode 100644 index f8c824a2e..000000000 --- a/docs/jianzhioffer/java/07_ConstructBinaryTree.md +++ /dev/null @@ -1,82 +0,0 @@ -## 重建二叉树 - -### 题目描述 -输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 `{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/jianzhioffer/java/08_NextNodeInBinaryTrees.md b/docs/jianzhioffer/java/08_NextNodeInBinaryTrees.md deleted file mode 100644 index e16037ce7..000000000 --- a/docs/jianzhioffer/java/08_NextNodeInBinaryTrees.md +++ /dev/null @@ -1,74 +0,0 @@ -## 二叉树的下一个结点 - -### 题目描述 -给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 - - -### 解法 -对于结点 `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/jianzhioffer/java/09_01_QueueWithTwoStacks.md b/docs/jianzhioffer/java/09_01_QueueWithTwoStacks.md deleted file mode 100644 index 9dc32d0d2..000000000 --- a/docs/jianzhioffer/java/09_01_QueueWithTwoStacks.md +++ /dev/null @@ -1,47 +0,0 @@ -## 用两个栈实现队列 - -### 题目描述 -用两个栈来实现一个队列,完成队列的 `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/jianzhioffer/java/09_02_StackWithTwoQueues.md b/docs/jianzhioffer/java/09_02_StackWithTwoQueues.md deleted file mode 100644 index 823b8fa29..000000000 --- a/docs/jianzhioffer/java/09_02_StackWithTwoQueues.md +++ /dev/null @@ -1,55 +0,0 @@ -## 用两个队列实现栈 - -### 题目描述 -用两个队列来实现一个栈,完成栈的 `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/jianzhioffer/java/10_01_Fibonacci.md b/docs/jianzhioffer/java/10_01_Fibonacci.md deleted file mode 100644 index 31ac8b0ec..000000000 --- a/docs/jianzhioffer/java/10_01_Fibonacci.md +++ /dev/null @@ -1,79 +0,0 @@ -## 斐波那契数列 - -### 题目描述 -大家都知道斐波那契数列,现在要求输入一个整数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/jianzhioffer/java/10_02_JumpFloor.md b/docs/jianzhioffer/java/10_02_JumpFloor.md deleted file mode 100644 index 268b7c8af..000000000 --- a/docs/jianzhioffer/java/10_02_JumpFloor.md +++ /dev/null @@ -1,42 +0,0 @@ -## 跳台阶 - -### 题目描述 -一只青蛙一次可以跳上`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/jianzhioffer/java/10_03_JumpFloorII.md b/docs/jianzhioffer/java/10_03_JumpFloorII.md deleted file mode 100644 index 91f3ac3ea..000000000 --- a/docs/jianzhioffer/java/10_03_JumpFloorII.md +++ /dev/null @@ -1,48 +0,0 @@ -## 变态跳台阶 - -### 题目描述 -一只青蛙一次可以跳上`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/jianzhioffer/java/10_04_RectCover.md b/docs/jianzhioffer/java/10_04_RectCover.md deleted file mode 100644 index 07ddc850c..000000000 --- a/docs/jianzhioffer/java/10_04_RectCover.md +++ /dev/null @@ -1,73 +0,0 @@ -## 矩形覆盖 - -### 题目描述 -我们可以用`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/jianzhioffer/java/11_MinNumberInRotatedArray.md b/docs/jianzhioffer/java/11_MinNumberInRotatedArray.md deleted file mode 100644 index e8fcdad00..000000000 --- a/docs/jianzhioffer/java/11_MinNumberInRotatedArray.md +++ /dev/null @@ -1,119 +0,0 @@ -## 旋转数组的最小数字 - -### 题目描述 -把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组 `{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/jianzhioffer/java/12_StringPathInMatrix.md b/docs/jianzhioffer/java/12_StringPathInMatrix.md deleted file mode 100644 index 9a87e9e3e..000000000 --- a/docs/jianzhioffer/java/12_StringPathInMatrix.md +++ /dev/null @@ -1,66 +0,0 @@ -## 矩阵中的路径 - -### 题目描述 -请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 `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/jianzhioffer/java/13_RobotMove.md b/docs/jianzhioffer/java/13_RobotMove.md deleted file mode 100644 index 7a4e8d5ed..000000000 --- a/docs/jianzhioffer/java/13_RobotMove.md +++ /dev/null @@ -1,66 +0,0 @@ -## 机器人的移动范围 - -### 题目描述 -地上有一个`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/jianzhioffer/java/14_CuttingRope.md b/docs/jianzhioffer/java/14_CuttingRope.md deleted file mode 100644 index c120a5b78..000000000 --- a/docs/jianzhioffer/java/14_CuttingRope.md +++ /dev/null @@ -1,102 +0,0 @@ -## 剪绳子 - -### 题目描述 -给你一根长度为`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/jianzhioffer/java/15_NumberOf1InBinary.md b/docs/jianzhioffer/java/15_NumberOf1InBinary.md deleted file mode 100644 index 23bf9351a..000000000 --- a/docs/jianzhioffer/java/15_NumberOf1InBinary.md +++ /dev/null @@ -1,73 +0,0 @@ -## 二进制中 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/jianzhioffer/java/16_Power.md b/docs/jianzhioffer/java/16_Power.md deleted file mode 100644 index f1bbc09c8..000000000 --- a/docs/jianzhioffer/java/16_Power.md +++ /dev/null @@ -1,36 +0,0 @@ -## 数值的整数次方 - -### 题目描述 -给定一个 `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/jianzhioffer/java/17_Print1ToMaxOfNDigits.md b/docs/jianzhioffer/java/17_Print1ToMaxOfNDigits.md deleted file mode 100644 index 86b8e8fa3..000000000 --- a/docs/jianzhioffer/java/17_Print1ToMaxOfNDigits.md +++ /dev/null @@ -1,90 +0,0 @@ -## 打印从 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/jianzhioffer/java/18_01_DeleteNodeInList.md b/docs/jianzhioffer/java/18_01_DeleteNodeInList.md deleted file mode 100644 index fdebe01dc..000000000 --- a/docs/jianzhioffer/java/18_01_DeleteNodeInList.md +++ /dev/null @@ -1,59 +0,0 @@ -## 在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/jianzhioffer/java/18_02_DeleteDuplicatedNode.md b/docs/jianzhioffer/java/18_02_DeleteDuplicatedNode.md deleted file mode 100644 index 054e6e341..000000000 --- a/docs/jianzhioffer/java/18_02_DeleteDuplicatedNode.md +++ /dev/null @@ -1,94 +0,0 @@ -## 删除链表中重复的节点 - -### 题目描述 -在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表`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/jianzhioffer/java/19_RegularExpressionsMatching.md b/docs/jianzhioffer/java/19_RegularExpressionsMatching.md deleted file mode 100644 index 5cd4833bb..000000000 --- a/docs/jianzhioffer/java/19_RegularExpressionsMatching.md +++ /dev/null @@ -1,68 +0,0 @@ -## 正则表达式匹配 - -### 题目描述 -请实现一个函数用来匹配包括`.`和`*`的正则表达式。模式中的字符`.`表示任意一个字符,而`*`表示它前面的字符可以出现任意次(包含`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/jianzhioffer/java/20_NumericStrings.md b/docs/jianzhioffer/java/20_NumericStrings.md deleted file mode 100644 index 55fa620c8..000000000 --- a/docs/jianzhioffer/java/20_NumericStrings.md +++ /dev/null @@ -1,115 +0,0 @@ -## 表示数值的字符串 - -### 题目描述 -请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+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/jianzhioffer/java/21_ReorderArray.md b/docs/jianzhioffer/java/21_ReorderArray.md deleted file mode 100644 index a4730a321..000000000 --- a/docs/jianzhioffer/java/21_ReorderArray.md +++ /dev/null @@ -1,68 +0,0 @@ -## 调整数组顺序使奇数位于偶数前面 - -### 题目描述 -输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 - -### 解法 -#### 解法一 -计算出奇数的个数,就很容易写出来了。 - -```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/jianzhioffer/java/22_KthNodeFromEnd.md b/docs/jianzhioffer/java/22_KthNodeFromEnd.md deleted file mode 100644 index 2e54c99e4..000000000 --- a/docs/jianzhioffer/java/22_KthNodeFromEnd.md +++ /dev/null @@ -1,61 +0,0 @@ -## 链表中倒数第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/jianzhioffer/java/23_EntryNodeInListLoop.md b/docs/jianzhioffer/java/23_EntryNodeInListLoop.md deleted file mode 100644 index 262cd9f58..000000000 --- a/docs/jianzhioffer/java/23_EntryNodeInListLoop.md +++ /dev/null @@ -1,83 +0,0 @@ -## 链表中环的入口结点 - -### 题目描述 -给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出`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/jianzhioffer/java/24_ReverseList.md b/docs/jianzhioffer/java/24_ReverseList.md deleted file mode 100644 index 118d65874..000000000 --- a/docs/jianzhioffer/java/24_ReverseList.md +++ /dev/null @@ -1,94 +0,0 @@ -## 反转链表 - -### 题目描述 -输入一个链表,反转链表后,输出新链表的表头。 - -### 解法 -#### 解法一 -利用头插法解决。 - -```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/jianzhioffer/java/25_MergeSortedLists.md b/docs/jianzhioffer/java/25_MergeSortedLists.md deleted file mode 100644 index 9bcc3c7b0..000000000 --- a/docs/jianzhioffer/java/25_MergeSortedLists.md +++ /dev/null @@ -1,112 +0,0 @@ -## 合并两个排序的链表 - -### 题目描述 -输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 - -### 解法 -#### 解法一 -同时遍历两链表进行 `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/jianzhioffer/java/26_SubstructureInTree.md b/docs/jianzhioffer/java/26_SubstructureInTree.md deleted file mode 100644 index 24b852e96..000000000 --- a/docs/jianzhioffer/java/26_SubstructureInTree.md +++ /dev/null @@ -1,69 +0,0 @@ -## 树的子结构 - -### 题目描述 -输入两棵二叉树`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/jianzhioffer/java/27_MirrorOfBinaryTree.md b/docs/jianzhioffer/java/27_MirrorOfBinaryTree.md deleted file mode 100644 index 8e036d5c2..000000000 --- a/docs/jianzhioffer/java/27_MirrorOfBinaryTree.md +++ /dev/null @@ -1,70 +0,0 @@ -## 二叉树的镜像 - -### 题目描述 -操作给定的二叉树,将其变换为源二叉树的镜像。 - -``` -源二叉树 - 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/jianzhioffer/java/28_SymmetricalBinaryTree.md b/docs/jianzhioffer/java/28_SymmetricalBinaryTree.md deleted file mode 100644 index 6b13edefe..000000000 --- a/docs/jianzhioffer/java/28_SymmetricalBinaryTree.md +++ /dev/null @@ -1,58 +0,0 @@ -## 对称的二叉树 - -### 题目描述 -请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。 - -### 解法 -比较二叉树的前序遍历序列和对称前序遍历序列是否一样,若是,说明是对称的。 - -```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/jianzhioffer/java/29_PrintMatrix.md b/docs/jianzhioffer/java/29_PrintMatrix.md deleted file mode 100644 index e47e18c89..000000000 --- a/docs/jianzhioffer/java/29_PrintMatrix.md +++ /dev/null @@ -1,103 +0,0 @@ -## 顺时针打印矩阵 - -### 题目描述 -输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下 `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/jianzhioffer/java/30_MinInStack.md b/docs/jianzhioffer/java/30_MinInStack.md deleted file mode 100644 index 38353b273..000000000 --- a/docs/jianzhioffer/java/30_MinInStack.md +++ /dev/null @@ -1,63 +0,0 @@ -## 包含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/jianzhioffer/java/31_StackPushPopOrder.md b/docs/jianzhioffer/java/31_StackPushPopOrder.md deleted file mode 100644 index 3b2a5e590..000000000 --- a/docs/jianzhioffer/java/31_StackPushPopOrder.md +++ /dev/null @@ -1,58 +0,0 @@ -## 栈的压入、弹出序列 - -### 题目描述 -输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列`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/jianzhioffer/java/32_01_PrintTreeFromTopToBottom.md b/docs/jianzhioffer/java/32_01_PrintTreeFromTopToBottom.md deleted file mode 100644 index c93a997e5..000000000 --- a/docs/jianzhioffer/java/32_01_PrintTreeFromTopToBottom.md +++ /dev/null @@ -1,64 +0,0 @@ -## 不分行从上到下打印二叉树 - -### 题目描述 -从上往下打印出二叉树的每个节点,同层节点从左至右打印。 - -### 解法 -先将根节点进入队列。 - -队头元素出队,将值存入 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/jianzhioffer/java/32_02_PrintTreesInLines.md b/docs/jianzhioffer/java/32_02_PrintTreesInLines.md deleted file mode 100644 index 4904948ff..000000000 --- a/docs/jianzhioffer/java/32_02_PrintTreesInLines.md +++ /dev/null @@ -1,73 +0,0 @@ -## 把二叉树打印成多行 - -### 题目描述 -从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。 - -### 解法 -与上一题类似,只不过需要用变量记录每一层要打印多少个节点。 - -```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/jianzhioffer/java/32_03_PrintTreesInZigzag.md b/docs/jianzhioffer/java/32_03_PrintTreesInZigzag.md deleted file mode 100644 index 538f10c0a..000000000 --- a/docs/jianzhioffer/java/32_03_PrintTreesInZigzag.md +++ /dev/null @@ -1,104 +0,0 @@ -## 按之字形打印二叉树 - -### 题目描述 -请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。 - -如二叉树: -``` - 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/jianzhioffer/java/33_SquenceOfBST.md b/docs/jianzhioffer/java/33_SquenceOfBST.md deleted file mode 100644 index 4d99624f8..000000000 --- a/docs/jianzhioffer/java/33_SquenceOfBST.md +++ /dev/null @@ -1,60 +0,0 @@ -## 二叉搜索树的后序遍历序列 - -### 题目描述 -输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出`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/jianzhioffer/java/34_PathInTree.md b/docs/jianzhioffer/java/34_PathInTree.md deleted file mode 100644 index d4dfc62a6..000000000 --- a/docs/jianzhioffer/java/34_PathInTree.md +++ /dev/null @@ -1,64 +0,0 @@ -## 二叉树中和为某一值的路径 - -### 题目描述 -输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的`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/jianzhioffer/java/35_CopyComplexList.md b/docs/jianzhioffer/java/35_CopyComplexList.md deleted file mode 100644 index 762e595c8..000000000 --- a/docs/jianzhioffer/java/35_CopyComplexList.md +++ /dev/null @@ -1,73 +0,0 @@ -## 复杂链表的复制 - -### 题目描述 -输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的 `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/jianzhioffer/java/36_ConvertBinarySearchTree.md b/docs/jianzhioffer/java/36_ConvertBinarySearchTree.md deleted file mode 100644 index d80076e29..000000000 --- a/docs/jianzhioffer/java/36_ConvertBinarySearchTree.md +++ /dev/null @@ -1,76 +0,0 @@ -## 二叉搜索树与双向链表 - -### 题目描述 -输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 - -### 解法 -由于是二叉搜索树,因此中序遍历的结果就是排序的。 - -中序遍历利用栈来实现。遍历时,前一个结点的 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/jianzhioffer/java/37_SerializeBinaryTrees.md b/docs/jianzhioffer/java/37_SerializeBinaryTrees.md deleted file mode 100644 index e9795c2f3..000000000 --- a/docs/jianzhioffer/java/37_SerializeBinaryTrees.md +++ /dev/null @@ -1,89 +0,0 @@ -## 序列化二叉树 - -### 题目描述 -请实现两个函数,分别用来序列化和反序列化二叉树。使用前序遍历实现,空节点使用字符`#` 表示。 - -比如有如下二叉树: - -```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/jianzhioffer/java/38_StringPermutation.md b/docs/jianzhioffer/java/38_StringPermutation.md deleted file mode 100644 index b603cb511..000000000 --- a/docs/jianzhioffer/java/38_StringPermutation.md +++ /dev/null @@ -1,74 +0,0 @@ -## 字符串的排列 - -### 题目描述 -输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串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/jianzhioffer/java/39_MoreThanHalfNumber.md b/docs/jianzhioffer/java/39_MoreThanHalfNumber.md deleted file mode 100644 index a256e5abe..000000000 --- a/docs/jianzhioffer/java/39_MoreThanHalfNumber.md +++ /dev/null @@ -1,162 +0,0 @@ -## 数组中出现次数超过一半的数字 - -### 题目描述 -数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为 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/jianzhioffer/java/40_KLeastNumbers.md b/docs/jianzhioffer/java/40_KLeastNumbers.md deleted file mode 100644 index 645478a08..000000000 --- a/docs/jianzhioffer/java/40_KLeastNumbers.md +++ /dev/null @@ -1,132 +0,0 @@ -## 获取数组中最小的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/jianzhioffer/java/41_StreamMedian.md b/docs/jianzhioffer/java/41_StreamMedian.md deleted file mode 100644 index f3e3ce8ed..000000000 --- a/docs/jianzhioffer/java/41_StreamMedian.md +++ /dev/null @@ -1,67 +0,0 @@ -## 数据流中的中位数 - -### 题目描述 -如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用`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/jianzhioffer/java/42_GreatestSumOfSubarrays.md b/docs/jianzhioffer/java/42_GreatestSumOfSubarrays.md deleted file mode 100644 index e5a2d99c6..000000000 --- a/docs/jianzhioffer/java/42_GreatestSumOfSubarrays.md +++ /dev/null @@ -1,49 +0,0 @@ -## 连续子数组的最大和 - -### 题目描述 -输入一个**非空**整型数组,数组里的数可能为正,也可能为负。 -数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。 - -要求时间复杂度为`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/jianzhioffer/java/43_NumberOf1.md b/docs/jianzhioffer/java/43_NumberOf1.md deleted file mode 100644 index 27352aafc..000000000 --- a/docs/jianzhioffer/java/43_NumberOf1.md +++ /dev/null @@ -1,66 +0,0 @@ -## 整数中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/jianzhioffer/java/44_DigitsInSequence.md b/docs/jianzhioffer/java/44_DigitsInSequence.md deleted file mode 100644 index 427f37445..000000000 --- a/docs/jianzhioffer/java/44_DigitsInSequence.md +++ /dev/null @@ -1,71 +0,0 @@ -## 数字序列中某一位的数字 - -### 题目描述 -数字以 `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/jianzhioffer/java/45_SortArrayForMinNumber.md b/docs/jianzhioffer/java/45_SortArrayForMinNumber.md deleted file mode 100644 index b563cb46e..000000000 --- a/docs/jianzhioffer/java/45_SortArrayForMinNumber.md +++ /dev/null @@ -1,50 +0,0 @@ -## 把数组排成最小的数 - -### 题目描述 -输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。 - -例如输入数组 `[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/jianzhioffer/java/46_TranslateNumbersToStrings.md b/docs/jianzhioffer/java/46_TranslateNumbersToStrings.md deleted file mode 100644 index 759b1f9c3..000000000 --- a/docs/jianzhioffer/java/46_TranslateNumbersToStrings.md +++ /dev/null @@ -1,56 +0,0 @@ -## 把数字翻译成字符串 - -### 题目描述 -给定一个数字,我们按照如下规则把它翻译为字符串: - -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/jianzhioffer/java/47_MaxValueOfGifts.md b/docs/jianzhioffer/java/47_MaxValueOfGifts.md deleted file mode 100644 index 8af6ff5b2..000000000 --- a/docs/jianzhioffer/java/47_MaxValueOfGifts.md +++ /dev/null @@ -1,57 +0,0 @@ -## 礼物的最大价值 - -### 题目描述 -在一个 `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/jianzhioffer/java/48_LongestSubstringWithoutDup.md b/docs/jianzhioffer/java/48_LongestSubstringWithoutDup.md deleted file mode 100644 index 0012f287b..000000000 --- a/docs/jianzhioffer/java/48_LongestSubstringWithoutDup.md +++ /dev/null @@ -1,63 +0,0 @@ -## 最长不含重复字符的子字符串 - -### 题目描述 -请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 - -假设字符串中只包含从 `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/jianzhioffer/java/49_UglyNumber.md b/docs/jianzhioffer/java/49_UglyNumber.md deleted file mode 100644 index bec37fd34..000000000 --- a/docs/jianzhioffer/java/49_UglyNumber.md +++ /dev/null @@ -1,106 +0,0 @@ -## 丑数 - -### 题目描述 -把只包含质因子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/jianzhioffer/java/50_01_FirstNotRepeatingChar.md b/docs/jianzhioffer/java/50_01_FirstNotRepeatingChar.md deleted file mode 100644 index ebf2baeb5..000000000 --- a/docs/jianzhioffer/java/50_01_FirstNotRepeatingChar.md +++ /dev/null @@ -1,43 +0,0 @@ -## 第一个只出现一次的字符 - -### 题目描述 -在一个字符串(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/jianzhioffer/java/50_02_FristCharacterInStream.md b/docs/jianzhioffer/java/50_02_FristCharacterInStream.md deleted file mode 100644 index 2d67dbcca..000000000 --- a/docs/jianzhioffer/java/50_02_FristCharacterInStream.md +++ /dev/null @@ -1,45 +0,0 @@ -## 字符流中第一个不重复的字符 - -### 题目描述 - -请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"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/jianzhioffer/java/52_FirstCommonNodesInLists.md b/docs/jianzhioffer/java/52_FirstCommonNodesInLists.md deleted file mode 100644 index 78fe0068b..000000000 --- a/docs/jianzhioffer/java/52_FirstCommonNodesInLists.md +++ /dev/null @@ -1,86 +0,0 @@ -## 两个链表的第一个公共结点 - -### 题目描述 -输入两个链表,找出它们的第一个公共结点。 - -**样例** -``` -给出两个链表如下所示: -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/jianzhioffer/java/53_01_NumberOfK.md b/docs/jianzhioffer/java/53_01_NumberOfK.md deleted file mode 100644 index 76cb7d228..000000000 --- a/docs/jianzhioffer/java/53_01_NumberOfK.md +++ /dev/null @@ -1,99 +0,0 @@ -## 数字在排序数组中出现的次数 - -### 题目描述 -统计一个数字在排序数组中出现的次数。 - -例如输入排序数组 `[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/jianzhioffer/java/53_02_MissingNumber.md b/docs/jianzhioffer/java/53_02_MissingNumber.md deleted file mode 100644 index ab3f8db5b..000000000 --- a/docs/jianzhioffer/java/53_02_MissingNumber.md +++ /dev/null @@ -1,62 +0,0 @@ -## 0到n-1中缺失的数字 - -### 题目描述 -一个长度为 `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/jianzhioffer/java/53_03_IntegerIdenticalToIndex.md b/docs/jianzhioffer/java/53_03_IntegerIdenticalToIndex.md deleted file mode 100644 index 6ea63a4a4..000000000 --- a/docs/jianzhioffer/java/53_03_IntegerIdenticalToIndex.md +++ /dev/null @@ -1,63 +0,0 @@ -## 数组中数值和下标相等的元素 - -### 题目描述 -假设一个单调递增的数组里的每个元素都是整数并且是唯一的。 - -请编程实现一个函数找出数组中任意一个数值等于其下标的元素。 - -例如,在数组 `[-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/jianzhioffer/java/54_KthNodeInBST.md b/docs/jianzhioffer/java/54_KthNodeInBST.md deleted file mode 100644 index be0bc7996..000000000 --- a/docs/jianzhioffer/java/54_KthNodeInBST.md +++ /dev/null @@ -1,54 +0,0 @@ -## 二叉搜索树的第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/jianzhioffer/java/55_01_TreeDepth.md b/docs/jianzhioffer/java/55_01_TreeDepth.md deleted file mode 100644 index 99797309c..000000000 --- a/docs/jianzhioffer/java/55_01_TreeDepth.md +++ /dev/null @@ -1,59 +0,0 @@ -## 二叉树的深度 - -### 题目描述 -输入一棵二叉树的根结点,求该树的深度。 - -从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 - -**样例** -``` -输入:二叉树[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/jianzhioffer/java/55_02_BalancedBinaryTree.md b/docs/jianzhioffer/java/55_02_BalancedBinaryTree.md deleted file mode 100644 index 521e1ceb7..000000000 --- a/docs/jianzhioffer/java/55_02_BalancedBinaryTree.md +++ /dev/null @@ -1,127 +0,0 @@ -## 平衡二叉树 - -### 题目描述 -输入一棵二叉树的根结点,判断该树是不是平衡二叉树。 - -如果某二叉树中任意结点的左右子树的深度相差不超过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/jianzhioffer/java/56_01_NumbersAppearOnce.md b/docs/jianzhioffer/java/56_01_NumbersAppearOnce.md deleted file mode 100644 index 1576feee2..000000000 --- a/docs/jianzhioffer/java/56_01_NumbersAppearOnce.md +++ /dev/null @@ -1,77 +0,0 @@ -## 数组中只出现一次的两个数字 - -### 题目描述 -一个整型数组里除了两个数字之外,其他的数字都出现了两次。 - -请写程序找出这两个只出现一次的数字。 - -你可以假设这两个数字一定存在。 - -**样例** -``` -输入:[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/jianzhioffer/java/56_02_NumberAppearingOnce.md b/docs/jianzhioffer/java/56_02_NumberAppearingOnce.md deleted file mode 100644 index f6e101c3c..000000000 --- a/docs/jianzhioffer/java/56_02_NumberAppearingOnce.md +++ /dev/null @@ -1,55 +0,0 @@ -## 数组中唯一只出现一次的数字 - -### 题目描述 -在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。 - -请找出那个只出现一次的数字。 - -你可以假设满足条件的数字一定存在。 - -**思考题:** - -- 如果要求只使用 `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/jianzhioffer/java/57_01_TwoNumbersWithSum.md b/docs/jianzhioffer/java/57_01_TwoNumbersWithSum.md deleted file mode 100644 index 0b4770178..000000000 --- a/docs/jianzhioffer/java/57_01_TwoNumbersWithSum.md +++ /dev/null @@ -1,55 +0,0 @@ -## 和为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/jianzhioffer/java/57_02_ContinuousSquenceWithSum.md b/docs/jianzhioffer/java/57_02_ContinuousSquenceWithSum.md deleted file mode 100644 index c837b5875..000000000 --- a/docs/jianzhioffer/java/57_02_ContinuousSquenceWithSum.md +++ /dev/null @@ -1,77 +0,0 @@ -## 和为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/jianzhioffer/java/58_01_ReverseWordsInSentence.md b/docs/jianzhioffer/java/58_01_ReverseWordsInSentence.md deleted file mode 100644 index 87f557479..000000000 --- a/docs/jianzhioffer/java/58_01_ReverseWordsInSentence.md +++ /dev/null @@ -1,55 +0,0 @@ -## 翻转单词顺序 - -### 题目描述 -输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。 - -为简单起见,标点符号和普通字母一样处理。 - -例如输入字符串 `"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/jianzhioffer/java/58_02_LeftRotateString.md b/docs/jianzhioffer/java/58_02_LeftRotateString.md deleted file mode 100644 index e78dc16bd..000000000 --- a/docs/jianzhioffer/java/58_02_LeftRotateString.md +++ /dev/null @@ -1,67 +0,0 @@ -## 左旋转字符串 - -### 题目描述 -字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。 - -请定义一个函数实现字符串左旋转操作的功能。 - -比如输入字符串 `"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/jianzhioffer/java/59_01_MaxInSlidingWindow.md b/docs/jianzhioffer/java/59_01_MaxInSlidingWindow.md deleted file mode 100644 index f568e9b30..000000000 --- a/docs/jianzhioffer/java/59_01_MaxInSlidingWindow.md +++ /dev/null @@ -1,75 +0,0 @@ -## 滑动窗口的最大值 - -### 题目描述 -给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。 - -例如,如果输入数组 `[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/jianzhioffer/java/61_ContinousCards.md b/docs/jianzhioffer/java/61_ContinousCards.md deleted file mode 100644 index 9ff94a437..000000000 --- a/docs/jianzhioffer/java/61_ContinousCards.md +++ /dev/null @@ -1,78 +0,0 @@ -## 扑克牌的顺子 - -### 题目描述 -从扑克牌中随机抽 `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/jianzhioffer/java/README.md b/docs/jianzhioffer/java/README.md deleted file mode 100644 index a7e31d6e0..000000000 --- a/docs/jianzhioffer/java/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# 剑指 Offer Java 题解 - -> 来源:[《剑指 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/jianzhioffer/java/SUMMARY.md b/docs/jianzhioffer/java/SUMMARY.md deleted file mode 100644 index 528c38641..000000000 --- a/docs/jianzhioffer/java/SUMMARY.md +++ /dev/null @@ -1,73 +0,0 @@ -+ [剑指 Offer Java 题解](README.md) -+ [找出数组中重复的数字](03_01_DuplicationInArray.md) -+ [不修改数组找出重复的数字](03_02_DuplicationInArrayNoEdit.md) -+ [二维数组中的查找](04_FindInPartiallySortedMatrix.md) -+ [替换空格](05_ReplaceSpaces.md) -+ [从尾到头打印链表](06_PrintListInReversedOrder.md) -+ [重建二叉树](07_ConstructBinaryTree.md) -+ [二叉树的下一个结点](08_NextNodeInBinaryTrees.md) -+ [用两个栈实现队列](09_01_QueueWithTwoStacks.md) -+ [用两个队列实现栈](09_02_StackWithTwoQueues.md) -+ [斐波那契数列](10_01_Fibonacci.md) -+ [跳台阶](10_02_JumpFloor.md) -+ [变态跳台阶](10_03_JumpFloorII.md) -+ [矩形覆盖](10_04_RectCover.md) -+ [旋转数组的最小数字](11_MinNumberInRotatedArray.md) -+ [矩阵中的路径](12_StringPathInMatrix.md) -+ [机器人的移动范围](13_RobotMove.md) -+ [剪绳子](14_CuttingRope.md) -+ [二进制中 1 的个数](15_NumberOf1InBinary.md) -+ [数值的整数次方](16_Power.md) -+ [打印从 1 到最大的 n 位数](17_Print1ToMaxOfNDigits.md) -+ [在O(1)时间内删除链表节点](18_01_DeleteNodeInList.md) -+ [删除链表中重复的节点](18_02_DeleteDuplicatedNode.md) -+ [正则表达式匹配](19_RegularExpressionsMatching.md) -+ [表示数值的字符串](20_NumericStrings.md) -+ [调整数组顺序使奇数位于偶数前面](21_ReorderArray.md) -+ [链表中倒数第k个结点](22_KthNodeFromEnd.md) -+ [链表中环的入口结点](23_EntryNodeInListLoop.md) -+ [反转链表](24_ReverseList.md) -+ [合并两个排序的链表](25_MergeSortedLists.md) -+ [树的子结构](26_SubstructureInTree.md) -+ [二叉树的镜像](27_MirrorOfBinaryTree.md) -+ [对称的二叉树](28_SymmetricalBinaryTree.md) -+ [顺时针打印矩阵](29_PrintMatrix.md) -+ [包含min函数的栈](30_MinInStack.md) -+ [栈的压入、弹出序列](31_StackPushPopOrder.md) -+ [不分行从上到下打印二叉树](32_01_PrintTreeFromTopToBottom.md) -+ [把二叉树打印成多行](32_02_PrintTreesInLines.md) -+ [按之字形打印二叉树](32_03_PrintTreesInZigzag.md) -+ [二叉搜索树的后序遍历序列](33_SquenceOfBST.md) -+ [二叉树中和为某一值的路径](34_PathInTree.md) -+ [复杂链表的复制](35_CopyComplexList.md) -+ [二叉搜索树与双向链表](36_ConvertBinarySearchTree.md) -+ [序列化二叉树](37_SerializeBinaryTrees.md) -+ [字符串的排列](38_StringPermutation.md) -+ [数组中出现次数超过一半的数字](39_MoreThanHalfNumber.md) -+ [获取数组中最小的k个数](40_KLeastNumbers.md) -+ [数据流中的中位数](41_StreamMedian.md) -+ [连续子数组的最大和](42_GreatestSumOfSubarrays.md) -+ [整数中1出现的次数](43_NumberOf1.md) -+ [数字序列中某一位的数字](44_DigitsInSequence.md) -+ [把数组排成最小的数](45_SortArrayForMinNumber.md) -+ [把数字翻译成字符串](46_TranslateNumbersToStrings.md) -+ [礼物的最大价值](47_MaxValueOfGifts.md) -+ [最长不含重复字符的子字符串](48_LongestSubstringWithoutDup.md) -+ [丑数](49_UglyNumber.md) -+ [第一个只出现一次的字符](50_01_FirstNotRepeatingChar.md) -+ [字符流中第一个不重复的字符](50_02_FristCharacterInStream.md) -+ [两个链表的第一个公共结点](52_FirstCommonNodesInLists.md) -+ [数字在排序数组中出现的次数](53_01_NumberOfK.md) -+ [0到n-1中缺失的数字](53_02_MissingNumber.md) -+ [数组中数值和下标相等的元素](53_03_IntegerIdenticalToIndex.md) -+ [二叉搜索树的第k个结点](54_KthNodeInBST.md) -+ [二叉树的深度](55_01_TreeDepth.md) -+ [平衡二叉树](55_02_BalancedBinaryTree.md) -+ [数组中只出现一次的两个数字](56_01_NumbersAppearOnce.md) -+ [数组中唯一只出现一次的数字](56_02_NumberAppearingOnce.md) -+ [和为S的两个数字](57_01_TwoNumbersWithSum.md) -+ [和为S的连续正数序列](57_02_ContinuousSquenceWithSum.md) -+ [翻转单词顺序](58_01_ReverseWordsInSentence.md) -+ [左旋转字符串](58_02_LeftRotateString.md) -+ [滑动窗口的最大值](59_01_MaxInSlidingWindow.md) -+ [扑克牌的顺子](61_ContinousCards.md) diff --git a/docs/leetcode/cpp/0002._Add_Two_Numbers.md b/docs/leetcode/cpp/0002._Add_Two_Numbers.md deleted file mode 100644 index 728077ac6..000000000 --- a/docs/leetcode/cpp/0002._Add_Two_Numbers.md +++ /dev/null @@ -1,70 +0,0 @@ -# 2. Add Two Numbers - -**难度:Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/add-two-numbers - -> 内容描述 - -``` -给定两个链表代表两个非负数,求这两个数的和 -(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/leetcode/cpp/0003._Longest_Substring_Without_Repeating_Characters.md b/docs/leetcode/cpp/0003._Longest_Substring_Without_Repeating_Characters.md deleted file mode 100644 index 983bad57c..000000000 --- a/docs/leetcode/cpp/0003._Longest_Substring_Without_Repeating_Characters.md +++ /dev/null @@ -1,97 +0,0 @@ -# 3. 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(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/leetcode/cpp/0004._Median_of_Two_Sorted_Arrays.md b/docs/leetcode/cpp/0004._Median_of_Two_Sorted_Arrays.md deleted file mode 100644 index be2f433bb..000000000 --- a/docs/leetcode/cpp/0004._Median_of_Two_Sorted_Arrays.md +++ /dev/null @@ -1,159 +0,0 @@ -# 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/leetcode/cpp/0005._Longest_Palindromic_Substring.md b/docs/leetcode/cpp/0005._Longest_Palindromic_Substring.md deleted file mode 100644 index b535fbe5d..000000000 --- a/docs/leetcode/cpp/0005._Longest_Palindromic_Substring.md +++ /dev/null @@ -1,64 +0,0 @@ -# 5. Longest Palindromic Substring - -**难度:Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/longest-palindromic-substring - -> 内容描述 - -``` -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/leetcode/cpp/0006._ZigZag_Conversion.md b/docs/leetcode/cpp/0006._ZigZag_Conversion.md deleted file mode 100644 index 6cbbc25c6..000000000 --- a/docs/leetcode/cpp/0006._ZigZag_Conversion.md +++ /dev/null @@ -1,96 +0,0 @@ -# 6. ZigZag Conversion - -**难度:Medium** - -## 刷题内容 - -> 原题连接 - -*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 -******- 时间复杂度: 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/leetcode/cpp/0007._Reverse_Integer.md b/docs/leetcode/cpp/0007._Reverse_Integer.md deleted file mode 100644 index 296913158..000000000 --- a/docs/leetcode/cpp/0007._Reverse_Integer.md +++ /dev/null @@ -1,50 +0,0 @@ -# 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/leetcode/cpp/0008._String_to_Integer_(atoi).md b/docs/leetcode/cpp/0008._String_to_Integer_(atoi).md deleted file mode 100644 index 66c9454fa..000000000 --- a/docs/leetcode/cpp/0008._String_to_Integer_(atoi).md +++ /dev/null @@ -1,104 +0,0 @@ -# 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���͵����ּ��ɣ������������������ģ����Ҫע��߽�ֵ���ж����ֵ�����������Ϊ�����Ч�ʡ��ȼ�����10��32�η���10��n�η���ֵ�� - -```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/leetcode/cpp/0009._Palindrome_Number.md b/docs/leetcode/cpp/0009._Palindrome_Number.md deleted file mode 100644 index 788beb123..000000000 --- a/docs/leetcode/cpp/0009._Palindrome_Number.md +++ /dev/null @@ -1,102 +0,0 @@ -# 9. Palindrome Number - -**难度:Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/palindrome-number -* -> 内容描述 - -``` -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 - -> 内容描述 - -``` -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/leetcode/cpp/0011._Container_With_Most_Water.md b/docs/leetcode/cpp/0011._Container_With_Most_Water.md deleted file mode 100644 index 1a610d4da..000000000 --- a/docs/leetcode/cpp/0011._Container_With_Most_Water.md +++ /dev/null @@ -1,41 +0,0 @@ -# 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/leetcode/cpp/0012._Integer_to_Roman.md b/docs/leetcode/cpp/0012._Integer_to_Roman.md deleted file mode 100644 index e646d8a4c..000000000 --- a/docs/leetcode/cpp/0012._Integer_to_Roman.md +++ /dev/null @@ -1,164 +0,0 @@ -# 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 else���IJ��ÿ������ǿ��Ի�һ�ָ����ŵ�д�����ô�����ÿ��� - -```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/leetcode/cpp/0014._Longest_Common_Prefix.md b/docs/leetcode/cpp/0014._Longest_Common_Prefix.md deleted file mode 100644 index d87e89f1d..000000000 --- a/docs/leetcode/cpp/0014._Longest_Common_Prefix.md +++ /dev/null @@ -1,58 +0,0 @@ -# 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/leetcode/cpp/0015._3sum.md b/docs/leetcode/cpp/0015._3sum.md deleted file mode 100644 index bbcbb74e8..000000000 --- a/docs/leetcode/cpp/0015._3sum.md +++ /dev/null @@ -1,61 +0,0 @@ -# 15. 3sum - -**难度:Medium** - -## 刷题内容 - -> 原题连接 - -*https://leetcode.com/problems/3sum -* -> 内容描述 - -``` -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/leetcode/cpp/0016._3Sum_Closest.md b/docs/leetcode/cpp/0016._3Sum_Closest.md deleted file mode 100644 index 496ac062c..000000000 --- a/docs/leetcode/cpp/0016._3Sum_Closest.md +++ /dev/null @@ -1,45 +0,0 @@ -## 16. 3Sum Closest - -难度:Medium - -## 内容 - -> 原题链接:https://leetcode.com/problems/3sum-closest - -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/leetcode/cpp/0017._Letter_Combinations_of_a_Phone_Number.md b/docs/leetcode/cpp/0017._Letter_Combinations_of_a_Phone_Number.md deleted file mode 100644 index d7a240e85..000000000 --- a/docs/leetcode/cpp/0017._Letter_Combinations_of_a_Phone_Number.md +++ /dev/null @@ -1,68 +0,0 @@ -# 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)****** - -�û��ݷ�ȥ�⣬�Ƚ������ַ���ת�����֡�����7��9֮����������ֶ���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/leetcode/cpp/0018._4Sum.md b/docs/leetcode/cpp/0018._4Sum.md deleted file mode 100644 index c3e0db2cb..000000000 --- a/docs/leetcode/cpp/0018._4Sum.md +++ /dev/null @@ -1,57 +0,0 @@ -## 18. 4Sum - -难度:Medium - -## 内容 - -题目链接:https://leetcode.com/problems/4sum - -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/leetcode/cpp/0019._Remove_Nth_Node_From_End_of_List.md b/docs/leetcode/cpp/0019._Remove_Nth_Node_From_End_of_List.md deleted file mode 100644 index 2c1fc990f..000000000 --- a/docs/leetcode/cpp/0019._Remove_Nth_Node_From_End_of_List.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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/leetcode/cpp/0020._Valid_Parentheses.md b/docs/leetcode/cpp/0020._Valid_Parentheses.md deleted file mode 100644 index 102c66ca6..000000000 --- a/docs/leetcode/cpp/0020._Valid_Parentheses.md +++ /dev/null @@ -1,55 +0,0 @@ -## 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 -* -> 内容描述 - -``` -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/leetcode/cpp/0022._Generate_Parentheses.md b/docs/leetcode/cpp/0022._Generate_Parentheses.md deleted file mode 100644 index 469322c3a..000000000 --- a/docs/leetcode/cpp/0022._Generate_Parentheses.md +++ /dev/null @@ -1,50 +0,0 @@ -# 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/leetcode/cpp/0023._Merge_K_Sorted_Lists.md b/docs/leetcode/cpp/0023._Merge_K_Sorted_Lists.md deleted file mode 100644 index bddfa6bb4..000000000 --- a/docs/leetcode/cpp/0023._Merge_K_Sorted_Lists.md +++ /dev/null @@ -1,125 +0,0 @@ -# 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/leetcode/cpp/0024._Swap_Nodes_in_Pairs.md b/docs/leetcode/cpp/0024._Swap_Nodes_in_Pairs.md deleted file mode 100644 index 4e812adab..000000000 --- a/docs/leetcode/cpp/0024._Swap_Nodes_in_Pairs.md +++ /dev/null @@ -1,53 +0,0 @@ -# 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/leetcode/cpp/0025._Reverse_Nodes_In_K_Group.md b/docs/leetcode/cpp/0025._Reverse_Nodes_In_K_Group.md deleted file mode 100644 index cdc28074c..000000000 --- a/docs/leetcode/cpp/0025._Reverse_Nodes_In_K_Group.md +++ /dev/null @@ -1,76 +0,0 @@ -# 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/leetcode/cpp/0027._Remove_Element.md b/docs/leetcode/cpp/0027._Remove_Element.md deleted file mode 100644 index 30694b543..000000000 --- a/docs/leetcode/cpp/0027._Remove_Element.md +++ /dev/null @@ -1,73 +0,0 @@ -# 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/leetcode/cpp/0028._Implement_Strstr.md b/docs/leetcode/cpp/0028._Implement_Strstr.md deleted file mode 100644 index b80786a76..000000000 --- a/docs/leetcode/cpp/0028._Implement_Strstr.md +++ /dev/null @@ -1,61 +0,0 @@ -# 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/leetcode/cpp/0029._Divide_Two_Integers.md b/docs/leetcode/cpp/0029._Divide_Two_Integers.md deleted file mode 100644 index 432bb349a..000000000 --- a/docs/leetcode/cpp/0029._Divide_Two_Integers.md +++ /dev/null @@ -1,80 +0,0 @@ -# 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)��ʼ��ֱ��ij��res + 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/leetcode/cpp/0030._Substring_With_Concatenation_Of_All_Words.md b/docs/leetcode/cpp/0030._Substring_With_Concatenation_Of_All_Words.md deleted file mode 100644 index 52efa1f10..000000000 --- a/docs/leetcode/cpp/0030._Substring_With_Concatenation_Of_All_Words.md +++ /dev/null @@ -1,64 +0,0 @@ -# 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/leetcode/cpp/0031._Next_Permutatio.md b/docs/leetcode/cpp/0031._Next_Permutatio.md deleted file mode 100644 index 5266def01..000000000 --- a/docs/leetcode/cpp/0031._Next_Permutatio.md +++ /dev/null @@ -1,64 +0,0 @@ -# 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/leetcode/cpp/0032._Longest_Valid_Parentheses.md b/docs/leetcode/cpp/0032._Longest_Valid_Parentheses.md deleted file mode 100644 index dfa13eae0..000000000 --- a/docs/leetcode/cpp/0032._Longest_Valid_Parentheses.md +++ /dev/null @@ -1,57 +0,0 @@ -# 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/leetcode/cpp/0033._Search_in_Rotated_Sorted_Array.md b/docs/leetcode/cpp/0033._Search_in_Rotated_Sorted_Array.md deleted file mode 100644 index 275307b05..000000000 --- a/docs/leetcode/cpp/0033._Search_in_Rotated_Sorted_Array.md +++ /dev/null @@ -1,80 +0,0 @@ -# 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/leetcode/cpp/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md b/docs/leetcode/cpp/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md deleted file mode 100644 index 27a9b7bf7..000000000 --- a/docs/leetcode/cpp/0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md +++ /dev/null @@ -1,105 +0,0 @@ -# 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_bound��upper_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/leetcode/cpp/0035._Search_Insert_Position.md b/docs/leetcode/cpp/0035._Search_Insert_Position.md deleted file mode 100644 index 03ee90eab..000000000 --- a/docs/leetcode/cpp/0035._Search_Insert_Position.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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/leetcode/cpp/0036._Valid_Sudoku.md b/docs/leetcode/cpp/0036._Valid_Sudoku.md deleted file mode 100644 index 48d5cdaac..000000000 --- a/docs/leetcode/cpp/0036._Valid_Sudoku.md +++ /dev/null @@ -1,90 +0,0 @@ -# 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)****** - -����board��9x9�ģ�ʵ�ʵ�ʱ�临�Ӷ�Ҳ��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/leetcode/cpp/0038._Count_and_Say.md b/docs/leetcode/cpp/0038._Count_and_Say.md deleted file mode 100644 index 3051bf77c..000000000 --- a/docs/leetcode/cpp/0038._Count_and_Say.md +++ /dev/null @@ -1,69 +0,0 @@ -# 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 1��n == 2ʱ���ǡ�11����������2��1���� two 1��n == 3ʱ���ǡ�21��������1��2��1��1���� one 2 one 1��n == 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/leetcode/cpp/0039._Combination_Sum.md b/docs/leetcode/cpp/0039._Combination_Sum.md deleted file mode 100644 index 37226b709..000000000 --- a/docs/leetcode/cpp/0039._Combination_Sum.md +++ /dev/null @@ -1,69 +0,0 @@ -# 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/leetcode/cpp/0040._Combination_Sum_II.md b/docs/leetcode/cpp/0040._Combination_Sum_II.md deleted file mode 100644 index f837be356..000000000 --- a/docs/leetcode/cpp/0040._Combination_Sum_II.md +++ /dev/null @@ -1,70 +0,0 @@ -# 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/leetcode/cpp/0041._First_Missing_Positive.md b/docs/leetcode/cpp/0041._First_Missing_Positive.md deleted file mode 100644 index 8c3b40a76..000000000 --- a/docs/leetcode/cpp/0041._First_Missing_Positive.md +++ /dev/null @@ -1,52 +0,0 @@ -# 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����������ĵ�һ������1����2���ڣ���������ĵڶ���λ�ӣ��������� - -```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/leetcode/cpp/0042._Trapping_Rain_Water.md b/docs/leetcode/cpp/0042._Trapping_Rain_Water.md deleted file mode 100644 index 55cb1d390..000000000 --- a/docs/leetcode/cpp/0042._Trapping_Rain_Water.md +++ /dev/null @@ -1,56 +0,0 @@ -# 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/leetcode/cpp/0043._Multiply_Strings.md b/docs/leetcode/cpp/0043._Multiply_Strings.md deleted file mode 100644 index 402275e25..000000000 --- a/docs/leetcode/cpp/0043._Multiply_Strings.md +++ /dev/null @@ -1,74 +0,0 @@ -# 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/leetcode/cpp/0044._Wildcard_Matching.md b/docs/leetcode/cpp/0044._Wildcard_Matching.md deleted file mode 100644 index 86a0eecbc..000000000 --- a/docs/leetcode/cpp/0044._Wildcard_Matching.md +++ /dev/null @@ -1,98 +0,0 @@ -# 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/leetcode/cpp/0045._Jump_Game_II.md b/docs/leetcode/cpp/0045._Jump_Game_II.md deleted file mode 100644 index adbc9cfdd..000000000 --- a/docs/leetcode/cpp/0045._Jump_Game_II.md +++ /dev/null @@ -1,54 +0,0 @@ -# 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/leetcode/cpp/0046._Permutations.md b/docs/leetcode/cpp/0046._Permutations.md deleted file mode 100644 index f2a9e583e..000000000 --- a/docs/leetcode/cpp/0046._Permutations.md +++ /dev/null @@ -1,99 +0,0 @@ -# 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/leetcode/cpp/0047._Permutations_II.md b/docs/leetcode/cpp/0047._Permutations_II.md deleted file mode 100644 index ed5ec1283..000000000 --- a/docs/leetcode/cpp/0047._Permutations_II.md +++ /dev/null @@ -1,102 +0,0 @@ -# 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/leetcode/cpp/0048._Rotate_Image.md b/docs/leetcode/cpp/0048._Rotate_Image.md deleted file mode 100644 index 30feef74b..000000000 --- a/docs/leetcode/cpp/0048._Rotate_Image.md +++ /dev/null @@ -1,71 +0,0 @@ -# 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/leetcode/cpp/0049._Group_Anagrams.md b/docs/leetcode/cpp/0049._Group_Anagrams.md deleted file mode 100644 index e7cb3c461..000000000 --- a/docs/leetcode/cpp/0049._Group_Anagrams.md +++ /dev/null @@ -1,53 +0,0 @@ -# 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/leetcode/cpp/0051._N-Queens.md b/docs/leetcode/cpp/0051._N-Queens.md deleted file mode 100644 index b190f1e96..000000000 --- a/docs/leetcode/cpp/0051._N-Queens.md +++ /dev/null @@ -1,91 +0,0 @@ -# 51. N-Queens - -**�Ѷ�:Hard** - -## ˢ������ -> ԭ������ - -* https://leetcode.com/problems/n-queens/ - -> �������� - -``` -The n-queens puzzle is the problem of placing n queens on an n��n 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/leetcode/cpp/0052._N-Queens_II.md b/docs/leetcode/cpp/0052._N-Queens_II.md deleted file mode 100644 index d3fe42dab..000000000 --- a/docs/leetcode/cpp/0052._N-Queens_II.md +++ /dev/null @@ -1,84 +0,0 @@ -# 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 n��n 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/leetcode/cpp/0053._Maximum_Subarray.md b/docs/leetcode/cpp/0053._Maximum_Subarray.md deleted file mode 100644 index 1ce150902..000000000 --- a/docs/leetcode/cpp/0053._Maximum_Subarray.md +++ /dev/null @@ -1,79 +0,0 @@ -# 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/leetcode/cpp/0054._Spiral_Matrix.md b/docs/leetcode/cpp/0054._Spiral_Matrix.md deleted file mode 100644 index 8fb997937..000000000 --- a/docs/leetcode/cpp/0054._Spiral_Matrix.md +++ /dev/null @@ -1,70 +0,0 @@ -# 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/leetcode/cpp/0055._Jump_Game.md b/docs/leetcode/cpp/0055._Jump_Game.md deleted file mode 100644 index 165942077..000000000 --- a/docs/leetcode/cpp/0055._Jump_Game.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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���ڶ���������[1��2]������Զ�ľ���Ϊ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/leetcode/cpp/0056._Merge_Intervals.md b/docs/leetcode/cpp/0056._Merge_Intervals.md deleted file mode 100644 index 0ee06bf72..000000000 --- a/docs/leetcode/cpp/0056._Merge_Intervals.md +++ /dev/null @@ -1,62 +0,0 @@ -# 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������ཻ�ͽ��ϲ��������IJ���ans�� - -```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/leetcode/cpp/0057._Insert_Interval.md b/docs/leetcode/cpp/0057._Insert_Interval.md deleted file mode 100644 index b910a1a0f..000000000 --- a/docs/leetcode/cpp/0057._Insert_Interval.md +++ /dev/null @@ -1,93 +0,0 @@ -# 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/leetcode/cpp/0058._Length_of_Last_Word.md b/docs/leetcode/cpp/0058._Length_of_Last_Word.md deleted file mode 100644 index 5586aa9f2..000000000 --- a/docs/leetcode/cpp/0058._Length_of_Last_Word.md +++ /dev/null @@ -1,37 +0,0 @@ -# 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/leetcode/cpp/0059._Spiral_Matrix_II.md b/docs/leetcode/cpp/0059._Spiral_Matrix_II.md deleted file mode 100644 index a77e1d205..000000000 --- a/docs/leetcode/cpp/0059._Spiral_Matrix_II.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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/leetcode/cpp/0060._Permutation_Sequence.md b/docs/leetcode/cpp/0060._Permutation_Sequence.md deleted file mode 100644 index f18865a3b..000000000 --- a/docs/leetcode/cpp/0060._Permutation_Sequence.md +++ /dev/null @@ -1,73 +0,0 @@ -# 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/leetcode/cpp/0061._Rotate_List.md b/docs/leetcode/cpp/0061._Rotate_List.md deleted file mode 100644 index 23261b62b..000000000 --- a/docs/leetcode/cpp/0061._Rotate_List.md +++ /dev/null @@ -1,113 +0,0 @@ -# 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��ȣ�������k��n�ij���ȡ�࣬��Ϊk���������ij���֮�����һ��ѭ��������Ҫ�ظ������� - - - -```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/leetcode/cpp/0062._Unique_Paths.md b/docs/leetcode/cpp/0062._Unique_Paths.md deleted file mode 100644 index d45c7294a..000000000 --- a/docs/leetcode/cpp/0062._Unique_Paths.md +++ /dev/null @@ -1,63 +0,0 @@ -# 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/leetcode/cpp/0064._Minimum_Path_Sum.md b/docs/leetcode/cpp/0064._Minimum_Path_Sum.md deleted file mode 100644 index c3cda766a..000000000 --- a/docs/leetcode/cpp/0064._Minimum_Path_Sum.md +++ /dev/null @@ -1,52 +0,0 @@ -# 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/leetcode/cpp/0065._Valid_Number.md b/docs/leetcode/cpp/0065._Valid_Number.md deleted file mode 100644 index 0f148bb69..000000000 --- a/docs/leetcode/cpp/0065._Valid_Number.md +++ /dev/null @@ -1,115 +0,0 @@ -# 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/leetcode/cpp/0066._Plus_One.md b/docs/leetcode/cpp/0066._Plus_One.md deleted file mode 100644 index fa34f2bfa..000000000 --- a/docs/leetcode/cpp/0066._Plus_One.md +++ /dev/null @@ -1,57 +0,0 @@ -# 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/leetcode/cpp/0068._Text_Justification.md b/docs/leetcode/cpp/0068._Text_Justification.md deleted file mode 100644 index f90ecabc3..000000000 --- a/docs/leetcode/cpp/0068._Text_Justification.md +++ /dev/null @@ -1,140 +0,0 @@ -# 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/leetcode/cpp/0069._Sqr(x).md b/docs/leetcode/cpp/0069._Sqr(x).md deleted file mode 100644 index f01d902b3..000000000 --- a/docs/leetcode/cpp/0069._Sqr(x).md +++ /dev/null @@ -1,73 +0,0 @@ -# 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)****** - -������0��x����������������Щ����ƽ����ֱ������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/leetcode/cpp/0072._Edit_Distance.md b/docs/leetcode/cpp/0072._Edit_Distance.md deleted file mode 100644 index 4ea772905..000000000 --- a/docs/leetcode/cpp/0072._Edit_Distance.md +++ /dev/null @@ -1,70 +0,0 @@ -# 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/leetcode/cpp/0075._Sort_Colors.md b/docs/leetcode/cpp/0075._Sort_Colors.md deleted file mode 100644 index 9b72ecc94..000000000 --- a/docs/leetcode/cpp/0075._Sort_Colors.md +++ /dev/null @@ -1,61 +0,0 @@ -# 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/leetcode/cpp/0076._Minimum_Window_Substring.md b/docs/leetcode/cpp/0076._Minimum_Window_Substring.md deleted file mode 100644 index 5be383407..000000000 --- a/docs/leetcode/cpp/0076._Minimum_Window_Substring.md +++ /dev/null @@ -1,74 +0,0 @@ -# 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/leetcode/cpp/0077._combinations.md b/docs/leetcode/cpp/0077._combinations.md deleted file mode 100644 index 434209189..000000000 --- a/docs/leetcode/cpp/0077._combinations.md +++ /dev/null @@ -1,53 +0,0 @@ -# 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/leetcode/cpp/0078._subsets.md b/docs/leetcode/cpp/0078._subsets.md deleted file mode 100644 index fc22be461..000000000 --- a/docs/leetcode/cpp/0078._subsets.md +++ /dev/null @@ -1,56 +0,0 @@ -# 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/leetcode/cpp/0081._Search_in_Rotated_Sorted_Array_II.md b/docs/leetcode/cpp/0081._Search_in_Rotated_Sorted_Array_II.md deleted file mode 100644 index eaa3caeee..000000000 --- a/docs/leetcode/cpp/0081._Search_in_Rotated_Sorted_Array_II.md +++ /dev/null @@ -1,82 +0,0 @@ -# 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/leetcode/cpp/0083._Remove_Duplicates_From_Sorted_Lists.md b/docs/leetcode/cpp/0083._Remove_Duplicates_From_Sorted_Lists.md deleted file mode 100644 index 4e502551f..000000000 --- a/docs/leetcode/cpp/0083._Remove_Duplicates_From_Sorted_Lists.md +++ /dev/null @@ -1,62 +0,0 @@ -#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/leetcode/cpp/0084._Largest_Rectangle_in_Histogram.md b/docs/leetcode/cpp/0084._Largest_Rectangle_in_Histogram.md deleted file mode 100644 index a9cab31f2..000000000 --- a/docs/leetcode/cpp/0084._Largest_Rectangle_in_Histogram.md +++ /dev/null @@ -1,97 +0,0 @@ -# 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/leetcode/cpp/0085._Maximal_Rectangle.md b/docs/leetcode/cpp/0085._Maximal_Rectangle.md deleted file mode 100644 index 73b72da59..000000000 --- a/docs/leetcode/cpp/0085._Maximal_Rectangle.md +++ /dev/null @@ -1,118 +0,0 @@ -# 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���С��count1����count1ȡ��С��ֵ����Ϊ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/leetcode/cpp/0087._Scramble_String.md b/docs/leetcode/cpp/0087._Scramble_String.md deleted file mode 100644 index e54810f5e..000000000 --- a/docs/leetcode/cpp/0087._Scramble_String.md +++ /dev/null @@ -1,123 +0,0 @@ -# 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)****** - -�տ�ʼ��ʱ����Ŀ����˼û�����������Ϊ�ǰ��ַ����԰룬��ʵ�ַ����кܶ�Ķ�������ʾ��������һ�ַ������ǵݹ�ķ�����ÿ�εݹ�ʱ�Ƚ�i��len��֮����Ӵ��Ƿ��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 - -�ڶ��ֵķ���ʹ��DP����������dp[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/leetcode/cpp/0088._Merge_Sorted_Array.md b/docs/leetcode/cpp/0088._Merge_Sorted_Array.md deleted file mode 100644 index b9fee289a..000000000 --- a/docs/leetcode/cpp/0088._Merge_Sorted_Array.md +++ /dev/null @@ -1,57 +0,0 @@ -# 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)****** - -�����������Ѿ�����õģ����ǿ���������ָ�� i��j ָ����������ĵ�һ��Ԫ�أ���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/leetcode/cpp/0090._Subsets_II.md b/docs/leetcode/cpp/0090._Subsets_II.md deleted file mode 100644 index eb6eb503e..000000000 --- a/docs/leetcode/cpp/0090._Subsets_II.md +++ /dev/null @@ -1,59 +0,0 @@ -# 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/leetcode/cpp/0094._binary_tree_inorder_traversal.md b/docs/leetcode/cpp/0094._binary_tree_inorder_traversal.md deleted file mode 100644 index c1710aa97..000000000 --- a/docs/leetcode/cpp/0094._binary_tree_inorder_traversal.md +++ /dev/null @@ -1,46 +0,0 @@ -# 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/leetcode/cpp/0096._Unique_Binary_Search_Trees.md b/docs/leetcode/cpp/0096._Unique_Binary_Search_Trees.md deleted file mode 100644 index 52a7190c6..000000000 --- a/docs/leetcode/cpp/0096._Unique_Binary_Search_Trees.md +++ /dev/null @@ -1,50 +0,0 @@ -# 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/leetcode/cpp/0099._Recover_Binary_Search_Tree.md b/docs/leetcode/cpp/0099._Recover_Binary_Search_Tree.md deleted file mode 100644 index 09a355cf4..000000000 --- a/docs/leetcode/cpp/0099._Recover_Binary_Search_Tree.md +++ /dev/null @@ -1,89 +0,0 @@ -# 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)****** - -�������Ҫ�㶮ƽ����������������ʱ�����ġ����������ʺ�����ֻ��Ҫ�Զ�������������������ҵ��ĸ�����������ɣ������һ�������������֮��Ϊ 321������3��1���ڶ��������������֮��Ϊ 1324������3��2�� - -```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/leetcode/cpp/0100._same_tree.md b/docs/leetcode/cpp/0100._same_tree.md deleted file mode 100644 index 8f6fe961f..000000000 --- a/docs/leetcode/cpp/0100._same_tree.md +++ /dev/null @@ -1,73 +0,0 @@ -# 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/leetcode/cpp/0101._Symmetric_Tree.md b/docs/leetcode/cpp/0101._Symmetric_Tree.md deleted file mode 100644 index b86b86759..000000000 --- a/docs/leetcode/cpp/0101._Symmetric_Tree.md +++ /dev/null @@ -1,63 +0,0 @@ -# 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/leetcode/cpp/0102._Binary_Tree_Level_Order_Traversal.md b/docs/leetcode/cpp/0102._Binary_Tree_Level_Order_Traversal.md deleted file mode 100644 index f59fa9493..000000000 --- a/docs/leetcode/cpp/0102._Binary_Tree_Level_Order_Traversal.md +++ /dev/null @@ -1,62 +0,0 @@ -# 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/leetcode/cpp/0104._Maximum_Depth_of_Binary_Tree.md b/docs/leetcode/cpp/0104._Maximum_Depth_of_Binary_Tree.md deleted file mode 100644 index 3e267cbf8..000000000 --- a/docs/leetcode/cpp/0104._Maximum_Depth_of_Binary_Tree.md +++ /dev/null @@ -1,64 +0,0 @@ -# 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/leetcode/cpp/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md b/docs/leetcode/cpp/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md deleted file mode 100644 index 8a33c3dd0..000000000 --- a/docs/leetcode/cpp/0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md +++ /dev/null @@ -1,59 +0,0 @@ -# 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/leetcode/cpp/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md b/docs/leetcode/cpp/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md deleted file mode 100644 index 1b5296661..000000000 --- a/docs/leetcode/cpp/0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md +++ /dev/null @@ -1,61 +0,0 @@ -# 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/leetcode/cpp/0107._Binary_Tree_Level_Order_Traversal_II.md b/docs/leetcode/cpp/0107._Binary_Tree_Level_Order_Traversal_II.md deleted file mode 100644 index 3ff76a532..000000000 --- a/docs/leetcode/cpp/0107._Binary_Tree_Level_Order_Traversal_II.md +++ /dev/null @@ -1,117 +0,0 @@ -# 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/leetcode/cpp/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md b/docs/leetcode/cpp/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md deleted file mode 100644 index b38fd10e0..000000000 --- a/docs/leetcode/cpp/0108._Convert_Sorted_Array_to_Binary_Search_Tree.md +++ /dev/null @@ -1,61 +0,0 @@ -# 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�����ֻ��ÿ�ν�����԰룬����һ����Ϊ����������һ����Ϊ���������ɡ�������assign����vecrtor��ֵ�� - -```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/leetcode/cpp/0109._Convert_Sorted_List_to_Binary_Search_Tree.md b/docs/leetcode/cpp/0109._Convert_Sorted_List_to_Binary_Search_Tree.md deleted file mode 100644 index 03844b11e..000000000 --- a/docs/leetcode/cpp/0109._Convert_Sorted_List_to_Binary_Search_Tree.md +++ /dev/null @@ -1,64 +0,0 @@ -# 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/leetcode/cpp/0110._Balanced_Binary_Tree.md b/docs/leetcode/cpp/0110._Balanced_Binary_Tree.md deleted file mode 100644 index d90577de3..000000000 --- a/docs/leetcode/cpp/0110._Balanced_Binary_Tree.md +++ /dev/null @@ -1,71 +0,0 @@ -# 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/leetcode/cpp/0111._Minimum_Depth_Of_Binary_Tree.md b/docs/leetcode/cpp/0111._Minimum_Depth_Of_Binary_Tree.md deleted file mode 100644 index d36eb1f73..000000000 --- a/docs/leetcode/cpp/0111._Minimum_Depth_Of_Binary_Tree.md +++ /dev/null @@ -1,39 +0,0 @@ -# 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/leetcode/cpp/0112._Path_Sum.md b/docs/leetcode/cpp/0112._Path_Sum.md deleted file mode 100644 index 54ceae04d..000000000 --- a/docs/leetcode/cpp/0112._Path_Sum.md +++ /dev/null @@ -1,54 +0,0 @@ -# 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/leetcode/cpp/0114._Flatten_Binary_Tree_to_Linked_List.md b/docs/leetcode/cpp/0114._Flatten_Binary_Tree_to_Linked_List.md deleted file mode 100644 index 19f6a6d30..000000000 --- a/docs/leetcode/cpp/0114._Flatten_Binary_Tree_to_Linked_List.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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/leetcode/cpp/0115._Distinct_Subsequences.md b/docs/leetcode/cpp/0115._Distinct_Subsequences.md deleted file mode 100644 index 01865e523..000000000 --- a/docs/leetcode/cpp/0115._Distinct_Subsequences.md +++ /dev/null @@ -1,80 +0,0 @@ -# 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/leetcode/cpp/0118._Pascals_Triangle.md b/docs/leetcode/cpp/0118._Pascals_Triangle.md deleted file mode 100644 index e134dea39..000000000 --- a/docs/leetcode/cpp/0118._Pascals_Triangle.md +++ /dev/null @@ -1,58 +0,0 @@ -## 118. Pascal's Triangle - -难度:Easy - -## 内容 - -题目链接:https://leetcode.com/problems/pascals-triangle - -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/leetcode/cpp/0119._Pascals_Triangle-II.md b/docs/leetcode/cpp/0119._Pascals_Triangle-II.md deleted file mode 100644 index 82f63c8d2..000000000 --- a/docs/leetcode/cpp/0119._Pascals_Triangle-II.md +++ /dev/null @@ -1,49 +0,0 @@ -## 119. Pascal's Triangle II - -难度:Easy - -## 内容 - -题目链接:https://leetcode.com/problems/pascals-triangle-ii - -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/leetcode/cpp/0120._Triangle.md b/docs/leetcode/cpp/0120._Triangle.md deleted file mode 100644 index b5c7712e3..000000000 --- a/docs/leetcode/cpp/0120._Triangle.md +++ /dev/null @@ -1,42 +0,0 @@ -# 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/leetcode/cpp/0121._Best_Tim_to_Buy_and_Sell_Stock.md b/docs/leetcode/cpp/0121._Best_Tim_to_Buy_and_Sell_Stock.md deleted file mode 100644 index 6084f7ce8..000000000 --- a/docs/leetcode/cpp/0121._Best_Tim_to_Buy_and_Sell_Stock.md +++ /dev/null @@ -1,40 +0,0 @@ -# 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/leetcode/cpp/0123._Best_Time_to_Buy_and_Sell_Stock_III.md b/docs/leetcode/cpp/0123._Best_Time_to_Buy_and_Sell_Stock_III.md deleted file mode 100644 index 4134cb78d..000000000 --- a/docs/leetcode/cpp/0123._Best_Time_to_Buy_and_Sell_Stock_III.md +++ /dev/null @@ -1,100 +0,0 @@ -# 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��֮ǰ����Сֵ��֮��������飬ÿ�θ���min1�����prices[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/leetcode/cpp/0124._Binary_Tree_Maximum_Path_Sum.md b/docs/leetcode/cpp/0124._Binary_Tree_Maximum_Path_Sum.md deleted file mode 100644 index cafe3a7ae..000000000 --- a/docs/leetcode/cpp/0124._Binary_Tree_Maximum_Path_Sum.md +++ /dev/null @@ -1,78 +0,0 @@ -# 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/leetcode/cpp/0127._Word_Ladde.md b/docs/leetcode/cpp/0127._Word_Ladde.md deleted file mode 100644 index 98fe7fcd7..000000000 --- a/docs/leetcode/cpp/0127._Word_Ladde.md +++ /dev/null @@ -1,158 +0,0 @@ -# 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һ��һ������������E�DZߵ�������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/leetcode/cpp/0128._Longest_Consecutive_Sequence.md b/docs/leetcode/cpp/0128._Longest_Consecutive_Sequence.md deleted file mode 100644 index 8531abb30..000000000 --- a/docs/leetcode/cpp/0128._Longest_Consecutive_Sequence.md +++ /dev/null @@ -1,83 +0,0 @@ -# 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/leetcode/cpp/0129._Sum_Root_to_Leaf_Numbers.md b/docs/leetcode/cpp/0129._Sum_Root_to_Leaf_Numbers.md deleted file mode 100644 index fe7ab4ae3..000000000 --- a/docs/leetcode/cpp/0129._Sum_Root_to_Leaf_Numbers.md +++ /dev/null @@ -1,75 +0,0 @@ -# 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/leetcode/cpp/0131._Palindrome_Partitioning.md b/docs/leetcode/cpp/0131._Palindrome_Partitioning.md deleted file mode 100644 index d4e60396a..000000000 --- a/docs/leetcode/cpp/0131._Palindrome_Partitioning.md +++ /dev/null @@ -1,64 +0,0 @@ -# 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/leetcode/cpp/0136._Single_Numbe.md b/docs/leetcode/cpp/0136._Single_Numbe.md deleted file mode 100644 index 5f2894d5c..000000000 --- a/docs/leetcode/cpp/0136._Single_Numbe.md +++ /dev/null @@ -1,79 +0,0 @@ -# 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/leetcode/cpp/0137._Single_Number_II.md b/docs/leetcode/cpp/0137._Single_Number_II.md deleted file mode 100644 index e449b0d30..000000000 --- a/docs/leetcode/cpp/0137._Single_Number_II.md +++ /dev/null @@ -1,64 +0,0 @@ -# 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/leetcode/cpp/0141._Linked_List_Cycle.md b/docs/leetcode/cpp/0141._Linked_List_Cycle.md deleted file mode 100644 index cae036790..000000000 --- a/docs/leetcode/cpp/0141._Linked_List_Cycle.md +++ /dev/null @@ -1,54 +0,0 @@ -#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/leetcode/cpp/0142._Linked_List_Cycle_II.md b/docs/leetcode/cpp/0142._Linked_List_Cycle_II.md deleted file mode 100644 index 2180fbf74..000000000 --- a/docs/leetcode/cpp/0142._Linked_List_Cycle_II.md +++ /dev/null @@ -1,78 +0,0 @@ -# 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/leetcode/cpp/0144._Binary_Tree_Preorder_Traversal.md b/docs/leetcode/cpp/0144._Binary_Tree_Preorder_Traversal.md deleted file mode 100644 index 47e4b1099..000000000 --- a/docs/leetcode/cpp/0144._Binary_Tree_Preorder_Traversal.md +++ /dev/null @@ -1,48 +0,0 @@ -# 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/leetcode/cpp/0145._Binary_Tree_Postorder_Traversal.md b/docs/leetcode/cpp/0145._Binary_Tree_Postorder_Traversal.md deleted file mode 100644 index 5893e9e19..000000000 --- a/docs/leetcode/cpp/0145._Binary_Tree_Postorder_Traversal.md +++ /dev/null @@ -1,113 +0,0 @@ -# 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/leetcode/cpp/0147._Insert_on_Sort_List.md b/docs/leetcode/cpp/0147._Insert_on_Sort_List.md deleted file mode 100644 index c3804b906..000000000 --- a/docs/leetcode/cpp/0147._Insert_on_Sort_List.md +++ /dev/null @@ -1,85 +0,0 @@ -# 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/leetcode/cpp/0148._Sort_list.md b/docs/leetcode/cpp/0148._Sort_list.md deleted file mode 100644 index a13194572..000000000 --- a/docs/leetcode/cpp/0148._Sort_list.md +++ /dev/null @@ -1,59 +0,0 @@ -# 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/leetcode/cpp/0151._Reverse_Words_in_a_String.md b/docs/leetcode/cpp/0151._Reverse_Words_in_a_String.md deleted file mode 100644 index f49c1257c..000000000 --- a/docs/leetcode/cpp/0151._Reverse_Words_in_a_String.md +++ /dev/null @@ -1,63 +0,0 @@ -# 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/leetcode/cpp/0153._Find_Minimum_in_Rotated_Sorted_Array.md b/docs/leetcode/cpp/0153._Find_Minimum_in_Rotated_Sorted_Array.md deleted file mode 100644 index 2f3d5e3d1..000000000 --- a/docs/leetcode/cpp/0153._Find_Minimum_in_Rotated_Sorted_Array.md +++ /dev/null @@ -1,91 +0,0 @@ -## 153. Find Minimum in Rotated Sorted Array - -难度:Medium - -## 内容 - -题目链接:https://leetcode.com/problems/find-minimum-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]`). - -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/leetcode/cpp/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md b/docs/leetcode/cpp/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md deleted file mode 100644 index b521d7e05..000000000 --- a/docs/leetcode/cpp/0154._Find_Minimum_in_Rotated_Sorted_Array-II.md +++ /dev/null @@ -1,105 +0,0 @@ -## 154. Find Minimum in Rotated Sorted Array II - -难度:Hard - -## 内容 - -题目链接:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii - -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). -- 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/leetcode/cpp/0160._Intersection_Of_Two_Linked_Lists.md b/docs/leetcode/cpp/0160._Intersection_Of_Two_Linked_Lists.md deleted file mode 100644 index 73f5102a4..000000000 --- a/docs/leetcode/cpp/0160._Intersection_Of_Two_Linked_Lists.md +++ /dev/null @@ -1,48 +0,0 @@ -# 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/leetcode/cpp/0164._Maximum_Gap.md b/docs/leetcode/cpp/0164._Maximum_Gap.md deleted file mode 100644 index c52d2c3f4..000000000 --- a/docs/leetcode/cpp/0164._Maximum_Gap.md +++ /dev/null @@ -1,97 +0,0 @@ -# 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/leetcode/cpp/0166._Fraction_to_Recurring_Decimal.md b/docs/leetcode/cpp/0166._Fraction_to_Recurring_Decimal.md deleted file mode 100644 index 88394c5b8..000000000 --- a/docs/leetcode/cpp/0166._Fraction_to_Recurring_Decimal.md +++ /dev/null @@ -1,105 +0,0 @@ -# 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����Сֵ����-1����int�����ֵ��������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/leetcode/cpp/0167._Two_Sum_II-Input_array_is_sorted.md b/docs/leetcode/cpp/0167._Two_Sum_II-Input_array_is_sorted.md deleted file mode 100644 index 9ab8b9619..000000000 --- a/docs/leetcode/cpp/0167._Two_Sum_II-Input_array_is_sorted.md +++ /dev/null @@ -1,53 +0,0 @@ -## 167. Two Sum II - Input array is sorted - -难度:Easy - -## 内容 - -原题链接:https://leetcode.com/problems/two-sum-ii-input-array-is-sorted - -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/leetcode/cpp/0199._Binary_Tree_Right_Side_View.md b/docs/leetcode/cpp/0199._Binary_Tree_Right_Side_View.md deleted file mode 100644 index c0389e978..000000000 --- a/docs/leetcode/cpp/0199._Binary_Tree_Right_Side_View.md +++ /dev/null @@ -1,58 +0,0 @@ -# 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/leetcode/cpp/0216._Combination_Sum_III.md b/docs/leetcode/cpp/0216._Combination_Sum_III.md deleted file mode 100644 index 16b760071..000000000 --- a/docs/leetcode/cpp/0216._Combination_Sum_III.md +++ /dev/null @@ -1,56 +0,0 @@ -# 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/leetcode/cpp/0230._Kth_Smallest_Element_in_a_BST.md b/docs/leetcode/cpp/0230._Kth_Smallest_Element_in_a_BST.md deleted file mode 100644 index 94e4978a9..000000000 --- a/docs/leetcode/cpp/0230._Kth_Smallest_Element_in_a_BST.md +++ /dev/null @@ -1,63 +0,0 @@ -# 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/leetcode/cpp/0260._Single_Number_III.md b/docs/leetcode/cpp/0260._Single_Number_III.md deleted file mode 100644 index a5c06ee4f..000000000 --- a/docs/leetcode/cpp/0260._Single_Number_III.md +++ /dev/null @@ -1,54 +0,0 @@ -# 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 ���ֵaXorb����������aXorbת���ɶ����ƣ��ӵ�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/leetcode/cpp/0287._Find_the_Duplicate_Number.md b/docs/leetcode/cpp/0287._Find_the_Duplicate_Number.md deleted file mode 100644 index 644959f03..000000000 --- a/docs/leetcode/cpp/0287._Find_the_Duplicate_Number.md +++ /dev/null @@ -1,48 +0,0 @@ -# 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/leetcode/cpp/0328._Odd_Even_Linked_List.md b/docs/leetcode/cpp/0328._Odd_Even_Linked_List.md deleted file mode 100644 index 85ae7826b..000000000 --- a/docs/leetcode/cpp/0328._Odd_Even_Linked_List.md +++ /dev/null @@ -1,51 +0,0 @@ -# 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/leetcode/cpp/0329._Longest_Increasing_Path_in_a_Matrix.md b/docs/leetcode/cpp/0329._Longest_Increasing_Path_in_a_Matrix.md deleted file mode 100644 index 8fbd48de9..000000000 --- a/docs/leetcode/cpp/0329._Longest_Increasing_Path_in_a_Matrix.md +++ /dev/null @@ -1,100 +0,0 @@ -# 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/leetcode/cpp/0413._Arithmetic_Slices.md b/docs/leetcode/cpp/0413._Arithmetic_Slices.md deleted file mode 100644 index 9366220b7..000000000 --- a/docs/leetcode/cpp/0413._Arithmetic_Slices.md +++ /dev/null @@ -1,65 +0,0 @@ -# 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/leetcode/cpp/0515._Find_Largest_Value_in_Each_Tree_Row.md b/docs/leetcode/cpp/0515._Find_Largest_Value_in_Each_Tree_Row.md deleted file mode 100644 index 88a8454f9..000000000 --- a/docs/leetcode/cpp/0515._Find_Largest_Value_in_Each_Tree_Row.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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/leetcode/cpp/0540._Single_Element_in_a_Sorted_Array.md b/docs/leetcode/cpp/0540._Single_Element_in_a_Sorted_Array.md deleted file mode 100644 index fc6f361ff..000000000 --- a/docs/leetcode/cpp/0540._Single_Element_in_a_Sorted_Array.md +++ /dev/null @@ -1,46 +0,0 @@ -# 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/leetcode/cpp/0629._K_Inverse_Pairs_Array.md b/docs/leetcode/cpp/0629._K_Inverse_Pairs_Array.md deleted file mode 100644 index a8a9045a4..000000000 --- a/docs/leetcode/cpp/0629._K_Inverse_Pairs_Array.md +++ /dev/null @@ -1,58 +0,0 @@ -### 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/leetcode/cpp/0632._Smallest_Range.md b/docs/leetcode/cpp/0632._Smallest_Range.md deleted file mode 100644 index 23656d930..000000000 --- a/docs/leetcode/cpp/0632._Smallest_Range.md +++ /dev/null @@ -1,59 +0,0 @@ -### 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/leetcode/cpp/0654._maximum_binary_tree.md b/docs/leetcode/cpp/0654._maximum_binary_tree.md deleted file mode 100644 index 67cbd034e..000000000 --- a/docs/leetcode/cpp/0654._maximum_binary_tree.md +++ /dev/null @@ -1,57 +0,0 @@ -# 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/leetcode/cpp/0668._Kth_Smallest_Number_in_Multiplication_Table.md b/docs/leetcode/cpp/0668._Kth_Smallest_Number_in_Multiplication_Table.md deleted file mode 100644 index db8c2122b..000000000 --- a/docs/leetcode/cpp/0668._Kth_Smallest_Number_in_Multiplication_Table.md +++ /dev/null @@ -1,55 +0,0 @@ -### 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/leetcode/cpp/0701._Insert_into_a_Binary_Search_Tree.md b/docs/leetcode/cpp/0701._Insert_into_a_Binary_Search_Tree.md deleted file mode 100644 index 6cb6ecfe2..000000000 --- a/docs/leetcode/cpp/0701._Insert_into_a_Binary_Search_Tree.md +++ /dev/null @@ -1,76 +0,0 @@ -# 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/leetcode/cpp/0715._Range_Module.md b/docs/leetcode/cpp/0715._Range_Module.md deleted file mode 100644 index 11f58f108..000000000 --- a/docs/leetcode/cpp/0715._Range_Module.md +++ /dev/null @@ -1,126 +0,0 @@ -### 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/leetcode/cpp/0719._Find_K-th_Smallest_Pair_Distance.md b/docs/leetcode/cpp/0719._Find_K-th_Smallest_Pair_Distance.md deleted file mode 100644 index c992e29cd..000000000 --- a/docs/leetcode/cpp/0719._Find_K-th_Smallest_Pair_Distance.md +++ /dev/null @@ -1,66 +0,0 @@ -### 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/leetcode/cpp/0739._Daily_Temperatures.md b/docs/leetcode/cpp/0739._Daily_Temperatures.md deleted file mode 100644 index 5d4142048..000000000 --- a/docs/leetcode/cpp/0739._Daily_Temperatures.md +++ /dev/null @@ -1,47 +0,0 @@ -# 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/leetcode/cpp/0797._All_Paths_From_Source_To_Target.md b/docs/leetcode/cpp/0797._All_Paths_From_Source_To_Target.md deleted file mode 100644 index c9d1deb3c..000000000 --- a/docs/leetcode/cpp/0797._All_Paths_From_Source_To_Target.md +++ /dev/null @@ -1,55 +0,0 @@ -# 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/leetcode/cpp/0814._Binary_Tree_Pruning.md b/docs/leetcode/cpp/0814._Binary_Tree_Pruning.md deleted file mode 100644 index 2925ff9e0..000000000 --- a/docs/leetcode/cpp/0814._Binary_Tree_Pruning.md +++ /dev/null @@ -1,43 +0,0 @@ -# 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/leetcode/cpp/0841._Keys_and_Rooms.md b/docs/leetcode/cpp/0841._Keys_and_Rooms.md deleted file mode 100644 index 739a27294..000000000 --- a/docs/leetcode/cpp/0841._Keys_and_Rooms.md +++ /dev/null @@ -1,76 +0,0 @@ -# 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/leetcode/cpp/0945._Minimum_Increment_to_Make_Array_Unique.md b/docs/leetcode/cpp/0945._Minimum_Increment_to_Make_Array_Unique.md deleted file mode 100644 index f9cf5f241..000000000 --- a/docs/leetcode/cpp/0945._Minimum_Increment_to_Make_Array_Unique.md +++ /dev/null @@ -1,38 +0,0 @@ -### 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/leetcode/cpp/0946._Validate_Stack_Sequences.md b/docs/leetcode/cpp/0946._Validate_Stack_Sequences.md deleted file mode 100644 index 33aa174b3..000000000 --- a/docs/leetcode/cpp/0946._Validate_Stack_Sequences.md +++ /dev/null @@ -1,41 +0,0 @@ -### 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/leetcode/cpp/0947._Most_Stones_Removed_with_Same_Row_or_Column.md b/docs/leetcode/cpp/0947._Most_Stones_Removed_with_Same_Row_or_Column.md deleted file mode 100644 index c4f3d7d0a..000000000 --- a/docs/leetcode/cpp/0947._Most_Stones_Removed_with_Same_Row_or_Column.md +++ /dev/null @@ -1,52 +0,0 @@ -### 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/leetcode/cpp/0948._Bag_of_Tokens.md b/docs/leetcode/cpp/0948._Bag_of_Tokens.md deleted file mode 100644 index 7ea0f6864..000000000 --- a/docs/leetcode/cpp/0948._Bag_of_Tokens.md +++ /dev/null @@ -1,72 +0,0 @@ -### 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/leetcode/cpp/0949._Largest_Time_for_Given_Digits.md b/docs/leetcode/cpp/0949._Largest_Time_for_Given_Digits.md deleted file mode 100644 index 3c856994e..000000000 --- a/docs/leetcode/cpp/0949._Largest_Time_for_Given_Digits.md +++ /dev/null @@ -1,49 +0,0 @@ -### 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/leetcode/cpp/0950._Reveal_Cards_In_Increasing_Order.md b/docs/leetcode/cpp/0950._Reveal_Cards_In_Increasing_Order.md deleted file mode 100644 index 894a66236..000000000 --- a/docs/leetcode/cpp/0950._Reveal_Cards_In_Increasing_Order.md +++ /dev/null @@ -1,72 +0,0 @@ -### 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/leetcode/cpp/0951._Flip_Equivalent_Binary_Trees.md b/docs/leetcode/cpp/0951._Flip_Equivalent_Binary_Trees.md deleted file mode 100644 index 1b1a86005..000000000 --- a/docs/leetcode/cpp/0951._Flip_Equivalent_Binary_Trees.md +++ /dev/null @@ -1,58 +0,0 @@ -### 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/leetcode/cpp/0952._Largest_Component_Size_by_Common_Factor.md b/docs/leetcode/cpp/0952._Largest_Component_Size_by_Common_Factor.md deleted file mode 100644 index 97aafcf0e..000000000 --- a/docs/leetcode/cpp/0952._Largest_Component_Size_by_Common_Factor.md +++ /dev/null @@ -1,125 +0,0 @@ -### 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/leetcode/cpp/README.md b/docs/leetcode/cpp/README.md deleted file mode 100644 index d21da03e8..000000000 --- a/docs/leetcode/cpp/README.md +++ /dev/null @@ -1 +0,0 @@ -# Leetcode C++ 题解 diff --git a/docs/leetcode/cpp/SUMMARY.md b/docs/leetcode/cpp/SUMMARY.md deleted file mode 100644 index 57853e01c..000000000 --- a/docs/leetcode/cpp/SUMMARY.md +++ /dev/null @@ -1,158 +0,0 @@ -+ [Leetcode C++ 题解](README.md) -+ [1. Two Sum](0001._Two_Sum.md) -+ [2. Add Two Numbers](0002._Add_Two_Numbers.md) -+ [3. Longest Substring Without Repeating Characters](0003._Longest_Substring_Without_Repeating_Characters.md) -+ [004. Median of Two Sorted Arrays](0004._Median_of_Two_Sorted_Arrays.md) -+ [5. Longest Palindromic Substring](0005._Longest_Palindromic_Substring.md) -+ [6. ZigZag Conversion](0006._ZigZag_Conversion.md) -+ [7. Reverse Integer](0007._Reverse_Integer.md) -+ [8. String to Integer (atoi)](0008._String_to_Integer_(atoi).md) -+ [9. Palindrome Number](0009._Palindrome_Number.md) -+ [10. Regular Expression Matching](0010._Regular_Expression_Matching.md) -+ [11. container with most water](0011._Container_With_Most_Water.md) -+ [12. Integer to Roman](0012._Integer_to_Roman.md) -+ [14. Longest Common Prefix](0014._Longest_Common_Prefix.md) -+ [15. 3sum](0015._3sum.md) -+ [16. 3Sum Closest](0016._3Sum_Closest.md) -+ [17. Letter Combinations of a Phone Number](0017._Letter_Combinations_of_a_Phone_Number.md) -+ [18. 4Sum](0018._4Sum.md) -+ [19. Remove Nth Node From End of List](0019._Remove_Nth_Node_From_End_of_List.md) -+ [20. Valid Parentheses](0020._Valid_Parentheses.md) -+ [21. Merge Two Sorted Lists](0021._Merge _Two _Sorted _Lists.md) -+ [22. Generate Parentheses](0022._Generate_Parentheses.md) -+ [23. merge k sorted lists](0023._Merge_K_Sorted_Lists.md) -+ [24. Swap Nodes in Pairs](0024._Swap_Nodes_in_Pairs.md) -+ [25.reverse nodes in k group](0025._Reverse_Nodes_In_K_Group.md) -+ [26.Remove Duplicates From Sorted Array](0026._Remove_Duplicates_From_Sorted_Array.md) -+ [27.Remove Element](0027._Remove_Element.md) -+ [28.implement strstr](0028._Implement_Strstr.md) -+ [29.divide two integers](0029._Divide_Two_Integers.md) -+ [30.substring with concatenation of all words](0030._Substring_With_Concatenation_Of_All_Words.md) -+ [31.Next Permutatio](0031._Next_Permutatio.md) -+ [32. Longest Valid Parentheses](0032._Longest_Valid_Parentheses.md) -+ [033. Search in Rotated Sorted Array](0033._Search_in_Rotated_Sorted_Array.md) -+ [34. Find First and Last Position of Element in Sorted Array](0034._Find_First_and_Last_Position_of_Element_in_Sorted_Array.md) -+ [35.search insert position](0035._Search_Insert_Position.md) -+ [36. Valid Sudoku](0036._Valid_Sudoku.md) -+ [38. Count and Say](0038._Count_and_Say.md) -+ [39. Combination Sum](0039._Combination_Sum.md) -+ [40. Combination Sum II](0040._Combination_Sum_II.md) -+ [041.First Missing Positive](0041._First_Missing_Positive.md) -+ [42. Trapping Rain Water](0042._Trapping_Rain_Water.md) -+ [43. Multiply Strings](0043._Multiply_Strings.md) -+ [44. Wildcard Matching](0044._Wildcard_Matching.md) -+ [045. Jump Game II](0045._Jump_Game_II.md) -+ [46. Permutations](0046._Permutations.md) -+ [47. Permutations II](0047._Permutations_II.md) -+ [49. Group Anagrams](0048._Rotate_Image.md) -+ [49. Group Anagrams](0049._Group_Anagrams.md) -+ [50. powx n](0050._powx_n.md) -+ [51. N-Queens](0051._ N-Queens.md) -+ [52. N-Queens II](0052._N-Queens_II.md) -+ [053. Maximum Subarray](0053._Maximum_Subarray.md) -+ [54. Spiral Matrix](0054._Spiral_Matrix.md) -+ [55. Jump Game](0055._Jump_Game.md) -+ [56. Merge Intervals](0056._Merge_Intervals.md) -+ [57. Insert Interval](0057._Insert_Interval.md) -+ [058. Length of Last Word](0058._Length_of_Last_Word.md) -+ [59. Spiral Matrix II](0059._Spiral_Matrix_II.md) -+ [60. Permutation Sequence](0060._Permutation_Sequence.md) -+ [61. Rotate List](0061._Rotate_List.md) -+ [62. Unique Paths](0062._Unique_Paths.md) -+ [63. Unique Paths II](0063._Unique_Paths_II.md) -+ [64. Minimum Path Sum](0064._Minimum_Path_Sum.md) -+ [65. Valid Number](0065._Valid_Number.md) -+ [66. Plus One](0066._Plus_One.md) -+ [68. Text Justification](0068._Text_Justification.md) -+ [69. Sqrt(x)](0069._Sqr(x).md) -+ [72. Edit Distance](0072._Edit_Distance.md) -+ [75. Sort Colors](0075._Sort_Colors.md) -+ [76. Minimum Window Substring](0076._Minimum_Window_Substring.md) -+ [77. Combinations](0077._combinations.md) -+ [78. Subsets](0078._subsets.md) -+ [81. Search in Rotated Sorted Array II](0081._Search_in_Rotated_Sorted_Array_II.md) -+ [ˢ������](0083._Remove_Duplicates_From_Sorted_Lists.md) -+ [84. Largest Rectangle in Histogram](0084._Largest_Rectangle_in_Histogram.md) -+ [85. Maximal Rectangle](0085._Maximal_Rectangle.md) -+ [87. Scramble String](0087._Scramble_String.md) -+ [88.Merge Sorted Array](0088._Merge_Sorted_Array.md) -+ [90. Subsets II](0090._Subsets_II.md) -+ [94. Binary Tree Inorder Traversal](0094._binary_tree_inorder_traversal.md) -+ [96. Unique Binary Search Trees](0096._Unique_Binary_Search_Trees.md) -+ [97. Interleaving String](0097._Interleaving_String.md) -+ [99. Recover Binary Search Tree](0099._Recover_Binary_Search_Tree.md) -+ [100. same tree](0100._same_tree.md) -+ [101. Symmetric Tree](0101._Symmetric_Tree.md) -+ [102. Binary Tree Level Order Traversal](0102._Binary_Tree_Level_Order_Traversal.md) -+ [104. Maximum Depth of Binary Tree](0104._Maximum_Depth_of_Binary_Tree.md) -+ [105. Construct Binary Tree from Preorder and Inorder Traversal](0105._Construct_Binary_Tree_from_Preorder_and_Inorder_Traversal.md) -+ [106. Construct Binary Tree from Inorder and Postorder Traversal](0106._Construct_Binary_Tree_from_Inorder_and_Postorder_Traversal.md) -+ [107.Binary Tree Level Order Traversal II](0107._Binary_Tree_Level_Order_Traversal_II.md) -+ [108. Convert Sorted Array to Binary Search Tree](0108._Convert_Sorted_Array_to_Binary_Search_Tree.md) -+ [109. Convert Sorted List to Binary Search Tree](0109._Convert_Sorted_List_to_Binary_Search_Tree.md) -+ [110.Balanced Binary Tree](0110._Balanced_Binary_Tree.md) -+ [111. Minimum Depth of Binary Tree](0111._Minimum_Depth_Of_Binary_Tree.md) -+ [112. Path Sum](0112._Path_Sum.md) -+ [114. Flatten Binary Tree to Linked List](0114._Flatten_Binary_Tree_to_Linked_List.md) -+ [115.Distinct Subsequences](0115._Distinct_Subsequences.md) -+ [118. Pascal's Triangle](0118._Pascals_Triangle.md) -+ [119. Pascal's Triangle II](0119._Pascals_Triangle-II.md) -+ [120. Triangle](0120._Triangle.md) -+ [121. Best Time to Buy and Sell Stock](0121._Best_Tim_to_Buy_and_Sell_Stock.md) -+ [122. Best Time to Buy and Sell Stock II](0122._Best_Time_to_Buy_and_Sell_Stock_II.md) -+ [123. Best Time to Buy and Sell Stock III](0123._Best_Time_to_Buy _and_Sell_Stock_III.md) -+ [124. Binary Tree Maximum Path Sum](0124._Binary_Tree_Maximum_Path_Sum.md) -+ [127. Word Ladder](0127._Word_Ladde.md) -+ [128. Longest Consecutive Sequence](0128._Longest_Consecutive_Sequence.md) -+ [129. Sum Root to Leaf Numbers](0129._Sum_Root_to_Leaf_Numbers.md) -+ [131. Palindrome Paritionaing](0131._Palindrome_Partitioning.md) -+ [136. Single Numbe](0136._Single_Numbe.md) -+ [137.Single Number II](0137._Single_Number_II.md) -+ [ˢ������](0141._Linked_List_Cycle.md) -+ [142. linked list cycle II](0142._Linked_List_Cycle_II.md) -+ [144. Binary Tree Preorder Traversal](0144._Binary_Tree_Preorder_Traversal.md) -+ [145. Binary Tree Postorder Traversal](0145._Binary_Tree_Postorder_Traversal.md) -+ [147. Insertion Sort List](0147._Insert_on_Sort_List.md) -+ [148.Sort list](0148._Sort _list.md) -+ [151. Reverse Words in a String](0151._Reverse_Words_in_a_String.md) -+ [153. Find Minimum in Rotated Sorted Array](0153._Find_Minimum_in_Rotated_Sorted_Array.md) -+ [154. Find Minimum in Rotated Sorted Array II](0154._Find_Minimum_in_Rotated_Sorted_Array-II.md) -+ [160 intersection_of_Two_Linked_Lists](0160._Intersection_Of_Two_Linked_Lists.md) -+ [164. Maximum Gap](0164._Maximum_Gap.md) -+ [166. Fraction to Recurring Decimal](0166._Fraction_to_Recurring_Decimal.md) -+ [167. Two Sum II - Input array is sorted](0167._Two_Sum_II-Input_array_is_sorted.md) -+ [199. Binary Tree Right Side View](0199._Binary_Tree_Right_Side_View.md) -+ [216. Combination Sum III](0216._Combination_Sum_III.md) -+ [230. Kth Smallest Element in a BST](0230._Kth_Smallest_Element_in_a_BST.md) -+ [260. Single Number III](0260._Single_Number_III.md) -+ [287. Find the Duplicate Number](0287._Find_the_Duplicate_Number.md) -+ [326. Power_of_Three](0326._Power_Of_Three.md) -+ [328. Odd Even Linked List](0328._Odd_Even_Linked_List.md) -+ [329. Longest Increasing Path in a Matrix](0329._Longest_Increasing_Path_in_a_Matrix.md) -+ [338. Counting Bits ](0338._Counting_Bits.md) -+ [413. Arithmetic Slices](0413._Arithmetic_Slices.md) -+ [442. Find All Duplicates in an Array](0442._Find_All_Duplicates_in_an_Array.md) -+ [513. Find Bottom Left Tree Value](0513._Find_Bottom_Left_Tree_Value.md) -+ [515. Find Largest Value in Each Tree Row](0515._Find_Largest_Value_in_Each_Tree_Row.md) -+ [540. Single Element in a Sorted Array](0540._Single_Element_in_a_Sorted_Array.md) -+ [581. Shortest Unsorted Continuous Subarray](0581._Shortest_Unsorted_Continuous_Subarray.md) -+ [793. K Inverse Pairs Array](0629._K_Inverse_Pairs_Array.md) -+ [632. Smallest Range](0632._Smallest_Range.md) -+ [654. Maximum Binary Tree ](0654._maximum_binary_tree.md) -+ [668. Kth Smallest Number in Multiplication Table](0668._Kth_Smallest_Number_in_Multiplication_Table.md) -+ [701. Insert into a Binary Search Tree](0701._Insert_into_a_Binary_Search_Tree.md) -+ [715. Range Module](0715._Range_Module.md) -+ [793. Find K-th Smallest Pair Distance](0719._Find_K-th_Smallest_Pair_Distance.md) -+ [739. Daily Temperatures](0739._Daily_Temperatures.md) -+ [797. All Paths From Source to Target](0797._All_Paths_From_Source_To_Target.md) -+ [814. Binary Tree Pruning](0814._Binary_Tree_Pruning.md) -+ [841. Keys and Rooms](0841._Keys_and_Rooms.md) -+ [877. Stone Game](0877._Stone_Game.md) -+ [945. Minimum Increment to Make Array Unique](0945._Minimum_Increment_to_Make_Array_Unique.md) -+ [946. Validate Stack Sequences](0946._Validate_Stack_Sequences.md) -+ [947. Most Stones Removed with Same Row or Column](0947._Most_Stones_Removed_with_Same_Row_or_Column.md) -+ [948. Bag of Tokens](0948._Bag_of_Tokens.md) -+ [949. Largest Time for Given Digits](0949._Largest_Time_for_Given_Digits.md) -+ [950. Reveal Cards In Increasing Order](0950._Reveal_Cards_In_Increasing_Order.md) -+ [951. Flip Equivalent Binary Trees](0951._Flip_Equivalent_Binary_Trees.md) -+ [952. Largest Component Size by Common Factor](0952._Largest_Component_Size_by_Common_Factor.md) \ No newline at end of file diff --git a/docs/leetcode/java/0001._Two_Sum.md b/docs/leetcode/java/0001._Two_Sum.md deleted file mode 100644 index 9292a32fd..000000000 --- a/docs/leetcode/java/0001._Two_Sum.md +++ /dev/null @@ -1,48 +0,0 @@ -# 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/leetcode/java/0002._add_two_numbers.md b/docs/leetcode/java/0002._add_two_numbers.md deleted file mode 100644 index 005317afd..000000000 --- a/docs/leetcode/java/0002._add_two_numbers.md +++ /dev/null @@ -1,90 +0,0 @@ -# 2. Add Two Numbers - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/add-two-numbers - -> 内容描述 - -``` -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/leetcode/java/0003._Longest_Substring_Without_Repeating_Characters.md b/docs/leetcode/java/0003._Longest_Substring_Without_Repeating_Characters.md deleted file mode 100644 index fb6388bab..000000000 --- a/docs/leetcode/java/0003._Longest_Substring_Without_Repeating_Characters.md +++ /dev/null @@ -1,52 +0,0 @@ -# 3. 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)******- 空间复杂度: 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 - -> 内容描述 - -``` -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/leetcode/java/0005._Longest_Palindromic_Substring.md b/docs/leetcode/java/0005._Longest_Palindromic_Substring.md deleted file mode 100644 index 7c8e361cf..000000000 --- a/docs/leetcode/java/0005._Longest_Palindromic_Substring.md +++ /dev/null @@ -1,78 +0,0 @@ -# 5. Longest Palindromic Substring - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/longest-palindromic-substring - -> 内容描述 - -``` -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/leetcode/java/0006._ZigZag_Conversion.md b/docs/leetcode/java/0006._ZigZag_Conversion.md deleted file mode 100644 index a4f7d1078..000000000 --- a/docs/leetcode/java/0006._ZigZag_Conversion.md +++ /dev/null @@ -1,93 +0,0 @@ -# 5. ZigZag Conversion - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.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 -******- 时间复杂度: 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/leetcode/java/0007._Reverse_Integer.md b/docs/leetcode/java/0007._Reverse_Integer.md deleted file mode 100644 index baa08fea1..000000000 --- a/docs/leetcode/java/0007._Reverse_Integer.md +++ /dev/null @@ -1,57 +0,0 @@ -# 5. Reverse Integer - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.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 - - -``` - -## 解题方案 - -> 思路 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/leetcode/java/0023._Merge_K_Sorted_Lists.md b/docs/leetcode/java/0023._Merge_K_Sorted_Lists.md deleted file mode 100644 index ec5107782..000000000 --- a/docs/leetcode/java/0023._Merge_K_Sorted_Lists.md +++ /dev/null @@ -1,69 +0,0 @@ -# 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 -] -``` - -## 解题方案 - -> 思路 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/leetcode/java/0141._linked_list_cycle.md b/docs/leetcode/java/0141._linked_list_cycle.md deleted file mode 100644 index 5ea465586..000000000 --- a/docs/leetcode/java/0141._linked_list_cycle.md +++ /dev/null @@ -1,51 +0,0 @@ -# 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? -``` - -## 解题方案 - - -> 思路 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/leetcode/java/0218._The_Skyline_Problem.md b/docs/leetcode/java/0218._The_Skyline_Problem.md deleted file mode 100644 index 452b013d8..000000000 --- a/docs/leetcode/java/0218._The_Skyline_Problem.md +++ /dev/null @@ -1,107 +0,0 @@ -# 218. The Skyline Problem - -**难度: Hard** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/the-skyline-problem - -> 内容描述 - -``` -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/leetcode/java/0238._product_of_array_except_self.md b/docs/leetcode/java/0238._product_of_array_except_self.md deleted file mode 100644 index 6b3ec01bc..000000000 --- a/docs/leetcode/java/0238._product_of_array_except_self.md +++ /dev/null @@ -1,69 +0,0 @@ -# 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/leetcode/java/0342._Power_of_Four.md b/docs/leetcode/java/0342._Power_of_Four.md deleted file mode 100644 index 064a5a2f4..000000000 --- a/docs/leetcode/java/0342._Power_of_Four.md +++ /dev/null @@ -1,46 +0,0 @@ -# 342. Power of Four - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/power-of-four - -> 内容描述 - -``` -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/leetcode/java/0757._Set_Intersection_Size_At_Least_Two.md b/docs/leetcode/java/0757._Set_Intersection_Size_At_Least_Two.md deleted file mode 100644 index b49ef161c..000000000 --- a/docs/leetcode/java/0757._Set_Intersection_Size_At_Least_Two.md +++ /dev/null @@ -1,75 +0,0 @@ -### 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/leetcode/java/0768._Max_Chunks_To_Make_Sorted_II.md b/docs/leetcode/java/0768._Max_Chunks_To_Make_Sorted_II.md deleted file mode 100644 index 1e2be6dfb..000000000 --- a/docs/leetcode/java/0768._Max_Chunks_To_Make_Sorted_II.md +++ /dev/null @@ -1,45 +0,0 @@ -### 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/leetcode/java/0780._Reaching_Points.md b/docs/leetcode/java/0780._Reaching_Points.md deleted file mode 100644 index 91dc0a208..000000000 --- a/docs/leetcode/java/0780._Reaching_Points.md +++ /dev/null @@ -1,59 +0,0 @@ -### 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/leetcode/java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md b/docs/leetcode/java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md deleted file mode 100644 index b3b42dfd3..000000000 --- a/docs/leetcode/java/0793._Preimage_Size_of_Factorial_Zeroes_Function.md +++ /dev/null @@ -1,78 +0,0 @@ -### 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/leetcode/java/0827._Making_A_Large_Island.md b/docs/leetcode/java/0827._Making_A_Large_Island.md deleted file mode 100644 index e9b072685..000000000 --- a/docs/leetcode/java/0827._Making_A_Large_Island.md +++ /dev/null @@ -1,128 +0,0 @@ -### 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/leetcode/java/0828._Unique_Letter_String.md b/docs/leetcode/java/0828._Unique_Letter_String.md deleted file mode 100644 index 046cedb08..000000000 --- a/docs/leetcode/java/0828._Unique_Letter_String.md +++ /dev/null @@ -1,169 +0,0 @@ -### 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/leetcode/java/0834._Sum_of_Distances_in_Tree.md b/docs/leetcode/java/0834._Sum_of_Distances_in_Tree.md deleted file mode 100644 index 0e4f499f6..000000000 --- a/docs/leetcode/java/0834._Sum_of_Distances_in_Tree.md +++ /dev/null @@ -1,144 +0,0 @@ -### 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/leetcode/java/0843._Guess_the_Word.md b/docs/leetcode/java/0843._Guess_the_Word.md deleted file mode 100644 index 8833e1812..000000000 --- a/docs/leetcode/java/0843._Guess_the_Word.md +++ /dev/null @@ -1,94 +0,0 @@ -### 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/leetcode/java/0847._Shortest_Path_Visiting_All_Nodes.md b/docs/leetcode/java/0847._Shortest_Path_Visiting_All_Nodes.md deleted file mode 100644 index 181c55087..000000000 --- a/docs/leetcode/java/0847._Shortest_Path_Visiting_All_Nodes.md +++ /dev/null @@ -1,85 +0,0 @@ -### 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/leetcode/java/0850._Rectangle_Area_II.md b/docs/leetcode/java/0850._Rectangle_Area_II.md deleted file mode 100644 index 3ded6874c..000000000 --- a/docs/leetcode/java/0850._Rectangle_Area_II.md +++ /dev/null @@ -1,87 +0,0 @@ -### 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/leetcode/java/0854._K-Similar_Strings.md b/docs/leetcode/java/0854._K-Similar_Strings.md deleted file mode 100644 index c30626cae..000000000 --- a/docs/leetcode/java/0854._K-Similar_Strings.md +++ /dev/null @@ -1,141 +0,0 @@ -### 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/leetcode/java/0857._Minimum_Cost_to_Hire_K_Workers.md b/docs/leetcode/java/0857._Minimum_Cost_to_Hire_K_Workers.md deleted file mode 100644 index 1b2dc913d..000000000 --- a/docs/leetcode/java/0857._Minimum_Cost_to_Hire_K_Workers.md +++ /dev/null @@ -1,63 +0,0 @@ -### 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/leetcode/java/0862._Shortest_Subarray_with_Sum_at_Least_K.md b/docs/leetcode/java/0862._Shortest_Subarray_with_Sum_at_Least_K.md deleted file mode 100644 index a931ffea0..000000000 --- a/docs/leetcode/java/0862._Shortest_Subarray_with_Sum_at_Least_K.md +++ /dev/null @@ -1,77 +0,0 @@ -### 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/leetcode/java/0864._Shortest_Path_to_Get_All_Keys.md b/docs/leetcode/java/0864._Shortest_Path_to_Get_All_Keys.md deleted file mode 100644 index 9125cc329..000000000 --- a/docs/leetcode/java/0864._Shortest_Path_to_Get_All_Keys.md +++ /dev/null @@ -1,180 +0,0 @@ -### 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/leetcode/java/0871._Minimum_Number_of_Refueling_Stops.md b/docs/leetcode/java/0871._Minimum_Number_of_Refueling_Stops.md deleted file mode 100644 index 5c57101f9..000000000 --- a/docs/leetcode/java/0871._Minimum_Number_of_Refueling_Stops.md +++ /dev/null @@ -1,69 +0,0 @@ -### 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/leetcode/java/0879._Profitable_Schemes.md b/docs/leetcode/java/0879._Profitable_Schemes.md deleted file mode 100644 index 8d6156782..000000000 --- a/docs/leetcode/java/0879._Profitable_Schemes.md +++ /dev/null @@ -1,66 +0,0 @@ -### 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/leetcode/java/0913._Cat_and_Mouse.md b/docs/leetcode/java/0913._Cat_and_Mouse.md deleted file mode 100644 index 1872b5f92..000000000 --- a/docs/leetcode/java/0913._Cat_and_Mouse.md +++ /dev/null @@ -1,178 +0,0 @@ -### 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/leetcode/java/0920._Number_of_Music_Playlists.md b/docs/leetcode/java/0920._Number_of_Music_Playlists.md deleted file mode 100644 index cf7685b22..000000000 --- a/docs/leetcode/java/0920._Number_of_Music_Playlists.md +++ /dev/null @@ -1,64 +0,0 @@ -### 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/leetcode/java/README.md b/docs/leetcode/java/README.md deleted file mode 100644 index 8c21fb92c..000000000 --- a/docs/leetcode/java/README.md +++ /dev/null @@ -1 +0,0 @@ -# Leetcode Java 题解 \ No newline at end of file diff --git a/docs/leetcode/java/SUMMARY.md b/docs/leetcode/java/SUMMARY.md deleted file mode 100644 index 703a9159f..000000000 --- a/docs/leetcode/java/SUMMARY.md +++ /dev/null @@ -1,41 +0,0 @@ -+ [Leetcode Java 题解](README.md) -+ [1. Two Sum](0001._Two_Sum.md) -+ [2. Add Two Numbers](0002._add_two_numbers.md) -+ [3. Longest Substring Without Repeating Characters](0003._Longest_Substring_Without_Repeating_Characters.md) -+ [4. Median of Two Sorted Arrays](0004._Median_of_Two_Sorted_Arrays.md) -+ [5. Longest Palindromic Substring](0005._Longest_Palindromic_Substring.md) -+ [6. ZigZag Conversion](0006._ZigZag_Conversion.md) -+ [7. Reverse Integer](0007._Reverse_Integer.md) -+ [23. Merge K Sorted Lists](0023._Merge_K_Sorted_Lists.md) -+ [141. Linked List Cycle](0141._linked_list_cycle.md) -+ [218. The Skyline Problem](0218._The_Skyline_Problem.md) -+ [238. Product of Array Except Self](0238._product_of_array_except_self.md) -+ [342. Power of Four](0342._Power_of_Four.md) -+ [403. Frog Jump](0403._Frog_Jump.md) -+ [757. Set Intersection Size At Least Two](0757._Set_Intersection_Size_At_Least_Two.md) -+ [768. Max Chunks To Make Sorted II](0768._Max_Chunks_To_Make_Sorted_II.md) -+ [780. Reaching Points](0780._Reaching_Points.md) -+ [793. Preimage Size of Factorial Zeroes Function](0793._Preimage_Size_of_Factorial_Zeroes_Function.md) -+ [827. Making A Large Island](0827._Making_A_Large_Island.md) -+ [828. Unique Letter String](0828._Unique_Letter_String.md) -+ [834. Sum of Distances in Tree](0834._Sum_of_Distances_in_Tree.md) -+ [843. Guess the Word](0843._Guess_the_Word.md) -+ [847. Shortest Path Visiting All Nodes](0847._Shortest_Path_Visiting_All_Nodes.md) -+ [850. Rectangle Area II](0850._Rectangle_Area_II.md) -+ [854. K-Similar Strings](0854._K-Similar_Strings.md) -+ [857. Minimum Cost to Hire K Workers](0857._Minimum_Cost_to_Hire_K_Workers.md) -+ [862. Shortest Subarray with Sum at Least K](0862._Shortest_Subarray_with_Sum_at_Least_K.md) -+ [864. Shortest Path to Get All Keys](0864._Shortest_Path_to_Get_All_Keys.md) -+ [871. Minimum Number of Refueling Stops](0871._Minimum_Number_of_Refueling_Stops.md) -+ [878. Nth Magical Number](0878._Nth_Magical_Number.md) -+ [879. Profitable Schemes](0879._Profitable_Schemes.md) -+ [899. Reachable Nodes In Subdivided Graph](0882._Reachable_Nodes_In_Subdivided_Graph.md) -+ [887. Super Egg Drop](0887._Super_Egg_Drop.md) -+ [891. Sum of Subsequence Widths](0891._Sum_of_Subsequence_Widths.md) -+ [895. Maximum Frequency Stack](0895._Maximum_Frequency_Stack.md) -+ [899. Orderly Queue](0899._Orderly_Queue.md) -+ [902. Numbers At Most N Given Digit Set](0902._Numbers_At_Most_N_Given_Digit_Set.md) -+ [903. Valid Permutations for DI Sequence](0903._Valid_Permutations_for_DI_Sequence.md) -+ [906. Super Palindromes](0906._Super_Palindromes.md) -+ [913. Cat and Mouse](0913._Cat_and_Mouse.md) -+ [920. Number of Music Playlists](0920._Number_of_Music_Playlists.md) \ No newline at end of file diff --git a/docs/leetcode/javascript/0001._Two_Sum.md b/docs/leetcode/javascript/0001._Two_Sum.md deleted file mode 100644 index d949862cb..000000000 --- a/docs/leetcode/javascript/0001._Two_Sum.md +++ /dev/null @@ -1,56 +0,0 @@ -# 001. 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)****** - -算法来源于知乎文章——[趣味算法思想](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/leetcode/javascript/0002._Add_Two_Numbers.md b/docs/leetcode/javascript/0002._Add_Two_Numbers.md deleted file mode 100644 index 42dd2529a..000000000 --- a/docs/leetcode/javascript/0002._Add_Two_Numbers.md +++ /dev/null @@ -1,74 +0,0 @@ -# 002. Add Two Numbers - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/add-two-numbers - -> 内容描述 - -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/leetcode/javascript/0003._Longest_Substring_without_Repeating_Characters.md b/docs/leetcode/javascript/0003._Longest_Substring_without_Repeating_Characters.md deleted file mode 100644 index f1b2250c3..000000000 --- a/docs/leetcode/javascript/0003._Longest_Substring_without_Repeating_Characters.md +++ /dev/null @@ -1,63 +0,0 @@ -# 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/leetcode/javascript/0005._Longest_Palindromic_Substring.md b/docs/leetcode/javascript/0005._Longest_Palindromic_Substring.md deleted file mode 100644 index 21da595e3..000000000 --- a/docs/leetcode/javascript/0005._Longest_Palindromic_Substring.md +++ /dev/null @@ -1,86 +0,0 @@ -# 0005. Longest Palindromic Substring - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -[https://leetcode-cn.com/problems/longest-palindromic-substring/](https://leetcode-cn.com/problems/longest-palindromic-substring/) - -> 内容描述 - -给定一个字符串 `s`,找到 `s` 中最长的回文子串。你可以假设 `s` 的最大长度为 1000。 - -#### 示例1: - - 输入: "babad" - 输出: "bab" - 注意: "aba" 也是一个有效答案。 - - -#### 示例2: - - 输入: "cbbd" - 输出: "bb" - - -#### 进阶: - -如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 - -## 解题方案 - -> 思路 -******- 时间复杂度: O(N)******- 空间复杂度: O(2N)****** - - -解法DP - -```javascript -/** - * @param {string} s - * @return {string} - */ -var longestPalindrome = function(s) { - let len = s.length; - if (len < 2) { - return s; - } - - dp = Array.from({length:len}).map(() => []); - -// 初始化 - for (let i = 0; i < len; i++) { - dp[i][i] = true; - } - - let maxLen = 1; - let start = 0; - - for (let j = 1; j < len; j++) { - for (let i = 0; i < j; i++) { - - if (s[i] === s[j]) { - if (j - i < 3) { - dp[i][j] = true; - } else { - dp[i][j] = dp[i + 1][j - 1]; - } - } else { - dp[i][j] = false; - } - - if (dp[i][j]) { - let curLen = j - i + 1; - if (curLen > maxLen) { - maxLen = curLen; - start = i; - } - } - } - } - return s.substring(start, start + maxLen) -}; -``` - diff --git a/docs/leetcode/javascript/0007._Reverse_Integer.md b/docs/leetcode/javascript/0007._Reverse_Integer.md deleted file mode 100644 index ad69518dd..000000000 --- a/docs/leetcode/javascript/0007._Reverse_Integer.md +++ /dev/null @@ -1,59 +0,0 @@ -# 007. 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. - -## 解题方案 - -> 思路 -******- 时间复杂度: 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/leetcode/javascript/0008._String_to_Integer.md b/docs/leetcode/javascript/0008._String_to_Integer.md deleted file mode 100644 index f830b57e6..000000000 --- a/docs/leetcode/javascript/0008._String_to_Integer.md +++ /dev/null @@ -1,94 +0,0 @@ -# 008. 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. - -``` -## 解题方案 - -> 思路 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/leetcode/javascript/0009._Palindrome_Number.md b/docs/leetcode/javascript/0009._Palindrome_Number.md deleted file mode 100644 index 0014aec66..000000000 --- a/docs/leetcode/javascript/0009._Palindrome_Number.md +++ /dev/null @@ -1,72 +0,0 @@ -# 9. Palindrome Number - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/palindrome-number - -> 内容描述 - -``` -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/leetcode/javascript/0011._Container_With_Most_Water.md b/docs/leetcode/javascript/0011._Container_With_Most_Water.md deleted file mode 100644 index 6886d4957..000000000 --- a/docs/leetcode/javascript/0011._Container_With_Most_Water.md +++ /dev/null @@ -1,71 +0,0 @@ -# 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. -``` -![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 - -> 内容描述 - -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/leetcode/javascript/0013._Roman_To_Integer.md b/docs/leetcode/javascript/0013._Roman_To_Integer.md deleted file mode 100644 index 53ebe7448..000000000 --- a/docs/leetcode/javascript/0013._Roman_To_Integer.md +++ /dev/null @@ -1,106 +0,0 @@ -# 13. Roman to Integer - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/roman-to-integer - -> 内容描述 - -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/leetcode/javascript/0014._Longest_Common_Prefix.md b/docs/leetcode/javascript/0014._Longest_Common_Prefix.md deleted file mode 100644 index 1c1f3407f..000000000 --- a/docs/leetcode/javascript/0014._Longest_Common_Prefix.md +++ /dev/null @@ -1,64 +0,0 @@ -# 014. Longest Common Prefix - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/two-sum - -> 内容描述 - -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/leetcode/javascript/0015._Three_Sum.md b/docs/leetcode/javascript/0015._Three_Sum.md deleted file mode 100644 index 5a396a35b..000000000 --- a/docs/leetcode/javascript/0015._Three_Sum.md +++ /dev/null @@ -1,74 +0,0 @@ -# 015. 3Sum - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/3sum - -> 内容描述 - -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/leetcode/javascript/0016._3_Sum_Closest.md b/docs/leetcode/javascript/0016._3_Sum_Closest.md deleted file mode 100644 index ebdf09828..000000000 --- a/docs/leetcode/javascript/0016._3_Sum_Closest.md +++ /dev/null @@ -1,66 +0,0 @@ -# 016. 3Sum Closest - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/3sum-closest - -> 内容描述 - -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/leetcode/javascript/0017._Letter_Combinations_Of_A_Phone_Number.md b/docs/leetcode/javascript/0017._Letter_Combinations_Of_A_Phone_Number.md deleted file mode 100644 index 6f9d9142c..000000000 --- a/docs/leetcode/javascript/0017._Letter_Combinations_Of_A_Phone_Number.md +++ /dev/null @@ -1,110 +0,0 @@ -# 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难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/ - -> 内容描述 - -给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。 - -示例: - - 给定一个链表: 1->2->3->4->5, 和 n = 2. - - 当删除了倒数第二个节点后,链表变为 1->2->3->5. -说明: - -给定的 n 保证是有效的。 - - - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** - -转化为数组,通过数组下标来确定删除的节点 -代码: - -```javascript -/** - * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; - * } - */ -/** - * @param {ListNode} head - * @param {number} n - * @return {ListNode} - */ -var removeNthFromEnd = function(head, n) { - if (!head || n === 0) { - return head; - } - const list = []; - let cur = head; - while (cur) { - list.push(cur); - cur = cur.next; - } - const index = list.length - n; - - if (list.length === 1 && n === 1) { - return null; - } - - if (index === 0) { - return list[1] - } else { - list[index-1].next = list[index+1]; - return list[0]; - } -}; -``` - - -> 思路2 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -使用快慢指针的方式,先让fast走n步,再让slow开始和fast一起走,当fast走完的时候,就是slow走到了正确的位置。 - -```javascript -var removeNthFromEnd = function(head, n) { - if (!head || n === 0) { - return head; - } - let dummy = new ListNode(-1); - dummy.next = head; - let fast = dummy; - let slow = dummy; - Array.from(({length:n+1})).forEach(() => { - fast = fast.next; - }) - while(fast) { - fast = fast.next; - slow = slow.next; - } - slow.next = slow.next.next; - return dummy.next; -}; - -``` diff --git a/docs/leetcode/javascript/0020._Valid_Parentheses.md b/docs/leetcode/javascript/0020._Valid_Parentheses.md deleted file mode 100644 index f990c12b6..000000000 --- a/docs/leetcode/javascript/0020._Valid_Parentheses.md +++ /dev/null @@ -1,94 +0,0 @@ -# 020. Valid Parentheses - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/two-sum - -> 内容描述 - -``` -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/leetcode/javascript/0022._Generate_Parentheses.md b/docs/leetcode/javascript/0022._Generate_Parentheses.md deleted file mode 100644 index 0ac68ce20..000000000 --- a/docs/leetcode/javascript/0022._Generate_Parentheses.md +++ /dev/null @@ -1,70 +0,0 @@ -# 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/leetcode/javascript/0024._Swap_Nodes_In_Pairs.md b/docs/leetcode/javascript/0024._Swap_Nodes_In_Pairs.md deleted file mode 100644 index 44b68dea4..000000000 --- a/docs/leetcode/javascript/0024._Swap_Nodes_In_Pairs.md +++ /dev/null @@ -1,88 +0,0 @@ -# 0024. Swap Nodes In Pairs - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/swap-nodes-in-pairs/ - -> 内容描述 - -给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 - -**你不能只是单纯的改变节点内部的值**,而是需要实际的进行节点交换。 - -  -示例: - - 给定 1->2->3->4, 你应该返回 2->1->4->3. - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -递归方式:思路主要是每次`swapPairs`返回的都是替换后的头指针,所以每次只替换两个,然后当前`head.next`指向的是移动两次指针后的`swapParis`返回结果 - -代码: - -```javascript -/** - * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; - * } - */ -/** - * @param {ListNode} head - * @return {ListNode} - */ -const swapPairs = function(head) { - if (!head || !head.next) { - return head; - } - - let root = head.next; - head.next = swapPairs(head.next.next); - root.next = head; - return root; -}; -``` - - - -> 思路 2 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -这里借鉴了Python的解题思路 -```javascript -/** - * @param {ListNode} head - * @return {ListNode} - */ -const swapPairs = function(head) { - if (!head || !head.next) { - return head; - } - - let tmp = new ListNode(); - tmp.next = head; - - let current = tmp; - while (current.next && current.next.next) { - let next1 = current.next; - let next2 = current.next.next; - let next3 = current.next.next.next; - current.next = next2; - next2.next = next1; - next1.next = next3; - current = next1; - } - - return tmp.next; -}; - -``` diff --git a/docs/leetcode/javascript/0027._Remove_Element.md b/docs/leetcode/javascript/0027._Remove_Element.md deleted file mode 100644 index b0dcfcff8..000000000 --- a/docs/leetcode/javascript/0027._Remove_Element.md +++ /dev/null @@ -1,81 +0,0 @@ -# 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难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/next-permutation/submissions/ - -> 内容描述 - -实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 - -如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 - -必须原地修改,只允许使用额外常数空间。 - -以下是一些例子,输入位于左侧列,其相应输出位于右侧列。 -`1,2,3` → `1,3,2` -`3,2,1` → `1,2,3` -`1,1,5` → `1,5,1` - - - - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -下一个排序与当前排序的关系是`尽可能多的共用前面的位数` - -以`[1,2,4,6,5,3]`为例: - -分为三个步骤 - -1. 从后向前查找,找到第一个升序排列的组合,即`[4,6]`,保存**这个位置**`2`(即`4`所在的位置) -2. 在**这个位置**上后面找到一个比他的数字进行调换——`5`,数组变为`[1,2,5,6,4,3]`,如果没有找到,则说明数组已经为最大的排列方式,直接翻转即可 -3. 对于**这个位置**后面的数组(`[6,4,2]`)进行升序排列,数组变为`[1,2,5,3,4,6]` - -代码: - -```javascript -/** - * @param {number[]} nums - * @return {void} Do not return anything, modify nums in-place instead. - */ -var nextPermutation = function(nums) { - if (!nums || !nums.length || nums.length <= 1) { - return nums - } - - let index = -1; - - // step 1: 找到最大共有位置 - for (let i = nums.length - 1; i > 0; i--) { - if (nums[i-1] < nums[i]) { - index = i - 1; - break; - } - } - - // 未找到的情况,翻转即可 - if (index === -1) { - return nums.reverse(); - } - - // step 2: 替换最大共有位置上的值 - for (let i = nums.length - 1; i > index; i--) { - if (nums[i] > nums[index]) { - [nums[i], nums[index]] = [nums[index], nums[i]] - break; - } - } - - // step 3: 最大共有位置之后的数据进行升序排列 - const afterList = nums.slice(index + 1) - afterList.reverse() - for (let i = index + 1; i < nums.length; i ++) { - nums[i] = afterList[i - index - 1] - } -}; -``` - diff --git a/docs/leetcode/javascript/0035._Search_Insert_Position.md b/docs/leetcode/javascript/0035._Search_Insert_Position.md deleted file mode 100644 index 5012bd120..000000000 --- a/docs/leetcode/javascript/0035._Search_Insert_Position.md +++ /dev/null @@ -1,62 +0,0 @@ -# 035. 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. - -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/leetcode/javascript/0053._Maximum_Subarray.md b/docs/leetcode/javascript/0053._Maximum_Subarray.md deleted file mode 100644 index 6d4139644..000000000 --- a/docs/leetcode/javascript/0053._Maximum_Subarray.md +++ /dev/null @@ -1,51 +0,0 @@ -# 053. Maximum Subarray - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -[https://leetcode-cn.com/problems/maximum-subarray/](https://leetcode-cn.com/problems/maximum-subarray/) - -> 内容描述 - -给定一个整数数组 `nums` ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 - -#### 示例: - - 输入: [-2,1,-3,4,-1,2,1,-5,4], - 输出: 6 - 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 - -#### 进阶: - -如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 - -## 解题方案 - -> 思路 -******- 时间复杂度: O(N)******- 空间复杂度: O(2N)****** - - -解法DP - -```javascript -/** - * @param {number[]} nums - * @return {number} - */ -var maxSubArray = function(nums) { - if(nums.length === 1) { - return nums[0] - } - let sum = nums[0] - let dp = nums[0] - for (let i = 1; i < nums.length; i++) { - dp = Math.max(dp + nums[i], nums[i]) - sum = Math.max(sum, dp) - } - return sum; -}; -``` - diff --git a/docs/leetcode/javascript/0054._Spiral_Matrix.md b/docs/leetcode/javascript/0054._Spiral_Matrix.md deleted file mode 100644 index 20bfc0c52..000000000 --- a/docs/leetcode/javascript/0054._Spiral_Matrix.md +++ /dev/null @@ -1,90 +0,0 @@ -# 054.Spiral Matrix - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/search-insert-position/ - -> 内容描述 - -给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 - - -**示例 1:** - -``` -输入: -[ - [ 1, 2, 3 ], - [ 4, 5, 6 ], - [ 7, 8, 9 ] -] -输出: [1,2,3,6,9,8,7,4,5] -``` - -**示例 2:** - -``` -输入: -[ - [1, 2, 3, 4], - [5, 6, 7, 8], - [9,10,11,12] -] -输出: [1,2,3,4,8,12,11,10,9,5,6,7] -``` - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** - -代码: -递归思路: - - 1. 取矩阵的第一行 - 2. 将矩阵逆时针反转90° - 3. 递归 - - -终止条件: - 矩阵为空 => 返回空矩阵 - 矩阵只剩下一行 => 返回这一行 - -```javascript -/** - * @param {number[][]} matrix - * @return {number[]} - */ -var spiralOrder = function(matrix) { - if (!matrix || !matrix.length) { - return matrix - } else if (matrix.length === 1 && Array.isArray(matrix[0])) { - return matrix[0] - } else { - return matrix.shift().concat(spiralOrder(rotate(matrix))) - } -}; - - -var rotate = function(matrix) { - if (!matrix || !matrix.length) { - return null - } - let newMatrix = [] - let m = matrix[0].length - let n = matrix.length - for (let y = m - 1; y >= 0; y--) { - let newLine = [] - for (let x = n - 1; x >= 0; x--) { - newLine.unshift(matrix[x][y]) - } - newMatrix.push(newLine); - } - return newMatrix; -} -``` - diff --git a/docs/leetcode/javascript/0055._Jump_Game.md b/docs/leetcode/javascript/0055._Jump_Game.md deleted file mode 100644 index f29e4a2ed..000000000 --- a/docs/leetcode/javascript/0055._Jump_Game.md +++ /dev/null @@ -1,68 +0,0 @@ -# 0055. Jump Game - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/jump-game/](https://leetcode-cn.com/problems/jump-game/) - -> 内容描述 - -给定一个非负整数数组,你最初位于数组的第一个位置。 - -数组中的每个元素代表你在该位置可以跳跃的最大长度。 - -判断你是否能够到达最后一个位置。 - -#### 示例1: - - 输入: [2,3,1,1,4] - 输出: true - 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 - -#### 示例2: - - 输入: [3,2,1,0,4] - 输出: false - 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 - - - -## 解题方案 - -> 思路 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - - 1. 如果数组中没有`0`,那么结果一定为`true` - 2. `reach`代表目前能跳到的最远位置(数组下标) - 3. 每轮循环,数组下标固定向有移动一位 - 4. `start`代表本轮循环的位置 - 5. 每轮循环更新一次最远可达的位置——`reach`,`reach`的值为**当前循环的值**+**当前的数组下标**与之前`reach`值的最大值 - 6. 循环终止条件: - * 当前下标值大于可达最远位置时,代表当前下标永远达到不了 - * 可达最远位置已经大于数组长度,代表已经能跳到最后位置了 - - -代码: - -```javascript -/** - * @param {number[]} nums - * @return {boolean} - */ -var canJump = function(nums) { - let start = 0; - let reach = 0; - if (nums.every(i => i)) { - return true - } - while (start <= reach && reach < nums.length - 1) { - reach = Math.max(reach, nums[start] + start); - start++; - } - return reach >= nums.length-1; -}; -``` - diff --git a/docs/leetcode/javascript/0056._Merge_Intervals.md b/docs/leetcode/javascript/0056._Merge_Intervals.md deleted file mode 100644 index 22b96ca2a..000000000 --- a/docs/leetcode/javascript/0056._Merge_Intervals.md +++ /dev/null @@ -1,57 +0,0 @@ -# 056. Merge Intervals - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/merge-intervals/ - -> 内容描述 - -给出一个区间的集合,请合并所有重叠的区间。 - -示例 1: - - 输入: [[1,3],[2,6],[8,10],[15,18]] - 输出: [[1,6],[8,10],[15,18]] - 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. - -示例 2: - - 输入: [[1,4],[4,5]] - 输出: [[1,5]] - 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(2N)******- 空间复杂度: O(N)****** - -先对输入进行排序,然后判断是存在间隔 - -代码: - -```javascript -/** - * @param {number[][]} intervals - * @return {number[][]} - */ - -var merge = function(intervals) { - if (!intervals || !intervals.length) { - return intervals; - } - intervals.sort((a, b) => (a[0] - b[0])) - return intervals.reduce((acc, [ currentLeft, currentRight ]) => { - if (currentLeft > acc[acc.length - 1][1]) { - acc.push([ currentLeft, currentRight ]); - } else if (currentRight > acc[acc.length - 1][1]){ - acc[acc.length - 1][1] = currentRight; - } - return acc; - - }, [intervals[0]]); -}; - -``` diff --git a/docs/leetcode/javascript/0058._Length_of_Last_Word.md b/docs/leetcode/javascript/0058._Length_of_Last_Word.md deleted file mode 100644 index af969273b..000000000 --- a/docs/leetcode/javascript/0058._Length_of_Last_Word.md +++ /dev/null @@ -1,49 +0,0 @@ -# 58. 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. - -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/leetcode/javascript/0061._Rotate_List.md b/docs/leetcode/javascript/0061._Rotate_List.md deleted file mode 100644 index 9a986b571..000000000 --- a/docs/leetcode/javascript/0061._Rotate_List.md +++ /dev/null @@ -1,79 +0,0 @@ -# 061. Rotate List - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/rotate-list/ - -> 内容描述 - -给定一个链表,旋转链表,将链表每个节点向右移动 `k` 个位置,其中 `k` 是非负数。 - -示例 1: - - 输入: 1->2->3->4->5->NULL, k = 2 - 输出: 4->5->1->2->3->NULL - 解释: - 向右旋转 1 步: 5->1->2->3->4->NULL - 向右旋转 2 步: 4->5->1->2->3->NULL - -示例 2: - - 输入: 0->1->2->NULL, k = 4 - 输出: 2->0->1->NULL - 解释: - 向右旋转 1 步: 2->0->1->NULL - 向右旋转 2 步: 1->2->0->NULL - 向右旋转 3 步: 0->1->2->NULL - 向右旋转 4 步: 2->0->1->NULL - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** - -将链表存储到数组中,再选择数组,然后再将数组转回链表 - -代码: - -```javascript -/** - * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; - * } - */ -/** - * @param {ListNode} head - * @param {number} k - * @return {ListNode} - */ -var rotateRight = function(head, k) { - if (!head || !head.next || k === 0) { - return head; - } - const list = []; - let cur = head; - - while (cur) { - list.push(cur) - cur = cur.next; - } - - const index = k%list.length; - list.unshift(...list.splice(list.length - index, list.length)) - list.forEach((node, index) => { - if (index < list.length) { - node.next = list[index+1] - } else { - node.next = null; - } - }) - return list[0] -}; - -``` diff --git a/docs/leetcode/javascript/0062._Unique_Paths.md b/docs/leetcode/javascript/0062._Unique_Paths.md deleted file mode 100644 index 43f256eec..000000000 --- a/docs/leetcode/javascript/0062._Unique_Paths.md +++ /dev/null @@ -1,127 +0,0 @@ -# 62. Unique Paths 不同路径 - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/unique-paths/ - -> 内容描述 - -一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 - -机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 - -问总共有多少条不同的路径? -![img](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/10/22/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 排列组合方式 - -例子中,m=7、n=3,也就是说,可以向右走6步(`m-1`)和向下走2步(`n-2`); -如果用符号`→`表示向右走,符号`↓`表示向下走,那么这道题就变成了,(m-1)个`→`和(n-1)个`↓`有多少种排列组合方式,也就是最终 -``` -计算公式:(m-1 + n-1)! ÷ ((m-1)! × (n-1)!) - -``` -自行实现阶乘计算函数——`factorial`即可 - - -代码: - -```javascript -/** - * @param {number} m - * @param {number} n - * @return {number} - */ -// 为了提高算法效率,利用cache缓存计算结果 -let cache = { - 1: 1 -} -var uniquePaths = function(m, n) { - return factorial(m + n - 2) / factorial(m - 1) / factorial(n - 1) -}; - -function factorial(num){ - if(num <= 1) { - return 1; - } else if (cache[num]) { - return cache[num] - }else{ - let value = num * factorial(num-1); - cache[num] = value; - return value - } -} - -``` - -> 思路 2 模拟矩阵 -> **- 时间复杂度: O(N)** -> -> **- 空间复杂度: O(N)** - -如果用每个格子上的值表示,当前格子到左上角格子的走法数量的话,那么右下角格子的值就是最终结果,样子如下 -| | | | -| - | - | - | -| 1 | 1 | 1 | -| 1 | 2 | 3 | -| 1 | 3 | 6 | -| 1 | 4 | 10 | -| 1 | 5 | 15 | -| 1 | 6 | 21 | -| 1 | 7 | 28 | - -发现规律,每个格子的值等于`左侧格子值 + 上方格子值`,所以用双层循环绘制表格,再去最后的值即可。 - -```javascript - -/** - * @param {number} m - * @param {number} n - * @return {number} - */ -var uniquePaths = function(m, n) { - let metrics = []; - for (let x = 0; x < m; x++) { - for (let y = 0; y < n; y++) { - if (!metrics[x]) { - metrics[x] = [] - } - if (y === 0 || x === 0) { - metrics[x][y] = 1 - } else { - metrics[x][y] = metrics[x][y - 1] + metrics[x - 1][y] - } - } - } - return metrics[m-1][n-1]; -}; -``` diff --git a/docs/leetcode/javascript/0064._Minimum_Path_Sum.md b/docs/leetcode/javascript/0064._Minimum_Path_Sum.md deleted file mode 100644 index 39cd13e84..000000000 --- a/docs/leetcode/javascript/0064._Minimum_Path_Sum.md +++ /dev/null @@ -1,70 +0,0 @@ -# 62. Unique Paths 不同路径 - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/minimum-path-sum/](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 的总和最小。 - - -## 解题方案 - -******- 时间复杂度: O(M*N)******- 空间复杂度: O(1)****** - -每个坐标的最小期望 = Min(上侧的最小期望, 左侧的最小期望) + 当前坐标值。 - -这样一次循环即可。 - -代码: - -```javascript -/** - * @param {number[][]} grid - * @return {number} - */ -var minPathSum = function(grid) { - const height = grid.length - const width = grid[0].length - if (width === 1) { - return grid.reduce((cur, pre) => (cur + pre[0]), 0) - } - if (height === 1) { - return grid[0].reduce((cur, pre) => (cur + pre), 0) - } - let min = 0 - for (let i = 0; i < width; i++) { - for (let j = 0; j < height; j++) { - if (j === 0 && i === 0) { - grid[j][i] = grid[j][i] - } else if (j === 0) { - grid[j][i] = grid[j][i] + grid[j][i - 1] - } else if (i === 0) { - grid[j][i] = grid[j][i] + grid[j - 1][i] - } else { - grid[j][i] = grid[j][i] + Math.min(grid[j][i - 1], grid[j - 1][i]) - } - min = grid[j][i] - } - } - return min -}; -``` diff --git a/docs/leetcode/javascript/0066._Plus_One.md b/docs/leetcode/javascript/0066._Plus_One.md deleted file mode 100644 index 69729733e..000000000 --- a/docs/leetcode/javascript/0066._Plus_One.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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)****** - -* 如果数字小于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/leetcode/javascript/0067._Add_Binary.md b/docs/leetcode/javascript/0067._Add_Binary.md deleted file mode 100644 index beb69a14d..000000000 --- a/docs/leetcode/javascript/0067._Add_Binary.md +++ /dev/null @@ -1,65 +0,0 @@ -# 67. Add Binary - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/add-binary - -> 内容描述 - -``` -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/leetcode/javascript/0074._Search_a_2D_Matrix.md b/docs/leetcode/javascript/0074._Search_a_2D_Matrix.md deleted file mode 100644 index dc32ab319..000000000 --- a/docs/leetcode/javascript/0074._Search_a_2D_Matrix.md +++ /dev/null @@ -1,71 +0,0 @@ -# 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/leetcode/javascript/0077._Combinations.md b/docs/leetcode/javascript/0077._Combinations.md deleted file mode 100644 index 9cf59e7b1..000000000 --- a/docs/leetcode/javascript/0077._Combinations.md +++ /dev/null @@ -1,69 +0,0 @@ -# 077. Combinations - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -[https://leetcode-cn.com/problems/combinations/](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], - ] - -#### 进阶: - -如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 - -## 解题方案 - -> 思路 -******- 时间复杂度: O(Nlogn)******- 空间复杂度: O(N)****** - - -回溯算法,算法参考:[leetCode回溯算法+剪枝](https://leetcode-cn.com/problems/combinations/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-ma-/) - -```javascript -/** - * @param {number} n - * @param {number} k - * @return {number[][]} - */ - -var combine = function(n, k) { - const result = [] - if (n <= 0 || k <= 0 || n < k) { - return result; - } - findCombinations(n, k, 1, []) - function findCombinations(n, k, index, list) { - list = [...list] - if (list.length === k) { - result.push(list); - return; - } - for (let i = index; i <= n - (k - list.length) + 1; i++) { - list.push(i); - findCombinations(n, k, i + 1, list); - list.pop(); - } - } - - return result -}; -``` - diff --git a/docs/leetcode/javascript/0079._Search_Word.md b/docs/leetcode/javascript/0079._Search_Word.md deleted file mode 100644 index 36f1b6353..000000000 --- a/docs/leetcode/javascript/0079._Search_Word.md +++ /dev/null @@ -1,107 +0,0 @@ -# 0079. Word Seach - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/word-search/ - -> 内容描述 - -给定一个二维网格和一个单词,找出该单词是否存在于网格中。 - -单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 - -示例: - - board = - [ - ['A','B','C','E'], - ['S','F','C','S'], - ['A','D','E','E'] - ] - - 给定 word = "ABCCED", 返回 true. - 给定 word = "SEE", 返回 true. - 给定 word = "ABCB", 返回 false. - - -## 解题方案 - -> 思路 -******- 时间复杂度: O(?)******- 空间复杂度: O(1)****** - -这个时间复杂度我不知道如何分析 - -思路是深度优先搜索 - -代码: - -```javascript -/** - * @param {character[][]} board - * @param {string} word - * @return {boolean} - */ -var exist = function(board, word) { - let height = board.length; - let width = board[0].length; - let result = false; - for(let x = 0; x < height; x++) { - for(let y = 0; y < width; y++) { - if (board[x][y] === word[0]) { - result = result || searchDFS(board, [ x, y ], shiftWord(word), [[x,y]]) - } - } - } - return result; -}; - -var searchDFS = function (board, [x,y], word, useList = []) { - const list = [...useList]; - let result = false; - if(!word || !word.length) { - return true; - } - - // 上 - if(x > 0 && board[x-1][y] === word[0] && !positionInList([x-1,y], list)) { - const l = [...list] - l.push([x-1, y]); - result = result || searchDFS(board, [x-1,y], shiftWord(word), l); - } - - // 下 - if (x < board.length-1 && board[x+1][y] === word[0] && !positionInList([x+1,y], list)) { - const l = [...list] - l.push([x+1, y]); - result = result || searchDFS(board, [x+1,y], shiftWord(word), l); - } - - // 左 - if (y > 0 && board[x][y-1] === word[0] && !positionInList([x,y-1], list)) { - const l = [...list] - l.push([x, y-1]); - result = result || searchDFS(board, [x,y-1], shiftWord(word), l); - } - - // 右 - if (y < board[0].length-1 && board[x][y+1] === word[0] && !positionInList([x,y+1], list)) { - const l = [...list] - l.push([x, y+1]); - result = result || searchDFS(board, [x,y+1], shiftWord(word), l); - } - - return result; -} - -var positionInList = function ([x, y], list = []) { - return list.some(([oX, oY]) => (oX === x && oY === y)) -} - -var shiftWord = function (word) { - return Array.prototype.slice.call(word, 1).join('') -} -``` diff --git a/docs/leetcode/javascript/0083._Remove_Duplicates_From_Sorted_List.md b/docs/leetcode/javascript/0083._Remove_Duplicates_From_Sorted_List.md deleted file mode 100644 index fe894d812..000000000 --- a/docs/leetcode/javascript/0083._Remove_Duplicates_From_Sorted_List.md +++ /dev/null @@ -1,148 +0,0 @@ -# 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/leetcode/javascript/0094._Binary_Tree_Inorder_Traversal.md b/docs/leetcode/javascript/0094._Binary_Tree_Inorder_Traversal.md deleted file mode 100644 index 52c029af1..000000000 --- a/docs/leetcode/javascript/0094._Binary_Tree_Inorder_Traversal.md +++ /dev/null @@ -1,106 +0,0 @@ -# 094. Binary Tree Inorder Traversal - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/binary-tree-inorder-traversal/](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/) - -> 内容描述 - -给定一个二叉树,返回它的*中序* 遍历。 - -**示例:** - -``` -输入: [1,null,2,3] - 1 - \ - 2 - / - 3 - -输出: [1,3,2] -``` - - -## 解题方案 - -> 思路 1 迭代 -> **- 时间复杂度: O(3N)** -> -> **- 空间复杂度: O(N)** - -> 执行用时 :**64 ms**, 在所有 JavaScript 提交中击败了**97.85%**的用户 -> -> 内存消耗 :**33.7 MB**, 在所有 JavaScript 提交中击败了**34.70%**的用户 - -```javascript -/** - * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; - * } - */ -/** - * @param {TreeNode} root - * @return {number[]} - */ -const inorderTraversal = node => { - const valueList = [] - forEachTree(node) - return valueList - function forEachTree (node) { - if (!node) { - return - } - forEachTree(node.left) - valueList.push(node.val) - forEachTree(node.right) - } -} -``` - - - -> 思路 2 迭代 -> -> - 时间复杂度: O(N²) -> - 空间复杂度: O(N²) - ->执行用时 :**76 ms**, 在所有 JavaScript 提交中击败了**69.05%**的用户 -> ->内存消耗 :**33.7 MB**, 在所有 JavaScript 提交中击败了**36.57%**的用户 - -```javascript -/** - * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; - * } - */ -/** - * @param {TreeNode} root - * @return {number[]} - */ -const inorderTraversal = (node) => { - const valList = [] - const stack = [] - while (node || stack.length) { - if (node) { - stack.push(node) - node = node.left - } else { - node = stack.pop() - valList.push(node.val) - node = node.right - } - } - return valList -}; -``` - diff --git a/docs/leetcode/javascript/0098._Validate_Binary_Search_Tree.md b/docs/leetcode/javascript/0098._Validate_Binary_Search_Tree.md deleted file mode 100644 index 9dd447661..000000000 --- a/docs/leetcode/javascript/0098._Validate_Binary_Search_Tree.md +++ /dev/null @@ -1,86 +0,0 @@ -# 098. Validate Binary Search Tree - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode.com/problems/validate-binary-search-tree/](https://leetcode.com/problems/validate-binary-search-tree/) - -> 内容描述 - -给定一个二叉树,判断其是否是一个有效的二叉搜索树。 - -假设一个二叉搜索树具有如下特征: - -节点的左子树只包含小于当前节点的数。 -节点的右子树只包含大于当前节点的数。 -所有左子树和右子树自身必须也是二叉搜索树。 - - -**示例 1:** - -``` -输入: - 2 - / \ - 1 3 -输出: true -``` - -**示例 2:** - -``` -输入: - 5 - / \ - 1 4 - / \ - 3 6 -输出: false -解释: 输入为: [5,1,4,null,null,3,6]。 - 根节点的值为 5 ,但是其右子节点值为 4 。 -``` - - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(2N)******- 空间复杂度: O(2N)****** - -一个思路简单的算法,二叉搜索树的中序遍历结果是个有序数组。 - -1. 获取当前二叉树的中序遍历结果数组 -2. 判断上步的数组是否是一个有序数组 - - - -代码: - -```javascript -/** - * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; - * } - */ -/** - * @param {TreeNode} root - * @return {boolean} - */ -var isValidBST = function(root) { - var list = inorderTraversal(root) - var base = list.join(',') - return base === [...new Set(list)].sort((a, b) => (a - b)).join(',') -}; - -// 获取中序遍历 -var inorderTraversal = function (root) { - if (root === null) return [] - return [...inorderTraversal(root.left), root.val, ...inorderTraversal(root.right)] -}; - -``` - diff --git a/docs/leetcode/javascript/0100._Same_Tree.md b/docs/leetcode/javascript/0100._Same_Tree.md deleted file mode 100644 index 34a3a98c8..000000000 --- a/docs/leetcode/javascript/0100._Same_Tree.md +++ /dev/null @@ -1,90 +0,0 @@ -# 100. Same Tree - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/same-tree/](https://leetcode-cn.com/problems/same-tree/) - -> 内容描述 - -给定两个二叉树,编写一个函数来检验它们是否相同。 - -如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 - - - -**示例 1:** - -``` -输入: 1 1 - / \ / \ - 2 3 2 3 - - [1,2,3], [1,2,3] - -输出: true -``` - -**示例 2:** - -``` -输入: 1 1 - / \ - 2 2 - - [1,2], [1,null,2] - -输出: false -``` - -**示例 3:** - -``` -输入: 1 1 - / \ / \ - 2 1 1 2 - - [1,2,1], [1,1,2] - -输出: false -``` - - - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -递归解法 - -1. 获取当前二叉树的中序遍历结果数组 -2. 判断上步的数组是否是一个有序数组 - -代码: - -```javascript -/** - * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; - * } - */ -/** - * @param {TreeNode} p - * @param {TreeNode} q - * @return {boolean} - */ -var isSameTree = function(p, q) { - if (p) { - return p && !!q && (p.val === q.val) && isSameTree(p.left, q.left) && isSameTree(p.right,q.right) - } else { - return !q - } -}; -``` - diff --git a/docs/leetcode/javascript/0101._Symmetric_Tree.md b/docs/leetcode/javascript/0101._Symmetric_Tree.md deleted file mode 100644 index a8cf6b4e3..000000000 --- a/docs/leetcode/javascript/0101._Symmetric_Tree.md +++ /dev/null @@ -1,77 +0,0 @@ -# 101. Symmetric Tree - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode.com/problems/symmetric-tree/](https://leetcode.com/problems/symmetric-tree/) - -> 内容描述 - -给定一个二叉树,检查它是否是镜像对称的。 - -例如,二叉树 `[1,2,2,3,4,4,3]` 是对称的。 - -``` - 1 - / \ - 2 2 - / \ / \ -3 4 4 3 -``` - -但是下面这个 `[1,2,2,null,3,null,3]` 则不是镜像对称的: - -``` - 1 - / \ - 2 2 - \ \ - 3 3 -``` - -**说明:** - -如果你可以运用递归和迭代两种方法解决这个问题,会很加分。 - - - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -递归解法 - -代码: - -```javascript -/** - * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; - * } - */ -/** - * @param {TreeNode} root - * @return {boolean} - */ -var isSymmetric = function(root) { - if (!root) { - return true - } - return isMirror(root, root) -}; - -function isMirror(t1, t2) { - if (t1 == null && t2 == null) return true; - if (t1 == null || t2 == null) return false; - return (t1.val == t2.val) - && isMirror(t1.right, t2.left) - && isMirror(t1.left, t2.right); -} -``` - diff --git a/docs/leetcode/javascript/0104._Maximum_Depth_of_Binary_Tree.md b/docs/leetcode/javascript/0104._Maximum_Depth_of_Binary_Tree.md deleted file mode 100644 index b24e3dcd4..000000000 --- a/docs/leetcode/javascript/0104._Maximum_Depth_of_Binary_Tree.md +++ /dev/null @@ -1,49 +0,0 @@ -# 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. -``` - -## 解题方案 - -> 思路 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/leetcode/javascript/0106._Construct_Binary_Tree_From_Inorder_And_Postorder_Traversal.md b/docs/leetcode/javascript/0106._Construct_Binary_Tree_From_Inorder_And_Postorder_Traversal.md deleted file mode 100644 index c454f9eaf..000000000 --- a/docs/leetcode/javascript/0106._Construct_Binary_Tree_From_Inorder_And_Postorder_Traversal.md +++ /dev/null @@ -1,54 +0,0 @@ -# 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 -******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** - -* - -代码: - -```javascript -var buildTree = function(inorder, postorder) { - if (!inorder.length || !postorder.length) { - return null - } - let rootVal = postorder[postorder.length - 1] - let root = new TreeNode(rootVal) - let k = inorder.indexOf(rootVal) - root.left = buildTree(inorder.slice(0, k), postorder.slice(0, k)) - root.right = buildTree(inorder.slice(k+1), postorder.slice(k, postorder.length - 1)) - return root -}; - -``` - diff --git a/docs/leetcode/javascript/0120._Triangle.md b/docs/leetcode/javascript/0120._Triangle.md deleted file mode 100644 index e9294e418..000000000 --- a/docs/leetcode/javascript/0120._Triangle.md +++ /dev/null @@ -1,73 +0,0 @@ -# 62. Triangle - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/minimum-path-sum/](https://leetcode-cn.com/problems/minimum-path-sum/) - -> 内容描述 - -给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 - -例如,给定三角形: - - [ - [2], - [3,4], - [6,5,7], - [4,1,8,3] - ] - -自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 - -#### 说明: - -如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。 - -## 解题方案 - -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -每个坐标的最小期望 = Min(左上的最小期望, 右上的最小期望) + 当前坐标值。 - -这样一次循环即可。 - -**Tips:** - -特殊情况: - - * 顶点的最小期望是自己 - * 最左侧的点的期望 = 当前坐标值 + 上方的值 - * 最右侧的点的期望 = 当前坐标值 + 上方的值 - -代码: - -```javascript -/** - * @param {number[][]} triangle - * @return {number} - */ -var minimumTotal = function(triangle) { - if (triangle[triangle.length - 1].length === 1) { - return triangle[0][0] - } - triangle.forEach((list, height) => { - list.forEach((n, i) => { - if (height === 0) { - triangle[height][i] = triangle[height][i] - } else if (i === 0) { - triangle[height][i] = triangle[height][i] + triangle[height - 1][0] - } else if (i === list.length - 1) { - triangle[height][i] = triangle[height][i] + triangle[height - 1][i - 1] - } else { - triangle[height][i] = triangle[height][i] + Math.min(triangle[height - 1][i], triangle[height - 1][i - 1]) - } - }) - }) - return Math.min(...triangle[triangle.length - 1]) -}; - -``` diff --git a/docs/leetcode/javascript/0121._Best_Time_To_Buy_And_Sell_Stock.md b/docs/leetcode/javascript/0121._Best_Time_To_Buy_And_Sell_Stock.md deleted file mode 100644 index 2930a8496..000000000 --- a/docs/leetcode/javascript/0121._Best_Time_To_Buy_And_Sell_Stock.md +++ /dev/null @@ -1,77 +0,0 @@ -# 0121. Best Time To Buy And Sell Stock - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/) - -> 内容描述 - -给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 - -如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 - -注意你不能在买入股票前卖出股票。 - - -#### 示例1 - - 输入: [7,1,5,3,6,4] - 输出: 5 - 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 - 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 - -#### 示例2 - - 输入: [7,6,4,3,1] - 输出: 0 - 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 - - -## 解题方案 - -> 思路1:DP -******- 时间复杂度: O(N)******- 空间复杂度: O(2N)****** - -```javascript -/** - * @param {number[]} prices - * @return {number} - */ -var maxProfit = function(prices) { - var lowestPrice = prices.shift() - var maxProfitCount = 0 - while (prices.length) { - var current = prices.shift() - lowestPrice = Math.min(lowestPrice, current) - maxProfitCount = Math.max(current - lowestPrice, maxProfitCount) - } - return maxProfitCount -}; - -``` - - - -> 思路 2: 暴力穷举法 -******- 时间复杂度: O(N²)******- 空间复杂度: O(2N)****** - -```javascript -/** - * @param {number[]} prices - * @return {number} - */ -var maxProfit = function(prices) { - var profitList = [] - while (prices.length) { - var cur = prices.shift() - profitList.push(Math.max(...prices) - cur) - } - var maxProfit = Math.max(...profitList) - return maxProfit > 0 ? maxProfit : 0 -}; - -``` diff --git a/docs/leetcode/javascript/0141._Linked_List_Cycle.md b/docs/leetcode/javascript/0141._Linked_List_Cycle.md deleted file mode 100644 index d68add337..000000000 --- a/docs/leetcode/javascript/0141._Linked_List_Cycle.md +++ /dev/null @@ -1,109 +0,0 @@ -# 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/leetcode/javascript/0146._LRU_Cache.md b/docs/leetcode/javascript/0146._LRU_Cache.md deleted file mode 100644 index 87d87dc7b..000000000 --- a/docs/leetcode/javascript/0146._LRU_Cache.md +++ /dev/null @@ -1,122 +0,0 @@ -# 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/leetcode/javascript/0167._Two_Sum_II_-_Input_array_is_sorted.md b/docs/leetcode/javascript/0167._Two_Sum_II_-_Input_array_is_sorted.md deleted file mode 100644 index c06245b1b..000000000 --- a/docs/leetcode/javascript/0167._Two_Sum_II_-_Input_array_is_sorted.md +++ /dev/null @@ -1,58 +0,0 @@ -# 167. Two Sum II - Input array is sorted - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/two-sum-ii-input-array-is-sorted - -> 内容描述 - -``` -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 - -> 内容描述 - -``` -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/leetcode/javascript/0171._Excel_Sheet_Column_Number.md b/docs/leetcode/javascript/0171._Excel_Sheet_Column_Number.md deleted file mode 100644 index fd007665e..000000000 --- a/docs/leetcode/javascript/0171._Excel_Sheet_Column_Number.md +++ /dev/null @@ -1,64 +0,0 @@ -# 0171. Excel Sheet Column Number - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/excel-sheet-column-number/ - -> 内容描述 - -给定一个Excel表格中的列名称,返回其相应的列序号。 - -例如, - - A -> 1 - B -> 2 - C -> 3 - ... - Z -> 26 - AA -> 27 - AB -> 28 - ... - -示例 1: - - 输入: "A" - 输出: 1 - -示例 2: - - 输入: "AB" - 输出: 28 - -示例 3: - - 输入: "ZY" - 输出: 701 - - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -利用parseInt可以按照进制来解析的特性,可以将英文字母轻松转换成数字 - -代码: - -```javascript -/** - * @param {string} s - * @return {number} - */ -var titleToNumber = function(s) { - if (!s) { - return 0 - } - let list = s.split('') - list = list.map((alpha, index) => (parseInt(alpha, 36) - 9) * Math.pow(26, list.length - index - 1)) - return list.reduce((acc, cur) => (acc + cur), 0) -} -``` diff --git a/docs/leetcode/javascript/0179._Largest_Number.md b/docs/leetcode/javascript/0179._Largest_Number.md deleted file mode 100644 index 4c9514ea9..000000000 --- a/docs/leetcode/javascript/0179._Largest_Number.md +++ /dev/null @@ -1,48 +0,0 @@ -# 0179. Largest Number - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/largest-number/ - -> 内容描述 - -给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。 - -示例 1: - - 输入: [10,2] - 输出: 210 -示例 2: - - 输入: [3,30,34,5,9] - 输出: 9534330 - -说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。 - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** - -排序时,计算两个数字谁在前面组成的数字比较大即可 - -代码: - -```javascript -/** - * @param {number[]} nums - * @return {string} - */ -var largestNumber = function(nums) { - if (nums.every(n => !n)) { - return '0' - } - return nums.sort((a, b) => { - return Number('' + b + a) - Number('' + a + b) - }).join('') -}; -``` diff --git a/docs/leetcode/javascript/0198._House_Robber.md b/docs/leetcode/javascript/0198._House_Robber.md deleted file mode 100644 index 1403ff6b1..000000000 --- a/docs/leetcode/javascript/0198._House_Robber.md +++ /dev/null @@ -1,64 +0,0 @@ -# 0198. House Robber - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/house-robber/](https://leetcode-cn.com/problems/house-robber/) - -> 内容描述 - -你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,**如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警**。 - -给定一个代表每个房屋存放金额的非负整数数组,计算你**在不触动警报装置的情况下**,能够偷窃到的最高金额。 - -示例 1: - - 输入: [1,2,3,1] - 输出: 4 - 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 -   偷窃到的最高金额 = 1 + 3 = 4 。 - - -示例 2: - - 输入: [2,7,9,3,1] - 输出: 12 - 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 -   偷窃到的最高金额 = 2 + 9 + 1 = 12 。 - - -## 解题方案 - -> 思路 -******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** - -DP动态规划 - -一次循环,循环到每个房间时都做一个选择:偷?还是不偷? - - * 偷:那么当前最大的收益(`DP[i]`) 为 `DP[i-2] + Vi`,其中为`Vi`代表当前房间的价值 - * 不偷:那么当前最大的收益(`DP[i]`)为`DP[i-1]` - - 所以`DP[i] = Max(DP[i-2] + Vi, DP[i-1]) ` - -代码: - -```javascript -/** - * @param {number[]} nums - * @return {number} - */ -var rob = function(nums) { - let dp = [] - if(!nums.length) { - return 0 - } - nums.forEach((n, i) => { - dp[i] = Math.max((dp[i-2] || 0) + n, (dp[i-1] || 0)) - }) - return dp[nums.length - 1] -}; -``` diff --git a/docs/leetcode/javascript/0203._Remove_Linked_List_Elements.md b/docs/leetcode/javascript/0203._Remove_Linked_List_Elements.md deleted file mode 100644 index ffce1f28c..000000000 --- a/docs/leetcode/javascript/0203._Remove_Linked_List_Elements.md +++ /dev/null @@ -1,139 +0,0 @@ -# 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/leetcode/javascript/0206._Reverse_Linked_List.md b/docs/leetcode/javascript/0206._Reverse_Linked_List.md deleted file mode 100644 index e4e4a7dbc..000000000 --- a/docs/leetcode/javascript/0206._Reverse_Linked_List.md +++ /dev/null @@ -1,120 +0,0 @@ -# 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/leetcode/javascript/0209._Minimum_Size_Subarray_Sum.md b/docs/leetcode/javascript/0209._Minimum_Size_Subarray_Sum.md deleted file mode 100644 index 06910108b..000000000 --- a/docs/leetcode/javascript/0209._Minimum_Size_Subarray_Sum.md +++ /dev/null @@ -1,80 +0,0 @@ -# 209. Minimum Size Subarray Sum - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/minimum-size-subarray-sum - -> 内容描述 - -``` -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/leetcode/javascript/0258._Add_Digits.md b/docs/leetcode/javascript/0258._Add_Digits.md deleted file mode 100644 index 95cb75971..000000000 --- a/docs/leetcode/javascript/0258._Add_Digits.md +++ /dev/null @@ -1,56 +0,0 @@ -# 258. Add Digits - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/add-digits - -> 内容描述 - -``` -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/leetcode/javascript/0320._Coin_Change.md b/docs/leetcode/javascript/0320._Coin_Change.md deleted file mode 100644 index 1587bd075..000000000 --- a/docs/leetcode/javascript/0320._Coin_Change.md +++ /dev/null @@ -1,68 +0,0 @@ -# 322. Coin Change - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/coin-change/](https://leetcode-cn.com/problems/coin-change/) - -> 内容描述 - -给定不同面额的硬币 `coins` 和一个总金额 `amount`。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 `-1`。 - -#### 示例1: - - 输入: coins = [1, 2, 5], amount = 11 - 输出: 3 - 解释: 11 = 5 + 5 + 1 - -#### 示例2: - - 输入: coins = [2], amount = 3 - 输出: -1 - - -#### 说明 - -你可以认为每种硬币的数量是无限的。 - -## 解题方案 - -******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** - -动态规划,思路参考:[链接](https://leetcode-cn.com/problems/coin-change/solution/javadi-gui-ji-yi-hua-sou-suo-dong-tai-gui-hua-by-s/) - -代码: - -```javascript -/** - * @param {number[]} coins - * @param {number} amount - * @return {number} - */ - -var coinChange = function(coins, amount) { - // 自底向上的动态规划 - if(coins.length === 0){ - return -1; - } - - // memo[n]的值: 表示的凑成总金额为n所需的最少的硬币个数 - let memo = Array.from({ length: amount+1 }); - memo[0] = 0; - for(let i = 1; i <= amount; i++){ - let min = Number.MAX_VALUE; - for(let j = 0; j < coins.length; j++){ - if(i - coins[j] >= 0 && memo[i-coins[j]] < min){ - min = memo[i-coins[j]] + 1; - } - } - // memo[i] = (min == Integer.MAX_VALUE ? Integer.MAX_VALUE : min); - memo[i] = min; - } - - return memo[amount] === Number.MAX_VALUE ? -1 : memo[amount]; -}; -``` diff --git a/docs/leetcode/javascript/0347._Top_K_Frequent_Elements.md b/docs/leetcode/javascript/0347._Top_K_Frequent_Elements.md deleted file mode 100644 index 1c56d181b..000000000 --- a/docs/leetcode/javascript/0347._Top_K_Frequent_Elements.md +++ /dev/null @@ -1,129 +0,0 @@ -# 0347. Top K Frequent Elements - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/top-k-frequent-elements/](https://leetcode-cn.com/problems/top-k-frequent-elements/) - -> 内容描述 - -给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 - - -#### 示例 1: - - 输入: nums = [1,1,1,2,2,3], k = 2 - 输出: [1,2] - -#### 示例 2: - - 输入: nums = [1], k = 1 - 输出: [1] - - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N*k)******- 空间复杂度: O(N)****** - -利用原生的sort方法, - 1. 遍历原有数组,推导出每个数字出现的频率。 - 2. 根据出现的频率,利用sort进行排序 - -代码: - -```javascript -/** - * @param {number[]} nums - * @param {number} k - * @return {number[]} - */ -var topKFrequent = function(nums, k) { - var list = {} - if (nums.length === k) { - return nums - } - while (nums.length) { - var num = nums.pop() - if (list[num]) { - list[num]++ - } else { - list[num] = 1 - } - } - - return Object.keys(list).sort((a, b) => { - return list[b] - list[a] - }).slice(0, k).map(n => Number(n)) -}; -``` - - -> 思路 2 -******- 时间复杂度: O(N*k)******- 空间复杂度: O(N)****** - -自行实现的排序方式 - 1. 遍历原有数组,推导出每个数字出现的频率。 - 2. 利用快排实现排序 - -```javascript -let partion = function(arr, left, right){ - let i = left; - let j = right; - let base = arr[left]; - while(i=base.freq && ik-1){ - quickSort(arr, left, m-1, k); - } - } -} - -let Node = function(val, freq){ - this.val = val; - this.freq = freq; -} -var topKFrequent = function(nums, k) { - let map = {}; - nums.forEach(e=>{ - if(map[e]){ - map[e].freq += 1; - }else{ - map[e] = new Node(e, 1); - } - }); - let arr = []; - for(let i in map){ - arr.push(map[i]); - } - quickSort(arr, 0, arr.length-1, k); - let res = []; - for(let i=0; i难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/remove-k-digits - -> 内容描述 - -``` -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/leetcode/javascript/0406._Queue_Reconstruction_By_Height.md b/docs/leetcode/javascript/0406._Queue_Reconstruction_By_Height.md deleted file mode 100644 index 14f0cff32..000000000 --- a/docs/leetcode/javascript/0406._Queue_Reconstruction_By_Height.md +++ /dev/null @@ -1,55 +0,0 @@ -# 406. Queue Reconstruction By Height - -**难度: medium** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/queue-reconstruction-by-height/](https://leetcode-cn.com/problems/queue-reconstruction-by-height/) - -> 内容描述 - -假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。 - -**注意:** -总人数少于1100人。 - -**示例 1:** - -``` -输入: -[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] - -输出: -[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] -``` - - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(N²)******- 空间复杂度: O(N)****** - -贪心算法 -**思路** -个子矮的人的位置不会影响到其他人,他的位置不会影响到其他人。 - -**操作步骤** - 1. 对人群排序,由高到低,身高相同再由低到高 - 2. 建立一个空队列 - 3. 对排序后的人群进行遍历,将当前遍历的人 按照他的索引(n)插入到队列第n的位置 - -代码: - -```javascript -var reconstructQueue = function(people) { - people.sort((a, b) => ((b[0] - a[0]) || (a[1] - b[1]))); - let queue = []; - people.forEach(person => { - queue.splice([person[1]], 0, person); - }) - return queue -}; -``` - diff --git a/docs/leetcode/javascript/0485._Max_Consecutive_Ones.md b/docs/leetcode/javascript/0485._Max_Consecutive_Ones.md deleted file mode 100644 index f034dca64..000000000 --- a/docs/leetcode/javascript/0485._Max_Consecutive_Ones.md +++ /dev/null @@ -1,53 +0,0 @@ -# 485. Max Consecutive Ones - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/max-consecutive-ones - -> 内容描述 - -``` -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 - -> 内容描述 - -``` -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难度: Easy** - -## 刷题内容 - -> 原题连接 - -* [https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/](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, 10,000]。 - 2. 输入的数组可能包含重复元素 ,所以升序的意思是<=。 - -## 解题方案 - -> 思路 1 -******- 时间复杂度: O(1)******- 空间复杂度: O(N)****** - -#### 省空间的算法,但是耗时间 - -每次循环,如果当前数组的第一位是最小值,则将其“弹出”;如果最后一位是最大值,则也将其“弹出”;如果以上两种情况都没有,则说明剩下的数组是最短无序连续子数组 - -代码: - -```javascript -/** - * @param {number[]} nums - * @return {number} - */ -var findUnsortedSubarray = function(nums) { - while (nums.length) { - if (nums[0] === Math.min(...nums)) { - nums.shift() - } else if (nums[nums.length - 1] === Math.max(...nums)) { - nums.pop() - } else { - return nums.length - } - } - return nums.length -}; -``` -> 思路 2 -******- 时间复杂度: O(1)******- 空间复杂度: O(2N)****** - -#### 省时间的算法,但是耗空间 - -与上面方法比较,不用每次都计算最大值和最小值 - - -```javascript -var findUnsortedSubarray = function(nums) { - const newNums = [...nums] - nums.sort((a, b) => (a - b)) - let startIndex = 0 - let endIndex = 0 -// 正向查找 - for (let i = 0; i < newNums.length; i++) { - if (nums[0] === newNums[i]) { - nums.shift() - } else { - break - } - } -// 逆向查找 - for (let j = newNums.length - 1; j > 0; j--) { - if (nums[nums.length - 1] === newNums[j]) { - nums.pop(); - } else { - break - } - } - return nums.length; -}; -``` - diff --git a/docs/leetcode/javascript/0881._Boats_to_Save_People.md b/docs/leetcode/javascript/0881._Boats_to_Save_People.md deleted file mode 100644 index f1d3cce1e..000000000 --- a/docs/leetcode/javascript/0881._Boats_to_Save_People.md +++ /dev/null @@ -1,70 +0,0 @@ -# 881. Boats to Save People - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/boats-to-save-people - -> 内容描述 - -``` -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/leetcode/javascript/0997._Find_The_Town_Judge.md b/docs/leetcode/javascript/0997._Find_The_Town_Judge.md deleted file mode 100644 index 36d41cf73..000000000 --- a/docs/leetcode/javascript/0997._Find_The_Town_Judge.md +++ /dev/null @@ -1,121 +0,0 @@ -# 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/leetcode/javascript/1025._Divisor_Game.md b/docs/leetcode/javascript/1025._Divisor_Game.md deleted file mode 100644 index 17c0434ea..000000000 --- a/docs/leetcode/javascript/1025._Divisor_Game.md +++ /dev/null @@ -1,52 +0,0 @@ -# 1025. Divisor Game - -**难度: Esay** - -## 刷题内容 - -> 原题连接 - -[https://leetcode-cn.com/problems/divisor-game/](https://leetcode-cn.com/problems/divisor-game/) - -> 内容描述 - -爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。 - -最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作: - -选出任一 x,满足 `0 < x < N` 且 `N % x == 0` 。 -用` N - x` 替换黑板上的数字` N `。 -如果玩家无法执行这些操作,就会输掉游戏。 - -只有在爱丽丝在游戏中取得胜利时才返回 `True`,否则返回 `False`。假设两个玩家都以最佳状态参与游戏。 - -#### 示例1: - - 输入:2 - 输出:true - 解释:爱丽丝选择 1,鲍勃无法进行操作。 - - -#### 示例2: - - 输入:3 - 输出:false - 解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。 - - -## 解题方案 - -> 思路 -******- 时间复杂度: O(1)******- 空间复杂度: O(1)****** - - -```javascript -/** - * @param {number} N - * @return {boolean} - */ -var divisorGame = function(N) { - return N % 2 === 0; -}; -``` - diff --git a/docs/leetcode/javascript/1130._Minimum_Cost_Tree_From_Leaf_Values.md b/docs/leetcode/javascript/1130._Minimum_Cost_Tree_From_Leaf_Values.md deleted file mode 100644 index f2cd5b40a..000000000 --- a/docs/leetcode/javascript/1130._Minimum_Cost_Tree_From_Leaf_Values.md +++ /dev/null @@ -1,80 +0,0 @@ -# 1130. Minimum Cost Tree From Leaf Values - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode-cn.com/problems/minimum-cost-tree-from-leaf-values/ - -> 内容描述 - -给你一个正整数数组 arr,考虑所有满足以下条件的二叉树: - -每个节点都有 0 个或是 2 个子节点。 -数组 arr 中的值与树的中序遍历中每个叶节点的值一一对应。(知识回顾:如果一个节点有 0 个子节点,那么该节点为叶节点。) -每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积。 -在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和。这个和的值是一个 32 位整数。 - -**示例 1:** - -``` -输入:arr = [6,2,4] -输出:32 -解释: -有两种可能的树,第一种的非叶节点的总和为 36,第二种非叶节点的总和为 32。 - - 24 24 - / \ / \ - 12 4 6 8 - / \ / \ -6 2 2 4 -``` - - **提示:** - -- `2 <= arr.length <= 40` -- `1 <= arr[i] <= 15` -- 答案保证是一个 32 位带符号整数,即小于 `2^31`。 - -## 解题方案 - -> 思路 -> **- 时间复杂度: O(N)** -> -> **- 空间复杂度: O(N)** - -> 执行用时 :**60 ms**, 在所有 javascript 提交中击败了**92.86%**的用户 -> -> 内存消耗 :**33.5 MB**, 在所有 javascript 提交中击败了**100.00%**的用户 - -代码: - -```javascript -/** - * @param {number[]} arr - * @return {number} - */ -var mctFromLeafValues = function(arr) { - if (!arr.length || arr.length < 2) { - return 0 - } - let res = 0; - let stack = []; - stack.unshift(Number.MAX_VALUE); - arr.forEach(num => { - while (stack[0] <= num) { - let mid = stack.shift() - res += mid * Math.min(stack[0], num); - } - stack.unshift(num); - }) - - while (stack.length > 2) { - res += stack.shift() * stack[0] - } - return res; -}; -``` - diff --git a/docs/leetcode/javascript/303._Range_Sum_Query_Immutable.md b/docs/leetcode/javascript/303._Range_Sum_Query_Immutable.md deleted file mode 100644 index efa72fae8..000000000 --- a/docs/leetcode/javascript/303._Range_Sum_Query_Immutable.md +++ /dev/null @@ -1,60 +0,0 @@ -# 303. Range Sum Query Immutable - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -[https://leetcode-cn.com/problems/range-sum-query-immutable/](https://leetcode-cn.com/problems/range-sum-query-immutable/) - -> 内容描述 - -给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。 - -#### 示例: - - 给定 nums = [-2, 0, 3, -5, 2, -1],求和函数为 sumRange() - - sumRange(0, 2) -> 1 - sumRange(2, 5) -> -1 - sumRange(0, 5) -> -3 - -说明: - - 1. 你可以假设数组不可变。 - 2. 会多次调用 sumRange 方法。 - - -## 解题方案 - -> 思路 -******- 时间复杂度: O(1)******- 空间复杂度: O(N)****** - - - -```javascript -/** - * @param {number[]} nums - */ -var NumArray = function(nums) { - this.value = nums -}; - -/** - * @param {number} i - * @param {number} j - * @return {number} - */ -NumArray.prototype.sumRange = function(i, j) { - return this.value.slice(i, j + 1).reduce((total, current) => total + current, 0) -}; - -/** - * Your NumArray object will be instantiated and called as such: - * var obj = new NumArray(nums) - * var param_1 = obj.sumRange(i,j) - */ - -``` - diff --git a/docs/leetcode/javascript/README.md b/docs/leetcode/javascript/README.md deleted file mode 100644 index 2ee20545c..000000000 --- a/docs/leetcode/javascript/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Leetcode JavaScript 题解 - -> 看左侧栏,开始你的表演! diff --git a/docs/leetcode/javascript/SUMMARY.md b/docs/leetcode/javascript/SUMMARY.md deleted file mode 100644 index e67ee5b41..000000000 --- a/docs/leetcode/javascript/SUMMARY.md +++ /dev/null @@ -1,58 +0,0 @@ -+ [Leetcode JavaScript 题解](README.md) -+ [0001 Two Sum](0001._Two_Sum.md) -+ [0002 Add Two Numbers](0002._Add_Two_Numbers.md) -+ [0003 Longest Substring without Repeating Characters](0003._Longest_Substring_without_Repeating_Characters.md) -+ [0007 Reverse Integer](0007._Reverse_Integer.md) -+ [0008 String to Integer](0008._String_to_Integer.md) -+ [0009 Palindrome Number](0009._Palindrome_Number.md) -+ [0011 Container With Most Water](0011._Container_With_Most_Water.md) -+ [0012 Integer To Roman](0012._Integer_To_Roman.md) -+ [0013 Roman To Integer](0013._Roman_To_Integer.md) -+ [0014 Longest Common Prefix](0014._Longest_Common_Prefix.md) -+ [0015 Three Sum](0015._Three_Sum.md) -+ [0016 3 Sum Closest](0016._3_Sum_Closest.md) -+ [0017 Letter Combinations Of A Phone Number](0017._Letter_Combinations_Of_A_Phone_Number.md) -+ [0019 Remove Nth Node From End Of List](0019._Remove_Nth_Node_From_End_Of_List.md) -+ [0020 Valid Parentheses](0020._Valid_Parentheses.md) -+ [0021 Merge Two Sorted Lists](0021._Merge_Two_Sorted_Lists.md) -+ [0022 Generate Parentheses](0022._Generate_Parentheses.md) -+ [0024 Swap Nodes In Pairs](0024._Swap_Nodes_In_Pairs.md) -+ [0027 Remove Element](0027._Remove_Element.md) -+ [0031 Next Permutation](0031._Next_Permutation.md) -+ [0035 Search Insert Position](0035._Search_Insert_Position.md) -+ [0054 Spiral Matrix](0054._Spiral_Matrix.md) -+ [0055 Jump Game](0055._Jump_Game.md) -+ [0056 Merge Intervals](0056._Merge_Intervals.md) -+ [0058 Length of Last Word](0058._Length_of_Last_Word.md) -+ [0061 Rotate List](0061._Rotate_List.md) -+ [0062 Unique Paths](0062._Unique_Paths.md) -+ [0066 Plus One](0066._Plus_One.md) -+ [0067 Add Binary](0067._Add_Binary.md) -+ [0074 Search a 2D Matrix](0074._Search_a_2D_Matrix.md) -+ [0079 Search Word](0079._Search_Word.md) -+ [0083 Remove Duplicates From Sorted List](0083._Remove_Duplicates_From_Sorted_List.md) -+ [0094 Binary Tree Inorder Traversal](0094._Binary_Tree_Inorder_Traversal.md) -+ [0098 Validate Binary Search Tree](0098._Validate_Binary_Search_Tree.md) -+ [0100 Same Tree](0100._Same_Tree.md) -+ [0101 Symmetric Tree](0101._Symmetric_Tree.md) -+ [0104 Maximum Depth of Binary Tree](0104._Maximum_Depth_of_Binary_Tree.md) -+ [0106 Construct Binary Tree From Inorder And Postorder Traversal](0106._Construct_Binary_Tree_From_Inorder_And_Postorder_Traversal.md) -+ [0141 Linked List Cycle](0141._Linked_List_Cycle.md) -+ [0146 LRU Cache](0146._LRU_Cache.md) -+ [0167 Two Sum II - Input array is sorted](0167._Two_Sum_II_-_Input_array_is_sorted.md) -+ [0167 Two Sum II Input Array is Sorted](0167._Two_Sum_II_Input_Array_is_Sorted.md) -+ [0171 Excel Sheet Column Number](0171._Excel_Sheet_Column_Number.md) -+ [0179 Largest Number](0179._Largest_Number.md) -+ [0203 Remove Linked List Elements](0203._Remove_Linked_List_Elements.md) -+ [0206 Reverse-Linked-List](0206._Reverse-Linked-List.md) -+ [0209 Minimum Size Subarray Sum](0209._Minimum_Size_Subarray_Sum.md) -+ [0258 Add Digits](0258._Add_Digits.md) -+ [0347 Top K Frequent Elements](0347._Top_K_Frequent_Elements.md) -+ [0402 Remove K Digits](0402._Remove_K_Digits.md) -+ [0406 Queue Reconstruction By Height](0406._Queue_Reconstruction_By_Height.md) -+ [0485 Max Consecutive Ones](0485._Max_Consecutive_Ones.md) -+ [0539 Minimum Time Difference](0539._Minimum_Time_Difference.md) -+ [0581 Shortest Unsorted Continuous Subarray](0581._Shortest_Unsorted_Continuous_Subarray.md) -+ [0881 Boats to Save People](0881._Boats_to_Save_People.md) -+ [0997 Find The Town Judge](0997._Find_The_Town_Judge.md) -+ [1130 Minimum Cost Tree From Leaf Values](1130._Minimum_Cost_Tree_From_Leaf_Values.md) diff --git a/docs/leetcode/javascript/book.json b/docs/leetcode/javascript/book.json deleted file mode 100644 index 212a5a79b..000000000 --- a/docs/leetcode/javascript/book.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "title" : "Pytorch 中文文档", - "author" : "ApacheCN", - "description" : "Pytorch 中文文档: 教程和文档", - "language" : "zh-hans", - "plugins": [ - "github", - "github-buttons", - "-sharing", - "insert-logo", - "sharing-plus", - "back-to-top-button", - "code", - "copy-code-button", - "mathjax", - "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/docs/Algorithm/Leetcode/JavaScript", - "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": "75439e2cbd22bdd813226000e9dcc12f" - }, - "pagefooter-apachecn": { - "copyright":"Copyright © ibooker.org.cn 2019", - "modify_label": "该文件修订时间: ", - "modify_format": "YYYY-MM-DD HH:mm:ss" - } - } -} diff --git a/docs/leetcode/python/001._two_sum.md b/docs/leetcode/python/001._two_sum.md deleted file mode 100644 index de097b037..000000000 --- a/docs/leetcode/python/001._two_sum.md +++ /dev/null @@ -1,72 +0,0 @@ -# 1. Two Sum 两数之和 - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/two-sum -* https://leetcode-cn.com/problems/two-sum - -> 内容描述 - -``` -给定 nums = [2, 7, 11, 15], target = 9 - -因为 nums[0] + nums[1] = 2 + 7 = 9 -所以返回 [0, 1] -``` - -## 解题方案 - -> 思路 1 - -我们在找两个的和是否等于某一个值。 - -如果是两两组合的笛卡尔积,相当于闭着眼碰运气,时间复杂度为: O(n^2) - -例如: - -``` -* 2+7 2+11 2+15 -* 7+11 7+15 -* 11+15 -``` - - -> 思路 2 - -如果我们换一种方式: `target - 当前数字`, 需要的另外一个变量就变成已知! - -1. 通过字典(哈希 Hash)对nums建立词库表 loopup, 时间复杂度是 0(n) -2. 判断差值是否存在 lookup 中, 时间复杂度是 0(1) -3. 所以最后的结果就是: O(n) * O(1) = O(n) - -```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: - # 为什么先后顺序是 lookup[target - num], i - # 因为当前是i,而差值只能从 lookup 中找,而 lookup 是在 i 之前面入库的 - # 所以 顺序是 lookup[target - num], i - return [lookup[target - num],i] - lookup[num] = i - return [] - - -if __name__ == "__main__": - - nums = [2, 7, 11, 15] - target = 9 - so = Solution() - n = so.twoSum(nums, target) - print("结果: ", n) -``` diff --git a/docs/leetcode/python/009._Palindrome_Number.md b/docs/leetcode/python/009._Palindrome_Number.md deleted file mode 100644 index baccde66d..000000000 --- a/docs/leetcode/python/009._Palindrome_Number.md +++ /dev/null @@ -1,103 +0,0 @@ -# 9. Palindrome Number 回文数 - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/palindrome-number -* https://leetcode-cn.com/problems/palindrome-number - -> 内容描述 - -``` -判断一个整数是否是回文数。【回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数】 - -示例 1: - -输入: 121 -输出: true - - -示例 2: - -输入: -121 -输出: false -解释: 从左向右读为 -121,从右向左读为 121-,因此它不是一个回文数 - - -示例 3: - -输入: 10 -输出: false -解释: 从右向左读为01,因此它不是一个回文数 -``` - -## 解题方案 - -> 思路1 - -* 排除小于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 - - -if __name__ == "__main__": - target = 12421 - so = Solution() - status = so.isPalindrome(target) - print("结果: ", status) -``` - - -> 思路2 - -* 排除小于0的数 -* 数字通过 % 10 求余数进行反转,进而得到最终反转的结果 -* 对比反转的结果是最初的结果是否相等 - -```python -class Solution(object): - def isPalindrome(self, x): - """ - :type x: int - :rtype: bool - """ - if x < 0: - return False - rev, y = 0, x - while x > 0: - rev = rev * 10 + x % 10 - print("余数: %s - 余数反转结果: %s" % (rev, x % 10)) - x = int(x/10) - return y == rev - - -if __name__ == "__main__": - target = 12321 - so = Solution() - n = so.isPalindrome(target) - print("结果: ", n) -""" -余数: 1 - 余数反转结果: 1 -余数: 12 - 余数反转结果: 2 -余数: 123 - 余数反转结果: 3 -余数: 1232 - 余数反转结果: 2 -余数: 12321 - 余数反转结果: 1 -结果: True -""" -``` diff --git a/docs/leetcode/python/017._letter_combinations_of_a_phone_number.md b/docs/leetcode/python/017._letter_combinations_of_a_phone_number.md deleted file mode 100644 index e951ad85d..000000000 --- a/docs/leetcode/python/017._letter_combinations_of_a_phone_number.md +++ /dev/null @@ -1,51 +0,0 @@ -### 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/leetcode/python/023._merge_k_sorted_lists.md b/docs/leetcode/python/023._merge_k_sorted_lists.md deleted file mode 100644 index 9cd97355c..000000000 --- a/docs/leetcode/python/023._merge_k_sorted_lists.md +++ /dev/null @@ -1,46 +0,0 @@ -### 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/leetcode/python/026._Remove_Duplicates_from_Sorted_Array.md b/docs/leetcode/python/026._Remove_Duplicates_from_Sorted_Array.md deleted file mode 100644 index 784ffb305..000000000 --- a/docs/leetcode/python/026._Remove_Duplicates_from_Sorted_Array.md +++ /dev/null @@ -1,84 +0,0 @@ -### 26. Remove Duplicates from Sorted Array - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* ttps://leetcode.com/problems/remove-duplicates-from-sorted-array -* https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array - -> 内容描述 - -给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 - -不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 - -示例 1: - -``` -给定数组 nums = [1,1,2], - -函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 - -你不需要考虑数组中超出新长度后面的元素。 -``` - -示例 2: - -``` -给定 nums = [0,0,1,1,1,2,2,3,3,4], - -函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 - -你不需要考虑数组中超出新长度后面的元素。 -``` - -## 解题方案 - -> 思路 1 - -因为题目说了是 `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/leetcode/python/027._Remove_Element.md b/docs/leetcode/python/027._Remove_Element.md deleted file mode 100644 index 0bed1cc89..000000000 --- a/docs/leetcode/python/027._Remove_Element.md +++ /dev/null @@ -1,55 +0,0 @@ -### 27. Remove Element - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/remove-element -* https://leetcode-cn.com/problems/remove-element/ - -> 内容描述 - -给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 - -不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 - -元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 - - -示例 1: - -``` -给定 nums = [3,2,2,3], val = 3, -函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 -你不需要考虑数组中超出新长度后面的元素。 -``` - -示例 2: - -``` -给定 nums = [0,1,2,2,3,0,4,2], val = 2, -函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 -注意这五个元素可为任意顺序。 -你不需要考虑数组中超出新长度后面的元素。 -``` - -## 解题方案 - -> 思路 1 - -瞬秒 - -```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/leetcode/python/034._Search_for_a_Range.md b/docs/leetcode/python/034._Search_for_a_Range.md deleted file mode 100644 index e5a7048b1..000000000 --- a/docs/leetcode/python/034._Search_for_a_Range.md +++ /dev/null @@ -1,77 +0,0 @@ -### 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/leetcode/python/035._search_insert_position.md b/docs/leetcode/python/035._search_insert_position.md deleted file mode 100644 index dcd4b79b1..000000000 --- a/docs/leetcode/python/035._search_insert_position.md +++ /dev/null @@ -1,81 +0,0 @@ -### 35. Search Insert Position - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/search-insert-position -* https://leetcode-cn.com/problems/search-insert-position - -> 内容描述 - -``` -给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 - -你可以假设数组中无重复元素。 - -示例 1: -输入: [1,3,5,6], 5 -输出: 2 - -示例 2: -输入: [1,3,5,6], 2 -输出: 1 - -示例 3: -输入: [1,3,5,6], 7 -输出: 4 - -示例 4: -输入: [1,3,5,6], 0 -输出: 0 -``` - -## 解题方案 - -> 思路 1: 暴力 - -```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 -``` - -> 思路 2: 二分 - -```python -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) - return mid -``` diff --git a/docs/leetcode/python/046._permutations.md b/docs/leetcode/python/046._permutations.md deleted file mode 100644 index 07e337ec3..000000000 --- a/docs/leetcode/python/046._permutations.md +++ /dev/null @@ -1,56 +0,0 @@ -### 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/leetcode/python/049._group_anagrams_python.md b/docs/leetcode/python/049._group_anagrams_python.md deleted file mode 100644 index 1371afdb4..000000000 --- a/docs/leetcode/python/049._group_anagrams_python.md +++ /dev/null @@ -1,28 +0,0 @@ -### 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/leetcode/python/050._pow(x,_n).md b/docs/leetcode/python/050._pow(x,_n).md deleted file mode 100644 index 697863e2f..000000000 --- a/docs/leetcode/python/050._pow(x,_n).md +++ /dev/null @@ -1,48 +0,0 @@ -### 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/leetcode/python/051._n-queens.md b/docs/leetcode/python/051._n-queens.md deleted file mode 100644 index 3e7c197c3..000000000 --- a/docs/leetcode/python/051._n-queens.md +++ /dev/null @@ -1,38 +0,0 @@ -### 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/leetcode/python/056._Merge_Intervals.md b/docs/leetcode/python/056._Merge_Intervals.md deleted file mode 100644 index 1f5ab7aa6..000000000 --- a/docs/leetcode/python/056._Merge_Intervals.md +++ /dev/null @@ -1,31 +0,0 @@ -### 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/leetcode/python/060._permutation_sequence.md b/docs/leetcode/python/060._permutation_sequence.md deleted file mode 100644 index 81935e253..000000000 --- a/docs/leetcode/python/060._permutation_sequence.md +++ /dev/null @@ -1,93 +0,0 @@ -###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/leetcode/python/067._add_binary.md b/docs/leetcode/python/067._add_binary.md deleted file mode 100644 index 875dc9e63..000000000 --- a/docs/leetcode/python/067._add_binary.md +++ /dev/null @@ -1,31 +0,0 @@ -###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/leetcode/python/076._Minimum_Window_Substring.md b/docs/leetcode/python/076._Minimum_Window_Substring.md deleted file mode 100644 index 1407d82d3..000000000 --- a/docs/leetcode/python/076._Minimum_Window_Substring.md +++ /dev/null @@ -1,44 +0,0 @@ -### 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/leetcode/python/079._word_search.md b/docs/leetcode/python/079._word_search.md deleted file mode 100644 index e097a4259..000000000 --- a/docs/leetcode/python/079._word_search.md +++ /dev/null @@ -1,63 +0,0 @@ -###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/leetcode/python/089._gray_code.md b/docs/leetcode/python/089._gray_code.md deleted file mode 100644 index c0a9f193c..000000000 --- a/docs/leetcode/python/089._gray_code.md +++ /dev/null @@ -1,101 +0,0 @@ -###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/leetcode/python/092._reverse_linked_list_ii.md b/docs/leetcode/python/092._reverse_linked_list_ii.md deleted file mode 100644 index f2b29da12..000000000 --- a/docs/leetcode/python/092._reverse_linked_list_ii.md +++ /dev/null @@ -1,66 +0,0 @@ -###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/leetcode/python/098._validate_binary_search_tree.md b/docs/leetcode/python/098._validate_binary_search_tree.md deleted file mode 100644 index c4b5dcfbf..000000000 --- a/docs/leetcode/python/098._validate_binary_search_tree.md +++ /dev/null @@ -1,74 +0,0 @@ -###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/leetcode/python/107._binary_tree_level_order_traversal_ii.md b/docs/leetcode/python/107._binary_tree_level_order_traversal_ii.md deleted file mode 100644 index 3ef6e4d8c..000000000 --- a/docs/leetcode/python/107._binary_tree_level_order_traversal_ii.md +++ /dev/null @@ -1,48 +0,0 @@ -###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/leetcode/python/121._Best_Time_to_Buy_and_Sell_Stock.md b/docs/leetcode/python/121._Best_Time_to_Buy_and_Sell_Stock.md deleted file mode 100644 index 23eaef0f8..000000000 --- a/docs/leetcode/python/121._Best_Time_to_Buy_and_Sell_Stock.md +++ /dev/null @@ -1,79 +0,0 @@ -# 121. Best Time to Buy and Sell Stock - -**难度: Easy** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/best-time-to-buy-and-sell-stock -* https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock - -> 内容描述 - -``` -给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 - -如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。 - -注意:你不能在买入股票前卖出股票。 - -示例 1: - -输入: [7,1,5,3,6,4] -输出: 5 -解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 - 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。 - -示例 2: - -输入: [7,6,4,3,1] -输出: 0 -解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 -``` - -## 解题方案 - -> 思路1 - -1. 找到一个最低价格的位置,记录 index -2. 找到一个最大卖出价格的位置,记录 利润 - -```py -class Solution: - def maxProfit(self, prices): - n = len(prices) - if n == 0: return 0 - - result = 0 - minprice = prices[0] - for i in range(1, n): - minprice = min(prices[i], minprice) - result = max(prices[i] - minprice, result) - return result -``` - -> 思路2 - -1. 初始化 dp,用于存放目录结果 -2. 找到最小值,计算当前最大的利润,存放到 dp中 -3. 找到 dp 以后一个元素,就是当前结果的最大值 - -```py -class Solution: - def maxProfit(self, prices): - n = len(prices) - if n == 0: return 0 - - dp = [0] * n - minprice = prices[0] - for i in range(1, n): - # 找到最小的值 - minprice = min(minprice, prices[i]) - dp[i] = max(dp[i - 1], prices[i] - minprice) - - return dp[-1] -``` - - - diff --git a/docs/leetcode/python/125._valid_palindrome.md b/docs/leetcode/python/125._valid_palindrome.md deleted file mode 100644 index d3e09f6c2..000000000 --- a/docs/leetcode/python/125._valid_palindrome.md +++ /dev/null @@ -1,46 +0,0 @@ -### 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/leetcode/python/127._word_ladder.md b/docs/leetcode/python/127._word_ladder.md deleted file mode 100644 index 42a14a7af..000000000 --- a/docs/leetcode/python/127._word_ladder.md +++ /dev/null @@ -1,43 +0,0 @@ -### 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/leetcode/python/139._word_break.md b/docs/leetcode/python/139._word_break.md deleted file mode 100644 index bfed64379..000000000 --- a/docs/leetcode/python/139._word_break.md +++ /dev/null @@ -1,77 +0,0 @@ -### 139. Word Break - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/word-break -* https://leetcode-cn.com/problems/word-break - - -> 内容描述 - -``` -给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 - -说明: -拆分时可以重复使用字典中的单词。 -你可以假设字典中没有重复的单词。 - -示例 1: -输入: s = "leetcode", wordDict = ["leet", "code"] -输出: true -解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。 - -示例 2: -输入: s = "applepenapple", wordDict = ["apple", "pen"] -输出: true -解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。 -  注意你可以重复使用字典中的单词。 - -示例 3: -输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] -输出: false -``` - - -## 解题方案 - -> 思路 1: - -``` -ok[0] = True - -catsandog => s[0:1] = c -ok[0] + s[0: 1] => False 表示 0 这个位置不可以拼接得到 - -catsandog => s[0:2] = ca -ok[0] + s[0: 2] => False 表示 0~1 这个位置不可以拼接得到 -ok[1] + s[1: 2] => False 表示 1~1 这个位置不可以拼接得到 - -catsandog => s[0:3] = cat -ok[0] + s[0: 3] => True 表示 0~2 这个位置可以拼接得到 -ok[1] + s[1: 3] => False 表示 1~2 这个位置不可以拼接得到 -ok[2] + s[2: 3] => False 表示 2~2 这个位置不可以拼接得到 - -catsandog => s[0:4] = cats -ok[0] + s[0: 4] => True 表示 0~3 这个位置可以拼接得到 -ok[1] + s[1: 4] => False 表示 1~3 这个位置不可以拼接得到 -ok[2] + s[2: 4] => False 表示 2~3 这个位置不可以拼接得到 -ok[3] + s[3: 4] => False 表示 3~3 这个位置不可以拼接得到 -``` - -```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] -``` diff --git a/docs/leetcode/python/143._reorder_list.md b/docs/leetcode/python/143._reorder_list.md deleted file mode 100644 index 59c9fb9fb..000000000 --- a/docs/leetcode/python/143._reorder_list.md +++ /dev/null @@ -1,112 +0,0 @@ -###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/leetcode/python/166._Fraction_to_Recurring_Decimal.md b/docs/leetcode/python/166._Fraction_to_Recurring_Decimal.md deleted file mode 100644 index d4285fe4b..000000000 --- a/docs/leetcode/python/166._Fraction_to_Recurring_Decimal.md +++ /dev/null @@ -1,42 +0,0 @@ -### 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/leetcode/python/198._house_robber.md b/docs/leetcode/python/198._house_robber.md deleted file mode 100644 index 2b2deedda..000000000 --- a/docs/leetcode/python/198._house_robber.md +++ /dev/null @@ -1,53 +0,0 @@ - -### 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/leetcode/python/200._number_of_islands.md b/docs/leetcode/python/200._number_of_islands.md deleted file mode 100644 index 73c5aecf4..000000000 --- a/docs/leetcode/python/200._number_of_islands.md +++ /dev/null @@ -1,130 +0,0 @@ -### 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/leetcode/python/206._reverse_linked_list.md b/docs/leetcode/python/206._reverse_linked_list.md deleted file mode 100644 index 97c10db26..000000000 --- a/docs/leetcode/python/206._reverse_linked_list.md +++ /dev/null @@ -1,69 +0,0 @@ -### 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/leetcode/python/226._invert_binary_tree.md b/docs/leetcode/python/226._invert_binary_tree.md deleted file mode 100644 index a66c2aeac..000000000 --- a/docs/leetcode/python/226._invert_binary_tree.md +++ /dev/null @@ -1,28 +0,0 @@ -### 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/leetcode/python/230._kth_smallest_element_in_a_bst.md b/docs/leetcode/python/230._kth_smallest_element_in_a_bst.md deleted file mode 100644 index 0746ef6ca..000000000 --- a/docs/leetcode/python/230._kth_smallest_element_in_a_bst.md +++ /dev/null @@ -1,48 +0,0 @@ -### 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/leetcode/python/235._lowest_common_ancestor_of_a_binary_search_tree.md b/docs/leetcode/python/235._lowest_common_ancestor_of_a_binary_search_tree.md deleted file mode 100644 index 62c1e09a5..000000000 --- a/docs/leetcode/python/235._lowest_common_ancestor_of_a_binary_search_tree.md +++ /dev/null @@ -1,33 +0,0 @@ -###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/leetcode/python/236._lowest_common_ancestor_of_a_binary_tree.md b/docs/leetcode/python/236._lowest_common_ancestor_of_a_binary_tree.md deleted file mode 100644 index 90d397641..000000000 --- a/docs/leetcode/python/236._lowest_common_ancestor_of_a_binary_tree.md +++ /dev/null @@ -1,104 +0,0 @@ - -###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/leetcode/python/252._Meeting_Rooms.md b/docs/leetcode/python/252._Meeting_Rooms.md deleted file mode 100644 index c84dee953..000000000 --- a/docs/leetcode/python/252._Meeting_Rooms.md +++ /dev/null @@ -1,47 +0,0 @@ -### 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/leetcode/python/268._missing_number.md b/docs/leetcode/python/268._missing_number.md deleted file mode 100644 index f44567eeb..000000000 --- a/docs/leetcode/python/268._missing_number.md +++ /dev/null @@ -1,49 +0,0 @@ -### 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/leetcode/python/277._Find_the_Celebrity.md b/docs/leetcode/python/277._Find_the_Celebrity.md deleted file mode 100644 index e6bc0312a..000000000 --- a/docs/leetcode/python/277._Find_the_Celebrity.md +++ /dev/null @@ -1,65 +0,0 @@ -### 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/leetcode/python/279._perfect_squares.md b/docs/leetcode/python/279._perfect_squares.md deleted file mode 100644 index ea7f612d0..000000000 --- a/docs/leetcode/python/279._perfect_squares.md +++ /dev/null @@ -1,146 +0,0 @@ -### 279. Perfect Squares - -**难度: Medium** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/perfect-squares -* https://leetcode-cn.com/problems/perfect-squares - -> 内容描述 - -``` -给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 - -示例 1: - -输入: n = 12 -输出: 3 -解释: 12 = 4 + 4 + 4. -示例 2: - -输入: n = 13 -输出: 2 -解释: 13 = 4 + 9. -``` - -## 解题方案 - -> 思路 1: 暴力破解 - -``` -求某个数的最少平方加和的个数 - -1. diff集合(小到大排序) = n - 平方根的平方的集合 -2. 每一层都在不断 - 平方根的平方 -3. 直到出现 0 代表得到结果 - -当然,你可以提前: dp.append(count) => return count, 得到最小值 - -n = 15 的时候 - -9 -4 -1 ->>> [6, 11, 14] ->>> [2, 5, 7, 10, 13] ->>> [1, 3, 4, 6, 9, 12] ->>> [0, 2, 3, 5, 8, 11] ->>> [1, 2, 4, 7, 10] ->>> [0, 1, 3, 6, 9] ->>> [0, 2, 5, 8] ->>> [1, 4, 7] ->>> [0, 3, 6] ->>> [2, 5] ->>> [1, 4] ->>> [0, 3] ->>> [2] ->>> [1] ->>> [0] ->>> [] -4 --- [4, 6, 7, 9, 12, 15] -``` - - -```python -class Solution(object): - def numSquares(self, n: int) -> int: - result = [] - count = 1 - diff_list = [n] - while len(diff_list): - diff_list = sorted(list(set([diff-i**2 for diff in diff_list for i in range(1, diff+1) if diff>=i**2]))) - # print(">>> %s" % diff_list) - if len(diff_list) < 1: - break - elif 0 in diff_list: - result.append(count) - count += 1 - # print(min(result), " --- ", result) - return min(result) if len(result)>0 else -1 -``` - -> 思路 2: 动态规划 - -``` -1. 初始化 inf 从0开始,所以数组长度 n+1 -2. 考虑到是平方,意味着他的间隔可能是跳跃性的,所以 - n = (n-j*j) + j*j - dp[i] = dp[i-1] + 1 -3. 那么 min 就是未来找到最小值而存在的,因为需要遍历很多个平方, dp[i] 用户存储最小值 -4. 返回 dp[-1] 的结果,也就是最终 n 的值 -``` - -```python -class Solution(object): - def numSquares(self, n: int) -> int: - square_nums = [i**2 for i in range(1, int(n**0.5)+1)] - dp = [float('inf')] * (n+1) - dp[0] = 0 - for i in range(1, n+1): - for square in square_nums: - if i < square: - break - # print("%s --- %s结果需要一次 --- %s结果需要%s次" % (i, square, i-square, dp[i-square])) - dp[i] = min(dp[i], dp[i-square] + 1) - return dp[-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/leetcode/python/280._Wiggle_Sort.md b/docs/leetcode/python/280._Wiggle_Sort.md deleted file mode 100644 index 3188ca405..000000000 --- a/docs/leetcode/python/280._Wiggle_Sort.md +++ /dev/null @@ -1,78 +0,0 @@ -### 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/leetcode/python/287._Find_the_Duplicate_Number.md b/docs/leetcode/python/287._Find_the_Duplicate_Number.md deleted file mode 100644 index 6b3dbd748..000000000 --- a/docs/leetcode/python/287._Find_the_Duplicate_Number.md +++ /dev/null @@ -1,177 +0,0 @@ - -# 287.Find the Duplicate Number 找到重复的数 - -### 难度:Medium - -## 刷题内容 - -> 原题链接 - - - 中文:https://leetcode-cn.com/problems/find-the-duplicate-number - - 英文:https://leetcode.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 - -实际上,我们在阅读完题目的时候,直观感觉,题目不是很难。但是,在我们看到下面的说明,也就是对我们题目的限制条件的时候,会猛然发现,题目的难度瞬间提升了好多倍。 - -下面我列出咱们需要注意的点: - - 包含 n+1 个整数的数组 - - 数组中的数字都在 1 到 n 之间(包括 1 和 n ,但是可以不连续,比如 [1,4,4,3,4]) - - 重复的数字,可以重复很多次,并不限于重复 1 次,2次,3次.. - - 不能更改原数组(这条是最要命的,原本我的想法是,我们可以排序完成之后,再进行二分查找法,碍于这个规定,无法进行) - - 只能用额外的 O(1) 的空间。(O(1) 空间的意思是不会因数组的长度改变而改变,对应本题就是不管我们的数组多长,我们能用的额外控制只能是 m 这个m 是一个确定的数,不会随着 n 的改变而改变。) - - 时间的复杂度小于 $O(n^2)$ - -注意的点差不多就是上面所说的了。 - -``` -这个思路我们使用 二分查找(binary search)+ 鸽笼原理(Pigeonhole Principle) -参考维基百科关于鸽笼原理的词条链接:https://en.wikipedia.org/wiki/Pigeonhole_principle - -"不允许修改数组" 与 "常数空间复杂度" 这两个限制条件意味着:禁止排序,并且不能使用 Map 等数据结构 - -小于 O(n^2) 的运行时间复杂度可以联想到使用二分将其中的一个 n 化简为 log n -可以参考 LeetCode Discuss:https://leetcode.com/discuss/60830/python-solution-explanation-without-changing-input-array - -二分枚举答案范围,使用鸽笼原理进行检验 - -根据鸽笼原理,给定 n+1 个范围为 [1, n]的整数,其中一定存在数字出现至少两次。 -假设枚举的数字为 n / 2 : -遍历数组,若数组中不大于 n / 2 的数字个数超过 n / 2 ,则可以确定 [1, n/2] 范围内一定有解,否则可以确定解落在 (n/2, n]范围内。 -``` - -也可以这样分析一下: -``` - -如果n 是5,那么就会有1 2 3 4 5 一共5个数字的可能,而array size 是6,那么其中一个数字肯定会至少出现两次。 - -如果没有重复的数字,小于等于1的数字 出现的次数 等于 1; - -小于等于2的数字 出现的次数 等于 2; - -... 同理3;4;5。 - -如果有重复的数字,如果重复的是1,那么 小于等于1的数字 出现的次数 肯定大于1; - -基于这个理论,我们可以在1 2 3 4 5 选出一个 mid, 遍历array来count 小于等于mid 的数字个数 小于等于 它自己mid 还是 大于 mid? - -如果count 小于等于mid, 说明 1 到 mid 这些数字 没有重复项, 重复项在 右半边 mid 到n, 所以缩小到右半边继续搜索; - -如果count 大于mid, 说明 1 到 mid 这些数字中 有重复项,缩小到 左半边继续搜索。 -``` - - -```python -class Solution(object): - def findDuplicate(self, nums): - """ - :type nums: List[int] - :rtype: int - """ - low, high = 1, len(nums) - 1 - while low <= high: - mid = (low + high) >> 1 - cnt = sum(x <= mid for x in nums) - if cnt > mid: - high = mid - 1 - else: - low = mid + 1 - return low - -s = Solution() -nums = [1,2,3,3] -print(s.findDuplicate(nums)) -``` - - 3 - - -思路 1 的解法是时间复杂度为 $O(nlogn)$ 的解法,思路 2 则是时间复杂度为 $O(n)$ ,但是相对来说,是投机取巧了些。 -> 思路 2 - -一次遍历统计,另一次遍历输出即可。 - - -```python -class Solution(object): - def findDuplicate(self, nums): - """ - :type nums: List[int] - :rtype: int - """ - dic = dict() - for n in nums: - dic[n] = dic.get(n, 0) + 1 - if dic[n] >= 2: - return n - -s = Solution() -nums = [1,2,3,3] -print(s.findDuplicate(nums)) -``` - - 3 - - -> 思路 3 - -思路 3 则是更加完整的 $O(n)$ 的解法,现在我还没有完全搞懂,我先写在下面吧,大佬们可以提前学习了解。 - - -```python -class Solution(object): - def findDuplicate(self, nums): - # The "tortoise and hare" step. We start at the end of the array and try - # to find an intersection point in the cycle. - slow = 0 - fast = 0 - - # Keep advancing 'slow' by one step and 'fast' by two steps until they - # meet inside the loop. - while True: - slow = nums[slow] - fast = nums[nums[fast]] - - if slow == fast: - break - - # Start up another pointer from the end of the array and march it forward - # until it hits the pointer inside the array. - finder = 0 - while True: - slow = nums[slow] - finder = nums[finder] - - # If the two hit, the intersection index is the duplicate element. - if slow == finder: - return slow - -s = Solution() -nums = [1,2,3,3] -print(s.findDuplicate(nums)) -``` - - 3 - diff --git a/docs/leetcode/python/300._longest_increasing_subsequence.md b/docs/leetcode/python/300._longest_increasing_subsequence.md deleted file mode 100644 index 9c59ae194..000000000 --- a/docs/leetcode/python/300._longest_increasing_subsequence.md +++ /dev/null @@ -1,41 +0,0 @@ -### 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/leetcode/python/322._Coin_Change.md b/docs/leetcode/python/322._Coin_Change.md deleted file mode 100644 index 1246fa161..000000000 --- a/docs/leetcode/python/322._Coin_Change.md +++ /dev/null @@ -1,52 +0,0 @@ -### 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 - -难度: -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/leetcode/python/341._Flatten_Nested_List_Iterator.md b/docs/leetcode/python/341._Flatten_Nested_List_Iterator.md deleted file mode 100644 index 2acc186f5..000000000 --- a/docs/leetcode/python/341._Flatten_Nested_List_Iterator.md +++ /dev/null @@ -1,47 +0,0 @@ -### 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/leetcode/python/380._Insert_Delete_GetRandom_O(1).md b/docs/leetcode/python/380._Insert_Delete_GetRandom_O(1).md deleted file mode 100644 index 401f3ee7f..000000000 --- a/docs/leetcode/python/380._Insert_Delete_GetRandom_O(1).md +++ /dev/null @@ -1,159 +0,0 @@ -### 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/leetcode/python/388._Longest_Absolute_File_Path.md b/docs/leetcode/python/388._Longest_Absolute_File_Path.md deleted file mode 100644 index 7d92da63a..000000000 --- a/docs/leetcode/python/388._Longest_Absolute_File_Path.md +++ /dev/null @@ -1,93 +0,0 @@ -### 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/leetcode/python/392._is_subsequence.md b/docs/leetcode/python/392._is_subsequence.md deleted file mode 100644 index c3f0c59f6..000000000 --- a/docs/leetcode/python/392._is_subsequence.md +++ /dev/null @@ -1,86 +0,0 @@ -# 392. Is Subsequence -**难度: 中等** - -## 刷题内容 - -> 原题连接 - -* https://leetcode.com/problems/is-subsequence - -> 内容描述 - -``` - -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/leetcode/python/400._Nth_Digit.md b/docs/leetcode/python/400._Nth_Digit.md deleted file mode 100644 index 6cc93ab3e..000000000 --- a/docs/leetcode/python/400._Nth_Digit.md +++ /dev/null @@ -1,46 +0,0 @@ -### 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/leetcode/python/463._Island_Perimeter.md b/docs/leetcode/python/463._Island_Perimeter.md deleted file mode 100644 index bedc5f8a1..000000000 --- a/docs/leetcode/python/463._Island_Perimeter.md +++ /dev/null @@ -1,38 +0,0 @@ -### 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/leetcode/python/740._delete_and_earn.md b/docs/leetcode/python/740._delete_and_earn.md deleted file mode 100644 index 3810c4b09..000000000 --- a/docs/leetcode/python/740._delete_and_earn.md +++ /dev/null @@ -1,29 +0,0 @@ -### 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/leetcode/python/844._Backspace_String_Compare.md b/docs/leetcode/python/844._Backspace_String_Compare.md deleted file mode 100644 index 4ddbd8ca1..000000000 --- a/docs/leetcode/python/844._Backspace_String_Compare.md +++ /dev/null @@ -1,38 +0,0 @@ -### 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/leetcode/python/README.md b/docs/leetcode/python/README.md deleted file mode 100644 index 465802ab2..000000000 --- a/docs/leetcode/python/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Leetcode Python 题解 - -> 看左侧栏,开始你的表演! diff --git a/docs/leetcode/python/SUMMARY.md b/docs/leetcode/python/SUMMARY.md deleted file mode 100644 index e591c1dce..000000000 --- a/docs/leetcode/python/SUMMARY.md +++ /dev/null @@ -1,302 +0,0 @@ -+ [Leetcode Python 题解](README.md) -+ [001 two sum](001._two_sum.md) -+ [002 add two numbers](002._add_two_numbers.md) -+ [003 longest substring without repeating characters](003._longest_substring_without_repeating_characters.md) -+ [004 median of two sorted arrays](004._median_of_two_sorted_arrays.md) -+ [005 longest palindromic substring](005._longest_palindromic_substring.md) -+ [006 ZigZag Conversion](006._ZigZag_Conversion.md) -+ [007 Reverse Integer](007._Reverse_Integer.md) -+ [008 string to integer (atoi)](008._string_to_integer_(atoi).md) -+ [009 Palindrome Number](009._Palindrome_Number.md) -+ [010 regular expression matching](010._regular_expression_matching.md) -+ [011 container with most water](011._container_with_most_water.md) -+ [012 Integer to Roman](012._Integer_to_Roman.md) -+ [013 Roman to Integer](013._Roman_to_Integer.md) -+ [014 longest common prefix](014._longest_common_prefix.md) -+ [015 3sum](015._3sum.md) -+ [016 3sum closest](016._3sum_closest.md) -+ [017 letter combinations of a phone number](017._letter_combinations_of_a_phone_number.md) -+ [018 4sum](018._4sum.md) -+ [019 remove nth node from end of list](019._remove_nth_node_from_end_of_list.md) -+ [020 valid parentheses](020._valid_parentheses.md) -+ [021 merge two sorted lists](021._merge_two_sorted_lists.md) -+ [022 generate parentheses](022._generate_parentheses.md) -+ [023 merge k sorted lists](023._merge_k_sorted_lists.md) -+ [024 swap nodes in pairs](024._swap_nodes_in_pairs.md) -+ [026 Remove Duplicates from Sorted Array](026._Remove_Duplicates_from_Sorted_Array.md) -+ [027 Remove Element](027._Remove_Element.md) -+ [028 implement strstr()](028._implement_strstr.md) -+ [030 Substring with Concatenation of All Words](030._Substring_with_Concatenation_of_All_Words.md) -+ [031 next permutation](031._next_permutation.md) -+ [032 longest valid parentheses](032._longest_valid_parentheses.md) -+ [033 search in rotated sorted array](033._search_in_rotated_sorted_array.md) -+ [034 Search for a Range](034._Search_for_a_Range.md) -+ [035 search insert position](035._search_insert_position.md) -+ [038 Count and Say](038._Count_and_Say.md) -+ [039 combination sum](039._combination_sum.md) -+ [040 combination sum ii](040._combination_sum_ii.md) -+ [041 First Missing Positive](041._First_Missing_Positive.md) -+ [042 trapping rain water](042._trapping_rain_water.md) -+ [043 multiply strings](043._multiply_strings.md) -+ [044 wildcard matching](044._wildcard_matching.md) -+ [045 Jump Game II](045._Jump_Game_II.md) -+ [046 permutations](046._permutations.md) -+ [047 permutations ii](047._permutations_ii.md) -+ [048 rotate image](048._rotate_image.md) -+ [049 group anagrams python](049._group_anagrams_python.md) -+ [050 pow(x, n)](050._pow(x,_n).md) -+ [051 n-queens](051._n-queens.md) -+ [052 n-queens ii](052._n-queens_ii.md) -+ [053 maximum subarray](053._maximum_subarray.md) -+ [054 spiral matrix](054._spiral_matrix.md) -+ [055 jump game](055._jump_game.md) -+ [056 Merge Intervals](056._Merge_Intervals.md) -+ [058 length of last word](058._length_of_last_word.md) -+ [059 spiral matrix ii](059._spiral_matrix_ii.md) -+ [060 permutation sequence](060._permutation_sequence.md) -+ [061 rotate list](061._rotate_list.md) -+ [062 unique paths](062._unique_paths.md) -+ [064 minimum path sum](064._minimum_path_sum.md) -+ [065 unique paths ii](065.unique_paths_ii.md) -+ [066 plus one](066._plus_one.md) -+ [067 add binary](067._add_binary.md) -+ [069 sqrt(x)](069._sqrt(x).md) -+ [070 Climbing Stairs](070._Climbing_Stairs.md) -+ [072 edit distance](072._edit_distance.md) -+ [073 Set Matrix Zeroes](073._Set_Matrix_Zeroes.md) -+ [074 search a 2d matrix](074._search_a_2d_matrix.md) -+ [075 sort colors](075._sort_colors.md) -+ [076 Minimum Window Substring](076._Minimum_Window_Substring.md) -+ [077 combinations](077._combinations.md) -+ [078 Subsets](078._Subsets.md) -+ [079 word search](079._word_search.md) -+ [082 remove duplicates from sorted list ii](082._remove_duplicates_from_sorted_list_ii.md) -+ [083 remove duplicates from sorted list](083._remove_duplicates_from_sorted_list.md) -+ [086 partition list](086._partition_list.md) -+ [088 merge sorted array](088._merge_sorted_array.md) -+ [089 gray code](089._gray_code.md) -+ [090 subsets ii](090._subsets_ii.md) -+ [091 decode ways](091._decode_ways.md) -+ [092 reverse linked list ii](092._reverse_linked_list_ii.md) -+ [093 restore ip addresses](093._restore_ip_addresses.md) -+ [094 binary tree inorder traversal](094._binary_tree_inorder_traversal.md) -+ [096 unique binary search trees](096._unique_binary_search_trees.md) -+ [098 validate binary search tree](098._validate_binary_search_tree.md) -+ [100 same tree](100._same_tree.md) -+ [101 symmetric tree](101._symmetric_tree.md) -+ [102 binary tree level order traversal](102._binary_tree_level_order_traversal.md) -+ [103 binary tree zigzag level order traversal](103._binary_tree_zigzag_level_order_traversal.md) -+ [104 maximum depth of binary tree](104._maximum_depth_of_binary_tree.md) -+ [105 construct binary tree from preorder and inorder traversal](105._construct_binary_tree_from_preorder_and_inorder_traversal.md) -+ [106 construct binary tree from inorder and postorder traversal](106._construct_binary_tree_from_inorder_and_postorder_traversal.md) -+ [107 binary tree level order traversal ii](107._binary_tree_level_order_traversal_ii.md) -+ [108 convert sorted array to binary search tree](108._convert_sorted_array_to_binary_search_tree.md) -+ [109 convert sorted list to binary search tree](109._convert_sorted_list_to_binary_search_tree.md) -+ [110 balanced binary tree](110._balanced_binary_tree.md) -+ [111 minimum depth of binary tree](111._minimum_depth_of_binary_tree.md) -+ [112 path sum](112._path_sum.md) -+ [113 path sum ii](113._path_sum_ii.md) -+ [114 flatten binary tree to linked list](114._flatten_binary_tree_to_linked_list.md) -+ [116 populating next right pointers in each node](116._populating_next_right_pointers_in_each_node.md) -+ [117 Populating Next Right Pointers in Each Node II](117._Populating_Next_Right_Pointers_in_Each_Node_II.md) -+ [118 pascal's triangle](118._pascal's_triangle.md) -+ [119 Pascal's Triangle II](119._Pascal's_Triangle_II.md) -+ [120 Triangle](120._Triangle.md) -+ [121 Best Time to Buy and Sell Stock](121._Best_Time_to_Buy_and_Sell_Stock.md) -+ [124 Binary Tree Maximum Path Sum](124._Binary_Tree_Maximum_Path_Sum.md) -+ [125 valid palindrome](125._valid_palindrome.md) -+ [126 Word Ladder II](126._Word_Ladder_II.md) -+ [127 word ladder](127._word_ladder.md) -+ [128 Longest Consecutive Sequence](128._Longest_Consecutive_Sequence.md) -+ [129 sum root to leaf numbers](129._sum_root_to_leaf_numbers.md) -+ [130 surrounded regions](130._surrounded_regions.md) -+ [131 palindrome partitioning](131._palindrome_partitioning.md) -+ [133 clone graph](133._clone_graph.md) -+ [136 single number](136._single_number.md) -+ [139 word break](139._word_break.md) -+ [140 word break ii](140._word_break_ii.md) -+ [141 linked list cycle](141._linked_list_cycle.md) -+ [142_Linked_List_Cycle_II md](142_Linked_List_Cycle_II.md) -+ [143 reorder list](143._reorder_list.md) -+ [144 binary tree preorder traversal](144._binary_tree_preorder_traversal.md) -+ [145 binary tree postorder traversal](145._binary_tree_postorder_traversal.md) -+ [147 insertion sort list](147._insertion_sort_list.md) -+ [148 sort list](148._sort_list.md) -+ [150 evaluate reverse polish notation](150._evaluate_reverse_polish_notation.md) -+ [151 reverse words in a string](151._reverse_words_in_a_string.md) -+ [152 maximum product subarray](152._maximum_product_subarray.md) -+ [153 find minimum in rotated sorted array](153._find_minimum_in_rotated_sorted_array.md) -+ [155 min stack](155._min_stack.md) -+ [157 Read N Characters Given Read4](157._Read_N_Characters_Given_Read4.md) -+ [158 Read N Characters Given Read4 II - Call multiple times](158._Read_N_Characters_Given_Read4_II_-_Call_multiple_times.md) -+ [159 Longest Substring with At Most Two Distinct Characters](159._Longest_Substring_with_At_Most_Two_Distinct_Characters.md) -+ [160 intersection of two linked lists](160._intersection_of_two_linked_lists.md) -+ [162 find peak element](162._find_peak_element.md) -+ [165 compare version numbers](165._compare_version_numbers.md) -+ [166 Fraction to Recurring Decimal](166._Fraction_to_Recurring_Decimal.md) -+ [167 two sum ii - input array is sorted](167._two_sum_ii_-_input_array_is_sorted.md) -+ [168 excel sheet column title](168._excel_sheet_column_title.md) -+ [169 majority element](169._majority_element.md) -+ [171 excel sheet column number](171._excel_sheet_column_number.md) -+ [173 binary search tree iterator](173._binary_search_tree_iterator.md) -+ [179 Largest Number](179._Largest_Number.md) -+ [182 duplicate emails](182._duplicate_emails.md) -+ [189 rotate array](189._rotate_array.md) -+ [191 number of 1 bits](191._number_of_1_bits.md) -+ [198 house robber](198._house_robber.md) -+ [199 binary tree right side view](199._binary_tree_right_side_view.md) -+ [200 number of islands](200._number_of_islands.md) -+ [203 remove linked list elements](203._remove_linked_list_elements.md) -+ [204 count primes](204._count_primes.md) -+ [205 isomorphic strings](205._isomorphic_strings.md) -+ [206 reverse linked list](206._reverse_linked_list.md) -+ [207 course schedule](207._course_schedule.md) -+ [208 implement trie (prefix tree)](208._implement_trie_(prefix_tree).md) -+ [210 course schedule ii](210._course_schedule_ii.md) -+ [211 Add and Search Word - Data structure design](211._Add_and_Search_Word_-_Data_structure_design.md) -+ [213 house robber ii](213._house_robber_ii.md) -+ [216 combination sum iii](216._combination_sum_iii.md) -+ [217 contains duplicate](217._contains_duplicate.md) -+ [218 The Skyline Problem](218._The_Skyline_Problem.md) -+ [219 contains duplicate ii](219._contains_duplicate_ii.md) -+ [221 maximal square](221._maximal_square.md) -+ [222 count complete tree nodes](222._count_complete_tree_nodes.md) -+ [223 rectangle area](223._rectangle_area.md) -+ [224 Basic Calculator](224._Basic_Calculator.md) -+ [225 implement stack using queues](225._implement_stack_using_queues.md) -+ [226 invert binary tree](226._invert_binary_tree.md) -+ [227 basic calculator ii](227._basic_calculator_ii.md) -+ [228 summary ranges](228._summary_ranges.md) -+ [229 majority element ii](229._majority_element_ii.md) -+ [230 kth smallest element in a bst](230._kth_smallest_element_in_a_bst.md) -+ [231 Power of Two](231._Power_of_Two.md) -+ [232 implement queue using stacks](232._implement_queue_using_stacks.md) -+ [234 palindrome linked list](234._palindrome_linked_list.md) -+ [235 lowest common ancestor of a binary search tree](235._lowest_common_ancestor_of_a_binary_search_tree.md) -+ [236 lowest common ancestor of a binary tree](236._lowest_common_ancestor_of_a_binary_tree.md) -+ [237 delete node in a linked list](237._delete_node_in_a_linked_list.md) -+ [238 product of array except self](238._product_of_array_except_self.md) -+ [240 search a 2d matrix ii](240._search_a_2d_matrix_ii.md) -+ [242 valid anagram](242._valid_anagram.md) -+ [249 Group Shifted Strings](249._Group_Shifted_Strings.md) -+ [252 Meeting Rooms](252._Meeting_Rooms.md) -+ [255 Verify Preorder Sequence in Binary Search Tree](255._Verify_Preorder_Sequence_in_Binary_Search_Tree.md) -+ [256 Paint House](256._Paint_House.md) -+ [257 binary tree paths](257._binary_tree_paths.md) -+ [258_ Add_Digits md](258._Add_Digits.md) -+ [261 Graph Valid Tree](261._Graph_Valid_Tree.md) -+ [263 ugly number](263._ugly_number.md) -+ [264 ugly number ii](264._ugly_number_ii.md) -+ [265 Paint House II](265._Paint_House_II.md) -+ [266 Palindrome Permutation](266._Palindrome_Permutation.md) -+ [267 Palindrome Permutation II](267._Palindrome_Permutation_II.md) -+ [268 missing number](268._missing_number.md) -+ [270 Closest Binary Search Tree Value](270._Closest_Binary_Search_Tree_Value.md) -+ [276 Paint Fence](276._Paint_Fence.md) -+ [277 Find the Celebrity](277._Find_the_Celebrity.md) -+ [278 First Bad Version](278._First_Bad_Version.md) -+ [279 perfect squares](279._perfect_squares.md) -+ [280 Wiggle Sort](280._Wiggle_Sort.md) -+ [283 move zeroes](283._move_zeroes.md) -+ [285 inorder successor in bst](285._inorder_successor_in_bst.md) -+ [286 Walls and Gates](286._Walls_and_Gates.md) -+ [287 Find the Duplicate Number](287._Find_the_Duplicate_Number.md) -+ [289 game of life](289._game_of_life.md) -+ [290 word pattern](290._word_pattern.md) -+ [292 nim game](292._nim_game.md) -+ [293 Flip Game](293._Flip_Game.md) -+ [296 Best Meeting Point](296._Best_Meeting_Point.md) -+ [298 Binary Tree Longest Consecutive Sequence](298._Binary_Tree_Longest_Consecutive_Sequence.md) -+ [299 bulls and cows](299._bulls_and_cows.md) -+ [300 longest increasing subsequence](300._longest_increasing_subsequence.md) -+ [303 range sum query - immutable](303._range_sum_query_-_immutable.md) -+ [316 Remove Duplicate Letters](316._Remove_Duplicate_Letters.md) -+ [319 Bulb Switcher](319._Bulb_Switcher.md) -+ [322 Coin Change](322._Coin_Change.md) -+ [323 number of connected components in an undirected graph](323._number_of_connected_components_in_an_undirected_graph.md) -+ [324 Wiggle Sort II](324._Wiggle_Sort_II.md) -+ [326 power of three](326._power_of_three.md) -+ [328 odd even linked list](328._odd_even_linked_list.md) -+ [334 increasing triplet subsequence](334._increasing_triplet_subsequence.md) -+ [337 house robber iii](337._house_robber_iii.md) -+ [338 Counting Bits](338._Counting_Bits.md) -+ [339 Nested List Weight Sum](339._Nested_List_Weight_Sum.md) -+ [341 Flatten Nested List Iterator](341._Flatten_Nested_List_Iterator.md) -+ [342 Power of Four](342._Power_of_Four.md) -+ [344 reverse string](344._reverse_string.md) -+ [345 Reverse Vowels of a String](345._Reverse_Vowels_of_a_String.md) -+ [349 intersection of two arrays](349._intersection_of_two_arrays.md) -+ [350 intersection of two arrays ii](350._intersection_of_two_arrays_ii.md) -+ [353 Design Snake Game](353._Design_Snake_Game.md) -+ [361 Bomb Enemy](361._Bomb_Enemy.md) -+ [364 Nested List Weight Sum II](364._Nested_List_Weight_Sum_II.md) -+ [366 Find Leaves of Binary Tree](366._Find_Leaves_of_Binary_Tree.md) -+ [367 valid perfect square](367._valid_perfect_square.md) -+ [369 Plus One Linked List](369._Plus_One_Linked_List.md) -+ [371 sum of two integers](371._sum_of_two_integers.md) -+ [374 Guess Number Higher or Lower](374._Guess_Number_Higher_or_Lower.md) -+ [377 combination sum iv](377._combination_sum_iv.md) -+ [378 kth smallest element in a sorted matrix](378._kth_smallest_element_in_a_sorted_matrix.md) -+ [380 Insert Delete GetRandom O(1)](380._Insert_Delete_GetRandom_O(1).md) -+ [381 Insert Delete GetRandom O(1) - Duplicates allowed](381._Insert_Delete_GetRandom_O(1)_-_Duplicates_allowed.md) -+ [382 linked list random node](382._linked_list_random_node.md) -+ [383 ransom note](383._ransom_note.md) -+ [384 Shuffle an Array](384._Shuffle_an_Array.md) -+ [386 Lexicographical Numbers](386._Lexicographical_Numbers.md) -+ [387 first unique character in a string](387._first_unique_character_in_a_string.md) -+ [388 Longest Absolute File Path](388._Longest_Absolute_File_Path.md) -+ [389 find the difference](389._find_the_difference.md) -+ [392 is subsequence](392._is_subsequence.md) -+ [394 decode string](394._decode_string.md) -+ [400 Nth Digit](400._Nth_Digit.md) -+ [401 binary watch](401._binary_watch.md) -+ [404 sum of left leaves](404._sum_of_left_leaves.md) -+ [405 Convert a Number to Hexadecimal](405._Convert_a_Number_to_Hexadecimal.md) -+ [406 Queue Reconstruction by Height](406._Queue_Reconstruction_by_Height.md) -+ [412 fizz buzz](412._fizz_buzz.md) -+ [413 Arithmetic Slices](413._Arithmetic_Slices.md) -+ [414 third maximum number](414._third_maximum_number.md) -+ [415 add strings](415._add_strings.md) -+ [416 Partition Equal Subset Sum](416._Partition_Equal_Subset_Sum.md) -+ [421 Maximum XOR of Two Numbers in an Array](421._Maximum_XOR_of_Two_Numbers_in_an_Array.md) -+ [422 Valid Word Square](422._Valid_Word_Square.md) -+ [434 number of segments in a string](434._number_of_segments_in_a_string.md) -+ [435 Non-overlapping Intervals](435._Non-overlapping_Intervals.md) -+ [437 path sum iii](437._path_sum_iii.md) -+ [438 Find All Anagrams in a String](438._Find_All_Anagrams_in_a_String.md) -+ [439 Ternary Expression Parser](439._Ternary_Expression_Parser.md) -+ [441 arranging coins](441._arranging_coins.md) -+ [448 Find All Numbers Disappeared in an Array](448._Find_All_Numbers_Disappeared_in_an_Array.md) -+ [450 Delete Node in a BST](450._Delete_Node_in_a_BST.md) -+ [453 Minimum Moves to Equal Array Elements](453._Minimum_Moves_to_Equal_Array_Elements.md) -+ [459 Repeated Substring Pattern](459._Repeated_Substring_Pattern.md) -+ [461 Hamming Distance](461._Hamming_Distance.md) -+ [463 Island Perimeter](463._Island_Perimeter.md) -+ [467 Unique Substrings in Wraparound String](467._Unique_Substrings_in_Wraparound_String.md) -+ [469 Convex Polygon](469._Convex_Polygon.md) -+ [476 Number Complement](476._Number_Complement.md) -+ [477 Total Hamming Distance](477._Total_Hamming_Distance.md) -+ [485 Max Consecutive Ones](485._Max_Consecutive_Ones.md) -+ [494 Target Sum](494._Target_Sum.md) -+ [536 Construct Binary Tree from String](536._Construct_Binary_Tree_from_String.md) -+ [587 Erect the Fence](587._Erect_the_Fence.md) -+ [599 Minimum Index Sum of Two Lists](599._Minimum_Index_Sum_of_Two_Lists.md) -+ [606 Construct String from Binary Tree](606._Construct_String_from_Binary_Tree.md) -+ [611 Valid Triangle Number](611._Valid_Triangle_Number.md) -+ [646 Maximum Length of Pair Chain](646._Maximum_Length_of_Pair_Chain.md) -+ [647 Palindromic Substrings](647._Palindromic_Substrings.md) -+ [657 Judge Route Circle](657._Judge_Route_Circle.md) -+ [665 Non-decreasing Array](665._Non-decreasing_Array.md) -+ [672 Bulb Switcher II](672._Bulb_Switcher_II.md) -+ [681 Next Closest Time](681._Next_Closest_Time.md) -+ [682 Baseball Game](682._Baseball_Game.md) -+ [685 Redundant Connection II](685._Redundant_Connection_II.md) -+ [687 Longest Univalue Path](687._Longest_Univalue_Path.md) -+ [693 Binary Number with Alternating Bits](693._Binary_Number_with_Alternating_Bits.md) -+ [701 Insert into a Binary Search Tree](701._Insert_into_a_Binary_Search_Tree.md) -+ [707 Design Linked List](707._Design_Linked_List.md) -+ [740 delete and earn](740._delete_and_earn.md) -+ [760 Find Anagram Mappings](760._Find_Anagram_Mappings.md) -+ [774 Minimize Max Distance to Gas Station](774._Minimize_Max_Distance_to_Gas_Station.md) -+ [777 Swap Adjacent in LR String](777._Swap_Adjacent_in_LR_String.md) -+ [844 Backspace String Compare](844._Backspace_String_Compare.md) diff --git a/docs/think-dast-zh/0.md b/docs/think-dast-zh/0.md deleted file mode 100644 index 06b294ed1..000000000 --- a/docs/think-dast-zh/0.md +++ /dev/null @@ -1,83 +0,0 @@ -# 前言 - -> 原文:[Preface](http://greenteapress.com/thinkdast/html/thinkdast001.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -## 本书背后的哲学 - -数据结构和算法是过去 50 年来最重要的发明之一,它们是软件工程师需要了解的基础工具。但是在我看来,这些话题的大部分书籍都过于理论,过于庞大,也是“自底向上”的: - -过于理论 - -算法的数学分析基于许多简化假设,它们限制了实践中的可用性。这个话题的许多描述都掩盖了简化,并专注于数学。在这本书中,我介绍了这个话题的最实际的子集,并省略或不强调其余的内容。 - -过于庞大 - -这些话题的大多数书籍至少有 500 页,有些超过 1000 页。通过关注我认为对软件工程师最有用的话题,我把这本书限制在 200 页以下。 - -过于“自底向上” - -许多数据结构的书籍着重于数据结构如何工作(实现),而不是使用它们(接口)。在这本书中,我从接口开始,“自顶向下”。读者在学习如何使用 Java 集合框架中的结构之后,再了解它们的工作原理。 - -最后,有些书将这个材料展示在上下文之外,缺少动机:这只是另一个数据结构!我试图使之生动起来,通过围绕一个应用 - 网页搜索 - 来组织这些话题,它广泛使用数据结构,并且是一个有趣和重要的话题。 - -这个应用激发了一些话题,通常不会在介绍性数据结构的课中涵盖,包括 Redis 的持久化数据结构。 - - -我已经做出了一些艰难的决定,来进行取舍,但我也做了一些妥协。我包括了大多数读者永远不会使用的一些话题,但是可能在技术面试中,你需要知道这些话题。对于这些话题,我提出了传统的观点和我怀疑的理由。 - -本书还介绍了软件工程实践的基本方面,包括版本控制和单元测试。大多数章节都包括一个练习,允许读者应用他们学到的内容。每个练习都提供自动化测试,来检查解决方案。对于大多数练习,我在下一章的开头展示我的解决方案。 - -### 0.1 预备条件 - -本书面向计算机科学及相关领域的大学生,专业软件工程师,软件工程培训人员和技术面试准备人员。 - -在你开始读这本书之前,你应该很熟悉 Java,尤其应该知道如何定义一个扩展现有类的新类,或实现一个`interface`。如果你不熟悉 Java 了,这里有两本书可以用于起步: - -+ Downey 和 Mayfield,《Think Java》(O'Reilly Media,2016),它面向以前从未编程过的人。 -+ Sierra 和 Bates,《Head First Java》(O'Reilly Media,2005),它适用于已经知道另一种编程语言的人。 - -如果你不熟悉 Java 中的接口,你可能需要在 上完成一个名为“什么是接口”的教程 。 - -一个词汇注解:“接口”这个词可能会令人困惑。在应用编程接口(API)的上下文中,它指代一组提供某些功能的类和方法。 - -在 Java 的上下文中,它还指代一个与类相似的语言特性,它规定了一组方法。为了避免混淆,我将使用正常字体中的“接口”来表示接口的一般思想,代码字体的`interface`用于 Java 语言特性。 - -你还应该熟悉类型参数和泛型类型。例如,你应该知道如何使用类型参数创建对象,如`ArrayList`。如果不是,你可以在 上了解类型参数。 - -你应该熟悉 Java 集合框架(JCF​​),你可以阅读 。特别是,你应该知道`List interface`,以及`ArrayList`和`LinkedList`类。 - -理想情况下,你应该熟悉 Apache Ant,它是 Java 的自动化构建工具。你可以在 上阅读 Ant 的更多信息。 - -你应该熟悉 JUnit,它是 Java 的单元测试框架。你可以在 上阅读更多信息。 - -## 处理代码 - -本书的代码位于 上的 Git 仓库中 。 - -Git 是一个“版本控制系统”,允许你跟踪构成项目的文件。Git 控制下的文件集合称为“仓库”。 - -GitHub 是一个托管服务,为 Git 仓库提供存储和方便的 Web 界面。它提供了几种使用代码的方法: - -+ 你可以通过按下`Fork`(派生)按钮,在 GitHub 上创建仓库的副本。如果你还没有 GitHub 帐户,则需要创建一个。派生之后,你可以在 GitHub 上拥有你自己的仓库,你可以使用它们来跟踪你编写的代码。然后,你可以“克隆”仓库,它将文件的副本下载到你的计算机。 -+ 或者,你可以克隆仓库而不进行派生。如果你选择此选项,则不需要 GitHub 帐户,但你无法将更改保存在 GitHub 上。 -+ 如果你不想使用 Git,你可以使用 GitHub 页面上的`Download`(下载)按钮或此链接,以 ZIP 压缩包格式下载代码。 - -克隆仓库或解压 ZIP 文件后,你应该有一个名为`ThinkDataStructures`的目录,其中有一个名为`code`的子目录。 - -本书中的示例是使用 Java SE 7 开发和测试的。如果你使用的是较旧的版本,一些示例将无法正常工作。如果你使用的是更新版本,那么它们都应该能用。 - -## 贡献者 - -这本书是我为纽约市 Flatiron School 写的课程的一个改编版,它提供了编程和网页开发相关的各种在线课程。他们提供基于这个材料的课程,提供在线开发环境,来自教师和其他学生的帮助,以及结业证书。你可以在 上找到更多信息 。 - -+ 在 Flatiron School,Joe Burgess,Ann John 和 Charles Pletcher 通过实现和测试,提供了来自初始规范的指导,建议和更正。谢谢你们! -+ 我非常感谢我的技术审校员 Barry Whitman, Patrick White 和 Chris Mayfield,他提出了许多有用的建议,并捕获了许多错误。当然,任何剩余的错误都是我的错,而不是他们的错! -+ 感谢 Olin College 的数据结构和算法课程中的教师和学生,他们读了这本书并提供了有用的反馈。 - -如果你对文本有任何意见或建议,请发送至:。 diff --git a/docs/think-dast-zh/1.md b/docs/think-dast-zh/1.md deleted file mode 100644 index 948265283..000000000 --- a/docs/think-dast-zh/1.md +++ /dev/null @@ -1,156 +0,0 @@ -# 第一章 接口 - -> 原文:[Chapter 1 Interfaces](http://greenteapress.com/thinkdast/html/thinkdast002.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -本书展示了三个话题: - -+ 数据结构:从 Java 集合框架(JCF)中的结构开始,你将学习如何使用列表和映射等数据结构,你将看到它们的工作原理。 -+ 算法分析:我提供了技术,来分析代码以及预测运行速度和需要多少空间(内存)。 -+ 信息检索:为了激发前两个主题,并使练习更加有趣,我们将使用数据结构和算法构建简单的 Web 搜索引擎。 - -以下是话题顺序的大纲: - -+ 我们将从`List`接口开始,你将编写实现这个接口的两种不同的方式。然后我们将你的实现与 Java `ArrayList`和`LinkedList`类进行比较。 -+ 接下来,我将介绍树形数据结构,你将处理第一个应用程序:一个程序,从维基百科页面读取页面,解析内容,并遍历生成的树来查找链接和其他特性。我们将使用这些工具来测试“到达哲学”的猜想(你可以通过阅读 来了解)。 -+ 我们将了解 Java 的`Map`接口和`HashMap`实现。然后,你将使用哈希表和二叉搜索树来编写实现此接口的类。 -+ 最后,你将使用这些(以及其他一些我之前介绍的)类来实现一个 Web 搜索引擎,其中包括:一个查找和读取页面的爬虫程序,一个存储网页内容的索引器,以便有效地搜索,以及一个从用户那里接受查询并返回相关结果的检索器。 - -让我们开始吧。 - -## 1.1 为什么有两种`List`? - -当人们开始使用 Java 集合框架时,有时候会混淆`ArrayList`和`LinkedList`。为什么 Java 提供两个`List interface`的实现呢?你应该如何选择使用哪一个?我们将在接下来的几章回答这些问题。 - -我将以回顾`interface`和实现它们的类开始,我将介绍“面向接口编程”的概念。 - -在最初的几个练习中,你将实现类似于`ArrayList`和`LinkedList`的类,这样你就会知道他们如何工作,我们会看到,他们每个类都有优点和缺点。对于`ArrayList`,一些操作更快或占用更少的空间;但对于`LinkedList`其他操作更快或空间更少。哪一个更适合于特定的应用程序,取决于它最常执行的操作。 - -## 1.2 Java 中的接口 - -Java `interface`规定了一组方法;任何实现这个`interface`的类都必须提供这些方法。例如,这里是`Comparable`的源代码,它是定义在`java.lang`包中的`interface`: - -```java -public interface Comparable { - public int compareTo(T o); -} -``` - -这个`interface`的定义使用类型参数`T`,这使得`Comparable`是个泛型类型。为了实现这个`interface`,一个类必须: - -+ 规定类型`T`,以及, -+ 提供一个名为`compareTo`的方法,接受一个对象作为参数,并返回`int`。 - -例如,以下是`java.lang.Integer`的源代码: - -```java -public final class Integer extends Number implements Comparable { - - public int compareTo(Integer anotherInteger) { - int thisVal = this.value; - int anotherVal = anotherInteger.value; - return (thisVal 译者注:根据[`Comparable`的文档](http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html#compareTo%28T%29),不必要这么复杂,直接返回`this.value - that.value`就足够了。 - -这个类扩展了`Number`,所以它继承了`Number`的方法和实例变量;它实现`Comparable`,所以它提供了一个名为`compareTo`的方法,接受`Integer`并返回一个`int`。 - -当一个类声明它实现一个`interface`,编译器会检查,它提供了所有`interface`定义的方法。 - -除此之外,这个`compareTo`的实现使用“三元运算符”,有时写作`?:`。如果你不熟悉,可以阅读 。 - -## 1.3 `List`接口 - -Java集合框架(JCF)定义了一个`interface`,称为 `List`,并提供了两个实现方式,`ArrayList`和`LinkedList`。 - -这个`interface`定义了`List`是什么意思;实现它的任何类`interface`必须提供一组特定的方法,包括`add`,`get`, `remove`,以及其它大约 20 个。 - -`ArrayList`并`LinkedList`提供这些方法,因此可以互换使用。用于`List`也可用于`ArrayList`,`LinkedList`,或实现`List`的其它任何对象。 - -这是一个人为的示例,展示了这一点: - -```java -public class ListClientExample { - private List list; - - public ListClientExample() { - list = new LinkedList(); - } - - private List getList() { - return list; - } - - public static void main(String[] args) { - ListClientExample lce = new ListClientExample(); - List list = lce.getList(); - System.out.println(list); - } -} -``` - -`ListClientExample`没有任何有用的东西,但它封装了`List`,并具有一个类的基本要素。也就是说,它包含一个`List`实例变量。我会使用这个类来表达这个要点,然后你将在第一个练习中使用它。 - -通过实例化(也就是创建)新的`LinkedList`,这个`ListClientExample`构造函数初始化`list`;读取器方法叫做`getList`,返回内部`List`对象的引用;并且`main`包含几行代码来测试这些方法。 - -这个例子的要点是,它尽可能地使用`List`,避免指定`LinkedList`,`ArrayList`,除非有必要。例如,实例变量被声明为`List`,并且`getList`返回`List`,但都不指定哪种类型的列表。 - -如果你改变主意并决定使用`ArrayList`,你只需要改变构造函数; 你不必进行任何其他更改。 - -这种风格被称为基于接口的编程,或者更随意,“面向接口编程”(见 )。这里我们谈论接口的一般思想,而不是 Java 接口。 - -当你使用库时,你的代码只依赖于类似“列表”的接口。它不应该依赖于一个特定的实现,像`ArrayList`。这样,如果将来的实现发生变化,使用它的代码仍然可以工作。 - -另一方面,如果接口改变,依赖于它的代码也必须改变。 这就是为什么库的开发人员避免更改接口,除非绝对有必要。 - -## 1.4 练习 1 - -因为这是第一个练习,我们会保持简单。你将从上一节获取代码并交换实现;也就是说,你会将`LinkedList`替换为`ArrayList`。因为面向接口编写程序,你将能够通过更改一行并添加一个`import`语句来交换实现。 - -以建立你的开发环境来开始。对于所有的练习,你需要能够编译和运行 Java 代码。我使用 JDK7 来开发示例。如果你使用的是更新的版本,则所有内容都应该仍然可以正常工作。如果你使用的是旧版本,可能会发现某些东西不兼容。 - -我建议使用交互式开发环境(IDE)来获取语法检查,自动完成和源代码重构。这些功能可帮助你避免错误或快速找到它们。但是,如果你正在准备技术面试,请记住,在面试期间你不会拥有这些工具,因此你也可以在没有他们的情况下练习编写代码。 - -如果你尚未下载本书的代码,请参阅 0.1 节中的指南。 - -在名为`code`的目录中,你应该找到这些文件和目录: - -+ `build.xml`是一个 Ant 文件,可以更容易地编译和运行代码。 -+ `lib`包含你需要的库(对于这个练习,只是 JUnit)。 -+ `src`包含源代码。 - -如果你浏览`src/com/allendowney/thinkdast`,你将找到此练习的源代码: - -+ `ListClientExample.java`包含上一节的代码。 -+ `ListClientExampleTest.java`包含一个 JUnit 测试`ListClientExample`。 - -查看`ListClientExample`并确保你了解它的作用。然后编译并运行它。如果你使用 Ant,你可以访问代码目录并运行`ant ListClientExample`。 - -你可能会得到一个警告。 - -``` -List is a raw type. References to generic type List -should be parameterized. -``` - -为了使这个例子保持简单,我没有留意在列表中指定元素的类型。如果此警告让你烦恼,你可以通过将`List`或`LinkedList`替换为`List`或`LinkedList`来修复。 - -回顾`ListClientExampleTest`。它运行一个测试,创建一个`ListClientExample`,调用`getList`,然后检查结果是否是一个`ArrayList`。最初,这个测试会失败,因为结果是一个`LinkedList`,而不是一个`ArrayList`。运行这个测试并确认它失败。 - -注意:这个测试对于这个练习是有意义的,但它不是测试的一个很好的例子。良好的测试应该检查被测类是否满足接口的要求;他们不应该依赖于实现的细节。 - -在`ListClientExample`中,将`LinkedList`替换为`ArrayList`。你可能需要添加一个`import`语句。编译并运行`ListClientExample`。然后再次运行测试。修改了这个之后,测试现在应该通过了。 - -为了这个此测试通过,你只需要在构造函数中更改`LinkedList`;你不必更改任何`List`出现的地方。如果你这样做会发生什么?来吧,将一个或者多个`List`替换为`ArrayList`。程序仍然可以正常工作,但现在是“过度指定”了。如果你将来改变主意,并希望再次交换接口,则必须更改代码。 - -在`ListClientExample`构造函数中,如果将`ArrayList`替换为`List`,会发生什么?为什么不能实例化`List`? diff --git a/docs/think-dast-zh/10.md b/docs/think-dast-zh/10.md deleted file mode 100644 index 5dee1fcb6..000000000 --- a/docs/think-dast-zh/10.md +++ /dev/null @@ -1,218 +0,0 @@ -# 第十章 哈希 - -> 原文:[Chapter 10 Hashing](http://greenteapress.com/thinkdast/html/thinkdast011.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -在本章中,我定义了一个比`MyLinearMap`更好的`Map`接口实现,`MyBetterMap`,并引入哈希,这使得`MyBetterMap`效率更高。 - -## 10.1 哈希 - -为了提高`MyLinearMap`的性能,我们将编写一个新的类,它被称为`MyBetterMap`,它包含`MyLinearMap`对象的集合。它在内嵌的映射之间划分键,因此每个映射中的条目数量更小,这加快了`findEntry`,以及依赖于它的方法的速度。 - -这是类定义的开始: - -```java -public class MyBetterMap implements Map { - - protected List> maps; - - public MyBetterMap(int k) { - makeMaps(k); - } - - protected void makeMaps(int k) { - maps = new ArrayList>(k); - for (int i=0; i()); - } - } -} -``` - -实例变量`maps`是一组`MyLinearMap`对象。构造函数接受一个参数`k`,决定至少最开始,要使用多少个映射。然后`makeMaps`创建内嵌的映射并将其存储在一个`ArrayList`中。 - -现在,完成这项工作的关键是,我们需要一些方法来查看一个键,并决定应该进入哪个映射。当我们`put`一个新的键时,我们选择一个映射;当我们`get`同样的键时,我们必须记住我们把它放在哪里。 - - -一种可能性是随机选择一个子映射,并跟踪我们把每个键放在哪里。但我们应该如何跟踪?看起来我们可以用一个`Map`来查找键,并找到正确的子映射,但是练习的重点是编写一个有效的`Map`实现。我们不能假设我们已经有了。 - -一个更好的方法是使用一个哈希函数,它接受一个`Object`,一个任意的`Object`,并返回一个称为哈希码的整数。重要的是,如果它不止一次看到相同的`Object`,它总是返回相同的哈希码。这样,如果我们使用哈希码来存储键,当我们查找时,我们将得到相同的哈希码。 - - -在Java中,每个`Object`都提供了`hashCode`,一种计算哈希函数的方法。这种方法的实现对于不同的对象是不同的;我们会很快看到一个例子。 - -这是一个辅助方法,为一个给定的键选择正确的子映射: - -```java -protected MyLinearMap chooseMap(Object key) { - int index = 0; - if (key != null) { - index = Math.abs(key.hashCode()) % maps.size(); - } - return maps.get(index); -} -``` - -如果`key`是`null`,我们任意选择索引为`0`的子映射。否则,我们使用`hashCode`获取一个整数,调用`Math.abs`来确保它是非负数,然后使用余数运算符`%`,这保证结果在`0`和`maps.size()-1`之间。所以`index`总是一个有效的`maps`索引。然后`chooseMap`返回为其所选的映射的引用。 - -我们使用`chooseMap`的`put`和`get`,所以当我们查询键的时候,我们得到添加时所选的相同映射,我们选择了相同的映射。至少应该是 - 稍后我会解释为什么这可能不起作用。 - -这是我的`put`和`get`的实现: - -```java -public V put(K key, V value) { - MyLinearMap map = chooseMap(key); - return map.put(key, value); -} - -public V get(Object key) { - MyLinearMap map = chooseMap(key); - return map.get(key); -} -``` - -很简单,对吧?在这两种方法中,我们使用`chooseMap`来找到正确的子映射,然后在子映射上调用一个方法。这就是它的工作原理。现在让我们考虑一下性能。 - -如果在`k`个子映射中分配了`n`个条目,则平均每个映射将有`n/k`个条目。当我们查找一个键时,我们必须计算其哈希码,这需要一些时间,然后我们搜索相应的子映射。 - -因为`MyBetterMap`中的条目列表,比`MyLinearMap`中的短`k`倍,我们的预期是`ķ`倍的搜索速度。但运行时间仍然与`n`成正比,所以`MyBetterMap`仍然是线性的。在下一个练习中,你将看到如何解决这个问题。 - -## 10.2 哈希如何工作? - -哈希函数的基本要求是,每次相同的对象应该产生相同的哈希码。对于不变的对象,这是比较容易的。对于具有可变状态的对象,我们必须花费更多精力。 - -作为一个不可变对象的例子,我将定义一个`SillyString`类,它包含一个`String`: - -```java -public class SillyString { - private final String innerString; - - public SillyString(String innerString) { - this.innerString = innerString; - } - - public String toString() { - return innerString; - } -``` - -这个类不是很有用,所以它叫做`SillyString`。但是我会使用它来展示,一个类如何定义它自己的哈希函数: - -```java - @Override - public boolean equals(Object other) { - return this.toString().equals(other.toString()); - } - - @Override - public int hashCode() { - int total = 0; - for (int i=0; i 上阅读更多内容。 - - -该哈希函数满足要求:如果两个`SillyString`对象包含相等的内嵌字符串,则它们将获得相同的哈希码。 - -这可以正常工作,但它可能不会产生良好的性能,因为它为许多不同的字符串返回相同的哈希码。如果两个字符串以任何顺序包含相同的字母,它们将具有相同的哈希码。即使它们不包含相同的字母,它们可能会产生相同的总量,例如`"ac"`和`"bb"`。 - -如果许多对象具有相同的哈希码,它们将在同一个子映射中。如果一些子映射比其他映射有更多的条目,那么当我们有`k`个映射时,加速比可能远远小于`k`。所以哈希函数的目的之一是统一;也就是说,以相等的可能性,在这个范围内产生任何值。你可以在 上阅读更多设计完成的,散列函数的信息。 - -## 10.3 哈希和可变性 - -`String`是不可变的,`SillyString`也是不可变的,因为`innerString`定义为`final`。一旦你创建了一个`SillyString`,你不能使`innerString`引用不同的`String`,你不能修改所指向的`String`。因此,它将始终具有相同的哈希码。 - - -但是让我们看看一个可变对象会发生什么。这是一个`SillyArray`定义,它与`SillyString`类似,除了它使用一个字符数组而不是一个`String`: - -```java -public class SillyArray { - private final char[] array; - - public SillyArray(char[] array) { - this.array = array; - } - - public String toString() { - return Arrays.toString(array); - } - - @Override - public boolean equals(Object other) { - return this.toString().equals(other.toString()); - } - - @Override - public int hashCode() { - int total = 0; - for (int i=0; i 原文:[Chapter 11 HashMap](http://greenteapress.com/thinkdast/html/thinkdast012.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -上一章中,我们写了一个使用哈希的`Map`接口的实现。我们期望这个版本更快,因为它搜索的列表较短,但增长顺序仍然是线性的。 - -如果存在`n`个条目和`k`个子映射,则子映射的大小平均为`n/k`,这仍然与`n`成正比。但是,如果我们与`n`一起增加`k`,我们可以限制`n/k`的大小。 - -例如,假设每次`n`超过`k`的时候,我们都使`k`加倍;在这种情况下,每个映射的条目的平均数量将小于`1`,并且几乎总是小于`10`,只要散列函数能够很好地展开键。 - - -如果每个子映射的条目数是不变的,我们可以在常数时间内搜索一个子映射。并且计算散列函数通常是常数时间(它可能取决于键的大小,但不取决于键的数量)。这使得`Map`的核心方法, `put`和`get`时间不变。 - -在下一个练习中,你将看到细节。 - -## 11.1 练习 9 - -在`MyHashMap.java`中,我提供了哈希表的大纲,它会按需增长。这里是定义的起始: - -```java -public class MyHashMap extends MyBetterMap implements Map { - - // average number of entries per sub-map before we rehash - private static final double FACTOR = 1.0; - - @Override - public V put(K key, V value) { - V oldValue = super.put(key, value); - - // check if the number of elements per sub-map exceeds the threshold - if (size() > maps.size() * FACTOR) { - rehash(); - } - return oldValue; - } -} -``` - -`MyHashMap`扩展了`MyBetterMap`,所以它继承了那里定义的方法。它覆盖的唯一方法是`put`,它调用了超类中的`put` -- 也就是说,它调用了`MyBetterMap `中的`put`版本 -- 然后它检查它是否必须`rehash`。调用`size`返回总数量`n`。调用`maps.size`返回内嵌映射的数量`k`。 - -常数`FACTOR`(称为负载因子)确定每个子映射的平均最大条目数。如果`n > k * FACTOR`,这意味着`n/k > FACTOR`,意味着每个子映射的条目数超过阈值,所以我们调用`rehash`。 - - -运行`ant build`来编译源文件。然后运行`ant MyHashMapTest`。它应该失败,因为执行`rehash`会抛出异常。你的工作是填充它。 - - -填充`rehash`的主体,来收集表中的条目,调整表的大小,然后重新放入条目。我提供了两种可能会派上用场的方法:`MyBetterMap.makeMaps`和`MyLinearMap.getEntries`。每次调用它时,你的解决方案应该使映射数量加倍。 - -## 11.2 分析`MyHashMap` - -如果最大子映射中的条目数与`n/k`成正比,并且`k`与`n`成正比,那么多个核心方法就是常数时间的: - -```java - public boolean containsKey(Object target){ - MyLinearMap map = chooseMap(target); - return map.containsKey(target); - } - - public V get(Object key){ - MyLinearMap map = chooseMap(key); return map.get(key); - } - public V remove(Object key){ - MyLinearMap map = chooseMap(key); - return map.remove(key); - } -``` - -每个方法都计算键的哈希,这是常数时间,然后在一个子映射上调用一个方法,这个方法是常数时间的。 - -到现在为止还挺好。但另一个核心方法,`put`有点难分析。当我们不需要`rehash`时,它是不变的时间,但是当我们这样做时,它是线性的。这样,它与 3.2 节中我们分析的`ArrayList.add`类似。 - - -出于同样的原因,如果我们平摊一系列的调用,结果是常数时间。同样,论证基于摊销分析(见 3.2 节)。 - - -假设子映射的初始数量`k`为`2`,负载因子为`1`。现在我们来看看`put`一系列的键需要多少工作量。作为基本的“工作单位”,我们将计算对密钥哈希,并将其添加到子映射中的次数。 - - -我们第一次调用`put`时,它需要`1`个工作单位。第二次也需要`1`个单位。第三次我们需要`rehash`,所以需要`2`个单位重新填充现有的键,和`1`个单位来对新键哈希。 - -> 译者注:可以单独计算`rehash`中转移元素的数量,然后将元素转移的复杂度和计算哈希的复杂度相加。 - -现在哈希表的大小是`4`,所以下次调用`put`时 ,需要`1`个工作单位。但是下一次我们必须`rehash`,需要`4`个单位来`rehash`现有的键,和`1`个单位来对新键哈希。 - - -图 11.1 展示了规律,对新键哈希的正常工作量在底部展示,额外工作量展示为塔楼。 - -![](img/11-1.jpg) - -图 11.1:向哈希表添加元素的工作量展示 - -如箭头所示,如果我们把塔楼推倒,每个积木都会在下一个塔楼之前填满空间。结果似乎`2`个单位的均匀高度,这表明`put`的平均工作量约为`2`个单位。这意味着`put`平均是常数时间。 - -这个图还显示了,当我们`rehash`的时候,为什么加倍子映射数量`k`很重要。如果我们只是加上`k`而不是加倍,那么这些塔楼会靠的太近,他们会开始堆积。这样就不会是常数时间了。 - -## 11.3 权衡 - -我们已经表明,`containsKey`,`get`和`remove`是常数时间,`put`平均为常数时间。我们应该花一点时间来欣赏它有多么出色。无论哈希表有多大,这些操作的性能几乎相同。算是这样吧。 - - -记住,我们的分析基于一个简单的计算模型,其中每个“工作单位”花费相同的时间量。真正的电脑比这更复杂。特别是,当处理足够小,适应高速缓存的数据结构时,它们通常最快;如果结构不适合高速缓存但仍适合内存,则稍慢一点;如果结构不适合在内存中,则非常慢。 - - -这个实现的另一个限制是,如果我们得到了一个值而不是一个键时,那么散列是不会有帮助的:`containsValue`是线性的,因为它必须搜索所有的子映射。查找一个值并找到相应的键(或可能的键),没有特别有效的方式。 - - -还有一个限制:`MyLinearMap`的一些常数时间的方法变成了线性的。例如: - -```java - public void clear() { - for (int i=0; i map: maps) { - total += map.size(); - } - return total; - } -``` - -为了累计整个大小,它必须迭代子映射。由于我们增加了子映射的数量`k`,随着条目数`n`增加,所以`k`与`n`成正比,所以`size`是线性的。 - -`put`也是线性的,因为它使用`size`: - -```java - public V put(K key, V value) { - V oldValue = super.put(key, value); - - if (size() > maps.size() * FACTOR) { - rehash(); - } - return oldValue; - } -``` - -如果`size`是线性的,我们做的一切都浪费了。 - -幸运的是,有一个简单的解决方案,我们以前看过:我们必须维护实例变量中的条目数,并且每当我们调用一个改变它的方法时更新它。 - -你会在这本书的仓库中找到我的解决方案`MyFixedHashMap.java`。这是类定义的起始: - -```java -public class MyFixedHashMap extends MyHashMap implements Map { - - private int size = 0; - - public void clear() { - super.clear(); - size = 0; - } -``` - -我们不修改`MyHashMap`,我定义一个扩展它的新类。它添加一个新的实例变量`size`,它被初始化为零。 - -更新`clear`很简单; 我们在超类中调用`clear`(清除子映射),然后更新`size`。 - - -更新`remove`和`put`有点困难,因为当我们调用超类的该方法,我们不能得知子映射的大小是否改变。这是我的解决方式: - -```java - public V remove(Object key) { - MyLinearMap map = chooseMap(key); - size -= map.size(); - V oldValue = map.remove(key); - size += map.size(); - return oldValue; - } -``` - -`remove`使用`chooseMap`找到正确的子映射,然后减去子映射的大小。它会在子映射上调用`remove`,根据是否找到了键,它可以改变子映射的大小,也可能不会改变它的大小。但是无论哪种方式,我们将子映射的新大小加到`size`,所以最终的`size`值是正确的。 - -重写的`put`版本是类似的: - -```java - public V put(K key, V value) { - MyLinearMap map = chooseMap(key); - size -= map.size(); - V oldValue = map.put(key, value); - size += map.size(); - - if (size() > maps.size() * FACTOR) { - size = 0; - rehash(); - } - return oldValue; - } -``` - -我们在这里也有同样的问题:当我们在子地图上调用`put`时,我们不知道是否添加了一个新的条目。所以我们使用相同的解决方案,减去旧的大小,然后加上新的大小。 - -现在`size`方法的实现很简单了: - -```java - public int size() { - return size; - } -``` - -并且正好是常数时间。 - -当我测量这个解决方案时,我发现放入`n`个键的总时间正比于`n`,也就是说,每个`put`是常数时间的,符合预期。 - -## 11.6 UML 类图 - -在本章中使用代码的一个挑战是,我们有几个互相依赖的类。以下是类之间的一些关系: - -+ `MyLinearMap`包含一个`LinkedList`并实现了`Map`。 -+ `MyBetterMap`包含许多`MyLinearMap`对象并实现了`Map`。 -+ `MyHashMap`扩展了`MyBetterMap`,所以它也包含`MyLinearMap对象`,并实现了`Map`。 -+ `MyFixedHashMap`扩展了`MyHashMap`并实现了`Map`。 - -为了有助于跟踪这些关系,软件工程师经常使用 UML 类图。UML 代表统一建模语言(见 )。“类图”是由 UML 定义的几种图形标准之一。 - -在类图中,每个类由一个框表示,类之间的关系由箭头表示。图 11.2 显示了使用在线工具 yUML()生成的,上一个练习的 UML 类图。 - -![](img/11-2.jpg) - -图11.2:本章中的 UML 类图 - -不同的关系由不同的箭头表示: - -+ 实心箭头表示 HAS-A 关系。例如,每个`MyBetterMap`实例包含多个`MyLinearMap`实例,因此它们通过实线箭头连接。 -+ 空心和实线箭头表示 IS-A 关系。例如,`MyHashMap`扩展 了`MyBetterMap`,因此它们通过 IS-A 箭头连接。 -+ 空心和虚线箭头表示一个类实现了一个接口;在这个图中,每个类都实现 `Map`。 - -UML 类图提供了一种简洁的方式,来表示大量类集合的信息。在设计阶段中,它们用于交流备选设计,在实施阶段中,用于维护项目的共享思维导图,并在部署过程中记录设计。 diff --git a/docs/think-dast-zh/12.md b/docs/think-dast-zh/12.md deleted file mode 100644 index 99394bcbe..000000000 --- a/docs/think-dast-zh/12.md +++ /dev/null @@ -1,224 +0,0 @@ -# 第十二章 `TreeMap` - -> 原文:[Chapter 12 TreeMap](http://greenteapress.com/thinkdast/html/thinkdast013.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -这一章展示了二叉搜索树,它是个`Map`接口的高效实现。如果我们想让元素有序,它非常实用。 - -## 12.1 哈希哪里不对? - -此时,你应该熟悉 Java 提供的`Map`接口和`HashMap`实现。通过使用哈希表来制作你自己的`Map`,你应该了解`HashMap`的工作原理,以及为什么我们预计其核心方法是常数时间的。 - -由于这种表现,`HashMap`被广泛使用,但并不是唯一的`Map`实现。有几个原因可能需要另一个实现: - -哈希可能很慢,所以即使`HashMap`操作是常数时间,“常数”可能很大。 -如果哈希函数将键均匀分配给子映射,效果很好。但设计良好的散列函数并不容易,如果太多的键在相同的子映射上,那么`HashMap`的性能可能会很差。 -哈希表中的键不以任何特定顺序存储;实际上,当表增长并且键被重新排列时,顺序可能会改变。对于某些应用程序,必须或至少保持键的顺序,这很有用。 - -很难同时解决所有这些问题,但是 Java 提供了一个称为`TreeMap`的实现: - -+ 它不使用哈希函数,所以它避免了哈希的开销和选择哈希函数的困难。 -+ 在`TreeMap`之中,键被存储在二叉搜索树中,这使我们可以以线性时间顺序遍历键。 -+ 核心方法的运行时间与`log(n)`成正比,并不像常数时间那样好,但仍然非常好。 - -在下一节中,我将解释二进制搜索树如何工作,然后你将使用它来实现`Map`。另外,使用树实现时,我们将分析映射的核心方法的性能。 - -## 12.2 二叉搜索树 - -二叉搜索树(BST)是一个树,其中每个`node`(节点)包含一个键,并且每个都具有“BST 属性”: - -+ 如果`node`有一个左子树,左子树中的所有键都必须小于`node`的键。 -+ 如果`node`有一个右子树,右子树中的所有键都必须大于`node`的键。 - -![](img/12-1.jpg) - -图 12.1:二叉搜索树示例 - -图 12.1 展示了一个具有此属性的整数的树。这个图片来自二叉搜索树的维基百科页面,位于 ,当你做这个练习时,你会发现它很实用。 - -根节点中的键为`8`,你可以确认根节点左边的所有键小于`8`,右边的所有键都更大。你还可以检查其他节点是否具有此属性。 - - -在二叉搜索树中查找一个键是很快的,因为我们不必搜索整个树。从根节点开始,我们可以使用以下算法: - -+ 将你要查找的键`target`,与当前节点的键进行比较。如果他们相等,你就完成了。 -+ 如果`target`小于当前键,搜索左子树。如果没有,`target`不在树上。 -+ 如果`target`大于当前键,搜索右子树。如果没有,`target`不在树上。 - -在树的每一层,你只需要搜索一个子树。例如,如果你在上图中查找`target = 4`,则从根节点开始,它包含键`8`。因为`target`小于`8`,你走了左边。因为`target`大于`3`,你走了右边。因为`target`小于`6`,你走了左边。然后你找到你要找的键。 - -在这个例子中,即使树包含九个键,它需要四次比较来找到目标。一般来说,比较的数量与树的高度成正比,而不是树中的键的数量。 - -因此,我们可以计算树的高度`h`和节点个数`n`的关系。从小的数值开始,逐渐增加: - -如果`h=1`,树只包含一个节点,那么`n=1`。 -如果`h=2`,我们可以添加两个节点,总共`n=3`。 -如果`h=3`,我们可以添加多达四个节点,总共`n=7`。 -如果`h=4`,我们可以添加多达八个节点,总共`n=15`。 - -现在你可能会看到这个规律。如果我们将树的层数从`1`数到`n`,第`i`层可以拥有多达`2^(n-1)`个节点。`h`层的树共有`2^h-1`个节点。如果我们有: - -``` -n = 2^h - 1 -``` - -我们可以对两边取以`2`为底的对数: - -``` -log2(n) ≈ h -``` - -意思是树的高度正比于`logn`,如果它是满的。也就是说,如果每一层包含最大数量的节点。 - -所以我们预计,我们可以以正比于`logn`的时间,在二叉搜索树中查找节点。如果树是慢的,即使是部分满的,这是对的。但是并不总是对的,我们将会看到。 - -时间正比于`logn`的算法是对数时间的,并且属于`O(logn)`的增长级别。 - - -## 12.3 练习 10 - -对于这个练习,你将要使用二叉搜索树编写`Map`接口的一个实现。 - -这里是实现的开头,叫做`MyTreeMap`: - -```java -public class MyTreeMap implements Map { - - private int size = 0; - private Node root = null; -``` - -实例变量是`size`,它跟踪了键的数量,以及`root`,它是树中根节点的引用。树为空的时候,`root`是`null`,`size`是`0`。 - -这里是`Node`的定义,它在`MyTreeMap`之中定义。 - -```java - protected class Node { - public K key; - public V value; - public Node left = null; - public Node right = null; - - public Node(K key, V value) { - this.key = key; - this.value = value; - } - } -``` - -每个节点包含一个键值对,以及两个子节点的引用,`left`和`right`。任意子节点都可以为`null`。 - -一些`Map`方法易于实现,比如`size`和`clear`: - -```java - public int size() { - return size; - } - - public void clear() { - size = 0; - root = null; - } -``` - -`size`显然是常数时间的。 - -`clear`也是常数时间的,但是考虑这个:当`root`赋为`null`时,垃圾收集器回收了树中的节点,这是线性时间的。这个工作是否应该由垃圾收集器的计数来完成呢?我认为是的。 - -下一节中,你会填充一些其它方法,包括最重要的`get`和`set`。 - -## 12.4 实现`TreeMap` - -这本书的仓库中,你将找到这些源文件: - -+ `MyTreeMap.java`包含上一节的代码,其中包含缺失方法的大纲。 -+ `MyTreeMapTest.java`包含单元`MyTreeMap`的测试。 - -运行`ant build`来编译源文件。然后运行`ant MyTreeMapTest`。几个测试应该失败,因为你有一些工作要做! - -我已经提供了`get`和`containsKey`的大纲。他们都使用`findNode`,这是我定义的私有方法;它不是`Map`接口的一部分。以下是它的起始: - -```java - private Node findNode(Object target) { - if (target == null) { - throw new IllegalArgumentException(); - } - - @SuppressWarnings("unchecked") - Comparable k = (Comparable) target; - - // TODO: FILL THIS IN! - return null; - } -``` - -参数`target`是我们要查找的键。如果`target`是`null`,`findNode`抛出异常。一些`Map`实现可以将`null`处理为一个键,但是在二叉搜索树中,我们需要能够比较键,所以处理`null`是有问题的。为了保持简单,这个实现不将`null`视为键。 - -下一行显示如何将`target`与树中的键进行比较。按照`get`和`containsKey`的签名(名称和参数),编译器认为`target`是一个`Object`。但是,我们需要能够对键进行比较,所以我们将`target`强制转换为`Comparable`,这意味着它可以与类型`K`(或任何超类)的示例比较。如果你不熟悉“类型通配符”的用法,可以在 上阅读更多内容。 - - -幸运的是,Java 的类型系统的处理不是这个练习的重点。你的工作是填写剩下的`findNode`。如果它发现一个包含`target`键的节点,它应该返回该节点。否则应该返回`null`。当你使其工作,`get`和`containsKey`的测试应该通过。 - -请注意,你的解决方案应该只搜索通过树的一条路径,因此它应该与树的高度成正比。你不应该搜索整棵树! - - -你的下一个任务是填充`containsValue`。为了让你起步,我提供了一个辅助方法`equals`,比较`target`和给定的键。请注意,树中的值(与键相反)不一定是可比较的,所以我们不能使用`compareTo`;我们必须在`target`上调用`equals`。 - - -不像你以前的`findNode`解决方案,你的`containsValue`解决方案应该搜索整个树,所以它的运行时间正比于键的数量`n`,而不是树的高度`h`。 - -> 译者注:这里你可能想使用之前讲过的 DFS 迭代器。 - -你应该填充的下一个方法是`put`。我提供了处理简单情况的起始代码: - -```java - public V put(K key, V value) { - if (key == null) { - throw new IllegalArgumentException(); - } - if (root == null) { - root = new Node(key, value); - size++; - return null; - } - return putHelper(root, key, value); - } - - private V putHelper(Node node, K key, V value) { - // TODO: Fill this in. - } -``` - -如果你尝试将`null`作为关键字,`put`则会抛出异常。 - -如果树为空,则`put`创建一个新节点并初始化实例变量`root`。 - -否则,它调用`putHelper`,这是我定义的私有方法;它不是`Map`接口的一部分。 - -填写`putHelper`,让它搜索树,以及: - -+ 如果`key`已经在树中,它将使用新值替换旧值,并返回旧值。 -+ 如果`key`不在树中,它将创建一个新节点,找到正确的添加位置,并返回`null`。 - -你的`put`实现的是时间应该与树的高度`h`成正比,而不是元素的数量`n`。理想情况下,你只需搜索一次树,但如果你发现两次更容易搜索,可以这样做:它会慢一些,但不会改变增长级别。 - -最后,你应该填充`keySet`。根据 的文档,该方法应该返回一个`Set`,可以按顺序迭代键;也就是说,按照`compareTo`方法,升序迭代。我们在 8.3 节中使用的`HashSet`实现不会维护键的顺序,但`LinkedHashSet`实现可以。你可以阅读 。 - - -我提供了一个`keySet`的大纲,创建并返回`LinkedHashSet`: - -``` - public Set keySet() { - Set set = new LinkedHashSet(); - return set; - } -``` - -你应该完成此方法,使其以升序向`set`添加树中的键。提示:你可能想编写一个辅助程序;你可能想让它递归;你也可能想要阅读 上的树的中序遍历。 - -当你完成时,所有测试都应该通过。下一章中,我会讲解我的解法,并测试核心方法的性能。 diff --git a/docs/think-dast-zh/13.md b/docs/think-dast-zh/13.md deleted file mode 100644 index 78e71b342..000000000 --- a/docs/think-dast-zh/13.md +++ /dev/null @@ -1,283 +0,0 @@ -# 第十三章 二叉搜索树 - -> 原文:[Chapter 13 Binary search tree](http://greenteapress.com/thinkdast/html/thinkdast014.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -本章介绍了上一个练习的解决方案,然后测试树形映射的性能。我展示了一个实现的问题,并解释了 Java 的`TreeMap`如何解决它。 - -## 13.1 简单的`MyTreeMap` - -上一个练习中,我给了你`MyTreeMap`的大纲,并让你填充缺失的方法。现在我会展示结果,从`findNode`开始: - -```java -private Node findNode(Object target) { - // some implementations can handle null as a key, but not this one - if (target == null) { - throw new IllegalArgumentException(); - } - - // something to make the compiler happy - @SuppressWarnings("unchecked") - Comparable k = (Comparable) target; - - // the actual search - Node node = root; - while (node != null) { - int cmp = k.compareTo(node.key); - if (cmp < 0) - node = node.left; - else if (cmp > 0) - node = node.right; - else - return node; - } - return null; -} -``` - -`findNode`是`containsKey`和`get`所使用的一个私有方法;它不是`Map`接口的一部分。参数`target`是我们要查找的键。我在上一个练习中解释了这种方法的第一部分: - -+ 在这个实现中,`null`不是键的合法值。 -+ 在我们可以在`target`上调用`compareTo`之前,我们必须把它强制转换为某种形式的`Comparable`。这里使用的“类型通配符”会尽可能允许;也就是说,它适用于任何实现`Comparable`类型,并且它的`compareTo`接受`K`或者任和`K`的超类。 - -之后,实际搜索比较简单。我们初始化一个循环变量`node`来引用根节点。每次循环中,我们将目标与`node.key`比较。如果目标小于当前键,我们移动到左子树。如果它更大,我们移动到右子树。如果相等,我们返回当前节点。 - -如果在没有找到目标的情况下,我们到达树的底部,我就认为,它不在树中并返回`null`。 - -## 13.2 搜索值 - -我在前面的练习中解释了,`findNode`运行时间与树的高度成正比,而不是节点的数量,因为我们不必搜索整个树。但是对于`containsValue`,我们必须搜索值,而不是键;BST 的特性不适用于值,因此我们必须搜索整个树。 - -我的解法是递归的: - -```java -public boolean containsValue(Object target) { - return containsValueHelper(root, target); -} - -private boolean containsValueHelper(Node node, Object target) { - if (node == null) { - return false; - } - if (equals(target, node.value)) { - return true; - } - if (containsValueHelper(node.left, target)) { - return true; - } - if (containsValueHelper(node.right, target)) { - return true; - } - return false; -} -``` - -`containsValue`将目标值作为参数,并立即调用`containsValueHelper`,传递树的根节点作为附加参数。 - -这是`containsValueHelper`的工作原理: - -+ 第一个`if`语句检查递归的边界情况。如果`node`是`null`,那意味着我们已经递归到树的底部,没有找到`target`,所以我们应该返回`false`。请注意,这只意味着目标没有出现在树的一条路径上;它仍然可能会在另一条路径上被发现。 -+ 第二种情况检查我们是否找到了我们正在寻找的东西。如果是这样,我们返回`true`。否则,我们必须继续。 -+ 第三种情况是执行递归调用,在左子树中搜索`target`。如果我们找到它,我们可以立即返回`true`,而不搜索右子树。否则我们继续。 -+ 第四种情况是搜索右子树。同样,如果我们找到我们正在寻找的东西,我们返回`true`。否则,我们搜索完了整棵树,返回`false`。 - -该方法“访问”了树中的每个节点,所以它的所需时间与节点数成正比。 - -## 13.3 实现`put` - -`put`方法比起`get`要复杂一些,因为要处理两种情况:(1)如果给定的键已经在树中,则替换并返回旧值;(2)否则必须在树中添加一个新的节点,在正确的地方。 - - -在上一个练习中,我提供了这个起始代码: - -```java -public V put(K key, V value) { - if (key == null) { - throw new IllegalArgumentException(); - } - if (root == null) { - root = new Node(key, value); - size++; - return null; - } - return putHelper(root, key, value); -} -``` - -并且让你填充`putHelper`。这里是我的答案: - -```java -private V putHelper(Node node, K key, V value) { - Comparable k = (Comparable) key; - int cmp = k.compareTo(node.key); - - if (cmp < 0) { - if (node.left == null) { - node.left = new Node(key, value); - size++; - return null; - } else { - return putHelper(node.left, key, value); - } - } - if (cmp > 0) { - if (node.right == null) { - node.right = new Node(key, value); - size++; - return null; - } else { - return putHelper(node.right, key, value); - } - } - V oldValue = node.value; - node.value = value; - return oldValue; -} -``` - -第一个参数`node`最初是树的根,但是每次我们执行递归调用,它指向了不同的子树。就像`get`一样,我们用`compareTo`方法来弄清楚,跟随哪一条树的路径。如果`cmp < 0`,我们添加的键小于`node.key`,那么我们要走左子树。有两种情况: - -+ 如果左子树为空,那就是,如果`node.left`是`null`,我们已经到达树的底部而没有找到`key`。这个时候,我们知道`key`不在树上,我们知道它应该放在哪里。所以我们创建一个新节点,并将它添加为`node`的左子树。 -+ 否则我们进行递归调用来搜索左子树。 - -如果`cmp > 0`,我们添加的键大于`node.key`,那么我们要走右子树。我们处理的两个案例与上一个分支相同。最后,如果`cmp == 0`,我们在树中找到了键,那么我们更改它并返回旧的值。 - -我使用递归编写了这个方法,使它更易于阅读,但它可以直接用迭代重写一遍,你可能想留作练习。 - -## 13.4 中序遍历 - -我要求你编写的最后一个方法是`keySet`,它返回一个`Set`,按升序包含树中的键。在其他`Map`实现中,`keySet`返回的键没有特定的顺序,但是树形实现的一个功能是,对键进行简单而有效的排序。所以我们应该利用它。 - -这是我的答案: - -```java -public Set keySet() { - Set set = new LinkedHashSet(); - addInOrder(root, set); - return set; -} - -private void addInOrder(Node node, Set set) { - if (node == null) return; - addInOrder(node.left, set); - set.add(node.key); - addInOrder(node.right, set); -} -``` - -在`keySet`中,我们创建一个`LinkedHashSet`,这是一个`Set`实现,使元素保持有序(与大多数其他`Set`实现不同)。然后我们调用`addInOrder`来遍历树。 - -第一个参数`node`最初是树的根,但正如你的期望,我们用它来递归地遍历树。`addInOrder`对树执行经典的“中序遍历”。 - -如果`node`是`null`,这意味着子树是空的,所以我们返回,而不向`set`添加任何东西。否则我们: - -1. 按顺序遍历左子树。 -1. 添加`node.key`。 -1. 按顺序遍历右子树。 - -请记住,BST 的特性保证左子树中的所有节点都小于`node.key`,并且右子树中的所有节点都更大。所以我们知道,`node.key`已按正确的顺序添加。 - -递归地应用相同的参数,我们知道左子树中的元素是有序的,右子树中的元素也一样。并且边界情况是正确的:如果子树为空,则不添加任何键。所以我们可以认为,该方法以正确的顺序添加所有键。 - -因为`containsValue`方法访问树中的每个节点,所以所需时间与`n`成正比。 - -## 13.5 对数时间的方法 - -在`MyTreeMap`中,`get`和`put`方法所需时间与树的高度`h`成正比。在上一个练习中,我们展示了如果树是满的 - 如果树的每一层都包含最大数量的节点 - 树的高度与`log n`成横臂。 - - -我也说了,`get`和`put`是对数时间的;也就是说,他们的所需时间与`logn`成正比。但是对于大多数应用程序,不能保证树是满的。一般来说,树的形状取决于键和添加顺序。 - -为了看看这在实践中是怎么回事,我们将用两个样本数据集来测试我们的实现:随机字符串的列表和升序的时间戳列表。 - - -这是生成随机字符串的代码: - -```java -Map map = new MyTreeMap(); - -for (int i=0; i map = new MyTreeMap(); - -for (int i=0; i 上阅读自平衡树的更多信息。 - -## 13.7 更多练习 - -在上一个练习中,你不必实现`remove`,但你可能需要尝试。如果从树中央删除节点,则必须重新排列剩余的节点,来恢复 BST 的特性。你可以自己弄清楚如何实现,或者你可以阅读 上的说明。 - -删除一个节点并重新平衡一个树是类似的操作:如果你做这个练习,你将更好地了解自平衡树如何工作。 diff --git a/docs/think-dast-zh/14.md b/docs/think-dast-zh/14.md deleted file mode 100644 index b512076bd..000000000 --- a/docs/think-dast-zh/14.md +++ /dev/null @@ -1,326 +0,0 @@ -# 第十四章 持久化 - -> 原文:[Chapter 14 Persistence](http://greenteapress.com/thinkdast/html/thinkdast015.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -在接下来的几个练习中,我们将返回到网页搜索引擎的构建。为了回顾,搜索引擎的组件是: - -+ 抓取:我们需要一个程序,可以下载一个网页,解析它,并提取文本和任何其他页面的链接。 -+ 索引:我们需要一个索引,可以查找检索项并找到包含它的页面。 -+ 检索:我们需要一种方法,从索引中收集结果,并识别与检索项最相关的页面。 - -如果你做了练习 8.3,你使用 Java 映射实现了一个索引。在本练习中,我们将重新审视索引器,并创建一个新版本,将结果存储在数据库中。 - - -如果你做了练习 7.4,你创建了一个爬虫,它跟踪它找到的第一个链接。在下一个练习中,我们将制作一个更通用的版本,将其查找到的每个链接存储在队列中,并对其进行排序。 - -然后,最后,你将处理检索问题。 - -在这些练习中,我提供较少的起始代码,你将做出更多的设计决策。这些练习也更加开放。我会提出一些最低限度的目标,你应该尝试实现它们,但如果你想挑战自己,有很多方法可以让你更深入。 - -现在,让我们开始编写一个新版本的索引器。 - -## 14.1 Redis - -索引器的之前版本,将索引存储在两个数据结构中:`TermCounter`将检索词映射为网页上显示的次数,以及`Index`将检索词映射为出现的页面集合。 - -这些数据结构存储在正在运行的 Java 程序的内存中,这意味着当程序停止运行时,索引会丢失。仅在运行程序的内存中存储的数据称为“易失的”,因为程序结束时会消失。 - - -在创建它的程序结束后,仍然存在的数据称为“持久的”。通常,存储在文件系统中的文件,以及存储在数据库中的数据是持久的。 - - -使数据持久化的一种简单方法是,将其存储在文件中。在程序结束之前,它可以将其数据结构转换为 JSON 格式(),然后将它们写入文件。当它再次启动时,它可以读取文件并重建数据结构。 - -但这个解决方案有几个问题: - -+ 读取和写入大型数据结构(如 Web 索引)会很慢。 -+ 整个数据结构可能不适合单个运行程序的内存。 -+ 如果程序意外结束(例如,由于断电),则自程序上次启动以来所做的任何更改都将丢失。 - -一个更好的选择是提供持久存储的数据库,并且能够读取和写入数据库的部分,而无需读取和写入整个数据。 - -有多种数据库管理系统(DBMS)提供不同的功能。你可以在 阅读概述。 - - -我为这个练习推荐的数据库是 Redis,它提供了类似于 Java 数据结构的持久数据结构。具体来说,它提供: - -字符串列表,与 Java 的`List`类似。 -哈希,类似于 Java 的`Map`。 -字符串集合,类似于 Java 的`Set`。 - -> 译者注:另外还有类似于 Java 的`LinkedHashSet`的有序集合。 - -Redis 是一个“键值数据库”,这意味着它包含的数据结构(值)由唯一的字符串(键)标识。Redis 中的键与 Java 中的引用相同:它标识一个对象。我们稍后会看到一些例子。 - -## 14.2 Redis 客户端和服务端 - -Redis 通常运行为远程服务;其实它的名字代表“REmote DIctionary Server”(远程字典服务,字典其实就是映射)。为了使用 Redis,你必须在某处运行 Redis 服务器,然后使用 Redis 客户端连接到 Redis 服务器。有很多方法可用于设置服务器,也有许多你可以使用的客户端。对于这个练习,我建议: - -不要自己安装和运行服务器,请考虑使用像 RedisToGo()这样的服务,它在云主机运行 Redis。他们提供了一个免费的计划(配置),有足够的资源用于练习。 -对于客户端,我推荐 Jedis,它是一个 Java 库,提供了使用 Redis 的类和方法。 - -以下是更详细的说明,以帮助你开始使用: - -+ 在 RedisToGo 上创建一个帐号,网址为 ,并选择所需的计划(可能是免费的起始计划)。 -+ 创建一个“实例”,它是运行 Redis 服务器的虚拟机。如果你单击“实例”选项卡,你将看到你的新实例,由主机名和端口号标识。例如,我有一个名为`dory-10534`的实例。 -+ 单击实例名称来访问配置页面。记下页面顶部附近的网址,如下所示: - ``` - redis://redistogo:1234567feedfacebeefa1e1234567@dory.redistogo.com:10534 - ``` - -这个 URL 包含服务器的主机名称`dory.redistogo.com`,端口号`10534`和连接到服务器所需的密码,它是中间较长的字母数字的字符串。你将需要此信息进行下一步。 - -## 14.3 制作基于 Redis 的索引 - -在本书的仓库中,你将找到此练习的源文件: - -+ `JedisMaker.java`包含连接到 Redis 服务器并运行几个 Jedis 方法的示例代码。 -+ `JedisIndex.java`包含此练习的起始代码。 -+ `JedisIndexTest.java`包含`JedisIndex`的测试代码。 -+ `WikiFetcher.java`包含我们在以前的练习中看到的代码,用于阅读网页并使用`jsoup`进行解析。 - -你还将需要这些文件,你在以前的练习中碰到过: - -`Index.java`使用 Java 数据结构实现索引。 -`TermCounter.java`表示从检索项到其频率的映射。 -`WikiNodeIterable.java`迭代`jsoup`生成的 DOM 树中的节点。 - -如果你有这些文件的有效版本,你可以使用它们进行此练习。如果你没有进行以前的练习,或者你对你的解决方案毫无信心,则可以从`solutions `文件夹复制我的解决方案。 - -第一步是使用 Jedis 连接到你的 Redis 服务器。`JedisMaker.java`展示了如何实现。它从文件读取你的 Redis 服务器的信息,连接到它并使用你的密码登录,然后返回一个可用于执行 Redis 操作的 Jedis 对象。 - - -如果你打开`JedisMaker.java`,你应该看到`JedisMaker`类,它是一个帮助类,它提供静态方法`make`,它创建一个 Jedis 对象。一旦该对象认证完毕,你可以使用它来与你的 Redis 数据库进行通信。 - -`JedisMaker`从名为`redis_url.txt`的文件读取你的 Redis 服务器信息,你应该放在目录`src/resources`中: - -+ 使用文本编辑器创建并编辑`ThinkDataStructures/code/src/resources/redis_url.txt`。 -+ 粘贴服务器的 URL。如果你使用的是 RedisToGo,则 URL 将如下所示: - ``` - redis://redistogo:1234567feedfacebeefa1e1234567@dory.redistogo.com:10534 - ``` - -因为此文件包含你的 Redis 服务器的密码,你不应将此文件放在公共仓库中。为了帮助你避免意外避免这种情况,仓库包含`.gitignore`文件,使文件难以(但不是不可能)放入你的仓库。 - -现在运行`ant build`来编译源文件,以及`ant JedisMaker`来运行`main`中的示例代码: - -```java - public static void main(String[] args) { - - Jedis jedis = make(); - - // String - jedis.set("mykey", "myvalue"); - String value = jedis.get("mykey"); - System.out.println("Got value: " + value); - - // Set - jedis.sadd("myset", "element1", "element2", "element3"); - System.out.println("element2 is member: " + - jedis.sismember("myset", "element2")); - - // List - jedis.rpush("mylist", "element1", "element2", "element3"); - System.out.println("element at index 1: " + - jedis.lindex("mylist", 1)); - - // Hash - jedis.hset("myhash", "word1", Integer.toString(2)); - jedis.hincrBy("myhash", "word2", 1); - System.out.println("frequency of word1: " + - jedis.hget("myhash", "word1")); - System.out.println("frequency of word1: " + - jedis.hget("myhash", "word2")); - - jedis.close(); - } -``` - -这个示例展示了数据类型和方法,你在这个练习中最可能使用它们。当你运行它时,输出应该是: - -``` -Got value: myvalue -element2 is member: true -element at index 1: element2 -frequency of word1: 2 -frequency of word2: 1 -``` - -下一节中我会解释代码的工作原理。 - -## 14.4 Redis 数据类型 - - -Redis 基本上是一个从键到值的映射,键是字符串,值可以是字符串,也可以是几种数据类型之一。最基本的 Redis 数据类型是字符串。我将用斜体书写 Redis 类型,来区别于 Java 类型。 - -为了向数据库添加一个字符串,请使用`jedis.set`,类似于`Map.put`; 参数是新的键和相应的值。为了查找一个键并获取其值,请使用`jedis.get`: - -```java - jedis.set("mykey", "myvalue"); - String value = jedis.get("mykey"); -``` - -在这个例子中,键是`"mykey"`,值是`"myvalue"`。 - -Redis 提供了一个集合结构,类似于 Java 的`Set`。为了向 Redis 集合添加元素,你可以选择一个键来标识集合,然后使用`jedis.sadd`: - -```java - jedis.sadd("myset", "element1", "element2", "element3"); - boolean flag = jedis.sismember("myset", "element2"); -``` - -你不必用单独的步骤来创建集合。如果不存在,Redis 会创建它。在这种情况下,它会创建一个名为`myset`的集合,包含三个元素。 - -`jedis.sismember`方法检查元素是否在一个集合中。添加元素和检查成员是常数时间的操作。 - - -Redis 还提供了一个列表结构,类似于 Java 的`List`。`jedis.rpush`方法在末尾(右端)向列表添加元素: - -```java - jedis.rpush("mylist", "element1", "element2", "element3"); - String element = jedis.lindex("mylist", 1); -``` - -同样,你不必在开始添加元素之前创建结构。此示例创建了一个名为`mylist`的列表,其中包含三个元素。 - -`jedis.lindex`方法使用整数索引,并返回列表中指定的元素。添加和访问元素是常数时间的操作。 - -最后,Redis 提供了一个哈希结构,类似于 Java 的`Map`。`jedis.hset`方法为哈希表添加新条目: - -```java - jedis.hset("myhash", "word1", Integer.toString(2)); - String value = jedis.hget("myhash", "word1"); -``` - -此示例创建一个名为的`myhash`哈希表,其中包含一个条目,该条目从将键`word1`映射到值`"2"`。 - -键和值都是字符串,所以如果我们要存储`Integer`,在我们调用`hset`之前,我们必须将它转换为`String`。当我们使用`hget`查找值时,结果是`String`,所以我们可能必须将其转换回`Integer`。 - - -使用 Redis 的哈希表可能会令人困惑,因为我们使用一个键来标识我们想要的哈希表,然后用另一个键标识哈希表中的值。在 Redis 的上下文中,第二个键被称为“字段”,这可能有助于保持清晰。所以类似`myhash`的“键”标志一个特定的哈希表,然后类似`word1`的“字段”标识一个哈希表中的值。 - -对于许多应用程序,Redis 哈希表中的值是整数,所以 Redis 提供了一些特殊的方法,比如`hincrby`将值作为数字来处理: - -```java - jedis.hincrBy("myhash", "word2", 1); -``` - -这个方法访问`myhash`,获取`word2`的当前值(如果不存在则为`0`),将其递增`1`,并将结果写回哈希表。 - -在哈希表中,设置,获取和递增条目是常数时间的操作。 - -你可以在 上阅读 Redis 数据类型的更多信息。 - -## 14.5 练习 11 - -这个时候,你可以获取一些信息,你需要使用它们来创建搜索引擎的索引,它将结果储存在 Redis 数据库中。 - - -现在运行`ant JedisIndexTest`。它应该失败,因为你有一些工作要做! - -`JedisIndexTest`测试了这些方法: - -+ `JedisIndex`,这是构造器,它接受`Jedis`对象作为参数。 -+ `indexPage`,它将一个网页添加到索引中;它需要一个`StringURL`和一个`jsoup Elements`对象,该对象包含应该建立索引的页面元素。 -+ `getCounts`,它接收检索词,并返回`Map`,包含检索词到它在页面上的出现次数的映射。 - -以下是如何使用这些方法的示例: - -```java - WikiFetcher wf = new WikiFetcher(); - String url1 = - "http://en.wikipedia.org/wiki/Java_(programming_language)"; - Elements paragraphs = wf.readWikipedia(url1); - - Jedis jedis = JedisMaker.make(); - JedisIndex index = new JedisIndex(jedis); - index.indexPage(url1, paragraphs); - Map map = index.getCounts("the"); -``` - -如果我们在结果`map`中查看`url1`,我们应该得到`339`,这是 Java 维基百科页面(即我们保存的版本)中,`the`出现的次数。 - -如果我们再次索引相同的页面,新的结果将替换旧的结果。 - -将数据结构从 Java 翻译成 Redis 的一个建议是:记住 Redis 数据库中的每个对象都以唯一的键标识,它是一个字符串。如果同一数据库中有两种对象,则可能需要向键添加前缀来区分它们。例如,在我们的解决方案中,我们有两种对象: - -+ 我们将`URLSet`定义为 Redis 集合,它包含`URL`,`URL`又包含给定检索词。每个`URLSet`的键的起始是`"URLSet:"`,所以要获取包含单词`the`的 URL,我们使用键`"URLSet:the"`来访问该集合。 -+ 我们将`TermCounter`定义为 Redis 哈希表,将出现在页面上的每个检索词映射到它的出现次数。`TermCounter`每个键的开头都以`"TermCounter:"`开头,以我们正在查找的页面的 URL 结尾。 - -在我的实现中,每个检索词都有一个`URLSet`,每个索引页面都有一个`TermCounter`。我提供两个辅助方法,`urlSetKey`和`termCounterKey`来组装这些键。 - -## 14.6 更多建议(如果你需要的话) - -到了这里,你拥有了完成练习所需的所有信息,所以如果准备好了就可以开始了。但是我有几个建议,你可能想先阅读它: - -+ 对于这个练习,我提供的指导比以前的练习少。你必须做出一些设计决策;特别是,你将必须弄清楚如何将问题分解成,你可以一次性测试的部分,然后将这些部分组合成一个完整的解决方案。如果你尝试一次写出整个项目,而不测试较小的部分,调试可能需要很长时间。 -+ 使用持久性数据的挑战之一是它是持久的。存储在数据库中的结构可能会在每次运行程序时发生更改。如果你弄乱了数据库,你将不得不修复它或重新开始,然后才能继续。为了帮助你控制住自己,我提供的方法叫`deleteURLSets`,`deleteTermCounters`和`deleteAllKeys`,你可以用它来清理数据库,并重新开始。你也可以使用`printIndex`来打印索引的内容。 -+ 每次调用 Jedis 的方法时,你的客户端会向服务器发送一条消息,然后服务器执行你请求的操作并发回消息。如果执行许多小操作,可能需要很长时间。你可以通过将一系列操作分组为一个`Transaction`,来提高性能。 - -例如,这是一个简单的`deleteAllKeys`版本: - -```java - public void deleteAllKeys() { - Set keys = jedis.keys("*"); - for (String key: keys) { - jedis.del(key); - } - } -``` - -每次调用`del`时,都需要从客户端到服务器的双向通信。如果索引包含多个页面,则该方法需要很长时间来执行。我们可以使用`Transaction`对象来加速: - -```java - public void deleteAllKeys() { - Set keys = jedis.keys("*"); - Transaction t = jedis.multi(); - for (String key: keys) { - t.del(key); - } - t.exec(); - } -``` - -`jedis.multi`返回一个`Transaction`对象,它提供`Jedis`对象的所有方法。但是当你调用`Transaction`的方法时,它不会立即执行该操作,并且不与服务器通信。在你调用`exec`之前,它会保存一批操作。然后它将所有保存的操作同时发送到服务器,这通常要快得多。 - -## 14.7 几个设计提示 - -现在你真的拥有了你需要的所有信息;你应该开始完成练习。但是如果你卡住了,或者如果你真的不知道如何开始,你可以再来一些提示。 - -在运行测试代码之前,不要阅读以下内容,尝试一些基本的 Redis 命令,并在`JedisIndex.java`中编写几个方法。 - -好的,如果你真的卡住了,这里有一些你可能想要处理的方法: - -```java - /** - * 向检索词相关的集合中添加 URL - */ - public void add(String term, TermCounter tc) {} - - /** - * 查找检索词并返回 URL 集合 - */ - public Set getURLs(String term) {} - - /** - * 返回检索词出现在给定 URL 中的次数 - */ - public Integer getCount(String url, String term) {} - - /** - * 将 TermCounter 的内容存入 Redis - */ - public List pushTermCounterToRedis(TermCounter tc) {} -``` - -这些是我在解决方案中使用的方法,但它们绝对不是将项目分解的唯一方法。所以如果他们有帮助,请接受这些建议,但是如果没有,请忽略它们。 - -对于每种方法,请考虑首先编写测试。当你弄清楚如何测试一个方法时,你经常会了解如何编写它。 - -祝你好运! diff --git a/docs/think-dast-zh/15.md b/docs/think-dast-zh/15.md deleted file mode 100644 index 6efece753..000000000 --- a/docs/think-dast-zh/15.md +++ /dev/null @@ -1,269 +0,0 @@ -# 第十五章 爬取维基百科 - -> 原文:[Chapter 15 Crawling Wikipedia](http://greenteapress.com/thinkdast/html/thinkdast016.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -在本章中,我展示了上一个练习的解决方案,并分析了 Web 索引算法的性能。然后我们构建一个简单的 Web 爬虫。 - -## 15.1 基于 Redis 的索引器 - -在我的解决方案中,我们在 Redis 中存储两种结构: - -+ 对于每个检索词,我们有一个`URLSet`,它是一个 Redis 集合,包含检索词的 URL。 -+ 对于每个网址,我们有一个`TermCounter`,这是一个 Redis 哈希表,将每个检索词映射到它出现的次数。 - -我们在上一章讨论了这些数据类型。你还可以在 上阅读 Redis `Set和`Hash`的信息 - -在`JedisIndex`中,我提供了一个方法,它可以接受一个检索词并返回 Redis 中它的`URLSet`的键: - -```java -private String urlSetKey(String term) { - return "URLSet:" + term; -} -``` - -以及一个方法,接受 URL 并返回 Redis 中它的`TermCounter`的键。 - -```java -private String termCounterKey(String url) { - return "TermCounter:" + url; -} -``` - -这里是`indexPage`的实现。 - -```java -public void indexPage(String url, Elements paragraphs) { - System.out.println("Indexing " + url); - - // make a TermCounter and count the terms in the paragraphs - TermCounter tc = new TermCounter(url); - tc.processElements(paragraphs); - - // push the contents of the TermCounter to Redis - pushTermCounterToRedis(tc); -} -``` - -为了索引页面,我们: - -+ 为页面内容创建一个 Java 的`TermCounter`,使用上一个练习中的代码。 -+ 将`TermCounter`的内容推送到 Redis。 - -以下是将`TermCounter`的内容推送到 Redis 的新代码: - -```java -public List pushTermCounterToRedis(TermCounter tc) { - Transaction t = jedis.multi(); - - String url = tc.getLabel(); - String hashname = termCounterKey(url); - - // if this page has already been indexed, delete the old hash - t.del(hashname); - - // for each term, add an entry in the TermCounter and a new - // member of the index - for (String term: tc.keySet()) { - Integer count = tc.get(term); - t.hset(hashname, term, count.toString()); - t.sadd(urlSetKey(term), url); - } - List res = t.exec(); - return res; -} -``` - -该方法使用`Transaction`来收集操作,并将它们一次性发送到服务器,这比发送一系列较小操作要快得多。 - -它遍历`TermCounter`中的检索词。对于每一个,它: - -+ 在 Redis 上寻找或者创建`TermCounter`,然后为新的检索词添加字段。 -+ 在 Redis 上寻找或创建`URLSet`,然后添加当前的 URL。 - -如果页面已被索引,则`TermCounter`在推送新内容之前删除旧页面 。 - -新的页面的索引就是这样。 - - -练习的第二部分要求你编写`getCounts`,它需要一个检索词,并从该词出现的每个网址返回一个映射。这是我的解决方案: - -```java - public Map getCounts(String term) { - Map map = new HashMap(); - Set urls = getURLs(term); - for (String url: urls) { - Integer count = getCount(url, term); - map.put(url, count); - } - return map; - } -``` - -此方法使用两种辅助方法: - -+ `getURLs`接受检索词并返回该字词出现的网址集合。 -+ `getCount`接受 URL 和检索词,并返回该检索词在给定 URL 处显示的次数。 - -以下是实现: - -```java - public Set getURLs(String term) { - Set set = jedis.smembers(urlSetKey(term)); - return set; - } - - public Integer getCount(String url, String term) { - String redisKey = termCounterKey(url); - String count = jedis.hget(redisKey, term); - return new Integer(count); - } -``` - -由于我们设计索引的方式,这些方法简单而高效。 - -## 15.2 查找的分析 - -假设我们索引了`N`个页面,并发现了`M`个唯一的检索词。检索词的查询需要多长时间?在继续之前,先考虑一下你的答案。 - -要查找一个检索词,我们调用`getCounts`,其中: - -+ 创建映射。 -+ 调用`getURLs`来获取 URL 的集合。 -+ 对于集合中的每个 URL,调用`getCount`并将条目添加到`HashMap`。 - -`getURLs`所需时间与包含检索词的网址数成正比。对于罕见的检索词,这可能是一个很小的数字,但是对于常见检索词,它可能和`N`一样大。 - -在循环中,我们调用了`getCount`,它在 Redis 上寻找`TermCounter`,查找一个检索词,并向`HashMap`添加一个条目。那些都是常数时间的操作,所以在最坏的情况下,`getCounts`的整体复杂度是`O(N)`。然而实际上,运行时间正比于包含检索词的页面数量,通常比`N`小得多。 - - -这个算法根据复杂性是有效的,但是它非常慢,因为它向 Redis 发送了许多较小的操作。你可以使用`Transaction`来加快速度 。你可能留作一个练习,或者你可以在`RedisIndex.java`中查看我的解决方案。 - -## 15.3 索引的分析 - -使用我们设计的数据结构,页面的索引需要多长时间?再次考虑你的答案,然后再继续。 - -为了索引页面,我们遍历其 DOM 树,找到所有`TextNode`对象,并将字符串拆分成检索词。这一切都与页面上的单词数成正比。 - - -对于每个检索词,我们在`HashMap`中增加一个计数器,这是一个常数时间的操作。所以创建`TermCounter`的所需时间与页面上的单词数成正比。 - - -将`TermCounter`推送到 Redis ,需要删除`TermCounter`,对于唯一检索词的数量是线性的。那么对于每个检索词,我们必须: - -+ 向`URLSet`添加元素,并且 -+ 向 Redis`TermCounter`添加元素。 - -这两个都是常数时间的操作,所以推送`TermCounter`的总时间对于唯一检索词的数量是线性的。 - -总之,`TermCounter`的创建与页面上的单词数成正比。向 Redis 推送`TermCounter`与唯一检索词的数量成正比。 - - -由于页面上的单词数量通常超过唯一检索词的数量,因此整体复杂度与页面上的单词数成正比。理论上,一个页面可能包含索引中的所有检索词,因此最坏的情况是`O(M)`,但实际上我们并不期待看到更糟糕的情况。 - -这个分析提出了一种提高效率的方法:我们应该避免索引很常见的词语。首先,他们占用了大量的时间和空间,因为它们出现在几乎每一个`URLSet`和`TermCounter`中。此外,它们不是很有用,因为它们不能帮助识别相关页面。 - -大多数搜索引擎避免索引常用单词,这在本文中称为停止词()。 - -## 15.4 图的遍历 - -如果你在第七章中完成了“到达哲学”练习,你已经有了一个程序,它读取维基百科页面,找到第一个链接,使用链接加载下一页,然后重复。这个程序是一种专用的爬虫,但是当人们说“网络爬虫”时,他们通常意味着一个程序: - -加载起始页面并对内容进行索引, -查找页面上的所有链接,并将链接的 URL 添加到集合中 -通过收集,加载和索引页面,以及添加新的 URL,来按照它的方式工作。 -如果它找到已经被索引的 URL,会跳过它。 - -你可以将 Web 视为图,其中每个页面都是一个节点,每个链接都是从一个节点到另一个节点的有向边。如果你不熟悉图,可以阅读 。 - -从源节点开始,爬虫程序遍历该图,访问每个可达节点一次。 - - -我们用于存储 URL 的集合决定了爬虫程序执行哪种遍历: - -+ 如果它是先进先出(FIFO)的队列,则爬虫程序将执行广度优先遍历。 -+ 如果它是后进先出(LIFO)的栈,则爬虫程序将执行深度优先遍历。 -+ 更通常来说,集合中的条目可能具有优先级。例如,我们可能希望对尚未编入索引的页面给予较高的优先级。 - -你可以在 上阅读图的遍历的更多信息 。 - -## 15.5 练习 12 - -现在是时候写爬虫了。在本书的仓库中,你将找到此练习的源文件: - -+ `WikiCrawler.java`,包含你的爬虫的其实代码。 -+ `WikiCrawlerTest.java`,包含`WikiCrawler`的测试代码。 -+ `JedisIndex.java`,这是我以前的练习的解决方案。 - -你还需要一些我们以前练习中使用过的辅助类: - -+ `JedisMaker.java` -+ `WikiFetcher.java` -+ `TermCounter.java` -+ `WikiNodeIterable.java` - -在运行`JedisMaker`之前,你必须提供一个文件,关于你的 Redis 服务器信息。如果你在上一个练习中这样做,你应该全部配置好了。否则,你可以在 14.3 节中找到说明。 - -运行`ant build`来编译源文件,然后运行`ant JedisMaker`来确保它配置为连接到你的 Redis 服务器。 - -现在运行`ant WikiCrawlerTest`。它应该失败,因为你有工作要做! - -这是我提供的`WikiCrawler`类的起始: - -```java -public class WikiCrawler { - - public final String source; - private JedisIndex index; - private Queue queue = new LinkedList(); - final static WikiFetcher wf = new WikiFetcher(); - - public WikiCrawler(String source, JedisIndex index) { - this.source = source; - this.index = index; - queue.offer(source); - } - - public int queueSize() { - return queue.size(); - } -``` - -实例变量是: - -+ `source`是我们开始抓取的网址。 -+ `index`是`JedisIndex`,结果应该放进这里。 -+ `queue`是`LinkedList`,这里面我们跟踪已发现但尚未编入索引的网址。 -+ `wf`是`WikiFetcher`,我们用来读取和解析网页。 - -你的工作是填写`crawl`。这是原型: - -```java -public String crawl(boolean testing) throws IOException {} -``` - -当这个方法在`WikiCrawlerTest`中调用时,`testing`参数为`true`,否则为`false`。 - -如果`testing`是`true`,`crawl`方法应该: - -+ 以 FIFO 的顺序从队列中选择并移除一个 URL。 -+ 使用`WikiFetcher.readWikipedia`读取页面的内容,它读取仓库中包含的,页面的缓存副本来进行测试(如果维基百科的版本更改,则避免出现问题)。 -+ 它应该索引页面,而不管它们是否已经被编入索引。 -+ 它应该找到页面上的所有内部链接,并按他们出现的顺序将它们添加到队列中。“内部链接”是指其他维基百科页面的链接。 -+ 它应该返回其索引的页面的 URL。 - -如果`testing`是`false`,这个方法应该: - -+ 以 FIFO 的顺序从队列中选择并移除一个 URL。 -+ 如果 URL 已经被编入索引,它不应该再次索引,并应该返回`null`。 -+ 否则它应该使用`WikiFetcher.fetchWikipedia`读取页面内容,从 Web 中读取当前内容。 -+ 然后,它应该对页面进行索引,将链接添加到队列,并返回其索引的页面的 URL。 - -`WikiCrawlerTest`加载具有大约`200`个链接的队列,然后调用`crawl`三次。每次调用后,它将检查队列的返回值和新长度。 - -当你的爬虫按规定工作时,此测试应通过。祝你好运! diff --git a/docs/think-dast-zh/16.md b/docs/think-dast-zh/16.md deleted file mode 100644 index 9b8ba745a..000000000 --- a/docs/think-dast-zh/16.md +++ /dev/null @@ -1,318 +0,0 @@ -# 第十六章 布尔搜索 - -> 原文:[Chapter 16 Boolean search](http://greenteapress.com/thinkdast/html/thinkdast017.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -在本章中,我展示了上一个练习的解决方案。然后,你将编写代码来组合多个搜索结果,并按照它与检索词的相关性进行排序。 - -## 16.1 爬虫的答案 - -首先,我们来解决上一个练习。我提供了一个`WikiCrawler`的大纲;你的工作是填写`crawl`。作为一个提醒,这里是`WikiCrawler`类中的字段: - -```java -public class WikiCrawler { - // keeps track of where we started - private final String source; - - // the index where the results go - private JedisIndex index; - - // queue of URLs to be indexed - private Queue queue = new LinkedList(); - - // fetcher used to get pages from Wikipedia - final static WikiFetcher wf = new WikiFetcher(); -} -``` - -当我们创建`WikiCrawler`时,我们传入`source`和 index。最初`queue`只包含一个元素,`source`。 - -注意,`queue`的实现是`LinkedList`,所以我们可以在末尾添加元素,并从开头删除它们 - 以常数时间。通过将`LinkedList`对象赋给`Queue`变量,我们将使用的方法限制在`Queue`接口中;具体来说,我们将使用`offer`添加元素,以及`poll`来删除它们。 - -这是我的`WikiCrawler.crawl`的实现: - -```java - public String crawl(boolean testing) throws IOException { - if (queue.isEmpty()) { - return null; - } - String url = queue.poll(); - System.out.println("Crawling " + url); - - if (testing==false && index.isIndexed(url)) { - System.out.println("Already indexed."); - return null; - } - - Elements paragraphs; - if (testing) { - paragraphs = wf.readWikipedia(url); - } else { - paragraphs = wf.fetchWikipedia(url); - } - index.indexPage(url, paragraphs); - queueInternalLinks(paragraphs); - return url; - } -``` - -这个方法的大部分复杂性是使其易于测试。这是它的逻辑: - -+ 如果队列为空,则返回`null`来表明它没有索引页面。 -+ 否则,它将从队列中删除并存储下一个 URL。 -+ 如果 URL 已经被索引,`crawl`不会再次对其进行索引,除非它处于测试模式。 -+ 接下来,它读取页面的内容:如果它处于测试模式,它从文件读取;否则它从 Web 读取。 -+ 它将页面索引。 -+ 它解析页面并向队列添加内部链接。 -+ 最后,它返回索引的页面的 URL。 - -我在 15.1 节展示了`Index.indexPage`的一个实现。所以唯一的新方法是`WikiCrawler.queueInternalLinks`。 - -我用不同的参数编写了这个方法的两个版本:一个是`Elements`对象,包含每个段落的 DOM 树,另一个是`Element`对象,包含大部分段落。 - - -第一个版本只是循环遍历段落。第二个版本是实际的逻辑。 - -```java - void queueInternalLinks(Elements paragraphs) { - for (Element paragraph: paragraphs) { - queueInternalLinks(paragraph); - } - } - - private void queueInternalLinks(Element paragraph) { - Elements elts = paragraph.select("a[href]"); - for (Element elt: elts) { - String relURL = elt.attr("href"); - - if (relURL.startsWith("/wiki/")) { - String absURL = elt.attr("abs:href"); - queue.offer(absURL); - } - } - } -``` - -要确定链接是否为“内部”链接,我们检查 URL 是否以`/wiki/`开头。这可能包括我们不想索引的一些页面,如有关维基百科的元页面。它可能会排除我们想要的一些页面,例如非英语语言页面的链接。但是,这个简单的测试足以起步了。 - -这就是它的一切。这个练习没有很多新的材料;这主要是一个机会,把这些作品组装到一起。 - -## 16.2 信息检索 - -这个项目的下一个阶段是实现一个搜索工具。我们需要的部分包括: - -+ 一个界面,其中用户可以提供检索词并查看结果。 -+ 一种查找机制,它接收每个检索词并返回包含它的页面。 -+ 用于组合来自多个检索词的搜索结果的机制。 -+ 对搜索结果打分和排序的算法。 - -用于这样的过程的通用术语是“信息检索”,你可以在 上阅读更多信息 。 - -在本练习中,我们将重点介绍步骤 3 和 4 。我们已经构建了一个 2 的简单的版本。如果你有兴趣构建 Web 应用程序,则可以考虑完成步骤 1。 - -## 16.3 布尔搜索 - -大多数搜索引擎可以执行“布尔搜索”,这意味着你可以使用布尔逻辑来组合来自多个检索词的结果。例如: - -+ 搜索“java + 编程”(加号可省略)可能只返回包含两个检索词:“java”和“编程”的页面。 -+ “java OR 编程”可能会返回包含任一检索词但不一定同时出现的页面。 -+ “java -印度尼西亚”可能返回包含“java”,不包含“印度尼西亚”的页面。 - -包含检索词和运算符的表达式称为“查询”。 - -当应用给搜索结果时,布尔操作符`+`,`OR`和`-`对应于集合操作 交,并和差。例如,假设 - -+ `s1`是包含“java”的页面集, -+ `s2`是包含“编程”的页面集,以及 -+ `s3`是包含“印度尼西亚”的页面集。 - -在这种情况下: - -+ `s1`和`s2`的交集是含有“java”和“编程”的页面集。 -+ `s1`和`s2`的并集是含有“java”或“编程”的页面集。 -+ `s1`与`s2`的差集是含有“java”而不含有“印度尼西亚”的页面集。 - -在下一节中,你将编写实现这些操作的方法。 - -## 16.4 练习 13 - -在本书的仓库中,你将找到此练习的源文件: -+ -+ `WikiSearch.java`,它定义了一个对象,包含搜索结果并对其执行操作。 -+ `WikiSearchTest.java`,它包含`WikiSearch`的测试代码。 -+ `Card.java`,它演示了如何使用`java.util.Collections`的`sort`方法。 - -你还将找到我们以前练习中使用过的一些辅助类。 - -这是`WikiSearch`类定义的起始: - -```java -public class WikiSearch { - - // map from URLs that contain the term(s) to relevance score - private Map map; - - public WikiSearch(Map map) { - this.map = map; - } - - public Integer getRelevance(String url) { - Integer relevance = map.get(url); - return relevance==null ? 0: relevance; - } -} -``` - -`WikiSearch`对象包含 URL 到它们的相关性分数的映射。在信息检索的上下文中,“相关性分数”用于表示页面多么满足从查询推断出的用户需求。相关性分数的构建有很多种方法,但大部分都基于“检索词频率”,它是搜索词在页面上的显示次数。一种常见的相关性分数称为 TF-IDF,代表“检索词频率 - 逆向文档频率”。你可以在 上阅读更多信息 。 - -你可以选择稍后实现 TF-IDF,但是我们将从一些更简单的 TF 开始: - -+ 如果查询包含单个检索词,页面的相关性就是其词频;也就是说该词在页面上出现的次数。 -+ 对于具有多个检索词的查询,页面的相关性是检索词频率的总和;也就是说,任何检索词出现的总次数。 - -现在你准备开始练习了。运行`ant build`来编译源文件,然后运行 `ant WikiSearchTest`。像往常一样,它应该失败,因为你有工作要做。 - -在`WikiSearch.java`中,填充的`and`,`or`以及`minus`的主体,使相关测试通过。你不必担心`testSort`。 - - -你可以运行`WikiSearchTest`而不使用`Jedis`,因为它不依赖于 Redis 数据库中的索引。但是,如果要对索引运行查询,则必须向文件提供有关`Redis`服务器的信息。详见 14.3 节。 - - -运行`ant JedisMaker`来确保它配置为连接到你的 Redis 服务器。然后运行`WikiSearch`,它打印来自三个查询的结果: - -+ “java” -+ “programming” -+ “java AND programming” - -最初的结果不按照特定的顺序,因为`WikiSearch.sort`是不完整的。 - -填充`sort`的主体,使结果以递增的相关顺序返回。我建议你使用`java.util.Collections`提供的`sort`方法,它可以排序任何种类的`List`。你可以阅读 上的文档 。 - -有两个`sort`版本: - -+ 单参数版本接受列表并使用它的`compareTo`方法对元素进行排序,因此元素必须是`Comparable`。 -+ 双参数版本接受任何对象类型的列表和一个`Comparator`,它是一个提供`compare`方法的对象,用于比较元素。 - -如果你不熟悉`Comparable`和`Comparator`接口,我将在下一节中解释它们。 - -## 16.5 `Comparable`和`Comparator` - -本书的仓库包含了`Card.java`,它演示了两个方式来排序`Card`对象的列表。这里是类定义的起始: - -```java -public class Card implements Comparable { - - private final int rank; - private final int suit; - - public Card(int rank, int suit) { - this.rank = rank; - this.suit = suit; - } -``` - -`Card`对象拥有两个整形字段,`rank`和`suit`。`Card`实现了`Comparable`,也就是说它提供`compareTo`: - -```java - public int compareTo(Card that) { - if (this.suit < that.suit) { - return -1; - } - if (this.suit > that.suit) { - return 1; - } - if (this.rank < that.rank) { - return -1; - } - if (this.rank > that.rank) { - return 1; - } - return 0; - } -``` - -`compareTo`规范表明,如果`this`小于`that`,则应该返回一个负数,如果它更大,则为正数,如果它们相等则为`0`。 - -如果使用单参数版本的`Collections.sort`,它将使用元素提供的`compareTo`方法对它们进行排序。为了演示,我们可以列出`52`张卡,如下所示: - -```java - public static List makeDeck() { - List cards = new ArrayList(); - for (int suit = 0; suit <= 3; suit++) { - for (int rank = 1; rank <= 13; rank++) { - Card card = new Card(rank, suit); - cards.add(card); - } - } - return cards; - } -``` - -并这样排序它们: - -```java - Collections.sort(cards); -``` - -这个版本的`sort`将元素按照所谓的“自然秩序”放置,因为它由对象本身决定。 - -但是可以通过提供一个`Comparator`对象,来强制实现不同的排序。例如,`Card`对象的自然顺序将`Ace`视为最小的牌,但在某些纸牌游戏中,它的排名最高。我们可以定义一个`Comparator`,将`Ace`视为最大的牌,像这样: - -```java - Comparator comparator = new Comparator() { - @Override - public int compare(Card card1, Card card2) { - if (card1.getSuit() < card2.getSuit()) { - return -1; - } - if (card1.getSuit() > card2.getSuit()) { - return 1; - } - int rank1 = getRankAceHigh(card1); - int rank2 = getRankAceHigh(card2); - - if (rank1 < rank2) { - return -1; - } - if (rank1 > rank2) { - return 1; - } - return 0; - } - - private int getRankAceHigh(Card card) { - int rank = card.getRank(); - if (rank == 1) { - return 14; - } else { - return rank; - } - } - }; -``` - -该代码定义了一个匿名类,按需实现`compare`。然后它创建一个新定义的匿名类的实例。如果你不熟悉 Java 中的匿名类,可以在 上阅读它们。 - -使用这个`Comparator`,我们可以这样调用`sort`: - -```java - Collections.sort(cards, comparator); -``` - - -在这个顺序中,黑桃的`Ace`是牌组上的最大的牌;梅花二是最小的。 - -如果你想试验这个部分的代码,它们在`Card.java`中。作为一个练习,你可能打算写一个比较器,先按照`rank`,然后再按照`suit`,所以所有的`Ace`都应该在一起,所有的二也是。以此类推。 - -## 16.6 扩展 - -如果你完成了此练习的基本版本,你可能需要处理这些可选练习: - -+ 请阅读 上的 TF-IDF,并实现它。你可能需要修改`JavaIndex`来计算文档频率;也就是说,每个检索词在索引的所有页面上出现的总次数。 -+ 对于具有多个检索词的查询,每个页面的总体相关性目前是每个检索词的相关性的总和。想想这个简单版本什么时候可能无法正常运行,并尝试一些替代方案。 -+ 构建用户界面,允许用户输入带有布尔运算符的查询。解析查询,生成结果,然后按相关性排序,并显示评分最高的 URL。考虑生成“片段”,它显示了检索词出现在页面的哪里。如果要为用户界面制作 Web 应用程序,请考虑将 Heroku 作为简单选项,用于 开发和部署 Java Web应用程序。见 。 diff --git a/docs/think-dast-zh/17.md b/docs/think-dast-zh/17.md deleted file mode 100644 index a230f65b1..000000000 --- a/docs/think-dast-zh/17.md +++ /dev/null @@ -1,291 +0,0 @@ -# 第十七章 排序 - -> 原文:[Chapter 17 Sorting](http://greenteapress.com/thinkdast/html/thinkdast018.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -计算机科学领域过度痴迷于排序算法。根据 CS 学生在这个主题上花费的时间,你会认为排序算法的选择是现代软件工程的基石。当然,现实是,软件开发人员可以在很多年中,或者整个职业生涯中,不必考虑排序如何工作。对于几乎所有的应用程序,它们都使用它们使用的语言或库提供的通用算法。通常这样就行了。 - -所以如果你跳过这一章,不了解排序算法,你仍然是一个优秀的开发人员。但是有一些原因你可能想要这样: - -+ 尽管有绝大多数应用程序都可以使用通用算法,但你可能需要了解两种专用算法:基数排序和有界堆排序。 -+ 一种排序算法,归并排序,是一个很好的教学示例,因为它演示了一个重要和实用的算法设计策略,称为“分治”。此外,当我们分析其表现时,你将了解到我们以前没有看到的增长级别,即线性对数。最后,一些最广泛使用的算法是包含归并排序的混合体。 -+ 了解排序算法的另一个原因是,技术面试官喜欢询问它们。如果你想要工作,如果你能展示 CS 文化素养,就有帮助。 - -因此,在本章中我们将分析插入排序,你将实现归并排序,我将给你讲解基数排序,你将编写有界堆排序的简单版本。 - -## 17.1 插入排序 - -我们将从插入排序开始,主要是因为它的描述和实现很简单。它不是很有效,但它有一些补救的特性,我们将看到它。 - - -我们不在这里解释算法,建议你阅读 中的插入排序的维基百科页面 ,其中包括伪代码和动画示例。当你理解了它的思路再回来。 - -这是 Java 中插入排序的实现: - -```java -public class ListSorter { - - public void insertionSort(List list, Comparator comparator) { - - for (int i=1; i < list.size(); i++) { - T elt_i = list.get(i); - int j = i; - while (j > 0) { - T elt_j = list.get(j-1); - if (comparator.compare(elt_i, elt_j) >= 0) { - break; - } - list.set(j, elt_j); - j--; - } - list.set(j, elt_i); - } - } -} -``` - -我定义了一个类,`ListSorter`作为排序算法的容器。通过使用类型参数`T`,我们可以编写一个方法,它在包含任何对象类型的列表上工作。 - -`insertionSort`需要两个参数,一个是任何类型的`List`,一个是`Comparator`,它知道如何比较类型`T`的对象。它对列表“原地”排序,这意味着它修改现有列表,不必分配任何新空间。 - -下面的示例演示了,如何使用`Integer`的`List`对象,调用此方法: - -```java - List list = new ArrayList( - Arrays.asList(3, 5, 1, 4, 2)); - - Comparator comparator = new Comparator() { - @Override - public int compare(Integer elt1, Integer elt2) { - return elt1.compareTo(elt2); - } - }; - - ListSorter sorter = new ListSorter(); - sorter.insertionSort(list, comparator); - System.out.println(list); -``` - -`insertionSort`有两个嵌套循环,所以你可能会猜到,它的运行时间是二次的。在这种情况下,一般是正确的,但你做出这个结论之前,你必须检查,每个循环的运行次数与`n`,数组的大小成正比。 - -外部循环从`1`迭代到`list.size()`,因此对于列表的大小`n`是线性的。内循环从`i`迭代到`0`,所以在`n`中也是线性的。因此,两个循环运行的总次数是二次的。 - -如果你不确定,这里是证明: - -第一次循环中,`i = 1`,内循环最多运行一次。 -第二次,`i = 2`,内循环最多运行两次。 -最后一次,`i = n - 1`,内循环最多运行`n`次。 - -因此,内循环运行的总次数是序列`1, 2, ..., n - 1`的和,即`n(n - 1)/2`。该表达式的主项(拥有最高指数)为`n^2`。 - -在最坏的情况下,插入排序是二次的。然而: - -+ 如果这些元素已经有序,或者几乎这样,插入排序是线性的。具体来说,如果每个元素距离它的有序位置不超过`k`个元素,则内部循环不会运行超过`k`次,并且总运行时间是`O(kn)`。 -+ 由于实现简单,开销较低;也就是,尽管运行时间是`an^2`,主项的系数`a`,也可能是小的。 - -所以如果我们知道数组几乎是有序的,或者不是很大,插入排序可能是一个不错的选择。但是对于大数组,我们可以做得更好。其实要好很多。 - -## 17.2 练习 14 - -归并排序是运行时间优于二次的几种算法之一。同样,不在这里解释算法,我建议你阅读维基百科 。一旦你有了想法,反回来,你可以通过写一个实现来测试你的理解。 - - -在本书的仓库中,你将找到此练习的源文件: - -+ `ListSorter.java` -+ `ListSorterTest.java` - -运行`ant build`来编译源文件,然后运行`ant ListSorterTest`。像往常一样,它应该失败,因为你有工作要做。 - -在`ListSorter.java`中,我提供了两个方法的大纲,`mergeSortInPlace`以及`mergeSort`: - -```java - public void mergeSortInPlace(List list, Comparator comparator) { - List sorted = mergeSortHelper(list, comparator); - list.clear(); - list.addAll(sorted); - } - - private List mergeSort(List list, Comparator comparator) { - // TODO: fill this in! - return null; - } -``` - -这两种方法做同样的事情,但提供不同的接口。`mergeSort`获取一个列表,并返回一个新列表,具有升序排列的相同元素。`mergeSortInPlace`是修改现有列表的`void`方法。 - -你的工作是填充`mergeSort`。在编写完全递归版本的合并排序之前,首先要这样: - -+ 将列表分成两半。 -+ 使用`Collections.sort`或`insertionSort`来排序这两部分。 -+ 将有序的两部分合并为一个完整的有序列表中。 - -这将给你一个机会来调试用于合并的代码,而无需处理递归方法的复杂性。 - -接下来,添加一个边界情况(请参阅 < http://thinkdast.com/basecase> )。如果你只提供一个列表,仅包含一个元素,则可以立即返回,因为它已经有序。或者如果列表的长度低于某个阈值,则可以使用`Collections.sort`或`insertionSort`。在进行前测试边界情况。 - -最后,修改你的解决方案,使其进行两次递归调用来排序数组的两个部分。当你使其正常工作,`testMergeSort`和`testMergeSortInPlace`应该通过。 - -## 17.3 归并排序的分析 - -为了对归并排序的运行时间进行划分,对递归层级和每个层级上完成多少工作方面进行思考,是很有帮助的。假设我们从包含`n`个元素的列表开始。以下是算法的步骤: - -+ 生成两个新数组,并将一半元素复制到每个数组中。 -+ 排序两个数组。 -+ 合并两个数组。 - -图 17.1 显示了这些步骤。 - -![](img/17-1.jpg) - -图 17.1:归并排序的展示,它展示了递归的一个层级。 - -第一步复制每个元素一次,因此它是线性的。第三步也复制每个元素一次,因此它也是线性的。现在我们需要弄清楚步骤`2`的复杂性。为了做到这一点,查看不同的计算图片会有帮助,它展示了递归的层数,如图 17.2 所示。 - -![](img/17-2.jpg) - -图 17.2:归并排序的展示,它展示了递归的所有层级。 - -在顶层,我们有`1`个列表,其中包含`n`个元素。为了简单起见,我们假设`n`是`2`的幂。在下一层,有`2`个列表包含`n/2`个元素。然后是`4`个列表与`n/4`元素,以此类推,直到我们得到`n`个列表与`1`元素。 - -在每一层,我们共有`n`个元素。在下降的过程中,我们必须将数组分成两半,这在每一层上都需要与`n`成正比的时间。在回来的路上,我们必须合并`n`个元素,这也是线性的。 - -如果层数为`h`,算法的总工作量为`O(nh)`。那么有多少层呢?有两种方法可以考虑: - -+ 我们用多少步,可以将`n`减半直到`1`? -+ 或者,我们用多少步,可以将`1`加倍直到`n`? - -第二个问题的另一种形式是“`2`的多少次方是`n`”? - -``` -2^h = n -``` - -对两边取以`2`为底的对数: - -``` -h = log2(n) -``` - -所以总时间是`O(nlogn)`。我没有纠结于对数的底,因为底不同的对数差别在于一个常数,所以所有的对数都是相同的增长级别。 - - -`O(nlogn)`中的算法有时被称为“线性对数”的,但大多数人只是说`n log n`。 - - -事实证明,`O(nlogn)`是通过元素比较的排序算法的理论下限。这意味着没有任何“比较排序”的增长级别比`n log n`好。请参见 。 - -但是我们将在下一节中看到,存在线性时间的非比较排序! - -## 基数排序 - -在 2008 年美国总统竞选期间,候选人巴拉克·奥巴马在访问 Google 时,被要求进行即兴算法分析。首席执行长埃里克·施密特开玩笑地问他,“排序一百万个 32 位整数的最有效的方法”。显然有人暗中告诉了奥巴马,因为他很快就回答说:“我认为冒泡排序是错误的。”你可以在 观看视频。 - -奥巴马是对的:冒泡排序在概念上是简单的,但其运行时间是二次的; 即使在二次排序算法中,其性能也不是很好。见 。 - - -施密特想要的答案可能是“基数排序”,这是一种非比较排序算法,如果元素的大小是有界的,例如 32 位整数或 20 个字符的字符串,它就可以工作。 - - -为了看看它是如何工作的,想象你有一堆索引卡,每张卡片包含三个字母的单词。以下是一个方法,可以对卡进行排序: - -+ 根据第一个字母,将卡片放入桶中。所以以`a`开头的单词应该在一个桶中,其次是以`b`开头的单词,以此类推 -+ 根据第二个字母再次将卡片放入每个桶。所以以`aa`开头的应该在一起,其次是以`ab`开头的,以此类推当然,并不是所有的桶都是满的,但是没关系。 -+ 根据第三个字母再次将卡片放入每个桶。 - -此时,每个桶包含一个元素,桶按升序排列。图 17.3 展示了三个字母的例子。 - -![](img/17-3.jpg) - -图 17.3:三个字母的基数排序的例子 - -最上面那行显示未排序的单词。第二行显示第一次遍历后的桶的样子。每个桶中的单词都以相同的字母开头。 - -第二遍之后,每个桶中的单词以相同的两个字母开头。在第三遍之后,每个桶中只能有一个单词,并且桶是有序的。 - -在每次遍历期间,我们遍历元素并将它们添加到桶中。只要桶允许在恒定时间内添加元素,每次遍历是线性的。 - -遍历数量,我会称之为`w`,取决于单词的“宽度”,但不取决于单词的数量,`n`。所以增长级别是`O(wn)`,对于`n`是线性的。 - -基数排序有许多变体,并有许多方法来实现每一个。你可以在 上阅读他们的更多信息。作为一个可选的练习,请考虑编写基数排序的一个版本。 - -## 17.5 堆排序 - -基数排序适用于大小有界的东西,除了他之外,还有一种你可能遇到的其它专用排序算法:有界堆排序。如果你在处理非常大的数据集,你想要得到前 10 个或者前`k`个元素,其中`k`远小于`n`,它是很有用的。 - -例如,假设你正在监视一 个Web 服务,它每天处理十亿次事务。在每一天结束时,你要汇报最大的`k`个事务(或最慢的,或者其它最 xx 的)。一个选项是存储所有事务,在一天结束时对它们进行排序,然后选择最大的`k`个。需要的时间与`nlogn`成正比,这非常慢,因为我们可能无法将十亿次交易记录在单个程序的内存中。我们必须使用“外部”排序算法。你可以在 上了解外部排序。 - - -使用有界堆,我们可以做得更好!以下是我们的实现方式: - -+ 我会解释(无界)堆排序。 -+ 你会实现它 -+ 我将解释有界堆排序并进行分析。 - -要了解堆排序,你必须了解堆,这是一个类似于二叉搜索树(BST)的数据结构。有一些区别: - -+ 在 BST 中,每个节点`x`都有“BST 特性”:`x`左子树中的所有节点都小于`x`,右子树中的所有节点都大于`x`。 -+ 在堆中,每个节点`x`都有“堆特性”:两个子树中的所有节点都大于`x`。 -+ 堆就像平衡的 BST;当你添加或删除元素时,他们会做一些额外的工作来重新使树平衡。因此,可以使用元素的数组来有效地实现它们。 - -> 译者注:这里先讨论最小堆。如果子树中所有节点都小于`x`,那么就是最大堆。 - -堆中最小的元素总是在根节点,所以我们可以在常数时间内找到它。在堆中添加和删除元素需要的时间与树的高度`h`成正比。而且由于堆总是平衡的,所以`h`与`log n`成正比。你可以在 上阅读更多堆的信息。 - -Java`PriorityQueue`使用堆实现。`PriorityQueue`提供`Queue`接口中指定的方法,包括`offer`和`poll`: - -+ `offer`:将一个元素添加到队列中,更新堆,使每个节点都具有“堆特性”。需要`logn`的时间。 -+ `poll`:从根节点中删除队列中的最小元素,并更新堆。需要`logn`的时间。 - -给定一个`PriorityQueue`,你可以像这样轻松地排序的`n`个元素的集合 : - -+ 使用`offer`,将集合的所有元素添加到`PriorityQueue`。 -+ 使用`poll`从队列中删除元素并将其添加到`List`。 - -因为`poll`返回队列中剩余的最小元素,所以元素按升序添加到`List`。这种排序方式称为堆排序 (请参阅 )。 - -向队列中添加`n`个元素需要`nlogn`的时间。删除`n`个元素也是如此。所以堆排序的运行时间是`O(n logn)`。 - -在本书的仓库中,你可以在`ListSorter.java`中找到`heapSort`方法的大纲。填充它,然后运行`ant ListSorterTest`来确认它可以工作。 - -## 17.6 有界堆排序 - -有界堆是一个限制为最多包含`k`个元素的堆。如果你有`n`个元素,你可以跟踪这个最大的`k`个元素: - -最初堆是空的。对于每个元素`x`: - -+ 分支 1:如果堆不满,请添加`x`到堆中。 -+ 分支 2:如果堆满了,请与堆中`x`的最小元素进行比较。如果`x`较小,它不能是最大的`k`个元素之一,所以你可以丢弃它。 -+ 分支 3:如果堆满了,并且`x`大于堆中的最小元素,请从堆中删除最小的元素并添加`x`。 - -使用顶部为最小元素的堆,我们可以跟踪最大的`k`个元素。我们来分析这个算法的性能。对于每个元素,我们执行以下操作之一: - -+ 分支 1:将元素添加到堆是`O(log k)`。 -+ 分支 2:找到堆中最小的元素是`O(1)`。 -+ 分支 3:删除最小元素是`O(log k)`。添加`x`也是`O(log k)`。 - -在最坏的情况下,如果元素按升序出现,我们总是执行分支 3。在这种情况下,处理`n`个元素的总时间是`O(n log k)`,对于`n`是线性的。 - -在`ListSorter.java`中,你会发现一个叫做`topK`的方法的大纲,它接受一个`List`、`Comparator`和一个整数`k`。它应该按升序返回`List`的`k`个最大的元素 。填充它,然后运行`ant ListSorterTest`来确认它可以工作。 - -## 17.7 空间复杂性 - -到目前为止,我们已经谈到了很多运行时间的分析,但是对于许多算法,我们也关心空间。例如,归并排序的一个缺点是它会复制数据。在我们的实现中,它分配的空间总量是`O(n log n)`。通过更机智的实现,你可以将空间要求降至`O(n)`。 - -相比之下,插入排序不会复制数据,因为它会原地排序元素。它使用临时变量来一次性比较两个元素,并使用一些其它局部变量。但它的空间使用不取决于`n`。 - -我们的堆排序实现创建了新`PriorityQueue`,来存储元素,所以空间是`O(n)`; 但是如果你能够原地对列表排序,则可以使用`O(1)`的空间执行堆排序 。 - -刚刚实现的有界堆栈算法的一个好处是,它只需要与`k`成正比的空间(我们要保留的元素的数量),而`k`通常比`n`小得多 。 - -软件开发人员往往比空间更加注重运行时间,对于许多应用程序来说,这是适当的。但是对于大型数据集,空间可能同等或更加重要。例如: - -+ 如果一个数据集不能放入一个程序的内存,那么运行时间通常会大大增加,或者根本不能运行。如果你选择一个需要较少空间的算法,并且这样可以将计算放入内存中,则可能会运行得更快。同样,使用较少空间的程序,可能会更好地利用 CPU 缓存并运行速度更快(请参阅 )。 -+ 在同时运行多个程序的服务器上,如果可以减少每个程序所需的空间,则可以在同一台服务器上运行更多程序,从而降低硬件和能源成本。 - -所以这些是一些原因,你应该至少了解一些算法的空间需求。 diff --git a/docs/think-dast-zh/2.md b/docs/think-dast-zh/2.md deleted file mode 100644 index ed0c6ab05..000000000 --- a/docs/think-dast-zh/2.md +++ /dev/null @@ -1,231 +0,0 @@ -# 第二章 算法分析 - -> 原文:[Chapter 2 Analysis of Algorithms](http://greenteapress.com/thinkdast/html/thinkdast003.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -我们在前面的章节中看到,Java 提供了两种`List`接口的实现,`ArrayList`和`LinkedList`。对于一些应用,`LinkedList`更快;对于其他应用,`ArrayList`更快。 - -要确定对于特定的应用,哪一个更好,一种方法是尝试它们,并看看它们需要多长时间。这种称为“性能分析”的方法有一些问题: - -+ 在比较算法之前,你必须实现这两个算法。 -+ 结果可能取决于你使用什么样的计算机。一种算法可能在一台机器上更好;另一个可能在不同的机器上更好。 -+ 结果可能取决于问题规模或作为输入提供的数据。 - -我们可以使用算法分析来解决这些问题中的一些问题。当它有效时,算法分析使我们可以比较算法而不必实现它们。但是我们必须做出一些假设: - -+ 为了避免处理计算机硬件的细节,我们通常会识别构成算法的基本操作,如加法,乘法和数字比较,并计算每个算法所需的操作次数。 -+ 为了避免处理输入数据的细节,最好的选择是分析我们预期输入的平均性能。如果不可能,一个常见的选择是分析最坏的情况。 -+ 最后,我们必须处理一个可能性,一种算法最适合小问题,另一个算法适用于较大的问题。在这种情况下,我们通常专注于较大的问题,因为小问题的差异可能并不重要,但对于大问题,差异可能是巨大的。 - -这种分析适用于简单的算法分类。例如,如果我们知道算法`A`的运行时间通常与输入规模成正比,即`n`,并且算法`B`通常与`n ** 2`成比例,我们预计`A`比`B`更快,至少对于`n`的较大值。 - -大多数简单的算法只能分为几类。 - -+ 常数时间:如果运行时间不依赖于输入的大小,算法是“常数时间”。例如,如果你有一个`n`个元素的数组,并且使用下标运算符(`[]`)来访问其中一个元素,则此操作将执行相同数量的操作,而不管数组有多大。 -+ 线性:如果运行时间与输入的大小成正比,则算法为“线性”的。例如,如果你计算数组的和,则必须访问`n`个元素并执行`n - 1`个添加。操作的总数(元素访问和加法)为`2 * n -1`,与`n`成正比。 -+ 平方:如果运行时间与`n ** 2`成正比,算法是“平方”的。例如,假设你要检查列表中的任何元素是否多次出现。一个简单的算法是将每个元素与其他元素进行比较。如果有`n`个元素,并且每个元素与`n - 1`个其他元素进行比较,则比较的总数是`n ** 2 - n`,随着`n`增长它与`n ** 2`成正比。 - -## 2.1 选择排序 - -例如,这是一个简单算法的实现,叫做“选择排序”(请见 ): - -```java -public class SelectionSort { - - /** - * Swaps the elements at indexes i and j. - */ - public static void swapElements(int[] array, int i, int j) { - int temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - - /** - * Finds the index of the lowest value - * starting from the index at start (inclusive) - * and going to the end of the array. - */ - public static int indexLowest(int[] array, int start) { - int lowIndex = start; - for (int i = start; i < array.length; i++) { - if (array[i] < array[lowIndex]) { - lowIndex = i; - } - } - return lowIndex; - } - - /** - * Sorts the elements (in place) using selection sort. - */ - public static void selectionSort(int[] array) { - for (int i = 0; i < array.length; i++) { - int j = indexLowest(array, i); - swapElements(array, i, j); - } - } -} -``` - -第一个方法`swapElements`交换数组的两个元素。元素的是常数时间的操作,因为如果我们知道元素的大小和第一个元素的位置,我们可以使用一个乘法和一个加法来计算任何其他元素的位置,这都是常数时间的操作。由于`swapElements`中的一切都是恒定的时间,整个方法是恒定的时间。 - -第二个方法`indexLowest`从给定的索引`start`开始,找到数组中最小元素的索引。每次遍历循环的时候,它访问数组的两个元素并执行一次比较。由于这些都是常数时间的操作,因此我们计算什么并不重要。为了保持简单,我们来计算一下比较的数量。 - -+ 如果`start`为`0`,则`indexLowest`遍历整个数组,并且比较的总数是数组的长度,我称之为`n`。 -+ 如果`start`为`1`,则比较数为`n - 1`。 -+ 一般情况下,比较的次数是`n - start`,因此`indexLowest`是线性的。 - -第三个方法`selectionSort`对数组进行排序。它从`0`循环到`n - 1`,所以循环执行了`n`次。每次调用`indexLowest`然后执行一个常数时间的操作`swapElements`。 - -第一次`indexLowest`被调用的时候,它进行`n`次比较。第二次,它进行`n - 1`比较,依此类推。比较的总数是 - -``` -n + n−1 + n−2 + ... + 1 + 0 -``` - -这个数列的和是`n(n+1)/2`,它(近似)与`n ** 2`成正比;这意味着`selectionSort`是平方的。 - -为了得到同样的结果,我们可以将`indexLowest`看作一个嵌套循环。每次调用`indexLowest`时,操作次数与`n`成正比。我们调用它`n`次,所以操作的总数与`n ** 2`成正比。 - -## 2.2 大 O 表示法 - -所有常数时间算法属于称为`O(1)`的集合。所以,说一个算法是常数时间的另一个方法就是,说它是`O(1)`的。与之类似,所有线性算法属于`O(n)`,所有二次算法都属于`O(n ** 2)`。这种分类算法的方式被称为“大 O 表示法”。 - -注意:我提供了一个大 O 符号的非专业定义。更多的数学处理请参见 。 - -这个符号提供了一个方便的方式,来编写通用的规则,关于算法在我们构造它们时的行为。例如,如果你执行线性时间算法,之后是常量算法,则总运行时间是线性的。`∈`表示“是...的成员”: - -``` -f ∈ O(n) && g ∈ O(1) => f + g ∈ O(n) -``` - -如果执行两个线性运算,则总数仍然是线性的: - -``` -f ∈ O(n) && g ∈ O(n) => f + g ∈ O(n) -``` - -事实上,如果你执行任何次数的线性运算,`k`,总数就是线性的,只要`k`是不依赖于`n`的常数。 - -``` -f ∈ O(n) && k 是常数 => kf ∈ O(n) -``` - -但是,如果执行`n`次线性运算,则结果为平方: - -``` -f ∈ O(n) => nf ∈ O(n ** 2) -``` - -一般来说,我们只关心`n`的最大指数。所以如果操作总数为`2 * n + 1`,则属于`O(n)`。主要常数`2`和附加项`1`对于这种分析并不重要。与之类似,`n ** 2 + 100 * n + 1000`是`O(n ** 2)`的。不要被大的数值分心! - -“增长级别”是同一概念的另一个名称。增长级别是一组算法,其运行时间在同一个大 O 分类中;例如,所有线性算法都属于相同的增长级别,因为它们的运行时间为`O(n)`。 - -在这种情况下,“级别”是一个团体,像圆桌骑士的阶级,这是一群骑士,而不是一种排队方式。因此,你可以将线性算法的阶级设想为一组勇敢,仗义,特别有效的算法。 - -## 2.3 练习 2 - -本章的练习是实现一个`List`,使用 Java 数组来存储元素。 - -在本书的代码库(请参阅 0.1 节)中,你将找到你需要的源文件: - -+ `MyArrayList.java`包含`List`接口的部分实现。其中四个方法是不完整的;你的工作是填充他们。 -+ `MyArrayListTest.java`包含 JUnit 测试,可用于检查你的工作。 - -你还会发现 Ant 构建文件`build.xml`。你应该可以从代码目录运行`ant MyArrayList`,来运行`MyArrayList.java`,其中包含一些简单的测试。或者你可以运行`ant MyArrayListTest`运行 JUnit 测试。 - -当你运行测试时,其中几个应该失败。如果你检查源代码,你会发现四条 TODO 注释,表示你应该填充的方法。 - -在开始填充缺少的方法之前,让我们来看看一些代码。这里是类定义,实例变量和构造函数。 - -```java -public class MyArrayList implements List { - int size; // keeps track of the number of elements - private E[] array; // stores the elements - - public MyArrayList() { - array = (E[]) new Object[10]; - size = 0; - } -} -``` - -正如注释所述,`size`跟踪`MyArrayList`中由多少元素,而且`array`是实际包含的元素的数组。 - -构造函数创建一个 10 个元素的数组,这些元素最初为`null`,并且`size`设为`0`。·大多数时候,数组的长度大于`size`,所以数组中由未使用的槽。 - -Java 的一个细节:你不能使用类型参数实例化数组;例如,这样不起作用: - -``` -array = new E [10]; -``` - -要解决此限制,你必须实例化一个`Object`数组,然后进行类型转换。你可以在 上阅读此问题的更多信息。 - -接下来,我们将介绍添加元素到列表的方法: - -```java -public boolean add(E element) { - if (size >= array.length) { - // make a bigger array and copy over the elements - E[] bigger = (E[]) new Object[array.length * 2]; - System.arraycopy(array, 0, bigger, 0, array.length); - array = bigger; - } - array[size] = element; - size++; - return true; -} -``` - -如果数组中没有未使用的空间,我们必须创建一个更大的数组,并复制这些元素。然后我们可以将元素存储在数组中并递增`size`。 - -为什么这个方法返回一个布尔值,这可能不明显,因为它似乎总是返回`true`。像之前一样,你可以在文档中找到答案:。如何分析这个方法的性能也不明显。在正常情况下,它是常数时间的,但如果我们必须调整数组的大小,它是线性的。我将在 3.2 节中介绍如何处理这个问题。 - -最后,让我们来看看`get`;之后你可以开始做这个练习了。 - -```java -public T get(int index) { - if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(); - } - return array[index]; -} -``` - -其实`get`很简单:如果索引超出范围,它会抛出异常; 否则读取并返回数组的元素。注意,它检查索引是否小于`size`,大于等于`array.length`,所以它不能访问数组的未使用的元素。 - -在`MyArrayList.java`中,你会找到`set`的桩,像这样: - -```java -public T set(int index, T element) { - // TODO: fill in this method. - return null; -} -``` - -阅读`set`的文档,在 ,然后填充此方法的主体。如果再运行`MyArrayListTest`,`testSet`应该通过。 - -提示:尽量避免重复索引检查的代码。 - -你的下一个任务是填充`indexOf`。像往常一样,你应该阅读 上的文档,以便你知道应该做什么。特别要注意它应该如何处理`null`。 - -我提供了一个辅助方法`equals`,它将数组中的元素与目标值进行比较,如果它们相等,返回`true`(并且正确处理`null`),则 返回。请注意,此方法是私有的,因为它仅在此类中使用;它不是`List`接口的一部分。 - -完成后,`再次运行MyArrayListTest`;`testIndexOf`,以及依赖于它的其他测试现在应该通过。 - -只剩下两个方法了,你需要完成这个练习。下一个是`add`的重载版本,它接受下标并将新值存储在给定的下标处,如果需要,移动其他元素来腾出空间。 - -再次阅读 上的文档,编写一个实现,并运行测试进行确认。 - -提示:避免重复扩充数组的代码。 - -最后一个:填充`remove`的主体。文档位于 。当你完成它时,所有的测试都应该通过。 - -一旦你的实现能够工作,将其与我的比较,你可以在 上找到它。 diff --git a/docs/think-dast-zh/3.md b/docs/think-dast-zh/3.md deleted file mode 100644 index 7c0e07760..000000000 --- a/docs/think-dast-zh/3.md +++ /dev/null @@ -1,350 +0,0 @@ -# 第三章 `ArrayList` - -> 原文:[Chapter 3 ArrayList](http://greenteapress.com/thinkdast/html/thinkdast004.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -本章一举两得:我展示了上一个练习的解法,并展示了一种使用摊销分析来划分算法的方法。 - -## 3.1 划分`MyArrayList`的方法 - -对于许多方法,我们不能通过测试代码来确定增长级别。例如,这里是`MyArrayList`的`get`的实现: - -```java -public E get(int index) { - if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(); - } - return array[index]; -} -``` - -`get`中的每个东西都是常数时间的。所以`get`是常数时间,没问题。 - -现在我们已经划分了`get`,我们可以使用它来划分`set`。这是我们以前的练习中的`set`: - -```java -public E set(int index, E element) { - E old = get(index); - array[index] = element; - return old; -} -``` - -该解决方案的一个有些机智的部分是,它不会显式检查数组的边界;它利用`get`,如果索引无效则引发异常。 - -`set`中的一切,包括`get`的调用都是常数时间,所以`set`也是常数时间。 - -接下来我们来看一些线性的方法。例如,以下是我的实现`indexOf`: - -```java -public int indexOf(Object target) { - for (int i = 0; i size) { - throw new IndexOutOfBoundsException(); - } - // add the element to get the resizing - add(element); - - // shift the other elements - for (int i=size-1; i>index; i--) { - array[i] = array[i-1]; - } - // put the new one in the right place - array[index] = element; -} -``` - -这个双参数的版本,叫做`add(int, E)`,它使用了单参数的版本,称为`add(E)`,它将新的元素放在最后。然后它将其他元素向右移动,并将新元素放在正确的位置。 - -在我们可以划分双参数`add`之前,我们必须划分单参数`add`: - -```java -public boolean add(E element) { - if (size >= array.length) { - // make a bigger array and copy over the elements - E[] bigger = (E[]) new Object[array.length * 2]; - System.arraycopy(array, 0, bigger, 0, array.length); - array = bigger; - } - array[size] = element; - size++; - return true; -} -``` - -单参数版本很难分析。如果数组中存在未使用的空间,那么它是常数时间,但如果我们必须调整数组的大小,它是线性的,因为`System.arraycopy`所需的时间与数组的大小成正比。 - -那么`add`是常数还是线性时间的?我们可以通过考虑一系列`n`个添加中,每次添加的平均操作次数,来分类此方法。为了简单起见,假设我们以一个有`2`个元素的空间的数组开始。 - -+ 我们第一次调用`add`时,它会在数组中找到未使用的空间,所以它存储`1`个元素。 -+ 第二次,它在数组中找到未使用的空间,所以它存储`1`个元素。 -+ 第三次,我们必须调整数组的大小,复制`2`个元素,并存储`1`个元素。现在数组的大小是`4`。 -+ 第四次存储`1`个元素。 -+ 第五次调整数组的大小,复制`4`个元素,并存储`1`个元素。现在数组的大小是`8`。 -+ 接下来的`3`个添加储存`3`个元素。 -+ 下一个添加复制`8`个并存储`1`个。现在的大小是`16`。 -+ 接下来的`7`个添加复制了`7`个元素。 - -以此类推,总结一下: - -+ `4`次添加之后,我们储存了`4`个元素,并复制了两个。 -+ `8`次添加之后,我们储存了`8`个元素,并复制了`6`个。 -+ `16`次添加之后,我们储存了`16`个元素,并复制了`14`个。 - -现在你应该看到了规律:要执行`n`次添加,我们必须存储`n`个元素并复制`n-2`个。所以操作总数为`n + n - 2`,为`2 * n - 2`。 - -为了得到每个添加的平均操作次数,我们将总和除以`n`;结果是`2 - 2 / n`。随着`n`变大,第二项`2 / n`变小。参考我们只关心`n`的最大指数的原则,我们可以认为`add`是常数时间的。 - -有时线性的算法平均可能是常数时间,这似乎是奇怪的。关键是我们每次调整大小时都加倍了数组的长度。这限制了每个元素被复制的次数。否则 - 如果我们向数组的长度添加一个固定的数量,而不是乘以一个固定的数量 - 分析就不起作用。 - -这种划分算法的方式,通过计算一系列调用中的平均时间,称为摊销分析。你可以在 上阅读更多信息。重要的想法是,复制数组的额外成本是通过一系列调用展开或“摊销”的。 - -现在,如果`add(E)`是常数时间,那么`add(int, E)`呢?调用`add(E)`后,它遍历数组的一部分并移动元素。这个循环是线性的,除了在列表末尾添加的特殊情况中。因此, `add(int, E)`是线性的。 - -## 3.3 问题规模 - -最后一个例子中,我们将考虑`removeAll`,这里是`MyArrayList`中的实现: - -```java -public boolean removeAll(Collection collection) { - boolean flag = true; - for (Object obj: collection) { - flag &= remove(obj); - } - return flag; -} -``` - -每次循环中,`removeAll`都调用`remove`,这是线性的。所以认为`removeAll`是二次的很诱人。但事实并非如此。 - -在这种方法中,循环对于每个`collection`中的元素运行一次。如果`collection`包含`m`个元素,并且我们从包含`n`个元素的列表中删除,则此方法是`O(nm)`的。如果`collection`的大小可以认为是常数,`removeAll`相对于`n`是线性的。但是,如果集合的大小与`n`成正比,`removeAll`则是平方的。例如,如果`collection`总是包含`100`个或更少的元素, `removeAll`则是线性的。但是,如果`collection`通常包含的列表中的 1% 元素,`removeAll`则是平方的。 - -当我们谈论问题规模时,我们必须小心我们正在讨论哪个大小。这个例子演示了算法分析的陷阱:对循环计数的诱人捷径。如果有一个循环,算法往往是 线性的。如果有两个循环(一个嵌套在另一个内),则该算法通常是平方的。不过要小心!你必须考虑每个循环运行多少次。如果所有循环的迭代次数与`n`成正比,你可以仅仅对循环进行计数之后离开。但是,如在这个例子中,迭代次数并不总是与`n`成正比,所以你必须考虑更多。 - -## 3.4 链接数据结构 - -对于下一个练习,我提供了`List`接口的部分实现,使用链表来存储元素。如果你不熟悉链表,你可以阅读 ,但本部分会提供简要介绍。 - -如果数据结构由对象(通常称为“节点”)组成,其中包含其他节点的引用,则它是“链接”的。在链表 中,每个节点包含列表中下一个节点的引用。其他链接结构包括树和图,其中节点可以包含多个其他节点的引用。 - -这是一个简单节点的类定义: - -```java -public class ListNode { - - public Object data; - public ListNode next; - - public ListNode() { - this.data = null; - this.next = null; - } - - public ListNode(Object data) { - this.data = data; - this.next = null; - } - - public ListNode(Object data, ListNode next) { - this.data = data; - this.next = next; - } - - public String toString() { - return "ListNode(" + data.toString() + ")"; - } -} -``` - -该`ListNode`对象具有两个实例变量:`data`是某种类型的`Object`的引用,并且`next`是列表中下一个节点的引用。在列表中的最后一个节点中,按照惯例,`next`是`null`。 - -`ListNode`提供了几个构造函数,可以让你为`data`和`next`提供值,或将它们初始化为默认值,`null`。 - -你可以将每个`ListNode`看作具有单个元素的列表,但更通常,列表可以包含任意数量的节点。有几种方法可以制作新的列表。一个简单的选项是,创建一组`ListNode`对象,如下所示: - -```java -ListNode node1 = new ListNode(1); -ListNode node2 = new ListNode(2); -ListNode node3 = new ListNode(3); -``` - -之后将其链接到一起,像这样: - -``` -node1.next = node2; -node2.next = node3; -node3.next = null; -``` - -或者,你可以创建一个节点并将其链接在一起。例如,如果要在列表开头添加一个新节点,可以这样做: - -```java -ListNode node0 = new ListNode(0, node1); -``` - -![](img/3-1.jpg) - -图 3.1 链表的对象图 - -图 3.1 是一个对象图,展示了这些变量及其引用的对象。在对象图中,变量的名称出现在框内,箭头显示它们所引用的内容。对象及其类型(如ListNode和Integer)出现在框外面。 - -## 3.5 练习 3 - -这本书的仓库中,你会找到你需要用于这个练习的源代码: - -+ `MyLinkedList.java`包含`List`接口的部分实现,使用链表存储元素。 -+ `MyLinkedListTest.java`包含用于`MyLinkedList`的 JUnit 测试。 - -运行`ant MyArrayList`来运行`MyArrayList.java`,其中包含几个简单的测试。 - -然后可以运行`ant MyArrayListTest`来运行 JUnit 测试。其中几个应该失败。如果你检查源代码,你会发现三条 TODO 注释,表示你应该填充的方法。 - -在开始之前,让我们来看看一些代码。以下是`MyLinkedList`的实例变量和构造函数: - -```java -public class MyLinkedList implements List { - - private int size; // keeps track of the number of elements - private Node head; // reference to the first node - - public MyLinkedList() { - head = null; - size = 0; - } -} -``` - -如注释所示,`size`跟踪`MyLinkedList`有多少元素;`head`是列表中第一个`Node`的引用,或者如果列表为空则为`null`。 - -存储元素数量不是必需的,并且一般来说,保留冗余信息是有风险的,因为如果没有正确更新,就有机会产生错误。它还需要一点点额外的空间。 - -但是如果我们显式存储`size`,我们可以实现常数时间的`size`方法;否则,我们必须遍历列表并对元素进行计数,这需要线性时间。 - -因为我们显式存储`size`明确地存储,每次添加或删除一个元素时,我们都要更新它,这样一来,这些方法就会减慢,但是它不会改变它们的增长级别,所以很值得。 - -构造函数将`head`设为null,表示空列表,并将`size`设为`0`。 - -这个类使用类型参数`E`作为元素的类型。如果你不熟悉类型参数,可能需要阅读本教程:。 - -类型参数也出现在`Node`的定义中,嵌套在`MyLinkedList`里面: - -```java -private class Node { - public E data; - public Node next; - - public Node(E data, Node next) { - this.data = data; - this.next = next; - } -} -``` - -除了这个,`Node`类似于上面的`ListNode`。 - -最后,这是我的`add`的实现: - -```java -public boolean add(E element) { - if (head == null) { - head = new Node(element); - } else { - Node node = head; - // loop until the last node - for ( ; node.next != null; node = node.next) {} - node.next = new Node(element); - } - size++; - return true; -} -``` - -此示例演示了你需要的两种解决方案: - -对于许多方法,作为特殊情况,我们必须处理列表的第一个元素。在这个例子中,如果我们向列表添加列表第一个元素,我们必须修改`head`。否则,我们遍历列表,找到末尾,并添加新节点。 -此方法展示了,如何使用`for`循环遍历列表中的节点。在你的解决方案中,你可能会在此循环中写出几个变体。注意,我们必须在循环之前声明`node`,以便我们可以在循环之后访问它。 - -现在轮到你了。填充`indexOf`的主体。像往常一样,你应该阅读文档,位于 ,所以你知道应该做什么。特别要注意它应该如何处理`null`。 - -与上一个练习一样,我提供了一个辅助方法`equals`,它将数组中的一个元素与目标值进行比较,并检查它们是否相等,并正确处理`null`。这个方法是私有的,因为它在这个类中使用,但它不是`List`接口的一部分。 - -完成后,再次运行测试;`testIndexOf`,以及依赖于它的其他测试现在应该通过。 - -接下来,你应该填充双参数版本的add,它使用索引并将新值存储在给定索引处。再次阅读 上的文档,编写一个实现,并运行测试进行确认。 - -最后一个:填写`remove`的主体。文档在这里:。当你完成它时,所有的测试都应该通过。 - -一旦你的实现能够工作,将它与仓库`solution`目录中的版本比较。 - -## 3.6 垃圾回收的注解 - -在`MyArrayList`以前的练习中,如果需要,数字会增长,但它不会缩小。该数组从不收集垃圾,并且在列表本身被销毁之前,元素不会收集垃圾。 - -链表实现的一个优点是,当元素被删除时它会缩小,并且未使用的节点可以立即被垃圾回收。 - -这是我的实现的`clear`方法: - -```java -public void clear() { - head = null; - size = 0; -} -``` - -当我们将`head`设为`null`时,我们删除第一个`Node`的引用。如果没有其他`Node`的引用(不应该有),它将被垃圾收集。这个时候,第二个`Node`引用被删除,所以它也被垃圾收集。此过程一直持续到所有节点都被收集。 - -那么我们应该如何划分`clear`?该方法本身包含两个常数时间的操作,所以它看起来像是常数时间。但是当你调用它时,你将使垃圾收集器做一些工作,它与元素数成正比。所以也许我们应该将其认为是线性的! - -这是一个有时被称为性能 bug 的例子:一个程序做了正确的事情,在这种意义上它是正确的,但它不属于我们预期的增长级别。在像 Java 这样的语言中,它在背后做了大量工作的,例如垃圾收集,这种 bug 可能很难找到。 diff --git a/docs/think-dast-zh/4.md b/docs/think-dast-zh/4.md deleted file mode 100644 index e0fd38183..000000000 --- a/docs/think-dast-zh/4.md +++ /dev/null @@ -1,280 +0,0 @@ -# 第四章 `LinkedList` - -> 原文:[Chapter 4 LinkedList](http://greenteapress.com/thinkdast/html/thinkdast005.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -这一章展示了上一个练习的解法,并继续讨论算法分析。 - -## 4.1 `MyLinkedList`方法的划分 - -我的`indexOf`实现在下面。在阅读说明之前,请阅读它,看看你是否可以确定其增长级别。 - -```java -public int indexOf(Object target) { - Node node = head; - for (int i=0; i= size) { - throw new IndexOutOfBoundsException(); - } - Node node = head; - for (int i=0; i list; - - public void setup(int n) { - list = new ArrayList(); - } - - public void timeMe(int n) { - for (int i=0; i。 - -但是下一次练习不需要太多的知识;即使你不喜欢匿名类,也可以复制和修改示例代码。 - -下一步是创建`Profiler`对象,传递`Timeable`对象和标题作为参数。 - -`Profiler`提供了`timingLoop`,它使用存储为实例变量的`Timeable`。它多次调用`Timeable`对象上的`timeMe`方法,使用一系列的`n`值。`timingLoop`接受两个参数: - -+ `startN`是`n`的值,计时循环应该从它开始。 -+ `endMillis`是以毫秒为单位的阈值。随着 `timingLoop`增加问题规模,运行时间增加;当运行时间超过此阈值时,`timingLoop`停止。 - -当你运行实验时,你可能需要调整这些参数。如果`startN`太低,运行时间可能太短,无法准确测量。如果`endMillis`太低,你可能无法获得足够的数据,来查看问题规模和运行时间之间的明确关系。 - -这段代码位于`ProfileListAdd.java`,你将在下一个练习中运行它。当我运行它时,我得到这个输出: - -``` -4000, 3 -8000, 0 -16000, 1 -32000, 2 -64000, 3 -128000, 6 -256000, 18 -512000, 30 -1024000, 88 -2048000, 185 -4096000, 242 -8192000, 544 -16384000, 1325 -``` - -第一列是问题规模,`n`;第二列是以毫秒为单位的运行时间。前几个测量非常嘈杂;最好将`startN`设置在`64000`左右。 - -`timingLoop`的结果是包含此数据的`XYSeries`。如果你将这个序列传给`plotResults`,它会产生一个如图 4.1 所示的图形。 - -![](img/4-1.jpg) - -图 4.1 分析结果:将`n`个元素添加到`ArrayList`末尾的运行时间与问题规模。 - -下一节解释了如何解释它。 - -## 4.4 解释结果 - -基于我们对`ArrayList`工作方式的理解,我们期望,在添加元素到最后时,`add`方法需要常数时间。所以添加`n`个元素的总时间应该是线性的。 - -为了测试这个理论,我们可以绘制总运行时间和问题规模,我们应该看到一条直线,至少对于大到足以准确测量的问题规模。在数学上,我们可以为这条直线编写一个函数: - -``` -runtime = a + b * n -``` - -其中`a`是线的截距,`b`是斜率。 - -另一方面,如果`add`是线性的,则`n`次添加的总时间将是平方。如果我们绘制运行时间与问题规模,我们预计会看到抛物线。或者在数学上,像: - -``` -runtime = a + b * n + c * n ** 2 -``` - -有了完美的数据,我们可能能够分辨直线和抛物线之间的区别,但如果测量结果很嘈杂,可能很难辨别。解释嘈杂的测量值的更好方法是,在重对数刻度上绘制的运行时间和问题规模。 - -为什么?我们假设运行时间与`n ** k`成正比,但是我们不知道指数`k`是什么。我们可以将关系写成这样: - -``` -runtime = a + b * n + … + c * n ** k -``` - -对于`n`的较大值,最大指数项是最重要的,因此: - -``` -runtime ≈ c * n ** k -``` - -其中`≈`意思是“大致相等”。现在,如果我们对这个方程的两边取对数: - -``` -log(runtime) ≈ log(c) + k * log(n) -``` - -这个方程式意味着,如果我们在重对数合度上绘制运行时间与`n`,我们预计看到一条直线,截距为`log(c)`,斜率为`k`。我们不太在意截距,但斜率表示增长级别:如果`k = 1`,算法是线性的;如果`k = 2`,则为平方的。 - -看上一节中的数字,你可以通过眼睛来估计斜率。但是当你调用`plotResults`它时,会计算数据的最小二乘拟合并打印估计的斜率。在这个例子中: - -``` -Estimated slope = 1.06194352346708 -``` - -它接近`1`;并且这表明`n`次添加的总时间是线性的,所以每个添加是常数时间,像预期的那样。 - -其中重要的一点:如果你在图形看到这样的直线,这并不意味着该算法是线性的。如果对于任何指数`k`,运行时间与`n ** k`成正比,我们预计看到斜率为`k`的直线。如果斜率接近`1`,则表明算法是线性的。如果接近`2`,它可能是平方的。 - -## 4.5 练习 4 - -在本书的仓库中,你将找到此练习所需的源文件: - -+ `Profiler.java`包含上述`Profiler`类的实现。你会使用这个类,但你不必知道它如何工作。但可以随时阅读源码。 -+ `ProfileListAdd.java`包含此练习的起始代码,包括上面的示例,它测量了`ArrayList.add`。你将修改此文件来测量其他一些方法。 - -此外,在`code`目录中,你将找到 Ant 构建文件`build.xml`。 - -运行`ant ProfileListAdd`来运行`ProfileListAdd.java`。你应该得到类似图 4.1 的结果,但是你可能需要调整`startN`或`endMillis`。估计的斜率应该接近`1`,表明执行`n`个添加操作的所需时间与`n`成正比;也就是说,它是`O(n)`的。 - -在`ProfileListAdd.java`中,你会发现一个空的方法`profileArrayListAddBeginning`。用测试`ArrayList.add`的代码填充这个方法的主体,总是把新元素放在开头。如果你以`profileArrayListAddEnd`的副本开始,你只需要进行一些更改。在`main`中添加一行来调用这个方法。 - -再次运行`ant ProfileListAdd`并解释结果。基于我们对`ArrayList`工作方式的理解,我们期望,每个添加操作是线性的,所以`n`次添加的总时间应该是平方的。如果是这样,在重对数刻度中,直线的估计斜率应该接近`2`。是吗? - -现在我们来将其与`LinkedList`比较。当我们把新元素放在开头,填充`profileLinkedListAddBeginning`并使用它划分`LinkedList.add`。你期望什么性能?结果是否符合你的期望? - -最后,填充`profileLinkedListAddEnd`的主体,使用它来划分`LinkedList.add`。你期望什么性能?结果是否符合你的期望? - -我将在下一章中展示结果并回答这些问题。 diff --git a/docs/think-dast-zh/5.md b/docs/think-dast-zh/5.md deleted file mode 100644 index 045241f80..000000000 --- a/docs/think-dast-zh/5.md +++ /dev/null @@ -1,215 +0,0 @@ -# 第五章 双链表 - -> 原文:[Chapter 5 Doubly-linked list](http://greenteapress.com/thinkdast/html/thinkdast006.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -本章回顾了上一个练习的结果,并介绍了`List`接口的另一个实现,即双链表。 - -## 5.1 性能分析结果 - -在之前的练习中,我们使用了`Profiler.java`,运行`ArrayList`和`LinkedList`的各种操作,它们具有一系列的问题规模。我们将运行时间与问题规模绘制在重对数比例尺上,并估计所得曲线的斜率,它表示运行时间和问题规模之间的关系的主要指数。 - -例如,当我们使用`add`方法将元素添加到`ArrayList`的末尾,我们发现,执行`n`次添加的总时间正比于`n`。也就是说,估计的斜率接近`1`。我们得出结论,执行`n`次添加是 `O(n)`的,所以平均来说,单个添加的时间是常数时间,或者`O(1)`,基于算法分析,这是我们的预期。 - - -这个练习要求你填充`profileArrayListAddBeginning`的主体,它测试了,在`ArrayList`头部添加一个新的元素的性能。根据我们的分析,我们预计每个添加都是线性的,因为它必须将其他元素向右移动;所以我们预计,`n`次添加是平方复杂度。 - - -这是一个解决方案,你可以在仓库的`solution`目录中找到它。 - -```java -public static void profileArrayListAddBeginning() { - Timeable timeable = new Timeable() { - List list; - - public void setup(int n) { - list = new ArrayList(); - } - - public void timeMe(int n) { - for (int i=0; i list; - - public void setup(int n) { - list = new LinkedList(); - } - - public void timeMe(int n) { - for (int i=0; i list; - - public void setup(int n) { - list = new LinkedList(); - } - - public void timeMe(int n) { - for (int i=0; i,它说: - -> `List`和`Deque`接口的双链表实现。[...] 所有的操作都能像双向列表那样执行。索引该列表中的操作将从头或者尾遍历列表,使用更接近指定索引的那个。 - -如果你不熟悉双链表,你可以在 上阅读更多相关信息,但简称为: - -+ 每个节点包含下一个节点的链接和上一个节点的链接。 -+ `LinkedList`对象包含指向列表的第一个和最后一个元素的链接。 - -所以我们可以从列表的任意一端开始,并以任意方向遍历它。因此,我们可以在常数时间内,在列表的头部和末尾添加和删除元素! - -下表总结了`ArrayList`,`MyLinkedList`(单链表)和`LinkedList`(双链表)的预期性能: - - -| | `MyArrayList` | `MyLinkedList` | `LinkedList` | -| --- | --- | --- | --- | -| `add`(尾部) | 1 | n | 1 | -| `add`(头部) | n | 1 | 1 | -| `add`(一般) | n | n | n | -| `get`/`set` | 1 | n | n | -| `indexOf`/ `lastIndexOf` | n | n | n | -| `isEmpty`/`size` | 1 | 1 | 1 | -| `remove`(尾部) | 1 | n | 1 | -| `remove`(头部) | n | 1 | 1 | -| `remove`(一般) | n | n | n | - -## 5.5 结构的选择 - -对于头部插入和删除,双链表的实现优于`ArrayList`。对于尾部插入和删除,都是一样好。所以,`ArrayList`唯一优势是`get`和`set`,链表中它需要线性时间,即使是双链表。 - -如果你知道,你的应用程序的运行时间取决于`get`和`set`元素的所需时间,则`ArrayList`可能是更好的选择。如果运行时间取决于在开头或者末尾附加添加和删除元素,`LinkedList`可能会更好。 - - -但请记住,这些建议是基于大型问题的增长级别。还有其他因素要考虑: - -+ 如果这些操作不占用你应用的大部分运行时间 - 也就是说,如果你的应用程序花费大部分时间来执行其他操作 - 那么你对`List`实现的选择并不重要。 -+ 如果你正在处理的列表不是很大,你可能无法获得期望的性能。对于小型问题,二次算法可能比线性算法更快,或者线性可能比常数时间更快。而对于小型问题,差异可能并不重要。 -+ 另外,别忘了空间。到目前为止,我们专注于运行时间,但不同的实现需要不同的空间。在`ArrayList`中,这些元素并排存储在单个内存块中,所以浪费的空间很少,并且计算机硬件通常在连续的块上更快。在链表中,每个元素需要一个节点,带有一个或两个链接。链接占用空间(有时甚至超过数据!),并且节点分散在内存中,硬件效率可能不高。 - -总而言之,算法分析为数据结构的选择提供了一些指南,但只有: - -+ 你的应用的运行时间很重要, -+ 你的应用的运行时间取决于你选择的数据结构,以及, -+ 问题的规模足够大,增长级别实际上预测了哪个数据结构更好。 - -作为一名软件工程师,在较长的职业生涯中,你几乎不必考虑这种情况。 diff --git a/docs/think-dast-zh/6.md b/docs/think-dast-zh/6.md deleted file mode 100644 index 3d76615e6..000000000 --- a/docs/think-dast-zh/6.md +++ /dev/null @@ -1,233 +0,0 @@ -# 第六章 树的遍历 - -> 原文:[Chapter 6 Tree traversal](http://greenteapress.com/thinkdast/html/thinkdast007.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -本章将介绍一个 Web 搜索引擎,我们将在本书其余部分开发它。我描述了搜索引擎的元素,并介绍了第一个应用程序,一个从维基百科下载和解析页面的 Web 爬行器。本章还介绍了深度优先搜索的递归实现,以及迭代实现,它使用 Java`Deque`实现“后入先出”的栈。 - -## 6.1 搜索引擎 - -网络搜索引擎,像谷歌搜索或 Bing,接受一组“检索项”,并返回一个网页列表,它们和这些项相关(之后我将讨论“相关”是什么意思)。你可以在 上阅读更多内容,但是我会解释你需要什么。 - -搜索引擎的基本组成部分是: - -抓取:我们需要一个程序,可以下载网页,解析它,并提取文本和任何其他页面的链接。 -索引:我们需要一个数据结构,可以查找一个检索项,并找到包含它的页面。 -检索:我们需要一种方法,从索引中收集结果,并识别与检索项最相关的页面。 - -我们以爬虫开始。爬虫的目标是查找和下载一组网页。对于像 Google 和 Bing 这样的搜索引擎,目标是查找所有网页,但爬虫通常仅限于较小的域。在我们的例子中,我们只会读取维基百科的页面。 - -作为第一步,我们将构建一个读取维基百科页面的爬虫,找到第一个链接,并跟着链接来到另一个页面,然后重复。我们将使用这个爬虫来测试“到达哲学”的猜想,它是: - -> 点击维基百科文章正文中的第一个小写的链接,然后对后续文章重复这个过程,通常最终会到达“哲学”的文章。 - -这个猜想在 中阐述,你可以阅读其历史。 - -测试这个猜想需要我们构建爬虫的基本部分,而不必爬取整个网络,甚至是所有维基百科。而且我觉得这个练习很有趣! - -在几个章节之内,我们将处理索引器,然后我们将到达检索器。 - -## 6.2 解析 HTML - -当你下载网页时,内容使用超文本标记语言(即 HTML)编写。例如,这里是一个最小的 HTML 文档: - -```html - - - - This is a title - - -

Hello world!

- - -``` - -短语`This is a title`和`Hello world!`是实际出现在页面上的文字;其他元素是指示文本应如何显示的标签。 - -当我们的爬虫下载页面时,它需要解析 HTML,以便提取文本并找到链接。为此,我们将使用`jsoup`,它是一个下载和解析 HTML 的开源 Java 库。 - -解析 HTML 的结果是文档对象模型(DOM)树,其中包含文档的元素,包括文本和标签。树是由节点组成的链接数据结构;节点表示文本,标签和其他文档元素。 - -节点之间的关系由文档的结构决定。在上面的例子中,第一个节点称为根,是``标签,它包含指向所包含两个节点的链接, ``和``;这些节点是根节点的子节点。 - -``节点有一个子节点,``,`<body>`节点有一个子节点, `<p>`(代表“段落”)。图 6.1 以图形方式表示该树。 - -![](img/6-1.jpg) - -图 6.1 简单 HTML 页面的 DOM 树 - -每个节点包含其子节点的链接; 此外,每个节点都包含其父节点的链接,所以任何节点都可以向上或向下浏览树。实际页面的 DOM 树通常比这个例子更复杂。 - -大多数网络浏览器提供了工具,用于检查你正在查看的页面的 DOM。在 Chrome 中,你可以右键单击网页的任何部分,然后从弹出的菜单中选择`Inspect`(检查)。在 Firefox 中,你可以右键单击并从菜单中选择`Inspect Element`(检查元素)。Safari 提供了一个名为 Web Inspector 的工具,你可以阅读 <http://thinkdast.com/safari>。对于 Internet Explorer,你可以阅读 <http://thinkdast.com/explorer> 上的说明 。 - -![](img/6-2.jpg) - -图 6.2:Chrome DOM 查看器的截图 - -图 6.2 展示了维基百科 Java 页面(<http://thinkdast.com/java>)的 DOM 截图。高亮的元素是文章正文的第一段,它包含在一个`<div>`元素中 ,带有`id="mw-content-text"`。我们将使用这个元素 ID 来标识我们下载的每篇文章的正文。 - -## 6.3 使用`jsoup` - -`jsoup`非常易于下载,和解析 Web 页面,以及访问 DOM 树。这里是一个例子: - -```java -String url = "http://en.wikipedia.org/wiki/Java_(programming_language)"; - -// download and parse the document -Connection conn = Jsoup.connect(url); -Document doc = conn.get(); - -// select the content text and pull out the paragraphs. -Element content = doc.getElementById("mw-content-text"); -Elements paragraphs = content.select("p"); -``` - -`Jsoup.connect`接受`String`形式的`url`,并连接 Web 服务器。`get`方法下载 HTML,解析,并返回`Document`对象,他表示 DOM。 - -`Document`提供了导航树和选择节点的方法。其实它提供了很多方法,可能会把人搞晕。此示例演示了两种选择节点的方式: - -+ `getElementById`接受`String`并在树中搜索匹配`id`字段的元素。在这里,它选择节点`<div id="mw-content-text" lang="en" dir="ltr" class="mw-content-ltr">`,它出现在每个维基页面上,来确定包含文章正文的`<div>`元素,而不是导航边栏和其他元素。`getElementById`的返回值是一个`Element`对象,代表这个`<div>`,并包含`<div>`中的元素作为后继节点。 -+ `select`接受`String`,遍历树,并返回与所有元素,它的标签与`String`匹配。在这个例子中,它返回所有`content`中的段落标签。返回值是一个`Elements`对象。 - -> 译者注:`select`方法接受 CSS 选择器,不仅仅能按照标签选择。请见 <https://jsoup.org/apidocs/org/jsoup/select/Selector.html>。 - -在你继续之前,你应该仔细阅读这些类的文档,以便知道他们能做什么。最重要的类是`Element`,`Elements`和`Node`,你可以阅读 <http://thinkdast.com/jsoupelt>,<http://thinkdast.com/jsoupelts> 和 <http://thinkdast.com/jsoupnode>。 - -`Node`表示 DOM 树中的一个节点;有几个扩展`Node`的子类,其中包括 `Element`,`TextNode`,`DataNode`,和`Comment`。`Elements`是`Element`对象的`Collection`。 - -![](img/6-3.jpg) - -图 6.3:被选类的 UML 图,由`jsoup`提供。编辑:<ttp://yuml.me/edit/4bc1c919> - -图 6.3 是一个 UML 图,展示了这些类之间的关系。在 UML 类图中,带有空心箭头的线表示一个类继承另一个类。例如,该图表示`Elements`继承`ArrayList`。我们将在第 11.6 节中再次接触 UML 图。 - -## 6.4 遍历 DOM - -为了使你变得更轻松,我提供了一个`WikiNodeIterable`类,可以让你遍历 DOM 树中的节点。以下是一个示例,展示如何使用它: - -```java -Elements paragraphs = content.select("p"); -Element firstPara = paragraphs.get(0); - -Iterable<Node> iter = new WikiNodeIterable(firstPara); -for (Node node: iter) { - if (node instanceof TextNode) { - System.out.print(node); - } -} -``` - -这个例子紧接着上一个例子。它选择`paragraphs`中的第一个段落,然后创建一个`WikiNodeIterable`,它实现`Iterable<Node>`。`WikiNodeIterable`执行“深度优先搜索”,它按照它们将出现在页面上的顺序产生节点。 - -在这个例子中,仅当`Node`是`TextNode`时,我们打印它,并忽略其他类型的`Node`,特别是代表标签的`Element`对象。结果是没有任何标记的 HTML 段落的纯文本。输出为: - -``` -Java is a general-purpose computer programming language that is concurrent, class-based, object-oriented,[13] and specifically designed … -``` - -> Java 是一种通用的计算机编程语言,它是并发的,基于类的,面向对象的,[13] 和特地设计的... - -## 6.5 深度优先搜索 - -有几种方式可以合理地遍历一个树,每个都有不同的应用。我们从“深度优先搜索”(DFS)开始。DFS 从树的根节点开始,并选择第一个子节点。如果子节点有子节点,则再次选择第一个子节点。当它到达没有子节点的节点时,它回溯,沿树向上移动到父节点,在那里它选择下一个子节点,如果有的话;否则它会再次回溯。当它探索了根节点的最后一个子节点,就完成了。 - -有两种常用的方式来实现 DFS,递归和迭代。递归实现简单优雅: - -```java -private static void recursiveDFS(Node node) { - if (node instanceof TextNode) { - System.out.print(node); - } - for (Node child: node.childNodes()) { - recursiveDFS(child); - } -} -``` - -这个方法对树中的每一个`Node`调用,从根节点开始。如果`Node`是一个`TextNode`,它打印其内容。如果`Node`有任何子节点,它会按顺序在每一个子节点上调用`recursiveDFS`。 - -在这个例子中,我们在遍历子节点之前打印每个`TextNode`的内容,所以这是一个“前序”遍历的例子。你可以在 <http://thinkdast.com/treetrav> 上了解“前序”,“后序”和“中序”遍历。对于此应用程序,遍历顺序并不重要。 - -通过进行递归调用,`recursiveDFS`使用调用栈(<http://thinkdast.com/callstack>)来跟踪子节点并以正确的顺序处理它们。作为替代,我们可以使用栈数据结构自己跟踪节点;如果我们这样做,我们可以避免递归并迭代遍历树。 - -## 6.6 Java 中的栈 - -在我解释 DFS 的迭代版本之前,我将解释栈数据结构。我们将从栈的一般概念开始,我将使用小写`s`指代“栈”。然后我们将讨论两个 Java`interfaces`,它们定义了栈的方法:`Stack`和`Deque`。 - -栈是与列表类似的数据结构:它是维护元素顺序的集合。栈和列表之间的主要区别是栈提供的方法较少。在通常的惯例中,它提供: - -`push`:它将一个元素添加到栈顶。 -`pop`:它从栈中删除并返回最顶部的元素。 -`peek`:它返回最顶部的元素而不修改栈。 -`isEmpty`:表示栈是否为空。 -因为`pop`总是返回最顶部的元素,栈也称为 LIFO,代表“后入先出”。栈的替代品是“队列”,它返回的元素顺序和添加顺序相同;即“先入先出(FIFO)。 - -为什么栈和队列是有用的,可能不是很明显:它们不提供任何列表没有的功能;实际上它们提供的功能更少。那么为什么不使用列表的一切?有两个原因: - -+ 如果你将自己限制于一小部分方法 - 也就是小型 API - 你的代码将更加易读,更不容易出错。例如,如果使用列表来表示栈,则可能会以错误的顺序删除元素。使用栈 API,这种错误在字面上是不可能的。避免错误的最佳方法是使它们不可能。 -+ 如果一个数据结构提供了小型 API,那么它更容易实现。例如,实现栈的简单方法是单链表。当我们压入一个元素时,我们将它添加到列表的开头;当我们弹出一个元素时,我们在开头删除它。对于链表,在开头添加和删除是常数时间的操作,因此这个实现是高效的。相反,大型 API 更难实现高效。 - -为了在 Java 中实现栈,你有三个选项: - -+ 继续使用`ArrayList`或`LinkedList`。如果使用`ArrayList`,请务必从最后添加和删​​除,这是一个常数时间的操作。并且小心不要在错误的地方添加元素,或以错误的顺序删除它们。 -+ Java 提供了一个`Stack`类,它提供了一组标准的栈方法。但是这个类是 Java 的一个旧部分:它与 Java 集合框架不兼容,后者之后才出现。 -+ 最好的选择可能是使用`Deque`接口的一个实现,如`ArrayDeque`。 - -`Deque`代表“双向队列”;它应该被发音为“deck”,但有些人叫它“deek”。在 Java 中, `Deque`接口提供`push`,`pop`,`peek`和`isEmpty`,因此你可以将`Deque`用作栈。它提供了其他方法,你可以阅读 <http://thinkdast.com/deque>,但现在我们不会使用它们。 - -## 6.7 迭代式 DFS - -这里是 DFS 的迭代版本,它使用`ArrayDeque`来表示`Node`对象的栈。 - -```java -private static void iterativeDFS(Node root) { - Deque<Node> stack = new ArrayDeque<Node>(); - stack.push(root); - - while (!stack.isEmpty()) { - Node node = stack.pop(); - if (node instanceof TextNode) { - System.out.print(node); - } - - List<Node> nodes = new ArrayList<Node>(node.childNodes()); - Collections.reverse(nodes); - - for (Node child: nodes) { - stack.push(child); - } - } -} -``` - -参数`root`是我们想要遍历的树的根节点,所以我们首先创建栈并将根节点压入它。 - -循环持续到栈为空。每次迭代,它会从栈中弹出`Node`。如果它得到`TextNode`,它打印内容。然后它把子节点们压栈。为了以正确的顺序处理子节点,我们必须以相反的顺序将它们压栈; 我们通过将子节点复制成一个`ArrayList`,原地反转元素,然后遍历反转的`ArrayList`。 - -DFS 的迭代版本的一个优点是,更容易实现为 Java`Iterator`;你会在下一章看到如何实现。 - -但是首先,有一个`Deque`接口的最后的注意事项:除了`ArrayDeque`,Java 提供另一个`Deque`的实现,我们的老朋友`LinkedList`。`LinkedList`实现两个接口,`List`和`Deque`(还有`Queue`)。你得到哪个接口,取决于你如何使用它。例如,如果将`LinkedList`对象赋给`Deque`变量,如下所示: - -```java -Deqeue<Node> deque = new LinkedList<Node>(); -``` - -你可以使用`Deque`接口中的方法,但不是所有`List`中的方法。如果你将其赋给`List`变量,像这样: - -```java -List<Node> deque = new LinkedList<Node>(); -``` - -你可以使用`List`接口中的方法,但不是所有`Deque`中的方法。并且如果像这样赋值: - -```java -LinkedList<Node> deque = new LinkedList<Node>(); -``` - -你可以使用所有方法,但是混合了来自不同接口的方法。你的代码会更不可读,并且更易于出错。 diff --git a/docs/think-dast-zh/7.md b/docs/think-dast-zh/7.md deleted file mode 100644 index ab74bb966..000000000 --- a/docs/think-dast-zh/7.md +++ /dev/null @@ -1,208 +0,0 @@ -# 第七章 到达哲学 - -> 原文:[Chapter 7 Getting to Philosophy](http://greenteapress.com/thinkdast/html/thinkdast008.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -本章的目标是开发一个 Web 爬虫,它测试了第 6.1 节中提到的“到达哲学”猜想。 - -## 7.1 起步 - -在本书的仓库中,你将找到一些帮助你起步的代码: - -+ `WikiNodeExample.java`包含前一章的代码,展示了 DOM 树中深度优先搜索(DFS)的递归和迭代实现。 -+ `WikiNodeIterable.java`包含`Iterable`类,用于遍历 DOM 树。我将在下一节中解释这段代码。 -+ `WikiFetcher.java`包含一个工具类,使用`jsoup`从维基百科下载页面。为了帮助你遵守维基百科的服务条款,此类限制了你下载页面的速度;如果你每秒请求许多页,在下载下一页之前会休眠一段时间。 -+ `WikiPhilosophy.java`包含你为此练习编写的代码的大纲。我们将在下面进行说明。 - -你还会发现 Ant 构建文件`build.xml`。如果你运行`ant WikiPhilosophy`,它将运行一些简单的启动代码。 - -## 7.2 可迭代对象和迭代器 - -在前一章中,我展示了迭代式深度优先搜索(DFS),并且认为与递归版本相比,迭代版本的优点在于,它更容易包装在`Iterator`对象中。在本节中,我们将看到如何实现它。 - -如果你不熟悉`Iterator`和`Iterable`接口,你可以阅读 <http://thinkdast.com/iterator> 和 <http://thinkdast.com/iterable>。 - -看看`WikiNodeIterable.java`的内容。外层的类`WikiNodeIterable`实现`Iterable<Node>`接口,所以我们可以在一个`for`循环中使用它: - -```java -Node root = ... -Iterable<Node> iter = new WikiNodeIterable(root); -for (Node node: iter) { - visit(node); -} -``` - -其中`root`是我们想要遍历的树的根节点,并且`visit`是一个方法,当我们“访问”`Node`时,做任何我们想要的事情。 - -`WikiNodeIterable`的实现遵循以下惯例: - -+ 构造函数接受并存储根`Node`的引用。 -+ `iterator`方法创建一个返回一个`Iterator`对象。 - -这是它的样子: - -```java -public class WikiNodeIterable implements Iterable<Node> { - - private Node root; - - public WikiNodeIterable(Node root) { - this.root = root; - } - - @Override - public Iterator<Node> iterator() { - return new WikiNodeIterator(root); - } -} -``` - -内层的类`WikiNodeIterator`,执行所有实际工作。 - -```java -private class WikiNodeIterator implements Iterator<Node> { - - Deque<Node> stack; - - public WikiNodeIterator(Node node) { - stack = new ArrayDeque<Node>(); - stack.push(root); - } - - @Override - public boolean hasNext() { - return !stack.isEmpty(); - } - - @Override - public Node next() { - if (stack.isEmpty()) { - throw new NoSuchElementException(); - } - - Node node = stack.pop(); - List<Node> nodes = new ArrayList<Node>(node.childNodes()); - Collections.reverse(nodes); - for (Node child: nodes) { - stack.push(child); - } - return node; - } -} -``` - -该代码与 DFS 的迭代版本几乎相同,但现在分为三个方法: - -+ 构造函数初始化栈(使用一个`ArrayDeque`实现)并将根节点压入这个栈。 -+ `isEmpty`检查栈是否为空。 -+ `next`从`Node`栈中弹出下一个节点,按相反的顺序压入子节点,并返回弹出的`Node`。如果有人在空`Iterator`上调用`next`,则会抛出异常。 - -可能不明显的是,值得使用两个类和五个方法,来重写一个完美的方法。但是现在我们已经完成了,在需要`Iterable`的任何地方,我们可以使用`WikiNodeIterable`,这使得它的语法整洁,易于将迭代逻辑(DFS)与我们对节点的处理分开。 - -## 7.3 `WikiFetcher` - -编写 Web 爬虫时,很容易下载太多页面,这可能会违反你要下载的服务器的服务条款。为了帮助你避免这种情况,我提供了一个`WikiFetcher`类,它可以做两件事情: - -+ 它封装了我们在上一章中介绍的代码,用于从维基百科下载页面,解析 HTML 以及选择内容文本。 -+ 它测量请求之间的时间,如果我们在请求之间没有足够的时间,它将休眠直到经过了合理的间隔。默认情况下,间隔为`1`秒。 - -这里是`WikiFetcher`的定义: - -```java -public class WikiFetcher { - private long lastRequestTime = -1; - private long minInterval = 1000; - - /** - * Fetches and parses a URL string, - * returning a list of paragraph elements. - * - * @param url - * @return - * @throws IOException - */ - public Elements fetchWikipedia(String url) throws IOException { - sleepIfNeeded(); - - Connection conn = Jsoup.connect(url); - Document doc = conn.get(); - Element content = doc.getElementById("mw-content-text"); - Elements paragraphs = content.select("p"); - return paragraphs; - } - - private void sleepIfNeeded() { - if (lastRequestTime != -1) { - long currentTime = System.currentTimeMillis(); - long nextRequestTime = lastRequestTime + minInterval; - if (currentTime < nextRequestTime) { - try { - Thread.sleep(nextRequestTime - currentTime); - } catch (InterruptedException e) { - System.err.println( - "Warning: sleep interrupted in fetchWikipedia."); - } - } - } - lastRequestTime = System.currentTimeMillis(); - } -} -``` - -唯一的公共方法是`fetchWikipedia`,接收`String`形式的 URL,并返回一个`Elements`集合,该集合包含的一个 DOM 元素表示内容文本中每个段落。这段代码应该很熟悉了。 - -新的代码是`sleepIfNeeded`,它检查自上次请求以来的时间,如果经过的时间小于`minInterval`(毫秒),则休眠。 - -这就是`WikiFetcher`全部。这是一个演示如何使用它的例子: - -```java -WikiFetcher wf = new WikiFetcher(); - -for (String url: urlList) { - Elements paragraphs = wf.fetchWikipedia(url); - processParagraphs(paragraphs); -} -``` - -在这个例子中,我们假设`urlList`是一个`String`的集合 ,并且`processParagraphs`是一个方法,对`Elements`做一些事情,它由`fetchWikipedia`返回。 - -此示例展示了一些重要的东西:你应该创建一个`WikiFetcher`对象并使用它来处理所有请求。如果有多个`WikiFetcher`的实例,则它们不会确保请求之间的最小间隔。 - -注意:我的`WikiFetcher`实现很简单,但是通过创建多个实例,人们很容易误用它。你可以通过制作`WikiFetcher`“单例” 来避免这个问题,你可以阅读 <http://thinkdast.com/singleton>。 - -## 7.4 练习 5 - -在`WikiPhilosophy.java`中,你会发现一个简单的`main`方法,展示了如何使用这些部分。从这个代码开始,你的工作是写一个爬虫: - -1. 获取维基百科页面的 URL,下载并分析。 -1. 它应该遍历所得到的 DOM 树来找到第一个 有效的链接。我会在下面解释“有效”的含义。 -1. 如果页面没有链接,或者如果第一个链接是我们已经看到的页面,程序应该指示失败并退出。 -1. 如果链接匹配维基百科页面上的哲学网址,程序应该提示成功并退出。 -1. 否则应该回到步骤`1`。 - -该程序应该为它访问的 URL 构建`List`,并在结束时显示结果(无论成功还是失败)。 - -那么我们应该认为什么是“有效的”链接?你在这里有一些选择 各种版本的“到达哲学”推测使用略有不同的规则,但这里有一些选择: - -+ 这个链接应该在页面的内容文本中,而不是侧栏或弹出框。 -+ 它不应该是斜体或括号。 -+ 你应该跳过外部链接,当前页面的链接和红色链接。 -+ 在某些版本中,如果文本以大写字母开头,则应跳过链接。 - -你不必遵循所有这些规则,但我们建议你至少处理括号,斜体以及当前页面的链接。 - -如果你有足够的信息来起步,请继续。或者你可能想要阅读这些提示: - -+ 当你遍历树的时候,你将需要处理的两种`Node`是`TextNode`和`Element`。如果你找到一个`Element`,你可能需要转换它的类型,来访问标签和其他信息。 -+ 当你找到包含链接的`Element`时,通过向上跟踪父节点链,可以检查是否是斜体。如果父节点链中有一个`<i>`或`<em>`标签,链接为斜体。 -+ 为了检查链接是否在括号中,你必须在遍历树时扫描文本,并跟踪开启和闭合括号(理想情况下,你的解决方案应该能够处理嵌套括号(像这样))。 - -如果你从 Java 页面开始,你应该在跟随七个链接之后到达哲学,除非我运行代码后发生了改变。 - -好的,这就是你所得到的所有帮助。现在全靠你了。玩的开心! - diff --git a/docs/think-dast-zh/8.md b/docs/think-dast-zh/8.md deleted file mode 100644 index eb2174193..000000000 --- a/docs/think-dast-zh/8.md +++ /dev/null @@ -1,253 +0,0 @@ -# 第八章 索引器 - -> 原文:[Chapter 8 Indexer](http://greenteapress.com/thinkdast/html/thinkdast009.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -目前,我们构建了一个基本的 Web 爬虫;我们下一步将是索引。在网页搜索的上下文中,索引是一种数据结构,可以查找检索词并找到该词出现的页面。此外,我们想知道每个页面上显示检索词的次数,这将有助于确定与该词最相关的页面。 - -例如,如果用户提交检索词“Java”和“编程”,我们将查找两个检索词并获得两组页面。带有“Java”的页面将包括 Java 岛屿,咖啡昵称以及编程语言的网页。具有“编程”一词的页面将包括不同编程语言的页面,以及该单词的其他用途。通过选择具有两个检索词的页面,我们希望消除不相关的页面,并找到 Java 编程的页面。 - -现在我们了解索引是什么,它执行什么操作,我们可以设计一个数据结构来表示它。 - -## 8.1 数据结构选取 - -索引的基本操作是查找;具体来说,我们需要能够查找检索词并找到包含它的所有页面。最简单的实现将是页面的集合。给定一个检索词,我们可以遍历页面的内容,并选择包含检索词的内容。但运行时间与所有页面上的总字数成正比,这太慢了。 - -一个更好的选择是一个映射(字典),它是一个数据结构,表示键值对的集合,并提供了一种方法,快速查找键以及相应值。例如,我们将要构建的第一个映射是`TermCounter`,它将每个检索词映射为页面中出现的次数。键是检索词,值是计数(也称为“频率”)。 - -Java 提供了`Map`的调用接口,它指定映射应该提供的方法;最重要的是: - -+ `get(key)`:此方法查找一个键并返回相应的值。 -+ `put(key, value)`:该方法向`Map`添加一个新的键值对,或者如果该键已经在映射中,它将替换与`key`关联的值。 - -Java 提供了几个`Map`实现,包括我们将关注的两个,`HashMap`以及`TreeMap`。在即将到来的章节中,我们将介绍这些实现并分析其性能。 - -除了检索词到计数的映射`TermCounter`之外,我们将定义一个被称为`Index`的类,它将检索词映射为出现的页面的集合。而这又引发了下一个问题,即如何表示页面集合。同样,如果我们考虑我们想要执行的操作,它们就指导了我们的决定。 - -在这种情况下,我们需要组合两个或多个集合,并找到所有这些集合中显示的页面。你可以将此操作看做集合的交集:两个集合的交集是出现在两者中的一组元素。 - -你可能猜到了,Java 提供了一个`Set`接口,来定义集合应该执行的操作。它实际上并不提供设置交集,但它提供了方法,使我们能够有​​效地实现交集和其他结合操作。核心的`Set`方法是: - -+ `add(element)`:该方法将一个元素添加到集合中;如果元素已经在集合中,则它不起作用。 -+ `contains(element)`:该方法检查给定元素是否在集合中。 - -Java 提供了几个`Set`实现,包括`HashSet`和`TreeSet`。 - -现在我们自顶向下设计了我们的数据结构,我们将从内到外实现它们,从`TermCounter`开始。 - -## 8.2 `TermCounter` - -`TermCounter`是一个类,表示检索词到页面中出现次数的映射。这是类定义的第一部分: - -```java -public class TermCounter { - - private Map<String, Integer> map; - private String label; - - public TermCounter(String label) { - this.label = label; - this.map = new HashMap<String, Integer>(); - } -} -``` - -实例变量`map`包含检索词到计数的映射,并且`label`标识检索词的来源文档;我们将使用它来存储 URL。 - -为了实现映射,我选择了`HashMap`,它是最常用的`Map`。在几章中,你将看到它是如何工作的,以及为什么它是一个常见的选择。 - -`TermCounter`提供`put`和`get`,定义如下: - -```java - public void put(String term, int count) { - map.put(term, count); - } - - public Integer get(String term) { - Integer count = map.get(term); - return count == null ? 0 : count; - } -``` - -`put`只是一个包装方法;当你调用`TermCounter`的`put`时,它会调用内嵌映射的`put`。 - -另一方面,`get`做了一些实际工作。当你调用`TermCounter`的`get`时,它会在映射上调用`get`,然后检查结果。如果该检索词没有出现在映射中,则`TermCount.get`返回`0`。`get`的这种定义方式使`incrementTermCount`的写入更容易,它需要一个检索词,并增加关联该检索词的计数器。 - -```java - public void incrementTermCount(String term) { - put(term, get(term) + 1); - } -``` - -如果这个检索词未见过,则`get`返回`0`;我们设为`1`,然后使用`put`向映射添加一个新的键值对。如果该检索词已经在映射中,我们得到旧的计数,增加`1`,然后存储新的计数,替换旧的值。 - -此外,`TermCounter`还提供了这些其他方法,来帮助索引网页: - -```java - public void processElements(Elements paragraphs) { - for (Node node: paragraphs) { - processTree(node); - } - } - - public void processTree(Node root) { - for (Node node: new WikiNodeIterable(root)) { - if (node instanceof TextNode) { - processText(((TextNode) node).text()); - } - } - } - - public void processText(String text) { - String[] array = text.replaceAll("\\pP", " "). - toLowerCase(). - split("\\s+"); - - for (int i=0; i<array.length; i++) { - String term = array[i]; - incrementTermCount(term); - } - } -``` - -最后,这里是一个例子,展示了如何使用`TermCounter`: - -```java - String url = "http://en.wikipedia.org/wiki/Java_(programming_language)"; - WikiFetcher wf = new WikiFetcher(); - Elements paragraphs = wf.fetchWikipedia(url); - - TermCounter counter = new TermCounter(url); - counter.processElements(paragraphs); - counter.printCounts(); -``` - -这个示例使用了`WikiFetcher`从维基百科下载页面,并解析正文。之后它创建了`TermCounter`并使用它来计数页面上的单词。 - -下一节中,你会拥有一个挑战,来运行这个代码,并通过填充缺失的方法来测试你的理解。 - -## 8.3 练习 6 - -在本书的存储库中,你将找到此练习的源文件: - -+ `TermCounter.java`包含上一节中的代码。 -+ `TermCounterTest.java`包含测试代码`TermCounter.java`。 -+ `Index.java`包含本练习下一部分的类定义。 -+ `WikiFetcher.java`包含我们在上一个练习中使用的,用于下载和解析网页的类。 -+ `WikiNodeIterable.java`包含我们用于遍历 DOM 树中的节点的类。 - -你还会发现 Ant 构建文件`build.xml`。 - -运行`ant build`来编译源文件。然后运行`ant TermCounter`;它应该运行上一节中的代码,并打印一个检索词列表及其计数。输出应该是这样的: - -``` -genericservlet, 2 -configurations, 1 -claimed, 1 -servletresponse, 2 -occur, 2 -Total of all counts = -1 -``` - -运行它时,检索词的顺序可能不同。 - -最后一行应该打印检索词计数的总和,但是由于方法`size`不完整而返回`-1`。填充此方法并`ant TermCounter`重新运行。结果应该是`4798`。 - -运行`ant TermCounterTest`来确认这部分练习是否完整和正确。 - -对于练习的第二部分,我将介绍`Index`对象的实现,你将填充一个缺失的方法。这是类定义的开始: - -```java -public class Index { - - private Map<String, Set<TermCounter>> index = - new HashMap<String, Set<TermCounter>>(); - - public void add(String term, TermCounter tc) { - Set<TermCounter> set = get(term); - - // if we're seeing a term for the first time, make a new Set - if (set == null) { - set = new HashSet<TermCounter>(); - index.put(term, set); - } - // otherwise we can modify an existing Set - set.add(tc); - } - - public Set<TermCounter> get(String term) { - return index.get(term); - } -``` - -实例变量`index`是每个检索词到一组`TermCounter`对象的映射。每个`TermCounter`表示检索词出现的页面。 - -`add`方法向集合添加新的`TermCounter`,它与检索词关联。当我们索引一个尚未出现的检索词时,我们必须创建一个新的集合。否则我们可以添加一个新的元素到一个现有的集合。在这种情况下,`set.add`修改位于`index`里面的集合,但不会修改`index`本身。我们唯一修改`index`的时候是添加一个新的检索词。 - -最后,`get`方法接受检索词并返回相应的`TermCounter`对象集。 - -这种数据结构比较复杂。回顾一下,`Index`包含`Map`,将每个检索词映射到`TermCounter`对象的`Set`,每个`TermCounter`包含一个`Map`,将检索词映射到计数。 - -![](img/8-1.jpg) - -图 8.1 `Index`的对象图 - -图 8.1 是展示这些对象的对象图。`Index`对象具有一个名为`index` 的`Map`实例变量。在这个例子中,`Map`只包含一个字符串,`"Java"`,它映射到一个`Set`,包含两个`TermCounter`对象的,代表每个出现单词“Java”的页面。 - -每个`TermCounter`包含`label`,它是页面的 URL,以及`map`,它是`Map`,包含页面上的单词和每个单词出现的次数。 - -`printIndex`方法展示了如何解压缩此数据结构: - -```java - public void printIndex() { - // loop through the search terms - for (String term: keySet()) { - System.out.println(term); - - // for each term, print pages where it appears and frequencies - Set<TermCounter> tcs = get(term); - for (TermCounter tc: tcs) { - Integer count = tc.get(term); - System.out.println(" " + tc.getLabel() + " " + count); - } - } - } -``` - -外层循环遍历检索词。内层循环迭代`TermCounter`对象。 - -运行`ant build`来确保你的源代码已编译,然后运行`ant Index`。它下载两个维基百科页面,对它们进行索引,并打印结果;但是当你运行它时,你将看不到任何输出,因为我们已经将其中一个方法留空。 - -你的工作是填写`indexPage`,它需要一个 URL(一个`String`)和一个`Elements`对象,并更新索引。下面的注释描述了应该做什么: - -```java -public void indexPage(String url, Elements paragraphs) { - // 生成一个 TermCounter 并统计段落中的检索词 - - // 对于 TermCounter 中的每个检索词,将 TermCounter 添加到索引 -} -``` - -它能工作之后,再次运行`ant Index`,你应该看到如下输出: - -```java -... -configurations - http://en.wikipedia.org/wiki/Programming_language 1 - http://en.wikipedia.org/wiki/Java_(programming_language) 1 -claimed - http://en.wikipedia.org/wiki/Java_(programming_language) 1 -servletresponse - http://en.wikipedia.org/wiki/Java_(programming_language) 2 -occur - http://en.wikipedia.org/wiki/Java_(programming_language) 2 -``` - -当你运行的时候,检索词的顺序可能有所不同。 - -同样,运行`ant TestIndex`来确定完成了这部分练习。 diff --git a/docs/think-dast-zh/9.md b/docs/think-dast-zh/9.md deleted file mode 100644 index 0cc664605..000000000 --- a/docs/think-dast-zh/9.md +++ /dev/null @@ -1,157 +0,0 @@ -# 第九章 `Map`接口 - -> 原文:[Chapter 9 The Map interface](http://greenteapress.com/thinkdast/html/thinkdast010.html) - -> 译者:[飞龙](https://github.com/wizardforcel) - -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) - -> 自豪地采用[谷歌翻译](https://translate.google.cn/) - -在接下来的几个练习中,我介绍了`Map`接口的几个实现。其中一个基于哈希表,这可以说是所发明的最神奇的数据结构。另一个是类似的`TreeMap`,不是很神奇,但它有附加功能,它可以按顺序迭代元素。 - -你将有机会实现这些数据结构,然后我们将分析其性能。 - -但是在我们可以解释哈希表之前,我们将从一个`Map`开始,它使用键值对的`List`来简单实现。 - -## 9.1 实现`MyLinearMap` - -像往常一样,我提供启动代码,你将填写缺少的方法。这是`MyLinearMap`类定义的起始: - -```java -public class MyLinearMap<K, V> implements Map<K, V> { - - private List<Entry> entries = new ArrayList<Entry>(); -``` - -该类使用两个类型参数,`K`是键的类型,`V`是值的类型。`MyLinearMap`实现`Map`,这意味着它必须提供`Map`接口中的方法。 - -`MyLinearMap`对象具有单个实例变量,`entries`,这是一个`Entry`的`ArrayList`对象。每个`Entry`都包含一个键值对。这里是定义: - -```java - public class Entry implements Map.Entry<K, V> { - private K key; - private V value; - - public Entry(K key, V value) { - this.key = key; - this.value = value; - } - - @Override - public K getKey() { - return key; - } - @Override - public V getValue() { - return value; - } - } -``` - -`Entry`没有什么,只是一个键和一个值的容器。该定义内嵌在`MyLinearList`中,因此它使用相同类型的参数,`K`和`V`。 - -这就是你做这个练习所需的所有东西,所以让我们开始吧。 - -## 9.2 练习 7 - -在本书的仓库中,你将找到此练习的源文件: - -+ `MyLinearMap.java`包含练习的第一部分的起始代码。 -+ `MyLinearMapTest.java`包含`MyLinearMap`的单元测试。 - -你还会找到 Ant 构建文件`build.xml`。 - -运行`ant build`来编译源文件。然后运行`ant MyLinearMapTest`;几个测试应该失败,因为你有一些任务要做。 - -首先,填写`findEntry`的主体。这是一个辅助方法,不是`Map`接口的一部分,但是一旦你让它工作,你可以在几种方法中使用它。给定一个目标键(Key),它应该搜索条目(Entry)并返回包含目标的条目(按照键,而不是值),或者如果不存在则返回`null`。请注意,我提供了`equals`,正确比较两个键并处理`null`。 - - -你可以再次运行`ant MyLinearMapTest`,但即使你的`findEntry`是正确的,测试也不会通过,因为`put`不完整。 - - -填充`put`。你应该阅读`Map.put`的文档,<http://thinkdast.com/listput> ,以便你知道应该做什么。你可能希望从一个版本开始,其中`put`始终添加新条目,并且不会修改现有条目;这样你可以先测试简单的情况。或者如果你更加自信,你可以一次写出整个东西。 - -一旦你`put`正常工作,测试`containsKey`应该通过。 - -阅读`Map.get`的文档,<http://thinkdast.com/listget> ,然后填充方法。再次运行测试。 - -最后,阅读`Map.remove`的文档,<http://thinkdast.com/maprem> 并填充方法。 - -到了这里,所有的测试都应该通过。恭喜! - -## 9.3 分析`MyLinearMap` - -这一节中,我展示了上一个练习的答案,并分析核心方法的性能。这里是`findEntry`和`equals`。 - -```java -private Entry findEntry(Object target) { - for (Entry entry: entries) { - if (equals(target, entry.getKey())) { - return entry; - } - } - return null; -} - -private boolean equals(Object target, Object obj) { - if (target == null) { - return obj == null; - } - return target.equals(obj); -} -``` - -`equals`的运行时间可能取决于`target`键和键的大小 ,但通常不取决于条目的数量,`n`。那么`equals`是常数时间。 - -在`findEntry`中,我们可能会很幸运,并在一开始就找到我们要找的键,但是我们不能指望它。一般来说,我们要搜索的条目数量与`n`成正比,所以`findEntry`是线性的。 - - -大部分的`MyLinearMap`核心方法使用`findEntry`,包括`put`,`get`,和`remove`。这就是他们的样子: - -```java -public V put(K key, V value) { - Entry entry = findEntry(key); - if (entry == null) { - entries.add(new Entry(key, value)); - return null; - } else { - V oldValue = entry.getValue(); - entry.setValue(value); - return oldValue; - } -} -public V get(Object key) { - Entry entry = findEntry(key); - if (entry == null) { - return null; - } - return entry.getValue(); -} -public V remove(Object key) { - Entry entry = findEntry(key); - if (entry == null) { - return null; - } else { - V value = entry.getValue(); - entries.remove(entry); - return value; - } -} -``` - -`put`调用`findEntry`之后,其他一切都是常数时间。记住这个`entries`是一个`ArrayList`,所以向末尾添加元素平均是常数时间。如果键已经在映射中,我们不需要添加条目,但我们必须调用`entry.getValue`和`entry.setValue`,而这些都是常数时间。把它们放在一起,`put`是线性的。 - -同样,`get`也是线性的。 - -`remove`稍微复杂一些,因为`entries.remove`可能需要从一开始或中间删除`ArrayList`的一个元素,并且需要线性时间。但是没关系:两个线性运算仍然是线性的。 - - -总而言之,核心方法都是线性的,这就是为什么我们将这个实现称为`MyLinearMap`(嗒嗒!)。 - -如果我们知道输入的数量很少,这个实现可能会很好,但是我们可以做得更好。实际上,`Map`所有的核心方法都是常数时间的实现。当你第一次听到这个消息时,可能似乎觉得不可能。实际上我们所说的是,你可以在常数时间内大海捞针,不管海有多大。这是魔法。 - -我们不是将条目存储在一个大的`List`中,而是把它们分解成许多短的列表。对于每个键,我们将使用哈希码(在下一节中进行说明)来确定要使用的列表。 -使用大量的简短列表比仅仅使用一个更快,但正如我将解释的,它不会改变增长级别;核心功能仍然是线性的。但还有一个技巧:如果我们增加列表的数量来限制每个列表的条目数,就会得到一个恒定时间的映射。你会在下一个练习中看到细节,但是首先要了解哈希! - -在下一章中,我将介绍一种解决方案,分析`Map`核心方法的性能,并引入更有效的实现。 diff --git a/docs/think-dast-zh/README.md b/docs/think-dast-zh/README.md deleted file mode 100644 index b4f884add..000000000 --- a/docs/think-dast-zh/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# 数据结构思维中文版 - -> 原书:[Think Data Structures: Algorithms and Information Retrieval in Java](http://greenteapress.com/thinkdast/html/index.html) -> -> 译者:[飞龙](https://github.com/wizardforcel) -> -> 版本:1.0.0 -> -> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) -> -> 自豪地采用[谷歌翻译](https://translate.google.cn/) -> -> 任何你写的代码,超过 6 个月不去看它,当你再看时,都像是别人写的。——Eagleson 定律 - -+ [ApacheCN 面试求职交流群 724187166](https://jq.qq.com/?_wv=1027&k=54ujcL3) -+ [ApacheCN 学习资源](http://www.apachecn.org/) - -‍ - -+ [在线阅读](https://think-dast.apachecn.org) -+ [在线阅读(Gitee)](https://apachecn.gitee.io/think-dast-zh/) -+ [PDF格式](https://www.gitbook.com/download/pdf/book/wizardforcel/think-dast) -+ [EPUB格式](https://www.gitbook.com/download/epub/book/wizardforcel/think-dast) -+ [MOBI格式](https://www.gitbook.com/download/mobi/book/wizardforcel/think-dast) -+ [代码仓库](http://github.com/apachecn/think-dast-zh) - -## 下载 - -### Docker - -``` -docker pull apachecn0/think-dast-zh -docker run -tid -p <port>:80 apachecn0/think-dast-zh -# 访问 http://localhost:{port} 查看文档 -``` - -### PYPI - -``` -pip install think-dast-zh -think-dast-zh <port> -# 访问 http://localhost:{port} 查看文档 -``` - -### NPM - -``` -npm install -g think-dast-zh -think-dast-zh <port> -# 访问 http://localhost:{port} 查看文档 -``` - -## 赞助我 - -![](img/qr_alipay.png) diff --git a/docs/think-dast-zh/SUMMARY.md b/docs/think-dast-zh/SUMMARY.md deleted file mode 100644 index 74b53d286..000000000 --- a/docs/think-dast-zh/SUMMARY.md +++ /dev/null @@ -1,19 +0,0 @@ -+ [数据结构思维中文版](README.md) -+ [前言](0.md) -+ [第一章 接口](1.md) -+ [第二章 算法分析](2.md) -+ [第三章 `ArrayList`](3.md) -+ [第四章 `LinkedList`](4.md) -+ [第五章 双链表](5.md) -+ [第六章 树的遍历](6.md) -+ [第七章 到达哲学](7.md) -+ [第八章 索引器](8.md) -+ [第九章 `Map`接口](9.md) -+ [第十章 哈希](10.md) -+ [第十一章 `HashMap`](11.md) -+ [第十二章 `TreeMap`](12.md) -+ [第十三章 二叉搜索树](13.md) -+ [第十四章 持久化](14.md) -+ [第十五章 爬取维基百科](15.md) -+ [第十六章 布尔搜索](16.md) -+ [第十七章 排序](17.md) \ No newline at end of file diff --git a/docs/think-dast-zh/cover.jpg b/docs/think-dast-zh/cover.jpg deleted file mode 100644 index b3d1291d4..000000000 Binary files a/docs/think-dast-zh/cover.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/11-1.jpg b/docs/think-dast-zh/img/11-1.jpg deleted file mode 100644 index 6eb203e1d..000000000 Binary files a/docs/think-dast-zh/img/11-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/11-2.jpg b/docs/think-dast-zh/img/11-2.jpg deleted file mode 100644 index eca333b05..000000000 Binary files a/docs/think-dast-zh/img/11-2.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/12-1.jpg b/docs/think-dast-zh/img/12-1.jpg deleted file mode 100644 index 1b4d0949f..000000000 Binary files a/docs/think-dast-zh/img/12-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/13-1.jpg b/docs/think-dast-zh/img/13-1.jpg deleted file mode 100644 index efbf59875..000000000 Binary files a/docs/think-dast-zh/img/13-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/17-1.jpg b/docs/think-dast-zh/img/17-1.jpg deleted file mode 100644 index e06d2d5fb..000000000 Binary files a/docs/think-dast-zh/img/17-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/17-2.jpg b/docs/think-dast-zh/img/17-2.jpg deleted file mode 100644 index cb8b82db9..000000000 Binary files a/docs/think-dast-zh/img/17-2.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/17-3.jpg b/docs/think-dast-zh/img/17-3.jpg deleted file mode 100644 index 1cbc1b28d..000000000 Binary files a/docs/think-dast-zh/img/17-3.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/3-1.jpg b/docs/think-dast-zh/img/3-1.jpg deleted file mode 100644 index 1498ed7ee..000000000 Binary files a/docs/think-dast-zh/img/3-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/4-1.jpg b/docs/think-dast-zh/img/4-1.jpg deleted file mode 100644 index 60da93100..000000000 Binary files a/docs/think-dast-zh/img/4-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/5-1.jpg b/docs/think-dast-zh/img/5-1.jpg deleted file mode 100644 index f4988e168..000000000 Binary files a/docs/think-dast-zh/img/5-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/5-2.jpg b/docs/think-dast-zh/img/5-2.jpg deleted file mode 100644 index 44e539c33..000000000 Binary files a/docs/think-dast-zh/img/5-2.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/5-3.jpg b/docs/think-dast-zh/img/5-3.jpg deleted file mode 100644 index 2cdb14763..000000000 Binary files a/docs/think-dast-zh/img/5-3.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/6-1.jpg b/docs/think-dast-zh/img/6-1.jpg deleted file mode 100644 index e226ea200..000000000 Binary files a/docs/think-dast-zh/img/6-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/6-2.jpg b/docs/think-dast-zh/img/6-2.jpg deleted file mode 100644 index 6daf3965b..000000000 Binary files a/docs/think-dast-zh/img/6-2.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/6-3.jpg b/docs/think-dast-zh/img/6-3.jpg deleted file mode 100644 index fe4840e05..000000000 Binary files a/docs/think-dast-zh/img/6-3.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/8-1.jpg b/docs/think-dast-zh/img/8-1.jpg deleted file mode 100644 index 6e86d2943..000000000 Binary files a/docs/think-dast-zh/img/8-1.jpg and /dev/null differ diff --git a/docs/think-dast-zh/img/qr_alipay.png b/docs/think-dast-zh/img/qr_alipay.png deleted file mode 100644 index 154eb4c80..000000000 Binary files a/docs/think-dast-zh/img/qr_alipay.png and /dev/null differ diff --git a/images/118/PascalTriangleAnimated2.gif b/images/118/PascalTriangleAnimated2.gif new file mode 100644 index 000000000..c002af436 Binary files /dev/null and b/images/118/PascalTriangleAnimated2.gif differ diff --git a/images/463/1.md b/images/463/1.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/images/463/1.md @@ -0,0 +1 @@ + diff --git a/images/463/island.png b/images/463/island.png new file mode 100644 index 000000000..76254a724 Binary files /dev/null and b/images/463/island.png differ diff --git a/images/84/1.md b/images/84/1.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/images/84/1.md @@ -0,0 +1 @@ + diff --git a/images/84/histogram1.png b/images/84/histogram1.png new file mode 100644 index 000000000..43600013c Binary files /dev/null and b/images/84/histogram1.png differ diff --git a/images/84/histogram_area1.png b/images/84/histogram_area1.png new file mode 100644 index 000000000..7a1a0ca9d Binary files /dev/null and b/images/84/histogram_area1.png differ diff --git a/images/MainPage/ApacheCN-group.png b/images/MainPage/ApacheCN-group.png new file mode 100644 index 000000000..ea93fc516 Binary files /dev/null and b/images/MainPage/ApacheCN-group.png differ diff --git a/images/N-Queens.png b/images/N-Queens.png new file mode 100644 index 000000000..1be6b68e4 Binary files /dev/null and b/images/N-Queens.png differ diff --git a/images/Project cornerstone/3221532952133_.pic_hd.jpg b/images/Project cornerstone/3221532952133_.pic_hd.jpg new file mode 100644 index 000000000..1d256984b Binary files /dev/null and b/images/Project cornerstone/3221532952133_.pic_hd.jpg differ diff --git a/images/Project cornerstone/3231532952152_.pic_hd.jpg b/images/Project cornerstone/3231532952152_.pic_hd.jpg new file mode 100644 index 000000000..b104984cd Binary files /dev/null and b/images/Project cornerstone/3231532952152_.pic_hd.jpg differ diff --git a/images/Project cornerstone/approve letter.md b/images/Project cornerstone/approve letter.md new file mode 100644 index 000000000..5ddfe96ae --- /dev/null +++ b/images/Project cornerstone/approve letter.md @@ -0,0 +1,3 @@ + +![](https://github.com/apachecn/LeetCode/blob/master/images/Project%20cornerstone/3221532952133_.pic_hd.jpg) +![](https://github.com/apachecn/LeetCode/blob/master/images/Project%20cornerstone/3231532952152_.pic_hd.jpg) diff --git a/images/README.md b/images/README.md new file mode 100644 index 000000000..d71e82389 --- /dev/null +++ b/images/README.md @@ -0,0 +1 @@ +# Images for the whole repository! diff --git a/images/SortingAlgorithm/BubbleSort_1.gif b/images/SortingAlgorithm/BubbleSort_1.gif new file mode 100644 index 000000000..9dd0ed47f Binary files /dev/null and b/images/SortingAlgorithm/BubbleSort_1.gif differ diff --git a/images/SortingAlgorithm/InsertSort_1.gif b/images/SortingAlgorithm/InsertSort_1.gif new file mode 100644 index 000000000..2702b14d4 Binary files /dev/null and b/images/SortingAlgorithm/InsertSort_1.gif differ diff --git a/images/SortingAlgorithm/MergeSort_1.gif b/images/SortingAlgorithm/MergeSort_1.gif new file mode 100644 index 000000000..a29ca19d0 Binary files /dev/null and b/images/SortingAlgorithm/MergeSort_1.gif differ diff --git a/images/SortingAlgorithm/QuickSort_1.gif b/images/SortingAlgorithm/QuickSort_1.gif new file mode 100644 index 000000000..ad88d3576 Binary files /dev/null and b/images/SortingAlgorithm/QuickSort_1.gif differ diff --git a/images/SortingAlgorithm/RadixSort_1.gif b/images/SortingAlgorithm/RadixSort_1.gif new file mode 100644 index 000000000..2a556955a Binary files /dev/null and b/images/SortingAlgorithm/RadixSort_1.gif differ diff --git a/images/SortingAlgorithm/RadixSort_2.png b/images/SortingAlgorithm/RadixSort_2.png new file mode 100644 index 000000000..922e878fa Binary files /dev/null and b/images/SortingAlgorithm/RadixSort_2.png differ diff --git a/images/SortingAlgorithm/SelectionSort_1.gif b/images/SortingAlgorithm/SelectionSort_1.gif new file mode 100644 index 000000000..353459bc6 Binary files /dev/null and b/images/SortingAlgorithm/SelectionSort_1.gif differ diff --git a/images/SortingAlgorithm/ShellSort_1.gif b/images/SortingAlgorithm/ShellSort_1.gif new file mode 100644 index 000000000..bbb3beacd Binary files /dev/null and b/images/SortingAlgorithm/ShellSort_1.gif differ diff --git a/images/SortingAlgorithm/ShellSort_2.png b/images/SortingAlgorithm/ShellSort_2.png new file mode 100644 index 000000000..891d3ba99 Binary files /dev/null and b/images/SortingAlgorithm/ShellSort_2.png differ diff --git a/images/SortingAlgorithm/ShellSort_3.png b/images/SortingAlgorithm/ShellSort_3.png new file mode 100644 index 000000000..0cf9303f5 Binary files /dev/null and b/images/SortingAlgorithm/ShellSort_3.png differ diff --git a/images/SortingAlgorithm/ShellSort_4.png b/images/SortingAlgorithm/ShellSort_4.png new file mode 100644 index 000000000..fa474c3d1 Binary files /dev/null and b/images/SortingAlgorithm/ShellSort_4.png differ diff --git "a/images/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/images/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" new file mode 100644 index 000000000..77b48e419 Binary files /dev/null and "b/images/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" differ diff --git "a/images/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/images/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" new file mode 100644 index 000000000..dbc5b0ef9 Binary files /dev/null and "b/images/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" differ diff --git "a/images/SortingAlgorithm/\345\206\222\346\263\241\346\216\222\345\272\217.gif" "b/images/SortingAlgorithm/\345\206\222\346\263\241\346\216\222\345\272\217.gif" new file mode 100644 index 000000000..f190e62de Binary files /dev/null and "b/images/SortingAlgorithm/\345\206\222\346\263\241\346\216\222\345\272\217.gif" differ diff --git "a/images/SortingAlgorithm/\345\237\272\346\225\260\346\216\222\345\272\217.gif" "b/images/SortingAlgorithm/\345\237\272\346\225\260\346\216\222\345\272\217.gif" new file mode 100644 index 000000000..bfec4065e Binary files /dev/null and "b/images/SortingAlgorithm/\345\237\272\346\225\260\346\216\222\345\272\217.gif" differ diff --git "a/images/SortingAlgorithm/\345\270\214\345\260\224\346\216\222\345\272\217.png" "b/images/SortingAlgorithm/\345\270\214\345\260\224\346\216\222\345\272\217.png" new file mode 100644 index 000000000..fa474c3d1 Binary files /dev/null and "b/images/SortingAlgorithm/\345\270\214\345\260\224\346\216\222\345\272\217.png" differ diff --git "a/images/SortingAlgorithm/\345\275\222\345\271\266\346\216\222\345\272\217.gif" "b/images/SortingAlgorithm/\345\275\222\345\271\266\346\216\222\345\272\217.gif" new file mode 100644 index 000000000..d6fa725b5 Binary files /dev/null and "b/images/SortingAlgorithm/\345\275\222\345\271\266\346\216\222\345\272\217.gif" differ diff --git "a/images/SortingAlgorithm/\345\277\253\351\200\237\346\216\222\345\272\217.gif" "b/images/SortingAlgorithm/\345\277\253\351\200\237\346\216\222\345\272\217.gif" new file mode 100644 index 000000000..6f04ec972 Binary files /dev/null and "b/images/SortingAlgorithm/\345\277\253\351\200\237\346\216\222\345\272\217.gif" differ diff --git "a/images/SortingAlgorithm/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" "b/images/SortingAlgorithm/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" new file mode 100644 index 000000000..f08422cd7 Binary files /dev/null and "b/images/SortingAlgorithm/\346\236\204\345\273\272\345\244\247\351\241\266\345\240\206.png" differ diff --git "a/images/SortingAlgorithm/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" "b/images/SortingAlgorithm/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" new file mode 100644 index 000000000..52e209b51 Binary files /dev/null and "b/images/SortingAlgorithm/\347\233\264\346\216\245\346\217\222\345\205\245\346\216\222\345\272\217.gif" differ diff --git "a/images/SortingAlgorithm/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" "b/images/SortingAlgorithm/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" new file mode 100644 index 000000000..d5975d0c6 Binary files /dev/null and "b/images/SortingAlgorithm/\347\256\200\345\215\225\351\200\211\346\213\251\346\216\222\345\272\217.gif" differ diff --git "a/images/SortingAlgorithm/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" "b/images/SortingAlgorithm/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" new file mode 100644 index 000000000..735cff280 Binary files /dev/null and "b/images/SortingAlgorithm/\350\260\203\346\225\264\345\244\247\351\241\266\345\240\206.png" differ diff --git a/images/WechatIMG439.jpeg b/images/WechatIMG439.jpeg new file mode 100644 index 000000000..bb3e46d13 Binary files /dev/null and b/images/WechatIMG439.jpeg differ diff --git a/images/readme_badges/71EC577ABCDF4D4AE8082BED5D204919.jpg b/images/readme_badges/71EC577ABCDF4D4AE8082BED5D204919.jpg new file mode 100644 index 000000000..6b87385eb Binary files /dev/null and b/images/readme_badges/71EC577ABCDF4D4AE8082BED5D204919.jpg differ diff --git a/images/readme_badges/organization.jpg b/images/readme_badges/organization.jpg new file mode 100644 index 000000000..50a0f7e13 Binary files /dev/null and b/images/readme_badges/organization.jpg differ diff --git a/images/sketch1.png b/images/sketch1.png new file mode 100644 index 000000000..7d1a945b8 Binary files /dev/null and b/images/sketch1.png differ diff --git a/images/union_find8D76B4AFCB73CED67BE37B92B385A55C.jpg b/images/union_find8D76B4AFCB73CED67BE37B92B385A55C.jpg new file mode 100644 index 000000000..89ecf404a Binary files /dev/null and b/images/union_find8D76B4AFCB73CED67BE37B92B385A55C.jpg differ diff --git "a/images/\347\272\277\347\250\213\350\275\254\346\215\242.jpg" "b/images/\347\272\277\347\250\213\350\275\254\346\215\242.jpg" new file mode 100644 index 000000000..7470017e0 Binary files /dev/null and "b/images/\347\272\277\347\250\213\350\275\254\346\215\242.jpg" differ diff --git a/index.html b/index.html deleted file mode 100644 index 4ea983619..000000000 --- a/index.html +++ /dev/null @@ -1,78 +0,0 @@ -<!-- index.html --> - -<!DOCTYPE html> -<html> -<head> - <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> - <meta name="viewport" content="width=device-width,initial-scale=1"> - <meta charset="UTF-8"> - <link rel="stylesheet" href="asset/vue.css"> - <link rel="stylesheet" href="asset/style.css"> - <link rel="stylesheet" href="asset/prism-darcula.css"> - <link rel="stylesheet" href="asset/sidebar.min.css"> - - <!-- google ads --> - <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> - - <!-- google webmaster --> - <meta name="google-site-verification" content="pyo9N70ZWyh8JB43bIu633mhxesJ1IcwWCZlM3jUfFo" /> - - <link rel="stylesheet" href="asset/dark-mode.css"> - <script src="asset/dark-mode.js"></script> - <link rel="stylesheet" href="asset/share.css"> - <script src="asset/share.js"></script> - <link rel="stylesheet" href="asset/edit.css"> - <script src="asset/edit.js"></script> - <link rel="stylesheet" href="asset/back-to-top.css"> - <script src="asset/back-to-top.js"></script> -</head> -<body> - <div id="app">now loading...</div> - <script> - window.$docsify = { - loadNavbar: 'NAV.md', - loadSidebar: 'SUMMARY.md', - name: 'ApacheCN 数据结构与算法译文集', - auto2top: true, - themeColor: '#dd9f05', - repo: 'apachecn/apachecn-algo-zh', - plugins: [window.docsPlugin], - alias: { - '/.*/SUMMARY.md': '/SUMMARY.md', - }, - bdStatId: '38525fdac4b5d4403900b943d4e7dd91', - cnzzId: '1275211409', - search: { - paths: 'auto', - placeholder: '搜索', - noData: '没有结果', - }, - copyCode: { - buttonText: '复制', - errorText: 'Error', - successText: 'OK!', - }, - } - </script> - - <script src="asset/docsify.min.js"></script> - <script src="asset/search.min.js"></script> - <script src="asset/prism-java.min.js"></script> - <script src="asset/prism-c.min.js"></script> - <script src="asset/prism-cpp.min.js"></script> - <script src="asset/prism-javascript.min.js"></script> - <script src="asset/prism-sql.min.js"></script> - <script src="asset/prism-kotlin.min.js"></script> - <script src="asset/prism-perl.min.js"></script> - <script src="asset/prism-python.min.js"></script> - <script src="asset/docsify-copy-code.min.js"></script> - <script src="asset/docsify-baidu-push.js"></script> - <script src="asset/docsify-baidu-stat.js"></script> - <script src="asset/docsify-cnzz.js"></script> - <script src="asset/docsify-apachecn-footer.js"></script> - <script src="asset/docsify-clicker.js"></script> - <link rel="stylesheet" href="asset/docsify-quick-page.css"> - <script src="asset/docsify-quick-page.js"></script> - <script src="asset/docsify-sidebar-collapse.min.js"></script> -</body> -</html> \ No newline at end of file diff --git a/src/51CFCB8475F4ED5B1CAD5F23CF96887A.jpg b/src/51CFCB8475F4ED5B1CAD5F23CF96887A.jpg new file mode 100644 index 000000000..575449655 Binary files /dev/null and b/src/51CFCB8475F4ED5B1CAD5F23CF96887A.jpg differ diff --git a/src/58.md b/src/58.md new file mode 100644 index 000000000..a9a4007cc --- /dev/null +++ b/src/58.md @@ -0,0 +1,3 @@ +![](https://github.com/apachecn/awesome-leetcode/blob/master/src/WechatIMG438.jpeg) + +![](https://github.com/apachecn/awesome-leetcode/blob/master/src/WechatIMG437.jpeg) diff --git a/src/5C3A0153C03FD214FE68B002903E2135.jpg b/src/5C3A0153C03FD214FE68B002903E2135.jpg new file mode 100644 index 000000000..25c13e263 Binary files /dev/null and b/src/5C3A0153C03FD214FE68B002903E2135.jpg differ diff --git a/src/B9A582497F833DDE4E93FA5BAA0BA4EB.jpg b/src/B9A582497F833DDE4E93FA5BAA0BA4EB.jpg new file mode 100644 index 000000000..d1517f587 Binary files /dev/null and b/src/B9A582497F833DDE4E93FA5BAA0BA4EB.jpg differ diff --git a/src/WechatIMG437.jpeg b/src/WechatIMG437.jpeg new file mode 100644 index 000000000..f68f5f831 Binary files /dev/null and b/src/WechatIMG437.jpeg differ diff --git a/src/WechatIMG438.jpeg b/src/WechatIMG438.jpeg new file mode 100644 index 000000000..b8fe14c3f Binary files /dev/null and b/src/WechatIMG438.jpeg differ diff --git a/src/aiqiyi.md b/src/aiqiyi.md new file mode 100644 index 000000000..575e89f5b --- /dev/null +++ b/src/aiqiyi.md @@ -0,0 +1,52 @@ +```python +"""第一题""" +id = input() + +first, second = sum(int(i) for i in id[:3]), sum(int(i) for i in id[3:]) + + +diff = second-first +if diff == 0: + print(0) +else: + nums = [int(i) for i in id] + + res = 0 + if diff > 0: + tmp = [9-i for i in nums[:3]] + [i for i in nums[3:]] + while diff > 0: + res += 1 + diff -= max(tmp) + tmp[tmp.index(max(tmp))] = 0 + print(res) + else: + tmp = [9-i for i in nums[3:]] + [i for i in nums[:3]] + while diff < 0: + res += 1 + diff += max(tmp) + tmp[tmp.index(max(tmp))] = 0 + print(res) + + + +"""第二题""" +tmp = input().split() +N, M, P = int(tmp[0]), int(tmp[1]), int(tmp[2]) + + +tmp = input().split() +foods = [int(i) for i in tmp] +# N, M, P = int(tmp[0]), int(tmp[1]), int(tmp[2]) +for i in range(M): + tmp = input().split() + if tmp[0] == 'B': + foods[int(tmp[1])-1] -= 1 + else: + foods[int(tmp[1])-1] += 1 + +# print(foods) +back_foods = sorted(foods)[::-1] + +# print(foods[P-1]) +print(back_foods.index(foods[P-1])+1) +``` diff --git a/src/baicizhanxiaomi.md b/src/baicizhanxiaomi.md new file mode 100644 index 000000000..7c5705d3f --- /dev/null +++ b/src/baicizhanxiaomi.md @@ -0,0 +1,163 @@ +```python +一晚上做了好几家的,头疼,这些捞b公司贼烦 + +我自己没有参加笔试,就是纯粹A着玩,纯属娱乐 + +"""百词斩第一题""" + +"""自我实现版本""" +def get_time_diff(time1, time2): + res = 0 + res += (int(time2[:2]) - int(time1[:2])) * 3600 + res += (int(time2[3:5]) - int(time1[3:5])) * 60 + res += int(time2[-2:]) - int(time1[-2:]) + return res + +time1 = input() +time2 = input() + +sec = get_time_diff(time1, time2) +print(int(30*sec//3600)) +print(int(6*sec//60)) +print(int(sec*6)) + + +"""工业版本 +可惜笔试不支持 +""" + +from dateutil.parser import parse + +def get_time_diff(time1, time2): + time1 = parse(time1) + time2 = parse(time2) + return (time2-time1).total_seconds() +time1 = '2018-09-20/' + input() +time2 = '2018-09-20/' + input() + +sec = get_time_diff(time1, time2) +print(int(30*sec//3600)) +print(int(6*sec//60)) +print(int(sec*6)) + + +""" +14:52:11 +21:41:14 + +00:00:00 +18:00:00 +""" + +"""百词斩第二题""" + +"""百词斩第二题""" + +n = int(input()) +nums = [int(i) for i in input().split()] +res = '' +# tmp = nums[0] +i = 0 +start = 0 +while i <= n-1: + i += 1 + tmp = 0 + while i <= n-1 and nums[i] == nums[i-1]+1: + i += 1 + tmp += 1 + # print(tmp, i) + if tmp >= 2: + # print(111) + res += str(nums[start]) + '-' + str(nums[i-1]) + ' ' + # start = i + elif tmp == 0: + # print(222) + res += str(nums[start]) + ' ' + else: + # print(333) + # print(nums[start:i+1]) + res += ' '.join([str(i) for i in nums[start:i]]) + ' ' + start = i + # tmp = 0 +print(res[:-1]) + + + +""" +6 +1 2 3 4 6 7 +6 +1 2 4 5 6 7 +""" + + +"""不知道谁的题目""" + +lookup = {} +inputs = [] +flag = True +while True: + user_input = input() + + if user_input == 'END': + break + inputs.append(user_input) + user_input = user_input.split('#') + + n, m = user_input[0], user_input[1] + num = int(m, int(n)) + lookup[num] = lookup.get(num, 0) + 1 + +res = [] +for i in range(len(inputs)): + tmp = inputs[i].split('#') + n, m = tmp[0], tmp[1] + num = int(m, int(n)) + if lookup[num] == 1: + res.append(inputs[i]) + +if not res: + print('None') +else: + for i in res: + print(i) +print(int('33', 4)) +""" +10#15 +4#32 +4#33 +8#17 +END +""" + + +“”“不知道谁的题目 +三种颜色的球 +”“” + +class Solution(object): + res = 0 + def cal_next(self, p, q, r, prev): + tmp = [p, q, r] + cur_max = max(tmp) + # 此时前面排好了且都满足,想要不相邻,数量最多的球中间的所有空格 + # 必须小于或等于另外两个球的数量,否则说明此时排列不合法直接return + if cur_max - 1 > sum(tmp) - cur_max: + return + if p == q == r == 0: + self.res += 1 + return + if p > 0 and prev != 'p': + self.cal_next(p-1, q, r, 'p') + if q > 0 and prev != 'q': + self.cal_next(p, q-1, r, 'q') + if r > 0 and prev != 'r': + self.cal_next(p, q, r-1, 'r') + +s = Solution() +p, q, r = [int(i) for i in input().split()] +s.cal_next(p, q, r, '') +print(s.res) + + +``` diff --git a/src/data_structure.md b/src/data_structure.md new file mode 100644 index 000000000..fc9238c7e --- /dev/null +++ b/src/data_structure.md @@ -0,0 +1,6 @@ +# 我们来一起每周学习数据结构吧,可以在群里一起讨论问题 + +# qq群号码:303677416 + +![](https://github.com/apachecn/awesome-leetcode/blob/master/images/WechatIMG439.jpeg) + diff --git a/src/didi.md b/src/didi.md new file mode 100644 index 000000000..e6d63525d --- /dev/null +++ b/src/didi.md @@ -0,0 +1,78 @@ +```python +"""第一题""" + +lookup1 = set('qwertasdfgzxcv') +lookup2 = set('yuiophjklbnm') + +def minDistance(word1, word2): + if len(word1) == 0 or len(word2) == 0: + return max(len(word1), len(word2)) + dp = [[0 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]: + tmp_dist == 0 + elif (word1[i-1] in lookup1 and word2[j-1] in lookup1) or (word1[i-1] in lookup2 and word2[j-1] in lookup2): + tmp_dist = 1 + else: + tmp_dist = 2 + dp[i][j] = min(dp[i-1][j]+3, dp[i][j-1]+3, dp[i-1][j-1]+tmp_dist) + # print(dp) + return dp[-1][-1] + +""" +slep slap sleep step shoe shop snap slep +""" + +strs = input().split(' ') +# print(strs) +dists = [0] +for i in range(1, len(strs)): + dists.append((minDistance(strs[0], strs[i]))) +# print(dists) +tmp = [0] * len(dists) +for i in range(1, len(dists)): + tmp[i] = [dists[i], strs[i]] +tmp = tmp[1:] + +tmp = sorted(tmp, key=lambda x:x[0]) +# print(tmp) +res = tmp[0][1]+' ' + tmp[1][1]+' '+tmp[2][1] +print(res) + + + +"""第二题""" PS: 这题感谢算法群里的kkk大佬指点我 + +class Solution(object): + res = 0 + def cal_next(self, p, q, r, prev): + tmp = [p, q, r] + cur_max = max(tmp) + # 此时前面排好了且都满足,想要不相邻,数量最多的球中间的所有空格 + # 必须小于或等于另外两个球的数量,否则说明此时排列不合法直接return + if cur_max - 1 > sum(tmp) - cur_max: + return + if p == q == r == 0: + self.res += 1 + return + if p > 0 and prev != 'p': + self.cal_next(p-1, q, r, 'p') + if q > 0 and prev != 'q': + self.cal_next(p, q-1, r, 'q') + if r > 0 and prev != 'r': + self.cal_next(p, q, r-1, 'r') + +s = Solution() +p, q, r = [int(i) for i in input().split()] +s.cal_next(p, q, r, '') +print(s.res) +``` +题目图片见下方: +### 第一题 +![](https://github.com/apachecn/awesome-leetcode/blob/master/src/51CFCB8475F4ED5B1CAD5F23CF96887A.jpg) +![](https://github.com/apachecn/awesome-leetcode/blob/master/src/B9A582497F833DDE4E93FA5BAA0BA4EB.jpg) +### 第二题 +![](https://github.com/apachecn/awesome-leetcode/blob/master/src/5C3A0153C03FD214FE68B002903E2135.jpg) + diff --git a/src/glodon.md b/src/glodon.md new file mode 100644 index 000000000..e8fe928cc --- /dev/null +++ b/src/glodon.md @@ -0,0 +1,99 @@ +```python + +"""第一题""" + +​​​​​​​def f(n): +    res = 0 +    for i in range(1, n+1, 2): +        res += i +    for i in range(2, n+1, 2): +        res -= i +    return res + + +"""第二题""" + +​​​​​​​res = [] +nums = ['9','8','7','6','5','4','3','2','1'] + + +def convert(formula): +    if not formula or len(formula) == 0: +        return 0 +    tmp = '' +    for i in range(len(formula)): +        if formula[i] == '+' formula[i] != '+' and formula[i] != '-': +            return int(tmp) + valid(formula[i+1:])  +        elif formula[i] == '-': +            return int(tmp) - valid(formula[i+1:]) +        else: +            tmp += formula[i] + +def valid(formula): +    if convert(formula) == 100: +        return True +    return False +         +             +def cal(formu, idx): +    if idx == len(nums) - 1: +        formula = ''.join(formu) +        if valid(formula): +            res.append(formula) +    for i in range(idx, len(nums)-1): +        cal(formu, i+1) +        cal(formu[:i] + [formu[i]+'+'] + formu[i+1:], i+1) +        cal(formu[:i] + [formu[i]+'-'] + formu[i+1:], i+1) + + +cal(nums, 0) +print('Results of formulas below all equal to 100') +for i in res: +    print(i) + +"""第三题""" + +​​​​​​​假设我们开始排列是1,2,3,4,5 +然后首先我们要让第一个位置变成2,3,4或者5才满足条件,而在其中我们又会遇到原位置没有变化的情况,则我们知道每次变换2个位置的时候总有重复,因为两边计算出的所有情况中总有一半是不满足的,并且是对于所有位置不同的情况下,那么我们不妨从第一个位置开始,则公式为   ,其中n为小朋友的个数    + +开始编码: +from math import factorial +def cal(n): +    return (n-1) * factorial(n-1) // 2                                                                                                                                                                                                                                                                                                                                                                                                                                                                          + + + + +"""第四题""" + +​​​​​​​import sys +def maxSum(nums, window_len): +    res = -sys.maxsize +    for i in range(len(nums)-window_len): +        res = max(res, sum(nums[i:i+k])) +    return res +         + + + +"""第五题""" + +class ListNode(object): +    def __init__(self, val, next, sib): +        self.val = val +        self.next = next +        self.sib = sib + +class Clone(object) +    def cloneComplicateListNode(self, head): +        if not head: +            return head +        dummy = cur = ListNode(head.val, None, None) +        while head: +            cur.next = self.cloneComplicateListNode(head.next) +            cur.sib = self.cloneComplicateListNode(head.sib) +            head = head.next +            cur = cur.next +        return dummy +         +``` diff --git a/src/indeed_tokyo.md b/src/indeed_tokyo.md new file mode 100644 index 000000000..a8f363d79 --- /dev/null +++ b/src/indeed_tokyo.md @@ -0,0 +1,130 @@ +```python +"""第一题""" +tmp = input().split() +n, q = int(tmp[0]), int(tmp[1]) +nums = [int(i) for i in input().split()] +idx_ms = [] +for i in range(q): + tmp = input().split() + idx, m = int(tmp[0]), int(tmp[1]) + idx_ms.append([idx, m]) +sums = sum([i for i in nums if i & 1 == 0]) +res = [sums] * (q+1) +for i in range(q): + flag = nums[idx_ms[i][0]-1] & 1 == 0 + + if flag and idx_ms[i][1] + nums[idx_ms[i][0]-1] & 1 == 0: + res[i+1] = res[i] + idx_ms[i][1] + elif flag and idx_ms[i][1] + nums[idx_ms[i][0]-1] & 1 != 0: + res[i+1] = res[i] - nums[idx_ms[i][0] - 1] + elif not flag and idx_ms[i][1] + nums[idx_ms[i][0]-1] & 1 == 0: + res[i + 1] = res[i] + idx_ms[i][1] + nums[idx_ms[i][0] - 1] + + else: + res[i+1] = res[i] + + nums[idx_ms[i][0] - 1] += idx_ms[i][1] + +# print(res[1:]) + +for i in range(q): + print(res[i+1]) + + + + + +"""第二题""" +import sys +N = int(input()) +nums = [-sys.maxsize] + [int(i) for i in input().split()] +res = 0 +flag = 1 +for i in range(len(nums)): + if nums[i] >= nums[i-1]: + continue + elif nums[i] <= 0 and -nums[i] >= nums[i-1]: + res += 1 + nums[i] = -nums[i] + elif nums[i] <= 0 and -nums[i] < nums[i-1]: + flag = 0 + print(-1) + break + elif nums[i] < nums[i-1] and nums[i] > 0: + flag = 0 + print(-1) + break +if flag: + print(res) + + + + +"""第三题""" +class Solution(): + def __init__(self): + self.res = 0 + self.lst = [] + def sol(self): + tmp = input().split() + row, col = int(tmp[0]), int(tmp[1]) + + grid = [] + for i in range(row): + grid.append([i for i in input()]) + def bfs_paths(grid, start, goal): + if start[0] == goal[0] and start[1] == goal[1]: + self.res += 1 + if start[0] == row-1 and start[1] == col-1: + return + # print(start, goal) + if 0 <= start[0] + 1 < row and grid[start[0]+1][start[1]] == '.': + bfs_paths(grid, [start[0]+1,start[1]], goal) + if 0 <= start[1] + 1 < col and grid[start[0]][start[1]+1] == '.': + bfs_paths(grid, [start[0],start[1]+1], goal) + # return res + n = int(input()) + for i in range(n): + tmp = input().split() + goal1, goal2 = int(tmp[0]), int(tmp[1]) + # print(goal1, goal2) + + + bfs_paths(grid, [0,0], [goal1-1,goal2-1]) + # print([goal1-1,goal2-1]) + self.lst.append(self.res % (pow(10, 9) + 7)) + self.res = 0 + + +s = Solution() +s.sol() +for i in s.lst: + print(i) + + + +"""第四题""" +tmp = input().split() +n, m = int(tmp[0]), int(tmp[1]) +requi = [] +for i in range(m): + nums = [int(i) for i in input().split()] + requi.append(nums) + +keys =set([1]) +rooms = set([1]) +# flag = True +while True: + flag1 = False + for i in requi: + + if i[0] in rooms and i[1] not in rooms: + if i[2] in keys: + flag1 = True + rooms.add(i[1]) + keys.add(i[1]) + if not flag1: + break + +print(len(rooms)) +``` diff --git a/src/kuaishou.md b/src/kuaishou.md new file mode 100644 index 000000000..3f47f58e6 --- /dev/null +++ b/src/kuaishou.md @@ -0,0 +1,141 @@ +```python +"""第一题""" + + +tmp = input().split() +numerator = int(tmp[0]) +denominator = int(tmp[1]) + +def fractionToDecimal(numerator, denominator): + if numerator == 0: + return '0' + res = '' + if numerator * denominator < 0: + res += '-' + numerator, denominator = abs(numerator), abs(denominator) + res += str(numerator // denominator) + if numerator % denominator == 0: + return res + res += '.' + r = numerator % denominator + m = {} + # print(res) + while r: + if r in m: + res = res[:m[r]] + '(' + res[m[r]:] + ')' + break + m[r] = len(res) + r *= 10 + res += str(r // denominator) + r %= denominator + + return res + + +res = fractionToDecimal(numerator, denominator) +# print(res) +if '(' not in res: + if '.' not in res: + print(int(res)) + else: + print(res) +else: + print(res) + + + + + + + +"""第二题""" + + +tmp = input().split(',') +if not tmp: + print(0) +else: + costs = [int(i) for i in tmp] + + if len(costs) == 1: + print(costs[-1]) + elif len(costs) == 2: + print(costs[-1]) + else: + dp = [0] * len(costs) + dp[0] = costs[0] + dp[1] = costs[1] + + + for i in range(2, len(dp)): + dp[i] = min(dp[i-1], dp[i-2]) + costs[i] + + print(min(dp[-3], dp[-2]) + costs[-1]) + + + + + +"""第三题""" +def max_sub_array(nums): + 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 (maxSum.index(max(maxSum)), max(maxSum)) +def min_sub_array(nums): + n = len(nums) + minSum = [nums[0] for i in range(n)] + for i in range(1, n): + minSum[i] = min(minSum[i - 1] + nums[i], nums[i]) + return (minSum.index(min(minSum)), min(minSum)) + +tmp = input().split() +N, M = int(tmp[0]), int(tmp[1]) +tmp = input().split(' ') +levels = [int(i) for i in tmp] +backup_levels = [i for i in levels] +idxes = [] +res = 0 +k = 0 +for i in range(M): + idx, cur_max = max_sub_array(levels) + if cur_max >= 0: + cur_sum = 0 + left_idx = 0 + for j in range(idx, -1, -1): + cur_sum += levels[j] + if cur_sum == cur_max: + left_idx = j + idxes.append([left_idx, idx]) + break + levels = levels[:left_idx] + levels[idx+1:] + # print(cur_max) + res += cur_max + # print(res) + else: + + # tmp = min_sub_array(backup_levels[idxes[i][0]:idxes[i][1] + 1])[1] + idx, cur_min = min_sub_array(backup_levels[idxes[k][0]:idxes[k][1] + 1]) + if cur_min <= 0: + cur_sum = 0 + left_idx = 0 + for j in range(idx, -1, -1): + cur_sum += backup_levels[j] + if cur_sum == cur_max: + left_idx = j + # idxes.append([left_idx, idx]) + break + # print(left_idx, idx) + k += 1 + res += -cur_min if cur_min <= 0 else 0 + +# print(res) +# print(backup_levels) +# print(idxes) + + +print(res) +# print() +# print(min_sub_array(backup_levels[0:5])) +``` diff --git a/src/liulishuo.md b/src/liulishuo.md new file mode 100644 index 000000000..2d50ba513 --- /dev/null +++ b/src/liulishuo.md @@ -0,0 +1,26 @@ +```python + +"""第一题""" +n = int(input()) +nums = [] +for i in range(n): + nums.append(int(input())) + +max_sum, max_end = nums[0], nums[0] +for i in range(1, len(nums)): + max_end = max(max_end + nums[i], nums[i]) + max_sum = max(max_sum, max_end) +print(max_sum) + + +"""问答题 + +Let's say the egg1 and egg2 + +Firstly, use egg1 from 2nd floor and drop it, if egg1 break, then use egg2 to check 1th floor, if egg2 doesn't break, then the highest floor we need is 1th, otherwise 2nd floor is what we want. If from neither floor two eggs don't break, we can do this from 4th and 3rd, 6th and 5th, 8th and 7th,,,,,,100th and 99th. + +From this method, we can easily get this problem reduced by 2 and totally time complexity will be O(lgn) if in programming. + +""" + +``` diff --git a/src/py2.x/TreeRecursionIterator.py b/src/py2.x/TreeRecursionIterator.py new file mode 100644 index 000000000..bf583fc82 --- /dev/null +++ b/src/py2.x/TreeRecursionIterator.py @@ -0,0 +1,35 @@ +# coding:utf8 + +from __future__ import print_function +class Node(): + def __init__(self, value, left=None, right=None): + self.value = value + self.left = left + self.right = right + +def midRecusion(node): + if node is None: + return + midRecusion(node.left) + print(node.value, end=' ') + midRecusion(node.right) + +def midIterator(node): + stack = [] + while stack or node: + if node is not None: + stack.append(node) + node = node.left + else: + node = stack.pop(-1) + print(node.value, end=' ') + node = node.right + +if __name__ == "__main__": + node = Node("D", Node("B", Node("A"), Node("C")), Node("E", right=Node("G", left=Node("F")))) + + print('\n中序遍历<递归>:') + midRecusion(node) + + print('\n中序遍历<迭代>:') + midIterator(node) \ No newline at end of file diff --git a/src/py2.x/list2iteration.py b/src/py2.x/list2iteration.py new file mode 100644 index 000000000..a4a333f7d --- /dev/null +++ b/src/py2.x/list2iteration.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +# coding:utf8 +''' +迭代使用的是循环结构。 +递归使用的是选择结构。 +''' +from __future__ import print_function + +# 递归求解 +def calculate(l): + if len(l) <= 1: + return l[0] + value = calculate(l[1:]) + return 10**(len(l) - 1) * l[0] + value + + +# 迭代求解 +def calculate2(l): + result = 0 + while len(l) >= 1: + result += 10 ** (len(l)-1) * l[0] + l = l[1:] + return result + + +l1 = [1, 2, 3] +l2 = [4, 5] +sum = 0 +result = calculate(l1) + calculate(l2) +# result = calculate2(l1) + calculate2(l2) +print(result) diff --git a/src/py3.x/TreeRecursionIterator.py b/src/py3.x/TreeRecursionIterator.py new file mode 100644 index 000000000..bf583fc82 --- /dev/null +++ b/src/py3.x/TreeRecursionIterator.py @@ -0,0 +1,35 @@ +# coding:utf8 + +from __future__ import print_function +class Node(): + def __init__(self, value, left=None, right=None): + self.value = value + self.left = left + self.right = right + +def midRecusion(node): + if node is None: + return + midRecusion(node.left) + print(node.value, end=' ') + midRecusion(node.right) + +def midIterator(node): + stack = [] + while stack or node: + if node is not None: + stack.append(node) + node = node.left + else: + node = stack.pop(-1) + print(node.value, end=' ') + node = node.right + +if __name__ == "__main__": + node = Node("D", Node("B", Node("A"), Node("C")), Node("E", right=Node("G", left=Node("F")))) + + print('\n中序遍历<递归>:') + midRecusion(node) + + print('\n中序遍历<迭代>:') + midIterator(node) \ No newline at end of file diff --git a/src/py3.x/list2iteration.py b/src/py3.x/list2iteration.py new file mode 100644 index 000000000..a4a333f7d --- /dev/null +++ b/src/py3.x/list2iteration.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +# coding:utf8 +''' +迭代使用的是循环结构。 +递归使用的是选择结构。 +''' +from __future__ import print_function + +# 递归求解 +def calculate(l): + if len(l) <= 1: + return l[0] + value = calculate(l[1:]) + return 10**(len(l) - 1) * l[0] + value + + +# 迭代求解 +def calculate2(l): + result = 0 + while len(l) >= 1: + result += 10 ** (len(l)-1) * l[0] + l = l[1:] + return result + + +l1 = [1, 2, 3] +l2 = [4, 5] +sum = 0 +result = calculate(l1) + calculate(l2) +# result = calculate2(l1) + calculate2(l2) +print(result) diff --git a/src/py3.x/sort/BubbleSort.py b/src/py3.x/sort/BubbleSort.py new file mode 100644 index 000000000..e3aeba83d --- /dev/null +++ b/src/py3.x/sort/BubbleSort.py @@ -0,0 +1,20 @@ +# coding:utf-8 + + +# 冒泡排序 +# 1. 外层循环负责帮忙递减内存循环的次数【len-1, 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 100644 index 000000000..2c49a75b2 --- /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/sort/MergeSort.py b/src/py3.x/sort/MergeSort.py new file mode 100644 index 000000000..44de67ad2 --- /dev/null +++ b/src/py3.x/sort/MergeSort.py @@ -0,0 +1,35 @@ +# coding: utf-8 + + +def MergeSort(nums): + if len(nums) <= 1: + return nums + num = int(len(nums)/2) + # 从中间,进行数据的拆分, 递归的返回数据进行迭代排序 + left = MergeSort(nums[:num]) + right = MergeSort(nums[num:]) + print("left: ", left) + print("right: ", right) + print("-" * 20) + return Merge(left, right) + + +def Merge(left, right): + l, r = 0, 0 + result = [] + while l < len(left) and r < len(right): + if left[l] < right[r]: + result.append(left[l]) + l += 1 + else: + result.append(right[r]) + r += 1 + result += left[l:] + result += right[r:] + return result + + +if __name__ == "__main__": + nums = [2, 6, 8, 5, 1, 4, 9, 3, 7] + nums = MergeSort(nums) + print('result:', nums) diff --git a/src/py3.x/sort/QuickSort.py b/src/py3.x/sort/QuickSort.py new file mode 100644 index 000000000..f8753b443 --- /dev/null +++ b/src/py3.x/sort/QuickSort.py @@ -0,0 +1,35 @@ +#!/usr/bin/python +# coding:utf8 + + +def quick_sort(nums, start, end): + i = start + j = end + # 结束排序 + if i >= j: + return + # 保存首个数值 + key = nums[i] + # 一次排序,i和j的值不断的靠拢,然后最终停止,结束一次排序 + while i < j: + # 和最右边的比较,如果>=key,然后j-1,慢慢的和前一个值比较;如果值<key,那么就交换位置 + while i < j and key <= nums[j]: + print(key, nums[j], '*' * 30) + j -= 1 + nums[i] = nums[j] + # 交换位置后,然后在和最左边的值开始比较,如果<=key,然后i+1,慢慢的和后一个值比较;如果值>key,那么就交换位置 + while i < j and key >= nums[i]: + print(key, nums[i], '*' * 30) + i += 1 + nums[j] = nums[i] + nums[i] = key + # 左边排序 + quick_sort(nums, start, i-1) + # 右边排序 + quick_sort(nums, i+1, end) + + +if __name__ == "__main__": + 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/sort/RadixSort.py b/src/py3.x/sort/RadixSort.py new file mode 100644 index 000000000..e5fc2aba3 --- /dev/null +++ b/src/py3.x/sort/RadixSort.py @@ -0,0 +1,46 @@ +#************************基数排序**************************** +#确定排序的次数 +#排序的顺序跟序列中最大数的位数相关 +def radix_sort_nums(L): + maxNum = L[0] +#寻找序列中的最大数 + for x in L: + if maxNum < x: + maxNum = x +#确定序列中的最大元素的位数 + times = 0 + while (maxNum > 0): + maxNum = int((maxNum/10)) + times += 1 + return times +#找到num从低到高第pos位的数据 +def get_num_pos(num, pos): + return (int((num/(10**(pos-1))))) % 10 +#基数排序 +def radix_sort(L): + count = 10 * [None] #存放各个桶的数据统计个数 + bucket = len(L) * [None] #暂时存放排序结果 +#从低位到高位依次执行循环 + for pos in range(1, radix_sort_nums(L)+1): + #置空各个桶的数据统计 + for x in range(0, 10): + count[x] = 0 + #统计当前该位(个位,十位,百位....)的元素数目 + for x in range(0, len(L)): + #统计各个桶将要装进去的元素个数 + j = get_num_pos(int(L[x]), pos) + count[j] += 1 + #count[i]表示第i个桶的右边界索引 + for x in range(1,10): + count[x] += count[x-1] + #将数据依次装入桶中 + for x in range(len(L)-1, -1, -1): + #求出元素第K位的数字 + j = get_num_pos(L[x], pos) + #放入对应的桶中,count[j]-1是第j个桶的右边界索引 + bucket[count[j]-1] = L[x] + #对应桶的装入数据索引-1 + count[j] -= 1 + # 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表 + for x in range(0, len(L)): + L[x] = bucket[x] diff --git a/src/py3.x/sort/SelectionSort.py b/src/py3.x/sort/SelectionSort.py new file mode 100644 index 000000000..a52a8ef47 --- /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/sort/ShellSort.py b/src/py3.x/sort/ShellSort.py new file mode 100644 index 000000000..5cd764ec7 --- /dev/null +++ b/src/py3.x/sort/ShellSort.py @@ -0,0 +1,26 @@ +# coding: utf8 + +from __future__ import print_function +def insert_sort(l, start, increment): + for i in range(start+increment, len(l), increment): + for j in range(start, len(l[:i]), increment): + if l[i] < l[j]: + l[i], l[j] = l[j], l[i] + print(increment, '--',l) + return l + +def shell_sort(l, increment): + # 依次进行分层 + while increment: + # 每一层,都进行n次插入排序 + for i in range(0, increment): + insert_sort(l, i, increment) + increment -= 1 + return l + +if __name__ == "__main__": + l = [5, 2, 9, 8, 1, 10, 3, 4, 7] + increment = len(l)/3+1 if len(l)%3 else len(l)/3 + print("开始", l) + l = shell_sort(l, increment) + print("结束", l) \ No newline at end of file diff --git a/src/qqchangE_problem.md b/src/qqchangE_problem.md new file mode 100644 index 000000000..0e3720024 --- /dev/null +++ b/src/qqchangE_problem.md @@ -0,0 +1,44 @@ +```python +def canPartition(nums): + def dfs(nums, target, num): + n = len(nums) + for i in range(n): + B = nums[:i] + nums[i + 1:] + if num + nums[i] == target: + return True + elif num + nums[i] < target: + if dfs(B, target, num + nums[i]): + return True + elif num == 0: # 有一个数比sum/2还大,直接返回False + return False + return False + + total = sum(nums) + + if total % 2 != 0: + return False + + target = total // 2 + + nums.sort(reverse=True) # 逆序排序,先从大的开始判断,速度会更快 + + res = dfs(nums, target, 0) + return res + + +print(canPartition([3, 3, 3, 4, 5])) +print(canPartition([1,1,2])) +print(canPartition([1,2,3,4])) +print(canPartition([2,3])) +print(canPartition([2,2,2,2,6])) +print(canPartition([1,2,2,2,2,7])) + + +output: +True +True +True +False +False +True +``` diff --git a/src/shopee.md b/src/shopee.md new file mode 100644 index 000000000..910dcc2fb --- /dev/null +++ b/src/shopee.md @@ -0,0 +1,71 @@ +```python +"""第一题千分位""" + +n = input()[::-1] +if not n or len(n) == 0: + print('') +else: + if n[-1] == '-': + n = n[:-1] + tmp = [] + for i in range(0, len(n), 3): + tmp.append(n[i:i+3]) + # print(tmp) + print('-'+','.join(i[::-1] for i in tmp[::-1])) + else: + tmp = [] + for i in range(0, len(n), 3): + tmp.append(n[i:i + 3]) + + print(','.join(i[::-1] for i in tmp[::-1])) + + + + +"""第二题通配符""" +p = input() +s = input() + + +def isMatch(s, p): + def helper(s, i, p, j): + if j == -1: + return i == -1 + if i == -1: + if p[j] == '*' or p[j] == '#': + return helper(s, i, p, j - 1) + return False + if p[j] == '*': + return helper(s, i - 1, p, j) or helper(s, i, p, j-1) + if p[j] == '#': + return helper(s, i - 1, p, j-1) or helper(s, i, p, j - 1) + 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) +# print(1 if isMatch(s, p) else 0) + + +tmp = [['a?c', 'abc'], ['a?c', 'ac'], ['a#c', 'ac'], ['a#c', 'abc'], ['a#c', 'abbc'], ['a*c', 'ac'], + ['a*c', 'abc'], ['a*c', 'abbc'], ['a*c', 'abd'], ['a?c#e*f', 'abcdef'], ['a?c#e*f', 'acdef']] +# for i in tmp: +# p, s = i[0], i[1] +# print(1 if isMatch(s, p) else 0) + +print(1 if isMatch(s, p) else 0) +""" +输出应该为: +1 +0 +1 +1 +0 +1 +1 +1 +0 +1 +0 +""" +``` diff --git a/src/sohuchangyouweipinhui.md b/src/sohuchangyouweipinhui.md new file mode 100644 index 000000000..6202842c9 --- /dev/null +++ b/src/sohuchangyouweipinhui.md @@ -0,0 +1,23 @@ +```python +"""搜狐畅游第一题""" +nums = [int(i) for i in input().split()] +print(int(sum(nums) - (len(nums)-1)*(len(nums)-2)/2)) + + +"""唯品会第一题""" +import heapq +[k, n] = [int(i) for i in input().split()] +topk = [] +for i in range(n): + nums = [int(i) for i in input().split()] + for num in nums: + heapq.heappush(topk, num) +res = 0 +for i in range(k): + res = heapq.heappop(topk) +print(res) + + +"""唯品会第二题""" +print(bin(sum([int(i, 2) for i in input().split()]))[2:]) +``` diff --git a/src/tecent.md b/src/tecent.md new file mode 100644 index 000000000..937e80253 --- /dev/null +++ b/src/tecent.md @@ -0,0 +1,118 @@ +```python + + + +# k = int(input()) +# a = input() +# b = input() +# set_a = set() +# for i in range(0, len(a)-k+1): +# set_a.add(a[i:i+k]) +# res = 0 +# for i in range(0, len(b)-k+1): +# if b[i:i+k] in set_a: +# res += 1 +# print(res) +""" +2 +abab +ababab +""" + +""" +7 14 +""" + +from math import sqrt +nums = [int(i) for i in input().split()] +x, y = nums[0], nums[1] + +# n = 1 +# while (n+1)*n/2 != sum(nums): +# n += 1 + +n = int((sqrt(8*sum(nums)+1)-1)/2) + +permu = [i+1 for i in range(n)] + +res = [] +def exist(permu, x, path): + if not permu and x != 0: + return (False, -1) + + if x == 0 or x in permu: + res.append(path+1) + return (True, path + 1) + if exist(permu[1:], x-permu[0], path+1)[0]: + res.append(exist(permu[1:], x-permu[0], path+1)[1]) + return (True, exist(permu[1:], x-permu[0], path+1)[1]) + if exist(permu[1:], x, path+1)[0]: + res.append(exist(permu[1:], x, path+1)[1]) + return (True, exist(permu[1:], x, path+1)[1]) + +exist(permu, x, 0) +print(res) +print(min(res) if res else -1) + +""" +2 3 3 +""" +# res = 0 +# def tri(a, b, c): +# if a + b > c and a + c > b and b + c > a: +# return True +# return False +# +# nums = [int(i) for i in input().split()] +# res = 0 +# for i in range(1, nums[0]+1): +# for j in range(i+1, nums[1]+1): +# for k in range(j, nums[2]+1): +# if tri(i, j, k): +# res += 3 +# +# print(res) +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# from math import sqrt +# nums = [int(i) for i in input().split()] +# x, y = nums[0], nums[1] +# +# n = 1 +# while (n+1)*n/2 != sum(nums): +# n += 1 +# +# n = int((sqrt(8*sum(nums)+1)-1)/2) +# +# permu = [i+1 for i in range(n)] +# res = 0 +# while x > 0: +# x -= permu[-1] +# permu = permu[:-1] +# res += 1 +# print(res) +``` diff --git a/src/times.md b/src/times.md new file mode 100644 index 000000000..3c7b2b0de --- /dev/null +++ b/src/times.md @@ -0,0 +1,6 @@ +http://bigocheatsheet.com/ + + +https://algs4.cs.princeton.edu/cheatsheet/ + +https://wiki.python.org/moin/TimeComplexity diff --git a/src/vmware.md b/src/vmware.md new file mode 100644 index 000000000..8d8e1f6eb --- /dev/null +++ b/src/vmware.md @@ -0,0 +1,67 @@ +```python +"""第一题: 线段数和三角形数""" +n = int(input()) + +if n == 1: + print(0, 0) +elif n == 2: + print(1, 0) +elif n == 3: + print(3, 1) +else: + # print(int(6+(n-4)/2*(2+(n-4)*2)), int(6+(n-4)/2*(2+(n-4)*2))-2) + print((n-3)*3+3, (n-3)*3+1) + + + +"""第二题:最小交换次数""" +n = int(input()) +tmp = input().split() +nums = [int(i) for i in tmp] +length = len(nums) +def sort1(nums): + res = 0 + for i in range(length): + swapped = False + for j in range(length-1): + if nums[j] > nums[j+1]: + swapped = True + nums[j], nums[j+1] = nums[j+1], nums[j] + res += 1 + if not swapped: + break + return res +def sort2(nums): + res = 0 + for i in range(length): + swapped = False + for j in range(length-1): + if nums[j] < nums[j+1]: + swapped = True + nums[j], nums[j+1] = nums[j+1], nums[j] + res += 1 + if not swapped: + break + return res + +print(min(sort1(nums), sort2(nums))) + + + + +"""第三题: 搬家""" +tmp = input().split() +N, W = int(tmp[0]), int(tmp[1]) +sums = 0 +for i in range(N): + sums += int(input()) +if sums == 0: + print(0) +else: + if sums <= W: + print(1) + elif sums == N * W: + print(N) + else: + print(sums//W + 1) +``` diff --git a/src/wangyihuyudierti.java b/src/wangyihuyudierti.java new file mode 100644 index 000000000..71d5c0167 --- /dev/null +++ b/src/wangyihuyudierti.java @@ -0,0 +1,71 @@ +import java.util.*; + +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + int n = sc.nextInt(); + + for (int i=0; i<=n; i++){ + String s = sc.nextLine(); + // System.out.println(s); + String[] xynum = s.split(" "); + // System.out.println(xynum[0]); + int x, y; + try{ + x = Integer.parseInt(xynum[0]); + }catch(NumberFormatException ex){ // handle your exception + continue; + } + try{ + y = Integer.valueOf(xynum[1]); + }catch(NumberFormatException ex){ // handle your exception + continue; + } + // System.out.println((Helper(xynum[2].substring(0,2),x))); + for (int j=1; j<xynum[2].length(); j++){ + if (Helper(xynum[2].substring(0,j),x) == Helper(xynum[2].substring(j,xynum[2].length()),y)){ + System.out.println(Helper(xynum[2].substring(0,j),x)); + } + } + + // System.out.println(Helper("111", 2)); + + // System.out.println(s); + // System.out.println(res); + } + } + + private static int Helper(String s, int k) { + int res = 0; + for (int i=s.length()-1;i>=0;i--){ + char chr = s.charAt(i); + int tmp; + if (chr == 'A') { + tmp = 10; + }else if(chr == 'B') { + tmp = 11; + }else if(chr == 'C') { + tmp = 12; + }else if(chr == 'D') { + tmp = 13; + }else if(chr == 'E') { + tmp = 14; + }else if(chr == 'F') { + tmp = 15; + } + else{ + tmp = Integer.parseInt(Character.toString(chr)); + } + + // System.out.println("tmp"+tmp); + res += tmp * Math.pow(k, s.length()-1-i); + // System.out.println("res"+res); + } + return res; + } +} +/* +1 +ABCDE + */ diff --git a/src/xunlei.md b/src/xunlei.md new file mode 100644 index 000000000..635826301 --- /dev/null +++ b/src/xunlei.md @@ -0,0 +1,49 @@ +```python +"""第一题""" +N = int(input()) + + +def gcd(big, small): + if big < small: + small, big = big, small + remainder = big % small + if remainder == 0: + return small + else: + return gcd(small,remainder) + +res = 0 +from math import sqrt +for c in range(1, N+1): + for a in range(1, c): + for b in range(max(c-a+1,a), c): + if a * a + b * b == c * c: + if gcd(a, b) == 1 and gcd(b, c) == 1 and gcd(a, c) == 1: + res += 1 + # print(a,b,c) + +print(res) + + +"""第二题""" +tmp = input().split() +positive, negative = int(tmp[0]), int(tmp[1]) +# print(positive, negative) + +idx = 0 +for i in range(6, -1, -1): + if i*positive+(7-i)*negative < 0: + idx = i + break +# print(idx) + + +res = (negative*(7-idx)+positive*idx) * 2 +# print(res) +if idx >= 3: + res += 3 * positive +else: + res += idx * positive + (3 - idx) * negative + +print(res) +``` diff --git a/src/zhaoyincreditcard.md b/src/zhaoyincreditcard.md new file mode 100644 index 000000000..c627baff9 --- /dev/null +++ b/src/zhaoyincreditcard.md @@ -0,0 +1,57 @@ +```python +"""第一题""" +gi = [int(i) for i in input().split()] +sj = [int(i) for i in input().split()] +res = 0 +for i in sj: + tmp = [j for j in gi if j <= i] + if tmp: + res += 1 + gi.remove(max(tmp)) +print(res) + + +"""第二题""" +n = int(input()) +if n == 1: + print(1) +elif n == 2: + print(2) +else: + dp = [0] * n + dp[0] = 1 + dp[1] = 2 + for i in range(2, n): + dp[i] = dp[i-1] + dp[i-2] + print(dp[-1]) + + +"""第三题""" +invalid = ['3', '4', '7'] +nochange = ['0', '1', '8'] +def good(n): + n = str(n) + for i in invalid: + if i in n: + return False + res = '' + for i in n: + if i in nochange: + res += i + if i == '2': + res += '5' + elif i == '5': + res += '2' + elif i == '6': + res += '9' + elif i == '9': + res += '6' + return res != n + +n = int(input()) +res = 0 +for i in range(n+1): + if good(i): + res += 1 +print(res) +``` diff --git a/src/zhaoyinwangluokeji.java b/src/zhaoyinwangluokeji.java new file mode 100644 index 000000000..0840da3c0 --- /dev/null +++ b/src/zhaoyinwangluokeji.java @@ -0,0 +1,42 @@ +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + int n = sc.nextInt(); + + Helper(n); + } + + private static void Helper(int n) { + int count = 90; + int start = 1; + String res = ""; + // System.out.print((count * 1.0 - (count-1)*count/2.0)/count); + while ((count * 1.0 - (count-1)*count/2.0)/count < start*1.0){ + for (int i = 0; i <= n / count; i++) { + if (count * i + (count-1) * count /2.0 == n) { + System.out.print("["); + res += "["; + for (int j =i; j <= i+count-1; j++){ + if (j==i+count-1){ + System.out.println(j+"]"); + res += Integer.toString(j) + "]"; + break; + } + System.out.print(j+", "); + res += Integer.toString(j) + ", "; + + } + // System.out.print("]"); + // System.out.println(""); + } + } + count -= 1; + } + res = new StringBuffer(res).reverse().toString(); + // System.out.print(res); + + } +} diff --git a/update.sh b/update.sh deleted file mode 100644 index f76166c4e..000000000 --- a/update.sh +++ /dev/null @@ -1,3 +0,0 @@ -git add -A -git commit -am "$(date "+%Y-%m-%d %H:%M:%S")" -git push \ No newline at end of file