3.1 字符串移位包含问题

来源:互联网 发布:js页面大小改变事件 编辑:程序博客网 时间:2024/04/29 20:11

1. 前言

本文的一些图片, 资料 截取自编程之美

2. 问题描述

这里写图片描述

3. 问题分析

解法一 : 循环arr.length 次, 每次比较arr中是否包含目标字符串
    如果不包含, 则将arr向右移动一位, 继续循环
    否则 跳出循环 返回true

解法二 : 如果目标字符串是arr的循环移位子字符串, 那么目标字符串必定是 arr + arr, 的子字符串
当然在进入方法的时候, 需要对目标字符串 和arr的长度进行校验一下 避免一下情况 : 目标字符串为 : “aa”, arr 为 : “a”

4. 代码

/** * file name : Test03StringShiftContains.java * created at : 8:48:35 AM May 27, 2015 * created by 970655147 */package com.hx.test04;public class Test03StringShiftContains {    // 判断src循环移位是否存在能够包含dst的子字符串    public static void main(String []args) {        char[] src = new char[]{'a', 'b', 'b', 'c', 'd' };        char[] dst = new char[]{'c', 'd', 'a', 'b' };        stringShiftContains01(src, dst);        stringShiftContains02(src, dst);    }    // 思路  如果src的长度小于dst的长度   则直接返回   因为无论src怎么移动  都不可能包含dst        // 否则  判断src是否包含dst  如果不包含  则src向右移动一位   并再次判断     直到移动了src.length位    public static void stringShiftContains01(char[] src, char[] dst) {        if(src.length < dst.length) {            return ;        }        for(int i=0; i<src.length; i++) {            if(contains(src, dst)) {                Log.log("contains");            }            rightShiftOnece(src);        }    }    // 如果dst能够通过src循环移位得到  那么dst必然是src+src的子序列    // 如果src的长度小于dst的长度   则直接返回   因为无论src怎么移动  都不可能包含dst    // 所以先构造一个char[]srcCopy  其内容为src + src    比如 src为"ab"   srcCopy为"abab"    // 然后  在判定srcCopy中是否包含dst    public static void stringShiftContains02(char[] src, char[] dst) {        if(src.length < dst.length) {            return ;        }        char[] srcCopy = new char[src.length * 2];        System.arraycopy(src, 0, srcCopy, 0, src.length);        System.arraycopy(src, 0, srcCopy, src.length, src.length);        if(contains(srcCopy, dst) ) {            Log.log("contains");        }    }    // 判断src中是否包含dst字符    private static boolean contains(char[] src, char[] dst) {        return indexOf(src, dst) > 0;    }    // 获取src中dst的子字符序列的索引    // 先进行边界判定, 在循环找出src中和dst第一个字符相同的索引i, 在继续比较dst后面的子字符串  如果找到匹配的  则返回索引        // 否则  继续从(i+1)开始寻找    // 注 : 代码是从 String.indexOf(char[] src, char[]dst)中拷贝过来的    private static int indexOf(char[] src, char[] dst) {        char[] source = src;        char[] target = dst;        int sourceOffset = 0, sourceCount = src.length;        int targetOffset = 0, targetCount = dst.length;        int fromIndex = 0;        if (fromIndex >= sourceCount) {            return (targetCount == 0 ? sourceCount : -1);        }        if (fromIndex < 0) {            fromIndex = 0;        }        if (targetCount == 0) {            return fromIndex;        }        char first = target[targetOffset];        int max = sourceOffset + (sourceCount - targetCount);        for (int i = sourceOffset + fromIndex; i <= max; i++) {            /* Look for first character. */            if (source[i] != first) {                while (++i <= max && source[i] != first);            }            /* Found first character, now look at the rest of v2 */            if (i <= max) {                int j = i + 1;                int end = j + targetCount - 1;                for (int k = targetOffset + 1; j < end && source[j]                        == target[k]; j++, k++);                if (j == end) {                    /* Found whole string. */                    return i - sourceOffset;                }            }        }        return -1;    }    // 将src中各个字符向右移动一位    private static void rightShiftOnece(char[] src) {        char tmp = src[src.length-1];        for(int i=src.length-1; i>0; i--) {            src[i] = src[i-1];        }        src[0] = tmp;    }}

5. 运行结果

这里写图片描述

6. 总结

这个问题, 对于第一种思路来说, 虽然想到非常容易, 但是效率并不高, 因为每一次都需要和dst进行一次contains操作
第二种思路 是比较巧妙的
个人的想法是, 将原字符串的元素做成一个循环单链表, 最后一个元素.next 接到第一个元素, 这样, 然后在查找子串, 当然和上面的第二种思路 基本上是一致的, 当然 也需要进行长度的校验

注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!

0 0
原创粉丝点击