[Java]求字符串的交集

最近在做Android开发的时候遇到这样一个问题。


服务器给客户端推送应用的时候会发送一个apk的列表serviceApkList,其中有n个apk的包名(com.xxx),类似于这个样子的。


因为客户端要到服务器端进行下载,然后可能出现下载失败的情况(网络不好,url错误等情况),本地也有一个apk的列表clientApkList


于是要在客户端上做比较,serviceApkList与clientApkList中是否包含相同的包名。



那么,问题来了。用什么方法进行比较


既能实现目标,又能最大限度地优化时间复杂度呢?


最简单的方法莫过于冒泡排序,一个个比,

可以实现,但时间复杂度为o(n^2)


然后又想到优化冒泡排序,当比对相同时,删除clientApkList中的相同包名

可以实现,但时间复杂度依然为o(n^2/2)

在应用比较少的时候用这个方法可以,因为是字符串,所以不能用什么二分查找啊,归并排序啊。


什么,等等,在同学的提醒下,可以先对字符串进行归并排序,然后使用二分查找的方法。

理论上来说,归并排序的时间复杂度:O(n log 2n)+二分查找的时间复杂度:O(log n)

当应用比较多的时候用这个方法就可以大大减少时间复杂度了。


但是用什么规则进行比较呢?


因为Andoird apk的包名大多数以com开头,所以比较开头是没有意义的,所以可以从结尾开始比较。

Java中是提供归并排序的方法的,只要定义好比较的算法就可以了。

所以可以写出如下的比较算法:

	private static class MyComparator implements Comparator<String> {

		@Override
		public int compare(String lhs, String rhs) {
			if (rhs == null) {
				throw new NullPointerException("the ComparableStr is null!");
			}
			if (lhs.equals(rhs)) {
				return 0;
			}
			int length = lhs.length() - 1;
			int anotherLength = rhs.length() - 1;
			// 比较
			int minLength = Math.min(length, anotherLength);
			for (int i = minLength - 1; i >= 0; i--) {
				int value = (int) (lhs.charAt(length--));
				int antherValue = (int) (rhs.charAt(anotherLength--));
				if (value != antherValue) {
					return value - antherValue;
				}
			}
			if (length != 0) {
				return lhs.charAt(length);
			} else if (anotherLength != 0) {
				return rhs.charAt(anotherLength);

			}
			return 0;
		}
	}


解释一下,这里是根据字符的ascii码值比较的,char类型是可以直接转换成int类型的,其值就是其 ascii码值,C语言中经常会用到这个东西。


然后就可以直接调用排序和比较方法了。

	public static void sort(List<String> list, MyComparator comparator) {
		Collections.sort(list, comparator);
	}

	public static boolean binaryFind(List<String> list, String target) {
		boolean result = Collections.binarySearch(list, target) > 0;
		return result;
	}


经过不大严密的单元测试,如下测试:

	List<String> list1 = new ArrayList<String>();
		String str1 = new String("abc");
		String str2 = new String("abc");
		String str3 = new String("bc");
		String str4 = new String("etyys");
		String str5 = new String("...");
		String str6 = new String("com.abv");
		String str7 = new String("com.abva");
		String str8 = new String("com.vvv");
		String str9 = new String("com.aav");
		list1.add(str1);
		list1.add(str2);
		list1.add(str3);
		list1.add(str4);
		list1.add(str5);
		list1.add(str6);
		list1.add(str7);
		list1.add(str8);
		list1.add(str9);
		sort(list1, new MyComparator());
		assertTrue(binaryFind(list1, "bc"));

结果:


通过!


总结:很多工作上的问题可以通过以前学过的知识解决,关键不是遇到足够多的案例,而是遇到新问题的时候能不能通过知识的转移来解决。

这可能是区别码农跟攻城狮的标准之一。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值