基础篇(2)

65 阅读4分钟

一、 明明的随机数

题目描述

明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N 个 1 到 1000 之间的随机整数 (N100)(N\leq100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。

输入格式

输入有两行,第 1 行为 1 个正整数,表示所生成的随机数的个数 N。

第 2 行有 N 个用空格隔开的正整数,为所产生的随机数。

输出格式

输出也是两行,第 1 行为 1 个正整数 M,表示不相同的随机数的个数。

第 2 行为 M 个用空格隔开的正整数,为从小到大排好序的不相同的随机数。

样例 #1

样例输入 #1

10
20 40 32 67 40 20 89 300 400 15

样例输出 #1

8
15 20 32 40 67 89 300 400

我的答案

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

void removeDuplicates(int arr[], int& n);//必须在main函数前声明

int main() {
    int N;
    cin >> N;
    int* num = new int[N]; // 动态分配内存,因为是动态数组,元素数目会改变
    for (int i = 0; i < N; i++) {
        cin >> num[i];
    }
    removeDuplicates(num, N); // 数组排序,去重
    cout << N << endl;
    for (int i = 0; i < N; i++) {
        cout << num[i] << ' ';
    }
    cout << endl;
    delete[] num; // 释放内存
    system("pause");
}

void removeDuplicates(int arr[], int& n) {  // 定义
    sort(arr, arr + n); // 对数组排序
    int j = 0;
    for (int i = 1; i < n; i++) {
        if (arr[i] != arr[j]) { // 如果当前元素和前一个元素不相等
            arr[++j] = arr[i];  // 把当前元素放到数组中
        }
    }
    n = j + 1; // 更新数组长度
}

其他方法

方法一(set容器)

使用 set 容器来实现去重和排序。set 自动会将元素从小到大排序,并保证集合中的元素不重复。需要注意的是,这里使用了范围 for 循环来遍历集合,需要使用 auto& 来对集合中的元素进行引用,否则会出现编译错误。

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

int main() {
    int N;
    cin >> N;
    set<int> s;
    for (int i = 0; i < N; i++) {
        int x;
        cin >> x;
        s.insert(x); // 插入元素x到集合s中
    }
    // 输出去重后的元素
    cout << s.size() << endl;
    for (auto& x : s) {
        cout << x << ' ';
    }
    cout << endl;
    return 0;
}

方法二、使用数组实现

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

int main() {
    int N;
    cin >> N;
    int a[N];
    for (int i = 0; i < N; i++) {
        cin >> a[i];
    }
    sort(a, a + N); // 对数组进行排序
    int n = unique(a, a + N) - a; // unique 函数返回不重复元素的末尾位置,我们使用指针偏移来计算不重复元素的个数
    // 输出去重后的元素
    cout << n << endl;
    for (int i = 0; i < n; i++) {
        cout << a[i] << ' ';
    }
    cout << endl;
    return 0;
}

需要注意的是,unique 函数会返回不重复元素的末尾位置,我们需要使用指针偏移来计算不重复元素的个数。例如,输入数组arr[]={1,2,4,4,5,6,6},返回数组arr[]={1,2,4,5,6}。缺点是只能去除相邻重复项,因此必须先对数组进行排序才能实现完全去重。

与方法一相比,方法二不需要额外空间去存储去重后的元素,但是需要对输入的数组进行排序,时间复杂度较高。

方法三:哈希表

使用 unordered_set 哈希表来实现去重。如果输入的元素不在哈希表中,我们将其插入到哈希表中,并将其插入到 vector 中。最后,我们对 vector 中的元素进行排序,并输出去重后的元素。使用哈希表的优点是插入和查找的时间复杂度较低,缺点是需要额外的空间来存储哈希表。

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

int main() {
    int N;
    cin >> N;
    unordered_set<int> s;
    vector<int> v;
    for (int i = 0; i < N; i++) {
        int x;
        cin >> x;
        if (s.find(x) == s.end()) { // 如果 x 不在哈希表中
            s.insert(x); // 插入元素到哈希表中
            v.push_back(x); // 插入元素到 vector 中
        }
    }
    sort(v.begin(), v.end()); // 对 vector 中的元素进行排序
    // 输出去重后的元素
    cout << v.size() << endl;
    for (auto& x : v) {
        cout << x << ' ';
    }
    cout << endl;
    return 0;
}

二、 质因数分解

题目描述

已知正整数 n 是两个不同的质数的乘积,试求出两者中较大的那个质数。

输入格式

输入一个正整数 n。

输出格式

输出一个正整数 p,即较大的那个质数。

样例 #1

样例输入 #1

21

样例输出 #1

7

提示

1n2×1091 \le n\le 2\times 10^9

我的答案

#include <iostream>
using namespace std;
int main()
{
    int n, f1, f2;
    cin >> n;
    for (int i = 2; i <= n / 2; i++)
    {
        if (n % i == 0)
        {
            f2 = n / i;
            break;
        }
    }
    cout << f2;
    return 0;
}

其实这里有个隐藏条件:正整数 n 是两个不同的质数的乘积,所以求出来的因子必定是质数。如果真要考虑因子是否为质数,方法如下:

#include <iostream>
using namespace std;

bool is_prime(int x) // 判断一个数是否为质数
{
    if (x < 2)
        return false;
    for (int i = 2; i * i < x; i++)
    {
        if (x % i == 0)
        {
            return false;
        }
    }
    return true;
}
int main()
{
    int n;
    cin >> n;
    int factor;
    for (int i = 2; i*i<=n; i++)
    {
        if (is_prime(i) && n % i == 0)
        {
            factor = n / i;
            break;
        }
    }
    cout<<factor;
    return 0;
}

当n较大时,程序的运行时间会比较长。我们可以进一步优化时间复杂度。注意到n是两个质数的乘积,因此其中一个质数一定不超过 n\sqrt{n},我们只需要从 n\sqrt{n}开始往下遍历即可,这样可以减小时间复杂度。

 for (int i = n / 2; i >= 2; i--) {
        if (n % i == 0 && is_prime(i)) 
         {
            factor = n/i;
            break;
         }
     }

三、 不高兴的津津

题目描述

津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不会因为其它事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查一下津津下周的日程安排,看看下周她会不会不高兴;如果会的话,哪天最不高兴。

输入格式

输入包括 7 行数据,分别表示周一到周日的日程安排。每行包括两个小于 10 的非负整数,用空格隔开,分别表示津津在学校上课的时间和妈妈安排她上课的时间。

输出格式

一个数字。如果不会不高兴则输出 0,如果会则输出最不高兴的是周几(用 1, 2, 3, 4, 5, 6, 7 分别表示周一,周二,周三,周四,周五,周六,周日)。如果有两天或两天以上不高兴的程度相当,则输出时间最靠前的一天。

样例 #1

样例输入 #1

5 3
6 2
7 2
5 3
5 4
0 4
0 6

样例输出 #1

3

我的答案

#include <iostream>
using namespace std;

int main()
{
    int a[7], b[7], c[7], n;
    for (int i = 0; i < 7; i++)
    {
        cin >> a[i] >> b[i];
        c[i] = a[i] + b[i];
    }
    int max = c[0];
    for (int i = 1; i < 7; i++)
    {
        if (max < c[i])
        {
            max = c[i];
            n = i + 1; // 易错
        }
    }
    cout << n;
    return 0;
}