LeetCode算法题编号891“子序列宽度之和”算法分析和解题思路在前两篇随笔中(在找工作的途中)
作者:互联网
我在研究该算法题的时候是先经过最笨的方法,然后慢慢优化得到计算量相对较少的算法。在研究该算法中断断续续的花了10个小时吧,基本都是晚上思考,白天为找工作准备。晚上思考算法并进行代码实现。
我也看了官方的答案,官方给的答案没有考虑数组中是否有重复的数。所以我这给了考虑重复的数的答案。如不准确还请告知。谢谢。
题目是:
给定一个整数数组 A ,考虑 A 的所有非空子序列。
对于任意序列 S ,设 S 的宽度是 S 的最大元素和最小元素的差。
返回 A 的所有子序列的宽度之和。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-subsequence-widths
在这题中考虑了:元素的排序,数组中是否有重复的数(不考虑这中情况,会使得最终结果与实际情况偏离。也就是在 考虑数组子系列的时候会重复计算)
首先统计数组中重复数的个数,并且用map集合封装。代码如下:
1 //运用map集合统计数组中每个数出现的次数 2 public static Map<Integer, Integer> getMap(Integer[] array){ 3 Map<Integer, Integer> map=new HashMap<>(); 4 Arrays.sort(array); 5 map.put(array[0], 1); 6 for(int i=1;i<array.length;i++) { 7 if(array[i-1]==array[i]) { //判断左右是否相等,若相等则对应值的次数加一 8 map.put(array[i-1], map.get(array[i-1])+1); 9 }else { //否则将不同的数输入map集合中 10 map.put(array[i], 1); 11 } 12 } 13 return map; 14 }
再将数组中不同的数封装在一个集合中。代码如下:
1 //将不同的数存储在一个数组中 并且 按从小到大的顺序。 2 public static Object[] getArrays(Integer[] array) { 3 List<Integer> list=new ArrayList<>(); 4 Arrays.sort(array); 5 list.add(array[0]); 6 for(int i=1;i<array.length;i++) { 7 if(array[i-1]==array[i]) { //判断左右是否相等,若相等则对应值的次数加一 8 }else { 9 list.add(array[i]); 10 } 11 } 12 Object[] A=list.toArray(); 13 return A; 14 }
再通过输入一个最大值,一个最小值。计算在最大值和最小值之间的数会出现的子序列的个数。代码如下(注释部分是为了校验在测试时出错的地方):
1 //求两数之间的排列的次数 2 public static int getNum(int i,int j) { //i的数值小于j 3 Map<Integer, Integer> map=getMap(array); 4 Object[] A=getArrays(array); 5 6 int num=1; 7 for(int k=i+1;k<j;k++) { 8 num=num*(map.get(A[k])+1); 9 // num=(int) ((num+Math.pow(2, j-k-1))*map.get(A[k])); 10 // num=(int) (num+map.get(A[k])*Math.pow(2, j-i-1)); 11 //num=num+map.get(A[k]); 12 // System.out.println("num1="+num); 13 } 14 // System.out.println("i="+i+" j="+j); 15 // System.out.println(num); 16 // System.out.println(2^(j-i)*num/2); 17 18 System.out.println("tula"+Math.pow(2, 0)+"nima"); 19 return num*map.get(A[i])*map.get(A[j]); 20 }
现在计算最终结果,代码如下:
1 //得出最终值 2 public static int getSum() { 3 int sum=0; 4 Object[] A=getArrays(array); 5 for(int j=1;j<A.length;j++) { 6 for(int i=0;i<j;i++) { //i的数值小于j 7 8 sum=sum+getNum(i, j)*((int)A[j]-(int)A[i]); 9 //System.out.println("A[i]="+A[i]+" i="+i+" A[j]="+A[j]+" j="+j+" getNum="+getNum(i, j)); 10 } 11 } 12 13 return sum; 14 15 }
最后的main函数直接就可以得到最终结果。(注释部分是在思考过程中,然后慢慢优化)。我给的方法现在还不是最优化的。但是可以得出正确结果。
1 public static void main(String[] args) { 2 3 4 System.out.println(getSum()); 5 6 7 8 9 // 10 // 11 // Map<Integer, Integer> map=new HashMap<>(); 12 // List<Integer> list=new ArrayList<>(); 13 // Integer[] array= {66,2,3,99,25,1,6,5,6,6,8,8,8,9}; 14 // Arrays.sort(array); //将数组中的数由小到大进行排序 15 // 16 // for(int i=0;i<array.length;i++) { 17 // System.out.print(array[i]+" "); 18 // } 19 // System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!");//打桩检测数据是否排序 20 // 21 // list.add(array[0]); 22 // map.put(array[0], 1); //将第一个数输入map集合中 23 // 24 // for(int i=1;i<array.length;i++) { 25 // if(array[i-1]==array[i]) { //判断左右是否相等,若相等则对应值的次数加一 26 // map.put(array[i-1], map.get(array[i-1])+1); 27 // }else { //否则将不同的数输入map集合中 28 // map.put(array[i], 1); 29 // list.add(array[i]); //将数组中不同的数放在list集合中。 30 // } 31 // } 32 // System.out.println(list); //打桩,检测list中的数据 33 // System.out.println(map); //打桩,检测map中的数据 34 // 35 // Object[] A=list.toArray(); //将集合转成数组 36 // System.out.println(A[5]); //检测 37 // 38 // //准备工作完成。 39 // 40 // 41 // int sum=0; //宽度之和。 42 // 43 // for(int i=1;i<A.length;i++) { 44 // for(int j=0;j<i;j++) { 45 // 46 // } 47 // } 48 // 49 // 50 // 51 }
标签:891,map,int,public,算法,static,数组,array,LeetCode 来源: https://www.cnblogs.com/zhou2420032204/p/13380529.html