<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: fengmao</title>
    <description>The latest articles on DEV Community by fengmao (@fengmao).</description>
    <link>https://dev.to/fengmao</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F97350%2F14bfbe76-6504-4128-a209-b2feb4bbc024.png</url>
      <title>DEV Community: fengmao</title>
      <link>https://dev.to/fengmao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fengmao"/>
    <language>en</language>
    <item>
      <title>史上最全的文档地址列表</title>
      <dc:creator>fengmao</dc:creator>
      <pubDate>Sun, 22 May 2022 08:42:00 +0000</pubDate>
      <link>https://dev.to/fengmao/shi-shang-zui-quan-de-wen-dang-di-zhi-lie-biao-554d</link>
      <guid>https://dev.to/fengmao/shi-shang-zui-quan-de-wen-dang-di-zhi-lie-biao-554d</guid>
      <description>&lt;p&gt;周末花了两天时间收集了几百个网站的文档地址，类型从前端到后端全部覆盖了，还有一些热门的技术，也添加进来了，这里分享给大家，统一的入口地址在&lt;a href="https://adochub.com"&gt;adochub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docker.adochub.com/"&gt;docker&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nginx.adochub.com/"&gt;nginx&lt;/a&gt;&lt;br&gt;
&lt;a href="https://python3.adochub.com/"&gt;python3&lt;/a&gt;&lt;br&gt;
&lt;a href="https://meteor.adochub.com/"&gt;meteor&lt;/a&gt;&lt;br&gt;
&lt;a href="https://prisma.adochub.com/"&gt;prisma&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vuejs.adochub.com/"&gt;vuejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://anaconda.adochub.com/"&gt;anaconda&lt;/a&gt;&lt;br&gt;
&lt;a href="https://caddyserver.adochub.com/"&gt;caddy server&lt;/a&gt;&lt;br&gt;
&lt;a href="https://divio.adochub.com/"&gt;divio&lt;/a&gt;&lt;br&gt;
&lt;a href="https://aws.adochub.com/"&gt;aws&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mongoosejs.adochub.com/"&gt;mongoosejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tidb.adochub.com/"&gt;tidb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flutter.adochub.com/"&gt;flutter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gitlab.adochub.com/"&gt;gitlab&lt;/a&gt;&lt;br&gt;
&lt;a href="https://threejs.adochub.com/"&gt;threejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://microsoft.adochub.com/"&gt;microsoft&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pytorch.adochub.com/"&gt;pytorch&lt;/a&gt;&lt;br&gt;
&lt;a href="https://moodle.adochub.com/"&gt;moodle&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kubernetes.adochub.com/"&gt;kubernetes&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.adochub.com/"&gt;github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://android.adochub.com/"&gt;android&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nodejs.adochub.com/"&gt;nodejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cyberark.adochub.com/"&gt;cyberark&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.adochub.com/"&gt;twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://zoho.adochub.com/"&gt;zoho&lt;/a&gt;&lt;br&gt;
&lt;a href="https://angular.adochub.com/"&gt;angular&lt;/a&gt;&lt;br&gt;
&lt;a href="https://newrelic.adochub.com/"&gt;newrelic&lt;/a&gt;&lt;br&gt;
&lt;a href="https://php.adochub.com/"&gt;php&lt;/a&gt;&lt;br&gt;
&lt;a href="https://npmjs.adochub.com/"&gt;npmjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://reactjs.adochub.com/"&gt;reactjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nestjs.adochub.com/"&gt;nestjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mongodb.adochub.com/"&gt;mongodb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pulsar.adochub.com/"&gt;pulsar&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mozilla.adochub.com/"&gt;mozilla&lt;/a&gt;&lt;br&gt;
&lt;a href="https://travis-ci.adochub.com/"&gt;travis-ci&lt;/a&gt;&lt;br&gt;
&lt;a href="https://solana.adochub.com/"&gt;solana&lt;/a&gt;&lt;br&gt;
&lt;a href="https://openstack.adochub.com/"&gt;openstack&lt;/a&gt;&lt;br&gt;
&lt;a href="https://laravel.adochub.com/"&gt;laravel&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stripe.com/docs"&gt;stripe&lt;/a&gt;&lt;br&gt;
&lt;a href="https://reactnative.adochub.com/"&gt;react native&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ansible.adochub.com/"&gt;ansible&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cypress.adochub.com/"&gt;cypress&lt;/a&gt;&lt;br&gt;
&lt;a href="https://djangoproject.adochub.com/"&gt;django project&lt;/a&gt;&lt;br&gt;
&lt;a href="https://auth0.adochub.com/"&gt;auth0&lt;/a&gt;&lt;br&gt;
&lt;a href="https://godotengine.adochub.com/"&gt;godotengine&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apollographql.adochub.com/"&gt;apollo graphql&lt;/a&gt;&lt;br&gt;
&lt;a href="https://getbootstrap.adochub.com/"&gt;getbootstrap&lt;/a&gt;&lt;br&gt;
&lt;a href="https://readthedocs.adochub.com/"&gt;readthedocs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://oracle.adochub.com/"&gt;oracle&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tailwindcss.adochub.com/"&gt;tailwindcss&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ubuntu.adochub.com/"&gt;ubuntu&lt;/a&gt;&lt;br&gt;
&lt;a href="https://netlify.adochub.com/"&gt;netlify&lt;/a&gt;&lt;br&gt;
&lt;a href="https://amplify.adochub.com/"&gt;amplify&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vaultproject.adochub.com/"&gt;vault project&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kotlinlang.adochub.com/"&gt;kotlin lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://momentjs.adochub.com/"&gt;momentjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://developers.cloudflare.com/docs"&gt;cloudflare&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sublimetext.adochub.com/"&gt;sublimetext&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nvidia.adochub.com/"&gt;nvidia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://prettier.adochub.com/"&gt;prettier&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pandas.adochub.com/"&gt;pandas&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pythonguide.adochub.com/"&gt;python guide&lt;/a&gt;&lt;br&gt;
&lt;a href="https://yarn.adochub.com/"&gt;yarn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://fasttext.adochub.com/"&gt;fasttext&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rancher.adochub.com/"&gt;rancher&lt;/a&gt;&lt;br&gt;
&lt;a href="https://postgresql.adochub.com/"&gt;postgresql&lt;/a&gt;&lt;br&gt;
&lt;a href="https://remix.adochub.com/"&gt;remix&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachehttpd.adochub.com/"&gt;apache httpd&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pig.adochub.com/"&gt;pig&lt;/a&gt;&lt;br&gt;
&lt;a href="https://async.adochub.com/"&gt;async&lt;/a&gt;&lt;br&gt;
&lt;a href="https://babeljs.adochub.com/"&gt;babeljs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://backbonejs.adochub.com/"&gt;backbonejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bash.adochub.com/"&gt;bash&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bluebirdjs.adochub.com/"&gt;bluebirdjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bottlepy.adochub.com/"&gt;bottlepy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bower.adochub.com/"&gt;bower&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cplusplus.adochub.com/"&gt;cplusplus&lt;/a&gt;&lt;br&gt;
&lt;a href="https://clanguage.adochub.com/"&gt;c language&lt;/a&gt;&lt;br&gt;
&lt;a href="https://wikipedia.adochub.com/"&gt;wikipedia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cakephp.adochub.com/"&gt;cakephp&lt;/a&gt;&lt;br&gt;
&lt;a href="https://chaijs.adochub.com/"&gt;chaijs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://chef.adochub.com/"&gt;chef&lt;/a&gt;&lt;br&gt;
&lt;a href="https://clojure.adochub.com/"&gt;clojure&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cmake.adochub.com/"&gt;cmake&lt;/a&gt;&lt;br&gt;
&lt;a href="https://codeception.adochub.com/"&gt;codeception&lt;/a&gt;&lt;br&gt;
&lt;a href="https://codecept.adochub.com/"&gt;codecept&lt;/a&gt;&lt;br&gt;
&lt;a href="https://codeigniter4.adochub.com/"&gt;codeigniter4&lt;/a&gt;&lt;br&gt;
&lt;a href="https://coffeescript.adochub.com/"&gt;coffeescript&lt;/a&gt;&lt;br&gt;
&lt;a href="https://composer.adochub.com/"&gt;composer&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cordova.adochub.com/"&gt;cordova&lt;/a&gt;&lt;br&gt;
&lt;a href="https://crystallang.adochub.com/"&gt;crystal lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dlang.adochub.com/"&gt;d lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://d3js.adochub.com/"&gt;d3js&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dartlang.adochub.com/"&gt;dart lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://deno.adochub.com/"&gt;deno&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dojo.adochub.com/"&gt;dojo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://drupal.adochub.com/"&gt;drupal&lt;/a&gt;&lt;br&gt;
&lt;a href="https://electronjs.adochub.com/"&gt;electronjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://emacs.adochub.com/"&gt;emacs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://elixirlang.adochub.com/"&gt;elixir lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://emberjs.adochub.com/"&gt;emberjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://enzymejs.adochub.com/"&gt;enzymejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://erlang.adochub.com/"&gt;erlang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://esbuild.adochub.com/"&gt;esbuild&lt;/a&gt;&lt;br&gt;
&lt;a href="https://eslint.adochub.com/"&gt;eslint&lt;/a&gt;&lt;br&gt;
&lt;a href="https://expressjs.adochub.com/"&gt;expressjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://eggjs.adochub.com/"&gt;eggjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://falcon.adochub.com/"&gt;falcon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://fishshell.adochub.com/"&gt;fishshell&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flask.adochub.com/"&gt;flask&lt;/a&gt;&lt;br&gt;
&lt;a href="https://algolia.adochub.com/"&gt;algolia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flow.adochub.com/"&gt;flow&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gcc.adochub.com/"&gt;gcc&lt;/a&gt;&lt;br&gt;
&lt;a href="https://git.adochub.com/"&gt;git&lt;/a&gt;&lt;br&gt;
&lt;a href="https://fortrancompiler.adochub.com/"&gt;fortran compiler&lt;/a&gt;&lt;br&gt;
&lt;a href="https://make.adochub.com/"&gt;make&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cobol.adochub.com/"&gt;cobol&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gnuplot.adochub.com/"&gt;gnuplot&lt;/a&gt;&lt;br&gt;
&lt;a href="https://golang.adochub.com/"&gt;go lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://graphite.adochub.com/"&gt;graphite&lt;/a&gt;&lt;br&gt;
&lt;a href="https://groovylang.adochub.com/"&gt;groovy lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gruntjs.adochub.com/"&gt;gruntjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gtk4.adochub.com/"&gt;gtk4&lt;/a&gt;&lt;br&gt;
&lt;a href="https://handlebarsjs.adochub.com/"&gt;handlebarsjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://haproxy.adochub.com/"&gt;haproxy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://haskell.adochub.com/"&gt;haskell&lt;/a&gt;&lt;br&gt;
&lt;a href="https://haxe.adochub.com/"&gt;haxe&lt;/a&gt;&lt;br&gt;
&lt;a href="https://homebrew.adochub.com/"&gt;homebrew&lt;/a&gt;&lt;br&gt;
&lt;a href="https://i3.adochub.com/"&gt;i3&lt;/a&gt;&lt;br&gt;
&lt;a href="https://immutablejs.adochub.com/"&gt;immutablejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://influxdata.adochub.com/"&gt;influxdata&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jasmine.adochub.com/"&gt;jasmine&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jekyll.adochub.com/"&gt;jekyll&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jestjs.adochub.com/"&gt;jestjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jinja.adochub.com/"&gt;jinja&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jquery.adochub.com/"&gt;jquery&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jqueryui.adochub.com/"&gt;jquery ui&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jsdoc.adochub.com/"&gt;jsdoc&lt;/a&gt;&lt;br&gt;
&lt;a href="https://julialang.adochub.com/"&gt;julia lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://knockoutjs.adochub.com/"&gt;knockoutjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://koajs.adochub.com/"&gt;koajs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://latexproject.adochub.com/"&gt;latex project&lt;/a&gt;&lt;br&gt;
&lt;a href="https://leafletjs.adochub.com/"&gt;leafletjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://lesscss.adochub.com/"&gt;less css&lt;/a&gt;&lt;br&gt;
&lt;a href="https://liquid.adochub.com/"&gt;liquid&lt;/a&gt;&lt;br&gt;
&lt;a href="https://lodash.adochub.com/"&gt;lodash&lt;/a&gt;&lt;br&gt;
&lt;a href="https://lualang.adochub.com/"&gt;lua lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://love.adochub.com/"&gt;love&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mariadb.adochub.com/"&gt;mariadb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://marionettejs.adochub.com/"&gt;marionettejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://markdown.adochub.com/"&gt;markdown&lt;/a&gt;&lt;br&gt;
&lt;a href="https://matplotlib.adochub.com/"&gt;matplotlib&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mochajs.adochub.com/"&gt;mochajs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://modernizr.adochub.com/"&gt;modernizr&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mimlang.adochub.com/"&gt;mim lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nokogiri.adochub.com/"&gt;nokogiri&lt;/a&gt;&lt;br&gt;
&lt;a href="https://numpy.adochub.com/"&gt;numpy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ocamllang.adochub.com/"&gt;ocaml lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://octave.adochub.com/"&gt;octave&lt;/a&gt;&lt;br&gt;
&lt;a href="https://openjdk.adochub.com/"&gt;openjdk&lt;/a&gt;&lt;br&gt;
&lt;a href="https://opentsdb.adochub.com/"&gt;opentsdb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://padrinorb.adochub.com/"&gt;padrinorb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://perllang.adochub.com/"&gt;perl lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://phalcon.adochub.com/"&gt;phalcon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://phaser.adochub.com/"&gt;phaser&lt;/a&gt;&lt;br&gt;
&lt;a href="https://phoenix.adochub.com/"&gt;phoenix&lt;/a&gt;&lt;br&gt;
&lt;a href="https://phpunit.adochub.com/"&gt;phpunit&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pugjs.adochub.com/"&gt;pugjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://puppeteer.adochub.com/"&gt;puppeteer&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pygame.adochub.com/"&gt;pygame&lt;/a&gt;&lt;br&gt;
&lt;a href="https://angularjs.adochub.com/"&gt;angularjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://qt.adochub.com/"&gt;qt&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rlang.adochub.com/"&gt;r lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ramdajs.adochub.com/"&gt;ramdajs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://react-bootstrap.adochub.com/"&gt;react-bootstrap&lt;/a&gt;&lt;br&gt;
&lt;a href="https://reactrouter.adochub.com/"&gt;react router&lt;/a&gt;&lt;br&gt;
&lt;a href="https://reactivex.adochub.com/"&gt;reactivex&lt;/a&gt;&lt;br&gt;
&lt;a href="https://redis.adochub.com/"&gt;redis&lt;/a&gt;&lt;br&gt;
&lt;a href="https://redux.adochub.com/"&gt;redux&lt;/a&gt;&lt;br&gt;
&lt;a href="https://relay.adochub.com/"&gt;relay&lt;/a&gt;&lt;br&gt;
&lt;a href="https://requirejs.adochub.com/"&gt;requirejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rethinkdb.adochub.com/"&gt;rethinkdb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rubylang.adochub.com/"&gt;ruby lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rubyonrails.adochub.com/"&gt;rubyonrails&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rustlang.adochub.com/"&gt;rust lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rxjs.adochub.com/"&gt;rxjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://saltproject.adochub.com/"&gt;saltproject&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sasslang.adochub.com/"&gt;sass lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://scalalang.adochub.com/"&gt;scala lang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://scikitimage.adochub.com/"&gt;scikit image&lt;/a&gt;&lt;br&gt;
&lt;a href="https://scikitlearn.adochub.com/"&gt;scikit learn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sequelize.adochub.com/"&gt;sequelize&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sinonjs.adochub.com/"&gt;sinonjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://socketio.adochub.com/"&gt;socket.io&lt;/a&gt;&lt;br&gt;
&lt;a href="https://spring-boot.adochub.com/"&gt;spring-boot&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sqlite.adochub.com/"&gt;sqlite&lt;/a&gt;&lt;br&gt;
&lt;a href="https://statsmodels.adochub.com/"&gt;statsmodels&lt;/a&gt;&lt;br&gt;
&lt;a href="https://symfony.adochub.com/"&gt;symfony&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tcltk.adochub.com/"&gt;tcl.tk&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tensorflow.adochub.com/"&gt;tensorflow&lt;/a&gt;&lt;br&gt;
&lt;a href="https://terraform.adochub.com/"&gt;terraform&lt;/a&gt;&lt;br&gt;
&lt;a href="https://trio.adochub.com/"&gt;trio&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twig.adochub.com/"&gt;twig&lt;/a&gt;&lt;br&gt;
&lt;a href="https://typescriptlang.adochub.com/"&gt;typescriptlang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://underscorejs.adochub.com/"&gt;underscorejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vagrant.adochub.com/"&gt;vagrant&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vitejs.adochub.com/"&gt;vitejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vuerouter.adochub.com/"&gt;vue router&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vuex.adochub.com/"&gt;vuex&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vulkan.adochub.com/"&gt;vulkan&lt;/a&gt;&lt;br&gt;
&lt;a href="https://webpack.adochub.com/"&gt;webpack&lt;/a&gt;&lt;br&gt;
&lt;a href="https://werkzeug.adochub.com/"&gt;werkzeug&lt;/a&gt;&lt;br&gt;
&lt;a href="https://wordpress.adochub.com/"&gt;wordpress&lt;/a&gt;&lt;br&gt;
&lt;a href="https://yiiframework.adochub.com/"&gt;yiiframework&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ziglang.adochub.com/"&gt;ziglang&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jqueryobile.adochub.com/"&gt;jquery mobile&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twilio.adochub.com/"&gt;twilio&lt;/a&gt;&lt;br&gt;
&lt;a href="https://paypal.adochub.com/"&gt;paypal&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apigee.adochub.com/"&gt;apigee&lt;/a&gt;&lt;br&gt;
&lt;a href="https://googleevelopers.adochub.com/"&gt;google developers&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nunjucks.adochub.com/"&gt;nunjucks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://unity3d.adochub.com/"&gt;unity3d&lt;/a&gt;&lt;br&gt;
&lt;a href="https://attic.adochub.com/"&gt;attic&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dbeaver.adochub.com/"&gt;dbeaver&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mysql.adochub.com/"&gt;mysql&lt;/a&gt;&lt;br&gt;
&lt;a href="https://antdesign.adochub.com/"&gt;ant.design&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.adochub.com/"&gt;medium&lt;/a&gt;&lt;br&gt;
&lt;a href="https://Antesignfue.adochub.com/"&gt;Ant Design of Vue&lt;/a&gt;&lt;br&gt;
&lt;a href="https://Materialesign.adochub.com/"&gt;Material Design 3&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apisix.adochub.com/"&gt;apisix&lt;/a&gt;&lt;br&gt;
&lt;a href="https://w3schools.adochub.com/"&gt;w3schools&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheccumulo.adochub.com/"&gt;apache accumulo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachectivemq.adochub.com/"&gt;apache activemq&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheirflow.adochub.com/"&gt;apache airflow&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachellura.adochub.com/"&gt;apache allura&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheny23.adochub.com/"&gt;apache any23&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacherchiva.adochub.com/"&gt;apache archiva&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacherrow.adochub.com/"&gt;apache arrow&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachevro.adochub.com/"&gt;apache avro&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheval.adochub.com/"&gt;apache bval&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheahir.adochub.com/"&gt;apache bahir&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheeam.adochub.com/"&gt;apache beam&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheIGTOP.adochub.com/"&gt;apache BIGTOP&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheookkeeper.adochub.com/"&gt;apache bookkeeper&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacherooklyn.adochub.com/"&gt;apache brooklyn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheuildr.adochub.com/"&gt;apache buildr&lt;/a&gt;&lt;br&gt;
&lt;a href="https://firebase.adochub.com/"&gt;firebase&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachexf.adochub.com/"&gt;apache cxf&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachealcite.adochub.com/"&gt;apache calcite&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheamel.adochub.com/"&gt;apache camel&lt;/a&gt;&lt;br&gt;
&lt;a href="https://capacherbondata.adochub.com/"&gt;capache arbondata&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheassandra.adochub.com/"&gt;apache cassandra&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheayenne.adochub.com/"&gt;apache cayenne&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheelix.adochub.com/"&gt;apache celix&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachelerezza.adochub.com/"&gt;apache clerezza&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheloudstack.adochub.com/"&gt;apache cloudstack&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheocoon.adochub.com/"&gt;apache cocoon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheommons.adochub.com/"&gt;apache commons&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheouchdb.adochub.com/"&gt;apache couchdb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheurator.adochub.com/"&gt;apache curator&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachetakes.adochub.com/"&gt;apache ctakes&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheaffodil.adochub.com/"&gt;apache daffodil&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheatafu.adochub.com/"&gt;apache datafu&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheatasketches.adochub.com/"&gt;apache datasketches&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheeltaspike.adochub.com/"&gt;apache deltaspike&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheolphinscheduler.adochub.com/"&gt;apache dolphinscheduler&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacherill.adochub.com/"&gt;apache drill&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheruid.adochub.com/"&gt;apache druid&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheubbo.adochub.com/"&gt;apache dubbo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachecharts.adochub.com/"&gt;apache echarts&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachelex.adochub.com/"&gt;apache flex&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachelume.adochub.com/"&gt;apache flume&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheluo.adochub.com/"&gt;apache fluo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachereemarker.adochub.com/"&gt;apache freemarker&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheeode.adochub.com/"&gt;apache geode&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheiraph.adochub.com/"&gt;apache giraph&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheobblin.adochub.com/"&gt;apache gobblin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheriffin.adochub.com/"&gt;apache griffin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheuacamole.adochub.com/"&gt;apache guacamole&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheawq.adochub.com/"&gt;apache hawq&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachebase.adochub.com/"&gt;apache hbase&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheadoop.adochub.com/"&gt;apache hadoop&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheop.adochub.com/"&gt;apache hop&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ApachettpComponents.adochub.com/"&gt;Apache HttpComponents&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheudi.adochub.com/"&gt;apache hudi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheceberg.adochub.com/"&gt;apache iceberg&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachegnite.adochub.com/"&gt;apache ignite&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachempala.adochub.com/"&gt;apache impala&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheotdb.adochub.com/"&gt;apache iotdb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachesis.adochub.com/"&gt;apache isis&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachemeter.adochub.com/"&gt;apache jmeter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachespwiki.adochub.com/"&gt;apache jspwiki&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheackrabbit.adochub.com/"&gt;apache jackrabbit&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheames.adochub.com/"&gt;apache james&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheena.adochub.com/"&gt;apache jena&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheohnzon.adochub.com/"&gt;apache johnzon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nextjs.adochub.com/"&gt;nextjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheclouds.adochub.com/"&gt;apache jclouds&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ghost.adochub.com/"&gt;ghost&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheafka.adochub.com/"&gt;apache kafka&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachearaf.adochub.com/"&gt;apache karaf&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheibble.adochub.com/"&gt;apache kibble&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachenox.adochub.com/"&gt;apache knox&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheudu.adochub.com/"&gt;apache kudu&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheylin.adochub.com/"&gt;apache kylin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheibcloud.adochub.com/"&gt;apache libcloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheogging.adochub.com/"&gt;apache logging&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheucene.adochub.com/"&gt;apache lucene&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheina.adochub.com/"&gt;apache mina&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheaven.adochub.com/"&gt;apache maven&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheesos.adochub.com/"&gt;apache mesos&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachenemonic.adochub.com/"&gt;apache mnemonic&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheyfaces.adochub.com/"&gt;apache myfaces&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheetbeans.adochub.com/"&gt;apache netbeans&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheifi.adochub.com/"&gt;apache nifi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheutch.adochub.com/"&gt;apache nutch&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacherc.adochub.com/"&gt;apache orc&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachelingo.adochub.com/"&gt;apache olingo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheozie.adochub.com/"&gt;apache oozie&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachepennlp.adochub.com/"&gt;apache opennlp&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachepenwebbeans.adochub.com/"&gt;apache openwebbeans&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachezone.adochub.com/"&gt;apache ozone&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachedfbox.adochub.com/"&gt;apache pdfbox&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheoi.adochub.com/"&gt;apache poi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachearquet.adochub.com/"&gt;apache parquet&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheerl.adochub.com/"&gt;apache perl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachehoenix.adochub.com/"&gt;apache phoenix&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheig.adochub.com/"&gt;apache pig&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheinot.adochub.com/"&gt;apache pinot&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheivot.adochub.com/"&gt;apache pivot&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachepr.adochub.com/"&gt;apache apr&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheortals.adochub.com/"&gt;apache portals&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachepid.adochub.com/"&gt;apache qpid&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheeef.adochub.com/"&gt;apache reef&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheanger.adochub.com/"&gt;apache ranger&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheocketmq.adochub.com/"&gt;apache rocketmq&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheoyale.adochub.com/"&gt;apache royale&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheinga.adochub.com/"&gt;apache singa&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheis.adochub.com/"&gt;apache sis&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheamza.adochub.com/"&gt;apache samza&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheantuario.adochub.com/"&gt;apache santuario&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheervicecomb.adochub.com/"&gt;apache servicecomb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheervicemix.adochub.com/"&gt;apache servicemix&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachehiro.adochub.com/"&gt;apache shiro&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachekywalking.adochub.com/"&gt;apache skywalking&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheling.adochub.com/"&gt;apache sling&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheolr.adochub.com/"&gt;apache solr&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachepark.adochub.com/"&gt;apache spark&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachetorm.adochub.com/"&gt;apache storm&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachetreams.adochub.com/"&gt;apache streams&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachetruts.adochub.com/"&gt;apache struts&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheubmarine.adochub.com/"&gt;apache submarine&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheubversion.adochub.com/"&gt;apache subversion&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheuperset.adochub.com/"&gt;apache superset&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheynapse.adochub.com/"&gt;apache synapse&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheystemds.adochub.com/"&gt;apache systemds&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachevm.adochub.com/"&gt;apache tvm&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheapestry.adochub.com/"&gt;apache tapestry&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheez.adochub.com/"&gt;apache tez&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apachehrift.adochub.com/"&gt;apache thrift&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheika.adochub.com/"&gt;apache tika&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheomee.adochub.com/"&gt;apache tomee&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheomcat.adochub.com/"&gt;apache tomcat&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacherafficcontrol.adochub.com/"&gt;apache trafficcontrol&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacherafficserver.adochub.com/"&gt;apache trafficserver&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheima.adochub.com/"&gt;apache uima&lt;/a&gt;&lt;br&gt;
&lt;a href="https://unomi.adochub.com/"&gt;unomi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheelocity.adochub.com/"&gt;apache velocity&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheicket.adochub.com/"&gt;apache wicket&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheetus.adochub.com/"&gt;apache yetus&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheunikorn.adochub.com/"&gt;apache yunikorn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheeppelin.adochub.com/"&gt;apache zeppelin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apacheookeeper.adochub.com/"&gt;apache zookeeper&lt;/a&gt;&lt;br&gt;
&lt;a href="https://hexo.adochub.com/"&gt;hexo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://hugo.adochub.com/"&gt;hugo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://coredns.adochub.com/"&gt;coredns&lt;/a&gt;&lt;br&gt;
&lt;a href="https://envoyproxy.adochub.com/"&gt;envoyproxy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://etcd.adochub.com/"&gt;etcd&lt;/a&gt;&lt;br&gt;
&lt;a href="https://fluentd.adochub.com/"&gt;fluentd&lt;/a&gt;&lt;br&gt;
&lt;a href="https://harbor.adochub.com/"&gt;harbor&lt;/a&gt;&lt;br&gt;
&lt;a href="https://helm.adochub.com/"&gt;helm&lt;/a&gt;&lt;br&gt;
&lt;a href="https://linkerd.adochub.com/"&gt;linkerd&lt;/a&gt;&lt;br&gt;
&lt;a href="https://asterixdb.adochub.com/"&gt;asterixdb&lt;/a&gt;&lt;br&gt;
&lt;a href="https://atlas.adochub.com/"&gt;atlas&lt;/a&gt;&lt;br&gt;
&lt;a href="https://openpolicyagent.adochub.com/"&gt;openpolicyagent&lt;/a&gt;&lt;br&gt;
&lt;a href="https://prometheus.adochub.com/"&gt;prometheus&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rook.adochub.com/"&gt;rook&lt;/a&gt;&lt;br&gt;
&lt;a href="https://theupdateframework.adochub.com/"&gt;theupdateframework&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tikv.adochub.com/"&gt;tikv&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vitess.adochub.com/"&gt;vitess&lt;/a&gt;&lt;br&gt;
&lt;a href="https://backstage.adochub.com/"&gt;backstage&lt;/a&gt;&lt;br&gt;
&lt;a href="https://buildpacks.adochub.com/"&gt;buildpacks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://chaos-mesh.adochub.com/"&gt;chaos-mesh&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cilium.adochub.com/"&gt;cilium&lt;/a&gt;&lt;br&gt;
&lt;a href="https://Cloudativeetwork.adochub.com/"&gt;Cloud Native Network&lt;/a&gt;&lt;br&gt;
&lt;a href="https://contour.adochub.com/"&gt;contour&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cortexmetrics.adochub.com/"&gt;cortexmetrics&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cri-o.adochub.com/"&gt;cri-o&lt;/a&gt;&lt;br&gt;
&lt;a href="https://crossplane.adochub.com/"&gt;crossplane&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dapr.adochub.com/"&gt;dapr&lt;/a&gt;&lt;br&gt;
&lt;a href="https://Dragonfly.adochub.com/"&gt;Dragonfly&lt;/a&gt;&lt;br&gt;
&lt;a href="https://falco.adochub.com/"&gt;falco&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flagger.adochub.com/"&gt;flagger&lt;/a&gt;&lt;br&gt;
&lt;a href="https://fluxcd.adochub.com/"&gt;fluxcd&lt;/a&gt;&lt;br&gt;
&lt;a href="https://grpc.adochub.com/"&gt;grpc&lt;/a&gt;&lt;br&gt;
&lt;a href="https://keda.adochub.com/"&gt;keda&lt;/a&gt;&lt;br&gt;
&lt;a href="https://knative.adochub.com/"&gt;knative&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kubeedge.adochub.com/"&gt;kubeedge&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kubevirt.adochub.com/"&gt;kubevirt&lt;/a&gt;&lt;br&gt;
&lt;a href="https://litmuschaos.adochub.com/"&gt;litmuschaos&lt;/a&gt;&lt;br&gt;
&lt;a href="https://longhorn.adochub.com/"&gt;longhorn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nats.adochub.com/"&gt;nats&lt;/a&gt;&lt;br&gt;
&lt;a href="https://opentelemetry.adochub.com/"&gt;opentelemetry&lt;/a&gt;&lt;br&gt;
&lt;a href="https://spiffe.adochub.com/"&gt;spiffe&lt;/a&gt;&lt;br&gt;
&lt;a href="https://volcano.adochub.com/"&gt;volcano&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vultr.adochub.com/"&gt;vultr&lt;/a&gt;&lt;br&gt;
&lt;a href="https://strapi.adochub.com/"&gt;strapi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://webtorrent.adochub.com/"&gt;webtorrent&lt;/a&gt;&lt;br&gt;
&lt;a href="https://animate.css.adochub.com/"&gt;animate.css&lt;/a&gt;&lt;br&gt;
&lt;a href="https://animejs.adochub.com/"&gt;animejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://akka.adochub.com/"&gt;akka&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apple.adochub.com/"&gt;apple&lt;/a&gt;&lt;br&gt;
&lt;a href="https://arduino.adochub.com/"&gt;arduino&lt;/a&gt;&lt;br&gt;
&lt;a href="https://googleloud.adochub.com/"&gt;google cloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://elasticearch.adochub.com/"&gt;elastic search&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bitnami.adochub.com/"&gt;bitnami&lt;/a&gt;&lt;br&gt;
&lt;a href="https://databricksws.adochub.com/"&gt;databricks aws&lt;/a&gt;&lt;br&gt;
&lt;a href="https://databrickscp.adochub.com/"&gt;databricks gcp&lt;/a&gt;&lt;br&gt;
&lt;a href="https://morpheusdata.adochub.com/"&gt;morpheusdata&lt;/a&gt;&lt;br&gt;
&lt;a href="https://netapp.adochub.com/"&gt;netapp&lt;/a&gt;&lt;br&gt;
&lt;a href="https://scorm.adochub.com/"&gt;scorm&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cloudfoundry.adochub.com/"&gt;cloudfoundry&lt;/a&gt;&lt;br&gt;
&lt;a href="https://yandexloud.adochub.com/"&gt;yandex cloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vmware.adochub.com/"&gt;vmware&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ibmloud.adochub.com/"&gt;ibm cloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://acquia.adochub.com/"&gt;acquia&lt;/a&gt;&lt;br&gt;
&lt;a href="https://f5loud.adochub.com/"&gt;f5 cloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://fortinet.adochub.com/"&gt;fortinet&lt;/a&gt;&lt;br&gt;
&lt;a href="https://splunk.adochub.com/"&gt;splunk&lt;/a&gt;&lt;br&gt;
&lt;a href="https://k6.adochub.com/"&gt;k6&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ionos.adochub.com/"&gt;ionos&lt;/a&gt;&lt;br&gt;
&lt;a href="https://thingsboard.adochub.com/"&gt;thingsboard&lt;/a&gt;&lt;br&gt;
&lt;a href="https://openshift.adochub.com/"&gt;openshift&lt;/a&gt;&lt;br&gt;
&lt;a href="https://anboxloud.adochub.com/"&gt;anbox cloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cloudera.adochub.com/"&gt;cloudera&lt;/a&gt;&lt;br&gt;
&lt;a href="https://banzaicloud.adochub.com/"&gt;banzaicloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://confluent.adochub.com/"&gt;confluent&lt;/a&gt;&lt;br&gt;
&lt;a href="https://serverless.adochub.com/"&gt;serverless&lt;/a&gt;&lt;br&gt;
&lt;a href="https://hashicorploud.adochub.com/"&gt;hashicorp cloud&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bitcoin.adochub.com/"&gt;bitcoin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://behat.adochub.com/"&gt;behat&lt;/a&gt;&lt;br&gt;
&lt;a href="https://blender.adochub.com/"&gt;blender&lt;/a&gt;&lt;br&gt;
&lt;a href="https://boost.adochub.com/"&gt;boost&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bosun.adochub.com/"&gt;bosun&lt;/a&gt;&lt;br&gt;
&lt;a href="https://boto3.adochub.com/"&gt;boto3&lt;/a&gt;&lt;br&gt;
&lt;a href="https://centos.adochub.com/"&gt;centos&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cherrypy.adochub.com/"&gt;cherrypy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ckeditor.adochub.com/"&gt;ckeditor&lt;/a&gt;&lt;br&gt;
&lt;a href="https://platformio.adochub.com/"&gt;platformio&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cloudkit.adochub.com/"&gt;cloudkit&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cocoapods.adochub.com/"&gt;cocoapods&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cocos2d-x.adochub.com/"&gt;cocos2d-x&lt;/a&gt;&lt;br&gt;
&lt;a href="https://elementscompiler.adochub.com/"&gt;elementscompiler&lt;/a&gt;&lt;br&gt;
&lt;a href="https://couchbase.adochub.com/"&gt;couchbase&lt;/a&gt;&lt;br&gt;
&lt;a href="https://cython.adochub.com/"&gt;cython&lt;/a&gt;&lt;br&gt;
&lt;a href="https://debian.adochub.com/"&gt;debian&lt;/a&gt;&lt;br&gt;
&lt;a href="https://eclipse.adochub.com/"&gt;eclipse&lt;/a&gt;&lt;br&gt;
&lt;a href="https://extjs.adochub.com/"&gt;extjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ffmpeg.adochub.com/"&gt;ffmpeg&lt;/a&gt;&lt;br&gt;
&lt;a href="https://claris.adochub.com/"&gt;claris&lt;/a&gt;&lt;br&gt;
&lt;a href="https://firebirdsql.adochub.com/"&gt;firebirdsql&lt;/a&gt;&lt;br&gt;
&lt;a href="https://themegrill.adochub.com/"&gt;themegrill&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flexbox.adochub.com/"&gt;flexbox&lt;/a&gt;&lt;br&gt;
&lt;a href="https://freebsd.adochub.com/"&gt;freebsd&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gulpjs.adochub.com/"&gt;gulpjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tutorialspoint.adochub.com/"&gt;tutorialspoint&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.wikihow.com/Main-Page"&gt;wikihow&lt;/a&gt;&lt;br&gt;
&lt;a href="https://geeksforgeeks.adochub.com/"&gt;geeksforgeeks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://heroku.adochub.com/"&gt;heroku&lt;/a&gt;&lt;br&gt;
&lt;a href="https://hibernate.adochub.com/"&gt;hibernate&lt;/a&gt;&lt;br&gt;
&lt;a href="https://highcharts.adochub.com/"&gt;highcharts&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jenkins.adochub.com/"&gt;jenkins&lt;/a&gt;&lt;br&gt;
&lt;a href="https://neo4j.adochub.com/"&gt;neo4j&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nunit.adochub.com/"&gt;nunit&lt;/a&gt;&lt;br&gt;
&lt;a href="https://odoo.adochub.com/"&gt;odoo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://opencv.adochub.com/"&gt;opencv&lt;/a&gt;&lt;br&gt;
&lt;a href="https://opengl.adochub.com/"&gt;opengl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://openlayers.adochub.com/"&gt;openlayers&lt;/a&gt;&lt;br&gt;
&lt;a href="https://openstreetmap.adochub.com/"&gt;openstreetmap&lt;/a&gt;&lt;br&gt;
&lt;a href="https://openssl.adochub.com/"&gt;openssl&lt;/a&gt;&lt;br&gt;
&lt;a href="https://osgi.adochub.com/"&gt;osgi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://phantomjs.adochub.com/"&gt;phantomjs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pharo.adochub.com/"&gt;pharo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://playframework.adochub.com/"&gt;playframework&lt;/a&gt;&lt;br&gt;
&lt;a href="https://postman.adochub.com/"&gt;postman&lt;/a&gt;&lt;br&gt;
&lt;a href="https://poweri.adochub.com/"&gt;power bi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://shopify.adochub.com/"&gt;shopify&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sinatra.adochub.com/"&gt;sinatra&lt;/a&gt;&lt;br&gt;
&lt;a href="https://slf4j.adochub.com/"&gt;slf4j&lt;/a&gt;&lt;br&gt;
&lt;a href="https://spotify.adochub.com/"&gt;spotify&lt;/a&gt;&lt;br&gt;
&lt;a href="https://swagger.adochub.com/"&gt;swagger&lt;/a&gt;&lt;br&gt;
&lt;a href="https://swig.adochub.com/"&gt;swig&lt;/a&gt;&lt;br&gt;
&lt;a href="https://javatpoint.adochub.com/"&gt;javatpoint&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tableau.adochub.com/"&gt;tableau&lt;/a&gt;&lt;br&gt;
&lt;a href="https://telegram.adochub.com/"&gt;telegram&lt;/a&gt;&lt;br&gt;
&lt;a href="https://testNG.adochub.com/"&gt;testNG&lt;/a&gt;&lt;br&gt;
&lt;a href="https://tornado.adochub.com/"&gt;tornado&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vaadin.adochub.com/"&gt;vaadin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://varnish.adochub.com/"&gt;varnish&lt;/a&gt;&lt;br&gt;
&lt;a href="https://virtualbox.adochub.com/"&gt;virtualbox&lt;/a&gt;&lt;br&gt;
&lt;a href="https://woocommerce.adochub.com/"&gt;woocommerce&lt;/a&gt;&lt;br&gt;
&lt;a href="https://grammarly.adochub.com/"&gt;grammarly&lt;/a&gt;&lt;br&gt;
&lt;a href="https://zeromq.adochub.com/"&gt;zeromq&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flutterflow.adochub.com/"&gt;flutterflow&lt;/a&gt;&lt;br&gt;
&lt;a href="https://getwidget.adochub.com/"&gt;getwidget&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sentry.adochub.com/"&gt;sentry&lt;/a&gt;&lt;br&gt;
&lt;a href="https://unrealengine.adochub.com/"&gt;unreal engine&lt;/a&gt;&lt;br&gt;
&lt;a href="https://scandit.adochub.com/"&gt;scandit&lt;/a&gt;&lt;br&gt;
&lt;a href="https://praw.adochub.com/"&gt;praw&lt;/a&gt;&lt;br&gt;
&lt;a href="https://airship.adochub.com/"&gt;airship&lt;/a&gt;&lt;br&gt;
&lt;a href="https://flameengine.adochub.com/"&gt;flame engine&lt;/a&gt;&lt;br&gt;
&lt;a href="https://sectionio.adochub.com/"&gt;section io&lt;/a&gt;&lt;br&gt;
&lt;a href="https://appium.adochub.com/"&gt;appium&lt;/a&gt;&lt;br&gt;
&lt;a href="https://scipy.adochub.com/"&gt;scipy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kivy.adochub.com/"&gt;kivy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jupyter.adochub.com/"&gt;jupyter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://selenium.adochub.com/"&gt;selenium&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kommunicate.adochub.com/"&gt;kommunicate&lt;/a&gt;&lt;br&gt;
&lt;a href="https://botsquad.adochub.com/"&gt;botsquad&lt;/a&gt;&lt;br&gt;
&lt;a href="https://wireshark.adochub.com/"&gt;wireshark&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ovh.adochub.com/"&gt;ovh&lt;/a&gt;&lt;br&gt;
&lt;a href="https://openebs.adochub.com/"&gt;openebs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mayastor.adochub.com/"&gt;mayastor&lt;/a&gt;&lt;br&gt;
&lt;a href="https://clickhouse.adochub.com/"&gt;clickhouse&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
    </item>
    <item>
      <title>step by step guide tell you how to build a website like apkmirror</title>
      <dc:creator>fengmao</dc:creator>
      <pubDate>Mon, 16 Aug 2021 12:58:48 +0000</pubDate>
      <link>https://dev.to/fengmao/step-by-step-guide-tell-you-how-to-build-a-website-like-apkmirror-3o2d</link>
      <guid>https://dev.to/fengmao/step-by-step-guide-tell-you-how-to-build-a-website-like-apkmirror-3o2d</guid>
      <description>&lt;p&gt;There are many &lt;a href="https://idoras.com"&gt;free apk download&lt;/a&gt; websites such as apkmirror, today i will tell you how to build a website like apkmirror, the programming language i used is &lt;a href="https://nodejs.org/en/"&gt;node.js&lt;/a&gt;, the database i used is &lt;a href="https://www.mongodb.com/"&gt;mongodb&lt;/a&gt;, search engine used is &lt;a href="https://elastic.co/"&gt;elasticsearch&lt;/a&gt;, the web framework i use is &lt;a href="https://eggjs.org/"&gt;eggjs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part I analysis apk file and save data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tool we need is appt, you can install it with &lt;strong&gt;sudo apt-get install aapt&lt;/strong&gt; on ubuntu, the command to analysis apk file is &lt;strong&gt;aapt dump badging test.apk&lt;/strong&gt;, as we need execute the command in node.js script so i use execSync to call the command, the code block is below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { execSync } = require('child_process');
