JAVA实现判断字符串子序列(子序列不需要黏在一起匹配,可以删减字符顺序匹配)

写在前面的话:题目稍有变化,注意审题!

题目:

给定字符串target和source,判断target是否为source的子序列。你可以认为target和source 中仅包含英文小写字母,字符串source可能会很长,长度~=500,000,而target是个短字符串,长度<=100。字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串,例如,'abc’是’aebycd’的一个子序列,而’ayb’不是。请找出最后一个序列的起始位置。

示例1

输入:
abc
eadbc
输出:
1

示例2

输入:
abc
abcaybec
输出:
3
说明:abcaybec中第0位的abc也匹配,但却不是最后匹配的序列。abcaybec中第3位的aybec去掉字符y、e后也为abc,也与目标字符串相符,故输出最后一个序列aybec的第一个字符的索引位置3。

解题

package com.winyar.algorithm.od;

import java.util.Scanner;

/**
 * @Describe 判断字符串子序列
 * @Author Winyar
 * @Date 2022/6/18
 */
public class SubSequenceLastIndex {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()) {
            String target = sc.nextLine();
            String source = sc.nextLine();
            int targetLen = target.length();
            int sourceLen = source.length();
            int i = targetLen - 1;
            int j = sourceLen - 1;
            // 标识是否有匹配的子序列
            boolean flag = false;
            // 逆序遍历
            while (i >= 0 && j >= 0) {
                if (target.charAt(i) == source.charAt(j)) {
                    if (i == 0) {
                        // 指针走到target第0位,说明能够匹配完目标字符串
                        flag = true;
                        System.out.println(j);
                    }
                    i--;
                    j--;
                } else {
                    // 没有找到相等的字符,继续向左遍历source字符串
                    j--;
                }
            }
            if (!flag) {
                System.out.println(-1);
            }
        }
        sc.close();
    }
}

类似题目

参考牛客网题目及解题思路:【查找两个字符串a,b中的最长公共子串】

描述
查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!

数据范围:字符串长度1\le length \le300 \1≤length≤300

输入描述:
输入两个字符串

输出描述:
返回重复出现的字符
示例1
输入:
abcdefghijklmnop
abcsafjklmnopqrstuvw
复制
输出:
jklmnop

解题

package com.winyar.niukewang;

import java.util.Scanner;

/**
 * @Describe 查找两个字符串a,b中的最长公共子串
 * @Author Winyar
 * @Date 2022/6/18
 */
public class MaxCommonSubStr {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String s1 = sc.nextLine();
            String s2 = sc.nextLine();
            System.out.println(longString(s1, s2));
        }
    }

    // 动态规划
    public static String longString(String str1, String str2) {
        String temp = "";
        // 保证str1是较短字符串
        if (str1.length() > str2.length()) {
            temp = str1;
            str1 = str2;
            str2 = temp;
        }
        int m = str1.length() + 1;
        int n = str2.length() + 1;
        // 表示在较短字符串str1以第i个字符结尾,str2中以第j个字符结尾时的公共子串长度。
        int[][] dp = new int[m][n];
        // 公共字串最大长度
        int max = 0;
        // 记录最大值的str1的结尾下标
        int index = 0;
        // 从左向右递推,i为短字符串str1的结尾索引,j为str2的结尾索引
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    // 相等则计数
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    // 不断更新变量
                    if (dp[i][j] > max) {
                        max = dp[i][j];
                        index = i;
                    }
                }
            }
        }
        // 截取最大公共子串
        return str1.substring(index - max, index);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值