LeetCode 双指针+hash表方法

hashtable+双指针窗口法解题思路

最近一直在刷leetcode,发现许多题目解法很相似,如求 findSubstring,minWindow,lengthOfLongestSubstring问题,解法大致都一样都是用滑动窗口的思想,不过滑动的规则没处理好,很容易导致时间复杂度增加;
题目链接:https://leetcode.com/problems/substring-with-concatenation-of-all-words/
http://oj.leetcode.com/problems/minimum-window-substring/
http://oj.leetcode.com/problems/longest-substring-without-repeating-characters/

//链接1题解
public ArrayList<Integer> findSubstring(String S, String[] L) {
    // Note: The Solution object is instantiated only once and is reused by each test case.
    ArrayList<Integer> res = new ArrayList<Integer>();
    if(S==null || S.length()==0 || L==null || L.length==0)
        return res;
    HashMap<String,Integer> map = new HashMap<String,Integer>();
    for(int i=0;i<L.length;i++)
    {
        if(map.containsKey(L[i]))
        {
            map.put(L[i],map.get(L[i])+1);
        }
        else
        {
            map.put(L[i],1);
        }
    }
    for(int i=0;i<L[0].length();i++)
    {
        HashMap<String,Integer> curMap = new HashMap<String,Integer>();
        int count = 0;
        int left = i;
        for(int j=i;j<=S.length()-L[0].length();j+=L[0].length())
        {
            String str = S.substring(j,j+L[0].length());

            if(map.containsKey(str))
            {
                if(curMap.containsKey(str))
                    curMap.put(str,curMap.get(str)+1);
                else
                    curMap.put(str,1);
                if(curMap.get(str)<=map.get(str))
                    count++;
                else
                {
                    while(curMap.get(str)>map.get(str))
                    {
                        String temp = S.substring(left,left+L[0].length());
                        if(curMap.containsKey(temp))
                        {
                            curMap.put(temp,curMap.get(temp)-1);
                            if(curMap.get(temp)<map.get(temp))
                                count--;
                        }
                        left += L[0].length();
                    }
                }
                if(count == L.length)
                {
                    res.add(left);
                    //if(left<)
                    String temp = S.substring(left,left+L[0].length());
                    if(curMap.containsKey(temp))
                        curMap.put(temp,curMap.get(temp)-1);
                    count--;
                    left += L[0].length();
                }
            }
            else
            {
                curMap.clear();
                count = 0;
                left = j+L[0].length();
            }
        }
    }
    return res;
}
/*复杂付分析:外循环L[0].length()次,内循环n/L[0].length()次,每次访问的字符串的总次数不超过2n此,每个word最多会被窗口两端各访问一次,总的时间复杂度O(n)*/
 public int lengthOfLongestSubstring(String s) {
         //双指针+hashtable(int数组实现)
         if(s==null||s.equals("")) return 0;
         int max=1;
         int[] wind=new int[256];
         int start=0,end=0;
         Arrays.fill(wind, -1);
         for(;end<s.length();end++){
                if(wind[s.charAt(end)]>=start)
                    start=wind[s.charAt(end)]+1;
                wind[s.charAt(end)]=end;
                max=Math.max(max,end-start+1);
             }
             return max;
    }
public String minWindow(String S, String T) {
    if(S==null || S.length()==0)
        return "";
    HashMap<Character, Integer> map = new HashMap<Character, Integer>();
    for(int i=0; i<T.length();i++)
    {
        if(map.containsKey(T.charAt(i)))
        {
            map.put(T.charAt(i),map.get(T.charAt(i))+1);
        }
        else
        {
            map.put(T.charAt(i),1);
        }
    }
    int left = 0;
    int count = 0;
    int minLen = S.length()+1;
    int minStart = 0;
    for(int right=0; right<S.length();right++)
    {
        if(map.containsKey(S.charAt(right)))
        {
            map.put(S.charAt(right),map.get(S.charAt(right))-1);
            if(map.get(S.charAt(right))>=0)
            {
                count++;
            }
            while(count == T.length())
            {
                if(right-left+1<minLen)
                {
                    minLen = right-left+1;
                    minStart = left;                    
                }
                if(map.containsKey(S.charAt(left)))
                {
                    map.put(S.charAt(left), map.get(S.charAt(left))+1);
                    if(map.get(S.charAt(left))>0)
                    {
                        count--;
                    }
                }
                left++;
            }
        }
    }
    if(minLen>S.length())
    {
        return "";
    }
    return S.substring(minStart,minStart+minLen);
}

关键点分析:
1,窗口左右端什么时候移,每次移动多少距离;
2,窗口内包含的字符序列是否符合要求;一般做法:将题目要求序列放入hashmap或字符数组中,然后遍历字符串的过程中碰到指定字符进行计数count,同时对hashmap进行增减处理,当count符合要求序列长度时停止;然后移动窗口,开始新的循环;左端移动时,对hashmap对应value进行加一处理,右端移动对hashmap对应value进行减一处理;
参考:
http://blog.csdn.net/linhuanmars/article/details/20343903

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值