【1.1】動態規劃求解不同的子序列

一、題目

給定一個字符串s和一個字符串t,計算在s的子序列中t出現的個數。
字符串的一個子序列是指,通過刪除一些(也可以不刪除)字符且不干擾剩余字符相對位置
所組成的新字符串。(例如,"ACE"是"ABCDE"的一個子序列,而"AEC"不是)
題目數據保證答案符合32位帶符號整數范圍。

提示:
1)0<=s . length, t. length<=1000
2)s和t由英文字母組成

二、求解思路

動態規劃解決思路

????????s的子序列中出現t的個數,其實就是字符串s的所有子序列中,和字符串t完全一樣的有多少個。
????????我們定義dp[i][ j]表示t的前i個字符可以由s的前j個字符組成的個數(也可以說是字符串s 的前j個字符組成的子序列中,和字符串t 的前i個字符組成的字符串一樣的有多少個)。
????????那么最終我們只需要求出dp[tLength][ sLength]即可(其中tLength和sLength分別表示字符串t和s的長度)。
????????如果字符串t的第i個字符和字符串s的第j個字符一樣,如下所示

????????如上圖所示我們可以有兩種選擇。
????????如果字符串t的第i個字符和字符串s的第j個字符不一樣,也就是說字符串s的第j個字符不能匹配字符串t的第i個字符。

????????那么我們只能計算字符串s的前j -1個字符構成的子序列中包含字符串t的前i個字符組成的字符串的個數。

????????動態規劃的三個步驟就是定義狀態,列出遞推公式,找出邊界條件。

詳細過程:

????????我們可以定義二維數組 dp[i][j],其中 dp[i][j] 表示字符串 t 的前 i 個字符可以由字符串 s 的前 j 個字符組成的子序列的個數。這里,i 的取值范圍是 0tLength(包括),j 的取值范圍是 0sLength(包括),并且 tLengthsLength 分別是字符串 ts 的長度。

初始化時,我們有:

  • dp[0][j] = 1,對于所有 j(包括 j = 0),因為空字符串 ts 的任何子序列。
  • dp[i][0] = 0,對于所有 i > 0,因為 s 的空子序列不包含任何字符,所以無法與 t 的任何非空前綴匹配。

接下來,我們考慮 dp[i][j] 的狀態轉移方程。有兩種情況:

  1. 如果 t[i-1] == s[j-1](注意字符串索引是從0開始的,所以我們用 i-1j-1 來訪問實際字符),那么 dp[i][j] 可以由 dp[i-1][j-1](即 t 的前 i-1 個字符與 s 的前 j-1 個字符組成的子序列個數)加上 dp[i][j-1](即不選擇 s[j-1] 時,t 的前 i 個字符可以由 s 的前 j-1 個字符組成的子序列個數)組成。這是因為我們可以選擇將 s[j-1] 包含在當前子序列中(如果它與 t[i-1] 匹配),也可以選擇不包含它。
  2. 如果 t[i-1] != s[j-1],那么 dp[i][j] 只能由 dp[i][j-1] 轉移而來,因為我們不能選擇 s[j-1] 來匹配 t[i-1]

用數學公式表示狀態轉移方程,我們有:

三、代碼實現

C代碼實現

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 函數 numDistinct 計算字符串 s 中包含字符串 t 作為子序列的不同子序列的數量。
int numDistinct(const char *s, const char *t) {// 獲取兩個字符串的長度int sLength = strlen(s);int tLength = strlen(t);// 為動態規劃表分配內存空間int **dp = (int **)malloc((tLength + 1) * sizeof(int *));for (int i = 0; i <= tLength; i++) {dp[i] = (int *)malloc((sLength + 1) * sizeof(int));memset(dp[i], 0, (sLength + 1) * sizeof(int)); // 初始化為0}// 基礎情況初始化,空字符串是任何字符串的子序列,所以初始化為 1for (int j = 0; j <= sLength; j++) {dp[0][j] = 1;}// 填充動態規劃表for (int i = 1; i <= tLength; i++) {for (int j = 1; j <= sLength; j++) {// 如果 t 的第 i 個字符和 s 的第 j 個字符相同if (t[i - 1] == s[j - 1]) {// 有兩種選擇:// 1. 使用 s[j-1] 來匹配 t[i-1] (dp[i-1][j-1])// 2. 不使用 s[j-1] (dp[i][j-1])dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];} else {// 如果 t 的第 i 個字符和 s 的第 j 個字符不同// 只能選擇不使用 s[j-1]dp[i][j] = dp[i][j - 1];}}}// 保存結果int result = dp[tLength][sLength];// 釋放動態規劃表的內存空間for (int i = 0; i <= tLength; i++) {free(dp[i]);}free(dp);// 返回 t 在 s 中作為子序列出現的總次數return result;
}int main() {const char *s = "rabbbit";const char *t = "rabbit";printf("The number of distinct subsequences is: %d\n", numDistinct(s, t));return 0;
}

