題目描述
小藍(lán)有一個(gè)超大的倉(cāng)庫(kù),可以擺放很多貨物。
現(xiàn)在,小藍(lán)有 n 箱貨物要擺放在倉(cāng)庫(kù),每箱貨物都是規(guī)則的正方體。小藍(lán)規(guī)定了長(zhǎng)、寬、高三個(gè)互相垂直的方向,每箱貨物的邊都必須嚴(yán)格平行于長(zhǎng)、寬、高。
小藍(lán)希望所有的貨物最終擺成一個(gè)大的長(zhǎng)方體。即在長(zhǎng)、寬、高的方向上分別堆 L、W、H 的貨物,滿(mǎn)足 n=L×W×H。
給定 n,請(qǐng)問(wèn)有多少種堆放貨物的方案滿(mǎn)足要求。
例如,當(dāng) n=4 時(shí),有以下 6 種方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。
請(qǐng)問(wèn),當(dāng) n=2021041820210418 (注意有 16 位數(shù)字)時(shí),總共有多少種方案?
首先要找到這個(gè)數(shù)的所有因子
1.使用ArrayList存放n的因子,要考慮到(如果兩個(gè)相同的數(shù)相乘等于n,只能存放一次)
2.在找因子的過(guò)程中,可以從1遍歷到根號(hào)n,這樣可以節(jié)省時(shí)間空間
3.找到因子之后繼續(xù)找擺放的方法,計(jì)算機(jī)就能輕松計(jì)算出結(jié)果了
import java.util.ArrayList;
public class Main {
? ? public static void main(String args[]) {
? ? ? ? //常規(guī)思路
? ? ? ? /*
? ? ? ? long num = 2021041820210418l;
? ? ? ? int count = 0;
? ? ? ? for ( long i = 1 ; i < num ; i++ ){
? ? ? ? ? ? for ( long j = 1 ; j < num ; j++ ){
? ? ? ? ? ? ? ? for ( long k = 1 ; k < num ; k++ ){
? ? ? ? ? ? ? ? ? ? if ( i * j *um ){
? ? ? ? ? ? ? ? ? ? ? ? count++;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? */
? ? ? ? //顯而易見(jiàn),這個(gè)算法的時(shí)間復(fù)雜的非常的大。計(jì)算機(jī)想要算出結(jié)果,可能需要幾天的時(shí)間
? ? ? ? //所以要另辟蹊徑
? ? ? ? //想想,三個(gè)數(shù)相乘要等于num,那么這三個(gè)數(shù)是不是都是num的因子,都能被num整除呢?
? ? ? ? //上方的算法,三層for循環(huán)都是從1遍歷到num,其中很多組合都是無(wú)效的
? ? ? ? //簡(jiǎn)而言之,這些無(wú)效組合中不能同時(shí)被num整除,而有效的組合,任何一個(gè)數(shù)都能被num整除
? ? ? ? //所以,如果我們能從num的因子里面去找組合,是不是時(shí)間復(fù)雜度就要小許多?
? ? ? ? long num = 2021041820210418l;
? ? ? ? //如果直接賦值,計(jì)算機(jī)默認(rèn)數(shù)字是int類(lèi)型,會(huì)報(bào)錯(cuò)。所以要在后面加'l',轉(zhuǎn)換為long類(lèi)型
? ? ? ? //定義一個(gè)ArrayList數(shù)組,存放num的因子
? ? ? ? ArrayList<Long> arr = new ArrayList<>();
? ? ? ? //從1開(kāi)始遍歷,遍歷到num的平方根結(jié)束。不需要把num遍歷一遍,這樣算法復(fù)雜都也非常大,重點(diǎn)看for循環(huán)里面的語(yǔ)句
? ? ? ? for ( long i = 1 ; i <= Math.sqrt(num) ; i++ ){
? ? ? ? ? ? if ( num % i == 0 ){
? ? ? ? ? ? ? ? arr.add(i);? ? //如果能被整除,就放到arr數(shù)組中
? ? ? ? ? ? ? ? //?。。≈攸c(diǎn)在這里,當(dāng)i能被num整除的情況下,求出num關(guān)于i的另外一個(gè)除數(shù)n
? ? ? ? ? ? ? ? //這樣,for循環(huán)不需要從1遍歷到num??梢酝ㄟ^(guò)較小的因子,求出另外一個(gè)較大的因子
? ? ? ? ? ? ? ? long n = num / i;
? ? ? ? ? ? ? ? //如果num = Math.sqrt(num)*Math.sqrt(num),那么由較小的因子求較大的因子時(shí),會(huì)重復(fù),要排除這種情況
? ? ? ? ? ? ? ? if ( n != i ){? ? ? //當(dāng)然,此時(shí)num,不會(huì)出現(xiàn)這種情況。如果num=4,就會(huì)出現(xiàn)這種情況
? ? ? ? ? ? ? ? ? ? arr.add(n);? ? //將較大的因子放入arr數(shù)組
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //System.out.println(arr.size());? //num一共有128個(gè)因子
? ? ? ? //三層for循環(huán)依次遍歷即可。 128^3 = 2097152 計(jì)算機(jī)完全可以在短時(shí)間內(nèi)算出結(jié)果
? ? ? ? int count = 0;
? ? ? ? for ( long i : arr ){
? ? ? ? ? ? for ( long j : arr ){
? ? ? ? ? ? ? ? for ( long k : arr ){
? ? ? ? ? ? ? ? ? ? if ( i * j * k == num ){
? ? ? ? ? ? ? ? ? ? ? ? count++;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? System.out.println(count);
? ?