hot100-子串-JS

一、560.和為k的子串

560. 和為 K 的子數組

?

提示

給你一個整數數組 nums 和一個整數?k ,請你統計并返回 該數組中和為?k?的子數組的個數?

子數組是數組中元素的連續非空序列。

示例 1:

輸入:nums = [1,1,1], k = 2
輸出:2

示例 2:

輸入:nums = [1,2,3], k = 3
輸出:2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

1.暴力枚舉法

暴力枚舉的基本思路是通過兩層循環來枚舉所有可能的子數組,然后計算每個子數組的和,判斷其是否等于目標值?k,如果相等則將計數器加 1。

/*** @param {number[]} nums* @param {number} k* @return {number}*/
var subarraySum = function (nums, k) {let count = 0;for (let i = 0; i < nums.length; i++) {let sum = 0;for (let j = i; j < nums.length; j++) {sum += nums[j];if (sum === k) {count++}}}return count;
};

2.使用前綴和與哈希表(推薦)

問題分析

給定一個整數數組?nums?和一個整數?k,要找出數組中和為?k?的子數組(連續非空元素序列)的個數。例如,對于數組?[1, 1, 1]?和?k = 2,子數組?[1, 1]?滿足和為?2,所以結果是?2

前綴和的引入

前綴和是指從數組開頭到當前位置的所有元素的和。假設我們有一個數組?nums = [a0, a1, a2, ..., an],那么:

  • 前綴和?prefixSum[0] = a0
  • 前綴和?prefixSum[1] = a0 + a1
  • 前綴和?prefixSum[2] = a0 + a1 + a2
  • 以此類推,prefixSum[i] = a0 + a1 + ... + ai

對于計算子數組和,有一個重要的性質:如果我們要找從索引?j?到索引?ij <= i)的子數組和,那么這個子數組和?subarraySum(j, i)?就等于?prefixSum[i] - prefixSum[j - 1](當?j > 0?時),如果?j = 0,則?subarraySum(j, i) = prefixSum[i]

算法思路推導

我們的目標是找到滿足?subarraySum(j, i) = k?的子數組個數。根據上面的前綴和性質,subarraySum(j, i) = prefixSum[i] - prefixSum[j - 1] = k,可以變形為?prefixSum[j - 1] = prefixSum[i] - k

這意味著,如果我們知道所有前綴和的值以及它們出現的次數,那么對于當前計算得到的前綴和?prefixSum[i],我們只需要檢查之前是否出現過?prefixSum[i] - k?這個前綴和。如果出現過,那么就說明存在一個子數組的和為?k,并且出現次數就是?prefixSum[i] - k?出現的次數。

哈希表的作用

為了高效地存儲和查詢前綴和及其出現的次數,我們使用哈希表(在 JavaScript 中是?Map?對象)。具體步驟如下:

  1. ?初始化?:

    • 創建一個空的?Map?對象?map,用于存儲前綴和及其出現的次數。
    • 初始化?map.set(0, 1),這是因為前綴和為?0?的情況是存在的(對應空數組,空數組的和為?0),出現次數為?1
    • 初始化變量?sum = 0?來記錄當前的前綴和,ans = 0?來記錄和為?k?的子數組的個數。
  2. ?遍歷數組?:

    • 對于數組中的每個元素?num,將其加到當前前綴和?sum?中,即?sum += num
    • 檢查?map?中是否存在?sum - k。如果存在,說明存在一個子數組的和為?k,將?map.get(sum - k)的值加到?ans?中。這是因為?sum - (sum - k) = kmap.get(sum - k)?表示之前出現過?sum - k?這個前綴和的次數,也就意味著有這么多組子數組的和為?k
    • 將當前前綴和?sum?及其出現的次數存入?map?中。如果?sum?已經存在于?map?中,將其出現次數加?1;否則,將其出現次數設為?1
  3. ?返回結果?:

    • 遍歷結束后,ans?中存儲的就是和為?k?的子數組的個數,將其返回。

