您的位置:首页 > 其它

LeetCode Contest 74

2018-03-06 00:29 120 查看
日常鸽比赛,不过做完这周的题后感觉挺有意思的,记一下思路。

Valid Tic-Tac-Toe State

问题

给出一个井字棋的棋盘,求是否合理。

思路

首先,井字棋先手为
X
,后手为
O
,因此合理的棋盘中
X
数量比
O
数量多
1
或两者相等,如果先手获胜,则
X
数量必然比
O
数量多
1
;如果后手获胜,则
X
数量必然和
O
数量相等。其次,一旦有一方获胜,即任意一行或一列或对角线均为
X
或均为
O
,则游戏结束,因此棋盘不能同时满足双方的胜利条件。我一开始还想到一种情况,就是一方获胜后继续游戏,导致棋盘中只有一方胜利,这种情况满足前面的条件,但实际上不合理,所以要特别考虑。后来我发现要满足这种情况至少要有六个相同的符号:

XOO
XXO
XXX


此时棋盘中只有
X
获胜,但事实上无论第六个
X
放在哪个位置,前五个
X
已经满足胜利条件了,因此这种情况是不合理的,如果仅根据胜利条件来判断棋盘是否合理会造成误判。不过,如果考虑
X
O
的数量关系就会得到正确的结果,因此不需要再当作特殊情况对待。

代码

class Solution {
public:
bool validTicTacToe(vector<string>& board) {
int xCount = 0, oCount = 0;  //X和O的数量
bool x3 = false, o3 = false;  //X和O的胜利条件

for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (board[i][j] == 'X') ++xCount;
else if (board[i][j] == 'O') ++oCount;
}
if (board[i][0] == 'X' && board[i][1] == 'X' && board[i][2] == 'X') x3 = true;
if (board[0][i] == 'X' && board[1][i] == 'X' && board[2][i] == 'X') x3 = true;
if (board[i][0] == 'O' && board[i][1] == 'O' && board[i][2] == 'O') o3 = true;
if (board[0][i] == 'O' && board[1][i] == 'O' && board[2][i] == 'O') o3 = true;
}
if (board[0][0] == 'X' && board[1][1] == 'X' && board[2][2] == 'X') x3 = true;
if (board[0][2] == 'X' && board[1][1] == 'X' && board[2][0] == 'X') x3 = true;
if (board[0][0] == 'O' && board[1][1] == 'O' && board[2][2] == 'O') o3 = true;
if (board[0][2] == 'O' && board[1][1] == 'O' && board[2][0] == 'O') o3 = true;

if (o3 && x3) return false;  //双方同时获胜
if (xCount > oCount + 1 || xCount < oCount) return false;  //X和O数量关系不合理
else if (xCount == oCount + 1 && o3) return false;  //X数量比O数量多1不可能后手获胜
else if (xCount == oCount && x3) return false;  //X数量和O数量相等不可能先手获胜
return true;
}
};


Number of Matching Subsequences

问题

给出一个字符串和一组序列,求字符串的子序列数量。

思路

求一个序列是否为字符串的子序列很简单,只需要遍历字符串就可以了,假设字符串长度
n
,序列长度
m
,那么时间复杂度为
O(n)
,已经达到最优。但如果对每一个序列都遍历字符串,假设序列数为
l
,那么时间复杂度为
O(l*n)
,这是最差的时间复杂度,很有可能超时。我一开始想用动态规划,记录字符串中每一个字母的下一个任意字母的最近位置,然后时间复杂度为
O(l*m)
,这是最优的时间复杂度,但空间复杂度为
O(26*n)
,不符合题目要求。后来我用
26
个队列记录每个序列的匹配情况,只需要遍历一次字符串就可以判断子序列的数量了,时间复杂度为
O(l*m)
,具体步骤如下:

