AspNetCore熟練應用CancellationToken,CTO會對你刮目相看

背景

  已經有很多文章記錄了 web程序中採用異步編程的優勢和.Net異步編程的用法, 異步編程雖然不能解決查詢數據庫的瓶頸, 但是利用線程切換,能最大限度的彈性利用工作線程, 提高了web服務的響應能力。

  【 9012年了,再不會異步編程你是真老了】

       本文要說的是利用異步編程中的取消機制緩解數據庫的查詢瓶頸開發者只需在 MVC/WebAPI查詢方法體內關注CancllationToken並適時取消異步任務, 這將大大提高應用的響應能力。

頭腦風暴

  想象你請求某網站頁面,該頁面正閃着菊花試圖努力綻放(正在加載),最終你忍不了:

① F5刷新

② 轉向其他頁面

③ 點擊瀏覽器“停止”按鈕 

對於可憐的服務器,用戶快速刷新5次,服務器將被迫接受 5倍的工作量,這是因為即使用戶刷新了瀏覽器(或點擊停止按鈕), 雖然取消了原始瀏覽器請求,但是Web服務器並不Care,仍然按部就班處理進入HTTP pipeline的請求(MVC/WebAPI 中默認行為)。其他②③場景類似。

在異步編程中能向任務發出Cancllation信號,停止web服務器一切後端查詢行為。在.NET中,這是使用CancellationToken完成的:

  • 取消令牌的實例傳遞到異步任務

  • 異步任務監視令牌,以查看請求是否已經被取消。

  • 如果請求取消,則應停止執行正在執行的操作。.NET中的大多數異步方法將具有接受取消令牌的重載。

本文所說的請求是,耗時長的服務端讀取查詢(返回數據但不修改數據的查詢)。取消已修改數據的請求對於用程序可能不是一個好的選擇:

    –  是否真的要因用戶導航到應用程序中的另一個頁面而取消保存?也許可以,但也可能不會。

   –  除了數據問題,這也不會提高性能,因為數據庫服務器將需要回滾該事務,這可能是一項昂貴的操作。

AspNetCore實踐

P1  監測CancellationToken令牌

  訪問 MyReallySlowReport頁面,等待5s,最終他們放棄了,去了其他頁面:

 所有正在進行的請求都將被取消。

MVC/WebAPI能接受到取消請求的信號。開發者只需要在Controller Action中添加CancellationToken參數,並在後續行為中監測該取消信號。

瀏覽器取消請求時,AspNetCore根據自動將HttpContext.RequestAborted這個token綁定到Action的CancellationToken 參數,CancellationTokenModelBinder將會在調用AddMvc()或services.AddMvcCore()時被注入。​

public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)
{
    List<ReportItem> items;
    using (ApplicationDbContext context = new ApplicationDbContext())
    {
        items = await context.ReportItems.ToListAsync(cancellationToken);
    }
    return View(items);
}

很容易取消SQL的查詢行為,因為上述EF的調用api支持取消異步操作; 對於自定義的長耗時查詢行為,可以使用CancllationToken的原生觸發用法:

public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)
{
    List<ReportItem> items;
    using (ApplicationDbContext context = new ApplicationDbContext())
    {
        items = await context.ReportItems.ToListAsync(cancellationToken);
    }

    foreach (var item in items)
    {
        cancellationToken.ThrowIfCancellationRequested();
            // slow non-cancellable work
            Thread.Sleep(1000);
    }
    return View(items);
}

 P2  處理取消異步操作向上拋出的異常 

 Web服務器觸發取消信號,一般會向上會拋出 OperationCanceledException 或者 TaskCancellationException,所以為了記錄這種非常規異常,建議採用獨立的ExceptionFilter記錄。

public class OperationCancelledExceptionFilter : ExceptionFilterAttribute
{
    private readonly ILogger _logger;

    public OperationCancelledExceptionFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<OperationCancelledExceptionFilter>();
    }
    public override void OnException(ExceptionContext context)
    {
        if(context.Exception is OperationCanceledException)
        {
            _logger.LogInformation("Request was cancelled");
            context.ExceptionHandled = true;
            context.Result = new StatusCodeResult(400);
        }
    }
}

P3  想要得到CTO的稱讚,可不是那麼簡單。

以上只是後端程序員利用取消機制緩解異步查詢瓶頸的後端操作,從web應用全流程角度思考,這個優化還能提升嗎?

> 以上是傳統的網頁請求場景,在取消請求時,瀏覽器幫助我們發起了Cancellation信號。 

> 想想日益常見的SPA程序(單頁面程序),絕大部分頁面請求都是Ajax請求,你點擊應用的另外一個“頁面(JS代碼維護頁面導航),瀏覽器不會自動取消請求。

