一、通常开发中经常使用到一些API进行相应的业务数据结构合并,已经面试中的一些常用的场景做合并,这里简单整理归纳下吧~
1、字符串数组元素拆开去重后合并.
实现效果如:Stream.of()、Arrays.stream();
String[] string={"array","merge","thread","merge"};
结果:
[array, merge, thread]
/**
* 去重合并字符串数组
*
* @param source source
* @return List<String>
*/
private static List<String> mergeStringArray(String[] source){
return Stream.of(source).map(num->num.split(",")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());
}
2、合并两个基础类型数组,使用IntStream.concat()方法.
int[] source={1,2,3,5,7};
int[] target={723,44,2,2};
方法一:通过Stream的流式合并.
/**
* 去重合并两个基础数组
* @param source 源数组
* @param target 目标数组
* @return int[]
*/
private static int[] mergeArray(int[] source,int[] target){
if(source.length==0&&target.length==0){
return new int[0];
}
if(source.length==0){
return target;
}
if(target.length==0){
return source;
}
return IntStream.concat(Arrays.stream(source).sorted(), Arrays.stream(target).sorted()).distinct().toArray();
}
方法二、通过双指针从后遍历来实现.
/**
*
* @param nums1 nums1
* @param m 长度
* @param nums2 nums2
* @param n 长度
*/
/**
*循环终止后有三种情况
* 两个数组都被遍历完,无剩余元素(两数组有效长度相等)**
* 数组1被遍历完,数组2元素剩余(数组2的有效长度更大)
* 数组2被遍历完,数组1元素剩余(数组1的有效长度更大)
* 情况1表示合并完毕
* 情况2,此时数组2中剩余的元素小于等于已经被合并的元素,将这些元素放在已合并元素之前即可
* 情况3,数组1中剩余的元素本来就在已经被合并的元素之前,不需要调整
* 合并完成.
*/
public static void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1, j = n - 1;
// 新数组的长度,从后面开始遍历
// 时间复杂度O(m+n)
// 空间复杂度O(1)
int index = m + n - 1;
while (i >= 0 || j >= 0) {
// 对应长度相等时候
if (i >= 0 && j >= 0) {
nums1[index--] = nums1[i] >= nums2[j] ? nums1[i--] : nums2[j--];
// 对应数组1元素剩余,排在前面即可
} else if (i >= 0) {
nums1[index--] = nums1[i--];
// 对应数组2元素剩余,排在前面即可
} else {
nums1[index--] = nums2[j--];
}
}
}
3、合并两个有序集合.
flatMap(Collection::stream):扁平化处理元素,Stream[]
/**
* 合并两个有序集合
*
* @param source 源集合
* @param target 目标集合
* @return
*/
public static List<Integer> mergeList(List<Integer> source,List<Integer> target){
if(CollectionUtils.isEmpty(source)&&CollectionUtils.isEmpty(target)){
return Collections.EMPTY_LIST;
}
if(CollectionUtils.isEmpty(source)){
return target;
}
if(CollectionUtils.isEmpty(target)){
return source;
}
return Stream.of(source,target).flatMap(Collection::stream).distinct().sorted().collect(Collectors.toList());
}
4、合并两个二叉树,通过树的前序遍历实现,递归解决,但是占用内存.
/**
* 合并两个二叉树
* @param source 源数
* @param target 目标树
* @return Node
*/
public static Node merge(Node source,Node target){
if(Objects.isNull(source)&&Objects.isNull(target)){
return null;
}
if(Objects.isNull(source)){
return target;
}
if(Objects.isNull(target)){
return source;
}
// 新增节点
Node node=new Node(source.value+target.value);
node.left= merge(source.left, target.left);
node.right=merge(source.right, target.right);
return node;
}
5、合并链表,递归实现.
/**
* 合并两个有序链表
* @param list1 链表一
* @param list2 链表二
* @return ListNode
*/
public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if (list1 == null) {
return list2;
}
if (list2 == null) {
return list1;
}
// 递归合并有序链表
if (list1.value <= list2.value) {
list1.next = mergeTwoLists(list1.next, list2);
return list1;
} else {
list2.next = mergeTwoLists(list1, list2.next);
return list2;
}
}
6、合并两个Map,使用JAVA8的merge方法.
/**
* 合并两个Map,适用长度不等时候
*
* @param map1
* @param map2
* @return
*/
public static Map<String,Integer> mergeMap(Map<String,Integer> map1, Map<String,Integer> map2){
if(MapUtils.isEmpty(map1)&&MapUtils.isEmpty(map2)){
return Collections.emptyMap();
}
if(MapUtils.isEmpty(map1)){
return map2;
}
if(MapUtils.isEmpty(map2)){
return map1;
}
// 按照两个Map的长度实现
if(map1.size()>map2.size()){
map1.forEach((k,v)->{
map2.merge(k, v, (oldValue,newValue)->(oldValue+newValue));
});
return map1;
}
map2.forEach((k,v)->{
map1.merge(k, v, (oldValue,newValue)->(oldValue+newValue));
});
return map2;
}
7、有序数组转换二叉搜索树,递归+二分搜索
public TreeNode sortedArrayToBST(int[] nums) {
return helper(nums, 0, nums.length - 1);
}
public TreeNode helper(int[] nums, int left, int right) {
if (left > right) {
return null;
}
// 总是选择中间位置左边的数字作为根节点,二叉搜索树特点:根节点大于左节点,小于右节点,那么类似二叉搜索树的中序遍历
int mid = left+(right-left)/2;
TreeNode root = new TreeNode(nums[mid]);
// 递归实现
root.left = helper(nums, left, mid - 1);
root.right = helper(nums, mid + 1, right);
return root;
}
8、有序链表转换值二叉树,递归+快慢指针
// 类似有序数组构造二叉搜索树
public TreeNode buildTree(ListNode left, ListNode right) {
if (left == right) {
return null;
}
ListNode mid = getMedian(left, right);
// 中间节点当做根节点
TreeNode root = new TreeNode(mid.val);
root.left = buildTree(left, mid);
root.right = buildTree(mid.next, right);
return root;
}
// 快慢指针求链表中间节点
public ListNode getMedian(ListNode left, ListNode right) {
ListNode fast = left;
ListNode slow = left;
while (fast != right && fast.next != right) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
数组,没排序则先保持有序,然后二分;链表,快慢指针寻找终点,二叉搜索树的中序左根右是有序的,同时注意边界条件,套路了,没啥子难度,熟悉Stream的流式操作。
Dubbo框架的数据结构合并
Merger
package com.alibaba.dubbo.rpc.cluster;
import com.alibaba.dubbo.common.extension.SPI;
@SPI
public interface Merger<T> {
T merge(T... items);
}
ShortArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
public class ShortArrayMerger implements Merger<short[]> {
@Override
public short[] merge(short[]... items) {
int total = 0;
for (short[] array : items) {
total += array.length;
}
short[] result = new short[total];
int index = 0;
for (short[] array : items) {
for (short item : array) {
result[index++] = item;
}
}
return result;
}
}
SetMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
import java.util.HashSet;
import java.util.Set;
public class SetMerger implements Merger<Set<?>> {
@Override
public Set<Object> merge(Set<?>... items) {
Set<Object> result = new HashSet<Object>();
for (Set<?> item : items) {
if (item != null) {
result.addAll(item);
}
}
return result;
}
}
ListMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
import java.util.ArrayList;
import java.util.List;
public class ListMerger implements Merger<List<?>> {
@Override
public List<Object> merge(List<?>... items) {
List<Object> result = new ArrayList<Object>();
for (List<?> item : items) {
if (item != null) {
result.addAll(item);
}
}
return result;
}
}
MapMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
import java.util.HashMap;
import java.util.Map;
public class MapMerger implements Merger<Map<?, ?>> {
@Override
public Map<?, ?> merge(Map<?, ?>... items) {
if (items.length == 0) {
return null;
}
Map<Object, Object> result = new HashMap<Object, Object>();
for (Map<?, ?> item : items) {
if (item != null) {
result.putAll(item);
}
}
return result;
}
}
BooleanArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
public class BooleanArrayMerger implements Merger<boolean[]> {
@Override
public boolean[] merge(boolean[]... items) {
int totalLen = 0;
for (boolean[] array : items) {
totalLen += array.length;
}
boolean[] result = new boolean[totalLen];
int index = 0;
for (boolean[] array : items) {
for (boolean item : array) {
result[index++] = item;
}
}
return result;
}
}
ByteArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
public class ByteArrayMerger implements Merger<byte[]> {
@Override
public byte[] merge(byte[]... items) {
int total = 0;
for (byte[] array : items) {
total += array.length;
}
byte[] result = new byte[total];
int index = 0;
for (byte[] array : items) {
for (byte item : array) {
result[index++] = item;
}
}
return result;
}
}
CharArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
public class CharArrayMerger implements Merger<char[]> {
@Override
public char[] merge(char[]... items) {
int total = 0;
for (char[] array : items) {
total += array.length;
}
char[] result = new char[total];
int index = 0;
for (char[] array : items) {
for (char item : array) {
result[index++] = item;
}
}
return result;
}
}
DoubleArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
public class DoubleArrayMerger implements Merger<double[]> {
@Override
public double[] merge(double[]... items) {
int total = 0;
for (double[] array : items) {
total += array.length;
}
double[] result = new double[total];
int index = 0;
for (double[] array : items) {
for (double item : array) {
result[index++] = item;
}
}
return result;
}
}
FloatArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
public class FloatArrayMerger implements Merger<float[]> {
@Override
public float[] merge(float[]... items) {
int total = 0;
for (float[] array : items) {
total += array.length;
}
float[] result = new float[total];
int index = 0;
for (float[] array : items) {
for (float item : array) {
result[index++] = item;
}
}
return result;
}
}
IntArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
public class IntArrayMerger implements Merger<int[]> {
@Override
public int[] merge(int[]... items) {
int totalLen = 0;
for (int[] item : items) {
totalLen += item.length;
}
int[] result = new int[totalLen];
int index = 0;
for (int[] item : items) {
for (int i : item) {
result[index++] = i;
}
}
return result;
}
}
LongArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
public class LongArrayMerger implements Merger<long[]> {
@Override
public long[] merge(long[]... items) {
int total = 0;
for (long[] array : items) {
total += array.length;
}
long[] result = new long[total];
int index = 0;
for (long[] array : items) {
for (long item : array) {
result[index++] = item;
}
}
return result;
}
}
ArrayMerger
package com.alibaba.dubbo.rpc.cluster.merger;
import com.alibaba.dubbo.rpc.cluster.Merger;
import java.lang.reflect.Array;
public class ArrayMerger implements Merger<Object[]> {
public static final ArrayMerger INSTANCE = new ArrayMerger();
@Override
public Object[] merge(Object[]... others) {
if (others.length == 0) {
return null;
}
int totalLen = 0;
for (int i = 0; i < others.length; i++) {
Object item = others[i];
if (item != null && item.getClass().isArray()) {
totalLen += Array.getLength(item);
} else {
throw new IllegalArgumentException((i + 1) + "th argument is not an array");
}
}
if (totalLen == 0) {
return null;
}
Class<?> type = others[0].getClass().getComponentType();
Object result = Array.newInstance(type, totalLen);
int index = 0;
for (Object array : others) {
for (int i = 0; i < Array.getLength(array); i++) {
Array.set(result, index++, Array.get(array, i));
}
}
return (Object[]) result;
}
}
MergerFactory
public class MergerFactory {
/**
* Merger 对象缓存
*/
private static final ConcurrentMap<Class<?>, Merger<?>> mergerCache =
new ConcurrentHashMap<Class<?>, Merger<?>>();
/**
* 获得指定类型的Merger对象
* @param returnType
* @param <T>
* @return
*/
public static <T> Merger<T> getMerger(Class<T> returnType) {
Merger result;
// 如果类型是集合
if (returnType.isArray()) {
// 获得类型
Class type = returnType.getComponentType();
// 从缓存中获得该类型的Merger对象
result = mergerCache.get(type);
// 如果为空,则
if (result == null) {
// 初始化所有的 Merger 扩展对象,到 mergerCache 缓存中。
loadMergers();
// 从集合中取出对应的Merger对象
result = mergerCache.get(type);
}
// 如果结果为空,则直接返回ArrayMerger的单例
if (result == null && !type.isPrimitive()) {
result = ArrayMerger.INSTANCE;
}
} else {
// 否则直接从mergerCache中取出
result = mergerCache.get(returnType);
// 如果为空
if (result == null) {
// 初始化所有的 Merger 扩展对象,到 mergerCache 缓存中。
loadMergers();
// 从集合中取出
result = mergerCache.get(returnType);
}
}
return result;
}
/**
* 初始化所有的 Merger 扩展对象,到 mergerCache 缓存中。
*/
static void loadMergers() {
// 获得Merger所有的扩展对象名
Set<String> names = ExtensionLoader.getExtensionLoader(Merger.class)
.getSupportedExtensions();
// 遍历
for (String name : names) {
// 加载每一个扩展实现,然后放入缓存。
Merger m = ExtensionLoader.getExtensionLoader(Merger.class).getExtension(name);
mergerCache.putIfAbsent(ReflectUtils.getGenericClass(m.getClass()), m);
}
}
}