畢業老,挖新坑,同學推薦了一個Leet Code OJ給我,之前搞ACM我最喜歡做DP題,所以對於新OJ,我想說的是,DP題就交給我吧。題目題解沒有順序,要查某題可以自行搜索,我還未解決的可以留言提醒我去搞定。順帶一提我這次做題準備全用JAVA來做。
P303. Range Sum Query - Immutable
題解:題目大一爲給定一個數組,給出一些問題,讓我們求出區間和,如果用O(n^2)的方法會非常直觀,但是效率不高,其實我們只要做一個預處理,每個問題就能夠在O(1)的時間內解出。因爲Range(i,j)=Sum[j]-Sum[i-1]{sum[i]爲數組前幾個數字的和}。所以預處理就是做數組前幾數和的過程。總體來說是一道簡單題。
參考代碼:
public class NumArray {
private int[] sum;
public NumArray(int[] nums) {
int l=nums.length;
if(l!=0){
sum=new int[l];
sum[0]=nums[0];
for(int i=1;i<l;i++)
sum[i]=sum[i-1]+nums[i];
}
}
public int sumRange(int i, int j) {
if(i==0) return sum[j];
return sum[j]-sum[i-1];
}
}
P368. Largest Divisible Subset
題解:題目大意爲一個非負數字集合,沒有重複的數字。求一個最長的子集,子集中任意兩數要滿足大的數要整除小的數。基本的DP題型,這道題時間複雜度要求不高,用n(O^2)的方法即可AC,首先先將數組排序,dp[i][1]代表數組中前i個數中最長的子集。由於當a整除b時,一定能保證整除b所有可以整除的其他數。所以轉移方程就是
dp[i][1]=max(dp[i][1],dp[j][1]+1){i%j==0};然後dp[i][0]則用來記錄它是由哪個j轉移過來的,方便輸出答案集合。具體詳情請看參考代碼。
參考代碼:
public class Solution {
public static List<Integer> largestDivisibleSubset(int[] nums) {
List<Integer> re=new ArrayList<Integer>();
if(nums.length==0) return re;
if(nums.length==1){
re.add(nums[0]);
return re;
}
Arrays.sort(nums);
int l=nums.length;
int[][] dp=new int[l+1][2];
dp[0][1]=1; dp[0][0]=-1;
for(int i=1;i<l;i++){
dp[i][1]=1; dp[i][0]=-1;
for(int j=0;j<i;j++)
if(nums[i]%nums[j]==0 && dp[j][1]+1>dp[i][1]){
dp[i][1]=dp[j][1]+1;
dp[i][0]=j;
}
}
int maxv=0,maxi=0;
for(int i=0;i<l;i++)
if(dp[i][1]>maxv){
maxv=dp[i][1];
maxi=i;
}
while(maxi!=-1){
re.add(nums[maxi]);
maxi=dp[maxi][0];
}
return re;
}
}