在這段代碼中:

  • 使用 mallocmemset 函數分配和初始化動態規劃表 dp 的內存。
  • 動態規劃表的行 dp[i] 表示字符串 t 的前 i 個字符在字符串 s 的前 j 個字符中作為子序列出現的次數。
  • 在計算完成后,使用 free 釋放動態規劃表 dp 的內存。
  • main 函數提供了一個簡單的測試用例來演示函數的使用。

C++代碼實現

#include <vector>
#include <string>// 函數 numDistinct 計算字符串 s 中包含字符串 t 作為子序列的不同子序列的數量。
int numDistinct(const std::string& s, const std::string& t) {// 獲取兩個字符串的長度int sLength = s.length();int tLength = t.length();// 使用 vector 構建二維動態規劃表 dp// dp[i][j] 表示 t 的前 i 個字符可以在 s 的前 j 個字符中出現的次數std::vector<std::vector<int>> dp(tLength + 1, std::vector<int>(sLength + 1, 0));// 基礎情況初始化,空字符串是任何字符串的子序列,所以初始化為 1for (int j = 0; j <= sLength; j++) {dp[0][j] = 1;}// 填充動態規劃表for (int i = 1; i <= tLength; i++) {for (int j = 1; j <= sLength; j++) {// 如果 t 的第 i 個字符和 s 的第 j 個字符相同if (t[i - 1] == s[j - 1]) {// 有兩種選擇:// 1. 使用 s[j-1] 來匹配 t[i-1] (dp[i-1][j-1])// 2. 不使用 s[j-1] (dp[i][j-1])dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];} else {// 如果 t 的第 i 個字符和 s 的第 j 個字符不同// 只能選擇不使用 s[j-1]dp[i][j] = dp[i][j - 1];}}}// 返回 t 在 s 中作為子序列出現的總次數return dp[tLength][sLength];
}

在這段代碼中:

  • std::vector<std::vector<int>> dp 創建了一個二維動態數組來存儲中間結果。
  • dp[i][j] 表示字符串 t 的前 i 個字符在字符串 s 的前 j 個字符中作為子序列出現的次數。
  • 初始化 dp[0][j]1,因為空字符串是任何字符串的子序列。
  • 循環遍歷 ts,根據當前字符是否匹配,更新 dp 表。
  • 最終返回 dp[tLength][sLength],它包含了 t 作為 s 的子序列的出現次數。

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

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

相關文章

6.2、函數的定義

代碼 #include <iostream> using namespace std; #include <string>//函數定義//語法&#xff1a;//返回值類型 函數名(參數列表) {函數體語句 return表達式}//加法函數 int add(int num1, int num2) {int sum num1 num2;return sum; } int main() {cout <&l…

SpringBoot異步接口實現 提升吞吐量

前言 Servlet 3.0之前&#xff1a;HTTP請求由單一線程處理。Servlet 3.0之后&#xff1a;支持異步處理&#xff0c;提高系統吞吐量。 SpringBoot 異步接口實現方式 AsyncContext&#xff1a;Servlet層級&#xff0c;不常用。Callable&#xff1a;使用java.util.concurrent.C…

聊聊Redis持久化策略RDB

寫在文章開頭 為避免服務器宕機著情況導致redis內存數據庫數據丟失&#xff0c;redis默認出通過rdb保證可靠性&#xff0c;本文將從源碼的角度帶讀者了解rdb讀寫時機和寫入流程。 Hi&#xff0c;我是 sharkChili &#xff0c;是個不斷在硬核技術上作死的 java coder &#xff…

刷代碼隨想錄有感(124):動態規劃——最長公共子序列

題干&#xff1a; 代碼&#xff1a; class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {vector<vector<int>>dp(nums1.size() 1, vector<int>(nums2.size() 1, 0));int res 0;for(int i 1; i <…

數據集采樣策略對模型性能的影響問題

數據集采樣策略對模型性能的影響問題&#xff0c;需要具體代碼示例 隨著機器學習和深度學習的快速發展&#xff0c;數據集的質量和規模對于模型性能的影響變得越來越重要。在實際應用中&#xff0c;我們往往面臨著數據集規模過大、樣本類別不平衡、樣本噪聲等問題。這時&#…

uni.showShareMenu({}) 和 uni.showShareImageMenu({}) 的區別

ChatGPT uni.showShareMenu({}) 和 uni.showShareImageMenu({}) 是 Uni-app 中兩個不同的 API&#xff0c;它們的作用和用法有所不同&#xff1a; uni.showShareMenu({}) 作用&#xff1a;用于顯示當前頁面的分享菜單&#xff0c;通常顯示在頁面的右上角&#xff08;類似于微…

lnternet 發展史

一&#xff0c;lnternet 發展史 ARPA net &#xff08;上世紀50年代二戰結束&#xff09; 無線 戰場指揮通信協議落后 TCP/IP 包交換 WEB (70年代 ) 80年代 90年代 二&#xff0c;互聯網的典型應用&#xff1a; 96年到2008年 第一代技術…

AJAX的概述 ,同步和異步的區別 ,AJAX 的交互模型和傳統交互模型的區別

