1. 程式人生 > >LeetCode581:最短無序連續子陣列

LeetCode581:最短無序連續子陣列

給定一個整數陣列,你需要尋找一個連續的子陣列,如果對這個子陣列進行升序排序,那麼整個陣列都會變為升序排序。

你找到的子陣列應是最短的,請輸出它的長度。

示例 1:

輸入: [2, 6, 4, 8, 10, 9, 15]
輸出: 5
解釋: 你只需要對 [6, 4, 8, 10, 9] 進行升序排序,那麼整個表都會變為升序排序。

說明 :

  1. 輸入的陣列長度範圍在 [1, 10,000]。
  2. 輸入的陣列可能包含重複元素 ,所以升序的意思是<=。

解析:

        筆者做這道題時沒有考慮到已經完全排序的情況。這道題目,如果是陣列完全排序,則所有的元素都在其應在的位置,連續陣列長度為0;若原陣列不是完全排序的,則需要知道原陣列首部和尾部有多少元素在排序陣列中應在的位置。所以,把原陣列備份並排序,從頭到尾,從尾到頭查詢第一個不在排序位置的元素位置,兩個下標差值加1即為連續子陣列長度。如果原陣列是已排序的,則返回0.

程式碼:

int findUnsortedSubarray(vector<int>& nums) 
{
	vector<int> copyNums(nums);
	sort(copyNums.begin(), copyNums.end());//排序
	int start, end;
	for (start = 0; start < nums.size(); start++)//從首部找到第一個不在其位的元素
	{
		if (nums[start] == copyNums[start])
			continue;
		else
			break;
	}
	for (end = nums.size() - 1; end >= 0; end--)//從尾部找到第一個不在其位的元素
	{
		if (nums[end] == copyNums[end])
			continue;
		else
			break;
	}
	if (end - start + 1 > 0)//注意判斷,原陣列可能是已經排序的
		return end - start + 1;
	return 0;

}

leetcode上有一種時間複雜度更低的方法,先找到原陣列第一個不是升序的位置,再找到原陣列最後一個不是升序的位置,然後找到兩個位置之間的最小值min和最大值max,向左判斷元素是否小於min,向右判斷元素是否大於max,找到剛好小於min和剛好大於max的元素位置,兩個位置之間的子陣列即為需要排序的連續子陣列。

程式碼:

int findUnsortedSubarray(vector<int>& nums) 
{
        int n = nums.size();
        int left = 0;
        int right = n - 1;
        while (left < n - 1 && nums[left] <= nums[left + 1])//找第一個非升序位置
            left += 1;
        if (left == n - 1)//已經排好序
            return 0;
        while (right > 0 && nums[right] >= nums[right - 1])//最後一個非升序位置
            right -= 1;
        int min_value = INT32_MAX;
        int max_value = INT32_MIN;
        for (int i = left; i < right + 1; i++) {//未排序的最大最小值
            min_value = min(nums[i], min_value);
            max_value = max(nums[i], max_value);
        }
        while (left > -1 && nums[left] > min_value)//向左找小於min的元素位置
            left -= 1;
        while (right < n && nums[right] < max_value)//向右找大於max元素的位置
            right += 1;
        return right - left - 1;
    }