积小于 k 的子集数
给定一个由 n 个元素组成的数组,您必须找到其元素乘积小于或等于给定整数 k 的子集的数量。
例子:
Input : arr[] = {2, 4, 5, 3}, k = 12
Output : 8
Explanation : All possible subsets whose
products are less than 12 are:
(2), (4), (5), (3), (2, 4), (2, 5), (2, 3), (4, 3)
Input : arr[] = {12, 32, 21 }, k = 1
Output : 0
Explanation : there is not any subset such
that product of elements is less than 1
方法:如果我们通过基本方法来解决这个问题,那么我们必须生成所有可能的 2 n个子集,然后我们必须计算子集元素的乘积并将产品值与给定的值进行比较。但是这种方法的缺点是它的时间复杂度太高,即 O(n*2 n )。现在,我们可以看到它将是指数时间复杂度,在竞争性编码的情况下应该避免这种情况。
进阶方法:我们将使用中间相遇的概念。通过使用这个概念,我们可以降低 O(n*2 n/2 ) 方法的复杂性。
如何在中间方法中使用 MEET:首先,我们简单地将给定数组分成两个相等的部分,然后我们为数组的两个部分生成所有可能的子集,并将每个子集的元素乘积的值分别存储到两个向量中(比如子集 1 和子集 2)。现在这将花费 O(2 n/2 ) 时间复杂度。现在,如果我们对这两个向量(子集 1 和子集 2)进行排序,每个向量都有 (2 n/2 ) 个元素,那么这将花费 O(2 n/2 *log2 n/2 ) ≈ O(n*(2 n/2 )) 时间复杂度。在下一步中,我们遍历具有 2 n/2 个元素的向量子集 1,并在第二个向量中找到 k/子集 1[i] 的上限,这将告诉我们乘积小于或等于 k 的总元素的计数。因此,对于subset1 中的每个元素,我们将尝试以subset2 中的upper_bound 形式执行二进制搜索,再次导致时间复杂度为O(n*(2 n/2 ))。因此,如果我们尝试计算这种方法的整体复杂度,我们将得到 O(n*(2 n/2 ) + n*(2 n/2 ) + n*(2 n/2 )) ≈ O(n*(2 n/2 )) 作为我们的时间复杂度,这比我们的蛮力方法有效得多。
算法 :
- 将数组分成相等的两部分。
- 生成所有子集并为每个子集计算元素的乘积并将其推送到向量。试试这个数组的两个部分。
- 对包含每个可能子集的元素乘积的新向量进行排序。
- 遍历任意一个向量,求元素 k/vector[i] 的上界,求出元素乘积小于 k 的 vector[i] 有多少个子集。
提高复杂性的一些关键点:
- 如果大于 k,则忽略数组中的元素。
- 如果大于 k,则忽略要推入向量(子集 1 或子集 2)的元素的乘积。
下面是上述方法的实现:
C++
// CPP to find the count subset having product // less than k #include
using namespace std; int findSubset(long long int arr[], int n, long long int k) { // declare four vector for dividing array into // two halves and storing product value of // possible subsets for them vector vect1, vect2, subset1, subset2; // ignore element greater than k and divide // array into 2 halves for (int i = 0; i < n; i++) { // ignore element if greater than k if (arr[i] > k) continue; if (i <= n / 2) vect1.push_back(arr[i]); else vect2.push_back(arr[i]); } // generate all subsets for 1st half (vect1) for (int i = 0; i < (1 << vect1.size()); i++) { long long value = 1; for (int j = 0; j < vect1.size(); j++) { if (i & (1 << j)) value *= vect1[j]; } // push only in case subset product is less // than equal to k if (value <= k) subset1.push_back(value); } // generate all subsets for 2nd half (vect2) for (int i = 0; i < (1 << vect2.size()); i++) { long long value = 1; for (int j = 0; j < vect2.size(); j++) { if (i & (1 << j)) value *= vect2[j]; } // push only in case subset product is // less than equal to k if (value <= k) subset2.push_back(value); } // sort subset2 sort(subset2.begin(), subset2.end()); long long count = 0; for (int i = 0; i < subset1.size(); i++) count += upper_bound(subset2.begin(), subset2.end(), (k / subset1[i])) - subset2.begin(); // for null subset decrement the value of count count--; // return count return count; } // driver program int main() { long long int arr[] = { 4, 2, 3, 6, 5 }; int n = sizeof(arr) / sizeof(arr[0]); long long int k = 25; cout << findSubset(arr, n, k); return 0; } Python3
# Python3 to find the count subset # having product less than k import bisect def findSubset(arr, n, k): # declare four vector for dividing # array into two halves and storing # product value of possible subsets # for them vect1, vect2, subset1, subset2 = [], [], [], [] # ignore element greater than k and # divide array into 2 halves for i in range(0, n): # ignore element if greater than k if arr[i] > k: continue if i <= n // 2: vect1.append(arr[i]) else: vect2.append(arr[i]) # generate all subsets for 1st half (vect1) for i in range(0, (1 << len(vect1))): value = 1 for j in range(0, len(vect1)): if i & (1 << j): value *= vect1[j] # push only in case subset product # is less than equal to k if value <= k: subset1.append(value) # generate all subsets for 2nd half (vect2) for i in range(0, (1 << len(vect2))): value = 1 for j in range(0, len(vect2)): if i & (1 << j): value *= vect2[j] # push only in case subset product # is less than equal to k if value <= k: subset2.append(value) # sort subset2 subset2.sort() count = 0 for i in range(0, len(subset1)): count += bisect.bisect(subset2, (k // subset1[i])) # for null subset decrement the # value of count count -= 1 # return count return count # Driver Code if __name__ == "__main__": arr = [4, 2, 3, 6, 5] n = len(arr) k = 25 print(findSubset(arr, n, k)) # This code is contributed by Rituraj Jain
输出:15