所以在SPA應用中,要前端自行發出取消請求的信號

var xhr = $.get("/api/myslowreport", function(data){
  //show the data
});

//If the user navigates away from this page
xhr.abort() 

That‘s all ,前後端程序猿通力配合, 應用的吞吐量和響應能力極大提升, CTO要給各位加薪了。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

台灣寄大陸海運貨物規則及重量限制?

大陸寄台灣海運費用試算一覽表

南投搬家前需注意的眉眉角角,別等搬了再說!

亞馬遜粉紅豚 外表夢幻屢遭漁夫獵捕

摘錄自2020年3月5日公視報導

腹部泛著粉紅漂亮膚色的亞馬遜淡水豚,動保專家率領的團隊將牠撈捕上岸,進行檢測、採樣、烙印標記以利追蹤的作業後,再把牠放回大自然。亞馬遜淡水豚是世界上體型最大的淡水豚,成年後體色從深灰轉淡變成粉紅,當牠改變行為或經陽光照射,膚色也會跟著改變,就像人會臉紅一樣。

亞馬遜粉紅豚的孕育期長達13個月,河豚寶寶出生後,有兩年時間需要母親照顧,由於哺育期比較長,母河豚每隔三到五年才會生育,加上每年約有2500隻粉紅豚遭到漁夫獵殺,做為獵捕另一種大型鯰魚的誘餌,這種淡水豚已經列入易危名單。當地檢方在2015年提出禁捕鯰魚的禁令,希望保護粉紅豚,不過禁漁令上個月到期,動保專家疾呼應該展延。

動保專家擔心,如果不趕快採取有效行動,亞馬遜粉紅豚恐怕會重演長江白鱀豚於2006年滅絕的悲劇。

物種保育
海洋
生態保育
國際新聞
亞馬遜

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!

無懼疫情泰國市場仍售野味 專家憂成武漢第二

摘錄自2020年3月9日星島日報報導

新冠肺炎疫情蔓延至今,仍未有緩解跡象,甚至蔓延至世界各地。在疫情暴發初期,不少專家都認為病毒源於野味,更直指是因為武漢海鮮市場暗售的野味。近日,澳洲節目揭發,泰國市場有商人無懼疫情持續,仍出售蜥蜴、猴子、野貓等野味,市場環境更是惡劣,野生動物均被困在狹窄的籠子。專家擔憂,恐會成為第二個武漢,並直指是「沉睡定時炸彈」。

據澳洲Nine電視台節目《60 Minutes》報道,美國環境與人權調查員Steven Galster與記者早前走訪泰國曼谷的洽圖洽市場(Chatuchak Market),發現有商人仍出售野生動物,包括野貓、狐狸、狨猴、蛇、蜥蜴、烏龜及穿山甲等野生動物。

雖然中國已關閉逾2萬類似的市場,但仍有其他亞洲國家經營。Galster又指為遏制病毒,應該關閉所有非法的野生動物交易市場,阻止病毒擴散與復發。

食品安全
生活環境
國際新聞
泰國
武漢肺炎
野味
傳統市場

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

台灣寄大陸海運貨物規則及重量限制?

大陸寄台灣海運費用試算一覽表

台中搬家,彰化搬家,南投搬家前需注意的眉眉角角,別等搬了再說!

德國SMA推出新型儲能2.5逆變器「陽光男孩」

德國太陽能逆變器巨頭SMA推出其新型「陽光男孩」儲能2.5(Sunny Boy Storage 2.5)逆變器,可與特斯拉的Powerwall系統結合,將「陽光男孩」蓄電成本減半。

SMA表示,這款新型逆變器 Sunny Boy Storage 2.5將於5月份投入德國市場,而歐洲和澳大利亞推出時間更晚一些。

此高壓蓄電裝置是一個AC耦合定制串式逆變器,可讓電池與標準的太陽能串式逆變器相連,也可以和家庭和電網相連。「陽光男孩」儲能2.5容量為7kWh,通過德國批發商進行銷售。SMA表示,到今年中期,其他廠商的高壓電池將與SMA的電力解決方案相結合。

該SMA設備單相運行,最大放電功率為2.5kW。可以並聯,可以與Sunny Home Manager的能量管理共同協調,並且可以在戶外安裝。

相比於SMA現有的交流耦合儲能產品「陽光冰島」(Sunny Island)的價格,「陽光男孩」儲能2.5的售價低了56%。因為「陽光冰島」有些必備的部件對於儲能2.5而言根本不需要。根據「陽光冰島」目前網上商店的價格,「陽光男孩」儲能2.5售價不會超過1,000歐元,這對於儲能系統而言並不算貴。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!

