模糊距离分析 及 java代码实现

模糊距离分析

原题

X和Y都是只有0和1组成的字符串。D(X,Y)称为模糊距离,定义如下:首先删除X和Y从头开始的公共子串然后将X和Y剩下部分的长度相加得到模糊距离例如D(1000,1111),首先,删除子串“1”,然后剩下“000”和“111”长度都是3,相加为6,则D(1000,1111)=6。例如D(101,1100),首先删除公共子串“1”,然后剩下"01"和"100"长度分别为2,3,相加为5,则D(101,1100)=5。

问题是,给定n个只有0和1的字符串,如:111110001011100...请找到最大的模糊距离,字符串总数为n,字符串最长为m。

分析

这个题目描述比较长,但实际上,并不难。只要耐心,看完题目,即可。描述也不晦涩。

直接想来,对于每一个01字符串,与其他的每一个01字符串进行模糊距离的计算,时间复杂度是O(nm),遍历完n个字符串,总的时间复杂度是O(n^2*m)。这个我们可以称为暴力法。

如何改进上面的方法的,主要是指缩小时间复杂度。一个非常通用的方法,就是以空间换时间。如何换呢?对于模糊距离的第一个条件,我们想到什么呢?公共前缀,不知道同学们,联想到树形结构:trie树没有。例如:给定000、001、0010,我们构造如下的trie树。

 0  
  0 
 1 0
0   

构造过程中,1为左子树,0为右子树。模糊距离的第一个条件是,去掉公共前缀,则计算时,两个字符串,要有公共前缀,也就意味着,只需要考虑开始分叉的节点,左右子树,可以有一个没有。这样,我们考虑第一个分叉的节点:0,然后可以计算第二部分了,如何计算剩下长度相加呢?尤其,为了找到模糊距离的最大值,我们求得当前节点的左子树的最大深度以及右子树的最大深度,两者相加,及得到一个模糊距离,为3。然后考虑1节点,右子树为空,则模糊距离为1。综合,最大的模糊距离为3。这里有一个小小的技巧,构建的过程中,可以在节点中,存储左右子树的高度,并随着加入新的字符串,更新左右子树的高度。总的时间复杂度为O(nm)。 根据上例,存储的左右子树的高度值变化如下 (left_height, right_height):

  • left_height: 左边子树的高度

  • right_height: 右边子树的高度

 0(0,2)  
  0(0,1) 
   0(0,0)
 0(0,2)  
  0(1,1) 
 1(0,0) 0(0,0)
 0(3,2)  
  0(2,1) 
 1(1,0) 0(0,0)
0(0,0)   

【分析完毕】

package Array;

import Tree.Node;

/**
 * @Title: MoHU_juli.java
 * @Package Array
 * @Description: X和Y都是只有0和1组成的字符串。D(X,Y)称为模糊距离,定义如下: 首先删除X和Y从头开始的公共子串
 *               然后将X和Y剩下部分的长度相加得到模糊距离
 *               例如D(1000,1111),首先,删除子串“1”,然后剩下“000”和“111”长度都是3,相加为6,则
 *               D(1000,1111)=6。
 *               例如D(101,1100),首先删除公共子串“1”,然后剩下"01"和"100"长度分别为2,3,相加为5,则
 *               D(101,1100)=5。
 * 
 *               问题是,给定n个只有0和1的字符串,如: 1111 1000 101 1100 ...
 *               请找到最大的模糊距离,字符串总数为n,字符串最长为m。
 * @author nutc
 * @date 2013-8-17 下午8:37:43
 * @version V1.0
 */
public class MoHU_juli {
	
	public static void main(String args[]){
		int [][] a = {{1,1,1,1},{1,1,0,0,1},{1,1,1,0,0,0}};
		System.out.println("模糊距离为"+findDis(a));
		int [][] b = {{1,1,1,1},{1,0,0,0}};
		System.out.println("模糊距离为"+findDis(b));
	}

	public static int findDis(int[][] val) {
		if (val == null)
			return 0;

		Node tree = new Node(-1);
		for (int i = 0; i < val.length; i++) {
			buildTree(tree, val[i]);
		}
//		tree.display();
		Result re = findMax(tree);
		return re.max;

	}

	public static void buildTree(Node root, int[] num) {
		if (num == null)
			return;
		Node now = root;
		for (int i = 0; i < num.length; i++) {
			int val = num[i];
			if (val == 1) {
				if (now.right == null) {
					Node n = new Node(1);
					now.right = n;
				}
				now = now.right;
			} else {
				if (now.left == null) {
					Node n = new Node(0);
					now.left = n;
				}
				now = now.left;
			}
		}
	}

	public static class Result {
		int max;
		int height;
	}

	public static Result findMax(Node n) {
		Result r = new Result();
		if (n == null) {
			r.height = 0;
			r.max = 0;
		}else{
			Result left = findMax(n.left);
			Result right = findMax(n.right);
			
			r.height = (left.height>right.height? left.height:right.height)  +1;
			int nowdis = left.height + right.height;  //注意模糊距离的概念! 所以应该是相加!!!
			
			r.max = left.max>right.max?left.max:right.max;
			r.max = r.max>nowdis? r.max:nowdis;
		}
		return r;
	}

}


举报该文章

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值