LintCode 16. 带重复元素的排列

写在前面:这题和全排列不含重复元素的那题几乎一样,我比较垃圾,就用HashSet去掉了重复的元素但是看了九章算法的答案也没看懂,他写的很有感觉。

用了hash,本来想着怎么写hashcode()和equal()方法的,哪知道都帮我写好了,Integer类型的元素存储在List中的hashcode()和equal()的方法可以直接使用
下面是源代码和我的测试代码:

//这是ArrayList父类public abstract class AbstractList<E>中的源码
public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }

public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;

        ListIterator<E> e1 = listIterator();
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }
@Test
    public void test() {
        List<Integer> list1 = new ArrayList<>();
        list1.add(1);
        List<Integer> list2 = new ArrayList<>();
        list2.add(2);
        List<Integer> list3 = new ArrayList<>();
        list3.add(1);

        System.out.println(list1.hashCode());
        System.out.println(list2.hashCode());
        System.out.println(list3.hashCode());
        System.out.println(list1==list2);
        System.out.println(list1==list3);
        System.out.println(list2==list3);
        System.out.println(list1.equals(list2));
        System.out.println(list1.equals(list3));
        System.out.println(list2.equals(list3));
        }
//运行结果
//        32
//        33
//        32
//        false
//        false
//        false
//        false
//        true
//        false

下面是我写的代码,只是使用HashSet去重

import org.junit.Test;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class permuteUnique {
    /**
     * @param : A list of integers
     * @return: A list of unique permutations
     * <p>
     * 16. 带重复元素的排列
     * 给出一个具有重复数字的列表,找出列表所有不同的排列。
     * <p>
     * 样例
     * 给出列表 [1,2,2],不同的排列有:
     * <p>
     * [
     * [1,2,2],
     * [2,1,2],
     * [2,2,1]
     * ]
     * 挑战
     * 使用递归和非递归分别完成该题。
     * <p>
     * 写过不含重复元素的全排列,这提是含重复元素的,应该相差不大
     */
    public List<List<Integer>> permuteUnique(int[] nums) {
        // write your code here
        HashSet<List<Integer>> hashResult = new HashSet<>();
        List<List<Integer>> result = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        if (nums == null) {
            return result;
        }
        if (nums.length == 0) {
            result.add(list);
            return result;
        }
        boolean[] color = new boolean[nums.length];
        for (int i = 0; i < nums.length; i++) {
            color[i] = false;
        }
        dfs(hashResult, list, nums, color);
        result = new ArrayList<>(hashResult);
        return result;
    }


    public void dfs(HashSet<List<Integer>> hashResult, List<Integer> list, int[] nums, boolean[] color) {
        if (list.size() == nums.length) {
            hashResult.add(new ArrayList<>(list));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            if (color[i] == false) {
                list.add(nums[i]);
                color[i] = true;
                dfs(hashResult, list, nums, color);
                color[i] = false;
                list.remove(list.size() - 1);
            }
        }
    }

    @Test
    public void testPermuteUnique() {
//        List<List<Integer>> result = permuteUnique(new int[]{1, 2, 2});
//        for (int i = 0; i < result.size(); i++) {
//            System.out.println(result.get(i).toString());
//        }

    }
}

下面是九章的答案,写的很难懂,狠巧妙
和没有重复元素的 Permutation 一题相比,只加了两句话:

Arrays.sort(nums) // 排序这样所有重复的数
if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) { continue; } // 跳过会造成重复的情况

    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> results = new ArrayList<>();
        if (nums == null) {
            return results;
        }

        Arrays.sort(nums);
        dfs(nums, new boolean[nums.length], new ArrayList<Integer>(), results);

        return results;
    }


      private void dfs(int[] nums,
                     boolean[] visited,
                     List<Integer> permutation,
                     List<List<Integer>> results) {
        if (nums.length == permutation.size()) {
            results.add(new ArrayList<Integer>(permutation));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            if (visited[i]) {
                continue;
            }
            if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) {
                continue;
            }

            permutation.add(nums[i]);
            visited[i] = true;
            dfs(nums, visited, permutation, results);
            visited[i] = false;
            permutation.remove(permutation.size() - 1);
        }
    } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值