392. 判断子序列

https://leetcode.cn/problems/is-subsequence/?envType=study-plan-v2&envId=top-interview-150
因为是子序列我们只要关心后一个字符在前一个字符后面出现过就行,至于在哪出现出现几次我们不关心,所以我们可以用HashMap<Character, ArrayList<Integer>> map;这个数据结构来存每一个字符出现过的位置然后遍历s,找到s中每一个字符在t中出现的位置(并且要在前一个字符的后面第一个,因为list是有序的我们可以通过二分来找),如果没找到则返回false,如果找到了则更新preIndex,继续遍历s,直到遍历完s,返回true.
题目后面那个拓展应该是让我们保留状态,我能想到比较好的方法就是构造字典树了,比如构造长度为i的字符串的字典树(1<i<=n),这样只用拿长度为i的字符串到对于长度的字典树匹配就行字典树匹配的时间是log n,总的时间就是nlog n,但是构造这样一个字典树组很麻烦,暂时只能想到这了。

class Solution {

    public static void main(String[] args) {
        String s = "abc";
        String t = "ahbgdc";
        System.out.println(new Solution().isSubsequence(s, t));
    }

    public boolean isSubsequence(String s, String t) {
        int len_s = s.length(), len_t = t.length();
        HashMap<Character, ArrayList<Integer>> map = new HashMap<>();//记录字符出现的位置
        for(int i = 0; i < len_t; i++) {
            if(!map.containsKey(t.charAt(i))) {
                ArrayList<Integer> list = new ArrayList<>();
                map.put(t.charAt(i), list);
            }
            map.get(t.charAt(i)).add(i);
        }
        int preIndex = -1, currIndex = 0;//preIndex记录上一个字符出现的位置,currIndex记录当前字符出现的位置
        int index = 0;//当前在找的字符
        while(index < len_s) {
            if(!map.containsKey(s.charAt(index))) {//如果s中出现了t中没有的字符,则直接返回false
                return false;
            }
            currIndex = getCurrIndex(preIndex, map.get(s.charAt(index)));//获取当前字符在t中出现的下一个位置
            if(currIndex == -1) return false;//没找到
            else {
                preIndex = currIndex;//更新preIndex
            }
            index++;
        }
        return true;
    }

    //找当前字符在前一个字符下标后第一次出现的下标
    public int getCurrIndex(int preIndex, ArrayList<Integer> list) {//通过二分找到一个出现在上一个字符后的待找字符
        int left = 0, right = list.size() - 1;
        while(left < right) {
            int mid = (left + right) >> 1;
            if(list.get(mid) > preIndex) right = mid;
            else left = mid + 1;
        }
        return list.get(left) > preIndex ? list.get(left) : -1;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值