Sunday, December 8, 2013

Max Points on a Line !!!!!!!!!!!!!!!!!!

Q:
Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

A:
现在的思路,就是,先根据slope 分组,  具有相同(很接近)斜率 slope的点放到一组。
然后,对每一组, 再找出具有相同(很接近) 的截距(intersect)的点来。 --记录最大的list的长度,然后返回即可。--------------理论上来讲,是O(n^2)
注意: 重复的点,也算不同的点来count
哎,就TM知道, 不能用这种屌丝办法,会超时,  现在好了,真的超时了。废了一晚上的时间。~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~主要的时间开销,就在Step1 里的双重循环上了。(对每个点,找它的所有的slope),其目的是: 将具有same  slope 的组合 放到一起。(虽然,可能不是相同的节点)
-----------------------------------------代码见本页最后--------------------------------



----------------其实,不是算法复杂度的问题, 是利用了O(n^2)的空间的问题。  也存储了太多的,冗余的slope。------------------------

--------------------------下面是别人的思路-------------------------------------------------
分析:首先要注意的是,输入数组中可能有重复的点。由于两点确定一条直线,一个很直观的解法是计算每两个点形成的直线,然后把相同的直线合并,最后 包含点最多的直线上点的个数就是本题的解。我们知道表示一条直线可以用斜率和y截距两个浮点数(垂直于x轴的直线斜率为无穷大,截距用x截距),同时还需 要保存每条直线上的点(避免重复)。听起来就很麻烦,但是基于这个思想有一种简单的实现方式:
  • 以某点O为中心,计算它和其他点的斜率,如果有两个点A、B和O点形成的斜率相等,那么ABO三点是共线的,如果有多个点和O的斜率相等,那么这 多个点和O也是共线的,因此我们可以求出包含O的所有直线中点数最多的直线,会得到一个最大共线点数k(O),如果和O点重复的点有n个(除了O本身), 那么K(O) = K(O) + n。这一步的计算中,为了提高效率,我们可以用哈希表来保存某个斜率对应的点的数目。
  • 对数组中的每一个点i,按照第一步计算得到每个点最大点数K(i)
  • 从k(i)中选取最大的就是本题的解
  • 注意:为了避免重复计算,以数组中第i个点为中心时,只计算数组中它右边的所有点        

public class MaxPointsOnALine2 {

    public int maxPoints(Point[] points) {
        // for each point, we calculate its slope with others,
        // if they are the same, we save them into a Hashtable
        if (points.length <= 1) { // pay attention to length == 1
            return points.length;
        }
        int nMaxPoints = 0;

        for (int i = 0; i < points.length - 1; i++) {
            // for slope Double, we map its count of integers that could form
            // this slope with points[i]

            Map<Long, Integer> map = new HashMap<Long, Integer>();
            Point pLeft = points[i];
            int nDuplicate = 1; // how many points that having the same (x,y)
                                // value with pLeft(inclusive)
            for (int j = i + 1; j < points.length; j++) {
                Point pRight = points[j];
                if (pLeft.x == pRight.x && pLeft.y == pRight.y) {
                    nDuplicate++;
                    continue;
                } else {
                    Long longSlope;  // is is 10000* actuall slope
                    // calculate their slope and save into a the HashMap
                    if (pLeft.x == pRight.x) {
                        longSlope = Long.MAX_VALUE;
                    } else {
                        double slope = (double) (pRight.y - pLeft.y) / (pRight.x - pLeft.x);
//                        slope = BigDecimal.valueOf(slope).setScale(5, BigDecimal.ROUND_HALF_DOWN)
//                                .doubleValue();// round the slope
                        longSlope =Math.round(slope*10000);
                    }
                    // insert the slope into the hashMap
                    Integer objCount = map.get(longSlope);
                    if (objCount == null) {
                        map.put(longSlope, 1);
                    } else {
                        map.put(longSlope, objCount + 1);
                    }
                }
            }// enf of for loop ---- j
            nMaxPoints = Math.max(nMaxPoints, nDuplicate); // in case that
                                                            // HashMap is empty
            // search all slopes passing pLeft, and update the nMaxPoints
            Iterator<Entry<Long, Integer>> iter = map.entrySet().iterator();
            while (iter.hasNext()) { // for each slope, need find the max point
                Map.Entry<Long, Integer> entry = (Map.Entry<Long, Integer>) iter.next();
                Integer curCount = (Integer) entry.getValue();
                nMaxPoints = Math.max(nMaxPoints, curCount + nDuplicate);
            } // end of while
        } // end of for loop ----- ivalue

        return nMaxPoints;
    }
}

