长度为K的绳子最多能盖住几个点问题的解法

问题描述:

        给定一个有序数组arr,从左到右依次表示X轴上从左往右点的位置,给定一个正整数K,返回如果有一根长度为K的绳子,最多能盖住几个点,绳子的边缘点碰到X轴上的点,也算盖住。

思路一:

        使用暴力解法。从数组的开头开始遍历,查找数组中遍历下标的前部分下标,知道不符合条件时停止遍历。

    public static int test(int[] arr,int L){
        int max = 0;
        for (int i = 0;i<arr.length;i++){
            int pre = i-1;
            while (pre >=0 &&arr[i] - arr[pre] <= L){
                pre--;
            }
            max = Math.max(max,i-pre);
        }
        return max;
    }

思路二:

        定义一个nearestIndex(int[] arr,int R,int value)方法,它的主要作用是从数组的0下表到R下表之间查找出最接近value值的数字,并返回其下标。从数组的开头开始遍历,通过nearestIndex方法找出数组中符合要求的下标,计算出两者之间的差值,全部遍历结束后,就可以查找出最大的差值,即为该题的解。(即把暴力解法中遍历下标前部分的方法使用二分法进行,时间复杂度从O(n)降到了O(logn))

    public static int maxPoint1(int[] arr,int L){
        int res = 1;
        for (int i = 0;i <arr.length;i++){
            int nearest = nearestIndex(arr,i,arr[i]-L);
            res = Math.max(res,i-nearest+1);
        }
        return res;
    }

    public static int nearestIndex(int[] arr,int R,int value){
        int L = 0;
        int index = R;
        while (L <= R){
            int mid = L +((R-L)>>1);
            if (arr[mid] >= value){
                index = mid;
                R = mid - 1;
            }else {
                L = mid + 1;
            }
        }
        return index;
    }

思路三:

        滑动窗口,规定L,R判断此时R -> L是否大于给定的长度K ,一直增大R,直到找到此时以L开头时的最大长度记录此时的值。然后向右移动L继续上面的步骤。(只需要遍历数组一次即可完成)

    public static int maxPoint2(int[] arr,int L){
        int left = 0;
        int right = 0;
        int N = arr.length;
        int max = 0;
        while (left<N){
            while (right<N && arr[right] - arr[left] <=L){
                right++;
            }
            max = Math.max(max,right-(left++));
        }
        return max;
    }

使用对数器进行验证

    public static int[] generateArray(int len,int max){
        int[] ans = new int[(int)(Math.random()*len)+1];
        for (int i =0;i<ans.length;i++){
            ans[i] = (int) (Math.random()*max);
        }
        Arrays.sort(ans);
        return ans;
    }

    public static void main(String[] args) {
        int len = 100;
        int max = 1000;
        int testTime = 100000;
        System.out.println("测试开始!");
        for (int i =0;i<testTime;i++){
            int L = (int)(Math.random()*max);
            int[] arr = generateArray(len,max);
            int ans1 = maxPoint1(arr,L);
            int ans2 = maxPoint2(arr,L);
            int ans3 = test(arr,L);
            if (ans1 != ans2 || ans2 != ans3){
                System.out.println("Oops!");
                break;
            }
        }
        System.out.println("测试结束!");
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值