【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】

专注 效率 记忆
预习 笔记 复习 做题

欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)
 
文章字体风格:
红色文字表示:重难点★✔
蓝色文字表示:思路以及想法★✔
 
如果大家觉得有帮助的话,感谢大家帮忙
点赞!收藏!转发!

本博客带大家一起学习,我们不图快,只求稳扎稳打。
由于我高三是在家自学的,经验教训告诉我,学习一定要长期积累,并且复习,所以我推出此系列。
只求每天坚持40分钟,一周学5天,复习2天
也就是一周学10道题
60天后我们就可以学完81道题,相信60天后,我们一定可以有扎实的代码基础!我们每天就40分钟,和我一起坚持下去吧!
qq群:878080619

第二十五天【考研408-数据结构(笔试)】

  • 十八、BFS
    • 1. 玛雅人的密码
    • 2. 等差数列
  • 十九、字符串处理
    • 1. 首字母大写
    • 2. 日志排序
    • 3. 字符串转换整数
  • 二十、递归,画图
    • 1. 重复者
  • 二十一、背包问题
    • 1. 01背包
    • 2. 神奇的口袋( 体积恰好是 )
    • 3. 整数拆分
  • 二十二、高精度
    • 1. N的阶乘
      • 做法:预处理
    • 2. 基本算术
    • 3. 整数查询

十八、BFS

1. 玛雅人的密码

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第1张图片
整体思路是用BFS暴搜
存在队列中的基本元素是pair

  • 前者表示经过多次交换后当下的字符串的组成
  • 后者表示达到当下的字符串状态,经过的交换次数

因为数字本身可能会重复出现,而且对于一个字符串交换它两个不同相邻位置得到的新字符串,也可能产生重复,但我们要求的是最少交换次数,因为BFS的性质,保证了可以实现最小,所以可以设置一个map映射组,来存储已经出现过的字符串情况,防止重复对相同组成的字符串再入队处理,以作到剪枝的作用,降低时间复杂度。

这道题进入BFS暴搜前,要做一些基本的判断,很容易就考虑不到,要做好了。

#include 
#include 
#include 
#include 
#include 

using namespace std;

int n;

int bfs(string start)
{
    queue<string> q;
    unordered_map<string, int> dist;
    dist[start] = 0;
    q.push(start);

    while (q.size())
    {
        auto t = q.front();
        q.pop();

        for (int i = 0; i < n; i ++ )
            if (t.substr(i, 4) == "2012")
                return dist[t];

        for (int i = 1; i < n; i ++ )
        {
            string r = t;
            swap(r[i], r[i - 1]);
            if (!dist.count(r))
            {
                dist[r] = dist[t] + 1;
                q.push(r);
            }
        }
    }
    return -1;
}

int main()
{
    string start;
    cin >> n >> start;
    cout << bfs(start) << endl;
    return 0;
}

2. 等差数列

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第2张图片
本题的思路由样例入手

根据样例分析出
只要每行有两个元素
那么该行就能推出所有等差数据

同理列也是

所以我们先遍历所有行和列
看哪些有两个元素的

然后根据这样行和列进行填充
填充过程中观察是否新数据使得对应的行或者列
变得大于两个元素,进而可以填充

那么该过程就想到了bfs

bfs队列存储的元素是什么呢?就是所在的行或者列

怎么判断是行还是列呢?
行的范围为(0-n)
列的范围(n,m+n)

#include 
#include 
#include 

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1010, M = N * 2;