1.取每个序列第一个字母对应队列,记录当前序列以及当前位置并插入队列。
2.取字符串第一个字母对应队列,取出队列中所有元素视为匹配成功,记录对应每个序列的下一个位置并插入下一个字母的对应队列,即让每个匹配当前字母成功的序列等待下一次匹配。
3.遍历字符串所有字母,判断字符串的子序列数量。


代码

class Solution {
public:
int numMatchingSubseq(string S, vector<string>& words) {
int ans = 0;
vector<queue<pair<int, int>>> v(26);
for (int i = 0; i < words.size(); ++i) {
v[words[i][0]-'a'].push({i, 1});
}
for (int i = 0; i < S.size(); ++i) {
int s = v[S[i]-'a'].size();
for (int j = 0; j < s; ++j) {
auto p = v[S[i]-'a'].front();
v[S[i]-'a'].pop();
if (p.second == words[p.first].size()) ++ans;
else v[words[p.first][p.second]-'a'].push({p.first, p.second+1});
}
}
return ans;
}
};


Number of Subarrays with Bounded Maximum

问题

给出一个序列和上下界,求最大项在上下界之间的连续的子序列数量。

思路

遍历序列,计算以每个元素结尾的符合要求的子序列数量并相加。如果当前元素大于上界,那么以当前元素结尾的子序列数量为
0
;如果当前元素在上下界之间,那么任意以当前元素结尾且不包含大于上界元素的子序列均符合要求,即从上一个大于上界元素的下一个元素开始到当前元素的数量;如果当前元素小于下界,那么任意以当前元素结尾且不包含大于上界元素且包含在上下界之间元素的子序列均符合要求,即从上一个大于上界元素的下一个元素开始到上一个在上下界之间元素的数量。

代码

class Solution {
public:
int numSubarrayBoundedMax(vector<int>& A, int L, int R) {
int ans = 0;
int a = 0;  //以当前元素结尾且符合要求的子序列数量
int b = 0;  //连续的小于下界元素的数量
for (int i = 0; i < A.size(); ++i) {
if (A[i] > R) a = b = 0;
else if (A[i] < L) ++b;
else {
a += b+1;
b = 0;
}
ans += a;
}
return ans;
}
};


Preimage Size of Factorial Zeroes Function

问题

n!
末尾的
0
的数量为
K
,求符合要求的
n
的数量。

思路

n! = 1*2*3*···*n
,因此
n!
末尾的
0
的数量与质因子
2
5
的数量有关。每有一个质因子
2
和一个质因子
5
n!
末尾就会有一个
0
,由于质因子
2
的数量大于质因子
5
的数量,所以
n!
末尾的
0
的数量等于质因子
5
的数量。假设
m >= 0
,那么
(5*m+1)!,(5*m+2)!,(5*m+3)!,(5*m+4)!,(5*m+5)!
末尾的
0
的数量相同,所以符合要求的
n
的数量要么为
0
,要么为
5
。当
K = 1,2,3,4,6,···
n
的数量为
5
,当
K = 5,···
n
的数量为
0
,因为
n!
的第
1
个含质因子
5
的因子为
5
,第
2
个因子为
10
,第
3
个因子为
15
,第
4
个因子为
20
,第
5
个因子为
25
,由于
25
有两个质因子
5
,所以不存在
n!
有且仅有
5
个质因子
5
。以此类推,不存在
n!
有且仅有
30
个质因子
5
,因为第
25
个因子为
125
125
有三个质因子
5
。将
K
作类似于进制的转换,我发现对于权
1,6,31,···
,如果有任意一个的系数为
5
,那么对应的
n!
不存在。

代码

class Solution {
public:
int preimageSizeFZF(int K) {
vector<int> v(15);
v[0] = 1;
for (int i = 1; i < 14; ++i) {
v[i] = 5*v[i-1] + 1;  //获得每一个权
}
for (int i = 13; i >= 0; --i) {
if (K / v[i] == 5) return 0;
else K %= v[i];
}
return 5;
}
};


总结

这次的题目非常有意思,我通过找规律得到了解题方法,但其中的原理并不能完全领会,还有待证明。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: