一个经典的字母排列算法
最近在研究一个问题,自己尝试些写了一个算法:
问题描述:给出一段字符,比如[a,b,c,d……],输出任意长度大于n的字符组合
- 分析:首先确立数学模型。这个问题的本质是排列问题,即:AL2 + AL3 + …… + ALL。既然是排列问题,就应该按照排列的思维来进行处理这个问题。首先不去分析具体的实现细节,遵循着从整体到局部的思想,先确立程序,然后在确立算法与数据结构。从上面的描述中,可以看出,排列是分层级的,比如长度为2的层级的排列,长度为3的层级的排列……程序与数学模型的一个区别就是,程序要实现具体细节,而数学模型是一种抽象。所以说,上面的排列公式,除了分析出层级之外,重要的是要考虑层级之间的关联。在实现具体细节的时候,发现,每一次层级的组合结果都是下一个层级要组合的原始数据。层级与层级之间的组合,对于程序来讲,要用递归算法来实现,这一点是毋庸置疑的。从整个过程来看,必须要有第一次组合产生的结果,作为整个组合的原始数据,以便进行后面层级的组合。
- 确立程序;
- 确立数据结果与算法;
- 代码:
package com.txq.letter.combine;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedDeque;/**
* 输出长度>len的字符串的任意组合,比如String s = "abc",输出为"ab","ba","ac","ca"……字符的排列
*
* @author TongXueQiang
* @date 2016/03/01
* @since JDK 1.7
*/
public class LetterCombation {
// 存放字符的原始队列
private static Queue<Character> queue = new ConcurrentLinkedDeque<Character>();
// 组合过程中产生的第一个结果集
private static Queue<List<String>> firstResult = new ConcurrentLinkedDeque<List<String>>();
// 最终结果集
private static Set<String> finalResult = new HashSet<String>();
// 组合的层级数,从2开始
private static int level = 2;/**
* 任意字母组合
*
* @param word
* @param len
* @return
*/
public Set<String> outputLetterCombina(String word, int len) {
if (word == null || word.equals("")) {
return null;
}
// 1.把word加入到原始队列中
init(word);
// 2.产生第一次结果集
firstResult = outputFirstCombination();
// 3.循环进行下一层级的组合,并得到最终结果集
finalResult = outputCombination(firstResult, level, word);
// 4.去除不符合期望的字符组合
return removeUnexpectedLetterComb(finalResult, len);
}/**
* 去除不符合期望的字符串
* @param finalResult2
* @return
*/
private Set<String> removeUnexpectedLetterComb(Set<String> result, int len) {
List<String> deleteList = new ArrayList<String>();
for (String s : result) {
if (s.length() <= len) {
deleteList.add(s);
}
}
result.removeAll(deleteList);
return result;
}/**
* 产生原始队列
*
* @param word
*/
public Queue<Character> init(String word) {
if (word == null || word.equals("")) {
return null;
}for (int i = 0;i < word.length();i++) {
Character c = Character.valueOf(word.charAt(i));
if (c.equals(' ') || c.equals('\n') || c.equals('\t') || c.equals('\r')) {
continue;
}
queue.add(c);
}return queue;
}/**
* 倒置字符串
*
* @param word
* @return
*/
public String reverse(String word) {
StringBuffer result = new StringBuffer();
for (int i = word.length() - 1; i >= 0; i--) {
result.append(word.charAt(i));
}
return result.toString();
}/**
* 倒置字符串,比如abc,倒置后为cab,abcd,倒置后为dabc……
*
* @param word
* @return
*/
public String reverseCombination(String word) {
char s[] = word.toCharArray();
List<String> ss = new ArrayList<String>();StringBuffer sb = new StringBuffer();
SoftReference<StringBuffer> srf = new SoftReference<StringBuffer>(sb);for (int i = 0; i < s.length - 1; i++) {
sb.append(s[i]);
}
// 把除最后一个字符意外的全部字符串加载到list中
ss.add(sb.toString());
sb = null;sb = new StringBuffer();
sb.append(s[s.length - 1]);
// 把最后一个字符加载到list中
ss.add(sb.toString());Collections.reverse(ss);// 倒置处理
sb = null;sb = new StringBuffer();
for (String s0 : ss) {
sb.append(s0);
}// 输出最后结果
return sb.toString();
}/**
* 输出长度为2的字母组合,作为第一个结果集,以备后续的组合使用
* @return
*/
public Queue<List<String>> outputFirstCombination() {
StringBuffer sb = null;
List<String> cell = null;SoftReference<List<String>> srf = new SoftReference<List<String>>(cell);
SoftReference<StringBuffer> srf0 = new SoftReference<StringBuffer>(sb);// 1.依次取出第一个字符,与剩下的字符组合
char ch = queue.poll();for (char cha : queue) {
cell = new ArrayList<String>();
sb = new StringBuffer();
sb.append(ch).append(cha);// 加入到cell中
cell.add(sb.toString());
cell.add(reverse(sb.toString()));// 把cell加入到首个结果集中
firstResult.add(cell);sb = null;
cell = null;
}// 递归终止条件
if (queue.size() != 1) {
outputFirstCombination();
}return firstResult;
}/**
* 输出组合,循环对输入的结果集中的每个cell处理,产生新的cell,然后把新的cell加载到中间结果集中,最后返回最后结果
*
* @param handleResult
* @param level
* @return
*/
public Set<String> outputCombination(Queue<List<String>> inputResult, int level, String word) {
// 定义新的中间结果集
Queue<List<String>> middleResult = new ConcurrentLinkedDeque<List<String>>();
SoftReference<Queue<List<String>>> srf = new SoftReference<Queue<List<String>>>(middleResult);StringBuffer sb = null;
// 1.把handleResult加入到最终结果集中
finalResult = addToFinalResult(inputResult);// 2.清空队列
queue.clear();// 3.对输入的结果集进行处理,进行下一层级的组合
List<String> cell = inputResult.poll();while (cell != null) {
// 新的cell
List<String> newCell = null;// ①.初始化队列
queue = init(word);// ②.从cell中取出第一个字符串,然后去除原始队列中与之匹配的字符串
removeStrFromOriginalQueue(cell);// ③.cell与原始队列中剩下的字符串进行组合,产生新的cell
originalQueueToCellCombination(newCell, cell, middleResult, sb);// ④.清空队列
queue.clear();// ⑤.下一个单元
cell = inputResult.poll();
}inputResult = null;
++ level;// 4.层级叠加// 5.递归终止条件
if (level != word.length()) {
outputCombination(middleResult, level, word);
}// 6.处理最后的中间结果集
addToFinalResult(middleResult);
middleResult = null;return finalResult;
}/**
* cell与原始队列中剩下的字符串进行组合,产生新的cell
*
* @param newCell
* @param cell
* @param middleResult
* @param sb
*/
private void originalQueueToCellCombination(List<String> newCell, List<String> cell,
Queue<List<String>> middleResult, StringBuffer sb) {
SoftReference<List<String>> srf = new SoftReference<List<String>>(newCell);
SoftReference<StringBuffer> srf0 = new SoftReference<StringBuffer>(sb);for (char c : queue) {
newCell = new ArrayList<String>();
for (String s : cell) {
sb = new StringBuffer();
sb.append(s).append(c);
newCell.add(sb.toString());
newCell.add(reverseCombination(sb.toString()));
sb = null;// 不用的对象
}
// 把newCell加载到中间结果集中
middleResult.add(newCell);
newCell = null;
}
}/**
* 从cell中取出第一个字符串,在原始队列中移除与之匹配的字符串
*
* @param cell
*/
private void removeStrFromOriginalQueue(List<String> cell) {
String firstWord = cell.get(0);
for (int i = 0; i < firstWord.length(); i++) {
queue.remove(firstWord.charAt(i));
}
}/**
* 输出到最终结果集中
*
* @param middleResult
*/
public Set<String> addToFinalResult(Queue<List<String>> middleResult) {
for (List<String> cell : middleResult) {
finalResult.addAll(cell);
}
return finalResult;
}
}程序在运行时,原始数据[abcdefgh]产生的排列,输出有109592个字符串,运行有点缓慢,再加一个字符i,输出结果通过计算预计有100多万个字符串,程序几乎无法运行。运行时,输入以下参数:-Xms1700m -Xmx1700m -Xmn900m -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=5 -XX:CMSInitiatingOccupacyFraction=85 -Xloggc:E:/gc.log。通过GC日志以及VisualVM监视,看到,当数据量非常大的时候,程序几乎都浪费在GC和FullGC上面。原因是内存不足导致,内存不足的原因是程序本身的问题。 一个好的算法会考虑时间复杂度和空间复杂度。在程序运行时,占用太多的内存,导致内存不足,会导致过多的GC和Full GC,也就是说,当数据量达到一定程度的时候,程序的绝大部分时间都浪费在GC上,性能十分低下。在写算法的时候,应该极力避免在循环体中频繁初始化对象,尤其是比较大的对象。这是经验问题。改变数据结构,减少内存占有量,减少GC时间,这就是优化的方向!
- 目前在中文分词领域里面,IK分词的性能是比较低下的,IK分词采用的数据结构是:当子节点小于3的用对象数组来存储,当大于3的时候,用HashMap来存储,以节约内存。但是,当字典中的汉字非常多的时候,维护太多的HashMap也不是一件很好的事情。采用三叉树这种数据结构,有效地解决了内存溢出问题。目前solr的搜索推荐系统的核心思想就是基于三叉树的前缀匹配算法,比如TSTLookup,JaSPellLookup。
转载于:https://www.cnblogs.com/txq157/articles/5238079.html
一个经典的字母排列算法相关推荐
- java实现apriori算法_七大经典、常用排序算法的原理、Java 实现以及算法分析
0. 前言 大家好,我是多选参数的程序员,一个正再 neng 操作系统.学数据结构和算法以及 Java 的硬核菜鸡.数据结构和算法是我准备新开的坑,主要是因为自己再这块确实很弱,需要大补(残废了一般) ...
- php 冒泡查找 降序 随机数 封装,又一个PHP实现的冒泡排序算法分享
又一个PHP实现的冒泡排序算法分享 经典的冒泡排序法一直是许多程序沿用的其中一种排序法,话说冒泡排序法在效率上比PHP系统函数sort更高效.本章不讨论性能,所以就不拿它来跟系统性能做对比了. 冒泡排 ...
- 经典十大排序算法(含升序降序,基数排序含负数排序)【Java版完整代码】【建议收藏系列】
经典十大排序算法[Java版完整代码] 写在前面的话 十大排序算法对比 冒泡排序 快速排序 直接选择排序 堆排序 归并排序 插入排序 希尔排序 计数排序 桶排序 基数排序 完整测试类 写在前面的话 ...
- 经典的K-means聚类算法
原理部分主要来自大牛zouxy09和trnadomeet两个人的博客:后面的代码详细讲解为自己精心编写 一.概述 非监督学习的一般流程是:先从一组无标签数据中学习特征,然后用学习到的 ...
- 一个经典编程面试题的“隐退”
[转] 一个经典编程面试题的"隐退" 作者:童燕群 | 发布日期:三月 22, 2014 本文由 伯乐在线 – 王伯 翻译自 The Noisy Channel. 面试程序员很困难 ...
- 用c语言实现字母排列组合,C语言字母排列组合的实现.pdf
C语言字母排列组合的实现 曹玉坤 2011-6-21 目录 概述3 需求3 规律3 实现算法5 难点6 代码6 概述 本文档概述字母排列组合的实现算法和分析过程,着重强调在 解决问题前,对问题的思考方 ...
- 用c语言实现字母排列组合,C语言字母排列组合的实现.doc
C语言字母排列组合的实现.doc C语言字母排列组合的实现曹玉坤2011-6-21目录概述3需求3规律3实现算法5难点6代码6概述 本文档概述字母排列组合的实现算法和分析过程,着重强调在解决问题前,对 ...
- 从一个实例中学习DTW算法
基于动态时间规整算法(DTW)的相似度计算 Killer 发表于(2015-10-063) 本文标签:大数据 机器学习 算法 浏览量:193次 喜欢收藏 在孤立词语音识别中,最为简单有效的方法是 ...
- 算法 经典的八大排序算法详解和代码实现
算法 经典的八大排序算法详解和代码实现 排序算法的介绍 排序的分类 算法的时间复杂度 时间频度 示例 图表理解时间复杂度的特点 时间复杂度 常见的时间复杂度 空间复杂度 排序算法的时间复杂度 冒泡排序 ...
最新文章
- /proc/sysrq-trigger使用说明
- loss和accuracy的关系
- 跨域请求获取Solr json检索结果并高亮显示
- VC++学习(15):多线程
- 【树形区间DP】加分二叉树(ssl 1033/luogu 1040)
- unity中创建游戏场景_在Unity中创建Beat Em Up游戏
- 《python深度学习》代码中文注释
- 系统仿真平台SkyEye可替代国外Matlab/Sumlink等同类软件
- C语言,利用函数调用统计输出素数并统计素数和
- 避障跟随测距c语言程序,红外避障小车c语言程序.pdf
- Servlet Session 跟踪
- android float类型保留两位小数_你知道MySQL中Decimal类型和Float Double的区别吗?
- 城乡规划转到计算机专业行吗,哪些大学城乡规划专业有博士点
- endnote安装_EndNote X8 系列教程(一):软件介绍与安装
- 桌面计算机怎么覆盖文件,恢复被覆盖的文件_恢复被覆盖的桌面文件
- 12.这就是搜索引擎:核心技术详解 --- 搜索引擎发展趋势
- 初中信息技术考试:Python试题及答案
- 阿里云Maven配置方案
- 阅读科研文献心得分享(二)
- Mysql 分表分区