字符串相关

编程语言均为JAVA。

字符串面试题类型

  1. 规则判断:字符串是否符合某个规则
    如整数规则,浮点数规则,回文字符串规则;
  2. 数字运算
    字符串拼大整数的方式实现加减乘除运算,模拟笔算过程。
  3. 与数组操作相关的类型
    (1)数组有关的调整,排序等操作
    (2)快排的改写等
  4. 字符计数
    c/c++中字符的ASCII码范围0-255,java中0-65535
    (1)哈希表
    (2)固定长度的数组
    (3)滑动窗口问题
    (4)寻找无重复字符子串问题
    (5)计算变位词问题
  5. 动态规划问题
    最长公共子串,最长公共子序列,最长回文子串,最长回文子序列等;
  6. 搜索问题
    宽度优先搜索,深度优先搜索
  7. 高级算法结构
    KMP算法,马拉车算法等

拓扑结构相同子树问题

对于两棵彼此独立的二叉树A和B,请编写一个高效算法,检查A中是否存在一棵子树与B树的拓扑结构完全相同。给定两棵二叉树的头结点A和B,请返回一个bool值,代表A中是否存在一棵同构于B的子树。

解题思路:首先了解子树的概念:子树是指一个节点及其这个节点下面的所有子节点。此题是寻找一个树中是否存在子树与另一棵树的拓扑结构相同,可转化为字符串问题求解,即在一个字符串p中寻找模式子串s的问题,故可以将树进行序列化转化为字符串,然后利用KMP算法求解。
代码实例:

import java.util.*;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}*/
public class IdenticalTree {
    public boolean chkIdentical(TreeNode A, TreeNode B) {
        //序列化A,B两棵树
        String strA = serialByPre(A);
        String strB = serialByPre(B);

        //利用KMP算法求解并返回结果
        return getIndexOfSubString(strA,strB)>=0?true:false;

    }

    //KMP算法:获取模式子串的位置

    public int getIndexOfSubString(String strP,String strM){

        //边界条件判断
        if(strP==null||strM==null||strP.length()1){
            return -1;
        }

        //字符串转化为字符数组
        char[] charP = strP.toCharArray();
        char[] charM = strM.toCharArray();

        int i = 0;
        int j = 0;
        //获取KMP中next数组
        int[] next = getNextArray(charM);

        //寻找模式子串的过程
        while(iif(j==-1||charP[i]==charM[j]){

                i++;
                j++;

            }else{
                j = next[j];
            }

        }

        //返回索引值或者-1
        return j==charM.length?i-j:-1;

    }

    //获取KMP算法中的next数组

    public int[] getNextArray(char[] charM){

        int[] next = new int[charM.length];
        //第一个值为-1
        next[0] = -1;
        int j = 0;
        int k = -1;

        while(j1){

            if(k==-1||charM[j]==charM[k]){
                k++;
                j++;

                if(charM[j]!=charM[k]){
                   next[j] = k;
                }else{
                    next[j] = next[k];
                }


            }else{
                k = next[k];
            }   

        }

        return next;

    }

    //序列化树 前序遍历
    public String serialByPre(TreeNode head){

        //空节点用#1
        if(head==null){
            return "#!";
        }

        //使用可变字符串
        StringBuffer result = new StringBuffer();
        result = result.append(head.val+"!");
        result = result.append(serialByPre(head.left));
        result = result.append(serialByPre(head.right));

        return result.toString();         

    } 

}

词语变形问题

题目
对于两个字符串A和B,如果A和B中出现的字符种类相同且每种字符出现的次数相同,则A和B互为变形词,请设计一个高效算法,检查两给定串是否互为变形词。

给定两个字符串A和B及他们的长度,请返回一个bool值,代表他们是否互为变形词。

测试样例:
“abc”,3,”bca”,3
返回:true

解题思路:设定一个大小为256的int数组,存储其中一个字符串中字符种类及字符出现的次数,然后在遍历另一个字符串,统计其字符种类以及每个字符出现的次数,在int数组上找到对应字符则减1,如果中间出现对应字符存储数值为0的话则返回false,否则遍历结束返回true.

代码实例:

import java.util.*;

