方法:DP+ 二分搜索
具体一点说,二分搜索是用在LIS(最长递增子序列)中(LIS见:点击打开链接)。主要思想就是LIS的思想。
有O(N*N)和O(NlgN)两种解法。
不论是哪种解法,首先都得按照w(宽)值对envelopes进行递增排序。
简单直观的O(N*N)的方法。
class Solution {
public:
int maxEnvelopes(vector<pair<int, int>>& envelopes) {
int size = envelopes.size();
quicksort(envelopes, 0, size - 1);
int maxN = judge(envelopes);
return maxN;
}
int quicksort(vector<pair<int, int>>& envelopes, int s, int e){
if (s >= e)return 0;
int Ref = envelopes[e].first;
int i = s - 1, j = s;
pair<int, int> temp;
for (; j<e; ++j){
if (envelopes[j].first<Ref){
i++;
temp = envelopes[j];
envelopes[j] = envelopes[i];
envelopes[i] = temp;
}
}
temp = envelopes[j];
envelopes[j] = envelopes[i + 1];
envelopes[i + 1] = temp;
quicksort(envelopes, s, i);
quicksort(envelopes, i + 2, e);
return 1;
}
int judge(vector<pair<int, int>>& envelopes) {
int size = envelopes.size(), largest,result=1;
if (size == 0) return 0;
vector<int> count;
count.push_back(1);
for (int i = 1; i < size; ++i){
largest = 0;
for (int j = 0; j < i; ++j){
if (envelopes[i].first>envelopes[j].first&&envelopes[i].second>envelopes[j].second&&count[j]>largest)
largest = count[j];
}
count.push_back(largest + 1);
if (largest + 1 > result) result = largest + 1;
}
return result;
}
};
在上面排序的基础上,对w相同的envelopes再按照h进行递减排序(当时就递减排序没想到)。(递减为了让w相同信封不嵌套)
然后应用二分搜索。(对stl不熟悉,自己写的排序,二分搜索等,代码很长,但时间还是在很行beat70%)
class Solution {
public:
int maxEnvelopes(vector<pair<int, int>>& envelopes) {
int size = envelopes.size();
vector<int> w, h;
for (int i = 0; i < size; ++i)
w.push_back(envelopes[i].first);
quicksort(envelopes, w, 0, size - 1, -1);//-1表示从小到大排序,1表示从大到小排序,
for (int i = 0; i < size; ++i)
h.push_back(envelopes[i].second);
w.push_back(-1);
int s = 0;
for (int i = 1; i <= size; ++i)
{
if (w[i] != w[i - 1]){
quicksort(envelopes, h, s, i-1, 1); //具有相同w的,按h由大到小排序
s = i;
}
}
int maxN = LIS(h);
return maxN;
}
int quicksort(vector<pair<int, int>>& envelopes, vector<int>& vect, int s, int e, int order){
if (s >= e)return 0;
int Ref = vect[e];
int i = s - 1, j = s;
int temp;
pair<int, int> temp1;
for (; j<e; ++j){
if ((vect[j] - Ref)*order>0){
i++;
temp = vect[j];
vect[j] = vect[i];
vect[i] = temp;
temp1 = envelopes[j];
envelopes[j] = envelopes[i];
envelopes[i] = temp1;
}
}
temp = vect[j];
vect[j] = vect[i + 1];
vect[i + 1] = temp;
temp1 = envelopes[j];
envelopes[j] = envelopes[i + 1];
envelopes[i + 1] = temp1;
quicksort(envelopes, vect, s, i, order);
quicksort(envelopes, vect, i + 2, e, order);
return 1;
}
int LIS(vector<int>& h) {
int size = h.size();
if (size == 0) return 0;
vector<int> temp;
temp.push_back(h[0]);
int len = 1, pos; //用于标示temp数组中的元素个数
for (int i = 1; i<size; i++)
{
if (h[i]>temp[len - 1]) //如果大于temp中最大的元素,则直接插入到temp数组末尾
{
temp.push_back(h[i]);
len++;
}
else
{
pos = BiSearch(temp, h[i]);//二分查找需要插入的位置
temp[pos] = h[i];
}
}
return len;
}
int BiSearch(vector<int>& temp, int key){
int len = temp.size();
int low = 0, high = len - 1, mid;
while (low <= high)
{
mid = (low + high) / 2;
if (temp[mid]>key)
high = mid - 1;
else if (temp[mid]<key)
low = mid + 1;
else
return mid;
}
return low; //数组data中不存在该元素,则返回该元素应该插入的位置
}
};
看讨论里面用stl函数,代码很短,值得好好学习。如下:
class Solution {
public:
int maxEnvelopes(vector<pair<int, int>>& envelopes)
{
int size = envelopes.size();
sort(envelopes.begin(), envelopes.end(), [](pair<int, int> a, pair<int, int>b){
return a.first<b.first || (a.first==b.first && a.second>b.second);
});
vector<int> collector;
for(auto& pair: envelopes)
{
auto iter = lower_bound(collector.begin(), collector.end(), pair.second);
if(iter == collector.end()) collector.push_back(pair.second);
else if(*iter > pair.second) *iter = pair.second;
}
return collector.size();
}
};
下面这句搞定了上面提到的两次不同的排序:
sort(envelopes.begin(), envelopes.end(), [](pair<int, int> a, pair<int, int>b){
return a.first<b.first || (a.first==b.first && a.second>b.second);
});
下面搞定了二分搜索等:
for(auto& pair: envelopes)
{
auto iter = lower_bound(collector.begin(), collector.end(), pair.second);
if(iter == collector.end()) collector.push_back(pair.second);
else if(*iter > pair.second) *iter = pair.second;
}
但是时间都差不多,比我的稍慢。