class Solution { public int[][] remain; public int sum(int[] arr) { int total = 0; for (int data : arr) { total += data; } return total; } /* Since we are finding if there is a way to partition the set into 2 subsets that have equal sum (let's call it x1 and x2) then we can check if there is a subset that has the sum equal to half Because x1 = x2 and x1 + x2 = total => x1 = x2 = total / 2 */ /* To find if there is a subset that can be sum up to a certain number, the idea is have a 2d array[][] where arr[i][j] represents if we haven't gone through that path (0), can't be summed up to sum (-1), can be summed up to sum (1). We can then search for by going: arr[half][i] -> arr[half - i][i'] -> ... until arr[n][m] = 0 where i, i', m belongs to nums[] */ public boolean canPartition(int[] nums) { int total = sum(nums); //Meaningless if the total is odd if (total % 2 != 0) { return false; } int half = total / 2; //Find half of the total sum remain = new int[half + 1][nums.length]; //Fill the base cases for (int indx = 0; indx < nums.length; indx++) { remain[0][indx] = 1; } //Fill out the rest fillTable(nums, half, nums.length - 1); boolean found = false; for(int data : remain[half]) { if (data == 1) { found = true; break; } } //Check if there is a subset that has the sum equals to that half return found; } public boolean fillTable(int[] nums, int curSum, int index) { if (curSum < 0 || index < 0) { //Invalid return false; } //No need to check again if (remain[curSum][index] != 0) { return remain[curSum][index] == 1 ? true : false; } //Default remain[curSum][index] = -1; boolean found = false; for (int indx = index; indx > -1 && found != true; indx--) { found = fillTable(nums, curSum - nums[indx], indx - 1); } if (found == true) { remain[curSum][index] = 1; } return found; } }