牛牛如今有 n 张扑克牌,每张扑克牌都有点数和花色两部分组成。点数为 ‘1’ - ‘9’ 的正整数,花色为 'C', 'D', 'H', 'S' 其中的一个,分别表示梅花、方块、红桃、黑桃。如今牛牛想按必定的顺序把这n张牌扔掉。扔牌顺序的规则以下:java
牛牛想知道他的扔牌顺序是什么,请返回扔牌顺序的字符串 数组
备注:spa
对于 100% 的数据,1 ≤ n ≤ 10。
输入code
"3C8D6H3D"
输出字符串
"3D3C8D6H"
说明get
开始 n = 4,为非素数,扔掉牌底的牌 3D n = 3,为素数,扔掉牌顶的牌 3C n = 2,为素数,扔掉牌顶的牌 8D n = 1,为非素数,扔掉牌底的牌 6H
输入数学
"8S8S8S8S8S8S8S"
输出string
"8S8S8S8S8S8S8S"
说明it
由于全是8S,因此扔牌顺序的每一张牌也都是8S
因为 n 在 [1, 10] 上,故本题直接把全部素数列出来便可。没什么难度。class
时间复杂度:O(n)
空间复杂度:O(n)
/** * * @param x string字符串 字符串从前到后分别是从上到下排列的n张扑克牌 * @return string字符串 */ public String Orderofpoker (String x) { int n = x.length() / 2; int top = 0, bot = x.length() - 2; String res = ""; while(n > 0){ if(n == 2 || n == 3 || n == 5 || n == 7){ res += x.substring(top, top + 2); top += 2; }else{ res += x.substring(bot, bot + 2); bot -= 2; } n--; } return res; }
今天牛牛去游乐园玩过山车项目,他以为过山车在上坡下坡的过程是很是刺激的,回到家以后就受到启发,想到了一个问题。若是把整个过山车的轨道看成是一个长度为 n 的数组 num,那么在过山车上坡时数组中的值是呈现递增趋势的,到了最高点之后,数组中的值呈现递减的趋势,牛牛把符合这样先增后减规律的数组定义为金字塔数组,请你帮牛牛在整个 num 数组中找出长度最长的金字塔数组,若是金字塔数组不存在,请输出 0。
备注:
1 <= n <= 1000000,且 num 数组中的数 0 <= num[i] <= 1000000。
输入
4,[1,2,3,1]
输出
4
输入
5,[1,5,3,3,1]
输出
3
在遍历的时候判断是不是金字塔数组便可。当前数字 i 和前一个数字 j 比较有三种状况:
时间复杂度:O(n)
空间复杂度:O(1)
/** * * @param n int整型 * @param num int整型一维数组 * @return int整型 */ public int getMaxLength (int n, int[] num) { // write code here int res = 0; int len = 1; boolean up = false; for(int i = 1; i < n; i++) { if(num[i] > num[i - 1]) { up = true; if(i > 1 && num[i - 1] < num[i - 2]) len = 1; len++; }else if(num[i] == num[i - 1]) { len = 1; up = false; }else { if(up) { len++; res = Math.max(len, res); } } } return res; }
金字塔数组长度 = 爬升阶段长度 + 1 (塔顶) + 降低阶段长度。
而降低阶段
至关于从右往左遍历时的爬升阶段
。
所以分别用 l 数组
和 r 数组
记录从左到右和从右到左的爬升阶段长度。
若 l[i] 和 r[i] 都不为 0,说明 i 是塔顶。
时间复杂度:O(n)
空间复杂度:O(n)
/** * * @param n int整型 * @param num int整型一维数组 * @return int整型 */ public int getMaxLength (int n, int[] num) { int res = 0; int[] l = new int[n]; int[] r = new int[n]; for(int i = 1; i < n; i++){ if(num[i] > num[i - 1]) l[i] = l[i - 1] + 1; } for(int i = n - 2; i >= 0; i--){ if(num[i] > num[i + 1]) r[i] = r[i + 1] + 1; } for(int i = 0; i < n; i++){ if(l[i] != 0 && r[i] != 0) res = Math.max(res, l[i] + r[i] + 1); } return res; }
牛牛最近在家里看到一个棋盘,有 n m 个格子,在棋盘旁边还放着 k 颗棋子,牛牛想把这 k 颗棋子所有放在 n m 的棋盘上,可是有一个限制条件:棋盘的第一行、第一列、最后一行和最后一列都必须有棋子。牛牛想知道这样的棋子放法到底有多少种,答案须要对 1e9 + 7
取模。
备注:
2 <= n, m <= 30; 1 <= k <=1000
输入
2,3,1
输出
0
说明
就1颗棋子,因此没法知足条件。
输入
2,2,2
输出
2
说明
咱们能够把第1颗棋子放在左上角,第2颗棋子放在右下角;也能够把第1颗棋子放在右上角,第2颗棋子放在左下角。故而有2种放法。
本题须要具有高中的数学知识:容斥原理和排列组合数。涉及的数学公式会在题解中给出,若是有看不明白的地方能够自行查询相关数学概念。
记行 i 上无棋子的集合为 $S_{ri}$, 列 j 上无棋子的集合为 $S_{cj}$。根据容斥原理,有
$$ \begin{aligned} res &= ∣S_{r1} ∩ S_{rn} ∩ S_{c1} ∩ S_{cm}∣ \hspace{100cm}\\ &= all - |S_{r1} ∪ S_{rn} ∪ S_{c1} ∪ S_{cm}∣\\ &= all - \sum_{C \subseteq U}(-1)^{size(C) - 1}|\cap_{e \in C} e| \end{aligned} $$
其中, $U = \{S_{r1}, S_{rn}, S_{c1}, S_{cm}\}$。
因为 $U$ 中只包含四个集合,所以能够用 4 个 bit 分别表示是否交集合 $S_i$。
总共有 $2^4 - 1 = 15$ 种交集状况,再加上 all ,共计 16 种状况。
排列组合数能够利用公式 $C_m^n = C_{m - 1}^n + C_{m - 1}^{n - 1}$ 迭代计算得出。
final int mod = (int)1e9 + 7; /** * * @param n int整型 * @param m int整型 * @param k int整型 * @return int整型 */ public int solve (int n, int m, int k) { if(k < 2) return 0; int[][] C = initC(); int res = 0; for(int i = 0; i < 16; i++){ int r = n, c = m, cnt = 0; if((i & 1) != 0) {r--; cnt++;} if((i & 2) != 0) {r--; cnt++;} if((i & 4) != 0) {c--; cnt++;} if((i & 8) != 0) {c--; cnt++;} res = (res - ((cnt & 1) * 2 - 1) * C[r * c][k]) % mod; } return (res + mod) % mod; } public int[][] initC(){ int n = 1000; int[][] C = new int[1001][1001]; for(int i = 1; i <= n; i++) C[i][0] = C[i][i] = 1; for(int i = 2; i <= n; i++){ for(int j = 1; j < i; j++){ C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod; } } return C; }
你们好,我是往西汪,一位坚持原创的新人博主。若是本文对你有帮助,请点赞、评论二连。你的支持是我创做路上的最大动力。谢谢你们!也欢迎来公众号【往西汪】找我玩耍~