【刷题汇总 -- 添加字符、数组变换、装箱问题】

今日刷题汇总 - day022

1、添加字符

1.1、题目

在这里插入图片描述

1.2、思路

读完题,知道有两个字符串A,B,其中B串的起始长度大于等于A串,然后可以将对A串前或后执行插入操作,使其与B达成一样的长度,且让A,B串中不同字符的个数最少。那么,采用蛮力法枚举所有可能,首先得明白,插入字符课以插入任意字符,所以插入的字符肯定为了与B串相同的字符,那么存在不同的字符只可能是在A串的初始串中,那么又因为可以前插或后插,为了初始串的不同字符个数最少那么,就与A串匹配,让其在最合适的位置满足对应每一位的字符相同,不同字符最少即可。简单画个图直观的理解:
在这里插入图片描述
那么接下来,就是程序实现。

1.3、程序实现

首先,按照题目要求输入初始A,B串,并求的A,B串的长度m,n,然后根据思路分析的要找最合适B串的起始位置,使其满足对应位置匹配字符相同的最多,相反就得到最少不同字符的个数了。利用for依次枚举,其中枚举到后面字符串长度小于A串长度就不同枚举了,因为小于长度了就不会匹配了,然后,内循环就是执行匹配字符,枚举到B串 i 位置为起始位置上时,统计A,B不同字符的个数,保存到ret中,并随着枚举不断更新即可,最后遍历完输出就得到最少不同字符个数了。

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string A, B;
    cin >> A >> B;
    int m = A.size();
    int n = B.size();
    int ret = m;
    // 枚举 B串最合适 的起始位置
    for (int i = 0; i <= n - m; i++)
    { 
        int tmp = 0;
        //匹配A串 i 起始位置时,A,B串的不同字符情况
        for (int j = 0; j < m; j++)
        {
            if (A[j] != B[i + j])
            {
                tmp++;
            }
        }
        ret = min(tmp, ret);
    }
    cout << ret << endl;
    return 0;
}

在这里插入图片描述

2、数组变换

2.1、题目

在这里插入图片描述

2.2、思路

读完题,知道n个元素的数组,可对数组中每个元素执行2操作,判断是否能够让数组中每一个元素都最终相等。其中,这个操作的使用次数不限,也可以不使用,并且可以对同一个位置使用多次。最终成功的就输出"Yes",不能完成的就输出"No"即可。那么,根据题目和示例分析,该数组中的元素会存在2的n次方关系,因为2,3不能通过一直2得到相同的数值的,也就是说,需要判断较小的数能否变换成最大值,如果能够变换成功,那么最⼤的数除以剩下的数的商,⼀定都是 2 的 n 次⽅。以1,2 ,4,8,16为例,满足所有元素都能通过2达成全部相等,同时验证了最大数除以剩余元素的商属于2的n次方,再以3,6,12,24为例,这组元素本身并不是属于2的n次方,那么也是可以通过2得到统一的相等数值的,发现通常以最大值为基准的,其次,验证了最大数除以剩余元素的商属于2的n次方,同时发现,需要较大值能整除较小值。所以综上所述,需要具备以下条件:
(1)、较大值除以较小值满足商属于2的n次方;
(2)、较大值能够整除较小值。
那么问题就演变为,怎么判断商是否属于2的n次方呢?
1.蛮力法,让这个数不断地除以2,直到最后等于1为止,说明是属于2的n次方的,否则不满足;
2.位运算,利用二进制的特点2的n次方满足以下两个情况:
(1)、方法1:x - x&(-x) = 0,则满足
(2)、方法2:x & (x-1) = 0,则满足。
那么接下来,就是程序实现。

2.3、程序实现

