数组元素排序
【问题描述】
给定n个元素,设计算法实现从小到大排序
【输入形式】
第一行元素个数n,第二行输入n个元素。
【输出形式】
按小到大排好序的元素
【样例输入】
3
15 12 20
【样例输出】
12 15 20
【参考代码】
#include <iostream>
#include <vector>
using namespace std;
// 二分查找应该插入的位置
int binarySearch(const vector<int>& arr, int item, int low, int high) {
while (low <= high) {
int mid = low + (high - low) / 2;
if (item == arr[mid]) {
return mid;
} else if (item < arr[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return low;
}
// 二分查找插入排序
void binaryInsertionSort(vector<int>& arr) {
int n = arr.size();
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
// 使用二分查找找到应该插入的位置
int loc = binarySearch(arr, key, 0, j);
// 将元素后移,为插入元素腾出空间
while (j >= loc) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
int main() {
int n;
cin >> n; // 读取元素个数
vector<int> arr(n);
for (int i = 0; i < n; ++i) {
cin >> arr[i]; // 读取元素值
}
binaryInsertionSort(arr); // 对数组进行排序
// 输出排序后的数组
for (int i = 0; i < n; ++i) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
//From:TengMMVP
双色汉诺塔
【问题描述】
设 A、B、C 是 3 个塔座。开始时,在塔座 A 上有一叠共 n 个圆盘,这些圆盘自下而上, 由大到小地叠在一起。各圆盘从小到大编号为 1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座 A 上的这一叠圆盘移到塔座 B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:
规则(1):每次只能移动 1 个圆盘;
规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):任何时刻都不允许将同色圆盘叠在一起;
规则(4):在满足移动规则(1)-(3)的前提下,可将圆盘移至 A,B,C 中任一塔座上。
【输入形式】
输入圆盘个数n
【输出形式】
每一行由一个正整数 k 和 2 个 字符 c1 和 c2 组成,表示将第 k 个圆盘从塔座 c1 移到塔座 c2 上
【样例输入】
3
【样例输出】
1 A B
2 A C
1 B C
3 A B
1 C A
2 C B
1 A B
【参考代码】
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
// 检查颜色是否相同
bool isSameColor(int n) {
return n % 2 == 0; // 偶数为红色,奇数为蓝色
}
// 移动圆盘
void moveDisc(int n, char from, char to, char aux, stack<int>& fromStack, stack<int>& toStack) {
cout << n << " " << from << " " << to << endl;
toStack.push(fromStack.top());
fromStack.pop();
}
// 实现汉诺塔移动逻辑,考虑颜色限制
void hanoi(int n, char from, char to, char aux, stack<int>& fromStack, stack<int>& toStack, stack<int>& auxStack) {
if (n == 1) {
moveDisc(n, from, to, aux, fromStack, toStack);
return;
}
hanoi(n - 1, from, aux, to, fromStack, auxStack, toStack);
moveDisc(n, from, to, aux, fromStack, toStack);
hanoi(n - 1, aux, to, from, auxStack, toStack, fromStack);
}
int main() {
// 输入圆盘个数n
int n;
cin >> n;
// 定义A、B、C三个栈
stack<int> A, B, C;
// 初始化A塔
for (int i = n; i > 0; --i) {
A.push(i);
}
hanoi(n, 'A', 'B', 'C', A, B, C);
return 0;
}
//From:TengMMVP
众数问题
【问题描述】
给定含有S个元素的多重集合S(元素未排序),每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为众数。例如,S={2,1,2,3,2,5}。多重数S的众数是2,其重数为3 。对于给定的由n个自然数组成的多重集S,计算S的众数及其重数。
【输入形式】
第1行为多重数集S中元素个数n;接下来的n行中,每行有一个自然数。
【输出形式】
输出文件有2行,第1行是众数,第2行是重数。
【样例输入】
6
2
1
2
3
2
5
【样例输出】
2
3
【参考代码】
#include <iostream>
#include <vector>
using namespace std;
// 计算指定数在数组中的重数
int countInRange(const vector<int>& nums, int num, int start, int end) {
int count = 0;
for (int i = start; i <= end; i++) {
if (nums[i] == num) count++;
}
return count;
}
// 递归函数,实际执行分治策略
pair<int, int> majorityElementRec(const vector<int>& nums, int start, int end) {
// 基本情况:数组只有一个元素
if (start == end) {
return {nums[start], 1};
}
int mid = (start + end) / 2;
auto left = majorityElementRec(nums, start, mid);
auto right = majorityElementRec(nums, mid + 1, end);
// 如果两边的众数相同,直接返回
if (left.first == right.first) {
return {left.first, left.second + right.second};
}
// 计算左右众数在整个区间的重数
int leftCount = countInRange(nums, left.first, start, end);
int rightCount = countInRange(nums, right.first, start, end);
// 返回重数较大的众数及其重数
return leftCount > rightCount ? make_pair(left.first, leftCount) : make_pair(right.first, rightCount);
}
int main() {
int n;
cin >> n;
vector<int> nums(n);
for (int i = 0; i < n; ++i) {
cin >> nums[i];
}
auto result = majorityElementRec(nums, 0, nums.size() - 1);
cout << result.first << "\n" << result.second << endl;
return 0;
}
//From:TengMMVP
逆序对计数
【问题描述】
对于给定的数组A,计算其逆序对的总数。即:
【输入形式】
输入包含1组测试用例。
一个测试用例占一行,第一个整数表示数组的长度,后面紧跟者数组中的各个整数元素,中间都用一个空格分开。
数组的长度
范围
每个数字A[i]的范围为
【输出形式】
输出一个整数,表示逆序对的个数。
【样例输入】
5 1 2 3 5 4
【样例输出】
1
【参考代码】
#include <iostream>
#include <vector>
using namespace std;
int merge(vector<int> &arr, int left, int mid, int right) {
int i = left;
int j = mid + 1;
int k = 0;
int inv_count = 0;
vector<int> temp(right - left + 1);
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
inv_count += (mid - i + 1); // 左边剩下的都是逆序对
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
for (i = left, k = 0; i <= right; ++i, ++k) {
arr[i] = temp[k];
}
return inv_count;
}
int mergeSort(vector<int> &arr, int left, int right) {
int inv_count = 0;
if (left < right) {
int mid = left + (right - left) / 2;
inv_count += mergeSort(arr, left, mid);
inv_count += mergeSort(arr, mid + 1, right);
inv_count += merge(arr, left, mid, right);
}
return inv_count;
}
int main() {
int n;
cin >> n;
vector<int> arr(n);
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
int inv_count = mergeSort(arr, 0, n - 1);
cout << inv_count << endl;
return 0;
}
//From:TengMMVP
快速排序练习
【问题描述】
给定n个元素,快速排序算法实现从小到大排序
【输入形式】
第一行输入元素个数n,第二行输入n个元素
【输出形式】
按小到大排好序的元素
【样例输入】
3
15 12 20
【样例输出】
12 15 20
【参考代码】
#include <iostream>
#include <vector>
using namespace std;
// 快速排序的分区函数
int partition(vector<int>& arr, int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为基准
int i = (low - 1); // 小于pivot的元素的索引
for (int j = low; j <= high- 1; j++) {
// 如果当前元素小于或等于pivot
if (arr[j] <= pivot) {
i++; // 增加小于pivot的元素的索引
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}
// 快速排序函数
void quickSort(vector<int>& arr, int low, int high) {
if (low < high) {
// pi是分区后的索引, arr[pi]现在放在正确的位置
int pi = partition(arr, low, high);
// 分别对分区前后的子数组进行排序
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
int main() {
//读入元素个数n
int n;
cin >> n;
//创建一个含有n个元素的动态数组arr(n)
vector<int> arr(n);
//读取每一个数字到动态数组中
for(int i = 0; i < n; i++) {
cin >> arr[i];
}
//核心:调用快速排序函数实现排序功能
quickSort(arr, 0, n - 1);
//输出排序后数组中的每一个元素
for(int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
//From:TengMMVP
半数集问题
【问题描述】
给定一个自然数n,由n开始可以依次产生半数集set(n)中的数如下:
(1)n∈set(n);
(2)在n的左边加上一个自然数,但该自然数不能超过最近添加的数的一半;
(3)按此规则进行处理,直到不能再添加自然数为止。
例如,set(6)={6,16,26,126,36,136}。半数集set(6)中有6个元素。注意,该半数集是多重集。
对于给定的自然数n,计算半数集set(n)中的元素个数。
【输入形式】
只有1行,给出整数n(0<n<1000)
【输出形式】
只有1行,给出半数集set(n)中的元素个数
【样例输入】
6
【样例输出】
6
【参考代码】
#include <iostream>
using namespace std;
// 计算半数集set(n)中的元素个数的递归函数
int halfSetCount(int n) {
//递归终止条件
if (n == 1) {
// 当n为1时,只有一个元素(即1本身),因此返回1
return 1;
}
int count = 1; // n本身也是半数集的一个元素,所以从1开始计数
for (int i = 1; i <= n / 2; ++i) {
// 对于每一个可能的数字i,递归计算以i开始的半数集的元素个数
count += halfSetCount(i);
}
return count;
}
int main() {
// 输入自然数n
int n;
cin >> n;
// 输出半数集set(n)中的元素个数
cout << halfSetCount(n);
return 0;
}
//From:TengMMVP