etcd-operator快速入門完全教程

Operator是指一類基於Kubernetes自定義資源對象(CRD)和控制器(Controller)的雲原生拓展服務,其中CRD定義了每個operator所創建和管理的自定義資源對象,Controller則包含了管理這些對象所相關的運維邏輯代碼。

對於普通用戶來說,如果要在k8s集群中部署一個高可用的etcd集群,那麼不僅要了解其相關的配置,同時又需要特定的etcd專業知識才能完成維護仲裁,重新配置集群成員,創建備份,處理災難恢復等等繁瑣的事件。

而在operator這一類拓展服務的協助下,我們就可以使用簡單易懂的YAML文件(同理參考Deployment)來聲明式的配置,創建和管理我們的etcd集群,下面我們就來一同了解下etcd-operator這個服務的架構以及它所包含的一些功能。

目 標

  1. 了解etcd-operator的架構與CRD資源對象

  2. 部署etcd-operator

  3. 使用etcd-operator創建etcd cluster

  4. 基於etcd-operator備份和恢復etcd cluster

服務架構

etcd-operator的設計是基於k8s的API Extension機制來進行拓展的,它為用戶設計了一個類似於Deployment的Controller,只不過這個Controller是用來專門管理etcd這一服務的。

用戶默認還是通過kubectl或UI來與k8s的API進行交互,只不過在這個k8s集群中多了一個用戶自定義的控制器(custom controller),operator controller的服務是以Pod的方式運行在k8s集群中的,同時這個服務也需要配置所需的RBAC權限(比如對Pod,Deployment,Volume等使用到的資源進行增刪改查的操作),下面我們用一個簡單的架構圖來進行闡述:

etcd-operator的自定義資源對象(CRD)

在k8s中,所有自定義的Controller和其自定義的資源對象(CRD)都必須滿足k8s API的規範(參考下圖):

  • apiVersion描述了當前自定義資源對象的版本號

  • Kind表示自定義資源對象的名稱,用戶可通過執行kubectl get $KIND_NAME來獲取所創建的CRD對象

  • Metadata繼承了原生k8s的metadata,用於添加標籤,Annotations等元數據

  • Spec是用戶可自定義設計的服務配置參數,如鏡像版本號,節點數量,資源配置等等..

  • Status包含了當前資源的的相關狀態,每個operator controller可自定義status所包含的信息,一般會選擇添加如conditions,updateTime和message等一類的信息。

下面先我們來了解一下etcd-operator所包含的幾個自定義資源對象(CRDs):

1、EtcdCluster: etcdcluster用來描述用戶自定義的etcd集群,可一鍵式部署和配置一個相關的etcd集群。

apiVersion: etcd.database.coreos.com/v1beta2
kind: EtcdCluster
metadata:
  name: etcd-cluster
spec:
  size: 3
  version: 3.2.25

2、EtcdBackup: etcdbackup用來描述和管理一個etcd集群的備份,當前支持定期備份到雲端存儲,如AWS s3, Aliyun oss(oss當前需使用quay.io/coreos/etcd-operator:dev鏡像)。


apiVersion: etcd.database.coreos.com/v1beta2
kind: EtcdBackup
metadata:
  name: etcd-backup
spec:
  etcdEndpoints: [<etcd-cluster-endpoints>]
  storageType: OSS #options are S3/ABS/GCS/OSS
  backupPolicy:
    backupIntervalInSecond: 125
    maxBackups: 4
  oss:
    #"<oss-bucket-name>/<path-to-backup-file>"
    path: <full-oss-path>
    ossSecret: <oss-secret>
    # Details about regions and endpoints, see https://www.alibabacloud.com/help/doc-detail/31837.htm
    endpoint: <endpoint> 

3、EtcdRestore:etcdrestore用來幫助將etcdbackup服務所創建的備份恢復到一個指定的etcd的集群。

apiVersion: etcd.database.coreos.com/v1beta2
kind: EtcdRestore
metadata:
  # name must be same to the spec.etcdCluster.name
  name: example-etcd-cluster
spec:
  etcdCluster:
    name: example-etcd-cluster
  backupStorageType: OSS
  oss:
    path: <full-oss-path> 
    ossSecret: <oss-secret>
    endpoint: <endpoint>

如何部署和使用etcd-operator

1、部署etcd-operator

在Rancher最新的stable v2.3.2 的版本中,用戶可通過應用商店(Catalog)來一鍵式部署 etcd-operator v0.9.0版本,同時原生k8s也可下載rancher/charts到本地后通過helm install的方式進行部署。

