单调栈:最短无序连续子数组

单调栈:最短无序连续子数组

问题:

在这里插入图片描述

1.排序法( O(nlogn))

思路:

建立一个新数组,其元素为原数组的升序排列,比较两数组,得到第一个和最后一个不匹配的元素,它们都需重新排列,且是子数组的边界

代码:

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n=nums.size();
        vector<int> sort_array( n );
        sort_array=nums;
        int i;
        int j;
        sort( sort_array.begin(),sort_array.end() );
        for( i=0;i<n;i++ )
        {
            if( sort_array[i]!=nums[i] )
                break;
        }
        for( j=n-1;j>0;j-- )
        {
            if( sort_array[j]!=nums[j] )
                break;
        }
        return max( j-i+1,0 );
    }
};

2.单调栈( O(n))

思路:

为寻找无序子数组中最小元素与最大元素在已排好序的整体数组中应处于的位置,使用单调栈。

先从头遍历数组并将数组元素的下标入栈,若出现当前需入栈的元素值小于栈顶元素所对应的元素值,我们需找到该元素应处于的正确位置。设该元素的正确位置对应的下标为k。将k赋为st.top(),并退栈,若该元素仍比st.top()对应的元素小,重复上述操作。最后得到的k即为该元素正确位置对应的下标。在一次遍历后,找到最小的k值,即为无序子数组的下边界。

设栈为st,在遍历完成后用st = stack() 清空栈。

再从尾部向前遍历数组,按上述相同的方法进行,若出现当前需入栈的元素值大于栈顶元素所对应的元素值,设其正确位置对应的下标为j。不断pop直至当前元素值不大于栈顶元素所对应的值。在一次遍历后,找到最大的j值,即为无序子数组的上边界。

当下边界大于上边界时,返回j-k+1,否则返回0

代码:

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n=nums.size();
        stack<int> st;
        int i;
        int k=n-1;
        int j=0;
        for( i=0;i<n;i++ )
        {
            while (!st.empty() && nums[st.top()] > nums[i])
            {
                k = min(k, st.top());
                st.pop();
            }
            st.push(i);
        }
        st = stack<int>();
        for( i=n-1;i>=0;i-- )
        {
            while (!st.empty() && nums[st.top()] < nums[i])
            {
                j = max(j, st.top());
                st.pop();
            }
            st.push(i);
        }
        return (j > k) ? j - k + 1 : 0;
    }
};

3.不使用额外存储空间的方法( O(n))

思路:

设数组为nums[n]

从数组头开始遍历,若出现nums[i]<nums[i-1],则nums[i]不处于其正确位置,找到不处于其正确位置的最小nums[i],设为min,此即为无序子数组的最小值。再从数组头进行第二次遍历,找到第一个大于此最小值的值,该值所处的位置即为最小值的正确位置,也即为子数组的下边界。

从数组尾开始遍历,同理,若出现nums[i]>nums[i+1],则nums[i]不处于其正确位置,找到不处于其正确位置的最大nums[i],设为max,此即为无序子数组的最大值。再从数组尾进行第二次遍历,找到第一个小于此最大值的值,该值所处的位置即为最大值的正确位置,也即为子数组的上边界。

代码:

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n=nums.size();
        int i;
        int min_num=nums[n-1];
        int max_num=nums[0];
        int k;
        int j;
        for( i=1;i<n;i++ )
            if( nums[i]<nums[i-1] )
            {
                min_num=min(nums[i],min_num);
            }
        for( i=n-2;i>=0;i-- )
            if( nums[i]>nums[i+1] )
            {
                max_num=max(nums[i],max_num);
            }
        for( i=0;i<n;i++ )
            if( nums[i]>min_num )
                break;
        k=i;
        for( i=n-1;i>=0;i-- )
            if( nums[i]<max_num )
                break;
        j=i;
        return ( j-k>0? j-k+1:0 );
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

happy19991001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值