近期筆試小結(附數據庫工程師面試準備)

《網易 0912》html

也不知道在網易招聘官網怎麼投了個數據庫管理工程師的,不過仍是認真的作了其筆試題。mysql

選擇題不說了,兩道編程題難度通常,需細心!ios

1.買蘋果面試

下面都是比較直接的作法,其實能夠考慮使用揹包模型去作。算法

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int n;
    while(cin>>n){
        int result=0;
        if(n<6)
        {
            cout<<-1<<endl;
            return 0;
        }
    
        while(n>0)
        {
            if(n%8==0)
            {
                result+=n/8;  
                break;
            }
            else
            {
                n-=6;
                if(n>=0)
                result++;
            }
        }
        if(n>=0)
            cout<<result<<endl;
        else
            cout<<-1<<endl;
    }
   
    return 0;
}

或(因爲範圍比較小能夠直接枚舉6個和8個的袋數維護最小值便可。時間複雜度:O(n^2/48) ):sql

#include <iostream>
#include <cstdio>

using namespace std;

int main(){
    int n, res = 10000;
    while(cin >> n){
        for(int i = 0; i <= 20; i++){
            for(int j = 0; j <= 20; j++){
                if(i * 6 + j * 8 == n){
                    res = min(res,(i + j));
                }
            }
        }
        if(res == 10000) res = -1;
        cout << res << endl;
    }
    
    return 0;
}

  

2.最大奇約數
數據庫

題意:編程

定義函數f(x)爲x的最大奇數約數,x爲正整數,例如f(44) = 11.如今給出一個N,須要求出f(1) + f(2) + f(3) + ... + f(N)緩存

例如: N = 7,則f(1) + f(2) + f(3) + f(4) + f(5) + f(6) + f(7) = 1 + 1 + 3 + 1 + 5 + 7 = 21.服務器

分析:易知奇數的最大奇約數是其自身, 而偶數的最大奇約數是是除去全部偶因子後的那個奇數。最直觀的想法就是挨個遍歷求各個數的最大奇約數的和。

然而很明顯,時間複雜度知足不了要求

#include <iostream>
using namespace std;

int main() {
    long long N;
    while(cin >> N){
        long long res = 0;
        for (long long i = 1; i <= N; ++i) {
            int temp = i;
            while (temp % 2 == 0) {
                temp /= 2;
            }
            res += temp;
        }
        cout << res << endl;
    }
    
    return 0;
}

須要找規律進行改進,記F(N)=f(1) + f(2) + f(3) + ... + f(N),觀察會發現,

若是N爲奇數,則f(2)+f(4)+...+f(N-1)=f(1) + f(2) + f(3)+...+f((N-1)/2)

那麼F(N) = 1 + 3 + 5 + ....+N + f(2) + f(4)+...+f(N-1)=F((N-1)/2)+(N+1)*(N+1)/4

若是N爲偶數,則F(N)=1+3+5+...+(N-1)+f(2)+...+f(N)=F(N/2)+N*N/4

#include<iostream>
using namespace std;

long long sum(long long n) {
    if (n == 1) {
        return 1;
    }
    if (n % 2 == 0) {
        return  sum(n / 2) + n * n / 4;
    }
    else {
        return sum((n-1)/2) + (n+1)*(n+1)/4;
    }
}
int main() {
    int N;
    while(cin >> N){
        cout << sum(N) << endl;
    }
}

 也能夠將奇偶統一能夠寫出更簡潔的代碼,以下:

#include <iostream>
using namespace std;

long long n;
long long sum(long long n){
    if(n == 0) return 0;
    return (long long)( (n + 1) / 2) * ( (n + 1) / 2) + sum(n / 2);
}
int main(){
    while(cin >> n){
        cout << sum(n) << endl;
    }
    return 0;
}

這樣每次計算問題規模減半,時間複雜度爲:O(log(n))  

 

3.聚簇索引的特色 

4.設計一個簡單的論壇系統的數據庫

這個其實網上有不少比較好的參考資料了:

論壇數據庫的設計(寫得很好)

總結幾種經常使用的論壇設計方法:

  • 分割思想:

(1)數據庫切分:用戶庫、主題庫、回覆庫

(2)數據表水平切分:用戶庫1-n、主題庫1-n、回覆庫1-n (好比按時間分)
(3)分佈式數據庫:每臺計算機中都有DBMS的一份完整拷貝副本,並具備本身局部的數據庫,位於不一樣地點的許多計算機經過網絡互相鏈接,共同組成一個完整的、全局的大型數據庫。

