洛谷P2652题 同花顺问题深度解析 玩转扑克牌算法

一、问题理解
同花顺是指同一花色的连续数字序列。题目要求找出最少需要更换多少张牌,才能使手中所有牌成为同花顺。
二、解题思路
预处理:按花色分组并排序
对每种花色,找出最长的连续数字序列
计算需要更换的牌数 = 总牌数 - 最长序列长度
三、关键算法详解
四、代码实现
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
struct Card {
int suit; // 花色
int num; // 数字
};
// 比较函数:先按花色排序,同花色按数字排序
bool cmp(const Card& a, const Card& b) {
if(a.suit != b.suit) return a.suit < b.suit;
return a.num < b.num;
}
int main() {
int n;
cin >> n;
vector<Card> cards(n);
for(int i = 0; i < n; i++) {
cin >> cards[i].suit >> cards[i].num;
}
// 按花色和数字排序
sort(cards.begin(), cards.end(), cmp);
int min_changes = n; // 初始化为最大可能值
// 遍历所有可能的同花顺区间
for(int i = 0; i < n; ) {
int j = i;
// 找到相同花色的连续区间
while(j < n && cards[j].suit == cards[i].suit) j++;
vector<int> nums;
for(int k = i; k < j; k++) {
nums.push_back(cards[k].num);
}
// 去重
sort(nums.begin(), nums.end());
nums.erase(unique(nums.begin(), nums.end()), nums.end());
// 滑动窗口找最长连续序列
int left = 0;
for(int right = 0; right < nums.size(); right++) {
while(nums[right] - nums[left] >= n) left++;
min_changes = min(min_changes, n - (right - left + 1));
}
i = j;
}
cout << min_changes << endl;
return 0;
}五、边界情况处理
所有牌花色相同的情况
数字完全相同的情况
牌数较少时的特殊情况
六、复杂度分析
时间复杂度:O(nlogn) 主要来自排序操作
空间复杂度:O(n) 存储牌的信息
七、优化方向
使用哈希表加速分组
并行处理不同花色
预处理数字范围
这个实现通过巧妙的排序和滑动窗口技术,高效地解决了同花顺问题,是处理序列类问题的经典范例。
原创内容 转载请注明出处
