求數組交集不同解法小結
聲明
文章均爲本人技術筆記,轉載請註明出處:
[1] https://segmentfault.com/u/yzwall
[2] blog.csdn.net/j_dark/
LintCode547:求數組交集_要求元素不重複
LintCode547,給出兩個數組,求二者交集且元素不重複,
解法一:排序+二分查找
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
,通過雙指針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;
}
}