示例分析

以輸入?nums = [1, 1, 1]k = 2?為例:

  • 初始化:map = {0: 1}sum = 0ans = 0
  • 第一次循環:
    • num = 1sum = 0 + 1 = 1
    • 檢查?map?中是否有?1 - 2 = -1,沒有。
    • map.set(1, 1)(現在?map = {0: 1, 1: 1})。
    • ans?不變,仍為?0
  • 第二次循環:
    • num = 1sum = 1 + 1 = 2
    • 檢查?map?中是否有?2 - 2 = 0,有,ans = ans + map.get(0) = 0 + 1 = 1
    • map.set(2, 1)(現在?map = {0: 1, 1: 1, 2: 1})。
  • 第三次循環:
    • num = 1sum = 2 + 1 = 3
    • 檢查?map?中是否有?3 - 2 = 1,有,ans = ans + map.get(1) = 1 + 1 = 2
    • map.set(3, 1)(現在?map = {0: 1, 1: 1, 2: 1, 3: 1})。
  • 最終返回?ans = 2,符合預期。

通過這樣的方式,使用前綴和與哈希表的方法能夠高效地解決“和為 K 的子數組”問題。希望以上解釋能幫助你理解這個算法的原理和實現過程。

代碼實現

/*** @param {number[]} nums* @param {number} k* @return {number}*/
var subarraySum = function (nums, k) {let map=new Map();// 初始設置為0的元素有1個map.set(0,1);let sum=0;let ans=0;for(let num of nums){// 計算元素的前綴和sum+=num;// 計數,統計前綴和為某個數共有多少個map.set(sum,(map.has(sum)||0)+1)// 判斷map中是否有 sum-k 如果存在,說明存在一個子數組的和為 kif(map.has(sum-k)){// 將 map.get(sum - k)的值加到 ans 中ans+=map.get(sum-k);}}return ans;
};

二、239.滑動窗口最大值

239. 滑動窗口最大值

?

給你一個整數數組 nums,有一個大小為?k?的滑動窗口從數組的最左側移動到數組的最右側。你只可以看到在滑動窗口內的 k?個數字。滑動窗口每次只向右移動一位。

返回 滑動窗口中的最大值

示例 1:

輸入:nums = [1,3,-1,-3,5,3,6,7], k = 3
輸出:[3,3,5,5,6,7]
解釋:
滑動窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       31 [3  -1  -3] 5  3  6  7       31  3 [-1  -3  5] 3  6  7       51  3  -1 [-3  5  3] 6  7       51  3  -1  -3 [5  3  6] 7       61  3  -1  -3  5 [3  6  7]      7

示例 2:

輸入:nums = [1], k = 1
輸出:[1]

提示:

  • 1 <= nums.length <= 105
  • -104?<= nums[i] <= 104
  • 1 <= k <= nums.length

1.暴力法(超出時間限制)

O(nk)會很慢

/*** @param {number[]} nums* @param {number} k* @return {number[]}*/
function maxSlidingWindow(nums, k) {let result=[]for (let i = 0; i < nums.length - k + 1; i++) {let max = -Infinity;for (let j = i; j < i + k; j++) {max = Math.max(nums[j], max)}result.push(max)}return result
}

2.優化解法(雙端隊列,時間復雜度 O(n))??