1)(可選)部署etcd-operator時可選擇同時創建一個etcd集群(此集群在etcd-operator被刪除時會被一同移除),當然用戶也可待etcd-operator部署完成通過kubectl apply -f myetcd.yaml來創建一個新的etcd集群。

2)部署時,如果用戶選擇啟動Enable Clusterwide of etcd Operator這個選項,那麼這個etcd-operator將作為集群層級對象來使用(否則為namespaced隔離),如果enable這個選項,那麼在創建etcd集群時需添加以下註釋才能創建創建:

kind: EtcdCluster
metadata:
  name: etcd-cluster
  # add this annotation when the clusterWide is enabled
  annotations:
    etcd.database.coreos.com/scope: clusterwide

2、創建etcd集群

接下來我們就可以使用上述的CRD自定義資源對象對來創建和管理我們的etcd集群了。

2.1 手動創建etcd集群

cat <<EOF | kubectl apply -f -
apiVersion: etcd.database.coreos.com/v1beta2
kind: EtcdCluster
metadata:
  name: "etcd-cluster"
spec:
  size: 3 # 默認etcd節點數
  version: "3.2.25" # etcd版本號
EOF

2.2 部署后可通過CRD對象來查看我們創建的etcd集群和pod狀態

$ kubectl get etcdcluster
NAME            AGE
etcd-cluster    2m

$ kubectl get pod
NAME                     READY   STATUS  RESTARTS AGE
etcd-cluster-g28f552vvx  1/1   Running    0      2m
etcd-cluster-lpftgqngl8  1/1   Running    0      2m
etcd-cluster-sdpcfrtv99  1/1   Running    0      2m

2.3 可以往etcd集群任意的寫入幾條數據驗證etcd集群是正常工作的(後續也可用來驗證集群的備份和恢復功能)

$ kubectl get svc
NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
etcd-cluster          ClusterIP   None           <none>        2379/TCP,2380/TCP   17h
etcd-cluster-client   ClusterIP   10.43.130.71   <none>        2379/TCP            17h
## write data
$ kubectl exec -it any-etcd-pod -- env "ETCDCTL_API=3" etcdctl --endpoints http://etcd-cluster-client:2379 put foo "Hello World"
## get data
$ kubectl exec -it any-etcd-pod -- env "ETCDCTL_API=3" etcdctl --endpoints http://etcd-cluster-client:2379 get foo
foo
Hello World

3、基於operator備份etcd cluster

3.1 確認了etcd集群正常運行后,作為devops後面要考慮的就是如何創建etcd集群的自動化備份,下面以阿里雲的OSS舉例:

cat <<EOF | kubectl apply -f -
apiVersion: etcd.database.coreos.com/v1beta2
kind: EtcdBackup
metadata:
  name: example-etcd-cluster-periodic-backup