public class Transform {
    public boolean chkTransform(String A, int lena, String B, int lenb) {
        //边界条件判断
        if(A==null||B==null||lena!=lenb){
            return false;
        }

        //字符串转字符数组处理
        char[] charA = A.toCharArray();
        char[] charB = B.toCharArray();

        //整形数组,存储字符数组中字符种类以及每种字符出现次数
        int[] map = new int[256];

        for(int i=0;i1;

        }


        //比较两个字符串字符种类以及字符出现次数
        for(int j=0;jif(map[charB[j]]==0){
                return false;
            }else{
                map[charB[j]] -= 1;
            }

        }

        return true;

    }
}

两个字符串互为旋转词问题

题目:
如果对于一个字符串A,将A的前面任意一部分挪到后边去形成的字符串称为A的旋转词。比如A=”12345”,A的旋转词有”12345”,”23451”,”34512”,”45123”和”51234”。对于两个字符串A和B,请判断A和B是否互为旋转词。

给定两个字符串A和B及他们的长度lena,lenb,请返回一个bool值,代表他们是否互为旋转词。

测试样例:
“cdab”,4,”abcd”,4
返回:true

解题思路
将字符串A与A进行拼接形成字符串AA,问题即可转化为在AA中寻找模式子串B的问题,可利用KMP算法求解。
代码实例:

import java.util.*;

public class Rotation {
    public boolean chkRotation(String A, int lena, String B, int lenb) {
        // 定义字符串AA=A+A,将问题转化为在AA中寻找模式子串B的问题,利用KMP算法求解即可
        String AA = A + A;
        //边界条件判定
        if(AA==null||B==null||2*lenareturn false;
        }

        return getIndexOfSubString(AA,B,2*lena,lenb)>=0?true:false;

    }


    //KMP算法实现

    public int getIndexOfSubString(String strA,String strB,int lenA,int lenB){

        char[] charA = strA.toCharArray();
        char[] charB = strB.toCharArray();

        int[] next = getNextArray(charB,lenB);
        int i = 0;
        int j = 0;

        while(iif(j==-1||charA[i]==charB[j]){
                i++;
                j++;
            }else{
                j = next[j];
            } 
        }


        return j==lenB?i-j:-1;


    }


    //next数组实现
    public int[] getNextArray(char[] charB,int lenb){

        int[] next = new int[lenb];
        next[0] = -1;
        int k = -1;
        int j = 0;

        while(j1){

            if(k==-1||charB[k]==charB[j]){
                k++;
                j++;

                if(charB[j]!=charB[k]){
                    next[j] = k;
                }else{
                    next[j] = next[k];
                }

            }else{
                k = next[k];
            }
        }

        return next;

    } 

}

句子的逆序调整问题

题目:
对于一个字符串,请设计一个算法,只在字符串的单词间做逆序调整,也就是说,字符串由一些由空格分隔的部分组成,你需要将这些部分逆序。

给定一个原字符串A和他的长度,请返回逆序后的字符串。

测试样例:
“dog loves pig”,13
返回:”pig loves dog”

解题思路:
此类型题目关键在于设计一个函数,将字符串做逆序调整,然后先将函数用于整个句子,再将函数用于句子中各个单词即可实现

代码:

import java.util.*;

public class Reverse {
    public String reverseSentence(String A, int n) {
        //边界条件判断
        if(A==null||A.length()==0){
            return null;
        }
        //对整个字符串做逆序调整,然后分割成单词数组
        String[] strArr = reverseWord(A,n).split(" ");
        StringBuffer sb = new StringBuffer();
        //单词数组中每个元素转换
        for(int i=0;i" ") ;
        }
        //转化为字符串并去除尾部空格
        return sb.toString().trim();
    }


    //字符串逆序函数
    public String reverseWord(String str,int len){

        int start = 0;
        int end = len-1;
        char[] charStr = str.toCharArray();

        char temp = charStr[start];
        while(start//字符数组转化为字符串
       return String.valueOf(charStr);

    }
}

字符串移位问题

题目:
对于一个字符串,请设计一个算法,将字符串的长度为len的前缀平移到字符串的最后。

给定一个字符串A和它的长度,同时给定len,请返回平移后的字符串。

测试样例:
“ABCDE”,5,3
返回:”DEABC”
解题思路:
此题思路与上题句子逆序调整问题相似,先设计一个逆序函数,然后将字符串的0-len-1部分,len-最后部分,整个字符串分别应用逆序函数即可实现。
代码:

