您的位置:首页 > 其它

Create Maximum Number

2016-07-22 04:15 369 查看
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

Given nums1 =
[3, 4, 6, 5]
, nums2 =
[9, 1, 2, 5, 8, 3]
, k =
5

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


Given nums1 =
[6, 7]
, nums2 =
[6, 0, 4]
, k =
5

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


Given nums1 =
[3, 9]
, nums2 =
[8, 9]
, k =
3

return
[9, 8, 9]


分析:http://bookshadow.com/weblog/2015/12/24/leetcode-create-maximum-number/

问题可以转化为这样的两个子问题:

1. 从数组nums中挑选出t个数,在保持元素相对顺序不变的情况下,使得选出的子数组最大化。

2. 在保持元素相对顺序不变的前提下,将数组nums1与数组nums2合并,使合并后的数组最大化。

枚举nums1子数组与nums2子数组的长度len1, len2,在满足长度之和len1+len2等于k的前提下,分别求解最大子数组,并进行合并。

然后从合并得到的子数组中取最大数组即为所求。

public class Solution {
public int[] maxNumber(int[] nums1, int[] nums2, int k) {
if (nums1 == null || nums2 == null || k < 1) return new int[0];
if (nums1.length + nums2.length < k) return new int[0];
int[] tempMax = new int[k];

for (int i = 0; i <= k; i++) {
if (nums1.length >= i && nums2.length >= (k - i)) {
int[] max1 = maxValueAndIndex(nums1, i);
int[] max2 = maxValueAndIndex(nums2, k - i);
int[] arr = merge(max1, max2);

if (compare(arr, tempMax)) {
tempMax = arr;
}
}
}
return tempMax;
}

public boolean compare(int[] arr, int[] tempMax) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] < tempMax[i]) {
return false;
} else if (arr[i] > tempMax[i]) {
return true;
}
}
return false;
}

public int[] merge(int[] arr1, int[] arr2) {
int[] arr = new int[arr1.length + arr2.length];
int k = 0, p = 0, q = 0;

while (p < arr1.length || q < arr2.length) {
if (p >= arr1.length || q < arr2.length && arr1[p] < arr2[q]) {
arr[k] = arr2[q];
q++;
} else if (q >= arr2.length || p < arr1.length && arr1[p] > arr2[q]) {
arr[k] = arr1[p];
p++;
} else {
if (isGreater(arr1, p, arr2, q)) {
arr[k] = arr1[p];
p++;
} else {
arr[k] = arr2[q];
q++;
}
}
k++;
}

return arr;
}

public boolean isGreater(int[] arr1, int p, int[] arr2, int q) {
while (p < arr1.length || q < arr2.length) {
if (q >= arr2.length || p < arr1.length && arr1[p] > arr2[q]) {
return true;
} else if (p >= arr1.length || q < arr2.length && arr1[p] < arr2[q]) {
return false;
} else {
p++;
q++;
}
}
return true;

}

public int[] maxValueAndIndex(int[] arr, int k) {

int[] nums = new int[k];
if (k == 0)    return nums;

int p = -1;
for (int i = 0; i < arr.length; i++) {
while (p >= 0 && nums[p] < arr[i] && (arr.length - i + p + 1) > k) {
p--;
}
if (p == nums.length - 1) continue;
p++;
nums[p] = arr[i];
}
return nums;
}
}


还有一个自己的想法,但是代码通不过,擦!

分析: 其实数字有个很好的特点,只要在剩余的数字里取一个最大的数,放在当前位置上,那么我们就可以肯定,不肯能有比当前数更大的了。 比如: xx_ _ _, x表示那个位置上已经被填入数字了,那么从5, 2, 1,7,3中,找出一个,使得组合最大,你会毫不犹豫的选择7,因为如果你不选7,不管后面你把7放在哪个位置,都比放7的情况更小。

好了,有了这个基础,解决下面这题就简单了。

从两个数组中,我们一定要找一个最大的出来放在首位(根据我们上面的分析),但是,这里有个条件,就是从每个数组里取的数,不能倒着取,如果你从nums1取了6,不好意思,下次你就不能取3,或者4了。

