1. 程式人生 > >Leetcode 416. Partition Equal Subset Sum 對半分 解題報告【修正版】

Leetcode 416. Partition Equal Subset Sum 對半分 解題報告【修正版】

1 解題思路

leetcode才出來的時候,測試用例比較簡單,所以我之前用的是暴力法,而且AC了,後面有人和我說沒法通過了,所以後面我重新做了下,[並且參照了他的思路(](http://blog.csdn.net/liuyue910828/article/details/52792357) 我多了註釋,做個廣告):

現在用了揹包去解決的,首先:
1、依然陣列的和必須要是偶數,否則無法劃分,共計n個數,這裡價值value/weight都等於nums
2、將問題轉化為揹包問題,即取前I個數(物品),和體積j下,dp[i][j]的最大值
dp[i][j]=max{ dp[i-1][j], dp[i-1][j-nums[i]]+nums[i] }。
3、這樣dp[n][sum/2] 如果等於sum/2 就證明用了這n個數下,正好能加出一個sum/2,所以就自然而然的通過了

PS:最後,我突然覺得其實都沒必要用二位陣列了。。。

原來的暴力解法:
其實所謂的對半分,就是一個數組劃分成兩部分,兩部分的和一樣
所以思路:
1、首先陣列的和必須要是偶數,否則無法劃分
2、直接暴力的DFS+回溯,即查詢是否有1/2與陣列和的存在
3、我是用了排序後,DFS時可以剪枝的方式
4、關於3中排序的開銷是否值得,大家自己測試

總之,是一個暴力而簡單的解法

#2 原題
Given a non-empty array containing only positive integers, find if the array can be partitioned into two
subsets such that the sum of elements in both subsets is equal. Note: Both the array size and each of the array element will not exceed 100. Example 1: Input: [1, 5, 11, 5] Output: true Explanation: The array can be partitioned as [1, 5, 5] and [11]. Example 2: Input: [1, 2, 3, 5] Output: false
Explanation: The array cannot be partitioned into equal sum subsets

3 DP版 public class Solution {

public boolean canPartition(int[] nums) {  
     int sum=0;  
     for (int num:nums) sum+= num;
     if(sum % 2 == 1) return false;
     else{  
        sum /=2;
        int n=nums.length;  
        // dp[i][j] 表示 如果我們取前i個數字,且揹包容量為j的情況下,最多能放入多少東西
        int dp[][]=new int[n][sum + 1];  
        // dp[0][0] 為初始狀態,表示,沒有任何沒有東西沒有體積,其餘部分初始化
        for(int i=nums[0];i<=sum;i++){
             dp[0][i] = nums[0];
        }
        //遍歷n個數字,即視為n個產品
        for(int i=1;i<n;i++){  
            //加入了這種物品後更新狀態
            for(int j=nums[i];j<=sum;j++){  
                dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-nums[i]]+nums[i]);  
            }  
        }  
        //放滿了才能表示正好1/2
        if(dp[n-1][sum]==sum) 
            return true;  
        else
            return false;  
     }  

 }  

}

4 老舊的暴力法 僅供參考 不可AC

我做的比較早,有人評論說超時了,所以我貼個AC的時間出來。AC區很多人的程式碼也都作廢了。。我也無語

我跑了三次,都是10ms
這裡寫圖片描述

現在的評測已經和我當時的評測不一樣了,所以以下程式碼作廢了!!!

而且現在我找到的好多程式碼,也都是或多或少不是超時就是錯誤,有人提供一個DP的正確解法麼?最近沒時間再做!!

public class Solution {
    /**
     * 首先和為奇數的過濾
     * 其次使用DFS
     * 排序後可以剪枝很多情況
     * */
    public boolean canPartition(int[] nums) {
        Arrays.sort(nums);
        int sum=0;
        for (int num:nums) sum+= num;
        if(sum % 2 == 1) return false;
        sum/=2;
        return dfs(0,sum,nums);
    }
    // 一一嘗試
    public boolean dfs(int index,int sum,int[] nums){
        sum -= nums[index] ;
        if(sum == 0) return true;
        for(int i=index+1;i<nums.length;i++){
            if(sum<nums[i]) break;
            if(dfs(i,sum,nums)) return true;
        }
        return false;
    }
}