求数组交集不同解法小结

来源:互联网 发布:淘宝店铺出售0 编辑:程序博客网 时间:2024/06/18 07:17

求数组交集不同解法小结

  • 求数组交集不同解法小结
    • 声明
    • LintCode547求数组交集_要求元素不重复
      • 解法一排序二分查找
      • 解法二HasSet暴力去重
      • 解法三双指针法重视
    • LintCode548求数组交集变种
      • 解法一HashMap统计次数实现
      • 解法二排序二分查找变种双指针

声明

文章均为本人技术笔记,转载请注明出处:
[1] https://segmentfault.com/u/yzwall
[2] blog.csdn.net/j_dark/

LintCode547:求数组交集_要求元素不重复

LintCode547,给出两个数组,求二者交集且元素不重复,O(N2)查找会超时;

解法一:排序+二分查找

O(N2)算法超时主要发生在大数组查找过程,因此采用二分查找提升查找效率,交集用HashSet保存实现去重;

/** * 解法1:排序+二分+HashSet去重 * http://www.lintcode.com/zh-cn/problem/intersection-of-two-arrays/ * 求数组交集,要求元素不重复出现 * @author yzwall */class Solution {    public int[] intersection(int[] num1, int[] num2) {        int[] results;        if (num1 == null || num1.length == 0 || num2 == null || num2.length == 0) {            results = new int[0];            return results;        }        HashSet<Integer> set = new HashSet<>();        Arrays.sort(num1);        Arrays.sort(num2);        int index2 = 0;        for (int i = 0; i < num1.length; i++) {            // num2是子集            if (index2 > num2.length - 1) {                break;            }            int index = binarySearch(num2, index2, num1[i]);            if (index != -1) {                // set去重                set.add(num1[i]);                // num2指针移动                index2 = index;            }        }        results = new int[set.size()];        int i = 0;        for (Integer cur : set) {            results[i++] = cur.intValue();        }        return results;    }    // Index2~num.length - 1,经典二分查找    private int binarySearch(int[] num, int index2, int target) {        int start = index2;        int end = num.length - 1;        while (start + 1 < end) {            int mid = start + (end - start) / 2;            if (num[mid] == target) {                return mid;            } else if (num[mid] < target) {                start = mid;            } else {                end = mid;            }        }        if (num[start] == target) {            return start;        }        if (num[end] == target) {            return end;        }        return -1;    }}

解法二:HasSet暴力去重

直接运用两个HashSet实现去重求交集,与解法一相比实现简单;

/** * 解法2:HashSet暴力去重 * http://www.lintcode.com/zh-cn/problem/intersection-of-two-arrays/ * 求数组交集,要求元素不重复出现 * @author yzwall */class Solution {    public int[] intersection(int[] num1, int[] num2) {        int[] results;        if (num1 == null || num1.length == 0 || num2 == null || num2.length == 0) {            results = new int[0];            return results;        }        HashSet<Integer> hash1 = new HashSet<>();        for (int i = 0; i < num1.length; i++) {            hash1.add(num1[i]);        }        HashSet<Integer> hash2 = new HashSet<>();        for (int i = 0; i < num2.length; i++) {            if (hash1.contains(num2[i])) {                hash2.add(num2[i]);            }        }        results = new int[hash2.size()];        int i = 0;        for (Integer num : hash2) {            results[i++] = num;        }        return results;    }}

解法三:双指针法(重视)

通过双指针求交集,必须首先将求交集的两数组排序

/** * 解法3:双指针法 * http://www.lintcode.com/zh-cn/problem/intersection-of-two-arrays/ * 求数组交集,要求元素不重复出现 * @author yzwall */class Solution {    public int[] intersection(int[] num1, int[] num2) {        int[] results;        if (num1 == null || num1.length == 0 || num2 == null || num2.length == 0) {            results = new int[0];            return results;        }        Arrays.sort(num1);        Arrays.sort(num2);        int i = 0, j = 0;        int index = 0;        int[] temp = new int[num1.length];        while (i < num1.length && j < num2.length) {            if (num1[i] == num2[j]) {                // temp[index - 1] != num1[i]去重                if (index == 0 || temp[index - 1] != num1[i]) {                    temp[index++] = num1[i];                }                i++;                j++;            } else if (num1[i] < num2[j]) {                i++;            } else {                j++;            }        }        i = 0;        results = new int[index];        for (i = 0; i < index; i++) {            results[i] = temp[i];        }        return results;    }}

LintCode548:求数组交集变种

在求数组交集的基础上,要求交集元素出现次数与在数组中出现次数相同;

解法一:HashMap统计次数实现

通过HashMap<Integer, Integer>记录数组中每个元素与对应的出现次数;

/** * 解法2:HashMap统计重复出现次数 * http://www.lintcode.com/zh-cn/problem/intersection-of-two-arrays-ii/ * 求两数组交集,要求交集元素按照最小出现次数出现 * @author yzwall */class Solution {    public int[] intersection(int[] num1, int[] num2) {        int[] results;        if (num1 == null || num1.length == 0 || num2 == null || num2.length == 0) {            results = new int[0];            return results;        }        HashMap<Integer, Integer> hash = new HashMap<>();        for (int i = 0; i < num1.length; i++) {            if (hash.containsKey(num1[i])) {                hash.put(num1[i], hash.get(num1[i]) + 1);            } else {                hash.put(num1[i], 1);            }        }        ArrayList<Integer> list = new ArrayList<>();        for (int i = 0; i < num2.length; i++) {            if (hash.containsKey(num2[i]) && hash.get(num2[i]) > 0) {                list.add(num2[i]);                hash.put(num2[i], hash.get(num2[i]) - 1);            }        }        results = new int[list.size()];        for (int i = 0; i < list.size(); i++) {            results[i] = list.get(i);        }        return results;    }}

解法二:排序+二分查找变种+双指针

变种二分查找:与经典二分不同,解法二中二分查找用于找到查找目标第一次出现位置;
双指针解法:经过排序后,假设两数组中拥有某个交集元素cur, 通过二分查找到cur在第二个数组中的位置index,通过双指针cnt1cnt2统计交集元素cur在两个数组中各自出现的总次数,较小者表示该交集元素在交集中出现的次数

/** * 解法1:排序+二分查找+双指针 * http://www.lintcode.com/zh-cn/problem/intersection-of-two-arrays-ii/ * 求两数组交集,要求交集元素按照最小出现次数出现 * @author yzwall */class Solution3 {    public int[] intersection(int[] num1, int[] num2) {        int[] results;        if (num1 == null || num1.length == 0 || num2 == null || num2.length == 0) {            results = new int[0];            return results;        }        ArrayList<Integer> list = new ArrayList<>();        Arrays.sort(num1);        Arrays.sort(num2);        int index2 = 0;        int i = 0;        while(i < num1.length) {            // num2是子集            if (index2 > num2.length - 1) {                break;            }            int cnt1 = 1, cnt2 = 1;            int cur = num1[i];            int index = binarySearch(num2, index2, cur);            if (index != -1) {                // 查找交集元素cur在数组num1中出现总次数                for (int k = 1; k < num1.length && i + k < num1.length; k++) {                    if (num1[i + k] != cur) {                        break;                    }                    cnt1++;                }                // 查找交集元素cur在数组num2中出现总次数                for (int k = 1; k < num2.length && index + k < num2.length; k++) {                    if (num2[index + k] != cur) {                        break;                    }                    cnt2++;                }                int min = Math.min(cnt1, cnt2);                for (int k = 0; k < min; k++) {                    list.add(cur);                }                // num2指针移动                index2 += cnt2;            }            // num1指针移动            i += cnt1;        }        results = new int[list.size()];        i = 0;        for (Integer cur : list) {            results[i++] = cur.intValue();        }        return results;    }    // 返回target第一次出现位置,target不存在返回-1    private int binarySearch(int[] num, int index2, int target) {        int start = index2;        int end = num.length - 1;        while (start + 1 < end) {            int mid = start + (end - start) / 2;            if (num[mid] == target) {                end = mid;            } else if (num[mid] < target) {                start = mid;            } else {                end = mid;            }        }        if (num[start] == target) {            return start;        }        if (num[end] == target) {            return end;        }        return -1;    }}
原创粉丝点击