1. 程式人生 > >LeetCode:438. Find All Anagrams in a String(找出相同的子串的下標)

LeetCode:438. Find All Anagrams in a String(找出相同的子串的下標)

Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.

Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.

The order of output does not matter.

Example 1:

Input:
s: "cbaebabacd" p: "abc"

Output:
[0, 6]

Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".

 

Example 2:

Input:
s: "abab" p: "ab"

Output:
[0, 1, 2]

Explanation:
The substring with start index = 0 is "ab", which is an anagram of "ab". The substring with start index = 1 is "ba", which is an anagram of "ab". The substring with start index = 2 is "ab", which is an anagram of "ab".

方法1:(這種方法比較容易想到,但是效率應該是不高)

package leetcode;

import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author zhangyu
 * @version V1.0
 * @ClassName: FindAllAnagrams
 * @Description: TOTO
 * @date 2018/12/5 17:22
 **/


public class FindAllAnagrams {
    @Test
    public void fun() {
        String s = "baa";
        String p = "aa";
        List<Integer> list= findAllAnagrams(s, p);
        System.out.println(list);
    }

    private List<Integer> findAllAnagrams(String s, String p) {
        //int [] indexs=new int[s.length()];
        List<Integer> list = new ArrayList<>();
        int i = 0;
        int j = p.length();
        while (j <= s.length()) {
            String subString = s.substring(i, j);
            if (equalsIgnoreOrderString1(subString, p)) {
                list.add(i);
            }
            i++;
            j++;
        }
        //return Arrays.copyOfRange(indexs,0,count);
        return list;
    }

    public boolean equalsIgnoreOrderString1(String s, String p) {
        if (s.length() == 0 || p.length() == 0) {
            return false;
        }
        if (s.length() != p.length()) {
            return false;
        }
        char[] chsp = p.toCharArray();
        for (char ch : chsp) {
            if (s.contains(String.valueOf(ch))) {
                s=s.replaceFirst(String.valueOf(ch), "@");
            } else {
                return false;
            }
        }
        return true;
    }
}

時間複雜度:O(n^3)

空間複雜度:O(n)


方法2:(一種比較高效的方法,利用陣列數字的方式)

package leetcode;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangyu
 * @version V1.0
 * @ClassName: FindAllAnagrams
 * @Description: TOTO
 * @date 2018/12/5 17:22
 **/


public class FindAllAnagrams2 {
    @Test
    public void fun() {
        String s = "baa";
        String p = "aa";
        List<Integer> list = findAnagrams(s, p);
        System.out.println(list);
    }

    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> ans = new ArrayList<>();
        int sl = s.length(), pl = p.length();
        if (sl < pl) {
            return ans;
        }
        int[] pa = new int[26];
        // 讓這些字元都對映在這26個數字中
        for (char c : p.toCharArray()) {
            System.out.println(pa[c - 'a']++);
        }

        int[] sa = new int[26];
        char[] sc = s.toCharArray();
        for (int i = 0; i < pl; i++) {
            sa[sc[i] - 'a']++;
        }
        if (isSame(sa, pa)) {
            ans.add(0);
        }
        for (int i = pl; i < sl; i++) {
            sa[sc[i] - 'a']++;
            sa[sc[i - pl] - 'a']--;
            if (isSame(sa, pa)) ans.add(i - pl + 1);
        }
        return ans;
    }

    private boolean isSame(int[] sa, int[] pa) {
        for (int i = 0; i < 26; i++) {
            if (sa[i] != pa[i]) return false;
        }
        return true;
    }
}

時間複雜度:O(n^2)

空間複雜度:O(n)