数组(集合)合并
/**
* 将两个递增的数组合并
* @param l
* @param l1
* @return
*/
public static List<Integer> test(Integer[] l,Integer[] l1){
List<Integer> a = Arrays.asList(l);
List<Integer> b = Arrays.asList(l1);
if(a == null || b == null){
throw new NullPointerException();
}
List<Integer> c = new ArrayList<>(a.size()+b.size());
int i = 0;
int j = 0;
while(i < a.size() && j < b.size()){
c.add(a.get(i) <= b.get(j) ? a.get(i++) : b.get(j++));
}
if(i == a.size()){
while(j < b.size()){
c.add(b.get(j));
j++;
}
}
if(j == b.size()){
while(i < a.size()){
c.add(a.get(i));
i++;
}
}
return c;
}
BF暴力破解查找主串中是否包含模式串
/**
* 判断targetStr是否包含sourceStr,起始索引的位置
*/
private static void bf() {
// 起始位置要小于等于 目标长度 - 原长度
// 循环比较,每一位是否相等
// 如果相等就比较下一位,不等就回溯索引位置
// 如果源的索引位置等于源的长度,说明比较结束了,返回true
String targetStr = "abaaaabbbbbbbbcccccababaaababaa";
String sourceStr = "ababaaababaa";
System.out.println(checkStrBF(targetStr, sourceStr));
}
private static Integer checkStrBF(String targetStr, String sourceStr) {
return checkStrBF(targetStr,sourceStr,0,0);
}
private static Integer checkStrBF(String targetStr, String sourceStr,Integer i,Integer j) {
int index = i;
if(i <= targetStr.length() - sourceStr.length()){
while (j<=sourceStr.length()){
if(targetStr.charAt(i++) == sourceStr.charAt(j++)){
if(j == sourceStr.length()){
return index;
}
}else {
i = i - j + 1;
j = 0;
return checkStrBF(targetStr,sourceStr,i,j);
}
}
}
return null;
}
KMP方式查找主串中是否包含模式串(先将next数组算出,再匹配)无法适配边读边匹配的场景
/**
* kmp算法匹配串
*/
private static void kmp() {
// 主串
String targetStr = "abaaaabbbbbbbbcccccababaaababaa";
// 模式串
String sourceStr = "ababaaababaa";
// 0 0 0 1 2 3 1 1 2 3 4 5
// 根据模式串计算next数组,前缀和后缀匹配
int[] nextArray = getNextArray(sourceStr);
System.out.println(Arrays.toString(nextArray));
int i = 0;
int j = 0;
// 循环迭代主串,开始匹配
System.out.println(cycle(targetStr, sourceStr, nextArray, i, j, false));
}
/**
* 比较主串中是否包含模式串
* @param targetStr 主串
* @param sourceStr 模式串
* @param nextArray next数组
* @param i 主串索引
* @param j 模式串索引
* @param flag 前一位是否相等标志位
* @return
*/
private static Boolean cycle(String targetStr, String sourceStr, int[] nextArray, int i, int j,boolean flag) {
// 设置主串的循环上限
while(i <= targetStr.length() - sourceStr.length()){
// 设置模式串的循环上限
while(j < sourceStr.length()){
// 如果当前索引的相等,则i和j都累加,比较下一位。
if(targetStr.charAt(i) == sourceStr.charAt(j)){
i++;j++;
// 如果j等于模式串的长度,说明比较结束,找到匹配的字符
if(j == sourceStr.length()){
return true;
}
// 将标志位设置为true,表示前一位相等
flag = true;
}else {
// 判断标志位
// 如果前一位相等当前位不等,主串需要继续在当前位比较。
// 如果前一位不等,主串需要顺移到下一位开始比较
if(!flag){
i++;
}
flag = false;
// j根据next数组回溯位置
j = nextArray[j];
}
}
}
return false;
}
/**
* 根据模式串计算next数组
* @param targetStr
* @return
*/
private static int[] getNextArray(String targetStr){
int[] array = new int[targetStr.length()];
for(int i = 0; i < targetStr.length();i++){
// 索引为0和1的默认从0开始
if(i == 0 || i == 1){
array[i] = 0;
}else{
int index = 0;
// 将前缀和后缀存储在数组中,存储的最大个数为子串长度-1
char[] head = new char[i-1];
char[] tail = new char[i-1];
// 查找次数为i-1次
for(int x = 1; x < i; x++){
// 前缀从0索引开存,后缀从尾索引开始存
head[x-1] = targetStr.charAt(x-1);
tail[i-1-x] = targetStr.charAt(i-x);
// 比较前缀和后缀是否相等
if(compareArray(head,tail)){
index = x;
}
}
array[i] = index;
}
}
return array;
}
/**
* 比较前缀数组和后缀数组是否相等
* @param head
* @param tail
* @return
*/
private static Boolean compareArray(char[] head,char[] tail){
int i = 0;
int j = 0;
while(i < head.length && j < tail.length){
char a = head[i++];
// 因为后缀是从数组尾部开始存的,所以前面的几位有可能是空,所以要取不为空的位
while(tail[j] == '\0'){
j++;
}
char b = tail[j++];
if(a != b){
return false;
}
}
return true;
}
KMP方式查找主串中是否包含模式串(将next数组的求算过程融入到匹配中)
/**
* kmp算法匹配串
*/
private static void kmp() {
// 主串
String targetStr = "abaaaabbbbbbbbcccccababaaababaa";
// 模式串
String sourceStr = "ababaaababaa";
// 0 0 0 1 2 3 1 1 2 3 4 5
int index = 0;
// 循环迭代主串,开始匹配
System.out.println(cycle(targetStr, sourceStr, index));
}
/**
* 比较主串中是否包含模式串
* @param targetStr 主串
* @param sourceStr 模式串
* @param index 主串索引
* @return
*/
private static Boolean cycle(String targetStr, String sourceStr, int index) {
// 主串索引
int i = index;
// 模式串索引
int j = 0;
// 上一位是否相同标志
boolean flag = false;
// 设置主串的循环上限
while(i <= targetStr.length() - sourceStr.length()){
// 设置模式串的循环上限
while(j < sourceStr.length()){
// 如果当前索引的相等,则i和j都累加,比较下一位。
if(targetStr.charAt(i) == sourceStr.charAt(j)){
i++;j++;
// 如果j等于模式串的长度,说明比较结束,找到匹配的字符
if(j == sourceStr.length()){
return true;
}
// 将标志位设置为true,表示前一位相等
flag = true;
}else {
// 判断标志位
// 如果前一位相等当前位不等,主串需要继续在当前位比较。
// 如果前一位不等,主串需要顺移到下一位开始比较
if(!flag){
i++;
}
flag = false;
/**
* 主要修改点,由原先的先计算next数组,变为实时计算next数组
*/
j = getNextArray(sourceStr,j);
}
}
}
return false;
}
/**
* 根据模式串计算next数组
* @param targetStr
* @param index 当前模式串的索引
* @return
*/
private static Integer getNextArray(String targetStr,Integer index){
// 索引为0和1的默认从0开始
if(index > 1){
// 将前缀和后缀存储在数组中,存储的最大个数为子串长度-1
char[] head = new char[index-1];
char[] tail = new char[index-1];
// 查找次数为i-1次
for(int x = 1; x < index; x++){
// 前缀从0索引开存,后缀从尾索引开始存
head[x-1] = targetStr.charAt(x-1);
tail[index-1-x] = targetStr.charAt(index-x);
// 比较前缀和后缀是否相等
if(compareArray(head,tail)){
return x;
}
}
}
return 0;
}
/**
* 比较前缀数组和后缀数组是否相等
* @param head
* @param tail
* @return
*/
private static Boolean compareArray(char[] head,char[] tail){
int i = 0;
int j = 0;
while(i < head.length && j < tail.length){
char a = head[i++];
// 因为后缀是从数组尾部开始存的,所以前面的几位有可能是空,所以要取不为空的位
while(tail[j] == '\0'){
j++;
}
char b = tail[j++];
if(a != b){
return false;
}
}
return true;
}