算法思路

  1. ?初始化數據結構?:

    • q?數組模擬單調棧,它的作用是存儲數組?nums?中元素的下標,并且保證棧內元素對應的?nums?值從棧底到棧頂是單調遞減的。這樣,棧頂元素對應的?nums?值始終是當前窗口內的最大值(或者候選最大值)。
    • ans?數組用于存儲每個滑動窗口的最大值,最終作為函數的返回結果。
  2. ?遍歷數組過程?:

    • ?維護單調性?:在每次將新元素?nums[i]?考慮加入窗口時,通過?while?循環檢查棧頂元素。如果當前元素?nums[i]?大于等于棧頂元素對應的?nums?值,就不斷彈出棧頂元素。這是因為棧頂元素不可能是當前窗口內的最大值了,通過這樣的操作保證了棧的單調性。
    • ?加入新元素?:將當前元素的下標?i?壓入棧?q?中,以便后續判斷該元素是否在窗口內以及作為可能的最大值候選。
    • ?檢查窗口范圍?:檢查棧頂元素的下標是否已經不在當前窗口范圍內(即小于等于?i - k)。如果是,說明該元素已經隨著窗口的滑動移出了當前窗口,需要將其從棧頂彈出,以確保棧中元素對應的下標都在當前窗口內。
    • ?記錄最大值?:當窗口已經形成(即?i >= k - 1,因為前?k - 1?個元素構不成完整窗口)時,棧頂元素對應的?nums?值就是當前窗口的最大值,將其加入到?ans?數組中。
  3. ?返回結果?:遍歷完整個數組?nums?后,ans?數組中已經存儲了每個滑動窗口的最大值,將其返回。

示例演示

給定的示例?nums = [1, 3, -1, -3, 5, 3, 6, 7]k = 3?為例,詳細演示如何計算滑動窗口最大值的:

初始化

  • 初始化?q?為一個空數組,用于模擬單調棧,存儲數組元素的下標;初始化?ans?為一個空數組,用于存儲每個滑動窗口的最大值。

  • i?初始化為?0,開始遍歷數組?nums

第一次循環 (i = 0)

  • nums[0] = 1,此時?q?為空,將?i = 0?壓入?q,即?q = [0]

  • 因為?q?只有一個元素,它的下標?0?滿足?0 >= 0 - 3(此時窗口還未完全形成,這里條件看似不成立但后續會處理),不執行?q.shift()

  • 由于?i = 0 < 3 - 1,窗口還未形成,不執行?ans.push(nums[q[0]])

第二次循環 (i = 1)

  • nums[1] = 3,因為?3 >= nums[q[q.length - 1]](即?3 >= nums[0]nums[0] = 1),執行?q.pop(),此時?q = [1]

  • 將?i = 1?壓入?qq = [1]

  • 因為?q[0] = 11 < 1 - 3?不成立,不執行?q.shift()

  • 由于?i = 1 < 3 - 1,窗口還未形成,不執行?ans.push(nums[q[0]])

第三次循環 (i = 2)

  • nums[2] = -1,因為?-1 < nums[q[q.length - 1]](即?-1 < nums[1]nums[1] = 3),不執行?q.pop()

  • 將?i = 2?壓入?qq = [1, 2]

  • 因為?q[0] = 11 < 2 - 3?不成立,不執行?q.shift()

  • 由于?i = 2 >= 3 - 1,窗口已經形成,執行?ans.push(nums[q[0]]),即?ans = [3]

第四次循環 (i = 3)

  • nums[3] = -3,因為?-3 < nums[q[q.length - 1]](即?-3 < nums[2]nums[2] = 3),不執行?q.pop()

  • 將?i = 3?壓入?qq = [1, 2, 3]

  • 因為?q[0] = 11 < 3 - 3?不成立,不執行?q.shift()

  • 由于?i = 3 >= 3 - 1,窗口已經形成,執行?ans.push(nums[q[0]]),即?ans = [3, 3]

第五次循環 (i = 4)

  • nums[4] = 5,因為?5 >= nums[q[q.length - 1]](即?5 >= nums[3]nums[3] = -3),執行?q.pop(),此時?q = [1, 2]

  • 因為?5 >= nums[q[q.length - 1]](即?5 >= nums[2]nums[2] = 3),再執行?q.pop(),此時?q = [1]

  • 將?i = 4?壓入?qq = [1]

  • 因為?q[0] = 11 < 4 - 3?不成立,不執行?q.shift()

  • 由于?i = 4 >= 3 - 1,窗口已經形成,執行?ans.push(nums[q[0]]),即?ans = [3, 3, 5]