int n, m;
int row[N], col[N];
int q[M], hh, tt = -1;
bool st[M];
PII ans[N * N];
int top;
int g[N][N];

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < m; j ++ )
        {
            scanf("%d", &g[i][j]);
            if (g[i][j])
            {
                row[i] ++ ;
                col[j] ++ ;
            }
        }

    for (int i = 0; i < n; i ++ )
        if (row[i] >= 2 && row[i] < m)
        {
            q[ ++ tt] = i;
            st[i] = true;
        }
    for (int i = 0; i < m; i ++ )
        if (col[i] >= 2 && col[i] < n)
        {
            q[ ++ tt] = i + n;
            st[i + n] = true;
        }

    while (hh <= tt)
    {
        auto t = q[hh ++ ];
        if (t < n)  // 行
        {
            PII p[2];
            int cnt = 0;
            for (int i = 0; i < m; i ++ )
                if (g[t][i])
                {
                    p[cnt ++ ] = {i, g[t][i]};
                    if (cnt == 2) break;
                }
            int d = (p[1].y - p[0].y) / (p[1].x - p[0].x);
            int a = p[1].y - d * p[1].x;

            for (int i = 0; i < m; i ++ )
                if (!g[t][i])
                {
                    g[t][i] = a + d * i;
                    ans[top ++ ] = {t, i};
                    col[i] ++ ;
                    if (col[i] >= 2 && col[i] < m && !st[i + n])
                    {
                        q[ ++ tt] = i + n;
                        st[i + n] = true;
                    }
                }
        }
        else  // 列
        {
            t -= n;
            PII p[2];
            int cnt = 0;
            for (int i = 0; i < n; i ++ )
                if (g[i][t])
                {
                    p[cnt ++ ] = {i, g[i][t]};
                    if (cnt == 2) break;
                }
            int d = (p[1].y - p[0].y) / (p[1].x - p[0].x);
            int a = p[1].y - d * p[1].x;
            for (int i = 0; i < n; i ++ )
                if (!g[i][t])
                {
                    g[i][t] = a + d * i;
                    ans[top ++ ] = {i, t};
                    row[i] ++ ;
                    if (row[i] >= 2 && row[i] < n && !st[i])
                    {
                        q[ ++ tt] = i;
                        st[i] = true;
                    }
                }
        }
    }

    sort(ans, ans + top);
    for (int i = 0; i < top; i ++ )
    {
        auto& p = ans[i];
        printf("%d %d %d\n", p.x + 1, p.y + 1, g[p.x][p.y]);
    }

    return 0;
}

十九、字符串处理

1. 首字母大写

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第3张图片

#include 
#include 
#include 

using namespace std;

int main()
{
    string s;
    getline(cin, s);
    for (int i = 0; i < s.size(); i ++ )
        if (!i || s[i - 1] == ' ')
            cout << (char)toupper(s[i]);
        else
            cout << s[i];
    return 0;
}

2. 日志排序

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第4张图片
【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第5张图片

#include 
#include 
#include 
#include 

using namespace std;

const int N = 10010;

int n;
string logs[N];

int main()
{
    while (getline(cin, logs[n]))
        if (logs[n].size()) n ++ ;
        else break;

    sort(logs, logs + n, [](string& a, string &b) {
        stringstream ssina(a), ssinb(b);
        string sa[4], sb[4];
        for (int i = 0; i < 4; i ++ )
        {
            ssina >> sa[i];
            ssinb >> sb[i];
        }

        if (sa[3] == sb[3]) return sa[1] + sa[2] < sb[1] + sb[2];

        double ta, tb;
        sscanf(sa[3].c_str(), "%lf(s)", &ta);
        sscanf(sb[3].c_str(), "%lf(s)", &tb);
        return ta < tb;
    });

    for (int i = 0; i < n; i ++ )
        cout << logs[i] << endl;

    return 0;
}

3. 字符串转换整数

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第6张图片

#include 
#include 
#include 
#include 

using namespace std;

typedef long long LL;

int main()
{
    string s;
    cin >> s;

    for (int i = 0; i < s.size(); i ++ )
        if (isdigit(s[i]))
        {
            LL x = 0;
            while (i < s.size() && isdigit(s[i]))
            {
                x = x * 10 + s[i] - '0';
                if (x > INT_MAX)
                {
                    puts("-1");
                    return 0;
                }
                i ++ ;
            }
            cout << x << endl;
            return 0;
        }

    puts("-1");
    return 0;
}

二十、递归,画图

1. 重复者

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第7张图片
本题由于第三次图形需要知道 第二层的图形

所以需要递归

#include 
#include 
#include 
#include 

using namespace std;

int n;
vector<string> p;

vector<string> g(int k)
{
    if (k == 1) return p;
    auto s = g(k - 1);
    int m = s.size();

    vector<string> res(n * m);
    for (int i = 0; i < n * m; i ++ )
        res[i] = string(n * m, ' ');

    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            if (p[i][j] != ' ')
                for (int x = 0; x < m; x ++ )
                    for (int y = 0; y < m; y ++ )
                        res[i * m + x][j * m + y] = s[x][y];

    return res;
}

int main()
{
    while (cin >> n, n)
    {
        p.clear();
        getchar();  // 读掉n后的回车
        for (int i = 0; i < n; i ++ )
        {
            string line;
            getline(cin, line);
            p.push_back(line);
        }

        int k;
        cin >> k;
        auto res = g(k);
        for (auto& s: res) cout << s << endl;
    }

    return 0;
}

二十一、背包问题

1. 01背包

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第8张图片

#include 
#include 
#include 

using namespace std;

const int N = 1010;

