排列組合相關筆試面試題(C++)

一、常考點
含有相同元素的全排列:例如2個a,3個b,4個c可以組成多少個不同的字符串?9!/2!/3!/4!。
n個人的全排列:排成一排爲n!,排成一圈且考慮旋轉帶來的差異也爲n!,排成一圈但不考慮旋轉差異則爲(n-1)!
二、普通排列組合練習題
1、X*Y的方格陣中,從左上角走到右下角,每次只能走一格且只能向右走或向下走,有多少種走法
解法:向右一定走Y-1步,向下一定走X-1步,總共要走X+Y-2步,走法有C(X+Y-2,X-1)種。
當n<=10時:
組合數的計算方法一(利用遞歸公式):
classRobot {
public:     
    intC(intn,intm) {
        if(m == 1)
            returnn;
        if(m == n || m == 0)
            return1;
        returnC(n-1,m-1)+C(n-1,m);
    }
     
    intcountWays(intx, inty) {       
        returnC(x+y-2,x-1);
    }
};
組合數的計算方法二(利用定義):
class Robot {
public
:
    int countWays(int x, int y) {        
        int n1 = 1,n2 = 1;
        for (int i = 1,j = x+y-2;i <= x-1;i++,j--) {
            n1 *= i;
            n2 *= j;
        }
        return n2/n1;
    }
};

3、n個人站隊,他們的編號依次從1到n,要求編號爲a的人必須在編號爲b的人的左邊,但不要求一定相鄰,請問共有多少種排法?第二問如果要求a必須在b的左邊,並且一定要相鄰,請問一共有多少種排法?
解法:
classStandInLine {
public:
    // 計算組合數 
    intC(intn,intm) {
        if(m == 1)
            returnn;
        if(m == n || m == 0)
            return1;
        returnC(n-1,m-1)+C(n-1,m);
    }
    // 計算階乘
    intA(intn,intm) {
        intres = 1;
        for(inti = n;i > n-m;i--) {
            res *= i;
        }
        returnres;
    }
     
    vector<int> getWays(intn, inta, intb) {
        vector<int> res;
        res.push_back(A(n-2,n-2)*(C(n-1,2)+C(n-1,1)));
        res.push_back(A(n-1,n-1));
        returnres;
    }
};

4、n顆相同的糖果,分給m個人,每人至少一顆,問有多少種分法。
解法:○○|○○○○○|○○○這10顆糖中間有9個空,插兩個隔板,分成3分,有C(9,2)種分法。
classDistribution {
public:
    intComb(intn,intm) {
        if(n == 0&& m == 0) return1;
        if(m == 1) returnn;
        if(m == n || m == 0) return1;
        returnComb(n-1,m-1)+Comb(n-1,m);
    }
     
    intgetWays(intn, intm) {
        returnComb(n-1,m-1);
    }
};

三、複雜排列組合練習題
1、卡特蘭數
當問題可以表示成以下兩種形式時,就是卡特蘭數問題。f(n)= C(2*n,n)/(n+1)。
①f(n) = f(0)*f(n-1)+ f(1)*f(n-2)+……+ f(n-2)*f(1)+ f(n-1)*f(0);
②f(n) = C(2*n,n)-C(2*n,n+1)。

2、n對左右括號,請求出合法的排列有多少個
解法:將左括號記爲1,右括號記爲-1,則n對左右括號的序列就是1、-1序列,從左到右遍歷該序列,並將遍歷元素值疊加記爲sum,假設遍歷到第j個時sum=0說明在j的左邊除了與j配對的括號對合法外,已遍歷的j/2-1對括號也是合法的括號序列,剩下的(2n-j)/2對括號也是合法的括號序列,則這種情況的組合總數爲f(j/2-1)*f(n-j/2),依次類推可知f(n) = f(0)*f(n-1)+ f(1)*f(n-2)+……+f(j/2-1)*f(n-j/2)+……+ f(n-2)*f(1)+ f(n-1)*f(0) = C(2*n,n)/(n+1)。

classParenthesis {
public:
    intComb(intn,intm) {
        if(n == 0) return0;
        if(m == 1) returnn;
        if(m == n || m == 0) return1;
        returnComb(n-1,m-1)+Comb(n-1,m);
    }
     
    intcountLegalWays(intn) {
        returnComb(2*n,n)/(n+1);
    }
};

3、n個數進出棧的順序有多少種
解法:假設進棧前的序列中第i個數在出棧後的序列中也在第i個位置,則說明前i-1個數完成進棧出棧操作後第i個數才進棧出棧,也就是說問題可描述爲f(n) = f(0)*f(n-1)+ f(1)*f(n-2)+……+ f(n-2)*f(1)+ f(n-1)*f(0)。

class Stack {
public:
    int countWays(int n) {
        int c1 = 1,c2 = 1;
        for (int i = 1;i <= n;i++)
            c1 *= i;
        for (int j = n+1;j <= 2*n;j++)
            c2 *= j;
        return c2/(c1*(n+1));
    }
};

4、以下問題均是卡特蘭數問題
2n個人排隊買票,n個人拿5塊錢,n個人拿10塊錢,票價是5塊錢1張,每個人買一張票,售票員手裏沒有零錢,問有多少種排隊方法讓售票員可以順利賣票。
求n個無差別的節點構成的二叉樹有多少種不同的結構?
12個高矮不同的人,排成兩排,每排必須是從矮到高排列,而且第二排比對應的第一排的人高,問排列方式有多少種?

5、有n個信封,包含n封信,現在把信拿出來,再裝回去,要求每封信不能裝回它原來的信封,問有多少種裝法?
解法:假設第i封信裝入第1個信封,則剩下的信和信封有兩種情況:①第1封信恰好也裝入了第i個信封,問題爲f(n-2);②第1封信沒有裝入第i個信封,問題爲f(n-1)。而i有n-1種選擇,所以原問題可以表示爲f(n)=(n-1)(f(n-1)+f(n-2))。

class CombineByMistake {
public
:
   int countWays(int n) {
        if (n == 1
            return 0;
        if (n == 2)
            return 1;
        long f1 = 0,f2 = 1;
        long mod = 1000000007;
        for (int i = 3;i <= n;i++) {            
            long temp = (i-1)*(f1+f2)%mod;
            f1 = f2;
            f2 = temp;
        }        
        return (int)f2;
    }
};

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