LeetCode(581):最短无序连续子数组 Shortest Unsorted Continuous Subarray(Java)

234 篇文章 1 订阅
177 篇文章 0 订阅

2019.10.27 #程序员笔试必备# LeetCode 从零单刷个人笔记整理(持续更新)

github:https://github.com/ChopinXBP/LeetCode-Babel

这道题根本的思路是要找到无序子数组的左边界和右边界,有三种方法:

1.排序

对原数组进行排序,将排序后的数组与原数组进行比较,找出最左和最右开始不对应的结点。可以从首尾进行顺序遍历,也可以用二分搜索。

2.借助栈

将所有元素依次入栈,如果当前元素比栈顶元素大,则连续弹出栈顶元素。被弹出的元素为位置不正确的元素,最小的弹出元素即为左边界。同理找出右边界即可。

3.寻找最小最大边界

遍历4次数组,前两次找出minEdge和maxEdge,后两次找出leftEdge和rightEdge。

minEdge(maxEdge)分别为数组开始非升序(非降序)后的最小(最大)元素,也即位置不正确的最小(最大)元素。

leftEdge(rightEdge)从第一个大于minEdge(小于maxEdge)的元素开始,代表位置不正确的子数组的左起(右起)第一个元素位置。


传送门:最短无序连续子数组

Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order, too.

You need to find the shortest such subarray and output its length.

给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

你找到的子数组应是最短的,请输出它的长度。

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

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


import java.util.Arrays;
import java.util.Stack;

/**
 *
 * Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending order,
 * then the whole array will be sorted in ascending order, too.
 * You need to find the shortest such subarray and output its length.
 * 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
 * 你找到的子数组应是最短的,请输出它的长度。
 *
 */

public class ShortestUnsortedContinuousSubarray {
    //排序
    public int findUnsortedSubarray(int[] nums) {
        int[] newNums = nums.clone();
        Arrays.sort(newNums);
        int begin = 0;
        while(begin < nums.length && nums[begin] == newNums[begin]){
            begin++;
        }
        int end = nums.length - 1;
        while(end >= 0 && nums[end] == newNums[end]){
            end--;
        }
        return begin < end ? end - begin + 1 : 0;
    }

    //栈
    public int findUnsortedSubarray2(int[] nums) {
        Stack<Integer> stack = new Stack<>();
        //将所有元素依次入栈,如果当前元素比栈顶元素大,则连续弹出栈顶元素。被弹出的元素为位置不正确的元素,将最小的弹出元素为左边界
        int leftEdge = nums.length - 1;
        for(int i = 0; i < nums.length; i++){
            while(!stack.isEmpty() && nums[stack.peek()] > nums[i]){
                leftEdge = Math.min(leftEdge, stack.pop());
            }
            stack.push(i);
        }
        stack.clear();
        //同理找出右边界
        int rightEdge = 0;
        for(int i = nums.length - 1; i >= 0; i--){
            while(!stack.isEmpty() && nums[stack.peek()] < nums[i]){
                rightEdge = Math.max(rightEdge, stack.pop());
            }
            stack.push(i);
        }
        return rightEdge - leftEdge > 0 ? rightEdge - leftEdge + 1 : 0;
    }

    //寻找最小最大边界
    public int findUnsortedSubarray3(int[] nums) {
        //minEdge(maxEdge)分别为数组开始非升序(非降序)后的最小(最大)元素,也即位置不正确的最小(最大)元素
        int minEdge = Integer.MAX_VALUE;
        boolean recordFlag = false;
        for(int i = 1; i < nums.length; i++){
            if(nums[i] < nums[i - 1]){
                recordFlag = true;
            }
            if(recordFlag){
                minEdge = Math.min(minEdge, nums[i]);
            }
        }
        int maxEdge = Integer.MIN_VALUE;
        recordFlag = false;
        for(int i = nums.length - 2; i >= 0; i--){
            if(nums[i] > nums[i + 1]){
                recordFlag = true;
            }
            if(recordFlag){
                maxEdge = Math.max(maxEdge, nums[i]);
            }
        }

        //leftEdge(rightEdge)从第一个大于minEdge(小于maxEdge)的元素开始,代表位置不正确的子数组的左起(右起)第一个元素位置
        int leftEdge = 0;
        while(leftEdge < nums.length){
            if(nums[leftEdge] > minEdge){
                break;
            }
            leftEdge++;
        }
        int rightEdge = nums.length - 1;
        while(rightEdge >= 0){
            if(nums[rightEdge] < maxEdge){
                break;
            }
            rightEdge--;
        }

        return leftEdge < rightEdge ? rightEdge - leftEdge + 1 : 0;
    }
}




#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值