spec:
  etcdEndpoints: [http://etcd-cluster-client:2379] #內網可使用svc地址,外網可用NodePort或LB代理地址
  storageType: OSS
  backupPolicy:
    backupIntervalInSecond: 120 #備份時間間隔
    maxBackups: 4 #最大備份數
  oss:
    path: my-bucket/etcd.backup
    ossSecret: oss-secret #需預先創建oss secret
    endpoint: oss-cn-hangzhou.aliyuncs.com
EOF

3.2 若OSS Secret不存在,用戶可先手動創建,具體配置可參考如下:

cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: oss-secret
type: Opaque
stringData:
  accessKeyID: myAccessKey
  accessKeySecret: mySecret
EOF

3.3 待etcdbackup創建成功后,用戶可以通過kubectl describe etcdbackup或查看etcd-backup controller日誌來查看備份狀態,如狀態显示為Succeeded: true,可以前往oss查看具體的備份內容。

4、基於operator恢復etcd cluster

最後,假設我們要將etcd集群A的備份數據恢復到另一個新的etcd集群B,那麼我們先手動創建一個名為etcd-cluster2的新集群(oss備份/恢復當前需使用quay.io/coreos/etcd-operator:dev鏡像)。

cat <<EOF | kubectl apply -f -
apiVersion: etcd.database.coreos.com/v1beta2
kind: EtcdCluster
metadata:
  name: "etcd-cluster2"
spec:
  size: 3
  version: "3.2.25"
EOF

然後通過創建etcdresotre將備份數據恢復到etcd-cluster2集群


cat <<EOF | kubectl apply -f -
apiVersion: etcd.database.coreos.com/v1beta2
kind: EtcdRestore
metadata:
  # name必須與下面的spec.etcdCluster.name保持一致
  name: etcd-cluster2
spec:
  etcdCluster:
    name: etcd-cluster2
  backupStorageType: OSS
  oss:
    path: my-bucket/etcd.backup_v1_2019-08-07-06:44:17
    ossSecret: oss-secret
    endpoint: oss-cn-hangzhou.aliyuncs.com
EOF

待etcdresotre對象創建成功后,可以查看etcd-operator-restore的日誌,大致內容如下:

$ kubectl logs -f etcd-operator-restore
...
time="2019-08-07T06:50:26Z" level=info msg="listening on 0.0.0.0:19999"
time="2019-08-07T06:50:26Z" level=info msg="starting restore controller" pkg=controller
time="2019-08-07T06:56:25Z" level=info msg="serving backup for restore CR etcd-cluster2"

通過kubectl查看pod我們可以看到etcd-cluster2集群的etcd節點被刪除重建:

NAME                       READY   STATUS    RESTARTS   AGE
etcd-cluster2-5tq2d5bvpf    0/1     Terminating   0      93s
etcd-cluster2-kfgvc692pp    1/1     Terminating   0      101s
etcd-cluster2-xqkgz8chb8    0/1     Init:1/3      0      6s
etcd-cluster2-pf2qxgtg9d    1/1     Running       0      48s
etcd-cluster2-x92l9vpx97    1/1     Running       0      40s

最後可通過etcdctl來驗證之前的數據是否存在(需設置ETCDCTL_API=3):

$ kubectl exec -it etcd-pod -- env "ETCDCTL_API=3" etcdctl --endpoints http://etcd-cluster2-client:2379 get foo
foo
Hello World

小 結

Etcd作為當前非常流行的key-value分佈式文件存儲,它本身的強一致性和較優的性能可以為許多分佈式計算解決分佈式存儲的需求,如果你的微服務和應用需要用到此類的數據庫,不妨來試試Rancher Catalog應用中的etcd-operator吧,Just do it!

相關資料:

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!

【算法】leetcode算法筆記:二叉樹,動態規劃和回溯法

前言

寫的比較匆忙,測試用例是能全部跑通的,不過考慮內存和效率的話,還有許多需要改進的地方,所以請多指教

在二叉樹中增加一行

題目描述

給定一個二叉樹,根節點為第1層,深度為 1。在其第 d 層追加一行值為 v 的節點。

添加規則:給定一個深度值 d (正整數),針對深度為 d-1 層的每一非空節點 N,為 N 創建兩個值為 v 的左子樹和右子樹。

將 N 原先的左子樹,連接為新節點 v 的左子樹;

將 N 原先的右子樹,連接為新節點 v 的右子樹。

如果 d 的值為 1,深度 d – 1 不存在,則創建一個新的根節點 v,原先的整棵樹將作為 v 的左子樹。

Example

Input: 
A binary tree as following:
       4
     /   \
    2     6
   / \   / 
  3   1 5   

v = 1

d = 2

Output: 
       4
      / \
     1   1
    /     \
   2       6
  / \     / 
 3   1   5  

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/add-one-row-to-tree

 
基本思想
二叉樹的先序遍歷   
代碼的基本結構
不是最終結構,而是大體的結構

/**
 * @param {number} cd:current depth,遞歸當前深度
 * @param {number} td:target depth, 目標深度
 */
var traversal = function (node, v, cd, td) {
    // 遞歸到目標深度,創建新節點並返回
  if (cd === td) {
    // return 新節點
  }
  // 向左子樹遞歸
  if (node.left) {
    node.left = traversal (node.left, v, cd + 1, td);
  }
  // 向右子樹遞歸
  if (node.right) {
    node.right = traversal (node.right, v, cd + 1, td);
  }
  // 返回舊節點
  return node;
};
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} v
 * @param {number} d
 * @return {TreeNode}
 */
var addOneRow = function (root, v, td) {
    // 從根節點開始遞歸
  traversal (root, v, 1, td);
  return root;
};

 

 

具體分析
我們可以分類討論,分三種情況處理  
第1種情況:目標深度<=當前遞歸路徑的最大深度 
處理方法:val節點替換該目標深度對應的節點,並且

  • 如果目標節點原來是左子樹,那麼重置后目標節點是val節點的左子樹

  • 如果目標節點原來是右子樹,那麼重置后目標節點是val節點的右子樹

 

第2種情況:目標深度>當前遞歸路徑的最大深度
閱讀題目發現,有這麼一個描述:“輸入的深度值 d 的範圍是:[1,二叉樹最大深度 + 1]”
所以呢,當目標深度恰好比當前路徑的樹的深度再深一層時,處理方式是:
在最底下那一層節點的左右分支新增val節點

 

第3種情況:目標深度為1

我們再分析題意,題目里說:“如果 d 的值為 1,深度 d – 1 不存在,則創建一個新的根節點 v,原先的整棵樹將作為 v 的左子樹。”

