您的位置:首页 > 编程语言

3.1 字符串移位包含问题

2015-08-26 21:51 288 查看

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, 所以请大家指出!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  编程之美