算法Day8:字符串专题——变形词、旋转词、回文串

蓝桥杯算法合集: 蓝桥杯算法合集(终极完结版)

最近忙着搭建个人博客,已经快半个月没写题了,手感都快没了。现在博客的事情基本差不多了,重心也该转到算法上来了。
字符串在蓝桥杯算法竞赛上基本上很常见的出题载体,旋转词、回文串、单词翻转等等。在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));
			
		}

	}

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值