KMP算法

69 阅读1分钟

简介

假设字符串str长度为N,字符串match长度为M,M <= N

想确定str中是否有某个子串是等于match的。

时间复杂度O(N)

实现

public static int getIndexOf(String s1, String s2) {
   if (s1 == null || s2 == null || s2.length() < 1 || s1.length() < s2.length()) {
      return -1;
   }
   char[] str1 = s1.toCharArray();
   char[] str2 = s2.toCharArray();
   int x = 0;
   int y = 0;
   // O(M) m <= n
   int[] next = getNextArray(str2);
   // O(N)
   while (x < str1.length && y < str2.length) {
      if (str1[x] == str2[y]) {
         x++;
         y++;
      } else if (next[y] == -1) { // y == 0
         x++;
      } else {
         y = next[y];
      }
   }
   return y == str2.length ? x - y : -1;
}

public static int[] getNextArray(char[] str2) {
   if (str2.length == 1) {
      return new int[] { -1 };
   }
   int[] next = new int[str2.length];
   next[0] = -1;
   next[1] = 0;
   int i = 2; // 目前在哪个位置上求next数组的值
   int cn = 0; // 当前是哪个位置的值再和i-1位置的字符比较
   while (i < next.length) {
      if (str2[i - 1] == str2[cn]) { // 配成功的时候
         next[i++] = ++cn;
      } else if (cn > 0) {
         cn = next[cn];
      } else {
         next[i++] = 0;
      }
   }
   return next;
}

题目一

给定两棵二叉树的头节点head1和head2

想知道head1中是否有某个子树的结构和head2完全一样

public static boolean containsTree2(Node big, Node small) {
   if (small == null) {
      return true;
   }
   if (big == null) {
      return false;
   }
   ArrayList<String> b = preSerial(big);
   ArrayList<String> s = preSerial(small);
   String[] str = new String[b.size()];
   for (int i = 0; i < str.length; i++) {
      str[i] = b.get(i);
   }

   String[] match = new String[s.size()];
   for (int i = 0; i < match.length; i++) {
      match[i] = s.get(i);
   }
   return getIndexOf(str, match) != -1;
}

public static ArrayList<String> preSerial(Node head) {
   ArrayList<String> ans = new ArrayList<>();
   pres(head, ans);
   return ans;
}

public static void pres(Node head, ArrayList<String> ans) {
   if (head == null) {
      ans.add(null);
   } else {
      ans.add(String.valueOf(head.value));
      pres(head.left, ans);
      pres(head.right, ans);
   }
}

public static int getIndexOf(String[] str1, String[] str2) {
   if (str1 == null || str2 == null || str1.length < 1 || str1.length < str2.length) {
      return -1;
   }
   int x = 0;
   int y = 0;
   int[] next = getNextArray(str2);
   while (x < str1.length && y < str2.length) {
      if (isEqual(str1[x], str2[y])) {
         x++;
         y++;
      } else if (next[y] == -1) {
         x++;
      } else {
         y = next[y];
      }
   }
   return y == str2.length ? x - y : -1;
}

public static int[] getNextArray(String[] ms) {
   if (ms.length == 1) {
      return new int[] { -1 };
   }
   int[] next = new int[ms.length];
   next[0] = -1;
   next[1] = 0;
   int i = 2;
   int cn = 0;
   while (i < next.length) {
      if (isEqual(ms[i - 1], ms[cn])) {
         next[i++] = ++cn;
      } else if (cn > 0) {
         cn = next[cn];
      } else {
         next[i++] = 0;
      }
   }
   return next;
}

public static boolean isEqual(String a, String b) {
   if (a == null && b == null) {
      return true;
   } else {
      if (a == null || b == null) {
         return false;
      } else {
         return a.equals(b);
      }
   }
}

题目二

判断str1和str2是否是旋转字符串

public static boolean isRotation(String a, String b) {
   if (a == null || b == null || a.length() != b.length()) {
      return false;
   }
   String b2 = b + b;
   return getIndexOf(b2, a) != -1;
}

// KMP Algorithm
public static int getIndexOf(String s, String m) {
   if (s.length() < m.length()) {
      return -1;
   }
   char[] ss = s.toCharArray();
   char[] ms = m.toCharArray();
   int si = 0;
   int mi = 0;
   int[] next = getNextArray(ms);
   while (si < ss.length && mi < ms.length) {
      if (ss[si] == ms[mi]) {
         si++;
         mi++;
      } else if (next[mi] == -1) {
         si++;
      } else {
         mi = next[mi];
      }
   }
   return mi == ms.length ? si - mi : -1;
}

public static int[] getNextArray(char[] ms) {
   if (ms.length == 1) {
      return new int[] { -1 };
   }
   int[] next = new int[ms.length];
   next[0] = -1;
   next[1] = 0;
   int pos = 2;
   int cn = 0;
   while (pos < next.length) {
      if (ms[pos - 1] == ms[cn]) {
         next[pos++] = ++cn;
      } else if (cn > 0) {
         cn = next[cn];
      } else {
         next[pos++] = 0;
      }
   }
   return next;
}

public static void main(String[] args) {
   String str1 = "yunzuocheng";
   String str2 = "zuochengyun";
   System.out.println(isRotation(str1, str2));

}