字符串习题总结1

目录

一.最长公共子序列(一)(动态规划)

 1.题目说明

2.图解说明

3.代码实现

二.最长公共子序列(二)

1.题目

2.思路图解

3.代码

三.最长公共子串

1.题目说明

2.思路图解

3.代码

四.判断一个字符串是否为另一个字符串的子序列 

1.题目描述

2.图解

3.代码

五.求最长无公共子串问题

1.题目描述

2.思路分析

3.代码实现

(1)实现方式一

(2)方式二实现

六.求字符串的全部子序列

1.题目描述

2.图解

3.代码实现

七.压缩字符串

1.题目

2.图解

3.代码

八.长度为k的重复字符的子串

1.题目

2.图解

3.代码

九.字符串解码

1.题目

2.图解

3.代码


一.最长公共子序列(一)(动态规划)

 1.题目说明

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

2.图解说明

3.代码实现

    //求最长公共子序列
    public int longestCommonSubsequence(String text1, String text2) {
        int row = text1.length();
        int col = text2.length();
        //这里使用行列多一个是因为防止第一个元素dp[i-1][j-1]越界
        int[][] dp = new int[row+1][col+1];
        for(int i=1; i<=row; i++) {
            for(int j=1; j<=col; j++) {
                //表示当前行列元素相等
                if(text1.charAt(i-1)==text2.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1]+1;
                }else {
                    //当前行列元素不等
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        //数组最后元素位置就是最大公共子序列数
        return dp[row][col];
    }

 

二.最长公共子序列(二)

1.题目

给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列。(相当于是找最长子序列的结果)

示例:

输入:"1A2C3D4B56","B1D23A456A"

返回值:"123456"

 

2.思路图解

首先还是根据动态规划来找最长子序列,在寻找最长子序列的时候,使用二维数组b需要保存走过的路径位置,这里b中1表示来自于左上方,b中为2表示来自于左边,b中3表示来自于上方,之后通过递归来进行还原。

3.代码

 //保存源字符串,之后通过该串进行还原
    private String x = "";
    //获取最长公共子序列
    String ans(int i, int j, int[][] b){ 
        String res = "";
        //递归终止条件
        if(i == 0 || j == 0)
            return res;
        //根据方向,往前递归,然后添加本级字符
        //说明来自左上方
        if(b[i][j] == 1){
            res += ans(i - 1, j - 1, b);//递归右边1
            res += x.charAt(i - 1);
        }
        else if(b[i][j] == 2)//左边,递归左边
            res += ans(i - 1, j, b);
        else if(b[i][j] == 3)//上边,递归上面
            res += ans(i,j - 1, b);
        return res;
    }
    public String LCS (String s1, String s2) {
        //特殊情况
        if(s1.length() == 0 || s2.length() == 0)
            return "-1";
        int len1 = s1.length();
        int len2 = s2.length();
        x = s1;
        y = s2;
        //dp[i][j]表示第一个字符串到第i位,第二个字符串到第j位为止的最长公共子序列长度
        int[][] dp = new int[len1 + 1][len2 + 1];
        //动态规划数组相加的方向
        int[][] b = new int[len1 + 1][len2 + 1];
        //遍历两个字符串每个位置求的最长长度
        for(int i = 1; i <= len1; i++){
            for(int j = 1; j <= len2; j++){
                //遇到两个字符相等
                if(s1.charAt(i - 1) == s2.charAt(j - 1)){
                    //考虑由二者都向前一位
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    //来自于左上方
                    b[i][j] = 1;
                }
                //遇到的两个字符不同
                else{
                    //保存来自上边
                    if(dp[i - 1][j] > dp[i][j - 1]){
                        dp[i][j] = dp[i - 1][j];
                        b[i][j] = 2;
                    }
                    //保存来自左边
                    else{
                        dp[i][j] = dp[i][j - 1];
                        b[i][j] = 3;
                    }
                }
            }
        }
        //获取答案字符串
        String res = ans(len1, len2, b);
        //检查答案是否位空
        if(res.isEmpty()) 
            return "-1";
        else
            return res;
    }

三.最长公共子串

1.题目说明

最长公共子串指的是两个字符串连续的子串。

例如abcde,与bcd这两个字符串的最长公共子串就是bcd。

2.思路图解

3.代码

//最长公共子串
    public String LCS (String str1, String str2) {
        int r = str1.length();
        int c = str2.length();
        int[][] dp = new int[r+1][c+1];
        int maxLen = 0;//保存最大长度
        int lastIndex = 0;//保存最后子序列结束的索引位置
        for(int i=1; i<=r; i++) {
            for(int j=1; j<=c; j++) {
                //从字符串首位置开始查找是否相等的元素
                if(str1.charAt(i-1) == str2.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1]+1;
                    if(dp[i][j]>maxLen) {
                        //修改最长连续子串的长度
                        maxLen = dp[i][j];
                        //修改结束位置
                        lastIndex = i-1;
                    }
                }else {
                    //当前不存在在公共子串
                    dp[i][j] = 0;
                }
            }
        }
        //截取最长公共子串
        return str1.substring(lastIndex-maxLen+1, lastIndex+1);
    }

四.判断一个字符串是否为另一个字符串的子序列 

1.题目描述

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

2.图解

3.代码

 //判断s是否为t的子串
    public boolean isSubsequence(String s, String t) {
        //双指针法
        int sL = s.length();
        int tL = t.length();
        int i = 0;//表示s的下标
        int j = 0;//表示t的下标
        while(i<sL && j<tL) {
            if(s.charAt(i) == t.charAt(j)) {
             i++;   
            }
            j++;
        }
        //如果i指针走到最后,就说明是子串,时间复杂度为O(max(s.length(), t.length()))
        return i==sL;
    }

五.求最长无公共子串问题

1.题目描述

给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子字符串是 "abc",所以其长度为 3。

2.思路分析

(1)首先需要保存无重复子字符串开始(begin)和结束(end)的位置。

(2)每次向后查找时需要与前面没有重复的子串进行比较,如果没有重复,就继续;遇到重复的就结束当前循环,从begin的下一个位置再开始进行查找。在进行查找的时候需要使用set集合来判断是否重复。

3.代码实现

(1)实现方式一

图解:

代码: 

public int lengthOfLongestSubstring(String s) {
        if(s.length()==0) {
            return 0;
        }
        //保存最大长度
        int maxLen = 0;
        //从字符串首位置开始依次向后查找
        for(int i=0; i<s.length(); i++) {
            //set集合保存没有重复的子字符串
            HashSet<Character> set = new HashSet<>();
            //相当于从begin开始向后查找
            for(int j=i;j<s.length(); j++) {
                //没有重复就添加到集合中
                if(!set.contains(s.charAt(j))) {
                    set.add(s.charAt(j));
                    //防止字符串本身就是一个无重复子串,所以每添加一个就保存最长的子串
                    maxLen = Math.max(maxLen, j-i+1);
                    
                }else {
                    //说明遇到重复的子串,就保存最长子串的长度,然后退出当前循环
                    maxLen = Math.max(maxLen, j-i);
                    break;
                }
            }
        }
        return maxLen;
    }

(2)方式二实现

举例如:求“abccd的不重复的最长子串”

图解:

代码:

public int lengthOfLongestSubstring(String s) {
        Set<Character> set = new HashSet<>();
        //保存最长无重复子字符串
        int maxLen = 0;
        //保存最右边当前元素
        int j=0;
        //从左到右依次寻找
        for(int i=0; i<s.length(); i++) {
            //每次从头删除set集合中的元素,因为要保持set中没有连续子字符串没有重复元素
            if(i!=0) {
                set.remove(s.charAt(i-1));
            }
            while(j<s.length() && !set.contains(s.charAt(j))) {
                //当没有重复子串j就一直后移,如果遇到重复的就结束
                set.add(s.charAt(j));
                j++;
            }
            //找到了从i-j的子串,然后于最大值进行比较
            maxLen = Math.max(maxLen, j-i);
        }
        return maxLen;
    }

六.求字符串的全部子序列

1.题目描述

给定一个字符串s,长度为n,求s的所有子序列

1.子序列: 指一个字符串删掉部分字符(也可以不删)形成的字符串,可以是不连续的,比如"abcde"的子序列可以有"ace","ad"等等

2.将所有的子序列的结果返回为一个字符串数组

3.字符串里面可能有重复字符,但是返回的子序列不能有重复的子序列,比如"aab"的子序列只有"","a","aa","aab","ab","b",不能存在2个相同的"ab"

4.返回字符串数组里面的顺序可以不唯一

例子:

输入:"aab"

返回值:["","a","aa","aab","ab","b"],返回的字符串数组里面不能存在"ab","ab"这样2个相同的子序列。

2.图解

3.代码实现

//将获取到的结果存储到set中,也是去重
Set<String> set = new HashSet<>();
    public String[] generatePermutation (String s) {
        // write code here
        dfs(new StringBuilder(), 0, s);
        //将set转化为字符串数组
        return set.toArray(new String[set.size()]);
        
    }
    public void dfs(StringBuilder sb, int index, String str) {
    //sb每次变化后,都会添加到set中,这里set会去重
        set.add(sb.toString());
        for(int i=index; i<str.length(); i++) {
            //添加当前位置字符
            sb.append(str.charAt(i));
            //递归向一个字符进行dfs
            dfs(sb, i+1, str);
            //结束后面递归就删除最后一个元素
            sb.deleteCharAt(sb.length()-1);
        }
    }

七.压缩字符串

1.题目

利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2bc5a3。
1.如果只有一个字符,1不用写
2.字符串中只包含大小写英文字母(a至z)

2.图解

3.代码

public String compressString (String param) {
        // write code here
       int left = 0;
        int right = 0;
        int n = param.length();
        StringBuilder sb = new StringBuilder();
        while(left<n) {
            char tmp = param.charAt(left);
            //right从left的后一个开始
            right = right+1;
            //查找连续重复的最终位置
            while(right<n) {
                if(tmp==param.charAt(right)){
                    right++;
                }else {
                    break;
                }
            }
            //根据后面元素个数来判断是否压缩
            sb.append(tmp);
            if(right-left>1) {
                sb.append(right-left);
            }
            //找完后,更新左边界
            left = right;
        }
        return sb.toString();
    }

八.长度为k的重复字符的子串

1.题目

给你一个由小写字母组成的长度为n的字符串 S ,找出所有长度为 k 且包含重复字符的子串,请你返回全部满足要求的子串的数目。

例子:

输入:"createfunonyoka",4

返回值:4

分别为:eate, unon, nony,onyo.

2.图解

3.代码

 public int numKLenSubstrRepeats (String s, int k) {
        // write code here
        int res = 0;
        //存储滑动窗口的元素
        int[] arr = new int[26];
        //构造初始的滑动窗口
        for(int i=0; i<k; i++) {
            arr[s.charAt(i)-'a']++;
        }
        if(isRepeat(arr)) res++;
        for(int i=k; i<s.length(); i++) {
            //滑动窗口思想,滑动窗口后移
            arr[s.charAt(i)-'a']++;
            arr[s.charAt(i-k)-'a']--;
            //窗口每移动一次,就判断是否有重复的字符
            if(isRepeat(arr)) res++;
        }
        return res;
    }
    //判断是否有重复字符的子串
    public boolean isRepeat(int[] arr){
        for(int i=0; i<arr.length; i++) {
            if(arr[i]>1) {
                return true;
            }
        }
        return false;
    }

九.字符串解码

1.题目

给一个加密过的字符串解码,返回解码后的字符串。

加密方法是:k[c] ,表示中括号中的 c 字符串重复 k 次,例如 3[a] 解码结果是 aaa ,保证输入字符串符合规则。不会出现类似 3a , 3[3] 这样的输入。

例子:

输入:"3[3[b]]"

返回值:"bbbbbbbbb"

2.图解

3.代码

  //设置成员变量为了之后对字符串好操作
    int i = 0;
    public String decodeString (String s) {
        // write code here
        LinkedList<String> stack = new LinkedList<>();
        while(i<s.length()) {
            char ch = s.charAt(i);
            //处理数字
            if(Character.isDigit(ch)) {
                //将数字放入栈中,在放之前防止是一个连续的数字,所以需要将
                //所有数字都访问完,这里使用一个函数来处理连续数字
                String nums = getNums(s);
                //将拼接好的数字添加到栈中
                stack.addLast(nums);
            }else if(Character.isLetter(ch) || ch=='['){//处理字符或者左括号
                stack.addLast(String.valueOf(s.charAt(i)));
                i++;
            }else {//遇到右括号,就处理栈中的数据,直到遇到左括号为止
                LinkedList<String> sub = new LinkedList<>();
                while(!"[".equals(stack.peekLast())) {
                    //处理栈顶字符串
                    sub.addLast(stack.removeLast());
                }
                //对字符串链表反转,恢复原来的顺序
                Collections.reverse(sub);
                //将左括号出栈
                stack.removeLast();
                //栈顶现在就是需要拼接的次数(数字)
                int num = Integer.parseInt(stack.removeLast());
                //在拼接之前,首先将sub的字符串链表拼接成一个完整的字符串
                String str = getString(sub);
                //将需要还原的倍数进行还原
                StringBuilder sb = new StringBuilder();
                while(num-->0) {
                    sb.append(str);
                }
                //将拼接好的字符串再重新入栈
                stack.addLast(sb.toString());
                i++;//指针后移
            }
        }
        //将栈中单个字符串进行拼接
        return getString(stack);
    }
    public String getNums(String s) {
        StringBuilder sb = new StringBuilder();
        //说明是数字,就一直拼接
        while(Character.isDigit(s.charAt(i))) {
            sb.append(s.charAt(i));
            i++;
        }
        return sb.toString();
    }
    public String getString(LinkedList<String> sub) {
        StringBuilder sb = new StringBuilder();
        for(String str:sub) {
            sb.append(str);
        }
        return sb.toString();
    }

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值