2021年4月

2021/4/17

  • 多个选项中选多个的题目,计算合法方案数。这种题目可以利用全排列来写

    • 六个里边选三个int arr[]={0,0,0,1,1,1,};
  • 消除尾一:x=x&(x+1)

    • 经典的二进制题目!
      在这里插入图片描述
  • 10个数的全排列,时间复杂度为10!

  • 最大公共子串最大公共子序列在二维动态规划时,是不一样的

    • 前者的状态转移是if(s1[i-1]==s2[i-1]) dp[i][j]=dp[i-1][j-1]+1;
    • 后者需要分三种情况进行讨论。
  • 背包问题的精髓在于:在递归或动态规划时,假设背包中已经装了xx的情况下,看剩下的容量怎么装。

2021/4/16

  • 若a、b、c三者和的余数为K,a的余数为i,b的余数为j
    • 则c的余数为(K-i+K-j)%K
    • (i以外需要凑的余数+j以外需要凑的余数)对K取余
  • 多重循环时间复杂度优化
    • 减少层数
    • 减少范围
    • 能否二分
    • 空间换时间
  • 倍数问题大多跟余数有关!
    • 多个数的和是某个数的倍数,意味着,各个数的余数的和等于目标数;
  • 动手编程之前,把问题想清楚,思路理清楚,每一步要做什么搞清楚,先注释,再编程。
  • 对于多维数组的问题,可以转换成一维进行处理
    • 如三维转一维
int convert(int i,int j,int k){
    int a=i-1,b=j-1,c=k-1;
    return a*row*column+b*column+c;
}

2021/4/14

  • python的数不会溢出,因此比赛填空题有些可以用python来解决
  • 取模与取余的区别在于
    • 取余是向0方向舍入(fix函数)
    • 取模是向负无穷方向舍入(floor函数)
    • 如-7 mod 4= 1 (到-8不足1), -7 %4 = -3 (到-4少了-3)

2021/4/13

  • 快速幂的精髓在于,将底数不断膨胀,幂不断缩小

递归写法

long long fastPow(long long base,int pow){
    if(pow==0)
        return 1;
    if(pow==1)
        return base;
    if(pow%2==1){
        return base*fastPow(base*base,pow/2);
    }
    return fastPow(base*base,pow/2);
}

非递归位运算写法

long long fastPow(long long base,int pow){
	long long res=1;
	while(pow){
		//处理奇数
		if(pow&1){
			res*=base;
		}
		base*=base;
		pow>>=1;
	}
	return res;
}

2021/4/12

  • 凡是在一组值中,选出一部分,在一定规则下组合成一个目标值,就可以看作是背包问题
    • 背包问题的精髓在于将目标值分解成0~n来逐个解决,每次选取数组中一个值时,对背包剩下的容量进行调整(一般是减少,也可能增加),装入背包后,剩余容量用已有的dp[j]来解决是背包问题能动态规划的核心原因

2021/4/11

  • 一些动态规划的问题,考虑将dp[i]是为,以i为结尾的xxx;
  • 使用dp数组,首先要搞明白dp[i]代表什么含义,可以是题中的要求求解的量,也可以是中间结果。并思考,dp[i]和dp[i-1](或者dp[i]和dp[0],dp[1]…dp[i-1])有什么关系。
  • 对于动态规划(或者其他问题)中的环形问题,可以采取分类的方法
    • 选第一个且不选最后一个,求出最优解
    • 选最后一个且不选第一个,求出最优解
  • 有一部分动态规划问题的精髓在于,对每一种情况进行试探,从而找出最优解。(不是返回dp[len-1]就行了,而是max(dp[i]) )
    • 比如leetcode121题股票交易,这是一道easy题,但是我想了好久没做出来,为什么?因为对动态规划题目定势思维了,认为dp[i]存储的就是最终结果,其实它也可以是中间结果,或者是需要进一步处理的信息。
    • 对这种题目,我们可以尝试在每一天卖出股票,从而找到最优的方案。

2021/4/10

  • 动态问题一定要搞清楚对谁进行0~n的划分(如果coins问题是对金额进行划分),也有可能是多个变量进行划分(二维、三维dp,但也可压缩。

  • 01背包问题为什么要倒序遍历(压缩的)dp数组

    • 比如在leetcode474中,这样一个临时的二维dp
      在这里插入图片描述
    • 假如从左上角往右下角遍历,每次利用i,j位置之前的数据修改dp[i][i],就会造成上一轮的临时数据已经被修改,后边的数据无法利用上一轮的临时数据了。而从右下角向左上角遍历,就不会出现这个问题。
      在这里插入图片描述
  • 01背包问题,动态规划的思路是:物品一个一个尝试,容量一点一点尝试,每个物品分类讨论的标准是:选与不选

2021/4/9

  • 对于动态规划中的初始条件问题(尤其是二维dp),可以额外写一个函数来处理,如下这个LCS最长公共子序列问题,使用safeReturn函数来处理第一行第一列的特殊情况
class Solution
{
public:
    int safeReturn(vector<vector<int> >&dp,int x,int y)
    {
        if(x<0 || y<0)
            return 0;
        return dp[x][y];
    }
    int longestCommonSubsequence(string text1, string text2)
    {
        int len1=text1.size(),len2=text2.size();
        //dp[i][j]表示,text1前i个字符和text2前j个字符的LCS数
        vector<vector<int> >dp(len1,vector<int>(len2,0));
        for(int i=0; i<len1; i++)
            for(int j=0; j<len2; j++)
            {
                if(text1[i]==text2[j])
                {
                    dp[i][j]+=1;
                    dp[i][j]+=safeReturn(dp,i-1,j-1);
                }
                else
                {
                    dp[i][j]=max(safeReturn(dp,i-1,j),safeReturn(dp,i,j-1));
                }

            }
        return dp[len1-1][len2-1];
    }
};
  • 对于动态规划问题,dp[i]记录的可以是中间结果,也可以是最终结果。如果记录的是中间结果,最后不能忘了遍历并返回最大值或最小值

2021/4/7

  • 排列与组合
    • 对于排列题,使用next_permutation或者自定义DFS+回溯的递归函数实现;
    • 对于组合题,使用递归对每个位置采取选中不选中两种方法。
  • 使用DFS+回溯编写不重复的全排列,在for循环的交换中,可以使用set集合来避免重复
    • 注意!使用之前,序列必须已经排好序!
    • 注意!内部交换时,仅仅让交换过来的数不等于自身,是远远不够的,因为可能多次交换过来同一个数,需要使用set才能完全去重。
void permutation(vector<int>&nums,int k){
    //在下一轮进行判断
    if(k==nums.size()){
        ans.push_back(nums);
        return;
    }
    set<int>record;
    for(int i=k;i<nums.size();i++){
        int target=nums[i];
        if(record.find(target)!=record.end()){
            continue;
        }
        record.insert(target);
        swap(nums[i],nums[k]);
        permutation(nums,k+1);
        swap(nums[i],nums[k]);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值