力扣31
法1:
从倒数第二个数开始查找,一直找到比下一个数要小的数的下标,假设为i,然后翻转i+1到n-1(n=arr.size())的所有数,接着有两种情况:
1、i==1:直接结束函数
2、利用二分法(C++有upper_bound)找到第一个大于arr[i]的数,然后互相交换。代码:
class Solution {
public:
void re(vector<int> &nums, int l, int r){
if(l>=r) return;
for(; l<r; l++,r--){
nums[l] ^= nums[r] ^= nums[l] ^= nums[r];
}
}
void nextPermutation(vector<int>& nums) {
int n = nums.size();
int i = n-2;
for(; i>=0; i--){
if(nums[i]<nums[i+1])
break;
}
re(nums, i+1, n-1);
if(i!=-1){
int index = upper_bound(nums.begin()+1+i, nums.end(), nums[i]) - nums.begin();
nums[i] ^= nums[index] ^= nums[i] ^= nums[index];
}
}
};
法2:
直接利用STL提供的函数(刺激):
class Solution {
public:
void nextPermutation(vector<int>& nums) {
next_permutation(nums.begin(), nums.end());
}
};
力扣5749
这道题的话就是下k个排列+排列到指定序列的最少次数合并。
首先怎么找第k个排列这个没啥好说,就是运行k次力扣31。
然后至于怎么排列到指定序列的最少次数,我的做法就是首先将原始序列每个数字转化为从0开始的有序序列,比如原始序列为5859, 则对应0123, 数字5有0和2两个数字,8有1,9有3,如果第k个序列为9855,则k个序列将被转化为3102,然后将3102按照普通的冒泡排序的做法,就可以求出排序需要的最少次数。下面上代码:
class Solution {
public:
void next(vector<int> &arr){
int i = arr.size()-2;
for(; i>=0 && arr[i]>=arr[i+1]; i--);
for(int l=i+1, r=arr.size()-1; l<r; l++,r--)
arr[l] ^= arr[r] ^= arr[l] ^= arr[r];
int k = upper_bound(arr.begin()+i+1, arr.end(), arr[i]) - arr.begin();
arr[i] ^= arr[k] ^= arr[i] ^= arr[k];
}
int getMinSwaps(string num, int k) {
int n = num.size();
vector<int> arr(n), ori(n);
for(int i=0; i<n; i++){
arr[i] = num[i]-'0';
ori[i] = num[i]-'0';
}
while(k--){
next(arr);
}
return fun(ori, arr);
}
int fun(vector<int> &ori, vector<int> &tar){
int diff = 0;
int n = ori.size();
for(; diff<n && ori[diff]==tar[diff]; diff++);
if(diff==n) return 0;
vector<vector<int>> temp(10, vector<int>());
vector<int> size(10, 0);
for(int i=diff, id=0; i<n; i++, id++){
temp[ori[i]].push_back(id);
}
for(int i=diff; i<n; i++){
tar[i] = temp[tar[i]][size[tar[i]]++];
}
//bubbo
int res = 0;
for(int i=0; i<n-diff-1; i++){
bool flag = false;
for(int j=diff; j<n-i-1; j++){
if(tar[j]>tar[j+1]){
res++;
tar[j] ^= tar[j+1] ^= tar[j] ^= tar[j+1];
flag = true;
}
}
if(!flag) break;
}
return res;
}
};