那么,我们怎么取才能保证最大,而且,并且剩余可取数字的个数还必须至少是K呢,这个好像就很简单了吧。

用两个指针,p, q 分别指到两个数组的头部,表面两个指针后面的数字是可取的,前面的不行,当我们从两个数组里找最大数字的时候,我们只需要保证 (nums1.length - p1) + (nums2.length - q) >= k (最大值在nums1) 或者 (nums1.length - p) + (nums2.length - q1) >= k (最大值在nums2). 这里k的值会不断减少。

public class Solution {

public static void main(String[] args) {
int[] arr1 = { 1, 5, 8, 1, 4, 0, 8, 5, 0, 7, 0, 5, 7, 6, 0, 5, 5, 2, 4, 3, 6, 4, 6, 6, 3, 8, 1, 1, 3, 1, 3, 5,
4, 3, 9, 5, 0, 3, 8, 1, 4, 9, 8, 8, 3, 4, 6, 2, 5, 4, 1, 1, 4, 6, 5, 2, 3, 6, 3, 5, 4, 3, 0, 7, 2, 5, 1,
5, 3, 3, 8, 2, 2, 7, 6, 7, 5, 9, 1, 2 };
int[] arr2 = { 7, 8, 5, 8, 0, 1, 1, 6, 1, 7, 6, 9, 6, 6, 0, 8, 5, 8, 6, 3, 4, 0, 4, 6, 7, 8, 7, 7, 7, 5, 7, 2,
5, 2, 1, 9, 5, 9, 3, 7, 3, 9, 9, 3, 1, 4, 3, 3, 9, 7, 1, 4, 4, 1, 4, 0, 2, 3, 1, 3, 2, 0, 2, 4, 0, 9, 2,
0, 1, 3, 9, 1, 2, 2, 6, 6, 9, 3, 6, 0 };
Solution s = new Solution();
int[] max = s.maxNumber(arr1, arr2, 80);

for (int i = 0; i < max.length; i++) {
System.out.println(max[i]);
}
}

public int[] maxNumber(int[] nums1, int[] nums2, int k) {
if (nums1 == null || nums2 == null || k < 1)
return new int[0];
if (nums1.length + nums2.length < k)
return new int[0];
int p = 0;
int q = 0;

int[] maxNum = new int[k];

while (k > 0) {
int[] max1 = maxValueAndIndex(nums1, p, k - (nums2.length - q));
int[] max2 = maxValueAndIndex(nums2, q, k - (nums1.length - p));

if (max1[0] > max2[0]) {
maxNum[maxNum.length - k] = max1[0];
p = max1[1] + 1;
} else if (max1[0] == max2[0]) {
if (chooseNums1(nums1, p + 1, nums2, q + 1, k - 2)) {
maxNum[maxNum.length - k] = max1[0];
p = max1[1] + 1;
} else {
maxNum[maxNum.length - k] = max2[0];
q = max2[1] + 1;
}
} else {
maxNum[maxNum.length - k] = max2[0];
q = max2[1] + 1;
}
k--;
}
return maxNum;

}

// chose nums1 or not
public boolean chooseNums1(int[] nums1, int p, int[] nums2, int q, int k) {
if (p == nums1.length && q == nums2.length) {
return true;
} else if (p == nums1.length) {
return false;
} else if (q == nums2.length) {
return true;
} else if (k <= 0) {
return true;
} else {
int[] max1 = maxValueAndIndex(nums1, p, k - (nums2.length - q));
int[] max2 = maxValueAndIndex(nums2, q, k - (nums1.length - p));

if (max1[0] > max2[0]) {
return true;
} else if (max1[0] == max2[0]) {
return chooseNums1(nums1, p + 1, nums2, q + 1, k - 2);
} else {
return false;
}
}
}

public int[] maxValueAndIndex(int[] arr, int start, int k) {
int[] max = new int[2];
if (start == arr.length) {
max[0] = -1;
max[1] = start;
return max;
}
max[0] = arr[start];
max[1] = start;

while (start < arr.length && arr.length - start >= k) {
if (arr[start] > max[0]) {
max[0] = arr[start];
max[1] = start;
}
start++;
}
return max;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: