• 最短无序连续子数组 | 算法详细分析


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

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

    示例 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;
       }
    
    }
    
  • 相关阅读:
    【原創】字符首字母大寫格式化函數
    [ZT]如何使SQLServer的日志文件不会增大
    乘除法運算時的異常
    【ZT】delegate 与 多线程
    String.IsNullOrEmpty 方法
    专家指“IP地址告急”系炒作 人均IP可达百万
    如何將程序的Access数据库嵌入到资源中发布
    [ZT]JavaScript+div实现模态对话框[修正版]
    android button背景随心搭配
    图片上传,包括从相册选取与拍照上传
  • 原文地址:https://www.cnblogs.com/cosefy/p/13084468.html
Copyright © 2020-2023  润新知