罪魁祸首找到啦~~~~~~~~~~~~~~, 就是
//                        slope = BigDecimal.valueOf(slope).setScale(5, BigDecimal.ROUND_HALF_DOWN)
//                                .doubleValue();// round the slope
把这句话注释掉,就可以了。  ~~~~~~~加上这句话,  运行时间,变成了10倍多。
~~~~~~~~可是,不是说double不能完全一样的值吗???????????
嗯,出现问题了,  去掉这句话之后, 出现  -0.0 和0.0 的slope不一样的问题。怎么办????

解决方法就是: 把double的slope * 10000, 转换成long 类型,就行了。

因此,方法一,也如此解决pass。    具体修改,可以见Eclipse中的代码。  (而且,上面的代码,也没有处理duplicates 的问题。  因此,还是只看解法2吧。


Mistakes:
1:  刚开始,没有考虑,输入数组的长度为0, 为1 的情况。  反而在题目中,直接默认为长度超过2了。  直接调用了, slopeList[0] 啊什么的

2:: 对于slope 为正无穷的情况, 在求 difference  of intersect的时候,要要单独处理,  其各自的intersect 可以用point.x 的值代替。

 3: 注意: 重复的点,也算不同的点来count。  但是,在实际

4: 一开始,设
        double minDiff = 0.0000001;
结果太小了,计算机的round error还是超过了这个值。 更改为
        double minDiff = 0.00001;  

5: 方法二的时候, update nMaxPoints 在第二个for循环后面,而且,刚开始,弄成iter 必须是非空才能update 的。因此,对于输入  ”(0,0),(0,0)“  就不能update nMaxPoints了。


Learned:
1:  round  a double data,   可以用下面的代码:
        double slope = 2.1234567;
        slope = BigDecimal.valueOf(slope).setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue();
        System.out.println(slope);
打印的结果是   2.12346
2:  在leetcode中,也可以在class的前面,加入import 语句。

3: 如何遍历一个HashMap
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
    Map.Entry entry = (Map.Entry) iter.next();
    Object key = entry.getKey();
    Object val = entry.getValue();
}
效率高,以后一定要使用此种方式!
3.5------------------另一种方式,更简单 ----------------
HashMap<Integer,Integer> map = new HashSet<Integer,Integer>();
for(int key : map.keySet()
        // do something

4:  表示直线,
First, DO NOT use double in such kind of problem, you don't need them and they will make you suffer, DO use integers
Second, <k, b> is not a good idea simply because you cannot represent all the possible line using it.
You can use <a, b, c> to represent all the possible line, i.e., ax + by + c = 0 where a, b, c are all integers.

--------------------------------------------第二遍-----------------------------------------

没有去遍历map,而直接是在建立的时候,查询并保存了结果。


Big Mistake: 
        当计算斜率的时候,  long / long  的结果是 long 的, 而不是double的, 因此,要想 得到小数的结果, 需要把一个先转换成double类型,  我艹~~~~~~~~~~~~~~~~~~~  你SB,~~~~~脑子坏掉了。 Tiger


import java.util.*;

public class Solution {
    public int maxPoints(Point[] points) {
        if (points.length <= 1)
            return points.length;
        int maxPointOnLine = 0;
        HashMap<Long, Integer> map = new HashMap<Long, Integer>();// map scale to count
        for (int i = 0; i < points.length; i++) {
            map.clear();
            int duplicate = 1;
            int maxCount = 0;
            for (int j = i + 1; j < points.length; j++) {
                Long ratio = 0L;
                if (points[j].x == points[i].x && points[j].y == points[i].y) {
                    duplicate++;
                } else {
                    if (points[j].x == points[i].x)
                        ratio = Long.MAX_VALUE;
                    else
                        ratio = (long) ( (double)(points[j].y - points[i].y) / (points[j].x - points[i].x) * 100000);
                    int count  =1;
                    if (map.get(ratio) != null)
                        count = map.get(ratio) +1;
                    map.put(ratio, count);
                    maxCount = Math.max(maxCount, count);
                }
            }
            maxPointOnLine = Math.max(maxPointOnLine, duplicate + maxCount);
        }
        return maxPointOnLine;
    }
}


错误2 :     2遍都有这个错误。 
另外,  在update maxPointOnLine 的时候, 不能把              maxPointOnLine 放到for  ( int   j) 这个循环的里边, 会导致  update的时候,  count 和 nDuplicate 不同时是最大的。  因此,要放到外边去。里层循环, 记录斜率的maxCount  .

哎,Tiger,先不要节省代码行数, 即使超出30行又能如何? 要保证正确才对。

错误3: 
曾经写过这样   count  = (map.get(key) == null)? 0 : map.get(key)   + 1 ;  这样的结果不是预期的。   不知道为什么  ~~~~~~~~





--------------------------------解法1 的代码(没pass,只代表思路)----------------------

import java.math.BigDecimal;
import java.util.Map;
import java.util.Map.Entry;

public class Solution {
public int maxPoints(Point[] points) {
        // first divided by slope,
        // NOTE: due to the fact that digital numbers cannot be too concise, we
        // use approximatin
        if (points == null || points.length == 0)
            return 0;
        if (points.length == 1)
            return 1;
        double minDiff = 0.00001;
        Map<Double, Integer> map = new HashMap<Double, Integer>();
        // a map from slope into the position of List of Points
        ArrayList<HashSet<Point>> slopeList = new ArrayList<HashSet<Point>>();

        // Step1: for each pair of points, calculte their slope and add them
        // into the hashMap
        for (int i = 0; i < points.length - 1; i++) {
            for (int j = i + 1; j < points.length; j++) {
                Point pLeft = points[i].x < points[j].x ? points[i] : points[j];
                Point pRight = points[i].x >= points[j].x ? points[i] : points[j];
                double slope;
                if (pRight.x - pLeft.x == 0) {
                    slope = Double.MAX_VALUE;
                } else {
                    slope =( (double)(pRight.y - pLeft.y)) / (pRight.x - pLeft.x);
                    slope = BigDecimal.valueOf(slope).setScale(5, BigDecimal.ROUND_HALF_DOWN)
                            .doubleValue();// round the slope
                }
                Integer index = map.get(slope);
                if (index == null) { // if current slope is not found
                    index = slopeList.size();
                    map.put(slope, slopeList.size()); // add at last position
                    HashSet<Point> tmp = new HashSet<Point>();
                    slopeList.add(tmp); // add one element at slopeList
                }
                HashSet<Point> tmpSet = slopeList.get(index);
                tmpSet.add(pLeft);
                tmpSet.add(pRight);
            }
        }

        // Step 2: now all list contains points of same slope, with some of
        // its neighgbors,
        // we try to find , if using same slope, check the intersect difference
        int maxPoints = 0;
        Iterator<Entry<Double, Integer>> iter = map.entrySet().iterator();
        while (iter.hasNext()) { // for each slope, need find the max point
                                    // through a line ,coz they might parrelel
            Map.Entry<Double, Integer> entry = (Map.Entry<Double, Integer>) iter.next();
            Double slope = (Double) entry.getKey();
            Integer index = (Integer) entry.getValue();

            HashSet<Point> curSet = slopeList.get(index);
            if (curSet.size() <= maxPoints) {
                continue;
            }
            // each element contains lists that having same slope and intersect 
            ArrayList<ArrayList<Point>> all = new ArrayList<ArrayList<Point>>();
            for (Point eachPoint : curSet) { // check the difference with
                                                // existing ones
                boolean findGroup = false;
                // check all points in the list, that might belongs to same
                // group
                for (int j = 0; j < all.size(); j++) {
                    // if found the node that with intercept small enough
                    // arraylist, with same slope and same intersect
                    ArrayList<Point> al = all.get(j);
                    double curIntercept, newIntersect;
                    if (slope == Double.MAX_VALUE) {
                        curIntercept = al.get(0).x;
                        newIntersect = eachPoint.x;
                    } else {
                        curIntercept = al.get(0).y - slope * al.get(0).x;
                        newIntersect = eachPoint.y - slope * eachPoint.x;
                    }
                    if (Math.abs(curIntercept - newIntersect) < minDiff) {
                        al.add(eachPoint);
                        findGroup = true;
                        break;
                    }
                }
                // if not find its group, we append this point to all
                if (findGroup == false) {
                    ArrayList<Point> al = new ArrayList<Point>();
                    al.add(eachPoint);
                    all.add(al);
                }
            }
            // find the maximun number of List, for current slope,
            for (int i = 0; i < all.size(); i++) {
                ArrayList<Point> al = all.get(i);
                if (al.size() > maxPoints) {
                    maxPoints = al.size();
                }
            }
        }
        return maxPoints;
    }
}

Saturday, December 7, 2013

String to Integer (atoi)

Q:
Implement atoi to convert a string to an integer.
Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.
Requirements for atoi: The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.
The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
If no valid conversion could be performed, a zero value is returned. (这里是句号)
 If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned.

A:
一开始,竟然没敢把题目看完,就不敢做了。哎,真是可笑,竟然留到了最后才做,这么一道简单的题目。 ╮(╯▽╰)╭    可悲啊, Tiger

思路很简单,就是一个个地数呗。

public class Solution {
   public int atoi(String str) {
        // Note: The Solution object is instantiated only once and is reused by
        // each test case.
        int INT_MAX = 2147483647;
        int INT_MIN = -2147483648;
        StringBuffer buf = new StringBuffer(str.trim());// ignore space at two
                                                        // ends
        int sign = 1;
        if (buf.length() == 0)
            return 0;
        if (buf.charAt(0) == '+') { // delete +
            buf.delete(0,1);
        } else if (buf.charAt(0) == '-') {
            sign = -1;
            buf.delete(0, 1);
        }
        str = buf.toString();
        long sum = 0;
        // adding from back to begin
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if (ch < '0' || ch > '9')
                break;
            int val = ch - '0';
            sum = sum * 10 + val;
            if (sign == 1) {
                if (sum > INT_MAX) {
                    return  INT_MAX;
                }
            } else { // sum should be negative
                if (sign * sum < INT_MIN) {
                    return   INT_MIN;
                }
            }
        }
        return (int) (sign * sum);

    }
}



