毕业老,挖新坑,同学推荐了一个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;
}
}