首先,按照题目要求写好输入,并求得数组中最大值作为基准值,然后再次遍历数组,结合标志位,判定是否符合思路分析中的两个条件即可。

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    cin >> n;
    int arr[51];
    int maxval = 0;
    for(int i = 0;i< n;i++)
    {
        cin >> arr[i];
        maxval = max(maxval,arr[i]);
    }
    int flag = 0;
    for(int i = 0;i < n;i++)
    {
        if(maxval % arr[i] != 0)
        {
            flag = 1;
            break;                
        }
        int x = maxval / arr[i];
        if(x & (x-1) != 0)
        {
            flag = 1;
            break;                
        }
    }
    if(flag) 
        cout << "NO" << endl;
    else 
        cout << "YES" << endl;
    return 0;
}

在这里插入图片描述

3、装箱问题

3.1、题目

在这里插入图片描述

3.2、思路

读完题,知道在限制了容量为V的箱子中,对于n个物品,任取若干个物品后要求尽可能让剩余空间最少即可。与之前写过的0/1背包问题类似,都是属于贪心加dp动态规划问题,因为存在放与不放的选择,限制了容量为V的上限,所以采用dp动态规划问题,那么就确定状态表示和状态转移方程,以dp[i][j]:表示在前 i 个物品中挑选,总体积不超过 j 的条件下,此时的最大体积是多少。那么剩余容量就是V - dp[i][j]。继续,推导状态转移方程,首先,对于第 i 个物品时可选择放入或不放入,所以存在两种情况:
(1)、对于选择放入第 i 个物品时,对于前面 i-1个物品时满足最大体积就是dp[i-1],然后总体积不超过 j ,那么对于 i -1个物品时就不能超过 j 减去第 i 个物品的体积 v[i] ,最后再加上第 i 个物品的体积,即,dp[i][j] = dp[i-1][j - v[i]] + v[i];值得注意的是,当选择放入第 i 个物品的前提条件是前 i -1 个物品能放下,即物品空间 j - v[i] 满足大于等于v[i]。
(2)、那么当选择不放入第 i 个物品时,在前面的物品满足最大体积就是到 i-1物品时满足,且也需要 i-1 个物品时总体积不能超过 j ,即dp[i][j] = dp[i-1][j]即可。
所以综上所述:
(1)、状态表示dp[i][j]:表示在前 i 个物品中挑选,总体积不超过 j 的条件下,此时的最大体积是多少。那么剩余容量就是V - dp[i][j]。
(2)、状态转移方程dp[i][j]两种情况:
a、选择不放入第 i 个物品时:dp[i][j] = dp[i-1][j];
b、选择放入第 i 个物品时:j - arr[i] >= 0 ,dp[i][j] = max(dp[i-1][j - v[i]] + v[i],dp[i][j]);
(3)、初始化依然采用方便的下标从1开始计数,所以多增加一行一列的方案即可。
那么接下来,就是程序实现。

3.3、程序实现 – dp(0/1背包问题)

(1)、状态表示dp[i][j]:表示在前 i 个物品中挑选,总体积不超过 j 的条件下,此时的最大体积是多少。那么剩余容量就是V - dp[i][j]。
(2)、状态转移方程dp[i][j]两种情况:
a、选择不放入第 i 个物品时:dp[i][j] = dp[i-1][j];
b、选择放入第 i 个物品时:j - arr[i] >= 0 ,dp[i][j] = max(dp[i-1][j - v[i]] + v[i],dp[i][j]);
(3)、初始化依然采用方便的下标从1开始计数,所以多增加一行一列的方案即可。

#include <iostream>

using namespace std;

const int N = 31;
const int M = 2e4 + 10;

int arr[N];
int dp[N][M];

int main()
{
    int v,n;
    cin >> v >> n;
    for(int i = 1;i <= n;i++)
        cin >> arr[i];
    
    for(int i = 1;i <= n;i++)
    {
        for(int j = 0;j <= v;j++)
        {
            dp[i][j] = dp[i-1][j];
            if(j >= arr[i])
                dp[i][j] = max(dp[i][j],dp[i-1][j-arr[i]] + arr[i]);
        }
    }
    
    cout << v - dp[n][v] << endl;
    return 0;
}

在这里插入图片描述
在这里插入图片描述

4、题目链接

🌟添加字符
🌟数组变换
🌟装箱问题

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值