Mistakes:
1:  题意理解错误, : 当超出范围时, 返回最大或最小的。 而不是返回  0.
2;  自己宽泛了题意。 当 + -符合后面,是不能再有空格的。

1: 要注意:
return (int) (sign * sum);   这里, 由于sum 是long 型的,   如果仅仅写成
return (int) sign * sum;     是不对的,  会先只转变 sign 的类型。    


--------------第二遍--------------
1: 刚开始,直接开始 考虑str[0] 的值。  而没有先考虑,是否存在 0 位置。

*********************每次计算之前判断是否越界****************

public class Solution { 
    public int myAtoi(String str) {
        boolean isNeg = false;
        str = str.trim();
        if(str.length()==0)
            return 0;
        if(str.charAt(0)=='+' || str.charAt(0)=='-'){
            isNeg = str.charAt(0)=='-';
            str = str.substring(1);
        }
        int sum = 0;
        for(int i =0;i<str.length();i++){
            char ch = str.charAt(i);
            if(Character.isDigit(ch)==false)
                break;
            if(isNeg && (sum < Integer.MIN_VALUE/10 || (sum == Integer.MIN_VALUE/10 && ch>= '8') ))
                return Integer.MIN_VALUE;
            if( !isNeg && (-sum > Integer.MAX_VALUE/10  || ( -sum == Integer.MAX_VALUE/10  && ch>='7')))
                return Integer.MAX_VALUE;
            sum = sum * 10 - (ch -'0');
        }
        return isNeg?sum:-sum;
    }
}

