算法第四章上机实践报告
1.实践题目: 4-2 删数问题
2.问题描述:
给定n位正整数a,去掉其中任意k≤n 个数字后,剩下的数字按原次序排列组成一个新 的正整数。对于给定的n位正整数a和正整数 k,设计一个算法找出剩下数字组成的新数最 小的删数方案。
输入格式:
第 1 行是1 个正整数 a。第 2 行是正整数k。
输出格式:
输出最小数。
输入样例:
在这里给出一组输入。例如:
178543
4
输出样例:
在这里给出相应的输出。例如:
13
3.算法描述:
由于测试的数据位数很大,所以用string来纪录输入的整数,再将整数中的每一位数存到数组b[i]中
贪心算法思路:
1.先求出剩余数字的位数d(d=原位数-删除位数),然后从原数据的第d位开始(从个位数开始往左数第c位,且包括这一位),挑出最小的一位c[1](若出现多个相同最小位,则挑最左边的),前面的n位数字全部删除并令k=k-n;
2.若k==0,则结束,输出删剩的数;
若k!=0,则将剩余数字重复第一步的过程直到k==0;
比如例子中的178543为6位数,删去k=4位:
【第一轮】6位数,删去k=4位,剩余2位,
则从第2位(十位数)开始往前,最小的数字是1,取出1,1前面有0位数,则k=k-0,为4,不变,不为0,将剩余的78543重复一轮
【第二轮】仍需删除4位,即为从78543中删除4位,剩余1位,
则从第1位(个位数)往前看,最小的数是3,3前面有4位数,删去,则k=k-4,等于0,删除完毕,结果为13
#include <iostream> #include <string> #include <algorithm> using namespace std; int b[100000]; int c[100000]; int main() { int k; string a = new char[100000]; cin >> a >> k; char ch; int BDigit = a.length(), CDigit;//BDigit为a的位数,CDigit为得到的结果的位数 for (int i = 0; i < a.length(); i++)//将整数中的每一位数存到数组b[i]中 { ch = a[a.length() - i - 1]; b[i] = ch - '0'; } CDigit = BDigit - k; int temp = 10;//用来记录每一轮的最小数,一位数的最小数一定<10 int locate;//记录每一轮取得的数字的位置 int result = 0;//记录结果 int judge = 0;//判断 for (int i = 0; i < CDigit; i++) { for (int j = BDigit - k - 1; j < BDigit; j++) { if (b[j] <= temp) { temp = b[j]; locate = j;//记录位置 } } k = k - (BDigit - locate - 1);//减去一轮中删除的数字个数 BDigit = locate; c[i] = temp; if (c[i] != 0)//若前面都是0,则不输出,遇到第一个非零数,改judge为1 { judge = 1; } if (judge == 1) { cout << c[i]; } temp = 10;//重置temp } if (judge == 0)//若剩下的数全部为0,则输出一个0 { cout << 0; } system("pause"); return 0; }
4.算法时间及空间复杂度分析:
算法中有两次for循环,需要CDigit*(k+1)次(k在循环中会变化),时间复杂度为O(n^2)
需要一个string及两个int数组记录,空间复杂度为O(n)
5.心得体会:
写第一题时很顺畅,写到第二题时讨论了很久想出上述算法方案(没有上网查,好像网上的方法不一样?),写好后一直答案错误,才发现是k没有做处理,处理好后有没注意到数据位数问题,只通过一个,改string后就AC了。
但是我还是不懂怎么证明贪心选择性质和最优子结构性质......