---
# System prepended metadata

title: 'LeetCode #698 [Partition to K Equal Sum Subsets](https://leetcode.com/problems/partition-to-k-equal-sum-subsets/)'
tags: [DFS, LeetCode, Medium]

---

###### tags: `LeetCode` `Medium` `DFS`
# LeetCode #698 [Partition to K Equal Sum Subsets](https://leetcode.com/problems/partition-to-k-equal-sum-subsets/)
### (Medium)


給定一個整數數組 nums 和一個正整數 k，找出是否有可能把這個數組分成 k 個非空子集，其總和都相等。

---
首先可以先將nums排序, 並計算總和以及每個組合的元素和, 若元素和不為整數則回傳空集合。

接下來使用DFS找組合, 每找到一組則從頭開始尋找新的組合, 並將組合數+1, 若組合數等同於k, 則回傳true, 若找完全部組合皆沒達成組合數等於k, 則回傳false。

幾個要點:
1. 當找到新的組合時(sum==total/k), 要回傳的是從頭開始, 但組合數+1的DFS
2. 由於找到新的組合後須從頭開始找, 因此不能用`if(i!=pos&&nums[i]==nums[i-1])continue;`來跳過重複值, 這會跳過所有不是第一個的重複值, 而非其原本的用意: 在DFS探索失敗"返回"後, 跳過探索必定失敗的重複值。

    差別在於這題是探索成功後尋找其他組合, 而非探索失敗後"返回"再尋找其他組合。因此本題需要使用last來辨識用過的值。

---
```
class Solution {
public:
    int total;
    int visited[16];
    int k;
    bool canPartitionKSubsets(vector<int>& nums, int k) {
        this->k = k;
        total = accumulate(nums.begin(), nums.end(), 0);
        sort(nums.begin(), nums.end());
        if(total%k!=0)return false;
        return dfs(0,0,0, nums);//pos, group, sum
    }
    bool dfs(int pos, int group, int sum, vector<int>& nums){
        if(sum>total/k)return false;
        if(sum==total/k)return dfs(0, group+1, 0, nums);
        if(group==k)return true;
        int last=-1;
        for(int i=pos;i<nums.size();i++){
            
            if(visited[i])continue;
            //if(i!=pos&&nums[i]==nums[i-1])continue;//不能這樣寫
            if(nums[i]==last)continue;
            visited[i]=1;
            last=nums[i];
            if(dfs(i+1, group, sum+nums[i], nums))return true;
            visited[i]=0;
        }
        return false;
    }
};
```