这里,或者直接用long 来记录结果,然后对比即可。

146. LRU Cache -------M !!!!!!!!!!!

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
The cache is initialized with a positive capacity.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4

A:

------------------用doubly-linked list做更新 + HashMap 来做cache---------
class LRUCache {
public:
    LRUCache(int capacity) {        
        cap = capacity;
        header = new Node(0,0);
        tail = new Node(0,0);
        header->next = tail;
        tail->pre = header;
    }
    
    int get(int key) {
        if(map.find(key)==map.end()){
            return -1;
        }
        Node* tmp = map[key];
        detachAndPutBegin(tmp);
        return tmp->val;
    }
    
    void put(int key, int value) {
        Node * tmp;
        if(map.find(key) == map.end()){
            tmp = new Node(key, value);
            if(map.size()==cap){
                auto delNode = tail->pre;
                delNode->pre->next = tail;
                tail->pre = delNode->pre;
                map.erase(delNode->key);
                delete(delNode);
            }
            map.insert({key, tmp});
            // insert at the begining of the list
            detachAndPutBegin(tmp);
        }else{
            map[key]->val = value;
            tmp = map[key];
            detachAndPutBegin(tmp);
        }
    }
private:    
    struct Node{
        int key, val; // need key to point back to delete the last Node* from map
        Node *pre, *next;
        Node(int key, int v):key(key), val(v), pre(NULL),next(NULL){}
    };
    Node *header, *tail;
    int cap =0;
    unordered_map<int,Node*> map;
    
    int detachAndPutBegin(Node * tmp){
        if(tmp->next){ // if in the list
            tmp->pre->next = tmp->next;
            tmp->next->pre = tmp->pre;
        }        
        // insert into the beginning of the list
        tmp->next = header->next;
        tmp->pre = header;
        header->next->pre = tmp;
        header->next = tmp;
        return tmp->val;
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */


Mistakes:
1:刚开始 删除list的时候,是在Dlist中做的。  可是,还需要把HashMap里的也删掉。

2:   考虑到要在Map中删除节点, 可是,Map只能按照Key 来删。
而我们在ListNode中,每次要删的是最后一个Node,  因此,我们需要在Node中保存每个点的key 值。

还有一个trick 就是double linked list 的前后都加了dummy 节点。这样就不需要处理边界情况。

Wednesday, December 4, 2013

Maximal Rectangle !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Q:
Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.

A:
简单的seading算法,(就是假装某点为左上角的corner,然后grow) 应该是太慢了。要注意利用rectangle这个词儿。------------O(n^3)

哎,学会了就行了。 那么纠结干啥?
你就是费劲巴力自己做出来, 有个屁用啊?Tiger, 你SB
这道题,是自己直接上网搜的思路。  看这里, 和这里
具体就是:利用求histogram的思路, 一层层地求最大面积。
 build a cache to make this problem to a list of "Largest Rectangle in Histogram" in M layers 
will take O(M*N^2) time and O(M) space

--------------------第二遍------------------

public class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix.length == 0)
            return 0;
        int m = matrix.length, n = matrix[0].length,maxArea = 0;
        int[] hist = new int[n];
        for (int i = 0; i < m; i++) { // for each row
            for (int j = 0; j < n; j++)
                hist[j] = matrix[i][j] == '0'? 0: hist[j]+1 ;
            maxArea = Math.max(maxArea, getMaxArea(hist));
        }
        return maxArea;
    }
    public int getMaxArea(int[] hist) { // calculate the max-area of a histogram
        int maxArea = 0, n = hist.length;
        Stack<int[]> stack = new Stack<>();
        for (int i = 0; i < n; i++) {
            int preIndex = i;
            while( ! stack.isEmpty()){
                int[] tmp = stack.peek();
                if( hist[i] < tmp[1]  ){ // calculate area before i
                    stack.pop();
                    maxArea = Math.max(maxArea, tmp[1] * (i-tmp[0]));
                    preIndex = tmp[0];
                }else{
                    break;
                }
            }
            stack.push( new int[]{preIndex,hist[i]} );
        }
        while( ! stack.isEmpty() ){
            int[] tmp = stack.pop();
            maxArea = Math.max(maxArea, tmp[1] * (n-tmp[0]) );
        }
        return maxArea;
    }
}


Mistakes:
这里的核心还是利用histgram 求矩形面积。
其难点在2个地方:
1: 每次发现一个更高的, 则push stack。 否则,计算其前面的比他小的矩形的面积(不包括现在的位置)    2:  计算完毕,重新push的时候,需要存入 最远的index,和现在的高度。(因此我们需要记录 preIndex)  


Learned:
1: 用极大化思想解决最大子矩形问题


Thursday, November 28, 2013

32. Longest Valid Parentheses ---------H

Q:
Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.
For "(()", the longest valid parentheses substring is "()", which has length = 2.
Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.

A:

 ---------------4th pass ----split into two round,  first find matching position of  ')' ,  and then combine them 

class Solution {
public:
    int longestValidParentheses(string s) {
        int n = s.length();
        vector<int> matched(n, -1);
        vector<int> stack; // stack of non matched (
        for(int i =0;i<n;i++){
            if(s[i] == '('){
                stack.push_back(i);
            }else{
                if(not stack.empty()){
                    matched[i] = stack.back();
                    stack.pop_back();
                }
            }
        }
        // find the left most match
        int res = 0;
        for(int i= 0;i<n;i++){
            if(matched[i] >=0){
                int pre = matched[i];
                if(pre-1>=0 && matched[pre-1] >=0){
                    pre = matched[pre-1];
                }
                matched[i] = pre; // this need UPDATED
                res = max(res, i - pre + 1);
            }
        }
        return res;
    }
};

直觉就是用DP算法。
把输入,从empty的情况,开始加入。来看待。
记录下来,与之匹配的left parentheses的位置。  最后,再计算总长度。


