Leecode:数组中的最长山脉

数组中的最长山脉

难度:中等

题目链接:https://leetcode-cn.com/problems/longest-mountain-in-array/

题目:

	我们把数组 A 中符合下列属性的任意连续子数组 B 称为 “山脉”:
	B.length >= 3
	存在 0 < i < B.length - 1 使得 B[0] < B[1] < ... B[i-1] < B[i] > B[i+1] > ... > B[B.length - 1]
(注意:B 可以是 A 的任意子数组,包括整个数组 A。)
	给出一个整数数组 A,返回最长 “山脉” 的长度。
	如果不含有 “山脉” 则返回 0。

 
示例 1:
输入:[2,1,4,7,3,2,5]
输出:5
解释:最长的 “山脉” 是 [1,4,7,3,2],长度为 5。

示例 2:
输入:[2,2,2]
输出:0
解释:不含 “山脉”。
 
提示:
0 <= A.length <= 10000
0 <= A[i] <= 10000

法一:

/**思路**/
/*
	遍历每个元素,将每个元素作为峰顶,用left,right两个指针分别向左右扩散,最后确定长度,并与res比较即可
*/

/**代码**/
public int longestMountain(int[] A) {
        int res = 0;
        for(int index=1;index<A.length-1;index++){
            int left = index;
            int right = index;
            for(int i=index-1;i>=0;i--){
                if(A[i] < A[i+1]) left=i;
                else break;
            }
            for(int j=index+1;j<A.length;j++){
                if(A[j] < A[j-1]) right=j;
                else break;
            }
            if(left!=index && right!=index && right-left >= 2) {
                System.out.println(left+" "+right);
                res = Math.max(res,right-left+1);
            }
            if(right-1>index) index = right-1;
        }
        return res;
    }

法二:

/**思路**/
/*
	对于一座山脉,我们称首元素B[0]和尾元素B[len(B)-1]为山脚,满足题目要求B[i-1]<B[i]>B[i+1]的元素B[i]为山顶。为了找出数组A最长的山脉,我们可以考虑枚举山顶,再从山顶向左右两侧扩展找到山脚。
	由于从左侧山脚到山顶的序列是严格单调递增的,而从山顶道右侧山脚的序列是严格单调递减的,因此我们可以使用动态规划(也可以理解为递推)的方法,计算出从任意一个元素开始,从左右两侧最多可以扩展的元素数目。
	我们用left[i]表示A[i]向左侧最多可以扩展的元素数目。如果A[i-1]<A[i],那么A[i]可以向左扩展到A[i-1],再扩展left[i]个元素,因此有
	left[i] = left[i-1]+1
	如果A[i-1]>=A[i],那么A[i]无法向左扩展,因此有left[i]=0
	特别的,当i=0时,A[i]为首元素,无法向左扩展,因此同样有left[0]=0
	同理,我们用right[i]表示A[i]向右侧最多可以扩展的元素数目,那么有类似的状态转移方程(递推式)
	right[i]=right[i+1]+1,	 A[i]>A[i+1]
	right[i]=0,				A[i]<=A[i+1]或i=n-1
	其中n是数组A的长度
	在计算出所有的left[]以及right[]之后,我们就可以枚举山顶,需要注意的是,只有当left[i]和right[i]均大于0时,A[i]才能作为山顶,并且所有山脉的长度为 left+right[i]+1.
	在所有的山脉中,最长的即为答案
*/

/**代码**/
class Solution {
    public int longestMountain(int[] A) {
        int n = A.length;
        if (n == 0) {
            return 0;
        }
        int[] left = new int[n];
        for (int i = 1; i < n; ++i) {
            left[i] = A[i - 1] < A[i] ? left[i - 1] + 1 : 0;
        }
        int[] right = new int[n];
        for (int i = n - 2; i >= 0; --i) {
            right[i] = A[i + 1] < A[i] ? right[i + 1] + 1 : 0;
        }
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            if (left[i] > 0 && right[i] > 0) {
                ans = Math.max(ans, left[i] + right[i] + 1);
            }
        }
        return ans;
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-mountain-in-array/solution/shu-zu-zhong-de-zui-chang-shan-mai-by-leetcode-sol/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

法三:

/**思路**/
/*
	我们也可以枚举山脚。例如当我们从左向右遍历整个数组A时,可以使用双指针的方法,一个指针枚举左侧山脚,另一个指针不断向右移动到右侧山脚。
	具体的,我们使用指针left指向左侧山脚,它的初始值为0,每当我们固定left时:
	1.我们首先需要保证left+2<n,这是因为山脉的长度至少为3;其次我们需要保证A[left]<A[left+1],否则left对应的不可能是左侧山脚
	2.我们将右侧山脚的right的初始值置为left+1,随后不断向右移动right,直到不满足A[right]<A[right+1]为止,此时:
		a.如果right=n-1,说明我们已经移动到了数组末尾,已经无法形成山脉了
		b.否则,right指向的可能是山顶。我们需要额外判断是有满足A[right]>A[right+1],这是因为如果两者相等,那么right指向的就不是山顶了。
	3.如果right指向的确实不是山顶,那么我们使用类似的方法,不断的向右移动right,知道不满足A[right]>A[right+1]为止,此时,right指向右侧山脚,A[left]到A[right]就对应着一座山脉
	4.需要注意的是,右侧山脚有可能是下一个左侧山脚,因此我们需要将right的值赋予left,以便于下一次枚举。在其他所有不满足要求的情况下,right对应的位置都不可能是下一个左侧山脚,因此可以将right+1的值赋予left。
	在下列的代码中,当不满足要求时,我们立即将right的值加1.这样一来,我们就可以统一在下一次枚举左侧山脚之前,将right的值赋予left了。
*/

/**代码**/
class Solution {
    public int longestMountain(int[] A) {
        int n = A.length;
        int ans = 0;
        int left = 0;
        while (left + 2 < n) {
            int right = left + 1;
            if (A[left] < A[left + 1]) {
                while (right + 1 < n && A[right] < A[right + 1]) {
                    ++right;
                }
                if (right < n - 1 && A[right] > A[right + 1]) {
                    while (right + 1 < n && A[right] > A[right + 1]) {
                        ++right;
                    }
                    ans = Math.max(ans, right - left + 1);
                } else {
                    ++right;
                }
            }
            left = right;
        }
        return ans;
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-mountain-in-array/solution/shu-zu-zhong-de-zui-chang-shan-mai-by-leetcode-sol/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

小结:

方法对比:法三>法二>法一(法三与法二时间复杂度相同,空间复杂度前者更优)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值