数组求交集算法

数组求交集的方法
1.暴力搜索
2.利用HashMap
3.先排序再用两个指针查找
4.位图法
5.大文件求交集用分治法,组内用位图法

public class Main {
    /**
     * 暴力搜索
     * <p>
     * 时间复杂度O(n^2) 空间复杂度O(1)
     */
    static ArrayList<Integer> f0(int[] arr, int[] arr2) {
        Set<Integer> res = new HashSet<>();
        for (int i : arr) {
            for (int j : arr2) {
                if (i == j) {
                    res.add(i);
                }
            }
        }

        return new ArrayList<>(res);
    }

    /**
     * 利用HashMap
     * <p>
     * 时间复杂度O(n) 空间复杂度O(n)
     */
    static ArrayList<Integer> f1(int[] arr, int[] arr2) {
        Set<Integer> res = new HashSet<>();
        Map<Integer, Integer> map = new HashMap<>();
        for (int a : arr) {

            if (map.containsKey(a)) {
                map.put(a, (map.get(a) + 1));
            } else {
                map.put(a, 1);
            }
        }

        for (int a : arr2) {
            if (map.containsKey(a)) {
                res.add(a);
            }
        }

        return new ArrayList<>(res);
    }

    /**
     * 先排序再用两个指针查找
     * <p>
     * 时间复杂度O(nlogn) 空间复杂度O(1)
     */
    static ArrayList<Integer> f2(int[] arr, int[] arr2) {
        Set<Integer> res = new HashSet<>();
        int p = 0, q = 0;
        Arrays.sort(arr);
        Arrays.sort(arr2);
        while (p < arr.length && q < arr2.length) {
            if (arr[p] < arr2[q]) {
                p++;
            } else if (arr2[q] < arr[p]) {
                q++;
            } else {
                res.add(arr[p]);
                p++;
                q++;
            }
        }

        return new ArrayList<>(res);
    }

    /**
     * 位图法
     * 思路:
     * 假设数组a有m个元素,数组b有n个元素,并且满足m<n
     * 1.建立一个int数组 extra 来表示bitmap, 一个int为32位,可以表示32个数, 那么extra的元素个数为: Max(a)-Min(a) + 1
     * 2.将a中的元素映射到 extra 中的对应位置,用1表示
     * 3.将b中的元素映射到 extra 中的对应位置,如果该位置已经是1,说明元素已经存在,为重复元素,记录该元素
     * <p>
     * 时间复杂度O(n) 空间复杂度O(Max(a)-Min(a)/32)
     */
    static List<Integer> f3(int[] a, int[] b) {
        int min, max;
        int alen = a.length;
        int blen = b.length;
        int[] ps, pl;
        int len;
        int longlen;
        if (alen < blen) {
            ps = a;
            len = alen;
            longlen = blen;
            pl = b;
        } else {
            ps = b;
            len = blen;
            longlen = alen;
            pl = a;
        }
        min = max = ps[0];
        for (int i = 1; i < len; ++i) {
            if (ps[i] < min)
                min = ps[i];
            if (ps[i] > max)
                max = ps[i];
        }
        int gap = max - min;
        gap = gap / 32 + 1; //存储差值要gap个int 类型的数
        int[] extra = new int[gap];
        for (int i = 0; i < gap; ++i) extra[i] = 0;
        int row, column;
        for (int i = 0; i < len; ++i) {
            //找到 ps[i] 在bitmap中位置, 用位运算将该位置记为1
            row = (ps[i] - min) / 32;
            column = (ps[i] - min) % 32;
            extra[row] |= 1 << column;

        }
        Set<Integer> res = new HashSet<>();
        for (int i = 0; i < longlen; ++i) {
            //pl[i]如果超出ps元素的范围,肯定就不重复了,所以只关注ps数组最大最小值范围内的数
            if (pl[i] >= min && pl[i] <= max) {
                row = (pl[i] - min) / 32;
                column = (pl[i] - min) % 32;
                //如果该位置已经是1,说明元素已经存在,为重复元素,记录该元素
                if (0 != (extra[row] & (1 << column))) {
                    res.add(pl[i]);
                }
            }
        }

        return new ArrayList<>(res);
    }
    
    public static void main(String[] args) {
        Random random = new Random();
        int m = 100000;
        int[] a = new int[m];
        while (m > 0) {
            a[m - 1] = random.nextInt(5000);
            m--;
        }
        int n = 100000;
        int[] b = new int[n];
        while (n > 0) {
            b[n - 1] = random.nextInt(5000);
            n--;
        }

        new Thread(() -> {
            long time = System.currentTimeMillis();
            System.out.println(f0(a, b));
            System.out.println("f0 cost: " + (System.currentTimeMillis() - time) + " ms");

        }).start();

        new Thread(() -> {
            long time = System.currentTimeMillis();
            System.out.println(f1(a, b));
            System.out.println("f1 cost: " + (System.currentTimeMillis() - time) + " ms");

        }).start();

        new Thread(() -> {
            long time = System.currentTimeMillis();
            System.out.println(f2(a, b));
            System.out.println("f2 cost: " + (System.currentTimeMillis() - time) + " ms");


        }).start();

        new Thread(() -> {
            long time = System.currentTimeMillis();
            System.out.println(f3(a, b));
            System.out.println("f3 cost: " + (System.currentTimeMillis() - time) + " ms");

        }).start();

    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,979评论 0 13
  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,474评论 3 44
  • 数组是最简单的数据结构,占据连续内存并且按顺序存储。 以下是与数组有关的算法题目。 (1)查询数组中重复数字 算法...
    顽皮的石头7788121阅读 2,129评论 0 0
  • 1. 链表 链表是最基本的数据结构,面试官也常常用链表来考察面试者的基本能力,而且链表相关的操作相对而言比较简单,...
    Mr希灵阅读 1,472评论 0 20
  • 剑指offer线性数据结构 剑指offer是找工作开始后刷的第一本书,刷题用牛客网。这本书可以说是已经总结归纳的很...
    锅锅Iris阅读 1,019评论 0 2