求解最小正整数问题(贪心算法)

例题:
键盘输入一个正整数n,去掉其中任意s个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的n和s,寻找一种方案使得剩下的数字组成新数最小。(n不超过240)
问题分析:
在位数固定的情况下,让高位的尽量小,其值也就较小,依据此贪心策略就可以解决问题。
为了实现贪心策略来删除数字,具体的就是:
相邻的两个数做比较,若高位比低位大则删除高位,若小,就与下一组相比较。
下面看一个实例:
在这里插入图片描述

由实例n1,相邻的数字只需要向后比较;而从实例n2开始可以看出,当第i位与第i+1位比较,若删除第i位后,必须向前考虑第i-1位与第i+1位进行比较,才能保证结果的正确性。

由此可知通过实例设计算法时,枚举的实例一定要有全面性。要尽可能的多列举几个不同的实例,在看如下的两个特殊情况:
在这里插入图片描述

经过以上的案例分析我们可以进行算法设计:
该算法主要由五部分组成:初始化,相邻的数字比较,处理过程中的删除不足够s位的情况,高位有0的情况和结果输出。
这里我们选择一种最简单也最好理解的方法**“物理进行字符删除”**
就是用后面的字符覆盖已删除的字符,字符串长度改变。但是这样可能会有较多的字符移动操作,算法的效率不高。
在用这种算法的时候,我们需要在继续一次删除后,就退出该循环,继续下次循环。反复运行s次后,判断以上特殊的情况,处理完整后,就可输出结果:

Java版源码:

/**
 * 最小正整数问题
 *
 */
 public class minPositiveInt { 
 static String str; 
 static int length; //数字的长度
 public static void main(String[] args) {
 Scanner scanner = new Scanner(System.in);
  int []date = new int [240];
  char []array =new char [240];
  System.out.println("输入数:");
  str = scanner.nextLine();//读数
  length = str.length();//str的长度
  for(int i=0;i<str.length();i++) {//将数存入char数组中
   array[i] = str.charAt(i);
  }
  System.out.println("请输入需要删除几个数:");
  int flag = scanner.nextInt();
  int sum = 0;//删除次数
  if(flag>length) {
   System.out.println("错误!删除的比原数字长!!");
   }else {
   for(int i=0;i<flag;i++) {
    for(int j=0;j<length-1;j++) {
     if(array[j]>array[j+1]) {
      delete(array,j);//删除array[j]
      sum++;
      break;  //删除了一个后退出
     }
    }
   }
   if(sum < flag) {//判断是否删除了规定的数量,没有进入if语句
    int a = flag-sum;
    length  -= a;
    }
   }

//输出数组
  System.out.println("所求最小正整数为: ");
  for(int i=0;i<length;i++) {
   System.out.print(array[i]);
  }
 }
//删除方法
 private static void delete(char[] array, int j) {
  for(int i=j;i<length-1;i++) {
   array[i] = array[i+1];
  }
  length--;
 }
}

这是第一种算法,虽然简单好理解但是多次的移位,让代码的效率不是那么高。所以接下来我介绍另外两种方法:
1.可以利用数组记录字符的存在状态,元素值为1表示对应的数字存在,元素值为0表示对应的元素值已删除。这样避免了字符的移动,字符串的长度不变,可以省略专门记录删除数字的位置。但是这样做前后数字的比较过程和最后的输出过程会相对麻烦一点
2.还是使用数组,记录未删除字符的下标,粗略的过程如下:
在这里插入图片描述这时该数组就像一个数据库的索引文件。但是此方法同样存在着操作复杂的问题。

总结:
以上就是这个问题我所罗列的三个方法,我只提供了第一种方法的源码,大家可以直接尝试的把后面两种方法实现出来。如果有什么疑问可以评论我们一起解决。

对于这个问题,因为我也是一个初学者,我目前还没掌握一个操作又简单同时后面的运算也不复杂的算法,希望各位大佬可以提一些建议,或者那块有问题可以指出我加以改进。

猜你喜欢

转载自blog.csdn.net/qq_44247658/article/details/106289811