(4)論壇功能能夠進行分隔,不一樣的服務器負責不一樣的功能

(5)用主從數據庫,master是寫, slave是讀

(6)把內容與其它信息分開,好處就是可讓每一個表的文件最小化,對數據庫操做壓力會減少,這樣保證每張表數據量很小,操做速度會快,也能夠在這裏使用緩存

  • 索引:

針對是否創建索引有着必定的分歧:

我的以爲創建索引仍是頗有必要的。理由以下:

(1)創建索引能夠加快檢索速度,對於論壇讀和寫的比例相差很大,用戶體驗固然是讀多寫少,因此綜合考慮仍是要用索引,並且是加在經常使用的讀關鍵字上。

(2)索引之因此會下降更新的速度,是由於更新還包括對索引的更新,從更新帖子10萬左右,這句話是說,咱們可能對發帖標題,發帖內容,回覆標題,回覆內容這4個字段作更新。須要注意的是,這四個字段並非用來創建錶鏈接的字段,爲了優化查詢速度咱們不會在這四個字段上創建索引,因此從這道題目出發,咱們創建的索引不會影響更新帖子的性能。只要被索引的列(例如回覆表的標題ID)不被頻繁更新,即便索引所在地行的其它列被頻繁update,索引也不會被更新從而產生性能消耗,一張表一天30萬次的索引更新,因它引發的性能消耗小到即便數據庫安裝在奔騰3單核CPU下都能輕鬆承擔下來。

(3)對於更新的速度慢的問題,咱們有解決的方法,你提交更新了後,前臺可讓程序返回一個正確結果,後臺開個線程異步慢慢跟新數據庫就是了,反正更新成功的前提就是假設數據庫鏈接永遠正確並處於可靠狀態。在數據庫和用戶之間創建一個緩衝區。(如,將更新的數據放到內存中,達到必定數量的時候再統一更新數據庫。假如以100條爲例,一旦內存中達到100條數據量將這100條數據統一入庫。減小insert操做)

  • 緩衝: 

讀的時候的緩衝:緩存路由表

           主題緩存表(這個取每一個區的前面100條記錄),通常來講負載最大的就是主題的第一頁,因此緩存表是個小表。 

    另外使用hibernate,在數據庫上面加了一層緩存。

           生成靜態頁,緩存最熱,最新的帖子。

          對於常常更新的數據都設計成單獨表 ,這樣能夠最大程度的利用hibernate緩存

          緩存經常使用的數據和表,利用緩存來將常常被訪問的帖子留在內存中,爲每條緩存的記錄添加一個訪問時間,若是長時間沒被訪問就從緩存中刪除掉,

          避免內存過大,每次用戶看帖的時候,首先檢索緩存中時候有須要的帖子,沒有的話再訪問數據庫,而後將數據庫返回的帖子信息存儲到緩存中。
寫的時候的緩衝:數據庫和用戶之間創建緩存,將更新的數據放在內存中,異步操做的。全部的寫貼操做 放到一個隊列而後批量執行插入數據庫操做。 

預估計的緩衝:假如用戶第一次打開某標題,那將此標題的相關的前100條數據緩存到客戶斷。這樣避開對數據庫的直接查詢,減小數據庫壓力。

  • 代碼優化 

儘可能避免表的鏈接約束經過代碼來實現約束 例如用戶id的驗證在用戶登陸時驗證這樣就能夠把帖子表的用戶id外鍵去掉這樣就成了單表操做、查詢 而鏈接能夠經過觸發來實現這樣最可能是查詢了3個表而不是鏈接中的笛卡爾笛卡爾積  回覆表的查詢限定每次查詢的記錄數例如限定10條其它的經過點擊觸發來操做"注代碼優化容易出現bug 緣由有些開發工具自己有優化" 

  • 數據庫性能調優 

儘可能用硬件來代替軟件優化 原則就是能用硬件的儘可能用硬件 好比磁盤陣列 RAID0 有條件用RAID10 加大內存 .避免小表上建索引 對論壇來講數據帖子和回覆不是很重要 能夠按期刪除一些垃圾帖子 樓主說的幾百萬條記錄的論壇對如今的數據庫管理系統和計算機來講永不着刻意的優化,按期維護打包備份數據庫就能夠了

