Java C++ 算法leetcode828統(tǒng)計(jì)子串中唯一字符乘法原理
題目要求


思路:模擬
解題的核心思想在于逆向思維,不考慮每個(gè)子數(shù)組中的唯一字符個(gè)數(shù),轉(zhuǎn)而考慮每個(gè)字符可以作為多少個(gè)子數(shù)組的唯一字符;
- 所以在計(jì)算答案時(shí)的算式和示例中給出的是不一樣的;
- 在計(jì)算每個(gè)字符“貢獻(xiàn)”【即當(dāng)前向左向右分別可組成的答案?jìng)€(gè)數(shù)】的時(shí)候要用到乘法原理。
對(duì)每一個(gè)字符s[i]s[i]s[i]都記錄其左邊和右邊的第一個(gè)相同字符位置,分別記為l[i]l[i]l[i]和r[i]r[i]r[i],這兩個(gè)位置中間構(gòu)成的就是s[i]s[i]s[i]能夠作為唯一字符的最長(zhǎng)子串,在這個(gè)最長(zhǎng)的子串中還有若干個(gè)較短的子串,此時(shí)s[i]s[i]s[i]的“貢獻(xiàn)”可由到左邊和到右邊的距離相乘計(jì)算得出。

java
class Solution {
public int uniqueLetterString(String s) {
char[] cs = s.toCharArray();
int n = cs.length, res = 0;
int[] l = new int[n], r = new int[n];
int[] letters = new int[26];
Arrays.fill(letters, -1);
for (int i = 0; i < n; i++) {
int idx = cs[i] - 'A';
l[i] = letters[idx]; // 左邊第一個(gè)相同的字符所在位置
letters[idx] = i; // 更新當(dāng)前字母最新左位置
}
Arrays.fill(letters, n);
for (int i = n - 1; i >= 0; i--) {
int idx = cs[i] - 'A';
r[i] = letters[idx]; // 右邊第一個(gè)相同的字符所在位置
letters[idx] = i; // 更新當(dāng)前字母最新右位置
}
for (int i = 0; i < n; i++)
res += (i - l[i]) * (r[i] - i);
return res;
}
}
- 時(shí)間復(fù)雜度:O(n)
- 空間復(fù)雜度:O(n)
C++
- 因?yàn)?code>memset初始化問(wèn)題,所以在構(gòu)成結(jié)果的時(shí)候多一步判斷。
class Solution {
public:
int uniqueLetterString(string s) {
int n = s.size(), res = 0;
cout << n << endl;
int l[n], r[n];
int letters[26];
memset(letters, -1, sizeof(letters));
for (int i = 0; i < n; i++) {
int idx = s[i] - 'A';
l[i] = letters[idx]; // 左邊第一個(gè)相同的字符所在位置
letters[idx] = i; // 更新當(dāng)前字母最新左位置
}
memset(letters, -1, sizeof(letters));
for (int i = n - 1; i >= 0; i--) {
int idx = s[i] - 'A';
r[i] = letters[idx]; // 右邊第一個(gè)相同的字符所在位置
letters[idx] = i; // 更新當(dāng)前字母最新右位置
}
for (int i = 0; i < n; i++) {
int ri = r[i] == -1 ? n : r[i];
res += (i - l[i]) * (ri - i);
}
return res;
}
};
- 時(shí)間復(fù)雜度:O(n)
- 空間復(fù)雜度:O(n)
Rust
- 用Rust的遍歷稍微改一下,思路一樣……
impl Solution {
pub fn unique_letter_string(s: String) -> i32 {
let cs = s.as_bytes();
(0..s.len()).into_iter().map(|i| {
let (mut l, mut r) = (i - 1, i + 1);
while l < s.len() && cs[l] != cs[i] {
l -= 1;
}
while r < s.len() && cs[r] != cs[i] {
r += 1;
}
((i - l) * (r - i)) as i32
}).sum::<i32>()
}
}
- 時(shí)間復(fù)雜度:O(n)
- 空間復(fù)雜度:O(n)
以上就是Java C++ 算法leetcode828統(tǒng)計(jì)子串中唯一字符乘法原理的詳細(xì)內(nèi)容,更多關(guān)于Java C++ 統(tǒng)計(jì)子串唯一字符的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Qt編寫地圖實(shí)現(xiàn)海量點(diǎn)位標(biāo)注
海量點(diǎn)位標(biāo)注的出現(xiàn),是為了解決普通設(shè)備點(diǎn)超過(guò)幾百個(gè)性能極速降低的問(wèn)題。本文將介紹如何通過(guò)Qt實(shí)現(xiàn)海量點(diǎn)位標(biāo)注功能,感興趣的可以了解一下2022-01-01
C++ COM編程之QueryInterface函數(shù)(一)
這篇文章主要介紹了C++ COM編程之QueryInterface函數(shù)(一),QueryInterface是組件本身提供對(duì)自己查詢的一個(gè)接口,需要的朋友可以參考下2014-10-10
Qt實(shí)現(xiàn)字幕滾動(dòng)效果的示例代碼
這篇文章主要介紹了Qt如何利用QTimer實(shí)現(xiàn)字幕滾動(dòng)功能,并且可以實(shí)現(xiàn)自行更改文本內(nèi)容、自適應(yīng)文本大小、自由調(diào)整速度等功能,感興趣的可以學(xué)習(xí)一下2022-06-06
C++ 中"priority_queue" 優(yōu)先級(jí)隊(duì)列實(shí)例詳解
這篇文章主要介紹了C++ 中"priority_queue" 優(yōu)先級(jí)隊(duì)列實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04
Qt實(shí)現(xiàn)一個(gè)簡(jiǎn)單的word文檔編輯器
本文主要介紹了Qt實(shí)現(xiàn)一個(gè)簡(jiǎn)單的word文檔編輯器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
C++實(shí)現(xiàn)LeetCode(166.分?jǐn)?shù)轉(zhuǎn)循環(huán)小數(shù))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(166.分?jǐn)?shù)轉(zhuǎn)循環(huán)小數(shù))2021-07-07
C++中std::find函數(shù)介紹和使用場(chǎng)景
std::find函數(shù)是一個(gè)非常實(shí)用的通用查找算法,適用于各種場(chǎng)景,本文主要介紹了C++中std::find函數(shù)介紹和使用場(chǎng)景,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02