---------------------------第二遍-----------------O(n)的复杂度-----即使是()()的向后跳的情况,也是最多发生O(n)次------------------------
思想是: 从后向前,记录一个该点最远可以达到的距离。
以后每一个新的位置 i ,如果是‘(’  首先找到它的match位置,(可能是 i+1 ,也可能是 farestMatch[i] +1 处)   。
找到match后,再查看是否是()()()这种情况, 并且加上。

public class Solution {
    public int longestValidParentheses(String s) {
        if (s == null || s.length() == 0)
            return 0;
        int n = s.length();
        int[] farestMatch = new int[n];
        for (int i = 0; i < n; i++)
            farestMatch[i] = -1;

        // count from back, at each potision,record farest matching position
        int maxLength = 0;
        for (int i = n - 2; i >= 0; i--) {
            if (s.charAt(i) == '(') {
                // if next position does NOT has its matching
                int k = i + 1;// to be next tested position
                if (farestMatch[i + 1] > 0) // if i+1 position already has it
                                            // matching
                    k = farestMatch[i + 1] + 1;
                if (k < n && s.charAt(k) == ')') {
                    farestMatch[i] = k;
                    // now add possible ()()()() loops
                    while (farestMatch[i] + 1 < n && farestMatch[farestMatch[i] + 1] > 0)
                        farestMatch[i] = farestMatch[farestMatch[i] + 1];

                    maxLength = Math.max(maxLength, farestMatch[i] - i + 1);
                }
            }
        }
        return maxLength;
    }
}

----------------------------3rd Pass-------------------------------------
这次是彻底的O(n)。  而不用那个while 循环。
思想是:  用一个数组,记录其到最左端match 的位置。
          遍历的时候,用stack,记录其前一个match的位置。  然后,每次combine前一个,即得到所有的,最长的match的长度。

public class Solution {
    public int longestValidParentheses(String s) {
        int res = 0,  n = s.length();
        int [] A = new int[n]; // remember A[i]'s furthest matching position
        Arrays.fill(A,-1);
        for(int i =1;i<n;i++){
            if(s.charAt(i) ==')'){
                int pre = i-1;
                if(A[pre] >=  0) // pre position has no match
                    pre = A[pre]-1;
                if(pre>=0 && s.charAt(pre)=='('){
                    A[i] = pre;
                    if(pre-1>=0 && A[pre-1]>=0)
                        A[i] = A[pre-1];
                    res = Math.max(res, i-A[i]+1);
                }
            }
        }
        return res;
    }
}




Mistakes:
1:  当最终计算最大长度的时候,  我随手写了个    if (mostLeftMatchPos[i] > 0 ){
但是, 应该,是    if (mostLeftMatchPos[i] >= 0 ){ 的。
哎,不知道为什么,当时能那样写。
2: 开始, 当输入  为“())的时候,陷入了死循环。
原因是当回头看到的是  与left 没有匹配的情况的时候。  光记得 update nRightMinusLeft 去了, 忘了把j的位置再减一。
3: 当计算longest的时候, 光考虑与之前的单独match了,却没有考虑输入为 “()() ”的情况。
因此,需要在for循环里加一个while语句。



Learned:
1:  不要想着, 精简代码。  重要的,是思路清楚。  最好是(只要复杂度不变) 先解决小问题。不要想着一步到位。  做正确才是最重要的。
例如,这里,刚开始,不要想着, 直接建立leftMostMatch 而,仅仅去找leftMatch即可。
至于()()这种情况。我们完全可以基于leftMatch数组再计算。


130. Surrounded Regions -M

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.
Example:
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:
X X X X
X X X X
X X X X
X O X X
Explanation:
Surrounded regions shouldn’t be on the border, which means that any 'O' on the border of the board are not flipped to 'X'. Any 'O' that is not on the border and it is not connected to an 'O' on the border will be flipped to 'X'. Two cells are connected if they are adjacent cells connected horizontally or vertically.

A:

用图像里的growing思想呗。 每碰到一个 o  就开始检测。直到出了边界或者确认包围(转换成X)  嗯,首先是把边界的设 为 标识 @ , 然后grow,
 虽然,也用了小技巧,来提速,但是,这个的实现,还是有点儿慢了。 具体实现,在最后(learned section的下面)

下面这个方法,是利用grow un-surrouned O, 方法。
简单来讲,就是先从四周开始,一层层地剥开。
但是,这样的假设是不成立的, 原因在于, 无法回溯到 zig-zag形式的。

哎,还是回到前面的思路, 考虑到,我们是对200*200的一个巨大的0闭环内没有通过。
我们考虑从四周开始grow un-surrouned region(也就是把上面的2个思路并起来。


class Solution {
public:
    void solve(vector<vector<char>>& board) {
        int m = board.size();
        if(m==0)
            return;
        int n = board[0].size();        
        vector<vector<int> > stack;
        for(int i =0;i<m;++i)
            for(int j =0;j<n;++j)
                if((i==0 || i==m-1 || j==0 || j==n-1 ) && board[i][j] =='O')
                    stack.push_back(vector<int>{i,j});
        // change boundary 'O' --> 'A',
        while(not stack.empty())
        {
            vector<vector<int>> newS;
            for(auto tmp : stack)
            {
                int i = tmp[0], j = tmp[1];
                board[i][j] = 'A';
                if(i>0 && board[i-1][j] =='O')
                    newS.push_back(vector<int>{i-1,j});
                if(i+1<m && board[i+1][j] =='O')
                    newS.push_back(vector<int>{i+1,j});
                if(j>0 && board[i][j-1] =='O')
                    newS.push_back(vector<int>{i,j-1});
                if(j+1<n && board[i][j+1] =='O')
                    newS.push_back(vector<int>{i,j+1});
            }
            stack = newS;
        }
        for(int i =0;i<m;++i)
            for(int j =0;j<n;++j)
                if(board[i][j]=='O')
                    board[i][j] = 'X';
                else if(board[i][j] == 'A')
                    board[i][j] = 'O';
        
    }
};


Mistakes:
2: 处于速度考虑,我们search的时候,尽量通过从4个边来,从内往里search???
3: 还是有一些拼写错误,  主要来自于copy 上面的代码(因为重复性太多)

----------------------------这个更改,删掉了copy vector这个步骤, 节省了空间-------------
class Solution {
public:
    void solve(vector<vector<char>>& board) {
        int m = board.size();
        if(m==0)
            return;
        int n = board[0].size();        
        vector<vector<int> > posList;
        for(int i =0;i<m;++i)
            for(int j =0;j<n;++j)
                if((i==0 || i==m-1 || j==0 || j==n-1 ) && board[i][j] =='O')
                    posList.push_back(vector<int>{i,j});
        // change boundary 'O' --> 'A',
        for(int cur = 0;cur<posList.size();++cur)
        {
            int i = posList[cur][0], j = posList[cur][1];
            board[i][j] = 'A';
            if(i>0 && board[i-1][j] =='O')
                posList.push_back(vector<int>{i-1,j});
            if(i+1<m && board[i+1][j] =='O')
                posList.push_back(vector<int>{i+1,j});
            if(j>0 && board[i][j-1] =='O')
                posList.push_back(vector<int>{i,j-1});
            if(j+1<n && board[i][j+1] =='O')
                posList.push_back(vector<int>{i,j+1});
        }
        for(int i =0;i<m;++i)
            for(int j =0;j<n;++j)
                if(board[i][j]=='O')
                    board[i][j] = 'X';
                else if(board[i][j] == 'A')
                    board[i][j] = 'O';
    }
};



Learned:
1: 在将就效率的时候,就不要搞些递归, 尽量用interative,  来存储中间数据。


--------------下面的这个,too  slow----------coz  we have use too many dfs ---------
public class Solution {
    public void solve(char[][] board) {
        if (board == null || board.length == 0)
            return;
        int m = board.length;
        int n = board[0].length;
        // DFS track the border
        // for first and last rows
        for (int j = 0; j < n; j++) {
            dfs(board, 0, j);
            dfs(board, m - 1, j);
        }
        // for most left and most right columns
        for (int i = 1; i < m - 1; i++) {
            dfs(board, i, 0);
            dfs(board, i, n - 1);
        }
        // flip all inner O into X , and boarder @ into O
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
                if (board[i][j] == 'O')
                    board[i][j] = 'X';
                else if (board[i][j] == '@')
                    board[i][j] = 'O';
    }

    private void dfs(char[][] board, int i, int j) {
        if (board[i][j] != 'O')
            return;
        board[i][j] = '@'; // set as a flag
        int m = board.length;
        int n = board[0].length;

        if (i - 1 >= 0 && board[i - 1][j] == 'O')// up
            dfs(board, i - 1, j);
        if (i + 1 < m && board[i + 1][j] == 'O')// down
            dfs(board, i + 1, j);
        if (j - 1 >= 0 && board[i][j - 1] == 'O')// left
            dfs(board, i, j - 1);
        if (j + 1 < n && board[i][j + 1] == 'O')// right
            dfs(board, i, j + 1);
    }
}

Wednesday, November 27, 2013

150. Evaluate Reverse Polish Notation. (medium)

Evaluate the value of an arithmetic expression in Reverse Polish Notation.
Valid operators are +-*/. Each operand may be an integer or another expression.
Note:
  • Division between two integers should truncate toward zero.
  • The given RPN expression is always valid. That means the expression would always evaluate to a result and there won't be any divide by zero operation.
Example 1:
Input: ["2", "1", "+", "3", "*"]
Output: 9
Explanation: ((2 + 1) * 3) = 9
Example 2:
Input: ["4", "13", "5", "/", "+"]
Output: 6
Explanation: (4 + (13 / 5)) = 6
Example 3:
Input: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
Output: 22
Explanation: 
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

A:

       每遇到运算符,就提出最后面的两个,运算,并保存。

class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> S;
for (auto s : tokens) {
if (s == "*" || s == "/" || s == "+" || s == "-") {
auto b = S.top();
S.pop();
auto a = S.top();
S.pop();
if (s == "*") {
S.push(a * b);
} else if (s == "/") {
S.push(a / b);
} else if (s == "+") {
S.push(a + b);
} else {
S.push(a - b);
}
} else {
S.push(stoi(s));
}
}
return S.top();
}
};

Mistakes:
1 : 没有考虑 当一个数为:负数的时候, 例如 -2,  如果只检查首字母, 就会误认为是运算符。
2: 刚开始,自以为是了。  用double类型保持中间值。
    没想到,作者是不用的。   用int数组就行。

----------第二遍-----------
3: 由于是从 + 的情况直接copy 的代码,  对于 -   / 的情况,没有考虑 a,b 的顺序要调过来的。


Learned:





Tuesday, November 26, 2013

148. Sort List ---- Medium !!!!!!!

Given the head of a linked list, return the list after sorting it in ascending order.

 

Example 1:

Input: head = [4,2,1,3]
Output: [1,2,3,4]

Example 2:

Input: head = [-1,5,3,4,0]
Output: [-1,0,3,4,5]

Example 3:

Input: head = []
Output: []

 

Constraints:

  • The number of nodes in the list is in the range [0, 5 * 104].
  • -105 <= Node.val <= 105

 

Follow up: Can you sort the linked list in O(n logn) time and O(1) memory (i.e. constant space)?

A:

insertion sort, 会超时


----------------------------merge sort   ---------------------------
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(!head || !head->next)
return head;
ListNode * slow = head, *fast = head->next;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
}
auto l1 = sortList(slow->next);
slow->next = nullptr;
auto l2 = sortList(head);
// merge two list
ListNode header;
auto tail = &header;
while(l1 && l2){
ListNode * tmp;
if(l1->val <= l2->val ){
tmp = l1;
l1 = l1->next;
}else{
tmp = l2;
l2 = l2->next;
}
tmp->next = nullptr;
tail->next = tmp;
tail = tail->next;
}
if(l1)
tail->next = l1;
else if(l2)
tail->next = l2;
return header.next;
}
};

