華為OD機試統一考試D卷C卷 - 構成指定長度字串的個數

xfcoding發表於2024-05-17

題目描述:構成指定長度字串的個數 (本題分值100)

給定 M(0 < M ≤ 30)個字元(a-z),從中取出任意字元(每個字元只能用一次)拼接成長度為 N(0 < N ≤ 5)的字串,

要求相同的字元不能相鄰,計算出給定的字元列表能拼接出多少種滿足條件的字串,

輸入非法或者無法拼接出滿足條件的字串則返回0。

解題思路

使用遞迴和回溯的思想來生成不同的字串。具體的邏輯如下:

首先,我們定義一個函式generateDistinctStrings,這個函式接收以下引數:可用字符集s,目標字串長度length,當前已生成的字串current,已生成的結果集result,以及一個標記陣列used,用來記錄每個字元是否已被使用。
在generateDistinctStrings函式中,首先檢查當前已生成的字串current的長度是否等於目標長度length。如果等於,說明我們已經生成了一個滿足長度要求的字串,將其新增到結果集result中,然後返回。
如果當前字串current的長度還未達到目標長度length,我們就需要繼續新增字元。此時,我們遍歷可用字符集s中的每一個字元。對於每一個字元,我們首先檢查它是否已經被使用(透過檢視used陣列),以及它是否與current的最後一個字元相同。如果字元已經被使用,或者與current的最後一個字元相同,我們就跳過這個字元,繼續檢查下一個字元。
如果一個字元未被使用,且與current的最後一個字元不同,我們就將它新增到current的末尾,然後標記這個字元為已使用,接著遞迴呼叫generateDistinctStrings函式,以生成下一個字元。
在遞迴呼叫返回後,我們需要取消對當前字元的使用標記,以便在後續的遍歷中可以再次使用這個字元。這就是回溯的思想,即撤銷之前的選擇,嘗試其他的選擇

函式 generateDistinctStrings(s, length, current, result, used)
    如果 current的長度 等於 length
        將 current 新增到 result
        返回
    對於 s中的每一個字元 c
        如果 c已被使用 或者 c與current的最後一個字元相同
            繼續下一次迴圈
        標記 c為已使用
        generateDistinctStrings(s, length, current + c, result, used)
        取消標記 c的使用狀態

C++

#include <iostream>
#include <unordered_set>
#include <vector>
#include <sstream>

using namespace std;

// 遞迴生成滿足條件的不同字串
void generateDistinctStrings(string s, int length, string current, unordered_set<string>& result, vector<bool>& used) {
    // 當生成的字串長度等於指定長度時,將其加入到結果集中
    if (current.length() == length) {
        result.insert(current);
        return;
    }

    // 遍歷字串中的字元
    for (int i = 0; i < s.length(); i++) {
        // 判斷字元是否已經被使用,或者當前字元與前一個字元相同
        if (used[i] || (current.length() > 0 && current.back() == s[i])) {
            continue;  // 如果字元已被使用或與前一個字元相同,則跳過當前字元
        }
        used[i] = true;  // 標記當前字元為已使用
        // 遞迴呼叫生成下一個字元
        generateDistinctStrings(s, length, current + s[i], result, used);
        used[i] = false;  // 取消標記當前字元的使用狀態,以便下一次遍歷
    }
}

// 計算滿足條件的不同字串的數量
int countDistinctStrings(string s, int length) {
    // 建立一個集合來儲存不同的字串
    unordered_set<string> distinctStrings;
    // 建立一個列表來標記字串中的字元是否已經被使用
    vector<bool> used(s.length(), false);
    // 呼叫generateDistinctStrings方法生成滿足條件的不同字串
    generateDistinctStrings(s, length, "", distinctStrings, used);
    // 列印生成的所有不同的字串
    // for (auto& str : distinctStrings) {
       // cout << str << endl;
    // }
    // 返回不同字串的數量
    return distinctStrings.size();
}

int main() {
    string input;
    getline(cin, input);
    // 將輸入的字串按空格分割為兩部分,分別為字串和長度
    string str;
    int length;
    istringstream iss(input);
    iss >> str >> length;

    // 呼叫countDistinctStrings方法計算滿足條件的不同字串的數量
    int count = countDistinctStrings(str, length);
    // 輸出計算結果
    cout <<  count << endl;

    return 0;
}

Python

def generate_distinct_strings(s,length,current,result,used):
    # 當生成的字串長度等於指定長度時,將其加入結果集中
    if len(current)==length:
        result.add(current)
        return

    # 遍歷字串中的字元
    for i in range(len(s)):
        if used[i] or (len(current)>0 and current[-1]==s[i]):
            # 如果字元已被使用或與前一個字元相同,則跳過當前字元
            continue
        # 標記當前字元已使用
        used[i]=True
        # 遞迴呼叫生成下一個字元
        generate_distinct_strings(s,length,current+s[i],result,used)
        # 取消標記當前字元使用狀態,以便下一次遍歷
        used[i]=False


# 計算滿足條件的不同字串的數量
def count_distinct_strings(s,length):
    # 建立一個集合來儲存不同的字串
    distinct_strings=set()
    # 建立一個列表來標記字串中的字元是否已經被使用
    used=[False]*len(s)
    # 呼叫generate_distinct_strings方法生成滿足條件的不同字串
    generate_distinct_strings(s,length,"",distinct_strings,used)
    # 列印生成所有不同的字串
    for string in distinct_strings:
        print(string)
    # 返回不同字串的數量
    return len(distinct_strings)


# 讀取使用者輸入的字串
input_str=input()
# 將輸入的字串空格分割為兩部分,分別是字串及長度
parts=input_str.split()
# 獲取輸入的字串
s=parts[0]
# 將輸入的長度部分轉化為整數
length=int(parts[1])

# 呼叫count_distinct_strings方法計算滿足條件的不同字串的數量
count=count_distinct_strings(s,length)
# 輸出計算結果
print(count)

相關文章