從正整數 N
開始,我們按任何順序(包括原始順序)將數字重新排序,注意其前導數字不能為零。
如果我們可以通過上述方式得到 2 的冪,返回 true
;否則,返回 false
。
示例 1:
輸入:1 輸出:true
示例 2:
輸入:10 輸出:false
示例 3:
輸入:16 輸出:true
示例 4:
輸入:24 輸出:false
思路:這個題的重點是求出數字的全排列(以0開頭的除外),和數字是否2的冪
首先我們來總結下關於全排列。
這是一個c++函數,包含在頭文件<algorithm>里面,下面是一般用法的基本格式。
1 int a[]; 2 do{ 3 4 }while(next_permutation(a,a+n));
STL提供了兩個用來計算排列組合關系的函數,分別是next_permutation和prev_permutation。首先我們必須了解什么是“下一個”排列組合,什么是“前一個”排列組合。考慮三個字符所組成的序列{a,b,c}。這個序列有六個可能的排列組合:abc,acb,bac,bca,cab,cba。這些排列組合根據less-than操作符做字典順序(lexicographical)的排序。也就是說,abc名列第一,因為每一個元素都小於其后的元素。acb是次一個排列組合,因為它是固定了a(序列內最小元素)之后所做的新組合。同樣道理,那些固定b(序列中次小元素)而做的排列組合,在次序上將先於那些固定c而做的排列組合。以bac和bca為例,bac在bca之前,因為次序ac小於序列ca。面對bca,我們可以說其前一個排列組合是bac,而其后一個排列組合是cab。序列abc沒有“前一個”排列組合,cba沒有“后一個”排列組合。
所以一般在用next_permutation函數之前,都將數字排序好,按照從小到大的順序。
下面來分析下next_permutation函數具體是怎么實現的。
- 從右往左掃描,發現第一個左鄰小於右鄰的數字,稱之為 PartitionNumber, 如上圖,
6
恰好是我們找到的 PartitionNumber . - 依然從右到左進行掃描,發現第一個比 PartitionNumber 要大的數,稱之為 ChangeNumber.而7恰好是我們找到的 ChangeNumber ,需要注意的是,這樣的數一定是存在的,否則的話,就找不到所以的 PartitionNumber 了.
- 交換 PartitionNumber 和 ChangeNumber.這樣一步,會使得新的排列組成的數比舊的排列組成的數要大,當然,新數增長的幅度不一定是最小的.
- 交換之后,將當前ChangeNumber后面的數(或者原來PartitionNumber位置之后的數)從小到大排列一下,如此反轉之后,可以保證,新的排列組成的數的增長幅度在所有的可能中最小.
template<calss BidrectionalIterator> bool next_permutation(BidrectionalIterator first,BidrectionalIterator last) { if(first == last) return false; /* 空區間 */ BidrectionalIterator i = first; ++i; if(i == last) return false; /* 只有一個元素 */ i = last; /* i指向尾端 */ --i; for(;;) { BidrectionalIterator ii = i; --i; /* 以上鎖定一組(兩個)相鄰元素 */ if(*i < *ii) /* 如果前一個元素小於后一個元素 */ { BidrectionalIterator j = last; /* 令j指向尾端 */ while(!(*i < *--j)); /* 由尾端往前找,直到遇到比*i大的元素 */ iter_swap(i,j); /* 交換i,j */ reverse(ii,last); /* 將ii之后的元素全部逆序重排 */ return true; } if(i == first) /* 進行至最前面了 */ { reverse(first,last); /* 全部逆序重排 */ return false; } } }
接着我們討論下,如何判斷一個數是2的冪。
我們知道,1個數乘以2就是將該數左移1位,而2的0次冪為1, 所以2的n次冪(就是2的0次冪n次乘以2)就是將1左移n位, 這樣我們知道如果一個數n是2的冪,則其只有首位為1,其后若干個0,必然有n & (n - 1)為0。(在求1個數的二進制表示中1的個數的時候說過,n&(n-1)去掉n的最后一個1)。因此,判斷一個數n是否為2的冪,只需要判斷n&(n-1)是否為0即可。
那如何判斷是2的多少次方呢
int log2(int value) //遞歸判斷一個數是2的多少次方 { if (value == 1) return 0; else return 1+log2(value>>1); }
下面附上本題的完整代碼
bool reorderedPowerOf2(int n) { int i,j,k,tmp; vector<int> a; a.clear(); while (n>0) { a.push_back(n%10); n/=10; } sort(a.begin(),a.end()); do { if (a[0]==0) continue; tmp=0; for (i=0;i<a.size();i++) tmp=tmp*10+a[i]; if((tmp&tmp-1)==0)return true; }while (next_permutation(a.begin(),a.end())); return false; }