240422 leetcode exercises

240422 leetcode exercises

@jarringslee

文章目錄

  • 240422 leetcode exercises
    • [237. 刪除鏈表中的節點](https://leetcode.cn/problems/delete-node-in-a-linked-list/)
      • 🔁節點覆蓋法
    • [392. 判斷子序列](https://leetcode.cn/problems/is-subsequence/)
      • 🔁直接遍歷
      • 🔁動歸預處理
    • [LCR 136. 刪除鏈表的節點](https://leetcode.cn/problems/shan-chu-lian-biao-de-jie-dian-lcof/)
      • 🔁直接遍歷

237. 刪除鏈表中的節點

有一個單鏈表的 head,我們想刪除它其中的一個節點 node

給你一個需要刪除的節點 node 。你將 無法訪問 第一個節點 head

鏈表的所有值都是 唯一的,并且保證給定的節點 node 不是鏈表中的最后一個節點。

刪除給定的節點。注意,刪除節點并不是指從內存中刪除它。這里的意思是:

  • 給定節點的值不應該存在于鏈表中。
  • 鏈表中的節點數應該減少 1。
  • node 前面的所有值順序相同。
  • node 后面的所有值順序相同。

? 他是想說什么意思呢,就是在不給你整個鏈表的情況下,讓你根據這個值來將這個節點刪除。

? 題目要求我們的函數被調用后輸出整個鏈表,而我們又注意到所寫函數是void類型,所以我們只需要執行刪除該節點的操作即可。

? 如果毫無思路,我們可以回憶一下刪除鏈表的原理:

讓上一個結點的next指針直接指向下一個節點。

? 由于我們需要對鏈表進行遍歷,才能獲得前驅指針并執行上述操作。但是這里我們根本無法獲取前驅指針。但是我們寫的函數又不需要我們返回鏈表,所以如果讓當前節點的值直接變成下一結點的值,也就是覆蓋下一個節點,是不是就等價于刪除了當前節點呢?

🔁節點覆蓋法

假設鏈表在內存中是這樣的(箭頭表示 next 指針):

 → [ A | * ] → [ B | * ] → [ C | * ] → …↑題目給出的node
  • [A|*] 表示當前節點的 val = Anext 指向下一個節點。
  • node 指針正指向值為 A 的節點,我們刪掉它。
void deleteNode(struct ListNode* node) {*node = *node -> next; //哈哈就一行。
}

這一行等價于同時做了兩件事:

node->val  = node->next->val;    // 把后繼節點的值 B 復制到當前節點
node->next = node->next->next;   // 把后繼節點的 next 指針復制過來

我們看看這個操作帶來了什么樣的影響:

  • 操作前

    [ A | -> X ]   [ B | -> Y ]node           next_node
    
    • node->val = A
    • node->next 指向下一個節點(值 B)
  • 執行 *node = *node->next;

    • node->val 變成了 B
    • node->next 變成了 node->next->next(即原來 B 的 next,指向 C)
  • 操作后

    [ B | -> Y ]   [ B | -> Y ]  node         (原 B 節點,已被孤立)
    

    現在的鏈表里,從 …→node 開始

    … → [ B | * ] → [ C | * ] → …
    

    ——等價于把原來的 B 節點直接「搬到」A 的位置,然后把原 B 節點從鏈表里跳過去了。

? 這道題通過 復制后繼節點 到當前節點,再跳過后繼,實現了在不知道前驅的情況下刪除節點的目標。關鍵一句 *node = *node->next;,相當于同時做了賦值 val 和重連 next,從鏈表邏輯上刪掉了下一節點。

? 我簡直是天才。

392. 判斷子序列

給定字符串 st ,判斷 s 是否為 t 的子序列。

字符串的一個子序列是原始字符串刪除一些(也可以不刪除)字符而不改變剩余字符相對位置形成的新字符串。(例如,"ace""abcde"的一個子序列,而"aec"不是)。

進階:

如果有大量輸入的 S,稱作 S1, S2, … , Sk 其中 k >= 10億,你需要依次檢查它們是否為 T 的子序列。在這種情況下,你會怎樣改變代碼?

示例 1:

輸入:s = "abc", t = "ahbgdc"
輸出:true

示例 2:

輸入:s = "axc", t = "ahbgdc"
輸出:false

? 乍一看以為是包含字符串的問題,結果仔細一看,發現如果子序列的所有字符能被給出序列順序地包含就符合條件。那么單次遍歷的話就會簡單很多。

🔁直接遍歷

直接建立循環直接進行比較。

bool isSubsequence(char* s, char* t) {if (s[0] == '\0') return true;//排除空字符串情況int i = 0;for (int j = 0; t[j] != '\0'; j++){ //外循環移動大串if (s[i] == t[j]) i++;//如果發現該位置與小串相等,小串移動if (s[i] == '\0') return true;//循環內移動完了就成功}return false;
}

?

? 但是題目又說, “當 t 很長、要對它執行大量(10億)子序列判斷查詢”,在這種變態情況下,我們想剛才那樣愚蠢地遍歷好像是有點笨拙了。但倘若我預處理目標串 t,一次性記錄好從每個位置往后字符 a…z 下次出現的位置,然后再用這個表快速「跳躍式」地在 t 中定位每個要匹配的 s[j],閣下又該如何應對?

🔁動歸預處理

1. What is nxt?

? 我們使用 (n+1)×26 的二維整型數組,用來存儲 “從位置 i 開始,字母 'a'+c 下一次出現的位置”(其中 0 ≤ i ≤ n0 ≤ c < 26)。

? nxt[i][c] 的含義是,在字符串 t 中,從下標 i(包含)往后,第一個字符等于 'a'+c 的位置索引;
如果再也不出現,即t 中再也沒有字符 ('a'+c),我們就把它設為 n(一個「越界」值)。

int (*nxt)[SIGMA] = malloc((n + 1) * sizeof(int[SIGMA]));

? 如果 t 中再也沒有字符 ('a'+c),我們就把它設為 n(一個「越界」值)。

? 這樣,查找 “從位置 i 往后,‘x’ 下次出現在哪里” 就只需要讀 nxt[i]['x'-'a'] 一次,時間 O(1)。

2. 構造 nxt

  1. 初始化末尾行

    for (int j = 0; j < SIGMA; j++) {nxt[n][j] = n;
    }
    

    位置 n 之后沒有任何字符,所有字母的「下次出現」都標記為 n

  2. 自底向上填表

    for (int i = n - 1; i >= 0; i--) {// 先拷貝后一行:默認后續出現位置和 i+1 一樣memcpy(nxt[i], nxt[i + 1], SIGMA * sizeof(int));// 然后把 t[i] 這一個字符的“下次出現”位置修正為 i 自己nxt[i][t[i] - 'a'] = i;
    }
    
    • “如果我在 i+1 后面第一次見到 c,位置是誰?” → nxt[i+1][c]

    • “但如果 t[i] 本身就是 c,就應該最近出現的位置是 i” → 覆蓋 nxt[i][c] = i

    • 最終,nxt[0][c] 恰好告訴我們「整個串中第一次出現 c 的位置」。

3. 用 nxt 快速匹配子序列

int i = -1;
for (int j = 0; s[j] && i < n; j++) {// 在 t 中,從 i+1 開始,尋找 s[j] 下一個出現的位置i = nxt[i + 1][s[j] - 'a'];
}
return i < n;

我們用 i 記錄上一次匹配到 t 的哪個位置。若初始 i = -1,表示還沒匹配過任何字符;要找下一個,就從 i+1 = 0 開始搜。對于對每個 s[j],我們先計算 c = s[j]-'a',再讀 pos = nxt[i+1][c]

如果 pos < n,說明在 t 中找到了,就把 i = pos,繼續下一個 s[j+1]

如果 pos == n,說明找不到,就會讓 i >= n ,循環后自然跳出,最后 return false

整個過程只做了 |s| 步 O(1) 的跳躍查詢,匹配結束后檢查 i < n 即可判斷 s 是否完全匹配為子序列。

時間和空間復雜度

  • 預處理
    • 時間:構造 nxt 需要做 n+1 行,每行拷貝 26 個整數 → O(26·n) ≈ O(n)。
    • 空間:存 (n+1)×26int → O(n·Σ),這里 Σ=26。
  • 匹配階段
    • 時間:遍歷 s 一次,每步 O(1) 查表 → O(|s|)。

對于極多次查詢同一個 t 是否包含不同 s 的變態情況,這種預處理 + 跳表的方法尤其高效。

LCR 136. 刪除鏈表的節點

給定單向鏈表的頭指針和一個要刪除的節點的值,定義一個函數刪除該節點。

返回刪除后的鏈表的頭節點。

示例 1:

輸入:head = [4,5,1,9], val = 5
輸出:[4,1,9]
解釋:給定你鏈表中值為 5 的第二個節點,那么在調用了你的函數之后,該鏈表應變為 4 -> 1 -> 9.

示例 2:

輸入:head = [4,5,1,9], val = 1
輸出:[4,5,9]
解釋:給定你鏈表中值為 1 的第三個節點,那么在調用了你的函數之后,該鏈表應變為 4 -> 5 -> 9.

? 我們使用前去節點遍歷的方法來找到需要刪除的值。

🔁直接遍歷

? 首先去掉目標只在頭結點的情況。

? 我們讓前驅指針在下個節點的指針不指向空下個節點的值不等于目標值的情況下向前移動,在題目保證數據的情況下,一定會在指針走向盡頭之前因為找到目標值而跳出這個循環。這時候我們讓前驅指針所在的節點的next指針直接指向下一個節點的next指針,也就是下下一個節點的地址。

struct ListNode* deleteNode(struct ListNode* head, int val) {if (head -> val == val) return head -> next;struct ListNode* prev = head;
//不滿足條件就遍歷while( (prev -> next != NULL) && (prev -> next -> val != val)) prev = prev -> next;
//找到目標值就刪if (prev -> next != NULL) prev -> next = prev -> next -> next; return head;
}

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

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

相關文章

MYSQL之庫的操作

創建數據庫 語法很簡單, 主要是看看選項(與編碼相關的): CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specification: [DEFAULT] CHARACTER SET charset_name [DEFAULT] COLLATE collation_name 1. 語句中大寫的是…

Git Flow分支模型

經典分支模型(Git Flow) 由 Vincent Driessen 提出的 Git Flow 模型,是管理 main(或 master)和 dev 分支的經典方案: main 用于生產發布,保持穩定; dev 用于日常開發,合并功能分支(feature/*); 功能開發在 feature 分支進行,完成后合并回 dev; 預發布分支(rele…

【Spring】依賴注入的方式:構造方法、setter注入、字段注入

在Spring框架中&#xff0c;除了構造器注入&#xff08;Constructor Injection&#xff09;和Setter注入&#xff08;Setter Injection&#xff09;&#xff0c;還有一種依賴注入方式&#xff1a;字段注入&#xff08;Field Injection&#xff09;。字段注入通過在Bean的字段上…

【數學建模】隨機森林算法詳解:原理、優缺點及應用

隨機森林算法詳解&#xff1a;原理、優缺點及應用 文章目錄 隨機森林算法詳解&#xff1a;原理、優缺點及應用引言隨機森林的基本原理隨機森林算法步驟隨機森林的優點隨機森林的缺點隨機森林的應用場景Python實現示例超參數調優結論參考文獻 引言 隨機森林是機器學習領域中一種…

HttpSessionListener 的用法筆記250417

HttpSessionListener 的用法筆記250417 以下是關于 HttpSessionListener 的用法詳解&#xff0c;涵蓋核心方法、實現步驟、典型應用場景及注意事項&#xff0c;幫助您全面掌握會話&#xff08;Session&#xff09;生命周期的監聽與管理&#xff1a; 1. 核心功能 HttpSessionLi…

【Python爬蟲基礎篇】--2.模塊解析

目錄 1.urllib庫 1.1.request模塊 1.1.1、urllib.request.urlopen() 函數 1.1.2.urllib.request.urlretrieve() 函數 1.2. error模塊 1.3. parse 模塊 2. BeautifulSoup4庫 2.1.對象種類 2.2.對象屬性 2.2.1.子節點 2.2.2.父節點 2.2.3.兄弟節點 2.2.4.回退和前進 …

Ubuntu-Linux從桌面到顯示的全流程:技術分析總結

引言 Ubuntu作為主流的Linux發行版&#xff0c;其顯示系統經歷了從傳統X11到現代Wayland的演進。本文將詳細分析從應用程序到屏幕顯示的完整技術流程&#xff0c;包括桌面環境、顯示服務器、圖形棧和硬件交互等核心環節。 1. 系統架構概覽 Ubuntu的顯示系統架構可分為四個主要…

在PyCharm中部署AI模型的完整指南

引言 隨著人工智能技術的快速發展,越來越多的開發者開始將AI模型集成到他們的應用程序中。PyCharm作為一款強大的Python IDE,為AI開發提供了出色的支持。本文將詳細介紹如何在PyCharm中部署AI模型,從環境配置到最終部署的完整流程。 第一部分:準備工作 1. 安裝PyCharm …

WHAT - 靜態資源緩存穿透

文章目錄 1. 動態哈希命名的基本思路2. 具體實現2.1 Vite/Webpack 配置動態哈希2.2 HTML 文件中動態引用手動引用使用 index.html 模板動態插入 2.3 結合 Cache-Control 避免緩存穿透2.4 適用于多環境的動態策略 總結 在多環境部署中&#xff0c;靜態資源緩存穿透是一個常見問題…

PoCL環境搭建

PoCL環境搭建 **一.關鍵功能與優勢****二.設計目的****三.測試步驟**1.創建容器2.安裝依賴3.編譯安裝pocl4.運行OpenCL測試程序 Portable Computing Language (PoCL) 簡介 Portable Computing Language (PoCL) 是一個開源的、符合標準的異構計算框架&#xff0c;旨在為 OpenCL…

【區塊鏈技術解析】從原理到實踐的全鏈路指南

目錄 前言&#xff1a;技術背景與價值當前技術痛點解決方案概述目標讀者說明 一、技術原理剖析核心概念圖解核心作用講解關鍵技術模塊技術選型對比 二、實戰演示環境配置要求核心代碼實現&#xff08;10個案例&#xff09;案例1&#xff1a;創建簡單區塊鏈案例2&#xff1a;工作…

在Windows上安裝Git

一、安裝 Git 下載 Git地址&#xff1a;Git - Downloads (git-scm.com) 1、在頁面中找到適用于 Windows 系統的最新版本安裝包&#xff08;通常為.exe 格式文件&#xff09;&#xff0c;點擊下載鏈接。 出于訪問Git官網需要科學上網&#xff0c;不會的可以私信我要軟件包&…

Golang interface總結(其一)

本篇是對golang 中的interface做一些淺層的、實用的總結 多態 常用場景 interface內僅包含函數類型&#xff0c;然后定義結構體去實現&#xff0c;如下 package mainimport "fmt"type Animal interface {Sound()Act() }type Cat struct{}func (c *Cat) Sound() {…

TVM計算圖分割--Collage

1 背景 為滿足高效部署的需要&#xff0c;整合大量優化的tensor代數庫和運行時做為后端成為必要之舉。現在的深度學習后端可以分為兩類&#xff1a;1&#xff09;算子庫(operator kernel libraries)&#xff0c;為每個DL算子單獨提供高效地低階kernel實現。這些庫一般也支持算…

Redis——內存策略

目錄 前言 1.過期策略 1.1過期策略——DB結構 1.2過期策略——惰性刪除 1.3過期策略——定期刪除 2.淘汰策略 2.1最少最近使用和使用頻率原理 2.2內存淘汰策略執行流程 總結&#xff1a; 前言 Redis之所以性能強&#xff0c;主要的原因就是基于內存存儲。然而單節點的R…

原型模式詳解及在自動駕駛場景代碼示例(c++代碼實現)

模式定義 原型模式&#xff08;Prototype Pattern&#xff09;是一種創建型設計模式&#xff0c;通過克隆已有對象來創建新對象&#xff0c;避免重復執行昂貴的初始化操作。該模式特別適用于需要高效創建相似對象的場景&#xff0c;是自動駕駛感知系統中處理大量重復數據結構的…

在kali中安裝AntSword(蟻劍)

步驟一、下載壓縮包 源碼&#xff1a;https://github.com/AntSwordProject/antSword&#xff0c;下載壓縮包。 加載器&#xff1a;https://github.com/AntSwordProject/AntSword-Loader&#xff0c;根據系統選擇壓縮包&#xff08;kali選擇AntSword-Loader-v4.0.3-linux-x64&…

華為倉頡編程語言基礎概述

第一章&#xff1a;技術演進與誕生背景 1.1 萬物智聯時代的編程挑戰 在5G、物聯網、邊緣計算等技術推動下&#xff0c;全球智能設備數量呈指數級增長。據IDC預測&#xff0c;2025年全球IoT設備將突破550億臺&#xff0c;這對系統級編程語言提出新要求&#xff1a; 異構硬件兼…

【Linux篇】探索進程間通信:如何使用匿名管道構建高效的進程池

從零開始&#xff1a;通過匿名管道實現進程池的基本原理 一. 進程間通信1.1 基本概念1.2 通信目的1.3 通信種類1.3.1 同步通信1.3.2 異步通信 1.4 如何通信 二. 管道2.1 什么是管道2.2 匿名管道2.2.1 pipe()2.2.2 示例代碼&#xff1a;使用 pipe() 進行父子進程通信2.2.3 管道容…

【LeetCode】嚼爛熱題100【持續更新】

2、字母異位詞分組 方法一&#xff1a;排序哈希表 思路&#xff1a;對每個字符串排序&#xff0c;排序后的字符串作為鍵插入到哈希表中&#xff0c;值為List<String>形式存儲單詞原型&#xff0c;鍵為排序后的字符串。 Map<String, List<String>> m new Ha…