算法作业第二周(leetCode)——321. Create Maximum Number

     我个人感觉本次做的题比上次那道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;
    }

};

但是感觉还是比大佬算法慢了好多(巨慢):

不过还是受益匪浅的,至少对栈的使用,还有预处理更加的熟悉了。 还是要好好学习呀!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值