【笔试强训day39】

目录

第一题:神奇的字母(二)                                                            

题目描述

输入描述:

输出描述:

输入

输出

说明

第二题: 字符编码                                                                         

描述

输入描述:

输出描述:

第三题:最少的完全平方数                                                            

描述

输入描述:

输出描述:

示例1


第一题:神奇的字母(二)                                                            

题目链接:神奇的字母二

题目描述

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网

我有个神奇的字母。
但我不告诉你是什么字母。
什么?你想知道这个字母是什么?那你就来猜呀~
字母的范围从'a'到'z'。
我会给你一段话,神奇的字母就是出现次数最多的那个字母哦~

输入描述:

一段话,仅由英文小写字母和空格组成。这段话可能有很多行。(保证存在出现次数最多的一个字母)
数据范围:所有字符串总长度之和不超过1000。

输出描述:

出现次数最多的那个神奇的字母。

输入

ranko sekai ichiban kawaii ranko saikou

输出

a

说明

这段话只有a出现了7次,其他字母都小于7次。

用一个hash数组来统计每个字母出现的次数就可以找到出现次数最多的。

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

int main()
{
    string s;
    int ans = 0;
    char c = 0;
    int hash[26] = { 0 };
    while (cin >> s) {
        for (auto ch : s) {
            hash[ch - 'a']++;
            if (hash[ch - 'a'] > ans) {
                ans = hash[ch - 'a'];
                c = ch;
            }
        }
    }
    cout << c << endl;
    return 0;
}

第二题: 字符编码                                                                         

题目链接:字符编码

描述

请设计一个算法,给一个字符串进行二进制编码(哈夫曼编码),使得编码后字符串的长度最短。

数据范围:字符串长度满足 1<𝑛≤1000 ,本题有多组输入

输入描述:

每组数据一行,为待编码的字符串。保证字符串长度小于等于1000。

输出描述:

一行输出最短的编码后长度。

输入:

MT-TECH-TEAM

输出:

33

哈夫曼编码。

统计每个字符出现的次数 ------> 用字符出现的次数(权值)来构建小堆 ------> 从小堆中依次取两个数据,累加求树的带权路径长度 --------> 把累加结果加入到堆中 --------> 堆中只剩一个元素为止。

求树的带权路径长度的方法不唯一,可以通过累加非根节点的权值得到。

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

int main() 
{
    string s;
    while (cin >> s) {
        int hash[300] = { 0 };
        for (auto ch : s) {
            hash[ch]++;
        }
        priority_queue<int, vector<int>, greater<int>> heap;
        for (auto val : hash) {
            if (val != 0) {
                heap.push(val);
            }
        }
        int ans = 0;
        while (heap.size() > 1) {
            int t1 = heap.top(); heap.pop();
            int t2 = heap.top(); heap.pop();
            ans += t1 + t2;
            heap.push(t1 + t2);
        }
        cout << ans << endl;
    }
    return 0;
}

第三题:最少的完全平方数                                                            

最少的完全平方数

描述

给定一个正整数n,请找出最少个数的完全平方数,使得这些完全平方数的和等于n。

完全平方指用一个整数乘以自己例如1*1,2*2,3*3等,依此类推。若一个数能表示成某个整数的平方的形式,则称这个数为完全平方数。例如:1,4,9,和16都是完全平方数,但是2,3,5,8,11等等不是

数据范围:1≤𝑛≤10^4

输入描述:

仅一行,输入一个正整数 n 

输出描述:

按题目要求输出完全平方数之和为n的最少个数

示例1

输入:

5

输出:

2

说明:

1+4=5

完全背包。

1)状态表示:在前 i 个数中选,和为 j 时所需平方数的最少个数。

2)状态转移方程:

  1. i 位置的数不选:dp[ i ] [ j ] = dp[ i - 1][ j ] --------①
  2. i 位置的数选:可以选1个、2个、3个……n个

dp[ i ] [ j ] = min( dp[ i - 1] [ j - i * i ]  + 1, dp[ i - 1] [ j - 2 * i * i ]  + 2, dp[ i - 1] [ j - 3 * i * i ]  + 3……)  ---------②

====>>

dp[ i ] [ j ] = min( dp[ i - 1][ j ],dp[ i - 1] [ j - i * i ]  + 1, dp[ i - 1] [ j - 2 * i * i ]  + 2, dp[ i - 1] [ j - 3 * i * i ]  + 3……) ---------③

观察第②个式子,i - 1一直不变,列是有规律的在递减。

在等式③中,令 j = j - i * i  ======>>

dp [ i ] [ j - i * i ] = min(dp[ i - 1][ j - i * i ],dp[ i - 1] [ j - 2 * i * i ]  + 1, dp[ i - 1] [ j - 3 * i * i ]  + 2, dp[ i - 1] [ j - 4 * i * i ]  + 3……)

等式两边同时 + 1 ========>>

dp [ i ] [ j - i * i ] + 1 = min(dp[ i - 1][ j - i * i ] + 1,dp[ i - 1] [ j - 2 * i * i ]  + 2, dp[ i - 1] [ j - 3 * i * i ]  + 3, dp[ i - 1] [ j - 4 * i * i ]  + 4……) ---------④

=======>>

式子④可以表示式子②中的诸多情况,所以状态转移方程为:

dp[ i ] [ j ] = min( dp[ i - 1][ j ] ,dp [ i ] [ j - i * i ] + 1);

需要注意的是,j >= i * i。

3)初始化:dp [ 0 ] [ 0 ] = 0,其余的无穷大。

4)填表顺序:上 ----> 下,左 ----> 右

5)返回值:dp[ 根号n] [ n ] -----> 在前根号n(包含)个数中找就可以了,下面的代码实现中,下标从1开始, 在前 i 个数中选,选的不是 i ,而是 i ^ 2.

最后,进行空间优化:把未进行空间优化的代码中的第一维砍掉,即

dp [ j ] = min( dp[ j ] ,dp [ j - i * i ] + 1);

未进行空间优化的代码是过不了的~

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

const int N = 1e4 + 10;
const int INF = 0x3f3f3f3f;
int dp[N];

int main()
{
    int n;
    cin >> n;
    memset(dp, INF, sizeof(dp));
    dp[0] = 0;
    for (int i = 1; i * i <= n; i++) {
        for (int j = i * i; j <= n; j++) {
            dp[j] = min(dp[j], dp[j - i * i] + 1);
        }
    }
    cout << dp[n] << endl;;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值