1.Next Permutation
Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
交换+排序
提供两个易错的例子:
1,4,3,2 -> 2,1,3,4
2,3,1 -> 3,2,1
代码如下:
public class Solution {
public static void nextPermutation(int[] nums){
if(nums == null || nums.length < 2) return;
int pos = nums.length-1,i = pos-1;
while(i >= 0 && nums[i] >= nums[i+1]) i--;
if(i<0) {Arrays.sort(nums); return;}
for(;pos>i;pos--) if(nums[pos]>nums[i]) break;
swap(nums,i,pos);
Arrays.sort(nums,i+1,nums.length);
}
public static void swap(int[] nums,int i,int j){
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
2.
Permutation Sequence
The set [1,2,3,…,n]
contains a total ofn! unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):
"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.
Note: Given n will be between 1 and 9 inclusive.
最容易想到的一种方法就是根据上一题中的nextPermutation依次计算每一个序列,但是这样会超时。
其实是可以直接计算的,我们可以把首位数字看成索引,比如上面的1,2,3就是索引,每个索引这种的排列数为2!那么根据k就能计算索引,对所有的位重复这个过程就能计算出结果
代码如下:
public class Solution {
public String getPermutation(int n, int k) {
StringBuilder res = new StringBuilder();
StringBuilder sb = new StringBuilder();
for(int i = 1;i <= n;i++) sb.append(i);
int count = k,index = 0,fac = fac(n);
for(int i = n;i >= 1;i--){
fac /= i;
index = (count-1)/fac;
res.append(sb.charAt(index));
sb.deleteCharAt(index);
count -= index*fac;
}
return res.toString();
}
public int fac(int n){
int res = 1;
for(int i = 1;i <= n;i++) res *= i;
return res;
}
}
3.Combinations
Given two integers n and k, return all possible combinations ofk numbers out of 1 ...n.
For example,
If n = 4 and k = 2, a solution is:
[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
可以用递归来做,遍历每一个元素,每个元素可选可不选,判断已经选择的元素的数量,如果为k就加入最终结果集合中。代码如下:
public class Solution {
public List<List<Integer>> combine(int n, int k) {
ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
ArrayList<Integer> tmp = new ArrayList<Integer>();
helper(n,k,1,tmp,res);
return res;
}
public void helper(int n,int k,int from,ArrayList<Integer> tmp,List<List<Integer>> res){
if(tmp.size() == k){
res.add(new ArrayList(tmp));
}
for(int i = from; i <= n; i++){
tmp.add(i);
helper(n,k,i+1,tmp,res);
tmp.remove(tmp.size() - 1);
}
}
}
4.Subsets
Given a set of distinct integers,nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3]
, a solution is:
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
求一个集合的子集,这个问题有多种解法。比如第一种方法,利用第3题的方法,一个集合的子集就是从中取出0个元素、1个元素...n个元素的全部情况,但是这种方法效率太低;第二种方法,还是采用第3题的思路,遍历每个元素,它可以加入或者不加入,只不过这里不再是当元素数到k时才加入结果集,而是每次都要加入。代码如下:
第一种方法:
public class Solution {
public List<List<Integer>> subsets(int[] nums) {
ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
ArrayList<Integer> tmp = new ArrayList<Integer>();
res.add(new ArrayList<Integer>());
for(int i=1;i<=nums.length;i++)
helper(nums,i,0,tmp,res);
return res;
}
public void helper(int[] nums,int k,int from,ArrayList<Integer> tmp,List<List<Integer>> res){
int len = nums.length;
if(tmp.size() == k) res.add(new ArrayList<Integer>(tmp));
for(int i = from; i < len; i++){
tmp.add(nums[i]);
helper(nums,k,i+1,tmp,res);
tmp.remove(tmp.size()-1);
}
}
}
第二种方法:
public class Solution {
public List<List<Integer>> subsets(int[] nums) {
ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
ArrayList<Integer> tmp = new ArrayList<Integer>();
helper(nums,0,tmp,res);
return res;
}
public void helper(int[] nums,int from,ArrayList<Integer> tmp,List<List<Integer>> res){
int len = nums.length;
res.add(new ArrayList<Integer>(tmp));
for(int i = from; i < len; i++){
tmp.add(nums[i]);
helper(nums,i+1,tmp,res);
tmp.remove(tmp.size()-1);
}
}
}
5.Subsets II
Given a collection of integers that might containduplicates,nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,2]
, a solution is:
[ [2], [1], [1,2,2], [2,2], [1,2], [] ]涉及到去重问题,去重的思路是这样的,比如有一个数组【abC】,其中C是一串数字,我们在遍历到a时,会对后面的bC以及C进行处理;当我们遍历到b时,会对后面的C进行递归处理,那么如果a和b相同,就会出现重复。
代码如下:
public class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
ArrayList<Integer> tmp = new ArrayList<Integer>();
ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
Arrays.sort(nums);
helper(nums,0,tmp,res);
return res;
}
public void helper(int[] nums,int pos,List<Integer> tmp, List<List<Integer>>res){
res.add(new ArrayList<Integer>(tmp));
for(int i = pos;i < nums.length;i++){
if(i == pos || nums[i] != nums[i-1]){
tmp.add(nums[i]);
helper(nums,i+1,tmp,res);
tmp.remove(tmp.size()-1);
}
}
}
}
6.Permutations
Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3]
have the following permutations:
[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
两种方法,第一种方法比较容易理解,因为每个位置上每个数都有可能出现,递归所有可能即可;第二种方法,采用交换元素的方法。
这里给出第二种的源码:
public class Solution {
public List<List<Integer>> permute(int[] nums) {
if(nums == null || nums.length == 0) return null;
ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
helper(nums,0,res);
return res;
}
public void helper(int[] nums,int pos,List<List<Integer>> res){
if(pos == nums.length){
ArrayList<Integer>tmp = new ArrayList<Integer>();
for(int n:nums) tmp.add(n);
res.add(tmp);
return;
}
Arrays.sort(nums,pos,nums.length);//加上这句之后,得到的序列就是递增的
for(int i = pos;i < nums.length;i++){
swap(nums,pos,i);
helper(nums,pos+1,res);
swap(nums,pos,i);
}
}
public void swap(int[] nums,int i,int j){
if(i == j) return;
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
7.Permutations II
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2]
have the following unique permutations:
[ [1,1,2], [1,2,1], [2,1,1] ]
涉及到去重问题
代码如下:
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
if(nums == null || nums.length == 0) return null;
ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
Arrays.sort(nums);
helper(nums,0,res);
return res;
}
public void helper(int[] nums,int pos,ArrayList<List<Integer>> res){
if(pos == nums.length-1){
ArrayList<Integer> tmp = new ArrayList<Integer>();
for(int n:nums) tmp.add(n);
res.add(tmp);
return;
}
Arrays.sort(nums,pos,nums.length);
for(int i = pos;i < nums.length;i++){
if(i != pos && nums[i] == nums[i-1]) continue;
swap(nums,pos,i);
helper(nums,pos+1,res);
swap(nums,pos,i);
}
}
public void swap(int[] nums,int i,int j){
if(i == j) return;
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}