我个人感觉本次做的题比上次那道hard难多了,以下为题目地址:
https://leetcode.com/problems/create-maximum-number/description/
这道题的大意是给定两个由各位数字(0-9)组成的数组,用数组中的数组合出一个最大的k位数。其中,数字在数组中的相对位置不能改变。
我一开始看到这道题的时候,心里想的是直接用dfs,然而这道题用dfs可以让本题算法复杂度爆炸。然后,我想了一下,觉得动态规划也不太可行,因为这道题前面的数字可以直接确定,就不存在多个状态。题目没有规定算法复杂度是多少,我就想,这道题可不可以实现O(m+n)级别的算法。
后来,我想出了一种预处理办法,就是通过一遍遍历,保存下来数组中每个位置上下一个指定数字(0-9)所在的位置。这个只需要维护一个数组,表明指定数字上一次出现的位置,算法复杂度为O(m+n)。然后,很明显的是,最大的数前面的位数越大越好,于是可以很容易地想到贪心算法,就是取两个数组中最大且最靠前的数,这里需要注意的是,取了数之后必须保证还可以取接下来的数保证可以组成k位数字,否则就不能取。
然后对于这道题,我想出了两种思路。一是直接通过上述的预处理,在两个数组中直接取下一个最大最前的数。另一个想法是,将k分为两部分,对每一个数组求最大序列,然后归并合起来。然而,我当时想能不能实现O(m+n)的算法,于是我就试了一下第一种算法,结果后来发现跟想象的有些差距,改来改去超时了。。。。。
失败的算法:
然后去看了一眼题解,发现别人的想法跟我第二种想法是一样的,就是把k分为两部分。区别在于,大神用了栈来处理单一数组,而我是通过先将数组预处理。感觉我还是很久没有用过栈,现在水平下降较多。。。。。
然后根据大佬的算法写出了改进的算法:
class Solution {
public:
vector<int> maxArray(vector<int>& nums1, int k){
int i,j,s1, temp, cnt;
int last[10];
vector<int> nextn[10], ans;
s1=nums1.size();
memset(last,-1,sizeof(last));
for(i=0;i<s1;i++)
{
temp=nums1[i];
if(last[temp]==-1)
{
nextn[temp].push_back(i);
last[temp]=0;
}
for(j=last[temp];j<i;j++)
nextn[temp].push_back(i);
last[temp]=i;
}
cnt=-1;
for(i=0;i<k;i++)
{
for(j=9;j>=0;j--)
{
if(cnt>=(int)nextn[j].size()-1||nextn[j].size()==0)
continue;
temp=nextn[j][cnt+1];
if(s1-temp-1<k-i-1)
continue;
cnt=temp;
ans.push_back(nums1[cnt]);
break;
}
}
return ans;
}
bool greater(vector<int>& nums1, int i, vector<int>& nums2, int j){
while (i < nums1.size() && j < nums2.size() && nums1[i] == nums2[j]){
i++;
j++;
}
return j == nums2.size() || (i<nums1.size() && nums1[i] > nums2[j]);
}
vector<int> merge(vector<int>& nums1, vector<int>& nums2, int k) {
std::vector<int> ans(k);
int i = 0, j = 0;
for (int r = 0; r<k; r++){
if( greater(nums1, i, nums2, j) ) ans[r] = nums1[i++] ;
else ans[r] = nums2[j++];
}
return ans;
}
vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
int m = nums1.size();
int n = nums2.size();
vector<int> result(k);
for (int i = std::max(0 , k - n); i <= k && i <= m; i++){
auto v1 = maxArray(nums1, i);
auto v2 = maxArray(nums2, k - i);
vector<int> candidate = merge(v1, v2, k);
if (greater(candidate, 0, result, 0)) result = candidate;
}
return result;
}
};
但是感觉还是比大佬算法慢了好多(巨慢):
不过还是受益匪浅的,至少对栈的使用,还有预处理更加的熟悉了。 还是要好好学习呀!