iOS LeetCode ☞ maximum number of splices

Posted by immanuelx2 on Mon, 20 Dec 2021 17:33:42 +0100

Given two arrays of length m and N, their elements are composed of 0 - 9, representing the numbers on each bit of two natural numbers. Now select k (k < = m + n) numbers from the two arrays and splice them into a new number. The numbers taken from the same array are required to maintain their relative order in the original array.

Find the maximum number that satisfies this condition. The result returns an array of length k representing the maximum number.

Note: Please optimize the time and space complexity of your algorithm as much as possible.

Example 1:

input:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
 output:
[9, 8, 6, 5, 3]

Example 2:

input:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
 output:
[6, 7, 6, 0, 4]

Example 3:

input:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
 output:
[9, 8, 9]

Problem solving ideas

In order to find the maximum number with length k, the largest subsequence needs to be selected from the two arrays respectively. The sum of the lengths of the two subsequences is kk, and then the two subsequences are combined to obtain the maximum number. The minimum length of the two subsequences is 0, the maximum cannot exceed K and cannot exceed the corresponding array length.

If the length of array nums1 is m and the length of array nums2 is n, it is necessary to select the subsequence with length x from array nums1 and the subsequence with length y from array nums2, where x + y = k and meet 0 ≤ x ≤ m and 0 ≤ y ≤ n. You need to traverse all possible X and Y values to get the maximum number for each set of X and Y values. Maintain the maximum number that can be obtained by splicing throughout the process.

For each set of x and y values, the process of obtaining the maximum number is divided into two steps. The first step is to obtain the maximum subsequence of the specified length from the two arrays respectively, and the second step is to merge the two maximum subsequences.

The first step can be achieved by monotonic stack. Monotone stack satisfies monotonic decrement of elements from the bottom of the stack to the top of the stack, traverses the array from left to right, and maintains the elements in the monotone stack during traversal. It is necessary to ensure that the number of elements in the monotone stack is equal to the length of the specified maximum subsequence after traversal. After traversal, the elements from the bottom of the stack to the top of the stack are spliced in turn to obtain the maximum subsequence.

The second step is to customize the comparison method. First, compare the current elements of the two subsequences. If the two current elements are different, select the larger element as the next merged element. Otherwise, you need to compare all the subsequent elements to determine which element to select as the next merged element.

code

	// 321. Maximum number of splices
    func maxNumber(_ nums1: [Int], _ nums2: [Int], _ k: Int) -> [Int] {
        func compare(_ subsequence1: [Int], _ index1: Int, _ subsequence2: [Int], _ index2: Int) -> Int {
            var index1 = index1, index2 = index2
            let x = subsequence1.count, y = subsequence2.count
            while index1 < x && index2 < y {
                let difference = subsequence1[index1] - subsequence2[index2]
                if difference != 0 {
                    return difference
                }
                index1 += 1
                index2 += 1
            }
            return (x - index1) - (y - index2)
        }
        
        func merge(_ subsequence1: [Int], _ subsequence2: [Int]) -> [Int] {
            let x = subsequence1.count, y = subsequence2.count
            if x == 0 {
                return subsequence2
            }
            if y == 0 {
                return subsequence1
            }
            
            let mergeCount = x + y
            var merged = [Int](repeating: 0, count: mergeCount)
            var index1 = 0, index2 = 0
            for i in 0..<mergeCount {
                if compare(subsequence1, index1, subsequence2, index2) > 0 {
                    merged[i] = subsequence1[index1]
                    index1 += 1
                } else {
                    merged[i] = subsequence2[index2]
                    index2 += 1
                }
            }
            return merged
        }
        
        func maxSubsequence(_ nums: [Int], _ k: Int) -> [Int] {
            var stack = [Int](repeating: 0, count: k)
            var top = -1, remain = nums.count - k
            for num in nums {
                while top >= 0 && stack[top] < num && remain > 0 {
                    top -= 1
                    remain -= 1
                }
                if top < k - 1 {
                    top += 1
                    stack[top] = num
                } else {
                    remain -= 1
                }
            }
            return stack
        }
        
        let m = nums1.count, n = nums2.count
        var subsequence = [Int](repeating: 0, count: k)
        let start = max(0, k - n), end = min(k, m)
        for i in start...end {
            let subsequence1 = maxSubsequence(nums1, i)
            let subsequence2 = maxSubsequence(nums2, k - i)
            let curMaxSubsequence = merge(subsequence1, subsequence2)
            if compare(curMaxSubsequence, 0, subsequence, 0) > 0 {
                subsequence = curMaxSubsequence
            }
        }
        
        return subsequence
    }

Topics: iOS Algorithm leetcode