LeetCode 392. Is Subsequence

问题描述

这里写图片描述

问题分析

  • 验证串s 是否是字符串t的子序列,有以下几种做法:
  • 方法1: 贪心
    用两个指针从前向后,若s[sIndex] == t[tIndex],说明在t中已经找到一个,则两指针都后移,若s[sIndex] != t[tIndex],则将tIndex后移,看t的下一个元素能否和s[sIndex]相匹配。

  • 方法2:动态规划
    dp[i][j] 来表示s[i ~ n] 是否是 t[j ~ n]的子序列,具体递推关系见实现

  • 方法三:二分查找 + 贪心(有点离线算法的意思)
    该方法主要针对于 Follow up 的问题,如果s串有多个怎么办,可以先对t串进行预处理,相当于一个离线算法
    设置一个list[]数组,然后将根据字符,将相同字符串成一个list,list中存的是该字符在t串中的下标。这样list中一定是升序的。
    然后遍历s串,假设前一个字符在t串中的索引为 preIndex,若当前字符ch未在数组中出现过,则直接返回false,若出现过,再对相应list进行二分查找,查找刚好大于等于preIndex + 1的元素是否存在,若存在,则更新preIndex,继续检验下一字符。若不存在,直接返回false.

经验教训

代码实现

  • 贪心
    public boolean isSubsequence(String s, String t) {
         if (s == null || t == null) {
             return false;
         }
        int sIndex = 0;
        int tIndex = 0;
        int sLen = s.length();
        int tLen = t.length();
        //贪心
        while (sIndex < sLen && tIndex < tLen) {
            if (s.charAt(sIndex) == t.charAt(tIndex)) {
                ++sIndex;
            }
            ++tIndex;
        }
        return sIndex == sLen;
    }
  • 动态规划
    public boolean isSubsequence(String s, String t) {
         if (s == null || t == null) {
             return false;
         }
        int sLen = s.length();
        int tLen = t.length();
        //dp[i][j]: 表示s[i ~ n] 是否是 t[j ~ n]的子序列
        boolean[][] dp = new boolean[sLen + 1][tLen + 1];
        for (int j = 0; j <= tLen; ++j) {
            dp[sLen][j] = true;
        }
        for (int i = sLen - 1; i >= 0; --i) {
            for (int j = tLen - 1; j >= 0; --j) {
                if (s.charAt(i) == t.charAt(j)) {
                    dp[i][j] = dp[i + 1][j + 1];
                }else {
                    dp[i][j] = dp[i][j + 1];
                }
            }
        }
        return dp[0][0];
    }
  • 二分查找 + 贪心
     public boolean isSubsequence(String s, String t) {
        if (s == null || t == null) {
            return false;
        }
         List<Integer>[] list = new List[256];
         //根据t串填list数组
         int tLen = t.length();
         for (int i = 0; i < tLen; ++i) {
             char ch = t.charAt(i);
             if (list[ch] == null) {
                 list[ch] = new ArrayList<Integer>();
             }
             //对于同一元素,存储索引
             list[ch].add(i);
         }
         //preIndex用来存储s某一字符在t中的索引
         int preIndex = -1;
         int sLen = s.length();
         //遍历s串
         for (int i = 0; i < sLen; ++i) {
            char ch = s.charAt(i);
             if (list[ch] == null) {
                 return false;
             }
             //利用二分查找,返回list[ch]中大于等于 preIndex + 1 的 元素
             int index = binarySearch(list[ch], preIndex + 1);
             if (index == -1) {
                 return false;
             }else {
                 //更新索引
                 preIndex = index;
             }
         }
         return true;
     }

    //返回list中刚刚大于等于target的元素,“刚刚”的概念也可点贪心的意思
    public int binarySearch(List<Integer> list, int target) {
        int begin = 0;
        int end = list.size() - 1;
        while (begin <= end) {
            int mid = begin + (end - begin) / 2;
            if (list.get(mid) < target) {
                begin = mid + 1;
            }else {
                end = mid - 1;
            }
        }
        return begin == list.size() ? -1 : list.get(begin);
    }

猜你喜欢

转载自blog.csdn.net/zjxxyz123/article/details/80286728