zoukankan      html  css  js  c++  java
  • 最短无序连续子数组 | 算法详细分析

    题目:最短无序连续子数组。

    给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
    你找到的子数组应是最短的,请输出它的长度。

    示例 1:

        输入: [2, 6, 4, 8, 10, 9, 15]
        输出: 5
        解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。
    

    说明 :

    ​ 输入的数组长度范围在 [1, 10,000]。
    ​ 输入的数组可能包含重复元素 ,所以升序的意思是<=。

     package com.test.day6_9;
     
     /**
     
      * @author cosefy
     
      * @date 2020/6/10
        */
        public class FindUnsortedSubarray {
        public static void main(String[] args) {
            int[] nums = {2, 5, 2, 3};
            int res1 = findUnsortedSubarray_Test1(nums);
            int res3 = findUnsortedSubarray_Test3(nums);
     
        ​    System.out.println("The result of test1: " + res1);
        ​    System.out.println("The result of test3: " + res3);
        }
    
    解法一:暴力算法(不占用空间)

    思路:一边从左边开始,依次确定当前元素是否是当前位置以后最小的元素,否则就退出循环,得到左边界;同理,获得右边界。
    分析:时间复杂度(n),空间复杂度O(1)
    易错点:注意参数的边界问题
    思考:
    -时间效率不高,可以考虑用空间换时间

    public static int findUnsortedSubarray_Test1(int[] nums) {
        int front_count = 0;
        int rear_count = 0;
        int i;
        for (i = 0; i < nums.length; i++) {
            boolean flag1 = true;
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i] > nums[j]) {
                    flag1 = false;
                    break;
                }
            }
            if (flag1)
                front_count++;
            else
                break;
        }
        for (int i2 = nums.length - 1; i2 >= i; i2--) {
            boolean flag2 = true;
            for (int j2 = i2 - 1; j2 >= i; j2--) {
                if (nums[i2] < nums[j2]) {
                    flag2 = false;
                    break;
                }
            }
            if (flag2)
                rear_count++;
            else
                break;
        }
        return nums.length - front_count - rear_count;
    }
    
    解法二:先排序再确定边界

    思路:排序之后,存放到一个新数组中,通过比较两个数组的差异得到左右边界。
    分析:时间复杂度O(nlogn),空间复杂度O(n)

    解法三:确定左右两边局部边界,再判断

    思路:首先根据数组左边符合递增排序确定简单左边界,根据数组右边符合递增排序确定右边简单右边界。接下来,找出数组无序部分的最小值和最大值,对左右两个简单边界进行精确边界的判断。
    分析:时间复杂度O(n),空间复杂度O(1)
    易错点:注意循环的判断条件,注意取值

      public static int findUnsortedSubarray_Test3(int[] nums) {
           int left = 0;
           int right = nums.length - 1;
           while (left < right) {
               if (nums[left] < nums[left + 1])   //符合递增条件
                   ++left;           //简单左边界右移
               else
                   break;            //不满足条件则跳出循环
           }
           while (left < right) {
               if (nums[right] > nums[right - 1])
                   --right;
               else
                   break;
           }
           //上面两个循环得到左右两个初级边界
    
       ​    int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
       ​    for (int i = left; i < right; i++) {
       ​        min = Math.min(min, nums[i]);   //获得当前无序序列中的最小值
       ​        max = Math.max(max, nums[i]);   //获得当前无序序列中的最大值
       ​    }
    
       ​    //下面根据min和max对初级边界进行精确缩减
       ​    for (int i = 0; i <= left; i++) {
       ​        if (nums[i] > min) {
       ​            left = i;
       ​            break;
       ​        }
       ​    }
       ​    for (int i = nums.length - 1; i >= right; i--) {
       ​        if (nums[i] < max) {
       ​            right = i;
       ​            break;
       ​        }
       ​    }
       ​    return right - left + 1;
       }
    
    }
    
  • 相关阅读:
    Javascript高级篇-Function对象
    Object类、instanceof
    [一]Head First设计模式之【策略模式】(鸭子设计的优化历程)
    匿名内部类
    设计模式之单例模式
    长江商业评论读书笔记
    [转]Freemarker数据类型转换
    面向对象编程——概论(一)
    IP地址处理模块IPy
    系统性能模块psutil
  • 原文地址:https://www.cnblogs.com/cosefy/p/13084468.html
Copyright © 2011-2022 走看看