注意:java中String内置类型,不可更改,要更改的话可考虑转StringBuffer, StringBuilder, char []之类
字符范围:[0,65535]
例1【0-1交换】
把一个0-1串(只包含0和1的串)进行排序,你可以交换任意两个位置,问最少交换的次数?
解析:利用快速排序的partition过程
public class Main {
public static int f(String s){
int sum = 0;
char[]c = s.toCharArray();
int low = 0,high = c.length-1;
while(low<high){
while(low<high && c[low]=='0')
low++;
while(low<high && c[high]=='1')
high--;
if(low<high){
sum++;low++;high--;
}
}
return sum;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine().trim();
System.out.println(f(s));
}
}
例2【交换星号】
一个字符串只包含*和数字,请把它的*号都放开头。
方法一:快排的patition过程(数字的相对位置会发生变化)
public static String f(String s){
char []c = s.toCharArray();
for(int i=0,j=0;j<c.length;j++){
if(c[j]=='*') {
c[j] = c[i];
c[i] = '*';
i++;
}
}
return String.valueOf(c);
}
方法二:倒着复制(数字的相对位置不发生改变)
public static String f(String s){
char []c = s.toCharArray();
int j=c.length-1;
for(int i=c.length-1;i>=0;i--){
if(c[i]!='*') {
c[j] = c[i];
j--;
}
}
while(j>=0){
c[j]='*';j--;
}
return String.valueOf(c);
}
例3【子串变位词】
给定两个串a和b,问b是否是a的子串的变位词。例如输入a = hello, b = lel, lle, ello都是true,但是b = elo是false。
解析:利用滑动窗口的思想
a. 比如b的长度是3,则考察a[0..2], [1..3],[2..4]是否和b是变位词
b.如何比较?用b中的次数减去a中一个“窗口”内的字符种类,如果结果全是0,则找到这样的子串了
c.窗口如何滑动? 向右移动一位 新窗口a[i - lenb + 1..i] 旧窗口a[i – lenb.. i – 1] =》扔掉a[i – lenb] 加入a[i]
public static Boolean f(String s,String son){
int nonZero = 0;
char[]a = s.toCharArray();
char[]b = son.toCharArray();
int []x = new int[26];//统计son中各字符数量
for(int i=0;i<b.length;i++){
if(++x[b[i]-'a']==1)
nonZero++;
}
//第一个窗口[0,b.length-1]
for(int i=0;i<b.length;i++){
int m = a[i] - 'a';
x[m]--;
if(x[m]==0) nonZero--;
else if(x[m]==-1) nonZero++;
}
if(nonZero==0) return true;
/*新窗口a[i-lenb+1,i]
旧窗口a[i-lenb,i-1]*/
for(int i=b.length;i<a.length;i++){
int m = a[i-b.length] - 'a';
x[m]++;
if(x[m]==1) nonZero++;
else if(x[m]==0) nonZero--;
m = a[i] - 'a';
x[m]--;
if(x[m]==0) nonZero--;
else if(x[m]==-1) nonZero++;
if(nonZero==0) return true;
}
return false;
}
例4【单词翻转】
翻转句子中全部的单词,单词内容不变。 例如I’m a student. 变为student. a I’m
解析:先翻转整个句子,再每个单词单独翻转
static String f(String s){
String result = "";
String ns = reverse(s);
String [] a = ns.split(" +");
for(int i=0;i<a.length;i++){
result += reverse(a[i])+" ";
}
return result.trim();
}
static String reverse(String s){
char[]a = s.toCharArray();
int low = 0,high = a.length-1;
while(low<high){
char c = a[low];
a[low] = a[high];
a[high] = c;
low++;high--;
}
return String.valueOf(a);
}
思考题:字符串循环移位abcd
移动1次变为bcda 移动2次变为cdab 移动3次变为dabc
结论: 长度为n, 移动m次,相当于移动m % n次 :前m % n位翻转,后n – m % n位翻转,总体再翻转一次