3.Sunday算法的一个小优化

优化算法思路:

1.Sunday算法关键思想
通过解析传统Sunday算法我发现它实现跳转的关键思想在于第二步,我们深入解析下第二步的原理:

we should working hard
work

h为什么要和work中的元素逐个比较?我们可以这样理解:
1) 当h和w比较时,我们可以确定houl和work是否可能匹配
2) 当h和o比较时,我们可以确定shou和work是否可能匹配
3) 当h和r比较时,我们可以确定 sho和work是否可能匹配
4) 当h和k比较时,我们可以确定e sh和work是否可能匹配
也就是说,这次比较我们可以确定e shoul和work的关系。
we should working hard
work

那么我们的优化策略就有了:
当h和work经过比较后发现h不在work中,我们可以直接跳过oul,用d来重复h的操作,以此类推,直到找到匹配项。

改进后的Sunday算法:

我们假设有一个字符串A长度为n 一个字符串B长度为m
我们使用Sunday算法在A中查找是否存在B

我们假设每次比较的时间为1,本文的复杂度分析主要是最坏复杂度分析

1) 将A,B首字母对齐

2) 查看B最后一个字符对应的A的位置(初始为m)上的字符是否在B中存在m次比较

3) 若存在,则将B中对应位置与其对齐后倒序比较,若全部相等则找到目标,否则执行步骤4 m-1次比较

4) 若不存在则将检查m+m位置上的字符是否在B中存在。m次比较

图示过程:

w	e		s	h	o	u	l	d		w	o	r	k	i	n	g		h	a	r	d
w	o	r	k							

1)首先查看s是否在work中存在,结果为不存在,跳过4位到l上
2)检查l在work中是否存在,结果为不存在,跳过4位到o上
3)检查o在work中是否存在,发现存在,则将两个串中的o对齐得到下面的:

w	e		s	h	o	u	l	d		w	o	r	k	i	n	g		h	a	r	d
										w	o	r	k								

4)检查它们相对应的串是否匹配,结果发现匹配,得到结果,配对完毕。

复杂度分析
我们拿传统Sunday算法的最坏复杂度情况进行计算:

类似下面情况的查找的复杂度最坏:
wordkkkkkkkkkkkkkkkkkkk
work

通过计算这样的复杂度为:
O(n,m)=(2m-1)n/m
化简后就是:O(n,m)=2
n-n/m
我们知道当n远大于m的时候,其时间复杂度可以近似看成:O(n)=n

这与传统的Sunday相比近似快了一倍。

代码实现

public int Sunday(String haystack, String needle) {
        int hayLen = haystack.length();//主串长度
        int nLen = needle.length();//子串长度
        int i=nLen-1;
        int l=0;
        int j=0;

        if(hayLen>nLen)
        {
            while(i<hayLen) {
                l=i;
                for (j=nLen-1;j>=0;j--)
                {
                    if (needle.charAt(j)==haystack.charAt(i)) {
                        i += nLen - 1 - j;
                        if (i < hayLen){
                            for (int n = nLen - 1; n >= 0; n--) {
                                if (needle.charAt(n) != haystack.charAt(i--)) {
                                    break;
                                } else if (n == 0) {
                                    return i + 1;
                                }
                            }
                        i = l;
                        break;
                       }
                        else{
                            return -1;
                        }
                    }
                }
                i+=nLen;
                continue;
                }
            return -1;
        }
        else{
            System.out.println("后者比前者长,不能进行查找操作");
            return -1;
        }

}

实现代码也少了许多,更简洁。

测试比较
针对上面两种算法我选取了一个下面的测试方法:
1.最坏情况测试:

public static void main(String[] args) {
        String a="wordkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk" +
                "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk" +
                "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk" +
                "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk" +
                "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk" +
                "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk" +
                "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk" +
               "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkwork";
        String b="work";
        BetterSunday01 find=new BetterSunday01();
        long startTime = System.currentTimeMillis();    //获取开始时间
        int i=0;
        for(int j=0;j<1000000;j++) {
            i = find.Sunday(a, b);
        }
        long endTime = System.currentTimeMillis();    //获取结束时间
        System.out.println(i);
        System.out.println("算法运行时间为:"+(endTime - startTime) + "ms");
}

传统算法的结果为:
在这里插入图片描述

优化后的算法结果为:
在这里插入图片描述
经计算改进后的算法针对上面的测试方法比传统的算法快了近67.5%。

2.一般情况测试:
从网上截取了一段正常的两万多字的文本并对它们进行测试发现它们的查找速度基本相同。
综合而言,本文对Sunday算法的优化提高了此查找算法的稳定性以及平均复杂度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值