滑动窗口系列(单序列双指针)9/9

一、最短无序连续子数组

题意:

给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。请你找出符合题意的 最短 子数组,并输出它的长度。

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

在 [2,6,4,8,10,9,15] 中,我们可以看出最后一个不符合升序的数字是9,第一个不符合升序的数字是6。其余两侧的元素都是正常的升序规律。

要点:所以我们这道题就是找左侧正常序列的结束点;右侧正常序列的起点。

右侧正常序列的起点:只要不出现右侧数字小于max;如果小于就要更新(此时更新的点就是起点)

        for (int i = 1; i < nums.length; i++) {
            if (max > nums[i])
                endIndex = i;
            max = Math.max(max, nums[i]);
        }

左侧正常序列的结束点:主要不出现左侧数字大于min,如果大于就要更新(此时更新的点是结束点)

        for (int i = nums.length-2; i >= 0; i--) {
            if (min < nums[i])
                startIndex = i;
            min = Math.min(min, nums[i]);
        }
代码:
/**
 * 贪心算法:子数组中的最小值是大于数组的最小值的;最大值是小于数组的最大值的
 */
class Solution {
    public int findUnsortedSubarray(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        int startIndex = nums.length-1;
        int endIndex = 0;
        int max = nums[0];
        int min = nums[startIndex];
        // max是这段范围中的最大值,要是在max的右边并且还比max小的 就要到数组里面进行排序
        for (int i = 1; i < nums.length; i++) {
            if (max > nums[i])
                endIndex = i;
            max = Math.max(max, nums[i]);
        }
        // min是这段范围中的最小值,要是在min的左边并且还比min大的 就要到min里面排序
        for (int i = nums.length-2; i >= 0; i--) {
            if (min < nums[i])
                startIndex = i;
            min = Math.min(min, nums[i]);
        }
        return startIndex - endIndex == nums.length - 1 ? 0 : endIndex - startIndex + 1;
    }
}

二、长按键入

题意:

你的朋友正在使用键盘输入他的名字 name。偶尔,在键入字符 c 时,按键可能会被长按,而字符可能被输入 1 次或多次。

你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字(其中一些字符可能被长按),那么就返回 True

给定一个name,每一个字符都有可能是多个的。判断typed缩减完是否是name。

思路:

left和right分别指向name和typed。

1.当name.charAt(left)==typed.charAt(right);两个指针同时向后移动;

2.当不相等的时候,要判断typed.charAt(right)==typed.charAt(right-1),

     2.1如果相等的话就说明是长按的。

     2.2如果不相等的话,就说明不匹配,直接return false;

代码:
class Solution {
    public boolean isLongPressedName(String name, String typed) {
        int left=0;
        int right=0;
        while(right<typed.length()){
            if(left<name.length()&&name.charAt(left)==typed.charAt(right)){
                left++;
            }else if(right==0||typed.charAt(right)!=typed.charAt(right-1)){
                return false;
            }
            right++;
        }
        return left==name.length();
    }
}

三、移动片段得到字符

给你两个字符串 start 和 target ,长度均为 n 。每个字符串  由字符 'L''R' 和 '_' 组成,其中:其中片段 'L' 只有在其左侧直接存在一个 空位 时才能向  移动,而片段 'R' 只有在其右侧直接存在一个 空位 时才能向  移动。

思路:

‘L’左边有空格才能左移,‘R’右边有空格才能右移。

1.如果两个字符串去除'_'后不相同,那么就无法通过移动片段获得。

2.如果相同,那么顺序都是相同的;比较相同字符的下标。(如果'_'之后的字符都不相同 那么有直接return false)

    2.1:如果碰到的是L,i<j; i无法左移得到j,直接返回false;

    2.2:如果碰到的是R,i>j;  i无法通过右移得到j,直接返回false;

3.如果有一个指针达到结尾了,直接break;

代码:
class Solution {
    public boolean canChange(String start, String target) {
        if(!start.replace("_","").equals(target.replace("_","")))return false;
        int i=0;
        int j=0;
        while(i<start.length()&&j<target.length()){
            while(i<start.length()&&start.charAt(i)=='_')i++;
            while(j<target.length()&&target.charAt(j)=='_')j++;
            //如果有一个提前到末尾 直接返回
            if(i==start.length()||j==target.length())break;
            //如果两个值都不相等 直接返回;
            if(start.charAt(i)!=target.charAt(j))return false;
            else{
                if(start.charAt(i)=='L'&&i<j)return false;
                if(start.charAt(i)=='R'&&i>j)return false;
            }
            i++;
            j++;
        }
        return true;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值