排除給定元素的等和陣列劃分
問題陳述
對於一個索引和一個數組 arr[]。檢查陣列 arr[] 是否可以劃分為兩個不相交的集合,排除 arr[index],使得兩個集合的和相等。
示例 1
輸入
arr[] = {4, 3, 1, 2}, Index = 1
輸出
No
解釋
我們必須排除 arr[1] = 3
所有可能的集合是:
Set 1: (4), Set 2: (2, 1), sum = 4≠3 Set 1: (4,1), Set 2: (2), sum = 5≠2 Set 1: (4,2), Set 2: (1), sum = 6≠1
沒有組合滿足條件。
示例 2
輸入
arr[] = {2, 5, 1, 4, 0}, index = 4
輸出
Yes Set 1 : (2, 4), sum = 6 Set 2 : (5, 1), sum = 6
解決方案
這個問題是劃分問題的修改版本,增加了這樣的限制:問題中給定的索引不能包含在陣列的任何一個劃分集合中。
首先,我們必須計算除給定索引處的數值之外,陣列中所有元素的和。
只有當總和為偶數時,才能將陣列劃分為兩個相等的部分。如果總和為奇數,則不會有任何可能的解。如果總和為偶數,我們繼續定義兩個變數 set1Sum 和 set2Sum 來儲存兩個集合的和。
我們將使用遞迴來確定 set1Sum 和 set2Sum 是否相等。起始索引為 0,陣列將被遞迴遍歷。對於陣列的每個索引都有兩個選項,要麼包含在 set1Sum 中,要麼包含在 set2Sum 中。
我們將首先呼叫遞迴函式將當前索引新增到集合 1 中,然後新增到集合 2 中。同時,確保檢查當前索引是否不是問題中給定的索引(必須排除),如果等於該索引,則在不更新總和的情況下呼叫下一個位置。一旦完整遍歷陣列,比較 set1Sum 和 set2Sum。如果總和相等,則返回;否則回溯並檢查其他選項。
方法
步驟 1 - 定義一個函式,我們將其命名為 calcPartitionSum。它將接收 6 個引數:給定的陣列 (arr)、arr 中給定的元素個數 (n)、第一個集合的和 (set1Sum)、第二個集合的和 (set2Sum)、要排除的元素的索引 (index) 和陣列中的當前位置 (i)。
步驟 2 - 如果 i 達到 arr 的末尾,則如果 set1Sum 等於 set2Sum,則函式返回 true,否則返回 false。
步驟 3 - 如果 i 達到索引,則函式將自身與下一個 i 一起呼叫,而不更新總和。
步驟 4 - 當 i 不等於 index 時,函式將首先為 set1 呼叫自身,然後為 set 2 呼叫自身。在一個函式呼叫中,它將透過將 arr[i] 新增到相應集合的和來更新和的值。
步驟 5 - 定義另一個函式,我們將其命名為 calcFullSum,用於計算整個陣列的和,但不包括給定索引處的數值。如果總和為奇數,則此函式將返回 false,並將呼叫 calcPartitionSum。
步驟 6 - calcPartitionSum 函式呼叫將具有初始化為 0 的 set1Sum 和 set2Sum 引數,index 等於給定的 index,i 等於 0。
步驟 7 - calcPartitionSum 返回的值將確定答案。
示例
下面是一個 C++ 程式,用於檢查陣列 arr[] 是否可以劃分為兩個不相交的集合,排除 arr[index],使得兩個集合的和相等。
#include <bits/stdc++.h> using namespace std; // Function to divide the array into 2 sets and // to check if the sum of sets becomes equal. bool calcPartitionSum(int arr[], int n, int set1Sum, int set2Sum, int index, int i){ // Compare the sums if i reaches the end of array // return true if both are equal else return false. if (i == n){ return (set1Sum == set2Sum); } // If i reaches index, then the function calls // itself with the next i without updating the sums if (i == index){ calcPartitionSum(arr, n, set1Sum, set2Sum, index, i + 1); } // Calling calcPartitionSum by including the value at // current index in the set 1 bool updateSet1 = calcPartitionSum(arr, n, set1Sum + arr[i],set2Sum, index, i + 1); // Calling calcPartitionSum by including the value at // current index in the set 2 bool updateSet2 = calcPartitionSum(arr, n, set1Sum, set2Sum + arr[i], index, i + 1); // returning true if any one of above calls give a true result return updateSet1 || updateSet2; } // Function to check if the array can be divided into 2 sets // and calls calcPartitionSum accordingly bool calcFullSum(int arr[], int n, int index){ // Initiate sum variable with 0 int sum = 0; // Iterate through the whole array and update the sum for (int i = 0; i < n; i++) { // Not updating the value of sum for given index // that needs to be excluded if (i == index){ continue; } sum += arr[i]; } // If sum is odd return false if (sum % 2 != 0) return false; // If sum is even call calcPartitionSum function. // The parameters set1Sum, set2Sum and i are initiated as 0 return calcPartitionSum(arr, n, 0, 0, index, 0); } // Driver Code int main() { int arr[] = {2, 5, 1, 4, 0}; int index = 4; int n = sizeof(arr) / sizeof(arr[0]); if (calcFullSum(arr, n, index)){ cout << "Yes"; } else{ cout << "No"; } return 0; }
輸出
對於給定的輸入 arr[] = {2, 5, 1, 4, 0} 和 index = 4,上述 C++ 程式將產生以下輸出:
Yes
時間複雜度
此演算法的時間複雜度為 O(2^n),其中 n 是陣列中元素的數量。由於 calcPartitionSum 對於陣列中的每個位置都被呼叫兩次,一次用於 set1Sum,一次用於 set2Sum,因此時間複雜度變為 O(2^n)。
空間複雜度
此演算法的空間複雜度為 O(n),其中 n 是陣列中元素的數量。由於 calcPartitionSum 是一個遞迴函式,它將具有大小為 n 的遞迴呼叫棧。
結論
因此,我們使用遞迴解決了排除給定元素的等和陣列劃分問題。我們首先檢查是否可以將陣列劃分為 2 個集合(排除給定索引)並得到結果。如果可以將陣列劃分為 2 個集合,我們將檢查劃分陣列後可以建立的 2 個集合的每種可能的組合,如果其中任何一種組合滿足給定條件,則返回 true。