题目描述
给定一个整数数组,编写一个函数,找出索引m和n,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的m和n(例如整个数组是有序的),请返回[-1,-1]。
示例:
输入: [1,2,4,7,10,11,7,12,6,7,16,18,19]
输出: [3,9]
提示:
- 0 <= len(array) <= 1000000
解题思路与代码
首先这道题是一道不算太难的中等题,难度算是中等偏简单吧。
-
首先,我先想出一个双指针的做法,这种做法呢就是只要遇到前面的大于后面的元素,就去交换元素,然后回溯指针,直到前面的元素小于后面的元素位置。
- 但是呢,这种做法的时间复杂度太高,超出了题目的时间限制,所以这种做法就直接pass掉。
-
紧接着,我就又想出了一个double双指针的做法,其逻辑是,把m和n的逻辑分开去写。
- 你可以把上一种回溯双指针的做法理解为,我把m和n的逻辑杂糅在一起去写了。因为每当出现前面>后面元素的情况,我就要去检查并更改m和n的数值。
- 而这一次呢,我创建出了4个指针。分别是max_m,min_n m,n 。这个时候我们只需要一个for循环就能解决问题。
max_m = array[0],min_n = array.back(),m = -1,n = -1;
- 在循环中,首先正向的,只要后一个元素 > 前一个元素。 我们就刷新 max_m 的值,使其 = array[i],否则,n = i。
- 其次是反向的,从数组的尾部来看,只要后一个元素 > 前一个元素。我们就刷新 min_n 的值,使其 = array[size - 1 - i],否则,m = size - 1 -i。
-
就这样,简简单单,我们就解决了这道题的所有逻辑部分。哦,对了,你还得写一个函数,去判断这个数组会不会第一开始,就是个有序数组,这个就不用我去教你了吧~
-
最后,我们只需要返回{m,n}的值就行。
具体的代码如下:
class Solution {
public:
vector<int> subSort(vector<int>& array) {
if (isOrdered(array)) return {-1,-1};
int size = array.size();
int max_m = array[0];
int min_n = array.back();
int m = -1;
int n = -1;
for(int i = 1; i < size; ++i){
if(array[i] >= max_m) max_m = array[i];
else n = i;
if(array[size - 1 - i] <= min_n) min_n = array[size - 1 - i];
else m = size - 1 - i;
}
return {m,n};
}
bool isOrdered(vector<int>& array) {
if (array.size() <= 1) return true;
for (int i = 1; i < array.size(); ++i) {
if (array[i - 1] > array[i]) return false;
}
return true;
}
};
复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)
总结
这道题目的意义在于测试和提升编程者在以下几个方面的能力:
-
问题分析:题目要求在给定的整数数组中找到一个最短的子数组,使得对这个子数组进行排序后整个数组变为有序。这需要编程者能够充分理解题意并分析问题。
-
编程思维:编程者需要思考如何高效地找到这个子数组的边界。这道题目要求实现一个高效的解决方案,因此编程者需要思考如何避免不必要的计算,如何降低时间复杂度。
-
编码技巧:在实现解决方案的过程中,编程者需要熟练地使用循环、条件语句和数组操作等基本编程元素。此外,编程者还需要注意避免一些常见的错误,如死循环。
-
调试与优化:编程者可能在实现过程中遇到问题,需要通过调试和优化代码来解决这些问题。这道题目也可以帮助编程者学会如何在实际编程过程中发现并解决问题。
总的来说,这道题目旨在帮助编程者提升分析问题、设计算法、编写代码以及调试优化的能力,这些能力对于一个优秀的程序员来说是非常重要的。
最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容
。