算法设计与分析_Part1

数组元素排序


【问题描述】

给定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,计算其逆序对的总数。即:

image.png

【输入形式】

输入包含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
  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值