Minimum number of days required to make m bouquets of flowers (two points)

1482. Minimum number of days required to make m bouquets of flowers

You are given an integer array bloomDay, and two integers m and k.

Now we need to make m bouquets of flowers. When making a bouquet, you need to use k adjacent flowers in the garden.

There are n flowers in the garden, and the i-th flower will bloom on bloomDay[i], which can be used in a bouquet.

Please return the minimum number of days you need to wait to pick m bouquets of flowers from the garden. If m bouquets of flowers cannot be picked, -1 is returned.

示例一:

输入:bloomDay = [1,10,3,10,2], m = 3, k = 1
输出:3
解释:让我们一起观察这三天的花开过程,x 表示花开,而 _ 表示花还未开。
现在需要制作 3 束花,每束只需要 1 朵。
1 天后:[x, _, _, _, _]   // 只能制作 1 束花
2 天后:[x, _, _, _, x]   // 只能制作 2 束花
3 天后:[x, _, x, _, x]   // 可以制作 3 束花,答案为 3

Solution 1, bisection + sorting

The number of days is two-stage and exclusive. Assume that the answer is day: The range of [0, day) is not sufficient to make m bouquets of flowers, and the range of (day, inf) can be made, but the number of days is ok. definite. This is the binary left boundary search for day or the right boundary rough search to find day-1;

  1. Looking at the explanation in the question, we are looking for a number of days that can satisfy the production of m bouquets of flowers, and a limit is added to determine the minimum number of days. Naturally, I thought of finding the number of days suitable for making m bouquets of flowers by dividing the left boundary into two in an ordered sequence of days .
  2. The check function is to traverse the entire bloomDay and count how many bouquets of flowers can be produced when encountering blooming ones, and finally return the total number of flowers produced in the corresponding days.

Bipartite left border template:

// 找值为target的处于最左位置的索引
    public int leftBound(int[] nums,int l, int r, int target){
        while(l<=r){
            int mid = l + (r-l)/2;
            if(nums[mid]>=target){
                r = mid-1;  //开区间
            }else{
                l = mid+1;//开区间
            }
        }
        // 越界或target不存在
        if(l>=nums.length || nums[l] != target)
            return -1;
        return l;
    }
class Solution {
int[] blooms;
  public int minDays(int[] bloomDay, int m, int k) {
    if(m*k > bloomDay.length) return -1; //需要的花多大于实际的花朵
    Set<Integer>  sortedDay = new TreeSet<Integer>((a,b) -> {return a-b;});
    for(int b : bloomDay){
        sortedDay.add(b);
    }
    Integer[] days =  (Integer[] ) sortedDay.toArray(new Integer[0]);
    //在days中二分查找合适的day
    if(m*k == bloomDay.length) return days[days.length-1].intValue(); //需要全部的花,在最大的日子
    blooms = bloomDay;
    return  leftBound(days, m, k);
  }
  /**
   *   左边界二分查找
   * @param days  排序过后的花开的日子
   * @param m  制作m束花
   * @param k  多少多花一束花
   * @return 最小的日子制作m束花
   */
    public int leftBound(Integer[] days, int m, int k)
    {
      int left = 0, right = days.length-1;
      while(left <= right){
        int mid = left + (right - left)/2;
        int num = check(days[mid], m, k); // mid这个日子里可以制作多少束花.
        //System.out.println(mid + " : " + num);
        if( num >= m){
          right = mid-1;
        }else{
          left = mid+1;
        }
      }
      if(left >= days.length) return -1;
      return days[left];
    }
    // 检查day天后可以制作花的数量
    public int check(int day, int m, int k){
        int i = 0, res = 0;
        while(i < blooms.length){
          if(blooms[i]<=day){
            //这朵花可以开 
            int tmp = 0;
            while(i < blooms.length && blooms[i] <= day){
                tmp++;
                if(tmp == k){
                  //连续开花达到制作一束花的水平
                  res++;
                  tmp = 0;
                }
                i++;
            }
        }
        ++i;
    }
    return res;
  }
}

Time complexity: Adding n numbers to Treeset is O(logn), bisecting is O(logn), checking the function is O(n), and the total time complexity is O(nlogn)??? However, Likou ran out of solution. Second slow. Don't know why.

Space complexity: O(n)

Solution 2: Divide the range of 1-1e9 into two parts

class Solution {
int[] blooms;
  public int minDays(int[] bloomDay, int m, int k) {
     
    //在days中二分查找合适的day 
      if( m*k > bloomDay.length) return -1;
    blooms = bloomDay;
    return  leftBound( m, k);
  }
  /**
   *   左边界二分查找
   * @param m  制作m束花
   * @param k  多少多花一束花
   * @return 最小的日子制作m束花
   */
    public int leftBound( int m, int k)
    {
      int left = 0, right = (int)1e9;
      while(left <= right){
        int mid = left + (right - left)/2;
        int num = check(mid, m, k); // mid这个日子里可以制作多少束花.
        //System.out.println(mid + " : " + num);
        if( num >= m){
          right = mid-1;
        }else{
          left = mid+1;
        }
      } 
      return left;
    }
    public int check(int day, int m, int k){
        int i = 0, res = 0;
        while(i < blooms.length){
          if(blooms[i]<=day){
            //这朵花可以开 
            int tmp = 0;
            while(i < blooms.length && blooms[i] <= day){
                tmp++;
                if(tmp == k){
                  //连续开花达到制作一束花的水平
                  res++;
                  tmp = 0;
                }
                i++;
            }
        }
        ++i;
    }
    return res;
  }
}
  • Time complexity: checkThe complexity of the function is O(n). The overall complexity is O(nlog(1e9))
  • Space complexity: O(n)
optimization:

Optimize the boundary of the two points, left=min{bloomday}, right = max{bloomday}

Guess you like

Origin blog.csdn.net/qq_40893490/article/details/116598758