int n, m;
int f[N][N];

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ )
    {
        int v, w;
        scanf("%d%d", &v, &w);
        for (int j = 0; j <= m; j ++ )
        {
            f[i][j] = f[i - 1][j];
            if (j >= v)
                f[i][j] = max(f[i][j], f[i - 1][j - v] + w);
        }
    }

    printf("%d\n", f[n][m]);
    return 0;
}

2. 神奇的口袋( 体积恰好是 )

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第9张图片

#include

using namespace std;

const int N = 50;

int f[N][N];
int a[N];
int n;

int main()
{
    cin >> n;
    
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    
    f[0][0] = 1;
    
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j <= 40; j++)
        {
            f[i][j] = f[i-1][j];
            if(a[i]<=j)
            {
                f[i][j] = f[i][j] + f[i-1][j-a[i]];
            }
        }
    }
    
    cout << f[n][40];
    
    return 0;
}

3. 整数拆分

【复习19-23天】【我们一起60天准备考研算法面试(大全)-第二十五天 25/60】_第10张图片
本题中如果用这种做法的话会爆内存

#include
using namespace std;
typedef long long LL;
const int N = 1e6+10, mod = 1e9;
LL v[25], f[25][N];     //v[]:存储 2 的 i 次幂,即 2^i     

void init(){        //预处理出 2 的 0 次幂到 20 次幂
    v[0] = 1;
    for(int i = 1;i <= 20;++i) v[i] = v[i - 1] * 2;
}

void solve(){
    int n;
    cin >> n;
    init();
    for(int i = 0;i <= 20;++i){
        for(int j = 0;j <= n;++j){
            if(!i || !j){   //状态为 f[i][0] 和 f[0][j] 时,将其初始化为 1
                f[i][j] = 1;
                continue;
            }

            if(j < v[i]) f[i][j] = f[i - 1][j];     //当 2^i > j 时,f[i][j]中只有一个集合(有0个 2^i 的集合)

            else f[i][j] = (f[i - 1][j] + f[i][j - v[i]]) % mod;    //状态转移方程
        }
    }

    cout << f[20][n];   
}

int main(){
    solve();
    return 0;
}

#include 
#include 
#include 

using namespace std;

const int N = 1000010, MOD = 1e9;

int n;
int f[N];

int main()
{
    scanf("%d", &n);
    f[0] = 1;
    for (int i = 1; i <= n; i *= 2)
        for (int j = i; j <= n; j ++ )
            f[j] = (f[j] + f[j - i]) % MOD;
    cout << f[n] << endl;

    return 0;
}

二十二、高精度

1. N的阶乘

在这里插入图片描述

做法:预处理

#include 
#include 
#include 
#include 

using namespace std;

const int N = 1010;

vector<int> F[N];

vector<int> mul(vector<int>& A, int b)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }
    return C;
}

int main()
{
    int n;
    F[0] = {1};
    for (int i = 1; i <= 1000; i ++ ) F[i] = mul(F[i - 1], i);

    while (cin >> n)
    {
        for (int i = F[n].size() - 1; i >= 0; i -- )
            cout << F[n][i];
        cout << endl;
    }

    return 0;
}

2. 基本算术

在这里插入图片描述

#include 
#include 
#include 
#include 

using namespace std;

int add(vector<int>& A, vector<int>& B)
{
    int res = 0;
    for (int i = 0, t = 0; i < A.size() || i < B.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i];
        if (i < B.size()) t += B[i];
        t /= 10;
        res += t;
    }
    return res;
}

int main()
{
    string a, b;
    while (cin >> a >> b, a != "0" || b != "0")
    {
        vector<int> A, B;
        for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
        for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
        int res = add(A, B);
        if (!res) puts("No carry operation.");
        else if (res == 1) puts("1 carry operation.");
        else printf("%d carry operations.\n", res);
    }

    return 0;
}

3. 整数查询

在这里插入图片描述

#include 
#include 
#include 
#include 

using namespace std;

vector<int> add(vector<int>& A, vector<int>& B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size() || i < B.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }
    return C;
}

int main()
{
    vector<int> A{0};
    string b;
    while (cin >> b, b != "0")
    {
        vector<int> B;
        for (int i = b.size() - 1; i >= 0; i -- )
            B.push_back(b[i] - '0');
        A = add(A, B);
    }

    while (A.size() > 1 && !A.back()) A.pop_back();
    for (int i = A.size() - 1; i >= 0; i -- )
        cout << A[i];
    cout << endl;

    return 0;
}

你可能感兴趣的:(算法,考研,面试)