import java.util.*;

public class Translation {
    public String stringTranslation(String A, int n, int len) {
        // 边界条件判定
        if(A==null||A.length()==0){
            return null;
        }
        //字符串转化为数组
        char[] cStr = A.toCharArray();
        reverse(cStr,0,len-1);
        reverse(cStr,len,n-1);
        reverse(cStr,0,n-1);
        return String.valueOf(cStr);
    }


    //逆序调整函数
    public void reverse(char[] cStr,int start,int end){

        char temp = cStr[start];
        while(start

拼接最小字典序

题目:
对于一个给定的字符串数组,请找到一种拼接顺序,使所有小字符串拼接成的大字符串是所有可能的拼接中字典序最小的。

给定一个字符串数组strs,同时给定它的大小,请返回拼接成的串。

测试样例:
[“abc”,”de”],2
“abcde”
解题思路:
此题目整体思路是将字符串数组进行排序,然后依此拼接即可。重点在于排序方式的修改,不能按照单个小字符串的字典顺序进行排序,如“b”,”ba”,按照这种排序方式拼接即为“bba”,显然最小字典顺序为“bab”,不符合要求。这里选择两两字符串拼接进行排序,即为“b”+”ba”与“ba”+”b”进行排序,显然排序结果会将“ba”放在“b”的前面,拼接后的字符串也满足最小字典顺序的要求。

代码:

import java.util.*;

public class Prior {
    public String findSmallest(String[] strs, int n) {
        //边界条件判定
        if(strs==null||strs.length==0){
            return null;
        }

        //构建新的排序方式
        Arrays.sort(strs,new Comparator(){

            @Override
            public int compare(String str1,String str2){
                return (str1+str2).compareTo(str2+str1);
            } 
        });

        //构建大字符串
        StringBuffer sb = new StringBuffer();
        for(int i=0;ireturn sb.toString();

    }
}

空格替换问题

题目:请编写一个方法,将字符串中的空格全部替换为“%20”。假定该字符串有足够的空间存放新增的字符,并且知道字符串的真实长度(小于等于1000),同时保证字符串由大小写的英文字母组成。

给定一个string iniString 为原始的串,以及串的长度 int len, 返回替换后的string。

测试样例:
“Mr John Smith”,13
返回:”Mr%20John%20Smith”
”Hello World”,12
返回:”Hello%20%20World”

解题思路:
遍历两次,第一次统计空格数量,第二次以此替换空格即可

代码:

import java.util.*;

public class Replacement {
    public String replaceSpace(String iniString, int length) {
        //边界条件检查
        if(iniString==null||length==0){
            return null;
        }

        //遍历一遍,统计空格数量
        char[] charStr = iniString.toCharArray();
        int spaceCount = 0;
        for(int i=0;iif(charStr[i]==' '){
                spaceCount++;
            }
        }


        //以此替换空格
        char[] newString = new char[length+spaceCount*2];
        int newLength = length+spaceCount*2-1;
        for(int i=length-1;i>=0;i--){
            if(charStr[i]==' '){
                newString[newLength--] = '0';
                newString[newLength--] = '2';
                newString[newLength--] = '%';
            }else{
                newString[newLength--] = charStr[i];
            }
        }

        return String.valueOf(newString);

    }
}

合法括号序列判断

题目:
对于一个字符串,请设计一个算法,判断其是否为一个合法的括号串。

给定一个字符串A和它的长度n,请返回一个bool值代表它是否为一个合法的括号串。

测试样例:
“(()())”,6
返回:true
测试样例:
“()a()()”,7
返回:false
测试样例:
“()(()()”,7
返回:false

解题思路:
设置一个int类型的变量number,遍历字符数组,遇到左括号加1,遇到右括号减1,最后number=0说明左右括号数量相等,否则不等。如果中间过程出现number<0,也说明括号序列不合法,右括号多余左括号

代码:

import java.util.*;

public class Parenthesis {
    public boolean chkParenthesis(String A, int n) {
        //边界条件判断
        if(A==null){
            return false;
        }

        //设置括号标志变量,遇到左括号加1,遇到右括号减1
        int number = 0;

        char[] charA = A.toCharArray();
        for(int i=0;i//小于0说明中间过程中左右括号不匹配,右括号多
            if(number<0){
                return false;
            }

            if(charA[i]!=')'&&charA[i]!='('){
                return false;
            }

            if(charA[i]=='('){
                number++;
            }else if(charA[i]==')'){
                number--;
            }
        }

        //循环结束等于0说明左右括号数量相等,否则不等
        if(number==0){
            return true;
        }else{
            return false;
        }


    }
}

字符判断问题

题目:
判断字符串b的所有字符是否都在字符串a中出现过,a、b都是可能包含汉字的字符串。b中重复出现的汉字,那么a中也要至少重复相同的次数。汉字使用gbk编码(简单的说,用两个字节表示一个汉字,高字节最高位为1的代表汉字,低字节最高位可以不为1)。
int is_include(char *a, char *b);
返回0表示没有都出现过,返回1表示都出现过。
请设计一个算法。

解题思路:
定义两个Map,存储两个字符串的字符种类以及出现的次数,然后循环比较即可

代码:

import java.io.*;
import java.util.*;
public class Main{

    public static void main(String[] args) throws IOException{

      //定义两个Map存储A,B字符串中各个字符种类以及出现的次数
        Map mapA = new HashMap();
        Map mapB = new HashMap();

        int s = 0;

        while((s=System.in.read())!='\n'){

            if(mapA.containsKey(s)){
                mapA.put(s,mapA.get(s)+1);
            }else{
                mapA.put(s,1);
            }

        }

        while((s=System.in.read())!='\n'){
            if(mapB.containsKey(s)){
                mapB.put(s,mapB.get(s)+1);
            }else{
                mapB.put(s,1);
            }

        }

      //遍历循环查找a中是否包含b中所有的字符串
          int flag = 1;
         for(int key:mapB.keySet()){

            if(mapA.get(key)==null|| mapA.get(key)get(key)){
               flag = 0;
               break;

            }
         }

      System.out.println(flag);


        }


    }

最长无重复子串问题

题目:
对于一个字符串,请设计一个高效算法,找到字符串的最长无重复字符的子串长度。

给定一个字符串A及它的长度n,请返回它的最长无重复字符子串长度。保证A中字符全部为小写英文字符,且长度小于等于500。

测试样例:
“aabcb”,5
返回:3

解题思路见代码注释
代码:

import java.util.*;

public class DistinctSubstring {
    public int longestSubstring(String A, int n) {
        //边界条件判断
        if(A==null||n==0){
            return -1;
        }

        //创建一个Hash表,存放每个字符最靠右的位置
        Map indexMap = new HashMap();
        //设定变量posA,posB,分别表示当前最长无重复子串的最左边字符位置,前一个最长无重复子串的最左边字符位置
        int posA = 0;
        int posB = 0;
        //设定pre变量,代表当前最长无重复子串的长度;res代表全局最长无重复子串长度
        int pre = 0;
        int res = 0;

        char[] charA = A.toCharArray();
        int key = 0;
        //依此计算以当前字符为结尾的最长无重复子串,然后取其中的最大值即可,只需要遍历一遍
        //当前字符最长无重复子串计算方式:
        //首先从hash表中取出当前字符上次出现的最靠右边的位置posA,需要判断Hash表是否存在该字符键,不存在的话pre++即可,存在另作计算如下
        //存在的话再计算当前字符前一个字符的最长无重复子串的起始位置posB,即i-pre,然后比较posA+1与posB的大小
        //如果posA+1>posB,那么最长无重复子串部分应该是posA+1~当前字符i的部分,即pre=i-posA,否则的话最长无重复子串部分应该是上一个字符的最长无重复子串加上当前字符,即长度为pre++
        //每次记得更新Hash表,并记录全局最大的pre即可
        for(int i=0;iif(indexMap.containsKey(key)){
                posA = indexMap.get(key)+1;
                posB = i - pre;

                if(posA>posB){
                    pre = i - posA+1;
                }else{
                    pre++;
                }

                indexMap.put(key,i);

            }else{
               indexMap.put(key,i); 
                pre++;

            }

            if(pre>res){
                res = pre;
            }
        }

        return res;
    }
}

你可能感兴趣的:(面试)