【寒假每日一题】找硬币(个人练习)详细题解+推导证明(第十二天)

前言

这个寒假每日一题的系列,难度都是比较低的,属于基础题。

今天的题目是来自PAT甲级真题1048。
在这里插入图片描述

题目

伊娃喜欢从整个宇宙中收集硬币。

有一天,她去了一家宇宙购物中心购物,结账时可以使用各种硬币付款。

但是,有一个特殊的付款要求:每张帐单,她只能使用恰好两个硬币来准确的支付消费金额。

给定她拥有的所有硬币的面额,请你帮她确定对于给定的金额,她是否可以找到两个硬币来支付。

输入格式

  • 第一行包含两个整数 N 和 M,分别表示硬币数量以及需要支付的金额。
  • 第二行包含 N 个整数,表示每个硬币的面额。

输出格式

  • 输出一行,包含两个整数 V1,V2,表示所选的两个硬币的面额,使得 V1≤V2 并且 V1+V2=M。
  • 如果答案不唯一,则输出 V1 最小的解。
  • 如果无解,则输出 No Solution。

数据范围

  • 1 ≤ N ≤ 105 , 1≤N≤105, 1N105,
  • 1 ≤ M ≤ 1000 1≤M≤1000 1M1000
输入样例1:
8 15
1 2 8 7 2 4 11 15
输出样例1:
4 11
输入样例2:
7 14
1 8 7 2 4 11 15
输出样例2:
No Solution

在这里插入图片描述

详细题解

写法1 O ( n ) O(n) O(n)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>

using namespace std;

const int INF = 10000;

int main()
{
    int n, m;
    cin >> n >> m;
    unordered_set<int> hash;
    
    int v1 = INF, v2;
    for (int i = 0; i < n; ++ i )
    {
        int a, b;
        cin >> a;
        b = m - a;
        if (hash.count(b))
        {
            hash.insert(a);
            if (a > b) swap(a, b);
            if (a < v1) v1 = a, v2 = b;
        }
        else hash.insert(a);
    }
    
    if (v1 == INF) puts("No Solution");
    else cout << v1 << " " << v2 << endl;
    
    return 0;
}

毫无疑问,这是用空间换时间的做法,利用哈希表进行增删查改,时间复杂度都是 O ( 1 ) O(1) O(1)的,但是相应的空间复杂度都是 O ( n ) O(n) O(n)的。

最后提交,AC😁
在这里插入图片描述

推导证明

其实整体思路就是用哈希表去存储查询过但是没有满足条件的数字,然后每次遍历即可。
在这里插入图片描述
但是需要注意的是,我们这里查找的是符合条件的最小值,所以,a < b,并且用 v1 和 v2 来存储最终值。

写法2 O ( n l o g n ) O(nlogn) O(nlogn)

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100005;

int n, m;
int f[N];

int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; ++ i ) cin >> f[i];
    sort(f, f + n);
    
    for (int i = 0, j = n - 1; i < j; ++ i )
    {
        while (i < j && f[i] + f[j] > m) -- j;
        if (i < j && f[i] + f[j] == m)
        {
            cout << f[i] << " " << f[j] << endl;
            return 0;
        }
    }
    puts("No Solution");
    return 0;
}

毫无疑问,双指针可以用来优化哈希表的空间复杂度,但是一般情况下需要排序,所以是 O ( n l o g n ) O(nlogn) O(nlogn)

最后提交,AC😁
在这里插入图片描述

推导证明

双指针需要注意的问题是,排序,如果是乱序的话,没办法保证单调性。
在这里插入图片描述
具体的说,就是如果最小值和最大值符合条件,那么即为输出答案,如果不符合条件,那么需要向内侧移动,内侧一定有符合条件的结果。但是如果不是排序的话,内侧未必会符合条件,即无法找到符合条件的结果。

所以,遇事不决,先排序。

举一反三

掌握两种方法的互相优化,如果面试官需要更低的时间复杂度,那么可以使用空间复杂度去置换,如果面试官需要更低的空间复杂度,或者不需要额外的空间复杂度,那么使用双指针。

总结

继续努力,坚持更新,12th打卡。

阿离这个视频真的太美了,爱了爱了

【不夜盛世 扶摇九天】——公孙离惊鸿舞

我是管小亮 CSDN认证博客专家 TensorFlow PyTorch 图像处理
纸上得来终觉浅,绝知此事要躬行

包括但不局限于机器学习,深度学习,自然语言处理,计算机视觉,知识图谱,还有Python,C++,TensorFlow,Pytorch,Keras,PaddlePaddle等,不定时分享资源(电子书/项目/工具),学习路线,思考,面经等!!!
已标记关键词 清除标记
相关推荐