【基础算法训练】—— 线性动态规划+位运算

简介: 【基础算法训练】—— 线性动态规划+位运算

第一题 [蓝桥杯 2013 省] 买不到的数目


题目描述

微信图片_20221019205840.png解题报告


解法一是一种数学知识的积累吧。

两个互质的数x,y不能组成的最大整数为x*y-x-y,如果题目给定的两个数不互质的话,那么任何数都能组成,所以给定的数一定是互质的。


解法二是动态规划。

这个动态规划不用闫式DP分析了。直接可以从递推的想法来实现。

bool数组 bool f[i]来记录是否能组成当前这个数字i

状态转移就十分简单了,倘若能够从f[i-n]转移过来或者能从f[i-m]转移过来,就是能够组成,否则就记录答案,表示不能组成当前的数字(从两个数字中最小的开始枚举,就能够递推找到最大的数字了)


参考代码(C++版本)


解法一:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n,m;
int main() 
{
    scanf("%lld %lld",&n,&m);
    printf("%lld",n*m - n -m);
    return 0;
}

解法二

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
bool f[1000010];
int n,m;
int main() 
{
    cin >> n >>m;
    int maxv = max(n,m);
    int minv = min(n,m);
    f[0] = true;
    int ans = 0;
    for(int i = minv; i <= n * m;i++)
    {
        if(f[i-minv]) f[i] = true;
        else if(i >= maxv && f[i-maxv]) f[i] = true;
        else ans = i;
    }
    cout << ans;
    return 0;
}

第二题 P3951 [NOIP2017 提高组] 小凯的疑惑


题目描述

微信图片_20221019210014.png

解题报告


参考代码(C++版本)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL; 
LL n, m; //2,147,483,648
int main()
{
  scanf("%lld %lld",&n,&m);
  printf("%lld\n",n*m-n-m);
  return 0;
} 

第三题 191. 位1的个数


积累lowbit运算


题目描述


微信图片_20221019210132.png

解题报告


lowbit运算——这东西是板子,背着就好

关于lowbit运算的知识点:

在这里插入图片描述

微信图片_20221019210225.png

根据图片中对lowbit运算的定义,对于非负整数10,其二进制表示为( 1010 ) 2 (1010)_2(1010)

2


,那么lowbit(n) = ( 10 ) 2 (10)_2(10)

2


 = 2



lowbit运算的证明/推导

关于运算的证明可以权当了解,现阶段会用,能Ac就好,以后学习更深入了再搞定原理也不迟的。

image.png

lowbit运算的作用

① 可以配合哈希表找出整除二进制表示下的所有是1的位数

② lowbit运算是树状数组的一个基本运算


参考代码(C++版本)

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int ans = 0;
         while(n)
         {
             n -= (n & (-n));
             ans ++;
         }
        return ans;
    }
};

第四题 461. 汉明距离


题目描述

微信图片_20221019210348.png

解题报告


使用右移运算符一位一位的移动,比较


参考代码(C++版本)

class Solution {
public:
    int hammingDistance(int x, int y) {
        //一位一位的移动,比较
        int ans = 0;
        while(x || y)
        {
            if((x&1) != (y&1)) ans ++;
            x >>= 1;
            y >>= 1;
        }
        return ans;
    }
};

解法二:

学习一下英雄哥的玩法微信图片_20221019210444.png

class Solution {
public:
    int hanmingWeight(uint32_t n)
    {
        int ans = 0;
        while(n)
        {
            ans += (n & 1);
            n >>= 1;
        }
        return ans;
    }
    int hammingDistance(int x, int y) {
        return hanmingWeight(x^y);
    }
};

第五题 136. 只出现一次的数字


异或运算积累


题目描述


微信图片_20221019210522.png

解题报告


解法一:哈希表

解法二:任意两个相同的数字(2的倍数同样成立哦)异或结果为0,那么把所有的数字全部异或之后,最后得到的结果就0 ^ 只出现一次的数字。因为异或运算有时候也称我不进位加法,0 ^ 只出现一次的数字 = 0 + 只出现一次的数字


参考代码(C++版本)


解法一

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        //哈希表的思想
        unordered_map <int,int> mp;
        int n = nums.size();
        for(int i = 0; i < n;i++)
            mp[nums[i]] ++;
        int ans = 0;
        for(int i = 0; i < n;i++)
            if(mp[nums[i]] == 1) 
                ans = nums[i];
        return ans;
    }
}; 

解法二:

这个解法的效率,嘎嘎提升了

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int n = nums.size();
        int ans = nums[0];
        for(int i = 1; i < n;i++)
            ans ^= nums[i];
        return ans;
    }
};

第六题 137. 只出现一次的数字 II


数位统计——为状态压缩动态规划做铺垫了


题目描述

微信图片_20221019210704.png

解题报告


老规矩,也是可以直接哈希表

解法二:数位统计


参考代码(C++版本)


解法一:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map <int,int> mp;
        int n = nums.size();
        for(int i = 0; i < n;i++)
            mp[nums[i]] ++;
        int ans = 0;
        for(int i = 0; i < n;i++)
            if(mp[nums[i]] == 1) 
                ans = nums[i];
        return ans;
    }
};

解法二:

数位统计的思想

看到这个题的数据范围了,其实就可以向着位运算的方向思考了。

现在了,其实可以使用一个32位的二进制来表示咱们要进行计算的十进制数字,然后对用于表示的32位的二进制进行求和,因为除了咱们需要的答案,其他的结果都是三的倍数,那么可以将求和的结果的每一位和3进行取模,最后得到的结果就是咱们需要的答案了,再把其从二进制转换为十进制就好。


样例演示:

nums = [2,2,3,2]

将这四个数字转换为32位的二进制:

[00000000000000000000000000000010, 00000000000000000000000000000010, 00000000000000000000000000000011, 00000000000000000000000000000010];


对这四个二进制的每一位进行求和:

[00000000000000000000000000000041]

将求和结果的每一位进行3的取模运算:

[00000000000000000000000000000011]

将得到的结果[00000000000000000000000000000011]从二进制转换成十进制就是3


class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans = 0;
        int n = nums.size();
        for(int i = 0; i < 32;i++)
        {
            int sum = 0;
            for(int j = 0;j < n;j++)
                sum += ((nums[j] >> i) & 1);
            if(sum%3) //将得到的二进制转十进制
                ans |= (1 << i);
        }
        return ans;
    }
};


总结


① 积累买不到数目的数学想法,我记得是使用裴蜀定理来证明的,后续补上吧

② 积累lowbit运算

③ 数位统计的想法

相关文章
|
1月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
14天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
30 2
|
1月前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
68 2
动态规划算法学习三:0-1背包问题
|
1月前
|
存储 机器学习/深度学习 算法
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
蓝桥杯Python编程练习题的集合,涵盖了从基础到提高的多个算法题目及其解答。
60 3
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
|
21天前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
9天前
|
算法 C# 索引
C#线性查找算法
C#线性查找算法!
|
1月前
|
机器学习/深度学习 算法 决策智能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
|
1月前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
65 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
1月前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
126 0
动态规划算法学习二:最长公共子序列
|
1月前
|
存储 算法
动态规划算法学习一:DP的重要知识点、矩阵连乘算法
这篇文章是关于动态规划算法中矩阵连乘问题的详解,包括问题描述、最优子结构、重叠子问题、递归方法、备忘录方法和动态规划算法设计的步骤。
101 0