這說明當:目標深度為1時,我們的處理方式是這樣的 

 

全部代碼 

/**
 * @param {v} val,插入節點攜帶的值
 * @param {cd} current depth,遞歸當前深度
 * @param {td} target depth, 目標深度
 * @param {isLeft}  判斷原目標深度的節點是在左子樹還是右子樹
 */
var traversal = function (node, v, cd, td, isLeft) {
  debugger;
  if (cd === td) {
    const newNode = new TreeNode (v);
    // 如果原來是左子樹,重置后目標節點還是在左子樹上,否則相反
    if (isLeft) {
      newNode.left = node;
    } else {
      newNode.right = node;
    }
    return newNode;
  }
  // 處理上述的第1和第2種情況
  if (node.left || (node.left === null && cd + 1 === td)) {
    node.left = traversal (node.left, v, cd + 1, td, true);
  }
  if (node.right || (node.right === null && cd + 1 === td)) {
    node.right = traversal (node.right, v, cd + 1, td, false);
  }
  return node;
};
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} v
 * @param {number} d
 * @return {TreeNode}
 */
var addOneRow = function (root, v, td) {
  // 處理目標深度為1的情況,也就是上述的第3種情況
  if (td === 1) {
    const n = new TreeNode (v);
    n.left = root;
    return n;
  }
  traversal (root, v, 1, td);
  return root;
};

 

單詞拆分 

題目描述 

給定一個非空字符串 s 和一個包含非空單詞列表的字典 wordDict,判定 s 是否可以被空格拆分為一個或多個在字典中出現的單詞。

說明:

1.拆分時可以重複使用字典中的單詞。

2.你可以假設字典中沒有重複的單詞。

 

Example 

example1
輸入: s = "applepenapple", wordDict = ["apple", "pen"]
輸出: true
解釋: 返回 true 因為 "applepenapple" 可以被拆分成 "apple pen apple"。
注意: 你可以重複使用字典中的單詞。

example2
輸入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
輸出: false

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/word-break

 

基本思想 

動態規劃

具體分析
動態規劃的關鍵點是:尋找狀態轉移方程
有了這個狀態轉移方程,我們就可以根據上一階段狀態和決策結果,去求出本階段的狀態和結果
然後,就可以從初始值,不斷遞推求出最終結果。
在這個問題里,我們使用一個一維數組來存放動態規劃過程的遞推數據
假設這個數組為dp,數組元素都為true或者false,
dp[N] 存放的是字符串s中從0到N截取的子串是否是“可拆分”的布爾值
讓我們從一個具體的中間場景出發來思考計算過程
假設我們有

wordDict = ['ab','cd','ef']
s ='abcdef'

並且假設目前我們已經得出了N=1到N=5的情況,而現在需要計算N=6的情況

或者說,我們已經求出了dp[1] 到dp[5]的布爾值,現在需要計算dp[6] = ?  
該怎麼計算呢?
現在新的字符f被加入到序列“abcde”的後面,如此以來,就新增了以下幾種6種需要計算的情況

A序列 + B序列
1.abcdef + ""
2.abcde + f
3.abcd + ef
4.abc + def
5.ab + cdef
6.a + bcdef
注意:當A可拆且B可拆時,則A+B也是可拆分的

 

從中我們不難發現兩點

  1. 當A可拆且B可拆時,則A+B也是可拆分的

  2. 這6種情況只要有一種組合序列是可拆分的,abcdef就一定是可拆的,也就得出dp[6] = true了

下面是根據根據已有的dp[1] 到dp[5]的布爾值,動態計算dp[6] 的過程

(注意只要計算到可拆,就可以break循環了)  
具體代碼

var initDp = function (len) {
  let dp = new Array (len + 1).fill (false);
  return dp;
};
/**
 * @param {string} s
 * @param {string[]} wordDict
 * @return {boolean}
 */
var wordBreak = function (s, wordDict) {
  // 處理空字符串
  if (s === '' && wordDict.indexOf ('') === -1) {
    return false;
  }
  const len = s.length;
  // 默認初始值全部為false
  const dp = initDp (len);
  const a = s.charAt (0);
  // 初始化動態規劃的初始值
  dp[0] = wordDict.indexOf (a) === -1 ? false : true;
  dp[1] = wordDict.indexOf (a) === -1 ? false : true;
  // i:end
  // j:start
  for (let i = 1; i < len; i++) {
    for (let j = 0; j <= i; j++) {
      // 序列[0,i] = 序列[0,j] + 序列[j,i]
      // preCanBreak表示序列[0,j]是否是可拆分的
      const preCanBreak = dp[j];
      // 截取序列[j,i]
      const str = s.slice (j, i + 1);
      // curCanBreak表示序列[j,i]是否是可拆分的
      const curCanBreak = wordDict.indexOf (str) !== -1;
      // 情況1: 序列[0,j]和序列[j,i]都可拆分,那麼序列[0,i]肯定也是可拆分的
      const flag1 = preCanBreak && curCanBreak;
      // 情況2: 序列[0,i]本身就存在於字典中,所以是可拆分的
      const flag2 = curCanBreak && j === 0;
      if (flag1 || flag2) {
        // 設置bool值,本輪計算結束
        dp[i + 1] = true;
        break;
      }
    }
  }
  // 返回最後結果
  return dp[len];
};

