diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bbc36c013..e183e0bfb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: Build and Deploy on: push: - branches: [ master ] + branches: [master] jobs: build-and-deploy: @@ -10,20 +10,20 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2.3.1 - with: + with: persist-credentials: false - - name: Set Ruby 2.7 + - name: Set Ruby 3.1 uses: actions/setup-ruby@v1 with: - ruby-version: 2.7 + ruby-version: 3.1 - name: Install and Build run: | gem install bundler bundle install bundle exec jekyll build - + - name: Deploy uses: JamesIves/github-pages-deploy-action@3.6.2 with: diff --git a/Gemfile.lock b/Gemfile.lock index 7650455f87..a81986aeaa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,96 +1,95 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.3.5) + activesupport (6.0.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) zeitwerk (~> 2.2, >= 2.2.2) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.11.1) colorator (1.1.0) - commonmarker (0.17.13) - ruby-enum (~> 0.5) - concurrent-ruby (1.1.8) - dnsruby (1.61.5) + commonmarker (0.23.6) + concurrent-ruby (1.1.10) + dnsruby (1.61.9) simpleidn (~> 0.1) - em-websocket (0.5.2) + em-websocket (0.5.3) eventmachine (>= 0.12.9) - http_parser.rb (~> 0.6.0) - ethon (0.12.0) - ffi (>= 1.3.0) + http_parser.rb (~> 0) + ethon (0.16.0) + ffi (>= 1.15.0) eventmachine (1.2.7) - execjs (2.7.0) - faraday (1.3.0) - faraday-net_http (~> 1.0) - multipart-post (>= 1.2, < 3) - ruby2_keywords - faraday-net_http (1.0.1) - ffi (1.14.2) + execjs (2.8.1) + faraday (2.7.2) + faraday-net_http (>= 2.0, < 3.1) + ruby2_keywords (>= 0.0.4) + faraday-net_http (3.0.2) + ffi (1.15.5) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (212) - github-pages-health-check (= 1.17.0) - jekyll (= 3.9.0) + github-pages (227) + github-pages-health-check (= 1.17.9) + jekyll (= 3.9.2) jekyll-avatar (= 0.7.0) jekyll-coffeescript (= 1.1.1) - jekyll-commonmark-ghpages (= 0.1.6) + jekyll-commonmark-ghpages (= 0.2.0) jekyll-default-layout (= 0.1.4) jekyll-feed (= 0.15.1) jekyll-gist (= 1.5.0) jekyll-github-metadata (= 2.13.0) + jekyll-include-cache (= 0.2.1) jekyll-mentions (= 1.6.0) jekyll-optional-front-matter (= 0.3.2) jekyll-paginate (= 1.1.0) jekyll-readme-index (= 0.3.0) jekyll-redirect-from (= 0.16.0) jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.2) + jekyll-remote-theme (= 0.4.3) jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.7.1) + jekyll-seo-tag (= 2.8.0) jekyll-sitemap (= 1.4.0) jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.1.1) - jekyll-theme-cayman (= 0.1.1) - jekyll-theme-dinky (= 0.1.1) - jekyll-theme-hacker (= 0.1.2) - jekyll-theme-leap-day (= 0.1.1) - jekyll-theme-merlot (= 0.1.1) - jekyll-theme-midnight (= 0.1.1) - jekyll-theme-minimal (= 0.1.1) - jekyll-theme-modernist (= 0.1.1) - jekyll-theme-primer (= 0.5.4) - jekyll-theme-slate (= 0.1.1) - jekyll-theme-tactile (= 0.1.1) - jekyll-theme-time-machine (= 0.1.1) + jekyll-theme-architect (= 0.2.0) + jekyll-theme-cayman (= 0.2.0) + jekyll-theme-dinky (= 0.2.0) + jekyll-theme-hacker (= 0.2.0) + jekyll-theme-leap-day (= 0.2.0) + jekyll-theme-merlot (= 0.2.0) + jekyll-theme-midnight (= 0.2.0) + jekyll-theme-minimal (= 0.2.0) + jekyll-theme-modernist (= 0.2.0) + jekyll-theme-primer (= 0.6.0) + jekyll-theme-slate (= 0.2.0) + jekyll-theme-tactile (= 0.2.0) + jekyll-theme-time-machine (= 0.2.0) jekyll-titles-from-headings (= 0.5.3) jemoji (= 0.12.0) - kramdown (= 2.3.0) + kramdown (= 2.3.2) kramdown-parser-gfm (= 1.1.0) liquid (= 4.0.3) mercenary (~> 0.3) minima (= 2.5.1) - nokogiri (>= 1.10.4, < 2.0) + nokogiri (>= 1.13.6, < 2.0) rouge (= 3.26.0) terminal-table (~> 1.4) - github-pages-health-check (1.17.0) + github-pages-health-check (1.17.9) addressable (~> 2.3) dnsruby (~> 1.60) octokit (~> 4.0) - public_suffix (>= 2.0.2, < 5.0) + public_suffix (>= 3.0, < 5.0) typhoeus (~> 1.3) - html-pipeline (2.14.0) + html-pipeline (2.14.3) activesupport (>= 2) nokogiri (>= 1.4) - http_parser.rb (0.6.0) + http_parser.rb (0.8.0) i18n (0.9.5) concurrent-ruby (~> 1.0) - jekyll (3.9.0) + jekyll (3.9.2) addressable (~> 2.4) colorator (~> 1.0) em-websocket (~> 0.5) @@ -108,12 +107,12 @@ GEM jekyll-coffeescript (1.1.1) coffee-script (~> 2.2) coffee-script-source (~> 1.11.1) - jekyll-commonmark (1.3.1) - commonmarker (~> 0.14) - jekyll (>= 3.7, < 5.0) - jekyll-commonmark-ghpages (0.1.6) - commonmarker (~> 0.17.6) - jekyll-commonmark (~> 1.2) + jekyll-commonmark (1.4.0) + commonmarker (~> 0.22) + jekyll-commonmark-ghpages (0.2.0) + commonmarker (~> 0.23.4) + jekyll (~> 3.9.0) + jekyll-commonmark (~> 1.4.0) rouge (>= 2.0, < 4.0) jekyll-default-layout (0.1.4) jekyll (~> 3.0) @@ -124,6 +123,8 @@ GEM jekyll-github-metadata (2.13.0) jekyll (>= 3.4, < 5.0) octokit (~> 4.0, != 4.4.0) + jekyll-include-cache (0.2.1) + jekyll (>= 3.7, < 5.0) jekyll-mentions (1.6.0) html-pipeline (~> 2.3) jekyll (>= 3.7, < 5.0) @@ -136,57 +137,57 @@ GEM jekyll (>= 3.3, < 5.0) jekyll-relative-links (0.6.1) jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.2) + jekyll-remote-theme (0.4.3) addressable (~> 2.0) jekyll (>= 3.5, < 5.0) jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) rubyzip (>= 1.3.0, < 3.0) jekyll-sass-converter (1.5.2) sass (~> 3.4) - jekyll-seo-tag (2.7.1) + jekyll-seo-tag (2.8.0) jekyll (>= 3.8, < 5.0) jekyll-sitemap (1.4.0) jekyll (>= 3.7, < 5.0) jekyll-swiss (1.0.0) - jekyll-theme-architect (0.1.1) - jekyll (~> 3.5) + jekyll-theme-architect (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.1.1) - jekyll (~> 3.5) + jekyll-theme-cayman (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.1.1) - jekyll (~> 3.5) + jekyll-theme-dinky (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.1.2) + jekyll-theme-hacker (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.1.1) - jekyll (~> 3.5) + jekyll-theme-leap-day (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.1.1) - jekyll (~> 3.5) + jekyll-theme-merlot (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.1.1) - jekyll (~> 3.5) + jekyll-theme-midnight (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.1.1) - jekyll (~> 3.5) + jekyll-theme-minimal (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.1.1) - jekyll (~> 3.5) + jekyll-theme-modernist (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.5.4) + jekyll-theme-primer (0.6.0) jekyll (> 3.5, < 5.0) jekyll-github-metadata (~> 2.9) jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.1.1) - jekyll (~> 3.5) + jekyll-theme-slate (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.1.1) - jekyll (~> 3.5) + jekyll-theme-tactile (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.1.1) - jekyll (~> 3.5) + jekyll-theme-time-machine (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-titles-from-headings (0.5.3) jekyll (>= 3.3, < 5.0) @@ -196,12 +197,12 @@ GEM gemoji (~> 3.0) html-pipeline (~> 2.2) jekyll (>= 3.0, < 5.0) - kramdown (2.3.0) + kramdown (2.3.2) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) liquid (4.0.3) - listen (3.4.1) + listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.3.6) @@ -209,37 +210,36 @@ GEM jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.14.4) - multipart-post (2.1.1) - nokogiri (1.12.5-x86_64-darwin) + minitest (5.17.0) + nokogiri (1.14.3-arm64-darwin) + racc (~> 1.4) + nokogiri (1.14.3-x86_64-darwin) racc (~> 1.4) - nokogiri (1.12.5-x86_64-linux) + nokogiri (1.14.3-x86_64-linux) racc (~> 1.4) - octokit (4.20.0) - faraday (>= 0.9) - sawyer (~> 0.8.0, >= 0.5.3) + octokit (4.25.1) + faraday (>= 1, < 3) + sawyer (~> 0.9) pathutil (0.16.2) forwardable-extended (~> 2.6) - public_suffix (4.0.6) - racc (1.5.2) - rb-fsevent (0.10.4) + public_suffix (4.0.7) + racc (1.6.2) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) rexml (3.2.5) rouge (3.26.0) - ruby-enum (0.9.0) - i18n - ruby2_keywords (0.0.4) - rubyzip (2.3.0) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) safe_yaml (1.0.5) sass (3.7.4) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.8.2) + sawyer (0.9.2) addressable (>= 2.3.5) - faraday (> 0.8, < 2.0) + faraday (>= 0.17.3, < 3) simpleidn (0.2.1) unf (~> 0.1.4) terminal-table (1.8.0) @@ -247,16 +247,17 @@ GEM thread_safe (0.3.6) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.9) + tzinfo (1.2.10) thread_safe (~> 0.1) unf (0.1.4) unf_ext - unf_ext (0.0.7.7) - unicode-display_width (1.7.0) + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) webrick (1.7.0) - zeitwerk (2.4.2) + zeitwerk (2.6.6) PLATFORMS + arm64-darwin-22 x86_64-darwin-20 x86_64-linux @@ -266,4 +267,4 @@ DEPENDENCIES webrick (~> 1.7) BUNDLED WITH - 2.2.13 + 2.3.26 diff --git a/LICENSE b/LICENSE index 5ec214b971..27d0e197d4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Zhuang Ma +Copyright (c) 2013 Fulong Ma Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index 995697195a..7c748d8cc8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Usage -无 +draft: true表示是草稿。 ## Acknowledge diff --git a/_config.yml b/_config.yml index 4c08f7ba29..82a5e40296 100644 --- a/_config.yml +++ b/_config.yml @@ -7,18 +7,17 @@ date_format: "ordinal" title: Fulongのblog subtitle: "Hi" description: "Fulongのblog" -# subtitle: "Legendary" -subtitle: "逃跑可耻但有用" +subtitle: "Logbook" keywords: logbook, mafulong timezone: Asia/Shanghai encoding: "utf-8" -side_bar_repo_limit: 4 -# 下面涉及js引用,先不能改 +side_bar_repo_limit: 3 repository: mafulong/mafulong.github.io # 对 css 和 js 资源的 cdn 加速配置 cdn: jsdelivr: - enabled: true + enabled: true + branch: "built" # 组件配置 components: # 分享 @@ -27,7 +26,6 @@ components: # 不蒜子访问统计 busuanzi: enabled: true - start_date: 2020-05-03 # 压缩页面内容 compress_html: clippings: all @@ -64,29 +62,18 @@ navs: href: /archives/ label: Achieves - # - - # href: /open-source - # label: Open-Source + - + href: /open-source + label: Open-Source -# - -# href: /wiki -# label: Wiki - href: /bookmark label: Bookmark -# - -# href: /links -# label: Links - href: /about label: About -# ---------------- # -# RSS # -# ---------------- # -# subscribe_rss: /feed.xml - # ---------------- # # Jekyll # # ---------------- # @@ -117,7 +104,7 @@ collections: # Comments # # ---------------- # # support provider: disqus, gitment, gitalk -comments_provider: gitalk +# comments_provider: gitalk # !!!重要!!! 请修改下面这些信息为你自己申请的 # !!!Important!!! Please modify infos below to yours # https://disqus.com @@ -131,11 +118,11 @@ comments_provider: gitalk # client_id: d2e1cbbd298958076462 # client_secret: b42a4178e5fd4a7cf63189ef4b1453b05c375709 # https://github.com/gitalk/gitalk#install -gitalk: - owner: mafulong - repo: blog-comment - clientID: 99d40aa8c51f2e320555 - clientSecret: 08d7d01185f19e4e205adc2b36a6750d92d640c2 +# gitalk: + # owner: mafulong + # repo: blog-comment + # clientID: 99d40aa8c51f2e320555 + # clientSecret: 08d7d01185f19e4e205adc2b36a6750d92d640c2 # 在使用其它评论组件时可点击显示 Disqus lazy_load_disqus : false @@ -146,16 +133,14 @@ simple_jekyll_search: # 是否支持全文搜索 fulltext: false # 最多显示多少条搜索结果 - limit: 16 + limit: 20 # ---------------- # # Google # # ---------------- # google: - # analytics_id: UA-80669434-1 - analytics_id: G-SS4VDLWLNC adsense: + header: false footer: false - sidebar: false content_header: false content_footer: false diff --git a/_data/links.yml b/_data/links.yml deleted file mode 100644 index 71cac97ce9..0000000000 --- a/_data/links.yml +++ /dev/null @@ -1,72 +0,0 @@ - -# - name: Connie 酱 -# url: https://connie99.github.io -# src: life - -# - name: 只宁静不致远 -# url: http://zxning.github.io -# src: life - -# - name: Blog Something -# url: http://chenxiaoyoyo.github.io -# src: life - -# - name: 日新亭 -# url: http://www.fengerzh.com/ -# src: life - -# - name: wanandroid -# url: http://www.wanandroid.com/ -# src: life - -# - name: ZZY补完计划 -# url: https://zzycreate.github.io/ -# src: life - -# - name: 村农 -# url: http://www.why-dong.com/ -# src: life - -# - name: 求生之路 -# url: http://blog.xiaolaoni.xin/ -# src: life - -# - name: 王玉超 -# url: https://yuchao.wang/ -# src: life - -# - name: 董小姐的草原 -# url: https://candy961.github.io/ -# src: life - -# - name: 水寒的博客 -# url: https://dp2px.com -# src: www - -# - name: 孙不服的博客 -# url: https://sunbufu.github.io/ -# src: www - -# - name: HwiLu's 博客 -# url: https://hwilu.github.io/ -# src: www - -# - name: 有次博客 -# url: http://you.ci/ -# src: www - -# - name: 呓城之城 -# url: http://yicheng.zdyrs.com/ -# src: www - -# - name: 秦大圣的博客 -# url: https://qinjisheng.top/ -# src: www - -# - name: 极客玩家大白 -# url: https://geekplayers.com/ -# src: www - -# - name: 见字如面 -# url: https://hiwannz.com -# src: www diff --git a/_data/skills.yml b/_data/skills.yml deleted file mode 100644 index 4575e85c17..0000000000 --- a/_data/skills.yml +++ /dev/null @@ -1,19 +0,0 @@ -# - name: Software Engineer Keywords -# keywords: -# - Java -# - C++ -# - Python -# - Design Patterns - -# - name: Mobile Developer Keywords -# keywords: -# - Android -# - Reverse Engineering - -# - name: Windows Developer Keywords -# keywords: -# - Win32 SDK -# - DuiLib -# - WTL -# - COM -# - WinDbg diff --git a/_data/social.yml b/_data/social.yml deleted file mode 100644 index 609e4c6ec1..0000000000 --- a/_data/social.yml +++ /dev/null @@ -1,12 +0,0 @@ -- sitename: GitHub - name: mafulong - url: https://github.com/mafulong - -- sitename: 博客 - name: LogBook - url: http://mafulong.github.io - -- sitename: 知乎 - name: mafulong知乎 - url: https://www.zhihu.com/people/ma-fu-long-86 - diff --git a/_data/template.md b/_data/template.md deleted file mode 100644 index 5ef1a00a40..0000000000 --- a/_data/template.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -layout: wiki -title: Wiki Template -categories: [cate1, cate2] -description: some word here -keywords: keyword1, keyword2 ---- - -Content here diff --git a/_includes/categories.html b/_includes/categories.html deleted file mode 100644 index de2c117a8c..0000000000 --- a/_includes/categories.html +++ /dev/null @@ -1,44 +0,0 @@ ---- -layout: default ---- - -{% assign assets_base_url = site.url %} -{% if site.cdn.jsdelivr.enabled %} -{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@master' %} -{% endif %} -
-
-
-
-
-

{{ page.title }}

-
-
-
- {% include sidebar-qrcode.html %} -
-
-
-
- -
-
-
-
- {{ content }} -
- -
- {% include comments.html %} -
-
-
- {% include sidebar-search.html %} - {% include sidebar-categories-nav.html %} - -
-
-
- \ No newline at end of file diff --git a/_includes/content-footer-ad.html b/_includes/content-footer-ad.html index ecffc109a9..23062db2e6 100755 --- a/_includes/content-footer-ad.html +++ b/_includes/content-footer-ad.html @@ -1,8 +1,3 @@ {% if site.google.adsense.content_footer %} - - {% endif %} \ No newline at end of file diff --git a/_includes/content-header-ad.html b/_includes/content-header-ad.html index 8c06795bb0..d6fe41ffd3 100755 --- a/_includes/content-header-ad.html +++ b/_includes/content-header-ad.html @@ -1,8 +1,3 @@ -{% if site.google.adsense.content_header and site.url contains 'mafulong.github.io' %} +{% if site.google.adsense.content_header %} - - -
{% endif %} \ No newline at end of file diff --git a/_includes/footer-ad.html b/_includes/footer-ad.html index 2a4c718e72..1315f70f50 100755 --- a/_includes/footer-ad.html +++ b/_includes/footer-ad.html @@ -1,8 +1,3 @@ {% if site.google.adsense.footer and page.layout != 'mindmap' %} - - {% endif %} \ No newline at end of file diff --git a/_includes/footer.html b/_includes/footer.html index 337f5cc66f..a9476309aa 100755 --- a/_includes/footer.html +++ b/_includes/footer.html @@ -43,6 +43,20 @@ + + {% if site.components.share.enabled %} {% endif %} @@ -84,8 +98,8 @@ {% endif %} {% if page.mindmap %} - - + + {% endif %} -
diff --git a/_includes/header.html b/_includes/header.html index 817307bbf8..9b1b62fb67 100755 --- a/_includes/header.html +++ b/_includes/header.html @@ -16,6 +16,7 @@ + {% assign highlight_base_url = 'https://mazhuang.org/rouge-themes/dist' %} {% if site.cdn.jsdelivr.enabled %} {% assign highlight_base_url = 'https://cdn.jsdelivr.net/gh/mzlogin/rouge-themes@master/dist' %} @@ -78,9 +79,10 @@ - + {% if site.google.adsense.header%} + {% endif %} diff --git a/_includes/page.html b/_includes/page.html deleted file mode 100644 index f8c7f371de..0000000000 --- a/_includes/page.html +++ /dev/null @@ -1,52 +0,0 @@ ---- -layout: default ---- - -{% assign assets_base_url = site.url %} -{% if site.cdn.jsdelivr.enabled %} -{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@master' %} -{% endif %} -
-
-
-
-
-

{{ page.title }}

- {% if page.subtitle %} -
- - {{ page.subtitle}} - -
- {% endif %} -
-
- -
-
-
- -
-
-
-
- {{ content }} -
- -
- {% include comments.html %} -
-
- -
-
- \ No newline at end of file diff --git a/_includes/sidebar-ad.html b/_includes/sidebar-ad.html deleted file mode 100755 index 6fbaf11869..0000000000 --- a/_includes/sidebar-ad.html +++ /dev/null @@ -1,8 +0,0 @@ -{% if site.google.adsense.sidebar and site.url contains 'mafulong.github.io' %} - - - -{% endif %}% \ No newline at end of file diff --git a/_includes/sidebar-post-nav.html b/_includes/sidebar-post-nav.html index 0a1902e587..1ab0c58d5b 100644 --- a/_includes/sidebar-post-nav.html +++ b/_includes/sidebar-post-nav.html @@ -1,6 +1,6 @@ -

Table of Contents

-
+

Table of Contents

+
diff --git a/_includes/sidebar-recent-update.html b/_includes/sidebar-recent-update.html new file mode 100755 index 0000000000..68e612e4ab --- /dev/null +++ b/_includes/sidebar-recent-update.html @@ -0,0 +1,11 @@ + +

Popular Posts

+ diff --git a/_includes/sidebar-search.html b/_includes/sidebar-search.html index ed6c900857..f6bdf81bf5 100644 --- a/_includes/sidebar-search.html +++ b/_includes/sidebar-search.html @@ -1,27 +1,50 @@ -

Search

-
    +
      + SimpleJekyllSearch({ + searchInput: document.getElementById('search_box'), + resultsContainer: document.getElementById('search_results'), + {% if site.cdn.jsdelivr.enabled and site.url contains 'mafulong.github.io' %} + json: 'https://cdn.jsdelivr.net/gh/mafulong/mafulong.github.io@built/assets/search_data.json', + {% else %} + json: '{{ site.url }}/assets/search_data.json', + {% endif %} + searchResultTemplate: '
    • {title}
    • ', + noResultsText: 'No results found', + limit: {{ site.simple_jekyll_search.limit }}, + fuzzy: false, + exclude: ['Welcome'] + }); + window.onload = function(){ + var query_text = window.location.search.substring(1); + var vars = query_text.split("&"); + for (var i=0;i diff --git a/_includes/visit-stat.html b/_includes/visit-stat.html index b156a3fa45..23fe1ac07a 100644 --- a/_includes/visit-stat.html +++ b/_includes/visit-stat.html @@ -8,11 +8,5 @@ - - - - - -
      {% endif %} \ No newline at end of file diff --git a/_layouts/categories.html b/_layouts/categories.html index d07595da2b..f9502c6439 100755 --- a/_layouts/categories.html +++ b/_layouts/categories.html @@ -4,7 +4,7 @@ {% assign assets_base_url = site.url %} {% if site.cdn.jsdelivr.enabled %} -{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@master' %} +{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@'| append: site.cdn.jsdelivr.branch %} {% endif %}
      @@ -24,20 +24,26 @@

      {{ page.title }}

      +
      + {% include sidebar-categories-cloud.html %} +
      {{ content }}
      -
      diff --git a/_layouts/default.html b/_layouts/default.html index 9c762fad3d..5d05f3f6a6 100755 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -4,9 +4,8 @@ {% assign assets_base_url = site.url %} {% if site.cdn.jsdelivr.enabled %} -{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@master' %} +{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@'| append: site.cdn.jsdelivr.branch %} {% endif %} -{% assign assets_images_url = ' - - - -
      - - - - diff --git a/_layouts/page.html b/_layouts/page.html index 7ba323b0cb..df074664a8 100755 --- a/_layouts/page.html +++ b/_layouts/page.html @@ -4,7 +4,7 @@ {% assign assets_base_url = site.url %} {% if site.cdn.jsdelivr.enabled %} -{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@master' %} +{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@'| append: site.cdn.jsdelivr.branch %} {% endif %}
      @@ -44,7 +44,7 @@

      {{ page.title }}

      diff --git a/_layouts/post.html b/_layouts/post.html index a544affaf9..08683b3491 100755 --- a/_layouts/post.html +++ b/_layouts/post.html @@ -4,7 +4,7 @@ {% assign assets_base_url = site.url %} {% if site.cdn.jsdelivr.enabled %} -{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@master' %} +{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@'| append: site.cdn.jsdelivr.branch %} {% endif %}
      @@ -50,17 +50,20 @@

      {{ page.title }}

      {{ content }} -
      diff --git a/_layouts/wiki.html b/_layouts/wiki.html deleted file mode 100755 index 68c3ac2e32..0000000000 --- a/_layouts/wiki.html +++ /dev/null @@ -1,46 +0,0 @@ ---- -layout: default ---- - -{% assign assets_base_url = site.url %} -{% if site.cdn.jsdelivr.enabled %} -{% assign assets_base_url = "https://cdn.jsdelivr.net/gh/" | append: site.repository | append: '@master' %} -{% endif %} -
      -
      -
      -
      -
      -

      {{ page.title }}

      -
      -
      -
      - {% include sidebar-qrcode.html %} -
      -
      -
      -
      - -
      -
      -
      - {% include content-header-ad.html %} -
      - {{ content }} - -
      - - {% include content-footer-ad.html %} -
      - {% include comments.html %} -
      -
      -
      - {% include sidebar-search.html %} - {% include sidebar-post-nav.html %} -
      -
      -
      - diff --git a/_posts/Algorithms/leetcode/2022-07-16-2335. Minimum Amount of Time to Fill Cups.md b/_posts/Algorithms/leetcode/2022-07-16-2335. Minimum Amount of Time to Fill Cups.md new file mode 100644 index 0000000000..77e574190c --- /dev/null +++ b/_posts/Algorithms/leetcode/2022-07-16-2335. Minimum Amount of Time to Fill Cups.md @@ -0,0 +1,78 @@ +--- +layout: post +category: leetcode +title: 2335. Minimum Amount of Time to Fill Cups +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/minimum-amount-of-time-to-fill-cups/) + +You have a water dispenser that can dispense cold, warm, and hot water. Every second, you can either fill up `2` cups with **different** types of water, or `1` cup of any type of water. + +You are given a **0-indexed** integer array `amount` of length `3` where `amount[0]`, `amount[1]`, and `amount[2]` denote the number of cold, warm, and hot water cups you need to fill respectively. Return *the **minimum** number of seconds needed to fill up all the cups*. + + + +**Example 1:** + +``` +Input: amount = [1,4,2] +Output: 4 +Explanation: One way to fill up the cups is: +Second 1: Fill up a cold cup and a warm cup. +Second 2: Fill up a warm cup and a hot cup. +Second 3: Fill up a warm cup and a hot cup. +Second 4: Fill up a warm cup. +It can be proven that 4 is the minimum number of seconds needed. +``` + +**Example 2:** + +``` +Input: amount = [5,4,4] +Output: 7 +Explanation: One way to fill up the cups is: +Second 1: Fill up a cold cup, and a hot cup. +Second 2: Fill up a cold cup, and a warm cup. +Second 3: Fill up a cold cup, and a warm cup. +Second 4: Fill up a warm cup, and a hot cup. +Second 5: Fill up a cold cup, and a hot cup. +Second 6: Fill up a cold cup, and a warm cup. +Second 7: Fill up a hot cup. +``` + +**Example 3:** + +``` +Input: amount = [5,0,0] +Output: 5 +Explanation: Every second, we fill up a cold cup. +``` + + + +**Constraints:** + +- `amount.length == 3` +- `0 <= amount[i] <= 100` + +## solution + +We can use the technique of greedy and category discussion. + +At every step only choose the max-2 cups to be filled. + +```python +class Solution: + def fillCups(self, amount: List[int]) -> int: + a, b, c = sorted(amount, reverse=True) + if b + c < a: + return a + t = b + c - a + if t % 2 == 0: + return (t // 2) + a + # t is odd + return ((t - 1) // 2) + a + 1 +``` + diff --git a/_posts/Algorithms/leetcode/2022-07-16-2336. Smallest Number in Infinite Set.md b/_posts/Algorithms/leetcode/2022-07-16-2336. Smallest Number in Infinite Set.md new file mode 100644 index 0000000000..9ced85dc92 --- /dev/null +++ b/_posts/Algorithms/leetcode/2022-07-16-2336. Smallest Number in Infinite Set.md @@ -0,0 +1,81 @@ +--- +layout: post +category: leetcode +title: 2336. Smallest Number in Infinite Set +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/smallest-number-in-infinite-set/) + +You have a set which contains all positive integers `[1, 2, 3, 4, 5, ...]`. + +Implement the `SmallestInfiniteSet` class: + +- `SmallestInfiniteSet()` Initializes the **SmallestInfiniteSet** object to contain **all** positive integers. +- `int popSmallest()` **Removes** and returns the smallest integer contained in the infinite set. +- `void addBack(int num)` **Adds** a positive integer `num` back into the infinite set, if it is **not** already in the infinite set. + + + +**Example 1:** + +``` +Input +["SmallestInfiniteSet", "addBack", "popSmallest", "popSmallest", "popSmallest", "addBack", "popSmallest", "popSmallest", "popSmallest"] +[[], [2], [], [], [], [1], [], [], []] +Output +[null, null, 1, 2, 3, null, 1, 4, 5] + +Explanation +SmallestInfiniteSet smallestInfiniteSet = new SmallestInfiniteSet(); +smallestInfiniteSet.addBack(2); // 2 is already in the set, so no change is made. +smallestInfiniteSet.popSmallest(); // return 1, since 1 is the smallest number, and remove it from the set. +smallestInfiniteSet.popSmallest(); // return 2, and remove it from the set. +smallestInfiniteSet.popSmallest(); // return 3, and remove it from the set. +smallestInfiniteSet.addBack(1); // 1 is added back to the set. +smallestInfiniteSet.popSmallest(); // return 1, since 1 was added back to the set and + // is the smallest number, and remove it from the set. +smallestInfiniteSet.popSmallest(); // return 4, and remove it from the set. +smallestInfiniteSet.popSmallest(); // return 5, and remove it from the set. +``` + + + +**Constraints:** + +- `1 <= num <= 1000` +- At most `1000` calls will be made **in total** to `popSmallest` and `addBack`. + +## solution + +One way, we can use the heapq + set. Another way, we can divide it into two parts, maintain the smallest num and a sortedset so that no initial heap in the first. + +```python +import heapq + + +class SmallestInfiniteSet: + + def __init__(self): + self.h = list(range(1, 1001, 1)) + self.s = set(self.h) + heapq.heapify(self.h) + + def popSmallest(self) -> int: + if self.h: + r = heapq.heappop(self.h) + self.s.remove(r) + return r + return -1 + + def addBack(self, num: int) -> None: + if num in self.s: + return + self.s.add(num) + heapq.heappush(self.h, num) + +``` + + + diff --git "a/_posts/Algorithms/leetcode/2022-08-18-2375. \346\240\271\346\215\256\346\250\241\345\274\217\344\270\262\346\236\204\351\200\240\346\234\200\345\260\217\346\225\260\345\255\227.md" "b/_posts/Algorithms/leetcode/2022-08-18-2375. \346\240\271\346\215\256\346\250\241\345\274\217\344\270\262\346\236\204\351\200\240\346\234\200\345\260\217\346\225\260\345\255\227.md" new file mode 100644 index 0000000000..d918b09610 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-08-18-2375. \346\240\271\346\215\256\346\250\241\345\274\217\344\270\262\346\236\204\351\200\240\346\234\200\345\260\217\346\225\260\345\255\227.md" @@ -0,0 +1,79 @@ +--- +layout: post +category: leetcode +title: 2375. 根据模式串构造最小数字 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/construct-smallest-number-from-di-string/) + +给你下标从 **0** 开始、长度为 `n` 的字符串 `pattern` ,它包含两种字符,`'I'` 表示 **上升** ,`'D'` 表示 **下降** 。 + +你需要构造一个下标从 **0** 开始长度为 `n + 1` 的字符串,且它要满足以下条件: + +- `num` 包含数字 `'1'` 到 `'9'` ,其中每个数字 **至多** 使用一次。 +- 如果 `pattern[i] == 'I'` ,那么 `num[i] < num[i + 1]` 。 +- 如果 `pattern[i] == 'D'` ,那么 `num[i] > num[i + 1]` 。 + +请你返回满足上述条件字典序 **最小** 的字符串 `num`。 + + + +**示例 1:** + +``` +输入:pattern = "IIIDIDDD" +输出:"123549876" +解释: +下标 0 ,1 ,2 和 4 处,我们需要使 num[i] < num[i+1] 。 +下标 3 ,5 ,6 和 7 处,我们需要使 num[i] > num[i+1] 。 +一些可能的 num 的值为 "245639871" ,"135749862" 和 "123849765" 。 +"123549876" 是满足条件最小的数字。 +注意,"123414321" 不是可行解因为数字 '1' 使用次数超过 1 次。 +``` + +**示例 2:** + +``` +输入:pattern = "DDD" +输出:"4321" +解释: +一些可能的 num 的值为 "9876" ,"7321" 和 "8742" 。 +"4321" 是满足条件最小的数字。 +``` + + + +**提示:** + +- `1 <= pattern.length <= 8` +- `pattern` 只包含字符 `'I'` 和 `'D'` 。 + + +## solution + +```python +''' +贪心: 数字其实就是123456789,遇到连续的D,就将连续的数字reverse, 其实就是找连续的I,连续的D,然后分段。 +''' +class Solution: + def smallestNumber(self, pattern: str) -> str: + n = len(pattern) + i = 0 + ans = [] + while i < n: + if i and pattern[i] == "I": + i += 1 + while i < n and pattern[i] == "I": + i += 1 + ans.append(i) + i0 = i + while i < n and pattern[i] == "D": + i += 1 + for x in range(i + 1, i0, -1): + ans.append(x) + return "".join(map(str, ans)) + +``` + diff --git "a/_posts/Algorithms/leetcode/2022-08-27-2386. \346\211\276\345\207\272\346\225\260\347\273\204\347\232\204\347\254\254 K \345\244\247\345\222\214.md" "b/_posts/Algorithms/leetcode/2022-08-27-2386. \346\211\276\345\207\272\346\225\260\347\273\204\347\232\204\347\254\254 K \345\244\247\345\222\214.md" new file mode 100644 index 0000000000..3184ef4b94 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-08-27-2386. \346\211\276\345\207\272\346\225\260\347\273\204\347\232\204\347\254\254 K \345\244\247\345\222\214.md" @@ -0,0 +1,136 @@ +--- +layout: post +category: leetcode +title: 2386. 找出数组的第 K 大和 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/find-the-k-sum-of-an-array/) + +给你一个整数数组 `nums` 和一个 **正** 整数 `k` 。你可以选择数组的任一 **子序列** 并且对其全部元素求和。 + +数组的 **第 k 大和** 定义为:可以获得的第 `k` 个 **最大** 子序列和(子序列和允许出现重复) + +返回数组的 **第 k 大和** 。 + +子序列是一个可以由其他数组删除某些或不删除元素排生而来的数组,且派生过程不改变剩余元素的顺序。 + +**注意:**空子序列的和视作 `0` 。 + + + +**示例 1:** + +``` +输入:nums = [2,4,-2], k = 5 +输出:2 +解释:所有可能获得的子序列和列出如下,按递减顺序排列: +- 6、4、4、2、2、0、0、-2 +数组的第 5 大和是 2 。 +``` + +**示例 2:** + +``` +输入:nums = [1,-2,3,4,-10,12], k = 16 +输出:10 +解释:数组的第 16 大和是 10 。 +``` + + + +**提示:** + +- `n == nums.length` +- `1 <= n <= 105` +- `-109 <= nums[i] <= 109` +- `1 <= k <= min(2000, 2n)` + +## solution + +[参考](https://leetcode.cn/problems/find-the-k-sum-of-an-array/solution/zhuan-huan-dui-by-endlesscheng-8yiq/) + +要记住 + +- 数组有序后,可以用堆动态生成子序列的和,按递增顺序,每取一个后便加下一个,同时当前也可减掉。 +- 回溯只要控制深度复杂度也可观,可用于二分等 + + + +优先队列做法 + +```python + +class Solution: + def kSum(self, nums: List[int], k: int) -> int: + s = 0 + for i, x in enumerate(nums): + if x >= 0: + s += x + else: + nums[i] = -x + import heapq + h = [(-s, 0)] + nums.sort() + for _ in range(k - 1): + l, i = heapq.heappop(h) + if i < len(nums): + heapq.heappush(h, (l + nums[i], i + 1)) + if i: + heapq.heappush(h, (l + nums[i] - nums[i - 1], i + 1)) + return - h[0][0] +``` + + + +二分做法 + +```python +class BinarySearch: + # If you wanna binary search big integer, plz set data range, which can be used as same as big integer low and high + # find the first index that value >= val + def bisect_left(data, val, key=None): + l, r = 0, len(data) - 1 + if key is None: + key = lambda x: data[mid] + while l <= r: + mid = (l + r) // 2 + if key(mid) >= val: + r = mid - 1 + else: + l = mid + 1 + return l +class Solution: + def kSum(self, nums: List[int], k: int) -> int: + s = 0 + for i, x in enumerate(nums): + if x >= 0: + s += x + else: + nums[i] = -x + total = sum(nums) + nums.sort() + + # 不超过limit的子序列数量 + def count(limit): + cnt = 0 + + # 算i之后的子序列数量,不包括空序列 + def f(cur, i): + nonlocal cnt + if cnt >= k - 1 or i >= len(nums) or cur + nums[i] > limit: + return + cnt += 1 + f(cur + nums[i], i + 1) + f(cur, i + 1) + + f(0, 0) + return cnt + + j = BinarySearch.bisect_left(range(total), k - 1, key=count) + + return s - j + +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-09-2430. \345\257\271\345\255\227\346\257\215\344\270\262\345\217\257\346\211\247\350\241\214\347\232\204\346\234\200\345\244\247\345\210\240\351\231\244\346\225\260.md" "b/_posts/Algorithms/leetcode/2022-10-09-2430. \345\257\271\345\255\227\346\257\215\344\270\262\345\217\257\346\211\247\350\241\214\347\232\204\346\234\200\345\244\247\345\210\240\351\231\244\346\225\260.md" new file mode 100644 index 0000000000..c3ee467c5d --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-09-2430. \345\257\271\345\255\227\346\257\215\344\270\262\345\217\257\346\211\247\350\241\214\347\232\204\346\234\200\345\244\247\345\210\240\351\231\244\346\225\260.md" @@ -0,0 +1,131 @@ +--- +layout: post +category: leetcode +title: 2430. 对字母串可执行的最大删除数 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/maximum-deletions-on-a-string/) + +给你一个仅由小写英文字母组成的字符串 `s` 。在一步操作中,你可以: + +- 删除 **整个字符串** `s` ,或者 +- 对于满足 `1 <= i <= s.length / 2` 的任意 `i` ,如果 `s` 中的 **前** `i` 个字母和接下来的 `i` 个字母 **相等** ,删除 **前** `i` 个字母。 + +例如,如果 `s = "ababc"` ,那么在一步操作中,你可以删除 `s` 的前两个字母得到 `"abc"` ,因为 `s` 的前两个字母和接下来的两个字母都等于 `"ab"` 。 + +返回删除 `s` 所需的最大操作数。 + + + +**示例 1:** + +``` +输入:s = "abcabcdabc" +输出:2 +解释: +- 删除前 3 个字母("abc"),因为它们和接下来 3 个字母相等。现在,s = "abcdabc"。 +- 删除全部字母。 +一共用了 2 步操作,所以返回 2 。可以证明 2 是所需的最大操作数。 +注意,在第二步操作中无法再次删除 "abc" ,因为 "abc" 的下一次出现并不是位于接下来的 3 个字母。 +``` + +**示例 2:** + +``` +输入:s = "aaabaab" +输出:4 +解释: +- 删除第一个字母("a"),因为它和接下来的字母相等。现在,s = "aabaab"。 +- 删除前 3 个字母("aab"),因为它们和接下来 3 个字母相等。现在,s = "aab"。 +- 删除第一个字母("a"),因为它和接下来的字母相等。现在,s = "ab"。 +- 删除全部字母。 +一共用了 4 步操作,所以返回 4 。可以证明 4 是所需的最大操作数。 +``` + +**示例 3:** + +``` +输入:s = "aaaaa" +输出:5 +解释:在每一步操作中,都可以仅删除 s 的第一个字母。 +``` + + + +**提示:** + +- `1 <= s.length <= 4000` +- `s` 仅由小写英文字母组成 + +## solution + +[参考](https://leetcode.cn/problems/maximum-deletions-on-a-string/solution/xian-xing-dppythonjavacgo-by-endlesschen-gpx9/) 不加特例判断会超时,因此使用hash string更优 + +```python +class Solution: + def deleteString(self, s: str) -> int: + n = len(s) + if len(set(s)) == 1: return n # 特判全部相同的情况 + lcp = [[0] * (n + 1) for _ in range(n + 1)] # lcp[i][j] 表示 s[i:] 和 s[j:] 的最长公共前缀 + for i in range(n - 1, -1, -1): + for j in range(n - 1, i, -1): + if s[i] == s[j]: + lcp[i][j] = lcp[i + 1][j + 1] + 1 + f = [0] * n + for i in range(n - 1, -1, -1): + for j in range(1, (n - i) // 2 + 1): + if lcp[i][i + j] >= j: # 说明 s[i:i+j] == s[i+j:i+2*j] + f[i] = max(f[i], f[i + j]) + f[i] += 1 + return f[0] +``` + +hash string也会超时 + + + +```python +class StringHash: + def __init__(self, s=""): + self.MOD = 998244353 + self.BASE = 131 + # 计算前缀哈希值 + n = len(s) + P = [0] * (n + 1) + P[0] = 1 + for i in range(1, n + 1, 1): + P[i] = P[i - 1] * self.BASE % self.MOD + H = [0] * (n + 1) + for i in range(1, n + 1, 1): + H[i] = (H[i - 1] * self.BASE + ord(s[i - 1])) % self.MOD + self.H = H + self.P = P + + ''' + s的[l,r]区间的hash值,闭区间, l从1开始 + ''' + + def get_hash(self, l=0, r=0): + l, r = l + 1, r + 1 + return (self.H[r] - self.H[l - 1] * self.P[r - l + 1] % self.MOD + self.MOD) % self.MOD + + +class Solution: + def deleteString(self, s: str) -> int: + n = len(s) + dp = [1] * n + hash = StringHash(s) + for i in range(n - 1, -1, -1): + for j in range(i + 1, n): + if (j - i + 1) % 2 == 0: + mid = (i + j) // 2 + if hash.get_hash(i, mid) == hash.get_hash(mid+1, j): + # print(i, j, mid) + dp[i] = max(dp[i], dp[mid+1]+1) + # print(dp[i]) + # print(dp) + return dp[0] +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-09-6202. \344\275\277\347\224\250\346\234\272\345\231\250\344\272\272\346\211\223\345\215\260\345\255\227\345\205\270\345\272\217\346\234\200\345\260\217\347\232\204\345\255\227\347\254\246\344\270\262.md" "b/_posts/Algorithms/leetcode/2022-10-09-6202. \344\275\277\347\224\250\346\234\272\345\231\250\344\272\272\346\211\223\345\215\260\345\255\227\345\205\270\345\272\217\346\234\200\345\260\217\347\232\204\345\255\227\347\254\246\344\270\262.md" new file mode 100644 index 0000000000..949501f164 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-09-6202. \344\275\277\347\224\250\346\234\272\345\231\250\344\272\272\346\211\223\345\215\260\345\255\227\345\205\270\345\272\217\346\234\200\345\260\217\347\232\204\345\255\227\347\254\246\344\270\262.md" @@ -0,0 +1,119 @@ +--- +layout: post +category: leetcode +title: 6202. 使用机器人打印字典序最小的字符串 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/using-a-robot-to-print-the-lexicographically-smallest-string/) + +给你一个字符串 `s` 和一个机器人,机器人当前有一个空字符串 `t` 。执行以下操作之一,直到 `s` 和 `t` **都变成空字符串:** + +- 删除字符串 `s` 的 **第一个** 字符,并将该字符给机器人。机器人把这个字符添加到 `t` 的尾部。 +- 删除字符串 `t` 的 **最后一个** 字符,并将该字符给机器人。机器人将该字符写到纸上。 + +请你返回纸上能写出的字典序最小的字符串。 + + + +**示例 1:** + +``` +输入:s = "zza" +输出:"azz" +解释:用 p 表示写出来的字符串。 +一开始,p="" ,s="zza" ,t="" 。 +执行第一个操作三次,得到 p="" ,s="" ,t="zza" 。 +执行第二个操作三次,得到 p="azz" ,s="" ,t="" 。 +``` + +**示例 2:** + +``` +输入:s = "bac" +输出:"abc" +解释:用 p 表示写出来的字符串。 +执行第一个操作两次,得到 p="" ,s="c" ,t="ba" 。 +执行第二个操作两次,得到 p="ab" ,s="c" ,t="" 。 +执行第一个操作,得到 p="ab" ,s="" ,t="c" 。 +执行第二个操作,得到 p="abc" ,s="" ,t="" 。 +``` + +**示例 3:** + +``` +输入:s = "bdda" +输出:"addb" +解释:用 p 表示写出来的字符串。 +一开始,p="" ,s="bdda" ,t="" 。 +执行第一个操作四次,得到 p="" ,s="" ,t="bdda" 。 +执行第二个操作四次,得到 p="addb" ,s="" ,t="" 。 +``` + + + +**提示:** + +- `1 <= s.length <= 105` +- `s` 只包含小写英文字母。 + +## solution + +本题是经典贪心:求出栈序列的最小字典序。 + +我们首先将题目描述进行转化:有一个初始为空的栈,给定字符的入栈顺序,求字典序最小的出栈序列。 + +```python +class Solution: + def robotWithString(self, s: str) -> str: + stack = [] + import collections + counter = collections.Counter(s) + ans = [] + ''' + 栈模拟, 栈顶是最小的就弹出,否则就继续入栈等有更小的弹出 + ''' + for c in s: + # 判断后面是否还有比它小的 + counter[c] -= 1 + minc = c + for x in string.ascii_lowercase: + if counter[x] > 0: + minc = x + break + # print(c, minc) + stack.append(c) + while stack and stack[-1] <= minc: + ans.append(stack.pop()) + return "".join(ans + stack[::-1]) + + +class Solution: + def robotWithString(self, s: str) -> str: + stack = [] + ans = [] + minc = [None] * (len(s) + 1) + t = 'z' + for i in range(len(s) - 1, -1, -1): + t = min(t, s[i]) + minc[i] = t + minc[-1] = chr(ord('z') + 1) + ''' + 栈模拟, 栈顶是最小的就弹出,否则就继续入栈等有更小的弹出 + ''' + for i, c in enumerate(s): + # 判断后面是否还有比它小的 + stack.append(c) + while stack and stack[-1] <= minc[i + 1]: + ans.append(stack.pop()) + return "".join(ans + stack) + + +if __name__ == '__main__': + f = Solution().robotWithString + print("actual:", f("caba"), "should:", None) + print("actual:", f("bac"), "should:", None) + print("actual:", f("bdda"), "should:", None) +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-16-6207. \347\273\237\350\256\241\345\256\232\347\225\214\345\255\220\346\225\260\347\273\204\347\232\204\346\225\260\347\233\256.md" "b/_posts/Algorithms/leetcode/2022-10-16-6207. \347\273\237\350\256\241\345\256\232\347\225\214\345\255\220\346\225\260\347\273\204\347\232\204\346\225\260\347\233\256.md" new file mode 100644 index 0000000000..3b8f7268b5 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-16-6207. \347\273\237\350\256\241\345\256\232\347\225\214\345\255\220\346\225\260\347\273\204\347\232\204\346\225\260\347\233\256.md" @@ -0,0 +1,71 @@ +--- +layout: post +category: leetcode +title: 6207. 统计定界子数组的数目 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/count-subarrays-with-fixed-bounds/) + +给你一个整数数组 `nums` 和两个整数 `minK` 以及 `maxK` 。 + +`nums` 的定界子数组是满足下述条件的一个子数组: + +- 子数组中的 **最小值** 等于 `minK` 。 +- 子数组中的 **最大值** 等于 `maxK` 。 + +返回定界子数组的数目。 + +子数组是数组中的一个连续部分。 + + + +**示例 1:** + +``` +输入:nums = [1,3,5,2,7,5], minK = 1, maxK = 5 +输出:2 +解释:定界子数组是 [1,3,5] 和 [1,3,5,2] 。 +``` + +**示例 2:** + +``` +输入:nums = [1,1,1,1], minK = 1, maxK = 1 +输出:10 +解释:nums 的每个子数组都是一个定界子数组。共有 10 个子数组。 +``` + + + +**提示:** + +- `2 <= nums.length <= 105` +- `1 <= nums[i], minK, maxK <= 106` + +## solution + +双指针 + +```python +class Solution: + def countSubarrays(self, nums: List[int], minK: int, maxK: int) -> int: + left = -1 + minI, maxI = -1, -1 + ans = 0 + for i, v in enumerate(nums): + if v < minK or v > maxK: + # 清空窗口 + left = i + minI = maxI = -1 + continue + if v == minK: + minI = i + if v == maxK: + maxI = i + if maxI != -1 and minI != -1: + ans += min(minI, maxI) - left + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-16-6211. \345\210\233\345\273\272\344\273\267\345\200\274\347\233\270\345\220\214\347\232\204\350\277\236\351\200\232\345\235\227.md" "b/_posts/Algorithms/leetcode/2022-10-16-6211. \345\210\233\345\273\272\344\273\267\345\200\274\347\233\270\345\220\214\347\232\204\350\277\236\351\200\232\345\235\227.md" new file mode 100644 index 0000000000..e733848d31 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-16-6211. \345\210\233\345\273\272\344\273\267\345\200\274\347\233\270\345\220\214\347\232\204\350\277\236\351\200\232\345\235\227.md" @@ -0,0 +1,90 @@ +--- +layout: post +category: leetcode +title: 6211. 创建价值相同的连通块 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/create-components-with-same-value/) + +有一棵 `n` 个节点的无向树,节点编号为 `0` 到 `n - 1` 。 + +给你一个长度为 `n` 下标从 **0** 开始的整数数组 `nums` ,其中 `nums[i]` 表示第 `i` 个节点的值。同时给你一个长度为 `n - 1` 的二维整数数组 `edges` ,其中 `edges[i] = [ai, bi]` 表示节点 `ai` 与 `bi` 之间有一条边。 + +你可以 **删除** 一些边,将这棵树分成几个连通块。一个连通块的 **价值** 定义为这个连通块中 **所有** 节点 `i` 对应的 `nums[i]` 之和。 + +你需要删除一些边,删除后得到的各个连通块的价值都相等。请返回你可以删除的边数 **最多** 为多少。 + + + +**示例 1:** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210161356949.png) + +``` +输入:nums = [6,2,2,2,6], edges = [[0,1],[1,2],[1,3],[3,4]] +输出:2 +解释:上图展示了我们可以删除边 [0,1] 和 [3,4] 。得到的连通块为 [0] ,[1,2,3] 和 [4] 。每个连通块的价值都为 6 。可以证明没有别的更好的删除方案存在了,所以答案为 2 。 +``` + +**示例 2:** + +``` +输入:nums = [2], edges = [] +输出:0 +解释:没有任何边可以删除。 +``` + + + +**提示:** + +- `1 <= n <= 2 * 104` +- `nums.length == n` +- `1 <= nums[i] <= 50` +- `edges.length == n - 1` +- `edges[i].length == 2` +- `0 <= edges[i][0], edges[i][1] <= n - 1` +- `edges` 表示一棵合法的树。 + +## solution + +[参考](https://leetcode.cn/problems/create-components-with-same-value/solution/by-endlesscheng-u03q/) + +```python +class Solution: + def componentValue(self, nums: List[int], edges: List[List[int]]) -> int: + n = len(nums) + import collections + graph = collections.defaultdict(list) + for u, v in edges: + graph[u].append(v) + graph[v].append(u) + total = sum(nums) + target = 0 + + # return the sum of subtree mod target + def dfs(u, fa=-1): + cur = nums[u] + for v in graph[u]: + if v == fa: continue + t = dfs(v, u) + if t == -1: + return -1 + cur += t + if cur == target: + return 0 + elif cur > target: + return -1 + return cur + + for k in range(min(n, total // max(nums)), 1, -1): + if total % k == 0: + target = total // k + if dfs(0, -1) == 0: + return k - 1 + return 0 + +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-23-407. \346\216\245\351\233\250\346\260\264 II.md" "b/_posts/Algorithms/leetcode/2022-10-23-407. \346\216\245\351\233\250\346\260\264 II.md" new file mode 100644 index 0000000000..74c45a99b1 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-23-407. \346\216\245\351\233\250\346\260\264 II.md" @@ -0,0 +1,83 @@ +--- +layout: post +category: leetcode +title: 407. 接雨水 II +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/trapping-rain-water-ii/) + +给你一个 `m x n` 的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。 + + + +**示例 1:** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210232302169.jpg) + +``` +输入: heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] +输出: 4 +解释: 下雨后,雨水将会被上图蓝色的方块中。总的接雨水量为1+2+1=4。 +``` + +**示例 2:** + +![img](https://assets.leetcode.com/uploads/2021/04/08/trap2-3d.jpg) + +``` +输入: heightMap = [[3,3,3,3,3],[3,2,2,2,3],[3,2,1,2,3],[3,2,2,2,3],[3,3,3,3,3]] +输出: 10 +``` + + + +**提示:** + +- `m == heightMap.length` +- `n == heightMap[i].length` +- `1 <= m, n <= 200` +- `0 <= heightMap[i][j] <= 2 * 104` + + + +## solution + +[参考](https://leetcode.cn/problems/trapping-rain-water-ii/solution/gong-shui-san-xie-jing-dian-dijkstra-yun-13ik/) + +Dijkstra. 从外向内扩展,路径定义为water高度。 + +```python +class Directions: + dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)] + diagonal_dirs = [(1, 1), (1, -1), (-1, 1), (-1, -1)] + all_dirs = dirs + diagonal_dirs + +class Solution: + def trapRainWater(self, heightMap: List[List[int]]) -> int: + m, n = len(heightMap), len(heightMap[0]) + h = [] + import heapq + dist = {} + for i in range(m): + heapq.heappush(h, (heightMap[i][0], i, 0)) + heapq.heappush(h, (heightMap[i][n - 1], i, n - 1)) + for j in range(1, n - 1): + heapq.heappush(h, (heightMap[0][j], 0, j)) + heapq.heappush(h, (heightMap[m - 1][j], m - 1, j)) + ans = 0 + while h: + ph, x, y = heapq.heappop(h) + if (x, y) in dist: continue + dist[(x, y)] = max(heightMap[x][y], ph) + if ph > heightMap[x][y]: + ans += ph - heightMap[x][y] + for dx, dy in Directions.dirs: + nx, ny = x + dx, y + dy + if 0 <= nx < m and 0 <= ny < n and (nx, ny) not in dist: + heapq.heappush(h, (dist[(x, y)], nx, ny)) + # print(dist) + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-23-6216. \344\275\277\346\225\260\347\273\204\347\233\270\347\255\211\347\232\204\346\234\200\345\260\217\345\274\200\351\224\200.md" "b/_posts/Algorithms/leetcode/2022-10-23-6216. \344\275\277\346\225\260\347\273\204\347\233\270\347\255\211\347\232\204\346\234\200\345\260\217\345\274\200\351\224\200.md" new file mode 100644 index 0000000000..140d0c7964 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-23-6216. \344\275\277\346\225\260\347\273\204\347\233\270\347\255\211\347\232\204\346\234\200\345\260\217\345\274\200\351\224\200.md" @@ -0,0 +1,75 @@ +--- +layout: post +category: leetcode +title: 6216. 使数组相等的最小开销 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/minimum-cost-to-make-array-equal/) + +给你两个下标从 **0** 开始的数组 `nums` 和 `cost` ,分别包含 `n` 个 **正** 整数。 + +你可以执行下面操作 **任意** 次: + +- 将 `nums` 中 **任意** 元素增加或者减小 `1` 。 + +对第 `i` 个元素执行一次操作的开销是 `cost[i]` 。 + +请你返回使 `nums` 中所有元素 **相等** 的 **最少** 总开销。 + + + +**示例 1:** + +``` +输入:nums = [1,3,5,2], cost = [2,3,1,14] +输出:8 +解释:我们可以执行以下操作使所有元素变为 2 : +- 增加第 0 个元素 1 次,开销为 2 。 +- 减小第 1 个元素 1 次,开销为 3 。 +- 减小第 2 个元素 3 次,开销为 1 + 1 + 1 = 3 。 +总开销为 2 + 3 + 3 = 8 。 +这是最小开销。 +``` + +**示例 2:** + +``` +输入:nums = [2,2,2,2,2], cost = [4,2,8,1,3] +输出:0 +解释:数组中所有元素已经全部相等,不需要执行额外的操作。 +``` + + + +**提示:** + +- `n == nums.length == cost.length` +- `1 <= n <= 105` +- `1 <= nums[i], cost[i] <= 106` + +## solution + +[参考](https://leetcode.cn/circle/discuss/uO4WuN/) + +![image-20221023180324838](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210231803876.png) + +```python +class Solution: + def minCost(self, nums: List[int], cost: List[int]) -> int: + d = list(zip(nums, cost)) + d = sorted(d) + mid = None + count = 0 + total = sum(cost) + for a, b in d: + count += b + if count >= total // 2: + mid = a + break + return sum(abs(a - mid) * c for a, c in d) + + +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-23-6217. \344\275\277\346\225\260\347\273\204\347\233\270\344\274\274\347\232\204\346\234\200\345\260\221\346\223\215\344\275\234\346\254\241\346\225\260.md" "b/_posts/Algorithms/leetcode/2022-10-23-6217. \344\275\277\346\225\260\347\273\204\347\233\270\344\274\274\347\232\204\346\234\200\345\260\221\346\223\215\344\275\234\346\254\241\346\225\260.md" new file mode 100644 index 0000000000..1370155333 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-23-6217. \344\275\277\346\225\260\347\273\204\347\233\270\344\274\274\347\232\204\346\234\200\345\260\221\346\223\215\344\275\234\346\254\241\346\225\260.md" @@ -0,0 +1,103 @@ +--- +layout: post +category: leetcode +title: 6217. 使数组相似的最少操作次数 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/minimum-number-of-operations-to-make-arrays-similar/) + +给你两个正整数数组 `nums` 和 `target` ,两个数组长度相等。 + +在一次操作中,你可以选择两个 **不同** 的下标 `i` 和 `j` ,其中 `0 <= i, j < nums.length` ,并且: + +- 令 `nums[i] = nums[i] + 2` 且 +- 令 `nums[j] = nums[j] - 2` 。 + +如果两个数组中每个元素出现的频率相等,我们称两个数组是 **相似** 的。 + +请你返回将 `nums` 变得与 `target` 相似的最少操作次数。测试数据保证 `nums` 一定能变得与 `target` 相似。 + + + +**示例 1:** + +``` +输入:nums = [8,12,6], target = [2,14,10] +输出:2 +解释:可以用两步操作将 nums 变得与 target 相似: +- 选择 i = 0 和 j = 2 ,nums = [10,12,4] 。 +- 选择 i = 1 和 j = 2 ,nums = [10,14,2] 。 +2 次操作是最少需要的操作次数。 +``` + +**示例 2:** + +``` +输入:nums = [1,2,5], target = [4,1,3] +输出:1 +解释:一步操作可以使 nums 变得与 target 相似: +- 选择 i = 1 和 j = 2 ,nums = [1,4,3] 。 +``` + +**示例 3:** + +``` +输入:nums = [1,1,1,1,1], target = [1,1,1,1,1] +输出:0 +解释:数组 nums 已经与 target 相似。 +``` + + + +**提示:** + +- `n == nums.length == target.length` +- `1 <= n <= 105` +- `1 <= nums[i], target[i] <= 106` +- `nums` 一定可以变得与 `target` 相似。 + +## solution + +[参考](https://leetcode.cn/problems/minimum-number-of-operations-to-make-arrays-similar/solution/by-endlesscheng-lusx/) + +![image-20221023183508545](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210231835582.png) + +```python +class Solution: + def makeSimilar(self, nums: List[int], target: List[int]) -> int: + nums = sorted(nums, key=lambda x: (x % 2, x)) + target = sorted(target, key=lambda x: (x % 2, x)) + ans = 0 + for i in range(len(nums)): + ans += abs(nums[i] - target[i]) + return ans // 4 + + +class Solution: + def makeSimilar(self, nums: List[int], target: List[int]) -> int: + nums = sorted(nums) + target = sorted(target) + a = [] + b = [] + for v in nums: + if v % 2 == 1: + a.append(v) + else: + b.append(v) + c = [] + d = [] + for v in target: + if v % 2 == 1: + c.append(v) + else: + d.append(v) + ans = 0 + for i in range(len(a)): + ans += abs(a[i] - c[i]) // 2 + for i in range(len(b)): + ans += abs(b[i] - d[i]) // 2 + return ans // 2 +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-24-915. \345\210\206\345\211\262\346\225\260\347\273\204.md" "b/_posts/Algorithms/leetcode/2022-10-24-915. \345\210\206\345\211\262\346\225\260\347\273\204.md" new file mode 100644 index 0000000000..e6de0d5396 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-24-915. \345\210\206\345\211\262\346\225\260\347\273\204.md" @@ -0,0 +1,66 @@ +--- +layout: post +category: leetcode +title: 915. 分割数组 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/partition-array-into-disjoint-intervals/) + +给定一个数组 `nums` ,将其划分为两个连续子数组 `left` 和 `right`, 使得: + +- `left` 中的每个元素都小于或等于 `right` 中的每个元素。 +- `left` 和 `right` 都是非空的。 +- `left` 的长度要尽可能小。 + +*在完成这样的分组后返回 `left` 的 **长度*** 。 + +用例可以保证存在这样的划分方法。 + + + +**示例 1:** + +``` +输入:nums = [5,0,3,8,6] +输出:3 +解释:left = [5,0,3],right = [8,6] +``` + +**示例 2:** + +``` +输入:nums = [1,1,1,0,6,12] +输出:4 +解释:left = [1,1,1,0],right = [6,12] +``` + + + +**提示:** + +- `2 <= nums.length <= 105` +- `0 <= nums[i] <= 106` +- 可以保证至少有一种方法能够按题目所描述的那样对 `nums` 进行划分。 + +## solution + +下面为一次遍历,使用后悔法。 + +```python +class Solution: + def partitionDisjoint(self, nums: List[int]) -> int: + n = len(nums) + leftpos = 0 + leftmax = nums[0] + currentmax = nums[0] + for i,v in enumerate(nums): + currentmax = max(currentmax, v) + if v < leftmax: + leftpos = i + leftmax = currentmax + return leftpos + 1 + +``` + diff --git "a/_posts/Algorithms/leetcode/2022-10-29-862. \345\222\214\350\207\263\345\260\221\344\270\272 K \347\232\204\346\234\200\347\237\255\345\255\220\346\225\260\347\273\204.md" "b/_posts/Algorithms/leetcode/2022-10-29-862. \345\222\214\350\207\263\345\260\221\344\270\272 K \347\232\204\346\234\200\347\237\255\345\255\220\346\225\260\347\273\204.md" new file mode 100644 index 0000000000..6b83df161c --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-10-29-862. \345\222\214\350\207\263\345\260\221\344\270\272 K \347\232\204\346\234\200\347\237\255\345\255\220\346\225\260\347\273\204.md" @@ -0,0 +1,120 @@ +--- +layout: post +category: leetcode +title: 862. 和至少为 K 的最短子数组 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/) + +给你一个整数数组 `nums` 和一个整数 `k` ,找出 `nums` 中和至少为 `k` 的 **最短非空子数组** ,并返回该子数组的长度。如果不存在这样的 **子数组** ,返回 `-1` 。 + +**子数组** 是数组中 **连续** 的一部分。 + + + + + +**示例 1:** + +``` +输入:nums = [1], k = 1 +输出:1 +``` + +**示例 2:** + +``` +输入:nums = [1,2], k = 4 +输出:-1 +``` + +**示例 3:** + +``` +输入:nums = [2,-1,2], k = 3 +输出:3 +``` + + + +**提示:** + +- `1 <= nums.length <= 105` +- `-105 <= nums[i] <= 105` +- `1 <= k <= 109` + +## solution + +单调队列 + +```python +''' +主要是去除无用数据,维护右端点 +可以单调栈二分,也可以单调队列 +参考: https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/solution/liang-zhang-tu-miao-dong-dan-diao-dui-li-9fvh/ +''' + +class Solution: + def shortestSubarray(self, nums: List[int], k: int) -> int: + ans = float('inf') + n = len(nums) + pre = [0] + for v in nums: + pre.append(pre[-1] + v) + import collections + q = collections.deque() + # 单调队列,j< i, 向右, 如果s[i] - s[j] >= k, j则不会再作为可作为答案的左端点了; 递增队列 对于s[j] >= s[i], 则j也可以舍弃 + for i, v in enumerate(pre): + while q and pre[q[-1]] >= v: + q.pop() + q.append(i) + while q and v - pre[q[0]] >= k: + ans = min(ans, i - q[0]) + q.popleft() + return ans if ans != float('inf') else -1 + + +``` + + + +```python +# 单调栈 + 二分 +class BinarySearch: + # If you wanna binary search big integer, plz set data range, which can be used as same as big integer low and high + # find the first index that value >= val + def bisect_left(data, val, l=None, r=None, key=None): + if l is None or r is None: + l, r = 0, len(data) - 1 + if key is None: + key = lambda x: data[mid] + while l <= r: + mid = (l + r) // 2 + if key(mid) >= val: + r = mid - 1 + else: + l = mid + 1 + return l + +class Solution: + def shortestSubarray(self, nums: List[int], k: int) -> int: + ans = float('inf') + pre = [0] + for v in nums: + pre.append(pre[-1] + v) + # print(pre) + q = [] + # 单调递增栈, 栈上二分 + for i, v in enumerate(pre): + while q and pre[q[-1]] >= v: + q.pop() + q.append(i) + t = BinarySearch.bisect_left(q, True, key=lambda x: v - pre[q[x]] < k) + if t - 1 >= 0: + ans = min(ans, i - q[t - 1]) + return ans if ans != float('inf') else -1 + +``` + diff --git "a/_posts/Algorithms/leetcode/2022-11-04-1674. \344\275\277\346\225\260\347\273\204\344\272\222\350\241\245\347\232\204\346\234\200\345\260\221\346\223\215\344\275\234\346\254\241\346\225\260.md" "b/_posts/Algorithms/leetcode/2022-11-04-1674. \344\275\277\346\225\260\347\273\204\344\272\222\350\241\245\347\232\204\346\234\200\345\260\221\346\223\215\344\275\234\346\254\241\346\225\260.md" new file mode 100644 index 0000000000..2d9cf05345 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-11-04-1674. \344\275\277\346\225\260\347\273\204\344\272\222\350\241\245\347\232\204\346\234\200\345\260\221\346\223\215\344\275\234\346\254\241\346\225\260.md" @@ -0,0 +1,106 @@ +--- +layout: post +category: leetcode +title: 1674. 使数组互补的最少操作次数 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/minimum-moves-to-make-array-complementary/) + +给你一个长度为 **偶数** `n` 的整数数组 `nums` 和一个整数 `limit` 。每一次操作,你可以将 `nums` 中的任何整数替换为 `1` 到 `limit` 之间的另一个整数。 + +如果对于所有下标 `i`(**下标从** `0` **开始**),`nums[i] + nums[n - 1 - i]` 都等于同一个数,则数组 `nums` 是 **互补的** 。例如,数组 `[1,2,3,4]` 是互补的,因为对于所有下标 `i` ,`nums[i] + nums[n - 1 - i] = 5` 。 + +返回使数组 **互补** 的 **最少** 操作次数。 + + + +**示例 1:** + +``` +输入:nums = [1,2,4,3], limit = 4 +输出:1 +解释:经过 1 次操作,你可以将数组 nums 变成 [1,2,2,3](加粗元素是变更的数字): +nums[0] + nums[3] = 1 + 3 = 4. +nums[1] + nums[2] = 2 + 2 = 4. +nums[2] + nums[1] = 2 + 2 = 4. +nums[3] + nums[0] = 3 + 1 = 4. +对于每个 i ,nums[i] + nums[n-1-i] = 4 ,所以 nums 是互补的。 +``` + +**示例 2:** + +``` +输入:nums = [1,2,2,1], limit = 2 +输出:2 +解释:经过 2 次操作,你可以将数组 nums 变成 [2,2,2,2] 。你不能将任何数字变更为 3 ,因为 3 > limit 。 +``` + +**示例 3:** + +``` +输入:nums = [1,2,1,2], limit = 2 +输出:0 +解释:nums 已经是互补的。 +``` + + + +**提示:** + +- `n == nums.length` +- `2 <= n <= 105` +- `1 <= nums[i] <= limit <= 105` +- `n` 是偶数。 + +## solution + +假设 `res[x]` 表示的是,`nums[i] + nums[n - 1 - i]` 为 `x` 的时候,需要多少次操作。 + +我们只需要计算出所有的 `x` 对应的 `res[x]`, 取最小值就好了。 + +根据题意,`nums[i] + nums[n - 1 - i]` 最小是 `2`,即将两个数都修改为 `1`;最大是 `2 * limit`,即将两个数都修改成 `limit`。 + +所以,`res[x]` 中 `x` 的取值范围是 `[2, 2 * limit]`。我们用一个 `res[2 * limit + 1]` 的数组就好。 + +```python +class Diff: + def __init__(self, n): + self.n = n + self.diff = [0] * (n + 1) + + # 给[l,r] + val + def add(self, l, r, val): + self.diff[l] += val + self.diff[r + 1] -= val + + # 差分数组还原成原数组 + def restore(self): + ans = [0] * self.n + ans[0] = self.diff[0] + for i in range(1, self.n): + ans[i] = ans[i - 1] + self.diff[i] + return ans + +class Solution: + def minMoves(self, nums: List[int], limit: int) -> int: + diff = Diff(2 * limit + 1) + n = len(nums) + for i in range((len(nums) + 1) // 2): + a, b = nums[i], nums[n - 1 - i] + if a > b: + a, b = b, a + ''' + 0: a+b + 2: [2, a+1) or (b+limit, 2*limit] + 1: + ''' + diff.add(2, a, 2) + diff.add(b + limit + 1, 2 * limit, 2) + diff.add(a + 1, b + limit, 1) + diff.add(a + b, a + b, -1) + # print(diff.restore()) + return min(diff.restore()[2:]) +``` + diff --git "a/_posts/Algorithms/leetcode/2022-11-06-6232. \346\234\200\345\260\217\347\247\273\345\212\250\346\200\273\350\267\235\347\246\273.md" "b/_posts/Algorithms/leetcode/2022-11-06-6232. \346\234\200\345\260\217\347\247\273\345\212\250\346\200\273\350\267\235\347\246\273.md" new file mode 100644 index 0000000000..ddaa802f80 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-11-06-6232. \346\234\200\345\260\217\347\247\273\345\212\250\346\200\273\350\267\235\347\246\273.md" @@ -0,0 +1,102 @@ +--- +layout: post +category: leetcode +title: 6232. 最小移动总距离 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/minimum-total-distance-traveled/) + +X 轴上有一些机器人和工厂。给你一个整数数组 `robot` ,其中 `robot[i]` 是第 `i` 个机器人的位置。再给你一个二维整数数组 `factory` ,其中 `factory[j] = [positionj, limitj]` ,表示第 `j` 个工厂的位置在 `positionj` ,且第 `j` 个工厂最多可以修理 `limitj` 个机器人。 + +每个机器人所在的位置 **互不相同** 。每个工厂所在的位置也 **互不相同** 。注意一个机器人可能一开始跟一个工厂在 **相同的位置** 。 + +所有机器人一开始都是坏的,他们会沿着设定的方向一直移动。设定的方向要么是 X 轴的正方向,要么是 X 轴的负方向。当一个机器人经过一个没达到上限的工厂时,这个工厂会维修这个机器人,且机器人停止移动。 + +**任何时刻**,你都可以设置 **部分** 机器人的移动方向。你的目标是最小化所有机器人总的移动距离。 + +请你返回所有机器人移动的最小总距离。测试数据保证所有机器人都可以被维修。 + +**注意:** + +- 所有机器人移动速度相同。 +- 如果两个机器人移动方向相同,它们永远不会碰撞。 +- 如果两个机器人迎面相遇,它们也不会碰撞,它们彼此之间会擦肩而过。 +- 如果一个机器人经过了一个已经达到上限的工厂,机器人会当作工厂不存在,继续移动。 +- 机器人从位置 `x` 到位置 `y` 的移动距离为 `|y - x|` 。 + + + +**示例 1:** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211061747130.png) + +``` +输入:robot = [0,4,6], factory = [[2,2],[6,2]] +输出:4 +解释:如上图所示: +- 第一个机器人从位置 0 沿着正方向移动,在第一个工厂处维修。 +- 第二个机器人从位置 4 沿着负方向移动,在第一个工厂处维修。 +- 第三个机器人在位置 6 被第二个工厂维修,它不需要移动。 +第一个工厂的维修上限是 2 ,它维修了 2 个机器人。 +第二个工厂的维修上限是 2 ,它维修了 1 个机器人。 +总移动距离是 |2 - 0| + |2 - 4| + |6 - 6| = 4 。没有办法得到比 4 更少的总移动距离。 +``` + +**示例 2:** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211061747289.png) + +``` +输入:robot = [1,-1], factory = [[-2,1],[2,1]] +输出:2 +解释:如上图所示: +- 第一个机器人从位置 1 沿着正方向移动,在第二个工厂处维修。 +- 第二个机器人在位置 -1 沿着负方向移动,在第一个工厂处维修。 +第一个工厂的维修上限是 1 ,它维修了 1 个机器人。 +第二个工厂的维修上限是 1 ,它维修了 1 个机器人。 +总移动距离是 |2 - 1| + |(-2) - (-1)| = 2 。没有办法得到比 2 更少的总移动距离。 +``` + + + +**提示:** + +- `1 <= robot.length, factory.length <= 100` +- `factory[j].length == 2` +- `-109 <= robot[i], positionj <= 109` +- `0 <= limitj <= robot.length` +- 测试数据保证所有机器人都可以被维修。 + +## solution + +动态规划 o(nnm) 一定要往局部思考,想到动态规划才行。 + +```python +class Solution: + def minimumTotalDistance(self, robot: List[int], factory: List[List[int]]) -> int: + robot = sorted(robot) + factory = sorted(factory) + n = len(robot) + + def f(i, j): + if j == 0 and i == 0: + return 0 + if j == 0 or i == 0: + return float('inf') + res = float('inf') + cost = 0 + for k in range(0, factory[j - 1][1] + 1): + if i - k < 0: break + if k > 0: + cost += abs(factory[j - 1][0] - robot[i - k]) + # print(i, j, k, cost) + res = min(res, f(i - k, j - 1) + cost) + # print(i, j, res) + return res + + ans = f(n, len(factory)) + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2022-12-04-6256. \345\260\206\350\212\202\347\202\271\345\210\206\346\210\220\345\260\275\345\217\257\350\203\275\345\244\232\347\232\204\347\273\204.md" "b/_posts/Algorithms/leetcode/2022-12-04-6256. \345\260\206\350\212\202\347\202\271\345\210\206\346\210\220\345\260\275\345\217\257\350\203\275\345\244\232\347\232\204\347\273\204.md" new file mode 100644 index 0000000000..a381b04ca4 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-12-04-6256. \345\260\206\350\212\202\347\202\271\345\210\206\346\210\220\345\260\275\345\217\257\350\203\275\345\244\232\347\232\204\347\273\204.md" @@ -0,0 +1,160 @@ +--- +layout: post +category: leetcode +title: 6256. 将节点分成尽可能多的组 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/divide-nodes-into-the-maximum-number-of-groups/) + +给你一个正整数 `n` ,表示一个 **无向** 图中的节点数目,节点编号从 `1` 到 `n` 。 + +同时给你一个二维整数数组 `edges` ,其中 `edges[i] = [ai, bi]` 表示节点 `ai` 和 `bi` 之间有一条 **双向** 边。注意给定的图可能是不连通的。 + +请你将图划分为 `m` 个组(编号从 **1** 开始),满足以下要求: + +- 图中每个节点都只属于一个组。 +- 图中每条边连接的两个点 `[ai, bi]` ,如果 `ai` 属于编号为 `x` 的组,`bi` 属于编号为 `y` 的组,那么 `|y - x| = 1` 。 + +请你返回最多可以将节点分为多少个组(也就是最大的 `m` )。如果没办法在给定条件下分组,请你返回 `-1` 。 + + + +**示例 1:** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202212041542634.png) + +``` +输入:n = 6, edges = [[1,2],[1,4],[1,5],[2,6],[2,3],[4,6]] +输出:4 +解释:如上图所示, +- 节点 5 在第一个组。 +- 节点 1 在第二个组。 +- 节点 2 和节点 4 在第三个组。 +- 节点 3 和节点 6 在第四个组。 +所有边都满足题目要求。 +如果我们创建第五个组,将第三个组或者第四个组中任何一个节点放到第五个组,至少有一条边连接的两个节点所属的组编号不符合题目要求。 +``` + +**示例 2:** + +``` +输入:n = 3, edges = [[1,2],[2,3],[3,1]] +输出:-1 +解释:如果我们将节点 1 放入第一个组,节点 2 放入第二个组,节点 3 放入第三个组,前两条边满足题目要求,但第三条边不满足题目要求。 +没有任何符合题目要求的分组方式。 +``` + + + +**提示:** + +- `1 <= n <= 500` +- `1 <= edges.length <= 104` +- `edges[i].length == 2` +- `1 <= ai, bi <= n` +- `ai != bi` +- 两个点之间至多只有一条边。 + +## solution + +``` +二分图才可以分组 / 也可以通过bfs后,比较和start点距离判断,a<->b, 则dis[a]!=dis[b]才可以分组 +``` + +```python + +class Graph: + def bfs(graph, start): + ''' + :param graph: collection.defaultdict(list) + :param start: start point + :return: + ''' + q = collections.deque() + q.append(start) + visit = set() + visit.add(start) + level = 0 + while len(q): + level += 1 + for _ in range(len(q)): + u = q.popleft() + for v in graph[u]: + if v not in visit: + visit.add(v) + q.append(v) + return visit, level + ''' + 划分连同分量, 返回每个联通分量的点list,可以多个联通分量 + ''' + def groups(self, points, graph) -> List[List[int]]: + groups = [] + total_visit = set() + for i in points: + visit = set() + def dfs(u): + nonlocal visit + visit.add(u) + for v in graph[u]: + if v not in visit: + dfs(v) + + if i not in total_visit: + dfs(i) + if visit: + for l in visit: + total_visit.add(l) + groups.append(list(visit)) + return groups + + # 判断是否是二分图,input可以是多个子连通图。graph: 链接表 + def isBipartite(self, graph) -> bool: + ans = True + color = collections.defaultdict(int) + n = len(graph) + + def dfs(i): + nonlocal ans + if not ans: + return + if color[i] == 0: + color[i] = 1 + cur = color[i] + for neighbor in graph[i]: + if color[neighbor] == cur: + ans = False + break + if color[neighbor] == 0: + color[neighbor] = 2 if cur == 1 else 1 + dfs(neighbor) + + for i in range(n): + if color[i] == 0: + dfs(i) + # print(color) + return ans + +class Solution: + def magnificentSets(self, n: int, edges: List[List[int]]) -> int: + graph = collections.defaultdict(list) + for u, v in edges: + graph[u].append(v) + graph[v].append(u) + # 二分图才可以分组 + if not Graph().isBipartite(graph): + return -1 + # 划分联通分量 + groups = Graph().groups(range(1, n + 1), graph) + ans = 0 + for group in groups: + t = 0 + # 对联通分量的每个节点用bfs求最大长度 + for i in group: + t = max(t, Graph.bfs(graph, i)[1]) + ans += t + return ans + +``` + diff --git "a/_posts/Algorithms/leetcode/2022-12-25-6270. \346\257\217\347\247\215\345\255\227\347\254\246\350\207\263\345\260\221\345\217\226 K \344\270\252.md" "b/_posts/Algorithms/leetcode/2022-12-25-6270. \346\257\217\347\247\215\345\255\227\347\254\246\350\207\263\345\260\221\345\217\226 K \344\270\252.md" new file mode 100644 index 0000000000..adcaed6940 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-12-25-6270. \346\257\217\347\247\215\345\255\227\347\254\246\350\207\263\345\260\221\345\217\226 K \344\270\252.md" @@ -0,0 +1,76 @@ +--- +layout: post +category: leetcode +title: 6270. 每种字符至少取 K 个 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/take-k-of-each-character-from-left-and-right/) + +给你一个由字符 `'a'`、`'b'`、`'c'` 组成的字符串 `s` 和一个非负整数 `k` 。每分钟,你可以选择取走 `s` **最左侧** 还是 **最右侧** 的那个字符。 + +你必须取走每种字符 **至少** `k` 个,返回需要的 **最少** 分钟数;如果无法取到,则返回 `-1` 。 + + + +**示例 1:** + +``` +输入:s = "aabaaaacaabc", k = 2 +输出:8 +解释: +从 s 的左侧取三个字符,现在共取到两个字符 'a' 、一个字符 'b' 。 +从 s 的右侧取五个字符,现在共取到四个字符 'a' 、两个字符 'b' 和两个字符 'c' 。 +共需要 3 + 5 = 8 分钟。 +可以证明需要的最少分钟数是 8 。 +``` + +**示例 2:** + +``` +输入:s = "a", k = 1 +输出:-1 +解释:无法取到一个字符 'b' 或者 'c',所以返回 -1 。 +``` + + + +**提示:** + +- `1 <= s.length <= 105` +- `s` 仅由字母 `'a'`、`'b'`、`'c'` 组成 +- `0 <= k <= s.length` + +## solution + +双指针。 + +```python +class Solution: + def takeCharacters(self, s: str, k: int) -> int: + cnt = collections.Counter() + + def check(cnt): + for c in "abc": + if cnt[c] < k: + return False + return True + + n = len(s) + r = n + while not check(cnt): + r -= 1 + if r < 0: + return -1 + cnt[s[r]] += 1 + ans = n - r + for l in range(n): + cnt[s[l]] += 1 + while r < n and cnt[s[r]] > k: + cnt[s[r]] -= 1 + r += 1 + ans = min(ans, l + 1 + n - r) + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2022-12-25-6272. \345\245\275\345\210\206\345\214\272\347\232\204\346\225\260\347\233\256.md" "b/_posts/Algorithms/leetcode/2022-12-25-6272. \345\245\275\345\210\206\345\214\272\347\232\204\346\225\260\347\233\256.md" new file mode 100644 index 0000000000..787337d55e --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-12-25-6272. \345\245\275\345\210\206\345\214\272\347\232\204\346\225\260\347\233\256.md" @@ -0,0 +1,79 @@ +--- +layout: post +category: leetcode +title: 6272. 好分区的数目 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/number-of-great-partitions/) + +给你一个正整数数组 `nums` 和一个整数 `k` 。 + +**分区** 的定义是:将数组划分成两个有序的 **组** ,并满足每个元素 **恰好** 存在于 **某一个** 组中。如果分区中每个组的元素和都大于等于 `k` ,则认为分区是一个好分区。 + +返回 **不同** 的好分区的数目。由于答案可能很大,请返回对 `109 + 7` **取余** 后的结果。 + +如果在两个分区中,存在某个元素 `nums[i]` 被分在不同的组中,则认为这两个分区不同。 + + + +**示例 1:** + +``` +输入:nums = [1,2,3,4], k = 4 +输出:6 +解释:好分区的情况是 ([1,2,3], [4]), ([1,3], [2,4]), ([1,4], [2,3]), ([2,3], [1,4]), ([2,4], [1,3]) 和 ([4], [1,2,3]) 。 +``` + +**示例 2:** + +``` +输入:nums = [3,3,3], k = 4 +输出:0 +解释:数组中不存在好分区。 +``` + +**示例 3:** + +``` +输入:nums = [6,6], k = 2 +输出:2 +解释:可以将 nums[0] 放入第一个分区或第二个分区中。 +好分区的情况是 ([6], [6]) 和 ([6], [6]) 。 +``` + + + +**提示:** + +- `1 <= nums.length, k <= 1000` +- `1 <= nums[i] <= 109` + +## solution + +[参考](https://leetcode.cn/problems/number-of-great-partitions/solution/ni-xiang-si-wei-01-bei-bao-fang-an-shu-p-v47x/) 考虑计算**坏分区**的数目,即第一个组或第二个组的元素和小于 k*k* 的方案数。根据对称性,我们只需要计算第一个组的元素和小于 k*k* 的方案数,然后乘 22 即可。 + +因此原问题转换成从 \textit{nums}*nums* 中选择若干元素,使得元素和小于 k*k* 的方案数,这可以用 **01 背包**求解。 + +```python +MOD = int(1e9 + 7) +INF = int(1e20) +class Math1: + pass +class Solution: + def countPartitions(self, nums: List[int], k: int) -> int: + # 统计bad数量,总数减去即可。 + if sum(nums) < 2*k:return 0 + n = len(nums) + dp = [0 for _ in range(k)] + dp[0] = 1 + for i, v in enumerate(nums): + for t in range(k-1, 0, -1): + if t >= v: + dp[t] += dp[t - v] % MOD + bad = sum(dp) + return (pow(2, n, MOD) - bad*2 + MOD) % MOD + +``` + diff --git "a/_posts/Algorithms/leetcode/2022-12-25-6276. \347\273\237\350\256\241\345\220\214\344\275\215\345\274\202\346\236\204\345\255\227\347\254\246\344\270\262\346\225\260\347\233\256.md" "b/_posts/Algorithms/leetcode/2022-12-25-6276. \347\273\237\350\256\241\345\220\214\344\275\215\345\274\202\346\236\204\345\255\227\347\254\246\344\270\262\346\225\260\347\233\256.md" new file mode 100644 index 0000000000..6754ad5df7 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-12-25-6276. \347\273\237\350\256\241\345\220\214\344\275\215\345\274\202\346\236\204\345\255\227\347\254\246\344\270\262\346\225\260\347\233\256.md" @@ -0,0 +1,125 @@ +--- +layout: post +category: leetcode +title: 6276. 统计同位异构字符串数目 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/count-anagrams/) + +给你一个字符串 `s` ,它包含一个或者多个单词。单词之间用单个空格 `' '` 隔开。 + +如果字符串 `t` 中第 `i` 个单词是 `s` 中第 `i` 个单词的一个 **排列** ,那么我们称字符串 `t` 是字符串 `s` 的同位异构字符串。 + +- 比方说,`"acb dfe"` 是 `"abc def"` 的同位异构字符串,但是 `"def cab"` 和 `"adc bef"` 不是。 + +请你返回 `s` 的同位异构字符串的数目,由于答案可能很大,请你将它对 `109 + 7` **取余** 后返回。 + + + +**示例 1:** + +``` +输入:s = "too hot" +输出:18 +解释:输入字符串的一些同位异构字符串为 "too hot" ,"oot hot" ,"oto toh" ,"too toh" 以及 "too oht" 。 +``` + +**示例 2:** + +``` +输入:s = "aa" +输出:1 +解释:输入字符串只有一个同位异构字符串。 +``` + + + +**提示:** + +- `1 <= s.length <= 105` +- `s` 只包含小写英文字母和空格 `' '` 。 +- 相邻单词之间由单个空格隔开。 + +## solution + +方法1: 大数阶乘除法,要用费马小定理。 + +方法2: 用comb换种思路,原来是阶乘相除,可以通过comb相乘,此时无除法。 + +```python +MOD = 10 ** 9 + 7 +class BigIntDivide: + def mod_inverse(i): + # 调用取模的乘幂运算, pow复杂度是log(exp)即log(MOD) + return pow(i, MOD - 2, MOD) + + def divide_mod(a, b): + ''' + 计算(a/b) % MOD, 除法变乘法,前提是b和MOD互为质数 + ''' + # 如果有多个b,比如a/b1/b2, 那就可以递归。a*mod_inverse(b1) % mod * mod_inverse(b2) % mod这样 + return a * BigIntDivide.mod_inverse(b) % MOD + + def divide_mods(a, b=[]): + ''' + 计算a /(b1*b2*b3) % MOD等形式,前提是b和MOD互为质数 + ''' + r = a % MOD + for i, v in enumerate(b): + r *= BigIntDivide.mod_inverse(v) + r %= MOD + return r + +class Math1: + + import functools + @functools.lru_cache(None) + def factorial_mod_cache(n): + if n == 0 or n == 1: + return 1 + return Math1.factorial_mod_cache(n - 1) * n % MOD +class Solution: + def countAnagrams(self, s: str) -> int: + d = s.split(' ') + + factorial_mod = Math1.factorial_mod_cache + + def calcu(x): + import collections + counter = collections.Counter(x) + n = len(x) + return BigIntDivide.divide_mods(factorial_mod(n), [factorial_mod(v) for v in counter.values()]) + + # print(calcu("too")) + + ans = 1 + for v in d: + ans *= calcu(v) + ans %= MOD + return ans % MOD +``` + + + +方法2 [参考](https://leetcode.cn/problems/count-anagrams/solution/python3pailiezuh-by-musing-clarkeeae-o2zg/) + + + +```python +MOD = 10 ** 9 + 7 + + +class Solution: + def countAnagrams(self, s: str) -> int: + ans = 1 + for word in s.split(): + n = len(word) + for v in Counter(word).values(): + ans *= comb(n, v) + ans %= MOD + n -= v + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2022-12-25-6295. \346\234\200\345\260\217\345\214\226\344\270\244\344\270\252\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\244\247\345\200\274.md" "b/_posts/Algorithms/leetcode/2022-12-25-6295. \346\234\200\345\260\217\345\214\226\344\270\244\344\270\252\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\244\247\345\200\274.md" new file mode 100644 index 0000000000..2147956263 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2022-12-25-6295. \346\234\200\345\260\217\345\214\226\344\270\244\344\270\252\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\244\247\345\200\274.md" @@ -0,0 +1,87 @@ +--- +layout: post +category: leetcode +title: 6295. 最小化两个数组中的最大值 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/minimize-the-maximum-of-two-arrays/) + +给你两个数组 `arr1` 和 `arr2` ,它们一开始都是空的。你需要往它们中添加正整数,使它们满足以下条件: + +- `arr1` 包含 `uniqueCnt1` 个 **互不相同** 的正整数,每个整数都 **不能** 被 `divisor1` **整除** 。 +- `arr2` 包含 `uniqueCnt2` 个 **互不相同** 的正整数,每个整数都 **不能** 被 `divisor2` **整除** 。 +- `arr1` 和 `arr2` 中的元素 **互不相同** 。 + +给你 `divisor1` ,`divisor2` ,`uniqueCnt1` 和 `uniqueCnt2` ,请你返回两个数组中 **最大元素** 的 **最小值** 。 + + + +**示例 1:** + +``` +输入:divisor1 = 2, divisor2 = 7, uniqueCnt1 = 1, uniqueCnt2 = 3 +输出:4 +解释: +我们可以把前 4 个自然数划分到 arr1 和 arr2 中。 +arr1 = [1] 和 arr2 = [2,3,4] 。 +可以看出两个数组都满足条件。 +最大值是 4 ,所以返回 4 。 +``` + +**示例 2:** + +``` +输入:divisor1 = 3, divisor2 = 5, uniqueCnt1 = 2, uniqueCnt2 = 1 +输出:3 +解释: +arr1 = [1,2] 和 arr2 = [3] 满足所有条件。 +最大值是 3 ,所以返回 3 。 +``` + +**示例 3:** + +``` +输入:divisor1 = 2, divisor2 = 4, uniqueCnt1 = 8, uniqueCnt2 = 2 +输出:15 +解释: +最终数组为 arr1 = [1,3,5,7,9,11,13,15] 和 arr2 = [2,6] 。 +上述方案是满足所有条件的最优解。 +``` + + + +**提示:** + +- `2 <= divisor1, divisor2 <= 105` +- `1 <= uniqueCnt1, uniqueCnt2 < 109` +- `2 <= uniqueCnt1 + uniqueCnt2 <= 109` + +## solution + +二分最大元素的可行值,得到的下界即为最大值的最小值。 + +判断过程中分为三类:保证在范围内有充足的数不是第一个数的倍数;不是第二个数的倍数;不为公倍数的数总数不少于总共要取的数。根据这三个条件即得到结果。 + +```python +class Math1: + def lcm(a, b): + import math + gcd = math.gcd(a, b) + return int(a * b / gcd) + +class Solution: + def minimizeSet(self, divisor1: int, divisor2: int, uniqueCnt1: int, uniqueCnt2: int) -> int: + lcm = Math1.lcm(divisor1, divisor2) + + def can(x): + a = x - x // divisor1 # arr1能放的数量 + b = x - x // divisor2 # arr2能放的数量 + c = x // lcm # arr1和2都不能放的 + return (a >= uniqueCnt1) and (b >= uniqueCnt2) and (x - c) >= uniqueCnt1+uniqueCnt2 + import bisect + r = bisect.bisect_left(range(2*uniqueCnt1 +2*uniqueCnt2), True, key=can) + return r +``` + diff --git "a/_posts/Algorithms/leetcode/2023-01-14-1819. \345\272\217\345\210\227\344\270\255\344\270\215\345\220\214\346\234\200\345\244\247\345\205\254\347\272\246\346\225\260\347\232\204\346\225\260\347\233\256.md" "b/_posts/Algorithms/leetcode/2023-01-14-1819. \345\272\217\345\210\227\344\270\255\344\270\215\345\220\214\346\234\200\345\244\247\345\205\254\347\272\246\346\225\260\347\232\204\346\225\260\347\233\256.md" new file mode 100644 index 0000000000..7933268bd0 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-01-14-1819. \345\272\217\345\210\227\344\270\255\344\270\215\345\220\214\346\234\200\345\244\247\345\205\254\347\272\246\346\225\260\347\232\204\346\225\260\347\233\256.md" @@ -0,0 +1,94 @@ +--- +layout: post +category: leetcode +title: 1819. 序列中不同最大公约数的数目 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/number-of-different-subsequences-gcds/) + +给你一个由正整数组成的数组 `nums` 。 + +数字序列的 **最大公约数** 定义为序列中所有整数的共有约数中的最大整数。 + +- 例如,序列 `[4,6,16]` 的最大公约数是 `2` 。 + +数组的一个 **子序列** 本质是一个序列,可以通过删除数组中的某些元素(或者不删除)得到。 + +- 例如,`[2,5,10]` 是 `[1,2,1,**2**,4,1,**5**,**10**]` 的一个子序列。 + +计算并返回 `nums` 的所有 **非空** 子序列中 **不同** 最大公约数的 **数目** 。 + + + +**示例 1:** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202301141325146.png) + +``` +输入:nums = [6,10,3] +输出:5 +解释:上图显示了所有的非空子序列与各自的最大公约数。 +不同的最大公约数为 6 、10 、3 、2 和 1 。 +``` + +**示例 2:** + +``` +输入:nums = [5,15,40,5,6] +输出:7 +``` + + + +**提示:** + +- `1 <= nums.length <= 105` +- `1 <= nums[i] <= 2 * 105` + +## solution + +![image-20230114132644447](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202301141326476.png) + + + +O(nlogn) 其中遍历每个数的倍数总时间复杂度为o(nlogn) 参考调和级数。 Or this [link](https://leetcode.cn/problems/number-of-different-subsequences-gcds/solution/ji-bai-100mei-ju-gcdxun-huan-you-hua-pyt-get7/) + +```python +MOD = int(1e9 + 7) +INF = int(1e20) + +import sortedcontainers +import bisect +import heapq +class Math1: + def gcd_list(self, nums): + import math + cur = nums[0] + for i in range(1, len(nums)): + cur = math.gcd(cur, nums[i]) + return cur + +class Solution: + def countDifferentSubsequenceGCDs(self, nums: List[int]) -> int: + n, mx = len(nums), max(nums) + ans = 0 + has = [False for _ in range(mx+1)] + for v in nums: + has[v] += 1 + gcd_list = Math1().gcd_list + for i in range(1, mx + 1): + x = [] + for j in range(i, mx + 1, i): + if has[j]: + x.append(j) + if x: + # print(i, x) + p = gcd_list(x) + if p == i: + ans += 1 + return ans + +``` + diff --git "a/_posts/Algorithms/leetcode/2023-01-28-2541. \344\275\277\346\225\260\347\273\204\344\270\255\346\211\200\346\234\211\345\205\203\347\264\240\347\233\270\347\255\211\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260 II.md" "b/_posts/Algorithms/leetcode/2023-01-28-2541. \344\275\277\346\225\260\347\273\204\344\270\255\346\211\200\346\234\211\345\205\203\347\264\240\347\233\270\347\255\211\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260 II.md" new file mode 100644 index 0000000000..c440f8c3ea --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-01-28-2541. \344\275\277\346\225\260\347\273\204\344\270\255\346\211\200\346\234\211\345\205\203\347\264\240\347\233\270\347\255\211\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260 II.md" @@ -0,0 +1,76 @@ +--- +layout: post +category: leetcode +title: 2541. 使数组中所有元素相等的最小操作数 II +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/minimum-operations-to-make-array-equal-ii/) + +给你两个整数数组 `nums1` 和 `nums2` ,两个数组长度都是 `n` ,再给你一个整数 `k` 。你可以对数组 `nums1` 进行以下操作: + +- 选择两个下标 `i` 和 `j` ,将 `nums1[i]` 增加 `k` ,将 `nums1[j]` 减少 `k` 。换言之,`nums1[i] = nums1[i] + k` 且 `nums1[j] = nums1[j] - k` 。 + +如果对于所有满足 `0 <= i < n` 都有 `num1[i] == nums2[i]` ,那么我们称 `nums1` **等于** `nums2` 。 + +请你返回使 `nums1` 等于 `nums2` 的 **最少** 操作数。如果没办法让它们相等,请你返回 `-1` 。 + + + +**示例 1:** + +``` +输入:nums1 = [4,3,1,4], nums2 = [1,3,7,1], k = 3 +输出:2 +解释:我们可以通过 2 个操作将 nums1 变成 nums2 。 +第 1 个操作:i = 2 ,j = 0 。操作后得到 nums1 = [1,3,4,4] 。 +第 2 个操作:i = 2 ,j = 3 。操作后得到 nums1 = [1,3,7,1] 。 +无法用更少操作使两个数组相等。 +``` + +**示例 2:** + +``` +输入:nums1 = [3,8,5,2], nums2 = [2,4,1,6], k = 1 +输出:-1 +解释:无法使两个数组相等。 +``` + + + +**提示:** + +- `n == nums1.length == nums2.length` +- `2 <= n <= 105` +- `0 <= nums1[i], nums2[j] <= 109` +- `0 <= k <= 105` + +## solution + +任选两个元素,一个+k,一个-k,问最少操作次数,使这个数组和另一个数组相同。累计操作次数即可,注意k为0的情况 + +```python + +class Solution: + def minOperations(self, nums1: List[int], nums2: List[int], k: int) -> int: + op1, op2 = 0, 0 + d = [] + for a, b in zip(nums1, nums2): + d.append(a - b) + if sum(d) != 0: return -1 + for v in d: + if k == 0: + # k==0时特判,不能相除法了。 + if v != 0: return -1 + continue + if abs(v) % k != 0: return -1 + if v > 0: + op1 += v // k + else: + op2 += (-v) // k + if op1 != op2: + return -1 + return op1 +``` + diff --git "a/_posts/Algorithms/leetcode/2023-01-28-2542. \346\234\200\345\244\247\345\255\220\345\272\217\345\210\227\347\232\204\345\210\206\346\225\260.md" "b/_posts/Algorithms/leetcode/2023-01-28-2542. \346\234\200\345\244\247\345\255\220\345\272\217\345\210\227\347\232\204\345\210\206\346\225\260.md" new file mode 100644 index 0000000000..3697889093 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-01-28-2542. \346\234\200\345\244\247\345\255\220\345\272\217\345\210\227\347\232\204\345\210\206\346\225\260.md" @@ -0,0 +1,90 @@ +--- +layout: post +category: leetcode +title: 2542. 最大子序列的分数 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/maximum-subsequence-score/) + +给你两个下标从 **0** 开始的整数数组 `nums1` 和 `nums2` ,两者长度都是 `n` ,再给你一个正整数 `k` 。你必须从 `nums1` 中选一个长度为 `k` 的 **子序列** 对应的下标。 + +对于选择的下标 `i0` ,`i1` ,..., `ik - 1` ,你的 **分数** 定义如下: + +- `nums1` 中下标对应元素求和,乘以 `nums2` 中下标对应元素的 **最小值** 。 +- 用公示表示: `(nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] , nums2[i1], ... ,nums2[ik - 1])` 。 + +请你返回 **最大** 可能的分数。 + +一个数组的 **子序列** 下标是集合 `{0, 1, ..., n-1}` 中删除若干元素得到的剩余集合,也可以不删除任何元素。 + + + +**示例 1:** + +``` +输入:nums1 = [1,3,3,2], nums2 = [2,1,3,4], k = 3 +输出:12 +解释: +四个可能的子序列分数为: +- 选择下标 0 ,1 和 2 ,得到分数 (1+3+3) * min(2,1,3) = 7 。 +- 选择下标 0 ,1 和 3 ,得到分数 (1+3+2) * min(2,1,4) = 6 。 +- 选择下标 0 ,2 和 3 ,得到分数 (1+3+2) * min(2,3,4) = 12 。 +- 选择下标 1 ,2 和 3 ,得到分数 (3+3+2) * min(1,3,4) = 8 。 +所以最大分数为 12 。 +``` + +**示例 2:** + +``` +输入:nums1 = [4,2,3,1,1], nums2 = [7,5,10,9,6], k = 1 +输出:30 +解释: +选择下标 2 最优:nums1[2] * nums2[2] = 3 * 10 = 30 是最大可能分数。 +``` + + + +**提示:** + +- `n == nums1.length == nums2.length` +- `1 <= n <= 105` +- `0 <= nums1[i], nums2[j] <= 105` +- `1 <= k <= n` + +## solution + +排序后,按从小到大枚举 + +```python +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + a1, a2 = nums1, nums2 + n = len(a1) + d = zip(a2, a1) + # 排序 + d = sorted(d, key=lambda x: (x[0], x[1])) + # 统计每个a2元素大于a2元素对应的最大a1和 + right_max_sumv = collections.defaultdict(int) + cur = 0 + import heapq + h = [] + # print(d) + for i in range(len(d) - 1, -1, -1): + b, c = d[i] + heapq.heappush(h, c) + cur += c + if len(h) > k: + x = heapq.heappop(h) + cur -= x + # print(h, cur) + if len(h) == k: + right_max_sumv[b] = cur + ans = 0 + # print(right_max_sumv) + for k, v in right_max_sumv.items(): + ans = max(ans, v * k) + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2023-01-28-2546. \346\211\247\350\241\214\351\200\220\344\275\215\350\277\220\347\256\227\344\275\277\345\255\227\347\254\246\344\270\262\347\233\270\347\255\211.md" "b/_posts/Algorithms/leetcode/2023-01-28-2546. \346\211\247\350\241\214\351\200\220\344\275\215\350\277\220\347\256\227\344\275\277\345\255\227\347\254\246\344\270\262\347\233\270\347\255\211.md" new file mode 100644 index 0000000000..e067a7d306 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-01-28-2546. \346\211\247\350\241\214\351\200\220\344\275\215\350\277\220\347\256\227\344\275\277\345\255\227\347\254\246\344\270\262\347\233\270\347\255\211.md" @@ -0,0 +1,58 @@ +--- +layout: post +category: leetcode +title: 2546. 执行逐位运算使字符串相等 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/apply-bitwise-operations-to-make-strings-equal/) + +给你两个下标从 **0** 开始的 **二元** 字符串 `s` 和 `target` ,两个字符串的长度均为 `n` 。你可以对 `s` 执行下述操作 **任意** 次: + +- 选择两个 **不同** 的下标 `i` 和 `j` ,其中 `0 <= i, j < n` 。 +- 同时,将 `s[i]` 替换为 (`s[i]` **OR** `s[j]`) ,`s[j]` 替换为 (`s[i]` **XOR** `s[j]`) 。 + +例如,如果 `s = "0110"` ,你可以选择 `i = 0` 和 `j = 2`,然后同时将 `s[0]` 替换为 (`s[0]` **OR** `s[2]` = `0` **OR** `1` = `1`),并将 `s[2]` 替换为 (`s[0]` **XOR** `s[2]` = `0` **XOR** `1` = `1`),最终得到 `s = "1110"` 。 + +如果可以使 `s` 等于 `target` ,返回 `true` ,否则,返回 `false` 。 + + + +**示例 1:** + +``` +输入:s = "1010", target = "0110" +输出:true +解释:可以执行下述操作: +- 选择 i = 2 和 j = 0 ,得到 s = "0010". +- 选择 i = 2 和 j = 1 ,得到 s = "0110". +可以使 s 等于 target ,返回 true 。 +``` + +**示例 2:** + +``` +输入:s = "11", target = "00" +输出:false +解释:执行任意次操作都无法使 s 等于 target 。 +``` + + + +**提示:** + +- `n == s.length == target.length` +- `2 <= n <= 105` +- `s` 和 `target` 仅由数字 `0` 和 `1` 组成 + +## solution + +找规律。 [参考](https://leetcode.cn/problems/apply-bitwise-operations-to-make-strings-equal/solution/nao-jin-ji-zhuan-wan-yi-xing-dai-ma-by-e-0fce/) + +```python +class Solution: + def makeStringsEqual(self, s: str, target: str) -> bool: + return ('1' in s) == ('1' in target) +``` + diff --git "a/_posts/Algorithms/leetcode/2023-01-28-2547. \346\213\206\345\210\206\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\344\273\243\344\273\267.md" "b/_posts/Algorithms/leetcode/2023-01-28-2547. \346\213\206\345\210\206\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\344\273\243\344\273\267.md" new file mode 100644 index 0000000000..c345b2e99a --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-01-28-2547. \346\213\206\345\210\206\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\344\273\243\344\273\267.md" @@ -0,0 +1,102 @@ +--- +layout: post +category: leetcode +title: 2547. 拆分数组的最小代价 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/minimum-cost-to-split-an-array/) + +给你一个整数数组 `nums` 和一个整数 `k` 。 + +将数组拆分成一些非空子数组。拆分的 **代价** 是每个子数组中的 **重要性** 之和。 + +令 `trimmed(subarray)` 作为子数组的一个特征,其中所有仅出现一次的数字将会被移除。 + +- 例如,`trimmed([3,1,2,4,3,4]) = [3,4,3,4]` 。 + +子数组的 **重要性** 定义为 `k + trimmed(subarray).length` 。 + +- 例如,如果一个子数组是 `[1,2,3,3,3,4,4]` ,`trimmed([1,2,3,3,3,4,4]) = [3,3,3,4,4]` 。这个子数组的重要性就是 `k + 5` 。 + +找出并返回拆分 `nums` 的所有可行方案中的最小代价。 + +**子数组** 是数组的一个连续 **非空** 元素序列。 + + + +**示例 1:** + +``` +输入:nums = [1,2,1,2,1,3,3], k = 2 +输出:8 +解释:将 nums 拆分成两个子数组:[1,2], [1,2,1,3,3] +[1,2] 的重要性是 2 + (0) = 2 。 +[1,2,1,3,3] 的重要性是 2 + (2 + 2) = 6 。 +拆分的代价是 2 + 6 = 8 ,可以证明这是所有可行的拆分方案中的最小代价。 +``` + +**示例 2:** + +``` +输入:nums = [1,2,1,2,1], k = 2 +输出:6 +解释:将 nums 拆分成两个子数组:[1,2], [1,2,1] 。 +[1,2] 的重要性是 2 + (0) = 2 。 +[1,2,1] 的重要性是 2 + (2) = 4 。 +拆分的代价是 2 + 4 = 6 ,可以证明这是所有可行的拆分方案中的最小代价。 +``` + +**示例 3:** + +``` +输入:nums = [1,2,1,2,1], k = 5 +输出:10 +解释:将 nums 拆分成一个子数组:[1,2,1,2,1]. +[1,2,1,2,1] 的重要性是 5 + (3 + 2) = 10 。 +拆分的代价是 10 ,可以证明这是所有可行的拆分方案中的最小代价。 +``` + + + +**提示:** + +- `1 <= nums.length <= 1000` +- `0 <= nums[i] < nums.length` +- `1 <= k <= 109` + + + +## solution + +一维DP。 + +dp(i)表示以0...i的代价,求dp(n-1)。 + +用map维护出现不止一次的元素个数。 + +```python +INF = int(1e20) +class Solution: + def minCost(self, nums: List[int], k: int) -> int: + n = len(nums) + dp = [INF for _ in range(n)] + for i in range(n): + res = INF + cnt = collections.Counter() + t = 0 + for j in range(i, -1, -1): + cnt[nums[j]] += 1 + if cnt[nums[j]] == 2: + t += 2 + elif cnt[nums[j]] > 2: + t += 1 + res = min(res, (dp[j - 1] if j - 1 >= 0 else 0) + k + t) + # if i == n-1 and j == 2: + # print("x") + dp[i] = res + # print(dp) + return dp[n - 1] +``` + diff --git "a/_posts/Algorithms/leetcode/2023-01-29-6339. \345\260\206\347\217\240\345\255\220\346\224\276\345\205\245\350\203\214\345\214\205\344\270\255.md" "b/_posts/Algorithms/leetcode/2023-01-29-6339. \345\260\206\347\217\240\345\255\220\346\224\276\345\205\245\350\203\214\345\214\205\344\270\255.md" new file mode 100644 index 0000000000..6a74e28a91 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-01-29-6339. \345\260\206\347\217\240\345\255\220\346\224\276\345\205\245\350\203\214\345\214\205\344\270\255.md" @@ -0,0 +1,74 @@ +--- +layout: post +category: leetcode +title: 6339. 将珠子放入背包中 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/put-marbles-in-bags/) + +你有 `k` 个背包。给你一个下标从 **0** 开始的整数数组 `weights` ,其中 `weights[i]` 是第 `i` 个珠子的重量。同时给你整数 `k` 。 + +请你按照如下规则将所有的珠子放进 `k` 个背包。 + +- 没有背包是空的。 +- 如果第 `i` 个珠子和第 `j` 个珠子在同一个背包里,那么下标在 `i` 到 `j` 之间的所有珠子都必须在这同一个背包中。 +- 如果一个背包有下标从 `i` 到 `j` 的所有珠子,那么这个背包的价格是 `weights[i] + weights[j]` 。 + +一个珠子分配方案的 **分数** 是所有 `k` 个背包的价格之和。 + +请你返回所有分配方案中,**最大分数** 与 **最小分数** 的 **差值** 为多少。 + + + +**示例 1:** + +``` +输入:weights = [1,3,5,1], k = 2 +输出:4 +解释: +分配方案 [1],[3,5,1] 得到最小得分 (1+1) + (3+1) = 6 。 +分配方案 [1,3],[5,1] 得到最大得分 (1+3) + (5+1) = 10 。 +所以差值为 10 - 6 = 4 。 +``` + +**示例 2:** + +``` +输入:weights = [1, 3], k = 2 +输出:0 +解释:唯一的分配方案为 [1],[3] 。 +最大最小得分相等,所以返回 0 。 +``` + + + +**提示:** + +- `1 <= k <= weights.length <= 105` +- `1 <= weights[i] <= 109` + +## solution + +脑筋急转弯 + +不要关注端点,要关注分割位置,收益就是分割位置左右两边 + +```python + +class Solution: + def putMarbles(self, weights: List[int], k: int) -> int: + # 不要关注端点,要关注分割位置,收益就是分割位置左右两边 + d = [] + for i in range(len(weights) - 1): + a, b = weights[i], weights[i + 1] + d.append(a + b) + d.sort() + # print(d) + ans = -sum(d[:k - 1]) + d = list(reversed(d)) + ans += sum(d[:k - 1]) + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2023-01-29-6340. \347\273\237\350\256\241\344\270\212\345\215\207\345\233\233\345\205\203\347\273\204.md" "b/_posts/Algorithms/leetcode/2023-01-29-6340. \347\273\237\350\256\241\344\270\212\345\215\207\345\233\233\345\205\203\347\273\204.md" new file mode 100644 index 0000000000..8bd342be32 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-01-29-6340. \347\273\237\350\256\241\344\270\212\345\215\207\345\233\233\345\205\203\347\273\204.md" @@ -0,0 +1,85 @@ +--- +layout: post +category: leetcode +title: 6340. 统计上升四元组 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/count-increasing-quadruplets/) + +给你一个长度为 `n` 下标从 **0** 开始的整数数组 `nums` ,它包含 `1` 到 `n` 的所有数字,请你返回上升四元组的数目。 + +如果一个四元组 `(i, j, k, l)` 满足以下条件,我们称它是上升的: + +- `0 <= i < j < k < l < n` 且 +- `nums[i] < nums[k] < nums[j] < nums[l]` 。 + + + +**示例 1:** + +``` +输入:nums = [1,3,2,4,5] +输出:2 +解释: +- 当 i = 0 ,j = 1 ,k = 2 且 l = 3 时,有 nums[i] < nums[k] < nums[j] < nums[l] 。 +- 当 i = 0 ,j = 1 ,k = 2 且 l = 4 时,有 nums[i] < nums[k] < nums[j] < nums[l] 。 +没有其他的四元组,所以我们返回 2 。 +``` + +**示例 2:** + +``` +输入:nums = [1,2,3,4] +输出:0 +解释:只存在一个四元组 i = 0 ,j = 1 ,k = 2 ,l = 3 ,但是 nums[j] < nums[k] ,所以我们返回 0 。 +``` + + + +**提示:** + +- `4 <= nums.length <= 4000` +- `1 <= nums[i] <= nums.length` +- `nums` 中所有数字 **互不相同** ,`nums` 是一个排列。 + +## solution + +统计四元组。 + +枚举中间的两个数。O(n2) + +需要预处理简化时间复杂度。 + +```python +class Solution: + def countQuadruplets(self, nums: List[int]) -> int: + n = len(nums) + # i,j,k,l. i j: + cnt_greater_j[j][i] = cnt + if nums[i] > nums[j]: + cnt += 1 + i -= 1 + ans = 0 + for j in range(n): + for k in range(j + 1, n): + if nums[j] > nums[k]: + ans += cnt_less_k[k][j] * cnt_greater_j[j][k] + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2023-01-30-1664. \347\224\237\346\210\220\345\271\263\350\241\241\346\225\260\347\273\204\347\232\204\346\226\271\346\241\210\346\225\260.md" "b/_posts/Algorithms/leetcode/2023-01-30-1664. \347\224\237\346\210\220\345\271\263\350\241\241\346\225\260\347\273\204\347\232\204\346\226\271\346\241\210\346\225\260.md" new file mode 100644 index 0000000000..9df6dbaaba --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-01-30-1664. \347\224\237\346\210\220\345\271\263\350\241\241\346\225\260\347\273\204\347\232\204\346\226\271\346\241\210\346\225\260.md" @@ -0,0 +1,98 @@ +--- +layout: post +category: leetcode +title: 1664. 生成平衡数组的方案数 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/ways-to-make-a-fair-array/) + +给你一个整数数组 `nums` 。你需要选择 **恰好** 一个下标(下标从 **0** 开始)并删除对应的元素。请注意剩下元素的下标可能会因为删除操作而发生改变。 + +比方说,如果 `nums = [6,1,7,4,1]` ,那么: + +- 选择删除下标 `1` ,剩下的数组为 `nums = [6,7,4,1]` 。 +- 选择删除下标 `2` ,剩下的数组为 `nums = [6,1,4,1]` 。 +- 选择删除下标 `4` ,剩下的数组为 `nums = [6,1,7,4]` 。 + +如果一个数组满足奇数下标元素的和与偶数下标元素的和相等,该数组就是一个 **平衡数组** 。 + +请你返回删除操作后,剩下的数组 `nums` 是 **平衡数组** 的 **方案数** 。 + + + +**示例 1:** + +``` +输入:nums = [2,1,6,4] +输出:1 +解释: +删除下标 0 :[1,6,4] -> 偶数元素下标为:1 + 4 = 5 。奇数元素下标为:6 。不平衡。 +删除下标 1 :[2,6,4] -> 偶数元素下标为:2 + 4 = 6 。奇数元素下标为:6 。平衡。 +删除下标 2 :[2,1,4] -> 偶数元素下标为:2 + 4 = 6 。奇数元素下标为:1 。不平衡。 +删除下标 3 :[2,1,6] -> 偶数元素下标为:2 + 6 = 8 。奇数元素下标为:1 。不平衡。 +只有一种让剩余数组成为平衡数组的方案。 +``` + +**示例 2:** + +``` +输入:nums = [1,1,1] +输出:3 +解释:你可以删除任意元素,剩余数组都是平衡数组。 +``` + +**示例 3:** + +``` +输入:nums = [1,2,3] +输出:0 +解释:不管删除哪个元素,剩下数组都不是平衡数组。 +``` + + + +**提示:** + +- `1 <= nums.length <= 105` +- `1 <= nums[i] <= 104` + +## solution + +找规律题 + +当删除某个下标后,新的偶数和 = 这个下标左边的偶数和 + 这个下标右边的奇数和 + +当删除某个下标后,新的奇数和 = 这个下标左边的奇数数和 + 这个下标右边的偶数数和 + +```python + +class Solution: + def waysToMakeFair(self, nums: List[int]) -> int: + odd, even = 0, 0 + for i, v in enumerate(nums): + if i % 2 == 0: + even += v + else: + odd += v + lo, le = 0, 0 + total = sum(nums) + # print(total, odd, even) + ans = 0 + for i, v in enumerate(nums): + if i % 2 == 0: + teven = odd - lo + le + if teven == total - v - teven: + ans += 1 + # print(i, v, teven) + le += v + else: + todd = even - le + lo + if todd == total - v - todd: + ans += 1 + # print(i, v, todd) + lo += v + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2023-02-03-1145. \344\272\214\345\217\211\346\240\221\347\235\200\350\211\262\346\270\270\346\210\217.md" "b/_posts/Algorithms/leetcode/2023-02-03-1145. \344\272\214\345\217\211\346\240\221\347\235\200\350\211\262\346\270\270\346\210\217.md" new file mode 100644 index 0000000000..e7605252ee --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-02-03-1145. \344\272\214\345\217\211\346\240\221\347\235\200\350\211\262\346\270\270\346\210\217.md" @@ -0,0 +1,84 @@ +--- +layout: post +category: leetcode +title: 1145. 二叉树着色游戏 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/binary-tree-coloring-game/) + +有两位极客玩家参与了一场「二叉树着色」的游戏。游戏中,给出二叉树的根节点 `root`,树上总共有 `n` 个节点,且 `n` 为奇数,其中每个节点上的值从 `1` 到 `n` 各不相同。 + +最开始时: + +- 「一号」玩家从 `[1, n]` 中取一个值 `x`(`1 <= x <= n`); +- 「二号」玩家也从 `[1, n]` 中取一个值 `y`(`1 <= y <= n`)且 `y != x`。 + +「一号」玩家给值为 `x` 的节点染上红色,而「二号」玩家给值为 `y` 的节点染上蓝色。 + +之后两位玩家轮流进行操作,「一号」玩家先手。每一回合,玩家选择一个被他染过色的节点,将所选节点一个 **未着色** 的邻节点(即左右子节点、或父节点)进行染色(「一号」玩家染红色,「二号」玩家染蓝色)。 + +如果(且仅在此种情况下)当前玩家无法找到这样的节点来染色时,其回合就会被跳过。 + +若两个玩家都没有可以染色的节点时,游戏结束。着色节点最多的那位玩家获得胜利 ✌️。 + +现在,假设你是「二号」玩家,根据所给出的输入,假如存在一个 `y` 值可以确保你赢得这场游戏,则返回 `true` ;若无法获胜,就请返回 `false` 。 + +**示例 1 :** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202302032031818.png) + +``` +输入:root = [1,2,3,4,5,6,7,8,9,10,11], n = 11, x = 3 +输出:true +解释:第二个玩家可以选择值为 2 的节点。 +``` + +**示例 2 :** + +``` +输入:root = [1,2,3], n = 3, x = 1 +输出:false +``` + + + +**提示:** + +- 树中节点数目为 `n` +- `1 <= x <= n <= 100` +- `n` 是奇数 +- `1 <= Node.val <= n` +- 树中所有值 **互不相同** + +## solution + +dfs遍历。 + +y节点肯定和x相邻,贪心。 + +统计左子树和右子树节点个数。 + +```python +class Solution: + def btreeGameWinningMove(self, root: Optional[TreeNode], n: int, x: int) -> bool: + lc, rc = 0, 0 + + def dfs(r): + if r is None: + return 0 + tl = dfs(r.left) + tr = dfs(r.right) + if r.val == x: + nonlocal lc, rc + lc = tl + rc = tr + return tl+tr + 1 + + dfs(root) + # print(lc, rc, n - lc - rc - 1) + y= max(lc, rc, n - lc - rc - 1) + return y > n -y +``` + diff --git "a/_posts/Algorithms/leetcode/2023-02-04-1798. \344\275\240\350\203\275\346\236\204\351\200\240\345\207\272\350\277\236\347\273\255\345\200\274\347\232\204\346\234\200\345\244\247\346\225\260\347\233\256.md" "b/_posts/Algorithms/leetcode/2023-02-04-1798. \344\275\240\350\203\275\346\236\204\351\200\240\345\207\272\350\277\236\347\273\255\345\200\274\347\232\204\346\234\200\345\244\247\346\225\260\347\233\256.md" new file mode 100644 index 0000000000..17d7633ed4 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-02-04-1798. \344\275\240\350\203\275\346\236\204\351\200\240\345\207\272\350\277\236\347\273\255\345\200\274\347\232\204\346\234\200\345\244\247\346\225\260\347\233\256.md" @@ -0,0 +1,76 @@ +--- +layout: post +category: leetcode +title: 1798. 你能构造出连续值的最大数目 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/maximum-number-of-consecutive-values-you-can-make/) + +给你一个长度为 `n` 的整数数组 `coins` ,它代表你拥有的 `n` 个硬币。第 `i` 个硬币的值为 `coins[i]` 。如果你从这些硬币中选出一部分硬币,它们的和为 `x` ,那么称,你可以 **构造** 出 `x` 。 + +请返回从 `0` 开始(**包括** `0` ),你最多能 **构造** 出多少个连续整数。 + +你可能有多个相同值的硬币。 + + + +**示例 1:** + +``` +输入:coins = [1,3] +输出:2 +解释:你可以得到以下这些值: +- 0:什么都不取 [] +- 1:取 [1] +从 0 开始,你可以构造出 2 个连续整数。 +``` + +**示例 2:** + +``` +输入:coins = [1,1,1,4] +输出:8 +解释:你可以得到以下这些值: +- 0:什么都不取 [] +- 1:取 [1] +- 2:取 [1,1] +- 3:取 [1,1,1] +- 4:取 [4] +- 5:取 [4,1] +- 6:取 [4,1,1] +- 7:取 [4,1,1,1] +从 0 开始,你可以构造出 8 个连续整数。 +``` + +**示例 3:** + +``` +输入:nums = [1,4,10,3,1] +输出:20 +``` + + + +**提示:** + +- `coins.length == n` +- `1 <= n <= 4 * 104` +- `1 <= coins[i] <= 4 * 104` + +## solution + +贪心。如果能构造0-x,现有y,则能构造0-x, y-x+y这俩区间了。 + +```python +class Solution: + def getMaximumConsecutive(self, coins: List[int]) -> int: + coins = sorted(coins) + x = 0 + for v in coins: + if x >= v - 1: + x += v + return x + 1 +``` + diff --git "a/_posts/Algorithms/leetcode/2023-02-05-6331. \344\270\244\344\270\252\347\272\277\346\256\265\350\216\267\345\276\227\347\232\204\346\234\200\345\244\232\345\245\226\345\223\201.md" "b/_posts/Algorithms/leetcode/2023-02-05-6331. \344\270\244\344\270\252\347\272\277\346\256\265\350\216\267\345\276\227\347\232\204\346\234\200\345\244\232\345\245\226\345\223\201.md" new file mode 100644 index 0000000000..6c726fd5b7 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-02-05-6331. \344\270\244\344\270\252\347\272\277\346\256\265\350\216\267\345\276\227\347\232\204\346\234\200\345\244\232\345\245\226\345\223\201.md" @@ -0,0 +1,70 @@ +--- +layout: post +category: leetcode +title: 6331. 两个线段获得的最多奖品 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/maximize-win-from-two-segments/) + +在 **X轴** 上有一些奖品。给你一个整数数组 `prizePositions` ,它按照 **非递减** 顺序排列,其中 `prizePositions[i]` 是第 `i` 件奖品的位置。数轴上一个位置可能会有多件奖品。再给你一个整数 `k` 。 + +你可以选择两个端点为整数的线段。每个线段的长度都必须是 `k` 。你可以获得位置在任一线段上的所有奖品(包括线段的两个端点)。注意,两个线段可能会有相交。 + +- 比方说 `k = 2` ,你可以选择线段 `[1, 3]` 和 `[2, 4]` ,你可以获得满足 `1 <= prizePositions[i] <= 3` 或者 `2 <= prizePositions[i] <= 4` 的所有奖品 i 。 + +请你返回在选择两个最优线段的前提下,可以获得的 **最多** 奖品数目。 + + + +**示例 1:** + +``` +输入:prizePositions = [1,1,2,2,3,3,5], k = 2 +输出:7 +解释:这个例子中,你可以选择线段 [1, 3] 和 [3, 5] ,获得 7 个奖品。 +``` + +**示例 2:** + +``` +输入:prizePositions = [1,2,3,4], k = 0 +输出:2 +解释:这个例子中,一个选择是选择线段 [3, 3] 和 [4, 4] ,获得 2 个奖品。 +``` + + + +**提示:** + +- `1 <= prizePositions.length <= 105` +- `1 <= prizePositions[i] <= 109` +- `0 <= k <= 109` +- `prizePositions` 有序非递减。 + + +## solution + +```python +class Solution: + def maximizeWin(self, prizePositions: List[int], k: int) -> int: + n = len(prizePositions) + ans = 0 + left = 0 + pre = [0] * n + ''' + 求最大的两个区间。每个区间可以双指针计算。找到一个后,只要找到左边里的最大一个就可以,可以持久化记录。 + ''' + for i in range(n): + while left <= i and prizePositions[i] - prizePositions[left] > k: + left += 1 + pre[i] = i - left + 1 + ans = max(ans, pre[i] + (pre[left - 1] if left - 1 >= 0 else 0)) + if i > 0: + pre[i] = max(pre[i], pre[i - 1]) + # print(pre) + return ans + +``` + diff --git "a/_posts/Algorithms/leetcode/2023-02-11-2556. \344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\277\273\350\275\254\346\234\200\345\244\232\344\270\200\346\254\241\344\275\277\350\267\257\345\276\204\344\270\215\350\277\236\351\200\232.md" "b/_posts/Algorithms/leetcode/2023-02-11-2556. \344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\277\273\350\275\254\346\234\200\345\244\232\344\270\200\346\254\241\344\275\277\350\267\257\345\276\204\344\270\215\350\277\236\351\200\232.md" new file mode 100644 index 0000000000..a8e2e9f2a8 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-02-11-2556. \344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\277\273\350\275\254\346\234\200\345\244\232\344\270\200\346\254\241\344\275\277\350\267\257\345\276\204\344\270\215\350\277\236\351\200\232.md" @@ -0,0 +1,77 @@ +--- +layout: post +category: leetcode +title: 2556. 二进制矩阵中翻转最多一次使路径不连通 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/disconnect-path-in-a-binary-matrix-by-at-most-one-flip/) + +给你一个下标从 **0** 开始的 `m x n` **二进制** 矩阵 `grid` 。你可以从一个格子 `(row, col)` 移动到格子 `(row + 1, col)` 或者 `(row, col + 1)` ,前提是前往的格子值为 `1` 。如果从 `(0, 0)` 到 `(m - 1, n - 1)` 没有任何路径,我们称该矩阵是 **不连通** 的。 + +你可以翻转 **最多一个** 格子的值(也可以不翻转)。你 **不能翻转** 格子 `(0, 0)` 和 `(m - 1, n - 1)` 。 + +如果可以使矩阵不连通,请你返回 `true` ,否则返回 `false` 。 + +**注意** ,翻转一个格子的值,可以使它的值从 `0` 变 `1` ,或从 `1` 变 `0` 。 + + + +**示例 1:** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202302111547206.png) + +``` +输入:grid = [[1,1,1],[1,0,0],[1,1,1]] +输出:true +解释:按照上图所示我们翻转蓝色格子里的值,翻转后从 (0, 0) 到 (2, 2) 没有路径。 +``` + +**示例 2:** + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202302111547907.png) + +``` +输入:grid = [[1,1,1],[1,0,1],[1,1,1]] +输出:false +解释:无法翻转至多一个格子,使 (0, 0) 到 (2, 2) 没有路径。 +``` + + + +**提示:** + +- `m == grid.length` +- `n == grid[i].length` +- `1 <= m, n <= 1000` +- `1 <= m * n <= 105` +- `grid[0][0] == grid[m - 1][n - 1] == 1` + +## solution + +判断是否有两次完全不同的路径,两次dfs,每次把当前路径去掉就行。 + +如果两次都可以到达终点,说明至少两次完全不同的路径。 + +```python + +class Solution: + def isPossibleToCutPath(self, grid: List[List[int]]) -> bool: + m, n = len(grid), len(grid[0]) + + def dfs(x, y): + if (x, y) == (m - 1, n - 1): + return True + grid[x][y] = 0 + if x + 1 < m and grid[x + 1][y] == 1: + if dfs(x + 1, y): + return True + if y + 1 < n and grid[x][y + 1] == 1: + if dfs(x, y + 1): + return True + return False + return (not dfs(0, 0)) or (not dfs(0, 0)) + +``` + diff --git "a/_posts/Algorithms/leetcode/2023-02-11-2561. \351\207\215\346\216\222\346\260\264\346\236\234.md" "b/_posts/Algorithms/leetcode/2023-02-11-2561. \351\207\215\346\216\222\346\260\264\346\236\234.md" new file mode 100644 index 0000000000..4111da436b --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-02-11-2561. \351\207\215\346\216\222\346\260\264\346\236\234.md" @@ -0,0 +1,74 @@ +--- +layout: post +category: leetcode +title: 2561. 重排水果 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/rearranging-fruits/) + +你有两个果篮,每个果篮中有 `n` 个水果。给你两个下标从 **0** 开始的整数数组 `basket1` 和 `basket2` ,用以表示两个果篮中每个水果的成本。 + +你希望两个果篮相等。为此,可以根据需要多次执行下述操作: + +- 选中两个下标 `i` 和 `j` ,并交换 `basket1` 中的第 `i` 个水果和 `basket2` 中的第 `j` 个水果。 +- 交换的成本是 `min(basket1i,basket2j)` 。 + +根据果篮中水果的成本进行排序,如果排序后结果完全相同,则认为两个果篮相等。 + +返回使两个果篮相等的最小交换成本,如果无法使两个果篮相等,则返回 `-1` 。 + + + +**示例 1:** + +``` +输入:basket1 = [4,2,2,2], basket2 = [1,4,1,2] +输出:1 +解释:交换 basket1 中下标为 1 的水果和 basket2 中下标为 0 的水果,交换的成本为 1 。此时,basket1 = [4,1,2,2] 且 basket2 = [2,4,1,2] 。重排两个数组,发现二者相等。 +``` + +**示例 2:** + +``` +输入:basket1 = [2,3,4,1], basket2 = [3,2,5,1] +输出:-1 +解释:可以证明无法使两个果篮相等。 +``` + + + +**提示:** + +- `basket1.length == bakste2.length` +- `1 <= basket1.length <= 105` +- `1 <= basket1i,basket2i <= 109` + +## solution + +排序+ 贪心 + +要点:可以找最小值当中介交换,此时最小值用了两次。 + +```python +class Solution: + def minCost(self, basket1: List[int], basket2: List[int]) -> int: + c1, c2 = collections.Counter(basket1), collections.Counter(basket2) + mv = min(min(basket1), min(basket2)) + diff = [] + c = collections.Counter() + for k, v in c1.items(): + c[k] += v + for k, v in c2.items(): + c[k] -= v + for k, v in c.items(): + if v == 0: continue + if abs(v) & 1: + return -1 + diff.extend([k] * (abs(v) // 2)) + diff.sort() + a = diff + return sum(min(x, mv * 2) for x in a[:len(a) // 2]) +``` + diff --git "a/_posts/Algorithms/leetcode/2023-02-12-6356. \345\255\220\345\255\227\347\254\246\344\270\262\345\274\202\346\210\226\346\237\245\350\257\242.md" "b/_posts/Algorithms/leetcode/2023-02-12-6356. \345\255\220\345\255\227\347\254\246\344\270\262\345\274\202\346\210\226\346\237\245\350\257\242.md" new file mode 100644 index 0000000000..86458e89c5 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-02-12-6356. \345\255\220\345\255\227\347\254\246\344\270\262\345\274\202\346\210\226\346\237\245\350\257\242.md" @@ -0,0 +1,87 @@ +--- +layout: post +category: leetcode +title: 6356. 子字符串异或查询 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/substring-xor-queries/) + +给你一个 **二进制字符串** `s` 和一个整数数组 `queries` ,其中 `queries[i] = [firsti, secondi]` 。 + +对于第 `i` 个查询,找到 `s` 的 **最短子字符串** ,它对应的 **十进制**值 `val` 与 `firsti` **按位异或** 得到 `secondi` ,换言之,`val ^ firsti == secondi` 。 + +第 `i` 个查询的答案是子字符串 `[lefti, righti]` 的两个端点(下标从 **0** 开始),如果不存在这样的子字符串,则答案为 `[-1, -1]` 。如果有多个答案,请你选择 `lefti` 最小的一个。 + +请你返回一个数组 `ans` ,其中 `ans[i] = [lefti, righti]` 是第 `i` 个查询的答案。 + +**子字符串** 是一个字符串中一段连续非空的字符序列。 + + + +**示例 1:** + +``` +输入:s = "101101", queries = [[0,5],[1,2]] +输出:[[0,2],[2,3]] +解释:第一个查询,端点为 [0,2] 的子字符串为 "101" ,对应十进制数字 5 ,且 5 ^ 0 = 5 ,所以第一个查询的答案为 [0,2]。第二个查询中,端点为 [2,3] 的子字符串为 "11" ,对应十进制数字 3 ,且 3 ^ 1 = 2 。所以第二个查询的答案为 [2,3] 。 +``` + +**示例 2:** + +``` +输入:s = "0101", queries = [[12,8]] +输出:[[-1,-1]] +解释:这个例子中,没有符合查询的答案,所以返回 [-1,-1] 。 +``` + +**示例 3:** + +``` +输入:s = "1", queries = [[4,5]] +输出:[[0,0]] +解释:这个例子中,端点为 [0,0] 的子字符串对应的十进制值为 1 ,且 1 ^ 4 = 5 。所以答案为 [0,0] 。 +``` + + + +**提示:** + +- `1 <= s.length <= 104` +- `s[i]` 要么是 `'0'` ,要么是 `'1'` 。 +- `1 <= queries.length <= 105` +- `0 <= firsti, secondi <= 109` + +## solution + +缓存下所有值,然后query时从map取即可。 + +```python +class Solution: + def substringXorQueries(self, s: str, queries: List[List[int]]) -> List[List[int]]: + l = len(bin(10 ** 9)[2:]) + l = min(l, len(s)) + m = {} + for a, b in queries: + x = a ^ b + m[x] = None + for i in range(len(s)): + t = 0 + for j in range(i, min(len(s), i + l + 1), 1): + t <<= 1 + t += int(s[j]) + if t in m and m[t] is None: + m[t] = [i, j] + elif t in m and m[t][1] - m[t][0] > j - i: + m[t] = [i, j] + ans = [] + for a, b in queries: + x = a ^ b + if m[x] is None: + ans.append([-1, -1]) + else: + ans.append(m[x]) + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2023-02-12-6357. \346\234\200\345\260\221\345\276\227\345\210\206\345\255\220\345\272\217\345\210\227.md" "b/_posts/Algorithms/leetcode/2023-02-12-6357. \346\234\200\345\260\221\345\276\227\345\210\206\345\255\220\345\272\217\345\210\227.md" new file mode 100644 index 0000000000..e0758b8812 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-02-12-6357. \346\234\200\345\260\221\345\276\227\345\210\206\345\255\220\345\272\217\345\210\227.md" @@ -0,0 +1,88 @@ +--- +layout: post +category: leetcode +title: 6357. 最少得分子序列 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/subsequence-with-the-minimum-score/) + +给你两个字符串 `s` 和 `t` 。 + +你可以从字符串 `t` 中删除任意数目的字符。 + +如果没有从字符串 `t` 中删除字符,那么得分为 `0` ,否则: + +- 令 `left` 为删除字符中的最小下标。 +- 令 `right` 为删除字符中的最大下标。 + +字符串的得分为 `right - left + 1` 。 + +请你返回使 `t` 成为 `s` 子序列的最小得分。 + +一个字符串的 **子序列** 是从原字符串中删除一些字符后(也可以一个也不删除),剩余字符不改变顺序得到的字符串。(比方说 `"ace"` 是 `"***a\***b***c\***d***e\***"` 的子序列,但是 `"aec"` 不是)。 + + + +**示例 1:** + +``` +输入:s = "abacaba", t = "bzaa" +输出:1 +解释:这个例子中,我们删除下标 1 处的字符 "z" (下标从 0 开始)。 +字符串 t 变为 "baa" ,它是字符串 "abacaba" 的子序列,得分为 1 - 1 + 1 = 1 。 +1 是能得到的最小得分。 +``` + +**示例 2:** + +``` +输入:s = "cde", t = "xyz" +输出:3 +解释:这个例子中,我们将下标为 0, 1 和 2 处的字符 "x" ,"y" 和 "z" 删除(下标从 0 开始)。 +字符串变成 "" ,它是字符串 "cde" 的子序列,得分为 2 - 0 + 1 = 3 。 +3 是能得到的最小得分。 +``` + + + +**提示:** + +- `1 <= s.length, t.length <= 105` +- `s` 和 `t` 都只包含小写英文字母。 + +## solution + +是个思维题。 + +实际上找s中每个位置的可以最大t的前缀和后缀即可。 + +时间复杂度O(m+n) + +```python +INF = int(1e20) + + +class Solution: + def minimumScore(self, s: str, t: str) -> int: + ns, nt = len(s), len(t) + pre = [] + j = 0 + for i in range(ns): + if j < nt and s[i] == t[j]: + j += 1 + pre.append(j) + # print(pre) + j = nt - 1 + ans = INF + for i in range(ns - 1, -1, -1): + ans = min(ans, max(0, j - pre[i] + 1)) + if j >= 0 and s[i] == t[j]: + j -= 1 + # print(j) + ans = min(ans, j + 1) + ans = max(ans, 0) + return ans +``` + diff --git "a/_posts/Algorithms/leetcode/2023-02-19-6358. \346\233\264\346\226\260\346\225\260\347\273\204\345\220\216\345\244\204\347\220\206\346\261\202\345\222\214\346\237\245\350\257\242.md" "b/_posts/Algorithms/leetcode/2023-02-19-6358. \346\233\264\346\226\260\346\225\260\347\273\204\345\220\216\345\244\204\347\220\206\346\261\202\345\222\214\346\237\245\350\257\242.md" new file mode 100644 index 0000000000..3b4268257b --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-02-19-6358. \346\233\264\346\226\260\346\225\260\347\273\204\345\220\216\345\244\204\347\220\206\346\261\202\345\222\214\346\237\245\350\257\242.md" @@ -0,0 +1,77 @@ +--- +layout: post +category: leetcode +title: 6358. 更新数组后处理求和查询 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/handling-sum-queries-after-update/) + +给你两个下标从 **0** 开始的数组 `nums1` 和 `nums2` ,和一个二维数组 `queries` 表示一些操作。总共有 3 种类型的操作: + +1. 操作类型 1 为 `queries[i] = [1, l, r]` 。你需要将 `nums1` 从下标 `l` 到下标 `r` 的所有 `0` 反转成 `1` 或将 `1` 反转成 `0` 。`l` 和 `r` 下标都从 **0** 开始。 +2. 操作类型 2 为 `queries[i] = [2, p, 0]` 。对于 `0 <= i < n` 中的所有下标,令 `nums2[i] = nums2[i] + nums1[i] * p` 。 +3. 操作类型 3 为 `queries[i] = [3, 0, 0]` 。求 `nums2` 中所有元素的和。 + +请你返回一个数组,包含所有第三种操作类型的答案。 + + + +**示例 1:** + +``` +输入:nums1 = [1,0,1], nums2 = [0,0,0], queries = [[1,1,1],[2,1,0],[3,0,0]] +输出:[3] +解释:第一个操作后 nums1 变为 [1,1,1] 。第二个操作后,nums2 变成 [1,1,1] ,所以第三个操作的答案为 3 。所以返回 [3] 。 +``` + +**示例 2:** + +``` +输入:nums1 = [1], nums2 = [5], queries = [[2,0,0],[3,0,0]] +输出:[5] +解释:第一个操作后,nums2 保持不变为 [5] ,所以第二个操作的答案是 5 。所以返回 [5] 。 +``` + + + +**提示:** + +- `1 <= nums1.length,nums2.length <= 105` +- `nums1.length = nums2.length` +- `1 <= queries.length <= 105` +- `queries[i].length = 3` +- `0 <= l <= r <= nums1.length - 1` +- `0 <= p <= 106` +- `0 <= nums1[i] <= 1` +- `0 <= nums2[i] <= 109` + +## solution + +线段树板子题。 + +```python + +class Solution: + def handleQuery(self, nums1: List[int], nums2: List[int], queries: List[List[int]]) -> List[int]: + sg = SegmentTree() + sg.op_update = SegOpUpdate.Update_Reverse + sg.op_collect = SegOpCollect.Collect_Sum + sg.build_with_data(nums1) + n = len(nums1) + total = sum(nums2) + ans = [] + for v in queries: + if v[0] == 1: + l, r = v[1], v[2] + sg.update_interval(l, r, 1) + elif v[0] == 2: + p = v[1] + total += sg.query_interval(0, n-1) * p + elif v[0] == 3: + ans.append(total) + return ans + +``` + diff --git "a/_posts/Algorithms/leetcode/2023-03-03-1487. \344\277\235\350\257\201\346\226\207\344\273\266\345\220\215\345\224\257\344\270\200.md" "b/_posts/Algorithms/leetcode/2023-03-03-1487. \344\277\235\350\257\201\346\226\207\344\273\266\345\220\215\345\224\257\344\270\200.md" new file mode 100644 index 0000000000..1158f9a13b --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-03-03-1487. \344\277\235\350\257\201\346\226\207\344\273\266\345\220\215\345\224\257\344\270\200.md" @@ -0,0 +1,104 @@ +--- +layout: post +category: leetcode +title: 1487. 保证文件名唯一 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/making-file-names-unique/) + +给你一个长度为 `n` 的字符串数组 `names` 。你将会在文件系统中创建 `n` 个文件夹:在第 `i` 分钟,新建名为 `names[i]` 的文件夹。 + +由于两个文件 **不能** 共享相同的文件名,因此如果新建文件夹使用的文件名已经被占用,系统会以 `(k)` 的形式为新文件夹的文件名添加后缀,其中 `k` 是能保证文件名唯一的 **最小正整数** 。 + +返回长度为 *`n`* 的字符串数组,其中 `ans[i]` 是创建第 `i` 个文件夹时系统分配给该文件夹的实际名称。 + + + +**示例 1:** + +``` +输入:names = ["pes","fifa","gta","pes(2019)"] +输出:["pes","fifa","gta","pes(2019)"] +解释:文件系统将会这样创建文件名: +"pes" --> 之前未分配,仍为 "pes" +"fifa" --> 之前未分配,仍为 "fifa" +"gta" --> 之前未分配,仍为 "gta" +"pes(2019)" --> 之前未分配,仍为 "pes(2019)" +``` + +**示例 2:** + +``` +输入:names = ["gta","gta(1)","gta","avalon"] +输出:["gta","gta(1)","gta(2)","avalon"] +解释:文件系统将会这样创建文件名: +"gta" --> 之前未分配,仍为 "gta" +"gta(1)" --> 之前未分配,仍为 "gta(1)" +"gta" --> 文件名被占用,系统为该名称添加后缀 (k),由于 "gta(1)" 也被占用,所以 k = 2 。实际创建的文件名为 "gta(2)" 。 +"avalon" --> 之前未分配,仍为 "avalon" +``` + +**示例 3:** + +``` +输入:names = ["onepiece","onepiece(1)","onepiece(2)","onepiece(3)","onepiece"] +输出:["onepiece","onepiece(1)","onepiece(2)","onepiece(3)","onepiece(4)"] +解释:当创建最后一个文件夹时,最小的正有效 k 为 4 ,文件名变为 "onepiece(4)"。 +``` + +**示例 4:** + +``` +输入:names = ["wano","wano","wano","wano"] +输出:["wano","wano(1)","wano(2)","wano(3)"] +解释:每次创建文件夹 "wano" 时,只需增加后缀中 k 的值即可。 +``` + +**示例 5:** + +``` +输入:names = ["kaido","kaido(1)","kaido","kaido(1)"] +输出:["kaido","kaido(1)","kaido(2)","kaido(1)(1)"] +解释:注意,如果含后缀文件名被占用,那么系统也会按规则在名称后添加新的后缀 (k) 。 +``` + + + +**提示:** + +- `1 <= names.length <= 5 * 10^4` +- `1 <= names[i].length <= 20` +- `names[i]` 由小写英文字母、数字和/或圆括号组成。 + +## solution + +set去重,维护一个name的最小可用数字。只在错误时移动。 + +```python +class Solution: + def getFolderNames(self, names: List[str]) -> List[str]: + d = set() + mv = {} + ans = [] + for name in names: + if name not in d: + d.add(name) + mv[name] = 1 + ans.append(name) + continue + x = None + while True: + x = "{}({})".format(name, mv[name]) + if x in d: + mv[name] += 1 + else: + break + d.add(x) + ans.append(x) + mv[x] = 1 + return ans + +``` + diff --git "a/_posts/Algorithms/leetcode/2023-03-14-1605. \347\273\231\345\256\232\350\241\214\345\222\214\345\210\227\347\232\204\345\222\214\346\261\202\345\217\257\350\241\214\347\237\251\351\230\265.md" "b/_posts/Algorithms/leetcode/2023-03-14-1605. \347\273\231\345\256\232\350\241\214\345\222\214\345\210\227\347\232\204\345\222\214\346\261\202\345\217\257\350\241\214\347\237\251\351\230\265.md" new file mode 100644 index 0000000000..fc9fc02d73 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-03-14-1605. \347\273\231\345\256\232\350\241\214\345\222\214\345\210\227\347\232\204\345\222\214\346\261\202\345\217\257\350\241\214\347\237\251\351\230\265.md" @@ -0,0 +1,103 @@ +--- +layout: post +category: leetcode +title: 1605. 给定行和列的和求可行矩阵 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/find-valid-matrix-given-row-and-column-sums/) + +给你两个非负整数数组 `rowSum` 和 `colSum` ,其中 `rowSum[i]` 是二维矩阵中第 `i` 行元素的和, `colSum[j]` 是第 `j` 列元素的和。换言之你不知道矩阵里的每个元素,但是你知道每一行和每一列的和。 + +请找到大小为 `rowSum.length x colSum.length` 的任意 **非负整数** 矩阵,且该矩阵满足 `rowSum` 和 `colSum` 的要求。 + +请你返回任意一个满足题目要求的二维矩阵,题目保证存在 **至少一个** 可行矩阵。 + + + +**示例 1:** + +``` +输入:rowSum = [3,8], colSum = [4,7] +输出:[[3,0], + [1,7]] +解释: +第 0 行:3 + 0 = 3 == rowSum[0] +第 1 行:1 + 7 = 8 == rowSum[1] +第 0 列:3 + 1 = 4 == colSum[0] +第 1 列:0 + 7 = 7 == colSum[1] +行和列的和都满足题目要求,且所有矩阵元素都是非负的。 +另一个可行的矩阵为:[[1,2], + [3,5]] +``` + +**示例 2:** + +``` +输入:rowSum = [5,7,10], colSum = [8,6,8] +输出:[[0,5,0], + [6,1,0], + [2,0,8]] +``` + +**示例 3:** + +``` +输入:rowSum = [14,9], colSum = [6,9,8] +输出:[[0,9,5], + [6,0,3]] +``` + +**示例 4:** + +``` +输入:rowSum = [1,0], colSum = [1] +输出:[[1], + [0]] +``` + +**示例 5:** + +``` +输入:rowSum = [0], colSum = [0] +输出:[[0]] +``` + + + +**提示:** + +- `1 <= rowSum.length, colSum.length <= 500` +- `0 <= rowSum[i], colSum[i] <= 108` +- `sum(rowSum) == sum(colSum)` + + + +## solution + +贪心,遇到个元素,就往最大了放,因为后面元素可以为0. [参考](https://leetcode.cn/problems/find-valid-matrix-given-row-and-column-sums/solution/mei-you-si-lu-yi-ge-dong-hua-miao-dong-f-eezj/) + +```python +class Solution: + def restoreMatrix(self, rowSum: List[int], colSum: List[int]) -> List[List[int]]: + n, m = len(rowSum), len(colSum) + res = [[0 for _ in range(m)] for _ in range(n)] + for i, r in enumerate(rowSum): + for j, c in enumerate(colSum): + res[i][j] = min(r, c) + r -= res[i][j] + colSum[j] -= res[i][j] + return res + + +if __name__ == '__main__': + f = Solution().restoreMatrix + + print("actual:", f(rowSum=[3, 8], colSum=[4, 7]), "should:", [[3, 0], [1, 7]]) + print("actual:", f(rowSum=[5, 7, 10], colSum=[8, 6, 8]), "should:", [[0, 5, 0], [6, 1, 0], [2, 0, 8]]) + print("actual:", f(rowSum=[14, 9], colSum=[6, 9, 8]), "should:", [[0, 9, 5], [6, 0, 3]]) + print("actual:", f(rowSum=[1, 0], colSum=[1]), "should:", [[1], [0]]) + print("actual:", f(rowSum=[0], colSum=[0]), "should:", [[0]]) +``` + diff --git "a/_posts/Algorithms/leetcode/2023-03-18-1615. \346\234\200\345\244\247\347\275\221\347\273\234\347\247\251.md" "b/_posts/Algorithms/leetcode/2023-03-18-1615. \346\234\200\345\244\247\347\275\221\347\273\234\347\247\251.md" new file mode 100644 index 0000000000..8e3dc9ffed --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-03-18-1615. \346\234\200\345\244\247\347\275\221\347\273\234\347\247\251.md" @@ -0,0 +1,102 @@ +--- +layout: post +category: leetcode +title: 1615. 最大网络秩 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/maximal-network-rank/) + +`n` 座城市和一些连接这些城市的道路 `roads` 共同组成一个基础设施网络。每个 `roads[i] = [ai, bi]` 都表示在城市 `ai` 和 `bi` 之间有一条双向道路。 + +两座不同城市构成的 **城市对** 的 **网络秩** 定义为:与这两座城市 **直接** 相连的道路总数。如果存在一条道路直接连接这两座城市,则这条道路只计算 **一次** 。 + +整个基础设施网络的 **最大网络秩** 是所有不同城市对中的 **最大网络秩** 。 + +给你整数 `n` 和数组 `roads`,返回整个基础设施网络的 **最大网络秩** 。 + + + +**示例 1:** + +**![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202303182204280.png)** + +``` +输入:n = 4, roads = [[0,1],[0,3],[1,2],[1,3]] +输出:4 +解释:城市 0 和 1 的网络秩是 4,因为共有 4 条道路与城市 0 或 1 相连。位于 0 和 1 之间的道路只计算一次。 +``` + +**示例 2:** + +**![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202303182204311.png)** + +``` +输入:n = 5, roads = [[0,1],[0,3],[1,2],[1,3],[2,3],[2,4]] +输出:5 +解释:共有 5 条道路与城市 1 或 2 相连。 +``` + +**示例 3:** + +``` +输入:n = 8, roads = [[0,1],[1,2],[2,3],[2,4],[5,6],[5,7]] +输出:5 +解释:2 和 5 的网络秩为 5,注意并非所有的城市都需要连接起来。 +``` + + + +**提示:** + +- `2 <= n <= 100` +- `0 <= roads.length <= n * (n - 1) / 2` +- `roads[i].length == 2` +- `0 <= ai, bi <= n-1` +- `ai != bi` +- 每对城市之间 **最多只有一条** 道路相连 + +通过 + +## solution + +贪心,直接看度最大的两组节点即可。 + +```python +class Solution: + def maximalNetworkRank(self, n: int, roads: List[List[int]]) -> int: + degree = collections.Counter() + for v in range(n): + degree[v] = 0 + for a, b in roads: + degree[a] += 1 + degree[b] += 1 + import heapq + x = heapq.nlargest(2, set(degree.values())) + first, second = 0, 0 + if len(x) >= 1: + first = x[0] + if len(x) >= 2: + second = x[1] + count2nodes = collections.defaultdict(list) + for k, v in degree.items(): + count2nodes[v].append(k) + roads_set = set(tuple(v) for v in roads) + if len(count2nodes[first]) == 1: + u = count2nodes[first][0] + for v in count2nodes[second]: + if not ((u, v) in roads_set or (v, u) in roads_set): + return first + second + return first + second - 1 + import math + n1, n2 = len(count2nodes[first]), len(count2nodes[second]) + if math.comb(n1, 2) > len(roads): + return 2 * first + for u in count2nodes[first]: + for v in count2nodes[first]: + if u != v and (u, v) not in roads_set and (v, u) not in roads_set: + return first * 2 + return max(2 * first - 1, 0) +``` + diff --git "a/_posts/Algorithms/leetcode/2023-04-08-1017. \350\264\237\344\272\214\350\277\233\345\210\266\350\275\254\346\215\242.md" "b/_posts/Algorithms/leetcode/2023-04-08-1017. \350\264\237\344\272\214\350\277\233\345\210\266\350\275\254\346\215\242.md" new file mode 100644 index 0000000000..16b18800c0 --- /dev/null +++ "b/_posts/Algorithms/leetcode/2023-04-08-1017. \350\264\237\344\272\214\350\277\233\345\210\266\350\275\254\346\215\242.md" @@ -0,0 +1,81 @@ +--- +layout: post +category: leetcode +title: 1017. 负二进制转换 +tags: leetcode +--- + +## title +[problem link](https://leetcode.cn/problems/convert-to-base-2/) + +给你一个整数 `n` ,以二进制字符串的形式返回该整数的 **负二进制(`base -2`)**表示。 + +**注意,**除非字符串就是 `"0"`,否则返回的字符串中不能含有前导零。 + + + +**示例 1:** + +``` +输入:n = 2 +输出:"110" +解释:(-2)2 + (-2)1 = 2 +``` + +**示例 2:** + +``` +输入:n = 3 +输出:"111" +解释:(-2)2 + (-2)1 + (-2)0 = 3 +``` + +**示例 3:** + +``` +输入:n = 4 +输出:"100" +解释:(-2)2 = 4 +``` + + + +**提示:** + +- `0 <= n <= 109` + +## solution + +负二进制的表达。 + +和二进制一样,但记得要处理下-1,每一位可能是-1,0,1,要把-1转换下,变成1. + +```python +class Solution: + def baseNeg2(self, n: int) -> str: + if n == 0: + return '0' + ans = [] + b = -2 + while n != 0: + x = n % b + ans.append(str(abs(x))) + if x < 0: + x += abs(b) # 变成正数 + n = (n - x) // b + ans = ans[::-1] + return "".join(ans) +``` + + + +延伸 + + + +转负三进制怎么办 + +b=-3即可。它可以转任意进制。处理好负数即可。 + + + diff --git "a/_posts/DailyLife/2018-02-07-\347\202\222\350\217\234.md" "b/_posts/DailyLife/2018-02-07-\347\202\222\350\217\234.md" deleted file mode 100644 index 49258f5d0b..0000000000 --- "a/_posts/DailyLife/2018-02-07-\347\202\222\350\217\234.md" +++ /dev/null @@ -1,132 +0,0 @@ ---- -layout: post -category: DailyLife -title: 炒菜 -tags: DailyLife ---- - -## 炒菜 - -### 土豆丝+肉丝 - -土豆去皮变成丝。 需要先洗一遍,去掉淀粉,否则氧化发黑,可以放水里,用到再捞出来。 - - - -肉丝洗3遍。 - - - -热锅, 放油, 底部全湿, 放肉丝, 2勺 料酒, 2勺生抽, 半勺老抽。 - - - -放土豆丝, 每5s翻炒,放鸡精, 如果老抽多了可以不放盐。 菜基本熟时放葱。 - - - - - -### 炒卷心菜 - -大小 长3*3大小,不要梗。 - - - -热锅冷油, 油比肉丝少点。 放卷心菜, 生抽2勺, 鸡精, 葱。 - - - -**要干锅时加热水。** - - - -### 五花肉+荷兰豆 - -不需要豆油 - -五花肉过于肥腻,需要锅里不放油 闷一会,因为不是肉丝所以没那么容易老。 - -直到肉变色,炸出油。 - -加蒜 加料酒,生抽老抽。因为肉比较大,可以加点水让配料入味 - -然后放荷兰豆炒。 - - - -### 蒜薹+肉丝 - -蒜薹切段,煮50秒,捞出来,这是为了避免蒜薹熟的慢。 - -肉丝做法 + 蒜薹。 - -### 红烧鸡翅根 - -鸡翅根切几道,红烧时入味 - -鸡翅根煮熟。 - -放油,鸡翅根,料酒,生抽,老抽 - -加水,4分之一高度。 - -加盐。 - -放葱。 - -味素。 - -红烧到无水 - - -### 茄子肉丝 -茄子 切成丝: - -1. 先斜着切片,5mm厚即可,茄子熟时缩的多。 - -2. 片再切丝,5mm宽 - -肉丝做法 - -茄子含水少,避免干锅需要加点水。 - - -### 芹菜肉丝 - -芹菜: -1. 长度2cm -2. 宽的芹菜要中间切一刀分开 -3. 先去叶子,再去根,再切 - -肉丝做法 - -芹菜含水多 - -### 红烧鸡爪 - -洗干净 去指甲 - -鸡爪炖2min,快熟那种 - -油,白砂糖让溶解,蒜, - -放鸡爪,生抽2勺,老抽和耗油各1勺, 耗油是提现的 - -一罐300ml的啤酒,没有啤酒就热水, 水大概刚好到鸡爪上限那, 挺多的 - -一个八角 - -中火20min, 直到快没有汤了 - -葱花,味素。 - - - -## 韭菜鸡蛋 - -- 一把韭菜,4个鸡蛋。 -- 韭菜洗干净,去死皮,切根,切长度为1.5-2cm左右 -- 锅里放油,放韭菜大概8-9分熟,颜色变了就可以,捞出来韭菜去水。 -- 放油,放鸡蛋,7-8分熟,成块了,放韭菜,加鸡精,加盐。 -- 注意:韭菜2-3s就变颜色了,要勤翻 diff --git "a/_posts/English/2020-12-09-\350\213\261\350\257\255\345\255\246\344\271\240.md" "b/_posts/English/2020-12-09-\350\213\261\350\257\255\345\255\246\344\271\240.md" new file mode 100644 index 0000000000..62a179e0d1 --- /dev/null +++ "b/_posts/English/2020-12-09-\350\213\261\350\257\255\345\255\246\344\271\240.md" @@ -0,0 +1,169 @@ +--- +layout: post +category: English +title: 英语学习 +tags: English +--- + +# 语法汇总 + +[语法顺口溜](https://zhuanlan.zhihu.com/p/146873536) + +## 单词 + +[语法-单词各种形式变化规则](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E5%8D%95%E8%AF%8D%E5%90%84%E7%A7%8D%E5%BD%A2%E5%BC%8F%E5%8F%98%E5%8C%96%E8%A7%84%E5%88%99/) + +## 介词 + + + +## 从句 + +[三大从句](https://mm.edrawsoft.cn/template/39526) + +[四级语法: 从句](https://mm.edrawsoft.cn/template/57209) + +从句时态: + +1. **主将从现** + +i will hit u when you come here + +if it rains, i will hit u. + +2. **主过从过** + +复合句有先后关系,过去+过去完成时, eg. when he came there, the train had gone. + +3. **主现从任** + +he tells me that u have died + +## 疑问句 + +[参考个人单独blog](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E7%96%91%E9%97%AE%E5%8F%A5/) + + +## 时态 + +[参考个人单独blog](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E6%97%B6%E6%80%81/) + +## 倒装 + +[参考个人单独blog](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E5%80%92%E8%A3%85%E5%8F%A5/) + +## 虚拟语气 + +[参考个人单独blog](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E8%99%9A%E6%8B%9F%E8%AF%AD%E6%B0%94/) + +## “限制性定语从句”和“非限制性定语从句”的区别 + +> [参考](https://zhuanlan.zhihu.com/p/30548008) + +> She despised people ***who flattered her***. 这是限制性的。非限制性就是表定语 非限制的 +> (她看不起**那些吹捧她的**人。) + +在上面的示例中,定语从句“who flattered her”起到了**限制名词**的作用(即缩小了名词的表示范围)。 + +因此,我们称这类定语从句为**限制性定语从句**。 + + + +在有些场景下,先行词的指向已经是唯一的了,此时就无法再缩小这个词的表示范围了。例如: + +> I made a card for mom ***who loves me most**.* (×) +> (我给**最爱我的**那个妈妈做了一张卡片。) + +每个人只有一个妈妈,所以“最爱我的那个妈妈”的表述明显不合逻辑,此时我们就需要用到**非限制性定语从句**。 + +所谓的非限制性定语从句,就是**使用“逗号”将定语从句与先行词隔开**,即: + +> I made a card for mom, ***who loves me most**.* +> (我给妈妈做了一张卡片,**她最爱我**。) + +因为非限制性定语从句的作用是:**不直接修饰先行词,只为先行词提供一些补充的信息。** + + + +①限定性定语从句: 从句不能省略,如果省略整个句子意思不完整。 + +非限定性定语从句: 从句可以省略,如果省略整个句子意思仍然完整 。 + +②限定性定语从句: 先行词可以用that 引导。 + +非限定性定语从句: 先行词不可以用that 引导。 + +eg. I like read the book that you lend me. + +③限定性定语从句: 引导词有时可以省略。 + +非限定性定语从句: 引导词不可以省略。 + +④限定性定语从句: 主句与从句不需要用逗号隔开。 + +非限定性定语从句: 主句与从句需要用逗号隔开。 + +⑤限定性定语从句: 从句只修饰先行词。 + +非限定性定语从句:从句既可以修饰先行词,也可以修饰整个句子或句子的一部分。 + + + +## 逗号使用 + +> [参考](https://zhuanlan.zhihu.com/p/46736877) + +1、当有三个或三个以上并列的单词或短语时,这些单词或短语要用逗号隔开,而且最后一个单词或短语一般都会用and或or连接,如: + +We had coffee, cheese and crackers and grapes. + +2、当两个前置形容词并列且可以调换顺序时,要用逗号隔开,如: + +He is a strong, healthy man. vs. He is a healthy, strong man. + + + +1、如果是以从句开头,则要在从句末尾用逗号隔开,如: + +If you are not sure about this, let me know now. + +2、如果开头的是介绍性短语,一般也要用逗号隔开,如: + +Having finally arrived in town, we went shopping. + +3、如果介绍性短语是以介词开头引导的,介词后面如果跟的是句子的主语,则要用逗号。则无论这个短语包含多少个单词,都无需用逗号隔开,如: + +Between your house on Main Street and my house on Grand Avenue, the mayor's mansion stands proudly. + + + +1、同位语,如: + +My best friend, Joe, arrived. + +2、非限定性定语从句(非限制作用,也不能用that),如: + +Jill, who is my sister, shut the door. + +3、分词短语,如: + +The man, knowing it was late, hurried home. + +# 学习资源 + +## English学习资源 + +计算机英语部分参考另一个博客 + +## English-level-up-tips-for-Chinese + +网址:https://github.com/byoungd/English-level-up-tips-for-Chinese + +## github上“读”北大(北大课程资料民间整理) + +网址:https://lib-pku.github.io/ + +github:https://github.com/lib-pku/libpku + + + diff --git "a/_posts/English/2021-01-02-\345\217\221\351\237\263-\351\237\263\346\240\207.md" "b/_posts/English/2021-01-01-\345\217\221\351\237\263-\351\237\263\346\240\207.md" similarity index 69% rename from "_posts/English/2021-01-02-\345\217\221\351\237\263-\351\237\263\346\240\207.md" rename to "_posts/English/2021-01-01-\345\217\221\351\237\263-\351\237\263\346\240\207.md" index 3db6572c3d..4265fca9ad 100644 --- "a/_posts/English/2021-01-02-\345\217\221\351\237\263-\351\237\263\346\240\207.md" +++ "b/_posts/English/2021-01-01-\345\217\221\351\237\263-\351\237\263\346\240\207.md" @@ -7,6 +7,12 @@ tags: English ## 发音-音标 +欧陆词典用的是DJ音标新版。也是咱们常用的 英的,有长短。而美音无长短,音标写法上。 + +影响发音的因素:圆唇度、舌位高低、舌位前后。舌位影响了开头大小。因此学音标应以舌位为主。 + +### 音标分类 + 分类1 ![音标分类表1](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv1/v1/123.png) @@ -17,28 +23,51 @@ tags: English -æ : ai, such as trap. - - +### BBC经典发音教程 [可学习的bilibili视频: BBC经典发音教程](https://www.bilibili.com/video/BV1Y4411M7Ac?p=2) +### 音标发音文字注解 + 元音: -- /ɪ/ 舌抵下齿,双唇扁平分开,牙床近于全舌,发短促之“一”音。 是字母i或y在单词中的发音,发此音要短促而轻快。 **bit, hit, minute/minit/** +- /ɪ/ 舌抵下齿,双唇扁平分开,牙床近于全舌,发短促之“一”音。类似军训一二一的yie。 是字母i或y在单词中的发音,发此音要短促而轻快。 **bit, hit, minute/minit/** - /i:/ 舌抵下齿,双唇扁平作微笑状,发“一”之长音。 是字母ea、ee、ey、ie、或ei在单词中的发音,此音是长元音,一定注意把音发足。 -- /ʊ/ 双唇成圆形,牙床近于半合,舌尖不触下齿,自然而不用力,发短促之“屋”音。 是字母u、oo或ou在单词中的发音 -- /u:/ 双唇成圆形,牙床近于半合,舌尖不触下齿,自然而不用力,发 “屋”之长音。 是字母oo或ou在单词中的发音 -- /ʌ/ 双唇平放,牙床半开,舌尖抵住下龈,舌后微微升起,发短促之“阿”音 是字母o或u在单词中的发音 + +前者嘴唇放松,双齿高度大概小指尖高。舌位低于 并 后于 后者。后者嘴唇微笑,cheese那样拉开。 + +sit, seat。 + + + +- /ʊ/ 双唇成圆形,牙床近于半合,舌尖不触下齿,自然而不用力,发短促之“屋”音。 是字母u、oo或ou在单词中的发音 book, took, foot, could, would. +- /u:/ 双唇成圆形,牙床近于半合,舌尖不触下齿,自然而不用力,发 “屋”之长音。 是字母oo或ou在单词中的发音 goose, two, food, noon, fool + +前者者口型更大,舌位更低。 + + + +- /ə/ 舌上抬,唇成自然状态,口半开半闭,发“厄”之短音。 是字母a、o、u、e、or、er或ur在单词中的发音. about. problem, memory. Easily. Analysis. 中央元音元音图居中,舌位和/з:/差不多 + +- /з:/ 舌上抬,唇成自然状态,口半开半闭,发“厄”之长音。 是字母er、ir、or或ur在单词中的发音。 her, person,learn,sir, world. + + + +- /ʌ/ 双唇平放,牙床半开,舌尖抵住下龈,舌后微微升起,发短促之“阿”音 是字母o或u在单词中的发音。 but, hut, must。舌位低于/ə/ + - /ɑ:/ 双唇张而不圆,牙床大开,舌后微升,舌尖向后升缩微离下齿,发“阿”之长音。 是字母er在闭音节或重读闭音节中的发音也是字母a在以st结尾的单词中的读音。 + - /ɒ/ 双唇稍微向外突出圆形,舌后升起,舌尖不触下齿,发“噢”音 是字母o在单词中的发音 -- /ɔ:/ 双唇界于开闭、圆唇之间,牙床半开渐至全开,舌尖卷上再过渡为卷后。 是字母o、al、or、oar、our或oor在单词中的发音 -- /ə/ 舌上抬,唇成自然状态,口半开半闭,发“厄”之短音。 是字母a、o、u、e、or、er或ur在单词中的发音 -- /з:/ 舌上抬,唇成自然状态,口半开半闭,发“厄”之长音。 是字母er、ir、or或ur在单词中的发音 -- /e/舌近硬腭,舌尖顶下齿,牙床半开半合,作微笑状。 是字母e或ea在单词中的发音 -- /æ/ 双唇扁平,舌前微升,舌尖抵住下龈,牙床开,软腭升起,唇自然开放。 是字母a在闭音节或重读闭音节中的发音。 **和/e/的区别,前者两指宽,像绵羊叫,后者一指宽。** + +- /ɔ:/ 双唇界于开闭、圆唇之间,牙床半开渐至全开,舌尖卷上再过渡为卷后。 是字母o、al、or、oar、our或oor在单词中的发音. caught bought law。 这个英音和美音不一样。美音类似噢,英音类似哦。 + + + +- /e/舌近硬腭,舌尖顶下齿,牙床半开半合,作微笑状。 是字母e或ea在单词中的发音。 bed, get, pet, let, met, set. 舌位比/i:/低。 + +- /æ/ 双唇扁平,舌前微升,舌尖抵住下龈,牙床开,软腭升起,唇自然开放。 是字母a在闭音节或重读闭音节中的发音。 **和/e/的区别,前者/æ/ 两指宽,像绵羊叫,后者/e/一指宽。** @@ -56,8 +85,8 @@ tags: English - /ð/ 上下齿咬舌尖,送出气流,并使舌齿互相摩擦,须振动声带。类似z。 this, that, then, there - /s/ 双唇微开,上下齿接近于合拢状态,舌尖抵住下龈,气流从牙缝送出。 - /z/ 双唇微开,上下齿接近于合拢状态,舌尖抵住下龈,气流从牙缝送出,须振动声带。 -- /∫/ 双唇微开,向前突出,舌尖升近上龈,用力将气息送出来。 -- /ʒ/ 双唇微开,向前突出,舌尖升近上龈,用力将气息送出来,须振动声带。 +- /∫/ 双唇微开,向前突出,**舌尖升近上龈**,用力将气息送出来。 +- /ʒ/ 双唇微开,向前突出,舌尖升近上龈,用力将气息送出来,须振动声带。**是声带震动版的/∫/** - /t∫/ 双唇微开,先用舌尖抵上齿龈,突然张开,使气流外冲而成音。 - /dʒ/ 双唇微开,先用舌尖抵上齿龈,突然张开,使气流外冲而成音,须振动声带。 - /m/ 双唇闭拢,舌放平,振动声带,使气流从鼻腔出来。 @@ -68,6 +97,7 @@ tags: English - /r/ 唇形稍圆,舌身略凹,舌尖上卷,振动声带。 - /w/ 双唇突出,呈尖圆形,舌后升向软腭,气息流过,须振动声带。 - /j/ 双唇微开,舌抵下齿贴近硬腭,气流摩擦而出。 +- /dz/ 类似汉语里资。对比/ts/ @@ -84,6 +114,8 @@ tags: English +### 音标区分 + **长元音和短元音区别:不是长短,是松和紧。松元音只动舌头和声带,不动嘴唇。** **双元音和单元音区别:[e]是单元音,发声短促:dead [ded] , [ai]是双元音,有从[a]到[i]的一个过渡过程:die [dai] (双元音过渡在汉语里是没有的)** @@ -92,10 +124,36 @@ tags: English 常见区别: -- [辅音/m/、/n/与/ŋ/](https://www.bilibili.com/video/BV1Ae41147Ng/?spm_id_from=trigger_reload) -- [/æ/ 和 /e/](/æ/ 和 /e/) -- [/u:/和/u/](/u:/和/u/) -- [清辅音θ与s](https://www.bilibili.com/video/BV1X7411S7V8?spm_id_from=333.337.search-card.all.click) +- [辅音/m/、/n/与/ŋ/](https://www.bilibili.com/video/BV1Ae41147Ng/?spm_id_from=trigger_reload) m是闭口,n嘴唇微张但牙齿闭合,最后那个是中度张嘴。 +- [/æ/ 和 /e/](https://www.bilibili.com/video/BV1o7411M7cV?spm_id_from=333.999.0.0&vd_source=4c51dba622ffb91bed5205311847907b) ae和/e/的区别,前者两指宽,像绵羊叫,后者一指宽。 +- [双元音/aɪ/与 单元音/æ/](https://www.bilibili.com/video/BV1xg4y187CT?spm_id_from=333.999.0.0&vd_source=4c51dba622ffb91bed5205311847907b) 前者双元音后者单元音 但语速快了就无法区分了 +- [/u:/和/u/](https://www.bilibili.com/video/BV1d7411M7i1?spm_id_from=333.999.0.0) +- [清辅音θ与s](https://www.bilibili.com/video/BV1X7411S7V8?spm_id_from=333.337.search-card.all.click) 前者 上下齿咬舌尖。 后者双唇微开,上下齿接近于合拢状态 + +### 元音图 + +元音图 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202208131030725.jpg) + +注意: 红色是汉语拼音,黄色是美国英语。不圆唇的在前,圆唇在后。开口大小就是舌位高低 + + + +元音的舌面不能与硬腭接触,否则就成了辅音。 + + + +这有一个看和听发音的[网站](https://tfcs.baruch.cuny.edu/consonants-vowels/) + + + +### 英语兔学习笔记 + +可每日英语听力上看,免费。 + +- /ɪ/舌位比/i:/低,类似军训一二一里的一。bit, fit, hit, fish. 舌位过高是错误方式,不能读 中文 币 的韵母。 +- ## 音节 @@ -117,7 +175,39 @@ tags: English 比如单词later和latter。我们把这两个词按照这种原理分开,分别就是la/ter和lat/ter。 -那么这样分完有什么意义呢,当然有意义,而且意义重大,因为它能让你正确判断单词的发音。不用看音标。看下面 +那么这样分完有什么意义呢,当然有意义,而且意义重大,因为它能让你正确判断单词的发音。不用看音标。 + + + +另外 辅音+l/e结尾,也可以构成音节 apple/pl/ bicycle/baskl/ + +### 重读音节 + +什么是重读音节呢?首先普及一下单音节的单词是没有重读符号的,但是要重读。比如:get,let,must.say等。 + +1. 一个音节就重读:(没有重读符号)me/mi/ lake/lek/ bread/bred/ + +2. 一般2、3个音节的单词,重读在第一音节上 sister/'sst/ tiger/tag/ + + 特俗 + + ```python + \1. a开头+辅音 + + 举例:away/ we/ ago/gu/ + + \2. be/re开头 + + 举例:begin/bgn/ reply/rpla/ + + \3. de/es/im/mis开头 + + 举例:delay/dle/ improve/mpruv/ + ``` + + + +3. 3个或以上音节的单词,重读在倒数第三个音节上。 'family de'mocracy phy'losophy @@ -133,22 +223,26 @@ tags: English 2、**闭音节**:英语中以一个或几个辅音字母(r w y 除外)结尾而中间只有一个元音字母的音节,称为**闭音节**。闭音节的元音字母不发它字母本身的音。 -如果这个音节在单词中是重读,那就是**重读闭音节**了。 +总结: 开音节:only元 或 者元+辅+不发音e; 闭音节: 剩下的 + +### 重读闭音节 + +如果这个音节在单词中是闭音节并且重读,那就是**重读闭音节**了。 重读闭音节即两个辅音中间夹一个短元音(即**“辅元辅”结尾**。) -重读闭音节结尾,且词尾只有一个辅音字母,要**双写**。 +重读闭音节结尾,且词尾只有一个辅音字母,变ing要**双写**。 重读闭音节三要素 1.必须是重读音节; -2.最后只有一个辅音字母;只有一个元音; +2.最后只有一个辅音字母 3.只有一个元音,元音字母发短元音 -总结: 开音节:only元 或 者元+辅+不发音e; 闭音节: 剩下的 + ## 字母发音规则 @@ -158,6 +252,8 @@ tags: English +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202208242353490.png) + aeiou在非重读闭音节里,一般发/ə/, 比如doctor后面的o @@ -241,4 +337,27 @@ z [ z ] -![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20220112133608.jpg) \ No newline at end of file +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20220112133608.jpg) + + + +## 常见单词音标 + +who when where why what whom which + +while [/waɪl/](cmd://Speak/_us_/while) + +why [ /waɪ/](cmd://Speak/_us_/why) + +when [/wɛn/](cmd://Speak/_us_/when) + + + +Allow: [美 /əˈlaʊ/](cmd://Speak/_us_/allow) a lao. + +provide. [美 /prə'vaɪd/](cmd://Speak/_us_/provide) p rou + +Begin: [美 /bɪˈɡɪn/](cmd://Speak/_us_/begin) bi gin + +Again: [美 /ə'ɡɛn/](cmd://Speak/_us_/again) a gan + diff --git "a/_posts/English/2021-01-02-\345\217\221\351\237\263-\345\217\221\351\237\263\350\247\204\345\210\231.md" "b/_posts/English/2021-01-02-\345\217\221\351\237\263-\345\217\221\351\237\263\350\247\204\345\210\231.md" index 03912e5f8b..984be368a6 100644 --- "a/_posts/English/2021-01-02-\345\217\221\351\237\263-\345\217\221\351\237\263\350\247\204\345\210\231.md" +++ "b/_posts/English/2021-01-02-\345\217\221\351\237\263-\345\217\221\351\237\263\350\247\204\345\210\231.md" @@ -5,44 +5,6 @@ title: 发音-发音规则 tags: English --- -## 总结 - -发音规则 昂克 - -- 辅音元音连读: not at all, 如果辅音是/r/ /l/ /ŋ/, 辅音双写: for a -- 元+元,添加连读,自动添加/j/或/w/, 只有i和u。do it, go out. /ɔː/自动加r, saw in -- 特殊添加元音: /n/+/s/=/n ts/ since -- 辅+辅, 三组内的略读只读后面的,所有辅音相同略读,浊音在前清辅音在后可略读前面的:v f, z s,ð θ. 不可略读:/tʃ/ /dʒ/ -- 特殊略读 nt+元音, 省略t :advantage -- 吞音,三组里碰到后面是三组里非兄弟辅音就吞音(也包含其他非爆破辅音)。吞音保留时值和状态不发音, that cat -- 吞音喉音停顿:/tən/ /dən/ 只留ən, written -- 略读 h-droping: him, his, he, her -- 略读 g-droping: doing. ing里的 -- 变音: about you. would you, rock you. /t/+/ju/;/d/+/ju/。 miss you: sh -- 清辅音+元,清辅音浊化 -- 不同意群不连读 -- 元音+元音,如果读音相近,可以连一起,比如law office. lawwfis -- schewa: for, of, have, or, and等,元音变成ə - -**总结2:** - -> 视频: https://www.bilibili.com/video/BV1SZ4y1K7Lr?p=6&spm_id_from=pageDriver - -- 元音挨着元音不容易读,所以才会区分a和an -- 同化&异化 - - 同化:前面音 改变 - - 常见爆破音: k,t,d, 后加辅音,前面音发一半,也叫失去爆破。 - - 浊音变清音,比如have to, of course, 的v变f. - - inperson读imperson, n->m,嘴唇闭合。 - - 同化:后面音 改变 - - 比如变复数读音 - - 相互作用 - - s+j: bless you. z+j:as you wish. t+j: meet you. d+j: did you. 类似的educate, tissue. - - 辅音连读 - - 异化, r接元音会读r, 否则不发音 -- 省音: t,d。 来自其他视频,**t+辅音里的t省略,nt+元的t省略, nd+辅的d省略** -- 节奏: 等时性。 - ## 重音 - 单音节 @@ -58,6 +20,22 @@ tags: English > 链接: https://www.bilibili.com/video/av19992217?from=search&seid=14758661060311518388 +### 总结 + +- 辅+元,**连读**: not at all, 如果辅音是/r/ /l/ /ŋ/, 辅音双写: for a +- 元+元,添加连读,当尾元音是i和u时,自动添加/j/或/w/。do it, go out. /ɔː/自动加r, saw in +- 特殊添加连读: /n/+/s/=/n ts/ since +- 辅+辅,**连读**, 三组内的略读只读后面的,所有辅音相同略读,浊音在前清辅音在后可略读前面的:v f, z s,ð θ. 不可略读:/tʃ/ /dʒ/ +- 辅+辅,**吞音**,三组里碰到后面是三组里非兄弟辅音就吞音(也包含其他非爆破辅音)。吞音保留时值和状态不发音, that cat +- 吞音喉音停顿:/tən/ /dən/ 只留ən, written +- 略读 h-droping: him, his, he, her。 give him /givim/ +- 略读 g-droping: doing. ing里的 +- 变音: about you. would you, rock you. /t/+/ju/;/d/+/ju/。 miss you: sh +- ~~清辅音+元,清辅音浊化~~ +- 不同意群不连读 +- 元音+元音,如果读音相近,可以连一起,比如law office. lawwfis +- schewa: for, of, have, or, and等,元音变成ə + ### 清辅音浊化 S后面的清辅音浊化现象可以这样归纳:清辅音跟着一个元音,前面又有一个 s ,无论是在单词的最前面还是中间,只要是在重读音节或次重读音节里,一般都读成对应浊辅音,如stand,strike,speak,sky 等等,值得一提的是strike不是不用变,而是它“tr”本来所发的音已是浊辅音,但也要变成“dr”所发的那个音 (如dream中的“dr”所发的音). @@ -177,7 +155,225 @@ i经常弱读为e,所以give hime读为后面的,这个经常用后面的 ![image-20210102230759698](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv1/v1/109.png) -### 弱读 缩写 其他 -- + + +## 100个最常见的英语单词发音 + +> [参考](https://www.zhihu.com/zvideo/1390373231258382336) , 包含了常见单词的弱读,比如him, to, do, of等。 + +笔记 + + + +正常schewa: + +- a,an,that, for, as( he's as tall as me), do, at, but, from, or, an, one, should, could, so, some, than + +不弱读的: + +- This, by, they, we, say, out, also. + +意群结尾p不发音,what's up + +1期: + +- the: the发音后面的/ə/ 当the后面接元音时可变成/i/ +- I am: I'm 有时只有一个音/m/, I'm sorry / m_ 'sorry/ +- you are: yer. +- It is: /its/ 有时可省略元音 /ts/ ts cool +- we are: /wər/ +- they are: /ðər/ +- to: tə, go to时, t变d +- Of: /əv/ 在kind of, sort of里省略/v/, kanda +- and: no /d/ or just /n/, ex: And I + +2期: + +- With: 后面轻音化, /θ/ +- he, him, 省略/h/, ex: what does he want +- You: /jə/ + +5期: + +- Who /u/, ex: Anyone who wants to come can come. + +6期: + +- Can /cən/ +- Him /əm/. Give him: /givem/ + +7期: + +- into /ində/. 这里的t不遵循t发音规则。 + +8期下: + +- Its: /ts/ 没有前面/i/了。 + +10期下: + +- give是实词,但give me时弱读, give me that: gimme 省略v +- us: əs + + + + + +## /t/发音 + +[参考](https://rachelsenglish.com/podcast/004-t-pronunciations-flap-t-stop-t-true-t/) + +### True T + +开头或者重音节,或者后面接r。 + +- True T Rule 1: At the beginning of a word + - Exception #1: in the TR cluster (train, try) – then it can sound like a CH + - Exception #2: the words to, today, tomorrow. These may begin with a Flap T. +- True T Rule 2: At the beginning of a stressed syllable (attain, until). This includes secondary stress. In a dictionary, secondary stress is marked with this: ˌ Primary stress is marked with this: ˈ + - Exception: when it’s followed by R (attribute, attract) + +### Stop T + +- How to make a Stop sound: Stop T vs. No T: Buy vs. bite +- Stop T Rule 1: When the T is followed by a consonant sound (definitely, bluntly) 后面接辅音 + - Exception: when the sound before the T is an R. Then it’s a Stop T (partly) : r+t+辅音 ,t不变 +- Stop T Rule 2: Make the T a Stop T when it’s the last sound in a thought group. :意群结尾 + - Exception: when the T is in a cluster, then we usually pronounce it (fact, best) : + + + +如果后面 是元音或者双元音 或者是意群的结尾,t就发音。可能是flap T, stop T + +### Flap T + +> [参考](https://www.goalsenglish.com/lessons/flap-t-sound-american-english-accent) + +- 类似d的发音 +- 发生flap T情况 + - Flap T Rule 1: a T is a Flap T between two vowels or diphthongs (beautiful, city) 元音间 If a ‘t’ is between two vowels, whether in a word or between two words, it will be pronounced as a ‘soft d.’ + - Exception: If the T begins a stressed syllable. Then it’s a True T (attain, attack) 重音上 + - Flap T Rule 2: a T is a Flap T after an R before a vowel or diphthong (party, dirty). Applies to linked phrase: (a lot of, about it) + - Exception: if the T begins a stressed syllable. Then it’s a True T (partake) + +例子 + +- it always + +### Drop T + +- Dropped T Rule 1: T can be dropped after N (center, internet) nt的t会省略 + - Exception: when there is a syllable split between N and T (until, intense) +- Dropped T Rule 2: Americans often drop the T between two other consonants (exactly, perfectly). This applies to phrases where two words link (just because) + - Exception: Not when the consonant before the T is an R (partly) + +例子 + +- shouldn't, didn't,won't + +### 总结 + +t前面是n? drop T + +t前面是辅音? + +- 后面是辅音? drop T +- 后面是元音? stop T + +t前面是元音? + +- 后面是元音? flap T +- 后面是辅音? drop T + +t是意群结尾? Stop T. p也类似。 + +只有两个元音间的t是d,否则stop / drop + + + +杂记: + +t+辅音里的t省略, 其实是停顿,但和省略差不多 + +nt比较特殊: nt+元的t省略, nd+辅的d省略 + +## /d/发音 + +nd+辅的d省略 + +## 重读和弱读 + +### 重读 + +**一般来讲我们应该重读content words, 就是有实际内容、实际意义的词**,例如:名词,实义动词,形容词,副词,数量词。名词方面,比如像mountain, history等;实义动词就是真正发出动作的词,比如像establish, jump等;形容词比如像stunning, terrifying这样的词;副词方面比如quickly, extremely等。这些词都是有实际意义的,也就是我所说的内容词,来表达句子意义的词,所以我们应该把它们做重读的处理。 + + + +**一般来讲哪些单词不重读,就是function words功能词,即那些起到语法功能作用的词,**比如像代词,介词,限定词,连词以及助动词等等,都是语法结构会运用到的词,这些词对句子的意义并不构成直接的影响。什么样的词属于限定词,比如像冠词the, a/an; some, few, my都是限定词;助动词像be动词,be, do, must这些都属于助动词;介词after, of, above, opposite, out of, on behalf of这些有介词意义的短语也包括在内。还有像连词,比如and, so, 还有代词this, him, our, you, it, 这些词在句子当中是起到语法意义的词。 + + + +总结: 重读的只有副词、名词、形容词、动词。但content words有时也不会重读,如果还有其他的重读的词的话。 + + + +### 弱读 + +1、重读的单词不会出现弱读现象,要读的响亮 + +这些词一般是表示句子含义的词,如名词,动词,副词,形容词 (today 今天, apple 苹果) + + + +2、非重读的部分的单词要读轻 + +这些词一般起到语法功能,如介词、连词、助动词等 (and 和, but但是,for为了) + + + + + +弱读现象存在于句子的非重读单词部分 + +对于句子非重读部分的单词 + +1、如果有弱读发音,就可以进行弱读 + +2、如果没有弱读发音,发本来的音即可 + + + +不能弱读情况 + +1、句子最后一个单词不能弱读 + +2、特意强调的单词不能弱读,要重读 + + + +## 英音美音区别 + +todo + + + +## 其它 + +> 视频: https://www.bilibili.com/video/BV1SZ4y1K7Lr?p=6&spm_id_from=pageDriver + +- 元音挨着元音不容易读,所以才会区分a和an +- 同化&异化 + - 同化:前面音 改变 + - 常见爆破音: k,t,d, 后加辅音,前面音发一半,也叫失去爆破。 + - 浊音变清音,比如have to, of course, 的v变f. + - inperson读imperson, n->m,嘴唇闭合。 + - 同化:后面音 改变 + - 比如变复数读音 + - 相互作用 + - s+j: bless you. z+j:as you wish. t+j: meet you. d+j: did you. 类似的educate, tissue. + - 辅音连读 + - 异化, r接元音会读r, 否则不发音 +- 省音: t,d。 来自其他视频,**t+辅音里的t省略,nt+元的t省略, nd+辅的d省略** +- 节奏: 等时性。 diff --git "a/_posts/English/2021-01-02-\350\257\255\346\263\225-\345\215\225\350\257\215\345\220\204\347\247\215\345\275\242\345\274\217\345\217\230\345\214\226\350\247\204\345\210\231.md" "b/_posts/English/2021-01-02-\350\257\255\346\263\225-\345\215\225\350\257\215\345\220\204\347\247\215\345\275\242\345\274\217\345\217\230\345\214\226\350\247\204\345\210\231.md" index add11756d2..95c5f8eeb9 100644 --- "a/_posts/English/2021-01-02-\350\257\255\346\263\225-\345\215\225\350\257\215\345\220\204\347\247\215\345\275\242\345\274\217\345\217\230\345\214\226\350\247\204\345\210\231.md" +++ "b/_posts/English/2021-01-02-\350\257\255\346\263\225-\345\215\225\350\257\215\345\220\204\347\247\215\345\275\242\345\274\217\345\217\230\345\214\226\350\247\204\345\210\231.md" @@ -17,7 +17,7 @@ tags: English ![image-20210102200549238](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv1/v1/134.png) -这里的辅音字母指除元音字母aeiou之外的字母,非音标发音指写法。 +下面的辅音字母指除元音字母aeiou之外的字母,非音标发音指写法。 **名词所有格's 的读音与名词复数和动词第三人称单数相同** diff --git "a/_posts/English/2021-01-02-\350\257\255\346\263\225-\350\231\232\346\213\237\350\257\255\346\260\224.md" "b/_posts/English/2021-01-02-\350\257\255\346\263\225-\350\231\232\346\213\237\350\257\255\346\260\224.md" index f515388fe4..0f909e5f97 100644 --- "a/_posts/English/2021-01-02-\350\257\255\346\263\225-\350\231\232\346\213\237\350\257\255\346\260\224.md" +++ "b/_posts/English/2021-01-02-\350\257\255\346\263\225-\350\231\232\346\213\237\350\257\255\346\260\224.md" @@ -107,3 +107,34 @@ if only(要是……就好了)与I wish一样,也用于表示与事实相 例2:In the absence of gravity, there would be no air around the earth.(如果没有重力,地球上不会有空气) + + +**6. It's time that** + +it is time that +从句,从句要用虚拟语气,有两种方式: + +1、从句用作一般过去时 + +例:It is time that we went to bed.我们该上床睡觉了。 + +2、从句用should+动词原形不能省略 + +例:It is time that we should go to bed.我们该睡觉了。 + + + + + +## should省略 + +1. 在表示建议,要求,命令,想法的动词后的从句里, 用should + 动词原形, should 可以省略. + +His doctor suggested that he (should) take short leave of absence. + +2. 在表示建议,要求,命令,想法的名词后的从句里, 用should + 动词原形, should可以省略. 如 advice, decision,agreement, command, decree, demand, determination, indication, insistence, order, preference, proposal, request, requirement, stipulation etc. + +His suggestion was that everyone (should) have a map. + +3. 在It is/was +形容词后的that 从句中用should的结构, should 可以省略. 这类形容词常见的有: advisable, anxious, compulsory, crucial, desirable, eager, essential, fitting, imperative(绝对必要), impossible, improper, important, natural, necessary, obligatory, possible, preferable, probable, recommended, urgent, vital etc. + It‘s natural that she (should) do so. + diff --git "a/_posts/English/2021-10-15-\350\256\241\347\256\227\346\234\272\350\213\261\350\257\255.md" "b/_posts/English/2021-10-15-\350\256\241\347\256\227\346\234\272\350\213\261\350\257\255.md" index 645aafd0ad..af6477aff5 100644 --- "a/_posts/English/2021-10-15-\350\256\241\347\256\227\346\234\272\350\213\261\350\257\255.md" +++ "b/_posts/English/2021-10-15-\350\256\241\347\256\227\346\234\272\350\213\261\350\257\255.md" @@ -7,197 +7,81 @@ tags: English ## 计算机英语 -单词: https://www.cnblogs.com/along21/p/8075668.html - -## 雇佣关系词汇 - -Employee: 员工, 包括普通雇员, 和有限公司的股东成员 -Employer: 老板(无限公司) -Own account workers: 要申请ABN, 多见于服务业,cleaner, plumber, 某些IT从业人员。 -Family workers: 在家族企业,且没有酬劳。 - -Full time, 也叫 permanent, 全职员工, 福利最好, 但是相应的时薪可能比较低。 福利包括, 带薪年假, 带薪病假,带薪事假,带薪育儿假,带薪公共假期, 长期服务奖励假(**Long service leave** ) , 以及彼此至少一个月的提前通知终止合同的缓冲期, 如果是公司裁退, 补贴n个月薪的补偿(为公司工作n年)。 - -Part time, 和Full time 类似, 不过不是5天工作制, 按照合同, 每星期工作4天或更少。 其他福利类似Full time。 - -casual, temporary, 小时工, 工钱按时薪算, 彼此可以随时终止合同。 无带薪假。 - -contractor, -fixed term, 合同工, 有固定的结束期限, 可能有部分福利如 带薪年假, 带薪病假,带薪事假,带薪育儿假,带薪公共假期。 具体要看合同的条款。 - -self-employed, sole trader, 要自己申请ABN, 和公司属于合作关系,而不是雇佣关系。 提供服务以换取酬劳, 如cleaner, plumber, 某些IT从业人员等。 - -partner, trust, company , 属于生意范畴 - -cash in hand, 非法现金工。 官方网上没有说明, 不过大家都知道怎么回事。 - -Apprenticeships and traineeships就是所谓的学徒, 有些工种需要满足一定期限的学徒期, 才能独自单干。 - -## 个人单词本 - -乐观的 optimistic - -悲观的 pessimistic - -熔断 circuit breaker circuit[/'sɝkɪt/](cmd://Speak/_us_/circuit) 电路 - -限流 rate limiting [/reɪt/](cmd://Speak/_uk_/rate) - -降级 fallback,n. degrade [/dɪ'greɪd/](cmd://Speak/_uk_/degrade), v. degration. - -服务发现 service discovery. - -负载均衡 load balance - -访问控制列表ACL: access control list - -可靠性: reliance, 可用的: reliable - -一致性: consistency - -最终一致性: eventually consistency [/ɪ'ventʃʊəlɪ/](cmd://Speak/_uk_/eventually) - -隔离: isolation [/aɪsə'leɪʃ(ə)n/](cmd://Speak/_uk_/isolation) - -连接池: connection pool [/puːl/](cmd://Speak/_uk_/pool) - -鉴权: authentication [/ɔ:,θenti'keiʃən/](cmd://Speak/_us_/authentication) - -计数器法: counter method - -滑动窗口: sliding window - -滚动的: rolling [/'rəʊlɪŋ/](cmd://Speak/_uk_/rolling) - -流量: traffic - -漏桶: Leaky Bucket [美 /'liki/](cmd://Speak/_us_/leaky)令牌桶: token bucket - -轮询,探询: poll [ /pəʊl/](cmd://Speak/_uk_/poll) - -延迟: delay - -定时器: timer, 任务定时调度: task scheduler - -定时的: timed - -时间轮: wheeltimer - -优先的: prior [/'praɪə/](cmd://Speak/_uk_/prior) - -circular [/'sɜːkjʊlə/](cmd://Speak/_uk_/circular)环形的,circuit环形vi, 电路。 - -缓冲 buffer - -层 level - -层级 hierarchy 分层的 hierarchical [美 /'haɪərɑrki/](cmd://Speak/_us_/hierarchy) - -灵活的 flexible - -线程安全 thread safety - -attribute 美 /ə'trɪbjut/ - -boolean - -atomic - -assign - -aspect - -ratio - -scale - -access - -represent - - - -发音不准的: feature, module, +计算机相关英语 +## 数学符号 +> [参考](https://www.sohu.com/a/214664854_200286) -## 计算机英语 - -> [参考](https://guanpengchn.github.io/awesome-pronunciation/content/L.html) - -access - -admin - -agile +介词: plus, minus. -alias [ˈeɪliəs] +the sum a plus b. the difference a minus b. -archive ['ɑːkaɪv] +动词: times, is divided by -array +equals. -aspect +括号 小到大: parentheses [/pə'rɛnθəsɪz/](cmd://Speak/_uk_/parentheses), bracket, brace. -avatar [/'ævətɑr/] +绝对值: absolute value of a -Azure +幂: a**n, a to the power of n, a super n, a to the n. -char +上角标: a superscript b,可以直接诶读a super b. -console +下角标: a sub b. -ctrl +符号英文: operator. -Daemon ['diːmən] +log: log2a, log to the base 2 of a -deque ['dek] +开根号: nth root of a. -event +since, because, implies. equivalent. -facade [fə'sɑːd] 外观模式 +区分括号: the quantity xx end of quantity. -hidden ['hɪdn] +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211208123506.jpeg) -hystrix +部分, 指分数, that fraction. -icon ['aɪkɑn] +分数: a over b. -image ['ɪmɪdʒ] +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211208123621.jpeg) -integer ['ɪntɪdʒə] +平方: square 立方: cube -Java ['dʒɑːvə] +p(x) 读p of x. -linear ['lɪnɪə] -locale [ləʊ'kɑːl] -Lucene [ˈlu:sɪn] +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211208123729.jpeg) -matrix [ˈmeɪtrɪks] -module ['mɒdjuːl] -nginx ['endʒɪn eks] +## 雇佣关系词汇 -parameter [pə'ræmɪtə] +Employee: 员工, 包括普通雇员, 和有限公司的股东成员 +Employer: 老板(无限公司) +Own account workers: 要申请ABN, 多见于服务业,cleaner, plumber, 某些IT从业人员。 +Family workers: 在家族企业,且没有酬劳。 -replica [ˈreplɪkə] +Full time, 也叫 permanent, 全职员工, 福利最好, 但是相应的时薪可能比较低。 福利包括, 带薪年假, 带薪病假,带薪事假,带薪育儿假,带薪公共假期, 长期服务奖励假(**Long service leave** ) , 以及彼此至少一个月的提前通知终止合同的缓冲期, 如果是公司裁退, 补贴n个月薪的补偿(为公司工作n年)。 -scale +Part time, 和Full time 类似, 不过不是5天工作制, 按照合同, 每星期工作4天或更少。 其他福利类似Full time。 -scheme [skiːm] 方案体系 +casual, temporary, 小时工, 工钱按时薪算, 彼此可以随时终止合同。 无带薪假。 -sudo [ˈsuːduː] +contractor, +fixed term, 合同工, 有固定的结束期限, 可能有部分福利如 带薪年假, 带薪病假,带薪事假,带薪育儿假,带薪公共假期。 具体要看合同的条款。 -suite [swiːt] +self-employed, sole trader, 要自己申请ABN, 和公司属于合作关系,而不是雇佣关系。 提供服务以换取酬劳, 如cleaner, plumber, 某些IT从业人员等。 -variable ['veərɪəbl] +partner, trust, company , 属于生意范畴 -width [wɪdθ] +cash in hand, 非法现金工。 官方网上没有说明, 不过大家都知道怎么回事。 -YouTube ['juː'tjuːb] +Apprenticeships and traineeships就是所谓的学徒, 有些工种需要满足一定期限的学徒期, 才能独自单干。 @@ -267,51 +151,69 @@ register ['redʒistə]暂存器 寄存器 syntax ['sintæks]语法 语法 -## 数学符号 +## 编程单词2 -> [参考](https://www.sohu.com/a/214664854_200286) +单词: https://www.cnblogs.com/along21/p/8075668.html -介词: plus, minus. -the sum a plus b. the difference a minus b. -动词: times, is divided by +## 算法面试中常用英语 -equals. +first, the input is head of linkedlist, -括号 小到大: parentheses [/pə'rɛnθəsɪz/](cmd://Speak/_uk_/parentheses), bracket, brace. -绝对值: absolute value of a -幂: a**n, a to the power of n, a super n, a to the n. +First, the naive idea that should not be considered is we can solve it in an exhaustive approach. -上角标: a superscript b,可以直接诶读a super b. +better idea, -下角标: a sub b. -符号英文: operator. -log: log2a, log to the base 2 of a +how to optimize it -开根号: nth root of a. -since, because, implies. equivalent. -区分括号: the quantity xx end of quantity. +use a map to record next value, -![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211208123506.jpeg) +define A as the map -部分, 指分数, that fraction. +we can get the map that I mentioned, by one loop, -分数: a over b. -![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211208123621.jpeg) -平方: square 立方: cube -p(x) 读p of x. +### Key Points +- each针对个体,every强调共性。 +- shift是整体转移,常用move,move to the right. +- 最左的leftmost, rightmost, 最多最大most, 最少最少least, maximum number +- using the sliding window technique. shrink 收缩 +- brute force, approach +- subtract 扣除、减去 +- intuition 直觉 +- sort the list by the starting position. +- build the prefix sum array to xxx +- 遍历 traverse +- 一个循环for loop 嵌套循环 two nested loops. +- linearly search 线性地查找 in O(n) time. +- given its staring position s, we know that the furthest position that can over is s+e. Having the furthest positon, we binary search the index of ending xxxx. +- Note that in this step, we greedily align xx with xxx +- at last 最后 +- indices 是index的复数 +- look for,in the forward direction. +- 比数量多少: less than/ more than 多少,least = 最少的, most = 最多的 +- 比值大小: 最大的greatest, 最小的smallest, smarller than/greater than 比大小。最大也可以Largest, 不过不标准Largest implies size, but greater implies value. +- 至少包含一个includes at least one +- track跟踪 track whether +- trim 修剪, encounter遇到 +- roughly粗略地 大概地 +- left side. the extreme end of +- within [a,b] 区间内 -![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211208123729.jpeg) + +### 例题 + +- [6068. 毯子覆盖的最多白色砖块数](https://mafulong.github.io/2022/05/15/6068.-%E6%AF%AF%E5%AD%90%E8%A6%86%E7%9B%96%E7%9A%84%E6%9C%80%E5%A4%9A%E7%99%BD%E8%89%B2%E7%A0%96%E5%9D%97%E6%95%B0/) +- [6069. Substring With Largest Variance](https://mafulong.github.io/2022/05/15/6069.-Substring-With-Largest-Variance/) \ No newline at end of file diff --git "a/_posts/English/2021-12-09-English\345\255\246\344\271\240\350\265\204\346\272\220.md" "b/_posts/English/2021-12-09-English\345\255\246\344\271\240\350\265\204\346\272\220.md" deleted file mode 100644 index f9712561c9..0000000000 --- "a/_posts/English/2021-12-09-English\345\255\246\344\271\240\350\265\204\346\272\220.md" +++ /dev/null @@ -1,23 +0,0 @@ ---- -layout: post -category: English -title: English学习资源 -tags: English ---- - -## English学习资源 - -计算机英语部分参考另一个博客 - -## English-level-up-tips-for-Chinese - -网址:https://github.com/byoungd/English-level-up-tips-for-Chinese - -## github上“读”北大(北大课程资料民间整理) - -网址:https://lib-pku.github.io/ - -github:https://github.com/lib-pku/libpku - - - diff --git "a/_posts/English/2021-12-11-English\350\257\255\346\263\225.md" "b/_posts/English/2021-12-11-English\350\257\255\346\263\225.md" deleted file mode 100644 index 49c0659b8b..0000000000 --- "a/_posts/English/2021-12-11-English\350\257\255\346\263\225.md" +++ /dev/null @@ -1,76 +0,0 @@ ---- -layout: post -category: English -title: English Grammmar -tags: English ---- - -[语法顺口溜](https://zhuanlan.zhihu.com/p/146873536) - -## 单词 - -[语法-单词各种形式变化规则](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E5%8D%95%E8%AF%8D%E5%90%84%E7%A7%8D%E5%BD%A2%E5%BC%8F%E5%8F%98%E5%8C%96%E8%A7%84%E5%88%99/) - -## 介词 - -参考:https://wenku.baidu.com/view/d6be381d747f5acfa1c7aa00b52acfc789eb9fad.html - - - -介词: - -年月周前要用 in, - -日子前面却不行。 - -遇到几号要用“on”, - -上午下午又是“in”。 - -要说某日上下午, - -用 on 换 in 才能行。 - -午夜黄昏用 at, - - - -## 从句 - -[三大从句](https://mm.edrawsoft.cn/template/39526) - -[四级语法: 从句](https://mm.edrawsoft.cn/template/57209) - -从句时态: - -1. **主将从现** - -i will hit u when you come here - -if it rains, i will hit u. - -2. **主过从过** - -复合句有先后关系,过去+过去完成时, eg. when he came there, the train had gone. - -3. **主现从任** - -he tells me that u have died - -## 疑问句 - -[参考个人单独blog](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E7%96%91%E9%97%AE%E5%8F%A5/) - - -## 时态 - -[参考个人单独blog](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E6%97%B6%E6%80%81/) - -## 倒装 - -[参考个人单独blog](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E5%80%92%E8%A3%85%E5%8F%A5/) - -## 虚拟语气 - -[参考个人单独blog](https://mafulong.github.io/2021/01/02/%E8%AF%AD%E6%B3%95-%E8%99%9A%E6%8B%9F%E8%AF%AD%E6%B0%94/) - diff --git "a/_posts/English/2021-12-11-\345\215\225\350\257\215-\345\270\270\347\224\250\350\276\250\346\236\220.md" "b/_posts/English/2021-12-11-\345\215\225\350\257\215-\345\270\270\347\224\250\350\276\250\346\236\220.md" new file mode 100644 index 0000000000..8ee9fe5072 --- /dev/null +++ "b/_posts/English/2021-12-11-\345\215\225\350\257\215-\345\270\270\347\224\250\350\276\250\346\236\220.md" @@ -0,0 +1,134 @@ +--- +layout: post +category: English +title: 单词-常用辨析 +tags: English +--- + +### till和until + +没区别 口语两个都行。until正式。 + +两者在用法上应注意以下几点: + +**1.** 相关主句谓语必须是持续性动词,若是终止性动词,则应为否定式(因为终止性动词一旦被否定就成为状态,便可持续)。如: + +We waited until [[till](http://www.yywords.com/)] he came. 我们一直等到他来。 + +We didn’t leave [until](http://www.yywords.com/) [till] he came. 直到他来我们才走。 + +**2.** 引导时间状语从句时,其谓语要用现在时表示将来意义。如: + +I won’t leave [until](http://www.yywords.com/) he comes back tomorrow. 我要等他明天回来再走。 + +**3.** 有时其后可跟副词、[介词](http://www.yywords.com/Article/200810/542.html)短语或从句等。如: + +He has been ill until recently. 他最近一直生病。 + +She didn’t return until after twelve o’clock. 直到 12 点过后她才回来。 + +They didn’t reach the station until after the train had left. 直到火车开走之后,他们才到达车站。 + +[Until when](http://www.yywords.com/) are you going to stay here? 你在这儿要待到什么时候? + + + +### 影响 + +**影响英文怎么说? 动词affect, 名字effect,非常大影响用impact。** **少用influence**, influence 会比较偏向是「思想上的影响」,会影响某个人的想法、意见、发展,或是决定,比如我们常会说「某个人影响我成为⋯⋯」、「某个人影响⋯⋯的发展」,这些就比较会使用 influence,而不是 affect。*My dad influenced me to be a teacher.* + + + +### 组成 + +**consist of xxx** + +**be composed of** + + + +组成和构成 + +https://xue.youdao.com/bbs/wenda/answer_detail?id=5499819 + +comprise, constitute, compose, consist of + + + +Consist 的用法是 consist of,要注意这个字不会使用被动语态,所以并没有 be consisted of (X) 的用法喔,直接说“整体 consist of 部分”就可以了 + +*Our team consists of the best players in the nation.* + + + +Comprise 同样是指“组成、构成”,但 **comprise 是个比 consist 更正式一点的字**,而且 comprise 主动及被动语态用法可以用,所以可以是“整体 comprise 部分”,也可以是“整体 be comprised of 部分” + + + +Compose 是个更正式的字,它的用法是**“整体 be composed of 部分”**,当做“由...组成”的意思时,只有被动用法喔 + +### wait + +是否加for,是sb/sth就加,如果是时间就不用加 + +wait也可以加to. I can't wait to do..等不及做 + +**当你想表达:** + +**1) 等谁?(who)** + +**2) 等什么?(what)** + +wait需要加for + +wait for sb/sth。 + +- She waits for the bus. +- You need to wait here for me. + + + + + +**1)等多久?(how long)** + +**2)在哪里等?(where)** + +wait不加for + +- Wait a minute. + +### 可能 + +用maybe一般 + +probably表示有把握发生。语气比possibly大。 + + + +[maybe](dic://maybe) 普通用词,美国英语多用。指某事也许如此,含不能确定意味。 +[perhaps](dic://perhaps) 普通用词,多用于英国,与maybe同义。 +[possibly](dic://possibly) 指客观上潜存着发生某种变化的可能。 +[probably](dic://probably) 一般指根据逻辑推理,估计有发生的可能,把握性较大,语气比possibly强。 + +### 常用错 + +> [中国程序员最容易犯的100个英语口语错误](https://github.com/eliaszon/Common-English-Mistakes-By-Chinese) + +How do you say xxx in English. + +I see. + +Do you get what I'm saying? / You get me? / Am I making sense? / Does this make sense? / Are we on the same page? + +I'm not feeling too good / I'm feeling (a little bit) under the weather + +reply me 有语法错误,要加 to ,reply to me + +weird 更常用,odd 不太常用 ( That's a little bit weird ) + +How much is something? (问价钱) + +你方便吗 You got a minute? / Are you available right now? / Are you free? 不要用Are you convenient? convenient 一般针对事物、地点,不是针对人的 + +Can you speak louder? / Can you speak up? \ No newline at end of file diff --git "a/_posts/English/2021-12-11-\345\215\225\350\257\215-\345\270\270\350\257\273\351\224\231.md" "b/_posts/English/2021-12-11-\345\215\225\350\257\215-\345\270\270\350\257\273\351\224\231.md" new file mode 100644 index 0000000000..67b7531b96 --- /dev/null +++ "b/_posts/English/2021-12-11-\345\215\225\350\257\215-\345\270\270\350\257\273\351\224\231.md" @@ -0,0 +1,142 @@ +--- +layout: post +category: English +title: 单词-常读错 +tags: English +--- + +## 常读错 + +boolean 美 /ˈbuliən/ + +atomic + +**assign** 美 /əˈsaɪn/ + +aspect 美 [美 /ˈæspekt/](cmd://Speak/_us_/aspect) + +ratio 美 /ˈreɪʃioʊ/ + +scale + +access 美 /ˈækses/ + +represent 美 /ˌreprɪˈzent/ + +feature 美 /ˈfiːtʃər/ + +module + + + + + +admin 美 /'ædmɪn/ + +agile 美 /ˈædʒl/ + +Scrum [美 /skrʌm/](cmd://Speak/_us_/scrum) + +alias [ˈeɪliəs] + +archive [‘ɑːkaɪv] + +array + +avatar [/’ævətɑr/] + +Azure + +char 美 /tʃɑːr/ + +console + +ctrl + +Daemon [‘diːmən] + +deque [‘dek] + +queue 美 /kjuː/ + +**event** (i wan t) 争议。请继续i wen t. + +facade [fə’sɑːd] 外观模式 + +hidden [‘hɪdn] + +hystrix + +icon [‘aɪkɑn] + +image [‘ɪmɪdʒ] + +integer [‘ɪntɪdʒə] + +Java [‘dʒɑːvə] + +linear [‘lɪnɪə] + +locale [ləʊ’kɑːl] + +Lucene [ˈlu:sɪn] + +**matrix** [ˈmeɪtrɪks] + +nginx [‘endʒɪn eks] + +**parameter** [pə’ræmɪtə] + +replica [ˈreplɪkə] + +scheme [skiːm] 方案体系 + +sudo [ˈsuːduː] + +suite [swiːt] *a suite of* 一系列 + +variable 美 /ˈveriəbl/ + +width [wɪdθ] + +YouTube [‘juː’tjuːb] + +timer 美 /'taɪmɚ/ 定时器 + +formal 美 /ˈfɔːrml/ + +Intrusive 侵入的 美 /ɪn'trusɪv/ + +**redundant** 冗余的 美 /rɪˈdʌndənt/ + +Diversity 美 /daɪˈvɜːrsəti/ + +utilize 美 /ˈjuːtəlaɪz/ + +execute 美 /ˈeksɪkjuːt/ execution + +via 美 /ˈvaɪə/ 经由,通过;凭借,借助于 + +prepare . (p pai r) + +preparation 美 /ˌprepəˈreɪʃn/ + +obviously obvious [美 /ˈɑːbviəs/](cmd://Speak/_us_/obvious) 开头不是e. 是ao 明显的 + +**curious** 好奇的 [美 /ˈkjʊriəs/](cmd://Speak/_us_/curious) + +equally 美 /ˈiːkwəli/ + +obey 美 /əˈbeɪ/ obey rules + +**again** 美 /ə'ɡɛn/ + +occasionally 美 /əˈkeɪʒnəli/ + +Library 库 [美 /'laɪbrɛri/](cmd://Speak/_us_/library) + +Horizontally [美 /ˌhɑrɪˈzɑntəlɪ/](cmd://Speak/_us_/horizontally) Vertically + + + +provide [美 /prə'vaɪd/](cmd://Speak/_us_/provide) 注意 不是p rao. 是p re \ No newline at end of file diff --git "a/_posts/English/2022-08-26-\345\215\225\350\257\215-\350\277\236\350\257\215.md" "b/_posts/English/2022-08-26-\345\215\225\350\257\215-\350\277\236\350\257\215.md" new file mode 100644 index 0000000000..a104de79c8 --- /dev/null +++ "b/_posts/English/2022-08-26-\345\215\225\350\257\215-\350\277\236\350\257\215.md" @@ -0,0 +1,610 @@ +--- +layout: post +category: English +title: 英语-连词 +tags: English +--- + +# 连词 + + + +## 不仅而且Not only but also + +[参考](https://en-grammar.xiao84.com/201612/27635.html) + +比较自由。also可省略, but also之间也可以加词。 + +可连接主语、谓语动词... + +The Americans and the British **not only** speak the same language **but also** share a large number of social customs. + + + +Note: + +- ”not only A but also B”结构中的A和B通常是同等成分。因此这句话是错误的“He not only plays the piano, but also the violin.” 可以改成“He plays **not only** the piano, but also the violin” + +## 也(too, as well, also, either) + +too和as well两者都可用在肯定句或疑问句的句末。两者通常可以换用。 + +She likes pizza as well. + +=She likes pizza too. + + + +- also: 常在**肯定句句中** +- too: 常在**肯定句句末**,前面常有逗号 +- either: 常在**否定句句末** He isn't a singer either. + + + +来自欧陆词典: + +[also](dic://also) 比too正式一些,语气较重,只用于肯定句,一般紧靠动词。 +[too](dic://too) 语气较轻,多用于口语,在肯定句中使用,通常位于句末。 +[as well](dic://as well) 一般不用否定句,通常放在句末,强调时可放在句中。 +[either](dic://either) 用于否定句,放在句末,之前加逗号。 +[likewise](dic://likewise) 是书面语用词。 + + + +也不nor + +He can't speak english, **nor** can I. + +## 除了 + +I did **nothing but** watch it + +## 然而 + +whereas + +Some praise him, **whereas** others condemn him + + + +## 尽管 + +**Although** she's young, she knows a lot. + +In spite of sth + +Despite sth + +## 只要 + +As long as I'm free, I will help you. + +**only if (连词)只有** + +The lawyer is paid only if he wins. + +当且仅当: if and only if xx + +## 要是xx就好了 + +if only + +There had to be an answer — he was sure he could tease it out if only he had time. + +## 以免 + +in case + +You should be careful **in case** there's a fire. + +## 为了 + +We study hard in order that we can pass the team. + + + +## 刚一。。。就。 + +推荐as soon as. + +**As soon as** I stepped inside,my glasses misted over. + +The stars came out **as soon as** darkness fell. + + + +**Hardly** I entered the room **when** the bell rang. + +**No sooner** had I come home **than** it began to rain. + +**Scarcely** had she entered the room **when** the phone rang. + +## 既然现在 + +**Now that** you are on duty, you should clean the classroom. + +## 无论 + +**Whether** you are sick **or** not, I'll help you. + +**No matter** how bad the weather is, the children will play foot-ball on the playground, not with standing + +**No matter** what it takes I will do the work. + +**Whatever** the reason, just hang in there. + +## 而不是 + +They relied on brains **rather than** brawn + +He preferred to die **instead of** stealing. + +## 尽可能地快 + +as soon as possible, soon: *adv.* 不久;即刻,马上 + +We must correct our defects **as soon as possible.** + +as quickly as possible. + +## 如果...将会怎么样? + +**What if** the car breaks down? + + + +## 15类英语连接词 + +> 参考:整理分享15类英语连接词,超级全。https://zhuanlan.zhihu.com/p/277394043 +> + +### 表示强调 + +still 然而,仍然 + +indeed 事实上 + +apparently 显然 + +oddly enough 奇怪的是. weird enough也行。It is weird enough that you live on the mantel. + +of course 当然 + +after all 终究 + +significantly 明显地;显著地 obviously + +interestingly 有趣的是 + +also 并且,另外 + +surely 肯定/必定地 + +certainly 无疑地; 确定地 I certainly treasure the friendship between us very much. + +undoubtedly 毫无疑问地 + +in any case 在任何情况下;无论如何 + +anyway 反正;不管怎样;总之 + +above all 首先,尤其是;最重要的是 + +in fact 事实上 + +especially 特别是 + +obviously 很明显 [ /'ɑbvɪəsli/](cmd://Speak/_us_/obviously) + +clearly 无疑的 + +例:In fact, he is not an honest man. + +事实上,他不是个诚实的人。 + + + +### 表示比较 + +like 就像 + +similarly 类似的 be similar to + +likewise 同样的;照样的 副词。Likewise, under the papalism in the middle ages of West, papacies dominate was the leading. + +in the same way 以同样的方式 + +in the same manner 以类似的方式 + +equally 同样地;相等程度地 + +例:I will help you solve this problem, but equally you need to give me some reward. + +我会帮你们解决这个问题,但是同样地,你们需要付出一些回报。 + + + +### 表示对比 + +by contrast 相比之下 + +on the contrary 相反 + +while 而;虽然,尽管 + +whereas 而 + +on the other hand 另一方面 + +unlike 不像 + +instead 而不是;而;相反 + +but 但 + +conversely 相反 + +different from 不同于 + +however 然而 + +nevertheless 不过 + +otherwise 否则 + +yet 然而, 但是 + +in contrast 与此相反;比较起来 + +例:On the other hand, they are also unwilling to adopt our advice. + +另一方面,他们也不愿意采纳我们的建议。 + + + +### 表示列举 + +for example 例如 + +for instance 例如 + +such as 如 + +take …for example 以……为例 + +except (for) 要不是由于 *except for* 除了…以外;要不是由于 + +to illustrate 为了说明(举例说明) + +例:We bought some fruits such as apples, oranges and pears. + +我们买了一些水果,有苹果橘子还有梨。 + + + +### 表示时间 + +later 后来;稍后;随后 + +next 然后;其次;接下来;下一... + +then 然后 + +finally 最终终于 + +at last 最后 + +eventually 最终 [ɪ'vɛntʃuəli/](cmd://Speak/_us_/eventually) + +meanwhile 与此同时 + +from now on 从现在开始 I have made up my mind not to go skating from now on. 我决心从此不再去滑冰. + +at the same time 同时 + +for the time being 暂时 adv + +in the end 最后 + +immediately 立即 + +in the meantime 在此期间;于此际;与此同时 + +in the meanwhile 同时;在此期间 + +recently 最近 + +soon 很快 + +now and then 偶尔;有时;不时 occasionally + +during 在…...的期间;在......期间的某个时候 The pond iced over during the night. + +nowadays 如今 + +since 自……以后;自……以来;此后;之前 + +lately 最近 + +as soon as 一旦 + +afterwards 后来 + +temporarily 暂时 + +earlier 早些时候 + +now 现在 + +after a while 不久;过了一会儿 + +例:She answered the question immediately. + +她迅速回答了这个问题。 + + + +### 表示顺序 + +first 首先,第一 + +second 第二 + +third 第三 + +then 然后 + +finally 最后 + +to begin with 首先,本来,一方面 To begin with, we must consider the faculties of the staff all-sidedly. + +first of all 首先 + +in the first place 首先 + +last 最后 + +next 下一个 + +above all 最重要的是 + +last but not the least 最后一点,也是非常重要的一点 + +first and most important 第一点也是最重要的一点 + +例:First of all, you should obey rules as a student. + +作为一个学生,首先你要遵守学校里的规章制度。 + + + +### 表示可能 + +presumably 大概 + +probably 可能 + +perhaps 也许 + +例:Perhaps he will not show up today. + +他今天可能不会露面了。 + + + +### 表示解释 + +in other words 换句话说 + +in fact 事实上 + +as a matter of fact 事实上 + +that is 即;就是说;换言之 + +namely 也就是;即是;换句话说 Namely, a return to white supremacy and institutional slavery. + +in simpler terms 简单来说 **To put it simply**, everything happens instantaneously. **In short,** the building would consist of two floors. + +例:He departed from his hometown, namely, London. + +他离开了自己的故乡,也就是伦敦。 + + + +### 表示递进 + +What is more 更重要的是;此外,而且 + +in addition 另外,此外 + +and 并且,以及 + +besides 况且,再说;此外,以及 + +also 而且;同样;还有 + +furthermore 此外 + +too 也;还 + +moreover 此外;而且 + +as well as 以及 + +additionally 另外 + +again 再说;又 + +例:Susan is a beautiful girl, what is more, she works hard all the time. + +苏珊是个漂亮的女孩,而且,她也一直努力工作。 + + + +### 表示让步 + +although 虽然 + +after all 毕竟 + +in spite of …尽管…… + +despite 尽管 + +even if 即使 + +even though 尽管 + +though 虽然 + +admittedly 不可否认 + +whatever may happen 不管三七二十一 + +例:Although you told a lie before, we believe in you now. + +虽然你以前说过谎,但我们现在相信你。 + + + +### 表示转折 + +however 然而 + +rather than 而不是;宁可…也不愿 + +instead of 而不是... + +but 但 + +yet 然而 + +on the other hand 另一方面 + +unfortunately 不幸的是 + +whereas 然而;鉴于; 反之 + +例:However, he did not pass the exam. + +然而,他没有通过考试。 + + + +### 表示原因 + +for this reason 因为这个原因 + +due to 由于 + +thanks to 多亏了 + +because 因为 + +because of 由于 + +as 因为,由于 + +since 因为,由于 + +owing to 由于 + +例:She broke up with her boyfriend because of a terrible quarrel. + +因为大吵了一架,她和男友分手了。 + + + +### 表示结果 + +as a result 结果.... + +thus 因此 + +hence 因此 + +so 所以 + +therefore 因此 + +accordingly 因此,于是 + +consequently 因此;结果;所以; 从而 + +as a consequence 因此,结果 + +例:Therefore, I decide to make an apology to him. + +因此,我决定向他道歉。 + + + +### 表示总结 + +on the whole 基本上,大体上;总的来说 + +in conclusion 总之;最后 + +in a word 总之 + +to sum up 总而言之;概括地说 + +in brief 简言之 + +in summary 总之 + +to conclude 最后;总之 + +to summarize 简而言之 + +in short 总之;简言之 + +例:In conclusion, we d better take measures as soon as possible. + +总之,我们最好尽可能快采取措施。 + + + +### 其他连接词 + +mostly 主要是;通常;多半地 + +occasionally 偶尔;有时 + +currently 目前 + +naturally 自然而然地 + +mainly 主要是 + +exactly 恰好地;正是 + +evidently 毫无疑问地; 显然 + +frankly 坦率地说;老实说 to be honest + +commonly 一般;通常;普遍 + +for this purpose 为此;有鉴于此 + +to a large extent 在很大程度上 + +for most of us 对我们大多数人来说 + +in many cases 在许多情况下 + +in this case 在这种情况下 + +例:Frankly, I do not mind her opinions at all. + +坦白说,我一点都不在乎她的看法。 + + + +according to 根据 + +## 参考 + +- https://www.sohu.com/a/330378162_100219060 + diff --git "a/_posts/English/2022-08-27-\350\257\255\346\226\231-\344\277\235\347\240\224\345\244\215\350\257\225\345\207\206\345\244\207.md" "b/_posts/English/2022-08-27-\350\257\255\346\226\231-\344\277\235\347\240\224\345\244\215\350\257\225\345\207\206\345\244\207.md" new file mode 100644 index 0000000000..65f64e8134 --- /dev/null +++ "b/_posts/English/2022-08-27-\350\257\255\346\226\231-\344\277\235\347\240\224\345\244\215\350\257\225\345\207\206\345\244\207.md" @@ -0,0 +1,82 @@ +--- +layout: post +category: English +title: 语料-保研复试准备 +tags: English +--- + +## SCI paper + +参与式感知激励机制算法研究 为了解决参与式感知中所收集数据在时间、空间上的分布不均而导致数据质量降低,提出一种考虑数据时空分布的激励机制,并在此机制中提出两种算法,第一种算法在数据收集总量满足需求的情况下最优化收集数据在时空上的分布,提高收集数据质量,第二种激励算法在第一种激励算法的基础上考虑总成本的降低,对多目标加权平均,同时降低总成本和优化收集数据在时空上的分布,并将这两种激励算法与固定价格的激励算法的结果进行对比,使用了Matlab, visio及Origin等编程及作图。题目为《A Time and Location Correlation Incentive Scheme for Deeply Data Gathering in Crowdsourcing Networks》 + +As the first author, I published a SCI paper with the title 《A Time and Location Correlation Incentive Scheme for Deeply Data Gathering in Crowdsourcing Networks》,the main content is about the incentive mechanism of participatory sensing. In this paper, two algorithms are proposed to solve the problem of uneven distribution of sensed data in time and space. I mainly use matlab, origin, visio. Lastly, it is about twenty-two pages. + +We use a new metrics to measure the value of data in distribution dimension which the former paper lost. + +Dynamic and Greedy. + + + +V2 + +It's about the incentive mechanism of participatory sensing, which is study that how to make people to help platform to get the most valuable sensing data by their smartphone with least cost, such as paying money or virtual money to people, yeah, rewarding the participated people + +Here's the question, what is the most valuable sensing data and how to judge it. + +We used a new metrics to measure the value of data in distribution dimension of time and space, which the former papers lost. + +In this paper, two algorithms are proposed to solve this problem. + +On the basis of meeting the requirements of Platform that geting enough sensed data, the first algorithm is maximize the the new metrics that I just mentioned by adjusting the rewards dynamically with a greedy algorithm. The second algorithm is to minimize the cost of the system while meeting the sensing data requirement and maximizing the new metrics. + +Finally, we compare our proposed scheme with existing schemes via extensive simulations. Extensive simulation results well justify the effectiveness of our scheme. + +I mainly use matlab, origin, visio. Lastly, it is about twenty-two pages. + + + +## 你认为最重要的学科是什么 + +What do you think is the most important subject? + +《数据结构》主要介绍如何合理地组织数据、有效地存储和处理数据,正确地设计算法以及对算法的分析与评价。用计算机解决实际问题,首先要做的事情就是要把涉及问题的相关信息存储到计算机中,也就是需要把问题的信息表示为计算机可接受的数据形式,然后根据问题处理功能的要求,对存储到计算机中的数据进行处理。归结为一句话,用计算机解题首先要用合理的结构表示数据,然后才能根据相应的算法处理结构,而数据表示和数据处理正是数据结构学科要研究的内容。 + +"Data Structure" mainly introduces how to organize data reasonably, efficiently store and process data, correctly design algorithms and analyze and evaluate algorithms. To solve practical problems with a computer, the first thing to do is to store the relevant information about the problem in the computer, that is, to represent the information of the problem as a form of data acceptable to the computer, and then to store the information according to the requirements of the problem processing function. Process the data into the computer. It comes down to one sentence. Solving a problem with a computer first requires a reasonable structure to represent the data, and then the structure can be processed according to the corresponding algorithm. Data representation and data processing are the contents of the data structure discipline. + +## 除了四六级证书外你还有其他证书么 + +目前我英语方面我只有英语四六级证书,但是我打算在大四学习英语,考托福或者雅思,因为在半年前我撰写并发表了我的第一篇SCI论文,大概22页,接近两万多字,我认识到了英语的重要性,无论是英文写作还是阅读外文文献 + +At present, I only have English CET-6 certificate in English, but I plan to study English in the senior year, test TOEFL or IELTS, because I wrote and published my first SCI paper six months ago, about 22 pages, close to 20,000. Multi-word, I realized the importance of English, whether it is writing in English or reading foreign literature. + +## 你如何证明你的英语能力 + +正如我刚才所说,在半年前我撰写并发表了我的第一篇SCI论文,大概22页,接近两万多字,论文是研究参与式感知中的激励机制的,并且我也阅读了大量相关的文献,这体现了我的英文阅读和写作能力。在平时的开发中,我也经常接触英语,比如Java开发的API文档,日志信息,同时我在leetcode平台上刷题超过200道,题目都是英文的,我认识到了英语重要性,想在接下来的一年考取托福雅思,更想到哈工大继续学习,希望老师给我这样一个机会。 + +As I said just now, I wrote and published my first SCI paper six months ago, about 22 pages, close to more than twenty thousand words. The paper is about the incentive mechanism in participatory perception, and I also read a lot. Related literature, which reflects my English reading and writing skills. In the usual development, I also often contact English, such as Java development API documentation, log information, and I brushed more than 200 words on the leetcode platform, the topics are in English, I realized the importance of English, want to pick up In the coming year, I took TOEFL IELTS and thought that Harbin Institute of Technology would continue to study. I hope the teacher will give me such an opportunity. + + + +## 学校 + +Central South University is located in Changsha, Hunan Province. It is a 985 university and it was founded in 2000. The former principal was Zhang Yuxue. The current principal of the school is Tian Hongqi. The school motto is practical, and there are several campuses, such as the headquarters, the new campus, and the railway campus. Behind the Yuelu Mountain, there is a beautiful scenery, as well as the Swan Lake, there are many white swan black swan, and even some TV dramas are also filmed in our school. Compared with other places in the school, I prefer to eat and live in the school. In terms of eating, there are many canteens, and the dishes are so many and cheap, which is full of praise. About the school’s living, in terms of the undergraduate. There are four students in a dormitory with air conditioning and a separate bathroom. The school encourages competition and innovation, and has established many related competitions. The participation of students is also very high. In a word, I like my university very much. Here, I have laid a solid foundation for my study. Ok. That’s all. Thank you. + + + +## 家乡 + +I come from Linjiang City of Jilin Province, which is in the northeast of China. Linjiang is named for the Yalu River. The another side of the Yalu River is North Korea. Therefore, there are rich water resources because of the yalu river. There are also some beautiful scenery, famous attractions such as Jinyinxia, Xianren Cave, and so on. The population here is small, but people are very easy-going. In addition, compare with other cities, the prices of the city are very low, even no subways. When I was in high school, I went to another place. To some extent, it is another hometown. In Jiangyuan District of Baishan City, which is the hometown of black fungus in China, the hometown of Songhua Stone in Jiangyuan District, you may find special stones in the mountains. There is also a stone pavilion that exhibits a wide variety of stones and corresponding prices. These two places are located in the eastern part of Jilin Province, so the winter is long, cold, and the frost comes early. I really like my hometown and I hope my hometown can get better. OK. That’s all. Thank you. + + + +## 家庭 + +I come from Linjiang City, Jilin Province. There are 4 people in my family. My parents and my sister, my sister is now married who is 9 years older than me. She has a daughter and even her daughter already in the first grade. My parents don't have a high diploma, making a living by selling fish. Compared with that my father is very strict with me, my mother is very gentle to me. Anyway, I am very grateful to my parents. OK. That’s all. Thank you. + +## 爱好 + + I have many hobbies, such as swimming, playing tennis, reading, Watching American TV and running in the night. I think hobbies can make my life colorful. Besides, having some hobbies can bring knowledge to me. For example, reading is a good way to get knowledge. So I also like to get knowledge in the library, but not what I learned in class. A book I read recently is 《java concurrency》. I can not learn all from class, so reading can bring me other knowledge. They can help me to improve myself. I spend the most time watching American TV. The American dramas I have seen include Old Friends, How I meet your mother, Big Bang, Little Shelton, Agent Carter, SHIELD Agent, Game of Thrones, Broke Girls. OK. That’s all. Thank you. + + + + \ No newline at end of file diff --git "a/_posts/English/2022-08-27-\350\257\255\346\226\231-\347\226\221\351\227\256.md" "b/_posts/English/2022-08-27-\350\257\255\346\226\231-\347\226\221\351\227\256.md" new file mode 100644 index 0000000000..119435a287 --- /dev/null +++ "b/_posts/English/2022-08-27-\350\257\255\346\226\231-\347\226\221\351\227\256.md" @@ -0,0 +1,59 @@ +--- +layout: post +category: English +title: 语料-疑问 +tags: English +--- + +### 进展怎么样? + +How is it going? + +How is it going with sb/sth? 进展怎么样 + +Is everything going well? + +How are you getting on with your project? + +### Going on + + What’s going on 发生什麼事? + +What’s going on?和what is happening?有相同的意思 + + + +go on + +1. go on (doing something): 继续(做某事) +2. go on (with something):继续(某事) + + + +1. The work is going on smoothly. + + 工作正在顺利进行。 + +## 怎么样? + +How does that sound? + +what do you say + +## 杂 + +could you take a look if u have a second? 有时间的话看一下 + +could u please help me confirm whether your feature is 100% ready + +你同意xx? Do you agree with sth. Are you in favor of doing/sth. + +How do I address you? 我怎样称呼您?(非常正式) + +How are you getting on? 你怎么样?(询问近况)Same as usual.还是老样子。 + +Could you elaborate on that? 详细说明 Would you mind elaborating on something? + +How would you suggest we do that? + +let's give it a try and see if it improves performance. \ No newline at end of file diff --git "a/_posts/English/2022-08-27-\350\257\255\346\226\231-\351\231\210\350\277\260.md" "b/_posts/English/2022-08-27-\350\257\255\346\226\231-\351\231\210\350\277\260.md" new file mode 100644 index 0000000000..6694a90b71 --- /dev/null +++ "b/_posts/English/2022-08-27-\350\257\255\346\226\231-\351\231\210\350\277\260.md" @@ -0,0 +1,766 @@ +--- +layout: post +category: English +title: 语料-陈述 +tags: English +--- + +## 个人单词本 + + + +乐观的 optimistic + +悲观的 pessimistic + +熔断 circuit breaker circuit[/'sɝkɪt/](cmd://Speak/_us_/circuit) 电路 + +限流 rate limiting [/reɪt/](cmd://Speak/_uk_/rate) + +降级 fallback,n. degrade [/dɪ'greɪd/](cmd://Speak/_uk_/degrade), v. degration. + +服务发现 service discovery. + +负载均衡 load balance + +访问控制列表ACL: access control list + +可靠性: reliance, 可用的: reliable + +一致性: consistency + +最终一致性: eventually consistency [/ɪ'ventʃʊəlɪ/](cmd://Speak/_uk_/eventually) + +隔离: isolation [/aɪsə'leɪʃ(ə)n/](cmd://Speak/_uk_/isolation) + +连接池: connection pool [/puːl/](cmd://Speak/_uk_/pool) + +鉴权: authentication [/ɔ:,θenti'keiʃən/](cmd://Speak/_us_/authentication) + +计数器法: counter method + +滑动窗口: sliding window + +滚动的: rolling [/'rəʊlɪŋ/](cmd://Speak/_uk_/rolling) + +流量: traffic + +漏桶: Leaky Bucket [美 /'liki/](cmd://Speak/_us_/leaky)令牌桶: token bucket + +轮询,探询: poll [ /pəʊl/](cmd://Speak/_uk_/poll) + +延迟: delay + +定时器: timer, 任务定时调度: task scheduler + +定时的: timed + +时间轮: wheeltimer + +优先的: prior [/'praɪə/](cmd://Speak/_uk_/prior) + +circular [/'sɜːkjʊlə/](cmd://Speak/_uk_/circular)环形的,circuit环形vi, 电路。 + +缓冲 buffer + +层 level + +层级 hierarchy 分层的 hierarchical [美 /'haɪərɑrki/](cmd://Speak/_us_/hierarchy) + +灵活的 flexible + +线程安全 thread safety + +attribute 美 /ə'trɪbjut/ + +boolean + +atomic + +assign + +aspect + +ratio + +scale + +access + +represent + +address 处理 = deal with = handle + +Matter 问题、事情 + +Look into调查 。别人给了建议,可以用look into that表示正在看这个建议的方案。 + +orchestration 编排 协调 + +resilience 弹性 + +cognitive 有认知的, 认识的。 + +elaborate more detail on XX,把XX详细解释 + +Expansion 扩容 + +unweighted 无权重的 + +inbound入境的; unbound 已自由的 + +Allegiance 忠诚 + +Approperiate 恰当的 + +premise n 前提。 vt 引出 + +Subsequent 随后的 + +Shepherd vt 带领 指导 + +suspend 暂停 + +Inconvenience 不变,for your convenience + +entitlement n 授权 + +Invocation n 祈祷 祈求 + +merchandise 货物 + +Catestrophic 灾难性的 + +Instrument 仪器工具 + +Comprehensive 广泛的,综合的 + +procedure 程序 手续 + +Ambiguous 模棱两可的 + +blast redius 爆炸半径 + +impose v 强加, imposing 壮观的,给人深刻印象的 + +Mitigate vt 使缓和 + +Intuitive 有直觉力的 + +denote表示 + +5 dogs in total. 总共 + +Clarification 澄清 + +look into 浏览、观察 + +address 称呼,设法解决 + +encryption 加密 + +assure vt 确保 = ensure + +Horizontally , + +artificial 人造的 + +Exempt [美 /ɪɡˈzempt/](cmd://Speak/_us_/exempt) vt 免除 豁免 + +Sustainable /səˈsteɪnəbl/ 可持续的 + +Gross 恶劣的 + +Dismiss vt 开除 解散 解雇 + +Revenue 税收 /ˈrevənuː/ + +Obliged adj. 感激的;有责任的;必须的 +v. 要求;约束;施恩惠(oblige的过去分词) + +Occasionally, temporary temporarily + +## 个人语料 + +看一遍 read through + +联系我, reach out to me + +接入access + +the details are list in the doc as well + +make sure that + +align the context with our PMs before formal access. + + + +reproduce the bug + +step-by-step screenshots + +outset开端 + +it is as expected. + +go through 经历 + +detailed feature review + +formal + +format + +phase阶段 + +correct + +don't hesitate to contact me. + + + +合规 compliance + +治理 governance [/'gʌv(ə)nəns/](cmd://Speak/_uk_/governance) + +be handed over to sb. 交接 + +please contact sb + + + +that's totally fine. + +走查 walkthrough + +conduct 实施 + +事故 failure + + + +bottleneck瓶颈。 + + + +nothing but 只不过 + +perform执行 运行 + +throttling 油门调节 + + + +favorite已经有了最的含义了,不要前面加most + + +never mind +I don't mind. + +work out (vt/ vi) *[work it out](dic://work it out)* + +I realy appreciate it. + +I own you one. + +I need to vent.发泄 +vent to. + +There's nothing wrong with sth. + +no way +There's no way xxx + + + +I see. + +what I have on my agenda today. + +Just as I start in on my email, my phone rings + + + +“**I have a question for you**” would be correct. “I have a question to you” would be incorrect. You could, however, say something like “I have a question to ask you” instead. + + + + + +have a hard time doing. 做什么困难 + +get sth in. 抽空做某事。 I try to get a snap in before the meeting. I try to get a run in before going to work + +be tired of doing sth + +change things up, 做些改变,it's time to change things up. + + + + + +finalize 敲定 + +Postpone 延期 put off. meeting has been postponed to Friday. + +Revision 修订 + +Variate 变量 + +Intrusive 侵入的, in chu si v + +redundant 冗余的 ri dan den t + +enroll 登记 v + + + + + + + + + + + +How to effectively utilize, 利用 + +thay **have** a lot **in common**. They have a little in common in their hobbies + +我尝试了。 I tried doing + +I tried ringing you several times yesterday but I couldn't get through. + +be responsible for doing 没有to do + +be resonsible to sb. + +fair enough: 勉强同意 部分合理 + + + +我不喜欢 It's my thing + + + +I'm dying to 非常想 + +I'd appreciate it if you'd come with me + +how long have you not seen him since yesterday. + +I'm convinced that + +Is it possible to + +It depends on sth + +It make no difference 没关系 + +It make no difference whether you come or not. + +make a difference 有影响 + +It would be wonderful if we could do that + +It is believed that + + + + + +Be similar to 不是with. + +Sure about that? + +I'm pretty good at + +Xx If there was.. + + + +Decent 得体的 + +There's nothing wrong with being poor + + + +I have confidence in you. + +Your work is bound to be successful. + +I'm quite sure we will win. + +Don't get your hopes too high. + +果不其然。That figures. + +I can't think of any way out now.Where do I go from here? + +现在也想不出什么办法,我该怎么办呢? + +You can try another time. + +我很后悔错过了那次机会。I'm sorry to have missed the chance. + += I regret having missed the chance. + + + +There has to be sth + + + +From/in my understanding, + +In my experience. Based on your past experience. + + + +We will sort it out. 我们会解决它 + + + +Just out of curiosity, xxx. 出于好奇心,记住curiosity写法,不是curioustiy + +That's to say = that means. + + + +note that xxx 注意 + +now that xxx 既然现在 + + + +occagsionally 偶尔地 + +temporary 临时的 temporarily. + +coincident. apparently/obvious. curious. + +I'm not sure what you mean by "gg." Can you please provide more context or clarify your request? + + + +no longer, not yet可以插入在动词前,比如been前 + +rather than doing sth, I would like to + +Rather 相当,类似very It is rather cheap at this price. 相当便宜 + +I'm rather pessimistic. + + + + + +So far so good, 目前还好 + +Look if nothing else, 别的不说。 + +You like it **the most** 最喜欢它了。 + +with respect to 关于。 类似for + +regarding 替代 for, 关于; + + + + + +move ahead 继续,和move on差不多。 Go ahead也行。 + + + +other than, 不同于 sth. 例句This means that, other than the primary key attributes, you don't have to define any attributes or data types when you create tables. + +along with 连同。 eg: The following are descriptions of each data type, along with examples in JSON format. + +Optionally 或者 Optionally, you can apply a condition to the sort key so that it returns only the items within a certain range of values. + +Suppose that 假设 eg: Suppose that the *Pets* table has a composite primary key consisting of *AnimalType* (partition key) and *Name* (sort key). + +Roughly 大概 Roughly half of them are men, half of them are women. + + + +if you are looking to do 如果你希望做xx,如果你想要 + +well, **regardless**, it's happening 无论如何 + + + +**从现在起**; 今后,, +例句;From now on, I will begin to write my book. + +It's due to arrive an hour from now.从现在起一个小时就该到了。 +I'll be more careful from now on .我今后会更加小心。from now on的用法相关疑问句在特定的环境和语调下,问句具有与其形式相反的含义,即肯定中暗含否定含义。所以翻译时一定要考虑语境和语调,表达出英语的否定意义。 + + + +All right, look, here's the deal + +To my understanding.我是这样理解的。 + + + +It's as if that 它好像 + + + +### looks like vs seems like + +后者抽象,前者是物理看见 + +Both are very similar. + +-"It looks like" is something you usually say when you can physically see something. + +-"It seems like" is something a little more abstract. It's something you can only "detect" or guess at. + + Examples: -"it seems like it will rain" -"it looks like it will rain" (these are both okay to say) + +-"It seems like just yesterday I was in high school" (you can't say "It looks like just yesterday I was in high school" because you can't physically "see" how much time has passed) + + + +like作为像时是介词,可以直接加宾语,同as。只有当like作为句子主要成分,如He is like a dog. 也可以说成,He looks like a dog. + +### ever怎么用 + +ever用作副词,意为“曾经、以前、无论何时、总是”等。其用法比较灵活 + +一、用于一般疑问句,意为“曾经、这以前”现代汉语中一般不译出。 +Does she ever go out at night?她通常晚上外出吗? +Have you ever been to Beijing?你曾去过北京吗? + +二、用于否定句,意为“无论何时都不……,至今不曾……”。 +Nothing ever happens in the lonely village.这个遥远的小村子至今未出过事。 +We hardly ever go shopping there.我们至今未在那里买过东西。 + +三、用于条件句,译为“曾经、有机会”。 +If you ever come to Beijing,please let me know.如果有机会来北京,请告诉我。 +If you ever have any problems,please call me.你若有问题,请打电话。 + +四、与比较级连用,译为“以前、以往、任何时候”。 +It is raining hard than ever.雨下得比以前更大了。 + +五、与最高级连用,译为“空前、有史以来、从来没有”。 +I think she is the best actress ever.我认为她是至今最优秀的演员。 + +六、与疑问词连用,加强语气,译为“到底、究竟”。 +When(where)ever did you see the panda?你到底在什么时候(哪里)看见那只熊猫的? + +七、口语中,用于带有be的疑问句加重语气,表感叹。 +Is she ever a beauty?她真漂亮! + +### 也 + +same sth as sth 不要用with。 the same as sth + +same for me 我也要一样的 + +same here = me too. 我也一样 否定No, me neither + +same to you 你也一样 + +It's same with her. 她也一样 + +neither do I. 我也不是 + +So do I 我也是 + + + +## 句子翻译练习精选100句 + +[链接](https://www.sohu.com/a/409918309_99918196) + +## 会议 + +会议推迟,postpone,v + +the meeting had been postponed., be postponed to Friday + +### 开场 + +thank you all for coming. + +perhaps we can make a start + +thanks everyone and welcome to today's meeting. lets begin. + + + +today's meeting is about ... + +we'll go over our budget. go over = 过一遍,类似review. + +需要等其它人吗 If we are all here let’s get started/ start the meeting/start. + +Is everyone here yet? 所有人都来了吗。 + +let's start in 5 minutes. 5分钟后开始。 + + + + + +### 中途 + +很抱歉打断 Sorry to interrupt + +你可以接管吗, take over. + +If noboay has anything else to add, we can continue on to the next item. 确实是continue on to 它继续sth。 + + + +let's move on to the next item. 让我们看下一点 + +I'd like to turn it to over to sb. 会议转接给某人 + +let's move on to the next item 让我们看下一项 + +### 结束 + +Before we close, let me summarize the main points + +Okay. It looks like we've covered the main items for the meeting today. + +Are there any questions before we finish? + +No? Okay. Thank you all for attending. That's all. + + + +If there are no other comments I’d like to wrap this meeting up. + + + +we are running out of time. + + + +## 时间 + +over time 随着时间过去 + +### 不久后 + +过去的不久后。**Not long after xx.** Not long after he took office, the United States suffered an economic depression + +现在未来的不久后。 + +1. **Soon**. They're tiny and chubby and so sweet to touch, and soon they'll grow up and resent you so much. +2. **Before long**. He shall know this before long. + + + +### 时钟时间点的表达 + +6:10 ten past six 过了 + +5:50 ten to six 还差 + +11:30 half past eleven 差半小时 + + + +差15分钟 a quarter 刻 + +9:15 nine fifteen ; fifteen past nine ; a quarter past nine + +3:45 three forty-five ; fifteen to four ; a quarter to four + + + +大约时间: 马上到, 还不到,刚过 + +It's almost two. 马上到两点了。 + +It's not quite two. 还不到两点。 + +It's just after two. 刚过两点。 + + + +### 世纪、年代、年、月、日的表达 + +世纪:在十七世纪 写作:in the 17th century,读作:in the seventeenth century。 或者 在十七世纪 写作:in the 1600s,读作:in the sixteen hundreds + + + +年代: 在二十世纪三十年代 写作:in the 1930s,读作:in the thirties of the twentieth century或 in the nineteen thirties + +在二十世纪二十年代早期 in the early 1920s; + +在二十世纪五十年代中期 in the mid-1950s + + + +十月一日 写作:October 1, October 1st, 1 October, 1st October, (the) 1st of October等,其中的October都可以写成缩写形式Oct. + +读作:October the first或the first of October + + + +### 介词使用 + +**若指在哪一年或哪一月,用介词in;若具体到某一天,需用介词on。** + +例如: + +She was born in 1989. + +She was born in August. + +She was born in August 1989. + +She was born on 2nd August, 1989. + + + + + +单纯地表示上下午时用in; in the morning + +有具体的星期或日期时用on;On Sunday morning/afternoon. + +有具体的时间时用at;At 6:30 tomorrow morning/afternoon. + +黎明、午、夜、点与分用at at night ; at 7:30 + + + +将来时态in...以后 + +- they will come back in 10 days. 他们将10天以后回来。 +- i‘ll come round in a day or two. 我一两天就回来。 +- come and see me in two days‘ time. 两天后来看我。 + +## 听不懂怎么办 + +My english is not that good, a little rusty 生锈的。 + +I do not understand what you said. + +could you slow down a bit? 慢一点嘛 Excuse me, could you please slow down a little bit. I have trouble understanding you + +- Can you please repeat your question? I didn't hear your question clearly, the line was cutting off. +- I'm sorry. Would you please repeat the question? +- Sorry, can you say it again? +- Excuse me, I didn't hear you. Could you please say that again? + + + +we mainly use chinese at work, and we also use english when collaborating with foreign colloeagues at the oversea offices. + +chinese is used mostly. + + + +I'm going to share my screen and please let me know when you can see it. + diff --git "a/_posts/Games/Xbox/2021-10-03-xbox\345\267\264\350\245\277\346\234\215\350\264\255\344\271\260\346\225\231\347\250\213.md" "b/_posts/Games/Xbox/2021-10-03-xbox\345\267\264\350\245\277\346\234\215\350\264\255\344\271\260\346\225\231\347\250\213.md" deleted file mode 100644 index d8dd198080..0000000000 --- "a/_posts/Games/Xbox/2021-10-03-xbox\345\267\264\350\245\277\346\234\215\350\264\255\344\271\260\346\225\231\347\250\213.md" +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: post -category: Xbox -title: xbox巴西服购买教程 -tags: Xbox ---- - -## xbox巴西服购买教程 - - - -1. 微软账号个人信息编辑,编辑所在国家,添加账单和送货地址,选巴西的。https://account.microsoft.com/profile/?fref=home.banner.profile-column.title - - ``` - 平台如果无法编辑删除,就新加个然后设为首选账单地址。 - - Rua Estados Unidos, No. 1071 - 城市: CRISOLOGO - 洲: 圣保罗州01427-001 - 巴西 - 61-21958270 - ``` - -2. 添加付款方式,信用卡支付 - -3. xbox登录西班牙服,记住购买时不能开加速器。选择已有购买方式就可以了。 \ No newline at end of file diff --git a/_posts/Tech/AWS/2021-09-30-AWS Overall.md b/_posts/Tech/AWS/2021-09-30-AWS Overall.md new file mode 100644 index 0000000000..4ee54bd11f --- /dev/null +++ b/_posts/Tech/AWS/2021-09-30-AWS Overall.md @@ -0,0 +1,268 @@ +--- +layout: post +category: AWS +title: AWS Overall +tags: AWS +--- + +## Cloud Notes + +IaaS、PaaS 和SaaS 的区别: 基础设施即服务(IaaS) 为云服务提供硬件,其中包括服务器、网络和存储。 平台即服务(PaaS) 除了提供IaaS 可提供的所有硬件之外,还提供操作系统和数据库。 软件即服务(SaaS) 提供了最多的支持,即为您的最终用户提供除其数据之外的所有服务。 + +[参考](https://www.zhihu.com/question/20387284) + +如果你是一个网站站长,想要建立一个网站。不采用云服务,你所需要的投入大概是:买服务器,安装服务器软件,编写网站程序。 + +现在你追随潮流,采用流行的云计算, + +如果你采用IaaS服务,那么意味着你就不用自己买服务器了,随便在哪家购买虚拟机,但是还是需要自己装服务器软件 + +而如果你采用PaaS的服务,那么意味着你既不需要买服务器,也不需要自己装服务器软件,只需要自己开发网站程序 + +如果你再进一步,购买某些在线论坛或者在线网店的服务,这意味着你也不用自己开发网站程序,只需要使用它们开发好的程序,而且他们会负责程序的升级、维护、增加服务器等,而你只需要专心运营即可,此即为SaaS。 + + + +## AWS Overall Notes + +云从业者Note: https://github.com/Matthewow/AWS-CLF-StudyNotes + + + +很好overall: https://www.zhihu.com/question/22314873 + + + +云的基础是计算、存储、网络,这三部分涵盖了互联网应用的各个方面,所有的云服务也是围绕这三部分去展开。 + + + +AWS的服务是按照region来划分的,在部署自己的应用之前,需要选择region,比如美国有us-west, us-east regions, 中国有cn-north, cn-west regions。基本上按照服务用户所在的区域来选择region,服务中国的用户就选择中国的region,服务美国的用户就选择美国的region。否则这个网络传输的成本就非常高,而且中国区其独有的网络环境,导致其他地区的服务是无法访问的。一个region又划分为多个AZ (availability zone), 一般情况下,我们需要把服务器均匀分布在多个AZ,为了避免单点故障,也就是我们所说的灾备多活。 + + + +选择好region后,就需要部署自己的[VPC](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/vpc/home) (virtual private cloud),一个VPC定义了一个私有隔离的网络环境。在VPC里面,我们部署所有的计算、网络资源。计算资源就是我们的服务器,AWS最出名的就是[EC2](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/ec2) (elastic compute cloud)。在部署EC2时,我们首先预估应用需要消耗的计算资源(cpu,磁盘,带宽等等),选择EC2的型号和数量。然后将所有的EC2分割成多个[ASG](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/ec2autoscaling/home) (auto scaling group), 一个ASG就相当于一个可弹性收缩的机器群,只要定义好扩容和缩容的指标,ASG就可以自己分配机器的数量。比如我们要求在EC2 CPU升到40%就扩容一倍,在CPU降到10%就缩容一倍,这样一个ASG里面机器CPU的消耗就一直均衡地保持在20%左右。具体分割成几个ASG,一般依据这个region有几个AZ来定,比如[us-east-1 region](https://www.zhihu.com/search?q=us-east-1+region&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A2333079486})有3个AZ,就分割成三个ASG,一个AZ部署一个ASG,这三个ASG在接受流量方面没有任何区别。接下来就是网络资源,每个VPC都有自己的ACL(acess control list),一个ACL定义了inbound rules和outbound rules,分别限制了访问IP的限制和访出IP的限制。VPC的网络资源被划分成多个子网subnets,一个subnet是一组IP地址的集合,前面说到的ASG就部署在[subnet](https://www.zhihu.com/search?q=subnet&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A2333079486})里面。一般来说subnet的数据量跟region AZ的数据成正比,每个AZ分配一个public subnet和一个private subnet,那么us-east-1的VPC就会有6个subnets。我们将ASG部署在private subnet里面,只允许vpc内部的IP访问,用于保护机器资源。因为public subnet是对外的,所以我们在public subnet里面部署ELB (elastic load balancer),用于接受vpc外的请求。有人会问如果我们想登录到ASG的EC2上面,应该怎么做?解决办法是在public subnet里面launch一个跳板机,我们先登录到跳板机,然后从跳板机里面登录到EC2上面。 + +接下来就是存储资源,AWS提供多种选择,我们最熟悉的应该就是[S3](https://link.zhihu.com/?target=https%3A//s3.console.aws.amazon.com/s3/home) (simple storage service)。S3是面向对象存储的服务,可以用来做数据归档、备份、恢复,或者作为数据分析、AI、Machine learning的数据湖来使用。通俗的理解就是我们的磁盘,它存储的key就是一个目录路径,相当于磁盘的目录,value是一个object,相当于文件或者子目录。在线的存储根据功能的不同也有很多选择,比较出名的而且是我用过的有三个。第一个是[DynamoDB](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/dynamodb/home),它是document-based NoSQL DB。DynamoDB是Amazon内部使用最频繁的数据,几乎90%的存储都会选择DynamoDB,绝对地超过RDS。这个现象的原因在这篇文章[Dynamo: Amazon’s Highly Available Key-value Store](https://link.zhihu.com/?target=https%3A//www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf)里面有解释,同时DDIA (Design [data-intensive application](https://www.zhihu.com/search?q=data-intensive+application&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A2333079486})) 这本书也给了同样的解释。总结就是:Amazon内部的存储90%以上都是单对多的关系,DynamoDB作为一个分布式的key-value DB,在可用性、扩展性方面非常适合这种单对多的存储结构。而且DynamoDB是最终一致性,进一步增加了它的可用性。关于DynamoDB我后面会单独出一篇介绍它的blog。而对于多对多的存储,我们就会用[RDS](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/rds) (relational database service),RDS字面理解就是[关系型数据库](https://www.zhihu.com/search?q=关系型数据库&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A2333079486})。AWS RDS上面托管了多种关系型数据库,包括mysql、oracle、MS SQL、aurora、MariaDB和PostgreSQL这六种数据库,其中我使用过mysql和aurora。在Amazon内部,[aurora](https://link.zhihu.com/?target=https%3A//docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html)使用的更频繁,它是兼容mysql和PostgreSQL的结合体,具体内容可见这篇文章[Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases](https://link.zhihu.com/?target=https%3A//www.allthingsdistributed.com/files/p1041-verbitski.pdf)。我使用的最后一种存储是[AWS elasticsearch](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/esv3/home) ,当时为了实现一个搜索功能,因为涉及到模糊匹配,全文搜索,就采用了[aws es](https://www.zhihu.com/search?q=aws+es&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A2333079486})。aws es跟主流的es已经分道扬镳,目前在aws上面称为openSearch service。 + +介绍完计算、网络、存储,接下来我想从应用的角度,讲讲在实际应用中,我们应该怎样使用AWS的服务。首先说消息队列,这个广泛应用的基础功能,AWS提供了[SQS](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/sqs/v2/home)和[SNS](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/sns/v3/home)。SQS是一个分布式的队列消息service,SNS是一个分布式的发布-订阅消息service。具体有人会问这两者有什么区别,这里给出了回答: [What is the difference between Amazon SNS and Amazon SQS?](https://link.zhihu.com/?target=https%3A//stackoverflow.com/questions/13681213/what-is-the-difference-between-amazon-sns-and-amazon-sqs)。 在我的实践中,SQS和SNS会结合起来使用,首先应用发布消息到SQS的queue里面,然后SNS消费这个queue的消息,放到自身的topic里面持久保存,然后其他的应用订阅这个topic,消费里面的消息。 + + + +建设完一个应用,然后就是DevOps。AWS在[托管代码](https://www.zhihu.com/search?q=托管代码&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A2333079486})、编译代码、部署应用、监控应用方面也提供了一整套服务,从前到后,[codeCommit](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/codesuite/codecommit) -> [codeArtifact](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/codesuite/codeartifact) -> [codeBuild](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/codesuite/codebuild) -> [codeDeploy](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/codesuite/codedeploy) -> [codePipeline](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/codesuite/codepipeline)。这一套实现了应用的continuous integration和continuous deployment。在监控方面,AWS提供了[cloudWatch](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/cloudwatch),可以以应用维度收集日志,视图化监控指标。AWS还提供了一个服务叫cloudFormation,这个服务在应用迁移的过程中,非常有用。Amazon内部很多都是国际化业务,应用需要部署到各个region。cloudFormation以yaml文本的形式记录下一个应用涉及到的各个服务资源配置,放在一个template里面。迁移到不同的region时,只需要一键run coudFormation template, 就可以部署好所有的AWS资源。 + + + +Notes: + +- region: 包含多个AZ, named by location 用aws需要选个region + +- AZ: availability zone. 包含一主多从的cluster,多个data center, 可以有另一个AZ继续保持主从。 region分多个AZ主要是为了容灾。 + +- region ---> AZ ----> data center 都是一对多。 一般情况下,region之间不会保持同步,互相独立,除非客户允许。 + + + +![image-20220930233334175](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202209302333289.png) + + + +- 选择region考量: compliance, latency, price, service availability + +## 术语 + +- IAM: identify and access management. 同account也是aws account level, account每月会进行计费,可以任意region里创建资源, work globally. 像s3等存储都是region level. EC2等就是AZ level. 意味着一个ec2不能分布在两个AZ。 IAM可以创建用户,然后授予权限给某个group + +- SQS: simple queue service + +- SNS: simple notification service. 发一些同事用的,比如发短信等。 + +- Aws route 53是 aws DNS + +- Amazon CouldFront 是CDN + +- 对象存储 + + - S3: simple storage service + +- cloudwatch for monitoring + +- ELB: elastic load balancer + +- EC2是 virtual machines. 全称: elastic compute cloud. 一共三种compute资源: vm, container services, serverless + +- AMI: amazon machine image 就是一堆配置,比如什么系统,安装哪些附加软件。可使用AMI启动一个同配置的实例。 类似docker的image + +- AWS Elastic Beanstalk 是一个应用程序管理平台,可以帮助客户轻松部署和扩展 Web 应用程序和服务。它将构建块(例如 EC2、Amazon RDS、Elastic Load Balancing、AWS Auto Scaling 和 Amazon CloudWatch)的预置、应用程序的部署、运行状况监控从用户身上分离出来,让用户可以集中精力编写代码。您只需指定要部署的容器映像、CPU 和内存要求、端口映射和容器链接即可。 + + Elastic Beanstalk 将自动处理所有的具体事务,包括预置 Amazon ECS 集群、均衡负载、自动扩展、监控以及在集群中放置容器。如果您希望利用容器的各种优势,但只想通过上传容器映像,在开发到生产等环节部署应用程序时享受到简易性,则 Elastic Beanstalk 非常适合。如果您需要对自定义应用程序架构进行更多精细化的控制,则可以直接使用 Amazon ECS。 + +- EBS: elastic block store. EC2也需要本地存储,这就是EBS 块存储。例如SSD等。它是外部挂载形式提供的,实例关机了,数据也还在,也可以做备份。适合那种临时数据,而非长期存储。一次只能挂载到一个AZ里的一个实例。 如果想多个实例连一个存储,可以用EFS/FSx, 前者linux,后者windows。 + + + +![image-20220930235011369](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202209302350393.png) + +![image-20220930234951120](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202209302349145.png) + +![image-20220930234939946](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202209302349976.png) + +![image-20220930235109632](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202209302351656.png) + + + +## Example: build an application like facebook ,a social media app. + +AWS介绍视频: [youtube](https://www.youtube.com/watch?v=Z3SYDTMP3ME&ab_channel=AWSTrainingCenter) + + + +![image-20221001104944376](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210011049445.png) + + + +![image-20221001110948079](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210011109118.png) + + + +![image-20221001144122955](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210011441985.png) + + + +加一些安全组件,IAM负责每个附件是否可访问,account管理范围等。 KMS负责数据的加密。 ACM负责access certificate management, 比如https证书等,在ELB这块。 WAF是防火墙,比如防止Ddos攻击之类的,在elb之前。Inspectoer负责监控每个service的安全,类似容器里一个agent。 + + + +![image-20221001150745631](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210011507662.png) + + + +codeCommit类似github这样代码仓库。 + +## Example: WordPress + +[link](http://www.cloudbin.cn/?p=2647) + +## 考证 + +[参考](https://zhuanlan.zhihu.com/p/138652055) + +先考**AWS Certified Solutions Architect - Associate** AWS 认证助理级解决方案架构师考试,这门考试更注重 AWS 的架构设计。助理级解决方案架构师需要基本了解 AWS 的几个基础的组件,比如 EC2,VPC, IAM, S3, Route53 等,掌握它们分别是什么,使用场景是什么,和传统数据中心的区别和优势等等 + + + +云从业者那个可以看这个: https://github.com/Matthewow/AWS-CLF-StudyNotes + + + + + +## 对象存储: S3及S3 Glacier + +> [官网](https://aws.amazon.com/s3/storage-classes/) + +Amazon S3 is object-level storage, which means that if you want to change a part of a file, you have to make the change and then re-upload the entire modified file. 对象存储,比较像字节的TOS。 也是以bucket隔离的,然后bucket可设置是否公开,可设置每个文件多版本, 可作为一个静态博客的host。 [对象存储参考](https://mafulong.github.io/2022/10/06/%E5%9D%97%E5%AD%98%E5%82%A8%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%AD%98%E5%82%A8%E5%92%8C%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8/) + +Amazon S3 Glacier is a great storage choice when low storage cost is paramount, your data is rarely retrieved, and retrieval latency of several hours is acceptable. If your application requires fast or frequent access to your data, consider using Amazon S3. Objects stored in Amazon S3 Glacier are called *archives*. 相比s3,价格便宜,适合平时不太访问的归档数据。 + + + +## 计算层:EC2 + + + +3种付费方案: + +1. on-demand, 运行时收费,按秒计费,价格固定。 +2. Reserved instances. (RIs) 预订 选定期的,有折扣。这种情况下即便选择不预付,非运行时也算收费。 它需要绑定一个instance type. +3. Spot instances. 类似出钱,然后aws自己评估这价格可以给几个实例这样。如果不够就掐掉实例。是最便宜的,但需要容忍突然停。 + +Dedicated hosts: 把物理机控制也给你,贵。和其他公司隔离开。 + + + +## 数据库 + +RDB: Amazon RDS, Redshit, Aurora. + +NoSQL: DynamoDB, Nepture, ElastiCache + + + + + +## IAM + + + +IAM (Identity Access Management) 由这些东西组成: + +- Users +- Groups 用户组 +- Roles 角色可以分配给AWS服务,让AWS服务有访问其他AWS资源的权限。 举个例子,我们可以赋予EC2实例一个角色,让其有访问S3的读写权限(后面课程会有关于这一点的实操) +- Policy Documents 策略。 策略具体定义了能访问哪些AWS资源,并且能执行哪些操作(比如List, Read, Write等) 策略的文档以JSON的格式展现 + +``` +// An example policy: allowing any access to any resource +{ + "Version": "2012-10-17" + "Statement": [ + { + "Effect": "Allow", + "Action": "*", + "Resource": "*" + } + ] +} +``` + + + +IAM 是 Global的,不属于任何一个 region + +Root 账号是你第一次配置账号的时候创建的,它拥有完全的 Admin aceess + +新 User 刚创建时是没有权限的。 + + + +首先要知道, AWS 提供了许许多多种类的服务或者说资源供我们使用, 这些资源挂在我们的 AWS 账户下, 这个账户就是我们第一次用 AWS 时用邮箱和密码申请的, 以后我们所有的资源申请, 账单费用都会挂到这个户头. + +那么 IAM 算什么呢? IAM 不是 AWS 的专有名词, 它是一个通用概念, 全称是 Identity and Access Management, 其要解决的两个问题就是身份认证 (Authtication) 和授权 (Authorization). 为此 AWS IAM 设计了用户, 角色, 用户组, 权限策略等概念和机制 + + + +场景 + +1. 自己公司的员工想访问 AWS Console 查看所在项目组的基础设施 +2. AWS 账户里的 EC2/Lambda 实例想访问同账户下的一台 RDS +3. 公网里用户的手机想要访问我们的后端存储(借助 API Gateway) + + + +AWS IAM 并不关心你创建的 IAM User 是给人用还是给程序用 + + + +AWS 官方建议 root 用户的唯一用途, 就是[用来创建你的第一个 IAM 用户](https://link.zhihu.com/?target=https%3A//docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html%23lock-away-credentials), 把这第一个 IAM 用户设置为管理员, 然后以后的工作都用这个管理员用户来进行. + + + +## SNS vs SQS + +AWS提供了[SQS](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/sqs/v2/home)和[SNS](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/sns/v3/home)。SQS是一个分布式的队列消息service,SNS是一个分布式的发布-订阅消息service。具体有人会问这两者有什么区别,这里给出了回答: [What is the difference between Amazon SNS and Amazon SQS?](https://link.zhihu.com/?target=https%3A//stackoverflow.com/questions/13681213/what-is-the-difference-between-amazon-sns-and-amazon-sqs)。 在我的实践中,SQS和SNS会结合起来使用,首先应用发布消息到SQS的queue里面,然后SNS消费这个queue的消息,放到自身的topic里面持久保存,然后其他的应用订阅这个topic,消费里面的消息。 + + + +sqs是一对一,不能一对多,消息可持久化,不推只能等拉,拉完就删除。 + +sns可一对多,不能持久化,push模型。 + +sqs及aws笔记,更全, [link](http://www.cloudbin.cn/?p=2530) + + + +## 参考 + +[参考](http://www.cloudbin.cn/?tag=aws) + diff --git a/_posts/Tech/AWS/2022-10-04-AWS network.md b/_posts/Tech/AWS/2022-10-04-AWS network.md new file mode 100644 index 0000000000..dca7abddcd --- /dev/null +++ b/_posts/Tech/AWS/2022-10-04-AWS network.md @@ -0,0 +1,406 @@ +--- +layout: post +category: AWS +title: AWS Network +tags: AWS +--- + +# AWS VPC + +## 名词解释 + +[参考](https://docs.amazonaws.cn/vpc/latest/userguide/what-is-amazon-vpc.html) + +- **Virtual Private Cloud (VPC)** + + [VPC](https://docs.amazonaws.cn/vpc/latest/userguide/configure-your-vpc.html) 是一个虚拟网络,与您在自己的数据中心中运行的传统网络极为相似。创建 VPC 后,您可以添加子网。翻译成中文是虚拟私有云。 + +- **子网** **Subnets** + + [子网](https://docs.amazonaws.cn/vpc/latest/userguide/configure-subnets.html)是您的 VPC 内的 IP 地址范围。子网必须位于单个可用区中。在添加子网后,您可以在 VPC 中部署 Amazon 资源。 + +- **IP 寻址** + + 您可以将 IPv4 地址和 IPv6 地址分配到 VPC 和子网。您还可以将您的公有 IPv4 和 IPv6 GUA 地址带到 Amazon 并将其分配到 VPC 中的资源,例如 EC2 实例、NAT 网关和网络负载均衡器。创建 VPC 时,需要为其分配一个 IPv4 CIDR 块(一系列私有 IPv4 地址)、一个 IPv6 CIDR 块或同时分配两种 CIDR 块(双堆栈)。 + + 私有 IPv4 地址无法通过 Internet 访问。IPv6 地址具有全球唯一性,可以配置为保持私有或通过互联网进行访问。 + +- **路由选择** + + 使用[路由表](https://docs.amazonaws.cn/vpc/latest/userguide/VPC_Route_Tables.html)决定将来自您的子网或网关的网络流量定向到何处。 + +- **网关和端点 ** **Gateways and endpoints** + + [网关](https://docs.amazonaws.cn/vpc/latest/userguide/extend-intro.html)将您的 VPC 连到其他网络。例如,使用[互联网网关](https://docs.amazonaws.cn/vpc/latest/userguide/VPC_Internet_Gateway.html)将您的 VPC 连接到网络。使用 [VPC 端点](https://docs.amazonaws.cn/vpc/latest/privatelink/privatelink-access-aws-services.html)私下连接到 Amazon Web Services,无需使用互联网网关或 NAT 设备。 + +- **对等连接** **Peering connections** + + 使用 [VPC 对等连接](https://docs.amazonaws.cn/vpc/latest/peering/)在两个 VPC 中的资源之间路由流量。 + +- **流量镜像** **Traffic Mirroring** + + 从网络接口[复制网络流量](https://docs.amazonaws.cn/vpc/latest/mirroring/),然后将其发送到安全和监控设备进行深度数据包检查。 + +- **中转网关 ** **Transit gateways** + + 将[中转网关](https://docs.amazonaws.cn/vpc/latest/userguide/extend-tgw.html)用作中央枢纽,以在 VPC、VPN 连接和 Amazon Direct Connect 连接之间路由流量。 + +- **VPC 流日志** **VPC Flow Logs** + + [流日志](https://docs.amazonaws.cn/vpc/latest/userguide/flow-logs.html)捕获有关在 VPC 中传入和传出网络接口的 IP 流量的信息。 + +- **VPN 连接** + + 使用 [Amazon Virtual Private Network (Amazon VPN)](https://docs.amazonaws.cn/vpc/latest/userguide/vpn-connections.html) 将 VPC 连接到您的本地网络。 + +## VPC + +**Amazon Virtual Private Cloud (Amazon VPC)**允许你在已定义的虚拟网络内启动AWS资源。这个虚拟网络与你在数据中心中运行的传统网络极其相似,并会为你提供使用AWS的可扩展基础设施的优势。 + +简单来说,VPC就是一个AWS用来隔离你的网络与其他客户网络的虚拟网络服务。在一个VPC里面,用户的数据会逻辑上地与其他AWS租户分离,用以保障数据安全。 + +**可以简单地理解为一个VPC就是一个虚拟的数据中心**,在这个虚拟数据中心内我们可以创建不同的子网(公有网络和私有网络),搭建我们的网页服务器,应用服务器,数据库服务器等等服务。 + +### VPC有如下特点 + +- VPC内可以创建多个子网 + +- 可以在选择的子网上启动EC2实例 + +- 在每一个子网上分配自己规划的IP地址 + +- 每一个子网配置自己的路由表 + +- 创建一个Internet Gateway并且绑定到VPC上,让EC2实例可以访问互联网 + +- VPC对你的AWS资源有更安全的保护 + +- 部署针对实例的安全组(Security Group) + +- 部署针对子网的**网络控制列表(Network Access Control List)** + +- 一个VPC可以跨越多个可用区(AZ) + +- **一个子网只能在一个可用区(AZ)内** + +- 安全组(Security Group)是有状态的,而网络控制列表(Network Access Control List)是无状态的 + + - 有状态:如果入向流量被允许,则出向的响应流量会被自动允许 +- 无状态:入向规则和出向规则需要分别单独配置,互不影响 + - 具体的区别挨踢小茶会在后续的章节详细讲解 + +- VPC的子网掩码范围是从/28到/16,不能设置在这个范围外的子网掩码 + +- VPC可以通过Virtual Private Gateway (VGW) 来与企业本地的数据中心相连 + +- VPC可以通过AWS PrivateLink访问其他AWS账户托管的服务(VPC终端节点服务) + + + +### VPC Peering + +**VPC Peering**可是两个VPC之间的网络连接,通过此连接,你可以使用IPv4地址在两个VPC之间传输流量。这两个VPC内的实例会和如果在同一个网络一样彼此通信。 + +- 可以通过AWS内网将一个VPC与另一个VPC相连 +- 同一个AWS账号内的2个VPC可以进行VPC Peering +- 不同AWS账号内的VPC也可以进行VPC Peering +- 不支持VPC Transitive Peering 不支持传递 + - 如果VPC A和VPC B做了Peering + - 而且VPC B和VPC C做了Peering + - 那么VPC A是**不能**和VPC C进行通信的 + - 要通信,只能将VPC A和VPC C进行Peering + +### 默认VPC + +- 在每一个区域(Region),AWS都有一个默认的VPC +- 在这个VPC里面所有子网都绑定了一个路由表,其中有默认路由(目的地址 0.0.0.0/0)到互联网 +- 所有在默认VPC内启动的EC2实例都可以直接访问互联网 +- 在默认VPC内启动的EC2实例都会被分配公网地址和私有地址 + +如下图所示,我们在某一个区域内有一个VPC,这个VPC的网络是172.31.0.0/16 + +在这个VPC内有2个子网,分别是172.31.0.0/20 和 172.31.16.0/20。这两个子网内都有一个EC2实例,每一个实例拥有一个该子网的私有地址(172.31.x.x)以及一个AWS分配的公网IP地址(203.0.113.x)。 + +这两个实例关联了一个主路由表,该路由表拥有一个访问172.31.0.0/16 VPC内流量的路由条目;还有一个目的为 0.0.0.0/0 的默认路由条目,指向Internet网关。 + +因此这两个实例都可以通过Internet网关访问外网。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211192248477.png) + +### VPC终端节点(VPC Endpoints) + +在一般的情况下,如果你需要访问S3服务,EC2实例或者DynamoDB的资源,你需要通过Internet公网来访问这些服务。有没有更快速、更安全的访问方式呢? + +**VPC终端节点(VPC Endpoints)**提供了这种可能性。 + +### PrivateLink + +VPC终端节点能建立VPC和一些AWS服务之间的高速、私密的“专线”。这个专线叫做PrivateLink,使用了这个技术,你无需再使用Internet网关、NAT网关、VPN或AWS Direct Connect连接就可以访问到一些AWS资源了! + +PrivateLink 是一种 Amazon Web Services (AWS) 的服务,它允许 AWS 中的服务与 VPC 内的资源进行安全、高速的连接,而无需通过公共 Internet。使用 PrivateLink,您可以将 AWS 中的服务(如 Amazon S3、Amazon EC2 等)作为一个私有端点,直接连接到 VPC 中的资源,从而实现私有、安全、低延迟的通信。 + +PrivateLink 使用 AWS VPC 内部的私有 IP 地址进行通信,这意味着您可以直接访问 AWS 中的服务,而不需要通过 NAT 网关或 VPN 连接。这样不仅可以提高通信的速度和稳定性,还可以提高安全性,因为数据和流量不会经过公共 Internet,不会受到网络威胁的影响。 + +使用 PrivateLink 时,您需要为要连接的 AWS 服务启用 PrivateLink,并在 VPC 中配置 VPC 端点。一旦配置完成,您就可以直接从 VPC 中的资源访问 AWS 服务,而不需要暴露公共 IP 地址。此外,PrivateLink 还支持跨账户连接,这意味着您可以将 AWS 服务连接到不同的 VPC 中的资源,从而实现更高的灵活性和可扩展性。 + +### vpc peering + +VPC Peering 是指连接两个或多个 VPC 的网络连接。它允许您在不通过公共 Internet 的情况下直接路由流量到其他 VPC,从而实现跨 VPC 通信。这种通信是私有、安全和高效的。 + +VPC Peering 通常用于以下情况: + +- 允许不同 VPC 之间的资源进行互操作,以便跨多个 VPC 进行应用程序部署 +- 实现基于 VPC 的多租户环境中的网络隔离,以确保租户之间的数据和流量不会相互干扰 +- 扩展 VPC 中的可用 IP 地址范围,以满足需要更多 IP 地址的资源的要求,而不必更改 VPC CIDR + +在 VPC Peering 中,不同 VPC 之间的流量不会经过公共互联网,因此通信速度更快,并且更加安全。但需要注意的是,VPC Peering 是一种单向连接,这意味着必须分别设置每个 VPC 之间的连接,才能实现完全的互通性。 + + + +限制: ip 有overlap不能用。 + +### private link 和 vpc peering区别 + +VPC Peering 和 PrivateLink 都可以用于在 AWS 中建立安全、私有的网络连接,但它们的使用场景略有不同。 + +VPC Peering 主要用于连接不同 VPC 之间的网络,从而实现跨 VPC 通信。而 PrivateLink 主要用于连接 AWS 服务与 VPC 内的资源进行安全、高速的连接。 + + + +vpc peering是免费的,没有private link安全。 + +private link是收费的,更安全。 + + + +So when would you use VPC Peering versus PrivateLink? + +VPC Peering is a good choice if you want to interconnect two or more VPCs within your company. You may also use it for integrating closely with trusted partners. + +For sharing specific services with customers and partners, PrivateLink may be a better choice. It limits your exposure by providing access to a specific service rather than your entire network. + +You'll also need to use PrivateLink in a few specific scenarios: + +- Connecting securely to AWS services from within a VPC +- Connecting services in VPCs with overlapping IP ranges +- Connecting securely to on-premise services from your VPCs + +### 服务不一定都在vpc里 + +服务不一定都在vpc里,比如公开可访问的s3。 但大部分服务都可以单独配置在vpc里,然后通过内部网络访问。 + +AWS 服务并不都在 VPC 中。AWS 提供的一些基础服务,如 Amazon S3、Amazon DynamoDB、Amazon SQS 等,都是通过公共网络提供的,您可以使用公共网络连接这些服务。 + +但是,大多数 AWS 服务都可以通过 Amazon VPC 进行访问,这意味着您可以将这些服务部署在您的 VPC 中,并通过 VPC 内部网络进行访问。例如,Amazon EC2 实例、Amazon RDS 数据库、Amazon ElastiCache 等服务都可以在 VPC 中部署,从而实现更安全、可靠的网络连接。 + +## 工作原理 + +[参考](https://docs.amazonaws.cn/vpc/latest/userguide/how-it-works.html) + +### IP 寻址 +创建 VPC 时,需要为其分配一个 IPv4 CIDR 块(一系列私有 IPv4 地址)、一个 IPv6 CIDR 块或同时分配两种 CIDR 块(双堆栈)。 + +私有 IPv4 地址无法通过 Internet 访问。IPv6 地址具有全球唯一性,可以配置为保持私有或通过互联网进行访问。 + +公有 IP 地址将从 Amazon 的公有 IP 地址池分配,它不与您的账户关联。在公有 IP 地址与您的实例取消关联后,该地址即释放回该池,并且不再可供您使用。您不能手动关联或取消关联公有 IP 地址。而是在某些情况下,我们从您的实例释放该公有 IP 地址,或向其分配新地址。有关更多信息,请参阅适用于 Linux 实例的 Amazon EC2 用户指南 中的公有 IP 地址。 + +### 访问 Internet + +> 私有网络不能访问互联网,需要互联网网关,私有网络内部之间可通信。 + +原定设置 VPC 包含一个互联网网关,而且每个原定设置子网都是公有子网。您在默认子网中启动的每个实例都有一个私有 IPv4 地址和一个公有 IPv4 地址。这些实例可以通过 Internet 网关与 Internet 通信。通过互联网网关,您的实例可通过 Amazon EC2 网络边界连接到 Internet。 + +默认情况下,您启动到非默认子网中的每个实例都有一个私有 IPv4 地址,但没有公有 IPv4 地址,除非您在启动时特意指定一个,或者修改子网的公有 IP 地址属性。这些实例可以相互通信,但无法访问 Internet。 + +您可以通过以下方式为在非默认子网中启动的实例启用 Internet 访问:将一个互联网网关附加到该实例的 VPC(如果其 VPC 不是默认 VPC),然后将一个弹性 IP 地址与该实例相关联。 + +或者,您还可以使用网络地址转换 (NAT) 设备,以允许 VPC 中的实例发起到互联网的出站连接,但阻止来自互联网的未经请求的入站连接。NAT 将多个私有 IPv4 地址映射到一个公有 IPv4 地址。您可以使用弹性 IP 地址配置 NAT 设备,并通过互联网网关将其与互联网相连。您可以通过 NAT 设备将私有子网中的实例连接到互联网,NAT 设备会将来自实例的流量路由到互联网网关,并将所有响应路由到该实例。 + +如果您将 IPv6 CIDR 块与 VPC 关联并为实例分配 IPv6 地址,则实例可以通过互联网网关通过 IPv6 连接到互联网。或者,实例也可以使用仅出口互联网网关经由 IPv6 发起到互联网的出站连接。IPv6 流量独立于 IPv4 流量;您的路由表必须包含单独的 IPv6 流量路由。 + + + +默认情况下,默认子网为公有子网,因为主路由表会将指定发往 Internet 的子网流量发送到 Internet 网关。 + + + +### NAT + +NAT的全程是“**Network Address Translation**”,中文解释是“**网络地址转换**”,它可以让整个机构只使用一个公有的IP地址出现在Internet上。 + +NAT是一种把内部私有地址(192.168.1.x,10.x.x.x等)转换为Internet公有地址的协议,它一定程度上解决了公网地址不足的问题。 + +- NAT实例需要创建在公有子网内 + + + + + +**堡垒机(Bastion Host)**又叫做跳板机(Jump Box),主要用于运维人员远程登陆服务器的集中管理。运维人员首先登陆到这台堡垒机(公网),然后再通过堡垒机管理位于内网的所有服务器。 + +堡垒机可以对运维人员的操作行为进行控制和审计,同时可以结合Token等技术达到更加安全的效果。 + +## VPC场景 + +**带单个公有子网的 VPC**: 此场景的配置包含一个有单一公有子网的 Virtual Private Cloud (VPC),以及一个 Internet 网关以启用 Internet 通信。如果您要运行单一层级且面向公众的 Web 应用程序,如博客或简单的网站,则我们建议您使用此配置。 + +**带有公有和私有子网的 VPC (NAT)**:这个场景的配置包括一个有公有子网和私有子网的 Virtual Private Cloud (VPC)。如果您希望运行面向公众的 Web 应用程序,并同时保留不可公开访问的后端服务器,我们建议您使用此场景。常用例子是一个多层网站,其 Web 服务器位于公有子网之内,数据库服务器则位于私有子网之内。您可以设置安全性和路由,以使 Web 服务器能够与数据库服务器建立通信。 + +公有子网中的实例可直接将出站流量发往 Internet,而私有子网中的实例不能这样做。但是,私有子网中的实例可使用位于公有子网中的网络地址转换 (NAT) 网关访问 Internet。数据库服务器可以使用 NAT 网关连接到 Internet 进行软件更新,但 Internet 不能建立到数据库服务器的连接。 + +## Security Groups(安全组) + +[参考](https://zhuanlan.zhihu.com/p/151419823) + +VPC 网络安全组标志 VPC 中的哪些流量可以发往 EC2 实例或从 EC2 发出。安全组指定具体的入向和出向流量规则,并精确到源地址(入向)和目的地址(出向)。这些安全组是与 EC2 实例而非子网关联的。 +默认情况下,流量只允许出,不允许入。 + + + +Security Group(SG)通过控制IP和端口来控制出站入站规则,可以用于EC2,RDS及下面将要用到的VPC Endpoint。 + + + +## 网络ACL(NACL) + +**网络访问控制列表(NACL)**与安全组(Security Group)类似,它能在子网的层面控制所有入站和出站的流量,为VPC提供更加安全的保障。 + + + +- 在你的**默认VPC**内会有一个默认的网络ACL(NACL),它会**允许**所有入向和出向的流量 +- 你可以创建一个自定义的网络ACL,在创建之初所有的入向和出向的流量都会被**拒绝**,除非进行手动更改 +- 对于所有VPC内的子网,每一个子网都需要关联一个网络ACL。如果没有关联任何网络ACL,那么子网会关联默认的网络ACL +- 一个网络ACL可以关联多个子网,但一个子网只能关联一个网络ACL +- 网络ACL包含了一系列(允许或拒绝)的规则,网络ACL会按顺序执行,一旦匹配就结束,不会再继续往下匹配 +- 网络ACL有入向和出向的规则,每一条规则都可以配置允许或者拒绝 +- 网络ACL是无状态的(安全组是有状态的) + - 被允许的入向流量的响应流量必须被精准的出向规则所允许(反之亦然) + - 一般至少需要允许临时端口(TCP 1024-65535) + - 关于临时端口的知识,可以参见[这里](https://docs.aws.amazon.com/zh_cn/AmazonVPC/latest/UserGuide/VPC_ACLs.html#VPC_ACLs_Ephemeral_Ports) + +## Difference between Internet Gateway and NAT Gateway + + + +参考 + +- Internet Gateway (IGW) allows instances with public IPs to access the internet. +- NAT Gateway (NGW) allows instances with no public IPs to access the internet. + +## 参考 + +[参考](https://juejin.cn/post/6949072638145003556) + +大部分 AWS 服务都需要以 VPC 为基础进行构建,比如最常用的 EC2,ALB,及无服务器服务 ECS Fargate。 vb + +当我们在一个 VPC 中创建 Subnet 时需要给 Subnet 选择一个 AZ(Availability Zone),一个 Subnet 只能选择建在一个 AZ 中。 + + + +**选择region** + +因为国内政策法规原因,AWS 在中国的服务与 AWS Global 服务略有不同。 + +AWS Global 的 Region 之间是通过主干网相连的,AWS 中国区的服务没有通过主干网与 AWS Global 相连,只有中国区内部两个 Region,北京和宁夏是相连接的。 + +在创建 VPC 时并不需要添写 AZ(Availability Zone)信息,VPC 只与 Region 有关。 + + + +Subnet 是最终承载大部分 AWS 服务的组件,比如 EC2, ECS Fargate,RDS。 + +Subnet 分为两种 Private Subnet 和 Public Subnet。 + +简单来说,不能直接访问 internet 的 Subnet 就是 Private Subnet,能直接访问 internet 的就是 Public Subnet。 + + + +Security Group(SG)通过控制IP和端口来控制出站入站规则,可以用于EC2,RDS及下面将要用到的VPC Endpoint。 + + + +VPC Endpoint用来直接连接VPC与AWS相关服务,比如RDS AIP,S3。 + +当系统安全要求比较高时,EC2处于的Subnet可能被限制,无法访问internet,这时EC2就无法访问AWS的一些服务,比如SSM。 + +这时我们可以利用VPC Endpoint把VPC和所需要访问的服务连接起来,然后EC2就可以不经internet访问到所需的服务。 + + + +[参考](https://juejin.cn/post/6954169148318433288) + +RT(Route Table)与Subnet相关连,用来描述网络路由。IGW: Internet gateway IGW是一个独立的组件配置在VPC上,使得VPC可以访问internet + +我们给VPC加了IGW之后,需要修改Subnet相关的路由,确保访问Internet的请求发送到IGW。 + +每个VPC中有一个默认的主RT,自动关联VPC内的每一个Subnet。我们现在为Subnet “ts-public-1”单独创建一个新的RT。 + + + +- 新建的Subnet就是Private Subnet +- 在Private Subnet中配置了到IGW的路由后,就变成Public Subnet +- Public Subnet中的EC2还要再配置一个Public IP或者EIP就可以访问Internet +- 如果EC2可以访问internet,其关联的Security Group入站规则如果允许从internet访问,那么这个EC2就可以从internet中直接访问到。 + + + +1. 实践中我们把应用程序,数据库放在Private Subnet中,阻止从internet访问。把堡垒机和ALB(Application Load balancer)放在Public Subnet,允许从internet访问。 + +2. 一般我们会建两套Public Subnet和Private Subnet,分别放在不同的AZ中,防止其中一个AZ出问题。这时如果配置NAT,也需要在两个Public Subnet中各配置一个NAT。 + + + +[参考](http://www.cloudbin.cn/?tag=aws) 暂无Note + +## 总结 + +VPC里多个AZ, 每个AZ都需要至少一个子网,默认是公有子网。但如果有internet访问不到的实例或者数据库,则需建个私有子网,私有子网默认不能访问internet,internet也不能访问私有子网。 + +要走互联网必须走internet gateway,它对整个vpc生效, public subnet可直接通过IGW与互联网互联,私有子网再通过NAT走公有子网是可以访问internet的,反向不能。 + +和互联网连接时都需要有个公网ip,这个是从amazon分配的。 + + + +# 跨账号访问aws service总结 + +比如 本账号lambda访问另一个账号的DDB + +Lambda 跨账号访问另一个账号中的 DynamoDB 表,一共有以下几种方法: + +1. 使用 assumeRole API:Lambda 函数在执行时使用 assumeRole API 切换到具有访问目标账号 DynamoDB 表权限的 IAM 角色。这种方法的优点是简单易用,只需要在代码中调用 assumeRole API 即可。缺点是需要进行额外的 IAM 角色配置和权限管理,同时存在一定的安全风险,因为将 IAM 凭证直接硬编码到代码中可能会导致安全问题。 +2. 使用 VPC Peering:通过建立 VPC Peering 连接,将源账号和目标账号的 VPC 相互连接起来,实现 Lambda 函数对 DynamoDB 表的访问。这种方法的优点是简单易用,可以通过 AWS 控制台完成配置,同时具有较高的安全性。缺点是需要进行 VPC 配置和管理,且无法实现跨区域访问。 +3. 使用 PrivateLink:通过在目标账号中创建一个 PrivateLink 终端节点,将 DynamoDB 表以私有方式暴露给源账号中的 Lambda 函数,实现跨账号访问。这种方法的优点是高度安全,可以通过 AWS PrivateLink 在私有网络中实现数据的加密传输,同时支持跨区域访问。缺点是需要进行较为复杂的 VPC 和 PrivateLink 配置,且可能需要进行网络安全设置和管理。 +4. 使用 AWS Resource Access Manager(RAM):通过使用 RAM,可以在多个 AWS 账号之间共享资源,并授予其他 AWS 账号访问这些资源的权限。Lambda 函数可以将 RAM 中的资源授权给目标账号,从而实现对 DynamoDB 表的访问。这种方法的优点是可以实现资源共享和管理,并且具有高度的可扩展性。缺点是需要进行 RAM 的配置和管理,且可能需要进行跨账号 IAM 角色的授权和管理。 + + + +一般来说,如果需要实现高度安全性和数据隔离,且需要支持跨区域访问,推荐使用 PrivateLink;如果只是需要简单快速地实现跨账号访问,可以选择使用 assumeRole API 或 VPC Peering。如果需要进行资源共享和管理,可以考虑使用 AWS RAM。 + +# Route 53 + +**Amazon Route 53**是一种高可用、高扩展性的云DNS服务。 + +Amazon Route 53 是一种托管域名系统 (DNS) 服务,它可帮助您为您的域名注册和管理 DNS 记录。您可以使用 Route 53 将您的域名映射到您的 VPC 内的资源,如 ELB 和 Amazon S3。 + +不同的DNS记录: + +- **CNAME** – CNAME (Canonical Name)可以将一个域名指向另一个域名。比如将aws.xiaopeiqing.com指向xiaopeiqing.com +- Alias记录 – 和CNAME类似,又叫做别名记录,可以将一个域名指向另一个域名。 + - **和CNAME最大的区别是,Alias可以应用在根域(Zone Apex)。即可以为xiaopeiqing.com的根域创建Alias记录,而不能创建CNAME** + - 别名记录可以节省你的时间,因为Route53会自动识别别名记录所指的记录中的更改。例如,假设example.com的一个别名记录指向位于lb1-1234.us-east-2.elb.amazonaws.com上的一个ELB负载均衡器。如果该负载均衡器的IP地址发生更改,Route53将在example.com的DNS应答中自动反映这些更改,而无需对包含example.com的记录的托管区域做出任何更改。 弹性负载均衡器(ELB)没有固定的IPv4地址,在使用ELB的时候永远使用它的DNS名字。很多场景下我们需要绑定DNS记录到ELB的endpoint地址,而不绑定任何IP + +# AWS Direct Connect + +AWS Direct Connect 是一种专用网络连接服务,它允许您通过私有连接连接到 AWS 服务。您可以使用 Direct Connect 将您的本地数据中心与您的 VPC 直接连接起来,实现更安全、更高带宽的网络连接。 + + + +AWS Direct Connect 是一种联网服务,提供了通过互联网连接到AWS 的替代方案。 使用AWS Direct Connect ,以前通过Internet 传输的数据将可以借助您的设施和AWS 之间的私有网络连接进行传输。 + +**不再需要通过网络提供商。** 描述的是本地IT数据中心和VPC连接。通过物理专线连接。 + +AWS Direct Connect 通过标准的以太网光纤电缆将您的内部网络链接到 AWS Direct Connect 位置。电缆的一端接到您的路由器,另一端接到 AWS Direct Connect 路由器。有了这个连接,你可以创建*虚拟接口*直接公有公有访问AWS服务(例如,到 Amazon S3)或 Amazon VPC,绕过您的网络路径中的互联网服务提供商。网络 ACL 和安全组都允许 (因此可到达您的实例) 的发起 ping 的AWS Direct Connect位置提供访问AWS在与之关联的区域中。您可以将单个连接用于公有区域或AWS GovCloud (US)公有访问AWS所有其他公有区域中的服务。 + +[参考](https://docs.aws.amazon.com/zh_cn/directconnect/latest/UserGuide/Welcome.html) + diff --git a/_posts/Tech/AWS/2022-11-18-AWS Compute.md b/_posts/Tech/AWS/2022-11-18-AWS Compute.md new file mode 100644 index 0000000000..4067771a68 --- /dev/null +++ b/_posts/Tech/AWS/2022-11-18-AWS Compute.md @@ -0,0 +1,195 @@ +--- +layout: post +category: AWS +title: AWS Compute +tags: AWS +--- + +## AWS Compute + +## AMI + +AMI: amazon machine image 就是一堆配置,比如什么系统,安装哪些附加软件。可使用AMI启动一个同配置的实例。 类似docker的image + +**Amazon Machine Image (AMI)** 是亚马逊AWS提供的系统镜像,这个AMI包含了如下的信息: + +- 由实例的操作系统、应用程序和应用程序相关的配置组成的模板 +- 一个指定的需要在实例启动时附加到实例的卷的信息(比方说定义了使用8 GB的General Purpose SSD卷) + +下图所示的是AMI的生命周期,你可以创建并注册一个AMI,并且可以使用这个AMI来创建一个EC2实例。同时你也可以将这个AMI复制到同一个AWS区域或者不同的AWS区域。你同样也可以注销这个AMI镜像。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211182358363.png) + +- **AMI是区域化的**,只能使用本区域的AMI来创建实例;但你可以将AMI从一个区域复制到另一个区域 + + + + + +## 弹性伸缩(Auto Scaling) + +**亚马逊弹性伸缩(Auto Scaling)**能**自动地**增加/减少EC2实例的数量,从而让你的应用程序一直能保持可用的状态。 + +你可以预定义Auto Scaling,使其在需求高峰期自动增加EC2实例,而在需求低谷自动减少EC2实例。这样不仅能让你的应用程序一直保持健康的状态,而且也节省了你为EC2实例所付出的费用。 + +Auto Scaling 适用于那些需求稳定的应用程序,同时也适用于在每小时、每天、甚至每周都有需求变化的应用程序。 + +- Auto Scaling能保证你一直拥有一定数量的EC2实例来分担应用程序的负载 +- Auto Scaling能带来更高的容错性、更好的可用性和更高的性价比 +- 你可以控制伸缩的策略来决定在什么时候终止和创建EC2实例,以处理动态变化的需求 +- 默认情况下,Auto Scaling能控制每一个可用区内所运行的实例数量尽量平均 + - 为了达到这个目标,Auto Scaling在需要启动新实例的时候,会选择一个目前拥有运行实例最少的可用区 + +Auto Scaling的构成组件: + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211190006430.png) + +### 启动配置(Launch Configuration) + +- 启动配置是弹性伸缩组用来启动EC2实例的时候所使用的模板 +- 启动配置包含了镜像文件(AMI),实例类型、密钥对、安全组和挂载的存储设备 +- 一个启动配置可以关联多个Auto Scaling组 +- **启动配置一经创建不能被更改,只能删除重建** +- 启动配置中可以使用CloudWatch的基础监控(Basic Monitoring)或者详细监控(Detail Monitoring) +- Auto Scaling automatically creates a launch configuration directly from an EC2 instance. + +### 弹性伸缩组(Auto Scaling Group) + +- 弹性伸缩组(ASG)是弹性伸缩的核心,它包含了多个拥有类似配置/类型的EC2实例,这些实例被逻辑上认为是一样的 +- 弹性伸缩组需要的几个参数: + - **启动配置(Launch Configuration)**:它决定了EC2使用什么模板,模板内容包括了镜像文件(AMI),实例类型、密钥对、安全组和挂载的存储设备 + - **最小和最大的性能**:决定了在弹性伸缩的情况下,EC2实例数量的浮动范围 + - **所需的性能**:决定了这个弹性伸缩组要保持的运作所需要的基本的EC2实例数量;如果没有填写,则默认为其数值等同于最小的性能 + - **可用区和子网**:定义EC2实例启动时候所在的可用区和子网信息 + - **参数和健康检查**:参数定义了何时启动新实例,何时终止旧实例;健康检查决定了实例的健康状态。 +- **如果一个EC2实例的健康状态变成“不健康”,那么ASG会终止这个EC2实例,并且自动启动一个新的EC2实例** +- 弹性伸缩组(ASG)只能在某一个AWS区域内运行,不能跨越多个区域 +- 如果启动配置(Launch Configuration)有更新,那么之后启动的新EC2实例会使用新的启动配置,而旧的EC2实例不受影响 +- 从AWS管理平台你可以直接删除一个弹性伸缩组(ASG);从AWS CLI你只能先将最小的性能和需求的性能两个参数设置为0,才能删除这个弹性伸缩组。 + + + +## ECS + +**Amazon Elastic Container Service (ECS)**是一个有高度扩展性的**容器管理服务**。它可以轻松运行、停止和管理集群上的Docker容器,你可以将容器安装在EC2实例上,或者使用**Fargate**来启动你的服务和任务。 + +Amazon ECS可以在一个区域内的多个可用区中创建高可用的应用程序容器,你可以定义集群中运行的Docker镜像和服务。而且你可以充分利用AWS内部的**Amazon ECR (Elastic Container Registry)**或者外部的Registry(比如Docker Hub或自建的Registry)来存储和提取容器镜像。 + + + +我们可以将标准化的代码、运行环境、系统工具等等打包成一个标准的集装箱,这个集装箱叫做**Docker镜像**(Docker Image)。这个Docker镜像的概念类似于EC2中的AMI (Amazon Machine Image)。 + +这些镜像文件通常会通过Dockerfile来构建,并且最终存放到**注册表(Registry)**内。这个Registry可以理解为摆放集装箱的码头,我们在需要某个类型的集装箱的时候就到码头去取。这类Registry可以是Amazon的ECR,也可以是公网上的Docker Hub,或者自己私有的Registry。 + + + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211192204245.png) + +### ECS创建举例 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211192208630.png) + + + +## Lambda + +使用**AWS Lambda**,你无需配置和管理任何服务器和应用程序就能运行你的代码。只需要上传代码,Lambda就会处理运行并且根据需要自动进行横向扩展。因此Lambda也被称为**无服务(Serverless)**函数。 + +要让AWS Lambda的代码执行,需要设定一些触发器(比如CloudWatch Log,CloudWatch Event,API Gateway等),因此Lambda函数被认为是**事件驱动的(Event-Driven)**。 + +在传统的应用部署过程中,我们往往需要安装操作系统 -> 安装应用程序 -> 配置环境并部署代码,而且往往还需要不定时地为操作系统和应用程序打补丁和进行维护。使用AWS Lambda就方便很多,只需要上传代码,AWS就会在需要的时候帮你运行。我们不再需要(也无法接触)任何操作系统层面的东西,也节省了非常多的部署时间,可以更专心地编写代码。 + + + +### AWS Lambda的特点 + +- 没有服务器/无服务,或者说真实的服务器由AWS管理 +- 只需要为运行的代码付费,不需要管理服务器和操作系统 +- **持续性/自动的性能伸缩** +- 非常便宜 +- AWS只会在代码运行期间收取相应的费用,代码未运行时不产生任何费用 +- **代码的最长执行时间是15分钟,如果代码执行时间超过15分钟,则需要将1个代码细分为多个** + +### 触发器有哪些 + +- **API Gateway** +- **AWS IoT** +- **CloudWatch Events** 比如cron job定时任务 +- CloudWatch Logs +- CodeCommit +- DynamoDB +- S3 +- SNS +- Cognito Sync Trigger +- SQS应该也可以? + + + +## 参考 + +[参考](http://www.cloudbin.cn/?tag=aws) + +## Compute选型 + +aws提供两种容器编排服务: ECS和EKS, k是kubernetes。 后者适合已经用了k8s的。 + +AWS fargate就是serverless, ECS/EKS 可集成在Fargate上或者EC2上。 container hosting platform + +Serverless: 允许在服务部署级别而不是服务器部署级别来管理应用部署。类似Faas。无需关注主机管理,服务运维。 + + + +ECS vs EC2 + +- ECS和EKS: aws负责容器管理,但customer依旧需要负责底层的ec2 instances. + +Fargate vs Lambda + +- Fargate is a Container as a Service (CaaS) offering, AWS Lambda is a Function as a Service (FaaS offering). + +Fargate是类似k8s的工具,可以管理容器,进行编排。 + +ECS vs Fargate + +- ECS delivers more control over the infrastructure, but the trade-off is the added management that comes with it. Fargate is the better option for ease of use as it takes infrastructure management out of the equation allowing you to focus on just the tasks to be run. ECS 提供了对基础设施的更多控制,但代价是随之而来的附加管理。Fargate 是易于使用的更好选择,因为它将基础设施管理排除在外,使您可以专注于要运行的任务。 + + + +Serverless vs EC2/ECS: + +- If you want to deploy your workloads and applications without having to manage any EC2 instances, you can do that on AWS with serverless compute. +- Serverless includes fargate, lambda. + + + +Serverless vs Lambda + +- the latter doesn't need the control of container + + + +两个方面 + +- 是否要管理主机 + - Yes: ecs, ec2 + - No: fargate, lambda +- 是否要管理容器,类似k8s的活。 + - Yes: fargate, ecs, ec2. + - No: lambda + + + + + +虚拟机相比容器好处,重要的是资源隔离。 + +- 拥有完整操作系统 +- 异质环境 +- 安全 + +容器好处: + +- 速度和可移植性,启动只有几秒钟,虚拟机要几分钟 +- 可扩展性,通过编排器,自动扩展。 +- 模块化 +- 易于更新。 \ No newline at end of file diff --git a/_posts/Tech/AWS/2022-11-18-AWS MQ.md b/_posts/Tech/AWS/2022-11-18-AWS MQ.md new file mode 100644 index 0000000000..3a848ebd31 --- /dev/null +++ b/_posts/Tech/AWS/2022-11-18-AWS MQ.md @@ -0,0 +1,100 @@ +--- +layout: post +category: AWS +title: AWS MQ +tags: AWS +--- + +## AWS MQ + +## SQS(Simple Queue Service) + +SQS有两种不同类型的队列,它们分别是: + +- **标准队列**(Standard Queue) +- **FIFO队列**(先进先出队列) + +### 标准队列 + +标准队列拥有**无限的吞吐量**,所有消息都会**至少传递一次**,并且它会尽最大努力进行排序。 + +标准队列是默认的队列类型。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211202300608.png) + +### FIFO队列 + +FIFO (First-in-first-out)队列在不使用批处理的情况下,**最多支持300TPS**(每秒300个发送、接受或删除操作)。 + +在队列中的消息都只会**不多不少地被处理一次**。 + +FIFO队列严格保持消息的**发送和接收顺序**。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211202300750.png) + +更多关于标准队列和FIFO队列的区别,可以查看[我需要哪种类型的队列?](https://docs.aws.amazon.com/zh_cn/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html#sqs-queue-types) + +### SQS的其他特点 + +- SQS是靠应用程序去**拉取的**,而不能主动推送给应用程序,推送服务我们使用**SNS(Simple Notification Service)** +- 消息会以256 KB的大小存放 +- 消息会在队列中保存1分钟~14天,默认时间是4天 +- 可见性超时(Visibility Timeout) + - 即当SQS队列收到新的消息并且被拉取走进行处理时,会触发Visibility Timeout的时间。这个消息不会被删除,而是会被设置为不可见,用来防止该消息在处理的过程中再一次被拉取 + - 当这个消息被处理完成后,这个消息会在SQS中被删除,表示这个任务已经处理完毕 + - 如果这个消息在Visibility Timeout时间结束之后还没有被处理完,则这个消息会设置为可见状态,等待另一个程序来进行处理 + - 因此**同一个消息可能会被处理两次(或以上)** + - 这个超时时间最大可以设置为**12小时** +- 标准SQS队列保证了每一个在队列内的消息都至少会被处理一次 +- 长轮询(Long Polling) + - 默认情况下,Amazon SQS使用**短轮询(Short Polling)**,即应用程序每次去查询SQS队列,SQS都会做回应(哪怕队列一直是空的) + - 使用了长轮训,应用程序每次去查询SQS队列,SQS队列不会马上做回应。而是等到队列里有消息可处理时,或者等到设定的超时时间再做出回应。 + - 长轮询可以一定程度减少SQS的花销 + +## SNS (Simple Notification Service) + +**SNS (Simple Notification Service)** 是一种完全托管的发布/订阅消息收发和移动通知服务,用于协调向订阅终端节点和客户端的消息分发。 + +SNS是一项 Web 服务,用于协调和管理向订阅终端节点或客户交付或发送消息的过程。在 Amazon SNS 中有两种类型的客户端:发布者和订阅者,也称为生产者和消费者。发布者通过创建消息并将消息发送至主题与订阅者进行异步交流,主题是一个逻辑访问点和通信渠道。订阅者(即 Web 服务器、电子邮件地址、Amazon SQS 队列、AWS Lambda 函数)在其订阅主题后通过受支持协议(即 Amazon SQS、HTTP/S、电子邮件、SMS、Lambda)中的一种使用或接收消息或通知。 + +我们可以使用SNS将消息推送到SQS消息队列中、AWS Lambda函数或者HTTP终端节点上。 + +SNS通知还可以发送推送通知到IOS,安卓,Windows和基于百度的设备,也可以通过电子邮箱或者SMS短信的形式发送到各种不同类型的设备上。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211202301979.png) + + + +在创建SNS Topic时的一些选项: + +- Encryption: 代表是否对Topic中的消息进行加密。如果需要处理的数据中有敏感信息,应做此设置。 +- Delivery retry policy (HTTP/S): 默认为3,也就说尝试三次后,消息还没有送到的话,就会彻底丢失。因此在使用SNS的时候,一旦出现这种情况,就应该使用DLQ来做容错。 + +### SNS的一些特点 + +- SNS是实时的**推送服务(Push)**,有别于SQS的**拉取服务(Pull/Poll)** +- 拥有简单的API,可以和其他应用程序兼容 +- 可以通过多种不同的传输协议进行集成 +- 便宜、用多少付费多少的服务模型 +- 在AWS管理控制台上就可以进行简单的操作 + +## SNS vs SQS + +AWS提供了[SQS](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/sqs/v2/home)和[SNS](https://link.zhihu.com/?target=https%3A//console.aws.amazon.com/sns/v3/home)。SQS是一个分布式的队列消息service,SNS是一个分布式的发布-订阅消息service。具体有人会问这两者有什么区别,这里给出了回答: [What is the difference between Amazon SNS and Amazon SQS?](https://link.zhihu.com/?target=https%3A//stackoverflow.com/questions/13681213/what-is-the-difference-between-amazon-sns-and-amazon-sqs)。 在我的实践中,SQS和SNS会结合起来使用,首先应用发布消息到SQS的queue里面,然后SNS消费这个queue的消息,放到自身的topic里面持久保存,然后其他的应用订阅这个topic,消费里面的消息。 + + + +sqs是一对一,不能一对多,消息可持久化,不推只能等拉,拉完就删除。 + +sns可一对多,不能持久化,push模型。 + +sqs及aws笔记,更全, [link](http://www.cloudbin.cn/?p=2530) + + + +个人觉得 sns是推 能力的一个抽象。比如推送,mq里的push,都是推。aws把推给抽象出来。就可以让用户像搭积木一样使用。 + + + + + diff --git a/_posts/Tech/AWS/2022-11-18-AWS Storage.md b/_posts/Tech/AWS/2022-11-18-AWS Storage.md new file mode 100644 index 0000000000..bf2a5141d9 --- /dev/null +++ b/_posts/Tech/AWS/2022-11-18-AWS Storage.md @@ -0,0 +1,225 @@ +--- +layout: post +category: AWS +title: AWS Storage +tags: AWS +--- + +## AWS Storage + +## dynamoDB + +[论文讲解](http://systemdesigns.blogspot.com/2016/01/dynamodb.html) + +[深入探讨 Amazon DynamoDB 的设计模 式、流复制和全局表](https://sides-share.s3.cn-north-1.amazonaws.com.cn/AWS+Webinar+2019/PDF/Amazon+DynamoDB+webinar.pdf) + +[官网](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html#Programming.LowLevelAPI.DataTypeDescriptors) + +[AWS 如何实现数据跨区域同步](https://techsummit.ctrip.com/pdf/songye.pdf) + +[MongoDB 与 DynamoDB 正面交锋](https://www.modb.pro/db/432414) + + + +## EBS + +### EBS的特点 + +- 亚马逊EBS卷提供了**高可用、可靠、持续性的块存储**,EBS可以依附到一个正在运行的EC2实例上 +- 如果你的EC2实例需要使用数据库或者文件系统,那么建议使用EBS作为首选的存储设备 +- EBS卷的存活可以脱离EC2实例的存活状态。也就是说在终止一个实例的时候,你可以选择保留该实例所绑定的EBS卷 +- EBS卷可以依附到**同一个可用区(AZ)**内的任何实例上 +- EBS卷可以被加密,如果进行了加密那么它存有的所有已有数据,传输的数据,以及制造的镜像都会被加密 +- **EBS卷可以通过快照(Snapshot)来进行(增量)备份,这个快照会保存在S3 (Simple Storage System)上** +- 你可以使用任何快照来创建一个基于该快照的EBS卷,并且随时将这个EBS卷应用到**该区域**的任何实例上 +- EBS卷创建的时候已经固定了可用区,并且**只能给该可用区的实例使用**。如果需要在其他可用区使用该EBS,那么可以创建快照,并且使用该快照创建一个在其他可用区的新的EBS卷 +- **快照还可以复制到其他的AWS区域** + +### EBS (Elastic Block Storage)小结 + +- EBS的不同类型,需要了解不同类型的EBS主要的使用场景 + - 通用型SSD – GP2 (高达10,000 IOPS),适用于启动盘,低延迟的应用程序等 + - 预配置型SSD – IO1 (超过10,000 IOPS),适用于IO密集型的数据库 + - 吞吐量优化型HDD -ST1,适用于数据仓库,日志处理 + - HDD Cold – SC1 – 适合较少使用的冷数据 + - HDD, Magnetic +- 不能将EBS挂载到多个EC2实例上,一个EBS只能挂载到1个EC2实例上。 + - 如果有共享数据盘的需求,请使用EFS (Elastic File System) +- 根EBS卷默认是不能进行加密的,但可以使用第三方的加密工具(例如BitLocker)对其进行加密 + - *除了根磁盘外的其他卷是可以加密的* + +### EBS快照(Snapshot)小结 + +- *EBS的快照会被保存到S3(Simple Storage System)上* + +- *你可以对一个EBS卷创建一个快照,这个快照会被保存到S3上* + +- 快照实际上是 + + 增量备份 + + ,只有在上次进行快照之后更改的数据才会被添加的S3上 + + - 因此第一次快照所花费的时间比较长 + - 而第二次以后的快照所花费的时间相对短很多 + +- 对加密的EBS卷创建快照,创建后的快照也会是加密的 + +- 从加密的快照恢复的EBS卷也会是加密的 + +- 你可以分享快照给其他账户或AWS市场,但仅限于这个快照是没有进行过加密的 + +- 要为一个作为根设备的EBS卷创建快照的话,建议停止这个实例再做快照 + +### 实例存储(Instance Store) + +- 实例存储也叫做**短暂性存储(Ephemeral Storage)** +- 实例存储的实例不能被停止(只能重启或终止),如果这个实例出现故障,那么在上面的所有数据将会丢失 +- 使用EBS的实例可以被停止,停止后EBS上的数据不会丢失 +- 重启使用实例存储的实例或者重启使用EBS的实例都不会导致数据丢失 + + + +## AWS EBS, S3和EFS的区别 + +- AWS S3对于静态页面的托管、多媒体分发、版本管理、大数据分析、数据存档来说都非常有用。S3可以和AWS CloudFront结合使用而达到更快的上传和下载速度。 +- AWS EBS是可以用来做数据库或托管应用程序的持续性文件系统,EBS具有很高的IO读写速度并且即插即用。 只能被单个EC2实例访问 +- 相比前面两种存储,AWS EFS是比较新的一项服务。它提供了可以在多个EC2实例之间共享的网络文件系统,功能类似于NAS设备。可以用EFS来处理大数据分析、多媒体处理和内容管理。 + +## S3 + +Amazon **Simple Storage Service (S3)** 是互联网存储解决方案,它提供了一个简单的Web接口,让其存储的数据和文件在互联网的任何地方给任何人访问。 + +文件对象存储。 + + + +### S3基本特性 + +- S3是**对象存储**,可以在S3上存储各种类型的文件,它不是**块存储**(EBS是块存储) +- 文件大小可以从0 字节到5 TB + - 使用Single Operation上传只能上传*最大5 GB*的文件 + - 使用分段上传(Multipart Upload)可以对文件进行分段上传,最大支持上传*5 TB*的文件 +- S3的总存储空间是**无限大**的 +- 文件存储在**存储桶(Bucket)**内,可以理解存储桶就是一个文件夹 +- S3的名字是需要**全球唯一**的,不能与任何区域的任何人拥有的S3重名 +- 存储桶创建之后会生成一个URL,命名类似于https://s3-ap-northeast-1.amazonaws.com/aws_xiaopeiqing_com + - **S3是以HTTPS的形式展现的,而非HTTP** + - ap-northeast-1表示了当前桶所在的区域 + - aws_xiaopeiqing_com表示了S3存储桶的名字,全球唯一 +- S3拥有99.99%(4个9)的可用性(Availability) + - 可用性可以理解为系统的uptime时间,即在一个自然年内(365天)有52.56分钟系统不可用 +- S3拥有99.999999999%(11个9)的持久性(Durability) + - 持久性可以认为是数据完整性/数据安全性,即在一千亿个存储在S3上的文件会有大概 1 个文件是不可读的 +- S3的存储桶创建的时候可以选择所在区域(Region),但不能选择可用区(AZ),AWS会负责S3的高可用、容灾问题 + - S3创建的时候可以选择某个AWS区域,一旦选择了就不能更改 + - 如果要在其他区域使用该S3的内容,可以使用**跨区域复制** +- S3拥有不同的等级(Standard, Stantard-IA, Onezone-IA, RRS, Glacier) +- 启用了**版本控制(Version Control)**你可以恢复S3内的文件到之前的版本 +- S3可以开启生命周期管理,对文件在不同的生命周期进行不同的操作 + - 比如,文件在创建30天后迁移到便宜的S3等级(S3-IA),再经过30天进行归档(迁移到Glacier),再过30天就进行删除 +- 要启用生命周期管理需要先启用版本控制功能 +- S3支持加密功能 +- 使用访问控制列表(Access Control Lists)和桶策略(Bucket Policy)可以控制S3的访问安全 +- 在S3上成功上传了文件,你将会得到一个**HTTP 200**的状态反馈 + +### 不同的S3存储类型 + +- **Standard – 默认的存储类:**如果上传对象时未注明则S3会分配这个类型的存储 +- **Standard – IA(Infrequently Accessed):**用于保存不经常访问的数据,但是需要访问的时候也能很快地访问到。存储的价格比标准S3便宜,但是读取的费用比标准的S3高,也因为如此才要把不经常访问的数据放到这种类型的S3上。并且数据跨了多个AWS地理位置。 +- **Intelligent_Tiering** 智能分层(S3 智能分层): 这种储存类别将对象存储在两个访问层中,一个是频繁访问的层,一个是不频繁访问的层;如果对象`30`天内未访问,则会被移动至不频繁访问的层,如果不频繁访问层中的对象被访问,则会被移动至频繁访问的层;频繁访问的层的存储费用与`STANDARD`一样,不频繁访问层的存储费用与`STANDARD_IA`一样,该储存类别的请求费用与`STANDARD`一样,**该储存类别有额外的监控费用**; +- **Onezone – IA:**同上,但数据只保存到一个AWS可用区内 +- **Glacier:**非常便宜,仅用于做归档。从Glacier读取数据需要花费3-5个小时。 +- **Glacier Deep Archive:** S3 Glacier Deep Archive 是 Amazon S3 成本最低的存储类,支持每年可能访问一两次的数据的长期保留和数字预留。它是为客户设计的 – 特别是那些监管严格的行业,如金融服务、医疗保健和公共部门 – 为了满足监管合规要求,将数据集保留 7-10 年或更长时间。S3 Glacier Deep Archive 还可用于备份和灾难恢复使用案例,是成本效益高、易于管理的磁带系统替代,无论磁带系统是本地库还是非本地服务都是如此。S3 Glacier Deep Archive 是 Amazon S3 Glacier 的补充,后者适合存档,其中会定期检索数据并且每隔几分钟可能需要一些数据。存储在 S3 Glacier Deep Archive 中的所有对象都将接受复制并存储在至少三个地理分散的可用区中,受 99.999999999% 的持久性保护,并且可在 12 小时内恢复。 + +## CloudFront CDN + +**Amazon CloudFront**是一种全球**内容分发网络(CDN)**服务,可以安全地以低延迟和高传输速度向浏览者分发数据、视频、应用程序和API。 + + + +- **边缘站点(Edge Location)**:边缘站点是内容缓存的地方,它存在于多个网络服务提供商的机房,它和AWS区域和可用区是完全不一样的概念。截至2018年中,AWS目前一共有100多个边缘站点。 +- **源(Origin)**:这是CDN缓存的内容所使用的源,源可以是一个S3存储桶,可以是一个EC2实例,一个弹性负载均衡器(ELB)或Route53,甚至可以是AWS之外的资源。 +- **分配(Distribution)**:AWS CloudFront创建后的名字 +- 分配分为两种类型,分别是 + - **Web Distribution**:一般的网站应用 + - **RTMP (Real-Time Messaging Protocol)**:媒体流 +- 你不只是可以从边缘站点读取数据,你还可以往边缘站点写入数据(比如上传一个文件),边缘站点会将你写入的数据同步到源上 +- 在CloudFront上的文件会被缓存在边缘节点,缓存的时间是**TTL(Time To Live)**。文件存在超过这个时间,缓存会被自动清除 +- 如果在到达TTL时间之前,你希望更新文件,那么你也可以**手动清除缓存**,但你将会被AWS**收取一定的费用** + +## ES + +AWS ES有两种node + +1. decicated master node 数量只能3-5。Dedicated Master 节点不太可能成为性能瓶颈,因为它们主要负责管理集群状态和协调分片分配等任务,并不会直接处理客户端的读写请求。相反,数据节点才是 AWS ES 集群中的性能瓶颈,因为它们需要实际检索和处理文档数据,对系统资源的消耗较大。 +2. 普通node,和es一样。 + +每个node都有存储的一个限制。node数量增加,则性能增加。 + +## Multi-AZ高可用 + +是多个AZ里配置一个主,其它从,类似同城多机房架构。 + + + +我们可以把AWS RDS数据库部署在多个**可用区(AZ)**内,以提供高可用性和故障转移支持。 + +使用Multi-AZ部署模式,RDS会在不同的可用区内配置和维护一个主数据库和一个备用数据库,主数据库的数据会自动复制到备用数据库中。 + +使用这种部署模式,可以为我们提供数据冗余,减少在系统备份期间的I/O冻结(上面有提到)。同时,更重要的是可以防止数据库实例的故障和单个可用区的故障。 + +如下图所示,我们可以在两个可用区内分别部署主数据库和备用数据库。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211192338177.png) + +目前Multi-AZ支持以下数据库: + +- Oracle +- PostgreSQL +- MySQL +- MariaDB +- SQL Server + +值得注意的是,Aurora数据库本身就支持多可用区部署的高可用设置,因此不需要为Aurora数据库特别开启这个功能。 + +在上次实验中我们有讲到,创建了RDS数据库之后我们会得到一个数据库的URL Endpoint。在开启Multi-AZ的情况下,这个URL Endpoints会根据主/备数据库的健康状态自动解析到IP地址。对于应用程序来说,我们只需要连接这个URL地址即可。 + +**高可用的设置只是用来解决灾备的问题,并不能解决读取性能的问题;要提升数据库读取性能,我们需要用到Read Replicas。** + + + +### 只读副本(Read Replicas) + +我们可以在源数据库实例的基础上,复制一种新类型的数据库实例,称之为**只读副本(Read Replicas)**。我们对源数据库的任何更新,都会**异步**更新到只读副本中。 + +因此,我们可以将应用程序的数据库读取功能转移到Read Replicas上,来减轻源数据库的负载。 + +对于有大量读取需求的数据库,我们可以使用这种方式来进行灵活的数据库扩展,同时突破单个数据库实例的性能限制。 + +Read Replicas还有如下的特点: + +- Read Replicas是用来提高读取性能的,不是用来做灾备的 +- 要创建Read Replicas需要源RDS实例开启了自动备份的功能 +- 可以为数据库创建最多**5个**Read Replicas +- 可以为Read Replicas创建Read Replicas(如下图所示) +- 每一个Read Replicas都有自己的URL Endpoint +- 可以为一个启用了Multi-AZ的数据库创建Read Replicas +- Read Replicas可以提升成为独立的数据库 +- 可以创建位于另一个区域(Region)的Read Replicas + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211192340392.png) + +目前Read Replicas支持以下数据库: + +- Aurora +- PostgreSQL +- MySQL +- MariaDB +- Oracle + +https://amazonaws-china.com/cn/rds/details/read-replicas/ + +## 参考 + +[参考](http://www.cloudbin.cn/?p=1968) diff --git a/_posts/Tech/AWS/2022-11-26-AWS DynamoDB.md b/_posts/Tech/AWS/2022-11-26-AWS DynamoDB.md new file mode 100644 index 0000000000..821e551848 --- /dev/null +++ b/_posts/Tech/AWS/2022-11-26-AWS DynamoDB.md @@ -0,0 +1,142 @@ +--- +layout: post +category: AWS +title: AWS DynamoDB +tags: AWS +--- + +## 表、索引 + +> [深入探讨 Amazon DynamoDB 的设计模 式、流复制和全局表](https://sides-share.s3.cn-north-1.amazonaws.com.cn/AWS+Webinar+2019/PDF/Amazon+DynamoDB+webinar.pdf) + +![image-20221126172356212](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211261723281.png) + +分区键和排序键共同唯一的标识一条记录 + +本地二级索引 Local Secondary Index (LSI) 单表上的。可以选择与表不同的排序键。同一个分区键。强一致性更新。 + + +全局二级索引 - Global Secondary Index (GSI) 可以选择与表不同的分区键以及排序键 每个索引分区会对应所有的表分区 + + + +![image-20221126172812498](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211261728526.png) + + + +对比 + +- Global Secondary + - 索引的尺寸没有上限 + - 读写容量和表是独立的 + - 只支持最终一致性 +- Index Local Secondary Index + - 索引保存在表的分区中,因此一个表 分区的尺寸的上限是10GB + - 使用的是表上定义的RCU和WCU + - 强一致性 + +索引指向的是实际存储,可以理解为空间指针。并不是数据的拷贝。像mysql B树指向主键一样。 + +## 实现 + +> [论文讲解](http://systemdesigns.blogspot.com/2016/01/dynamodb.html) + +Dynamo在某些故障的场景中将牺牲一致性。 + +Dynamo的系统假设和要求: +1)query model:对数据项简单的读,写是通过一个主键唯一性标识。状态存储为一个由唯一性键确定二进制对象。没有横跨多个数据项的操作,也不需要关系方案(relational schema)。这项规定是基于观察相当一部分Amazon的服务可以使用这个简单的查询模型,并不需要任何关系模式。Dynamo的目标应用程序需要存储的对象都比较小(通常小于1MB)。 + +2)ACID属性:ACID是一种保证数据库事务可靠地处理的属性。在数据库方面的,对数据的单一的逻辑操作被称作所谓的交易。Amazon的经验表明,在保证ACID的数据存储提往往有很差的可用性。Dynamo的目标应用程序是高可用性,弱一致性(ACID“中的C”)。Dynamo不提供任何数据隔离(Isolation)保证,只允许单一的关键更新。 + +3)efficiency:系统需运作在一般的commodity hardware上。Amazon平台的服务都有着严格的延时要求, 鉴于对状态的访问在服务操作中起着至关重要的作用,存储系统必须能够满足那些严格的SLA,服务必须能够通过配置Dynamo,使他们不断达到延时和吞吐量的要求。因此,必须在成本效率,可用性和耐用性保证之间做权衡。 + + + +提供get, put操作。 + + + +最终一致性。 + +### Partition + +按key做partition, 一致性Hash。 + +### Replication + +replica, 复制,用了NWR,让用户做一致性的选择。读数据时如果有不同版本,会所有版本数据都返回回去。 + +### Data Versioning + +多版本。Vector Clock 一个Vector Clock可以理解为一个<节点编号,计数器>对的列表。每一个版本的数据都会带上一个Vector Clock。Dynamo中,最重要的是要保证写操作的高可用性,即“Always Writeable”,这样就不可避免的牺牲掉数据的一致性。如上所述,Dynamo中并没有对数据做强一致性要求,而是采用的最终一致性(eventual consistency)。若不保证各个副本的强一致性,则用户在读取数据的时候很可能读到的不是最新的数据。Dynamo中将数据的增加或删除这种操作都视为一种增加操作,即每一次操作的结果都作为一份全新的数据保存,这样也就造成了一份数据会存在多个版本,分布在不同的节点上。这种情况类似于版本管理中的多份副本同时有多人在修改。多数情况下,系统会自动合并这些版本,一旦合并尝试失败,那么冲突的解决就交给应用层来解决。这时系统表现出来的现象就是,一个GET(KEY)操作,返回的不是单一的数据,而是一个多版本的数据列表,由用户决定如何合并。这其中的关键技术就是Vector Clock。 + + + +其实就是读修复。 + +### Failure Detection + +临时性故障,采用Hinted Handoff提示移交机制 + +为防止要写入节点宕机导致操作失败,采用提示移交机制将操作相关数据写入到随机节点,宕机节点恢复后可根据这些数据进行重放,最终获得数据一致性。 + + + + 以N=3为例,如果在一次写操作时发现节点A挂了,那么本应该存在A上的副本就会发送到D上,同时在D中会记录这个副本的元信息(MetaData)。其中有个标示,表明这份数据是本应该存在A上的,一旦节点D之后检测到A从故障中恢复了,D就会将这个本属于A的副本回传给A,之后删除这份数据。Dynamo中称这种技术为“Hinted Handoff”。 + + + +另外为了应对整个机房掉线的故障,Dynamo中应用了一个很巧妙的方案。每次读写都会从”Preference List”列表中取出R或W个节点。那么只要在这个列表生成的时候,让其中的节点是分布于不同机房的,自然数据就写到了不同机房的节点上。 + + + +对于某节点非临时性故障,利用反熵得到丢失数据进行恢复。一些数据存储有后台进程,不断查找副本之间的数据差异,将任何缺少的数据从一个副本复制到另一个副本。和基于主节点复制的复制日志不同,此反熵过程不保证任何特定的顺序复制写入,并且会引入明显的同步滞后 + + + +## 事务 + +> [官网wiki](https://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/transactions.html) + +支持事务,所有操作必须成功完成,否则不会进行任何更改。 + +隔离级别: + +1. 可序列化 +2. 读已提交 + + + +## 其他 + + + +> [官网](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html#Programming.LowLevelAPI.DataTypeDescriptors) + +begin_with这个操作要记得。其他后面看。begin_with是字符串前缀匹配,应该用了字典树等加速。 + + + +> [AWS 如何实现数据跨区域同步](https://techsummit.ctrip.com/pdf/songye.pdf) + +没啥子东西,数据操作优先同区域内,主要靠复制。 + + + +> [MongoDB 与 DynamoDB 正面交锋](https://www.modb.pro/db/432414) + +没啥东西 + + + +> [通俗易懂之DynamoDB(一) ----分区键、排序键、GSI](https://zhuanlan.zhihu.com/p/101965292) + +**getItem、query和scan** + +这三个操作都是查询操作,效率分别是:getItem > query > scan + +getItem是根据primary key进行查询,可以理解为通过primary key在hashMap上查询,速度是最快的,缺点是必须知道primary key且只能查询单个,使用情况相对较少。 + +scan是全表扫描,是最慢的一个,理论上能不用就不用,只有实在走投无路才考虑全表扫描。 + +query是最常见的方式,在dynamoDB的使用中,我们唯一的目的就是写出高效的查询query。 diff --git a/_posts/Tech/AWS/2022-12-14-AWS CloudWatch.md b/_posts/Tech/AWS/2022-12-14-AWS CloudWatch.md new file mode 100644 index 0000000000..38746d77c0 --- /dev/null +++ b/_posts/Tech/AWS/2022-12-14-AWS CloudWatch.md @@ -0,0 +1,19 @@ +--- +layout: post +category: AWS +title: AWS CloudWatch +tags: AWS +published: false +--- + +## AWS CloudWatch + +主要是Dashboard, metrics, alarms等。 + +metrics的dimension不能用in操作。只能取1个或者不取。 + + + +## 待更新 + +期待后续... diff --git a/_posts/Tech/AWS/2023-02-09-AWS IAM.md b/_posts/Tech/AWS/2023-02-09-AWS IAM.md new file mode 100644 index 0000000000..9329ff06ec --- /dev/null +++ b/_posts/Tech/AWS/2023-02-09-AWS IAM.md @@ -0,0 +1,346 @@ +--- +layout: post +category: AWS +title: AWS IAM +tags: AWS +--- + +## AWS IAM + + + +首先要知道, AWS 提供了许许多多种类的服务或者说资源供我们使用, 这些资源挂在我们的 AWS 账户下, 这个账户就是我们第一次用 AWS 时用邮箱和密码申请的, 以后我们所有的资源申请, 账单费用都会挂到这个户头. + +那么 IAM 算什么呢? IAM 不是 AWS 的专有名词, 它是一个通用概念, 全称是 Identity and Access Management, 其要解决的两个问题就是身份认证 (Authtication) 和授权 (Authorization). 为此 AWS IAM 设计了用户, 角色, 用户组, 权限策略等概念和机制 + + + +IAM (Identity Access Management) 由这些东西组成: + +- Users +- Groups 用户组 +- Roles 角色可以分配给AWS服务,让AWS服务有访问其他AWS资源的权限。 举个例子,我们可以赋予EC2实例一个角色,让其有访问S3的读写权限(后面课程会有关于这一点的实操) +- Policy Documents 策略。 策略具体定义了能访问哪些AWS资源,并且能执行哪些操作(比如List, Read, Write等) 策略的文档以JSON的格式展现 + +``` +// An example policy: allowing any access to any resource +{ + "Version": "2012-10-17" + "Statement": [ + { + "Effect": "Allow", + "Action": "*", + "Resource": "*" + } + ] +} +``` + + + +IAM 是 Global的,不属于任何一个 region + + + + + +## IAM Entities + +首先 IAM 为了能够同时照顾到 “人” 和 “非人“ 这两类资源访问者, 使用了一个概念叫做 Entity(实体), 目前 IAM 里有两种 Entity: IAM User 和 IAM Role. 一般来说公司可以为每个程序员创建一个 IAM User 的实体, 让他们能够访问 AWS Console做一些权限之内的事情; 而对于非人的程序, 一般的实践则是创建 IAM Role, 然后令这程序 “假装”(Assume) 这个角色, 这样它就有了这个角色的权限, 一个 IAM Role 可以让很多程序一起假装, 不过要想假装 Role 的话, 必须得是 AWS 里的资源才行, 这是当然的, 像上面第三个例子, 公网的设备想访问我们的存储资源, 首先要通过 API Gateway, 由 API Gateway 来完成这个假装动作. + +## Users + +在 AWS 里,一个 IAM user 和 unix 下的一个用户几乎等价。你可以创建任意数量的用户,为其分配登录 AWS management console 所需要的密码,以及使用 AWS CLI(或其他使用 AWS SDK 的应用)所需要的密钥。你可以赋予用户管理员的权限,使其能够任意操作 AWS 的所有服务,也可以依照 Principle of least privilege,只授权合适的权限。下面是使用 AWS CLI 创建一个用户的示例: + +``` +saws> aws iam create-user --user-name tyrchen +{ + "User": { + "CreateDate": "2015-11-03T23:05:05.353Z", + "Arn": "arn:aws:iam:::user/tyrchen", + "UserName": "tyrchen", + "UserId": "AIDAISBVIGXYRRQLDDC3A", + "Path": "/" + } +} +``` + +当然,这样创建的用户是没有任何权限的,甚至无法登录,你可以用下面的命令进一步为用户关联群组,设置密码和密钥: + +``` +saws> aws iam add-user-to-group --user-name --group-name +saws> aws iam create-login-profile --user-name --password +saws> aws iam create-access-key --user-name +``` + +IAM User 创建了之后, 就可以将这个实体给到某个员工让他使用, 第一次给员工时可能是将用户名和初始密码告知他, 员工登陆后可以自行修改密码. 这里用户名 + 密码就是这个 IAM User 的认证信息 (Credentials), 不过 Credentials 可不光是只有用户名 + 密码这一种形式, 还可以是 Access Key ID + Secret Acces Key 的形式, 更进一步的, 还可以是 MFA 的形式. 用户名 + 密码一般用于员工认为登陆 AWS Console 界面, Access Key 则一般用于 AWS CLI, 用户脚本这种程序访问方式. 用户或者程序通过提供 Credentials 来向 AWS IAM 证明自己, 获得合法身份 (Identity), IAM 根据这个身份来做进一步的权限审查. + + + +## Groups + +群组(groups)也等同于常见的 unix group。将一个用户添加到一个群组里,可以自动获得这个群组所具有的权限。在一家小的创业公司里,其 AWS 账号下可能会建立这些群组: + +- Admins:拥有全部资源的访问权限 +- Devs:拥有大部分资源的访问权限,但可能不具备一些关键性的权限,如创建用户 +- Ops:拥有部署的权限 +- Stakeholders:拥有只读权限,一般给 manager 查看信息之用 + +还需要为其添加 policy: + +`saws> aws iam attach-group-policy --group-name --policy-arn` + +在前面的例子和这个例子里,我们都看到了 ARN 这个关键字。ARN 是 Amazon Resource Names 的缩写,在 AWS 里,创建的任何资源有其全局唯一的 ARN。ARN 是一个很重要的概念,它是访问控制可以到达的最小粒度。在使用 AWS SDK 时,我们也需要 ARN 来操作对应的资源。 + + + +群组中授权增加、删除或者修改时,这些变更都会适用于所有用户。有些时候最好不要将授权直接分配给用户。 + +## Roles + +角色(roles)类似于用户,但没有任何访问凭证(密码或者密钥),它一般被赋予某个资源(包括用户) + +role都是短期凭证。 + + + +对于非人的程序, 一般的实践则是创建 IAM Role, 然后令这程序 “假装”(Assume) 这个角色, 这样它就有了这个角色的权限, 一个 IAM Role 可以让很多程序一起假装, 不过要想假装 Role 的话, 必须得是 AWS 里的资源才行 + + + +Credentials 就是认证信息,比如用户名+密码 或者AccessID + Secret Access Key等。 + +在 Credentials 这一点上, IAM Role 和 IAM User 不同, 因为 IAM Role 没有 Credentials, 或者准确地说是没有固定的 Credentials, 实际上当假装一个角色来获得对某资源的访问权时, 临时的 Credentials 会被生成, 但这是 AWS IAM 底层的实现机理, 从用户这一面上从来不需要操心配置角色的 Credentials, 所以我们就可以按照角色没有 Credentials 来理解. 至于为什么角色没有 Credentials, 那是因为角色只能由 AWS 自身的其他资源所假装, 比如由 EC2, Lambda 来假装, 而当你已经取得了这些资源的操作权限时, 你实际上已经通过 IAM User 的用户名密码或者 Access Key 证明了自己的身份, 所以再假装某个角色的时候, 就不需要再证明身份了. + +虽然说我们部署在 EC2 里的程序, 一般是通过假装角色来获得对某资源的访问权限, 但是 AWS IAM 并不关心你创建的 IAM User 是给人用还是给程序用, 我们给程序创建一个 IAM User, 然后将其 Access Key 嵌到程序代码中令其获得对资源的访问权限也是可以的. 我们可以根据自己的场景灵活决定. + + + +场景 + +1. 自己公司的员工想访问 AWS Console 查看所在项目组的基础设施 + 1. AWS User. 可以通过Group管理。 +2. AWS 账户里的 EC2/Lambda 实例想访问同账户下的一台 RDS + 1. 给EC2添加Role。User也行,但要AK,SK啥的不方便 +3. 公网里用户的手机想要访问我们的后端存储(借助 API Gateway) + 1. 借助API Gateway, 给它加Role + + + +AWS IAM 并不关心你创建的 IAM User 是给人用还是给程序用。 + + + +另外 角色也可以给User, 但基本都是使用角色进行跨账户访问。 系统管理员可以创建角色,在一个账户中授权给用户,可以在另一个账户中访问资源。 + + + +那权限挂在User上还是角色上?可以看下面这个例子。角色不该轻易给User。 + +一个用户可能在应用中将数据存储到AWS S3 bucket中。为了保护应用数据的完整性,用户并没有被给予授权来直接对bucket进行编写。在这样的例子中,在运行应用的AWS EC2实例中使用角色将有助于分配授权。 + + + +一个lambda or 一个ecs只能有一个执行角色。可以lambda里的configration里看到。除了这个执行角色添加policy,也可以assume成其它role,但一次只能assume成一个。可以通过API手动切换。 + + + +## Root User + +Root 账号是你第一次配置账号的时候创建的,它拥有完全的 Admin aceess + +新 User 刚创建时是没有权限的。 + +AWS 官方建议 root 用户的唯一用途, 就是[用来创建你的第一个 IAM 用户](https://link.zhihu.com/?target=https%3A//docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html%23lock-away-credentials), 把这第一个 IAM 用户设置为管理员, 然后以后的工作都用这个管理员用户来进行. + + + +## 策略 policy document + +AWS 下的权限都通过 policy document 描述 + +IAM 策略可以直接附加到用户、组或角色上。 + +policy 是用 JSON 来描述的,主要包含 Statement,也就是这个 policy 拥有的权限的陈述,一言以蔽之,即:**谁**在什么**条件**下能对哪些**资源**的哪些**操作**进行**处理**。也就是所谓的撰写 policy 的**PARCE**原则: + +- Principal:谁 主体指代一个用户、角色或 AWS 服务,这些主体可以请求访问 AWS 资源。 +- Action:哪些操作 +- Resource:哪些资源 +- Condition:什么条件 +- Effect:怎么处理(Allow/Deny) + + + +一个 IAM policy 包含一个或多个 JSON 对象,每个对象都包含一个 policy 的名称和一个 policy 的定义。这个定义通常包含了一个或多个 Statement 对象,每个 Statement 定义了一组操作、资源和条件,以及授予或拒绝这些操作的效果。**看起来,其实就是一个策略是多个json文件,每个json文件就下面有一个Version这样的json。** + +​ + +下面讲讲 policy 的执行规则,它也是几乎所有访问控制方案的通用规则: + +- 默认情况下,一切资源的一切行为的访问都是 Deny +- 如果在 policy 里显式 Deny,则最终的结果是 Deny +- 否则,如果在 policy 里是 Allow,则最终结果是 Allow +- 否则,最终结果是 Deny + + + +我们看一个允许对 S3 进行只读操作的 policy: + +``` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:Get*", + "s3:List*" + ], + "Resource": "*" + } + ] +} +``` + +其中,Effect 是 Allow,允许 policy 中所有列出的权限,Resource 是`*`,代表任意 S3 的资源,Action 有两个:`s3:Get*`和`s3:List*`,允许列出 S3 下的资源目录,及获取某个具体的 S3 Object。 + +在这个 policy 里,Principal 和 Condition 都没有出现。如果对资源的访问没有任何附加条件,是不需要 Condition 的;而这条 policy 的使用者是用户相关的 principal(users, groups, roles),当其被添加到某个用户身上时,自然获得了 principal 的属性,所以这里不必指明,也不能指明。 + + + +policy支持variable. 允许用户在 policy 里使用 AWS 预置的一些变量,比如`${aws:username}`。 可以实现用户只能访问S3自己文件夹这样的能力。 + +一个角色可以attach多个policy。 + + + +## 信任策略 + +> A want to assume as B. 信任策略加在B上。 + +在AWS中,当实体A需要访问某些资源,但没有直接访问这些资源的权限时,可以通过Assume Role操作来获取一个临时凭证,该凭证赋予实体A访问资源的权限。在这种情况下,实体A必须信任另一个实体B,以便它可以Assume Role操作,并且只有在实体B的策略允许时,才能访问资源。 + + + +此时A的信任关系里有B。B有个assumeRole的policy。信任关系决定了谁可以assume成它。 + +总之,IAM的信任关系是AWS中的一种授权机制,用于允许一个实体代表另一个实体访问资源,并确保只有授权的实体可以访问这些资源。 + + + +## AssumeRole policy配置 + +> A want to assume as B. assume policy加在A上。 +> +> 所以实际上,A和B都需要加,一个是policy,一个是信任策略的policy. refer: https://nelson.cloud/aws-iam-allowing-a-role-to-assume-another-role/ + +AssumeRole 权限是一种 IAM 权限,用于授予 IAM 实体(如 IAM 用户或角色)调用 `AssumeRole` API 的权限。通过调用 `AssumeRole` API,实体可以获取其他 IAM 角色的权限并扮演该角色,从而访问该角色可访问的 AWS 资源。 + + + +**使用场景** + +1. 跨账户访问资源:AssumeRole 可以用于授予一个 AWS 账户中的 IAM 实体(如 IAM 用户或角色)访问另一个 AWS 账户中的资源的权限。 +2. 使用跨服务角色:如果您在一个服务中运行了一个应用程序,该应用程序需要访问另一个 AWS 服务中的资源,但是您不想直接授予该应用程序访问该服务的权限,可以使用 AssumeRole 为应用程序创建一个跨服务角色。该角色可以通过 AssumeRole API 访问该服务,并且您可以在角色策略中限制访问该服务的权限。 + + + +[参考](https://nelson.cloud/aws-iam-allowing-a-role-to-assume-another-role/) + +同账号 + +- B增加trust relationship即可 + +不同账号 + +- B增加trust relationship +- A增加policy。 + + + +一次至多只能assume成一个角色,只能调用api来assume。 + + + +## Best Practices + +每年的[ AWS re:invent ](https://reinvent.awsevents.com/)大会,都会有一个 session:Top 10 AWS IAM Best Practices,感兴趣的读者可以去[ YouTube 搜索](https://www.youtube.com/results?search_query=Top+10+AWS+IAM+Best+Practices)。[ 2015 年的 top 10(top 11)](https://www.youtube.com/watch?v=_wiGpBQGCjU)如下: + +1. users: create individual users +2. permissions: Grant least priviledge +3. groups: manage permissions with groups +4. conditions: restrict priviledged access further with conditions +5. auditing: enable cloudTrail to get logs of API calls +6. password: configure a strong password policy +7. rotate: rotate security credentials regularly. +8. MFA: enable MFA (Multi-Factor Authentication) for priviledged users +9. sharing: use IAM roles to share access +10. roles: use IAM roles for EC2 instances +11. root: reduce or remove use of root + +这 11 条 best practices 很清晰,我就不详细解释了。 + +按照上面的原则,如果一个用户只需要访问 AWS management console,那么不要为其创建密钥;反之,如果一个用户只使用 AWS CLI,则不要为其创建密码。一切不必要的,都是多余的——这就是安全之道。 + + + +一个由来已久的信息安全原则就是用户应该且只能拥有他们执行的职责的授权。这也就是最小授权原则,旨在最小化可信用户对于信息系统产生的不利影响。 + +在授权给群组时,也应该使用最小授权。只授权给有需要的群组的成员。如果一些群组成员需要额外的授权,然后创建额外的群组,并为他们分配额外的授权。需要额外授权的用户可以分配到这两个群组中。IAM群组和角色可以让系统管理员按需为用户和应用授权。 + + + +## 总结 + +- 定义群组管理类似的用户。用户都是需要密码等认证的。 + +- 用户上没有policy,都通过群组管理 + +- 定义角色保护应用,比如只想某EC2访问,就给EC2加角色,而不是加User上。 + +- 角色比User的一个好处就是不需要认证信息,因为本身就是AWS自带认证信息。所以给非人的资源一般都是角色。当然EC2也可以是User,访问时需要AK,SK啥的,不如角色方便。 + +- 角色分给User目的就是使用角色进行跨账户访问。 + +- User的credential 两种: 用户名+密码, ak+sk。角色不需要这类东西,自己天然就带了,像psm一样。 + +- IAM策略可以分配给AWS账号、IAM用户、IAM组、IAM角色等AWS资源。 + +- cdk里ecs要发sns,需要给ecs授权。cdk里可以把sns topic传入ecs,然后把ecs service那个role(只有1个),grant相应权限即可。一个EC2只能有一个执行角色。 + +- 让另一个aws账号的sqs订阅当前账号的sns加权限时,可以直接给另一个aws account加权限。sns有access policy + +- 账号A的ddb暴露给账号b的服务c,可以账号A里创建一个角色,然后创建一个Policy, grant c the role.即principle是c。 + +- 一个lambda只能有一个执行角色,不能同时有多个。但可以通过assumeAPI手动切换,意味着每次都切换因此不合理。所以直接操作执行角色授予权限就行,可以IAM里配置执行角色assume成其他。 + +- 一个 IAM 角色可以通过 AssumeRole API 来同时 assume 多个角色,从而获取这些角色的权限。这种做法称为角色链 (Role chaining)。直接看上面AssumeRole部分。 + +- SQS access policy如果只有一个Id,那就是defaultPolicy。Amazon SQS 默认的访问策略(access policy)不包含任何明确的权限规则,它允许任何 AWS 账户中的任何用户对队列进行读写操作。但注意,lambda执行角色还需要添加消费的权限,例如,为 Lambda 函数执行角色添加`AmazonSQSFullAccess`策略。相当于权限都是两方的,两个都需要愿意才行。 + + + +许多 AWS 服务都支持单独的执行角色,这些角色允许服务执行操作而不需要使用您的 AWS 凭证。以下是一些支持单独执行角色的常见 AWS 服务: + +- Amazon EC2:实例角色 +- AWS Lambda:执行角色 +- Amazon ECS:任务角色 +- Amazon EKS:服务角色 +- Amazon S3:存储桶策略 +- Amazon SQS:队列策略 +- Amazon SNS:主题策略 +- Amazon Kinesis Data Streams:流策略 +- Amazon RDS:实例角色 +- Amazon Redshift:集群 IAM 角色 + +这些执行角色通常是与 AWS Identity and Access Management (IAM) 配合使用的,它们允许您授予 AWS 服务和资源执行所需操作的最小权限,从而提高安全性和可管理性。此外,许多服务还提供了自定义权限策略,以便您更精细地控制执行角色的权限。 + + + + + +## 参考 + +- [AWS 系列:深入了解 IAM 和访问控制](https://www.infoq.cn/article/aws-iam-dive-in) + +- [AWS IAM 深入理解](https://zhuanlan.zhihu.com/p/432934574) \ No newline at end of file diff --git a/_posts/Tech/AWS/2023-02-10-AWS Cloudformation And CDK.md b/_posts/Tech/AWS/2023-02-10-AWS Cloudformation And CDK.md new file mode 100644 index 0000000000..1029d6d231 --- /dev/null +++ b/_posts/Tech/AWS/2023-02-10-AWS Cloudformation And CDK.md @@ -0,0 +1,149 @@ +--- +layout: post +category: AWS +title: AWS Cloudformation And CDK +tags: AWS +--- + +# AWS Cloudformation + +cloudFormation以yaml文本的形式记录下一个应用涉及到的各个服务资源配置,放在一个template里面。迁移到不同的region时,只需要一键run coudFormation template, 就可以部署好所有的AWS资源。 + +也叫AWS 堆栈 + +## 为什么使用 CloudFormation? + +**基础设施即代码:**CloudFormation 使我们只用一个步骤就可以创建一个“资源堆栈”。资源是我们创建的东西(EC2 实例、VPC、子网等等),一组这样的资源称为堆栈。我们可以编写一个模板,使用它可以很容易地按照我们的意愿通过一个步骤创建一个网络堆栈。这比通过管理控制台或 CLI 手动创建网络更快,而且可重复,一致性更好。我们可以将模板签入源代码控制,并在任何时候根据需要把它用于任何目的。 + + + +**可升级:**我们可以通过修改 CloudFormation 模板来修改网络堆栈,然后根据修改后的模板修改堆栈。CloudFormation 足够智能,可以通过修改堆栈来匹配模板。 + + + +**可重用**:我们可以重用这个模板,在不同时期、不同区域创建多个不用用途的网络。 + + + +**漂移检测:**CloudFormation 有一个新特性(截止到 2018 年 11 月),可以让我们知道资源是否已经“漂移”出了最初的配置。这可能发生在管理员手动更改资源时,这通常不是成熟的组织所鼓励的做法。 + + + +**用完即弃:**我们很容易在用完之后把堆栈删除。 + + + +## 使用 + +CloudFormation 支持 JSON 或 YAML,我们将使用后者。主要原因是:1)句法不那么讲究,2)能够在工作中添加注释 + +比如一个[VPC示例](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc.html) + +然后AWS控制台。 登录,选择任何区域。在菜单中找到 CloudFormation,如果需要的话,使用搜索功能。登入后,点击“创建堆栈”。选择“上传你自己的模板”选项,然后单击“下一步”。就可以创建堆栈了,还可以看到事件和资源。 + +这些事件将显示你的 VPC 是在什么时候创建的,以及它是在什么时候成功创建的。当堆栈中的最后一个资源被创建时,堆栈的状态将更改为已成功创建。 + +有一个重要的概念需要注意,如果在创建堆栈时遇到任何错误,整个堆栈(所有资源)将回滚。这种行为可以被重写,但通常这样就行!通常情况下,从头开始执行每一步要容易得多。 + +如果堆栈失败,它仍然会显示在堆栈列表中,即使堆栈中没有资源。这样做是为了给你时间来调查错误。确定问题后,使用“删除堆栈”操作。 + +## 参考 + +- [AWS CloudFormation简介](https://juejin.cn/post/7122039768124227614) + +- [如何使用 CloudFormation 构建 VPC(第一部分)](https://www.infoq.cn/article/hsaedm*2we5jmh9tfjeg) + +# CDK + + AWS **Cloud Development Kit** + + + +The AWS Cloud Development Kit (CDK) provides some of the same benefits of CloudFormation but with a few key differences. + +The CDK is an infrastructure-as-code solution that you can use with several popular programming languages. In other words, it's like CloudFormation, but using a language you already know. The CDK also contains command line tools to create infrastructure-as-code templates and to instantiate, update, and tear down stacks. + + + +CDK和Cloud Formation很像,但一个区别是它可以用自己知道的一个语言,比如typescript来写这样。 + +CDK 把 CloudFormation 抽象了一层。它使用 TypeScript 等程序语言,把 CloudFormation 的模板包装成了一个领域专用语言(domain-specific language),CDK 的编译器会把这个语言再转译成 CloudFormation 模板。 + +CDK更好用。但底层实际也是CloudFormation。 + + + +CDK 教程: [官网](https://aws.amazon.com/cn/getting-started/guides/setup-cdk/module-three/?trk=31aeab24-3bd8-472c-a670-df09849e33f8&sc_channel=el) + +**cdk deploy** 命令会将您的 TypeScript 编译为 JavaScript,同时创建一个 CloudFormation 更改集来部署此更改。 + + + +## CDK教程 + +### cdk命令 + +```scala +cdk diff compare deployed stack with current state 将指定的堆栈及其依赖关系与已部署的堆栈或本地 CloudFormation 模板进行比较 + +cdk deploy 命令会将您的 TypeScript 编译为 JavaScript,同时创建一个 CloudFormation 更改集来部署此更改。 deploy this stack to your default AWS account/region + +cdk synth emits the synthesized CloudFormation template +cdk init --language typescript +cdk list (ls) 列出应用程序中的堆栈 +``` + +cdk bootstrp只有在用一些kms等特殊资源时才有用 + + + + + +自定义ts主要在lib文件夹中。 + +## 基础设施 + + + +在深入探讨代码的编写之前,我们需要解释和安装 **[AWS CDK 构造库模块](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html)**。 构造可以代表单个 AWS 资源,例如 Amazon Simple Storage Service(Amazon S3)存储桶,也可以是由多个 AWS 相关资源组成的更高级别的抽象。 AWS 构造库由几个模块组成。 对于本教程,我们需要 Amazon EC2 模块,该模块中还包括对 Amazon VPC 的支持。 + +要安装 Amazon EC2 模块,我们将使用 **npm**。 在项目目录中运行以下命令: + +```bash +npm install @aws-cdk/aws-ec2 +``` + +该命令安装所有必需的模块。如果查看您的 **package.json** 文件,就会看到该文件也添加到此处。 + + + +事例code + +```scala +import * as cdk from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +// import * as sqs from 'aws-cdk-lib/aws-sqs'; + +export class CdkDemoStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + // The code that defines your stack goes here + // We have created the VPC object from the VPC class + new ec2.Vpc(this, 'mainVPC', { + // This is where you can define how many AZs you want to use + maxAzs: 2, + // This is where you can define the subnet configuration per AZ + subnetConfiguration: [ + { + cidrMask: 24, + name: 'public-subnet', + subnetType: ec2.SubnetType.PUBLIC, + } + ] + }); + } +} +``` + diff --git "a/_posts/Tech/Algorithms/2018-01-18-\345\210\206\346\236\220\346\227\266\351\227\264\345\244\215\346\235\202\345\272\246.md" "b/_posts/Tech/Algorithms/2018-01-18-\345\210\206\346\236\220\346\227\266\351\227\264\345\244\215\346\235\202\345\272\246.md" index 85488e17cd..4025af158b 100644 --- "a/_posts/Tech/Algorithms/2018-01-18-\345\210\206\346\236\220\346\227\266\351\227\264\345\244\215\346\235\202\345\272\246.md" +++ "b/_posts/Tech/Algorithms/2018-01-18-\345\210\206\346\236\220\346\227\266\351\227\264\345\244\215\346\235\202\345\272\246.md" @@ -20,8 +20,6 @@ T(n) = n^klogn if k==log(b)a [递归的时间复杂度分析](https://blog.csdn.net/qq_36582604/article/details/81661236) - - 我们先看下面这个例子 ![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv2/v2/10.png) @@ -30,8 +28,6 @@ T(n) = n^klogn if k==log(b)a ![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv1/v1/20.png) - - [归并排序时间复杂度分析](https://blog.csdn.net/qq_32534441/article/details/95098059) ``` @@ -39,7 +35,7 @@ T(n)=2*T(n/2)+n 第一层n, 第二层2*(n/2), 第三层4*(n/4), 每层都有个n,高度Logn ``` -[合并k个链表的时间复杂度分析](https://blog.csdn.net/qq_22080999/article/details/80669993) +[合并 k 个链表的时间复杂度分析](https://blog.csdn.net/qq_22080999/article/details/80669993) 分治的话: @@ -49,45 +45,42 @@ T(kn) = 2T(k/2*n) + kn 高度log2(k),每层累加都是kn, 因此最终是log2(k) * kn ``` -方法1:暴力,k个链表按顺序合并 +方法 1:暴力,k 个链表按顺序合并 时间复杂度: (n+n)+(2n+n)+...+ ((k-1)n + n) = (1+2+...+k-1)n + (k-1)n = (1+2+...+k-1+k)n -n = (k^2+k-1)/2*n = O(k^2*n) -方法2:将k*n个结点放到vector,再将vector排序,再将结点顺序相连 +方法 2:将 k\*n 个结点放到 vector,再将 vector 排序,再将结点顺序相连 -设有K个链表,平均每个链表有n个结点,时间复杂度: +设有 K 个链表,平均每个链表有 n 个结点,时间复杂度: kN*logkN +kN = O(kN*logkN) -方法3:对k个链表进行分治,两两进行合并 +方法 3:对 k 个链表进行分治,两两进行合并 -设有k个链表,平均每个链表有n个结点,时间复杂度: +设有 k 个链表,平均每个链表有 n 个结点,时间复杂度: -第一轮:进行k/2次,每次处理2n个数字 +第一轮:进行 k/2 次,每次处理 2n 个数字 -第2轮,进行k/4次,每次处理4n个数字 +第 2 轮,进行 k/4 次,每次处理 4n 个数字 ... -最后一次,进行k/(2^logk)次,每次处理2^logk*n个数 - -2n*k/2+...+2^logk*n * k/(2^logk) - +最后一次,进行 k/(2^logk)次,每次处理 2^logk\*n 个数 +2n*k/2+...+2^logk*n \* k/(2^logk) ## 常见算法时间复杂度 时间复杂度总结: -prim o(e+vlogv), 主要是优先队列top v次,每次log(v), 然后边遍历总计2e. +prim o(e+vlogv), 主要是优先队列 top v 次,每次 log(v), 然后边遍历总计 2e. kruskal o(eloge), 主要是边的排序耗时上。 -dijsktra o(e+vlogv), 边总计e, 优先队列取了v次,每次top log(v), 这里指的斐波那契堆,该堆insert 为o(1),其他和二叉堆一致。 - -floyd wallshal, o(n3) +dijsktra o(e+vlogv), 边总计 e, 优先队列取了 v 次,每次 top log(v), 这里指的斐波那契堆,该堆 insert 为 o(1),其他和二叉堆一致。 -bellman-ford, o(ve), 每个边松弛一次,共循环v次,o(ve); +floyd wallshal, o(n3) +bellman-ford, o(ve), 每个边松弛一次,共循环 v 次,o(ve); diff --git "a/_posts/Tech/Algorithms/2018-03-13-\345\212\250\346\200\201\350\247\204\345\210\222\344\271\213\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227\345\255\220\344\270\262.md" "b/_posts/Tech/Algorithms/2018-03-13-\345\212\250\346\200\201\350\247\204\345\210\222\344\271\213\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227\345\255\220\344\270\262.md" index 4913182da9..f941661942 100644 --- "a/_posts/Tech/Algorithms/2018-03-13-\345\212\250\346\200\201\350\247\204\345\210\222\344\271\213\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227\345\255\220\344\270\262.md" +++ "b/_posts/Tech/Algorithms/2018-03-13-\345\212\250\346\200\201\350\247\204\345\210\222\344\271\213\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227\345\255\220\344\270\262.md" @@ -1,7 +1,7 @@ --- layout: post category: Algorithms -title: 动态规划之公共子序列子串 +title: 动态规划之公共子序列/子串/前缀 tags: Algorithms --- @@ -183,3 +183,23 @@ public class LCString { } ``` + +## 最长前缀LCP Longest common prefix + +求两个字符串任意两个位置开头的最长公共前缀。时间复杂度o(n2) 如果是暴力需要o(n3) 枚举i,j然后到头。 + + + +```scala +class Strings: + def LongestCommonPrefix(a, b): + # lcp[i][j] 表示 s[i:] 和 s[j:] 的最长公共前缀 + n, m = len(a), len(b) + lcp = [[0] * (m + 1) for _ in range(n + 1)] + for i in range(n - 1, -1, -1): + for j in range(m - 1, -1, -1): + if a[i] == b[j]: + lcp[i][j] = lcp[i + 1][j + 1] + 1 + return lcp +``` + diff --git "a/_posts/Tech/Algorithms/2018-03-13-\345\233\236\346\272\257\346\263\225\345\222\214\346\216\222\345\210\227\347\273\204\345\220\210.md" "b/_posts/Tech/Algorithms/2018-03-13-\345\233\236\346\272\257\346\263\225\345\222\214\346\216\222\345\210\227\347\273\204\345\220\210.md" index ff312327cc..ca30800030 100644 --- "a/_posts/Tech/Algorithms/2018-03-13-\345\233\236\346\272\257\346\263\225\345\222\214\346\216\222\345\210\227\347\273\204\345\220\210.md" +++ "b/_posts/Tech/Algorithms/2018-03-13-\345\233\236\346\272\257\346\263\225\345\222\214\346\216\222\345\210\227\347\273\204\345\220\210.md" @@ -259,27 +259,28 @@ int main() { [the link](https://leetcode.com/problems/subsets/) -```java -public List> subsets(int[] nums) { - List> list = new ArrayList<>(); - Arrays.sort(nums); - backtrack(list, new ArrayList<>(), nums, 0); - return list; -} +```python +class Solution: + def subsets(self, nums: List[int]) -> List[List[int]]: + res = [] + def backtrack(nums, start, tempList: List[int], res): + res.append(tempList.copy()) + for i in range(start, len(nums)): + tempList.append(nums[i]) + backtrack(nums, i + 1, tempList, res) + tempList.pop() + return + + + backtrack(nums, 0, [], res) + print(res) + return res -private void backtrack(List> list , List tempList, int [] nums, int start){ - list.add(new ArrayList<>(tempList)); - for(int i = start; i < nums.length; i++){ - tempList.add(nums[i]); - backtrack(list, tempList, nums, i + 1); - tempList.remove(tempList.size() - 1); - } -} ``` #### 有重复 -[the link]( https://leetcode.com/problems/subsets-ii/) +[the link]( https://leetcode.cn/problems/subsets-ii/) ``` [ @@ -294,23 +295,24 @@ private void backtrack(List> list , List tempList, int [] 这个注意是有duplicate的,所以要注意 -```java -public List> subsetsWithDup(int[] nums) { - List> list = new ArrayList<>(); - Arrays.sort(nums); - backtrack(list, new ArrayList<>(), nums, 0); - return list; -} +```python +class Solution: + def subsetsWithDup(self, nums: List[int]) -> List[List[int]]: + def backtrack(nums, start, tempList: List[int], res): + res.append(tempList.copy()) + for i in range(start, len(nums)): + if i > start and nums[i] == nums[i-1]: + continue + tempList.append(nums[i]) + backtrack(nums, i + 1, tempList, res) + tempList.pop() + return -private void backtrack(List> list, List tempList, int [] nums, int start){ - list.add(new ArrayList<>(tempList)); - for(int i = start; i < nums.length; i++){ - if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates - tempList.add(nums[i]); - backtrack(list, tempList, nums, i + 1); - tempList.remove(tempList.size() - 1); - } -} + nums.sort() + res = [] + backtrack(nums, 0, [], res) + print(res) + return res ``` 也可以设置visit数组 diff --git "a/_posts/Tech/Algorithms/2018-08-01-\351\230\237\345\210\227\345\222\214\346\240\210.md" "b/_posts/Tech/Algorithms/2018-08-01-\351\230\237\345\210\227\345\222\214\346\240\210.md" index af863894ef..ef2859e924 100644 --- "a/_posts/Tech/Algorithms/2018-08-01-\351\230\237\345\210\227\345\222\214\346\240\210.md" +++ "b/_posts/Tech/Algorithms/2018-08-01-\351\230\237\345\210\227\345\222\214\346\240\210.md" @@ -165,4 +165,13 @@ class Solution: -类似题目: [394. 字符串解码](https://leetcode-cn.com/problems/decode-string/) \ No newline at end of file +类似题目: [394. 字符串解码](https://leetcode-cn.com/problems/decode-string/) + + + + + +给定入栈顺序,求某个出栈顺序。 + +1. [6202. 使用机器人打印字典序最小的字符串](https://mafulong.github.io/2022/10/09/6202.-%E4%BD%BF%E7%94%A8%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%89%93%E5%8D%B0%E5%AD%97%E5%85%B8%E5%BA%8F%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2/) +2. [栈的压入、弹出序列](https://mafulong.github.io/2018/10/20/%E6%A0%88%E7%9A%84%E5%8E%8B%E5%85%A5-%E5%BC%B9%E5%87%BA%E5%BA%8F%E5%88%97/) \ No newline at end of file diff --git "a/_posts/Tech/algorithms/2018-08-13-\346\254\247\346\213\211\345\233\236\350\267\257.md" "b/_posts/Tech/Algorithms/2018-08-13-\346\254\247\346\213\211\350\267\257\345\276\204.md" similarity index 87% rename from "_posts/Tech/algorithms/2018-08-13-\346\254\247\346\213\211\345\233\236\350\267\257.md" rename to "_posts/Tech/Algorithms/2018-08-13-\346\254\247\346\213\211\350\267\257\345\276\204.md" index 6b221feac6..3e19382e31 100644 --- "a/_posts/Tech/algorithms/2018-08-13-\346\254\247\346\213\211\345\233\236\350\267\257.md" +++ "b/_posts/Tech/Algorithms/2018-08-13-\346\254\247\346\213\211\350\267\257\345\276\204.md" @@ -1,14 +1,16 @@ --- layout: post category: Algorithms -title: 欧拉回路 +title: 欧拉路径 tags: Algorithms --- ## 欧拉回路定义及判断 -如果能从图的某一顶点出发,每条边恰好经过一次,这样的路线称为欧拉道路(Eulerian Path)。 +如果能从图的某一顶点出发,每条边恰好经过一次,这样的路线称为**欧拉道路(Eulerian Path)。也叫欧拉路径** + +如果每条边恰好经过一次,且能回到起点,这样的路线称为**欧拉回路**(Eulerian Circuit)。 + -如果每条边恰好经过一次,且能回到起点,这样的路线称为欧拉回路(Eulerian Circuit)。 对于无向图G,当且仅当G 是连通的,且最多有两个奇点,则存在欧拉道路。 @@ -22,7 +24,7 @@ tags: Algorithms - 通过图中所有边恰好一次且行遍所有顶点的通路称为欧拉通路。 - 通过图中所有边恰好一次且行遍所有顶点的回路称为欧拉回路。 -- 具有欧拉回路的无向图称为欧拉图。 +- **具有欧拉回路的无向图称为欧拉图。** - 具有欧拉通路但不具有欧拉回路的无向图称为半欧拉图。 @@ -41,6 +43,10 @@ tags: Algorithms 给定一个 *n* 个点 *m* 条边的图,要求从指定的顶点出发,经过所有的边恰好一次(可以理解为给定起点的「一笔画」问题)其实就是求欧拉路径。 +如果在有欧拉回路中的图,它就求的是欧拉回路。如果非欧拉回路的图就是欧拉路径。 + + + Hierholzer 算法用于在连通图中寻找欧拉路径,其流程如下:[参考](https://leetcode-cn.com/problems/reconstruct-itinerary/solution/zhong-xin-an-pai-xing-cheng-by-leetcode-solution/) @@ -70,11 +76,17 @@ def dfs(u): stack = stack[::-1] ``` +以上是求点的路径。 有向图还是无向图都没关系,无向图就变两个有向的边就行。 + + + +如果是求边路径,pop后进入stack即可。 + ## 相关题目 -- [332. 重新安排行程](https://leetcode-cn.com/problems/reconstruct-itinerary/) -- [753. 破解保险箱](https://leetcode-cn.com/problems/cracking-the-safe/) 求锁所有密码,就是抽象出多个节点,然后求欧拉回路. +- [332. 重新安排行程](https://leetcode-cn.com/problems/reconstruct-itinerary/) 求欧拉路径 点的顺序 +- [753. 破解保险箱](https://leetcode-cn.com/problems/cracking-the-safe/) 求锁所有密码,就是抽象出多个节点,然后求欧拉路径. - [5932. 合法重新排列数对](https://leetcode-cn.com/problems/valid-arrangement-of-pairs/) diff --git "a/_posts/Tech/Algorithms/2021-01-25-\345\215\232\345\274\210\350\256\272.md" "b/_posts/Tech/Algorithms/2021-01-25-\345\215\232\345\274\210\350\256\272.md" index 2273a453fe..b86928dd25 100644 --- "a/_posts/Tech/Algorithms/2021-01-25-\345\215\232\345\274\210\350\256\272.md" +++ "b/_posts/Tech/Algorithms/2021-01-25-\345\215\232\345\274\210\350\256\272.md" @@ -3,6 +3,7 @@ layout: post category: Algorithms title: 博弈论 tags: Algorithms +recent_update: true --- ## 博弈论 diff --git "a/_posts/Tech/Algorithms/2021-03-11-\344\270\221\346\225\260.md" "b/_posts/Tech/Algorithms/2021-03-11-\344\270\221\346\225\260.md" deleted file mode 100644 index b28798fa3a..0000000000 --- "a/_posts/Tech/Algorithms/2021-03-11-\344\270\221\346\225\260.md" +++ /dev/null @@ -1,57 +0,0 @@ ---- -layout: post -category: Algorithms -title: 丑数 -tags: Algorithms ---- - -## 丑数 - -[[剑指 Offer 49. 丑数](https://leetcode-cn.com/problems/chou-shu-lcof/) - -[313. 超级丑数](https://leetcode-cn.com/problems/super-ugly-number/) - -### 使用优先队列 - -```python -class Solution: - def nthSuperUglyNumber(self, n: int, primes: List[int]) -> int: - import heapq - hq = [1] - res = [] - for _ in range(n): - top = heapq.heappop(hq) - res.append(top) - while hq and hq[0] == top: - heapq.heappop(hq) - for k in primes: - heapq.heappush(hq, top * k) - print(res) - return res[-1] -``` - - - -### 使用多指针 - -```c++ -//cpp: -class Solution { -public://别人的代码就是精简,惭愧啊,继续学习。 - int GetUglyNumber_Solution(int index) { - if (index < 7)return index; - vector res(index); - res[0] = 1; - int t2 = 0, t3 = 0, t5 = 0, i; - for (i = 1; i < index; ++i) - { - res[i] = min(res[t2] * 2, min(res[t3] * 3, res[t5] * 5)); - if (res[i] == res[t2] * 2)t2++; - if (res[i] == res[t3] * 3)t3++; - if (res[i] == res[t5] * 5)t5++; - } - return res[index - 1]; - } -}; -``` - diff --git "a/_posts/Tech/Algorithms/2021-03-11-\345\244\232\350\267\257\345\275\222\345\271\266 \344\270\221\346\225\260.md" "b/_posts/Tech/Algorithms/2021-03-11-\345\244\232\350\267\257\345\275\222\345\271\266 \344\270\221\346\225\260.md" new file mode 100644 index 0000000000..bbf460d84d --- /dev/null +++ "b/_posts/Tech/Algorithms/2021-03-11-\345\244\232\350\267\257\345\275\222\345\271\266 \344\270\221\346\225\260.md" @@ -0,0 +1,124 @@ +--- +layout: post +category: Algorithms +title: 多路归并 丑数 +tags: Algorithms +--- + +[找第k小及变种,个人另一篇博客,内容有重合](https://mafulong.github.io/2022/01/03/%E6%89%BE%E7%AC%ACk%E5%B0%8F%E5%8F%8A%E5%8F%98%E7%A7%8D/) + + + +## 丑数 + +[[剑指 Offer 49. 丑数](https://leetcode-cn.com/problems/chou-shu-lcof/) + + + +### 使用优先队列 + +```python +class Solution: + def nthSuperUglyNumber(self, n: int, primes: List[int]) -> int: + import heapq + hq = [1] + res = [] + for _ in range(n): + top = heapq.heappop(hq) + res.append(top) + while hq and hq[0] == top: + heapq.heappop(hq) + for k in primes: + heapq.heappush(hq, top * k) + print(res) + return res[-1] +``` + + + +### 使用多指针 + +```c++ +//cpp: +class Solution { +public:/ + int GetUglyNumber_Solution(int index) { + if (index < 7)return index; + vector res(index); + res[0] = 1; + int t2 = 0, t3 = 0, t5 = 0, i; + for (i = 1; i < index; ++i) + { + res[i] = min(res[t2] * 2, min(res[t3] * 3, res[t5] * 5)); + if (res[i] == res[t2] * 2)t2++; + if (res[i] == res[t3] * 3)t3++; + if (res[i] == res[t5] * 5)t5++; + } + return res[index - 1]; + } +}; +``` + +多路归并。 + +## 超级丑数 + +不只2,3,5 + +![image-20221122214259661](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202211222143705.png) + +[313. 超级丑数](https://leetcode-cn.com/problems/super-ugly-number/) + +```python +class Solution: + def nthSuperUglyNumber(self, n: int, primes: List[int]) -> int: + import heapq + hpush, hpop = heapq.heappush,heapq.heappop + h = [] + for i in range(len(primes)): + hpush(h, (primes[i], i, 0)) + ans = [1] + for i in range(1,n): + if not h: + return -1 + val = h[0][0] + ans.append(val) + while h and h[0][0] == val: + _,j,idx = hpop(h) + # print(idx,ans) + hpush(h, (ans[idx]*primes[j], j, idx+1)) + return ans[-1] + + +``` + + + +## 其它多路归并 + +- [373. 查找和最小的K对数字](https://mafulong.github.io/2022/01/03/373.-%E6%9F%A5%E6%89%BE%E5%92%8C%E6%9C%80%E5%B0%8F%E7%9A%84K%E5%AF%B9%E6%95%B0%E5%AD%97/) 给定两个以升序排列的整数数组 `nums1` 和 `nums2` , 以及一个整数 `k` 。定义一对值 `(u,v)`,其中第一个元素来自 `nums1`,第二个元素来自 `nums2` 。请找到和最小的 `k` 个数对 `(u1,v1)`, ` (u2,v2)` ... `(uk,vk)` 。 + +```python +class Solution: + def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]: + # equal with 多路链表归并,用heap取最小那个,然后移动指针,也就是超级丑数 + # 性能o(klog(k)) + import heapq + h = [] + for j in range(min(len(nums2),k)): + heapq.heappush(h, (nums1[0]+nums2[j], 0, j)) + res = [] + while k > 0 and h: + _,i,j = heapq.heappop(h) + res.append([nums1[i], nums2[j]]) + if i+1 < len(nums1): + heapq.heappush(h, (nums1[i+1]+nums2[j], i+1,j)) + k-=1 + return res +``` + + + +- [有序矩阵的 Kth Element](https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/description/) + - 多路归并 + - 二分法更优。 diff --git "a/_posts/Tech/Algorithms/2021-06-21-\345\215\225\350\260\203\351\230\237\345\210\227\345\222\214\345\215\225\350\260\203\346\240\210.md" "b/_posts/Tech/Algorithms/2021-06-21-\345\215\225\350\260\203\351\230\237\345\210\227\345\222\214\345\215\225\350\260\203\346\240\210.md" index ceae6d6f9c..ef926ee344 100644 --- "a/_posts/Tech/Algorithms/2021-06-21-\345\215\225\350\260\203\351\230\237\345\210\227\345\222\214\345\215\225\350\260\203\346\240\210.md" +++ "b/_posts/Tech/Algorithms/2021-06-21-\345\215\225\350\260\203\351\230\237\345\210\227\345\222\214\345\215\225\350\260\203\346\240\210.md" @@ -96,6 +96,48 @@ class Solution: 求左边右边, 最小的大于等于arr[i]的位置,一种方式是sortedList, 一种方式是sorted(range(N), lambda x:arr[x]) +### 最大宽度 最大上升坡 + +求最大坡度, 坡度定义: i < j 且 A[i] <= A[j]。这样的坡的宽度为 j - i。找每个元素比它大的最后一个位置 +可以按https://leetcode.cn/submissions/detail/208988818/ 中,按val对range(n)排序,o(nlogn),此时对排序位置i的元素最大坡度就是右边最大j。此时右边元素都不小于当前元素。 + +```python +class Solution: + def maxWidthRamp(self, nums: List[int]) -> int: + ans = 0 + m = float('inf') + for i in sorted(range(len(nums)), key=lambda x: nums[x]): + ans = max(ans, i - m) + m = min(m, i) + return ans +``` + +也可以单调栈o(n)求,先求正序递减栈,然后倒序枚举,如果比栈顶大,则栈顶元素后续就无用可pop了 + +```python + +class Solution: + def maxWidthRamp(self, nums: List[int]) -> int: + ans = 0 + stack = [] + for i, v in enumerate(nums): + if not stack or v < nums[stack[-1]]: + stack.append(i) + # print(stack) + for i in range(len(nums) - 1, -1, -1): + while stack and nums[i] >= nums[stack[-1]]: + ans = max(ans, i - stack.pop()) + return ans + +``` + + + +类似题目: + +- [1124. 表现良好的最长时间段](https://leetcode.cn/problems/longest-well-performing-interval/) 先转化成+1,-1的list,然后求前缀和的最长坡度,要求`a[i] < a[j]` 。解法和上面一致。 + + ## 单调队列 @@ -146,4 +188,3 @@ class Solution: - [862. 和至少为 K 的最短子数组](https://leetcode-cn.com/problems/shortest-subarray-with-sum-at-least-k/) 求前缀和,对前缀和队列递增,求最大差值。 - diff --git "a/_posts/Tech/Algorithms/2021-08-12-\345\233\236\346\226\207.md" "b/_posts/Tech/Algorithms/2021-08-12-\345\233\236\346\226\207.md" index e782af0844..ce69a52ac5 100644 --- "a/_posts/Tech/Algorithms/2021-08-12-\345\233\236\346\226\207.md" +++ "b/_posts/Tech/Algorithms/2021-08-12-\345\233\236\346\226\207.md" @@ -9,7 +9,7 @@ tags: Algorithms -#### Manacher 算法 +#### Manacher 算法 给你一个字符串 `s`,找到 `s` 中最长的回文子串。 @@ -19,8 +19,12 @@ tags: Algorithms 这里边长0表示a,边长1表示aaa -``` - n = len(s) +```python + ''' + 须先变为回文皆奇数长度, 可提前转换: s1 = '#' + '#'.join(list(s)) + '#' + ''' + + n = len(s) arm_len = [0] * n def expand(left, right): @@ -42,6 +46,23 @@ tags: Algorithms right = i + arm_len[i] ``` +时间复杂度o(n). + + + +根据以上得到的arm_len 判断某个子串是不是回文。 + +```python + def is_palindrome(s, i, j, armlen): + mid = (i + j) // 2 # 前半部分或中间 + # 找中心点,然后对应到s1上 + t = 2 * mid + 1 + if (j - i + 1) % 2 == 0: + t += 1 + return armlen[t] >= j - i + 1 + +``` + ## 回文技巧 @@ -49,3 +70,10 @@ tags: Algorithms DP: - 用 P(i,j) 表示字符串 s 的第 i到 j 个字母组成的串(下文表示成 s[i:j])是否为回文串 . 变成区间dp + + + +## 应用 + +- [647. 回文子串](https://leetcode.cn/problems/palindromic-substrings/) 给你一个字符串 `s` ,请你统计并返回这个字符串中 **回文子串** 的数目。1.中心扩展o(n2), 2. manacher o(n) +- [6236. 不重叠回文子字符串的最大数目](https://leetcode.cn/problems/maximum-number-of-non-overlapping-palindrome-substrings/) 实际是dp,判断s(i,j)是不是回文。 diff --git "a/_posts/Tech/Algorithms/2021-09-08-\347\212\266\346\200\201\345\216\213\347\274\251.md" "b/_posts/Tech/Algorithms/2021-09-08-\347\212\266\346\200\201\345\216\213\347\274\251.md" index ea30e809e2..85843010a6 100644 --- "a/_posts/Tech/Algorithms/2021-09-08-\347\212\266\346\200\201\345\216\213\347\274\251.md" +++ "b/_posts/Tech/Algorithms/2021-09-08-\347\212\266\346\200\201\345\216\213\347\274\251.md" @@ -3,6 +3,7 @@ layout: post category: Algorithms title: 状态压缩 tags: Algorithms +recent_update: true --- ## 状态压缩 diff --git a/_posts/Tech/Algorithms/2021-12-05-BFS.md b/_posts/Tech/Algorithms/2021-12-05-BFS.md index d5097a7ac7..ffd0c10075 100644 --- a/_posts/Tech/Algorithms/2021-12-05-BFS.md +++ b/_posts/Tech/Algorithms/2021-12-05-BFS.md @@ -11,29 +11,22 @@ tags: Algorithms - 在append时检查visit标记和设置visit标记 - 只能解决长度为1的问题 -``` -const visited = {} -function bfs() { - let q = new Queue() - q.push(初始状态) - while(q.length) { - let i = q.pop() - if (visited[i]) continue - for (i的可抵达状态j) { - if (j 合法) { - q.push(j) - } - } - } - // 找到所有合法解 -} -``` + + +也可以在queue pop时再check 是否visit和标记visit,时间复杂度加边数。 + + 题目: - [求最少转弯的路径](https://mafulong.github.io/2018/08/27/bfs%E6%9C%80%E5%B0%8F%E8%BD%AC%E5%BC%AF%E8%B7%AF%E5%BE%84/) 每次转弯时加1 - [126. 单词接龙 II](https://leetcode.cn/problems/word-ladder-ii/) 输入所有bfs路径,层次遍历 + dfs回溯pre. +## 从外向内扩展 + +- [407. 接雨水 II](https://leetcode.cn/problems/trapping-rain-water-ii/) 从外向内dijkstra。 +- [417. 太平洋大西洋水流问题](https://leetcode.cn/problems/pacific-atlantic-water-flow/) 从外向内bfs/dfs。 + ## 双向BFS > [双向bfs模板参考](https://leetcode-cn.com/problems/open-the-lock/solution/gong-shui-san-xie-yi-ti-shuang-jie-shuan-wyr9/) diff --git "a/_posts/Tech/Algorithms/2021-12-23-\344\270\200\350\207\264\346\200\247hash.md" "b/_posts/Tech/Algorithms/2021-12-23-\344\270\200\350\207\264\346\200\247hash.md" index 8b0b8fa32a..cf90d17eaa 100644 --- "a/_posts/Tech/Algorithms/2021-12-23-\344\270\200\350\207\264\346\200\247hash.md" +++ "b/_posts/Tech/Algorithms/2021-12-23-\344\270\200\350\207\264\346\200\247hash.md" @@ -5,6 +5,8 @@ title: 一致性hash tags: Algorithms --- +# 一致性hash + ## 一致性hash 1. 首先,我们将hash算法的值域映射成一个具有232 次方个桶的空间中,即0~(232)-1的数字空间。现在我们可以将这些数字头尾相连,组合成一个闭合的环形。 @@ -104,4 +106,44 @@ class HashSeverMgr(object): ## 参考 - [一致性 hash 原理及实现(python 版)](https://xie.infoq.cn/article/e7182d18df48bc26eeb30b207) -- [图解一致性hash算法和实现](https://aijishu.com/a/1060000000007241) \ No newline at end of file +- [图解一致性hash算法和实现](https://aijishu.com/a/1060000000007241) + +## 补充 + +增加节点/删除节点都需要先执行挪数据这个操作,如果没这个操作,可能会读空,但读空范围因为一致性hash的存在,导致影响有限,对于缓存应该是没关系的,如果是持久化的就需要备份,不能让读空。 + + + +# hash slot + +集群: +是一个提供多个Redis(分布式)节点间共享数据的程序集。 +集群部署 +Redis 集群的键空间被分割为 16384 hash个槽(slot), 集群的最大节点数量也是 16384 个 + +分片: + Redis Cluster在设计中没有使用一致性哈希(Consistency Hashing),而是使用数据分片引入哈希槽(hash slot)来实现; + +一个 Redis Cluster包含16384(0~16383)即2^14个哈希槽,存储在Redis Cluster中的所有键都会被映射到这些slot中,集群中的每个键都属于这16384个哈希槽中的一个,集群使用公式slot=CRC16(key)/16384来计算key属于哪个槽,其中CRC16(key)语句用于计算key的CRC16 校验和。 + + + +这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我像移除节点A,需要将A中得槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务, 所**以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.** + + + +数据迁移 +数据迁移可以理解为slot(槽)和key的迁移,这个功能很重要,极大地方便了集群做线性扩展,以及**实现平滑的扩容或缩容。** + + + + + +和一致性哈希相比 + +1. 它并不是闭合的,key的定位规则是**根据CRC-16(key)%16384的值来判断属于哪个槽区,从而判断该key属于哪个节点**,而一致性哈希是根据hash(key)的值来顺时针找第一个hash(ip)的节点,从而确定key存储在哪个节点。 +2. 一致性哈希是创建虚拟节点来实现节点宕机后的数据转移并保证数据的安全性和集群的可用性的, 当节点不可用时,分摊给多个其他节点,因为虚节点的存在。redis cluster是采用master节点有多个slave节点机制来保证数据的完整性的,master节点写入数据,slave节点同步数据。当master节点挂机后,slave节点会通过选举机制选举出一个节点变成master节点,实现高可用。但是这里有一点需要考虑,如果master节点存在热点缓存,某一个时刻某个key的访问急剧增高,这时该mater节点可能操劳过度而死,随后从节点选举为主节点后,同样宕机,一次类推,造成缓存雪崩即热点缓存问题。 + + + +两者都是要挪数据的! \ No newline at end of file diff --git "a/_posts/Tech/Algorithms/2022-05-01-\346\225\260\345\255\246.md" "b/_posts/Tech/Algorithms/2022-05-01-\346\225\260\345\255\246.md" index d776a249c9..487b8959fe 100644 --- "a/_posts/Tech/Algorithms/2022-05-01-\346\225\260\345\255\246.md" +++ "b/_posts/Tech/Algorithms/2022-05-01-\346\225\260\345\255\246.md" @@ -5,8 +5,6 @@ title: 数学 tags: Algorithms --- - - ## 排列组合 > [参考](https://baike.baidu.com/item/%E6%8E%92%E5%88%97%E7%BB%84%E5%90%88/706498) @@ -19,8 +17,64 @@ tags: Algorithms ![image-20211002195906842](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211002195912.png) +![image-20220904145610986](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202209041456830.png) + +另外 C(0,0) = 1, 0 的为 1。 + +组合数性质 + +![image-20220904145924154](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202209041459183.png) + +### 大组合数求解边模 + +利用组合数性质. o(n2) + +```python + def comb_mod(self, n, m, mod=10 ** 9 + 7): + ''' + 大组合数计算C(n,m),边求边mod, 利用组合数性质C(n,m) = 1*C(n-1,m-1) + C(n-1,m) + ''' + dp = [[0 for _ in range(n+1)] for _ in range(n+1)] + dp[0][0] = 1 + for i in range(1, n+1): + dp[i][0] = 1 + for j in range(1, i+1): + dp[i][j] = (dp[i-1][j-1] + dp[i-1][j]) % mod + return dp[n][m] + +``` + +组合数求和公式 + +![image-20220904150115865](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202209041501896.png) + + + +### python中排列组合 + +```python + # 组合 + math.comb # n! / (k! * (n - k)!) + math.perm # n! / (n - k)! + +``` + + + + + +### 求组合数 小球放盒子 + +> [参考2](https://www.luogu.com.cn/blog/chengni5673/dang-xiao-qiu-yu-shang-he-zi) + +默认问题为 n 个小球放到 m 个盒子里,题型共有三项要求,球是否相同,盒子是否相同,能否有空盒。 + +- 球相同,盒子不同,不能有空盒。 实质就是把 n 个小球分为 m 组。插板法。 `C(n-1,m-1)` +- 球相同,盒子不同,可以有空盒。对于每个盒子,我们都给他一个球,那么上一个问题就和这问题一样了,所以我们可以看做自己有 n+m 个小球,然后我们在排列完之后在每一组都删去一个小球,这样就能枚举出有空盒的情况了。`C(n+m-1,m-1)` +- 其他复杂情况看参考。 + ## 等差等比数列 > [参考](https://wenku.baidu.com/view/0c5e350102020740be1e9b79.html) @@ -29,20 +83,18 @@ tags: Algorithms image-20210801124109093 - - ## 复杂的复杂度计算 ### 幂函数和对数函数和指数函数对比 - - ![image-20220223194514512](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20220223194514.png) ### 调和级数 ![image-20220223193553568](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20220223193558.png) +这里有用到: [link](https://leetcode.cn/problems/number-of-different-subsequences-gcds/solution/ji-bai-100mei-ju-gcdxun-huan-you-hua-pyt-get7/) + ### 二项式定理 ![](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211002200037.png) @@ -53,16 +105,20 @@ tags: Algorithms ## 中位数 -在一步操作中,你可以使数组中的一个元素加 `1` 或者减 `1` ,所有数都靠近**中位数**可使所有数组元素相等时移动数最少。 相关题目: [最少移动次数使数组元素相等 II](https://leetcode-cn.com/problems/minimum-moves-to-equal-array-elements-ii/) +在一步操作中,你可以使数组中的一个元素加 `1` 或者减 `1` ,所有数都靠近**中位数**可使所有数组元素相等时移动数最少。 相关题目: [最少移动次数使数组元素相等 II](https://leetcode-cn.com/problems/minimum-moves-to-equal-array-elements-ii/) +即中位数到所有数距离和最小,如果是偶数,可以在中位数两侧的数据构成的区间内任意取值,对结果无影响证明: +![image-20221023121438346](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210231214395.png) + +另一个相似题目:有cost,需转化拆分,然后再算中位数,[6216. 使数组相等的最小开销](https://mafulong.github.io/2022/10/23/6216.-%E4%BD%BF%E6%95%B0%E7%BB%84%E7%9B%B8%E7%AD%89%E7%9A%84%E6%9C%80%E5%B0%8F%E5%BC%80%E9%94%80/) ## 素数 -### 判断是否素数和求1-n的素数求某数的素数 +### 判断是否素数 o(sqrt(N)) ```python -# 判断某数是否是素数 +# 判断某数是否是素数 o(sqrt(n)) def is_prime(a): if a <= 1: return False import math @@ -71,7 +127,16 @@ def is_prime(a): return True -# 求1-n每个数的素数,以下时间复杂度O(n) 朴素筛法 +``` + +### 求 1-n 的所有素数 筛法 o(N) + +#### 埃氏筛法 + +```python +# 求1-n每个数的素数,以下时间复杂度O(nloglogn) 接近o(n) +# 如果我们从小到大考虑每个数,然后同时把当前这个数的所有(比自己大的)倍数记为合数,那么运行结束的时候没有被标记的数就是素数了。 +# Eratosthenes 筛法(埃拉托斯特尼筛法,简称埃氏筛法) def get_all_prime(n): a = [False] * n res = [] @@ -82,21 +147,31 @@ def get_all_prime(n): for j in range(2 * i, n, i): a[j] = True return res +``` -# 求某数的质因数列表,比如8,是[(2,3)], 6是[(2,1),(3,1)] -def calcu(a): - counter = collections.Counter() - prime = get_all_prime(a + 1) - for p in prime: - while a % p == 0: - counter[p] += 1 - a /= p - return counter.items() +#### **线性筛法** 也称为 **Euler 筛法**(欧拉筛法) + +埃氏筛法仍有优化空间,它会将一个合数重复多次标记。有没有什么办法省掉无意义的步骤呢?答案是肯定的。 + +如果能让每个合数都只被标记一次,那么时间复杂度就可以降到 o(n)了。 + +```python +def get_all_prime(n): + a = [False] * n + res = [] + for i in range(2, n): + if a[i]: continue + # a[i]是素数 + res.append(i) + for j in range(2 * i, n, i): + if a[j]: break # 多了个这行 + a[j] = True + return res ``` ## 平方数 -[先看Cyc2018](http://www.cyc2018.xyz/%E7%AE%97%E6%B3%95/Leetcode%20%E9%A2%98%E8%A7%A3/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E6%95%B0%E5%AD%A6.html#_1-%E5%B9%B3%E6%96%B9%E6%95%B0) +[先看 Cyc2018](http://www.cyc2018.xyz/%E7%AE%97%E6%B3%95/Leetcode%20%E9%A2%98%E8%A7%A3/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E6%95%B0%E5%AD%A6.html#_1-%E5%B9%B3%E6%96%B9%E6%95%B0) ### 生成所有平方数 @@ -106,8 +181,6 @@ def calcu(a): 间隔为等差数列,使用这个特性可以得到从 1 开始的平方序列。 - - ### 3 的 n 次方 [Power of Three (Easy)](https://leetcode-cn.com/problems/power-of-three/description/) @@ -118,33 +191,114 @@ public boolean isPowerOfThree(int n) { } ``` -## 因数 +## 除法 + +```python + # b % a == 0 + # 表示b能被a整除,a可以整除b, 被除数永远都是有这个『被』 +``` + +表示b能被a整除,a可以整除b, 被除数永远都是有这个『被』 + + + +大整数除法,除法中取模。 + +## 有负数的除法求模 不同语言可能不同 + +比如a 除以 b,求对应商和余数。不同语言可能不同 + +计算-7 Mod 4 + +那么:a = -7;b = 4; + +第一步:求整数商c,c应该是-1.75,如进行求模运算c = -2(向负无穷方向舍入),求余运算则c = -1(向0方向舍入); + +第二步:计算模和余数的公式相同,但因c的值不同,求模时r = 1,求余时r = -3。 + + 当符号不一致时,结果不一样。求模运算结果的符号和b一致,求余运算结果的符号和a一致。 + +在C/C++, C#, JAVA, PHP这几门主流语言中,%运算符都是做取余运算,而在python中的%是做取模运算。 + + + +**python求商是向负无穷靠近,而其他是靠近0.** + +## 因数理论 ### 素数分解 -每一个数都可以分解成素数的乘积,例如 84 = 22 * 31 * 50 * 71 * 110 * 130 * 170 * … +每一个数都可以分解成素数的乘积,例如 84 = 22 _ 31 _ 50 _ 71 _ 110 _ 130 _ 170 \* … ### 整除 -令 x = 2m0 * 3m1 * 5m2 * 7m3 * 11m4 * … +令 x = 2m0 _ 3m1 _ 5m2 _ 7m3 _ 11m4 \* … -令 y = 2n0 * 3n1 * 5n2 * 7n3 * 11n4 * … +令 y = 2n0 _ 3n1 _ 5n2 _ 7n3 _ 11n4 \* … 如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。 -### 最大公约数最小公倍数 +### 最大公约数最小公倍数的素数表示 + +每个质因数的乘积 + +x 和 y 的最大公约数为:gcd(x,y) = 2min(m0,n0) _ 3min(m1,n1) _ 5min(m2,n2) \* ... + +x 和 y 的最小公倍数为:lcm(x,y) = 2max(m0,n0) _ 3max(m1,n1) _ 5max(m2,n2) \* ... + +### 约数个数和约数之和 + +如果 N = p1^c1 _ p2^c2 _ ... _pk^ck +约数个数: (c1 + 1) _ (c2 + 1) _ ... _ (ck + 1) +约数之和: (p1^0 + p1^1 + ... + p1^c1) _ ... _ (pk^0 + pk^1 + ... + pk^ck) -x 和 y 的最大公约数为:gcd(x,y) = 2min(m0,n0) * 3min(m1,n1) * 5min(m2,n2) * ... -x 和 y 的最小公倍数为:lcm(x,y) = 2max(m0,n0) * 3max(m1,n1) * 5max(m2,n2) * ... -### 求质因数和对应计数 +## 因数相关问题 -o(n)近似 +### 试除法求所有约数: + +#### 求一个数的因子列表 o(sqrt(n)) + +o(sqrt(n)) + +```python +divisors = [] +d = 1 +while d * d <= k: # 预处理 k 的所有因子 + if k % d == 0: + divisors.append(d) + if d * d < k: # 避免 d= k/d的情况,此时如果append会重复 + divisors.append(k / d) + d += 1 +``` + +#### 统计 1-n 每个数的因子列表 o(nlogn) + +o(nlogn) + +```python +MX = 100001 +divisors = [[] for _ in range(MX)] # 每个value就是key的因子列表,乘积肯定>value,因为因子之间可能有倍数 +for i in range(1, MX): # 预处理每个数的所有因子,时间复杂度 O(MlogM),M=1e5 + for j in range(i, MX, i): + divisors[j].append(i) +``` + +### 分解质因数 + +#### 求某数质因数列表 o(sqrt(N)) + +o(sqrt(N)) + +求某数的质因数列表,比如 8,是[2,2,2] + +枚举[2, sqrt(n)+1), 如果是质因数,就接着除,最大大于 1,它本身就是质数。 + +也叫 求欧拉函数 ```python # 求质因数列表 -# Python Version def breakdown(N): result = [] from math import sqrt @@ -158,76 +312,248 @@ def breakdown(N): return result ``` -### 统计1-n每个数的因子列表 +#### 统计 1-n 每个数的质因数列表 -o(nlogn) +筛法求欧拉函数 + +类似,暂时不写。 + +### gcd 求最大公约数和最小公倍数 欧几里得算法 + +欧几里得算法 ```python -MX = 100001 -divisors = [[] for _ in range(MX)] # 每个value就是key的因子列表,乘积肯定>value,因为因子之间可能有倍数 -for i in range(1, MX): # 预处理每个数的所有因子,时间复杂度 O(MlogM),M=1e5 - for j in range(i, MX, i): - divisors[j].append(i) +class Math1: + def gcd(self, a, b): + if b == 0: + return a + return self.gcd(b, a % b) ``` -### 求一个数的因子列表 +最小公倍数就是 a\*b/gcd(a,b) + -o(sqrt(n)) + +### gcd性质 + +如果ax+by=1, 则gcd(x,y) = 1 + + + +### 多个数求最大公约数和最小公倍数 + +多个数的最大公约数: ```python -divisors = [] -d = 1 -while d * d <= k: # 预处理 k 的所有因子 - if k % d == 0: - divisors.append(d) - if d * d < k: # 避免 d= k/d的情况,此时如果append会重复 - divisors.append(k / d) - d += 1 +def gcd_list(self, nums): + import math + cur = nums[0] + for i in range(1, len(nums)): + cur = math.gcd(cur, nums[i]) + return cur ``` -### gcd求最大公约数: +多个数的最小公倍数: -```c++ -int gcd(int a, int b) { - return b == 0 ? a : gcd(b, a%b); -} +> 注意这里不是直接多个数乘积除以他们的gcd呀,而且不断一个一个加计算的。 -int gcd(int a, int b) { - while (b != 0) { - int t = a%b; - a = b; - b = t; - } - return a; -} +```python +def lcm_list(self, nums): + import math + prod = 1 + for v in nums: + prod = prod * v / math.gcd(prod, v) + return prod +``` + +### 1到n里有多少个数可整除a? + +```python +n//a ``` -最小公倍数就是a*b/gcd(a,b) + + +### 1到n里有多少个a的因数? + +[参考另一个博客](https://mafulong.github.io/2018/04/30/%E8%AE%A1%E7%AE%97n%E7%9A%84%E9%98%B6%E4%B9%98%E4%B8%AD%E6%9C%89%E5%A4%9A%E5%B0%91%E4%B8%AAk/) + +```python + def calcu(x,a): + ''' + 1-x中有多少个因数a, 比如1-26里有5,10, 15, 20, 各自1个5, 5*5两个5,一共6个 + ''' + r = 0 + while x: + # 贡献5的数量,贡献5*5的数量,贡献5*5*5的数量 + r += x //a + x //= a + return r + print(calcu(26, 5)) +``` + + + +## 大整数取模问题 + +### 大数相乘取模 + +```python + def prod(d=[], mod=10 ** 9 + 7): + r = d[0] % mod + for v in d[1:]: + r *= v + r %= mod + return r +``` + + + +### 大数相除取模 费马小定理 + +如果a/b,然后a和b都是大数要取模,这时不能相乘取模来计算 + +`(a/b)%c=(a%c)/(b%c)`是**不成立**的 + + + +> [除法取模](https://leetcode.cn/problems/count-anagrams/solution/by-simpleson-crwb/) + +```python + +# 原: i//j%MOD +# 现: i*modInverse(j)%MOD +MOD = int(1e9 + 7) + +class BigIntDivide: + def mod_inverse(sefl, i): + # 调用取模的乘幂运算, pow复杂度是log(exp)即log(MOD) + return pow(i, MOD - 2, MOD) + + def divide_mod(self, a, b): + ''' + 计算(a/b) % MOD, 除法变乘法,前提是b和MOD互为质数 + ''' + # 如果有多个b,比如a/b1/b2, 那就可以递归。a*mod_inverse(b1) % mod * mod_inverse(b2) % mod这样 + return a * self.mod_inverse(b) % MOD + + def divide_mods(self, a, b=[]): + ''' + 计算a /(b1*b2*b3) % MOD等形式,前提是b和MOD互为质数 + ''' + r = a % MOD + for i, v in enumerate(b): + r *= self.mod_inverse(v) + r %= MOD + return r + + +``` + + + +### 大数幂取模 + +```python +r = pow(base=2, exp=3, mod=3) +print(r) +``` + + + +## 阶乘 + +```python +import math +math.factorial(3) +``` + + + +## 分配问题 + +### a能否分成满足条件的两份,其中只能分给指定一份 + +[2513. 最小化两个数组中的最大值](https://leetcode.cn/problems/minimize-the-maximum-of-two-arrays/) 给你两个数组 arr1 和 arr2 ,它们一开始都是空的。你需要往它们中添加正整数,使它们满足以下条件: + +arr1 包含 uniqueCnt1 个 互不相同 的正整数,每个整数都 不能 被 divisor1 整除 。 +arr2 包含 uniqueCnt2 个 互不相同 的正整数,每个整数都 不能 被 divisor2 整除 。 +arr1 和 arr2 中的元素 互不相同 。 +给你 divisor1 ,divisor2 ,uniqueCnt1 和 uniqueCnt2 ,请你返回两个数组中 最大元素 的 最小值 。 + + + +参考, [link](https://leetcode.cn/circle/discuss/YeBDQY/view/B8caF0/) + +**Key**: 判断过程中分为三类:保证在范围内有充足的数不是第一个数的倍数;不是第二个数的倍数;不为公倍数的数总数不少于总共要取的数。根据这三个条件即得到结果。 + +## 位运算 + +a xor b ==c 则 a = b xor c. ## 进制转换 ```c++ - int a, b; - vector v; - cin >> a >> b; - while (a != 0) { - v.push_back(a%b); - a = a / b; - } + def baseX(self, n, x): + ''' + 进制转换,10进制变x进制 + :return: 数组,每个数是该位上数 + ''' + ans = [] + while n != 0: + n, b = divmod(n, x) + ans.append(b) + ans.reverse() + return ans + + def base10(self, n=[], x=2): + ''' + 从x进制转成10进制 + ''' + ans = 0 + for v in n: + ans *= x + ans += v + return ans ``` -### 小数的进制转换 +### 负进制的转换 -[可以参考](https://blog.csdn.net/u013349653/article/details/51367453) +[负二进制转换](https://leetcode.cn/problems/convert-to-base-2/) + +[个人blog 1017. 负二进制转换](https://mafulong.github.io/2023/04/08/1017.-%E8%B4%9F%E4%BA%8C%E8%BF%9B%E5%88%B6%E8%BD%AC%E6%8D%A2/) 可以任何负进制转换 + +```python +class Solution: + def baseNeg2(self, n: int) -> str: + if n == 0: + return '0' + ans = [] + b = -2 + while n != 0: + x = n % b + ans.append(str(abs(x))) + if x < 0: + x += abs(b) # 变成正数 + n = (n - x) // b + ans = ans[::-1] + return "".join(ans) +``` - 十进制小数转二进制数:“乘以2取整,顺序排列”(乘2取整法) - 例: (0.625)10= (0.101)2 +### 小数的进制转换 + +[可以参考](https://blog.csdn.net/u013349653/article/details/51367453) + +十进制小数转二进制数:“乘以 2 取整,顺序排列”(乘 2 取整法) + +例: (0.625)10= (0.101)2 + image-20220603233141181 ## 容斥原理 @@ -242,7 +568,23 @@ int gcd(int a, int b) { ## 幂 -### 快速幂 +### 快速幂 O(logk) + +求 m^k mod p,时间复杂度 O(logk)。 + +```c++ +int qmi(int m, int k, int p) +{ + int res = 1 % p, t = m; + while (k) + { + if (k&1) res = res * t % p; + t = t * t % p; + k >>= 1; + } + return res; +} +``` ### 求根号 @@ -252,7 +594,7 @@ int gcd(int a, int b) { ### 求根号变种 小数精度 -`while l<=r`不用变,只需要变步长即可。eps可以比期望精度再小一个量级。 +`while l<=r`不用变,只需要变步长即可。eps 可以比期望精度再小一个量级。 ```python @@ -277,8 +619,6 @@ if __name__ == '__main__': print(f(0.04, 1e-10)) ``` +## Acwing 数学 - -## Acwing数学 - -[参考](https://www.acwing.com/file_system/file/content/whole/index/content/3273/) 本文只涉及部分 +[参考](https://www.acwing.com/file_system/file/content/whole/index/content/3273/) 本文只涉及部分 diff --git "a/_posts/Tech/Algorithms/2022-07-31-\347\256\200\345\215\225\345\233\276\347\232\204\346\234\200\345\244\247\347\216\257\346\234\200\351\225\277\351\223\276.md" "b/_posts/Tech/Algorithms/2022-07-31-\347\256\200\345\215\225\345\233\276\347\232\204\346\234\200\345\244\247\347\216\257\346\234\200\351\225\277\351\223\276.md" new file mode 100644 index 0000000000..60c620721d --- /dev/null +++ "b/_posts/Tech/Algorithms/2022-07-31-\347\256\200\345\215\225\345\233\276\347\232\204\346\234\200\345\244\247\347\216\257\346\234\200\351\225\277\351\223\276.md" @@ -0,0 +1,127 @@ +--- +layout: post +category: Algorithms +title: 简单图的最大环最长链 +tags: Algorithms +--- + +## 最大环最长链 + +https://www.cnblogs.com/lfri/p/15758120.html + +最大环是针对的是出度为1的图,否则会多环重合。 + +最长链是无环的图,求一个最长路径的长度。 + + + +## 最大环 + +### 有向图 + +有多种方法: + +- 一种是先用拓扑排序将外链去掉,再dfs每一个环 +- DFS: 另一种是从某一点出发,记录途径的点,如果遇到已经访问过的点,说明找到了环的入口。减去起始点到入口的距离,就是环的长度。 +- 还有一种有并查集,对于`x->y`,如果`x`和`y`同属于一个集合,说明形成了一个环。 + + + +dfs代码 + +```python +class Solution: + def longestCycle(self, edges: List[int]) -> int: + n = len(edges) + vis = collections.defaultdict(bool) + ans = -1 + for i in range(n): + if vis[i]: continue + path = [] + cur = i + while not vis[cur]: + vis[cur] = True + path.append(cur) + cur = edges[cur] + if cur == -1: break + if cur == -1: continue + for j in range(len(path)): + if path[j] == cur: + t = len(path) - j + ans = max(ans, t) + break + return ans +``` + +### 无向图 + +和有向图类似,略 + +## 最长链 + +等价问题: [310. 最小高度树](https://leetcode.cn/problems/minimum-height-trees/) + +### 有向图 + +这里有一个很重要的问题,有环怎么办? +有环的情况下,求最长链是没有意义的。要么保证无环,要么是求连接到环上的链的长度。 +例如求连接到环上的链的长度,需要从入度为0的节点开始,递推计算,于是采用拓扑序。 + + + +```c++ +int TopologicalSort(vector& favorite) { + int n = favorite.size(); + vector vis(n, false); + vectorin(n, 0); + vectordp(n, 1); + queue q; + for(int i = 0;i < n;i++) in[favorite[i]]++; + for(int i = 0;i < n;i++) { + if(in[i] == 0) q.push(i); + } + while(!q.empty()) { + int cur = q.front(); + q.pop(); + // cout << cur << " "; + dp[favorite[cur]] = max(dp[favorite[cur]], dp[cur] + 1); + if(--in[favorite[cur]] == 0) q.push(favorite[cur]); + } + // dp[i] 表示到达i的最长链的长度 + int two_point_sum = 0; // 题目相关部分 + for(int i = 0;i < n;i++) { + if(i == favorite[favorite[i]]) two_point_sum += dp[i]; + } + return two_point_sum; +} +``` + +### 无向无环图 + +- 也可以和有向图一样,拓扑序+dp +- 还有一种有趣的方法,两次dfs。可以证明,从任一点出发,dfs能走到的最远点一定是"直径"的一个端点,然后从这个端点出发,dfs得到另一个端点。 参考下面【路径最长的两个叶子节点】 + +例如[Leetcode310最小树高度](https://leetcode.cn/problems/minimum-height-trees/solution/zui-xiao-gao-du-shu-by-leetcode-solution-6v6f/),等价于求树的直径 +第一次dfs找到一个端点,再从这个端点出发dfs找到另一个端点,最后在写个dfs得到路径 + + + +### DFS/BFS 求最长链 + +> [参考](https://leetcode.cn/problems/minimum-height-trees/solution/zui-xiao-gao-du-shu-by-leetcode-solution-6v6f/) + +可以利用以下算法找到图中距离最远的两个节点与它们之间的路径: + +以任意节点 pp 出现,利用广度优先搜索或者深度优先搜索找到以 pp 为起点的最长路径的终点 xx; + +以节点 xx 出发,找到以 xx 为起点的最长路径的终点 yy; + +xx 到 yy 之间的路径即为图中的最长路径,找到路径的中间节点即为根节点。 + +上述算法的证明可以参考「[算法导论习题解答 9-1](http://courses.csail.mit.edu/6.046/fall01/handouts/ps9sol.pdf)」。 + + + +## 参考 + +- [图的最大环最长链](https://www.cnblogs.com/lfri/p/15758120.html) diff --git "a/_posts/Tech/Algorithms/2022-08-19-\346\225\260\344\275\215DP.md" "b/_posts/Tech/Algorithms/2022-08-19-\346\225\260\344\275\215DP.md" new file mode 100644 index 0000000000..ffdd366c48 --- /dev/null +++ "b/_posts/Tech/Algorithms/2022-08-19-\346\225\260\344\275\215DP.md" @@ -0,0 +1,91 @@ +--- +layout: post +category: Algorithms +title: 数位DP +tags: Algorithms +--- + +## 数位DP + +数位:把一个数字按照个、十、百、千等等一位一位地拆开,关注它每一位上的数字。如果拆的是十进制数,那么每一位数字都是 0~9,其他进制可类比十进制。 + +数位 DP:用来解决一类特定问题,这种问题比较好辨认,一般具有这几个特征: + +1. 要求统计满足一定条件的数的数量(即,最终目的为计数); +2. 这些条件经过转化后可以使用「数位」的思想去理解和判断; +3. 输入会提供一个数字区间(有时也只提供上界)来作为统计的限制; +4. 上界很大(比如 ),暴力枚举验证会超时。 + + + +比如统计[a,b] 之间的满足某个条件的数,这个b可能是1e15这样。 注定无法枚举。此类就可以数位DP, 然后a到b形式也可以变成f(b) -f(a)差分来统一处理。记得a这个本身单个可能要额外减去。 + +## 模板 + +1. 记忆化搜索 +2. 关键参数: 数位i, 用过数字mask, is_limit是否是受限,is_num前面是否填了数字.后面两个参数可适用于其它数位 DP 题目。 + +该模板对应[视频](https://www.bilibili.com/video/BV1rS4y1s721?vd_source=9d3646ab1738010f91f766880db9c1c6) + +题目: [2376. 统计特殊整数](https://leetcode.cn/problems/count-special-integers/) + +> 如果一个正整数每一个数位都是 **互不相同** 的,我们称它是 **特殊整数** 。 +> +> 给你一个 **正** 整数 `n` ,请你返回区间 `[1, n]` 之间特殊整数的数目。 + +```python +class Solution: + def countSpecialNumbers(self, n: int) -> int: + # 数位dp + s = str(n) + import functools + ''' + 记忆化搜索,i表示计算数位i, mark表示用过的数字 + 返回从数位i开始填数字,前面填数字的集合为mask, 能构造出整数的数量 + is_limit表示是否前i-1位是s对应位上的,即最大受限值max了,如果是则当前数字上线是s[i],而不是'9' + is_num表示前面是否填了数字,如果为True,则当前可从0开始,否则只能从1开始,后续会有个数位变成True, 从该数位开始是真实数字 + ''' + @functools.lru_cache(None) + def f(i: int, mask: int, is_limit: bool, is_num: bool): + if i == len(s): + # 最后一位了,合法则return 1 + return int(is_num) + res = 0 + if not is_num: + # 此时已经有前缀0了,因此不受限 + res += f(i + 1, mask, False, False) + # 数位i的上限 + up = int(s[i]) if is_limit else 9 + # 如果是is_num, 则可以从0开始,否则只能从1开始,毕竟是第一位数字 + for d in range(1 - int(is_num), up + 1): + if (mask >> d) & 1 == 0: + # 没用过该数字 + res += f(i + 1, mask | (1 << d), is_limit and d == up, True) + return res + + # 第一位就受限,因此is_limit = True + return f(0, 0, True, False) + +``` + +## 应用 + +- [902. 最大为 N 的数字组合](https://leetcode.cn/problems/numbers-at-most-n-given-digit-set/) 求1-N的使用了digits里数字的数量,没有0, f(i: int, is_limit: bool, is_num: bool) + +- [233. 数字 1 的个数](https://leetcode.cn/problems/number-of-digit-one/) 给定一个整数 `n`,计算所有小于等于 `n` 的非负整数中数字 `1` 出现的个数。def f(i: int, ones: int, is_limit: bool, is_num: bool): ones是当前已用ones的数量。 + +- [面试题 17.06. 2出现的次数](https://leetcode.cn/problems/number-of-2s-in-range-lcci/) 和数字1的个数类似。 + +- [600. 不含连续1的非负整数](https://leetcode.cn/problems/non-negative-integers-without-consecutive-ones/) 给定一个正整数 `n` ,返回范围在 `[0, n]` 都非负整数中,其二进制表示不包含 **连续的 1** 的个数。def f(i: int, last_is_one: bool, is_limit: bool) + +- [1012. 至少有 1 位重复的数字](https://leetcode.cn/problems/numbers-with-repeated-digits/) 等价为n-完全不重复个数 + +- [1397. 找到所有好字符串](https://leetcode.cn/problems/find-all-good-strings/) + +- 给你两个长度为 n 的字符串 s1 和 s2 ,以及一个字符串 evil 。请你返回 好字符串 的数目。好字符串 的定义为:它的长度为 n ,字典序大于等于 s1 ,字典序小于等于 s2 ,且不包含 evil 为子字符串。 难点在于要动态维护kmp,先求evil的next数组,然后把匹配j当dp参数传递下去。 + + + +## 参考 + +https://leetcode.cn/problems/count-special-integers/solution/shu-wei-dp-mo-ban-by-endlesscheng-xtgx/ diff --git "a/_posts/Tech/Algorithms/2022-10-10-\345\255\227\347\254\246\344\270\262hash.md" "b/_posts/Tech/Algorithms/2022-10-10-\345\255\227\347\254\246\344\270\262hash.md" new file mode 100644 index 0000000000..83d09a4b43 --- /dev/null +++ "b/_posts/Tech/Algorithms/2022-10-10-\345\255\227\347\254\246\344\270\262hash.md" @@ -0,0 +1,73 @@ +--- +layout: post +category: Algorithms +title: 字符串hash +tags: Algorithms +--- + +## 字符串hash + +字符串hash得到hash值,用于o(1)时间复杂度判断是否相等。在提前计算好整个字符串的预处理情况下,可快速比较某两子串是否相等。 + + + +[oi wiki参考](https://oi-wiki.org/string/hash/) + + + +![image-20221010130458789](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202210101304818.png) + + + +## 模板 + +```python +class StringHash: + def __init__(self, s=""): + self.MOD = 998244353 + self.BASE = 131 + # 计算前缀哈希值 + n = len(s) + P = [0] * (n + 1) + P[0] = 1 + for i in range(1, n + 1, 1): + P[i] = P[i - 1] * self.BASE % self.MOD + H = [0] * (n + 1) + for i in range(1, n + 1, 1): + H[i] = (H[i - 1] * self.BASE + ord(s[i - 1])) % self.MOD + self.H = H + self.P = P + + ''' + s的[l,r]区间的hash值,闭区间, l从1开始 + ''' + + def get_hash(self, l=0, r=0): + l, r = l + 1, r + 1 + return (self.H[r] - self.H[l - 1] * self.P[r - l + 1] % self.MOD + self.MOD) % self.MOD + +示例: https://leetcode.cn/problems/maximum-deletions-on-a-string/submissions/ +class Solution: + def deleteString(self, s: str) -> int: + n = len(s) + dp = [1] * n + hash = StringHash(s) + for i in range(n - 1, -1, -1): + for j in range(i + 1, n): + if (j - i + 1) % 2 == 0: + mid = (i + j) // 2 + if hash.get_hash(i, mid) == hash.get_hash(mid+1, j): + # print(i, j, mid) + dp[i] = max(dp[i], dp[mid+1]+1) + # print(dp[i]) + # print(dp) + return dp[0] +``` + + + +## 题目 + + + +题目: https://leetcode.cn/problems/maximum-deletions-on-a-string/solution/by-tsreaper-9xkh/ diff --git "a/_posts/Tech/Algorithms/2022-10-16-\345\217\214\346\214\207\351\222\210.md" "b/_posts/Tech/Algorithms/2022-10-16-\345\217\214\346\214\207\351\222\210.md" new file mode 100644 index 0000000000..66fdad41f9 --- /dev/null +++ "b/_posts/Tech/Algorithms/2022-10-16-\345\217\214\346\214\207\351\222\210.md" @@ -0,0 +1,39 @@ +--- +layout: post +category: Algorithms +title: 双指针 +tags: Algorithms +--- + +## 双指针 + + + +1. 统计子数组数目,枚举右边界,左边界视情况而定。比如求子数组数目,要求子数组包含两个值,那枚举i,j就等于有两个值的最后最小坐标,每次结果可加i-j+1, 实例题目 [6207. 统计定界子数组的数目](https://leetcode.cn/problems/count-subarrays-with-fixed-bounds/) [题解](https://leetcode.cn/problems/count-subarrays-with-fixed-bounds/solution/hua-dong-chuang-by-yi-wei-8-c7h7/) + +2. [3Sum](https://leetcode-cn.com/problems/3sum/) 排序+双指针 + +3. [Longest Repeating Character Replacement](https://leetcode-cn.com/problems/longest-repeating-character-replacement/) 给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。 + + 解答: **双指针。这个双指针属于left每次只移动一次,记得看下。** + +4. [11. 盛最多水的容器](https://leetcode.cn/problems/container-with-most-water/) 多个柱子,挑两个柱子,统计最多能接多少水,双指针,不断缩小两边矮的那个 + +5. [1438. 绝对差不超过限制的最长连续子数组](https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/) 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。 维护max, min的队列,同时双指针,不断移动左指针。 + +6. [6270. 每种字符至少取 K 个](https://mafulong.github.io/2022/12/25/6270.-%E6%AF%8F%E7%A7%8D%E5%AD%97%E7%AC%A6%E8%87%B3%E5%B0%91%E5%8F%96-K-%E4%B8%AA/) 给你一个由字符 `'a'`、`'b'`、`'c'` 组成的字符串 `s` 和一个非负整数 `k` 。每分钟,你可以选择取走 `s` **最左侧** 还是 **最右侧** 的那个字符。 + + 你必须取走每种字符 **至少** `k` 个,返回需要的 **最少** 分钟数 + +7. [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) + +8. 给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。 + + 如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。 + + 反向思考,找最大子数组。 + + + + + diff --git "a/_posts/Tech/Algorithms/2023-01-15-\346\240\221\345\275\242DP\345\222\214\346\215\242\346\240\271DP.md" "b/_posts/Tech/Algorithms/2023-01-15-\346\240\221\345\275\242DP\345\222\214\346\215\242\346\240\271DP.md" new file mode 100644 index 0000000000..42b522f152 --- /dev/null +++ "b/_posts/Tech/Algorithms/2023-01-15-\346\240\221\345\275\242DP\345\222\214\346\215\242\346\240\271DP.md" @@ -0,0 +1,281 @@ +--- +layout: post +category: Algorithms +title: 树形DP和换根DP +tags: Algorithms +--- + +## 树形DP和换根DP + +[oi wiki](https://oi-wiki.org/dp/tree/) + +## 树形DP + +固定一个根节点。在树上做DP. 往往是树dfs遍历,先子树再基于子树结果对当前节点DP递推到根节点。 + + + +对于图转树的DFS遍历,其实就是无向树。 + +```python +class DoubleTree: + def tree_dfs(graph, root): + ''' + 这种树上dfs不需要维护visit记录,只需要记录遍历刀当前节点的parent就可以了。时间复杂度o(n) + ''' + import collections + p = collections.defaultdict(lambda: -1) + + def dfs(u): + if len(graph[u]) == 1 and u in p: + print("is leaf") + for v in graph[u]: + if p[u] != v: # 非访问过 + # 多次生效,针对多个v + p[v] = u + dfs(v) + + def dfs_p(u, p): + if len(graph[u]) == 1 and u != root: + # 判断叶子节点时要用和这个双重判断 + + print("is leaf") + for v in graph[u]: + if v != p: + dfs_p(v, u) + + +``` + + + +也可以通过 g[0].append(-1) # 防止根节点被认作叶子 + + + + + +经典树形DP + +- [124. 二叉树中的最大路径和](https://leetcode.cn/problems/binary-tree-maximum-path-sum/) 给你一个二叉树的根节点 `root` ,返回其 **最大路径和** 。 + + ```python + class Solution: + ans = float('-inf') + + def maxPathSum(self, root: TreeNode) -> int: + def dfs(node): + if not node: + return 0 + l = dfs(node.left) + r = dfs(node.right) + self.ans = max(self.ans, max(l, 0) + max(r, 0) + node.val) + return max(l, r, 0) + node.val + dfs(root) + return self.ans + ``` + + + +- [310. 最小高度树](https://leetcode.cn/problems/minimum-height-trees/) +- [6294. 最大价值和与最小价值和的差值](https://leetcode.cn/problems/difference-between-maximum-and-minimum-price-sum/) 求最长直径,随便固定一个点为root。 树形DP +- [2246. 相邻字符不同的最长路径](https://leetcode.cn/problems/longest-path-with-different-adjacent-characters/) 和最大路径和一样 + + + + + +## 换根DP + +- [参考](https://leetcode.cn/problems/difference-between-maximum-and-minimum-price-sum/solution/huan-gen-dong-tai-gui-hua-jie-fa-by-vcli-gaii/) + +换根DP就是再已知u节点为根节点的情况下,取u节点的一个孩子节点作为新的根节点,不断递归,求出所有节点为根节点情况时的结果。这其实就是一个二次dfs的过程。 + +第一次dfs是处理0节点为根节点的情况。 + +第二次dfs是0节点换根到其中子节点,并不断重复的dfs. + +两次dfs都是在一个双向图上做遍历。因此要用`dfs(u, p)`这种dfs方式。 + +```scala + def dfs(u, p): + # dp[u] 根据子节点的预处理数组更新, optional + for v in graph[u]: + if v == p: continue + # xxxx + # 预处理数组更新, h0[u] = xxx, h0[v] = xxx, optional + # dp[u] 更新作为非根时变换, optional + # dp[v] 更新作为根时变换, optional + dfs(v, u) # 换根 + # 恢复dp[u], dp[v], 预处理数组到u为根节点时的状态 +``` + +第二次dfs时,u节点已经是根节点了,如果有预处理数组,则u的子节点的值已经转成正确的了,计算机u节点的dp值就可以根据u的子节点预处理数组计算了。 + +换根到子节点前,也需要更新下预处理数组中关于u节点的信息,因此换根后u节点就是子节点了。 + +记住每次改变只有u 和 v的dp值改变,以及预处理数组中关于u和v的值改变。 + + + + + +通常题目: + +- 求满足条件的根的可能数量 +- 求每个节点为根时的一个结果。 + +时间复杂度通常是O(n) + + + +换根时预处理数组转换 + +- 孩子节点数目size。[834. 树中距离之和](https://leetcode.cn/problems/sum-of-distances-in-tree/) +- 孩子最大高度。[310. 最小高度树](https://leetcode.cn/problems/minimum-height-trees/) +- 孩子最长路径节点价值和。类似最大高度。[2538. 最大价值和与最小价值和的差值](https://leetcode.cn/problems/difference-between-maximum-and-minimum-price-sum/) + + + + + +**旧版:** + + + +树形 DP 中的换根 DP 问题又被称为二次扫描,通常不会指定根结点,并且根结点的变化会对一些值,例如子结点深度和、点权和等产生影响。 + +通常需要两次 DFS,第一次 DFS 预处理诸如深度,点权和之类的信息,在第二次 DFS 开始运行换根动态规划。 + +第二次dfs时,把父节点作为子树。来调整。比如 [参考](https://zhuanlan.zhihu.com/p/437753260) + +![image-20230115160137183](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202301151601264.png) + +需要计算出换根后的值的变化。 然后枚举根。 + + + +每次换根只能换相邻的。否则影响其它节点计算。只有相邻时只影响相邻的。而且枚举的一定是根,而不是第三个点为根的情况的相邻递推。 + +换根后不用恢复数据,因为是邻接点递推的。其它的没用。 + + + + +记住每次改变只有u 和 v的dp值改变。[详细](https://leetcode.cn/problems/sum-of-distances-in-tree/solution/shu-zhong-ju-chi-zhi-he-by-leetcode-solution/) + + +- [834. 树中距离之和](https://leetcode.cn/problems/sum-of-distances-in-tree/) 给定一个无向、连通的树。树中有 `n` 个标记为 `0...n-1` 的节点以及 `n-1` 条边 。返回长度为 `n` 的数组 `answer` ,其中 `answer[i]` 是树中第 `i` 个节点与所有其他节点之间的距离之和。 +- [310. 最小高度树](https://leetcode.cn/problems/minimum-height-trees/) [参考题解](https://leetcode.cn/problems/difference-between-maximum-and-minimum-price-sum/solution/huan-gen-dong-tai-gui-hua-jie-fa-by-vcli-gaii/) + +```python +class Solution: + def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]: + graph = collections.defaultdict(list) + for a, b in edges: + graph[a].append(b) + graph[b].append(a) + h0 = [0 for _ in range(n)] + + def dfs(u, p): + nonlocal h0 + l = 0 + for v in graph[u]: + if v == p: continue + l = max(l, dfs(v, u) + 1) + h0[u] = l + return l + + dfs(0, -1) + # print(h0) + + dp = [0] * n + + def dfs2(u, p): + nonlocal dp + # 此时就是u为root,每次进入函数都是已经换根为u了。此时孩子的h0是准的,h0[u]是不准的,需要根据孩子重新计算 + first, second = -1, -1 + for v in graph[u]: + if h0[v] >= first: + second = first + first = h0[v] + elif h0[v] >= second: + second = h0[v] + dp[u] = first + 1 + # print(u, dp[u]) + for v in graph[u]: + if v == p: continue + # 假设u与v换根 + h0[u] = first if h0[v] != first else second + h0[u] += 1 + dfs2(v, u) + + dfs2(0, -1) + # print(dp) + minv = min(dp) + ans = [] + for i in range(n): + if dp[i] == minv: + ans.append(i) + return ans + +``` + + + +- [6294. 最大价值和与最小价值和的差值](https://leetcode.cn/problems/difference-between-maximum-and-minimum-price-sum/) 换根DP + +```python +class Solution: + def maxOutput(self, n: int, edges: List[List[int]], price: List[int]) -> int: + graph = collections.defaultdict(list) + for a, b in edges: + graph[a].append(b) + graph[b].append(a) + # 求最大价值和 + h0 = [0 for _ in range(n)] + + + # 第一次遍历,统计以0为根的结果 + def dfs(u, p): + nonlocal h0 + l = price[u] + for v in graph[u]: + if v == p: continue + dfs(v, u) + l = max(l, price[u] + h0[v]) + h0[u] = l + return l + + dfs(0, -1) + # print(h0) + + dp = [0] * n + + def dfs2(u, p): + nonlocal dp + # 此时就是u为root,每次进入函数都是已经换根为u了。此时孩子的h0是准的,h0[u]是不准的,需要根据孩子重新计算下h0[u] + first, second = 0, 0 + dp[u] = 0 + for v in graph[u]: + # 此时不能continue,因为p是有用的,u为root,无p + # if v == p: continue + if h0[v] >= first: + second = first + first = h0[v] + elif h0[v] >= second: + second = h0[v] + # 以u为根情况下 h0和dp的值 + dp[u] = first + h0[u] = first + price[u] + # print(u, dp[u], first, second) + for v in graph[u]: + if v == p: continue + # 假设u与v换根 + h0[u] = price[u] + (first if (h0[v] != first) else second) + dfs2(v, u) + + dfs2(0, -1) + return max(dp) +``` + diff --git "a/_posts/Tech/Algorithms/2023-01-29-\347\273\237\350\256\241\345\233\233\345\205\203\347\273\204\344\271\213\344\270\255\351\227\264\346\236\232\344\270\276.md" "b/_posts/Tech/Algorithms/2023-01-29-\347\273\237\350\256\241\345\233\233\345\205\203\347\273\204\344\271\213\344\270\255\351\227\264\346\236\232\344\270\276.md" new file mode 100644 index 0000000000..087462b364 --- /dev/null +++ "b/_posts/Tech/Algorithms/2023-01-29-\347\273\237\350\256\241\345\233\233\345\205\203\347\273\204\344\271\213\344\270\255\351\227\264\346\236\232\344\270\276.md" @@ -0,0 +1,23 @@ +--- +layout: post +category: Algorithms +title: 统计四元组之中间枚举 +tags: Algorithms +--- + +## 统计四元组之技巧 中间枚举 + +有些题目是让统计四元组之类的数量。 + +此时就可以枚举中间的。 + +通常可以应用些预处理来降低时间复杂度。 + + + +应用 + +- [6340. 统计上升四元组](https://leetcode.cn/contest/weekly-contest-330/problems/count-increasing-quadruplets/) [参考](https://leetcode.cn/circle/discuss/LWLEFc/view/4dIQzE/) + +- [2242. 节点序列的最大得分](https://leetcode.cn/problems/maximum-score-of-a-node-sequence/) + diff --git "a/_posts/Tech/docker/2019-07-27-docker\345\205\245\351\227\250.md" "b/_posts/Tech/Container/2019-07-27-docker\345\205\245\351\227\250.md" similarity index 71% rename from "_posts/Tech/docker/2019-07-27-docker\345\205\245\351\227\250.md" rename to "_posts/Tech/Container/2019-07-27-docker\345\205\245\351\227\250.md" index fc13204ab1..c84a3ca942 100644 --- "a/_posts/Tech/docker/2019-07-27-docker\345\205\245\351\227\250.md" +++ "b/_posts/Tech/Container/2019-07-27-docker\345\205\245\351\227\250.md" @@ -1,14 +1,32 @@ --- layout: post -category: Docker +category: Container title: docker入门 tags: Docker --- # docker入门 +Docker 是一种商业容器化平台和运行时环境,它可帮助开发人员构建、部署和运行容器。它采用客户端-服务器架构,通过单个 API 提供简单的命令和自动化功能。 + +Docker 还提供一个工具包,它常用于将应用打包为不可变的容器镜像,即通过编写 [Dockerfile](https://docs.docker.com/engine/reference/builder/),然后运行相应的[命令](https://docs.docker.com/engine/reference/commandline/build/)来使用 Docker 服务器构建镜像。开发人员可以不使用 Docker 创建容器,但使用 Docker 平台可以让创建过程更加便捷。然后,可以将这些容器镜像部署到任何支持容器的平台上运行,例如 Kubernetes、Docker Swarm、Mesos 或 HashiCorp Nomad。 + + + +运行容器前需要编写Docker File,通过 dockerFile 生成镜像,然后才能运行 Docker 容器。 + +Docker File 定义了运行镜像(image)所需的所有内容,包括操作系统和软件安装位置。一般情况下都不需要从头开始编写 Docker File,在 Docker Hub 中有来自世界各地的工程师编写好的镜像,你可以基于此修改。 + +虚拟化技术已经走过了三个时代,没有容器化技术的演进就不会有 Docker 技术的诞生。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202303082226902.png) + + + + ## 简单三部曲 + [官方参考](https://docs.docker.com/get-started/) 可运行以下脚本 diff --git a/_posts/Tech/Container/2023-03-08-k8s.md b/_posts/Tech/Container/2023-03-08-k8s.md new file mode 100644 index 0000000000..e80af9532d --- /dev/null +++ b/_posts/Tech/Container/2023-03-08-k8s.md @@ -0,0 +1,75 @@ +--- +layout: post +category: Container +title: k8s +tags: Container +--- + +## k8s + +Kubernetes(有时也称为 K8s)是一个广受欢迎的开源平台,可以跨越网络资源集群来编排容器运行时系统。不论有无 Docker,均可使用 Kubernetes。 + +Kubernetes 最初由 Google 开发,该公司需要一种全新方式来每周大规模运行数十亿个容器。2014 年,Kubernetes 由 Google 以开源形式发布,现被广泛认为是容器和分布式应用部署领域的市场领导者和行业标准编排工具。[Google 表示](https://queue.acm.org/detail.cfm?id=2898444),Kubernetes 的“主要设计目标是简化复杂分布式系统的部署与管理,同时仍然受益于容器带来的更高利用率。” + +Kubernetes 将一系列容器捆绑成一组,并在同一台机器上进行管理,以减少网络开销并提高资源使用效率。例如,应用服务器、Redis 缓存和 SQL 数据库便是此此类容器集。Docker 容器的特点是每个容器一个进程。 + + + +## 有了容器为何需要k8s + +Docker 提供容器的生命周期管理和,[Docker](https://link.segmentfault.com/?enc=IMFQZ%2BeeI7dBtplzfKTw3Q%3D%3D.QrUq9Oz3A4oa%2FwDSC9RDPSISW7u34lI46PhRGInHHOd%2FKKe2YyzXmnKCZGw9CC0hpYMMItTK6AbXm9HYoRZOa%2BtgNwetTCKuJGbbTcKQNFYN%2BlWlCIRn74EYt%2F1F3aPyKA%2BfIIibdZ9su%2FMIH%2FRvPzUKfJOThlhxIyD2kjiU%2Fvu7oza%2BKL88Kk%2FGxDx2X9VfEc4fdK5wG1oU3iJ908sMJiptGxQIBfacr%2BUM52e20DvJL1hYtzoNKoDQfv4On%2FOW2jrjskVIsJWpnTrGE5bc%2FJrfSHU0PHMTc2%2BS1ztWR7neofBwAWqTnjMyJoZqKtE5) 镜像构建运行时容器。它的主要优点是将将软件/应用程序运行所需的设置和依赖项打包到一个容器中,从而实现了可移植性等优点。 + +[Kubernetes](https://link.segmentfault.com/?enc=W81xiwGoNRkvUPq6WfcWfg%3D%3D.KxqHDaD%2B%2BR2FaIDFTlmkFD756ZnXYK2ioDgLAwRRq2JjkLmkagG3T2%2BjXlwt%2Byi%2Bpv%2BL84c%2FuffzfvOX1auNr2bqdSSokkIoVL1OCHAyS8P8sB8GLoYna5%2B%2FvBqtDP59%2FmlGrala2AmkscHWKr7M7gTvRZBRtmRfWLswIJXeDLFAYSeyTjskXGU6uy45eiiDlLHI6%2B9sZLmf3a9UfYRcxM5vq47c%2FY9eTnRQu7%2Bal3nFanU2bjFCeg91DLprZi9qwrq40VKU8104ofE9iFZ96ljUk25mFBf5sXRbv0QJ14Doi2542WRqrtfuOTxc3a4J) 用于关联和编排在多个主机上运行的容器。 + + + +尽管Docker为容器化的应用程序提供了开放标准,但随着容器越来越多出现了一系列新问题: + +- 如何协调和调度这些容器? +- 如何在升级应用程序时不会中断服务? +- 如何监视应用程序的运行状况? +- 如何批量重新启动容器里的程序? + +解决这些问题需要容器编排技术,可以将众多机器抽象,对外呈现出一台超大机器。现在业界比较流行的有:k8s、Mesos、Docker Swarm。 + +在业务发展初期只有几个微服务,这时用 Docker 就足够了,但随着业务规模逐渐扩大,容器越来越多,运维人员的工作越来越复杂,这个时候就需要编排系统解救opers。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202303082229567.png) + + + +## k8s架构 + +K8s总体来说是主从架构模式Master - Slave架构,master节点负责调度、管理,slave节点负责具体程序的运行和节点服务,在K8s里面,主节点一般叫做master node,从节点叫做worker node。所有的主节点和从节点一起组成了K8s集群,在集群里面master和slave都可以是多个,是一个多主多从的集群架构。 + +### 2.1 K8s Master Node核心组件 + + +- **API Server**:作用是K8s的请求入口提供能力,API Server组件负责接收K8s所有的命令请求,不管是UI控制台还是命令行都会经过API Server组件,API Server负责接收具体的命令请求,去通知其它组件工作。 +- **Scheduler**:是K8s调度所有worker节点的调度组件,当K8s需要部署服务时,通过Scheduler调度组件来负责调度具体的Worker Node节点来进行服务的部署工作。 +- **Controller Manager**:监控K8s所有的Worker Node,对工作节点的性能和工作状态监控,例如某个节点的服务挂了以后,Controller Manager组件就会立马感知到,然后通知Scheduler组件去调度选择Worker Node来重新部署服务。Controller Manager是由多个Controller组成:`Node Controller`、`Service Controller`、`Volume Controller`等 +- **etcd**:K8s默认的数据信息存储服务,是一个基于Raft算法的分布式KV服务器,类似于ZK功能。etcd存储了K8s的关心配置和用户配置数据。 + + +### 2.2 K8s Worker Node核心组件 + + +- Kubelet:工作节点的监视器,并且负责和Master Node进行通信,定时的向Master Node上报工作节点的服务状态,并且负责接收Master Node发来的各种命令。 +- Kube Proxy:工作节点的网络代理组件,负责基础通信能力。 +- Container Runtime:工作节点的运行时环境。 + + +## 3.K8s核心概念 + +### 3.1 Deployment + +Deployment负责创建和更新应用程序的实例,创建Deployment后,K8s的Master节点会将应用程序实例调度到集群中各个Worker节点上。Pod是K8s最小的编排单位,K8s要支持弹性扩容、负载均衡就得需要一个Controller来管理,Deployment就是来控制和编排应用程序。 在Deployment的配置文件里面可以指定需要部署的Pod标签、Pod个数等。 + +### 3.2 Pod + +Pod是K8s编排容器的最小逻辑单元,Pod也相当于是一个逻辑主机的概念负责管理具体的应用实例,包括1个或多个Docker容器,一般是一对一关系。 Pod同样也有yaml配置文件,在配置文件里面可以配置暴露的端口、服务标签、镜像信息等。 + +### 3.3 Service + +Service是K8s里面的一个抽象的概念,Service是一组Pod的逻辑集合,给这些Pod提供服务发现、负载的能力。 虽然每一个Pod都有自己的IP和端口,但是Pod的IP并不会暴露给外部;访问Pod必须通过Service,Service提供流量的接收。Service可以通过配置Type来对外暴露访问入口,默认是ClusterIP模式(在几群的内部IP上公开Servcie),除了这个默认模式外,还提供NodePort、LoadBalancer等。 Service同样提供了yaml文件配置,可以配置例如暴露端口、Pod的选择等。 + diff --git "a/_posts/Tech/Database/2021-01-09-\346\225\260\346\215\256\345\272\223\345\257\271\346\257\224.md" "b/_posts/Tech/Database/2021-01-09-\346\225\260\346\215\256\345\272\223\345\257\271\346\257\224.md" index 0f45d5872d..1d12cfacdb 100644 --- "a/_posts/Tech/Database/2021-01-09-\346\225\260\346\215\256\345\272\223\345\257\271\346\257\224.md" +++ "b/_posts/Tech/Database/2021-01-09-\346\225\260\346\215\256\345\272\223\345\257\271\346\257\224.md" @@ -270,4 +270,19 @@ Google 发布了第一个列型存储数据库 [Bigtable](http://www.read.seas.h - 排行榜或者得分数据 - 临时数据,如购物车 - 频繁访问的(“热”)表 -- 元数据/查找表 \ No newline at end of file +- 元数据/查找表 + + + +## NoSQL + +> [参考](https://aws.amazon.com/cn/nosql/) + +### 为什么应该使用 NoSQL 数据库? + +NoSQL 数据库非常适合许多现代应用程序,例如移动、Web 和游戏等应用程序,它们需要灵活、可扩展、高性能和功能强大的数据库以提供卓越的用户体验。 + +- **灵活性:**NoSQL 数据库通常提供灵活的架构,以实现更快速、更多的迭代开发。灵活的数据模型使 NoSQL 数据库成为半结构化和非结构化数据的理想之选。 +- **可扩展性:**NoSQL 数据库通常被设计为通过使用分布式硬件集群来横向扩展,而不是通过添加昂贵和强大的服务器来纵向扩展。一些云提供商在后台将这些操作处理为完全托管服务。 +- **高性能:**NoSQL 数据库针对特定的数据模型和访问模式进行了优化,这与尝试使用关系数据库完成类似功能相比可实现更高的性能。 +- **强大的功能:**NoSQL 数据库提供功能强大的 API 和数据类型,专门针对其各自的数据模型而构建。 \ No newline at end of file diff --git a/_posts/Tech/DistributedSystem/2018-11-22-consul.md b/_posts/Tech/DistributedSystem/2018-11-22-consul.md index 8f9d81f2b3..7014ad4166 100644 --- a/_posts/Tech/DistributedSystem/2018-11-22-consul.md +++ b/_posts/Tech/DistributedSystem/2018-11-22-consul.md @@ -29,7 +29,7 @@ Consul使用gossip协议管理成员关系、广播消息到整个集群,他 ![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv3/v3/20211224165321.png) - +图里的client不是consul里的,是consul使用者。 ## 实现原理 diff --git a/_posts/Tech/DistributedSystem/2020-12-15-SOA.md b/_posts/Tech/DistributedSystem/2020-12-15-SOA.md index 9242fbf352..b1516a5a4f 100644 --- a/_posts/Tech/DistributedSystem/2020-12-15-SOA.md +++ b/_posts/Tech/DistributedSystem/2020-12-15-SOA.md @@ -20,12 +20,9 @@ SOA是支持面向服务的架构方式。面向服务是一种从服务、基 -### 知乎对此描述 +### 解释 -作者:光太狼 -链接:https://www.zhihu.com/question/42061683/answer/251131634 -来源:知乎 -著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 +Refer: https://www.zhihu.com/question/42061683/answer/251131634 @@ -63,3 +60,45 @@ SOA粗暴理解:把系统按照实际业务,拆分成刚刚好大小的、 ## SOA和微服务microservice的区别 +我们应该将SOA视为微服务的超集。 + + + +| **SOA架构** | **微服务架构** | +| ---------------------------------------- | ---------------------------------------- | +| 最大化应用服务的可重用性 | 关注于解耦 | +| 系统的变化需要修改整体结构 | 系统的变化是创造一种新的服务 | +| DevOps和持续交付正在变得流行,但不是主流 | 专注于DevOps和持续交付 | +| 专注于业务功能的可重用性 | 更加重视“边界上下文”的概念 | +| 对于通信,它使用企业服务总线(ESB) | 对于通信使用不那么复杂和简单的消息系统 | +| 支持多种消息协议 | 使用轻量级协议,如HTTP,REST或Thrift API | +| 为部署到它的所有服务使用通用平台 | 应用服务器并未真正使用,通常使用云平台 | +| 使用容器(如Docker)不太受欢迎 | 容器与微服务一起工作得很好 | +| SOA服务共享数据存储 | 每个微服务可以具有独立的数据存储 | +| 共同治理和标准 | 轻松治理,更加注重团队协作和选择自由度 | + +我将在上表中显示的某些方面进一步详细说明,并进一步解释其中的差异: + +- 开发 - 在这两种体系结构中,可以使用不同的编程语言和工具开发服务,从而为开发团队带来技术多样性。可以在多个团队中组织开发,但是,在SOA中,每个团队都需要了解常见的通信机制。另一方面,通过微服务,服务可以独立于其他服务运行和部署。因此,更容易经常部署新版本的微服务或独立扩展服务。您可以在此处进一步了解微服务的这些优点。 + +- “绑定上下文” - SOA鼓励共享组件,而微服务试图通过“绑定上下文”最小化共享。绑定上下文指的是将组件及其数据作为单个单元耦合,具有最小的依赖性。由于SOA依赖于多种服务来满足业务请求,因此基于SOA构建的系统可能比微服务慢。 + +- 通信 - 在SOA中,ESB可能成为影响整个系统的单点故障。由于每个服务都通过ESB进行通信,如果其中一个服务速度变慢,它可能会阻塞ESB请求该服务。另一方面,微服务在容错方面要好得多。例如,如果一个微服务有内存故障,那么只有那个微服务会受到影响。所有其他微服务将继续定期处理请求。 + +- 互操作性 - SOA通过其消息传递中间件组件促进多个异构协议的使用。微服务试图通过减少集成选择的数量来简化架构模式。**因此,如果要在异构环境中使用不同协议集成多个系统,则需要考虑SOA。如果可以通过相同的远程访问协议访问所有服务,那么微服务对您来说是更好的选择。** + +- 大小 - 最后但并非最不重要的是,**SOA和微服务之间的主要区别在于大小和范围。微服务中的前缀“微”指的是内部组件的粒度,这意味着它们必须比SOA趋向于小得多。微服务中的服务组件通常只有一个目的,他们做得很好。另一方面,在SOA中,服务通常包含更多的业务功能,并且它们通常作为完整的子系统实现。** + + + +人们不能简单地说一个架构比另一个架构好。它主要取决于您正在构建的应用程序的目的。**SOA更适合需要与许多其他应用程序集成的大型复杂企业应用程序环境。** 话虽这么说,**较小的应用程序不适合SOA,因为它们不需要消息传递中间件组件。** 另一方面,**微服务更适合于较小且分区良好的基于Web的系统。此外,如果您正在开发移动或Web应用程序,那么微服务可以让您作为开发人员获得更大的控制权。** 最后,我们可以得出结论,因为它们用于不同的目的 - **微服务和SOA确实是不同类型的架构。** + + + + + +SOA范围大,着眼于整个企业,而微服务范围小,着眼于应用。 + +**SOA是与企业服务的公开性密切相关的,关注的范围更大,是应用与应用之间的通信、服务公开。** + +**微服务是与应用架构紧密相关的,关注的范围小,只关注应用本身的范围。** diff --git "a/_posts/Tech/DistributedSystem/2021-01-09-\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.md" "b/_posts/Tech/DistributedSystem/2021-01-09-\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.md" index 451b6f264b..cde54a6f67 100644 --- "a/_posts/Tech/DistributedSystem/2021-01-09-\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.md" +++ "b/_posts/Tech/DistributedSystem/2021-01-09-\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.md" @@ -96,6 +96,11 @@ __两阶段提交协议解决的是分布式数据库数据强一致性问题__ 针对两阶段提交存在的问题,三阶段提交协议通过引入一个 **预询盘** 阶段,以及超时策略来减少整个集群的阻塞时间,提升系统性能。三阶段提交的三个阶段分别为:预询盘(can_commit)、预提交(pre_commit),以及事务提交(do_commit)。 + + +1. 引入canCommit阶段减少**同步阻塞**。 +2. 引入超时减少**单点故障**,没有协调者消息并超时了,直接 commit + #### 第一阶段:预询盘 该阶段协调者会去询问各个参与者是否能够正常执行事务,参与者根据自身情况回复一个预估值,相对于真正的执行事务,这个过程是轻量的,具体步骤如下: diff --git "a/_posts/Tech/DistributedSystem/2021-01-09-\345\210\206\345\270\203\345\274\217\347\256\227\346\263\225\345\222\214\345\215\217\350\256\256.md" "b/_posts/Tech/DistributedSystem/2021-01-09-\345\210\206\345\270\203\345\274\217\347\256\227\346\263\225\345\222\214\345\215\217\350\256\256.md" index 98418ccab5..37b316420d 100644 --- "a/_posts/Tech/DistributedSystem/2021-01-09-\345\210\206\345\270\203\345\274\217\347\256\227\346\263\225\345\222\214\345\215\217\350\256\256.md" +++ "b/_posts/Tech/DistributedSystem/2021-01-09-\345\210\206\345\270\203\345\274\217\347\256\227\346\263\225\345\222\214\345\215\217\350\256\256.md" @@ -3,6 +3,7 @@ layout: post category: DistributedSystem title: 分布式算法和协议 tags: DistributedSystem +recent_update: true --- ## 分布式算法和协议-思维导图 @@ -37,6 +38,14 @@ tags: DistributedSystem image-20210109160824094 +这里的ZAB为何是最终一致性而不是强一致性?[参考](https://www.zhihu.com/question/455703356/answer/1847949827) + +- 写是强一致性,单领导者模型,写需要majority保证,脑裂情况下也可以写强一致 +- 读两种接口,1:读单个机器的,2:只读主的。但脑裂时多个主还是不能强一致性。 +- etcd做了读的优化,读时也需要majority(多数同意),需要大伙同意认为它是主,但牺牲了效率。 + +这里的一致性是从读写方面,写一致性,都写成功,读一致性,从提供的读接口任意时刻咋读都一样。和事务一致性不太一样。 + ## 分布式互斥方法(集中,民主协商,轮值ceo(令牌)) ![4210e133d9d94ea22917db55458c11c6](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv2/v2/34.png) diff --git "a/_posts/Tech/DistributedSystem/2021-12-26-etcd\345\222\214raft.md" "b/_posts/Tech/DistributedSystem/2021-12-26-etcd\345\222\214raft.md" index 3fd12cdff4..0bf8fbfdf5 100644 --- "a/_posts/Tech/DistributedSystem/2021-12-26-etcd\345\222\214raft.md" +++ "b/_posts/Tech/DistributedSystem/2021-12-26-etcd\345\222\214raft.md" @@ -3,6 +3,7 @@ layout: post category: DistributedSystem title: etcd和raft tags: DistributedSystem +recent_update: true --- # etcd diff --git a/_posts/Tech/DistributedSystem/2022-02-21-zookeeper.md b/_posts/Tech/DistributedSystem/2022-02-21-zookeeper.md new file mode 100644 index 0000000000..e1e4daccb6 --- /dev/null +++ b/_posts/Tech/DistributedSystem/2022-02-21-zookeeper.md @@ -0,0 +1,40 @@ +--- +layout: post +category: DistributedSystem +title: zookeeper +tags: DistributedSystem +--- + +## zookeeper + + + +了解zk: [参考](https://segmentfault.com/a/1190000022431516) + +zk有序树形节点实现分布式锁: [参考](http://www.cyc2018.xyz/%E5%85%B6%E5%AE%83/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/%E5%88%86%E5%B8%83%E5%BC%8F.html#zookeeper-%E7%9A%84%E6%9C%89%E5%BA%8F%E8%8A%82%E7%82%B9) + +- Kafka 选举就用的这个。leader选举。 + +paxos执行过程: [参考](http://www.cyc2018.xyz/%E5%85%B6%E5%AE%83/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/%E5%88%86%E5%B8%83%E5%BC%8F.html#%E6%9C%80%E7%BB%88%E4%B8%80%E8%87%B4%E6%80%A7) + +zk基于zab协议,是个paxos的变种。 + +zk的所有副本都可以提供读服务,与此相对应的,只有主节点可以提供写服务。 + +选举原则:数据最新or ID最大的节点作为主。 + +## QA + +### zk会脑裂吗 + +不会脑裂。默认 **只有获得超过半数节点的投票, 才能选举出leader.** 因此只会有一个leader存在。可能会有部分节点没有follow leader。这些节点已经挂了。 + +### zk or ZAB为何是最终一致性而不是强一致性 + +[参考](https://www.zhihu.com/question/455703356/answer/1847949827) + +- 写是强一致性,单领导者模型,写需要majority保证(写节点超过一半),脑裂情况下也可以写强一致 +- 读两种接口,1:读单个机器的,2:只读主的。如果是后者就是强一致性的。 +- etcd做了读的优化,读时也需要majority,需要大伙同意认为它是主,但牺牲了效率。 + +这里的一致性是从读写方面,写一致性,都写成功,读一致性,从提供的读接口任意时刻咋读都一样。和事务一致性不太一样。 \ No newline at end of file diff --git "a/_posts/Tech/DistributedSystem/2022-11-26-\346\227\240\344\270\273\345\244\215\345\210\266\347\263\273\347\273\237.md" "b/_posts/Tech/DistributedSystem/2022-11-26-\346\227\240\344\270\273\345\244\215\345\210\266\347\263\273\347\273\237.md" new file mode 100644 index 0000000000..ee018bc3b1 --- /dev/null +++ "b/_posts/Tech/DistributedSystem/2022-11-26-\346\227\240\344\270\273\345\244\215\345\210\266\347\263\273\347\273\237.md" @@ -0,0 +1,63 @@ +--- +layout: post +category: DistributedSystem +title: 无主复制系统 +tags: DistributedSystem +--- + +为什么需要复制数据? - 允许系统在部分节点出现故障后继续工作(增加可用性) - 地理上保持数据离用户更近(减少延迟) - 扩展可以提供查询的机器数量(增加读吞吐) + +复制算法: 1. 单主复制:所有客户端都将写入操作发送到主节点上,该节点负责将数据更改事件发送到其它副本。每个副本都可以接受读请求,但内容可能是过期值。 2. 多主复制:系统中存在多个主节点,每个都可以接受请求,客户端将写请求发送到其中一个主节点上,该节点负责将数据更改事件同步到其它主节点和自己的从节点。 3. 无主复制:客户端将写请求发送多个节点上,读取时从多个节点上并行读取,以此检测和纠正某些过期数据。 + +主从复制可参考 [link](https://iswade.github.io/database/replication/) + +## 无主复制 + +单主、多主复制思路都是:客户端向一个主节点发写请求,而DB系统负责将写请求复制到其他副本。主节点决定写顺序,从节点按相同顺序应用主节点发送的写日志。 + +某些数据存储系统采用不同设计:放弃主节点,允许任何副本直接接受客户端的写。最早的复制数据系统就是无主节点的(或称之为去中心复制、无中心复制),但后来在关系数据库主导时代,这个想法几乎被忘却。在亚马逊将其用于其内部的Dynamo系统后,它再一次成为流行的DB架构。 Riak,Cassandra和Voldemort都是由Dynamo启发的无主复制模型的开源数据存储,所以这类数据库也被称为*Dynamo风格*。 + + + +在一些无主实现中,客户端直接将写请求发到多副本,而另一些实现中,有一个协调者(coordinator)节点代表客户端进行写入,但与主节点的数据库不同,协调者不负责维护写入顺序。这种设计差异对DB使用方式有深远影响。 + + + +失效节点重新上线,而客户端开始读取它。节点失效期间发生的任何写入在该节点都尚未同步,因此读取可能得到过期数据。 + +为解决该问题,当一个客户端从DB读数据时,它不是向1个副本发送请求,而是并行发送到多副本。客户端可能会从不同节点获得不同响应,即来自一个节点的最新值和来自另一个节点的旧值。可利用版本号确定哪个值更新。 + +### 读修复和反熵 + +复制模型应确保所有数据最终复制到所有副本。在一个失效节点重新上线后,它如何赶上错过的写入呢? + +Dynamo风格的数据存储系统常机制: + +#### 读修复(Read repair) + +当客户端并行读取多副本时,可检测到过期的返回值。客户端可判断副本3是过期值,然后将新值写入该副本。适用于读密集场景 + +#### 反熵过程(Anti-entropy process) + +一些数据存储有后台进程,不断查找副本之间的数据差异,将任何缺少的数据从一个副本复制到另一个副本。和基于主节点复制的复制日志不同,此反熵过程不保证任何特定的顺序复制写入,并且会引入明显的同步滞后 + + + +并非所有系统都实现这俩方案。如Voldemort目前无反熵过程。若无反熵过程,由于【读修复】只在发生读取时才可能执行修复,那些很少访问的数据有可能在某些副本中已丢失而无法再检测到,从而降低了写的持久性。 + + + +反熵就是树形的hash,用于快速比较数据是否一致的。 + + + +## 参考 + +- [**无主复制系统(1)-节点故障时写DB**](https://blog.51cto.com/u_11440114/5550577) +- [**无主复制系统(2)-读写quorum**](https://blog.51cto.com/u_11440114/5550582) + + + + + +TODO: 需要读下ddia. diff --git a/_posts/Tech/DistributedSystem/2023-03-19-service mesh.md b/_posts/Tech/DistributedSystem/2023-03-19-service mesh.md new file mode 100644 index 0000000000..990d79635e --- /dev/null +++ b/_posts/Tech/DistributedSystem/2023-03-19-service mesh.md @@ -0,0 +1,34 @@ +--- +layout: post +category: DistributedSystem +title: service mesh +tags: DistributedSystem +--- + +## service mesh + +在TCP出现之后,机器之间的网络通信不再是一个难题,以GFS/BigTable/MapReduce为代表的分布式系统得以蓬勃发展。这时,分布式系统特有的通信语义又出现了,如熔断策略、负载均衡、服务发现、认证和授权、quota限制、trace和监控等等,于是服务根据业务需求来实现一部分所需的通信语义。 + +service mesh就实现了这种通信语义。 + +![img](https://pic2.zhimg.com/80/v2-e5660d35a311467c3323f10ebf2fb9a5_1440w.webp) + +服务网格是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但对应用程序透明。 + +**`Service Mesh`目的是解决系统架构微服务化后的服务间通信和治理问题。** 服务网格由`Sidecar`节点组成,这个模式的精髓在于实现了数据面(业务逻辑)和控制面的解耦。具体到[微服务](https://so.csdn.net/so/search?q=微服务&spm=1001.2101.3001.7020)架构中,即给每一个微服务实例同步部署一个`Sidecar`。可以sidecar形式和应用程序部署到一起。 + + + +Service Mesh具有如下优点: + +- 屏蔽分布式系统通信的复杂性(负载均衡、服务发现、认证授权、监控追踪、流量控制等等),服务只用关注业务逻辑; +- 真正的语言无关,服务可以用任何语言编写,只需和Service Mesh通信即可; +- 对应用透明,Service Mesh组件可以单独升级; + + + + + +## 参考 + +- [什么是 Service Mesh](https://zhuanlan.zhihu.com/p/61901608) \ No newline at end of file diff --git a/_posts/Tech/ElasticSearch/2020-12-08-ElasticSearch.md b/_posts/Tech/ElasticSearch/2020-12-08-ElasticSearch.md index de4939df98..5eda1601ec 100644 --- a/_posts/Tech/ElasticSearch/2020-12-08-ElasticSearch.md +++ b/_posts/Tech/ElasticSearch/2020-12-08-ElasticSearch.md @@ -3,6 +3,7 @@ layout: post category: ElasticSearch title: ElasticSearch(ES)原理 tags: ElasticSearch +recent_update: true --- ## Part1: ES介绍及核心概念 diff --git "a/_posts/Tech/FrontEnd/2017-12-03-css\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2017-12-03-css\345\255\246\344\271\240\347\254\224\350\256\260.md" index 1df5eb98e6..a76bfdfb2d 100644 --- "a/_posts/Tech/FrontEnd/2017-12-03-css\345\255\246\344\271\240\347\254\224\350\256\260.md" +++ "b/_posts/Tech/FrontEnd/2017-12-03-css\345\255\246\344\271\240\347\254\224\350\256\260.md" @@ -4,7 +4,39 @@ category: FrontEnd title: CSS笔记 tags: FrontEnd --- +# 概述 + +CSS:Cascading Style Sheet,层叠样式表。CSS 的作用就是给 HTML 页面标签添加各种样式,**定义网页的显示效果**。简单一句话:CSS 将网页**内容和显示样式进行分离**,提高了显示功能。 + +**CSS 优点:** + +1. 使数据和显示分开 +2. 降低网络流量 +3. 使整个网站视觉效果一致 +4. 使开发效率提高了(耦合性降低,一个人负责写 html,一个人负责写 css) + +比如说,有一个样式需要在一百个页面上显示,如果是 html 来实现,那要写一百遍,现在有了 css,只要写一遍。现在,html 只提供数据和一些控件,完全交给 css 提供各种各样的样式。 + +重点:盒子模型、浮动、定位 + + + +CSS 的书写方式,实就是问你 CSS 的代码放在哪个位置。CSS 代码理论上的位置是任意的,**但通常写在` + + +
      +
      + AAAA +
      +
      + + + + +``` + diff --git "a/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260.md" new file mode 100644 index 0000000000..84ad1c0710 --- /dev/null +++ "b/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260.md" @@ -0,0 +1,457 @@ +--- +layout: post +category: FrontEnd +title: html笔记 +tags: FrontEnd +--- + +# 如何理解HTML? + +**Web标准包括三个方面**: + +- 结构标准(HTML):用于对网页元素进行整理和分类。 +- 表现标准(CSS):用于设置网页元素的版式、颜色、大小等外观样式。 +- 行为标准(JS):用于定义网页的交互和行为。 + + + +HTML 不是一种编程语言,是一种描述性的**标记语言**。 + +**作用**:HTML是负责描述文档**语义**的语言。 + +HTML 格式的文件是一个纯本文文件(就是用txt文件改名而成),用一些标签来描述语义,这些标签在浏览器页面上是无法直观看到的,所以称之为“超文本标记语言”。 + +比如,面试的时候问你,`

      ` 标签有什么作用? + +- 正确答案:给文本增加主标题的语义。 +- 错误答案:给文字加粗、加黑、变大。 + +之前的HTMl很混乱,还有些样式的标签,比如粗体`` 等,新一代的html都废弃这些了,使之专门负责语义。 + + + + + +**语义化的意义是什么** + +- 开发者容易理解,便于维护。 +- 机器(搜索引擎、读屏软件等)容易理解结构 +- 有助于 SEO + + + +HTML 相当于人的身体组织结构 + +# 笔记 + + + +- [文档声明头](https://web.qianguyihao.com/01-HTML/03-%E5%88%9D%E8%AF%86HTML.html#_1%E3%80%81%E6%96%87%E6%A1%A3%E5%A3%B0%E6%98%8E%E5%A4%B4) +- [计算机编码介绍](https://web.qianguyihao.com/01-HTML/03-%E5%88%9D%E8%AF%86HTML.html#_4%E3%80%81-body-%E6%A0%87%E7%AD%BE) unicode是4字节表示,ansi是2字节,utf-8是变长。中文除utf8外还可以gbk仅包含常用中文。追求速度就后者,字节少,快,但不全。 +- HTML中所有的**文字之间**,如果有空格、换行、tab都将被折叠为一个空格显示。 + +- [iframe](https://web.qianguyihao.com/01-HTML/07-html%E6%A0%87%E7%AD%BE%E5%9B%BE%E6%96%87%E8%AF%A6%E8%A7%A3%EF%BC%88%E4%BA%8C%EF%BC%89.html#frame-%EF%BC%9A%E6%A1%86%E6%9E%B6) + +```html + + + + + + Title + + + + + + + + + + +

      mafulong

      + +
      + + Baidu + +
      + + + +

      mafulong

      + + +

      mafulong

      +

      mafulong

      + + + mafulong + + mafulong + 引用 +
      自动缩进的长引用
      + 数学变量,斜体表示 + +
      斜体表示
      + +
      +        
      +            保持代码格式,不删除空格
      +        
      +    
      + + + + + + + + + + + + + + + + + + + + +
      NameTelephone
      12323
      fjdf
      + + +
        +
      1. 1
      2. +
      + +
        +
      • +
      + +
      +
      Coffee
      +
      - black hot drink
      +
      Milk
      +
      - white cold drink
      +
      + + Pulpit rock + + +

      无边框的图片链接: + + HTML 教程

      + + + + + + +``` + + + +```html +fieldset,legend 是表单的语义化。 +``` + +- [label标签](https://web.qianguyihao.com/01-HTML/07-html%E6%A0%87%E7%AD%BE%E5%9B%BE%E6%96%87%E8%AF%A6%E8%A7%A3%EF%BC%88%E4%BA%8C%EF%BC%89.html#%E8%A1%A8%E5%8D%95%E7%9A%84%E8%AF%AD%E4%B9%89%E5%8C%96) 将文字绑定到一个input上,避免点文字和点radio等分离,使其作为一个整体。 + +```html + + + + + Title + + + + + + +

      我的母亲有 蓝色 的眼睛。

      + + + +
      +

      这是一个在 div 元素中的标题。

      +

      这是一个在 div 元素中的文本。

      +
      + + + + + + +

      人生啊

      +
      + +
      + + +
      + Personal information: + Name:
      + E-mail:
      + Date of birth: +
      + First name
      + + female + male + + + + + + + + + + + + + +
      + + + +``` + + + +# 速查 + +## 参考手册 + +- [HTML 参考手册](https://www.runoob.com/tags/html-reference.html) + + + +## HTML基本文档 + +```html + + + +文档标题 + + +可见文本... + + +``` + +## 基本标签(Basic Tags) + +```html +

      最大的标题

      +

      . . .

      +

      . . .

      +

      . . .

      +
      . . .
      +
      最小的标题
      + +

      这是一个段落。

      +
      (换行) +
      (水平线) + +``` + +## 文本格式化(Formatting) + +```html +粗体文本 +计算机代码 +强调文本 +斜体文本 +键盘输入 + H5已废弃 +
      预格式化文本
      +更小的文本 +重要的文本 + + (缩写) + TheWHO was founded in 1948. +
      (联系信息) + 就是斜体 + (文字方向) +
      (从另一个源引用的部分) + (工作的名称) + (删除的文本) + (插入的文本) + (下标文本) + (上标文本) +``` + +## 链接(Links) + +```html +普通的链接:链接文本 +图像链接: 替换文本 +邮件链接: 发送e-mail +书签: +提示部分 +跳到提示部分 +``` + + + +> [参考](https://www.runoob.com/html/html-links.html) + +可以超链接可以设置html锚点到某个元素。 + + + +## 图片(Images) + +必须有src和alt属性 + +```html +替换文本 +``` + +## 样式/区块(Styles/Sections) + +```html + +
      文档中的块级元素
      +文档中的内联元素 +``` + +## 无序列表 + +```html +
        +
      • 项目
      • +
      • 项目
      • +
      +``` + +## 有序列表 + +```html +
        +
      1. 第一项
      2. +
      3. 第二项
      4. +
      +``` + +## 定义列表 + +```html +
      +
      项目 1
      +
      描述项目 1
      +
      项目 2
      +
      描述项目 2
      +
      +``` + +## 表格(Tables) + +```html + + + + + + + + + +
      表格标题表格标题
      表格数据表格数据
      +``` + +## 框架(Iframe) + +```html + +``` + +## 表单(Forms) + +每个输入元素必须有一个name属性 + +在form规定action, submit提交就执行,method规定post还是get, 默认是get + +```html +
      + + + + + + + + + + +
      +``` + +> [参考](https://www.runoob.com/html/html-forms.html) + +表单是一个包含表单元素的区域。 + +表单元素是允许用户在表单中输入内容,比如:文本域(textarea)、下拉列表(select)、单选框(radio-buttons)、复选框(checkbox) 等等。 + +我们可以使用 **form** 标签来创建表单 + + + +input也可以脱离form使用,不过可能需要结合ajax等。 + + + +## 实体(Entities) + +```html +< 等同于 < +> 等同于 > +© 等同于 © +``` + + + +## 事件 + +[参考](https://www.runoob.com/tags/ref-eventattributes.html) + +- `onclick`:用户点击 HTML 元素。 +- `onchange`:HTML 元素改变. `onchange` 事件会在域的内容改变时发生。`onchange` 事件也可用于单选框与复选框改变后触发的事件。 +- `onload`:浏览器已完成页面的加载。 +- `onmouseover`:用户在一个HTML元素上移动鼠标。 +- `onmouseout`:用户从一个HTML元素上移开鼠标。 +- `onkeydown`:用户按下键盘按键。 \ No newline at end of file diff --git "a/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260\344\270\212.md" "b/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260\344\270\212.md" deleted file mode 100644 index fa20c72437..0000000000 --- "a/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260\344\270\212.md" +++ /dev/null @@ -1,94 +0,0 @@ ---- -layout: post -category: FrontEnd -title: html笔记上 -tags: FrontEnd ---- - -## html - -```html - - - - - - Title - - - - - - - - - - -

      mafulong

      - -
      - - Baidu - -
      - - - -

      mafulong

      - - -

      mafulong

      -

      mafulong

      - - - mafulong - - mafulong - 引用 -
      自动缩进的长引用
      - 数学变量,斜体表示 - -
      斜体表示
      - -
      -        
      -            保持代码格式,不删除空格
      -        
      -    
      - - - - - - - - - - - - - - - -
      12323
      fjdf
      - - -
        -
      1. 1
      2. -
      - -
        -
      • -
      - - - - - -``` \ No newline at end of file diff --git "a/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260\344\270\213.md" "b/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260\344\270\213.md" deleted file mode 100644 index c2b3556ae5..0000000000 --- "a/_posts/Tech/FrontEnd/2017-12-03-html\345\255\246\344\271\240\347\254\224\350\256\260\344\270\213.md" +++ /dev/null @@ -1,65 +0,0 @@ ---- -layout: post -category: FrontEnd -title: html笔记下 -tags: FrontEnd ---- - -## html - -```html - - - - - Title - - - - - - - - - - - - - -

      人生啊

      -
      - -
      - - - First name
      - - female - male - - - - - - - - - -
      -
      - - -``` diff --git "a/_posts/Tech/FrontEnd/2017-12-03-javascript\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2017-12-03-javascript\345\255\246\344\271\240\347\254\224\350\256\260.md" new file mode 100644 index 0000000000..1d8f9714e1 --- /dev/null +++ "b/_posts/Tech/FrontEnd/2017-12-03-javascript\345\255\246\344\271\240\347\254\224\350\256\260.md" @@ -0,0 +1,2308 @@ +--- +layout: post +category: FrontEnd +title: javascript笔记 +tags: FrontEnd +recent_update: true +--- + +# 语法 + +## 页面如何添加js + +外部脚本, 可以插入任何位置。 需要js后缀 + +```javascript + +``` + +内部脚本 + +```javascript + +``` + +脚本可被放置在 HTML 页面的 body和head部分中。 + +内联,在html里。 + +```scala + +``` + + + +## Js调用策略 + +调用顺序:HTML 元素是按其在页面中出现的次序调用的,如果用 JavaScript 来管理页面上的元素(更精确的说法是使用 [文档对象模型](https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model) DOM),若 JavaScript 加载于欲操作的 HTML 元素之前,则代码将出错。 + + + +JavaScript 调用于文档头处,解析 HTML 文档体之前。这样做是有隐患的,需要使用一些结构来避免错误发生。 + + + +“内部”示例使用了以下结构: + +```js +document.addEventListener("DOMContentLoaded", function() { + . . . +}); +``` + +这是一个事件监听器,它监听浏览器的 "`DOMContentLoaded`" 事件,即 HTML 文档体加载、解释完毕事件。事件触发时将调用 " `. . .`" 处的代码,从而避免了错误发生([事件](https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Events) 的概念稍后学习)。 + +“外部”示例中使用了 JavaScript 的一项现代技术(`async` “异步”属性)来解决这一问题,它告知浏览器在遇到 ` +``` + +上述情况下,脚本和 HTML 将一并加载,代码将顺利运行。 + +**备注:** “外部”示例中 `async` 属性可以解决调用顺序问题,因此无需使用 `DOMContentLoaded` 事件。而 `async` 只能用于外部脚本,因此不适用于“内部”示例。 + + + +另外用了async后 多个js顺序就保证不了了,需要用defer + +解决这一问题可使用 `defer` 属性,脚本将按照在页面中出现的顺序加载和运行: + +```js + + + + + +``` + + + +脚本调用策略小结: + +- 如果脚本无需等待页面解析,且无依赖独立运行,那么应使用 `async`。 +- 如果脚本需要等待页面解析,且依赖于其它脚本,调用这些脚本时应使用 `defer`,将关联的脚本按所需顺序置于 HTML 中。 + + + +## 注释 + +``` +// 我是一条注释 +``` + +``` +/* + 我也是 + 一条注释 +*/ +``` + +## JavaScript 输入输出 + +JavaScript 没有任何打印或者输出的函数。 + +document.write是直接写入到页面的内容流,如果在写之前没有调用document.open, 浏览器会自动调用open。每次写完关闭之后重新调用该函数,会导致页面被重写。 + + JavaScript 显示数据 + JavaScript 可以通过不同的方式来输出数据: + + 使用 window.alert() 弹出警告框。 + 使用 document.write() 方法将内容写到 HTML 文档中。 + 使用 innerHTML 写入到 HTML 元素。 + 使用 console.log() 写入到浏览器的控制台。 + +输入可以prompt + +```js +function updateName() { + let name = prompt('输入一个新的名字:'); + para.textContent = '玩家 1:' + name; +} +``` + +```scala +console.log('name:' + name + ',age:' + age); //传统写法 +console.log(`我是${name},age:${age}`); //ES6 写法。注意语法格式 +``` + + + +## 操作 HTML 元素 + +如需从 JavaScript 访问某个 HTML 元素,您可以使用 document.getElementById(id) 方法。 + +```javascript +//通过标签找html元素 +var x=document.getElementById("main");//id: main +var y=x.getElementsByTagName("p"); + +var element=document.getElementById("header"); +element.innerHTML="New Header"; + +document.getElementById(id).attribute=new value; + +document.getElementById("image").src="landscape.jpg"; + +document.getElementById("p2").style.color="blue"; + +``` + +## 变量 + +在 ES6 语法之前,统一使用`var`关键字来声明一个变量。比如: + +```javascript +var name; // 定义一个名为 name 的变量。name是变量名。 +``` + +在 ES6 语法及之后的版本里,可以使用 `const`、`let`关键字来定义一个变量 + +```js +const name; // 定义一个常量 + +let age; // 定义一个变量 +``` + + + +**变量初始化** + +一旦你定义了一个变量,你就能够初始化它。方法如下,在变量名之后跟上一个“=”,然后是数值: + +```scala +myName = 'Chris'; +myAge = 37; + +// 你可以像这样在声明变量的时候给变量初始化: + +let myName = 'Chris'; +``` + +变量不声明,直接赋值:(正常) ;只声明,不赋值:(注意,打印 undefined);不声明,不赋值,直接使用:(会报错) + + + +## 数据类型 + +### 数据类型 + +#### JS 中一共有八种数据类型 + +- **基本数据类型(值类型)**:String 字符串、Number 数值、BigInt 大型数值、Boolean 布尔值、Null 空值、Undefined 未定义、Symbol。 +- **引用数据类型(引用类型)**:Object 对象。 + +注意:内置对象 Function、Array、Date、RegExp、Error 等都是属于 Object 类型。也就是说,除了那七种基本数据类型之外,其他的,都称之为 Object 类型。 + + + +**数据类型之间最大的区别**: + +- 基本数据类型:参数赋值的时候,传数值。 +- 引用数据类型:参数赋值的时候,传地址。 + +```javascript +// 声明一个变量的语法是在 var 或 let 关键字之后加上这个变量的名字: + +let myName; +let myAge; + +//JavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型: + +//声明变量时可以确定其类型,如 +var carname=new String; +var x= new Number; +var y= new Boolean; +var cars= new Array; +var person= new Object; +``` + + + +### String + +字符串是由若干个字符组成的,这些字符的数量就是字符串的长度。我们可以通过字符串的 length 属性可以获取整个字符串的长度。 + +字符串型可以是引号中的任意文本,其语法为:双引号 `""` 或者单引号 `''`。 + +js中常用单引号,html中用双引号 + + + +有了 ES6 语法,字符串拼接可以这样写: + +```javascript +var name = 'qianguyihao'; +var age = '26'; + +console.log('我是' + name + ',age:' + age); //传统写法 +console.log(`我是${name},age:${age}`); //ES6 写法。注意语法格式 + + +// 模板字符串支持换行 +const html = `
      + ${result.name} + ${result.age} + ${result.sex} +
      `; + +// 模板字符串中可以调用函数。字符串中调用函数的位置,将会显示函数执行后的返回值。 +function getName() { + return 'qianguyihao'; +} + +console.log(`www.${getName()}.com`); // 打印结果:www.qianguyihao.com + + +var str = 'smyhvae'; +console.log(str.length); // 获取字符串的长度 +console.log(str[2]); // 获取字符串中的第3个字符(下标为2的字符) + +``` + +### Number + +在 JS 中,只要是数,就是 Number 数值型的。无论整浮、浮点数(即小数)、无论大小、无论正负,都是 Number 类型的。 + +#### 数值范围 + +由于内存的限制,ECMAScript 并不能保存世界上所有的数值。 + +- 最大值:`Number.MAX_VALUE`,这个值为: 1.7976931348623157e+308 +- 最小值:`Number.MIN_VALUE`,这个值为: 5e-324 + +如果使用 Number 表示的变量超过了最大值,则会返回 Infinity。 + +- 无穷大(正无穷):Infinity +- 无穷小(负无穷):-Infinity + +注意:`typeof Infinity`的返回结果是 number。 + +#### NaN + +**NaN**:是一个特殊的数字,表示 Not a Number,非数值。在进行数值运算时,如果得不到正常结果,就会返回 NaN。 + +比如: + +```javascript +console.log('abc' / 18); //结果是NaN +``` + +**Undefined 和任何数值计算的结果为 NaN。NaN 与任何值都不相等,包括 NaN 本身。** + + + +### 数组 + +开头为0 + +- 获取字符串或者数组的长度,用arr.length属性 +- 数组添加头部元素: arr.unshift("a","b"....); 结尾用push()方法 +- 将数组元素连接成字符串: arr.join("连接符") +- 当数组的存储空间不够时,数组会自动扩容。其它编程语言中数组的大小是固定的,不会自动扩容。 +- 如果访问数组中不存在的索引时,不会报错,会返回undefined。 +- 数组可以存储不同类型数据,其它编程语言中数组只能存储相同类型数据。 +- 数组分配的存储空间不一定是连续的。其它语言数组分配的存储空间是连续的。 + +```javascript +let arr1 = []; // 创建一个空的数组 + +let arr2 = [1, 2, 3]; // 创建带初始值的数组 + +var cars=new Array(); +cars[0]="Audi"; +cars[1]="BMW"; +cars[2]="Volvo"; +// 或者 +var cars=new Array("Audi","BMW","Volvo"); +// 或者 +var cars=["Audi","BMW","Volvo"]; + +let sequence = [1, 1, 2, 3, 5, 8, 13]; +for (let i = 0; i < sequence.length; i++) { + console.log(sequence[i]); +} +sequence.length; +myArray.push('Cardiff'); +let removedItem = myArray.pop(); +``` + + + +数组解构赋值,代码举例: + +```js +let [a, b, c] = [1, 2, [3, 4]]; +``` + +判断是否为数组 + +```javascript +布尔值 = Array.isArray(被检测的数组); +``` + + + +```scala +const name = 'qianguyihao'; +console.log(Array.from(name)); // 打印结果是数组:["q","i","a","n","g","u","y","i","h","a","o"] +``` + + + +```scala +// ES5语法 +arr.forEach(function (currentItem, currentIndex, currentArray) { + console.log(currentValue); +}); + +// ES6语法 +arr.forEach((currentItem, currentIndex, currentArray) => { + console.log(currentValue); +}); + +参数1:当前正在遍历的元素 + +参数2:当前正在遍历的元素的索引 + +参数3:正在遍历的数组 + +注意,forEach() 没有返回值。也可以理解成:forEach() 的返回值是 undefined。 +forEach() 通过参数 2、参数 3 修改原数组:(标准做法。 如果你想在遍历数组的同时,去改变数组里的元素内容,那么,最好是用 map() 方法来做,不要用 forEach()方法,避免出现一些低级错误。 + +// ES6语法 +const newArr = arr.map((currentItem, currentIndex, currentArray) => { + return newItem; +}); +``` + + + +### 对象 + +见 章节 面向对象 + +### Undefined 和 Null + +Undefined 这个值表示变量不含有值。 + +- case1:变量已声明,未赋值时 + +- case2:变量未声明(未定义)时, 如果用 `typeof` 检查这个变量时,会返回 `undefined` + +- case3:函数无返回值时, 如果一个函数没有返回值,那么,这个函数的返回值就是 undefined。 + + 或者,也可以这样理解:在定义一个函数时,如果末尾没有 return 语句,那么,其实就是 `return undefined`。 + +- case4:调用函数时,未传参。调用函数时,如果没有传参,那么,这个参数的值就是 undefined。 + + + +可以通过将变量的值设置为 null 来清空变量。**null 虽然是一个单独的数据类型,但null 相当于是一个 object,只不过地址为空(空指针)而已**。 + + + +undefined 实际上是由 null 衍生出来的,所以`null == undefined`的结果为 true。 + +- 任何值和 null 运算,null 可看做 0 运算。 +- 任何数据类型和 undefined 运算都是 NaN。 + + + +### 动态类型 + +JavaScript 是一种“动态类型语言”,这意味着不同于其他一些语言 (译者注:如 C、JAVA),您不需要指定变量将包含什么数据类型(例如 number 或 string) + +例如,如果你声明一个变量并给它一个带引号的值,浏览器就会知道它是一个字符串: + +``` +let myString = 'Hello'; +``` + +### 基本包装类型 + +我们都知道,js 中的数据类型包括以下几种。 + +- 基本数据类型:String、Number、Boolean、Null、Undefined +- 引用数据类型:Object + +JS 为我们提供了三个**基本包装类**: + +- String():将基本数据类型字符串,转换为 String 对象。 +- Number():将基本数据类型的数字,转换为 Number 对象。 +- Boolean():将基本数据类型的布尔值,转换为 Boolean 对象。 + +通过上面这这三个包装类,我们可以**将基本数据类型的数据转换为对象**。 + + + +```javascript +let str1 = 'qianguyihao'; +let str2 = new String('qianguyihao'); + +let num = new Number(3); + +let bool = new Boolean(true); + +console.log(typeof str1); // 打印结果:string +console.log(typeof str2); // 注意,打印结果:object +``` + +**需要注意的是**:我们在实际应用中一般不会使用基本数据类型的**对象**。如果使用基本数据类型的对象,在做一些比较时可能会带来一些**不可预期**的结果。 + + + +当我们对一些基本数据类型的值去调用属性和方法时,JS引擎会**临时使用包装类将基本数据类型转换为引用数据类型**(即“隐式类型转换”),这样的话,基本数据类型就有了属性和方法,然后再调用对象的属性和方法;调用完以后,再将其转换为基本数据类型。 + +比如str.length + +## 运算符 + +### typeof 操作符 + +你可以使用 typeof 操作符来查看 JavaScript 变量的数据类型。 +请注意: + + NaN 的数据类型是 number + 数组(Array)的数据类型是 object + 日期(Date)的数据类型为 object + null 的数据类型是 object + 未定义变量的数据类型为 undefined + +实例 + +```javascript +typeof "John" // 返回 string +typeof 3.14 // 返回 number +typeof NaN // 返回 number +typeof false // 返回 boolean +typeof [1,2,3,4] // 返回 object +typeof {name:'John', age:34} // 返回 object +typeof new Date() // 返回 object +typeof function () {} // 返回 function +typeof myCar // 返回 undefined (如果 myCar 没有声明) +typeof null // 返回 object +``` + +### constructor 属性 + +constructor 属性返回所有 JavaScript 变量的构造函数。 + +实例 + +```javascript +"John".constructor // 返回函数 String() { [native code] } +(3.14).constructor // 返回函数 Number() { [native code] } +false.constructor // 返回函数 Boolean() { [native code] } +[1,2,3,4].constructor // 返回函数 Array() { [native code] } +{name:'John', age:34}.constructor // 返回函数 Object() { [native code] } +new Date().constructor // 返回函数 Date() { [native code] } +function () {}.constructor // 返回函数 Function(){ [native code] } + +function isArray(myArray) { + return myArray.constructor.toString().indexOf("Array") > -1; +} + +function isDate(myDate) { + return myDate.constructor.toString().indexOf("Date") > -1; +} +``` + +### 比较 + +| 运算符 | 名称 | 作用 | 示例 | +| :----- | :--------- | :----------------------- | :------------ | +| `===` | 严格等于 | 测试左右值是否相同 | `5 === 2 + 4` | +| `!==` | 严格不等于 | 测试左右值是否**不**相同 | `5 !== 2 + 3` | + +```text +== 等于 +=== 全等于 +``` + + + +`==`这个符号并不严谨,会做隐式转换,将不同的数据类型,**转为相同类型**进行比较。例如: + +```javascript +console.log('6' == 6); // 打印结果:true。这里的字符串"6"会先转换为数字6,然后再进行比较 +console.log(true == '1'); // 打印结果:true +console.log(0 == -0); // 打印结果:true + +console.log(null == 0); // 打印结果:false +``` + +```javascript +console.log(undefined == null); //打印结果:true。 +``` + + + +**全等在比较时,不会做类型转换**。如果要保证**完全等于**(即:不仅要判断取值相等,还要判断数据类型相同),我们就要用三个等号`===`。例如: + +```javascript +console.log('6' === 6); //false +console.log(6 === 6); //true +``` + +### 逻辑运算符 + +- `&&` — 逻辑与; 使得并列两个或者更多的表达式成为可能,只有当这些表达式每一个都返回`true`时,整个表达式才会返回`true.` +- `||` — 逻辑或; 当两个或者更多表达式当中的任何一个返回 `true` 则整个表达式将会返回 `true`. +- ! — 逻辑非; 对一个布尔值取反,非 true 返回 false,非 false 返回 true. + +## 类型转换 + +### 显式类型转换 + +- toString() +- String() +- Number() +- parseInt(string) +- parseFloat(string) +- Boolean() + +### 隐式类型转换 + +- isNaN () +- 自增/自减运算符:`++`、`—-` +- 正号/负号:`+a`、`-a` +- 加号:`+` +- 运算符:`-`、`*`、`/` + + + +### 将数字转换为字符串 + +```javascript +全局方法 String() 可以将数字转换为字符串。 + +String(x) // 将变量 x 转换为字符串并返回 +String(123) // 将数字 123 转换为字符串并返回 +String(100 + 23) // 将数字表达式转换为字符串并返回 + +Number 方法 toString() 也是有同样的效果。 + +实例 +x.toString() +(123).toString() +(100 + 23).toString() + +``` + +### 将布尔值转换为字符串 + +```javascript +全局方法 String() 可以将布尔值转换为字符串。 + +String(false) // 返回 "false" +String(true) // 返回 "true" +Boolean 方法 toString() 也有相同的效果。 + +false.toString() // 返回 "false" +true.toString() // 返回 "true" +``` + +### 将日期转换为字符串 + +```javascript +Date() 返回字符串。 + +Date() // 返回 Thu Jul 17 2014 15:38:19 GMT+0200 (W. Europe Daylight Time) +全局方法 String() 可以将日期对象转换为字符串。 + +String(new Date()) // 返回 Thu Jul 17 2014 15:38:19 GMT+0200 (W. Europe Daylight Time) +Date 方法 toString() 也有相同的效果。 + +实例 +obj = new Date() +obj.toString() // 返回 Thu Jul 17 2014 15:38:19 GMT+0200 (W. Europe Daylight Time) +``` + +### 将字符串转换为数字 + +```javascript +全局方法 Number() 可以将字符串转换为数字。 + +字符串包含数字(如 "3.14") 转换为数字 (如 3.14). + +空字符串转换为 0。 + +其他的字符串会转换为 NaN (不是个数字)。 + +Number("3.14") // 返回 3.14 +Number(" ") // 返回 0 +Number("") // 返回 0 +Number("99 88") // 返回 NaN + +一元运算符 + +Operator + 可用于将变量转换为数字: +``` + +### 将布尔值转换为数字 + +```javascript +全局方法 Number() 可将布尔值转换为数字。 + +Number(false) // 返回 0 +Number(true) // 返回 1 +``` + +### 将日期转换为数字 + +```javascript +全局方法 Number() 可将日期转换为数字。 + +d = new Date(); +Number(d) // 返回 1404568027739 +日期方法 getTime() 也有相同的效果。 + +d = new Date(); +d.getTime() // 返回 1404568027739 +``` + + + +### 布尔值情况列举【重要】 + +其他的数据类型都可以转换为 Boolean 类型。无论是隐式转换,还是显示转换,转换结果都是一样的。有下面几种情况: + +(1)情况一:数字 --> 布尔。 0 和 NaN的转换结果 false,其余的都是 true。比如 `Boolean(NaN)`的结果是 false。 + +(2)情况二:字符串 ---> 布尔。空串的转换结果是false,其余的都是 true。全是空格的字符串,转换结果也是 true。字符串`'0'`的转换结果也是 true。 + +(3)情况三:null 和 undefined 都会转换为 false。 + +(4)情况四:引用数据类型会转换为 true。注意,空数组`[]`和空对象`{}`,**转换结果也是 true**,这一点,很多人都不知道。 + + + + + + + +## 面向对象 + +### 对象 + +对象由花括号分隔。在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号分隔 + +### 对象创建 + +```javascript +// 方式1:字面量 对象的字面量就是一个{}。里面的属性和方法均是键值对. key可以也可以没有引号 +var person={ + firstname : "Bill", + lastname : "Gates", + id : 5566 +}; + +// 方式2:工厂模式 new Object()。弊端: 使用工厂方法创建的对象,使用的构造函数都是 Object。所以创建的对象都是 Object 这个类型,就导致我们无法区分出多种不同类型的对象。 + +person=new Object(); +person.firstname="Bill"; +person.lastname="Gates"; +person.age=56; +person.eyecolor="blue"; +//或者 +person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"}; +//或者对象构造器 构造函数 推荐 +function person(firstname,lastname,age,eyecolor) +{ + this.firstname=firstname; + this.lastname=lastname; + this.age=age; + this.eyecolor=eyecolor; +} +var myFather=new person("Bill","Gates",56,"blue"); +``` + +**构造函数**:是一种特殊的函数,主要用来创建和初始化对象,也就是为对象的成员变量赋初始值。它与 `new` 一起使用才有意义。 + +- 构造函数的创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。 +- 构造函数和普通函数的区别就是**调用方式**的不同:普通函数是直接调用,而**构造函数需要使用 new 关键字来调用。** + +**this 的指向也有所不同**: + +- 1.以函数的形式调用时,this 永远都是 window。比如`fun();`相当于`window.fun();` +- 2.以方法的形式调用时,this 是调用方法的那个对象 +- 3.以构造函数的形式调用时,this 是新创建的实例对象 + + + +### 访问对象属性 + +对象属性有两种寻址方式: + +```javascript + name=person.lastname; + name=person["lastname"]; +``` + +### 对象方法 + +```javascript +var person = { + firstName: "John", + lastName : "Doe", + id : 5566, + fullName : function() + { + return this.firstName + " " + this.lastName; + } +}; +document.getElementById("demo").innerHTML = person.fullName(); +``` + +### 使用对象方法 + +对象方法通过添加 () 调用 (作为一个函数)。 + +```javascript +name = person.fullName(); +``` + +### instanceof + +使用 instanceof 可以检查**一个对象是否为一个类的实例**。 + +**语法如下**: + +```javascript +对象 instanceof 构造函数; +``` + +### 浅拷贝 + +ES6 给我们提供了新的语法糖,通过 `Object.assgin()` 可以实现**浅拷贝**。 + +`Object.assgin()` 在日常开发中,使用得相当频繁,非掌握不可。 + +**语法**: + +```js +// 语法1 +obj2 = Object.assgin(obj2, obj1); + +// 语法2 +Object.assign(目标对象, 源对象1, 源对象2...); +``` + +**解释**:将`obj1` 拷贝给 `obj2`。执行完毕后,obj2 的值会被更新。 + +**作用**:将 obj1 的值追加到 obj2 中。如果对象里的属性名相同,会被覆盖。 + +从语法2中可以看出,Object.assign() 可以将多个“源对象”拷贝到“目标对象”中。 + + + +深拷贝其实就是将浅拷贝进行递归。 + +### 原型 + +原型就是父类 继承的父类。 + +## 函数 + +### 定义 + +```javascript +// 传统定义函数方式 +function myFunction(a,b) +{ + if (a>b) + { + return; + } + x=a+b +} + +function Test () { + // +} + +const Test = function () { + // +} + +// 使用箭头函数定义函数时可以省略 function 关键字 +const Test = (...params) => { + // +} + +// 该函数只有一个参数时可以简写成: +const Test = param => { + return param; +} + +console.log(Test('hello')); // hello + +// 很少用, +const 变量名/函数名 = new Function('形参1', '形参2', '函数体'); +const fun3 = new Function('a', 'b', 'console.log("我是函数内部的内容"); console.log(a + b);'); +``` + +### 实际参数和形式参数的个数,可以不同 + +实际参数和形式参数的个数,可以不同。调用函数时,解析器不会检查实参的数量。 + +- 如果实参个数 > 形参个数,则末尾的实参是多余的,不会被赋值,因为没有形参能接收它。 +- 如果实参个数 < 形参个数,则末尾的形参是多余的,值是 undefined,因为它没有接收到实参。(undefined参与运算时,表达式的运算结果为NaN) + +函数的实参可以是任意的数据类型。调用函数时,解析器不会检查实参类型,所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型检查。 + +函数体内可以没有返回值,也可以根据需要加返回值。语法格式:`return 函数的返回值`。 + + + +### 类数组对象 arguments + +在调用函数时,浏览器每次都会传递进两个隐含的参数: + +- 1.函数的上下文对象 this +- 2.**封装实参的对象** arguments + +```javascript +function foo() { + console.log(arguments); + console.log(typeof arguments); +} + +foo('a', 'b'); +``` + +函数内的 arguments 是一个**类数组对象**,里面存储的是它接收到的**实参列表**。所有函数都内置了一个 arguments 对象,有个讲究的地方是:只有函数才有arguments。 + +具体来说,在调用函数时,我们所传递的实参都会在 arguments 中保存。**arguments 代表的是所有实参**。 + +arguments 的展示形式是一个**伪数组**。意思是,它和数组有点像,但它并不是数组。它具有以下特点: + +- 可以进行遍历;具有数组的 length 属性,可以获取长度。 +- 可以通过索引(从0开始计数)存储数据、获取和操作数据。比如,我们可以通过索引访问某个实参。 +- 不能调用数组的方法。比如push()、pop() 等方法都没有。 +- 即使我们不定义形参,也可以通过 arguments 来获取实参:arguments[0] 表示第一个实参、arguments[1] 表示第二个实参,以此类推。 +- 当我们不确定有多少个参数传递的时候,可以用 **arguments** 来获取。 + +### 立即执行函数 + +```scala +(function() { + // 函数体 +})(a, b); +``` + +即执行函数往往只会执行一次。为什么呢?因为没有变量保存它,执行完了之后,就找不到它了。 + + + + +### 闭包(closure) + +**闭包**:如果**外部作用域**有权访问另外一个**函数内部**的**局部变量**时,那就产生了闭包。这个内部函数称之为闭包函数。注意,这里强调的是访问**局部变量**。 + +闭包代码举例: + +```js +function fun1() { + const a = 10; + return function fun2() { + console.log(a); + }; +} +fun1(); +// 调用外部函数,就能得到内部函数,并用 变量 result 接收 +const result = fun1(); +// 在 fun1函数的外部,执行了内部函数 fun2,并访问到了 fun2的内部变量a +result(); // 10 +``` + + + +## This指向 + +### This 指向详解 + +> - [this指向](https://juejin.cn/post/6981251280236707853) + +解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是 this,this 指向的是一个对象,这个对象我们称为函数执行的 上下文对象。 + + + +在ES5语法中,根据函数的调用方式的不同,this 会指向不同的对象: + + + +1. 方法调用模式下,this 总是指向调用它所在方法的对象,this 的指向与所在方法的调用位置有关,而与方法的声明位置无关(箭头函数特殊); +2. 函数调用下,this 指向 window ,调用方法没有明确对象的时候,this 指向 window,如 setTimeout、匿名函数等; +3. 构造函数调用模式下,this 指向被构造的对象; +4. apply,call,bind 调用模式下,this 指向第一个参数; +5. 箭头函数,在声明的时候绑定this,而非取决于调用位置;**技巧:它的外层没有函数,this 是 window;外层有函数,看外层函数的 this 是谁,它的 this 就是谁。** +6. 严格模式下,如果 this 没有被执行环境(execution context)定义,那 this是 为undefined; + + + + + +```scala +//以函数形式调用,this是window +fun(); //可以理解成 window.fun() + +function fun() { + console.log(this); + console.log(this.name); +} + +打印结果: + Window + 全局的name属性 + + + +//以方法的形式调用,this是调用方法的对象 +obj2.sayName(); + +``` + + + +### call、apply、bind + +call 和 apply 的作用,完全一样,唯一的区别:参数; call 接收的参数不固定,第一个参数是函数体内 this 的指向,第二个参数以下是依次传入的参数。 apply接收两个参数,第一个参数也是函数体内 this 的指向。第二个参数是一个集合对象(数组或者类数组) + +同时call和apply会传实参,因为会直接调用一次。而bind是返回替换this后的函数,不会执行一次。 + + + +bind() 方法**不会调用函数**,但是可以改变函数内部的 this 指向。 + +把call()、apply()、bind()这三个方法做一下对比,你会发现:实际开发中, bind() 方法使用得最为频繁。如果有些函数,我们不需要立即调用,但是又想改变这个函数内部的this指向,此时用 bind() 是最为合适的。 + +语法: + +```js +新函数 = fn1.bind(想要将this指向哪里, 函数实参1, 函数实参2); +``` + + + +参数: + +- 第一个参数:在 fn1 函数运行时,指定 fn1 函数的this 指向。如果不需要改变 this 指向,则传 null。 +- 其他参数:fn1 函数的实参。 + +解释:它不会调用 fn1 函数,但会返回 由指定this 和指定实参的**原函数拷贝**。可以看出, bind() 方法是有返回值的。 + + + +## if和循环 + +### if else + +```javascript +if (time<10) +{ + x="Good morning"; +} +else if (time<20) +{ + x="Good day"; +} +else +{ + x="Good evening"; +} +``` + +### swith语法 + +```javascript +var day=new Date().getDay(); +switch (day) +{ + case 6: + x="Today it's Saturday"; + break; + case 0: + x="Today it's Sunday"; + break; + default: + x="Looking forward to the Weekend"; +} +``` + +### for循环 + +```javascript +for (var i=0;i"); +} + +for (var i=0,len=cars.length; i"); +} +//循环遍历对象的属性 +var person={fname:"John",lname:"Doe",age:25}; +for (x in person) +{ + txt=txt + person[x]; +} +forin不推荐用在数组上。数组应该用forof +for(let value of arr) { + console.log(value); +} +``` + +### while循环 + +```javascript +while (i<5) +{ + x=x + "The number is " + i + "
      "; + i++; +} + +do +{ + x=x + "The number is " + i + "
      "; + i++; +} +while (i<5); +//break; continue; +``` + +## 作用域 + +> [参考](https://web.qianguyihao.com/04-JavaScript%E5%9F%BA%E7%A1%80/23-%E4%BD%9C%E7%94%A8%E5%9F%9F%E3%80%81%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87%E3%80%81%E5%87%BD%E6%95%B0%E6%8F%90%E5%8D%87.html#%E4%BD%9C%E7%94%A8%E5%9F%9F%EF%BC%88scope%EF%BC%89%E7%9A%84%E6%A6%82%E5%BF%B5%E5%92%8C%E5%88%86%E7%B1%BB) + +直接编写在 script 标签中的 JS 代码,都在全局作用域。全局作用域在页面打开时创建,在页面关闭时销毁。 + +在全局作用域中有一个全局对象 window,它代表的是浏览器的窗口,由浏览器创建,我们可以直接使用。相关知识点如下: + +- 创建的**变量**都会作为 window 对象的属性保存。比如在全局作用域内写 `const a = 100`,这里的 `a` 等价于 `window.a`。 +- 创建的**函数**都会作为 window 对象的方法保存。 +- 无论是在函数外还是函数内,变量如果未经声明就赋值(意思是,如果不加var/let/const),这个变量是**全局变量**。 + +JS在解析代码之前,有一个“**预处理**(预解析)”阶段,将当前 JS 代码中所有变量的定义和函数的定义,放到所有代码的最前面。 + +- 使用 var 关键字声明的变量( 比如 `var a = 1`),**会在所有的代码执行之前被声明**(但是不会赋值)。但是如果声明变量时不是用 var 关键字(比如直接写`a = 1`),则变量不会被声明提前。 +- 使用`函数声明`的形式创建的函数`function foo(){}`,**会被声明提前**。 +- 在JS的规则中,函数提升优先于变量提升。 + + + +在函数作用域中,也有声明提前的现象: + +- 函数中,使用 var 关键字声明的变量,会在函数中所有代码执行之前被提前声明。 +- 函数中,没有 var 声明的变量都是**全局变量**,且并不会被提前声明。 + + + +在 ES5 中没有块级作用域 + +## try catch + +```javascript +try +{ + throw exception; + adddlert("Welcome guest!"); +} +catch(err) +{ + txt="There was an error on this page.\n\n"; + txt+="Error description: " + err.message + "\n\n"; + txt+="Click OK to continue.\n\n"; + alert(txt); +} +``` + +## 事件 + +```javascript +//DOM事件 +//

      请点击该文本

      this就是自己的id +//

      请点击该文本

      +document.getElementById("myBtn").onclick=function(){displayDate()}; +// +//分配事件 +document.getElementById("myBtn").onclick=function(){displayDate()}; + +//创建元素 +var para=document.createElement("p"); +var node=document.createTextNode("这是新段落。"); +para.appendChild(node); +var element=document.getElementById("div1"); +element.appendChild(para); +//删除元素 +var parent=document.getElementById("div1"); +var child=document.getElementById("p1"); +parent.removeChild(child); +//正则表达式 RegExp +``` + + + +## 其他 小结 + +- 字符串转换为数字用Number(str)或者parseInt(str)/parseFloat(str)方法 +- 数字转换为字符串用var.toString()方法 +- NaN: not a number +- 可以直接使用Math.方法名,如max(...), +- ByName()只用于表单元素,一般是单选和复选框 +- 两个特殊方法,document.title, document.body +- html中onclick="f()", js中obj.click=f,前者是调用属性,后者是给属性赋值 +- 只执行最后一次window.onload=function(){ } +- 事件绑定: obj.addEventListener("click",funcion,false); + + + +# jquery教程 + +## 语法 +```javacript + $(document).ready(function(){ + + // 开始写 jQuery 代码... + + }); + + 简洁写法(与以上写法效果相同): + $(function(){ + + // 开始写 jQuery 代码... + + }); + +#id 选择器 +$("#test") +.class 选择器 +$(".test") +$("p").css("background-color","red"); +$(this) 选取当前 HTML 元素 +``` + +## 事件 +```javascript +$("p").click(function(){ + // action goes here!! +}); +$("p").click(); +$("p").dblclick(function(){ + $(this).hide(); +}); + +jQuery hide() 和 show() +通过 jQuery,您可以使用 toggle() 方法来切换 hide() 和 show() 方法。 + +$(selector).toggle(speed,callback); +可选的 speed 参数规定隐藏/显示的速度,可以取以下值:"slow"、"fast" 或毫秒。 +可选的 callback 参数是 toggle() 方法完成后所执行的函数名称。 +可选的 callback 参数,具有以下三点说明: +$(selector)选中的元素的个数为n个,则callback函数会执行n次 +callback函数名后加括号,会立刻执行函数体,而不是等到显示/隐藏完成后才执行 +callback既可以是函数名,也可以是匿名函数 + +Callback 函数在当前动画 100% 完成之后执行。 + +通过 jQuery,可以把动作/方法链接在一起。 +Chaining 允许我们在一条语句中运行多个 jQuery 方法(在相同的元素上)。 +$("#p1").css("color","red").slideUp(2000).slideDown(2000); +$("#p1").css("color","red") + .slideUp(2000) + .slideDown(2000); + +三个简单实用的用于 DOM 操作的 jQuery 方法: +text() - 设置或返回所选元素的文本内容 +html() - 设置或返回所选元素的内容(包括 HTML 标记) +val() - 设置或返回表单字段的值 + +$("#btn1").click(function(){ + alert("Text: " + $("#test").text()); +}); +$("#btn2").click(function(){ + alert("HTML: " + $("#test").html()); +}); +$("#btn1").click(function(){ + alert("Value: " + $("#test").val()); +}); + +下面的例子演示如何通过 jQuery val() 方法获得输入字段的值: + + + + +

      名称:

      + + + + +$("button").click(function(){ + alert($("#w3s").attr("href")); +}); + +下面的例子演示如何通过 text()、html() 以及 val() 方法来设置内容: +$("#btn1").click(function(){ + $("#test1").text("Hello world!"); +}); +$("#btn2").click(function(){ + $("#test2").html("Hello world!"); +}); +$("#btn3").click(function(){ + $("#test3").val("Dolly Duck"); +}); +text()、html() 以及 val() 的回调函数 + +上面的三个 jQuery 方法:text()、html() 以及 val(),同样拥有回调函数。 +回调函数由两个参数:被选元素列表中当前元素的下标,以及原始(旧的)值。 +然后以函数新值返回您希望使用的字符串。 +$("#btn1").click(function(){ + $("#test1").text(function(i,origText){ + return "Old text: " + origText + " New text: Hello world! + (index: " + i + ")"; + }); +}); + +$("button").click(function(){ + $("#w3s").attr("href","//www.w3cschool.cn/jquery"); +}); + +append() - 在被选元素内部的结尾插入指定内容 +prepend() - 在被选元素内部的开头插入指定内容 +after() - 在被选元素之后插入内容 +before() - 在被选元素之前插入内容 + +$("p").append("Some appended text."); + +$("#div1").remove(); + +$("#div1").empty(); + +addClass() - 向被选元素添加一个或多个类 +removeClass() - 从被选元素删除一个或多个类 +toggleClass() - 对被选元素进行添加/删除类的切换操作 +css() - 设置或返回样式属性 + +$("button").click(function(){ + $("h1,h2,p").addClass("blue"); + $("div").addClass("important"); +}); + +您也可以在 addClass() 方法中规定多个类: +$("button").click(function(){ + $("#div1").addClass("important blue"); +}); + +下面的例子将返回首个匹配元素的 background-color 值: +$("p").css("background-color"); + +$("p").css("background-color","yellow"); + +$("p").css({"background-color":"yellow","font-size":"200%"}); + + + +旧版本 +$("").hide() +//必须 +$(document).ready(function(){ + +--- jQuery functions go here ---- + +}); + +jQuery 语法实例 +$(this).hide() +演示 jQuery hide() 函数,隐藏当前的 HTML 元素。 +$("#test").hide() +演示 jQuery hide() 函数,隐藏 id="test" 的元素。 +$("p").hide() +演示 jQuery hide() 函数,隐藏所有

      元素。 +$(".test").hide() +演示 jQuery hide() 函数,隐藏所有 class="test" 的元素。 + +jQuery 元素选择器 +jQuery 使用 CSS 选择器来选取 HTML 元素。 +$("p") 选取

      元素。 +$("p.intro") 选取所有 class="intro" 的

      元素。 +$("p#demo") 选取所有 id="demo" 的

      元素。 +jQuery 属性选择器 +jQuery 使用 XPath 表达式来选择带有给定属性的元素。 +$("[href]") 选取所有带有 href 属性的元素。 +$("[href='#']") 选取所有带有 href 值等于 "#" 的元素。 +$("[href!='#']") 选取所有带有 href 值不等于 "#" 的元素。 +$("[href$='.jpg']") 选取所有 href 值以 ".jpg" 结尾的元素。 +jQuery CSS 选择器 +jQuery CSS 选择器可用于改变 HTML 元素的 CSS 属性。 +下面的例子把所有 p 元素的背景颜色更改为红色: +$("p").css("background-color","red"); + +$(document).ready(function) 将函数绑定到文档的就绪事件(当文档完成加载时) +$(selector).click(function) 触发或将函数绑定到被选元素的点击事件 +$(selector).dblclick(function) 触发或将函数绑定到被选元素的双击事件 +$(selector).focus(function) 触发或将函数绑定到被选元素的获得焦点事件 +$(selector).mouseover(function) 触发或将函数绑定到被选元素的鼠标悬停事件 + +$("#btn1").click(function(){ + $("#test1").text("Hello world!"); +}); +$("#btn2").click(function(){ + $("#test2").html("Hello world!"); +}); +$("#btn3").click(function(){ + $("#test3").val("Dolly Duck"); +}); +//回调函数 +$("#btn1").click(function(){ + $("#test1").text(function(i,origText){ + return "Old text: " + origText + " New text: Hello world! + (index: " + i + ")"; + }); +}); + +$("button").click(function(){ + $("#w3s").attr("href","http://www.w3school.com.cn/jquery"); +}); +//同时设置多个属性 +$("button").click(function(){ + $("#w3s").attr({ + "href" : "http://www.w3school.com.cn/jquery", + "title" : "W3School jQuery Tutorial" + }); +}); + +$("p").append("Some appended text."); +$("p").prepend("Some prepended text."); + +function appendText() +{ +var txt1="

      Text.

      "; // 以 HTML 创建新元素 +var txt2=$("

      ").text("Text."); // 以 jQuery 创建新元素 +var txt3=document.createElement("p"); // 以 DOM 创建新元素 +txt3.innerHTML="Text."; +$("p").append(txt1,txt2,txt3); // 追加新元素 +} + +$("img").after("Some text after"); +$("img").before("Some text before"); + +$("#div1").remove(); +$("#div1").empty(); +$("p").remove(".italic"); + +$("button").click(function(){ + $("h1,h2,p").addClass("blue"); + $("div").addClass("important"); +}); + +$("button").click(function(){ + $("h1,h2,p").removeClass("blue"); +}); + +$("p").css("background-color","yellow"); +$("p").css({"background-color":"yellow","font-size":"200%"}); +``` + +# Jquery淘汰 + +[参考](https://www.xiejiahe.com/blog/detail/59b35ad615c192bd11b90469) + + + +# ajax教程 + +## ajax请求数据 +### get +```javascript + var xmlhttp=new XMLHttpRequest(); + xmlhttp.open("GET","/test/GetSearchTips?sear="+thisnode.value,true); + xmlhttp.send(); +``` + +### post +```javascript + xmlhttp.open("POST","/myservlet",true); + xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); + xmlhttp.send("name=mafulong&age=14"); +``` + +## 后台处理数据 +```java + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { +// super.doGet(req, resp); +// resp.setContentType("text/html"); + String name=req.getParameter("name"); + System.out.println(name); + resp.setContentType("application/json; charset=UTF-8"); + PrintWriter out=resp.getWriter(); +// out.print("fjdkfjdk"); +// out.println("

      abc

      "); + JSONObject jsonObject=new JSONObject(); + JSONArray jsonArray=new JSONArray(); + jsonArray.put(jsonObject); + jsonArray.put(jsonObject); + try{ + jsonObject.put("name","mafulong"); + jsonObject.put("age",18); + }catch (Exception e){ + e.printStackTrace(); + } +// out.print(jsonObject.toString()); + out.print(jsonArray.toString()); + + } +``` + +## 前端处理后端接收得数据 +```javascript + xmlhttp.onreadystatechange=function() + { + if (xmlhttp.readyState==4 && xmlhttp.status==200) + { + // document.getElementById("myDiv").innerHTML=xmlhttp.responseText; + alert("success "); + var data=xmlhttp.responseText; + var djson=JSON.parse(data); + var str=""; + for(var i=0;i"; + str+=djson[i].age+"
      "; + } + document.getElementById("myDiv").innerHTML=str; + } + } +``` + +# 千古 笔记 + +> [参考](https://web.qianguyihao.com/04-JavaScript%E5%9F%BA%E7%A1%80/03-%E5%B8%B8%E9%87%8F%E5%92%8C%E5%8F%98%E9%87%8F.html#%E5%8F%98%E9%87%8F%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96%E3%80%90%E9%87%8D%E8%A6%81%E3%80%91) + +变量不声明,直接赋值:(正常) ;只声明,不赋值:(注意,打印 undefined);不声明,不赋值,直接使用:(会报错) + + + +## 事件 + +### 事件 绑定 + +- [事件](https://web.qianguyihao.com/04-JavaScript%E5%9F%BA%E7%A1%80/35-%E4%BA%8B%E4%BB%B6%E7%AE%80%E4%BB%8B.html#%E4%BA%8B%E4%BB%B6%E7%AE%80%E4%BB%8B) + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202212150003045.png) + + + +```scala + //这种事件绑定的方式,如果绑定多个,则后面的会覆盖掉前面的 + btn.onclick = function () { + console.log("事件1"); + } + // 方式2 + element.addEventListener('click', function () { + + }, false); + 参数解释: + + 参数1:事件名的字符串(注意,没有on) + + 参数2:回调函数:当事件触发时,该函数会被执行 + + 参数3:true表示捕获阶段触发,false表示冒泡阶段触发(默认)。如果不写,则默认为false。【重要】 +``` + +也可以传入event参数。 + +```html +small.onmousemove = function (event) {} +``` + +### 事件的传播和事件冒泡 + +- [事件的传播和事件冒泡](https://web.qianguyihao.com/04-JavaScript%E5%9F%BA%E7%A1%80/42-%E4%BA%8B%E4%BB%B6%E7%9A%84%E4%BC%A0%E6%92%AD%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1.html#dom%E4%BA%8B%E4%BB%B6%E6%B5%81) + +事件传播的三个阶段是:事件捕获、事件冒泡和目标。 + +- 事件捕获阶段:事件从祖先元素往子元素查找(DOM树结构),直到捕获到事件目标 target。在这个过程中,默认情况下,事件相应的监听函数是不会被触发的。 +- 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。 +- 事件冒泡阶段:事件从事件目标 target 开始,从子元素往冒泡祖先元素冒泡,直到页面的最上一级标签。 + + + +捕获阶段,事件依次传递的顺序是:window --> document --> html--> body --> 父元素、子元素、目标元素。 + + + +**事件冒泡**: 当一个元素上的事件被触发的时候(比如说鼠标点击了一个按钮),同样的事件将会在那个元素的所有**祖先元素**中被触发。这一过程被称为事件冒泡;这个事件从原始元素开始一直冒泡到DOM树的最上层。 + +通俗来讲,冒泡指的是:**子元素的事件被触发时,父元素的同样的事件也会被触发**。取消冒泡就是取消这种机制。 + + + +以下事件不冒泡:blur、focus、load、unload、onmouseenter、onmouseleave。意思是,事件不会往父元素那里传递。 + +大部分情况下,冒泡都是有益的。当然,如果你想阻止冒泡,也是可以的。可以按下面的方法阻止冒泡。 + +```javascript + event.stopPropagation(); +``` + + + +可以用这个冒泡做一些[事件委托](https://web.qianguyihao.com/04-JavaScript%E5%9F%BA%E7%A1%80/43-%E4%BA%8B%E4%BB%B6%E5%A7%94%E6%89%98.html) 为父节点注册 click 事件,当子节点被点击的时候,click事件会从子节点开始**向父节点冒泡**。**父节点捕获到事件**之后,开始执行方法体里的内容:通过判断 event.target 拿到了被点击的子节点``。从而可以获取到相应的信息,并作处理。 + +## Dom + +> [DOM](https://web.qianguyihao.com/04-JavaScript%E5%9F%BA%E7%A1%80/36-DOM%E7%AE%80%E4%BB%8B%E5%92%8CDOM%E6%93%8D%E4%BD%9C.html#%E5%B8%B8%E8%A7%81%E6%A6%82%E5%BF%B5) + +**节点**(Node):构成 HTML 网页的最基本单元。网页中的每一个部分都可以称为是一个节点,比如:html标签、属性、文本、注释、整个文档等都是一个节点。 + +虽然都是节点,但是实际上他们的具体类型是不同的。常见节点分为四类: + +- 文档节点(文档):整个 HTML 文档。整个 HTML 文档就是一个文档节点。 +- 元素节点(标签):HTML标签。 +- 属性节点(属性):元素的属性。 +- 文本节点(文本):HTML标签中的文本内容(包括标签之间的空格、换行)。 + +节点的类型不同,属性和方法也都不尽相同。所有的节点都是Object。 + +**解析过程**: HTML加载完毕,渲染引擎会在内存中把HTML文档,生成一个DOM树,getElementById是获取内中DOM上的元素节点。然后操作的时候修改的是该元素的**属性**。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202212151021206.png) + + + +### 有三种方式可以获取DOM节点 + +```javascript +var div1 = document.getElementById("box1"); //方式一:通过 id 获取 一个 元素节点(为什么是一个呢?因为 id 是唯一的) + +var arr1 = document.getElementsByTagName("div"); //方式二:通过 标签名 获取 元素节点数组,所以有s + +var arr2 = document.getElementsByClassName("hehe"); //方式三:通过 类名 获取 元素节点数组,所以有s +``` + +document.querySelector()方法,querySelectorAll()方法选择器写法和css选择器写法一样,但效率低 + + + +DOM的节点并不是孤立的,因此可以通过DOM节点之间的相对关系对它们进行访问。 + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202212151022606.png) + + + +获取父节点 + +```javascript + 节点.parentNode +``` + +获取所有的子节点 + +(1)childNodes:标准属性。返回的是指定元素的子节点的集合(包括元素节点、所有属性、文本节点) +(2)children:非标准属性。返回的是指定元素的子元素节点的集合。【重要】它只返回HTML节点,甚至不返回文本节点。 + + + +创建节点的流程:createElement(), createTextNode(),把文本节点插入元素节点 appendChild() + + + +### 获取节点的属性值 + +**方式1**: + +```javascript + 元素节点.属性名; + 元素节点[属性名]; +``` + +**方式2**: + +```javascript + 元素节点.getAttribute("属性名称"); +``` + +### 设置节点的属性值 + +方式1举例:(设置节点的属性值) + +```javascript + myNode.src = "images/2.jpg" //修改src的属性值 + myNode.className = "image2-box"; //修改class的name +``` + +方式2: + +```javascript + 元素节点.setAttribute("属性名", "新的属性值"); +``` + +方式2举例:(设置节点的属性值) + +```javascript + myNode.setAttribute("src","images/3.jpg"); +``` + + + +**如果是节点的“原始属性”**(比如 普通标签的`class/className`属性、普通标签的`style`属性、普通标签的 title属性、img 标签的`src`属性、超链接的`href`属性等),**方式1和方式2是等价的**,可以混用。怎么理解混用呢?比如说:用 `div.title = '我是标题'`设置属性,用 `div.getAttribute('title')`获取属性,就是混用。 + +但如果是节点的“非原始属性”,**这两种方式不能交换使用**,get值和set值必须使用同一种方法。 + + + +### nodeType属性 + +这里讲一下nodeType属性。 + +- **nodeType == 1 表示的是元素节点**(标签) 。记住:在这里,元素就是标签。 +- nodeType == 2 表示是属性节点。 +- nodeType == 3 是文本节点。 + + + +## style属性的获取和修改 + +在DOM当中,如果想设置样式,有两种形式: + +- className(针对内嵌样式) +- style(针对行内样式) + +需要注意的是:style是一个对象,只能获取**行内样式**,不能获取内嵌的样式和外链的样式。 + +### 通过 js 读取/设置元素的样式 只能行内 + +```javascript + 元素.style["属性"]; //格式 + + box.style["width"]; //举例 + +box1.style.width = "300px"; +box1.style.backgroundColor = "red"; // 驼峰命名法 +``` + +备注:我们通过style属性设置的样式都是**行内样式**,而行内样式有较高的优先级。但是如果在样式中的其他地方写了`!important`,则此时`!important`会有更高的优先级。 + + + +### 通过 js 获取元素当前显示的样式 不只行内 + +(1)w3c的做法: + +```javascript + window.getComputedStyle("要获取样式的元素", "伪元素"); +``` + +两个参数都是必须要有的。参数二中,如果没有伪元素就用 null 代替(一般都传null)。 + +(2)IE和opera的做法: + +```javascript + obj.currentStyle; +``` + +注意: + +- 如果当前元素没有设置该样式,则获取它的默认值。 +- 该方法会返回一个**对象**,对象中封装了当前元素对应的样式,可以通过`对象.样式名`来读取具体的某一个样式。 +- 通过currentStyle和getComputedStyle()读取到的样式都是只读的,不能修改,如果要修改必须通过style属性。 + + + +```js + var div1 = document.getElementsByTagName("div")[0]; + + console.log(getStyle(div1, "width")); + console.log(getStyle(div1, "padding")); + console.log(getStyle(div1, "background-color")); + + /* + * 兼容方法,获取元素当前正在显示的样式。 + * 参数: + * obj 要获取样式的元素 + *. name 要获取的样式名 + */ + function getStyle(ele, attr) { + if (window.getComputedStyle) { + return window.getComputedStyle(ele, null)[attr]; + } + return ele.currentStyle[attr]; + } +``` + + + +## BOM + +- [BOM](https://web.qianguyihao.com/04-JavaScript%E5%9F%BA%E7%A1%80/45-BOM%E7%AE%80%E4%BB%8B%E5%92%8Cnavigator.userAgent&History&Location.html#%E5%B8%B8%E8%A7%81%E6%A6%82%E5%BF%B5) + +- **BOM**:浏览器对象模型(Browser Object Model),操作**浏览器部分功能**的API。比如让浏览器自动滚动。 + +```text +location.href = 'https://xxx'; +``` + +解释:获取当前页面的 url 路径(或者设置 url 路径);或者跳转到指定路径。 + +需要特别注意的是:window.location.href的赋值,并不会中断Javascript的执行立即进行页面跳转。因为 LocationChange 行为在浏览器内核中是起定时器异步执行的。异步执行的好处是为了防止代码调用过深,导致栈溢出,另外也是为了防止递归进入加载逻辑,导致状态紊乱,保证导航请求是顺序执行的。 + +解决办法:在 location.href 的下一行,加上 return 即可。意思是,执行了 location.href 之后,就不要再继续往下执行了。 + + + +```javascript + location.reload(); +``` + +解释:用于重新加载当前页面,作用和刷新按钮一样。 + +## 定时器 + +- setInterval():循环调用。将一段代码,**每隔一段时间**执行一次。(循环执行) +- setTimeout():延时调用。将一段代码,等待一段时间之后**再执行**。(只执行一次) + +每间隔一秒,将 数字 加1: + +```javascript + let num = 1; + setInterval(function () { + num ++; + console.log(num); + }, 1000); +``` + + + +定时器的返回值是作为这个定时器的**唯一标识**,可以用来清除定时器。具体方法是:假设定时器setInterval()的返回值是`参数1`,那么`clearInterval(参数1)`就可以清除定时器。 + +setTimeout()的道理是一样的。 + + + + + +## ES5严格模式 + +> [ES5中的严格模式](https://web.qianguyihao.com/05-JavaScript%E5%9F%BA%E7%A1%80%EF%BC%9AES6%E8%AF%AD%E6%B3%95/02-ES5%E4%B8%AD%E7%9A%84%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F.html#es%E7%9A%84%E5%87%A0%E4%B8%AA%E9%87%8D%E8%A6%81%E7%89%88%E6%9C%AC) + +使用 + +- 针对整个文件:将`use strict`放在文件的第一行,则整个文件将以严格模式运行。 +- 针对单个函数:将`use strict`放在函数体的第一行,则整个函数以严格模式运行。 + +语法和行为改变 + +- 必须用var声明变量 + +- 禁止自定义的函数中的this指向window + +- 创建eval作用域 + +- 对象不能有重名的属性 + +- 为了向将来Javascript的新版本过渡,严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。 + + + + + +在 ES6 语法及之后的版本里,可以使用 `const`、`let`关键字来定义一个变量 + +```js +const name; // 定义一个常量 + +let age; // 定义一个变量 +``` + +如果你想定义一个常量,就用 const;如果你想定义一个变量,就用 let。 + + + +## Json + +```scala +var a = { + b: 3, + c: "dd", +}; +console.log(a); +b = JSON.stringify(a); +console.log(b); + +console.log(JSON.parse(b)); +``` + +1、js对象(数组) --> json对象(数组): + +```javascript + JSON.stringify(obj/arr) +``` + +2、json对象(数组) --> js对象(数组): + +```javascript + JSON.parse(json)1 +``` + +上面这两个方法是ES5中提供的。不需要Import新的包,js就支持 + +## 同源和跨域 + +> [同源和跨域](https://web.qianguyihao.com/06-JavaScript%E5%9F%BA%E7%A1%80%EF%BC%9A%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B/04-%E5%90%8C%E6%BA%90%E5%92%8C%E8%B7%A8%E5%9F%9F.html#%E5%90%8C%E6%BA%90%E5%92%8C%E8%B7%A8%E5%9F%9F) + +同源策略是浏览器的一种安全策略,所谓同源是指,域名,协议,端口完全相同。 + +从我自己的网站访问别人网站的内容,就叫跨域。 + + + +  同源策略限制以下几种行为: + +- Cookie、LocalStorage 和 IndexDB 无法读取 +- DOM和JS对象无法获得 +- AJAX 请求不能发送 + + + +指当前域名不能请求其它域名的内容。解决跨域常见几种方式 + +- iframe:处于安全性考虑,浏览器的开发厂商已经禁止了这种方式。 +- JSONP:script 标签的 src 属性传递数据。 +- 跨域资源共享(CORS) [参考](https://juejin.cn/post/6844903882083024910#heading-5) + - CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。 + - 请求里有Origin, 服务端会校验。 + - 请求header里有**Access-Control-Request-**xx + - 预检请求可以只有一次 + +## Promise 异步编程 + +> [Promise](https://web.qianguyihao.com/06-JavaScript%E5%9F%BA%E7%A1%80%EF%BC%9A%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B/05-Promise%E5%85%A5%E9%97%A8%E8%AF%A6%E8%A7%A3.html) + +**回调的缺点** + +回调的写法比较直观,不需要 return,层层嵌套即可。但也存在两个问题: + +- 如果嵌套过深,则会出现**回调地狱**的问题。 +- 不同的函数,回调的参数,在写法上可能不一致,导致不规范、且需要**单独记忆**。 + +在 ES5 中,当进行多层嵌套回调时,会导致代码层次过多,很难进行后续维护和二次开发;而且会导致**回调地狱**的问题。ES6 中的 Promise 就可以解决这些问题。 + + + +ES6 中的 Promise 是异步编程的一种方案。从语法上讲,Promise 是一个对象,它可以获取异步操作的消息。 + +Promise 对象, 可以**用同步的表现形式来书写异步代码**(也就是说,代码看起来是同步的,但本质上的运行过程是异步的)。使用 Promise 主要有以下好处: + +- 1、可以很好地解决**回调地狱**的问题(避免了层层嵌套的回调函数)。 +- 2、语法简洁、可读性强,便于后期维护。 +- 3、Promise 对象提供了简洁的 API,使得管理异步操作更加容易。比如**多任务等待合并**。 + + + +- [使用 Promise](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises) + +Promise 很棒的一点就是**链式调用**(**chaining**)。 + + + +有可能会在一个回调失败之后继续使用链式操作,即,使用一个 `catch`,这对于在链式操作中抛出一个失败之后,再次进行新的操作会很有用。请阅读下面的例子: + +```js +new Promise((resolve, reject) => { + console.log('初始化'); + + resolve(); +}) +.then(() => { + throw new Error('有哪里不对了'); + + console.log('执行「这个」”'); +}) +.catch(() => { + console.log('执行「那个」'); +}) +.then(() => { + console.log('执行「这个」,无论前面发生了什么'); +}); +``` + + + + + +# MDN + +> [参考](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises) + +## 模块module + +可命名.mjs文件,和.js文件实际一样,但便于理解 + +需要导出。类似 + +```js +export const name = 'square'; + +export function draw(ctx, length, x, y, color) {} +``` + +需要导入。类似 + +```scala +import { name, draw, reportArea, reportPerimeter } from '/js-examples/modules/basic-modules/modules/square.mjs'; +``` + +现在我们只需要将 main.mjs 模块应用到我们的 HTML 页面。这与我们将常规脚本应用于页面的方式非常相似,但有一些显着的差异。首先,你需要把 `type="module"` 放到 [``](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/script) 标签中,来声明这个脚本是一个模块: + +``` + +``` + + + +支持重命名 + +```js +// inside module.mjs +export { + function1 as newFunctionName, + function2 as anotherNewFunctionName +}; + +// inside main.mjs +import { newFunctionName, anotherNewFunctionName } from '/modules/module.mjs'; +``` + + + +```js +// inside module.mjs +export { function1, function2 }; + +// inside main.mjs +import { function1 as newFunctionName, + function2 as anotherNewFunctionName } from '/modules/module.mjs'; +``` + + + + + +支持模块对象创建 + +一个更好的解决方是,导入每一个模块功能到一个模块功能对象上。可以使用以下语法形式: + +```js +import * as Module from '/modules/module.mjs'; +``` + +这将获取 `module.mjs` 中所有可用的导出,并使它们可以作为对象模块的成员使用,从而有效地为其提供自己的命名空间。例如: + +```js +Module.function1() +Module.function2() +etc. +``` + +## 原型 + +> [原型(prototype)](https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes#%E4%BD%BF%E7%94%A8_javascript_%E4%B8%AD%E7%9A%84%E5%8E%9F%E5%9E%8B) + +在传统的 OOP 中,首先定义“类”,此后创建对象实例时,类中定义的所有属性和方法都被复制到实例中。在 JavaScript 中并不如此复制——而是在对象实例和它的构造器之间建立一个链接(它是__proto__属性,是从构造函数的`prototype`属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法。 + +理解对象的原型(可以通过 [`Object.getPrototypeOf(obj)`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/GetPrototypeOf)或者已被弃用的[`__proto__`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)属性获得)与构造函数的 `prototype` 属性之间的区别是很重要的。前者是每个实例上都有的属性,后者是构造函数的属性。也就是说,`Object.getPrototypeOf(new Foobar())` 和 `Foobar.prototype` 指向着同一个对象。 + + + +在 javascript 中,函数可以有属性。每个函数都有一个特殊的属性叫作**原型(prototype)**。 + +prototype是个对象。`prototype` 属性的值是一个对象,我们希望被原型链下游的对象继承的属性和方法,都被储存在其中。 + +原型对象是一个内部对象,应当使用 `__proto__` 访问)。`prototype` 属性包含(指向)一个对象,你在这个对象中定义需要被继承的成员。 + +原型链中的方法和属性**没有**被复制到其他对象——它们被访问需要通过前面所说的“原型链”的方式。这是和构造器里直接声明定义方法的区别,构造器里的是每个实例都有一份。原型链里全部只有一份。 + + + +每个实例对象都从原型中继承了一个 constructor 属性,该属性指向了用于构造此实例对象的构造函数。 + + + +事实上,一种极其常见的对象定义模式是,在构造器(函数体)中定义属性、在 `prototype` 属性上定义方法。如此,构造器只包含属性定义,而方法则分装在不同的代码块,代码更具可读性。例如: + +```js +// 构造器及其属性定义 + +function Test(a,b,c,d) { + // 属性定义 +}; + +// 定义第一个方法 + +Test.prototype.x = function () { ... } + +// 定义第二个方法 + +Test.prototype.y = function () { ... } + +// 等等…… +``` + + + +Object.prototype的**proto**属性是一个访问器属性(一个getter函数和一个setter函数),它公开访问它的对象的内部[[Prototype]](对象或null)。 + + + +> [轻松理解JS 原型原型链](https://juejin.cn/post/6844903989088092174) + +1. js分为**函数对**象和**普通对象**,每个对象都有__proto__属性,但是只有函数对象才有prototype属性 +2. Object、Function都是js内置的**函数**, 类似的还有我们常用到的Array、RegExp、Date、Boolean、Number、String +3. 属性__proto__是一个对象,它有两个属性,constructor和__proto__; +4. 原型对象prototype有一个默认的constructor属性,用于记录实例是由哪个构造函数创建; + + + +```scala + function Person(name, age){ + this.name = name; + this.age = age; + } + + Person.prototype.motherland = 'China' + let person01 = new Person('小明', 18); +``` + + + + +js之父在设计js原型、原型链的时候遵从以下两个准则 +1. Person.prototype.constructor == Person // **准则1:原型对象(即Person.prototype)的constructor指向构造函数本身** +2. person01.__proto__ == Person.prototype // **准则2:实例(即person01)的__proto__和原型对象指向同一个地方** + + + + + +构造函数和原型可支持面向对象的特性。但不容易实现。下面是es6里的class笔记。 + + + + + +## 类 + +> [JavaScript 中的类](https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Classes_in_JavaScript) + +### 类 ES6 class + +下面的是es6里提供的 + +这里描述的特性并不是一种继承对象的新方式:在引擎的底层,这一特性使用的仍是原型。这只是一种更容易的创建原型链的方法。 + + + +```scala +class Person { + + name; + + constructor(name) { + this.name = name; + } + + introduceSelf() { + console.log(`Hi! I'm ${this.name}`); + } + +} + +const giles = new Person('Giles'); + +giles.introduceSelf(); // Hi! I'm Giles +``` + +构造函数使用 [`constructor`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/constructor) 关键字来声明。就像[在类声明外的构造函数](https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Basics)一样,它会: + +- 创建一个新的对象 +- 将 `this` 绑定到这个新的对象,你可以在构造函数代码中使用 `this` 来引用它 +- 执行构造函数中的代码 +- 返回这个新的对象 + +如果你不需要任何特殊的初始化内容,你可以省略构造函数,默认的构造函数会被自动生成 + + + +### **继承** + +对于上文给出的 Person 类,我们声明一个它的子类 Professor。 + +注意extends, constructor里的super + +```scala + + +class Professor extends Person { + + teaches; + + constructor(name, teaches) { + super(name); + this.teaches = teaches; + } + + introduceSelf() { + console.log(`My name is ${this.name}, and I will be your ${this.teaches} professor.`); + } + + grade(paper) { + const grade = Math.floor(Math.random() * (5 - 1) + 1); + console.log(grade); + } + +} +``` + + + +### 私有 + +想要某些字段私有。可以用字段前面加#. 私有数据属性必须在类的声明中声明,而且其名称需以 `#` 开头。 + + + +与私有数据属性一样,你也可以声明私有方法。而且名称也是以 `#` 开头,只能在类自己的方法中调用 + + + +```scala +class Student extends Person { + + #year; + + constructor(name, year) { + super(name); + this.#year = year; + } + somePublicMethod() { + this.#somePrivateMethod(); + } + + #somePrivateMethod() { + console.log('You called me?'); + } +} +``` + +### 注意点 + +1. 在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象。 + +2. 类里面的共有属性和方法一定要加this调用。 + +3. 类里面的this指向问题。 constructor里面的this指向的是 创建的实例对象,方法里面的this指向这个方法的调用者 +4. 属性只能放到构造函数里,`this.xxx` 来定义。没有静态属性 + + + + + +### 静态方法 + +使用 `static` 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用: + +```js +class Animal { + static isAnimal(a) { + return a instanceof Animal; + } +} + +let a = new Animal('Jack'); +Animal.isAnimal(a); // true +a.isAnimal(a); // TypeError: a.isAnimal is not a function +``` + + + +# ES6 + +> [参考](https://web.qianguyihao.com/05-JavaScript%E5%9F%BA%E7%A1%80%EF%BC%9AES6%E8%AF%AD%E6%B3%95/01-ES5%E5%92%8CES6%E7%9A%84%E4%BB%8B%E7%BB%8D.html#%E5%89%8D%E8%A8%80) + +简单来说,ECMAScript 是 JS 的语言标准。当然,ECMAScript 还包括其他脚本语言的语言标准。 + +ES6 是新的 JS 语法标准。**ES6 实际上是一个泛指,泛指 ES 2015 及后续的版本**。 + +ES6 的改进如下: + +- ES6 之前的变量提升,会导致程序在运行时有一些不可预测性。而 ES6 中通过 let、const 变量优化了这一点。 +- ES6 增加了很多功能,比如:**常量、作用域、对象代理、异步处理、类、继承**等。这些在 ES5 中想实现,比较复杂,但是 ES6 对它们进行了封装。 +- ES6 之前的语法过于松散,实现相同的功能,不同的人可能会写出不同的代码。 + +ES6 的目标是:让 JS 语言可以编写复杂的大型应用程序,成为企业级开发语言。 + + + + + +现在,有了 ES6 之后,我们可以使用对象解构的方式进行赋值。举例如下: + +```js +const person = { name: 'qianguyihao', age: 28, sex: '男' }; +let { name, age, sex } = person; // 对象的结构赋值 +``` + + + + + +ES6 在**函数扩展**方面,新增了很多特性。例如: + +- 箭头函数 +- 参数默认值 +- 参数结构赋值 +- 剩余参数 +- 扩展运算符 +- this 绑定 +- 尾调用 + + + +```scala +const fn2 = (a, b) => { + console.log('haha'); + return a + b; +}; + +console.log(fn2(1, 2)); //输出结果:3 +``` + +ES6 的箭头函数中:**箭头函数本身不绑定 this**,this 指向的是**箭头函数定义位置的 this**(也就是说,箭头函数在哪个位置定义的,this 就跟这个位置的 this 指向相同)。 + +```scala +function fn(param = 'hello') { + console.log(param); +} +``` + +```scala +const fn = (...args) => { + //当不确定方法的参数时,可以使用剩余参数 + console.log(args[0]); + console.log(args[1]); + console.log(args[2]); + console.log(args[3]); +}; + +``` + diff --git "a/_posts/Tech/FrontEnd/2017-12-03-jquery\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2017-12-03-jquery\345\255\246\344\271\240\347\254\224\350\256\260.md" deleted file mode 100644 index bf0d9b09ad..0000000000 --- "a/_posts/Tech/FrontEnd/2017-12-03-jquery\345\255\246\344\271\240\347\254\224\350\256\260.md" +++ /dev/null @@ -1,110 +0,0 @@ ---- -layout: post -category: FrontEnd -title: jquery笔记 -tags: FrontEnd ---- -class用. ,id用# - -## jquery - -```javascript -$("").hide() -//必须 -$(document).ready(function(){ - ---- jQuery functions go here ---- - -}); - -jQuery 语法实例 -$(this).hide() -演示 jQuery hide() 函数,隐藏当前的 HTML 元素。 -$("#test").hide() -演示 jQuery hide() 函数,隐藏 id="test" 的元素。 -$("p").hide() -演示 jQuery hide() 函数,隐藏所有

      元素。 -$(".test").hide() -演示 jQuery hide() 函数,隐藏所有 class="test" 的元素。 - -jQuery 元素选择器 -jQuery 使用 CSS 选择器来选取 HTML 元素。 -$("p") 选取

      元素。 -$("p.intro") 选取所有 class="intro" 的

      元素。 -$("p#demo") 选取所有 id="demo" 的

      元素。 -jQuery 属性选择器 -jQuery 使用 XPath 表达式来选择带有给定属性的元素。 -$("[href]") 选取所有带有 href 属性的元素。 -$("[href='#']") 选取所有带有 href 值等于 "#" 的元素。 -$("[href!='#']") 选取所有带有 href 值不等于 "#" 的元素。 -$("[href$='.jpg']") 选取所有 href 值以 ".jpg" 结尾的元素。 -jQuery CSS 选择器 -jQuery CSS 选择器可用于改变 HTML 元素的 CSS 属性。 -下面的例子把所有 p 元素的背景颜色更改为红色: -$("p").css("background-color","red"); - -$(document).ready(function) 将函数绑定到文档的就绪事件(当文档完成加载时) -$(selector).click(function) 触发或将函数绑定到被选元素的点击事件 -$(selector).dblclick(function) 触发或将函数绑定到被选元素的双击事件 -$(selector).focus(function) 触发或将函数绑定到被选元素的获得焦点事件 -$(selector).mouseover(function) 触发或将函数绑定到被选元素的鼠标悬停事件 - -$("#btn1").click(function(){ - $("#test1").text("Hello world!"); -}); -$("#btn2").click(function(){ - $("#test2").html("Hello world!"); -}); -$("#btn3").click(function(){ - $("#test3").val("Dolly Duck"); -}); -//回调函数 -$("#btn1").click(function(){ - $("#test1").text(function(i,origText){ - return "Old text: " + origText + " New text: Hello world! - (index: " + i + ")"; - }); -}); - -$("button").click(function(){ - $("#w3s").attr("href","http://www.w3school.com.cn/jquery"); -}); -//同时设置多个属性 -$("button").click(function(){ - $("#w3s").attr({ - "href" : "http://www.w3school.com.cn/jquery", - "title" : "W3School jQuery Tutorial" - }); -}); - -$("p").append("Some appended text."); -$("p").prepend("Some prepended text."); - -function appendText() -{ -var txt1="

      Text.

      "; // 以 HTML 创建新元素 -var txt2=$("

      ").text("Text."); // 以 jQuery 创建新元素 -var txt3=document.createElement("p"); // 以 DOM 创建新元素 -txt3.innerHTML="Text."; -$("p").append(txt1,txt2,txt3); // 追加新元素 -} - -$("img").after("Some text after"); -$("img").before("Some text before"); - -$("#div1").remove(); -$("#div1").empty(); -$("p").remove(".italic"); - -$("button").click(function(){ - $("h1,h2,p").addClass("blue"); - $("div").addClass("important"); -}); - -$("button").click(function(){ - $("h1,h2,p").removeClass("blue"); -}); - -$("p").css("background-color","yellow"); -$("p").css({"background-color":"yellow","font-size":"200%"}); -``` \ No newline at end of file diff --git "a/_posts/Tech/FrontEnd/2017-12-03-js\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2017-12-03-js\345\255\246\344\271\240\347\254\224\350\256\260.md" deleted file mode 100644 index 9d528c3cec..0000000000 --- "a/_posts/Tech/FrontEnd/2017-12-03-js\345\255\246\344\271\240\347\254\224\350\256\260.md" +++ /dev/null @@ -1,378 +0,0 @@ ---- -layout: post -category: FrontEnd -title: javascript笔记 -tags: FrontEnd ---- - -## javascript -- 字符串转换为数字用Number(str)或则和parseInt(str)/parseFloat(str)方法 -- 数字转换为字符串用var.toString()方法 -- 获取字符串或者数组的长度,用arr.length属性 -- 数组添加头部元素: arr.unshift("a","b"....); 结尾用push()方法 -- NaN: not a number -- 将数组元素连接成字符串: arr.join("连接符") -- 可以直接使用Math.方法名,如max(...), -- document.querySelector()方法,querySelectorAll()方法选择器写法和css选择器写法一样,但效率低 -- ByName()只用于表单元素,一般是单选和复选框 -- 两个特殊方法,document.title, document.body -- 节点有三种:元素节点,属性节点,文本节点 -- 创建节点的流程:createElement(), createTextNode(),把文本节点插入元素节点 appendChild(),把组装好的节点插入到已有元素中:appendChild() -- obj.style.属性名只可以获得行内样式,是没办法获得内部样式和外部样式的。一般用getComputedStyle.属性名或者obj.style.cssText()="width:3px"等来写,后者可以写多个,css写法,前者驼峰样式,没有-了 -- html中onclick="f()", js中obj.click=f,前者是调用属性,后者是给属性赋值 -- 只执行最后一次window.onload=function(){ } -- 事件绑定: obj.addEventListener("click",funcion,false); - -# javascript基础教程 - -## 插入js用法 -1. 可以插入到html的任何位置 -2. 头部 -3. 头部> - -```javascript -// 内部脚本 -/*使用标签*/ -//外部脚本使用 可以插入任何位置 -//document.write()加载后使用,将覆盖,如函数中 - -//JavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型: -document.getElementById("demo").innerHTML="我的第一段 JavaScript"; -document.write("

      我的第一段 JavaScript

      "); -``` - -## 变量声明用法 -```javascript -对大小写敏感 -拆行用\ -//声明变量 -var a; -var name="Gates", age=56, job="CEO"; - -// 数组 开头为0 -var cars=new Array(); -cars[0]="Audi"; -cars[1]="BMW"; -cars[2]="Volvo"; -// 或者 -var cars=new Array("Audi","BMW","Volvo"); -// 或者 -var cars=["Audi","BMW","Volvo"]; - -// 对象 -var person={ - firstname : "Bill", - lastname : "Gates", - id : 5566 -}; - -//声明变量时可以确定其类型,如 -var carname=new String; -var x= new Number; -var y= new Boolean; -var cars= new Array; -var person= new Object; - -//创建对象 -person=new Object(); -person.firstname="Bill"; -person.lastname="Gates"; -person.age=56; -person.eyecolor="blue"; -//或者 -person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"}; -//或者对象构造器 -function person(firstname,lastname,age,eyecolor) -{ - this.firstname=firstname; - this.lastname=lastname; - this.age=age; - this.eyecolor=eyecolor; -} -var myFather=new person("Bill","Gates",56,"blue"); -//定义对象方法 -function person(firstname,lastname,age,eyecolor) -{ - this.firstname=firstname; - this.lastname=lastname; - this.age=age; - this.eyecolor=eyecolor; - - this.changeName=changeName; - function changeName(name) - { - this.lastname=name; - } -} - -``` - -## if else用法,循环 - -```javascript - -if (time<10) -{ - x="Good morning"; -} -else if (time<20) -{ - x="Good day"; -} -else -{ - x="Good evening"; -} - -var day=new Date().getDay(); -switch (day) -{ - case 6: - x="Today it's Saturday"; - break; - case 0: - x="Today it's Sunday"; - break; - default: - x="Looking forward to the Weekend"; -} - -for (var i=0;i"); -} -for (var i=0,len=cars.length; i"); -} -//循环遍历对象的属性 -var person={fname:"John",lname:"Doe",age:25}; -for (x in person) -{ - txt=txt + person[x]; -} - -while (i<5) -{ - x=x + "The number is " + i + "
      "; - i++; -} -do -{ - x=x + "The number is " + i + "
      "; - i++; -} -while (i<5); -//break; continue; -``` - -## 函数 -```javascript -function myFunction(var1,var2) -{ - // 这里是要执行的代码 - return 3;//可以没有 -} - -``` -## try/catch -```javacript -try -{ - throw exception; - adddlert("Welcome guest!"); -} -catch(err) -{ - txt="There was an error on this page.\n\n"; - txt+="Error description: " + err.message + "\n\n"; - txt+="Click OK to continue.\n\n"; - alert(txt); -} -``` - -## 引用元素 -```javascript -//通过标签找html元素 -var x=document.getElementById("main");//id: main -var y=x.getElementsByTagName("p"); - -var element=document.getElementById("header"); -element.innerHTML="New Header"; - -document.getElementById(id).attribute=new value; - -document.getElementById("image").src="landscape.jpg"; - -document.getElementById("p2").style.color="blue"; - -//DOM事件 -//

      请点击该文本

      this就是自己的id -//

      请点击该文本

      -document.getElementById("myBtn").onclick=function(){displayDate()}; -// -//分配事件 -document.getElementById("myBtn").onclick=function(){displayDate()}; - -//创建元素 -var para=document.createElement("p"); -var node=document.createTextNode("这是新段落。"); -para.appendChild(node); -var element=document.getElementById("div1"); -element.appendChild(para); -//删除元素 -var parent=document.getElementById("div1"); -var child=document.getElementById("p1"); -parent.removeChild(child); -//正则表达式 RegExp -``` - -# jquery教程 - -## 语法 -```javacript - $(document).ready(function(){ - - // 开始写 jQuery 代码... - - }); - - 简洁写法(与以上写法效果相同): - $(function(){ - - // 开始写 jQuery 代码... - - }); - -#id 选择器 -$("#test") -.class 选择器 -$(".test") -$("p").css("background-color","red"); -$(this) 选取当前 HTML 元素 - ``` - -## 事件 -```javascript -$("p").click(function(){ - // action goes here!! -}); -$("p").click(); -$("p").dblclick(function(){ - $(this).hide(); -}); - -jQuery hide() 和 show() -通过 jQuery,您可以使用 toggle() 方法来切换 hide() 和 show() 方法。 - -$(selector).toggle(speed,callback); -可选的 speed 参数规定隐藏/显示的速度,可以取以下值:"slow"、"fast" 或毫秒。 -可选的 callback 参数是 toggle() 方法完成后所执行的函数名称。 -可选的 callback 参数,具有以下三点说明: -$(selector)选中的元素的个数为n个,则callback函数会执行n次 -callback函数名后加括号,会立刻执行函数体,而不是等到显示/隐藏完成后才执行 -callback既可以是函数名,也可以是匿名函数 - -Callback 函数在当前动画 100% 完成之后执行。 - -通过 jQuery,可以把动作/方法链接在一起。 -Chaining 允许我们在一条语句中运行多个 jQuery 方法(在相同的元素上)。 -$("#p1").css("color","red").slideUp(2000).slideDown(2000); -$("#p1").css("color","red") - .slideUp(2000) - .slideDown(2000); - -三个简单实用的用于 DOM 操作的 jQuery 方法: -text() - 设置或返回所选元素的文本内容 -html() - 设置或返回所选元素的内容(包括 HTML 标记) -val() - 设置或返回表单字段的值 - -$("#btn1").click(function(){ - alert("Text: " + $("#test").text()); -}); -$("#btn2").click(function(){ - alert("HTML: " + $("#test").html()); -}); -$("#btn1").click(function(){ - alert("Value: " + $("#test").val()); -}); - -下面的例子演示如何通过 jQuery val() 方法获得输入字段的值: - - - - -

      名称:

      - - - - -$("button").click(function(){ - alert($("#w3s").attr("href")); -}); - -下面的例子演示如何通过 text()、html() 以及 val() 方法来设置内容: -$("#btn1").click(function(){ - $("#test1").text("Hello world!"); -}); -$("#btn2").click(function(){ - $("#test2").html("Hello world!"); -}); -$("#btn3").click(function(){ - $("#test3").val("Dolly Duck"); -}); -text()、html() 以及 val() 的回调函数 - -上面的三个 jQuery 方法:text()、html() 以及 val(),同样拥有回调函数。 -回调函数由两个参数:被选元素列表中当前元素的下标,以及原始(旧的)值。 -然后以函数新值返回您希望使用的字符串。 -$("#btn1").click(function(){ - $("#test1").text(function(i,origText){ - return "Old text: " + origText + " New text: Hello world! - (index: " + i + ")"; - }); -}); - -$("button").click(function(){ - $("#w3s").attr("href","//www.w3cschool.cn/jquery"); -}); - -append() - 在被选元素内部的结尾插入指定内容 -prepend() - 在被选元素内部的开头插入指定内容 -after() - 在被选元素之后插入内容 -before() - 在被选元素之前插入内容 - -$("p").append("Some appended text."); - -$("#div1").remove(); - -$("#div1").empty(); - -addClass() - 向被选元素添加一个或多个类 -removeClass() - 从被选元素删除一个或多个类 -toggleClass() - 对被选元素进行添加/删除类的切换操作 -css() - 设置或返回样式属性 - -$("button").click(function(){ - $("h1,h2,p").addClass("blue"); - $("div").addClass("important"); -}); - -您也可以在 addClass() 方法中规定多个类: -$("button").click(function(){ - $("#div1").addClass("important blue"); -}); - -下面的例子将返回首个匹配元素的 background-color 值: -$("p").css("background-color"); - -$("p").css("background-color","yellow"); - -$("p").css({"background-color":"yellow","font-size":"200%"}); -``` \ No newline at end of file diff --git "a/_posts/Tech/FrontEnd/2018-02-11-html\351\200\237\346\237\245.md" "b/_posts/Tech/FrontEnd/2018-02-11-html\351\200\237\346\237\245.md" deleted file mode 100644 index 1db8f68d5c..0000000000 --- "a/_posts/Tech/FrontEnd/2018-02-11-html\351\200\237\346\237\245.md" +++ /dev/null @@ -1,160 +0,0 @@ ---- -layout: post -category: FrontEnd -title: html速查 -tags: FrontEnd ---- - -## HTML基本文档 -```html - - - -文档标题 - - -可见文本... - - -``` - -## 基本标签(Basic Tags) -```html -

      最大的标题

      -

      . . .

      -

      . . .

      -

      . . .

      -
      . . .
      -
      最小的标题
      - -

      这是一个段落。

      -
      (换行) -
      (水平线) - -``` - -## 文本格式化(Formatting) -```html -粗体文本 -计算机代码 -强调文本 -斜体文本 -键盘输入 - H5已废弃 -
      预格式化文本
      -更小的文本 -重要的文本 - - (缩写) - TheWHO was founded in 1948. -
      (联系信息) - 就是斜体 - (文字方向) -
      (从另一个源引用的部分) - (工作的名称) - (删除的文本) - (插入的文本) - (下标文本) - (上标文本) -``` - -## 链接(Links) -```html -普通的链接:链接文本 -图像链接: 替换文本 -邮件链接: 发送e-mail -书签: -提示部分 -跳到提示部分 -``` - -## 图片(Images) -必须有src和alt属性 -```html -替换文本 -``` - -## 样式/区块(Styles/Sections) -```html - -
      文档中的块级元素
      -文档中的内联元素 -``` - -## 无序列表 -```html -
        -
      • 项目
      • -
      • 项目
      • -
      -``` - -## 有序列表 -```html -
        -
      1. 第一项
      2. -
      3. 第二项
      4. -
      -``` - -## 定义列表 -```html -
      -
      项目 1
      -
      描述项目 1
      -
      项目 2
      -
      描述项目 2
      -
      -``` - -## 表格(Tables) -```html - - - - - - - - - -
      表格标题表格标题
      表格数据表格数据
      -``` - -## 框架(Iframe) -```html - -``` - -## 表单(Forms) -每个输入元素必须有一个name属性 - -在form规定action, submit提交就,规定post还是get -```html -
      - - - - - - - - - - -
      -``` - -## 实体(Entities) -```html -< 等同于 < -> 等同于 > -© 等同于 © -``` \ No newline at end of file diff --git "a/_posts/Tech/FrontEnd/2018-02-12-javascript\351\200\237\346\237\245.md" "b/_posts/Tech/FrontEnd/2018-02-12-javascript\351\200\237\346\237\245.md" deleted file mode 100644 index a10a1b8753..0000000000 --- "a/_posts/Tech/FrontEnd/2018-02-12-javascript\351\200\237\346\237\245.md" +++ /dev/null @@ -1,408 +0,0 @@ ---- -layout: post -category: FrontEnd -title: javascript速查 -tags: FrontEnd ---- - -## js用法 -外部脚本, 可以插入任何位置 -```javascript - -``` -内部脚本 -```javascript - -``` -脚本可被放置在 HTML 页面的 body和head部分中。 - -## JavaScript 输出 -JavaScript 没有任何打印或者输出的函数。 - -document.write是直接写入到页面的内容流,如果在写之前没有调用document.open, 浏览器会自动调用open。每次写完关闭之后重新调用该函数,会导致页面被重写。 - - JavaScript 显示数据 - JavaScript 可以通过不同的方式来输出数据: - - 使用 window.alert() 弹出警告框。 - 使用 document.write() 方法将内容写到 HTML 文档中。 - 使用 innerHTML 写入到 HTML 元素。 - 使用 console.log() 写入到浏览器的控制台。 - -## 操作 HTML 元素 -如需从 JavaScript 访问某个 HTML 元素,您可以使用 document.getElementById(id) 方法。 -```javascript -//通过标签找html元素 -var x=document.getElementById("main");//id: main -var y=x.getElementsByTagName("p"); - -var element=document.getElementById("header"); -element.innerHTML="New Header"; - -document.getElementById(id).attribute=new value; - -document.getElementById("image").src="landscape.jpg"; - -document.getElementById("p2").style.color="blue"; - -``` -## 变量 -字符串(String)、数字(Number)、布尔(Boolean)、数组(Array)、对象(Object)、空(Null)、未定义(Undefined)。 -```javascript -//声明变量 -var a; -var name="Gates", age=56, job="CEO"; -//JavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型: - -//声明变量时可以确定其类型,如 -var carname=new String; -var x= new Number; -var y= new Boolean; -var cars= new Array; -var person= new Object; -``` - -## 数组 -开头为0 -```javascript -var cars=new Array(); -cars[0]="Audi"; -cars[1]="BMW"; -cars[2]="Volvo"; -// 或者 -var cars=new Array("Audi","BMW","Volvo"); -// 或者 -var cars=["Audi","BMW","Volvo"]; -``` - -## 对象 -对象由花括号分隔。在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号分隔 - -### 对象创建 -```javascript -var person={ - firstname : "Bill", - lastname : "Gates", - id : 5566 -}; - -//创建对象 -person=new Object(); -person.firstname="Bill"; -person.lastname="Gates"; -person.age=56; -person.eyecolor="blue"; -//或者 -person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"}; -//或者对象构造器 -function person(firstname,lastname,age,eyecolor) -{ - this.firstname=firstname; - this.lastname=lastname; - this.age=age; - this.eyecolor=eyecolor; -} -var myFather=new person("Bill","Gates",56,"blue"); -``` - -### 访问对象属性 -对象属性有两种寻址方式: -```javascript - name=person.lastname; - name=person["lastname"]; -``` - -### 对象方法 -```javascript -var person = { - firstName: "John", - lastName : "Doe", - id : 5566, - fullName : function() - { - return this.firstName + " " + this.lastName; - } -}; -document.getElementById("demo").innerHTML = person.fullName(); -``` - -### 使用对象方法 -对象方法通过添加 () 调用 (作为一个函数)。 -```javascript -name = person.fullName(); -``` - -## Undefined 和 Null -Undefined 这个值表示变量不含有值。 - -可以通过将变量的值设置为 null 来清空变量。 - -## 函数 -```javascript -// 传统定义函数方式 -function myFunction(a,b) -{ - if (a>b) - { - return; - } - x=a+b -} - -function Test () { - // -} - -const Test = function () { - // -} - -// 使用箭头函数定义函数时可以省略 function 关键字 -const Test = (...params) => { - // -} - -// 该函数只有一个参数时可以简写成: -const Test = param => { - return param; -} - -console.log(Test('hello')); // hello -``` - -## 语法 -### if else -```javascript -if (time<10) -{ - x="Good morning"; -} -else if (time<20) -{ - x="Good day"; -} -else -{ - x="Good evening"; -} -``` - -### swith语法 -```javascript -var day=new Date().getDay(); -switch (day) -{ - case 6: - x="Today it's Saturday"; - break; - case 0: - x="Today it's Sunday"; - break; - default: - x="Looking forward to the Weekend"; -} -``` - -### for循环 -```javascript -for (var i=0;i"); -} -//循环遍历对象的属性 -var person={fname:"John",lname:"Doe",age:25}; -for (x in person) -{ - txt=txt + person[x]; -} -``` - -### while循环 -```javascript -while (i<5) -{ - x=x + "The number is " + i + "
      "; - i++; -} - -do -{ - x=x + "The number is " + i + "
      "; - i++; -} -while (i<5); -//break; continue; -``` - -## 类型转化 - -### typeof 操作符 -你可以使用 typeof 操作符来查看 JavaScript 变量的数据类型。 -请注意: - - NaN 的数据类型是 number - 数组(Array)的数据类型是 object - 日期(Date)的数据类型为 object - null 的数据类型是 object - 未定义变量的数据类型为 undefined -实例 - -```javascript -typeof "John" // 返回 string -typeof 3.14 // 返回 number -typeof NaN // 返回 number -typeof false // 返回 boolean -typeof [1,2,3,4] // 返回 object -typeof {name:'John', age:34} // 返回 object -typeof new Date() // 返回 object -typeof function () {} // 返回 function -typeof myCar // 返回 undefined (如果 myCar 没有声明) -typeof null // 返回 object -``` - -### constructor 属性 -constructor 属性返回所有 JavaScript 变量的构造函数。 - -实例 -```javascript -"John".constructor // 返回函数 String() { [native code] } -(3.14).constructor // 返回函数 Number() { [native code] } -false.constructor // 返回函数 Boolean() { [native code] } -[1,2,3,4].constructor // 返回函数 Array() { [native code] } -{name:'John', age:34}.constructor // 返回函数 Object() { [native code] } -new Date().constructor // 返回函数 Date() { [native code] } -function () {}.constructor // 返回函数 Function(){ [native code] } - -function isArray(myArray) { - return myArray.constructor.toString().indexOf("Array") > -1; -} - -function isDate(myDate) { - return myDate.constructor.toString().indexOf("Date") > -1; -} -``` - -### 将数字转换为字符串 -```javascript -全局方法 String() 可以将数字转换为字符串。 - -String(x) // 将变量 x 转换为字符串并返回 -String(123) // 将数字 123 转换为字符串并返回 -String(100 + 23) // 将数字表达式转换为字符串并返回 - -Number 方法 toString() 也是有同样的效果。 - -实例 -x.toString() -(123).toString() -(100 + 23).toString() - -``` - -### 将布尔值转换为字符串 -```javascript -全局方法 String() 可以将布尔值转换为字符串。 - -String(false) // 返回 "false" -String(true) // 返回 "true" -Boolean 方法 toString() 也有相同的效果。 - -false.toString() // 返回 "false" -true.toString() // 返回 "true" -``` - -### 将日期转换为字符串 -```javascript -Date() 返回字符串。 - -Date() // 返回 Thu Jul 17 2014 15:38:19 GMT+0200 (W. Europe Daylight Time) -全局方法 String() 可以将日期对象转换为字符串。 - -String(new Date()) // 返回 Thu Jul 17 2014 15:38:19 GMT+0200 (W. Europe Daylight Time) -Date 方法 toString() 也有相同的效果。 - -实例 -obj = new Date() -obj.toString() // 返回 Thu Jul 17 2014 15:38:19 GMT+0200 (W. Europe Daylight Time) -``` - -### 将字符串转换为数字 -```javascript -全局方法 Number() 可以将字符串转换为数字。 - -字符串包含数字(如 "3.14") 转换为数字 (如 3.14). - -空字符串转换为 0。 - -其他的字符串会转换为 NaN (不是个数字)。 - -Number("3.14") // 返回 3.14 -Number(" ") // 返回 0 -Number("") // 返回 0 -Number("99 88") // 返回 NaN - -一元运算符 + -Operator + 可用于将变量转换为数字: -``` -### 将布尔值转换为数字 -```javascript - -全局方法 Number() 可将布尔值转换为数字。 - -Number(false) // 返回 0 -Number(true) // 返回 1 -``` - -### 将日期转换为数字 -```javascript - -全局方法 Number() 可将日期转换为数字。 - -d = new Date(); -Number(d) // 返回 1404568027739 -日期方法 getTime() 也有相同的效果。 - -d = new Date(); -d.getTime() // 返回 1404568027739 -``` - -## try catch -```javascript -try -{ - throw exception; - adddlert("Welcome guest!"); -} -catch(err) -{ - txt="There was an error on this page.\n\n"; - txt+="Error description: " + err.message + "\n\n"; - txt+="Click OK to continue.\n\n"; - alert(txt); -} -``` - -## 其他 -```javascript -//DOM事件 -//

      请点击该文本

      this就是自己的id -//

      请点击该文本

      -document.getElementById("myBtn").onclick=function(){displayDate()}; -// -//分配事件 -document.getElementById("myBtn").onclick=function(){displayDate()}; - -//创建元素 -var para=document.createElement("p"); -var node=document.createTextNode("这是新段落。"); -para.appendChild(node); -var element=document.getElementById("div1"); -element.appendChild(para); -//删除元素 -var parent=document.getElementById("div1"); -var child=document.getElementById("p1"); -parent.removeChild(child); -//正则表达式 RegExp -``` \ No newline at end of file diff --git a/_posts/Tech/FrontEnd/2018-06-15-ajax.md b/_posts/Tech/FrontEnd/2018-06-15-ajax.md deleted file mode 100644 index 388f2c44ae..0000000000 --- a/_posts/Tech/FrontEnd/2018-06-15-ajax.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -layout: post -category: FrontEnd -title: ajax -tags: FrontEnd ---- -代码链接库[my github](https://github.com/mafulong/ajaxLearning) - - -## ajax请求数据 -### get -```javascript - var xmlhttp=new XMLHttpRequest(); - xmlhttp.open("GET","/test/GetSearchTips?sear="+thisnode.value,true); - xmlhttp.send(); -``` - -### post -```javascript - xmlhttp.open("POST","/myservlet",true); - xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); - xmlhttp.send("name=mafulong&age=14"); -``` - -## 后台处理数据 -```java - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { -// super.doGet(req, resp); -// resp.setContentType("text/html"); - String name=req.getParameter("name"); - System.out.println(name); - resp.setContentType("application/json; charset=UTF-8"); - PrintWriter out=resp.getWriter(); -// out.print("fjdkfjdk"); -// out.println("

      abc

      "); - JSONObject jsonObject=new JSONObject(); - JSONArray jsonArray=new JSONArray(); - jsonArray.put(jsonObject); - jsonArray.put(jsonObject); - try{ - jsonObject.put("name","mafulong"); - jsonObject.put("age",18); - }catch (Exception e){ - e.printStackTrace(); - } -// out.print(jsonObject.toString()); - out.print(jsonArray.toString()); - - } -``` - -## 前端处理后端接收得数据 -```javascript - xmlhttp.onreadystatechange=function() - { - if (xmlhttp.readyState==4 && xmlhttp.status==200) - { - // document.getElementById("myDiv").innerHTML=xmlhttp.responseText; - alert("success "); - var data=xmlhttp.responseText; - var djson=JSON.parse(data); - var str=""; - for(var i=0;i"; - str+=djson[i].age+"
      "; - } - document.getElementById("myDiv").innerHTML=str; - } - } -``` \ No newline at end of file diff --git "a/_posts/Tech/FrontEnd/2018-06-20-css\346\265\256\345\212\250.md" "b/_posts/Tech/FrontEnd/2018-06-20-css\346\265\256\345\212\250.md" deleted file mode 100644 index 3dd40c8e32..0000000000 --- "a/_posts/Tech/FrontEnd/2018-06-20-css\346\265\256\345\212\250.md" +++ /dev/null @@ -1,12 +0,0 @@ ---- -layout: post -category: FrontEnd -title: css浮动 -tags: FrontEnd ---- - - -[参考链接](https://www.cnblogs.com/smyhvae/p/7297736.html) - -[参考链接2](https://blog.csdn.net/u010297791/article/details/76718589) - diff --git "a/_posts/Tech/FrontEnd/2020-02-01-jsp\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2020-02-01-jsp\347\254\224\350\256\260.md" new file mode 100644 index 0000000000..97f683401f --- /dev/null +++ "b/_posts/Tech/FrontEnd/2020-02-01-jsp\347\254\224\350\256\260.md" @@ -0,0 +1,134 @@ +--- +layout: post +category: FrontEnd +title: jsp笔记 +tags: FrontEnd +--- + +## jsp笔记 + +JSP(Java Server Page)是一种动态网页技术标准,在HTML中嵌入Java程序片段(Scriptlet)和JSP标签(tag)所构成。 + + + +执行逻辑 + +```scala +服务端收到客户端的请求 +if(请求HTML/XML页面){ + 直接将页面相应代码发给客户端 +} +else if(请求JSP页面){ + if(页面第一次被请求 || 页面被修改过){ + 1.JSP文件(.jsp)转换成servlet文件(.java) + 2.编译生成字节码文件(.class) + 3.执行字节码文件,并将执行结果以HTML的形式返回给客户端。 + } + else{ + //页面之前已执行过且未被修改 + 直接执行已生成的字节码文件(.class),并将执行结果以HTML的形式返回给客户端。 + } +} +``` + +## JSP基本元素 + +- 声明:`<%! int a; %>`,声明页面全局变量。 +- 表达式:`<%=...%>`,将结果转成字符串形式输出到页面中 +- 代码片段(Scriptlet):`<% ... %>`,java代码片段,多行没关系的。注意System.out.Print输出是控制台和html展示无关。 +- JSP指令(静态):`<%@ xxx %>`格式 + `<%@ page 属性1="xx" 属性2="xx"%>`,设置页面属性 + `<%@ include file="文件名"%>`,将文件插入到当前页面中(静态插入) +- JSP动作(动态):``格式 + ``,将文件的执行结果插入到当前页面(动态插入) + ``,停止当前页面,转向指定HTML/JSP文件的页面(地址栏不变) + ``,传递参数,作为include/forward的子标签使用,在其他页面中通过request.getParameter(“变量名”)接收参数。 + +## JSP内置对象 + +JSP内置对象无需创建就可以直接使用,具体有以下几种: + +- 输出输入对象:request对象、response对象、out对象 +- 通信控制对象:pageContext对象、session对象、application对象 +- Servlet对象:page对象、config对象 +- 错误处理对象:exception对象 + +### JSP内置对象作用域 + +| 作用域 | 说明 | +| :---------: | :----------------------------------------------------------: | +| page | 只能在当前页面中访问 | +| request | 整个请求周期,从发起请求到返回响应。(期间可能forward跳转了多个页面) | +| session | 整个当前会话,从打开浏览器开始,到关闭浏览器都算一个session | +| application | 整个应用期,从服务器启动应用,到应用结束(对象可被所有用户共享) | + +### request对象 + +- 当客户端通过HTTP请求JSP页面时,服务器会自动创建request对象,并将请求信息封装进去。处理完请求后,request对象即自动销毁。 +- 常用方法:(注意区分参数和属性) + `String getParameter(String name)`:获取客户端传送给服务器的参数值(如form表单中的内容) + `void setAttribute(String name,Object obj)`:服务端自己设置request属性值(便于在页面间传数据) + `Object getAttribute(String name)`:获取相应属性值(返回Obj类型,要进行强转) +- 传参数(parameter)的方式:客户端通过form表单(可设置get/post形式)、服务端通过include/forward动作(get形式)。但一般服务端页面间通过属性(Attribute)传信息较常用。 +- request还可获得客户端的IP地址、协议等信息。 + +### response对象 + +- 服务器向客户端发数据时,自动创建response对象。response只负责设置响应的头部信息,响应体信息由其他对象设置。 +- 重定向网页:`response.sendRedirect("xxx")`,与forward的区别:forward仅能站内跳转,重定向可跳转到任何网站;forward带request信息跳转,重定向不带request跳转。 +- 页面定时刷新/跳转: + `response.setHeader("refresh","5")`,每隔5s页面自动刷新一次。 + `response.setHeader("refresh","5;url=www.baidu,com")`,5s后自动跳转到百度页面。 + +### session对象 + +- 会话(session)的含义:从用户第一次进入网站,到浏览器关闭期间,称为一次会话。用户第一次进入网站,服务器会生成session id标识不同用户,并将相关信息存储在浏览器,因此第二次访问(不关浏览器)还可识别出是同一用户。 +- session对象可用来传递信息、获取会话属性。 + +### application对象 + +每个Web程序一个application,只要不关闭服务器,application对象即一直存在。用于保存应用程序中的公有数据(所有的用户共享)。可用来记录访问网站的总人数。 + + + +## JSTL + +jsp标准标签库(Jsp Standarded Tap Library),使用标签取代jsp页面上的代码 + +常用的就是下面两个标签 + +``和`` + +用之前需要先引入。 + +`<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>` + +## EL表达式 + +### EL 语法和使用 + +EL(Expression Language) 是为了使 JSP 写起来更加简单。表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法,让 Jsp 的代码更 加简化。 + + 语法:`${expression}` + + 备注: + +1. el 表达式一般操作的是域对象中的数据,操作不了局部变量。 +2. JSP中的四个域对象: + - **pageContext**(本页面) + - **request**(一次请求) + - **session**(一次会话) + - **application**(整个应用程序) +3. EL 默认的查找方式为**从小到大**查找,找到即可。当域对象全找完了还未找到则返回空字符串 ””。 + + + +还支持List遍历等。以下就是遍历list这个List变量。 + +```php +${empty list} +``` + +## 参考 + +- https://renli1024.github.io/2018/02/13/JSP/ \ No newline at end of file diff --git "a/_posts/Tech/FrontEnd/2020-11-08-leetcode\347\224\237\346\210\220\345\215\232\345\256\242\350\204\232\346\234\254.md" "b/_posts/Tech/FrontEnd/2020-11-08-leetcode\347\224\237\346\210\220\345\215\232\345\256\242\350\204\232\346\234\254.md" deleted file mode 100644 index 45f344b8a2..0000000000 --- "a/_posts/Tech/FrontEnd/2020-11-08-leetcode\347\224\237\346\210\220\345\215\232\345\256\242\350\204\232\346\234\254.md" +++ /dev/null @@ -1,115 +0,0 @@ ---- -layout: post -category: FrontEnd -title: leetcode生成博客脚本 -tags: FrontEnd ---- - -## leetcode生成博客脚本 - - -通过leetcode网站下运行,爬取标题、题目,生成基于jekyll的博客创建命令,并自动复制到剪贴板,在shell运行后便可以生成博客文件。 - -chrome控制台下开source即可运行 - -```javascript - -let date = new Date() -var dateStr = dateFormat("YYYY-mm-dd-", date) - -// let date = new Date() -// var dateStr = dateFormat("YYYY-mm-dd", date) - -// var title = document.getElementsByClassName("css-v3d350")[0].innerHTML -// console.log("title:", title) -// // var clipBoardContent =dateStr + title + ".md" -// // console.log(clipBoardContent) -// // window.copy(clipBoardContent); - -function dateFormat(fmt, date) { - let ret; - const opt = { - "Y+": date.getFullYear().toString(), // 年 - "m+": (date.getMonth() + 1).toString(), // 月 - "d+": date.getDate().toString(), // 日 - "H+": date.getHours().toString(), // 时 - "M+": date.getMinutes().toString(), // 分 - "S+": date.getSeconds().toString() // 秒 - // 有其他格式化字符需求可以继续添加,必须转化成字符串 - }; - for (let k in opt) { - ret = new RegExp("(" + k + ")").exec(fmt); - if (ret) { - fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0"))) - }; - }; - return fmt; -} - - - -var href = window.location.href; - - -var title = document.getElementsByClassName("css-v3d350")[0].innerHTML -// console.log("title:", title) - -var content = document.getElementsByClassName("content__u3I1 question-content__JfgR")[0] -// console.log(content) - -console.log(content.innerHTML) -String.prototype.myReplace=function(f,e){//吧f替换成e - var reg=new RegExp(f,"g"); //创建正则RegExp对象 - return this.replace(reg,e); -} -html = content.innerHTML -var regex = /(<([^>]+)>)/ig -// html = html.myReplace("
      ", "
      '''\n")
      -// html = html.myReplace("
      ", "
      '''\n") -html = html.myReplace("<", "<"); - -html = html.myReplace(">", ">"); -html = html.myReplace(" ", ""); -html = html.replace(regex, ""); -console.log(html) -// let date = new Date() -// var dateStr = dateFormat("YYYY-mm-dd", date) - -// var code = document.getElementsByClassName("CodeMirror-code")[0].innerHTML -// console.log(code) -// code = code.replace(regex,""); -// console.log(code) - -var data =`--- -layout: post -category: leetcode -title: `+title+` -tags: leetcode ---- - -## title -[problem link](`+href+`) -`+html+` - -## solution - -\`\`\`python - -\`\`\` -` - -console.log(data) - - -var fileName = dateStr + title + ".md"; -var path = "/Users/mafulong/mafulong.github.io/_posts/Algorithms/leetcode/"+fileName; -// console.log(path) - -pathStr = "\""+path+"\"" -var shell = "touch "+pathStr +";" -+ "echo \'"+data+"\' >"+pathStr+" ; code "+pathStr; - -// ```; echo \'``` + ```fdfd``` + ```> ```+path + ```; cat ```+path; -// console.log(shell) -window.copy(shell); -``` \ No newline at end of file diff --git "a/_posts/Tech/FrontEnd/2021-09-10-\345\211\215\347\253\257\345\274\200\345\217\221\345\267\245\345\205\267.md" "b/_posts/Tech/FrontEnd/2021-09-10-\345\211\215\347\253\257\345\274\200\345\217\221\345\267\245\345\205\267.md" new file mode 100644 index 0000000000..f9658ae3b2 --- /dev/null +++ "b/_posts/Tech/FrontEnd/2021-09-10-\345\211\215\347\253\257\345\274\200\345\217\221\345\267\245\345\205\267.md" @@ -0,0 +1,37 @@ +--- +layout: post +category: FrontEnd +title: 前端开发工具 +tags: FrontEnd +--- + +# 前端开发工具 + +# vscode + +## 必备插件 + +#### Auto Close Tag + +自动闭合 HTML/XML 标签 + +### Auto Rename Tag + +自动重命名 HTML/XML 标签 + +### Bracket Pair Colorizer + +用于着色匹配括号,让你的代码分层更清晰 + +### Code Runner + +运行代码片段或多种语言的代码文件 + +### Code Spell Checker + +源代码拼写检查器,提示代码中单词拼写错误 + +### CSS Peek + +允许查看css,并从HTML文件定位到css文件,文件定义跳转 + diff --git "a/_posts/Tech/FrontEnd/2022-07-16-NodeJS\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2022-07-16-NodeJS\347\254\224\350\256\260.md" new file mode 100644 index 0000000000..e047795e46 --- /dev/null +++ "b/_posts/Tech/FrontEnd/2022-07-16-NodeJS\347\254\224\350\256\260.md" @@ -0,0 +1,362 @@ +--- +layout: post +category: FrontEnd +title: NodeJS笔记 +tags: FrontEnd +--- + +# NodeJS笔记 + +> [Node.js介绍](https://web.qianguyihao.com/11-Node.js/01-Node.js%E4%BB%8B%E7%BB%8D.html#todo) + +[Node.js](https://nodejs.org/zh-cn/) 是一个基于 **Chrome V8 引擎**的 JavaScript 运行环境。Node.js 使用了一个**事件驱动**、**非阻塞式 I/O**的模型,使其轻量又高效。Node.js 的包管理工具 npm 是全球最大的开源库生态系统。 + +Node.js 不是一门语言,也不是 JavaScript 的框架,也不是像Nginx一样的Web服务器 ,**Node.js 是 JavaScript 在服务器端的运行环境(平台)**。 + + + +在 Node.js 里运行 JavaScript,跟在 Chrome 里运行 JavaScript 有什么不同? + +二者采用的是同样的 JS 引擎。在 Node.js 里写 JS,和在前端写 JS,几乎没有不同。在写法上的区别在于:Node.js 没有浏览器、页面标签相关的 API,但是新增了一些 Node.js 相关的 API。通俗来说,对于开发者而言,在前端写 JS 是用于控制浏览器;而 Node.js 环境写 JS 可以控制整个计算机。 + + + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202212242058356.png) + + + +历史回顾: + +(1)一开始,页面很简单,html 是后端渲染的(比如PHP、ASP、JSP等方式)。后端发现页面中的 js 好麻烦(虽然简单,但是坑多),于是让公司招聘专门写 js 的人,简称「前端切图仔」。 + +(2)随着 Node.js 和前端 MVC 的兴起,以及前端越来越复杂,慢慢演变成了「前后端分离」。 + +(3)前端的 SPA 应用流行之后,发现 SEO 问题很大,而且首屏渲染速度很慢,但是自己选的路再难走也要走下去,于是用 Node.js 在服务端渲染被看成是一条出路。 + +(4)以前在一起的时候,是后端做部分前端的工作;现在在一起的时候,是前端做部分后端的工作。 + + + +还可以做客户端软件 + +Electron 框架就是基于 Node.js 的,可以用来开发客户端软件。 + +Electron 原名为 Atom Shell,是由 GitHub 开发的一个开源框架。Electron 以 Node.js 作为运行时(runtime),以 chromium 作为渲染引擎,使开发者可以使用 JS 这种前端技术栈开来发跨平台的桌面GUI应用程序。 + +有一点你可能会感到惊讶:程序员们都在用的代码编辑器 VS Code 软件, 就是基于 Electron 框架来开发的。其他使用 Electron 进行开发的知名应用还有:Skype、GitHub Desktop、Slack、WhatsApp等。 + + + +## Node.js 的特点 + +- 异步、非阻塞 IO 模型 +- 事件循环 +- 单线程 +- 总结:轻量和高效 + +Node.js 的性能和效率非常高。 + +传统的 Java 语言是一个请求开启一个线程,当请求处理完毕后就关闭这个线程。而 Node.js 则完全没有采用这种模型,它本质上就是一个单线程。 + +你可能会疑问:一个线程如何服务于大量的请求、如何处理高并发的呢?这是因为,Node.js 采用的是异步的、非阻塞的模型。 + +这里所谓的“单线程”,指的是 Node 的主线程只有一个。为了确保主线程不被阻塞,主线程是用于接收客户端请求。但不会处理具体的任务。而 Node 的背后还有一个线程池,线程池会处理长时间运行的任务(比如 IO 操作、网络操作)。线程池里的任务是通过队列和事件循环的机制来执行。 + + + +node默认的是单线程,一个nodejs应用无法利用多核资源,能够采用事件驱动和异步“I/O”的方式,实现一个单线程、高并发的运行时环境。 + +nodejs**实际上只有js执行是单线程的**,I/O显然是其他线程。 + +Node.js没有在运行Javascript时创建新线程的能力。 + +js执行线程是单线程的,只要将所需的I/O传递给libuv,自己马上回来做别的事情,然后libuv在指定的时间回调即可。 + + + + + +### 使用 Node.js 时的劣势 + +- 程序运行不稳定,可能会出现服务不可用的情况 +- 程序运行效率较低,每秒的请求数维持在一个较低的水平 +- 前端同学对服务器端的技术不太熟悉。 + +## Hello world + +```js +var http = require('http'); + +http.createServer(function (request, response) { + + // 发送 HTTP 头部 + // HTTP 状态值: 200 : OK + // 内容类型: text/plain + response.writeHead(200, {'Content-Type': 'text/plain'}); + + // 发送响应数据 "Hello World" + response.end('Hello World\n'); +}).listen(8888); + +// 终端打印如下信息 +console.log('Server running at http://127.0.0.1:8888/'); +``` + +## npm使用 + +```shell +npm -v +npm install express # 本地,项目的node_modules目录,会自动创建 +npm install express -g # 全局安装 +npm list -g # 看全局模块列表 +npm list grunt # 看版本号 +npm uninstall express # 卸载模块 +npm update express +npm search express + +# 创建模块 +npm init # 会创建package.json 需要手动输入很多东西,auth, version啥的 +npm init -y # 可以用这个替代,创建default package.json +npm publish # 发布到资源库 +``` + +使用package.json描述POM + +### 版本号 + +使用NPM下载和发布代码时都会接触到版本号。NPM使用语义版本号来管理代码,这里简单介绍一下。 + +语义版本号分为X.Y.Z三位,分别代表主版本号、次版本号和补丁版本号。当代码变更时,版本号按以下原则更新。 + +- 如果只是修复bug,需要更新Z位。 +- 如果是新增了功能,但是向下兼容,需要更新Y位。 +- 如果有大变动,向下不兼容,需要更新X位。 + +版本号有了这个保证后,在申明第三方包依赖时,除了可依赖于一个固定版本号外,还可依赖于某个范围的版本号。例如"argv": "0.0.x"表示依赖于0.0.x系列的最新版argv。 + +## 回调函数 + +Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。 + +通过回调来实现异步编程。回调函数一般作为函数的最后一个参数出现 + + + +非阻塞代码实例 + +```js +var fs = require("fs"); + +fs.readFile('input.txt', function (err, data) { + if (err) return console.error(err); + console.log(data.toString()); +}); + +console.log("程序执行结束!"); +``` + +## 事件循环 + +类似非阻塞IO, 观察者模式。 + +Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例: + +```js +// 引入 events 模块 +var events = require('events'); +// 创建 eventEmitter 对象 +var eventEmitter = new events.EventEmitter(); + +// 创建事件处理程序 +var connectHandler = function connected() { + console.log('连接成功。'); + + // 触发 data_received 事件 + eventEmitter.emit('data_received'); +} + +// 绑定 connection 事件处理程序 +eventEmitter.on('connection', connectHandler); + +// 使用匿名函数绑定 data_received 事件 +eventEmitter.on('data_received', function(){ + console.log('数据接收成功。'); +}); + +// 触发 connection 事件 +eventEmitter.emit('connection'); + +console.log("程序执行完毕。"); +``` + +emit是触发 + +on是绑定对应处理 + + + +在 Node 应用程序中,执行异步操作的函数将回调函数作为最后一个参数, 回调函数接收错误对象作为第一个参数。 + + + +## EventEmitter + +Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。 + +这些产生事件的对象都是 events.EventEmitter 的实例。 + +events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。 + + + + + +EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件监听器。 + +当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。 + +```js +//event.js 文件 +var events = require('events'); +var emitter = new events.EventEmitter(); +emitter.on('someEvent', function(arg1, arg2) { + console.log('listener1', arg1, arg2); +}); +emitter.on('someEvent', function(arg1, arg2) { + console.log('listener2', arg1, arg2); +}); +emitter.emit('someEvent', 'arg1 参数', 'arg2 参数'); +``` + +大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。 + + + +## Stream + +Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)。 + +Node.js,Stream 有四种流类型: + +- **Readable** - 可读操作。 +- **Writable** - 可写操作。 +- **Duplex** - 可读可写操作. +- **Transform** - 操作被写入数据,然后读出结果。 + +所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有: + +- **data** - 当有数据可读时触发。 +- **end** - 没有更多的数据可读时触发。 +- **error** - 在接收和写入过程中发生错误时触发。 +- **finish** - 所有数据已被写入到底层系统时触发。 + +从流中读取数据 + +```js +var fs = require("fs"); +var data = ''; + +// 创建可读流 +var readerStream = fs.createReadStream('input.txt'); + +// 设置编码为 utf8。 +readerStream.setEncoding('UTF8'); + +// 处理流事件 --> data, end, and error +readerStream.on('data', function(chunk) { + data += chunk; +}); + +readerStream.on('end',function(){ + console.log(data); +}); + +readerStream.on('error', function(err){ + console.log(err.stack); +}); + +console.log("程序执行完毕"); +``` + + + +写入流 + +```js +var fs = require("fs"); +var data = '菜鸟教程官网地址:www.runoob.com'; + +// 创建一个可以写入的流,写入到文件 output.txt 中 +var writerStream = fs.createWriteStream('output.txt'); + +// 使用 utf8 编码写入数据 +writerStream.write(data,'UTF8'); + +// 标记文件末尾 +writerStream.end(); + +// 处理流事件 --> finish、error +writerStream.on('finish', function() { + console.log("写入完成。"); +}); + +writerStream.on('error', function(err){ + console.log(err.stack); +}); + +console.log("程序执行完毕"); +``` + + + +管道流 + +可一对多 链式流 + +```js +readerStream.pipe(writerStream); + +fs.createReadStream('input.txt') + .pipe(zlib.createGzip()) + .pipe(fs.createWriteStream('input.txt.gz')); +``` + + + +## 模块系统 + +## 引入模块 + +在 Node.js 中,引入一个模块非常简单,如下我们创建一个 **main.js** 文件并引入 hello 模块,代码如下: + +```js +var hello = require('./hello'); +hello.world(); +``` + +以上实例中,代码 require('./hello') 引入了当前目录下的 hello.js 文件(./ 为当前目录,node.js 默认后缀为 js)。 + +Node.js 提供了 exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。 + +接下来我们就来创建 hello.js 文件,代码如下: + +```js +exports.world = function() { + console.log('Hello World'); +} +``` + +在以上示例中,hello.js 通过 exports 对象把 world 作为模块的访问接口,在 main.js 中通过 require('./hello') 加载这个模块,然后就可以直接访 问 hello.js 中 exports 对象的成员函数了。 + + + +require方法接受以下几种参数的传递: + +- http、fs、path等,原生模块。 +- ./mod或../mod,相对路径的文件模块。 +- /pathtomodule/mod,绝对路径的文件模块。 +- mod,非原生模块的文件模块。 + +## 参考 + +- [Node.js](https://www.runoob.com/nodejs/nodejs-router.html) diff --git "a/_posts/Tech/FrontEnd/2022-08-26-chrome\350\260\203\350\257\225.md" "b/_posts/Tech/FrontEnd/2022-08-26-chrome\350\260\203\350\257\225.md" new file mode 100644 index 0000000000..0f71c76863 --- /dev/null +++ "b/_posts/Tech/FrontEnd/2022-08-26-chrome\350\260\203\350\257\225.md" @@ -0,0 +1,54 @@ +--- +layout: post +category: FrontEnd +title: chrome调试 +tags: FrontEnd +--- + +## chrome调试 + + + +## 控制台打印对象 + +console.log + +console.table: 如果你要打印的变量是一个数组,每一个元素都是一个对象。我建议你使用`console.table`来打印,其表格化的呈现更加美观易读。 + + + +## 选择元素 + +**\$ 和 \$\$** + +如果你在 console 下没有任何库使用`$`和`$$`,那么你可以使用它们分别作为`document.querySelector()` 和 `document.querySelectorAll()`的快捷键。 + +**$0** + +如果你想引用某个 DOM 元素,使用`$0`。`$0`指向你当前在 Element 中选中的元素。如果指定了`$0`,`$1`指向之前选中的元素。以此类推,直到`$4`都可以使用。 + +## **getEventListeners()** + +`getEventListeners(domElement)` 返回在 DOM 元素上注册的所有的事件 + + + +## 函数断点**debug(fn)** + +如果你想在点击按钮后的执行过程中暂停,你可以使用`debug`函数。`debug(fn)`接收一个函数作为参数,当每次该函数被调用时,Debugger 就会在该函数的第一行中断执行。 + +想象一下你要 debug 一个按钮的问题,但是你不知道这个按钮对应的事件函数在代码中什么位置。除了去大量的源代码中慢慢寻找之外,还有一个巧妙的方法。使用`getEventListeners`函数,然后将`debug`方法注入进去。这样,当你点击按钮的时候,就会在该函数的第一行停下来。 + + + +## 监听dom元素断点 + +可以找到改dom元素属性的js位置。 + +elements上右键break on, 选attribute. + + + +## 参考 + +[参考](https://blog.fundebug.com/2018/08/22/art-of-debugging-with-chrome-devtools/) diff --git "a/_posts/Tech/FrontEnd/2022-12-01-typescript\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2022-12-01-typescript\347\254\224\350\256\260.md" new file mode 100644 index 0000000000..5403626621 --- /dev/null +++ "b/_posts/Tech/FrontEnd/2022-12-01-typescript\347\254\224\350\256\260.md" @@ -0,0 +1,975 @@ +--- +layout: post +category: FrontEnd +title: typescript笔记 +tags: FrontEnd +recent_update: true +--- + +# typescript笔记 + +## JavaScript 与 TypeScript 的区别 + +TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。 + + + +TypeScript 是一种给 JavaScript 添加特性的语言扩展。增加的功能包括: + +- 类型批注和编译时类型检查 +- 类型推断 +- 类型擦除 +- 接口 +- 枚举 +- Mixin +- 泛型编程 +- 名字空间 +- 元组 +- Await + + + +支持es6标准。 + + + +从 TypeScript 的名字就可以看出来,「类型」是其最核心的特性。 + +我们知道,JavaScript 是一门非常灵活的编程语言: + +- 它没有类型约束,一个变量可能初始化时是字符串,过一会儿又被赋值为数字。 +- 由于隐式类型转换的存在,有的变量的类型很难在运行前就确定。 +- 基于原型的面向对象编程,使得原型上的属性或方法可以在运行时被修改。 +- 函数是 JavaScript 中的一等公民[[2\]](https://ts.xcatliu.com/introduction/what-is-typescript.html#link-2),可以赋值给变量,也可以当作参数或返回值。 + + + + + +**TypeScript 是静态类型** + +TypeScript 在运行前需要先编译为 JavaScript,而在编译阶段就会进行类型检查,所以 **TypeScript 是静态类型** + + + +什么是 TypeScript? + +- TypeScript 是添加了类型系统的 JavaScript,适用于任何规模的项目。 +- TypeScript 是一门静态类型、弱类型的语言。 +- TypeScript 是完全兼容 JavaScript 的,它不会修改 JavaScript 运行时的特性。 +- TypeScript 可以编译为 JavaScript,然后运行在浏览器、Node.js 等任何能运行 JavaScript 的环境中。 +- TypeScript 拥有很多编译选项,类型检查的严格程度由你决定。 +- TypeScript 可以和 JavaScript 共存,这意味着 JavaScript 项目能够渐进式的迁移到 TypeScript。 +- TypeScript 增强了编辑器(IDE)的功能,提供了代码补全、接口提示、跳转到定义、代码重构等能力。 +- TypeScript 拥有活跃的社区,大多数常用的第三方库都提供了类型声明。 +- TypeScript 与标准同步发展,符合最新的 ECMAScript 标准(stage 3)。 + +## 安装 + +如果你的本地环境已经安装了 npm 工具,可以使用以下命令来安装。 + +使用国内镜像: + +``` +npm config set registry https://registry.npmmirror.com +``` + +安装 typescript: + +``` +npm install -g typescript +``` + +安装完成后我们可以使用 **tsc** 命令来执行 TypeScript 的相关代码,以下是查看版本号: + +``` +$ tsc -v +Version 3.2.2 +``` + + + +编译一个 TypeScript 文件很简单: + +```bash +tsc hello.ts +``` + +我们约定使用 TypeScript 编写的文件以 `.ts` 为后缀,用 TypeScript 编写 React 时,以 `.tsx` 为后缀。 + + + +为了vscode可以运行ts. 需要下面安装 + +```scala +npm install -g ts-node +``` + + + +## helloworld + +```typescript +const hello : string = "Hello World!" +console.log(hello) +``` + +# 基础 + +## 原始数据类型 + +布尔值是最基础的数据类型,在 TypeScript 中,使用 `boolean` 定义布尔值类型: + +```ts +let isDone: boolean = false; + +// 编译通过 +// 后面约定,未强调编译错误的代码片段,默认为编译通过 +``` + +注意,使用构造函数 `Boolean` 创造的对象**不是**布尔值: + +```ts +let createdByNewBoolean: boolean = new Boolean(1); +``` + + + +使用 `number` 定义数值类型: + +```ts +let decLiteral: number = 6; +``` + + + +使用 `string` 定义字符串类型: + +```ts +let myName: string = 'Tom'; +``` + +```ts +// 模板字符串 +let sentence: string = `Hello, my name is ${myName}. +I'll be ${myAge + 1} years old next month.`; +``` + + + +JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 `void` 表示没有任何返回值的函数: + +```ts +function alertName(): void { + alert('My name is Tom'); +} +``` + +声明一个 `void` 类型的变量没有什么用,因为你只能将它赋值为 `undefined` 和 `null`(只在 --strictNullChecks 未指定时): + +```ts +let unusable: void = undefined; +``` + + + +在 TypeScript 中,可以使用 `null` 和 `undefined` 来定义这两个原始数据类型: + +```ts +let u: undefined = undefined; +let n: null = null; +``` + +与 `void` 的区别是,`undefined` 和 `null` 是所有类型的子类型。也就是说 `undefined` 类型的变量,可以赋值给 `number` 类型的变量: + +```ts +// 这样不会报错 +let num: number = undefined; +``` + +而 `void` 类型的变量不能赋值给 `number` 类型的变量: + + + +## 任意值 + + `any` 类型,则允许被赋值为任意类型。 + +```ts +let myFavoriteNumber: any = 'seven'; +myFavoriteNumber = 7; +``` + + + +在任意值上访问任何属性都是允许的: + +```ts +let anyThing: any = 'hello'; +console.log(anyThing.myName); +console.log(anyThing.myName.firstName); +``` + +可以认为,**声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值**。 + + + +**变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型**: + +```ts +let something; +``` + + + +## 类型推论 + +以下代码虽然没有指定类型,但是会在编译的时候报错: + +```ts +let myFavoriteNumber = 'seven'; +myFavoriteNumber = 7; + +// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'. +``` + +事实上,它等价于: + +```ts +let myFavoriteNumber: string = 'seven'; +myFavoriteNumber = 7; + +// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'. +``` + +TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论。 + +**如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 `any` 类型而完全不被类型检查**: + +```ts +let myFavoriteNumber; +myFavoriteNumber = 'seven'; +myFavoriteNumber = 7; +``` + + + +## 联合类型 + +联合类型(Union Types)表示取值可以为多种类型中的一种。 + +```ts +let myFavoriteNumber: string | number; +myFavoriteNumber = 'seven'; +myFavoriteNumber = 7; +``` + + + +当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们**只能访问此联合类型的所有类型里共有的属性或方法** + + + +联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型: + +```ts +let myFavoriteNumber: string | number; +myFavoriteNumber = 'seven'; +``` + + + +## 接口 + +在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。 + + + +```ts +interface Person { + name: string; + age: number; +} + +let tom: Person = { + name: 'Tom', + age: 25 +}; +``` + + + +- 定义的变量比接口少了一些属性是不允许的。会编译报错 +- 多一些属性也是不允许的。 可见,**赋值的时候,变量的形状必须和接口的形状保持一致**。 + + + +可选 + +- 有时我们希望不要完全匹配一个形状,那么可以用可选属性. 可选属性的含义是该属性可以不存在。这时**仍然不允许添加未定义的属性**: + + ```ts + interface Person { + age?: number; + } + + ``` + + + +任意类型 + +- 有时候我们希望一个接口允许有任意的属性,可以使用如下方式。 使用 `[propName: string]` 定义了任意属性取 `string` 类型的值。需要注意的是,**一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集**。 + +```ts +interface Person { + name: string; + age?: number; + [propName: string]: any; +} +``` + +- 一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以在任意属性中使用联合类型 + + + +只读属性 + +- 有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 `readonly` 定义只读属性。 **注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候**: + +```ts +interface Person { + readonly id: number; +} +``` + +基于interface声明新变量的技巧 + +```scala +p = Person{ + id: 1, + name: "name" +} + +以下都是 可以的,会根据id,name这些fieldname匹配对应的值,同时支持别名,比如id1是id的别名。 +const {id} = p +console.log(id) +const {name} = p +const {id, name} = p +const {id: id1} = p +console.log(id1) +``` + + + + + +## 数组的类型 + +最简单的方法是使用「类型 + 方括号」来表示数组: + +```ts +let fibonacci: number[] = [1, 1, 2, 3, 5]; +``` + +数组的项中**不允许**出现其他的类型 + + + +我们也可以使用数组泛型(Array Generic) `Array` 来表示数组: + +```ts +let fibonacci: Array = [1, 1, 2, 3, 5]; +``` + + + +## 类数组 + +类数组(Array-like Object)不是数组类型 + +```ts +function sum() { + let args: { + [index: number]: number; + length: number; + callee: Function; + } = arguments; +} +``` + +在这个例子中,我们除了约束当索引的类型是数字时,值的类型必须是数字之外,也约束了它还有 `length` 和 `callee` 两个属性。 + + + +## 函数的类型 + +```ts +function sum(x: number, y: number): number { + return x + y; +} +``` + +注意,**输入多余的(或者少于要求的)参数,是不被允许的**: + + + +### 函数表达式 + +如果要我们现在写一个对函数表达式(Function Expression)的定义,可能会写成这样: + +```ts +let mySum = function (x: number, y: number): number { + return x + y; +}; +``` + +这是可以通过编译的,不过事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 `mySum`,是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给 `mySum` 添加类型,则应该是这样: + +```ts +let mySum: (x: number, y: number) => number = function (x: number, y: number): number { + return x + y; +}; +``` + +注意不要混淆了 TypeScript 中的 `=>` 和 ES6 中的 `=>`。 + +在 TypeScript 的类型定义中,`=>` 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。 + +在 ES6 中,`=>` 叫做箭头函数,应用十分广泛,可以参考 [ES6 中的箭头函数](http://es6.ruanyifeng.com/#docs/function#箭头函数)。 + + + +### 用接口定义函数 + +我们也可以使用接口的方式来定义一个函数需要符合的形状: + +```ts +interface SearchFunc { + (source: string, subString: string): boolean; +} + +let mySearch: SearchFunc; +mySearch = function(source: string, subString: string) { + return source.search(subString) !== -1; +} +``` + +采用函数表达式`|`接口定义函数的方式时,对等号左侧进行类型限制,可以保证以后对函数名赋值时保证参数个数、参数类型、返回值类型不变。 + + + + + +### 可选参数和默认值、剩余参数 + +```ts +function buildName(firstName: string, lastName?: string) {} + +function buildName(firstName: string, lastName: string = 'Cat') { + return firstName + ' ' + lastName; +} + +function push(array, ...items) { + items.forEach(function(item) { + array.push(item); + }); +} +``` + +需要注意的是,可选参数必须接在必需参数后面。换句话说,**可选参数后面不允许再出现必需参数了** + + + + + +### 重载 + +联合类型**缺点,就是不能够精确的表达,输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串。** + + + +以下重载可避免。支持重载。 + +```ts +function reverse(x: number): number; +function reverse(x: string): string; +function reverse(x: number | string): number | string | void { + if (typeof x === 'number') { + return Number(x.toString().split('').reverse().join('')); + } else if (typeof x === 'string') { + return x.split('').reverse().join(''); + } +} +``` + + + +### 类型断言 + +类型断言(Type Assertion)可以用来手动指定一个值的类型。 + + + +```ts +值 as 类型 + +animal as Fish +``` + + + +用途 + +- 联合类型可以被断言为其中一个类型 +- 父类可以被断言为子类 +- 任何类型都可以被断言为 any +- any 可以被断言为任何类型 + + + +- 若 `A` 兼容 `B`,那么 `A` 能够被断言为 `B`,`B` 也能被断言为 `A`。 + +- 类型断言只会影响 TypeScript 编译时的类型,类型断言语句在编译结果中会被删除。所以类型断言不是类型转换,它不会真的影响到变量的类型。只是让编译器正确地编译,骗过编译器。 + +## 声明文件 + +> [声明文件](https://ts.xcatliu.com/basics/declaration-files.html) + +参考引用即可。 + + + +- [`declare var`](https://ts.xcatliu.com/basics/declaration-files.html#declare-var) 声明全局变量 +- [`declare function`](https://ts.xcatliu.com/basics/declaration-files.html#declare-function) 声明全局方法 +- [`declare class`](https://ts.xcatliu.com/basics/declaration-files.html#declare-class) 声明全局类 +- [`declare enum`](https://ts.xcatliu.com/basics/declaration-files.html#declare-enum) 声明全局枚举类型 +- [`declare namespace`](https://ts.xcatliu.com/basics/declaration-files.html#declare-namespace) 声明(含有子属性的)全局对象 +- [`interface` 和 `type`](https://ts.xcatliu.com/basics/declaration-files.html#interface-和-type) 声明全局类型 +- [`export`](https://ts.xcatliu.com/basics/declaration-files.html#export) 导出变量 +- [`export namespace`](https://ts.xcatliu.com/basics/declaration-files.html#export-namespace) 导出(含有子属性的)对象 +- [`export default`](https://ts.xcatliu.com/basics/declaration-files.html#export-default) ES6 默认导出 +- [`export =`](https://ts.xcatliu.com/basics/declaration-files.html#export-1) commonjs 导出模块 +- [`export as namespace`](https://ts.xcatliu.com/basics/declaration-files.html#export-as-namespace) UMD 库声明全局变量 +- [`declare global`](https://ts.xcatliu.com/basics/declaration-files.html#declare-global) 扩展全局变量 +- [`declare module`](https://ts.xcatliu.com/basics/declaration-files.html#declare-module) 扩展模块 +- [`/// `](https://ts.xcatliu.com/basics/declaration-files.html#san-xie-xian-zhi-ling) 三斜线指令 + + + +# 进阶 + +## 类型别名 + +类型别名用来给一个类型起个新名字。 + + + +```ts +type Name = string; +type NameResolver = () => string; +type NameOrResolver = Name | NameResolver; +function getName(n: NameOrResolver): Name { + if (typeof n === 'string') { + return n; + } else { + return n(); + } +} +``` + +上例中,我们使用 `type` 创建类型别名。 + +类型别名常用于联合类型。 + + + +## 字符串字面量类型 + +字符串字面量类型用来约束取值只能是某几个字符串中的一个。 + + + +```ts +type EventNames = 'click' | 'scroll' | 'mousemove'; +function handleEvent(ele: Element, event: EventNames) { + // do something +} + +handleEvent(document.getElementById('hello'), 'scroll'); // 没问题 +handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为 'dblclick' + +// index.ts(7,47): error TS2345: Argument of type '"dblclick"' is not assignable to parameter of type 'EventNames'. +``` + +上例中,我们使用 `type` 定了一个字符串字面量类型 `EventNames`,它只能取三种字符串中的一种。 + +注意,**类型别名与字符串字面量类型都是使用 `type` 进行定义。** + + + +## 元组 + +数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。 + +元组起源于函数编程语言(如 F#),这些语言中会频繁使用元组。 + +定义一对值分别为 `string` 和 `number` 的元组: + +```ts +let tom: [string, number] = ['Tom', 25]; +``` + +当赋值或访问一个已知索引的元素时,会得到正确的类型: + +```ts +let tom: [string, number]; +tom[0] = 'Tom'; +tom[1] = 25; +``` + +也可以只赋值其中一项 + + + +当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型: + +```ts +let tom: [string, number]; +tom = ['Tom', 25]; +tom.push('male'); +tom.push(true); + +// Argument of type 'true' is not assignable to parameter of type 'string | number'. +``` + + + +## 枚举 + +枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。 + +枚举使用 `enum` 关键字来定义: + +```ts +enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; +``` + +枚举成员会被赋值为从 `0` 开始递增的数字,同时也会对枚举值到枚举名进行反向映射: + +```ts +enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; + +console.log(Days["Sun"] === 0); // true +console.log(Days["Mon"] === 1); // true +console.log(Days["Tue"] === 2); // true +console.log(Days["Sat"] === 6); // true + +console.log(Days[0] === "Sun"); // true +console.log(Days[1] === "Mon"); // true +console.log(Days[2] === "Tue"); // true +console.log(Days[6] === "Sat"); // true +``` + + + +我们也可以给枚举项手动赋值: + +```ts +enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat}; + +console.log(Days["Sun"] === 7); // true +console.log(Days["Mon"] === 1); // true +``` + +未手动赋值的枚举项会接着上一个枚举项递增。如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 是不会察觉到这一点的。所以使用的时候需要注意,最好不要出现这种覆盖的情况。 + + + +## 类 + +### 实例属性 + +ES6 中实例的属性只能通过构造函数中的 `this.xxx` 来定义,ES7 提案中可以直接在类里面定义: + +```js +class Animal { + name = 'Jack'; + + constructor() { + // ... + } +} + +let a = new Animal(); +console.log(a.name); // Jack +``` + +### 静态属性 + +ES7 提案中,可以使用 `static` 定义一个静态属性: + +```js +class Animal { + static num = 42; + + constructor() { + // ... + } +} + +console.log(Animal.num); // 42 +``` + + + +### public private 和 protected + +TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 `public`、`private` 和 `protected`。 + + 需要注意的是,TypeScript 编译之后的代码中,并没有限制 `private` 属性在外部的可访问性。 + + + +### 构造函数参数可带访问属性 + +修饰符和`readonly`还可以使用在构造函数参数中,等同于类中定义该属性同时给该属性赋值,使代码更简洁。 + +```ts +class Animal { + // public name: string; + public constructor(public name) { + // this.name = name; + } +} +``` + + + +注意如果 `readonly` 和其他访问修饰符同时存在的话,需要写在其后面。 + +```ts +class Animal { + // public readonly name; + public constructor(public readonly name) { + // this.name = name; + } +} +``` + + + +### 抽象类 + +`abstract` 用于定义抽象类和其中的抽象方法。 + +首先,抽象类是不允许被实例化的: + +```ts +abstract class Animal { + public name; + public constructor(name) { + this.name = name; + } + public abstract sayHi(); +} +``` + +其次,抽象类中的抽象方法必须被子类实现 + + + +## 类与接口 + +实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 `implements` 关键字来实现。这个特性大大提高了面向对象的灵活性。 + +```ts +interface Alarm { + alert(): void; +} + +class Door { +} + +class SecurityDoor extends Door implements Alarm { + alert() { + console.log('SecurityDoor alert'); + } +} +``` + +一个类可以实现多个接口: + +```ts +interface Alarm { + alert(): void; +} + +interface Light { + lightOn(): void; + lightOff(): void; +} + +class Car implements Alarm, Light { + alert() { + console.log('Car alert'); + } + lightOn() { + console.log('Car light on'); + } + lightOff() { + console.log('Car light off'); + } +} +``` + + + +接口与接口之间可以是继承关系: + +```ts +interface Alarm { + alert(): void; +} + +interface LightableAlarm extends Alarm { + lightOn(): void; + lightOff(): void; +} +``` + + + +常见的面向对象语言中,接口是不能继承类的,但是在 TypeScript 中却是可以的: + +```ts +class Point { + x: number; + y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } +} + +interface Point3d extends Point { + z: number; +} +``` + + + +## 泛型 + +泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。 + +泛型函数、泛型类、泛型接口、泛型类默认泛型 + +```ts +function createArray(length: number, value: T): Array { + let result: T[] = []; + for (let i = 0; i < length; i++) { + result[i] = value; + } + return result; +} + +createArray(3, 'x'); // ['x', 'x', 'x'] + +// or 自动推算 +createArray(3, 'x'); // ['x', 'x', 'x'] + +``` + + + +定义泛型的时候,可以一次定义多个类型参数: + +```ts +function swap(tuple: [T, U]): [U, T] { + return [tuple[1], tuple[0]]; +} + +swap([7, 'seven']); // ['seven', 7] +``` + + + +当然也可以使用含有泛型的接口来定义函数的形状: + +```ts +interface CreateArrayFunc { + (length: number, value: T): Array; +} +``` + + + +与泛型接口类似,泛型也可以用于类的类型定义中: + +```ts +class GenericNumber { + zeroValue: T; + add: (x: T, y: T) => T; +} + +let myGenericNumber = new GenericNumber(); +myGenericNumber.zeroValue = 0; +myGenericNumber.add = function(x, y) { return x + y; }; +``` + + + +在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。 + +```ts +function createArray(length: number, value: T): Array { + let result: T[] = []; + for (let i = 0; i < length; i++) { + result[i] = value; + } + return result; +} +``` + + + +## 声明合并 + +如果定义了两个相同名字的函数、接口或类,那么它们会合并成一个类型: + +函数合并就是函数类型里提到的**重载** + + + +接口中的属性在合并时会简单的合并到一个接口中: + +```ts +interface Alarm { + price: number; +} +interface Alarm { + weight: number; +} +``` + +相当于: + +```ts +interface Alarm { + price: number; + weight: number; +} +``` + +注意,**合并的属性的类型必须是唯一的** + + + + + +类的合并与接口的合并规则一致。 + +# 参考 + +- [TypeScript 入门教程](https://ts.xcatliu.com/) diff --git "a/_posts/Tech/FrontEnd/2022-12-24-react\347\254\224\350\256\260.md" "b/_posts/Tech/FrontEnd/2022-12-24-react\347\254\224\350\256\260.md" new file mode 100644 index 0000000000..2e59ed9546 --- /dev/null +++ "b/_posts/Tech/FrontEnd/2022-12-24-react\347\254\224\350\256\260.md" @@ -0,0 +1,884 @@ +--- +layout: post +category: FrontEnd +title: react笔记 +tags: FrontEnd +--- + +# react笔记 + +> [React](https://web.qianguyihao.com/13-React%E5%9F%BA%E7%A1%80/01-React%E4%BB%8B%E7%BB%8D.html) + +## React 介绍 + +### React 是什么 + +- Facebook 开源的一个JS库。 +- 一个用于动态构建用户界面的JS库。 +- 不是一个MCV框架,构建可复用web组件,侧重UI + +### React 的特点 + +- Declarative(声明式编码) +- Component-Based(组件化编码) +- Learn Once, Write Anywhere(支持客户端、服务器端渲染) +- 高效的DOM Diff算法,最小化页面重绘。虚拟(virtual)DOM,不总是直接操作DOM +- 单向数据流 React是单向的从数据到视图的渲染,非双向数据绑定 + +### React高效的原因 + +- 虚拟(virtual)DOM,不总是直接操作DOM +- 高效的DOM Diff算法,最小化页面重绘(即“局部渲染”)。 + +虚拟DOM指的是:在真实DOM的上一层**映射**一层虚拟DOM。我们操作的是映射关系,而不是真实的DOM。假设页面的样式做了修改(比如新增了一个标签),此时修改的是虚拟DOM的样式,真实的DOM并未发生变化。那什么时候,真实的DOM会发生变化呢? 当我把所有的内容操作完之后,转化为真实的DOM,此时要打包统一的渲染页面,于是真实的DOM发生变化,然后渲染一次。 这样做的话,可以减少页面的渲染次数。 + +## JSX和组件 + + + +react 使用 JSX 来替代常规的 JavaScript。 + +JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。 + +如果碰见jsx或者tsx文件,就是用了jsx语法。其中tsx是typescript+jsx + +我们不需要一定使用 JSX,但它有以下优点: + +- JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。 +- 它是类型安全的,在编译过程中就能发现错误。 +- 使用 JSX 编写模板更加简单快速。 + +```js +const element =

      Hello, world!

      ; +``` + +我们推荐在 React 中使用 JSX 来描述用户界面。 + +每个return jsx的叫组件。 + + + +对于原生的react代码,每次创建元素很麻烦,所以我们提出了用jsx语法代替,此时代码中return的`
      `就是一种jsx语法。jsx语法需要注意的点在于: + +1. 对于jsx中的标签内如果需要传值,主要要使用{}包裹,如果使用"",则默认会传一个string的值,容易造成错误 +2. 对于传入的对象,我们需要用{{key:value}}包裹,此时第一层是用来表示这里面是js代码,第二层用来表示这个是个对象 +3. jsx其实就是一种语法模板,他用来翻译react中书写的代码,而用来将jsx语法翻译的工具叫做babel-loader,而babel-loader被webpack内置了,因为我们用的脚手架其实就是webpack的打包,所以默认我们就可以写jsx语法而不报错。 + +### + +JSX 允许在大括号中嵌入任何表达式,所以我们可以在 map() 中这样使用: + +```scala +function NumberList(props) { + const numbers = props.numbers; + return ( +
        + {numbers.map((number) => + + + )} +
      + ); +} +``` + +如果想在jsx里加注释,就{}包起来, + +想加console.log,也是这样包起来。 {}其实是返回了一个值,这个值作为jsx里用的。 + +```scala +return ( + {console.log('xx')} + {console.log('234')} + ) +``` + + + +每个组件就对应了一个html元素。html元素的属性会传递成组件的元素。 + +## Hello world + +```html + + + + + + + Document + + + + + + + +
      + + + + + +``` + +## React安装 + +```html + + + + +``` + +## 自定义组件参数渲染 + +自定义组件两种方式,函数式组件和类组件。 + + + +以下代码实现了显示时间的时钟,react拿Date渲染。 + +```js +function Clock(props) { + return ( +
      +

      Hello, world!

      +

      现在是 {props.date.toLocaleTimeString()}.

      +
      + ); +} + +function tick() { + ReactDOM.render( + , + document.getElementById('example') + ); +} + +setInterval(tick, 1000); +``` + +除了函数外我们还可以创建一个 React.Component 的 ES6 类,该类封装了要展示的元素,需要注意的是在 render() 方法中,需要使用 **this.props** 替换 **props**: + +```js +class Clock extends React.Component { + render() { + return ( +
      +

      Hello, world!

      +

      现在是 {this.props.date.toLocaleTimeString()}.

      +
      + ); + } +} + +function tick() { + ReactDOM.render( + , + document.getElementById('example') + ); +} + +setInterval(tick, 1000); + +``` + +## 复合组件 + +```js +function Name(props) { + return

      网站名称:{props.name}

      ; +} +function Url(props) { + return

      网站地址:{props.url}

      ; +} +function Nickname(props) { + return

      网站小名:{props.nickname}

      ; +} +function App() { + return ( +
      + + + +
      + ); +} + +ReactDOM.render( + , + document.getElementById('example') +); +``` + + + +## 有状态的组件(定时刷新等) + +> [React State(状态)](https://www.runoob.com/react/react-state.html) +> +> 其实就是组件可以实现定时刷新等功能,不用操作DOM + +### 定时功能 + +React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。 + +React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。 + +注意必须要用react api来更新state,如果直接this.state赋值不会重绘。state其实就是一个Object可以多层结构 自定义。 + +每次调用`this.setState`就重绘一次。 + +```scala +class Clock extends React.Component { + constructor(props) { + super(props); + this.state = {date: new Date()}; + } + // 挂载,注册定时任务 + componentDidMount() { + this.timerID = setInterval( + () => this.tick(), + 1000 + ); + } + // 卸载定时任务 + componentWillUnmount() { + clearInterval(this.timerID); + } + + tick() { + this.setState({ + date: new Date() + }); + } + + render() { + return ( +
      +

      Hello, world!

      +

      现在是 {this.state.date.toLocaleTimeString()}.

      +
      + ); + } +} + +ReactDOM.render( + , + document.getElementById('example') +); +``` + + + +每当 Clock 组件第一次加载到 DOM 中的时候,我们都想生成定时器,这在 React 中被称为**挂载**。 + +同样,每当 Clock 生成的这个 DOM 被移除的时候,我们也会想要清除定时器,这在 React 中被称为**卸载**。 + + + +代码解析: + +- **componentDidMount()** 与 **componentWillUnmount()** 方法被称作生命周期钩子。 +- 在组件输出到 DOM 后会执行 **componentDidMount()** 钩子,我们就可以在这个钩子上设置一个定时器。 +- this.timerID 为定时器的 ID,我们可以在 **componentWillUnmount()** 钩子中卸载定时器。 + + + +### 数据自顶向下流动 + +父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。 + +这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。 + + + + + +## State 和 Props 组件参数传递 + +> [State 和 Props](https://www.runoob.com/react/react-props.html) 组件的参数传递、父组件传递给子组件 + + + +state 和 props 主要的区别在于 **props** 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。 + + + +### 使用props + +```js +function HelloMessage(props) { + return

      Hello {props.name}!

      ; +} + +const element = ; + +ReactDOM.render( + element, + document.getElementById('example') +); + +``` + + + +设置默认props属性 + +```js +class HelloMessage extends React.Component { + render() { + return ( +

      Hello, {this.props.name}

      + ); + } +} + +// default props +HelloMessage.defaultProps = { + name: 'Runoob' +}; + +const element = ; + +ReactDOM.render( + element, + document.getElementById('example') +``` + + + +##### props是只读的 + +所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。 + +### 组合使用 state 和 props + +在应用中组合使用 state 和 props 。我们可以在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。在 render 函数中, 我们设置 name 和 site 来获取父组件传递过来的数据。 + + + +```js +class WebSite extends React.Component { + constructor() { + super(); + + this.state = { + name: "菜鸟教程", + site: "https://www.runoob.com" + } + } + render() { + return ( +
      + + +
      + ); + } +} + + + +class Name extends React.Component { + render() { + return ( +

      {this.props.name}

      + ); + } +} +``` + + + +### Props 验证 + +比如验证是String类型才行。 + +```js +class MyTitle extends React.Component { + render() { + return ( +

      Hello, {this.props.title}

      + ); + } +} + +MyTitle.propTypes = { + title: PropTypes.string +}; +``` + +Props 验证使用 **propTypes**,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。 + + + +## React 事件处理 按钮等逻辑 + +> [React 事件处理](https://www.runoob.com/react/react-event-handle.html) 按钮等逻辑 + +```scala +class Popper extends React.Component{ + constructor(){ + super(); + this.state = {name:'Hello world!'}; + } + // onclick执行逻辑 + preventPop(name, e){ //事件对象e要放在最后 + e.preventDefault(); + alert(name); + } + + render(){ + return ( +
      +

      hello

      + {/* 通过 bind() 方法传递参数。 */} + Click +
      + ); + } +} +``` + + + + + +子组件如何给父组件传递消息? [参考](https://www.runoob.com/react/react-forms-events.html) + +当你需要从子组件中更新父组件的 **state** 时,你需要在父组件通过创建事件句柄 (**handleChange**) ,并作为 prop (**updateStateProp**) 传递到你的子组件上。实例如下: + +```javascript +class Content extends React.Component { + render() { + return
      + +

      {this.props.myDataProp}

      +
      + } +} +class HelloMessage extends React.Component { + constructor(props) { + super(props); + this.state = {value: 'Hello Runoob!'}; + this.handleChange = this.handleChange.bind(this); + } + handleChange(event) { + this.setState({value: '菜鸟教程'}) + } + render() { + var value = this.state.value; + return
      + +
      ; + } +} +ReactDOM.render( + , + document.getElementById('example') +); + +``` + + + +## React 条件渲染 + +> [React 条件渲染](https://www.runoob.com/react/react-conditional-rendering.html) + + + +在jsx里定义条件或者变量来渲染可以不同的结果。 + +变量控制: + +```scala + render() { + const isLoggedIn = this.state.isLoggedIn; + + let button = null; + if (isLoggedIn) { + button = ; + } else { + button = ; + } + + return ( +
      + + {button} +
      + ); +``` + + + +三目运算符 + +```scala +render() { + const isLoggedIn = this.state.isLoggedIn; + return ( +
      + {isLoggedIn ? ( + + ) : ( + + )} +
      + ); +} +``` + + + +## React 列表 & Keys + +> [React 列表 & Keys](https://www.runoob.com/react/react-lists-and-keys.html) + + + +```scala +function NumberList(props) { + const numbers = props.numbers; + const listItems = numbers.map((number) => +
    • Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。 + {number} +
    • + ); + return ( +
        {listItems}
      + ); +} + +const numbers = [1, 2, 3, 4, 5]; +ReactDOM.render( + , + document.getElementById('example') +); + +``` + +Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。 + + + +## React 组件 API + +> [React 组件 API](https://www.runoob.com/react/react-component-api.html) + +- 设置状态:setState 合并nextState和当前state,并重新渲染组件。 + - setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。合并指如果json两个key,可以只操作一个而不影响另一个Key。 + - 另外注意setState()并不会立即改变this.state,而是创建一个即将处理的state。setState()并不一定是同步的,为了提升性能React会批量执行state和DOM渲染。 +- 替换状态:replaceState 不合并。 +- 设置属性:setProps 设置属性,合并。 +- 替换属性:replaceProps 替换属性 +- 强制更新:forceUpdate + - forceUpdate()方法会使组件调用自身的render()方法重新渲染组件,组件的子组件也会调用自己的render()。但是,组件重新渲染时,依然会读取this.props和this.state,如果状态没有改变,那么React只会更新DOM。 + - forceUpdate()方法适用于this.props和this.state之外的组件重绘(如:修改了this.state后),通过该方法通知React需要调用render() + - 一般来说,应该尽量避免使用forceUpdate(),而仅从this.props和this.state中读取状态并由React触发render()调用。 +- 获取DOM节点:findDOMNode + - 返回值:DOM元素DOMElement + - 如果组件已经挂载到DOM中,该方法返回对应的本地浏览器 DOM 元素。当**render**返回**null** 或 **false**时,**this.findDOMNode()**也会返回**null**。从DOM 中读取值的时候,该方法很有用,如:获取表单字段的值和做一些 DOM 操作。 + +## React 组件生命周期 + +> [React 组件生命周期](https://www.runoob.com/react/react-component-life-cycle.html) + +- Mounting(挂载):已插入真实 DOM +- Updating(更新):正在被重新渲染 +- Unmounting(卸载):已移出真实 DOM + +![img](https://cdn.jsdelivr.net/gh/mafulong/mdPic@vv6/v6/202303152334216.png) + +- `componentDidMount()`: 在组件挂载后(插入 DOM 树中)立即调用。 +- `componentDidUpdate()`: 在重绘后会被立即调用。 +- `componentWillUnmount()`: 在组件卸载及销毁之前直接调用。 + + + +例子 + +- [React AJAX](https://www.runoob.com/react/react-ajax.html) 使用ajax请求服务端数据,挂载时开始异步请求数据,并设置回调,如果请求有结果了,就setState重绘,卸载时取消进行中的请求。 + + + +## React 表单 + +> [React 表单](https://www.runoob.com/react/react-forms-events.html) + +HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素生来就保留一些内部状态。 + +在 HTML 当中,像 `,