1、判断字符串有无重复字符
class test{
public static void main(String[] args) {
String inistring = "abcdaef";
System.out.println(check(inistring));
}
static boolean check(String inistring){
int [] flag = new int[128]; //128ascall码的用法
for(int i=0;i<inistring.length();i++){
int c = (int)(inistring.charAt(i));
if(flag[c]>0) return false;
else flag[c]++;
}
return true;
}
}
2、巧妙翻转字符串
例如 : this is nowcoder
翻转为: redcowon si siht
class test{
public static void main(String[] args) {
String inistring = "abcdaef";
}
static String reverstring(String inistring){
int len = inistring.length();
char[] chararr = new char[len];
for(int i=0;i<len;i++){
chararr[i] = inistring.charAt(len-i+1);
}
return new String(chararr);
}
}
class test{
public static void main(String[] args) {
String inistring = "abcdaef";
}
static String reverstring(String inistring){
StringBuffer sb = new StringBuffer(inistring);
return sb.reverse().toString();
}
}
3、变形词问题
两个字符串,,其中一个能不能通过换一换顺序变成另一个字符串
思路:把两个换成字符数组,,然后arrays.sort排序,,最后Arrays.equals(a,b)就可以了
4、替换字符串中的空格(空格换成%20)
class test{
public static void main(String[] args) {
String inistring = "abcdaef";
System.out.println(replace("haha hehe"));
}
static String replace(String inistring){
return inistring.replaceAll("\\s","%20");
}
}
但是这个题主要不是考察这个,,,而是 字符串不可变,,增加空间的问题
class test{
public static void main(String[] args) {
String inistring = "abcdaef";
System.out.println(replace("haha hehe0000000000000000".toCharArray(),15));
}
static String replace(char[] inistring,int length){
int count = length;
for(int i=0;i<length;i++){
if(inistring[i] == ' '){
count+=2;
}
}
//然后用快慢指针做
int p1 = length-1;
int p2 = count-1;
while (p1>=0){
if(inistring[p1]==' '){
inistring[p2--] = ' ';
inistring[p2--] = '2';
inistring[p2--] = '%';
}else {
inistring[p2--] = inistring[p1];
}
p1--;
}
return new String(inistring,0,count);
}
}
5、压缩字符串(字符串统计)
aabbccccaaa
class test2{
public static void main(String[] args) {
}
static String zipString(String str){
int count =0;
char last =0;
StringBuilder sb = new StringBuilder();
for(int i=0;i<str.length();i++){
char charat = str.charAt(i);
if (sb.length() == 0) {
sb.append(charat);
count++; //加第一个字符
}else {
if(last==charat){
count++;
}else {
sb.append(count).append(charat);
count++;
}
}
last = charat;
}
if(count>=1){
sb.append(count);
}
if(sb.length()>=str.length()){
return str;
}
return sb.toString();
}
}
6、问两个字符串的字符集相同否?
class test2{
public static void main(String[] args) {
}
static boolean check(String str1,String str2){
int []help = new int[256];
for(int i=0;i< str1.length();i++){
char c = str1.charAt(i);
if (help[c] == 0) {
help[c] =1;
}
}
for(int i=0;i<str2.length();i++){
char c = str2.charAt(i);
if(help[c]==0){
return false;
}
}
return true;
}
}
用hashmap的话就不用限制256 还是128,,,这样就不需要要求hashmap了
import java.util.HashMap;
import java.util.Map;
class test2{
public static void main(String[] args) {
}
static boolean check(String str1,String str2){
Map<Character,Integer> map = new HashMap<>();
for(int i=0;i< str1.length();i++){
char c = str1.charAt(i);
if (map.get(c)==0) {
map.put(c,1);
}
}
for(int i=0;i<str2.length();i++){
char c = str2.charAt(i);
if(map.get(c)==null){
return false;
}
}
return true;
}
}
7、旋转词
给两个串,s1和s2,问s2能否通过s1做循环移位得到
s1:A A B C D
s2:C D A A
思路:s1×2 看看包不包含s2就可以了
class test2{
public static void main(String[] args) {
}
static boolean check(String str1,String str2){
StringBuilder sb = new StringBuilder();
sb.append(str1).append(str1);
return sb.toString().contains(str2);
}
}
8、单词的翻转(其实stringbuilder 和stringbuffer的区别不太大,但是推荐用stringbuild 因为他的速度会快一些)
here you are
转成 are you here
class test2{
public static void main(String[] args) {
String res = reverse("here you are");
}
static String reverse(String str){
String s1 = reversestring(str);
String []words = s1.split("\\s");
StringBuilder sb = new StringBuilder();
for(int i=0;i<words.length;i++){
sb.append(reversestring(words[i]+" "));
}
}
static String reversestring(String str){
StringBuilder sb = new StringBuilder(str);
return sb.reverse().toString();
}
}
9、去掉字符串中连续出现k次的0
java正则操作
class test2{
public static void main(String[] args) {
String res = remove("here you000are",3);
System.out.println(res);
}
static String remove(String str,int k){
String regexp = "0{"+k+"}";
return str.replaceAll(regexp,""); //前面直接写的话加双引号"0{3}"
}
}
10、最短摘要
集齐所有关键字的最短串
例题:一个产品的英文简介,包含m个英文单词,每个单词空格分开,没有其他标点符号,给n个单词关键字,
思路:借鉴尺取法
思路:如果暴力的话每一次都要从下一个重新来,,尺取法比较跳跃,i和j两个指针,,i先找到第一个n,然后j从i开始往后找,知道包含所有的关键字停止,然后i再向后扫,找到下一个关键字停止,,看从i到j是否包含所有的关键字,若包含,更新最短距离,若不包含,,j往下扫,直到包含完所有的关键字停止,计算最短路。。更新,,,,过程中,i和j从不回头
class test2{
public static void main(String[] args) {
solve2(new String[]{"a", "b", "c", "seed", "c", "e", "f", "c", "c", "seed", "e", "f", "seed", "c"}, new String[]{"c", "c", "e", "f"});
}
static void solve2(String []w, String [] keys){
int begin = -1; //begin和end是确定的头和尾
int end = -1;//而j和i是下一次移动的光标
int j=-1;
int minlen = 0;
int p2 = -1;
int len =0;
int []keyfound = new int[keys.length];//判断重复关键字 不让一个关键字出现好几次而别的没有出现
for(int i=0;i<w.length;i++){
String w1 = w[i];
int index = indexOf(keys,w1);
if(index == -1){
continue; //没找着,,意思就是他不是关键字
}
else { //i是一个关键字,
keyfound[index] = 1;
}
if(p2!=j){
j = p2;
}else {
j=i+1;
}
for (;j<w.length;j++){
String w2 = w[j];
int index1 =indexOf(keys,w2);
if(index1==-1 || keyfound[index1]==1){
continue;
}else { //扎到了
keyfound[index1] = 1;
if(sum(keyfound) == keys.length){
p2 = j;
if(j-i+1<len){
len = j=i+1;
begin = i;
end = j;
}
}
}
}
}
}
static int sum(int [] keyfound){
int sum =0;
for (int e:keyfound){
sum+=e;
}
return sum;
}
static int indexOf(String []keys,String w){
for(int i=0;i<keys.length;i++){
if(keys[i].equals(w)){
return i;
}
}
return -1;
}
}
上面代码可能不对,,下面是正确的代码
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Edge {
public static void main(String[] args) {
solve2(new String[]{"a", "b", "c", "seed", "c", "e", "f", "c", "c", "seed", "e", "f", "seed", "c"}, new String[]{"c", "c", "e", "f"});
solve2(new String[]{"a", "b", "a", "a", "b", "c", "d", "h", "e", "f", "f"}, new String[]{"b", "c", "d"});
}
public static void solve2(String[] w, String[] keys) {
Arrays.sort(keys);
//begin和end用于在找到更短的包含全部关键字的子数组时更新
int begin = -1;
int end = -1;
int j = -1;//上一次囊括了所有关键字的右边界
int minLen = Integer.MAX_VALUE;
for (int i = 0; i < w.length; i++) {
//如果i位置是关键字,求以i开头包含所有关键字的序列
String word1 = w[i];
int index = Arrays.binarySearch(keys, word1);
if (-1 == index) {
continue;
}
if (j == -1){
j = i + 1;
}
while (j < w.length) {
String word2 = w[j];//文章单词
int index1 = Arrays.binarySearch(keys, word2);
if (index1 == -1) {
j++;
continue;
} else {//找到关键字
if (containsAll(keys, w, i, j)) {//全部到齐
if (j - i + 1 < minLen) {//更新
minLen = j - i + 1;
begin = i;
end = j;
}
break;
} else {
j++;
}
}
}
}
print(w, begin, end);
}
private static void print(String[] w, int begin, int end) {
System.out.println(begin + " " + end);
for (int i = begin; i <= end; i++) {
System.out.print(w[i] + " ");
}
System.out.println();
}
private static boolean containsAll(String[] keyWords, String[] w, int i, int j) {
Map<String, Integer> map = new HashMap<>();
for (int k = 0; k < keyWords.length; k++) {
String key = keyWords[k];
if (map.get(key) == null) {
map.put(key, 1);
} else {
map.put(key, map.get(key) + 1);
}
}
Map<String, Integer> map2 = new HashMap<>();
for (int k = i; k <= j; k++) {
String key = w[k];
if (map2.get(key) == null) {
map2.put(key, 1);
} else {
map2.put(key, map2.get(key) + 1);
}
}
for (Map.Entry<String, Integer> e :
map.entrySet()) {
if (map2.get(e.getKey()) == null || map2.get(e.getKey()) < e.getValue()) {
return false;
}
}
return true;
}
}
11、开启字符串匹配的算法
第一种:RabinKarp
第二种:KMP
第三种:前缀树(字典树 ,Trie);后缀数组
第一种:(滚动哈希)
ABABAB
BAB
下面三个求哈希,上面从每一个开始,每三个求一个哈希,,,比对哈希值
小tip:C0*31^2 + C1*31^1+C2
可以用递推循环施展开((0+C0)×31+C1)×31+C2
普通哈希:
class test{
public static void main(String[] args) {
}
static long hash(String str){
long hash = 0;
for (int i=0;i!=str.length();i++){
hash += 31*hash+str.charAt(i);
}
return hash;
}
static void match(String p,String s){
long hash_p = hash(p);
for (int i=0;i+p.length()<=s.length();i++){
long hash = hash(s.substring(i,i+p.length()));
if(hash == hash_p){
System.out.println("match");
}
}
}
}
滚动哈希:不用每三个都算一次了,可以递推求出后面的哈希
哈希冲突:十万数据,波动大概在0~3;百万数据,冲突大概在110+ ,竞赛中不太需要去补那一下,,如果想的话再判断一次 模式串是否等于字符串就可以了
class test{
public static void main(String[] args) {
}
static long[] hash(String s,int n){ //n代表几个求一个hash
long[] res = new long[s.length()-n+1];
res[0] = hash(s.substring(0,n));
for(int i=n;i<s.length();i++){
char newchar = s.charAt(i);
char ochar = s.charAt(i-n);
long v =(res[i-n]*seed +newchar-NExponent.ex2(seed,n)*ochar)%long.MAX_VALUE;
res[i-n+1] = v;
}
return res;
}
}
第二种:KMP(next数组很重要)kmp整体的复杂度在O(m+n)
这里的next数组好像不太对,因为next数组第一个数字是-1,而第二个数字是0 这里的next数组求出来是0 0 1 2 3 但是整体是对的,,不懂的话可以把案例带进去感受一下,,,很好懂的
public class test6 {
public static int kmp(String str, String dest,int[] next){//str文本串 dest 模式串
for(int i = 0, j = 0; i < str.length(); i++){
while(j > 0 && str.charAt(i) != dest.charAt(j)){
j = next[j - 1];
}
if(str.charAt(i) == dest.charAt(j)){
j++;
}
if(j == dest.length()){
return i-j+1;
}
}
return 0;
}
public static int[] kmpnext(String dest){
int[] next = new int[dest.length()];
next[0] = 0;
for(int i = 1,j = 0; i < dest.length(); i++){
while(j > 0 && dest.charAt(j) != dest.charAt(i)){
j = next[j - 1];
}
if(dest.charAt(i) == dest.charAt(j)){
j++;
}
next[i] = j;
}
return next;
}
public static void main(String[] args){
String a = "ababa";
String b = "ssdfgasdbababa";
int[] next = kmpnext(a);
int res = kmp(b, a,next);
System.out.println(res);
for(int i = 0; i < next.length; i++){
System.out.println(next[i]);
}
System.out.println(next.length);
}
}
注释掉的代码是可以变种为计算出现这个字符串的次数的;
kmp的正确姿势
判断模式串在字符串中在哪里出现
class test3{
public static void main(String[] args) {
String src = "babababcbabababb";
int index = indexOf1(src, "bababb");
System.out.println(index);
}
static int indexOf1(String s,String p){
if(s.length()==0|| p.length()==0) return -1;
if(p.length()>s.length()) return -1;
// int count = 0;
int next[] = next(p);
int i = 0;
int j =0;
int slen = s.length();
int plen = p.length();
while (i<slen){
if(j==-1 || s.charAt(i) == p.charAt(j)){
i++;
j++;
}else {
j = next[j];
}
if(j==plen){
return i-j;
}
}
return -1;
}
static int[] next(String p){
int length = p.length();
int next[] = new int[length];
char p_c[] =p.toCharArray();
next[0] = -1;
if(length==1){
return next;//在这里判断不要越界了,如果长度为一,写next(1)的话就会越界
}
next[1] = 0;
int j = 1;//next(1)= 0 next(j) = k;
int k = 0;
//一直到next数组填到完就可以了
while (j<length-1){
if(k<0 || p_c[j]==p_c[k]){
next[j+1] = k+1;
j = j+1;
k = k+1;
//上面这三句可以归为一句就是next[++j] = ++k; 这一句变成next[J+1]=K+1 后还有两句是因为这句过后i和j并没有自增,没有变化
}else {
k = next[k];//不同
}
}
return next;
}
}
还有可能字符串中并不只有一个模式串’,需要算有多少个,,代码只需要改几行 标星号的地方就是需要修改的地方
class test3{
public static void main(String[] args) {
String src = "babababcbabababb";
int index = indexOf1(src, "bab");
System.out.println(index);
}
static int indexOf1(String s,String p){
if(s.length()==0|| p.length()==0) return -1;
if(p.length()>s.length()) return -1;
int count = 0;//**********************************
int next[] = next(p);
int i = 0;
int j =0;
int slen = s.length();
int plen = p.length();
while (i<slen){
if(j==-1 || s.charAt(i) == p.charAt(j)){
i++;
j++;
}else {
j = next[j];
}
if(j==plen){
count++;//********************************************
i--;//************************************
j =next[j-1];//********************************
}
}
return count;//**********************************
}
static int[] next(String p){
int length = p.length();
int next[] = new int[length];
char p_c[] =p.toCharArray();
next[0] = -1;
if(length==1){
return next;//在这里判断不要越界了,如果长度为一,写next(1)的话就会越界
}
next[1] = 0;
int j = 1;//next(1)= 0 next(j) = k;
int k = 0;
//一直到next数组填到完就可以了
while (j<length-1){
if(k<0 || p_c[j]==p_c[k]){
next[++j] = ++k;
}else {
k = next[k];//不同
}
}
return next;
}
}
最后,,来写一下kmp的暴力法吧
class test3{
public static void main(String[] args) {
String src = "babababcbabababb";
int index = indexOf2(src, "bababb");
System.out.println(index);
}
static int indexOf2(String s,String p){
int i=0;
int j=0;
int sc = 0;
while (sc<s.length()){
if(s.charAt(sc)==p.charAt(j)){
sc++;
j++;
if(j==p.length()){
return i;
}
}else {
i++;
sc =i;//扫描指针sc以i为起点
j=0;// j恢复0
}
}
return -1;
}
}
第三种:后缀数组:暂且先不写。。。。