全排列 

題目描述

給定一個沒有重複数字的序列,返回其所有可能的全排列。

Example

輸入: [1,2,3]
輸出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/permutations

 

基本思想

回溯法

 

具體分析

  1. 深度優先搜索搞一波,index在遞歸中向前推進

  2. 當index等於數組長度的時候,結束遞歸,收集到results中(數組記得要深拷貝哦)

  3. 兩次数字交換的運用,計算出兩種情況

總結

想不通沒關係,套路一波就完事了 

具體代碼

var swap = function (nums, i, j) {
  const temp = nums[i];
  nums[i] = nums[j];
  nums[j] = temp;
};

var recursion = function (nums, results, index) {
  // 剪枝
  if (index >= nums.length) {
    results.push (nums.concat ());
    return;
  }
  // 初始化i為index
  for (let i = index; i < nums.length; i++) {
    // index 和 i交換??
    // 統計交換和沒交換的兩種情況
    swap (nums, index, i);
    recursion (nums, results, index + 1);
    swap (nums, index, i);
  }
};
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function (nums) {
  const results = [];
  recursion (nums, results, 0);
  return results;
};

 

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

台灣寄大陸海運貨物規則及重量限制?

大陸寄台灣海運費用試算一覽表

台中搬家,彰化搬家,南投搬家前需注意的眉眉角角,別等搬了再說!

圈養鯨豚退休後的家 世界第一個鯨魚安養中心 選在加拿大天然海灣

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!

豬瘟疫情持續 日本沖繩阿古豬赴離島避難

摘錄自2020年03月15日中央通訊社日本報導

日本沖繩縣沖繩本島豬瘟(Classical Swine Fever,又稱典型豬瘟,不是非洲豬瘟)疫情未見平息,為避免當地特有種「阿古豬」被注射疫苗,決定送30隻純種阿古豬到離島避難。

豬對沖繩民眾來說是不可或缺的食材,號稱「除了聲音以外全部都可以吃」,其中的「阿古豬」大約在600年前從中國來到沖繩後,被視為沖繩特有種,肉質在全日本都相當受歡迎。

為了降低感染豬瘟風險。沖繩縣政府把未接種疫苗的30頭純種阿古豬列為隔離對象,送往久米島上已有的隔離設施避難。沖繩本島全數豬隻將被注射豬瘟疫苗,久米島的隔離措施只是為了避免讓阿古豬被接種疫苗的暫時性措施,最後計畫是在久米島及其他沖繩縣離島建設阿古豬專用設施,屆時會再度移動阿古豬。

豬瘟是一種對肉豬或野豬具高度傳染力的疾病,但不會傳染給人類。根據日本家畜傳染病預防法規定,只要養豬場發現豬隻感染豬瘟,就必須撲殺養豬場內所有豬隻。

永續發展
糧食
動物福利
經濟動物
國際新聞
沖繩
阿古豬
豬瘟

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

台灣寄大陸海運貨物規則及重量限制?

大陸寄台灣海運費用試算一覽表

台中搬家,彰化搬家,南投搬家前需注意的眉眉角角,別等搬了再說!

中國將大砍電動巴士補助?

中國大力補貼發展電動巴士,但狀況似乎有了改變。由於補貼過於慷慨,衍生「騙補」等弊端,因此中國方面擬減少電動巴士的補助,最高調降49.5%,平均降幅32%。

《鉅亨網》指出,由於中國先前對電動巴士的補貼方案太過寬鬆,以致2015下半年逐漸浮現弊端,2016年各地相關補貼辦法至今仍無法推出。中國考慮減少電動大巴的補貼額度,平均降幅可能達32%,最大規格巴士的補貼最多將減少49.5%,幾乎腰斬。此外,售價超過人民幣35萬元的電動車可能將被排除在政府補貼之外。

據消息人士指出,多個中國政府相關部門正在針對上述補貼調整計畫進行審核,需待國務院或人大批准後方可實行。

