698.劃分為k個相等的子集
阿新 • • 發佈:2021-10-27
回溯
預處理:
1.計算累加和s,如果s%k!=0,返回false。
2.按從小到大給陣列排序。
準備k個桶,每個桶的容量為s/k。遍歷陣列,嘗試將當前元素新增到每個桶中,如果所有所有桶都放不下則返回false。如果能遍歷完陣列則返回true。
陣列排序是一種優化操作,如果當前元素都沒有桶可以放得下,那後面的元素就不用再遍歷可以直接返回false了,因為後面的元素更大。
public boolean canPartitionKSubsets(int[] nums, int k) { //因為題目限制條件不用擔心溢位 int sum = 0; for(int i = 0; i < nums.length; i++){ sum += nums[i]; } if(sum % k != 0){ return false; } //求出子集的和 sum = sum / k; //排序 小的放最前面大的放最後面 Arrays.sort(nums); //如果子集的和小於陣列最大的直接返回false if(nums[nums.length - 1] > sum){ return false; } //建立一個長度為k的桶 int[] arr = new int[k]; //桶的每一個值都是子集的和 Arrays.fill(arr, sum); //從陣列最後一個數開始進行遞迴 return help(nums, nums.length - 1, arr, k); } boolean help(int[] nums, int cur, int[] arr, int k){ //已經遍歷到了-1說明前面的所有數都正好可以放入桶裡,那所有桶的值此時都為0,說明找到了結果,返回true if(cur < 0){ return true; } //遍歷k個桶 for(int i = 0; i < k; i++){ //如果正好能放下當前的數或者放下當前的數後,還有機會繼續放前面的數(剪枝) if(arr[i] == nums[cur] || (cur > 0 && arr[i] - nums[cur] >= nums[0])){ //放當前的數到桶i裡 arr[i] -= nums[cur]; //開始放下一個數 if(help(nums, cur - 1, arr, k)){ return true; } //這個數不該放在桶i中 //從桶中拿回當前的數 arr[i] += nums[cur]; } } return false; }