針對 M 個查詢,反轉給定字串的範圍


在這個問題中,我們將根據陣列值對給定的字串執行 M 次反轉查詢。

解決該問題的樸素方法是根據給定的陣列值反轉每個字串片段。

最佳化方法利用了以下邏輯:當我們對同一個子字串反轉兩次時,我們會得到原始字串。

問題陳述 - 我們給定一個包含字母字元的 alpha 字串。此外,我們還給定一個大小為 M 的 arr[] 陣列,其中包含正整數。我們需要對給定的字串執行 M 個操作並返回最終字串。

在每個操作中,我們需要獲取 arr[i] 並反轉從 arr[i] 到 N − arr[i] + 1 的子字串。

示例

輸入

alpha = "pqrst"; arr = {2, 1};

輸出

tqrsp

解釋 

  • 執行第一個查詢後,字串變為“psrqt”。

  • 執行第二個查詢後,我們得到“tqrsp”。

輸入

−  alpha = "pqrst"; arr = {1, 1};

輸出

 − ‘pqrst’

解釋 - 如果我們對同一個查詢執行偶數次,我們會得到相同的字串。

輸入

 −  alpha = "pqrst"; arr = {1, 1, 1};

輸出

 − ‘tsrqp’

解釋 - 如果我們對同一個查詢執行奇數次,我們會得到字串的反轉。

方法 1

在這種方法中,我們將使用 reverse() 方法反轉子字串。我們將使用給定的查詢獲取起始和結束指標,並反轉給定字串的子字串。

演算法

步驟 1 - 開始遍歷查詢陣列。

步驟 2 - 使用 arr[p] − 1 初始化“left”變數。

步驟 3 - 使用 str_len − arr[p] + 1 初始化“right”變數。

步驟 4 - 使用 reverse() 方法反轉從左指標到右指標的子字串。

示例

#include <bits/stdc++.h>
using namespace std;

void reverseStrings(string &alpha, int str_len, vector<int> &arr, int arr_len){
    // Traverse all queries
    for (int p = 0; p < arr_len; p++){
        // Get starting pointer
        int left = arr[p] - 1;
        // Ending pointer
        int right = str_len - arr[p] + 1;
        // Reverse the string
        reverse(alpha.begin() + left, alpha.begin() + right);
    }
}
int main(){
    int str_len = 5;
    string alpha = "pqrst";
    int arr_len = 2;
    vector<int> arr = {2, 1};
    reverseStrings(alpha, str_len, arr, arr_len);
    cout << "The string after performing queries is " << alpha << endl;
    return 0;
}

輸出

The string after performing queries is tqrsp

時間複雜度 - 反轉子字串 M 次的時間複雜度為 O(N*M)。

空間複雜度 - O(1),因為我們沒有使用任何動態空間。

方法 2

在這種方法中,我們將計算特定索引以及在給定查詢中包含反轉的次數。如果任何索引在偶數次包含在反轉中,我們不需要反轉它。如果任何索引在所有給定查詢中奇數次包含在反轉中,我們需要反轉特定索引處的字元。

演算法

步驟 1 - 初始化長度等於字串長度的“cnt”列表,並將其值初始化為 0,以儲存特定索引包含在反轉中的次數。

步驟 2 - 遍歷給定查詢的陣列,並根據當前查詢獲取字串的左指標和右指標。

步驟 3 - 還執行 changeRange() 函式以根據當前查詢的左指標和右指標更新“cnt”列表。

步驟 3.1 - 在 changeRange() 函式中,增加“cnt”列表中“left”索引處的值。

步驟 3.2 - 減小“cnt”列表中所有位於“right + 1”指標右側的值。

這裡,我們需要在 [left, right] 範圍內將“cnt”列表的所有值加 1。因此,我們只將 cnt[left] 加 1,因為獲取字首和會將所有位於“left”索引右側的值加 1。此外,我們不希望增加 [right, str_len] 索引之間的 cnt 值,因此我們已經將其減 1,因為字首和會將其加 1。

步驟 4 - 接下來,執行 getPrefixSum() 函式以計算“cnt”列表的字首和。

步驟 4.1 - 在 getPrefixSum() 函式中,遍歷字串並將前一個元素的值新增到當前元素。

步驟 5 - 接下來,以相反的順序遍歷“cnt”列表。如果當前元素為奇數,則將其追加到“tmp”字串。

步驟 6 - 使用 0 初始化“p”和“q”,以原始順序遍歷“cnt”列表。

步驟 7 - 如果“cnt”列表中的當前元素為奇數,則使用 tmp[q] 更新 alpha[p]。

步驟 8 - 最後,返回 alpha 字串。

示例

#include <iostream>
#include <vector>
using namespace std;

void changeRange(vector<int>& cnt, int left, int right) {
    // Increase the value of the left index
    cnt[left]++;
    // Decrement value for all indexes after the right index
    if (right + 1 < cnt.size())
        cnt[right + 1]--;
}
void getPrefixSum(vector<int>& cnt) {
    // Calculate prefix sum
    for (int p = 1; p < cnt.size(); p++) {
        cnt[p] += cnt[p - 1];
    }
}
string reverseStrings(string alpha, int str_len, vector<int>& arr, int arr_len) {
    vector<int> cnt(str_len, 0);
    // Traverse the array
    for (int p = 0; p < arr_len; p++) {
        int left = arr[p] <= (str_len + 1) / 2 ? arr[p] - 1 : str_len - arr[p];
        int right = arr[p] <= (str_len + 1) / 2 ? str_len - arr[p] : arr[p] - 1;
        // Changes index ranges between left and right
        changeRange(cnt, left, right);
    }
    getPrefixSum(cnt);
    string tmp;
    // Store characters with the odd reversal in the reverse order in the tmp string
    for (int p = cnt.size() - 1; p >= 0; p--) {
        if (cnt[p] % 2 != 0)
            tmp.push_back(alpha[p]);
    }
    int p = 0, q = 0;
    // For even reversal, pick the character from the original string.
    // For odd reversal, pick the character from the temp string.
    for (p = 0; p < cnt.size(); p++) {
        if (cnt[p] % 2 != 0)
            alpha[p] = tmp[q++];
    }
    // Answer string
    return alpha;
}
int main() {
    int str_len = 5;
    string alpha = "pqrst";
    int arr_len = 2;
    vector<int> arr = { 2, 1 };
    alpha = reverseStrings(alpha, str_len, arr, arr_len);
    cout << "The string after performing queries is: " <<alpha << endl;
    return 0;
}

輸出

The string after performing queries is: tqrsp

時間複雜度 - O(M*N + N),其中 O(M*N) 用於根據查詢更新“cnt”列表,O(N) 用於更新給定字串。

空間複雜度 - O(N),用於使用“cnt”列表。

在第一種方法中,我們使用 reveres() 方法對給定字串執行所有查詢。在第二種方法中,我們使用字首和技術來計算特定索引包含在反轉中的次數。

更新於: 2023-07-17

235 次檢視

開啟你的 職業生涯

透過完成課程獲得認證

開始學習
廣告