leetcode : 321. Create Maximum Number : 有点难度的贪心法
2016-03-28 01:57
344 查看
321. Create Maximum Number
My SubmissionsQuestion
Total Accepted: 4587 Total
Submissions: 22666 Difficulty: Hard
Given two arrays of length
mand
nwith
digits
0-9representing two numbers. Create the maximum number of length
k <= m + nfrom digits of the two. The relative order of the digits from the same array must be preserved. Return an array of the
kdigits.
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; }
相关文章推荐
- LeetCode Lowest Common Ancestor of a Binary Serach Tree
- 移动web资源整理
- ThinkPHP3.2.3学习笔记1---控制器
- pageResponse - 让H5适配移动设备全家
- 几点建议,让Redis在你的系统中发挥更大作用
- Machine Learning 学习资源小收集
- PyQt4菜单栏
- Android解析——json解析为javabean
- Linux笔记
- 汇编写启动代码之设置栈和调用C语言2
- sass入门
- 习题2-4 子序列的和
- css3-font-face
- 如何精确地测量java对象的大小-底层instrument API
- mongodb入门
- 《Spring Boot实战》笔记(目录)
- Node.js domain异常捕获的一些实践
- 使用 Node.js 搭建 Web 服务器
- 浅谈属性动画简单使用之实现卫星菜单(二)
- c语言:四舍五入