【數學】B075_LC_使結果不超過閾值的最小除數(二分)

一、Problem

Given an array of integers nums and an integer threshold, we will choose a positive integer divisor and divide all the array by it and sum the result of the division. Find the smallest divisor such that the result mentioned above is less than or equal to threshold.

Each result of division is rounded to the nearest integer greater than or equal to that element. (For example: 7/3 = 3 and 10/2 = 5).

It is guaranteed that there will be an answer.

Input: nums = [1,2,5,9], threshold = 6
Output: 5
Explanation: We can get a sum to 17 (1+2+5+9) if the divisor is 1. 
If the divisor is 4 we can get a sum to 7 (1+1+2+3) and if the divisor is 5 the sum will be 5 (1+1+1+2). 

二、Solution

方法一:暴力

因爲沒有意識到除數的選擇範圍,所以一開始想的是暴力,主要思想爲:

  • num 從 1 開始,將商累加到 cur 中,直到 set 中存在重複 cur 則該 num 爲答案。

很遺憾這是錯的.

class Solution {
    public int smallestDivisor(int[] A, int th) {
    	int num = 0;
    	long cur = 0;
        Set<Long> st = new HashSet<>();
    	while (true) {
            num++;
    		for (int a : A) {
                double r = (long) Math.ceil(a/num);
    		    if (r < 1) cur++;
                else       cur += r;
                if (cur > th)
                    continue;
    		}
            if (st.contains(cur))
                break;
            st.add(cur);
            cur = 0;
    	}
    	return num-1;
    }
}

方法二:二分

觀察題意,可以發現,除數 num 越大,得到的商累加 sum 和就越小,所以 sum 結果的具有單調性,可以根據 sum 的大小二分查找枚舉 num

class Solution {
	int f(int[] A, int div) {
		int sum = 0;
		for (int a : A) {
			sum += a / div;
			if (a % div != 0)
				sum++;
		}
		return sum;
	}
    public int smallestDivisor(int[] A, int th) {
    	int l = 1, r = (int) 1e6;
    	while (l < r) {
    		int mid = l + r >>> 1, sum = f(A, mid);
    		if (sum > th) l = mid + 1;
    		else          r = mid;
    	}
    	return r;
    }
}

複雜度分析

  • 時間複雜度:O(N×logMax)O(N × logMax)
  • 空間複雜度:O(1)O(1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章