提升速度的關鍵: 
(1)創建合理的索引並在查詢時充分利用; 
(2)避免使用關聯,這樣避免整表掃描;使用關聯不如屢次使用主鍵查詢來的快; 
(3)一些處理的功能儘量放到內存中來作,好比組織主題和回覆; 
(4)海量緩存(使用靜態頁面也是個不錯的作法)

(5)按期對錶進行轉儲

 

數據庫面試相關準備題

4.存儲過程和函數的區別是什麼?

5.什麼是數據庫事務?

6.遊標的做用是什麼,如何知道遊標已經到了最後?

7.觸發器

8.什麼叫SQL注入式攻擊,如何防範?

9.解釋聚簇索引和非聚簇索引之間的區別?

10.SELECT INTO 和 INSERT INTO SELECT 兩種表複製語句

11.SQL 中GO的做用

每一個被GO分隔的語句都是一個單獨的事務,一個語句執行失敗不會影響其它語句執行。

12.SQL中的case when then else end用法

13.一點實例明白mysql數據庫存儲過程 

14.數據庫中最經常使用的是哪兩種併發控制協議?

數據庫併發控制 你選樂觀鎖仍是悲觀鎖?

15.

----------------------------------- 

《新美大0911》

1.收紅包問題

題意:在一個桌子上放了若干個數值不等的紅包,圍成一個圈,如今讓你選取若干個紅包,要求相鄰的兩個紅包不能同時選取,編程求出選取紅包所得錢數的最大值;

輸入:

2

1,2,3

1,2,3,4

輸出:

3

6

分析:

按順序依次選取紅包,則每一個位置都有兩種狀態,選取和不選取,最終要使紅包錢數最大化,能夠用動態規劃的思想來解決。在動態規劃中,每一步的選擇都是前面全部步驟的總結,每一步選擇最優從而使最終方案最優。DP算法的這種本質決定了問題必須是線性結構,不過本問題是環狀結構,第一個紅包(指邏輯上的第一個,其實環上的任何一個紅包均可以做爲第一個)的狀態不只會影響第二個紅包的狀態,還會影響最後一個紅包的狀態,那麼要先將環狀結構轉化爲線性結構,具體的實現方式是:

(1)選取第一個紅包的全部方案:選取第一個紅包,從而第二個紅包和最後一個紅包都不能選取,剩餘紅包的狀態不肯定;

(2)不選取第一個紅包的全部方案:不選取第一個紅包,那麼剩下的紅包狀態都不肯定。

若桌上某個位置的紅包被選取,那麼其後一個位置的紅包就不能選取;若某一位置的紅包未選取,其後一個位置的紅包就能夠選取,也能夠不被選取。DP轉移方程:

 -> dp[i+1][0]=max(dp[i][0],dp[i][1]);

  -> dp[i+1][1]=dp[i][0] ;

其中i表示紅包的索引,第二維中的0表示不選取第i個紅包,1表示選取第i個紅包,即第二維用來表示紅包的兩種狀態;

而dp[i][0]表示從紅包0到紅包i中選取紅包,而且不選取紅包i,獲得的紅包錢數最大值;dp[i][1]表示從紅包0到紅包i中選取紅包,而且選取紅包i,所獲得的紅包錢數最大值。---算法時間複雜度爲O(n)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> Hbao;

int Choose(int begin, int end)
{
    if (end < begin) return 0;
    int dp[2], temp;
    dp[0] = dp[1] = 0;
    for (int i = begin; i <= end; i++)
    {
        temp = dp[0];
        dp[0] = max(dp[0], dp[1]);
        dp[1] = temp + Hbao[i];
    }
    return max(dp[0], dp[1]);
}

int main()
{
    int t, n, val, res;
    cin >> t;
    while (t--)
    {
        cin >> val;
        Hbao.push_back(val);
        while (cin.get() == ','){
            cin >> val;
            Hbao.push_back(val);
        }
        n = Hbao.size();
        //1.選取紅包0,而後對紅包2到紅包n-2進行DP
        res = Hbao[0] + Choose(2, n - 2);
        //2.不選取紅包0,而後對紅包1到紅包n-1進行DP
        res = max(res, Choose(1, n - 1));
        cout << res << endl;
        Hbao.clear();
    }
    
    return 0;
}

 

可參考:http://blog.csdn.net/lrgdongnan/article/details/52506373 

相關文章
相關標籤/搜索