----------- For follow up question: quick sort --------------------
但是依然LTE了 ???????????
原因在于,如果是在最坏的情况,数组本来就是倒叙的。
暂时没有什么很好的解决方法。 (数组的形式,可以很方便用首尾的平均值)  还是用merge sort来解决这个问题吧。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
// quick sort
if(not head || not head->next)
return head;
ListNode h1(INT_MIN), h2(INT_MIN);
int pivot = head->val;
ListNode* runner = head->next; // do not include head when generating
while(runner){
auto tmp = runner;
runner = runner->next;
tmp->next = nullptr;

if(tmp->val <= pivot){
tmp->next = h1.next;
h1.next = tmp;
}else{
tmp->next = h2.next;
h2.next = tmp;
}
}
auto h_small = sortList(h1.next);
auto h_big = sortList(h2.next);
head->next = h_big;
if(not h_small)
return head;

// append h2 to h1;
runner = h_small;
while( runner->next){
runner = runner->next;
}
runner->next = head;
return h_small;
}
};




Mistakes: 

2: when updating runner after a while loop, always remember to set runner= runner.next; after extracting Header2 list.

 3: Coz we forget updating the tail  even after we already done inserting the list.
 4:  日!!!!!!
 刚开始, return 命令行上面的一句:         header= newHeader; 应该写成
        header.next = newHeader.next;  就对了。
╮(╯▽╰)╭, 基础不行啊。Tiger ,这种SB的问题,你都能犯~~~~~~ 搞了爷们儿2个小时。 艹


Learned:
1: in C++,  to judge whether a node is null, we have 3 method
       a)  node == NULL
       b)  ! node
       c) not node

2: 
quick sort 最大的trick就是,每次要把pivot摘下来,放到中间。 这样可以保证每次都变小。


3: linkedlist ,摘下一个节点的时候
auto tmp = runner;
runner = runner->next;
tmp->next = nullptr;
顺序不能乱。 主要是第二行和第三行,要注意,顺序不能错。