leetcode優美的排列

"""
假設有從 1 到 N 的 N 個整數,如果從這 N 個數字中成功構造出一個數組,使得數組的第 i 位 (1 <= i <= N) 滿足如下兩個條件中的一個,我們就稱這個數組爲一個優美的排列。條件:

    第 i 位的數字能被 i 整除
    i 能被第 i 位上的數字整除

現在給定一個整數 N,請問可以構造多少個優美的排列?

來源:力扣(LeetCode)
"""
#直接暴力枚舉所有排列判斷會超時

class Solution(object):
    def solve(self, start, end, strlist, reslist):
        if(start == end):
            flag = 0
            for j in range(end+1):
                if(strlist[j]%(j+1)!=0 and (j+1)%strlist[j]!=0):
                    flag = 1
                    break;
            if(flag == 0):
                reslist.append(strlist)
        for i in range(start,end+1):
            strlist[i], strlist[start] = strlist[start], strlist[i]
            self.solve(start+1, end, strlist, reslist)
            strlist[i], strlist[start] = strlist[start], strlist[i]

    def countArrangement(self, N):
        """
        :type N: int
        :rtype: int
        """
        strlist = list(range(1,N+1))
        #print(strlist)
        reslist = list()
        self.solve(0,N-1,strlist, reslist)
        #print(reslist)
        return len(reslist)
        


#優化後的暴力搜索
#在每次填數的時候就判斷

class Solution(object):
    c=0
    def solve(self, start, strlist):
        #print(start)
        if(start == len(strlist)):
            self.c = self.c + 1
        for i in range(start,len(strlist)):
            #if(strlist[i]%(start+1)==0 or (start+1)%strlist[i]==0) and (strlist[start]%(i+1)==0 or (i+1)%strlist[start]==0):
            strlist[i], strlist[start] = strlist[start], strlist[i]
            if(strlist[start]%(start+1)==0 or (start+1)%strlist[start]==0):
                self.solve(start+1, strlist)
            strlist[i], strlist[start] = strlist[start], strlist[i]

    def countArrangement(self, N):
        """
        :type N: int
        :rtype: int
        """
        strlist = list(range(1,N+1))
        print(strlist)
        self.solve(0,strlist)
        #print(reslist)
        return self.c

 

#回溯
#用bool數組表示是否已經使用過當前數,每次從沒有使用過的數拿一個放到pos,如果滿足條件,繼續下一個,否則換數。

public class Solution {
    int count = 0;
    public int countArrangement(int N) {
        boolean[] visited = new boolean[N + 1];
        calculate(N, 1, visited);
        return count;
    }
    public void calculate(int N, int pos, boolean[] visited) {
        if (pos > N)
            count++;
        for (int i = 1; i <= N; i++) {
            if (!visited[i] && (pos % i == 0 || i % pos == 0)) {
                visited[i] = true;
                calculate(N, pos + 1, visited);
                visited[i] = false;
            }
        }
    }
}

 

# dp,狀態壓縮
"""
思路:用一個n位的二進制數表示二進制中爲1的數字已任意順序放在數組的前m位(m爲該二進制數中1的個數)。
例子:二進制數010101,第1,3,5位是1,一共3個1,所以表示1,3,5以任意順序放在數組前3位。
狀態:dp[n]表示二進制數n代表的所有排列中有效情況的數量。
更新狀態:對於二進制中爲0的位,判斷是否可以作爲下一個放入數組中的數,若是則更新dp[n | (1 << j)] += dp[n]
例子:010101中,第2位爲0,判斷其是否可放在數組第4位(因爲數組已有3個數),顯然可以(4%2==0),更新dp[010101 | (1 << (2-1))] += dp[010101];
即dp[010111] += dp[010101];
"""

int countArrangement(int N) {
        vector<int> dp(1 << N,0);
        //每個數都能放在第1位
        for(int i = 0;i < N;++i)
        {
            dp[1 << i] = 1;
        }
        for(int i = 0;i < (1 << N);++i)
        {
            int index = 1;
            int temp = i;
            //計算1的個數
            while(temp)
            {
                temp &= temp-1;
                ++index;
            }
            for(int j = 0;j < N;++j)
            {
                //二進制位爲0(未被選取),且能放在第index位
                if(!(i & (1 << j)) && ((j+1) % index == 0 || index % (j+1) == 0))
                {
                    dp[1 << j | i] += dp[i];
                }
            }
        }
        return dp[(1 << N) -1];
    }

 

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