題目描述:構成指定長度字串的個數 (本題分值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)