LEETCODE 数组hard难度

1

128. 最长连续序列

给定一个未排序的整数数组,找出最长连续序列的长度。

要求算法的时间复杂度为 O(n)。

示例:

输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。

2

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

思路1:统计每层的雨水数量。
整个思路就是,求第 i 层的水,遍历每个位置,如果当前的高度小于 i,并且两边有高度大于等于 i 的,说明这个地方一定有水,水就可以加 11。

如果求高度为 i 的水,首先用一个变量 temp 保存当前累积的水,初始化为 00。从左到右遍历墙的高度,遇到高度大于等于 i 的时候,开始更新 temp。更新原则是遇到高度小于 i 的就把 temp 加 11,遇到高度大于等于 i 的,就把 temp 加到最终的答案 ans 里,并且 temp 置零,然后继续循环。
也就是红色区域中的水,数组是 height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ] 。

原则是高度小于 1,temp ++,高度大于等于 1,ans = ans + temp,temp = 0。

temp 初始化为 0,ans = 0

height[0] 等于 0 < 1,不更新。

height[1] 等于 1 >= 1,开始更新 temp。

height[2] 等于 0 < 1,temp = temp + 1 = 1。

height[3] 等于 2 >= 1,ans = ans + temp = 1,temp = 0。

height[4] 等于 1 >= 1,ans = ans + temp = 1,temp = 0。

height[5] 等于 0 < 1,temp = temp + 1 = 1。

height[6] 等于 1 >= 1,ans = ans + temp = 2,temp = 0。

剩下的 height[7] 到最后,高度都大于等于 1,更新 ans = ans + temp = 2,temp = 0。而其实 temp 一直都是 0,所以 ans 没有变化。

再求第 2 行的水。

也就是红色区域中的水,数组是 height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ]。

原则是高度小于 2,temp ++,高度大于等于 2,ans = ans + temp,temp = 0。

temp 初始化为 0,ans 此时等于 2。

height[0] 等于 0 < 2,不更新。

height[1] 等于 1 < 2,不更新。

height[2] 等于 0 < 2,不更新。

height[3] 等于 2 >= 2,开始更新

height[4] 等于 1 < 2,temp = temp + 1 = 1。

height[5] 等于 0 < 2,temp = temp + 1 = 2。

height[6] 等于 1 < 2,temp = temp + 1 = 3。

height[7] 等于 3 >= 2,ans = ans + temp = 5,temp = 0。

height[8] 等于 2 >= 2,ans = ans + temp = 3,temp = 0。

height[9] 等于 1 < 2,temp = temp + 1 = 1。

height[10] 等于 2 >= 2,ans = ans + temp = 6,temp = 0。

height[11] 等于 1 < 2,temp = temp + 1 = 1。

然后结束循环,此时的 ans 就是6。

作者:windliang
链接:https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8/

class Solution {
    public int trap(int[] height) {
        int hei = getHeight(height);
        int ans = 0;
        for(int i=1;i<=hei;i++){
            int tmp=0;
            boolean flag=false;
            for(int j=0;j<height.length;j++){
                if(flag&&height[j]<i)
                tmp++;
                else if(height[j]>=i){
                    flag=true;
                    ans+=tmp;
                    tmp=0;
                }
            }
        }
        return ans;
    }

    public int getHeight(int[] height){
        int max=0;
        for(int i=0;i<height.length;i++){
            if(max<height[i])
            max=height[i];
        }
        return max;
    }
}

思路2:按列求雨水数量
求每一列的水,我们只需要关注当前列,以及左边最高的墙,右边最高的墙就够了。

装水的多少,当然根据木桶效应,我们只需要看左边最高的墙和右边最高的墙中较矮的一个就够了。

所以,根据较矮的那个墙和当前列的墙的高度可以分为三种情况。
1.较矮的墙的高度大于当前列的墙的高度
很明显,较矮的一边,也就是左边的墙的高度,减去当前列的高度就可以了,也就是 2 - 1 = 1,可
以存一个单位的水。
2.较矮的墙的高度小于当前列的墙的高度

class Solution {
    public int trap(int[] height) {
        int ans = 0;
        for(int i=1;i<height.length-1;i++){
            int left=0;
            for(int j=i-1;j>=0;j--){
                if(left<height[j])
                left=height[j];
            }
            int right=0;
            for(int j=i+1;j<height.length;j++){
                if(right<height[j])
                right=height[j];
            }
            int max= Math.min(left,right);
            if(max>height[i])
            ans+=(max-height[i]);
        }
        return ans;
    }
}

思路3:在第二种方法上的改进,由于第二种方法每次需要求左右两边的最大值,我们可以预先求得放在一个数组里,由于左右两边的最小高度和当前柱子的高度相等时也是没有雨水数的,所以这里我们选的左右两边最大值包括当前的柱子高度。

class Solution {
    public int trap(int[] height) {
        int[] left=new int[height.length];
        int[] right = new int[height.length];
        if(height.length<2)
        return 0;
        int ll = height[0];
        for(int i=1;i<height.length;i++){
            ll=Math.max(ll,height[i]);
            left[i]=ll;
        }
        int ans = 0;
        int rr=height[height.length-1];
                for(int i=height.length-2;i>=0;i--){
            rr=Math.max(rr,height[i]);
            right[i]=rr;
        }
        for(int i=1;i<height.length;i++){
            int min=Math.min(left[i],right[i]);
            if(min>height[i])
            ans+=(min-height[i]);
        }
        return ans;
    }
}

思路4:使用单调递减栈来实现

class Solution {
    public int trap(int[] height) {
        int ans = 0;
        int len = height.length;
        if(len<3)
        return 0;
        Stack<Integer> st = new Stack<>();
        int cur = 0;
        while(cur<len){

            while(!st.isEmpty()&&height[cur]>height[st.peek()]){
                int tmp = height[st.pop()];
                if(st.isEmpty())
                break;
                int min = Math.min(height[cur],height[st.peek()]);
                int wi = cur-st.peek()-1;
                ans+=(min-tmp)*wi;
            }
            st.push(cur);
            cur++;
        }
        return ans;
    }
}

3

4. 寻找两个有序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0
示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int[] arr= new int[len1+len2];
        int index=0;
        int i=0;
        int j=0;
        while(i<len1&&j<len2){
            if(nums1[i]<nums2[j]){
                arr[index++]=nums1[i++];
            }else{
                arr[index++]=nums2[j++];
            }
        }
        while(i<len1)
        arr[index++]=nums1[i++];
        while(j<len2)
        arr[index++]=nums2[j++];
        if(arr.length%2==0){
            int n = arr[arr.length/2];
            int m = arr[arr.length/2-1];
            return (n+m)/2.0;
        }else{
            return (double) arr[arr.length/2];
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值