`
蔡华江
  • 浏览: 107620 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

一道算法题(二)

    博客分类:
  • JAVA
阅读更多

[原题]

        http://www.iteye.com/topic/15295

写道
假设有这样一种字符串,它们的长度不大于 26 ,而且若一个这样的字符串其长度为 m ,则这个字符串必定由 a, b, c ... z 中的前 m 个字母构成,同时我们保证每个字母出现且仅出现一次。比方说某个字符串长度为 5 ,那么它一定是由 a, b, c, d, e 这 5 个字母构成,不会多一个也不会少一个。嗯嗯,这样一来,一旦长度确定,这个字符串中有哪些字母也就确定了,唯一的区别就是这些字母的前后顺序而已。

现在我们用一个由大写字母 A 和 B 构成的序列来描述这类字符串里各个字母的前后顺序:

如果字母 b 在字母 a 的后面,那么序列的第一个字母就是 A (After),否则序列的第一个字母就是 B (Before);
如果字母 c 在字母 b 的后面,那么序列的第二个字母就是 A ,否则就是 B;
如果字母 d 在字母 c 的后面,那么 …… 不用多说了吧?直到这个字符串的结束。

这规则甚是简单,不过有个问题就是同一个 AB 序列,可能有多个字符串都与之相符,比方说序列“ABA”,就有“acdb”、“cadb”等等好几种可能性。说的专业一点,这一个序列实际上对应了一个字符串集合。那么现在问题来了:给你一个这样的 AB 序列,问你究竟有多少个不同的字符串能够与之相符?或者说这个序列对应的字符串集合有多大?注意,只要求个数,不要求枚举所有的字符串。

       这是一个老贴子了,并且3楼帖了答案,但是我认为,这个答案是不标准的,正确与否姑且不论,题中假设的26位长的数据那个是不支持的,因为极易出内存溢出,于是我重新设计了一种算法,我认为在内存上和时间中都比原来的优秀。

其实在后面还有更好的解法,欢迎读原贴。

 

[解题思路]

       一开始,我也受到了找到数据间的数学关系的影响。别说,还真找到了一个,只是数学太差,无法表达出来,假设为5位数,那么数据的分布是1,4,3,2,2,3,4,1...1,4,3,2,2,3,4,1.....,有什么用呢,好像没用。。

      终于偶然间恍然大悟,有个最简单的规律就是,假设这是一个从a开始,每次都有A,B两种可能,但是上级已出现的概率决定了下级出现的概率,由于不需要枚举出各个数据,那么可以只要知道上级中最后的那个数出现的位置,就决定了下级有那些可能会出现的情况。

 

[代码实现]

import java.math.BigInteger;

public class Main {

	/**
	 * 数组相加
	 * 
	 * @param arr1
	 * @param arr2
	 * @return
	 */
	private static BigInteger[] add(BigInteger[] arr1, BigInteger[] arr2) {
		if (arr1.length != arr2.length)
			return null;
		for (int i = 0; i < arr1.length; i++) {
			arr1[i] = arr1[i].add(arr2[i]);
		}
		return arr1;
	}

	/**
	 * 数组集体相乘一个倍数
	 * 
	 * @param arr
	 * @param num
	 * @return
	 */
	private static BigInteger[] multiply(BigInteger[] arr, BigInteger num) {
		if (arr == null)
			return null;
		for (int i = 0; i < arr.length; i++) {
			arr[i] = arr[i].multiply(num);
		}
		return arr;
	}

	/**
	 * 求解一个字符串中加入一个新的字符位置分布<br>
	 * 
	 * 对一个定长length的字符中,在一定位置index中的前后(charAt)加入一个字符<br>
	 * 其将产生一个数组,可以记录新加字符所在位置<br>
	 * 在index前加入一个字符时,从0-index之间都有一种可能<br>
	 * 在index后加入一个字符时,从index+1-length之间也有一种可能
	 * 
	 * @param length
	 * @param index
	 * @param charAt
	 * @return
	 */
	private static BigInteger[] child(int length, int index, char charAt) {
		BigInteger[] arr = new BigInteger[length + 1];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = new BigInteger("0");
		}
		if (charAt == 'A') {
			for (int i = index + 1; i <= length; i++) {
				arr[i] = new BigInteger("1");
			}
		} else {
			for (int i = 0; i <= index; i++) {
				arr[i] = new BigInteger("1");
			}
		}
		return arr;
	}

	/**
	 * 取出对应字符所在位置的分布数组<br>
	 * 
	 * 对于一个已经存在的数组分布来说,扩展一个charAt的字符,那么产生的新数组分布也是一定的<br>
	 * 遍历现存的数组分布,对其每个值进行求对应的数组分布可能,并将结果与现在记录个数相乘,累加后的结果即一个全新的数组分布
	 * 
	 * @param sizes
	 * @param charAt
	 * @return
	 */
	private static BigInteger[] step(BigInteger[] sizes, char charAt) {
		BigInteger[] newSizes = new BigInteger[sizes.length + 1];
		for (int i = 0; i < newSizes.length; i++) {
			newSizes[i] = new BigInteger("0");
		}
		for (int i = 0; i < sizes.length; i++) {
			newSizes = add(newSizes, multiply(child(sizes.length, i, charAt), sizes[i]));
		}
		return newSizes;
	}

	/**
	 * 根据AB字符串取出符合条件的个数
	 * 
	 * @param str
	 * @return
	 */
	private static BigInteger test(String str) {
		BigInteger[] sizes = new BigInteger[] { new BigInteger("1") };
		BigInteger sum = new BigInteger("0");
		for (int i = 0; i < str.length(); i++) {
			sizes = step(sizes, str.charAt(i));
		}
		for (int i = 0; i < sizes.length; i++) {
			sum = sum.add(sizes[i]);
		}
		return sum;
	}

	public static void main(String[] args) {
                System.out.println(test("AAA"));
                System.out.println(test("AAB"));
                System.out.println(test("ABA"));
                System.out.println(test("ABAA"));
                System.out.println(test("ABAB"));
                System.out.println(test("AABAAABAAABAAABAAABAAABABB"));
	}
}

 

[结论 ]

       运算结果如下:

1
3
5
9
16
23469961608638992720
 

       查看结果的前几个,还是正确的,就是无法对后面的结论进行验证了,寒。。。

       在使用BigInteger代替int后,不但可以实现对26位数据的计算,那怕是假设为62位,也是秒杀的。

       这个算法最大的好处是不占用内存,那怕对1000的数据计算时,理论上也就约占2x1000多的数组。但是数据约大,计算的时间还是成指数倍的增长了。

       PS:谁想知道1000的数据有多少种可能么?试试就知道了。我的机器上花了7分钟,居然算过来了。。

 

 

 

分享到:
评论
2 楼 Mrluo 2011-10-19  
1 楼 蔡华江 2010-09-16  
晕,存草稿的,居然直接发布了

相关推荐

    每天一道算法题:分治算法,回归算法,贪心算法,回溯算法.zip

    贪心算法 每天一道算法题:分治算法,回归算法,贪心算法,回溯算法.zip

    一道算法题,亏在二叉树的构造和递归算法上了

    标题中的“一道算法题,亏在二叉树的构造和递归算法上了”暗示了这个问题主要涉及计算机科学中的数据结构,特别是二叉树,以及使用递归算法解决相关问题。在编程领域,二叉树是一种基础且重要的数据结构,常用于实现...

    一道网易笔试算法题

    12-02-28网易笔试一道算法题,附件代码是我自己的解题

    一道微软面试算法题进来看看

    根据给定的信息,我们可以推断出这是一道与链表操作相关的微软面试算法题。下面将详细介绍该题目可能涉及的知识点、解题思路以及代码实现。 ### 题目解析 #### 标题:一道微软面试算法题进来看看 这个标题暗示了...

    hadoop2面试题 - 2012腾讯笔试的一道算法题.pdf

    ### hadoop2面试题 - 2012腾讯笔试的一道算法题 #### 背景与题目概述 本文档提供了2012年腾讯笔试中一道关于字符串处理的算法题,该题目要求将字符串中的所有大写字母移动到字符串的末尾,同时保持其他字符的相对...

    一道算法题

    在这个场景中,我们关注的是一道与二进制文件相关的算法题。二进制文件(Binary File)是计算机存储数据的一种方式,它不同于文本文件,不以人类可读的字符编码存储,而是以特定格式存储机器可以直接理解和处理的位...

    考试类精品--总结一下面试常考的算法题,希望可以帮助每一位想要提升自己面试能力的同学。对于每一道算法题会总结代码、时.zip

    在准备面试时,掌握一些常见的算法题是至关重要的,尤其是对于技术面试来说。这份压缩包“考试类精品--总结一下面试常考的算法题”显然为面试者提供了一个宝贵的资源,帮助他们提升自身的编程和算法解决能力。在这个...

    DJI大疆2019年8月雷达算法工程师笔试题B卷

    以下是大疆2019年8月雷达算法工程师笔试题的知识点详细解读。 首先,“DJI大疆2019年8月雷达算法工程师笔试题B卷”这一标题说明这是一次面向特定职位(雷达算法工程师)的招聘考试。大疆(DJI)是一家专门从事民用...

    cutepig123#cutepig123.github.io#2007-10-26-问一道算法题算出这些直线一共有多少个交点1

    board=Algorithm&gid=8898发信人: snoowball (Snowball), 信区: Algorithm标 题: Re: 问一道算法题

    leetcode中文版-DailyAlgorithms:每日一道算法题,成长进步每一天

    说实话,一天做完一道算法题还是很吃力的,并且每个人都自己的规划和任务,也不是都有时间刷题。所以,大家可以根据具体情况来安排个人时间,有时间了多做一些,没时间就少做或不做。 目前构想的题目知识模块有:

    JAVA零基础算法练习题

    对于初学者,了解和掌握基础算法,如排序(冒泡排序、选择排序、插入排序、快速排序等)、查找(线性查找、二分查找等)以及数据结构(数组、链表、栈、队列等)是必不可少的。 这个"零基础配套练习题51道完整版...

    leetcode算法题主函数如何写-one_algorithm_one_day:每天一道算法题

    每天一道算法题 为了应付面试,开始写博客,准备开三个系列,第一个 JS算法系列,主要整理一些面试过程中常见的算法题 ; 第二个 ECMAScript规范解析,主要是想从ES规范的角度来解析JS代码的实际执行过程,只有真正...

    算法题的概要介绍与分析

    详细解析与解答:对于每一道算法题,提供清晰、详尽的解题思路、代码实现以及时间复杂度分析是非常重要的。这不仅能帮助用户理解问题本质,还能学习到高效的解决策略。 互动学习平台:一些资源还提供了在线的编程...

    去哪儿网2014笔试算法题汇总

    这个问题是去哪儿网2014年笔试中的一道算法题,其目标是编写一个函数`RP2AP`,接收一个相对路径字符串作为输入,并返回其对应的绝对路径。 该函数的核心逻辑如下: 1. 首先,检查输入和输出指针是否为NULL,如果...

    一道python走迷宫算法题

    ### Python走迷宫算法题详解 #### 背景与目的 本文旨在通过解决一道具体的Python编程题目——“走迷宫”来深入了解递归、深度优先搜索(DFS)等算法的应用,并通过具体实例掌握如何利用Python高效地解决问题。此题...

    算法导论中文第三版习题答案

    2. 设计和实现算法:书中提供了许多经典的算法,如快速排序、归并排序、二分查找等,读者需要学会如何编写这些算法的代码。 3. 数学应用:部分习题涉及到概率、图论、组合数学等领域的知识,这些是理解和设计某些...

    JAVA经典算法90题【含源码】

    每一道题目的源代码都能让你看到实际的实现过程,理解算法背后的逻辑。通过阅读和理解他人的代码,可以提高自己的编程思维和代码质量,同时也能避免在未来开发中重复发明轮子。 此外,这90道题目还包含了最新的JAVA...

Global site tag (gtag.js) - Google Analytics