算法總結系列——數組的巧妙運用+動態規劃

前言

做完今天美團的912筆試編程題。感覺這個題目很巧,讓我深刻領略了數組的巧妙運用。決定記錄下,下次再遇到相關數組的巧妙運用時更新下。

正題

平時經常用數組來進行一些巧妙的事情,比如,用數組存儲a-z所有字符在這個字符串中出現的次數。我們經常會把需要用到的值直接當做數組下標來用,這樣就不需要再去遍歷數組來得到想要的值。比如將要講述的題目:

題目大意如下,有n個數(2<=n<=10^5),從中選取任意兩個數,直接組合,求能組成7的倍數的個數。比如下面這組數據
3
127,1996,12
其中能組成7的倍數的,是127 12,1996 12,1996 127,12 1996。所以答案爲4。

剛開始看這個題目的時候一頭霧水,根本不知道如何下筆。兩個for循環肯定不行,超時了。那麼有沒有巧妙的方法呢?

思路

仔細觀察,發現兩個數組合,假設a和b自由組合,那麼就是a*(10k)+b或者 b*(10k)+a,其中,10k代表b的位數或a的位數。就可以以這個作爲突破口,在剛輸入a的時候,就將a左移0-9位的數全部存儲起來(這裏的座左移不是二進制的做移動,而是直接添0),下次運用時直接找有幾個這樣的值就行了。題目需要找到7的倍數的人,所以a移動後 mod 7的值要存儲起來,以及a移動的位數肯定也要記錄。
巧妙運用數組,數組的維數一定要選取好,這和動態規劃一樣,可以多點,但絕不能少,可以由多到少慢慢遞減。直接使用某個值作爲數組的下標,直接訪問而不需要再循環去遍歷查找。
那麼需要記錄什麼呢?首先,肯定需要記錄下a左移後mod 7的值(爲了後續直接查找引用數組),這裏作爲數組第一維,還需要a左移的位數,這樣才知道是不是剛好這兩個數能自由組合,這是第二維。貌似二維就足夠了,但是真的夠了嗎?
no,編程過程中,會發現,還需要第三維,這裏第三維大小只需要申明爲2就行,例如,dp[i][j][0],代表沒有移動(0)的時候,位數爲j的人,在mod 7爲i的數有幾個。dp[i][j][1],代表像左移動了 j位之後,mod 7 ==i 的數有幾個。
核心代碼如下:

struct Node{
	int x;//x代表值
	int y;//y代表位數。
}node[MAXN];
long long multi[10];

void handle(){
	memset(dp,0,sizeof(dp));
    multi[0]=1;
    for(int i=1; i<10; i++)
    {
        multi[i] = multi[i-1]*10;
    }
    for(int i=0; i<n; i++)
    {
        int temp;
        scanf("%d",&temp);
        node[i].x = (long long)temp;
        node[i].y = 0;
        while(temp)//求出temp的位數存儲在node[i].y中。
        {
            node[i].y++;
            temp = temp/10;
        }
        dp[(int)node[i].x%7][node[i].y][0]++;//這裏0採用node[i].y來存儲,就是爲了之後把該值作爲組合的右邊值時方便直接調用。
        for(int j=1; j<10; j++)
        {
            int mod = (int)((long long)node[i].x)*multi[j]%7;
            dp[mod][j][1]++;//這裏1時,採用左移了的j位來存儲而不是採用node[i].y也是爲了之後吧該值作爲組合的左邊值時方便直接調用。
        }
    }
    int ans = 0;
    for(int i=0; i<n; i++)
    {
        int mod = (int)node[i].x%7;
        ans += dp[(7-mod)%7][node[i].y][1];//這裏%7也別忘了,比如mod爲0時,(7-mod)%7應該對應0。
        if((node[i].x*multi[node[i].y]%7)==((7-mod)%7))//扣除自己跟自己組合。這裏容易遺漏,比如127,127127也是7的倍數。LZ在這裏糾結了好久。
            ans--;
        for(int j=1; j<10; j++)
        {
            mod = (int)((long long)node[i].x)*multi[j]%7;
            ans+=dp[(7-mod)%7][j][0];
        }
    }
    printf("%d\n",ans/2);
} 

總結

總結一下,這個題目就是採用數組來記錄,因爲左右移動的位置不大,而要求爲7的倍數又可以採用mod來做,範圍都很小,所以可以採用數組來記錄下。這個題目運用確實很巧,平時在項目中一般會採用hashmap嵌套hashmap或嵌套arraryList的方式,這裏當然也可以,但是顯然數組更讓人喜歡一點點(因爲算法題目)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章