思路:
题目的主要信息:
- 一个长度为n的字符串,用数字表示牌的点数,字母'C''D''H''S'表示花色,同一牌这两部分相连,即长度为n的字符串有张牌
- 如果还剩下素数张牌,则扔掉牌顶,如果还剩下非素数张牌则将牌底扔掉
- 求扔掉全部牌的顺序,输出字符串
方法一:暴力判断素数+字符串截取
具体做法:
对于每次剩下的牌数,我们可以暴力判断其是否是素数。我们用两个指针left和right指向牌顶和牌底的下标,每次剩下的n为素数我们就截取牌顶指针后两位字符,n为非素数我们就截取牌底指针后两位字符,直到n为0.
class Solution { public: bool isPrime(int a){ if(a <= 1) return false; for(int i = 2; i * i <= a; i++) //循环判断是否是素数 if(a % i == 0) return false; return true; } string Orderofpoker(string x) { int n = x.length() / 2; //字符串包括点数与花色 string res = ""; int left = 0; //牌顶 int right = x.length() - 2; //牌底 while(n){ if(isPrime(n)){ //素数截取前面两个 res += x.substr(left, 2); left += 2; }else{ //非素数截取后面两个 res += x.substr(right, 2); right -= 2; } n--; } return res; } };
复杂度分析:
- 时间复杂度:,其中并非字符串长度而是牌数即字符串长度的一半,判断每个数是否为素数每次为,外面一共次循环
- 空间复杂度:,res为返回必要空间,无额外空间
方法二:素数数组+双向队列
具体做法:
因为题目明确给出了,因此我们可以用一个数组直接存储这些数字是否是素数,然后利用数组直接判断。
同时,我们还可以用双向队列模拟这个过程,字符串所有字符入队列,素数弹出队列前端两个元素,非素数弹出队列后端两个元素。
class Solution { public: string Orderofpoker(string x) { bool isPrime[11] = {false, false, true, true, false, true, false, true, false, false, false}; deque<char> q; q.clear(); for(int i = 0; i < x.length(); i++) //进入双向队列 q.push_back(x[i]); int n = x.length() / 2; //字符串包括点数与花色 string res = ""; while(!q.empty()){ if(isPrime[n]){ //直接查看是否为素数 res += q.front(); //添加两个队列前端的元素 q.pop_front(); res += q.front(); q.pop_front(); }else{ char c1 = q.back(); //队列后端的元素要先加前面的再加后面的,因此先弹出的后加 q.pop_back(); char c2 = q.back(); q.pop_back(); res += c2; res += c1; } n--; } return res; } };
复杂度分析:
- 时间复杂度:,字符入队列为,后续只有一次循环的
- 空间复杂度:,字符串的双向队列长度为,res属于必要空间