转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6851631.html
(解题金句:其他问题字符串化,然后调用String类封装方法解决问题; 字符串问题数组化,然后操作字符数组解决问题。)
(从字符串中寻找某种性质的子串问题,与从二叉树中寻找某种性质的子树相类似,解题思路为从头到尾模拟拼写字符串的过程,对拼写过程中的每一个字符,对已拼写的子串的进行性质判断,更新相关信息。当拼写到结尾时,记录下的信息即为所求。)
一:字符串问题简述
字符串相关问题通常有以下特性:
1:字符串数组化:对于一个字符串,通常看作一个字符数组来处理,常见的有数组排序、调整、查找等。
2:其他问题字符串化:很多问题可以用字符串来模拟、处理
关于字符串的一些常见概念:
1:回文:一个字符串,从左到右读和从右到左读是完全一样的。
2:子串:字符串中任意个连续的字符组成的子序列称为该串的子串。
3:子序列:子序列就是在原来字符串中找出一部分字符(不强制连续)组成的序列。
4:递增子序列: 首先它是子序列,其次它们的元素是递增的。
5:最长子序列:子序列中元素的个数是最多的那一序列。
6:公共子序列:子序列的元素必须在两个字符串中都要出现。
7:前缀树:从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
8:后缀树:后缀树中存储的关键词为所有的后缀。
9:字符串匹配:其输入是原字符串(String)和子串(又称模式,Pattern)组成,输出为子串在原字符串中的首次出现的位置。常见算法有暴力搜索(Brute force),KMP, BM(Boyer Moore)等等。【注:一般面试问匹配算法的实现思路,而做题则是使用匹配结果即可,Java中封装了String.contains()/String.indexOf()方法了】
常见字符串操作:
1:替换
2:变形
3:拼接
常见字符串题型:
1:规则判断:字符串是否符合某种规则、格式
2:模拟数字运算
3:字符串数组化处理:字符数组的调整、查找、排序等
4:字符统计问题
5:动态规划:最长公共子串、最长公共子序列、最长回文子串、最长回文子序列...
6:搜索类型:用DFS/BFS模拟字符串变换的过程,从中获取解
7:字符串匹配问题:从str1中查找str2
二:两棵树拓扑结构比较问题
给出两棵二叉树树,判断树2是否为树1的某棵子树。
解法:按照同一种遍历规则,序列化两棵二叉树,把问题转化为字符串匹配问题——str1中是否包含str2子串。
public static void preOrder(TreeNode root,ArrayList<String> pre){ if(root==null){//1:遍历到叶子结点的左右儿子,用#表示空结点 pre.add("#"); return; } Integer value=root.val; pre.add(value.toString()); preOrder(root.left,pre); preOrder(root.right,pre); } public static boolean chkIdentical(TreeNode A, TreeNode B) { ArrayList<String> listA=new ArrayList<String>(); ArrayList<String> listB=new ArrayList<String>(); //遍历两棵树 preOrder(A,listA); preOrder(B,listB); //把树的遍历结果转为字符串 StringBuilder builderA=new StringBuilder(); for(String i:listA){ builderA.append(i); } String strA=builderA.toString(); StringBuilder builderB=new StringBuilder(); for(String j:listB){ builderB.append(j); } String strB=builderB.toString(); //判断A树序列中是否有B树序列 return strA.contains(strB); }
三:变形词
变形词定义:字符串str1中字符种类以及各字符出现次数,与字符串str2中种类及出现次数一致,则str1和str2互为变形词。
思路:使用两个hashMap,分别统计str1和str2中各字符出现次数即可。注意特殊情况:两字符串长度不同,则绝对不互为变形词。
public boolean chkTransform(String A, int lena, String B, int lenb) { if(lena!=lenb){ return false; } char[] charsA=A.toCharArray(); char[] charsB=B.toCharArray(); HashMap<Character,Integer> mapA=new HashMap<Character,Integer>(); HashMap<Character,Integer> mapB=new HashMap<Character,Integer>(); for(Character ch:charsA){ if(mapA.get(ch)==null){ mapA.put(ch,1); }else{ mapA.put(ch,mapA.get(ch)+1); } } for(Character ch:charsB){ if(mapB.get(ch)==null){ mapB.put(ch,1); }else{ mapB.put(ch,mapB.get(ch)+1); } }
//如果字符种类数不一样,则直接返回false if(mapA.size()!=mapB.size()){ return false; }
//由于不知道具体哪些种类,那么直接取两字符串拼接,遍历拼接后字符串每个字符即可得到两字符串所有种类 String sum=A+B; char[] sumchars=sum.toCharArray(); for(Character ch:sumchars){ if(mapA.get(ch)!=mapB.get(ch)){//无论哪一个字符,只有A,B中数量不相等,则返回false return false; } } return true; }