演算法作業第二週(leetCode)——321. Create Maximum Number
我個人感覺本次做的題比上次那道hard難多了,以下為題目地址:
這道題的大意是給定兩個由各位數字(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; } };
但是感覺還是比大佬演算法慢了好多(巨慢):
不過還是受益匪淺的,至少對棧的使用,還有預處理更加的熟悉了。 還是要好好學習呀!