蓝桥杯算法合集: 蓝桥杯算法合集(终极完结版)
最近忙着搭建个人博客,已经快半个月没写题了,手感都快没了。现在博客的事情基本差不多了,重心也该转到算法上来了。
字符串在蓝桥杯算法竞赛上基本上很常见的出题载体,旋转词、回文串、单词翻转等等。在Java中String是不可变的,一经声明创建就不能修改,因此要熟练掌握字符串与字符数组的转换以及动态字符串StringBuilder和StringBuffer的API。下面列出几点:
字符串常用API
字符串转字符数组
String s;
char [] arra=s.toCharArray();
字符串转可变字符串
String s;
StringBuilder sb=new StringBuilder(s);
字符串常用方法
String s,s1;
s.contains(s1) //是否包含子串s1
s.replaceAll('正则表达式被替换字符','替换字符')
StringBuilder常用方法
StringBuilder sb=new StringBuilder([字符串]);
sb.append('字符') //添加字符
sb.reverse() //翻转字符串sb
sb.toString() //得到sb的字符串类型
sb.replace()//replace(int start, int end, String str) 使用给定 String 中的字符替换此序列的子字符串中的字符。
变形词
/*
*对于两个字符串A和B,如果A和B中出现的字符种类相同
*且每种字符出现的次数相同,则A和B互为变形词,
*这里规定大小写为不同字符且考虑空格
*例如:aabcd和bcada互为变形词
*请设计一个高效算法,检查两给定串是否互为变形词。
*
*/
package 字符串;
import java.util.Arrays;
import java.util.Scanner;
public class 变形词 {
//使用javaAPI
public static boolean check1(String s1,String s2) {
//先把两个字符串转为数组后 排序 判断两个数组是否完全一致
//复杂度n*log(n)
if(s1.length()!=s2.length())
return false;
char[] charArr1 = s1.toCharArray();
char[] charArr2 = s2.toCharArray();
Arrays.sort(charArr1);
Arrays.sort(charArr2);
return Arrays.equals(charArr1, charArr2);
//charArr1.equals(charArr2); abd bda false这是因为数组地equal比较的是两个数组的地址
}
//要求字符串的元素必须在Ascii或者Unicode编码表里
public static boolean check2(String s1,String s2) {
int len1=s1.length();
int len2=s2.length();
if(len1!=len2)
return false;
int [] a=new int[255];
for (int i=0;i<len1;i++) {
int c=(int)s1.charAt(i);
a[c]++;
}
for(int i=1;i<len2;i++) {
int c=(int)s2.charAt(i);
a[c]--;
//s2的某个元素多了
if(a[c]<0) return false;
}
for (int i=0;i<len1;i++) {
//s1的某个元素多了
if(a[i]>0) return false;
}
return true;
}
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
while(true) {
String s1=reader.next();
String s2=reader.next();
System.out.println(check2(s1,s2));
}
}
}
单词翻转
/*
将字符串中按单词翻转,如:(I want to be a painter)
变为 (painter a be to want I)
*/
package 字符串;
import java.util.Scanner;
/*
* 与前面翻转字符串类似 不过这里要在字符串翻转的基础上再进行单词翻转
*/
public class 单词反转 {
public static String reverse(String s) {
//以s为范本得到一个字符串
StringBuilder sb=new StringBuilder(s);
return sb.reverse().toString(); //.toString();
}
public static StringBuilder reverseWords(String s) {
String initS=reverse(s);
StringBuilder sb=new StringBuilder();
//sb没有split方法
/*
\s 表示匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
注意特殊字符如&需要转义 Java中用\\表示转义字符\
*/
//以空格分隔字符串得到字符串数组
String[] arr=initS.split("\\s");
int len=arr.length;
for(int i=0;i<len;i++) {
//System.out.println(arr[i]);
sb.append(reverse(arr[i])+" ");
}
return sb;
}
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
//while(true) {
String s=reader.nextLine();
System.out.println(reverseWords(s));
//}
}
}
翻转字符串
/*
*请写一个算法 实现翻转字符串
*例如
*hello world
*dlrow olleh
*
*/
package 字符串;
import java.util.Arrays;
import java.util.Scanner;
public class 翻转字符串 {
public static String reverse(String s) {
//以s为范本得到一个字符串
StringBuilder sb=new StringBuilder(s);
return sb.reverse().toString(); //.toString();
}
public static String reverse1(String s) {
int len=s.length();
char [] c=new char[len];
StringBuffer sb=new StringBuffer();
for(int i=0;i<len;i++) {
c[i]=s.charAt(len-1-i);
}
sb.append(c, 0, len);
//Arrays.toString(c) abd [d, b, a]
//StringBuffer类可变字符串变String类
return sb.toString();
//return new String(c)
}
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
while(true) {
String s=reader.next();
System.out.println(reverse1(s));
}
}
}
回文串
/*
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
比如“level”或者“noon”就是回文串。
*/
package 字符串;
import java.util.Scanner;
public class 回文串 {
//le v el noon
public static boolean isPalindrome(String initS) {
int len=initS.length()-1;
int mid=len/2;
for(int i=0;i<=mid;i++) {
if(initS.charAt(i)!=initS.charAt(len-i))
return false;
}
return true;
}
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
while(true) {
String s=reader.next();
System.out.println(isPalindrome(s));
}
}
}
判断两字符串的字符集是否相同
/*给定两个字符串判断它们的字符集是否相同。
例如:“aaabbcc”和“abc”的字符集是相同的,字符集都是{a,b,c}。
* "abcd"与“aaccd”则不同,前者字符集合为{a,b,c,d}后者为{a,c,d}
*
*
*/
package 字符串;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class 判断两字符串的字符集是否相同 {
//假设两个字符串的字符集都是Unicode集的一个子集
/*
* 扫描第一个字符串 将出现的字符对应的Unicode编码位置 记为1
* 那么扫描第二个字符串时 若出现的的字符编码第一个字符没有 也就是该位置为0则可以直接返回false
*/
private static boolean check1(String s1, String s2) {
int []a=new int[255];
int []b=new int[255];
//扫描s1
for(int i=0;i<s1.length();i++) {
int c=(int)s1.charAt(i);
if(a[c]==0) {
a[c]=1;
}
}
//扫描s2
//还要考虑s2的字符种类是s1的子集 比如说abcd aaccd因此需要用再上一个数组统计s2的字符种类
for(int i=0;i<s2.length();i++) {
int c=(int)s2.charAt(i);
if(a[c]==0) {
return false;
}
if(b[c]==0) {
b[c]=1;
}
}
int sum1=0;
int sum2=0;
//需再额外判断
for(int i=0;i<a.length;i++) {
sum1+=a[i];
sum2+=b[i];
}
if(sum1!=sum2) {
return false;
}
return true;
}
/*这题与前面变形词类似,不同的地方在于,对字符出现的次数没要求。
*只要你s1出现的字符我s2都有
*同样的s2有的字符我s1也一个都不能少(这一点不要漏了)
*可以使用set结构 但必须要使用两个set分别统计字符种类的个数
*/
//使用Se集合统计出现的字符
private static boolean check2(String s1, String s2) {
Set<Character> set=new HashSet<> ();
Set<Character> set2=new HashSet<> ();
for(int i=0;i<s1.length();i++) {
set.add(s1.charAt(i));
}
int size=set.size();
for(int i=0;i<s2.length();i++) {
char c=s2.charAt(i);
if(!set.contains(c)) {
return false;
}
set2.add(c);
}
//还要多加一步判断 如果s1的字符种类比s2的多 如 abcd aaccdd 应返回false
if(set.size()!=set2.size())
return false;
return true;
}
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
while(true) {
String s1=reader.next();
System.out.println(s1);
String s2=reader.next();
System.out.println(s2);
System.out.println(check1(s1,s2));
System.out.println(check2(s1,s2));
}
}
}
判断字符串有误重复字符
/*
*实现一个算法来判断一个字符串中的字符是否唯一(即没有重复).
*不能使用额外的数据结构。 (即只使用基本的数据结构)
*是ASCII字符,还是只是26个字母? 还是有更大的字符集,
*对于不同的情况,可能会有不同的解决方案。
*/
package 字符串;
import java.util.Scanner;
public class 判断字符串有无重复重复字符 {
public static boolean check(String s) {
//假设该字符串全是Ascii码组成 全为Unicode也类似地
char[] a=new char[128];
for(int i=0;i<s.length();i++) {
int c=(int)s.charAt(i);
if(a[c]==0) {
a[c]=1;
}else {
return false;
}
}
return true;
}
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
while(true) {
String s=reader.next();
System.out.println(check(s));
}
}
}
替换空格
/*
请编写一个方法,将字符串中的空格全部替换为“%20”。
假定该字符串有足够的空间存放新增的字符,并且知道字符串的真实长度(小于等于1000),
同时保证字符串由大小写的英文字母组成。
给定一个string iniString 为原始的串,以及串的长度 int len, 返回替换后的string。
测试样例:
"Mr John Smith”,13
返回:"Mr%20John%20Smith"
*/
package 字符串;
import java.util.Scanner;
public class 替换空格 {
//使用java API
public static String replace1(String s,int len) {
/*
replaceAll(String regex, String replacement)
regex -- 匹配此字符串的正则表达式。
newChar -- 用来替换每个匹配项的字符串。
在Java中 正则表达式前要有“\\”转义 s表示字符串
*/
return s.replaceAll("\\s", "%20");
}
public static String replace2(String s,int len) {
//计算新字符串长度
int newlen=len;
for(int i=0;i<s.length();i++) {
//原先空格 现在%20 多了两个字符长度
if(s.charAt(i)==' ') {
newlen+=2;
}
}
System.out.println(newlen);
int p1=0;
//注意:StringBuffer无参构造方法,构造一个没有字符的字符串缓冲区,初始容量为16个字符。
StringBuffer ns=new StringBuffer(newlen);
while(p1<=len-1) {
if(s.charAt(p1)==' ') {
ns.append('%');
ns.append('2');
ns.append('0');
}else
ns.append(s.charAt(p1));
p1++;
}
return ns.toString();
}
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
while(true) {
String s1=reader.nextLine();
int len=reader.nextInt();
System.out.println(replace1(s1,len));
System.out.println(replace2(s1,len));
}
}
}
旋转词
/*
如果字符串t是字符串s的后面若干个字符循环右移得到的,称s和t是旋转词,
例如"abedef"和"efabed"是旋转词,而"abedef"和"feabcd"旋转词。
尝试设计一个算法判断一个字符串s2可否由另一个字符串s1旋转得到
示例:
abc ab
false
ab abc
true
defa fabde
true
fabde defa
false
*/
package 字符串;
import java.util.Scanner;
public class 旋转词 {
/*
* 一开始的想法是穷举法 把s1的所有旋转词都列出来 然后看看s2在不在里面
* 后来看了视频是有规律的:
* 比如s1=abedef s2=efabed
* efabedefabed 会发现两个s2拼在一起出现了 s1 也就是说旋转此的特征是:
* 原字符串是 旋转之后得到的词语两个拼接在一起的字符串的子集
*/
public static boolean isRevolve(String s1,String s2) {
StringBuilder sb=new StringBuilder(s2).append(s2);
//contians(charSequence s)
return sb.toString().contains(s1);
}
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
while(true) {
String s1=reader.next();
String s2=reader.next();
System.out.println(isRevolve(s1,s2));
}
}
}