算法第四章实践报告

  1.实践题目:删数问题

  2.问题描述:

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

  3.算法描述:

    根据我的观察,要删的数有以下规则:

      1)从左往右数,第一个递减数(即这个数比后一个数大)为要删的数;

      2)若为非递减数列,则最右边的数(最大数)为要删的数。

      

    如果把这个数的每一位数根据大小画成折线图,则易观察得出,要删的数为峰值数,若有多个峰,则第一个峰为要删的数。以样例输入178543为例,第一个要删的数为8,即为第一个峰值数。

    因此,该算法变为找到并删除第一个峰值数。

    数据结构:

      使用变长数组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.心得体会(对本次实践收获及疑惑进行总结)

    我认为这个算法的最大的难点在于搞清楚要删的数是什么,有何规律。刚做这道题时,我简单地认为,既然要保持删后的数最小,那么每次将数列的最大数删掉不就行了吗!这并不是我们正确的贪心策略。例如,在输入18592,k=1时,要删的数并不是9,而是8。因为数在每一数位上的权值是不一样的,越靠近左边权值越大,例如,如果是五位数,那么权值最大的是万位。因此,删的数必须越靠近左边越好。因此我们的贪心策略就是删除从左往右的第一个峰值数。只要清楚这一点,算法的实现无非就是遍历、判断,较为简单。其次,数据结构也是一个值得关注的点。一开始我使用了简单的定长数组int[]。但发现删除数值的时候较为麻烦,需要用数据移位或者将要删除的置为-1等方式来进行删除操作,需要写大量冗长代码,因此后来我直接利用的变长数组Vector来储存,效率确实提高了许多。最后,一个麻烦的问题是如何正确地输出数值。上面提到过,直接输出有可能造成输出前置0。比如输入1000,k=1,正确输出是0,但因为数据存储方式的原因,直接输出会变成000。因此要设计算法来删除前置0。一开始我使用StringBuder的方式来拼接成字符串,然后再将字符串转为整形值。

  StringBuilder builder = new StringBuilder();
  for (int t : n) {
   builder.append(t);
  }
  System.out.println(Integer.parseInt(builder.toString()));
这个方法在编译器上输出是正确的,但不知为什么PTA上不给通过,最后无奈只能用其他方式来输出了。。。先贴出来放在这里。
posted @ 2018-12-01 17:57  wanderlust  阅读(209)  评论(0编辑  收藏  举报