第四章实践报告

1.实践题目:删数问题

 

2.问题描述:给定n位正整数a,去掉其中任意k≤n 个数字后,剩下的数字按原次序排列组成一个新 的正整数。对于给定的n位正整数a和正整数 k,设计一个算法找出剩下数字组成的新数最 小的删数方案。

 

3.算法描述:每删一个数字时,最优的选择是从左到右遍历,删掉第一个开始递减的数字,如果是递增数列,则删除最右边的数。

      而最后的结果最优解与每次删一个数字的最优解合并起来是一样的。

 

数据结构:

      使用变长数组Vector<Inteeger>,将输入数拆成每一位按顺序存储于变长数组 n 中。

    算法 - 删数:

      int count = 0;  // 用于记录已经删除的数的个数
      while (count < k) {   // 当已删的数还未达到k
        for (int i=0; i<n.size()-1; i++) {   // 遍历数的每一位
          if (第 i 个数大于第 i+1 个数) {
            删除第i个元素;  // 表明第 i 个数是峰值数,删除
            count++;  // 计数+1
            break; //因为一趟遍历只能删一个数,且要删的数就是第一个峰值数,因此直接跳出循环
          }
          if (遍历到末尾仍未找到峰值数) {
            删除第i个元素; //前面无峰值数,因此峰在最后一个数,删除
            count++;
            break;
          }
        }
      }

    算法 - 输出数据:

      因为输出的数值不允许有前置0(例如021要变成21,000要变成0)。该算法确保不会输出前置0。

      boolean isFirstOutput = true; //用布尔值表示当前是否还未输出数值,仍为第一个输出
      for (int t : n) { //遍历Vector数组n
      if (当前数为0且为第一个输出) continue; //跳过,不输出
      输出t; //否则输出,且将判断变量设为false。
      isFirstOutput = false;
      }
      if (isFirstOutput) //如果遍历到最后判断变量仍为true,说明输出值为0,但把0全部略过了,这里补上一个0。
      输出0;

4.算法时间及空间复杂度分析:

     时间复杂度:最坏情况下,算法每次都遍历到最末尾。一次遍历为O(n),共遍历了k次,因此时间复杂度为O(k*n)。

    空间复杂度:算法使用了Vector来保存数据,因此空间复杂度为O(1)。

 

5.心得体会

我觉得首先是要搞清楚该问题的贪心性质,即只删除一个数字时,删除什么样的数字是最优解,而这个最优解与最终结果的最优解是否一致。这个问题里我和李祥浩同学讨论了很长时间,一开始觉得只用删除最大的那些数就可以了,但细想这样是不对的

最后我们找到了正确的每一步的贪心选择,但是在去除0的问题上也花了比较多的时间,这提醒我们编程要事无巨细,要过问题不仅核心算法要找对,语法要好,还要考虑到每一种情况,才能真正解决问题。

 

posted @ 2018-12-02 19:54  LLB1  阅读(94)  评论(0编辑  收藏  举报