力扣526.优美的排列
class Solution { int count=0; boolean vis[]; public int countArrangement(int n) { vis=new boolean[n+1]; //我的问题1:不知道参数设置什么,有些遗忘,参数要去设置下标排到什么位置 dfs(1,n); return count; } //实现 public void dfs(int pos,int n){ if(pos==n+1){ count++; return ; } for(int i=1;i<=n;i++){ if(vis[i]==false&&(i%pos==0||pos%i==0)){ vis[i]=true; dfs(pos+1,n); vis[i]=false; //恢复现场 } } } }
力扣1027.最长等差数列
dp:以i位置的元素为结尾的所有子序列中,最长的等差序列长度
dp[i-1],dp[i-2],....dp[0]——dp[i],因为只存了一个长度,但是我们只是知道长度,我们连最基础的等差序列长什么样子都不清楚。.
状态表示一定要包含两个信息:1.长度2.等差序列的样子
dp[i][j]:i位置以及j位置为结尾的所有子序列中,最长的等差序列的长度。(i<j)
初始化:
dp表里面,所有的值,都初始化为2
(提问:假如dp[0][0]那么不就是一个元素,那么不就是1吗,
答:i<j. 我们只会用到对角线的上半部分,连对角线都用不到,所以直接全初始化
4.填表顺序
1.先固定最后一个数,2.枚举倒数第二个数
或者
1.先固定倒数第二个数,2.枚举倒数第一个数。
class Solution { public int longestArithSeqLength(int[] nums) { //建标,为什么使用Map,因为假如要找那个距离i最近的下标,还需要一层遍历,这样很大概率超时,所以使用MAP来去存储距离最近的i那个下标 //一遍dp,一边保存距离他最近的下标 Map<Integer,Integer>hash=new HashMap<Integer,Integer>(); //a的位置可能有nums[0] hash.put(nums[0],0); int n=nums.length; int [][]dp=new int[n][n]; //我们只会用到dp的上半部分,因为i<j的 for(int i=0;i<n;i++){ //初始化 Arrays.fill(dp[i],2); } int ret=2; //i从0开始,j从1开始,那么dp表初始化的值本来就是2,没有意义,他不可能是3 // ,所以需要i从1开始,j从2开始 //固定了i位置,接下来枚举即可 for(int i=1;i<n;i++){ //j在i的后面,他本质还是一维数组 for(int j=i+1;j<n;j++){ //本质还是看一维数组 i :a j:b 以ij结尾 // a-x=b-a,所以x=2a-b; int a=2*nums[i]-nums[j]; //看a是否存在 if(hash.containsKey(a)){ //get(a),获取a元素所在的下标 dp[i][j]=dp[hash.get(a)][i]+1; ret=Math.max(ret,dp[i][j]); } } //说明i走完了,把i位置扔进哈希表里面 hash.put(nums[i],i); } return ret; } }
力扣300.最长递增子序列
子序列:[a,b,c,d,e]按从左往右的顺序,任意挑选几个,[a,b,d]相对的顺序不变。
子数组:子数组,必须跳出来后是连续的
子序列>子数组
class Solution { public int lengthOfLIS(int[] nums) { //dp[i]以i位置为结尾的子序列,最长子序列的长度 //状态表示分为两大类 //1.自己玩,长度为1 //2.跟在前面元素后面,构成递增子序列,nums[j]<nums[i] int max1=1; int n=nums.length; int []dp=new int[n]; Arrays.fill(dp,1); //从左往右 for(int i=1;i<n;i++){ for(int j=0;j<i;j++){ if(nums[j]<nums[i]){ // j在 0 - i-1区间内动,为什么取一个最大值呢,因为j这个位置可以在i的前面也可以在后面,换句话说 //并不是一定在i-1这个位置,那么也就是说我们需要的是保存最大的dp[j],而不是最近的,推荐是去调试一下。 dp[i]=Math.max(dp[j]+1,dp[i]); max1=Math.max(max1,dp[i]); } } } return max1; } }
力扣376.摆动序列
dp[i]:以i位置元素为结尾的所有子序列中,最长的摆动序列的长度,细分
f[i]:以i位置元素为结尾的所有子序列中,最后一个位置呈现"上升"趋势的最长摆动序列的长度
g[i]:以i位置元素结尾的所有子序列中,最后一个位置呈现"下降"趋势的最长摆动序列的长度
2.状态转移方程
f[i]:g[i-1]+1,f[i];
g[i]:f[i-1]+1,g[i];
初始化
全部是1呗
i位置结尾的最大值 他那个遍历max意味着
他从前面一堆中 找出最长的和这个看能不能连上,如果能连上且最长那么就+1 ,假如说他这个值不是最长 那么她就保留原有的i位置和j位置连起来的那个最长
max的意思是说 前面那个有可能连上 但是不一定最长
(虽然f[i]:g[i-1]+1,f[i]; 这里你写一个f[i-1]也是对的,但是这样他就不是正确的含义了,假如你当前呈现上升趋势,然后f[i-1]是以i-1位置结尾的最大上升趋势,这样换句话说,就会i越大,f越大,g也一样,那么最后迎来的就是f[n-1]和g[n-1]求max值,来计算了 )
class Solution { public int wiggleMaxLength(int[] nums) { int n=nums.length; //f[i]:以i位置元素为结尾的所有子序列中,最后一个位置呈现"上升"趋势的最长摆动序列的长度 //g[i]:以i位置元素结尾的所有子序列中,最后一个位置呈现"下降"趋势的最长摆动序列的长度 int []f=new int[n]; int []g=new int[n]; Arrays.fill(f,1); Arrays.fill(g,1); //dp[i]:表示以i位置元素为结尾的所有子序列,最长的摆动序列长度。 int ret=1; for(int i=1;i<n;i++){ for(int j=0;j<i;j++){//j在i的前面 if(nums[j]<nums[i]){ f[i]=Math.max(f[i],g[j]+1);} else if(nums[j]>nums[i]){ g[i]=Math.max(g[i],f[j]+1); } } ret=Math.max(ret,Math.max(f[i],g[i])); } return ret; } }