程序员面试金典 5 (字符串)

本文介绍四种翻转字符串的方法,包括直接交换、使用辅助数据结构等;并提供两种判断字符串字符是否可重新排列成另一字符串的算法;最后探讨如何验证字符串中所有字符是否各不相同。
1 请实现一个算法,在不使用额外数据结构和储存空间的情况下,翻转一个给定的字符串(可以使用单个过程变量)。

给定一个string iniString,请返回一个string,为翻转后的字符串。保证字符串的长度小于等于5000。

//法 1:我的想法  使用额外数据结构  字符数组
public class Reverse{
    public String reverseString(String iniString){
       char[] arr=iniString.toCharArray();
       int start=0;
       int end=arr.length-1;
       while(start<end){
           char tmp=arr[start];
           arr[start]=arr[end];
           arr[end]=tmp;
           start++;
           end--;
       }
       return new String(arr);
     }
}

//法2 :额外的字符串

public class Reverse{
    public String reverseString(String iniString){

     String str="";
    for(int i=0;i<iniString.length();i++){
      str=iniString.charAt(i)+str; //连接顺序刚好相反
    }
  return str;
  }
}


//法3 :利用StringBuffer字符缓存区

public class Reverse{
    public String reverseString(String iniString){

     StringBuffer st=new StringBuffer(iniString);
    return st.reverse().toString();
  }
}

方法4的说明: 折半交换。

将字符串一分为二。分别交换这两部分即可。

递归停止条件是子串长度为2或3.这两种情况可以直接返回交换后的结果。

设字符串长度为 l:

若l为双数,分别处理 substring(l/2,l)+substring(0,l/2).

如“abcdefgh”=>“efgh|abcd”=>“gh|ef|cd|ab”=>“hg|fe|dc|ba”即可。

若l为单数,分别处理substring(l/2+1,l)+ charAt(l/2)+ substring(0,l/2).

如“abcdefghi”=>"fghi|e|abcd"=>"hi|fg|e|cd|ab"=>"ih|gf|e|dc|ba".

//法 4:严格意义上最符合题意的方法

public class Reverse{
    public String reverseString(String iniString){

    if(iniString.length()==2){
     return ""+iniString.charAt(1)+iniString.charAt(0);
   }
   if(iniString.length()==3){
     return ""+iniString.charAt(2)+iniString.charAt(0)+iniString.charAt(1);
   }
   if(iniString.length()%2==0){
     return reverseString(iniString.subString(iniString.length()/2,iniString.length()))+reverseString(iniString.subString(0,iniString.length()/2));
   else{
     return reverseString(iniString.subString(iniString.length()/2+1,iniString.length()))+iniString.charAt(iniString.length()/2)+reverseString(iniString.subString(0,iniString.length()/2);

2. 给定两个字符串,请编写程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。这里规定大小写为不同字符,且考虑字符串重点空格。
给定一个string stringA和一个string stringB,请返回一个bool,代表两串是否重新排列后可相同。保证两串的长度都小于等于5000。


//法1 :排序完再对比两个字符串是否相等
import java.util.*;
public class Same {
     public boolean checkSam(String stringA, String stringB) {
              byte [] b1=stringA.getBytes();
        byte[] b2=stringB.getBytes();
        Arrays.sort(b1);
        Arrays.sort(b2);
        String s1=new String(b1);
        String s2=new String(b2);
        //排序对比每一项
        if(s1.equals(s2))
            return true;
        return false;
       }
}

//法2:用空间换取时间
//使用数组 256 char 8位
import java.util.*;
public class Same {
     public boolean checkSam(String stringA, String stringB) {
        if(stringA==null&&stringB==null) 
         return true;
        if(stringA==null||stringB==null)
         return false; 
        if(stringA.length()!=stringB.length())
         return false;  
        byte [] b1=stringA.getBytes();
        byte[] b2=stringB.getBytes();
        int []bCount=new int[256];
        for(int i=0;i<256;i++)
            bCount[i]=0;
        for(int i=0;i<b1.length;i++)
            bCount[b1[i]]++;
        for(int j=0;j<b2.length;j++)
            bCount[b2[j]]--;
        for(int k=0;k<256;k++){
            if(bCount[k]!=0)
                return false;
        }
        return true;
   }
}


//哈希表
import java.util.*;
public class Same {
     public boolean checkSam(String stringA, String stringB) {
    if(stringA==null&&stringB==null) return true;
        if(stringA==null||stringB==null) return false;
        if(stringA.length()!=stringB.length()) return false;
        HashMap<Character,Integer> mapA=new HashMap<Character,Integer>();
        HashMap<Character,Integer> mapB=new HashMap<Character,Integer>();
        for(int i=0;i<stringA.length();i++){
            mapA.put(stringA.charAt(i),mapA.containsKey(stringA.charAt(i))?mapA.get(stringA.charAt(i))+1:0);
            mapB.put(stringB.charAt(i),mapB.containsKey(stringB.charAt(i))?mapB.get(stringB.charAt(i))+1:0);
        }
        for(char ch:mapA.keySet()) 
           if(mapA.get(ch)!=mapB.get(ch)) 
               return false;
        return true;
   }
}


3 请实现一个算法,确定一个字符串的所有字符是否全都不同。这里我们要求不允许使用额外的存储结构。
给定一个string iniString,请返回一个bool值,True代表所有字符全都不同,False代表存在相同的字符。保证字符串中的字符为ASCII字符。字符串的长度小于等于3000。


//我的想法(但是用到储存结构)
import java.util.*;
public class Different{
     public boolean checkDifferent(String iniString){
         char [] arr=iniString.toCharArray();
         Arrays.sort(arr);
         for(int i=0;i<arr.length-1;i++){
             if(arr[i]==arr[i+1])
                 return false;
         }
     }
}

//法2:用到了额外储存结构,TreeSet  可以去重
import java.util.*;
public class Different{
     public boolean checkDifferent(String iniString){
         int iniLength=iniString.length();
         char [] charArray=iniString.toCharArray();
         TreeSet<Character> after=new TreeSet<Character>();
         for(int i=0;i<charArray.length;i++){
            after.add(charArray[i]);
         }
         int afterLength=after.size();
         if(afterLength==iniLength)
            return true;
         return false;
     }
}
//法3:没有使用额外的储存结构 
import java.util.*;
public class Different{
     public boolean checkDifferent(String iniString){
        if(iniString.length()>256)
            return false;
         for(int i=0;i<iniString.length();i++){
             for(int j=i+1;j<iniString.length();j++){
                 if((iniString.charAt(i)^iniString.charAt(j)==0)
                      return false;
             }
         }
         return true;
     }
}


//法4:万能正则大法好啊!!
import java.util.*;
public class Different{
     public boolean checkDifferent(String iniString){
        return !iniString.matches(".*(.)(.*\\1).*");
注解:
“(.)”表示一个捕获组,“\\1”表示一个反向引用,也就是说“\\1”与“(.)”这两个位置的值可以相同,其他位置都是".*",表示匹配0~n个任意字符。总的来说,这个正则表达式是匹配出现重复字符的字符串。



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值