第六次循環 (i = 5)

  • nums[5] = 3,因為?3 >= nums[q[q.length - 1]](即?3 >= nums[1]nums[1] = 1),執行?q.pop(),此時?q = [5]

  • 將?i = 5?壓入?qq = [5]

  • 因為?q[0] = 55 < 5 - 3?不成立,不執行?q.shift()

  • 由于?i = 5 >= 3 - 1,窗口已經形成,執行?ans.push(nums[q[0]]),即?ans = [3, 3, 5, 5]

第七次循環 (i = 6)

  • nums[6] = 6,因為?6 >= nums[q[q.length - 1]](即?6 >= nums[5]nums[5] = 3),執行?q.pop(),此時?q = [6]

  • 將?i = 6?壓入?qq = [6]

  • 因為?q[0] = 66 < 6 - 3?不成立,不執行?q.shift()

  • 由于?i = 6 >= 3 - 1,窗口已經形成,執行?ans.push(nums[q[0]]),即?ans = [3, 3, 5, 5, 6]

第八次循環 (i = 7)

  • nums[7] = 7,因為?7 >= nums[q[q.length - 1]](即?7 >= nums[6]nums[6] = 6),執行?q.pop(),此時?q = [7]

  • 將?i = 7?壓入?qq = [7]

  • 因為?q[0] = 77 < 7 - 3?不成立,不執行?q.shift()

  • 由于?i = 7 >= 3 - 1,窗口已經形成,執行?ans.push(nums[q[0]]),即?ans = [3, 3, 5, 5, 6, 7]

循環結束

遍歷完整個數組?nums?后,ans?數組中存儲了每個滑動窗口的最大值,最終返回?ans = [3, 3, 5, 5, 6, 7]

代碼實現

var maxSlidingWindow = function(nums, k) {let q = []; // 用于模擬單調棧,存儲數組元素的下標let ans = []; // 用于存儲每個滑動窗口的最大值for (let i = 0; i < nums.length; i++) {// 當棧不為空,并且當前元素大于等于棧頂元素對應的nums值時while (q.length > 0 && nums[i] >= nums[q[q.length - 1]]) {q.pop(); // 彈出棧頂元素,因為它不可能是當前窗口內的最大值了}q.push(i); // 將當前元素的下標壓入棧中// 如果棧頂元素的下標已經不在當前窗口范圍內(即小于等于i - k)if (q[0] <= i - k) {q.shift(); // 彈出棧頂元素,因為它已經不在當前窗口內了}// 當窗口已經形成(即i >= k - 1,因為前k - 1個元素構不成完整窗口)if (i >= k - 1) {ans.push(nums[q[0]]); // 將棧頂元素對應的nums值(也就是當前窗口的最大值)加入到結果數組ans中}}return ans;
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/904968.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904968.shtml
英文地址,請注明出處:http://en.pswp.cn/news/904968.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

01背包類問題

文章目錄 [模版]01背包1. 第一問: 背包不一定能裝滿(1) 狀態表示(2) 狀態轉移方程(3) 初始化(4) 填表順序(5) 返回值 2. 第二問: 背包恰好裝滿3. 空間優化 416.分割等和子集1. 狀態表示2. 狀態轉移方程3. 初始化4. 填表順序5. 返回值 [494. 目標和](https://leetcode.cn/proble…

解鎖 DevOps 新境界 :使用 Flux 進行 GitOps 現場演示 – 自動化您的 Kubernetes 部署

前言 GitOps 是實現持續部署的云原生方式。它的名字來源于標準且占主導地位的版本控制系統 Git。GitOps 的 Git 在某種程度上類似于 Kubernetes 的 etcd&#xff0c;但更進一步&#xff0c;因為 etcd 本身不保存版本歷史記錄。毋庸置疑&#xff0c;任何源代碼管理服務&#xf…

將Docker鏡像變為可執行文件?體驗docker2exe帶來的便捷!

在現代軟件開發中,容器化技術極大地改變了應用程序部署和管理的方式。Docker,作為領先的容器化平臺,已經成為開發者不可或缺的工具。然而,對于不熟悉Docker的用戶來說,接觸和運行Docker鏡像可能會是一個復雜的過程。為了解決這一問題,docker2exe項目應運而生。它提供了一…

IBM BAW(原BPM升級版)使用教程第八講

續前篇&#xff01; 一、流程開發功能模塊使用邏輯和順序 前面我們已經對 流程、用戶界面、公開的自動化服務、服務、事件、團隊、數據、性能、文件各個模塊進行了詳細講解&#xff0c;現在統一進行全面統一講解。 在 IBM Business Automation Workflow (BAW) 中&#xff0c;…

針對共享內存和上述windows消息機制 在C++ 和qt之間的案例 進行詳細舉例說明

針對共享內存和上述windows消息機制 在C++ 和qt之間的案例 進行詳細舉例說明 以下是關于在 C++ 和 Qt 中使用共享內存(QSharedMemory)和 Windows 消息機制(SendMessage / PostMessage)進行跨線程或跨進程通信的詳細示例。 ?? 使用 QSharedMemory 進行進程間通信(Qt 示例…

jetson orin nano super AI模型部署之路(十)使用frp配置內網穿透,隨時隨地ssh到機器

為什么要內網穿透&#xff1f; 我們使用jetson設備時&#xff0c;一般都是在局域網內的電腦去ssh局域網內的jetson設備&#xff0c;但是這種ssh或者VNC僅限于局域網之間的設備。 如果你出差了&#xff0c;或者不在jetson設備的局域網內&#xff0c;想再去ssh或者VNC我們的jet…

VScode密鑰(公鑰,私鑰)實現免密登錄【很細,很全,附帶一些沒免密登錄成功的一些解決方法】

一、 生成SSH密鑰對 ssh-keygen 或者 ssh-keygen -t rsa -b 4096區別&#xff1a;-t rsa可以明確表示生成的是 RSA 類型的密鑰-b參數將密鑰長度設置為 4096 位默認&#xff1a;2048 位密鑰不指定-t參數&#xff0c;ssh -keygen默認也可能生成 RSA 密鑰【確保本機安裝ssh&#…

解釋器和基于規則的系統比較

解釋器&#xff08;Interpreter&#xff09;和基于規則的系統&#xff08;Rule-Based System&#xff09;是兩種不同的軟件架構風格&#xff0c;分別適用于不同的應用場景。它們在設計理念、執行機制和適用領域上有顯著差異。以下是它們的核心對比&#xff1a; 1. 解釋器&#…

DB4S:一個開源跨平臺的SQLite數據庫管理工具

DB Browser for SQLite&#xff08;DB4S&#xff09;是一款開源、跨平臺的 SQLite 數據庫管理工具&#xff0c;用于創建、瀏覽和編輯 SQLite 以及 SQLCipher 數據庫文件。 功能特性 DB4S 提供了一個電子表格風格的數據庫管理界面&#xff0c;以及一個 SQL 查詢工具。DB4S 支持…

printf調試時候正常,運行時打印不出來

問題是在添加了 printf 功能后&#xff0c;程序獨立運行時無法正常打印輸出&#xff0c;而調試模式下正常。這表明問題可能與 printf 的重定向實現、標準庫配置、或編譯器相關設置有關。 解決&#xff1a; 原來是使用 Keil/IAR&#xff0c;printf可能需要啟用 MicroLIB 或正確…

輕松制作高質量視頻,實時生成神器LTX-Video重磅登場!

探索LTX-Video&#xff1a;實時視頻生成跨越新高度 在如今這個視覺內容主導的數字時代&#xff0c;視頻生成成為推動創意表達的關鍵。而今天&#xff0c;我們將帶您深入探索LTX-Video&#xff0c;一個強大的開源項目&#xff0c;致力于通過尖端技術將視頻生成提升到一個全新的…

分布式事務快速入門

分布式事務基本概念 使用分布式事務的場景&#xff1a;分布式場景下的跨數據庫事務 分布式事務誕生的理論&#xff1a;CAP和Base 3種一致性&#xff1a; 強一致性 &#xff1a;系統寫入了什么&#xff0c;讀出來的就是什么。 弱一致性 &#xff1a;不一定可以讀取到最新寫入…

nvme Unable to change power state from D3cold to D0, device inaccessible

有個thinkpad l15 gen4筆記本&#xff0c;使用較少&#xff0c;有一塊三星m2和東芝14t硬盤&#xff0c;想安裝飛牛nas系統作為家庭照片庫&#xff0c;制作飛牛啟動盤&#xff0c;發現安裝飛牛需要全盤格式化&#xff0c;電腦本身的系統還是需要保留的&#xff0c;故想到再安裝一…

Unity Shaders and Effets Cookbook

目錄 作者簡介 審稿人簡介 前言 我是偏偏 Unity Shaders and Effets Cookbook 第一章&#xff1a;Diffuse Shading - 漫反射著色器 第二章&#xff1a;Using Textures for Effects - 著色器紋理特效的應用 第三章&#xff1a;Making Your Game Shine with Specular - 鏡…

部署RocketMQ

部署環境&#xff1a;jdk8以上&#xff0c;Linux系統 下載和安裝指令&#xff1a; wget https://archive.apache.org/dist/rocketmq/4.9.4/rocketmq-all-4.9.4-bin-release.zip 顯示下載成功&#xff1a; --2025-05-10 11:34:46-- https://archive.apache.org/dist/rocketm…

使用FastAPI和React以及MongoDB構建全棧Web應用04 MongoDB快速入門

一、NoSQL 概述 1.1 了解關系數據庫的局限性 Before diving into NoSQL, it’s essential to understand the challenges posed by traditional Relational Database Management Systems (RDBMS). While RDBMS have been the cornerstone of data management for decades, th…

高精度之加減乘除之多解總結(加與減篇)

開篇總述&#xff1a;精度計算的教學比較雜亂&#xff0c;無系統的學習&#xff0c;且存在同法多線的方式進行同一種運算&#xff0c;所以我寫此篇的目的只是為了直指本質&#xff0c;不走教科書方式&#xff0c;步驟冗雜。 一&#xff0c;加法 我在此講兩種方法&#xff1a; …

氣象大模型光伏功率預測中的應用:從短期,超短期,中長期的實現與開源代碼詳解

1. 引言 光伏功率預測對于電力系統調度、能源管理和電網穩定性至關重要。隨著深度學習技術的發展,大模型(如Transformer、LSTM等)在時間序列預測領域展現出強大能力。本文將詳細介紹基于大模型的光伏功率預測方法,涵蓋短期(1-6小時)、超短期(15分鐘-1小時)和中長期(1天-1周…

玩轉Docker(一):基本概念

容器技術是繼大數據和云計算之后又一炙手可熱的技術&#xff0c;而且未來相當一段時間內都會非常流行。 本文將對其基本概念和基本使用做出介紹。包括容器生態系統、容器的原理、怎樣運行第一個容器、容器技術的概念與實踐、Docker鏡像等等 目錄 一. 鳥瞰容器生態系統 1. 容器…

計算機視覺與深度學習 | 基于數字圖像處理的裂縫檢測與識別系統(matlab代碼)

???????????????????????????????? 基于數字圖像處理的裂縫檢測與識別系統 ??????????????????????????**系統架構設計****1. 圖像預處理**目標:消除噪聲+增強裂縫特征**2. 圖像分割**目標:提取裂縫區域**3. 特征…