const fs = require("fs"); 
const md5 = require('md5');
const { sleep, getDir } = require('../util');

const analysis = (output) =&amp;gt; {
  const res = {};
  let out = output.toString().replace(/'/g, '');

  out = out.split('\n');

  let tmp = out[0].split(' ');
  res.package = tmp[1].split('=')[1];
  res.versionCode = tmp[2].split('=')[1];
  res.versionName = tmp[3].split('=')[1];

  tmp = out[2].split(':')
  if (tmp[0] == 'sdkVersion') {
    res.sdkVersion = tmp[1];
  }

  tmp = out[3].split(':');
  if (tmp[0] == 'targetSdkVersion') {
    res.targetSdkVersion = tmp[1];
  }

  tmp = out[out.length - 2].split(':');
  if (tmp[0] == 'native-code') {
    res.variant = tmp[1].trim().replace(/ /g, '|');

    tmp = out[out.length - 6].split(':');
    res.screen = tmp[1].trim();

    tmp = out[out.length - 4].split(':');
    res.locales = tmp[1].trim();
  } else {
    res.variant = 'noarch';

    tmp = out[out.length - 5].split(':');
    res.screen = tmp[1].trim();

    tmp = out[out.length - 3].split(':');
    res.locales = tmp[1].trim();
  }
  return res;
}

const filters = ['.', '..'];

const run = async () =&amp;gt; {
  while (true) {
    const dirs = fs.readdirSync(getDir('tmp'));
    for (const dir of dirs) {
      if (!filters.includes(dir)) {
        const name = getDir('tmp', dir);
        try {
          const output = execSync(`/usr/bin/aapt dump badging ${name}`);
          const res = analysis(output);
          const stats = fs.statSync(name);
          res.fileSize = stats.size;
          const newName = getDir('apk', `${res.package}_${res.versionCode}_idoras.com.apk`);
          const tasks = [];
          const url = `https://play.google.com/store/apps/details?id=${res.package}`;
          tasks.push({ _id: md5(url), url, host: 'play.google.com', type: 'detail', package: res.package, done: 0 });
          await global.db.collection('tasks').insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
          const one = await global.db.collection('apk').findOne({ _id: res.package }).catch(() =&amp;gt; {});
          if (one) {
            const a = +one.versionCode;
            const b = +res.versionCode;
            if (b &amp;gt; a) {
              await global.db.collection('apk').updateOne({ _id: res.package }, { $set:{ udate: Date.now(), versionCode: res.versionCode, versionName: res.versionName, done: 1 }}).catch(() =&amp;gt; {});
            }
          } else {
            await global.db.collection('apk').insertOne({ _id: res.package, versionCode: res.versionCode, versionName: res.versionName, cdate: Date.now(), udate: Date.now(), done: 0, down: 0 }).catch(() =&amp;gt; {});
          }
          res._id = `${res.package}_${res.versionCode}`;
          await global.db.collection('variant').insertOne({ ...res, cdate: Date.now() }).catch(() =&amp;gt; {});
          fs.renameSync(name, newName);
        } catch (err) {
          console.error(err);
          fs.unlinkSync(name);
        }
      }
    }
    if (dirs.length == 0) {
      console.log('no apk files to analysis');
      await sleep(60000);
    }
  }
};

module.exports = run;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;getDir&lt;/strong&gt; and &lt;strong&gt;sleep&lt;/strong&gt; is util function, you can find the source code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const req = require('request');
const path = require('path');
const os = require('os');
const agent = new require('socks-proxy-agent')('socks5://localhost:1080');

let root = '/data';
const options = {
  headers: {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
  },
  timeout: 30000,
  encoding: null,
};
if (os.platform() == 'win32') {
  options.agent = agent;
  root = 'd:/data';
}
const request = req.defaults(options);

const getDir = (...paths) =&amp;gt; {
  paths.unshift(root);
  return path.join(...paths);
};

const sleep = (time) =&amp;gt; new Promise((resolve) =&amp;gt; {
    setTimeout(() =&amp;gt; {
      resolve();
    }, time);
  });

const fetch = (url) =&amp;gt; new Promise((resolve) =&amp;gt; {
    console.log(`down ${url} started`);
    request(url, (err, res, body) =&amp;gt; {
      if (res &amp;amp;&amp;amp; res.statusCode === 200) {
        console.log(`down ${url} 200`);
        resolve(body);
      } else {
        console.error(`down ${url} ${res &amp;amp;&amp;amp; res.statusCode} ${err}`);
        if (res &amp;amp;&amp;amp; res.statusCode) {
          resolve(res.statusCode);
        } else {
          // ESOCKETTIMEOUT 超时错误返回600
          resolve(600);
        }
      }
    });
  });

module.exports = { getDir, sleep, fetch };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main logic is we get basic information from appt, parse the output, get apk id such as &lt;strong&gt;com.moonvideo.android.resso&lt;/strong&gt;, and insert a task to get apk logo and images and brief from &lt;a href="https://play.google.com/store/apps"&gt;play.google.com&lt;/a&gt;, i wrote a little crawler framework, each website with one parser bind with the host, every url have a type, each type bind with a function, the play.google.com’s parser code is below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { URL } = require('url');
const md5 = require('md5');
const cheerio = require('cheerio');
const slugify = require('slugify');

const resolve = (from, to) =&amp;gt; {
  const resolvedUrl = new URL(to, new URL(from, 'resolve://'));
  if (resolvedUrl.protocol === 'resolve:') {
    // `from` is a relative URL.
    const { pathname, search, hash } = resolvedUrl;
    return pathname + search + hash;
  }
  return resolvedUrl.toString();
}

const fns = {

  detail: async (page) =&amp;gt; {
    const host = page.host;
    try {
      const $ = cheerio.load(page.con.toString(), { decodeEntities: false });
      const brief = $('div.DWPxHb &amp;gt; span &amp;gt; div:nth-child(1)').html();
      const name = $('h1.AHFaub &amp;gt; span').text();
      const dev = $('div.qQKdcc &amp;gt; span:nth-child(1) &amp;gt; a').text();
      const tag = $('div.qQKdcc &amp;gt; span:nth-child(2) &amp;gt; a').attr('href').split('/')[4];
      const images = [];
      const tasks = [];
      $('button.Q4vdJd &amp;gt; img').each((i, ele) =&amp;gt; {
        let url = $(ele).attr('src');
        if (!url || !url.startsWith('https')) {
          url = $(ele).attr('data-src')
        }
        tasks.push({ _id: md5(url), url, type: 'download', host: (new URL(url)).hostname, done: 0 });
        images.push({ _id: md5(url), url });
      });
      const logourl = $('div.xSyT2c &amp;gt; img').attr('src');
      tasks.push({ _id: md5(logourl), url: logourl, type: 'download', host: (new URL(logourl)).hostname, package: page.package, done: 0 });
      const res = await global.db.collection('tasks').insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-detail insert ${res.insertedCount} from ${tasks.length} tasks`);
      await global.db.collection('apk').updateOne({ _id: page.package }, { $set:{ brief, name, dev, devSlug: slugify(dev), tag, tagSlug: slugify(tag), images, done: 1 } });
      return 1;
    } catch (err) {
      console.error(`${host}-detail parse ${page.url} ${err}`);
      return 4;
    }
  },

  run: (page) =&amp;gt; {
    const fn = fns[page.type];
    if (fn) {
      return fn(page);
    }
    console.error(`${page.url} parser not found`);
    return 0;
  }

};

module.exports = fns;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;every apk we analysis with aapt will send one request to play.google.com to get it’s name, brief, developer info, tag, images, i will use these data to show on the website.&lt;/p&gt;

&lt;p&gt;now we have the data of apk file, so where to find the apk files? You can download them from &lt;a href="https://idoras.com"&gt;idoras&lt;/a&gt; or &lt;a href="https://www.apkmirror.com/"&gt;apkmirror&lt;/a&gt; or &lt;a href="https://apkpure.com/"&gt;apkpure&lt;/a&gt;, also you can write node.js script to download them from website such as &lt;a href="https://idoras.com"&gt;idoras&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next we need index these data with elasticsearch so we can use them later, the code is below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { sleep } = require('../util');
const { Client } = require('@elastic/elasticsearch');

const getApks = (apks) =&amp;gt; {
  const res = [];
  apks.forEach((apk) =&amp;gt; {
    if(apk.name) {
      const tmp = {};
      res.push({ index: { _index: 'apk', _type: '_doc', _id: apk._id } });
      tmp.id = apk._id;
      tmp.versionCode = apk.versionCode;
      tmp.versionName = apk.versionName;
      tmp.cdate = apk.cdate;
      tmp.udate = apk.udate;
      tmp.down = apk.down;
      tmp.brief = apk.brief;
      tmp.dev = apk.dev;
      tmp.devSlug = apk.devSlug;
      tmp.name = apk.name;
      tmp.tag = apk.tag;
      res.push(tmp);
    }
  });
  return res;
};

const run = async () =&amp;gt; {

  while (true) {
    const esclient = new Client({
      node: 'http://username:password@ip:9200',
      maxRetries: 3,
      requestTimeout: 60000
    });
    const apks = await global.db.collection('apk').find({ done: 1 }).limit(100).toArray().catch((err) =&amp;gt; console.error(err));
    const tmp = getApks(apks);
    if (tmp &amp;amp;&amp;amp; tmp.length) {
      let res = await esclient.bulk({ refresh: true, body: tmp }).catch((err) =&amp;gt; console.error(err));
      if (res) {
        const ulist = apks.map((apk) =&amp;gt; ({ updateOne: { filter: { _id: apk._id }, update: { $set: { done: 6 } }, upsert: false } }));
        res = await global.db.collection('apk').bulkWrite(ulist, { ordered: false, w: 1 }).catch(() =&amp;gt; {});
        res &amp;amp;&amp;amp; console.log(`apk:indexer update ${res.modifiedCount} from ${res.matchedCount}`);
      }
    } else {
      console.log('apk:indexer no apk to index');
      await sleep(60000);
    }
    await esclient.close();
  }
};

module.exports = run;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Part II build website with eggjs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The template engine i use is &lt;a href="https://nunjucks.bootcss.com/"&gt;nunjucks&lt;/a&gt;, also i used some eggjs plugins such &lt;a href="https://www.npmjs.com/package/egg-elasticsearch2"&gt;egg-elasticsearch2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The logic is easy, at home page we query data from elasticsearch, and render data into nunjucks template, basiclly it’s a list page, also i will cache the hot download apks into &lt;strong&gt;ctx.app.hots&lt;/strong&gt;, refresh it every 30 minutes, and show the hot download apks on the right aside, also the html template support responsive design, it will show perfect on mobile system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use strict';

const Controller = require('egg').Controller;

class HomeController extends Controller {

  async home() {
    const { ctx } = this;
    const params = ctx.params;
    const page = parseInt(params.page, 10) || 1;
    if (page &amp;lt; 1) {
      ctx.redirect('/list/1/', 301);
    }
    const start = (page - 1) * ctx.helper.size;
    const query = {
      body: [
        { index: 'apk', type: '_doc' },
        { query: { bool: { must: [{ match_all: {} }, { exists: { field: 'id' } }] } }, highlight: { fields: { name: {} } }, from: start, size: ctx.helper.size, sort: [{ udate: { order: 'desc' } }, '_score' ] },
      ],
    };
    const info = {};
    const res = await ctx.app.elasticsearch.msearch(query);
    ctx.helper.getList(res.responses[0], info);

    let tpage = Math.floor(info.all / ctx.helper.size) + (info.all % ctx.helper.size ? 1 : 0);
    tpage &amp;lt; 1 &amp;amp;&amp;amp; (tpage = 1);
    if (page &amp;gt; tpage) {
      if (tpage &amp;gt; 500) {
        ctx.redirect('/list/500/', 301);
      } else {
        ctx.redirect(`/list/${tpage}/`, 301);
      }
    } else if (page &amp;gt; 500) {
      ctx.redirect('/list/500/', 301);
    }
    tpage = tpage &amp;gt; 500 ? 500 : tpage;
    info.pages = ctx.helper.getPages(page, tpage);

    info.url = ctx.request.url;
    if (info.url === '/') {
      info.title = 'Free Apk download online - idoras.com';
      info.keywords = 'app download,apk download, free apk download, idoras, apk downloader, android apk download';
      info.description = 'Free apk download for Android with idoras APK downloader. NoAds, Faster apk downloads and apk file update speed. Best of all, it\'s free';
      info.home = true;
    } else {
      info.title = `Free Apk download - page${page} - idoras.com`;
      info.keywords = `app download,apk download, free apk download, idoras, apk downloader, android apk download,apk list page${page}`;
      info.description = info.list.map(item =&amp;gt; item.name).join(',').substring(0, 150);
    }

    if (!ctx.app.hots) {
      ctx.app.hots = info.hots = await ctx.service.search.hot();
    } else {
      info.hots = ctx.app.hots;
    }
    info.slist = ctx.helper.getKeys();
    await ctx.render('home.html', { info });
  }

  async version() {
    const { ctx } = this;
    const params = ctx.params;
    const id = params.id;
    const apk = await ctx.model.Apk.findById(id);
    const list = await ctx.model.Variant.find({ package: id });
    list.sort((a, b) =&amp;gt; b.versionCode - a.versionCode);
    const info = { apk, list };
    info.variant = list[0] || {};
    info.title = `${apk.name} Free Apk download - idoras.com`;
    info.keywords = `${apk.name} download, app download,apk download, free apk download, idoras, apk downloader, android apk download`;
    info.description = `download ${apk.name} free apks online, it's faster and free online, many version to download`;
    if (!ctx.app.hots) {
      ctx.app.hots = info.hots = await ctx.service.search.hot();
    } else {
      info.hots = ctx.app.hots;
    }
    info.slist = ctx.helper.getKeys();
    await ctx.render('version.html', { info });
  }

  async download() {
    const { ctx } = this;
    const params = ctx.params;
    const id = params.id;
    const version = params.version;
    const apk = await ctx.model.Apk.findById(id);
    const variant = await ctx.model.Variant.findById(`${id}_${version}`);
    const list = await ctx.model.Variant.find({ package: id });
    list.sort((a, b) =&amp;gt; b.cdate - a.cdate);
    apk.down = apk.down + 1;
    apk.save();
    ctx.app.elasticsearch.update({ index: 'apk', type: '_doc', id, body: { script: 'ctx._source.down += 1', upsert: { down: 1 } } }, () =&amp;gt; { });
    const info = { apk, variant, list };
    info.title = `${apk.name} ${apk.versionName} Free Apk download online - idoras.com`;
    info.keywords = `${apk.name} ${apk.versionName} download online, app download,apk download, free apk download, idoras, apk downloader, android apk download`;
    info.description = `download ${apk.name} ${apk.versionName} free apks online, it's faster and free online, many version to download`;
    if (!ctx.app.hots) {
      ctx.app.hots = info.hots = await ctx.service.search.hot();
    } else {
      info.hots = ctx.app.hots;
    }
    info.slist = ctx.helper.getKeys();
    await ctx.render('download.html', { info });
  }

  async dev() {
    const { ctx } = this;
    const params = ctx.params;
    const devSlug = params.devSlug;
    const page = parseInt(params.page, 10) || 1;
    if (page &amp;lt; 1) {
      ctx.redirect(`/dev/${devSlug}/1/`, 301);
    }
    const start = (page - 1) * ctx.helper.size;
    const info = { devSlug };
    const query = {
      body: [
        { index: 'apk', type: '_doc' },
        { query: { term: { devSlug } }, from: start, size: ctx.helper.size, sort: [{ udate: { order: 'desc' } }, '_score' ] },
      ],
    };
    const res = await ctx.app.elasticsearch.msearch(query);
    ctx.helper.getList(res.responses[0], info);

    let tpage = Math.floor(info.all / ctx.helper.size) + (info.all % ctx.helper.size ? 1 : 0);
    tpage &amp;lt; 1 &amp;amp;&amp;amp; (tpage = 1);
    if (page &amp;gt; tpage) {
      if (tpage &amp;gt; 500) {
        ctx.redirect(`/dev/${devSlug}/500/`, 301);
      } else {
        ctx.redirect(`/dev/${devSlug}/${tpage}/`, 301);
      }
    } else if (page &amp;gt; 500) {
      ctx.redirect(`/dev/${devSlug}/500/`, 301);
    }
    tpage = tpage &amp;gt; 500 ? 500 : tpage;
    info.pages = ctx.helper.getPages(page, tpage);

    info.title = `apk developered by ${devSlug} download - idoras.com`;
    info.keywords = `${devSlug} apks download online, app download,apk download, free apk download, idoras, apk downloader, android apk download`;
    info.description = `download ${devSlug} free apks online, it's faster and free online, many version to download`;
    if (!ctx.app.hots) {
      ctx.app.hots = info.hots = await ctx.service.search.hot();
    } else {
      info.hots = ctx.app.hots;
    }
    info.slist = ctx.helper.getKeys();
    await ctx.render('dev.html', { info });
  }

  async tag() {
    const { ctx } = this;
    const params = ctx.params;
    const tag = params.tag;
    const page = parseInt(params.page, 10) || 1;
    if (page &amp;lt; 1) {
      ctx.redirect(`/tag/${tag}/1/`, 301);
    }
    const start = (page - 1) * ctx.helper.size;
    const info = { tag };
    const query = {
      body: [
        { index: 'apk', type: '_doc' },
        { query: { term: { tag } }, from: start, size: ctx.helper.size, sort: [{ udate: { order: 'desc' } }, '_score' ] },
      ],
    };
    const res = await ctx.app.elasticsearch.msearch(query);
    ctx.helper.getList(res.responses[0], info);

    let tpage = Math.floor(info.all / ctx.helper.size) + (info.all % ctx.helper.size ? 1 : 0);
    tpage &amp;lt; 1 &amp;amp;&amp;amp; (tpage = 1);
    if (page &amp;gt; tpage) {
      if (tpage &amp;gt; 500) {
        ctx.redirect(`/tag/${tag}/500/`, 301);
      } else {
        ctx.redirect(`/tag/${tag}/${tpage}/`, 301);
      }
    } else if (page &amp;gt; 500) {
      ctx.redirect(`/tag/${tag}/500/`, 301);
    }
    tpage = tpage &amp;gt; 500 ? 500 : tpage;
    info.pages = ctx.helper.getPages(page, tpage);

    info.title = `apk tagged with ${tag} download - idoras.com`;
    info.keywords = `${tag} apks download online, app download,apk download, free apk download, idoras, apk downloader, android apk download`;
    info.description = `download ${tag} free apks online, it's faster and free online, many version to download`;
    if (!ctx.app.hots) {
      ctx.app.hots = info.hots = await ctx.service.search.hot();
    } else {
      info.hots = ctx.app.hots;
    }
    info.slist = ctx.helper.getKeys();
    await ctx.render('tag.html', { info });
  }

  async search() {
    const { ctx } = this;
    const params = ctx.params;
    const key = params.key;
    const page = parseInt(params.page, 10) || 1;
    if (page &amp;lt; 1) {
      ctx.redirect(`/search/${key}/1/`, 301);
    }
    const start = (page - 1) * ctx.helper.size;
    const info = { key };
    const query = {
      body: [
        { index: 'apk', type: '_doc' },
      ],
    };
    if (key) {
      query.body.push({ query: { multi_match: { query: key, fields: [ 'name', 'id', 'brief' ] } }, from: start, size: ctx.helper.size, sort: [ '_score' ] });
    } else {
      query.body.push({ query: { bool: { must: [{ match_all: {} }, { exists: { field: 'id' } }] } }, from: start, size: ctx.helper.size, sort: [ '_score' ] });
    }
    const res = await ctx.app.elasticsearch.msearch(query);
    key &amp;amp;&amp;amp; res.responses[0].hits.hits.length &amp;amp;&amp;amp; ctx.helper.putKey(key);
    ctx.helper.getList(res.responses[0], info);

    let tpage = Math.floor(info.all / ctx.helper.size) + (info.all % ctx.helper.size ? 1 : 0);
    tpage &amp;lt; 1 &amp;amp;&amp;amp; (tpage = 1);
    if (page &amp;gt; tpage) {
      if (tpage &amp;gt; 500) {
        ctx.redirect(`/search/${key}/500/`, 301);
      } else {
        ctx.redirect(`/search/${key}/${tpage}/`, 301);
      }
    } else if (page &amp;gt; 500) {
      ctx.redirect(`/search/${key}/500/`, 301);
    }
    tpage = tpage &amp;gt; 500 ? 500 : tpage;
    info.pages = ctx.helper.getPages(page, tpage);

    info.title = `search ${key} apks to download online - idoras.com`;
    info.keywords = `${key} apks download online, app download,apk download, free apk download, idoras, apk downloader, android apk download`;
    info.description = `download ${key} free apks online, it's faster and free online, many version to download`;
    if (!ctx.app.hots) {
      ctx.app.hots = info.hots = await ctx.service.search.hot();
    } else {
      info.hots = ctx.app.hots;
    }
    info.slist = ctx.helper.getKeys();
    await ctx.render('search.html', { info });
  }

  async re() {
    const { ctx } = this;
    const params = ctx.request.body;
    const key = params.key;
    if (key) {
      ctx.redirect(`/search/${encodeURI(key)}/`, 301);
    } else {
      ctx.redirect('/search/', 301);
    }
  }
}

module.exports = HomeController;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use strict';

// eslint-disable-next-line no-unused-vars
module.exports = (options, app) =&amp;gt; {
  return async function mobileMiddleware(ctx, next) {
    const u = ctx.get('user-agent') || '';
    const tmp = {
      trident: u.indexOf('Trident') &amp;gt; -1, // IE内核
      presto: u.indexOf('Presto') &amp;gt; -1, // opera内核
      webKit: u.indexOf('AppleWebKit') &amp;gt; -1, // 苹果、谷歌内核
      gecko: u.indexOf('Gecko') &amp;gt; -1 &amp;amp;&amp;amp; u.indexOf('KHTML') === -1, // 火狐内核
      mobile: !!u.match(/AppleWebKit.*Mobile.*/), // 是否为移动终端
      ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), // ios终端
      android: u.indexOf('Android') &amp;gt; -1 || u.indexOf('Linux') &amp;gt; -1, // android终端或者uc浏览器
      iPhone: u.indexOf('iPhone') &amp;gt; -1, // 是否为iPhone或者QQHD浏览器
      iPad: u.indexOf('iPad') &amp;gt; -1, // 是否iPad
      webApp: u.indexOf('Safari') === -1, // 是否web应该程序，没有头部与底部
      weixin: u.indexOf('MicroMessenger') &amp;gt; -1, // 是否微信 （2015-01-22新增）
      qq: u.match(/\sQQ/i) === ' qq', // 是否QQ
    };
    if (tmp.mobile || tmp.android || tmp.ios || tmp.weixin) {
      ctx.request.mobile = true;
    }
    await next();
  };
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset="UTF-8"&amp;gt;
  &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
  &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
  &amp;lt;title&amp;gt;{{info.title}}&amp;lt;/title&amp;gt;
  &amp;lt;meta name="keywords" content="{{info.keywords}}"&amp;gt;
  &amp;lt;meta name="description" content="{{info.description}}"&amp;gt;
  &amp;lt;meta property="og:site_name" content="idoras.com"&amp;gt;
  &amp;lt;meta property="og:title" content="{{info.title}}"&amp;gt;
  &amp;lt;meta property="og:type" content="website"&amp;gt;
  &amp;lt;link rel="shortcut icon" href="/favicon.ico"&amp;gt;
  &amp;lt;link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css"&amp;gt;
  &amp;lt;link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"&amp;gt;
  &amp;lt;link rel="stylesheet" href="/css/material-components-web.min.css"&amp;gt;
  &amp;lt;link rel="stylesheet" href="/css/app.css?v=2021080817"&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;

  &amp;lt;aside class="mdc-drawer mdc-drawer--dismissible"&amp;gt;
    &amp;lt;div class="mdc-drawer__header"&amp;gt;
      &amp;lt;h3 class="mdc-drawer__title"&amp;gt;IDORAS&amp;lt;/h3&amp;gt;
      &amp;lt;h6 class="mdc-drawer__subtitle"&amp;gt;download free android apks&amp;lt;/h6&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="mdc-drawer__content"&amp;gt;
      &amp;lt;nav class="mdc-list"&amp;gt;
        &amp;lt;a class="mdc-list-item mdc-list-item--activated" href="/" aria-selected="true"&amp;gt;
          &amp;lt;i class="material-icons mdc-list-item__graphic" aria-hidden="true"&amp;gt;home&amp;lt;/i&amp;gt;
          &amp;lt;span class="mdc-list-item__text"&amp;gt;Home&amp;lt;/span&amp;gt;
        &amp;lt;/a&amp;gt;
      &amp;lt;/nav&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/aside&amp;gt;
  &amp;lt;div class="mdc-drawer-app-content"&amp;gt;
    &amp;lt;header class="mdc-top-app-bar app-bar" id="app-bar"&amp;gt;
      &amp;lt;div class="mdc-top-app-bar__row container"&amp;gt;
        &amp;lt;section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-start"&amp;gt;
          &amp;lt;i href="" class="demo-menu material-icons mdc-top-app-bar__navigation-icon mdc-nav-icon menuLogo"
            style="text-decoration: none;cursor: pointer;"&amp;gt;menu&amp;lt;/i&amp;gt;
          &amp;lt;a class="mdc-top-app-bar__title" href="/" style="color: #fff;"&amp;gt;IDORAS&amp;lt;/a&amp;gt;
        &amp;lt;/section&amp;gt;
        &amp;lt;section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-end" role="toolbar"&amp;gt;
          &amp;lt;a href="/search/"&amp;gt;
            &amp;lt;i class="material-icons icon-white"&amp;gt;search&amp;lt;/i&amp;gt;
          &amp;lt;/a&amp;gt;
        &amp;lt;/section&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/header&amp;gt;

    &amp;lt;main class="main-content" id="main-content"&amp;gt;
      &amp;lt;div class="mdc-top-app-bar--fixed-adjust container"&amp;gt;
        &amp;lt;div class="mdc-layout-grid" style="padding:0"&amp;gt;
          &amp;lt;div class="mdc-layout-grid__inner"&amp;gt;
            &amp;lt;div
              class="mdc-layout-grid__cell mdc-layout-grid__cell--span-8 mdc-layout-grid__cell--span-12-tablet mdc-layout-grid__cell--span-12-phone"&amp;gt;
              {% if ctx.request.mobile %}
              &amp;lt;div class="details-title"&amp;gt;
                &amp;lt;!-- Go to www.addthis.com/dashboard to customize your tools --&amp;gt; 
                &amp;lt;div class="addthis_inline_share_toolbox_bm88"&amp;gt;&amp;lt;/div&amp;gt;
              &amp;lt;/div&amp;gt;
              {% endif %}
              &amp;lt;div class="listWidght"&amp;gt;
                &amp;lt;form action="/re" style="overflow:visible" method="POST" onsubmit="return key.value!=''" role="search"&amp;gt;
                  &amp;lt;input class="search-key" type="text" id="key" name="key" placeholder="Google Play Store or com.android.vending" size="1" style="padding: 5px;" /&amp;gt;
                  &amp;lt;button type="submit" class="search mdc-button mdc-button--raised button"&amp;gt;
                    &amp;lt;i class="material-icons icon-white"&amp;gt;search&amp;lt;/i&amp;gt;
                  &amp;lt;/button&amp;gt;
                &amp;lt;/form&amp;gt;
              &amp;lt;/div&amp;gt;
              &amp;lt;div class="listWidget"&amp;gt;
                &amp;lt;div class="box"&amp;gt;
                  &amp;lt;div class="title bread-crumbs"&amp;gt;
                    &amp;lt;h5 class="widgetHeader"&amp;gt;Latest Upload&amp;lt;/h5&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                {% for item in info.list %}
                &amp;lt;div&amp;gt;
                  &amp;lt;div class="appRow"&amp;gt;
                    &amp;lt;div class="table-row"&amp;gt;
                      &amp;lt;div style="width: 56px;" class="table-cell"&amp;gt;
                        &amp;lt;img style="width:50px; height:50px;"
                          src="https://img.idoras.com/img/{{item.id}}.png"&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div class="table-cell"&amp;gt;
                        &amp;lt;div style="padding-top: 4px;"&amp;gt;
                          &amp;lt;h5 title="{{item.name}} {{item.versionName}} ({{item.versionCode}}) by {{item.dev}}"
                            class="appRowTitle wrapText marginZero block-on-mobile"&amp;gt;
                            &amp;lt;a class="fontBlack" href="/apk/{{item.id}}/"&amp;gt;{{item.name}} {{item.versionName}}&amp;lt;/a&amp;gt;
                          &amp;lt;/h5&amp;gt;
                          &amp;lt;a href="/dev/{{item.devSlug}}/" class="byDeveloper block-on-mobile wrapText"&amp;gt;by {{item.dev}}&amp;lt;/a&amp;gt;
                          &amp;lt;span style="padding:4px 12px 0 0;" class="colorLightBlack"&amp;gt;&amp;lt;span class="udate"&amp;gt;{{ctx.helper.fdate(item.udate)}}&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
                        &amp;lt;/div&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div style="width: 30px;" class="table-cell"&amp;gt;
                        &amp;lt;div class="iconsBox "&amp;gt;
                          &amp;lt;div class="downloadIconPositioning"&amp;gt;
                            &amp;lt;a class="downloadLink" href="/apk/{{item.id}}/{{item.versionCode}}/"&amp;gt;
                              &amp;lt;i class="material-icons icon-blue" aria-hidden="true"&amp;gt;download&amp;lt;/i&amp;gt;
                            &amp;lt;/a&amp;gt;
                          &amp;lt;/div&amp;gt;
                        &amp;lt;/div&amp;gt;
                      &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                {% endfor %}
                &amp;lt;div class="appRow center"&amp;gt;
                  &amp;lt;div class="pagination mobile"&amp;gt;
                    &amp;lt;div class="wp-pagenavi" role="navigation"&amp;gt;
                      {% for page in info.pages %}
                      &amp;lt;a href="/list/{{page.page}}/"
                        class="{%if loop.first%}first{%endif%} {%if loop.last%}last{%endif%} {%if page.current%}current{%endif%}"&amp;gt;
                        &amp;lt;span class="mdc-fab__icon"&amp;gt;
                          {{page.text}}
                        &amp;lt;/span&amp;gt;
                      &amp;lt;/a&amp;gt;
                      {% endfor %}
                    &amp;lt;/div&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
              &amp;lt;/div&amp;gt;
              &amp;lt;div class="pages"&amp;gt;

              &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div
              class="mdc-layout-grid__cell mdc-layout-grid__cell--span-4 mdc-layout-grid__cell--span-12-tablet mdc-layout-grid__cell--span-12-phone"&amp;gt;
              {% if info.slist.length &amp;gt; 0 %}
              &amp;lt;div class="listWidget"&amp;gt;
                &amp;lt;div class="box"&amp;gt;
                  &amp;lt;div class="title bread-crumbs"&amp;gt;
                    &amp;lt;h5 class="widgetHeader"&amp;gt;Hot Searches&amp;lt;/h5&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;div&amp;gt;
                  &amp;lt;div class="appRow"&amp;gt;
                    {% for item in info.slist %}
                    &amp;lt;a href="/search/{{item.ekey}}/" class="mdc-button"&amp;gt;
                      &amp;lt;span class="mdc-button__label"&amp;gt;{{item.key}}&amp;lt;/span&amp;gt;
                    &amp;lt;/a&amp;gt;
                    {% endfor %}
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
              &amp;lt;/div&amp;gt;
              {% endif %}
              &amp;lt;div class="listWidget"&amp;gt;
                &amp;lt;div class="box"&amp;gt;
                  &amp;lt;div class="title bread-crumbs"&amp;gt;
                    &amp;lt;h5 class="widgetHeader"&amp;gt;Social Medias&amp;lt;/h5&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;div&amp;gt;
                  &amp;lt;div class="appRow"&amp;gt;
                    &amp;lt;div class="table-row"&amp;gt;
                      &amp;lt;div class="table-cell center"&amp;gt;
                        &amp;lt;a href="https://www.facebook.com/profile.php?id=100071468057179" target="_blank"&amp;gt;
                          &amp;lt;img style="vertical-align: baseline; height: 24px; width: 24px;" src="/img/facebook.png" class="clickable"&amp;gt;
                        &amp;lt;/a&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div class="table-cell center"&amp;gt;
                        &amp;lt;a href="https://twitter.com/Shaoyang2000" target="_blank"&amp;gt;
                          &amp;lt;img style="vertical-align: baseline; height: 24px; width: 24px;" src="/img/twitter.png" class="clickable"&amp;gt;
                        &amp;lt;/a&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div class="table-cell center"&amp;gt;
                        &amp;lt;a href="https://t.me/idoras_official" target="_blank"&amp;gt;
                          &amp;lt;img style="vertical-align: baseline; height: 24px; width: 24px;" src="/img/telegram.png" class="clickable"&amp;gt;
                        &amp;lt;/a&amp;gt;
                      &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
              &amp;lt;/div&amp;gt;
              &amp;lt;div class="listWidget"&amp;gt;
                &amp;lt;div class="box"&amp;gt;
                  &amp;lt;div class="title bread-crumbs"&amp;gt;
                    &amp;lt;h5 class="widgetHeader"&amp;gt;Popular In Last 24 Hours&amp;lt;/h5&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                {% for item in info.hots[0].list %}
                &amp;lt;div&amp;gt;
                  &amp;lt;div class="appRow"&amp;gt;
                    &amp;lt;div class="table-row"&amp;gt;
                      &amp;lt;div style="width: 56px;" class="table-cell"&amp;gt;
                        &amp;lt;img style="width:50px; height:50px;"
                          src="https://img.idoras.com/img/{{item.id}}.png"&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div class="table-cell"&amp;gt;
                        &amp;lt;h5 title="{{item.name}} {{item.versionName}}" class="appRowTitle wrapText marginZero block-on-mobile"&amp;gt;
                          &amp;lt;a class="fontBlack" href="/apk/{{item.id}}/"&amp;gt;{{item.name}} {{item.versionName}}&amp;lt;/a&amp;gt;
                        &amp;lt;/h5&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div style="width: 50px; text-align: right;" class="table-cell"&amp;gt;
                        &amp;lt;span style="padding-right:12px;" class="colorLightBlack"&amp;gt;{{item.down}}&amp;lt;/span&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div style="width: 22px;" class="table-cell"&amp;gt;
                        &amp;lt;div class="iconsBox one-icon"&amp;gt;
                          &amp;lt;div class="downloadIconPositioning"&amp;gt;
                            &amp;lt;a class="downloadLink"
                              href="/apk/{{item.id}}/"&amp;gt;
                              &amp;lt;i class="material-icons icon-blue" aria-hidden="true"&amp;gt;download&amp;lt;/i&amp;gt;
                            &amp;lt;/a&amp;gt;
                          &amp;lt;/div&amp;gt;
                        &amp;lt;/div&amp;gt;
                      &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                {% endfor %}
              &amp;lt;/div&amp;gt;
              &amp;lt;div class="listWidget"&amp;gt;
                &amp;lt;div class="box"&amp;gt;
                  &amp;lt;div class="title bread-crumbs"&amp;gt;
                    &amp;lt;h5 class="widgetHeader"&amp;gt;Popular In Last 7 Days&amp;lt;/h5&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                {% for item in info.hots[1].list %}
                &amp;lt;div&amp;gt;
                  &amp;lt;div class="appRow"&amp;gt;
                    &amp;lt;div class="table-row"&amp;gt;
                      &amp;lt;div style="width: 56px;" class="table-cell"&amp;gt;
                        &amp;lt;img style="width:50px; height:50px;"
                          src="https://img.idoras.com/img/{{item.id}}.png"&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div class="table-cell"&amp;gt;
                        &amp;lt;h5 title="{{item.name}} {{item.versionName}}" class="appRowTitle wrapText marginZero block-on-mobile"&amp;gt;
                          &amp;lt;a class="fontBlack" href="/apk/{{item.id}}/"&amp;gt;{{item.name}} {{item.versionName}}&amp;lt;/a&amp;gt;
                        &amp;lt;/h5&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div style="width: 50px; text-align: right;" class="table-cell"&amp;gt;
                        &amp;lt;span style="padding-right:12px;" class="colorLightBlack"&amp;gt;{{item.down}}&amp;lt;/span&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div style="width: 22px;" class="table-cell"&amp;gt;
                        &amp;lt;div class="iconsBox one-icon"&amp;gt;
                          &amp;lt;div class="downloadIconPositioning"&amp;gt;
                            &amp;lt;a class="downloadLink"
                              href="/apk/{{item.id}}/"&amp;gt;
                              &amp;lt;i class="material-icons icon-blue" aria-hidden="true"&amp;gt;download&amp;lt;/i&amp;gt;
                            &amp;lt;/a&amp;gt;
                          &amp;lt;/div&amp;gt;
                        &amp;lt;/div&amp;gt;
                      &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                {% endfor %}
              &amp;lt;/div&amp;gt;
              &amp;lt;div class="listWidget"&amp;gt;
                &amp;lt;div class="box"&amp;gt;
                  &amp;lt;div class="title bread-crumbs"&amp;gt;
                    &amp;lt;h5 class="widgetHeader"&amp;gt;Popular In Last 30 Days&amp;lt;/h5&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                {% for item in info.hots[2].list %}
                &amp;lt;div&amp;gt;
                  &amp;lt;div class="appRow"&amp;gt;
                    &amp;lt;div class="table-row"&amp;gt;
                      &amp;lt;div style="width: 56px;" class="table-cell"&amp;gt;
                        &amp;lt;img style="width:50px; height:50px;"
                          src="https://img.idoras.com/img/{{item.id}}.png"&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div class="table-cell"&amp;gt;
                        &amp;lt;h5 title="{{item.name}} {{item.versionName}}" class="appRowTitle wrapText marginZero block-on-mobile"&amp;gt;
                          &amp;lt;a class="fontBlack" href="/apk/{{item.id}}/"&amp;gt;{{item.name}} {{item.versionName}}&amp;lt;/a&amp;gt;
                        &amp;lt;/h5&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div style="width: 50px; text-align: right;" class="table-cell"&amp;gt;
                        &amp;lt;span style="padding-right:12px;" class="colorLightBlack"&amp;gt;{{item.down}}&amp;lt;/span&amp;gt;
                      &amp;lt;/div&amp;gt;
                      &amp;lt;div style="width: 22px;" class="table-cell"&amp;gt;
                        &amp;lt;div class="iconsBox one-icon"&amp;gt;
                          &amp;lt;div class="downloadIconPositioning"&amp;gt;
                            &amp;lt;a class="downloadLink"
                              href="/apk/{{item.id}}/"&amp;gt;
                              &amp;lt;i class="material-icons icon-blue" aria-hidden="true"&amp;gt;download&amp;lt;/i&amp;gt;
                            &amp;lt;/a&amp;gt;
                          &amp;lt;/div&amp;gt;
                        &amp;lt;/div&amp;gt;
                      &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                  &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
                {% endfor %}
              &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="footer"&amp;gt;
        &amp;lt;div class="b"&amp;gt;
          &amp;lt;p&amp;gt;&amp;lt;a href="/about/"&amp;gt;About Us&amp;lt;/a&amp;gt; | &amp;lt;a href="/contact-us/"&amp;gt;Contact Us&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
          &amp;lt;p&amp;gt;&amp;lt;a href="/privacy-policy/" rel="nofollow"&amp;gt;Privacy Policy&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
          &amp;lt;p&amp;gt;&amp;lt;a href="/report-content/"&amp;gt;Report abuse&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
          &amp;lt;p&amp;gt;&amp;lt;a href="/dmca/" rel="nofollow"&amp;gt;DMCA Disclaimer&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
          &amp;lt;p&amp;gt;idoras.com © 2016-2021&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/main&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;script src="/js/material-components-web.min.js"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src="/js/app.js?v=20210805"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s the main code i wrote for the website, leave a comment if you want to know more about my code, at last remember the website address &lt;a href="https://idoras.com"&gt;https://idoras.com&lt;/a&gt; i built a week ago, and share it with your firends if you find it useful, thanks.&lt;/p&gt;

</description>
      <category>freeapkdownload</category>
    </item>
    <item>
      <title>字节跳动最常考的 64 道JS算法题</title>
      <dc:creator>fengmao</dc:creator>
      <pubDate>Fri, 09 Apr 2021 13:08:22 +0000</pubDate>
      <link>https://dev.to/fengmao/64-js-3loo</link>
      <guid>https://dev.to/fengmao/64-js-3loo</guid>
      <description>&lt;h2&gt;
  
  
  缘起
&lt;/h2&gt;

&lt;p&gt;现在大厂面试中，算法题几乎为必考项，且近几年频现 LeetCode 真题，此篇为拿到字节、腾讯、京东 Offer 的笔者本人在准备面试过程中亲自刷过以及遇到过高频算法题。文章内容会分模块整理，对于笔者在面试过程中遇到的真题，会给予着重 【🔥】标出。&lt;/p&gt;

&lt;p&gt;同时，可以毫不客气的说，如果你准备时间有限，又想追求算法题准备效率最大化，那么你只需要按照大纲把下面的题目刷完，并把代码烂熟于心，就几乎可以应对 90% 的面试算法考题了。&lt;/p&gt;

&lt;p&gt;整理这篇内容的目的一个是笔者在之前准备面试时的一点积累，而它确实也帮助笔者在面试算法题中过关斩将，同时呢，也希望能够在金三银四给予拼搏的你，一点点帮助就好！💪&lt;/p&gt;

&lt;p&gt;文末有福利 ：）😈&lt;/p&gt;

&lt;p&gt;本篇内容包括如下模块：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  高频算法题系列：链表&lt;/li&gt;
&lt;li&gt;  【🔥】【有真题】高频算法题系列：字符串&lt;/li&gt;
&lt;li&gt;  【🔥】【有真题】高频算法题系列：数组问题&lt;/li&gt;
&lt;li&gt;  高频算法题系列：二叉树&lt;/li&gt;
&lt;li&gt;  【🔥】高频算法题系列：排序算法&lt;/li&gt;
&lt;li&gt;  【🔥】高频算法题系列：二分查找&lt;/li&gt;
&lt;li&gt;  【🔥】高频算法题系列：动态规划&lt;/li&gt;
&lt;li&gt;  高频算法题系列：BFS&lt;/li&gt;
&lt;li&gt;  【🔥】高频算法题系列：栈&lt;/li&gt;
&lt;li&gt;  【🔥】高频算法题系列：DFS&lt;/li&gt;
&lt;li&gt;  【🔥】高频算法题系列：回溯算法&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;其中标🔥的部分代表非常高频的考题，其中不乏笔者遇到的原题。其中对于每一类，首先会列出包含的考题，然后针对每一道考题会给出难度、考察知识点、是否是面试真题，在每道题详细介绍时，还会给出每道题的 LeetCode 链接，帮助读者理解题意，以及能够进行实际的测验，还可以观看其他人的答案，更好的帮助准备。&lt;/p&gt;

&lt;h2&gt;
  
  
  高频算法题系列：链表
&lt;/h2&gt;

&lt;p&gt;笔者遇到的高频链表题主要包含这几道：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  通过链表的后续遍历判断回文链表问题 【简单】&lt;/li&gt;
&lt;li&gt;  链表的反向输出 【简单】&lt;/li&gt;
&lt;li&gt;  合并 K 个升序链表 【困难】&lt;/li&gt;
&lt;li&gt;  K个一组翻转链表 【困难】&lt;/li&gt;
&lt;li&gt;  环形链表 【简单】&lt;/li&gt;
&lt;li&gt;  排序链表 【中等】&lt;/li&gt;
&lt;li&gt;  相交链表 【简单】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  前序遍历判断回文链表
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/palindrome-linked-list/"&gt;【LeetCode 直通车】：234 回文链表（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解1
&lt;/h4&gt;

&lt;p&gt;利用链表的后续遍历，使用函数调用栈作为后序遍历栈，来判断是否回文&lt;/p&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
  *
  */
var isPalindrome = function(head) {
    let left = head;
    function traverse(right) {
        if (right == null) return true;
        let res = traverse(right.next);
        res = res &amp;amp;&amp;amp; (right.val === left.val);
        left = left.next;
        return res;
    }
    return traverse(head);
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  题解2
&lt;/h4&gt;

&lt;p&gt;通过 快、慢指针找链表中点，然后反转链表，比较两个链表两侧是否相等，来判断是否是回文链表&lt;/p&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
  *
  */
var isPalindrome = function(head) {
    // 反转 slower 链表
    let right = reverse(findCenter(head));
    let left = head;
    // 开始比较
    while (right != null) {
        if (left.val !== right.val) {
            return false;
        }
        left = left.next;
        right = right.next;
    }
    return true;
}
function findCenter(head) {
    let slower = head, faster = head;
    while (faster &amp;amp;&amp;amp; faster.next != null) {
        slower = slower.next;
        faster = faster.next.next;
    }
    // 如果 faster 不等于 null，说明是奇数个，slower 再移动一格
    if (faster != null) {
        slower = slower.next;
    }
    return slower;
}
function reverse(head) {
    let prev = null, cur = head, nxt = head;
    while (cur != null) {
        nxt = cur.next;
        cur.next = prev;
        prev = cur;
        cur = nxt;
    }
    return prev;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  反转链表
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/reverse-linked-list/"&gt;【LeetCode 直通车】：206 反转链表（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * 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 == null || head.next == null) return head;
    let last = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return last;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  合并K个升序链表
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/merge-k-sorted-lists/"&gt;【LeetCode 直通车】：23 合并K个升序链表（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 */
var mergeKLists = function(lists) {
    if (lists.length === 0) return null;
    return mergeArr(lists);
};
function mergeArr(lists) {
    if (lists.length &amp;lt;= 1) return lists[0];
    let index = Math.floor(lists.length / 2);
    const left = mergeArr(lists.slice(0, index))
    const right = mergeArr(lists.slice(index));
    return merge(left, right);
}
function merge(l1, l2) {
    if (l1 == null &amp;amp;&amp;amp; l2 == null) return null;
    if (l1 != null &amp;amp;&amp;amp; l2 == null) return l1;
    if (l1 == null &amp;amp;&amp;amp; l2 != null) return l2;
    let newHead = null, head = null;
    while (l1 != null &amp;amp;&amp;amp; l2 != null) {
        if (l1.val &amp;lt; l2.val) {
            if (!head) {
                newHead = l1;
                head = l1;
            } else {
                newHead.next = l1;
                newHead = newHead.next;
            }
            l1 = l1.next;
        } else {
            if (!head) {
                newHead = l2;
                head = l2;
            } else {
                newHead.next = l2;
                newHead = newHead.next;
            }
            l2 = l2.next;
        }
    }
    newHead.next = l1 ? l1 : l2;
    return head;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  K 个一组翻转链表
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/reverse-nodes-in-k-group/"&gt;【LeetCode 直通车】：25 K 个一组翻转链表（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var reverseKGroup = function(head, k) {
    let a = head, b = head;
    for (let i = 0; i &amp;lt; k; i++) {
        if (b == null) return head;
        b = b.next;
    }
    const newHead = reverse(a, b);
    a.next = reverseKGroup(b, k);
    return newHead;
};
function reverse(a, b) {
    let prev = null, cur = a, nxt = a;
    while (cur != b) {
        nxt = cur.next;
        cur.next = prev;
        prev = cur;
        cur = nxt;
    }
    return prev;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  环形链表
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/linked-list-cycle/"&gt;【LeetCode 直通车】：141 环形链表（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * 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 slower = head, faster = head;
    while (faster != null &amp;amp;&amp;amp; faster.next != null) {
        slower = slower.next;
        faster = faster.next.next;
        if (slower === faster) return true;
    }
    return false;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  排序链表
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/sort-list/"&gt;【LeetCode 直通车】：148 排序链表（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var sortList = function(head) {
    if (head == null) return null;
    let newHead = head;
    return mergeSort(head);
};
function mergeSort(head) {
    if (head.next != null) {
        let slower = getCenter(head);
        let nxt = slower.next;
        slower.next = null;
        console.log(head, slower, nxt);
        const left = mergeSort(head);
        const right = mergeSort(nxt);
        head = merge(left, right);
    }
    return head;
}
function merge(left, right) {
    let newHead = null, head = null;
    while (left != null &amp;amp;&amp;amp; right != null) {
        if (left.val &amp;lt; right.val) {
            if (!head) {
                newHead = left;
                head = left;
            } else {
                newHead.next = left;
                newHead = newHead.next;
            }
            left = left.next;
        } else {
            if (!head) {
                newHead = right;
                head = right;
            } else {
                newHead.next = right;
                newHead = newHead.next;
            }
            right = right.next;
        }
    }
    newHead.next = left ? left : right;
    return head;
}
function getCenter(head) {
    let slower = head, faster = head.next;
    while (faster != null &amp;amp;&amp;amp; faster.next != null) {
        slower = slower.next;
        faster = faster.next.next;
    }
    return slower;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  相交链表
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/intersection-of-two-linked-lists/"&gt;【LeetCode 直通车】：160 相交链表（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    let lastHeadA = null;
    let lastHeadB = null;
    let originHeadA = headA;
    let originHeadB = headB;
    if (!headA || !headB) {
        return null;
    }
    while (true) {
        if (headB == headA) {
            return headB;
        }
        if (headA &amp;amp;&amp;amp; headA.next == null) {
            lastHeadA = headA;
            headA = originHeadB;
        } else {
            headA = headA.next;
        }
        if (headB &amp;amp;&amp;amp; headB.next == null) {
            lastHeadB = headB
            headB = originHeadA;
        } else {
            headB = headB.next;
        }
        if (lastHeadA &amp;amp;&amp;amp; lastHeadB &amp;amp;&amp;amp; lastHeadA != lastHeadB) {
            return null;
        }
    }
    return null;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  【🔥】高频算法题系列：字符串
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  最长回文子串 【中等】【双指针】【面试真题】&lt;/li&gt;
&lt;li&gt;  最长公共前缀 【简单】【双指针】&lt;/li&gt;
&lt;li&gt;  无重复字符的最长子串【中等】【双指针】&lt;/li&gt;
&lt;li&gt;  最小覆盖子串 【困难】【滑动窗口】【面试真题】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  【面试真题】最长回文子串【双指针】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/longest-palindromic-substring/"&gt;【LeetCode 直通车】：5 最长回文子串（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
    if (s.length === 1) return s;
    let maxRes = 0, maxStr = '';
    for (let i = 0; i &amp;lt; s.length; i++) {
        let str1 = palindrome(s, i, i);
        let str2 = palindrome(s, i, i + 1);   
        if (str1.length &amp;gt; maxRes) {
            maxStr = str1;
            maxRes = str1.length;
        }
        if (str2.length &amp;gt; maxRes) {
            maxStr = str2;
            maxRes = str2.length;
        }
    }
    return maxStr;
};
function palindrome(s, l, r) {
    while (l &amp;gt;= 0 &amp;amp;&amp;amp; r &amp;lt; s.length &amp;amp;&amp;amp; s[l] === s[r]) {
        l--;
        r++;
    }
    return s.slice(l + 1, r);
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  最长公共前缀【双指针】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/longest-common-prefix/"&gt;【LeetCode 直通车】：14 最长公共前缀（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string[]} strs
 * @return {string}
 */
var longestCommonPrefix = function(strs) {
    if (strs.length === 0) return "";
    let first = strs[0];
    if (first === "") return "";
    let minLen = Number.MAX_SAFE_INTEGER;
    for (let i = 1; i &amp;lt; strs.length; i++) {
        const len = twoStrLongestCommonPrefix(first, strs[i]);
        minLen = Math.min(len, minLen);
    }
    return first.slice(0, minLen);
};
function twoStrLongestCommonPrefix (s, t) {
    let i = 0, j = 0;
    let cnt = 0;
    while (i &amp;lt; s.length &amp;amp;&amp;amp; j &amp;lt; t.length) {
        console.log(s[i], t[j], cnt)
        if (s[i] === t[j])  {
            cnt++;
        } else {
            return cnt;
        }
        i++;
        j++;
    }
    return cnt;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  无重复字符的最长子串【双指针】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/"&gt;【LeetCode 直通车】：3 无重复字符的最长子串（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  let window = {};
  let left = 0, right = 0;
  let maxLen = 0, maxStr = '';
  while (right &amp;lt; s.length) {
    let c = s[right];
    right++;
    if (window[c]) window[c]++;
    else window[c] = 1
    while (window[c] &amp;gt; 1) {
      let d = s[left];
      left++;
      window[d]--;
    }
    if (maxLen &amp;lt; right - left) {
      maxLen = right - left;
    }
  }
  return maxLen;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】 最小覆盖子串【滑动窗口】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/minimum-window-substring/"&gt;【LeetCode 直通车】：76 最小覆盖子串（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function(s, t) {
    let need = {}, window = {};
    for (let c of t) {
        if (!need[c]) need[c] = 1;
        else need[c]++;
    }
    let left = 0, right = 0;
    let valid = 0, len = Object.keys(need).length;
    let minLen = s.length + 1, minStr = '';
    while (right &amp;lt; s.length) {
        const d = s[right];
        right++;
        if (!window[d]) window[d] = 1;
        else window[d]++;
        if (need[d] &amp;amp;&amp;amp; need[d] === window[d]) {
            valid++;
        }
        console.log('left - right', left, right);
        while (valid === len) {
            if (right - left &amp;lt; minLen) {
                minLen = right - left;
                minStr = s.slice(left, right);
            }
            console.lo
            let c = s[left];
            left++;
            window[c]--;
            if (need[c] &amp;amp;&amp;amp; window[c] &amp;lt; need[c]) {
                valid--;
            }
        }
    }
    return minStr;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  【🔥】高频算法题系列：数组问题
&lt;/h2&gt;

&lt;p&gt;主要有几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  俄罗斯套娃信封问题【困难】【排序+最长上升子序列】【面试真题】&lt;/li&gt;
&lt;li&gt;  最长连续递增序列 【简单】【双指针】&lt;/li&gt;
&lt;li&gt;  最长连续序列【困难】【哈希表】&lt;/li&gt;
&lt;li&gt;  盛最多水的容器【困难】【面试真题】&lt;/li&gt;
&lt;li&gt;  寻找两个正序数组的中位数【困难】【双指针】&lt;/li&gt;
&lt;li&gt;  删除有序数组中的重复项【简单】【快慢指针】&lt;/li&gt;
&lt;li&gt;  和为K的子数组【中等】【哈希表】&lt;/li&gt;
&lt;li&gt;  nSum 问题【系列】【简单】【哈希表】&lt;/li&gt;
&lt;li&gt;  接雨水【困难】【暴力+备忘录优化】【面试真题】&lt;/li&gt;
&lt;li&gt;  跳跃游戏【系列】【中等】【贪心算法】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  【面试真题】俄罗斯套娃信封问题【排序+最长上升子序列】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/russian-doll-envelopes/"&gt;【LeetCode 直通车】：354 俄罗斯套娃信封问题（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[][]} envelopes
 * @return {number}
 */
var maxEnvelopes = function(envelopes) {
  if (envelopes.length === 1) return 1;
    envelopes.sort((a, b) =&amp;gt; {
        if (a[0] !== b[0]) return a[0] - b[0];
        else return b[1] - a[1];
    });
    let LISArr = [];
    for (let [key, value] of envelopes) {
      LISArr.push(value);
    }
    console.log( LISArr);
    return LIS(LISArr);
};
function LIS(arr) {
  let dp = [];
  let maxAns = 0;
  for (let i = 0; i &amp;lt; arr.length; i++) {
    dp[i] = 1;
  }
  for (let i = 1; i &amp;lt; arr.length; i++) {
    for (let j = i; j &amp;gt;= 0; j--) {
      if (arr[i] &amp;gt; arr[j]) {
        dp[i] = Math.max(dp[i], dp[j] + 1)
      }
      maxAns = Math.max(maxAns, dp[i]);
    }
  }
  return maxAns;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  最长连续递增序列【快慢指针】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/"&gt;【LeetCode 直通车】：674 最长连续递增序列（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {number}
 */
var findLengthOfLCIS = function(nums) {
    if (nums.length === 0) return 0;
    const n = nums.length;
    let left = 0, right = 1;
    let globalMaxLen = 1, maxLen = 1;
    while (right &amp;lt; n) {
        if (nums[right] &amp;gt; nums[left]) maxLen++;
        else {
            maxLen = 1;
        }
        left++;
        right++;
        globalMaxLen = Math.max(globalMaxLen, maxLen);
    }
    return globalMaxLen;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  最长连续序列 【哈希表】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/longest-consecutive-sequence/"&gt;【LeetCode 直通车】：128 最长连续序列（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {number}
 */
var longestConsecutive = function(nums) {
    if (nums.length === 0) return 0;
    const set = new Set(nums);
    const n = nums.length;
    let globalLongest = 1;
    for (let i = 0; i &amp;lt; n; i++) {
        if (!set.has(nums[i] - 1)) {
            let longest = 1;
            let currentNum = nums[i];
            while (set.has(currentNum + 1)) {
                currentNum += 1;
                longest++;
            }
            globalLongest = Math.max(globalLongest, longest);
        }
    }
    return globalLongest;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】盛最多水的容器【哈希表】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/container-with-most-water/"&gt;【LeetCode 直通车】：11 盛最多水的容器（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    let n = height.length;
    let left = 0, right = n - 1;
    let maxOpacity = 0;
    while (left &amp;lt; right) {
        let res = Math.min(height[left], height[right]) * (right - left);
        maxOpacity = Math.max(maxOpacity, res);
        if (height[left] &amp;lt; height[right]) left++
        else right--;
    }
    return maxOpacity;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  寻找两个正序数组的中位数【双指针】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/median-of-two-sorted-arrays/"&gt;【LeetCode 直通车】：4 寻找两个正序数组的中位数（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    let m = nums1.length, n = nums2.length;
    let i = 0, j = 0;
    let newArr = [];
    while (i &amp;lt; m &amp;amp;&amp;amp; j &amp;lt; n) {
        if (nums1[i] &amp;lt; nums2[j]) {
            newArr.push(nums1[i++]);
        } else {
            newArr.push(nums2[j++]);
        }
    }
    newArr = newArr.concat(i &amp;lt; m ? nums1.slice(i) : nums2.slice(j));
    const len = newArr.length;
    console.log(newArr)
    if (len % 2 === 0) {
        return (newArr[len / 2] + newArr[len / 2 - 1]) / 2;
    } else {
        return newArr[Math.floor(len / 2)];
    }
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  删除有序数组中的重复项【快慢指针】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/"&gt;【LeetCode 直通车】：26 删除有序数组中的重复项（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
  if (nums.length &amp;lt;= 1) return nums.length;
  let lo = 0, hi = 0;
  while (hi &amp;lt; nums.length) {
    while (nums[lo] === nums[hi] &amp;amp;&amp;amp; hi &amp;lt; nums.length) hi++;
    if (nums[lo] !== nums[hi] &amp;amp;&amp;amp; hi &amp;lt; nums.length) {
      lo++;
      nums[lo] = nums[hi];
    }
    hi++;
  }
  return lo + 1;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  和为K的子数组【哈希表】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/subarray-sum-equals-k/"&gt;【LeetCode 直通车】：560 和为K的子数组（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var subarraySum = function(nums, k) {
    let cnt = 0;
    let sum0_i = 0, sum0_j = 0;
    let map = new Map();
    map.set(0, 1);
    for (let i = 0; i &amp;lt;= nums.length; i++) {
        sum0_i += nums[i];
        sum0_j = sum0_i - k;
        console.log('map', sum0_j, map.get(sum0_j))
        if (map.has(sum0_j)) {
            cnt += map.get(sum0_j);
        }
        let sumCnt = map.get(sum0_i) || 0;
        map.set(sum0_i, sumCnt + 1);
    }
    return cnt;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  nSum问题【哈希表】【系列】
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/two-sum/"&gt;【LeetCode 直通车】：1 两数之和（简单）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/"&gt;【LeetCode 直通车】：167 两数之和 II - 输入有序数组（简单）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/3sum/"&gt;【LeetCode 直通车】：15 三数之和（中等）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/4sum/"&gt;【LeetCode 直通车】：18 四数之和（中等）&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;受限于篇幅，这里只给出第一道题的代码模板，也是一面常考真题。&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
  let map2 = new Map();
  for (let i = 0; i &amp;lt; nums.length; i++) {
    map2.set(nums[i], i);
  }
  for (let i = 0; i &amp;lt; nums.length; i++) {
    if (map2.has(target - nums[i]) &amp;amp;&amp;amp; map2.get(target - nums[i]) !== i) return [i, map2.get(target - nums[i])]
  }
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】接雨水【暴力+备忘录优化】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/trapping-rain-water/"&gt;【LeetCode 直通车】：42 接雨水（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} height
 * @return {number}
 */
var trap = function(height) {
    let l_max = [], r_max = [];
    let len = height.length;
    let maxCapacity = 0;
    for (let i = 0; i &amp;lt; len; i++) {
        l_max[i] = height[i];
        r_max[i] = height[i];
    }
    for (let i = 1; i &amp;lt; len; i++) {
        l_max[i] = Math.max(l_max[i - 1], height[i]);
    }
    for (let j = len - 2; j &amp;gt;= 0; j--) {
        r_max[j] = Math.max(r_max[j + 1], height[j]);
    }
    for (let i = 0; i &amp;lt; len; i++) {
        maxCapacity += Math.min(l_max[i], r_max[i]) - height[i];
    }
    return maxCapacity;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  跳跃游戏【贪心算法】【系列】
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/jump-game/"&gt;【LeetCode 直通车】：55 跳跃游戏（中等）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/jump-game-ii/"&gt;【LeetCode 直通车】：45 跳跃游戏 II（中等）&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;受限于篇幅，这里只给出第一道题的代码模板，也是一面常考真题。&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {boolean}
 */
var canJump = function(nums) {
    let faster = 0;
    for (let i = 0; i &amp;lt; nums.length - 1; i++) {
        faster = Math.max(faster, i + nums[i]);
        if (faster &amp;lt;= i) return false;
    }
    return faster &amp;gt;= nums.length - 1;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  高频算法题系列：二叉树
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  二叉树的最近公共祖先【简单】【二叉树】&lt;/li&gt;
&lt;li&gt;  二叉搜索树中的搜索【简单】【二叉树】&lt;/li&gt;
&lt;li&gt;  删除二叉搜索树中的节点【中等】【二叉树】&lt;/li&gt;
&lt;li&gt;  完全二叉树的节点个数【中等】【二叉树】&lt;/li&gt;
&lt;li&gt;  二叉树的锯齿形层序遍历【中等】【二叉树】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  二叉树的最近公共祖先【二叉树】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/"&gt;【LeetCode 直通车】：236 二叉树的最近公共祖先（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
let visited;let parent;
var lowestCommonAncestor = function(root, p, q) {
    visited = new Set();
    parent = new Map();
    dfs(root);
    while (p != null) {
        visited.add(p.val);
        p = parent.get(p.val);
    }
    while (q != null) {
        if (visited.has(q.val)) {
            return q;
        }
        q = parent.get(q.val);
    }
    return null;
};
function dfs(root) {
    if (root.left != null) {
        parent.set(root.left.val, root);
        dfs(root.left);
    }
    if (root.right != null) {
        parent.set(root.right.val, root);
        dfs(root.right);
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  二叉搜索树中的搜索【二叉树】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/search-in-a-binary-search-tree/"&gt;【LeetCode 直通车】：700 二叉搜索树中的搜索（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} val
 * @return {TreeNode}
 */
var searchBST = function(root, val) {
    if (root == null) return null;
    if (root.val === val) return root;
    if (root.val &amp;gt; val) {
        return searchBST(root.left, val);
    } else if (root.val &amp;lt; val) {
        return searchBST(root.right, val);
    }
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  删除二叉搜索树中的节点【二叉树】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/delete-node-in-a-bst/"&gt;【LeetCode 直通车】：450 删除二叉搜索树中的节点（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} key
 * @return {TreeNode}
 */
var deleteNode = function(root, key) {
    if (root == null) return null;
    if (root.val === key) {
        if (root.left == null &amp;amp;&amp;amp; root.right == null) return null;
        if (root.left == null) return root.right;
        if (root.right == null) return root.left;
        if (root.left != null &amp;amp;&amp;amp; root.right != null)  {
            let target = getMinTreeMaxNode(root.left);
            root.val = target.val;
            root.left = deleteNode(root.left, target.val);
        }
    }
    if (root.val &amp;lt; key) {
        root.right = deleteNode(root.right, key);
    } else if (root.val &amp;gt; key) {
        root.left = deleteNode(root.left, key);
    }
    return root;
};
function getMinTreeMaxNode(root) {
    if (root.right == null) return root;
    return getMinTreeMaxNode(root.right);
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  完全二叉树的节点个数【二叉树】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/count-complete-tree-nodes/"&gt;【LeetCode 直通车】：222 完全二叉树的节点个数（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var countNodes = function(root) {
    if (root == null) return 0;
    let l = root, r = root;
    let lh = 0, rh = 0;
    while (l != null) {
      l = l.left;
      lh++;
    }
    while (r != null) {
      r = r.right;
      rh++;
    }
    if (lh === rh) {
      return Math.pow(2, lh) - 1;
    }
    return 1 + countNodes(root.left) + countNodes(root.right);
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  二叉树的锯齿形层序遍历【二叉树】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/"&gt;【LeetCode 直通车】：103 二叉树的锯齿形层序遍历（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
let res;
var zigzagLevelOrder = function(root) {
    if (root == null) return [];
    res = [];
    BFS(root, true);
    return res;
};
function BFS(root, inOrder) {
    let arr = [];
    let resItem = [];
    let node;
    let stack1 = new Stack();
    let stack2 = new Stack();
    // 判断交换时机
    let flag;
    stack1.push(root);
    res.push([root.val]);
    inOrder = !inOrder;
    while (!stack1.isEmpty() || !stack2.isEmpty()) {
        if (stack1.isEmpty()) {
            flag = 'stack1';
        } else if (stack2.isEmpty()) {
            flag = 'stack2';
        }
        // 决定取那个栈里面的元素
        if (flag === 'stack2' &amp;amp;&amp;amp; !stack1.isEmpty()) node = stack1.pop();
        else if (flag === 'stack1' &amp;amp;&amp;amp; !stack2.isEmpty()) node = stack2.pop();
        if (inOrder) {
            if (node.left) {
                if (flag === 'stack1') {
                    stack1.push(node.left);
                } else {
                    stack2.push(node.left);
                }
                resItem.push(node.left.val);
            }
            if (node.right) {
                if (flag === 'stack1') {
                    stack1.push(node.right);
                } else {
                    stack2.push(node.right);
                }
                resItem.push(node.right.val);
            }
        } else {
            if (node.right) {
                if (flag === 'stack1') {
                    stack1.push(node.right);
                } else {
                    stack2.push(node.right);
                }
                resItem.push(node.right.val);
            }
            if (node.left) {
                if (flag === 'stack1') {
                    stack1.push(node.left);
                } else {
                    stack2.push(node.left);
                }
                resItem.push(node.left.val);
            }
        }
        // 判断下次翻转的时机
        if ((flag === 'stack2' &amp;amp;&amp;amp; stack1.isEmpty()) || (flag === 'stack1' &amp;amp;&amp;amp; stack2.isEmpty())) {
            inOrder = !inOrder;
            // 需要翻转了，就加一轮值
            if (resItem.length &amp;gt; 0) {
                res.push(resItem);
            }   
            resItem = [];
        }
    }
}
class Stack {
    constructor() {
        this.count = 0;
        this.items = [];
    }
    push(element) {
        this.items[this.count] = element;
        this.count++;
    }
    pop() {
        if (this.isEmpty()) return undefined;
        const element = this.items[this.count - 1];
        delete this.items[this.count - 1];
        this.count--;
        return element;
    }
    size() {
        return this.count;
    }
    isEmpty() {
        return this.size() === 0;
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  【🔥】高频算法题系列：排序算法
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  用最少数量的箭引爆气球【中等】【排序】&lt;/li&gt;
&lt;li&gt;  合并区间【中等】【排序算法+区间问题】【面试真题】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  用最少数量的箭引爆气球【排序算法】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/"&gt;【LeetCode 直通车】：452 用最少数量的箭引爆气球（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[][]} points
 * @return {number}
 */
var findMinArrowShots = function(points) {
    if (points.length === 0) return 0;
    points.sort((a, b) =&amp;gt; a[1] - b[1]);
    let cnt = 1;
    let resArr = [points[0]];
    let curr, last;
    for (let i = 1; i &amp;lt; points.length; i++) {
        curr = points[i];
        last = resArr[resArr.length - 1];
        if (curr[0] &amp;gt; last[1]) {
            resArr.push(curr);
            cnt++;
        }
    }
    return cnt;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  合并区间【排序算法+区间问题】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/merge-intervals/"&gt;【LeetCode 直通车】：56 合并区间（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[][]} intervals
 * @return {number[][]}
 */
var merge = function(intervals) {
    if (intervals.length === 0) return [];
    intervals.sort((a, b) =&amp;gt; a[0] - b[0]);
    let mergeArr = [intervals[0]];
    let last, curr;
    for (let j = 1; j &amp;lt; intervals.length; j++) {
        last = mergeArr[mergeArr.length - 1];
        curr = intervals[j];
        if (last[1] &amp;gt;= curr[0]) {
            last[1] = Math.max(curr[1], last[1]);
        } else {
            mergeArr.push(curr);
        }
    }
    return mergeArr;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  高频算法题系列：二分查找
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  寻找两个正序数组的中位数【困难】【二分查找】&lt;/li&gt;
&lt;li&gt;  判断子序列【简单】【二分查找】&lt;/li&gt;
&lt;li&gt;  在排序数组中查找元素的第一个和最后一个位置【中等】【二分查找】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  寻找两个正序数组的中位数【二分查找】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/median-of-two-sorted-arrays/"&gt;【LeetCode 直通车】：4 寻找两个正序数组的中位数（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    let m = nums1.length, n = nums2.length;
    let i = 0, j = 0;
    let newArr = [];
    while (i &amp;lt; m &amp;amp;&amp;amp; j &amp;lt; n) {
        if (nums1[i] &amp;lt; nums2[j]) {
            newArr.push(nums1[i++]);
        } else {
            newArr.push(nums2[j++]);
        }
    }
    newArr = newArr.concat(i &amp;lt; m ? nums1.slice(i) : nums2.slice(j));
    const len = newArr.length;
    console.log(newArr)
    if (len % 2 === 0) {
        return (newArr[len / 2] + newArr[len / 2 - 1]) / 2;
    } else {
        return newArr[Math.floor(len / 2)];
    }
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  判断子序列【二分查找】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/is-subsequence/"&gt;【LeetCode 直通车】：392 判断子序列（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isSubsequence = function(s, t) {
    let hash = {};
    for (let i = 0; i &amp;lt; t.length; i++) {
        if (!hash[t[i]]) hash[t[i]] = [];
        hash[t[i]].push(i);
    }
    let lastMaxIndex = 0;
    for (let i = 0; i &amp;lt; s.length; i++) {
        if (hash[s[i]]) {
            const index = binarySearch(hash[s[i]], lastMaxIndex);
            console.log('index', index, hash[s[i]]);
            if (index === -1) return false;
            lastMaxIndex = hash[s[i]][index] + 1;
        } else return false;
    }
    return true;
};
function binarySearch(array, targetIndex) {
    let left = 0, right = array.length;
    while (left &amp;lt; right) {
        let mid = left + Math.floor((right - left) / 2);
        if (array[mid] &amp;gt;= targetIndex) {
            right = mid;
        } else if (array[mid] &amp;lt; targetIndex) {
            left = mid + 1;
        }
    }
    if (left &amp;gt;= array.length || array[left] &amp;lt; targetIndex) return -1;
    return left;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  💁 在排序数组中查找元素的第一个和最后一个位置【二分搜索】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/"&gt;【LeetCode 直通车】：34 在排序数组中查找元素的第一个和最后一个位置（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    const left = leftBound(nums, target);
    const right = rightBound(nums, target);
    return [left, right];
};
function leftBound(nums, target) {
    let left = 0;
    let right = nums.length - 1;
    while (left &amp;lt;= right) {
        let mid = Math.floor(left + (right - left) / 2);
        if (nums[mid] === target) {
            right = mid - 1;
        } else if (nums[mid] &amp;lt; target) {
            left = mid + 1;
        } else if (nums[mid] &amp;gt; target) {
            right = mid - 1;
        }
    }
    if (left &amp;gt;= nums.length || nums[left] !== target) {
        return -1;
    }
    return left;
}
function rightBound(nums, target) {
    let left = 0;
    let right = nums.length - 1;
    while (left &amp;lt;= right) {
        let mid = Math.floor(left + (right - left) / 2);
        if (nums[mid] === target) {
            left = mid + 1;
        } else if (nums[mid] &amp;lt; target) {
            left = mid + 1;
        } else if (nums[mid] &amp;gt; target) {
            right = mid - 1;
        }
    }
    if (right &amp;lt; 0 || nums[right] !== target) {
        return -1;
    }
    return right;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  【🔥】高频算法题系列：动态规划
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  最长递增子序列【中等】【动态规划】&lt;/li&gt;
&lt;li&gt;  零钱兑换【中等】【动态规划】【面试真题】&lt;/li&gt;
&lt;li&gt;  最长公共子序列 【中等】【动态规划】【面试真题】&lt;/li&gt;
&lt;li&gt;  编辑距离 【困难】【动态规划】&lt;/li&gt;
&lt;li&gt;  最长回文子序列【中等】【动态规划】【面试真题】&lt;/li&gt;
&lt;li&gt;  最大子序和【简单】【动态规划】【面试真题】&lt;/li&gt;
&lt;li&gt;  买卖股票的最佳时机系列【系列】【动态规划】【面试真题】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  最长递增子序列【动态规划】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/longest-increasing-subsequence/"&gt;【LeetCode 直通车】：300 最长递增子序列（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {number}
 */
var lengthOfLIS = function(nums) {
    let maxLen = 0, n = nums.length;
    let dp = [];
    for (let i = 0; i &amp;lt; n; i++) {
        dp[i] = 1;
    }
    for (let i = 0; i &amp;lt; n; i++) {
        for (let j = 0; j &amp;lt; i; j++) {
            if (nums[i] &amp;gt; nums[j]) {
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
        maxLen = Math.max(maxLen, dp[i]);
    }
    return maxLen;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】 零钱兑换【动态规划】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/coin-change/"&gt;【LeetCode 直通车】：322 零钱兑换（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} coins
 * @param {number} amount
 * @return {number}
 */
var coinChange = function(coins, amount) {
  if (amount === 0) return 0;
  let dp = [];
  for (let i = 0; i &amp;lt;= amount; i++) {
    dp[i] = amount + 1;
  }
  dp[0] = 0;
  for (let i = 0; i &amp;lt;= amount; i++) {
    for (let j = 0; j &amp;lt; coins.length; j++) {
      if (i &amp;gt;= coins[j]) {
        dp[i] = Math.min(dp[i - coins[j]] + 1, dp[i])
      }
    }
  }
  return dp[amount] === amount + 1 ? -1 : dp[amount];
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】 最长公共子序列【动态规划】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/longest-common-subsequence/"&gt;【LeetCode 直通车】：1143 最长公共子序列（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} text1
 * @param {string} text2
 * @return {number}
 */
var longestCommonSubsequence = function(text1, text2) {
    let n1 = text1.length, n2 = text2.length;
    let dp = [];
    for (let i = -1; i &amp;lt; n1; i++) {
        dp[i] = [];
        for (let j = -1; j &amp;lt; n2;j++) {
            dp[i][j] = 0;
        }
    }
    for (let i = 0; i &amp;lt; n1; i++) {
        for (let j = 0; j &amp;lt; n2; j++) {
            if (text1[i] === text2[j]) {
                dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1);
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])
            }
        }
    }
    return dp[n1 - 1][n2 - 1];
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  编辑距离【动态规划】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/edit-distance/"&gt;【LeetCode 直通车】：72 编辑距离（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} word1
 * @param {string} word2
 * @return {number}
 */
var minDistance = function(word1, word2) {
  let len1 = word1.length, len2 = word2.length;
  let dp = [];
  for (let i = 0; i &amp;lt;= len1; i++) {
    dp[i] = [];
    for (let j = 0; j &amp;lt;= len2; j++) {
      dp[i][j] = 0;
      if (i === 0) {
        dp[i][j] = j;
      }
      if (j === 0) {
        dp[i][j] = i;
      }
    }
  }
  for (let i = 1; i &amp;lt;= len1; i++) {
    for (let j = 1; j &amp;lt;= len2; j++) {
      if (word1[i - 1] === word2[j - 1]) {
        dp[i][j] = dp[i - 1][j - 1];
      } else {
        dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + 1);
      }
    }
  }
  return dp[len1][len2];
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】最长回文子序列【动态规划】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/longest-palindromic-subsequence/"&gt;【LeetCode 直通车】：516 最长回文子序列（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} s
 * @return {number}
 */
var longestPalindromeSubseq = function(s) {
    let dp = [];
    for (let i = 0; i &amp;lt; s.length; i++) {
        dp[i] = [];
        for (let j = 0; j &amp;lt; s.length; j++) {
            dp[i][j] = 0;
        }
        dp[i][i] = 1;
    }
    for (let i = s.length - 1; i &amp;gt;= 0; i--) {
        for (let j = i + 1; j &amp;lt; s.length; j++) {
            if (s[i] === s[j]) {
                dp[i][j] = dp[i + 1][j - 1] + 2;
            } else {
                dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[0][s.length - 1];
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】💁 最大子序和【动态规划】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/maximum-subarray/"&gt;【LeetCode 直通车】：53 最大子序和（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    let maxSum = -Infinity;
    let dp = [], n = nums.length;
    for (let i = -1; i &amp;lt; n; i++) {
        dp[i] = 0;
    }
    for (let i = 0; i &amp;lt; n; i++) {
        dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);
        maxSum = Math.max(maxSum, dp[i]);
    }
    return maxSum;
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】💁 买卖股票的最佳时机【动态规划】
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/container-with-most-water/"&gt;【LeetCode 直通车】：121 买卖股票的最佳时机（简单）&lt;/a&gt;【面试真题】&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/"&gt;【LeetCode 直通车】：122 买卖股票的最佳时机 II（简单）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/"&gt;【LeetCode 直通车】：123 买卖股票的最佳时机 III（困难）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/container-with-most-water/"&gt;【LeetCode 直通车】：188 买卖股票的最佳时机IV（困难）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/"&gt;【LeetCode 直通车】：309 买卖股票的最佳时机含冷冻期（中等）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/"&gt;【LeetCode 直通车】：714 买卖股票的最佳时机含手续费（中等）&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;受限于篇幅，这里只给出第一道题的代码模板，也是一面常考真题，笔者在面试字节跳动时就遇到过。&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  let dp = [];
  for (let i = -1; i &amp;lt; prices.length; i++) {
    dp[i] = []
    for (let j = 0; j &amp;lt;= 1; j++) {
      dp[i][j] = [];
      dp[i][j][0] = 0;
      dp[i][j][1] = 0;
      if (i === -1) {
        dp[i][j][1] = -Infinity;
      }
      if (j === 0) {
        dp[i][j][1] = -Infinity;
      }
      if (j === -1) {
        dp[i][j][1] = -Infinity;
      }
    }
  }
  for (let i = 0; i &amp;lt; prices.length; i++) {
    for (let j = 1; j &amp;lt;= 1; j++) {
      dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
      dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
    }
  }
  return dp[prices.length - 1][1][0];
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  高频算法题系列：BFS
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  打开转盘锁【中等】【BFS】&lt;/li&gt;
&lt;li&gt;  二叉树的最小深度【简单】【BFS】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  打开转盘锁【BFS】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/open-the-lock/"&gt;【LeetCode 直通车】：752 打开转盘锁（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string[]} deadends
 * @param {string} target
 * @return {number}
 */
var openLock = function(deadends, target) {
  let queue = new Queue();
  let visited = new Set();
  let step = 0;
  queue.push('0000');
  visited.add('0000');
  while (!queue.isEmpty()) {
    let size = queue.size();
    for (let i = 0; i &amp;lt; size; i++) {
      let str = queue.pop();
      if (deadends.includes(str)) continue;
      if (target === str) {
        return step;
      }
      for (let j = 0; j &amp;lt; 4; j++) {
        let plusStr = plusOne(str, j);
        let minusStr = minusOne(str, j);
        if (!visited.has(plusStr)) {
          queue.push(plusStr);
          visited.add(plusStr)
        }
        if (!visited.has(minusStr)) {
          queue.push(minusStr);
          visited.add(minusStr)
        }
      }
    }
    step++;
  }
  return -1;
};
function plusOne(str, index) {
  let strArr = str.split('');
  if (strArr[index] === '9') {
    strArr[index] = '0'
  } else {
    strArr[index] = (Number(strArr[index]) + 1).toString()
  }
  return strArr.join('');
}
function minusOne(str, index) {
  let strArr = str.split('');
  if (strArr[index] === '0') {
    strArr[index] = '9'
  } else {
    strArr[index] = (Number(strArr[index]) - 1).toString()
  }
  return strArr.join('');
}
class Queue {
  constructor() {
    this.items = [];
    this.count = 0;
    this.lowerCount = 0;
  }
  push(elem) {
    this.items[this.count++] = elem;
  }
  pop() {
    if (this.isEmpty()) {
      return;
    }
    const elem = this.items[this.lowerCount];
    delete this.items[this.lowerCount];
    this.lowerCount++;
    return elem;
  }
  isEmpty() {
    if (this.size() === 0) return true;
    return false;
  }
  size() {
    return this.count - this.lowerCount;
  }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  二叉树的最小深度【BFS】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/"&gt;【LeetCode 直通车】：111 二叉树的最小深度（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var minDepth = function(root) {
  if (root == null) return 0;
  let depth = 1;
  let queue = new Queue();
  queue.push(root);
  while (!queue.isEmpty()) {
    let size = queue.size();
    for (let i = 0; i &amp;lt; size; i++) {
      const node = queue.pop();
      if (node.left == null &amp;amp;&amp;amp; node.right == null) return depth;
      if (node.left) {
        queue.push(node.left);
      }
      if (node.right) {
        queue.push(node.right);
      }
    }
    depth++;
  }
  return depth;
};
class Queue {
  constructor() {
    this.items = [];
    this.count = 0;
    this.lowerCount = 0;
  }
  push(elem) {
    this.items[this.count++] = elem;
  }
  pop() {
    if (this.isEmpty()) {
      return;
    }
    const elem = this.items[this.lowerCount];
    delete this.items[this.lowerCount];
    this.lowerCount++;
    return elem;
  }
  isEmpty() {
    if (this.size() === 0) return true;
    return false;
  }
  size() {
    return this.count - this.lowerCount;
  }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  【🔥】高频算法题系列：栈
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  最小栈【简单】【栈】&lt;/li&gt;
&lt;li&gt;  有效的括号【中等】【栈】【面试真题】&lt;/li&gt;
&lt;li&gt;  简化路径【中等】【栈】&lt;/li&gt;
&lt;li&gt;  下一个更大元素 【系列】【栈】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  最小栈【栈】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/min-stack/"&gt;【LeetCode 直通车】：155 最小栈（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * initialize your data structure here.
 */
var MinStack = function() {
    this.stack = [];
    this.minArr = [];
    this.count = 0;
    this.min = Number.MAX_SAFE_INTEGER;
};
/** 
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
    this.min = Math.min(this.min, x);
    this.minArr[this.count] = this.min;
    this.stack[this.count] = x;
    this.count++;
};
/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
    const element = this.stack[this.count - 1];
    if (this.count - 2 &amp;gt;= 0) this.min = this.minArr[this.count - 2];
    else  this.min = Number.MAX_SAFE_INTEGER;
    delete this.stack[this.count - 1];
    delete this.minArr[this.count - 1];
    this.count--;
    return element;
};
/**
 * @return {number}
 */
MinStack.prototype.top = function() {
    if (this.count &amp;gt;= 1) {
        return this.stack[this.count - 1];
    }
    return null;
};
/**
 * @return {number}
 */
MinStack.prototype.getMin = function() {
    const element = this.minArr[this.count - 1];
    return element;
};
/**
 * Your MinStack object will be instantiated and called as such:
 * var obj = new MinStack()
 * obj.push(x)
 * obj.pop()
 * var param_3 = obj.top()
 * var param_4 = obj.getMin()
 */

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【系列】下一个更大元素 【栈】
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/next-greater-element-i/"&gt;【LeetCode 直通车】：496 下一个更大元素 I（简单）&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  👉 &lt;a href="https://leetcode-cn.com/problems/next-greater-element-ii/"&gt;【LeetCode 直通车】：503 下一个更大元素 II（中等）&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;受限于篇幅，这里只给出第一道题的代码模板&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var nextGreaterElements = function(nums) {
    let ans = [];
    let stack = new Stack();
    const n = nums.length;
    for (let i = 2 * n - 1; i &amp;gt;= 0; i--) {
        while (!stack.isEmpty() &amp;amp;&amp;amp; stack.top() &amp;lt;= nums[i % n]) {
            stack.pop();
        }
        ans[i % n] = stack.isEmpty() ? -1 : stack.top();
        stack.push(nums[i % n]);
    }
    return ans;
};
class Stack {
    constructor() {
        this.count = 0;
        this.items = [];
    }
    top() {
        if (this.isEmpty()) return undefined;
        return this.items[this.count - 1];
    }
    push(element) {
        this.items[this.count] = element;
        this.count++;
    }
    pop() {
        if (this.isEmpty()) return undefined;
        const element = this.items[this.count - 1];
        delete this.items[this.count - 1];
        this.count--;
        return element;
    }
    isEmpty() {
        return this.size() === 0;
    }
    size() {
        return this.count;
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  【面试真题】有效的括号【栈】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/valid-parentheses/"&gt;【LeetCode 直通车】：20 有效的括号（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {
    if (s.length === 0) {
        return true;
    }
    if (s.length % 2 !== 0) {
        return false;
    }
    let map = {
        ')': '(',
        ']': '[',
        '}': '{',
    };
    let left = ['(', '[', '{'];
    let right = [')', ']', '}'];
    let stack = new Stack();
    for (let i = 0; i &amp;lt; s.length; i++) {
        if (!right.includes(s[i])) {
            stack.push(s[i]);
        } else {
            const matchStr = map[s[i]];
            while (!stack.isEmpty()) {
                const element = stack.pop();
                if (left.includes(element) &amp;amp;&amp;amp; matchStr !== element)  return false;
                if (element === matchStr) break;
            }
        }
    }
    return stack.isEmpty();
};
class Stack {
    constructor() {
        this.count = 0;
        this.items = [];
    }
    push(element) {
        this.items[this.count] = element;
        this.count++;
    }
    pop() {
        if (this.isEmpty()) return undefined;
        const element = this.items[this.count - 1];
        delete this.items[this.count - 1];
        this.count--;
        return element;
    }
    isEmpty() {
        return this.size() === 0;
    }
    size() {
        return this.count;
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  简化路径【栈】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/simplify-path/"&gt;【LeetCode 直通车】：71 简化路径（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} path
 * @return {string}
 */
var simplifyPath = function(path) {
    let newPath = path.split('/');
    newPath = newPath.filter(item =&amp;gt; item !== "");
    const stack = new Stack();
    for (let s of newPath) {
        if (s === '..') stack.pop();
        else if (s !== '.') stack.push(s);
    }
    if (stack.isEmpty()) return '/';
    let str = '';
    while (!stack.isEmpty()) {
        const element = stack.pop();
        str = '/' + element + str;
    }
    return str;
};
function handleBack(stack, tag, num) {
    if (!stack.isEmpty()) return num;
    const element = stack.pop();
    if (element === '..') return handleBack(stack, tag, num + 1);
    else {
        stack.push(element);
        return num;
    }
}
class Stack {
    constructor() {
        this.count = 0;
        this.items = [];
    }
    push(element) {
        this.items[this.count] = element;
        this.count++;
    }
    pop() {
        if (this.isEmpty()) return undefined;
        const element = this.items[this.count - 1];
        delete this.items[this.count - 1];
        this.count--;
        return element;
    }
    size() {
        return this.count;
    }
    isEmpty() {
        return this.size() === 0;
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  【🔥】高频算法题系列：DFS
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  岛屿的最大面积【中等】【DFS】&lt;/li&gt;
&lt;li&gt;  相同的树【简单】【DFS】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  岛屿的最大面积【DFS】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/max-area-of-island/"&gt;【LeetCode 直通车】：695 岛屿的最大面积（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[][]} grid
 * @return {number}
 */
let maxX, maxY;let visited;let globalMaxArea;
var maxAreaOfIsland = function(grid) {
    visited = new Set();
    maxX = grid.length;
    maxY = grid[0].length;
    globalMaxArea = 0;
    for (let i = 0; i &amp;lt; maxX; i++) {
        for (let j = 0; j &amp;lt; maxY; j++) {
            if (grid[i][j] === 1) {
                visited.add(`(${i}, ${j})`);
                globalMaxArea = Math.max(globalMaxArea, dfs(grid, i, j));
            }
            visited.clear();
        }
    }
    return globalMaxArea;
};
function dfs(grid, x, y) {
    let res = 1;
    for (let i = -1; i &amp;lt;= 1; i++) {
        for (let j = -1; j &amp;lt;= 1; j++) {
            if (Math.abs(i) === Math.abs(j)) continue;
            const newX = x + i;
            const newY = y + j;
            if (newX &amp;gt;= maxX || newX &amp;lt; 0 || newY &amp;gt;= maxY || newY &amp;lt; 0) continue;
            if (visited.has(`(${newX}, ${newY})`)) continue;
            visited.add(`(${newX}, ${newY})`);
            const areaCnt = grid[newX][newY]
            if (areaCnt === 1) {
                const cnt = dfs(grid, newX, newY);
                res += cnt;
            } 
        }
    }
    return res;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  相同的树【DFS】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/same-tree/"&gt;【LeetCode 直通车】：100 相同的树（简单）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * 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 == null &amp;amp;&amp;amp; q == null) return true;
    if (p == null || q == null) return false;
    if (p.val !== q.val) return false;
    return isSameTree(p.left, q.left) &amp;amp;&amp;amp; isSameTree(p.right, q.right);
};

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  【🔥】高频算法题系列：回溯算法
&lt;/h2&gt;

&lt;p&gt;主要有以下几类高频考题：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  N皇后【困难】【回溯算法】【面试真题】&lt;/li&gt;
&lt;li&gt;  全排列【中等】【回溯算法】&lt;/li&gt;
&lt;li&gt;  括号生成【中等】【回溯算法】&lt;/li&gt;
&lt;li&gt;  复原 IP 地址【中等】【回溯算法】&lt;/li&gt;
&lt;li&gt;  子集 【简单】【回溯算法】&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  【面试真题】N皇后【回溯算法】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/n-queens/"&gt;【LeetCode 直通车】：51 N皇后（困难）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number} n
 * @return {string[][]}
 */
let result = [];
var solveNQueens = function(n) {
    result = [];
    let board = [];
    for (let i = 0; i &amp;lt; n; i++) {
      board[i] = [];
      for (let j = 0; j &amp;lt; n; j++) {
        board[i][j] = '.'
      }
    }
    backtrack(0, board, n);
    return result;
};
function deepClone(board) {
  let res = [];
  for (let i = 0; i &amp;lt; board.length; i++) {
    res.push(board[i].join(''));
  }
  return res;
}
function backtrack(row, board, n) {
    if (row === n) {
      result.push(deepClone(board));
      return;
    }
    for (let j = 0; j &amp;lt; n; j++) {
        if (checkInValid(board, row, j, n)) continue;
        board[row][j] = 'Q';
        backtrack(row + 1, board, n);
        board[row][j] = '.';
      }
}
function checkInValid(board, row, column, n) {
  // 行
  for (let i = 0; i &amp;lt; n; i++) {
    if (board[i][column] === 'Q') return true;
  }
  for (let i = row - 1, j = column + 1; i &amp;gt;= 0 &amp;amp;&amp;amp; j &amp;lt; n; i--, j++) {
    if (board[i][j] === 'Q') return true;
  }
  for (let i = row - 1, j = column - 1; i &amp;gt;= 0 &amp;amp;&amp;amp; j &amp;gt;= 0; i--, j--) {
    if (board[i][j] === 'Q') return true;
  }
  return false;
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  全排列【回溯算法】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/permutations/"&gt;【LeetCode 直通车】：46 全排列（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
let results = [];var permute = function(nums) {
    results = [];
    backtrack(nums, []);
    return results;
};
function backtrack(nums, track) {
    if (nums.length === track.length) {
        results.push(track.slice());
        return;
    }
    for (let i = 0; i &amp;lt; nums.length; i++) {
        if (track.includes(nums[i])) continue;
        track.push(nums[i]);
        backtrack(nums, track);
        track.pop();
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  括号生成【回溯算法】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/generate-parentheses/"&gt;【LeetCode 直通车】：22 括号生成（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number} n
 * @return {string[]}
 */
var generateParenthesis = function(n) {
    let validRes = [];
    backtrack(n * 2, validRes, '');
    return validRes;
};
function backtrack(len, validRes, bracket) {
    if (bracket.length === len) {
        if (isValidCombination(bracket)) {
            validRes.push(bracket);
        }
        return;
    }
    for (let str of ['(', ')']) {
        bracket += str;
        backtrack(len, validRes, bracket);
        bracket = bracket.slice(0, bracket.length - 1);
    }
}
function isValidCombination(bracket) {
    let stack = new Stack();
    for (let i = 0; i &amp;lt; bracket.length; i++) {
        const str = bracket[i];
        if (str === '(') {
            stack.push(str);
        } else if (str === ')') {
            const top = stack.pop();
            if (top !== '(') return false;
        }
    }
    return stack.isEmpty();
}
class Stack {
    constructor() {
        this.count = 0;
        this.items = [];
    }
    push(element) {
        this.items[this.count] = element;
        this.count++;
    }
    pop() {
        if (this.isEmpty()) return;
        const element = this.items[this.count - 1];
        delete this.items[this.count - 1];
        this.count--;
        return element;
    }
    size() {
        return this.count;
    }
    isEmpty() {
        return this.size() === 0;
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  复原 IP 地址【回溯算法】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/restore-ip-addresses/"&gt;【LeetCode 直通车】：93 复原 IP 地址（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {string} s
 * @return {string[]}
 */
var restoreIpAddresses = function(s) {
    if (s.length &amp;gt; 12) return [];
    let res = [];
    const track = [];
    backtrack(s, track, res);
    return res;
};
function backtrack(s, track, res) {
    if (track.length === 4 &amp;amp;&amp;amp; s.length === 0) {
        res.push(track.join('.'));
        return;
    }
    let len = s.length &amp;gt;= 3 ? 3 : s.length;
    for (let i = 0; i &amp;lt; len; i++) {
        const c = s.slice(0, i + 1);
        if (parseInt(c) &amp;gt; 255) continue;
        if (i &amp;gt;= 1 &amp;amp;&amp;amp;  parseInt(c) &amp;lt; parseInt((1 + '0'.repeat(i)))) continue;
        track.push(c);
        backtrack(s.slice(i + 1), track, res);
        track.pop();
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  子集【回溯算法】
&lt;/h3&gt;

&lt;p&gt;👉 &lt;a href="https://leetcode-cn.com/problems/subsets/"&gt;【LeetCode 直通车】：78 子集（中等）&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  题解
&lt;/h4&gt;

&lt;p&gt;→点击展开查看&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsets = function(nums) {
    if (nums.length === 0) return [[]];
    let resArr = [];
    backtrack(nums, 0, [], resArr);
    return resArr;
};
function backtrack(nums, index, subArr, resArr) {
    if (Array.isArray(subArr)) {
        resArr.push(subArr.slice());
    }
    if (index === nums.length) {
        return;
    } 
    for (let i = index; i &amp;lt; nums.length; i++) {
        subArr.push(nums[i]);
        backtrack(nums, i + 1, subArr, resArr);
        subArr.pop(nums[i]);
    }
}

复制代码
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;原文地址 &lt;a href="https://ideras.com"&gt;干货文章分享&lt;/a&gt; - &lt;a href="https://ideras.com/zi-jie-tiao-dong-zui-ai-kao-de-64-dao-suan-fa-ti-jsban/"&gt;字节跳动最常考的 64 道JS算法题&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  原创不易
&lt;/h3&gt;

&lt;p&gt;喜欢的话原创不易，给点鼓励吧 ❤️ 别忘了 分享、点赞、在看 三连哦~。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>程序员财富自由之路 自媒体篇 | 3000字干货分享</title>
      <dc:creator>fengmao</dc:creator>
      <pubDate>Tue, 14 Jul 2020 07:43:45 +0000</pubDate>
      <link>https://dev.to/fengmao/3000-36c5</link>
      <guid>https://dev.to/fengmao/3000-36c5</guid>
      <description>&lt;p&gt;疫情期间，很多人的收入多多少少都受到了影响。当然，有的人坐吃山空，也有的人收入翻倍。&lt;/p&gt;

&lt;p&gt;我仔细观察了一下这些收入翻倍的人，发现他们基本都离不开三个字。哪三个字？就是&lt;strong&gt;自媒体&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;自媒体是什么？&lt;/p&gt;

&lt;p&gt;自媒体是指以内容为中心，个人创作者以网络的形式进行内容传播，从而获得一定关注度和影响力的方式。&lt;strong&gt;自媒体的内容形态非常广泛，文章、动态短文、音频、闻达、图集、短视频、长视频、直播等等都是自媒体可以采用的形式。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;目前从事自媒体的人群有多么庞大呢？根据艾瑞网的调查数据，目前我国全职从事自媒体的人数达到了370万以上，而兼职人群则超过了600万。可见，做自媒体已经是大势所趋。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;自媒体做得好的人，到底有多赚？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;精品大号的“一条”，非头条广告费就达到了百万；&lt;/p&gt;

&lt;p&gt;家庭美学定位的“卡娃微卡”，一条广告费超过10万；&lt;/p&gt;

&lt;p&gt;papi酱，在微博上迅速走红后，短期内广告价格上涨到了2200万……&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NmVT5Hdh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-16834171789a6f87.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NmVT5Hdh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-16834171789a6f87.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;（微信公众号平台报价）&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7NYUo1pz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-f2b0e34a5f78b360.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7NYUo1pz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-f2b0e34a5f78b360.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;（抖音星图达人的预估报价）&lt;/p&gt;

&lt;p&gt;博多·舍费尔在《财富自由之路》中分析个人收入构成时提到，&lt;strong&gt;个人收入的高低其实与五个因素息息相关，分别是“能力、精力、影响力/知名度、创意和自我评价”，而其中，影响力是最强的杠杆。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;自媒体就是你能够利用好的扩大个人影响力的最佳方式。抓住了自媒体机会的人，现在都已经赚得盆满钵满。&lt;/p&gt;

&lt;p&gt;如果你只是低头做事，那么你的才华很有可能只有老板知道，也只有老板会付给你薪酬。但是，当你在自媒体上做分享时，你的知识可以送达千千万万的粉丝，他们同样会为你的付出买单。你只需要工作一次，就能获得上不封顶的报酬。&lt;/p&gt;

&lt;p&gt;一份时间卖出一次，想拿到百万年薪难度系数太高。一份时间卖出很多次，实现财富自由，其实并没有想象中那么难。&lt;/p&gt;

&lt;p&gt;或许你会问，普通人也能通过做自媒体赚到钱吗？&lt;/p&gt;

&lt;p&gt;答案是肯定的。农村四哥王荣琪，是一名从四川泸州到南方的打工仔，他从零开始经营今日头条，短短几个月，就拥有了380万粉丝，收益过万，还获得“2019今日头条年度生机创作者”称号。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bk5pb48K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-8876c5bd9bd681a0.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bk5pb48K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-8876c5bd9bd681a0.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;（农村四哥的演讲）&lt;/p&gt;

&lt;p&gt;现在的自媒体风格非常包容，哪怕你只是一个普通人，只要你掌握了一定的方法，做的内容有趣、有料，那么，你就能收获粉丝的信赖，在自媒体的红利中分得一杯羹。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;凯文·凯利的1000粉丝理论告诉我们，只要能找到1000个铁杆粉丝，他们愿意为你的内容买单，你就足以生存得很好。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;02&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;现在能赚钱的自媒体平台有哪些呢？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这个可就多了。图文类的自媒体平台有：今日头条、百家号、企鹅号、大鱼号、网易号、简书、搜狐视频号、微信公众号、知乎等等。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xtSwTebF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-3c8c6ff0f65bdedf.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xtSwTebF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-3c8c6ff0f65bdedf.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;视频类的自媒体平台有：抖音小视频、西瓜视频、火山小视频、快手等等。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NrFDJWaM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-39b07581fd2aa74b.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NrFDJWaM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-39b07581fd2aa74b.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;不管你是想做哪个类型内容，都不愁找不到平台发布。而且，不同的平台对于创作者都还会有相应的扶持计划和奖励计划。只要你持续产出高质量内容，就不愁没有收入。&lt;/p&gt;

&lt;p&gt;下面详细地为大家讲解三个目前最能赚钱的平台：&lt;/p&gt;

&lt;p&gt;1、&lt;strong&gt;今日头条&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;平台特点：&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;今日头条是北京字节跳动有限公司开发的一款搜索引擎产品，特点在于算法推荐，自动匹配内容和用户。新手想要从自媒体赚到钱，从今日头条入手是最好的，因为今日头条是官方鼓励赚钱，平台流量非常大，日活1.2亿+，只要你坚持发布内容就能找到对应的粉丝。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;运营方法：&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;今日头条可以通过微头条、图集、长图文、问答等内容形式来变现，收益十分可观。&lt;/p&gt;

&lt;p&gt;微头条：非常自由，字数、配图、领域、格式都没有限制，涨粉快，达到一定粉丝数量还可以开通商品带货功能，轻轻松松就能获得卖货收益。通过写优质微头条，可以获得加V认证，即“XX 领域优质创作者”勋章，后续能获得更多的流量扶持。&lt;/p&gt;

&lt;p&gt;图文内容：图文内容也有阅读收益，如果拿到原创标，收益会更高。针对优质的长图文，今日头条推出青云计划，单篇图文不仅仅可以获得阅读收益，还能获得平台奖励，最低收益300元，上不封顶。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kr3KxzMG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-a41ff969f95a265c.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kr3KxzMG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-a41ff969f95a265c.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片6.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;问答变现：今日头条的问答有另一个名称，叫悟空问答。只要开通了问答收益，针对你感兴趣或者有把握的领域进行回答，就能通过回答问题获得一定的收益。问答里面也有“问答青云计划”，一档奖金300，二档奖金100，随手一个回答就也能有三位数的收入，不香么？&lt;/p&gt;

&lt;p&gt;2、&lt;strong&gt;百家号&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;平台特点：&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;百家号是百度专门为内容创作者打造的一个集内容创作、发布及变现为一体的互联网平台。背靠百度这个最大的中文搜索引擎网站，百家号的流量和收益也是值得关注的。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;运营方法：&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;图文收益：百家号的图文收益目前是10000阅读/30元，可以说是主流自媒体平台之首了。在百家号上写图文内容，只要阅读量过万，获得几百收益并不难。&lt;/p&gt;

&lt;p&gt;其他收益：百家号和今日头条相似，同样也有广告分成，问答收入，原创标收益，并且可以自荐文章，如果入选的话就可以获得至少100元+的收入和流量支持。&lt;/p&gt;

&lt;p&gt;带货变现：百家号的文章中可以插入商品链接，通过写文章来带货，获得一定的带货分成。有的人通过带货，一篇文章轻轻松松就能获得几千收益。&lt;/p&gt;

&lt;p&gt;同时，百家号上面也有非常多的创作者扶持计划，例如“百+计划”，百+计划的上榜者最高可以获得2万元的收益。很多的创作活动也都可以参与，都有机会获得金额不等的奖励。&lt;/p&gt;

&lt;p&gt;3、&lt;strong&gt;微信公众号&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;平台特点：&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;微信公众号是基于微信社交平台而存在的个人自媒体，其重要性和必要性不言而喻。虽然说，微信公众号现在已经是大号林立，但是也依然有很多自媒体人，独辟蹊径，后来居上，短时间内获得大量粉丝，成为一匹突围的黑马。现在微信也相应开放了视频号，微信公众号极有可能会迎来下一个春天。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;运营方法：&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;相对于今日头条和百家号，微信公众号对于自媒体人的要求会稍微高一些。因为微信公众号一般是需要通过爆款文章、刷屏文章来获得关注，粉丝数和粉丝忠诚度决定了微信公众号能够赚到多少钱。&lt;/p&gt;

&lt;p&gt;微信公众号的收益主要来自于硬广和软广。微信公众号图文下面会投放广告，通过粉丝点击广告而获得收入，但这个收入不是特别多。真正可观的是微信公众号号主自己接广告，发软文，一般来说，一条软文广告的收益在几千到百万不等。&lt;/p&gt;

&lt;p&gt;另外，微信公众号号主自身也可以在公众号上推出付费阅读、社群、课程等付费服务，从而获得一定的收益。&lt;/p&gt;

&lt;p&gt;03&lt;/p&gt;

&lt;p&gt;做自媒体需要具备哪些技能？如何培养这些技能？&lt;/p&gt;

&lt;p&gt;1、&lt;strong&gt;写作能力&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;做自媒体的人都需要一定的文字功底，这是最基础的能力。&lt;strong&gt;不要求你妙笔生花，文采斐然，但是最起码你要把内容讲清楚，讲透彻。&lt;/strong&gt;首先，你要能够把自己的观点完整地叙述出来，思路顺畅，然后在此基础上去追求文字的技巧性，做到把握节奏，引人入胜，让人有读下去的欲望。&lt;/p&gt;

&lt;p&gt;对于写作的把握和对文字的驾驭，这些都是可以通过技能学习和长期练习得来的。对于文案的写作，其实都有一定的规律可循，爆款文章的思路很多时候都是共通的。&lt;strong&gt;只要你懂得了其中的思维，自然就可以举一反三。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;2、&lt;strong&gt;用户思维&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;毫无疑问，做自媒体的人，粉丝就是我们的经济来源。如果我们总是按照我们自己的想法去做自媒体，写自己想写的文章，那么后果就是阅读量惨淡，折腾一个月也不见得有收益。&lt;strong&gt;真正想赚到钱，我们就应该拥有用户思维，去关注用户的关注点在哪里，用户的真正需求是什么，从而做好自己的账号定位和内容规划。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;用户思维要怎么培养？第一步，对标。找到自己所在领域自媒体排行榜前10的大号。第二部，拆解。去做账号的拆解和分析，剖析他们的账号定位、选题方向、文章风格、粉丝运营都是怎么做的。在能力允许的情况下，还可以开展市场调研，真正了解你的目标用户需求，再对症下药，给出解决方案。&lt;/p&gt;

&lt;p&gt;3、&lt;strong&gt;紧跟热点&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;现在的信息爆炸社会，每个人每天都要应对成百上千的信息资讯。你的内容如何在众多的内容中脱颖而出，就取决于你的内容是否能够第一时间吸引到用户的注意力。&lt;/p&gt;

&lt;p&gt;眼球经济时代，顾名思义，就是你的内容必须第一时间抓住用户的眼球，没有注意力就没有利润，没有利润就注定要失败，而&lt;strong&gt;获取用户注意力的捷径就是紧跟热点。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;何为热点？其实是用户自己投票选出来的议题。&lt;/strong&gt;也就是说，不需要我们再去苦心积虑地做选题，只要紧跟热点，这些内容就是用户自己想要看到的。例如，最近乘风破浪的姐姐们十分火爆，只要与该热点相关的内容，基本上阅读量都不会太差。&lt;/p&gt;

&lt;p&gt;所以，自媒体人一定要学会追踪热点，要有把自己的独家内容与时事热点相结合的能力，这样才能在保证最大打开率的同时输出自己的观点。&lt;/p&gt;

&lt;p&gt;4、&lt;strong&gt;善用工具&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;作为自媒体人，一个人同时要兼顾许多工作，既要收集资料，又要做好选题，既要撰写文章，还要会P图修图，常常会手忙脚乱，费时又费力。&lt;strong&gt;如果能善用工具，就能起到事半功倍的效果。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;那么，自媒体人要怎么培养这个技能呢？首先就是要时刻名铭记工具思维，当遇到一个任务的时候，可以搜索一下是否有工具可以简化该任务流程，或者可以提高工作效率，对于别人推荐的工具，可以多进行尝试，选择适合自己的工具。&lt;/p&gt;

&lt;p&gt;在这里介绍几个自媒体人经常会用到的工具：&lt;/p&gt;

&lt;p&gt;1）资料收集方面：&lt;/p&gt;

&lt;p&gt;果汁排行榜&lt;a href="http://www.guozhivip.com/rank/index.html"&gt;&lt;u&gt;http://www.guozhivip.com/rank/index.html&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;各类榜单排名大全，绝对是选题蹭热点的不二利器&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0kLT5cSm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-ae1c255da903ba3b.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0kLT5cSm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-ae1c255da903ba3b.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片7.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;大数据导航网&lt;a href="http://hao.199it.com/"&gt;&lt;u&gt;http://hao.199it.com/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;涵盖了各类指数网站和互联网工具，非常适合寻找相关材料和论据。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VLj5nzc5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-15ae30df1dc8c957.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VLj5nzc5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-15ae30df1dc8c957.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2）文章撰写方面：&lt;/p&gt;

&lt;p&gt;石墨文档：&lt;a href="https://shimo.im/welcome"&gt;&lt;u&gt;https://shimo.im/welcome&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;实时保存，多人协作，手机和电脑均可操作，方便快捷，不用担心用Word中途断电的情况&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZSdNze3U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-ecf4977f31b63a54.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZSdNze3U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-ecf4977f31b63a54.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;坚果云：&lt;a href="https://www.jianguoyun.com/"&gt;&lt;u&gt;https://www.jianguoyun.com/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;可以实现多终端保存文件，并且自动更新，手机和电脑能够同步，对于写作者来说是一大福音，随时随地都能码字了&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0aHorVCG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-7a522eeefb8ac2bf.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0aHorVCG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-7a522eeefb8ac2bf.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片10.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3）文章排版方面：&lt;/p&gt;

&lt;p&gt;秀米：&lt;u&gt;https://xiumi.us/#/&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;一键排版、文章布局调整、团队文章等功能非常实用&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IwKc8HIh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-82d5bcf021f25a95.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IwKc8HIh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-82d5bcf021f25a95.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片11.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;135排版器：&lt;a href="https://www.135editor.com/"&gt;&lt;u&gt;https://www.135editor.com/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;样式繁多，小清新风格也是一大特色&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bnakPxsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-38cf47559db6c6fd.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bnakPxsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-38cf47559db6c6fd.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片12.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5、图片制作网站：&lt;/p&gt;

&lt;p&gt;创客贴：&lt;a href="https://www.chuangkit.com/"&gt;&lt;u&gt;https://www.chuangkit.com/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在线图片编辑器，很多免费模板可以直接套用，封面图海报分分钟搞定&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H8pA5zaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-0f2cf7fa6644bd1f.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H8pA5zaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-0f2cf7fa6644bd1f.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片13.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Canva：&lt;a href="https://www.canva.cn/templates/?utm_medium=paid&amp;amp;utm_source=baidu&amp;amp;utm_campaign=ACQ-brand-zone&amp;amp;utm_term=canva&amp;amp;utm_content=sem"&gt;&lt;u&gt;https://www.canva.cn/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;简单好用的在线设计平台，设计范围更广，模板样式更偏向于高端时尚风格&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--50bJR75K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-5cc9b31fe4b50278.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--50bJR75K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://upload-images.jianshu.io/upload_images/1355291-5cc9b31fe4b50278.png%3FimageMogr2/auto-orient/strip%257CimageView2/2/w/1240" alt="图片14.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;04&lt;/p&gt;

&lt;p&gt;由于本文的目标读者都是程序员群体，最后给大家推荐一个阅读英文技术文档的网站，&lt;a href="https://doc.liusha.io"&gt;https://doc.liusha.io&lt;/a&gt;，要想学好技术，英语是非常重要了，除了发展自媒体副业，程序员本业也是要好好发展的，大家觉得呢？&lt;/p&gt;

</description>
    </item>
    <item>
      <title>爬虫黑科技，我是怎么爬取indeed的职位数据的</title>
      <dc:creator>fengmao</dc:creator>
      <pubDate>Fri, 20 Mar 2020 07:21:23 +0000</pubDate>
      <link>https://dev.to/fengmao/indeed-76k</link>
      <guid>https://dev.to/fengmao/indeed-76k</guid>
      <description>&lt;p&gt;最近在学习nodejs爬虫技术，学了request模块，所以想着写一个自己的爬虫项目，研究了半天，最后选定indeed作为目标网站，通过爬取indeed的职位数据，然后开发一个自己的职位搜索引擎，目前已经上线了，虽然功能还是比较简单，但还是贴一下网址&lt;a href="https://ideras.com"&gt;job search engine&lt;/a&gt;，证明一下这个爬虫项目是有用的。下面就来讲讲整个爬虫的思路。 &lt;/p&gt;

&lt;h2&gt;
  
  
  确定入口页面
&lt;/h2&gt;

&lt;p&gt;众所周知，爬虫是需要入口页面的，通过入口页面，不断的爬取链接，最后爬取完整个网站。在这个第一步的时候，就遇到了困难，一般来说都是选取首页和列表页作为入口页面的，但是indeed的列表页面做了限制，不能爬取完整的列表，顶多只能抓取前100页，但是这没有难倒我，我发现indeed有一个&lt;strong&gt;Browse Jobs&lt;/strong&gt; 页面，通过这个页面，可以获取indeed按地区搜索和按类型搜索的所有列表。下面贴一下这个页面的解析代码。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;start: async (page) =&amp;gt; {
  const host = URL.parse(page.url).hostname;
  const tasks = [];
  try {
    const $ = cheerio.load(iconv.decode(page.con, 'utf-8'), { decodeEntities: false });
    $('#states &amp;gt; tbody &amp;gt; tr &amp;gt; td &amp;gt; a').each((i, ele) =&amp;gt; {
      const url = URL.resolve(page.url, $(ele).attr('href'));
      tasks.push({ _id: md5(url), type: 'city', host, url, done: 0, name: $(ele).text() });
    });
    $('#categories &amp;gt; tbody &amp;gt; tr &amp;gt; td &amp;gt; a').each((i, ele) =&amp;gt; {
      const url = URL.resolve(page.url, $(ele).attr('href'));
      tasks.push({ _id: md5(url), type: 'category', host, url, done: 0, name: $(ele).text() });
    });
    const res = await global.com.task.insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
    res &amp;amp;&amp;amp; console.log(`${host}-start insert ${res.insertedCount} from ${tasks.length} tasks`);
    return 1;
  } catch (err) {
    console.error(`${host}-start parse ${page.url} ${err}`);
    return 0;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;通过cheerio解析html内容，把按地区搜索和按类型搜索链接插入到数据库中。&lt;/p&gt;

&lt;h2&gt;
  
  
  爬虫架构
&lt;/h2&gt;

&lt;p&gt;这里简单讲一下我的爬虫架构思路，数据库选用mongodb。每一个待爬取的页面存一条记录page，包含id,url,done,type,host等字段，id用&lt;code&gt;md5(url)&lt;/code&gt;生成，避免重复。每一个type有一个对应的html内容解析方法，主要的业务逻辑都集中在这些解析方法里面，上面贴出来的代码就是例子。&lt;/p&gt;

&lt;p&gt;爬取html采用request模块，进行了简单的封装，把callback封装成promise，方便使用async和await方式调用，代码如下。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const req = require('request');

const request = req.defaults({
  headers: {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
  },
  timeout: 30000,
  encoding: null
});

const fetch = (url) =&amp;gt; new Promise((resolve) =&amp;gt; {
    console.log(`down ${url} started`);
    request(encodeURI(url), (err, res, body) =&amp;gt; {
      if (res &amp;amp;&amp;amp; res.statusCode === 200) {
        console.log(`down ${url} 200`);
        resolve(body);
      } else {
        console.error(`down ${url} ${res &amp;amp;&amp;amp; res.statusCode} ${err}`);
        if (res &amp;amp;&amp;amp; res.statusCode) {
          resolve(res.statusCode);
        } else {
          // ESOCKETTIMEOUT 超时错误返回600
          resolve(600);
        }
      }
    });
  });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;做了简单的反反爬处理，把user-agent改成电脑通用的user-agent，设置了超时时间30秒，其中&lt;code&gt;encoding: null&lt;/code&gt;设置request直接返回buffer，而不是解析后的内容，这样的好处是如果页面是gbk或者utf-8编码，只要解析html的时候指定编码就行了，如果这里指定&lt;code&gt;encoding: utf-8&lt;/code&gt;，则当页面编码是gbk的时候，页面内容会乱码。&lt;/p&gt;

&lt;p&gt;request默认是回调函数形式，通过promise封装，如果成功，则返回页面内容的buffer，如果失败，则返回错误状态码，如果超时，则返回600，这些懂nodejs的应该很好理解。&lt;/p&gt;

&lt;h2&gt;
  
  
  完整的解析代码
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const URL = require('url');
const md5 = require('md5');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');

const json = (data) =&amp;gt; {
  let res;
  try {
    res = JSON.parse(data);
  } catch (err) {
    console.error(err);
   }
  return res;
};

const rules = [
  /\/jobs\?q=.*&amp;amp;sort=date&amp;amp;start=\d+/,
  /\/jobs\?q=&amp;amp;l=.*&amp;amp;sort=date&amp;amp;start=\d+/
];

const fns = {

  start: async (page) =&amp;gt; {
    const host = URL.parse(page.url).hostname;
    const tasks = [];
    try {
      const $ = cheerio.load(iconv.decode(page.con, 'utf-8'), { decodeEntities: false });
      $('#states &amp;gt; tbody &amp;gt; tr &amp;gt; td &amp;gt; a').each((i, ele) =&amp;gt; {
        const url = URL.resolve(page.url, $(ele).attr('href'));
        tasks.push({ _id: md5(url), type: 'city', host, url, done: 0, name: $(ele).text() });
      });
      $('#categories &amp;gt; tbody &amp;gt; tr &amp;gt; td &amp;gt; a').each((i, ele) =&amp;gt; {
        const url = URL.resolve(page.url, $(ele).attr('href'));
        tasks.push({ _id: md5(url), type: 'category', host, url, done: 0, name: $(ele).text() });
      });
      const res = await global.com.task.insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-start insert ${res.insertedCount} from ${tasks.length} tasks`);
      return 1;
    } catch (err) {
      console.error(`${host}-start parse ${page.url} ${err}`);
      return 0;
    }
  },

  city: async (page) =&amp;gt; {
    const host = URL.parse(page.url).hostname;
    const tasks = [];
    const cities = [];
    try {
      const $ = cheerio.load(iconv.decode(page.con, 'utf-8'), { decodeEntities: false });
      $('#cities &amp;gt; tbody &amp;gt; tr &amp;gt; td &amp;gt; p.city &amp;gt; a').each((i, ele) =&amp;gt; {
        // https://www.indeed.com/l-Charlotte,-NC-jobs.html
        let tmp = $(ele).attr('href').match(/l-(?&amp;lt;loc&amp;gt;.*)-jobs.html/u);
        if (!tmp) {
          tmp = $(ele).attr('href').match(/l=(?&amp;lt;loc&amp;gt;.*)/u);
        }
        const { loc } = tmp.groups;
        const url = `https://www.indeed.com/jobs?l=${decodeURIComponent(loc)}&amp;amp;sort=date`;
        tasks.push({ _id: md5(url), type: 'search', host, url, done: 0 });
        cities.push({ _id: `${$(ele).text()}_${page.name}`, parent: page.name, name: $(ele).text(), url });
      });
      let res = await global.com.city.insertMany(cities, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-city insert ${res.insertedCount} from ${cities.length} cities`);

      res = await global.com.task.insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-city insert ${res.insertedCount} from ${tasks.length} tasks`);
      return 1;
    } catch (err) {
      console.error(`${host}-city parse ${page.url} ${err}`);
      return 0;
    }
  },

  category: async (page) =&amp;gt; {
    const host = URL.parse(page.url).hostname;
    const tasks = [];
    const categories = [];
    try {
      const $ = cheerio.load(iconv.decode(page.con, 'utf-8'), { decodeEntities: false });
      $('#titles &amp;gt; tbody &amp;gt; tr &amp;gt; td &amp;gt; p.job &amp;gt; a').each((i, ele) =&amp;gt; {
        const { query } = $(ele).attr('href').match(/q-(?&amp;lt;query&amp;gt;.*)-jobs.html/u).groups;
        const url = `https://www.indeed.com/jobs?q=${decodeURIComponent(query)}&amp;amp;sort=date`;
        tasks.push({ _id: md5(url), type: 'search', host, url, done: 0 });
        categories.push({ _id: `${$(ele).text()}_${page.name}`, parent: page.name, name: $(ele).text(), url });
      });
      let res = await global.com.category.insertMany(categories, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-category insert ${res.insertedCount} from ${categories.length} categories`);

      res = await global.com.task.insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-category insert ${res.insertedCount} from ${tasks.length} tasks`);
      return 1;
    } catch (err) {
      console.error(`${host}-category parse ${page.url} ${err}`);
      return 0;
    }
  },

  search: async (page) =&amp;gt; {
    const host = URL.parse(page.url).hostname;
    const tasks = [];
    const durls = [];
    try {
      const con = iconv.decode(page.con, 'utf-8');
      const $ = cheerio.load(con, { decodeEntities: false });
      const list = con.match(/jobmap\[\d+\]= {.*}/g);
      const jobmap = [];
      if (list) {
         // eslint-disable-next-line no-eval
        list.map((item) =&amp;gt; eval(item));
      }
      for (const item of jobmap) {
        const cmplink = URL.resolve(page.url, item.cmplnk);
        const { query } = URL.parse(cmplink, true);
        let name;
        if (query.q) {
          // eslint-disable-next-line prefer-destructuring
          name = query.q.split(' #')[0].split('#')[0];
        } else {
          const tmp = cmplink.match(/q-(?&amp;lt;text&amp;gt;.*)-jobs.html/u);
          if (!tmp) {
            // eslint-disable-next-line no-continue
            continue;
          }
          const { text } = tmp.groups;
          // eslint-disable-next-line prefer-destructuring
          name = text.replace(/-/g, ' ').split(' #')[0];
        }
        const surl = `https://www.indeed.com/cmp/_cs/cmpauto?q=${name}&amp;amp;n=10&amp;amp;returnlogourls=1&amp;amp;returncmppageurls=1&amp;amp;caret=8`;
        const burl = `https://www.indeed.com/viewjob?jk=${item.jk}&amp;amp;from=vjs&amp;amp;vjs=1`;
        const durl = `https://www.indeed.com/rpc/jobdescs?jks=${item.jk}`;
        tasks.push({ _id: md5(surl), type: 'suggest', host, url: surl, done: 0 });
        tasks.push({ _id: md5(burl), type: 'brief', host, url: burl, done: 0 });
        durls.push({ _id: md5(durl), type: 'detail', host, url: durl, done: 0 });
      }
      $('a[href]').each((i, ele) =&amp;gt; {
        const tmp = URL.resolve(page.url, $(ele).attr('href'));
        const [url] = tmp.split('#');
        const { path, hostname } = URL.parse(url);
        for (const rule of rules) {
          if (rule.test(path)) {
            if (hostname == host) {
              // tasks.push({ _id: md5(url), type: 'list', host, url: decodeURI(url), done: 0 });
            }
            break;
          }
        }
      });

      let res = await global.com.task.insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-search insert ${res.insertedCount} from ${tasks.length} tasks`);

      res = await global.com.task.insertMany(durls, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-search insert ${res.insertedCount} from ${durls.length} tasks`);

      return 1;
    } catch (err) {
      console.error(`${host}-search parse ${page.url} ${err}`);
      return 0;
    }
  },

  suggest: async (page) =&amp;gt; {
    const host = URL.parse(page.url).hostname;
    const tasks = [];
    const companies = [];
    try {
      const con = page.con.toString('utf-8');
      const data = json(con);
      for (const item of data) {
        const id = item.overviewUrl.replace('/cmp/', '');
        const cmpurl = `https://www.indeed.com/cmp/${id}`;
        const joburl = `https://www.indeed.com/cmp/${id}/jobs?clearPrefilter=1`;
        tasks.push({ _id: md5(cmpurl), type: 'company', host, url: cmpurl, done: 0 });
        tasks.push({ _id: md5(joburl), type: 'jobs', host, url: joburl, done: 0 });
        companies.push({ _id: id, name: item.name, url: cmpurl });
      }

      let res = await global.com.company.insertMany(companies, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-suggest insert ${res.insertedCount} from ${companies.length} companies`);

      res = await global.com.task.insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-suggest insert ${res.insertedCount} from ${tasks.length} tasks`);
      return 1;
    } catch (err) {
      console.error(`${host}-suggest parse ${page.url} ${err}`);
      return 0;
    }
  },

  // list: () =&amp;gt; {},

  jobs: async (page) =&amp;gt; {
    const host = URL.parse(page.url).hostname;
    const tasks = [];
    const durls = [];
    try {
      const con = iconv.decode(page.con, 'utf-8');
      const tmp = con.match(/window._initialData=(?&amp;lt;text&amp;gt;.*);&amp;lt;\/script&amp;gt;&amp;lt;script&amp;gt;window._sentryData/u);
      let data;
      if (tmp) {
        const { text } = tmp.groups;
        data = json(text);
        if (data.jobList &amp;amp;&amp;amp; data.jobList.pagination &amp;amp;&amp;amp; data.jobList.pagination.paginationLinks) {
          for (const item of data.jobList.pagination.paginationLinks) {
            // eslint-disable-next-line max-depth
            if (item.href) {
              item.href = item.href.replace(/\u002F/g, '/');
              const url = URL.resolve(page.url, decodeURI(item.href));
              tasks.push({ _id: md5(url), type: 'jobs', host, url: decodeURI(url), done: 0 });
            }
          }
        }
        if (data.jobList &amp;amp;&amp;amp; data.jobList.jobs) {
          for (const job of data.jobList.jobs) {
            const burl = `https://www.indeed.com/viewjob?jk=${job.jobKey}&amp;amp;from=vjs&amp;amp;vjs=1`;
            const durl = `https://www.indeed.com/rpc/jobdescs?jks=${job.jobKey}`;
            tasks.push({ _id: md5(burl), type: 'brief', host, url: burl, done: 0 });
            durls.push({ _id: md5(durl), type: 'detail', host, url: durl, done: 0 });
          }
        }
      } else {
        console.log(`${host}-jobs ${page.url} has no _initialData`);
      }
      let res = await global.com.task.insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-search insert ${res.insertedCount} from ${tasks.length} tasks`);

      res = await global.com.task.insertMany(durls, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-search insert ${res.insertedCount} from ${durls.length} tasks`);

      return 1;
    } catch (err) {
      console.error(`${host}-jobs parse ${page.url} ${err}`);
      return 0;
    }
  },

  brief: async (page) =&amp;gt; {
    const host = URL.parse(page.url).hostname;
    try {
      const con = page.con.toString('utf-8');
      const data = json(con);
      data.done = 0;
      data.views = 0;
      data.host = host;
      // format publish date
      if (data.vfvm &amp;amp;&amp;amp; data.vfvm.jobAgeRelative) {
        const str = data.vfvm.jobAgeRelative;
        const tmp = str.split(' ');
        const [first, second] = tmp;
        if (first == 'Just' || first == 'Today') {
          data.publishDate = Date.now();
        } else {
          const num = first.replace(/\+/, '');
          if (second == 'hours') {
            const date = new Date();
            const time = date.getTime();
            // eslint-disable-next-line no-mixed-operators
            date.setTime(time - num * 60 * 60 * 1000);
            data.publishDate = date.getTime();
          } else if (second == 'days') {
            const date = new Date();
            const time = date.getTime();
            // eslint-disable-next-line no-mixed-operators
            date.setTime(time - num * 24 * 60 * 60 * 1000);
            data.publishDate = date.getTime();
          } else {
            data.publishDate = Date.now();
          }
        }
      }
      await global.com.job.updateOne({ _id: data.jobKey }, { $set: data }, { upsert: true }).catch(() =&amp;gt; { });

      const tasks = [];
      const url = `https://www.indeed.com/jobs?l=${data.jobLocationModel.jobLocation}&amp;amp;sort=date`;
      tasks.push({ _id: md5(url), type: 'search', host, url, done: 0 });
      const res = await global.com.task.insertMany(tasks, { ordered: false }).catch(() =&amp;gt; {});
      res &amp;amp;&amp;amp; console.log(`${host}-brief insert ${res.insertedCount} from ${tasks.length} tasks`);
      return 1;
    } catch (err) {
      console.error(`${host}-brief parse ${page.url} ${err}`);
      return 0;
    }
  },

  detail: async (page) =&amp;gt; {
    const host = URL.parse(page.url).hostname;
    try {
      const con = page.con.toString('utf-8');
      const data = json(con);
      const [jobKey] = Object.keys(data);
      await global.com.job.updateOne({ _id: jobKey }, { $set: { content: data[jobKey], done: 1 } }).catch(() =&amp;gt; { });
      return 1;
    } catch (err) {
      console.error(`${host}-detail parse ${page.url} ${err}`);
      return 0;
    }
  },

  run: (page) =&amp;gt; {
    if (page.type == 'list') {
      page.type = 'search';
    }
    const fn = fns[page.type];
    if (fn) {
      return fn(page);
    }
    console.error(`${page.url} parser not found`);
    return 0;
  }

};

module.exports = fns;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;每一个解析方法都会插入一些新的链接，新的链接记录都会有一个type字段，通过type字段，可以知道新的链接的解析方法，这样就能完整解析所有的页面了。例如start方法会插入type为city和category的记录，type为city的页面记录的解析方法就是&lt;code&gt;city&lt;/code&gt;方法，city方法里面又会插入type为search的链接，这样一直循环，直到最后的brief和detail方法分别获取职位数据的简介和详细内容。&lt;/p&gt;

&lt;p&gt;其实爬虫最关键的就是这些html解析方法，有了这些方法，你就能获取任何想要的结构化内容了。&lt;/p&gt;

&lt;h2&gt;
  
  
  数据索引
&lt;/h2&gt;

&lt;p&gt;这部分就很简单了，有了前面获取的结构化数据，按照elasticsearch，新建一个schema，然后写个程序定时把职位数据添加到es的索引里面就行了。因为职位详情的内容有点多，我就没有把content字段添加到索引里面了，因为太占内存了，服务器内存不够用了，&amp;gt;_&amp;lt;。&lt;/p&gt;

&lt;h2&gt;
  
  
  DEMO
&lt;/h2&gt;

&lt;p&gt;最后还是贴上网址供大家检阅，&lt;a href="https://ideras.com"&gt;job search engine&lt;/a&gt;。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>哔哩搜索 - 最好用的种子搜索神器</title>
      <dc:creator>fengmao</dc:creator>
      <pubDate>Tue, 04 Feb 2020 01:27:03 +0000</pubDate>
      <link>https://dev.to/fengmao/-4pc4</link>
      <guid>https://dev.to/fengmao/-4pc4</guid>
      <description>&lt;p&gt;&lt;a href="https://biliworld.com"&gt;哔哩搜索&lt;/a&gt;是最快的种子搜索神器，包含了近1000w的种子数据，免费提供下载&lt;/p&gt;

</description>
      <category>哔哩搜索</category>
    </item>
    <item>
      <title>ideras job search engine launch</title>
      <dc:creator>fengmao</dc:creator>
      <pubDate>Sun, 02 Feb 2020 12:03:44 +0000</pubDate>
      <link>https://dev.to/fengmao/ideras-job-search-engine-launch-1end</link>
      <guid>https://dev.to/fengmao/ideras-job-search-engine-launch-1end</guid>
      <description>&lt;p&gt;ideras.com is built with angular 8 and nodejs 12, the data is crawlered with nodejs, now ideras.com has almost 10 millions jobs on our database, you can find the latest job from many job sites.&lt;br&gt;
We want to build a free &lt;a href="https://ideras.com"&gt;job search engine&lt;/a&gt; with better expereince than those already exist job search sites, ideras.com is beautiful and easy to use, it's very fast and smooth.&lt;br&gt;
it's a great &lt;a href="https://ideras.com"&gt;career websites&lt;/a&gt; for job seekers to find new jobs.&lt;br&gt;
Please let me know what you think about ideras.com.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>luanch of idoras.com</title>
      <dc:creator>fengmao</dc:creator>
      <pubDate>Fri, 31 Aug 2018 09:31:46 +0000</pubDate>
      <link>https://dev.to/fengmao/luanch-of-idorascom-1ee3</link>
      <guid>https://dev.to/fengmao/luanch-of-idorascom-1ee3</guid>
      <description>&lt;p&gt;I'm glad to announce the luanch of &lt;a href="https://idoras.com"&gt;rss reader&lt;/a&gt;, it's written with node.js.&lt;/p&gt;

&lt;p&gt;How does idoras.com work?&lt;/p&gt;

&lt;p&gt;First i collect many website's feed source, and collect feed item, then use readability api to clean the item's content, and show the content on website.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
