P1498P2562 [AHOI2002] Kitty猫基因编码
#include <iostream>
using namespace std;
#include <cmath>
#include <vector>
#include <string>
string encode(string str){
if(str.find("0") == string::npos) return "B";
if(str.find("1") == string::npos) return "A";
int half = str.size()/2;
return "C" + encode(str.substr(0,half)) + encode(str.substr(half));
}
int main(){
string s;
cin>>s;
cout<< encode(s)<<endl;
}
你完全理解正确!这段代码采用的是 直接返回值的方式,而不是对原先字符串进行修改,主要原因有以下几点:
1. 避免复杂性:处理重复元素
如果直接对原始字符串进行修改,当字符串中存在多个相同的 0
或 1
时,就需要对整个字符串的每个字符进行跟踪和修改。例如:
- 如果遇到全为
0
的字符串(如000
),我们需要将它整体替换为一个A
。 - 直接修改原字符串会导致以下问题:
- 需要移除多余字符: 例如,原来的
000
需要被替换为单个A
,那么我们需要移除其余的两个0
。 - 调整字符串结构: 修改会导致字符串长度缩短,后续的递归和分割操作需要动态调整。
- 状态管理复杂: 在原字符串上操作,可能需要额外的标记或数组来管理哪些字符已经被处理,增加了逻辑复杂性。
- 需要移除多余字符: 例如,原来的
因此,采用 直接返回值 的方式,可以避免这些问题,不需要对原字符串进行任何修改,所有逻辑都在返回值中完成。
2. 返回值递归的自然适配
采用递归返回值的方式非常符合分治问题的特点:
- 每个子问题的结果独立于其他子问题,直接通过返回值组合即可。
- 父问题只需要知道子问题的结果,而不需要直接修改父问题的原始数据。
对于这道题:
- 如果字符串全是
0
,直接返回"A"
,无需修改原字符串。 - 如果字符串全是
1
,直接返回"B"
。 - 如果既包含
0
又包含1
,分为两部分递归计算,并将子结果通过返回值合并为C + left + right
。
这种模式避免了原字符串的复杂修改,递归组合也非常简洁自然。
3. 原字符串的不可变性
递归过程中,字符串的不可变性是一个很大的优势:
- 每次递归分割出新的子串(如
substr
),这些子串和原字符串没有耦合关系。 - 这保证了递归调用之间不会互相干扰,逻辑清晰且容易调试。
- 如果直接修改原字符串,需要小心管理修改后的状态,防止对后续的递归产生副作用。
4. 避免修改的复杂示例
如果采用修改原字符串的方式,代码会变得更复杂。例如:
void encode_inplace(string &s, int start, int end) {
// 判断当前范围是否全是 0 或全是 1
bool all_zero = true, all_one = true;
for (int i = start; i < end; ++i) {
if (s[i] == '1') all_zero = false;
if (s[i] == '0') all_one = false;
}
// 修改原字符串内容
if (all_zero) {
s[start] = 'A';
s.erase(start + 1, end - start - 1); // 移除多余字符
return;
}
if (all_one) {
s[start] = 'B';
s.erase(start + 1, end - start - 1); // 移除多余字符
return;
}
// 递归处理左右两部分
int mid = (start + end) / 2;
encode_inplace(s, start, mid);
encode_inplace(s, mid, end);
// 合并结果
s[start] = 'C';
s.erase(start + 1, mid - start - 1); // 左部分清理
s.erase(start + 1 + (mid - start - 1), end - mid - 1); // 右部分清理
}
这种方式复杂性较高:
- 需要手动移除字符串的多余部分。
- 需要实时维护字符串的长度和递归分割点。
- 字符串的状态管理复杂,容易出错。
相比之下,直接返回结果的方式简洁且高效。
5. 返回值方式的简化性
采用返回值的方式,逻辑更加清晰:
- 每次递归只需关注当前子字符串的结果,不用关心如何修改或清理原字符串。
- 递归的返回值天然地形成了合并的链式逻辑,例如:
这种组合方式非常直观,直接体现了分治思想。return "C" + encode(left) + encode(right);
总结
采用直接返回值的方式而非修改原字符串的原因是:
- 避免处理重复字符的复杂性: 直接返回
"A"
或"B"
表示的结果,省去了移除多余字符的麻烦。 - 自然适配递归逻辑: 返回值可以直接用来组合子结果,无需修改字符串。
- 保证字符串不可变性: 避免因修改原字符串而引入的状态管理复杂性。
- 更简洁清晰: 返回值递归更贴合分治思想,代码简洁且易于维护。
这种设计方式很好地平衡了简洁性与效率,尤其适用于这种递归分治的场景!