[TOC]java
文章均为本人技术笔记,转载请注明出处:
[1] https://segmentfault.com/u/yzwall
[2] blog.csdn.net/j_dark/算法
LintCode547,给出两个数组,求两者交集且元素不重复,$O(N^{2})$查找会超时;segmentfault
$O(N ^{2})$算法超时主要发生在大数组查找过程,所以采用二分查找提高查找效率,交集用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; } }
直接运用两个HashSet
实现去重求交集,与解法一相比实现简单;.net
/** * 解法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; } }
在求数组交集的基础上,要求交集元素出现次数与在数组中出现次数相同;code
经过HashMap<Integer, Integer>
记录数组中每一个元素与对应的出现次数;blog
/** * 解法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
,经过双指针cnt1
与cnt2
统计交集元素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; } }