【常用算法思路分析系列】字符串高频题集

本文是【常用算法思路分析系列】的第二篇,分析字符串相关的高频题目。第一篇是关于排序相关的高频题,还没有看的同学请移步:【常用算法思路分析系列】排序高频题集


1、KMP字符匹配

对于两棵彼此独立的二叉树A和B,请编写一个高效算法,检查A中是否存在一棵子树与B树的拓扑结构完全相同,即给定两棵二叉树的头结点A和B,请返回一个boolean值,代表A中是否存在一棵同构于B的子树。上述其实就是一个字符匹配的问题,我们将A、B两棵二叉树进行遍历,得到一个字符串,就是判断B串是否是A串的子串。而字符匹配常用的算法采用KMP来实现。关于KMP算法分析,我这篇文章中有详细的介绍:我眼中的KMP

public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
        public TreeNode(int val) {
            this.val = val;
        }
    }

    public boolean chkIdentical(TreeNode A, TreeNode B) {
        String s1 = getSerializString(A);
        String s2 = getSerializString(B);
        return kmp(s1,s2);
    }
    //遍历二叉树得到字符串
    private static String getSerializString(TreeNode head){
        if(head == null)
            return null;
        StringBuilder sb = new StringBuilder();
        sb.append(head.val).append(getSerializString(head.left)).append(getSerializString(head.right));
        return sb.toString();
    }

    public static boolean kmp(String str1,String str2){
        char[] strA = str1.toCharArray();
        char[] strB = str2.toCharArray();
        int[] next = getNextArray(strB);
        int i,k;
        for(i = 0,k = 0; i < strA.length; i++){
            while(k > 0 && strA[i] != strB[k])
                k = next[k-1];
            if(strA[i] == strB[k]){
                k++;
            }
            /*
             * 注意,这里和求next数组有一点区别,因为kmp里面是主串和子串进行比较,当子串最后一个元素都相等的时候,k就相当于是子串和主串相同的公共部分长度,
             * 而对于求next数组中的方法来说,相当于是自身和自身进行比较
             */
            if(k == strB.length){
                return true;
            }
        }
        return false;
    }

    private static int[] getNextArray(char[] chs){
        int i;//字符数组的下表指示器
        int k;//前一个字符处的最大公共(相等)前、后缀子串的长度
        int[] next = new int[chs.length];
        for(i = 1,k = 0; i < chs.length; i++){
            while(k > 0 && chs[i] != chs[k])
                k = next[k - 1];
            if(chs[i] == chs[k]){
                k++;
            }
            next[i] = k;

        }
        return next;
    }

/** 解法二:暴力破解法
     * 时间复杂度为O(m*n),m、n分别为strA.length()和strB.length()
     * @param strA
     * @param strB
     * @return
     */
    private static boolean compareIdentical(String strA,String strB){
        int indexA,indexB;
        char[] charA = strA.toCharArray();
        char[] charB = strB.toCharArray();
        for(int i = 0; i < charA.length; i++){
            if(charA[i] == charB[0]){
                indexA = i;
                for(indexB = 0; indexB < charB.length && indexA < charA.length; indexB++){
                    if(charA[indexA++] != charB[indexB])
                        break;
                }
                if(indexB >= charB.length){//表示已经匹配到
                    return true;
                }
            }
        }
        return false;
    }


2、判断是否为变形词
对于两个字符串A和B,如果A和B中出现的字符种类相同且每种字符出现的次数相同,则A和B互为变形词,请设计一个高效算法,检查两给定串是否互为变形词。

以int[]数组作为哈希表,字符的ASCII值作为下标进行映射。先以A字符串的每个字符值作为下标进行映射,令其对应位置的值+1,遍历完后,再使用B字符值进行遍历,先查看对应位置是否为0,如果为0了,表示A中没有该字符(或少于B中的字符数量),如果不为0,则将对应位置的值-1。

/**
     * 以int[]数组作为哈希表,字符作为下标进行映射。
     * 时间复杂度为O(N),空间复杂度为O(N)
     * @param A
     * @param lena
     * @param B
     * @param lenb
     * @return
     */
    public static boolean chkTransform(String A, int lena, String B, int lenb) {
        if(A == null || B == null || lena != lenb){
            return false;
        }
        char[] charA = A.toCharArray();
        char[] charB = B.toCharArray();
        int[] map = new int[256];
        for(int i = 0; i < charA.length; i++){
            map[charA[i]]++;
        }
        for(int i = 0; i < charA.length; i++){
            if(map[charB[i]]-- == 0)//这里只能是--在后面
                return false;
        }
        return true;
    }

    /**
     * 暴力破解法
     * @param A
     * @param lena
     * @param B
     * @param lenb
     * @return
     */
    public static boolean chkTransform2(String A, int lena, String B, int lenb) {
        if(A == null || B == null || lena != lenb){
            return false;
        }
        Map<Character,Integer> mapA = new HashMap<Character,Integer>();
        Map<Character,Integer> mapB = new HashMap<Character,Integer>();
        char[] charA = A.toCharArray();
        char[] charB = B.toCharArray();
        char key;
        for(int i = 0; i < charA.length; i++){
            key = charA[i];
            if(mapA.containsKey(key)){
                mapA.put(key, mapA.get(key) + 1);
            }else{
                mapA.put(key, 1);
            }
        }
   
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值