1. 程式人生 > 其它 >869. 重新排序得到 2 的冪(回溯 hash表)

869. 重新排序得到 2 的冪(回溯 hash表)

連結:https://leetcode-cn.com/problems/reordered-power-of-2/

題目

給定正整數 N,我們按任何順序(包括原始順序)將數字重新排序,注意其前導數字不能為零。

如果我們可以通過上述方式得到2 的冪,返回 true;否則,返回 false。

用例

示例 1:

輸入:1
輸出:true
示例 2:

輸入:10
輸出:false
示例 3:

輸入:16
輸出:true
示例 4:

輸入:24
輸出:false
示例 5:

輸入:46
輸出:true

提示:

1 <= N <= 10^9

思路

方法1
回溯+位運算
重新排序取2的冪其實可以分解為兩個子問題:

  1. 全排列(回溯)
  2. 判斷序列數字是否為2的冪(位運算)

我一開始的思路是將數字轉化為字串格式(to_string())進行全排列再轉回數字(stoi())判斷
全排列回溯用的交換指定位置
注意字串開頭為0情況的剪枝

class Solution {
public:
	bool reorderedPowerOf2(int n) {
		string s = to_string(n);
		dfs(s, 0);
		return istrue;
	}
private:
	bool istrue = false;
	void dfs(string &s, int index){
		
		if (istrue==true)
			return;
		if (s[0] != '0'){
			int temp = stoi(s);
			int t = temp&(temp - 1);
			if (t == 0)
				istrue=true;
		}
		for (int i = index; i<s.size(); i++){
			swap(s[index], s[i]);
			dfs(s, index + 1);
			swap(s[index], s[i]);
		}
	}
};

中間我對每次替換都進行了判斷 導致很多重複
實際可以只對最後index==s.size()情況下進行判定

class Solution {
public:
	bool reorderedPowerOf2(int n) {
		string s = to_string(n);
		dfs(s, 0);
		return istrue;
	}
private:
	bool istrue = false;
	void dfs(string &s, int index){
		
		if (istrue==true)
			return;
		if (index==s.size()&&s[0] != '0'){
			int temp = stoi(s);
			int t = temp&(temp - 1);
			if (t == 0)
				istrue=true;
		}
		for (int i = index; i<s.size(); i++){
			swap(s[index], s[i]);
			dfs(s, index + 1);
			swap(s[index], s[i]);
		}
	}
};

由於存在重複數,交換效率很低,而且數字轉字串再轉回數字效率較低
所以換了插入構造目標排列的方式代替替換
對於重複的值和初始為0的排列可以直接剪枝
先對所有字元進行排序
注意設定一個訪問陣列
訪問陣列不為0時可以取
重複數字在前一相同數字vis[i]未取情況下不取

class Solution {
public:
	bool reorderedPowerOf2(int n) {
		string s = to_string(n);
		vis.resize(s.size(), 1);//訪問陣列
		sort(s.begin(), s.end());
		return dfs(s, 0, 0);;
	}
private:
	vector<int>vis;
	bool dfs(string &s, int index, int num){
		if (index == s.size()){
			return istwo(num);
		}
		for (int i = 0; i<s.size();++i){
			if ((index == 0 && s[i] == '0') || (i>0 &&vis[i-1]&& s[i] == s[i - 1]) || vis[i] == 0)
				continue;
			num = num * 10 + s[i] - '0';
			vis[i] = 0;
			if (dfs(s, index + 1, num))
				return true;
			num = (num - s[i] + '0') / 10;
			vis[i] = 1;
		}
		return false;
	}
	bool istwo(int n){
		return  (n&(n - 1) )== 0;
	}
};

方法2
預處理+hash表
實際上對於XXX序列重新排序來滿足特定序列的問題 都可以用hash表來儲存序列元素出現次數結果,進行比較
由於10e9範圍內2的冪是固定的(2^30)
我們可以將所有2的冪統計其序列 元素頻率,存在string中(vector也行)放入hash表
然後統計目標數的元素頻率 ,在hash表中查詢比較

class Solution {
public:
    bool reorderedPowerOf2(int n) {
        for(int i=1;i<1e9;i<<=1){
            p.insert(countDigits(i));
        }
        return (p.count(countDigits(n))>0);
    }
    string countDigits(int n){
        string cnt(10,0);//使用string記錄每一位出現頻率
        while(n){
            ++cnt[n%10];
            n/=10;
        }
        return cnt;
    }
    unordered_set<string>p;
};