蓝桥杯24.H:整数删除(C++)

步骤

  1. 完成题意和样例的输入和输出(编程思维,遇到一个题如何拆开)
  • ——对
  1. 把程序放到官网上去验证(算法思维,对前面写出的程序进行优化
  • ——快
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

思路分析

  1. 数据存储
    • 放到一维数组里
  2. 程序分析
    1. 找到最小值的下标
    2. 在最小值的左右两个位置加上最小值
    3. 将删除的值改为-1
    4. 套一层循环

代码示范

  1. 先写一部分代码
    1. 进行单元测试,写出部分逻辑,避免出现错误,使验证每一步都是正确的
    2. 每写一步检测对不对,对了再写下一步
//物理上删除数组中的元素
#include <iostream>
#include <stdio.h>
using namespace std;

int main()
{
	//第一步,输入
	int N, M;
	cin >> N >> M;
	//scanf("%d %d", &N, &M);
	int buff[N] = {0};
	for (int i = 0; i < N; i++)
	{
		cin >> buff[i];
		//scanf("%d", buff+i);
	}
	
	/*单元测试,验证输入的正确性*/
	//cout << N << ", " << M << endl;
	//for (int i = 0; i < N; i++)
	//{
	//	cout << buff[i] << " ";
	//}

	for (int i = 0; i < M; i++)
	{
		//第二步:找到数组中最小元素的下标
		int minId = 0;
		for (int j = 0; j < N - i; j++)
		{
			if (buff[minId] > buff[j])
			{
				minId = j;
			}
		}
		// 单元测试2,验证找到的数组中最小的元素和其下标
		//cout << buff[minId] << " " << minId << endl;
		
		//第三步:最小元素下标左右都加上最小元素
		if (minId - 1 > -1)
			buff[minId - 1] += buff[minId];
		if (minId + 1 < N)
			buff[minId + 1] += buff[minId];
		
		//第四步:删除最小元素(物理上删除)
		for (int j = minId; j < N - i; j++) //N-i代表删除了i个元素
		{
			buff[j] = buff[j + 1];
		}
	}
	//第五步:输出数组剩下的元素
	for (int i = 0; i < N - M; i++) //N - M 数组剩下的元素个数
	{
		cout << buff[i] << " ";
	}
	return 0;
}
//逻辑上删除数组中的元素
#include <iostream>
#include <stdio.h>
#include <stdint.h>
using namespace std;

int main()
{
	//第一步,输入
	int N, M;
	cin >> N >> M;
	//scanf("%d %d", &N, &M);
	int buff[N] = {0};
	for (int i = 0; i < N; i++)
	{
		cin >> buff[i];
		//scanf("%d", buff+i);
	}
	
	/*单元测试,验证输入的正确性*/
	//cout << N << ", " << M << endl;
	//for (int i = 0; i < N; i++)
	//{
	//	cout << buff[i] << " ";
	//}

	for (int i = 0; i < M; i++)
	{
		//第二步:找到数组中最小元素的下标
		int minId = 0;
		for (int j = 0; j < N; j++)
		{
			if (buff[j] == INT_MAX)
				continue;
			if (buff[minId] > buff[j])
				minId = j;
		}
		// 单元测试2,验证找到的数组中最小的元素和其下标
		//cout << buff[minId] << " " << minId << endl;
		
		//第三步:最小元素下标左右都加上最小元素
		//找到minId左边未删除的元素
		int j;
		for (j = minId - 1; j > -1; j--)
		{
			if (buff[j] != INT_MAX)
				break;
		}
		if (j > -1)
			buff[j] += buff[minId];
		
		for (j = minId + 1; j < N; j++)
		{
			if (buff[j] != INT_MAX)
				break;
		}
		if (j < N)
			buff[j] += buff[minId];
		
		//第四步:删除最小元素(逻辑上上删除)
		buff[minId] = INT_MAX;  //INT_MAX表示元素已经删除
	}
	//第五步:输出数组剩下的元素
	for (int i = 0; i < N; i++) //N - M 数组剩下的元素个数
	{
		if (buff[i] == INT_MAX)
			continue;
		cout << buff[i] << " ";
	}
	return 0;
}

蓝桥杯不能使用<stdint.h>
即不能使用INT_MAX
需要宏定义一个

#include <math.h>
#define MAX pow(2,31)-1  //2的31次-1

算法优化

静态查找,只进行查找操作的查找,用二分法

  • 动态查找,在查找过程中同时插入新的数据元素,或者删除已存在的数据元素。用排序树或队列
  1. 输入不需要优化
  2. 第二步查找最小值,需要将O(N2)降低为O(NlogN)
    1. 数据是无序的
    2. 属于动态查找
    3. 用排序树,AVL,红黑树
      1. STL里,set或multiset
      2. set不允许有重复的键
      3. multiset允许有重复的键
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <set>

using namespace std;

#define MAX pow(2,31)-1

int main()
{
	multiset<int> buff;
	buff.insert(5);

	for (multiset<int>::iterator it = buff.begin(); it != buff.end(); it++)
	{
		cout << *it << endl;
	}
	return 0;
}

代码优化

  1. 数据存储->DS
    1. 复杂
    2. 空间
  2. 程序设计->算法
    1. 简单
    2. 时间
//模拟链表+排序树
//链表,物理上删除元素
//模拟链表,逻辑上删除元素
//逻辑上删除数组中的元素
#include <iostream>
#include <stdio.h>
#include <stdint.h>
#include <vector>
#include <set>

using namespace std;

typedef long long INT64;  //数据规模的原因
typedef pair<int, int> Key;  //存放值和下标的类型

typedef struct
{
	int id;          //下标
	INT64 val;       //值
	int prev;        //上一个元素的下标
	int next;        //下一个元素的下标
}Node;    //buff模拟链表使用

int main()
{
	//第一步,输入
	int N, M;
	cin >> N >> M;
	//scanf("%d %d", &N, &M);
	
	Node buff[N] = {0};
	multiset<Key> mSet;
	for (int i = 0; i < N; i++)
	{
		INT64 v;
		cin >> v;
		buff[i] = {i, v, i-1, i+1}
		mSet.insert(Key(v, i));
	}

	//for (multiset<Key>::iterator it = mSet.begin;
	//			it != mSet.end(); i++)
	//{
	//	cout << it->first << ", " << it->second << endl;
	//}

	for (int i = 0; i < M; i++)
	{
		//第二步:找到数组中最小元素的下标
		multiset<Key>::iterator minIt = mSet.begin();
		int minId = minIt->second;
		int minV = minIt->first;

		// 单元测试2,验证找到的数组中最小的元素和其下标
		//cout << buff[minId] << " " << minId << endl;
		
		//第三步:最小元素下标左右都加上最小元素
		//找到minId左边未删除的元素
		int prev = buff[minId].prev;
		int next = buff[minId].next;
		if (prev != -1)
		{
			mSet.erase(Key(buff[prev].val, prev));
			//删除原有的左值
			buff[prev].val += buff[minId].val;
			buff[prev].next = buff[minId].next;
			mSet.insert(Key(buff[prev].val, prev)); 
			//添加新的左值
		}
		if (next != N)
		{
			mSet.erase(Key(buff[next].val, next)); 
			//删除原有的右值
			buff[next].val += buff[minId].val;
			buff[prev].prev = buff[minId].prev;
			mSet.insert(Key(buff[next].val, next)); 
			//添加新的右值
		}
		
		//第四步:删除最小元素(逻辑上上删除)
		buff[minId].val = MAX;  //MAX表示元素已经删除
		mSet.erase(minIt);
	}
	//第五步:输出数组剩下的元素
	for (int i = 0; i < N; i++) //N - M 数组剩下的元素个数
	{
		if (buff[i].val == MAX)
			continue;
		cout << buff[i] << " ";
	}
	return 0;
}

代码优化2

优先级队列

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <queue>

using namespace std;

int main()
{
	priority_queue<int, vector<int>, greater<int> > qBuff;
	qBuff.push(5);
	qBuff.push(3);
	qBuff.push(2);
	qBuff.push(8);
	qBuff.push(7);

	while(qBuff.empty() == false)
	{
		cout << qBuff.top() << " ";
		qBuff.pop();
	}
	return 0;
}

示范

/**  
* H题:方式五 - 模拟链表+优先队列  
* 该程序通过模拟链表和使用优先队列的方式解决问题。  
*/  
  
#include <iostream>
#include <vector>
#include <queue>
using namespace std;  
  
typedef long long INT64;  
typedef pair<INT64, int> Key; // Key 定义  
  
typedef struct  
{  
	int prev;  
	int next;  
	INT64 sum;  //相加之后所放的位置
} Node; // 结点定义  
  
int main()  
{  
	int N, M;  
	cin >> N >> M; // 输入总数 N 和操作次数 M  
	  
	// 初始化结点数组和优先队列  
	Node buff[N] = {0};  
	  
	/* 核心代码*/  
	priority_queue, greater> buffQ;  
	  
	// 初始化链表结点和优先队列  
	for(int i = 0; i < N; i++)  
	{  
		INT64 v;  
		cin >> v;  
		buff[i] = {i-1, i+1};
		//初始化链表结点,每个结点有前驱和后继  
		buffQ.push(Key(v, i)); // 将每个结点的值和索引加入优先队列  
	}  
	  
	// 执行优化操作,保留前 N-M 个元素  
	while(buffQ.size() > N-M)  
	{  
		Key e = buffQ.top();  
		buffQ.pop();  
		  
		int id = e.second; // 获取当前操作结点的索引  
		INT64 val = e.first; // 获取当前操作结点的值  
		  
		if(buff[id].sum)  
		{  
			/* 核心代码*/  
			buffQ.push(Key(buff[id].sum + val, id)); 
			// 将当前结点和其后继结点的和重新加入优先队列  
			buff[id].sum = 0; // 将当前结点的 sum 置零  
		} 
		else  
		{  
			int prev = buff[id].prev;  
			int next = buff[id].next;  
			  
			// 将当前结点的值分配给前驱和后继结点  
			if(prev != -1)  
			{  
				buff[prev].sum += val;  
				buff[prev].next = buff[id].next;  
			}  
			if(next != N)  
			{  
				buff[next].sum += val;  
				buff[next].prev = buff[id].prev;  
			}  
		}  
	}  
	  
	vector res(N, 0);  
	  
	// 将优先队列中的结果保存到数组中  
	while(buffQ.empty() == false)  
	{  
		Key e = buffQ.top();  
		buffQ.pop();  
		res[e.second] = e.first + buff[e.second].sum;  
	}  
	  
	// 输出结果  
	for(int i = 0; i < N; i++)  
	{  
		if(res[i]) cout << res[i] << " ";  
	}  
	  
	return 0;  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值