Description:

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]
] Thoughts:
这个问题和之前的permutations问题类似,区别在于这次给定的数字有重复的部分,但是我们输出的排列又不允许重复。排列的话,一个数字不允许重复使用,之前在permutions中我们用Nums.contains来规避这个问题,但是在现在这个问题中因为
nums中有重复的数字,所以这个方法不行了,解决的办法是我们开辟一个和nums等长的boolean数组addnums,addnums中值为true,表示nums中对应位置上的数字已经被包含在排列中,就要跳过这个数字。通过这个方法我们就解决了基本的排列问题。
还有一个问题需要解决的就是排列不允许重复,这个问题的解决方法就是跳过那些已经作为首数字出现过的数字。首先我们对于原始数组进行一次排序,然后在每次选择数字的时候判断,对于大于首字符的数字是否等于首字符,并且还没有使用过,
如果是的话就跳过。以下是我的java代码:
package middle;
import java.util.*;
public class PermutationTwo {
public List<List<Integer>> permuteUnique(int[] nums){
List<List<Integer>> result = new ArrayList<List<Integer>>(); Arrays.sort(nums);
ArrayList addnums = new ArrayList();
trackBack(nums, new ArrayList(), result, addnums);
return result;
} private void trackBack(int[] nums, ArrayList arrayList,
List<List<Integer>> result, ArrayList addnums) {
// TODO Auto-generated method stub
if(arrayList.size()==nums.length && result.contains(arrayList)==false){
result.add(new ArrayList(arrayList));
}
for(int i = 0; i<nums.length;i++){
// if(i > 0 && nums[i] == nums[i-1]) continue;
if(addnums.contains(i)) continue;
arrayList.add(nums[i]);
addnums.add(i);
trackBack(nums, arrayList, result, addnums);
arrayList.remove(arrayList.size() - 1);
addnums.remove(addnums.size() - 1);
}
} public List<List<Integer>> permuteUniqueTwo(int[] nums){
List<List<Integer>> result = new ArrayList<List<Integer>>(); Arrays.sort(nums);
trackBackTwo(nums, result, new ArrayList(), new boolean[nums.length]); return result;
} private void trackBackTwo(int[] nums, List<List<Integer>> result,
ArrayList arrayList, boolean[] use) {
// TODO Auto-generated method stub
if(arrayList.size() == nums.length){
result.add(new ArrayList(arrayList));
}else{
for(int i = 0; i< nums.length;i++){
if(use[i] || i > 0&&nums[i] == nums[i-1]&&use[i-1]==false) continue;
use[i] = true;
arrayList.add(nums[i]);
trackBackTwo(nums, result, arrayList, use);
arrayList.remove(arrayList.size() - 1);
use[i] = false;
}
}
} public static void main(String args[]){
PermutationTwo p = new PermutationTwo();
int[] nums = new int[]{1, -1, 1, 2, -1, 2, 2, -1};
List<List<Integer>> list = p.permuteUniqueTwo(nums);
System.out.println(list);
} }

还有第二种更加直观的解法,但是它的执行时间太慢了,leetcode上通过不了,但是为了更加便于理解我还是把它写出来。解决重复数字的问题,我是用一个ArrayList记录当前已经使用过的数字的位置,如果当前数字的位置在ArrayList中已经
出现过了,那就说明当前的数字已经用过了,就要跳过。然后我们根据得到的排列,判断当前的排列是否包含在result中,如果包含了,也就是说当前的排列已经出现过了,那么该排列就不能加入到result中。换句话说,只有新的排列才能够出现在result
中。以下是我的java代码:
package middle;
import java.util.*;
public class PermutationTwo {
public List<List<Integer>> permuteUnique(int[] nums){
List<List<Integer>> result = new ArrayList<List<Integer>>(); Arrays.sort(nums);
ArrayList addnums = new ArrayList();
trackBack(nums, new ArrayList(), result, addnums);
return result;
} private void trackBack(int[] nums, ArrayList arrayList,
List<List<Integer>> result, ArrayList addnums) {
// TODO Auto-generated method stub
if(arrayList.size()==nums.length && result.contains(arrayList)==false){
result.add(new ArrayList(arrayList));
}
for(int i = 0; i<nums.length;i++){
// if(i > 0 && nums[i] == nums[i-1]) continue;
if(addnums.contains(i)) continue;
arrayList.add(nums[i]);
addnums.add(i);
trackBack(nums, arrayList, result, addnums);
arrayList.remove(arrayList.size() - 1);
addnums.remove(addnums.size() - 1);
}
} public static void main(String args[]){
PermutationTwo p = new PermutationTwo();
int[] nums = new int[]{1, -1, 1, 2, -1, 2, 2, -1};
List<List<Integer>> list = p.permuteUnique(nums);
System.out.println(list);
} }

PermutationTwo的更多相关文章

随机推荐

  1. Uva - 506 - System Dependencies

    模拟题,注意显示安装和隐式安装,显示安装的必须显示显示删除.把名字转化为整数维护.其他注意都注释了.输入稍微多一下,题目不是很麻烦. AC代码: #include <iostream> # ...

  2. Linux Debugging(四): 使用GDB来理解C++ 对象的内存布局(多重继承,虚继承)

    前一段时间再次拜读<Inside the C++ Object Model> 深入探索C++对象模型,有了进一步的理解,因此我也写了四篇博文算是读书笔记: Program Transfor ...

  3. 访问日志IO性能优化

    在高并发量的场景下磁盘IO往往是性能的瓶颈所在,访问日志涉及到频繁的写操作,所以这部分要尽可能地优化,不然将拖累系统的整体性能.针对文件记录及数据库记录两种方式可以有以下措施提高写性能, l 避免频繁 ...

  4. Linux Android 多点触摸协议 原文出自【比特网】,转载请保留原文链接:http://soft.chinabyte.com/os/71/12306571.shtml

    为了使用功能强大的多点触控设备,就需要一种方案去上报用户层所需的详细的手指触摸数据.这个文档所描述的多点触控协议可以让内核驱动程序向用户层上报任意多指的数据信息. 使用说明 单点触摸信息是以ABS承载 ...

  5. jenkins新建slave

    (1)linux-ssh方式 请确保slave账户的java为1.6版本,其中1.3.4.6.7.8.9为必填项. (2)windows-jnlp方式 (1)与ssh方式不同,windows节点请先在 ...

  6. (NO.00001)iOS游戏SpeedBoy Lite成形记(十一)

    之前的10篇内容主要实现了选手从起点移动至终点的动作,比较随机的模拟了选手的速度变化,另外完成了选手到达终点时该做的事情. 接下来的几篇中我们进一步完善SpeedBoy Lite项目,使它真正成为一个 ...

  7. Django访问量和页面点击数统计

    http://blog.csdn.net/pipisorry/article/details/47396311 下面是在模板中做一个简单的页面点击数统计.model阅读量统计.用户访问量统计的方法 简 ...

  8. 不错的东西: AutoMapper

    详细信息可阅读原文:http://csharppulse.blogspot.in/2013/08/crud-operations-using-automapper-in-c_381.html 这东西可 ...

  9. Java-ServletResponse-ServletResponseWrapper

    /** * Defines an object to assist a servlet in sending a response to the client. * The servlet conta ...

  10. android 自定义gallerey并实现预览功能

    自从Gallery被谷歌废弃以后,Google推荐使用ViewPager和HorizontalScrollView来实现Gallery的效果.的确HorizontalScrollView可以实现Gal ...