Lintcode 32 Minimum Window Substring

题目描述

Description
Given a string source and a string target, find the minimum window in source which will contain all the characters in target.

  • If there is no such window in source that covers all characters in target, return the emtpy string “”.
  • If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in source.
  • The target string may contain duplicate characters, the minimum window should cover all characters including the duplicate characters in target.

Clarification
Should the characters in minimum window has the same order in target?

  • Not necessary.

Example
For source = “ADOBECODEBANC”, target = “ABC”, the minimum window is “BANC”

Challenge
Can you do it in time complexity O(n) ?
题目意思是给定字符串source和目标字符串target,在字符串source中找到包括所有目标字符串字母的最小子串。

思路

刚开始我想用循环来扫描,然后用replacefirst来替换掉重复的(可能难以表述清楚),不过这样也做出来了,不过明显不好理解,所以就换了一种方法写(最开始的代码后面也会贴出来)
之后呢,思考了下,认为用hashmap来做会比较方便,而且便于理解,大致思路如下
用一个HashMap<Character, Integer>来存放每个字符,key是字符,value值为map中字符的个数

  • 首先将target字符串中每个字符存放进map里面
for (int i = 0; i < tSize; i++) {
            char c = target.charAt(i);
            if (map.containsKey(c)) {
                map.put(c, map.get(c) + 1);
            } else {
                map.put(c, 1);
            }
        }
  • 之后循环找到符合条件的字符串(包含目标字符串中所有字符的字符串)
while (j < sSize && n < tSize) {
                    char c = source.charAt(j);
                    if (map.containsKey(c)) {
                        if (map.get(c) > 0) {
                            n++;
                        }
                        map.put(c, map.get(c) - 1);
                    }
                    j++;
                }
  • 然后再根据字符串长度来替换result字符串(最终字符串)
if (n == tSize && min > j - i) {
                    min = j - i;
                    result = source.substring(i, j);
                }
  • 最后再判断是否要将字符放回去
char c = source.charAt(i);
                if (map.containsKey(c)) {
                    if (map.get(c) >= 0) {
                        n--;
                    }
                    map.put(c, map.get(c) + 1);
                }

代码

  • 最开始的解法
public class Solution {
    /**
     * @param source : A string
     * @param target: A string
     * @return: A string denote the minimum window, return "" if there is no such a string
     */
    public String minWindow(String source, String target) {
        // write your code here
        if (source.length() == 0 || target.length() == 0) {
            return source;
        }
        String str;
        int min = source.length();
        int start = 0, end = 0;
        int ssize = source.length() - target.length() + 1;
        for (int i = 0; i < ssize; i++) {
            String t = target;
            str = "";
            if (t.contains(String.valueOf(source.charAt(i)))) {
                for (int j = i; j < min + i && j < source.length(); j++) {
                    String temp = String.valueOf(source.charAt(j));
                    if (t.contains(temp)) {
                        str += temp;
                        if ("*&^%$#@!():".contains(temp)) {
                            temp = "//" + temp;
                        }
                        t = t.replaceFirst(temp,"");
                    }
                    if (str.length() == target.length() && min >= j - i + 1) {
                        min = j - i + 1;
                        start = i;
                        end = j + 1;
                        break;
                    }
                }
            }
        }
        return source.substring(start, end);
    }
}
  • hashmap解法
public String minWindow(String source, String target) {
        // write your code here
        //第一种解法用hashmap
        HashMap<Character, Integer> map = new HashMap<>();
        int tSize = target.length();
        int sSize = source.length();
        //将target字符串中所有的字符放入map中
        for (int i = 0; i < tSize; i++) {
            char c = target.charAt(i);
            if (map.containsKey(c)) {
                map.put(c, map.get(c) + 1);
            } else {
                map.put(c, 1);
            }
        }
        String result = "";
        int min = Integer.MAX_VALUE;
        int n = 0, j = 0;
        for (int i = 0; i < sSize; i++) {
            if (map.containsKey(source.charAt(i))) {
                //找到符合条件的子串
                while (j < sSize && n < tSize) {
                    char c = source.charAt(j);
                    if (map.containsKey(c)) {
                        if (map.get(c) > 0) {
                            n++;
                        }
                        map.put(c, map.get(c) - 1);
                    }
                    j++;
                }
                //替换result
                if (n == tSize && min > j - i) {
                    min = j - i;
                    result = source.substring(i, j);
                }
                //判断是否要将第一个字符重新放回map中
                char c = source.charAt(i);
                if (map.containsKey(c)) {
                    if (map.get(c) >= 0) {
                        n--;
                    }
                    map.put(c, map.get(c) + 1);
                }
            }
        }
        return result;
    }

还有一种解法,是不用hashmap的,而是用大小为256(正好对应char字符)数组储存字符,大体思路差不多,这个更好理解吧

  • 不用hashmap的解法
public String minWindow(String source, String target) {
        // write your code here
        //第二种解法不用hashmap
        int tSize = target.length();
        int sSize = source.length();
        //将target里面的每个字符放入数组中
        for (int i = 0; i < tSize; i++) {
            chars[target.charAt(i)]++;
        }
        String result = "";
        int j = 0, min = Integer.MAX_VALUE;
        for (int i = 0; i < sSize; i++) {
            while (j < sSize && !isFindAll()) {
                chars[source.charAt(j)]--;
                j++;
            }
            if (isFindAll() && j - i < min) {
                min = j - i;
                result = source.substring(i, j);
            }
            chars[source.charAt(i)]++;
        }
        return result;
    }

    //判断是否所有字符都被寻找到了
    private boolean isFindAll() {
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] > 0) {
                return false;
            }
        }
        return true;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值