一. AJAX的概述 1.1 什么是ajax 同步&#xff1a; 異步&#xff1a; 1.AJAX Asynchronous JavaScript and XML&#xff08;異步的 JavaScript 和 XML&#xff09;。 ? 說明&#xff1a;異步&#xff1a;就是不同步。例如我們向后臺發送請求&#xff0c;同步的方式是后臺必…

日語筆記——jy

敬語尊敬自兼丁寧するされるいたすします先生が詳細に説明されるご説明いたします説明しますいうおっしゃる申す言うお名まえはなんとおっしゃいますかほかのことは申すまでもない親の言う事をよく聞く行くいらっしゃる參る行きます先生もいらっしゃるのですかご一緒に參りまし…

Node.js學習路線

Node.js是一個基于Chrome V8引擎的JavaScript運行環境&#xff0c;它允許JavaScript在服務器端運行。Node.js的核心內容和高階內容涵蓋了多個方面&#xff0c;以下是對Node.js的詳細解析、核心內容以及高階內容的歸納&#xff1a; 一、Node.js簡介 運行環境&#xff1a;Node.…

svn忽略上傳文件node_modules文件

文章目錄 1.點擊svn項目右鍵-》選中svn的屬性2. 點擊 新建3. 點擊其他4. 選擇屬性 svn:global-ignores5. 輸入忽略文件 1.點擊svn項目右鍵-》選中svn的屬性 2. 點擊 新建 3. 點擊其他 4. 選擇屬性 svn:global-ignores 5. 輸入忽略文件

四、【源碼】Bean屬性注入

源碼地址&#xff1a;https://github.com/spring-projects/spring-framework 倉庫地址&#xff1a;https://gitcode.net/qq_42665745/spring/-/tree/04-porperty-inject Bean屬性注入 屬性注入相關的類 1.PropertyValue&#xff1a;屬性對象&#xff0c;name:value 2.Prope…

【Asterinas】Asterinas 進程啟動與切換

Asterinas 進程啟動與切換 進程啟動 進程創建&#xff1a; Rust pub fn spawn_user_process( executable_path: &str, argv: Vec, envp: Vec, ) -> Result<Arc> { // spawn user process should give an absolute path debug_assert!(executable_path.starts_with…

數據結構 —— 二叉樹

1.樹的概念及結構 1.1樹的概念 樹是一種非線性的數據結構&#xff0c;它有著多分支&#xff0c;層次性的特點。 由于其形態類似于自然界中倒過來的數&#xff0c;所以我們將這種數據結構稱為“樹形結構” 注意&#xff1a; 樹形結構中&#xff0c;子樹之間不能有交集&#x…

降重工具大揭秘:AI如何幫你輕松搞定論文重寫?

已經天臨五年了&#xff0c;大學生們還在為論文降重煩惱……手動降重確實是個難題&#xff0c;必須要先付點小經費去靠譜的網站查重&#xff0c;再對著紅字標注去改&#xff0c;后面每一次的論文呢查重結果都像賭//博&#xff0c;誰也不知道明明是同一篇文章&#xff0c;第二次…

2024鯤鵬昇騰創新大賽集訓營Ascend C算子學習筆記

異構計算架構&#xff08;CANN&#xff09; 對標英偉達的CUDA CuDNN的核心軟件層&#xff0c;向上支持多種AI框架&#xff0c;向下服務AI處理器&#xff0c;發揮承上啟下的關鍵作用&#xff0c;是提升昇騰AI處理器計算效率的關鍵平臺。主要包括有各種引擎、編譯器、執行器、算…

(番外篇)指針的一些相關習題講解(速進,干貨滿滿)(2)

前言&#xff1a; 小編感覺最近有點太墮落&#xff0c;于是我開始從事這篇文章的撰寫&#xff0c;現在也是進入七月份了&#xff0c;我現在文章開頭定一個小目標&#xff0c;我決定在七月份發布至少十篇文章&#xff0c;希望我可以說到做到&#xff08;我前面就口頭欠了不少文章…

OpenSSL的一些使用案例

目錄 一、介紹 二、基本使用 1、Shell &#xff08;1&#xff09;文件加解密 &#xff08;2&#xff09;生成密鑰文件 2、API &#xff08;1&#xff09;md5sum &#xff08;2&#xff09;AES256加解密 一、介紹 本篇博客重點不是詳細描述 OpenSSL 的用法&#xff0c;只…

什么是校園氣象站

在科技日新月異的今天&#xff0c;氣象觀測不僅局限于專業的氣象機構&#xff0c;它已經走進了我們的校園&#xff0c;成為了學生們探索自然、學習科學知識的重要平臺。 校園氣象站是設置在學校內部&#xff0c;用于進行氣象觀測、數據記錄和科學實驗的設施。它通常由氣象傳感器…

MySQL之應用層優化和備份與恢復(一)

應用層優化 緩存 作為基礎組件的緩存 緩存有可能成為基礎設施的重要組成部分。也很容易陷入一個陷阱&#xff0c;認為緩存雖然很好用&#xff0c;但并不是重要到非有不可得東西。你也許會辯駁&#xff0c;如果緩存服務器宕機或者緩存被清空&#xff0c;請求也可以直接落在數…