根據中國工信部資料,今年一月中國共生產1.61萬輛新能源車,比去年12月大幅減少83.8%。而中國電動汽車資源網數據更直指,中國宇通、中通、比亞迪、北汽等電動巴士生產商的二月產量只有3110輛。相較之下,2015年中國商用純電動巴士的生產與銷量都超過10萬輛。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!

設計模式(Java語言)- 簡單工廠模式

  簡單工廠模式有稱為靜態工廠模式,屬於設計模式中的創建型模式。簡單工廠模式通過對外提供一個靜態方法來統一為類創建實例。簡單工廠模式的目的是實現類與類之間解耦,其次是客戶端不需要知道這個對象是如何被穿創建出來的,只需要調用簡單工廠模式的方法來統一創建就可以了,從而明確了各個類的職責。

  一、創建簡單工廠模式的步驟

  第一步:聲明一個抽象類(接口),以及對應的抽象方法,由實現類分別去實現這個方法。

  第二步: 創建具體實現類,實現抽象方法。

  第三步:創建一個簡單工廠類,聲明一個靜態方法,根據傳入的不同的類型來確定創建抽象類的具體實現類。

  第四步:客戶端通過工廠類獲取實例對象。

 

  二、應用案例: 

  下面以製造手機為例子,在現實生活中可能有很多工廠可以創建不同品牌的手機,這些工廠可以根據不同的需求來創建不同的手機。根據上面的步驟,首先我們需要一個抽象類,所以我們需要知道不同品牌的手機其實都是屬於手機這種類別,因此我們可以將手機抽出來做成一個抽象類:

/**
 * 手機類
 */
public interface Phone {
    //製造手機的方法,留給具體的實現類來製造
    void create();
}

  第二步我們需要開始製造不同品牌的手機了:

  製造華為手機

public class Huawei implements Phone {
    @Override
    public void create() {
        System.out.println("====正在製造華為手機======");
    }
}

  蘋果手機

public class Iphone implements Phone {
    @Override
    public void create() {
        System.out.println("====正在製造蘋果手機======");
    }
}

  第三步我們需要創建一個工廠方法,返回手機類。具體製造什麼品牌的手機,需要根據傳進來的手機名字來決定,因此我們可以這麼寫:

public class SimpleFactory {

    public static Phone createPhone(String name) {
        if ("huawei".equals(name))
            return new Huawei();
        else
            return new Iphone();

    }

}

  第四步,手機創建好了,我們就可以使用了,即客戶端調用工廠方法創建對象實例

public class Client {

public static void main(String[] args) {
Phone huawei = SimpleFactory.createPhone("huawei");
huawei.create();

Phone iphone = SimpleFactory.createPhone("iphone");
iphone.create();
}

}

//輸出結果

====正在製造華為手機======
====正在製造蘋果手機======

  到這裏,簡單工廠模式基本已經寫完了,仔細看會發現這種方法創建對象違反了ocp原則,每次增加不同品牌手機的時候都需要在工廠方法里添加不同的條件判斷。如果手機品牌越來越多,代碼看起來非常臃腫,很不利於後期的代碼維護。因此,我們改進一下,不要通過手機品牌名稱來判斷需要創建哪一中對象了,而是客戶端想要創建什麼對象,只需要傳入具體的實現類就可以了,然後通過Java的反射來創建對象。

public class SimpleFactory2 {

    public static Phone create(Class<? extends Phone> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

}

  客戶端調用

public class Client {

    public static void main(String[] args) {
        Phone huawei = SimpleFactory2.create(Huawei.class);
        huawei.create();

        Phone iphone = SimpleFactory2.create(Iphone.class);
        iphone.create();
    }

}
//運行結果

====正在製造華為手機======
====正在製造蘋果手機======

  經過修改之後,每次增加新的手機品牌時就不用修改工廠方法的邏輯了。但是,還是有一個問題,就是每次創建對象都是通過反射來創建的,所以在性能上是有一定的損耗的。

 

  三、總結:

  優點:

    1、簡單優化了軟件體繫結構,明確了各自功能模塊的職責和權利

    2、通過工廠類,外界不需要直接創建具體產品對象,只需要負責消費,不需要關心內部如何創建對象

  缺點:

    1、改進前的簡單工廠模式全部創建邏輯都集中在一個工廠類中,能創建的類只能是考慮到的,如果需要添加新的類,就必須改變工廠類了

    2、改進前的簡單工廠模式隨着具體產品的不斷增多,可能會出現共產類根據不同條件創建不同實例的需求,這種對條件的判斷和對具體產品類型的判斷交錯在一起,很難避免功能模塊的蔓延,對系統的維護和擴展不利

    3、改進后的簡單工廠模式主要是使用反射效率會低一些

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!