description
brute-force:刚开始是暴力+贪心,先使小时最大,然后再使分钟最大。这样会出现小时最大但分钟非法的情况,例如
A
=
[
2
,
0
,
6
,
6
]
A=[2,0,6,6]
A=[2,0,6,6] 时,小时为20,分钟只能为66(非法)。改进:直接从大到小枚举所有的时间,看能否由A组成。
判断能否由A组成时,有两种方法,一种是整体判断:统计A中各数字出现的次数和当前时间各数字出现的次数,比较对应数字的次数即可。第二种是在这道题里用的,每次找一个数字,若找到标记为已用。这种方法在不能全部找到的情况需要进行回滚。相比较还是第一种方法比较好。
class Solution {
private:
vector<int> vis;
public:
int findDigit(vector<int>& A, int target){
for (int i = 0;i< A.size();++i)
if (A[i]==target && vis[i]==0){
vis[i] = 1;
return i;
}
return -1;
}
string largestTimeFromDigits(vector<int>& A) {
vis = vector<int>(A.size(), 0);
string res = "";
for (int i = 23;i >= 0;--i)
for (int j = 59;j >= 0;--j){
int a = findDigit(A, i/10);
int b = findDigit(A, i%10);
int c = findDigit(A, j/10);
int d = findDigit(A, j%10);
if (a!=-1 && b!=-1 && c!=-1 && d!=-1){
res.push_back(A[a]+'0');
res.push_back(A[b]+'0');
res.push_back(':');
res.push_back(A[c]+'0');
res.push_back(A[d]+'0');
return res;
}
//进行回滚
else{
if (a !=- 1) vis[a] = 0;
if (b != -1) vis[b] = 0;
if (c != -1) vis[c] = 0;
if (d != -1) vis[d] = 0;
}
}
return "";
}
};
看了讨论区,更好的做法是使用排列组合来做。上述方法最多需要 24 ∗ 60 = 1440 24*60=1440 24∗60=1440 得到结果,而排列组合最多只需要 A 4 4 = 24 A_4^4=24 A44=24 就可以得到结果,
string largestTimeFromDigits(vector<int>& A) {
sort(begin(A), end(A), greater<int>());
do if ((A[0] < 2 || (A[0] == 2 && A[1] < 4)) && A[2] < 6)
return to_string(A[0]) + to_string(A[1]) + ":" + to_string(A[2]) + to_string(A[3]);
while (prev_permutation(begin(A), end(A)));
return "";
}
整理一下 algorithm 头文件中关于排列组合的函数:
- next_permutation (字典序产生排列)
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last); bool next_permutation (BidirectionalIterator first, BidirectionalIterator last, Compare comp);
- prev_permutation(逆字典序产生排列)
bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last ); bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last, Compare comp);
- is_permutation
bool is_permutation (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2);