分享会【一】

动态规划

做题步骤:

1.确定好dp数组及其下标含义

2.确定递推公式

3.dp数组如何初始化

4.确定遍历顺序

5.举例推导dp数组

实例表现:

最长回文子序列

解题思路

dp[i][j]含义:表示 s 的第 i 个字符到第 j 个字符组成的子串中,最长的回文序列长度是多少。

状态转移方程

->子序列:元素可以不连续

如果 s 的第 i 个字符和第 j 个字符相同的话,那么dp[i][j] = dp[i+1][j-1] + 2;

​ 如果 s 的第 i 个字符和第 j 个字符不同的话,那么dp[i][j] = max(dp[i+1][j],dp[i][j-1]

遍历顺序:i 从最后一个字符开始往前遍历,j 从 i + 1 开始往后遍历,这样可以保证每个子问题都已经算好了。

初始化:i == j 时dp[i][j] =1(单个字符的最长回文序列是 1)

代码实现

int longestPalindromeSubseq(char * s){
    int n,i,j;
    n = strlen(s);
    if(n == 1){
        return n;
    }
    int max = 1;
    int dp[1001][1001]={0};
    //dp[i][j]表示第i个字符到第j个字符之间的回文子序列的长度
    for(i = 1;i < n+1;i ++){
        dp[i][i] = 1;
    }
    /**dp含义、递推公式、初始化、遍历顺序
    s[i] == s[j]时,那么dp[i][j] = dp[i+1][j-1] + 2;
    s[i] != s[j]时,dp[i][j] = max(dp[i+1][j],dp[i][j-1]
    
    */
    for(i = n;i >= 1;i--){
        for(j = i+1;j <= n;j++){
            if(s[i-1] == s[j-1]){
                dp[i][j] = dp[i+1][j-1] + 2;
            }else{
                // dp[i][j] = fmax(dp[i+1][j],dp[i][j-1]);
                if(dp[i+1][j] > dp[i][j-1]){
                    dp[i][j] = dp[i+1][j];
                }else{
                    dp[i][j] = dp[i][j-1];
                }
            }
            if(max < dp[i][j]){
            max = dp[i][j];
        }
        }
        // max = fmax(max,dp[i][j]);
        
    }
   return max;
}

打家劫舍_1

解题思路:

i 的含义:表示前i步能偷的最大金额(第i家是否必偷)

状态转移方程

偷?dp[i-2]+nums[i]

不偷?dp[i-1]->不一定非要偷,dp[i-1]不一定偷nums[i-1]

->取最大值

每家必偷,再加上上一次偷的最大值

dp[i] = max(dp[i-2],dp[i-3])+ nums[i];

初始化

dp[0] = nums[0],

dp[1] = nums[1],

dp[2] = nums[2] + nums[0];

代码实现:

class Solution {
    int max(int a,int b){
        if(a > b)return a;
        else return b;
    }
    public int rob(int[] nums) {
        int[] dp = new int [1001];
        int m = 0;
        int n = nums.length;
        dp[0] = nums[0];
        m = max(dp[0],m);
        if(n == 1){
            return m;
        }
        dp[1] = nums[1];
        m = max(dp[1],m);
        if(n == 2){
            return m;
        }
        dp[2] = nums[2] + nums[0];
        m = max(dp[2],m);
        if(n == 3){
            return m;
        }
        for(int i = 3;i < n;i++){
            dp[i] = max(dp[i-2],dp[i-3])+nums[i];
            m = max(dp[i],m);
        }
        return m;
    }
}

打家劫舍_2

在打家劫舍_1的基础上添加了限制条件,nums[0],nums[n-1]相邻

解题思路

改进点:当偷第一家时,dp数组在n-2就结束循环;

不偷第一家时,dp数组从dp[1]开始初始化,在dp[n-1]结束循环

找出最大的金额

边界处理:当数组只有三个时,取出最大值即可

代码实现

class Solution {
    int max(int a,int b){
        a = a > b ? a : b;
        return a;
    }
    public int rob(int[] nums) {
        int[] dp = new int [1001];
        int n  = nums.length;
        int m;
        if(n == 1){
            return nums[0];
        }
        m = max(nums[0],nums[1]);
        if(n == 2){
            return m;
        }
        if(n == 3){
            return max(nums[2],m);
        }
        dp[0] = nums[0];
        dp[1] = nums[1];
        dp[2] = max ,nums[1]);
        m = max(dp[2],m);
        for(int i = 3;i < n-1;i++){
            dp [i] = max(dp[i-2],dp[i-3])+nums[i];
            m = max(m,dp[i]);
        }
        int s;
        dp[1] = nums[1];
        dp[2] = nums[2];
        s = max(nums[1],nums[2]);
        dp[3] = max(nums[1] + nums[3],nums[2]);
        s = max(dp[3],s); 
        for(int i=4;i<n;i++){
            dp [i] = max(dp[i-2],dp[i-3])+nums[i];
            s = max(s,dp[i]);
        }
        m = max(m,s);
        return m;
    }
}

930. 和相同的二元子数组 - 力扣(LeetCode)中等

int numSubarraysWithSum(int* nums, int numsSize, int goal){
    int hash[60010];
    int i;
    int ans=0;
    for(i=1;i<numsSize;i++){
        nums[i] += nums[i-1];
    }
    memset(hash,0,sizeof(hash));
    hash[goal]=1;
    for(i=0;i<numsSize;i++){
        ans += hash[nums[i]];
        hash[nums[i]+goal]++;
    }
    return ans;
}

31. 下一个排列 - 力扣(LeetCode)

1.第一个非递减的->记录下标i

2.i后排序,找到第一个比他大的交换

class Solution {
    public void nextPermutation(int[] nums) {
        int q = nums.length-1,p = nums.length-2,cur;
        int temp = 0,i,j,flag=0;
        //->找到不是递减的地方
            for(q = nums.length-1,p = nums.length-2;p >= 0;p--,q--){
                if(nums[p] < nums[q]){//i = 0,p=0,q=1,1<3
                    flag=1;
                    break;
                }
            } 
        //交换:nums[p]后排序->找到递增序列第一个大于nums[p]的数->交换
        if(flag == 1){
            Arrays.sort (nums,p+1,nums.length);
            for(j=p+1;j<nums.length;j++){
                if(nums[j] > nums[p]){
                    break;
                }
            }
            temp = nums[p];
            nums[p] = nums[j];
            nums[j] = temp;
        }else{
            Arrays.sort (nums,0,nums.length);  
        }
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值