"Li Kou" question 1673: find the most competitive subsequence (stack)
Give you an integer array num and a positive integer k, and return the most competitive num subsequence with length K.
A subsequence of an array is a sequence obtained by deleting some elements from the array (elements may not be deleted).
In the first different position between subsequence A and subsequence b, if the number in a is less than the corresponding number in b, subsequence A is more competitive than subsequence b (with the same length). For example, [1,3,4] is more competitive than [1,3,5]. In the first different position, that is, the last position, 4 is less than 5.
Example 1:
Input: nums = [3,5,2,6], k = 2 Output:[2,6] Interpretation: in all possible subsequence sets {[3,5], [3,2], [3,6], [5,2], [5,6], [2,6]} In,[2,6] Most competitive.
Example 2:
Input: nums = [2,4,3,3,5,4,9,6], k = 4 Output:[2,3,3,4]
Tips:
- 1 <= nums.length <= 10^5
- 0 <= nums[i] <= 10^9
- 1 <= k <= nums.length
Understand the meaning of the question:
- Definition of subsequence: subsequence of an array is a sequence obtained by deleting some elements (elements may not be deleted) from the array. Note: the definition of "subsequence" requires these elements to maintain their relative positions in the original array;
- The definition of "minimum competitiveness" in the title is similar to "minimum dictionary order". If you did 316. Remove duplicate letters , 402. Remove the K digits and 456.132 mode You will know that this problem may need to use "stack". Therefore, we need to discuss why we can use "stack" to solve this problem.
Why do you think of using "stack"
See "example 1"
Input: nums = [3, 5, 2, 6], k = 2
Keep 2 elements and remove 2 elements. Read the input array into a linear data structure in turn:
- Read 3, add 3, and then [3];
- Read 5 and add 5. At this time [3, 5];
- When you read 2, 2 is smaller than the previous 5, so you can abandon 5 because [3, 2,...] Ratio [3, 5,...] More competitive. Similarly, 2 is smaller than the previous 3, so 3 can be discarded. At this time, the linear data structure is empty and 2 is added. The linear data structure is added after 5:3, and the first out is just in line with the law of "last in first out", so the "stack" is used.
- Read 6 and add 6. At this time [2, 6] is what you want.
Points needing attention:
- Calculate the number of elements that can be removed according to the length and k of the array. They can be removed only when they need to be removed;
- If there are elements that can be deleted after the traversal is completed, the elements should be deleted from the end of the stack. This is because the elements in the "stack" are monotonous, and deleting elements from the end can ensure the most competitive.
Reference code 1:
import java.util.ArrayDeque; import java.util.Deque; public class Solution { public int[] mostCompetitive(int[] nums, int k) { int len = nums.length; if (k == len) { return nums; } // Number of elements to be removed int removeCount = len - k; Deque<Integer> stack = new ArrayDeque<>(); for (int num : nums) { // Note: only when there are elements that can be removed can they be removed while (removeCount > 0 && !stack.isEmpty() && num < stack.peekLast()) { stack.removeLast(); removeCount--; } stack.addLast(num); } // If there are elements that can be deleted, delete them from the end for (int i = 0; i < removeCount; i++) { stack.removeLast(); } // At this time, the elements in the stack are the most competitive arrays. You can traverse the stack and assign values to the array int[] res = new int[k]; int index = k - 1; for (int i = 0; i < k; i++) { res[index] = stack.removeLast(); index--; } return res; } }
Note: ArrayDeque is recommended in the Java document Stack class. The API with Last suffix is used because the complexity at the end of Array implementation operation is O ( 1 ) O(1) O(1), and the Deque implementation is a circular array. In fact, the operation head and tail can be used. As long as it is used as a stack, the API does not have to be the same as me.
Complexity analysis:
- Time complexity: O ( N ) O(N) O(N), here N N N is the size of the input array. All elements are stacked once and out of the stack once;
- Space complexity: O ( N ) O(N) O(N), the stack size is N N N.
Generally speaking, this kind of problem can put an element that can never be removed in the stack first, so it can avoid judging whether the stack is empty during the loop. According to the data range given by the topic, you can put an integer less than or equal to 0 here.
Reference code 2:
import java.util.ArrayDeque; import java.util.Deque; public class Solution { public int[] mostCompetitive(int[] nums, int k) { int len = nums.length; if (k == len) { return nums; } int removeCount = len - k; Deque<Integer> stack = new ArrayDeque<>(); // sentry stack.addLast(0); for (int num : nums) { // Because there is 0, the stack must not be empty, so there is no need to judge whether the stack is empty while (removeCount > 0 && num < stack.peekLast()) { stack.removeLast(); removeCount--; } stack.addLast(num); } for (int i = 0; i < removeCount; i++) { stack.removeLast(); } int[] res = new int[k]; int index = k - 1; for (int i = 0; i < k; i++) { res[index] = stack.removeLast(); index--; } return res; } }
Complexity analysis: (same as "reference code 1").
summary
The subsequence keeps the relative order of elements and the definition of "most competitive" determines that solving this problem just conforms to the law of "last in, first out". Therefore, you can use "stack", and the elements in the stack just keep the monotonous characteristics.
Recently, I'm explaining a series of tutorials on "algorithm is not fun" at station B, address , explain the algorithm and data structure from a novice perspective, which is easy to understand and rigorous. The official account: algorithm is not fun. Thank you for your support!