力扣LCP23题:魔术排列的模拟解决方案

一、问题理解
题目描述了一个魔术洗牌过程:
将卡牌偶数位置的牌移到奇数位置牌前面
每次取前k张牌,剩余牌重复上述过程
判断是否存在k值使得最终取牌顺序等于目标排列
二、解决思路
暴力尝试法:尝试所有可能的k值(1到n),模拟洗牌和取牌过程,检查是否匹配目标排列。
优化思路:
观察洗牌后的第一个元素必须是target[0],这可以缩小k的可能范围
但最直观的方法是直接模拟整个过程
三、关键步骤详解
洗牌操作:
将当前排列的偶数下标元素(1-based)提取出来
再将奇数下标元素接在后面
例如[1,2,3,4,5] → [2,4,1,3,5]
取牌操作:
每次取前k张牌加入结果
剩余牌继续洗牌
直到所有牌被取完
验证匹配:
在取牌过程中实时检查是否与target匹配
一旦发现不匹配立即终止当前k的尝试
四、完整代码
class Solution {
public:
bool isMagic(vector<int>& target) {
int n = target.size();
// 生成初始排列1~n
vector<int> initial(n);
for(int i = 0; i < n; i++) initial[i] = i + 1;
// 尝试所有可能的k值(1到n)
for(int k = 1; k <= n; k++) {
vector<int> current = initial;
vector<int> result;
bool valid = true;
while(!current.empty()) {
// 第一步:洗牌操作
vector<int> shuffled;
// 先放偶数位置(索引1,3,...,对应下标0,2,...)
for(int i = 1; i < current.size(); i += 2) {
shuffled.push_back(current[i]);
}
// 再放奇数位置(索引0,2,...,对应下标0,2,...)
for(int i = 0; i < current.size(); i += 2) {
shuffled.push_back(current[i]);
}
// 第二步:取牌操作
int take = min(k, (int)shuffled.size());
for(int i = 0; i < take; i++) {
result.push_back(shuffled[i]);
// 检查是否与target匹配
if(result.size() > target.size() ||
result[result.size()-1] != target[result.size()-1]) {
valid = false;
break;
}
}
if(!valid) break;
// 剩余牌继续处理
current = vector<int>(shuffled.begin() + take, shuffled.end());
}
if(valid && result == target) {
return true;
}
}
return false;
}
};五、代码解析
初始化:生成初始排列1~n
k值尝试:遍历所有可能的k值(1到n)
洗牌模拟:
分离偶数和奇数位置元素
合并成新排列
取牌验证:
取前k张牌
检查是否与target对应位置匹配
结果判断:如果完全匹配则返回true
原创内容 转载请注明出处
