HJ3.明明的随机数
解法一(偷懒解法):
#include <iostream>
#include <string>
#include <set>
int main(int argc, const char * argv[]) {
int n, num;
std::set<int> nums;
while (std::cin >> n) {
while (n--) {
std::cin >> num;
nums.insert(num);
}
for (auto& i : nums) {
std::cout << i << std::endl;
}
nums.clear();
}
return 0;
}
解法二:
#include <iostream>
#include <string>
#include <vector>
void swap(std::vector<int>& nums, int a, int b) {
int sz = (int)nums.size();
if (a != b && (a > 0 && a < sz) && (b > 0 && b < sz)) {
int t = nums[a];
nums[a] = nums[b];
nums[b] = t;
}
}
void deal_pivot(std::vector<int>& nums, int l, int r) {
if (l < r) {
int m = (l + r) / 2;
if (nums[l] > nums[m]) {
swap(nums, l, m);
}
if (nums[l] > nums[r]) {
swap(nums, l, r);
}
if (nums[r] < nums[m]) {
swap(nums, r, m);
}
swap(nums, m, l);
}
}
int part(std::vector<int>& nums, int l, int r) {
int pivot = nums[l];
while (l < r) {
while (l < r && nums[r] >= pivot) {
--r;
}
nums[l] = nums[r];
while (l < r && nums[l] <= pivot) {
++l;
}
nums[r] = nums[l];
}
nums[l] = pivot;
return l;
}
void quick_sort(std::vector<int>& nums, int l, int r) {
if (l < r) {
int pivot = part(nums, l, r);
quick_sort(nums, l, pivot - 1);
quick_sort(nums, pivot + 1, r);
}
}
void make_uniq(std::vector<int>& nums) {
quick_sort(nums, 0, (int)nums.size() - 1);
for (int i = 1; i < nums.size(); ++i) {
if (nums[i - 1] == nums[i]) {
nums.erase(nums.begin() + i);
--i;
}
}
}
int main(int argc, const char * argv[]) {
int n, num;
std::vector<int> nums;
while (std::cin >> n) {
while (n--) {
std::cin >> num;
nums.emplace_back(num);
}
make_uniq(nums);
for (auto& i : nums) {
std::cout << i << std::endl;
}
nums.clear();
}
return 0;
}
解题思路:
难点1:如果在允许使用库的情况下,重点在于能不能想到利用set排序去重;
难点2:这道题被标记为了较难,使用set库的话就失去了题目本身的意义,更多地,题目在考察答题者能否手撕排序算法。这里使用的快排算法,也是最常被问到的。deal_pivot只是对枢轴值的一个中位数优化,可以不用关注,唯一需要记忆的就quick_sort算法本身的递归结构和最核心的part函数。,quick_sort函数体本身不用记忆,理解后自然就记住了,part函数就那么几行,没啥好办法,理解了之后背就完事;
int part(std::vector<int>& nums, int l, int r) {
int pivot = nums[l];
while (l < r) {
while (l < r && nums[r] >= pivot) {
--r;
}
nums[l] = nums[r];
while (l < r && nums[l] <= pivot) {
++l;
}
nums[r] = nums[l];
}
nums[l] = pivot;
return l;
}
void quick_sort(std::vector<int>& nums, int l, int r) {
if (l < r) {
int pivot = part(nums, l, r);
quick_sort(nums, l, pivot - 1);
quick_sort(nums, pivot + 1, r);
}
}
难点3:set的使用,很久不用会忘记方法;
知识点:
知识点1:unordered_set与set的区别;
unordered_set基于哈希表,是无序的。
set实现了红黑树的平衡二叉检索树的数据结构,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值;另外,还得保证根节点左子树的高度与右子树高度相等。
知识点2:set与vector的转换;
#include <set>
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> vec;
vec = { 1, 2, 3, 4, 8, 9, 3, 2, 1, 0, 4, 8 };
set<int> st(vec.begin(), vec.end());
vec.assign(st.begin(), st.end());
for (auto& i : vec) {
cout << i << endl;
}
return 0;
}
知识点3:快排是一种不稳定的排序算法;核心思想是通过与枢轴值的比较,将比枢轴值小的放在左侧,大的放在右侧,以此二分下去。