22/11/14算法:给定一个有序数组arr,代表坐落在X轴上的点

121 阅读1分钟
题目:
给定一个有序数组arr,代表坐落在X轴上的点。
给定一个正数K,代表绳子的长度。
返回绳子最多压中几个点?(即使绳子边缘处盖住点也算盖住)
暴力解法:

遍历一遍数组,到达的每个位置都判断这个点能压中的点。

时间复杂度:O(N)。

public static int maxPoint1(int[] arr, int len) {
    int max = 0;
    for (int i = 0; i < arr.length; i++) {
        int pre = i - 1;
        while (pre >= 0 && arr[i] - arr[pre] <= len) {
            pre--;
        }
        max = Math.max(max, i - pre);
    }
    return max;
}
贪心+二分:

贪心体现在每次都拿绳子的尾部压住数组上存在的点。

当前位置的值减去绳子长度就是当前位置所能压到的最远的点。

使用二分查找寻找这个位置。

例如当前位置的值为893,绳子长度为100,当前位置能压到的最远位置为793。

使用二分查找寻找值为793的下标位置(如果不存在这个值,那么就找最小的大于793的值的位置)。

时间复杂度:O(N * log N)

public static int maxPoint2(int[] arr, int len) {
    int res = 0;
    for (int i = 0; i < arr.length; i++) {
        int nearest = nearestIndex(arr, i, arr[i] - len);
        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;
}
滑动窗口

判断每个位置延迟绳子的长度后,能压到的最多的点数。和方法二不同的是,窗口一直在向右边延伸,不需要每次都使用二分法去寻找。

image.png

image.png

image.png

时间复杂度:O(N)

public static int maxPoint3(int[] arr, int len) {
    int max = 0;
    int right = 0, N = arr.length;
    // 假定窗口leftright 判断每个点到后面最多能盖几个点,然后每个点都出个结果,比较最大的
    for (int left = 0; left < N; left++) {
        // 当前点根据绳子长度像后覆盖点,直到 没有数 可以延伸或者 大于绳子长度L
        while (right < N && arr[right] - arr[left] <= len) {
            right++;
        }
        // 比较旧覆盖点和新覆盖点哪个大就留哪个
        max = Math.max(max, right - left);
    }
    // 关键是right只能向后,就像个窗口一样,而算法一需要每次都二分去查找覆盖的点
    return max;
}
Go语言代码

// 暴力求解 时间复杂度O(N^2)
func maxPoint(arr []int, L int) int {
   res := 0
   N := len(arr)
   for i := 0; i < N; i++ {
      pre := i - 1
      for pre >= 0 && arr[i]-arr[pre] <= L {
         pre--
      }
      if i-pre > res {
         res = i - pre
      }
   }
   return res
}

// 贪心+二分 时间复杂度O(N * logN)
func maxPoint2(arr []int, L int) int {
   res := 0
   N := len(arr)
   for i := 0; i < N; i++ {
      nearest := nearestIndex(arr, i, arr[i]-L)
      if i-nearest+1 > res {
         res = i - nearest + 1
      }
   }
   return res
}
func nearestIndex(arr []int, R, value int) int {
   L := 0
   index := R
   for L <= R {
      mid := L + ((R - L) >> 1)
      if arr[mid] >= value {
         index = mid
         R = mid - 1
      } else {
         L = mid + 1
      }
   }
   return index
}

// 滑动窗口 时间复杂度O(N)
func maxPoint3(arr []int, L int) int {
   res := 0
   left, right, N := 0, 0, len(arr)
   for left < N {
      for right < N && arr[right]-arr[left] <= L {
         right++
      }
      if right-left > res {
         res = right - left
      }
      left++
   }
   return res
}