字符串相关练习题目

一、字符串问题总结:

(1)字符串可以看成字符数组,那么

(2)回文字符串

(3)大数相加减乘除

(4)数组有关的调整、排序(快排划分技巧):

(5)字符计数(哈希表 固定长度数组)滑动窗口、寻找无重复字符子串、计算变为词

C++字符是0~255,java 0~65535

(6)动态规划:最长公共子串、最长公共子序列、最长回文子串、最长回文子序列

(7)搜索类型(str每次只能变化1个位置 如何str1编程str2):宽度、广度深度搜索

(8)高级算法与数据结构解决(了解):ManacherKMP、前缀树、后缀树和后缀数组

 

二、题目:

(1)t2是否为t1的子结构

1)普通解法:t1中每个节点为头节点的子树 是否与t2一致(时间复杂度On1*n2))

最优解:序列化+KMP先序遍历两个树获得字符串s1 s2kmp判断s2是否为s1,时间复杂度O(m+n)

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

给定两棵二叉树的头结点AB,请返回一个bool值,代表A中是否存在一棵同构于B的子树。


/*
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) {
        return serialize(A).indexOf(serialize(B)) != -1 ? true : false;
    }
    public String serialize(TreeNode root) {
        if (root == null) {//注意序列化 遍历结束一个节点要加特殊符号,不然12 无法分辨是1,2还是12
            return "# ";
        } 
        return root.val + "!" + serialize(root.left) + serialize(root.right); 
    }
}


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

(2)Str1str2是否为变形词(字符种类 每个字符出现次数一样)

Hash表对字频统计,可以使用固定长度的数组,也可以使用map


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

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

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

public class Transform {
    public boolean chkTransform(String s1, int lena, String s2, int lenb) {
        // write code here
        if(lena==0&&lenb==0) return true;
        if(lena==0||lenb==0||lena!=lenb) return false;
        Map<Character,Integer> mapA=new HashMap();
        Map<Character,Integer> mapB=new HashMap();
        for(int i=0;i<lena;i++){//词频记录在HashMap中
            char c1=s1.charAt(i);
            char c2=s2.charAt(i);
            if(!mapA.containsKey(c1)){
                mapA.put(c1,1);
            }else{
                mapA.put(c1,mapA.get(c1)+1);
            }
            
            if(!mapB.containsKey(c2)){
                mapB.put(c2,1);
            }else{
                mapB.put(c2,mapB.get(c2)+1);
            }
        }
        if(mapA.size()!=mapB.size()) return false;//map的长度不同--》不是变形词
        for(char c:mapA.keySet()){//比较两个字符串的词频
            if(mapA.get(c)!=mapB.get(c)) return false;
        }
        return true;
    }
}


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

(3)旋转词

长度相等-->s=s1+s1-->kmp寻找s中是否包含s2,时间复杂度O(n)  

public class Rotation {
    public boolean chkRotation(String s1, int lena, String s2, int lenb) {
        // write code here
        if(lena!=lenb) return false;
        String s=s1+s1;
		//return s.contains(s2);
        return s.indexOf(s2)!=-1?true:false;
    }
}


KMP算法

public class Problem_04_IsRotation {

	public static boolean isRotation(String a, String b) {
		if (a == null || b == null || a.length() != b.length()) {
			return false;
		}
		String b2 = b + b;
		return getIndexOf(b2, a) != -1;
	}

	// KMP Algorithm
	public static int getIndexOf(String s, String m) {
		if (s.length() < m.length()) {
			return -1;
		}
		char[] ss = s.toCharArray();
		char[] ms = m.toCharArray();
		int si = 0;
		int mi = 0;
		int[] next = getNextArray(ms);
		while (si < ss.length && mi < ms.length) {
			if (ss[si] == ms[mi]) {
				si++;
				mi++;
			} else if (next[mi] == -1) {
				si++;
			} else {
				mi = next[mi];
			}
		}
		return mi == ms.length ? si - mi : -1;
	}

	public static int[] getNextArray(char[] ms) {
		if (ms.length == 1) {
			return new int[] { -1 };
		}
		int[] next = new int[ms.length];
		next[0] = -1;
		next[1] = 0;
		int pos = 2;
		int cn = 0;
		while (pos < next.length) {
			if (ms[pos - 1] == ms[cn]) {
				next[pos++] = ++cn;
			} else if (cn > 0) {
				cn = next[cn];
			} else {
				next[pos++] = 0;
			}
		}
		return next;
	}

	public static void main(String[] args) {
		String str1 = "yunzuocheng";
		String str2 = "zuochengyun";
		System.out.println(isRotation(str1, str2));

	}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


(1)单词逆序

头尾交换--> 对每个单词再逆序  

Pig loves dog-->god sevol gip-->dog loves dog

public class Reverse {
    public String reverseSentence(String s, int n) {
        // write code here
        if(s.length()<=0||s==null) return null;
        char[] cs=s.toCharArray();
        reverse(cs,0,n-1);
        int start=0;
        int end=0;
        int i=0;
        while(i<n){
            while(i<n&&cs[i]==' ')//单词开始地方
                i++;
            start=i;
            while(i<n&&cs[i]!=' ')//单词结束位置
                i++;
            end=i;
            reverse(cs,start,end-1);
        }
        return String.valueOf(cs);
    }
     
    public void reverse(char[] cs,int left,int right){
        while(left<=right){
            char c=cs[left];
            cs[left]=cs[right];
            cs[right]=c;
            left++;
            right--;
        }
    }
}


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


(6)移位Str,,i,str[0...i]移到右侧,str[i+1...n-1]移到左侧 “abcde2->deabc

要求时间复杂度O(n)空间O(1)

因为要求原地调整,所以只能借助字符串交换函数:

Str[0..i]逆序-->cbadestr[i+1..n-1]逆序-->cbaed,整体逆序-->deabc


public class Translation {
    public String stringTranslation(String s, int n, int len) {
        // write code here
        char[] cs=s.toCharArray();
        reverse(cs,0,len-1);
        reverse(cs,len,n-1);
        reverse(cs,0,n-1);
        return String.valueOf(cs);
    }
    public void reverse(char[] cs,int left,int right){
        while(left<=right){
            char c=cs[left];
            cs[left]=cs[right];
            cs[right]=c;
            left++;
            right--;
        }
    }
}

--------------------------------------------------------------------------------------------------------------------------


(6)Strs[]字符串拼接,拼接顺序是最小的,返回最大字符串

其实这是一种排序,要实现Comparator接口并实现里面的方法,在调用Arrays.sort方法。排序依据Str1+str2<str2+str1那么str1排在str2前面 


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

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

测试样例:
["abc","de"],2
"abcde"

class MyComparator implements Comparator<String>{//自定义比较器
    public int compare(String s1,String s2){
        String str1=s1+s2;
        String str2=s2+s1;
        return str1.compareTo(str2);
    }
}
public class Prior {
    public String findSmallest(String[] strs, int n) {
        // write code here
        if(strs==null||strs.length==0) return null;
        Arrays.sort(strs,new MyComparator());
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<n;i++){
            sb.append(strs[i]);
        }
        return sb.toString();
    }
}


-----------------------------------------------------------------------------------------------------------------

(7)空格替换:

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

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

思路:如 a  b  c 首先统计空格数量为2,那么替换后的字符串长度由5-->5+2*2=9,所以 从右向左遍历str ,c放到 s[8]处,遇到空格 s[7]放20 s[6]放%,然后b放到s[5]直到s[0]=a


public class Replacement {
    public String replaceSpace(String s, int len) {

        //return s.replaceAll(" ","%20"); //当然这题的意思不是直接调用replaceAll方法
        int count=0;
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)==' ') count++;
        }
        char[] cs=new char[len+count*2];
        
        int j=0;
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)!=' ') cs[j++]=s.charAt(i);
            else{
                cs[j++]='%';
                cs[j++]='2';
                cs[j++]='0';
            }
        }
        return String.valueOf(cs);
    }
}



------------------------------------------------------------------------------------------------------------------


(8)括号匹配:

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

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


思路:时间复杂度O(n)空间复杂度O(1),如果采用栈,空间复杂度是O(n)

int num=0;//当前时刻,左括号-右括号的个数,如果<0,说明)出现多余不匹配,如果最后没等于0也不匹配


测试样例:
"(()())",6
返回:true

public class Parenthesis {
    public boolean chkParenthesis(String s, int n) {
 		//时间复杂度O(n)空间复杂度O(1),如果采用栈的话,那么空间复杂度是O(n)
        int num=0;//当前时刻,左括号-右括号的个数,如果<0,说明)出现多余不匹配,如果最后没等于0也不匹配
        for(int i=0;i<n;i++){
            if(s.charAt(i)=='(') num++;
            if(s.charAt(i)==')')num--;
            if(num<0) return false;
        }
        if(num==0)return true;
        return false;
    }
}


------------------------------------------------------------------------------------------------------------------


        (9)

最长无重复子字符串(动态规划):时间O(n),空间O(n)

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

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

测试样例:aabcb,返回3

 

思路:从左到右依次求出s[0..n-1]每个位置向左的最长无重复子字符串。假设现在求s[i]=c位置处的向左的最长无重复子串:

Map---每种字符之前出现的位置

Int pre---s[i-1]结尾情况下,最长无重复子串的长度

首先,int A=map.get(c)表名c上次出现的位置,即cabdf...c往左最长的子串要在第一个c之后.

然后,如果pre在位置A的右边,那么以s[i]结尾的最长无重复子串,要在pre之后,不然s[i-1]就会有重复。

如果pre在位置A的左边,那么以s[i]结尾的最长无重复子串,就是位置A

MaxmaxIndex分别记录最大长度和结尾的字符位置。


public class DistinctSubstring {
    public int longestSubstring(String s, int n) {
        if(s==null||n==0) return 0;
        char[] cs=s.toCharArray();
        int[] map=new int[256];//记录每个字符上次出现的位置
        for(int i=0;i<256;i++) map[i]=-1;
        int pre=-1;//当前节点的前一节点做结尾时,的最长无重复子串长度
        int cur=0;
        int len=0;
        for(int i=0;i<n;i++){
            pre=Math.max(pre,map[cs[i]]);//看当前节点和前一节点拿两个的无重复子串长
            cur=i-pre;
            len=Math.max(len,cur);
            map[cs[i]]=i;
        }
        return len;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值