通过将所有出现的元素移动到开始或结束来对数组进行排序的最少操作
给定一个大小为N且 arr[i] ≤ N的数组arr[] ,任务是找到以升序对数组进行排序的最小操作数,其中在一个操作中,您可以选择一个整数X ,并且:
- 将所有出现的 X 移到开头或
- 将所有出现的 X 移到末尾。
例子:
Input: arr[] = {2, 1, 1, 2, 3, 1, 4, 3}, N = 8
Output: 2
Explanation:
First operation -> Select X = 1 and add all the 1 in front.
The updated array arr[] = {1, 1, 1, 2, 2, 3, 4, 3}.
Second operation -> Select X= 4 and add all the 4 in end.
The updated array arr[ ] = [1, 1, 1, 2, 2, 3, 3, 4].
Hence the array become sorted in two operations.
Input: arr[] = {1, 1, 2, 2}, N = 4
Output: 0
Explanation: The array is already sorted. Hence the answer is 0.
方法:这个问题可以使用 这 基于以下思想的贪心方法。
The idea to solve this problem is to find the longest subsequence of elements (considering all occurrences of an element) which will be in consecutive positions in sorted form. Then those elements need not to be moved anywhere else, and only moving the other elements will sort array in minimum steps.
请按照下图更好地理解:
插图:
For example arr[] = {2, 1, 1, 2, 3, 1, 4, 3}.
When the elements are sorted they will be {1, 1, 1, 2, 2, 3, 3, 4}.
The longest subsequence in arr[] which are in consecutive positions as they will be in sorted array is {2, 2, 3, 3}.
So the remaining unique elements are {1, 4} only.
Minimum required operations are 2.
First operation:
=> Move all the 1s to the front of array.
=> The updated array arr[] = {1, 1, 1, 2, 2, 3, 4, 3}
Second operation:
=> Move 4 to the end of the array.
=> The updated array arr[] = {1, 1, 1, 2, 2, 3, 3, 4}
根据上面的思路,按照下面的步骤解决这个问题:
- 将元素分为三类。
- 我们将在前面移动的元素。
- 我们不会在任何地方移动的元素。
- 我们将最终移动的元素。
- 所以要使数组排序,这三个条件必须满足。
- 第一类的所有元素必须小于第二类的最小元素。
- 第三类的所有元素必须大于第二类的最大元素。
- 如果我们删除第一类和第三类的所有元素,剩下的数组必须按非降序排序。
- 因此,为了使总步数最小化,第二类中的元素必须是最大的,如从上述想法所见。
- 存储每个元素的第一次和最后一次出现。
- 从i = N 开始迭代到 1 (将i视为数组元素而不是索引):
- 如果它的结束点小于元素的起始索引刚好大于它,则增加子序列的大小。
- 如果不是,则将其设置为最后一个并继续其他元素。
- 除了最长子序列中的元素之外的唯一元素是必需的答案。
以下是上述方法的实现:
C++
// C++ code for above approach
#include
using namespace std;
// Function to find the minimum operation
// to sort the array
int minOpsSortArray(vector& arr, int N)
{
vector > O(N + 1,
vector(2, N + 1));
// Storing the first and the last occurence
// of each integer.
for (int i = 0; i < N; ++i) {
O[arr[i]][0] = min(O[arr[i]][0], i);
O[arr[i]][1] = i;
}
int ans = 0, tot = 0;
int last = N + 1, ctr = 0;
for (int i = N; i > 0; i--) {
// Checking if the integer 'i'
// is present in the array or not.
if (O[i][0] != N + 1) {
ctr++;
// Checking if the last occurrence
// of integer 'i' comes before
// the first occurrence of the
// integer 'j' that is just greater
// than integer 'i'.
if (O[i][1] < last) {
tot++;
ans = max(ans, tot);
last = O[i][0];
}
else {
tot = 1;
last = O[i][0];
}
}
}
// Total number of distinct integers -
// maximum number of distinct integers
// that we do not move.
return ctr - ans;
}
// Driver code
int main()
{
int N = 8;
vector arr = { 2, 1, 1, 2, 3, 1, 4, 3 };
// Function call
cout << minOpsSortArray(arr, N);
return 0;
}
2
时间复杂度:O(N)
辅助空间: O(N)