31. Next Permutation + 46. Permutations + 47. Permutations II + 60. Permutation Sequence
▶ 问题:字典序生成有关的问题。
▶ 31. 由当前序列生成字典序里的下一个序列。
● 初版代码,19 ms
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
int i, j, temp;
for (i = nums.size() - ; i > && nums[i - ] >= nums[i]; i--);// 从右向左寻找第一个递增对
if (!i) // i == 0,当前排序已经是最大的,全反序得到最小的
{
for (j = ; i < nums.size() / ; j++)
temp = nums[j], nums[j] = nums[nums.size() - - j], nums[nums.size() - - j] = temp;
return;
}
else if (i == nums.size() - ) // 最后两个元素就是递增对,交换他俩就行
{
temp = nums[i], nums[i] = nums[i - ], nums[i - ] = temp;
return;
}
for (j = nums.size() - ; j >= i && nums[j] <= nums[i - ]; j--);// 其他情形,需要在右侧递减部分中找到比递增较小元更大的第一个元素
temp = nums[i - ], nums[i - ] = nums[j], nums[j] = temp; // 将右侧较大的元素交换到递增对较小元的位置
for (j = i; j < (nums.size() + i) / ; j++) // 右侧进行反序
temp = nums[j],nums[j] = nums[nums.size() + i - - j],nums[nums.size() + i - - j] = temp;
return;
}
};
● 改进代码,15 ms,第二次查找时使用二分法改进,引入原数组长度的常量,引入内置交换函数 std::swap()。
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
const int len = nums.size();
int i, j, temp, lp;
for (i = len - ; i > && nums[i - ] >= nums[i]; i--);
if (!i)
{
for (i = ; i < len / ; i++)
swap(nums[i], nums[len - - i]);
return;
}
else if (i == len - )
{
swap(nums[i], nums[i - ]);
return;
}
for (lp = i, j = len, temp = (lp + j) / ; temp > lp; temp = (lp + j) / )
(nums[temp] > nums[i - ]) ? (lp = temp) : (j = temp);
swap(nums[i - ], nums[lp]);
for (j = i; j < (len + i) / ; j++)
swap(nums[j], nums[len + i - - j]);
return;
}
};
● 大佬的代码,13 ms,使用了排序函数
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
const int len = nums.size();
int i, flag, index;
for (flag = , i = index = len - ; i > ; i--)
{
if (nums[i] <= nums[i - ])
index--;
else
{
for (int j = len - ; j >= index; j--)
{
if (nums[j] > nums[i - ])
{
swap(nums[i - ], nums[j]);
break;
}
}
sort(nums.begin() + i, nums.end());
flag = ;
break;
}
}
if (len && flag)
sort(nums.begin(), nums.end());
}
};
● 偷懒的代码,14 ms,直接使用内置函数 next_permutation(),该函数返回值是一个 bool 变量,仅当输入的数组引用是一个降序时返回 false,但此时仍然将数组调整为字典序的下一个(升序)。
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
next_permutation(nums.begin(), nums.end());
return;
}
};
▶ 46. 生成给定元素的所有排列(元素无重复)
● 自己的代码,13 ms,反复调用第 31 题的结果来进行枚举。
class Solution
{
public:
void nextPermutation(vector<int>& nums)
{
const int len = nums.size();
int i, j, temp, lp;
for (i = len - ; i > && nums[i - ] >= nums[i]; i--);
if (!i)
{
for (i = ; i < len / ; i++)
swap(nums[i], nums[len - - i]);
return;
}
else if (i == len - )
{
swap(nums[i], nums[i - ]);
return;
}
for (lp = i, j = len, temp = (lp + j) / ; temp > lp; temp = (lp + j) / )
(nums[temp] > nums[i - ]) ? (lp = temp) : (j = temp);
swap(nums[i - ], nums[lp]);
for (j = i; j < (len + i) / ; j++)
swap(nums[j], nums[len + i - - j]);
return;
}
vector<vector<int>> permute(vector<int>& nums)
{
int count, i;
vector<vector<int>> output;
for (i = nums.size(), count = ; i > ; count *= i, i--); // 计算阶乘(总共排列数)
sort(nums.begin(),nums.end()); // 排序得到第一个排列
output.push_back(nums);
for (i = ; i < count; i++) // 每次循环生成下一个排列,不合并压入可以优化最后一次函数 nextPermutation()调用
{
nextPermutation(nums);
output.push_back(nums);
}
return output;
}
};
● 大佬的代码,13 ms,使用了内置函数 next_permutation()
class Solution
{
public:
vector<vector<int>> permute(vector<int>& nums)
{
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for (result.push_back(nums); next_permutation(nums.begin(), nums.end());)
result.push_back(nums);
return result;
}
};
▶ 47. 生成给定元素的所有排列(元素有重复)
● 自己的代码,26 ms,原数组排序后统计各重复部分的长度,计算重复排列数。由于前面 31 题中的程序在求“下一个排列”的时候已经跳过了重复的情形,所以只要恰当的减少该函数的调用次数就能列出所有含重复元素的排列。
class Solution
{
public:
void nextPermutation(vector<int>& nums)// 改进
{
const int len = nums.size();
int i, j, temp, lp;
for (i = len - ; i > && nums[i - ] >= nums[i]; i--);
if (!i)
{
for (i = ; i < len / ; i++)
swap(nums[i], nums[len - - i]);
return;
}
else if (i == len - )
{
swap(nums[i], nums[i - ]);
return;
}
for (lp = i, j = len, temp = (lp + j) / ; temp > lp; temp = (lp + j) / )
(nums[temp] > nums[i - ]) ? (lp = temp) : (j = temp);
swap(nums[i - ], nums[lp]);
for (j = i; j < (len + i) / ; j++)
swap(nums[j], nums[len + i - - j]);
return;
}
inline int factorial(int a)// 阶乘函数
{
int i, output;
for (output = , i = ; i <= a; output *= i, i++);
return output;
}
vector<vector<int>> permuteUnique(vector<int>& nums)
{
int count, i, rep;
vector<vector<int>> output;
count = factorial(nums.size()); // 计算重复排列数
sort(nums.begin(), nums.end()); // 排序得到第一个排列
for (i = ; i < nums.size() - ; i++)
{
for (; i < nums.size() - && nums[i] != nums[i + ]; i++); // 跳过相邻项不同的部分
for (rep = ; i < nums.size() - && nums[i] == nums[i + ]; rep++, i++); // 记录本节中相邻项相同的个数
count /= factorial(rep + ); // 重复排列的计算
}
output.push_back(nums);
for (i = ; i < count; i++) // 每次循环生成下一个排列,不合并压入可以优化最后一次函数 nextPermutation()调用
{
nextPermutation(nums);
output.push_back(nums);
}
return output;
}
};
● 大佬的代码,30 ms,回溯,逐个寻找新排列。
class Solution
{
public:
vector<vector<int>> permuteUnique(vector<int>& nums)
{
vector<vector<int>> result; // 存放结果
vector<int> flags(nums.size(), ), content;// flag[i] 表当前 nums[i] 是否被使用,content 为当前排列(填满就送入 reslut)
sort(nums.begin(), nums.end());
helper(nums, content, flags, result);
return result;
} void helper(vector<int>& nums, vector<int>& content, vector<int>& flags, vector<vector<int>>& result)
{
if (content.size() == nums.size())// 所有元素都被使用,将 content 中的排列放入 result 中
{
result.push_back(content);
return;
}
for (int i = ; i < nums.size(); i++)
{
if (i > && nums[i] == nums[i - ] && flags[i - ] != )// 跳过相同的元素
break;
if (!flags[i])// 元素 nums[i] 还没有被谁用过
{
flags[i] = ; // 把元素 nums[i] 添加到当前的排列末尾
content.push_back(nums[i]);
int i1 = i;
while (i < nums.size() - && nums[i + ] == nums[i])// 跳过相同元素
i++;
helper(nums, content, flags, result); // 尝试在添加了元素 nums[i] 以后继续添加下一个元素
content.pop_back(); // 去掉当前添加的元素,由于元素可能重复,所以需要在最后一个元素处标记未使用
flags[i1] = ;
}
}
}
};
● 大佬的代码改进,27 ms,基本算法相同。
class Solution
{
public:
vector<vector<int>> permuteUnique(vector<int>& nums)
{
vector<vector<int>> result;
vector<bool> flags(nums.size(), true);
vector<int> content;
sort(nums.begin(), nums.end());
helper(nums, content, flags, result);
return result;
}
void helper(vector<int>& nums, vector<int>& content, vector<bool>& flags, vector<vector<int>>& result)
{
if (content.size() == nums.size())
{
result.push_back(content);
return;
}
int i, j;
for (i = ; i < nums.size(); i++)
{
if (flags[i])
{
flags[i] = false;
content.push_back(nums[i]);
for (j = i; i < nums.size() - && nums[i + ] == nums[i]; i++);
helper(nums, content, flags, result);
content.pop_back();
flags[j] = true;
}
}
}
};
▶ 60. 求给定元素字典序排列中的第 k 个。
● 初版,108 ms,逐个生成排列,直到第 k 个为止。
class Solution
{
public:
string getPermutation(int n, int k)
{
int i;
vector<int> table(n);
for (i = ; i < n; table[i] = i++);
for (i = ; i < k; i++)
next_permutation(table.begin(), table.end());
string output("");
for (i = ; i < n; i++)
output += table[i] + '';
return output;
}
};
● 改进版,6 ms,利用阶乘计算出所求排列,最快的解法算法与之相同。
class Solution
{
public:
string getPermutation(int n, int k)
{
int i, j;
string ret;
vector<int> factorial(n, );// 阶乘和字符的打表
vector<char> num(n, ); for (i = ; i < n; i++)
factorial[i] = factorial[i - ] * i;
for (i = ; i < n; i++)
num[i] = '' + (i + );
for (i = n, k--; i >= ; i--)
{
j = k / factorial[i - ];
k %= factorial[i - ];
ret.push_back(num[j]);
num.erase(num.begin() + j);
}
return ret;
}
};
31. Next Permutation + 46. Permutations + 47. Permutations II + 60. Permutation Sequence的更多相关文章
- [LeetCode] 47. 全排列 II
题目链接 : https://leetcode-cn.com/problems/permutations-ii/ 题目描述: 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [ ...
- Leetcode之回溯法专题-47. 全排列 II(Permutations II)
Leetcode之回溯法专题-47. 全排列 II(Permutations II) 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [1,1,2] 输出: [ [1,1,2] ...
- [LeetCode] 47. Permutations II 全排列 II
Given a collection of numbers that might contain duplicates, return all possible unique permutations ...
- [Leetcode][Python]47: Permutations II
# -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 47: Permutations IIhttps://oj.leetcode. ...
- [leetcode] 47. Permutations II
Given a collection of numbers that might contain duplicates, return all possible unique permutations ...
- 47. Permutations II
题目: Given a collection of numbers that might contain duplicates, return all possible unique permutat ...
- Leetcode之回溯法专题-46. 全排列(Permutations)
Leetcode之回溯法专题-46. 全排列(Permutations) 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3, ...
- leetcode 46. 全排列 及 47. 全排列 II
46. 全排列 问题描述 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3 ...
- LeetCode 31 Next Permutation / 60 Permutation Sequence [Permutation]
LeetCode 31 Next Permutation / 60 Permutation Sequence [Permutation] <c++> LeetCode 31 Next Pe ...
随机推荐
- HDU 4638 树状数组 想法题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4638 解题思路: 题意为询问一段区间里的数能组成多少段连续的数.先考虑从左往右一个数一个数添加,考虑当 ...
- MySql5.5安装(windows)
首先贴出安装包 32位安装包链接:https://pan.baidu.com/s/1AGLpcKv1I4kvWjPsVMyS8Q 密码:xypy 64位安装包链接:https://pan.baidu. ...
- 【HAOI2010】订货
可以DP也可以是费用流,然而被我用非常简单的DP破了[开心] 原题: 某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付存贮费用m,假定 ...
- JS 中 this 的用法
this是JavaScript语言中的一个关键字 他是函数运行时,在函数体内部自动生成的一个对象, 只能在函数体内部使用. 在不同function中, this有不同的值. 1. 纯粹的函数调用. f ...
- 海思3518EV200 SDK中获取和保存H.264码流详解
/****************************************** step 2: Start to get streams of each channel. ********** ...
- JUC集合之 ConcurrentHashMap
ConcurrentHashMap介绍 ConcurrentHashMap是线程安全的哈希表. HashMap, Hashtable, ConcurrentHashMap之间的关联如下: HashMa ...
- tyvj1659中中救援队
题目:http://www.joyoi.cn/problem/tyvj-1659 发现每条边要走两次,每个点要走它连接的边数次. 所以把边的权值赋成 本身的值+两个端点的点权,求最小生成树即可. !边 ...
- [转]Oracle中trace的几种
Oracle中trace的几种 标签: 杂谈 我们在Oracle中在做troubleshooting的时候,经常要去做跟踪来查错,那今天就介绍几种trace的方法. 在这之前,我先说说10046事 ...
- MySQL性能指标及计算方法(go)
绝大多数MySQL性能指标可以通过以下两种方式获取: (1)mysqladmin 使用mysqladmin extended-status命令获得的MySQL的性能指标,默认为累计值.如果想了解当前状 ...
- python格式化输出 format
看图