您的位置:首页 > 其它

leetcode : 321. Create Maximum Number : 有点难度的贪心法

2016-03-28 01:57 344 查看


321. Create Maximum Number

My Submissions

Question

Total Accepted: 4587 Total
Submissions: 22666 Difficulty: Hard

Given two arrays of length
m
and
n
with
digits
0-9
representing two numbers. Create the maximum number of length
k
<= m + n
from digits of the two. The relative order of the digits from the same array must be preserved. Return an array of the
k
digits.
You should try to optimize your time and space complexity.
Example 1:

nums1 =
[3, 4, 6, 5]


nums2 =
[9, 1, 2, 5, 8, 3]


k =
5


return
[9, 8, 6, 5, 3]

Example 2:

nums1 =
[6, 7]


nums2 =
[6, 0, 4]


k =
5


return
[6, 7, 6, 0, 4]

Example 3:

nums1 =
[3, 9]


nums2 =
[8, 9]


k =
3


return
[9, 8, 9]


开始看题目,没有想法,肯定不会是暴力搜索所有可能的拼接。后来想到:如果能分别从两个数组中选出候选子集,那么就应该能够根据类似归并的样子,将其拼接成最大数组。但是,如何从一个数组中选出候选子集。瞄了一眼提示才知道:长度为subK候选子集就是在子数组中最大的子数组。

1.推论:假设数组x和数组y分别选出长度是r的subX和长度是(k-r)的subY组成的数组Z最大,并且保证元素保持原有的顺序(元素o在subX中哪些元素前后,在Z中仍然保持这样的顺序)。那么subX和subY分别是X,Y的固定长度的最大数组

原因很简单:贪心法证明,假设subX是拼接成最大数组Z的子数组,如果subX不是X的最大数组,那么存在subXX是X数组在固定长度的最大数组。subX和subY可以拼接成Z1,那么由subXX的数组元素来替换subX拼接成Z2,很明显Z2一定大于Z1。因此subX不是拼接成最大数组Z的子数组,与假设矛盾。因此,subX是X的最大数组。

既然知道subX是X中长度为r的最大数组,找出这个数组只要在元素的可能范围内选取最大元素,即可贪心法找出。

问题的下一步是:如何将两个最大数组合并成一个最大数组。开始的想法是:反正所有元素都要使用,使用类似归并法的方法,将大值尽可能排在前面即可。整体思路是对的,但是有个致命的bug:当遇到相等的比较,那么使用哪一个?一开始没有意识到这个问题,随便是用哪一个,结果wrong了好久。最后终于意识到,选择哪一个结果不一样的:

例如:

案例1:

5,3

5,8

案例2:

5,5,8

5,8

案例3:

5

5,8

案例4:

5,5,3,7,9

5,5,3,7,8

等考虑完成这些情况后,调试AC

public class Solution {
public int[] submax(int[]numx,int subk){
if(subk>numx.length||subk==0)
return null;
if(subk==numx.length)
return numx;
int[] subre=new int[subk];
int left=0,right=numx.length-subk;
for(int i=0;i<subk;i++){
int max=Integer.MIN_VALUE;
int maxIndex=-1;
for(int j=left;j<=right;j++){
if(max<numx[j]){
max=numx[j];
maxIndex=j;
}
}
if(maxIndex!=-1){
subre[i]=max;
left=maxIndex+1;
right++;
}
}
return subre;
}
public int[] merge(int[] sub1,int[] sub2){
if(sub1==null||sub2==null)
return sub1!=null?sub1:sub2;
int len1=sub1.length;
int len2=sub2.length;
int len=len1+len2;
int[] mergeList=new int[len];
int i=0,j=0;
int index=0;
while(i<len1&&j<len2){
if(sub1[i]<sub2[j])
mergeList[index++]=sub2[j++];
else {
if(sub1[i]>sub2[j])
mergeList[index++]=sub1[i++];
else {
int equalNum;
boolean find=false;
for(equalNum=1;i+equalNum<len1&&j+equalNum<len2;equalNum++){
if(sub1[i+equalNum]!=sub2[j+equalNum]){
find=true;break;
}
}
if(!find&&(i+equalNum<len1||j+equalNum<len2))
find=true;
if(find){
int whichone=0;
if(i+equalNum>=len1||j+equalNum>=len2)
whichone=i+equalNum<len1?1:2;
else {
whichone=sub1[i+equalNum]<sub2[j+equalNum]?2:1;
}
mergeList[index++]=whichone==1?sub1[i++]:sub2[j++];
}
else {
mergeList[index++]=sub1[i++];
}
}
}
}
while(i<len1)
mergeList[index++]=sub1[i++];
while(j<len2)
mergeList[index++]=sub2[j++];
return mergeList;
}
public int comparIntList(int[] first,int[] second){
if(first.length!=second.length)
return first.length-second.length;
for(int i=0;i<first.length;i++)
if(first[i]!=second[i]){
return first[i]-second[i];
}
return 0;
}
public int[] maxNumber(int[] nums1, int[] nums2, int k) {
int[] re=new int[k];
int[] subre1,subre2;
int len1=nums1.length;
int len2=nums2.length;
if(k>len1+len2)
return null;
int minNum1=k-len2<0?0:k-len2;
int maxNum1=len1<k?len1:k;
for(int i=minNum1;i<=maxNum1;i++){
subre1=submax(nums1, i);
subre2=submax(nums2, k-i);
int[] temp=merge(subre1,subre2);
if(i==minNum1||comparIntList(temp,re)>0){
System.arraycopy(temp, 0, re, 0, k);
}
}
return re;
}
}


实际上,针对相等比较的情况,需要比较的是剩余数组的大小,然后对大的数组,压一个元素进结果数据。隔壁家的代码就是精炼

public int[] maxNumber(int[] nums1, int[] nums2, int k) {
int n = nums1.length;
int m = nums2.length;
int[] ans = new int[k];
for (int i = Math.max(0, k - m); i <= k && i <= n; ++i) {
int[] candidate = merge(maxArray(nums1, i), maxArray(nums2, k - i), k);
if (greater(candidate, 0, ans, 0)) ans = candidate;
}
return ans;
}
private int[] merge(int[] nums1, int[] nums2, int k) {
int[] ans = new int[k];
for (int i = 0, j = 0, r = 0; r < k; ++r)
ans[r] = greater(nums1, i, nums2, j) ? nums1[i++] : nums2[j++];
return ans;
}
public boolean greater(int[] nums1, int i, int[] nums2, int j) {
while (i < nums1.length && j < nums2.length && nums1[i] == nums2[j]) {
i++;
j++;
}
return j == nums2.length || (i < nums1.length && nums1[i] > nums2[j]);
}
public int[] maxArray(int[] nums, int k) {
int n = nums.length;
int[] ans = new int[k];
for (int i = 0, j = 0; i < n; ++i) {
while (n - i + j > k && j > 0 && ans[j - 1] < nums[i]) j--;
if (j < k) ans[j++] = nums[i];
}
return ans;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: