C++ 标准库 - 容器和算法

STL 容器

目录 分类 序列式容器 关联式容器 无序(关联式)容器 容器适配器 共同点 容器声明 迭代器 共有函数

分类

序列式容器

  • 向量 (vector) 后端可高效增加元素的顺序表。
  • 数组 (array)C++11,定长的顺序表,C 风格数组的简单包装。
  • 双端队列 (deque) 双端都可高效增加元素的顺序表。
  • 列表 (list) 可以沿双向遍历的链表。
  • 单向列表 (forward_list) 只能沿一个方向遍历的链表。

关联式容器

  • 集合 (set) 用以有序地存储 互异 元素的容器。其实现是由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种比较元素大小的谓词进行排列。
  • 多重集合 (multiset) 用以有序地存储元素的容器。允许存在相等的元素。
  • 映射 (map) 由 {键,值} 对组成的集合,以某种比较键大小关系的谓词进行排列。
  • 多重映射 (multimap) 由 {键,值} 对组成的多重集合,亦即允许键有相等情况的映射。

什么是谓词 (Predicate)?

谓词就是返回值为真或者假的函数。STL 容器中经常会使用到谓词,用于模板参数。

无序(关联式)容器

  • 无序(多重)集合 (unordered_set/unordered_multiset)C++11 ,与 set/multiset 的区别在于元素无序,只关心「元素是否存在」,使用哈希实现。
  • 无序(多重)映射 (unordered_map/unordered_multimap)C++11 ,与 map/multimap 的区别在于键 (key) 无序,只关心 "键与值的对应关系",使用哈希实现。

容器适配器

容器适配器其实并不是容器。它们不具有容器的某些特点(如:有迭代器、有 clear() 函数......)。

「适配器是使一种事物的行为类似于另外一种事物行为的一种机制」,适配器对容器进行包装,使其表现出另外一种行为。

  • (stack) 后进先出 (LIFO) 的容器,默认是对双端队列(deque)的包装。
  • 队列 (queue) 先进先出 (FIFO) 的容器,默认是对双端队列(deque)的包装。
  • 优先队列 (priority_queue) 元素的次序是由作用于所存储的值对上的某种谓词决定的的一种队列,默认是对向量(vector)的包装。

共同点

容器声明

都是 containerName<typeName,...> name 的形式,但模板参数(<> 内的参数)的个数、形式会根据具体容器而变。

本质原因:STL 就是「标准模板库」,所以容器都是模板类。

迭代器

请参考 迭代器

共有函数

=:有赋值运算符以及复制构造函数。

begin():返回指向开头元素的迭代器。

end():返回指向末尾的下一个元素的迭代器。end() 不指向某个元素,但它是末尾元素的后继。

size():返回容器内的元素个数。

max_size():返回容器 理论上 能存储的最大元素个数。依容器类型和所存储变量的类型而变。

empty():返回容器是否为空。

swap():交换两个容器。

clear():清空容器。

==/!=/</>/<=/>=:按 字典序 比较两个容器的大小。(比较元素大小时 map 的每个元素相当于 set<pair<key, value> >,无序容器不支持 </>/<=/>=。)

STL 算法

STL 提供了大约 100 个实现算法的模版函数,基本都包含在 <algorithm> 之中,还有一部分包含在 <numeric><functional>。完备的函数列表请 参见参考手册,排序相关的可以参考 排序内容的对应页面

  • find:顺序查找。find(v.begin(), v.end(), value),其中 value 为需要查找的值。

  • reverse:翻转数组、字符串。reverse(v.begin(), v.end())reverse(a + begin, a + end)

  • unique:去除容器中相邻的重复元素。unique(ForwardIterator first, ForwardIterator last),返回值为指向 去重后 容器结尾的迭代器,原容器大小不变。与 sort 结合使用可以实现完整容器去重。

    C++ STL中 unique() 函数(详解)

  • random_shuffle:随机地打乱数组。random_shuffle(v.begin(), v.end())random_shuffle(v + begin, v + end)

  • sort:排序。sort(v.begin(), v.end(), cmp)sort(a + begin, a + end, cmp),其中 end 是排序的数组最后一个元素的后一位,cmp 为自定义的比较函数。

  • stable_sort:稳定排序,用法同 sort()

  • nth_element:按指定范围进行分类,即找出序列中第 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 大的元素,使其左边均为小于它的数,右边均为大于它的数。nth_element(v.begin(), v.begin() + mid, v.end(), cmp)nth_element(a + begin, a + begin + mid, a + end, cmp)

  • binary_search:二分查找。binary_search(v.begin(), v.end(), value),其中 value 为需要查找的值。

    binary_search函数默认期望的是一个以非降序(即升序或等值)排列的范围。 如果你希望在一个降序排列的容器中查找元素,你需要提供与你的排序准则相匹配的比较函数给binary_search。这样,binary_search才能正确地在降序排列的vector中查找元素。对于你的代码,你可以这样做:

    cpp 复制代码
    bool m = binary_search(vi.begin(), vi.end(), 5, greater<int>());

    通过添加greater<int>()作为binary_search的第四个参数,你就为搜索提供了正确的比较准则,使其能够在降序排列的vector中正确工作。这样,如果vector中包含元素5binary_search就会返回true(即1),而不是0

    cpp 复制代码
    #include <bits/stdc++.h>
    
    using namespace std;
    
    int main() {
    	vector<int> vi;
    	int n = 10;
    	for(int i = 1; i - 1 < n; i ++) {
    		vi.push_back(i);
    	}
    	random_shuffle(vi.begin(), vi.end());
    
    	sort(vi.begin(), vi.end(), greater<int>());
    	
    	for(auto v : vi) {
    		printf("%d ", v);
    	}
    
    	cout << '\n';
    
    	bool m = binary_search(vi.begin(), vi.end(), 5, greater<int>());
    
    	cout << "\nm = " << m;
    	return 0;
    }
    markdown 复制代码
    10 9 8 7 6 5 4 3 2 1
    
    m = 1
    --------------------------------
    Process exited after 0.01305 seconds with return value 0
  • merge:将两个(已排序的)序列 有序合并 到第三个序列的 插入迭代器 上。merge(v1.begin(), v1.end(), v2.begin(), v2.end() ,back_inserter(v3))

  • inplace_merge:将两个(已按小于运算符排序的):[first,middle), [middle,last) 范围 原地合并为一个有序序列inplace_merge(v.begin(), v.begin() + middle, v.end())

  • lower_bound:在一个有序序列中进行二分查找,返回指向第一个 大于等于 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x 的元素的位置的迭代器。如果不存在这样的元素,则返回尾迭代器。lower_bound(v.begin(),v.end(),x)

  • upper_bound:在一个有序序列中进行二分查找,返回指向第一个 大于 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x 的元素的位置的迭代器。如果不存在这样的元素,则返回尾迭代器。upper_bound(v.begin(),v.end(),x)

cpp 复制代码
// 升序数组中:
upper_bound(a.begin(), a.end(), x); // 查找第一个 > x的元素
lower_bound(a.begin(), a.end(), x); // 查找第一个 >= x的元素
// 降序数组中:
upper_bound(a.begin(), a.end(), x, greater<type>()); // 查找第一个 < x的元素
lower_bound(a.begin(), a.end(), x, greater<type>()); // 查找第一个 <= x的元素

lower_boundupper_bound 的时间复杂度

在一般的数组里,这两个函数的时间复杂度均为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( l o g n ) O(log n) </math>O(logn),但在 set 等关联式容器中,直接调用 lower_bound(s.begin(),s.end(),val) 的时间复杂度是 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n) 的。

set 等关联式容器中已经封装了 lower_bound 等函数(像 s.lower_bound(val) 这样),这样调用的时间复杂度是 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( l o g n ) O(log n) </math>O(logn) 的。

  • next_permutation:将当前排列更改为 全排列中的下一个排列 。如果当前排列已经是 全排列中的最后一个排列 (元素完全从大到小排列),函数返回 false 并将排列更改为 全排列中的第一个排列 (元素完全从小到大排列);否则,函数返回 truenext_permutation(v.begin(), v.end())next_permutation(v + begin, v + end)
  • prev_permutation:将当前排列更改为 全排列中的上一个排列 。用法同 next_permutation
  • partial_sum:求前缀和。设源容器为 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x,目标容器为 <math xmlns="http://www.w3.org/1998/Math/MathML"> y y </math>y,则令 <math xmlns="http://www.w3.org/1998/Math/MathML"> y [ i ] = x [ 0 ] + x [ 1 ] + ⋯ + x [ i ] y[i]=x[0]+x[1]+\dots+x[i] </math>y[i]=x[0]+x[1]+⋯+x[i]。partial_sum(src.begin(), src.end(), back_inserter(dst))

使用样例

全排列next_permutation

  • 使用 next_permutation 生成 1 到 9 的全排列。例题:Luogu P1706 全排列问题

    c 复制代码
    int N = 9, a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    do {
      for (int i = 0; i < N; i++) cout << a[i] << " ";
      cout << endl;
    } while (next_permutation(a, a + N));

全排列问题

题目描述

按照字典序输出自然数 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 </math>1 到 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 所有不重复的排列,即 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n。

输出格式

由 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 ∼ n 1 \sim n </math>1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 <math xmlns="http://www.w3.org/1998/Math/MathML"> 5 5 </math>5 个场宽。

样例输入 #1

3

样例输出 #1

markdown 复制代码
    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1

提示

<math xmlns="http://www.w3.org/1998/Math/MathML"> 1 ≤ n ≤ 9 1 \leq n \leq 9 </math>1≤n≤9。

题解
cpp 复制代码
#include <stdio.h>
#include <algorithm>

using namespace std;

int main() {
	int n;
	scanf("%d", &n);

	int a[n];

	for(int i = 1; i <= n; ++i) {
		a[i-1] = i;
	}
	do {
		for (int i = 0; i < n; ++i) {
            printf("%5d", a[i]); // 固定5个场宽
//			printf("    %d", a[i]); // 或者4个空格
		}
		printf("\n");
	} while(next_permutation(a, a + n));

	return 0;
}

二分查找lower_boundupper_bound

  • 使用 lower_boundupper_bound 查找有序数组 <math xmlns="http://www.w3.org/1998/Math/MathML"> a a </math>a 中小于 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x,等于 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x,大于 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x 元素的分界线。
cpp 复制代码
int N = 10, a[] = {1, 1, 2, 4, 5, 5, 7, 7, 9, 9}, x = 5;
int i = lower_bound(a, a + N, x) - a, j = upper_bound(a, a + N, x) - a;
// 通过返回的地址减去起始地址,得到找到数字在数组中的下标。
// a[0] ~ a[i - 1] 为小于x的元素, a[i] ~ a[j - 1] 为等于x的元素,
// a[j] ~ a[N - 1] 为大于x的元素
cout << i << " " << j << endl;//4 6
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
	int x = 5;
	vector<int> a{1, 1, 2, 4, 5, 5, 7, 7, 9, 9};
	auto begin = a.begin();
	auto end = a.end();
	// 通过返回的地址减去起始地址begin, 得到找到数字在数组中的下标。
	int i = lower_bound(begin, end, 5) - begin, j = upper_bound(begin, end, 5) - begin;
	cout << i << " " << j << endl;//4 6
	
	return 0;
}

前缀和 partial_sum

  • 使用 partial_sum 求解 <math xmlns="http://www.w3.org/1998/Math/MathML"> s r c src </math>src 中元素的前缀和,并存储于 <math xmlns="http://www.w3.org/1998/Math/MathML"> d s t dst </math>dst 中。
cpp 复制代码
vector<int> src = {1, 2, 3, 4, 5}, dst;
// 求解src中元素的前缀和,dst[i] = src[0] + ... + src[i]
// back_inserter 函数作用在 dst 容器上,提供一个迭代器
partial_sum(src.begin(), src.end(), back_inserter(dst));
for (unsigned int i = 0; i < dst.size(); i++) cout << dst[i] << " "; //1 3 6 10 15

C++ STL back_inserter 函数说明

back_inserter用于在末尾插入元素。 实现方法是构造一个迭代器,这个迭代器可以在容器末尾添加元素。 这个迭代器是以安插(insert)方式而非覆写(overwrite)方式运作的。

可以使用back_inserter的容器是有push_back成员函数的容器,比如vector, deque and list

lower_bound查找有序数组 a 中最接近 x 的元素

  • 使用 lower_bound 查找有序数组 <math xmlns="http://www.w3.org/1998/Math/MathML"> a a </math>a 中最接近 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x 的元素。例题:UVa10487 Closest Sums
cpp 复制代码
int N = 10, a[] = {1, 1, 2, 4, 5, 5, 8, 8, 9, 9}, x = 6;
// lower_bound将返回a中第一个大于等于x的元素的地址,计算出的i为其下标
int i = lower_bound(a, a + N, x) - a;
// 在以下两种情况下,a[i] (a中第一个大于等于x的元素) 即为答案:
// 1. a中最小的元素都大于等于x;
// 2. a中存在大于等于x的元素,且第一个大于等于x的元素 (a[i])
// 相比于第一个小于x的元素 (a[i - 1]) 更接近x;
// 否则,a[i - 1] (a中第一个小于x的元素) 即为答案
if (i == 0 || (i < N && a[i] - x < x - a[i - 1]))
  cout << a[i];
else
  cout << a[i - 1];

Closest Sums

题目描述

Given is a set of integers and then a sequence of queries. A query gives you a number and asks to find a sum of two distinct numbers from the set, which is closest to the query number.

给出的是一组整数,然后是一系列查询。查询给出一个数字,要求从整数集合中找出最接近查询数字的两个不同数字之和。

输入格式

Input contains multiple cases. Each case starts with an integer n (1 < n ≤ 1000), which indicates, how many numbers are in the set of integer. Next n lines contain n numbers. Of course there is only one number in a single line. The next line contains a positive integer m giving the number of queries, 0 < m < 25. The next m lines contain an integer of the query, one per line. Input is terminated by a case whose n = 0. Surely, this case needs no processing.

输入包含多个案例。每个案例以一个整数 n(1 < n ≤ 1000)开始,表示整数集合中有多少个数字。接下来的 n 行包含 n 个数字。当然,一行中只有一个数字。下一行包含一个正整数 m,表示查询次数,0 < m < 25。接下来的 m 行包含查询的整数,每行一个。输入以 n = 0 的情况结束。当然,这种情况无需处理。

输出格式

Output should be organized as in the sample below. For each query output one line giving the query value and the closest sum in the format as in the sample. Inputs will be such that no ties will occur.

输出应按以下示例组织。对于每个查询,按样本中的格式输出一行,给出查询值和最接近的总和。输入时不得出现并列。

样例输入 #1

5
3
12
17
33
34
3
1
51
30
3
1
2
3
3
1
2
3
3
1
2
3
3
4
5
6
0

样例输出 #1

vbnet 复制代码
Case 1:
Closest sum to 1 is 15.
Closest sum to 51 is 51.
Closest sum to 30 is 29.
Case 2:
Closest sum to 1 is 3.
Closest sum to 2 is 3.
Closest sum to 3 is 3.
Case 3:
Closest sum to 4 is 4.
Closest sum to 5 is 5.
Closest sum to 6 is 5.

题目分析

题目要求对于给定的一组整数集合,回答一系列的查询。每一次查询包含一个数字,需要找到集合中两个不同数字之和,该和最接近查询的数字。

输入格式规定了如何提供整数集合和查询,首先是集合中整数的数量n,接着是n个整数,一个整数一行。然后是查询数量m,随后是m个查询数字,每个查询一行。当输入的n为0时,表示输入结束。

输出格式要求对每个查询输出一行,给出查询值和最接近的和,格式见样例输出。

在给出的C++代码示例中,lower_bound 函数用于找到数组a中第一个大于或等于查询值x的元素的位置。找到这个位置后的步骤是判断这个元素是否就是我们要的答案。如果数组中最小的元素值已经大于或等于x,或者这个元素与x的差值小于它前一个元素与x的差值,那么这个元素就是答案。否则,就选择前一个元素。

根据这段代码示例,题目的解答应该是创建一个存储整数集合的数组,对于每个查询,使用lower_bound找到最接近的大于或等于查询值的元素,并按上述规则选择最接近的和的两个数。然后按照要求的格式输出。

注意,这段代码仅处理一个查询而非多个查询,并且假定数组a已经按非递减顺序排列。在实际问题中,需要处理多个查询,并且可能需要先对集合进行排序。此外,需要两重循环来找出所有可能的两数之和,然后使用类似于上述逻辑来找出最接近的和。

题解
cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <limits>

using namespace std;

int main() {
  int n, m, caseNumber = 0;
  while (cin >> n && n) {
    // 存储整数集合
    vector<int> numbers(n);
    for (int i = 0; i < n; ++i) {
      cin >> numbers[i];
    }
    // 对整数集合排序,以便使用lower_bound
    sort(numbers.begin(), numbers.end());

    // 存储所有可能的两数之和
    vector<int> sums;
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        sums.push_back(numbers[i] + numbers[j]);
      }
    }

    // 解决重复和的问题
    sort(sums.begin(), sums.end());
    sums.erase(unique(sums.begin(), sums.end()), sums.end());
//    cout << "---\n";
//    for(auto s : sums) {
//    	cout << s << " ";
//	}
//	cout << "\n---\n";

    // 开始处理查询
    cin >> m;
    cout << "Case " << ++caseNumber << ":" << endl;
    while (m--) {
      int query;
      cin >> query;
      // 找到大于等于query的第一个和的位置
      auto it = lower_bound(sums.begin(), sums.end(), query);
      int sum = *it;
      // 寻找最接近的和
      if (it != sums.begin() && (it == sums.end() || query - *(it - 1) <= *it - query)) {
        sum = *(it - 1);
      }

      cout << "Closest sum to " << query << " is " << sum << "." << endl;
    }
  }
  return 0;
}

我的代码接受按照输入格式规定的整数集合和查询序列,对每个查询找到最接近的两数之和,并按照要求输出结果。

首先使用一个循环读取每一个案例,直到遇到一个整数集合大小为0的情况,表示输入结束。对于每个案例,它遵循以下步骤:

  1. 读取整数集合 :首先,它读取一个整数n,表示集合中的整数数量。然后,使用一个for循环读取这些整数,并将它们存储在vector<int> numbers中。

  2. 排序整数集合 :使用sort(numbers.begin(), numbers.end())对整数集合进行排序,这是为了后续能够有效地使用lower_bound函数来寻找接近查询值的和。

  3. 计算所有可能的两数之和 :通过两层嵌套的for循环遍历排序后的整数集合,计算所有可能的两个不同数的和,并将这些和存储在另一个向量vector<int> sums中。这一步骤是解决问题的关键,因为我们需要从这些和中找到最接近查询值的和。

  4. 处理两数之和的重复值 :由于可能存在重复的和,我们使用sort(sums.begin(), sums.end())对和进行排序,然后使用uniqueerase方法去除重复的和。这样做既可以减少后续查找的工作量,也确保我们能够正确地找到最接近的和。

  5. 处理查询 :读取查询数量m,然后对于每个查询,使用lower_bound在已排序的和中寻找第一个大于等于查询值的和。lower_bound返回的是一个迭代器,指向找到的元素。

  6. 寻找最接近的和 :一旦找到大于等于查询值的和,代码会检查它是不是最接近的。如果存在一个更小的和(即lower_bound返回的迭代器不指向sums的开始),并且这个更小的和与查询值的差距比当前找到的和更小,那么选择这个更小的和作为答案。

  7. 输出结果:对于每个查询,根据格式要求输出查询值和最接近的和。

整个实现的核心在于先计算出所有可能的两数之和,然后对于每个查询值,高效地找到最接近的和。这种方法利用了排序和二分查找算法,以实现较快的查找速度。

使用 sortunique 查找数组 <math xmlns="http://www.w3.org/1998/Math/MathML"> a a </math>a 中 第 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 小的值

  • 使用 sortunique 查找数组 <math xmlns="http://www.w3.org/1998/Math/MathML"> a a </math>a 中 第 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 小的值 (注意:重复出现的值仅算一次,因此本题不是求解第 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 小的元素)。例题:Luogu P1138 第 k 小整数
cpp 复制代码
int N = 10, a[] = {1, 3, 3, 7, 2, 5, 1, 2, 4, 6}, k = 3;
sort(a, a + N);
// unique将返回去重之后数组最后一个元素之后的地址,计算出的cnt为去重后数组的长度
int cnt = unique(a, a + N) - a;
cout << a[k - 1];

第 k 小整数

题目描述

现有 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 个正整数,要求出这 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 个正整数中的第 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 个最小整数(相同大小的整数只计算一次)。

输入格式

第一行为 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k; 第二行开始为 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 个正整数的值,整数间用空格隔开。

输出格式

第 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k个最小整数的值;若无解,则输出 NO RESULT

样例输入 #1

10 3
1 3 3 7 2 5 1 2 4 6

样例输出 #1

3

提示

<math xmlns="http://www.w3.org/1998/Math/MathML"> n ≤ 10000 n \leq 10000 </math>n≤10000, <math xmlns="http://www.w3.org/1998/Math/MathML"> k ≤ 1000 k \leq 1000 </math>k≤1000,正整数均小于 <math xmlns="http://www.w3.org/1998/Math/MathML"> 30000 30000 </math>30000。

题解

Unaccepted

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
	int n, k;
	
	while(cin >> n >> k) {
		vector<int> nums;
		for(size_t i = 0; i < n; ++i) {
			int x;
			cin >> x;
			nums.push_back(x);
		}
		sort(nums.begin(), nums.end());
		int cnt = unique(nums.begin(), nums.end()) - nums.begin();
		cout << nums[k - 1] << '\n';
	}
    return 0;
}

你的代码中有一个常见的错误。unique 函数实际上并不直接删除重复的元素,而是将不重复的元素移到容器的开始部分,并返回新的不重复序列的结束迭代器。因此,如果你在调用 unique 后没有使用返回的迭代器来实际删除那些多余的元素,你的容器 nums 仍然包含所有原始元素,包括重复的,它们只是被移到了容器的末尾。

要修复这个问题,你需要在调用 unique 后,使用 erase 方法来删除从新序列的结束迭代器到 nums.end() 的所有元素。此外,在输出第 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 小的数之前,你需要检查 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 是否大于不重复元素的数量 cnt。如果大于,应输出 NO RESULT

这里是修正后的代码段:

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int n, k;
    
    while(cin >> n >> k) {
        vector<int> nums;
        for(int i = 0; i < n; ++i) {
            int x;
            cin >> x;
            nums.push_back(x);
        }
        sort(nums.begin(), nums.end());
        auto it = unique(nums.begin(), nums.end());
        nums.erase(it, nums.end()); // 删除重复的元素
        if(k > nums.size()) { // 检查k是否大于不重复元素的数量
            cout << "NO RESULT\n";
        } else {
            cout << nums[k - 1] << '\n';
        }
    }
    return 0;
}

这段代码首先将 nums 数组排序,然后去除重复的元素,并且只在 k 不大于去重后的数组大小时才输出第 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 小的数,否则输出 NO RESULT

相关推荐
ZZZ_O^O17 分钟前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
CV-King40 分钟前
opencv实战项目(三十):使用傅里叶变换进行图像边缘检测
人工智能·opencv·算法·计算机视觉
代码雕刻家1 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
雨中rain1 小时前
算法 | 位运算(哈希思想)
算法
Kalika0-03 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
sp_fyf_20243 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02
人工智能·神经网络·算法·计算机视觉·语言模型·自然语言处理·数据挖掘
我是哈哈hh5 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
Tisfy5 小时前
LeetCode 2187.完成旅途的最少时间:二分查找
算法·leetcode·二分查找·题解·二分
Mephisto.java5 小时前
【力扣 | SQL题 | 每日四题】力扣2082, 2084, 2072, 2112, 180
sql·算法·leetcode
robin_suli5 小时前
滑动窗口->dd爱框框
算法