869.重新排序得到2的幂
题目
给定正整数 n
,我们按任何顺序(包括原始顺序)将数字重新排序,注意其前导数字不能为零。
如果我们可以通过上述方式得到 2
的幂,返回 true
;否则,返回false
。
数据范围
1 <= n <= 109
分析
可以dfs
,懒得写dfs
就使用next_permutaion()
函数吧,注意使用这个函数要对数组进行升序排列以及do{}while()
循环,不然无法得到所有的全排列,然后判断一下前导零的情况
代码
typedef long long ll;
class Solution {
public:
ll num[100];
ll pow2[100];
void init() {
pow2[0] = 1;
for(ll i = 1; i <= 30; i ++ ) {
pow2[i] = pow2[i - 1] * 2;
}
}
ll getVal(ll n) {
ll res = 0;
for(ll i = n; i >= 1; i -- ) {
res = res * 10 + num[i];
}
return res;
}
bool check(ll k) {
for(ll i = 0; i <= 30; i ++ ) {
if(k == pow2[i]) return true;
}
return false;
}
ll qpow(ll a, ll n) {
ll res = 1;
while(n) {
if(n % 2) res = res * a;
a = a * a;
n /= 2;
}
return res;
}
bool reorderedPowerOf2(ll n) {
init();
ll cnt = 0;
while(n) {
num[++ cnt] = n % 10;
n /= 10;
}
sort(num + 1, num + cnt + 1);
do {
ll k = getVal(cnt);
if(k < qpow(10, cnt - 1)) continue;
if(check(k)) {
return true;
}
} while(next_permutation(num + 1, num + cnt + 1));
return false;
}
};
153.寻找旋转排序数组中的最小值
题目
已知一个长度为 n
的数组,预先按照升序排列,经由 1
到 n
次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7]
在变化后可能得到:
若旋转 4
次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7
次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]]
旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]
。
给你一个元素值 互不相同 的数组 nums
,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为O(log n)
的算法解决此问题。
数据范围
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums
中的所有整数 互不相同nums
原来是一个升序排序的数组,并进行了1
至n
次旋转
分析
容易发现旋转后的数组有个性质,即是由两段升序子数组拼接而成,这是可以封为两种情况
- 当
nums[0]<nums[nums.size()-1]
时,则整个数组升序,最小的值就是num[0]
- 当
nums[0]>nums[nums.size()-1]
时,只需要找到两个升序子数组的分割点即可,这时可以知道左边升序子数组一定是都大于右边升序子数组的,否则就不满足有升序数组旋转得到,因此问题可以转化为找到比nums[0]
小的第一个数即可,使用二分很容易找到
代码
class Solution {
public:
int find(int x, int n, vector<int> &nums) {
int l = 0, r = n;
while(l < r) {
int mid = (l + r) >> 1;
if(nums[mid] < x) r = mid;
else l = mid + 1;
}
return r;
}
int findMin(vector<int>& nums) {
if(nums[0] < nums[nums.size() - 1]) return nums[0];
int pos = find(nums[0], nums.size() - 1, nums);
return nums[pos];
}
};