[7/30] 買香蕉

MIOJ #98 買香蕉 ??

描述

我是一個愛吃香蕉的強迫癥。今天我要去水果店論筐買香蕉。 現(xiàn)在水果店有好多筐香蕉,我的要求是買回來的每一筐里必須有相同數(shù)量的香蕉。 為了實現(xiàn)這個目標,你可以每次做兩件事情。 1)放棄筐里的一部分香蕉 2)連筐帶香蕉放棄一整筐 我想知道我能得到最多多少香蕉。

輸入

以空格分割的多個正整數(shù),每個正整數(shù)表示一筐香蕉的總香蕉數(shù)

輸出

最多能得到的香蕉數(shù)

輸入樣例

1 2 3
5 0 29 14

輸出樣例

4
29

解法

大力出奇跡,暴力解法

這個問題無非是選擇哪幾筐的問題,先把所有可能的選擇枚舉出來,然后找到每個選擇中最小的那筐,每筐都是這個數(shù)量時就是最終獲得的香蕉數(shù)量,遍歷所有所有選擇然后找到香蕉數(shù)量最大的即可。

第一步:枚舉出所有的方案。集合 {1,2,3}枚舉出所有的方案有
23 種,除去空集,還有7個。1~7,幾個數(shù)字換算為二進制分別是,001,010,011,100,101,110,111,每一位的0還是1可以視作是否選擇這個元素。依照這個想法,我們可以寫出程序枚舉出所有的可能方案。

第二步:計算每一種方案對應(yīng)可獲得的香蕉數(shù)量,就是每種方案中香蕉數(shù)量最小值*筐的數(shù)量。

代碼如下:


package  com.li2niu.mioj.day7.BuyBananas; 
 import  java.util.Arrays;  import  java.util.Scanner;  /**
 * @author chuanyi@88.com
 * @date 2020/10/29
 * @Description
 */ 
 public  class  Main  {  public  static  void  main(String[] args)  {  Scanner scan =  new  Scanner(System.in);  String line;  while  (scan.hasNextLine())  { line = scan.nextLine().trim();  String[] strings = line.split(" ");  int[] nums =  new  int[strings.length];  for  (int i =  0; i < strings.length; i++)  { nums[i]  =  Integer.parseInt(strings[i]);  }  System.out.println(buyBananas(nums));  }  }  private  static  int  buyBananas(int[] nums)  {  String[] buyMethods =  enumBuyMethod(nums);  int max =  0;  for  (String buyMethod : buyMethods)  {  String[] numbers = buyMethod.split(",");  int min = nums[Integer.parseInt(numbers[0])];  for  (int i =  1; i < numbers.length; i++)  {  int temp = nums[Integer.parseInt(numbers[i])];  if  (temp < min)  { min = temp;  }  }  int count = min * numbers.length;  if  (count > max)  { max = count;  }  }  return max;  }  /**
     * 枚舉導(dǎo)致內(nèi)存超限,只存下標
     * 使用字符串存儲每一種方案中的筐的下標
     * @param nums
     * @return
     */  private  static  String[]  enumBuyMethod(int[] nums)  {  int length = nums.length;  int subSetNum =  (int)  Math.pow(2, length);  int temp;  String[] strings =  new  String[subSetNum -  1];  for  (int i =  0; i < subSetNum; i++)  {  if  (i ==  0)  {  continue;  } temp = i;  StringBuilder set =  new  StringBuilder();  for  (int j =  0; j < length; j++)  {  if  ((temp &  1)  ==  1)  { set.append(j);  if  (j < length -  1)  { set.append(",");  }  } temp >>=  1;  }  if  (set.charAt(set.length()  -  1)  ==  ',')  { set.deleteCharAt(set.length()  -  1);  } strings[i -  1]  = set.toString();  }  return strings;  }  }  

時間復(fù)雜度為 O(2n+1n) 。枚舉的總數(shù)為 2n ,每種方案都需要遍歷數(shù)字的每個二進制位取出對應(yīng)筐的下標,這個長度是 n ,最后統(tǒng)計每一種方案對應(yīng)的香蕉數(shù)也是相同的復(fù)雜度。這樣,時間復(fù)雜度就是O(2n+1n) 。

空間復(fù)雜度 O(2n-1)=O(2n) 。一個用于存儲方案的輔助數(shù)組。

但是這樣的暴力方法會內(nèi)存超限?。?!

排序,找短板

有什么其他的辦法嗎?

題設(shè)說,筐中的香蕉是可以放棄一部分的。 比較容易想到的一點是找到一筐數(shù)量比較少最佳的香蕉,然后讓其他的筐都減少到相同的數(shù)量。因為香蕉只能減少,不能增加,我們應(yīng)當從數(shù)量較少的香蕉筐開始,讓其余的可能的香蕉筐放棄一部分以達到相同的數(shù)量。

第一步:從小到大排列香蕉筐

第二部:從小到大遍歷這些筐,讓比當前筐多的香蕉都保持相同的數(shù)量,求出可以得到的香蕉總數(shù)。找到這些總和的最大值。

代碼如下:

package  com.li2niu.mioj.day7.BuyBananas;  import  java.util.Arrays;  import  java.util.Scanner;  /**
 * @author chuanyi@88.com
 * @date 2020/10/29
 * @Description
 */  public  class  Main  {  public  static  void  main(String[] args)  {  Scanner scan =  new  Scanner(System.in);  String line;  while  (scan.hasNextLine())  { line = scan.nextLine().trim();  String[] strings = line.split(" ");  int[] nums =  new  int[strings.length];  for  (int i =  0; i < strings.length; i++)  { nums[i]  =  Integer.parseInt(strings[i]);  }  System.out.println(buyBananas1(nums));  }  }  private  static  int  buyBananas1(int[] nums)  {  Arrays.sort(nums);  int max =  0;  int length = nums.length;  for  (int i =  0; i < length; i++)  {  int count = nums[i]  *  (length - i);  if  (count > max)  { max = count;  }  }  return max;  }  }  

時間復(fù)雜度是

O(nlogn+n)=O(nlogn) 。使用的Arrays.sort 時間復(fù)雜度是O(nlogn) ,遍歷需要O(n) 。

空間復(fù)雜度O(1) 。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容